From noreply at buildbot.pypy.org Fri Jul 1 01:15:52 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 1 Jul 2011 01:15:52 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge default Message-ID: <20110630231552.7BBA182936@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45199:33ebb9235c26 Date: 2011-06-29 16:35 -0700 http://bitbucket.org/pypy/pypy/changeset/33ebb9235c26/ Log: merge default diff --git a/_pytest/__init__.py b/_pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.0.3' +__version__ = '2.1.0.dev4' diff --git a/_pytest/assertion.py b/_pytest/assertion.py deleted file mode 100644 --- a/_pytest/assertion.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -support for presented detailed information in failing assertions. -""" -import py -import sys -from _pytest.monkeypatch import monkeypatch - -def pytest_addoption(parser): - group = parser.getgroup("debugconfig") - group._addoption('--no-assert', action="store_true", default=False, - dest="noassert", - help="disable python assert expression reinterpretation."), - -def pytest_configure(config): - # The _reprcompare attribute on the py.code module is used by - # py._code._assertionnew to detect this plugin was loaded and in - # turn call the hooks defined here as part of the - # DebugInterpreter. - m = monkeypatch() - config._cleanup.append(m.undo) - warn_about_missing_assertion() - if not config.getvalue("noassert") and not config.getvalue("nomagic"): - def callbinrepr(op, left, right): - hook_result = config.hook.pytest_assertrepr_compare( - config=config, op=op, left=left, right=right) - for new_expl in hook_result: - if new_expl: - return '\n~'.join(new_expl) - m.setattr(py.builtin.builtins, - 'AssertionError', py.code._AssertionError) - m.setattr(py.code, '_reprcompare', callbinrepr) - -def warn_about_missing_assertion(): - try: - assert False - except AssertionError: - pass - else: - sys.stderr.write("WARNING: failing tests may report as passing because " - "assertions are turned off! (are you using python -O?)\n") - -# Provide basestring in python3 -try: - basestring = basestring -except NameError: - basestring = str - - -def pytest_assertrepr_compare(op, left, right): - """return specialised explanations for some operators/operands""" - width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op - left_repr = py.io.saferepr(left, maxsize=int(width/2)) - right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) - summary = '%s %s %s' % (left_repr, op, right_repr) - - issequence = lambda x: isinstance(x, (list, tuple)) - istext = lambda x: isinstance(x, basestring) - isdict = lambda x: isinstance(x, dict) - isset = lambda x: isinstance(x, set) - - explanation = None - try: - if op == '==': - if istext(left) and istext(right): - explanation = _diff_text(left, right) - elif issequence(left) and issequence(right): - explanation = _compare_eq_sequence(left, right) - elif isset(left) and isset(right): - explanation = _compare_eq_set(left, right) - elif isdict(left) and isdict(right): - explanation = _diff_text(py.std.pprint.pformat(left), - py.std.pprint.pformat(right)) - elif op == 'not in': - if istext(left) and istext(right): - explanation = _notin_text(left, right) - except py.builtin._sysex: - raise - except: - excinfo = py.code.ExceptionInfo() - explanation = ['(pytest_assertion plugin: representation of ' - 'details failed. Probably an object has a faulty __repr__.)', - str(excinfo) - ] - - - if not explanation: - return None - - # Don't include pageloads of data, should be configurable - if len(''.join(explanation)) > 80*8: - explanation = ['Detailed information too verbose, truncated'] - - return [summary] + explanation - - -def _diff_text(left, right): - """Return the explanation for the diff between text - - This will skip leading and trailing characters which are - identical to keep the diff minimal. - """ - explanation = [] - i = 0 # just in case left or right has zero length - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - break - if i > 42: - i -= 10 # Provide some context - explanation = ['Skipping %s identical ' - 'leading characters in diff' % i] - left = left[i:] - right = right[i:] - if len(left) == len(right): - for i in range(len(left)): - if left[-i] != right[-i]: - break - if i > 42: - i -= 10 # Provide some context - explanation += ['Skipping %s identical ' - 'trailing characters in diff' % i] - left = left[:-i] - right = right[:-i] - explanation += [line.strip('\n') - for line in py.std.difflib.ndiff(left.splitlines(), - right.splitlines())] - return explanation - - -def _compare_eq_sequence(left, right): - explanation = [] - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - explanation += ['At index %s diff: %r != %r' % - (i, left[i], right[i])] - break - if len(left) > len(right): - explanation += ['Left contains more items, ' - 'first extra item: %s' % py.io.saferepr(left[len(right)],)] - elif len(left) < len(right): - explanation += ['Right contains more items, ' - 'first extra item: %s' % py.io.saferepr(right[len(left)],)] - return explanation # + _diff_text(py.std.pprint.pformat(left), - # py.std.pprint.pformat(right)) - - -def _compare_eq_set(left, right): - explanation = [] - diff_left = left - right - diff_right = right - left - if diff_left: - explanation.append('Extra items in the left set:') - for item in diff_left: - explanation.append(py.io.saferepr(item)) - if diff_right: - explanation.append('Extra items in the right set:') - for item in diff_right: - explanation.append(py.io.saferepr(item)) - return explanation - - -def _notin_text(term, text): - index = text.find(term) - head = text[:index] - tail = text[index+len(term):] - correct_text = head + tail - diff = _diff_text(correct_text, text) - newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] - for line in diff: - if line.startswith('Skipping'): - continue - if line.startswith('- '): - continue - if line.startswith('+ '): - newdiff.append(' ' + line[2:]) - else: - newdiff.append(line) - return newdiff diff --git a/_pytest/assertion/__init__.py b/_pytest/assertion/__init__.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/__init__.py @@ -0,0 +1,128 @@ +""" +support for presenting detailed information in failing assertions. +""" +import py +import imp +import marshal +import struct +import sys +import pytest +from _pytest.monkeypatch import monkeypatch +from _pytest.assertion import reinterpret, util + +try: + from _pytest.assertion.rewrite import rewrite_asserts +except ImportError: + rewrite_asserts = None +else: + import ast + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption('--assertmode', action="store", dest="assertmode", + choices=("on", "old", "off", "default"), default="default", + metavar="on|old|off", + help="""control assertion debugging tools. +'off' performs no assertion debugging. +'old' reinterprets the expressions in asserts to glean information. +'on' (the default) rewrites the assert statements in test modules to provide +sub-expression results.""") + group.addoption('--no-assert', action="store_true", default=False, + dest="noassert", help="DEPRECATED equivalent to --assertmode=off") + group.addoption('--nomagic', action="store_true", default=False, + dest="nomagic", help="DEPRECATED equivalent to --assertmode=off") + +class AssertionState: + """State for the assertion plugin.""" + + def __init__(self, config, mode): + self.mode = mode + self.trace = config.trace.root.get("assertion") + +def pytest_configure(config): + warn_about_missing_assertion() + mode = config.getvalue("assertmode") + if config.getvalue("noassert") or config.getvalue("nomagic"): + if mode not in ("off", "default"): + raise pytest.UsageError("assertion options conflict") + mode = "off" + elif mode == "default": + mode = "on" + if mode != "off": + def callbinrepr(op, left, right): + hook_result = config.hook.pytest_assertrepr_compare( + config=config, op=op, left=left, right=right) + for new_expl in hook_result: + if new_expl: + return '\n~'.join(new_expl) + m = monkeypatch() + config._cleanup.append(m.undo) + m.setattr(py.builtin.builtins, 'AssertionError', + reinterpret.AssertionError) + m.setattr(util, '_reprcompare', callbinrepr) + if mode == "on" and rewrite_asserts is None: + mode = "old" + config._assertstate = AssertionState(config, mode) + config._assertstate.trace("configured with mode set to %r" % (mode,)) + +def _write_pyc(co, source_path): + if hasattr(imp, "cache_from_source"): + # Handle PEP 3147 pycs. + pyc = py.path.local(imp.cache_from_source(str(source_path))) + pyc.ensure() + else: + pyc = source_path + "c" + mtime = int(source_path.mtime()) + fp = pyc.open("wb") + try: + fp.write(imp.get_magic()) + fp.write(struct.pack(">", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + + +class DebugInterpreter(ast.NodeVisitor): + """Interpret AST nodes to gleam useful debugging information. """ + + def __init__(self, frame): + self.frame = frame + + def generic_visit(self, node): + # Fallback when we don't have a special implementation. + if _is_ast_expr(node): + mod = ast.Expression(node) + co = self._compile(mod) + try: + result = self.frame.eval(co) + except Exception: + raise Failure() + explanation = self.frame.repr(result) + return explanation, result + elif _is_ast_stmt(node): + mod = ast.Module([node]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co) + except Exception: + raise Failure() + return None, None + else: + raise AssertionError("can't handle %s" %(node,)) + + def _compile(self, source, mode="eval"): + return compile(source, "", mode) + + def visit_Expr(self, expr): + return self.visit(expr.value) + + def visit_Module(self, mod): + for stmt in mod.body: + self.visit(stmt) + + def visit_Name(self, name): + explanation, result = self.generic_visit(name) + # See if the name is local. + source = "%r in locals() is not globals()" % (name.id,) + co = self._compile(source) + try: + local = self.frame.eval(co) + except Exception: + # have to assume it isn't + local = None + if local is None or not self.frame.is_true(local): + return name.id, result + return explanation, result + + def visit_Compare(self, comp): + left = comp.left + left_explanation, left_result = self.visit(left) + for op, next_op in zip(comp.ops, comp.comparators): + next_explanation, next_result = self.visit(next_op) + op_symbol = operator_map[op.__class__] + explanation = "%s %s %s" % (left_explanation, op_symbol, + next_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=next_result) + except Exception: + raise Failure(explanation) + try: + if not self.frame.is_true(result): + break + except KeyboardInterrupt: + raise + except: + break + left_explanation, left_result = next_explanation, next_result + + if util._reprcompare is not None: + res = util._reprcompare(op_symbol, left_result, next_result) + if res: + explanation = res + return explanation, result + + def visit_BoolOp(self, boolop): + is_or = isinstance(boolop.op, ast.Or) + explanations = [] + for operand in boolop.values: + explanation, result = self.visit(operand) + explanations.append(explanation) + if result == is_or: + break + name = is_or and " or " or " and " + explanation = "(" + name.join(explanations) + ")" + return explanation, result + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_explanation, operand_result = self.visit(unary.operand) + explanation = pattern % (operand_explanation,) + co = self._compile(pattern % ("__exprinfo_expr",)) + try: + result = self.frame.eval(co, __exprinfo_expr=operand_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_BinOp(self, binop): + left_explanation, left_result = self.visit(binop.left) + right_explanation, right_result = self.visit(binop.right) + symbol = operator_map[binop.op.__class__] + explanation = "(%s %s %s)" % (left_explanation, symbol, + right_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=right_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_Call(self, call): + func_explanation, func = self.visit(call.func) + arg_explanations = [] + ns = {"__exprinfo_func" : func} + arguments = [] + for arg in call.args: + arg_explanation, arg_result = self.visit(arg) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + arguments.append(arg_name) + arg_explanations.append(arg_explanation) + for keyword in call.keywords: + arg_explanation, arg_result = self.visit(keyword.value) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + keyword_source = "%s=%%s" % (keyword.arg) + arguments.append(keyword_source % (arg_name,)) + arg_explanations.append(keyword_source % (arg_explanation,)) + if call.starargs: + arg_explanation, arg_result = self.visit(call.starargs) + arg_name = "__exprinfo_star" + ns[arg_name] = arg_result + arguments.append("*%s" % (arg_name,)) + arg_explanations.append("*%s" % (arg_explanation,)) + if call.kwargs: + arg_explanation, arg_result = self.visit(call.kwargs) + arg_name = "__exprinfo_kwds" + ns[arg_name] = arg_result + arguments.append("**%s" % (arg_name,)) + arg_explanations.append("**%s" % (arg_explanation,)) + args_explained = ", ".join(arg_explanations) + explanation = "%s(%s)" % (func_explanation, args_explained) + args = ", ".join(arguments) + source = "__exprinfo_func(%s)" % (args,) + co = self._compile(source) + try: + result = self.frame.eval(co, **ns) + except Exception: + raise Failure(explanation) + pattern = "%s\n{%s = %s\n}" + rep = self.frame.repr(result) + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def _is_builtin_name(self, name): + pattern = "%r not in globals() and %r not in locals()" + source = pattern % (name.id, name.id) + co = self._compile(source) + try: + return self.frame.eval(co) + except Exception: + return False + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + source_explanation, source_result = self.visit(attr.value) + explanation = "%s.%s" % (source_explanation, attr.attr) + source = "__exprinfo_expr.%s" % (attr.attr,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + raise Failure(explanation) + explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), + self.frame.repr(result), + source_explanation, attr.attr) + # Check if the attr is from an instance. + source = "%r in getattr(__exprinfo_expr, '__dict__', {})" + source = source % (attr.attr,) + co = self._compile(source) + try: + from_instance = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + from_instance = None + if from_instance is None or self.frame.is_true(from_instance): + rep = self.frame.repr(result) + pattern = "%s\n{%s = %s\n}" + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def visit_Assert(self, assrt): + test_explanation, test_result = self.visit(assrt.test) + explanation = "assert %s" % (test_explanation,) + if not self.frame.is_true(test_result): + try: + raise BuiltinAssertionError + except Exception: + raise Failure(explanation) + return explanation, test_result + + def visit_Assign(self, assign): + value_explanation, value_result = self.visit(assign.value) + explanation = "... = %s" % (value_explanation,) + name = ast.Name("__exprinfo_expr", ast.Load(), + lineno=assign.value.lineno, + col_offset=assign.value.col_offset) + new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, + col_offset=assign.col_offset) + mod = ast.Module([new_assign]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co, __exprinfo_expr=value_result) + except Exception: + raise Failure(explanation) + return explanation, value_result diff --git a/_pytest/assertion/oldinterpret.py b/_pytest/assertion/oldinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/oldinterpret.py @@ -0,0 +1,552 @@ +import py +import sys, inspect +from compiler import parse, ast, pycodegen +from _pytest.assertion.util import format_explanation +from _pytest.assertion.reinterpret import BuiltinAssertionError + +passthroughex = py.builtin._sysex + +class Failure: + def __init__(self, node): + self.exc, self.value, self.tb = sys.exc_info() + self.node = node + +class View(object): + """View base class. + + If C is a subclass of View, then C(x) creates a proxy object around + the object x. The actual class of the proxy is not C in general, + but a *subclass* of C determined by the rules below. To avoid confusion + we call view class the class of the proxy (a subclass of C, so of View) + and object class the class of x. + + Attributes and methods not found in the proxy are automatically read on x. + Other operations like setting attributes are performed on the proxy, as + determined by its view class. The object x is available from the proxy + as its __obj__ attribute. + + The view class selection is determined by the __view__ tuples and the + optional __viewkey__ method. By default, the selected view class is the + most specific subclass of C whose __view__ mentions the class of x. + If no such subclass is found, the search proceeds with the parent + object classes. For example, C(True) will first look for a subclass + of C with __view__ = (..., bool, ...) and only if it doesn't find any + look for one with __view__ = (..., int, ...), and then ..., object,... + If everything fails the class C itself is considered to be the default. + + Alternatively, the view class selection can be driven by another aspect + of the object x, instead of the class of x, by overriding __viewkey__. + See last example at the end of this module. + """ + + _viewcache = {} + __view__ = () + + def __new__(rootclass, obj, *args, **kwds): + self = object.__new__(rootclass) + self.__obj__ = obj + self.__rootclass__ = rootclass + key = self.__viewkey__() + try: + self.__class__ = self._viewcache[key] + except KeyError: + self.__class__ = self._selectsubclass(key) + return self + + def __getattr__(self, attr): + # attributes not found in the normal hierarchy rooted on View + # are looked up in the object's real class + return getattr(self.__obj__, attr) + + def __viewkey__(self): + return self.__obj__.__class__ + + def __matchkey__(self, key, subclasses): + if inspect.isclass(key): + keys = inspect.getmro(key) + else: + keys = [key] + for key in keys: + result = [C for C in subclasses if key in C.__view__] + if result: + return result + return [] + + def _selectsubclass(self, key): + subclasses = list(enumsubclasses(self.__rootclass__)) + for C in subclasses: + if not isinstance(C.__view__, tuple): + C.__view__ = (C.__view__,) + choices = self.__matchkey__(key, subclasses) + if not choices: + return self.__rootclass__ + elif len(choices) == 1: + return choices[0] + else: + # combine the multiple choices + return type('?', tuple(choices), {}) + + def __repr__(self): + return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) + + +def enumsubclasses(cls): + for subcls in cls.__subclasses__(): + for subsubclass in enumsubclasses(subcls): + yield subsubclass + yield cls + + +class Interpretable(View): + """A parse tree node with a few extra methods.""" + explanation = None + + def is_builtin(self, frame): + return False + + def eval(self, frame): + # fall-back for unknown expression nodes + try: + expr = ast.Expression(self.__obj__) + expr.filename = '' + self.__obj__.filename = '' + co = pycodegen.ExpressionCodeGenerator(expr).getCode() + result = frame.eval(co) + except passthroughex: + raise + except: + raise Failure(self) + self.result = result + self.explanation = self.explanation or frame.repr(self.result) + + def run(self, frame): + # fall-back for unknown statement nodes + try: + expr = ast.Module(None, ast.Stmt([self.__obj__])) + expr.filename = '' + co = pycodegen.ModuleCodeGenerator(expr).getCode() + frame.exec_(co) + except passthroughex: + raise + except: + raise Failure(self) + + def nice_explanation(self): + return format_explanation(self.explanation) + + +class Name(Interpretable): + __view__ = ast.Name + + def is_local(self, frame): + source = '%r in locals() is not globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_global(self, frame): + source = '%r in globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_builtin(self, frame): + source = '%r not in locals() and %r not in globals()' % ( + self.name, self.name) + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + super(Name, self).eval(frame) + if not self.is_local(frame): + self.explanation = self.name + +class Compare(Interpretable): + __view__ = ast.Compare + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + for operation, expr2 in self.ops: + if hasattr(self, 'result'): + # shortcutting in chained expressions + if not frame.is_true(self.result): + break + expr2 = Interpretable(expr2) + expr2.eval(frame) + self.explanation = "%s %s %s" % ( + expr.explanation, operation, expr2.explanation) + source = "__exprinfo_left %s __exprinfo_right" % operation + try: + self.result = frame.eval(source, + __exprinfo_left=expr.result, + __exprinfo_right=expr2.result) + except passthroughex: + raise + except: + raise Failure(self) + expr = expr2 + +class And(Interpretable): + __view__ = ast.And + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if not frame.is_true(expr.result): + break + self.explanation = '(' + ' and '.join(explanations) + ')' + +class Or(Interpretable): + __view__ = ast.Or + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if frame.is_true(expr.result): + break + self.explanation = '(' + ' or '.join(explanations) + ')' + + +# == Unary operations == +keepalive = [] +for astclass, astpattern in { + ast.Not : 'not __exprinfo_expr', + ast.Invert : '(~__exprinfo_expr)', + }.items(): + + class UnaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + expr = Interpretable(self.expr) + expr.eval(frame) + self.explanation = astpattern.replace('__exprinfo_expr', + expr.explanation) + try: + self.result = frame.eval(astpattern, + __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(UnaryArith) + +# == Binary operations == +for astclass, astpattern in { + ast.Add : '(__exprinfo_left + __exprinfo_right)', + ast.Sub : '(__exprinfo_left - __exprinfo_right)', + ast.Mul : '(__exprinfo_left * __exprinfo_right)', + ast.Div : '(__exprinfo_left / __exprinfo_right)', + ast.Mod : '(__exprinfo_left % __exprinfo_right)', + ast.Power : '(__exprinfo_left ** __exprinfo_right)', + }.items(): + + class BinaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + left = Interpretable(self.left) + left.eval(frame) + right = Interpretable(self.right) + right.eval(frame) + self.explanation = (astpattern + .replace('__exprinfo_left', left .explanation) + .replace('__exprinfo_right', right.explanation)) + try: + self.result = frame.eval(astpattern, + __exprinfo_left=left.result, + __exprinfo_right=right.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(BinaryArith) + + +class CallFunc(Interpretable): + __view__ = ast.CallFunc + + def is_bool(self, frame): + source = 'isinstance(__exprinfo_value, bool)' + try: + return frame.is_true(frame.eval(source, + __exprinfo_value=self.result)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + node = Interpretable(self.node) + node.eval(frame) + explanations = [] + vars = {'__exprinfo_fn': node.result} + source = '__exprinfo_fn(' + for a in self.args: + if isinstance(a, ast.Keyword): + keyword = a.name + a = a.expr + else: + keyword = None + a = Interpretable(a) + a.eval(frame) + argname = '__exprinfo_%d' % len(vars) + vars[argname] = a.result + if keyword is None: + source += argname + ',' + explanations.append(a.explanation) + else: + source += '%s=%s,' % (keyword, argname) + explanations.append('%s=%s' % (keyword, a.explanation)) + if self.star_args: + star_args = Interpretable(self.star_args) + star_args.eval(frame) + argname = '__exprinfo_star' + vars[argname] = star_args.result + source += '*' + argname + ',' + explanations.append('*' + star_args.explanation) + if self.dstar_args: + dstar_args = Interpretable(self.dstar_args) + dstar_args.eval(frame) + argname = '__exprinfo_kwds' + vars[argname] = dstar_args.result + source += '**' + argname + ',' + explanations.append('**' + dstar_args.explanation) + self.explanation = "%s(%s)" % ( + node.explanation, ', '.join(explanations)) + if source.endswith(','): + source = source[:-1] + source += ')' + try: + self.result = frame.eval(source, **vars) + except passthroughex: + raise + except: + raise Failure(self) + if not node.is_builtin(frame) or not self.is_bool(frame): + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +class Getattr(Interpretable): + __view__ = ast.Getattr + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + source = '__exprinfo_expr.%s' % self.attrname + try: + self.result = frame.eval(source, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + self.explanation = '%s.%s' % (expr.explanation, self.attrname) + # if the attribute comes from the instance, its value is interesting + source = ('hasattr(__exprinfo_expr, "__dict__") and ' + '%r in __exprinfo_expr.__dict__' % self.attrname) + try: + from_instance = frame.is_true( + frame.eval(source, __exprinfo_expr=expr.result)) + except passthroughex: + raise + except: + from_instance = True + if from_instance: + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +# == Re-interpretation of full statements == + +class Assert(Interpretable): + __view__ = ast.Assert + + def run(self, frame): + test = Interpretable(self.test) + test.eval(frame) + # print the result as 'assert ' + self.result = test.result + self.explanation = 'assert ' + test.explanation + if not frame.is_true(test.result): + try: + raise BuiltinAssertionError + except passthroughex: + raise + except: + raise Failure(self) + +class Assign(Interpretable): + __view__ = ast.Assign + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = '... = ' + expr.explanation + # fall-back-run the rest of the assignment + ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) + mod = ast.Module(None, ast.Stmt([ass])) + mod.filename = '' + co = pycodegen.ModuleCodeGenerator(mod).getCode() + try: + frame.exec_(co, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + +class Discard(Interpretable): + __view__ = ast.Discard + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = expr.explanation + +class Stmt(Interpretable): + __view__ = ast.Stmt + + def run(self, frame): + for stmt in self.nodes: + stmt = Interpretable(stmt) + stmt.run(frame) + + +def report_failure(e): + explanation = e.node.nice_explanation() + if explanation: + explanation = ", in: " + explanation + else: + explanation = "" + sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) + +def check(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + expr = parse(s, 'eval') + assert isinstance(expr, ast.Expression) + node = Interpretable(expr.node) + try: + node.eval(frame) + except passthroughex: + raise + except Failure: + e = sys.exc_info()[1] + report_failure(e) + else: + if not frame.is_true(node.result): + sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) + + +########################################################### +# API / Entry points +# ######################################################### + +def interpret(source, frame, should_fail=False): + module = Interpretable(parse(source, 'exec').node) + #print "got module", module + if isinstance(frame, py.std.types.FrameType): + frame = py.code.Frame(frame) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + return getfailure(e) + except passthroughex: + raise + except: + import traceback + traceback.print_exc() + if should_fail: + return ("(assertion failed, but when it was re-run for " + "printing intermediate values, it did not fail. Suggestions: " + "compute assert expression before the assert or use --nomagic)") + else: + return None + +def getmsg(excinfo): + if isinstance(excinfo, tuple): + excinfo = py.code.ExceptionInfo(excinfo) + #frame, line = gettbline(tb) + #frame = py.code.Frame(frame) + #return interpret(line, frame) + + tb = excinfo.traceback[-1] + source = str(tb.statement).strip() + x = interpret(source, tb.frame, should_fail=True) + if not isinstance(x, str): + raise TypeError("interpret returned non-string %r" % (x,)) + return x + +def getfailure(e): + explanation = e.node.nice_explanation() + if str(e.value): + lines = explanation.split('\n') + lines[0] += " << %s" % (e.value,) + explanation = '\n'.join(lines) + text = "%s: %s" % (e.exc.__name__, explanation) + if text.startswith('AssertionError: assert '): + text = text[16:] + return text + +def run(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + module = Interpretable(parse(s, 'exec').node) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + report_failure(e) + + +if __name__ == '__main__': + # example: + def f(): + return 5 + def g(): + return 3 + def h(x): + return 'never' + check("f() * g() == 5") + check("not f()") + check("not (f() and g() or 0)") + check("f() == g()") + i = 4 + check("i == f()") + check("len(f()) == 0") + check("isinstance(2+3+4, float)") + + run("x = i") + check("x == 5") + + run("assert not f(), 'oops'") + run("a, b, c = 1, 2") + run("a, b, c = f()") + + check("max([f(),g()]) == 4") + check("'hello'[g()] == 'h'") + run("'guk%d' % h(f())") diff --git a/_pytest/assertion/reinterpret.py b/_pytest/assertion/reinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/reinterpret.py @@ -0,0 +1,48 @@ +import sys +import py + +BuiltinAssertionError = py.builtin.builtins.AssertionError + +class AssertionError(BuiltinAssertionError): + def __init__(self, *args): + BuiltinAssertionError.__init__(self, *args) + if args: + try: + self.msg = str(args[0]) + except py.builtin._sysex: + raise + except: + self.msg = "<[broken __repr__] %s at %0xd>" %( + args[0].__class__, id(args[0])) + else: + f = py.code.Frame(sys._getframe(1)) + try: + source = f.code.fullsource + if source is not None: + try: + source = source.getstatement(f.lineno, assertion=True) + except IndexError: + source = None + else: + source = str(source.deindent()).strip() + except py.error.ENOENT: + source = None + # this can also occur during reinterpretation, when the + # co_filename is set to "". + if source: + self.msg = reinterpret(source, f, should_fail=True) + else: + self.msg = "" + if not self.args: + self.args = (self.msg,) + +if sys.version_info > (3, 0): + AssertionError.__module__ = "builtins" + reinterpret_old = "old reinterpretation not available for py3" +else: + from _pytest.assertion.oldinterpret import interpret as reinterpret_old +if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): + from _pytest.assertion.newinterpret import interpret as reinterpret +else: + reinterpret = reinterpret_old + diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/rewrite.py @@ -0,0 +1,340 @@ +"""Rewrite assertion AST to produce nice error messages""" + +import ast +import collections +import itertools +import sys + +import py +from _pytest.assertion import util + + +def rewrite_asserts(mod): + """Rewrite the assert statements in mod.""" + AssertionRewriter().run(mod) + + +_saferepr = py.io.saferepr +from _pytest.assertion.util import format_explanation as _format_explanation + +def _format_boolop(operands, explanations, is_or): + show_explanations = [] + for operand, expl in zip(operands, explanations): + show_explanations.append(expl) + if operand == is_or: + break + return "(" + (is_or and " or " or " and ").join(show_explanations) + ")" + +def _call_reprcompare(ops, results, expls, each_obj): + for i, res, expl in zip(range(len(ops)), results, expls): + try: + done = not res + except Exception: + done = True + if done: + break + if util._reprcompare is not None: + custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1]) + if custom is not None: + return custom + return expl + + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + +binop_map = { + ast.BitOr : "|", + ast.BitXor : "^", + ast.BitAnd : "&", + ast.LShift : "<<", + ast.RShift : ">>", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + + +def set_location(node, lineno, col_offset): + """Set node location information recursively.""" + def _fix(node, lineno, col_offset): + if "lineno" in node._attributes: + node.lineno = lineno + if "col_offset" in node._attributes: + node.col_offset = col_offset + for child in ast.iter_child_nodes(node): + _fix(child, lineno, col_offset) + _fix(node, lineno, col_offset) + return node + + +class AssertionRewriter(ast.NodeVisitor): + + def run(self, mod): + """Find all assert statements in *mod* and rewrite them.""" + if not mod.body: + # Nothing to do. + return + # Insert some special imports at the top of the module but after any + # docstrings and __future__ imports. + aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"), + ast.alias("_pytest.assertion.rewrite", "@pytest_ar")] + expect_docstring = True + pos = 0 + lineno = 0 + for item in mod.body: + if (expect_docstring and isinstance(item, ast.Expr) and + isinstance(item.value, ast.Str)): + doc = item.value.s + if "PYTEST_DONT_REWRITE" in doc: + # The module has disabled assertion rewriting. + return + lineno += len(doc) - 1 + expect_docstring = False + elif (not isinstance(item, ast.ImportFrom) or item.level > 0 and + item.identifier != "__future__"): + lineno = item.lineno + break + pos += 1 + imports = [ast.Import([alias], lineno=lineno, col_offset=0) + for alias in aliases] + mod.body[pos:pos] = imports + # Collect asserts. + nodes = collections.deque([mod]) + while nodes: + node = nodes.popleft() + for name, field in ast.iter_fields(node): + if isinstance(field, list): + new = [] + for i, child in enumerate(field): + if isinstance(child, ast.Assert): + # Transform assert. + new.extend(self.visit(child)) + else: + new.append(child) + if isinstance(child, ast.AST): + nodes.append(child) + setattr(node, name, new) + elif (isinstance(field, ast.AST) and + # Don't recurse into expressions as they can't contain + # asserts. + not isinstance(field, ast.expr)): + nodes.append(field) + + def variable(self): + """Get a new variable.""" + # Use a character invalid in python identifiers to avoid clashing. + name = "@py_assert" + str(next(self.variable_counter)) + self.variables.add(name) + return name + + def assign(self, expr): + """Give *expr* a name.""" + name = self.variable() + self.statements.append(ast.Assign([ast.Name(name, ast.Store())], expr)) + return ast.Name(name, ast.Load()) + + def display(self, expr): + """Call py.io.saferepr on the expression.""" + return self.helper("saferepr", expr) + + def helper(self, name, *args): + """Call a helper in this module.""" + py_name = ast.Name("@pytest_ar", ast.Load()) + attr = ast.Attribute(py_name, "_" + name, ast.Load()) + return ast.Call(attr, list(args), [], None, None) + + def builtin(self, name): + """Return the builtin called *name*.""" + builtin_name = ast.Name("@py_builtins", ast.Load()) + return ast.Attribute(builtin_name, name, ast.Load()) + + def explanation_param(self, expr): + specifier = "py" + str(next(self.variable_counter)) + self.explanation_specifiers[specifier] = expr + return "%(" + specifier + ")s" + + def push_format_context(self): + self.explanation_specifiers = {} + self.stack.append(self.explanation_specifiers) + + def pop_format_context(self, expl_expr): + current = self.stack.pop() + if self.stack: + self.explanation_specifiers = self.stack[-1] + keys = [ast.Str(key) for key in current.keys()] + format_dict = ast.Dict(keys, list(current.values())) + form = ast.BinOp(expl_expr, ast.Mod(), format_dict) + name = "@py_format" + str(next(self.variable_counter)) + self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form)) + return ast.Name(name, ast.Load()) + + def generic_visit(self, node): + """Handle expressions we don't have custom code for.""" + assert isinstance(node, ast.expr) + res = self.assign(node) + return res, self.explanation_param(self.display(res)) + + def visit_Assert(self, assert_): + if assert_.msg: + # There's already a message. Don't mess with it. + return [assert_] + self.statements = [] + self.variables = set() + self.variable_counter = itertools.count() + self.stack = [] + self.on_failure = [] + self.push_format_context() + # Rewrite assert into a bunch of statements. + top_condition, explanation = self.visit(assert_.test) + # Create failure message. + body = self.on_failure + negation = ast.UnaryOp(ast.Not(), top_condition) + self.statements.append(ast.If(negation, body, [])) + explanation = "assert " + explanation + template = ast.Str(explanation) + msg = self.pop_format_context(template) + fmt = self.helper("format_explanation", msg) + err_name = ast.Name("AssertionError", ast.Load()) + exc = ast.Call(err_name, [fmt], [], None, None) + if sys.version_info[0] >= 3: + raise_ = ast.Raise(exc, None) + else: + raise_ = ast.Raise(exc, None, None) + body.append(raise_) + # Delete temporary variables. + names = [ast.Name(name, ast.Del()) for name in self.variables] + if names: + delete = ast.Delete(names) + self.statements.append(delete) + # Fix line numbers. + for stmt in self.statements: + set_location(stmt, assert_.lineno, assert_.col_offset) + return self.statements + + def visit_Name(self, name): + # Check if the name is local or not. + locs = ast.Call(self.builtin("locals"), [], [], None, None) + globs = ast.Call(self.builtin("globals"), [], [], None, None) + ops = [ast.In(), ast.IsNot()] + test = ast.Compare(ast.Str(name.id), ops, [locs, globs]) + expr = ast.IfExp(test, self.display(name), ast.Str(name.id)) + return name, self.explanation_param(expr) + + def visit_BoolOp(self, boolop): + operands = [] + explanations = [] + self.push_format_context() + for operand in boolop.values: + res, explanation = self.visit(operand) + operands.append(res) + explanations.append(explanation) + expls = ast.Tuple([ast.Str(expl) for expl in explanations], ast.Load()) + is_or = ast.Num(isinstance(boolop.op, ast.Or)) + expl_template = self.helper("format_boolop", + ast.Tuple(operands, ast.Load()), expls, + is_or) + expl = self.pop_format_context(expl_template) + res = self.assign(ast.BoolOp(boolop.op, operands)) + return res, self.explanation_param(expl) + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_res, operand_expl = self.visit(unary.operand) + res = self.assign(ast.UnaryOp(unary.op, operand_res)) + return res, pattern % (operand_expl,) + + def visit_BinOp(self, binop): + symbol = binop_map[binop.op.__class__] + left_expr, left_expl = self.visit(binop.left) + right_expr, right_expl = self.visit(binop.right) + explanation = "(%s %s %s)" % (left_expl, symbol, right_expl) + res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) + return res, explanation + + def visit_Call(self, call): + new_func, func_expl = self.visit(call.func) + arg_expls = [] + new_args = [] + new_kwargs = [] + new_star = new_kwarg = None + for arg in call.args: + res, expl = self.visit(arg) + new_args.append(res) + arg_expls.append(expl) + for keyword in call.keywords: + res, expl = self.visit(keyword.value) + new_kwargs.append(ast.keyword(keyword.arg, res)) + arg_expls.append(keyword.arg + "=" + expl) + if call.starargs: + new_star, expl = self.visit(call.starargs) + arg_expls.append("*" + expl) + if call.kwargs: + new_kwarg, expl = self.visit(call.kwarg) + arg_expls.append("**" + expl) + expl = "%s(%s)" % (func_expl, ', '.join(arg_expls)) + new_call = ast.Call(new_func, new_args, new_kwargs, new_star, new_kwarg) + res = self.assign(new_call) + res_expl = self.explanation_param(self.display(res)) + outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl) + return res, outer_expl + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + value, value_expl = self.visit(attr.value) + res = self.assign(ast.Attribute(value, attr.attr, ast.Load())) + res_expl = self.explanation_param(self.display(res)) + pat = "%s\n{%s = %s.%s\n}" + expl = pat % (res_expl, res_expl, value_expl, attr.attr) + return res, expl + + def visit_Compare(self, comp): + self.push_format_context() + left_res, left_expl = self.visit(comp.left) + res_variables = [self.variable() for i in range(len(comp.ops))] + load_names = [ast.Name(v, ast.Load()) for v in res_variables] + store_names = [ast.Name(v, ast.Store()) for v in res_variables] + it = zip(range(len(comp.ops)), comp.ops, comp.comparators) + expls = [] + syms = [] + results = [left_res] + for i, op, next_operand in it: + next_res, next_expl = self.visit(next_operand) + results.append(next_res) + sym = binop_map[op.__class__] + syms.append(ast.Str(sym)) + expl = "%s %s %s" % (left_expl, sym, next_expl) + expls.append(ast.Str(expl)) + res_expr = ast.Compare(left_res, [op], [next_res]) + self.statements.append(ast.Assign([store_names[i]], res_expr)) + left_res, left_expl = next_res, next_expl + # Use py.code._reprcompare if that's available. + expl_call = self.helper("call_reprcompare", + ast.Tuple(syms, ast.Load()), + ast.Tuple(load_names, ast.Load()), + ast.Tuple(expls, ast.Load()), + ast.Tuple(results, ast.Load())) + if len(comp.ops) > 1: + res = ast.BoolOp(ast.And(), load_names) + else: + res = load_names[0] + return res, self.explanation_param(self.pop_format_context(expl_call)) diff --git a/_pytest/assertion/util.py b/_pytest/assertion/util.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/util.py @@ -0,0 +1,213 @@ +"""Utilities for assertion debugging""" + +import py + + +# The _reprcompare attribute on the util module is used by the new assertion +# interpretation code and assertion rewriter to detect this plugin was +# loaded and in turn call the hooks defined here as part of the +# DebugInterpreter. +_reprcompare = None + +def format_explanation(explanation): + """This formats an explanation + + Normally all embedded newlines are escaped, however there are + three exceptions: \n{, \n} and \n~. The first two are intended + cover nested explanations, see function and attribute explanations + for examples (.visit_Call(), visit_Attribute()). The last one is + for when one explanation needs to span multiple lines, e.g. when + displaying diffs. + """ + # simplify 'assert False where False = ...' + where = 0 + while True: + start = where = explanation.find("False\n{False = ", where) + if where == -1: + break + level = 0 + for i, c in enumerate(explanation[start:]): + if c == "{": + level += 1 + elif c == "}": + level -= 1 + if not level: + break + else: + raise AssertionError("unbalanced braces: %r" % (explanation,)) + end = start + i + where = end + if explanation[end - 1] == '\n': + explanation = (explanation[:start] + explanation[start+15:end-1] + + explanation[end+1:]) + where -= 17 + raw_lines = (explanation or '').split('\n') + # escape newlines not followed by {, } and ~ + lines = [raw_lines[0]] + for l in raw_lines[1:]: + if l.startswith('{') or l.startswith('}') or l.startswith('~'): + lines.append(l) + else: + lines[-1] += '\\n' + l + + result = lines[:1] + stack = [0] + stackcnt = [0] + for line in lines[1:]: + if line.startswith('{'): + if stackcnt[-1]: + s = 'and ' + else: + s = 'where ' + stack.append(len(result)) + stackcnt[-1] += 1 + stackcnt.append(0) + result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) + elif line.startswith('}'): + assert line.startswith('}') + stack.pop() + stackcnt.pop() + result[stack[-1]] += line[1:] + else: + assert line.startswith('~') + result.append(' '*len(stack) + line[1:]) + assert len(stack) == 1 + return '\n'.join(result) + + +# Provide basestring in python3 +try: + basestring = basestring +except NameError: + basestring = str + + +def assertrepr_compare(op, left, right): + """return specialised explanations for some operators/operands""" + width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op + left_repr = py.io.saferepr(left, maxsize=int(width/2)) + right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) + summary = '%s %s %s' % (left_repr, op, right_repr) + + issequence = lambda x: isinstance(x, (list, tuple)) + istext = lambda x: isinstance(x, basestring) + isdict = lambda x: isinstance(x, dict) + isset = lambda x: isinstance(x, set) + + explanation = None + try: + if op == '==': + if istext(left) and istext(right): + explanation = _diff_text(left, right) + elif issequence(left) and issequence(right): + explanation = _compare_eq_sequence(left, right) + elif isset(left) and isset(right): + explanation = _compare_eq_set(left, right) + elif isdict(left) and isdict(right): + explanation = _diff_text(py.std.pprint.pformat(left), + py.std.pprint.pformat(right)) + elif op == 'not in': + if istext(left) and istext(right): + explanation = _notin_text(left, right) + except py.builtin._sysex: + raise + except: + excinfo = py.code.ExceptionInfo() + explanation = ['(pytest_assertion plugin: representation of ' + 'details failed. Probably an object has a faulty __repr__.)', + str(excinfo) + ] + + + if not explanation: + return None + + # Don't include pageloads of data, should be configurable + if len(''.join(explanation)) > 80*8: + explanation = ['Detailed information too verbose, truncated'] + + return [summary] + explanation + + +def _diff_text(left, right): + """Return the explanation for the diff between text + + This will skip leading and trailing characters which are + identical to keep the diff minimal. + """ + explanation = [] + i = 0 # just in case left or right has zero length + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + break + if i > 42: + i -= 10 # Provide some context + explanation = ['Skipping %s identical ' + 'leading characters in diff' % i] + left = left[i:] + right = right[i:] + if len(left) == len(right): + for i in range(len(left)): + if left[-i] != right[-i]: + break + if i > 42: + i -= 10 # Provide some context + explanation += ['Skipping %s identical ' + 'trailing characters in diff' % i] + left = left[:-i] + right = right[:-i] + explanation += [line.strip('\n') + for line in py.std.difflib.ndiff(left.splitlines(), + right.splitlines())] + return explanation + + +def _compare_eq_sequence(left, right): + explanation = [] + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + explanation += ['At index %s diff: %r != %r' % + (i, left[i], right[i])] + break + if len(left) > len(right): + explanation += ['Left contains more items, ' + 'first extra item: %s' % py.io.saferepr(left[len(right)],)] + elif len(left) < len(right): + explanation += ['Right contains more items, ' + 'first extra item: %s' % py.io.saferepr(right[len(left)],)] + return explanation # + _diff_text(py.std.pprint.pformat(left), + # py.std.pprint.pformat(right)) + + +def _compare_eq_set(left, right): + explanation = [] + diff_left = left - right + diff_right = right - left + if diff_left: + explanation.append('Extra items in the left set:') + for item in diff_left: + explanation.append(py.io.saferepr(item)) + if diff_right: + explanation.append('Extra items in the right set:') + for item in diff_right: + explanation.append(py.io.saferepr(item)) + return explanation + + +def _notin_text(term, text): + index = text.find(term) + head = text[:index] + tail = text[index+len(term):] + correct_text = head + tail + diff = _diff_text(correct_text, text) + newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] + for line in diff: + if line.startswith('Skipping'): + continue + if line.startswith('- '): + continue + if line.startswith('+ '): + newdiff.append(' ' + line[2:]) + else: + newdiff.append(line) + return newdiff diff --git a/_pytest/doctest.py b/_pytest/doctest.py --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -59,7 +59,7 @@ inner_excinfo = py.code.ExceptionInfo(excinfo.value.exc_info) lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)] - + lines += py.std.traceback.format_exception(*excinfo.value.exc_info) return ReprFailDoctest(reprlocation, lines) else: return super(DoctestItem, self).repr_failure(excinfo) diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -16,9 +16,6 @@ group.addoption('--traceconfig', action="store_true", dest="traceconfig", default=False, help="trace considerations of conftest.py files."), - group._addoption('--nomagic', - action="store_true", dest="nomagic", default=False, - help="don't reinterpret asserts, no traceback cutting. ") group.addoption('--debug', action="store_true", dest="debug", default=False, help="generate and show internal debugging information.") diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -65,7 +65,8 @@ class LogXML(object): def __init__(self, logfile, prefix): - self.logfile = logfile + logfile = os.path.expanduser(os.path.expandvars(logfile)) + self.logfile = os.path.normpath(logfile) self.prefix = prefix self.test_logs = [] self.passed = self.skipped = 0 @@ -76,7 +77,7 @@ names = report.nodeid.split("::") names[0] = names[0].replace("/", '.') names = tuple(names) - d = {'time': self._durations.pop(names, "0")} + d = {'time': self._durations.pop(report.nodeid, "0")} names = [x.replace(".py", "") for x in names if x != "()"] classnames = names[:-1] if self.prefix: @@ -170,12 +171,11 @@ self.append_skipped(report) def pytest_runtest_call(self, item, __multicall__): - names = tuple(item.listnames()) start = time.time() try: return __multicall__.execute() finally: - self._durations[names] = time.time() - start + self._durations[item.nodeid] = time.time() - start def pytest_collectreport(self, report): if not report.passed: diff --git a/_pytest/main.py b/_pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -46,23 +46,25 @@ def pytest_namespace(): - return dict(collect=dict(Item=Item, Collector=Collector, File=File)) + collect = dict(Item=Item, Collector=Collector, File=File, Session=Session) + return dict(collect=collect) def pytest_configure(config): py.test.config = config # compatibiltiy if config.option.exitfirst: config.option.maxfail = 1 -def pytest_cmdline_main(config): - """ default command line protocol for initialization, session, - running tests and reporting. """ +def wrap_session(config, doit): + """Skeleton command line program""" session = Session(config) session.exitstatus = EXIT_OK + initstate = 0 try: config.pluginmanager.do_configure(config) + initstate = 1 config.hook.pytest_sessionstart(session=session) - config.hook.pytest_collection(session=session) - config.hook.pytest_runtestloop(session=session) + initstate = 2 + doit(config, session) except pytest.UsageError: raise except KeyboardInterrupt: @@ -77,18 +79,24 @@ sys.stderr.write("mainloop: caught Spurious SystemExit!\n") if not session.exitstatus and session._testsfailed: session.exitstatus = EXIT_TESTSFAILED - config.hook.pytest_sessionfinish(session=session, - exitstatus=session.exitstatus) - config.pluginmanager.do_unconfigure(config) + if initstate >= 2: + config.hook.pytest_sessionfinish(session=session, + exitstatus=session.exitstatus) + if initstate >= 1: + config.pluginmanager.do_unconfigure(config) return session.exitstatus +def pytest_cmdline_main(config): + return wrap_session(config, _main) + +def _main(config, session): + """ default command line protocol for initialization, session, + running tests and reporting. """ + config.hook.pytest_collection(session=session) + config.hook.pytest_runtestloop(session=session) + def pytest_collection(session): - session.perform_collect() - hook = session.config.hook - hook.pytest_collection_modifyitems(session=session, - config=session.config, items=session.items) - hook.pytest_collection_finish(session=session) - return True + return session.perform_collect() def pytest_runtestloop(session): if session.config.option.collectonly: @@ -374,6 +382,16 @@ return HookProxy(fspath, self.config) def perform_collect(self, args=None, genitems=True): + hook = self.config.hook + try: + items = self._perform_collect(args, genitems) + hook.pytest_collection_modifyitems(session=self, + config=self.config, items=items) + finally: + hook.pytest_collection_finish(session=self) + return items + + def _perform_collect(self, args, genitems): if args is None: args = self.config.args self.trace("perform_collect", self, args) diff --git a/_pytest/mark.py b/_pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -153,7 +153,7 @@ def __repr__(self): return "" % ( - self._name, self.args, self.kwargs) + self.name, self.args, self.kwargs) def pytest_itemcollected(item): if not isinstance(item, pytest.Function): diff --git a/_pytest/pytester.py b/_pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -6,7 +6,7 @@ import inspect import time from fnmatch import fnmatch -from _pytest.main import Session +from _pytest.main import Session, EXIT_OK from py.builtin import print_ from _pytest.core import HookRelay @@ -292,13 +292,19 @@ assert '::' not in str(arg) p = py.path.local(arg) x = session.fspath.bestrelpath(p) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def getpathnode(self, path): - config = self.parseconfig(path) + config = self.parseconfigure(path) session = Session(config) x = session.fspath.bestrelpath(path) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def genitems(self, colitems): session = colitems[0].session @@ -312,7 +318,9 @@ config = self.parseconfigure(*args) rec = self.getreportrecorder(config) session = Session(config) + config.hook.pytest_sessionstart(session=session) session.perform_collect() + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) return session.items, rec def runitem(self, source): @@ -382,6 +390,8 @@ c.basetemp = py.path.local.make_numbered_dir(prefix="reparse", keep=0, rootdir=self.tmpdir, lock_timeout=None) c.parse(args) + c.pluginmanager.do_configure(c) + self.request.addfinalizer(lambda: c.pluginmanager.do_unconfigure(c)) return c finally: py.test.config = oldconfig diff --git a/_pytest/python.py b/_pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -226,8 +226,13 @@ def _importtestmodule(self): # we assume we are only called once per module + from _pytest import assertion + assertion.before_module_import(self) try: - mod = self.fspath.pyimport(ensuresyspath=True) + try: + mod = self.fspath.pyimport(ensuresyspath=True) + finally: + assertion.after_module_import(self) except SyntaxError: excinfo = py.code.ExceptionInfo() raise self.CollectError(excinfo.getrepr(style="short")) @@ -374,7 +379,7 @@ # test generators are seen as collectors but they also # invoke setup/teardown on popular request # (induced by the common "test_*" naming shared with normal tests) - self.config._setupstate.prepare(self) + self.session._setupstate.prepare(self) # see FunctionMixin.setup and test_setupstate_is_preserved_134 self._preservedparent = self.parent.obj l = [] @@ -721,7 +726,7 @@ def _addfinalizer(self, finalizer, scope): colitem = self._getscopeitem(scope) - self.config._setupstate.addfinalizer( + self._pyfuncitem.session._setupstate.addfinalizer( finalizer=finalizer, colitem=colitem) def __repr__(self): @@ -742,8 +747,10 @@ raise self.LookupError(msg) def showfuncargs(config): - from _pytest.main import Session - session = Session(config) + from _pytest.main import wrap_session + return wrap_session(config, _showfuncargs_main) + +def _showfuncargs_main(config, session): session.perform_collect() if session.items: plugins = session.items[0].getplugins() diff --git a/_pytest/runner.py b/_pytest/runner.py --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -14,17 +14,15 @@ # # pytest plugin hooks -# XXX move to pytest_sessionstart and fix py.test owns tests -def pytest_configure(config): - config._setupstate = SetupState() +def pytest_sessionstart(session): + session._setupstate = SetupState() def pytest_sessionfinish(session, exitstatus): - if hasattr(session.config, '_setupstate'): - hook = session.config.hook - rep = hook.pytest__teardown_final(session=session) - if rep: - hook.pytest__teardown_final_logerror(session=session, report=rep) - session.exitstatus = 1 + hook = session.config.hook + rep = hook.pytest__teardown_final(session=session) + if rep: + hook.pytest__teardown_final_logerror(session=session, report=rep) + session.exitstatus = 1 class NodeInfo: def __init__(self, location): @@ -46,16 +44,16 @@ return reports def pytest_runtest_setup(item): - item.config._setupstate.prepare(item) + item.session._setupstate.prepare(item) def pytest_runtest_call(item): item.runtest() def pytest_runtest_teardown(item): - item.config._setupstate.teardown_exact(item) + item.session._setupstate.teardown_exact(item) def pytest__teardown_final(session): - call = CallInfo(session.config._setupstate.teardown_all, when="teardown") + call = CallInfo(session._setupstate.teardown_all, when="teardown") if call.excinfo: ntraceback = call.excinfo.traceback .cut(excludepath=py._pydir) call.excinfo.traceback = ntraceback.filter() diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,14 +4399,8 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) - self.assertTrue(l.__add__.im_class is list) + self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__objclass__ is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/lib-python/modified-2.7/test/test_extcall.py b/lib-python/modified-2.7/test/test_extcall.py --- a/lib-python/modified-2.7/test/test_extcall.py +++ b/lib-python/modified-2.7/test/test_extcall.py @@ -299,7 +299,7 @@ def f(a): return a self.assertEqual(f(**{u'a': 4}), 4) - self.assertRaises(TypeError, lambda: f(**{u'stören': 4})) + self.assertRaises(TypeError, f, **{u'stören': 4}) self.assertRaises(TypeError, f, **{u'someLongString':2}) try: f(a=4, **{u'a': 4}) diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -275,7 +275,8 @@ return unicode(x, 'utf-8') class Connection(object): - def __init__(self, database, isolation_level="", detect_types=0, timeout=None, cached_statements=None, factory=None): + def __init__(self, database, timeout=5.0, detect_types=0, isolation_level="", + check_same_thread=True, factory=None, cached_statements=100): self.db = c_void_p() if sqlite.sqlite3_open(database, byref(self.db)) != SQLITE_OK: raise OperationalError("Could not open database") @@ -308,7 +309,8 @@ self._aggregates = {} self.aggregate_instances = {} self._collations = {} - self.thread_ident = thread_get_ident() + if check_same_thread: + self.thread_ident = thread_get_ident() def _get_exception(self, error_code = None): if error_code is None: diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py --- a/lib_pypy/datetime.py +++ b/lib_pypy/datetime.py @@ -1422,12 +1422,17 @@ converter = _time.localtime else: converter = _time.gmtime - if 1 - (t % 1.0) < 0.000001: - t = float(int(t)) + 1 - if t < 0: - t -= 1 + if t < 0.0: + us = int(round(((-t) % 1.0) * 1000000)) + if us > 0: + us = 1000000 - us + t -= 1.0 + else: + us = int(round((t % 1.0) * 1000000)) + if us == 1000000: + us = 0 + t += 1.0 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) - us = int((t % 1.0) * 1000000) ss = min(ss, 59) # clamp out leap seconds if the platform has them result = cls(y, m, d, hh, mm, ss, us, tz) if tz is not None: diff --git a/lib_pypy/msvcrt.py b/lib_pypy/msvcrt.py --- a/lib_pypy/msvcrt.py +++ b/lib_pypy/msvcrt.py @@ -46,4 +46,42 @@ e = get_errno() raise IOError(e, errno.errorcode[e]) +# Console I/O routines + +kbhit = _c._kbhit +kbhit.argtypes = [] +kbhit.restype = ctypes.c_int + +getch = _c._getch +getch.argtypes = [] +getch.restype = ctypes.c_char + +getwch = _c._getwch +getwch.argtypes = [] +getwch.restype = ctypes.c_wchar + +getche = _c._getche +getche.argtypes = [] +getche.restype = ctypes.c_char + +getwche = _c._getwche +getwche.argtypes = [] +getwche.restype = ctypes.c_wchar + +putch = _c._putch +putch.argtypes = [ctypes.c_char] +putch.restype = None + +putwch = _c._putwch +putwch.argtypes = [ctypes.c_wchar] +putwch.restype = None + +ungetch = _c._ungetch +ungetch.argtypes = [ctypes.c_char] +ungetch.restype = None + +ungetwch = _c._ungetwch +ungetwch.argtypes = [ctypes.c_wchar] +ungetwch.restype = None + del ctypes diff --git a/lib_pypy/pypy_test/test_datetime.py b/lib_pypy/pypy_test/test_datetime.py --- a/lib_pypy/pypy_test/test_datetime.py +++ b/lib_pypy/pypy_test/test_datetime.py @@ -32,4 +32,28 @@ assert datetime.datetime.utcfromtimestamp(a).microsecond == 0 assert datetime.datetime.utcfromtimestamp(a).second == 1 - +def test_more_datetime_rounding(): + # this test verified on top of CPython 2.7 (using a plain + # "import datetime" above) + expected_results = { + -1000.0: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.9999996: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.4: 'datetime.datetime(1970, 1, 1, 0, 43, 20, 600000)', + -999.0000004: 'datetime.datetime(1970, 1, 1, 0, 43, 21)', + -1.0: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.9999996: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.4: 'datetime.datetime(1970, 1, 1, 0, 59, 59, 600000)', + -0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.4: 'datetime.datetime(1970, 1, 1, 1, 0, 0, 400000)', + 0.9999996: 'datetime.datetime(1970, 1, 1, 1, 0, 1)', + 1000.0: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.0000004: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.4: 'datetime.datetime(1970, 1, 1, 1, 16, 40, 400000)', + 1000.9999996: 'datetime.datetime(1970, 1, 1, 1, 16, 41)', + 1293843661.191: 'datetime.datetime(2011, 1, 1, 2, 1, 1, 191000)', + } + for t in sorted(expected_results): + dt = datetime.datetime.fromtimestamp(t) + assert repr(dt) == expected_results[t] diff --git a/lib_pypy/resource.py b/lib_pypy/resource.py --- a/lib_pypy/resource.py +++ b/lib_pypy/resource.py @@ -7,7 +7,7 @@ from ctypes_support import standard_c_lib as libc from ctypes_support import get_errno -from ctypes import Structure, c_int, c_long, byref, sizeof +from ctypes import Structure, c_int, c_long, byref, sizeof, POINTER from errno import EINVAL, EPERM import _structseq @@ -25,6 +25,8 @@ _setrlimit = libc.setrlimit try: _getpagesize = libc.getpagesize + _getpagesize.argtypes = () + _getpagesize.restype = c_int except AttributeError: from os import sysconf _getpagesize = None @@ -61,6 +63,10 @@ ("ru_nivcsw", c_long), ) +_getrusage.argtypes = (c_int, POINTER(_struct_rusage)) +_getrusage.restype = c_int + + class struct_rusage: __metaclass__ = _structseq.structseqtype @@ -94,6 +100,12 @@ ("rlim_max", rlim_t), ) +_getrlimit.argtypes = (c_int, POINTER(rlimit)) +_getrlimit.restype = c_int +_setrlimit.argtypes = (c_int, POINTER(rlimit)) +_setrlimit.restype = c_int + + @builtinify def getrusage(who): ru = _struct_rusage() diff --git a/py/__init__.py b/py/__init__.py --- a/py/__init__.py +++ b/py/__init__.py @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2010 """ -__version__ = '1.4.3' +__version__ = '1.4.4.dev1' from py import _apipkg @@ -70,10 +70,6 @@ 'getrawcode' : '._code.code:getrawcode', 'patch_builtins' : '._code.code:patch_builtins', 'unpatch_builtins' : '._code.code:unpatch_builtins', - '_AssertionError' : '._code.assertion:AssertionError', - '_reinterpret_old' : '._code.assertion:reinterpret_old', - '_reinterpret' : '._code.assertion:reinterpret', - '_reprcompare' : '._code.assertion:_reprcompare', }, # backports and additions of builtins diff --git a/py/_code/_assertionnew.py b/py/_code/_assertionnew.py deleted file mode 100644 --- a/py/_code/_assertionnew.py +++ /dev/null @@ -1,339 +0,0 @@ -""" -Find intermediate evalutation results in assert statements through builtin AST. -This should replace _assertionold.py eventually. -""" - -import sys -import ast - -import py -from py._code.assertion import _format_explanation, BuiltinAssertionError - - -if sys.platform.startswith("java") and sys.version_info < (2, 5, 2): - # See http://bugs.jython.org/issue1497 - _exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict", - "ListComp", "GeneratorExp", "Yield", "Compare", "Call", - "Repr", "Num", "Str", "Attribute", "Subscript", "Name", - "List", "Tuple") - _stmts = ("FunctionDef", "ClassDef", "Return", "Delete", "Assign", - "AugAssign", "Print", "For", "While", "If", "With", "Raise", - "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom", - "Exec", "Global", "Expr", "Pass", "Break", "Continue") - _expr_nodes = set(getattr(ast, name) for name in _exprs) - _stmt_nodes = set(getattr(ast, name) for name in _stmts) - def _is_ast_expr(node): - return node.__class__ in _expr_nodes - def _is_ast_stmt(node): - return node.__class__ in _stmt_nodes -else: - def _is_ast_expr(node): - return isinstance(node, ast.expr) - def _is_ast_stmt(node): - return isinstance(node, ast.stmt) - - -class Failure(Exception): - """Error found while interpreting AST.""" - - def __init__(self, explanation=""): - self.cause = sys.exc_info() - self.explanation = explanation - - -def interpret(source, frame, should_fail=False): - mod = ast.parse(source) - visitor = DebugInterpreter(frame) - try: - visitor.visit(mod) - except Failure: - failure = sys.exc_info()[1] - return getfailure(failure) - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --no-assert)") - -def run(offending_line, frame=None): - if frame is None: - frame = py.code.Frame(sys._getframe(1)) - return interpret(offending_line, frame) - -def getfailure(failure): - explanation = _format_explanation(failure.explanation) - value = failure.cause[1] - if str(value): - lines = explanation.splitlines() - if not lines: - lines.append("") - lines[0] += " << %s" % (value,) - explanation = "\n".join(lines) - text = "%s: %s" % (failure.cause[0].__name__, explanation) - if text.startswith("AssertionError: assert "): - text = text[16:] - return text - - -operator_map = { - ast.BitOr : "|", - ast.BitXor : "^", - ast.BitAnd : "&", - ast.LShift : "<<", - ast.RShift : ">>", - ast.Add : "+", - ast.Sub : "-", - ast.Mult : "*", - ast.Div : "/", - ast.FloorDiv : "//", - ast.Mod : "%", - ast.Eq : "==", - ast.NotEq : "!=", - ast.Lt : "<", - ast.LtE : "<=", - ast.Gt : ">", - ast.GtE : ">=", - ast.Pow : "**", - ast.Is : "is", - ast.IsNot : "is not", - ast.In : "in", - ast.NotIn : "not in" -} - -unary_map = { - ast.Not : "not %s", - ast.Invert : "~%s", - ast.USub : "-%s", - ast.UAdd : "+%s" -} - - -class DebugInterpreter(ast.NodeVisitor): - """Interpret AST nodes to gleam useful debugging information. """ - - def __init__(self, frame): - self.frame = frame - - def generic_visit(self, node): - # Fallback when we don't have a special implementation. - if _is_ast_expr(node): - mod = ast.Expression(node) - co = self._compile(mod) - try: - result = self.frame.eval(co) - except Exception: - raise Failure() - explanation = self.frame.repr(result) - return explanation, result - elif _is_ast_stmt(node): - mod = ast.Module([node]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co) - except Exception: - raise Failure() - return None, None - else: - raise AssertionError("can't handle %s" %(node,)) - - def _compile(self, source, mode="eval"): - return compile(source, "", mode) - - def visit_Expr(self, expr): - return self.visit(expr.value) - - def visit_Module(self, mod): - for stmt in mod.body: - self.visit(stmt) - - def visit_Name(self, name): - explanation, result = self.generic_visit(name) - # See if the name is local. - source = "%r in locals() is not globals()" % (name.id,) - co = self._compile(source) - try: - local = self.frame.eval(co) - except Exception: - # have to assume it isn't - local = False - if not local: - return name.id, result - return explanation, result - - def visit_Compare(self, comp): - left = comp.left - left_explanation, left_result = self.visit(left) - for op, next_op in zip(comp.ops, comp.comparators): - next_explanation, next_result = self.visit(next_op) - op_symbol = operator_map[op.__class__] - explanation = "%s %s %s" % (left_explanation, op_symbol, - next_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=next_result) - except Exception: - raise Failure(explanation) - try: - if not result: - break - except KeyboardInterrupt: - raise - except: - break - left_explanation, left_result = next_explanation, next_result - - rcomp = py.code._reprcompare - if rcomp: - res = rcomp(op_symbol, left_result, next_result) - if res: - explanation = res - return explanation, result - - def visit_BoolOp(self, boolop): - is_or = isinstance(boolop.op, ast.Or) - explanations = [] - for operand in boolop.values: - explanation, result = self.visit(operand) - explanations.append(explanation) - if result == is_or: - break - name = is_or and " or " or " and " - explanation = "(" + name.join(explanations) + ")" - return explanation, result - - def visit_UnaryOp(self, unary): - pattern = unary_map[unary.op.__class__] - operand_explanation, operand_result = self.visit(unary.operand) - explanation = pattern % (operand_explanation,) - co = self._compile(pattern % ("__exprinfo_expr",)) - try: - result = self.frame.eval(co, __exprinfo_expr=operand_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_BinOp(self, binop): - left_explanation, left_result = self.visit(binop.left) - right_explanation, right_result = self.visit(binop.right) - symbol = operator_map[binop.op.__class__] - explanation = "(%s %s %s)" % (left_explanation, symbol, - right_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=right_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_Call(self, call): - func_explanation, func = self.visit(call.func) - arg_explanations = [] - ns = {"__exprinfo_func" : func} - arguments = [] - for arg in call.args: - arg_explanation, arg_result = self.visit(arg) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - arguments.append(arg_name) - arg_explanations.append(arg_explanation) - for keyword in call.keywords: - arg_explanation, arg_result = self.visit(keyword.value) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - keyword_source = "%s=%%s" % (keyword.arg) - arguments.append(keyword_source % (arg_name,)) - arg_explanations.append(keyword_source % (arg_explanation,)) - if call.starargs: - arg_explanation, arg_result = self.visit(call.starargs) - arg_name = "__exprinfo_star" - ns[arg_name] = arg_result - arguments.append("*%s" % (arg_name,)) - arg_explanations.append("*%s" % (arg_explanation,)) - if call.kwargs: - arg_explanation, arg_result = self.visit(call.kwargs) - arg_name = "__exprinfo_kwds" - ns[arg_name] = arg_result - arguments.append("**%s" % (arg_name,)) - arg_explanations.append("**%s" % (arg_explanation,)) - args_explained = ", ".join(arg_explanations) - explanation = "%s(%s)" % (func_explanation, args_explained) - args = ", ".join(arguments) - source = "__exprinfo_func(%s)" % (args,) - co = self._compile(source) - try: - result = self.frame.eval(co, **ns) - except Exception: - raise Failure(explanation) - pattern = "%s\n{%s = %s\n}" - rep = self.frame.repr(result) - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def _is_builtin_name(self, name): - pattern = "%r not in globals() and %r not in locals()" - source = pattern % (name.id, name.id) - co = self._compile(source) - try: - return self.frame.eval(co) - except Exception: - return False - - def visit_Attribute(self, attr): - if not isinstance(attr.ctx, ast.Load): - return self.generic_visit(attr) - source_explanation, source_result = self.visit(attr.value) - explanation = "%s.%s" % (source_explanation, attr.attr) - source = "__exprinfo_expr.%s" % (attr.attr,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - raise Failure(explanation) - explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), - self.frame.repr(result), - source_explanation, attr.attr) - # Check if the attr is from an instance. - source = "%r in getattr(__exprinfo_expr, '__dict__', {})" - source = source % (attr.attr,) - co = self._compile(source) - try: - from_instance = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - from_instance = True - if from_instance: - rep = self.frame.repr(result) - pattern = "%s\n{%s = %s\n}" - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def visit_Assert(self, assrt): - test_explanation, test_result = self.visit(assrt.test) - if test_explanation.startswith("False\n{False =") and \ - test_explanation.endswith("\n"): - test_explanation = test_explanation[15:-2] - explanation = "assert %s" % (test_explanation,) - if not test_result: - try: - raise BuiltinAssertionError - except Exception: - raise Failure(explanation) - return explanation, test_result - - def visit_Assign(self, assign): - value_explanation, value_result = self.visit(assign.value) - explanation = "... = %s" % (value_explanation,) - name = ast.Name("__exprinfo_expr", ast.Load(), - lineno=assign.value.lineno, - col_offset=assign.value.col_offset) - new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, - col_offset=assign.col_offset) - mod = ast.Module([new_assign]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co, __exprinfo_expr=value_result) - except Exception: - raise Failure(explanation) - return explanation, value_result diff --git a/py/_code/_assertionold.py b/py/_code/_assertionold.py deleted file mode 100644 --- a/py/_code/_assertionold.py +++ /dev/null @@ -1,555 +0,0 @@ -import py -import sys, inspect -from compiler import parse, ast, pycodegen -from py._code.assertion import BuiltinAssertionError, _format_explanation - -passthroughex = py.builtin._sysex - -class Failure: - def __init__(self, node): - self.exc, self.value, self.tb = sys.exc_info() - self.node = node - -class View(object): - """View base class. - - If C is a subclass of View, then C(x) creates a proxy object around - the object x. The actual class of the proxy is not C in general, - but a *subclass* of C determined by the rules below. To avoid confusion - we call view class the class of the proxy (a subclass of C, so of View) - and object class the class of x. - - Attributes and methods not found in the proxy are automatically read on x. - Other operations like setting attributes are performed on the proxy, as - determined by its view class. The object x is available from the proxy - as its __obj__ attribute. - - The view class selection is determined by the __view__ tuples and the - optional __viewkey__ method. By default, the selected view class is the - most specific subclass of C whose __view__ mentions the class of x. - If no such subclass is found, the search proceeds with the parent - object classes. For example, C(True) will first look for a subclass - of C with __view__ = (..., bool, ...) and only if it doesn't find any - look for one with __view__ = (..., int, ...), and then ..., object,... - If everything fails the class C itself is considered to be the default. - - Alternatively, the view class selection can be driven by another aspect - of the object x, instead of the class of x, by overriding __viewkey__. - See last example at the end of this module. - """ - - _viewcache = {} - __view__ = () - - def __new__(rootclass, obj, *args, **kwds): - self = object.__new__(rootclass) - self.__obj__ = obj - self.__rootclass__ = rootclass - key = self.__viewkey__() - try: - self.__class__ = self._viewcache[key] - except KeyError: - self.__class__ = self._selectsubclass(key) - return self - - def __getattr__(self, attr): - # attributes not found in the normal hierarchy rooted on View - # are looked up in the object's real class - return getattr(self.__obj__, attr) - - def __viewkey__(self): - return self.__obj__.__class__ - - def __matchkey__(self, key, subclasses): - if inspect.isclass(key): - keys = inspect.getmro(key) - else: - keys = [key] - for key in keys: - result = [C for C in subclasses if key in C.__view__] - if result: - return result - return [] - - def _selectsubclass(self, key): - subclasses = list(enumsubclasses(self.__rootclass__)) - for C in subclasses: - if not isinstance(C.__view__, tuple): - C.__view__ = (C.__view__,) - choices = self.__matchkey__(key, subclasses) - if not choices: - return self.__rootclass__ - elif len(choices) == 1: - return choices[0] - else: - # combine the multiple choices - return type('?', tuple(choices), {}) - - def __repr__(self): - return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) - - -def enumsubclasses(cls): - for subcls in cls.__subclasses__(): - for subsubclass in enumsubclasses(subcls): - yield subsubclass - yield cls - - -class Interpretable(View): - """A parse tree node with a few extra methods.""" - explanation = None - - def is_builtin(self, frame): - return False - - def eval(self, frame): - # fall-back for unknown expression nodes - try: - expr = ast.Expression(self.__obj__) - expr.filename = '' - self.__obj__.filename = '' - co = pycodegen.ExpressionCodeGenerator(expr).getCode() - result = frame.eval(co) - except passthroughex: - raise - except: - raise Failure(self) - self.result = result - self.explanation = self.explanation or frame.repr(self.result) - - def run(self, frame): - # fall-back for unknown statement nodes - try: - expr = ast.Module(None, ast.Stmt([self.__obj__])) - expr.filename = '' - co = pycodegen.ModuleCodeGenerator(expr).getCode() - frame.exec_(co) - except passthroughex: - raise - except: - raise Failure(self) - - def nice_explanation(self): - return _format_explanation(self.explanation) - - -class Name(Interpretable): - __view__ = ast.Name - - def is_local(self, frame): - source = '%r in locals() is not globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_global(self, frame): - source = '%r in globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_builtin(self, frame): - source = '%r not in locals() and %r not in globals()' % ( - self.name, self.name) - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - super(Name, self).eval(frame) - if not self.is_local(frame): - self.explanation = self.name - -class Compare(Interpretable): - __view__ = ast.Compare - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - for operation, expr2 in self.ops: - if hasattr(self, 'result'): - # shortcutting in chained expressions - if not frame.is_true(self.result): - break - expr2 = Interpretable(expr2) - expr2.eval(frame) - self.explanation = "%s %s %s" % ( - expr.explanation, operation, expr2.explanation) - source = "__exprinfo_left %s __exprinfo_right" % operation - try: - self.result = frame.eval(source, - __exprinfo_left=expr.result, - __exprinfo_right=expr2.result) - except passthroughex: - raise - except: - raise Failure(self) - expr = expr2 - -class And(Interpretable): - __view__ = ast.And - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if not frame.is_true(expr.result): - break - self.explanation = '(' + ' and '.join(explanations) + ')' - -class Or(Interpretable): - __view__ = ast.Or - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if frame.is_true(expr.result): - break - self.explanation = '(' + ' or '.join(explanations) + ')' - - -# == Unary operations == -keepalive = [] -for astclass, astpattern in { - ast.Not : 'not __exprinfo_expr', - ast.Invert : '(~__exprinfo_expr)', - }.items(): - - class UnaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - expr = Interpretable(self.expr) - expr.eval(frame) - self.explanation = astpattern.replace('__exprinfo_expr', - expr.explanation) - try: - self.result = frame.eval(astpattern, - __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(UnaryArith) - -# == Binary operations == -for astclass, astpattern in { - ast.Add : '(__exprinfo_left + __exprinfo_right)', - ast.Sub : '(__exprinfo_left - __exprinfo_right)', - ast.Mul : '(__exprinfo_left * __exprinfo_right)', - ast.Div : '(__exprinfo_left / __exprinfo_right)', - ast.Mod : '(__exprinfo_left % __exprinfo_right)', - ast.Power : '(__exprinfo_left ** __exprinfo_right)', - }.items(): - - class BinaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - left = Interpretable(self.left) - left.eval(frame) - right = Interpretable(self.right) - right.eval(frame) - self.explanation = (astpattern - .replace('__exprinfo_left', left .explanation) - .replace('__exprinfo_right', right.explanation)) - try: - self.result = frame.eval(astpattern, - __exprinfo_left=left.result, - __exprinfo_right=right.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(BinaryArith) - - -class CallFunc(Interpretable): - __view__ = ast.CallFunc - - def is_bool(self, frame): - source = 'isinstance(__exprinfo_value, bool)' - try: - return frame.is_true(frame.eval(source, - __exprinfo_value=self.result)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - node = Interpretable(self.node) - node.eval(frame) - explanations = [] - vars = {'__exprinfo_fn': node.result} - source = '__exprinfo_fn(' - for a in self.args: - if isinstance(a, ast.Keyword): - keyword = a.name - a = a.expr - else: - keyword = None - a = Interpretable(a) - a.eval(frame) - argname = '__exprinfo_%d' % len(vars) - vars[argname] = a.result - if keyword is None: - source += argname + ',' - explanations.append(a.explanation) - else: - source += '%s=%s,' % (keyword, argname) - explanations.append('%s=%s' % (keyword, a.explanation)) - if self.star_args: - star_args = Interpretable(self.star_args) - star_args.eval(frame) - argname = '__exprinfo_star' - vars[argname] = star_args.result - source += '*' + argname + ',' - explanations.append('*' + star_args.explanation) - if self.dstar_args: - dstar_args = Interpretable(self.dstar_args) - dstar_args.eval(frame) - argname = '__exprinfo_kwds' - vars[argname] = dstar_args.result - source += '**' + argname + ',' - explanations.append('**' + dstar_args.explanation) - self.explanation = "%s(%s)" % ( - node.explanation, ', '.join(explanations)) - if source.endswith(','): - source = source[:-1] - source += ')' - try: - self.result = frame.eval(source, **vars) - except passthroughex: - raise - except: - raise Failure(self) - if not node.is_builtin(frame) or not self.is_bool(frame): - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -class Getattr(Interpretable): - __view__ = ast.Getattr - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - source = '__exprinfo_expr.%s' % self.attrname - try: - self.result = frame.eval(source, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - self.explanation = '%s.%s' % (expr.explanation, self.attrname) - # if the attribute comes from the instance, its value is interesting - source = ('hasattr(__exprinfo_expr, "__dict__") and ' - '%r in __exprinfo_expr.__dict__' % self.attrname) - try: - from_instance = frame.is_true( - frame.eval(source, __exprinfo_expr=expr.result)) - except passthroughex: - raise - except: - from_instance = True - if from_instance: - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -# == Re-interpretation of full statements == - -class Assert(Interpretable): - __view__ = ast.Assert - - def run(self, frame): - test = Interpretable(self.test) - test.eval(frame) - # simplify 'assert False where False = ...' - if (test.explanation.startswith('False\n{False = ') and - test.explanation.endswith('\n}')): - test.explanation = test.explanation[15:-2] - # print the result as 'assert ' - self.result = test.result - self.explanation = 'assert ' + test.explanation - if not frame.is_true(test.result): - try: - raise BuiltinAssertionError - except passthroughex: - raise - except: - raise Failure(self) - -class Assign(Interpretable): - __view__ = ast.Assign - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = '... = ' + expr.explanation - # fall-back-run the rest of the assignment - ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) - mod = ast.Module(None, ast.Stmt([ass])) - mod.filename = '' - co = pycodegen.ModuleCodeGenerator(mod).getCode() - try: - frame.exec_(co, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - -class Discard(Interpretable): - __view__ = ast.Discard - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = expr.explanation - -class Stmt(Interpretable): - __view__ = ast.Stmt - - def run(self, frame): - for stmt in self.nodes: - stmt = Interpretable(stmt) - stmt.run(frame) - - -def report_failure(e): - explanation = e.node.nice_explanation() - if explanation: - explanation = ", in: " + explanation - else: - explanation = "" - sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) - -def check(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - expr = parse(s, 'eval') - assert isinstance(expr, ast.Expression) - node = Interpretable(expr.node) - try: - node.eval(frame) - except passthroughex: - raise - except Failure: - e = sys.exc_info()[1] - report_failure(e) - else: - if not frame.is_true(node.result): - sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) - - -########################################################### -# API / Entry points -# ######################################################### - -def interpret(source, frame, should_fail=False): - module = Interpretable(parse(source, 'exec').node) - #print "got module", module - if isinstance(frame, py.std.types.FrameType): - frame = py.code.Frame(frame) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - return getfailure(e) - except passthroughex: - raise - except: - import traceback - traceback.print_exc() - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --nomagic)") - else: - return None - -def getmsg(excinfo): - if isinstance(excinfo, tuple): - excinfo = py.code.ExceptionInfo(excinfo) - #frame, line = gettbline(tb) - #frame = py.code.Frame(frame) - #return interpret(line, frame) - - tb = excinfo.traceback[-1] - source = str(tb.statement).strip() - x = interpret(source, tb.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - return x - -def getfailure(e): - explanation = e.node.nice_explanation() - if str(e.value): - lines = explanation.split('\n') - lines[0] += " << %s" % (e.value,) - explanation = '\n'.join(lines) - text = "%s: %s" % (e.exc.__name__, explanation) - if text.startswith('AssertionError: assert '): - text = text[16:] - return text - -def run(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - module = Interpretable(parse(s, 'exec').node) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - report_failure(e) - - -if __name__ == '__main__': - # example: - def f(): - return 5 - def g(): - return 3 - def h(x): - return 'never' - check("f() * g() == 5") - check("not f()") - check("not (f() and g() or 0)") - check("f() == g()") - i = 4 - check("i == f()") - check("len(f()) == 0") - check("isinstance(2+3+4, float)") - - run("x = i") - check("x == 5") - - run("assert not f(), 'oops'") - run("a, b, c = 1, 2") - run("a, b, c = f()") - - check("max([f(),g()]) == 4") - check("'hello'[g()] == 'h'") - run("'guk%d' % h(f())") diff --git a/py/_code/assertion.py b/py/_code/assertion.py deleted file mode 100644 --- a/py/_code/assertion.py +++ /dev/null @@ -1,94 +0,0 @@ -import sys -import py - -BuiltinAssertionError = py.builtin.builtins.AssertionError - -_reprcompare = None # if set, will be called by assert reinterp for comparison ops - -def _format_explanation(explanation): - """This formats an explanation - - Normally all embedded newlines are escaped, however there are - three exceptions: \n{, \n} and \n~. The first two are intended - cover nested explanations, see function and attribute explanations - for examples (.visit_Call(), visit_Attribute()). The last one is - for when one explanation needs to span multiple lines, e.g. when - displaying diffs. - """ - raw_lines = (explanation or '').split('\n') - # escape newlines not followed by {, } and ~ - lines = [raw_lines[0]] - for l in raw_lines[1:]: - if l.startswith('{') or l.startswith('}') or l.startswith('~'): - lines.append(l) - else: - lines[-1] += '\\n' + l - - result = lines[:1] - stack = [0] - stackcnt = [0] - for line in lines[1:]: - if line.startswith('{'): - if stackcnt[-1]: - s = 'and ' - else: - s = 'where ' - stack.append(len(result)) - stackcnt[-1] += 1 - stackcnt.append(0) - result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) - elif line.startswith('}'): - assert line.startswith('}') - stack.pop() - stackcnt.pop() - result[stack[-1]] += line[1:] - else: - assert line.startswith('~') - result.append(' '*len(stack) + line[1:]) - assert len(stack) == 1 - return '\n'.join(result) - - -class AssertionError(BuiltinAssertionError): - def __init__(self, *args): - BuiltinAssertionError.__init__(self, *args) - if args: - try: - self.msg = str(args[0]) - except py.builtin._sysex: - raise - except: - self.msg = "<[broken __repr__] %s at %0xd>" %( - args[0].__class__, id(args[0])) - else: - f = py.code.Frame(sys._getframe(1)) - try: - source = f.code.fullsource - if source is not None: - try: - source = source.getstatement(f.lineno, assertion=True) - except IndexError: - source = None - else: - source = str(source.deindent()).strip() - except py.error.ENOENT: - source = None - # this can also occur during reinterpretation, when the - # co_filename is set to "". - if source: - self.msg = reinterpret(source, f, should_fail=True) - else: - self.msg = "" - if not self.args: - self.args = (self.msg,) - -if sys.version_info > (3, 0): - AssertionError.__module__ = "builtins" - reinterpret_old = "old reinterpretation not available for py3" -else: - from py._code._assertionold import interpret as reinterpret_old -if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): - from py._code._assertionnew import interpret as reinterpret -else: - reinterpret = reinterpret_old - diff --git a/py/_code/code.py b/py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -145,17 +145,6 @@ return self.frame.f_locals locals = property(getlocals, None, None, "locals of underlaying frame") - def reinterpret(self): - """Reinterpret the failing statement and returns a detailed information - about what operations are performed.""" - if self.exprinfo is None: - source = str(self.statement).strip() - x = py.code._reinterpret(source, self.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - self.exprinfo = x - return self.exprinfo - def getfirstlinesource(self): # on Jython this firstlineno can be -1 apparently return max(self.frame.code.firstlineno, 0) @@ -310,7 +299,7 @@ # ExceptionInfo-like classes may have different attributes. if tup is None: tup = sys.exc_info() - if exprinfo is None and isinstance(tup[1], py.code._AssertionError): + if exprinfo is None and isinstance(tup[1], AssertionError): exprinfo = getattr(tup[1], 'msg', None) if exprinfo is None: exprinfo = str(tup[1]) @@ -690,22 +679,15 @@ oldbuiltins = {} -def patch_builtins(assertion=True, compile=True): - """ put compile and AssertionError builtins to Python's builtins. """ - if assertion: - from py._code import assertion - l = oldbuiltins.setdefault('AssertionError', []) - l.append(py.builtin.builtins.AssertionError) - py.builtin.builtins.AssertionError = assertion.AssertionError +def patch_builtins(compile=True): + """ put compile builtins to Python's builtins. """ if compile: l = oldbuiltins.setdefault('compile', []) l.append(py.builtin.builtins.compile) py.builtin.builtins.compile = py.code.compile -def unpatch_builtins(assertion=True, compile=True): +def unpatch_builtins(compile=True): """ remove compile and AssertionError builtins from Python builtins. """ - if assertion: - py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop() if compile: py.builtin.builtins.compile = oldbuiltins['compile'].pop() diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -299,12 +299,13 @@ listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -84,6 +84,7 @@ "_rawffi": [("objspace.usemodules.struct", True)], "cpyext": [("translation.secondaryentrypoints", "cpyext"), ("translation.shared", sys.platform == "win32")], + "_ffi": [("translation.jit_ffi", True)], } module_import_dependencies = { diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py --- a/pypy/config/test/test_pypyoption.py +++ b/pypy/config/test/test_pypyoption.py @@ -73,3 +73,7 @@ fn = prefix + "." + path + ".txt" yield check_file_exists, fn +def test__ffi_opt(): + config = get_pypy_config(translating=True) + config.objspace.usemodules._ffi = True + assert config.translation.jit_ffi diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -117,6 +117,8 @@ ChoiceOption("jit_profiler", "integrate profiler support into the JIT", ["off", "oprofile"], default="off"), + # jit_ffi is automatically turned on by withmod-_ffi (which is enabled by default) + BoolOption("jit_ffi", "optimize libffi calls", default=False, cmdline=None), # misc BoolOption("verbose", "Print extra information", default=False), diff --git a/pypy/doc/garbage_collection.rst b/pypy/doc/garbage_collection.rst --- a/pypy/doc/garbage_collection.rst +++ b/pypy/doc/garbage_collection.rst @@ -212,90 +212,4 @@ becomes free garbage, to be collected at the next major collection. -Minimark GC ------------ - -This is a simplification and rewrite of the ideas from the Hybrid GC. -It uses a nursery for the young objects, and mark-and-sweep for the old -objects. This is a moving GC, but objects may only move once (from -the nursery to the old stage). - -The main difference with the Hybrid GC is that the mark-and-sweep -objects (the "old stage") are directly handled by the GC's custom -allocator, instead of being handled by malloc() calls. The gain is that -it is then possible, during a major collection, to walk through all old -generation objects without needing to store a list of pointers to them. -So as a first approximation, when compared to the Hybrid GC, the -Minimark GC saves one word of memory per old object. - -There are a number of environment variables that can be tweaked to -influence the GC. (Their default value should be ok for most usages.) -You can read more about them at the start of -`pypy/rpython/memory/gc/minimark.py`_. - -In more details: - -- The small newly malloced objects are allocated in the nursery (case 1). - All objects living in the nursery are "young". - -- The big objects are always handled directly by the system malloc(). - But the big newly malloced objects are still "young" when they are - allocated (case 2), even though they don't live in the nursery. - -- When the nursery is full, we do a minor collection, i.e. we find - which "young" objects are still alive (from cases 1 and 2). The - "young" flag is then removed. The surviving case 1 objects are moved - to the old stage. The dying case 2 objects are immediately freed. - -- The old stage is an area of memory containing old (small) objects. It - is handled by `pypy/rpython/memory/gc/minimarkpage.py`_. It is organized - as "arenas" of 256KB or 512KB, subdivided into "pages" of 4KB or 8KB. - Each page can either be free, or contain small objects of all the same - size. Furthermore at any point in time each object location can be - either allocated or freed. The basic design comes from ``obmalloc.c`` - from CPython (which itself comes from the same source as the Linux - system malloc()). - -- New objects are added to the old stage at every minor collection. - Immediately after a minor collection, when we reach some threshold, we - trigger a major collection. This is the mark-and-sweep step. It walks - over *all* objects (mark), and then frees some fraction of them (sweep). - This means that the only time when we want to free objects is while - walking over all of them; we never ask to free an object given just its - address. This allows some simplifications and memory savings when - compared to ``obmalloc.c``. - -- As with all generational collectors, this GC needs a write barrier to - record which old objects have a reference to young objects. - -- Additionally, we found out that it is useful to handle the case of - big arrays specially: when we allocate a big array (with the system - malloc()), we reserve a small number of bytes before. When the array - grows old, we use the extra bytes as a set of bits. Each bit - represents 128 entries in the array. Whenever the write barrier is - called to record a reference from the Nth entry of the array to some - young object, we set the bit number ``(N/128)`` to 1. This can - considerably speed up minor collections, because we then only have to - scan 128 entries of the array instead of all of them. - -- As usual, we need special care about weak references, and objects with - finalizers. Weak references are allocated in the nursery, and if they - survive they move to the old stage, as usual for all objects; the - difference is that the reference they contain must either follow the - object, or be set to NULL if the object dies. And the objects with - finalizers, considered rare enough, are immediately allocated old to - simplify the design. In particular their ``__del__`` method can only - be called just after a major collection. - -- The objects move once only, so we can use a trick to implement id() - and hash(). If the object is not in the nursery, it won't move any - more, so its id() and hash() are the object's address, cast to an - integer. If the object is in the nursery, and we ask for its id() - or its hash(), then we pre-reserve a location in the old stage, and - return the address of that location. If the object survives the - next minor collection, we move it there, and so its id() and hash() - are preserved. If the object dies then the pre-reserved location - becomes free garbage, to be collected at the next major collection. - - .. include:: _ref.txt diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -91,7 +91,7 @@ Remove the GIL -------------- -This is a major task that requiers lots of thinking. However, few subprojects +This is a major task that requires lots of thinking. However, few subprojects can be potentially specified, unless a better plan can be thought out: * A thread-aware garbage collector @@ -124,6 +124,25 @@ for our needs. It's possible that this has changed, reviving the LLVM backend (or writing new from scratch) for static compilation would be a good project. +(On the other hand, just generating C code and using clang might be enough. +The issue with that is the so-called "asmgcc GC root finder", which has tons +of issues of this own. In my opinion (arigo), it would be definitely a +better project to try to optimize the alternative, the "shadowstack" GC root +finder, which is nicely portable. So far it gives a pypy that is around +7% slower.) + +Embedding PyPy +---------------------------------------- + +Being able to embed PyPy, say with its own limited C API, would be +useful. But here is the most interesting variant, straight from +EuroPython live discussion :-) We can have a generic "libpypy.so" that +can be used as a placeholder dynamic library, and when it gets loaded, +it runs a .py module that installs (via ctypes) the interface it wants +exported. This would give us a one-size-fits-all generic .so file to be +imported by any application that wants to load .so files :-) + + .. _`issue tracker`: http://bugs.pypy.org .. _`mailing list`: http://mail.python.org/mailman/listinfo/pypy-dev .. _`jitviewer`: http://bitbucket.org/pypy/jitviewer diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -90,15 +90,18 @@ ### Construction ### def __init__(self, space, args_w, keywords=None, keywords_w=None, - w_stararg=None, w_starstararg=None): + w_stararg=None, w_starstararg=None, keyword_names_w=None): self.space = space assert isinstance(args_w, list) self.arguments_w = args_w self.keywords = keywords self.keywords_w = keywords_w + self.keyword_names_w = keyword_names_w # matches the tail of .keywords if keywords is not None: assert keywords_w is not None assert len(keywords_w) == len(keywords) + assert (keyword_names_w is None or + len(keyword_names_w) <= len(keywords)) make_sure_not_resized(self.keywords) make_sure_not_resized(self.keywords_w) @@ -132,7 +135,8 @@ def replace_arguments(self, args_w): "Return a new Arguments with a args_w as positional arguments." - return Arguments(self.space, args_w, self.keywords, self.keywords_w) + return Arguments(self.space, args_w, self.keywords, self.keywords_w, + keyword_names_w = self.keyword_names_w) def prepend(self, w_firstarg): "Return a new Arguments with a new argument inserted first." @@ -201,15 +205,16 @@ space.w_TypeError, space.wrap("keywords must be strings")) if e.match(space, space.w_UnicodeEncodeError): - raise OperationError( - space.w_TypeError, - space.wrap("keyword cannot be encoded to ascii")) - raise - if self.keywords and key in self.keywords: - raise operationerrfmt(self.space.w_TypeError, - "got multiple values " - "for keyword argument " - "'%s'", key) + # Allow this to pass through + key = None + else: + raise + else: + if self.keywords and key in self.keywords: + raise operationerrfmt(self.space.w_TypeError, + "got multiple values " + "for keyword argument " + "'%s'", key) keywords[i] = key keywords_w[i] = space.getitem(w_starstararg, w_key) i += 1 @@ -219,6 +224,7 @@ else: self.keywords = self.keywords + keywords self.keywords_w = self.keywords_w + keywords_w + self.keyword_names_w = keys_w def fixedunpack(self, argcount): """The simplest argument parsing: get the 'argcount' arguments, @@ -339,6 +345,10 @@ used_keywords = [False] * num_kwds for i in range(num_kwds): name = keywords[i] + # If name was not encoded as a string, it could be None. In that + # case, it's definitely not going to be in the signature. + if name is None: + continue j = signature.find_argname(name) if j < 0: continue @@ -374,17 +384,26 @@ if has_kwarg: w_kwds = self.space.newdict() if num_remainingkwds: + # + limit = len(keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(keywords)): if not used_keywords[i]: - key = keywords[i] - self.space.setitem(w_kwds, self.space.wrap(key), keywords_w[i]) + if i < limit: + w_key = self.space.wrap(keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + self.space.setitem(w_kwds, w_key, keywords_w[i]) + # scope_w[co_argcount + has_vararg] = w_kwds elif num_remainingkwds: if co_argcount == 0: raise ArgErrCount(avail, num_kwds, co_argcount, has_vararg, has_kwarg, defaults_w, missing) - raise ArgErrUnknownKwds(num_remainingkwds, keywords, used_keywords) + raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords, + used_keywords, self.keyword_names_w) if missing: raise ArgErrCount(avail, num_kwds, @@ -443,9 +462,15 @@ w_args = space.newtuple(self.arguments_w) w_kwds = space.newdict() if self.keywords is not None: + limit = len(self.keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(self.keywords)): - space.setitem(w_kwds, space.wrap(self.keywords[i]), - self.keywords_w[i]) + if i < limit: + w_key = space.wrap(self.keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + space.setitem(w_kwds, w_key, self.keywords_w[i]) return w_args, w_kwds class ArgumentsForTranslation(Arguments): @@ -666,14 +691,33 @@ class ArgErrUnknownKwds(ArgErr): - def __init__(self, num_remainingkwds, keywords, used_keywords): - self.kwd_name = '' + def __init__(self, space, num_remainingkwds, keywords, used_keywords, + keyword_names_w): + name = '' self.num_kwds = num_remainingkwds if num_remainingkwds == 1: for i in range(len(keywords)): if not used_keywords[i]: - self.kwd_name = keywords[i] + name = keywords[i] + if name is None: + # We'll assume it's unicode. Encode it. + # Careful, I *think* it should not be possible to + # get an IndexError here but you never know. + try: + if keyword_names_w is None: + raise IndexError + # note: negative-based indexing from the end + w_name = keyword_names_w[i - len(keywords)] + except IndexError: + name = '?' + else: + w_enc = space.wrap(space.sys.defaultencoding) + w_err = space.wrap("replace") + w_name = space.call_method(w_name, "encode", w_enc, + w_err) + name = space.str_w(w_name) break + self.kwd_name = name def getmsg(self, fnname): if self.num_kwds == 1: diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -134,7 +134,7 @@ def accept_comp_iteration(self, codegen, index): self.elt.walkabout(codegen) - codegen.emit_op_arg(ops.SET_ADD, index) + codegen.emit_op_arg(ops.SET_ADD, index + 1) class __extend__(ast.DictComp): @@ -148,7 +148,7 @@ def accept_comp_iteration(self, codegen, index): self.value.walkabout(codegen) self.key.walkabout(codegen) - codegen.emit_op_arg(ops.MAP_ADD, index) + codegen.emit_op_arg(ops.MAP_ADD, index + 1) # These are frame blocks. diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -92,7 +92,10 @@ return name if len(name) + 2 >= MANGLE_LEN: return name - if name.endswith('__'): + # Don't mangle __id__ or names with dots. The only time a name with a dot + # can occur is when we are compiling an import statement that has a package + # name. + if name.endswith('__') or '.' in name: return name try: i = 0 diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -55,7 +55,7 @@ co_expr = compile(evalexpr, '', 'eval') space = self.space pyco_expr = PyCode._from_code(space, co_expr) - w_res = pyco_expr.exec_host_bytecode(space, w_dict, w_dict) + w_res = pyco_expr.exec_host_bytecode(w_dict, w_dict) res = space.str_w(space.repr(w_res)) if not isinstance(expected, float): assert res == repr(expected) @@ -308,6 +308,15 @@ "p.__name__", os.path.__name__) yield (self.st, 'from os import *', "path.__name__, sep", (os.path.__name__, os.sep)) + yield (self.st, ''' + class A(object): + def m(self): + from __foo__.bar import x + try: + A().m() + except ImportError, e: + msg = str(e) + ''', "msg", "No module named __foo__") def test_if_stmts(self): yield self.st, "a = 42\nif a > 10: a += 2", "a", 44 diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -989,10 +989,7 @@ compiler = self.createcompiler() expression = compiler.compile(expression, '?', 'eval', 0, hidden_applevel=hidden_applevel) - if isinstance(expression, types.CodeType): - # XXX only used by appsupport - expression = PyCode._from_code(self, expression) - if not isinstance(expression, PyCode): + else: raise TypeError, 'space.eval(): expected a string, code or PyCode object' return expression.exec_code(self, w_globals, w_locals) @@ -1007,9 +1004,6 @@ compiler = self.createcompiler() statement = compiler.compile(statement, filename, 'exec', 0, hidden_applevel=hidden_applevel) - if isinstance(statement, types.CodeType): - # XXX only used by appsupport - statement = PyCode._from_code(self, statement) if not isinstance(statement, PyCode): raise TypeError, 'space.exec_(): expected a string, code or PyCode object' w_key = self.wrap('__builtins__') diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -100,12 +100,12 @@ @jit.dont_look_inside def fast2locals(self): - # Copy values from self.fastlocals_w to self.w_locals + # Copy values from the fastlocals to self.w_locals if self.w_locals is None: self.w_locals = self.space.newdict() varnames = self.getcode().getvarnames() fastscope_w = self.getfastscope() - for i in range(min(len(varnames), len(fastscope_w))): + for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] if w_value is not None: @@ -114,7 +114,7 @@ @jit.dont_look_inside def locals2fast(self): - # Copy values from self.w_locals to self.fastlocals_w + # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None varnames = self.getcode().getvarnames() numlocals = self.getfastscopelength() diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -98,7 +98,7 @@ self.closure) for i in funccallunrolling: if i < nargs: - new_frame.fastlocals_w[i] = args_w[i] + new_frame.locals_stack_w[i] = args_w[i] return new_frame.run() elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1: assert isinstance(code, gateway.BuiltinCodePassThroughArguments1) @@ -158,7 +158,7 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg return new_frame.run() @@ -169,13 +169,13 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = self.defs_w[j] + new_frame.locals_stack_w[i] = self.defs_w[j] i += 1 return new_frame.run() diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -170,7 +170,7 @@ for i in range(len(args_to_copy)): argnum = args_to_copy[i] if argnum >= 0: - self.cells[i].set(self.fastlocals_w[argnum]) + self.cells[i].set(self.locals_stack_w[argnum]) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -63,6 +63,7 @@ the pypy compiler""" self.space = space eval.Code.__init__(self, name) + assert nlocals >= 0 self.co_argcount = argcount self.co_nlocals = nlocals self.co_stacksize = stacksize @@ -95,7 +96,7 @@ if self.co_flags & CO_VARKEYWORDS: argcount += 1 # Cell vars could shadow already-set arguments. - # astcompiler.pyassem used to be clever about the order of + # The compiler used to be clever about the order of # the variables in both co_varnames and co_cellvars, but # it no longer is for the sake of simplicity. Moreover # code objects loaded from CPython don't necessarily follow @@ -202,7 +203,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -215,7 +216,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -256,7 +257,7 @@ tuple(self.co_freevars), tuple(self.co_cellvars) ) - def exec_host_bytecode(self, w_dict, w_globals, w_locals): + def exec_host_bytecode(self, w_globals, w_locals): from pypy.interpreter.pyframe import CPythonFrame frame = CPythonFrame(self.space, self, w_globals, None) frame.setdictscope(w_locals) diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -9,7 +9,7 @@ from pypy.interpreter import pytraceback from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib.jit import hint -from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.debug import make_sure_not_resized, check_nonneg from pypy.rlib.rarithmetic import intmask from pypy.rlib import jit from pypy.tool import stdlib_opcode @@ -56,16 +56,18 @@ assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals) - self.valuestack_w = [None] * code.co_stacksize - self.valuestackdepth = 0 + self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize) + self.nlocals = code.co_nlocals + self.valuestackdepth = code.co_nlocals self.lastblock = None + make_sure_not_resized(self.locals_stack_w) + check_nonneg(self.nlocals) + # if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure, code) - self.fastlocals_w = [None] * code.co_nlocals - make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno def mark_as_escaped(self): @@ -184,14 +186,14 @@ # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth - self.valuestack_w[depth] = w_object + self.locals_stack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 - assert depth >= 0, "pop from empty value stack" - w_object = self.valuestack_w[depth] - self.valuestack_w[depth] = None + assert depth >= self.nlocals, "pop from empty value stack" + w_object = self.locals_stack_w[depth] + self.locals_stack_w[depth] = None self.valuestackdepth = depth return w_object @@ -217,24 +219,24 @@ def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n - assert base >= 0 + assert base >= self.nlocals while True: n -= 1 if n < 0: break - values_w[n] = self.valuestack_w[base+n] + values_w[n] = self.locals_stack_w[base+n] return values_w @jit.unroll_safe def dropvalues(self, n): n = hint(n, promote=True) finaldepth = self.valuestackdepth - n - assert finaldepth >= 0, "stack underflow in dropvalues()" + assert finaldepth >= self.nlocals, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break - self.valuestack_w[finaldepth+n] = None + self.locals_stack_w[finaldepth+n] = None self.valuestackdepth = finaldepth @jit.unroll_safe @@ -261,30 +263,30 @@ # Contrast this with CPython where it's PEEK(-1). index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "peek past the bottom of the stack" - return self.valuestack_w[index] + assert index >= self.nlocals, "peek past the bottom of the stack" + return self.locals_stack_w[index] def settopvalue(self, w_object, index_from_top=0): index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "settop past the bottom of the stack" - self.valuestack_w[index] = w_object + assert index >= self.nlocals, "settop past the bottom of the stack" + self.locals_stack_w[index] = w_object @jit.unroll_safe def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 finaldepth = hint(finaldepth, promote=True) while depth >= finaldepth: - self.valuestack_w[depth] = None + self.locals_stack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth - def savevaluestack(self): - return self.valuestack_w[:self.valuestackdepth] + def save_locals_stack(self): + return self.locals_stack_w[:self.valuestackdepth] - def restorevaluestack(self, items_w): - assert None not in items_w - self.valuestack_w[:len(items_w)] = items_w + def restore_locals_stack(self, items_w): + self.locals_stack_w[:len(items_w)] = items_w + self.init_cells() self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): @@ -314,11 +316,12 @@ else: f_lineno = self.f_lineno - values_w = self.valuestack_w[0:self.valuestackdepth] + values_w = self.locals_stack_w[self.nlocals:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) - w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) + w_fastlocals = maker.slp_into_tuple_with_nulls( + space, self.locals_stack_w[:self.nlocals]) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None @@ -399,7 +402,8 @@ new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) - new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None @@ -423,28 +427,28 @@ @jit.dont_look_inside def getfastscope(self): "Get the fast locals as a list." - return self.fastlocals_w + return self.locals_stack_w @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) - if scope_len > len(self.fastlocals_w): + if scope_len > self.nlocals: raise ValueError, "new fastscope is longer than the allocated area" - # don't assign directly to 'fastlocals_w[:scope_len]' to be + # don't assign directly to 'locals_stack_w[:scope_len]' to be # virtualizable-friendly for i in range(scope_len): - self.fastlocals_w[i] = scope_w[i] + self.locals_stack_w[i] = scope_w[i] self.init_cells() def init_cells(self): - """Initialize cellvars from self.fastlocals_w + """Initialize cellvars from self.locals_stack_w. This is overridden in nestedscope.py""" pass def getfastscopelength(self): - return self.pycode.co_nlocals + return self.nlocals def getclosure(self): return None diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -324,7 +324,7 @@ def LOAD_FAST(self, varindex, next_instr): # access a local variable directly - w_value = self.fastlocals_w[varindex] + w_value = self.locals_stack_w[varindex] if w_value is None: self._load_fast_failed(varindex) self.pushvalue(w_value) @@ -343,7 +343,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self.fastlocals_w[varindex] = w_newvalue + self.locals_stack_w[varindex] = w_newvalue def POP_TOP(self, oparg, next_instr): self.popvalue() @@ -696,12 +696,12 @@ LOAD_GLOBAL._always_inline_ = True def DELETE_FAST(self, varindex, next_instr): - if self.fastlocals_w[varindex] is None: + if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise operationerrfmt(self.space.w_UnboundLocalError, message, varname) - self.fastlocals_w[varindex] = None + self.locals_stack_w[varindex] = None def BUILD_TUPLE(self, itemcount, next_instr): items = self.popvalues(itemcount) @@ -1048,13 +1048,13 @@ def SET_ADD(self, oparg, next_instr): w_value = self.popvalue() - w_set = self.peekvalue(oparg) + w_set = self.peekvalue(oparg - 1) self.space.call_method(w_set, 'add', w_value) def MAP_ADD(self, oparg, next_instr): w_key = self.popvalue() w_value = self.popvalue() - w_dict = self.peekvalue(oparg) + w_dict = self.peekvalue(oparg - 1) self.space.setitem(w_dict, w_key, w_value) def SET_LINENO(self, lineno, next_instr): @@ -1091,12 +1091,10 @@ @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): - w_set = self.space.call_function(self.space.w_set) - if itemcount: - w_add = self.space.getattr(w_set, self.space.wrap("add")) - for i in range(itemcount): - w_item = self.popvalue() - self.space.call_function(w_add, w_item) + w_set = self.space.newset() + for i in range(itemcount): + w_item = self.popvalue() + self.space.call_method(w_set, 'add', w_item) self.pushvalue(w_set) def STORE_MAP(self, oparg, next_instr): diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import py from pypy.interpreter.argument import (Arguments, ArgumentsForTranslation, ArgErr, ArgErrUnknownKwds, ArgErrMultipleValues, ArgErrCount, rawshape, @@ -126,6 +127,7 @@ w_AttributeError = AttributeError w_UnicodeEncodeError = UnicodeEncodeError w_dict = dict + w_str = str class TestArgumentsNormal(object): @@ -485,26 +487,6 @@ args._match_signature(None, l, Signature(['abc'])) assert len(l) == 1 assert l[0] == space.wrap(5) - # - def str_w(w): - try: - return str(w) - except UnicodeEncodeError: - raise OperationError(space.w_UnicodeEncodeError, - space.wrap("oups")) - space.str_w = str_w - w_starstar = space.wrap({u'\u1234': 5}) - err = py.test.raises(OperationError, Arguments, - space, [], w_starstararg=w_starstar) - # Check that we get a TypeError. On CPython it is because of - # "no argument called '?'". On PyPy we get a TypeError too, but - # earlier: "keyword cannot be encoded to ascii". The - # difference, besides the error message, is only apparent if the - # receiver also takes a **arg. Then CPython passes the - # non-ascii unicode unmodified, whereas PyPy complains. We will - # not care until someone has a use case for that. - assert not err.value.match(space, space.w_UnicodeEncodeError) - assert err.value.match(space, space.w_TypeError) class TestErrorHandling(object): def test_missing_args(self): @@ -559,13 +541,26 @@ assert 0, "did not raise" def test_unknown_keywords(self): - err = ArgErrUnknownKwds(1, ['a', 'b'], [True, False]) + space = DummySpace() + err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [True, False], None) s = err.getmsg('foo') assert s == "foo() got an unexpected keyword argument 'b'" - err = ArgErrUnknownKwds(2, ['a', 'b', 'c'], [True, False, False]) + err = ArgErrUnknownKwds(space, 2, ['a', 'b', 'c'], + [True, False, False], None) s = err.getmsg('foo') assert s == "foo() got 2 unexpected keyword arguments" + def test_unknown_unicode_keyword(self): + class DummySpaceUnicode(DummySpace): + class sys: + defaultencoding = 'utf-8' + space = DummySpaceUnicode() + err = ArgErrUnknownKwds(space, 1, ['a', None, 'b', 'c'], + [True, False, True, True], + [unichr(0x1234), u'b', u'c']) + s = err.getmsg('foo') + assert s == "foo() got an unexpected keyword argument '\xe1\x88\xb4'" + def test_multiple_values(self): err = ArgErrMultipleValues('bla') s = err.getmsg('foo') @@ -592,6 +587,14 @@ exc = raises(TypeError, (lambda a, b, **kw: 0), a=1) assert exc.value.message == "() takes exactly 2 non-keyword arguments (0 given)" + def test_unicode_keywords(self): + def f(**kwargs): + assert kwargs[u"美"] == 42 + f(**{u"美" : 42}) + def f(x): pass + e = raises(TypeError, "f(**{u'ü' : 19})") + assert "?" in str(e.value) + def make_arguments_for_translation(space, args_w, keywords_w={}, w_stararg=None, w_starstararg=None): return ArgumentsForTranslation(space, args_w, keywords_w.keys(), diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py --- a/pypy/interpreter/test/test_eval.py +++ b/pypy/interpreter/test/test_eval.py @@ -15,16 +15,16 @@ self.code = code Frame.__init__(self, space) self.numlocals = numlocals - self.fastlocals_w = [None] * self.numlocals + self._fastlocals_w = [None] * self.numlocals def getcode(self): return self.code def setfastscope(self, scope_w): - self.fastlocals_w = scope_w + self._fastlocals_w = scope_w def getfastscope(self): - return self.fastlocals_w + return self._fastlocals_w def getfastscopelength(self): return self.numlocals @@ -38,11 +38,11 @@ self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({})) - self.f.fastlocals_w[0] = w(5) + self.f._fastlocals_w[0] = w(5) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5})) - self.f.fastlocals_w[2] = w(7) + self.f._fastlocals_w[2] = w(7) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5, 'args': 7})) @@ -57,13 +57,13 @@ w = self.space.wrap self.f.w_locals = self.space.wrap({}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [None]*5) + self.sameList(self.f._fastlocals_w, [None]*5) self.f.w_locals = self.space.wrap({'x': 5}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) + self.sameList(self.f._fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.wrap({'x':5, 'args':7}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), None, w(7), - None, None]) + self.sameList(self.f._fastlocals_w, [w(5), None, w(7), + None, None]) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -203,3 +203,26 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + import sys + class A(object): + def m(self): + "aaa" + m.x = 3 + + bm = A().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.im_class is A + if '__pypy__' in sys.builtin_module_names: + assert bm.__objclass__ is A + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + if '__pypy__' in sys.builtin_module_names: + assert l.append.__objclass__ is list + assert l.__add__.__self__ is l + assert l.__add__.__objclass__ is list diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -761,13 +761,17 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), + __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -136,6 +136,7 @@ 'call' : (('ref', 'varargs'), 'intorptr'), 'call_assembler' : (('varargs',), 'intorptr'), 'cond_call_gc_wb' : (('ptr', 'ptr'), None), + 'cond_call_gc_wb_array': (('ptr', 'int', 'ptr'), None), 'oosend' : (('varargs',), 'intorptr'), 'oosend_pure' : (('varargs',), 'intorptr'), 'guard_true' : (('bool',), None), @@ -857,6 +858,9 @@ def op_cond_call_gc_wb(self, descr, a, b): py.test.skip("cond_call_gc_wb not supported") + def op_cond_call_gc_wb_array(self, descr, a, b, c): + py.test.skip("cond_call_gc_wb_array not supported") + def op_oosend(self, descr, obj, *args): raise NotImplementedError("oosend for lltype backend??") diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -1,5 +1,6 @@ import py from pypy.rpython.lltypesystem import lltype, rffi, llmemory, rclass +from pypy.rpython.lltypesystem.lloperation import llop from pypy.jit.backend.llsupport import symbolic, support from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr from pypy.jit.metainterp.history import BasicFailDescr, LoopToken, BoxFloat @@ -45,6 +46,8 @@ size = 0 # help translation is_immutable = False + tid = llop.combine_ushort(lltype.Signed, 0, 0) + def __init__(self, size, count_fields_if_immut=-1): self.size = size self.count_fields_if_immut = count_fields_if_immut @@ -149,6 +152,7 @@ class BaseArrayDescr(AbstractDescr): _clsname = '' + tid = llop.combine_ushort(lltype.Signed, 0, 0) def get_base_size(self, translate_support_code): basesize, _, _ = symbolic.get_array_token(_A, translate_support_code) @@ -263,6 +267,9 @@ def __repr__(self): res = '%s(%s)' % (self.__class__.__name__, self.arg_classes) + extraeffect = getattr(self.extrainfo, 'extraeffect', None) + if extraeffect is not None: + res += ' EF=%r' % extraeffect oopspecindex = getattr(self.extrainfo, 'oopspecindex', 0) if oopspecindex: from pypy.jit.codewriter.effectinfo import EffectInfo diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -476,6 +476,7 @@ return cpu.cast_adr_to_int(funcaddr) def get_write_barrier_from_array_fn(self, cpu): + # returns a function with arguments [array, index, newvalue] llop1 = self.llop1 funcptr = llop1.get_write_barrier_from_array_failing_case( self.WB_ARRAY_FUNCPTR) @@ -552,7 +553,7 @@ self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType( [llmemory.Address, llmemory.Address], lltype.Void)) self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType( - [llmemory.Address, lltype.Signed], lltype.Void)) + [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void)) self.write_barrier_descr = WriteBarrierDescr(self) # def malloc_array(itemsize, tid, num_elem): @@ -763,10 +764,8 @@ newops.append(op) return newops - def _gen_write_barrier(self, newops, v_base, v_value_or_index): - # NB. the 2nd argument of COND_CALL_GC_WB is either a pointer - # (regular case), or an index (case of write_barrier_from_array) - args = [v_base, v_value_or_index] + def _gen_write_barrier(self, newops, v_base, v_value): + args = [v_base, v_value] newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None, descr=self.write_barrier_descr)) @@ -780,7 +779,10 @@ length = known_lengths.get(v_base, LARGE) if length >= LARGE: # unknown or too big: produce a write_barrier_from_array - self._gen_write_barrier(newops, v_base, v_index) + args = [v_base, v_index, v_value] + newops.append(ResOperation(rop.COND_CALL_GC_WB_ARRAY, args, + None, + descr=self.write_barrier_descr)) return # fall-back case: produce a write_barrier self._gen_write_barrier(newops, v_base, v_value) diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py --- a/pypy/jit/backend/llsupport/test/test_gc.py +++ b/pypy/jit/backend/llsupport/test/test_gc.py @@ -9,7 +9,7 @@ from pypy.jit.metainterp.resoperation import get_deep_immutable_oplist from pypy.jit.tool.oparser import parse from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists def test_boehm(): gc_ll_descr = GcLLDescr_boehm(None, None, None) @@ -553,12 +553,15 @@ del operations[:2] assert len(operations) == 2 # - assert operations[0].getopnum() == rop.COND_CALL_GC_WB - assert operations[0].getarg(0) == v_base if isinstance(v_new_length, ConstInt) and v_new_length.value < 130: + assert operations[0].getopnum() == rop.COND_CALL_GC_WB + assert operations[0].getarg(0) == v_base assert operations[0].getarg(1) == v_value else: + assert operations[0].getopnum() == rop.COND_CALL_GC_WB_ARRAY + assert operations[0].getarg(0) == v_base assert operations[0].getarg(1) == v_index + assert operations[0].getarg(2) == v_value assert operations[0].result is None # assert operations[1].getopnum() == rop.SETARRAYITEM_RAW diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -1694,12 +1694,13 @@ assert record == [] def test_cond_call_gc_wb_array(self): - def func_void(a, b): - record.append((a, b)) + def func_void(a, b, c): + record.append((a, b, c)) record = [] # S = lltype.GcStruct('S', ('tid', lltype.Signed)) - FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed], lltype.Void) + FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)], + lltype.Void) func_ptr = llhelper(lltype.Ptr(FUNC), func_void) funcbox = self.get_funcbox(self.cpu, func_ptr) class WriteBarrierDescr(AbstractDescr): @@ -1719,11 +1720,11 @@ s.tid = value sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s) del record[:] - self.execute_operation(rop.COND_CALL_GC_WB, - [BoxPtr(sgcref), ConstInt(123)], - 'void', descr=WriteBarrierDescr()) + self.execute_operation(rop.COND_CALL_GC_WB_ARRAY, + [BoxPtr(sgcref), ConstInt(123), BoxPtr(sgcref)], + 'void', descr=WriteBarrierDescr()) if cond: - assert record == [(s, 123)] + assert record == [(s, 123, s)] else: assert record == [] diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -703,22 +703,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: @@ -889,7 +895,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -901,7 +907,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) @@ -2223,15 +2229,26 @@ def genop_discard_cond_call_gc_wb(self, op, arglocs): # Write code equivalent to write_barrier() in the GC: it checks # a flag in the object at arglocs[0], and if set, it calls the - # function remember_young_pointer() from the GC. The two arguments - # to the call are in arglocs[:2]. The rest, arglocs[2:], contains + # function remember_young_pointer() from the GC. The arguments + # to the call are in arglocs[:N]. The rest, arglocs[N:], contains # registers that need to be saved and restored across the call. - # If op.getarg(1) is a int, it is an array index and we must call - # instead remember_young_pointer_from_array(). + # N is either 2 (regular write barrier) or 3 (array write barrier). descr = op.getdescr() if we_are_translated(): cls = self.cpu.gc_ll_descr.has_write_barrier_class() assert cls is not None and isinstance(descr, cls) + # + opnum = op.getopnum() + if opnum == rop.COND_CALL_GC_WB: + N = 2 + func = descr.get_write_barrier_fn(self.cpu) + elif opnum == rop.COND_CALL_GC_WB_ARRAY: + N = 3 + func = descr.get_write_barrier_from_array_fn(self.cpu) + assert func != 0 + else: + raise AssertionError(opnum) + # loc_base = arglocs[0] self.mc.TEST8(addr_add_const(loc_base, descr.jit_wb_if_flag_byteofs), imm(descr.jit_wb_if_flag_singlebyte)) @@ -2242,29 +2259,27 @@ if IS_X86_32: limit = -1 # push all arglocs on the stack elif IS_X86_64: - limit = 1 # push only arglocs[2:] on the stack + limit = N - 1 # push only arglocs[N:] on the stack for i in range(len(arglocs)-1, limit, -1): loc = arglocs[i] if isinstance(loc, RegLoc): self.mc.PUSH_r(loc.value) else: - assert not IS_X86_64 # there should only be regs in arglocs[2:] + assert not IS_X86_64 # there should only be regs in arglocs[N:] self.mc.PUSH_i32(loc.getint()) if IS_X86_64: # We clobber these registers to pass the arguments, but that's # okay, because consider_cond_call_gc_wb makes sure that any # caller-save registers with values in them are present in - # arglocs[2:] too, so they are saved on the stack above and + # arglocs[N:] too, so they are saved on the stack above and # restored below. - remap_frame_layout(self, arglocs[:2], [edi, esi], + if N == 2: + callargs = [edi, esi] + else: + callargs = [edi, esi, edx] + remap_frame_layout(self, arglocs[:N], callargs, X86_64_SCRATCH_REG) - - if op.getarg(1).type == INT: - func = descr.get_write_barrier_from_array_fn(self.cpu) - assert func != 0 - else: - func = descr.get_write_barrier_fn(self.cpu) - + # # misaligned stack in the call, but it's ok because the write barrier # is not going to call anything more. Also, this assumes that the # write barrier does not touch the xmm registers. (Slightly delicate @@ -2273,8 +2288,8 @@ # be done properly) self.mc.CALL(imm(func)) if IS_X86_32: - self.mc.ADD_ri(esp.value, 2*WORD) - for i in range(2, len(arglocs)): + self.mc.ADD_ri(esp.value, N*WORD) + for i in range(N, len(arglocs)): loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) @@ -2283,6 +2298,8 @@ assert 0 < offset <= 127 self.mc.overwrite(jz_location-1, chr(offset)) + genop_discard_cond_call_gc_wb_array = genop_discard_cond_call_gc_wb + def genop_force_token(self, op, arglocs, resloc): # RegAlloc.consider_force_token ensures this: assert isinstance(resloc, RegLoc) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -884,12 +884,12 @@ def consider_cond_call_gc_wb(self, op): assert op.result is None args = op.getarglist() - loc_newvalue_or_index= self.rm.make_sure_var_in_reg(op.getarg(1), args) - # ^^^ we force loc_newvalue_or_index in a reg (unless it's a Const), - # because it will be needed anyway by the following setfield_gc. - # It avoids loading it twice from the memory. - loc_base = self.rm.make_sure_var_in_reg(op.getarg(0), args) - arglocs = [loc_base, loc_newvalue_or_index] + N = len(args) + # we force all arguments in a reg (unless they are Consts), + # because it will be needed anyway by the following setfield_gc + # or setarrayitem_gc. It avoids loading it twice from the memory. + arglocs = [self.rm.make_sure_var_in_reg(op.getarg(i), args) + for i in range(N)] # add eax, ecx and edx as extra "arguments" to ensure they are # saved and restored. Fish in self.rm to know which of these # registers really need to be saved (a bit of a hack). Moreover, @@ -903,6 +903,8 @@ self.PerformDiscard(op, arglocs) self.rm.possibly_free_vars_for_op(op) + consider_cond_call_gc_wb_array = consider_cond_call_gc_wb + def fastpath_malloc_fixedsize(self, op, descr): assert isinstance(descr, BaseSizeDescr) self._do_fastpath_malloc(op, descr.size, descr.tid) diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -467,13 +469,13 @@ # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,6 +185,13 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -75,20 +75,22 @@ # OS_MATH_SQRT = 100 - def __new__(cls, readonly_descrs_fields, + def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, can_invalidate=False): - key = (_frozenset_or_none(readonly_descrs_fields), - _frozenset_or_none(write_descrs_fields), - _frozenset_or_none(write_descrs_arrays), + key = (frozenset(readonly_descrs_fields), + frozenset(readonly_descrs_arrays), + frozenset(write_descrs_fields), + frozenset(write_descrs_arrays), extraeffect, oopspecindex) if key in cls._cache: return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields + result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ extraeffect == EffectInfo.EF_PURE: result.write_descrs_fields = [] @@ -124,7 +126,7 @@ if effects is top_set: return EffectInfo(None, None, None, extraeffect) readonly_descrs_fields = [] - # readonly_descrs_arrays = [] --- not enabled for now + readonly_descrs_arrays = [] write_descrs_fields = [] write_descrs_arrays = [] @@ -150,10 +152,13 @@ elif tup[0] == "array": add_array(write_descrs_arrays, tup) elif tup[0] == "readarray": - pass + tupw = ("array",) + tup[1:] + if tupw not in effects: + add_array(readonly_descrs_arrays, tup) else: assert 0 return EffectInfo(readonly_descrs_fields, + readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect, diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -44,10 +44,6 @@ return True if mod.startswith('pypy.translator.'): # XXX wtf? return True - # string builder interface - if mod == 'pypy.rpython.lltypesystem.rbuilder': - return True - return False def look_inside_graph(self, graph): diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -35,6 +35,15 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays +def test_include_read_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo.write_descrs_fields + assert not effectinfo.write_descrs_arrays + def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) @@ -52,6 +61,16 @@ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.write_descrs_arrays +def test_dont_include_read_and_write_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A)), + ("array", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert not effectinfo.readonly_descrs_arrays + assert not effectinfo.write_descrs_fields + assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLException diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -14,8 +14,8 @@ from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper -from pypy.jit.metainterp.optimizeutil import InvalidLoop -from pypy.jit.metainterp.resume import NUMBERING +from pypy.jit.metainterp.optimize import InvalidLoop +from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong def giveup(): @@ -119,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -302,7 +303,7 @@ rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) CNT_INT = -0x20000000 CNT_REF = -0x40000000 @@ -633,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -316,6 +316,7 @@ if value in (rop.FORCE_TOKEN, rop.CALL_ASSEMBLER, rop.COND_CALL_GC_WB, + rop.COND_CALL_GC_WB_ARRAY, rop.DEBUG_MERGE_POINT, rop.JIT_DEBUG, rop.SETARRAYITEM_RAW, diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -4,7 +4,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rlib.objectmodel import we_are_translated, r_dict, Symbolic from pypy.rlib.objectmodel import compute_unique_id -from pypy.rlib.rarithmetic import intmask, r_int64 +from pypy.rlib.rarithmetic import r_int64 from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop @@ -791,6 +791,7 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py --- a/pypy/jit/metainterp/logger.py +++ b/pypy/jit/metainterp/logger.py @@ -103,6 +103,7 @@ if op.getopnum() == rop.DEBUG_MERGE_POINT: jd_sd = self.metainterp_sd.jitdrivers_sd[op.getarg(0).getint()] s = jd_sd.warmstate.get_location_str(op.getarglist()[2:]) + s = s.replace(',', '.') # we use comma for argument splitting return "debug_merge_point(%d, '%s')" % (op.getarg(1).getint(), s) if ops_offset is None: offset = -1 diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py --- a/pypy/jit/metainterp/optimize.py +++ b/pypy/jit/metainterp/optimize.py @@ -1,9 +1,20 @@ from pypy.rlib.debug import debug_start, debug_stop +from pypy.jit.metainterp.jitexc import JitException + +class InvalidLoop(JitException): + """Raised when the optimize*.py detect that the loop that + we are trying to build cannot possibly make sense as a + long-running loop (e.g. it cannot run 2 complete iterations).""" + +class RetraceLoop(JitException): + """ Raised when inlining a short preamble resulted in an + InvalidLoop. This means the optimized loop is too specialized + to be useful here, so we trace it again and produced a second + copy specialized in some different way. + """ # ____________________________________________________________ -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, optimize_bridge_1 - def optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): debug_start("jit-optimize") try: @@ -13,7 +24,7 @@ debug_stop("jit-optimize") def _optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): - cpu = metainterp_sd.cpu + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 loop.logops = metainterp_sd.logger_noopt.log_loop(loop.inputargs, loop.operations) # XXX do we really still need a list? @@ -36,7 +47,7 @@ def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts, inline_short_preamble, retraced=False): - cpu = metainterp_sd.cpu + from pypy.jit.metainterp.optimizeopt import optimize_bridge_1 bridge.logops = metainterp_sd.logger_noopt.log_loop(bridge.inputargs, bridge.operations) if old_loop_tokens: diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -15,7 +15,7 @@ ('virtualize', OptVirtualize), ('string', OptString), ('heap', OptHeap), - ('ffi', OptFfiCall), + ('ffi', None), ('unroll', None)] # no direct instantiation of unroll unroll_all_opts = unrolling_iterable(ALL_OPTS) @@ -25,10 +25,9 @@ ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) PARAMETERS['enable_opts'] = ALL_OPTS_NAMES -def optimize_loop_1(metainterp_sd, loop, enable_opts, +def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): - """Optimize loop.operations to remove internal overheadish operations. - """ + config = metainterp_sd.config optimizations = [] unroll = 'unroll' in enable_opts for name, opt in unroll_all_opts: @@ -40,6 +39,11 @@ # FIXME: Workaround to disable string optimisation # during preamble but to keep it during the loop optimizations.append(o) + elif name == 'ffi' and config.translation.jit_ffi: + # we cannot put the class directly in the unrolling_iterable, + # because we do not want it to be seen at all (to avoid to + # introduce a dependency on libffi in case we do not need it) + optimizations.append(OptFfiCall()) if ('rewrite' not in enable_opts or 'virtualize' not in enable_opts or 'heap' not in enable_opts): @@ -48,6 +52,17 @@ if inline_short_preamble: optimizations = [OptInlineShortPreamble(retraced)] + optimizations + return optimizations, unroll + + +def optimize_loop_1(metainterp_sd, loop, enable_opts, + inline_short_preamble=True, retraced=False): + """Optimize loop.operations to remove internal overheadish operations. + """ + + optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, + inline_short_preamble, retraced) + if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -8,8 +8,8 @@ class CachedField(object): def __init__(self): - # Cache information for a field descr. It can be in one - # of two states: + # Cache information for a field descr, or for an (array descr, index) + # pair. It can be in one of two states: # # 1. 'cached_fields' is a dict mapping OptValues of structs # to OptValues of fields. All fields on-heap are @@ -27,19 +27,19 @@ self._lazy_setfield_registered = False def do_setfield(self, optheap, op): - # Update the state with the SETFIELD_GC operation 'op'. + # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) if self.possible_aliasing(optheap, structvalue): self.force_lazy_setfield(optheap) assert not self.possible_aliasing(optheap, structvalue) cached_fieldvalue = self._cached_fields.get(structvalue, None) if cached_fieldvalue is not fieldvalue: # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields list + # myself in the optheap's _lazy_setfields_and_arrayitems list self._lazy_setfield = op if not self._lazy_setfield_registered: - optheap._lazy_setfields.append(self) + optheap._lazy_setfields_and_arrayitems.append(self) self._lazy_setfield_registered = True else: # this is the case where the pending setfield ends up @@ -65,7 +65,7 @@ if self._lazy_setfield is not None: op = self._lazy_setfield assert optheap.getvalue(op.getarg(0)) is structvalue - return optheap.getvalue(op.getarg(1)) + return optheap.getvalue(op.getarglist()[-1]) else: return self._cached_fields.get(structvalue, None) @@ -87,7 +87,7 @@ # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) def get_reconstructed(self, optimizer, valuemap): @@ -100,25 +100,20 @@ return cf -class CachedArrayItems(object): - def __init__(self): - self.fixed_index_items = {} - self.var_index_item = None - self.var_index_indexvalue = None - class BogusPureField(JitException): pass class OptHeap(Optimization): """Cache repeated heap accesses""" - + def __init__(self): # cached fields: {descr: CachedField} self.cached_fields = {} - self._lazy_setfields = [] - # cached array items: {descr: CachedArrayItems} + # cached array items: {array descr: {index: CachedField}} self.cached_arrayitems = {} + # + self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -126,34 +121,23 @@ new = OptHeap() if True: - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() else: assert 0 # was: new.lazy_setfields = self.lazy_setfields - + for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) - new.cached_arrayitems = {} - for descr, d in self.cached_arrayitems.items(): - newd = {} - new.cached_arrayitems[descr] = newd - for value, cache in d.items(): - newcache = CachedArrayItems() - newd[value.get_reconstructed(optimizer, valuemap)] = newcache - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_reconstructed(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) - for index, fieldvalue in cache.fixed_index_items.items(): - newcache.fixed_index_items[index] = \ - fieldvalue.get_reconstructed(optimizer, valuemap) + for descr, submap in self.cached_arrayitems.items(): + newdict = {} + for index, d in submap.items(): + newdict[index] = d.get_reconstructed(optimizer, valuemap) + new.cached_arrayitems[descr] = newdict return new def clean_caches(self): - del self._lazy_setfields[:] + del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() self.cached_arrayitems.clear() @@ -164,50 +148,16 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): - d = self.cached_arrayitems.get(descr, None) - if d is None: - d = self.cached_arrayitems[descr] = {} - cache = d.get(value, None) - if cache is None: - cache = d[value] = CachedArrayItems() - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - index = indexbox.getint() - if write: - for value, othercache in d.iteritems(): - # fixed index, clean the variable index cache, in case the - # index is the same - othercache.var_index_indexvalue = None - othercache.var_index_item = None - try: - del othercache.fixed_index_items[index] - except KeyError: - pass - cache.fixed_index_items[index] = fieldvalue - else: - if write: - for value, othercache in d.iteritems(): - # variable index, clear all caches for this descr - othercache.var_index_indexvalue = None - othercache.var_index_item = None - othercache.fixed_index_items.clear() - cache.var_index_indexvalue = indexvalue - cache.var_index_item = fieldvalue - - def read_cached_arrayitem(self, descr, value, indexvalue): - d = self.cached_arrayitems.get(descr, None) - if d is None: - return None - cache = d.get(value, None) - if cache is None: - return None - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - return cache.fixed_index_items.get(indexbox.getint(), None) - elif cache.var_index_indexvalue is indexvalue: - return cache.var_index_item - return None + def arrayitem_cache(self, descr, index): + try: + submap = self.cached_arrayitems[descr] + except KeyError: + submap = self.cached_arrayitems[descr] = {} + try: + cf = submap[index] + except KeyError: + cf = submap[index] = CachedField() + return cf def emit_operation(self, op): self.emitting_operation(op) @@ -219,7 +169,8 @@ if op.is_ovf(): return if op.is_guard(): - self.optimizer.pendingfields = self.force_lazy_setfields_for_guard() + self.optimizer.pendingfields = ( + self.force_lazy_setfields_and_arrayitems_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -248,6 +199,8 @@ # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: self.force_lazy_setfield(fielddescr) + for arraydescr in effectinfo.readonly_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: self.force_lazy_setfield(fielddescr) try: @@ -256,8 +209,11 @@ except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) try: - del self.cached_arrayitems[arraydescr] + submap = self.cached_arrayitems[arraydescr] + for cf in submap.itervalues(): + cf._cached_fields.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -266,7 +222,7 @@ # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. return - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() self.clean_caches() @@ -277,6 +233,10 @@ for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] + for submap in self.cached_arrayitems.itervalues(): + for cf in submap.itervalues(): + if value in cf._cached_fields: + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -285,6 +245,14 @@ return cf.force_lazy_setfield(self) + def force_lazy_setarrayitem(self, arraydescr): + try: + submap = self.cached_arrayitems[arraydescr] + except KeyError: + return + for cf in submap.values(): + cf.force_lazy_setfield(self) + def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes # sense to avoid a situation like "int_eq/setfield_gc/guard_true", @@ -309,30 +277,49 @@ newoperations[-2] = lastop newoperations[-1] = prevop - def force_all_lazy_setfields(self): - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + def _assert_valid_cf(self, cf): + # check that 'cf' is in cached_fields or cached_arrayitems + if not we_are_translated(): + if cf not in self.cached_fields.values(): + for submap in self.cached_arrayitems.values(): + if cf in submap.values(): + break + else: + assert 0, "'cf' not in cached_fields/cached_arrayitems" + + def force_all_lazy_setfields_and_arrayitems(self): + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) cf.force_lazy_setfield(self) - def force_lazy_setfields_for_guard(self): + def force_lazy_setfields_and_arrayitems_for_guard(self): pendingfields = [] - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) op = cf._lazy_setfield if op is None: continue # the only really interesting case that we need to handle in the # guards' resume data is that of a virtual object that is stored - # into a field of a non-virtual object. + # into a field of a non-virtual object. Here, 'op' in either + # SETFIELD_GC or SETARRAYITEM_GC. value = self.getvalue(op.getarg(0)) assert not value.is_virtual() # it must be a non-virtual - fieldvalue = self.getvalue(op.getarg(1)) + fieldvalue = self.getvalue(op.getarglist()[-1]) if fieldvalue.is_virtual(): # this is the case that we leave to resume.py + opnum = op.getopnum() + if opnum == rop.SETFIELD_GC: + itemindex = -1 + elif opnum == rop.SETARRAYITEM_GC: + indexvalue = self.getvalue(op.getarg(1)) + assert indexvalue.is_constant() + itemindex = indexvalue.box.getint() + assert itemindex >= 0 + else: + assert 0 pendingfields.append((op.getdescr(), value.box, - fieldvalue.get_key_box())) + fieldvalue.get_key_box(), itemindex)) else: cf.force_lazy_setfield(self) self.fixup_guard_situation() @@ -364,24 +351,45 @@ cf.do_setfield(self, op) def optimize_GETARRAYITEM_GC(self, op): - value = self.getvalue(op.getarg(0)) + arrayvalue = self.getvalue(op.getarg(0)) indexvalue = self.getvalue(op.getarg(1)) - fieldvalue = self.read_cached_arrayitem(op.getdescr(), value, indexvalue) - if fieldvalue is not None: - self.make_equal_to(op.result, fieldvalue) - return - ###self.optimizer.optimize_default(op) + cf = None + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + fieldvalue = cf.getfield_from_cache(self, arrayvalue) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # default case: produce the operation + arrayvalue.ensure_nonnull() self.emit_operation(op) - fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) + # the remember the result of reading the array item + if cf is not None: + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(arrayvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): - self.emit_operation(op) - value = self.getvalue(op.getarg(0)) - fieldvalue = self.getvalue(op.getarg(2)) + if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), + op.getarg(1)], + op.getdescr()): + os.write(2, '[bogus immutable array declaration: %s]\n' % + (op.getdescr().repr_of_descr())) + raise BogusPureField + # indexvalue = self.getvalue(op.getarg(1)) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - write=True) + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + cf.do_setfield(self, op) + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # and then emit the operation + self.emit_operation(op) def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeutil import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -23,7 +23,7 @@ def reconstruct_for_next_iteration(self, optimizer, valuemap): assert self.posponedop is None - return self + return self def propagate_forward(self, op): if op.is_ovf(): @@ -194,7 +194,7 @@ # Synthesize the reverse ops for optimize_default to reuse self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0)) self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1)) - + def optimize_INT_MUL_OVF(self, op): v1 = self.getvalue(op.getarg(0)) @@ -292,6 +292,11 @@ v1.intbound.make_ge(IntLowerBound(0)) v1.intbound.make_lt(IntUpperBound(256)) + def optimize_UNICODEGETITEM(self, op): + self.emit_operation(op) + v1 = self.getvalue(op.result) + v1.intbound.make_ge(IntLowerBound(0)) + def make_int_lt(self, box1, box2): v1 = self.getvalue(box1) v2 = self.getvalue(box2) @@ -368,6 +373,15 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -413,5 +427,6 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL + optimize_ops = _findall(OptIntBounds, 'optimize_') propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,9 +4,9 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs -from pypy.jit.metainterp.optimizeutil import descrlist_dict -from pypy.jit.metainterp.optimizeutil import InvalidLoop, args_dict +from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.rpython.lltypesystem import lltype @@ -141,6 +141,9 @@ # meaning it has been forced. return self.box is None + def is_forced_virtual(self): + return False + def getfield(self, ofs, default): raise NotImplementedError diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -184,6 +184,32 @@ else: self.emit_operation(op) + def optimize_FLOAT_MUL(self, op): + arg1 = op.getarg(0) + arg2 = op.getarg(1) + + # Constant fold f0 * 1.0 and turn f0 * -1.0 into a FLOAT_NEG, these + # work in all cases, including NaN and inf + for lhs, rhs in [(arg1, arg2), (arg2, arg1)]: + v1 = self.getvalue(lhs) + v2 = self.getvalue(rhs) + + if v1.is_constant(): + if v1.box.getfloat() == 1.0: + self.make_equal_to(op.result, v2) + return + elif v1.box.getfloat() == -1.0: + self.emit_operation(ResOperation( + rop.FLOAT_NEG, [rhs], op.result + )) + return + self.emit_operation(op) + + def optimize_FLOAT_NEG(self, op): + v1 = op.getarg(0) + self.emit_operation(op) + self.pure(rop.FLOAT_NEG, [op.result], v1) + def optimize_CALL_PURE(self, op): arg_consts = [] for i in range(op.numargs()): @@ -193,7 +219,7 @@ break arg_consts.append(const) else: - # all constant arguments: check if we already know the reslut + # all constant arguments: check if we already know the result try: result = self.optimizer.call_pure_results[arg_consts] except KeyError: diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/string.py --- a/pypy/jit/metainterp/optimizeopt/string.py +++ b/pypy/jit/metainterp/optimizeopt/string.py @@ -8,7 +8,7 @@ from pypy.jit.metainterp.optimizeopt import optimizer, virtualize from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1 from pypy.jit.metainterp.optimizeopt.optimizer import llhelper -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter import heaptracker from pypy.rlib.unroll import unrolling_iterable @@ -348,7 +348,7 @@ optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimizer, strbox, indexbox, mode): +def _strgetitem(optimization, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimizer.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,8 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self.optimizer, - value.force_box(),vindex.force_box(), mode) + resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/test/__init__.py b/pypy/jit/metainterp/optimizeopt/test/__init__.py new file mode 100644 diff --git a/pypy/jit/metainterp/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py rename from pypy/jit/metainterp/test/test_optimizebasic.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1,40 +1,15 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, FakeMetaInterpStaticData) from pypy.jit.metainterp.test.test_compile import FakeLogger import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt -from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation -from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.optimizeutil import args_dict - -##class FakeFrame(object): -## parent_resumedata_snapshot = None -## parent_resumedata_frame_info_list = None - -## def __init__(self, code="", pc=0): -## self.jitcode = code -## self.pc = pc - -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() - self.logger_ops = FakeLogger() - self.logger_noopt = FakeLogger() + def test_store_final_boxes_in_guard(): from pypy.jit.metainterp.compile import ResumeGuardDescr @@ -104,7 +79,7 @@ assert vinfo3 is vinfo4 def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil + from pypy.jit.metainterp.optimizeopt import util as optimizeutil h1 = optimizeutil.descrlist_hash([]) h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) h3 = optimizeutil.descrlist_hash( @@ -133,159 +108,55 @@ # ____________________________________________________________ -def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}, - text_right=None): - # try to use the full width of the terminal to display the list - # unfortunately, does not work with the default capture method of py.test - # (which is fd), you you need to use either -s or --capture=sys, else you - # get the standard 80 columns width - totwidth = py.io.get_terminal_width() - width = totwidth / 2 - 1 - print ' Comparing lists '.center(totwidth, '-') - text_right = text_right or 'expected' - print '%s| %s' % ('optimized'.center(width), text_right.center(width)) - for op1, op2 in zip(oplist1, oplist2): - txt1 = str(op1) - txt2 = str(op2) - while txt1 or txt2: - print '%s| %s' % (txt1[:width].ljust(width), txt2[:width]) - txt1 = txt1[width:] - txt2 = txt2[width:] - assert op1.getopnum() == op2.getopnum() - assert op1.numargs() == op2.numargs() - for i in range(op1.numargs()): - x = op1.getarg(i) - y = op2.getarg(i) - assert x == remap.get(y, y) - if op2.result in remap: - assert op1.result == remap[op2.result] - else: - remap[op2.result] = op1.result - if op1.getopnum() != rop.JUMP: # xxx obscure - assert op1.getdescr() == op2.getdescr() - if op1.getfailargs() or op2.getfailargs(): - assert len(op1.getfailargs()) == len(op2.getfailargs()) - if strict_fail_args: - for x, y in zip(op1.getfailargs(), op2.getfailargs()): - assert x == remap.get(y, y) - else: - fail_args1 = set(op1.getfailargs()) - fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()]) - assert fail_args1 == fail_args2 - assert len(oplist1) == len(oplist2) - print '-'*totwidth - return True - -def test_equaloplists(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops, namespace=namespace) - loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), - namespace=namespace) - assert equaloplists(loop1.operations, loop2.operations) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -def test_equaloplists_fail_args(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2, i1] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop2.operations)") - assert equaloplists(loop1.operations, loop2.operations, - strict_fail_args=False) - loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -# ____________________________________________________________ - -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) class BaseTestBasic(BaseTest): - def invent_fail_descr(self, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap) + enable_opts = "intbounds:rewrite:virtualize:string:heap" def optimize_loop(self, ops, optops, call_pure_results=None): + loop = self.parse(ops) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v - metainterp_sd = FakeMetaInterpStaticData(self.cpu) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - # - # XXX list the exact optimizations that are needed for each test - from pypy.jit.metainterp.optimizeopt import (OptIntBounds, - OptRewrite, - OptVirtualize, - OptString, - OptHeap, - Optimizer) - from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall - - optimizations = [OptIntBounds(), - OptRewrite(), - OptVirtualize(), - OptString(), - OptHeap(), - OptFfiCall(), - ] - optimizer = Optimizer(metainterp_sd, loop, optimizations) - optimizer.propagate_all_forward() - # expected = self.parse(optops) + self._do_optimize_loop(loop, call_pure_results) print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + + class BaseTestOptimizeBasic(BaseTestBasic): @@ -1234,8 +1105,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1600,9 +1471,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) jump(p1, i1, i2, p3) """ @@ -1776,6 +1647,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2038,7 +1910,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2056,7 +1927,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2074,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2290,25 +2159,83 @@ """ self.optimize_loop(ops, expected) + def test_fold_constant_partial_ops_float(self): + ops = """ + [f0] + f1 = float_mul(f0, 1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + + ops = """ + [f0] + f1 = float_mul(f0, -1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(-1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + def test_fold_repeated_float_neg(self): + ops = """ + [f0] + f1 = float_neg(f0) + f2 = float_neg(f1) + f3 = float_neg(f2) + f4 = float_neg(f3) + escape(f4) + jump(f4) + """ + expected = """ + [f0] + # The backend removes this dead op. + f1 = float_neg(f0) + escape(f0) + jump(f0) + """ + self.optimize_loop(ops, expected) + # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2417,7 +2344,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2438,7 +2364,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2458,7 +2383,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2484,7 +2408,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2509,7 +2433,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2533,7 +2456,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2554,7 +2476,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2575,7 +2496,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2597,7 +2517,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2639,7 +2558,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2665,7 +2583,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2689,9 +2606,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2983,7 +2897,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3029,7 +2942,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3068,7 +2980,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3095,7 +3006,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -4569,6 +4479,47 @@ # not obvious, because of the exception UnicodeDecodeError that # can be raised by ll_str2unicode() + def test_strgetitem_repeated(self): + ops = """ + [p0, i0] + i1 = strgetitem(p0, i0) + i2 = strgetitem(p0, i0) + i3 = int_eq(i1, i2) + guard_true(i3) [] + escape(i2) + jump(p0, i0) + """ + expected = """ + [p0, i0] + i1 = strgetitem(p0, i0) + escape(i1) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py rename from pypy/jit/metainterp/test/test_optimizefficall.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py --- a/pypy/jit/metainterp/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py @@ -2,8 +2,8 @@ from pypy.rlib.libffi import Func, types from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.metainterp.test.test_optimizebasic import BaseTestBasic -from pypy.jit.metainterp.test.test_optimizebasic import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import BaseTestBasic +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import LLtypeMixin class MyCallDescr(AbstractDescr): """ @@ -32,7 +32,8 @@ class TestFfiCall(BaseTestBasic, LLtypeMixin): - jit_ffi = True + + enable_opts = "intbounds:rewrite:virtualize:string:heap:ffi" class namespace: cpu = LLtypeMixin.cpu @@ -50,7 +51,7 @@ restype=types.sint) # def calldescr(cpu, FUNC, oopspecindex, extraeffect=None): - einfo = EffectInfo([], [], [], oopspecindex=oopspecindex, + einfo = EffectInfo([], [], [], [], oopspecindex=oopspecindex, extraeffect=extraeffect) return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo) # diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py rename from pypy/jit/metainterp/test/test_optimizeopt.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1,202 +1,88 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, Storage, _sortboxes) import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT, build_opt_chain +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.test.test_optimizebasic import equaloplists -from pypy.jit.metainterp.optimizeutil import args_dict - -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu, jit_ffi=False): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() - self.jit_ffi = jit_ffi - -def test_store_final_boxes_in_guard(): - from pypy.jit.metainterp.compile import ResumeGuardDescr - from pypy.jit.metainterp.resume import tag, TAGBOX - b0 = BoxInt() - b1 = BoxInt() - opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu), - None) - fdescr = ResumeGuardDescr() - op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr) - # setup rd data - fi0 = resume.FrameInfo(None, "code0", 11) - fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33) - snapshot0 = resume.Snapshot(None, [b0]) - fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1]) +from pypy.jit.metainterp.optimizeopt.util import args_dict +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import FakeMetaInterpStaticData +from pypy.config.pypyoption import get_pypy_config + + +def test_build_opt_chain(): + def check(chain, expected_names): + names = [opt.__class__.__name__ for opt in chain] + assert names == expected_names # - opt.store_final_boxes_in_guard(op) - if op.getfailargs() == [b0, b1]: - assert list(fdescr.rd_numb.nums) == [tag(1, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)] - else: - assert op.getfailargs() == [b1, b0] - assert list(fdescr.rd_numb.nums) == [tag(0, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(1, TAGBOX)] - assert fdescr.rd_virtuals is None - assert fdescr.rd_consts == [] - -def test_sharing_field_lists_of_virtual(): - class FakeOptimizer(object): - class cpu(object): - pass - opt = FakeOptimizer() - virt1 = virtualize.AbstractVirtualStructValue(opt, None) - lst1 = virt1._get_field_descr_list() - assert lst1 == [] - lst2 = virt1._get_field_descr_list() - assert lst1 is lst2 - virt1.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst3 = virt1._get_field_descr_list() - assert lst3 == [LLtypeMixin.valuedescr] - lst4 = virt1._get_field_descr_list() - assert lst3 is lst4 - - virt2 = virtualize.AbstractVirtualStructValue(opt, None) - lst5 = virt2._get_field_descr_list() - assert lst5 is lst1 - virt2.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst6 = virt1._get_field_descr_list() - assert lst6 is lst3 - -def test_reuse_vinfo(): - class FakeVInfo(object): - def set_content(self, fieldnums): - self.fieldnums = fieldnums - def equals(self, fieldnums): - return self.fieldnums == fieldnums - class FakeVirtualValue(virtualize.AbstractVirtualValue): - def _make_virtual(self, *args): - return FakeVInfo() - v1 = FakeVirtualValue(None, None, None) - vinfo1 = v1.make_virtual_info(None, [1, 2, 4]) - vinfo2 = v1.make_virtual_info(None, [1, 2, 4]) - assert vinfo1 is vinfo2 - vinfo3 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is not vinfo2 - vinfo4 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is vinfo4 - -def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil - h1 = optimizeutil.descrlist_hash([]) - h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) - h3 = optimizeutil.descrlist_hash( - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert h1 != h2 - assert h2 != h3 - assert optimizeutil.descrlist_eq([], []) - assert not optimizeutil.descrlist_eq([], [LLtypeMixin.valuedescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.nextdescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr, LLtypeMixin.nextdescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.nextdescr, LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - - # descrlist_eq should compare by identity of the descrs, not by the result - # of sort_key - class FakeDescr(object): - def sort_key(self): - return 1 - - assert not optimizeutil.descrlist_eq([FakeDescr()], [FakeDescr()]) + metainterp_sd = FakeMetaInterpStaticData(None) + chain, _ = build_opt_chain(metainterp_sd, "", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "heap:intbounds") + check(chain, ["OptInlineShortPreamble", "OptIntBounds", "OptHeap", "OptSimplify"]) + # + chain, unroll = build_opt_chain(metainterp_sd, "unroll") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + assert unroll + # + chain, _ = build_opt_chain(metainterp_sd, "aaa:bbb", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptFfiCall", "OptSimplify"]) + # + metainterp_sd.config = get_pypy_config(translating=True) + assert not metainterp_sd.config.translation.jit_ffi + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # ____________________________________________________________ -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure + + +class FakeDescr(compile.ResumeGuardDescr): + class rd_snapshot: + class prev: + prev = None + boxes = [] + boxes = [] def clone_if_mutable(self): - res = Storage(self.metainterp_sd, self.original_greenkey) - self.copy_all_attributes_into(res) - return res - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) - -class BaseTestOptimizeOpt(BaseTest): - jit_ffi = False - - def invent_fail_descr(self, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected, text_right=None): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap, text_right) - - def optimize_loop(self, ops, optops, expected_preamble=None, + return self + + +class BaseTestWithUnroll(BaseTest): + + enable_opts = "intbounds:rewrite:virtualize:string:heap:unroll" + + def optimize_loop(self, ops, expected, expected_preamble=None, call_pure_results=None): loop = self.parse(ops) - if optops != "crash!": - expected = self.parse(optops) - else: - expected = "crash!" + if expected != "crash!": + expected = self.parse(expected) if expected_preamble: expected_preamble = self.parse(expected_preamble) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v + loop.preamble = TreeLoop('preamble') loop.preamble.inputargs = loop.inputargs loop.preamble.token = LoopToken() - metainterp_sd = FakeMetaInterpStaticData(self.cpu, self.jit_ffi) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - class FakeDescr(compile.ResumeGuardDescr): - class rd_snapshot: - class prev: - prev = None - boxes = [] - boxes = [] - def clone_if_mutable(self): - return self loop.preamble.start_resumedescr = FakeDescr() - optimize_loop_1(metainterp_sd, loop, ALL_OPTS_DICT) # - + self._do_optimize_loop(loop, call_pure_results) + # print print loop.preamble.inputargs print '\n'.join([str(o) for o in loop.preamble.operations]) @@ -204,16 +90,14 @@ print loop.inputargs print '\n'.join([str(o) for o in loop.operations]) print - assert expected != "crash!", "should have raised an exception" self.assert_equal(loop, expected) if expected_preamble: self.assert_equal(loop.preamble, expected_preamble, text_right='expected preamble') - return loop -class OptimizeOptTest(BaseTestOptimizeOpt): +class OptimizeOptTest(BaseTestWithUnroll): def setup_method(self, meth=None): class FailDescr(compile.ResumeGuardDescr): @@ -1497,8 +1381,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1922,9 +1806,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -1934,9 +1818,9 @@ # i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -2171,6 +2055,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2857,8 +2742,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -5427,7 +5310,7 @@ """ self.optimize_strunicode_loop(ops, expected) - def test_strgetitem_small(self): + def test_strgetitem_bounds(self): ops = """ [p0, i0] i1 = strgetitem(p0, i0) @@ -5439,7 +5322,20 @@ """ expected = """ [p0, i0] - i1 = strgetitem(p0, i0) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_unicodegetitem_bounds(self): + ops = """ + [p0, i0] + i1 = unicodegetitem(p0, i0) + i2 = int_lt(i1, 0) + guard_false(i2) [] + jump(p0, i0) + """ + expected = """ + [p0, i0] jump(p0, i0) """ self.optimize_loop(ops, expected) @@ -5953,3 +5849,54 @@ jump(i3, i4) """ self.optimize_loop(ops, expected) + + def test_forced_virtual_pure_getfield(self): + ops = """ + [p0] + p1 = getfield_gc_pure(p0, descr=valuedescr) + jump(p1) + """ + self.optimize_loop(ops, ops) + + ops = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + p2 = getfield_gc_pure(p1, descr=valuedescr) + escape(p2) + jump(p0) + """ + expected = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + escape(p0) + jump(p0) + """ + self.optimize_loop(ops, expected) + + def test_setarrayitem_lazy(self): + ops = """ + [i0, i1] + p0 = escape() + i2 = escape() + p1 = new_with_vtable(ConstClass(node_vtable)) + setarrayitem_gc(p0, 2, p1, descr=arraydescr) + guard_true(i2) [] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + expected = """ + [i0, i1] + p0 = escape() + i2 = escape() + guard_true(i2) [p0] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py rename from pypy/jit/metainterp/test/test_optimizeutil.py rename to pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/test/test_optimizeutil.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -9,11 +9,15 @@ from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, Const, TreeLoop, BoxObj, ConstObj, AbstractDescr) -from pypy.jit.metainterp.optimizeutil import sort_descrs, InvalidLoop +from pypy.jit.metainterp.optimizeopt.util import sort_descrs, equaloplists +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter.heaptracker import register_known_gctype, adr2int -from pypy.jit.tool.oparser import parse +from pypy.jit.tool.oparser import parse, pure_parse from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr +from pypy.jit.metainterp import compile, resume, history +from pypy.jit.metainterp.jitprof import EmptyProfiler +from pypy.config.pypyoption import get_pypy_config def test_sort_descrs(): class PseudoDescr(AbstractDescr): @@ -28,6 +32,44 @@ sort_descrs(lst2) assert lst2 == lst +def test_equaloplists(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops, namespace=namespace) + loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), + namespace=namespace) + assert equaloplists(loop1.operations, loop2.operations) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + +def test_equaloplists_fail_args(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2, i1] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop2.operations)") + assert equaloplists(loop1.operations, loop2.operations, + strict_fail_args=False) + loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + # ____________________________________________________________ class LLtypeMixin(object): @@ -124,19 +166,19 @@ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [])) + EffectInfo([], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [])) + EffectInfo([], [], [adescr], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [arraydescr])) + EffectInfo([], [], [adescr], [arraydescr])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([adescr], [], [])) + EffectInfo([adescr], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([nextdescr], [], [], + EffectInfo([nextdescr], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), @@ -153,15 +195,15 @@ _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): @@ -256,8 +298,45 @@ ## u_vtable_adr: cpu.typedescrof(U)} ## namespace = locals() +# ____________________________________________________________ + + + +class Fake(object): + failargs_limit = 1000 + storedebug = None + + +class FakeMetaInterpStaticData(object): + + def __init__(self, cpu): + self.cpu = cpu + self.profiler = EmptyProfiler() + self.options = Fake() + self.globaldata = Fake() + self.config = get_pypy_config(translating=True) + self.config.translation.jit_ffi = True + + +class Storage(compile.ResumeGuardDescr): + "for tests." + def __init__(self, metainterp_sd=None, original_greenkey=None): + self.metainterp_sd = metainterp_sd + self.original_greenkey = original_greenkey + def store_final_boxes(self, op, boxes): + op.setfailargs(boxes) + def __eq__(self, other): + return type(self) is type(other) # xxx obscure + def clone_if_mutable(self): + res = Storage(self.metainterp_sd, self.original_greenkey) + self.copy_all_attributes_into(res) + return res + +def _sortboxes(boxes): + _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} + return sorted(boxes, key=lambda box: _kind2count[box.type]) + class BaseTest(object): - invent_fail_descr = None def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, @@ -265,5 +344,40 @@ boxkinds=boxkinds, invent_fail_descr=self.invent_fail_descr) + def invent_fail_descr(self, model, fail_args): + if fail_args is None: + return None + descr = Storage() + descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) + descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) + return descr + + def assert_equal(self, optimized, expected, text_right=None): + from pypy.jit.metainterp.optimizeopt.util import equaloplists + assert len(optimized.inputargs) == len(expected.inputargs) + remap = {} + for box1, box2 in zip(optimized.inputargs, expected.inputargs): + assert box1.__class__ == box2.__class__ + remap[box2] = box1 + assert equaloplists(optimized.operations, + expected.operations, False, remap, text_right) + + def _do_optimize_loop(self, loop, call_pure_results): + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 + from pypy.jit.metainterp.optimizeopt.util import args_dict + + self.loop = loop + loop.call_pure_results = args_dict() + if call_pure_results is not None: + for k, v in call_pure_results.items(): + loop.call_pure_results[list(k)] = v + metainterp_sd = FakeMetaInterpStaticData(self.cpu) + if hasattr(self, 'vrefinfo'): + metainterp_sd.virtualref_info = self.vrefinfo + if hasattr(self, 'callinfocollection'): + metainterp_sd.callinfocollection = self.callinfocollection + # + optimize_loop_1(metainterp_sd, loop, self.enable_opts) + # ____________________________________________________________ diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -5,7 +5,7 @@ from pypy.jit.metainterp.resume import Snapshot from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop, RetraceLoop +from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.history import make_hashable_int from pypy.jit.codewriter.effectinfo import EffectInfo diff --git a/pypy/jit/metainterp/optimizeutil.py b/pypy/jit/metainterp/optimizeopt/util.py rename from pypy/jit/metainterp/optimizeutil.py rename to pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeutil.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -1,21 +1,10 @@ +import py from pypy.rlib.objectmodel import r_dict, compute_identity_hash from pypy.rlib.rarithmetic import intmask from pypy.rlib.unroll import unrolling_iterable from pypy.jit.metainterp import resoperation, history -from pypy.jit.metainterp.jitexc import JitException from pypy.rlib.debug import make_sure_not_resized - -class InvalidLoop(JitException): - """Raised when the optimize*.py detect that the loop that - we are trying to build cannot possibly make sense as a - long-running loop (e.g. it cannot run 2 complete iterations).""" - -class RetraceLoop(JitException): - """ Raised when inlining a short preamble resulted in an - InvalidLoop. This means the optimized loop is too specialized - to be useful here, so we trace it again and produced a second - copy specialized in some different way. - """ +from pypy.jit.metainterp.resoperation import rop # ____________________________________________________________ # Misc. utilities @@ -113,3 +102,49 @@ def args_dict_box(): return r_dict(args_eq, args_hash) + + +# ____________________________________________________________ + +def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}, + text_right=None): + # try to use the full width of the terminal to display the list + # unfortunately, does not work with the default capture method of py.test + # (which is fd), you you need to use either -s or --capture=sys, else you + # get the standard 80 columns width + totwidth = py.io.get_terminal_width() + width = totwidth / 2 - 1 + print ' Comparing lists '.center(totwidth, '-') + text_right = text_right or 'expected' + print '%s| %s' % ('optimized'.center(width), text_right.center(width)) + for op1, op2 in zip(oplist1, oplist2): + txt1 = str(op1) + txt2 = str(op2) + while txt1 or txt2: + print '%s| %s' % (txt1[:width].ljust(width), txt2[:width]) + txt1 = txt1[width:] + txt2 = txt2[width:] + assert op1.getopnum() == op2.getopnum() + assert op1.numargs() == op2.numargs() + for i in range(op1.numargs()): + x = op1.getarg(i) + y = op2.getarg(i) + assert x == remap.get(y, y) + if op2.result in remap: + assert op1.result == remap[op2.result] + else: + remap[op2.result] = op1.result + if op1.getopnum() != rop.JUMP: # xxx obscure + assert op1.getdescr() == op2.getdescr() + if op1.getfailargs() or op2.getfailargs(): + assert len(op1.getfailargs()) == len(op2.getfailargs()) + if strict_fail_args: + for x, y in zip(op1.getfailargs(), op2.getfailargs()): + assert x == remap.get(y, y) + else: + fail_args1 = set(op1.getfailargs()) + fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()]) + assert fail_args1 == fail_args2 + assert len(oplist1) == len(oplist2) + print '-'*totwidth + return True diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.history import Const, ConstInt, BoxInt from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs -from pypy.jit.metainterp.optimizeutil import descrlist_dict +from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.optimizeopt import optimizer from pypy.jit.metainterp.executor import execute @@ -20,6 +20,9 @@ self.source_op = source_op # the NEW_WITH_VTABLE/NEW_ARRAY operation # that builds this box + def is_forced_virtual(self): + return self.box is not None + def get_key_box(self): if self.box is None: return self.keybox @@ -120,7 +123,6 @@ op = ResOperation(rop.SETFIELD_GC, [box, subbox], None, descr=ofs) newoperations.append(op) - self._fields = None def _get_field_descr_list(self): _cached_sorted_fields = self._cached_sorted_fields @@ -351,7 +353,7 @@ if not self.optimizer.cpu.ts.CONST_NULL.same_constant(objbox): seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None, descr = vrefinfo.descr_forced)) - + # - set 'virtual_token' to TOKEN_NONE args = [op.getarg(0), ConstInt(vrefinfo.TOKEN_NONE)] seo(ResOperation(rop.SETFIELD_GC, args, None, @@ -365,6 +367,14 @@ def optimize_GETFIELD_GC(self, op): value = self.getvalue(op.getarg(0)) + # If this is an immutable field (as indicated by op.is_always_pure()) + # then it's safe to reuse the virtual's field, even if it has been + # forced, because it should never be written to again. + if value.is_forced_virtual() and op.is_always_pure(): + fieldvalue = value.getfield(op.getdescr(), None) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return if value.is_virtual(): assert isinstance(value, AbstractVirtualValue) fieldvalue = value.getfield(op.getdescr(), None) @@ -382,6 +392,7 @@ def optimize_SETFIELD_GC(self, op): value = self.getvalue(op.getarg(0)) + if value.is_virtual(): fieldvalue = self.getvalue(op.getarg(1)) value.setfield(op.getdescr(), fieldvalue) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1,5 +1,5 @@ -import py, os, sys -from pypy.rpython.lltypesystem import lltype, llmemory, rclass +import py, sys +from pypy.rpython.lltypesystem import lltype, rclass from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import debug_start, debug_stop, debug_print @@ -15,13 +15,13 @@ from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE, \ - ABORT_BAD_LOOP, ABORT_FORCE_QUASIIMMUT + ABORT_FORCE_QUASIIMMUT from pypy.jit.metainterp.jitexc import JitException, get_llexception -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize -from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr, MissingLiveness -from pypy.jit.codewriter import heaptracker, longlong -from pypy.jit.metainterp.optimizeutil import RetraceLoop, args_dict_box, args_dict +from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr +from pypy.jit.codewriter import heaptracker +from pypy.jit.metainterp.optimizeopt.util import args_dict_box +from pypy.jit.metainterp.optimize import RetraceLoop # ____________________________________________________________ @@ -867,7 +867,7 @@ any_operation = len(self.metainterp.history.operations) > 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jdindex, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -914,8 +914,10 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jd_index, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation + loc = jitdriver_sd.warmstate.get_location_str(greenkey) + debug_print(loc) args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @@ -1262,8 +1264,7 @@ logger_ops = None def __init__(self, cpu, options, - ProfilerClass=EmptyProfiler, warmrunnerdesc=None, - jit_ffi=True): + ProfilerClass=EmptyProfiler, warmrunnerdesc=None): self.cpu = cpu self.stats = self.cpu.stats self.options = options @@ -1273,7 +1274,11 @@ self.profiler = ProfilerClass() self.profiler.cpu = cpu self.warmrunnerdesc = warmrunnerdesc - self.jit_ffi = jit_ffi + if warmrunnerdesc: + self.config = warmrunnerdesc.translator.config + else: + from pypy.config.pypyoption import get_pypy_config + self.config = get_pypy_config(translating=True) backendmodule = self.cpu.__module__ backendmodule = backendmodule.split('.')[-2] @@ -1924,7 +1929,6 @@ self.history.inputargs = original_inputargs self.history.operations.pop() # remove the JUMP - # FIXME: Why is self.history.inputargs not restored? def compile_bridge(self, live_arg_boxes): num_green_args = self.jitdriver_sd.num_green_args @@ -1960,6 +1964,8 @@ start_resumedescr, False) self.history.operations.pop() # remove the JUMP if loop_token is None: + self.history.inputargs = original_inputargs + self.history.operations = original_operations return if loop_token.short_preamble: @@ -2114,7 +2120,6 @@ def vrefs_after_residual_call(self): vrefinfo = self.staticdata.virtualref_info for i in range(0, len(self.virtualref_boxes), 2): - virtualbox = self.virtualref_boxes[i] vrefbox = self.virtualref_boxes[i+1] vref = vrefbox.getref_base() if vrefinfo.tracing_after_residual_call(vref): diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -191,9 +191,15 @@ # of the operation. It must inherit from AbstractDescr. The # backend provides it with cpu.fielddescrof(), cpu.arraydescrof(), # cpu.calldescrof(), and cpu.typedescrof(). + self._check_descr(descr) + self._descr = descr + + def _check_descr(self, descr): + if not we_are_translated() and getattr(descr, 'I_am_a_descr', False): + return # needed for the mock case in oparser_model from pypy.jit.metainterp.history import check_descr check_descr(descr) - self._descr = descr + class GuardResOp(ResOpWithDescr): @@ -471,8 +477,8 @@ 'STRSETITEM/3', 'UNICODESETITEM/3', #'RUNTIMENEW/1', # ootype operation - 'COND_CALL_GC_WB/2d', # [objptr, newvalue] or [arrayptr, index] - # (for the write barrier, latter is in an array) + 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier) + 'COND_CALL_GC_WB_ARRAY/3d', # [objptr, arrayindex, newvalue] (write barr.) 'DEBUG_MERGE_POINT/*', # debugging only 'JIT_DEBUG/*', # debugging only 'VIRTUAL_REF_FINISH/2', # removed before it's passed to the backend diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -2,15 +2,17 @@ from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr +from pypy.rpython import annlowlevel from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop # Logic to encode the chain of frames and the state of the boxes at a # guard operation, and to decode it again. This is a bit advanced, @@ -82,6 +84,13 @@ ('nums', lltype.Array(rffi.SHORT))) NUMBERINGP.TO.become(NUMBERING) +PENDINGFIELDSTRUCT = lltype.Struct('PendingField', + ('lldescr', annlowlevel.base_ptr_lltype()), + ('num', rffi.SHORT), + ('fieldnum', rffi.SHORT), + ('itemindex', rffi.INT)) +PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) + TAGMASK = 3 def tag(value, tagbits): @@ -329,7 +338,7 @@ value = values[box] value.get_args_for_fail(self) - for _, box, fieldbox in pending_setfields: + for _, box, fieldbox, _ in pending_setfields: self.register_box(box) self.register_box(fieldbox) value = values[fieldbox] @@ -405,13 +414,25 @@ return False def _add_pending_fields(self, pending_setfields): - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) if pending_setfields: - rd_pendingfields = [] - for descr, box, fieldbox in pending_setfields: + n = len(pending_setfields) + rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) + for i in range(n): + descr, box, fieldbox, itemindex = pending_setfields[i] + lldescr = annlowlevel.cast_instance_to_base_ptr(descr) num = self._gettagged(box) fieldnum = self._gettagged(fieldbox) - rd_pendingfields.append((descr, num, fieldnum)) + # the index is limited to 2147483647 (64-bit machines only) + if itemindex > 2147483647: + from pypy.jit.metainterp import compile + compile.giveup() + itemindex = rffi.cast(rffi.INT, itemindex) + # + rd_pendingfields[i].lldescr = lldescr + rd_pendingfields[i].num = num + rd_pendingfields[i].fieldnum = fieldnum + rd_pendingfields[i].itemindex= itemindex self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): @@ -727,10 +748,28 @@ self.virtuals_cache = [self.virtual_default] * len(virtuals) def _prepare_pendingfields(self, pendingfields): - if pendingfields is not None: - for descr, num, fieldnum in pendingfields: + if pendingfields: + for i in range(len(pendingfields)): + lldescr = pendingfields[i].lldescr + num = pendingfields[i].num + fieldnum = pendingfields[i].fieldnum + itemindex= pendingfields[i].itemindex + descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, + lldescr) struct = self.decode_ref(num) - self.setfield(descr, struct, fieldnum) + itemindex = rffi.cast(lltype.Signed, itemindex) + if itemindex < 0: + self.setfield(descr, struct, fieldnum) + else: + self.setarrayitem(descr, struct, itemindex, fieldnum) + + def setarrayitem(self, arraydescr, array, index, fieldnum): + if arraydescr.is_array_of_pointers(): + self.setarrayitem_ref(arraydescr, array, index, fieldnum) + elif arraydescr.is_array_of_floats(): + self.setarrayitem_float(arraydescr, array, index, fieldnum) + else: + self.setarrayitem_int(arraydescr, array, index, fieldnum) def _prepare_next_section(self, info): # Use info.enumerate_vars(), normally dispatching to @@ -903,15 +942,15 @@ structbox, fieldbox) def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, INT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT) def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, REF) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF) def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) - def setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): + def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): itembox = self.decode_box(fieldnum, kind) self.metainterp.execute_and_record(rop.SETARRAYITEM_GC, arraydescr, arraybox, diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -500,7 +500,7 @@ y -= x return y # - res = self.meta_interp(f, [3, 6], repeat=7) + res = self.meta_interp(f, [3, 6], repeat=7, function_threshold=0) assert res == 6 - 4 - 5 self.check_history(call=0) # because the trace starts in the middle # @@ -1677,6 +1677,8 @@ res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) self.check_loop_count(9) + self.check_loops(getarrayitem_gc=8, everywhere=True) + py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) def test_multiple_specialied_versions_bridge(self): @@ -2230,6 +2232,87 @@ self.check_loops(getfield_gc_pure=0) self.check_loops(getfield_gc_pure=2, everywhere=True) + def test_frame_finished_during_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 1 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 1000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'a']) + def f(): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 2) + a = A(0) + sa = 0 + while a.val < 8: + myjitdriver.jit_merge_point(a=a, sa=sa) + a = a.inc() + if a.val > 4: + a = B(a.val) + sa += a.num + return sa + res = self.meta_interp(f, []) + assert res == f() + + def test_frame_finished_during_continued_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 100 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 10000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'b', 'a']) + def f(b): + myjitdriver.set_param('threshold', 6) + myjitdriver.set_param('trace_eagerness', 4) + a = A(0) + sa = 0 + while a.val < 15: + myjitdriver.jit_merge_point(a=a, b=b, sa=sa) + a = a.inc() + if a.val > 8: + a = B(a.val) + if b == 1: + b = 2 + else: + b = 1 + sa += a.num + b + return sa + res = self.meta_interp(f, [1]) + assert res == f(1) + + def test_remove_array_operations(self): + myjitdriver = JitDriver(greens = [], reds = ['a']) + class W_Int: + def __init__(self, intvalue): + self.intvalue = intvalue + def f(x): + a = [W_Int(x)] + while a[0].intvalue > 0: + myjitdriver.jit_merge_point(a=a) + a[0] = W_Int(a[0].intvalue - 3) + return a[0].intvalue + res = self.meta_interp(f, [100]) + assert res == -2 + #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py --- a/pypy/jit/metainterp/test/test_compile.py +++ b/pypy/jit/metainterp/test/test_compile.py @@ -1,3 +1,4 @@ +from pypy.config.pypyoption import get_pypy_config from pypy.jit.metainterp.history import LoopToken, ConstInt, History, Stats from pypy.jit.metainterp.history import BoxInt, INT from pypy.jit.metainterp.compile import insert_loop_token, compile_new_loop @@ -5,7 +6,7 @@ from pypy.jit.metainterp.compile import ResumeGuardCountersInt from pypy.jit.metainterp.compile import compile_tmp_callback from pypy.jit.metainterp import jitprof, typesystem, compile -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.tool.oparser import parse from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT @@ -57,11 +58,11 @@ logger_noopt = FakeLogger() logger_ops = FakeLogger() + config = get_pypy_config(translating=True) stats = Stats() profiler = jitprof.EmptyProfiler() warmrunnerdesc = None - jit_ffi = False def log(self, msg, event_kind=None): pass diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -130,6 +130,38 @@ assert res == 50 self.check_loops(int_mod=1) + def test_repeated_lookup(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'd']) + class Wrapper(object): + _immutable_fields_ = ["value"] + def __init__(self, value): + self.value = value + def eq_func(a, b): + return a.value == b.value + def hash_func(x): + return objectmodel.compute_hash(x.value) + + def f(n): + d = None + while n > 0: + myjitdriver.jit_merge_point(n=n, d=d) + d = objectmodel.r_dict(eq_func, hash_func) + y = Wrapper(str(n)) + d[y] = n - 1 + n = d[y] + return d[Wrapper(str(n + 1))] + + res = self.meta_interp(f, [100], listops=True) + assert res == f(50) + # XXX: ideally there would be 7 calls here, but repeated CALL_PURE with + # the same arguments are not folded, because we have conflicting + # definitions of pure, once strhash can be appropriately folded + # this should be decreased to seven. + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + "guard_true": 1, "int_and": 1, "int_gt": 1, + "int_is_true": 1, "int_sub": 1, "jump": 1, + "new_with_vtable": 1, "setfield_gc": 1}) + class TestOOtype(DictTests, OOJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py --- a/pypy/jit/metainterp/test/test_jitdriver.py +++ b/pypy/jit/metainterp/test/test_jitdriver.py @@ -113,6 +113,7 @@ return n # def loop2(g, r): + myjitdriver1.set_param('function_threshold', 0) while r > 0: myjitdriver2.can_enter_jit(g=g, r=r) myjitdriver2.jit_merge_point(g=g, r=r) diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -49,7 +49,7 @@ x = l[n] l = [3] * 100 l[3] = x - l[3] = x + 1 + l[4] = x + 1 n -= 1 return l[0] diff --git a/pypy/jit/metainterp/test/test_logger.py b/pypy/jit/metainterp/test/test_logger.py --- a/pypy/jit/metainterp/test/test_logger.py +++ b/pypy/jit/metainterp/test/test_logger.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp import logger from pypy.jit.metainterp.typesystem import llhelper from StringIO import StringIO -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.metainterp.history import AbstractDescr, LoopToken, BasicFailDescr from pypy.jit.backend.model import AbstractCPU @@ -53,7 +53,7 @@ def make_metainterp_sd(self): class FakeJitDriver(object): class warmstate(object): - get_location_str = staticmethod(lambda args: args[0]._get_str()) + get_location_str = staticmethod(lambda args: "dupa") class FakeMetaInterpSd: cpu = AbstractCPU() @@ -116,10 +116,10 @@ def test_debug_merge_point(self): inp = ''' [] - debug_merge_point(0, 0, "dupa") + debug_merge_point(0, 0) ''' _, loop, oloop = self.reparse(inp, check_equal=False) - assert loop.operations[0].getarg(2)._get_str() == "dupa" + assert loop.operations[0].getarg(1).getint() == 0 assert oloop.operations[0].getarg(1)._get_str() == "dupa" def test_floats(self): diff --git a/pypy/jit/metainterp/test/test_pyjitpl.py b/pypy/jit/metainterp/test/test_pyjitpl.py --- a/pypy/jit/metainterp/test/test_pyjitpl.py +++ b/pypy/jit/metainterp/test/test_pyjitpl.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.history import BoxInt, ConstInt from pypy.jit.metainterp.history import History from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.codewriter.jitcode import JitCode diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -483,6 +483,7 @@ def main(inline): myjitdriver.set_param("threshold", 10) + myjitdriver.set_param('function_threshold', 60) if inline: myjitdriver.set_param('inlining', True) else: @@ -1193,6 +1194,51 @@ i -= 1 self.meta_interp(portal, [0, 10], inline=True) + def test_trace_from_start_always(self): + from pypy.rlib.nonconst import NonConstant + + driver = JitDriver(greens = ['c'], reds = ['i', 'v']) + + def portal(c, i, v): + while i > 0: + driver.jit_merge_point(c=c, i=i, v=v) + portal(c, i - 1, v) + if v: + driver.can_enter_jit(c=c, i=i, v=v) + break + + def main(c, i, set_param, v): + if set_param: + driver.set_param('function_threshold', 0) + portal(c, i, v) + + self.meta_interp(main, [10, 10, False, False], inline=True) + self.check_tree_loop_count(1) + self.check_loop_count(0) + self.meta_interp(main, [3, 10, True, False], inline=True) + self.check_tree_loop_count(0) + self.check_loop_count(0) + + def test_trace_from_start_does_not_prevent_inlining(self): + driver = JitDriver(greens = ['c', 'bc'], reds = ['i']) + + def portal(bc, c, i): + while True: + driver.jit_merge_point(c=c, bc=bc, i=i) + if bc == 0: + portal(1, 8, 0) + c += 1 + else: + return + if c == 10: # bc == 0 + c = 0 + if i >= 100: + return + driver.can_enter_jit(c=c, bc=bc, i=i) + i += 1 + + self.meta_interp(portal, [0, 0, 0], inline=True) + self.check_loops(call=0, call_may_force=0) class TestLLtype(RecursiveTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py --- a/pypy/jit/metainterp/test/test_resume.py +++ b/pypy/jit/metainterp/test/test_resume.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.resume import * from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt from pypy.jit.metainterp.history import ConstPtr, ConstFloat -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.metainterp import executor from pypy.jit.codewriter import heaptracker, longlong @@ -1238,7 +1238,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, values, 0) assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)]) + modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s, -1)]) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume @@ -1259,6 +1259,106 @@ assert len(expected) == len(trace) assert demo55.next == demo66 +def test_virtual_adder_pending_fields_and_arrayitems(): + class Storage(object): + pass + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier._add_pending_fields([]) + assert not storage.rd_pendingfields + # + class FieldDescr(object): + pass + field_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061)} + modifier._add_pending_fields([(field_a, 42, 61, -1)]) + pf = storage.rd_pendingfields + assert len(pf) == 1 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is field_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + # + array_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061), + 62: rffi.cast(rffi.SHORT, 1062), + 63: rffi.cast(rffi.SHORT, 1063)} + modifier._add_pending_fields([(array_a, 42, 61, 0), + (array_a, 42, 62, 2147483647)]) + pf = storage.rd_pendingfields + assert len(pf) == 2 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[1].num) == 1042 + assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 + assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + # + from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole + py.test.raises(SwitchToBlackhole, modifier._add_pending_fields, + [(array_a, 42, 63, 2147483648)]) + +def test_resume_reader_fields_and_arrayitems(): + class ResumeReader(AbstractResumeDataReader): + def __init__(self, got=None, got_array=None): + self.got = got + self.got_array = got_array + def setfield(self, descr, struct, fieldnum): + assert lltype.typeOf(struct) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got.append((descr, struct, fieldnum)) + def setarrayitem(self, arraydescr, array, index, fieldnum): + assert lltype.typeOf(array) is lltype.Signed + assert lltype.typeOf(index) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got_array.append((arraydescr, array, index, fieldnum)) + def decode_ref(self, num): + return rffi.cast(lltype.Signed, num) * 100 + got = [] + pf = lltype.nullptr(PENDINGFIELDSP.TO) + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [] + # + class FieldDescr(AbstractDescr): + pass + field_a = FieldDescr() + field_b = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 2) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) + pf[0].itemindex = rffi.cast(rffi.INT, -1) + pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) + pf[1].num = rffi.cast(rffi.SHORT, 2042) + pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) + pf[1].itemindex = rffi.cast(rffi.INT, -1) + got = [] + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] + # + array_a = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 1) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) + pf[0].itemindex = rffi.cast(rffi.INT, 123) + got_array = [] + ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + assert got_array == [(array_a, 104200, 123, 1063)] + def test_invalidation_needed(): class options: diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -11,7 +11,7 @@ from pypy.rpython.rclass import FieldListAccessor from pypy.jit.metainterp.warmspot import get_stats, get_translator from pypy.jit.metainterp import history -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin def promote_virtualizable(*args): pass diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py --- a/pypy/jit/metainterp/virtualref.py +++ b/pypy/jit/metainterp/virtualref.py @@ -1,5 +1,5 @@ from pypy.rpython.rmodel import inputconst, log -from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass +from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.jit.metainterp import history from pypy.jit.codewriter import heaptracker from pypy.rlib.jit import InvalidVirtualRef diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -1,6 +1,5 @@ import sys, py -from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr -from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.annlowlevel import llhelper, MixLevelHelperAnnotator,\ cast_base_ptr_to_instance, hlstr from pypy.annotation import model as annmodel @@ -10,16 +9,12 @@ from pypy.objspace.flow.model import checkgraph, Link, copygraph from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import r_uint, intmask -from pypy.rlib.debug import debug_print, fatalerror -from pypy.rlib.debug import debug_start, debug_stop -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.translator.simplify import get_funcobj, get_functype +from pypy.rlib.debug import fatalerror +from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function from pypy.jit.metainterp import history, pyjitpl, gc, memmgr -from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp -from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper +from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.jitdriver import JitDriverStaticData @@ -66,6 +61,7 @@ def jittify_and_run(interp, graph, args, repeat=1, backendopt=False, trace_limit=sys.maxint, inline=False, loop_longevity=0, retrace_limit=5, + function_threshold=4, enable_opts=ALL_OPTS_NAMES, **kwds): from pypy.config.config import ConfigError translator = interp.typer.annotator.translator @@ -77,9 +73,14 @@ translator.config.translation.list_comprehension_operations = True except ConfigError: pass + try: + translator.config.translation.jit_ffi = True + except ConfigError: + pass warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds) for jd in warmrunnerdesc.jitdrivers_sd: jd.warmstate.set_param_threshold(3) # for tests + jd.warmstate.set_param_function_threshold(function_threshold) jd.warmstate.set_param_trace_eagerness(2) # for tests jd.warmstate.set_param_trace_limit(trace_limit) jd.warmstate.set_param_inlining(inline) @@ -291,9 +292,6 @@ self.stats = stats if translate_support_code: self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper) - annhelper = self.annhelper - else: - annhelper = None cpu = CPUClass(self.translator.rtyper, self.stats, self.opt, translate_support_code, gcdescr=self.gcdescr) self.cpu = cpu @@ -422,7 +420,7 @@ if self.translator.rtyper.type_system.name == 'lltypesystem': def maybe_enter_jit(*args): try: - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) except JitException: raise # go through except Exception, e: @@ -430,15 +428,12 @@ maybe_enter_jit._always_inline_ = True else: def maybe_enter_jit(*args): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) maybe_enter_jit._always_inline_ = True jd._maybe_enter_jit_fn = maybe_enter_jit - can_inline = state.can_inline_greenargs - num_green_args = jd.num_green_args def maybe_enter_from_start(*args): - if not can_inline(*args[:num_green_args]): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_function_threshold, *args) maybe_enter_from_start._always_inline_ = True jd._maybe_enter_from_start_fn = maybe_enter_from_start @@ -549,7 +544,6 @@ self.rewrite_can_enter_jit(jd, sublist) def rewrite_can_enter_jit(self, jd, can_enter_jits): - FUNC = jd._JIT_ENTER_FUNCTYPE FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -1,7 +1,7 @@ import sys, weakref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi from pypy.rpython.ootypesystem import ootype -from pypy.rpython.annlowlevel import hlstr, llstr, cast_base_ptr_to_instance +from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance from pypy.rpython.annlowlevel import cast_object_to_ptr from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict from pypy.rlib.rarithmetic import intmask @@ -208,15 +208,20 @@ meth = getattr(self, 'set_param_' + name) meth(default_value) - def set_param_threshold(self, threshold): + def _compute_threshold(self, threshold): if threshold <= 0: - self.increment_threshold = 0 # never reach the THRESHOLD_LIMIT - return + return 0 # never reach the THRESHOLD_LIMIT if threshold < 2: threshold = 2 - self.increment_threshold = (self.THRESHOLD_LIMIT // threshold) + 1 + return (self.THRESHOLD_LIMIT // threshold) + 1 # the number is at least 1, and at most about half THRESHOLD_LIMIT + def set_param_threshold(self, threshold): + self.increment_threshold = self._compute_threshold(threshold) + + def set_param_function_threshold(self, threshold): + self.increment_function_threshold = self._compute_threshold(threshold) + def set_param_trace_eagerness(self, value): self.trace_eagerness = value @@ -291,7 +296,7 @@ self.make_jitdriver_callbacks() confirm_enter_jit = self.confirm_enter_jit - def maybe_compile_and_run(*args): + def maybe_compile_and_run(threshold, *args): """Entry point to the JIT. Called at the point with the can_enter_jit() hint. """ @@ -307,7 +312,7 @@ if cell.counter >= 0: # update the profiling counter - n = cell.counter + self.increment_threshold + n = cell.counter + threshold if n <= self.THRESHOLD_LIMIT: # bound not reached cell.counter = n return @@ -497,7 +502,6 @@ if hasattr(self, 'set_future_values'): return self.set_future_values - warmrunnerdesc = self.warmrunnerdesc jitdriver_sd = self.jitdriver_sd cpu = self.cpu vinfo = jitdriver_sd.virtualizable_info @@ -513,7 +517,6 @@ # if vinfo is not None: i0 = len(jitdriver_sd._red_args_types) - num_green_args = jitdriver_sd.num_green_args index_of_virtualizable = jitdriver_sd.index_of_virtualizable vable_static_fields = unrolling_iterable( zip(vinfo.static_extra_types, vinfo.static_fields)) diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -3,24 +3,15 @@ in a nicer fashion """ -from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat,\ - LoopToken, get_const_ptr_for_string, get_const_ptr_for_unicode +from pypy.jit.tool.oparser_model import get_model + from pypy.jit.metainterp.resoperation import rop, ResOperation, \ ResOpWithDescr, N_aryOp, \ UnaryOp, PlainResOp -from pypy.jit.metainterp.typesystem import llhelper -from pypy.jit.codewriter.heaptracker import adr2int -from pypy.jit.codewriter import longlong -from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.rpython.ootypesystem import ootype class ParseError(Exception): pass -class Boxes(object): - pass - class ESCAPE_OP(N_aryOp, ResOpWithDescr): OPNUM = -123 @@ -54,37 +45,15 @@ def clone(self): return FORCE_SPILL(self.OPNUM, self.getarglist()[:]) -class ExtendedTreeLoop(TreeLoop): - def getboxes(self): - def opboxes(operations): - for op in operations: - yield op.result - for box in op.getarglist(): - yield box - def allboxes(): - for box in self.inputargs: - yield box - for box in opboxes(self.operations): - yield box - - boxes = Boxes() - for box in allboxes(): - if isinstance(box, Box): - name = str(box) - setattr(boxes, name, box) - return boxes - - def setvalues(self, **kwds): - boxes = self.getboxes() - for name, value in kwds.iteritems(): - getattr(boxes, name).value = value - -def default_fail_descr(fail_args=None): - return BasicFailDescr() +def default_fail_descr(model, fail_args=None): + return model.BasicFailDescr() class OpParser(object): + + use_mock_model = False + def __init__(self, input, cpu, namespace, type_system, boxkinds, invent_fail_descr=default_fail_descr, nonstrict=False): @@ -100,7 +69,8 @@ self._cache = {} self.invent_fail_descr = invent_fail_descr self.nonstrict = nonstrict - self.looptoken = LoopToken() + self.model = get_model(self.use_mock_model) + self.looptoken = self.model.LoopToken() def get_const(self, name, typ): if self._consts is None: @@ -108,16 +78,16 @@ obj = self._consts[name] if self.type_system == 'lltype': if typ == 'ptr': - return ConstPtr(obj) + return self.model.ConstPtr(obj) else: assert typ == 'class' - return ConstInt(adr2int(llmemory.cast_ptr_to_adr(obj))) + return self.model.ConstInt(self.model.ptr_to_int(obj)) else: if typ == 'ptr': - return ConstObj(obj) + return self.model.ConstObj(obj) else: assert typ == 'class' - return ConstObj(ootype.cast_to_object(obj)) + return self.model.ConstObj(ootype.cast_to_object(obj)) def get_descr(self, poss_descr): if poss_descr.startswith('<'): @@ -132,16 +102,16 @@ pass if elem.startswith('i'): # integer - box = BoxInt() - _box_counter_more_than(elem[1:]) + box = self.model.BoxInt() + _box_counter_more_than(self.model, elem[1:]) elif elem.startswith('f'): - box = BoxFloat() - _box_counter_more_than(elem[1:]) + box = self.model.BoxFloat() + _box_counter_more_than(self.model, elem[1:]) elif elem.startswith('p'): # pointer - ts = getattr(self.cpu, 'ts', llhelper) + ts = getattr(self.cpu, 'ts', self.model.llhelper) box = ts.BoxRef() - _box_counter_more_than(elem[1:]) + _box_counter_more_than(self.model, elem[1:]) else: for prefix, boxclass in self.boxkinds.iteritems(): if elem.startswith(prefix): @@ -175,21 +145,21 @@ def getvar(self, arg): if not arg: - return ConstInt(0) + return self.model.ConstInt(0) try: - return ConstInt(int(arg)) + return self.model.ConstInt(int(arg)) except ValueError: if self.is_float(arg): - return ConstFloat(longlong.getfloatstorage(float(arg))) + return self.model.ConstFloat(self.model.convert_to_floatstorage(arg)) if (arg.startswith('"') or arg.startswith("'") or arg.startswith('s"')): # XXX ootype info = arg[1:].strip("'\"") - return get_const_ptr_for_string(info) + return self.model.get_const_ptr_for_string(info) if arg.startswith('u"'): # XXX ootype info = arg[1:].strip("'\"") - return get_const_ptr_for_unicode(info) + return self.model.get_const_ptr_for_unicode(info) if arg.startswith('ConstClass('): name = arg[len('ConstClass('):-1] return self.get_const(name, 'class') @@ -197,9 +167,9 @@ return None elif arg == 'NULL': if self.type_system == 'lltype': - return ConstPtr(ConstPtr.value) + return self.model.ConstPtr(self.model.ConstPtr.value) else: - return ConstObj(ConstObj.value) + return self.model.ConstObj(self.model.ConstObj.value) elif arg.startswith('ConstPtr('): name = arg[len('ConstPtr('):-1] return self.get_const(name, 'ptr') @@ -211,11 +181,8 @@ args = [] descr = None if argspec.strip(): - if opname == 'debug_merge_point': - allargs = argspec.split(',', 2) - else: - allargs = [arg for arg in argspec.split(",") - if arg != ''] + allargs = [arg for arg in argspec.split(",") + if arg != ''] poss_descr = allargs[-1].strip() if poss_descr.startswith('descr='): @@ -266,14 +233,14 @@ "Unknown var in fail_args: %s" % arg) fail_args.append(fail_arg) if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr(fail_args) + descr = self.invent_fail_descr(self.model, fail_args) if hasattr(descr, '_oparser_uses_descr_of_guard'): descr._oparser_uses_descr_of_guard(self, fail_args) else: fail_args = None if opnum == rop.FINISH: if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr() + descr = self.invent_fail_descr(self.model) elif opnum == rop.JUMP: if descr is None and self.invent_fail_descr: descr = self.looptoken @@ -338,7 +305,7 @@ num, ops, last_offset = self.parse_ops(base_indent, newlines, 0) if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) - loop = ExtendedTreeLoop("loop") + loop = self.model.ExtendedTreeLoop("loop") loop.comment = first_comment loop.token = self.looptoken loop.operations = ops @@ -394,7 +361,7 @@ def parse(input, cpu=None, namespace=None, type_system='lltype', boxkinds=None, invent_fail_descr=default_fail_descr, - no_namespace=False, nonstrict=False): + no_namespace=False, nonstrict=False, OpParser=OpParser): if namespace is None and not no_namespace: namespace = {} return OpParser(input, cpu, namespace, type_system, boxkinds, @@ -405,6 +372,6 @@ return parse(*args, **kwds) -def _box_counter_more_than(s): +def _box_counter_more_than(model, s): if s.isdigit(): - Box._counter = max(Box._counter, int(s)+1) + model.Box._counter = max(model.Box._counter, int(s)+1) diff --git a/pypy/jit/tool/oparser_model.py b/pypy/jit/tool/oparser_model.py new file mode 100644 --- /dev/null +++ b/pypy/jit/tool/oparser_model.py @@ -0,0 +1,148 @@ +class Boxes(object): + pass + +def get_real_model(): + class LoopModel(object): + from pypy.jit.metainterp.history import TreeLoop, LoopToken + from pypy.jit.metainterp.history import Box, BoxInt, BoxFloat + from pypy.jit.metainterp.history import ConstInt, ConstObj, ConstPtr, ConstFloat + from pypy.jit.metainterp.history import BasicFailDescr + from pypy.jit.metainterp.typesystem import llhelper + + from pypy.jit.metainterp.history import get_const_ptr_for_string + from pypy.jit.metainterp.history import get_const_ptr_for_unicode + get_const_ptr_for_string = staticmethod(get_const_ptr_for_string) + get_const_ptr_for_unicode = staticmethod(get_const_ptr_for_unicode) + + @staticmethod + def convert_to_floatstorage(arg): + from pypy.jit.codewriter import longlong + return longlong.getfloatstorage(float(arg)) + + @staticmethod + def ptr_to_int(obj): + from pypy.jit.codewriter.heaptracker import adr2int + from pypy.rpython.lltypesystem import llmemory + return adr2int(llmemory.cast_ptr_to_adr(obj)) + + @staticmethod + def ootype_cast_to_object(obj): + from pypy.rpython.ootypesystem import ootype + return ootype.cast_to_object(obj) + + return LoopModel + +def get_mock_model(): + class LoopModel(object): + + class TreeLoop(object): + def __init__(self, name): + self.name = name + + class LoopToken(object): + I_am_a_descr = True + + class BasicFailDescr(object): + I_am_a_descr = True + + class Box(object): + _counter = 0 + type = 'b' + + def __init__(self, value=0): + self.value = value + + def __repr__(self): + result = str(self) + result += '(%s)' % self.value + return result + + def __str__(self): + if not hasattr(self, '_str'): + self._str = '%s%d' % (self.type, Box._counter) + Box._counter += 1 + return self._str + + class BoxInt(Box): + type = 'i' + + class BoxFloat(Box): + type = 'f' + + class BoxRef(Box): + type = 'p' + + class Const(object): + def __init__(self, value=None): + self.value = value + + def _get_str(self): + return str(self.value) + + class ConstInt(Const): + pass + + class ConstPtr(Const): + pass + + class ConstFloat(Const): + pass + + @classmethod + def get_const_ptr_for_string(cls, s): + return cls.ConstPtr(s) + + @classmethod + def get_const_ptr_for_unicode(cls, s): + return cls.ConstPtr(s) + + @staticmethod + def convert_to_floatstorage(arg): + return float(arg) + + @staticmethod + def ptr_to_int(obj): + return id(obj) + + class llhelper(object): + pass + + LoopModel.llhelper.BoxRef = LoopModel.BoxRef + + return LoopModel + + +def get_model(use_mock): + if use_mock: + model = get_mock_model() + else: + model = get_real_model() + + class ExtendedTreeLoop(model.TreeLoop): + + def getboxes(self): + def opboxes(operations): + for op in operations: + yield op.result + for box in op.getarglist(): + yield box + def allboxes(): + for box in self.inputargs: + yield box + for box in opboxes(self.operations): + yield box + + boxes = Boxes() + for box in allboxes(): + if isinstance(box, model.Box): + name = str(box) + setattr(boxes, name, box) + return boxes + + def setvalues(self, **kwds): + boxes = self.getboxes() + for name, value in kwds.iteritems(): + getattr(boxes, name).value = value + + model.ExtendedTreeLoop = ExtendedTreeLoop + return model diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -32,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/jit/tool/test/test_oparser.py b/pypy/jit/tool/test/test_oparser.py --- a/pypy/jit/tool/test/test_oparser.py +++ b/pypy/jit/tool/test/test_oparser.py @@ -1,227 +1,274 @@ import py +import sys from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.jit.tool.oparser import parse, ParseError +from pypy.jit.tool.oparser import parse, OpParser from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken,\ - BoxFloat +from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken -def test_basic_parse(): - x = """ - [i0, i1] - # a comment - i2 = int_add(i0, i1) - i3 = int_sub(i2, 3) # another comment - finish() # (tricky) - """ - loop = parse(x) - assert len(loop.operations) == 3 - assert [op.getopnum() for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, - rop.FINISH] - assert len(loop.inputargs) == 2 - assert loop.operations[-1].getdescr() +class BaseTestOparser(object): -def test_const_ptr_subops(): - x = """ - [p0] - guard_class(p0, ConstClass(vtable)) [] - """ - S = lltype.Struct('S') - vtable = lltype.nullptr(S) - loop = parse(x, None, locals()) - assert len(loop.operations) == 1 - assert loop.operations[0].getdescr() - assert loop.operations[0].getfailargs() == [] + OpParser = None -def test_descr(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - i1 = getfield_gc(p0, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff + def parse(self, *args, **kwds): + kwds['OpParser'] = self.OpParser + return parse(*args, **kwds) -def test_after_fail(): - x = """ - [i0] - guard_value(i0, 3) [] - i1 = int_add(1, 2) - """ - loop = parse(x, None, {}) - assert len(loop.operations) == 2 + def test_basic_parse(self): + x = """ + [i0, i1] + # a comment + i2 = int_add(i0, i1) + i3 = int_sub(i2, 3) # another comment + finish() # (tricky) + """ + loop = self.parse(x) + assert len(loop.operations) == 3 + assert [op.getopnum() for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, + rop.FINISH] + assert len(loop.inputargs) == 2 + assert loop.operations[-1].getdescr() -def test_descr_setfield(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - setfield_gc(p0, 3, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff + def test_const_ptr_subops(self): + x = """ + [p0] + guard_class(p0, ConstClass(vtable)) [] + """ + S = lltype.Struct('S') + vtable = lltype.nullptr(S) + loop = self.parse(x, None, locals()) + assert len(loop.operations) == 1 + assert loop.operations[0].getdescr() + assert loop.operations[0].getfailargs() == [] -def test_boxname(): - x = """ - [i42] - i50 = int_add(i42, 1) - """ - loop = parse(x, None, {}) - assert str(loop.inputargs[0]) == 'i42' - assert str(loop.operations[0].result) == 'i50' + def test_descr(self): + class Xyz(AbstractDescr): + I_am_a_descr = True # for the mock case -def test_getboxes(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - boxes = loop.getboxes() - assert boxes.i0 is loop.inputargs[0] - assert boxes.i1 is loop.operations[0].result - -def test_setvalues(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - loop.setvalues(i0=32, i1=42) - assert loop.inputargs[0].value == 32 - assert loop.operations[0].result.value == 42 + x = """ + [p0] + i1 = getfield_gc(p0, descr=stuff) + """ + stuff = Xyz() + loop = self.parse(x, None, locals()) + assert loop.operations[0].getdescr() is stuff -def test_boxkind(): - x = """ - [sum0] - """ - loop = parse(x, None, {}, boxkinds={'sum': BoxInt}) - b = loop.getboxes() - assert isinstance(b.sum0, BoxInt) - -def test_getvar_const_ptr(): - x = ''' - [] - call(ConstPtr(func_ptr)) + def test_after_fail(self): + x = """ + [i0] + guard_value(i0, 3) [] + i1 = int_add(1, 2) + """ + loop = self.parse(x, None, {}) + assert len(loop.operations) == 2 + + def test_descr_setfield(self): + class Xyz(AbstractDescr): + I_am_a_descr = True # for the mock case + + x = """ + [p0] + setfield_gc(p0, 3, descr=stuff) + """ + stuff = Xyz() + loop = self.parse(x, None, locals()) + assert loop.operations[0].getdescr() is stuff + + def test_boxname(self): + x = """ + [i42] + i50 = int_add(i42, 1) + """ + loop = self.parse(x, None, {}) + assert str(loop.inputargs[0]) == 'i42' + assert str(loop.operations[0].result) == 'i50' + + def test_getboxes(self): + x = """ + [i0] + i1 = int_add(i0, 10) + """ + loop = self.parse(x, None, {}) + boxes = loop.getboxes() + assert boxes.i0 is loop.inputargs[0] + assert boxes.i1 is loop.operations[0].result + + def test_setvalues(self): + x = """ + [i0] + i1 = int_add(i0, 10) + """ + loop = self.parse(x, None, {}) + loop.setvalues(i0=32, i1=42) + assert loop.inputargs[0].value == 32 + assert loop.operations[0].result.value == 42 + + def test_getvar_const_ptr(self): + x = ''' + [] + call(ConstPtr(func_ptr)) + ''' + TP = lltype.GcArray(lltype.Signed) + NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) + loop = self.parse(x, None, {'func_ptr' : NULL}) + assert loop.operations[0].getarg(0).value == NULL + + def test_jump_target(self): + x = ''' + [] + jump() + ''' + loop = self.parse(x) + assert loop.operations[0].getdescr() is loop.token + + def test_jump_target_other(self): + looptoken = LoopToken() + looptoken.I_am_a_descr = True # for the mock case + x = ''' + [] + jump(descr=looptoken) + ''' + loop = self.parse(x, namespace=locals()) + assert loop.operations[0].getdescr() is looptoken + + def test_floats(self): + x = ''' + [f0] + f1 = float_add(f0, 3.5) + ''' + loop = self.parse(x) + box = loop.operations[0].getarg(0) + # we cannot use isinstance, because in case of mock the class will be + # constructed on the fly + assert box.__class__.__name__ == 'BoxFloat' + + def test_debug_merge_point(self): + x = ''' + [] + debug_merge_point(0, "info") + debug_merge_point(0, 'info') + debug_merge_point(1, ' info') + debug_merge_point(0, '(stuff) #1') + ''' + loop = self.parse(x) + assert loop.operations[0].getarg(1)._get_str() == 'info' + assert loop.operations[1].getarg(1)._get_str() == 'info' + assert loop.operations[2].getarg(1)._get_str() == " info" + assert loop.operations[3].getarg(1)._get_str() == "(stuff) #1" + + + def test_descr_with_obj_print(self): + x = ''' + [p0] + setfield_gc(p0, 1, descr=) + ''' + loop = self.parse(x) + # assert did not explode + + example_loop_log = '''\ + # bridge out of Guard12, 6 ops + [i0, i1, i2] + i4 = int_add(i0, 2) + i6 = int_sub(i1, 1) + i8 = int_gt(i6, 3) + guard_true(i8, descr=) [i4, i6] + debug_merge_point('(no jitdriver.get_printable_location!)', 0) + jump(i6, i4, descr=) ''' - TP = lltype.GcArray(lltype.Signed) - NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) - loop = parse(x, None, {'func_ptr' : NULL}) - assert loop.operations[0].getarg(0).value == NULL -def test_jump_target(): - x = ''' - [] - jump() - ''' - loop = parse(x) - assert loop.operations[0].getdescr() is loop.token + def test_parse_no_namespace(self): + loop = self.parse(self.example_loop_log, no_namespace=True) -def test_jump_target_other(): - looptoken = LoopToken() - x = ''' - [] - jump(descr=looptoken) - ''' - loop = parse(x, namespace=locals()) - assert loop.operations[0].getdescr() is looptoken + def test_attach_comment_to_loop(self): + loop = self.parse(self.example_loop_log, no_namespace=True) + assert loop.comment == ' # bridge out of Guard12, 6 ops' -def test_floats(): - x = ''' - [f0] - f1 = float_add(f0, 3.5) - ''' - loop = parse(x) - assert isinstance(loop.operations[0].getarg(0), BoxFloat) - -def test_debug_merge_point(): - x = ''' - [] - debug_merge_point(0, "info") - debug_merge_point(0, 'info') - debug_merge_point(1, ' info') - debug_merge_point(0, '(stuff) #1') - ''' - loop = parse(x) - assert loop.operations[0].getarg(1)._get_str() == 'info' - assert loop.operations[1].getarg(1)._get_str() == 'info' - assert loop.operations[2].getarg(1)._get_str() == " info" - assert loop.operations[3].getarg(1)._get_str() == "(stuff) #1" - + def test_parse_new_with_comma(self): + # this is generated by PYPYJITLOG, check that we can handle it + x = ''' + [] + p0 = new(, descr=) + ''' + loop = self.parse(x) + assert loop.operations[0].getopname() == 'new' -def test_descr_with_obj_print(): - x = ''' - [p0] - setfield_gc(p0, 1, descr=) - ''' - loop = parse(x) - # assert did not explode + def test_no_fail_args(self): + x = ''' + [i0] + guard_true(i0, descr=) + ''' + loop = self.parse(x, nonstrict=True) + assert loop.operations[0].getfailargs() == [] -example_loop_log = '''\ -# bridge out of Guard12, 6 ops -[i0, i1, i2] -i4 = int_add(i0, 2) -i6 = int_sub(i1, 1) -i8 = int_gt(i6, 3) -guard_true(i8, descr=) [i4, i6] -debug_merge_point('(no jitdriver.get_printable_location!)', 0) -jump(i6, i4, descr=) -''' + def test_no_inputargs(self): + x = ''' + i2 = int_add(i0, i1) + ''' + loop = self.parse(x, nonstrict=True) + assert loop.inputargs == [] + assert loop.operations[0].getopname() == 'int_add' -def test_parse_no_namespace(): - loop = parse(example_loop_log, no_namespace=True) + def test_offsets(self): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + """ + # +30: --end of the loop-- + loop = self.parse(x) + assert loop.operations[0].offset == 10 + assert not hasattr(loop.operations[1], 'offset') -def test_attach_comment_to_loop(): - loop = parse(example_loop_log, no_namespace=True) - assert loop.comment == '# bridge out of Guard12, 6 ops' + def test_last_offset(self): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + +30: --end of the loop-- + """ + loop = self.parse(x) + assert len(loop.operations) == 2 + assert loop.last_offset == 30 -def test_parse_new_with_comma(): - # this is generated by PYPYJITLOG, check that we can handle it - x = ''' - [] - p0 = new(, descr=) - ''' - loop = parse(x) - assert loop.operations[0].getopname() == 'new' -def test_no_fail_args(): - x = ''' - [i0] - guard_true(i0, descr=) - ''' - loop = parse(x, nonstrict=True) - assert loop.operations[0].getfailargs() == [] +class TestOpParser(BaseTestOparser): -def test_no_inputargs(): - x = ''' - i2 = int_add(i0, i1) - ''' - loop = parse(x, nonstrict=True) - assert loop.inputargs == [] - assert loop.operations[0].getopname() == 'int_add' + OpParser = OpParser -def test_offsets(): - x = """ - [i0, i1] - +10: i2 = int_add(i0, i1) - i3 = int_add(i2, 3) - """ - # +30: --end of the loop-- - loop = parse(x) - assert loop.operations[0].offset == 10 - assert not hasattr(loop.operations[1], 'offset') + def test_boxkind(self): + x = """ + [sum0] + """ + loop = self.parse(x, None, {}, boxkinds={'sum': BoxInt}) + b = loop.getboxes() + assert isinstance(b.sum0, BoxInt) -def test_last_offset(): - x = """ - [i0, i1] - +10: i2 = int_add(i0, i1) - i3 = int_add(i2, 3) - +30: --end of the loop-- - """ - loop = parse(x) - assert len(loop.operations) == 2 - assert loop.last_offset == 30 + +class ForbiddenModule(object): + def __init__(self, name, old_mod): + self.name = name + self.old_mod = old_mod + + def __getattr__(self, attr): + assert False, "You should not import module %s" % self.name + + +class TestOpParserWithMock(BaseTestOparser): + + class OpParser(OpParser): + use_mock_model = True + + def setup_class(cls): + forbidden_mods = [ + 'pypy.jit.metainterp.history', + 'pypy.rpython.lltypesystem.lltype', + ] + for modname in forbidden_mods: + if modname in sys.modules: + newmod = ForbiddenModule(modname, sys.modules[modname]) + sys.modules[modname] = newmod + + def teardown_class(cls): + for modname, mod in sys.modules.iteritems(): + if isinstance(mod, ForbiddenModule): + sys.modules[modname] = mod.old_mod diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -294,7 +294,7 @@ break new_frame = space.createframe(code, w_func.w_func_globals, w_func.closure) - new_frame.fastlocals_w[0] = w_item + new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) return result_w diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -1,5 +1,6 @@ import autopath import sys +from pypy import conftest class AppTestBuiltinApp: def setup_class(cls): @@ -15,6 +16,15 @@ cls.w_sane_lookup = cls.space.wrap(True) except KeyError: cls.w_sane_lookup = cls.space.wrap(False) + # starting with CPython 2.6, when the stack is almost out, we + # can get a random error, instead of just a RuntimeError. + # For example if an object x has a __getattr__, we can get + # AttributeError if attempting to call x.__getattr__ runs out + # of stack. That's annoying, so we just work around it. + if conftest.option.runappdirect: + cls.w_safe_runtimerror = cls.space.wrap(True) + else: + cls.w_safe_runtimerror = cls.space.wrap(sys.version_info < (2, 6)) def test_bytes_alias(self): assert bytes is str @@ -399,6 +409,8 @@ def test_cmp_cyclic(self): if not self.sane_lookup: skip("underlying Python implementation has insane dict lookup") + if not self.safe_runtimerror: + skip("underlying Python may raise random exceptions on stack ovf") a = []; a.append(a) b = []; b.append(b) from UserList import UserList diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -3,6 +3,14 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.imp.importing import get_pyc_magic + +class BuildersModule(MixedModule): + appleveldefs = {} + + interpleveldefs = { + "UnicodeBuilder": "interp_builders.W_UnicodeBuilder", + } + class Module(MixedModule): appleveldefs = { } @@ -19,6 +27,10 @@ 'lookup_special' : 'interp_magic.lookup_special', } + submodules = { + "builders": BuildersModule, + } + def setup_after_space_initialization(self): """NOT_RPYTHON""" if not self.space.config.translating: diff --git a/pypy/module/__pypy__/interp_builders.py b/pypy/module/__pypy__/interp_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_builders.py @@ -0,0 +1,50 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef +from pypy.rlib.rstring import UnicodeBuilder + + +class W_UnicodeBuilder(Wrappable): + def __init__(self, space, size): + if size == -1: + self.builder = UnicodeBuilder() + else: + self.builder = UnicodeBuilder(size) + self.done = False + + def _check_done(self, space): + if self.done: + raise OperationError(space.w_ValueError, space.wrap("Can't operate on a done builder")) + + @unwrap_spec(size=int) + def descr__new__(space, w_subtype, size=-1): + return W_UnicodeBuilder(space, size) + + @unwrap_spec(s=unicode) + def descr_append(self, space, s): + self._check_done(space) + self.builder.append(s) + + @unwrap_spec(s=unicode, start=int, end=int) + def descr_append_slice(self, space, s, start, end): + self._check_done(space) + if not 0 <= start <= end <= len(s): + raise OperationError(space.w_ValueError, space.wrap("bad start/stop")) + self.builder.append_slice(s, start, end) + + def descr_build(self, space): + self._check_done(space) + w_s = space.wrap(self.builder.build()) + self.done = True + return w_s + + +W_UnicodeBuilder.typedef = TypeDef("UnicodeBuilder", + __new__ = interp2app(W_UnicodeBuilder.descr__new__.im_func), + + append = interp2app(W_UnicodeBuilder.descr_append), + append_slice = interp2app(W_UnicodeBuilder.descr_append_slice), + build = interp2app(W_UnicodeBuilder.descr_build), +) +W_UnicodeBuilder.typedef.acceptable_as_base_class = False \ No newline at end of file diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,15 +1,19 @@ from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.error import OperationError -from pypy.rlib import debug +from pypy.rlib import debug, jit + + at jit.dont_look_inside @unwrap_spec(category=str) def debug_start(space, category): debug.debug_start(category) + at jit.dont_look_inside def debug_print(space, args_w): parts = [space.str_w(space.str(w_item)) for w_item in args_w] debug.debug_print(' '.join(parts)) + at jit.dont_look_inside @unwrap_spec(category=str) def debug_stop(space, category): debug.debug_stop(category) diff --git a/pypy/module/__pypy__/test/test_builders.py b/pypy/module/__pypy__/test/test_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_builders.py @@ -0,0 +1,34 @@ +from pypy.conftest import gettestobjspace + + +class AppTestBuilders(object): + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['__pypy__']) + + def test_simple(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append(u"abc") + b.append(u"123") + b.append(u"1") + s = b.build() + assert s == u"abc1231" + raises(ValueError, b.build) + raises(ValueError, b.append, u"123") + + def test_preallocate(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder(10) + b.append(u"abc") + b.append(u"123") + s = b.build() + assert s == u"abc123" + + def test_append_slice(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append_slice(u"abcdefgh", 2, 5) + raises(ValueError, b.append_slice, u"1", 2, 1) + s = b.build() + assert s == "cde" + raises(ValueError, b.append_slice, u"abc", 1, 2) \ No newline at end of file diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -176,7 +176,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + elif (_MS_WINDOWS and space.is_true(space.isinstance(w_name, space.w_int))): ordinal = space.int_w(w_name) @@ -261,7 +261,7 @@ def descr_size_alignment(self, space, n=1): return space.newtuple([space.wrap(self.size * n), space.wrap(self.alignment)]) - + class W_DataInstance(Wrappable): def __init__(self, space, size, address=r_uint(0)): @@ -427,7 +427,7 @@ if not (argletter in TYPEMAP_PTR_LETTERS and letter in TYPEMAP_PTR_LETTERS): msg = "Argument %d should be typecode %s, got %s" - raise operationerrfmt(space.w_TypeError, msg, + raise operationerrfmt(space.w_TypeError, msg, i+1, argletter, letter) args_ll.append(arg.ll_buffer) # XXX we could avoid the intermediate list args_ll @@ -480,17 +480,25 @@ alignment = _create_new_accessor('alignment', 'c_alignment') @unwrap_spec(address=r_uint, maxlength=int) -def charp2string(space, address, maxlength=sys.maxint): +def charp2string(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.charp2strn(rffi.cast(rffi.CCHARP, address), maxlength) + charp_addr = rffi.cast(rffi.CCHARP, address) + if maxlength == -1: + s = rffi.charp2str(charp_addr) + else: + s = rffi.charp2strn(charp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) -def wcharp2unicode(space, address, maxlength=sys.maxint): +def wcharp2unicode(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.wcharp2unicoden(rffi.cast(rffi.CWCHARP, address), maxlength) + wcharp_addr = rffi.cast(rffi.CWCHARP, address) + if maxlength == -1: + s = rffi.wcharp2unicode(wcharp_addr) + else: + s = rffi.wcharp2unicoden(wcharp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,3 +1,4 @@ +from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable @@ -899,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/_stackless/test/test_greenlet.py b/pypy/module/_stackless/test/test_greenlet.py --- a/pypy/module/_stackless/test/test_greenlet.py +++ b/pypy/module/_stackless/test/test_greenlet.py @@ -72,6 +72,23 @@ g1 = greenlet(f) raises(ValueError, g2.switch) + + def test_exc_info_save_restore(self): + from _stackless import greenlet + import sys + def f(): + try: + raise ValueError('fun') + except: + exc_info = sys.exc_info() + greenlet(h).switch() + assert exc_info == sys.exc_info() + + def h(): + assert sys.exc_info() == (None, None, None) + + greenlet(f).switch() + def test_exception(self): from _stackless import greenlet import sys diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -526,15 +526,7 @@ def array_tostring__Array(space, self): cbuf = self.charbuf() - s = ''.join([cbuf[i] for i in xrange(self.len * mytype.bytes)]) - return self.space.wrap(s) -## -## s = '' -## i = 0 -## while i < self.len * mytype.bytes: -## s += cbuf[i] -## i += 1 -## return self.space.wrap(s) + return self.space.wrap(rffi.charpsize2str(cbuf, self.len * mytype.bytes)) def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): if not isinstance(w_f, W_File): diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -39,6 +39,7 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject +import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject import pypy.module.cpyext.longobject @@ -64,6 +65,7 @@ import pypy.module.cpyext.memoryobject import pypy.module.cpyext.codecs import pypy.module.cpyext.pyfile +import pypy.module.cpyext.pystrtod # now that all rffi_platform.Struct types are registered, configure them api.configure_types() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -562,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/pystrtod.py @@ -0,0 +1,68 @@ +import errno +from pypy.interpreter.error import OperationError +from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.pyobject import PyObject +from pypy.rlib import rdtoa +from pypy.rlib import rfloat +from pypy.rlib import rposix +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi + + + at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +def PyOS_string_to_double(space, s, endptr, w_overflow_exception): + """Convert a string s to a double, raising a Python + exception on failure. The set of accepted strings corresponds to + the set of strings accepted by Python's float() constructor, + except that s must not have leading or trailing whitespace. + The conversion is independent of the current locale. + + If endptr is NULL, convert the whole string. Raise + ValueError and return -1.0 if the string is not a valid + representation of a floating-point number. + + If endptr is not NULL, convert as much of the string as + possible and set *endptr to point to the first unconverted + character. If no initial segment of the string is the valid + representation of a floating-point number, set *endptr to point + to the beginning of the string, raise ValueError, and return + -1.0. + + If s represents a value that is too large to store in a float + (for example, "1e500" is such a string on many platforms) then + if overflow_exception is NULL return Py_HUGE_VAL (with + an appropriate sign) and don't set any exception. Otherwise, + overflow_exception must point to a Python exception object; + raise that exception and return -1.0. In both cases, set + *endptr to point to the first character after the converted value. + + If any other error occurs during the conversion (for example an + out-of-memory error), set the appropriate Python exception and + return -1.0. + """ + user_endptr = True + try: + if not endptr: + endptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + user_endptr = False + result = rdtoa.dg_strtod(s, endptr) + endpos = (rffi.cast(rffi.LONG, endptr[0]) - + rffi.cast(rffi.LONG, s)) + if endpos == 0 or (not user_endptr and not endptr[0][0] == '\0'): + raise OperationError( + space.w_ValueError, + space.wrap('invalid input at position %s' % endpos)) + if rposix.get_errno() == errno.ERANGE: + rposix.set_errno(0) + if w_overflow_exception is None: + if result > 0: + return rfloat.INFINITY + else: + return -rfloat.INFINITY + else: + raise OperationError(w_overflow_exception, + space.wrap('value too large')) + return result + finally: + if not user_endptr: + lltype.free(endptr, flavor='raw') diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/setobject.py @@ -0,0 +1,46 @@ +from pypy.interpreter.error import OperationError +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, + build_type_checkers) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, + borrow_from, make_ref, from_ref) +from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall +from pypy.objspace.std.setobject import W_SetObject, newset +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject + + +PySet_Check, PySet_CheckExact = build_type_checkers("Set") + + + at cpython_api([PyObject], PyObject) +def PySet_New(space, w_iterable): + if w_iterable is None: + return space.call_function(space.w_set) + else: + return space.call_function(space.w_set, w_iterable) + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Add(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'add', w_obj) + return 0 + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Discard(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'discard', w_obj) + return 0 + + + at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +def PySet_GET_SIZE(space, w_s): + return space.int_w(space.len(w_s)) + + at cpython_api([PyObject], Py_ssize_t, error=-1) +def PySet_Size(space, ref): + if not PySet_Check(space, ref): + raise OperationError(space.w_TypeError, + space.wrap("expected set object")) + return PySet_GET_SIZE(space, ref) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -480,39 +480,6 @@ """Create a new Python complex number object from a C Py_complex value.""" raise NotImplementedError - at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) -def PyOS_string_to_double(space, s, endptr, overflow_exception): - """Convert a string s to a double, raising a Python - exception on failure. The set of accepted strings corresponds to - the set of strings accepted by Python's float() constructor, - except that s must not have leading or trailing whitespace. - The conversion is independent of the current locale. - - If endptr is NULL, convert the whole string. Raise - ValueError and return -1.0 if the string is not a valid - representation of a floating-point number. - - If endptr is not NULL, convert as much of the string as - possible and set *endptr to point to the first unconverted - character. If no initial segment of the string is the valid - representation of a floating-point number, set *endptr to point - to the beginning of the string, raise ValueError, and return - -1.0. - - If s represents a value that is too large to store in a float - (for example, "1e500" is such a string on many platforms) then - if overflow_exception is NULL return Py_HUGE_VAL (with - an appropriate sign) and don't set any exception. Otherwise, - overflow_exception must point to a Python exception object; - raise that exception and return -1.0. In both cases, set - *endptr to point to the first character after the converted value. - - If any other error occurs during the conversion (for example an - out-of-memory error), set the appropriate Python exception and - return -1.0. - """ - raise NotImplementedError - @cpython_api([rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_strtod(space, nptr, endptr): """Convert a string to a double. This function behaves like the Standard C diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -0,0 +1,93 @@ +import math + +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype + + +class TestPyOS_string_to_double(BaseApiTest): + + def test_simple_float(self, api): + s = rffi.str2charp('0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == 0.4 + rffi.free_charp(s) + + def test_empty_string(self, api): + s = rffi.str2charp('') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_bad_string(self, api): + s = rffi.str2charp(' 0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_overflow_pos(self, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r > 0 + rffi.free_charp(s) + + def test_overflow_neg(self, api): + s = rffi.str2charp('-1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r < 0 + rffi.free_charp(s) + + def test_overflow_exc(self, space, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, space.w_ValueError) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_endptr_number(self, api): + s = rffi.str2charp('0.4') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_tail(self, api): + s = rffi.str2charp('0.4 foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_no_conversion(self, api): + s = rffi.str2charp('foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == -1.0 + raises(ValueError) + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + api.PyErr_Clear() + rffi.free_charp(s) + lltype.free(endp, flavor='raw') diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_setobject.py @@ -0,0 +1,29 @@ +import py + +from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace + + +class TestTupleObject(BaseApiTest): + def test_setobj(self, space, api): + assert not api.PySet_Check(space.w_None) + assert api.PySet_Add(space.w_None, space.w_None) == -1 + api.PyErr_Clear() + w_set = space.call_function(space.w_set) + space.call_method(w_set, 'update', space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + assert api.PySet_GET_SIZE(w_set) == 4 + raises(TypeError, api.PySet_Size(space.newlist([]))) + api.PyErr_Clear() + + def test_set_add_discard(self, space, api): + w_set = api.PySet_New(None) + assert api.PySet_Size(w_set) == 0 + w_set = api.PySet_New(space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + api.PySet_Add(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 5 + api.PySet_Discard(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 4 diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -367,3 +367,14 @@ data, len(u), lltype.nullptr(rffi.CCHARP.TO)) rffi.free_wcharp(data) + def test_format(self, space, api): + w_format = space.wrap(u'hi %s') + w_args = space.wrap((u'test',)) + w_formated = api.PyUnicode_Format(w_format, w_args) + assert space.unwrap(w_formated) == space.unwrap(space.mod(w_format, w_args)) + + def test_join(self, space, api): + w_sep = space.wrap(u'') + w_seq = space.wrap([u'a', u'b']) + w_joined = api.PyUnicode_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == u'ab' diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,6 +7,7 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) + assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -523,3 +523,11 @@ copies sizeof(Py_UNICODE) * length bytes from source to target""" for i in range(0, length): target[i] = source[i] + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Format(space, w_format, w_args): + return space.mod(w_format, w_args) + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -21,6 +21,10 @@ """Return the referenced object from a weak reference. If the referent is no longer live, returns None. This function returns a borrowed reference. """ + return PyWeakref_GET_OBJECT(space, w_ref) + + at cpython_api([PyObject], PyObject) +def PyWeakref_GET_OBJECT(space, w_ref): return borrow_from(w_ref, space.call_function(w_ref)) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -622,7 +622,13 @@ try: if find_info: w_mod = load_module(space, w_modulename, find_info) - w_mod = space.getitem(space.sys.get("modules"), w_modulename) + try: + w_mod = space.getitem(space.sys.get("modules"), + w_modulename) + except OperationError, oe: + if not oe.match(space, space.w_KeyError): + raise + raise OperationError(space.w_ImportError, w_modulename) if w_parent is not None: space.setattr(w_parent, space.wrap(partname), w_mod) return w_mod diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py --- a/pypy/module/imp/test/test_import.py +++ b/pypy/module/imp/test/test_import.py @@ -37,6 +37,7 @@ ambig = "imamodule = 1", test_reload = "def test():\n raise ValueError\n", infinite_reload = "import infinite_reload; reload(infinite_reload)", + del_sys_module = "import sys\ndel sys.modules['del_sys_module']\n", ) root.ensure("notapackage", dir=1) # empty, no __init__.py setuppkg("pkg", @@ -562,6 +563,14 @@ except ImportError: pass + def test_del_from_sys_modules(self): + try: + import del_sys_module + except ImportError: + pass # ok + else: + assert False, 'should not work' + class TestAbi: def test_abi_tag(self): space1 = gettestobjspace(soabi='TEST') diff --git a/pypy/module/math/__init__.py b/pypy/module/math/__init__.py --- a/pypy/module/math/__init__.py +++ b/pypy/module/math/__init__.py @@ -4,6 +4,7 @@ class Module(MixedModule): appleveldefs = { + 'factorial' : 'app_math.factorial' } interpleveldefs = { @@ -40,7 +41,6 @@ 'isnan' : 'interp_math.isnan', 'trunc' : 'interp_math.trunc', 'fsum' : 'interp_math.fsum', - 'factorial' : 'interp_math.factorial', 'asinh' : 'interp_math.asinh', 'acosh' : 'interp_math.acosh', 'atanh' : 'interp_math.atanh', diff --git a/pypy/module/math/app_math.py b/pypy/module/math/app_math.py new file mode 100644 --- /dev/null +++ b/pypy/module/math/app_math.py @@ -0,0 +1,13 @@ +def factorial(x): + """Find x!.""" + if isinstance(x, float): + fl = int(x) + if fl != x: + raise ValueError("float arguments must be integral") + x = fl + if x < 0: + raise ValueError("x must be >= 0") + res = 1 + for i in range(1, x + 1): + res *= i + return res diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -373,22 +373,6 @@ hi = v return space.wrap(hi) -def factorial(space, w_x): - """Find x!.""" - if space.isinstance_w(w_x, space.w_float): - fl = space.float_w(w_x) - if math.floor(fl) != fl: - raise OperationError(space.w_ValueError, - space.wrap("float arguments must be integral")) - w_x = space.long(w_x) - x = space.int_w(w_x) - if x < 0: - raise OperationError(space.w_ValueError, space.wrap("x must be >= 0")) - w_res = space.wrap(1) - for i in range(1, x + 1): - w_res = space.mul(w_res, space.wrap(i)) - return w_res - def log1p(space, w_x): """Find log(x + 1).""" return math1(space, rfloat.log1p, w_x) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -8,11 +8,15 @@ interpleveldefs = { 'array': 'interp_numarray.SingleDimArray', 'zeros': 'interp_numarray.zeros', + 'empty': 'interp_numarray.zeros', + 'ones': 'interp_numarray.ones', # ufuncs + 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', 'copysign': 'interp_ufuncs.copysign', 'exp': 'interp_ufuncs.exp', + 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', 'negative': 'interp_ufuncs.negative', @@ -20,4 +24,7 @@ 'sign': 'interp_ufuncs.sign', } - appleveldefs = {} + appleveldefs = { + 'average': 'app_numpy.average', + 'mean': 'app_numpy.mean', + } diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/app_numpy.py @@ -0,0 +1,11 @@ +import numpy + +def average(a): + # This implements a weighted average, for now we don't implement the + # weighting, just the average part! + return mean(a) + +def mean(a): + if not hasattr(a, "mean"): + a = numpy.array(a) + return a.mean() \ No newline at end of file diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/compile.py @@ -0,0 +1,49 @@ + +""" This is a set of tools for standalone compiling of numpy expressions. +It should not be imported by the module itself +""" + +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray + +class BogusBytecode(Exception): + pass + +def create_array(size): + a = SingleDimArray(size) + for i in range(size): + a.storage[i] = float(i % 10) + return a + +class TrivialSpace(object): + def wrap(self, x): + return x + +def numpy_compile(bytecode, array_size): + space = TrivialSpace() + stack = [] + i = 0 + for b in bytecode: + if b == 'a': + stack.append(create_array(array_size)) + i += 1 + elif b == 'f': + stack.append(FloatWrapper(1.2)) + elif b == '+': + right = stack.pop() + stack.append(stack.pop().descr_add(space, right)) + elif b == '-': + right = stack.pop() + stack.append(stack.pop().descr_sub(space, right)) + elif b == '*': + right = stack.pop() + stack.append(stack.pop().descr_mul(space, right)) + elif b == '/': + right = stack.pop() + stack.append(stack.pop().descr_div(space, right)) + else: + print "Unknown opcode: %s" % b + raise BogusBytecode() + if len(stack) != 1: + print "Bogus bytecode, uneven stack length" + raise BogusBytecode() + return stack[0] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,7 +1,7 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable from pypy.interpreter.error import operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name @@ -44,9 +44,13 @@ self.invalidates = [] def invalidated(self): + if self.invalidates: + self._invalidated() + + def _invalidated(self): for arr in self.invalidates: arr.force_if_needed() - self.invalidates = [] + del self.invalidates[:] def _binop_impl(function): signature = Signature() @@ -80,18 +84,36 @@ def get_concrete(self): raise NotImplementedError + def descr_get_shape(self, space): + return space.newtuple([self.descr_len(space)]) + def descr_len(self, space): return self.get_concrete().descr_len(space) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - return self.get_concrete().descr_getitem(space, item) + def descr_getitem(self, space, w_idx): + # TODO: indexing by tuples + start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) + if step == 0: + # Single index + return space.wrap(self.get_concrete().getitem(start)) + else: + # Slice + res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) + return space.wrap(res) @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): self.invalidated() return self.get_concrete().descr_setitem(space, item, value) + def descr_mean(self, space): + s = 0 + concrete = self.get_concrete() + size = concrete.find_size() + for i in xrange(size): + s += concrete.getitem(i) + return space.wrap(s / size) + class FloatWrapper(BaseArray): """ @@ -119,6 +141,10 @@ self.forced_result = None self.signature = signature + def _del_sources(self): + # Function for deleting references to source arrays, to allow garbage-collecting them + raise NotImplementedError + def compute(self): i = 0 signature = self.signature @@ -135,6 +161,7 @@ def force_if_needed(self): if self.forced_result is None: self.forced_result = self.compute() + self._del_sources() def get_concrete(self): self.force_if_needed() @@ -145,6 +172,13 @@ return self.forced_result.eval(i) return self._eval(i) + def find_size(self): + if self.forced_result is not None: + # The result has been computed and sources may be unavailable + return self.forced_result.find_size() + return self._find_size() + + class Call1(VirtualArray): _immutable_fields_ = ["function", "values"] @@ -153,7 +187,10 @@ self.function = function self.values = values - def find_size(self): + def _del_sources(self): + self.values = None + + def _find_size(self): return self.values.find_size() def _eval(self, i): @@ -164,13 +201,18 @@ Intermediate class for performing binary operations. """ _immutable_fields_ = ["function", "left", "right"] + def __init__(self, function, left, right, signature): VirtualArray.__init__(self, signature) self.function = function self.left = left self.right = right - def find_size(self): + def _del_sources(self): + self.left = None + self.right = None + + def _find_size(self): try: return self.left.find_size() except ValueError: @@ -181,6 +223,58 @@ lhs, rhs = self.left.eval(i), self.right.eval(i) return self.function(lhs, rhs) +class ViewArray(BaseArray): + """ + Class for representing views of arrays, they will reflect changes of parent + arrays. Example: slices + """ + _immutable_fields_ = ["parent"] + + def __init__(self, parent, signature): + BaseArray.__init__(self) + self.signature = signature + self.parent = parent + self.invalidates = parent.invalidates + + def get_concrete(self): + # in fact, ViewArray never gets "concrete" as it never stores data. + # This implementation is needed for BaseArray getitem/setitem to work, + # can be refactored. + return self + + def eval(self, i): + return self.parent.eval(self.calc_index(i)) + + def getitem(self, item): + return self.parent.getitem(self.calc_index(item)) + + @unwrap_spec(item=int, value=float) + def descr_setitem(self, space, item, value): + return self.parent.descr_setitem(space, self.calc_index(item), value) + + def descr_len(self, space): + return space.wrap(self.find_size()) + + def calc_index(self, item): + raise NotImplementedError + +class SingleDimSlice(ViewArray): + _immutable_fields_ = ["start", "stop", "step", "size"] + static_signature = Signature() + + def __init__(self, start, stop, step, slice_length, parent, signature): + ViewArray.__init__(self, parent, signature) + self.start = start + self.stop = stop + self.step = step + self.size = slice_length + + def find_size(self): + return self.size + + def calc_index(self, item): + return (self.start + item * self.step) + class SingleDimArray(BaseArray): signature = Signature() @@ -215,10 +309,8 @@ def descr_len(self, space): return space.wrap(self.size) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - item = self.getindex(space, item) - return space.wrap(self.storage[item]) + def getitem(self, item): + return self.storage[item] @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): @@ -238,14 +330,23 @@ i += 1 return space.wrap(arr) - at unwrap_spec(ObjSpace, int) + at unwrap_spec(size=int) def zeros(space, size): return space.wrap(SingleDimArray(size)) + at unwrap_spec(size=int) +def ones(space, size): + arr = SingleDimArray(size) + for i in xrange(size): + arr.storage[i] = 1.0 + return space.wrap(arr) BaseArray.typedef = TypeDef( 'numarray', __new__ = interp2app(descr_new_numarray), + + shape = GetSetProperty(BaseArray.descr_get_shape), + __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), __setitem__ = interp2app(BaseArray.descr_setitem), @@ -254,4 +355,6 @@ __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), __div__ = interp2app(BaseArray.descr_div), -) \ No newline at end of file + + mean = interp2app(BaseArray.descr_mean), +) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -8,22 +8,24 @@ def ufunc(func): signature = Signature() - @unwrap_spec(array=BaseArray) - def impl(space, array): - w_res = Call1(func, array, array.signature.transition(signature)) - array.invalidates.append(w_res) - return w_res + def impl(space, w_obj): + if isinstance(w_obj, BaseArray): + w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) + w_obj.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() - @unwrap_spec(larray=BaseArray, rarray=BaseArray) - def impl(space, larray, rarray): - new_sig = larray.signature.transition(signature).transition(rarray.signature) - w_res = Call2(func, larray, rarray, new_sig) - larray.invalidates.append(w_res) - rarray.invalidates.append(w_res) - return w_res + def impl(space, w_lhs, w_rhs): + if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): + new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) + w_res = Call2(func, w_lhs, w_rhs, new_sig) + w_lhs.invalidates.append(w_res) + w_rhs.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @ufunc @@ -60,6 +62,10 @@ return 1.0 / value @ufunc +def floor(value): + return math.floor(value) + + at ufunc def sign(value): if value == 0.0: return 0.0 diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -16,4 +16,14 @@ v3 = ar.descr_add(space, FloatWrapper(1.0)) assert v2.signature is v3.signature v4 = ar.descr_add(space, ar) - assert v1.signature is v4.signature \ No newline at end of file + assert v1.signature is v4.signature + + def test_slice_signature(self, space): + ar = SingleDimArray(10) + v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1))) + v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1))) + assert v1.signature is v2.signature + + v3 = ar.descr_add(space, v1) + v4 = ar.descr_add(space, v2) + assert v3.signature is v4.signature \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_module.py b/pypy/module/micronumpy/test/test_module.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_module.py @@ -0,0 +1,13 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + + +class AppTestNumPyModule(BaseNumpyAppTest): + def test_mean(self): + from numpy import array, mean + assert mean(array(range(5))) == 2.0 + assert mean(range(5)) == 2.0 + + def test_average(self): + from numpy import array, average + assert average(range(10)) == 4.5 + assert average(array(range(10))) == 4.5 \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,6 +18,25 @@ a[13] = 5.3 assert a[13] == 5.3 + def test_empty(self): + """ + Test that empty() works. + """ + + from numpy import empty + a = empty(2) + a[1] = 1.0 + assert a[1] == 1.0 + + def test_ones(self): + from numpy import ones + a = ones(3) + assert len(a) == 3 + assert a[0] == 1 + raises(IndexError, "a[3]") + a[2] = 4 + assert a[2] == 4 + def test_iterator_init(self): from numpy import array a = array(range(5)) @@ -46,6 +65,15 @@ assert len(a) == 5 assert len(a + a) == 5 + def test_shape(self): + from numpy import array + a = array(range(5)) + assert a.shape == (5,) + b = a + a + assert b.shape == (5,) + c = a[:3] + assert c.shape == (3,) + def test_add(self): from numpy import array a = array(range(5)) @@ -138,4 +166,51 @@ b = a + a c = b + b b[1] = 5 - assert c[1] == 4 \ No newline at end of file + assert c[1] == 4 + + def test_getslice(self): + from numpy import array + a = array(range(5)) + s = a[1:5] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[i+1] + + def test_getslice_step(self): + from numpy import array + a = array(range(10)) + s = a[1:9:2] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[2*i+1] + + def test_slice_update(self): + from numpy import array + a = array(range(5)) + s = a[0:3] + s[1] = 10 + assert a[1] == 10 + a[2] = 20 + assert s[2] == 20 + + + def test_slice_invaidate(self): + # check that slice shares invalidation list with + from numpy import array + a = array(range(5)) + s = a[0:2] + b = array([10,11]) + c = s + b + a[0] = 100 + assert c[0] == 10 + assert c[1] == 12 + d = s + b + a[1] = 101 + assert d[0] == 110 + assert d[1] == 12 + + def test_mean(self): + from numpy import array, mean + a = array(range(5)) + assert a.mean() == 2.0 + assert a[:4].mean() == 1.5 \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -3,6 +3,13 @@ class AppTestUfuncs(BaseNumpyAppTest): + def test_single_item(self): + from numpy import negative, sign, minimum + + assert negative(5.0) == -5.0 + assert sign(-0.0) == 0.0 + assert minimum(2.0, 3.0) == 2.0 + def test_negative(self): from numpy import array, negative @@ -60,6 +67,15 @@ for i in range(4): assert b[i] == reference[i] + def test_floor(self): + from numpy import array, floor + + reference = [-2.0, -1.0, 0.0, 1.0, 1.0] + a = array([-1.4, -1.0, 0.0, 1.0, 1.4]) + b = floor(a) + for i in range(5): + assert b[i] == reference[i] + def test_copysign(self): from numpy import array, copysign diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,8 +1,9 @@ from pypy.jit.metainterp.test.support import LLJitMixin +from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call1, Call2, add, mul) + FloatWrapper, Call1, Call2, SingleDimSlice, add, mul) from pypy.module.micronumpy.interp_ufuncs import negative - +from pypy.module.micronumpy.compile import numpy_compile class FakeSpace(object): pass @@ -91,4 +92,54 @@ self.meta_interp(f, [5], listops=True, backendopt=True) # This is 3, not 2 because there is a bridge for the exit. - self.check_loop_count(3) \ No newline at end of file + self.check_loop_count(3) + + def test_slice(self): + space = self.space + + def f(i): + step = 3 + ar = SingleDimArray(step*i) + s = SingleDimSlice(0, step*i, step, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s, s, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 1, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + + def test_slice2(self): + space = self.space + + def f(i): + step1 = 2 + step2 = 3 + ar = SingleDimArray(step2*i) + s1 = SingleDimSlice(0, step1*i, step1, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + s2 = SingleDimSlice(0, step2*i, step2, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s1, s2, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 2, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + +class TestTranslation(object): + def test_compile(self): + x = numpy_compile('aa+f*f/a-', 10) + x = x.compute() + assert isinstance(x, SingleDimArray) + assert x.size == 10 + assert x.storage[0] == 0 + assert x.storage[1] == ((1 + 1) * 1.2) / 1.2 - 1 + + def test_translation(self): + # we import main to check if the target compiles + from pypy.translator.goal.targetnumpystandalone import main + from pypy.rpython.annlowlevel import llstr + + interpret(main, [llstr('af+'), 100]) diff --git a/pypy/module/operator/app_operator.py b/pypy/module/operator/app_operator.py --- a/pypy/module/operator/app_operator.py +++ b/pypy/module/operator/app_operator.py @@ -4,6 +4,7 @@ This module exports a set of operators as functions. E.g. operator.add(x,y) is equivalent to x+y. ''' +from __pypy__ import builtinify def countOf(a,b): 'countOf(a, b) -- Return the number of times b occurs in a.' @@ -66,50 +67,56 @@ a[b:c] = d __setslice__ = setslice -class attrgetter(object): - def __init__(self, attr, *attrs): - self.attrs = (attr,) + attrs +def attrgetter(attr, *attrs): + if attrs: + getters = [single_attr_getter(a) for a in (attr,) + attrs] + def getter(obj): + return tuple([getter(obj) for getter in getters]) + else: + getter = single_attr_getter(attr) + return builtinify(getter) - def _resolve_attr(self, obj, attr): - last = 0 - while True: - try: - dot = attr.find(".", last) - except AttributeError: - raise TypeError - if dot > 0: - obj = getattr(obj, attr[last:dot]) - last = dot + 1 - else: - return getattr(obj, attr[last:]) +def single_attr_getter(attr): + if not isinstance(attr, str): + if not isinstance(attr, unicode): + def _raise_typeerror(obj): + raise TypeError("argument must be a string, not %r" % + (type(attr).__name__,)) + return _raise_typeerror + attr = attr.encode('ascii') + # + def make_getter(name, prevfn=None): + if prevfn is None: + def getter(obj): + return getattr(obj, name) + else: + def getter(obj): + return getattr(prevfn(obj), name) + return getter + # + last = 0 + getter = None + while True: + dot = attr.find(".", last) + if dot < 0: break + getter = make_getter(attr[last:dot], getter) + last = dot + 1 + return make_getter(attr[last:], getter) - def __call__(self, obj): - if len(self.attrs) == 1: - return self._resolve_attr(obj, self.attrs[0]) - return tuple(self._resolve_attr(obj, attr) for attr in self.attrs) -class itemgetter(object): +def itemgetter(item, *items): + if items: + list_of_indices = [item] + list(items) + def getter(obj): + return tuple([obj[i] for i in list_of_indices]) + else: + def getter(obj): + return obj[item] + return builtinify(getter) - def __init__(self, item, *args): - self.items = args - self.item = item - def __call__(self, obj): - result = obj[self.item] - - if self.items: - list = [result] + [obj[item] for item in self.items] - return tuple(list) - - return result - -class methodcaller(object): - - def __init__(self, method_name, *args, **kwargs): - self.method_name = method_name - self.args = args - self.kwargs = kwargs - - def __call__(self, obj): - return getattr(obj, self.method_name)(*self.args, **self.kwargs) +def methodcaller(method_name, *args, **kwargs): + def call(obj): + return getattr(obj, method_name)(*args, **kwargs) + return builtinify(call) diff --git a/pypy/module/posix/app_posix.py b/pypy/module/posix/app_posix.py --- a/pypy/module/posix/app_posix.py +++ b/pypy/module/posix/app_posix.py @@ -107,6 +107,9 @@ def tmpnam(): """Return an absolute pathname of a file that did not exist at the time the call is made.""" + from warnings import warn + warn(RuntimeWarning("tmpnam is a potential security risk to your program")) + import tempfile return tempfile.mktemp() @@ -114,6 +117,9 @@ """Return an absolute pathname of a file that did not exist at the time the call is made. The directory and a prefix may be specified as strings; they may be omitted or None if not needed.""" + from warnings import warn + warn(RuntimeWarning("tempnam is a potential security risk to your program")) + import tempfile return tempfile.mktemp('', prefix or 'tmp', dir) diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -847,6 +847,21 @@ assert os.path.basename(s1).startswith(prefix or 'tmp') assert os.path.basename(s2).startswith(prefix or 'tmp') + def test_tmpnam_warning(self): + import warnings, os + # + def f_tmpnam_warning(): os.tmpnam() # a single line + # + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + f_tmpnam_warning() + assert len(w) == 1 + assert issubclass(w[-1].category, RuntimeWarning) + assert "potential security risk" in str(w[-1].message) + # check that the warning points to the call to os.tmpnam(), + # not to some code inside app_posix.py + assert w[-1].lineno == f_tmpnam_warning.func_code.co_firstlineno + class AppTestEnvironment(object): def setup_class(cls): diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,6 +8,7 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'set_compile_hook': 'interp_jit.set_compile_hook', + 'DebugMergePoint': 'interp_resop.W_DebugMergePoint', } def setup_after_space_initialization(self): diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -17,10 +17,11 @@ from opcode import opmap from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant +from pypy.jit.metainterp.resoperation import rop +from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes PyFrame._virtualizable2_ = ['last_instr', 'pycode', - 'valuestackdepth', 'valuestack_w[*]', - 'fastlocals_w[*]', + 'valuestackdepth', 'locals_stack_w[*]', 'last_exception', 'lastblock', 'is_being_profiled', @@ -47,6 +48,16 @@ return (bytecode.co_flags & CO_GENERATOR) != 0 +def wrap_oplist(space, logops, operations): + list_w = [] + for op in operations: + if op.getopnum() == rop.DEBUG_MERGE_POINT: + list_w.append(space.wrap(debug_merge_point_from_boxes( + op.getarglist()))) + else: + list_w.append(space.wrap(logops.repr_of_resop(op))) + return list_w + class PyPyJitDriver(JitDriver): reds = ['frame', 'ec'] greens = ['next_instr', 'is_being_profiled', 'pycode'] @@ -62,8 +73,7 @@ return if space.is_true(cache.w_compile_hook): logops = logger._make_log_operations() - list_w = [space.wrap(logops.repr_of_resop(op)) - for op in operations] + list_w = wrap_oplist(space, logops, operations) pycode = cast_base_ptr_to_instance(PyCode, ll_pycode) cache.in_recursion = True try: @@ -85,8 +95,7 @@ return if space.is_true(cache.w_compile_hook): logops = logger._make_log_operations() - list_w = [space.wrap(logops.repr_of_resop(op)) - for op in operations] + list_w = wrap_oplist(space, logops, operations) cache.in_recursion = True try: space.call_function(cache.w_compile_hook, diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/interp_resop.py @@ -0,0 +1,41 @@ + +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.gateway import unwrap_spec, interp2app +from pypy.interpreter.pycode import PyCode +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.annlowlevel import cast_base_ptr_to_instance +from pypy.rpython.lltypesystem.rclass import OBJECT + +class W_DebugMergePoint(Wrappable): + """ A class representing debug_merge_point JIT operation + """ + + def __init__(self, mp_no, offset, pycode): + self.mp_no = mp_no + self.offset = offset + self.pycode = pycode + + def descr_repr(self, space): + return space.wrap('DebugMergePoint()') + + at unwrap_spec(mp_no=int, offset=int, pycode=PyCode) +def new_debug_merge_point(space, w_tp, mp_no, offset, pycode): + return W_DebugMergePoint(mp_no, offset, pycode) + +def debug_merge_point_from_boxes(boxes): + mp_no = boxes[0].getint() + offset = boxes[2].getint() + llcode = lltype.cast_opaque_ptr(lltype.Ptr(OBJECT), + boxes[4].getref_base()) + pycode = cast_base_ptr_to_instance(PyCode, llcode) + assert pycode is not None + return W_DebugMergePoint(mp_no, offset, pycode) + +W_DebugMergePoint.typedef = TypeDef( + 'DebugMergePoint', + __new__ = interp2app(new_debug_merge_point), + __doc__ = W_DebugMergePoint.__doc__, + __repr__ = interp2app(W_DebugMergePoint.descr_repr), + code = interp_attrproperty('pycode', W_DebugMergePoint), +) diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,8 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof', 'cppyy', '_weakref']: + 'posix', '_socket', '_sre', '_lsprof', 'cppyy', '_weakref', + '__pypy__']: return True return False diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -8,12 +8,13 @@ from pypy.jit.metainterp.logger import Logger from pypy.rpython.annlowlevel import (cast_instance_to_base_ptr, cast_base_ptr_to_instance) +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.module.pypyjit.interp_jit import pypyjitdriver from pypy.jit.tool.oparser import parse from pypy.jit.metainterp.typesystem import llhelper class MockSD(object): - class cpu: + class cpu(object): ts = llhelper class AppTestJitHook(object): @@ -27,14 +28,17 @@ pass return f """) + cls.w_f = w_f ll_code = cast_instance_to_base_ptr(w_f.code) + code_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, ll_code) logger = Logger(MockSD()) oplist = parse(""" [i1, i2] i3 = int_add(i1, i2) + debug_merge_point(0, 0, 0, 0, ConstPtr(ptr0)) guard_true(i3) [] - """).operations + """, namespace={'ptr0': code_gcref}).operations def interp_on_compile(): pypyjitdriver.on_compile(logger, LoopToken(), oplist, 'loop', @@ -63,7 +67,7 @@ assert all[0][0][0].co_name == 'f' assert all[0][0][1] == 0 assert all[0][0][2] == False - assert len(all[0][1]) == 2 + assert len(all[0][1]) == 3 assert 'int_add' in all[0][1][0] self.on_compile_bridge() assert len(all) == 2 @@ -103,3 +107,20 @@ self.on_compile_bridge() assert len(l) == 2 # and did not crash + def test_on_compile_types(self): + import pypyjit + l = [] + + def hook(*args): + l.append(args) + + pypyjit.set_compile_hook(hook) + self.on_compile() + dmp = l[0][3][1] + assert isinstance(dmp, pypyjit.DebugMergePoint) + assert dmp.code is self.f.func_code + + def test_creation(self): + import pypyjit + dmp = pypyjit.DebugMergePoint(0, 0, self.f.func_code) + assert dmp.code is self.f.func_code diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -2,6 +2,7 @@ import sys import re import os.path +from _pytest.assertion import newinterpret from pypy.tool.jitlogparser.parser import SimpleParser, Function, TraceForOpcode from pypy.tool.jitlogparser.storage import LoopStorage @@ -194,7 +195,7 @@ # transform self._assert(x, 'foo') into assert x, 'foo' source = source.replace('self._assert(', 'assert ') source = source[:-1] # remove the trailing ')' - self.msg = py.code._reinterpret(source, f, should_fail=True) + self.msg = newinterpret.interpret(source, f, should_fail=True) else: self.msg = "" diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -58,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -46,7 +46,7 @@ guard_no_overflow(descr=) i18 = int_add(i7, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) """) def test_array_intimg(self): @@ -83,7 +83,7 @@ setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) i28 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -11,21 +11,14 @@ return 1 + rec(n-1) # # this loop is traced and then aborted, because the trace is too - # long. But then "rec" is marked as "don't inline" - i = 0 - j = 0 - while i < 20: - i += 1 - j += rec(100) - # - # next time we try to trace "rec", instead of inlining we compile - # it separately and generate a call_assembler + # long. But then "rec" is marked as "don't inline". Since we + # already traced function from the start (because of number), + # now we can inline it as call assembler i = 0 j = 0 while i < 20: i += 1 j += rec(100) # ID: call_rec - a = 0 return j # log = self.run(fn, [], threshold=18) @@ -38,6 +31,20 @@ ... """) + def test_fib(self): + def fib(n): + if n == 0 or n == 1: + return 1 + return fib(n - 1) + fib(n - 2) # ID: call_rec + + log = self.run(fib, [7], function_threshold=15) + loop, = log.loops_by_filename(self.filepath, is_entry_bridge='*') + #assert loop.match_by_id('call_rec', ''' + #... + #p1 = call_assembler(..., descr=...) + #... + #''') + def test_simple_call(self): src = """ OFFSET = 0 @@ -180,7 +187,7 @@ guard_no_overflow(descr=) i18 = force_token() --TICK-- - jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) """) def test_default_and_kw(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -115,7 +115,6 @@ # ---------------------- loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i8 = getfield_gc_pure(p5, descr=) i9 = int_lt(i8, i7) guard_true(i9, descr=.*) guard_not_invalidated(descr=.*) @@ -125,7 +124,7 @@ p20 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p20, i11, descr=) setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i7, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py --- a/pypy/module/pypyjit/test_pypy_c/test_intbound.py +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -97,7 +97,7 @@ guard_no_overflow(descr=...) i17 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) """) def test_intbound_sub_lt(self): @@ -149,7 +149,7 @@ guard_no_overflow(descr=...) i19 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) """) def test_intbound_addmul_ge(self): @@ -177,7 +177,7 @@ guard_no_overflow(descr=...) i21 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) """) def test_intbound_eq(self): @@ -209,7 +209,7 @@ guard_no_overflow(descr=...) i16 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) """) def test_intbound_mul(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -167,7 +167,7 @@ guard_false(i16, descr=) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) + setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, 146982464, descr=) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) @@ -179,7 +179,7 @@ i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -0,0 +1,42 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestString(BaseTestPyPyC): + def test_lookup_default_encoding(self): + def main(n): + import string + i = 0 + letters = string.letters + uletters = unicode(string.letters) + while i < n: + i += letters[i % len(letters)] == uletters[i % len(letters)] + return i + + log = self.run(main, [300]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i14 = int_lt(i6, i9) + guard_true(i14, descr=) + i15 = int_mod(i6, i10) + i17 = int_rshift(i15, 63) + i18 = int_and(i10, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=) + i22 = int_ge(i19, i10) + guard_false(i22, descr=) + i23 = strgetitem(p11, i19) + i24 = int_ge(i19, i12) + guard_false(i24, descr=) + i25 = unicodegetitem(p13, i19) + guard_not_invalidated(descr=) + p27 = newstr(1) + strsetitem(p27, 0, i23) + p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) + guard_no_exception(descr=) + i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) + guard_true(i32, descr=) + i34 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) \ No newline at end of file diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -7,6 +7,8 @@ class Module(MixedModule): """Sys Builtin Module. """ + _immutable_fields_ = ["defaultencoding?"] + def __init__(self, space, w_name): """NOT_RPYTHON""" # because parent __init__ isn't if space.config.translating: diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -384,8 +384,9 @@ # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) - stack_items_w = self.crnt_frame.valuestack_w - for i in range(self.crnt_frame.valuestackdepth-1, -1, -1): + f = self.crnt_frame + stack_items_w = f.locals_stack_w + for i in range(f.valuestackdepth-1, f.nlocals-1, -1): w_v = stack_items_w[i] if isinstance(w_v, Constant): if w_v.value is oldvalue: diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py --- a/pypy/objspace/flow/framestate.py +++ b/pypy/objspace/flow/framestate.py @@ -10,7 +10,7 @@ def __init__(self, state): if isinstance(state, PyFrame): # getfastscope() can return real None, for undefined locals - data = state.getfastscope() + state.savevaluestack() + data = state.save_locals_stack() if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -36,11 +36,9 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): - fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) # Nones == undefined locals - frame.restorevaluestack(data[fastlocals:-2]) + frame.restore_locals_stack(data[:-2]) # Nones == undefined locals if data[-2] == Constant(None): assert data[-1] == Constant(None) frame.last_exception = None diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py --- a/pypy/objspace/flow/test/test_framestate.py +++ b/pypy/objspace/flow/test/test_framestate.py @@ -25,7 +25,7 @@ dummy = Constant(None) #dummy.dummy = True arg_list = ([Variable() for i in range(formalargcount)] + - [dummy] * (len(frame.fastlocals_w) - formalargcount)) + [dummy] * (frame.nlocals - formalargcount)) frame.setfastscope(arg_list) return frame @@ -42,7 +42,7 @@ def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1 != fs2 @@ -55,7 +55,7 @@ def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general @@ -63,7 +63,7 @@ def test_restore_frame(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs1.restoreframe(frame) assert fs1 == FrameState(frame) @@ -82,25 +82,26 @@ def test_getoutputargs(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable - # fastlocals_w[-1] -> fastlocals_w[-1] is Constant(None) - assert outputargs == [frame.fastlocals_w[0], Constant(None)] + # locals_w[n-1] -> locals_w[n-1] is Constant(None) + assert outputargs == [frame.locals_stack_w[0], Constant(None)] def test_union_different_constants(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(42) + frame.locals_stack_w[frame.nlocals-1] = Constant(42) fs2 = FrameState(frame) fs3 = fs1.union(fs2) fs3.restoreframe(frame) - assert isinstance(frame.fastlocals_w[-1], Variable) # generalized + assert isinstance(frame.locals_stack_w[frame.nlocals-1], Variable) + # ^^^ generalized def test_union_spectag(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(SpecTag()) + frame.locals_stack_w[frame.nlocals-1] = Constant(SpecTag()) fs2 = FrameState(frame) assert fs1.union(fs2) is None # UnionError diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,13 +1,14 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.debug import mark_dict_non_null def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -59,7 +60,8 @@ def initialize_as_rdict(self): assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) + self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) return self.r_dict_content @@ -308,6 +310,7 @@ def __init__(self, space): self.space = space self.content = {} + mark_dict_non_null(self.content) def impl_setitem(self, w_key, w_value): space = self.space @@ -317,6 +320,7 @@ self._as_rdict().impl_fallback_setitem(w_key, w_value) def impl_setitem_str(self, key, w_value): + assert key is not None self.content[key] = w_value def impl_setdefault(self, w_key, w_default): @@ -342,6 +346,7 @@ return len(self.content) def impl_getitem_str(self, key): + assert key is not None return self.content.get(key, None) def impl_getitem(self, w_key): diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -311,6 +311,10 @@ classofinstance=classofinstance, strdict=strdict) + def newset(self): + from pypy.objspace.std.setobject import newset + return W_SetObject(self, newset(self)) + def newslice(self, w_start, w_end, w_step): return W_SliceObject(w_start, w_end, w_step) diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -50,6 +50,10 @@ u = self.space.wrap(set('simsalabim')) assert self.space.eq_w(s,u) + def test_space_newset(self): + s = self.space.newset() + assert self.space.str_w(self.space.repr(s)) == 'set([])' + class AppTestAppSetTest: def test_subtype(self): class subset(set):pass diff --git a/pypy/pytest.ini b/pypy/pytest.ini new file mode 100644 --- /dev/null +++ b/pypy/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --assertmode=old \ No newline at end of file diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py --- a/pypy/rlib/clibffi.py +++ b/pypy/rlib/clibffi.py @@ -10,6 +10,7 @@ from pypy.rlib.rmmap import alloc from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal from pypy.rlib.rdynload import DLOpenError, DLLHANDLE +from pypy.rlib import jit from pypy.tool.autopath import pypydir from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform @@ -18,6 +19,10 @@ import sys import ctypes.util +from pypy.tool.ansi_print import ansi_log +log = py.log.Producer("libffi") +py.log.setconsumer("libffi", ansi_log) + # maaaybe isinstance here would be better. Think _MSVC = platform.name == "msvc" _MINGW = platform.name == "mingw32" @@ -67,12 +72,17 @@ result = os.path.join(dir, 'libffi.a') if os.path.exists(result): return result - raise ImportError("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("trying to use the dynamic library instead...") + return None + path_libffi_a = None if hasattr(platform, 'library_dirs_for_libffi_a'): + path_libffi_a = find_libffi_a() + if path_libffi_a is not None: # platforms on which we want static linking libraries = [] - link_files = [find_libffi_a()] + link_files = [path_libffi_a] else: # platforms on which we want dynamic linking libraries = ['ffi'] @@ -261,6 +271,7 @@ elif _MSVC: get_libc_handle = external('pypy_get_libc_handle', [], DLLHANDLE) + @jit.dont_look_inside def get_libc_name(): return rwin32.GetModuleFileName(get_libc_handle()) diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -273,7 +273,8 @@ class JitHintError(Exception): """Inconsistency in the JIT hints.""" -PARAMETERS = {'threshold': 1000, +PARAMETERS = {'threshold': 1032, # just above 1024 + 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, 'inlining': 0, diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -272,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -134,7 +134,8 @@ def external(name, argtypes, restype, **kw): kw['compilation_info'] = eci - eci.export_symbols += (name,) + if not kw.get('macro', False): + eci.export_symbols += (name,) return rffi.llexternal( name, argtypes, restype, **kw) @@ -150,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rrandom.py b/pypy/rlib/rrandom.py --- a/pypy/rlib/rrandom.py +++ b/pypy/rlib/rrandom.py @@ -24,8 +24,7 @@ def __init__(self, seed=r_uint(0)): self.state = [r_uint(0)] * N self.index = 0 - if seed: - self.init_genrand(seed) + self.init_genrand(seed) def init_genrand(self, s): mt = self.state diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rlib/test/test_rrandom.py b/pypy/rlib/test/test_rrandom.py --- a/pypy/rlib/test/test_rrandom.py +++ b/pypy/rlib/test/test_rrandom.py @@ -3,6 +3,12 @@ # the numbers were created by using CPython's _randommodule.c +def test_init_from_zero(): + rnd = Random(0) + assert rnd.state[:14] == [0, 1, 1812433255, 1900727105, 1208447044, + 2481403966, 4042607538, 337614300, 3232553940, + 1018809052, 3202401494, 1775180719, 3192392114, 594215549] + def test_init_from_seed(): rnd = Random(1000) assert rnd.state[:14] == [1000, 4252021385, 1724402292, 571538732, diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -206,7 +215,7 @@ if dictobj is None: return lltype.nullptr(self.DICT) if not isinstance(dictobj, (dict, objectmodel.r_dict)): - raise TyperError("expected a dict: %r" % (dictobj,)) + raise TypeError("expected a dict: %r" % (dictobj,)) try: key = Constant(dictobj) return self.dict_cache[key] @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -139,10 +139,10 @@ source = py.code.Source(""" def call_external_function(%(argnames)s): before = aroundstate.before - after = aroundstate.after if before: before() # NB. it is essential that no exception checking occurs here! res = funcptr(%(argnames)s) + after = aroundstate.after if after: after() return res """ % locals()) @@ -253,7 +253,7 @@ if hasattr(callable, '_errorcode_'): errorcode = callable._errorcode_ else: - errorcode = TP.TO.RESULT._example() + errorcode = TP.TO.RESULT._defl() callable_name = getattr(callable, '__name__', '?') if callbackholder is not None: callbackholder.callbacks[callable] = True @@ -262,13 +262,9 @@ def wrapper(%s): # no *args - no GIL for mallocing the tuple llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py if aroundstate is not None: - before = aroundstate.before after = aroundstate.after - else: - before = None - after = None - if after: - after() + if after: + after() # from now on we hold the GIL stackcounter.stacks_counter += 1 try: @@ -282,8 +278,10 @@ traceback.print_exc() result = errorcode stackcounter.stacks_counter -= 1 - if before: - before() + if aroundstate is not None: + before = aroundstate.before + if before: + before() # here we don't hold the GIL any more. As in the wrapper() produced # by llexternal, it is essential that no exception checking occurs # after the call to before(). diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py --- a/pypy/rpython/lltypesystem/rlist.py +++ b/pypy/rpython/lltypesystem/rlist.py @@ -250,12 +250,11 @@ length = l.length l.length = length + 1 l.ll_setitem_fast(length, newitem) -ll_append_noresize.oopspec = 'list.append(l, newitem)' def ll_both_none(lst1, lst2): return not lst1 and not lst2 - + # ____________________________________________________________ # diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted +from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -57,6 +57,8 @@ llmemory.itemoffsetof(TP.chars, 0) + llmemory.sizeof(CHAR_TP) * item) + # It'd be nice to be able to look inside this function. + @dont_look_inside @enforceargs(None, None, int, int, int) def copy_string_contents(src, dst, srcstart, dststart, length): assert srcstart >= 0 @@ -323,6 +325,8 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' + # it's pure but it does not look like it + @purefunction def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -334,7 +338,6 @@ x = 29872897 s.hash = x return x - ll_strhash._pure_function_ = True # it's pure but it does not look like it def ll_strfasthash(s): return s.hash # assumes that the hash is already computed diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,23 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + class Cls(self.AddressStack): + def append(self2, addr): + assert addr not in self2.tolist() + self.AddressStack.append(self2, addr) + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +637,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +655,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +698,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +789,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +882,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +922,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,13 +933,13 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded - self.remember_young_pointer_from_array(addr_array, index) + self.remember_young_pointer_from_array2(addr_array, index) else: self.remember_young_pointer(addr_array, newvalue) @@ -943,20 +955,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -976,20 +991,22 @@ def _init_writebarrier_with_card_marker(self): DEBUG = self.DEBUG - def remember_young_pointer_from_array(addr_array, index): + def remember_young_pointer_from_array2(addr_array, index): # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,27 +1019,85 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return # # We set the flag (even if the newly written address does not # actually point to the nursery, which seems to be ok -- actually - # it seems more important that remember_young_pointer_from_array() + # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET - remember_young_pointer_from_array._dont_inline_ = True + remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 - self.remember_young_pointer_from_array = ( - remember_young_pointer_from_array) + self.remember_young_pointer_from_array2 = ( + remember_young_pointer_from_array2) + + # xxx trying it out for the JIT: a 3-arguments version of the above + def remember_young_pointer_from_array3(addr_array, index, newvalue): + objhdr = self.header(addr_array) + # + # a single check for the common case of neither GCFLAG_HAS_CARDS + # nor GCFLAG_NO_HEAP_PTRS + if objhdr.tid & (GCFLAG_HAS_CARDS | GCFLAG_NO_HEAP_PTRS) == 0: + # common case: fast path, jump to the end of the function + pass + elif objhdr.tid & GCFLAG_HAS_CARDS == 0: + # no cards, but GCFLAG_NO_HEAP_PTRS is set. + objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS + self.prebuilt_root_objects.append(addr_array) + # jump to the end of the function + else: + # case with cards. + # + # If the newly written address does not actually point to a + # young object, leave now. + if not self.appears_to_be_young(newvalue): + return + # + # 'addr_array' is a raw_malloc'ed array with card markers + # in front. Compute the index of the bit to set: + bitindex = index >> self.card_page_shift + byteindex = bitindex >> 3 + bitmask = 1 << (bitindex & 7) + # + # If the bit is already set, leave now. + addr_byte = self.get_card(addr_array, byteindex) + byte = ord(addr_byte.char[0]) + if byte & bitmask: + return + addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET + return + # + # Logic for the no-cards case, put here to minimize the number + # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # + if self.appears_to_be_young(newvalue): + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS + + remember_young_pointer_from_array3._dont_inline_ = True + assert self.card_page_indices > 0 + self.remember_young_pointer_from_array3 = ( + remember_young_pointer_from_array3) + + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) def assume_young_pointers(self, addr_struct): @@ -1030,15 +1105,16 @@ may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1046,15 +1122,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1062,6 +1159,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1078,20 +1191,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1124,7 +1245,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1132,7 +1253,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1148,11 +1269,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1188,19 +1309,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1239,7 +1371,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1286,11 +1430,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,78 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag + # + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert not res # there might be young ptrs, let ll_arraycopy to find them + + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -463,7 +464,7 @@ annmodel.SomeInteger()], annmodel.s_None, inline=True) - func = getattr(gcdata.gc, 'remember_young_pointer_from_array', + func = getattr(gcdata.gc, 'remember_young_pointer_from_array3', None) if func is not None: # func should not be a bound method, but a real function @@ -471,7 +472,8 @@ self.write_barrier_from_array_failing_case_ptr = \ getfn(func, [annmodel.SomeAddress(), - annmodel.SomeInteger()], + annmodel.SomeInteger(), + annmodel.SomeAddress()], annmodel.s_None) self.statistics_ptr = getfn(GCClass.statistics.im_func, [s_gc, annmodel.SomeInteger()], @@ -883,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,7 +598,6 @@ res = self.interpret(func, []) assert res in [5263, 6352] - class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): def func(i): @@ -860,6 +859,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/tool/gcc_cache.py b/pypy/tool/gcc_cache.py --- a/pypy/tool/gcc_cache.py +++ b/pypy/tool/gcc_cache.py @@ -39,7 +39,16 @@ data = '' if not (data.startswith('True') or data.startswith('FAIL\n')): try: - platform.compile(c_files, eci) + _previous = platform.log_errors + try: + platform.log_errors = False + platform.compile(c_files, eci) + finally: + del platform.log_errors + # ^^^remove from the instance --- needed so that it can + # compare equal to another instance without it + if platform.log_errors != _previous: + platform.log_errors = _previous data = 'True' path.write(data) except CompilationError, e: diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,4 +1,5 @@ import re, sys + from pypy.jit.metainterp.resoperation import rop, opname from pypy.jit.tool.oparser import OpParser @@ -51,6 +52,7 @@ # factory method Op = Op + use_mock_model = True @classmethod def parse_from_input(cls, input): @@ -96,7 +98,7 @@ def __init__(self, operations, storage): if operations[0].name == 'debug_merge_point': self.inline_level = int(operations[0].args[0]) - m = re.search('\w]+), file \'(.+?)\', line (\d+)> #(\d+) (\w+)', + m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', operations[0].getarg(1)) if m is None: # a non-code loop, like StrLiteralSearch or something @@ -119,6 +121,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -218,6 +223,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -38,10 +38,10 @@ def test_split(): ops = parse(''' [i0] - debug_merge_point(0, " #10 ADD") - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -54,12 +54,12 @@ def test_inlined_call(): ops = parse(""" [] - debug_merge_point(0, ' #28 CALL_FUNCTION') + debug_merge_point(0, ' #28 CALL_FUNCTION') i18 = getfield_gc(p0, descr=) - debug_merge_point(1, ' #0 LOAD_FAST') - debug_merge_point(1, ' #3 LOAD_CONST') - debug_merge_point(1, ' #7 RETURN_VALUE') - debug_merge_point(0, ' #31 STORE_FAST') + debug_merge_point(1, ' #0 LOAD_FAST') + debug_merge_point(1, ' #3 LOAD_CONST') + debug_merge_point(1, ' #7 RETURN_VALUE') + debug_merge_point(0, ' #31 STORE_FAST') """) res = Function.from_operations(ops.operations, LoopStorage()) assert len(res.chunks) == 3 # two chunks + inlined call @@ -72,10 +72,10 @@ def test_name(): ops = parse(''' [i0] - debug_merge_point(0, " #10 ADD") - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -89,10 +89,10 @@ ops = parse(''' [i0] i3 = int_add(i0, 1) - debug_merge_point(0, " #10 ADD") - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -102,10 +102,10 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(0, " #0 LOAD_FAST") - debug_merge_point(0, " #3 LOAD_FAST") - debug_merge_point(0, " #6 BINARY_ADD") - debug_merge_point(0, " #7 RETURN_VALUE") + debug_merge_point(0, " #0 LOAD_FAST") + debug_merge_point(0, " #3 LOAD_FAST") + debug_merge_point(0, " #6 BINARY_ADD") + debug_merge_point(0, " #7 RETURN_VALUE") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.chunks[1].lineno == 3 @@ -114,11 +114,11 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(0, " #9 LOAD_FAST") - debug_merge_point(0, " #12 LOAD_CONST") - debug_merge_point(0, " #22 LOAD_CONST") - debug_merge_point(0, " #28 LOAD_CONST") - debug_merge_point(0, " #6 SETUP_LOOP") + debug_merge_point(0, " #9 LOAD_FAST") + debug_merge_point(0, " #12 LOAD_CONST") + debug_merge_point(0, " #22 LOAD_CONST") + debug_merge_point(0, " #28 LOAD_CONST") + debug_merge_point(0, " #6 SETUP_LOOP") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.linerange == (7, 9) @@ -128,7 +128,7 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] - debug_merge_point(0, ' #17 FOR_ITER') + debug_merge_point(0, ' #17 FOR_ITER') guard_class(p6, 144264192, descr=) p12 = getfield_gc(p6, descr=) """ % locals()) @@ -168,7 +168,7 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -1,8 +1,13 @@ import autopath import py -from pypy.interpreter import gateway +from pypy.interpreter import gateway, pycode from pypy.interpreter.error import OperationError +try: + from _pytest.assertion.newinterpret import interpret +except ImportError: + from _pytest.assertion.oldinterpret import interpret + # ____________________________________________________________ class AppCode(object): @@ -51,13 +56,11 @@ space = self.space for key, w_value in vars.items(): space.setitem(self.w_locals, space.wrap(key), w_value) - return space.eval(code, self.w_globals, self.w_locals) - - def exec_(self, code, **vars): - space = self.space - for key, w_value in vars.items(): - space.setitem(self.w_locals, space.wrap(key), w_value) - space.exec_(code, self.w_globals, self.w_locals) + if isinstance(code, str): + return space.eval(code, self.w_globals, self.w_locals) + pyc = pycode.PyCode._from_code(space, code) + return pyc.exec_host_bytecode(self.w_globals, self.w_locals) + exec_ = eval def repr(self, w_value): return self.space.unwrap(self.space.repr(w_value)) @@ -163,8 +166,8 @@ except py.error.ENOENT: source = None from pypy import conftest - if source and not py.test.config.option.nomagic: - msg = py.code._reinterpret_old(source, runner, should_fail=True) + if source and py.test.config._assertstate.mode != "off": + msg = interpret(source, runner, should_fail=True) space.setattr(w_self, space.wrap('args'), space.newtuple([space.wrap(msg)])) w_msg = space.wrap(msg) diff --git a/pypy/tool/pytest/test/test_pytestsupport.py b/pypy/tool/pytest/test/test_pytestsupport.py --- a/pypy/tool/pytest/test/test_pytestsupport.py +++ b/pypy/tool/pytest/test/test_pytestsupport.py @@ -4,7 +4,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.pyframe import PyFrame from pypy.tool.pytest.appsupport import (AppFrame, build_pytest_assertion, - AppExceptionInfo) + AppExceptionInfo, interpret) import py from pypy.tool.udir import udir import os @@ -22,8 +22,8 @@ co = PyCode._from_code(space, somefunc.func_code) pyframe = PyFrame(space, co, space.newdict(), None) runner = AppFrame(space, pyframe) - py.code._reinterpret_old("f = lambda x: x+1", runner, should_fail=False) - msg = py.code._reinterpret_old("assert isinstance(f(2), float)", runner) + interpret("f = lambda x: x+1", runner, should_fail=False) + msg = interpret("assert isinstance(f(2), float)", runner) assert msg.startswith("assert isinstance(3, float)\n" " + where 3 = ") @@ -58,6 +58,12 @@ except AssertionError, e: assert e.msg == "Failed" +def app_test_comparison(): + try: + assert 3 > 4 + except AssertionError, e: + assert "3 > 4" in e.msg + def test_appexecinfo(space): try: diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -3,9 +3,9 @@ It uses 'pypy/translator/goal/pypy-c' and parts of the rest of the working copy. Usage: - package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] + package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] [destination-for-tarball] [pypy-c-path] -Usually you would do: package.py ../../.. pypy-VER-PLATFORM. +Usually you would do: package.py ../../.. pypy-VER-PLATFORM The output is found in the directory /tmp/usession-YOURNAME/build/. """ @@ -122,7 +122,10 @@ zf.close() else: archive = str(builddir.join(name + '.tar.bz2')) - e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) + if sys.platform == 'darwin': + e = os.system('tar --numeric-owner -cvjf ' + archive + " " + name) + else: + e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) if e: raise OSError('"tar" returned exit status %r' % e) finally: diff --git a/pypy/tool/test/test_gcc_cache.py b/pypy/tool/test/test_gcc_cache.py --- a/pypy/tool/test/test_gcc_cache.py +++ b/pypy/tool/test/test_gcc_cache.py @@ -1,11 +1,13 @@ - +import sys from pypy.tool.gcc_cache import * from pypy.tool.udir import udir -import md5 +import md5, cStringIO from pypy.translator.tool.cbuild import ExternalCompilationInfo +localudir = udir.join('test_gcc_cache').ensure(dir=1) + def test_gcc_exec(): - f = udir.join("x.c") + f = localudir.join("x.c") f.write(""" #include #include @@ -15,8 +17,8 @@ return 0; } """) - dir1 = udir.join('test_gcc_exec_dir1').ensure(dir=1) - dir2 = udir.join('test_gcc_exec_dir2').ensure(dir=1) + dir1 = localudir.join('test_gcc_exec_dir1').ensure(dir=1) + dir2 = localudir.join('test_gcc_exec_dir2').ensure(dir=1) dir1.join('test_gcc_exec.h').write('#define ANSWER 3\n') dir2.join('test_gcc_exec.h').write('#define ANSWER 42\n') eci = ExternalCompilationInfo(include_dirs=[str(dir1)]) @@ -36,7 +38,7 @@ print '>>>' def test_gcc_ask(): - f = udir.join("y.c") + f = localudir.join("y.c") f.write(""" #include #include @@ -46,8 +48,8 @@ return 0; } """) - dir1 = udir.join('test_gcc_ask_dir1').ensure(dir=1) - dir2 = udir.join('test_gcc_ask_dir2').ensure(dir=1) + dir1 = localudir.join('test_gcc_ask_dir1').ensure(dir=1) + dir2 = localudir.join('test_gcc_ask_dir2').ensure(dir=1) dir1.join('test_gcc_ask.h').write('/* hello world */\n') dir2.join('test_gcc_ask.h').write('#error boom\n') eci = ExternalCompilationInfo(include_dirs=[str(dir1)]) @@ -63,3 +65,15 @@ print '<<<' print err print '>>>' + +def test_gcc_ask_doesnt_log_errors(): + f = localudir.join('z.c') + f.write("""this file is not valid C code\n""") + eci = ExternalCompilationInfo() + oldstderr = sys.stderr + try: + sys.stderr = capture = cStringIO.StringIO() + py.test.raises(CompilationError, try_compile_cache, [f], eci) + finally: + sys.stderr = oldstderr + assert 'ERROR' not in capture.getvalue().upper() diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -297,6 +297,13 @@ gc_startup_code = RefcountingGcPolicy.gc_startup_code.im_func + def compilation_info(self): + eci = BasicGcPolicy.compilation_info(self) + eci = eci.merge(ExternalCompilationInfo( + post_include_bits=['#define USING_NO_GC_AT_ALL'], + )) + return eci + class FrameworkGcPolicy(BasicGcPolicy): transformerclass = framework.FrameworkGCTransformer diff --git a/pypy/translator/c/gcc/test/elf/track12.s b/pypy/translator/c/gcc/test/elf/track12.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf/track12.s @@ -0,0 +1,9 @@ + .type pypy_f, @function +pypy_f: + pushl 4(%esp) + call pypy_other + ;; expected {4(%esp) | %ebx, %esi, %edi, %ebp | (%esp)} + popl %eax + /* GCROOT %eax */ + ret + .size pypy_f, .-pypy_f diff --git a/pypy/translator/c/gcc/test/elf/track13.s b/pypy/translator/c/gcc/test/elf/track13.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf/track13.s @@ -0,0 +1,9 @@ + .type pypy_f, @function +pypy_f: + call pypy_other + ;; expected {(%esp) | %ebx, %esi, %edi, %ebp | 8(%esp)} + pushl 8(%esp) + popl %eax + /* GCROOT %eax */ + ret + .size pypy_f, .-pypy_f diff --git a/pypy/translator/c/gcc/test/msvc/track_and_esp.s b/pypy/translator/c/gcc/test/msvc/track_and_esp.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/msvc/track_and_esp.s @@ -0,0 +1,474 @@ +PUBLIC ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ ; `string' +PUBLIC _pypy_g_ll_math_ll_math_frexp +; COMDAT ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ +CONST SEGMENT +??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ DB 'pypy_g_ll_math_l' + DB 'l_math_frexp', 00H ; `string' +; Function compile flags: /Ogtpy +CONST ENDS +; COMDAT _pypy_g_ll_math_ll_math_frexp +_TEXT SEGMENT +_l_mantissa_0$ = -8 ; size = 8 +_l_v21638$ = -8 ; size = 8 +_l_x_14$ = 8 ; size = 8 +_pypy_g_ll_math_ll_math_frexp PROC ; COMDAT + +; 58245: struct pypy_tuple2_0 *pypy_g_ll_math_ll_math_frexp(double l_x_14) { + + push ebp + mov ebp, esp + and esp, -64 ; ffffffc0H + +; 58246: long *l_exp_p_0; double l_mantissa_0; bool_t l_v21641; +; 58247: bool_t l_v21643; bool_t l_v21644; bool_t l_v21646; bool_t l_v21647; +; 58248: bool_t l_v21652; bool_t l_v21653; bool_t l_v21660; bool_t l_v21666; +; 58249: bool_t l_v21670; bool_t l_v21674; bool_t l_v21676; double l_v21638; +; 58250: long l_v21637; long l_v21649; long l_v21651; long l_v21677; +; 58251: long l_v21678; struct pypy_exceptions_Exception0 *l_v21687; +; 58252: struct pypy_header0 *l_v21654; struct pypy_object0 *l_v21682; +; 58253: struct pypy_object0 *l_v21691; struct pypy_object_vtable0 *l_v21665; +; 58254: struct pypy_object_vtable0 *l_v21669; +; 58255: struct pypy_object_vtable0 *l_v21675; +; 58256: struct pypy_object_vtable0 *l_v21683; struct pypy_tuple2_0 *l_v21640; +; 58257: struct pypy_tuple2_0 *l_v21695; void* l_v21639; void* l_v21648; +; 58258: void* l_v21650; void* l_v21656; void* l_v21658; void* l_v21659; +; 58259: void* l_v21668; void* l_v21672; void* l_v21679; void* l_v21688; +; 58260: void* l_v21696; +; 58261: goto block0; +; 58262: +; 58263: block0: +; 58264: l_v21641 = pypy_g_ll_math_ll_math_isnan(l_x_14); + + fld QWORD PTR _l_x_14$[ebp] + sub esp, 52 ; 00000034H + push ebx + push esi + push edi + sub esp, 8 + fstp QWORD PTR [esp] +$block0$88239: + call _pypy_g_ll_math_ll_math_isnan + +; 58265: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isnan); +; 58266: l_v21643 = l_v21641; +; 58267: if (l_v21643) { +; 58268: l_v21637 = 0L; +; 58269: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] + add esp, 8 + test al, al + +; 58270: goto block3; + + jne SHORT $LN10 at pypy_g_ll_@159 + +; 58271: } +; 58272: goto block1; +; 58273: +; 58274: block1: +; 58275: l_v21644 = pypy_g_ll_math_ll_math_isinf(l_x_14); + + sub esp, 8 + fstp QWORD PTR [esp] +$block1$88243: + call _pypy_g_ll_math_ll_math_isinf + add esp, 8 + +; 58276: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isinf); +; 58277: l_v21646 = l_v21644; +; 58278: if (l_v21646) { + + test al, al + je SHORT $block2$88245 + +; 58279: l_v21637 = 0L; +; 58280: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] +$LN10 at pypy_g_ll_@159: + +; 58288: goto block14; +; 58289: } +; 58290: l_v21637 = 0L; + + xor edi, edi +$LN30 at pypy_g_ll_@159: + +; 58291: l_v21638 = l_x_14; +; 58292: goto block3; +; 58293: +; 58294: block3: +; 58295: l_v21648 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free; + + mov esi, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4 + fstp QWORD PTR _l_v21638$[esp+64] + +; 58296: OP_RAW_MALLOC_USAGE((0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21649); +; 58297: l_v21650 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_top_of_space; +; 58298: OP_ADR_DELTA(l_v21650, l_v21648, l_v21651); + + mov eax, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+12 + sub eax, esi + +; 58299: OP_INT_GT(l_v21649, l_v21651, l_v21652); + + cmp eax, 24 ; 00000018H +$block3$88242: + +; 58300: if (l_v21652) { + + jge $block4$88260 + +; 58334: l_v21695 = l_v21640; +; 58335: goto block8; +; 58336: +; 58337: block8: +; 58338: RPY_DEBUG_RETURN(); +; 58339: return l_v21695; +; 58340: +; 58341: block9: +; 58342: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58343: l_v21695 = ((struct pypy_tuple2_0 *) NULL); +; 58344: goto block8; +; 58345: +; 58346: block10: +; 58347: abort(); /* debug_llinterpcall should be unreachable */ +; 58348: l_v21665 = (&pypy_g_ExcData)->ed_exc_type; +; 58349: l_v21666 = (l_v21665 == NULL); +; 58350: if (!l_v21666) { +; 58351: goto block11; +; 58352: } +; 58353: goto block5; +; 58354: +; 58355: block11: +; 58356: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58357: l_v21696 = NULL; +; 58358: goto block6; +; 58359: +; 58360: block12: +; 58361: l_v21668 = pypy_g_SemiSpaceGC_obtain_free_space((&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC), (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0)))); + + push 24 ; 00000018H + push OFFSET _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC +$block12$88259: + call _pypy_g_SemiSpaceGC_obtain_free_space + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58362: l_v21669 = (&pypy_g_ExcData)->ed_exc_type; +; 58363: l_v21670 = (l_v21669 == NULL); + + xor ecx, ecx + add esp, 8 + cmp DWORD PTR _pypy_g_ExcData, ecx + +; 58364: if (!l_v21670) { + + je $LN5 at pypy_g_ll_@159 + +; 58368: goto block4; +; 58369: +; 58370: block13: +; 58371: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?N@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?8??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block13$88313: +$block9$88285: + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block2$88245: + +; 58281: goto block3; +; 58282: } +; 58283: goto block2; +; 58284: +; 58285: block2: +; 58286: OP_FLOAT_IS_TRUE(l_x_14, l_v21647); + + fldz + fld QWORD PTR _l_x_14$[ebp] + fucom ST(1) + fnstsw ax + fstp ST(1) + test ah, 68 ; 00000044H + +; 58287: if (l_v21647) { + + jnp $LN10 at pypy_g_ll_@159 + +; 58372: l_v21696 = NULL; +; 58373: goto block6; +; 58374: +; 58375: block14: +; 58376: l_v21672 = pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign(1L, (0 + 0), sizeof(long)); + + push 4 + fstp ST(0) + push 0 + push 1 +$block14$88247: + call _pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } + mov esi, eax + +; 58377: OP_TRACK_ALLOC_START(l_v21672, /* nothing */); + + push OFFSET ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ + push esi + call _pypy_debug_alloc_start + ;; expected {4(%ebp) | 28(%esp), 24(%esp), 20(%esp), (%ebp) | } + add esp, 20 ; 00000014H + +; 58378: l_exp_p_0 = (long *)l_v21672; +; 58379: l_v21674 = (l_exp_p_0 != NULL); + + test esi, esi + +; 58380: if (!l_v21674) { + + jne SHORT $block15$88324 + +; 58418: goto block8; +; 58419: +; 58420: block18: +; 58421: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BB@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], esi + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block18$88323: + +; 58422: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block15$88324: + +; 58381: goto block18; +; 58382: } +; 58383: goto block15; +; 58384: +; 58385: block15: +; 58386: l_mantissa_0 = pypy_g_frexp__Float_arrayPtr_star_2(l_x_14, l_exp_p_0); + + fld QWORD PTR _l_x_14$[ebp] + push esi + sub esp, 8 + fstp QWORD PTR [esp] + call _pypy_g_frexp__Float_arrayPtr_star_2 + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } + +; 58387: l_v21675 = (&pypy_g_ExcData)->ed_exc_type; +; 58388: l_v21676 = (l_v21675 == NULL); + + mov edi, DWORD PTR _pypy_g_ExcData + fstp QWORD PTR _l_mantissa_0$[esp+76] + add esp, 12 ; 0000000cH + test edi, edi + +; 58389: if (!l_v21676) { + + je SHORT $block16$88328 + +; 58403: +; 58404: block17: +; 58405: l_v21682 = (&pypy_g_ExcData)->ed_exc_value; +; 58406: l_v21683 = (&pypy_g_ExcData)->ed_exc_type; +; 58407: PYPY_DEBUG_CATCH_EXCEPTION("ll_math_ll_math_frexp", l_v21683, l_v21683 == (&pypy_g_py__code_assertion_AssertionError_vtable.ae_super.ae_super.se_super.e_super) || l_v21683 == (&pypy_g_exceptions_NotImplementedError_vtable.nie_super.re_super.se_super.e_super)); + + mov eax, DWORD PTR _pypydtcount + mov ebx, DWORD PTR _pypy_g_ExcData+4 + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BA@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], edi + inc eax + and eax, 8191 ; 00001fffH +$block17$88327: + mov DWORD PTR _pypydtcount, eax + cmp edi, OFFSET _pypy_g_py__code_assertion_AssertionError_vtable + je SHORT $LN1 at pypy_g_ll_@159 + cmp edi, OFFSET _pypy_g_exceptions_NotImplementedError_vtable + jne SHORT $LN2 at pypy_g_ll_@159 +$LN1 at pypy_g_ll_@159: + call _pypy_debug_catch_fatal_exception +$LN2 at pypy_g_ll_@159: + +; 58408: (&pypy_g_ExcData)->ed_exc_value = ((struct pypy_object0 *) NULL); + + xor eax, eax + +; 58409: (&pypy_g_ExcData)->ed_exc_type = ((struct pypy_object_vtable0 *) NULL); +; 58410: l_v21687 = (struct pypy_exceptions_Exception0 *)l_v21682; +; 58411: l_v21688 = (void*)l_exp_p_0; +; 58412: OP_TRACK_ALLOC_STOP(l_v21688, /* nothing */); + + push esi + mov DWORD PTR _pypy_g_ExcData+4, eax + mov DWORD PTR _pypy_g_ExcData, eax + call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } + +; 58413: OP_RAW_FREE(l_v21688, /* nothing */); + + push esi + call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58414: l_v21691 = (struct pypy_object0 *)l_v21687; +; 58415: pypy_g_RPyReRaiseException(l_v21683, l_v21691); + + push ebx + push edi + call _pypy_g_RPyReRaiseException + add esp, 16 ; 00000010H + +; 58416: pypy_asm_gc_nocollect(pypy_g_RPyReRaiseException); +; 58417: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block16$88328: + +; 58390: goto block17; +; 58391: } +; 58392: goto block16; +; 58393: +; 58394: block16: +; 58395: l_v21677 = RPyBareItem(l_exp_p_0, 0L); +; 58396: l_v21678 = (long)(l_v21677); + + mov edi, DWORD PTR [esi] + +; 58397: l_v21679 = (void*)l_exp_p_0; +; 58398: OP_TRACK_ALLOC_STOP(l_v21679, /* nothing */); + + push esi + call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } + +; 58399: OP_RAW_FREE(l_v21679, /* nothing */); + + push esi + call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58400: l_v21637 = l_v21678; +; 58401: l_v21638 = l_mantissa_0; + + fld QWORD PTR _l_mantissa_0$[esp+72] + add esp, 8 + +; 58402: goto block3; + + jmp $LN30 at pypy_g_ll_@159 +$LN5 at pypy_g_ll_@159: + +; 58365: goto block13; +; 58366: } +; 58367: l_v21639 = l_v21668; + + mov esi, eax +$block4$88260: +$block5$88263: + +; 58301: goto block12; +; 58302: } +; 58303: l_v21639 = l_v21648; +; 58304: goto block4; +; 58305: +; 58306: block4: +; 58307: OP_INT_IS_TRUE(RUNNING_ON_LLINTERP, l_v21653); +; 58308: if (l_v21653) { +; 58309: goto block10; +; 58310: } +; 58311: goto block5; +; 58312: +; 58313: block5: +; 58314: l_v21654 = (struct pypy_header0 *)l_v21639; +; 58315: RPyField(l_v21654, h_tid) = (GROUP_MEMBER_OFFSET(struct group_pypy_g_typeinfo_s, member20)+0L); + + test esi, esi + jne SHORT $LN18 at pypy_g_ll_@159 + call _RPyAbort +$LN18 at pypy_g_ll_@159: + +; 58316: OP_ADR_ADD(l_v21639, (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21656); +; 58317: (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free = l_v21656; +; 58318: OP_ADR_ADD(l_v21639, 0, l_v21658); +; 58319: l_v21659 = (void*)l_v21658; +; 58320: l_v21696 = l_v21659; +; 58321: goto block6; +; 58322: +; 58323: block6: +; 58324: l_v21640 = (struct pypy_tuple2_0 *)l_v21696; +; 58325: l_v21660 = (l_v21640 != NULL); +; 58326: if (!l_v21660) { +; 58327: goto block9; +; 58328: } +; 58329: goto block7; +; 58330: +; 58331: block7: +; 58332: RPyField(l_v21640, t_item0) = l_v21638; + + fld QWORD PTR _l_v21638$[esp+64] + mov DWORD PTR [esi], 81 ; 00000051H + lea ecx, DWORD PTR [esi+24] + mov DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4, ecx + fstp QWORD PTR [esi+8] + +; 58333: RPyField(l_v21640, t_item1) = l_v21637; + + mov DWORD PTR [esi+16], edi + +; 58423: goto block8; +; 58424: } + + pop edi + mov eax, esi + pop esi +$block6$88281: +$block8$88289: + pop ebx + mov esp, ebp + pop ebp + ret 0 +_pypy_g_ll_math_ll_math_frexp ENDP +_TEXT ENDS diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -271,7 +271,8 @@ match = self.r_localvar_esp.match(localvar) if match: - if localvar == self.TOP_OF_STACK: # for pushl and popl, by + if localvar == self.TOP_OF_STACK_MINUS_WORD: + # for pushl and popl, by hint = None # default ebp addressing is else: # a bit nicer hint = 'esp' @@ -526,8 +527,9 @@ target = match.group("target") if target == self.ESP: # only for andl $-16, %esp used to align the stack in main(). - # main() should not be seen at all. - raise AssertionError("instruction unexpected outside of main()") + # main() should not be seen at all. But on e.g. MSVC we see + # the instruction somewhere else too... + return InsnCannotFollowEsp() else: return self.binary_insn(line) @@ -591,10 +593,12 @@ def _visit_push(self, line): match = self.r_unaryinsn.match(line) source = match.group(1) - return [InsnStackAdjust(-self.WORD)] + self.insns_for_copy(source, self.TOP_OF_STACK) + return self.insns_for_copy(source, self.TOP_OF_STACK_MINUS_WORD) + \ + [InsnStackAdjust(-self.WORD)] def _visit_pop(self, target): - return self.insns_for_copy(self.TOP_OF_STACK, target) + [InsnStackAdjust(+self.WORD)] + return [InsnStackAdjust(+self.WORD)] + \ + self.insns_for_copy(self.TOP_OF_STACK_MINUS_WORD, target) def _visit_prologue(self): # for the prologue of functions that use %ebp as frame pointer @@ -986,15 +990,15 @@ OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' LABEL = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)' OFFSET_LABELS = 2**30 - TOP_OF_STACK = '0(%esp)' + TOP_OF_STACK_MINUS_WORD = '-4(%esp)' r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$") r_functionend = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$") - LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|\d*[(]%esp[)]" + LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|-?\d*[(]%esp[)]" LOCALVARFP = LOCALVAR + r"|-?\d*[(]%ebp[)]" r_localvarnofp = re.compile(LOCALVAR) r_localvarfp = re.compile(LOCALVARFP) - r_localvar_esp = re.compile(r"(\d*)[(]%esp[)]") + r_localvar_esp = re.compile(r"(-?\d*)[(]%esp[)]") r_localvar_ebp = re.compile(r"(-?\d*)[(]%ebp[)]") r_rel_label = re.compile(r"(\d+):\s*$") @@ -1047,7 +1051,7 @@ OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' LABEL = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)' OFFSET_LABELS = 2**30 - TOP_OF_STACK = '0(%rsp)' + TOP_OF_STACK_MINUS_WORD = '-8(%rsp)' r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$") r_functionend = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$") @@ -1143,7 +1147,7 @@ CALLEE_SAVE_REGISTERS = ['ebx', 'esi', 'edi', 'ebp'] REG2LOC = dict((_reg, LOC_REG | ((_i+1)<<2)) for _i, _reg in enumerate(CALLEE_SAVE_REGISTERS)) - TOP_OF_STACK = 'DWORD PTR [esp]' + TOP_OF_STACK_MINUS_WORD = 'DWORD PTR [esp-4]' OPERAND = r'(?:(:?WORD|DWORD|BYTE) PTR |OFFSET )?[_\w?:@$]*(?:[-+0-9]+)?(:?\[[-+*\w0-9]+\])?' LABEL = r'([a-zA-Z_$@.][a-zA-Z0-9_$@.]*)' @@ -1173,7 +1177,7 @@ r_gcroot_marker = re.compile(r"$1") # never matches r_gcroot_marker_var = re.compile(r"DWORD PTR .+_constant_always_one_.+pypy_asm_gcroot") r_gcnocollect_marker = re.compile(r"\spypy_asm_gc_nocollect\(("+OPERAND+")\);") - r_bottom_marker = re.compile(r"; .+\tpypy_asm_stack_bottom\(\);") + r_bottom_marker = re.compile(r"; .+\spypy_asm_stack_bottom\(\);") FUNCTIONS_NOT_RETURNING = { '__exit': None, diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -569,7 +569,10 @@ gcmapfiles = ['%s.gcmap' % (c,) for c in trackgcfiles] mk.definition('ASMFILES', sfiles) mk.definition('GCMAPFILES', gcmapfiles) - mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') if self.config.translation.shared: mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup") @@ -644,7 +647,10 @@ '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)') else: - mk.definition('DEBUGFLAGS', '-O1 -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O1 -g') mk.write() #self.translator.platform, # , diff --git a/pypy/translator/c/node.py b/pypy/translator/c/node.py --- a/pypy/translator/c/node.py +++ b/pypy/translator/c/node.py @@ -1031,7 +1031,7 @@ if (issubclass(value, BaseException) and value.__module__ == 'exceptions'): return 'PyExc_' + value.__name__ - if value is py.code._AssertionError: + if issubclass(value, AssertionError): return 'PyExc_AssertionError' if value is _StackOverflow: return 'PyExc_RuntimeError' diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h --- a/pypy/translator/c/src/main.h +++ b/pypy/translator/c/src/main.h @@ -79,6 +79,7 @@ fprintf(stderr, "Fatal error during initialization: %s\n", errmsg); #endif abort(); + return 1; } int PYPY_MAIN_FUNCTION(int argc, char *argv[]) diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h --- a/pypy/translator/c/src/mem.h +++ b/pypy/translator/c/src/mem.h @@ -222,6 +222,15 @@ #endif /* USING_BOEHM_GC */ + +#ifdef USING_NO_GC_AT_ALL +#define OP_BOEHM_ZERO_MALLOC(size, r, restype, is_atomic, is_varsize) \ + r = (restype) calloc(1, size); +#define OP_BOEHM_DISAPPEARING_LINK(link, obj, r) /* nothing */ +#define OP_GC__DISABLE_FINALIZERS(r) /* nothing */ +#define OP_GC__ENABLE_FINALIZERS(r) /* nothing */ +#endif + /************************************************************/ /* weakref support */ diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -1117,6 +1117,7 @@ S = lltype.GcStruct('S', ('u', lltype.Ptr(U))) A = lltype.GcArray(lltype.Ptr(S)) filename = self.filename_dump_typeids_z + open_flags = os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0) def fn(): s = lltype.malloc(S) @@ -1128,7 +1129,7 @@ # p = rgc.get_typeids_z() s = ''.join([p[i] for i in range(len(p))]) - fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0666) + fd = os.open(filename, open_flags, 0666) os.write(fd, s) os.close(fd) return 0 @@ -1137,7 +1138,7 @@ def test_write_typeids_z(self): self.run("write_typeids_z") - f = open(self.filename_dump_typeids_z) + f = open(self.filename_dump_typeids_z, 'rb') data_z = f.read() f.close() import zlib diff --git a/pypy/translator/goal/targetnumpystandalone.py b/pypy/translator/goal/targetnumpystandalone.py --- a/pypy/translator/goal/targetnumpystandalone.py +++ b/pypy/translator/goal/targetnumpystandalone.py @@ -10,46 +10,32 @@ """ import time -from pypy.module.micronumpy.numarray import SingleDimArray, Code, compute +from pypy.module.micronumpy.compile import numpy_compile from pypy.jit.codewriter.policy import JitPolicy - -def create_array(size): - a = SingleDimArray(size) - for i in range(size): - a.storage[i] = float(i % 10) - return a +from pypy.rpython.annlowlevel import hlstr def entry_point(argv): if len(argv) != 3: print __doc__ return 1 - bytecode = argv[1] - for b in bytecode: - if b not in 'alf': - print "WRONG BYTECODE" - print __doc__ - return 2 try: size = int(argv[2]) except ValueError: print "INVALID LITERAL FOR INT:", argv[2] print __doc__ return 3 - no_arrays = bytecode.count('l') - no_floats = bytecode.count('f') - arrays = [] - floats = [] - for i in range(no_arrays): - arrays.append(create_array(size)) - for i in range(no_floats): - floats.append(float(i + 1)) - code = Code(bytecode, arrays, floats) t0 = time.time() - compute(code) - print "bytecode:", bytecode, "size:", size + main(argv[0], size) + print "bytecode:", argv[0], "size:", size print "took:", time.time() - t0 return 0 +def main(bc, size): + if not isinstance(bc, str): + bc = hlstr(bc) # for tests + a = numpy_compile(bc, size) + a = a.compute() + def target(*args): return entry_point, None diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -103,6 +103,8 @@ specname = os.path.splitext(os.path.basename(targetspec))[0] sys.path.insert(0, os.path.dirname(targetspec)) mod = __import__(specname) + if 'target' not in mod.__dict__: + raise Exception("file %r is not a valid targetxxx.py." % (targetspec,)) return mod.__dict__ def parse_options_and_load_target(): @@ -149,6 +151,9 @@ log.ERROR("Could not find target %r" % (arg, )) sys.exit(1) + # apply the platform settings + set_platform(config) + targetspec = translateconfig.targetspec targetspec_dic = load_target(targetspec) @@ -164,9 +169,6 @@ existing_config=config, translating=True) - # apply the platform settings - set_platform(config) - # apply the optimization level settings set_opt_level(config, translateconfig.opt) diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py --- a/pypy/translator/platform/__init__.py +++ b/pypy/translator/platform/__init__.py @@ -38,6 +38,7 @@ c_environ = None relevant_environ = () + log_errors = True so_prefixes = ('',) @@ -120,11 +121,12 @@ if returncode != 0: errorfile = outname.new(ext='errors') errorfile.write(stderr, 'wb') - stderrlines = stderr.splitlines() - for line in stderrlines: - log.Error(line) - # ^^^ don't use ERROR, because it might actually be fine. - # Also, ERROR confuses lib-python/conftest.py. + if self.log_errors: + stderrlines = stderr.splitlines() + for line in stderrlines: + log.Error(line) + # ^^^ don't use ERROR, because it might actually be fine. + # Also, ERROR confuses lib-python/conftest.py. raise CompilationError(stdout, stderr) else: for line in stderr.splitlines(): diff --git a/pypy/translator/platform/darwin.py b/pypy/translator/platform/darwin.py --- a/pypy/translator/platform/darwin.py +++ b/pypy/translator/platform/darwin.py @@ -68,12 +68,10 @@ class Darwin_i386(Darwin): name = "darwin_i386" - link_flags = ('-arch', 'i386', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'i386') + cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer') class Darwin_x86_64(Darwin): name = "darwin_x86_64" - link_flags = ('-arch', 'x86_64', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'x86_64') + cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer') diff --git a/pytest.py b/pytest.py old mode 100644 new mode 100755 --- a/pytest.py +++ b/pytest.py @@ -1,7 +1,6 @@ +#!/usr/bin/env python """ unit and functional testing with Python. -(pypy version of startup script) -see http://pytest.org for details. """ __all__ = ['main'] @@ -9,23 +8,6 @@ from _pytest import core as cmdline from _pytest import __version__ -# This pytest.py script is located in the pypy source tree -# which has a copy of pytest and py within its source tree. -# If the environment also has an installed version of pytest/py -# we are bound to get warnings so we disable them. -# XXX eventually pytest and py should not be inlined shipped -# with the pypy source code but become a requirement for installation. - -import warnings -warnings.filterwarnings("ignore", - "Module py was already imported", category=UserWarning) -warnings.filterwarnings("ignore", - "Module _pytest was already imported", - category=UserWarning) -warnings.filterwarnings("ignore", - "Module pytest was already imported", - category=UserWarning) - if __name__ == '__main__': # if run as a script or by 'python -m pytest' raise SystemExit(main()) else: From noreply at buildbot.pypy.org Fri Jul 1 01:15:53 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 1 Jul 2011 01:15:53 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: rtyper fixes Message-ID: <20110630231553.C433282936@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45200:7d28278c1f7d Date: 2011-06-30 10:40 -0700 http://bitbucket.org/pypy/pypy/changeset/7d28278c1f7d/ Log: rtyper fixes diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -341,7 +341,7 @@ pymethod_name = helper.map_operator_name( method_name, capi.c_method_num_args(self.handle, i), capi.charp2str_free(capi.c_method_result_type(self.handle, i))) - if not self.methods.has_key(pymethod_name): + if not pymethod_name in self.methods: cppfunction = self._make_cppfunction(i) overload = args_temp.setdefault(pymethod_name, []) overload.append(cppfunction) @@ -406,7 +406,7 @@ num_data_members = capi.c_num_data_members(self.handle) for i in range(num_data_members): data_member_name = capi.charp2str_free(capi.c_data_member_name(self.handle, i)) - if not self.data_members.has_key(data_member_name): + if not data_member_name in self.data_members: type_name = capi.charp2str_free(capi.c_data_member_type(self.handle, i)) offset = capi.c_data_member_offset(self.handle, i) data_member = W_CPPStaticDataMember(self.space, type_name, offset) From noreply at buildbot.pypy.org Fri Jul 1 01:15:55 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 1 Jul 2011 01:15:55 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: offsets for calling base classes Message-ID: <20110630231555.0C29382936@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45201:e58b8f224098 Date: 2011-06-30 13:20 -0700 http://bitbucket.org/pypy/pypy/changeset/e58b8f224098/ Log: offsets for calling base classes diff --git a/pypy/module/cppyy/capi.py b/pypy/module/cppyy/capi.py --- a/pypy/module/cppyy/capi.py +++ b/pypy/module/cppyy/capi.py @@ -78,6 +78,10 @@ "cppyy_is_subtype", [C_TYPEHANDLE, C_TYPEHANDLE], rffi.INT, compilation_info=eci) +c_base_offset = rffi.llexternal( + "cppyy_base_offset", + [C_TYPEHANDLE, C_TYPEHANDLE], rffi.SIZE_T, + compilation_info=eci) c_call_v = rffi.llexternal( @@ -168,7 +172,7 @@ compilation_info=eci) c_data_member_offset = rffi.llexternal( "cppyy_data_member_offset", - [C_TYPEHANDLE, rffi.INT], rffi.INT, + [C_TYPEHANDLE, rffi.INT], rffi.SIZE_T, compilation_info=eci) c_is_staticdata = rffi.llexternal( diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -357,7 +357,10 @@ obj = space.interpclass_w(w_obj) if isinstance(obj, W_CPPInstance): if capi.c_is_subtype(obj.cppclass.handle, self.cpptype.handle): - return obj.rawobject + offset = capi.c_base_offset(obj.cppclass.handle, self.cpptype.handle) + obj_address = lltype.direct_ptradd(obj.rawobject, offset) + objptr = rffi.cast(rffi.CCHARP, obj_address) + return objptr raise OperationError(space.w_TypeError, space.wrap("cannot pass %s as %s" % ( space.type(w_obj).getname(space, "?"), diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/reflexcwrapper.h --- a/pypy/module/cppyy/include/reflexcwrapper.h +++ b/pypy/module/cppyy/include/reflexcwrapper.h @@ -36,7 +36,8 @@ char* cppyy_final_name(cppyy_typehandle_t handle); int cppyy_num_bases(cppyy_typehandle_t handle); char* cppyy_base_name(cppyy_typehandle_t handle, int base_index); - int cppyy_is_subtype(cppyy_typehandle_t h1, cppyy_typehandle_t h2); + int cppyy_is_subtype(cppyy_typehandle_t dh, cppyy_typehandle_t bh); + size_t cppyy_base_offset(cppyy_typehandle_t dh, cppyy_typehandle_t bh); /* method/function reflection information */ int cppyy_num_methods(cppyy_typehandle_t handle); diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx --- a/pypy/module/cppyy/src/reflexcwrapper.cxx +++ b/pypy/module/cppyy/src/reflexcwrapper.cxx @@ -21,6 +21,36 @@ return Reflex::Scope((Reflex::ScopeName*)handle); } +static inline size_t base_offset(const Reflex::Type& td, const Reflex::Type& tb) { + // when dealing with virtual inheritance the only (reasonably) well-defined info is + // in a Reflex internal base table, that contains all offsets within the hierarchy + Reflex::Member getbases = td.FunctionMemberByName( + "__getBasesTable", Reflex::Type(), 0, Reflex::INHERITEDMEMBERS_NO, Reflex::DELAYEDLOAD_OFF); + if (getbases) { + typedef std::vector > Bases_t; + Bases_t* bases; + Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases); + getbases.Invoke(&bases_holder); + + for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) { + if (ibase->first.ToType() == tb) { + if (ibase->first.IsVirtual()) { + Reflex::Object o = td.Construct(); + size_t offset = ibase->first.Offset(o.Address()); + o.Destruct(); + return offset; + } else + return ibase->first.Offset(0); + } + } + + // contrary to typical invoke()s, the result of the internal getbases function + // is a pointer to a function static, so no delete + } + + return 0; +} + /* name to handle --------------------------------------------------------- */ cppyy_typehandle_t cppyy_get_typehandle(const char* class_name) { @@ -171,12 +201,20 @@ return cppstring_to_cstring(name); } -int cppyy_is_subtype(cppyy_typehandle_t h1, cppyy_typehandle_t h2) { - if (h1 == h2) +int cppyy_is_subtype(cppyy_typehandle_t dh, cppyy_typehandle_t bh) { + if (dh == bh) return 1; - Reflex::Type t1 = type_from_handle(h1); - Reflex::Type t2 = type_from_handle(h2); - return (int)t2.HasBase(t1); + Reflex::Type td = type_from_handle(dh); + Reflex::Type tb = type_from_handle(bh); + return (int)td.HasBase(tb); +} + +size_t cppyy_base_offset(cppyy_typehandle_t dh, cppyy_typehandle_t bh) { + if (dh == bh) + return 0; + Reflex::Type td = type_from_handle(dh); + Reflex::Type tb = type_from_handle(bh); + return base_offset(td, tb); } @@ -265,34 +303,8 @@ if (s != m.DeclaringScope()) { // in case this data member is part of a base class, the offset is complicated - // when dealing with virtual inheritance and only (reasonably) well-defined with a - // Reflex internal base table, that contains all offsets within the full hierarchy - Reflex::Member getbases = s.FunctionMemberByName( - "__getBasesTable", Reflex::Type(), 0, Reflex::INHERITEDMEMBERS_NO, Reflex::DELAYEDLOAD_OFF); - if (getbases) { - typedef std::vector > Bases_t; - Bases_t* bases; - Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases); - getbases.Invoke(&bases_holder); - - Reflex::Type d = m.DeclaringType(); - - for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) { - if (ibase->first.ToType() == d) { - if (d.IsVirtual()) { - Reflex::Type t = type_from_handle(handle); - Reflex::Object o = t.Construct(); - size_t offset = ibase->first.Offset(o.Address()) + m.Offset(); - o.Destruct(); - return offset; - } else - return ibase->first.Offset(0); - } - } - - // contrary to typical invoke()s, the result of the internal getbases function - // is a pointer to a function static, so no delete - } + // when dealing with virtual inheritance and needs to be calculated + return base_offset(s, m.DeclaringType()) + m.Offset(); } return m.Offset(); diff --git a/pypy/module/cppyy/test/advancedcpp.xml b/pypy/module/cppyy/test/advancedcpp.xml --- a/pypy/module/cppyy/test/advancedcpp.xml +++ b/pypy/module/cppyy/test/advancedcpp.xml @@ -12,6 +12,8 @@ + + diff --git a/pypy/module/cppyy/test/test_advancedcpp.py b/pypy/module/cppyy/test/test_advancedcpp.py --- a/pypy/module/cppyy/test/test_advancedcpp.py +++ b/pypy/module/cppyy/test/test_advancedcpp.py @@ -23,7 +23,7 @@ import cppyy return cppyy.load_lib(%r)""" % (shared_lib, )) - def test01_default_argeumetns(self): + def test01_default_arguments(self): """Test usage of default arguments""" import cppyy @@ -277,3 +277,36 @@ # assert d.get_value() == 44 d.destruct() + + def test07_pass_by_reference(self): + """Test reference passing when using virtual inheritance""" + + import cppyy + gbl = cppyy.gbl + b_class = gbl.b_class + c_class = gbl.c_class_2 + d_class = gbl.d_class + + #----- + b = b_class() + b.m_a, b.m_b = 11, 22 + assert gbl.get_a(b) == 11 + assert gbl.get_b(b) == 22 + b.destruct() + + #----- + c = c_class() + c.m_a, c.m_b, c.m_c = 11, 22, 33 + assert gbl.get_a(c) == 11 + assert gbl.get_b(c) == 22 + assert gbl.get_c(c) == 33 + c.destruct() + + #----- + d = d_class() + d.m_a, d.m_b, d.m_c, d.m_d = 11, 22, 33, 44 + assert gbl.get_a(d) == 11 + assert gbl.get_b(d) == 22 + assert gbl.get_c(d) == 33 + assert gbl.get_d(d) == 44 + d.destruct() From noreply at buildbot.pypy.org Fri Jul 1 01:15:56 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 1 Jul 2011 01:15:56 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: rtyper fixes and initial attempt at class type data members Message-ID: <20110630231556.4C00C82936@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45202:af95ab4c411e Date: 2011-06-30 15:40 -0700 http://bitbucket.org/pypy/pypy/changeset/af95ab4c411e/ Log: rtyper fixes and initial attempt at class type data members diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -1,4 +1,5 @@ import sys + from pypy.interpreter.error import OperationError from pypy.interpreter.buffer import Buffer from pypy.rpython.lltypesystem import rffi, lltype @@ -359,7 +360,7 @@ if capi.c_is_subtype(obj.cppclass.handle, self.cpptype.handle): offset = capi.c_base_offset(obj.cppclass.handle, self.cpptype.handle) obj_address = lltype.direct_ptradd(obj.rawobject, offset) - objptr = rffi.cast(rffi.CCHARP, obj_address) + objptr = rffi.cast(rffi.VOIDP, obj_address) return objptr raise OperationError(space.w_TypeError, space.wrap("cannot pass %s as %s" % ( @@ -368,7 +369,19 @@ def free_argument(self, arg): pass - + +class InstanceConverter(InstancePtrConverter): + _immutable_ = True + + def from_memory(self, space, w_obj, offset): + address = self._get_raw_address(space, w_obj, offset) + obj_address = rffi.cast(rffi.VOIDP, address) + from pypy.module.cppyy import interp_cppyy + return interp_cppyy.W_CPPInstance(space, self.cpptype, obj_address) + + def free_argument(self, arg): + pass + def get_converter(space, name): from pypy.module.cppyy import interp_cppyy @@ -380,6 +393,8 @@ # 5) generalized cases (covers basically all user classes) # 6) void converter, which fails on use + from pypy.module.cppyy import interp_cppyy + # 1) full, exact match try: return _converters[name](space, -1) @@ -405,12 +420,14 @@ # 5) generalized cases (covers basically all user classes) cpptype = interp_cppyy.type_byname(space, clean_name) - - if cpptype and (compound == "*" or compound == "&"): + if cpptype: # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPType cpptype = space.interp_w(W_CPPType, cpptype, can_be_None=False) - return InstancePtrConverter(space, cpptype) + if compound == "*" or compound == "&": + return InstancePtrConverter(space, cpptype) + elif compound == "": + return InstanceConverter(space, cpptype) # 6) void converter, which fails on use # diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -1,7 +1,6 @@ import sys from pypy.interpreter.error import OperationError - from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib import libffi @@ -203,7 +202,7 @@ # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPType cpptype = space.interp_w(W_CPPType, cpptype, can_be_None=False) - if (compound == "*" or compound == "&"): + if compound == "*" or compound == "&": return InstancePtrExecutor(space, clean_name, cpptype) elif compound == "": return InstanceExecutor(space, clean_name, cpptype) diff --git a/pypy/module/cppyy/test/test_advancedcpp.py b/pypy/module/cppyy/test/test_advancedcpp.py --- a/pypy/module/cppyy/test/test_advancedcpp.py +++ b/pypy/module/cppyy/test/test_advancedcpp.py @@ -147,6 +147,7 @@ assert gbl.T1(int) is gbl.T1('int') assert gbl.T2('T1') is gbl.T2('T1') assert gbl.T2(gbl.T1('int')) is gbl.T2('T1') + assert gbl.T2(gbl.T1(int)) is gbl.T2('T1') assert gbl.T3('int,double') is gbl.T3('int,double') assert gbl.T3('int', 'double') is gbl.T3('int,double') assert gbl.T3(int, 'double') is gbl.T3('int,double') @@ -157,18 +158,28 @@ assert gbl.a_ns.T4('a_ns::T4 >')\ is gbl.a_ns.T4(gbl.a_ns.T4(gbl.T3(int, 'double'))) + #----- t1 = gbl.T1(int)() assert t1.m_t1 == 1 assert t1.value() == 1 t1.destruct() + #----- t1 = gbl.T1(int)(11) assert t1.m_t1 == 11 assert t1.value() == 11 t1.m_t1 = 111 assert t1.value() == 111 + assert t1.m_t1 == 111 t1.destruct() + #----- + t2 = gbl.T2(gbl.T1(int))(gbl.T1(int)(32)) +# t2.m_t2.m_t1 = 32 +# assert t2.m_t2.value() == 32 +# assert t2.m_t2.m_t1 == 32 + t2.destruct() + def test05_abstract_classes(self): """Test non-instatiatability of abstract classes""" From noreply at buildbot.pypy.org Fri Jul 1 01:55:57 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 1 Jul 2011 01:55:57 +0200 (CEST) Subject: [pypy-commit] pypy default: Allow inlining into cStringIO, and make Unpickler a new-style class. Message-ID: <20110630235557.05BEA82936@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45203:00b076fd4b52 Date: 2011-06-30 17:02 -0700 http://bitbucket.org/pypy/pypy/changeset/00b076fd4b52/ Log: Allow inlining into cStringIO, and make Unpickler a new-style class. diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -15,7 +15,7 @@ if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', 'posix', '_socket', '_sre', '_lsprof', '_weakref', - '__pypy__']: + '__pypy__', 'cStringIO']: return True return False From noreply at buildbot.pypy.org Fri Jul 1 01:55:58 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 1 Jul 2011 01:55:58 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20110630235558.4013682936@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45204:6bca4ed0f817 Date: 2011-06-30 17:02 -0700 http://bitbucket.org/pypy/pypy/changeset/6bca4ed0f817/ Log: merged upstream diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -845,11 +845,13 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 base = entries[0].f_hash else: base = global_popitem_index.nextindex @@ -865,7 +867,11 @@ entries[0].f_hash = base + counter else: global_popitem_index.nextindex = base + counter - entry = entries[i] + return i + +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) From noreply at buildbot.pypy.org Fri Jul 1 02:14:09 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 1 Jul 2011 02:14:09 +0200 (CEST) Subject: [pypy-commit] pypy default: Don't look inside ll_popitem, it requires getinteriorfield in the JIT. Message-ID: <20110701001409.6EADC82936@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45205:5da5234186ef Date: 2011-06-30 17:21 -0700 http://bitbucket.org/pypy/pypy/changeset/5da5234186ef/ Log: Don't look inside ll_popitem, it requires getinteriorfield in the JIT. diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -869,6 +869,7 @@ global_popitem_index.nextindex = base + counter return i + at jit.dont_look_inside def ll_popitem(ELEM, dic): i = _ll_getnextitem(dic) entry = dic.entries[i] From noreply at buildbot.pypy.org Fri Jul 1 08:44:56 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 1 Jul 2011 08:44:56 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: enable all pure operations in short preamble Message-ID: <20110701064456.E651D82936@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45206:f46d3a44611f Date: 2011-06-29 20:36 +0200 http://bitbucket.org/pypy/pypy/changeset/f46d3a44611f/ Log: enable all pure operations in short preamble diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -420,8 +420,7 @@ def produce_potential_short_preamble_ops(self, potential_ops): for op in self.emitted_pure_operations: - if op.is_always_pure(): - potential_ops[op.result] = op + potential_ops[op.result] = op for opt in self.optimizations: opt.produce_potential_short_preamble_ops(potential_ops) From noreply at buildbot.pypy.org Fri Jul 1 08:44:58 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 1 Jul 2011 08:44:58 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: hg revert -r 45027 optimizeopt/heap.py Message-ID: <20110701064458.326D282936@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45207:3af4b2b1b960 Date: 2011-06-30 19:13 +0200 http://bitbucket.org/pypy/pypy/changeset/3af4b2b1b960/ Log: hg revert -r 45027 optimizeopt/heap.py diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.history import ConstInt, Const + class CachedField(object): def __init__(self): @@ -23,7 +23,6 @@ # 'cached_fields'. # self._cached_fields = {} - self._cached_fields_getfield_op = {} self._lazy_setfield = None self._lazy_setfield_registered = False @@ -70,10 +69,9 @@ else: return self._cached_fields.get(structvalue, None) - def remember_field_value(self, structvalue, fieldvalue, getfield_op=None): + def remember_field_value(self, structvalue, fieldvalue): assert self._lazy_setfield is None self._cached_fields[structvalue] = fieldvalue - self._cached_fields_getfield_op[structvalue] = getfield_op def force_lazy_setfield(self, optheap): op = self._lazy_setfield @@ -83,7 +81,6 @@ # setfield might impact any of the stored result (because of # possible aliasing). self._cached_fields.clear() - self._cached_fields_getfield_op.clear() self._lazy_setfield = None optheap.next_optimization.propagate_forward(op) # Once it is done, we can put at least one piece of information @@ -93,32 +90,21 @@ fieldvalue = optheap.getvalue(op.getarg(1)) self.remember_field_value(structvalue, fieldvalue) - def get_cloned(self, optimizer, valuemap, short_boxes): + def get_reconstructed(self, optimizer, valuemap): assert self._lazy_setfield is None cf = CachedField() for structvalue, fieldvalue in self._cached_fields.iteritems(): - op = self._cached_fields_getfield_op.get(structvalue, None) - if op and op.result in short_boxes and short_boxes[op.result] is op: - structvalue2 = structvalue.get_cloned(optimizer, valuemap) - fieldvalue2 = fieldvalue .get_cloned(optimizer, valuemap) - cf._cached_fields[structvalue2] = fieldvalue2 + structvalue2 = structvalue.get_reconstructed(optimizer, valuemap) + fieldvalue2 = fieldvalue .get_reconstructed(optimizer, valuemap) + cf._cached_fields[structvalue2] = fieldvalue2 return cf - def produce_potential_short_preamble_ops(self, optimizer, - potential_ops, descr): - if self._lazy_setfield is not None: - return - for structvalue, op in self._cached_fields_getfield_op.iteritems(): - if op and structvalue in self._cached_fields: - potential_ops[op.result] = op class CachedArrayItems(object): def __init__(self): self.fixed_index_items = {} - self.fixed_index_getops = {} self.var_index_item = None self.var_index_indexvalue = None - self.var_index_getop = None class BogusPureField(JitException): pass @@ -133,23 +119,19 @@ self._lazy_setfields = [] # cached array items: {descr: CachedArrayItems} self.cached_arrayitems = {} - self.original_producer = {} self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False - def force_at_end_of_preamble(self): - self.force_all_lazy_setfields() - - def flush(self): - self.force_all_lazy_setfields() - - def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, - optimizer, valuemap): + def reconstruct_for_next_iteration(self, optimizer, valuemap): new = OptHeap() + if True: + self.force_all_lazy_setfields() + else: + assert 0 # was: new.lazy_setfields = self.lazy_setfields + for descr, d in self.cached_fields.items(): - new.cached_fields[descr] = d.get_cloned(optimizer, valuemap, short_boxes) - return new + new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) new.cached_arrayitems = {} for descr, d in self.cached_arrayitems.items(): @@ -157,41 +139,19 @@ new.cached_arrayitems[descr] = newd for value, cache in d.items(): newcache = CachedArrayItems() - newd[value.get_cloned(optimizer, valuemap)] = newcache - if cache.var_index_getop and cache.var_index_getop.result in short_boxes: - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_cloned(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_cloned(optimizer, - valuemap) + newd[value.get_reconstructed(optimizer, valuemap)] = newcache + if cache.var_index_item: + newcache.var_index_item = \ + cache.var_index_item.get_reconstructed(optimizer, valuemap) + if cache.var_index_indexvalue: + newcache.var_index_indexvalue = \ + cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) for index, fieldvalue in cache.fixed_index_items.items(): - op = cache.fixed_index_getops.get(index, None) - if op and op.result in short_boxes: - newcache.fixed_index_items[index] = \ - fieldvalue.get_cloned(optimizer, valuemap) + newcache.fixed_index_items[index] = \ + fieldvalue.get_reconstructed(optimizer, valuemap) return new - def produce_potential_short_preamble_ops(self, potential_ops): - for descr, d in self.cached_fields.items(): - d.produce_potential_short_preamble_ops(self.optimizer, - potential_ops, descr) - return - - for descr, d in self.cached_arrayitems.items(): - for value, cache in d.items(): - for index in cache.fixed_index_items.keys(): - op = cache.fixed_index_getops[index] - if op: - potential_ops[op.result] = op - if cache.var_index_item and cache.var_index_indexvalue: - op = cache.var_index_getop - if op: - potential_ops[op.result] = op - - def clean_caches(self): del self._lazy_setfields[:] self.cached_fields.clear() @@ -204,8 +164,7 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, - write=False, getop=None): + def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): d = self.cached_arrayitems.get(descr, None) if d is None: d = self.cached_arrayitems[descr] = {} @@ -223,11 +182,9 @@ othercache.var_index_item = None try: del othercache.fixed_index_items[index] - del othercache.fixed_index_getops[index] except KeyError: pass cache.fixed_index_items[index] = fieldvalue - cache.fixed_index_getops[index] = getop else: if write: for value, othercache in d.iteritems(): @@ -235,10 +192,8 @@ othercache.var_index_indexvalue = None othercache.var_index_item = None othercache.fixed_index_items.clear() - othercache.fixed_index_getops.clear() cache.var_index_indexvalue = indexvalue cache.var_index_item = fieldvalue - cache.var_index_getop = getop def read_cached_arrayitem(self, descr, value, indexvalue): d = self.cached_arrayitems.get(descr, None) @@ -298,7 +253,6 @@ try: cf = self.cached_fields[fielddescr] cf._cached_fields.clear() - cf._cached_fields_getfield_op.clear() except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: @@ -322,14 +276,7 @@ if value is not newvalue: for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: - if newvalue not in cf._cached_fields: - cf._cached_fields[newvalue] = cf._cached_fields[value] - op = cf._cached_fields_getfield_op[value].clone() - constbox = value.box - assert isinstance(constbox, Const) - op.setarg(0, constbox) - cf._cached_fields_getfield_op[newvalue] = op - + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -397,14 +344,14 @@ fieldvalue = cf.getfield_from_cache(self, structvalue) if fieldvalue is not None: self.make_equal_to(op.result, fieldvalue) - else: - # default case: produce the operation - structvalue.ensure_nonnull() - ###self.optimizer.optimize_default(op) - self.emit_operation(op) - # then remember the result of reading the field - fieldvalue = self.getvalue(op.result) - cf.remember_field_value(structvalue, fieldvalue, op) + return + # default case: produce the operation + structvalue.ensure_nonnull() + ###self.optimizer.optimize_default(op) + self.emit_operation(op) + # then remember the result of reading the field + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(structvalue, fieldvalue) def optimize_SETFIELD_GC(self, op): if self.has_pure_result(rop.GETFIELD_GC_PURE, [op.getarg(0)], @@ -426,8 +373,7 @@ ###self.optimizer.optimize_default(op) self.emit_operation(op) fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - getop=op) + self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): self.emit_operation(op) From noreply at buildbot.pypy.org Fri Jul 1 08:45:00 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 1 Jul 2011 08:45:00 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: hg merge default Message-ID: <20110701064500.283ED82936@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45208:f9ee4e34b791 Date: 2011-06-30 19:26 +0200 http://bitbucket.org/pypy/pypy/changeset/f9ee4e34b791/ Log: hg merge default diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,14 +4399,8 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) - self.assertTrue(l.__add__.im_class is list) + self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__objclass__ is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -299,12 +299,13 @@ listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -131,6 +131,18 @@ finder, which is nicely portable. So far it gives a pypy that is around 7% slower.) +Embedding PyPy +---------------------------------------- + +Being able to embed PyPy, say with its own limited C API, would be +useful. But here is the most interesting variant, straight from +EuroPython live discussion :-) We can have a generic "libpypy.so" that +can be used as a placeholder dynamic library, and when it gets loaded, +it runs a .py module that installs (via ctypes) the interface it wants +exported. This would give us a one-size-fits-all generic .so file to be +imported by any application that wants to load .so files :-) + + .. _`issue tracker`: http://bugs.pypy.org .. _`mailing list`: http://mail.python.org/mailman/listinfo/pypy-dev .. _`jitviewer`: http://bitbucket.org/pypy/jitviewer diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -134,7 +134,7 @@ def accept_comp_iteration(self, codegen, index): self.elt.walkabout(codegen) - codegen.emit_op_arg(ops.SET_ADD, index) + codegen.emit_op_arg(ops.SET_ADD, index + 1) class __extend__(ast.DictComp): @@ -148,7 +148,7 @@ def accept_comp_iteration(self, codegen, index): self.value.walkabout(codegen) self.key.walkabout(codegen) - codegen.emit_op_arg(ops.MAP_ADD, index) + codegen.emit_op_arg(ops.MAP_ADD, index + 1) # These are frame blocks. diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -92,7 +92,10 @@ return name if len(name) + 2 >= MANGLE_LEN: return name - if name.endswith('__'): + # Don't mangle __id__ or names with dots. The only time a name with a dot + # can occur is when we are compiling an import statement that has a package + # name. + if name.endswith('__') or '.' in name: return name try: i = 0 diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -308,6 +308,15 @@ "p.__name__", os.path.__name__) yield (self.st, 'from os import *', "path.__name__, sep", (os.path.__name__, os.sep)) + yield (self.st, ''' + class A(object): + def m(self): + from __foo__.bar import x + try: + A().m() + except ImportError, e: + msg = str(e) + ''', "msg", "No module named __foo__") def test_if_stmts(self): yield self.st, "a = 42\nif a > 10: a += 2", "a", 44 diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -100,12 +100,12 @@ @jit.dont_look_inside def fast2locals(self): - # Copy values from self.fastlocals_w to self.w_locals + # Copy values from the fastlocals to self.w_locals if self.w_locals is None: self.w_locals = self.space.newdict() varnames = self.getcode().getvarnames() fastscope_w = self.getfastscope() - for i in range(min(len(varnames), len(fastscope_w))): + for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] if w_value is not None: @@ -114,7 +114,7 @@ @jit.dont_look_inside def locals2fast(self): - # Copy values from self.w_locals to self.fastlocals_w + # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None varnames = self.getcode().getvarnames() numlocals = self.getfastscopelength() diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -98,7 +98,7 @@ self.closure) for i in funccallunrolling: if i < nargs: - new_frame.fastlocals_w[i] = args_w[i] + new_frame.locals_stack_w[i] = args_w[i] return new_frame.run() elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1: assert isinstance(code, gateway.BuiltinCodePassThroughArguments1) @@ -158,7 +158,7 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg return new_frame.run() @@ -169,13 +169,13 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = self.defs_w[j] + new_frame.locals_stack_w[i] = self.defs_w[j] i += 1 return new_frame.run() diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -170,7 +170,7 @@ for i in range(len(args_to_copy)): argnum = args_to_copy[i] if argnum >= 0: - self.cells[i].set(self.fastlocals_w[argnum]) + self.cells[i].set(self.locals_stack_w[argnum]) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -63,6 +63,7 @@ the pypy compiler""" self.space = space eval.Code.__init__(self, name) + assert nlocals >= 0 self.co_argcount = argcount self.co_nlocals = nlocals self.co_stacksize = stacksize @@ -202,7 +203,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -215,7 +216,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -9,7 +9,7 @@ from pypy.interpreter import pytraceback from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib.jit import hint -from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.debug import make_sure_not_resized, check_nonneg from pypy.rlib.rarithmetic import intmask from pypy.rlib import jit from pypy.tool import stdlib_opcode @@ -56,16 +56,18 @@ assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals) - self.valuestack_w = [None] * code.co_stacksize - self.valuestackdepth = 0 + self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize) + self.nlocals = code.co_nlocals + self.valuestackdepth = code.co_nlocals self.lastblock = None + make_sure_not_resized(self.locals_stack_w) + check_nonneg(self.nlocals) + # if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure, code) - self.fastlocals_w = [None] * code.co_nlocals - make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno def mark_as_escaped(self): @@ -184,14 +186,14 @@ # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth - self.valuestack_w[depth] = w_object + self.locals_stack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 - assert depth >= 0, "pop from empty value stack" - w_object = self.valuestack_w[depth] - self.valuestack_w[depth] = None + assert depth >= self.nlocals, "pop from empty value stack" + w_object = self.locals_stack_w[depth] + self.locals_stack_w[depth] = None self.valuestackdepth = depth return w_object @@ -217,24 +219,24 @@ def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n - assert base >= 0 + assert base >= self.nlocals while True: n -= 1 if n < 0: break - values_w[n] = self.valuestack_w[base+n] + values_w[n] = self.locals_stack_w[base+n] return values_w @jit.unroll_safe def dropvalues(self, n): n = hint(n, promote=True) finaldepth = self.valuestackdepth - n - assert finaldepth >= 0, "stack underflow in dropvalues()" + assert finaldepth >= self.nlocals, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break - self.valuestack_w[finaldepth+n] = None + self.locals_stack_w[finaldepth+n] = None self.valuestackdepth = finaldepth @jit.unroll_safe @@ -261,30 +263,30 @@ # Contrast this with CPython where it's PEEK(-1). index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "peek past the bottom of the stack" - return self.valuestack_w[index] + assert index >= self.nlocals, "peek past the bottom of the stack" + return self.locals_stack_w[index] def settopvalue(self, w_object, index_from_top=0): index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "settop past the bottom of the stack" - self.valuestack_w[index] = w_object + assert index >= self.nlocals, "settop past the bottom of the stack" + self.locals_stack_w[index] = w_object @jit.unroll_safe def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 finaldepth = hint(finaldepth, promote=True) while depth >= finaldepth: - self.valuestack_w[depth] = None + self.locals_stack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth - def savevaluestack(self): - return self.valuestack_w[:self.valuestackdepth] + def save_locals_stack(self): + return self.locals_stack_w[:self.valuestackdepth] - def restorevaluestack(self, items_w): - assert None not in items_w - self.valuestack_w[:len(items_w)] = items_w + def restore_locals_stack(self, items_w): + self.locals_stack_w[:len(items_w)] = items_w + self.init_cells() self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): @@ -314,11 +316,12 @@ else: f_lineno = self.f_lineno - values_w = self.valuestack_w[0:self.valuestackdepth] + values_w = self.locals_stack_w[self.nlocals:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) - w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) + w_fastlocals = maker.slp_into_tuple_with_nulls( + space, self.locals_stack_w[:self.nlocals]) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None @@ -399,7 +402,8 @@ new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) - new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None @@ -423,28 +427,28 @@ @jit.dont_look_inside def getfastscope(self): "Get the fast locals as a list." - return self.fastlocals_w + return self.locals_stack_w @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) - if scope_len > len(self.fastlocals_w): + if scope_len > self.nlocals: raise ValueError, "new fastscope is longer than the allocated area" - # don't assign directly to 'fastlocals_w[:scope_len]' to be + # don't assign directly to 'locals_stack_w[:scope_len]' to be # virtualizable-friendly for i in range(scope_len): - self.fastlocals_w[i] = scope_w[i] + self.locals_stack_w[i] = scope_w[i] self.init_cells() def init_cells(self): - """Initialize cellvars from self.fastlocals_w + """Initialize cellvars from self.locals_stack_w. This is overridden in nestedscope.py""" pass def getfastscopelength(self): - return self.pycode.co_nlocals + return self.nlocals def getclosure(self): return None diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -324,7 +324,7 @@ def LOAD_FAST(self, varindex, next_instr): # access a local variable directly - w_value = self.fastlocals_w[varindex] + w_value = self.locals_stack_w[varindex] if w_value is None: self._load_fast_failed(varindex) self.pushvalue(w_value) @@ -343,7 +343,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self.fastlocals_w[varindex] = w_newvalue + self.locals_stack_w[varindex] = w_newvalue def POP_TOP(self, oparg, next_instr): self.popvalue() @@ -696,12 +696,12 @@ LOAD_GLOBAL._always_inline_ = True def DELETE_FAST(self, varindex, next_instr): - if self.fastlocals_w[varindex] is None: + if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise operationerrfmt(self.space.w_UnboundLocalError, message, varname) - self.fastlocals_w[varindex] = None + self.locals_stack_w[varindex] = None def BUILD_TUPLE(self, itemcount, next_instr): items = self.popvalues(itemcount) @@ -1048,13 +1048,13 @@ def SET_ADD(self, oparg, next_instr): w_value = self.popvalue() - w_set = self.peekvalue(oparg) + w_set = self.peekvalue(oparg - 1) self.space.call_method(w_set, 'add', w_value) def MAP_ADD(self, oparg, next_instr): w_key = self.popvalue() w_value = self.popvalue() - w_dict = self.peekvalue(oparg) + w_dict = self.peekvalue(oparg - 1) self.space.setitem(w_dict, w_key, w_value) def SET_LINENO(self, lineno, next_instr): @@ -1091,12 +1091,10 @@ @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): - w_set = self.space.call_function(self.space.w_set) - if itemcount: - w_add = self.space.getattr(w_set, self.space.wrap("add")) - for i in range(itemcount): - w_item = self.popvalue() - self.space.call_function(w_add, w_item) + w_set = self.space.newset() + for i in range(itemcount): + w_item = self.popvalue() + self.space.call_method(w_set, 'add', w_item) self.pushvalue(w_set) def STORE_MAP(self, oparg, next_instr): diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py --- a/pypy/interpreter/test/test_eval.py +++ b/pypy/interpreter/test/test_eval.py @@ -15,16 +15,16 @@ self.code = code Frame.__init__(self, space) self.numlocals = numlocals - self.fastlocals_w = [None] * self.numlocals + self._fastlocals_w = [None] * self.numlocals def getcode(self): return self.code def setfastscope(self, scope_w): - self.fastlocals_w = scope_w + self._fastlocals_w = scope_w def getfastscope(self): - return self.fastlocals_w + return self._fastlocals_w def getfastscopelength(self): return self.numlocals @@ -38,11 +38,11 @@ self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({})) - self.f.fastlocals_w[0] = w(5) + self.f._fastlocals_w[0] = w(5) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5})) - self.f.fastlocals_w[2] = w(7) + self.f._fastlocals_w[2] = w(7) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5, 'args': 7})) @@ -57,13 +57,13 @@ w = self.space.wrap self.f.w_locals = self.space.wrap({}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [None]*5) + self.sameList(self.f._fastlocals_w, [None]*5) self.f.w_locals = self.space.wrap({'x': 5}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) + self.sameList(self.f._fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.wrap({'x':5, 'args':7}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), None, w(7), - None, None]) + self.sameList(self.f._fastlocals_w, [w(5), None, w(7), + None, None]) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -203,3 +203,26 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + import sys + class A(object): + def m(self): + "aaa" + m.x = 3 + + bm = A().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.im_class is A + if '__pypy__' in sys.builtin_module_names: + assert bm.__objclass__ is A + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + if '__pypy__' in sys.builtin_module_names: + assert l.append.__objclass__ is list + assert l.__add__.__self__ is l + assert l.__add__.__objclass__ is list diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -761,13 +761,17 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), + __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -703,22 +703,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: @@ -889,7 +895,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -901,7 +907,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -467,13 +469,13 @@ # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,6 +185,13 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -75,12 +75,13 @@ # OS_MATH_SQRT = 100 - def __new__(cls, readonly_descrs_fields, + def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, can_invalidate=False): key = (frozenset(readonly_descrs_fields), + frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, @@ -89,6 +90,7 @@ return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields + result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ extraeffect == EffectInfo.EF_PURE: result.write_descrs_fields = [] @@ -119,7 +121,7 @@ if effects is top_set: return None readonly_descrs_fields = [] - # readonly_descrs_arrays = [] --- not enabled for now + readonly_descrs_arrays = [] write_descrs_fields = [] write_descrs_arrays = [] @@ -145,10 +147,13 @@ elif tup[0] == "array": add_array(write_descrs_arrays, tup) elif tup[0] == "readarray": - pass + tupw = ("array",) + tup[1:] + if tupw not in effects: + add_array(readonly_descrs_arrays, tup) else: assert 0 return EffectInfo(readonly_descrs_fields, + readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect, diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -44,10 +44,6 @@ return True if mod.startswith('pypy.translator.'): # XXX wtf? return True - # string builder interface - if mod == 'pypy.rpython.lltypesystem.rbuilder': - return True - return False def look_inside_graph(self, graph): diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -34,6 +34,15 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays +def test_include_read_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo.write_descrs_fields + assert not effectinfo.write_descrs_arrays + def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) @@ -51,6 +60,16 @@ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.write_descrs_arrays +def test_dont_include_read_and_write_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A)), + ("array", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert not effectinfo.readonly_descrs_arrays + assert not effectinfo.write_descrs_fields + assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLException diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -15,7 +15,7 @@ from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.jit.metainterp.optimize import InvalidLoop -from pypy.jit.metainterp.resume import NUMBERING +from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong def giveup(): @@ -119,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -302,7 +303,7 @@ rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) CNT_INT = -0x20000000 CNT_REF = -0x40000000 @@ -633,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop debug_print('InvalidLoop in compile_new_bridge') diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -4,7 +4,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rlib.objectmodel import we_are_translated, r_dict, Symbolic from pypy.rlib.objectmodel import compute_unique_id -from pypy.rlib.rarithmetic import intmask, r_int64 +from pypy.rlib.rarithmetic import r_int64 from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop @@ -792,6 +792,7 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py --- a/pypy/jit/metainterp/optimize.py +++ b/pypy/jit/metainterp/optimize.py @@ -25,7 +25,6 @@ def _optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): from pypy.jit.metainterp.optimizeopt import optimize_loop_1 - cpu = metainterp_sd.cpu loop.logops = metainterp_sd.logger_noopt.log_loop(loop.inputargs, loop.operations) # XXX do we really still need a list? @@ -49,7 +48,6 @@ def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts, inline_short_preamble, retraced=False): from pypy.jit.metainterp.optimizeopt import optimize_bridge_1 - cpu = metainterp_sd.cpu bridge.logops = metainterp_sd.logger_noopt.log_loop(bridge.inputargs, bridge.operations) if old_loop_tokens: diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -8,8 +8,8 @@ class CachedField(object): def __init__(self): - # Cache information for a field descr. It can be in one - # of two states: + # Cache information for a field descr, or for an (array descr, index) + # pair. It can be in one of two states: # # 1. 'cached_fields' is a dict mapping OptValues of structs # to OptValues of fields. All fields on-heap are @@ -27,19 +27,19 @@ self._lazy_setfield_registered = False def do_setfield(self, optheap, op): - # Update the state with the SETFIELD_GC operation 'op'. + # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) if self.possible_aliasing(optheap, structvalue): self.force_lazy_setfield(optheap) assert not self.possible_aliasing(optheap, structvalue) cached_fieldvalue = self._cached_fields.get(structvalue, None) if cached_fieldvalue is not fieldvalue: # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields list + # myself in the optheap's _lazy_setfields_and_arrayitems list self._lazy_setfield = op if not self._lazy_setfield_registered: - optheap._lazy_setfields.append(self) + optheap._lazy_setfields_and_arrayitems.append(self) self._lazy_setfield_registered = True else: # this is the case where the pending setfield ends up @@ -65,7 +65,7 @@ if self._lazy_setfield is not None: op = self._lazy_setfield assert optheap.getvalue(op.getarg(0)) is structvalue - return optheap.getvalue(op.getarg(1)) + return optheap.getvalue(op.getarglist()[-1]) else: return self._cached_fields.get(structvalue, None) @@ -87,7 +87,7 @@ # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) def get_reconstructed(self, optimizer, valuemap): @@ -100,25 +100,20 @@ return cf -class CachedArrayItems(object): - def __init__(self): - self.fixed_index_items = {} - self.var_index_item = None - self.var_index_indexvalue = None - class BogusPureField(JitException): pass class OptHeap(Optimization): """Cache repeated heap accesses""" - + def __init__(self): # cached fields: {descr: CachedField} self.cached_fields = {} - self._lazy_setfields = [] - # cached array items: {descr: CachedArrayItems} + # cached array items: {array descr: {index: CachedField}} self.cached_arrayitems = {} + # + self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -126,34 +121,23 @@ new = OptHeap() if True: - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() else: assert 0 # was: new.lazy_setfields = self.lazy_setfields - + for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) - new.cached_arrayitems = {} - for descr, d in self.cached_arrayitems.items(): - newd = {} - new.cached_arrayitems[descr] = newd - for value, cache in d.items(): - newcache = CachedArrayItems() - newd[value.get_reconstructed(optimizer, valuemap)] = newcache - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_reconstructed(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) - for index, fieldvalue in cache.fixed_index_items.items(): - newcache.fixed_index_items[index] = \ - fieldvalue.get_reconstructed(optimizer, valuemap) + for descr, submap in self.cached_arrayitems.items(): + newdict = {} + for index, d in submap.items(): + newdict[index] = d.get_reconstructed(optimizer, valuemap) + new.cached_arrayitems[descr] = newdict return new def clean_caches(self): - del self._lazy_setfields[:] + del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() self.cached_arrayitems.clear() @@ -164,50 +148,16 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): - d = self.cached_arrayitems.get(descr, None) - if d is None: - d = self.cached_arrayitems[descr] = {} - cache = d.get(value, None) - if cache is None: - cache = d[value] = CachedArrayItems() - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - index = indexbox.getint() - if write: - for value, othercache in d.iteritems(): - # fixed index, clean the variable index cache, in case the - # index is the same - othercache.var_index_indexvalue = None - othercache.var_index_item = None - try: - del othercache.fixed_index_items[index] - except KeyError: - pass - cache.fixed_index_items[index] = fieldvalue - else: - if write: - for value, othercache in d.iteritems(): - # variable index, clear all caches for this descr - othercache.var_index_indexvalue = None - othercache.var_index_item = None - othercache.fixed_index_items.clear() - cache.var_index_indexvalue = indexvalue - cache.var_index_item = fieldvalue - - def read_cached_arrayitem(self, descr, value, indexvalue): - d = self.cached_arrayitems.get(descr, None) - if d is None: - return None - cache = d.get(value, None) - if cache is None: - return None - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - return cache.fixed_index_items.get(indexbox.getint(), None) - elif cache.var_index_indexvalue is indexvalue: - return cache.var_index_item - return None + def arrayitem_cache(self, descr, index): + try: + submap = self.cached_arrayitems[descr] + except KeyError: + submap = self.cached_arrayitems[descr] = {} + try: + cf = submap[index] + except KeyError: + cf = submap[index] = CachedField() + return cf def emit_operation(self, op): self.emitting_operation(op) @@ -219,7 +169,8 @@ if op.is_ovf(): return if op.is_guard(): - self.optimizer.pendingfields = self.force_lazy_setfields_for_guard() + self.optimizer.pendingfields = ( + self.force_lazy_setfields_and_arrayitems_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -248,6 +199,8 @@ # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: self.force_lazy_setfield(fielddescr) + for arraydescr in effectinfo.readonly_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: self.force_lazy_setfield(fielddescr) try: @@ -256,8 +209,11 @@ except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) try: - del self.cached_arrayitems[arraydescr] + submap = self.cached_arrayitems[arraydescr] + for cf in submap.itervalues(): + cf._cached_fields.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -266,7 +222,7 @@ # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. return - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() self.clean_caches() @@ -277,6 +233,10 @@ for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] + for submap in self.cached_arrayitems.itervalues(): + for cf in submap.itervalues(): + if value in cf._cached_fields: + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -285,6 +245,14 @@ return cf.force_lazy_setfield(self) + def force_lazy_setarrayitem(self, arraydescr): + try: + submap = self.cached_arrayitems[arraydescr] + except KeyError: + return + for cf in submap.values(): + cf.force_lazy_setfield(self) + def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes # sense to avoid a situation like "int_eq/setfield_gc/guard_true", @@ -309,30 +277,49 @@ newoperations[-2] = lastop newoperations[-1] = prevop - def force_all_lazy_setfields(self): - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + def _assert_valid_cf(self, cf): + # check that 'cf' is in cached_fields or cached_arrayitems + if not we_are_translated(): + if cf not in self.cached_fields.values(): + for submap in self.cached_arrayitems.values(): + if cf in submap.values(): + break + else: + assert 0, "'cf' not in cached_fields/cached_arrayitems" + + def force_all_lazy_setfields_and_arrayitems(self): + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) cf.force_lazy_setfield(self) - def force_lazy_setfields_for_guard(self): + def force_lazy_setfields_and_arrayitems_for_guard(self): pendingfields = [] - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) op = cf._lazy_setfield if op is None: continue # the only really interesting case that we need to handle in the # guards' resume data is that of a virtual object that is stored - # into a field of a non-virtual object. + # into a field of a non-virtual object. Here, 'op' in either + # SETFIELD_GC or SETARRAYITEM_GC. value = self.getvalue(op.getarg(0)) assert not value.is_virtual() # it must be a non-virtual - fieldvalue = self.getvalue(op.getarg(1)) + fieldvalue = self.getvalue(op.getarglist()[-1]) if fieldvalue.is_virtual(): # this is the case that we leave to resume.py + opnum = op.getopnum() + if opnum == rop.SETFIELD_GC: + itemindex = -1 + elif opnum == rop.SETARRAYITEM_GC: + indexvalue = self.getvalue(op.getarg(1)) + assert indexvalue.is_constant() + itemindex = indexvalue.box.getint() + assert itemindex >= 0 + else: + assert 0 pendingfields.append((op.getdescr(), value.box, - fieldvalue.get_key_box())) + fieldvalue.get_key_box(), itemindex)) else: cf.force_lazy_setfield(self) self.fixup_guard_situation() @@ -364,24 +351,45 @@ cf.do_setfield(self, op) def optimize_GETARRAYITEM_GC(self, op): - value = self.getvalue(op.getarg(0)) + arrayvalue = self.getvalue(op.getarg(0)) indexvalue = self.getvalue(op.getarg(1)) - fieldvalue = self.read_cached_arrayitem(op.getdescr(), value, indexvalue) - if fieldvalue is not None: - self.make_equal_to(op.result, fieldvalue) - return - ###self.optimizer.optimize_default(op) + cf = None + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + fieldvalue = cf.getfield_from_cache(self, arrayvalue) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # default case: produce the operation + arrayvalue.ensure_nonnull() self.emit_operation(op) - fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) + # the remember the result of reading the array item + if cf is not None: + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(arrayvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): - self.emit_operation(op) - value = self.getvalue(op.getarg(0)) - fieldvalue = self.getvalue(op.getarg(2)) + if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), + op.getarg(1)], + op.getdescr()): + os.write(2, '[bogus immutable array declaration: %s]\n' % + (op.getdescr().repr_of_descr())) + raise BogusPureField + # indexvalue = self.getvalue(op.getarg(1)) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - write=True) + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + cf.do_setfield(self, op) + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # and then emit the operation + self.emit_operation(op) def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 from pypy.jit.metainterp.optimizeopt.util import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -194,7 +194,7 @@ # Synthesize the reverse ops for optimize_default to reuse self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0)) self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1)) - + def optimize_INT_MUL_OVF(self, op): v1 = self.getvalue(op.getarg(0)) @@ -292,6 +292,11 @@ v1.intbound.make_ge(IntLowerBound(0)) v1.intbound.make_lt(IntUpperBound(256)) + def optimize_UNICODEGETITEM(self, op): + self.emit_operation(op) + v1 = self.getvalue(op.result) + v1.intbound.make_ge(IntLowerBound(0)) + def make_int_lt(self, box1, box2): v1 = self.getvalue(box1) v2 = self.getvalue(box2) @@ -368,6 +373,15 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -413,5 +427,6 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL + optimize_ops = _findall(OptIntBounds, 'optimize_') propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -195,6 +195,9 @@ # meaning it has been forced. return self.box is None + def is_forced_virtual(self): + return False + def getfield(self, ofs, default): raise NotImplementedError diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -232,7 +232,7 @@ break arg_consts.append(const) else: - # all constant arguments: check if we already know the reslut + # all constant arguments: check if we already know the result try: result = self.optimizer.call_pure_results[arg_consts] except KeyError: diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/string.py --- a/pypy/jit/metainterp/optimizeopt/string.py +++ b/pypy/jit/metainterp/optimizeopt/string.py @@ -348,7 +348,7 @@ optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimizer, strbox, indexbox, mode): +def _strgetitem(optimization, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimizer.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,8 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self.optimizer, - value.force_box(),vindex.force_box(), mode) + resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -121,6 +121,41 @@ print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + class BaseTestOptimizeBasic(BaseTestBasic): @@ -1070,8 +1105,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1436,9 +1471,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) jump(p1, i1, i2, p3) """ @@ -1612,6 +1647,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -1874,7 +1910,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1892,7 +1927,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1910,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2203,23 +2236,6 @@ # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2328,7 +2344,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2349,7 +2364,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2369,7 +2383,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2395,7 +2408,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2420,7 +2433,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2444,7 +2456,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2465,7 +2476,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2486,7 +2496,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2508,7 +2517,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2550,7 +2558,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2576,7 +2583,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2600,9 +2606,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2894,7 +2897,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2940,7 +2942,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2979,7 +2980,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3006,7 +3006,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -4480,6 +4479,47 @@ # not obvious, because of the exception UnicodeDecodeError that # can be raised by ll_str2unicode() + def test_strgetitem_repeated(self): + ops = """ + [p0, i0] + i1 = strgetitem(p0, i0) + i2 = strgetitem(p0, i0) + i3 = int_eq(i1, i2) + guard_true(i3) [] + escape(i2) + jump(p0, i0) + """ + expected = """ + [p0, i0] + i1 = strgetitem(p0, i0) + escape(i1) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py @@ -51,7 +51,7 @@ restype=types.sint) # def calldescr(cpu, FUNC, oopspecindex, extraeffect=None): - einfo = EffectInfo([], [], [], oopspecindex=oopspecindex, + einfo = EffectInfo([], [], [], [], oopspecindex=oopspecindex, extraeffect=extraeffect) return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo) # diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1482,8 +1482,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1926,9 +1926,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -1938,9 +1938,9 @@ # i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -2208,6 +2208,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2990,8 +2991,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -5597,7 +5596,7 @@ """ self.optimize_strunicode_loop(ops, expected, expected) - def test_strgetitem_small(self): + def test_strgetitem_bounds(self): ops = """ [p0, i0] i1 = strgetitem(p0, i0) @@ -5609,7 +5608,20 @@ """ expected = """ [p0, i0] - i1 = strgetitem(p0, i0) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_unicodegetitem_bounds(self): + ops = """ + [p0, i0] + i1 = unicodegetitem(p0, i0) + i2 = int_lt(i1, 0) + guard_false(i2) [] + jump(p0, i0) + """ + expected = """ + [p0, i0] jump(p0, i0) """ self.optimize_loop(ops, expected, expected) @@ -6183,7 +6195,7 @@ """ self.optimize_loop(ops, expected) - def test_constant_getfield1(self): + def test_constant_getfield1(self): ops = """ [p1, p187, i184] p188 = getarrayitem_gc(p187, i184, descr=) @@ -6352,3 +6364,54 @@ """ self.optimize_loop(ops, expected, expected_short=short) + def test_forced_virtual_pure_getfield(self): + ops = """ + [p0] + p1 = getfield_gc_pure(p0, descr=valuedescr) + jump(p1) + """ + self.optimize_loop(ops, ops) + + ops = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + p2 = getfield_gc_pure(p1, descr=valuedescr) + escape(p2) + jump(p0) + """ + expected = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + escape(p0) + jump(p0) + """ + self.optimize_loop(ops, expected) + + def test_setarrayitem_lazy(self): + ops = """ + [i0, i1] + p0 = escape() + i2 = escape() + p1 = new_with_vtable(ConstClass(node_vtable)) + setarrayitem_gc(p0, 2, p1, descr=arraydescr) + guard_true(i2) [] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + expected = """ + [i0, i1] + p0 = escape() + i2 = escape() + guard_true(i2) [p0] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass + diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/optimizeopt/test/test_util.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -166,19 +166,19 @@ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [])) + EffectInfo([], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [])) + EffectInfo([], [], [adescr], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [arraydescr])) + EffectInfo([], [], [adescr], [arraydescr])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([adescr], [], [])) + EffectInfo([adescr], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([nextdescr], [], [], + EffectInfo([nextdescr], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), @@ -195,15 +195,15 @@ _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -21,6 +21,9 @@ self.source_op = source_op # the NEW_WITH_VTABLE/NEW_ARRAY operation # that builds this box + def is_forced_virtual(self): + return self.box is not None + def get_key_box(self): if self.box is None: return self.keybox @@ -136,7 +139,6 @@ op = ResOperation(rop.SETFIELD_GC, [box, subbox], None, descr=ofs) newoperations.append(op) - self._fields = None def _get_field_descr_list(self): _cached_sorted_fields = self._cached_sorted_fields @@ -367,7 +369,7 @@ if not self.optimizer.cpu.ts.CONST_NULL.same_constant(objbox): seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None, descr = vrefinfo.descr_forced)) - + # - set 'virtual_token' to TOKEN_NONE args = [op.getarg(0), ConstInt(vrefinfo.TOKEN_NONE)] seo(ResOperation(rop.SETFIELD_GC, args, None, @@ -381,6 +383,14 @@ def optimize_GETFIELD_GC(self, op): value = self.getvalue(op.getarg(0)) + # If this is an immutable field (as indicated by op.is_always_pure()) + # then it's safe to reuse the virtual's field, even if it has been + # forced, because it should never be written to again. + if value.is_forced_virtual() and op.is_always_pure(): + fieldvalue = value.getfield(op.getdescr(), None) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return if value.is_virtual(): assert isinstance(value, AbstractVirtualValue) fieldvalue = value.getfield(op.getdescr(), None) @@ -398,6 +408,7 @@ def optimize_SETFIELD_GC(self, op): value = self.getvalue(op.getarg(0)) + if value.is_virtual(): fieldvalue = self.getvalue(op.getarg(1)) value.setfield(op.getdescr(), fieldvalue) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1,5 +1,5 @@ -import py, os, sys -from pypy.rpython.lltypesystem import lltype, llmemory, rclass +import py, sys +from pypy.rpython.lltypesystem import lltype, rclass from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import debug_start, debug_stop, debug_print @@ -15,13 +15,12 @@ from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE, \ - ABORT_BAD_LOOP, ABORT_FORCE_QUASIIMMUT + ABORT_FORCE_QUASIIMMUT from pypy.jit.metainterp.jitexc import JitException, get_llexception -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize -from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr, MissingLiveness -from pypy.jit.codewriter import heaptracker, longlong -from pypy.jit.metainterp.optimizeopt.util import args_dict_box, args_dict +from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr +from pypy.jit.codewriter import heaptracker +from pypy.jit.metainterp.optimizeopt.util import args_dict_box from pypy.jit.metainterp.optimize import RetraceLoop # ____________________________________________________________ @@ -868,7 +867,7 @@ any_operation = len(self.metainterp.history.operations) > 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jdindex, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -915,8 +914,10 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jd_index, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation + loc = jitdriver_sd.warmstate.get_location_str(greenkey) + debug_print(loc) args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @@ -2119,7 +2120,6 @@ def vrefs_after_residual_call(self): vrefinfo = self.staticdata.virtualref_info for i in range(0, len(self.virtualref_boxes), 2): - virtualbox = self.virtualref_boxes[i] vrefbox = self.virtualref_boxes[i+1] vref = vrefbox.getref_base() if vrefinfo.tracing_after_residual_call(vref): diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -2,10 +2,12 @@ from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr +from pypy.rpython import annlowlevel from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert @@ -82,6 +84,13 @@ ('nums', lltype.Array(rffi.SHORT))) NUMBERINGP.TO.become(NUMBERING) +PENDINGFIELDSTRUCT = lltype.Struct('PendingField', + ('lldescr', annlowlevel.base_ptr_lltype()), + ('num', rffi.SHORT), + ('fieldnum', rffi.SHORT), + ('itemindex', rffi.INT)) +PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) + TAGMASK = 3 def tag(value, tagbits): @@ -329,7 +338,7 @@ value = values[box] value.get_args_for_fail(self) - for _, box, fieldbox in pending_setfields: + for _, box, fieldbox, _ in pending_setfields: self.register_box(box) self.register_box(fieldbox) value = values[fieldbox] @@ -405,13 +414,25 @@ return False def _add_pending_fields(self, pending_setfields): - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) if pending_setfields: - rd_pendingfields = [] - for descr, box, fieldbox in pending_setfields: + n = len(pending_setfields) + rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) + for i in range(n): + descr, box, fieldbox, itemindex = pending_setfields[i] + lldescr = annlowlevel.cast_instance_to_base_ptr(descr) num = self._gettagged(box) fieldnum = self._gettagged(fieldbox) - rd_pendingfields.append((descr, num, fieldnum)) + # the index is limited to 2147483647 (64-bit machines only) + if itemindex > 2147483647: + from pypy.jit.metainterp import compile + compile.giveup() + itemindex = rffi.cast(rffi.INT, itemindex) + # + rd_pendingfields[i].lldescr = lldescr + rd_pendingfields[i].num = num + rd_pendingfields[i].fieldnum = fieldnum + rd_pendingfields[i].itemindex= itemindex self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): @@ -670,10 +691,28 @@ self.virtuals_cache = [self.virtual_default] * len(virtuals) def _prepare_pendingfields(self, pendingfields): - if pendingfields is not None: - for descr, num, fieldnum in pendingfields: + if pendingfields: + for i in range(len(pendingfields)): + lldescr = pendingfields[i].lldescr + num = pendingfields[i].num + fieldnum = pendingfields[i].fieldnum + itemindex= pendingfields[i].itemindex + descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, + lldescr) struct = self.decode_ref(num) - self.setfield(descr, struct, fieldnum) + itemindex = rffi.cast(lltype.Signed, itemindex) + if itemindex < 0: + self.setfield(descr, struct, fieldnum) + else: + self.setarrayitem(descr, struct, itemindex, fieldnum) + + def setarrayitem(self, arraydescr, array, index, fieldnum): + if arraydescr.is_array_of_pointers(): + self.setarrayitem_ref(arraydescr, array, index, fieldnum) + elif arraydescr.is_array_of_floats(): + self.setarrayitem_float(arraydescr, array, index, fieldnum) + else: + self.setarrayitem_int(arraydescr, array, index, fieldnum) def _prepare_next_section(self, info): # Use info.enumerate_vars(), normally dispatching to @@ -846,15 +885,15 @@ structbox, fieldbox) def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, INT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT) def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, REF) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF) def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) - def setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): + def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): itembox = self.decode_box(fieldnum, kind) self.metainterp.execute_and_record(rop.SETARRAYITEM_GC, arraydescr, arraybox, diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1712,6 +1712,7 @@ assert res == g(6, 14) self.check_loop_count(9) self.check_loops(getarrayitem_gc=8, everywhere=True) + py.test.skip("for the following, we need setarrayitem(varindex)") def test_multiple_specialied_versions_bridge(self): myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res']) @@ -2687,6 +2688,20 @@ res = self.meta_interp(f, [1]) assert res == f(1) + def test_remove_array_operations(self): + myjitdriver = JitDriver(greens = [], reds = ['a']) + class W_Int: + def __init__(self, intvalue): + self.intvalue = intvalue + def f(x): + a = [W_Int(x)] + while a[0].intvalue > 0: + myjitdriver.jit_merge_point(a=a) + a[0] = W_Int(a[0].intvalue - 3) + return a[0].intvalue + res = self.meta_interp(f, [100]) + assert res == -2 + #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? class TestOOtype(BasicTests, OOJitMixin): diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -130,6 +130,38 @@ assert res == 50 self.check_loops(int_mod=1) + def test_repeated_lookup(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'd']) + class Wrapper(object): + _immutable_fields_ = ["value"] + def __init__(self, value): + self.value = value + def eq_func(a, b): + return a.value == b.value + def hash_func(x): + return objectmodel.compute_hash(x.value) + + def f(n): + d = None + while n > 0: + myjitdriver.jit_merge_point(n=n, d=d) + d = objectmodel.r_dict(eq_func, hash_func) + y = Wrapper(str(n)) + d[y] = n - 1 + n = d[y] + return d[Wrapper(str(n + 1))] + + res = self.meta_interp(f, [100], listops=True) + assert res == f(50) + # XXX: ideally there would be 7 calls here, but repeated CALL_PURE with + # the same arguments are not folded, because we have conflicting + # definitions of pure, once strhash can be appropriately folded + # this should be decreased to seven. + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + "guard_true": 1, "int_and": 1, "int_gt": 1, + "int_is_true": 1, "int_sub": 1, "jump": 1, + "new_with_vtable": 1, "setfield_gc": 1}) + class TestOOtype(DictTests, OOJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -49,7 +49,7 @@ x = l[n] l = [3] * 100 l[3] = x - l[3] = x + 1 + l[4] = x + 1 n -= 1 return l[0] diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py --- a/pypy/jit/metainterp/test/test_resume.py +++ b/pypy/jit/metainterp/test/test_resume.py @@ -1238,7 +1238,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, values, 0) assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)]) + modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s, -1)]) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume @@ -1259,6 +1259,106 @@ assert len(expected) == len(trace) assert demo55.next == demo66 +def test_virtual_adder_pending_fields_and_arrayitems(): + class Storage(object): + pass + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier._add_pending_fields([]) + assert not storage.rd_pendingfields + # + class FieldDescr(object): + pass + field_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061)} + modifier._add_pending_fields([(field_a, 42, 61, -1)]) + pf = storage.rd_pendingfields + assert len(pf) == 1 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is field_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + # + array_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061), + 62: rffi.cast(rffi.SHORT, 1062), + 63: rffi.cast(rffi.SHORT, 1063)} + modifier._add_pending_fields([(array_a, 42, 61, 0), + (array_a, 42, 62, 2147483647)]) + pf = storage.rd_pendingfields + assert len(pf) == 2 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[1].num) == 1042 + assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 + assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + # + from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole + py.test.raises(SwitchToBlackhole, modifier._add_pending_fields, + [(array_a, 42, 63, 2147483648)]) + +def test_resume_reader_fields_and_arrayitems(): + class ResumeReader(AbstractResumeDataReader): + def __init__(self, got=None, got_array=None): + self.got = got + self.got_array = got_array + def setfield(self, descr, struct, fieldnum): + assert lltype.typeOf(struct) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got.append((descr, struct, fieldnum)) + def setarrayitem(self, arraydescr, array, index, fieldnum): + assert lltype.typeOf(array) is lltype.Signed + assert lltype.typeOf(index) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got_array.append((arraydescr, array, index, fieldnum)) + def decode_ref(self, num): + return rffi.cast(lltype.Signed, num) * 100 + got = [] + pf = lltype.nullptr(PENDINGFIELDSP.TO) + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [] + # + class FieldDescr(AbstractDescr): + pass + field_a = FieldDescr() + field_b = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 2) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) + pf[0].itemindex = rffi.cast(rffi.INT, -1) + pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) + pf[1].num = rffi.cast(rffi.SHORT, 2042) + pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) + pf[1].itemindex = rffi.cast(rffi.INT, -1) + got = [] + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] + # + array_a = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 1) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) + pf[0].itemindex = rffi.cast(rffi.INT, 123) + got_array = [] + ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + assert got_array == [(array_a, 104200, 123, 1063)] + def test_invalidation_needed(): class options: diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py --- a/pypy/jit/metainterp/virtualref.py +++ b/pypy/jit/metainterp/virtualref.py @@ -1,5 +1,5 @@ from pypy.rpython.rmodel import inputconst, log -from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass +from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.jit.metainterp import history from pypy.jit.codewriter import heaptracker from pypy.rlib.jit import InvalidVirtualRef diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -1,6 +1,5 @@ import sys, py -from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr -from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.annlowlevel import llhelper, MixLevelHelperAnnotator,\ cast_base_ptr_to_instance, hlstr from pypy.annotation import model as annmodel @@ -10,16 +9,12 @@ from pypy.objspace.flow.model import checkgraph, Link, copygraph from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import r_uint, intmask -from pypy.rlib.debug import debug_print, fatalerror -from pypy.rlib.debug import debug_start, debug_stop -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.translator.simplify import get_funcobj, get_functype +from pypy.rlib.debug import fatalerror +from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function from pypy.jit.metainterp import history, pyjitpl, gc, memmgr -from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp -from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper +from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.jitdriver import JitDriverStaticData @@ -297,9 +292,6 @@ self.stats = stats if translate_support_code: self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper) - annhelper = self.annhelper - else: - annhelper = None cpu = CPUClass(self.translator.rtyper, self.stats, self.opt, translate_support_code, gcdescr=self.gcdescr) self.cpu = cpu @@ -440,7 +432,6 @@ maybe_enter_jit._always_inline_ = True jd._maybe_enter_jit_fn = maybe_enter_jit - num_green_args = jd.num_green_args def maybe_enter_from_start(*args): maybe_compile_and_run(state.increment_function_threshold, *args) maybe_enter_from_start._always_inline_ = True @@ -553,7 +544,6 @@ self.rewrite_can_enter_jit(jd, sublist) def rewrite_can_enter_jit(self, jd, can_enter_jits): - FUNC = jd._JIT_ENTER_FUNCTYPE FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -1,7 +1,7 @@ import sys, weakref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi from pypy.rpython.ootypesystem import ootype -from pypy.rpython.annlowlevel import hlstr, llstr, cast_base_ptr_to_instance +from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance from pypy.rpython.annlowlevel import cast_object_to_ptr from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict from pypy.rlib.rarithmetic import intmask @@ -502,7 +502,6 @@ if hasattr(self, 'set_future_values'): return self.set_future_values - warmrunnerdesc = self.warmrunnerdesc jitdriver_sd = self.jitdriver_sd cpu = self.cpu vinfo = jitdriver_sd.virtualizable_info @@ -518,7 +517,6 @@ # if vinfo is not None: i0 = len(jitdriver_sd._red_args_types) - num_green_args = jitdriver_sd.num_green_args index_of_virtualizable = jitdriver_sd.index_of_virtualizable vable_static_fields = unrolling_iterable( zip(vinfo.static_extra_types, vinfo.static_fields)) diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -32,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -294,7 +294,7 @@ break new_frame = space.createframe(code, w_func.w_func_globals, w_func.closure) - new_frame.fastlocals_w[0] = w_item + new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) return result_w diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -3,6 +3,14 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.imp.importing import get_pyc_magic + +class BuildersModule(MixedModule): + appleveldefs = {} + + interpleveldefs = { + "UnicodeBuilder": "interp_builders.W_UnicodeBuilder", + } + class Module(MixedModule): appleveldefs = { } @@ -19,6 +27,10 @@ 'lookup_special' : 'interp_magic.lookup_special', } + submodules = { + "builders": BuildersModule, + } + def setup_after_space_initialization(self): """NOT_RPYTHON""" if not self.space.config.translating: diff --git a/pypy/module/__pypy__/interp_builders.py b/pypy/module/__pypy__/interp_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_builders.py @@ -0,0 +1,50 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef +from pypy.rlib.rstring import UnicodeBuilder + + +class W_UnicodeBuilder(Wrappable): + def __init__(self, space, size): + if size == -1: + self.builder = UnicodeBuilder() + else: + self.builder = UnicodeBuilder(size) + self.done = False + + def _check_done(self, space): + if self.done: + raise OperationError(space.w_ValueError, space.wrap("Can't operate on a done builder")) + + @unwrap_spec(size=int) + def descr__new__(space, w_subtype, size=-1): + return W_UnicodeBuilder(space, size) + + @unwrap_spec(s=unicode) + def descr_append(self, space, s): + self._check_done(space) + self.builder.append(s) + + @unwrap_spec(s=unicode, start=int, end=int) + def descr_append_slice(self, space, s, start, end): + self._check_done(space) + if not 0 <= start <= end <= len(s): + raise OperationError(space.w_ValueError, space.wrap("bad start/stop")) + self.builder.append_slice(s, start, end) + + def descr_build(self, space): + self._check_done(space) + w_s = space.wrap(self.builder.build()) + self.done = True + return w_s + + +W_UnicodeBuilder.typedef = TypeDef("UnicodeBuilder", + __new__ = interp2app(W_UnicodeBuilder.descr__new__.im_func), + + append = interp2app(W_UnicodeBuilder.descr_append), + append_slice = interp2app(W_UnicodeBuilder.descr_append_slice), + build = interp2app(W_UnicodeBuilder.descr_build), +) +W_UnicodeBuilder.typedef.acceptable_as_base_class = False \ No newline at end of file diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,15 +1,19 @@ from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.error import OperationError -from pypy.rlib import debug +from pypy.rlib import debug, jit + + at jit.dont_look_inside @unwrap_spec(category=str) def debug_start(space, category): debug.debug_start(category) + at jit.dont_look_inside def debug_print(space, args_w): parts = [space.str_w(space.str(w_item)) for w_item in args_w] debug.debug_print(' '.join(parts)) + at jit.dont_look_inside @unwrap_spec(category=str) def debug_stop(space, category): debug.debug_stop(category) diff --git a/pypy/module/__pypy__/test/test_builders.py b/pypy/module/__pypy__/test/test_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_builders.py @@ -0,0 +1,34 @@ +from pypy.conftest import gettestobjspace + + +class AppTestBuilders(object): + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['__pypy__']) + + def test_simple(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append(u"abc") + b.append(u"123") + b.append(u"1") + s = b.build() + assert s == u"abc1231" + raises(ValueError, b.build) + raises(ValueError, b.append, u"123") + + def test_preallocate(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder(10) + b.append(u"abc") + b.append(u"123") + s = b.build() + assert s == u"abc123" + + def test_append_slice(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append_slice(u"abcdefgh", 2, 5) + raises(ValueError, b.append_slice, u"1", 2, 1) + s = b.build() + assert s == "cde" + raises(ValueError, b.append_slice, u"abc", 1, 2) \ No newline at end of file diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -900,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/_stackless/test/test_greenlet.py b/pypy/module/_stackless/test/test_greenlet.py --- a/pypy/module/_stackless/test/test_greenlet.py +++ b/pypy/module/_stackless/test/test_greenlet.py @@ -72,6 +72,23 @@ g1 = greenlet(f) raises(ValueError, g2.switch) + + def test_exc_info_save_restore(self): + from _stackless import greenlet + import sys + def f(): + try: + raise ValueError('fun') + except: + exc_info = sys.exc_info() + greenlet(h).switch() + assert exc_info == sys.exc_info() + + def h(): + assert sys.exc_info() == (None, None, None) + + greenlet(f).switch() + def test_exception(self): from _stackless import greenlet import sys diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -39,6 +39,7 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject +import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject import pypy.module.cpyext.longobject @@ -64,6 +65,7 @@ import pypy.module.cpyext.memoryobject import pypy.module.cpyext.codecs import pypy.module.cpyext.pyfile +import pypy.module.cpyext.pystrtod # now that all rffi_platform.Struct types are registered, configure them api.configure_types() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -562,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/pystrtod.py @@ -0,0 +1,68 @@ +import errno +from pypy.interpreter.error import OperationError +from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.pyobject import PyObject +from pypy.rlib import rdtoa +from pypy.rlib import rfloat +from pypy.rlib import rposix +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi + + + at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +def PyOS_string_to_double(space, s, endptr, w_overflow_exception): + """Convert a string s to a double, raising a Python + exception on failure. The set of accepted strings corresponds to + the set of strings accepted by Python's float() constructor, + except that s must not have leading or trailing whitespace. + The conversion is independent of the current locale. + + If endptr is NULL, convert the whole string. Raise + ValueError and return -1.0 if the string is not a valid + representation of a floating-point number. + + If endptr is not NULL, convert as much of the string as + possible and set *endptr to point to the first unconverted + character. If no initial segment of the string is the valid + representation of a floating-point number, set *endptr to point + to the beginning of the string, raise ValueError, and return + -1.0. + + If s represents a value that is too large to store in a float + (for example, "1e500" is such a string on many platforms) then + if overflow_exception is NULL return Py_HUGE_VAL (with + an appropriate sign) and don't set any exception. Otherwise, + overflow_exception must point to a Python exception object; + raise that exception and return -1.0. In both cases, set + *endptr to point to the first character after the converted value. + + If any other error occurs during the conversion (for example an + out-of-memory error), set the appropriate Python exception and + return -1.0. + """ + user_endptr = True + try: + if not endptr: + endptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + user_endptr = False + result = rdtoa.dg_strtod(s, endptr) + endpos = (rffi.cast(rffi.LONG, endptr[0]) - + rffi.cast(rffi.LONG, s)) + if endpos == 0 or (not user_endptr and not endptr[0][0] == '\0'): + raise OperationError( + space.w_ValueError, + space.wrap('invalid input at position %s' % endpos)) + if rposix.get_errno() == errno.ERANGE: + rposix.set_errno(0) + if w_overflow_exception is None: + if result > 0: + return rfloat.INFINITY + else: + return -rfloat.INFINITY + else: + raise OperationError(w_overflow_exception, + space.wrap('value too large')) + return result + finally: + if not user_endptr: + lltype.free(endptr, flavor='raw') diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/setobject.py @@ -0,0 +1,46 @@ +from pypy.interpreter.error import OperationError +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, + build_type_checkers) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, + borrow_from, make_ref, from_ref) +from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall +from pypy.objspace.std.setobject import W_SetObject, newset +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject + + +PySet_Check, PySet_CheckExact = build_type_checkers("Set") + + + at cpython_api([PyObject], PyObject) +def PySet_New(space, w_iterable): + if w_iterable is None: + return space.call_function(space.w_set) + else: + return space.call_function(space.w_set, w_iterable) + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Add(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'add', w_obj) + return 0 + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Discard(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'discard', w_obj) + return 0 + + + at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +def PySet_GET_SIZE(space, w_s): + return space.int_w(space.len(w_s)) + + at cpython_api([PyObject], Py_ssize_t, error=-1) +def PySet_Size(space, ref): + if not PySet_Check(space, ref): + raise OperationError(space.w_TypeError, + space.wrap("expected set object")) + return PySet_GET_SIZE(space, ref) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -480,39 +480,6 @@ """Create a new Python complex number object from a C Py_complex value.""" raise NotImplementedError - at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) -def PyOS_string_to_double(space, s, endptr, overflow_exception): - """Convert a string s to a double, raising a Python - exception on failure. The set of accepted strings corresponds to - the set of strings accepted by Python's float() constructor, - except that s must not have leading or trailing whitespace. - The conversion is independent of the current locale. - - If endptr is NULL, convert the whole string. Raise - ValueError and return -1.0 if the string is not a valid - representation of a floating-point number. - - If endptr is not NULL, convert as much of the string as - possible and set *endptr to point to the first unconverted - character. If no initial segment of the string is the valid - representation of a floating-point number, set *endptr to point - to the beginning of the string, raise ValueError, and return - -1.0. - - If s represents a value that is too large to store in a float - (for example, "1e500" is such a string on many platforms) then - if overflow_exception is NULL return Py_HUGE_VAL (with - an appropriate sign) and don't set any exception. Otherwise, - overflow_exception must point to a Python exception object; - raise that exception and return -1.0. In both cases, set - *endptr to point to the first character after the converted value. - - If any other error occurs during the conversion (for example an - out-of-memory error), set the appropriate Python exception and - return -1.0. - """ - raise NotImplementedError - @cpython_api([rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_strtod(space, nptr, endptr): """Convert a string to a double. This function behaves like the Standard C diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -0,0 +1,93 @@ +import math + +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype + + +class TestPyOS_string_to_double(BaseApiTest): + + def test_simple_float(self, api): + s = rffi.str2charp('0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == 0.4 + rffi.free_charp(s) + + def test_empty_string(self, api): + s = rffi.str2charp('') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_bad_string(self, api): + s = rffi.str2charp(' 0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_overflow_pos(self, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r > 0 + rffi.free_charp(s) + + def test_overflow_neg(self, api): + s = rffi.str2charp('-1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r < 0 + rffi.free_charp(s) + + def test_overflow_exc(self, space, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, space.w_ValueError) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_endptr_number(self, api): + s = rffi.str2charp('0.4') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_tail(self, api): + s = rffi.str2charp('0.4 foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_no_conversion(self, api): + s = rffi.str2charp('foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == -1.0 + raises(ValueError) + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + api.PyErr_Clear() + rffi.free_charp(s) + lltype.free(endp, flavor='raw') diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_setobject.py @@ -0,0 +1,29 @@ +import py + +from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace + + +class TestTupleObject(BaseApiTest): + def test_setobj(self, space, api): + assert not api.PySet_Check(space.w_None) + assert api.PySet_Add(space.w_None, space.w_None) == -1 + api.PyErr_Clear() + w_set = space.call_function(space.w_set) + space.call_method(w_set, 'update', space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + assert api.PySet_GET_SIZE(w_set) == 4 + raises(TypeError, api.PySet_Size(space.newlist([]))) + api.PyErr_Clear() + + def test_set_add_discard(self, space, api): + w_set = api.PySet_New(None) + assert api.PySet_Size(w_set) == 0 + w_set = api.PySet_New(space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + api.PySet_Add(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 5 + api.PySet_Discard(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 4 diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -367,3 +367,14 @@ data, len(u), lltype.nullptr(rffi.CCHARP.TO)) rffi.free_wcharp(data) + def test_format(self, space, api): + w_format = space.wrap(u'hi %s') + w_args = space.wrap((u'test',)) + w_formated = api.PyUnicode_Format(w_format, w_args) + assert space.unwrap(w_formated) == space.unwrap(space.mod(w_format, w_args)) + + def test_join(self, space, api): + w_sep = space.wrap(u'') + w_seq = space.wrap([u'a', u'b']) + w_joined = api.PyUnicode_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == u'ab' diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,6 +7,7 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) + assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -523,3 +523,11 @@ copies sizeof(Py_UNICODE) * length bytes from source to target""" for i in range(0, length): target[i] = source[i] + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Format(space, w_format, w_args): + return space.mod(w_format, w_args) + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -21,6 +21,10 @@ """Return the referenced object from a weak reference. If the referent is no longer live, returns None. This function returns a borrowed reference. """ + return PyWeakref_GET_OBJECT(space, w_ref) + + at cpython_api([PyObject], PyObject) +def PyWeakref_GET_OBJECT(space, w_ref): return borrow_from(w_ref, space.call_function(w_ref)) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -622,7 +622,13 @@ try: if find_info: w_mod = load_module(space, w_modulename, find_info) - w_mod = space.getitem(space.sys.get("modules"), w_modulename) + try: + w_mod = space.getitem(space.sys.get("modules"), + w_modulename) + except OperationError, oe: + if not oe.match(space, space.w_KeyError): + raise + raise OperationError(space.w_ImportError, w_modulename) if w_parent is not None: space.setattr(w_parent, space.wrap(partname), w_mod) return w_mod diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py --- a/pypy/module/imp/test/test_import.py +++ b/pypy/module/imp/test/test_import.py @@ -37,6 +37,7 @@ ambig = "imamodule = 1", test_reload = "def test():\n raise ValueError\n", infinite_reload = "import infinite_reload; reload(infinite_reload)", + del_sys_module = "import sys\ndel sys.modules['del_sys_module']\n", ) root.ensure("notapackage", dir=1) # empty, no __init__.py setuppkg("pkg", @@ -562,6 +563,14 @@ except ImportError: pass + def test_del_from_sys_modules(self): + try: + import del_sys_module + except ImportError: + pass # ok + else: + assert False, 'should not work' + class TestAbi: def test_abi_tag(self): space1 = gettestobjspace(soabi='TEST') diff --git a/pypy/module/math/__init__.py b/pypy/module/math/__init__.py --- a/pypy/module/math/__init__.py +++ b/pypy/module/math/__init__.py @@ -4,6 +4,7 @@ class Module(MixedModule): appleveldefs = { + 'factorial' : 'app_math.factorial' } interpleveldefs = { @@ -40,7 +41,6 @@ 'isnan' : 'interp_math.isnan', 'trunc' : 'interp_math.trunc', 'fsum' : 'interp_math.fsum', - 'factorial' : 'interp_math.factorial', 'asinh' : 'interp_math.asinh', 'acosh' : 'interp_math.acosh', 'atanh' : 'interp_math.atanh', diff --git a/pypy/module/math/app_math.py b/pypy/module/math/app_math.py new file mode 100644 --- /dev/null +++ b/pypy/module/math/app_math.py @@ -0,0 +1,13 @@ +def factorial(x): + """Find x!.""" + if isinstance(x, float): + fl = int(x) + if fl != x: + raise ValueError("float arguments must be integral") + x = fl + if x < 0: + raise ValueError("x must be >= 0") + res = 1 + for i in range(1, x + 1): + res *= i + return res diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -373,22 +373,6 @@ hi = v return space.wrap(hi) -def factorial(space, w_x): - """Find x!.""" - if space.isinstance_w(w_x, space.w_float): - fl = space.float_w(w_x) - if math.floor(fl) != fl: - raise OperationError(space.w_ValueError, - space.wrap("float arguments must be integral")) - w_x = space.long(w_x) - x = space.int_w(w_x) - if x < 0: - raise OperationError(space.w_ValueError, space.wrap("x must be >= 0")) - w_res = space.wrap(1) - for i in range(1, x + 1): - w_res = space.mul(w_res, space.wrap(i)) - return w_res - def log1p(space, w_x): """Find log(x + 1).""" return math1(space, rfloat.log1p, w_x) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -16,6 +16,7 @@ 'absolute': 'interp_ufuncs.absolute', 'copysign': 'interp_ufuncs.copysign', 'exp': 'interp_ufuncs.exp', + 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', 'negative': 'interp_ufuncs.negative', diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -44,6 +44,10 @@ self.invalidates = [] def invalidated(self): + if self.invalidates: + self._invalidated() + + def _invalidated(self): for arr in self.invalidates: arr.force_if_needed() del self.invalidates[:] @@ -353,4 +357,4 @@ __div__ = interp2app(BaseArray.descr_div), mean = interp2app(BaseArray.descr_mean), -) \ No newline at end of file +) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -62,6 +62,10 @@ return 1.0 / value @ufunc +def floor(value): + return math.floor(value) + + at ufunc def sign(value): if value == 0.0: return 0.0 diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -67,6 +67,15 @@ for i in range(4): assert b[i] == reference[i] + def test_floor(self): + from numpy import array, floor + + reference = [-2.0, -1.0, 0.0, 1.0, 1.0] + a = array([-1.4, -1.0, 0.0, 1.0, 1.4]) + b = floor(a) + for i in range(5): + assert b[i] == reference[i] + def test_copysign(self): from numpy import array, copysign diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -21,8 +21,7 @@ from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes PyFrame._virtualizable2_ = ['last_instr', 'pycode', - 'valuestackdepth', 'valuestack_w[*]', - 'fastlocals_w[*]', + 'valuestackdepth', 'locals_stack_w[*]', 'last_exception', 'lastblock', 'is_being_profiled', diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,8 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof', '_weakref']: + 'posix', '_socket', '_sre', '_lsprof', '_weakref', + '__pypy__']: return True return False diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -58,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -46,7 +46,7 @@ guard_no_overflow(descr=) i18 = int_add(i7, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) """) def test_array_intimg(self): @@ -83,7 +83,7 @@ setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) i28 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -11,21 +11,14 @@ return 1 + rec(n-1) # # this loop is traced and then aborted, because the trace is too - # long. But then "rec" is marked as "don't inline" - i = 0 - j = 0 - while i < 20: - i += 1 - j += rec(100) - # - # next time we try to trace "rec", instead of inlining we compile - # it separately and generate a call_assembler + # long. But then "rec" is marked as "don't inline". Since we + # already traced function from the start (because of number), + # now we can inline it as call assembler i = 0 j = 0 while i < 20: i += 1 j += rec(100) # ID: call_rec - a = 0 return j # log = self.run(fn, [], threshold=18) @@ -38,6 +31,20 @@ ... """) + def test_fib(self): + def fib(n): + if n == 0 or n == 1: + return 1 + return fib(n - 1) + fib(n - 2) # ID: call_rec + + log = self.run(fib, [7], function_threshold=15) + loop, = log.loops_by_filename(self.filepath, is_entry_bridge='*') + #assert loop.match_by_id('call_rec', ''' + #... + #p1 = call_assembler(..., descr=...) + #... + #''') + def test_simple_call(self): src = """ OFFSET = 0 @@ -180,7 +187,7 @@ guard_no_overflow(descr=) i18 = force_token() --TICK-- - jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) """) def test_default_and_kw(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -115,7 +115,6 @@ # ---------------------- loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i8 = getfield_gc_pure(p5, descr=) i9 = int_lt(i8, i7) guard_true(i9, descr=.*) guard_not_invalidated(descr=.*) @@ -125,7 +124,7 @@ p20 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p20, i11, descr=) setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i7, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py --- a/pypy/module/pypyjit/test_pypy_c/test_intbound.py +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -97,7 +97,7 @@ guard_no_overflow(descr=...) i17 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) """) def test_intbound_sub_lt(self): @@ -150,7 +150,7 @@ guard_no_overflow(descr=...) i19 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) """) def test_intbound_addmul_ge(self): @@ -178,7 +178,7 @@ guard_no_overflow(descr=...) i21 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) """) def test_intbound_eq(self): @@ -210,7 +210,7 @@ guard_no_overflow(descr=...) i16 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) """) def test_intbound_mul(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -169,7 +169,7 @@ guard_false(i16, descr=) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) + setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, 146982464, descr=) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) @@ -182,6 +182,7 @@ guard_no_overflow(descr=) --TICK-- jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -0,0 +1,42 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestString(BaseTestPyPyC): + def test_lookup_default_encoding(self): + def main(n): + import string + i = 0 + letters = string.letters + uletters = unicode(string.letters) + while i < n: + i += letters[i % len(letters)] == uletters[i % len(letters)] + return i + + log = self.run(main, [300]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i14 = int_lt(i6, i9) + guard_true(i14, descr=) + i15 = int_mod(i6, i10) + i17 = int_rshift(i15, 63) + i18 = int_and(i10, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=) + i22 = int_ge(i19, i10) + guard_false(i22, descr=) + i23 = strgetitem(p11, i19) + i24 = int_ge(i19, i12) + guard_false(i24, descr=) + i25 = unicodegetitem(p13, i19) + guard_not_invalidated(descr=) + p27 = newstr(1) + strsetitem(p27, 0, i23) + p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) + guard_no_exception(descr=) + i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) + guard_true(i32, descr=) + i34 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) \ No newline at end of file diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -7,6 +7,8 @@ class Module(MixedModule): """Sys Builtin Module. """ + _immutable_fields_ = ["defaultencoding?"] + def __init__(self, space, w_name): """NOT_RPYTHON""" # because parent __init__ isn't if space.config.translating: diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -384,8 +384,9 @@ # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) - stack_items_w = self.crnt_frame.valuestack_w - for i in range(self.crnt_frame.valuestackdepth-1, -1, -1): + f = self.crnt_frame + stack_items_w = f.locals_stack_w + for i in range(f.valuestackdepth-1, f.nlocals-1, -1): w_v = stack_items_w[i] if isinstance(w_v, Constant): if w_v.value is oldvalue: diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py --- a/pypy/objspace/flow/framestate.py +++ b/pypy/objspace/flow/framestate.py @@ -10,7 +10,7 @@ def __init__(self, state): if isinstance(state, PyFrame): # getfastscope() can return real None, for undefined locals - data = state.getfastscope() + state.savevaluestack() + data = state.save_locals_stack() if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -36,11 +36,9 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): - fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) # Nones == undefined locals - frame.restorevaluestack(data[fastlocals:-2]) + frame.restore_locals_stack(data[:-2]) # Nones == undefined locals if data[-2] == Constant(None): assert data[-1] == Constant(None) frame.last_exception = None diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py --- a/pypy/objspace/flow/test/test_framestate.py +++ b/pypy/objspace/flow/test/test_framestate.py @@ -25,7 +25,7 @@ dummy = Constant(None) #dummy.dummy = True arg_list = ([Variable() for i in range(formalargcount)] + - [dummy] * (len(frame.fastlocals_w) - formalargcount)) + [dummy] * (frame.nlocals - formalargcount)) frame.setfastscope(arg_list) return frame @@ -42,7 +42,7 @@ def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1 != fs2 @@ -55,7 +55,7 @@ def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general @@ -63,7 +63,7 @@ def test_restore_frame(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs1.restoreframe(frame) assert fs1 == FrameState(frame) @@ -82,25 +82,26 @@ def test_getoutputargs(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable - # fastlocals_w[-1] -> fastlocals_w[-1] is Constant(None) - assert outputargs == [frame.fastlocals_w[0], Constant(None)] + # locals_w[n-1] -> locals_w[n-1] is Constant(None) + assert outputargs == [frame.locals_stack_w[0], Constant(None)] def test_union_different_constants(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(42) + frame.locals_stack_w[frame.nlocals-1] = Constant(42) fs2 = FrameState(frame) fs3 = fs1.union(fs2) fs3.restoreframe(frame) - assert isinstance(frame.fastlocals_w[-1], Variable) # generalized + assert isinstance(frame.locals_stack_w[frame.nlocals-1], Variable) + # ^^^ generalized def test_union_spectag(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(SpecTag()) + frame.locals_stack_w[frame.nlocals-1] = Constant(SpecTag()) fs2 = FrameState(frame) assert fs1.union(fs2) is None # UnionError diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,13 +1,14 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.debug import mark_dict_non_null def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -59,7 +60,8 @@ def initialize_as_rdict(self): assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) + self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) return self.r_dict_content @@ -308,6 +310,7 @@ def __init__(self, space): self.space = space self.content = {} + mark_dict_non_null(self.content) def impl_setitem(self, w_key, w_value): space = self.space @@ -317,6 +320,7 @@ self._as_rdict().impl_fallback_setitem(w_key, w_value) def impl_setitem_str(self, key, w_value): + assert key is not None self.content[key] = w_value def impl_setdefault(self, w_key, w_default): @@ -342,6 +346,7 @@ return len(self.content) def impl_getitem_str(self, key): + assert key is not None return self.content.get(key, None) def impl_getitem(self, w_key): diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -311,6 +311,10 @@ classofinstance=classofinstance, strdict=strdict) + def newset(self): + from pypy.objspace.std.setobject import newset + return W_SetObject(self, newset(self)) + def newslice(self, w_start, w_end, w_step): return W_SliceObject(w_start, w_end, w_step) diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -50,6 +50,10 @@ u = self.space.wrap(set('simsalabim')) assert self.space.eq_w(s,u) + def test_space_newset(self): + s = self.space.newset() + assert self.space.str_w(self.space.repr(s)) == 'set([])' + class AppTestAppSetTest: def test_subtype(self): class subset(set):pass diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -272,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -151,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -206,7 +215,7 @@ if dictobj is None: return lltype.nullptr(self.DICT) if not isinstance(dictobj, (dict, objectmodel.r_dict)): - raise TyperError("expected a dict: %r" % (dictobj,)) + raise TypeError("expected a dict: %r" % (dictobj,)) try: key = Constant(dictobj) return self.dict_cache[key] @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) @@ -835,8 +847,12 @@ def ll_popitem(ELEM, dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -845,7 +861,10 @@ break else: raise KeyError - global_popitem_index.nextindex += counter + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter entry = entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py --- a/pypy/rpython/lltypesystem/rlist.py +++ b/pypy/rpython/lltypesystem/rlist.py @@ -250,12 +250,11 @@ length = l.length l.length = length + 1 l.ll_setitem_fast(length, newitem) -ll_append_noresize.oopspec = 'list.append(l, newitem)' def ll_both_none(lst1, lst2): return not lst1 and not lst2 - + # ____________________________________________________________ # diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted +from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -57,6 +57,8 @@ llmemory.itemoffsetof(TP.chars, 0) + llmemory.sizeof(CHAR_TP) * item) + # It'd be nice to be able to look inside this function. + @dont_look_inside @enforceargs(None, None, int, int, int) def copy_string_contents(src, dst, srcstart, dststart, length): assert srcstart >= 0 @@ -323,6 +325,8 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' + # it's pure but it does not look like it + @purefunction def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -334,7 +338,6 @@ x = 29872897 s.hash = x return x - ll_strhash._pure_function_ = True # it's pure but it does not look like it def ll_strfasthash(s): return s.hash # assumes that the hash is already computed diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,23 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + class Cls(self.AddressStack): + def append(self2, addr): + assert addr not in self2.tolist() + self.AddressStack.append(self2, addr) + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +637,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +655,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +698,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +789,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +882,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +922,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,11 +933,11 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded self.remember_young_pointer_from_array2(addr_array, index) else: @@ -943,20 +955,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -980,16 +995,18 @@ # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,9 +1019,7 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return @@ -1016,7 +1031,7 @@ addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True @@ -1026,9 +1041,6 @@ # xxx trying it out for the JIT: a 3-arguments version of the above def remember_young_pointer_from_array3(addr_array, index, newvalue): - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") objhdr = self.header(addr_array) # # a single check for the common case of neither GCFLAG_HAS_CARDS @@ -1044,8 +1056,8 @@ else: # case with cards. # - # If the newly written address does not actually point to the - # nursery, leave now. + # If the newly written address does not actually point to a + # young object, leave now. if not self.appears_to_be_young(newvalue): return # @@ -1056,46 +1068,53 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + \ - (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True assert self.card_page_indices > 0 self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1103,15 +1122,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1119,6 +1159,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1135,20 +1191,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1181,7 +1245,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1189,7 +1253,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1205,11 +1269,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1245,19 +1309,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1296,7 +1371,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1343,11 +1430,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,78 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag + # + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert not res # there might be young ptrs, let ll_arraycopy to find them + + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -884,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,29 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): @@ -860,6 +883,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -121,6 +121,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): if self.code is None: return None @@ -222,6 +225,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -168,7 +168,7 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -103,6 +103,8 @@ specname = os.path.splitext(os.path.basename(targetspec))[0] sys.path.insert(0, os.path.dirname(targetspec)) mod = __import__(specname) + if 'target' not in mod.__dict__: + raise Exception("file %r is not a valid targetxxx.py." % (targetspec,)) return mod.__dict__ def parse_options_and_load_target(): diff --git a/pypy/translator/platform/darwin.py b/pypy/translator/platform/darwin.py --- a/pypy/translator/platform/darwin.py +++ b/pypy/translator/platform/darwin.py @@ -68,12 +68,10 @@ class Darwin_i386(Darwin): name = "darwin_i386" - link_flags = ('-arch', 'i386', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'i386') + cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer') class Darwin_x86_64(Darwin): name = "darwin_x86_64" - link_flags = ('-arch', 'x86_64', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'x86_64') + cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer') From noreply at buildbot.pypy.org Fri Jul 1 08:45:01 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 1 Jul 2011 08:45:01 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: typo Message-ID: <20110701064501.69CBD82936@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45209:c530885f74e1 Date: 2011-06-30 19:29 +0200 http://bitbucket.org/pypy/pypy/changeset/c530885f74e1/ Log: typo diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6195,7 +6195,7 @@ """ self.optimize_loop(ops, expected) - def test_constant_getfield1(self): + def test_constant_getfield1(self): ops = """ [p1, p187, i184] p188 = getarrayitem_gc(p187, i184, descr=) @@ -6364,7 +6364,7 @@ """ self.optimize_loop(ops, expected, expected_short=short) - def test_forced_virtual_pure_getfield(self): + def test_forced_virtual_pure_getfield(self): ops = """ [p0] p1 = getfield_gc_pure(p0, descr=valuedescr) From noreply at buildbot.pypy.org Fri Jul 1 08:45:02 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 1 Jul 2011 08:45:02 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: complete merge without support for heap operations in the short preamble Message-ID: <20110701064502.A36D082936@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45210:47aed66223f9 Date: 2011-06-30 19:38 +0200 http://bitbucket.org/pypy/pypy/changeset/47aed66223f9/ Log: complete merge without support for heap operations in the short preamble diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -117,13 +117,16 @@ self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False - def reconstruct_for_next_iteration(self, optimizer, valuemap): + def force_at_end_of_preamble(self): + self.force_all_lazy_setfields_and_arrayitems() + + def flush(self): + self.force_all_lazy_setfields_and_arrayitems() + + def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, + optimizer, valuemap): new = OptHeap() - - if True: - self.force_all_lazy_setfields_and_arrayitems() - else: - assert 0 # was: new.lazy_setfields = self.lazy_setfields + return new for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) From noreply at buildbot.pypy.org Fri Jul 1 08:45:03 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 1 Jul 2011 08:45:03 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: merged getfield_gc support in short preamble manually Message-ID: <20110701064503.DD17782936@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45211:bbd855e7d8bf Date: 2011-07-01 08:11 +0200 http://bitbucket.org/pypy/pypy/changeset/bbd855e7d8bf/ Log: merged getfield_gc support in short preamble manually diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -4,6 +4,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.optimizeopt.optimizer import Optimization +from pypy.jit.metainterp.history import ConstInt, Const class CachedField(object): @@ -23,6 +24,7 @@ # 'cached_fields'. # self._cached_fields = {} + self._cached_fields_getfield_op = {} self._lazy_setfield = None self._lazy_setfield_registered = False @@ -69,9 +71,10 @@ else: return self._cached_fields.get(structvalue, None) - def remember_field_value(self, structvalue, fieldvalue): + def remember_field_value(self, structvalue, fieldvalue, getfield_op=None): assert self._lazy_setfield is None self._cached_fields[structvalue] = fieldvalue + self._cached_fields_getfield_op[structvalue] = getfield_op def force_lazy_setfield(self, optheap): op = self._lazy_setfield @@ -80,7 +83,7 @@ # Now we clear _cached_fields, because actually doing the # setfield might impact any of the stored result (because of # possible aliasing). - self._cached_fields.clear() + self.clear() self._lazy_setfield = None optheap.next_optimization.propagate_forward(op) # Once it is done, we can put at least one piece of information @@ -90,15 +93,38 @@ fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) - def get_reconstructed(self, optimizer, valuemap): + def clear(self): + self._cached_fields.clear() + self._cached_fields_getfield_op.clear() + + def turned_constant(self, newvalue, value): + if newvalue not in self._cached_fields: + self._cached_fields[newvalue] = self._cached_fields[value] + op = self._cached_fields_getfield_op[value].clone() + constbox = value.box + assert isinstance(constbox, Const) + op.setarg(0, constbox) + self._cached_fields_getfield_op[newvalue] = op + + def get_cloned(self, optimizer, valuemap, short_boxes): assert self._lazy_setfield is None cf = CachedField() for structvalue, fieldvalue in self._cached_fields.iteritems(): - structvalue2 = structvalue.get_reconstructed(optimizer, valuemap) - fieldvalue2 = fieldvalue .get_reconstructed(optimizer, valuemap) - cf._cached_fields[structvalue2] = fieldvalue2 + op = self._cached_fields_getfield_op.get(structvalue, None) + if op and op.result in short_boxes and short_boxes[op.result] is op: + structvalue2 = structvalue.get_cloned(optimizer, valuemap) + fieldvalue2 = fieldvalue .get_cloned(optimizer, valuemap) + cf._cached_fields[structvalue2] = fieldvalue2 return cf + def produce_potential_short_preamble_ops(self, optimizer, + potential_ops, descr): + if self._lazy_setfield is not None: + return + for structvalue, op in self._cached_fields_getfield_op.iteritems(): + if op and structvalue in self._cached_fields: + potential_ops[op.result] = op + class BogusPureField(JitException): pass @@ -126,10 +152,10 @@ def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, optimizer, valuemap): new = OptHeap() - return new for descr, d in self.cached_fields.items(): - new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) + new.cached_fields[descr] = d.get_cloned(optimizer, valuemap, short_boxes) + return new for descr, submap in self.cached_arrayitems.items(): newdict = {} @@ -139,6 +165,12 @@ return new + def produce_potential_short_preamble_ops(self, potential_ops): + for descr, d in self.cached_fields.items(): + d.produce_potential_short_preamble_ops(self.optimizer, + potential_ops, descr) + + def clean_caches(self): del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() @@ -208,7 +240,7 @@ self.force_lazy_setfield(fielddescr) try: cf = self.cached_fields[fielddescr] - cf._cached_fields.clear() + cf.clear() except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: @@ -235,11 +267,11 @@ if value is not newvalue: for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: - cf._cached_fields[newvalue] = cf._cached_fields[value] + cf.turned_constant(newvalue, value) for submap in self.cached_arrayitems.itervalues(): for cf in submap.itervalues(): if value in cf._cached_fields: - cf._cached_fields[newvalue] = cf._cached_fields[value] + cf.turned_constant(newvalue, value) def force_lazy_setfield(self, descr): try: @@ -341,7 +373,7 @@ self.emit_operation(op) # then remember the result of reading the field fieldvalue = self.getvalue(op.result) - cf.remember_field_value(structvalue, fieldvalue) + cf.remember_field_value(structvalue, fieldvalue, op) def optimize_SETFIELD_GC(self, op): if self.has_pure_result(rop.GETFIELD_GC_PURE, [op.getarg(0)], From noreply at buildbot.pypy.org Fri Jul 1 08:45:05 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 1 Jul 2011 08:45:05 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: getarrayitem support in short preamble Message-ID: <20110701064505.235A082936@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45212:7548253bd55d Date: 2011-07-01 08:22 +0200 http://bitbucket.org/pypy/pypy/changeset/7548253bd55d/ Log: getarrayitem support in short preamble diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -155,12 +155,11 @@ for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_cloned(optimizer, valuemap, short_boxes) - return new for descr, submap in self.cached_arrayitems.items(): newdict = {} for index, d in submap.items(): - newdict[index] = d.get_reconstructed(optimizer, valuemap) + newdict[index] = d.get_cloned(optimizer, valuemap, short_boxes) new.cached_arrayitems[descr] = newdict return new @@ -169,7 +168,11 @@ for descr, d in self.cached_fields.items(): d.produce_potential_short_preamble_ops(self.optimizer, potential_ops, descr) - + + for descr, submap in self.cached_arrayitems.items(): + for index, d in submap.items(): + d.produce_potential_short_preamble_ops(self.optimizer, + potential_ops, descr) def clean_caches(self): del self._lazy_setfields_and_arrayitems[:] @@ -248,7 +251,7 @@ try: submap = self.cached_arrayitems[arraydescr] for cf in submap.itervalues(): - cf._cached_fields.clear() + cf.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -405,7 +408,7 @@ # the remember the result of reading the array item if cf is not None: fieldvalue = self.getvalue(op.result) - cf.remember_field_value(arrayvalue, fieldvalue) + cf.remember_field_value(arrayvalue, fieldvalue, op) def optimize_SETARRAYITEM_GC(self, op): if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), From noreply at buildbot.pypy.org Fri Jul 1 08:45:06 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 1 Jul 2011 08:45:06 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: hg merge Message-ID: <20110701064506.5C75E82936@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45213:7227eb74c244 Date: 2011-07-01 08:24 +0200 http://bitbucket.org/pypy/pypy/changeset/7227eb74c244/ Log: hg merge diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -845,11 +845,13 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 base = entries[0].f_hash else: base = global_popitem_index.nextindex @@ -865,7 +867,11 @@ entries[0].f_hash = base + counter else: global_popitem_index.nextindex = base + counter - entry = entries[i] + return i + +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) From noreply at buildbot.pypy.org Fri Jul 1 11:30:30 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 1 Jul 2011 11:30:30 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: Meeting from today. Message-ID: <20110701093030.3006582936@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r3814:5a519d6c0813 Date: 2011-07-01 11:37 +0200 http://bitbucket.org/pypy/extradoc/changeset/5a519d6c0813/ Log: Meeting from today. diff --git a/sprintinfo/genova-pegli-2011/sprintplanning.txt b/sprintinfo/genova-pegli-2011/sprintplanning.txt --- a/sprintinfo/genova-pegli-2011/sprintplanning.txt +++ b/sprintinfo/genova-pegli-2011/sprintplanning.txt @@ -3,13 +3,12 @@ 1. cython backend (anto hardshooter) (not done) 2. crowdsourcing as a way to get funded (kickstarter like website? Haskell Industry approach? we need a "we are bloody fast" website (lac, all) (half done) -3. discuss GIL removal plan (arigo, all) (not done) +3. discuss GIL removal plan (arigo, all) DONE 4. embedding pypy as a .so (not done) 5. ootype progress, play with jpype (berdario, anto) (not done) -6. pypy logging improvements (berdario + others) (not done) -7. look in the list of reported bugs and fix them (everybody) (did some) +7. look in the list of reported bugs and fix them (everybody) (did some more) 8. improving the performance of shadowstack (arigo + somebody) (not done) -9. CCP games issues / windows on 64 bit machines (tismer + others) +9. windows on 64 bit machines (tismer + others) (in-progress) 10. status of tealet and enhance it (tismer + arigo) proof of concept works, but only with Boehm 11. work on "success stories" part of pypy.org @@ -21,3 +20,6 @@ try to do more of it. Anto has brought an access point. Maybe this will be better. +12. make a quick demo from the sobel algorithm (anto) +13. investigate the fannkuch benchmark (anto, romain) +14. visiting Genova (done) From noreply at buildbot.pypy.org Fri Jul 1 11:37:05 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 1 Jul 2011 11:37:05 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Add success webpage Message-ID: <20110701093705.E488482936@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r200:c05a212b17d1 Date: 2011-07-01 11:42 +0200 http://bitbucket.org/pypy/pypy.org/changeset/c05a212b17d1/ Log: Add success webpage diff --git a/source/README b/source/README --- a/source/README +++ b/source/README @@ -6,9 +6,8 @@ ampify/environ/yatiblog -o .. -you'll get html output in the parent directory. -Then you can check it in, go to codespeak in /www/pypy.org/htdocs/ -and type "hg pull -u". +you'll get html output in the parent directory. you need an account +on ep.io for updating. Other required dependencies: * "docutils" from "easy_install docutils" diff --git a/source/success.txt b/source/success.txt new file mode 100644 --- /dev/null +++ b/source/success.txt @@ -0,0 +1,27 @@ +--- +layout: page +title: Success stories +--- + +PyPy has been successfully used in production by various people. Here are +few excepts of feedback we received: + +LWN short experiment +-------------------- + +LWN did `an experiment`_ with parsing "git log" and got a speedup from 63s to +21s using PyPy over CPython. + +"In other ways, PyPy is ready for prime time; it implements the (Python 2.x) language faithfully, and it is fast." + +.. _`an experiment`: http://lwn.net/Articles/442268/ + +MyHDL +----- + +MyHDL got speed up by 6-12x according to their `performance page`_, putting +it in the same league as other HDL implementations. + +"By simply changing the Python interpreter, MyHDL is playing in the same league as Verilog and VHDL simulators. This is a remarkable achievement, given that Python's power stays completely available. There is no reason anymore to avoid MyHDL because of performance concerns." + +.. _`performance page`: http://www.myhdl.org/doku.php/performance diff --git a/success.html b/success.html new file mode 100644 --- /dev/null +++ b/success.html @@ -0,0 +1,122 @@ + + + + PyPy :: Success stories + + + + + + + + + + + + + + + +
+ +
+
+
+

Success stories

+

PyPy has been successfully used in production by various people. Here are +few excepts of feedback we received:

+
+

LWN short experiment

+

LWN did an experiment with parsing “git log” and got a speedup from 63s to +21s using PyPy over CPython.

+

“In other ways, PyPy is ready for prime time; it implements the (Python 2.x) language faithfully, and it is fast.”

+
+
+

MyHDL

+

MyHDL got speed up by 6-12x according to their performance page, putting +it in the same league as other HDL implementations.

+

“By simply changing the Python interpreter, MyHDL is playing in the same league as Verilog and VHDL simulators. This is a remarkable achievement, given that Python's power stays completely available. There is no reason anymore to avoid MyHDL because of performance concerns.”

+
+
+ +
+
+
+ + \ No newline at end of file From noreply at buildbot.pypy.org Fri Jul 1 11:37:07 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 1 Jul 2011 11:37:07 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update the template Message-ID: <20110701093707.134B382936@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r201:a5734e608e41 Date: 2011-07-01 11:44 +0200 http://bitbucket.org/pypy/pypy.org/changeset/a5734e608e41/ Log: update the template diff --git a/archive.html b/archive.html --- a/archive.html +++ b/archive.html @@ -40,7 +40,7 @@ -->
- +
diff --git a/compat.html b/compat.html --- a/compat.html +++ b/compat.html @@ -40,7 +40,7 @@
-->
- +
diff --git a/contact.html b/contact.html --- a/contact.html +++ b/contact.html @@ -40,7 +40,7 @@
-->
- +
diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -40,7 +40,7 @@
-->
- +
diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -40,7 +40,7 @@
-->
- +
diff --git a/howtohelp.html b/howtohelp.html --- a/howtohelp.html +++ b/howtohelp.html @@ -40,7 +40,7 @@
-->
- +
diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -40,7 +40,7 @@
-->
- +
diff --git a/source/_layouts/site.genshi b/source/_layouts/site.genshi --- a/source/_layouts/site.genshi +++ b/source/_layouts/site.genshi @@ -6,6 +6,7 @@ 'code': [ ('Home', 'index.html'), ('Features', 'features.html'), + ('Success stories', 'success.html'), ('Download', 'download.html'), ('Compatibility', 'compat.html'), ('Performance', 'http://speed.pypy.org'), diff --git a/success.html b/success.html --- a/success.html +++ b/success.html @@ -40,7 +40,7 @@
-->
- +
From noreply at buildbot.pypy.org Fri Jul 1 11:42:08 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 1 Jul 2011 11:42:08 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: import the benchmark Message-ID: <20110701094208.1CDBC82936@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3815:3d56fe3ca53b Date: 2011-07-01 11:42 +0200 http://bitbucket.org/pypy/extradoc/changeset/3d56fe3ca53b/ Log: import the benchmark diff --git a/talk/ctpug2011/src/count.py b/talk/ctpug2011/src/count.py new file mode 100644 --- /dev/null +++ b/talk/ctpug2011/src/count.py @@ -0,0 +1,23 @@ +import sys +import time + +def count_mult_of_5(N): + mult = 0 + not_mult = 0 + for i in range(N): + if i % 5 == 0: + mult += 1 + else: + not_mult += 1 + return mult, not_mult + +def main(): + N = int(sys.argv[1]) + start = time.clock() + count = count_mult_of_5(N) + end = time.clock() + print 'count: ', count + print 'time:', end-start, 'secs' + +if __name__ == '__main__': + main() From noreply at buildbot.pypy.org Fri Jul 1 11:42:09 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 1 Jul 2011 11:42:09 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: merge Message-ID: <20110701094209.481EE82936@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3816:74a9317c6e25 Date: 2011-07-01 11:49 +0200 http://bitbucket.org/pypy/extradoc/changeset/74a9317c6e25/ Log: merge diff --git a/talk/ctpug2011/src/count.py b/talk/ctpug2011/src/count.py new file mode 100644 --- /dev/null +++ b/talk/ctpug2011/src/count.py @@ -0,0 +1,23 @@ +import sys +import time + +def count_mult_of_5(N): + mult = 0 + not_mult = 0 + for i in range(N): + if i % 5 == 0: + mult += 1 + else: + not_mult += 1 + return mult, not_mult + +def main(): + N = int(sys.argv[1]) + start = time.clock() + count = count_mult_of_5(N) + end = time.clock() + print 'count: ', count + print 'time:', end-start, 'secs' + +if __name__ == '__main__': + main() From noreply at buildbot.pypy.org Fri Jul 1 14:12:21 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 1 Jul 2011 14:12:21 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update urls (also fix the typo, thank you flymake Message-ID: <20110701121221.1FFDC82936@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r202:b760bec18802 Date: 2011-07-01 14:19 +0200 http://bitbucket.org/pypy/pypy.org/changeset/b760bec18802/ Log: update urls (also fix the typo, thank you flymake diff --git a/js/detect.js b/js/detect.js --- a/js/detect.js +++ b/js/detect.js @@ -1,20 +1,21 @@ $(document).ready(function() { var download_url, download_text; + var base = 'http://bitbucket.org/pypy/pypy/downloads/'; if (navigator.platform.indexOf('Linux') != -1) { if (navigator.platform.indexOf('64') != -1) { - download_url = 'download/pypy-1.5-linux64.tar.bz2'; + download_url = base + 'pypy-1.5-linux64.tar.bz2'; download_text = 'Download linux x86-64 bin'; } else { - download_url = 'download/pypy-1.5-linux.tar.bz2'; + download_url = base + 'pypy-1.5-linux.tar.bz2'; download_text = 'Download linux x86 bin (32 bit)'; } } else if (navigator.platform.indexOf('Win') != -1) { - download_url = 'download/pypy-1.5-win32.zip'; + download_url = base + 'pypy-1.5-win32.zip'; download_text = 'Download Windows x86 bin'; } else if (navigator.platform.indexOf('Mac') != 1) { - download_url = 'download/pypy-1.5-osx64.tar.bz2'; - downloat_text = 'Download Mac OS X 10.6 bin (64 bit)'; + download_url = base + 'pypy-1.5-osx64.tar.bz2'; + download_text = 'Download Mac OS X 10.6 bin (64 bit)'; } else { download_url = "download.html"; download_text = "Download page"; From noreply at buildbot.pypy.org Fri Jul 1 14:18:30 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 1 Jul 2011 14:18:30 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: merge up to 9ccaeaff6e07 Message-ID: <20110701121830.386A582936@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45214:1372220cf8f6 Date: 2011-06-30 16:00 +0200 http://bitbucket.org/pypy/pypy/changeset/1372220cf8f6/ Log: merge up to 9ccaeaff6e07 diff --git a/pypy/doc/_ref.txt b/pypy/doc/_ref.txt --- a/pypy/doc/_ref.txt +++ b/pypy/doc/_ref.txt @@ -1,3 +1,4 @@ +.. _`ctypes_configure/doc/sample.py`: https://bitbucket.org/pypy/pypy/src/default/ctypes_configure/doc/sample.py .. _`demo/`: https://bitbucket.org/pypy/pypy/src/default/demo/ .. _`demo/pickle_coroutine.py`: https://bitbucket.org/pypy/pypy/src/default/demo/pickle_coroutine.py .. _`lib-python/`: https://bitbucket.org/pypy/pypy/src/default/lib-python/ diff --git a/pypy/doc/ctypes-implementation.rst b/pypy/doc/ctypes-implementation.rst --- a/pypy/doc/ctypes-implementation.rst +++ b/pypy/doc/ctypes-implementation.rst @@ -137,7 +137,27 @@ ctypes configure ================= -We also released `ctypes-configure`_, which is an experimental package trying to -approach the portability issues of ctypes-based code. +We also released ``ctypes-configure``, which is an experimental package +trying to approach the portability issues of ctypes-based code. -.. _`ctypes-configure`: http://codespeak.net/~fijal/configure.html +idea +---- + +One of ctypes problems is that ctypes programs are usually not very +platform-independent. We created ctypes_configure, which invokes c +compiler (via distutils) for various platform-dependent details like +exact sizes of types (for example size_t), ``#defines``, exact outline of +structures etc. It replaces in this regard code generator (h2py). + +installation +------------ + +``easy_install ctypes_configure`` + +usage +----- + +`ctypes_configure/doc/sample.py`_ explains in details how to use it. + + +.. include:: _ref.txt diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -42,7 +42,7 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. -.. _`ctypes-configure`: http://codespeak.net/~fijal/configure.html +.. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure Pros ---- diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -300,6 +300,6 @@ .. _`CLI backend`: cli-backend.html .. _`Boehm-Demers-Weiser garbage collector`: http://www.hpl.hp.com/personal/Hans_Boehm/gc/ .. _clr: clr-module.html -.. _`CPythons core language regression tests`: http://codespeak.net:8099/summary?category=applevel&branch=%3Ctrunk%3E +.. _`CPythons core language regression tests`: http://buildbot.pypy.org/summary?category=applevel&branch=%3Ctrunk%3E .. include:: _ref.txt diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -141,15 +141,6 @@ You can also find CPython's compliance tests run with compiled ``pypy-c`` executables there. -information dating from early 2007: - -`PyPy LOC statistics`_ shows LOC statistics about PyPy. - -`PyPy statistics`_ is a page with various statistics about the PyPy project. - -`compatibility matrix`_ is a diagram that shows which of the various features -of the PyPy interpreter work together with which other features. - Source Code Documentation =============================================== @@ -207,8 +198,6 @@ .. _`development methodology`: dev_method.html .. _`sprint reports`: sprint-reports.html .. _`papers, talks and related projects`: extradoc.html -.. _`PyPy LOC statistics`: http://codespeak.net/~hpk/pypy-stat/ -.. _`PyPy statistics`: http://codespeak.net/pypy/trunk/pypy/doc/statistic .. _`object spaces`: objspace.html .. _`interpreter optimizations`: interpreter-optimizations.html .. _`translation`: translation.html @@ -222,7 +211,7 @@ .. _`bytecode interpreter`: interpreter.html .. _`EU reports`: index-report.html .. _`Technical reports`: index-report.html -.. _`summary`: http://codespeak.net:8099/summary +.. _`summary`: http://buildbot.pypy.org/summary .. _`ideas for PyPy related projects`: project-ideas.html .. _`Nightly builds and benchmarks`: http://tuatara.cs.uni-duesseldorf.de/benchmark.html .. _`directory reference`: @@ -360,7 +349,6 @@ .. _Mono: http://www.mono-project.com/ .. _`"standard library"`: rlib.html .. _`graph viewer`: getting-started-dev.html#try-out-the-translator -.. _`compatibility matrix`: image/compat-matrix.png .. The following documentation is important and reasonably up-to-date: diff --git a/pypy/doc/video-index.rst b/pypy/doc/video-index.rst --- a/pypy/doc/video-index.rst +++ b/pypy/doc/video-index.rst @@ -42,11 +42,11 @@ Trailer: PyPy at the PyCon 2006 ------------------------------- -130mb: http://codespeak.net/download/pypy/video/pycon-trailer.avi.torrent +130mb: http://wyvern.cs.uni-duesseldorf.de/torrent/pycon-trailer.avi.torrent -71mb: http://codespeak.net/download/pypy/video/pycon-trailer-medium.avi.torrent +71mb: http://wyvern.cs.uni-duesseldorf.de/torrent/pycon-trailer-medium.avi.torrent -50mb: http://codespeak.net/download/pypy/video/pycon-trailer-320x240.avi.torrent +50mb: http://wyvern.cs.uni-duesseldorf.de/torrent/pycon-trailer-320x240.avi.torrent .. image:: image/pycon-trailer.jpg :scale: 100 @@ -62,9 +62,9 @@ Interview with Tim Peters ------------------------- -440mb: http://codespeak.net/download/pypy/video/interview-timpeters-v2.avi.torrent +440mb: http://wyvern.cs.uni-duesseldorf.de/torrent/interview-timpeters-v2.avi.torrent -138mb: http://codespeak.net/download/pypy/video/interview-timpeters-320x240.avi.torrent +138mb: http://wyvern.cs.uni-duesseldorf.de/torrent/interview-timpeters-320x240.avi.torrent .. image:: image/interview-timpeters.jpg :scale: 100 @@ -82,9 +82,9 @@ Interview with Bob Ippolito --------------------------- -155mb: http://codespeak.net/download/pypy/video/interview-bobippolito-v2.avi.torrent +155mb: http://wyvern.cs.uni-duesseldorf.de/torrent/interview-bobippolito-v2.avi.torrent -50mb: http://codespeak.net/download/pypy/video/interview-bobippolito-320x240.avi.torrent +50mb: http://wyvern.cs.uni-duesseldorf.de/torrent/interview-bobippolito-320x240.avi.torrent .. image:: image/interview-bobippolito.jpg :scale: 100 @@ -102,9 +102,9 @@ Introductory talk on PyPy ------------------------- -430mb: http://codespeak.net/download/pypy/video/introductory-talk-pycon-v1.avi.torrent +430mb: http://wyvern.cs.uni-duesseldorf.de/torrent/introductory-talk-pycon-v1.avi.torrent -166mb: http://codespeak.net/download/pypy/video/introductory-talk-pycon-320x240.avi.torrent +166mb: http://wyvern.cs.uni-duesseldorf.de/torrent/introductory-talk-pycon-320x240.avi.torrent .. image:: image/introductory-talk-pycon.jpg :scale: 100 @@ -125,9 +125,9 @@ Talk on Agile Open Source Methods in the PyPy project ----------------------------------------------------- -395mb: http://codespeak.net/download/pypy/video/agile-talk-v1.avi.torrent +395mb: http://wyvern.cs.uni-duesseldorf.de/torrent/agile-talk-v1.avi.torrent -153mb: http://codespeak.net/download/pypy/video/agile-talk-320x240.avi.torrent +153mb: http://wyvern.cs.uni-duesseldorf.de/torrent/agile-talk-320x240.avi.torrent .. image:: image/agile-talk.jpg :scale: 100 @@ -148,9 +148,9 @@ PyPy Architecture session ------------------------- -744mb: http://codespeak.net/download/pypy/video/architecture-session-v1.avi.torrent +744mb: http://wyvern.cs.uni-duesseldorf.de/torrent/architecture-session-v1.avi.torrent -288mb: http://codespeak.net/download/pypy/video/architecture-session-320x240.avi.torrent +288mb: http://wyvern.cs.uni-duesseldorf.de/torrent/architecture-session-320x240.avi.torrent .. image:: image/architecture-session.jpg :scale: 100 @@ -171,9 +171,9 @@ Sprint tutorial --------------- -680mb: http://codespeak.net/download/pypy/video/sprint-tutorial-v2.avi.torrent +680mb: http://wyvern.cs.uni-duesseldorf.de/torrent/sprint-tutorial-v2.avi.torrent -263mb: http://codespeak.net/download/pypy/video/sprint-tutorial-320x240.avi.torrent +263mb: http://wyvern.cs.uni-duesseldorf.de/torrent/sprint-tutorial-320x240.avi.torrent .. image:: image/sprint-tutorial.jpg :scale: 100 @@ -190,9 +190,9 @@ Scripting .NET with IronPython by Jim Hugunin --------------------------------------------- -372mb: http://codespeak.net/download/pypy/video/ironpython-talk-v2.avi.torrent +372mb: http://wyvern.cs.uni-duesseldorf.de/torrent/ironpython-talk-v2.avi.torrent -270mb: http://codespeak.net/download/pypy/video/ironpython-talk-320x240.avi.torrent +270mb: http://wyvern.cs.uni-duesseldorf.de/torrent/ironpython-talk-320x240.avi.torrent .. image:: image/ironpython.jpg :scale: 100 @@ -209,9 +209,9 @@ Bram Cohen, founder and developer of BitTorrent ----------------------------------------------- -509mb: http://codespeak.net/download/pypy/video/bram-cohen-interview-v1.avi.torrent +509mb: http://wyvern.cs.uni-duesseldorf.de/torrent/bram-cohen-interview-v1.avi.torrent -370mb: http://codespeak.net/download/pypy/video/bram-cohen-interview-320x240.avi.torrent +370mb: http://wyvern.cs.uni-duesseldorf.de/torrent/bram-cohen-interview-320x240.avi.torrent .. image:: image/bram.jpg :scale: 100 @@ -226,9 +226,9 @@ Keynote speech by Guido van Rossum on the new Python 2.5 features ----------------------------------------------------------------- -695mb: http://codespeak.net/download/pypy/video/keynote-speech_guido-van-rossum_v1.avi.torrent +695mb: http://wyvern.cs.uni-duesseldorf.de/torrent/keynote-speech_guido-van-rossum_v1.avi.torrent -430mb: http://codespeak.net/download/pypy/video/keynote-speech_guido-van-rossum_320x240.avi.torrent +430mb: http://wyvern.cs.uni-duesseldorf.de/torrent/keynote-speech_guido-van-rossum_320x240.avi.torrent .. image:: image/guido.jpg :scale: 100 @@ -243,11 +243,11 @@ Trailer: PyPy sprint at the University of Palma de Mallorca ----------------------------------------------------------- -166mb: http://codespeak.net/download/pypy/video/mallorca-trailer-v1.avi.torrent +166mb: http://wyvern.cs.uni-duesseldorf.de/torrent/mallorca-trailer-v1.avi.torrent -88mb: http://codespeak.net/download/pypy/video/mallorca-trailer-medium.avi.torrent +88mb: http://wyvern.cs.uni-duesseldorf.de/torrent/mallorca-trailer-medium.avi.torrent -64mb: http://codespeak.net/download/pypy/video/mallorca-trailer-320x240.avi.torrent +64mb: http://wyvern.cs.uni-duesseldorf.de/torrent/mallorca-trailer-320x240.avi.torrent .. image:: image/mallorca-trailer.jpg :scale: 100 @@ -262,9 +262,9 @@ Coding discussion of core developers Armin Rigo and Samuele Pedroni ------------------------------------------------------------------- -620mb: http://codespeak.net/download/pypy/video/coding-discussion-v1.avi.torrent +620mb: http://wyvern.cs.uni-duesseldorf.de/torrent/coding-discussion-v1.avi.torrent -240mb: http://codespeak.net/download/pypy/video/coding-discussion-320x240.avi.torrent +240mb: http://wyvern.cs.uni-duesseldorf.de/torrent/coding-discussion-320x240.avi.torrent .. image:: image/coding-discussion.jpg :scale: 100 @@ -279,9 +279,9 @@ PyPy technical talk at the University of Palma de Mallorca ---------------------------------------------------------- -865mb: http://codespeak.net/download/pypy/video/introductory-student-talk-v2.avi.torrent +865mb: http://wyvern.cs.uni-duesseldorf.de/torrent/introductory-student-talk-v2.avi.torrent -437mb: http://codespeak.net/download/pypy/video/introductory-student-talk-320x240.avi.torrent +437mb: http://wyvern.cs.uni-duesseldorf.de/torrent/introductory-student-talk-320x240.avi.torrent .. image:: image/introductory-student-talk.jpg :scale: 100 diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -304,7 +304,12 @@ self.unimport_module(name) self.cleanup_references(self.space) if self.check_and_print_leaks(): - assert False, "Test leaks or loses object(s)." + assert False, ( + "Test leaks or loses object(s). You should also check if " + "the test actually passed in the first place; if it failed " + "it is likely to reach this place.") + # XXX find out how to disable check_and_print_leaks() if the + # XXX test failed... class AppTestCpythonExtension(AppTestCpythonExtensionBase): diff --git a/pypy/module/cpyext/test/test_structseq.py b/pypy/module/cpyext/test/test_structseq.py --- a/pypy/module/cpyext/test/test_structseq.py +++ b/pypy/module/cpyext/test/test_structseq.py @@ -30,6 +30,7 @@ """ PyObject *seq; PyStructSequence_InitType(&PyDatatype, &Data_desc); + if (PyErr_Occurred()) return NULL; seq = PyStructSequence_New(&PyDatatype); if (!seq) return NULL; PyStructSequence_SET_ITEM(seq, 0, PyInt_FromLong(42)); diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -29,7 +29,18 @@ raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) def impl_setitem_str(self, name, w_value): - self.w_type.setdictvalue(self.space, name, w_value) + try: + self.w_type.setdictvalue(self.space, name, w_value) + except OperationError, e: + if not e.match(self.space, self.space.w_TypeError): + raise + w_type = self.w_type + if not w_type.is_cpytype(): + raise + # xxx obscure workaround: allow cpyext to write to type->tp_dict. + # xxx like CPython, we assume that this is only done early after + # xxx the type is created, and we don't invalidate any cache. + w_type.dict_w[name] = w_value def impl_setdefault(self, w_key, w_default): space = self.space diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -32,22 +32,6 @@ reprlist = [repr(w_item) for w_item in w_self.setdata.keys()] return "<%s(%s)>" % (w_self.__class__.__name__, ', '.join(reprlist)) - def _newobj(w_self, space, rdict_w=None): - """Make a new set or frozenset by taking ownership of 'rdict_w'.""" - #return space.call(space.type(w_self),W_SetIterObject(rdict_w)) - objtype = type(w_self) - if objtype is W_SetObject: - w_obj = W_SetObject(space, rdict_w) - elif objtype is W_FrozensetObject: - w_obj = W_FrozensetObject(space, rdict_w) - else: - w_type = space.type(w_self) - _, w_newdescr = w_type.lookup_where('__new__') - w_newfunc = space.get(w_newdescr, w_type) - w_itemiterator = W_SetIterObject(rdict_w) - w_obj = space.call_function(w_newfunc, w_type, w_itemiterator) - return w_obj - _lifeline_ = None def getweakref(self): return self._lifeline_ @@ -57,10 +41,28 @@ class W_SetObject(W_BaseSetObject): from pypy.objspace.std.settype import set_typedef as typedef + def _newobj(w_self, space, rdict_w): + """Make a new set by taking ownership of 'rdict_w'.""" + if type(w_self) is W_SetObject: + return W_SetObject(space, rdict_w) + w_type = space.type(w_self) + w_obj = space.allocate_instance(W_SetObject, w_type) + W_SetObject.__init__(w_obj, space, rdict_w) + return w_obj + class W_FrozensetObject(W_BaseSetObject): from pypy.objspace.std.frozensettype import frozenset_typedef as typedef hash = 0 + def _newobj(w_self, space, rdict_w): + """Make a new frozenset by taking ownership of 'rdict_w'.""" + if type(w_self) is W_FrozensetObject: + return W_FrozensetObject(space, rdict_w) + w_type = space.type(w_self) + w_obj = space.allocate_instance(W_FrozensetObject, w_type) + W_FrozensetObject.__init__(w_obj, space, rdict_w) + return w_obj + registerimplementation(W_BaseSetObject) registerimplementation(W_SetObject) registerimplementation(W_FrozensetObject) diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -57,6 +57,32 @@ b = a | set('abc') assert type(b) is subset + def test_init_new_behavior(self): + s = set.__new__(set, 'abc') + assert s == set() # empty + s.__init__('def') + assert s == set('def') + # + s = frozenset.__new__(frozenset, 'abc') + assert s == frozenset('abc') # non-empty + s.__init__('def') + assert s == frozenset('abc') # the __init__ is ignored + + def test_subtype_bug(self): + class subset(set): pass + b = subset('abc') + subset.__new__ = lambda *args: foobar # not called + b = b.copy() + assert type(b) is subset + assert set(b) == set('abc') + # + class frozensubset(frozenset): pass + b = frozensubset('abc') + frozensubset.__new__ = lambda *args: foobar # not called + b = b.copy() + assert type(b) is frozensubset + assert frozenset(b) == frozenset('abc') + def test_union(self): a = set([4, 5]) b = a.union([5, 7]) @@ -131,11 +157,6 @@ assert s1 is not s2 assert s1 == s2 assert type(s2) is myfrozen - class myfrozen(frozenset): - def __new__(cls): - return frozenset.__new__(cls, 'abc') - s1 = myfrozen() - raises(TypeError, s1.copy) def test_update(self): s1 = set('abc') From noreply at buildbot.pypy.org Fri Jul 1 14:18:32 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 1 Jul 2011 14:18:32 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: merge 98d5562c9322 (out of line guards) Message-ID: <20110701121832.5F0C882936@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45215:5f9517d7f75b Date: 2011-06-30 16:08 +0200 http://bitbucket.org/pypy/pypy/changeset/5f9517d7f75b/ Log: merge 98d5562c9322 (out of line guards) diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py --- a/pypy/annotation/description.py +++ b/pypy/annotation/description.py @@ -3,7 +3,6 @@ from pypy.interpreter.pycode import cpython_code_signature from pypy.interpreter.argument import rawshape from pypy.interpreter.argument import ArgErr -from pypy.interpreter.function import Defaults from pypy.tool.sourcetools import valid_identifier from pypy.tool.pairtype import extendabletype @@ -251,7 +250,7 @@ for x in defaults: defs_s.append(self.bookkeeper.immutablevalue(x)) try: - inputcells = args.match_signature(signature, Defaults(defs_s)) + inputcells = args.match_signature(signature, defs_s) except ArgErr, e: raise TypeError, "signature mismatch: %s" % e.getmsg(self.name) return inputcells @@ -638,16 +637,19 @@ return None def maybe_return_immutable_list(self, attr, s_result): - # hack: 'x.lst' where lst is listed in _immutable_fields_ as 'lst[*]' + # hack: 'x.lst' where lst is listed in _immutable_fields_ as + # either 'lst[*]' or 'lst?[*]' # should really return an immutable list as a result. Implemented # by changing the result's annotation (but not, of course, doing an # actual copy in the rtyper). Tested in pypy.rpython.test.test_rlist, # test_immutable_list_out_of_instance. - search = '%s[*]' % (attr,) + search1 = '%s[*]' % (attr,) + search2 = '%s?[*]' % (attr,) cdesc = self while cdesc is not None: if '_immutable_fields_' in cdesc.classdict: - if search in cdesc.classdict['_immutable_fields_'].value: + if (search1 in cdesc.classdict['_immutable_fields_'].value or + search2 in cdesc.classdict['_immutable_fields_'].value): s_result.listdef.never_resize() s_copy = s_result.listdef.offspring() s_copy.listdef.mark_as_immutable() diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py --- a/pypy/annotation/test/test_annrpython.py +++ b/pypy/annotation/test/test_annrpython.py @@ -3398,6 +3398,20 @@ s = a.build_types(f, [int]) assert s.listdef.listitem.immutable + def test_return_immutable_list_quasiimmut_field(self): + class A: + _immutable_fields_ = 'lst?[*]' + def f(n): + a = A() + l1 = [n, 0] + l1[1] = n+1 + a.lst = l1 + return a.lst + + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.listdef.listitem.immutable + def test_immutable_list_is_actually_resized(self): class A: _immutable_fields_ = 'lst[*]' diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -239,7 +239,7 @@ ### Parsing for function calls ### - def _match_signature(self, w_firstarg, scope_w, signature, defaults=None, + def _match_signature(self, w_firstarg, scope_w, signature, defaults_w=None, blindargs=0): """Parse args and kwargs according to the signature of a code object, or raise an ArgErr in case of failure. @@ -247,20 +247,20 @@ """ if jit.we_are_jitted() and self._dont_jit: return self._match_signature_jit_opaque(w_firstarg, scope_w, - signature, defaults, + signature, defaults_w, blindargs) return self._really_match_signature(w_firstarg, scope_w, signature, - defaults, blindargs) + defaults_w, blindargs) @jit.dont_look_inside def _match_signature_jit_opaque(self, w_firstarg, scope_w, signature, - defaults, blindargs): + defaults_w, blindargs): return self._really_match_signature(w_firstarg, scope_w, signature, - defaults, blindargs) + defaults_w, blindargs) @jit.unroll_safe - def _really_match_signature(self, w_firstarg, scope_w, signature, defaults=None, - blindargs=0): + def _really_match_signature(self, w_firstarg, scope_w, signature, + defaults_w=None, blindargs=0): # # args_w = list of the normal actual parameters, wrapped # kwds_w = real dictionary {'keyword': wrapped parameter} @@ -327,7 +327,7 @@ elif avail > co_argcount: raise ArgErrCount(avail, num_kwds, co_argcount, has_vararg, has_kwarg, - defaults, 0) + defaults_w, 0) # the code assumes that keywords can potentially be large, but that # argnames is typically not too large @@ -357,12 +357,13 @@ num_remainingkwds -= 1 missing = 0 if input_argcount < co_argcount: - def_first = co_argcount - (0 if defaults is None else defaults.getlen()) + def_first = co_argcount - (0 if defaults_w is None else len(defaults_w)) for i in range(input_argcount, co_argcount): if scope_w[i] is not None: - pass - elif i >= def_first: - scope_w[i] = defaults.getitem(i - def_first) + continue + defnum = i - def_first + if defnum >= 0: + scope_w[i] = defaults_w[defnum] else: # error: not enough arguments. Don't signal it immediately # because it might be related to a problem with */** or @@ -382,20 +383,20 @@ if co_argcount == 0: raise ArgErrCount(avail, num_kwds, co_argcount, has_vararg, has_kwarg, - defaults, missing) + defaults_w, missing) raise ArgErrUnknownKwds(num_remainingkwds, keywords, used_keywords) if missing: raise ArgErrCount(avail, num_kwds, co_argcount, has_vararg, has_kwarg, - defaults, missing) + defaults_w, missing) return co_argcount + has_vararg + has_kwarg def parse_into_scope(self, w_firstarg, - scope_w, fnname, signature, defaults=None): + scope_w, fnname, signature, defaults_w=None): """Parse args and kwargs to initialize a frame according to the signature of code object. Store the argumentvalues into scope_w. @@ -403,29 +404,29 @@ """ try: return self._match_signature(w_firstarg, - scope_w, signature, defaults, 0) + scope_w, signature, defaults_w, 0) except ArgErr, e: raise OperationError(self.space.w_TypeError, self.space.wrap(e.getmsg(fnname))) - def _parse(self, w_firstarg, signature, defaults, blindargs=0): + def _parse(self, w_firstarg, signature, defaults_w, blindargs=0): """Parse args and kwargs according to the signature of a code object, or raise an ArgErr in case of failure. """ scopelen = signature.scope_length() scope_w = [None] * scopelen - self._match_signature(w_firstarg, scope_w, signature, defaults, + self._match_signature(w_firstarg, scope_w, signature, defaults_w, blindargs) return scope_w def parse_obj(self, w_firstarg, - fnname, signature, defaults=None, blindargs=0): + fnname, signature, defaults_w=None, blindargs=0): """Parse args and kwargs to initialize a frame according to the signature of code object. """ try: - return self._parse(w_firstarg, signature, defaults, blindargs) + return self._parse(w_firstarg, signature, defaults_w, blindargs) except ArgErr, e: raise OperationError(self.space.w_TypeError, self.space.wrap(e.getmsg(fnname))) @@ -474,23 +475,23 @@ - def _match_signature(self, w_firstarg, scope_w, signature, defaults=None, + def _match_signature(self, w_firstarg, scope_w, signature, defaults_w=None, blindargs=0): self.combine_if_necessary() # _match_signature is destructive return Arguments._match_signature( self, w_firstarg, scope_w, signature, - defaults, blindargs) + defaults_w, blindargs) def unpack(self): self.combine_if_necessary() return Arguments.unpack(self) - def match_signature(self, signature, defaults): + def match_signature(self, signature, defaults_w): """Parse args and kwargs according to the signature of a code object, or raise an ArgErr in case of failure. """ - return self._parse(None, signature, defaults) + return self._parse(None, signature, defaults_w) def unmatch_signature(self, signature, data_w): """kind of inverse of match_signature""" @@ -603,12 +604,12 @@ class ArgErrCount(ArgErr): def __init__(self, got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg, - defaults, missing_args): + defaults_w, missing_args): self.expected_nargs = expected_nargs self.has_vararg = has_vararg self.has_kwarg = has_kwarg - self.num_defaults = 0 if defaults is None else defaults.getlen() + self.num_defaults = 0 if defaults_w is None else len(defaults_w) self.missing_args = missing_args self.num_args = got_nargs self.num_kwds = nkwds diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -21,28 +21,6 @@ assert not func.can_change_code return func.code -class Defaults(object): - _immutable_fields_ = ["items[*]", "promote"] - - def __init__(self, items, promote=False): - self.items = items - self.promote = promote - - def getitems(self): - # an idea - we want to promote only items that we know won't change - # too often. this is the case for builtin functions and functions - # with known constant defaults. Otherwise we don't want to promote - # this so lambda a=a won't create a new trace each time it's - # encountered - if self.promote: - return jit.hint(self, promote=True).items - return self.items - - def getitem(self, idx): - return self.getitems()[idx] - - def getlen(self): - return len(self.getitems()) class Function(Wrappable): """A function is a code object captured with some environment: @@ -50,17 +28,20 @@ and an arbitrary 'closure' passed to the code object.""" can_change_code = True + _immutable_fields_ = ['code?', + 'w_func_globals?', + 'closure?', + 'defs_w?[*]'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, - forcename=None, promote_defs=False): + forcename=None): self.space = space self.name = forcename or code.co_name self.w_doc = None # lazily read from code.getdocstring() self.code = code # Code instance self.w_func_globals = w_globals # the globals dictionary self.closure = closure # normally, list of Cell instances or None - self.defs = Defaults(defs_w, promote=promote_defs) - # wrapper around list of w_default's + self.defs_w = defs_w self.w_func_dict = None # filled out below if needed self.w_module = None @@ -157,7 +138,7 @@ return self._flat_pycall(code, nargs, frame) elif fast_natural_arity & Code.FLATPYCALL: natural_arity = fast_natural_arity & 0xff - if natural_arity > nargs >= natural_arity - self.defs.getlen(): + if natural_arity > nargs >= natural_arity - len(self.defs_w): assert isinstance(code, PyCode) return self._flat_pycall_defaults(code, nargs, frame, natural_arity - nargs) @@ -190,12 +171,11 @@ w_arg = frame.peekvalue(nargs-1-i) new_frame.fastlocals_w[i] = w_arg - defs = self.defs - ndefs = defs.getlen() + ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = defs.getitem(j) + new_frame.fastlocals_w[i] = self.defs_w[j] i += 1 return new_frame.run() @@ -311,7 +291,7 @@ w(self.code), w_func_globals, w_closure, - nt(self.defs.getitems()), + nt(self.defs_w), w_func_dict, self.w_module, ] @@ -346,11 +326,11 @@ if space.is_w(w_func_dict, space.w_None): w_func_dict = None self.w_func_dict = w_func_dict - self.defs = Defaults(space.fixedview(w_defs)) + self.defs_w = space.fixedview(w_defs) self.w_module = w_module def fget_func_defaults(self, space): - values_w = self.defs.getitems() + values_w = self.defs_w # the `None in values_w` check here is to ensure that interp-level # functions with a default of NoneNotWrapped do not get their defaults # exposed at applevel @@ -360,14 +340,14 @@ def fset_func_defaults(self, space, w_defaults): if space.is_w(w_defaults, space.w_None): - self.defs = Defaults([]) + self.defs_w = [] return if not space.is_true(space.isinstance(w_defaults, space.w_tuple)): raise OperationError( space.w_TypeError, space.wrap("func_defaults must be set to a tuple object or None") ) - self.defs = Defaults(space.fixedview(w_defaults)) + self.defs_w = space.fixedview(w_defaults) def fdel_func_defaults(self, space): - self.defs = Defaults([]) + self.defs_w = [] def fget_func_doc(self, space): if self.w_doc is None: @@ -448,6 +428,7 @@ class Method(Wrappable): """A method is a function bound to a specific instance or class.""" + _immutable_fields_ = ['w_function', 'w_instance', 'w_class'] def __init__(self, space, w_function, w_instance, w_class): self.space = space @@ -631,8 +612,7 @@ def __init__(self, func): assert isinstance(func, Function) Function.__init__(self, func.space, func.code, func.w_func_globals, - func.defs.getitems(), func.closure, func.name, - promote_defs=True) + func.defs_w, func.closure, func.name) self.w_doc = func.w_doc self.w_func_dict = func.w_func_dict self.w_module = func.w_module diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -594,7 +594,7 @@ space = func.space activation = self.activation scope_w = args.parse_obj(w_obj, func.name, self.sig, - func.defs, self.minargs) + func.defs_w, self.minargs) try: w_result = activation._run(space, scope_w) except DescrMismatch: diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -7,6 +7,7 @@ class GeneratorIterator(Wrappable): "An iterator created by a generator." + _immutable_fields_ = ['pycode'] def __init__(self, frame): self.space = frame.space diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -204,7 +204,7 @@ fresh_virtualizable=True) args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, func.name, - sig, func.defs) + sig, func.defs_w) fresh_frame.init_cells() return frame.run() @@ -217,7 +217,7 @@ fresh_virtualizable=True) args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, func.name, - sig, func.defs) + sig, func.defs_w) fresh_frame.init_cells() return frame.run() diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1197,6 +1197,7 @@ WHY_CONTINUE, SContinueLoop WHY_YIELD not needed """ + _immutable_ = True def nomoreblocks(self): raise BytecodeCorruption("misplaced bytecode - should not return") @@ -1207,6 +1208,7 @@ class SReturnValue(SuspendedUnroller): """Signals a 'return' statement. Argument is the wrapped object to return.""" + _immutable_ = True kind = 0x01 def __init__(self, w_returnvalue): self.w_returnvalue = w_returnvalue @@ -1222,6 +1224,7 @@ class SApplicationException(SuspendedUnroller): """Signals an application-level exception (i.e. an OperationException).""" + _immutable_ = True kind = 0x02 def __init__(self, operr): self.operr = operr @@ -1236,6 +1239,7 @@ class SBreakLoop(SuspendedUnroller): """Signals a 'break' statement.""" + _immutable_ = True kind = 0x04 def state_unpack_variables(self, space): @@ -1249,6 +1253,7 @@ class SContinueLoop(SuspendedUnroller): """Signals a 'continue' statement. Argument is the bytecode position of the beginning of the loop.""" + _immutable_ = True kind = 0x08 def __init__(self, jump_to): self.jump_to = jump_to @@ -1261,10 +1266,11 @@ class FrameBlock(object): - """Abstract base class for frame blocks from the blockstack, used by the SETUP_XXX and POP_BLOCK opcodes.""" + _immutable_ = True + def __init__(self, frame, handlerposition): self.handlerposition = handlerposition self.valuestackdepth = frame.valuestackdepth @@ -1306,6 +1312,7 @@ class LoopBlock(FrameBlock): """A loop block. Stores the end-of-loop pointer in case of 'break'.""" + _immutable_ = True _opname = 'SETUP_LOOP' handling_mask = SBreakLoop.kind | SContinueLoop.kind @@ -1325,6 +1332,7 @@ class ExceptBlock(FrameBlock): """An try:except: block. Stores the position of the exception handler.""" + _immutable_ = True _opname = 'SETUP_EXCEPT' handling_mask = SApplicationException.kind @@ -1349,6 +1357,7 @@ class FinallyBlock(FrameBlock): """A try:finally: block. Stores the position of the exception handler.""" + _immutable_ = True _opname = 'SETUP_FINALLY' handling_mask = -1 # handles every kind of SuspendedUnroller @@ -1376,6 +1385,8 @@ class WithBlock(FinallyBlock): + _immutable_ = True + def really_handle(self, frame, unroller): if (frame.space.full_exceptions and isinstance(unroller, SApplicationException)): diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -3,7 +3,6 @@ ArgErr, ArgErrUnknownKwds, ArgErrMultipleValues, ArgErrCount, rawshape, Signature) from pypy.interpreter.error import OperationError -from pypy.interpreter.function import Defaults class TestSignature(object): @@ -184,7 +183,7 @@ py.test.raises(ArgErr, args._match_signature, None, l, Signature(["a"], "*")) args = Arguments(space, []) l = [None] - args._match_signature(None, l, Signature(["a"]), defaults=Defaults([1])) + args._match_signature(None, l, Signature(["a"]), defaults_w=[1]) assert l == [1] args = Arguments(space, []) l = [None] @@ -232,7 +231,7 @@ py.test.raises(ArgErr, args._match_signature, firstarg, l, Signature(["a", "b", "c", "d", "e"], "*")) l = [None, None, None, None, None] args = Arguments(space, arglist, w_stararg=starargs) - args._match_signature(firstarg, l, Signature(["a", "b", "c", "d", "e"]), defaults=Defaults([1])) + args._match_signature(firstarg, l, Signature(["a", "b", "c", "d", "e"]), defaults_w=[1]) assert l == [4, 5, 6, 7, 1] for j in range(len(values)): l = [None] * (j + 1) @@ -257,24 +256,24 @@ assert len(keywords) == len(keywords_w) args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) l = [None, None, None] - args._match_signature(None, l, Signature(["a", "b", "c"]), defaults=Defaults([4])) + args._match_signature(None, l, Signature(["a", "b", "c"]), defaults_w=[4]) assert l == [1, 2, 3] args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) l = [None, None, None, None] - args._match_signature(None, l, Signature(["a", "b", "b1", "c"]), defaults=Defaults([4, 5])) + args._match_signature(None, l, Signature(["a", "b", "b1", "c"]), defaults_w=[4, 5]) assert l == [1, 2, 4, 3] args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) l = [None, None, None, None] - args._match_signature(None, l, Signature(["a", "b", "c", "d"]), defaults=Defaults([4, 5])) + args._match_signature(None, l, Signature(["a", "b", "c", "d"]), defaults_w=[4, 5]) assert l == [1, 2, 3, 5] args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) l = [None, None, None, None] py.test.raises(ArgErr, args._match_signature, None, l, - Signature(["c", "b", "a", "d"]), defaults=Defaults([4, 5])) + Signature(["c", "b", "a", "d"]), defaults_w=[4, 5]) args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) l = [None, None, None, None] py.test.raises(ArgErr, args._match_signature, None, l, - Signature(["a", "b", "c1", "d"]), defaults=Defaults([4, 5])) + Signature(["a", "b", "c1", "d"]), defaults_w=[4, 5]) args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) l = [None, None, None] args._match_signature(None, l, Signature(["a", "b"], None, "**")) @@ -355,10 +354,10 @@ calls = [] def _match_signature(w_firstarg, scope_w, signature, - defaults=None, blindargs=0): - defaults = [] if defaults is None else defaults.getitems() + defaults_w=None, blindargs=0): + defaults_w = [] if defaults_w is None else defaults_w calls.append((w_firstarg, scope_w, signature.argnames, signature.has_vararg(), - signature.has_kwarg(), defaults, blindargs)) + signature.has_kwarg(), defaults_w, blindargs)) args._match_signature = _match_signature scope_w = args.parse_obj(None, "foo", Signature(["a", "b"], None, None)) @@ -376,7 +375,7 @@ calls = [] scope_w = args.parse_obj(None, "foo", Signature(["a", "b"], "args", "kw"), - defaults=Defaults(['x', 'y'])) + defaults_w=['x', 'y']) assert len(calls) == 1 assert calls[0] == (None, [None, None, None, None], ["a", "b"], True, True, @@ -384,7 +383,7 @@ calls = [] scope_w = args.parse_obj("obj", "foo", Signature(["a", "b"], "args", "kw"), - defaults=Defaults(['x', 'y']), blindargs=1) + defaults_w=['x', 'y'], blindargs=1) assert len(calls) == 1 assert calls[0] == ("obj", [None, None, None, None], ["a", "b"], True, True, @@ -413,10 +412,10 @@ calls = [] def _match_signature(w_firstarg, scope_w, signature, - defaults=None, blindargs=0): - defaults = [] if defaults is None else defaults.getitems() + defaults_w=None, blindargs=0): + defaults_w = [] if defaults_w is None else defaults_w calls.append((w_firstarg, scope_w, signature.argnames, signature.has_vararg(), - signature.has_kwarg(), defaults, blindargs)) + signature.has_kwarg(), defaults_w, blindargs)) args._match_signature = _match_signature scope_w = [None, None] @@ -429,7 +428,7 @@ scope_w = [None, None, None, None] args.parse_into_scope(None, scope_w, "foo", Signature(["a", "b"], "args", "kw"), - defaults=Defaults(['x', 'y'])) + defaults_w=['x', 'y']) assert len(calls) == 1 assert calls[0] == (None, scope_w, ["a", "b"], True, True, @@ -439,7 +438,7 @@ scope_w = [None, None, None, None] args.parse_into_scope("obj", scope_w, "foo", Signature(["a", "b"], "args", "kw"), - defaults=Defaults(['x', 'y'])) + defaults_w=['x', 'y']) assert len(calls) == 1 assert calls[0] == ("obj", scope_w, ["a", "b"], True, True, @@ -511,25 +510,25 @@ def test_missing_args(self): # got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg, # defaults_w, missing_args - err = ArgErrCount(1, 0, 0, False, False, Defaults([]), 0) + err = ArgErrCount(1, 0, 0, False, False, None, 0) s = err.getmsg('foo') assert s == "foo() takes no argument (1 given)" - err = ArgErrCount(0, 0, 1, False, False, Defaults([]), 1) + err = ArgErrCount(0, 0, 1, False, False, [], 1) s = err.getmsg('foo') assert s == "foo() takes exactly 1 argument (0 given)" - err = ArgErrCount(3, 0, 2, False, False, Defaults([]), 0) + err = ArgErrCount(3, 0, 2, False, False, [], 0) s = err.getmsg('foo') assert s == "foo() takes exactly 2 arguments (3 given)" - err = ArgErrCount(1, 0, 2, True, False, Defaults([]), 1) + err = ArgErrCount(1, 0, 2, True, False, [], 1) s = err.getmsg('foo') assert s == "foo() takes at least 2 arguments (1 given)" - err = ArgErrCount(3, 0, 2, True, False, Defaults(['a']), 0) + err = ArgErrCount(3, 0, 2, True, False, ['a'], 0) s = err.getmsg('foo') assert s == "foo() takes at most 2 arguments (3 given)" - err = ArgErrCount(0, 1, 2, True, False, Defaults(['a']), 1) + err = ArgErrCount(0, 1, 2, True, False, ['a'], 1) s = err.getmsg('foo') assert s == "foo() takes at least 1 argument (1 given)" - err = ArgErrCount(2, 1, 1, False, True, Defaults([]), 0) + err = ArgErrCount(2, 1, 1, False, True, [], 0) s = err.getmsg('foo') assert s == "foo() takes exactly 1 argument (3 given)" @@ -603,7 +602,7 @@ args = make_arguments_for_translation(space, [1]) sig = Signature(['a', 'b', 'c'], None, None) - data = args.match_signature(sig, Defaults([2, 3])) + data = args.match_signature(sig, [2, 3]) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() @@ -615,25 +614,25 @@ args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2}) sig = Signature(['a', 'b', 'c'], None, None) - data = args.match_signature(sig, Defaults([])) + data = args.match_signature(sig, []) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() args = make_arguments_for_translation(space, [1], {'c': 5}) sig = Signature(['a', 'b', 'c'], None, None) - data = args.match_signature(sig, Defaults([2, 3])) + data = args.match_signature(sig, [2, 3]) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7}) sig = Signature(['a', 'b', 'c'], None, 'kw') - data = args.match_signature(sig, Defaults([2, 3])) + data = args.match_signature(sig, [2, 3]) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() args = make_arguments_for_translation(space, [1,2,3,4,5], {'e': 5, 'd': 7}) sig = Signature(['a', 'b', 'c'], 'r', 'kw') - data = args.match_signature(sig, Defaults([2, 3])) + data = args.match_signature(sig, [2, 3]) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() @@ -641,7 +640,7 @@ w_stararg=[1], w_starstararg={'c': 5, 'd': 7}) sig = Signature(['a', 'b', 'c'], None, 'kw') - data = args.match_signature(sig, Defaults([2, 3])) + data = args.match_signature(sig, [2, 3]) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() @@ -649,7 +648,7 @@ w_stararg=[3,4,5], w_starstararg={'e': 5, 'd': 7}) sig = Signature(['a', 'b', 'c'], 'r', 'kw') - data = args.match_signature(sig, Defaults([2, 3])) + data = args.match_signature(sig, [2, 3]) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -4,7 +4,6 @@ from pypy.conftest import gettestobjspace from pypy.interpreter import gateway, argument from pypy.interpreter.gateway import ObjSpace, W_Root -from pypy.interpreter.function import Defaults import py import sys @@ -12,7 +11,7 @@ def __init__(self, space, name): self.space = space self.name = name - self.defs = Defaults([]) + self.defs_w = [] class TestBuiltinCode: def test_signature(self): diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -168,6 +168,7 @@ class CompiledLoop(object): has_been_freed = False + invalid = False def __init__(self): self.inputargs = [] @@ -944,6 +945,9 @@ if forced: raise GuardFailed + def op_guard_not_invalidated(self, descr): + if self.loop.invalid: + raise GuardFailed class OOFrame(Frame): diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -286,6 +286,10 @@ raise ValueError("CALL_ASSEMBLER not supported") llimpl.redirect_call_assembler(self, oldlooptoken, newlooptoken) + def invalidate_loop(self, looptoken): + for loop in looptoken.compiled_loop_token.loop_and_bridges: + loop._obj.externalobj.invalid = True + # ---------- def sizeof(self, S): diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py --- a/pypy/jit/backend/model.py +++ b/pypy/jit/backend/model.py @@ -141,6 +141,16 @@ oldlooptoken so that from now own they will call newlooptoken.""" raise NotImplementedError + def invalidate_loop(self, looptoken): + """Activate all GUARD_NOT_INVALIDATED in the loop and its attached + bridges. Before this call, all GUARD_NOT_INVALIDATED do nothing; + after this call, they all fail. Note that afterwards, if one such + guard fails often enough, it has a bridge attached to it; it is + possible then to re-call invalidate_loop() on the same looptoken, + which must invalidate all newer GUARD_NOT_INVALIDATED, but not the + old one that already has a bridge attached to it.""" + raise NotImplementedError + def free_loop_and_bridges(self, compiled_loop_token): """This method is called to free resources (machine code, references to resume guards, etc.) allocated by the compilation @@ -296,6 +306,7 @@ # that belong to this loop or to a bridge attached to it. # Filled by the frontend calling record_faildescr_index(). self.faildescr_indices = [] + self.invalidate_positions = [] debug_start("jit-mem-looptoken-alloc") debug_print("allocating Loop #", self.number) debug_stop("jit-mem-looptoken-alloc") diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -1870,6 +1870,66 @@ assert self.cpu.get_latest_value_int(2) == 10 assert values == [1, 10] + def test_guard_not_invalidated(self): + cpu = self.cpu + i0 = BoxInt() + i1 = BoxInt() + faildescr = BasicFailDescr(1) + ops = [ + ResOperation(rop.GUARD_NOT_INVALIDATED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [i0], None, descr=BasicFailDescr(0)) + ] + ops[0].setfailargs([i1]) + looptoken = LoopToken() + self.cpu.compile_loop([i0, i1], ops, looptoken) + + self.cpu.set_future_value_int(0, -42) + self.cpu.set_future_value_int(1, 9) + fail = self.cpu.execute_token(looptoken) + assert fail.identifier == 0 + assert self.cpu.get_latest_value_int(0) == -42 + print 'step 1 ok' + print '-'*79 + + # mark as failing + self.cpu.invalidate_loop(looptoken) + + self.cpu.set_future_value_int(0, -42) + self.cpu.set_future_value_int(1, 9) + fail = self.cpu.execute_token(looptoken) + assert fail is faildescr + assert self.cpu.get_latest_value_int(0) == 9 + print 'step 2 ok' + print '-'*79 + + # attach a bridge + i2 = BoxInt() + faildescr2 = BasicFailDescr(2) + ops = [ + ResOperation(rop.GUARD_NOT_INVALIDATED, [],None, descr=faildescr2), + ResOperation(rop.FINISH, [i2], None, descr=BasicFailDescr(3)) + ] + ops[0].setfailargs([]) + self.cpu.compile_bridge(faildescr, [i2], ops, looptoken) + + self.cpu.set_future_value_int(0, -42) + self.cpu.set_future_value_int(1, 9) + fail = self.cpu.execute_token(looptoken) + assert fail.identifier == 3 + assert self.cpu.get_latest_value_int(0) == 9 + print 'step 3 ok' + print '-'*79 + + # mark as failing again + self.cpu.invalidate_loop(looptoken) + + self.cpu.set_future_value_int(0, -42) + self.cpu.set_future_value_int(1, 9) + fail = self.cpu.execute_token(looptoken) + assert fail is faildescr2 + print 'step 4 ok' + print '-'*79 + # pure do_ / descr features def test_do_operations(self): diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -48,11 +48,13 @@ class GuardToken(object): - def __init__(self, faildescr, failargs, fail_locs, exc): + def __init__(self, faildescr, failargs, fail_locs, exc, + is_guard_not_invalidated): self.faildescr = faildescr self.failargs = failargs self.fail_locs = fail_locs self.exc = exc + self.is_guard_not_invalidated = is_guard_not_invalidated DEBUG_COUNTER = lltype.Struct('DEBUG_COUNTER', ('i', lltype.Signed)) @@ -435,15 +437,36 @@ # tok.faildescr._x86_adr_jump_offset to contain the raw address of # the 4-byte target field in the JMP/Jcond instruction, and patch # the field in question to point (initially) to the recovery stub + clt = self.current_clt for tok in self.pending_guard_tokens: addr = rawstart + tok.pos_jump_offset tok.faildescr._x86_adr_jump_offset = addr relative_target = tok.pos_recovery_stub - (tok.pos_jump_offset + 4) assert rx86.fits_in_32bits(relative_target) # - mc = codebuf.MachineCodeBlockWrapper() - mc.writeimm32(relative_target) - mc.copy_to_raw_memory(addr) + if not tok.is_guard_not_invalidated: + mc = codebuf.MachineCodeBlockWrapper() + mc.writeimm32(relative_target) + mc.copy_to_raw_memory(addr) + else: + # GUARD_NOT_INVALIDATED, record an entry in + # clt.invalidate_positions of the form: + # (addr-in-the-code-of-the-not-yet-written-jump-target, + # relative-target-to-use) + relpos = tok.pos_jump_offset + clt.invalidate_positions.append((rawstart + relpos, + relative_target)) + # General idea: Although no code was generated by this + # guard, the code might be patched with a "JMP rel32" to + # the guard recovery code. This recovery code is + # already generated, and looks like the recovery code + # for any guard, even if at first it has no jump to it. + # So we may later write 5 bytes overriding the existing + # instructions; this works because a CALL instruction + # would also take at least 5 bytes. If it could take + # less, we would run into the issue that overwriting the + # 5 bytes here might get a few nonsense bytes at the + # return address of the following CALL. def get_asmmemmgr_blocks(self, looptoken): clt = looptoken.compiled_loop_token @@ -1471,6 +1494,12 @@ self.mc.CMP(heap(self.cpu.pos_exception()), imm0) self.implement_guard(guard_token, 'NZ') + def genop_guard_guard_not_invalidated(self, ign_1, guard_op, guard_token, + locs, ign_2): + pos = self.mc.get_relative_pos() + 1 # after potential jmp + guard_token.pos_jump_offset = pos + self.pending_guard_tokens.append(guard_token) + def genop_guard_guard_exception(self, ign_1, guard_op, guard_token, locs, resloc): loc = locs[0] @@ -1569,7 +1598,9 @@ exc = (guard_opnum == rop.GUARD_EXCEPTION or guard_opnum == rop.GUARD_NO_EXCEPTION or guard_opnum == rop.GUARD_NOT_FORCED) - return GuardToken(faildescr, failargs, fail_locs, exc) + is_guard_not_invalidated = guard_opnum == rop.GUARD_NOT_INVALIDATED + return GuardToken(faildescr, failargs, fail_locs, exc, + is_guard_not_invalidated) def generate_quick_failure(self, guardtok): """Generate the initial code for handling a failure. We try to diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -455,6 +455,8 @@ def consider_guard_no_exception(self, op): self.perform_guard(op, [], None) + consider_guard_not_invalidated = consider_guard_no_exception + def consider_guard_exception(self, op): loc = self.rm.make_sure_var_in_reg(op.getarg(0)) box = TempBox() diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py --- a/pypy/jit/backend/x86/runner.py +++ b/pypy/jit/backend/x86/runner.py @@ -153,6 +153,17 @@ def redirect_call_assembler(self, oldlooptoken, newlooptoken): self.assembler.redirect_call_assembler(oldlooptoken, newlooptoken) + def invalidate_loop(self, looptoken): + from pypy.jit.backend.x86 import codebuf + + for addr, tgt in looptoken.compiled_loop_token.invalidate_positions: + mc = codebuf.MachineCodeBlockWrapper() + mc.JMP_l(tgt) + assert mc.get_relative_pos() == 5 # [JMP] [tgt 4 bytes] + mc.copy_to_raw_memory(addr - 1) + # positions invalidated + looptoken.compiled_loop_token.invalidate_positions = [] + class CPU386(AbstractX86CPU): WORD = 4 NUM_REGS = 8 diff --git a/pypy/jit/backend/x86/test/test_quasiimmut.py b/pypy/jit/backend/x86/test/test_quasiimmut.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/x86/test/test_quasiimmut.py @@ -0,0 +1,9 @@ + +import py +from pypy.jit.backend.x86.test.test_basic import Jit386Mixin +from pypy.jit.metainterp.test import test_quasiimmut + +class TestLoopSpec(Jit386Mixin, test_quasiimmut.QuasiImmutTests): + # for the individual tests see + # ====> ../../../metainterp/test/test_loop.py + pass diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -6,6 +6,7 @@ from pypy.jit.codewriter import support from pypy.jit.codewriter.jitcode import JitCode from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer +from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection from pypy.translator.simplify import get_funcobj, get_functype @@ -30,6 +31,7 @@ self.raise_analyzer = RaiseAnalyzer(translator) self.readwrite_analyzer = ReadWriteAnalyzer(translator) self.virtualizable_analyzer = VirtualizableAnalyzer(translator) + self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator) # for index, jd in enumerate(jitdrivers_sd): jd.index = index @@ -220,6 +222,8 @@ if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE + elif self.quasiimmut_analyzer.analyze(op): + extraeffect = EffectInfo.EF_CAN_INVALIDATE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif pure: @@ -237,6 +241,7 @@ if pure or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE + assert extraeffect != EffectInfo.EF_CAN_INVALIDATE # return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT, effectinfo) diff --git a/pypy/jit/codewriter/codewriter.py b/pypy/jit/codewriter/codewriter.py --- a/pypy/jit/codewriter/codewriter.py +++ b/pypy/jit/codewriter/codewriter.py @@ -13,13 +13,13 @@ class CodeWriter(object): callcontrol = None # for tests + debug = False - def __init__(self, cpu=None, jitdrivers_sd=[], debug=False): + def __init__(self, cpu=None, jitdrivers_sd=[]): self.cpu = cpu self.assembler = Assembler() self.callcontrol = CallControl(cpu, jitdrivers_sd) self._seen_files = set() - self.debug = debug def transform_func_to_jitcode(self, func, values, type_system='lltype'): """For testing.""" diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -13,7 +13,8 @@ EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) - EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 4 #can raise and force virtualizables + EF_CAN_INVALIDATE = 4 #can force all GUARD_NOT_INVALIDATED + EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables # the 'oopspecindex' field is one of the following values: OS_NONE = 0 # normal case, no oopspec @@ -100,6 +101,9 @@ cls._cache[key] = result return result + def check_can_invalidate(self): + return self.extraeffect >= self.EF_CAN_INVALIDATE + def check_forces_virtual_or_virtualizable(self): return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE @@ -175,6 +179,10 @@ return op.opname in ('jit_force_virtualizable', 'jit_force_virtual') +class QuasiImmutAnalyzer(BoolGraphAnalyzer): + def analyze_simple_operation(self, op, graphinfo): + return op.opname == 'jit_force_quasi_immutable' + # ____________________________________________________________ class CallInfoCollection(object): diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -9,6 +9,8 @@ from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter.policy import log from pypy.jit.metainterp.typesystem import deref, arrayItem +from pypy.jit.metainterp import quasiimmut +from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY from pypy.rlib import objectmodel from pypy.rlib.jit import _we_are_jitted from pypy.translator.simplify import get_funcobj @@ -113,7 +115,7 @@ "known non-negative, or catching IndexError, or\n" "not inlining at all (for tests: use listops=True).\n" "Occurred in: %r" % self.graph) - # extra expanation: with the way things are organized in + # extra explanation: with the way things are organized in # rpython/rlist.py, the ll_getitem becomes a function call # that is typically meant to be inlined by the JIT, but # this does not work with vable arrays because @@ -362,7 +364,7 @@ # If the resulting op1 is still a direct_call, turn it into a # residual_call. if isinstance(op1, SpaceOperation) and op1.opname == 'direct_call': - op1 = self.handle_residual_call(op1 or op) + op1 = self.handle_residual_call(op1) return op1 def handle_recursive_call(self, op): @@ -563,7 +565,8 @@ arraydescr) return [] # check for _immutable_fields_ hints - if v_inst.concretetype.TO._immutable_field(c_fieldname.value): + immut = v_inst.concretetype.TO._immutable_field(c_fieldname.value) + if immut: if (self.callcontrol is not None and self.callcontrol.could_be_green_field(v_inst.concretetype.TO, c_fieldname.value)): @@ -576,8 +579,18 @@ descr = self.cpu.fielddescrof(v_inst.concretetype.TO, c_fieldname.value) kind = getkind(RESULT)[0] - return SpaceOperation('getfield_%s_%s%s' % (argname, kind, pure), - [v_inst, descr], op.result) + op1 = SpaceOperation('getfield_%s_%s%s' % (argname, kind, pure), + [v_inst, descr], op.result) + # + if immut in (IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY): + descr1 = self.cpu.fielddescrof( + v_inst.concretetype.TO, + quasiimmut.get_mutate_field_name(c_fieldname.value)) + op1 = [SpaceOperation('-live-', [], None), + SpaceOperation('record_quasiimmut_field', + [v_inst, descr, descr1], None), + op1] + return op1 def rewrite_op_setfield(self, op): if self.is_typeptr_getset(op): @@ -1370,6 +1383,15 @@ return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, EffectInfo.EF_PURE) + def rewrite_op_jit_force_quasi_immutable(self, op): + v_inst, c_fieldname = op.args + descr1 = self.cpu.fielddescrof(v_inst.concretetype.TO, + c_fieldname.value) + op0 = SpaceOperation('-live-', [], None) + op1 = SpaceOperation('jit_force_quasi_immutable', [v_inst, descr1], + None) + return [op0, op1] + # ____________________________________________________________ class NotSupported(Exception): diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -969,3 +969,48 @@ assert op1.args[3] == ListOfKind("ref", []) assert op1.args[4] == ListOfKind('float', [v1]) assert op1.result == v2 + +def test_quasi_immutable(): + from pypy.rpython.rclass import FieldListAccessor, IR_QUASIIMMUTABLE + accessor = FieldListAccessor() + accessor.initialize(None, {'inst_x': IR_QUASIIMMUTABLE}) + v2 = varoftype(lltype.Signed) + STRUCT = lltype.GcStruct('struct', ('inst_x', lltype.Signed), + ('mutate_x', rclass.OBJECTPTR), + hints={'immutable_fields': accessor}) + for v_x in [const(lltype.malloc(STRUCT)), varoftype(lltype.Ptr(STRUCT))]: + op = SpaceOperation('getfield', [v_x, Constant('inst_x', lltype.Void)], + v2) + tr = Transformer(FakeCPU()) + [_, op1, op2] = tr.rewrite_operation(op) + assert op1.opname == 'record_quasiimmut_field' + assert len(op1.args) == 3 + assert op1.args[0] == v_x + assert op1.args[1] == ('fielddescr', STRUCT, 'inst_x') + assert op1.args[2] == ('fielddescr', STRUCT, 'mutate_x') + assert op1.result is None + assert op2.opname == 'getfield_gc_i' + assert len(op2.args) == 2 + assert op2.args[0] == v_x + assert op2.args[1] == ('fielddescr', STRUCT, 'inst_x') + assert op2.result is op.result + +def test_quasi_immutable_setfield(): + from pypy.rpython.rclass import FieldListAccessor, IR_QUASIIMMUTABLE + accessor = FieldListAccessor() + accessor.initialize(None, {'inst_x': IR_QUASIIMMUTABLE}) + v1 = varoftype(lltype.Signed) + STRUCT = lltype.GcStruct('struct', ('inst_x', lltype.Signed), + ('mutate_x', rclass.OBJECTPTR), + hints={'immutable_fields': accessor}) + for v_x in [const(lltype.malloc(STRUCT)), varoftype(lltype.Ptr(STRUCT))]: + op = SpaceOperation('jit_force_quasi_immutable', + [v_x, Constant('mutate_x', lltype.Void)], + varoftype(lltype.Void)) + tr = Transformer(FakeCPU(), FakeRegularCallControl()) + tr.graph = 'currentgraph' + op0, op1 = tr.rewrite_operation(op) + assert op0.opname == '-live-' + assert op1.opname == 'jit_force_quasi_immutable' + assert op1.args[0] == v_x + assert op1.args[1] == ('fielddescr', STRUCT, 'mutate_x') diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -1174,6 +1174,15 @@ def bhimpl_setfield_raw_f(cpu, struct, fielddescr, newvalue): cpu.bh_setfield_raw_f(struct, fielddescr, newvalue) + @arguments("r", "d", "d") + def bhimpl_record_quasiimmut_field(struct, fielddescr, mutatefielddescr): + pass + + @arguments("cpu", "r", "d") + def bhimpl_jit_force_quasi_immutable(cpu, struct, mutatefielddescr): + from pypy.jit.metainterp import quasiimmut + quasiimmut.do_force_quasi_immutable(cpu, struct, mutatefielddescr) + @arguments("cpu", "d", returns="r") def bhimpl_new(cpu, descr): return cpu.bh_new(descr) @@ -1299,6 +1308,8 @@ # We get here because it used to overflow, but now it no longer # does. pass + elif opnum == rop.GUARD_NOT_INVALIDATED: + pass else: from pypy.jit.metainterp.resoperation import opname raise NotImplementedError(opname[opnum]) diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -76,6 +76,11 @@ op.setdescr(None) # clear reference, mostly for tests if not we_are_translated(): op._jumptarget_number = descr.number + # record this looptoken on the QuasiImmut used in the code + if loop.quasi_immutable_deps is not None: + for qmut in loop.quasi_immutable_deps: + qmut.register_loop_token(wref) + # XXX maybe we should clear the dictionary here # mostly for tests: make sure we don't keep a reference to the LoopToken loop.token = None if not we_are_translated(): @@ -396,6 +401,12 @@ self.copy_all_attributes_into(res) return res +class ResumeGuardNotInvalidated(ResumeGuardDescr): + def _clone_if_mutable(self): + res = ResumeGuardNotInvalidated() + self.copy_all_attributes_into(res) + return res + class ResumeAtPositionDescr(ResumeGuardDescr): def _clone_if_mutable(self): res = ResumeAtPositionDescr() diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -322,6 +322,7 @@ rop.DEBUG_MERGE_POINT, rop.JIT_DEBUG, rop.SETARRAYITEM_RAW, + rop.QUASIIMMUT_FIELD, ): # list of opcodes never executed by pyjitpl continue raise AssertionError("missing %r" % (key,)) diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -791,6 +791,7 @@ operations = None token = None call_pure_results = None + quasi_immutable_deps = None def __init__(self, name): self.name = name diff --git a/pypy/jit/metainterp/jitprof.py b/pypy/jit/metainterp/jitprof.py --- a/pypy/jit/metainterp/jitprof.py +++ b/pypy/jit/metainterp/jitprof.py @@ -22,6 +22,7 @@ ABORT_BRIDGE ABORT_ESCAPE ABORT_BAD_LOOP +ABORT_FORCE_QUASIIMMUT NVIRTUALS NVHOLES NVREUSED @@ -179,6 +180,8 @@ self._print_intline("abort: compiling", cnt[ABORT_BRIDGE]) self._print_intline("abort: vable escape", cnt[ABORT_ESCAPE]) self._print_intline("abort: bad loop", cnt[ABORT_BAD_LOOP]) + self._print_intline("abort: force quasi-immut", + cnt[ABORT_FORCE_QUASIIMMUT]) self._print_intline("nvirtuals", cnt[NVIRTUALS]) self._print_intline("nvholes", cnt[NVHOLES]) self._print_intline("nvreused", cnt[NVREUSED]) diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -41,7 +41,8 @@ # during preamble but to keep it during the loop optimizations.append(o) - if 'rewrite' not in enable_opts or 'virtualize' not in enable_opts: + if ('rewrite' not in enable_opts or 'virtualize' not in enable_opts + or 'heap' not in enable_opts): optimizations.append(OptSimplify()) if inline_short_preamble: diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -119,6 +119,8 @@ self._lazy_setfields = [] # cached array items: {descr: CachedArrayItems} self.cached_arrayitems = {} + self._remove_guard_not_invalidated = False + self._seen_guard_not_invalidated = False def reconstruct_for_next_iteration(self, optimizer, valuemap): new = OptHeap() @@ -238,6 +240,8 @@ effectinfo = None else: effectinfo = op.getdescr().get_extra_info() + if effectinfo is None or effectinfo.check_can_invalidate(): + self._seen_guard_not_invalidated = False if effectinfo is not None: # XXX we can get the wrong complexity here, if the lists # XXX stored on effectinfo are large @@ -378,6 +382,46 @@ self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, write=True) + def optimize_QUASIIMMUT_FIELD(self, op): + # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) + # x = GETFIELD_GC(s, descr='inst_x') + # If 's' is a constant (after optimizations), then we make 's.inst_x' + # a constant too, and we rely on the rest of the optimizations to + # constant-fold the following getfield_gc. + structvalue = self.getvalue(op.getarg(0)) + if not structvalue.is_constant(): + self._remove_guard_not_invalidated = True + return # not a constant at all; ignore QUASIIMMUT_FIELD + # + from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr + qmutdescr = op.getdescr() + assert isinstance(qmutdescr, QuasiImmutDescr) + # check that the value is still correct; it could have changed + # already between the tracing and now. In this case, we are + # simply ignoring the QUASIIMMUT_FIELD hint and compiling it + # as a regular getfield. + if not qmutdescr.is_still_valid(): + self._remove_guard_not_invalidated = True + return + # record as an out-of-line guard + if self.optimizer.quasi_immutable_deps is None: + self.optimizer.quasi_immutable_deps = {} + self.optimizer.quasi_immutable_deps[qmutdescr.qmut] = None + # perform the replacement in the list of operations + fieldvalue = self.getvalue(qmutdescr.constantfieldbox) + cf = self.field_cache(qmutdescr.fielddescr) + cf.force_lazy_setfield(self) + cf.remember_field_value(structvalue, fieldvalue) + self._remove_guard_not_invalidated = False + + def optimize_GUARD_NOT_INVALIDATED(self, op): + if self._remove_guard_not_invalidated: + return + if self._seen_guard_not_invalidated: + return + self._seen_guard_not_invalidated = True + self.emit_operation(op) + def propagate_forward(self, op): opnum = op.getopnum() for value, func in optimize_ops: diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -257,6 +257,7 @@ self.pendingfields = [] self.posponedop = None self.exception_might_have_happened = False + self.quasi_immutable_deps = None self.newoperations = [] if loop is not None: self.call_pure_results = loop.call_pure_results @@ -309,6 +310,7 @@ new.pure_operations = self.pure_operations new.producer = self.producer assert self.posponedop is None + new.quasi_immutable_deps = self.quasi_immutable_deps return new @@ -410,6 +412,7 @@ self.first_optimization.propagate_forward(op) self.i += 1 self.loop.operations = self.newoperations + self.loop.quasi_immutable_deps = self.quasi_immutable_deps # accumulate counters self.resumedata_memo.update_counters(self.metainterp_sd.profiler) diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -20,6 +20,11 @@ op = ResOperation(rop.SAME_AS, [op.getarg(0)], op.result) self.emit_operation(op) + def optimize_QUASIIMMUT_FIELD(self, op): + # xxx ideally we could also kill the following GUARD_NOT_INVALIDATED + # but it's a bit hard to implement robustly if heap.py is also run + pass + def propagate_forward(self, op): opnum = op.getopnum() for value, func in optimize_ops: diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -267,6 +267,8 @@ virtual_state = modifier.get_virtual_state(jump_args) loop.preamble.operations = self.optimizer.newoperations + loop.preamble.quasi_immutable_deps = ( + self.optimizer.quasi_immutable_deps) self.optimizer = self.optimizer.reconstruct_for_next_iteration() inputargs = self.inline(self.cloned_operations, loop.inputargs, jump_args) @@ -276,6 +278,7 @@ loop.preamble.operations.append(jmp) loop.operations = self.optimizer.newoperations + loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps start_resumedescr = loop.preamble.start_resumedescr.clone_if_mutable() assert isinstance(start_resumedescr, ResumeGuardDescr) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -15,7 +15,7 @@ from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE, \ - ABORT_BAD_LOOP + ABORT_BAD_LOOP, ABORT_FORCE_QUASIIMMUT from pypy.jit.metainterp.jitexc import JitException, get_llexception from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize @@ -555,6 +555,35 @@ opimpl_setfield_raw_r = _opimpl_setfield_raw_any opimpl_setfield_raw_f = _opimpl_setfield_raw_any + @arguments("box", "descr", "descr", "orgpc") + def opimpl_record_quasiimmut_field(self, box, fielddescr, + mutatefielddescr, orgpc): + from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr + cpu = self.metainterp.cpu + descr = QuasiImmutDescr(cpu, box, fielddescr, mutatefielddescr) + self.metainterp.history.record(rop.QUASIIMMUT_FIELD, [box], + None, descr=descr) + self.generate_guard(rop.GUARD_NOT_INVALIDATED, resumepc=orgpc) + + @arguments("box", "descr", "orgpc") + def opimpl_jit_force_quasi_immutable(self, box, mutatefielddescr, orgpc): + # During tracing, a 'jit_force_quasi_immutable' usually turns into + # the operations that check that the content of 'mutate_xxx' is null. + # If it is actually not null already now, then we abort tracing. + # The idea is that if we use 'jit_force_quasi_immutable' on a freshly + # allocated object, then the GETFIELD_GC will know that the answer is + # null, and the guard will be removed. So the fact that the field is + # quasi-immutable will have no effect, and instead it will work as a + # regular, probably virtual, structure. + mutatebox = self.execute_with_descr(rop.GETFIELD_GC, + mutatefielddescr, box) + if mutatebox.nonnull(): + from pypy.jit.metainterp.quasiimmut import do_force_quasi_immutable + do_force_quasi_immutable(self.metainterp.cpu, box.getref_base(), + mutatefielddescr) + raise SwitchToBlackhole(ABORT_FORCE_QUASIIMMUT) + self.generate_guard(rop.GUARD_ISNULL, mutatebox, resumepc=orgpc) + def _nonstandard_virtualizable(self, pc, box): # returns True if 'box' is actually not the "standard" virtualizable # that is stored in metainterp.virtualizable_boxes[-1] @@ -1080,6 +1109,8 @@ if opnum == rop.GUARD_NOT_FORCED: resumedescr = compile.ResumeGuardForcedDescr(metainterp_sd, metainterp.jitdriver_sd) + elif opnum == rop.GUARD_NOT_INVALIDATED: + resumedescr = compile.ResumeGuardNotInvalidated() else: resumedescr = compile.ResumeGuardDescr() guard_op = metainterp.history.record(opnum, moreargs, None, @@ -1852,6 +1883,9 @@ self.handle_possible_exception() except ChangeFrame: pass + elif opnum == rop.GUARD_NOT_INVALIDATED: + pass # XXX we want to do something special in resume descr, + # but not now elif opnum == rop.GUARD_NO_OVERFLOW: # an overflow now detected self.execute_raised(OverflowError(), constant=True) try: diff --git a/pypy/jit/metainterp/quasiimmut.py b/pypy/jit/metainterp/quasiimmut.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/quasiimmut.py @@ -0,0 +1,121 @@ +import weakref +from pypy.rpython.lltypesystem import lltype, rclass +from pypy.rpython.annlowlevel import cast_base_ptr_to_instance +from pypy.jit.metainterp.history import AbstractDescr + + +def get_mutate_field_name(fieldname): + if fieldname.startswith('inst_'): # lltype + return 'mutate_' + fieldname[5:] + elif fieldname.startswith('o'): # ootype + return 'mutate_' + fieldname[1:] + else: + raise AssertionError(fieldname) + +def get_current_qmut_instance(cpu, gcref, mutatefielddescr): + """Returns the current QuasiImmut instance in the field, + possibly creating one. + """ + qmut_gcref = cpu.bh_getfield_gc_r(gcref, mutatefielddescr) + if qmut_gcref: + qmut = QuasiImmut.show(cpu, qmut_gcref) + else: + qmut = QuasiImmut(cpu) + cpu.bh_setfield_gc_r(gcref, mutatefielddescr, qmut.hide()) + return qmut + +def make_invalidation_function(STRUCT, mutatefieldname): + # + def _invalidate_now(p): + qmut_ptr = getattr(p, mutatefieldname) + setattr(p, mutatefieldname, lltype.nullptr(rclass.OBJECT)) + qmut = cast_base_ptr_to_instance(QuasiImmut, qmut_ptr) + qmut.invalidate() + _invalidate_now._dont_inline_ = True + # + def invalidation(p): + if getattr(p, mutatefieldname): + _invalidate_now(p) + # + return invalidation + +def do_force_quasi_immutable(cpu, p, mutatefielddescr): + qmut_ref = cpu.bh_getfield_gc_r(p, mutatefielddescr) + if qmut_ref: + cpu.bh_setfield_gc_r(p, mutatefielddescr, cpu.ts.NULLREF) + qmut_ptr = lltype.cast_opaque_ptr(rclass.OBJECTPTR, qmut_ref) + qmut = cast_base_ptr_to_instance(QuasiImmut, qmut_ptr) + qmut.invalidate() + + +class QuasiImmut(object): + llopaque = True + + def __init__(self, cpu): + self.cpu = cpu + # list of weakrefs to the LoopTokens that must be invalidated if + # this value ever changes + self.looptokens_wrefs = [] + self.compress_limit = 30 + + def hide(self): + qmut_ptr = self.cpu.ts.cast_instance_to_base_ref(self) + return self.cpu.ts.cast_to_ref(qmut_ptr) + + @staticmethod + def show(cpu, qmut_gcref): + qmut_ptr = cpu.ts.cast_to_baseclass(qmut_gcref) + return cast_base_ptr_to_instance(QuasiImmut, qmut_ptr) + + def register_loop_token(self, wref_looptoken): + if len(self.looptokens_wrefs) > self.compress_limit: + self.compress_looptokens_list() + self.looptokens_wrefs.append(wref_looptoken) + + def compress_looptokens_list(self): + self.looptokens_wrefs = [wref for wref in self.looptokens_wrefs + if wref() is not None] + self.compress_limit = (len(self.looptokens_wrefs) + 15) * 2 + + def invalidate(self): + # When this is called, all the loops that we record become + # invalid: all GUARD_NOT_INVALIDATED in these loops (and + # in attached bridges) must now fail. + wrefs = self.looptokens_wrefs + self.looptokens_wrefs = [] + for wref in wrefs: + looptoken = wref() + if looptoken is not None: + self.cpu.invalidate_loop(looptoken) + + +class QuasiImmutDescr(AbstractDescr): + structbox = None + + def __init__(self, cpu, structbox, fielddescr, mutatefielddescr): + self.cpu = cpu + self.structbox = structbox + self.fielddescr = fielddescr + self.mutatefielddescr = mutatefielddescr + gcref = structbox.getref_base() + self.qmut = get_current_qmut_instance(cpu, gcref, mutatefielddescr) + self.constantfieldbox = self.get_current_constant_fieldvalue() + + def get_current_constant_fieldvalue(self): + from pypy.jit.metainterp import executor + from pypy.jit.metainterp.resoperation import rop + fieldbox = executor.execute(self.cpu, None, rop.GETFIELD_GC, + self.fielddescr, self.structbox) + return fieldbox.constbox() + + def is_still_valid(self): + assert self.structbox is not None + cpu = self.cpu + gcref = self.structbox.getref_base() + qmut = get_current_qmut_instance(cpu, gcref, self.mutatefielddescr) + if qmut is not self.qmut: + return False + else: + currentbox = self.get_current_constant_fieldvalue() + assert self.constantfieldbox.same_constant(currentbox) + return True diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -380,6 +380,7 @@ 'GUARD_NO_OVERFLOW/0d', 'GUARD_OVERFLOW/0d', 'GUARD_NOT_FORCED/0d', + 'GUARD_NOT_INVALIDATED/0d', '_GUARD_LAST', # ----- end of guard operations ----- '_NOSIDEEFFECT_FIRST', # ----- start of no_side_effect operations ----- @@ -476,6 +477,7 @@ 'VIRTUAL_REF_FINISH/2', # removed before it's passed to the backend 'COPYSTRCONTENT/5', # src, dst, srcstart, dststart, length 'COPYUNICODECONTENT/5', + 'QUASIIMMUT_FIELD/1d', # [objptr], descr=SlowMutateDescr '_CANRAISE_FIRST', # ----- start of can_raise operations ----- '_CALL_FIRST', diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -8,12 +8,12 @@ from pypy.jit.metainterp import pyjitpl, history from pypy.jit.metainterp.warmstate import set_future_value from pypy.jit.codewriter.policy import JitPolicy -from pypy.jit.codewriter import longlong -from pypy.rlib.rfloat import isinf, isnan +from pypy.jit.codewriter import codewriter, longlong +from pypy.rlib.rfloat import isnan def _get_jitcodes(testself, CPUClass, func, values, type_system, supports_longlong=False, **kwds): - from pypy.jit.codewriter import support, codewriter + from pypy.jit.codewriter import support class FakeJitCell: __compiled_merge_points = [] @@ -50,6 +50,7 @@ stats = history.Stats() cpu = CPUClass(rtyper, stats, None, False) cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()]) + cw.debug = True testself.cw = cw policy = JitPolicy() policy.set_supports_floats(True) @@ -173,7 +174,12 @@ kwds['type_system'] = self.type_system if "backendopt" not in kwds: kwds["backendopt"] = False - return ll_meta_interp(*args, **kwds) + old = codewriter.CodeWriter.debug + try: + codewriter.CodeWriter.debug = True + return ll_meta_interp(*args, **kwds) + finally: + codewriter.CodeWriter.debug = old def interp_operations(self, f, args, **kwds): # get the JitCodes for the function f diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -65,7 +65,7 @@ ] assert profiler.events == expected assert profiler.times == [3, 2, 1, 1] - assert profiler.counters == [1, 2, 1, 1, 3, 3, 1, 13, 2, 0, 0, 0, + assert profiler.counters == [1, 2, 1, 1, 3, 3, 1, 13, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0] def test_simple_loop_with_call(self): diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py --- a/pypy/jit/metainterp/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/test/test_optimizeopt.py @@ -5718,34 +5718,121 @@ # not obvious, because of the exception UnicodeDecodeError that # can be raised by ll_str2unicode() - - - -##class TestOOtype(OptimizeOptTest, OOtypeMixin): - -## def test_instanceof(self): -## ops = """ -## [i0] -## p0 = new_with_vtable(ConstClass(node_vtable)) -## i1 = instanceof(p0, descr=nodesize) -## jump(i1) -## """ -## expected = """ -## [i0] -## jump(1) -## """ -## self.optimize_loop(ops, expected) - -## def test_instanceof_guard_class(self): -## ops = """ -## [i0, p0] -## guard_class(p0, ConstClass(node_vtable)) [] -## i1 = instanceof(p0, descr=nodesize) -## jump(i1, p0) -## """ -## expected = """ -## [i0, p0] -## guard_class(p0, ConstClass(node_vtable)) [] -## jump(1, p0) -## """ -## self.optimize_loop(ops, expected) + def test_quasi_immut(self): + ops = """ + [p0, p1, i0] + quasiimmut_field(p0, descr=quasiimmutdescr) + guard_not_invalidated() [] + i1 = getfield_gc(p0, descr=quasifielddescr) + escape(i1) + jump(p1, p0, i1) + """ + expected = """ + [p0, p1, i0] + i1 = getfield_gc(p0, descr=quasifielddescr) + escape(i1) + jump(p1, p0, i1) + """ + self.optimize_loop(ops, expected) + + def test_quasi_immut_2(self): + ops = """ + [] + quasiimmut_field(ConstPtr(myptr), descr=quasiimmutdescr) + guard_not_invalidated() [] + i1 = getfield_gc(ConstPtr(myptr), descr=quasifielddescr) + escape(i1) + jump() + """ + expected = """ + [] + guard_not_invalidated() [] + escape(-4247) + jump() + """ + self.optimize_loop(ops, expected, expected) + + def test_remove_extra_guards_not_invalidated(self): + ops = """ + [i0] + guard_not_invalidated() [] + guard_not_invalidated() [] + i1 = int_add(i0, 1) + guard_not_invalidated() [] + guard_not_invalidated() [] + jump(i1) + """ + expected = """ + [i0] + guard_not_invalidated() [] + i1 = int_add(i0, 1) + jump(i1) + """ + self.optimize_loop(ops, expected) + + def test_call_may_force_invalidated_guards(self): + ops = """ + [i0] + guard_not_invalidated() [] + call_may_force(i0, descr=mayforcevirtdescr) + guard_not_invalidated() [] + jump(i0) + """ + expected = """ + [i0] + guard_not_invalidated() [] + call_may_force(i0, descr=mayforcevirtdescr) + guard_not_invalidated() [] + jump(i0) + """ + self.optimize_loop(ops, expected) + + def test_call_may_force_invalidated_guards_reload(self): + ops = """ + [i0a, i0b] + quasiimmut_field(ConstPtr(myptr), descr=quasiimmutdescr) + guard_not_invalidated() [] + i1 = getfield_gc(ConstPtr(myptr), descr=quasifielddescr) + call_may_force(i0b, descr=mayforcevirtdescr) + quasiimmut_field(ConstPtr(myptr), descr=quasiimmutdescr) + guard_not_invalidated() [] + i2 = getfield_gc(ConstPtr(myptr), descr=quasifielddescr) + i3 = escape(i1) + i4 = escape(i2) + jump(i3, i4) + """ + expected = """ + [i0a, i0b] + guard_not_invalidated() [] + call_may_force(i0b, descr=mayforcevirtdescr) + guard_not_invalidated() [] + i3 = escape(-4247) + i4 = escape(-4247) + jump(i3, i4) + """ + self.optimize_loop(ops, expected) + + def test_call_may_force_invalidated_guards_virtual(self): + ops = """ + [i0a, i0b] + p = new(descr=quasisize) + setfield_gc(p, 421, descr=quasifielddescr) + quasiimmut_field(p, descr=quasiimmutdescr) + guard_not_invalidated() [] + i1 = getfield_gc(p, descr=quasifielddescr) + call_may_force(i0b, descr=mayforcevirtdescr) + quasiimmut_field(p, descr=quasiimmutdescr) + guard_not_invalidated() [] + i2 = getfield_gc(p, descr=quasifielddescr) + i3 = escape(i1) + i4 = escape(i2) + jump(i3, i4) + """ + expected = """ + [i0a, i0b] + call_may_force(i0b, descr=mayforcevirtdescr) + i3 = escape(421) + i4 = escape(421) + jump(i3, i4) + """ + self.optimize_loop(ops, expected) diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/test/test_optimizeutil.py --- a/pypy/jit/metainterp/test/test_optimizeutil.py +++ b/pypy/jit/metainterp/test/test_optimizeutil.py @@ -3,6 +3,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr from pypy.rpython.ootypesystem import ootype from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE +from pypy.rpython.rclass import FieldListAccessor, IR_QUASIIMMUTABLE from pypy.jit.backend.llgraph import runner from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, @@ -12,6 +13,7 @@ from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter.heaptracker import register_known_gctype, adr2int from pypy.jit.tool.oparser import parse +from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr def test_sort_descrs(): class PseudoDescr(AbstractDescr): @@ -62,6 +64,20 @@ nextdescr = cpu.fielddescrof(NODE, 'next') otherdescr = cpu.fielddescrof(NODE2, 'other') + accessor = FieldListAccessor() + accessor.initialize(None, {'inst_field': IR_QUASIIMMUTABLE}) + QUASI = lltype.GcStruct('QUASIIMMUT', ('inst_field', lltype.Signed), + ('mutate_field', rclass.OBJECTPTR), + hints={'immutable_fields': accessor}) + quasisize = cpu.sizeof(QUASI) + quasi = lltype.malloc(QUASI, immortal=True) + quasi.inst_field = -4247 + quasifielddescr = cpu.fielddescrof(QUASI, 'inst_field') + quasibox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, quasi)) + quasiimmutdescr = QuasiImmutDescr(cpu, quasibox, + quasifielddescr, + cpu.fielddescrof(QUASI, 'mutate_field')) + NODEOBJ = lltype.GcStruct('NODEOBJ', ('parent', OBJECT), ('ref', lltype.Ptr(OBJECT))) nodeobj = lltype.malloc(NODEOBJ) diff --git a/pypy/jit/metainterp/test/test_quasiimmut.py b/pypy/jit/metainterp/test/test_quasiimmut.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_quasiimmut.py @@ -0,0 +1,462 @@ + +import py + +from pypy.rpython.lltypesystem import lltype, llmemory, rclass +from pypy.rpython.rclass import FieldListAccessor, IR_QUASIIMMUTABLE +from pypy.jit.metainterp import typesystem +from pypy.jit.metainterp.quasiimmut import QuasiImmut +from pypy.jit.metainterp.quasiimmut import get_current_qmut_instance +from pypy.jit.metainterp.test.support import LLJitMixin +from pypy.jit.codewriter.policy import StopAtXPolicy +from pypy.rlib.jit import JitDriver, dont_look_inside + + +def test_get_current_qmut_instance(): + accessor = FieldListAccessor() + accessor.initialize(None, {'inst_x': IR_QUASIIMMUTABLE}) + STRUCT = lltype.GcStruct('Foo', ('inst_x', lltype.Signed), + ('mutate_x', rclass.OBJECTPTR), + hints={'immutable_fields': accessor}) + foo = lltype.malloc(STRUCT, zero=True) + foo.inst_x = 42 + assert not foo.mutate_x + + class FakeCPU: + ts = typesystem.llhelper + + def bh_getfield_gc_r(self, gcref, fielddescr): + assert fielddescr == mutatefielddescr + foo = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), gcref) + result = foo.mutate_x + return lltype.cast_opaque_ptr(llmemory.GCREF, result) + + def bh_setfield_gc_r(self, gcref, fielddescr, newvalue_gcref): + assert fielddescr == mutatefielddescr + foo = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), gcref) + newvalue = lltype.cast_opaque_ptr(rclass.OBJECTPTR, newvalue_gcref) + foo.mutate_x = newvalue + + cpu = FakeCPU() + mutatefielddescr = ('fielddescr', STRUCT, 'mutate_x') + + foo_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, foo) + qmut1 = get_current_qmut_instance(cpu, foo_gcref, mutatefielddescr) + assert isinstance(qmut1, QuasiImmut) + qmut2 = get_current_qmut_instance(cpu, foo_gcref, mutatefielddescr) + assert qmut1 is qmut2 + + +class QuasiImmutTests(object): + + def test_simple_1(self): + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['a?'] + def __init__(self, a): + self.a = a + def f(a, x): + foo = Foo(a) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # read a quasi-immutable field out of a Constant + total += foo.a + x -= 1 + return total + # + res = self.meta_interp(f, [100, 7]) + assert res == 700 + self.check_loops(guard_not_invalidated=2, getfield_gc=0, + everywhere=True) + # + from pypy.jit.metainterp.warmspot import get_stats + loops = get_stats().loops + for loop in loops: + assert len(loop.quasi_immutable_deps) == 1 + assert isinstance(loop.quasi_immutable_deps.keys()[0], QuasiImmut) + + def test_nonopt_1(self): + myjitdriver = JitDriver(greens=[], reds=['x', 'total', 'lst']) + class Foo: + _immutable_fields_ = ['a?'] + def __init__(self, a): + self.a = a + def setup(x): + return [Foo(100 + i) for i in range(x)] + def f(a, x): + lst = setup(x) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(lst=lst, x=x, total=total) + # read a quasi-immutable field out of a variable + x -= 1 + total += lst[x].a + return total + # + assert f(100, 7) == 721 + res = self.meta_interp(f, [100, 7]) + assert res == 721 + self.check_loops(guard_not_invalidated=0, getfield_gc=1) + # + from pypy.jit.metainterp.warmspot import get_stats + loops = get_stats().loops + for loop in loops: + assert loop.quasi_immutable_deps is None + + def test_opt_via_virtual_1(self): + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['a?'] + def __init__(self, a): + self.a = a + class A: + pass + def f(a, x): + foo = Foo(a) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # make it a Constant after optimization only + a = A() + a.foo = foo + foo = a.foo + # read a quasi-immutable field out of it + total += foo.a + x -= 1 + return total + # + res = self.meta_interp(f, [100, 7]) + assert res == 700 + self.check_loops(guard_not_invalidated=2, getfield_gc=0, + everywhere=True) + + def test_change_during_tracing_1(self): + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['a?'] + def __init__(self, a): + self.a = a + @dont_look_inside + def residual_call(foo): + foo.a += 1 + def f(a, x): + foo = Foo(a) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # read a quasi-immutable field out of a Constant + total += foo.a + residual_call(foo) + x -= 1 + return total + # + assert f(100, 7) == 721 + res = self.meta_interp(f, [100, 7]) + assert res == 721 + self.check_loops(guard_not_invalidated=0, getfield_gc=1) + + def test_change_during_tracing_2(self): + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['a?'] + def __init__(self, a): + self.a = a + @dont_look_inside + def residual_call(foo, difference): + foo.a += difference + def f(a, x): + foo = Foo(a) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # read a quasi-immutable field out of a Constant + total += foo.a + residual_call(foo, +1) + residual_call(foo, -1) + x -= 1 + return total + # + assert f(100, 7) == 700 + res = self.meta_interp(f, [100, 7]) + assert res == 700 + self.check_loops(guard_not_invalidated=0, getfield_gc=1) + + def test_change_invalidate_reentering(self): + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['a?'] + def __init__(self, a): + self.a = a + def f(foo, x): + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # read a quasi-immutable field out of a Constant + total += foo.a + x -= 1 + return total + def g(a, x): + foo = Foo(a) + res1 = f(foo, x) + foo.a += 1 # invalidation, while the jit is not running + res2 = f(foo, x) # should still mark the loop as invalid + return res1 * 1000 + res2 + # + assert g(100, 7) == 700707 + res = self.meta_interp(g, [100, 7]) + assert res == 700707 + self.check_loops(guard_not_invalidated=2, getfield_gc=0) + + def test_invalidate_while_running(self): + jitdriver = JitDriver(greens=['foo'], reds=['i', 'total']) + + class Foo(object): + _immutable_fields_ = ['a?'] + def __init__(self, a): + self.a = a + + def external(foo, v): + if v: + foo.a = 2 + + def f(foo): + i = 0 + total = 0 + while i < 10: + jitdriver.jit_merge_point(i=i, foo=foo, total=total) + external(foo, i > 7) + i += 1 + total += foo.a + return total + + def g(): + return f(Foo(1)) + + assert self.meta_interp(g, [], policy=StopAtXPolicy(external)) == g() + + def test_invalidate_by_setfield(self): + jitdriver = JitDriver(greens=['bc', 'foo'], reds=['i', 'total']) + + class Foo(object): + _immutable_fields_ = ['a?'] + def __init__(self, a): + self.a = a + + def f(foo, bc): + i = 0 + total = 0 + while i < 10: + jitdriver.jit_merge_point(bc=bc, i=i, foo=foo, total=total) + if bc == 0: + f(foo, 1) + if bc == 1: + foo.a = int(i > 5) + i += 1 + total += foo.a + return total + + def g(): + return f(Foo(1), 0) + + assert self.meta_interp(g, []) == g() + + def test_invalidate_bridge(self): + jitdriver = JitDriver(greens=['foo'], reds=['i', 'total']) + + class Foo(object): + _immutable_fields_ = ['a?'] + + def f(foo): + i = 0 + total = 0 + while i < 10: + jitdriver.jit_merge_point(i=i, total=total, foo=foo) + if i > 5: + total += foo.a + else: + total += 2*foo.a + i += 1 + return total + + def main(): + foo = Foo() + foo.a = 1 + total = f(foo) + foo.a = 2 + total += f(foo) + foo.a = 1 + total += f(foo) + return total + + res = self.meta_interp(main, []) + self.check_loop_count(7) + assert res == main() + + def test_change_during_running(self): + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['a?'] + def __init__(self, a): + self.a = a + @dont_look_inside + def residual_call(foo, x): + if x == 5: + foo.a += 1 + def f(a, x): + foo = Foo(a) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # read a quasi-immutable field out of a Constant + total += foo.a + residual_call(foo, x) + total += foo.a + x -= 1 + return total + # + assert f(100, 15) == 3009 + res = self.meta_interp(f, [100, 15]) + assert res == 3009 + self.check_loops(guard_not_invalidated=2, getfield_gc=0, + call_may_force=0, guard_not_forced=0) + + def test_list_simple_1(self): + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['lst?[*]'] + def __init__(self, lst): + self.lst = lst + def f(a, x): + lst1 = [0, 0] + lst1[1] = a + foo = Foo(lst1) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # read a quasi-immutable field out of a Constant + total += foo.lst[1] + x -= 1 + return total + # + res = self.meta_interp(f, [100, 7]) + assert res == 700 + self.check_loops(guard_not_invalidated=2, getfield_gc=0, + getarrayitem_gc=0, getarrayitem_gc_pure=0, + everywhere=True) + # + from pypy.jit.metainterp.warmspot import get_stats + loops = get_stats().loops + for loop in loops: + assert len(loop.quasi_immutable_deps) == 1 + assert isinstance(loop.quasi_immutable_deps.keys()[0], QuasiImmut) + + def test_list_length_1(self): + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['lst?[*]'] + def __init__(self, lst): + self.lst = lst + class A: + pass + def f(a, x): + lst1 = [0, 0] + lst1[1] = a + foo = Foo(lst1) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # make it a Constant after optimization only + a = A() + a.foo = foo + foo = a.foo + # read a quasi-immutable field out of it + total += foo.lst[1] + # also read the length + total += len(foo.lst) + x -= 1 + return total + # + res = self.meta_interp(f, [100, 7]) + assert res == 714 + self.check_loops(guard_not_invalidated=2, getfield_gc=0, + getarrayitem_gc=0, getarrayitem_gc_pure=0, + arraylen_gc=0, everywhere=True) + # + from pypy.jit.metainterp.warmspot import get_stats + loops = get_stats().loops + for loop in loops: + assert len(loop.quasi_immutable_deps) == 1 + assert isinstance(loop.quasi_immutable_deps.keys()[0], QuasiImmut) + + def test_list_pass_around(self): + py.test.skip("think about a way to fix it") + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['lst?[*]'] + def __init__(self, lst): + self.lst = lst + def g(lst): + # here, 'lst' is statically annotated as a "modified" list, + # so the following doesn't generate a getarrayitem_gc_pure... + return lst[1] + def f(a, x): + lst1 = [0, 0] + g(lst1) + lst1[1] = a + foo = Foo(lst1) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # read a quasi-immutable field out of a Constant + total += g(foo.lst) + x -= 1 + return total + # + res = self.meta_interp(f, [100, 7]) + assert res == 700 + self.check_loops(guard_not_invalidated=2, getfield_gc=0, + getarrayitem_gc=0, getarrayitem_gc_pure=0, + everywhere=True) + # + from pypy.jit.metainterp.warmspot import get_stats + loops = get_stats().loops + for loop in loops: + assert len(loop.quasi_immutable_deps) == 1 + assert isinstance(loop.quasi_immutable_deps.keys()[0], QuasiImmut) + + def test_list_change_during_running(self): + myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) + class Foo: + _immutable_fields_ = ['lst?[*]'] + def __init__(self, lst): + self.lst = lst + @dont_look_inside + def residual_call(foo, x): + if x == 5: + lst2 = [0, 0] + lst2[1] = foo.lst[1] + 1 + foo.lst = lst2 + def f(a, x): + lst1 = [0, 0] + lst1[1] = a + foo = Foo(lst1) + total = 0 + while x > 0: + myjitdriver.jit_merge_point(foo=foo, x=x, total=total) + # read a quasi-immutable field out of a Constant + total += foo.lst[1] + residual_call(foo, x) + total += foo.lst[1] + x -= 1 + return total + # + assert f(100, 15) == 3009 + res = self.meta_interp(f, [100, 15]) + assert res == 3009 + self.check_loops(guard_not_invalidated=2, getfield_gc=0, + getarrayitem_gc=0, getarrayitem_gc_pure=0, + call_may_force=0, guard_not_forced=0) + + +class TestLLtypeGreenFieldsTests(QuasiImmutTests, LLJitMixin): + pass diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -2,6 +2,7 @@ from pypy.rpython.extregistry import ExtRegistryEntry from pypy.rpython.lltypesystem import lltype, lloperation, rclass, llmemory from pypy.rpython.annlowlevel import llhelper +from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker from pypy.rlib.jit import JitDriver, hint, dont_look_inside @@ -45,7 +46,7 @@ ('inst_node', lltype.Ptr(LLtypeMixin.NODE)), hints = {'virtualizable2_accessor': FieldListAccessor()}) XY._hints['virtualizable2_accessor'].initialize( - XY, {'inst_x' : "", 'inst_node' : ""}) + XY, {'inst_x' : IR_IMMUTABLE, 'inst_node' : IR_IMMUTABLE}) xy_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) heaptracker.set_testing_vtable_for_gcstruct(XY, xy_vtable, 'XY') @@ -210,7 +211,8 @@ ('inst_l2', lltype.Ptr(lltype.GcArray(lltype.Signed))), hints = {'virtualizable2_accessor': FieldListAccessor()}) XY2._hints['virtualizable2_accessor'].initialize( - XY2, {'inst_x' : "", 'inst_l1' : "[*]", 'inst_l2' : "[*]"}) + XY2, {'inst_x' : IR_IMMUTABLE, + 'inst_l1' : IR_IMMUTABLE_ARRAY, 'inst_l2' : IR_IMMUTABLE_ARRAY}) xy2_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) heaptracker.set_testing_vtable_for_gcstruct(XY2, xy2_vtable, 'XY2') diff --git a/pypy/jit/metainterp/virtualizable.py b/pypy/jit/metainterp/virtualizable.py --- a/pypy/jit/metainterp/virtualizable.py +++ b/pypy/jit/metainterp/virtualizable.py @@ -1,6 +1,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.ootypesystem import ootype from pypy.rpython.annlowlevel import cast_base_ptr_to_instance +from pypy.rpython.rclass import IR_IMMUTABLE_ARRAY, IR_IMMUTABLE from pypy.rpython import rvirtualizable2 from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable @@ -10,7 +11,7 @@ from pypy.jit.metainterp.warmstate import wrap, unwrap from pypy.rlib.objectmodel import specialize -class VirtualizableInfo: +class VirtualizableInfo(object): TOKEN_NONE = 0 # must be 0 -- see also x86.call_assembler TOKEN_TRACING_RESCALL = -1 @@ -33,11 +34,13 @@ all_fields = accessor.fields static_fields = [] array_fields = [] - for name, suffix in all_fields.iteritems(): - if suffix == '[*]': + for name, tp in all_fields.iteritems(): + if tp == IR_IMMUTABLE_ARRAY: array_fields.append(name) + elif tp == IR_IMMUTABLE: + static_fields.append(name) else: - static_fields.append(name) + raise Exception("unknown type: %s" % tp) self.static_fields = static_fields self.array_fields = array_fields # diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -131,6 +131,16 @@ def find_set_param(graphs): return _find_jit_marker(graphs, 'set_param') +def find_force_quasi_immutable(graphs): + results = [] + for graph in graphs: + for block in graph.iterblocks(): + for i in range(len(block.operations)): + op = block.operations[i] + if op.opname == 'jit_force_quasi_immutable': + results.append((graph, block, i)) + return results + def get_stats(): return pyjitpl._warmrunnerdesc.stats @@ -187,6 +197,7 @@ self.rewrite_can_enter_jits() self.rewrite_set_param() self.rewrite_force_virtual(vrefinfo) + self.rewrite_force_quasi_immutable() self.add_finish() self.metainterp_sd.finish_setup(self.codewriter) @@ -842,6 +853,28 @@ all_graphs = self.translator.graphs vrefinfo.replace_force_virtual_with_call(all_graphs) + def replace_force_quasiimmut_with_direct_call(self, op): + ARG = op.args[0].concretetype + mutatefieldname = op.args[1].value + key = (ARG, mutatefieldname) + if key in self._cache_force_quasiimmed_funcs: + cptr = self._cache_force_quasiimmed_funcs[key] + else: + from pypy.jit.metainterp import quasiimmut + func = quasiimmut.make_invalidation_function(ARG, mutatefieldname) + FUNC = lltype.Ptr(lltype.FuncType([ARG], lltype.Void)) + llptr = self.helper_func(FUNC, func) + cptr = Constant(llptr, FUNC) + self._cache_force_quasiimmed_funcs[key] = cptr + op.opname = 'direct_call' + op.args = [cptr, op.args[0]] + + def rewrite_force_quasi_immutable(self): + self._cache_force_quasiimmed_funcs = {} + graphs = self.translator.graphs + for graph, block, i in find_force_quasi_immutable(graphs): + self.replace_force_quasiimmut_with_direct_call(block.operations[i]) + # ____________________________________________________________ def execute_token(self, loop_token): diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py --- a/pypy/jit/tl/pypyjit.py +++ b/pypy/jit/tl/pypyjit.py @@ -115,6 +115,8 @@ # print a message, and restart unixcheckpoint.restartable_point(auto='run') + from pypy.jit.codewriter.codewriter import CodeWriter + CodeWriter.debug = True from pypy.jit.tl.pypyjit_child import run_child, run_child_ootype if BACKEND == 'c': run_child(globals(), locals()) diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -1,18 +1,11 @@ try: - def g(x): - return x - 1 def f(x): - while x: - x = g(x) - import cProfile - import time - t1 = time.time() - cProfile.run("f(10000000)") - t2 = time.time() - f(10000000) - t3 = time.time() - print t2 - t1, t3 - t2, (t3 - t2) / (t2 - t1) + i = 0 + while i < x: + range(i) + i += 1 + f(10000) except Exception, e: print "Exception: ", type(e) print e diff --git a/pypy/jit/tool/jitoutput.py b/pypy/jit/tool/jitoutput.py --- a/pypy/jit/tool/jitoutput.py +++ b/pypy/jit/tool/jitoutput.py @@ -25,6 +25,7 @@ (('abort.compiling',), '^abort: compiling:\s+(\d+)$'), (('abort.vable_escape',), '^abort: vable escape:\s+(\d+)$'), (('abort.bad_loop',), '^abort: bad loop:\s+(\d+)$'), + (('abort.force_quasiimmut',), '^abort: force quasi-immut:\s+(\d+)$'), (('nvirtuals',), '^nvirtuals:\s+(\d+)$'), (('nvholes',), '^nvholes:\s+(\d+)$'), (('nvreused',), '^nvreused:\s+(\d+)$'), diff --git a/pypy/jit/tool/test/test_jitoutput.py b/pypy/jit/tool/test/test_jitoutput.py --- a/pypy/jit/tool/test/test_jitoutput.py +++ b/pypy/jit/tool/test/test_jitoutput.py @@ -61,6 +61,7 @@ abort: compiling: 11 abort: vable escape: 12 abort: bad loop: 135 +abort: force quasi-immut: 3 nvirtuals: 13 nvholes: 14 nvreused: 15 @@ -89,6 +90,7 @@ assert info.abort.compiling == 11 assert info.abort.vable_escape == 12 assert info.abort.bad_loop == 135 + assert info.abort.force_quasiimmut == 3 assert info.nvirtuals == 13 assert info.nvholes == 14 assert info.nvreused == 15 diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -128,7 +128,7 @@ if op.name != 'debug_merge_point' or include_debug_merge_points: yield op - def allops(self, include_debug_merge_points=False, opcode=None): + def _allops(self, include_debug_merge_points=False, opcode=None): opcode_name = opcode for chunk in self.flatten_chunks(): opcode = chunk.getopcode() @@ -136,6 +136,9 @@ for op in self._ops_for_chunk(chunk, include_debug_merge_points): yield op + def allops(self, *args, **kwds): + return list(self._allops(*args, **kwds)) + def format_ops(self, id=None, **kwds): if id is None: ops = self.allops(**kwds) @@ -146,7 +149,7 @@ def print_ops(self, *args, **kwds): print self.format_ops(*args, **kwds) - def ops_by_id(self, id, include_debug_merge_points=False, opcode=None): + def _ops_by_id(self, id, include_debug_merge_points=False, opcode=None): opcode_name = opcode target_opcodes = self.ids[id] for chunk in self.flatten_chunks(): @@ -156,6 +159,9 @@ for op in self._ops_for_chunk(chunk, include_debug_merge_points): yield op + def ops_by_id(self, *args, **kwds): + return list(self._ops_by_id(*args, **kwds)) + def match(self, expected_src, **kwds): ops = list(self.allops()) matcher = OpMatcher(ops, src=self.format_ops()) @@ -167,6 +173,7 @@ return matcher.match(expected_src) class InvalidMatch(Exception): + opindex = None def __init__(self, message, frame): Exception.__init__(self, message) @@ -326,31 +333,39 @@ """ iter_exp_ops = iter(expected_ops) iter_ops = iter(self.ops) - for exp_op in iter_exp_ops: - if exp_op == '...': - # loop until we find an operation which matches - try: - exp_op = iter_exp_ops.next() - except StopIteration: - # the ... is the last line in the expected_ops, so we just - # return because it matches everything until the end - return - op = self.match_until(exp_op, iter_ops) - else: - while True: - op = self._next_op(iter_ops) - if op.name not in ignore_ops: - break - self.match_op(op, exp_op) + for opindex, exp_op in enumerate(iter_exp_ops): + try: + if exp_op == '...': + # loop until we find an operation which matches + try: + exp_op = iter_exp_ops.next() + except StopIteration: + # the ... is the last line in the expected_ops, so we just + # return because it matches everything until the end + return + op = self.match_until(exp_op, iter_ops) + else: + while True: + op = self._next_op(iter_ops) + if op.name not in ignore_ops: + break + self.match_op(op, exp_op) + except InvalidMatch, e: + e.opindex = opindex + raise # # make sure we exhausted iter_ops self._next_op(iter_ops, assert_raises=True) def match(self, expected_src, ignore_ops=[]): - def format(src): + def format(src, opindex=None): if src is None: return '' - return py.code.Source(src).deindent().indent() + text = str(py.code.Source(src).deindent().indent()) + lines = text.splitlines(True) + if opindex is not None and 0 <= opindex < len(lines): + lines[opindex] = lines[opindex].rstrip() + '\t<=====\n' + return ''.join(lines) # expected_src = self.preprocess_expected_src(expected_src) expected_ops = self.parse_ops(expected_src) @@ -366,7 +381,7 @@ print print "Ignore ops:", ignore_ops print "Got:" - print format(self.src) + print format(self.src, e.opindex) print print "Expected:" print format(expected_src) diff --git a/pypy/module/pypyjit/test_pypy_c/test_model.py b/pypy/module/pypyjit/test_pypy_c/test_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_model.py @@ -468,11 +468,13 @@ log = self.run(f) loop, = log.loops_by_id('ntohs') assert loop.match_by_id('ntohs', """ + guard_not_invalidated(descr=...) p12 = call(ConstClass(ntohs), 1, descr=...) guard_no_exception(descr=...) """) # assert not loop.match_by_id('ntohs', """ + guard_not_invalidated(descr=...) p12 = call(ConstClass(foobar), 1, descr=...) guard_no_exception(descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py --- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py +++ b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py @@ -221,7 +221,7 @@ entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('meth1', opcode='LOOKUP_METHOD') assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', - 'getfield_gc', 'guard_value'] + 'guard_not_invalidated'] # the second LOOKUP_METHOD is folded away assert list(entry_bridge.ops_by_id('meth2', opcode='LOOKUP_METHOD')) == [] # @@ -231,14 +231,15 @@ assert loop.match(""" i15 = int_lt(i6, i9) guard_true(i15, descr=) + guard_not_invalidated(descr=) i16 = force_token() i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) + guard_no_overflow(descr=) i18 = force_token() i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) + guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, p14, descr=) + jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) """) def test_static_classmethod_call(self): @@ -264,17 +265,17 @@ assert loop.match(""" i14 = int_lt(i6, i9) guard_true(i14, descr=) + guard_not_invalidated(descr=) i15 = force_token() i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=) i18 = force_token() i20 = int_sub(i17, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i20, p7, i17, i9, p10, p11, p12, p13, descr=) + jump(p0, p1, p2, p3, p4, p5, i20, p7, i17, i9, p10, p11, p12, descr=) """) def test_default_and_kw(self): - py.test.skip("Wait until we have saner defaults strat") def main(n): def f(i, j=1): return i + j @@ -415,8 +416,9 @@ assert loop.match(""" i7 = int_lt(i5, i6) guard_true(i7, descr=) + guard_not_invalidated(descr=) i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) """) @@ -439,10 +441,11 @@ assert loop.match(""" i9 = int_lt(i5, i6) guard_true(i9, descr=) + guard_not_invalidated(descr=) i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, i10, i6, i7, p8, descr=) + jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) """) def test_mixed_type_loop(self): @@ -506,15 +509,15 @@ i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) + guard_not_invalidated(descr=) i23 = int_lt(i18, 0) - guard_false(i23, descr=) + guard_false(i23, descr=) i25 = int_ge(i18, i9) - guard_false(i25, descr=) - i26 = int_mul(i18, i10) - i27 = int_add_ovf(i7, i26) - guard_no_overflow(descr=) + guard_false(i25, descr=) + i27 = int_add_ovf(i7, i18) + guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i27, i18, i9, i10, i20, i12, p13, i14, i15, descr=) + jump(..., descr=) """) def test_exception_inside_loop_1(self): @@ -533,11 +536,12 @@ assert loop.match(""" i5 = int_is_true(i3) guard_true(i5, descr=) + guard_not_invalidated(descr=) --EXC-TICK-- i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, i12, descr=) + jump(..., descr=) """) def test_exception_inside_loop_2(self): @@ -580,10 +584,11 @@ assert loop.match(""" i7 = int_lt(i4, i5) guard_true(i7, descr=) + guard_not_invalidated(descr=) --EXC-TICK-- i14 = int_add(i4, 1) --TICK-- - jump(p0, p1, p2, p3, i14, i5, descr=) + jump(..., descr=) """) def test_chain_of_guards(self): @@ -685,10 +690,11 @@ assert loop.match_by_id('import', """ p11 = getfield_gc(ConstPtr(ptr10), descr=) guard_value(p11, ConstPtr(ptr12), descr=) + guard_not_invalidated(descr=) p14 = getfield_gc(ConstPtr(ptr13), descr=) p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) + guard_value(p14, ConstPtr(ptr17), descr=) + guard_isnull(p16, descr=) """) def test_import_fast_path(self, tmpdir): @@ -1109,7 +1115,7 @@ # ------------------------------- entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') - assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', + assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', 'getfield_gc', 'guard_nonnull_class'] # the STORE_ATTR is folded away assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] @@ -1121,6 +1127,7 @@ i8 = getfield_gc_pure(p5, descr=) i9 = int_lt(i8, i7) guard_true(i9, descr=.*) + guard_not_invalidated(descr=.*) i11 = int_add(i8, 1) i12 = force_token() --TICK-- diff --git a/pypy/objspace/std/boolobject.py b/pypy/objspace/std/boolobject.py --- a/pypy/objspace/std/boolobject.py +++ b/pypy/objspace/std/boolobject.py @@ -5,8 +5,7 @@ class W_BoolObject(W_Object): from pypy.objspace.std.booltype import bool_typedef as typedef - - _immutable_ = True + _immutable_fields_ = ['boolval'] def __init__(w_self, boolval): w_self.boolval = not not boolval diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -22,7 +22,6 @@ from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.buffer import RWBuffer -from pypy.interpreter.function import Defaults from pypy.objspace.std.bytearraytype import ( makebytearraydata_w, getbytevalue, new_bytearray @@ -43,7 +42,7 @@ registerimplementation(W_BytearrayObject) init_signature = Signature(['source', 'encoding', 'errors'], None, None) -init_defaults = Defaults([None, None, None]) +init_defaults = [None, None, None] def init__Bytearray(space, w_bytearray, __args__): # this is on the silly side diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -4,7 +4,6 @@ from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import Defaults from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS from pypy.rlib.objectmodel import r_dict, we_are_translated @@ -617,7 +616,7 @@ init_signature = Signature(['seq_or_map'], None, 'kwargs') -init_defaults = Defaults([None]) +init_defaults = [None] def update1(space, w_dict, w_data): if space.findattr(w_data, space.wrap("keys")) is None: diff --git a/pypy/objspace/std/fake.py b/pypy/objspace/std/fake.py --- a/pypy/objspace/std/fake.py +++ b/pypy/objspace/std/fake.py @@ -144,7 +144,7 @@ frame = func.space.createframe(self, func.w_func_globals, func.closure) sig = self.signature() - scope_w = args.parse_obj(None, func.name, sig, func.defs.getitems()) + scope_w = args.parse_obj(None, func.name, sig, func.defs_w) frame.setfastscope(scope_w) return frame.run() diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -8,7 +8,6 @@ from pypy.objspace.std import slicetype from pypy.interpreter import gateway, baseobjspace -from pypy.interpreter.function import Defaults from pypy.rlib.listsort import TimSort from pypy.interpreter.argument import Signature @@ -33,7 +32,7 @@ init_signature = Signature(['sequence'], None, None) -init_defaults = Defaults([None]) +init_defaults = [None] def init__List(space, w_list, __args__): from pypy.objspace.std.tupleobject import W_TupleObject diff --git a/pypy/objspace/std/noneobject.py b/pypy/objspace/std/noneobject.py --- a/pypy/objspace/std/noneobject.py +++ b/pypy/objspace/std/noneobject.py @@ -9,7 +9,6 @@ class W_NoneObject(W_Object): from pypy.objspace.std.nonetype import none_typedef as typedef - _immutable_ = True def unwrap(w_self, space): return None diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -5,7 +5,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter import gateway from pypy.interpreter.argument import Signature -from pypy.interpreter.function import Defaults from pypy.objspace.std.settype import set_typedef as settypedef from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef @@ -625,7 +624,7 @@ cmp__Frozenset_frozensettypedef = cmp__Set_settypedef init_signature = Signature(['some_iterable'], None, None) -init_defaults = Defaults([None]) +init_defaults = [None] def init__Set(space, w_set, __args__): w_iterable, = __args__.parse_obj( None, 'set', diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -88,13 +88,14 @@ _immutable_fields_ = ["flag_heaptype", "flag_cpytype", - # flag_abstract is not immutable + "flag_abstract?", 'needsdel', 'weakrefable', 'hasdict', 'nslots', 'instancetypedef', 'terminator', + '_version_tag?', ] # for config.objspace.std.getattributeshortcut diff --git a/pypy/rpython/annlowlevel.py b/pypy/rpython/annlowlevel.py --- a/pypy/rpython/annlowlevel.py +++ b/pypy/rpython/annlowlevel.py @@ -480,7 +480,26 @@ # ____________________________________________________________ def cast_object_to_ptr(PTR, object): - raise NotImplementedError("cast_object_to_ptr") + """NOT_RPYTHON: hack. The object may be disguised as a PTR now. + Limited to casting a given object to a single type. + """ + if isinstance(PTR, lltype.Ptr): + TO = PTR.TO + else: + TO = PTR + if not hasattr(object, '_carry_around_for_tests'): + assert not hasattr(object, '_TYPE') + object._carry_around_for_tests = True + object._TYPE = TO + else: + assert object._TYPE == TO + # + if isinstance(PTR, lltype.Ptr): + return lltype._ptr(PTR, object, True) + elif isinstance(PTR, ootype.Instance): + return object + else: + raise NotImplementedError("cast_object_to_ptr(%r, ...)" % PTR) def cast_instance_to_base_ptr(instance): return cast_object_to_ptr(base_ptr_lltype(), instance) @@ -535,7 +554,13 @@ # ____________________________________________________________ def cast_base_ptr_to_instance(Class, ptr): - raise NotImplementedError("cast_base_ptr_to_instance") + """NOT_RPYTHON: hack. Reverse the hacking done in cast_object_to_ptr().""" + if isinstance(lltype.typeOf(ptr), lltype.Ptr): + ptr = ptr._as_obj() + if not isinstance(ptr, Class): + raise NotImplementedError("cast_base_ptr_to_instance: casting %r to %r" + % (ptr, Class)) + return ptr class CastBasePtrToInstanceEntry(extregistry.ExtRegistryEntry): _about_ = cast_base_ptr_to_instance diff --git a/pypy/rpython/callparse.py b/pypy/rpython/callparse.py --- a/pypy/rpython/callparse.py +++ b/pypy/rpython/callparse.py @@ -1,5 +1,4 @@ from pypy.interpreter.argument import ArgumentsForTranslation, ArgErr -from pypy.interpreter.function import Defaults from pypy.annotation import model as annmodel from pypy.rpython import rtuple from pypy.rpython.error import TyperError @@ -53,7 +52,7 @@ for x in graph.defaults: defs_h.append(ConstHolder(x)) try: - holders = arguments.match_signature(signature, Defaults(defs_h)) + holders = arguments.match_signature(signature, defs_h) except ArgErr, e: raise TyperError, "signature mismatch: %s" % e.getmsg(graph.name) diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -578,6 +578,7 @@ _all_callbacks_results = [] _int2obj = {} _callback_exc_info = None +_opaque_objs = [None] def get_rtyper(): llinterp = LLInterpreter.current_interpreter @@ -616,6 +617,10 @@ T = lltype.Ptr(lltype.typeOf(container)) # otherwise it came from integer and we want a c_void_p with # the same valu + if getattr(container, 'llopaque', None): + no = len(_opaque_objs) + _opaque_objs.append(container) + return no * 2 + 1 else: container = llobj._obj if isinstance(T.TO, lltype.FuncType): @@ -764,10 +769,14 @@ if isinstance(T, lltype.Typedef): T = T.OF if isinstance(T, lltype.Ptr): - if not cobj or not ctypes.cast(cobj, ctypes.c_void_p).value: # NULL pointer + ptrval = ctypes.cast(cobj, ctypes.c_void_p).value + if not cobj or not ptrval: # NULL pointer # CFunctionType.__nonzero__ is broken before Python 2.6 return lltype.nullptr(T.TO) if isinstance(T.TO, lltype.Struct): + if ptrval & 1: # a tagged pointer + gcref = _opaque_objs[ptrval // 2].hide() + return lltype.cast_opaque_ptr(T, gcref) REAL_TYPE = T.TO if T.TO._arrayfld is not None: carray = getattr(cobj.contents, T.TO._arrayfld) @@ -1231,7 +1240,9 @@ return not self == other def _cast_to_ptr(self, PTRTYPE): - return force_cast(PTRTYPE, self.intval) + if self.intval & 1: + return _opaque_objs[self.intval // 2] + return force_cast(PTRTYPE, self.intval) ## def _cast_to_int(self): ## return self.intval diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -433,6 +433,7 @@ 'jit_marker': LLOp(), 'jit_force_virtualizable':LLOp(canrun=True), 'jit_force_virtual': LLOp(canrun=True), + 'jit_force_quasi_immutable': LLOp(canrun=True), 'get_exception_addr': LLOp(), 'get_exc_value_addr': LLOp(), 'do_malloc_fixedsize_clear':LLOp(canraise=(MemoryError,),canunwindgc=True), diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -341,13 +341,14 @@ return _struct(self, n, initialization='example') def _immutable_field(self, field): + if self._hints.get('immutable'): + return True if 'immutable_fields' in self._hints: try: - s = self._hints['immutable_fields'].fields[field] - return s or True + return self._hints['immutable_fields'].fields[field] except KeyError: pass - return self._hints.get('immutable', False) + return False class RttiStruct(Struct): _runtime_type_info = None @@ -1029,6 +1030,8 @@ return None # null pointer if type(p._obj0) is int: return p # a pointer obtained by cast_int_to_ptr + if getattr(p._obj0, '_carry_around_for_tests', False): + return p # a pointer obtained by cast_instance_to_base_ptr container = obj._normalizedcontainer() if type(container) is int: # this must be an opaque ptr originating from an integer @@ -1881,8 +1884,8 @@ if self.__class__ is not other.__class__: return NotImplemented if hasattr(self, 'container') and hasattr(other, 'container'): - obj1 = self.container._normalizedcontainer() - obj2 = other.container._normalizedcontainer() + obj1 = self._normalizedcontainer() + obj2 = other._normalizedcontainer() return obj1 == obj2 else: return self is other @@ -1906,6 +1909,8 @@ # an integer, cast to a ptr, cast to an opaque if type(self.container) is int: return self.container + if getattr(self.container, '_carry_around_for_tests', False): + return self.container return self.container._normalizedcontainer() else: return _parentable._normalizedcontainer(self) diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -525,6 +525,9 @@ def op_jit_force_virtual(x): return x +def op_jit_force_quasi_immutable(*args): + pass + def op_get_group_member(TYPE, grpptr, memberoffset): from pypy.rpython.lltypesystem import llgroup assert isinstance(memberoffset, llgroup.GroupMemberOffset) diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py --- a/pypy/rpython/lltypesystem/rclass.py +++ b/pypy/rpython/lltypesystem/rclass.py @@ -322,6 +322,7 @@ # before they are fully built, to avoid strange bugs in case # of recursion where other code would uses these # partially-initialized dicts. + AbstractInstanceRepr._setup_repr(self) self.rclass = getclassrepr(self.rtyper, self.classdef) fields = {} allinstancefields = {} @@ -370,6 +371,11 @@ kwds = {} if self.gcflavor == 'gc': kwds['rtti'] = True + + for name, attrdef in attrs: + if not attrdef.readonly and self.is_quasi_immutable(name): + llfields.append(('mutate_' + name, OBJECTPTR)) + object_type = MkStruct(self.classdef.name, ('super', self.rbase.object_type), hints=hints, @@ -488,6 +494,7 @@ if force_cast: vinst = llops.genop('cast_pointer', [vinst], resulttype=self) self.hook_access_field(vinst, cname, llops, flags) + self.hook_setfield(vinst, attr, llops) llops.genop('setfield', [vinst, cname, vvalue]) else: if self.classdef is None: @@ -495,9 +502,6 @@ self.rbase.setfield(vinst, attr, vvalue, llops, force_cast=True, flags=flags) - def hook_access_field(self, vinst, cname, llops, flags): - pass # for virtualizables; see rvirtualizable2.py - def new_instance(self, llops, classcallhop=None): """Build a new instance, without calling __init__.""" flavor = self.gcflavor diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -1293,6 +1293,28 @@ rffi.cast(SP, p).x = 0 lltype.free(chunk, flavor='raw') + def test_opaque_tagged_pointers(self): + from pypy.rpython.annlowlevel import cast_base_ptr_to_instance + from pypy.rpython.annlowlevel import cast_instance_to_base_ptr + from pypy.rpython.lltypesystem import rclass + + class Opaque(object): + llopaque = True + + def hide(self): + ptr = cast_instance_to_base_ptr(self) + return lltype.cast_opaque_ptr(llmemory.GCREF, ptr) + + @staticmethod + def show(gcref): + ptr = lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), gcref) + return cast_base_ptr_to_instance(Opaque, ptr) + + opaque = Opaque() + round = ctypes2lltype(llmemory.GCREF, lltype2ctypes(opaque.hide())) + assert Opaque.show(round) is opaque + + class TestPlatform(object): def test_lib_on_libpaths(self): from pypy.translator.platform import platform diff --git a/pypy/rpython/lltypesystem/test/test_lloperation.py b/pypy/rpython/lltypesystem/test/test_lloperation.py --- a/pypy/rpython/lltypesystem/test/test_lloperation.py +++ b/pypy/rpython/lltypesystem/test/test_lloperation.py @@ -54,6 +54,7 @@ def test_is_pure(): from pypy.objspace.flow.model import Variable, Constant + from pypy.rpython import rclass assert llop.bool_not.is_pure([Variable()]) assert llop.debug_assert.is_pure([Variable()]) assert not llop.int_add_ovf.is_pure([Variable(), Variable()]) @@ -85,38 +86,52 @@ assert llop.getarrayitem.is_pure([v_a2, Variable()]) assert llop.getarraysize.is_pure([v_a2]) # - accessor = rclass.FieldListAccessor() - S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed), - hints={'immutable_fields': accessor}) - accessor.initialize(S3, {'x': ''}) - v_s3 = Variable() - v_s3.concretetype = lltype.Ptr(S3) - assert not llop.setfield.is_pure([v_s3, Constant('x'), Variable()]) - assert not llop.setfield.is_pure([v_s3, Constant('y'), Variable()]) - assert llop.getfield.is_pure([v_s3, Constant('x')]) - assert not llop.getfield.is_pure([v_s3, Constant('y')]) + for kind in [rclass.IR_MUTABLE, rclass.IR_IMMUTABLE, + rclass.IR_IMMUTABLE_ARRAY, rclass.IR_QUASIIMMUTABLE, + rclass.IR_QUASIIMMUTABLE_ARRAY]: + accessor = rclass.FieldListAccessor() + S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed), + hints={'immutable_fields': accessor}) + accessor.initialize(S3, {'x': kind}) + v_s3 = Variable() + v_s3.concretetype = lltype.Ptr(S3) + assert not llop.setfield.is_pure([v_s3, Constant('x'), Variable()]) + assert not llop.setfield.is_pure([v_s3, Constant('y'), Variable()]) + assert llop.getfield.is_pure([v_s3, Constant('x')]) is kind + assert not llop.getfield.is_pure([v_s3, Constant('y')]) def test_getfield_pure(): S1 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed)) S2 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed), hints={'immutable': True}) accessor = rclass.FieldListAccessor() - S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed), - hints={'immutable_fields': accessor}) - accessor.initialize(S3, {'x': ''}) # s1 = lltype.malloc(S1); s1.x = 45 py.test.raises(TypeError, llop.getfield, lltype.Signed, s1, 'x') s2 = lltype.malloc(S2); s2.x = 45 assert llop.getfield(lltype.Signed, s2, 'x') == 45 - s3 = lltype.malloc(S3); s3.x = 46; s3.y = 47 - assert llop.getfield(lltype.Signed, s3, 'x') == 46 - py.test.raises(TypeError, llop.getfield, lltype.Signed, s3, 'y') # py.test.raises(TypeError, llop.getinteriorfield, lltype.Signed, s1, 'x') assert llop.getinteriorfield(lltype.Signed, s2, 'x') == 45 - assert llop.getinteriorfield(lltype.Signed, s3, 'x') == 46 - py.test.raises(TypeError, llop.getinteriorfield, lltype.Signed, s3, 'y') + # + for kind in [rclass.IR_MUTABLE, rclass.IR_IMMUTABLE, + rclass.IR_IMMUTABLE_ARRAY, rclass.IR_QUASIIMMUTABLE, + rclass.IR_QUASIIMMUTABLE_ARRAY]: + # + S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed), + hints={'immutable_fields': accessor}) + accessor.initialize(S3, {'x': kind}) + s3 = lltype.malloc(S3); s3.x = 46; s3.y = 47 + if kind in [rclass.IR_IMMUTABLE, rclass.IR_IMMUTABLE_ARRAY]: + assert llop.getfield(lltype.Signed, s3, 'x') == 46 + assert llop.getinteriorfield(lltype.Signed, s3, 'x') == 46 + else: + py.test.raises(TypeError, llop.getfield, lltype.Signed, s3, 'x') + py.test.raises(TypeError, llop.getinteriorfield, + lltype.Signed, s3, 'x') + py.test.raises(TypeError, llop.getfield, lltype.Signed, s3, 'y') + py.test.raises(TypeError, llop.getinteriorfield, + lltype.Signed, s3, 'y') # ___________________________________________________________________________ # This tests that the LLInterpreter and the LL_OPERATIONS tables are in sync. diff --git a/pypy/rpython/lltypesystem/test/test_lltype.py b/pypy/rpython/lltypesystem/test/test_lltype.py --- a/pypy/rpython/lltypesystem/test/test_lltype.py +++ b/pypy/rpython/lltypesystem/test/test_lltype.py @@ -794,15 +794,8 @@ def __init__(self, fields): self.fields = fields S = GcStruct('S', ('x', lltype.Signed), - hints={'immutable_fields': FieldListAccessor({'x':''})}) - assert S._immutable_field('x') == True - # - class FieldListAccessor(object): - def __init__(self, fields): - self.fields = fields - S = GcStruct('S', ('x', lltype.Signed), - hints={'immutable_fields': FieldListAccessor({'x':'[*]'})}) - assert S._immutable_field('x') == '[*]' + hints={'immutable_fields': FieldListAccessor({'x': 1234})}) + assert S._immutable_field('x') == 1234 def test_typedef(): T = Typedef(Signed, 'T') diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -268,13 +268,14 @@ return self._superclass._get_fields_with_default() + self._fields_with_default def _immutable_field(self, field): + if self._hints.get('immutable'): + return True if 'immutable_fields' in self._hints: try: - s = self._hints['immutable_fields'].fields[field] - return s or True + return self._hints['immutable_fields'].fields[field] except KeyError: pass - return self._hints.get('immutable', False) + return False class SpecializableType(OOType): diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -262,6 +262,10 @@ self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef) self.rbase.setup() + for name, attrdef in selfattrs.iteritems(): + if not attrdef.readonly and self.is_quasi_immutable(name): + ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + classattributes = {} baseInstance = self.lowleveltype._superclass classrepr = getclassrepr(self.rtyper, self.classdef) @@ -476,11 +480,9 @@ mangled_name = mangle(attr, self.rtyper.getconfig()) cname = inputconst(ootype.Void, mangled_name) self.hook_access_field(vinst, cname, llops, flags) + self.hook_setfield(vinst, attr, llops) llops.genop('oosetfield', [vinst, cname, vvalue]) - def hook_access_field(self, vinst, cname, llops, flags): - pass # for virtualizables; see rvirtualizable2.py - def rtype_is_true(self, hop): vinst, = hop.inputargs(self) return hop.genop('oononnull', [vinst], resulttype=ootype.Bool) diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -3,7 +3,8 @@ #from pypy.annotation.classdef import isclassdef from pypy.annotation import description from pypy.rpython.error import TyperError -from pypy.rpython.rmodel import Repr, getgcflavor +from pypy.rpython.rmodel import Repr, getgcflavor, inputconst +from pypy.rpython.lltypesystem.lltype import Void class FieldListAccessor(object): @@ -12,6 +13,8 @@ assert type(fields) is dict self.TYPE = TYPE self.fields = fields + for x in fields.itervalues(): + assert isinstance(x, ImmutableRanking) def __repr__(self): return '' % getattr(self, 'TYPE', '?') @@ -19,6 +22,21 @@ def _freeze_(self): return True +class ImmutableRanking(object): + def __init__(self, name, is_immutable): + self.name = name + self.is_immutable = is_immutable + def __nonzero__(self): + return self.is_immutable + def __repr__(self): + return '<%s>' % self.name + +IR_MUTABLE = ImmutableRanking('mutable', False) +IR_IMMUTABLE = ImmutableRanking('immutable', True) +IR_IMMUTABLE_ARRAY = ImmutableRanking('immutable_array', True) +IR_QUASIIMMUTABLE = ImmutableRanking('quasiimmutable', False) +IR_QUASIIMMUTABLE_ARRAY = ImmutableRanking('quasiimmutable_array', False) + class ImmutableConflictError(Exception): """Raised when the _immutable_ or _immutable_fields_ hints are not consistent across a class hierarchy.""" @@ -155,7 +173,8 @@ self.classdef = classdef def _setup_repr(self): - pass + if self.classdef is None: + self.immutable_field_set = set() def _check_for_immutable_hints(self, hints): loc = self.classdef.classdesc.lookup('_immutable_') @@ -167,13 +186,13 @@ self.classdef,)) hints = hints.copy() hints['immutable'] = True - self.immutable_field_list = [] # unless overwritten below + self.immutable_field_set = set() # unless overwritten below if self.classdef.classdesc.lookup('_immutable_fields_') is not None: hints = hints.copy() immutable_fields = self.classdef.classdesc.classdict.get( '_immutable_fields_') if immutable_fields is not None: - self.immutable_field_list = immutable_fields.value + self.immutable_field_set = set(immutable_fields.value) accessor = FieldListAccessor() hints['immutable_fields'] = accessor return hints @@ -201,33 +220,38 @@ if "immutable_fields" in hints: accessor = hints["immutable_fields"] if not hasattr(accessor, 'fields'): - immutable_fields = [] + immutable_fields = set() rbase = self while rbase.classdef is not None: - immutable_fields += rbase.immutable_field_list + immutable_fields.update(rbase.immutable_field_set) rbase = rbase.rbase self._parse_field_list(immutable_fields, accessor) def _parse_field_list(self, fields, accessor): - with_suffix = {} + ranking = {} for name in fields: - if name.endswith('[*]'): + if name.endswith('?[*]'): # a quasi-immutable field pointing to + name = name[:-4] # an immutable array + rank = IR_QUASIIMMUTABLE_ARRAY + elif name.endswith('[*]'): # for virtualizables' lists name = name[:-3] - suffix = '[*]' - else: - suffix = '' + rank = IR_IMMUTABLE_ARRAY + elif name.endswith('?'): # a quasi-immutable field + name = name[:-1] + rank = IR_QUASIIMMUTABLE + else: # a regular immutable/green field + rank = IR_IMMUTABLE try: mangled_name, r = self._get_field(name) except KeyError: continue - with_suffix[mangled_name] = suffix - accessor.initialize(self.object_type, with_suffix) - return with_suffix + ranking[mangled_name] = rank + accessor.initialize(self.object_type, ranking) + return ranking def _check_for_immutable_conflicts(self): # check for conflicts, i.e. a field that is defined normally as # mutable in some parent class but that is now declared immutable - from pypy.rpython.lltypesystem.lltype import Void is_self_immutable = "immutable" in self.object_type._hints base = self while base.classdef is not None: @@ -248,12 +272,32 @@ "class %r has _immutable_=True, but parent class %r " "defines (at least) the mutable field %r" % ( self, base, fieldname)) - if fieldname in self.immutable_field_list: + if (fieldname in self.immutable_field_set or + (fieldname + '?') in self.immutable_field_set): raise ImmutableConflictError( "field %r is defined mutable in class %r, but " "listed in _immutable_fields_ in subclass %r" % ( fieldname, base, self)) + def hook_access_field(self, vinst, cname, llops, flags): + pass # for virtualizables; see rvirtualizable2.py + + def hook_setfield(self, vinst, fieldname, llops): + if self.is_quasi_immutable(fieldname): + c_fieldname = inputconst(Void, 'mutate_' + fieldname) + llops.genop('jit_force_quasi_immutable', [vinst, c_fieldname]) + + def is_quasi_immutable(self, fieldname): + search1 = fieldname + '?' + search2 = fieldname + '?[*]' + rbase = self + while rbase.classdef is not None: + if (search1 in rbase.immutable_field_set or + search2 in rbase.immutable_field_set): + return True + rbase = rbase.rbase + return False + def new_instance(self, llops, classcallhop=None): raise NotImplementedError diff --git a/pypy/rpython/rvirtualizable2.py b/pypy/rpython/rvirtualizable2.py --- a/pypy/rpython/rvirtualizable2.py +++ b/pypy/rpython/rvirtualizable2.py @@ -50,7 +50,7 @@ def hook_access_field(self, vinst, cname, llops, flags): #if not flags.get('access_directly'): - if cname.value in self.my_redirected_fields: + if self.my_redirected_fields.get(cname.value): cflags = inputconst(lltype.Void, flags) llops.genop('jit_force_virtualizable', [vinst, cname, cflags]) diff --git a/pypy/rpython/test/test_annlowlevel.py b/pypy/rpython/test/test_annlowlevel.py --- a/pypy/rpython/test/test_annlowlevel.py +++ b/pypy/rpython/test/test_annlowlevel.py @@ -4,9 +4,12 @@ from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from pypy.rpython.lltypesystem.rstr import mallocstr, mallocunicode +from pypy.rpython.lltypesystem import lltype from pypy.rpython.ootypesystem import ootype from pypy.rpython.annlowlevel import hlstr, llstr, oostr from pypy.rpython.annlowlevel import hlunicode, llunicode +from pypy.rpython import annlowlevel + class TestLLType(BaseRtypingTest, LLRtypeMixin): def test_hlstr(self): @@ -53,6 +56,15 @@ res = self.interpret(f, [self.unicode_to_ll(u"abc")]) assert res == 3 + def test_cast_instance_to_base_ptr(self): + class X(object): + pass + x = X() + ptr = annlowlevel.cast_instance_to_base_ptr(x) + assert lltype.typeOf(ptr) == annlowlevel.base_ptr_lltype() + y = annlowlevel.cast_base_ptr_to_instance(X, ptr) + assert y is x + class TestOOType(BaseRtypingTest, OORtypeMixin): def test_hlstr(self): @@ -71,3 +83,12 @@ res = self.interpret(f, [self.string_to_ll("abc")]) assert res == 3 + + def test_cast_instance_to_base_obj(self): + class X(object): + pass + x = X() + obj = annlowlevel.cast_instance_to_base_obj(x) + assert lltype.typeOf(obj) == annlowlevel.base_obj_ootype() + y = annlowlevel.cast_base_ptr_to_instance(X, obj) + assert y is x diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -5,6 +5,8 @@ from pypy.rpython.ootypesystem import ootype from pypy.rlib.rarithmetic import intmask, r_longlong from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin +from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY +from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY from pypy.objspace.flow.model import summary class EmptyBase(object): @@ -746,8 +748,10 @@ t, typer, graph = self.gengraph(f, []) A_TYPE = deref(graph.getreturnvar().concretetype) accessor = A_TYPE._hints["immutable_fields"] - assert accessor.fields == {"inst_x" : "", "inst_y" : "[*]"} or \ - accessor.fields == {"ox" : "", "oy" : "[*]"} # for ootype + assert accessor.fields == {"inst_x": IR_IMMUTABLE, + "inst_y": IR_IMMUTABLE_ARRAY} or \ + accessor.fields == {"ox": IR_IMMUTABLE, + "oy": IR_IMMUTABLE_ARRAY} # for ootype def test_immutable_fields_subclass_1(self): from pypy.jit.metainterp.typesystem import deref @@ -765,8 +769,8 @@ t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) accessor = B_TYPE._hints["immutable_fields"] - assert accessor.fields == {"inst_x" : ""} or \ - accessor.fields == {"ox" : ""} # for ootype + assert accessor.fields == {"inst_x": IR_IMMUTABLE} or \ + accessor.fields == {"ox": IR_IMMUTABLE} # for ootype def test_immutable_fields_subclass_2(self): from pypy.jit.metainterp.typesystem import deref @@ -785,8 +789,10 @@ t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) accessor = B_TYPE._hints["immutable_fields"] - assert accessor.fields == {"inst_x" : "", "inst_y" : ""} or \ - accessor.fields == {"ox" : "", "oy" : ""} # for ootype + assert accessor.fields == {"inst_x": IR_IMMUTABLE, + "inst_y": IR_IMMUTABLE} or \ + accessor.fields == {"ox": IR_IMMUTABLE, + "oy": IR_IMMUTABLE} # for ootype def test_immutable_fields_only_in_subclass(self): from pypy.jit.metainterp.typesystem import deref @@ -804,8 +810,8 @@ t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) accessor = B_TYPE._hints["immutable_fields"] - assert accessor.fields == {"inst_y" : ""} or \ - accessor.fields == {"oy" : ""} # for ootype + assert accessor.fields == {"inst_y": IR_IMMUTABLE} or \ + accessor.fields == {"oy": IR_IMMUTABLE} # for ootype def test_immutable_forbidden_inheritance_1(self): from pypy.rpython.rclass import ImmutableConflictError @@ -849,8 +855,8 @@ except AttributeError: A_TYPE = B_TYPE._superclass # for ootype accessor = A_TYPE._hints["immutable_fields"] - assert accessor.fields == {"inst_v" : ""} or \ - accessor.fields == {"ov" : ""} # for ootype + assert accessor.fields == {"inst_v": IR_IMMUTABLE} or \ + accessor.fields == {"ov": IR_IMMUTABLE} # for ootype def test_immutable_subclass_1(self): from pypy.rpython.rclass import ImmutableConflictError @@ -895,6 +901,58 @@ B_TYPE = deref(graph.getreturnvar().concretetype) assert B_TYPE._hints["immutable"] + def test_quasi_immutable(self): + from pypy.jit.metainterp.typesystem import deref + class A(object): + _immutable_fields_ = ['x', 'y', 'a?', 'b?'] + class B(A): + pass + def f(): + a = A() + a.x = 42 + a.a = 142 + b = B() + b.x = 43 + b.y = 41 + b.a = 44 + b.b = 45 + return B() + t, typer, graph = self.gengraph(f, []) + B_TYPE = deref(graph.getreturnvar().concretetype) + accessor = B_TYPE._hints["immutable_fields"] + assert accessor.fields == {"inst_y": IR_IMMUTABLE, + "inst_b": IR_QUASIIMMUTABLE} or \ + accessor.fields == {"ox": IR_IMMUTABLE, + "oy": IR_IMMUTABLE, + "oa": IR_QUASIIMMUTABLE, + "ob": IR_QUASIIMMUTABLE} # for ootype + found = [] + for op in graph.startblock.operations: + if op.opname == 'jit_force_quasi_immutable': + found.append(op.args[1].value) + assert found == ['mutate_a', 'mutate_a', 'mutate_b'] + + def test_quasi_immutable_array(self): + from pypy.jit.metainterp.typesystem import deref + class A(object): + _immutable_fields_ = ['c?[*]'] + class B(A): + pass + def f(): + a = A() + a.c = [3, 4, 5] + return A() + t, typer, graph = self.gengraph(f, []) + A_TYPE = deref(graph.getreturnvar().concretetype) + accessor = A_TYPE._hints["immutable_fields"] + assert accessor.fields == {"inst_c": IR_QUASIIMMUTABLE_ARRAY} or \ + accessor.fields == {"oc": IR_QUASIIMMUTABLE_ARRAY} # for ootype + found = [] + for op in graph.startblock.operations: + if op.opname == 'jit_force_quasi_immutable': + found.append(op.args[1].value) + assert found == ['mutate_c'] + class TestLLtype(BaseTestRclass, LLRtypeMixin): diff --git a/pypy/rpython/test/test_rvirtualizable2.py b/pypy/rpython/test/test_rvirtualizable2.py --- a/pypy/rpython/test/test_rvirtualizable2.py +++ b/pypy/rpython/test/test_rvirtualizable2.py @@ -5,6 +5,7 @@ from pypy.rlib.jit import hint from pypy.objspace.flow.model import summary from pypy.rpython.llinterp import LLInterpreter +from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy import conftest @@ -116,8 +117,8 @@ TYPE = self.gettype(v_inst) accessor = TYPE._hints['virtualizable2_accessor'] assert accessor.TYPE == TYPE - assert accessor.fields == {self.prefix + 'v1' : "", - self.prefix + 'v2': "[*]"} + assert accessor.fields == {self.prefix + 'v1': IR_IMMUTABLE, + self.prefix + 'v2': IR_IMMUTABLE_ARRAY} # def fn2(n): Base().base1 = 42 diff --git a/pypy/translator/geninterplevel.py b/pypy/translator/geninterplevel.py --- a/pypy/translator/geninterplevel.py +++ b/pypy/translator/geninterplevel.py @@ -71,7 +71,7 @@ log = py.log.Producer("geninterp") py.log.setconsumer("geninterp", ansi_log) -GI_VERSION = '1.2.8' # bump this for substantial changes +GI_VERSION = '1.2.9' # bump this for substantial changes # ____________________________________________________________ try: @@ -1175,8 +1175,7 @@ pass defaultsname = self.uniquename('default') self._defaults_cache[key] = defaultsname - self.initcode.append("from pypy.interpreter.function import Defaults") - self.initcode.append("%s = Defaults([%s])" % (defaultsname, ', '.join(names))) + self.initcode.append("%s = [%s]" % (defaultsname, ', '.join(names))) return defaultsname def gen_rpyfunction(self, func): From noreply at buildbot.pypy.org Fri Jul 1 14:18:33 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 1 Jul 2011 14:18:33 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: start implementing support for out of line guards Message-ID: <20110701121833.A3EB782936@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45216:fbc58902cd0d Date: 2011-06-30 18:24 +0200 http://bitbucket.org/pypy/pypy/changeset/fbc58902cd0d/ Log: start implementing support for out of line guards diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -25,7 +25,7 @@ from pypy.rpython.annlowlevel import llhelper from pypy.rpython.lltypesystem import lltype, rffi, llmemory from pypy.rpython.lltypesystem.lloperation import llop -from pypy.jit.backend.arm.opassembler import ResOpAssembler +from pypy.jit.backend.arm.opassembler import ResOpAssembler, GuardToken from pypy.rlib.debug import (debug_print, debug_start, debug_stop, have_debug_prints) @@ -76,7 +76,7 @@ self.malloc_str_func_addr = 0 self.malloc_unicode_func_addr = 0 self.memcpy_addr = 0 - self.guard_descrs = None + self.pending_guards = None self._exit_code_addr = 0 self.current_clt = None self.malloc_slowpath = 0 @@ -88,7 +88,7 @@ assert self.memcpy_addr != 0, 'setup_once() not called?' self.current_clt = looptoken.compiled_loop_token self.mc = ARMv7Builder() - self.guard_descrs = [] + self.pending_guards = [] assert self.datablockwrapper is None allblocks = self.get_asmmemmgr_blocks(looptoken) self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr, @@ -98,7 +98,7 @@ self.current_clt = None self._regalloc = None self.mc = None - self.guard_descrs = None + self.pending_guards = None def setup_once(self): # Addresses of functions called by new_xxx operations @@ -300,7 +300,7 @@ return mc.materialize(self.cpu.asmmemmgr, [], self.cpu.gc_ll_descr.gcrootmap) - def _gen_path_to_exit_path(self, op, args, arglocs, fcond=c.AL, save_exc=False): + def gen_descr_encoding(self, op, args, arglocs): descr = op.getdescr() if op.getopnum() != rop.FINISH: assert isinstance(descr, AbstractFailDescr) @@ -357,15 +357,21 @@ n = self.cpu.get_fail_descr_number(descr) encode32(mem, j+1, n) - self.mc.LDR_ri(r.ip.value, r.pc.value, imm=WORD) + return memaddr + + def _gen_path_to_exit_path(self, op, args, arglocs, fcond=c.AL, save_exc=False): + memaddr = self.gen_descr_encoding(op, args, arglocs) + self.gen_exit_code(self.mc, memaddr, fcond, save_exc) + return memaddr + + def gen_exit_code(self, mc, memaddr, fcond=c.AL, save_exc=False): + mc.LDR_ri(r.ip.value, r.pc.value, imm=WORD) if save_exc: path = self._leave_jitted_hook_save_exc else: path = self._leave_jitted_hook - self.mc.B(path) - self.mc.write32(memaddr) - - return memaddr + mc.B(path) + mc.write32(memaddr) def align(self): while(self.mc.currpos() % FUNC_ALIGN != 0): @@ -583,7 +589,7 @@ loop_start = self.materialize_loop(looptoken) looptoken._arm_bootstrap_code = loop_start looptoken._arm_direct_bootstrap_code = loop_start + direct_bootstrap_code - self.update_descrs_for_bridges(loop_start) + self.process_pending_guards(loop_start) if log and not we_are_translated(): print 'Loop', inputargs, operations self.mc._dump_trace(loop_start, 'loop_%s.asm' % self.cpu.total_compiled_loops) @@ -612,7 +618,7 @@ self._patch_sp_offset(sp_patch_location, regalloc.frame_manager.frame_depth) bridge_start = self.materialize_loop(original_loop_token) - self.update_descrs_for_bridges(bridge_start) + self.process_pending_guards(bridge_start) self.patch_trace(faildescr, original_loop_token, bridge_start, regalloc) if log and not we_are_translated(): @@ -628,10 +634,17 @@ return self.mc.materialize(self.cpu.asmmemmgr, allblocks, self.cpu.gc_ll_descr.gcrootmap) - def update_descrs_for_bridges(self, block_start): - for descr in self.guard_descrs: + def process_pending_guards(self, block_start): + clt = self.current_clt + for tok in self.pending_guards: + descr = tok.descr + #XXX _arm_block_start should go in the looptoken descr._arm_block_start = block_start - + descr._failure_recovery_code = tok.encoded_args + descr._arm_guard_pos = tok.offset + if tok.is_invalidate: + clt.invalidate_positions.append( + (block_start + tok.offset, tok.encoded_args)) def get_asmmemmgr_blocks(self, looptoken): clt = looptoken.compiled_loop_token diff --git a/pypy/jit/backend/arm/opassembler.py b/pypy/jit/backend/arm/opassembler.py --- a/pypy/jit/backend/arm/opassembler.py +++ b/pypy/jit/backend/arm/opassembler.py @@ -33,6 +33,13 @@ NO_FORCE_INDEX = -1 +class GuardToken(object): + def __init__(self, descr, offset=0, encoded_args=0, is_invalidate=False): + self.descr = descr + self.offset = offset + self.encoded_args = encoded_args + self.is_invalidate = is_invalidate + class IntOpAsslember(object): _mixin_ = True @@ -161,16 +168,17 @@ def _emit_guard(self, op, arglocs, fcond, save_exc=False): descr = op.getdescr() assert isinstance(descr, AbstractFailDescr) - self.guard_descrs.append(descr) + + if not we_are_translated() and hasattr(op, 'getfailargs'): print 'Failargs: ', op.getfailargs() self.mc.ADD_ri(r.pc.value, r.pc.value, self.guard_size-PC_OFFSET, cond=fcond) - descr._arm_guard_pos = self.mc.currpos() + pos = self.mc.currpos() memaddr = self._gen_path_to_exit_path(op, op.getfailargs(), arglocs, save_exc=save_exc) - descr._failure_recovery_code = memaddr + self.pending_guards.append(GuardToken(op.getdescr(), pos=pos, memaddr=memaddr)) return c.AL def _emit_guard_overflow(self, guard, failargs, fcond): @@ -238,6 +246,11 @@ self._cmp_guard_class(op, arglocs, regalloc, fcond) return fcond + def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): + pos = self.mc.currpos() # after potential jmp + memaddr = self.gen_descr_encoding(op, op.getfailargs(), locs) + self.pending_guards.append(GuardToken(op.getdescr(), pos, memaddr, True)) + def _cmp_guard_class(self, op, locs, regalloc, fcond): offset = locs[2] if offset is not None: diff --git a/pypy/jit/backend/arm/regalloc.py b/pypy/jit/backend/arm/regalloc.py --- a/pypy/jit/backend/arm/regalloc.py +++ b/pypy/jit/backend/arm/regalloc.py @@ -509,6 +509,8 @@ return locs prepare_op_guard_overflow = prepare_op_guard_no_overflow + prepare_op_guard_not_invalidated = prepare_op_guard_no_overflow + def prepare_op_guard_exception(self, op, fcond): boxes = list(op.getarglist()) diff --git a/pypy/jit/backend/arm/runner.py b/pypy/jit/backend/arm/runner.py --- a/pypy/jit/backend/arm/runner.py +++ b/pypy/jit/backend/arm/runner.py @@ -128,3 +128,20 @@ def redirect_call_assembler(self, oldlooptoken, newlooptoken): self.assembler.redirect_call_assembler(oldlooptoken, newlooptoken) + + def invalidate_loop(self, looptoken): + """Activate all GUARD_NOT_INVALIDATED in the loop and its attached + bridges. Before this call, all GUARD_NOT_INVALIDATED do nothing; + after this call, they all fail. Note that afterwards, if one such + guard fails often enough, it has a bridge attached to it; it is + possible then to re-call invalidate_loop() on the same looptoken, + which must invalidate all newer GUARD_NOT_INVALIDATED, but not the + old one that already has a bridge attached to it.""" + from pypy.jit.backend.arm.codebuilder import ARMv7Builder + + for tgt, memaddr in looptoken.compiled_loop_token.invalidate_positions: + mc = ARMv7Builder() + self.assembler.gen_exit_code(mc, memaddr) + mc.copy_to_raw_memory(tgt) + # positions invalidated + looptoken.compiled_loop_token.invalidate_positions = [] From noreply at buildbot.pypy.org Fri Jul 1 14:18:34 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 1 Jul 2011 14:18:34 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: small fixes Message-ID: <20110701121834.DF05082936@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45217:f5732081f673 Date: 2011-07-01 10:05 +0200 http://bitbucket.org/pypy/pypy/changeset/f5732081f673/ Log: small fixes diff --git a/pypy/jit/backend/arm/opassembler.py b/pypy/jit/backend/arm/opassembler.py --- a/pypy/jit/backend/arm/opassembler.py +++ b/pypy/jit/backend/arm/opassembler.py @@ -178,7 +178,8 @@ memaddr = self._gen_path_to_exit_path(op, op.getfailargs(), arglocs, save_exc=save_exc) - self.pending_guards.append(GuardToken(op.getdescr(), pos=pos, memaddr=memaddr)) + self.pending_guards.append(GuardToken(op.getdescr(), + offset=pos, encoded_args=memaddr)) return c.AL def _emit_guard_overflow(self, guard, failargs, fcond): @@ -250,6 +251,7 @@ pos = self.mc.currpos() # after potential jmp memaddr = self.gen_descr_encoding(op, op.getfailargs(), locs) self.pending_guards.append(GuardToken(op.getdescr(), pos, memaddr, True)) + return fcond def _cmp_guard_class(self, op, locs, regalloc, fcond): offset = locs[2] From noreply at buildbot.pypy.org Fri Jul 1 14:18:36 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 1 Jul 2011 14:18:36 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: generate a B(ranch) instruction for jumps with a known offset Message-ID: <20110701121836.23D2182936@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45218:300083553621 Date: 2011-07-01 11:01 +0200 http://bitbucket.org/pypy/pypy/changeset/300083553621/ Log: generate a B(ranch) instruction for jumps with a known offset diff --git a/pypy/jit/backend/arm/codebuilder.py b/pypy/jit/backend/arm/codebuilder.py --- a/pypy/jit/backend/arm/codebuilder.py +++ b/pypy/jit/backend/arm/codebuilder.py @@ -168,16 +168,9 @@ if target_ofs > pos: raise NotImplementedError else: - target_ofs = pos - target_ofs - target = WORD + target_ofs + arch.PC_OFFSET/2 - if target >= 0 and target <= 0xFF: - self.SUB_ri(reg.pc.value, reg.pc.value, target, cond=c) - else: - assert c == cond.AL - self.LDR_ri(reg.ip.value, reg.pc.value, cond=c) - self.SUB_rr(reg.pc.value, reg.pc.value, reg.ip.value, cond=c) - target += WORD - self.write32(target) + target_ofs = target_ofs - (pos + arch.PC_OFFSET) + assert target_ofs & 0x3 == 0 + self.write32(c << 28 | 0xA << 24 | (target_ofs >> 2) & 0xFFFFFF) def BL(self, target, c=cond.AL): if c == cond.AL: From noreply at buildbot.pypy.org Fri Jul 1 14:18:37 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 1 Jul 2011 14:18:37 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: refactor guards make the handling more similar to how it is done in the x86 Message-ID: <20110701121837.6281282936@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45219:0268a6ca49d1 Date: 2011-07-01 14:25 +0200 http://bitbucket.org/pypy/pypy/changeset/0268a6ca49d1/ Log: refactor guards make the handling more similar to how it is done in the x86 backend generating a check and a conditional jump to an exit stub that is later generated at the end of the compiled loop. diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -300,11 +300,7 @@ return mc.materialize(self.cpu.asmmemmgr, [], self.cpu.gc_ll_descr.gcrootmap) - def gen_descr_encoding(self, op, args, arglocs): - descr = op.getdescr() - if op.getopnum() != rop.FINISH: - assert isinstance(descr, AbstractFailDescr) - descr._arm_frame_depth = arglocs[0].getint() + def gen_descr_encoding(self, descr, args, arglocs): # The size of the allocated memory is based on the following sizes # first argloc is the frame depth and not considered for the memory # allocation @@ -359,8 +355,8 @@ encode32(mem, j+1, n) return memaddr - def _gen_path_to_exit_path(self, op, args, arglocs, fcond=c.AL, save_exc=False): - memaddr = self.gen_descr_encoding(op, args, arglocs) + def _gen_path_to_exit_path(self, descr, args, arglocs, fcond=c.AL, save_exc=False): + memaddr = self.gen_descr_encoding(descr, args, arglocs) self.gen_exit_code(self.mc, memaddr, fcond, save_exc) return memaddr @@ -586,6 +582,7 @@ direct_bootstrap_code = self.mc.currpos() self.gen_direct_bootstrap_code(loop_head, looptoken, inputargs) + self.write_pending_failure_recoveries() loop_start = self.materialize_loop(looptoken) looptoken._arm_bootstrap_code = loop_start looptoken._arm_direct_bootstrap_code = loop_start + direct_bootstrap_code @@ -617,6 +614,7 @@ #original_loop_token._arm_frame_depth = regalloc.frame_manager.frame_depth self._patch_sp_offset(sp_patch_location, regalloc.frame_manager.frame_depth) + self.write_pending_failure_recoveries() bridge_start = self.materialize_loop(original_loop_token) self.process_pending_guards(bridge_start) @@ -634,17 +632,38 @@ return self.mc.materialize(self.cpu.asmmemmgr, allblocks, self.cpu.gc_ll_descr.gcrootmap) + def write_pending_failure_recoveries(self): + for tok in self.pending_guards: + descr = tok.descr + #generate the exit stub and the encoded representation + pos = self.mc.currpos() + tok.pos_recovery_stub = pos + + memaddr = self._gen_path_to_exit_path(descr, tok.failargs, + tok.faillocs, save_exc=tok.save_exc) + # store info on the descr + descr._arm_frame_depth = tok.faillocs[0].getint() + descr._failure_recovery_code = memaddr + descr._arm_guard_pos = pos + def process_pending_guards(self, block_start): clt = self.current_clt for tok in self.pending_guards: descr = tok.descr + assert isinstance(descr, AbstractFailDescr) + #XXX _arm_block_start should go in the looptoken descr._arm_block_start = block_start - descr._failure_recovery_code = tok.encoded_args - descr._arm_guard_pos = tok.offset - if tok.is_invalidate: + + if not tok.is_invalidate: + #patch the guard jumpt to the stub + # overwrite the generate NOP with a B_offs to the pos of the stub + mc = ARMv7Builder() + mc.B_offs(descr._arm_guard_pos - tok.offset, c.get_opposite_of(tok.fcond)) + mc.copy_to_raw_memory(block_start + tok.offset) + else: clt.invalidate_positions.append( - (block_start + tok.offset, tok.encoded_args)) + (block_start + tok.offset, descr._arm_guard_pos - tok.offset)) def get_asmmemmgr_blocks(self, looptoken): clt = looptoken.compiled_loop_token diff --git a/pypy/jit/backend/arm/codebuilder.py b/pypy/jit/backend/arm/codebuilder.py --- a/pypy/jit/backend/arm/codebuilder.py +++ b/pypy/jit/backend/arm/codebuilder.py @@ -156,6 +156,8 @@ self.write32(cond << 28 | 0xEF1FA10) def B(self, target, c=cond.AL): + #assert self._fits_in_24bits(target) + #return (c << 20 | 0xA << 24 | target & 0xFFFFFF) if c == cond.AL: self.LDR_ri(reg.pc.value, reg.pc.value, -arch.PC_OFFSET/2) self.write32(target) @@ -165,12 +167,9 @@ def B_offs(self, target_ofs, c=cond.AL): pos = self.currpos() - if target_ofs > pos: - raise NotImplementedError - else: - target_ofs = target_ofs - (pos + arch.PC_OFFSET) - assert target_ofs & 0x3 == 0 - self.write32(c << 28 | 0xA << 24 | (target_ofs >> 2) & 0xFFFFFF) + target_ofs = target_ofs - (pos + arch.PC_OFFSET) + assert target_ofs & 0x3 == 0 + self.write32(c << 28 | 0xA << 24 | (target_ofs >> 2) & 0xFFFFFF) def BL(self, target, c=cond.AL): if c == cond.AL: @@ -242,6 +241,9 @@ self.index = start self.end = start + size + def currpos(self): + return self.index + def writechar(self, char): assert self.index <= self.end self.cb.overwrite(self.index, char) diff --git a/pypy/jit/backend/arm/opassembler.py b/pypy/jit/backend/arm/opassembler.py --- a/pypy/jit/backend/arm/opassembler.py +++ b/pypy/jit/backend/arm/opassembler.py @@ -34,11 +34,15 @@ NO_FORCE_INDEX = -1 class GuardToken(object): - def __init__(self, descr, offset=0, encoded_args=0, is_invalidate=False): + def __init__(self, descr, failargs, faillocs, offset, fcond=c.AL, + save_exc=False, is_invalidate=False): self.descr = descr self.offset = offset - self.encoded_args = encoded_args self.is_invalidate = is_invalidate + self.failargs = failargs + self.faillocs = faillocs + self.save_exc = save_exc + self.fcond=fcond class IntOpAsslember(object): @@ -165,7 +169,7 @@ _mixin_ = True guard_size = 5*WORD - def _emit_guard(self, op, arglocs, fcond, save_exc=False): + def _emit_guard(self, op, arglocs, fcond, save_exc=False, is_guard_not_ivalidated=False): descr = op.getdescr() assert isinstance(descr, AbstractFailDescr) @@ -173,13 +177,15 @@ if not we_are_translated() and hasattr(op, 'getfailargs'): print 'Failargs: ', op.getfailargs() - self.mc.ADD_ri(r.pc.value, r.pc.value, self.guard_size-PC_OFFSET, cond=fcond) pos = self.mc.currpos() - - memaddr = self._gen_path_to_exit_path(op, op.getfailargs(), - arglocs, save_exc=save_exc) - self.pending_guards.append(GuardToken(op.getdescr(), - offset=pos, encoded_args=memaddr)) + self.mc.NOP() + self.pending_guards.append(GuardToken(descr, + failargs=op.getfailargs(), + faillocs=arglocs, + offset=pos, + fcond=fcond, + is_invalidate=is_guard_not_ivalidated, + save_exc=save_exc)) return c.AL def _emit_guard_overflow(self, guard, failargs, fcond): @@ -241,17 +247,14 @@ self.mc.CMP_ri(arglocs[0].value, 0) if offset is not None: - self.mc.ADD_ri(r.pc.value, r.pc.value, 2*WORD, cond=c.EQ) + self._emit_guard(op, arglocs[3:], c.NE) else: raise NotImplementedError self._cmp_guard_class(op, arglocs, regalloc, fcond) return fcond def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): - pos = self.mc.currpos() # after potential jmp - memaddr = self.gen_descr_encoding(op, op.getfailargs(), locs) - self.pending_guards.append(GuardToken(op.getdescr(), pos, memaddr, True)) - return fcond + return self._emit_guard(op, locs, fcond, is_guard_not_ivalidated=True) def _cmp_guard_class(self, op, locs, regalloc, fcond): offset = locs[2] @@ -289,7 +292,7 @@ return fcond def emit_op_finish(self, op, arglocs, regalloc, fcond): - self._gen_path_to_exit_path(op, op.getarglist(), arglocs, c.AL) + self._gen_path_to_exit_path(op.getdescr(), op.getarglist(), arglocs, c.AL) return fcond def emit_op_call(self, op, args, regalloc, fcond, force_index=-1): diff --git a/pypy/jit/backend/arm/runner.py b/pypy/jit/backend/arm/runner.py --- a/pypy/jit/backend/arm/runner.py +++ b/pypy/jit/backend/arm/runner.py @@ -139,9 +139,9 @@ old one that already has a bridge attached to it.""" from pypy.jit.backend.arm.codebuilder import ARMv7Builder - for tgt, memaddr in looptoken.compiled_loop_token.invalidate_positions: + for jmp, tgt in looptoken.compiled_loop_token.invalidate_positions: mc = ARMv7Builder() - self.assembler.gen_exit_code(mc, memaddr) - mc.copy_to_raw_memory(tgt) + mc.B_offs(tgt) + mc.copy_to_raw_memory(jmp) # positions invalidated looptoken.compiled_loop_token.invalidate_positions = [] From noreply at buildbot.pypy.org Fri Jul 1 14:51:28 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 1 Jul 2011 14:51:28 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: exit more nicely than with an IOError/broken pipe Message-ID: <20110701125128.DD0E882936@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: extradoc Changeset: r3817:9541fc4c39ea Date: 2011-07-01 14:58 +0200 http://bitbucket.org/pypy/extradoc/changeset/9541fc4c39ea/ Log: exit more nicely than with an IOError/broken pipe diff --git a/talk/iwtc11/benchmarks/image/magnify.py b/talk/iwtc11/benchmarks/image/magnify.py --- a/talk/iwtc11/benchmarks/image/magnify.py +++ b/talk/iwtc11/benchmarks/image/magnify.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python + +import errno from plain import Image from math import atan2, sqrt, sin, cos, ceil, floor @@ -65,7 +68,13 @@ start = start0 = time() for fcnt, img in enumerate(mplayer(MyImage, fn)): - view(magnify(img)) + try: + view(magnify(img)) + except IOError, e: + if e.errno != errno.EPIPE: + raise + print 'Exiting' + break print 1.0 / (time() - start), 'fps, ', (fcnt-2) / (time() - start0), 'average fps' start = time() if fcnt==2: diff --git a/talk/iwtc11/benchmarks/image/sobel.py b/talk/iwtc11/benchmarks/image/sobel.py --- a/talk/iwtc11/benchmarks/image/sobel.py +++ b/talk/iwtc11/benchmarks/image/sobel.py @@ -1,3 +1,4 @@ +import errno from noborder import NoBorderImagePadded from math import sqrt @@ -78,8 +79,15 @@ #view(img) #sobeldx(img) #view(uint8(sobel_magnitude(img))) - view(sobel_magnitude_uint8(img)) #sobel_magnitude_uint8(img) + try: + view(sobel_magnitude_uint8(img)) + except IOError, e: + if e.errno != errno.EPIPE: + raise + print 'Exiting' + break + print 1.0 / (time() - start), 'fps, ', (fcnt-2) / (time() - start0), 'average fps' start = time() if fcnt==2: From noreply at buildbot.pypy.org Fri Jul 1 15:03:42 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 1 Jul 2011 15:03:42 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: fix runner test and llgraph Message-ID: <20110701130342.6770E82936@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45220:5cc2f54862c8 Date: 2011-07-01 15:10 +0200 http://bitbucket.org/pypy/pypy/changeset/5cc2f54862c8/ Log: fix runner test and llgraph diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -808,26 +808,25 @@ else: raise NotImplementedError - def op_getinteriorfield_gc(self, fielddescr, array, index, arraydescr): - if fielddescr.typeinfo == REF: - return do_getinteriorfield_gc_ptr(array, index, fielddescr.ofs) - elif fielddescr.typeinfo == INT: - return do_getinteriorfield_gc_int(array, index, fielddescr.ofs) - elif fielddescr.typeinfo == FLOAT: - return do_getinteriorfield_gc_float(array, index, fielddescr.ofs) + def op_getinteriorfield_gc(self, descr, array, index): + if descr.typeinfo == REF: + return do_getinteriorfield_gc_ptr(array, index, descr.ofs) + elif descr.typeinfo == INT: + return do_getinteriorfield_gc_int(array, index, descr.ofs) + elif descr.typeinfo == FLOAT: + return do_getinteriorfield_gc_float(array, index, descr.ofs) else: raise NotImplementedError - def op_setinteriorfield_gc(self, fielddescr, array, index, newvalue, - arraydescr): - if fielddescr.typeinfo == REF: - return do_setinteriorfield_gc_ptr(array, index, fielddescr.ofs, + def op_setinteriorfield_gc(self, descr, array, index, newvalue): + if descr.typeinfo == REF: + return do_setinteriorfield_gc_ptr(array, index, descr.ofs, newvalue) - elif fielddescr.typeinfo == INT: - return do_setinteriorfield_gc_int(array, index, fielddescr.ofs, + elif descr.typeinfo == INT: + return do_setinteriorfield_gc_int(array, index, descr.ofs, newvalue) - elif fielddescr.typeinfo == FLOAT: - return do_setinteriorfield_gc_float(array, index, fielddescr.ofs, + elif descr.typeinfo == FLOAT: + return do_setinteriorfield_gc_float(array, index, descr.ofs, newvalue) else: raise NotImplementedError diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -314,6 +314,13 @@ token = history.getkind(getattr(S, fieldname)) return self.getdescr(ofs, token[0], name=fieldname) + def interiorfielddescrof(self, A, fieldname): + S = A.OF + ofs2 = symbolic.get_size(A) + ofs, size = symbolic.get_field_token(S, fieldname) + token = history.getkind(getattr(S, fieldname)) + return self.getdescr(ofs, token[0], name=fieldname, extrainfo=ofs2) + def calldescrof(self, FUNC, ARGS, RESULT, extrainfo=None): arg_types = [] for ARG in ARGS: diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py --- a/pypy/jit/backend/model.py +++ b/pypy/jit/backend/model.py @@ -1,5 +1,5 @@ from pypy.rlib.debug import debug_start, debug_print, debug_stop -from pypy.jit.metainterp import history, compile +from pypy.jit.metainterp import history class AbstractCPU(object): @@ -212,6 +212,10 @@ def typedescrof(TYPE): raise NotImplementedError + @staticmethod + def interiorfielddescrof(A, fieldname): + raise NotImplementedError + # ---------- the backend-dependent operations ---------- # lltype specific operations diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -877,30 +877,26 @@ ('p', lltype.Ptr(TP))) a_box, A = self.alloc_array_of(ITEM, 15) s_box, S = self.alloc_instance(TP) - adescr = self.cpu.arraydescrof(A) - kdescr = self.cpu.fielddescrof(ITEM, 'k') - vdescr = self.cpu.fielddescrof(ITEM, 'v') - pdescr = self.cpu.fielddescrof(ITEM, 'p') + kdescr = self.cpu.interiorfielddescrof(A, 'k') + vdescr = self.cpu.interiorfielddescrof(A, 'v') + pdescr = self.cpu.interiorfielddescrof(A, 'p') self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), - BoxFloat(1.5), adescr], + BoxFloat(1.5)], 'void', descr=kdescr) - r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3), - adescr], 'float', - descr=kdescr) + r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)], + 'float', descr=kdescr) assert r.getfloat() == 1.5 self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), - BoxInt(15), adescr], + BoxInt(15)], 'void', descr=vdescr) - r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3), - adescr], 'int', - descr=vdescr) + r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)], + 'int', descr=vdescr) assert r.getint() == 15 self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), - s_box, adescr], + s_box], 'void', descr=pdescr) - r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3), - adescr], 'ref', - descr=pdescr) + r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)], + 'ref', descr=pdescr) assert r.getref_base() == s_box.getref_base() def test_string_basic(self): diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -455,7 +455,7 @@ 'GETARRAYITEM_GC/2d', 'GETARRAYITEM_RAW/2d', - 'GETINTERIORFIELD_GC/3d', + 'GETINTERIORFIELD_GC/2d', 'GETFIELD_GC/1d', 'GETFIELD_RAW/1d', '_MALLOC_FIRST', @@ -472,7 +472,7 @@ 'SETARRAYITEM_GC/3d', 'SETARRAYITEM_RAW/3d', - 'SETINTERIORFIELD_GC/4d', + 'SETINTERIORFIELD_GC/3d', 'SETFIELD_GC/2d', 'SETFIELD_RAW/2d', 'STRSETITEM/3', From noreply at buildbot.pypy.org Fri Jul 1 15:08:02 2011 From: noreply at buildbot.pypy.org (berdario) Date: Fri, 1 Jul 2011 15:08:02 +0200 (CEST) Subject: [pypy-commit] pypy default: Deleted old stale code that was commented-out in r 4973 and branch hl-backend Message-ID: <20110701130802.8D5B482936@wyvern.cs.uni-duesseldorf.de> Author: Dario Bertini Branch: Changeset: r45221:63cc9b6cfcb7 Date: 2011-06-29 22:44 +0200 http://bitbucket.org/pypy/pypy/changeset/63cc9b6cfcb7/ Log: Deleted old stale code that was commented-out in r 4973 and branch hl-backend diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -351,17 +351,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -379,8 +368,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( From noreply at buildbot.pypy.org Fri Jul 1 15:08:03 2011 From: noreply at buildbot.pypy.org (berdario) Date: Fri, 1 Jul 2011 15:08:03 +0200 (CEST) Subject: [pypy-commit] pypy default: Deleted old stale code that apparently was commented-out in r 9092 and branch ast-experiments Message-ID: <20110701130803.CA37782936@wyvern.cs.uni-duesseldorf.de> Author: Dario Bertini Branch: Changeset: r45222:c65284866830 Date: 2011-06-30 06:38 +0200 http://bitbucket.org/pypy/pypy/changeset/c65284866830/ Log: Deleted old stale code that apparently was commented-out in r 9092 and branch ast-experiments diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) From noreply at buildbot.pypy.org Fri Jul 1 15:08:06 2011 From: noreply at buildbot.pypy.org (berdario) Date: Fri, 1 Jul 2011 15:08:06 +0200 (CEST) Subject: [pypy-commit] pypy int32on64-experiment: Bunch of misc. changes Message-ID: <20110701130806.619DF8293A@wyvern.cs.uni-duesseldorf.de> Author: Dario Bertini Branch: int32on64-experiment Changeset: r45224:2e960c5fb5c2 Date: 2011-07-01 12:14 +0200 http://bitbucket.org/pypy/pypy/changeset/2e960c5fb5c2/ Log: Bunch of misc. changes diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -332,9 +332,7 @@ return result if tp is bool: result = SomeBool() - elif tp is int: - result = SomeInteger(nonneg = x>=0) - elif tp is long: + elif tp is int or tp is long: if -sys.maxint-1 <= x <= sys.maxint: x = int(x) result = SomeInteger(nonneg = x>=0) diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py --- a/pypy/annotation/test/test_annrpython.py +++ b/pypy/annotation/test/test_annrpython.py @@ -849,7 +849,7 @@ assert s == annmodel.SomeInteger(nonneg = True, unsigned = True) def test_large_unsigned(self): - large_constant = sys.maxint * 2 + 1 # 0xFFFFFFFF on 32-bit platforms + large_constant = 2**64-1 # 0xFFFFFFFF on 32-bit platforms def f(): return large_constant a = self.RPythonAnnotator() diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -41,7 +41,7 @@ _bits = 0 _itest = 1 _Ltest = 1L -while _itest == _Ltest and type(_itest) is int: +while _itest == _Ltest and _itest <= sys.maxint: _itest *= 2 _Ltest *= 2 _bits += 1 @@ -59,11 +59,11 @@ assert LONG_BIT_SHIFT < 99, "LONG_BIT_SHIFT value not found?" def intmask(n): - if isinstance(n, int): - return int(n) # possibly bool->int if isinstance(n, objectmodel.Symbolic): return n # assume Symbolics don't overflow assert not isinstance(n, float) + if -sys.maxint -1 < n < sys.maxint: + return int(n) n = long(n) n &= LONG_MASK if n >= LONG_TEST: @@ -107,8 +107,8 @@ # raise OverflowError if the operation did overflow assert not isinstance(r, r_uint), "unexpected ovf check on unsigned" assert not isinstance(r, r_longlong), "ovfcheck not supported on r_longlong" - assert not isinstance(r,r_ulonglong),"ovfcheck not supported on r_ulonglong" - if type(r) is long: + assert not isinstance(r, r_ulonglong), "ovfcheck not supported on r_ulonglong" + if r > sys.maxint or r < -sys.maxint - 1: raise OverflowError, "signed integer expression did overflow" return r @@ -116,7 +116,7 @@ # a copy of the above, because we cannot call ovfcheck # in a context where no primitiveoperator is involved. assert not isinstance(r, r_uint), "unexpected ovf check on unsigned" - if isinstance(r, long): + if r > sys.maxint or r < -sys.maxint - 1: raise OverflowError, "signed integer expression did overflow" return r diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -904,11 +904,11 @@ offsetof._annspecialcase_ = 'specialize:memo' # check that we have a sane configuration -assert sys.maxint == (1 << (8 * sizeof(lltype.Signed) - 1)) - 1, ( - "Mixed configuration of the word size of the machine:\n\t" - "the underlying Python was compiled with maxint=%d,\n\t" - "but the C compiler says that 'long' is %d bytes" % ( - sys.maxint, sizeof(lltype.Signed))) +#assert sys.maxint == (1 << (8 * sizeof(lltype.Signed) - 1)) - 1, ( + #"Mixed configuration of the word size of the machine:\n\t" + #"the underlying Python was compiled with maxint=%d,\n\t" + #"but the C compiler says that 'long' is %d bytes" % ( + #sys.maxint, sizeof(lltype.Signed))) # ********************** some helpers ******************* diff --git a/pypy/rpython/test/test_rint.py b/pypy/rpython/test/test_rint.py --- a/pypy/rpython/test/test_rint.py +++ b/pypy/rpython/test/test_rint.py @@ -389,12 +389,32 @@ return objectmodel.compute_hash(x) res = self.interpret(f, [123456789]) assert res == 123456789 - res = self.interpret(f, [r_int64(123456789012345678)]) - if sys.maxint == 2147483647: + num = r_int64(123456789012345678) + res = self.interpret(f, [num]) + if isinstance(num, r_longlong): # check the way we compute such a hash so far assert res == -1506741426 + 9 * 28744523 else: assert res == 123456789012345678 + + def test_strange_behaviour(self): + def f(x): + return objectmodel.compute_hash(x) + + #happened on 64bit when changing sys.maxint + old_maxint = sys.maxint + sys.maxint = 2**31-1 + num1 = r_int64(2**32 - 1) + num2 = r_int64(2**32) + + interpreted_res = self.interpret(f, [num1]) + res = f(num1) + sys.maxint = old_maxint + assert res == interpreted_res + + interpreted_res = self.interpret(f, [num2]) + res = f(num2) + assert res == interpreted_res def test_int_between(self): def fn(a, b, c): diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -11,6 +11,8 @@ """ import sys, os +sys.maxint = (2**31)-1 + if len(sys.argv) == 1 and os.path.dirname(sys.argv[0]) in '.': print >> sys.stderr, __doc__ sys.exit(2) From noreply at buildbot.pypy.org Fri Jul 1 15:08:07 2011 From: noreply at buildbot.pypy.org (berdario) Date: Fri, 1 Jul 2011 15:08:07 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: Small cleanup (eg test_all.py) Message-ID: <20110701130807.9F85E8293A@wyvern.cs.uni-duesseldorf.de> Author: Dario Bertini Branch: win64 test Changeset: r45225:313a60758e6a Date: 2011-07-01 15:09 +0200 http://bitbucket.org/pypy/pypy/changeset/313a60758e6a/ Log: Small cleanup (eg test_all.py) Changed the int argtype in opimpl diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -72,7 +72,6 @@ n &= LONG_MASK if n >= LONG_TEST: n -= 2*LONG_TEST - # return int(n) return n def longlongmask(n): @@ -113,7 +112,6 @@ assert not isinstance(r, r_uint), "unexpected ovf check on unsigned" assert not isinstance(r, r_longlong), "ovfcheck not supported on r_longlong" assert not isinstance(r,r_ulonglong),"ovfcheck not supported on r_ulonglong" - # if type(r) is long: if abs(r) > sys.maxint: raise OverflowError, "signed integer expression did overflow" return r diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -29,7 +29,7 @@ r_longlong_result = r_longlong argtype_by_name = { - 'int': long, # XXX int, + 'int': (int, long), 'float': float, 'uint': r_uint, 'llong': r_longlong_arg, diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -1,7 +1,3 @@ -import sys -sys.orig_maxint = sys.maxint -sys.maxint = 2**63-1 - #! /usr/bin/env python """ PyPy Test runner interface @@ -14,6 +10,9 @@ For more information, use test_all.py -h. """ import sys, os +sys.orig_maxint = sys.maxint +sys.maxint = 2**63-1 + if len(sys.argv) == 1 and os.path.dirname(sys.argv[0]) in '.': print >> sys.stderr, __doc__ From noreply at buildbot.pypy.org Fri Jul 1 15:08:08 2011 From: noreply at buildbot.pypy.org (berdario) Date: Fri, 1 Jul 2011 15:08:08 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110701130808.DA89F8293A@wyvern.cs.uni-duesseldorf.de> Author: Dario Bertini Branch: Changeset: r45226:62f51617cbc7 Date: 2011-07-01 15:14 +0200 http://bitbucket.org/pypy/pypy/changeset/62f51617cbc7/ Log: merge heads diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -357,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -385,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) From noreply at buildbot.pypy.org Fri Jul 1 15:34:07 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 1 Jul 2011 15:34:07 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: fix pyjitpl.py and fix tests. the last test is less relevant now Message-ID: <20110701133407.410BF8293A@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45227:5cecfca503ca Date: 2011-07-01 15:41 +0200 http://bitbucket.org/pypy/pypy/changeset/5cecfca503ca/ Log: fix pyjitpl.py and fix tests. the last test is less relevant now diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -409,37 +409,28 @@ assert isinstance(fielddescr, Descr) return llimpl.do_getfield_raw_float(struct, fielddescr.ofs) - def bh_getinteriorfield_gc_i(self, array, index, arraydescr, fielddescr): - assert isinstance(arraydescr, Descr) - assert isinstance(fielddescr, Descr) - return llimpl.do_getinteriorfield_gc_int(array, index, fielddescr.ofs) - def bh_getinteriorfield_gc_r(self, array, index, arraydescr, fielddescr): - assert isinstance(arraydescr, Descr) - assert isinstance(fielddescr, Descr) - return llimpl.do_getinteriorfield_gc_ptr(array, index, fielddescr.ofs) - def bh_getinteriorfield_gc_f(self, array, index, arraydescr, fielddescr): - assert isinstance(arraydescr, Descr) - assert isinstance(fielddescr, Descr) - return llimpl.do_getinteriorfield_gc_float(array, index, fielddescr.ofs) + def bh_getinteriorfield_gc_i(self, array, index, descr): + assert isinstance(descr, Descr) + return llimpl.do_getinteriorfield_gc_int(array, index, descr.ofs) + def bh_getinteriorfield_gc_r(self, array, index, descr): + assert isinstance(descr, Descr) + return llimpl.do_getinteriorfield_gc_ptr(array, index, descr.ofs) + def bh_getinteriorfield_gc_f(self, array, index, descr): + assert isinstance(descr, Descr) + return llimpl.do_getinteriorfield_gc_float(array, index, descr.ofs) - def bh_setinteriorfield_gc_i(self, array, index, arraydescr, fielddescr, - value): - assert isinstance(arraydescr, Descr) - assert isinstance(fielddescr, Descr) - return llimpl.do_setinteriorfield_gc_int(array, index, fielddescr.ofs, + def bh_setinteriorfield_gc_i(self, array, index, descr, value): + assert isinstance(descr, Descr) + return llimpl.do_setinteriorfield_gc_int(array, index, descr.ofs, value) - def bh_setinteriorfield_gc_r(self, array, index, arraydescr, fielddescr, - value): - assert isinstance(arraydescr, Descr) - assert isinstance(fielddescr, Descr) - return llimpl.do_setinteriorfield_gc_ptr(array, index, fielddescr.ofs, + def bh_setinteriorfield_gc_r(self, array, index, descr, value): + assert isinstance(descr, Descr) + return llimpl.do_setinteriorfield_gc_ptr(array, index, descr.ofs, value) - def bh_setinteriorfield_gc_f(self, array, index, arraydescr, fielddescr, - value): - assert isinstance(arraydescr, Descr) - assert isinstance(fielddescr, Descr) - return llimpl.do_setinteriorfield_gc_float(array, index, fielddescr.ofs, - value) + def bh_setinteriorfield_gc_f(self, array, index, descr, value): + assert isinstance(descr, Descr) + return llimpl.do_setinteriorfield_gc_float(array, index, descr.ofs, + value) def bh_new(self, sizedescr): assert isinstance(sizedescr, Descr) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,10 +3,9 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rpython.llinterp import LLException from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr from pypy.jit.codewriter import heaptracker, longlong from pypy.jit.metainterp.jitexc import JitException, get_llexception, reraise @@ -1114,16 +1113,25 @@ array = cpu.bh_getfield_gc_r(vable, fdescr) return cpu.bh_arraylen_gc(adescr, array) - @arguments("cpu", "r", "i", "d", "d", returns="i") - def bhimpl_getinteriorfield_gc_i(cpu, array, index, arraydescr, fielddescr): - return cpu.bh_getinteriorfield_gc_i(array, index, arraydescr, - fielddescr) + @arguments("cpu", "r", "i", "d", returns="i") + def bhimpl_getinteriorfield_gc_i(cpu, array, index, descr): + return cpu.bh_getinteriorfield_gc_i(array, index, descr) + @arguments("cpu", "r", "i", "d", returns="r") + def bhimpl_getinteriorfield_gc_r(cpu, array, index, descr): + return cpu.bh_getinteriorfield_gc_r(array, index, descr) + @arguments("cpu", "r", "i", "d", returns="f") + def bhimpl_getinteriorfield_gc_f(cpu, array, index, descr): + return cpu.bh_getinteriorfield_gc_f(array, index, descr) - @arguments("cpu", "r", "i", "d", "i", "d") - def bhimpl_setinteriorfield_gc_i(cpu, array, index, arraydescr, - fielddescr, value): - cpu.bh_setinteriorfield_gc_i(array, index, arraydescr, fielddescr, - value) + @arguments("cpu", "r", "i", "d", "i") + def bhimpl_setinteriorfield_gc_i(cpu, array, index, descr, value): + cpu.bh_setinteriorfield_gc_i(array, index, descr, value) + @arguments("cpu", "r", "i", "d", "r") + def bhimpl_setinteriorfield_gc_r(cpu, array, index, descr, value): + cpu.bh_setinteriorfield_gc_r(array, index, descr, value) + @arguments("cpu", "r", "i", "d", "f") + def bhimpl_setinteriorfield_gc_f(cpu, array, index, descr, value): + cpu.bh_setinteriorfield_gc_f(array, index, descr, value) @arguments("cpu", "r", "d", returns="i") def bhimpl_getfield_gc_i(cpu, struct, fielddescr): diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -120,31 +120,27 @@ else: cpu.bh_setarrayitem_raw_i(arraydescr, array, index, itembox.getint()) -def do_getinteriorfield_gc(cpu, _, arraybox, indexbox, arraydescr, fielddescr): +def do_getinteriorfield_gc(cpu, _, arraybox, indexbox, descr): array = arraybox.getref_base() index = indexbox.getint() - if fielddescr.is_pointer_field(): - return BoxPtr(cpu.bh_getinteriorfield_gc_r(array, index, arraydescr, - fielddescr)) - elif fielddescr.is_float_field(): - return BoxFloat(cpu.bh_getinteriorfield_gc_f(array, index, arraydescr, - fielddescr)) + if descr.is_pointer_field(): + return BoxPtr(cpu.bh_getinteriorfield_gc_r(array, index, descr)) + elif descr.is_float_field(): + return BoxFloat(cpu.bh_getinteriorfield_gc_f(array, index, descr)) else: - return BoxInt(cpu.bh_getinteriorfield_gc_i(array, index, arraydescr, - fielddescr)) + return BoxInt(cpu.bh_getinteriorfield_gc_i(array, index, descr)) -def do_setinteriorfield_gc(cpu, _, arraybox, indexbox, valuebox, arraydescr, - fielddescr): +def do_setinteriorfield_gc(cpu, _, arraybox, indexbox, valuebox, descr): array = arraybox.getref_base() index = indexbox.getint() - if fielddescr.is_pointer_field(): - cpu.bh_setinteriorfield_gc_r(array, index, arraydescr, fielddescr, + if descr.is_pointer_field(): + cpu.bh_setinteriorfield_gc_r(array, index, descr, valuebox.getref_base()) - elif fielddescr.is_float_field(): - cpu.bh_setinteriorfield_gc_f(array, index, arraydescr, fielddescr, + elif descr.is_float_field(): + cpu.bh_setinteriorfield_gc_f(array, index, descr, valuebox.getfloatstorage()) else: - cpu.bh_setinteriorfield_gc_i(array, index, arraydescr, fielddescr, + cpu.bh_setinteriorfield_gc_i(array, index, descr, valuebox.getint()) def do_getfield_gc(cpu, _, structbox, fielddescr): diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -512,11 +512,10 @@ opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any - @arguments("box", "box", "descr", "descr") - def _opimpl_getinteriorfield_gc_any(self, array, index, arraydescr, - fielddescr): - return self.execute_with_descr(rop.GETINTERIORFIELD_GC, fielddescr, - array, index, arraydescr) + @arguments("box", "box", "descr") + def _opimpl_getinteriorfield_gc_any(self, array, index, descr): + return self.execute_with_descr(rop.GETINTERIORFIELD_GC, descr, + array, index) opimpl_getinteriorfield_gc_i = _opimpl_getinteriorfield_gc_any opimpl_getinteriorfield_gc_f = _opimpl_getinteriorfield_gc_any opimpl_getinteriorfield_gc_r = _opimpl_getinteriorfield_gc_any @@ -544,11 +543,10 @@ opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any - @arguments("box", "box", "box", "descr", "descr") - def _opimpl_setinteriorfield_gc_any(self, array, index, value, arraydescr, - fielddescr): - self.execute_with_descr(rop.SETINTERIORFIELD_GC, fielddescr, - array, index, value, arraydescr) + @arguments("box", "box", "box", "descr") + def _opimpl_setinteriorfield_gc_any(self, array, index, value, descr): + self.execute_with_descr(rop.SETINTERIORFIELD_GC, descr, + array, index, value) opimpl_setinteriorfield_gc_i = _opimpl_setinteriorfield_gc_any opimpl_setinteriorfield_gc_f = _opimpl_setinteriorfield_gc_any opimpl_setinteriorfield_gc_r = _opimpl_setinteriorfield_gc_any diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -92,7 +92,7 @@ res1 = f(100) res2 = self.meta_interp(f, [100], listops=True) assert res1 == res2 - self.check_loops(int_mod=1) # the hash was traced + self.check_loops(int_mod=3) # the hash was traced and eq def test_dict_setdefault(self): myjitdriver = JitDriver(greens = [], reds = ['total', 'dct']) @@ -129,7 +129,7 @@ assert f(100) == 50 res = self.meta_interp(f, [100], listops=True) assert res == 50 - self.check_loops(int_mod=1) + self.check_loops(int_mod=3) # key + eq def test_repeated_lookup(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'd']) @@ -154,14 +154,7 @@ res = self.meta_interp(f, [100], listops=True) assert res == f(50) - # XXX: ideally there would be 7 calls here, but repeated CALL_PURE with - # the same arguments are not folded, because we have conflicting - # definitions of pure, once strhash can be appropriately folded - # this should be decreased to seven. - self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, - "guard_true": 1, "int_and": 1, "int_gt": 1, - "int_is_true": 1, "int_sub": 1, "jump": 1, - "new_with_vtable": 1, "setfield_gc": 1}) + self.check_loops(call=4) class TestOOtype(DictTests, OOJitMixin): From noreply at buildbot.pypy.org Fri Jul 1 15:47:18 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 1 Jul 2011 15:47:18 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: merge default Message-ID: <20110701134718.8E1978293A@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45228:deb116fcd516 Date: 2011-07-01 15:54 +0200 http://bitbucket.org/pypy/pypy/changeset/deb116fcd516/ Log: merge default diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,14 +4399,8 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) - self.assertTrue(l.__add__.im_class is list) + self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__objclass__ is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -299,12 +299,13 @@ listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -134,7 +134,7 @@ def accept_comp_iteration(self, codegen, index): self.elt.walkabout(codegen) - codegen.emit_op_arg(ops.SET_ADD, index) + codegen.emit_op_arg(ops.SET_ADD, index + 1) class __extend__(ast.DictComp): @@ -148,7 +148,7 @@ def accept_comp_iteration(self, codegen, index): self.value.walkabout(codegen) self.key.walkabout(codegen) - codegen.emit_op_arg(ops.MAP_ADD, index) + codegen.emit_op_arg(ops.MAP_ADD, index + 1) # These are frame blocks. diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -92,7 +92,10 @@ return name if len(name) + 2 >= MANGLE_LEN: return name - if name.endswith('__'): + # Don't mangle __id__ or names with dots. The only time a name with a dot + # can occur is when we are compiling an import statement that has a package + # name. + if name.endswith('__') or '.' in name: return name try: i = 0 diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -308,6 +308,15 @@ "p.__name__", os.path.__name__) yield (self.st, 'from os import *', "path.__name__, sep", (os.path.__name__, os.sep)) + yield (self.st, ''' + class A(object): + def m(self): + from __foo__.bar import x + try: + A().m() + except ImportError, e: + msg = str(e) + ''', "msg", "No module named __foo__") def test_if_stmts(self): yield self.st, "a = 42\nif a > 10: a += 2", "a", 44 diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -100,12 +100,12 @@ @jit.dont_look_inside def fast2locals(self): - # Copy values from self.fastlocals_w to self.w_locals + # Copy values from the fastlocals to self.w_locals if self.w_locals is None: self.w_locals = self.space.newdict() varnames = self.getcode().getvarnames() fastscope_w = self.getfastscope() - for i in range(min(len(varnames), len(fastscope_w))): + for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] if w_value is not None: @@ -114,7 +114,7 @@ @jit.dont_look_inside def locals2fast(self): - # Copy values from self.w_locals to self.fastlocals_w + # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None varnames = self.getcode().getvarnames() numlocals = self.getfastscopelength() diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -98,7 +98,7 @@ self.closure) for i in funccallunrolling: if i < nargs: - new_frame.fastlocals_w[i] = args_w[i] + new_frame.locals_stack_w[i] = args_w[i] return new_frame.run() elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1: assert isinstance(code, gateway.BuiltinCodePassThroughArguments1) @@ -158,7 +158,7 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg return new_frame.run() @@ -169,13 +169,13 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = self.defs_w[j] + new_frame.locals_stack_w[i] = self.defs_w[j] i += 1 return new_frame.run() diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -170,7 +170,7 @@ for i in range(len(args_to_copy)): argnum = args_to_copy[i] if argnum >= 0: - self.cells[i].set(self.fastlocals_w[argnum]) + self.cells[i].set(self.locals_stack_w[argnum]) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -63,6 +63,7 @@ the pypy compiler""" self.space = space eval.Code.__init__(self, name) + assert nlocals >= 0 self.co_argcount = argcount self.co_nlocals = nlocals self.co_stacksize = stacksize @@ -202,7 +203,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -215,7 +216,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -9,7 +9,7 @@ from pypy.interpreter import pytraceback from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib.jit import hint -from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.debug import make_sure_not_resized, check_nonneg from pypy.rlib.rarithmetic import intmask from pypy.rlib import jit from pypy.tool import stdlib_opcode @@ -56,16 +56,18 @@ assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals) - self.valuestack_w = [None] * code.co_stacksize - self.valuestackdepth = 0 + self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize) + self.nlocals = code.co_nlocals + self.valuestackdepth = code.co_nlocals self.lastblock = None + make_sure_not_resized(self.locals_stack_w) + check_nonneg(self.nlocals) + # if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure, code) - self.fastlocals_w = [None] * code.co_nlocals - make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno def mark_as_escaped(self): @@ -184,14 +186,14 @@ # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth - self.valuestack_w[depth] = w_object + self.locals_stack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 - assert depth >= 0, "pop from empty value stack" - w_object = self.valuestack_w[depth] - self.valuestack_w[depth] = None + assert depth >= self.nlocals, "pop from empty value stack" + w_object = self.locals_stack_w[depth] + self.locals_stack_w[depth] = None self.valuestackdepth = depth return w_object @@ -217,24 +219,24 @@ def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n - assert base >= 0 + assert base >= self.nlocals while True: n -= 1 if n < 0: break - values_w[n] = self.valuestack_w[base+n] + values_w[n] = self.locals_stack_w[base+n] return values_w @jit.unroll_safe def dropvalues(self, n): n = hint(n, promote=True) finaldepth = self.valuestackdepth - n - assert finaldepth >= 0, "stack underflow in dropvalues()" + assert finaldepth >= self.nlocals, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break - self.valuestack_w[finaldepth+n] = None + self.locals_stack_w[finaldepth+n] = None self.valuestackdepth = finaldepth @jit.unroll_safe @@ -261,30 +263,30 @@ # Contrast this with CPython where it's PEEK(-1). index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "peek past the bottom of the stack" - return self.valuestack_w[index] + assert index >= self.nlocals, "peek past the bottom of the stack" + return self.locals_stack_w[index] def settopvalue(self, w_object, index_from_top=0): index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "settop past the bottom of the stack" - self.valuestack_w[index] = w_object + assert index >= self.nlocals, "settop past the bottom of the stack" + self.locals_stack_w[index] = w_object @jit.unroll_safe def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 finaldepth = hint(finaldepth, promote=True) while depth >= finaldepth: - self.valuestack_w[depth] = None + self.locals_stack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth - def savevaluestack(self): - return self.valuestack_w[:self.valuestackdepth] + def save_locals_stack(self): + return self.locals_stack_w[:self.valuestackdepth] - def restorevaluestack(self, items_w): - assert None not in items_w - self.valuestack_w[:len(items_w)] = items_w + def restore_locals_stack(self, items_w): + self.locals_stack_w[:len(items_w)] = items_w + self.init_cells() self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): @@ -314,11 +316,12 @@ else: f_lineno = self.f_lineno - values_w = self.valuestack_w[0:self.valuestackdepth] + values_w = self.locals_stack_w[self.nlocals:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) - w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) + w_fastlocals = maker.slp_into_tuple_with_nulls( + space, self.locals_stack_w[:self.nlocals]) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None @@ -399,7 +402,8 @@ new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) - new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None @@ -423,28 +427,28 @@ @jit.dont_look_inside def getfastscope(self): "Get the fast locals as a list." - return self.fastlocals_w + return self.locals_stack_w @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) - if scope_len > len(self.fastlocals_w): + if scope_len > self.nlocals: raise ValueError, "new fastscope is longer than the allocated area" - # don't assign directly to 'fastlocals_w[:scope_len]' to be + # don't assign directly to 'locals_stack_w[:scope_len]' to be # virtualizable-friendly for i in range(scope_len): - self.fastlocals_w[i] = scope_w[i] + self.locals_stack_w[i] = scope_w[i] self.init_cells() def init_cells(self): - """Initialize cellvars from self.fastlocals_w + """Initialize cellvars from self.locals_stack_w. This is overridden in nestedscope.py""" pass def getfastscopelength(self): - return self.pycode.co_nlocals + return self.nlocals def getclosure(self): return None diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -324,7 +324,7 @@ def LOAD_FAST(self, varindex, next_instr): # access a local variable directly - w_value = self.fastlocals_w[varindex] + w_value = self.locals_stack_w[varindex] if w_value is None: self._load_fast_failed(varindex) self.pushvalue(w_value) @@ -343,7 +343,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self.fastlocals_w[varindex] = w_newvalue + self.locals_stack_w[varindex] = w_newvalue def POP_TOP(self, oparg, next_instr): self.popvalue() @@ -696,12 +696,12 @@ LOAD_GLOBAL._always_inline_ = True def DELETE_FAST(self, varindex, next_instr): - if self.fastlocals_w[varindex] is None: + if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise operationerrfmt(self.space.w_UnboundLocalError, message, varname) - self.fastlocals_w[varindex] = None + self.locals_stack_w[varindex] = None def BUILD_TUPLE(self, itemcount, next_instr): items = self.popvalues(itemcount) @@ -1048,13 +1048,13 @@ def SET_ADD(self, oparg, next_instr): w_value = self.popvalue() - w_set = self.peekvalue(oparg) + w_set = self.peekvalue(oparg - 1) self.space.call_method(w_set, 'add', w_value) def MAP_ADD(self, oparg, next_instr): w_key = self.popvalue() w_value = self.popvalue() - w_dict = self.peekvalue(oparg) + w_dict = self.peekvalue(oparg - 1) self.space.setitem(w_dict, w_key, w_value) def SET_LINENO(self, lineno, next_instr): @@ -1091,12 +1091,10 @@ @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): - w_set = self.space.call_function(self.space.w_set) - if itemcount: - w_add = self.space.getattr(w_set, self.space.wrap("add")) - for i in range(itemcount): - w_item = self.popvalue() - self.space.call_function(w_add, w_item) + w_set = self.space.newset() + for i in range(itemcount): + w_item = self.popvalue() + self.space.call_method(w_set, 'add', w_item) self.pushvalue(w_set) def STORE_MAP(self, oparg, next_instr): diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py --- a/pypy/interpreter/test/test_eval.py +++ b/pypy/interpreter/test/test_eval.py @@ -15,16 +15,16 @@ self.code = code Frame.__init__(self, space) self.numlocals = numlocals - self.fastlocals_w = [None] * self.numlocals + self._fastlocals_w = [None] * self.numlocals def getcode(self): return self.code def setfastscope(self, scope_w): - self.fastlocals_w = scope_w + self._fastlocals_w = scope_w def getfastscope(self): - return self.fastlocals_w + return self._fastlocals_w def getfastscopelength(self): return self.numlocals @@ -38,11 +38,11 @@ self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({})) - self.f.fastlocals_w[0] = w(5) + self.f._fastlocals_w[0] = w(5) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5})) - self.f.fastlocals_w[2] = w(7) + self.f._fastlocals_w[2] = w(7) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5, 'args': 7})) @@ -57,13 +57,13 @@ w = self.space.wrap self.f.w_locals = self.space.wrap({}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [None]*5) + self.sameList(self.f._fastlocals_w, [None]*5) self.f.w_locals = self.space.wrap({'x': 5}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) + self.sameList(self.f._fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.wrap({'x':5, 'args':7}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), None, w(7), - None, None]) + self.sameList(self.f._fastlocals_w, [w(5), None, w(7), + None, None]) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -203,3 +203,26 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + import sys + class A(object): + def m(self): + "aaa" + m.x = 3 + + bm = A().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.im_class is A + if '__pypy__' in sys.builtin_module_names: + assert bm.__objclass__ is A + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + if '__pypy__' in sys.builtin_module_names: + assert l.append.__objclass__ is list + assert l.__add__.__self__ is l + assert l.__add__.__objclass__ is list diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -761,13 +761,17 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), + __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -703,22 +703,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: @@ -889,7 +895,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -901,7 +907,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -467,13 +469,13 @@ # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,6 +185,13 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -75,12 +75,13 @@ # OS_MATH_SQRT = 100 - def __new__(cls, readonly_descrs_fields, + def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, can_invalidate=False): key = (frozenset(readonly_descrs_fields), + frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, @@ -89,6 +90,7 @@ return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields + result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ extraeffect == EffectInfo.EF_PURE: result.write_descrs_fields = [] @@ -119,7 +121,7 @@ if effects is top_set: return None readonly_descrs_fields = [] - # readonly_descrs_arrays = [] --- not enabled for now + readonly_descrs_arrays = [] write_descrs_fields = [] write_descrs_arrays = [] @@ -145,10 +147,13 @@ elif tup[0] == "array": add_array(write_descrs_arrays, tup) elif tup[0] == "readarray": - pass + tupw = ("array",) + tup[1:] + if tupw not in effects: + add_array(readonly_descrs_arrays, tup) else: assert 0 return EffectInfo(readonly_descrs_fields, + readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect, diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -44,10 +44,6 @@ return True if mod.startswith('pypy.translator.'): # XXX wtf? return True - # string builder interface - if mod == 'pypy.rpython.lltypesystem.rbuilder': - return True - return False def look_inside_graph(self, graph): diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -34,6 +34,15 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays +def test_include_read_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo.write_descrs_fields + assert not effectinfo.write_descrs_arrays + def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) @@ -51,6 +60,16 @@ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.write_descrs_arrays +def test_dont_include_read_and_write_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A)), + ("array", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert not effectinfo.readonly_descrs_arrays + assert not effectinfo.write_descrs_fields + assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -15,7 +15,7 @@ from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.jit.metainterp.optimize import InvalidLoop -from pypy.jit.metainterp.resume import NUMBERING +from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong def giveup(): @@ -119,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -302,7 +303,7 @@ rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) CNT_INT = -0x20000000 CNT_REF = -0x40000000 @@ -633,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -4,7 +4,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rlib.objectmodel import we_are_translated, r_dict, Symbolic from pypy.rlib.objectmodel import compute_unique_id -from pypy.rlib.rarithmetic import intmask, r_int64 +from pypy.rlib.rarithmetic import r_int64 from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop @@ -791,6 +791,7 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py --- a/pypy/jit/metainterp/optimize.py +++ b/pypy/jit/metainterp/optimize.py @@ -25,7 +25,6 @@ def _optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): from pypy.jit.metainterp.optimizeopt import optimize_loop_1 - cpu = metainterp_sd.cpu loop.logops = metainterp_sd.logger_noopt.log_loop(loop.inputargs, loop.operations) # XXX do we really still need a list? @@ -49,7 +48,6 @@ def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts, inline_short_preamble, retraced=False): from pypy.jit.metainterp.optimizeopt import optimize_bridge_1 - cpu = metainterp_sd.cpu bridge.logops = metainterp_sd.logger_noopt.log_loop(bridge.inputargs, bridge.operations) if old_loop_tokens: diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -8,8 +8,8 @@ class CachedField(object): def __init__(self): - # Cache information for a field descr. It can be in one - # of two states: + # Cache information for a field descr, or for an (array descr, index) + # pair. It can be in one of two states: # # 1. 'cached_fields' is a dict mapping OptValues of structs # to OptValues of fields. All fields on-heap are @@ -27,19 +27,19 @@ self._lazy_setfield_registered = False def do_setfield(self, optheap, op): - # Update the state with the SETFIELD_GC operation 'op'. + # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) if self.possible_aliasing(optheap, structvalue): self.force_lazy_setfield(optheap) assert not self.possible_aliasing(optheap, structvalue) cached_fieldvalue = self._cached_fields.get(structvalue, None) if cached_fieldvalue is not fieldvalue: # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields list + # myself in the optheap's _lazy_setfields_and_arrayitems list self._lazy_setfield = op if not self._lazy_setfield_registered: - optheap._lazy_setfields.append(self) + optheap._lazy_setfields_and_arrayitems.append(self) self._lazy_setfield_registered = True else: # this is the case where the pending setfield ends up @@ -65,7 +65,7 @@ if self._lazy_setfield is not None: op = self._lazy_setfield assert optheap.getvalue(op.getarg(0)) is structvalue - return optheap.getvalue(op.getarg(1)) + return optheap.getvalue(op.getarglist()[-1]) else: return self._cached_fields.get(structvalue, None) @@ -87,7 +87,7 @@ # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) def get_reconstructed(self, optimizer, valuemap): @@ -100,12 +100,6 @@ return cf -class CachedArrayItems(object): - def __init__(self): - self.fixed_index_items = {} - self.var_index_item = None - self.var_index_indexvalue = None - class BogusPureField(JitException): pass @@ -116,9 +110,10 @@ def __init__(self): # cached fields: {descr: CachedField} self.cached_fields = {} - self._lazy_setfields = [] - # cached array items: {descr: CachedArrayItems} + # cached array items: {array descr: {index: CachedField}} self.cached_arrayitems = {} + # + self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -126,34 +121,23 @@ new = OptHeap() if True: - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() else: assert 0 # was: new.lazy_setfields = self.lazy_setfields for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) - new.cached_arrayitems = {} - for descr, d in self.cached_arrayitems.items(): - newd = {} - new.cached_arrayitems[descr] = newd - for value, cache in d.items(): - newcache = CachedArrayItems() - newd[value.get_reconstructed(optimizer, valuemap)] = newcache - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_reconstructed(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) - for index, fieldvalue in cache.fixed_index_items.items(): - newcache.fixed_index_items[index] = \ - fieldvalue.get_reconstructed(optimizer, valuemap) + for descr, submap in self.cached_arrayitems.items(): + newdict = {} + for index, d in submap.items(): + newdict[index] = d.get_reconstructed(optimizer, valuemap) + new.cached_arrayitems[descr] = newdict return new def clean_caches(self): - del self._lazy_setfields[:] + del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() self.cached_arrayitems.clear() @@ -164,50 +148,16 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): - d = self.cached_arrayitems.get(descr, None) - if d is None: - d = self.cached_arrayitems[descr] = {} - cache = d.get(value, None) - if cache is None: - cache = d[value] = CachedArrayItems() - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - index = indexbox.getint() - if write: - for value, othercache in d.iteritems(): - # fixed index, clean the variable index cache, in case the - # index is the same - othercache.var_index_indexvalue = None - othercache.var_index_item = None - try: - del othercache.fixed_index_items[index] - except KeyError: - pass - cache.fixed_index_items[index] = fieldvalue - else: - if write: - for value, othercache in d.iteritems(): - # variable index, clear all caches for this descr - othercache.var_index_indexvalue = None - othercache.var_index_item = None - othercache.fixed_index_items.clear() - cache.var_index_indexvalue = indexvalue - cache.var_index_item = fieldvalue - - def read_cached_arrayitem(self, descr, value, indexvalue): - d = self.cached_arrayitems.get(descr, None) - if d is None: - return None - cache = d.get(value, None) - if cache is None: - return None - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - return cache.fixed_index_items.get(indexbox.getint(), None) - elif cache.var_index_indexvalue is indexvalue: - return cache.var_index_item - return None + def arrayitem_cache(self, descr, index): + try: + submap = self.cached_arrayitems[descr] + except KeyError: + submap = self.cached_arrayitems[descr] = {} + try: + cf = submap[index] + except KeyError: + cf = submap[index] = CachedField() + return cf def emit_operation(self, op): self.emitting_operation(op) @@ -219,7 +169,8 @@ if op.is_ovf(): return if op.is_guard(): - self.optimizer.pendingfields = self.force_lazy_setfields_for_guard() + self.optimizer.pendingfields = ( + self.force_lazy_setfields_and_arrayitems_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -248,6 +199,8 @@ # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: self.force_lazy_setfield(fielddescr) + for arraydescr in effectinfo.readonly_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: self.force_lazy_setfield(fielddescr) try: @@ -256,8 +209,11 @@ except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) try: - del self.cached_arrayitems[arraydescr] + submap = self.cached_arrayitems[arraydescr] + for cf in submap.itervalues(): + cf._cached_fields.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -266,7 +222,7 @@ # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. return - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() self.clean_caches() @@ -277,6 +233,10 @@ for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] + for submap in self.cached_arrayitems.itervalues(): + for cf in submap.itervalues(): + if value in cf._cached_fields: + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -285,6 +245,14 @@ return cf.force_lazy_setfield(self) + def force_lazy_setarrayitem(self, arraydescr): + try: + submap = self.cached_arrayitems[arraydescr] + except KeyError: + return + for cf in submap.values(): + cf.force_lazy_setfield(self) + def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes # sense to avoid a situation like "int_eq/setfield_gc/guard_true", @@ -309,30 +277,49 @@ newoperations[-2] = lastop newoperations[-1] = prevop - def force_all_lazy_setfields(self): - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + def _assert_valid_cf(self, cf): + # check that 'cf' is in cached_fields or cached_arrayitems + if not we_are_translated(): + if cf not in self.cached_fields.values(): + for submap in self.cached_arrayitems.values(): + if cf in submap.values(): + break + else: + assert 0, "'cf' not in cached_fields/cached_arrayitems" + + def force_all_lazy_setfields_and_arrayitems(self): + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) cf.force_lazy_setfield(self) - def force_lazy_setfields_for_guard(self): + def force_lazy_setfields_and_arrayitems_for_guard(self): pendingfields = [] - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) op = cf._lazy_setfield if op is None: continue # the only really interesting case that we need to handle in the # guards' resume data is that of a virtual object that is stored - # into a field of a non-virtual object. + # into a field of a non-virtual object. Here, 'op' in either + # SETFIELD_GC or SETARRAYITEM_GC. value = self.getvalue(op.getarg(0)) assert not value.is_virtual() # it must be a non-virtual - fieldvalue = self.getvalue(op.getarg(1)) + fieldvalue = self.getvalue(op.getarglist()[-1]) if fieldvalue.is_virtual(): # this is the case that we leave to resume.py + opnum = op.getopnum() + if opnum == rop.SETFIELD_GC: + itemindex = -1 + elif opnum == rop.SETARRAYITEM_GC: + indexvalue = self.getvalue(op.getarg(1)) + assert indexvalue.is_constant() + itemindex = indexvalue.box.getint() + assert itemindex >= 0 + else: + assert 0 pendingfields.append((op.getdescr(), value.box, - fieldvalue.get_key_box())) + fieldvalue.get_key_box(), itemindex)) else: cf.force_lazy_setfield(self) self.fixup_guard_situation() @@ -364,24 +351,45 @@ cf.do_setfield(self, op) def optimize_GETARRAYITEM_GC(self, op): - value = self.getvalue(op.getarg(0)) + arrayvalue = self.getvalue(op.getarg(0)) indexvalue = self.getvalue(op.getarg(1)) - fieldvalue = self.read_cached_arrayitem(op.getdescr(), value, indexvalue) - if fieldvalue is not None: - self.make_equal_to(op.result, fieldvalue) - return - ###self.optimizer.optimize_default(op) + cf = None + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + fieldvalue = cf.getfield_from_cache(self, arrayvalue) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # default case: produce the operation + arrayvalue.ensure_nonnull() self.emit_operation(op) - fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) + # the remember the result of reading the array item + if cf is not None: + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(arrayvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): - self.emit_operation(op) - value = self.getvalue(op.getarg(0)) - fieldvalue = self.getvalue(op.getarg(2)) + if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), + op.getarg(1)], + op.getdescr()): + os.write(2, '[bogus immutable array declaration: %s]\n' % + (op.getdescr().repr_of_descr())) + raise BogusPureField + # indexvalue = self.getvalue(op.getarg(1)) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - write=True) + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + cf.do_setfield(self, op) + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # and then emit the operation + self.emit_operation(op) def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 from pypy.jit.metainterp.optimizeopt.util import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -23,7 +23,7 @@ def reconstruct_for_next_iteration(self, optimizer, valuemap): assert self.posponedop is None - return self + return self def propagate_forward(self, op): if op.is_ovf(): @@ -194,7 +194,7 @@ # Synthesize the reverse ops for optimize_default to reuse self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0)) self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1)) - + def optimize_INT_MUL_OVF(self, op): v1 = self.getvalue(op.getarg(0)) @@ -292,6 +292,11 @@ v1.intbound.make_ge(IntLowerBound(0)) v1.intbound.make_lt(IntUpperBound(256)) + def optimize_UNICODEGETITEM(self, op): + self.emit_operation(op) + v1 = self.getvalue(op.result) + v1.intbound.make_ge(IntLowerBound(0)) + def make_int_lt(self, box1, box2): v1 = self.getvalue(box1) v2 = self.getvalue(box2) @@ -368,6 +373,15 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -413,5 +427,6 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL + optimize_ops = _findall(OptIntBounds, 'optimize_') propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/string.py --- a/pypy/jit/metainterp/optimizeopt/string.py +++ b/pypy/jit/metainterp/optimizeopt/string.py @@ -348,7 +348,7 @@ optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimizer, strbox, indexbox, mode): +def _strgetitem(optimization, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimizer.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,8 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self.optimizer, - value.force_box(),vindex.force_box(), mode) + resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -121,6 +121,41 @@ print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + class BaseTestOptimizeBasic(BaseTestBasic): @@ -1070,8 +1105,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1436,9 +1471,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) jump(p1, i1, i2, p3) """ @@ -1612,6 +1647,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -1874,7 +1910,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1892,7 +1927,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1910,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2203,23 +2236,6 @@ # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2328,7 +2344,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2349,7 +2364,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2369,7 +2383,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2395,7 +2408,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2420,7 +2433,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2444,7 +2456,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2465,7 +2476,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2486,7 +2496,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2508,7 +2517,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2550,7 +2558,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2576,7 +2583,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2600,9 +2606,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2894,7 +2897,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2940,7 +2942,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2979,7 +2980,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3006,7 +3006,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -4480,6 +4479,47 @@ # not obvious, because of the exception UnicodeDecodeError that # can be raised by ll_str2unicode() + def test_strgetitem_repeated(self): + ops = """ + [p0, i0] + i1 = strgetitem(p0, i0) + i2 = strgetitem(p0, i0) + i3 = int_eq(i1, i2) + guard_true(i3) [] + escape(i2) + jump(p0, i0) + """ + expected = """ + [p0, i0] + i1 = strgetitem(p0, i0) + escape(i1) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py @@ -51,7 +51,7 @@ restype=types.sint) # def calldescr(cpu, FUNC, oopspecindex, extraeffect=None): - einfo = EffectInfo([], [], [], oopspecindex=oopspecindex, + einfo = EffectInfo([], [], [], [], oopspecindex=oopspecindex, extraeffect=extraeffect) return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo) # diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1381,8 +1381,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1806,9 +1806,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -1818,9 +1818,9 @@ # i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -2055,6 +2055,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2741,8 +2742,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -5311,7 +5310,7 @@ """ self.optimize_strunicode_loop(ops, expected) - def test_strgetitem_small(self): + def test_strgetitem_bounds(self): ops = """ [p0, i0] i1 = strgetitem(p0, i0) @@ -5323,7 +5322,20 @@ """ expected = """ [p0, i0] - i1 = strgetitem(p0, i0) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_unicodegetitem_bounds(self): + ops = """ + [p0, i0] + i1 = unicodegetitem(p0, i0) + i2 = int_lt(i1, 0) + guard_false(i2) [] + jump(p0, i0) + """ + expected = """ + [p0, i0] jump(p0, i0) """ self.optimize_loop(ops, expected) @@ -5863,4 +5875,28 @@ escape(p0) jump(p0) """ - self.optimize_loop(ops, expected) \ No newline at end of file + self.optimize_loop(ops, expected) + + def test_setarrayitem_lazy(self): + ops = """ + [i0, i1] + p0 = escape() + i2 = escape() + p1 = new_with_vtable(ConstClass(node_vtable)) + setarrayitem_gc(p0, 2, p1, descr=arraydescr) + guard_true(i2) [] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + expected = """ + [i0, i1] + p0 = escape() + i2 = escape() + guard_true(i2) [p0] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/optimizeopt/test/test_util.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -166,19 +166,19 @@ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [])) + EffectInfo([], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [])) + EffectInfo([], [], [adescr], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [arraydescr])) + EffectInfo([], [], [adescr], [arraydescr])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([adescr], [], [])) + EffectInfo([adescr], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([nextdescr], [], [], + EffectInfo([nextdescr], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), @@ -195,15 +195,15 @@ _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1,5 +1,5 @@ -import py, os, sys -from pypy.rpython.lltypesystem import lltype, llmemory, rclass +import py, sys +from pypy.rpython.lltypesystem import lltype, rclass from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import debug_start, debug_stop, debug_print @@ -15,13 +15,12 @@ from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE, \ - ABORT_BAD_LOOP, ABORT_FORCE_QUASIIMMUT + ABORT_FORCE_QUASIIMMUT from pypy.jit.metainterp.jitexc import JitException, get_llexception -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize -from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr, MissingLiveness -from pypy.jit.codewriter import heaptracker, longlong -from pypy.jit.metainterp.optimizeopt.util import args_dict_box, args_dict +from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr +from pypy.jit.codewriter import heaptracker +from pypy.jit.metainterp.optimizeopt.util import args_dict_box from pypy.jit.metainterp.optimize import RetraceLoop # ____________________________________________________________ @@ -885,7 +884,7 @@ any_operation = len(self.metainterp.history.operations) > 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jdindex, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -932,8 +931,10 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jd_index, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation + loc = jitdriver_sd.warmstate.get_location_str(greenkey) + debug_print(loc) args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @@ -2136,7 +2137,6 @@ def vrefs_after_residual_call(self): vrefinfo = self.staticdata.virtualref_info for i in range(0, len(self.virtualref_boxes), 2): - virtualbox = self.virtualref_boxes[i] vrefbox = self.virtualref_boxes[i+1] vref = vrefbox.getref_base() if vrefinfo.tracing_after_residual_call(vref): diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -2,10 +2,12 @@ from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr +from pypy.rpython import annlowlevel from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert @@ -82,6 +84,13 @@ ('nums', lltype.Array(rffi.SHORT))) NUMBERINGP.TO.become(NUMBERING) +PENDINGFIELDSTRUCT = lltype.Struct('PendingField', + ('lldescr', annlowlevel.base_ptr_lltype()), + ('num', rffi.SHORT), + ('fieldnum', rffi.SHORT), + ('itemindex', rffi.INT)) +PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) + TAGMASK = 3 def tag(value, tagbits): @@ -329,7 +338,7 @@ value = values[box] value.get_args_for_fail(self) - for _, box, fieldbox in pending_setfields: + for _, box, fieldbox, _ in pending_setfields: self.register_box(box) self.register_box(fieldbox) value = values[fieldbox] @@ -405,13 +414,25 @@ return False def _add_pending_fields(self, pending_setfields): - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) if pending_setfields: - rd_pendingfields = [] - for descr, box, fieldbox in pending_setfields: + n = len(pending_setfields) + rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) + for i in range(n): + descr, box, fieldbox, itemindex = pending_setfields[i] + lldescr = annlowlevel.cast_instance_to_base_ptr(descr) num = self._gettagged(box) fieldnum = self._gettagged(fieldbox) - rd_pendingfields.append((descr, num, fieldnum)) + # the index is limited to 2147483647 (64-bit machines only) + if itemindex > 2147483647: + from pypy.jit.metainterp import compile + compile.giveup() + itemindex = rffi.cast(rffi.INT, itemindex) + # + rd_pendingfields[i].lldescr = lldescr + rd_pendingfields[i].num = num + rd_pendingfields[i].fieldnum = fieldnum + rd_pendingfields[i].itemindex= itemindex self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): @@ -727,10 +748,28 @@ self.virtuals_cache = [self.virtual_default] * len(virtuals) def _prepare_pendingfields(self, pendingfields): - if pendingfields is not None: - for descr, num, fieldnum in pendingfields: + if pendingfields: + for i in range(len(pendingfields)): + lldescr = pendingfields[i].lldescr + num = pendingfields[i].num + fieldnum = pendingfields[i].fieldnum + itemindex= pendingfields[i].itemindex + descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, + lldescr) struct = self.decode_ref(num) - self.setfield(descr, struct, fieldnum) + itemindex = rffi.cast(lltype.Signed, itemindex) + if itemindex < 0: + self.setfield(descr, struct, fieldnum) + else: + self.setarrayitem(descr, struct, itemindex, fieldnum) + + def setarrayitem(self, arraydescr, array, index, fieldnum): + if arraydescr.is_array_of_pointers(): + self.setarrayitem_ref(arraydescr, array, index, fieldnum) + elif arraydescr.is_array_of_floats(): + self.setarrayitem_float(arraydescr, array, index, fieldnum) + else: + self.setarrayitem_int(arraydescr, array, index, fieldnum) def _prepare_next_section(self, info): # Use info.enumerate_vars(), normally dispatching to @@ -903,15 +942,15 @@ structbox, fieldbox) def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, INT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT) def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, REF) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF) def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) - def setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): + def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): itembox = self.decode_box(fieldnum, kind) self.metainterp.execute_and_record(rop.SETARRAYITEM_GC, arraydescr, arraybox, diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1677,6 +1677,8 @@ res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) self.check_loop_count(9) + self.check_loops(getarrayitem_gc=8, everywhere=True) + py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) def test_multiple_specialied_versions_bridge(self): @@ -2296,6 +2298,21 @@ res = self.meta_interp(f, [1]) assert res == f(1) + def test_remove_array_operations(self): + myjitdriver = JitDriver(greens = [], reds = ['a']) + class W_Int: + def __init__(self, intvalue): + self.intvalue = intvalue + def f(x): + a = [W_Int(x)] + while a[0].intvalue > 0: + myjitdriver.jit_merge_point(a=a) + a[0] = W_Int(a[0].intvalue - 3) + return a[0].intvalue + res = self.meta_interp(f, [100]) + assert res == -2 + #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -49,7 +49,7 @@ x = l[n] l = [3] * 100 l[3] = x - l[3] = x + 1 + l[4] = x + 1 n -= 1 return l[0] diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py --- a/pypy/jit/metainterp/test/test_resume.py +++ b/pypy/jit/metainterp/test/test_resume.py @@ -1238,7 +1238,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, values, 0) assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)]) + modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s, -1)]) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume @@ -1259,6 +1259,106 @@ assert len(expected) == len(trace) assert demo55.next == demo66 +def test_virtual_adder_pending_fields_and_arrayitems(): + class Storage(object): + pass + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier._add_pending_fields([]) + assert not storage.rd_pendingfields + # + class FieldDescr(object): + pass + field_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061)} + modifier._add_pending_fields([(field_a, 42, 61, -1)]) + pf = storage.rd_pendingfields + assert len(pf) == 1 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is field_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + # + array_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061), + 62: rffi.cast(rffi.SHORT, 1062), + 63: rffi.cast(rffi.SHORT, 1063)} + modifier._add_pending_fields([(array_a, 42, 61, 0), + (array_a, 42, 62, 2147483647)]) + pf = storage.rd_pendingfields + assert len(pf) == 2 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[1].num) == 1042 + assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 + assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + # + from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole + py.test.raises(SwitchToBlackhole, modifier._add_pending_fields, + [(array_a, 42, 63, 2147483648)]) + +def test_resume_reader_fields_and_arrayitems(): + class ResumeReader(AbstractResumeDataReader): + def __init__(self, got=None, got_array=None): + self.got = got + self.got_array = got_array + def setfield(self, descr, struct, fieldnum): + assert lltype.typeOf(struct) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got.append((descr, struct, fieldnum)) + def setarrayitem(self, arraydescr, array, index, fieldnum): + assert lltype.typeOf(array) is lltype.Signed + assert lltype.typeOf(index) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got_array.append((arraydescr, array, index, fieldnum)) + def decode_ref(self, num): + return rffi.cast(lltype.Signed, num) * 100 + got = [] + pf = lltype.nullptr(PENDINGFIELDSP.TO) + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [] + # + class FieldDescr(AbstractDescr): + pass + field_a = FieldDescr() + field_b = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 2) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) + pf[0].itemindex = rffi.cast(rffi.INT, -1) + pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) + pf[1].num = rffi.cast(rffi.SHORT, 2042) + pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) + pf[1].itemindex = rffi.cast(rffi.INT, -1) + got = [] + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] + # + array_a = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 1) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) + pf[0].itemindex = rffi.cast(rffi.INT, 123) + got_array = [] + ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + assert got_array == [(array_a, 104200, 123, 1063)] + def test_invalidation_needed(): class options: diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py --- a/pypy/jit/metainterp/virtualref.py +++ b/pypy/jit/metainterp/virtualref.py @@ -1,5 +1,5 @@ from pypy.rpython.rmodel import inputconst, log -from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass +from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.jit.metainterp import history from pypy.jit.codewriter import heaptracker from pypy.rlib.jit import InvalidVirtualRef diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -1,6 +1,5 @@ import sys, py -from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr -from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.annlowlevel import llhelper, MixLevelHelperAnnotator,\ cast_base_ptr_to_instance, hlstr from pypy.annotation import model as annmodel @@ -10,16 +9,12 @@ from pypy.objspace.flow.model import checkgraph, Link, copygraph from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import r_uint, intmask -from pypy.rlib.debug import debug_print, fatalerror -from pypy.rlib.debug import debug_start, debug_stop -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.translator.simplify import get_funcobj, get_functype +from pypy.rlib.debug import fatalerror +from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function from pypy.jit.metainterp import history, pyjitpl, gc, memmgr -from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp -from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper +from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.jitdriver import JitDriverStaticData @@ -297,9 +292,6 @@ self.stats = stats if translate_support_code: self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper) - annhelper = self.annhelper - else: - annhelper = None cpu = CPUClass(self.translator.rtyper, self.stats, self.opt, translate_support_code, gcdescr=self.gcdescr) self.cpu = cpu @@ -440,7 +432,6 @@ maybe_enter_jit._always_inline_ = True jd._maybe_enter_jit_fn = maybe_enter_jit - num_green_args = jd.num_green_args def maybe_enter_from_start(*args): maybe_compile_and_run(state.increment_function_threshold, *args) maybe_enter_from_start._always_inline_ = True @@ -553,7 +544,6 @@ self.rewrite_can_enter_jit(jd, sublist) def rewrite_can_enter_jit(self, jd, can_enter_jits): - FUNC = jd._JIT_ENTER_FUNCTYPE FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -1,7 +1,7 @@ import sys, weakref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi from pypy.rpython.ootypesystem import ootype -from pypy.rpython.annlowlevel import hlstr, llstr, cast_base_ptr_to_instance +from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance from pypy.rpython.annlowlevel import cast_object_to_ptr from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict from pypy.rlib.rarithmetic import intmask @@ -502,7 +502,6 @@ if hasattr(self, 'set_future_values'): return self.set_future_values - warmrunnerdesc = self.warmrunnerdesc jitdriver_sd = self.jitdriver_sd cpu = self.cpu vinfo = jitdriver_sd.virtualizable_info @@ -518,7 +517,6 @@ # if vinfo is not None: i0 = len(jitdriver_sd._red_args_types) - num_green_args = jitdriver_sd.num_green_args index_of_virtualizable = jitdriver_sd.index_of_virtualizable vable_static_fields = unrolling_iterable( zip(vinfo.static_extra_types, vinfo.static_fields)) diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -32,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -294,7 +294,7 @@ break new_frame = space.createframe(code, w_func.w_func_globals, w_func.closure) - new_frame.fastlocals_w[0] = w_item + new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) return result_w diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -3,6 +3,14 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.imp.importing import get_pyc_magic + +class BuildersModule(MixedModule): + appleveldefs = {} + + interpleveldefs = { + "UnicodeBuilder": "interp_builders.W_UnicodeBuilder", + } + class Module(MixedModule): appleveldefs = { } @@ -19,6 +27,10 @@ 'lookup_special' : 'interp_magic.lookup_special', } + submodules = { + "builders": BuildersModule, + } + def setup_after_space_initialization(self): """NOT_RPYTHON""" if not self.space.config.translating: diff --git a/pypy/module/__pypy__/interp_builders.py b/pypy/module/__pypy__/interp_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_builders.py @@ -0,0 +1,50 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef +from pypy.rlib.rstring import UnicodeBuilder + + +class W_UnicodeBuilder(Wrappable): + def __init__(self, space, size): + if size == -1: + self.builder = UnicodeBuilder() + else: + self.builder = UnicodeBuilder(size) + self.done = False + + def _check_done(self, space): + if self.done: + raise OperationError(space.w_ValueError, space.wrap("Can't operate on a done builder")) + + @unwrap_spec(size=int) + def descr__new__(space, w_subtype, size=-1): + return W_UnicodeBuilder(space, size) + + @unwrap_spec(s=unicode) + def descr_append(self, space, s): + self._check_done(space) + self.builder.append(s) + + @unwrap_spec(s=unicode, start=int, end=int) + def descr_append_slice(self, space, s, start, end): + self._check_done(space) + if not 0 <= start <= end <= len(s): + raise OperationError(space.w_ValueError, space.wrap("bad start/stop")) + self.builder.append_slice(s, start, end) + + def descr_build(self, space): + self._check_done(space) + w_s = space.wrap(self.builder.build()) + self.done = True + return w_s + + +W_UnicodeBuilder.typedef = TypeDef("UnicodeBuilder", + __new__ = interp2app(W_UnicodeBuilder.descr__new__.im_func), + + append = interp2app(W_UnicodeBuilder.descr_append), + append_slice = interp2app(W_UnicodeBuilder.descr_append_slice), + build = interp2app(W_UnicodeBuilder.descr_build), +) +W_UnicodeBuilder.typedef.acceptable_as_base_class = False \ No newline at end of file diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,15 +1,19 @@ from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.error import OperationError -from pypy.rlib import debug +from pypy.rlib import debug, jit + + at jit.dont_look_inside @unwrap_spec(category=str) def debug_start(space, category): debug.debug_start(category) + at jit.dont_look_inside def debug_print(space, args_w): parts = [space.str_w(space.str(w_item)) for w_item in args_w] debug.debug_print(' '.join(parts)) + at jit.dont_look_inside @unwrap_spec(category=str) def debug_stop(space, category): debug.debug_stop(category) diff --git a/pypy/module/__pypy__/test/test_builders.py b/pypy/module/__pypy__/test/test_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_builders.py @@ -0,0 +1,34 @@ +from pypy.conftest import gettestobjspace + + +class AppTestBuilders(object): + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['__pypy__']) + + def test_simple(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append(u"abc") + b.append(u"123") + b.append(u"1") + s = b.build() + assert s == u"abc1231" + raises(ValueError, b.build) + raises(ValueError, b.append, u"123") + + def test_preallocate(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder(10) + b.append(u"abc") + b.append(u"123") + s = b.build() + assert s == u"abc123" + + def test_append_slice(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append_slice(u"abcdefgh", 2, 5) + raises(ValueError, b.append_slice, u"1", 2, 1) + s = b.build() + assert s == "cde" + raises(ValueError, b.append_slice, u"abc", 1, 2) \ No newline at end of file diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -900,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/_stackless/test/test_greenlet.py b/pypy/module/_stackless/test/test_greenlet.py --- a/pypy/module/_stackless/test/test_greenlet.py +++ b/pypy/module/_stackless/test/test_greenlet.py @@ -72,6 +72,23 @@ g1 = greenlet(f) raises(ValueError, g2.switch) + + def test_exc_info_save_restore(self): + from _stackless import greenlet + import sys + def f(): + try: + raise ValueError('fun') + except: + exc_info = sys.exc_info() + greenlet(h).switch() + assert exc_info == sys.exc_info() + + def h(): + assert sys.exc_info() == (None, None, None) + + greenlet(f).switch() + def test_exception(self): from _stackless import greenlet import sys diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -39,6 +39,7 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject +import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject import pypy.module.cpyext.longobject @@ -64,6 +65,7 @@ import pypy.module.cpyext.memoryobject import pypy.module.cpyext.codecs import pypy.module.cpyext.pyfile +import pypy.module.cpyext.pystrtod # now that all rffi_platform.Struct types are registered, configure them api.configure_types() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -562,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/pystrtod.py @@ -0,0 +1,68 @@ +import errno +from pypy.interpreter.error import OperationError +from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.pyobject import PyObject +from pypy.rlib import rdtoa +from pypy.rlib import rfloat +from pypy.rlib import rposix +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi + + + at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +def PyOS_string_to_double(space, s, endptr, w_overflow_exception): + """Convert a string s to a double, raising a Python + exception on failure. The set of accepted strings corresponds to + the set of strings accepted by Python's float() constructor, + except that s must not have leading or trailing whitespace. + The conversion is independent of the current locale. + + If endptr is NULL, convert the whole string. Raise + ValueError and return -1.0 if the string is not a valid + representation of a floating-point number. + + If endptr is not NULL, convert as much of the string as + possible and set *endptr to point to the first unconverted + character. If no initial segment of the string is the valid + representation of a floating-point number, set *endptr to point + to the beginning of the string, raise ValueError, and return + -1.0. + + If s represents a value that is too large to store in a float + (for example, "1e500" is such a string on many platforms) then + if overflow_exception is NULL return Py_HUGE_VAL (with + an appropriate sign) and don't set any exception. Otherwise, + overflow_exception must point to a Python exception object; + raise that exception and return -1.0. In both cases, set + *endptr to point to the first character after the converted value. + + If any other error occurs during the conversion (for example an + out-of-memory error), set the appropriate Python exception and + return -1.0. + """ + user_endptr = True + try: + if not endptr: + endptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + user_endptr = False + result = rdtoa.dg_strtod(s, endptr) + endpos = (rffi.cast(rffi.LONG, endptr[0]) - + rffi.cast(rffi.LONG, s)) + if endpos == 0 or (not user_endptr and not endptr[0][0] == '\0'): + raise OperationError( + space.w_ValueError, + space.wrap('invalid input at position %s' % endpos)) + if rposix.get_errno() == errno.ERANGE: + rposix.set_errno(0) + if w_overflow_exception is None: + if result > 0: + return rfloat.INFINITY + else: + return -rfloat.INFINITY + else: + raise OperationError(w_overflow_exception, + space.wrap('value too large')) + return result + finally: + if not user_endptr: + lltype.free(endptr, flavor='raw') diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/setobject.py @@ -0,0 +1,46 @@ +from pypy.interpreter.error import OperationError +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, + build_type_checkers) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, + borrow_from, make_ref, from_ref) +from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall +from pypy.objspace.std.setobject import W_SetObject, newset +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject + + +PySet_Check, PySet_CheckExact = build_type_checkers("Set") + + + at cpython_api([PyObject], PyObject) +def PySet_New(space, w_iterable): + if w_iterable is None: + return space.call_function(space.w_set) + else: + return space.call_function(space.w_set, w_iterable) + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Add(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'add', w_obj) + return 0 + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Discard(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'discard', w_obj) + return 0 + + + at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +def PySet_GET_SIZE(space, w_s): + return space.int_w(space.len(w_s)) + + at cpython_api([PyObject], Py_ssize_t, error=-1) +def PySet_Size(space, ref): + if not PySet_Check(space, ref): + raise OperationError(space.w_TypeError, + space.wrap("expected set object")) + return PySet_GET_SIZE(space, ref) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -480,39 +480,6 @@ """Create a new Python complex number object from a C Py_complex value.""" raise NotImplementedError - at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) -def PyOS_string_to_double(space, s, endptr, overflow_exception): - """Convert a string s to a double, raising a Python - exception on failure. The set of accepted strings corresponds to - the set of strings accepted by Python's float() constructor, - except that s must not have leading or trailing whitespace. - The conversion is independent of the current locale. - - If endptr is NULL, convert the whole string. Raise - ValueError and return -1.0 if the string is not a valid - representation of a floating-point number. - - If endptr is not NULL, convert as much of the string as - possible and set *endptr to point to the first unconverted - character. If no initial segment of the string is the valid - representation of a floating-point number, set *endptr to point - to the beginning of the string, raise ValueError, and return - -1.0. - - If s represents a value that is too large to store in a float - (for example, "1e500" is such a string on many platforms) then - if overflow_exception is NULL return Py_HUGE_VAL (with - an appropriate sign) and don't set any exception. Otherwise, - overflow_exception must point to a Python exception object; - raise that exception and return -1.0. In both cases, set - *endptr to point to the first character after the converted value. - - If any other error occurs during the conversion (for example an - out-of-memory error), set the appropriate Python exception and - return -1.0. - """ - raise NotImplementedError - @cpython_api([rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_strtod(space, nptr, endptr): """Convert a string to a double. This function behaves like the Standard C diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -0,0 +1,93 @@ +import math + +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype + + +class TestPyOS_string_to_double(BaseApiTest): + + def test_simple_float(self, api): + s = rffi.str2charp('0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == 0.4 + rffi.free_charp(s) + + def test_empty_string(self, api): + s = rffi.str2charp('') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_bad_string(self, api): + s = rffi.str2charp(' 0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_overflow_pos(self, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r > 0 + rffi.free_charp(s) + + def test_overflow_neg(self, api): + s = rffi.str2charp('-1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r < 0 + rffi.free_charp(s) + + def test_overflow_exc(self, space, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, space.w_ValueError) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_endptr_number(self, api): + s = rffi.str2charp('0.4') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_tail(self, api): + s = rffi.str2charp('0.4 foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_no_conversion(self, api): + s = rffi.str2charp('foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == -1.0 + raises(ValueError) + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + api.PyErr_Clear() + rffi.free_charp(s) + lltype.free(endp, flavor='raw') diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_setobject.py @@ -0,0 +1,29 @@ +import py + +from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace + + +class TestTupleObject(BaseApiTest): + def test_setobj(self, space, api): + assert not api.PySet_Check(space.w_None) + assert api.PySet_Add(space.w_None, space.w_None) == -1 + api.PyErr_Clear() + w_set = space.call_function(space.w_set) + space.call_method(w_set, 'update', space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + assert api.PySet_GET_SIZE(w_set) == 4 + raises(TypeError, api.PySet_Size(space.newlist([]))) + api.PyErr_Clear() + + def test_set_add_discard(self, space, api): + w_set = api.PySet_New(None) + assert api.PySet_Size(w_set) == 0 + w_set = api.PySet_New(space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + api.PySet_Add(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 5 + api.PySet_Discard(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 4 diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -367,3 +367,14 @@ data, len(u), lltype.nullptr(rffi.CCHARP.TO)) rffi.free_wcharp(data) + def test_format(self, space, api): + w_format = space.wrap(u'hi %s') + w_args = space.wrap((u'test',)) + w_formated = api.PyUnicode_Format(w_format, w_args) + assert space.unwrap(w_formated) == space.unwrap(space.mod(w_format, w_args)) + + def test_join(self, space, api): + w_sep = space.wrap(u'') + w_seq = space.wrap([u'a', u'b']) + w_joined = api.PyUnicode_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == u'ab' diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,6 +7,7 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) + assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -523,3 +523,11 @@ copies sizeof(Py_UNICODE) * length bytes from source to target""" for i in range(0, length): target[i] = source[i] + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Format(space, w_format, w_args): + return space.mod(w_format, w_args) + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -21,6 +21,10 @@ """Return the referenced object from a weak reference. If the referent is no longer live, returns None. This function returns a borrowed reference. """ + return PyWeakref_GET_OBJECT(space, w_ref) + + at cpython_api([PyObject], PyObject) +def PyWeakref_GET_OBJECT(space, w_ref): return borrow_from(w_ref, space.call_function(w_ref)) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/math/__init__.py b/pypy/module/math/__init__.py --- a/pypy/module/math/__init__.py +++ b/pypy/module/math/__init__.py @@ -4,6 +4,7 @@ class Module(MixedModule): appleveldefs = { + 'factorial' : 'app_math.factorial' } interpleveldefs = { @@ -40,7 +41,6 @@ 'isnan' : 'interp_math.isnan', 'trunc' : 'interp_math.trunc', 'fsum' : 'interp_math.fsum', - 'factorial' : 'interp_math.factorial', 'asinh' : 'interp_math.asinh', 'acosh' : 'interp_math.acosh', 'atanh' : 'interp_math.atanh', diff --git a/pypy/module/math/app_math.py b/pypy/module/math/app_math.py new file mode 100644 --- /dev/null +++ b/pypy/module/math/app_math.py @@ -0,0 +1,13 @@ +def factorial(x): + """Find x!.""" + if isinstance(x, float): + fl = int(x) + if fl != x: + raise ValueError("float arguments must be integral") + x = fl + if x < 0: + raise ValueError("x must be >= 0") + res = 1 + for i in range(1, x + 1): + res *= i + return res diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -373,22 +373,6 @@ hi = v return space.wrap(hi) -def factorial(space, w_x): - """Find x!.""" - if space.isinstance_w(w_x, space.w_float): - fl = space.float_w(w_x) - if math.floor(fl) != fl: - raise OperationError(space.w_ValueError, - space.wrap("float arguments must be integral")) - w_x = space.long(w_x) - x = space.int_w(w_x) - if x < 0: - raise OperationError(space.w_ValueError, space.wrap("x must be >= 0")) - w_res = space.wrap(1) - for i in range(1, x + 1): - w_res = space.mul(w_res, space.wrap(i)) - return w_res - def log1p(space, w_x): """Find log(x + 1).""" return math1(space, rfloat.log1p, w_x) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -16,6 +16,7 @@ 'absolute': 'interp_ufuncs.absolute', 'copysign': 'interp_ufuncs.copysign', 'exp': 'interp_ufuncs.exp', + 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', 'negative': 'interp_ufuncs.negative', diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -62,6 +62,10 @@ return 1.0 / value @ufunc +def floor(value): + return math.floor(value) + + at ufunc def sign(value): if value == 0.0: return 0.0 diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -67,6 +67,15 @@ for i in range(4): assert b[i] == reference[i] + def test_floor(self): + from numpy import array, floor + + reference = [-2.0, -1.0, 0.0, 1.0, 1.0] + a = array([-1.4, -1.0, 0.0, 1.0, 1.4]) + b = floor(a) + for i in range(5): + assert b[i] == reference[i] + def test_copysign(self): from numpy import array, copysign diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -21,8 +21,7 @@ from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes PyFrame._virtualizable2_ = ['last_instr', 'pycode', - 'valuestackdepth', 'valuestack_w[*]', - 'fastlocals_w[*]', + 'valuestackdepth', 'locals_stack_w[*]', 'last_exception', 'lastblock', 'is_being_profiled', diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,8 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof', '_weakref']: + 'posix', '_socket', '_sre', '_lsprof', '_weakref', + '__pypy__']: return True return False diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -58,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -46,7 +46,7 @@ guard_no_overflow(descr=) i18 = int_add(i7, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) """) def test_array_intimg(self): @@ -83,7 +83,7 @@ setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) i28 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -187,7 +187,7 @@ guard_no_overflow(descr=) i18 = force_token() --TICK-- - jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) """) def test_default_and_kw(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -115,7 +115,6 @@ # ---------------------- loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i8 = getfield_gc_pure(p5, descr=) i9 = int_lt(i8, i7) guard_true(i9, descr=.*) guard_not_invalidated(descr=.*) @@ -125,7 +124,7 @@ p20 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p20, i11, descr=) setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i7, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py --- a/pypy/module/pypyjit/test_pypy_c/test_intbound.py +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -97,7 +97,7 @@ guard_no_overflow(descr=...) i17 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) """) def test_intbound_sub_lt(self): @@ -149,7 +149,7 @@ guard_no_overflow(descr=...) i19 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) """) def test_intbound_addmul_ge(self): @@ -177,7 +177,7 @@ guard_no_overflow(descr=...) i21 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) """) def test_intbound_eq(self): @@ -209,7 +209,7 @@ guard_no_overflow(descr=...) i16 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) """) def test_intbound_mul(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -167,7 +167,7 @@ guard_false(i16, descr=) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) + setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, 146982464, descr=) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) @@ -179,7 +179,7 @@ i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -384,8 +384,9 @@ # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) - stack_items_w = self.crnt_frame.valuestack_w - for i in range(self.crnt_frame.valuestackdepth-1, -1, -1): + f = self.crnt_frame + stack_items_w = f.locals_stack_w + for i in range(f.valuestackdepth-1, f.nlocals-1, -1): w_v = stack_items_w[i] if isinstance(w_v, Constant): if w_v.value is oldvalue: diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py --- a/pypy/objspace/flow/framestate.py +++ b/pypy/objspace/flow/framestate.py @@ -10,7 +10,7 @@ def __init__(self, state): if isinstance(state, PyFrame): # getfastscope() can return real None, for undefined locals - data = state.getfastscope() + state.savevaluestack() + data = state.save_locals_stack() if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -36,11 +36,9 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): - fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) # Nones == undefined locals - frame.restorevaluestack(data[fastlocals:-2]) + frame.restore_locals_stack(data[:-2]) # Nones == undefined locals if data[-2] == Constant(None): assert data[-1] == Constant(None) frame.last_exception = None diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py --- a/pypy/objspace/flow/test/test_framestate.py +++ b/pypy/objspace/flow/test/test_framestate.py @@ -25,7 +25,7 @@ dummy = Constant(None) #dummy.dummy = True arg_list = ([Variable() for i in range(formalargcount)] + - [dummy] * (len(frame.fastlocals_w) - formalargcount)) + [dummy] * (frame.nlocals - formalargcount)) frame.setfastscope(arg_list) return frame @@ -42,7 +42,7 @@ def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1 != fs2 @@ -55,7 +55,7 @@ def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general @@ -63,7 +63,7 @@ def test_restore_frame(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs1.restoreframe(frame) assert fs1 == FrameState(frame) @@ -82,25 +82,26 @@ def test_getoutputargs(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable - # fastlocals_w[-1] -> fastlocals_w[-1] is Constant(None) - assert outputargs == [frame.fastlocals_w[0], Constant(None)] + # locals_w[n-1] -> locals_w[n-1] is Constant(None) + assert outputargs == [frame.locals_stack_w[0], Constant(None)] def test_union_different_constants(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(42) + frame.locals_stack_w[frame.nlocals-1] = Constant(42) fs2 = FrameState(frame) fs3 = fs1.union(fs2) fs3.restoreframe(frame) - assert isinstance(frame.fastlocals_w[-1], Variable) # generalized + assert isinstance(frame.locals_stack_w[frame.nlocals-1], Variable) + # ^^^ generalized def test_union_spectag(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(SpecTag()) + frame.locals_stack_w[frame.nlocals-1] = Constant(SpecTag()) fs2 = FrameState(frame) assert fs1.union(fs2) is None # UnionError diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,13 +1,14 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.debug import mark_dict_non_null def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -59,7 +60,8 @@ def initialize_as_rdict(self): assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) + self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) return self.r_dict_content @@ -308,6 +310,7 @@ def __init__(self, space): self.space = space self.content = {} + mark_dict_non_null(self.content) def impl_setitem(self, w_key, w_value): space = self.space @@ -317,6 +320,7 @@ self._as_rdict().impl_fallback_setitem(w_key, w_value) def impl_setitem_str(self, key, w_value): + assert key is not None self.content[key] = w_value def impl_setdefault(self, w_key, w_default): @@ -342,6 +346,7 @@ return len(self.content) def impl_getitem_str(self, key): + assert key is not None return self.content.get(key, None) def impl_getitem(self, w_key): diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -311,6 +311,10 @@ classofinstance=classofinstance, strdict=strdict) + def newset(self): + from pypy.objspace.std.setobject import newset + return W_SetObject(self, newset(self)) + def newslice(self, w_start, w_end, w_step): return W_SliceObject(w_start, w_end, w_step) diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -50,6 +50,10 @@ u = self.space.wrap(set('simsalabim')) assert self.space.eq_w(s,u) + def test_space_newset(self): + s = self.space.newset() + assert self.space.str_w(self.space.repr(s)) == 'set([])' + class AppTestAppSetTest: def test_subtype(self): class subset(set):pass diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -272,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -151,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -7,6 +7,7 @@ from pypy.rlib.objectmodel import hlinvoke from pypy.rlib import objectmodel from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -40,7 +41,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -59,6 +60,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -95,6 +97,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -204,7 +213,7 @@ if dictobj is None: return lltype.nullptr(self.DICT) if not isinstance(dictobj, (dict, objectmodel.r_dict)): - raise TyperError("expected a dict: %r" % (dictobj,)) + raise TypeError("expected a dict: %r" % (dictobj,)) try: key = Constant(dictobj) return self.dict_cache[key] @@ -645,12 +654,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted +from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -57,6 +57,8 @@ llmemory.itemoffsetof(TP.chars, 0) + llmemory.sizeof(CHAR_TP) * item) + # It'd be nice to be able to look inside this function. + @dont_look_inside @enforceargs(None, None, int, int, int) def copy_string_contents(src, dst, srcstart, dststart, length): assert srcstart >= 0 diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,23 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + class Cls(self.AddressStack): + def append(self2, addr): + assert addr not in self2.tolist() + self.AddressStack.append(self2, addr) + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +637,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +655,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +698,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +789,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +882,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +922,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,11 +933,11 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded self.remember_young_pointer_from_array2(addr_array, index) else: @@ -943,20 +955,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -980,16 +995,18 @@ # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,9 +1019,7 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return @@ -1016,7 +1031,7 @@ addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True @@ -1026,9 +1041,6 @@ # xxx trying it out for the JIT: a 3-arguments version of the above def remember_young_pointer_from_array3(addr_array, index, newvalue): - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") objhdr = self.header(addr_array) # # a single check for the common case of neither GCFLAG_HAS_CARDS @@ -1044,8 +1056,8 @@ else: # case with cards. # - # If the newly written address does not actually point to the - # nursery, leave now. + # If the newly written address does not actually point to a + # young object, leave now. if not self.appears_to_be_young(newvalue): return # @@ -1056,46 +1068,53 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + \ - (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True assert self.card_page_indices > 0 self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1103,15 +1122,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1119,6 +1159,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1135,20 +1191,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1181,7 +1245,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1189,7 +1253,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1205,11 +1269,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1245,19 +1309,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1296,7 +1371,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1343,11 +1430,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,78 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag + # + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert not res # there might be young ptrs, let ll_arraycopy to find them + + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -884,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,7 +598,6 @@ res = self.interpret(func, []) assert res in [5263, 6352] - class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): def func(i): @@ -860,6 +859,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -121,6 +121,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -220,6 +223,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -168,7 +168,7 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' From noreply at buildbot.pypy.org Fri Jul 1 16:12:19 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 16:12:19 +0200 (CEST) Subject: [pypy-commit] pypy default: rename purefunction into elidable (but keep an purefunction around as an alias, some external projects like prolog still use it). Message-ID: <20110701141219.2DE688293A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45229:382f399e74b3 Date: 2011-07-01 16:19 +0200 http://bitbucket.org/pypy/pypy/changeset/382f399e74b3/ Log: rename purefunction into elidable (but keep an purefunction around as an alias, some external projects like prolog still use it). diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -92,7 +92,7 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -847,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1233,7 +1233,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,10 +304,10 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): n = hint(n, promote=True) return externfn(n, n+1) @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, hint, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -32,7 +32,7 @@ return self._getcell_makenew(key) return self.content.get(key, None) - @jit.purefunction + @jit.elidable def _getcell_makenew(self, key): return self.content.setdefault(key, ModuleCell()) diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import hint, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -360,7 +360,7 @@ w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -820,7 +820,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,24 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +# keep "purefunction" for not breaking external projects, deprecated +purefunction = elidable + def hint(x, **kwds): """ Hint for the JIT @@ -60,13 +63,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +88,9 @@ return result return decorator +# keep "purefunction_promote" for not breaking external projects, deprecated +purefunction_promote = elidable_promote + def oopspec(spec): def decorator(func): func.oopspec = spec diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -74,7 +74,7 @@ raise KeyError @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,8 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - # it's pure but it does not look like it - @purefunction + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -342,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -352,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -370,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -387,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -428,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -451,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -471,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -487,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -504,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -516,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -527,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -595,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -718,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -816,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -831,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -842,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError From noreply at buildbot.pypy.org Fri Jul 1 16:15:58 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 1 Jul 2011 16:15:58 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: merge up to d05a7437ee20 Message-ID: <20110701141558.3D68D8293A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45230:04530d3561b1 Date: 2011-07-01 15:16 +0200 http://bitbucket.org/pypy/pypy/changeset/04530d3561b1/ Log: merge up to d05a7437ee20 diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -61,7 +61,7 @@ usemodules = '', skip=None): self.basename = basename - self._usemodules = usemodules.split() + self._usemodules = usemodules.split() + ['signal'] self._compiler = compiler self.core = core self.skip = skip @@ -154,17 +154,17 @@ RegrTest('test_cmd.py'), RegrTest('test_cmd_line_script.py'), RegrTest('test_codeccallbacks.py', core=True), - RegrTest('test_codecencodings_cn.py', skip="encodings not available"), - RegrTest('test_codecencodings_hk.py', skip="encodings not available"), - RegrTest('test_codecencodings_jp.py', skip="encodings not available"), - RegrTest('test_codecencodings_kr.py', skip="encodings not available"), - RegrTest('test_codecencodings_tw.py', skip="encodings not available"), + RegrTest('test_codecencodings_cn.py'), + RegrTest('test_codecencodings_hk.py'), + RegrTest('test_codecencodings_jp.py'), + RegrTest('test_codecencodings_kr.py'), + RegrTest('test_codecencodings_tw.py'), - RegrTest('test_codecmaps_cn.py', skip="encodings not available"), - RegrTest('test_codecmaps_hk.py', skip="encodings not available"), - RegrTest('test_codecmaps_jp.py', skip="encodings not available"), - RegrTest('test_codecmaps_kr.py', skip="encodings not available"), - RegrTest('test_codecmaps_tw.py', skip="encodings not available"), + RegrTest('test_codecmaps_cn.py'), + RegrTest('test_codecmaps_hk.py'), + RegrTest('test_codecmaps_jp.py'), + RegrTest('test_codecmaps_kr.py'), + RegrTest('test_codecmaps_tw.py'), RegrTest('test_codecs.py', core=True), RegrTest('test_codeop.py', core=True), RegrTest('test_coercion.py', core=True), @@ -314,7 +314,7 @@ RegrTest('test_mmap.py'), RegrTest('test_module.py', core=True), RegrTest('test_modulefinder.py'), - RegrTest('test_multibytecodec.py', skip="unsupported codecs"), + RegrTest('test_multibytecodec.py'), RegrTest('test_multibytecodec_support.py', skip="not a test"), RegrTest('test_multifile.py'), RegrTest('test_multiprocessing.py', skip='FIXME leaves subprocesses'), @@ -400,7 +400,7 @@ RegrTest('test_softspace.py', core=True), RegrTest('test_sort.py', core=True), - RegrTest('test_ssl.py'), + RegrTest('test_ssl.py', usemodules='_ssl _socket select'), RegrTest('test_str.py', core=True), RegrTest('test_strftime.py'), diff --git a/lib-python/modified-2.7/site.py b/lib-python/modified-2.7/site.py --- a/lib-python/modified-2.7/site.py +++ b/lib-python/modified-2.7/site.py @@ -454,10 +454,10 @@ __builtin__.copyright = _Printer("copyright", sys.copyright) __builtin__.credits = _Printer( "credits", - "PyPy is maintained by the PyPy developers: http://codespeak.net/pypy") + "PyPy is maintained by the PyPy developers: http://pypy.org/") __builtin__.license = _Printer( "license", - "See http://codespeak.net/svn/pypy/dist/LICENSE") + "See https://bitbucket.org/pypy/pypy/src/default/LICENSE") diff --git a/lib-python/modified-2.7/test/test_codecs.py b/lib-python/modified-2.7/test/test_codecs.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_codecs.py +++ /dev/null @@ -1,1615 +0,0 @@ -from test import test_support -import unittest -import codecs -import sys, StringIO, _testcapi - -class Queue(object): - """ - queue: write bytes at one end, read bytes from the other end - """ - def __init__(self): - self._buffer = "" - - def write(self, chars): - self._buffer += chars - - def read(self, size=-1): - if size<0: - s = self._buffer - self._buffer = "" - return s - else: - s = self._buffer[:size] - self._buffer = self._buffer[size:] - return s - -class ReadTest(unittest.TestCase): - def check_partial(self, input, partialresults): - # get a StreamReader for the encoding and feed the bytestring version - # of input to the reader byte by byte. Read everything available from - # the StreamReader and check that the results equal the appropriate - # entries from partialresults. - q = Queue() - r = codecs.getreader(self.encoding)(q) - result = u"" - for (c, partialresult) in zip(input.encode(self.encoding), partialresults): - q.write(c) - result += r.read() - self.assertEqual(result, partialresult) - # check that there's nothing left in the buffers - self.assertEqual(r.read(), u"") - self.assertEqual(r.bytebuffer, "") - self.assertEqual(r.charbuffer, u"") - - # do the check again, this time using a incremental decoder - d = codecs.getincrementaldecoder(self.encoding)() - result = u"" - for (c, partialresult) in zip(input.encode(self.encoding), partialresults): - result += d.decode(c) - self.assertEqual(result, partialresult) - # check that there's nothing left in the buffers - self.assertEqual(d.decode("", True), u"") - self.assertEqual(d.buffer, "") - - # Check whether the reset method works properly - d.reset() - result = u"" - for (c, partialresult) in zip(input.encode(self.encoding), partialresults): - result += d.decode(c) - self.assertEqual(result, partialresult) - # check that there's nothing left in the buffers - self.assertEqual(d.decode("", True), u"") - self.assertEqual(d.buffer, "") - - # check iterdecode() - encoded = input.encode(self.encoding) - self.assertEqual( - input, - u"".join(codecs.iterdecode(encoded, self.encoding)) - ) - - def test_readline(self): - def getreader(input): - stream = StringIO.StringIO(input.encode(self.encoding)) - return codecs.getreader(self.encoding)(stream) - - def readalllines(input, keepends=True, size=None): - reader = getreader(input) - lines = [] - while True: - line = reader.readline(size=size, keepends=keepends) - if not line: - break - lines.append(line) - return "|".join(lines) - - s = u"foo\nbar\r\nbaz\rspam\u2028eggs" - sexpected = u"foo\n|bar\r\n|baz\r|spam\u2028|eggs" - sexpectednoends = u"foo|bar|baz|spam|eggs" - self.assertEqual(readalllines(s, True), sexpected) - self.assertEqual(readalllines(s, False), sexpectednoends) - self.assertEqual(readalllines(s, True, 10), sexpected) - self.assertEqual(readalllines(s, False, 10), sexpectednoends) - - # Test long lines (multiple calls to read() in readline()) - vw = [] - vwo = [] - for (i, lineend) in enumerate(u"\n \r\n \r \u2028".split()): - vw.append((i*200)*u"\3042" + lineend) - vwo.append((i*200)*u"\3042") - self.assertEqual(readalllines("".join(vw), True), "".join(vw)) - self.assertEqual(readalllines("".join(vw), False),"".join(vwo)) - - # Test lines where the first read might end with \r, so the - # reader has to look ahead whether this is a lone \r or a \r\n - for size in xrange(80): - for lineend in u"\n \r\n \r \u2028".split(): - s = 10*(size*u"a" + lineend + u"xxx\n") - reader = getreader(s) - for i in xrange(10): - self.assertEqual( - reader.readline(keepends=True), - size*u"a" + lineend, - ) - reader = getreader(s) - for i in xrange(10): - self.assertEqual( - reader.readline(keepends=False), - size*u"a", - ) - - def test_bug1175396(self): - s = [ - '<%!--===================================================\r\n', - ' BLOG index page: show recent articles,\r\n', - ' today\'s articles, or articles of a specific date.\r\n', - '========================================================--%>\r\n', - '<%@inputencoding="ISO-8859-1"%>\r\n', - '<%@pagetemplate=TEMPLATE.y%>\r\n', - '<%@import=import frog.util, frog%>\r\n', - '<%@import=import frog.objects%>\r\n', - '<%@import=from frog.storageerrors import StorageError%>\r\n', - '<%\r\n', - '\r\n', - 'import logging\r\n', - 'log=logging.getLogger("Snakelets.logger")\r\n', - '\r\n', - '\r\n', - 'user=self.SessionCtx.user\r\n', - 'storageEngine=self.SessionCtx.storageEngine\r\n', - '\r\n', - '\r\n', - 'def readArticlesFromDate(date, count=None):\r\n', - ' entryids=storageEngine.listBlogEntries(date)\r\n', - ' entryids.reverse() # descending\r\n', - ' if count:\r\n', - ' entryids=entryids[:count]\r\n', - ' try:\r\n', - ' return [ frog.objects.BlogEntry.load(storageEngine, date, Id) for Id in entryids ]\r\n', - ' except StorageError,x:\r\n', - ' log.error("Error loading articles: "+str(x))\r\n', - ' self.abort("cannot load articles")\r\n', - '\r\n', - 'showdate=None\r\n', - '\r\n', - 'arg=self.Request.getArg()\r\n', - 'if arg=="today":\r\n', - ' #-------------------- TODAY\'S ARTICLES\r\n', - ' self.write("

Today\'s articles

")\r\n', - ' showdate = frog.util.isodatestr() \r\n', - ' entries = readArticlesFromDate(showdate)\r\n', - 'elif arg=="active":\r\n', - ' #-------------------- ACTIVE ARTICLES redirect\r\n', - ' self.Yredirect("active.y")\r\n', - 'elif arg=="login":\r\n', - ' #-------------------- LOGIN PAGE redirect\r\n', - ' self.Yredirect("login.y")\r\n', - 'elif arg=="date":\r\n', - ' #-------------------- ARTICLES OF A SPECIFIC DATE\r\n', - ' showdate = self.Request.getParameter("date")\r\n', - ' self.write("

Articles written on %s

"% frog.util.mediumdatestr(showdate))\r\n', - ' entries = readArticlesFromDate(showdate)\r\n', - 'else:\r\n', - ' #-------------------- RECENT ARTICLES\r\n', - ' self.write("

Recent articles

")\r\n', - ' dates=storageEngine.listBlogEntryDates()\r\n', - ' if dates:\r\n', - ' entries=[]\r\n', - ' SHOWAMOUNT=10\r\n', - ' for showdate in dates:\r\n', - ' entries.extend( readArticlesFromDate(showdate, SHOWAMOUNT-len(entries)) )\r\n', - ' if len(entries)>=SHOWAMOUNT:\r\n', - ' break\r\n', - ' \r\n', - ] - stream = StringIO.StringIO("".join(s).encode(self.encoding)) - reader = codecs.getreader(self.encoding)(stream) - for (i, line) in enumerate(reader): - self.assertEqual(line, s[i]) - - def test_readlinequeue(self): - q = Queue() - writer = codecs.getwriter(self.encoding)(q) - reader = codecs.getreader(self.encoding)(q) - - # No lineends - writer.write(u"foo\r") - self.assertEqual(reader.readline(keepends=False), u"foo") - writer.write(u"\nbar\r") - self.assertEqual(reader.readline(keepends=False), u"") - self.assertEqual(reader.readline(keepends=False), u"bar") - writer.write(u"baz") - self.assertEqual(reader.readline(keepends=False), u"baz") - self.assertEqual(reader.readline(keepends=False), u"") - - # Lineends - writer.write(u"foo\r") - self.assertEqual(reader.readline(keepends=True), u"foo\r") - writer.write(u"\nbar\r") - self.assertEqual(reader.readline(keepends=True), u"\n") - self.assertEqual(reader.readline(keepends=True), u"bar\r") - writer.write(u"baz") - self.assertEqual(reader.readline(keepends=True), u"baz") - self.assertEqual(reader.readline(keepends=True), u"") - writer.write(u"foo\r\n") - self.assertEqual(reader.readline(keepends=True), u"foo\r\n") - - def test_bug1098990_a(self): - s1 = u"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\r\n" - s2 = u"offending line: ladfj askldfj klasdj fskla dfzaskdj fasklfj laskd fjasklfzzzzaa%whereisthis!!!\r\n" - s3 = u"next line.\r\n" - - s = (s1+s2+s3).encode(self.encoding) - stream = StringIO.StringIO(s) - reader = codecs.getreader(self.encoding)(stream) - self.assertEqual(reader.readline(), s1) - self.assertEqual(reader.readline(), s2) - self.assertEqual(reader.readline(), s3) - self.assertEqual(reader.readline(), u"") - - def test_bug1098990_b(self): - s1 = u"aaaaaaaaaaaaaaaaaaaaaaaa\r\n" - s2 = u"bbbbbbbbbbbbbbbbbbbbbbbb\r\n" - s3 = u"stillokay:bbbbxx\r\n" - s4 = u"broken!!!!badbad\r\n" - s5 = u"againokay.\r\n" - - s = (s1+s2+s3+s4+s5).encode(self.encoding) - stream = StringIO.StringIO(s) - reader = codecs.getreader(self.encoding)(stream) - self.assertEqual(reader.readline(), s1) - self.assertEqual(reader.readline(), s2) - self.assertEqual(reader.readline(), s3) - self.assertEqual(reader.readline(), s4) - self.assertEqual(reader.readline(), s5) - self.assertEqual(reader.readline(), u"") - -class UTF32Test(ReadTest): - encoding = "utf-32" - - spamle = ('\xff\xfe\x00\x00' - 's\x00\x00\x00p\x00\x00\x00a\x00\x00\x00m\x00\x00\x00' - 's\x00\x00\x00p\x00\x00\x00a\x00\x00\x00m\x00\x00\x00') - spambe = ('\x00\x00\xfe\xff' - '\x00\x00\x00s\x00\x00\x00p\x00\x00\x00a\x00\x00\x00m' - '\x00\x00\x00s\x00\x00\x00p\x00\x00\x00a\x00\x00\x00m') - - def test_only_one_bom(self): - _,_,reader,writer = codecs.lookup(self.encoding) - # encode some stream - s = StringIO.StringIO() - f = writer(s) - f.write(u"spam") - f.write(u"spam") - d = s.getvalue() - # check whether there is exactly one BOM in it - self.assertTrue(d == self.spamle or d == self.spambe) - # try to read it back - s = StringIO.StringIO(d) - f = reader(s) - self.assertEqual(f.read(), u"spamspam") - - def test_badbom(self): - s = StringIO.StringIO(4*"\xff") - f = codecs.getreader(self.encoding)(s) - self.assertRaises(UnicodeError, f.read) - - s = StringIO.StringIO(8*"\xff") - f = codecs.getreader(self.encoding)(s) - self.assertRaises(UnicodeError, f.read) - - def test_partial(self): - self.check_partial( - u"\x00\xff\u0100\uffff", - [ - u"", # first byte of BOM read - u"", # second byte of BOM read - u"", # third byte of BOM read - u"", # fourth byte of BOM read => byteorder known - u"", - u"", - u"", - u"\x00", - u"\x00", - u"\x00", - u"\x00", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100\uffff", - ] - ) - - def test_handlers(self): - self.assertEqual((u'\ufffd', 1), - codecs.utf_32_decode('\x01', 'replace', True)) - self.assertEqual((u'', 1), - codecs.utf_32_decode('\x01', 'ignore', True)) - - def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_32_decode, - "\xff", "strict", True) - - def test_issue8941(self): - # Issue #8941: insufficient result allocation when decoding into - # surrogate pairs on UCS-2 builds. - encoded_le = '\xff\xfe\x00\x00' + '\x00\x00\x01\x00' * 1024 - self.assertEqual(u'\U00010000' * 1024, - codecs.utf_32_decode(encoded_le)[0]) - encoded_be = '\x00\x00\xfe\xff' + '\x00\x01\x00\x00' * 1024 - self.assertEqual(u'\U00010000' * 1024, - codecs.utf_32_decode(encoded_be)[0]) - -class UTF32LETest(ReadTest): - encoding = "utf-32-le" - - def test_partial(self): - self.check_partial( - u"\x00\xff\u0100\uffff", - [ - u"", - u"", - u"", - u"\x00", - u"\x00", - u"\x00", - u"\x00", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100\uffff", - ] - ) - - def test_simple(self): - self.assertEqual(u"\U00010203".encode(self.encoding), "\x03\x02\x01\x00") - - def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_32_le_decode, - "\xff", "strict", True) - - def test_issue8941(self): - # Issue #8941: insufficient result allocation when decoding into - # surrogate pairs on UCS-2 builds. - encoded = '\x00\x00\x01\x00' * 1024 - self.assertEqual(u'\U00010000' * 1024, - codecs.utf_32_le_decode(encoded)[0]) - -class UTF32BETest(ReadTest): - encoding = "utf-32-be" - - def test_partial(self): - self.check_partial( - u"\x00\xff\u0100\uffff", - [ - u"", - u"", - u"", - u"\x00", - u"\x00", - u"\x00", - u"\x00", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100\uffff", - ] - ) - - def test_simple(self): - self.assertEqual(u"\U00010203".encode(self.encoding), "\x00\x01\x02\x03") - - def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_32_be_decode, - "\xff", "strict", True) - - def test_issue8941(self): - # Issue #8941: insufficient result allocation when decoding into - # surrogate pairs on UCS-2 builds. - encoded = '\x00\x01\x00\x00' * 1024 - self.assertEqual(u'\U00010000' * 1024, - codecs.utf_32_be_decode(encoded)[0]) - - -class UTF16Test(ReadTest): - encoding = "utf-16" - - spamle = '\xff\xfes\x00p\x00a\x00m\x00s\x00p\x00a\x00m\x00' - spambe = '\xfe\xff\x00s\x00p\x00a\x00m\x00s\x00p\x00a\x00m' - - def test_only_one_bom(self): - _,_,reader,writer = codecs.lookup(self.encoding) - # encode some stream - s = StringIO.StringIO() - f = writer(s) - f.write(u"spam") - f.write(u"spam") - d = s.getvalue() - # check whether there is exactly one BOM in it - self.assertTrue(d == self.spamle or d == self.spambe) - # try to read it back - s = StringIO.StringIO(d) - f = reader(s) - self.assertEqual(f.read(), u"spamspam") - - def test_badbom(self): - s = StringIO.StringIO("\xff\xff") - f = codecs.getreader(self.encoding)(s) - self.assertRaises(UnicodeError, f.read) - - s = StringIO.StringIO("\xff\xff\xff\xff") - f = codecs.getreader(self.encoding)(s) - self.assertRaises(UnicodeError, f.read) - - def test_partial(self): - self.check_partial( - u"\x00\xff\u0100\uffff", - [ - u"", # first byte of BOM read - u"", # second byte of BOM read => byteorder known - u"", - u"\x00", - u"\x00", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100\uffff", - ] - ) - - def test_handlers(self): - self.assertEqual((u'\ufffd', 1), - codecs.utf_16_decode('\x01', 'replace', True)) - self.assertEqual((u'', 1), - codecs.utf_16_decode('\x01', 'ignore', True)) - - def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_decode, "\xff", "strict", True) - - def test_bug691291(self): - # Files are always opened in binary mode, even if no binary mode was - # specified. This means that no automatic conversion of '\n' is done - # on reading and writing. - s1 = u'Hello\r\nworld\r\n' - - s = s1.encode(self.encoding) - try: - with open(test_support.TESTFN, 'wb') as fp: - fp.write(s) - with codecs.open(test_support.TESTFN, 'U', encoding=self.encoding) as reader: - self.assertEqual(reader.read(), s1) - finally: - test_support.unlink(test_support.TESTFN) - -class UTF16LETest(ReadTest): - encoding = "utf-16-le" - - def test_partial(self): - self.check_partial( - u"\x00\xff\u0100\uffff", - [ - u"", - u"\x00", - u"\x00", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100\uffff", - ] - ) - - def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, "\xff", "strict", True) - -class UTF16BETest(ReadTest): - encoding = "utf-16-be" - - def test_partial(self): - self.check_partial( - u"\x00\xff\u0100\uffff", - [ - u"", - u"\x00", - u"\x00", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff\u0100", - u"\x00\xff\u0100", - u"\x00\xff\u0100\uffff", - ] - ) - - def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, "\xff", "strict", True) - -class UTF8Test(ReadTest): - encoding = "utf-8" - - def test_partial(self): - self.check_partial( - u"\x00\xff\u07ff\u0800\uffff", - [ - u"\x00", - u"\x00", - u"\x00\xff", - u"\x00\xff", - u"\x00\xff\u07ff", - u"\x00\xff\u07ff", - u"\x00\xff\u07ff", - u"\x00\xff\u07ff\u0800", - u"\x00\xff\u07ff\u0800", - u"\x00\xff\u07ff\u0800", - u"\x00\xff\u07ff\u0800\uffff", - ] - ) - -class UTF7Test(ReadTest): - encoding = "utf-7" - - def test_partial(self): - self.check_partial( - u"a+-b", - [ - u"a", - u"a", - u"a+", - u"a+-", - u"a+-b", - ] - ) - -class UTF16ExTest(unittest.TestCase): - - def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_ex_decode, "\xff", "strict", 0, True) - - def test_bad_args(self): - self.assertRaises(TypeError, codecs.utf_16_ex_decode) - -class ReadBufferTest(unittest.TestCase): - - def test_array(self): - import array - self.assertEqual( - codecs.readbuffer_encode(array.array("c", "spam")), - ("spam", 4) - ) - - def test_empty(self): - self.assertEqual(codecs.readbuffer_encode(""), ("", 0)) - - def test_bad_args(self): - self.assertRaises(TypeError, codecs.readbuffer_encode) - self.assertRaises(TypeError, codecs.readbuffer_encode, 42) - -class CharBufferTest(unittest.TestCase): - - def test_string(self): - self.assertEqual(codecs.charbuffer_encode("spam"), ("spam", 4)) - - def test_empty(self): - self.assertEqual(codecs.charbuffer_encode(""), ("", 0)) - - def test_bad_args(self): - self.assertRaises(TypeError, codecs.charbuffer_encode) - self.assertRaises(TypeError, codecs.charbuffer_encode, 42) - -class UTF8SigTest(ReadTest): - encoding = "utf-8-sig" - - def test_partial(self): - self.check_partial( - u"\ufeff\x00\xff\u07ff\u0800\uffff", - [ - u"", - u"", - u"", # First BOM has been read and skipped - u"", - u"", - u"\ufeff", # Second BOM has been read and emitted - u"\ufeff\x00", # "\x00" read and emitted - u"\ufeff\x00", # First byte of encoded u"\xff" read - u"\ufeff\x00\xff", # Second byte of encoded u"\xff" read - u"\ufeff\x00\xff", # First byte of encoded u"\u07ff" read - u"\ufeff\x00\xff\u07ff", # Second byte of encoded u"\u07ff" read - u"\ufeff\x00\xff\u07ff", - u"\ufeff\x00\xff\u07ff", - u"\ufeff\x00\xff\u07ff\u0800", - u"\ufeff\x00\xff\u07ff\u0800", - u"\ufeff\x00\xff\u07ff\u0800", - u"\ufeff\x00\xff\u07ff\u0800\uffff", - ] - ) - - def test_bug1601501(self): - # SF bug #1601501: check that the codec works with a buffer - unicode("\xef\xbb\xbf", "utf-8-sig") - - def test_bom(self): - d = codecs.getincrementaldecoder("utf-8-sig")() - s = u"spam" - self.assertEqual(d.decode(s.encode("utf-8-sig")), s) - - def test_stream_bom(self): - unistring = u"ABC\u00A1\u2200XYZ" - bytestring = codecs.BOM_UTF8 + "ABC\xC2\xA1\xE2\x88\x80XYZ" - - reader = codecs.getreader("utf-8-sig") - for sizehint in [None] + range(1, 11) + \ - [64, 128, 256, 512, 1024]: - istream = reader(StringIO.StringIO(bytestring)) - ostream = StringIO.StringIO() - while 1: - if sizehint is not None: - data = istream.read(sizehint) - else: - data = istream.read() - - if not data: - break - ostream.write(data) - - got = ostream.getvalue() - self.assertEqual(got, unistring) - - def test_stream_bare(self): - unistring = u"ABC\u00A1\u2200XYZ" - bytestring = "ABC\xC2\xA1\xE2\x88\x80XYZ" - - reader = codecs.getreader("utf-8-sig") - for sizehint in [None] + range(1, 11) + \ - [64, 128, 256, 512, 1024]: - istream = reader(StringIO.StringIO(bytestring)) - ostream = StringIO.StringIO() - while 1: - if sizehint is not None: - data = istream.read(sizehint) - else: - data = istream.read() - - if not data: - break - ostream.write(data) - - got = ostream.getvalue() - self.assertEqual(got, unistring) - -class EscapeDecodeTest(unittest.TestCase): - def test_empty(self): - self.assertEqual(codecs.escape_decode(""), ("", 0)) - -class RecodingTest(unittest.TestCase): - def test_recoding(self): - f = StringIO.StringIO() - f2 = codecs.EncodedFile(f, "unicode_internal", "utf-8") - f2.write(u"a") - f2.close() - # Python used to crash on this at exit because of a refcount - # bug in _codecsmodule.c - -# From RFC 3492 -punycode_testcases = [ - # A Arabic (Egyptian): - (u"\u0644\u064A\u0647\u0645\u0627\u0628\u062A\u0643\u0644" - u"\u0645\u0648\u0634\u0639\u0631\u0628\u064A\u061F", - "egbpdaj6bu4bxfgehfvwxn"), - # B Chinese (simplified): - (u"\u4ED6\u4EEC\u4E3A\u4EC0\u4E48\u4E0D\u8BF4\u4E2D\u6587", - "ihqwcrb4cv8a8dqg056pqjye"), - # C Chinese (traditional): - (u"\u4ED6\u5011\u7232\u4EC0\u9EBD\u4E0D\u8AAA\u4E2D\u6587", - "ihqwctvzc91f659drss3x8bo0yb"), - # D Czech: Proprostnemluvesky - (u"\u0050\u0072\u006F\u010D\u0070\u0072\u006F\u0073\u0074" - u"\u011B\u006E\u0065\u006D\u006C\u0075\u0076\u00ED\u010D" - u"\u0065\u0073\u006B\u0079", - "Proprostnemluvesky-uyb24dma41a"), - # E Hebrew: - (u"\u05DC\u05DE\u05D4\u05D4\u05DD\u05E4\u05E9\u05D5\u05D8" - u"\u05DC\u05D0\u05DE\u05D3\u05D1\u05E8\u05D9\u05DD\u05E2" - u"\u05D1\u05E8\u05D9\u05EA", - "4dbcagdahymbxekheh6e0a7fei0b"), - # F Hindi (Devanagari): - (u"\u092F\u0939\u0932\u094B\u0917\u0939\u093F\u0928\u094D" - u"\u0926\u0940\u0915\u094D\u092F\u094B\u0902\u0928\u0939" - u"\u0940\u0902\u092C\u094B\u0932\u0938\u0915\u0924\u0947" - u"\u0939\u0948\u0902", - "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd"), - - #(G) Japanese (kanji and hiragana): - (u"\u306A\u305C\u307F\u3093\u306A\u65E5\u672C\u8A9E\u3092" - u"\u8A71\u3057\u3066\u304F\u308C\u306A\u3044\u306E\u304B", - "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa"), - - # (H) Korean (Hangul syllables): - (u"\uC138\uACC4\uC758\uBAA8\uB4E0\uC0AC\uB78C\uB4E4\uC774" - u"\uD55C\uAD6D\uC5B4\uB97C\uC774\uD574\uD55C\uB2E4\uBA74" - u"\uC5BC\uB9C8\uB098\uC88B\uC744\uAE4C", - "989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5j" - "psd879ccm6fea98c"), - - # (I) Russian (Cyrillic): - (u"\u043F\u043E\u0447\u0435\u043C\u0443\u0436\u0435\u043E" - u"\u043D\u0438\u043D\u0435\u0433\u043E\u0432\u043E\u0440" - u"\u044F\u0442\u043F\u043E\u0440\u0443\u0441\u0441\u043A" - u"\u0438", - "b1abfaaepdrnnbgefbaDotcwatmq2g4l"), - - # (J) Spanish: PorqunopuedensimplementehablarenEspaol - (u"\u0050\u006F\u0072\u0071\u0075\u00E9\u006E\u006F\u0070" - u"\u0075\u0065\u0064\u0065\u006E\u0073\u0069\u006D\u0070" - u"\u006C\u0065\u006D\u0065\u006E\u0074\u0065\u0068\u0061" - u"\u0062\u006C\u0061\u0072\u0065\u006E\u0045\u0073\u0070" - u"\u0061\u00F1\u006F\u006C", - "PorqunopuedensimplementehablarenEspaol-fmd56a"), - - # (K) Vietnamese: - # Tisaohkhngthch\ - # nitingVit - (u"\u0054\u1EA1\u0069\u0073\u0061\u006F\u0068\u1ECD\u006B" - u"\u0068\u00F4\u006E\u0067\u0074\u0068\u1EC3\u0063\u0068" - u"\u1EC9\u006E\u00F3\u0069\u0074\u0069\u1EBF\u006E\u0067" - u"\u0056\u0069\u1EC7\u0074", - "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g"), - - #(L) 3B - (u"\u0033\u5E74\u0042\u7D44\u91D1\u516B\u5148\u751F", - "3B-ww4c5e180e575a65lsy2b"), - - # (M) -with-SUPER-MONKEYS - (u"\u5B89\u5BA4\u5948\u7F8E\u6075\u002D\u0077\u0069\u0074" - u"\u0068\u002D\u0053\u0055\u0050\u0045\u0052\u002D\u004D" - u"\u004F\u004E\u004B\u0045\u0059\u0053", - "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n"), - - # (N) Hello-Another-Way- - (u"\u0048\u0065\u006C\u006C\u006F\u002D\u0041\u006E\u006F" - u"\u0074\u0068\u0065\u0072\u002D\u0057\u0061\u0079\u002D" - u"\u305D\u308C\u305E\u308C\u306E\u5834\u6240", - "Hello-Another-Way--fc4qua05auwb3674vfr0b"), - - # (O) 2 - (u"\u3072\u3068\u3064\u5C4B\u6839\u306E\u4E0B\u0032", - "2-u9tlzr9756bt3uc0v"), - - # (P) MajiKoi5 - (u"\u004D\u0061\u006A\u0069\u3067\u004B\u006F\u0069\u3059" - u"\u308B\u0035\u79D2\u524D", - "MajiKoi5-783gue6qz075azm5e"), - - # (Q) de - (u"\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", - "de-jg4avhby1noc0d"), - - # (R) - (u"\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067", - "d9juau41awczczp"), - - # (S) -> $1.00 <- - (u"\u002D\u003E\u0020\u0024\u0031\u002E\u0030\u0030\u0020" - u"\u003C\u002D", - "-> $1.00 <--") - ] - -for i in punycode_testcases: - if len(i)!=2: - print repr(i) - -class PunycodeTest(unittest.TestCase): - def test_encode(self): - for uni, puny in punycode_testcases: - # Need to convert both strings to lower case, since - # some of the extended encodings use upper case, but our - # code produces only lower case. Converting just puny to - # lower is also insufficient, since some of the input characters - # are upper case. - self.assertEqual(uni.encode("punycode").lower(), puny.lower()) - - def test_decode(self): - for uni, puny in punycode_testcases: - self.assertEqual(uni, puny.decode("punycode")) - -class UnicodeInternalTest(unittest.TestCase): - def test_bug1251300(self): - # Decoding with unicode_internal used to not correctly handle "code - # points" above 0x10ffff on UCS-4 builds. - if sys.maxunicode > 0xffff: - ok = [ - ("\x00\x10\xff\xff", u"\U0010ffff"), - ("\x00\x00\x01\x01", u"\U00000101"), - ("", u""), - ] - not_ok = [ - "\x7f\xff\xff\xff", - "\x80\x00\x00\x00", - "\x81\x00\x00\x00", - "\x00", - "\x00\x00\x00\x00\x00", - ] - for internal, uni in ok: - if sys.byteorder == "little": - internal = "".join(reversed(internal)) - self.assertEqual(uni, internal.decode("unicode_internal")) - for internal in not_ok: - if sys.byteorder == "little": - internal = "".join(reversed(internal)) - self.assertRaises(UnicodeDecodeError, internal.decode, - "unicode_internal") - - def test_decode_error_attributes(self): - if sys.maxunicode > 0xffff: - try: - "\x00\x00\x00\x00\x00\x11\x11\x00".decode("unicode_internal") - except UnicodeDecodeError, ex: - self.assertEqual("unicode_internal", ex.encoding) - self.assertEqual("\x00\x00\x00\x00\x00\x11\x11\x00", ex.object) - self.assertEqual(4, ex.start) - self.assertEqual(8, ex.end) - else: - self.fail() - - def test_decode_callback(self): - if sys.maxunicode > 0xffff: - codecs.register_error("UnicodeInternalTest", codecs.ignore_errors) - decoder = codecs.getdecoder("unicode_internal") - ab = u"ab".encode("unicode_internal") - ignored = decoder("%s\x22\x22\x22\x22%s" % (ab[:4], ab[4:]), - "UnicodeInternalTest") - self.assertEqual((u"ab", 12), ignored) - - def test_encode_length(self): - # Issue 3739 - encoder = codecs.getencoder("unicode_internal") - self.assertEqual(encoder(u"a")[1], 1) - self.assertEqual(encoder(u"\xe9\u0142")[1], 2) - - encoder = codecs.getencoder("string-escape") - self.assertEqual(encoder(r'\x00')[1], 4) - -# From http://www.gnu.org/software/libidn/draft-josefsson-idn-test-vectors.html -nameprep_tests = [ - # 3.1 Map to nothing. - ('foo\xc2\xad\xcd\x8f\xe1\xa0\x86\xe1\xa0\x8bbar' - '\xe2\x80\x8b\xe2\x81\xa0baz\xef\xb8\x80\xef\xb8\x88\xef' - '\xb8\x8f\xef\xbb\xbf', - 'foobarbaz'), - # 3.2 Case folding ASCII U+0043 U+0041 U+0046 U+0045. - ('CAFE', - 'cafe'), - # 3.3 Case folding 8bit U+00DF (german sharp s). - # The original test case is bogus; it says \xc3\xdf - ('\xc3\x9f', - 'ss'), - # 3.4 Case folding U+0130 (turkish capital I with dot). - ('\xc4\xb0', - 'i\xcc\x87'), - # 3.5 Case folding multibyte U+0143 U+037A. - ('\xc5\x83\xcd\xba', - '\xc5\x84 \xce\xb9'), - # 3.6 Case folding U+2121 U+33C6 U+1D7BB. - # XXX: skip this as it fails in UCS-2 mode - #('\xe2\x84\xa1\xe3\x8f\x86\xf0\x9d\x9e\xbb', - # 'telc\xe2\x88\x95kg\xcf\x83'), - (None, None), - # 3.7 Normalization of U+006a U+030c U+00A0 U+00AA. - ('j\xcc\x8c\xc2\xa0\xc2\xaa', - '\xc7\xb0 a'), - # 3.8 Case folding U+1FB7 and normalization. - ('\xe1\xbe\xb7', - '\xe1\xbe\xb6\xce\xb9'), - # 3.9 Self-reverting case folding U+01F0 and normalization. - # The original test case is bogus, it says `\xc7\xf0' - ('\xc7\xb0', - '\xc7\xb0'), - # 3.10 Self-reverting case folding U+0390 and normalization. - ('\xce\x90', - '\xce\x90'), - # 3.11 Self-reverting case folding U+03B0 and normalization. - ('\xce\xb0', - '\xce\xb0'), - # 3.12 Self-reverting case folding U+1E96 and normalization. - ('\xe1\xba\x96', - '\xe1\xba\x96'), - # 3.13 Self-reverting case folding U+1F56 and normalization. - ('\xe1\xbd\x96', - '\xe1\xbd\x96'), - # 3.14 ASCII space character U+0020. - (' ', - ' '), - # 3.15 Non-ASCII 8bit space character U+00A0. - ('\xc2\xa0', - ' '), - # 3.16 Non-ASCII multibyte space character U+1680. - ('\xe1\x9a\x80', - None), - # 3.17 Non-ASCII multibyte space character U+2000. - ('\xe2\x80\x80', - ' '), - # 3.18 Zero Width Space U+200b. - ('\xe2\x80\x8b', - ''), - # 3.19 Non-ASCII multibyte space character U+3000. - ('\xe3\x80\x80', - ' '), - # 3.20 ASCII control characters U+0010 U+007F. - ('\x10\x7f', - '\x10\x7f'), - # 3.21 Non-ASCII 8bit control character U+0085. - ('\xc2\x85', - None), - # 3.22 Non-ASCII multibyte control character U+180E. - ('\xe1\xa0\x8e', - None), - # 3.23 Zero Width No-Break Space U+FEFF. - ('\xef\xbb\xbf', - ''), - # 3.24 Non-ASCII control character U+1D175. - ('\xf0\x9d\x85\xb5', - None), - # 3.25 Plane 0 private use character U+F123. - ('\xef\x84\xa3', - None), - # 3.26 Plane 15 private use character U+F1234. - ('\xf3\xb1\x88\xb4', - None), - # 3.27 Plane 16 private use character U+10F234. - ('\xf4\x8f\x88\xb4', - None), - # 3.28 Non-character code point U+8FFFE. - ('\xf2\x8f\xbf\xbe', - None), - # 3.29 Non-character code point U+10FFFF. - ('\xf4\x8f\xbf\xbf', - None), - # 3.30 Surrogate code U+DF42. - ('\xed\xbd\x82', - None), - # 3.31 Non-plain text character U+FFFD. - ('\xef\xbf\xbd', - None), - # 3.32 Ideographic description character U+2FF5. - ('\xe2\xbf\xb5', - None), - # 3.33 Display property character U+0341. - ('\xcd\x81', - '\xcc\x81'), - # 3.34 Left-to-right mark U+200E. - ('\xe2\x80\x8e', - None), - # 3.35 Deprecated U+202A. - ('\xe2\x80\xaa', - None), - # 3.36 Language tagging character U+E0001. - ('\xf3\xa0\x80\x81', - None), - # 3.37 Language tagging character U+E0042. - ('\xf3\xa0\x81\x82', - None), - # 3.38 Bidi: RandALCat character U+05BE and LCat characters. - ('foo\xd6\xbebar', - None), - # 3.39 Bidi: RandALCat character U+FD50 and LCat characters. - ('foo\xef\xb5\x90bar', - None), - # 3.40 Bidi: RandALCat character U+FB38 and LCat characters. - ('foo\xef\xb9\xb6bar', - 'foo \xd9\x8ebar'), - # 3.41 Bidi: RandALCat without trailing RandALCat U+0627 U+0031. - ('\xd8\xa71', - None), - # 3.42 Bidi: RandALCat character U+0627 U+0031 U+0628. - ('\xd8\xa71\xd8\xa8', - '\xd8\xa71\xd8\xa8'), - # 3.43 Unassigned code point U+E0002. - # Skip this test as we allow unassigned - #('\xf3\xa0\x80\x82', - # None), - (None, None), - # 3.44 Larger test (shrinking). - # Original test case reads \xc3\xdf - ('X\xc2\xad\xc3\x9f\xc4\xb0\xe2\x84\xa1j\xcc\x8c\xc2\xa0\xc2' - '\xaa\xce\xb0\xe2\x80\x80', - 'xssi\xcc\x87tel\xc7\xb0 a\xce\xb0 '), - # 3.45 Larger test (expanding). - # Original test case reads \xc3\x9f - ('X\xc3\x9f\xe3\x8c\x96\xc4\xb0\xe2\x84\xa1\xe2\x92\x9f\xe3\x8c' - '\x80', - 'xss\xe3\x82\xad\xe3\x83\xad\xe3\x83\xa1\xe3\x83\xbc\xe3' - '\x83\x88\xe3\x83\xabi\xcc\x87tel\x28d\x29\xe3\x82' - '\xa2\xe3\x83\x91\xe3\x83\xbc\xe3\x83\x88') - ] - - -class NameprepTest(unittest.TestCase): - def test_nameprep(self): - from encodings.idna import nameprep - for pos, (orig, prepped) in enumerate(nameprep_tests): - if orig is None: - # Skipped - continue - # The Unicode strings are given in UTF-8 - orig = unicode(orig, "utf-8") - if prepped is None: - # Input contains prohibited characters - self.assertRaises(UnicodeError, nameprep, orig) - else: - prepped = unicode(prepped, "utf-8") - try: - self.assertEqual(nameprep(orig), prepped) - except Exception,e: - raise test_support.TestFailed("Test 3.%d: %s" % (pos+1, str(e))) - -class IDNACodecTest(unittest.TestCase): - def test_builtin_decode(self): - self.assertEqual(unicode("python.org", "idna"), u"python.org") - self.assertEqual(unicode("python.org.", "idna"), u"python.org.") - self.assertEqual(unicode("xn--pythn-mua.org", "idna"), u"pyth\xf6n.org") - self.assertEqual(unicode("xn--pythn-mua.org.", "idna"), u"pyth\xf6n.org.") - - def test_builtin_encode(self): - self.assertEqual(u"python.org".encode("idna"), "python.org") - self.assertEqual("python.org.".encode("idna"), "python.org.") - self.assertEqual(u"pyth\xf6n.org".encode("idna"), "xn--pythn-mua.org") - self.assertEqual(u"pyth\xf6n.org.".encode("idna"), "xn--pythn-mua.org.") - - def test_stream(self): - import StringIO - r = codecs.getreader("idna")(StringIO.StringIO("abc")) - r.read(3) - self.assertEqual(r.read(), u"") - - def test_incremental_decode(self): - self.assertEqual( - "".join(codecs.iterdecode("python.org", "idna")), - u"python.org" - ) - self.assertEqual( - "".join(codecs.iterdecode("python.org.", "idna")), - u"python.org." - ) - self.assertEqual( - "".join(codecs.iterdecode("xn--pythn-mua.org.", "idna")), - u"pyth\xf6n.org." - ) - self.assertEqual( - "".join(codecs.iterdecode("xn--pythn-mua.org.", "idna")), - u"pyth\xf6n.org." - ) - - decoder = codecs.getincrementaldecoder("idna")() - self.assertEqual(decoder.decode("xn--xam", ), u"") - self.assertEqual(decoder.decode("ple-9ta.o", ), u"\xe4xample.") - self.assertEqual(decoder.decode(u"rg"), u"") - self.assertEqual(decoder.decode(u"", True), u"org") - - decoder.reset() - self.assertEqual(decoder.decode("xn--xam", ), u"") - self.assertEqual(decoder.decode("ple-9ta.o", ), u"\xe4xample.") - self.assertEqual(decoder.decode("rg."), u"org.") - self.assertEqual(decoder.decode("", True), u"") - - def test_incremental_encode(self): - self.assertEqual( - "".join(codecs.iterencode(u"python.org", "idna")), - "python.org" - ) - self.assertEqual( - "".join(codecs.iterencode(u"python.org.", "idna")), - "python.org." - ) - self.assertEqual( - "".join(codecs.iterencode(u"pyth\xf6n.org.", "idna")), - "xn--pythn-mua.org." - ) - self.assertEqual( - "".join(codecs.iterencode(u"pyth\xf6n.org.", "idna")), - "xn--pythn-mua.org." - ) - - encoder = codecs.getincrementalencoder("idna")() - self.assertEqual(encoder.encode(u"\xe4x"), "") - self.assertEqual(encoder.encode(u"ample.org"), "xn--xample-9ta.") - self.assertEqual(encoder.encode(u"", True), "org") - - encoder.reset() - self.assertEqual(encoder.encode(u"\xe4x"), "") - self.assertEqual(encoder.encode(u"ample.org."), "xn--xample-9ta.org.") - self.assertEqual(encoder.encode(u"", True), "") - -class CodecsModuleTest(unittest.TestCase): - - def test_decode(self): - self.assertEqual(codecs.decode('\xe4\xf6\xfc', 'latin-1'), - u'\xe4\xf6\xfc') - self.assertRaises(TypeError, codecs.decode) - self.assertEqual(codecs.decode('abc'), u'abc') - self.assertRaises(UnicodeDecodeError, codecs.decode, '\xff', 'ascii') - - def test_encode(self): - self.assertEqual(codecs.encode(u'\xe4\xf6\xfc', 'latin-1'), - '\xe4\xf6\xfc') - self.assertRaises(TypeError, codecs.encode) - self.assertRaises(LookupError, codecs.encode, "foo", "__spam__") - self.assertEqual(codecs.encode(u'abc'), 'abc') - self.assertRaises(UnicodeEncodeError, codecs.encode, u'\xffff', 'ascii') - - def test_register(self): - self.assertRaises(TypeError, codecs.register) - self.assertRaises(TypeError, codecs.register, 42) - - def test_lookup(self): - self.assertRaises(TypeError, codecs.lookup) - self.assertRaises(LookupError, codecs.lookup, "__spam__") - self.assertRaises(LookupError, codecs.lookup, " ") - - def test_getencoder(self): - self.assertRaises(TypeError, codecs.getencoder) - self.assertRaises(LookupError, codecs.getencoder, "__spam__") - - def test_getdecoder(self): - self.assertRaises(TypeError, codecs.getdecoder) - self.assertRaises(LookupError, codecs.getdecoder, "__spam__") - - def test_getreader(self): - self.assertRaises(TypeError, codecs.getreader) - self.assertRaises(LookupError, codecs.getreader, "__spam__") - - def test_getwriter(self): - self.assertRaises(TypeError, codecs.getwriter) - self.assertRaises(LookupError, codecs.getwriter, "__spam__") - -class StreamReaderTest(unittest.TestCase): - - def setUp(self): - self.reader = codecs.getreader('utf-8') - self.stream = StringIO.StringIO('\xed\x95\x9c\n\xea\xb8\x80') - - def test_readlines(self): - f = self.reader(self.stream) - self.assertEqual(f.readlines(), [u'\ud55c\n', u'\uae00']) - -class EncodedFileTest(unittest.TestCase): - - def test_basic(self): - f = StringIO.StringIO('\xed\x95\x9c\n\xea\xb8\x80') - ef = codecs.EncodedFile(f, 'utf-16-le', 'utf-8') - self.assertEqual(ef.read(), '\\\xd5\n\x00\x00\xae') - - f = StringIO.StringIO() - ef = codecs.EncodedFile(f, 'utf-8', 'latin1') - ef.write('\xc3\xbc') - self.assertEqual(f.getvalue(), '\xfc') - -class Str2StrTest(unittest.TestCase): - - def test_read(self): - sin = "\x80".encode("base64_codec") - reader = codecs.getreader("base64_codec")(StringIO.StringIO(sin)) - sout = reader.read() - self.assertEqual(sout, "\x80") - self.assertIsInstance(sout, str) - - def test_readline(self): - sin = "\x80".encode("base64_codec") - reader = codecs.getreader("base64_codec")(StringIO.StringIO(sin)) - sout = reader.readline() - self.assertEqual(sout, "\x80") - self.assertIsInstance(sout, str) - -all_unicode_encodings = [ - "ascii", - "base64_codec", - ## "big5", - ## "big5hkscs", - "charmap", - "cp037", - "cp1006", - "cp1026", - "cp1140", - "cp1250", - "cp1251", - "cp1252", - "cp1253", - "cp1254", - "cp1255", - "cp1256", - "cp1257", - "cp1258", - "cp424", - "cp437", - "cp500", - "cp720", - "cp737", - "cp775", - "cp850", - "cp852", - "cp855", - "cp856", - "cp857", - "cp858", - "cp860", - "cp861", - "cp862", - "cp863", - "cp864", - "cp865", - "cp866", - "cp869", - "cp874", - "cp875", - ## "cp932", - ## "cp949", - ## "cp950", - ## "euc_jis_2004", - ## "euc_jisx0213", - ## "euc_jp", - ## "euc_kr", - ## "gb18030", - ## "gb2312", - ## "gbk", - "hex_codec", - "hp_roman8", - ## "hz", - "idna", - ## "iso2022_jp", - ## "iso2022_jp_1", - ## "iso2022_jp_2", - ## "iso2022_jp_2004", - ## "iso2022_jp_3", - ## "iso2022_jp_ext", - ## "iso2022_kr", - "iso8859_1", - "iso8859_10", - "iso8859_11", - "iso8859_13", - "iso8859_14", - "iso8859_15", - "iso8859_16", - "iso8859_2", - "iso8859_3", - "iso8859_4", - "iso8859_5", - "iso8859_6", - "iso8859_7", - "iso8859_8", - "iso8859_9", - ## "johab", - "koi8_r", - "koi8_u", - "latin_1", - "mac_cyrillic", - "mac_greek", - "mac_iceland", - "mac_latin2", - "mac_roman", - "mac_turkish", - "palmos", - "ptcp154", - "punycode", - "raw_unicode_escape", - "rot_13", - ## "shift_jis", - ## "shift_jis_2004", - ## "shift_jisx0213", - "tis_620", - "unicode_escape", - "unicode_internal", - "utf_16", - "utf_16_be", - "utf_16_le", - "utf_7", - "utf_8", -] - -if hasattr(codecs, "mbcs_encode"): - all_unicode_encodings.append("mbcs") - -# The following encodings work only with str, not unicode -all_string_encodings = [ - "quopri_codec", - "string_escape", - "uu_codec", -] - -# The following encoding is not tested, because it's not supposed -# to work: -# "undefined" - -# The following encodings don't work in stateful mode -broken_unicode_with_streams = [ - "base64_codec", - "hex_codec", - "punycode", - "unicode_internal" -] -broken_incremental_coders = broken_unicode_with_streams[:] - -# The following encodings only support "strict" mode -only_strict_mode = [ - "idna", - "zlib_codec", - "bz2_codec", -] - -try: - import bz2 -except ImportError: - pass -else: - all_unicode_encodings.append("bz2_codec") - broken_unicode_with_streams.append("bz2_codec") - -try: - import zlib -except ImportError: - pass -else: - all_unicode_encodings.append("zlib_codec") - broken_unicode_with_streams.append("zlib_codec") - -class BasicUnicodeTest(unittest.TestCase): - def test_basics(self): - s = u"abc123" # all codecs should be able to encode these - for encoding in all_unicode_encodings: - name = codecs.lookup(encoding).name - if encoding.endswith("_codec"): - name += "_codec" - elif encoding == "latin_1": - name = "latin_1" - self.assertEqual(encoding.replace("_", "-"), name.replace("_", "-")) - (bytes, size) = codecs.getencoder(encoding)(s) - self.assertEqual(size, len(s), "%r != %r (encoding=%r)" % (size, len(s), encoding)) - (chars, size) = codecs.getdecoder(encoding)(bytes) - self.assertEqual(chars, s, "%r != %r (encoding=%r)" % (chars, s, encoding)) - - if encoding not in broken_unicode_with_streams: - # check stream reader/writer - q = Queue() - writer = codecs.getwriter(encoding)(q) - encodedresult = "" - for c in s: - writer.write(c) - encodedresult += q.read() - q = Queue() - reader = codecs.getreader(encoding)(q) - decodedresult = u"" - for c in encodedresult: - q.write(c) - decodedresult += reader.read() - self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - - if encoding not in broken_incremental_coders: - # check incremental decoder/encoder (fetched via the Python - # and C API) and iterencode()/iterdecode() - try: - encoder = codecs.getincrementalencoder(encoding)() - cencoder = _testcapi.codec_incrementalencoder(encoding) - except LookupError: # no IncrementalEncoder - pass - else: - # check incremental decoder/encoder - encodedresult = "" - for c in s: - encodedresult += encoder.encode(c) - encodedresult += encoder.encode(u"", True) - decoder = codecs.getincrementaldecoder(encoding)() - decodedresult = u"" - for c in encodedresult: - decodedresult += decoder.decode(c) - decodedresult += decoder.decode("", True) - self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - - # check C API - encodedresult = "" - for c in s: - encodedresult += cencoder.encode(c) - encodedresult += cencoder.encode(u"", True) - cdecoder = _testcapi.codec_incrementaldecoder(encoding) - decodedresult = u"" - for c in encodedresult: - decodedresult += cdecoder.decode(c) - decodedresult += cdecoder.decode("", True) - self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - - # check iterencode()/iterdecode() - result = u"".join(codecs.iterdecode(codecs.iterencode(s, encoding), encoding)) - self.assertEqual(result, s, "%r != %r (encoding=%r)" % (result, s, encoding)) - - # check iterencode()/iterdecode() with empty string - result = u"".join(codecs.iterdecode(codecs.iterencode(u"", encoding), encoding)) - self.assertEqual(result, u"") - - if encoding not in only_strict_mode: - # check incremental decoder/encoder with errors argument - try: - encoder = codecs.getincrementalencoder(encoding)("ignore") - cencoder = _testcapi.codec_incrementalencoder(encoding, "ignore") - except LookupError: # no IncrementalEncoder - pass - else: - encodedresult = "".join(encoder.encode(c) for c in s) - decoder = codecs.getincrementaldecoder(encoding)("ignore") - decodedresult = u"".join(decoder.decode(c) for c in encodedresult) - self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - - encodedresult = "".join(cencoder.encode(c) for c in s) - cdecoder = _testcapi.codec_incrementaldecoder(encoding, "ignore") - decodedresult = u"".join(cdecoder.decode(c) for c in encodedresult) - self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - - def test_seek(self): - # all codecs should be able to encode these - s = u"%s\n%s\n" % (100*u"abc123", 100*u"def456") - for encoding in all_unicode_encodings: - if encoding == "idna": # FIXME: See SF bug #1163178 - continue - if encoding in broken_unicode_with_streams: - continue - reader = codecs.getreader(encoding)(StringIO.StringIO(s.encode(encoding))) - for t in xrange(5): - # Test that calling seek resets the internal codec state and buffers - reader.seek(0, 0) - line = reader.readline() - self.assertEqual(s[:len(line)], line) - - def test_bad_decode_args(self): - for encoding in all_unicode_encodings: - decoder = codecs.getdecoder(encoding) - self.assertRaises(TypeError, decoder) - if encoding not in ("idna", "punycode"): - self.assertRaises(TypeError, decoder, 42) - - def test_bad_encode_args(self): - for encoding in all_unicode_encodings: - encoder = codecs.getencoder(encoding) - self.assertRaises(TypeError, encoder) - - def test_encoding_map_type_initialized(self): - from encodings import cp1140 - # This used to crash, we are only verifying there's no crash. - table_type = type(cp1140.encoding_table) - self.assertEqual(table_type, table_type) - -class BasicStrTest(unittest.TestCase): - def test_basics(self): - s = "abc123" - for encoding in all_string_encodings: - (bytes, size) = codecs.getencoder(encoding)(s) - self.assertEqual(size, len(s)) - (chars, size) = codecs.getdecoder(encoding)(bytes) - self.assertEqual(chars, s, "%r != %r (encoding=%r)" % (chars, s, encoding)) - -class CharmapTest(unittest.TestCase): - def test_decode_with_string_map(self): - self.assertEqual( - codecs.charmap_decode("\x00\x01\x02", "strict", u"abc"), - (u"abc", 3) - ) - - self.assertEqual( - codecs.charmap_decode("\x00\x01\x02", "replace", u"ab"), - (u"ab\ufffd", 3) - ) - - self.assertEqual( - codecs.charmap_decode("\x00\x01\x02", "replace", u"ab\ufffe"), - (u"ab\ufffd", 3) - ) - - self.assertEqual( - codecs.charmap_decode("\x00\x01\x02", "ignore", u"ab"), - (u"ab", 3) - ) - - self.assertEqual( - codecs.charmap_decode("\x00\x01\x02", "ignore", u"ab\ufffe"), - (u"ab", 3) - ) - - allbytes = "".join(chr(i) for i in xrange(256)) - self.assertEqual( - codecs.charmap_decode(allbytes, "ignore", u""), - (u"", len(allbytes)) - ) - -class WithStmtTest(unittest.TestCase): - def test_encodedfile(self): - f = StringIO.StringIO("\xc3\xbc") - with codecs.EncodedFile(f, "latin-1", "utf-8") as ef: - self.assertEqual(ef.read(), "\xfc") - - def test_streamreaderwriter(self): - f = StringIO.StringIO("\xc3\xbc") - info = codecs.lookup("utf-8") - with codecs.StreamReaderWriter(f, info.streamreader, - info.streamwriter, 'strict') as srw: - self.assertEqual(srw.read(), u"\xfc") - - -class BomTest(unittest.TestCase): - def test_seek0(self): - data = u"1234567890" - tests = ("utf-16", - "utf-16-le", - "utf-16-be", - "utf-32", - "utf-32-le", - "utf-32-be") - for encoding in tests: - # Check if the BOM is written only once - with codecs.open(test_support.TESTFN, 'w+', encoding=encoding) as f: - f.write(data) - f.write(data) - f.seek(0) - self.assertEqual(f.read(), data * 2) - f.seek(0) - self.assertEqual(f.read(), data * 2) - - # Check that the BOM is written after a seek(0) - with codecs.open(test_support.TESTFN, 'w+', encoding=encoding) as f: - f.write(data[0]) - self.assertNotEqual(f.tell(), 0) - f.seek(0) - f.write(data) - f.seek(0) - self.assertEqual(f.read(), data) - - # (StreamWriter) Check that the BOM is written after a seek(0) - with codecs.open(test_support.TESTFN, 'w+', encoding=encoding) as f: - f.writer.write(data[0]) - self.assertNotEqual(f.writer.tell(), 0) - f.writer.seek(0) - f.writer.write(data) - f.seek(0) - self.assertEqual(f.read(), data) - - # Check that the BOM is not written after a seek() at a position - # different than the start - with codecs.open(test_support.TESTFN, 'w+', encoding=encoding) as f: - f.write(data) - f.seek(f.tell()) - f.write(data) - f.seek(0) - self.assertEqual(f.read(), data * 2) - - # (StreamWriter) Check that the BOM is not written after a seek() - # at a position different than the start - with codecs.open(test_support.TESTFN, 'w+', encoding=encoding) as f: - f.writer.write(data) - f.writer.seek(f.writer.tell()) - f.writer.write(data) - f.seek(0) - self.assertEqual(f.read(), data * 2) - - -def test_main(): - test_support.run_unittest( - UTF32Test, - UTF32LETest, - UTF32BETest, - UTF16Test, - UTF16LETest, - UTF16BETest, - UTF8Test, - UTF8SigTest, - UTF7Test, - UTF16ExTest, - ReadBufferTest, - CharBufferTest, - EscapeDecodeTest, - RecodingTest, - PunycodeTest, - UnicodeInternalTest, - NameprepTest, - IDNACodecTest, - CodecsModuleTest, - StreamReaderTest, - EncodedFileTest, - Str2StrTest, - BasicUnicodeTest, - BasicStrTest, - CharmapTest, - WithStmtTest, - BomTest, - ) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_ssl.py b/lib-python/modified-2.7/test/test_ssl.py --- a/lib-python/modified-2.7/test/test_ssl.py +++ b/lib-python/modified-2.7/test/test_ssl.py @@ -105,7 +105,6 @@ print "didn't raise TypeError" ssl.RAND_add("this is a random string", 75.0) - @test_support.impl_detail("obscure test") def test_parse_cert(self): # note that this uses an 'unofficial' function in _ssl.c, # provided solely for this test, to exercise the certificate @@ -840,6 +839,8 @@ c = socket.socket() c.connect((HOST, port)) listener_gone.wait() + # XXX why is it necessary? + test_support.gc_collect() try: ssl_sock = ssl.wrap_socket(c) except IOError: diff --git a/lib-python/2.7/uuid.py b/lib-python/modified-2.7/uuid.py copy from lib-python/2.7/uuid.py copy to lib-python/modified-2.7/uuid.py --- a/lib-python/2.7/uuid.py +++ b/lib-python/modified-2.7/uuid.py @@ -406,8 +406,12 @@ continue if hasattr(lib, 'uuid_generate_random'): _uuid_generate_random = lib.uuid_generate_random + _uuid_generate_random.argtypes = [ctypes.c_char * 16] + _uuid_generate_random.restype = None if hasattr(lib, 'uuid_generate_time'): _uuid_generate_time = lib.uuid_generate_time + _uuid_generate_time.argtypes = [ctypes.c_char * 16] + _uuid_generate_time.restype = None # The uuid_generate_* functions are broken on MacOS X 10.5, as noted # in issue #8621 the function generates the same sequence of values @@ -436,6 +440,9 @@ lib = None _UuidCreate = getattr(lib, 'UuidCreateSequential', getattr(lib, 'UuidCreate', None)) + if _UuidCreate is not None: + _UuidCreate.argtypes = [ctypes.c_char * 16] + _UuidCreate.restype = ctypes.c_int except: pass diff --git a/lib_pypy/_codecs_cn.py b/lib_pypy/_codecs_cn.py new file mode 100644 --- /dev/null +++ b/lib_pypy/_codecs_cn.py @@ -0,0 +1,7 @@ +# this getcodec() function supports any multibyte codec, although +# for compatibility with CPython it should only be used for the +# codecs from this module, i.e.: +# +# 'gb2312', 'gbk', 'gb18030', 'hz' + +from _multibytecodec import __getcodec as getcodec diff --git a/lib_pypy/_codecs_hk.py b/lib_pypy/_codecs_hk.py new file mode 100644 --- /dev/null +++ b/lib_pypy/_codecs_hk.py @@ -0,0 +1,7 @@ +# this getcodec() function supports any multibyte codec, although +# for compatibility with CPython it should only be used for the +# codecs from this module, i.e.: +# +# 'big5hkscs' + +from _multibytecodec import __getcodec as getcodec diff --git a/lib_pypy/_codecs_iso2022.py b/lib_pypy/_codecs_iso2022.py new file mode 100644 --- /dev/null +++ b/lib_pypy/_codecs_iso2022.py @@ -0,0 +1,8 @@ +# this getcodec() function supports any multibyte codec, although +# for compatibility with CPython it should only be used for the +# codecs from this module, i.e.: +# +# 'iso2022_kr', 'iso2022_jp', 'iso2022_jp_1', 'iso2022_jp_2', +# 'iso2022_jp_2004', 'iso2022_jp_3', 'iso2022_jp_ext' + +from _multibytecodec import __getcodec as getcodec diff --git a/lib_pypy/_codecs_jp.py b/lib_pypy/_codecs_jp.py new file mode 100644 --- /dev/null +++ b/lib_pypy/_codecs_jp.py @@ -0,0 +1,8 @@ +# this getcodec() function supports any multibyte codec, although +# for compatibility with CPython it should only be used for the +# codecs from this module, i.e.: +# +# 'shift_jis', 'cp932', 'euc_jp', 'shift_jis_2004', +# 'euc_jis_2004', 'euc_jisx0213', 'shift_jisx0213' + +from _multibytecodec import __getcodec as getcodec diff --git a/lib_pypy/_codecs_kr.py b/lib_pypy/_codecs_kr.py new file mode 100644 --- /dev/null +++ b/lib_pypy/_codecs_kr.py @@ -0,0 +1,7 @@ +# this getcodec() function supports any multibyte codec, although +# for compatibility with CPython it should only be used for the +# codecs from this module, i.e.: +# +# 'euc_kr', 'cp949', 'johab' + +from _multibytecodec import __getcodec as getcodec diff --git a/lib_pypy/_codecs_tw.py b/lib_pypy/_codecs_tw.py new file mode 100644 --- /dev/null +++ b/lib_pypy/_codecs_tw.py @@ -0,0 +1,7 @@ +# this getcodec() function supports any multibyte codec, although +# for compatibility with CPython it should only be used for the +# codecs from this module, i.e.: +# +# 'big5', 'cp950' + +from _multibytecodec import __getcodec as getcodec diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -180,9 +180,17 @@ sqlite.sqlite3_libversion.argtypes = [] sqlite.sqlite3_libversion.restype = c_char_p sqlite.sqlite3_open.argtypes = [c_char_p, c_void_p] +sqlite.sqlite3_open.restype = c_int sqlite.sqlite3_prepare_v2.argtypes = [c_void_p, c_char_p, c_int, c_void_p, POINTER(c_char_p)] +sqlite.sqlite3_prepare_v2.restype = c_int sqlite.sqlite3_column_decltype.argtypes = [c_void_p, c_int] sqlite.sqlite3_column_decltype.restype = c_char_p +sqlite.sqlite3_step.argtypes = [c_void_p] +sqlite.sqlite3_step.restype = c_int +sqlite.sqlite3_reset.argtypes = [c_void_p] +sqlite.sqlite3_reset.restype = c_int +sqlite.sqlite3_column_count.argtypes = [c_void_p] +sqlite.sqlite3_column_count.restype = c_int sqlite.sqlite3_result_blob.argtypes = [c_void_p, c_char_p, c_int, c_void_p] sqlite.sqlite3_result_int64.argtypes = [c_void_p, c_int64] @@ -491,7 +499,7 @@ return callback(text1, text2) c_collation_callback = COLLATION(collation_callback) - self._collations[name] = collation_callback + self._collations[name] = c_collation_callback ret = sqlite.sqlite3_create_collation(self.db, name, diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -33,7 +33,7 @@ "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", "_bisect", "binascii", "_multiprocessing", '_warnings', - "_collections"] + "_collections", "_multibytecodec"] )) translation_modules = default_modules.copy() diff --git a/pypy/config/support.py b/pypy/config/support.py --- a/pypy/config/support.py +++ b/pypy/config/support.py @@ -2,13 +2,15 @@ """ Some support code """ -import re, sys, os +import re, sys, os, subprocess def detect_number_of_processors(filename_or_file='/proc/cpuinfo'): - if sys.platform != 'linux2': - return 1 # implement me if os.environ.get('MAKEFLAGS'): return 1 # don't override MAKEFLAGS. This will call 'make' without any '-j' option + if sys.platform == 'darwin': + return darwin_get_cpu_count() + elif sys.platform != 'linux2': + return 1 # implement me try: if isinstance(filename_or_file, str): f = open(filename_or_file, "r") @@ -23,3 +25,12 @@ return count except: return 1 # we really don't want to explode here, at worst we have 1 + +def darwin_get_cpu_count(cmd = "/usr/sbin/sysctl hw.ncpu"): + try: + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + # 'hw.ncpu: 20' + count = proc.communicate()[0].rstrip()[8:] + return int(count) + except (OSError, ValueError): + return 1 diff --git a/pypy/config/test/test_support.py b/pypy/config/test/test_support.py --- a/pypy/config/test/test_support.py +++ b/pypy/config/test/test_support.py @@ -1,6 +1,6 @@ from cStringIO import StringIO -from pypy.config.support import detect_number_of_processors +from pypy.config import support import os, sys, py cpuinfo = """ @@ -39,15 +39,38 @@ assert varname == 'MAKEFLAGS' return self._value -def test_cpuinfo(): +def test_cpuinfo_linux(): if sys.platform != 'linux2': py.test.skip("linux only") saved = os.environ try: os.environ = FakeEnviron(None) - assert detect_number_of_processors(StringIO(cpuinfo)) == 3 - assert detect_number_of_processors('random crap that does not exist') == 1 + assert support.detect_number_of_processors(StringIO(cpuinfo)) == 3 + assert support.detect_number_of_processors('random crap that does not exist') == 1 os.environ = FakeEnviron('-j2') - assert detect_number_of_processors(StringIO(cpuinfo)) == 1 + assert support.detect_number_of_processors(StringIO(cpuinfo)) == 1 finally: os.environ = saved + +def test_cpuinfo_darwin(): + if sys.platform != 'darwin': + py.test.skip('mac only') + saved_func = support.darwin_get_cpu_count + saved = os.environ + def count(): + return 42 + try: + support.darwin_get_cpu_count = count + os.environ = FakeEnviron(None) + assert support.detect_number_of_processors() == 42 + os.environ = FakeEnviron('-j2') + assert support.detect_number_of_processors() == 1 + finally: + os.environ = saved + support.darwin_get_cpu_count = saved_func + +def test_darwin_get_cpu_count(): + if sys.platform != 'darwin': + py.test.skip('mac only') + assert support.darwin_get_cpu_count() > 0 # hopefully + assert support.darwin_get_cpu_count("false") == 1 diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -164,9 +164,6 @@ cmdline="--cflags"), StrOption("linkerflags", "Specify flags for the linker (C backend only)", cmdline="--ldflags"), - BoolOption("force_make", "Force execution of makefile instead of" - " calling platform", cmdline="--force-make", - default=False, negation=False), IntOption("make_jobs", "Specify -j argument to make for compilation" " (C backend only)", cmdline="--make-jobs", default=detect_number_of_processors()), diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -560,12 +560,6 @@ match an exception, as this will miss exceptions that are instances of subclasses. -We are thinking about replacing ``OperationError`` with a -family of common exception classes (e.g. ``AppKeyError``, -``AppIndexError``...) so that we can more easily catch them. -The generic ``AppError`` would stand for all other -application-level classes. - .. _`modules`: diff --git a/pypy/doc/config/objspace.usemodules._multibytecodec.txt b/pypy/doc/config/objspace.usemodules._multibytecodec.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.usemodules._multibytecodec.txt @@ -0,0 +1,6 @@ +Use the '_multibytecodec' module. +Used by the standard library to provide codecs for 'gb2312', 'gbk', 'gb18030', +'hz', 'big5hkscs', 'iso2022_kr', 'iso2022_jp', 'iso2022_jp_1', 'iso2022_jp_2', +'iso2022_jp_2004', 'iso2022_jp_3', 'iso2022_jp_ext', 'shift_jis', 'cp932', +'euc_jp', 'shift_jis_2004', 'euc_jis_2004', 'euc_jisx0213', 'shift_jisx0213', +'euc_kr', 'cp949', 'johab', 'big5', 'cp950'. diff --git a/pypy/doc/config/translation.force_make.txt b/pypy/doc/config/translation.force_make.txt deleted file mode 100644 --- a/pypy/doc/config/translation.force_make.txt +++ /dev/null @@ -1,1 +0,0 @@ -Force executing makefile instead of using platform. diff --git a/pypy/doc/eventhistory.rst b/pypy/doc/eventhistory.rst --- a/pypy/doc/eventhistory.rst +++ b/pypy/doc/eventhistory.rst @@ -267,7 +267,7 @@ .. _`day 1`: http://codespeak.net/pipermail/pypy-dev/2005q2/002169.html .. _`day 2`: http://codespeak.net/pipermail/pypy-dev/2005q2/002171.html .. _`day 3`: http://codespeak.net/pipermail/pypy-dev/2005q2/002172.html -.. _`pypy-dev`: http://codespeak.net/mailman/listinfo/pypy-dev +.. _`pypy-dev`: http://python.org/mailman/listinfo/pypy-dev .. _EuroPython: http://europython.org .. _`translation`: translation.html diff --git a/pypy/doc/extradoc.rst b/pypy/doc/extradoc.rst --- a/pypy/doc/extradoc.rst +++ b/pypy/doc/extradoc.rst @@ -67,7 +67,7 @@ .. _bibtex: https://bitbucket.org/pypy/extradoc/raw/tip/talk/bibtex.bib .. _`Allocation Removal by Partial Evaluation in a Tracing JIT`: http://codespeak.net/svn/pypy/extradoc/talk/pepm2011/bolz-allocation-removal.pdf .. _`Towards a Jitting VM for Prolog Execution`: http://www.stups.uni-duesseldorf.de/publications/bolz-prolog-jit.pdf -.. _`High performance implementation of Python for CLI/.NET with JIT compiler generation for dynamic languages`: http://codespeak.net/svn/user/antocuni/phd/thesis/thesis.pdf +.. _`High performance implementation of Python for CLI/.NET with JIT compiler generation for dynamic languages`: http://buildbot.pypy.org/misc/antocuni-thesis.pdf .. _`How to *not* write Virtual Machines for Dynamic Languages`: https://bitbucket.org/pypy/extradoc/raw/tip/talk/dyla2007/dyla.pdf .. _`Tracing the Meta-Level: PyPy's Tracing JIT Compiler`: https://bitbucket.org/pypy/extradoc/raw/tip/talk/icooolps2009/bolz-tracing-jit.pdf .. _`Faster than C#: Efficient Implementation of Dynamic Languages on .NET`: https://bitbucket.org/pypy/extradoc/raw/tip/talk/icooolps2009-dotnet/cli-jit.pdf @@ -335,7 +335,7 @@ Microsoft's Common Language Runtime (CLR) Intermediate Language (IL). * Tunes_ is not entirely unrelated. The web site changed a lot, but a - snapshot of the `old Tunes Wiki`_ is available on codespeak; browsing + snapshot of the `old Tunes Wiki`_ is available; browsing through it is a lot of fun. .. _TraceMonkey: https://wiki.mozilla.org/JavaScript:TraceMonkey @@ -355,4 +355,4 @@ .. _`Dynamic Native Optimization of Native Interpreters`: http://people.csail.mit.edu/gregs/dynamorio.html .. _JikesRVM: http://jikesrvm.org/ .. _Tunes: http://tunes.org -.. _`old Tunes Wiki`: http://codespeak.net/cliki.tunes.org/ +.. _`old Tunes Wiki`: http://buildbot.pypy.org/misc/cliki.tunes.org/ diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -162,7 +162,7 @@ discussions. .. _`contact us`: index.html -.. _`mailing list`: http://codespeak.net/mailman/listinfo/pypy-dev +.. _`mailing list`: http://python.org/mailman/listinfo/pypy-dev ------------------------------------------------------------- OSError: ... cannot restore segment prot after reloc... Help? diff --git a/pypy/doc/getting-started-dev.rst b/pypy/doc/getting-started-dev.rst --- a/pypy/doc/getting-started-dev.rst +++ b/pypy/doc/getting-started-dev.rst @@ -369,7 +369,7 @@ .. _`full Python interpreter`: getting-started-python.html .. _`the blog`: http://morepypy.blogspot.com -.. _`pypy-dev mailing list`: http://codespeak.net/mailman/listinfo/pypy-dev +.. _`pypy-dev mailing list`: http://python.org/mailman/listinfo/pypy-dev .. _`contact possibilities`: index.html .. _`py library`: http://pylib.org diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -217,23 +217,29 @@ is "similar enough": some details of the system on which the translation occurred might be hard-coded in the executable. -For installation purposes, note that the executable needs to be able to -find its version of the Python standard library in the following three -directories: ``lib-python/2.7``, ``lib-python/modified-2.7`` and -``lib_pypy``. They are located by "looking around" starting from the -directory in which the executable resides. The current logic is to try -to find a ``PREFIX`` from which the directories -``PREFIX/lib-python/2.7`` and ``PREFIX/lib-python/modified.2.7`` and -``PREFIX/lib_pypy`` can all be found. The prefixes that are tried are:: +PyPy dynamically finds the location of its libraries depending on the location +of the executable. The directory hierarchy of a typical PyPy installation +looks like this:: - . - ./lib/pypy1.5 - .. - ../lib/pypy1.5 - ../.. - ../../lib/pypy-1.5 - ../../.. - etc. + ./bin/pypy + ./include/ + ./lib_pypy/ + ./lib-python/2.7 + ./lib-python/modified-2.7 + ./site-packages/ + +The hierarchy shown above is relative to a PREFIX directory. PREFIX is +computed by starting from the directory where the executable resides, and +"walking up" the filesystem until we find a directory containing ``lib_pypy``, +``lib-python/2.7`` and ``lib-python/2.7.1``. + +The archives (.tar.bz2 or .zip) containing PyPy releases already contain the +correct hierarchy, so to run PyPy it's enough to unpack the archive, and run +the ``bin/pypy`` executable. + +To install PyPy system wide on unix-like systems, it is recommended to put the +whole hierarchy alone (e.g. in ``/opt/pypy1.5``) and put a symlink to the +``pypy`` executable into ``/usr/bin`` or ``/usr/local/bin`` If the executable fails to find suitable libraries, it will report ``debug: WARNING: library path not found, using compiled-in sys.path`` diff --git a/pypy/doc/index-report.rst b/pypy/doc/index-report.rst --- a/pypy/doc/index-report.rst +++ b/pypy/doc/index-report.rst @@ -99,7 +99,7 @@ .. _`py-lib`: http://pylib.org/ .. _`py.test`: http://pytest.org/ .. _codespeak: http://codespeak.net/ -.. _`pypy-dev`: http://codespeak.net/mailman/listinfo/pypy-dev +.. _`pypy-dev`: http://python.org/mailman/listinfo/pypy-dev Reports of 2006 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -52,8 +52,6 @@ * `Mercurial commit mailing list`_: updates to code and documentation. -* `Sprint mailing list`_: mailing list for organizing upcoming sprints. - * `Development bug/feature tracker`_: filing bugs and feature requests. * **IRC channel #pypy on freenode**: Many of the core developers are hanging out @@ -76,9 +74,8 @@ .. _`PyPy blog`: http://morepypy.blogspot.com/ .. _`development bug/feature tracker`: https://codespeak.net/issue/pypy-dev/ .. _here: http://tismerysoft.de/pypy/irc-logs/pypy -.. _`sprint mailing list`: http://codespeak.net/mailman/listinfo/pypy-sprint -.. _`Mercurial commit mailing list`: http://codespeak.net/mailman/listinfo/pypy-svn -.. _`development mailing list`: http://codespeak.net/mailman/listinfo/pypy-dev +.. _`Mercurial commit mailing list`: http://python.org/mailman/listinfo/pypy-commit +.. _`development mailing list`: http://python.org/mailman/listinfo/pypy-dev .. _`FAQ`: faq.html .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html diff --git a/pypy/doc/statistic/index.rst b/pypy/doc/statistic/index.rst --- a/pypy/doc/statistic/index.rst +++ b/pypy/doc/statistic/index.rst @@ -63,5 +63,5 @@ .. image:: webaccess.png -.. _`pypy-dev`: http://codespeak.net/mailman/listinfo/pypy-svn -.. _`pypy-svn`: http://codespeak.net/mailman/listinfo/pypy-dev +.. _`pypy-dev`: http://python.org/mailman/listinfo/pypy-commit +.. _`pypy-svn`: http://python.org/mailman/listinfo/pypy-dev diff --git a/pypy/doc/translation.rst b/pypy/doc/translation.rst --- a/pypy/doc/translation.rst +++ b/pypy/doc/translation.rst @@ -684,7 +684,7 @@ .. _`Common Language Infrastructure`: http://www.ecma-international.org/publications/standards/Ecma-335.htm .. _`.NET`: http://www.microsoft.com/net/ .. _Mono: http://www.mono-project.com/ -.. _`Master's thesis`: http://codespeak.net/~antocuni/Implementing%20Python%20in%20.NET.pdf +.. _`Master's thesis`: http://buildbot.pypy.org/misc/Implementing%20Python%20in%20.NET.pdf .. _GenCLI: cli-backend.html GenJVM diff --git a/pypy/doc/video-index.rst b/pypy/doc/video-index.rst --- a/pypy/doc/video-index.rst +++ b/pypy/doc/video-index.rst @@ -42,11 +42,11 @@ Trailer: PyPy at the PyCon 2006 ------------------------------- -130mb: http://wyvern.cs.uni-duesseldorf.de/torrent/pycon-trailer.avi.torrent +130mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer.avi.torrent -71mb: http://wyvern.cs.uni-duesseldorf.de/torrent/pycon-trailer-medium.avi.torrent +71mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer-medium.avi.torrent -50mb: http://wyvern.cs.uni-duesseldorf.de/torrent/pycon-trailer-320x240.avi.torrent +50mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer-320x240.avi.torrent .. image:: image/pycon-trailer.jpg :scale: 100 @@ -62,9 +62,9 @@ Interview with Tim Peters ------------------------- -440mb: http://wyvern.cs.uni-duesseldorf.de/torrent/interview-timpeters-v2.avi.torrent +440mb: http://buildbot.pypy.org/misc/torrent/interview-timpeters-v2.avi.torrent -138mb: http://wyvern.cs.uni-duesseldorf.de/torrent/interview-timpeters-320x240.avi.torrent +138mb: http://buildbot.pypy.org/misc/torrent/interview-timpeters-320x240.avi.torrent .. image:: image/interview-timpeters.jpg :scale: 100 @@ -82,9 +82,9 @@ Interview with Bob Ippolito --------------------------- -155mb: http://wyvern.cs.uni-duesseldorf.de/torrent/interview-bobippolito-v2.avi.torrent +155mb: http://buildbot.pypy.org/misc/torrent/interview-bobippolito-v2.avi.torrent -50mb: http://wyvern.cs.uni-duesseldorf.de/torrent/interview-bobippolito-320x240.avi.torrent +50mb: http://buildbot.pypy.org/misc/torrent/interview-bobippolito-320x240.avi.torrent .. image:: image/interview-bobippolito.jpg :scale: 100 @@ -102,9 +102,9 @@ Introductory talk on PyPy ------------------------- -430mb: http://wyvern.cs.uni-duesseldorf.de/torrent/introductory-talk-pycon-v1.avi.torrent +430mb: http://buildbot.pypy.org/misc/torrent/introductory-talk-pycon-v1.avi.torrent -166mb: http://wyvern.cs.uni-duesseldorf.de/torrent/introductory-talk-pycon-320x240.avi.torrent +166mb: http://buildbot.pypy.org/misc/torrent/introductory-talk-pycon-320x240.avi.torrent .. image:: image/introductory-talk-pycon.jpg :scale: 100 @@ -125,9 +125,9 @@ Talk on Agile Open Source Methods in the PyPy project ----------------------------------------------------- -395mb: http://wyvern.cs.uni-duesseldorf.de/torrent/agile-talk-v1.avi.torrent +395mb: http://buildbot.pypy.org/misc/torrent/agile-talk-v1.avi.torrent -153mb: http://wyvern.cs.uni-duesseldorf.de/torrent/agile-talk-320x240.avi.torrent +153mb: http://buildbot.pypy.org/misc/torrent/agile-talk-320x240.avi.torrent .. image:: image/agile-talk.jpg :scale: 100 @@ -148,9 +148,9 @@ PyPy Architecture session ------------------------- -744mb: http://wyvern.cs.uni-duesseldorf.de/torrent/architecture-session-v1.avi.torrent +744mb: http://buildbot.pypy.org/misc/torrent/architecture-session-v1.avi.torrent -288mb: http://wyvern.cs.uni-duesseldorf.de/torrent/architecture-session-320x240.avi.torrent +288mb: http://buildbot.pypy.org/misc/torrent/architecture-session-320x240.avi.torrent .. image:: image/architecture-session.jpg :scale: 100 @@ -171,9 +171,9 @@ Sprint tutorial --------------- -680mb: http://wyvern.cs.uni-duesseldorf.de/torrent/sprint-tutorial-v2.avi.torrent +680mb: http://buildbot.pypy.org/misc/torrent/sprint-tutorial-v2.avi.torrent -263mb: http://wyvern.cs.uni-duesseldorf.de/torrent/sprint-tutorial-320x240.avi.torrent +263mb: http://buildbot.pypy.org/misc/torrent/sprint-tutorial-320x240.avi.torrent .. image:: image/sprint-tutorial.jpg :scale: 100 @@ -190,9 +190,9 @@ Scripting .NET with IronPython by Jim Hugunin --------------------------------------------- -372mb: http://wyvern.cs.uni-duesseldorf.de/torrent/ironpython-talk-v2.avi.torrent +372mb: http://buildbot.pypy.org/misc/torrent/ironpython-talk-v2.avi.torrent -270mb: http://wyvern.cs.uni-duesseldorf.de/torrent/ironpython-talk-320x240.avi.torrent +270mb: http://buildbot.pypy.org/misc/torrent/ironpython-talk-320x240.avi.torrent .. image:: image/ironpython.jpg :scale: 100 @@ -209,9 +209,9 @@ Bram Cohen, founder and developer of BitTorrent ----------------------------------------------- -509mb: http://wyvern.cs.uni-duesseldorf.de/torrent/bram-cohen-interview-v1.avi.torrent +509mb: http://buildbot.pypy.org/misc/torrent/bram-cohen-interview-v1.avi.torrent -370mb: http://wyvern.cs.uni-duesseldorf.de/torrent/bram-cohen-interview-320x240.avi.torrent +370mb: http://buildbot.pypy.org/misc/torrent/bram-cohen-interview-320x240.avi.torrent .. image:: image/bram.jpg :scale: 100 @@ -226,9 +226,9 @@ Keynote speech by Guido van Rossum on the new Python 2.5 features ----------------------------------------------------------------- -695mb: http://wyvern.cs.uni-duesseldorf.de/torrent/keynote-speech_guido-van-rossum_v1.avi.torrent +695mb: http://buildbot.pypy.org/misc/torrent/keynote-speech_guido-van-rossum_v1.avi.torrent -430mb: http://wyvern.cs.uni-duesseldorf.de/torrent/keynote-speech_guido-van-rossum_320x240.avi.torrent +430mb: http://buildbot.pypy.org/misc/torrent/keynote-speech_guido-van-rossum_320x240.avi.torrent .. image:: image/guido.jpg :scale: 100 @@ -243,11 +243,11 @@ Trailer: PyPy sprint at the University of Palma de Mallorca ----------------------------------------------------------- -166mb: http://wyvern.cs.uni-duesseldorf.de/torrent/mallorca-trailer-v1.avi.torrent +166mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-v1.avi.torrent -88mb: http://wyvern.cs.uni-duesseldorf.de/torrent/mallorca-trailer-medium.avi.torrent +88mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-medium.avi.torrent -64mb: http://wyvern.cs.uni-duesseldorf.de/torrent/mallorca-trailer-320x240.avi.torrent +64mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-320x240.avi.torrent .. image:: image/mallorca-trailer.jpg :scale: 100 @@ -262,9 +262,9 @@ Coding discussion of core developers Armin Rigo and Samuele Pedroni ------------------------------------------------------------------- -620mb: http://wyvern.cs.uni-duesseldorf.de/torrent/coding-discussion-v1.avi.torrent +620mb: http://buildbot.pypy.org/misc/torrent/coding-discussion-v1.avi.torrent -240mb: http://wyvern.cs.uni-duesseldorf.de/torrent/coding-discussion-320x240.avi.torrent +240mb: http://buildbot.pypy.org/misc/torrent/coding-discussion-320x240.avi.torrent .. image:: image/coding-discussion.jpg :scale: 100 @@ -279,9 +279,9 @@ PyPy technical talk at the University of Palma de Mallorca ---------------------------------------------------------- -865mb: http://wyvern.cs.uni-duesseldorf.de/torrent/introductory-student-talk-v2.avi.torrent +865mb: http://buildbot.pypy.org/misc/torrent/introductory-student-talk-v2.avi.torrent -437mb: http://wyvern.cs.uni-duesseldorf.de/torrent/introductory-student-talk-320x240.avi.torrent +437mb: http://buildbot.pypy.org/misc/torrent/introductory-student-talk-320x240.avi.torrent .. image:: image/introductory-student-talk.jpg :scale: 100 diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -615,33 +615,42 @@ self.num_kwds = nkwds def getmsg(self, fnname): - args = None - #args_w, kwds_w = args.unpack() - nargs = self.num_args + self.num_kwds n = self.expected_nargs if n == 0: - msg = "%s() takes no argument (%d given)" % ( + msg = "%s() takes no arguments (%d given)" % ( fnname, - nargs) + self.num_args + self.num_kwds) else: defcount = self.num_defaults + has_kwarg = self.has_kwarg + num_args = self.num_args + num_kwds = self.num_kwds if defcount == 0 and not self.has_vararg: msg1 = "exactly" + if not has_kwarg: + num_args += num_kwds + num_kwds = 0 elif not self.missing_args: msg1 = "at most" else: msg1 = "at least" + has_kwarg = False n -= defcount if n == 1: plural = "" else: plural = "s" - msg = "%s() takes %s %d argument%s (%d given)" % ( + if has_kwarg or num_kwds > 0: + msg2 = " non-keyword" + else: + msg2 = "" + msg = "%s() takes %s %d%s argument%s (%d given)" % ( fnname, msg1, n, + msg2, plural, - nargs) + num_args) return msg class ArgErrMultipleValues(ArgErr): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -890,8 +890,7 @@ try: w_res = self.call_args(w_func, args) except OperationError, e: - w_value = e.get_w_value(self) - ec.c_exception_trace(frame, w_value) + ec.c_exception_trace(frame, w_func) raise ec.c_return_trace(frame, w_func, args) return w_res diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -56,10 +56,10 @@ frame.f_backref = self.topframeref self.topframeref = jit.virtual_ref(frame) - def leave(self, frame): + def leave(self, frame, w_exitvalue): try: if self.profilefunc: - self._trace(frame, 'leaveframe', self.space.w_None) + self._trace(frame, 'leaveframe', w_exitvalue) finally: self.topframeref = frame.f_backref jit.virtual_ref_finish(frame) diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -138,6 +138,7 @@ not self.space.config.translating) executioncontext = self.space.getexecutioncontext() executioncontext.enter(self) + w_exitvalue = self.space.w_None try: executioncontext.call_trace(self) # @@ -166,7 +167,7 @@ # allocating exception objects in some cases self.last_exception = None finally: - executioncontext.leave(self) + executioncontext.leave(self, w_exitvalue) return w_exitvalue execute_frame.insert_stack_check_here = True diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -512,25 +512,34 @@ # defaults_w, missing_args err = ArgErrCount(1, 0, 0, False, False, None, 0) s = err.getmsg('foo') - assert s == "foo() takes no argument (1 given)" + assert s == "foo() takes no arguments (1 given)" err = ArgErrCount(0, 0, 1, False, False, [], 1) s = err.getmsg('foo') assert s == "foo() takes exactly 1 argument (0 given)" err = ArgErrCount(3, 0, 2, False, False, [], 0) s = err.getmsg('foo') assert s == "foo() takes exactly 2 arguments (3 given)" + err = ArgErrCount(3, 0, 2, False, False, ['a'], 0) + s = err.getmsg('foo') + assert s == "foo() takes at most 2 arguments (3 given)" err = ArgErrCount(1, 0, 2, True, False, [], 1) s = err.getmsg('foo') assert s == "foo() takes at least 2 arguments (1 given)" - err = ArgErrCount(3, 0, 2, True, False, ['a'], 0) - s = err.getmsg('foo') - assert s == "foo() takes at most 2 arguments (3 given)" err = ArgErrCount(0, 1, 2, True, False, ['a'], 1) s = err.getmsg('foo') - assert s == "foo() takes at least 1 argument (1 given)" + assert s == "foo() takes at least 1 non-keyword argument (0 given)" err = ArgErrCount(2, 1, 1, False, True, [], 0) s = err.getmsg('foo') - assert s == "foo() takes exactly 1 argument (3 given)" + assert s == "foo() takes exactly 1 non-keyword argument (2 given)" + err = ArgErrCount(0, 1, 1, False, True, [], 1) + s = err.getmsg('foo') + assert s == "foo() takes exactly 1 non-keyword argument (0 given)" + err = ArgErrCount(0, 1, 1, True, True, [], 1) + s = err.getmsg('foo') + assert s == "foo() takes at least 1 non-keyword argument (0 given)" + err = ArgErrCount(2, 1, 1, False, True, ['a'], 0) + s = err.getmsg('foo') + assert s == "foo() takes at most 1 non-keyword argument (2 given)" def test_bad_type_for_star(self): space = self.space @@ -565,15 +574,23 @@ class AppTestArgument: def test_error_message(self): exc = raises(TypeError, (lambda a, b=2: 0), b=3) - assert exc.value.message == "() takes at least 1 argument (1 given)" + assert exc.value.message == "() takes at least 1 non-keyword argument (0 given)" exc = raises(TypeError, (lambda: 0), b=3) - assert exc.value.message == "() takes no argument (1 given)" + assert exc.value.message == "() takes no arguments (1 given)" exc = raises(TypeError, (lambda a, b: 0), 1, 2, 3, a=1) assert exc.value.message == "() takes exactly 2 arguments (4 given)" exc = raises(TypeError, (lambda a, b=1: 0), 1, 2, 3, a=1) - assert exc.value.message == "() takes at most 2 arguments (4 given)" + assert exc.value.message == "() takes at most 2 non-keyword arguments (3 given)" exc = raises(TypeError, (lambda a, b=1, **kw: 0), 1, 2, 3) - assert exc.value.message == "() takes at most 2 arguments (3 given)" + assert exc.value.message == "() takes at most 2 non-keyword arguments (3 given)" + exc = raises(TypeError, (lambda a, b, c=3, **kw: 0), 1) + assert exc.value.message == "() takes at least 2 arguments (1 given)" + exc = raises(TypeError, (lambda a, b, **kw: 0), 1) + assert exc.value.message == "() takes exactly 2 non-keyword arguments (1 given)" + exc = raises(TypeError, (lambda a, b, c=3, **kw: 0), a=1) + assert exc.value.message == "() takes at least 2 non-keyword arguments (0 given)" + exc = raises(TypeError, (lambda a, b, **kw: 0), a=1) + assert exc.value.message == "() takes exactly 2 non-keyword arguments (0 given)" def make_arguments_for_translation(space, args_w, keywords_w={}, w_stararg=None, w_starstararg=None): diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -324,3 +324,70 @@ g.close() assert 'Called 1' in data assert 'Called 2' in data + + +class AppTestProfile: + + def test_return(self): + import sys + l = [] + def profile(frame, event, arg): + l.append((event, arg)) + + def bar(x): + return 40 + x + + sys.setprofile(profile) + bar(2) + sys.setprofile(None) + assert l == [('call', None), + ('return', 42), + ('c_call', sys.setprofile)], repr(l) + + def test_c_return(self): + import sys + l = [] + def profile(frame, event, arg): + l.append((event, arg)) + + sys.setprofile(profile) + max(2, 42) + sys.setprofile(None) + assert l == [('c_call', max), + ('c_return', max), + ('c_call', sys.setprofile)], repr(l) + + def test_exception(self): + import sys + l = [] + def profile(frame, event, arg): + l.append((event, arg)) + + def f(): + raise ValueError("foo") + + sys.setprofile(profile) + try: + f() + except ValueError: + pass + sys.setprofile(None) + assert l == [('call', None), + ('return', None), + ('c_call', sys.setprofile)], repr(l) + + def test_c_exception(self): + import sys + l = [] + def profile(frame, event, arg): + l.append((event, arg)) + + sys.setprofile(profile) + try: + divmod(5, 0) + except ZeroDivisionError: + pass + sys.setprofile(None) + assert l == [('c_call', divmod), + ('c_exception', divmod), + ('c_call', sys.setprofile)], repr(l) diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py --- a/pypy/interpreter/test/test_function.py +++ b/pypy/interpreter/test/test_function.py @@ -98,6 +98,14 @@ raises(TypeError, "dir.func_code = f.func_code") raises(TypeError, "list.append.im_func.func_code = f.func_code") + def test_set_module_to_name_eagerly(self): + skip("fails on PyPy but works on CPython. Unsure we want to care") + exec '''if 1: + __name__ = "foo" + def f(): pass + __name__ = "bar" + assert f.__module__ == "foo"''' in {} + class AppTestFunction: def test_simple_call(self): diff --git a/pypy/jit/backend/arm/test/test_gc_integration.py b/pypy/jit/backend/arm/test/test_gc_integration.py --- a/pypy/jit/backend/arm/test/test_gc_integration.py +++ b/pypy/jit/backend/arm/test/test_gc_integration.py @@ -69,6 +69,7 @@ self.gcrefs.initialize() self.single_gcref_descr = GcPtrFieldDescr('', 0) + replace_constptrs_with_getfield_raw = GcLLDescr_framework.replace_constptrs_with_getfield_raw.im_func rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func class TestRegallocDirectGcIntegration(object): diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -35,7 +35,7 @@ def do_write_barrier(self, gcref_struct, gcref_newptr): pass def rewrite_assembler(self, cpu, operations): - pass + return operations def can_inline_malloc(self, descr): return False def can_inline_malloc_varsize(self, descr, num_elem): @@ -772,6 +772,31 @@ funcptr(llmemory.cast_ptr_to_adr(gcref_struct), llmemory.cast_ptr_to_adr(gcref_newptr)) + def replace_constptrs_with_getfield_raw(self, cpu, newops, op): + # xxx some performance issue here + newargs = [None] * op.numargs() + needs_copy = False + for i in range(op.numargs()): + v = op.getarg(i) + newargs[i] = v + if isinstance(v, ConstPtr) and bool(v.value): + addr = self.gcrefs.get_address_of_gcref(v.value) + # ^^^even for non-movable objects, to record their presence + if rgc.can_move(v.value): + box = BoxPtr(v.value) + addr = cpu.cast_adr_to_int(addr) + newops.append(ResOperation(rop.GETFIELD_RAW, + [ConstInt(addr)], box, + self.single_gcref_descr)) + newargs[i] = box + needs_copy = True + # + if needs_copy: + return op.copy_and_change(op.getopnum(), args=newargs) + else: + return op + + def rewrite_assembler(self, cpu, operations): # Perform two kinds of rewrites in parallel: # @@ -794,19 +819,7 @@ if op.getopnum() == rop.DEBUG_MERGE_POINT: continue # ---------- replace ConstPtrs with GETFIELD_RAW ---------- - # xxx some performance issue here - for i in range(op.numargs()): - v = op.getarg(i) - if isinstance(v, ConstPtr) and bool(v.value): - addr = self.gcrefs.get_address_of_gcref(v.value) - # ^^^even for non-movable objects, to record their presence - if rgc.can_move(v.value): - box = BoxPtr(v.value) - addr = cpu.cast_adr_to_int(addr) - newops.append(ResOperation(rop.GETFIELD_RAW, - [ConstInt(addr)], box, - self.single_gcref_descr)) - op.setarg(i, box) + op = self.replace_constptrs_with_getfield_raw(cpu, newops, op) if op.is_malloc(): last_malloc = op.result elif op.can_malloc(): @@ -835,8 +848,7 @@ op = op.copy_and_change(rop.SETARRAYITEM_RAW) # ---------- newops.append(op) - del operations[:] - operations.extend(newops) + return newops def _gen_write_barrier(self, newops, v_base, v_value): args = [v_base, v_value] diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py --- a/pypy/jit/backend/llsupport/test/test_gc.py +++ b/pypy/jit/backend/llsupport/test/test_gc.py @@ -6,6 +6,7 @@ from pypy.jit.backend.llsupport.gc import * from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.gc import get_description +from pypy.jit.metainterp.resoperation import get_deep_immutable_oplist from pypy.jit.tool.oparser import parse from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE from pypy.jit.metainterp.test.test_optimizeopt import equaloplists @@ -413,7 +414,7 @@ ResOperation(rop.DEBUG_MERGE_POINT, ['dummy', 2], None), ] gc_ll_descr = self.gc_ll_descr - gc_ll_descr.rewrite_assembler(None, operations) + operations = gc_ll_descr.rewrite_assembler(None, operations) assert len(operations) == 0 def test_rewrite_assembler_1(self): @@ -437,7 +438,8 @@ ] gc_ll_descr = self.gc_ll_descr gc_ll_descr.gcrefs = MyFakeGCRefList() - gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) + operations = get_deep_immutable_oplist(operations) + operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) assert len(operations) == 2 assert operations[0].getopnum() == rop.GETFIELD_RAW assert operations[0].getarg(0) == ConstInt(43) @@ -472,9 +474,10 @@ gc_ll_descr = self.gc_ll_descr gc_ll_descr.gcrefs = MyFakeGCRefList() old_can_move = rgc.can_move + operations = get_deep_immutable_oplist(operations) try: rgc.can_move = lambda s: False - gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) + operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) finally: rgc.can_move = old_can_move assert len(operations) == 1 @@ -496,7 +499,8 @@ descr=field_descr), ] gc_ll_descr = self.gc_ll_descr - gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = get_deep_immutable_oplist(operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) assert len(operations) == 2 # assert operations[0].getopnum() == rop.COND_CALL_GC_WB @@ -520,7 +524,8 @@ descr=array_descr), ] gc_ll_descr = self.gc_ll_descr - gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = get_deep_immutable_oplist(operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) assert len(operations) == 2 # assert operations[0].getopnum() == rop.COND_CALL_GC_WB @@ -552,8 +557,9 @@ setfield_gc(p0, p1, descr=xdescr) jump() """, namespace=locals()) - self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations) - equaloplists(ops.operations, expected.operations) + operations = get_deep_immutable_oplist(ops.operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + equaloplists(operations, expected.operations) def test_rewrite_assembler_initialization_store_2(self): S = lltype.GcStruct('S', ('parent', OBJECT), @@ -576,8 +582,9 @@ setfield_raw(p0, p1, descr=xdescr) jump() """, namespace=locals()) - self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations) - equaloplists(ops.operations, expected.operations) + operations = get_deep_immutable_oplist(ops.operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + equaloplists(operations, expected.operations) def test_rewrite_assembler_initialization_store_3(self): A = lltype.GcArray(lltype.Ptr(lltype.GcStruct('S'))) @@ -594,8 +601,9 @@ setarrayitem_gc(p0, 0, p1, descr=arraydescr) jump() """, namespace=locals()) - self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations) - equaloplists(ops.operations, expected.operations) + operations = get_deep_immutable_oplist(ops.operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + equaloplists(operations, expected.operations) class TestFrameworkMiniMark(TestFramework): gc = 'minimark' diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py --- a/pypy/jit/backend/model.py +++ b/pypy/jit/backend/model.py @@ -58,12 +58,19 @@ """Called once by the front-end when the program stops.""" pass - def compile_loop(self, inputargs, operations, looptoken, log=True): """Assemble the given loop. Should create and attach a fresh CompiledLoopToken to looptoken.compiled_loop_token and stick extra attributes on it to point to the compiled loop in assembler. + + Optionally, return a ``ops_offset`` dictionary, which maps each operation + to its offset in the compiled code. The ``ops_offset`` dictionary is then + used by the operation logger to print the offsets in the log. The + offset representing the end of the last operation is stored in + ``ops_offset[None]``: note that this might not coincide with the end of + the loop, because usually in the loop footer there is code which does + not belong to any particular operation. """ raise NotImplementedError @@ -71,9 +78,16 @@ original_loop_token, log=True): """Assemble the bridge. The FailDescr is the descr of the original guard that failed. + + Optionally, return a ``ops_offset`` dictionary. See the docstring of + ``compiled_loop`` for more informations about it. """ raise NotImplementedError + def dump_loop_token(self, looptoken): + """Print a disassembled version of looptoken to stdout""" + raise NotImplementedError + def execute_token(self, looptoken): """Execute the generated code referenced by the looptoken. Returns the descr of the last executed operation: either the one diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -189,6 +189,8 @@ wr_i1 = weakref.ref(i1) wr_guard = weakref.ref(operations[2]) self.cpu.compile_loop(inputargs, operations, looptoken) + if hasattr(looptoken, '_x86_ops_offset'): + del looptoken._x86_ops_offset # else it's kept alive del i0, i1, i2 del inputargs del operations diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -334,7 +334,7 @@ operations = self._inject_debugging_code(looptoken, operations) regalloc = RegAlloc(self, self.cpu.translate_support_code) - arglocs = regalloc.prepare_loop(inputargs, operations, looptoken) + arglocs, operations = regalloc.prepare_loop(inputargs, operations, looptoken) looptoken._x86_arglocs = arglocs bootstrappos = self.mc.get_relative_pos() @@ -361,6 +361,13 @@ frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) # + ops_offset = self.mc.ops_offset + if not we_are_translated(): + # used only by looptoken.dump() -- useful in tests + looptoken._x86_rawstart = rawstart + looptoken._x86_fullsize = fullsize + looptoken._x86_ops_offset = ops_offset + looptoken._x86_bootstrap_code = rawstart + bootstrappos looptoken._x86_loop_code = rawstart + self.looppos looptoken._x86_direct_bootstrap_code = rawstart + directbootstrappos @@ -370,6 +377,7 @@ name = "Loop # %s: %s" % (looptoken.number, funcname) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) + return ops_offset def assemble_bridge(self, faildescr, inputargs, operations, original_loop_token, log): @@ -397,8 +405,8 @@ [loc.assembler() for loc in faildescr._x86_debug_faillocs]) regalloc = RegAlloc(self, self.cpu.translate_support_code) fail_depths = faildescr._x86_current_depths - regalloc.prepare_bridge(fail_depths, inputargs, arglocs, - operations) + operations = regalloc.prepare_bridge(fail_depths, inputargs, arglocs, + operations) stackadjustpos = self._patchable_stackadjust() frame_depth, param_depth = self._assemble(regalloc, operations) @@ -419,12 +427,14 @@ faildescr._x86_bridge_param_depth = param_depth # patch the jump from original guard self.patch_jump_for_descr(faildescr, rawstart) + ops_offset = self.mc.ops_offset self.teardown() # oprofile support if self.cpu.profile_agent is not None: name = "Bridge # %s: %s" % (descr_number, funcname) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) + return ops_offset def write_pending_failure_recoveries(self): # for each pending guard, generate the code of the recovery stub diff --git a/pypy/jit/backend/x86/codebuf.py b/pypy/jit/backend/x86/codebuf.py --- a/pypy/jit/backend/x86/codebuf.py +++ b/pypy/jit/backend/x86/codebuf.py @@ -1,5 +1,7 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rarithmetic import intmask +from pypy.rlib.debug import debug_start, debug_print, debug_stop +from pypy.rlib.debug import have_debug_prints from pypy.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin from pypy.jit.backend.x86.rx86 import X86_32_CodeBuilder, X86_64_CodeBuilder from pypy.jit.backend.x86.regloc import LocationCodeBuilder @@ -25,10 +27,19 @@ # at [p-4:p] encode an absolute address that will need to be # made relative. self.relocations = [] + # + # ResOperation --> offset in the assembly. + # ops_offset[None] represents the beginning of the code after the last op + # (i.e., the tail of the loop) + self.ops_offset = {} def add_pending_relocation(self): self.relocations.append(self.get_relative_pos()) + def mark_op(self, op): + pos = self.get_relative_pos() + self.ops_offset[op] = pos + def copy_to_raw_memory(self, addr): self._copy_to_raw_memory(addr) for reloc in self.relocations: diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -161,7 +161,7 @@ self.fm = X86FrameManager() self.param_depth = 0 cpu = self.assembler.cpu - cpu.gc_ll_descr.rewrite_assembler(cpu, operations) + operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations) # compute longevity of variables longevity = compute_vars_longevity(inputargs, operations) self.longevity = longevity @@ -170,20 +170,22 @@ assembler = self.assembler) self.xrm = xmm_reg_mgr_cls(longevity, frame_manager = self.fm, assembler = self.assembler) + return operations def prepare_loop(self, inputargs, operations, looptoken): - self._prepare(inputargs, operations) + operations = self._prepare(inputargs, operations) jump = operations[-1] loop_consts = compute_loop_consts(inputargs, jump, looptoken) self.loop_consts = loop_consts - return self._process_inputargs(inputargs) + return self._process_inputargs(inputargs), operations def prepare_bridge(self, prev_depths, inputargs, arglocs, operations): - self._prepare(inputargs, operations) + operations = self._prepare(inputargs, operations) self.loop_consts = {} self._update_bindings(arglocs, inputargs) self.fm.frame_depth = prev_depths[0] self.param_depth = prev_depths[1] + return operations def reserve_param(self, n): self.param_depth = max(self.param_depth, n) @@ -402,6 +404,7 @@ #self.operations = operations while i < len(operations): op = operations[i] + self.assembler.mc.mark_op(op) self.rm.position = i self.xrm.position = i if op.has_no_side_effect() and op.result not in self.longevity: @@ -422,6 +425,7 @@ i += 1 assert not self.rm.reg_bindings assert not self.xrm.reg_bindings + self.assembler.mc.mark_op(None) # end of the loop def loc(self, v): diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py --- a/pypy/jit/backend/x86/runner.py +++ b/pypy/jit/backend/x86/runner.py @@ -60,16 +60,33 @@ self.assembler.finish_once() self.profile_agent.shutdown() + def dump_loop_token(self, looptoken): + """ + NOT_RPYTHON + """ + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + data = [] + label_list = [(offset, name) for name, offset in + looptoken._x86_ops_offset.iteritems()] + label_list.sort() + addr = looptoken._x86_rawstart + src = rffi.cast(rffi.CCHARP, addr) + for p in range(looptoken._x86_fullsize): + data.append(src[p]) + data = ''.join(data) + lines = machine_code_dump(data, addr, self.backend_name, label_list) + print ''.join(lines) + def compile_loop(self, inputargs, operations, looptoken, log=True): - self.assembler.assemble_loop(inputargs, operations, looptoken, - log=log) + return self.assembler.assemble_loop(inputargs, operations, looptoken, + log=log) def compile_bridge(self, faildescr, inputargs, operations, original_loop_token, log=True): clt = original_loop_token.compiled_loop_token clt.compiling_a_bridge() - self.assembler.assemble_bridge(faildescr, inputargs, operations, - original_loop_token, log=log) + return self.assembler.assemble_bridge(faildescr, inputargs, operations, + original_loop_token, log=log) def set_future_value_int(self, index, intvalue): self.assembler.fail_boxes_int.setitem(index, intvalue) @@ -164,7 +181,9 @@ # positions invalidated looptoken.compiled_loop_token.invalidate_positions = [] + class CPU386(AbstractX86CPU): + backend_name = 'x86' WORD = 4 NUM_REGS = 8 CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.esi, regloc.edi] @@ -180,6 +199,7 @@ supports_longlong = False class CPU_X86_64(AbstractX86CPU): + backend_name = 'x86_64' WORD = 8 NUM_REGS = 16 CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.r12, regloc.r13, regloc.r14, regloc.r15] diff --git a/pypy/jit/backend/x86/test/test_gc_integration.py b/pypy/jit/backend/x86/test/test_gc_integration.py --- a/pypy/jit/backend/x86/test/test_gc_integration.py +++ b/pypy/jit/backend/x86/test/test_gc_integration.py @@ -54,7 +54,8 @@ self.gcrefs = GcRefList() self.gcrefs.initialize() self.single_gcref_descr = GcPtrFieldDescr('', 0) - + + replace_constptrs_with_getfield_raw = GcLLDescr_framework.replace_constptrs_with_getfield_raw.im_func rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func class TestRegallocDirectGcIntegration(object): diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -390,6 +390,29 @@ res = self.cpu.get_latest_value_int(0) assert res == 20 + def test_ops_offset(self): + from pypy.rlib import debug + i0 = BoxInt() + i1 = BoxInt() + i2 = BoxInt() + looptoken = LoopToken() + operations = [ + ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), + ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), + ResOperation(rop.JUMP, [i1], None, descr=looptoken), + ] + inputargs = [i0] + debug._log = dlog = debug.DebugLog() + ops_offset = self.cpu.compile_loop(inputargs, operations, looptoken) + debug._log = None + # + assert ops_offset is looptoken._x86_ops_offset + # getfield_raw/int_add/setfield_raw + ops + None + assert len(ops_offset) == 3 + len(operations) + 1 + assert (ops_offset[operations[0]] <= + ops_offset[operations[1]] <= + ops_offset[operations[2]] <= + ops_offset[None]) class TestDebuggingAssembler(object): def setup_method(self, meth): diff --git a/pypy/jit/backend/x86/tool/__init__.py b/pypy/jit/backend/x86/tool/__init__.py new file mode 100644 diff --git a/pypy/jit/backend/x86/tool/test/test_viewcode.py b/pypy/jit/backend/x86/tool/test/test_viewcode.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/x86/tool/test/test_viewcode.py @@ -0,0 +1,55 @@ +from cStringIO import StringIO +from pypy.jit.backend.x86.tool.viewcode import format_code_dump_with_labels + +def test_format_code_dump_with_labels(): + lines = StringIO(""" +aa00 <.data>: +aa00: one +aa01: two +aa03: three +aa04: for +aa05: five +aa06: six +aa0c: seven +aa12: eight +""".strip()).readlines() + # + label_list = [(0x00, 'AAA'), (0x03, 'BBB'), (0x0c, 'CCC')] + lines = format_code_dump_with_labels(0xAA00, lines, label_list) + out = ''.join(lines) + assert out == """ +aa00 <.data>: + +AAA +aa00: one +aa01: two + +BBB +aa03: three +aa04: for +aa05: five +aa06: six + +CCC +aa0c: seven +aa12: eight +""".strip() + + +def test_format_code_dump_with_labels_no_labels(): + input = """ +aa00 <.data>: +aa00: one +aa01: two +aa03: three +aa04: for +aa05: five +aa06: six +aa0c: seven +aa12: eight +""".strip() + lines = StringIO(input).readlines() + # + lines = format_code_dump_with_labels(0xAA00, lines, label_list=None) + out = ''.join(lines) + assert out.strip() == input diff --git a/pypy/jit/backend/x86/tool/viewcode.py b/pypy/jit/backend/x86/tool/viewcode.py --- a/pypy/jit/backend/x86/tool/viewcode.py +++ b/pypy/jit/backend/x86/tool/viewcode.py @@ -31,13 +31,14 @@ if sys.platform == "win32": XXX # lots more in Psyco -def machine_code_dump(data, originaddr, backend_name): +def machine_code_dump(data, originaddr, backend_name, label_list=None): objdump_backend_option = { 'x86': 'i386', 'x86_64': 'x86-64', 'i386': 'i386', } objdump = ('objdump -M %(backend)s -b binary -m i386 ' + '--disassembler-options=intel-mnemonics ' '--adjust-vma=%(origin)d -D %(file)s') # f = open(tmpfile, 'wb') @@ -50,7 +51,32 @@ }, 'r') result = g.readlines() g.close() - return result[6:] # drop some objdump cruft + lines = result[6:] # drop some objdump cruft + return format_code_dump_with_labels(originaddr, lines, label_list) + +def format_code_dump_with_labels(originaddr, lines, label_list): + from pypy.rlib.rarithmetic import r_uint + if not label_list: + label_list = [] + originaddr = r_uint(originaddr) + itlines = iter(lines) + yield itlines.next() # don't process the first line + for lbl_start, lbl_name in label_list: + for line in itlines: + addr, _ = line.split(':', 1) + addr = int(addr, 16) + if addr >= originaddr+lbl_start: + yield '\n' + if lbl_name is None: + yield '--end of the loop--\n' + else: + yield str(lbl_name) + '\n' + yield line + break + yield line + # yield all the remaining lines + for line in itlines: + yield line def load_symbols(filename): # the program that lists symbols, and the output it gives @@ -134,6 +160,7 @@ def disassemble(self): if not hasattr(self, 'text'): lines = machine_code_dump(self.data, self.addr, self.world.backend_name) + lines = list(lines) # instead of adding symbol names in the dumps we could # also make the 0xNNNNNNNN addresses be red and show the # symbol name when the mouse is over them diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -7,7 +7,7 @@ from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name -from pypy.jit.metainterp.resoperation import ResOperation, rop +from pypy.jit.metainterp.resoperation import ResOperation, rop, get_deep_immutable_oplist from pypy.jit.metainterp.history import TreeLoop, Box, History, LoopToken from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const @@ -73,7 +73,7 @@ # test_memgr.py) if descr is not looptoken: looptoken.record_jump_to(descr) - op.setdescr(None) # clear reference, mostly for tests + op._descr = None # clear reference, mostly for tests if not we_are_translated(): op._jumptarget_number = descr.number # record this looptoken on the QuasiImmut used in the code @@ -156,20 +156,16 @@ loop_token.number = n = globaldata.loopnumbering globaldata.loopnumbering += 1 - metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, type) - short = loop.token.short_preamble - if short: - metainterp_sd.logger_ops.log_short_preamble(short[-1].inputargs, - short[-1].operations) - if not we_are_translated(): show_loop(metainterp_sd, loop) loop.check_consistency() + + operations = get_deep_immutable_oplist(loop.operations) metainterp_sd.profiler.start_backend() debug_start("jit-backend") try: - metainterp_sd.cpu.compile_loop(loop.inputargs, loop.operations, - loop.token) + ops_offset = metainterp_sd.cpu.compile_loop(loop.inputargs, operations, + loop.token) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() @@ -180,27 +176,37 @@ else: loop._ignore_during_counting = True metainterp_sd.log("compiled new " + type) + # + metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, type, ops_offset) + short = loop.token.short_preamble + if short: + metainterp_sd.logger_ops.log_short_preamble(short[-1].inputargs, + short[-1].operations) + # if metainterp_sd.warmrunnerdesc is not None: # for tests metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(loop.token) def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations, original_loop_token): - n = metainterp_sd.cpu.get_fail_descr_number(faildescr) - metainterp_sd.logger_ops.log_bridge(inputargs, operations, n) if not we_are_translated(): show_loop(metainterp_sd) TreeLoop.check_consistency_of(inputargs, operations) metainterp_sd.profiler.start_backend() + operations = get_deep_immutable_oplist(operations) debug_start("jit-backend") try: - metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations, - original_loop_token) + ops_offset = metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations, + original_loop_token) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() if not we_are_translated(): metainterp_sd.stats.compiled() metainterp_sd.log("compiled new bridge") + # + n = metainterp_sd.cpu.get_fail_descr_number(faildescr) + metainterp_sd.logger_ops.log_bridge(inputargs, operations, n, ops_offset) + # if metainterp_sd.warmrunnerdesc is not None: # for tests metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive( original_loop_token) @@ -685,6 +691,7 @@ ResOperation(rop.FINISH, finishargs, None, descr=jd.portal_finishtoken) ] operations[1].setfailargs([]) + operations = get_deep_immutable_oplist(operations) cpu.compile_loop(inputargs, operations, loop_token, log=False) if memory_manager is not None: # for tests memory_manager.keep_loop_alive(loop_token) diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -785,6 +785,8 @@ def repr_of_descr(self): return '' % self.number + def dump(self): + self.compiled_loop_token.cpu.dump_loop_token(self) class TreeLoop(object): inputargs = None diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py --- a/pypy/jit/metainterp/logger.py +++ b/pypy/jit/metainterp/logger.py @@ -14,33 +14,33 @@ self.ts = metainterp_sd.cpu.ts self.guard_number = guard_number - def log_loop(self, inputargs, operations, number=0, type=None): + def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): if type is None: debug_start("jit-log-noopt-loop") - self._log_operations(inputargs, operations) + self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-loop") else: debug_start("jit-log-opt-loop") debug_print("# Loop", number, ":", type, "with", len(operations), "ops") - self._log_operations(inputargs, operations) + self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-opt-loop") - def log_bridge(self, inputargs, operations, number=-1): + def log_bridge(self, inputargs, operations, number=-1, ops_offset=None): if number == -1: debug_start("jit-log-noopt-bridge") - self._log_operations(inputargs, operations) + self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-bridge") else: debug_start("jit-log-opt-bridge") debug_print("# bridge out of Guard", number, "with", len(operations), "ops") - self._log_operations(inputargs, operations) + self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-opt-bridge") def log_short_preamble(self, inputargs, operations): debug_start("jit-log-short-preamble") - self._log_operations(inputargs, operations) + self._log_operations(inputargs, operations, ops_offset=None) debug_stop("jit-log-short-preamble") def repr_of_descr(self, descr): @@ -75,9 +75,11 @@ else: return '?' - def _log_operations(self, inputargs, operations): + def _log_operations(self, inputargs, operations, ops_offset): if not have_debug_prints(): return + if ops_offset is None: + ops_offset = {} memo = {} if inputargs is not None: args = ", ".join([self.repr_of_arg(memo, arg) for arg in inputargs]) @@ -89,6 +91,11 @@ reclev = op.getarg(1).getint() debug_print("debug_merge_point('%s', %s)" % (loc, reclev)) continue + offset = ops_offset.get(op, -1) + if offset == -1: + s_offset = "" + else: + s_offset = "+%d: " % offset args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())]) if op.result is not None: res = self.repr_of_arg(memo, op.result) + " = " @@ -108,8 +115,11 @@ for arg in op.getfailargs()]) + ']' else: fail_args = '' - debug_print(res + op.getopname() + + debug_print(s_offset + res + op.getopname() + '(' + args + ')' + fail_args) + if ops_offset and None in ops_offset: + offset = ops_offset[None] + debug_print("+%d: --end of the loop--" % offset) def int_could_be_an_address(x): diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -15,7 +15,7 @@ def reconstruct_for_next_iteration(self, optimizer, valuemap): return self - + def propagate_forward(self, op): args = self.optimizer.make_args_key(op) if self.find_rewritable_bool(op, args): @@ -40,7 +40,7 @@ return False return self.is_emittable(op) - + def try_boolinvers(self, op, targs): oldop = self.optimizer.pure_operations.get(targs, None) if oldop is not None and oldop.getdescr() is op.getdescr(): @@ -69,7 +69,7 @@ try: oldopnum = opboolreflex[op.getopnum()] # FIXME: add INT_ADD, INT_MUL targs = self.optimizer.make_args_key(ResOperation(oldopnum, [args[1], args[0]], - None)) + None)) oldop = self.optimizer.pure_operations.get(targs, None) if oldop is not None and oldop.getdescr() is op.getdescr(): self.make_equal_to(op.result, self.getvalue(oldop.result)) @@ -80,7 +80,7 @@ try: oldopnum = opboolinvers[opboolreflex[op.getopnum()]] targs = self.optimizer.make_args_key(ResOperation(oldopnum, [args[1], args[0]], - None)) + None)) if self.try_boolinvers(op, targs): return True except KeyError: @@ -157,6 +157,15 @@ self.emit_operation(op) + def optimize_UINT_FLOORDIV(self, op): + v1 = self.getvalue(op.getarg(0)) + v2 = self.getvalue(op.getarg(1)) + + if v2.is_constant() and v2.box.getint() == 1: + self.make_equal_to(op.result, v1) + else: + self.emit_operation(op) + def optimize_INT_LSHIFT(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -322,7 +331,7 @@ self.emit_operation(op) resvalue = self.getvalue(op.result) self.optimizer.loop_invariant_results[key] = resvalue - + def _optimize_nullness(self, op, box, expect_nonnull): value = self.getvalue(box) if value.is_nonnull(): @@ -381,7 +390,7 @@ ## if realclassbox is not None: ## checkclassbox = self.optimizer.cpu.typedescr2classbox(op.descr) ## result = self.optimizer.cpu.ts.subclassOf(self.optimizer.cpu, -## realclassbox, +## realclassbox, ## checkclassbox) ## self.make_constant_int(op.result, result) ## return diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -626,3 +626,25 @@ rop.PTR_EQ: rop.PTR_EQ, rop.PTR_NE: rop.PTR_NE, } + + +def get_deep_immutable_oplist(operations): + """ + When not we_are_translated(), turns ``operations`` into a frozenlist and + monkey-patch its items to make sure they are not mutated. + + When we_are_translated(), do nothing and just return the old list. + """ + from pypy.tool.frozenlist import frozenlist + if we_are_translated(): + return operations + # + def setarg(*args): + assert False, "operations cannot change at this point" + def setdescr(*args): + assert False, "operations cannot change at this point" + newops = frozenlist(operations) + for op in newops: + op.setarg = setarg + op.setdescr = setdescr + return newops diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py --- a/pypy/jit/metainterp/test/test_compile.py +++ b/pypy/jit/metainterp/test/test_compile.py @@ -34,7 +34,7 @@ self.seen.append((inputargs, operations, token)) class FakeLogger(object): - def log_loop(self, inputargs, operations, number=0, type=None): + def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): pass class FakeState(object): diff --git a/pypy/jit/metainterp/test/test_logger.py b/pypy/jit/metainterp/test/test_logger.py --- a/pypy/jit/metainterp/test/test_logger.py +++ b/pypy/jit/metainterp/test/test_logger.py @@ -31,10 +31,10 @@ return log_stream.getvalue() class Logger(logger.Logger): - def log_loop(self, loop, namespace={}): + def log_loop(self, loop, namespace={}, ops_offset=None): self.namespace = namespace return capturing(logger.Logger.log_loop, self, - loop.inputargs, loop.operations) + loop.inputargs, loop.operations, ops_offset=ops_offset) def repr_of_descr(self, descr): for k, v in self.namespace.items(): @@ -178,3 +178,27 @@ output = capturing(bare_logger.log_bridge, [], [], 3) assert output.splitlines()[0] == "# bridge out of Guard 3 with 0 ops" pure_parse(output) + + def test_ops_offset(self): + inp = ''' + [i0] + i1 = int_add(i0, 1) + i2 = int_mul(i1, 2) + jump(i2) + ''' + loop = pure_parse(inp) + ops = loop.operations + ops_offset = { + ops[0]: 10, + ops[2]: 30, + None: 40 + } + logger = Logger(self.make_metainterp_sd()) + output = logger.log_loop(loop, ops_offset=ops_offset) + assert output.strip() == """ +[i0] ++10: i2 = int_add(i0, 1) +i4 = int_mul(i2, 2) ++30: jump(i4) ++40: --end of the loop-- +""".strip() diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py --- a/pypy/jit/metainterp/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/test/test_optimizeopt.py @@ -2843,6 +2843,18 @@ """ self.optimize_loop(ops, expected) + def test_fold_partially_constant_uint_floordiv(self): + ops = """ + [i0] + i1 = uint_floordiv(i0, 1) + jump(i1) + """ + expected = """ + [i0] + jump(i0) + """ + self.optimize_loop(ops, expected) + # ---------- class TestLLtype(OptimizeOptTest, LLtypeMixin): @@ -5746,7 +5758,7 @@ """ expected = """ [] - guard_not_invalidated() [] + guard_not_invalidated() [] escape(-4247) jump() """ diff --git a/pypy/jit/metainterp/test/test_resoperation.py b/pypy/jit/metainterp/test/test_resoperation.py --- a/pypy/jit/metainterp/test/test_resoperation.py +++ b/pypy/jit/metainterp/test/test_resoperation.py @@ -68,3 +68,11 @@ call = rop.ResOperation(rop.rop.CALL, ['a', 'b'], 'c', descr=mydescr) assert call.can_malloc() assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c').can_malloc() + +def test_get_deep_immutable_oplist(): + ops = [rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c')] + newops = rop.get_deep_immutable_oplist(ops) + py.test.raises(AttributeError, "newops.append('foobar')") + py.test.raises(TypeError, "newops[0] = 'foobar'") + py.test.raises(AssertionError, "newops[0].setarg(0, 'd')") + py.test.raises(AssertionError, "newops[0].setdescr('foobar')") diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -18,6 +18,7 @@ def test_unwrap(): S = lltype.GcStruct('S') + RS = lltype.Struct('S') p = lltype.malloc(S) po = lltype.cast_opaque_ptr(llmemory.GCREF, p) assert unwrap(lltype.Void, BoxInt(42)) is None @@ -25,6 +26,7 @@ assert unwrap(lltype.Char, BoxInt(42)) == chr(42) assert unwrap(lltype.Float, boxfloat(42.5)) == 42.5 assert unwrap(lltype.Ptr(S), BoxPtr(po)) == p + assert unwrap(lltype.Ptr(RS), BoxInt(0)) == lltype.nullptr(RS) def test_wrap(): def _is(box1, box2): diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -54,7 +54,10 @@ if TYPE is lltype.Void: return None if isinstance(TYPE, lltype.Ptr): - return box.getref(TYPE) + if TYPE.TO._gckind == "gc": + return box.getref(TYPE) + else: + return llmemory.cast_adr_to_ptr(box.getaddr(), TYPE) if isinstance(TYPE, ootype.OOType): return box.getref(TYPE) if TYPE == lltype.Float: @@ -578,7 +581,7 @@ cell.set_entry_loop_token(entry_loop_token) return entry_loop_token self.get_assembler_token = get_assembler_token - + # get_location_ptr = self.jitdriver_sd._get_printable_location_ptr if get_location_ptr is None: diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -335,7 +335,7 @@ continue # a comment or empty line newlines.append(line) base_indent, inpargs, newlines = self.parse_inpargs(newlines) - num, ops = self.parse_ops(base_indent, newlines, 0) + num, ops, last_offset = self.parse_ops(base_indent, newlines, 0) if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) loop = ExtendedTreeLoop("loop") @@ -343,11 +343,13 @@ loop.token = self.looptoken loop.operations = ops loop.inputargs = inpargs + loop.last_offset = last_offset return loop def parse_ops(self, indent, lines, start): num = start ops = [] + last_offset = None while num < len(lines): line = lines[num] if not line.startswith(" " * indent): @@ -356,9 +358,25 @@ elif line.startswith(" "*(indent + 1)): raise ParseError("indentation not valid any more") else: - ops.append(self.parse_next_op(lines[num].strip())) + line = line.strip() + offset, line = self.parse_offset(line) + if line == '--end of the loop--': + last_offset = offset + else: + op = self.parse_next_op(line) + if offset: + op.offset = offset + ops.append(op) num += 1 - return num, ops + return num, ops, last_offset + + def parse_offset(self, line): + if line.startswith('+'): + # it begins with an offset, like: "+10: i1 = int_add(...)" + offset, _, line = line.partition(':') + offset = int(offset) + return offset, line.strip() + return None, line def parse_inpargs(self, lines): line = lines[0] diff --git a/pypy/jit/tool/test/test_oparser.py b/pypy/jit/tool/test/test_oparser.py --- a/pypy/jit/tool/test/test_oparser.py +++ b/pypy/jit/tool/test/test_oparser.py @@ -1,7 +1,7 @@ - +import py from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.jit.tool.oparser import parse +from pypy.jit.tool.oparser import parse, ParseError from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken,\ BoxFloat @@ -203,3 +203,25 @@ loop = parse(x, nonstrict=True) assert loop.inputargs == [] assert loop.operations[0].getopname() == 'int_add' + +def test_offsets(): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + """ + # +30: --end of the loop-- + loop = parse(x) + assert loop.operations[0].offset == 10 + assert not hasattr(loop.operations[1], 'offset') + +def test_last_offset(): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + +30: --end of the loop-- + """ + loop = parse(x) + assert len(loop.operations) == 2 + assert loop.last_offset == 30 diff --git a/pypy/module/_multibytecodec/__init__.py b/pypy/module/_multibytecodec/__init__.py new file mode 100644 --- /dev/null +++ b/pypy/module/_multibytecodec/__init__.py @@ -0,0 +1,21 @@ +from pypy.interpreter.mixedmodule import MixedModule + + +class Module(MixedModule): + + interpleveldefs = { + # for compatibility this name is obscured, and should be called + # via the _codecs_*.py modules written in lib_pypy. + '__getcodec': 'interp_multibytecodec.getcodec', + } + + appleveldefs = { + 'MultibyteIncrementalEncoder': + 'app_multibytecodec.MultibyteIncrementalEncoder', + 'MultibyteIncrementalDecoder': + 'app_multibytecodec.MultibyteIncrementalDecoder', + 'MultibyteStreamReader': + 'app_multibytecodec.MultibyteStreamReader', + 'MultibyteStreamWriter': + 'app_multibytecodec.MultibyteStreamWriter', + } diff --git a/pypy/module/_multibytecodec/app_multibytecodec.py b/pypy/module/_multibytecodec/app_multibytecodec.py new file mode 100644 --- /dev/null +++ b/pypy/module/_multibytecodec/app_multibytecodec.py @@ -0,0 +1,34 @@ +# NOT_RPYTHON +# +# These classes are not supported so far. +# +# My theory is that they are not widely used on CPython either, because +# I found two bugs just by looking at their .c source: they always call +# encreset() after a piece of data, even though I think it's wrong --- +# it should be called only once at the end; and mbiencoder_reset() calls +# decreset() instead of encreset(). +# + +class MultibyteIncrementalEncoder(object): + def __init__(self, *args, **kwds): + raise LookupError( + "MultibyteIncrementalEncoder not implemented; " + "see pypy/module/_multibytecodec/app_multibytecodec.py") + +class MultibyteIncrementalDecoder(object): + def __init__(self, *args, **kwds): + raise LookupError( + "MultibyteIncrementalDecoder not implemented; " + "see pypy/module/_multibytecodec/app_multibytecodec.py") + +class MultibyteStreamReader(object): + def __init__(self, *args, **kwds): + raise LookupError( + "MultibyteStreamReader not implemented; " + "see pypy/module/_multibytecodec/app_multibytecodec.py") + +class MultibyteStreamWriter(object): + def __init__(self, *args, **kwds): + raise LookupError( + "MultibyteStreamWriter not implemented; " + "see pypy/module/_multibytecodec/app_multibytecodec.py") diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py new file mode 100644 --- /dev/null +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -0,0 +1,212 @@ +import py, sys +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.translator.tool.cbuild import ExternalCompilationInfo +from pypy.tool.autopath import pypydir + + +class EncodeDecodeError(Exception): + def __init__(self, start, end, reason): + self.start = start + self.end = end + self.reason = reason + def __repr__(self): + return 'EncodeDecodeError(%r, %r, %r)' % (self.start, self.end, + self.reason) + +srcdir = py.path.local(pypydir).join('translator', 'c') + +codecs = [ + # _codecs_cn + 'gb2312', 'gbk', 'gb18030', 'hz', + + # _codecs_hk + 'big5hkscs', + + # _codecs_iso2022 + 'iso2022_kr', 'iso2022_jp', 'iso2022_jp_1', 'iso2022_jp_2', + 'iso2022_jp_2004', 'iso2022_jp_3', 'iso2022_jp_ext', + + # _codecs_jp + 'shift_jis', 'cp932', 'euc_jp', 'shift_jis_2004', + 'euc_jis_2004', 'euc_jisx0213', 'shift_jisx0213', + + # _codecs_kr + 'euc_kr', 'cp949', 'johab', + + # _codecs_tw + 'big5', 'cp950', +] + +eci = ExternalCompilationInfo( + separate_module_files = [ + srcdir.join('src', 'cjkcodecs', '_codecs_cn.c'), + srcdir.join('src', 'cjkcodecs', '_codecs_hk.c'), + srcdir.join('src', 'cjkcodecs', '_codecs_iso2022.c'), + srcdir.join('src', 'cjkcodecs', '_codecs_jp.c'), + srcdir.join('src', 'cjkcodecs', '_codecs_kr.c'), + srcdir.join('src', 'cjkcodecs', '_codecs_tw.c'), + srcdir.join('src', 'cjkcodecs', 'multibytecodec.c'), + ], + includes = ['src/cjkcodecs/multibytecodec.h'], + include_dirs = [str(srcdir)], + export_symbols = [ + "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", + "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", + "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + + "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", + "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", + "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], +) + +MBERR_TOOSMALL = -1 # insufficient output buffer space +MBERR_TOOFEW = -2 # incomplete input buffer +MBERR_INTERNAL = -3 # internal runtime error +MBERR_NOMEMORY = -4 # out of memory + +MULTIBYTECODEC_P = rffi.COpaquePtr('struct MultibyteCodec_s', + compilation_info=eci) + +def llexternal(*args, **kwds): + kwds.setdefault('compilation_info', eci) + kwds.setdefault('sandboxsafe', True) + kwds.setdefault('_nowrapper', True) + return rffi.llexternal(*args, **kwds) + +def getter_for(name): + return llexternal('pypy_cjkcodec_%s' % name, [], MULTIBYTECODEC_P) + +_codecs_getters = dict([(name, getter_for(name)) for name in codecs]) +assert len(_codecs_getters) == len(codecs) + +def getcodec(name): + getter = _codecs_getters[name] + return getter() + +# ____________________________________________________________ +# Decoding + +DECODEBUF_P = rffi.COpaquePtr('struct pypy_cjk_dec_s', compilation_info=eci) +pypy_cjk_dec_init = llexternal('pypy_cjk_dec_init', + [MULTIBYTECODEC_P, rffi.CCHARP, rffi.SSIZE_T], + DECODEBUF_P) +pypy_cjk_dec_free = llexternal('pypy_cjk_dec_free', [DECODEBUF_P], + lltype.Void) +pypy_cjk_dec_chunk = llexternal('pypy_cjk_dec_chunk', [DECODEBUF_P], + rffi.SSIZE_T) +pypy_cjk_dec_outbuf = llexternal('pypy_cjk_dec_outbuf', [DECODEBUF_P], + rffi.CWCHARP) +pypy_cjk_dec_outlen = llexternal('pypy_cjk_dec_outlen', [DECODEBUF_P], + rffi.SSIZE_T) +pypy_cjk_dec_inbuf_remaining = llexternal('pypy_cjk_dec_inbuf_remaining', + [DECODEBUF_P], rffi.SSIZE_T) +pypy_cjk_dec_inbuf_consumed = llexternal('pypy_cjk_dec_inbuf_consumed', + [DECODEBUF_P], rffi.SSIZE_T) + +def decode(codec, stringdata): + inleft = len(stringdata) + inbuf = rffi.get_nonmovingbuffer(stringdata) + try: + decodebuf = pypy_cjk_dec_init(codec, inbuf, inleft) + if not decodebuf: + raise MemoryError + try: + r = pypy_cjk_dec_chunk(decodebuf) + if r != 0: + multibytecodec_decerror(decodebuf, r) + assert False + src = pypy_cjk_dec_outbuf(decodebuf) + length = pypy_cjk_dec_outlen(decodebuf) + return rffi.wcharpsize2unicode(src, length) + # + finally: + pypy_cjk_dec_free(decodebuf) + # + finally: + rffi.free_nonmovingbuffer(stringdata, inbuf) + +def multibytecodec_decerror(decodebuf, e): + if e > 0: + reason = "illegal multibyte sequence" + esize = e + elif e == MBERR_TOOFEW: + reason = "incomplete multibyte sequence" + esize = pypy_cjk_dec_inbuf_remaining(decodebuf) + elif e == MBERR_NOMEMORY: + raise MemoryError + else: + raise RuntimeError + # + # if errors == ERROR_REPLACE:... + # if errors == ERROR_IGNORE or errors == ERROR_REPLACE:... + start = pypy_cjk_dec_inbuf_consumed(decodebuf) + end = start + esize + if 1: # errors == ERROR_STRICT: + raise EncodeDecodeError(start, end, reason) + +# ____________________________________________________________ +# Encoding +ENCODEBUF_P = rffi.COpaquePtr('struct pypy_cjk_enc_s', compilation_info=eci) +pypy_cjk_enc_init = llexternal('pypy_cjk_enc_init', + [MULTIBYTECODEC_P, rffi.CWCHARP, rffi.SSIZE_T], + ENCODEBUF_P) +pypy_cjk_enc_free = llexternal('pypy_cjk_enc_free', [ENCODEBUF_P], + lltype.Void) +pypy_cjk_enc_chunk = llexternal('pypy_cjk_enc_chunk', [ENCODEBUF_P], + rffi.SSIZE_T) +pypy_cjk_enc_reset = llexternal('pypy_cjk_enc_reset', [ENCODEBUF_P], + rffi.SSIZE_T) +pypy_cjk_enc_outbuf = llexternal('pypy_cjk_enc_outbuf', [ENCODEBUF_P], + rffi.CCHARP) +pypy_cjk_enc_outlen = llexternal('pypy_cjk_enc_outlen', [ENCODEBUF_P], + rffi.SSIZE_T) +pypy_cjk_enc_inbuf_remaining = llexternal('pypy_cjk_enc_inbuf_remaining', + [ENCODEBUF_P], rffi.SSIZE_T) +pypy_cjk_enc_inbuf_consumed = llexternal('pypy_cjk_enc_inbuf_consumed', + [ENCODEBUF_P], rffi.SSIZE_T) + +def encode(codec, unicodedata): + inleft = len(unicodedata) + inbuf = rffi.get_nonmoving_unicodebuffer(unicodedata) + try: + encodebuf = pypy_cjk_enc_init(codec, inbuf, inleft) + if not encodebuf: + raise MemoryError + try: + r = pypy_cjk_enc_chunk(encodebuf) + if r != 0: + multibytecodec_encerror(encodebuf, r) + assert False + r = pypy_cjk_enc_reset(encodebuf) + if r != 0: + multibytecodec_encerror(encodebuf, r) + assert False + src = pypy_cjk_enc_outbuf(encodebuf) + length = pypy_cjk_enc_outlen(encodebuf) + return rffi.charpsize2str(src, length) + # + finally: + pypy_cjk_enc_free(encodebuf) + # + finally: + rffi.free_nonmoving_unicodebuffer(unicodedata, inbuf) + +def multibytecodec_encerror(encodebuf, e): + if e > 0: + reason = "illegal multibyte sequence" + esize = e + elif e == MBERR_TOOFEW: + reason = "incomplete multibyte sequence" + esize = pypy_cjk_enc_inbuf_remaining(encodebuf) + elif e == MBERR_NOMEMORY: + raise MemoryError + else: + raise RuntimeError + # + # if errors == ERROR_REPLACE:... + # if errors == ERROR_IGNORE or errors == ERROR_REPLACE:... + start = pypy_cjk_enc_inbuf_consumed(encodebuf) + end = start + esize + if 1: # errors == ERROR_STRICT: + raise EncodeDecodeError(start, end, reason) diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py new file mode 100644 --- /dev/null +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -0,0 +1,79 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.gateway import ObjSpace, interp2app +from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.error import OperationError +from pypy.module._multibytecodec import c_codecs + + +class MultibyteCodec(Wrappable): + + def __init__(self, name, codec): + self.name = name + self.codec = codec + + def decode(self, space, input, errors=None): + if errors is not None and errors != 'strict': + raise OperationError(space.w_NotImplementedError, # XXX + space.wrap("errors='%s' in _multibytecodec" + % errors)) + # + try: + output = c_codecs.decode(self.codec, input) + except c_codecs.EncodeDecodeError, e: + raise OperationError( + space.w_UnicodeDecodeError, + space.newtuple([ + space.wrap(self.name), + space.wrap(input), + space.wrap(e.start), + space.wrap(e.end), + space.wrap(e.reason)])) + except RuntimeError: + raise OperationError(space.w_RuntimeError, + space.wrap("internal codec error")) + return space.newtuple([space.wrap(output), + space.wrap(len(input))]) + decode.unwrap_spec = ['self', ObjSpace, str, 'str_or_None'] + + def encode(self, space, input, errors=None): + if errors is not None and errors != 'strict': + raise OperationError(space.w_NotImplementedError, # XXX + space.wrap("errors='%s' in _multibytecodec" + % errors)) + # + try: + output = c_codecs.encode(self.codec, input) + except c_codecs.EncodeDecodeError, e: + raise OperationError( + space.w_UnicodeEncodeError, + space.newtuple([ + space.wrap(self.name), + space.wrap(input), + space.wrap(e.start), + space.wrap(e.end), + space.wrap(e.reason)])) + except RuntimeError: + raise OperationError(space.w_RuntimeError, + space.wrap("internal codec error")) + return space.newtuple([space.wrap(output), + space.wrap(len(input))]) + encode.unwrap_spec = ['self', ObjSpace, unicode, 'str_or_None'] + + +MultibyteCodec.typedef = TypeDef( + 'MultibyteCodec', + __module__ = '_multibytecodec', + decode = interp2app(MultibyteCodec.decode), + encode = interp2app(MultibyteCodec.encode), + ) +MultibyteCodec.typedef.acceptable_as_base_class = False + + +def getcodec(space, name): + try: + codec = c_codecs.getcodec(name) + except KeyError: + raise OperationError(space.w_LookupError, + space.wrap("no such codec is supported.")) + return space.wrap(MultibyteCodec(name, codec)) +getcodec.unwrap_spec = [ObjSpace, str] diff --git a/pypy/module/_multibytecodec/test/__init__.py b/pypy/module/_multibytecodec/test/__init__.py new file mode 100644 --- /dev/null +++ b/pypy/module/_multibytecodec/test/__init__.py @@ -0,0 +1,1 @@ +# diff --git a/pypy/module/_multibytecodec/test/test_app_codecs.py b/pypy/module/_multibytecodec/test/test_app_codecs.py new file mode 100644 --- /dev/null +++ b/pypy/module/_multibytecodec/test/test_app_codecs.py @@ -0,0 +1,56 @@ +from pypy.conftest import gettestobjspace + + +class AppTestCodecs: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['_multibytecodec']) + + def test_missing_codec(self): + import _codecs_cn + raises(LookupError, _codecs_cn.getcodec, "foobar") + + def test_decode_hz(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.decode("~{abc}") + assert r == (u'\u5f95\u6cef', 6) + + def test_strict_error(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.decode("~{abc}", "strict") + assert r == (u'\u5f95\u6cef', 6) + assert type(r[0]) is unicode + + def test_decode_hz_error(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + e = raises(UnicodeDecodeError, codec.decode, "~{}").value + assert e.args == ('hz', '~{}', 2, 3, 'incomplete multibyte sequence') + assert e.encoding == 'hz' + assert e.object == '~{}' and type(e.object) is str + assert e.start == 2 + assert e.end == 3 + assert e.reason == "incomplete multibyte sequence" + # + e = raises(UnicodeDecodeError, codec.decode, "~{xyz}").value + assert e.args == ('hz', '~{xyz}', 2, 4, 'illegal multibyte sequence') + + def test_encode_hz(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.encode(u'\u5f95\u6cef') + assert r == ('~{abc}~}', 2) + assert type(r[0]) is str + + def test_encode_hz_error(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + u = u'abc\u1234def' + e = raises(UnicodeEncodeError, codec.encode, u).value + assert e.args == ('hz', u, 3, 4, 'illegal multibyte sequence') + assert e.encoding == 'hz' + assert e.object == u and type(e.object) is unicode + assert e.start == 3 + assert e.end == 4 + assert e.reason == 'illegal multibyte sequence' diff --git a/pypy/module/_multibytecodec/test/test_c_codecs.py b/pypy/module/_multibytecodec/test/test_c_codecs.py new file mode 100644 --- /dev/null +++ b/pypy/module/_multibytecodec/test/test_c_codecs.py @@ -0,0 +1,57 @@ +import py +from pypy.module._multibytecodec.c_codecs import getcodec, codecs +from pypy.module._multibytecodec.c_codecs import decode, encode +from pypy.module._multibytecodec.c_codecs import EncodeDecodeError + + +def test_codecs_existence(): + for name in codecs: + c = getcodec(name) + assert c + py.test.raises(KeyError, getcodec, "foobar") + +def test_decode_gbk(): + c = getcodec("gbk") + u = decode(c, "\xA1\xAA") + assert u == unichr(0x2014) + u = decode(c, "foobar") + assert u == u"foobar" + +def test_decode_hz(): + # stateful + c = getcodec("hz") + u = decode(c, "~{abc}") + assert u == u'\u5f95\u6cef' + +def test_decode_hz_error(): + # error + c = getcodec("hz") + e = py.test.raises(EncodeDecodeError, decode, c, "~{}").value + assert e.start == 2 + assert e.end == 3 + assert e.reason == "incomplete multibyte sequence" + # + e = py.test.raises(EncodeDecodeError, decode, c, "~{xyz}").value + assert e.start == 2 + assert e.end == 4 + assert e.reason == "illegal multibyte sequence" + +def test_encode_hz(): + c = getcodec("hz") + s = encode(c, u'foobar') + assert s == 'foobar' and type(s) is str + s = encode(c, u'\u5f95\u6cef') + assert s == '~{abc}~}' + +def test_encode_hz_error(): + # error + c = getcodec("hz") + e = py.test.raises(EncodeDecodeError, encode, c, u'abc\u1234def').value + assert e.start == 3 + assert e.end == 4 + assert e.reason == "illegal multibyte sequence" + +def test_encode_jisx0208(): + c = getcodec('iso2022_jp') + s = encode(c, u'\u83ca\u5730\u6642\u592b') + assert s == '\x1b$B5FCO;~IW\x1b(B' and type(s) is str diff --git a/pypy/module/_multibytecodec/test/test_translation.py b/pypy/module/_multibytecodec/test/test_translation.py new file mode 100644 --- /dev/null +++ b/pypy/module/_multibytecodec/test/test_translation.py @@ -0,0 +1,20 @@ +from pypy.module._multibytecodec import c_codecs +from pypy.translator.c.test import test_standalone + + +class TestTranslation(test_standalone.StandaloneTests): + + def test_translation(self): + # + def entry_point(argv): + codecname, string = argv[1], argv[2] + c = c_codecs.getcodec(codecname) + u = c_codecs.decode(c, string) + r = c_codecs.encode(c, u) + print r + return 0 + # + t, cbuilder = self.compile(entry_point) + cmd = 'hz "~{abc}"' + data = cbuilder.cmdexec(cmd) + assert data == '~{abc}~}\n' diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py --- a/pypy/module/_socket/test/test_sock_app.py +++ b/pypy/module/_socket/test/test_sock_app.py @@ -372,11 +372,12 @@ def test_socket_connect(self): import _socket, os s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM, 0) - # XXX temporarily we use codespeak to test, will have more robust tests in - # the absence of a network connection later when more parts of the socket - # API are implemented. currently skip the test if there is no connection. + # XXX temporarily we use python.org to test, will have more robust tests + # in the absence of a network connection later when more parts of the + # socket API are implemented. Currently skip the test if there is no + # connection. try: - s.connect(("codespeak.net", 80)) + s.connect(("www.python.org", 80)) except _socket.gaierror, ex: skip("GAIError - probably no connection: %s" % str(ex.args)) name = s.getpeername() # Will raise socket.error if not connected @@ -506,11 +507,12 @@ # Test that send/sendall/sendto accept a buffer or a unicode as arg import _socket, os s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM, 0) - # XXX temporarily we use codespeak to test, will have more robust tests in - # the absence of a network connection later when more parts of the socket - # API are implemented. currently skip the test if there is no connection. + # XXX temporarily we use python.org to test, will have more robust tests + # in the absence of a network connection later when more parts of the + # socket API are implemented. Currently skip the test if there is no + # connection. try: - s.connect(("codespeak.net", 80)) + s.connect(("www.python.org", 80)) except _socket.gaierror, ex: skip("GAIError - probably no connection: %s" % str(ex.args)) s.send(buffer('')) diff --git a/pypy/module/_ssl/__init__.py b/pypy/module/_ssl/__init__.py --- a/pypy/module/_ssl/__init__.py +++ b/pypy/module/_ssl/__init__.py @@ -7,6 +7,7 @@ interpleveldefs = { 'sslwrap': 'interp_ssl.sslwrap', 'SSLError': 'interp_ssl.get_error(space)', + '_test_decode_cert': 'interp_ssl._test_decode_cert', } appleveldefs = { @@ -30,3 +31,5 @@ def startup(self, space): from pypy.rlib.ropenssl import init_ssl init_ssl() + from pypy.module._ssl.interp_ssl import setup_ssl_threads + setup_ssl_threads() diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -4,6 +4,7 @@ from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll, rsocket from pypy.rlib.ropenssl import * @@ -68,11 +69,8 @@ def ssl_error(space, msg, errno=0): w_exception_class = get_error(space) - if errno: - w_exception = space.call_function(w_exception_class, - space.wrap(errno), space.wrap(msg)) - else: - w_exception = space.call_function(w_exception_class, space.wrap(msg)) + w_exception = space.call_function(w_exception_class, + space.wrap(errno), space.wrap(msg)) return OperationError(w_exception_class, w_exception) if HAVE_OPENSSL_RAND: @@ -169,10 +167,10 @@ num_bytes = 0 while True: err = 0 - + num_bytes = libssl_SSL_write(self.ssl, data, len(data)) err = libssl_SSL_get_error(self.ssl, num_bytes) - + if err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout(self.space, self.w_socket, False) @@ -181,24 +179,34 @@ self.w_socket, True) else: sockstate = SOCKET_OPERATION_OK - + if sockstate == SOCKET_HAS_TIMED_OUT: raise ssl_error(self.space, "The write operation timed out") elif sockstate == SOCKET_HAS_BEEN_CLOSED: raise ssl_error(self.space, "Underlying socket has been closed.") elif sockstate == SOCKET_IS_NONBLOCKING: break - + if err == SSL_ERROR_WANT_READ or err == SSL_ERROR_WANT_WRITE: continue else: break - + if num_bytes > 0: return self.space.wrap(num_bytes) else: raise _ssl_seterror(self.space, self, num_bytes) + def pending(self): + """pending() -> count + + Returns the number of already decrypted bytes available for read, + pending on the connection.""" + count = libssl_SSL_pending(self.ssl) + if count < 0: + raise _ssl_seterror(self.space, self, count) + return self.space.wrap(count) + @unwrap_spec(num_bytes=int) def read(self, num_bytes=1024): """read([len]) -> string @@ -369,18 +377,263 @@ return self.w_socket + def cipher(self, space): + if not self.ssl: + return space.w_None + current = libssl_SSL_get_current_cipher(self.ssl) + if not current: + return space.w_None + + name = libssl_SSL_CIPHER_get_name(current) + if name: + w_name = space.wrap(rffi.charp2str(name)) + else: + w_name = space.w_None + + proto = libssl_SSL_CIPHER_get_version(current) + if proto: + w_proto = space.wrap(rffi.charp2str(name)) + else: + w_proto = space.w_None + + bits = libssl_SSL_CIPHER_get_bits(current, + lltype.nullptr(rffi.INTP.TO)) + w_bits = space.newint(bits) + + return space.newtuple([w_name, w_proto, w_bits]) + + @unwrap_spec(der=bool) + def peer_certificate(self, der=False): + """peer_certificate([der=False]) -> certificate + + Returns the certificate for the peer. If no certificate was provided, + returns None. If a certificate was provided, but not validated, returns + an empty dictionary. Otherwise returns a dict containing information + about the peer certificate. + + If the optional argument is True, returns a DER-encoded copy of the + peer certificate, or None if no certificate was provided. This will + return the certificate even if it wasn't validated.""" + if not self.peer_cert: + return self.space.w_None + + if der: + # return cert in DER-encoded format + with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as buf_ptr: + buf_ptr[0] = lltype.nullptr(rffi.CCHARP.TO) + length = libssl_i2d_X509(self.peer_cert, buf_ptr) + if length < 0: + raise _ssl_seterror(self.space, self, length) + try: + # this is actually an immutable bytes sequence + return self.space.wrap(rffi.charp2str(buf_ptr[0])) + finally: + libssl_OPENSSL_free(buf_ptr[0]) + else: + verification = libssl_SSL_CTX_get_verify_mode( + libssl_SSL_get_SSL_CTX(self.ssl)) + if not verification & SSL_VERIFY_PEER: + return self.space.newdict() + else: + return _decode_certificate(self.space, self.peer_cert) + +def _decode_certificate(space, certificate, verbose=False): + w_retval = space.newdict() + + w_peer = _create_tuple_for_X509_NAME( + space, libssl_X509_get_subject_name(certificate)) + space.setitem(w_retval, space.wrap("subject"), w_peer) + + if verbose: + w_issuer = _create_tuple_for_X509_NAME( + space, libssl_X509_get_issuer_name(certificate)) + space.setitem(w_retval, space.wrap("issuer"), w_issuer) + + space.setitem(w_retval, space.wrap("version"), + space.wrap(libssl_X509_get_version(certificate))) + + biobuf = libssl_BIO_new(libssl_BIO_s_mem()) + try: + + if verbose: + libssl_BIO_reset(biobuf) + serialNumber = libssl_X509_get_serialNumber(certificate) + libssl_i2a_ASN1_INTEGER(biobuf, serialNumber) + # should not exceed 20 octets, 160 bits, so buf is big enough + with lltype.scoped_alloc(rffi.CCHARP.TO, 100) as buf: + length = libssl_BIO_gets(biobuf, buf, 99) + if length < 0: + raise _ssl_seterror(space, None, length) + + w_serial = space.wrap(rffi.charpsize2str(buf, length)) + space.setitem(w_retval, space.wrap("serialNumber"), w_serial) + + libssl_BIO_reset(biobuf) + notBefore = libssl_X509_get_notBefore(certificate) + libssl_ASN1_TIME_print(biobuf, notBefore) + with lltype.scoped_alloc(rffi.CCHARP.TO, 100) as buf: + length = libssl_BIO_gets(biobuf, buf, 99) + if length < 0: + raise _ssl_seterror(space, None, length) + w_date = space.wrap(rffi.charpsize2str(buf, length)) + space.setitem(w_retval, space.wrap("notBefore"), w_date) + + libssl_BIO_reset(biobuf) + notAfter = libssl_X509_get_notAfter(certificate) + libssl_ASN1_TIME_print(biobuf, notAfter) + with lltype.scoped_alloc(rffi.CCHARP.TO, 100) as buf: + length = libssl_BIO_gets(biobuf, buf, 99) + if length < 0: + raise _ssl_seterror(space, None, length) + w_date = space.wrap(rffi.charpsize2str(buf, length)) + space.setitem(w_retval, space.wrap("notAfter"), w_date) + finally: + libssl_BIO_free(biobuf) + + # Now look for subjectAltName + w_alt_names = _get_peer_alt_names(space, certificate) + if w_alt_names is not space.w_None: + space.setitem(w_retval, space.wrap("subjectAltName"), w_alt_names) + + return w_retval + +def _create_tuple_for_X509_NAME(space, xname): + entry_count = libssl_X509_NAME_entry_count(xname) + dn_w = [] + rdn_w = [] + rdn_level = -1 + for index in range(entry_count): + entry = libssl_X509_NAME_get_entry(xname, index) + # check to see if we've gotten to a new RDN + entry_level = intmask(entry[0].c_set) + if rdn_level >= 0: + if rdn_level != entry_level: + # yes, new RDN + # add old RDN to DN + dn_w.append(space.newtuple(list(rdn_w))) + rdn_w = [] + rdn_level = entry_level + + # Now add this attribute to the current RDN + name = libssl_X509_NAME_ENTRY_get_object(entry) + value = libssl_X509_NAME_ENTRY_get_data(entry) + attr = _create_tuple_for_attribute(space, name, value) + rdn_w.append(attr) + + # Now, there is typically a dangling RDN + if rdn_w: + dn_w.append(space.newtuple(list(rdn_w))) + return space.newtuple(list(dn_w)) + +def _get_peer_alt_names(space, certificate): + # this code follows the procedure outlined in + # OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print() + # function to extract the STACK_OF(GENERAL_NAME), + # then iterates through the stack to add the + # names. + + if not certificate: + return space.w_None + + # get a memory buffer + biobuf = libssl_BIO_new(libssl_BIO_s_mem()) + + try: + alt_names_w = [] + i = 0 + while True: + i = libssl_X509_get_ext_by_NID( + certificate, NID_subject_alt_name, i) + if i < 0: + break + + # now decode the altName + ext = libssl_X509_get_ext(certificate, i) + method = libssl_X509V3_EXT_get(ext) + if not method: + raise ssl_error(space, + "No method for internalizing subjectAltName!'") + + with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr: + p_ptr[0] = ext[0].c_value.c_data + length = intmask(ext[0].c_value.c_length) + null = lltype.nullptr(rffi.VOIDP.TO) + if method[0].c_it: + names = rffi.cast(GENERAL_NAMES, libssl_ASN1_item_d2i( + null, p_ptr, length, + libssl_ASN1_ITEM_ptr(method[0].c_it))) + else: + names = rffi.cast(GENERAL_NAMES, method[0].c_d2i( + null, p_ptr, length)) + + for j in range(libssl_sk_GENERAL_NAME_num(names)): + # Get a rendering of each name in the set of names + + name = libssl_sk_GENERAL_NAME_value(names, j) + if intmask(name[0].c_type) == GEN_DIRNAME: + + # we special-case DirName as a tuple of tuples of attributes + dirname = libssl_pypy_GENERAL_NAME_dirn(name) + w_t = space.newtuple([ + space.wrap("DirName"), + _create_tuple_for_X509_NAME(space, dirname) + ]) + else: + + # for everything else, we use the OpenSSL print form + + libssl_BIO_reset(biobuf) + libssl_GENERAL_NAME_print(biobuf, name) + with lltype.scoped_alloc(rffi.CCHARP.TO, 2048) as buf: + length = libssl_BIO_gets(biobuf, buf, 2047) + if length < 0: + raise _ssl_seterror(space, None, 0) + + v = rffi.charpsize2str(buf, length) + v1, v2 = v.split(':', 1) + w_t = space.newtuple([space.wrap(v1), + space.wrap(v2)]) + + alt_names_w.append(w_t) + finally: + libssl_BIO_free(biobuf) + + if alt_names_w: + return space.newtuple(list(alt_names_w)) + else: + return space.w_None + +def _create_tuple_for_attribute(space, name, value): + with lltype.scoped_alloc(rffi.CCHARP.TO, X509_NAME_MAXLEN) as buf: + length = libssl_OBJ_obj2txt(buf, X509_NAME_MAXLEN, name, 0) + if length < 0: + raise _ssl_seterror(space, None, 0) + w_name = space.wrap(rffi.charpsize2str(buf, length)) + + with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as buf_ptr: + length = libssl_ASN1_STRING_to_UTF8(buf_ptr, value) + if length < 0: + raise _ssl_seterror(space, None, 0) + w_value = space.wrap(rffi.charpsize2str(buf_ptr[0], length)) + w_value = space.call_method(w_value, "decode", space.wrap("utf-8")) + + return space.newtuple([w_name, w_value]) SSLObject.typedef = TypeDef("SSLObject", server = interp2app(SSLObject.server), issuer = interp2app(SSLObject.issuer), write = interp2app(SSLObject.write), + pending = interp2app(SSLObject.pending), read = interp2app(SSLObject.read), - do_handshake=interp2app(SSLObject.do_handshake), - shutdown=interp2app(SSLObject.shutdown), + do_handshake = interp2app(SSLObject.do_handshake), + shutdown = interp2app(SSLObject.shutdown), + cipher = interp2app(SSLObject.cipher), + peer_certificate = interp2app(SSLObject.peer_certificate), ) -def new_sslobject(space, w_sock, side, w_key_file, w_cert_file): +def new_sslobject(space, w_sock, side, w_key_file, w_cert_file, + cert_mode, protocol, w_cacerts_file, w_ciphers): ss = SSLObject(space) sock_fd = space.int_w(space.call_method(w_sock, "fileno")) @@ -397,18 +650,47 @@ cert_file = None else: cert_file = space.str_w(w_cert_file) + if space.is_w(w_cacerts_file, space.w_None): + cacerts_file = None + else: + cacerts_file = space.str_w(w_cacerts_file) + if space.is_w(w_ciphers, space.w_None): + ciphers = None + else: + ciphers = space.str_w(w_ciphers) if side == PY_SSL_SERVER and (not key_file or not cert_file): raise ssl_error(space, "Both the key & certificate files " "must be specified for server-side operation") - ss.ctx = libssl_SSL_CTX_new(libssl_SSLv23_method()) # set up context + # set up context + if protocol == PY_SSL_VERSION_TLS1: + method = libssl_TLSv1_method() + elif protocol == PY_SSL_VERSION_SSL3: + method = libssl_SSLv3_method() + elif protocol == PY_SSL_VERSION_SSL2: + method = libssl_SSLv2_method() + elif protocol == PY_SSL_VERSION_SSL23: + method = libssl_SSLv23_method() + else: + raise ssl_error(space, "Invalid SSL protocol variant specified") + ss.ctx = libssl_SSL_CTX_new(method) if not ss.ctx: - raise ssl_error(space, "Invalid SSL protocol variant specified") + raise ssl_error(space, "Could not create SSL context") - # XXX SSL_CTX_set_cipher_list? + if ciphers: + ret = libssl_SSL_CTX_set_cipher_list(ss.ctx, ciphers) + if ret == 0: + raise ssl_error(space, "No cipher can be selected.") - # XXX SSL_CTX_load_verify_locations? + if cert_mode != PY_SSL_CERT_NONE: + if not cacerts_file: + raise ssl_error(space, + "No root certificates specified for " + "verification of other-side certificates.") + ret = libssl_SSL_CTX_load_verify_locations(ss.ctx, cacerts_file, None) + if ret != 1: + raise _ssl_seterror(space, None, 0) if key_file: ret = libssl_SSL_CTX_use_PrivateKey_file(ss.ctx, key_file, @@ -423,7 +705,12 @@ # ssl compatibility libssl_SSL_CTX_set_options(ss.ctx, SSL_OP_ALL) - libssl_SSL_CTX_set_verify(ss.ctx, SSL_VERIFY_NONE, None) # set verify level + verification_mode = SSL_VERIFY_NONE + if cert_mode == PY_SSL_CERT_OPTIONAL: + verification_mode = SSL_VERIFY_PEER + elif cert_mode == PY_SSL_CERT_REQUIRED: + verification_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT + libssl_SSL_CTX_set_verify(ss.ctx, verification_mode, None) ss.ssl = libssl_SSL_new(ss.ctx) # new ssl struct libssl_SSL_set_fd(ss.ssl, sock_fd) # set the socket for SSL libssl_SSL_set_mode(ss.ssl, SSL_MODE_AUTO_RETRY) @@ -432,8 +719,8 @@ # to non-blocking mode (blocking is the default) if has_timeout: # Set both the read and write BIO's to non-blocking mode - libssl_BIO_ctrl(libssl_SSL_get_rbio(ss.ssl), BIO_C_SET_NBIO, 1, None) - libssl_BIO_ctrl(libssl_SSL_get_wbio(ss.ssl), BIO_C_SET_NBIO, 1, None) + libssl_BIO_set_nbio(libssl_SSL_get_rbio(ss.ssl), 1) + libssl_BIO_set_nbio(libssl_SSL_get_wbio(ss.ssl), 1) libssl_SSL_set_connect_state(ss.ssl) if side == PY_SSL_CLIENT: @@ -494,7 +781,10 @@ def _ssl_seterror(space, ss, ret): assert ret <= 0 - err = libssl_SSL_get_error(ss.ssl, ret) + if ss and ss.ssl: + err = libssl_SSL_get_error(ss.ssl, ret) + else: + err = SSL_ERROR_SSL errstr = "" errval = 0 @@ -546,10 +836,12 @@ @unwrap_spec(side=int, cert_mode=int, protocol=int) def sslwrap(space, w_socket, side, w_key_file=None, w_cert_file=None, cert_mode=PY_SSL_CERT_NONE, protocol=PY_SSL_VERSION_SSL23, - w_cacerts_file=None, w_cipher=None): + w_cacerts_file=None, w_ciphers=None): """sslwrap(socket, side, [keyfile, certfile]) -> sslobject""" return space.wrap(new_sslobject( - space, w_socket, side, w_key_file, w_cert_file)) + space, w_socket, side, w_key_file, w_cert_file, + cert_mode, protocol, + w_cacerts_file, w_ciphers)) class Cache: def __init__(self, space): @@ -559,3 +851,59 @@ def get_error(space): return space.fromcache(Cache).w_error + + at unwrap_spec(filename=str, verbose=bool) +def _test_decode_cert(space, filename, verbose=True): + cert = libssl_BIO_new(libssl_BIO_s_file()) + if not cert: + raise ssl_error(space, "Can't malloc memory to read file") + + try: + if libssl_BIO_read_filename(cert, filename) <= 0: + raise ssl_error(space, "Can't open file") + + x = libssl_PEM_read_bio_X509_AUX(cert, None, None, None) + if not x: + raise ssl_error(space, "Error decoding PEM-encoded file") + + try: + return _decode_certificate(space, x, verbose) + finally: + libssl_X509_free(x) + finally: + libssl_BIO_free(cert) + +# this function is needed to perform locking on shared data +# structures. (Note that OpenSSL uses a number of global data +# structures that will be implicitly shared whenever multiple threads +# use OpenSSL.) Multi-threaded applications will crash at random if +# it is not set. +# +# locking_function() must be able to handle up to CRYPTO_num_locks() +# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and +# releases it otherwise. +# +# filename and line are the file number of the function setting the +# lock. They can be useful for debugging. +_ssl_locks = [] + +def _ssl_thread_locking_function(mode, n, filename, line): + n = intmask(n) + if n < 0 or n >= len(_ssl_locks): + return + + if intmask(mode) & CRYPTO_LOCK: + _ssl_locks[n].acquire(True) + else: + _ssl_locks[n].release() + +def _ssl_thread_id_function(): + from pypy.module.thread import ll_thread + return rffi.cast(rffi.INT, ll_thread.get_ident()) + +def setup_ssl_threads(): + from pypy.module.thread import ll_thread + for i in range(libssl_CRYPTO_num_locks()): + _ssl_locks.append(ll_thread.allocate_lock()) + libssl_CRYPTO_set_locking_callback(_ssl_thread_locking_function) + libssl_CRYPTO_set_id_callback(_ssl_thread_id_function) diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py --- a/pypy/module/_ssl/test/test_ssl.py +++ b/pypy/module/_ssl/test/test_ssl.py @@ -81,7 +81,7 @@ ss = _ssl.sslwrap(s, 0) s.close() exc = raises(_ssl.SSLError, ss.write, "data") - assert exc.value.message == "Underlying socket has been closed." + assert exc.value.strerror == "Underlying socket has been closed." class AppTestConnectedSSL: @@ -90,8 +90,8 @@ cls.space = space def setup_method(self, method): - # https://codespeak.net/ - ADDR = "codespeak.net", 443 + # https://www.verisign.net/ + ADDR = "www.verisign.net", 443 self.w_s = self.space.appexec([self.space.wrap(ADDR)], """(ADDR): import socket @@ -146,6 +146,7 @@ data = ss.read(10) assert isinstance(data, str) assert len(data) == 10 + assert ss.pending() > 50 # many more bytes to read self.s.close() def test_shutdown(self): diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -12,9 +12,21 @@ appleveldefs = { } + atexit_funcs = [] + def startup(self, space): space.fromcache(State).startup(space) + def register_atexit(self, function): + if len(self.atexit_funcs) >= 32: + raise ValueError("cannot register more than 32 atexit functions") + self.atexit_funcs.append(function) + + def shutdown(self, space): + for func in self.atexit_funcs: + func() + + # import these modules to register api functions by side-effect import pypy.module.cpyext.thread import pypy.module.cpyext.pyobject diff --git a/pypy/module/cpyext/import_.py b/pypy/module/cpyext/import_.py --- a/pypy/module/cpyext/import_.py +++ b/pypy/module/cpyext/import_.py @@ -73,3 +73,10 @@ w_mod = Module(space, space.wrap(modulename)) return borrow_from(None, w_mod) + at cpython_api([], PyObject) +def PyImport_GetModuleDict(space): + """Return the dictionary used for the module administration (a.k.a. + sys.modules). Note that this is a per-interpreter variable.""" + w_modulesDict = space.sys.get('modules') + return borrow_from(None, w_modulesDict) + diff --git a/pypy/module/cpyext/number.py b/pypy/module/cpyext/number.py --- a/pypy/module/cpyext/number.py +++ b/pypy/module/cpyext/number.py @@ -40,8 +40,7 @@ @cpython_api([PyObject], PyObject) def PyNumber_Int(space, w_obj): """Returns the o converted to an integer object on success, or NULL on failure. - If the argument is outside the integer range a long object will be returned - instead. This is the equivalent of the Python expression int(o).""" + This is the equivalent of the Python expression int(o).""" return space.int(w_obj) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/cpyext/pyfile.py b/pypy/module/cpyext/pyfile.py --- a/pypy/module/cpyext/pyfile.py +++ b/pypy/module/cpyext/pyfile.py @@ -1,8 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( cpython_api, CONST_STRING, FILEP, build_type_checkers) -from pypy.module.cpyext.pyobject import ( - PyObject) +from pypy.module.cpyext.pyobject import PyObject, borrow_from from pypy.interpreter.error import OperationError from pypy.module._file.interp_file import W_File @@ -66,3 +65,7 @@ space.call_method(w_p, "write", w_s) return 0 + at cpython_api([PyObject], PyObject) +def PyFile_Name(space, w_p): + """Return the name of the file specified by p as a string object.""" + return borrow_from(w_p, space.getattr(w_p, space.wrap("name"))) \ No newline at end of file diff --git a/pypy/module/cpyext/pythonrun.py b/pypy/module/cpyext/pythonrun.py --- a/pypy/module/cpyext/pythonrun.py +++ b/pypy/module/cpyext/pythonrun.py @@ -14,3 +14,21 @@ value.""" return space.fromcache(State).get_programname() + at cpython_api([lltype.Ptr(lltype.FuncType([], lltype.Void))], rffi.INT_real, error=-1) +def Py_AtExit(space, func_ptr): + """Register a cleanup function to be called by Py_Finalize(). The cleanup + function will be called with no arguments and should return no value. At + most 32 cleanup functions can be registered. When the registration is + successful, Py_AtExit() returns 0; on failure, it returns -1. The cleanup + function registered last is called first. Each cleanup function will be + called at most once. Since Python's internal finalization will have + completed before the cleanup function, no Python APIs should be called by + func.""" + from pypy.module import cpyext + w_module = space.getbuiltinmodule('cpyext') + module = space.interp_w(cpyext.Module, w_module) + try: + module.register_atexit(func_ptr) + except ValueError: + return -1 + return 0 diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -36,7 +36,6 @@ def PySequence_Length(space, w_obj): return space.len_w(w_obj) - @cpython_api([PyObject, CONST_STRING], PyObject) def PySequence_Fast(space, w_obj, m): """Returns the sequence o as a tuple, unless it is already a tuple or list, in @@ -96,10 +95,21 @@ return 0 @cpython_api([PyObject, Py_ssize_t], PyObject) +def PySequence_ITEM(space, w_obj, i): + """Return the ith element of o or NULL on failure. Macro form of + PySequence_GetItem() but without checking that + PySequence_Check(o)() is true and without adjustment for negative + indices. + + This function used an int type for i. This might require + changes in your code for properly supporting 64-bit systems.""" + return space.getitem(w_obj, space.wrap(i)) + + at cpython_api([PyObject, Py_ssize_t], PyObject) def PySequence_GetItem(space, w_obj, i): """Return the ith element of o, or NULL on failure. This is the equivalent of the Python expression o[i].""" - return space.getitem(w_obj, space.wrap(i)) + return PySequence_ITEM(space, w_obj, i) @cpython_api([PyObject], PyObject) def PySequence_List(space, w_obj): @@ -154,3 +164,27 @@ equivalent of the Python statement del o[i].""" space.delitem(w_o, space.wrap(i)) return 0 + + at cpython_api([PyObject, PyObject], Py_ssize_t, error=-1) +def PySequence_Index(space, w_seq, w_obj): + """Return the first index i for which o[i] == value. On error, return + -1. This is equivalent to the Python expression o.index(value). + + This function returned an int type. This might require changes + in your code for properly supporting 64-bit systems.""" + + w_iter = space.iter(w_seq) + idx = 0 + while True: + try: + w_next = space.next(w_iter) + except OperationError, e: + if e.match(space, space.w_StopIteration): + break + raise + if space.is_true(space.eq(w_next, w_obj)): + return idx + idx += 1 + + raise OperationError(space.w_ValueError, space.wrap( + "sequence.index(x): x not in sequence")) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -47,7 +47,7 @@ allows for complicated memory sharing possibilities, but some caller may not be able to handle all the complexity but may want to see if the exporter will let them take a simpler view to its memory. - + Some exporters may not be able to share memory in every possible way and may need to raise errors to signal to some consumers that something is just not possible. These errors should be a BufferError unless @@ -55,17 +55,17 @@ exporter can use flags information to simplify how much of the Py_buffer structure is filled in with non-default values and/or raise an error if the object can't support a simpler view of its memory. - + 0 is returned on success and -1 on error. - + The following table gives possible values to the flags arguments. - + Flag - + Description - + PyBUF_SIMPLE - + This is the default flag state. The returned buffer may or may not have writable memory. The format of the data will be assumed to be unsigned @@ -73,14 +73,14 @@ never needs to be '|'d to the others. The exporter will raise an error if it cannot provide such a contiguous buffer of bytes. - + PyBUF_WRITABLE - + The returned buffer must be writable. If it is not writable, then raise an error. - + PyBUF_STRIDES - + This implies PyBUF_ND. The returned buffer must provide strides information (i.e. the strides cannot be NULL). This would be used when @@ -89,20 +89,20 @@ you can handle shape. The exporter can raise an error if a strided representation of the data is not possible (i.e. without the suboffsets). - + PyBUF_ND - + The returned buffer must provide shape information. The memory will be assumed C-style contiguous (last dimension varies the fastest). The exporter may raise an error if it cannot provide this kind of contiguous buffer. If this is not given then shape will be NULL. - + PyBUF_C_CONTIGUOUS PyBUF_F_CONTIGUOUS PyBUF_ANY_CONTIGUOUS - + These flags indicate that the contiguity returned buffer must be respectively, C-contiguous (last dimension varies the fastest), Fortran contiguous @@ -111,18 +111,18 @@ PyBUF_STRIDES and guarantee that the strides buffer info structure will be filled in correctly. - + PyBUF_INDIRECT - + This flag indicates the returned buffer must have suboffsets information (which can be NULL if no suboffsets are needed). This can be used when the consumer can handle indirect array referencing implied by these suboffsets. This implies PyBUF_STRIDES. - + PyBUF_FORMAT - + The returned buffer must have true format information if this flag is provided. This would be used when the consumer is going to be checking @@ -132,43 +132,43 @@ explicitly requested then the format must be returned as NULL (which means 'B', or unsigned bytes) - + PyBUF_STRIDED - + This is equivalent to (PyBUF_STRIDES | PyBUF_WRITABLE). - + PyBUF_STRIDED_RO - + This is equivalent to (PyBUF_STRIDES). - + PyBUF_RECORDS - + This is equivalent to (PyBUF_STRIDES | PyBUF_FORMAT | PyBUF_WRITABLE). - + PyBUF_RECORDS_RO - + This is equivalent to (PyBUF_STRIDES | PyBUF_FORMAT). - + PyBUF_FULL - + This is equivalent to (PyBUF_INDIRECT | PyBUF_FORMAT | PyBUF_WRITABLE). - + PyBUF_FULL_RO - + This is equivalent to (PyBUF_INDIRECT | PyBUF_FORMAT). - + PyBUF_CONTIG - + This is equivalent to (PyBUF_ND | PyBUF_WRITABLE). - + PyBUF_CONTIG_RO - + This is equivalent to (PyBUF_ND).""" raise NotImplementedError @@ -251,7 +251,7 @@ def PyByteArray_FromObject(space, o): """Return a new bytearray object from any object, o, that implements the buffer protocol. - + XXX expand about the buffer protocol, at least somewhere""" raise NotImplementedError @@ -354,7 +354,7 @@ @cpython_api([PyObject], rffi.INT_real, error=-1) def PyCodec_Register(space, search_function): """Register a new codec search function. - + As side effect, this tries to load the encodings package, if not yet done, to make sure that it is always first in the list of search functions.""" raise NotImplementedError @@ -362,7 +362,7 @@ @cpython_api([PyObject, rffi.CCHARP, rffi.CCHARP], PyObject) def PyCodec_Encode(space, object, encoding, errors): """Generic codec based encoding API. - + object is passed through the encoder function found for the given encoding using the error handling method defined by errors. errors may be NULL to use the default method defined for the codec. Raises a @@ -372,7 +372,7 @@ @cpython_api([PyObject, rffi.CCHARP, rffi.CCHARP], PyObject) def PyCodec_Decode(space, object, encoding, errors): """Generic codec based decoding API. - + object is passed through the decoder function found for the given encoding using the error handling method defined by errors. errors may be NULL to use the default method defined for the codec. Raises a @@ -405,7 +405,7 @@ This callback function will be called by a codec when it encounters unencodable characters/undecodable bytes and name is specified as the error parameter in the call to the encode/decode function. - + The callback gets a single argument, an instance of UnicodeEncodeError, UnicodeDecodeError or UnicodeTranslateError that holds information about the problematic @@ -415,7 +415,7 @@ containing the replacement for the problematic sequence, and an integer giving the offset in the original string at which encoding/decoding should be resumed. - + Return 0 on success, -1 on error.""" raise NotImplementedError @@ -500,18 +500,18 @@ the set of strings accepted by Python's float() constructor, except that s must not have leading or trailing whitespace. The conversion is independent of the current locale. - + If endptr is NULL, convert the whole string. Raise ValueError and return -1.0 if the string is not a valid representation of a floating-point number. - + If endptr is not NULL, convert as much of the string as possible and set *endptr to point to the first unconverted character. If no initial segment of the string is the valid representation of a floating-point number, set *endptr to point to the beginning of the string, raise ValueError, and return -1.0. - + If s represents a value that is too large to store in a float (for example, "1e500" is such a string on many platforms) then if overflow_exception is NULL return Py_HUGE_VAL (with @@ -519,7 +519,7 @@ overflow_exception must point to a Python exception object; raise that exception and return -1.0. In both cases, set *endptr to point to the first character after the converted value. - + If any other error occurs during the conversion (for example an out-of-memory error), set the appropriate Python exception and return -1.0. @@ -531,12 +531,12 @@ """Convert a string to a double. This function behaves like the Standard C function strtod() does in the C locale. It does this without changing the current locale, since that would not be thread-safe. - + PyOS_ascii_strtod() should typically be used for reading configuration files or other non-user input that should be locale independent. - + See the Unix man page strtod(2) for details. - + Use PyOS_string_to_double() instead.""" raise NotImplementedError @@ -546,10 +546,10 @@ separator. format is a printf()-style format string specifying the number format. Allowed conversion characters are 'e', 'E', 'f', 'F', 'g' and 'G'. - + The return value is a pointer to buffer with the converted string or NULL if the conversion failed. - + This function is removed in Python 2.7 and 3.1. Use PyOS_double_to_string() instead.""" raise NotImplementedError @@ -558,29 +558,29 @@ def PyOS_double_to_string(space, val, format_code, precision, flags, ptype): """Convert a double val to a string using supplied format_code, precision, and flags. - + format_code must be one of 'e', 'E', 'f', 'F', 'g', 'G' or 'r'. For 'r', the supplied precision must be 0 and is ignored. The 'r' format code specifies the standard repr() format. - + flags can be zero or more of the values Py_DTSF_SIGN, Py_DTSF_ADD_DOT_0, or Py_DTSF_ALT, or-ed together: - + Py_DTSF_SIGN means to always precede the returned string with a sign character, even if val is non-negative. - + Py_DTSF_ADD_DOT_0 means to ensure that the returned string will not look like an integer. - + Py_DTSF_ALT means to apply "alternate" formatting rules. See the documentation for the PyOS_snprintf() '#' specifier for details. - + If ptype is non-NULL, then the value it points to will be set to one of Py_DTST_FINITE, Py_DTST_INFINITE, or Py_DTST_NAN, signifying that val is a finite number, an infinite number, or not a number, respectively. - + The return value is a pointer to buffer with the converted string or NULL if the conversion failed. The caller is responsible for freeing the returned string by calling PyMem_Free(). @@ -590,9 +590,9 @@ @cpython_api([rffi.CCHARP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_atof(space, nptr): """Convert a string to a double in a locale-independent way. - + See the Unix man page atof(2) for details. - + Use PyOS_string_to_double() instead.""" raise NotImplementedError @@ -683,7 +683,7 @@ override is true, else the first wins. Return 0 on success or -1 if an exception was raised. Equivalent Python (except for the return value): - + def PyDict_MergeFromSeq2(a, seq2, override): for key, value in seq2: if override or key not in a: @@ -708,7 +708,7 @@ def PyErr_SetExcFromWindowsErr(space, type, ierr): """Similar to PyErr_SetFromWindowsErr(), with an additional parameter specifying the exception type to be raised. Availability: Windows. - + Return value: always NULL.""" raise NotImplementedError @@ -724,7 +724,7 @@ def PyErr_SetExcFromWindowsErrWithFilename(space, type, ierr, filename): """Similar to PyErr_SetFromWindowsErrWithFilename(), with an additional parameter specifying the exception type to be raised. Availability: Windows. - + Return value: always NULL.""" raise NotImplementedError @@ -815,15 +815,15 @@ @cpython_api([rffi.CCHARP], rffi.INT_real, error=1) def Py_EnterRecursiveCall(space, where): """Marks a point where a recursive C-level call is about to be performed. - + If USE_STACKCHECK is defined, this function checks if the the OS stack overflowed using PyOS_CheckStack(). In this is the case, it sets a MemoryError and returns a nonzero value. - + The function then checks if the recursion limit is reached. If this is the case, a RuntimeError is set and a nonzero value is returned. Otherwise, zero is returned. - + where should be a string such as " in instance check" to be concatenated to the RuntimeError message caused by the recursion depth limit.""" @@ -843,12 +843,12 @@ Callers of this must call PyFile_DecUseCount() when they are finished with the FILE*. Otherwise the file object will never be closed by Python. - + The GIL must be held while calling this function. - + The suggested use is to call this after PyFile_AsFile() and before you release the GIL: - + FILE *fp = PyFile_AsFile(p); PyFile_IncUseCount(p); /* ... */ @@ -865,18 +865,12 @@ """Decrements the PyFileObject's internal unlocked_count member to indicate that the caller is done with its own use of the FILE*. This may only be called to undo a prior call to PyFile_IncUseCount(). - + The GIL must be held while calling this function (see the example above). """ raise NotImplementedError - at cpython_api([PyObject], PyObject) -def PyFile_Name(space, p): - """Return the name of the file specified by p as a string object.""" - borrow_from() - raise NotImplementedError - @cpython_api([PyFileObject, rffi.CCHARP], rffi.INT_real, error=0) def PyFile_SetEncoding(space, p, enc): """Set the file's encoding for Unicode output to enc. Return 1 on success and 0 @@ -944,10 +938,10 @@ def PyFloat_AsString(space, buf, v): """Convert the argument v to a string, using the same rules as str(). The length of buf should be at least 100. - + This function is unsafe to call because it writes to a buffer whose length it does not know. - + Use PyObject_Str() or PyOS_double_to_string() instead.""" raise NotImplementedError @@ -955,10 +949,10 @@ def PyFloat_AsReprString(space, buf, v): """Same as PyFloat_AsString, except uses the same rules as repr(). The length of buf should be at least 100. - + This function is unsafe to call because it writes to a buffer whose length it does not know. - + Use PyObject_Repr() or PyOS_double_to_string() instead.""" raise NotImplementedError @@ -966,7 +960,7 @@ def PyFunction_New(space, code, globals): """Return a new function object associated with the code object code. globals must be a dictionary with the global variables accessible to the function. - + The function's docstring, name and __module__ are retrieved from the code object, the argument defaults and closure are set to NULL.""" raise NotImplementedError @@ -1002,7 +996,7 @@ def PyFunction_SetDefaults(space, op, defaults): """Set the argument default values for the function object op. defaults must be Py_None or a tuple. - + Raises SystemError and returns -1 on failure.""" raise NotImplementedError @@ -1017,7 +1011,7 @@ def PyFunction_SetClosure(space, op, closure): """Set the closure associated with the function object op. closure must be Py_None or a tuple of cell objects. - + Raises SystemError and returns -1 on failure.""" raise NotImplementedError @@ -1025,7 +1019,7 @@ def PyObject_GC_NewVar(space, type, size): """Analogous to PyObject_NewVar() but for container objects with the Py_TPFLAGS_HAVE_GC flag set. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -1034,7 +1028,7 @@ def PyObject_GC_Resize(space, op, newsize): """Resize an object allocated by PyObject_NewVar(). Returns the resized object or NULL on failure. - + This function used an int type for newsize. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -1074,15 +1068,15 @@ """Import a module. This is best described by referring to the built-in Python function __import__(), as the standard __import__() function calls this function directly. - + The return value is a new reference to the imported module or top-level package, or NULL with an exception set on failure (before Python 2.4, the module may still be created in this case). Like for __import__(), the return value when a submodule of a package was requested is normally the top-level package, unless a non-empty fromlist was given. - + Failing imports remove incomplete module objects. - + The function is an alias for PyImport_ImportModuleLevel() with -1 as level, meaning relative import.""" raise NotImplementedError @@ -1092,7 +1086,7 @@ """Import a module. This is best described by referring to the built-in Python function __import__(), as the standard __import__() function calls this function directly. - + The return value is a new reference to the imported module or top-level package, or NULL with an exception set on failure. Like for __import__(), the return value when a submodule of a package was requested is normally the @@ -1120,16 +1114,16 @@ incompletely initialized modules in sys.modules is dangerous, as imports of such modules have no way to know that the module object is an unknown (and probably damaged with respect to the module author's intents) state. - + The module's __file__ attribute will be set to the code object's co_filename. - + This function will reload the module if it was already imported. See PyImport_ReloadModule() for the intended way to reload a module. - + If name points to a dotted name of the form package.module, any package structures not already created will still not be created. - + name is removed from sys.modules in error cases.""" raise NotImplementedError @@ -1250,7 +1244,7 @@ allocated by the Python interpreter. This is a no-op when called for a second time (without calling Py_Initialize() again first). There is no return value; errors during finalization are ignored. - + This function is provided for a number of reasons. An embedding application might want to restart Python without having to restart the application itself. An application that has loaded the Python interpreter from a dynamically @@ -1258,7 +1252,7 @@ before unloading the DLL. During a hunt for memory leaks in an application a developer might want to free all memory allocated by Python before exiting from the application. - + Bugs and caveats: The destruction of modules and objects in modules is done in random order; this may cause destructors (__del__() methods) to fail when they depend on other objects (even functions) or modules. Dynamically @@ -1308,13 +1302,13 @@ variable in the top-level Makefile and the --exec-prefix argument to the configure script at build time. The value is available to Python code as sys.exec_prefix. It is only useful on Unix. - + Background: The exec-prefix differs from the prefix when platform dependent files (such as executables and shared libraries) are installed in a different directory tree. In a typical installation, platform dependent files may be installed in the /usr/local/plat subtree while platform independent may be installed in /usr/local. - + Generally speaking, a platform is a combination of hardware and software families, e.g. Sparc machines running the Solaris 2.x operating system are considered the same platform, but Intel machines running Solaris 2.x are another @@ -1325,7 +1319,7 @@ meaningless, and set to the empty string. Note that compiled Python bytecode files are platform independent (but not independent from the Python version by which they were compiled!). - + System administrators will know how to configure the mount or automount programs to share /usr/local between platforms while having /usr/local/plat be a different filesystem for each @@ -1351,7 +1345,7 @@ storage; the caller should not modify its value. The list sys.path is initialized with this value on interpreter startup; it can be (and usually is) modified later to change the search path for loading modules. - + XXX should give the exact rules""" raise NotImplementedError @@ -1359,9 +1353,9 @@ def Py_GetVersion(space): """Return the version of this Python interpreter. This is a string that looks something like - + "1.5 (\#67, Dec 31 1997, 22:34:28) [GCC 2.7.2.2]" - + The first word (up to the first space character) is the current Python version; the first three characters are the major and minor version separated by a period. The returned string points into static storage; the caller should not @@ -1382,9 +1376,9 @@ @cpython_api([], rffi.CCHARP) def Py_GetCopyright(space): """Return the official copyright string for the current Python version, for example - + 'Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam' - + The returned string points into static storage; the caller should not modify its value. The value is available to Python code as sys.copyright.""" raise NotImplementedError @@ -1393,9 +1387,9 @@ def Py_GetCompiler(space): """Return an indication of the compiler used to build the current Python version, in square brackets, for example: - + "[GCC 2.7.2.2]" - + The returned string points into static storage; the caller should not modify its value. The value is available to Python code as part of the variable sys.version.""" @@ -1405,9 +1399,9 @@ def Py_GetBuildInfo(space): """Return information about the sequence number and build date and time of the current Python interpreter instance, for example - + "\#67, Aug 1 1997, 22:34:28" - + The returned string points into static storage; the caller should not modify its value. The value is available to Python code as part of the variable sys.version.""" @@ -1422,31 +1416,31 @@ will be run, the first entry in argv can be an empty string. If this function fails to initialize sys.argv, a fatal condition is signalled using Py_FatalError(). - + If updatepath is zero, this is all the function does. If updatepath is non-zero, the function also modifies sys.path according to the following algorithm: - + If the name of an existing script is passed in argv[0], the absolute path of the directory where the script is located is prepended to sys.path. - + Otherwise (that is, if argc is 0 or argv[0] doesn't point to an existing file name), an empty string is prepended to sys.path, which is the same as prepending the current working directory ("."). - + It is recommended that applications embedding the Python interpreter for purposes other than executing a single script pass 0 as updatepath, and update sys.path themselves if desired. See CVE-2008-5983. - + On versions before 2.6.6, you can achieve the same effect by manually popping the first sys.path element after having called PySys_SetArgv(), for example using: - + PyRun_SimpleString("import sys; sys.path.pop(0)\n"); - + XXX impl. doesn't seem consistent in allowing 0/NULL for the params; check w/ Guido.""" raise NotImplementedError @@ -1461,7 +1455,7 @@ """Set the default "home" directory, that is, the location of the standard Python libraries. See PYTHONHOME for the meaning of the argument string. - + The argument should point to a zero-terminated character string in static storage whose contents will not change for the duration of the program's execution. No code in the Python interpreter will change the contents of @@ -1509,7 +1503,7 @@ the dictionary. It is okay to call this function when no current thread state is available. If this function returns NULL, no exception has been raised and the caller should assume no current thread state is available. - + Previously this could only be called when a current thread is active, and NULL meant that an exception was raised.""" borrow_from() @@ -1531,7 +1525,7 @@ def PyEval_AcquireLock(space): """Acquire the global interpreter lock. The lock must have been created earlier. If this thread already has the lock, a deadlock ensues. - + This function does not change the current thread state. Please use PyEval_RestoreThread() or PyEval_AcquireThread() instead.""" @@ -1540,7 +1534,7 @@ @cpython_api([], lltype.Void) def PyEval_ReleaseLock(space): """Release the global interpreter lock. The lock must have been created earlier. - + This function does not change the current thread state. Please use PyEval_SaveThread() or PyEval_ReleaseThread() instead.""" @@ -1556,7 +1550,7 @@ separate. The new environment has no sys.argv variable. It has new standard I/O stream file objects sys.stdin, sys.stdout and sys.stderr (however these refer to the same underlying file descriptors). - + The return value points to the first thread state created in the new sub-interpreter. This thread state is made in the current thread state. Note that no actual thread is created; see the discussion of thread states @@ -1567,7 +1561,7 @@ calling this function and is still held when it returns; however, unlike most other Python/C API functions, there needn't be a current thread state on entry.) - + Extension modules are shared between (sub-)interpreters as follows: the first time a particular extension is imported, it is initialized normally, and a (shallow) copy of its module's dictionary is squirreled away. When the same @@ -1601,11 +1595,11 @@ asynchronous notification recursively, but it can still be interrupted to switch threads if the global interpreter lock is released, for example, if it calls back into Python code. - + This function returns 0 on success in which case the notification has been scheduled. Otherwise, for example if the notification buffer is full, it returns -1 without setting any exception. - + This function can be called on any thread, be it a Python thread or some other system thread. If it is a Python thread, it doesn't matter if it holds the global interpreter lock or not. @@ -1633,62 +1627,62 @@ def PyEval_GetCallStats(space, self): """Return a tuple of function call counts. There are constants defined for the positions within the tuple: - + Name - + Value - + PCALL_ALL - + 0 - + PCALL_FUNCTION - + 1 - + PCALL_FAST_FUNCTION - + 2 - + PCALL_FASTER_FUNCTION - + 3 - + PCALL_METHOD - + 4 - + PCALL_BOUND_METHOD - + 5 - + PCALL_CFUNCTION - + 6 - + PCALL_TYPE - + 7 - + PCALL_GENERATOR - + 8 - + PCALL_OTHER - + 9 - + PCALL_POP - + 10 - + PCALL_FAST_FUNCTION means no argument tuple needs to be created. PCALL_FASTER_FUNCTION means that the fast-path frame setup code is used. - + If there is a method call where the call can be optimized by changing the argument tuple and calling the function directly, it gets recorded twice. - + This function is only present if Python is compiled with CALL_PROFILE defined.""" raise NotImplementedError @@ -1747,7 +1741,7 @@ and high. Return NULL and set an exception if unsuccessful. Analogous to list[low:high]. Negative indices, as when slicing from Python, are not supported. - + This function used an int for low and high. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -1773,7 +1767,7 @@ gives the number of characters, and base is the radix for the conversion. The radix must be in the range [2, 36]; if it is out of range, ValueError will be raised. - + This function used an int for length. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -1803,21 +1797,21 @@ """Marshal a long integer, value, to file. This will only write the least-significant 32 bits of value; regardless of the size of the native long type. - + version indicates the file format.""" raise NotImplementedError @cpython_api([PyObject, FILE, rffi.INT_real], lltype.Void) def PyMarshal_WriteObjectToFile(space, value, file, version): """Marshal a Python object, value, to file. - + version indicates the file format.""" raise NotImplementedError @cpython_api([PyObject, rffi.INT_real], PyObject) def PyMarshal_WriteObjectToString(space, value, version): """Return a string object containing the marshalled representation of value. - + version indicates the file format.""" raise NotImplementedError @@ -1860,7 +1854,7 @@ containing len bytes pointed to by string. On error, sets the appropriate exception (EOFError or TypeError) and returns NULL. - + This function used an int type for len. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2012,7 +2006,7 @@ """Return the result of repeating sequence object o count times, or NULL on failure. The operation is done in-place when o supports it. This is the equivalent of the Python expression o *= count. - + This function used an int type for count. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2022,16 +2016,7 @@ """Return the number of occurrences of value in o, that is, return the number of keys for which o[key] == value. On failure, return -1. This is equivalent to the Python expression o.count(value). - - This function returned an int type. This might require changes - in your code for properly supporting 64-bit systems.""" - raise NotImplementedError - - at cpython_api([PyObject, PyObject], Py_ssize_t, error=-1) -def PySequence_Index(space, o, value): - """Return the first index i for which o[i] == value. On error, return - -1. This is equivalent to the Python expression o.index(value). - + This function returned an int type. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2040,24 +2025,13 @@ def PySequence_Fast_ITEMS(space, o): """Return the underlying array of PyObject pointers. Assumes that o was returned by PySequence_Fast() and o is not NULL. - + Note, if a list gets resized, the reallocation may relocate the items array. So, only use the underlying array pointer in contexts where the sequence cannot change. """ raise NotImplementedError - at cpython_api([PyObject, Py_ssize_t], PyObject) -def PySequence_ITEM(space, o, i): - """Return the ith element of o or NULL on failure. Macro form of - PySequence_GetItem() but without checking that - PySequence_Check(o)() is true and without adjustment for negative - indices. - - This function used an int type for i. This might require - changes in your code for properly supporting 64-bit systems.""" - raise NotImplementedError - @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL) def PySet_Check(space, p): """Return true if p is a set object or an instance of a subtype. @@ -2104,7 +2078,7 @@ The iterable may be NULL to create a new empty frozenset. Return the new set on success or NULL on failure. Raise TypeError if iterable is not actually iterable. - + Now guaranteed to return a brand-new frozenset. Formerly, frozensets of zero-length were a singleton. This got in the way of building-up new frozensets with PySet_Add().""" @@ -2115,7 +2089,7 @@ """Return the length of a set or frozenset object. Equivalent to len(anyset). Raises a PyExc_SystemError if anyset is not a set, frozenset, or an instance of a subtype. - + This function returned an int. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2141,7 +2115,7 @@ the key is unhashable. Raise a MemoryError if there is no room to grow. Raise a SystemError if set is an not an instance of set or its subtype. - + Now works with instances of frozenset or its subtypes. Like PyTuple_SetItem() in that it can be used to fill-in the values of brand new frozensets before they are exposed to other code.""" @@ -2181,7 +2155,7 @@ though there is a lot of talk about reference counts, think of this function as reference-count-neutral; you own the object after the call if and only if you owned it before the call.) - + This function is not available in 3.x and does not have a PyBytes alias.""" raise NotImplementedError @@ -2192,9 +2166,9 @@ as the parameters of the same name in the unicode() built-in function. The codec to be used is looked up using the Python codec registry. Return NULL if an exception was raised by the codec. - + This function is not available in 3.x and does not have a PyBytes alias. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2206,7 +2180,7 @@ meaning as the parameters of the same name in the string encode() method. The codec to be used is looked up using the Python codec registry. Return NULL if an exception was raised by the codec. - + This function is not available in 3.x and does not have a PyBytes alias.""" raise NotImplementedError @@ -2217,9 +2191,9 @@ have the same meaning as the parameters of the same name in the string encode() method. The codec to be used is looked up using the Python codec registry. Return NULL if an exception was raised by the codec. - + This function is not available in 3.x and does not have a PyBytes alias. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2280,23 +2254,11 @@ standard C library function exit(status).""" raise NotImplementedError - at cpython_api([rffi.VOIDP], rffi.INT_real, error=-1) -def Py_AtExit(space, func): - """Register a cleanup function to be called by Py_Finalize(). The cleanup - function will be called with no arguments and should return no value. At - most 32 cleanup functions can be registered. When the registration is - successful, Py_AtExit() returns 0; on failure, it returns -1. The cleanup - function registered last is called first. Each cleanup function will be - called at most once. Since Python's internal finalization will have - completed before the cleanup function, no Python APIs should be called by - func.""" - raise NotImplementedError - @cpython_api([PyObject, Py_ssize_t, Py_ssize_t], PyObject) def PyTuple_GetSlice(space, p, low, high): """Take a slice of the tuple pointed to by p from low to high and return it as a new tuple. - + This function used an int type for low and high. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2384,93 +2346,93 @@ a string with the values formatted into it. The variable arguments must be C types and must correspond exactly to the format characters in the format string. The following format characters are allowed: - + Format Characters - + Type - + Comment - + %% - + n/a - + The literal % character. - + %c - + int - + A single character, represented as an C int. - + %d - + int - + Exactly equivalent to printf("%d"). - + %u - + unsigned int - + Exactly equivalent to printf("%u"). - + %ld - + long - + Exactly equivalent to printf("%ld"). - + %lu - + unsigned long - + Exactly equivalent to printf("%lu"). - + %zd - + Py_ssize_t - + Exactly equivalent to printf("%zd"). - + %zu - + size_t - + Exactly equivalent to printf("%zu"). - + %i - + int - + Exactly equivalent to printf("%i"). - + %x - + int - + Exactly equivalent to printf("%x"). - + %s - + char* - + A null-terminated C character array. - + %p - + void* - + The hex representation of a C pointer. Mostly equivalent to printf("%p") except that @@ -2478,38 +2440,38 @@ the literal 0x regardless of what the platform's printf yields. - + %U - + PyObject* - + A unicode object. - + %V - + PyObject*, char * - + A unicode object (which may be NULL) and a null-terminated C character array as a second parameter (which will be used, if the first parameter is NULL). - + %S - + PyObject* - + The result of calling PyObject_Unicode(). - + %R - + PyObject* - + The result of calling PyObject_Repr(). - + An unrecognized format character causes all the rest of the format string to be copied as-is to the result string, and any extra arguments discarded. """ @@ -2529,7 +2491,7 @@ of the same name in the Unicode encode() method. The codec to be used is looked up using the Python codec registry. Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2540,7 +2502,7 @@ consumed is not NULL, trailing incomplete UTF-8 byte sequences will not be treated as an error. Those bytes will not be decoded and the number of bytes that have been decoded will be stored in consumed. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2549,7 +2511,7 @@ def PyUnicode_EncodeUTF8(space, s, size, errors): """Encode the Py_UNICODE buffer of the given size using UTF-8 and return a Python string object. Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2559,26 +2521,26 @@ """Decode length bytes from a UTF-32 encoded buffer string and return the corresponding Unicode object. errors (if non-NULL) defines the error handling. It defaults to "strict". - + If byteorder is non-NULL, the decoder starts decoding using the given byte order: - + *byteorder == -1: little endian *byteorder == 0: native order *byteorder == 1: big endian - + If *byteorder is zero, and the first four bytes of the input data are a byte order mark (BOM), the decoder switches to this byte order and the BOM is not copied into the resulting Unicode string. If *byteorder is -1 or 1, any byte order mark is copied to the output. - + After completion, *byteorder is set to the current byte order at the end of input data. - + In a narrow build codepoints outside the BMP will be decoded as surrogate pairs. - + If byteorder is NULL, the codec starts in native order mode. - + Return NULL if an exception was raised by the codec. """ raise NotImplementedError @@ -2597,17 +2559,17 @@ def PyUnicode_EncodeUTF32(space, s, size, errors, byteorder): """Return a Python bytes object holding the UTF-32 encoded value of the Unicode data in s. Output is written according to the following byte order: - + byteorder == -1: little endian byteorder == 0: native byte order (writes a BOM mark) byteorder == 1: big endian - + If byteorder is 0, the output string will always start with the Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is prepended. - + If Py_UNICODE_WIDE is not defined, surrogate pairs will be output as a single codepoint. - + Return NULL if an exception was raised by the codec. """ raise NotImplementedError @@ -2627,7 +2589,7 @@ trailing incomplete UTF-16 byte sequences (such as an odd number of bytes or a split surrogate pair) as an error. Those bytes will not be decoded and the number of bytes that have been decoded will be stored in consumed. - + This function used an int type for size and an int * type for consumed. This might require changes in your code for properly supporting 64-bit systems.""" @@ -2637,20 +2599,20 @@ def PyUnicode_EncodeUTF16(space, s, size, errors, byteorder): """Return a Python string object holding the UTF-16 encoded value of the Unicode data in s. Output is written according to the following byte order: - + byteorder == -1: little endian byteorder == 0: native byte order (writes a BOM mark) byteorder == 1: big endian - + If byteorder is 0, the output string will always start with the Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is prepended. - + If Py_UNICODE_WIDE is defined, a single Py_UNICODE value may get represented as a surrogate pair. If it is not defined, each Py_UNICODE values is interpreted as an UCS-2 character. - + Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2681,7 +2643,7 @@ """Encode the Py_UNICODE buffer of the given size using UTF-7 and return a Python bytes object. Return NULL if an exception was raised by the codec. - + If base64SetO is nonzero, "Set O" (punctuation that has no otherwise special meaning) will be encoded in base-64. If base64WhiteSpace is nonzero, whitespace will be encoded in base-64. Both are set to zero for the @@ -2692,7 +2654,7 @@ def PyUnicode_DecodeUnicodeEscape(space, s, size, errors): """Create a Unicode object by decoding size bytes of the Unicode-Escape encoded string s. Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2702,7 +2664,7 @@ """Encode the Py_UNICODE buffer of the given size using Unicode-Escape and return a Python string object. Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2711,7 +2673,7 @@ def PyUnicode_DecodeRawUnicodeEscape(space, s, size, errors): """Create a Unicode object by decoding size bytes of the Raw-Unicode-Escape encoded string s. Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2721,7 +2683,7 @@ """Encode the Py_UNICODE buffer of the given size using Raw-Unicode-Escape and return a Python string object. Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2737,7 +2699,7 @@ def PyUnicode_DecodeLatin1(space, s, size, errors): """Create a Unicode object by decoding size bytes of the Latin-1 encoded string s. Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2746,7 +2708,7 @@ def PyUnicode_EncodeLatin1(space, s, size, errors): """Encode the Py_UNICODE buffer of the given size using Latin-1 and return a Python string object. Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2766,9 +2728,9 @@ dictionary mapping byte or a unicode string, which is treated as a lookup table. Byte values greater that the length of the string and U+FFFE "characters" are treated as "undefined mapping". - + Allowed unicode string as mapping argument. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2778,7 +2740,7 @@ """Encode the Py_UNICODE buffer of the given size using the given mapping object and return a Python string object. Return NULL if an exception was raised by the codec. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2795,14 +2757,14 @@ """Translate a Py_UNICODE buffer of the given length by applying a character mapping table to it and return the resulting Unicode object. Return NULL when an exception was raised by the codec. - + The mapping table must map Unicode ordinal integers to Unicode ordinal integers or None (causing deletion of the character). - + Mapping tables need only provide the __getitem__() interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a LookupError) are left untouched and are copied as-is. - + This function used an int type for size. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2834,7 +2796,7 @@ will be done at all whitespace substrings. Otherwise, splits occur at the given separator. At most maxsplit splits will be done. If negative, no limit is set. Separators are not included in the resulting list. - + This function used an int type for maxsplit. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2850,14 +2812,14 @@ def PyUnicode_Translate(space, str, table, errors): """Translate a string by applying a character mapping table to it and return the resulting Unicode object. - + The mapping table must map Unicode ordinal integers to Unicode ordinal integers or None (causing deletion of the character). - + Mapping tables need only provide the __getitem__() interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a LookupError) are left untouched and are copied as-is. - + errors has the usual meaning for codecs. It may be NULL which indicates to use the default error handling.""" raise NotImplementedError @@ -2873,7 +2835,7 @@ """Return 1 if substr matches str*[*start:end] at the given tail end (direction == -1 means to do a prefix match, direction == 1 a suffix match), 0 otherwise. Return -1 if an error occurred. - + This function used an int type for start and end. This might require changes in your code for properly supporting 64-bit systems.""" @@ -2886,7 +2848,7 @@ backward search). The return value is the index of the first match; a value of -1 indicates that no match was found, and -2 indicates that an error occurred and an exception has been set. - + This function used an int type for start and end. This might require changes in your code for properly supporting 64-bit systems.""" @@ -2896,7 +2858,7 @@ def PyUnicode_Count(space, str, substr, start, end): """Return the number of non-overlapping occurrences of substr in str[start:end]. Return -1 if an error occurred. - + This function returned an int type and used an int type for start and end. This might require changes in your code for properly supporting 64-bit systems.""" @@ -2907,7 +2869,7 @@ """Replace at most maxcount occurrences of substr in str with replstr and return the resulting Unicode object. maxcount == -1 means replace all occurrences. - + This function used an int type for maxcount. This might require changes in your code for properly supporting 64-bit systems.""" raise NotImplementedError @@ -2915,17 +2877,17 @@ @cpython_api([PyObject, PyObject, rffi.INT_real], PyObject) def PyUnicode_RichCompare(space, left, right, op): """Rich compare two unicode strings and return one of the following: - + NULL in case an exception was raised - + Py_True or Py_False for successful comparisons - + Py_NotImplemented in case the type combination is unknown - + Note that Py_EQ and Py_NE comparisons can cause a UnicodeWarning in case the conversion of the arguments to Unicode fails with a UnicodeDecodeError. - + Possible values for op are Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, and Py_LE.""" raise NotImplementedError @@ -2940,7 +2902,7 @@ def PyUnicode_Contains(space, container, element): """Check whether element is contained in container and return true or false accordingly. - + element has to coerce to a one element Unicode string. -1 is returned if there was an error.""" raise NotImplementedError @@ -2955,7 +2917,7 @@ value will be the integer passed to the sys.exit() function, 1 if the interpreter exits due to an exception, or 2 if the parameter list does not represent a valid Python command line. - + Note that if an otherwise unhandled SystemError is raised, this function will not return 1, but exit the process, as long as Py_InspectFlag is not set.""" @@ -2995,7 +2957,7 @@ is created. Returns 0 on success or -1 if an exception was raised. If there was an error, there is no way to get the exception information. For the meaning of flags, see below. - + Note that if an otherwise unhandled SystemError is raised, this function will not return -1, but exit the process, as long as Py_InspectFlag is not set.""" @@ -3097,7 +3059,7 @@ dictionaries globals and locals with the compiler flags specified by flags. The parameter start specifies the start token that should be used to parse the source code. - + Returns the result of executing the code as a Python object, or NULL if an exception was raised.""" raise NotImplementedError diff --git a/pypy/module/cpyext/test/test_eval.py b/pypy/module/cpyext/test/test_eval.py --- a/pypy/module/cpyext/test/test_eval.py +++ b/pypy/module/cpyext/test/test_eval.py @@ -166,6 +166,15 @@ lltype.free(pi, flavor='raw') + def test_atexit(self, space, api): + lst = [] + def func(): + lst.append(42) + api.Py_AtExit(func) + cpyext = space.getbuiltinmodule('cpyext') + cpyext.shutdown(space) # simulate shutdown + assert lst == [42] + class AppTestCall(AppTestCpythonExtensionBase): def test_CallFunction(self): module = self.import_extension('foo', [ diff --git a/pypy/module/cpyext/test/test_import.py b/pypy/module/cpyext/test/test_import.py --- a/pypy/module/cpyext/test/test_import.py +++ b/pypy/module/cpyext/test/test_import.py @@ -18,6 +18,19 @@ assert space.str_w(space.getattr(w_foobar, space.wrap('__name__'))) == 'foobar' + def test_getmoduledict(self, space, api): + testmod = "binascii" + w_pre_dict = api.PyImport_GetModuleDict() + assert not space.is_true(space.contains(w_pre_dict, space.wrap(testmod))) + + with rffi.scoped_str2charp(testmod) as modname: + w_module = api.PyImport_ImportModule(modname) + print w_module + assert w_module + + w_dict = api.PyImport_GetModuleDict() + assert space.is_true(space.contains(w_dict, space.wrap(testmod))) + def test_reload(self, space, api): pdb = api.PyImport_Import(space.wrap("pdb")) space.delattr(pdb, space.wrap("set_trace")) diff --git a/pypy/module/cpyext/test/test_number.py b/pypy/module/cpyext/test/test_number.py --- a/pypy/module/cpyext/test/test_number.py +++ b/pypy/module/cpyext/test/test_number.py @@ -23,6 +23,8 @@ def test_number_int(self, space, api): w_l = api.PyNumber_Int(space.wrap(123L)) assert api.PyInt_CheckExact(w_l) + w_l = api.PyNumber_Int(space.wrap(2 << 65)) + assert api.PyLong_CheckExact(w_l) def test_numbermethods(self, space, api): assert "ab" == space.unwrap( diff --git a/pypy/module/cpyext/test/test_pyfile.py b/pypy/module/cpyext/test/test_pyfile.py --- a/pypy/module/cpyext/test/test_pyfile.py +++ b/pypy/module/cpyext/test/test_pyfile.py @@ -52,6 +52,13 @@ space.call_method(w_file, "close") + def test_file_name(self, space, api): + name = str(udir / "_test_file") + with rffi.scoped_str2charp(name) as filename: + with rffi.scoped_str2charp("wb") as mode: + w_file = api.PyFile_FromString(filename, mode) + assert space.str_w(api.PyFile_Name(w_file)) == name + @pytest.mark.xfail def test_file_fromfile(self, space, api): api.PyFile_Fromfile() diff --git a/pypy/module/cpyext/test/test_sequence.py b/pypy/module/cpyext/test/test_sequence.py --- a/pypy/module/cpyext/test/test_sequence.py +++ b/pypy/module/cpyext/test/test_sequence.py @@ -105,3 +105,34 @@ self.raises(space, api, IndexError, api.PySequence_DelItem, w_l, 3) + + def test_getitem(self, space, api): + thelist = [8, 7, 6, 5, 4, 3, 2, 1] + w_l = space.wrap(thelist) + + result = api.PySequence_GetItem(w_l, 4) + assert space.is_true(space.eq(result, space.wrap(4))) + + result = api.PySequence_ITEM(w_l, 4) + assert space.is_true(space.eq(result, space.wrap(4))) + + self.raises(space, api, IndexError, api.PySequence_GetItem, w_l, 9000) + + def test_index(self, space, api): + thelist = [9, 8, 7, 6, 5, 4, 3, 2, 1] + w_l = space.wrap(thelist) + w_tofind = space.wrap(5) + + result = api.PySequence_Index(w_l, w_tofind) + assert result == thelist.index(5) + + w_tofind = space.wrap(9001) + result = api.PySequence_Index(w_l, w_tofind) + assert result == -1 + assert api.PyErr_Occurred() is space.w_ValueError + api.PyErr_Clear() + + gen = (x ** 2 for x in range(40)) + w_tofind = space.wrap(16) + result = api.PySequence_Index(space.wrap(gen), w_tofind) + assert result == 4 diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,7 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - '_socket', '_sre', '_lsprof']: + 'posix', '_socket', '_sre', '_lsprof']: return True return False diff --git a/pypy/module/pypyjit/test/test_policy.py b/pypy/module/pypyjit/test/test_policy.py --- a/pypy/module/pypyjit/test/test_policy.py +++ b/pypy/module/pypyjit/test/test_policy.py @@ -39,7 +39,7 @@ def test_pypy_module(): from pypy.module._random.interp_random import W_Random assert not pypypolicy.look_inside_function(W_Random.random) - assert not pypypolicy.look_inside_pypy_module('posix.interp_expat') + assert not pypypolicy.look_inside_pypy_module('select.interp_epoll') assert pypypolicy.look_inside_pypy_module('__builtin__.operation') assert pypypolicy.look_inside_pypy_module('__builtin__.abstractinst') assert pypypolicy.look_inside_pypy_module('__builtin__.functional') diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py --- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py +++ b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py @@ -1031,7 +1031,6 @@ """) def test_func_defaults(self): - py.test.skip("until we fix defaults") def main(n): i = 1 while i < n: @@ -1044,20 +1043,10 @@ assert loop.match(""" i10 = int_lt(i5, i6) guard_true(i10, descr=) - # This can be improved if the JIT realized the lookup of i5 produces - # a constant and thus can be removed entirely i120 = int_add(i5, 1) - i140 = int_lt(0, i120) - guard_true(i140, descr=) - i13 = uint_floordiv(i5, i7) - i15 = int_add(i13, 1) - i17 = int_lt(i15, 0) - guard_false(i17, descr=) - i20 = int_sub(i15, i5) - i21 = int_add_ovf(i5, i20) - guard_no_overflow(descr=) + guard_not_invalidated(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, descr=) + jump(..., descr=) """) def test_unpack_iterable_non_list_tuple(self): @@ -1092,7 +1081,7 @@ --TICK-- jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) """) - + def test_mutate_class(self): def fn(n): class A(object): @@ -1497,7 +1486,7 @@ def main(): i=0 sa=0 - while i < 300: + while i < 300: sa+=min(max(i, 3000), 4000) i+=1 return sa @@ -1534,7 +1523,7 @@ p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) ... """) - + def test_iter_max(self): def main(): i = 2 @@ -1552,7 +1541,7 @@ assert len(guards) < 20 assert loop.match_by_id('max',""" ... - p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) + p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) ... """) diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -114,6 +114,8 @@ c_thread_releaselock(self._lock) def __del__(self): + if free_ll_lock is None: # happens when tests are shutting down + return free_ll_lock(self._lock) def __enter__(self): diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -52,12 +52,16 @@ c = v[0] return space.newbool(fun(c)) else: - for idx in range(len(v)): - if not fun(v[idx]): - return space.w_False - return space.w_True + return _is_generic_loop(space, v, fun) _is_generic._annspecialcase_ = "specialize:arg(2)" +def _is_generic_loop(space, v, fun): + for idx in range(len(v)): + if not fun(v[idx]): + return space.w_False + return space.w_True +_is_generic_loop._annspecialcase_ = "specialize:arg(2)" + def _upper(ch): if ch.islower(): o = ord(ch) - 32 diff --git a/pypy/objspace/trace.py b/pypy/objspace/trace.py --- a/pypy/objspace/trace.py +++ b/pypy/objspace/trace.py @@ -110,10 +110,10 @@ self.result.append(EnterFrame(frame)) self.ec.enter(frame) - def leave(self, frame): + def leave(self, frame, w_exitvalue): """ called just after evaluating of a frame is suspended/finished. """ self.result.append(LeaveFrame(frame)) - self.ec.leave(frame) + self.ec.leave(frame, w_exitvalue) def bytecode_trace(self, frame): """ called just before execution of a bytecode. """ diff --git a/pypy/rlib/_rsocket_rffi.py b/pypy/rlib/_rsocket_rffi.py --- a/pypy/rlib/_rsocket_rffi.py +++ b/pypy/rlib/_rsocket_rffi.py @@ -90,35 +90,10 @@ COND_HEADER = '' constants = {} -sources = [""" - void pypy_macro_wrapper_FD_SET(int fd, fd_set *set) - { - FD_SET(fd, set); - } - void pypy_macro_wrapper_FD_ZERO(fd_set *set) - { - FD_ZERO(set); - } - void pypy_macro_wrapper_FD_CLR(int fd, fd_set *set) - { - FD_CLR(fd, set); - } - int pypy_macro_wrapper_FD_ISSET(int fd, fd_set *set) - { - return FD_ISSET(fd, set); - } - """] - eci = ExternalCompilationInfo( post_include_bits = [HEADER, COND_HEADER], includes = includes, libraries = libraries, - separate_module_sources = sources, - export_symbols = ['pypy_macro_wrapper_FD_ZERO', - 'pypy_macro_wrapper_FD_SET', - 'pypy_macro_wrapper_FD_CLR', - 'pypy_macro_wrapper_FD_ISSET', - ], ) class CConfig: @@ -484,9 +459,9 @@ return rffi.llexternal(name, args, result, compilation_info=eci, calling_conv=calling_conv) -def external_c(name, args, result): +def external_c(name, args, result, **kwargs): return rffi.llexternal(name, args, result, compilation_info=eci, - calling_conv='c') + calling_conv='c', **kwargs) if _POSIX: dup = external('dup', [socketfd_type], socketfd_type) @@ -583,10 +558,10 @@ fd_set, lltype.Ptr(timeval)], rffi.INT) -FD_CLR = external_c('pypy_macro_wrapper_FD_CLR', [rffi.INT, fd_set], lltype.Void) -FD_ISSET = external_c('pypy_macro_wrapper_FD_ISSET', [rffi.INT, fd_set], rffi.INT) -FD_SET = external_c('pypy_macro_wrapper_FD_SET', [rffi.INT, fd_set], lltype.Void) -FD_ZERO = external_c('pypy_macro_wrapper_FD_ZERO', [fd_set], lltype.Void) +FD_CLR = external_c('FD_CLR', [rffi.INT, fd_set], lltype.Void, macro=True) +FD_ISSET = external_c('FD_ISSET', [rffi.INT, fd_set], rffi.INT, macro=True) +FD_SET = external_c('FD_SET', [rffi.INT, fd_set], lltype.Void, macro=True) +FD_ZERO = external_c('FD_ZERO', [fd_set], lltype.Void, macro=True) if _POSIX: pollfdarray = rffi.CArray(pollfd) diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -15,19 +15,27 @@ 'winsock2.h', # wincrypt.h defines X509_NAME, include it here # so that openssl/ssl.h can repair this nonsense. - 'wincrypt.h', - 'openssl/ssl.h', - 'openssl/err.h', - 'openssl/evp.h'] + 'wincrypt.h'] else: libraries = ['ssl', 'crypto'] - includes = ['openssl/ssl.h', 'openssl/err.h', - 'openssl/evp.h'] + includes = [] + +includes += [ + 'openssl/ssl.h', + 'openssl/err.h', + 'openssl/rand.h', + 'openssl/evp.h', + 'openssl/x509v3.h'] eci = ExternalCompilationInfo( libraries = libraries, includes = includes, export_symbols = [], + post_include_bits = [ + # Unnamed structures are not supported by rffi_platform. + # So we replace an attribute access with a macro call. + '#define pypy_GENERAL_NAME_dirn(name) (name->d.dirn)', + ], ) eci = rffi_platform.configure_external_library( @@ -43,6 +51,10 @@ else: from pypy.rlib._rsocket_rffi import FD_SETSIZE as MAX_FD_SIZE +ASN1_STRING = lltype.Ptr(lltype.ForwardReference()) +ASN1_ITEM = rffi.COpaquePtr('ASN1_ITEM') +X509_NAME = rffi.COpaquePtr('X509_NAME') + class CConfig: _compilation_info_ = eci @@ -53,6 +65,8 @@ SSL_FILETYPE_PEM = rffi_platform.ConstantInteger("SSL_FILETYPE_PEM") SSL_OP_ALL = rffi_platform.ConstantInteger("SSL_OP_ALL") SSL_VERIFY_NONE = rffi_platform.ConstantInteger("SSL_VERIFY_NONE") + SSL_VERIFY_PEER = rffi_platform.ConstantInteger("SSL_VERIFY_PEER") + SSL_VERIFY_FAIL_IF_NO_PEER_CERT = rffi_platform.ConstantInteger("SSL_VERIFY_FAIL_IF_NO_PEER_CERT") SSL_ERROR_WANT_READ = rffi_platform.ConstantInteger( "SSL_ERROR_WANT_READ") SSL_ERROR_WANT_WRITE = rffi_platform.ConstantInteger( @@ -67,21 +81,54 @@ SSL_ERROR_SSL = rffi_platform.ConstantInteger("SSL_ERROR_SSL") SSL_RECEIVED_SHUTDOWN = rffi_platform.ConstantInteger( "SSL_RECEIVED_SHUTDOWN") - SSL_CTRL_OPTIONS = rffi_platform.ConstantInteger("SSL_CTRL_OPTIONS") - SSL_CTRL_MODE = rffi_platform.ConstantInteger("SSL_CTRL_MODE") - BIO_C_SET_NBIO = rffi_platform.ConstantInteger("BIO_C_SET_NBIO") SSL_MODE_AUTO_RETRY = rffi_platform.ConstantInteger("SSL_MODE_AUTO_RETRY") + NID_subject_alt_name = rffi_platform.ConstantInteger("NID_subject_alt_name") + GEN_DIRNAME = rffi_platform.ConstantInteger("GEN_DIRNAME") + + CRYPTO_LOCK = rffi_platform.ConstantInteger("CRYPTO_LOCK") + + # Some structures, with only the fields used in the _ssl module + X509_name_entry_st = rffi_platform.Struct('struct X509_name_entry_st', + [('set', rffi.INT)]) + asn1_string_st = rffi_platform.Struct('struct asn1_string_st', + [('length', rffi.INT), + ('data', rffi.CCHARP)]) + X509_extension_st = rffi_platform.Struct( + 'struct X509_extension_st', + [('value', ASN1_STRING)]) + ASN1_ITEM_EXP = lltype.FuncType([], ASN1_ITEM) + X509V3_EXT_D2I = lltype.FuncType([rffi.VOIDP, rffi.CCHARPP, rffi.LONG], + rffi.VOIDP) + v3_ext_method = rffi_platform.Struct( + 'struct v3_ext_method', + [('it', lltype.Ptr(ASN1_ITEM_EXP)), + ('d2i', lltype.Ptr(X509V3_EXT_D2I))]) + GENERAL_NAME_st = rffi_platform.Struct( + 'struct GENERAL_NAME_st', + [('type', rffi.INT), + ]) + + for k, v in rffi_platform.configure(CConfig).items(): globals()[k] = v # opaque structures SSL_METHOD = rffi.COpaquePtr('SSL_METHOD') SSL_CTX = rffi.COpaquePtr('SSL_CTX') +SSL_CIPHER = rffi.COpaquePtr('SSL_CIPHER') SSL = rffi.COpaquePtr('SSL') BIO = rffi.COpaquePtr('BIO') X509 = rffi.COpaquePtr('X509') -X509_NAME = rffi.COpaquePtr('X509_NAME') +X509_NAME_ENTRY = rffi.CArrayPtr(X509_name_entry_st) +X509_EXTENSION = rffi.CArrayPtr(X509_extension_st) +X509V3_EXT_METHOD = rffi.CArrayPtr(v3_ext_method) +ASN1_OBJECT = rffi.COpaquePtr('ASN1_OBJECT') +ASN1_STRING.TO.become(asn1_string_st) +ASN1_TIME = rffi.COpaquePtr('ASN1_TIME') +ASN1_INTEGER = rffi.COpaquePtr('ASN1_INTEGER') +GENERAL_NAMES = rffi.COpaquePtr('GENERAL_NAMES') +GENERAL_NAME = rffi.CArrayPtr(GENERAL_NAME_st) HAVE_OPENSSL_RAND = OPENSSL_VERSION_NUMBER >= 0x0090500f @@ -97,18 +144,36 @@ ssl_external('SSL_load_error_strings', [], lltype.Void) ssl_external('SSL_library_init', [], rffi.INT) +ssl_external('CRYPTO_num_locks', [], rffi.INT) +ssl_external('CRYPTO_set_locking_callback', + [lltype.Ptr(lltype.FuncType( + [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], + lltype.Void) +ssl_external('CRYPTO_set_id_callback', + [lltype.Ptr(lltype.FuncType([], rffi.INT))], + lltype.Void) + if HAVE_OPENSSL_RAND: ssl_external('RAND_add', [rffi.CCHARP, rffi.INT, rffi.DOUBLE], lltype.Void) ssl_external('RAND_status', [], rffi.INT) ssl_external('RAND_egd', [rffi.CCHARP], rffi.INT) ssl_external('SSL_CTX_new', [SSL_METHOD], SSL_CTX) +ssl_external('SSL_get_SSL_CTX', [SSL], SSL_CTX) +ssl_external('TLSv1_method', [], SSL_METHOD) +ssl_external('SSLv2_method', [], SSL_METHOD) +ssl_external('SSLv3_method', [], SSL_METHOD) ssl_external('SSLv23_method', [], SSL_METHOD) ssl_external('SSL_CTX_use_PrivateKey_file', [SSL_CTX, rffi.CCHARP, rffi.INT], rffi.INT) ssl_external('SSL_CTX_use_certificate_chain_file', [SSL_CTX, rffi.CCHARP], rffi.INT) +ssl_external('SSL_CTX_set_options', [SSL_CTX, rffi.INT], rffi.INT, macro=True) ssl_external('SSL_CTX_ctrl', [SSL_CTX, rffi.INT, rffi.INT, rffi.VOIDP], rffi.INT) ssl_external('SSL_CTX_set_verify', [SSL_CTX, rffi.INT, rffi.VOIDP], lltype.Void) +ssl_external('SSL_CTX_get_verify_mode', [SSL_CTX], rffi.INT) +ssl_external('SSL_CTX_set_cipher_list', [SSL_CTX, rffi.CCHARP], rffi.INT) +ssl_external('SSL_CTX_load_verify_locations', [SSL_CTX, rffi.CCHARP, rffi.CCHARP], rffi.INT) ssl_external('SSL_new', [SSL_CTX], SSL) ssl_external('SSL_set_fd', [SSL, rffi.INT], rffi.INT) +ssl_external('SSL_set_mode', [SSL, rffi.INT], rffi.INT, macro=True) ssl_external('SSL_ctrl', [SSL, rffi.INT, rffi.INT, rffi.VOIDP], rffi.INT) ssl_external('BIO_ctrl', [BIO, rffi.INT, rffi.INT, rffi.VOIDP], rffi.INT) ssl_external('SSL_get_rbio', [SSL], BIO) @@ -122,20 +187,70 @@ ssl_external('SSL_get_shutdown', [SSL], rffi.INT) ssl_external('SSL_set_read_ahead', [SSL, rffi.INT], lltype.Void) -ssl_external('ERR_get_error', [], rffi.INT) -ssl_external('ERR_error_string', [rffi.ULONG, rffi.CCHARP], rffi.CCHARP) ssl_external('SSL_get_peer_certificate', [SSL], X509) ssl_external('X509_get_subject_name', [X509], X509_NAME) ssl_external('X509_get_issuer_name', [X509], X509_NAME) ssl_external('X509_NAME_oneline', [X509_NAME, rffi.CCHARP, rffi.INT], rffi.CCHARP) +ssl_external('X509_NAME_entry_count', [X509_NAME], rffi.INT) +ssl_external('X509_NAME_get_entry', [X509_NAME, rffi.INT], X509_NAME_ENTRY) +ssl_external('X509_NAME_ENTRY_get_object', [X509_NAME_ENTRY], ASN1_OBJECT) +ssl_external('X509_NAME_ENTRY_get_data', [X509_NAME_ENTRY], ASN1_STRING) +ssl_external('i2d_X509', [X509, rffi.CCHARPP], rffi.INT) ssl_external('X509_free', [X509], lltype.Void) +ssl_external('X509_get_notBefore', [X509], ASN1_TIME, macro=True) +ssl_external('X509_get_notAfter', [X509], ASN1_TIME, macro=True) +ssl_external('X509_get_serialNumber', [X509], ASN1_INTEGER) +ssl_external('X509_get_version', [X509], rffi.INT, macro=True) +ssl_external('X509_get_ext_by_NID', [X509, rffi.INT, rffi.INT], rffi.INT) +ssl_external('X509_get_ext', [X509, rffi.INT], X509_EXTENSION) +ssl_external('X509V3_EXT_get', [X509_EXTENSION], X509V3_EXT_METHOD) + + +ssl_external('OBJ_obj2txt', + [rffi.CCHARP, rffi.INT, ASN1_OBJECT, rffi.INT], rffi.INT) +ssl_external('ASN1_STRING_to_UTF8', [rffi.CCHARPP, ASN1_STRING], rffi.INT) +ssl_external('ASN1_TIME_print', [BIO, ASN1_TIME], rffi.INT) +ssl_external('i2a_ASN1_INTEGER', [BIO, ASN1_INTEGER], rffi.INT) +ssl_external('ASN1_item_d2i', + [rffi.VOIDP, rffi.CCHARPP, rffi.LONG, ASN1_ITEM], rffi.VOIDP) +ssl_external('ASN1_ITEM_ptr', [rffi.VOIDP], ASN1_ITEM, macro=True) + +ssl_external('sk_GENERAL_NAME_num', [GENERAL_NAMES], rffi.INT, + macro=True) +ssl_external('sk_GENERAL_NAME_value', [GENERAL_NAMES, rffi.INT], GENERAL_NAME, + macro=True) +ssl_external('GENERAL_NAME_print', [BIO, GENERAL_NAME], rffi.INT) +ssl_external('pypy_GENERAL_NAME_dirn', [GENERAL_NAME], X509_NAME, + macro=True) + +ssl_external('SSL_get_current_cipher', [SSL], SSL_CIPHER) +ssl_external('SSL_CIPHER_get_name', [SSL_CIPHER], rffi.CCHARP) +ssl_external('SSL_CIPHER_get_version', [SSL_CIPHER], rffi.CCHARP) +ssl_external('SSL_CIPHER_get_bits', [SSL_CIPHER, rffi.INTP], rffi.INT) + +ssl_external('ERR_get_error', [], rffi.INT) +ssl_external('ERR_error_string', [rffi.ULONG, rffi.CCHARP], rffi.CCHARP) + ssl_external('SSL_free', [SSL], lltype.Void) ssl_external('SSL_CTX_free', [SSL_CTX], lltype.Void) +ssl_external('CRYPTO_free', [rffi.VOIDP], lltype.Void) +libssl_OPENSSL_free = libssl_CRYPTO_free + ssl_external('SSL_write', [SSL, rffi.CCHARP, rffi.INT], rffi.INT) ssl_external('SSL_pending', [SSL], rffi.INT) ssl_external('SSL_read', [SSL, rffi.CCHARP, rffi.INT], rffi.INT) -ssl_external('SSL_read', [SSL, rffi.CCHARP, rffi.INT], rffi.INT) +BIO_METHOD = rffi.COpaquePtr('BIO_METHOD') +ssl_external('BIO_s_mem', [], BIO_METHOD) +ssl_external('BIO_s_file', [], BIO_METHOD) +ssl_external('BIO_new', [BIO_METHOD], BIO) +ssl_external('BIO_set_nbio', [BIO, rffi.INT], rffi.INT, macro=True) +ssl_external('BIO_free', [BIO], rffi.INT) +ssl_external('BIO_reset', [BIO], rffi.INT, macro=True) +ssl_external('BIO_read_filename', [BIO, rffi.CCHARP], rffi.INT, macro=True) +ssl_external('BIO_gets', [BIO, rffi.CCHARP, rffi.INT], rffi.INT) +ssl_external('PEM_read_bio_X509_AUX', + [BIO, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP], X509) EVP_MD_CTX = rffi.COpaquePtr('EVP_MD_CTX', compilation_info=eci) EVP_MD = rffi.COpaquePtr('EVP_MD') @@ -159,13 +274,6 @@ EVP_MD_CTX_cleanup = external( 'EVP_MD_CTX_cleanup', [EVP_MD_CTX], rffi.INT) -def libssl_SSL_set_mode(ssl, op): - return libssl_SSL_ctrl(ssl, SSL_CTRL_MODE, op, None) -def libssl_SSL_CTX_set_options(ctx, op): - return libssl_SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, op, None) -def libssl_BIO_set_nbio(bio, nonblocking): - return libssl_BIO_ctrl(bio, BIO_C_SET_NBIO, nonblocking, None) - def init_ssl(): libssl_SSL_load_error_strings() libssl_SSL_library_init() diff --git a/pypy/rlib/test/test_rsocket.py b/pypy/rlib/test/test_rsocket.py --- a/pypy/rlib/test/test_rsocket.py +++ b/pypy/rlib/test/test_rsocket.py @@ -297,24 +297,25 @@ e = py.test.raises(GAIError, getaddrinfo, 'www.very-invalidaddress.com', None) assert isinstance(e.value.get_msg(), str) -def test_getaddrinfo_codespeak(): - lst = getaddrinfo('codespeak.net', None) +def test_getaddrinfo_pydotorg(): + lst = getaddrinfo('python.org', None) assert isinstance(lst, list) found = False for family, socktype, protocol, canonname, addr in lst: - if addr.get_host() == '88.198.193.90': + if addr.get_host() == '82.94.164.162': found = True assert found, lst def test_getaddrinfo_no_reverse_lookup(): # It seems that getaddrinfo never runs a reverse lookup on Linux. # Python2.3 on Windows returns the hostname. - lst = getaddrinfo('213.239.226.252', None, flags=AI_NUMERICHOST) + lst = getaddrinfo('82.94.164.162', None, flags=AI_NUMERICHOST) assert isinstance(lst, list) found = False + print lst for family, socktype, protocol, canonname, addr in lst: - assert canonname != 'codespeak.net' - if addr.get_host() == '213.239.226.252': + assert 'python.org' not in canonname + if addr.get_host() == '82.94.164.162': found = True assert found, lst diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -616,7 +616,7 @@ container = llobj._obj.container T = lltype.Ptr(lltype.typeOf(container)) # otherwise it came from integer and we want a c_void_p with - # the same valu + # the same value if getattr(container, 'llopaque', None): no = len(_opaque_objs) _opaque_objs.append(container) @@ -774,7 +774,7 @@ # CFunctionType.__nonzero__ is broken before Python 2.6 return lltype.nullptr(T.TO) if isinstance(T.TO, lltype.Struct): - if ptrval & 1: # a tagged pointer + if T.TO._gckind == 'gc' and ptrval & 1: # a tagged pointer gcref = _opaque_objs[ptrval // 2].hide() return lltype.cast_opaque_ptr(T, gcref) REAL_TYPE = T.TO @@ -973,13 +973,13 @@ if funcname == 'mmap': funcname = 'mmap64' if hasattr(old_eci, '_with_ctypes'): - eci = old_eci._with_ctypes - else: - try: - eci = _eci_cache[old_eci] - except KeyError: - eci = old_eci.compile_shared_lib() - _eci_cache[old_eci] = eci + old_eci = old_eci._with_ctypes + + try: + eci = _eci_cache[old_eci] + except KeyError: + eci = old_eci.compile_shared_lib() + _eci_cache[old_eci] = eci libraries = eci.testonly_libraries + eci.libraries + eci.frameworks diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py --- a/pypy/rpython/lltypesystem/rbuilder.py +++ b/pypy/rpython/lltypesystem/rbuilder.py @@ -6,6 +6,7 @@ from pypy.rpython.annlowlevel import llstr from pypy.rlib import rgc from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.objectmodel import enforceargs from pypy.rpython.lltypesystem.lltype import staticAdtMethod from pypy.tool.sourcetools import func_with_new_name @@ -15,6 +16,7 @@ GROW_FAST_UNTIL = 100*1024*1024 # 100 MB def new_grow_func(name, mallocfn, copycontentsfn): + @enforceargs(None, int) def stringbuilder_grow(ll_builder, needed): allocated = ll_builder.allocated #if allocated < GROW_FAST_UNTIL: diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -15,6 +15,7 @@ from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.rpython.annlowlevel import llhelper from pypy.rlib.objectmodel import we_are_translated +from pypy.rlib.rstring import StringBuilder, UnicodeBuilder from pypy.rpython.lltypesystem import llmemory import os, sys @@ -54,7 +55,8 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False): + oo_primitive=None, pure_function=False, + macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -78,7 +80,13 @@ assert callable(_callable) ext_type = lltype.FuncType(args, result) if _callable is None: - _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) + if macro is not None: + if macro is True: + macro = name + _callable = generate_macro_wrapper( + name, macro, ext_type, compilation_info) + else: + _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) if pure_function: _callable._pure_function_ = True kwds = {} @@ -314,6 +322,41 @@ compilation_info=eci, sandboxsafe=True, _nowrapper=True, _callable=lambda: None) +def generate_macro_wrapper(name, macro, functype, eci): + """Wraps a function-like macro inside a real function, and expose + it with llexternal.""" + + # Generate the function call + from pypy.translator.c.database import LowLevelDatabase + from pypy.translator.c.support import cdecl + wrapper_name = 'pypy_macro_wrapper_%s' % (name,) + argnames = ['arg%d' % (i,) for i in range(len(functype.ARGS))] + db = LowLevelDatabase() + implementationtypename = db.gettype(functype, argnames=argnames) + if functype.RESULT is lltype.Void: + pattern = '%s { %s(%s); }' + else: + pattern = '%s { return %s(%s); }' + source = pattern % ( + cdecl(implementationtypename, wrapper_name), + macro, ', '.join(argnames)) + + # Now stuff this source into a "companion" eci that will be used + # by ll2ctypes. We replace eci._with_ctypes, so that only one + # shared library is actually compiled (when ll2ctypes calls the + # first function) + ctypes_eci = eci.merge(ExternalCompilationInfo( + separate_module_sources=[source], + export_symbols=[wrapper_name], + )) + if hasattr(eci, '_with_ctypes'): + ctypes_eci = eci._with_ctypes.merge(ctypes_eci) + eci._with_ctypes = ctypes_eci + func = llexternal(wrapper_name, functype.ARGS, functype.RESULT, + compilation_info=eci, _nowrapper=True) + # _nowrapper=True returns a pointer which is not hashable + return lambda *args: func(*args) + # ____________________________________________________________ # Few helpers for keeping callback arguments alive # this makes passing opaque objects possible (they don't even pass @@ -496,7 +539,7 @@ val = rffi_platform.sizeof(name, compilation_info) cache[name] = val return val - + hints['getsize'] = lazy_getsize return lltype.OpaqueType(name, hints) @@ -594,24 +637,24 @@ # conversions between str and char* # conversions between unicode and wchar_t* def make_string_mappings(strtype): - + if strtype is str: from pypy.rpython.lltypesystem.rstr import STR as STRTYPE from pypy.rpython.annlowlevel import llstr as llstrtype from pypy.rpython.annlowlevel import hlstr as hlstrtype TYPEP = CCHARP ll_char_type = lltype.Char - emptystr = '' lastchar = '\x00' + builder_class = StringBuilder else: from pypy.rpython.lltypesystem.rstr import UNICODE as STRTYPE from pypy.rpython.annlowlevel import llunicode as llstrtype from pypy.rpython.annlowlevel import hlunicode as hlstrtype TYPEP = CWCHARP ll_char_type = lltype.UniChar - emptystr = u'' lastchar = u'\x00' - + builder_class = UnicodeBuilder + # str -> char* def str2charp(s): """ str -> char* @@ -632,12 +675,12 @@ # char* -> str # doesn't free char* def charp2str(cp): - l = [] + b = builder_class() i = 0 while cp[i] != lastchar: - l.append(cp[i]) + b.append(cp[i]) i += 1 - return emptystr.join(l) + return b.build() # str -> char* def get_nonmovingbuffer(data): @@ -735,17 +778,19 @@ # char* -> str, with an upper bound on the length in case there is no \x00 def charp2strn(cp, maxlen): - l = [] + b = builder_class(maxlen) i = 0 while i < maxlen and cp[i] != lastchar: - l.append(cp[i]) + b.append(cp[i]) i += 1 - return emptystr.join(l) + return b.build() # char* and size -> str (which can contain null bytes) def charpsize2str(cp, size): - l = [cp[i] for i in range(size)] - return emptystr.join(l) + b = builder_class(size) + for i in xrange(size): + b.append(cp[i]) + return b.build() charpsize2str._annenforceargs_ = [None, int] return (str2charp, free_charp, charp2str, diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -787,6 +787,19 @@ res = fn() assert res == 42 + def test_llexternal_macro(self): + eci = ExternalCompilationInfo( + post_include_bits = ["#define fn(x) (42 + x)"], + ) + fn1 = rffi.llexternal('fn', [rffi.INT], rffi.INT, + compilation_info=eci, macro=True) + fn2 = rffi.llexternal('fn2', [rffi.DOUBLE], rffi.DOUBLE, + compilation_info=eci, macro='fn') + res = fn1(10) + assert res == 52 + res = fn2(10.5) + assert res == 52.5 + def test_prebuilt_constant(self): header = py.code.Source(""" #ifndef _SOME_H @@ -1318,7 +1331,6 @@ class TestPlatform(object): def test_lib_on_libpaths(self): from pypy.translator.platform import platform - from pypy.translator.tool.cbuild import ExternalCompilationInfo tmpdir = udir.join('lib_on_libppaths') tmpdir.ensure(dir=1) @@ -1340,7 +1352,6 @@ py.test.skip("Not supported") from pypy.translator.platform import platform - from pypy.translator.tool.cbuild import ExternalCompilationInfo tmpdir = udir.join('lib_on_libppaths_prefix') tmpdir.ensure(dir=1) diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -714,8 +714,7 @@ malloc_ptr = self.malloc_varsize_clear_ptr args = [self.c_const_gc, c_type_id, v_length, c_size, c_varitemsize, c_ofstolength, c_can_collect] - keep_current_args = flags.get('keep_current_args', False) - livevars = self.push_roots(hop, keep_current_args=keep_current_args) + livevars = self.push_roots(hop) v_result = hop.genop("direct_call", [malloc_ptr] + args, resulttype=llmemory.GCREF) self.pop_roots(hop, livevars) diff --git a/pypy/rpython/memory/test/test_gctypelayout.py b/pypy/rpython/memory/test/test_gctypelayout.py --- a/pypy/rpython/memory/test/test_gctypelayout.py +++ b/pypy/rpython/memory/test/test_gctypelayout.py @@ -4,6 +4,7 @@ from pypy.rpython.memory.gctypelayout import gc_pointers_inside from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.test.test_llinterp import get_interpreter +from pypy.rpython.rclass import IR_IMMUTABLE from pypy.objspace.flow.model import Constant class FakeGC: @@ -101,7 +102,7 @@ accessor = rclass.FieldListAccessor() S3 = lltype.GcStruct('S', ('x', PT), ('y', PT), hints={'immutable_fields': accessor}) - accessor.initialize(S3, {'x': ''}) + accessor.initialize(S3, {'x': IR_IMMUTABLE}) # s1 = lltype.malloc(S1) adr = llmemory.cast_ptr_to_adr(s1) diff --git a/pypy/rpython/test/test_rfloat.py b/pypy/rpython/test/test_rfloat.py --- a/pypy/rpython/test/test_rfloat.py +++ b/pypy/rpython/test/test_rfloat.py @@ -177,7 +177,11 @@ n1 = x * x n2 = y * y * y return rfloat.isnan(n1 / n2) - assert self.interpret(fn, [1e200, 1e200]) # nan + if self.__class__.__name__ != 'TestCliFloat': + # the next line currently fails on mono 2.6.7 (ubuntu 11.04), see: + # https://bugzilla.novell.com/show_bug.cgi?id=692493 + assert self.interpret(fn, [1e200, 1e200]) # nan + # assert not self.interpret(fn, [1e200, 1.0]) # +inf assert not self.interpret(fn, [1e200, -1.0]) # -inf assert not self.interpret(fn, [42.5, 2.3]) # +finite @@ -205,7 +209,11 @@ assert self.interpret(fn, [42.5, -2.3]) # -finite assert not self.interpret(fn, [1e200, 1.0]) # +inf assert not self.interpret(fn, [1e200, -1.0]) # -inf - assert not self.interpret(fn, [1e200, 1e200]) # nan + # + if self.__class__.__name__ != 'TestCliFloat': + # the next line currently fails on mono 2.6.7 (ubuntu 11.04), see: + # https://bugzilla.novell.com/show_bug.cgi?id=692493 + assert not self.interpret(fn, [1e200, 1e200]) # nan class TestLLtype(BaseTestRfloat, LLRtypeMixin): diff --git a/pypy/tool/clean_old_branches.py b/pypy/tool/clean_old_branches.py new file mode 100644 --- /dev/null +++ b/pypy/tool/clean_old_branches.py @@ -0,0 +1,72 @@ +""" +For branches that have been closed but still have a dangling head +in 'hg heads --topo --closed', force them to join with the branch +called 'closed-branch'. It reduces the number of heads. +""" + +import os, sys + +if not os.listdir('.hg'): + print 'Must run this script from the top-level directory.' + sys.exit(1) + +def heads(args): + g = os.popen(r"hg heads --topo %s --template '{branches} {node|short}\n'" + % args, 'r') + result = g.read() + g.close() + result = result.splitlines(False) + result = [s for s in result + if not s.startswith(' ') + and not s.startswith('closed-branches ')] + return result + +all_heads = heads("--closed") +opened_heads = heads("") + +closed_heads = [s for s in all_heads if s not in opened_heads] + +if not closed_heads: + print >> sys.stderr, 'no dangling closed heads.' + sys.exit() + +# ____________________________________________________________ + +closed_heads.reverse() + +for branch_head in closed_heads: + branch, head = branch_head.split() + print '\t', branch +print +print 'The branches listed above will be merged to "closed-branches".' +print 'You need to run this script in a clean working copy where you' +print 'don''t mind all files being removed.' +print +if raw_input('Continue? [y/n] ').upper() != 'Y': + sys.exit(1) + +# ____________________________________________________________ + +def do(cmd): + print cmd + err = os.system(cmd) + if err != 0: + print '*** error %r' % (err,) + sys.exit(1) + +for branch_head in closed_heads: + branch, head = branch_head.split() + print + print '***** %s ***** %s *****' % (branch, head) + do("hg up --clean closed-branches") + do("hg --config extensions.purge= purge --all") + do("hg merge -y %s" % head) + for fn in os.listdir('.'): + if fn.lower() != '.hg': + do("rm -fr -- '%s'" % fn) + do("hg rm --after -- '%s' || true" % fn) + do("hg ci -m'Merge closed head %s on branch %s'" % (head, branch)) + +print +do("hg ci --close-branch -m're-close this branch'") +do("hg up default") diff --git a/pypy/tool/frozenlist.py b/pypy/tool/frozenlist.py new file mode 100644 --- /dev/null +++ b/pypy/tool/frozenlist.py @@ -0,0 +1,19 @@ +from pypy.tool.sourcetools import func_with_new_name + +def forbid(*args): + raise TypeError, "cannot mutate a frozenlist" + +class frozenlist(list): + __setitem__ = func_with_new_name(forbid, '__setitem__') + __delitem__ = func_with_new_name(forbid, '__delitem__') + __setslice__ = func_with_new_name(forbid, '__setslice__') + __delslice__ = func_with_new_name(forbid, '__delslice__') + __iadd__ = func_with_new_name(forbid, '__iadd__') + __imul__ = func_with_new_name(forbid, '__imul__') + append = func_with_new_name(forbid, 'append') + insert = func_with_new_name(forbid, 'insert') + pop = func_with_new_name(forbid, 'pop') + remove = func_with_new_name(forbid, 'remove') + reverse = func_with_new_name(forbid, 'reverse') + sort = func_with_new_name(forbid, 'sort') + extend = func_with_new_name(forbid, 'extend') diff --git a/pypy/tool/runsubprocess.py b/pypy/tool/runsubprocess.py --- a/pypy/tool/runsubprocess.py +++ b/pypy/tool/runsubprocess.py @@ -3,7 +3,7 @@ if the current process already grew very large. """ -import sys +import sys, gc import os from subprocess import PIPE, Popen @@ -21,6 +21,11 @@ else: args = [str(executable)] + args shell = False + # Just before spawning the subprocess, do a gc.collect(). This + # should help if we are running on top of PyPy, if the subprocess + # is going to need a lot of RAM and we are using a lot too. + gc.collect() + # pipe = Popen(args, stdout=PIPE, stderr=PIPE, shell=shell, env=env, cwd=cwd) stdout, stderr = pipe.communicate() return pipe.returncode, stdout, stderr diff --git a/pypy/tool/test/test_frozenlist.py b/pypy/tool/test/test_frozenlist.py new file mode 100644 --- /dev/null +++ b/pypy/tool/test/test_frozenlist.py @@ -0,0 +1,21 @@ +import py +from pypy.tool.frozenlist import frozenlist + +def test_frozenlist(): + l = frozenlist([1, 2, 3]) + assert l[0] == 1 + assert l[:2] == [1, 2] + assert l.index(2) == 1 + py.test.raises(TypeError, "l[0] = 1") + py.test.raises(TypeError, "del l[0]") + py.test.raises(TypeError, "l[:] = []") + py.test.raises(TypeError, "del l[:]") + py.test.raises(TypeError, "l += []") + py.test.raises(TypeError, "l *= 2") + py.test.raises(TypeError, "l.append(1)") + py.test.raises(TypeError, "l.insert(0, 0)") + py.test.raises(TypeError, "l.pop()") + py.test.raises(TypeError, "l.remove(1)") + py.test.raises(TypeError, "l.reverse()") + py.test.raises(TypeError, "l.sort()") + py.test.raises(TypeError, "l.extend([])") diff --git a/pypy/translator/backendopt/test/test_constfold.py b/pypy/translator/backendopt/test/test_constfold.py --- a/pypy/translator/backendopt/test/test_constfold.py +++ b/pypy/translator/backendopt/test/test_constfold.py @@ -49,7 +49,7 @@ accessor = rclass.FieldListAccessor() S2 = lltype.GcStruct('S2', ('x', lltype.Signed), hints={'immutable_fields': accessor}) - accessor.initialize(S2, {'x': ''}) + accessor.initialize(S2, {'x': rclass.IR_IMMUTABLE}) test_simple(S2) diff --git a/pypy/translator/c/funcgen.py b/pypy/translator/c/funcgen.py --- a/pypy/translator/c/funcgen.py +++ b/pypy/translator/c/funcgen.py @@ -843,6 +843,9 @@ return '%s = %s; /* JIT_FORCE_VIRTUAL */' % (self.expr(op.result), self.expr(op.args[0])) + def OP_JIT_FORCE_QUASI_IMMUTABLE(self, op): + return '/* JIT_FORCE_QUASI_IMMUTABLE %s */' % op + def OP_GET_GROUP_MEMBER(self, op): typename = self.db.gettype(op.result.concretetype) return '%s = (%s)_OP_GET_GROUP_MEMBER(%s, %s);' % ( diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -508,27 +508,15 @@ shared = self.config.translation.shared - if (self.config.translation.gcrootfinder == "asmgcc" or - self.config.translation.force_make): - extra_opts = [] - if self.config.translation.make_jobs != 1: - extra_opts += ['-j', str(self.config.translation.make_jobs)] - self.translator.platform.execute_makefile(self.targetdir, - extra_opts) - if shared: - self.shared_library_name = self.executable_name.new( - purebasename='lib' + self.executable_name.purebasename, - ext=self.translator.platform.so_ext) - else: - compiler = CCompilerDriver(self.translator.platform, - [self.c_source_filename] + self.extrafiles, - self.eci, profbased=self.getprofbased(), - outputfilename=exe_name) - self.executable_name = compiler.build(shared=shared) - if shared: - self.executable_name = self.build_main_for_shared( - self.executable_name, "pypy_main_startup", exe_name) - assert self.executable_name + extra_opts = [] + if self.config.translation.make_jobs != 1: + extra_opts += ['-j', str(self.config.translation.make_jobs)] + self.translator.platform.execute_makefile(self.targetdir, + extra_opts) + if shared: + self.shared_library_name = self.executable_name.new( + purebasename='lib' + self.executable_name.purebasename, + ext=self.translator.platform.so_ext) self._compiled = True return self.executable_name diff --git a/pypy/translator/c/src/cjkcodecs/README b/pypy/translator/c/src/cjkcodecs/README new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/README @@ -0,0 +1,86 @@ +Source +------ +The .c and .h files come directly from CPython, with the exception of +cjkcodecs.h and multibytecodec.h, which have been ripped of their +CPython dependencies. + + +To generate or modify mapping headers +------------------------------------- +Mapping headers are imported from CJKCodecs as pre-generated form. +If you need to tweak or add something on it, please look at tools/ +subdirectory of CJKCodecs' distribution. + + + +Notes on implmentation characteristics of each codecs +----------------------------------------------------- + +1) Big5 codec + + The big5 codec maps the following characters as cp950 does rather + than conforming Unicode.org's that maps to 0xFFFD. + + BIG5 Unicode Description + + 0xA15A 0x2574 SPACING UNDERSCORE + 0xA1C3 0xFFE3 SPACING HEAVY OVERSCORE + 0xA1C5 0x02CD SPACING HEAVY UNDERSCORE + 0xA1FE 0xFF0F LT DIAG UP RIGHT TO LOW LEFT + 0xA240 0xFF3C LT DIAG UP LEFT TO LOW RIGHT + 0xA2CC 0x5341 HANGZHOU NUMERAL TEN + 0xA2CE 0x5345 HANGZHOU NUMERAL THIRTY + + Because unicode 0x5341, 0x5345, 0xFF0F, 0xFF3C is mapped to another + big5 codes already, a roundtrip compatibility is not guaranteed for + them. + + +2) cp932 codec + + To conform to Windows's real mapping, cp932 codec maps the following + codepoints in addition of the official cp932 mapping. + + CP932 Unicode Description + + 0x80 0x80 UNDEFINED + 0xA0 0xF8F0 UNDEFINED + 0xFD 0xF8F1 UNDEFINED + 0xFE 0xF8F2 UNDEFINED + 0xFF 0xF8F3 UNDEFINED + + +3) euc-jisx0213 codec + + The euc-jisx0213 codec maps JIS X 0213 Plane 1 code 0x2140 into + unicode U+FF3C instead of U+005C as on unicode.org's mapping. + Because euc-jisx0213 has REVERSE SOLIDUS on 0x5c already and A140 + is shown as a full width character, mapping to U+FF3C can make + more sense. + + The euc-jisx0213 codec is enabled to decode JIS X 0212 codes on + codeset 2. Because JIS X 0212 and JIS X 0213 Plane 2 don't have + overlapped by each other, it doesn't bother standard conformations + (and JIS X 0213 Plane 2 is intended to use so.) On encoding + sessions, the codec will try to encode kanji characters in this + order: + + JIS X 0213 Plane 1 -> JIS X 0213 Plane 2 -> JIS X 0212 + + +4) euc-jp codec + + The euc-jp codec is a compatibility instance on these points: + - U+FF3C FULLWIDTH REVERSE SOLIDUS is mapped to EUC-JP A1C0 (vice versa) + - U+00A5 YEN SIGN is mapped to EUC-JP 0x5c. (one way) + - U+203E OVERLINE is mapped to EUC-JP 0x7e. (one way) + + +5) shift-jis codec + + The shift-jis codec is mapping 0x20-0x7e area to U+20-U+7E directly + instead of using JIS X 0201 for compatibility. The differences are: + - U+005C REVERSE SOLIDUS is mapped to SHIFT-JIS 0x5c. + - U+007E TILDE is mapped to SHIFT-JIS 0x7e. + - U+FF3C FULL-WIDTH REVERSE SOLIDUS is mapped to SHIFT-JIS 815f. + diff --git a/pypy/translator/c/src/cjkcodecs/_codecs_cn.c b/pypy/translator/c/src/cjkcodecs/_codecs_cn.c new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/_codecs_cn.c @@ -0,0 +1,444 @@ +/* + * _codecs_cn.c: Codecs collection for Mainland Chinese encodings + * + * Written by Hye-Shik Chang + */ + +#include "src/cjkcodecs/cjkcodecs.h" +#include "src/cjkcodecs/mappings_cn.h" + +/** + * hz is predefined as 100 on AIX. So we undefine it to avoid + * conflict against hz codec's. + */ +#ifdef _AIX +#undef hz +#endif + +/* GBK and GB2312 map differently in few codepoints that are listed below: + * + * gb2312 gbk + * A1A4 U+30FB KATAKANA MIDDLE DOT U+00B7 MIDDLE DOT + * A1AA U+2015 HORIZONTAL BAR U+2014 EM DASH + * A844 undefined U+2015 HORIZONTAL BAR + */ + +#define GBK_DECODE(dc1, dc2, assi) \ + if ((dc1) == 0xa1 && (dc2) == 0xaa) (assi) = 0x2014; \ + else if ((dc1) == 0xa8 && (dc2) == 0x44) (assi) = 0x2015; \ + else if ((dc1) == 0xa1 && (dc2) == 0xa4) (assi) = 0x00b7; \ + else TRYMAP_DEC(gb2312, assi, dc1 ^ 0x80, dc2 ^ 0x80); \ + else TRYMAP_DEC(gbkext, assi, dc1, dc2); + +#define GBK_ENCODE(code, assi) \ + if ((code) == 0x2014) (assi) = 0xa1aa; \ + else if ((code) == 0x2015) (assi) = 0xa844; \ + else if ((code) == 0x00b7) (assi) = 0xa1a4; \ + else if ((code) != 0x30fb && TRYMAP_ENC_COND(gbcommon, assi, code)); + +/* + * GB2312 codec + */ + +ENCODER(gb2312) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + TRYMAP_ENC(gbcommon, code, c); + else return 1; + + if (code & 0x8000) /* MSB set: GBK */ + return 1; + + OUT1((code >> 8) | 0x80) + OUT2((code & 0xFF) | 0x80) + NEXT(1, 2) + } + + return 0; +} + +DECODER(gb2312) +{ + while (inleft > 0) { + unsigned char c = **inbuf; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + TRYMAP_DEC(gb2312, **outbuf, c ^ 0x80, IN2 ^ 0x80) { + NEXT(2, 1) + } + else return 2; + } + + return 0; +} + + +/* + * GBK codec + */ + +ENCODER(gbk) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + + GBK_ENCODE(c, code) + else return 1; + + OUT1((code >> 8) | 0x80) + if (code & 0x8000) + OUT2((code & 0xFF)) /* MSB set: GBK */ + else + OUT2((code & 0xFF) | 0x80) /* MSB unset: GB2312 */ + NEXT(1, 2) + } + + return 0; +} + +DECODER(gbk) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + GBK_DECODE(c, IN2, **outbuf) + else return 2; + + NEXT(2, 1) + } + + return 0; +} + + +/* + * GB18030 codec + */ + +ENCODER(gb18030) +{ + while (inleft > 0) { + ucs4_t c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1(c) + NEXT(1, 1) + continue; + } + + DECODE_SURROGATE(c) + if (c > 0x10FFFF) +#if Py_UNICODE_SIZE == 2 + return 2; /* surrogates pair */ +#else + return 1; +#endif + else if (c >= 0x10000) { + ucs4_t tc = c - 0x10000; + + REQUIRE_OUTBUF(4) + + OUT4((unsigned char)(tc % 10) + 0x30) + tc /= 10; + OUT3((unsigned char)(tc % 126) + 0x81) + tc /= 126; + OUT2((unsigned char)(tc % 10) + 0x30) + tc /= 10; + OUT1((unsigned char)(tc + 0x90)) + +#if Py_UNICODE_SIZE == 2 + NEXT(2, 4) /* surrogates pair */ +#else + NEXT(1, 4) +#endif + continue; + } + + REQUIRE_OUTBUF(2) + + GBK_ENCODE(c, code) + else TRYMAP_ENC(gb18030ext, code, c); + else { + const struct _gb18030_to_unibmp_ranges *utrrange; + + REQUIRE_OUTBUF(4) + + for (utrrange = gb18030_to_unibmp_ranges; + utrrange->first != 0; + utrrange++) + if (utrrange->first <= c && + c <= utrrange->last) { + Py_UNICODE tc; + + tc = c - utrrange->first + + utrrange->base; + + OUT4((unsigned char)(tc % 10) + 0x30) + tc /= 10; + OUT3((unsigned char)(tc % 126) + 0x81) + tc /= 126; + OUT2((unsigned char)(tc % 10) + 0x30) + tc /= 10; + OUT1((unsigned char)tc + 0x81) + + NEXT(1, 4) + break; + } + + if (utrrange->first == 0) + return 1; + continue; + } + + OUT1((code >> 8) | 0x80) + if (code & 0x8000) + OUT2((code & 0xFF)) /* MSB set: GBK or GB18030ext */ + else + OUT2((code & 0xFF) | 0x80) /* MSB unset: GB2312 */ + + NEXT(1, 2) + } + + return 0; +} + +DECODER(gb18030) +{ + while (inleft > 0) { + unsigned char c = IN1, c2; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + c2 = IN2; + if (c2 >= 0x30 && c2 <= 0x39) { /* 4 bytes seq */ + const struct _gb18030_to_unibmp_ranges *utr; + unsigned char c3, c4; + ucs4_t lseq; + + REQUIRE_INBUF(4) + c3 = IN3; + c4 = IN4; + if (c < 0x81 || c3 < 0x81 || c4 < 0x30 || c4 > 0x39) + return 4; + c -= 0x81; c2 -= 0x30; + c3 -= 0x81; c4 -= 0x30; + + if (c < 4) { /* U+0080 - U+FFFF */ + lseq = ((ucs4_t)c * 10 + c2) * 1260 + + (ucs4_t)c3 * 10 + c4; + if (lseq < 39420) { + for (utr = gb18030_to_unibmp_ranges; + lseq >= (utr + 1)->base; + utr++) ; + OUT1(utr->first - utr->base + lseq) + NEXT(4, 1) + continue; + } + } + else if (c >= 15) { /* U+10000 - U+10FFFF */ + lseq = 0x10000 + (((ucs4_t)c-15) * 10 + c2) + * 1260 + (ucs4_t)c3 * 10 + c4; + if (lseq <= 0x10FFFF) { + WRITEUCS4(lseq); + NEXT_IN(4) + continue; + } + } + return 4; + } + + GBK_DECODE(c, c2, **outbuf) + else TRYMAP_DEC(gb18030ext, **outbuf, c, c2); + else return 2; + + NEXT(2, 1) + } + + return 0; +} + + +/* + * HZ codec + */ + +ENCODER_INIT(hz) +{ + state->i = 0; + return 0; +} + +ENCODER_RESET(hz) +{ + if (state->i != 0) { + WRITE2('~', '}') + state->i = 0; + NEXT_OUT(2) + } + return 0; +} + +ENCODER(hz) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + if (state->i == 0) { + WRITE1((unsigned char)c) + NEXT(1, 1) + } + else { + WRITE3('~', '}', (unsigned char)c) + NEXT(1, 3) + state->i = 0; + } + continue; + } + + UCS4INVALID(c) + + TRYMAP_ENC(gbcommon, code, c); + else return 1; + + if (code & 0x8000) /* MSB set: GBK */ + return 1; + + if (state->i == 0) { + WRITE4('~', '{', code >> 8, code & 0xff) + NEXT(1, 4) + state->i = 1; + } + else { + WRITE2(code >> 8, code & 0xff) + NEXT(1, 2) + } + } + + return 0; +} + +DECODER_INIT(hz) +{ + state->i = 0; + return 0; +} + +DECODER_RESET(hz) +{ + state->i = 0; + return 0; +} + +DECODER(hz) +{ + while (inleft > 0) { + unsigned char c = IN1; + + if (c == '~') { + unsigned char c2 = IN2; + + REQUIRE_INBUF(2) + if (c2 == '~') { + WRITE1('~') + NEXT(2, 1) + continue; + } + else if (c2 == '{' && state->i == 0) + state->i = 1; /* set GB */ + else if (c2 == '}' && state->i == 1) + state->i = 0; /* set ASCII */ + else if (c2 == '\n') + ; /* line-continuation */ + else + return 2; + NEXT(2, 0); + continue; + } + + if (c & 0x80) + return 1; + + if (state->i == 0) { /* ASCII mode */ + WRITE1(c) + NEXT(1, 1) + } + else { /* GB mode */ + REQUIRE_INBUF(2) + REQUIRE_OUTBUF(1) + TRYMAP_DEC(gb2312, **outbuf, c, IN2) { + NEXT(2, 1) + } + else + return 2; + } + } + + return 0; +} + + +BEGIN_MAPPINGS_LIST + MAPPING_DECONLY(gb2312) + MAPPING_DECONLY(gbkext) + MAPPING_ENCONLY(gbcommon) + MAPPING_ENCDEC(gb18030ext) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS(gb2312) + CODEC_STATELESS(gbk) + CODEC_STATELESS(gb18030) + CODEC_STATEFUL(hz) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(cn) diff --git a/pypy/translator/c/src/cjkcodecs/_codecs_hk.c b/pypy/translator/c/src/cjkcodecs/_codecs_hk.c new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/_codecs_hk.c @@ -0,0 +1,180 @@ +/* + * _codecs_hk.c: Codecs collection for encodings from Hong Kong + * + * Written by Hye-Shik Chang + */ + +#define USING_IMPORTED_MAPS + +#include "src/cjkcodecs/cjkcodecs.h" +#include "src/cjkcodecs/mappings_hk.h" + +/* + * BIG5HKSCS codec + */ + +USING_IMPORTED_MAP(big5); +static const encode_map *big5_encmap = NULL; +static const decode_map *big5_decmap = NULL; + +CODEC_INIT(big5hkscs) +{ + IMPORT_MAP(tw, big5, &big5_encmap, &big5_decmap); + return 0; +} + +/* + * There are four possible pair unicode -> big5hkscs maps as in HKSCS 2004: + * U+00CA U+0304 -> 8862 (U+00CA alone is mapped to 8866) + * U+00CA U+030C -> 8864 + * U+00EA U+0304 -> 88a3 (U+00EA alone is mapped to 88a7) + * U+00EA U+030C -> 88a5 + * These are handled by not mapping tables but a hand-written code. + */ +static const DBCHAR big5hkscs_pairenc_table[4] = {0x8862, 0x8864, 0x88a3, 0x88a5}; + +ENCODER(big5hkscs) +{ + while (inleft > 0) { + ucs4_t c = **inbuf; + DBCHAR code; + Py_ssize_t insize; + + if (c < 0x80) { + REQUIRE_OUTBUF(1) + **outbuf = (unsigned char)c; + NEXT(1, 1) + continue; + } + + DECODE_SURROGATE(c) + insize = GET_INSIZE(c); + + REQUIRE_OUTBUF(2) + + if (c < 0x10000) { + TRYMAP_ENC(big5hkscs_bmp, code, c) { + if (code == MULTIC) { + if (inleft >= 2 && + ((c & 0xffdf) == 0x00ca) && + (((*inbuf)[1] & 0xfff7) == 0x0304)) { + code = big5hkscs_pairenc_table[ + ((c >> 4) | + ((*inbuf)[1] >> 3)) & 3]; + insize = 2; + } + else if (inleft < 2 && + !(flags & MBENC_FLUSH)) + return MBERR_TOOFEW; + else { + if (c == 0xca) + code = 0x8866; + else /* c == 0xea */ + code = 0x88a7; + } + } + } + else TRYMAP_ENC(big5, code, c); + else return 1; + } + else if (c < 0x20000) + return insize; + else if (c < 0x30000) { + TRYMAP_ENC(big5hkscs_nonbmp, code, c & 0xffff); + else return insize; + } + else + return insize; + + OUT1(code >> 8) + OUT2(code & 0xFF) + NEXT(insize, 2) + } + + return 0; +} + +#define BH2S(c1, c2) (((c1) - 0x87) * (0xfe - 0x40 + 1) + ((c2) - 0x40)) + +DECODER(big5hkscs) +{ + while (inleft > 0) { + unsigned char c = IN1; + ucs4_t decoded; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + if (0xc6 <= c && c <= 0xc8 && (c >= 0xc7 || IN2 >= 0xa1)) + goto hkscsdec; + + TRYMAP_DEC(big5, **outbuf, c, IN2) { + NEXT(2, 1) + } + else +hkscsdec: TRYMAP_DEC(big5hkscs, decoded, c, IN2) { + int s = BH2S(c, IN2); + const unsigned char *hintbase; + + assert(0x87 <= c && c <= 0xfe); + assert(0x40 <= IN2 && IN2 <= 0xfe); + + if (BH2S(0x87, 0x40) <= s && s <= BH2S(0xa0, 0xfe)) { + hintbase = big5hkscs_phint_0; + s -= BH2S(0x87, 0x40); + } + else if (BH2S(0xc6,0xa1) <= s && s <= BH2S(0xc8,0xfe)){ + hintbase = big5hkscs_phint_12130; + s -= BH2S(0xc6, 0xa1); + } + else if (BH2S(0xf9,0xd6) <= s && s <= BH2S(0xfe,0xfe)){ + hintbase = big5hkscs_phint_21924; + s -= BH2S(0xf9, 0xd6); + } + else + return MBERR_INTERNAL; + + if (hintbase[s >> 3] & (1 << (s & 7))) { + WRITEUCS4(decoded | 0x20000) + NEXT_IN(2) + } + else { + OUT1(decoded) + NEXT(2, 1) + } + } + else { + switch ((c << 8) | IN2) { + case 0x8862: WRITE2(0x00ca, 0x0304); break; + case 0x8864: WRITE2(0x00ca, 0x030c); break; + case 0x88a3: WRITE2(0x00ea, 0x0304); break; + case 0x88a5: WRITE2(0x00ea, 0x030c); break; + default: return 2; + } + + NEXT(2, 2) /* all decoded codepoints are pairs, above. */ + } + } + + return 0; +} + + +BEGIN_MAPPINGS_LIST + MAPPING_DECONLY(big5hkscs) + MAPPING_ENCONLY(big5hkscs_bmp) + MAPPING_ENCONLY(big5hkscs_nonbmp) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS_WINIT(big5hkscs) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(hk) diff --git a/pypy/translator/c/src/cjkcodecs/_codecs_iso2022.c b/pypy/translator/c/src/cjkcodecs/_codecs_iso2022.c new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/_codecs_iso2022.c @@ -0,0 +1,1112 @@ +/* + * _codecs_iso2022.c: Codecs collection for ISO-2022 encodings. + * + * Written by Hye-Shik Chang + */ + +#define USING_IMPORTED_MAPS +#define USING_BINARY_PAIR_SEARCH +#define EXTERN_JISX0213_PAIR +#define EMULATE_JISX0213_2000_ENCODE_INVALID MAP_UNMAPPABLE +#define EMULATE_JISX0213_2000_DECODE_INVALID MAP_UNMAPPABLE + +#include "src/cjkcodecs/cjkcodecs.h" +#include "src/cjkcodecs/alg_jisx0201.h" +#include "src/cjkcodecs/emu_jisx0213_2000.h" +#include "src/cjkcodecs/mappings_jisx0213_pair.h" + +/* STATE + + state->c[0-3] + + 00000000 + ||^^^^^| + |+-----+---- G0-3 Character Set + +----------- Is G0-3 double byte? + + state->c[4] + + 00000000 + || + |+---- Locked-Shift? + +----- ESC Throughout +*/ + +#define ESC 0x1B +#define SO 0x0E +#define SI 0x0F +#define LF 0x0A + +#define MAX_ESCSEQLEN 16 + +#define CHARSET_ISO8859_1 'A' +#define CHARSET_ASCII 'B' +#define CHARSET_ISO8859_7 'F' +#define CHARSET_JISX0201_K 'I' +#define CHARSET_JISX0201_R 'J' + +#define CHARSET_GB2312 ('A'|CHARSET_DBCS) +#define CHARSET_JISX0208 ('B'|CHARSET_DBCS) +#define CHARSET_KSX1001 ('C'|CHARSET_DBCS) +#define CHARSET_JISX0212 ('D'|CHARSET_DBCS) +#define CHARSET_GB2312_8565 ('E'|CHARSET_DBCS) +#define CHARSET_CNS11643_1 ('G'|CHARSET_DBCS) +#define CHARSET_CNS11643_2 ('H'|CHARSET_DBCS) +#define CHARSET_JISX0213_2000_1 ('O'|CHARSET_DBCS) +#define CHARSET_JISX0213_2 ('P'|CHARSET_DBCS) +#define CHARSET_JISX0213_2004_1 ('Q'|CHARSET_DBCS) +#define CHARSET_JISX0208_O ('@'|CHARSET_DBCS) + +#define CHARSET_DBCS 0x80 +#define ESCMARK(mark) ((mark) & 0x7f) + +#define IS_ESCEND(c) (((c) >= 'A' && (c) <= 'Z') || (c) == '@') +#define IS_ISO2022ESC(c2) \ + ((c2) == '(' || (c2) == ')' || (c2) == '$' || \ + (c2) == '.' || (c2) == '&') + /* this is not a complete list of ISO-2022 escape sequence headers. + * but, it's enough to implement CJK instances of iso-2022. */ + +#define MAP_UNMAPPABLE 0xFFFF +#define MAP_MULTIPLE_AVAIL 0xFFFE /* for JIS X 0213 */ + +#define F_SHIFTED 0x01 +#define F_ESCTHROUGHOUT 0x02 + +#define STATE_SETG(dn, v) ((state)->c[dn]) = (v); +#define STATE_GETG(dn) ((state)->c[dn]) + +#define STATE_G0 STATE_GETG(0) +#define STATE_G1 STATE_GETG(1) +#define STATE_G2 STATE_GETG(2) +#define STATE_G3 STATE_GETG(3) +#define STATE_SETG0(v) STATE_SETG(0, v) +#define STATE_SETG1(v) STATE_SETG(1, v) +#define STATE_SETG2(v) STATE_SETG(2, v) +#define STATE_SETG3(v) STATE_SETG(3, v) + +#define STATE_SETFLAG(f) ((state)->c[4]) |= (f); +#define STATE_GETFLAG(f) ((state)->c[4] & (f)) +#define STATE_CLEARFLAG(f) ((state)->c[4]) &= ~(f); +#define STATE_CLEARFLAGS() ((state)->c[4]) = 0; + +#define ISO2022_CONFIG ((const struct iso2022_config *)config) +#define CONFIG_ISSET(flag) (ISO2022_CONFIG->flags & (flag)) +#define CONFIG_DESIGNATIONS (ISO2022_CONFIG->designations) + +/* iso2022_config.flags */ +#define NO_SHIFT 0x01 +#define USE_G2 0x02 +#define USE_JISX0208_EXT 0x04 + +/*-*- internal data structures -*-*/ + +typedef int (*iso2022_init_func)(void); +typedef ucs4_t (*iso2022_decode_func)(const unsigned char *data); +typedef DBCHAR (*iso2022_encode_func)(const ucs4_t *data, Py_ssize_t *length); + +struct iso2022_designation { + unsigned char mark; + unsigned char plane; + unsigned char width; + iso2022_init_func initializer; + iso2022_decode_func decoder; + iso2022_encode_func encoder; +}; + +struct iso2022_config { + int flags; + const struct iso2022_designation *designations; /* non-ascii desigs */ +}; + +/*-*- iso-2022 codec implementation -*-*/ + +CODEC_INIT(iso2022) +{ + const struct iso2022_designation *desig = CONFIG_DESIGNATIONS; + for (desig = CONFIG_DESIGNATIONS; desig->mark; desig++) + if (desig->initializer != NULL && desig->initializer() != 0) + return -1; + return 0; +} + +ENCODER_INIT(iso2022) +{ + STATE_CLEARFLAGS() + STATE_SETG0(CHARSET_ASCII) + STATE_SETG1(CHARSET_ASCII) + return 0; +} + +ENCODER_RESET(iso2022) +{ + if (STATE_GETFLAG(F_SHIFTED)) { + WRITE1(SI) + NEXT_OUT(1) + STATE_CLEARFLAG(F_SHIFTED) + } + if (STATE_G0 != CHARSET_ASCII) { + WRITE3(ESC, '(', 'B') + NEXT_OUT(3) + STATE_SETG0(CHARSET_ASCII) + } + return 0; +} + +ENCODER(iso2022) +{ + while (inleft > 0) { + const struct iso2022_designation *dsg; + DBCHAR encoded; + ucs4_t c = **inbuf; + Py_ssize_t insize; + + if (c < 0x80) { + if (STATE_G0 != CHARSET_ASCII) { + WRITE3(ESC, '(', 'B') + STATE_SETG0(CHARSET_ASCII) + NEXT_OUT(3) + } + if (STATE_GETFLAG(F_SHIFTED)) { + WRITE1(SI) + STATE_CLEARFLAG(F_SHIFTED) + NEXT_OUT(1) + } + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + + DECODE_SURROGATE(c) + insize = GET_INSIZE(c); + + encoded = MAP_UNMAPPABLE; + for (dsg = CONFIG_DESIGNATIONS; dsg->mark; dsg++) { + Py_ssize_t length = 1; + encoded = dsg->encoder(&c, &length); + if (encoded == MAP_MULTIPLE_AVAIL) { + /* this implementation won't work for pair + * of non-bmp characters. */ + if (inleft < 2) { + if (!(flags & MBENC_FLUSH)) + return MBERR_TOOFEW; + length = -1; + } + else + length = 2; +#if Py_UNICODE_SIZE == 2 + if (length == 2) { + ucs4_t u4in[2]; + u4in[0] = (ucs4_t)IN1; + u4in[1] = (ucs4_t)IN2; + encoded = dsg->encoder(u4in, &length); + } else + encoded = dsg->encoder(&c, &length); +#else + encoded = dsg->encoder(&c, &length); +#endif + if (encoded != MAP_UNMAPPABLE) { + insize = length; + break; + } + } + else if (encoded != MAP_UNMAPPABLE) + break; + } + + if (!dsg->mark) + return 1; + assert(dsg->width == 1 || dsg->width == 2); + + switch (dsg->plane) { + case 0: /* G0 */ + if (STATE_GETFLAG(F_SHIFTED)) { + WRITE1(SI) + STATE_CLEARFLAG(F_SHIFTED) + NEXT_OUT(1) + } + if (STATE_G0 != dsg->mark) { + if (dsg->width == 1) { + WRITE3(ESC, '(', ESCMARK(dsg->mark)) + STATE_SETG0(dsg->mark) + NEXT_OUT(3) + } + else if (dsg->mark == CHARSET_JISX0208) { + WRITE3(ESC, '$', ESCMARK(dsg->mark)) + STATE_SETG0(dsg->mark) + NEXT_OUT(3) + } + else { + WRITE4(ESC, '$', '(', + ESCMARK(dsg->mark)) + STATE_SETG0(dsg->mark) + NEXT_OUT(4) + } + } + break; + case 1: /* G1 */ + if (STATE_G1 != dsg->mark) { + if (dsg->width == 1) { + WRITE3(ESC, ')', ESCMARK(dsg->mark)) + STATE_SETG1(dsg->mark) + NEXT_OUT(3) + } + else { + WRITE4(ESC, '$', ')', + ESCMARK(dsg->mark)) + STATE_SETG1(dsg->mark) + NEXT_OUT(4) + } + } + if (!STATE_GETFLAG(F_SHIFTED)) { + WRITE1(SO) + STATE_SETFLAG(F_SHIFTED) + NEXT_OUT(1) + } + break; + default: /* G2 and G3 is not supported: no encoding in + * CJKCodecs are using them yet */ + return MBERR_INTERNAL; + } + + if (dsg->width == 1) { + WRITE1((unsigned char)encoded) + NEXT_OUT(1) + } + else { + WRITE2(encoded >> 8, encoded & 0xff) + NEXT_OUT(2) + } + NEXT_IN(insize) + } + + return 0; +} + +DECODER_INIT(iso2022) +{ + STATE_CLEARFLAGS() + STATE_SETG0(CHARSET_ASCII) + STATE_SETG1(CHARSET_ASCII) + STATE_SETG2(CHARSET_ASCII) + return 0; +} + +DECODER_RESET(iso2022) +{ + STATE_SETG0(CHARSET_ASCII) + STATE_CLEARFLAG(F_SHIFTED) + return 0; +} + +static Py_ssize_t +iso2022processesc(const void *config, MultibyteCodec_State *state, + const unsigned char **inbuf, Py_ssize_t *inleft) +{ + unsigned char charset, designation; + Py_ssize_t i, esclen; + + for (i = 1;i < MAX_ESCSEQLEN;i++) { + if (i >= *inleft) + return MBERR_TOOFEW; + if (IS_ESCEND((*inbuf)[i])) { + esclen = i + 1; + break; + } + else if (CONFIG_ISSET(USE_JISX0208_EXT) && i+1 < *inleft && + (*inbuf)[i] == '&' && (*inbuf)[i+1] == '@') + i += 2; + } + + if (i >= MAX_ESCSEQLEN) + return 1; /* unterminated escape sequence */ + + switch (esclen) { + case 3: + if (IN2 == '$') { + charset = IN3 | CHARSET_DBCS; + designation = 0; + } + else { + charset = IN3; + if (IN2 == '(') designation = 0; + else if (IN2 == ')') designation = 1; + else if (CONFIG_ISSET(USE_G2) && IN2 == '.') + designation = 2; + else return 3; + } + break; + case 4: + if (IN2 != '$') + return 4; + + charset = IN4 | CHARSET_DBCS; + if (IN3 == '(') designation = 0; + else if (IN3 == ')') designation = 1; + else return 4; + break; + case 6: /* designation with prefix */ + if (CONFIG_ISSET(USE_JISX0208_EXT) && + (*inbuf)[3] == ESC && (*inbuf)[4] == '$' && + (*inbuf)[5] == 'B') { + charset = 'B' | CHARSET_DBCS; + designation = 0; + } + else + return 6; + break; + default: + return esclen; + } + + /* raise error when the charset is not designated for this encoding */ + if (charset != CHARSET_ASCII) { + const struct iso2022_designation *dsg; + + for (dsg = CONFIG_DESIGNATIONS; dsg->mark; dsg++) + if (dsg->mark == charset) + break; + if (!dsg->mark) + return esclen; + } + + STATE_SETG(designation, charset) + *inleft -= esclen; + (*inbuf) += esclen; + return 0; +} + +#define ISO8859_7_DECODE(c, assi) \ + if ((c) < 0xa0) (assi) = (c); \ + else if ((c) < 0xc0 && (0x288f3bc9L & (1L << ((c)-0xa0)))) \ + (assi) = (c); \ + else if ((c) >= 0xb4 && (c) <= 0xfe && ((c) >= 0xd4 || \ + (0xbffffd77L & (1L << ((c)-0xb4))))) \ + (assi) = 0x02d0 + (c); \ + else if ((c) == 0xa1) (assi) = 0x2018; \ + else if ((c) == 0xa2) (assi) = 0x2019; \ + else if ((c) == 0xaf) (assi) = 0x2015; + +static Py_ssize_t +iso2022processg2(const void *config, MultibyteCodec_State *state, + const unsigned char **inbuf, Py_ssize_t *inleft, + Py_UNICODE **outbuf, Py_ssize_t *outleft) +{ + /* not written to use encoder, decoder functions because only few + * encodings use G2 designations in CJKCodecs */ + if (STATE_G2 == CHARSET_ISO8859_1) { + if (IN3 < 0x80) + OUT1(IN3 + 0x80) + else + return 3; + } + else if (STATE_G2 == CHARSET_ISO8859_7) { + ISO8859_7_DECODE(IN3 ^ 0x80, **outbuf) + else return 3; + } + else if (STATE_G2 == CHARSET_ASCII) { + if (IN3 & 0x80) return 3; + else **outbuf = IN3; + } + else + return MBERR_INTERNAL; + + (*inbuf) += 3; + *inleft -= 3; + (*outbuf) += 1; + *outleft -= 1; + return 0; +} + +DECODER(iso2022) +{ + const struct iso2022_designation *dsgcache = NULL; + + while (inleft > 0) { + unsigned char c = IN1; + Py_ssize_t err; + + if (STATE_GETFLAG(F_ESCTHROUGHOUT)) { + /* ESC throughout mode: + * for non-iso2022 escape sequences */ + WRITE1(c) /* assume as ISO-8859-1 */ + NEXT(1, 1) + if (IS_ESCEND(c)) { + STATE_CLEARFLAG(F_ESCTHROUGHOUT) + } + continue; + } + + switch (c) { + case ESC: + REQUIRE_INBUF(2) + if (IS_ISO2022ESC(IN2)) { + err = iso2022processesc(config, state, + inbuf, &inleft); + if (err != 0) + return err; + } + else if (CONFIG_ISSET(USE_G2) && IN2 == 'N') {/* SS2 */ + REQUIRE_INBUF(3) + err = iso2022processg2(config, state, + inbuf, &inleft, outbuf, &outleft); + if (err != 0) + return err; + } + else { + WRITE1(ESC) + STATE_SETFLAG(F_ESCTHROUGHOUT) + NEXT(1, 1) + } + break; + case SI: + if (CONFIG_ISSET(NO_SHIFT)) + goto bypass; + STATE_CLEARFLAG(F_SHIFTED) + NEXT_IN(1) + break; + case SO: + if (CONFIG_ISSET(NO_SHIFT)) + goto bypass; + STATE_SETFLAG(F_SHIFTED) + NEXT_IN(1) + break; + case LF: + STATE_CLEARFLAG(F_SHIFTED) + WRITE1(LF) + NEXT(1, 1) + break; + default: + if (c < 0x20) /* C0 */ + goto bypass; + else if (c >= 0x80) + return 1; + else { + const struct iso2022_designation *dsg; + unsigned char charset; + ucs4_t decoded; + + if (STATE_GETFLAG(F_SHIFTED)) + charset = STATE_G1; + else + charset = STATE_G0; + + if (charset == CHARSET_ASCII) { +bypass: WRITE1(c) + NEXT(1, 1) + break; + } + + if (dsgcache != NULL && + dsgcache->mark == charset) + dsg = dsgcache; + else { + for (dsg = CONFIG_DESIGNATIONS; + dsg->mark != charset +#ifdef Py_DEBUG + && dsg->mark != '\0' +#endif + ;dsg++) + /* noop */; + assert(dsg->mark != '\0'); + dsgcache = dsg; + } + + REQUIRE_INBUF(dsg->width) + decoded = dsg->decoder(*inbuf); + if (decoded == MAP_UNMAPPABLE) + return dsg->width; + + if (decoded < 0x10000) { + WRITE1(decoded) + NEXT_OUT(1) + } + else if (decoded < 0x30000) { + WRITEUCS4(decoded) + } + else { /* JIS X 0213 pairs */ + WRITE2(decoded >> 16, decoded & 0xffff) + NEXT_OUT(2) + } + NEXT_IN(dsg->width) + } + break; + } + } + return 0; +} + +/*-*- mapping table holders -*-*/ + +USING_IMPORTED_MAP(cp949) +USING_IMPORTED_MAP(ksx1001) +USING_IMPORTED_MAP(jisxcommon) +USING_IMPORTED_MAP(jisx0208) +USING_IMPORTED_MAP(jisx0212) +USING_IMPORTED_MAP(jisx0213_bmp) +USING_IMPORTED_MAP(jisx0213_1_bmp) +USING_IMPORTED_MAP(jisx0213_2_bmp) +USING_IMPORTED_MAP(jisx0213_emp) +USING_IMPORTED_MAP(jisx0213_1_emp) +USING_IMPORTED_MAP(jisx0213_2_emp) +USING_IMPORTED_MAP(jisx0213_pair) +USING_IMPORTED_MAP(gbcommon) +USING_IMPORTED_MAP(gb2312) + +#define ENCMAP(enc) static const encode_map *enc##_encmap = NULL; +#define DECMAP(enc) static const decode_map *enc##_decmap = NULL; + +/* kr */ +ENCMAP(cp949) +DECMAP(ksx1001) + +/* jp */ +ENCMAP(jisxcommon) +DECMAP(jisx0208) +DECMAP(jisx0212) +ENCMAP(jisx0213_bmp) +DECMAP(jisx0213_1_bmp) +DECMAP(jisx0213_2_bmp) +ENCMAP(jisx0213_emp) +DECMAP(jisx0213_1_emp) +DECMAP(jisx0213_2_emp) + +/* cn */ +ENCMAP(gbcommon) +DECMAP(gb2312) + +/* tw */ + +/*-*- mapping access functions -*-*/ + +static int +ksx1001_init(void) +{ + IMPORT_MAP(kr, cp949, &cp949_encmap, NULL); + IMPORT_MAP(kr, ksx1001, NULL, &ksx1001_decmap); + return 0; +} + +static ucs4_t +ksx1001_decoder(const unsigned char *data) +{ + ucs4_t u; + TRYMAP_DEC(ksx1001, u, data[0], data[1]) + return u; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +ksx1001_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + assert(*length == 1); + if (*data < 0x10000) { + TRYMAP_ENC(cp949, coded, *data) + if (!(coded & 0x8000)) + return coded; + } + return MAP_UNMAPPABLE; +} + +static int +jisx0208_init(void) +{ + IMPORT_MAP(jp, jisxcommon, &jisxcommon_encmap, NULL); + IMPORT_MAP(jp, jisx0208, NULL, &jisx0208_decmap); + return 0; +} + +static ucs4_t +jisx0208_decoder(const unsigned char *data) +{ + ucs4_t u; + if (data[0] == 0x21 && data[1] == 0x40) /* F/W REVERSE SOLIDUS */ + return 0xff3c; + else TRYMAP_DEC(jisx0208, u, data[0], data[1]) + return u; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +jisx0208_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + assert(*length == 1); + if (*data < 0x10000) { + if (*data == 0xff3c) /* F/W REVERSE SOLIDUS */ + return 0x2140; + else TRYMAP_ENC(jisxcommon, coded, *data) { + if (!(coded & 0x8000)) + return coded; + } + } + return MAP_UNMAPPABLE; +} + +static int +jisx0212_init(void) +{ + IMPORT_MAP(jp, jisxcommon, &jisxcommon_encmap, NULL); + IMPORT_MAP(jp, jisx0212, NULL, &jisx0212_decmap); + return 0; +} + +static ucs4_t +jisx0212_decoder(const unsigned char *data) +{ + ucs4_t u; + TRYMAP_DEC(jisx0212, u, data[0], data[1]) + return u; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +jisx0212_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + assert(*length == 1); + if (*data < 0x10000) { + TRYMAP_ENC(jisxcommon, coded, *data) { + if (coded & 0x8000) + return coded & 0x7fff; + } + } + return MAP_UNMAPPABLE; +} + +static int +jisx0213_init(void) +{ + jisx0208_init(); + IMPORT_MAP(jp, jisx0213_bmp, &jisx0213_bmp_encmap, NULL); + IMPORT_MAP(jp, jisx0213_1_bmp, NULL, &jisx0213_1_bmp_decmap); + IMPORT_MAP(jp, jisx0213_2_bmp, NULL, &jisx0213_2_bmp_decmap); + IMPORT_MAP(jp, jisx0213_emp, &jisx0213_emp_encmap, NULL); + IMPORT_MAP(jp, jisx0213_1_emp, NULL, &jisx0213_1_emp_decmap); + IMPORT_MAP(jp, jisx0213_2_emp, NULL, &jisx0213_2_emp_decmap); + IMPORT_MAP(jp, jisx0213_pair, &jisx0213_pair_encmap, &jisx0213_pair_decmap); + return 0; +} + +#define config ((void *)2000) +static ucs4_t +jisx0213_2000_1_decoder(const unsigned char *data) +{ + ucs4_t u; + EMULATE_JISX0213_2000_DECODE_PLANE1(u, data[0], data[1]) + else if (data[0] == 0x21 && data[1] == 0x40) /* F/W REVERSE SOLIDUS */ + return 0xff3c; + else TRYMAP_DEC(jisx0208, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_1_bmp, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_1_emp, u, data[0], data[1]) + u |= 0x20000; + else TRYMAP_DEC(jisx0213_pair, u, data[0], data[1]); + else + return MAP_UNMAPPABLE; + return u; +} + +static ucs4_t +jisx0213_2000_2_decoder(const unsigned char *data) +{ + ucs4_t u; + EMULATE_JISX0213_2000_DECODE_PLANE2(u, data[0], data[1]) + TRYMAP_DEC(jisx0213_2_bmp, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_2_emp, u, data[0], data[1]) + u |= 0x20000; + else + return MAP_UNMAPPABLE; + return u; +} +#undef config + +static ucs4_t +jisx0213_2004_1_decoder(const unsigned char *data) +{ + ucs4_t u; + if (data[0] == 0x21 && data[1] == 0x40) /* F/W REVERSE SOLIDUS */ + return 0xff3c; + else TRYMAP_DEC(jisx0208, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_1_bmp, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_1_emp, u, data[0], data[1]) + u |= 0x20000; + else TRYMAP_DEC(jisx0213_pair, u, data[0], data[1]); + else + return MAP_UNMAPPABLE; + return u; +} + +static ucs4_t +jisx0213_2004_2_decoder(const unsigned char *data) +{ + ucs4_t u; + TRYMAP_DEC(jisx0213_2_bmp, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_2_emp, u, data[0], data[1]) + u |= 0x20000; + else + return MAP_UNMAPPABLE; + return u; +} + +static DBCHAR +jisx0213_encoder(const ucs4_t *data, Py_ssize_t *length, void *config) +{ + DBCHAR coded; + + switch (*length) { + case 1: /* first character */ + if (*data >= 0x10000) { + if ((*data) >> 16 == 0x20000 >> 16) { + EMULATE_JISX0213_2000_ENCODE_EMP(coded, *data) + else TRYMAP_ENC(jisx0213_emp, coded, + (*data) & 0xffff) + return coded; + } + return MAP_UNMAPPABLE; + } + + EMULATE_JISX0213_2000_ENCODE_BMP(coded, *data) + else TRYMAP_ENC(jisx0213_bmp, coded, *data) { + if (coded == MULTIC) + return MAP_MULTIPLE_AVAIL; + } + else TRYMAP_ENC(jisxcommon, coded, *data) { + if (coded & 0x8000) + return MAP_UNMAPPABLE; + } + else + return MAP_UNMAPPABLE; + return coded; + case 2: /* second character of unicode pair */ + coded = find_pairencmap((ucs2_t)data[0], (ucs2_t)data[1], + jisx0213_pair_encmap, JISX0213_ENCPAIRS); + if (coded == DBCINV) { + *length = 1; + coded = find_pairencmap((ucs2_t)data[0], 0, + jisx0213_pair_encmap, JISX0213_ENCPAIRS); + if (coded == DBCINV) + return MAP_UNMAPPABLE; + } + else + return coded; + case -1: /* flush unterminated */ + *length = 1; + coded = find_pairencmap((ucs2_t)data[0], 0, + jisx0213_pair_encmap, JISX0213_ENCPAIRS); + if (coded == DBCINV) + return MAP_UNMAPPABLE; + else + return coded; + default: + return MAP_UNMAPPABLE; + } +} + +static DBCHAR +jisx0213_2000_1_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded = jisx0213_encoder(data, length, (void *)2000); + if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL) + return coded; + else if (coded & 0x8000) + return MAP_UNMAPPABLE; + else + return coded; +} + +static DBCHAR +jisx0213_2000_1_encoder_paironly(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + Py_ssize_t ilength = *length; + + coded = jisx0213_encoder(data, length, (void *)2000); + switch (ilength) { + case 1: + if (coded == MAP_MULTIPLE_AVAIL) + return MAP_MULTIPLE_AVAIL; + else + return MAP_UNMAPPABLE; + case 2: + if (*length != 2) + return MAP_UNMAPPABLE; + else + return coded; + default: + return MAP_UNMAPPABLE; + } +} + +static DBCHAR +jisx0213_2000_2_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded = jisx0213_encoder(data, length, (void *)2000); + if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL) + return coded; + else if (coded & 0x8000) + return coded & 0x7fff; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +jisx0213_2004_1_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded = jisx0213_encoder(data, length, NULL); + if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL) + return coded; + else if (coded & 0x8000) + return MAP_UNMAPPABLE; + else + return coded; +} + +static DBCHAR +jisx0213_2004_1_encoder_paironly(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + Py_ssize_t ilength = *length; + + coded = jisx0213_encoder(data, length, NULL); + switch (ilength) { + case 1: + if (coded == MAP_MULTIPLE_AVAIL) + return MAP_MULTIPLE_AVAIL; + else + return MAP_UNMAPPABLE; + case 2: + if (*length != 2) + return MAP_UNMAPPABLE; + else + return coded; + default: + return MAP_UNMAPPABLE; + } +} + +static DBCHAR +jisx0213_2004_2_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded = jisx0213_encoder(data, length, NULL); + if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL) + return coded; + else if (coded & 0x8000) + return coded & 0x7fff; + else + return MAP_UNMAPPABLE; +} + +static ucs4_t +jisx0201_r_decoder(const unsigned char *data) +{ + ucs4_t u; + JISX0201_R_DECODE(*data, u) + else return MAP_UNMAPPABLE; + return u; +} + +static DBCHAR +jisx0201_r_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + JISX0201_R_ENCODE(*data, coded) + else return MAP_UNMAPPABLE; + return coded; +} + +static ucs4_t +jisx0201_k_decoder(const unsigned char *data) +{ + ucs4_t u; + JISX0201_K_DECODE(*data ^ 0x80, u) + else return MAP_UNMAPPABLE; + return u; +} + +static DBCHAR +jisx0201_k_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + JISX0201_K_ENCODE(*data, coded) + else return MAP_UNMAPPABLE; + return coded - 0x80; +} + +static int +gb2312_init(void) +{ + IMPORT_MAP(cn, gbcommon, &gbcommon_encmap, NULL); + IMPORT_MAP(cn, gb2312, NULL, &gb2312_decmap); + return 0; +} + +static ucs4_t +gb2312_decoder(const unsigned char *data) +{ + ucs4_t u; + TRYMAP_DEC(gb2312, u, data[0], data[1]) + return u; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +gb2312_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + assert(*length == 1); + if (*data < 0x10000) { + TRYMAP_ENC(gbcommon, coded, *data) { + if (!(coded & 0x8000)) + return coded; + } + } + return MAP_UNMAPPABLE; +} + + +static ucs4_t +dummy_decoder(const unsigned char *data) +{ + return MAP_UNMAPPABLE; +} + +static DBCHAR +dummy_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + return MAP_UNMAPPABLE; +} + +/*-*- registry tables -*-*/ + +#define REGISTRY_KSX1001_G0 { CHARSET_KSX1001, 0, 2, \ + ksx1001_init, \ + ksx1001_decoder, ksx1001_encoder } +#define REGISTRY_KSX1001_G1 { CHARSET_KSX1001, 1, 2, \ + ksx1001_init, \ + ksx1001_decoder, ksx1001_encoder } +#define REGISTRY_JISX0201_R { CHARSET_JISX0201_R, 0, 1, \ + NULL, \ + jisx0201_r_decoder, jisx0201_r_encoder } +#define REGISTRY_JISX0201_K { CHARSET_JISX0201_K, 0, 1, \ + NULL, \ + jisx0201_k_decoder, jisx0201_k_encoder } +#define REGISTRY_JISX0208 { CHARSET_JISX0208, 0, 2, \ + jisx0208_init, \ + jisx0208_decoder, jisx0208_encoder } +#define REGISTRY_JISX0208_O { CHARSET_JISX0208_O, 0, 2, \ + jisx0208_init, \ + jisx0208_decoder, jisx0208_encoder } +#define REGISTRY_JISX0212 { CHARSET_JISX0212, 0, 2, \ + jisx0212_init, \ + jisx0212_decoder, jisx0212_encoder } +#define REGISTRY_JISX0213_2000_1 { CHARSET_JISX0213_2000_1, 0, 2, \ + jisx0213_init, \ + jisx0213_2000_1_decoder, \ + jisx0213_2000_1_encoder } +#define REGISTRY_JISX0213_2000_1_PAIRONLY { CHARSET_JISX0213_2000_1, 0, 2, \ + jisx0213_init, \ + jisx0213_2000_1_decoder, \ + jisx0213_2000_1_encoder_paironly } +#define REGISTRY_JISX0213_2000_2 { CHARSET_JISX0213_2, 0, 2, \ + jisx0213_init, \ + jisx0213_2000_2_decoder, \ + jisx0213_2000_2_encoder } +#define REGISTRY_JISX0213_2004_1 { CHARSET_JISX0213_2004_1, 0, 2, \ + jisx0213_init, \ + jisx0213_2004_1_decoder, \ + jisx0213_2004_1_encoder } +#define REGISTRY_JISX0213_2004_1_PAIRONLY { CHARSET_JISX0213_2004_1, 0, 2, \ + jisx0213_init, \ + jisx0213_2004_1_decoder, \ + jisx0213_2004_1_encoder_paironly } +#define REGISTRY_JISX0213_2004_2 { CHARSET_JISX0213_2, 0, 2, \ + jisx0213_init, \ + jisx0213_2004_2_decoder, \ + jisx0213_2004_2_encoder } +#define REGISTRY_GB2312 { CHARSET_GB2312, 0, 2, \ + gb2312_init, \ + gb2312_decoder, gb2312_encoder } +#define REGISTRY_CNS11643_1 { CHARSET_CNS11643_1, 1, 2, \ + cns11643_init, \ + cns11643_1_decoder, cns11643_1_encoder } +#define REGISTRY_CNS11643_2 { CHARSET_CNS11643_2, 2, 2, \ + cns11643_init, \ + cns11643_2_decoder, cns11643_2_encoder } +#define REGISTRY_ISO8859_1 { CHARSET_ISO8859_1, 2, 1, \ + NULL, dummy_decoder, dummy_encoder } +#define REGISTRY_ISO8859_7 { CHARSET_ISO8859_7, 2, 1, \ + NULL, dummy_decoder, dummy_encoder } +#define REGISTRY_SENTINEL { 0, } +#define CONFIGDEF(var, attrs) \ + static const struct iso2022_config iso2022_##var##_config = { \ + attrs, iso2022_##var##_designations \ + }; + +static const struct iso2022_designation iso2022_kr_designations[] = { + REGISTRY_KSX1001_G1, REGISTRY_SENTINEL +}; +CONFIGDEF(kr, 0) + +static const struct iso2022_designation iso2022_jp_designations[] = { + REGISTRY_JISX0208, REGISTRY_JISX0201_R, REGISTRY_JISX0208_O, + REGISTRY_SENTINEL +}; +CONFIGDEF(jp, NO_SHIFT | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_1_designations[] = { + REGISTRY_JISX0208, REGISTRY_JISX0212, REGISTRY_JISX0201_R, + REGISTRY_JISX0208_O, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_1, NO_SHIFT | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_2_designations[] = { + REGISTRY_JISX0208, REGISTRY_JISX0212, REGISTRY_KSX1001_G0, + REGISTRY_GB2312, REGISTRY_JISX0201_R, REGISTRY_JISX0208_O, + REGISTRY_ISO8859_1, REGISTRY_ISO8859_7, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_2, NO_SHIFT | USE_G2 | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_2004_designations[] = { + REGISTRY_JISX0213_2004_1_PAIRONLY, REGISTRY_JISX0208, + REGISTRY_JISX0213_2004_1, REGISTRY_JISX0213_2004_2, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_2004, NO_SHIFT | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_3_designations[] = { + REGISTRY_JISX0213_2000_1_PAIRONLY, REGISTRY_JISX0208, + REGISTRY_JISX0213_2000_1, REGISTRY_JISX0213_2000_2, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_3, NO_SHIFT | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_ext_designations[] = { + REGISTRY_JISX0208, REGISTRY_JISX0212, REGISTRY_JISX0201_R, + REGISTRY_JISX0201_K, REGISTRY_JISX0208_O, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_ext, NO_SHIFT | USE_JISX0208_EXT) + + +BEGIN_MAPPINGS_LIST + /* no mapping table here */ +END_MAPPINGS_LIST + +#define ISO2022_CODEC(variation) \ + CODEC_STATEFUL_CONFIG(iso2022, \ + variation, \ + &iso2022_##variation##_config) + +BEGIN_CODECS_LIST + ISO2022_CODEC(kr) + ISO2022_CODEC(jp) + ISO2022_CODEC(jp_1) + ISO2022_CODEC(jp_2) + ISO2022_CODEC(jp_2004) + ISO2022_CODEC(jp_3) + ISO2022_CODEC(jp_ext) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(iso2022) diff --git a/pypy/translator/c/src/cjkcodecs/_codecs_jp.c b/pypy/translator/c/src/cjkcodecs/_codecs_jp.c new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/_codecs_jp.c @@ -0,0 +1,731 @@ +/* + * _codecs_jp.c: Codecs collection for Japanese encodings + * + * Written by Hye-Shik Chang + */ + +#define USING_BINARY_PAIR_SEARCH +#define EMPBASE 0x20000 + +#include "src/cjkcodecs/cjkcodecs.h" +#include "src/cjkcodecs/mappings_jp.h" +#include "src/cjkcodecs/mappings_jisx0213_pair.h" +#include "src/cjkcodecs/alg_jisx0201.h" +#include "src/cjkcodecs/emu_jisx0213_2000.h" + +/* + * CP932 codec + */ + +ENCODER(cp932) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + unsigned char c1, c2; + + if (c <= 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + else if (c >= 0xff61 && c <= 0xff9f) { + WRITE1(c - 0xfec0) + NEXT(1, 1) + continue; + } + else if (c >= 0xf8f0 && c <= 0xf8f3) { + /* Windows compatibility */ + REQUIRE_OUTBUF(1) + if (c == 0xf8f0) + OUT1(0xa0) + else + OUT1(c - 0xfef1 + 0xfd) + NEXT(1, 1) + continue; + } + + UCS4INVALID(c) + REQUIRE_OUTBUF(2) + + TRYMAP_ENC(cp932ext, code, c) { + OUT1(code >> 8) + OUT2(code & 0xff) + } + else TRYMAP_ENC(jisxcommon, code, c) { + if (code & 0x8000) /* MSB set: JIS X 0212 */ + return 1; + + /* JIS X 0208 */ + c1 = code >> 8; + c2 = code & 0xff; + c2 = (((c1 - 0x21) & 1) ? 0x5e : 0) + (c2 - 0x21); + c1 = (c1 - 0x21) >> 1; + OUT1(c1 < 0x1f ? c1 + 0x81 : c1 + 0xc1) + OUT2(c2 < 0x3f ? c2 + 0x40 : c2 + 0x41) + } + else if (c >= 0xe000 && c < 0xe758) { + /* User-defined area */ + c1 = (Py_UNICODE)(c - 0xe000) / 188; + c2 = (Py_UNICODE)(c - 0xe000) % 188; + OUT1(c1 + 0xf0) + OUT2(c2 < 0x3f ? c2 + 0x40 : c2 + 0x41) + } + else + return 1; + + NEXT(1, 2) + } + + return 0; +} + +DECODER(cp932) +{ + while (inleft > 0) { + unsigned char c = IN1, c2; + + REQUIRE_OUTBUF(1) + if (c <= 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + else if (c >= 0xa0 && c <= 0xdf) { + if (c == 0xa0) + OUT1(0xf8f0) /* half-width katakana */ + else + OUT1(0xfec0 + c) + NEXT(1, 1) + continue; + } + else if (c >= 0xfd/* && c <= 0xff*/) { + /* Windows compatibility */ + OUT1(0xf8f1 - 0xfd + c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + c2 = IN2; + + TRYMAP_DEC(cp932ext, **outbuf, c, c2); + else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)){ + if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) + return 2; + + c = (c < 0xe0 ? c - 0x81 : c - 0xc1); + c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); + c = (2 * c + (c2 < 0x5e ? 0 : 1) + 0x21); + c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21; + + TRYMAP_DEC(jisx0208, **outbuf, c, c2); + else return 2; + } + else if (c >= 0xf0 && c <= 0xf9) { + if ((c2 >= 0x40 && c2 <= 0x7e) || + (c2 >= 0x80 && c2 <= 0xfc)) + OUT1(0xe000 + 188 * (c - 0xf0) + + (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41)) + else + return 2; + } + else + return 2; + + NEXT(2, 1) + } + + return 0; +} + + +/* + * EUC-JIS-2004 codec + */ + +ENCODER(euc_jis_2004) +{ + while (inleft > 0) { + ucs4_t c = IN1; + DBCHAR code; + Py_ssize_t insize; + + if (c < 0x80) { + WRITE1(c) + NEXT(1, 1) + continue; + } + + DECODE_SURROGATE(c) + insize = GET_INSIZE(c); + + if (c <= 0xFFFF) { + EMULATE_JISX0213_2000_ENCODE_BMP(code, c) + else TRYMAP_ENC(jisx0213_bmp, code, c) { + if (code == MULTIC) { + if (inleft < 2) { + if (flags & MBENC_FLUSH) { + code = find_pairencmap( + (ucs2_t)c, 0, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) + return 1; + } + else + return MBERR_TOOFEW; + } + else { + code = find_pairencmap( + (ucs2_t)c, (*inbuf)[1], + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) { + code = find_pairencmap( + (ucs2_t)c, 0, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) + return 1; + } else + insize = 2; + } + } + } + else TRYMAP_ENC(jisxcommon, code, c); + else if (c >= 0xff61 && c <= 0xff9f) { + /* JIS X 0201 half-width katakana */ + WRITE2(0x8e, c - 0xfec0) + NEXT(1, 2) + continue; + } + else if (c == 0xff3c) + /* F/W REVERSE SOLIDUS (see NOTES) */ + code = 0x2140; + else if (c == 0xff5e) + /* F/W TILDE (see NOTES) */ + code = 0x2232; + else + return 1; + } + else if (c >> 16 == EMPBASE >> 16) { + EMULATE_JISX0213_2000_ENCODE_EMP(code, c) + else TRYMAP_ENC(jisx0213_emp, code, c & 0xffff); + else return insize; + } + else + return insize; + + if (code & 0x8000) { + /* Codeset 2 */ + WRITE3(0x8f, code >> 8, (code & 0xFF) | 0x80) + NEXT(insize, 3) + } else { + /* Codeset 1 */ + WRITE2((code >> 8) | 0x80, (code & 0xFF) | 0x80) + NEXT(insize, 2) + } + } + + return 0; +} + +DECODER(euc_jis_2004) +{ + while (inleft > 0) { + unsigned char c = IN1; + ucs4_t code; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + if (c == 0x8e) { + /* JIS X 0201 half-width katakana */ + unsigned char c2; + + REQUIRE_INBUF(2) + c2 = IN2; + if (c2 >= 0xa1 && c2 <= 0xdf) { + OUT1(0xfec0 + c2) + NEXT(2, 1) + } + else + return 2; + } + else if (c == 0x8f) { + unsigned char c2, c3; + + REQUIRE_INBUF(3) + c2 = IN2 ^ 0x80; + c3 = IN3 ^ 0x80; + + /* JIS X 0213 Plane 2 or JIS X 0212 (see NOTES) */ + EMULATE_JISX0213_2000_DECODE_PLANE2(**outbuf, c2, c3) + else TRYMAP_DEC(jisx0213_2_bmp, **outbuf, c2, c3) ; + else TRYMAP_DEC(jisx0213_2_emp, code, c2, c3) { + WRITEUCS4(EMPBASE | code) + NEXT_IN(3) + continue; + } + else TRYMAP_DEC(jisx0212, **outbuf, c2, c3) ; + else return 3; + NEXT(3, 1) + } + else { + unsigned char c2; + + REQUIRE_INBUF(2) + c ^= 0x80; + c2 = IN2 ^ 0x80; + + /* JIS X 0213 Plane 1 */ + EMULATE_JISX0213_2000_DECODE_PLANE1(**outbuf, c, c2) + else if (c == 0x21 && c2 == 0x40) **outbuf = 0xff3c; + else if (c == 0x22 && c2 == 0x32) **outbuf = 0xff5e; + else TRYMAP_DEC(jisx0208, **outbuf, c, c2); + else TRYMAP_DEC(jisx0213_1_bmp, **outbuf, c, c2); + else TRYMAP_DEC(jisx0213_1_emp, code, c, c2) { + WRITEUCS4(EMPBASE | code) + NEXT_IN(2) + continue; + } + else TRYMAP_DEC(jisx0213_pair, code, c, c2) { + WRITE2(code >> 16, code & 0xffff) + NEXT(2, 2) + continue; + } + else return 2; + NEXT(2, 1) + } + } + + return 0; +} + + +/* + * EUC-JP codec + */ + +ENCODER(euc_jp) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + + UCS4INVALID(c) + + TRYMAP_ENC(jisxcommon, code, c); + else if (c >= 0xff61 && c <= 0xff9f) { + /* JIS X 0201 half-width katakana */ + WRITE2(0x8e, c - 0xfec0) + NEXT(1, 2) + continue; + } +#ifndef STRICT_BUILD + else if (c == 0xff3c) /* FULL-WIDTH REVERSE SOLIDUS */ + code = 0x2140; + else if (c == 0xa5) { /* YEN SIGN */ + WRITE1(0x5c); + NEXT(1, 1) + continue; + } else if (c == 0x203e) { /* OVERLINE */ + WRITE1(0x7e); + NEXT(1, 1) + continue; + } +#endif + else + return 1; + + if (code & 0x8000) { + /* JIS X 0212 */ + WRITE3(0x8f, code >> 8, (code & 0xFF) | 0x80) + NEXT(1, 3) + } else { + /* JIS X 0208 */ + WRITE2((code >> 8) | 0x80, (code & 0xFF) | 0x80) + NEXT(1, 2) + } + } + + return 0; +} + +DECODER(euc_jp) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + if (c == 0x8e) { + /* JIS X 0201 half-width katakana */ + unsigned char c2; + + REQUIRE_INBUF(2) + c2 = IN2; + if (c2 >= 0xa1 && c2 <= 0xdf) { + OUT1(0xfec0 + c2) + NEXT(2, 1) + } + else + return 2; + } + else if (c == 0x8f) { + unsigned char c2, c3; + + REQUIRE_INBUF(3) + c2 = IN2; + c3 = IN3; + /* JIS X 0212 */ + TRYMAP_DEC(jisx0212, **outbuf, c2 ^ 0x80, c3 ^ 0x80) { + NEXT(3, 1) + } + else + return 3; + } + else { + unsigned char c2; + + REQUIRE_INBUF(2) + c2 = IN2; + /* JIS X 0208 */ +#ifndef STRICT_BUILD + if (c == 0xa1 && c2 == 0xc0) + /* FULL-WIDTH REVERSE SOLIDUS */ + **outbuf = 0xff3c; + else +#endif + TRYMAP_DEC(jisx0208, **outbuf, + c ^ 0x80, c2 ^ 0x80) ; + else return 2; + NEXT(2, 1) + } + } + + return 0; +} + + +/* + * SHIFT_JIS codec + */ + +ENCODER(shift_jis) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + unsigned char c1, c2; + +#ifdef STRICT_BUILD + JISX0201_R_ENCODE(c, code) +#else + if (c < 0x80) code = c; + else if (c == 0x00a5) code = 0x5c; /* YEN SIGN */ + else if (c == 0x203e) code = 0x7e; /* OVERLINE */ +#endif + else JISX0201_K_ENCODE(c, code) + else UCS4INVALID(c) + else code = NOCHAR; + + if (code < 0x80 || (code >= 0xa1 && code <= 0xdf)) { + REQUIRE_OUTBUF(1) + + OUT1((unsigned char)code) + NEXT(1, 1) + continue; + } + + REQUIRE_OUTBUF(2) + + if (code == NOCHAR) { + TRYMAP_ENC(jisxcommon, code, c); +#ifndef STRICT_BUILD + else if (c == 0xff3c) + code = 0x2140; /* FULL-WIDTH REVERSE SOLIDUS */ +#endif + else + return 1; + + if (code & 0x8000) /* MSB set: JIS X 0212 */ + return 1; + } + + c1 = code >> 8; + c2 = code & 0xff; + c2 = (((c1 - 0x21) & 1) ? 0x5e : 0) + (c2 - 0x21); + c1 = (c1 - 0x21) >> 1; + OUT1(c1 < 0x1f ? c1 + 0x81 : c1 + 0xc1) + OUT2(c2 < 0x3f ? c2 + 0x40 : c2 + 0x41) + NEXT(1, 2) + } + + return 0; +} + +DECODER(shift_jis) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + +#ifdef STRICT_BUILD + JISX0201_R_DECODE(c, **outbuf) +#else + if (c < 0x80) **outbuf = c; +#endif + else JISX0201_K_DECODE(c, **outbuf) + else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)){ + unsigned char c1, c2; + + REQUIRE_INBUF(2) + c2 = IN2; + if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) + return 2; + + c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1); + c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); + c1 = (2 * c1 + (c2 < 0x5e ? 0 : 1) + 0x21); + c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21; + +#ifndef STRICT_BUILD + if (c1 == 0x21 && c2 == 0x40) { + /* FULL-WIDTH REVERSE SOLIDUS */ + OUT1(0xff3c) + NEXT(2, 1) + continue; + } +#endif + TRYMAP_DEC(jisx0208, **outbuf, c1, c2) { + NEXT(2, 1) + continue; + } + else + return 2; + } + else + return 2; + + NEXT(1, 1) /* JIS X 0201 */ + } + + return 0; +} + + +/* + * SHIFT_JIS-2004 codec + */ + +ENCODER(shift_jis_2004) +{ + while (inleft > 0) { + ucs4_t c = IN1; + DBCHAR code = NOCHAR; + int c1, c2; + Py_ssize_t insize; + + JISX0201_ENCODE(c, code) + else DECODE_SURROGATE(c) + + if (code < 0x80 || (code >= 0xa1 && code <= 0xdf)) { + WRITE1((unsigned char)code) + NEXT(1, 1) + continue; + } + + REQUIRE_OUTBUF(2) + insize = GET_INSIZE(c); + + if (code == NOCHAR) { + if (c <= 0xffff) { + EMULATE_JISX0213_2000_ENCODE_BMP(code, c) + else TRYMAP_ENC(jisx0213_bmp, code, c) { + if (code == MULTIC) { + if (inleft < 2) { + if (flags & MBENC_FLUSH) { + code = find_pairencmap + ((ucs2_t)c, 0, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) + return 1; + } + else + return MBERR_TOOFEW; + } + else { + code = find_pairencmap( + (ucs2_t)c, IN2, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) { + code = find_pairencmap( + (ucs2_t)c, 0, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) + return 1; + } + else + insize = 2; + } + } + } + else TRYMAP_ENC(jisxcommon, code, c) { + /* abandon JIS X 0212 codes */ + if (code & 0x8000) + return 1; + } + else return 1; + } + else if (c >> 16 == EMPBASE >> 16) { + EMULATE_JISX0213_2000_ENCODE_EMP(code, c) + else TRYMAP_ENC(jisx0213_emp, code, c&0xffff); + else return insize; + } + else + return insize; + } + + c1 = code >> 8; + c2 = (code & 0xff) - 0x21; + + if (c1 & 0x80) { /* Plane 2 */ + if (c1 >= 0xee) c1 -= 0x87; + else if (c1 >= 0xac || c1 == 0xa8) c1 -= 0x49; + else c1 -= 0x43; + } + else /* Plane 1 */ + c1 -= 0x21; + + if (c1 & 1) c2 += 0x5e; + c1 >>= 1; + OUT1(c1 + (c1 < 0x1f ? 0x81 : 0xc1)) + OUT2(c2 + (c2 < 0x3f ? 0x40 : 0x41)) + + NEXT(insize, 2) + } + + return 0; +} + +DECODER(shift_jis_2004) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + JISX0201_DECODE(c, **outbuf) + else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc)){ + unsigned char c1, c2; + ucs4_t code; + + REQUIRE_INBUF(2) + c2 = IN2; + if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) + return 2; + + c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1); + c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); + c1 = (2 * c1 + (c2 < 0x5e ? 0 : 1)); + c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21; + + if (c1 < 0x5e) { /* Plane 1 */ + c1 += 0x21; + EMULATE_JISX0213_2000_DECODE_PLANE1(**outbuf, + c1, c2) + else TRYMAP_DEC(jisx0208, **outbuf, c1, c2) { + NEXT_OUT(1) + } + else TRYMAP_DEC(jisx0213_1_bmp, **outbuf, + c1, c2) { + NEXT_OUT(1) + } + else TRYMAP_DEC(jisx0213_1_emp, code, c1, c2) { + WRITEUCS4(EMPBASE | code) + } + else TRYMAP_DEC(jisx0213_pair, code, c1, c2) { + WRITE2(code >> 16, code & 0xffff) + NEXT_OUT(2) + } + else + return 2; + NEXT_IN(2) + } + else { /* Plane 2 */ + if (c1 >= 0x67) c1 += 0x07; + else if (c1 >= 0x63 || c1 == 0x5f) c1 -= 0x37; + else c1 -= 0x3d; + + EMULATE_JISX0213_2000_DECODE_PLANE2(**outbuf, + c1, c2) + else TRYMAP_DEC(jisx0213_2_bmp, **outbuf, + c1, c2) ; + else TRYMAP_DEC(jisx0213_2_emp, code, c1, c2) { + WRITEUCS4(EMPBASE | code) + NEXT_IN(2) + continue; + } + else + return 2; + NEXT(2, 1) + } + continue; + } + else + return 2; + + NEXT(1, 1) /* JIS X 0201 */ + } + + return 0; +} + + +BEGIN_MAPPINGS_LIST + MAPPING_DECONLY(jisx0208) + MAPPING_DECONLY(jisx0212) + MAPPING_ENCONLY(jisxcommon) + MAPPING_DECONLY(jisx0213_1_bmp) + MAPPING_DECONLY(jisx0213_2_bmp) + MAPPING_ENCONLY(jisx0213_bmp) + MAPPING_DECONLY(jisx0213_1_emp) + MAPPING_DECONLY(jisx0213_2_emp) + MAPPING_ENCONLY(jisx0213_emp) + MAPPING_ENCDEC(jisx0213_pair) + MAPPING_ENCDEC(cp932ext) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS(shift_jis) + CODEC_STATELESS(cp932) + CODEC_STATELESS(euc_jp) + CODEC_STATELESS(shift_jis_2004) + CODEC_STATELESS(euc_jis_2004) + CODEC_STATELESS_CONFIG(euc_jisx0213, (void *)2000, euc_jis_2004) + CODEC_STATELESS_CONFIG(shift_jisx0213, (void *)2000, shift_jis_2004) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(jp) diff --git a/pypy/translator/c/src/cjkcodecs/_codecs_kr.c b/pypy/translator/c/src/cjkcodecs/_codecs_kr.c new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/_codecs_kr.c @@ -0,0 +1,452 @@ +/* + * _codecs_kr.c: Codecs collection for Korean encodings + * + * Written by Hye-Shik Chang + */ + +#include "src/cjkcodecs/cjkcodecs.h" +#include "src/cjkcodecs/mappings_kr.h" + +/* + * EUC-KR codec + */ + +#define EUCKR_JAMO_FIRSTBYTE 0xA4 +#define EUCKR_JAMO_FILLER 0xD4 + +static const unsigned char u2cgk_choseong[19] = { + 0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xa9, 0xb1, 0xb2, + 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe +}; +static const unsigned char u2cgk_jungseong[21] = { + 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, + 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, + 0xcf, 0xd0, 0xd1, 0xd2, 0xd3 +}; +static const unsigned char u2cgk_jongseong[28] = { + 0xd4, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, + 0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xba, + 0xbb, 0xbc, 0xbd, 0xbe +}; + +ENCODER(euc_kr) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + TRYMAP_ENC(cp949, code, c); + else return 1; + + if ((code & 0x8000) == 0) { + /* KS X 1001 coded character */ + OUT1((code >> 8) | 0x80) + OUT2((code & 0xFF) | 0x80) + NEXT(1, 2) + } + else { /* Mapping is found in CP949 extension, + * but we encode it in KS X 1001:1998 Annex 3, + * make-up sequence for EUC-KR. */ + + REQUIRE_OUTBUF(8) + + /* syllable composition precedence */ + OUT1(EUCKR_JAMO_FIRSTBYTE) + OUT2(EUCKR_JAMO_FILLER) + + /* All codepoints in CP949 extension are in unicode + * Hangul Syllable area. */ + assert(0xac00 <= c && c <= 0xd7a3); + c -= 0xac00; + + OUT3(EUCKR_JAMO_FIRSTBYTE) + OUT4(u2cgk_choseong[c / 588]) + NEXT_OUT(4) + + OUT1(EUCKR_JAMO_FIRSTBYTE) + OUT2(u2cgk_jungseong[(c / 28) % 21]) + OUT3(EUCKR_JAMO_FIRSTBYTE) + OUT4(u2cgk_jongseong[c % 28]) + NEXT(1, 4) + } + } + + return 0; +} + +#define NONE 127 + +static const unsigned char cgk2u_choseong[] = { /* [A1, BE] */ + 0, 1, NONE, 2, NONE, NONE, 3, 4, + 5, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + 6, 7, 8, NONE, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18 +}; +static const unsigned char cgk2u_jongseong[] = { /* [A1, BE] */ + 1, 2, 3, 4, 5, 6, 7, NONE, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, NONE, 18, 19, 20, 21, 22, + NONE, 23, 24, 25, 26, 27 +}; + +DECODER(euc_kr) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + if (c == EUCKR_JAMO_FIRSTBYTE && + IN2 == EUCKR_JAMO_FILLER) { + /* KS X 1001:1998 Annex 3 make-up sequence */ + DBCHAR cho, jung, jong; + + REQUIRE_INBUF(8) + if ((*inbuf)[2] != EUCKR_JAMO_FIRSTBYTE || + (*inbuf)[4] != EUCKR_JAMO_FIRSTBYTE || + (*inbuf)[6] != EUCKR_JAMO_FIRSTBYTE) + return 8; + + c = (*inbuf)[3]; + if (0xa1 <= c && c <= 0xbe) + cho = cgk2u_choseong[c - 0xa1]; + else + cho = NONE; + + c = (*inbuf)[5]; + jung = (0xbf <= c && c <= 0xd3) ? c - 0xbf : NONE; + + c = (*inbuf)[7]; + if (c == EUCKR_JAMO_FILLER) + jong = 0; + else if (0xa1 <= c && c <= 0xbe) + jong = cgk2u_jongseong[c - 0xa1]; + else + jong = NONE; + + if (cho == NONE || jung == NONE || jong == NONE) + return 8; + + OUT1(0xac00 + cho*588 + jung*28 + jong); + NEXT(8, 1) + } + else TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80) { + NEXT(2, 1) + } + else + return 2; + } + + return 0; +} +#undef NONE + + +/* + * CP949 codec + */ + +ENCODER(cp949) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + TRYMAP_ENC(cp949, code, c); + else return 1; + + OUT1((code >> 8) | 0x80) + if (code & 0x8000) + OUT2(code & 0xFF) /* MSB set: CP949 */ + else + OUT2((code & 0xFF) | 0x80) /* MSB unset: ks x 1001 */ + NEXT(1, 2) + } + + return 0; +} + +DECODER(cp949) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80); + else TRYMAP_DEC(cp949ext, **outbuf, c, IN2); + else return 2; + + NEXT(2, 1) + } + + return 0; +} + + +/* + * JOHAB codec + */ + +static const unsigned char u2johabidx_choseong[32] = { + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, +}; +static const unsigned char u2johabidx_jungseong[32] = { + 0x03, 0x04, 0x05, 0x06, 0x07, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x1a, 0x1b, 0x1c, 0x1d, +}; +static const unsigned char u2johabidx_jongseong[32] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, +}; +static const DBCHAR u2johabjamo[] = { + 0x8841, 0x8c41, 0x8444, 0x9041, 0x8446, 0x8447, 0x9441, + 0x9841, 0x9c41, 0x844a, 0x844b, 0x844c, 0x844d, 0x844e, 0x844f, + 0x8450, 0xa041, 0xa441, 0xa841, 0x8454, 0xac41, 0xb041, 0xb441, + 0xb841, 0xbc41, 0xc041, 0xc441, 0xc841, 0xcc41, 0xd041, 0x8461, + 0x8481, 0x84a1, 0x84c1, 0x84e1, 0x8541, 0x8561, 0x8581, 0x85a1, + 0x85c1, 0x85e1, 0x8641, 0x8661, 0x8681, 0x86a1, 0x86c1, 0x86e1, + 0x8741, 0x8761, 0x8781, 0x87a1, +}; + +ENCODER(johab) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + + if (c >= 0xac00 && c <= 0xd7a3) { + c -= 0xac00; + code = 0x8000 | + (u2johabidx_choseong[c / 588] << 10) | + (u2johabidx_jungseong[(c / 28) % 21] << 5) | + u2johabidx_jongseong[c % 28]; + } + else if (c >= 0x3131 && c <= 0x3163) + code = u2johabjamo[c - 0x3131]; + else TRYMAP_ENC(cp949, code, c) { + unsigned char c1, c2, t2; + unsigned short t1; + + assert((code & 0x8000) == 0); + c1 = code >> 8; + c2 = code & 0xff; + if (((c1 >= 0x21 && c1 <= 0x2c) || + (c1 >= 0x4a && c1 <= 0x7d)) && + (c2 >= 0x21 && c2 <= 0x7e)) { + t1 = (c1 < 0x4a ? (c1 - 0x21 + 0x1b2) : + (c1 - 0x21 + 0x197)); + t2 = ((t1 & 1) ? 0x5e : 0) + (c2 - 0x21); + OUT1(t1 >> 1) + OUT2(t2 < 0x4e ? t2 + 0x31 : t2 + 0x43) + NEXT(1, 2) + continue; + } + else + return 1; + } + else + return 1; + + OUT1(code >> 8) + OUT2(code & 0xff) + NEXT(1, 2) + } + + return 0; +} + +#define FILL 0xfd +#define NONE 0xff + +static const unsigned char johabidx_choseong[32] = { + NONE, FILL, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x10, 0x11, 0x12, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, +}; +static const unsigned char johabidx_jungseong[32] = { + NONE, NONE, FILL, 0x00, 0x01, 0x02, 0x03, 0x04, + NONE, NONE, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + NONE, NONE, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + NONE, NONE, 0x11, 0x12, 0x13, 0x14, NONE, NONE, +}; +static const unsigned char johabidx_jongseong[32] = { + NONE, FILL, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, NONE, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, NONE, NONE, +}; + +static const unsigned char johabjamo_choseong[32] = { + NONE, FILL, 0x31, 0x32, 0x34, 0x37, 0x38, 0x39, + 0x41, 0x42, 0x43, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, +}; +static const unsigned char johabjamo_jungseong[32] = { + NONE, NONE, FILL, 0x4f, 0x50, 0x51, 0x52, 0x53, + NONE, NONE, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + NONE, NONE, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + NONE, NONE, 0x60, 0x61, 0x62, 0x63, NONE, NONE, +}; +static const unsigned char johabjamo_jongseong[32] = { + NONE, FILL, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, NONE, 0x42, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, NONE, NONE, +}; + +DECODER(johab) +{ + while (inleft > 0) { + unsigned char c = IN1, c2; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + c2 = IN2; + + if (c < 0xd8) { + /* johab hangul */ + unsigned char c_cho, c_jung, c_jong; + unsigned char i_cho, i_jung, i_jong; + + c_cho = (c >> 2) & 0x1f; + c_jung = ((c << 3) | c2 >> 5) & 0x1f; + c_jong = c2 & 0x1f; + + i_cho = johabidx_choseong[c_cho]; + i_jung = johabidx_jungseong[c_jung]; + i_jong = johabidx_jongseong[c_jong]; + + if (i_cho == NONE || i_jung == NONE || i_jong == NONE) + return 2; + + /* we don't use U+1100 hangul jamo yet. */ + if (i_cho == FILL) { + if (i_jung == FILL) { + if (i_jong == FILL) + OUT1(0x3000) + else + OUT1(0x3100 | + johabjamo_jongseong[c_jong]) + } + else { + if (i_jong == FILL) + OUT1(0x3100 | + johabjamo_jungseong[c_jung]) + else + return 2; + } + } else { + if (i_jung == FILL) { + if (i_jong == FILL) + OUT1(0x3100 | + johabjamo_choseong[c_cho]) + else + return 2; + } + else + OUT1(0xac00 + + i_cho * 588 + + i_jung * 28 + + (i_jong == FILL ? 0 : i_jong)) + } + NEXT(2, 1) + } else { + /* KS X 1001 except hangul jamos and syllables */ + if (c == 0xdf || c > 0xf9 || + c2 < 0x31 || (c2 >= 0x80 && c2 < 0x91) || + (c2 & 0x7f) == 0x7f || + (c == 0xda && (c2 >= 0xa1 && c2 <= 0xd3))) + return 2; + else { + unsigned char t1, t2; + + t1 = (c < 0xe0 ? 2 * (c - 0xd9) : + 2 * c - 0x197); + t2 = (c2 < 0x91 ? c2 - 0x31 : c2 - 0x43); + t1 = t1 + (t2 < 0x5e ? 0 : 1) + 0x21; + t2 = (t2 < 0x5e ? t2 : t2 - 0x5e) + 0x21; + + TRYMAP_DEC(ksx1001, **outbuf, t1, t2); + else return 2; + NEXT(2, 1) + } + } + } + + return 0; +} +#undef NONE +#undef FILL + + +BEGIN_MAPPINGS_LIST + MAPPING_DECONLY(ksx1001) + MAPPING_ENCONLY(cp949) + MAPPING_DECONLY(cp949ext) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS(euc_kr) + CODEC_STATELESS(cp949) + CODEC_STATELESS(johab) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(kr) diff --git a/pypy/translator/c/src/cjkcodecs/_codecs_tw.c b/pypy/translator/c/src/cjkcodecs/_codecs_tw.c new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/_codecs_tw.c @@ -0,0 +1,132 @@ +/* + * _codecs_tw.c: Codecs collection for Taiwan's encodings + * + * Written by Hye-Shik Chang + */ + +#include "src/cjkcodecs/cjkcodecs.h" +#include "src/cjkcodecs/mappings_tw.h" + +/* + * BIG5 codec + */ + +ENCODER(big5) +{ + while (inleft > 0) { + Py_UNICODE c = **inbuf; + DBCHAR code; + + if (c < 0x80) { + REQUIRE_OUTBUF(1) + **outbuf = (unsigned char)c; + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + + TRYMAP_ENC(big5, code, c); + else return 1; + + OUT1(code >> 8) + OUT2(code & 0xFF) + NEXT(1, 2) + } + + return 0; +} + +DECODER(big5) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + TRYMAP_DEC(big5, **outbuf, c, IN2) { + NEXT(2, 1) + } + else return 2; + } + + return 0; +} + + +/* + * CP950 codec + */ + +ENCODER(cp950) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + TRYMAP_ENC(cp950ext, code, c); + else TRYMAP_ENC(big5, code, c); + else return 1; + + OUT1(code >> 8) + OUT2(code & 0xFF) + NEXT(1, 2) + } + + return 0; +} + +DECODER(cp950) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + TRYMAP_DEC(cp950ext, **outbuf, c, IN2); + else TRYMAP_DEC(big5, **outbuf, c, IN2); + else return 2; + + NEXT(2, 1) + } + + return 0; +} + + + +BEGIN_MAPPINGS_LIST + MAPPING_ENCDEC(big5) + MAPPING_ENCDEC(cp950ext) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS(big5) + CODEC_STATELESS(cp950) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(tw) diff --git a/pypy/translator/c/src/cjkcodecs/alg_jisx0201.h b/pypy/translator/c/src/cjkcodecs/alg_jisx0201.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/alg_jisx0201.h @@ -0,0 +1,24 @@ +#define JISX0201_R_ENCODE(c, assi) \ + if ((c) < 0x80 && (c) != 0x5c && (c) != 0x7e) \ + (assi) = (c); \ + else if ((c) == 0x00a5) (assi) = 0x5c; \ + else if ((c) == 0x203e) (assi) = 0x7e; +#define JISX0201_K_ENCODE(c, assi) \ + if ((c) >= 0xff61 && (c) <= 0xff9f) \ + (assi) = (c) - 0xfec0; +#define JISX0201_ENCODE(c, assi) \ + JISX0201_R_ENCODE(c, assi) \ + else JISX0201_K_ENCODE(c, assi) + +#define JISX0201_R_DECODE(c, assi) \ + if ((c) < 0x5c) (assi) = (c); \ + else if ((c) == 0x5c) (assi) = 0x00a5; \ + else if ((c) < 0x7e) (assi) = (c); \ + else if ((c) == 0x7e) (assi) = 0x203e; \ + else if ((c) == 0x7f) (assi) = 0x7f; +#define JISX0201_K_DECODE(c, assi) \ + if ((c) >= 0xa1 && (c) <= 0xdf) \ + (assi) = 0xfec0 + (c); +#define JISX0201_DECODE(c, assi) \ + JISX0201_R_DECODE(c, assi) \ + else JISX0201_K_DECODE(c, assi) diff --git a/pypy/translator/c/src/cjkcodecs/cjkcodecs.h b/pypy/translator/c/src/cjkcodecs/cjkcodecs.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/cjkcodecs.h @@ -0,0 +1,309 @@ +/* + * cjkcodecs.h is inspired by the file of the same name from CPython, + * but was heavily modified to suit PyPy. + * + * Original author: Hye-Shik Chang + * Modified by: Armin Rigo + */ + +#ifndef _CJKCODECS_H_ +#define _CJKCODECS_H_ + +#include "src/cjkcodecs/multibytecodec.h" + + +/* a unicode "undefined" codepoint */ +#define UNIINV 0xFFFE + +/* internal-use DBCS codepoints which aren't used by any charsets */ +#define NOCHAR 0xFFFF +#define MULTIC 0xFFFE +#define DBCINV 0xFFFD + +/* shorter macros to save source size of mapping tables */ +#define U UNIINV +#define N NOCHAR +#define M MULTIC +#define D DBCINV + +struct dbcs_index { + const ucs2_t *map; + unsigned char bottom, top; +}; +typedef struct dbcs_index decode_map; + +struct widedbcs_index { + const ucs4_t *map; + unsigned char bottom, top; +}; +typedef struct widedbcs_index widedecode_map; + +struct unim_index { + const DBCHAR *map; + unsigned char bottom, top; +}; +typedef struct unim_index encode_map; + +struct unim_index_bytebased { + const unsigned char *map; + unsigned char bottom, top; +}; + +struct dbcs_map { + const char *charset; + const struct unim_index *encmap; + const struct dbcs_index *decmap; +}; + +struct pair_encodemap { + ucs4_t uniseq; + DBCHAR code; +}; + +#define CODEC_INIT(encoding) \ + static int encoding##_codec_init(const void *config) + +#define ENCODER_INIT(encoding) \ + static int encoding##_encode_init( \ + MultibyteCodec_State *state, const void *config) +#define ENCODER(encoding) \ + static Py_ssize_t encoding##_encode( \ + MultibyteCodec_State *state, const void *config, \ + const Py_UNICODE **inbuf, Py_ssize_t inleft, \ + unsigned char **outbuf, Py_ssize_t outleft, int flags) +#define ENCODER_RESET(encoding) \ + static Py_ssize_t encoding##_encode_reset( \ + MultibyteCodec_State *state, const void *config, \ + unsigned char **outbuf, Py_ssize_t outleft) + +#define DECODER_INIT(encoding) \ + static int encoding##_decode_init( \ + MultibyteCodec_State *state, const void *config) +#define DECODER(encoding) \ + static Py_ssize_t encoding##_decode( \ + MultibyteCodec_State *state, const void *config, \ + const unsigned char **inbuf, Py_ssize_t inleft, \ + Py_UNICODE **outbuf, Py_ssize_t outleft) +#define DECODER_RESET(encoding) \ + static Py_ssize_t encoding##_decode_reset( \ + MultibyteCodec_State *state, const void *config) + +#if Py_UNICODE_SIZE == 4 +#define UCS4INVALID(code) \ + if ((code) > 0xFFFF) \ + return 1; +#else +#define UCS4INVALID(code) \ + if (0) ; +#endif + +#define NEXT_IN(i) \ + (*inbuf) += (i); \ + (inleft) -= (i); +#define NEXT_OUT(o) \ + (*outbuf) += (o); \ + (outleft) -= (o); +#define NEXT(i, o) \ + NEXT_IN(i) NEXT_OUT(o) + +#define REQUIRE_INBUF(n) \ + if (inleft < (n)) \ + return MBERR_TOOFEW; +#define REQUIRE_OUTBUF(n) \ + if (outleft < (n)) \ + return MBERR_TOOSMALL; + +#define IN1 ((*inbuf)[0]) +#define IN2 ((*inbuf)[1]) +#define IN3 ((*inbuf)[2]) +#define IN4 ((*inbuf)[3]) + +#define OUT1(c) ((*outbuf)[0]) = (c); +#define OUT2(c) ((*outbuf)[1]) = (c); +#define OUT3(c) ((*outbuf)[2]) = (c); +#define OUT4(c) ((*outbuf)[3]) = (c); + +#define WRITE1(c1) \ + REQUIRE_OUTBUF(1) \ + (*outbuf)[0] = (c1); +#define WRITE2(c1, c2) \ + REQUIRE_OUTBUF(2) \ + (*outbuf)[0] = (c1); \ + (*outbuf)[1] = (c2); +#define WRITE3(c1, c2, c3) \ + REQUIRE_OUTBUF(3) \ + (*outbuf)[0] = (c1); \ + (*outbuf)[1] = (c2); \ + (*outbuf)[2] = (c3); +#define WRITE4(c1, c2, c3, c4) \ + REQUIRE_OUTBUF(4) \ + (*outbuf)[0] = (c1); \ + (*outbuf)[1] = (c2); \ + (*outbuf)[2] = (c3); \ + (*outbuf)[3] = (c4); + +#if Py_UNICODE_SIZE == 2 +# define WRITEUCS4(c) \ + REQUIRE_OUTBUF(2) \ + (*outbuf)[0] = 0xd800 + (((c) - 0x10000) >> 10); \ + (*outbuf)[1] = 0xdc00 + (((c) - 0x10000) & 0x3ff); \ + NEXT_OUT(2) +#else +# define WRITEUCS4(c) \ + REQUIRE_OUTBUF(1) \ + **outbuf = (Py_UNICODE)(c); \ + NEXT_OUT(1) +#endif + +#define _TRYMAP_ENC(m, assi, val) \ + ((m)->map != NULL && (val) >= (m)->bottom && \ + (val)<= (m)->top && ((assi) = (m)->map[(val) - \ + (m)->bottom]) != NOCHAR) +#define TRYMAP_ENC_COND(charset, assi, uni) \ + _TRYMAP_ENC(&charset##_encmap[(uni) >> 8], assi, (uni) & 0xff) +#define TRYMAP_ENC(charset, assi, uni) \ + if TRYMAP_ENC_COND(charset, assi, uni) + +#define _TRYMAP_DEC(m, assi, val) \ + ((m)->map != NULL && (val) >= (m)->bottom && \ + (val)<= (m)->top && ((assi) = (m)->map[(val) - \ + (m)->bottom]) != UNIINV) +#define TRYMAP_DEC(charset, assi, c1, c2) \ + if _TRYMAP_DEC(&charset##_decmap[c1], assi, c2) + +#define _TRYMAP_ENC_MPLANE(m, assplane, asshi, asslo, val) \ + ((m)->map != NULL && (val) >= (m)->bottom && \ + (val)<= (m)->top && \ + ((assplane) = (m)->map[((val) - (m)->bottom)*3]) != 0 && \ + (((asshi) = (m)->map[((val) - (m)->bottom)*3 + 1]), 1) && \ + (((asslo) = (m)->map[((val) - (m)->bottom)*3 + 2]), 1)) +#define TRYMAP_ENC_MPLANE(charset, assplane, asshi, asslo, uni) \ + if _TRYMAP_ENC_MPLANE(&charset##_encmap[(uni) >> 8], \ + assplane, asshi, asslo, (uni) & 0xff) +#define TRYMAP_DEC_MPLANE(charset, assi, plane, c1, c2) \ + if _TRYMAP_DEC(&charset##_decmap[plane][c1], assi, c2) + +#if Py_UNICODE_SIZE == 2 +#define DECODE_SURROGATE(c) \ + if (c >> 10 == 0xd800 >> 10) { /* high surrogate */ \ + REQUIRE_INBUF(2) \ + if (IN2 >> 10 == 0xdc00 >> 10) { /* low surrogate */ \ + c = 0x10000 + ((ucs4_t)(c - 0xd800) << 10) + \ + ((ucs4_t)(IN2) - 0xdc00); \ + } \ + } +#define GET_INSIZE(c) ((c) > 0xffff ? 2 : 1) +#else +#define DECODE_SURROGATE(c) {;} +#define GET_INSIZE(c) 1 +#endif + +#define BEGIN_MAPPINGS_LIST /* empty */ +#define MAPPING_ENCONLY(enc) \ + const struct dbcs_map pypy_cjkmap_##enc = {#enc, (void*)enc##_encmap, NULL}; +#define MAPPING_DECONLY(enc) \ + const struct dbcs_map pypy_cjkmap_##enc = {#enc, NULL, (void*)enc##_decmap}; +#define MAPPING_ENCDEC(enc) \ + const struct dbcs_map pypy_cjkmap_##enc = {#enc, (void*)enc##_encmap, \ + (void*)enc##_decmap}; +#define END_MAPPINGS_LIST /* empty */ + +#define BEGIN_CODECS_LIST /* empty */ +#define _CODEC(name) \ + static const MultibyteCodec _pypy_cjkcodec_##name; \ + const MultibyteCodec *pypy_cjkcodec_##name(void) { \ + if (_pypy_cjkcodec_##name.codecinit != NULL) { \ + int r = _pypy_cjkcodec_##name.codecinit(_pypy_cjkcodec_##name.config); \ + assert(r == 0); \ + } \ + return &_pypy_cjkcodec_##name; \ + } \ + static const MultibyteCodec _pypy_cjkcodec_##name +#define _STATEFUL_METHODS(enc) \ + enc##_encode, \ + enc##_encode_init, \ + enc##_encode_reset, \ + enc##_decode, \ + enc##_decode_init, \ + enc##_decode_reset, +#define _STATELESS_METHODS(enc) \ + enc##_encode, NULL, NULL, \ + enc##_decode, NULL, NULL, +#define CODEC_STATEFUL(enc) _CODEC(enc) = { \ + #enc, NULL, NULL, \ + _STATEFUL_METHODS(enc) \ + }; +#define CODEC_STATELESS(enc) _CODEC(enc) = { \ + #enc, NULL, NULL, \ + _STATELESS_METHODS(enc) \ + }; +#define CODEC_STATELESS_WINIT(enc) _CODEC(enc) = { \ + #enc, NULL, \ + enc##_codec_init, \ + _STATELESS_METHODS(enc) \ + }; +#define CODEC_STATELESS_CONFIG(enc, config, baseenc) _CODEC(enc) = { \ + #enc, config, NULL, \ + _STATELESS_METHODS(baseenc) \ + }; +#define CODEC_STATEFUL_CONFIG(enc, variation, config) \ + _CODEC(enc##_##variation) = { \ + #enc "_" #variation, \ + config, \ + enc##_codec_init, \ + _STATEFUL_METHODS(enc) \ + }; +#define END_CODECS_LIST /* empty */ + + +#ifdef USING_BINARY_PAIR_SEARCH +static DBCHAR +find_pairencmap(ucs2_t body, ucs2_t modifier, + const struct pair_encodemap *haystack, int haystacksize) +{ + int pos, min, max; + ucs4_t value = body << 16 | modifier; + + min = 0; + max = haystacksize; + + for (pos = haystacksize >> 1; min != max; pos = (min + max) >> 1) + if (value < haystack[pos].uniseq) { + if (max == pos) break; + else max = pos; + } + else if (value > haystack[pos].uniseq) { + if (min == pos) break; + else min = pos; + } + else + break; + + if (value == haystack[pos].uniseq) + return haystack[pos].code; + else + return DBCINV; +} +#endif + + +#ifdef USING_IMPORTED_MAPS +#define USING_IMPORTED_MAP(charset) \ + extern const struct dbcs_map pypy_cjkmap_##charset; + +#define IMPORT_MAP(locale, charset, encmap, decmap) \ + importmap(&pypy_cjkmap_##charset, encmap, decmap) + +static void importmap(const struct dbcs_map *src, void *encmp, + void *decmp) +{ + if (encmp) *(const encode_map **)encmp = src->encmap; + if (decmp) *(const decode_map **)decmp = src->decmap; +} +#endif + + +#define I_AM_A_MODULE_FOR(loc) /* empty */ + + +#endif diff --git a/pypy/translator/c/src/cjkcodecs/emu_jisx0213_2000.h b/pypy/translator/c/src/cjkcodecs/emu_jisx0213_2000.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/emu_jisx0213_2000.h @@ -0,0 +1,43 @@ +/* These routines may be quite inefficient, but it's used only to emulate old + * standards. */ + +#ifndef EMULATE_JISX0213_2000_ENCODE_INVALID +#define EMULATE_JISX0213_2000_ENCODE_INVALID 1 +#endif + +#define EMULATE_JISX0213_2000_ENCODE_BMP(assi, c) \ + if (config == (void *)2000 && ( \ + (c) == 0x9B1C || (c) == 0x4FF1 || \ + (c) == 0x525D || (c) == 0x541E || \ + (c) == 0x5653 || (c) == 0x59F8 || \ + (c) == 0x5C5B || (c) == 0x5E77 || \ + (c) == 0x7626 || (c) == 0x7E6B)) \ + return EMULATE_JISX0213_2000_ENCODE_INVALID; \ + else if (config == (void *)2000 && (c) == 0x9B1D) \ + (assi) = 0x8000 | 0x7d3b; \ + +#define EMULATE_JISX0213_2000_ENCODE_EMP(assi, c) \ + if (config == (void *)2000 && (c) == 0x20B9F) \ + return EMULATE_JISX0213_2000_ENCODE_INVALID; + +#ifndef EMULATE_JISX0213_2000_DECODE_INVALID +#define EMULATE_JISX0213_2000_DECODE_INVALID 2 +#endif + +#define EMULATE_JISX0213_2000_DECODE_PLANE1(assi, c1, c2) \ + if (config == (void *)2000 && \ + (((c1) == 0x2E && (c2) == 0x21) || \ + ((c1) == 0x2F && (c2) == 0x7E) || \ + ((c1) == 0x4F && (c2) == 0x54) || \ + ((c1) == 0x4F && (c2) == 0x7E) || \ + ((c1) == 0x74 && (c2) == 0x27) || \ + ((c1) == 0x7E && (c2) == 0x7A) || \ + ((c1) == 0x7E && (c2) == 0x7B) || \ + ((c1) == 0x7E && (c2) == 0x7C) || \ + ((c1) == 0x7E && (c2) == 0x7D) || \ + ((c1) == 0x7E && (c2) == 0x7E))) \ + return EMULATE_JISX0213_2000_DECODE_INVALID; + +#define EMULATE_JISX0213_2000_DECODE_PLANE2(assi, c1, c2) \ + if (config == (void *)2000 && (c1) == 0x7D && (c2) == 0x3B) \ + (assi) = 0x9B1D; diff --git a/pypy/translator/c/src/cjkcodecs/mappings_cn.h b/pypy/translator/c/src/cjkcodecs/mappings_cn.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/mappings_cn.h @@ -0,0 +1,4103 @@ +static const ucs2_t __gb2312_decmap[7482] = { +12288,12289,12290,12539,713,711,168,12291,12293,8213,65374,8214,8230,8216, +8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303, +12310,12311,12304,12305,177,215,247,8758,8743,8744,8721,8719,8746,8745,8712, +8759,8730,8869,8741,8736,8978,8857,8747,8750,8801,8780,8776,8765,8733,8800, +8814,8815,8804,8805,8734,8757,8756,9794,9792,176,8242,8243,8451,65284,164, +65504,65505,8240,167,8470,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651, +9650,8251,8594,8592,8593,8595,12307,9352,9353,9354,9355,9356,9357,9358,9359, +9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9332,9333,9334, +9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349, +9350,9351,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,U,U,12832,12833, +12834,12835,12836,12837,12838,12839,12840,12841,U,U,8544,8545,8546,8547,8548, +8549,8550,8551,8552,8553,8554,8555,65281,65282,65283,65509,65285,65286,65287, +65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300, +65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313, +65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326, +65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339, +65340,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352, +65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365, +65366,65367,65368,65369,65370,65371,65372,65373,65507,12353,12354,12355,12356, +12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369, +12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382, +12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395, +12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408, +12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421, +12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434, +12435,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460, +12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473, +12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486, +12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499, +12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512, +12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525, +12526,12527,12528,12529,12530,12531,12532,12533,12534,913,914,915,916,917,918, +919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,U,U,U, +U,U,U,U,U,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961, +963,964,965,966,967,968,969,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048, +1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063, +1064,1065,1066,1067,1068,1069,1070,1071,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,1072, +1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086, +1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101, +1102,1103,257,225,462,224,275,233,283,232,299,237,464,236,333,243,466,242,363, +250,468,249,470,472,474,476,252,234,U,U,U,U,U,U,U,U,U,U,12549,12550,12551, +12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564, +12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577, +12578,12579,12580,12581,12582,12583,12584,12585,9472,9473,9474,9475,9476,9477, +9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492, +9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507, +9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522, +9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537, +9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,21834,38463,22467,25384, +21710,21769,21696,30353,30284,34108,30702,33406,30861,29233,38552,38797,27688, +23433,20474,25353,26263,23736,33018,26696,32942,26114,30414,20985,25942,29100, +32753,34948,20658,22885,25034,28595,33453,25420,25170,21485,21543,31494,20843, +30116,24052,25300,36299,38774,25226,32793,22365,38712,32610,29240,30333,26575, +30334,25670,20336,36133,25308,31255,26001,29677,25644,25203,33324,39041,26495, +29256,25198,25292,20276,29923,21322,21150,32458,37030,24110,26758,27036,33152, +32465,26834,30917,34444,38225,20621,35876,33502,32990,21253,35090,21093,34180, +38649,20445,22561,39281,23453,25265,25253,26292,35961,40077,29190,26479,30865, +24754,21329,21271,36744,32972,36125,38049,20493,29384,22791,24811,28953,34987, +22868,33519,26412,31528,23849,32503,29997,27893,36454,36856,36924,40763,27604, +37145,31508,24444,30887,34006,34109,27605,27609,27606,24065,24199,30201,38381, +25949,24330,24517,36767,22721,33218,36991,38491,38829,36793,32534,36140,25153, +20415,21464,21342,36776,36777,36779,36941,26631,24426,33176,34920,40150,24971, +21035,30250,24428,25996,28626,28392,23486,25672,20853,20912,26564,19993,31177, +39292,28851,30149,24182,29627,33760,25773,25320,38069,27874,21338,21187,25615, +38082,31636,20271,24091,33334,33046,33162,28196,27850,39539,25429,21340,21754, +34917,22496,19981,24067,27493,31807,37096,24598,25830,29468,35009,26448,25165, +36130,30572,36393,37319,24425,33756,34081,39184,21442,34453,27531,24813,24808, +28799,33485,33329,20179,27815,34255,25805,31961,27133,26361,33609,21397,31574, +20391,20876,27979,23618,36461,25554,21449,33580,33590,26597,30900,25661,23519, +23700,24046,35815,25286,26612,35962,25600,25530,34633,39307,35863,32544,38130, +20135,38416,39076,26124,29462,22330,23581,24120,38271,20607,32928,21378,25950, +30021,21809,20513,36229,25220,38046,26397,22066,28526,24034,21557,28818,36710, +25199,25764,25507,24443,28552,37108,33251,36784,23576,26216,24561,27785,38472, +36225,34924,25745,31216,22478,27225,25104,21576,20056,31243,24809,28548,35802, +25215,36894,39563,31204,21507,30196,25345,21273,27744,36831,24347,39536,32827, +40831,20360,23610,36196,32709,26021,28861,20805,20914,34411,23815,23456,25277, +37228,30068,36364,31264,24833,31609,20167,32504,30597,19985,33261,21021,20986, +27249,21416,36487,38148,38607,28353,38500,26970,30784,20648,30679,25616,35302, +22788,25571,24029,31359,26941,20256,33337,21912,20018,30126,31383,24162,24202, +38383,21019,21561,28810,25462,38180,22402,26149,26943,37255,21767,28147,32431, +34850,25139,32496,30133,33576,30913,38604,36766,24904,29943,35789,27492,21050, +36176,27425,32874,33905,22257,21254,20174,19995,20945,31895,37259,31751,20419, +36479,31713,31388,25703,23828,20652,33030,30209,31929,28140,32736,26449,23384, +23544,30923,25774,25619,25514,25387,38169,25645,36798,31572,30249,25171,22823, +21574,27513,20643,25140,24102,27526,20195,36151,34955,24453,36910,24608,32829, +25285,20025,21333,37112,25528,32966,26086,27694,20294,24814,28129,35806,24377, +34507,24403,25377,20826,33633,26723,20992,25443,36424,20498,23707,31095,23548, +21040,31291,24764,36947,30423,24503,24471,30340,36460,28783,30331,31561,30634, +20979,37011,22564,20302,28404,36842,25932,31515,29380,28068,32735,23265,25269, +24213,22320,33922,31532,24093,24351,36882,32532,39072,25474,28359,30872,28857, +20856,38747,22443,30005,20291,30008,24215,24806,22880,28096,27583,30857,21500, +38613,20939,20993,25481,21514,38035,35843,36300,29241,30879,34678,36845,35853, +21472,19969,30447,21486,38025,39030,40718,38189,23450,35746,20002,19996,20908, +33891,25026,21160,26635,20375,24683,20923,27934,20828,25238,26007,38497,35910, +36887,30168,37117,30563,27602,29322,29420,35835,22581,30585,36172,26460,38208, +32922,24230,28193,22930,31471,30701,38203,27573,26029,32526,22534,20817,38431, +23545,22697,21544,36466,25958,39039,22244,38045,30462,36929,25479,21702,22810, +22842,22427,36530,26421,36346,33333,21057,24816,22549,34558,23784,40517,20420, +39069,35769,23077,24694,21380,25212,36943,37122,39295,24681,32780,20799,32819, +23572,39285,27953,20108,36144,21457,32602,31567,20240,20047,38400,27861,29648, +34281,24070,30058,32763,27146,30718,38034,32321,20961,28902,21453,36820,33539, +36137,29359,39277,27867,22346,33459,26041,32938,25151,38450,22952,20223,35775, +32442,25918,33778,38750,21857,39134,32933,21290,35837,21536,32954,24223,27832, +36153,33452,37210,21545,27675,20998,32439,22367,28954,27774,31881,22859,20221, +24575,24868,31914,20016,23553,26539,34562,23792,38155,39118,30127,28925,36898, +20911,32541,35773,22857,20964,20315,21542,22827,25975,32932,23413,25206,25282, +36752,24133,27679,31526,20239,20440,26381,28014,28074,31119,34993,24343,29995, +25242,36741,20463,37340,26023,33071,33105,24220,33104,36212,21103,35206,36171, +22797,20613,20184,38428,29238,33145,36127,23500,35747,38468,22919,32538,21648, +22134,22030,35813,25913,27010,38041,30422,28297,24178,29976,26438,26577,31487, +32925,36214,24863,31174,25954,36195,20872,21018,38050,32568,32923,32434,23703, +28207,26464,31705,30347,39640,33167,32660,31957,25630,38224,31295,21578,21733, +27468,25601,25096,40509,33011,30105,21106,38761,33883,26684,34532,38401,38548, +38124,20010,21508,32473,26681,36319,32789,26356,24218,32697,22466,32831,26775, +24037,25915,21151,24685,40858,20379,36524,20844,23467,24339,24041,27742,25329, +36129,20849,38057,21246,27807,33503,29399,22434,26500,36141,22815,36764,33735, +21653,31629,20272,27837,23396,22993,40723,21476,34506,39592,35895,32929,25925, +39038,22266,38599,21038,29916,21072,23521,25346,35074,20054,25296,24618,26874, +20851,23448,20896,35266,31649,39302,32592,24815,28748,36143,20809,24191,36891, +29808,35268,22317,30789,24402,40863,38394,36712,39740,35809,30328,26690,26588, +36330,36149,21053,36746,28378,26829,38149,37101,22269,26524,35065,36807,21704, +39608,23401,28023,27686,20133,23475,39559,37219,25000,37039,38889,21547,28085, +23506,20989,21898,32597,32752,25788,25421,26097,25022,24717,28938,27735,27721, +22831,26477,33322,22741,22158,35946,27627,37085,22909,32791,21495,28009,21621, +21917,33655,33743,26680,31166,21644,20309,21512,30418,35977,38402,27827,28088, +36203,35088,40548,36154,22079,40657,30165,24456,29408,24680,21756,20136,27178, +34913,24658,36720,21700,28888,34425,40511,27946,23439,24344,32418,21897,20399, +29492,21564,21402,20505,21518,21628,20046,24573,29786,22774,33899,32993,34676, +29392,31946,28246,24359,34382,21804,25252,20114,27818,25143,33457,21719,21326, +29502,28369,30011,21010,21270,35805,27088,24458,24576,28142,22351,27426,29615, +26707,36824,32531,25442,24739,21796,30186,35938,28949,28067,23462,24187,33618, +24908,40644,30970,34647,31783,30343,20976,24822,29004,26179,24140,24653,35854, +28784,25381,36745,24509,24674,34516,22238,27585,24724,24935,21321,24800,26214, +36159,31229,20250,28905,27719,35763,35826,32472,33636,26127,23130,39746,27985, +28151,35905,27963,20249,28779,33719,25110,24785,38669,36135,31096,20987,22334, +22522,26426,30072,31293,31215,31637,32908,39269,36857,28608,35749,40481,23020, +32489,32521,21513,26497,26840,36753,31821,38598,21450,24613,30142,27762,21363, +23241,32423,25380,20960,33034,24049,34015,25216,20864,23395,20238,31085,21058, +24760,27982,23492,23490,35745,35760,26082,24524,38469,22931,32487,32426,22025, +26551,22841,20339,23478,21152,33626,39050,36158,30002,38078,20551,31292,20215, +26550,39550,23233,27516,30417,22362,23574,31546,38388,29006,20860,32937,33392, +22904,32516,33575,26816,26604,30897,30839,25315,25441,31616,20461,21098,20943, +33616,27099,37492,36341,36145,35265,38190,31661,20214,20581,33328,21073,39279, +28176,28293,28071,24314,20725,23004,23558,27974,27743,30086,33931,26728,22870, +35762,21280,37233,38477,34121,26898,30977,28966,33014,20132,37066,27975,39556, +23047,22204,25605,38128,30699,20389,33050,29409,35282,39290,32564,32478,21119, +25945,37237,36735,36739,21483,31382,25581,25509,30342,31224,34903,38454,25130, +21163,33410,26708,26480,25463,30571,31469,27905,32467,35299,22992,25106,34249, +33445,30028,20511,20171,30117,35819,23626,24062,31563,26020,37329,20170,27941, +35167,32039,38182,20165,35880,36827,38771,26187,31105,36817,28908,28024,23613, +21170,33606,20834,33550,30555,26230,40120,20140,24778,31934,31923,32463,20117, +35686,26223,39048,38745,22659,25964,38236,24452,30153,38742,31455,31454,20928, +28847,31384,25578,31350,32416,29590,38893,20037,28792,20061,37202,21417,25937, +26087,33276,33285,21646,23601,30106,38816,25304,29401,30141,23621,39545,33738, +23616,21632,30697,20030,27822,32858,25298,25454,24040,20855,36317,36382,38191, +20465,21477,24807,28844,21095,25424,40515,23071,20518,30519,21367,32482,25733, +25899,25225,25496,20500,29237,35273,20915,35776,32477,22343,33740,38055,20891, +21531,23803,20426,31459,27994,37089,39567,21888,21654,21345,21679,24320,25577, +26999,20975,24936,21002,22570,21208,22350,30733,30475,24247,24951,31968,25179, +25239,20130,28821,32771,25335,28900,38752,22391,33499,26607,26869,30933,39063, +31185,22771,21683,21487,28212,20811,21051,23458,35838,32943,21827,22438,24691, +22353,21549,31354,24656,23380,25511,25248,21475,25187,23495,26543,21741,31391, +33510,37239,24211,35044,22840,22446,25358,36328,33007,22359,31607,20393,24555, +23485,27454,21281,31568,29378,26694,30719,30518,26103,20917,20111,30420,23743, +31397,33909,22862,39745,20608,39304,24871,28291,22372,26118,25414,22256,25324, +25193,24275,38420,22403,25289,21895,34593,33098,36771,21862,33713,26469,36182, +34013,23146,26639,25318,31726,38417,20848,28572,35888,25597,35272,25042,32518, +28866,28389,29701,27028,29436,24266,37070,26391,28010,25438,21171,29282,32769, +20332,23013,37226,28889,28061,21202,20048,38647,38253,34174,30922,32047,20769, +22418,25794,32907,31867,27882,26865,26974,20919,21400,26792,29313,40654,31729, +29432,31163,28435,29702,26446,37324,40100,31036,33673,33620,21519,26647,20029, +21385,21169,30782,21382,21033,20616,20363,20432,30178,31435,31890,27813,38582, +21147,29827,21737,20457,32852,33714,36830,38256,24265,24604,28063,24088,25947, +33080,38142,24651,28860,32451,31918,20937,26753,31921,33391,20004,36742,37327, +26238,20142,35845,25769,32842,20698,30103,29134,23525,36797,28518,20102,25730, +38243,24278,26009,21015,35010,28872,21155,29454,29747,26519,30967,38678,20020, +37051,40158,28107,20955,36161,21533,25294,29618,33777,38646,40836,38083,20278, +32666,20940,28789,38517,23725,39046,21478,20196,28316,29705,27060,30827,39311, +30041,21016,30244,27969,26611,20845,40857,32843,21657,31548,31423,38534,22404, +25314,38471,27004,23044,25602,31699,28431,38475,33446,21346,39045,24208,28809, +25523,21348,34383,40065,40595,30860,38706,36335,36162,40575,28510,31108,24405, +38470,25134,39540,21525,38109,20387,26053,23653,23649,32533,34385,27695,24459, +29575,28388,32511,23782,25371,23402,28390,21365,20081,25504,30053,25249,36718, +20262,20177,27814,32438,35770,33821,34746,32599,36923,38179,31657,39585,35064, +33853,27931,39558,32476,22920,40635,29595,30721,34434,39532,39554,22043,21527, +22475,20080,40614,21334,36808,33033,30610,39314,34542,28385,34067,26364,24930, +28459,35881,33426,33579,30450,27667,24537,33725,29483,33541,38170,27611,30683, +38086,21359,33538,20882,24125,35980,36152,20040,29611,26522,26757,37238,38665, +29028,27809,30473,23186,38209,27599,32654,26151,23504,22969,23194,38376,38391, +20204,33804,33945,27308,30431,38192,29467,26790,23391,30511,37274,38753,31964, +36855,35868,24357,31859,31192,35269,27852,34588,23494,24130,26825,30496,32501, +20885,20813,21193,23081,32517,38754,33495,25551,30596,34256,31186,28218,24217, +22937,34065,28781,27665,25279,30399,25935,24751,38397,26126,34719,40483,38125, +21517,21629,35884,25720,25721,34321,27169,33180,30952,25705,39764,25273,26411, +33707,22696,40664,27819,28448,23518,38476,35851,29279,26576,25287,29281,20137, +22982,27597,22675,26286,24149,21215,24917,26408,30446,30566,29287,31302,25343, +21738,21584,38048,37027,23068,32435,27670,20035,22902,32784,22856,21335,30007, +38590,22218,25376,33041,24700,38393,28118,21602,39297,20869,23273,33021,22958, +38675,20522,27877,23612,25311,20320,21311,33147,36870,28346,34091,25288,24180, +30910,25781,25467,24565,23064,37247,40479,23615,25423,32834,23421,21870,38218, +38221,28037,24744,26592,29406,20957,23425,25319,27870,29275,25197,38062,32445, +33043,27987,20892,24324,22900,21162,24594,22899,26262,34384,30111,25386,25062, +31983,35834,21734,27431,40485,27572,34261,21589,20598,27812,21866,36276,29228, +24085,24597,29750,25293,25490,29260,24472,28227,27966,25856,28504,30424,30928, +30460,30036,21028,21467,20051,24222,26049,32810,32982,25243,21638,21032,28846, +34957,36305,27873,21624,32986,22521,35060,36180,38506,37197,20329,27803,21943, +30406,30768,25256,28921,28558,24429,34028,26842,30844,31735,33192,26379,40527, +25447,30896,22383,30738,38713,25209,25259,21128,29749,27607,21860,33086,30130, +30382,21305,30174,20731,23617,35692,31687,20559,29255,39575,39128,28418,29922, +31080,25735,30629,25340,39057,36139,21697,32856,20050,22378,33529,33805,24179, +20973,29942,35780,23631,22369,27900,39047,23110,30772,39748,36843,31893,21078, +25169,38138,20166,33670,33889,33769,33970,22484,26420,22275,26222,28006,35889, +26333,28689,26399,27450,26646,25114,22971,19971,20932,28422,26578,27791,20854, +26827,22855,27495,30054,23822,33040,40784,26071,31048,31041,39569,36215,23682, +20062,20225,21551,22865,30732,22120,27668,36804,24323,27773,27875,35755,25488, +24688,27965,29301,25190,38030,38085,21315,36801,31614,20191,35878,20094,40660, +38065,38067,21069,28508,36963,27973,35892,22545,23884,27424,27465,26538,21595, +33108,32652,22681,34103,24378,25250,27207,38201,25970,24708,26725,30631,20052, +20392,24039,38808,25772,32728,23789,20431,31373,20999,33540,19988,24623,31363, +38054,20405,20146,31206,29748,21220,33465,25810,31165,23517,27777,38738,36731, +27682,20542,21375,28165,25806,26228,27696,24773,39031,35831,24198,29756,31351, +31179,19992,37041,29699,27714,22234,37195,27845,36235,21306,34502,26354,36527, +23624,39537,28192,21462,23094,40843,36259,21435,22280,39079,26435,37275,27849, +20840,30154,25331,29356,21048,21149,32570,28820,30264,21364,40522,27063,30830, +38592,35033,32676,28982,29123,20873,26579,29924,22756,25880,22199,35753,39286, +25200,32469,24825,28909,22764,20161,20154,24525,38887,20219,35748,20995,22922, +32427,25172,20173,26085,25102,33592,33993,33635,34701,29076,28342,23481,32466, +20887,25545,26580,32905,33593,34837,20754,23418,22914,36785,20083,27741,20837, +35109,36719,38446,34122,29790,38160,38384,28070,33509,24369,25746,27922,33832, +33134,40131,22622,36187,19977,21441,20254,25955,26705,21971,20007,25620,39578, +25195,23234,29791,33394,28073,26862,20711,33678,30722,26432,21049,27801,32433, +20667,21861,29022,31579,26194,29642,33515,26441,23665,21024,29053,34923,38378, +38485,25797,36193,33203,21892,27733,25159,32558,22674,20260,21830,36175,26188, +19978,23578,35059,26786,25422,31245,28903,33421,21242,38902,23569,21736,37045, +32461,22882,36170,34503,33292,33293,36198,25668,23556,24913,28041,31038,35774, +30775,30003,21627,20280,36523,28145,23072,32453,31070,27784,23457,23158,29978, +32958,24910,28183,22768,29983,29989,29298,21319,32499,30465,30427,21097,32988, +22307,24072,22833,29422,26045,28287,35799,23608,34417,21313,30707,25342,26102, +20160,39135,34432,23454,35782,21490,30690,20351,23630,39542,22987,24335,31034, +22763,19990,26623,20107,25325,35475,36893,21183,26159,21980,22124,36866,20181, +20365,37322,39280,27663,24066,24643,23460,35270,35797,25910,25163,39318,23432, +23551,25480,21806,21463,30246,20861,34092,26530,26803,27530,25234,36755,21460, +33298,28113,30095,20070,36174,23408,29087,34223,26257,26329,32626,34560,40653, +40736,23646,26415,36848,26641,26463,25101,31446,22661,24246,25968,28465,24661, +21047,32781,25684,34928,29993,24069,26643,25332,38684,21452,29245,35841,27700, +30561,31246,21550,30636,39034,33308,35828,30805,26388,28865,26031,25749,22070, +24605,31169,21496,19997,27515,32902,23546,21987,22235,20282,20284,39282,24051, +26494,32824,24578,39042,36865,23435,35772,35829,25628,33368,25822,22013,33487, +37221,20439,32032,36895,31903,20723,22609,28335,23487,35785,32899,37240,33948, +31639,34429,38539,38543,32485,39635,30862,23681,31319,36930,38567,31071,23385, +25439,31499,34001,26797,21766,32553,29712,32034,38145,25152,22604,20182,23427, +22905,22612,29549,25374,36427,36367,32974,33492,25260,21488,27888,37214,22826, +24577,27760,22349,25674,36138,30251,28393,22363,27264,30192,28525,35885,35848, +22374,27631,34962,30899,25506,21497,28845,27748,22616,25642,22530,26848,33179, +21776,31958,20504,36538,28108,36255,28907,25487,28059,28372,32486,33796,26691, +36867,28120,38518,35752,22871,29305,34276,33150,30140,35466,26799,21076,36386, +38161,25552,39064,36420,21884,20307,26367,22159,24789,28053,21059,23625,22825, +28155,22635,30000,29980,24684,33300,33094,25361,26465,36834,30522,36339,36148, +38081,24086,21381,21548,28867,27712,24311,20572,20141,24237,25402,33351,36890, +26704,37230,30643,21516,38108,24420,31461,26742,25413,31570,32479,30171,20599, +25237,22836,36879,20984,31171,31361,22270,24466,36884,28034,23648,22303,21520, +20820,28237,22242,25512,39059,33151,34581,35114,36864,21534,23663,33216,25302, +25176,33073,40501,38464,39534,39548,26925,22949,25299,21822,25366,21703,34521, +27964,23043,29926,34972,27498,22806,35916,24367,28286,29609,39037,20024,28919, +23436,30871,25405,26202,30358,24779,23451,23113,19975,33109,27754,29579,20129, +26505,32593,24448,26106,26395,24536,22916,23041,24013,24494,21361,38886,36829, +26693,22260,21807,24799,20026,28493,32500,33479,33806,22996,20255,20266,23614, +32428,26410,34074,21619,30031,32963,21890,39759,20301,28205,35859,23561,24944, +21355,30239,28201,34442,25991,38395,32441,21563,31283,32010,38382,21985,32705, +29934,25373,34583,28065,31389,25105,26017,21351,25569,27779,24043,21596,38056, +20044,27745,35820,23627,26080,33436,26791,21566,21556,27595,27494,20116,25410, +21320,33310,20237,20398,22366,25098,38654,26212,29289,21247,21153,24735,35823, +26132,29081,26512,35199,30802,30717,26224,22075,21560,38177,29306,31232,24687, +24076,24713,33181,22805,24796,29060,28911,28330,27728,29312,27268,34989,24109, +20064,23219,21916,38115,27927,31995,38553,25103,32454,30606,34430,21283,38686, +36758,26247,23777,20384,29421,19979,21414,22799,21523,25472,38184,20808,20185, +40092,32420,21688,36132,34900,33335,38386,28046,24358,23244,26174,38505,29616, +29486,21439,33146,39301,32673,23466,38519,38480,32447,30456,21410,38262,39321, +31665,35140,28248,20065,32724,31077,35814,24819,21709,20139,39033,24055,27233, +20687,21521,35937,33831,30813,38660,21066,21742,22179,38144,28040,23477,28102, +26195,23567,23389,26657,32918,21880,31505,25928,26964,20123,27463,34638,38795, +21327,25375,25658,37034,26012,32961,35856,20889,26800,21368,34809,25032,27844, +27899,35874,23633,34218,33455,38156,27427,36763,26032,24571,24515,20449,34885, +26143,33125,29481,24826,20852,21009,22411,24418,37026,34892,37266,24184,26447, +24615,22995,20804,20982,33016,21256,27769,38596,29066,20241,20462,32670,26429, +21957,38152,31168,34966,32483,22687,25100,38656,34394,22040,39035,24464,35768, +33988,37207,21465,26093,24207,30044,24676,32110,23167,32490,32493,36713,21927, +23459,24748,26059,29572,36873,30307,30505,32474,38772,34203,23398,31348,38634, +34880,21195,29071,24490,26092,35810,23547,39535,24033,27529,27739,35757,35759, +36874,36805,21387,25276,40486,40493,21568,20011,33469,29273,34460,23830,34905, +28079,38597,21713,20122,35766,28937,21693,38409,28895,28153,30416,20005,30740, +34578,23721,24310,35328,39068,38414,28814,27839,22852,25513,30524,34893,28436, +33395,22576,29141,21388,30746,38593,21761,24422,28976,23476,35866,39564,27523, +22830,40495,31207,26472,25196,20335,30113,32650,27915,38451,27687,20208,30162, +20859,26679,28478,36992,33136,22934,29814,25671,23591,36965,31377,35875,23002, +21676,33280,33647,35201,32768,26928,22094,32822,29239,37326,20918,20063,39029, +25494,19994,21494,26355,33099,22812,28082,19968,22777,21307,25558,38129,20381, +20234,34915,39056,22839,36951,31227,20202,33008,30097,27778,23452,23016,24413, +26885,34433,20506,24050,20057,30691,20197,33402,25233,26131,37009,23673,20159, +24441,33222,36920,32900,30123,20134,35028,24847,27589,24518,20041,30410,28322, +35811,35758,35850,35793,24322,32764,32716,32462,33589,33643,22240,27575,38899, +38452,23035,21535,38134,28139,23493,39278,23609,24341,38544,21360,33521,27185, +23156,40560,24212,32552,33721,33828,33829,33639,34631,36814,36194,30408,24433, +39062,30828,26144,21727,25317,20323,33219,30152,24248,38605,36362,34553,21647, +27891,28044,27704,24703,21191,29992,24189,20248,24736,24551,23588,30001,37038, +38080,29369,27833,28216,37193,26377,21451,21491,20305,37321,35825,21448,24188, +36802,28132,20110,30402,27014,34398,24858,33286,20313,20446,36926,40060,24841, +28189,28180,38533,20104,23089,38632,19982,23679,31161,23431,35821,32701,29577, +22495,33419,37057,21505,36935,21947,23786,24481,24840,27442,29425,32946,35465, +28020,23507,35029,39044,35947,39533,40499,28170,20900,20803,22435,34945,21407, +25588,36757,22253,21592,22278,29503,28304,32536,36828,33489,24895,24616,38498, +26352,32422,36234,36291,38053,23731,31908,26376,24742,38405,32792,20113,37095, +21248,38504,20801,36816,34164,37213,26197,38901,23381,21277,30776,26434,26685, +21705,28798,23472,36733,20877,22312,21681,25874,26242,36190,36163,33039,33900, +36973,31967,20991,34299,26531,26089,28577,34468,36481,22122,36896,30338,28790, +29157,36131,25321,21017,27901,36156,24590,22686,24974,26366,36192,25166,21939, +28195,26413,36711,38113,38392,30504,26629,27048,21643,20045,28856,35784,25688, +25995,23429,31364,20538,23528,30651,27617,35449,31896,27838,30415,26025,36759, +23853,23637,34360,26632,21344,25112,31449,28251,32509,27167,31456,24432,28467, +24352,25484,28072,26454,19976,24080,36134,20183,32960,30260,38556,25307,26157, +25214,27836,36213,29031,32617,20806,32903,21484,36974,25240,21746,34544,36761, +32773,38167,34071,36825,27993,29645,26015,30495,29956,30759,33275,36126,38024, +20390,26517,30137,35786,38663,25391,38215,38453,33976,25379,30529,24449,29424, +20105,24596,25972,25327,27491,25919,24103,30151,37073,35777,33437,26525,25903, +21553,34584,30693,32930,33026,27713,20043,32455,32844,30452,26893,27542,25191, +20540,20356,22336,25351,27490,36286,21482,26088,32440,24535,25370,25527,33267, +33268,32622,24092,23769,21046,26234,31209,31258,36136,28825,30164,28382,27835, +31378,20013,30405,24544,38047,34935,32456,31181,32959,37325,20210,20247,33311, +21608,24030,27954,35788,31909,36724,32920,24090,21650,30385,23449,26172,39588, +29664,26666,34523,26417,29482,35832,35803,36880,31481,28891,29038,25284,30633, +22065,20027,33879,26609,21161,34496,36142,38136,31569,20303,27880,31069,39547, +25235,29226,25341,19987,30742,36716,25776,36186,31686,26729,24196,35013,22918, +25758,22766,29366,26894,38181,36861,36184,22368,32512,35846,20934,25417,25305, +21331,26700,29730,33537,37196,21828,30528,28796,27978,20857,21672,36164,23039, +28363,28100,23388,32043,20180,31869,28371,23376,33258,28173,23383,39683,26837, +36394,23447,32508,24635,32437,37049,36208,22863,25549,31199,36275,21330,26063, +31062,35781,38459,32452,38075,32386,22068,37257,26368,32618,23562,36981,26152, +24038,20304,26590,20570,20316,22352,24231,20109,19980,20800,19984,24319,21317, +19989,20120,19998,39730,23404,22121,20008,31162,20031,21269,20039,22829,29243, +21358,27664,22239,32996,39319,27603,30590,40727,20022,20127,40720,20060,20073, +20115,33416,23387,21868,22031,20164,21389,21405,21411,21413,21422,38757,36189, +21274,21493,21286,21294,21310,36188,21350,21347,20994,21000,21006,21037,21043, +21055,21056,21068,21086,21089,21084,33967,21117,21122,21121,21136,21139,20866, +32596,20155,20163,20169,20162,20200,20193,20203,20190,20251,20211,20258,20324, +20213,20261,20263,20233,20267,20318,20327,25912,20314,20317,20319,20311,20274, +20285,20342,20340,20369,20361,20355,20367,20350,20347,20394,20348,20396,20372, +20454,20456,20458,20421,20442,20451,20444,20433,20447,20472,20521,20556,20467, +20524,20495,20526,20525,20478,20508,20492,20517,20520,20606,20547,20565,20552, +20558,20588,20603,20645,20647,20649,20666,20694,20742,20717,20716,20710,20718, +20743,20747,20189,27709,20312,20325,20430,40864,27718,31860,20846,24061,40649, +39320,20865,22804,21241,21261,35335,21264,20971,22809,20821,20128,20822,20147, +34926,34980,20149,33044,35026,31104,23348,34819,32696,20907,20913,20925,20924, +20935,20886,20898,20901,35744,35750,35751,35754,35764,35765,35767,35778,35779, +35787,35791,35790,35794,35795,35796,35798,35800,35801,35804,35807,35808,35812, +35816,35817,35822,35824,35827,35830,35833,35836,35839,35840,35842,35844,35847, +35852,35855,35857,35858,35860,35861,35862,35865,35867,35864,35869,35871,35872, +35873,35877,35879,35882,35883,35886,35887,35890,35891,35893,35894,21353,21370, +38429,38434,38433,38449,38442,38461,38460,38466,38473,38484,38495,38503,38508, +38514,38516,38536,38541,38551,38576,37015,37019,37021,37017,37036,37025,37044, +37043,37046,37050,37048,37040,37071,37061,37054,37072,37060,37063,37075,37094, +37090,37084,37079,37083,37099,37103,37118,37124,37154,37150,37155,37169,37167, +37177,37187,37190,21005,22850,21154,21164,21165,21182,21759,21200,21206,21232, +21471,29166,30669,24308,20981,20988,39727,21430,24321,30042,24047,22348,22441, +22433,22654,22716,22725,22737,22313,22316,22314,22323,22329,22318,22319,22364, +22331,22338,22377,22405,22379,22406,22396,22395,22376,22381,22390,22387,22445, +22436,22412,22450,22479,22439,22452,22419,22432,22485,22488,22490,22489,22482, +22456,22516,22511,22520,22500,22493,22539,22541,22525,22509,22528,22558,22553, +22596,22560,22629,22636,22657,22665,22682,22656,39336,40729,25087,33401,33405, +33407,33423,33418,33448,33412,33422,33425,33431,33433,33451,33464,33470,33456, +33480,33482,33507,33432,33463,33454,33483,33484,33473,33449,33460,33441,33450, +33439,33476,33486,33444,33505,33545,33527,33508,33551,33543,33500,33524,33490, +33496,33548,33531,33491,33553,33562,33542,33556,33557,33504,33493,33564,33617, +33627,33628,33544,33682,33596,33588,33585,33691,33630,33583,33615,33607,33603, +33631,33600,33559,33632,33581,33594,33587,33638,33637,33640,33563,33641,33644, +33642,33645,33646,33712,33656,33715,33716,33696,33706,33683,33692,33669,33660, +33718,33705,33661,33720,33659,33688,33694,33704,33722,33724,33729,33793,33765, +33752,22535,33816,33803,33757,33789,33750,33820,33848,33809,33798,33748,33759, +33807,33795,33784,33785,33770,33733,33728,33830,33776,33761,33884,33873,33882, +33881,33907,33927,33928,33914,33929,33912,33852,33862,33897,33910,33932,33934, +33841,33901,33985,33997,34000,34022,33981,34003,33994,33983,33978,34016,33953, +33977,33972,33943,34021,34019,34060,29965,34104,34032,34105,34079,34106,34134, +34107,34047,34044,34137,34120,34152,34148,34142,34170,30626,34115,34162,34171, +34212,34216,34183,34191,34169,34222,34204,34181,34233,34231,34224,34259,34241, +34268,34303,34343,34309,34345,34326,34364,24318,24328,22844,22849,32823,22869, +22874,22872,21263,23586,23589,23596,23604,25164,25194,25247,25275,25290,25306, +25303,25326,25378,25334,25401,25419,25411,25517,25590,25457,25466,25486,25524, +25453,25516,25482,25449,25518,25532,25586,25592,25568,25599,25540,25566,25550, +25682,25542,25534,25669,25665,25611,25627,25632,25612,25638,25633,25694,25732, +25709,25750,25722,25783,25784,25753,25786,25792,25808,25815,25828,25826,25865, +25893,25902,24331,24530,29977,24337,21343,21489,21501,21481,21480,21499,21522, +21526,21510,21579,21586,21587,21588,21590,21571,21537,21591,21593,21539,21554, +21634,21652,21623,21617,21604,21658,21659,21636,21622,21606,21661,21712,21677, +21698,21684,21714,21671,21670,21715,21716,21618,21667,21717,21691,21695,21708, +21721,21722,21724,21673,21674,21668,21725,21711,21726,21787,21735,21792,21757, +21780,21747,21794,21795,21775,21777,21799,21802,21863,21903,21941,21833,21869, +21825,21845,21823,21840,21820,21815,21846,21877,21878,21879,21811,21808,21852, +21899,21970,21891,21937,21945,21896,21889,21919,21886,21974,21905,21883,21983, +21949,21950,21908,21913,21994,22007,21961,22047,21969,21995,21996,21972,21990, +21981,21956,21999,21989,22002,22003,21964,21965,21992,22005,21988,36756,22046, +22024,22028,22017,22052,22051,22014,22016,22055,22061,22104,22073,22103,22060, +22093,22114,22105,22108,22092,22100,22150,22116,22129,22123,22139,22140,22149, +22163,22191,22228,22231,22237,22241,22261,22251,22265,22271,22276,22282,22281, +22300,24079,24089,24084,24081,24113,24123,24124,24119,24132,24148,24155,24158, +24161,23692,23674,23693,23696,23702,23688,23704,23705,23697,23706,23708,23733, +23714,23741,23724,23723,23729,23715,23745,23735,23748,23762,23780,23755,23781, +23810,23811,23847,23846,23854,23844,23838,23814,23835,23896,23870,23860,23869, +23916,23899,23919,23901,23915,23883,23882,23913,23924,23938,23961,23965,35955, +23991,24005,24435,24439,24450,24455,24457,24460,24469,24473,24476,24488,24493, +24501,24508,34914,24417,29357,29360,29364,29367,29368,29379,29377,29390,29389, +29394,29416,29423,29417,29426,29428,29431,29441,29427,29443,29434,29435,29463, +29459,29473,29450,29470,29469,29461,29474,29497,29477,29484,29496,29489,29520, +29517,29527,29536,29548,29551,29566,33307,22821,39143,22820,22786,39267,39271, +39272,39273,39274,39275,39276,39284,39287,39293,39296,39300,39303,39306,39309, +39312,39313,39315,39316,39317,24192,24209,24203,24214,24229,24224,24249,24245, +24254,24243,36179,24274,24273,24283,24296,24298,33210,24516,24521,24534,24527, +24579,24558,24580,24545,24548,24574,24581,24582,24554,24557,24568,24601,24629, +24614,24603,24591,24589,24617,24619,24586,24639,24609,24696,24697,24699,24698, +24642,24682,24701,24726,24730,24749,24733,24707,24722,24716,24731,24812,24763, +24753,24797,24792,24774,24794,24756,24864,24870,24853,24867,24820,24832,24846, +24875,24906,24949,25004,24980,24999,25015,25044,25077,24541,38579,38377,38379, +38385,38387,38389,38390,38396,38398,38403,38404,38406,38408,38410,38411,38412, +38413,38415,38418,38421,38422,38423,38425,38426,20012,29247,25109,27701,27732, +27740,27722,27811,27781,27792,27796,27788,27752,27753,27764,27766,27782,27817, +27856,27860,27821,27895,27896,27889,27863,27826,27872,27862,27898,27883,27886, +27825,27859,27887,27902,27961,27943,27916,27971,27976,27911,27908,27929,27918, +27947,27981,27950,27957,27930,27983,27986,27988,27955,28049,28015,28062,28064, +27998,28051,28052,27996,28000,28028,28003,28186,28103,28101,28126,28174,28095, +28128,28177,28134,28125,28121,28182,28075,28172,28078,28203,28270,28238,28267, +28338,28255,28294,28243,28244,28210,28197,28228,28383,28337,28312,28384,28461, +28386,28325,28327,28349,28347,28343,28375,28340,28367,28303,28354,28319,28514, +28486,28487,28452,28437,28409,28463,28470,28491,28532,28458,28425,28457,28553, +28557,28556,28536,28530,28540,28538,28625,28617,28583,28601,28598,28610,28641, +28654,28638,28640,28655,28698,28707,28699,28729,28725,28751,28766,23424,23428, +23445,23443,23461,23480,29999,39582,25652,23524,23534,35120,23536,36423,35591, +36790,36819,36821,36837,36846,36836,36841,36838,36851,36840,36869,36868,36875, +36902,36881,36877,36886,36897,36917,36918,36909,36911,36932,36945,36946,36944, +36968,36952,36962,36955,26297,36980,36989,36994,37000,36995,37003,24400,24407, +24406,24408,23611,21675,23632,23641,23409,23651,23654,32700,24362,24361,24365, +33396,24380,39739,23662,22913,22915,22925,22953,22954,22947,22935,22986,22955, +22942,22948,22994,22962,22959,22999,22974,23045,23046,23005,23048,23011,23000, +23033,23052,23049,23090,23092,23057,23075,23059,23104,23143,23114,23125,23100, +23138,23157,33004,23210,23195,23159,23162,23230,23275,23218,23250,23252,23224, +23264,23267,23281,23254,23270,23256,23260,23305,23319,23318,23346,23351,23360, +23573,23580,23386,23397,23411,23377,23379,23394,39541,39543,39544,39546,39551, +39549,39552,39553,39557,39560,39562,39568,39570,39571,39574,39576,39579,39580, +39581,39583,39584,39586,39587,39589,39591,32415,32417,32419,32421,32424,32425, +32429,32432,32446,32448,32449,32450,32457,32459,32460,32464,32468,32471,32475, +32480,32481,32488,32491,32494,32495,32497,32498,32525,32502,32506,32507,32510, +32513,32514,32515,32519,32520,32523,32524,32527,32529,32530,32535,32537,32540, +32539,32543,32545,32546,32547,32548,32549,32550,32551,32554,32555,32556,32557, +32559,32560,32561,32562,32563,32565,24186,30079,24027,30014,37013,29582,29585, +29614,29602,29599,29647,29634,29649,29623,29619,29632,29641,29640,29669,29657, +39036,29706,29673,29671,29662,29626,29682,29711,29738,29787,29734,29733,29736, +29744,29742,29740,29723,29722,29761,29788,29783,29781,29785,29815,29805,29822, +29852,29838,29824,29825,29831,29835,29854,29864,29865,29840,29863,29906,29882, +38890,38891,38892,26444,26451,26462,26440,26473,26533,26503,26474,26483,26520, +26535,26485,26536,26526,26541,26507,26487,26492,26608,26633,26584,26634,26601, +26544,26636,26585,26549,26586,26547,26589,26624,26563,26552,26594,26638,26561, +26621,26674,26675,26720,26721,26702,26722,26692,26724,26755,26653,26709,26726, +26689,26727,26688,26686,26698,26697,26665,26805,26767,26740,26743,26771,26731, +26818,26990,26876,26911,26912,26873,26916,26864,26891,26881,26967,26851,26896, +26993,26937,26976,26946,26973,27012,26987,27008,27032,27000,26932,27084,27015, +27016,27086,27017,26982,26979,27001,27035,27047,27067,27051,27053,27092,27057, +27073,27082,27103,27029,27104,27021,27135,27183,27117,27159,27160,27237,27122, +27204,27198,27296,27216,27227,27189,27278,27257,27197,27176,27224,27260,27281, +27280,27305,27287,27307,29495,29522,27521,27522,27527,27524,27538,27539,27533, +27546,27547,27553,27562,36715,36717,36721,36722,36723,36725,36726,36728,36727, +36729,36730,36732,36734,36737,36738,36740,36743,36747,36749,36750,36751,36760, +36762,36558,25099,25111,25115,25119,25122,25121,25125,25124,25132,33255,29935, +29940,29951,29967,29969,29971,25908,26094,26095,26096,26122,26137,26482,26115, +26133,26112,28805,26359,26141,26164,26161,26166,26165,32774,26207,26196,26177, +26191,26198,26209,26199,26231,26244,26252,26279,26269,26302,26331,26332,26342, +26345,36146,36147,36150,36155,36157,36160,36165,36166,36168,36169,36167,36173, +36181,36185,35271,35274,35275,35276,35278,35279,35280,35281,29294,29343,29277, +29286,29295,29310,29311,29316,29323,29325,29327,29330,25352,25394,25520,25663, +25816,32772,27626,27635,27645,27637,27641,27653,27655,27654,27661,27669,27672, +27673,27674,27681,27689,27684,27690,27698,25909,25941,25963,29261,29266,29270, +29232,34402,21014,32927,32924,32915,32956,26378,32957,32945,32939,32941,32948, +32951,32999,33000,33001,33002,32987,32962,32964,32985,32973,32983,26384,32989, +33003,33009,33012,33005,33037,33038,33010,33020,26389,33042,35930,33078,33054, +33068,33048,33074,33096,33100,33107,33140,33113,33114,33137,33120,33129,33148, +33149,33133,33127,22605,23221,33160,33154,33169,28373,33187,33194,33228,26406, +33226,33211,33217,33190,27428,27447,27449,27459,27462,27481,39121,39122,39123, +39125,39129,39130,27571,24384,27586,35315,26000,40785,26003,26044,26054,26052, +26051,26060,26062,26066,26070,28800,28828,28822,28829,28859,28864,28855,28843, +28849,28904,28874,28944,28947,28950,28975,28977,29043,29020,29032,28997,29042, +29002,29048,29050,29080,29107,29109,29096,29088,29152,29140,29159,29177,29213, +29224,28780,28952,29030,29113,25150,25149,25155,25160,25161,31035,31040,31046, +31049,31067,31068,31059,31066,31074,31063,31072,31087,31079,31098,31109,31114, +31130,31143,31155,24529,24528,24636,24669,24666,24679,24641,24665,24675,24747, +24838,24845,24925,25001,24989,25035,25041,25094,32896,32895,27795,27894,28156, +30710,30712,30720,30729,30743,30744,30737,26027,30765,30748,30749,30777,30778, +30779,30751,30780,30757,30764,30755,30761,30798,30829,30806,30807,30758,30800, +30791,30796,30826,30875,30867,30874,30855,30876,30881,30883,30898,30905,30885, +30932,30937,30921,30956,30962,30981,30964,30995,31012,31006,31028,40859,40697, +40699,40700,30449,30468,30477,30457,30471,30472,30490,30498,30489,30509,30502, +30517,30520,30544,30545,30535,30531,30554,30568,30562,30565,30591,30605,30589, +30592,30604,30609,30623,30624,30640,30645,30653,30010,30016,30030,30027,30024, +30043,30066,30073,30083,32600,32609,32607,35400,32616,32628,32625,32633,32641, +32638,30413,30437,34866,38021,38022,38023,38027,38026,38028,38029,38031,38032, +38036,38039,38037,38042,38043,38044,38051,38052,38059,38058,38061,38060,38063, +38064,38066,38068,38070,38071,38072,38073,38074,38076,38077,38079,38084,38088, +38089,38090,38091,38092,38093,38094,38096,38097,38098,38101,38102,38103,38105, +38104,38107,38110,38111,38112,38114,38116,38117,38119,38120,38122,38121,38123, +38126,38127,38131,38132,38133,38135,38137,38140,38141,38143,38147,38146,38150, +38151,38153,38154,38157,38158,38159,38162,38163,38164,38165,38166,38168,38171, +38173,38174,38175,38178,38186,38187,38185,38188,38193,38194,38196,38198,38199, +38200,38204,38206,38207,38210,38197,38212,38213,38214,38217,38220,38222,38223, +38226,38227,38228,38230,38231,38232,38233,38235,38238,38239,38237,38241,38242, +38244,38245,38246,38247,38248,38249,38250,38251,38252,38255,38257,38258,38259, +38202,30695,30700,38601,31189,31213,31203,31211,31238,23879,31235,31234,31262, +31252,31289,31287,31313,40655,39333,31344,30344,30350,30355,30361,30372,29918, +29920,29996,40480,40482,40488,40489,40490,40491,40492,40498,40497,40502,40504, +40503,40505,40506,40510,40513,40514,40516,40518,40519,40520,40521,40523,40524, +40526,40529,40533,40535,40538,40539,40540,40542,40547,40550,40551,40552,40553, +40554,40555,40556,40561,40557,40563,30098,30100,30102,30112,30109,30124,30115, +30131,30132,30136,30148,30129,30128,30147,30146,30166,30157,30179,30184,30182, +30180,30187,30183,30211,30193,30204,30207,30224,30208,30213,30220,30231,30218, +30245,30232,30229,30233,30235,30268,30242,30240,30272,30253,30256,30271,30261, +30275,30270,30259,30285,30302,30292,30300,30294,30315,30319,32714,31462,31352, +31353,31360,31366,31368,31381,31398,31392,31404,31400,31405,31411,34916,34921, +34930,34941,34943,34946,34978,35014,34999,35004,35017,35042,35022,35043,35045, +35057,35098,35068,35048,35070,35056,35105,35097,35091,35099,35082,35124,35115, +35126,35137,35174,35195,30091,32997,30386,30388,30684,32786,32788,32790,32796, +32800,32802,32805,32806,32807,32809,32808,32817,32779,32821,32835,32838,32845, +32850,32873,32881,35203,39032,39040,39043,39049,39052,39053,39055,39060,39066, +39067,39070,39071,39073,39074,39077,39078,34381,34388,34412,34414,34431,34426, +34428,34427,34472,34445,34443,34476,34461,34471,34467,34474,34451,34473,34486, +34500,34485,34510,34480,34490,34481,34479,34505,34511,34484,34537,34545,34546, +34541,34547,34512,34579,34526,34548,34527,34520,34513,34563,34567,34552,34568, +34570,34573,34569,34595,34619,34590,34597,34606,34586,34622,34632,34612,34609, +34601,34615,34623,34690,34594,34685,34686,34683,34656,34672,34636,34670,34699, +34643,34659,34684,34660,34649,34661,34707,34735,34728,34770,34758,34696,34693, +34733,34711,34691,34731,34789,34732,34741,34739,34763,34771,34749,34769,34752, +34762,34779,34794,34784,34798,34838,34835,34814,34826,34843,34849,34873,34876, +32566,32578,32580,32581,33296,31482,31485,31496,31491,31492,31509,31498,31531, +31503,31559,31544,31530,31513,31534,31537,31520,31525,31524,31539,31550,31518, +31576,31578,31557,31605,31564,31581,31584,31598,31611,31586,31602,31601,31632, +31654,31655,31672,31660,31645,31656,31621,31658,31644,31650,31659,31668,31697, +31681,31692,31709,31706,31717,31718,31722,31756,31742,31740,31759,31766,31755, +31775,31786,31782,31800,31809,31808,33278,33281,33282,33284,33260,34884,33313, +33314,33315,33325,33327,33320,33323,33336,33339,33331,33332,33342,33348,33353, +33355,33359,33370,33375,33384,34942,34949,34952,35032,35039,35166,32669,32671, +32679,32687,32688,32690,31868,25929,31889,31901,31900,31902,31906,31922,31932, +31933,31937,31943,31948,31949,31944,31941,31959,31976,33390,26280,32703,32718, +32725,32741,32737,32742,32745,32750,32755,31992,32119,32166,32174,32327,32411, +40632,40628,36211,36228,36244,36241,36273,36199,36205,35911,35913,37194,37200, +37198,37199,37220,37218,37217,37232,37225,37231,37245,37246,37234,37236,37241, +37260,37253,37264,37261,37265,37282,37283,37290,37293,37294,37295,37301,37300, +37306,35925,40574,36280,36331,36357,36441,36457,36277,36287,36284,36282,36292, +36310,36311,36314,36318,36302,36303,36315,36294,36332,36343,36344,36323,36345, +36347,36324,36361,36349,36372,36381,36383,36396,36398,36387,36399,36410,36416, +36409,36405,36413,36401,36425,36417,36418,36433,36434,36426,36464,36470,36476, +36463,36468,36485,36495,36500,36496,36508,36510,35960,35970,35978,35973,35992, +35988,26011,35286,35294,35290,35292,35301,35307,35311,35390,35622,38739,38633, +38643,38639,38662,38657,38664,38671,38670,38698,38701,38704,38718,40832,40835, +40837,40838,40839,40840,40841,40842,40844,40702,40715,40717,38585,38588,38589, +38606,38610,30655,38624,37518,37550,37576,37694,37738,37834,37775,37950,37995, +40063,40066,40069,40070,40071,40072,31267,40075,40078,40080,40081,40082,40084, +40085,40090,40091,40094,40095,40096,40097,40098,40099,40101,40102,40103,40104, +40105,40107,40109,40110,40112,40113,40114,40115,40116,40117,40118,40119,40122, +40123,40124,40125,40132,40133,40134,40135,40138,40139,40140,40141,40142,40143, +40144,40147,40148,40149,40151,40152,40153,40156,40157,40159,40162,38780,38789, +38801,38802,38804,38831,38827,38819,38834,38836,39601,39600,39607,40536,39606, +39610,39612,39617,39616,39621,39618,39627,39628,39633,39749,39747,39751,39753, +39752,39757,39761,39144,39181,39214,39253,39252,39647,39649,39654,39663,39659, +39675,39661,39673,39688,39695,39699,39711,39715,40637,40638,32315,40578,40583, +40584,40587,40594,37846,40605,40607,40667,40668,40669,40672,40671,40674,40681, +40679,40677,40682,40687,40738,40748,40751,40761,40759,40765,40766,40772, +}; + +static const struct dbcs_index gb2312_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb2312_decmap+0,33,126},{__gb2312_decmap+94, +49,124},{__gb2312_decmap+170,33,126},{__gb2312_decmap+264,33,115},{ +__gb2312_decmap+347,33,118},{__gb2312_decmap+433,33,88},{__gb2312_decmap+489, +33,113},{__gb2312_decmap+570,33,105},{__gb2312_decmap+643,36,111},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb2312_decmap+719,33,126},{ +__gb2312_decmap+813,33,126},{__gb2312_decmap+907,33,126},{__gb2312_decmap+1001 +,33,126},{__gb2312_decmap+1095,33,126},{__gb2312_decmap+1189,33,126},{ +__gb2312_decmap+1283,33,126},{__gb2312_decmap+1377,33,126},{__gb2312_decmap+ +1471,33,126},{__gb2312_decmap+1565,33,126},{__gb2312_decmap+1659,33,126},{ +__gb2312_decmap+1753,33,126},{__gb2312_decmap+1847,33,126},{__gb2312_decmap+ +1941,33,126},{__gb2312_decmap+2035,33,126},{__gb2312_decmap+2129,33,126},{ +__gb2312_decmap+2223,33,126},{__gb2312_decmap+2317,33,126},{__gb2312_decmap+ +2411,33,126},{__gb2312_decmap+2505,33,126},{__gb2312_decmap+2599,33,126},{ +__gb2312_decmap+2693,33,126},{__gb2312_decmap+2787,33,126},{__gb2312_decmap+ +2881,33,126},{__gb2312_decmap+2975,33,126},{__gb2312_decmap+3069,33,126},{ +__gb2312_decmap+3163,33,126},{__gb2312_decmap+3257,33,126},{__gb2312_decmap+ +3351,33,126},{__gb2312_decmap+3445,33,126},{__gb2312_decmap+3539,33,126},{ +__gb2312_decmap+3633,33,126},{__gb2312_decmap+3727,33,126},{__gb2312_decmap+ +3821,33,126},{__gb2312_decmap+3915,33,126},{__gb2312_decmap+4009,33,126},{ +__gb2312_decmap+4103,33,126},{__gb2312_decmap+4197,33,126},{__gb2312_decmap+ +4291,33,126},{__gb2312_decmap+4385,33,121},{__gb2312_decmap+4474,33,126},{ +__gb2312_decmap+4568,33,126},{__gb2312_decmap+4662,33,126},{__gb2312_decmap+ +4756,33,126},{__gb2312_decmap+4850,33,126},{__gb2312_decmap+4944,33,126},{ +__gb2312_decmap+5038,33,126},{__gb2312_decmap+5132,33,126},{__gb2312_decmap+ +5226,33,126},{__gb2312_decmap+5320,33,126},{__gb2312_decmap+5414,33,126},{ +__gb2312_decmap+5508,33,126},{__gb2312_decmap+5602,33,126},{__gb2312_decmap+ +5696,33,126},{__gb2312_decmap+5790,33,126},{__gb2312_decmap+5884,33,126},{ +__gb2312_decmap+5978,33,126},{__gb2312_decmap+6072,33,126},{__gb2312_decmap+ +6166,33,126},{__gb2312_decmap+6260,33,126},{__gb2312_decmap+6354,33,126},{ +__gb2312_decmap+6448,33,126},{__gb2312_decmap+6542,33,126},{__gb2312_decmap+ +6636,33,126},{__gb2312_decmap+6730,33,126},{__gb2312_decmap+6824,33,126},{ +__gb2312_decmap+6918,33,126},{__gb2312_decmap+7012,33,126},{__gb2312_decmap+ +7106,33,126},{__gb2312_decmap+7200,33,126},{__gb2312_decmap+7294,33,126},{ +__gb2312_decmap+7388,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const ucs2_t __gbkext_decmap[14531] = { +19970,19972,19973,19974,19983,19986,19991,19999,20000,20001,20003,20006,20009, +20014,20015,20017,20019,20021,20023,20028,20032,20033,20034,20036,20038,20042, +20049,20053,20055,20058,20059,20066,20067,20068,20069,20071,20072,20074,20075, +20076,20077,20078,20079,20082,20084,20085,20086,20087,20088,20089,20090,20091, +20092,20093,20095,20096,20097,20098,20099,20100,20101,20103,20106,U,20112, +20118,20119,20121,20124,20125,20126,20131,20138,20143,20144,20145,20148,20150, +20151,20152,20153,20156,20157,20158,20168,20172,20175,20176,20178,20186,20187, +20188,20192,20194,20198,20199,20201,20205,20206,20207,20209,20212,20216,20217, +20218,20220,20222,20224,20226,20227,20228,20229,20230,20231,20232,20235,20236, +20242,20243,20244,20245,20246,20252,20253,20257,20259,20264,20265,20268,20269, +20270,20273,20275,20277,20279,20281,20283,20286,20287,20288,20289,20290,20292, +20293,20295,20296,20297,20298,20299,20300,20306,20308,20310,20321,20322,20326, +20328,20330,20331,20333,20334,20337,20338,20341,20343,20344,20345,20346,20349, +20352,20353,20354,20357,20358,20359,20362,20364,20366,20368,20370,20371,20373, +20374,20376,20377,20378,20380,20382,20383,20385,20386,20388,20395,20397,20400, +20401,20402,20403,20404,20406,20407,20408,20409,20410,20411,20412,20413,20414, +20416,20417,20418,20422,20423,20424,20425,20427,20428,20429,20434,20435,20436, +20437,20438,20441,20443,20448,20450,20452,20453,20455,20459,20460,20464,20466, +20468,20469,20470,20471,20473,20475,20476,20477,20479,20480,20481,20482,20483, +20484,20485,20486,20487,20488,20489,20490,U,20491,20494,20496,20497,20499, +20501,20502,20503,20507,20509,20510,20512,20514,20515,20516,20519,20523,20527, +20528,20529,20530,20531,20532,20533,20534,20535,20536,20537,20539,20541,20543, +20544,20545,20546,20548,20549,20550,20553,20554,20555,20557,20560,20561,20562, +20563,20564,20566,20567,20568,20569,20571,20573,20574,20575,20576,20577,20578, +20579,20580,20582,20583,20584,20585,20586,20587,20589,20590,20591,20592,20593, +20594,20595,20596,20597,20600,20601,20602,20604,20605,20609,20610,20611,20612, +20614,20615,20617,20618,20619,20620,20622,20623,20624,20625,20626,20627,20628, +20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641, +20642,20644,20646,20650,20651,20653,20654,20655,20656,20657,20659,20660,20661, +20662,20663,20664,20665,20668,20669,20670,20671,20672,20673,20674,20675,20676, +20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,20688,20689,20690, +20691,20692,20693,20695,20696,20697,20699,20700,20701,20702,20703,20704,20705, +20706,20707,20708,20709,20712,20713,20714,20715,20719,20720,20721,20722,20724, +20726,20727,20728,20729,20730,20732,20733,20734,20735,20736,20737,20738,20739, +20740,20741,20744,U,20745,20746,20748,20749,20750,20751,20752,20753,20755, +20756,20757,20758,20759,20760,20761,20762,20763,20764,20765,20766,20767,20768, +20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782, +20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,20795, +20796,20797,20798,20802,20807,20810,20812,20814,20815,20816,20818,20819,20823, +20824,20825,20827,20829,20830,20831,20832,20833,20835,20836,20838,20839,20841, +20842,20847,20850,20858,20862,20863,20867,20868,20870,20871,20874,20875,20878, +20879,20880,20881,20883,20884,20888,20890,20893,20894,20895,20897,20899,20902, +20903,20904,20905,20906,20909,20910,20916,20920,20921,20922,20926,20927,20929, +20930,20931,20933,20936,20938,20941,20942,20944,20946,20947,20948,20949,20950, +20951,20952,20953,20954,20956,20958,20959,20962,20963,20965,20966,20967,20968, +20969,20970,20972,20974,20977,20978,20980,20983,20990,20996,20997,21001,21003, +21004,21007,21008,21011,21012,21013,21020,21022,21023,21025,21026,21027,21029, +21030,21031,21034,21036,21039,21041,21042,21044,21045,21052,21054,21060,21061, +21062,21063,21064,21065,21067,21070,21071,21074,21075,21077,21079,21080,U, +21081,21082,21083,21085,21087,21088,21090,21091,21092,21094,21096,21099,21100, +21101,21102,21104,21105,21107,21108,21109,21110,21111,21112,21113,21114,21115, +21116,21118,21120,21123,21124,21125,21126,21127,21129,21130,21131,21132,21133, +21134,21135,21137,21138,21140,21141,21142,21143,21144,21145,21146,21148,21156, +21157,21158,21159,21166,21167,21168,21172,21173,21174,21175,21176,21177,21178, +21179,21180,21181,21184,21185,21186,21188,21189,21190,21192,21194,21196,21197, +21198,21199,21201,21203,21204,21205,21207,21209,21210,21211,21212,21213,21214, +21216,21217,21218,21219,21221,21222,21223,21224,21225,21226,21227,21228,21229, +21230,21231,21233,21234,21235,21236,21237,21238,21239,21240,21243,21244,21245, +21249,21250,21251,21252,21255,21257,21258,21259,21260,21262,21265,21266,21267, +21268,21272,21275,21276,21278,21279,21282,21284,21285,21287,21288,21289,21291, +21292,21293,21295,21296,21297,21298,21299,21300,21301,21302,21303,21304,21308, +21309,21312,21314,21316,21318,21323,21324,21325,21328,21332,21336,21337,21339, +21341,21349,21352,21354,21356,21357,21362,21366,21369,21371,21372,21373,21374, +21376,21377,21379,21383,21384,21386,21390,21391,U,21392,21393,21394,21395, +21396,21398,21399,21401,21403,21404,21406,21408,21409,21412,21415,21418,21419, +21420,21421,21423,21424,21425,21426,21427,21428,21429,21431,21432,21433,21434, +21436,21437,21438,21440,21443,21444,21445,21446,21447,21454,21455,21456,21458, +21459,21461,21466,21468,21469,21470,21473,21474,21479,21492,21498,21502,21503, +21504,21506,21509,21511,21515,21524,21528,21529,21530,21532,21538,21540,21541, +21546,21552,21555,21558,21559,21562,21565,21567,21569,21570,21572,21573,21575, +21577,21580,21581,21582,21583,21585,21594,21597,21598,21599,21600,21601,21603, +21605,21607,21609,21610,21611,21612,21613,21614,21615,21616,21620,21625,21626, +21630,21631,21633,21635,21637,21639,21640,21641,21642,21645,21649,21651,21655, +21656,21660,21662,21663,21664,21665,21666,21669,21678,21680,21682,21685,21686, +21687,21689,21690,21692,21694,21699,21701,21706,21707,21718,21720,21723,21728, +21729,21730,21731,21732,21739,21740,21743,21744,21745,21748,21749,21750,21751, +21752,21753,21755,21758,21760,21762,21763,21764,21765,21768,21770,21771,21772, +21773,21774,21778,21779,21781,21782,21783,21784,21785,21786,21788,21789,21790, +21791,21793,21797,21798,U,21800,21801,21803,21805,21810,21812,21813,21814, +21816,21817,21818,21819,21821,21824,21826,21829,21831,21832,21835,21836,21837, +21838,21839,21841,21842,21843,21844,21847,21848,21849,21850,21851,21853,21854, +21855,21856,21858,21859,21864,21865,21867,21871,21872,21873,21874,21875,21876, +21881,21882,21885,21887,21893,21894,21900,21901,21902,21904,21906,21907,21909, +21910,21911,21914,21915,21918,21920,21921,21922,21923,21924,21925,21926,21928, +21929,21930,21931,21932,21933,21934,21935,21936,21938,21940,21942,21944,21946, +21948,21951,21952,21953,21954,21955,21958,21959,21960,21962,21963,21966,21967, +21968,21973,21975,21976,21977,21978,21979,21982,21984,21986,21991,21993,21997, +21998,22000,22001,22004,22006,22008,22009,22010,22011,22012,22015,22018,22019, +22020,22021,22022,22023,22026,22027,22029,22032,22033,22034,22035,22036,22037, +22038,22039,22041,22042,22044,22045,22048,22049,22050,22053,22054,22056,22057, +22058,22059,22062,22063,22064,22067,22069,22071,22072,22074,22076,22077,22078, +22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22095, +22096,22097,22098,22099,22101,22102,22106,22107,22109,22110,22111,22112,22113, +U,22115,22117,22118,22119,22125,22126,22127,22128,22130,22131,22132,22133, +22135,22136,22137,22138,22141,22142,22143,22144,22145,22146,22147,22148,22151, +22152,22153,22154,22155,22156,22157,22160,22161,22162,22164,22165,22166,22167, +22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,22178,22180,22181, +22182,22183,22184,22185,22186,22187,22188,22189,22190,22192,22193,22194,22195, +22196,22197,22198,22200,22201,22202,22203,22205,22206,22207,22208,22209,22210, +22211,22212,22213,22214,22215,22216,22217,22219,22220,22221,22222,22223,22224, +22225,22226,22227,22229,22230,22232,22233,22236,22243,22245,22246,22247,22248, +22249,22250,22252,22254,22255,22258,22259,22262,22263,22264,22267,22268,22272, +22273,22274,22277,22279,22283,22284,22285,22286,22287,22288,22289,22290,22291, +22292,22293,22294,22295,22296,22297,22298,22299,22301,22302,22304,22305,22306, +22308,22309,22310,22311,22315,22321,22322,22324,22325,22326,22327,22328,22332, +22333,22335,22337,22339,22340,22341,22342,22344,22345,22347,22354,22355,22356, +22357,22358,22360,22361,22370,22371,22373,22375,22380,22382,22384,22385,22386, +22388,22389,22392,22393,22394,22397,22398,22399,22400,U,22401,22407,22408, +22409,22410,22413,22414,22415,22416,22417,22420,22421,22422,22423,22424,22425, +22426,22428,22429,22430,22431,22437,22440,22442,22444,22447,22448,22449,22451, +22453,22454,22455,22457,22458,22459,22460,22461,22462,22463,22464,22465,22468, +22469,22470,22471,22472,22473,22474,22476,22477,22480,22481,22483,22486,22487, +22491,22492,22494,22497,22498,22499,22501,22502,22503,22504,22505,22506,22507, +22508,22510,22512,22513,22514,22515,22517,22518,22519,22523,22524,22526,22527, +22529,22531,22532,22533,22536,22537,22538,22540,22542,22543,22544,22546,22547, +22548,22550,22551,22552,22554,22555,22556,22557,22559,22562,22563,22565,22566, +22567,22568,22569,22571,22572,22573,22574,22575,22577,22578,22579,22580,22582, +22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,22595, +22597,22598,22599,22600,22601,22602,22603,22606,22607,22608,22610,22611,22613, +22614,22615,22617,22618,22619,22620,22621,22623,22624,22625,22626,22627,22628, +22630,22631,22632,22633,22634,22637,22638,22639,22640,22641,22642,22643,22644, +22645,22646,22647,22648,22649,22650,22651,22652,22653,22655,22658,22660,22662, +22663,22664,22666,22667,22668,U,22669,22670,22671,22672,22673,22676,22677, +22678,22679,22680,22683,22684,22685,22688,22689,22690,22691,22692,22693,22694, +22695,22698,22699,22700,22701,22702,22703,22704,22705,22706,22707,22708,22709, +22710,22711,22712,22713,22714,22715,22717,22718,22719,22720,22722,22723,22724, +22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22738,22739, +22740,22742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753, +22754,22755,22757,22758,22759,22760,22761,22762,22765,22767,22769,22770,22772, +22773,22775,22776,22778,22779,22780,22781,22782,22783,22784,22785,22787,22789, +22790,22792,22793,22794,22795,22796,22798,22800,22801,22802,22803,22807,22808, +22811,22813,22814,22816,22817,22818,22819,22822,22824,22828,22832,22834,22835, +22837,22838,22843,22845,22846,22847,22848,22851,22853,22854,22858,22860,22861, +22864,22866,22867,22873,22875,22876,22877,22878,22879,22881,22883,22884,22886, +22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,22898,22901, +22903,22906,22907,22908,22910,22911,22912,22917,22921,22923,22924,22926,22927, +22928,22929,22932,22933,22936,22938,22939,22940,22941,22943,22944,22945,22946, +22950,U,22951,22956,22957,22960,22961,22963,22964,22965,22966,22967,22968, +22970,22972,22973,22975,22976,22977,22978,22979,22980,22981,22983,22984,22985, +22988,22989,22990,22991,22997,22998,23001,23003,23006,23007,23008,23009,23010, +23012,23014,23015,23017,23018,23019,23021,23022,23023,23024,23025,23026,23027, +23028,23029,23030,23031,23032,23034,23036,23037,23038,23040,23042,23050,23051, +23053,23054,23055,23056,23058,23060,23061,23062,23063,23065,23066,23067,23069, +23070,23073,23074,23076,23078,23079,23080,23082,23083,23084,23085,23086,23087, +23088,23091,23093,23095,23096,23097,23098,23099,23101,23102,23103,23105,23106, +23107,23108,23109,23111,23112,23115,23116,23117,23118,23119,23120,23121,23122, +23123,23124,23126,23127,23128,23129,23131,23132,23133,23134,23135,23136,23137, +23139,23140,23141,23142,23144,23145,23147,23148,23149,23150,23151,23152,23153, +23154,23155,23160,23161,23163,23164,23165,23166,23168,23169,23170,23171,23172, +23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185, +23187,23188,23189,23190,23191,23192,23193,23196,23197,23198,23199,23200,23201, +23202,23203,23204,23205,23206,23207,23208,23209,23211,23212,U,23213,23214, +23215,23216,23217,23220,23222,23223,23225,23226,23227,23228,23229,23231,23232, +23235,23236,23237,23238,23239,23240,23242,23243,23245,23246,23247,23248,23249, +23251,23253,23255,23257,23258,23259,23261,23262,23263,23266,23268,23269,23271, +23272,23274,23276,23277,23278,23279,23280,23282,23283,23284,23285,23286,23287, +23288,23289,23290,23291,23292,23293,23294,23295,23296,23297,23298,23299,23300, +23301,23302,23303,23304,23306,23307,23308,23309,23310,23311,23312,23313,23314, +23315,23316,23317,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329, +23330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,23342, +23343,23344,23345,23347,23349,23350,23352,23353,23354,23355,23356,23357,23358, +23359,23361,23362,23363,23364,23365,23366,23367,23368,23369,23370,23371,23372, +23373,23374,23375,23378,23382,23390,23392,23393,23399,23400,23403,23405,23406, +23407,23410,23412,23414,23415,23416,23417,23419,23420,23422,23423,23426,23430, +23434,23437,23438,23440,23441,23442,23444,23446,23455,23463,23464,23465,23468, +23469,23470,23471,23473,23474,23479,23482,23483,23484,23488,23489,23491,23496, +23497,23498,23499,23501,23502,23503,U,23505,23508,23509,23510,23511,23512, +23513,23514,23515,23516,23520,23522,23523,23526,23527,23529,23530,23531,23532, +23533,23535,23537,23538,23539,23540,23541,23542,23543,23549,23550,23552,23554, +23555,23557,23559,23560,23563,23564,23565,23566,23568,23570,23571,23575,23577, +23579,23582,23583,23584,23585,23587,23590,23592,23593,23594,23595,23597,23598, +23599,23600,23602,23603,23605,23606,23607,23619,23620,23622,23623,23628,23629, +23634,23635,23636,23638,23639,23640,23642,23643,23644,23645,23647,23650,23652, +23655,23656,23657,23658,23659,23660,23661,23664,23666,23667,23668,23669,23670, +23671,23672,23675,23676,23677,23678,23680,23683,23684,23685,23686,23687,23689, +23690,23691,23694,23695,23698,23699,23701,23709,23710,23711,23712,23713,23716, +23717,23718,23719,23720,23722,23726,23727,23728,23730,23732,23734,23737,23738, +23739,23740,23742,23744,23746,23747,23749,23750,23751,23752,23753,23754,23756, +23757,23758,23759,23760,23761,23763,23764,23765,23766,23767,23768,23770,23771, +23772,23773,23774,23775,23776,23778,23779,23783,23785,23787,23788,23790,23791, +23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,23804,23805,23806, +23807,23808,U,23809,23812,23813,23816,23817,23818,23819,23820,23821,23823, +23824,23825,23826,23827,23829,23831,23832,23833,23834,23836,23837,23839,23840, +23841,23842,23843,23845,23848,23850,23851,23852,23855,23856,23857,23858,23859, +23861,23862,23863,23864,23865,23866,23867,23868,23871,23872,23873,23874,23875, +23876,23877,23878,23880,23881,23885,23886,23887,23888,23889,23890,23891,23892, +23893,23894,23895,23897,23898,23900,23902,23903,23904,23905,23906,23907,23908, +23909,23910,23911,23912,23914,23917,23918,23920,23921,23922,23923,23925,23926, +23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23939,23940, +23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953, +23954,23955,23956,23957,23958,23959,23960,23962,23963,23964,23966,23967,23968, +23969,23970,23971,23972,23973,23974,23975,23976,23977,23978,23979,23980,23981, +23982,23983,23984,23985,23986,23987,23988,23989,23990,23992,23993,23994,23995, +23996,23997,23998,23999,24000,24001,24002,24003,24004,24006,24007,24008,24009, +24010,24011,24012,24014,24015,24016,24017,24018,24019,24020,24021,24022,24023, +24024,24025,24026,24028,24031,24032,24035,24036,24042,24044,24045,U,24048, +24053,24054,24056,24057,24058,24059,24060,24063,24064,24068,24071,24073,24074, +24075,24077,24078,24082,24083,24087,24094,24095,24096,24097,24098,24099,24100, +24101,24104,24105,24106,24107,24108,24111,24112,24114,24115,24116,24117,24118, +24121,24122,24126,24127,24128,24129,24131,24134,24135,24136,24137,24138,24139, +24141,24142,24143,24144,24145,24146,24147,24150,24151,24152,24153,24154,24156, +24157,24159,24160,24163,24164,24165,24166,24167,24168,24169,24170,24171,24172, +24173,24174,24175,24176,24177,24181,24183,24185,24190,24193,24194,24195,24197, +24200,24201,24204,24205,24206,24210,24216,24219,24221,24225,24226,24227,24228, +24232,24233,24234,24235,24236,24238,24239,24240,24241,24242,24244,24250,24251, +24252,24253,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24267, +24268,24269,24270,24271,24272,24276,24277,24279,24280,24281,24282,24284,24285, +24286,24287,24288,24289,24290,24291,24292,24293,24294,24295,24297,24299,24300, +24301,24302,24303,24304,24305,24306,24307,24309,24312,24313,24315,24316,24317, +24325,24326,24327,24329,24332,24333,24334,24336,24338,24340,24342,24345,24346, +24348,24349,24350,24353,24354,24355,24356,U,24360,24363,24364,24366,24368, +24370,24371,24372,24373,24374,24375,24376,24379,24381,24382,24383,24385,24386, +24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,24398,24399, +24401,24404,24409,24410,24411,24412,24414,24415,24416,24419,24421,24423,24424, +24427,24430,24431,24434,24436,24437,24438,24440,24442,24445,24446,24447,24451, +24454,24461,24462,24463,24465,24467,24468,24470,24474,24475,24477,24478,24479, +24480,24482,24483,24484,24485,24486,24487,24489,24491,24492,24495,24496,24497, +24498,24499,24500,24502,24504,24505,24506,24507,24510,24511,24512,24513,24514, +24519,24520,24522,24523,24526,24531,24532,24533,24538,24539,24540,24542,24543, +24546,24547,24549,24550,24552,24553,24556,24559,24560,24562,24563,24564,24566, +24567,24569,24570,24572,24583,24584,24585,24587,24588,24592,24593,24595,24599, +24600,24602,24606,24607,24610,24611,24612,24620,24621,24622,24624,24625,24626, +24627,24628,24630,24631,24632,24633,24634,24637,24638,24640,24644,24645,24646, +24647,24648,24649,24650,24652,24654,24655,24657,24659,24660,24662,24663,24664, +24667,24668,24670,24671,24672,24673,24677,24678,24686,24689,24690,24692,24693, +24695,24702,24704,U,24705,24706,24709,24710,24711,24712,24714,24715,24718, +24719,24720,24721,24723,24725,24727,24728,24729,24732,24734,24737,24738,24740, +24741,24743,24745,24746,24750,24752,24755,24757,24758,24759,24761,24762,24765, +24766,24767,24768,24769,24770,24771,24772,24775,24776,24777,24780,24781,24782, +24783,24784,24786,24787,24788,24790,24791,24793,24795,24798,24801,24802,24803, +24804,24805,24810,24817,24818,24821,24823,24824,24827,24828,24829,24830,24831, +24834,24835,24836,24837,24839,24842,24843,24844,24848,24849,24850,24851,24852, +24854,24855,24856,24857,24859,24860,24861,24862,24865,24866,24869,24872,24873, +24874,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,24887, +24888,24889,24890,24891,24892,24893,24894,24896,24897,24898,24899,24900,24901, +24902,24903,24905,24907,24909,24911,24912,24914,24915,24916,24918,24919,24920, +24921,24922,24923,24924,24926,24927,24928,24929,24931,24932,24933,24934,24937, +24938,24939,24940,24941,24942,24943,24945,24946,24947,24948,24950,24952,24953, +24954,24955,24956,24957,24958,24959,24960,24961,24962,24963,24964,24965,24966, +24967,24968,24969,24970,24972,24973,24975,24976,24977,24978,24979,24981,U, +24982,24983,24984,24985,24986,24987,24988,24990,24991,24992,24993,24994,24995, +24996,24997,24998,25002,25003,25005,25006,25007,25008,25009,25010,25011,25012, +25013,25014,25016,25017,25018,25019,25020,25021,25023,25024,25025,25027,25028, +25029,25030,25031,25033,25036,25037,25038,25039,25040,25043,25045,25046,25047, +25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,25058,25059,25060, +25061,25063,25064,25065,25066,25067,25068,25069,25070,25071,25072,25073,25074, +25075,25076,25078,25079,25080,25081,25082,25083,25084,25085,25086,25088,25089, +25090,25091,25092,25093,25095,25097,25107,25108,25113,25116,25117,25118,25120, +25123,25126,25127,25128,25129,25131,25133,25135,25136,25137,25138,25141,25142, +25144,25145,25146,25147,25148,25154,25156,25157,25158,25162,25167,25168,25173, +25174,25175,25177,25178,25180,25181,25182,25183,25184,25185,25186,25188,25189, +25192,25201,25202,25204,25205,25207,25208,25210,25211,25213,25217,25218,25219, +25221,25222,25223,25224,25227,25228,25229,25230,25231,25232,25236,25241,25244, +25245,25246,25251,25254,25255,25257,25258,25261,25262,25263,25264,25266,25267, +25268,25270,25271,25272,25274,25278,25280,25281,U,25283,25291,25295,25297, +25301,25309,25310,25312,25313,25316,25322,25323,25328,25330,25333,25336,25337, +25338,25339,25344,25347,25348,25349,25350,25354,25355,25356,25357,25359,25360, +25362,25363,25364,25365,25367,25368,25369,25372,25382,25383,25385,25388,25389, +25390,25392,25393,25395,25396,25397,25398,25399,25400,25403,25404,25406,25407, +25408,25409,25412,25415,25416,25418,25425,25426,25427,25428,25430,25431,25432, +25433,25434,25435,25436,25437,25440,25444,25445,25446,25448,25450,25451,25452, +25455,25456,25458,25459,25460,25461,25464,25465,25468,25469,25470,25471,25473, +25475,25476,25477,25478,25483,25485,25489,25491,25492,25493,25495,25497,25498, +25499,25500,25501,25502,25503,25505,25508,25510,25515,25519,25521,25522,25525, +25526,25529,25531,25533,25535,25536,25537,25538,25539,25541,25543,25544,25546, +25547,25548,25553,25555,25556,25557,25559,25560,25561,25562,25563,25564,25565, +25567,25570,25572,25573,25574,25575,25576,25579,25580,25582,25583,25584,25585, +25587,25589,25591,25593,25594,25595,25596,25598,25603,25604,25606,25607,25608, +25609,25610,25613,25614,25617,25618,25621,25622,25623,25624,25625,25626,25629, +25631,25634,25635,25636,U,25637,25639,25640,25641,25643,25646,25647,25648, +25649,25650,25651,25653,25654,25655,25656,25657,25659,25660,25662,25664,25666, +25667,25673,25675,25676,25677,25678,25679,25680,25681,25683,25685,25686,25687, +25689,25690,25691,25692,25693,25695,25696,25697,25698,25699,25700,25701,25702, +25704,25706,25707,25708,25710,25711,25712,25713,25714,25715,25716,25717,25718, +25719,25723,25724,25725,25726,25727,25728,25729,25731,25734,25736,25737,25738, +25739,25740,25741,25742,25743,25744,25747,25748,25751,25752,25754,25755,25756, +25757,25759,25760,25761,25762,25763,25765,25766,25767,25768,25770,25771,25775, +25777,25778,25779,25780,25782,25785,25787,25789,25790,25791,25793,25795,25796, +25798,25799,25800,25801,25802,25803,25804,25807,25809,25811,25812,25813,25814, +25817,25818,25819,25820,25821,25823,25824,25825,25827,25829,25831,25832,25833, +25834,25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846, +25847,25848,25849,25850,25851,25852,25853,25854,25855,25857,25858,25859,25860, +25861,25862,25863,25864,25866,25867,25868,25869,25870,25871,25872,25873,25875, +25876,25877,25878,25879,25881,25882,25883,25884,25885,25886,25887,25888,25889, +U,25890,25891,25892,25894,25895,25896,25897,25898,25900,25901,25904,25905, +25906,25907,25911,25914,25916,25917,25920,25921,25922,25923,25924,25926,25927, +25930,25931,25933,25934,25936,25938,25939,25940,25943,25944,25946,25948,25951, +25952,25953,25956,25957,25959,25960,25961,25962,25965,25966,25967,25969,25971, +25973,25974,25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,25986, +25987,25988,25989,25990,25992,25993,25994,25997,25998,25999,26002,26004,26005, +26006,26008,26010,26013,26014,26016,26018,26019,26022,26024,26026,26028,26030, +26033,26034,26035,26036,26037,26038,26039,26040,26042,26043,26046,26047,26048, +26050,26055,26056,26057,26058,26061,26064,26065,26067,26068,26069,26072,26073, +26074,26075,26076,26077,26078,26079,26081,26083,26084,26090,26091,26098,26099, +26100,26101,26104,26105,26107,26108,26109,26110,26111,26113,26116,26117,26119, +26120,26121,26123,26125,26128,26129,26130,26134,26135,26136,26138,26139,26140, +26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26162, +26163,26167,26168,26169,26170,26171,26173,26175,26176,26178,26180,26181,26182, +26183,26184,26185,26186,26189,26190,26192,26193,26200,U,26201,26203,26204, +26205,26206,26208,26210,26211,26213,26215,26217,26218,26219,26220,26221,26225, +26226,26227,26229,26232,26233,26235,26236,26237,26239,26240,26241,26243,26245, +26246,26248,26249,26250,26251,26253,26254,26255,26256,26258,26259,26260,26261, +26264,26265,26266,26267,26268,26270,26271,26272,26273,26274,26275,26276,26277, +26278,26281,26282,26283,26284,26285,26287,26288,26289,26290,26291,26293,26294, +26295,26296,26298,26299,26300,26301,26303,26304,26305,26306,26307,26308,26309, +26310,26311,26312,26313,26314,26315,26316,26317,26318,26319,26320,26321,26322, +26323,26324,26325,26326,26327,26328,26330,26334,26335,26336,26337,26338,26339, +26340,26341,26343,26344,26346,26347,26348,26349,26350,26351,26353,26357,26358, +26360,26362,26363,26365,26369,26370,26371,26372,26373,26374,26375,26380,26382, +26383,26385,26386,26387,26390,26392,26393,26394,26396,26398,26400,26401,26402, +26403,26404,26405,26407,26409,26414,26416,26418,26419,26422,26423,26424,26425, +26427,26428,26430,26431,26433,26436,26437,26439,26442,26443,26445,26450,26452, +26453,26455,26456,26457,26458,26459,26461,26466,26467,26468,26470,26471,26475, +26476,26478,26481,26484,26486,U,26488,26489,26490,26491,26493,26496,26498, +26499,26501,26502,26504,26506,26508,26509,26510,26511,26513,26514,26515,26516, +26518,26521,26523,26527,26528,26529,26532,26534,26537,26540,26542,26545,26546, +26548,26553,26554,26555,26556,26557,26558,26559,26560,26562,26565,26566,26567, +26568,26569,26570,26571,26572,26573,26574,26581,26582,26583,26587,26591,26593, +26595,26596,26598,26599,26600,26602,26603,26605,26606,26610,26613,26614,26615, +26616,26617,26618,26619,26620,26622,26625,26626,26627,26628,26630,26637,26640, +26642,26644,26645,26648,26649,26650,26651,26652,26654,26655,26656,26658,26659, +26660,26661,26662,26663,26664,26667,26668,26669,26670,26671,26672,26673,26676, +26677,26678,26682,26683,26687,26695,26699,26701,26703,26706,26710,26711,26712, +26713,26714,26715,26716,26717,26718,26719,26730,26732,26733,26734,26735,26736, +26737,26738,26739,26741,26744,26745,26746,26747,26748,26749,26750,26751,26752, +26754,26756,26759,26760,26761,26762,26763,26764,26765,26766,26768,26769,26770, +26772,26773,26774,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785, +26787,26788,26789,26793,26794,26795,26796,26798,26801,26802,26804,26806,26807, +26808,U,26809,26810,26811,26812,26813,26814,26815,26817,26819,26820,26821, +26822,26823,26824,26826,26828,26830,26831,26832,26833,26835,26836,26838,26839, +26841,26843,26844,26845,26846,26847,26849,26850,26852,26853,26854,26855,26856, +26857,26858,26859,26860,26861,26863,26866,26867,26868,26870,26871,26872,26875, +26877,26878,26879,26880,26882,26883,26884,26886,26887,26888,26889,26890,26892, +26895,26897,26899,26900,26901,26902,26903,26904,26905,26906,26907,26908,26909, +26910,26913,26914,26915,26917,26918,26919,26920,26921,26922,26923,26924,26926, +26927,26929,26930,26931,26933,26934,26935,26936,26938,26939,26940,26942,26944, +26945,26947,26948,26949,26950,26951,26952,26953,26954,26955,26956,26957,26958, +26959,26960,26961,26962,26963,26965,26966,26968,26969,26971,26972,26975,26977, +26978,26980,26981,26983,26984,26985,26986,26988,26989,26991,26992,26994,26995, +26996,26997,26998,27002,27003,27005,27006,27007,27009,27011,27013,27018,27019, +27020,27022,27023,27024,27025,27026,27027,27030,27031,27033,27034,27037,27038, +27039,27040,27041,27042,27043,27044,27045,27046,27049,27050,27052,27054,27055, +27056,27058,27059,27061,27062,27064,27065,27066,27068,27069,U,27070,27071, +27072,27074,27075,27076,27077,27078,27079,27080,27081,27083,27085,27087,27089, +27090,27091,27093,27094,27095,27096,27097,27098,27100,27101,27102,27105,27106, +27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27118,27119,27120, +27121,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27134,27136, +27137,27138,27139,27140,27141,27142,27143,27144,27145,27147,27148,27149,27150, +27151,27152,27153,27154,27155,27156,27157,27158,27161,27162,27163,27164,27165, +27166,27168,27170,27171,27172,27173,27174,27175,27177,27179,27180,27181,27182, +27184,27186,27187,27188,27190,27191,27192,27193,27194,27195,27196,27199,27200, +27201,27202,27203,27205,27206,27208,27209,27210,27211,27212,27213,27214,27215, +27217,27218,27219,27220,27221,27222,27223,27226,27228,27229,27230,27231,27232, +27234,27235,27236,27238,27239,27240,27241,27242,27243,27244,27245,27246,27247, +27248,27250,27251,27252,27253,27254,27255,27256,27258,27259,27261,27262,27263, +27265,27266,27267,27269,27270,27271,27272,27273,27274,27275,27276,27277,27279, +27282,27283,27284,27285,27286,27288,27289,27290,27291,27292,27293,27294,27295, +27297,27298,27299,27300,27301,27302,U,27303,27304,27306,27309,27310,27311, +27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324, +27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337, +27338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,27350, +27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,27362,27363, +27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,27374,27375,27376, +27377,27378,27379,27380,27381,27382,27383,27384,27385,27386,27387,27388,27389, +27390,27391,27392,27393,27394,27395,27396,27397,27398,27399,27400,27401,27402, +27403,27404,27405,27406,27407,27408,27409,27410,27411,27412,27413,27414,27415, +27416,27417,27418,27419,27420,27421,27422,27423,27429,27430,27432,27433,27434, +27435,27436,27437,27438,27439,27440,27441,27443,27444,27445,27446,27448,27451, +27452,27453,27455,27456,27457,27458,27460,27461,27464,27466,27467,27469,27470, +27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27482,27483,27484, +27485,27486,27487,27488,27489,27496,27497,27499,27500,27501,27502,27503,27504, +27505,27506,27507,27508,27509,27510,27511,27512,27514,27517,27518,27519,27520, +27525,27528,U,27532,27534,27535,27536,27537,27540,27541,27543,27544,27545, +27548,27549,27550,27551,27552,27554,27555,27556,27557,27558,27559,27560,27561, +27563,27564,27565,27566,27567,27568,27569,27570,27574,27576,27577,27578,27579, +27580,27581,27582,27584,27587,27588,27590,27591,27592,27593,27594,27596,27598, +27600,27601,27608,27610,27612,27613,27614,27615,27616,27618,27619,27620,27621, +27622,27623,27624,27625,27628,27629,27630,27632,27633,27634,27636,27638,27639, +27640,27642,27643,27644,27646,27647,27648,27649,27650,27651,27652,27656,27657, +27658,27659,27660,27662,27666,27671,27676,27677,27678,27680,27683,27685,27691, +27692,27693,27697,27699,27702,27703,27705,27706,27707,27708,27710,27711,27715, +27716,27717,27720,27723,27724,27725,27726,27727,27729,27730,27731,27734,27736, +27737,27738,27746,27747,27749,27750,27751,27755,27756,27757,27758,27759,27761, +27763,27765,27767,27768,27770,27771,27772,27775,27776,27780,27783,27786,27787, +27789,27790,27793,27794,27797,27798,27799,27800,27802,27804,27805,27806,27808, +27810,27816,27820,27823,27824,27828,27829,27830,27831,27834,27840,27841,27842, +27843,27846,27847,27848,27851,27853,27854,27855,27857,27858,27864,U,27865, +27866,27868,27869,27871,27876,27878,27879,27881,27884,27885,27890,27892,27897, +27903,27904,27906,27907,27909,27910,27912,27913,27914,27917,27919,27920,27921, +27923,27924,27925,27926,27928,27932,27933,27935,27936,27937,27938,27939,27940, +27942,27944,27945,27948,27949,27951,27952,27956,27958,27959,27960,27962,27967, +27968,27970,27972,27977,27980,27984,27989,27990,27991,27992,27995,27997,27999, +28001,28002,28004,28005,28007,28008,28011,28012,28013,28016,28017,28018,28019, +28021,28022,28025,28026,28027,28029,28030,28031,28032,28033,28035,28036,28038, +28039,28042,28043,28045,28047,28048,28050,28054,28055,28056,28057,28058,28060, +28066,28069,28076,28077,28080,28081,28083,28084,28086,28087,28089,28090,28091, +28092,28093,28094,28097,28098,28099,28104,28105,28106,28109,28110,28111,28112, +28114,28115,28116,28117,28119,28122,28123,28124,28127,28130,28131,28133,28135, +28136,28137,28138,28141,28143,28144,28146,28148,28149,28150,28152,28154,28157, +28158,28159,28160,28161,28162,28163,28164,28166,28167,28168,28169,28171,28175, +28178,28179,28181,28184,28185,28187,28188,28190,28191,28194,28198,28199,28200, +28202,28204,28206,28208,28209,28211,28213,U,28214,28215,28217,28219,28220, +28221,28222,28223,28224,28225,28226,28229,28230,28231,28232,28233,28234,28235, +28236,28239,28240,28241,28242,28245,28247,28249,28250,28252,28253,28254,28256, +28257,28258,28259,28260,28261,28262,28263,28264,28265,28266,28268,28269,28271, +28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284, +28285,28288,28289,28290,28292,28295,28296,28298,28299,28300,28301,28302,28305, +28306,28307,28308,28309,28310,28311,28313,28314,28315,28317,28318,28320,28321, +28323,28324,28326,28328,28329,28331,28332,28333,28334,28336,28339,28341,28344, +28345,28348,28350,28351,28352,28355,28356,28357,28358,28360,28361,28362,28364, +28365,28366,28368,28370,28374,28376,28377,28379,28380,28381,28387,28391,28394, +28395,28396,28397,28398,28399,28400,28401,28402,28403,28405,28406,28407,28408, +28410,28411,28412,28413,28414,28415,28416,28417,28419,28420,28421,28423,28424, +28426,28427,28428,28429,28430,28432,28433,28434,28438,28439,28440,28441,28442, +28443,28444,28445,28446,28447,28449,28450,28451,28453,28454,28455,28456,28460, +28462,28464,28466,28468,28469,28471,28472,28473,28474,28475,28476,28477,28479, +28480,28481,28482,U,28483,28484,28485,28488,28489,28490,28492,28494,28495, +28496,28497,28498,28499,28500,28501,28502,28503,28505,28506,28507,28509,28511, +28512,28513,28515,28516,28517,28519,28520,28521,28522,28523,28524,28527,28528, +28529,28531,28533,28534,28535,28537,28539,28541,28542,28543,28544,28545,28546, +28547,28549,28550,28551,28554,28555,28559,28560,28561,28562,28563,28564,28565, +28566,28567,28568,28569,28570,28571,28573,28574,28575,28576,28578,28579,28580, +28581,28582,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594, +28596,28597,28599,28600,28602,28603,28604,28605,28606,28607,28609,28611,28612, +28613,28614,28615,28616,28618,28619,28620,28621,28622,28623,28624,28627,28628, +28629,28630,28631,28632,28633,28634,28635,28636,28637,28639,28642,28643,28644, +28645,28646,28647,28648,28649,28650,28651,28652,28653,28656,28657,28658,28659, +28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,28670,28671,28672, +28673,28674,28675,28676,28677,28678,28679,28680,28681,28682,28683,28684,28685, +28686,28687,28688,28690,28691,28692,28693,28694,28695,28696,28697,28700,28701, +28702,28703,28704,28705,28706,28708,28709,28710,28711,28712,28713,28714,U, +28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28726,28727,28728, +28730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,28742, +28743,28744,28745,28746,28747,28749,28750,28752,28753,28754,28755,28756,28757, +28758,28759,28760,28761,28762,28763,28764,28765,28767,28768,28769,28770,28771, +28772,28773,28774,28775,28776,28777,28778,28782,28785,28786,28787,28788,28791, +28793,28794,28795,28797,28801,28802,28803,28804,28806,28807,28808,28811,28812, +28813,28815,28816,28817,28819,28823,28824,28826,28827,28830,28831,28832,28833, +28834,28835,28836,28837,28838,28839,28840,28841,28842,28848,28850,28852,28853, +28854,28858,28862,28863,28868,28869,28870,28871,28873,28875,28876,28877,28878, +28879,28880,28881,28882,28883,28884,28885,28886,28887,28890,28892,28893,28894, +28896,28897,28898,28899,28901,28906,28910,28912,28913,28914,28915,28916,28917, +28918,28920,28922,28923,28924,28926,28927,28928,28929,28930,28931,28932,28933, +28934,28935,28936,28939,28940,28941,28942,28943,28945,28946,28948,28951,28955, +28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28967,28968,28969, +28970,28971,28972,28973,28974,28978,28979,28980,U,28981,28983,28984,28985, +28986,28987,28988,28989,28990,28991,28992,28993,28994,28995,28996,28998,28999, +29000,29001,29003,29005,29007,29008,29009,29010,29011,29012,29013,29014,29015, +29016,29017,29018,29019,29021,29023,29024,29025,29026,29027,29029,29033,29034, +29035,29036,29037,29039,29040,29041,29044,29045,29046,29047,29049,29051,29052, +29054,29055,29056,29057,29058,29059,29061,29062,29063,29064,29065,29067,29068, +29069,29070,29072,29073,29074,29075,29077,29078,29079,29082,29083,29084,29085, +29086,29089,29090,29091,29092,29093,29094,29095,29097,29098,29099,29101,29102, +29103,29104,29105,29106,29108,29110,29111,29112,29114,29115,29116,29117,29118, +29119,29120,29121,29122,29124,29125,29126,29127,29128,29129,29130,29131,29132, +29133,29135,29136,29137,29138,29139,29142,29143,29144,29145,29146,29147,29148, +29149,29150,29151,29153,29154,29155,29156,29158,29160,29161,29162,29163,29164, +29165,29167,29168,29169,29170,29171,29172,29173,29174,29175,29176,29178,29179, +29180,29181,29182,29183,29184,29185,29186,29187,29188,29189,29191,29192,29193, +29194,29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206, +29207,29208,29209,29210,U,29211,29212,29214,29215,29216,29217,29218,29219, +29220,29221,29222,29223,29225,29227,29229,29230,29231,29234,29235,29236,29242, +29244,29246,29248,29249,29250,29251,29252,29253,29254,29257,29258,29259,29262, +29263,29264,29265,29267,29268,29269,29271,29272,29274,29276,29278,29280,29283, +29284,29285,29288,29290,29291,29292,29293,29296,29297,29299,29300,29302,29303, +29304,29307,29308,29309,29314,29315,29317,29318,29319,29320,29321,29324,29326, +29328,29329,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341, +29342,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,29354,29355, +29358,29361,29362,29363,29365,29370,29371,29372,29373,29374,29375,29376,29381, +29382,29383,29385,29386,29387,29388,29391,29393,29395,29396,29397,29398,29400, +29402,29403,183,U,U,U,U,U,8212,8560,8561,8562,8563,8564,8565,8566,8567,8568, +8569,65077,65078,65081,65082,65087,65088,65085,65086,65089,65090,65091,65092, +U,U,65083,65084,65079,65080,65073,U,65075,65076,714,715,729,8211,8213,8229, +8245,8453,8457,8598,8599,8600,8601,8725,8735,8739,8786,8806,8807,8895,9552, +9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567, +9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582, +9583,9584,9585,9586,9587,9601,9602,9603,9604,9605,9606,9607,U,9608,9609,9610, +9611,9612,9613,9614,9615,9619,9620,9621,9660,9661,9698,9699,9700,9701,9737, +8853,12306,12317,12318,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,593,U,324,328,U,609,12321,12322,12323,12324,12325,12326, +12327,12328,12329,12963,13198,13199,13212,13213,13214,13217,13252,13262,13265, +13266,13269,65072,65506,65508,U,8481,12849,U,8208,U,U,U,12540,12443,12444, +12541,12542,12294,12445,12446,65097,65098,65099,65100,65101,65102,65103,65104, +65105,65106,65108,65109,65110,65111,65113,65114,65115,65116,65117,65118,65119, +65120,65121,U,65122,65123,65124,65125,65126,65128,65129,65130,65131,U,U,U,U,U, +U,U,U,U,U,U,U,U,12295,29404,29405,29407,29410,29411,29412,29413,29414,29415, +29418,29419,29429,29430,29433,29437,29438,29439,29440,29442,29444,29445,29446, +29447,29448,29449,29451,29452,29453,29455,29456,29457,29458,29460,29464,29465, +29466,29471,29472,29475,29476,29478,29479,29480,29485,29487,29488,29490,29491, +29493,29494,29498,29499,29500,29501,29504,29505,29506,29507,29508,29509,29510, +29511,29512,U,29513,29514,29515,29516,29518,29519,29521,29523,29524,29525, +29526,29528,29529,29530,29531,29532,29533,29534,29535,29537,29538,29539,29540, +29541,29542,29543,29544,29545,29546,29547,29550,29552,29553,29554,29555,29556, +29557,29558,29559,29560,29561,29562,29563,29564,29565,29567,29568,29569,29570, +29571,29573,29574,29576,29578,29580,29581,29583,29584,29586,29587,29588,29589, +29591,29592,29593,29594,29596,29597,29598,29600,29601,29603,29604,29605,29606, +29607,29608,29610,29612,29613,29617,29620,29621,29622,29624,29625,29628,29629, +29630,29631,29633,29635,29636,29637,29638,29639,U,29643,29644,29646,29650, +29651,29652,29653,29654,29655,29656,29658,29659,29660,29661,29663,29665,29666, +29667,29668,29670,29672,29674,29675,29676,29678,29679,29680,29681,29683,29684, +29685,29686,29687,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697, +29698,29700,29703,29704,29707,29708,29709,29710,29713,29714,29715,29716,29717, +29718,29719,29720,29721,29724,29725,29726,29727,29728,29729,29731,29732,29735, +29737,29739,29741,29743,29745,29746,29751,29752,29753,29754,29755,29757,29758, +29759,29760,29762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772, +29773,U,29774,29775,29776,29777,29778,29779,29780,29782,29784,29789,29792, +29793,29794,29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29806, +29807,29809,29810,29811,29812,29813,29816,29817,29818,29819,29820,29821,29823, +29826,29828,29829,29830,29832,29833,29834,29836,29837,29839,29841,29842,29843, +29844,29845,29846,29847,29848,29849,29850,29851,29853,29855,29856,29857,29858, +29859,29860,29861,29862,29866,29867,29868,29869,29870,29871,29872,29873,29874, +29875,29876,29877,29878,29879,29880,29881,29883,29884,29885,29886,29887,29888, +29889,29890,29891,29892,29893,29894,29895,U,29896,29897,29898,29899,29900, +29901,29902,29903,29904,29905,29907,29908,29909,29910,29911,29912,29913,29914, +29915,29917,29919,29921,29925,29927,29928,29929,29930,29931,29932,29933,29936, +29937,29938,29939,29941,29944,29945,29946,29947,29948,29949,29950,29952,29953, +29954,29955,29957,29958,29959,29960,29961,29962,29963,29964,29966,29968,29970, +29972,29973,29974,29975,29979,29981,29982,29984,29985,29986,29987,29988,29990, +29991,29994,29998,30004,30006,30009,30012,30013,30015,30017,30018,30019,30020, +30022,30023,30025,30026,30029,30032,30033,30034,30035,30037,30038,30039,30040, +U,30045,30046,30047,30048,30049,30050,30051,30052,30055,30056,30057,30059, +30060,30061,30062,30063,30064,30065,30067,30069,30070,30071,30074,30075,30076, +30077,30078,30080,30081,30082,30084,30085,30087,30088,30089,30090,30092,30093, +30094,30096,30099,30101,30104,30107,30108,30110,30114,30118,30119,30120,30121, +30122,30125,30134,30135,30138,30139,30143,30144,30145,30150,30155,30156,30158, +30159,30160,30161,30163,30167,30169,30170,30172,30173,30175,30176,30177,30181, +30185,30188,30189,30190,30191,30194,30195,30197,30198,30199,30200,30202,30203, +30205,30206,30210,30212,30214,30215,U,30216,30217,30219,30221,30222,30223, +30225,30226,30227,30228,30230,30234,30236,30237,30238,30241,30243,30247,30248, +30252,30254,30255,30257,30258,30262,30263,30265,30266,30267,30269,30273,30274, +30276,30277,30278,30279,30280,30281,30282,30283,30286,30287,30288,30289,30290, +30291,30293,30295,30296,30297,30298,30299,30301,30303,30304,30305,30306,30308, +30309,30310,30311,30312,30313,30314,30316,30317,30318,30320,30321,30322,30323, +30324,30325,30326,30327,30329,30330,30332,30335,30336,30337,30339,30341,30345, +30346,30348,30349,30351,30352,30354,30356,30357,30359,30360,30362,30363,U, +30364,30365,30366,30367,30368,30369,30370,30371,30373,30374,30375,30376,30377, +30378,30379,30380,30381,30383,30384,30387,30389,30390,30391,30392,30393,30394, +30395,30396,30397,30398,30400,30401,30403,30404,30407,30409,30411,30412,30419, +30421,30425,30426,30428,30429,30430,30432,30433,30434,30435,30436,30438,30439, +30440,30441,30442,30443,30444,30445,30448,30451,30453,30454,30455,30458,30459, +30461,30463,30464,30466,30467,30469,30470,30474,30476,30478,30479,30480,30481, +30482,30483,30484,30485,30486,30487,30488,30491,30492,30493,30494,30497,30499, +30500,30501,30503,30506,30507,U,30508,30510,30512,30513,30514,30515,30516, +30521,30523,30525,30526,30527,30530,30532,30533,30534,30536,30537,30538,30539, +30540,30541,30542,30543,30546,30547,30548,30549,30550,30551,30552,30553,30556, +30557,30558,30559,30560,30564,30567,30569,30570,30573,30574,30575,30576,30577, +30578,30579,30580,30581,30582,30583,30584,30586,30587,30588,30593,30594,30595, +30598,30599,30600,30601,30602,30603,30607,30608,30611,30612,30613,30614,30615, +30616,30617,30618,30619,30620,30621,30622,30625,30627,30628,30630,30632,30635, +30637,30638,30639,30641,30642,30644,30646,30647,30648,30649,30650,U,30652, +30654,30656,30657,30658,30659,30660,30661,30662,30663,30664,30665,30666,30667, +30668,30670,30671,30672,30673,30674,30675,30676,30677,30678,30680,30681,30682, +30685,30686,30687,30688,30689,30692,30694,30696,30698,30703,30704,30705,30706, +30708,30709,30711,30713,30714,30715,30716,30723,30724,30725,30726,30727,30728, +30730,30731,30734,30735,30736,30739,30741,30745,30747,30750,30752,30753,30754, +30756,30760,30762,30763,30766,30767,30769,30770,30771,30773,30774,30781,30783, +30785,30786,30787,30788,30790,30792,30793,30794,30795,30797,30799,30801,30803, +30804,30808,30809,30810,U,30811,30812,30814,30815,30816,30817,30818,30819, +30820,30821,30822,30823,30824,30825,30831,30832,30833,30834,30835,30836,30837, +30838,30840,30841,30842,30843,30845,30846,30847,30848,30849,30850,30851,30852, +30853,30854,30856,30858,30859,30863,30864,30866,30868,30869,30870,30873,30877, +30878,30880,30882,30884,30886,30888,30889,30890,30891,30892,30893,30894,30895, +30901,30902,30903,30904,30906,30907,30908,30909,30911,30912,30914,30915,30916, +30918,30919,30920,30924,30925,30926,30927,30929,30930,30931,30934,30935,30936, +30938,30939,30940,30941,30942,30943,30944,30945,30946,30947,U,30948,30949, +30950,30951,30953,30954,30955,30957,30958,30959,30960,30961,30963,30965,30966, +30968,30969,30971,30972,30973,30974,30975,30976,30978,30979,30980,30982,30983, +30984,30985,30986,30987,30988,30989,30990,30991,30992,30993,30994,30996,30997, +30998,30999,31000,31001,31002,31003,31004,31005,31007,31008,31009,31010,31011, +31013,31014,31015,31016,31017,31018,31019,31020,31021,31022,31023,31024,31025, +31026,31027,31029,31030,31031,31032,31033,31037,31039,31042,31043,31044,31045, +31047,31050,31051,31052,31053,31054,31055,31056,31057,31058,31060,31061,31064, +31065,31073,31075,U,31076,31078,31081,31082,31083,31084,31086,31088,31089, +31090,31091,31092,31093,31094,31097,31099,31100,31101,31102,31103,31106,31107, +31110,31111,31112,31113,31115,31116,31117,31118,31120,31121,31122,31123,31124, +31125,31126,31127,31128,31129,31131,31132,31133,31134,31135,31136,31137,31138, +31139,31140,31141,31142,31144,31145,31146,31147,31148,31149,31150,31151,31152, +31153,31154,31156,31157,31158,31159,31160,31164,31167,31170,31172,31173,31175, +31176,31178,31180,31182,31183,31184,31187,31188,31190,31191,31193,31194,31195, +31196,31197,31198,31200,31201,31202,31205,31208,31210,U,31212,31214,31217, +31218,31219,31220,31221,31222,31223,31225,31226,31228,31230,31231,31233,31236, +31237,31239,31240,31241,31242,31244,31247,31248,31249,31250,31251,31253,31254, +31256,31257,31259,31260,31261,31263,31265,31266,31268,31269,31270,31271,31272, +31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,31284,31285,31286, +31288,31290,31294,31296,31297,31298,31299,31300,31301,31303,31304,31305,31306, +31307,31308,31309,31310,31311,31312,31314,31315,31316,31317,31318,31320,31321, +31322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,31334, +31335,31336,U,31337,31338,31339,31340,31341,31342,31343,31345,31346,31347, +31349,31355,31356,31357,31358,31362,31365,31367,31369,31370,31371,31372,31374, +31375,31376,31379,31380,31385,31386,31387,31390,31393,31394,31395,31396,31399, +31401,31402,31403,31406,31407,31408,31409,31410,31412,31413,31414,31415,31416, +31417,31418,31419,31420,31421,31422,31424,31425,31426,31427,31428,31429,31430, +31431,31432,31433,31434,31436,31437,31438,31439,31440,31441,31442,31443,31444, +31445,31447,31448,31450,31451,31452,31453,31457,31458,31460,31463,31464,31465, +31466,31467,31468,31470,31472,31473,31474,31475,U,31476,31477,31478,31479, +31480,31483,31484,31486,31488,31489,31490,31493,31495,31497,31500,31501,31502, +31504,31506,31507,31510,31511,31512,31514,31516,31517,31519,31521,31522,31523, +31527,31529,31533,31535,31536,31538,31540,31541,31542,31543,31545,31547,31549, +31551,31552,31553,31554,31555,31556,31558,31560,31562,31565,31566,31571,31573, +31575,31577,31580,31582,31583,31585,31587,31588,31589,31590,31591,31592,31593, +31594,31595,31596,31597,31599,31600,31603,31604,31606,31608,31610,31612,31613, +31615,31617,31618,31619,31620,31622,31623,31624,31625,31626,31627,31628,31630, +31631,U,31633,31634,31635,31638,31640,31641,31642,31643,31646,31647,31648, +31651,31652,31653,31662,31663,31664,31666,31667,31669,31670,31671,31673,31674, +31675,31676,31677,31678,31679,31680,31682,31683,31684,31685,31688,31689,31690, +31691,31693,31694,31695,31696,31698,31700,31701,31702,31703,31704,31707,31708, +31710,31711,31712,31714,31715,31716,31719,31720,31721,31723,31724,31725,31727, +31728,31730,31731,31732,31733,31734,31736,31737,31738,31739,31741,31743,31744, +31745,31746,31747,31748,31749,31750,31752,31753,31754,31757,31758,31760,31761, +31762,31763,31764,31765,31767,31768,31769,U,31770,31771,31772,31773,31774, +31776,31777,31778,31779,31780,31781,31784,31785,31787,31788,31789,31790,31791, +31792,31793,31794,31795,31796,31797,31798,31799,31801,31802,31803,31804,31805, +31806,31810,31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31822, +31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,31835, +31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848, +31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,31861,31862,31863, +31864,31865,31866,31870,31871,31872,31873,31874,31875,31876,31877,31878,31879, +U,31880,31882,31883,31884,31885,31886,31887,31888,31891,31892,31894,31897, +31898,31899,31904,31905,31907,31910,31911,31912,31913,31915,31916,31917,31919, +31920,31924,31925,31926,31927,31928,31930,31931,31935,31936,31938,31939,31940, +31942,31945,31947,31950,31951,31952,31953,31954,31955,31956,31960,31962,31963, +31965,31966,31969,31970,31971,31972,31973,31974,31975,31977,31978,31979,31980, +31981,31982,31984,31985,31986,31987,31988,31989,31990,31991,31993,31994,31996, +31997,31998,31999,32000,32001,32002,32003,32004,32005,32006,32007,32008,32009, +32011,32012,32013,32014,32015,32016,U,32017,32018,32019,32020,32021,32022, +32023,32024,32025,32026,32027,32028,32029,32030,32031,32033,32035,32036,32037, +32038,32040,32041,32042,32044,32045,32046,32048,32049,32050,32051,32052,32053, +32054,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,32066, +32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,32078,32079, +32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,32090,32091,32092, +32093,32094,32095,32096,32097,32098,32099,32100,32101,32102,32103,32104,32105, +32106,32107,32108,32109,32111,32112,32113,32114,32115,32116,32117,32118,U, +32120,32121,32122,32123,32124,32125,32126,32127,32128,32129,32130,32131,32132, +32133,32134,32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145, +32146,32147,32148,32149,32150,32151,32152,32153,32154,32155,32156,32157,32158, +32159,32160,32161,32162,32163,32164,32165,32167,32168,32169,32170,32171,32172, +32173,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,32186, +32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,32198,32199, +32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,32210,32211,32212, +32213,32214,32215,32216,32217,U,32218,32219,32220,32221,32222,32223,32224, +32225,32226,32227,32228,32229,32230,32231,32232,32233,32234,32235,32236,32237, +32238,32239,32240,32241,32242,32243,32244,32245,32246,32247,32248,32249,32250, +32251,32252,32253,32254,32255,32256,32257,32258,32259,32260,32261,32262,32263, +32264,32265,32266,32267,32268,32269,32270,32271,32272,32273,32274,32275,32276, +32277,32278,32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289, +32290,32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302, +32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,U,32314, +32316,32317,32318,32319,32320,32322,32323,32324,32325,32326,32328,32329,32330, +32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,32342,32343, +32344,32345,32346,32347,32348,32349,32350,32351,32352,32353,32354,32355,32356, +32357,32358,32359,32360,32361,32362,32363,32364,32365,32366,32367,32368,32369, +32370,32371,32372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382, +32383,32384,32385,32387,32388,32389,32390,32391,32392,32393,32394,32395,32396, +32397,32398,32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409, +32410,32412,32413,32414,U,32430,32436,32443,32444,32470,32484,32492,32505, +32522,32528,32542,32567,32569,32571,32572,32573,32574,32575,32576,32577,32579, +32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32594,32595,32598, +32601,32603,32604,32605,32606,32608,32611,32612,32613,32614,32615,32619,32620, +32621,32623,32624,32627,32629,32630,32631,32632,32634,32635,32636,32637,32639, +32640,32642,32643,32644,32645,32646,32647,32648,32649,32651,32653,32655,32656, +32657,32658,32659,32661,32662,32663,32664,32665,32667,32668,32672,32674,32675, +32677,32678,32680,32681,32682,32683,32684,32685,32686,32689,U,32691,32692, +32693,32694,32695,32698,32699,32702,32704,32706,32707,32708,32710,32711,32712, +32713,32715,32717,32719,32720,32721,32722,32723,32726,32727,32729,32730,32731, +32732,32733,32734,32738,32739,32740,32743,32744,32746,32747,32748,32749,32751, +32754,32756,32757,32758,32759,32760,32761,32762,32765,32766,32767,32770,32775, +32776,32777,32778,32782,32783,32785,32787,32794,32795,32797,32798,32799,32801, +32803,32804,32811,32812,32813,32814,32815,32816,32818,32820,32825,32826,32828, +32830,32832,32833,32836,32837,32839,32840,32841,32846,32847,32848,32849,32851, +32853,32854,32855,U,32857,32859,32860,32861,32862,32863,32864,32865,32866, +32867,32868,32869,32870,32871,32872,32875,32876,32877,32878,32879,32880,32882, +32883,32884,32885,32886,32887,32888,32889,32890,32891,32892,32893,32894,32897, +32898,32901,32904,32906,32909,32910,32911,32912,32913,32914,32916,32917,32919, +32921,32926,32931,32934,32935,32936,32940,32944,32947,32949,32950,32952,32953, +32955,32965,32967,32968,32969,32970,32971,32975,32976,32977,32978,32979,32980, +32981,32984,32991,32992,32994,32995,32998,33006,33013,33015,33017,33019,33022, +33023,33024,33025,33027,33028,33029,33031,33032,33035,U,33036,33045,33047, +33049,33051,33052,33053,33055,33056,33057,33058,33059,33060,33061,33062,33063, +33064,33065,33066,33067,33069,33070,33072,33075,33076,33077,33079,33081,33082, +33083,33084,33085,33087,33088,33089,33090,33091,33092,33093,33095,33097,33101, +33102,33103,33106,33110,33111,33112,33115,33116,33117,33118,33119,33121,33122, +33123,33124,33126,33128,33130,33131,33132,33135,33138,33139,33141,33142,33143, +33144,33153,33155,33156,33157,33158,33159,33161,33163,33164,33165,33166,33168, +33170,33171,33172,33173,33174,33175,33177,33178,33182,33183,33184,33185,33186, +33188,33189,U,33191,33193,33195,33196,33197,33198,33199,33200,33201,33202, +33204,33205,33206,33207,33208,33209,33212,33213,33214,33215,33220,33221,33223, +33224,33225,33227,33229,33230,33231,33232,33233,33234,33235,33236,33237,33238, +33239,33240,33241,33242,33243,33244,33245,33246,33247,33248,33249,33250,33252, +33253,33254,33256,33257,33259,33262,33263,33264,33265,33266,33269,33270,33271, +33272,33273,33274,33277,33279,33283,33287,33288,33289,33290,33291,33294,33295, +33297,33299,33301,33302,33303,33304,33305,33306,33309,33312,33316,33317,33318, +33319,33321,33326,33330,33338,33340,33341,33343,U,33344,33345,33346,33347, +33349,33350,33352,33354,33356,33357,33358,33360,33361,33362,33363,33364,33365, +33366,33367,33369,33371,33372,33373,33374,33376,33377,33378,33379,33380,33381, +33382,33383,33385,33386,33387,33388,33389,33393,33397,33398,33399,33400,33403, +33404,33408,33409,33411,33413,33414,33415,33417,33420,33424,33427,33428,33429, +33430,33434,33435,33438,33440,33442,33443,33447,33458,33461,33462,33466,33467, +33468,33471,33472,33474,33475,33477,33478,33481,33488,33494,33497,33498,33501, +33506,33511,33512,33513,33514,33516,33517,33518,33520,33522,33523,33525,33526, +33528,U,33530,33532,33533,33534,33535,33536,33546,33547,33549,33552,33554, +33555,33558,33560,33561,33565,33566,33567,33568,33569,33570,33571,33572,33573, +33574,33577,33578,33582,33584,33586,33591,33595,33597,33598,33599,33601,33602, +33604,33605,33608,33610,33611,33612,33613,33614,33619,33621,33622,33623,33624, +33625,33629,33634,33648,33649,33650,33651,33652,33653,33654,33657,33658,33662, +33663,33664,33665,33666,33667,33668,33671,33672,33674,33675,33676,33677,33679, +33680,33681,33684,33685,33686,33687,33689,33690,33693,33695,33697,33698,33699, +33700,33701,33702,33703,33708,33709,33710,U,33711,33717,33723,33726,33727, +33730,33731,33732,33734,33736,33737,33739,33741,33742,33744,33745,33746,33747, +33749,33751,33753,33754,33755,33758,33762,33763,33764,33766,33767,33768,33771, +33772,33773,33774,33775,33779,33780,33781,33782,33783,33786,33787,33788,33790, +33791,33792,33794,33797,33799,33800,33801,33802,33808,33810,33811,33812,33813, +33814,33815,33817,33818,33819,33822,33823,33824,33825,33826,33827,33833,33834, +33835,33836,33837,33838,33839,33840,33842,33843,33844,33845,33846,33847,33849, +33850,33851,33854,33855,33856,33857,33858,33859,33860,33861,33863,33864,33865, +U,33866,33867,33868,33869,33870,33871,33872,33874,33875,33876,33877,33878, +33880,33885,33886,33887,33888,33890,33892,33893,33894,33895,33896,33898,33902, +33903,33904,33906,33908,33911,33913,33915,33916,33917,33918,33919,33920,33921, +33923,33924,33925,33926,33930,33933,33935,33936,33937,33938,33939,33940,33941, +33942,33944,33946,33947,33949,33950,33951,33952,33954,33955,33956,33957,33958, +33959,33960,33961,33962,33963,33964,33965,33966,33968,33969,33971,33973,33974, +33975,33979,33980,33982,33984,33986,33987,33989,33990,33991,33992,33995,33996, +33998,33999,34002,34004,34005,34007,U,34008,34009,34010,34011,34012,34014, +34017,34018,34020,34023,34024,34025,34026,34027,34029,34030,34031,34033,34034, +34035,34036,34037,34038,34039,34040,34041,34042,34043,34045,34046,34048,34049, +34050,34051,34052,34053,34054,34055,34056,34057,34058,34059,34061,34062,34063, +34064,34066,34068,34069,34070,34072,34073,34075,34076,34077,34078,34080,34082, +34083,34084,34085,34086,34087,34088,34089,34090,34093,34094,34095,34096,34097, +34098,34099,34100,34101,34102,34110,34111,34112,34113,34114,34116,34117,34118, +34119,34123,34124,34125,34126,34127,34128,34129,34130,34131,34132,34133,U, +34135,34136,34138,34139,34140,34141,34143,34144,34145,34146,34147,34149,34150, +34151,34153,34154,34155,34156,34157,34158,34159,34160,34161,34163,34165,34166, +34167,34168,34172,34173,34175,34176,34177,34178,34179,34182,34184,34185,34186, +34187,34188,34189,34190,34192,34193,34194,34195,34196,34197,34198,34199,34200, +34201,34202,34205,34206,34207,34208,34209,34210,34211,34213,34214,34215,34217, +34219,34220,34221,34225,34226,34227,34228,34229,34230,34232,34234,34235,34236, +34237,34238,34239,34240,34242,34243,34244,34245,34246,34247,34248,34250,34251, +34252,34253,34254,34257,34258,U,34260,34262,34263,34264,34265,34266,34267, +34269,34270,34271,34272,34273,34274,34275,34277,34278,34279,34280,34282,34283, +34284,34285,34286,34287,34288,34289,34290,34291,34292,34293,34294,34295,34296, +34297,34298,34300,34301,34302,34304,34305,34306,34307,34308,34310,34311,34312, +34313,34314,34315,34316,34317,34318,34319,34320,34322,34323,34324,34325,34327, +34328,34329,34330,34331,34332,34333,34334,34335,34336,34337,34338,34339,34340, +34341,34342,34344,34346,34347,34348,34349,34350,34351,34352,34353,34354,34355, +34356,34357,34358,34359,34361,34362,34363,34365,34366,34367,34368,U,34369, +34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34386,34387, +34389,34390,34391,34392,34393,34395,34396,34397,34399,34400,34401,34403,34404, +34405,34406,34407,34408,34409,34410,34413,34415,34416,34418,34419,34420,34421, +34422,34423,34424,34435,34436,34437,34438,34439,34440,34441,34446,34447,34448, +34449,34450,34452,34454,34455,34456,34457,34458,34459,34462,34463,34464,34465, +34466,34469,34470,34475,34477,34478,34482,34483,34487,34488,34489,34491,34492, +34493,34494,34495,34497,34498,34499,34501,34504,34508,34509,34514,34515,34517, +34518,34519,34522,34524,U,34525,34528,34529,34530,34531,34533,34534,34535, +34536,34538,34539,34540,34543,34549,34550,34551,34554,34555,34556,34557,34559, +34561,34564,34565,34566,34571,34572,34574,34575,34576,34577,34580,34582,34585, +34587,34589,34591,34592,34596,34598,34599,34600,34602,34603,34604,34605,34607, +34608,34610,34611,34613,34614,34616,34617,34618,34620,34621,34624,34625,34626, +34627,34628,34629,34630,34634,34635,34637,34639,34640,34641,34642,34644,34645, +34646,34648,34650,34651,34652,34653,34654,34655,34657,34658,34662,34663,34664, +34665,34666,34667,34668,34669,34671,34673,34674,34675,34677,U,34679,34680, +34681,34682,34687,34688,34689,34692,34694,34695,34697,34698,34700,34702,34703, +34704,34705,34706,34708,34709,34710,34712,34713,34714,34715,34716,34717,34718, +34720,34721,34722,34723,34724,34725,34726,34727,34729,34730,34734,34736,34737, +34738,34740,34742,34743,34744,34745,34747,34748,34750,34751,34753,34754,34755, +34756,34757,34759,34760,34761,34764,34765,34766,34767,34768,34772,34773,34774, +34775,34776,34777,34778,34780,34781,34782,34783,34785,34786,34787,34788,34790, +34791,34792,34793,34795,34796,34797,34799,34800,34801,34802,34803,34804,34805, +34806,34807,34808,U,34810,34811,34812,34813,34815,34816,34817,34818,34820, +34821,34822,34823,34824,34825,34827,34828,34829,34830,34831,34832,34833,34834, +34836,34839,34840,34841,34842,34844,34845,34846,34847,34848,34851,34852,34853, +34854,34855,34856,34857,34858,34859,34860,34861,34862,34863,34864,34865,34867, +34868,34869,34870,34871,34872,34874,34875,34877,34878,34879,34881,34882,34883, +34886,34887,34888,34889,34890,34891,34894,34895,34896,34897,34898,34899,34901, +34902,34904,34906,34907,34908,34909,34910,34911,34912,34918,34919,34922,34925, +34927,34929,34931,34932,34933,34934,34936,34937,34938,U,34939,34940,34944, +34947,34950,34951,34953,34954,34956,34958,34959,34960,34961,34963,34964,34965, +34967,34968,34969,34970,34971,34973,34974,34975,34976,34977,34979,34981,34982, +34983,34984,34985,34986,34988,34990,34991,34992,34994,34995,34996,34997,34998, +35000,35001,35002,35003,35005,35006,35007,35008,35011,35012,35015,35016,35018, +35019,35020,35021,35023,35024,35025,35027,35030,35031,35034,35035,35036,35037, +35038,35040,35041,35046,35047,35049,35050,35051,35052,35053,35054,35055,35058, +35061,35062,35063,35066,35067,35069,35071,35072,35073,35075,35076,35077,35078, +35079,35080,U,35081,35083,35084,35085,35086,35087,35089,35092,35093,35094, +35095,35096,35100,35101,35102,35103,35104,35106,35107,35108,35110,35111,35112, +35113,35116,35117,35118,35119,35121,35122,35123,35125,35127,35128,35129,35130, +35131,35132,35133,35134,35135,35136,35138,35139,35141,35142,35143,35144,35145, +35146,35147,35148,35149,35150,35151,35152,35153,35154,35155,35156,35157,35158, +35159,35160,35161,35162,35163,35164,35165,35168,35169,35170,35171,35172,35173, +35175,35176,35177,35178,35179,35180,35181,35182,35183,35184,35185,35186,35187, +35188,35189,35190,35191,35192,35193,35194,35196,U,35197,35198,35200,35202, +35204,35205,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217, +35218,35219,35220,35221,35222,35223,35224,35225,35226,35227,35228,35229,35230, +35231,35232,35233,35234,35235,35236,35237,35238,35239,35240,35241,35242,35243, +35244,35245,35246,35247,35248,35249,35250,35251,35252,35253,35254,35255,35256, +35257,35258,35259,35260,35261,35262,35263,35264,35267,35277,35283,35284,35285, +35287,35288,35289,35291,35293,35295,35296,35297,35298,35300,35303,35304,35305, +35306,35308,35309,35310,35312,35313,35314,35316,35317,35318,35319,35320,35321, +35322,U,35323,35324,35325,35326,35327,35329,35330,35331,35332,35333,35334, +35336,35337,35338,35339,35340,35341,35342,35343,35344,35345,35346,35347,35348, +35349,35350,35351,35352,35353,35354,35355,35356,35357,35358,35359,35360,35361, +35362,35363,35364,35365,35366,35367,35368,35369,35370,35371,35372,35373,35374, +35375,35376,35377,35378,35379,35380,35381,35382,35383,35384,35385,35386,35387, +35388,35389,35391,35392,35393,35394,35395,35396,35397,35398,35399,35401,35402, +35403,35404,35405,35406,35407,35408,35409,35410,35411,35412,35413,35414,35415, +35416,35417,35418,35419,35420,35421,35422,U,35423,35424,35425,35426,35427, +35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440, +35441,35442,35443,35444,35445,35446,35447,35448,35450,35451,35452,35453,35454, +35455,35456,35457,35458,35459,35460,35461,35462,35463,35464,35467,35468,35469, +35470,35471,35472,35473,35474,35476,35477,35478,35479,35480,35481,35482,35483, +35484,35485,35486,35487,35488,35489,35490,35491,35492,35493,35494,35495,35496, +35497,35498,35499,35500,35501,35502,35503,35504,35505,35506,35507,35508,35509, +35510,35511,35512,35513,35514,35515,35516,35517,35518,35519,35520,35521,35522, +U,35523,35524,35525,35526,35527,35528,35529,35530,35531,35532,35533,35534, +35535,35536,35537,35538,35539,35540,35541,35542,35543,35544,35545,35546,35547, +35548,35549,35550,35551,35552,35553,35554,35555,35556,35557,35558,35559,35560, +35561,35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573, +35574,35575,35576,35577,35578,35579,35580,35581,35582,35583,35584,35585,35586, +35587,35588,35589,35590,35592,35593,35594,35595,35596,35597,35598,35599,35600, +35601,35602,35603,35604,35605,35606,35607,35608,35609,35610,35611,35612,35613, +35614,35615,35616,35617,35618,35619,U,35620,35621,35623,35624,35625,35626, +35627,35628,35629,35630,35631,35632,35633,35634,35635,35636,35637,35638,35639, +35640,35641,35642,35643,35644,35645,35646,35647,35648,35649,35650,35651,35652, +35653,35654,35655,35656,35657,35658,35659,35660,35661,35662,35663,35664,35665, +35666,35667,35668,35669,35670,35671,35672,35673,35674,35675,35676,35677,35678, +35679,35680,35681,35682,35683,35684,35685,35687,35688,35689,35690,35691,35693, +35694,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706, +35707,35708,35709,35710,35711,35712,35713,35714,35715,35716,35717,35718,U, +35719,35720,35721,35722,35723,35724,35725,35726,35727,35728,35729,35730,35731, +35732,35733,35734,35735,35736,35737,35738,35739,35740,35741,35742,35743,35756, +35761,35771,35783,35792,35818,35849,35870,35896,35897,35898,35899,35900,35901, +35902,35903,35904,35906,35907,35908,35909,35912,35914,35915,35917,35918,35919, +35920,35921,35922,35923,35924,35926,35927,35928,35929,35931,35932,35933,35934, +35935,35936,35939,35940,35941,35942,35943,35944,35945,35948,35949,35950,35951, +35952,35953,35954,35956,35957,35958,35959,35963,35964,35965,35966,35967,35968, +35969,35971,35972,35974,35975,U,35976,35979,35981,35982,35983,35984,35985, +35986,35987,35989,35990,35991,35993,35994,35995,35996,35997,35998,35999,36000, +36001,36002,36003,36004,36005,36006,36007,36008,36009,36010,36011,36012,36013, +36014,36015,36016,36017,36018,36019,36020,36021,36022,36023,36024,36025,36026, +36027,36028,36029,36030,36031,36032,36033,36034,36035,36036,36037,36038,36039, +36040,36041,36042,36043,36044,36045,36046,36047,36048,36049,36050,36051,36052, +36053,36054,36055,36056,36057,36058,36059,36060,36061,36062,36063,36064,36065, +36066,36067,36068,36069,36070,36071,36072,36073,36074,36075,36076,U,36077, +36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089,36090, +36091,36092,36093,36094,36095,36096,36097,36098,36099,36100,36101,36102,36103, +36104,36105,36106,36107,36108,36109,36110,36111,36112,36113,36114,36115,36116, +36117,36118,36119,36120,36121,36122,36123,36124,36128,36177,36178,36183,36191, +36197,36200,36201,36202,36204,36206,36207,36209,36210,36216,36217,36218,36219, +36220,36221,36222,36223,36224,36226,36227,36230,36231,36232,36233,36236,36237, +36238,36239,36240,36242,36243,36245,36246,36247,36248,36249,36250,36251,36252, +36253,36254,36256,36257,U,36258,36260,36261,36262,36263,36264,36265,36266, +36267,36268,36269,36270,36271,36272,36274,36278,36279,36281,36283,36285,36288, +36289,36290,36293,36295,36296,36297,36298,36301,36304,36306,36307,36308,36309, +36312,36313,36316,36320,36321,36322,36325,36326,36327,36329,36333,36334,36336, +36337,36338,36340,36342,36348,36350,36351,36352,36353,36354,36355,36356,36358, +36359,36360,36363,36365,36366,36368,36369,36370,36371,36373,36374,36375,36376, +36377,36378,36379,36380,36384,36385,36388,36389,36390,36391,36392,36395,36397, +36400,36402,36403,36404,36406,36407,36408,36411,36412,36414,U,36415,36419, +36421,36422,36428,36429,36430,36431,36432,36435,36436,36437,36438,36439,36440, +36442,36443,36444,36445,36446,36447,36448,36449,36450,36451,36452,36453,36455, +36456,36458,36459,36462,36465,36467,36469,36471,36472,36473,36474,36475,36477, +36478,36480,36482,36483,36484,36486,36488,36489,36490,36491,36492,36493,36494, +36497,36498,36499,36501,36502,36503,36504,36505,36506,36507,36509,36511,36512, +36513,36514,36515,36516,36517,36518,36519,36520,36521,36522,36525,36526,36528, +36529,36531,36532,36533,36534,36535,36536,36537,36539,36540,36541,36542,36543, +36544,36545,36546,U,36547,36548,36549,36550,36551,36552,36553,36554,36555, +36556,36557,36559,36560,36561,36562,36563,36564,36565,36566,36567,36568,36569, +36570,36571,36572,36573,36574,36575,36576,36577,36578,36579,36580,36581,36582, +36583,36584,36585,36586,36587,36588,36589,36590,36591,36592,36593,36594,36595, +36596,36597,36598,36599,36600,36601,36602,36603,36604,36605,36606,36607,36608, +36609,36610,36611,36612,36613,36614,36615,36616,36617,36618,36619,36620,36621, +36622,36623,36624,36625,36626,36627,36628,36629,36630,36631,36632,36633,36634, +36635,36636,36637,36638,36639,36640,36641,36642,36643,U,36644,36645,36646, +36647,36648,36649,36650,36651,36652,36653,36654,36655,36656,36657,36658,36659, +36660,36661,36662,36663,36664,36665,36666,36667,36668,36669,36670,36671,36672, +36673,36674,36675,36676,36677,36678,36679,36680,36681,36682,36683,36684,36685, +36686,36687,36688,36689,36690,36691,36692,36693,36694,36695,36696,36697,36698, +36699,36700,36701,36702,36703,36704,36705,36706,36707,36708,36709,36714,36736, +36748,36754,36765,36768,36769,36770,36772,36773,36774,36775,36778,36780,36781, +36782,36783,36786,36787,36788,36789,36791,36792,36794,36795,36796,36799,36800, +36803,36806,U,36809,36810,36811,36812,36813,36815,36818,36822,36823,36826, +36832,36833,36835,36839,36844,36847,36849,36850,36852,36853,36854,36858,36859, +36860,36862,36863,36871,36872,36876,36878,36883,36885,36888,36889,36892,36899, +36900,36901,36903,36904,36905,36906,36907,36908,36912,36913,36914,36915,36916, +36919,36921,36922,36925,36927,36928,36931,36933,36934,36936,36937,36938,36939, +36940,36942,36948,36949,36950,36953,36954,36956,36957,36958,36959,36960,36961, +36964,36966,36967,36969,36970,36971,36972,36975,36976,36977,36978,36979,36982, +36983,36984,36985,36986,36987,36988,36990,36993,U,36996,36997,36998,36999, +37001,37002,37004,37005,37006,37007,37008,37010,37012,37014,37016,37018,37020, +37022,37023,37024,37028,37029,37031,37032,37033,37035,37037,37042,37047,37052, +37053,37055,37056,37058,37059,37062,37064,37065,37067,37068,37069,37074,37076, +37077,37078,37080,37081,37082,37086,37087,37088,37091,37092,37093,37097,37098, +37100,37102,37104,37105,37106,37107,37109,37110,37111,37113,37114,37115,37116, +37119,37120,37121,37123,37125,37126,37127,37128,37129,37130,37131,37132,37133, +37134,37135,37136,37137,37138,37139,37140,37141,37142,37143,37144,37146,37147, +37148,U,37149,37151,37152,37153,37156,37157,37158,37159,37160,37161,37162, +37163,37164,37165,37166,37168,37170,37171,37172,37173,37174,37175,37176,37178, +37179,37180,37181,37182,37183,37184,37185,37186,37188,37189,37191,37192,37201, +37203,37204,37205,37206,37208,37209,37211,37212,37215,37216,37222,37223,37224, +37227,37229,37235,37242,37243,37244,37248,37249,37250,37251,37252,37254,37256, +37258,37262,37263,37267,37268,37269,37270,37271,37272,37273,37276,37277,37278, +37279,37280,37281,37284,37285,37286,37287,37288,37289,37291,37292,37296,37297, +37298,37299,37302,37303,37304,37305,37307,U,37308,37309,37310,37311,37312, +37313,37314,37315,37316,37317,37318,37320,37323,37328,37330,37331,37332,37333, +37334,37335,37336,37337,37338,37339,37341,37342,37343,37344,37345,37346,37347, +37348,37349,37350,37351,37352,37353,37354,37355,37356,37357,37358,37359,37360, +37361,37362,37363,37364,37365,37366,37367,37368,37369,37370,37371,37372,37373, +37374,37375,37376,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386, +37387,37388,37389,37390,37391,37392,37393,37394,37395,37396,37397,37398,37399, +37400,37401,37402,37403,37404,37405,37406,37407,37408,37409,37410,37411,37412, +U,37413,37414,37415,37416,37417,37418,37419,37420,37421,37422,37423,37424, +37425,37426,37427,37428,37429,37430,37431,37432,37433,37434,37435,37436,37437, +37438,37439,37440,37441,37442,37443,37444,37445,37446,37447,37448,37449,37450, +37451,37452,37453,37454,37455,37456,37457,37458,37459,37460,37461,37462,37463, +37464,37465,37466,37467,37468,37469,37470,37471,37472,37473,37474,37475,37476, +37477,37478,37479,37480,37481,37482,37483,37484,37485,37486,37487,37488,37489, +37490,37491,37493,37494,37495,37496,37497,37498,37499,37500,37501,37502,37503, +37504,37505,37506,37507,37508,37509,U,37510,37511,37512,37513,37514,37515, +37516,37517,37519,37520,37521,37522,37523,37524,37525,37526,37527,37528,37529, +37530,37531,37532,37533,37534,37535,37536,37537,37538,37539,37540,37541,37542, +37543,37544,37545,37546,37547,37548,37549,37551,37552,37553,37554,37555,37556, +37557,37558,37559,37560,37561,37562,37563,37564,37565,37566,37567,37568,37569, +37570,37571,37572,37573,37574,37575,37577,37578,37579,37580,37581,37582,37583, +37584,37585,37586,37587,37588,37589,37590,37591,37592,37593,37594,37595,37596, +37597,37598,37599,37600,37601,37602,37603,37604,37605,37606,37607,37608,U, +37609,37610,37611,37612,37613,37614,37615,37616,37617,37618,37619,37620,37621, +37622,37623,37624,37625,37626,37627,37628,37629,37630,37631,37632,37633,37634, +37635,37636,37637,37638,37639,37640,37641,37642,37643,37644,37645,37646,37647, +37648,37649,37650,37651,37652,37653,37654,37655,37656,37657,37658,37659,37660, +37661,37662,37663,37664,37665,37666,37667,37668,37669,37670,37671,37672,37673, +37674,37675,37676,37677,37678,37679,37680,37681,37682,37683,37684,37685,37686, +37687,37688,37689,37690,37691,37692,37693,37695,37696,37697,37698,37699,37700, +37701,37702,37703,37704,37705,U,37706,37707,37708,37709,37710,37711,37712, +37713,37714,37715,37716,37717,37718,37719,37720,37721,37722,37723,37724,37725, +37726,37727,37728,37729,37730,37731,37732,37733,37734,37735,37736,37737,37739, +37740,37741,37742,37743,37744,37745,37746,37747,37748,37749,37750,37751,37752, +37753,37754,37755,37756,37757,37758,37759,37760,37761,37762,37763,37764,37765, +37766,37767,37768,37769,37770,37771,37772,37773,37774,37776,37777,37778,37779, +37780,37781,37782,37783,37784,37785,37786,37787,37788,37789,37790,37791,37792, +37793,37794,37795,37796,37797,37798,37799,37800,37801,37802,37803,U,37804, +37805,37806,37807,37808,37809,37810,37811,37812,37813,37814,37815,37816,37817, +37818,37819,37820,37821,37822,37823,37824,37825,37826,37827,37828,37829,37830, +37831,37832,37833,37835,37836,37837,37838,37839,37840,37841,37842,37843,37844, +37845,37847,37848,37849,37850,37851,37852,37853,37854,37855,37856,37857,37858, +37859,37860,37861,37862,37863,37864,37865,37866,37867,37868,37869,37870,37871, +37872,37873,37874,37875,37876,37877,37878,37879,37880,37881,37882,37883,37884, +37885,37886,37887,37888,37889,37890,37891,37892,37893,37894,37895,37896,37897, +37898,37899,37900,37901,U,37902,37903,37904,37905,37906,37907,37908,37909, +37910,37911,37912,37913,37914,37915,37916,37917,37918,37919,37920,37921,37922, +37923,37924,37925,37926,37927,37928,37929,37930,37931,37932,37933,37934,37935, +37936,37937,37938,37939,37940,37941,37942,37943,37944,37945,37946,37947,37948, +37949,37951,37952,37953,37954,37955,37956,37957,37958,37959,37960,37961,37962, +37963,37964,37965,37966,37967,37968,37969,37970,37971,37972,37973,37974,37975, +37976,37977,37978,37979,37980,37981,37982,37983,37984,37985,37986,37987,37988, +37989,37990,37991,37992,37993,37994,37996,37997,37998,37999,U,38000,38001, +38002,38003,38004,38005,38006,38007,38008,38009,38010,38011,38012,38013,38014, +38015,38016,38017,38018,38019,38020,38033,38038,38040,38087,38095,38099,38100, +38106,38118,38139,38172,38176,38183,38195,38205,38211,38216,38219,38229,38234, +38240,38254,38260,38261,38263,38264,38265,38266,38267,38268,38269,38270,38272, +38273,38274,38275,38276,38277,38278,38279,38280,38281,38282,38283,38284,38285, +38286,38287,38288,38289,38290,38291,38292,38293,38294,38295,38296,38297,38298, +38299,38300,38301,38302,38303,38304,38305,38306,38307,38308,38309,38310,38311, +38312,38313,38314,U,38315,38316,38317,38318,38319,38320,38321,38322,38323, +38324,38325,38326,38327,38328,38329,38330,38331,38332,38333,38334,38335,38336, +38337,38338,38339,38340,38341,38342,38343,38344,38345,38346,38347,38348,38349, +38350,38351,38352,38353,38354,38355,38356,38357,38358,38359,38360,38361,38362, +38363,38364,38365,38366,38367,38368,38369,38370,38371,38372,38373,38374,38375, +38380,38399,38407,38419,38424,38427,38430,38432,38435,38436,38437,38438,38439, +38440,38441,38443,38444,38445,38447,38448,38455,38456,38457,38458,38462,38465, +38467,38474,38478,38479,38481,38482,38483,38486,38487,U,38488,38489,38490, +38492,38493,38494,38496,38499,38501,38502,38507,38509,38510,38511,38512,38513, +38515,38520,38521,38522,38523,38524,38525,38526,38527,38528,38529,38530,38531, +38532,38535,38537,38538,38540,38542,38545,38546,38547,38549,38550,38554,38555, +38557,38558,38559,38560,38561,38562,38563,38564,38565,38566,38568,38569,38570, +38571,38572,38573,38574,38575,38577,38578,38580,38581,38583,38584,38586,38587, +38591,38594,38595,38600,38602,38603,38608,38609,38611,38612,38614,38615,38616, +38617,38618,38619,38620,38621,38622,38623,38625,38626,38627,38628,38629,38630, +38631,38635,U,38636,38637,38638,38640,38641,38642,38644,38645,38648,38650, +38651,38652,38653,38655,38658,38659,38661,38666,38667,38668,38672,38673,38674, +38676,38677,38679,38680,38681,38682,38683,38685,38687,38688,38689,38690,38691, +38692,38693,38694,38695,38696,38697,38699,38700,38702,38703,38705,38707,38708, +38709,38710,38711,38714,38715,38716,38717,38719,38720,38721,38722,38723,38724, +38725,38726,38727,38728,38729,38730,38731,38732,38733,38734,38735,38736,38737, +38740,38741,38743,38744,38746,38748,38749,38751,38755,38756,38758,38759,38760, +38762,38763,38764,38765,38766,38767,38768,38769,U,38770,38773,38775,38776, +38777,38778,38779,38781,38782,38783,38784,38785,38786,38787,38788,38790,38791, +38792,38793,38794,38796,38798,38799,38800,38803,38805,38806,38807,38809,38810, +38811,38812,38813,38814,38815,38817,38818,38820,38821,38822,38823,38824,38825, +38826,38828,38830,38832,38833,38835,38837,38838,38839,38840,38841,38842,38843, +38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856, +38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869, +38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882, +38883,U,38884,38885,38888,38894,38895,38896,38897,38898,38900,38903,38904, +38905,38906,38907,38908,38909,38910,38911,38912,38913,38914,38915,38916,38917, +38918,38919,38920,38921,38922,38923,38924,38925,38926,38927,38928,38929,38930, +38931,38932,38933,38934,38935,38936,38937,38938,38939,38940,38941,38942,38943, +38944,38945,38946,38947,38948,38949,38950,38951,38952,38953,38954,38955,38956, +38957,38958,38959,38960,38961,38962,38963,38964,38965,38966,38967,38968,38969, +38970,38971,38972,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982, +38983,38984,38985,38986,38987,38988,38989,U,38990,38991,38992,38993,38994, +38995,38996,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39007, +39008,39009,39010,39011,39012,39013,39014,39015,39016,39017,39018,39019,39020, +39021,39022,39023,39024,39025,39026,39027,39028,39051,39054,39058,39061,39065, +39075,39080,39081,39082,39083,39084,39085,39086,39087,39088,39089,39090,39091, +39092,39093,39094,39095,39096,39097,39098,39099,39100,39101,39102,39103,39104, +39105,39106,39107,39108,39109,39110,39111,39112,39113,39114,39115,39116,39117, +39119,39120,39124,39126,39127,39131,39132,39133,39136,39137,39138,39139,39140, +U,39141,39142,39145,39146,39147,39148,39149,39150,39151,39152,39153,39154, +39155,39156,39157,39158,39159,39160,39161,39162,39163,39164,39165,39166,39167, +39168,39169,39170,39171,39172,39173,39174,39175,39176,39177,39178,39179,39180, +39182,39183,39185,39186,39187,39188,39189,39190,39191,39192,39193,39194,39195, +39196,39197,39198,39199,39200,39201,39202,39203,39204,39205,39206,39207,39208, +39209,39210,39211,39212,39213,39215,39216,39217,39218,39219,39220,39221,39222, +39223,39224,39225,39226,39227,39228,39229,39230,39231,39232,39233,39234,39235, +39236,39237,39238,39239,39240,39241,U,39242,39243,39244,39245,39246,39247, +39248,39249,39250,39251,39254,39255,39256,39257,39258,39259,39260,39261,39262, +39263,39264,39265,39266,39268,39270,39283,39288,39289,39291,39294,39298,39299, +39305,39308,39310,39322,39323,39324,39325,39326,39327,39328,39329,39330,39331, +39332,39334,39335,39337,39338,39339,39340,39341,39342,39343,39344,39345,39346, +39347,39348,39349,39350,39351,39352,39353,39354,39355,39356,39357,39358,39359, +39360,39361,39362,39363,39364,39365,39366,39367,39368,39369,39370,39371,39372, +39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383,39384,U, +39385,39386,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396,39397, +39398,39399,39400,39401,39402,39403,39404,39405,39406,39407,39408,39409,39410, +39411,39412,39413,39414,39415,39416,39417,39418,39419,39420,39421,39422,39423, +39424,39425,39426,39427,39428,39429,39430,39431,39432,39433,39434,39435,39436, +39437,39438,39439,39440,39441,39442,39443,39444,39445,39446,39447,39448,39449, +39450,39451,39452,39453,39454,39455,39456,39457,39458,39459,39460,39461,39462, +39463,39464,39465,39466,39467,39468,39469,39470,39471,39472,39473,39474,39475, +39476,39477,39478,39479,39480,U,39481,39482,39483,39484,39485,39486,39487, +39488,39489,39490,39491,39492,39493,39494,39495,39496,39497,39498,39499,39500, +39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39511,39512,39513, +39514,39515,39516,39517,39518,39519,39520,39521,39522,39523,39524,39525,39526, +39527,39528,39529,39530,39531,39538,39555,39561,39565,39566,39572,39573,39577, +39590,39593,39594,39595,39596,39597,39598,39599,39602,39603,39604,39605,39609, +39611,39613,39614,39615,39619,39620,39622,39623,39624,39625,39626,39629,39630, +39631,39632,39634,39636,39637,39638,39639,39641,39642,39643,39644,U,39645, +39646,39648,39650,39651,39652,39653,39655,39656,39657,39658,39660,39662,39664, +39665,39666,39667,39668,39669,39670,39671,39672,39674,39676,39677,39678,39679, +39680,39681,39682,39684,39685,39686,39687,39689,39690,39691,39692,39693,39694, +39696,39697,39698,39700,39701,39702,39703,39704,39705,39706,39707,39708,39709, +39710,39712,39713,39714,39716,39717,39718,39719,39720,39721,39722,39723,39724, +39725,39726,39728,39729,39731,39732,39733,39734,39735,39736,39737,39738,39741, +39742,39743,39744,39750,39754,39755,39756,39758,39760,39762,39763,39765,39766, +39767,39768,39769,39770,U,39771,39772,39773,39774,39775,39776,39777,39778, +39779,39780,39781,39782,39783,39784,39785,39786,39787,39788,39789,39790,39791, +39792,39793,39794,39795,39796,39797,39798,39799,39800,39801,39802,39803,39804, +39805,39806,39807,39808,39809,39810,39811,39812,39813,39814,39815,39816,39817, +39818,39819,39820,39821,39822,39823,39824,39825,39826,39827,39828,39829,39830, +39831,39832,39833,39834,39835,39836,39837,39838,39839,39840,39841,39842,39843, +39844,39845,39846,39847,39848,39849,39850,39851,39852,39853,39854,39855,39856, +39857,39858,39859,39860,39861,39862,39863,39864,39865,39866,U,39867,39868, +39869,39870,39871,39872,39873,39874,39875,39876,39877,39878,39879,39880,39881, +39882,39883,39884,39885,39886,39887,39888,39889,39890,39891,39892,39893,39894, +39895,39896,39897,39898,39899,39900,39901,39902,39903,39904,39905,39906,39907, +39908,39909,39910,39911,39912,39913,39914,39915,39916,39917,39918,39919,39920, +39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933, +39934,39935,39936,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946, +39947,39948,39949,39950,39951,39952,39953,39954,39955,39956,39957,39958,39959, +39960,39961,39962,U,39963,39964,39965,39966,39967,39968,39969,39970,39971, +39972,39973,39974,39975,39976,39977,39978,39979,39980,39981,39982,39983,39984, +39985,39986,39987,39988,39989,39990,39991,39992,39993,39994,39995,39996,39997, +39998,39999,40000,40001,40002,40003,40004,40005,40006,40007,40008,40009,40010, +40011,40012,40013,40014,40015,40016,40017,40018,40019,40020,40021,40022,40023, +40024,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,40035,40036, +40037,40038,40039,40040,40041,40042,40043,40044,40045,40046,40047,40048,40049, +40050,40051,40052,40053,40054,40055,40056,40057,40058,U,40059,40061,40062, +40064,40067,40068,40073,40074,40076,40079,40083,40086,40087,40088,40089,40093, +40106,40108,40111,40121,40126,40127,40128,40129,40130,40136,40137,40145,40146, +40154,40155,40160,40161,40163,40164,40165,40166,40167,40168,40169,40170,40171, +40172,40173,40174,40175,40176,40177,40178,40179,40180,40181,40182,40183,40184, +40185,40186,40187,40188,40189,40190,40191,40192,40193,40194,40195,40196,40197, +40198,40199,40200,40201,40202,40203,40204,40205,40206,40207,40208,40209,40210, +40211,40212,40213,40214,40215,40216,40217,40218,40219,40220,40221,40222,40223, +40224,40225,U,40226,40227,40228,40229,40230,40231,40232,40233,40234,40235, +40236,40237,40238,40239,40240,40241,40242,40243,40244,40245,40246,40247,40248, +40249,40250,40251,40252,40253,40254,40255,40256,40257,40258,40259,40260,40261, +40262,40263,40264,40265,40266,40267,40268,40269,40270,40271,40272,40273,40274, +40275,40276,40277,40278,40279,40280,40281,40282,40283,40284,40285,40286,40287, +40288,40289,40290,40291,40292,40293,40294,40295,40296,40297,40298,40299,40300, +40301,40302,40303,40304,40305,40306,40307,40308,40309,40310,40311,40312,40313, +40314,40315,40316,40317,40318,40319,40320,40321,U,40322,40323,40324,40325, +40326,40327,40328,40329,40330,40331,40332,40333,40334,40335,40336,40337,40338, +40339,40340,40341,40342,40343,40344,40345,40346,40347,40348,40349,40350,40351, +40352,40353,40354,40355,40356,40357,40358,40359,40360,40361,40362,40363,40364, +40365,40366,40367,40368,40369,40370,40371,40372,40373,40374,40375,40376,40377, +40378,40379,40380,40381,40382,40383,40384,40385,40386,40387,40388,40389,40390, +40391,40392,40393,40394,40395,40396,40397,40398,40399,40400,40401,40402,40403, +40404,40405,40406,40407,40408,40409,40410,40411,40412,40413,40414,40415,40416, +40417,U,40418,40419,40420,40421,40422,40423,40424,40425,40426,40427,40428, +40429,40430,40431,40432,40433,40434,40435,40436,40437,40438,40439,40440,40441, +40442,40443,40444,40445,40446,40447,40448,40449,40450,40451,40452,40453,40454, +40455,40456,40457,40458,40459,40460,40461,40462,40463,40464,40465,40466,40467, +40468,40469,40470,40471,40472,40473,40474,40475,40476,40477,40478,40484,40487, +40494,40496,40500,40507,40508,40512,40525,40528,40530,40531,40532,40534,40537, +40541,40543,40544,40545,40546,40549,40558,40559,40562,40564,40565,40566,40567, +40568,40569,40570,40571,40572,40573,40576,U,40577,40579,40580,40581,40582, +40585,40586,40588,40589,40590,40591,40592,40593,40596,40597,40598,40599,40600, +40601,40602,40603,40604,40606,40608,40609,40610,40611,40612,40613,40615,40616, +40617,40618,40619,40620,40621,40622,40623,40624,40625,40626,40627,40629,40630, +40631,40633,40634,40636,40639,40640,40641,40642,40643,40645,40646,40647,40648, +40650,40651,40652,40656,40658,40659,40661,40662,40663,40665,40666,40670,40673, +40675,40676,40678,40680,40683,40684,40685,40686,40688,40689,40690,40691,40692, +40693,40694,40695,40696,40698,40701,40703,40704,40705,40706,40707,40708,40709, +U,40710,40711,40712,40713,40714,40716,40719,40721,40722,40724,40725,40726, +40728,40730,40731,40732,40733,40734,40735,40737,40739,40740,40741,40742,40743, +40744,40745,40746,40747,40749,40750,40752,40753,40754,40755,40756,40757,40758, +40760,40762,40764,40767,40768,40769,40770,40771,40773,40774,40775,40776,40777, +40778,40779,40780,40781,40782,40783,40786,40787,40788,40789,40790,40791,40792, +40793,40794,40795,40796,40797,40798,40799,40800,40801,40802,40803,40804,40805, +40806,40807,40808,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818, +40819,40820,40821,40822,40823,40824,U,40825,40826,40827,40828,40829,40830, +40833,40834,40845,40846,40847,40848,40849,40850,40851,40852,40853,40854,40855, +40856,40860,40861,40862,40865,40866,40867,40868,40869,63788,63865,63893,63975, +63985,64012,64013,64014,64015,64017,64019,64020,64024,64031,64032,64033,64035, +64036,64039,64040,64041, +}; + +static const struct dbcs_index gbkext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{__gbkext_decmap+0,64,254},{__gbkext_decmap+191,64, +254},{__gbkext_decmap+382,64,254},{__gbkext_decmap+573,64,254},{ +__gbkext_decmap+764,64,254},{__gbkext_decmap+955,64,254},{__gbkext_decmap+1146 +,64,254},{__gbkext_decmap+1337,64,254},{__gbkext_decmap+1528,64,254},{ +__gbkext_decmap+1719,64,254},{__gbkext_decmap+1910,64,254},{__gbkext_decmap+ +2101,64,254},{__gbkext_decmap+2292,64,254},{__gbkext_decmap+2483,64,254},{ +__gbkext_decmap+2674,64,254},{__gbkext_decmap+2865,64,254},{__gbkext_decmap+ +3056,64,254},{__gbkext_decmap+3247,64,254},{__gbkext_decmap+3438,64,254},{ +__gbkext_decmap+3629,64,254},{__gbkext_decmap+3820,64,254},{__gbkext_decmap+ +4011,64,254},{__gbkext_decmap+4202,64,254},{__gbkext_decmap+4393,64,254},{ +__gbkext_decmap+4584,64,254},{__gbkext_decmap+4775,64,254},{__gbkext_decmap+ +4966,64,254},{__gbkext_decmap+5157,64,254},{__gbkext_decmap+5348,64,254},{ +__gbkext_decmap+5539,64,254},{__gbkext_decmap+5730,64,254},{__gbkext_decmap+ +5921,64,254},{__gbkext_decmap+6112,164,170},{__gbkext_decmap+6119,161,170},{0, +0,0},{0,0,0},{0,0,0},{__gbkext_decmap+6129,224,245},{0,0,0},{__gbkext_decmap+ +6151,64,192},{__gbkext_decmap+6280,64,150},{__gbkext_decmap+6367,64,160},{ +__gbkext_decmap+6464,64,160},{__gbkext_decmap+6561,64,160},{__gbkext_decmap+ +6658,64,160},{__gbkext_decmap+6755,64,160},{__gbkext_decmap+6852,64,160},{ +__gbkext_decmap+6949,64,160},{__gbkext_decmap+7046,64,160},{__gbkext_decmap+ +7143,64,160},{__gbkext_decmap+7240,64,160},{__gbkext_decmap+7337,64,160},{ +__gbkext_decmap+7434,64,160},{__gbkext_decmap+7531,64,160},{__gbkext_decmap+ +7628,64,160},{__gbkext_decmap+7725,64,160},{__gbkext_decmap+7822,64,160},{ +__gbkext_decmap+7919,64,160},{__gbkext_decmap+8016,64,160},{__gbkext_decmap+ +8113,64,160},{__gbkext_decmap+8210,64,160},{__gbkext_decmap+8307,64,160},{ +__gbkext_decmap+8404,64,160},{__gbkext_decmap+8501,64,160},{__gbkext_decmap+ +8598,64,160},{__gbkext_decmap+8695,64,160},{__gbkext_decmap+8792,64,160},{ +__gbkext_decmap+8889,64,160},{__gbkext_decmap+8986,64,160},{__gbkext_decmap+ +9083,64,160},{__gbkext_decmap+9180,64,160},{__gbkext_decmap+9277,64,160},{ +__gbkext_decmap+9374,64,160},{__gbkext_decmap+9471,64,160},{__gbkext_decmap+ +9568,64,160},{__gbkext_decmap+9665,64,160},{__gbkext_decmap+9762,64,160},{ +__gbkext_decmap+9859,64,160},{__gbkext_decmap+9956,64,160},{__gbkext_decmap+ +10053,64,160},{__gbkext_decmap+10150,64,160},{__gbkext_decmap+10247,64,160},{ +__gbkext_decmap+10344,64,160},{__gbkext_decmap+10441,64,160},{__gbkext_decmap+ +10538,64,160},{__gbkext_decmap+10635,64,160},{__gbkext_decmap+10732,64,160},{ +__gbkext_decmap+10829,64,160},{__gbkext_decmap+10926,64,160},{__gbkext_decmap+ +11023,64,160},{__gbkext_decmap+11120,64,160},{__gbkext_decmap+11217,64,160},{ +__gbkext_decmap+11314,64,160},{__gbkext_decmap+11411,64,160},{__gbkext_decmap+ +11508,64,160},{__gbkext_decmap+11605,64,160},{__gbkext_decmap+11702,64,160},{ +__gbkext_decmap+11799,64,160},{__gbkext_decmap+11896,64,160},{__gbkext_decmap+ +11993,64,160},{__gbkext_decmap+12090,64,160},{__gbkext_decmap+12187,64,160},{ +__gbkext_decmap+12284,64,160},{__gbkext_decmap+12381,64,160},{__gbkext_decmap+ +12478,64,160},{__gbkext_decmap+12575,64,160},{__gbkext_decmap+12672,64,160},{ +__gbkext_decmap+12769,64,160},{__gbkext_decmap+12866,64,160},{__gbkext_decmap+ +12963,64,160},{__gbkext_decmap+13060,64,160},{__gbkext_decmap+13157,64,160},{ +__gbkext_decmap+13254,64,160},{__gbkext_decmap+13351,64,160},{__gbkext_decmap+ +13448,64,160},{__gbkext_decmap+13545,64,160},{__gbkext_decmap+13642,64,160},{ +__gbkext_decmap+13739,64,160},{__gbkext_decmap+13836,64,160},{__gbkext_decmap+ +13933,64,160},{__gbkext_decmap+14030,64,160},{__gbkext_decmap+14127,64,160},{ +__gbkext_decmap+14224,64,160},{__gbkext_decmap+14321,64,160},{__gbkext_decmap+ +14418,64,160},{__gbkext_decmap+14515,64,79},{0,0,0}, +}; + +static const DBCHAR __gbcommon_encmap[23231] = { +8552,N,N,8556,8487,N,N,N,N,N,N,N,8547,8512,N,N,N,N,N,41380,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8513,N,N,N,N,N,N,N,N,10276,10274, +N,N,N,N,N,N,10280,10278,10298,N,10284,10282,N,N,N,N,10288,10286,N,N,N,8514,N, +10292,10290,N,10297,10273,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10277,N,N,N,N,N,N, +N,10279,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10281,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,43197,N,N,N,43198,N,N,N,N,10285,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,10289,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10275, +N,10283,N,10287,N,10291,N,10293,N,10294,N,10295,N,10296,43195,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,43200,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8486,N,8485, +43072,43073,N,N,N,N,N,N,N,N,N,N,N,N,N,43074,9761,9762,9763,9764,9765,9766, +9767,9768,9769,9770,9771,9772,9773,9774,9775,9776,9777,N,9778,9779,9780,9781, +9782,9783,9784,N,N,N,N,N,N,N,9793,9794,9795,9796,9797,9798,9799,9800,9801, +9802,9803,9804,9805,9806,9807,9808,9809,N,9810,9811,9812,9813,9814,9815,9816, +10023,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10017,10018,10019,10020,10021,10022,10024, +10025,10026,10027,10028,10029,10030,10031,10032,10033,10034,10035,10036,10037, +10038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,10049,10065, +10066,10067,10068,10069,10070,10072,10073,10074,10075,10076,10077,10078,10079, +10080,10081,10082,10083,10084,10085,10086,10087,10088,10089,10090,10091,10092, +10093,10094,10095,10096,10097,N,10071,43356,N,N,43075,41386,8490,8492,N,8494, +8495,N,N,8496,8497,N,N,N,N,N,N,N,43077,8493,N,N,N,N,N,N,N,N,N,8555,N,8548, +8549,N,43078,N,N,N,N,N,8569,8550,N,43079,N,N,N,43080,N,N,N,N,N,N,N,N,N,N,N,N, +8557,N,N,N,N,N,N,N,N,N,N,43353,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +8817,8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,8828,N,N,N,N,41633, +41634,41635,41636,41637,41638,41639,41640,41641,41642,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,8571,8572,8570,8573,N,N,43081,43082,43083,43084,8522,N,N, +N,N,N,N,8519,N,8518,N,N,N,43085,N,N,N,N,8524,N,N,8536,8542,43086,8527,N,N, +43087,N,8526,N,8516,8517,8521,8520,8530,N,N,8531,N,N,N,N,N,8544,8543,8515, +8523,N,N,N,N,N,8535,N,N,N,N,N,N,N,N,N,N,8534,N,N,N,8533,N,N,N,N,N,43088,N,N,N, +N,N,N,N,N,N,N,N,N,N,8537,8532,N,N,8540,8541,43089,43090,N,N,N,N,N,N,8538,8539, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43154,N,N,N,8529,N,N,N,N,N,N,N,N,N,N,N,8525,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,43091,8528,8793,8794,8795,8796,8797,8798,8799,8800,8801,8802, +N,N,N,N,N,N,N,N,N,N,8773,8774,8775,8776,8777,8778,8779,8780,8781,8782,8783, +8784,8785,8786,8787,8788,8789,8790,8791,8792,8753,8754,8755,8756,8757,8758, +8759,8760,8761,8762,8763,8764,8765,8766,8767,8768,8769,8770,8771,8772,10532, +10533,10534,10535,10536,10537,10538,10539,10540,10541,10542,10543,10544,10545, +10546,10547,10548,10549,10550,10551,10552,10553,10554,10555,10556,10557,10558, +10559,10560,10561,10562,10563,10564,10565,10566,10567,10568,10569,10570,10571, +10572,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584, +10585,10586,10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597, +10598,10599,10600,10601,10602,10603,10604,10605,10606,10607,N,N,N,N,43092, +43093,43094,43095,43096,43097,43098,43099,43100,43101,43102,43103,43104,43105, +43106,43107,43108,43109,43110,43111,43112,43113,43114,43115,43116,43117,43118, +43119,43120,43121,43122,43123,43124,43125,43126,43127,N,N,N,N,N,N,N,N,N,N,N,N, +N,43128,43129,43130,43131,43132,43133,43134,43136,43137,43138,43139,43140, +43141,43142,43143,N,N,N,43144,43145,43146,N,N,N,N,N,N,N,N,N,N,8566,8565,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,8568,8567,N,N,N,N,N,N,N,N,43147,43148,N,N,N,N,N,N,N, +N,8564,8563,N,N,N,8560,N,N,8562,8561,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43149,43150,43151,43152,8559,8558,N,N,43153,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +8546,N,8545,8481,8482,8483,8488,N,8489,43365,43414,8500,8501,8502,8503,8504, +8505,8506,8507,8510,8511,43155,8574,8498,8499,8508,8509,N,N,N,N,N,43156,43157, +N,N,43328,43329,43330,43331,43332,43333,43334,43335,43336,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258, +9259,9260,9261,9262,9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273, +9274,9275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288, +9289,9290,9291,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303, +9304,9305,9306,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318, +9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,N,N,N,N,N,N, +N,43361,43362,43366,43367,N,N,9505,9506,9507,9508,9509,9510,9511,9512,9513, +9514,9515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528, +9529,9530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543, +9544,9545,9546,9547,9548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558, +9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573, +9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588, +9589,9590,N,N,N,N,8484,43360,43363,43364,10309,10310,10311,10312,10313,10314, +10315,10316,10317,10318,10319,10320,10321,10322,10323,10324,10325,10326,10327, +10328,10329,10330,10331,10332,10333,10334,10335,10336,10337,10338,10339,10340, +10341,10342,10343,10344,10345,8805,8806,8807,8808,8809,8810,8811,8812,8813, +8814,N,N,N,N,N,N,N,43354,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,43337,43338,43339,N,N,N,N,N,N,N,N,N,N,N,N,43340,43341,43342, +N,N,43343,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43344,N,N,N,N,N,N,N,N,N,43345,N,N,43346,43347,N,N,43348,21051,13857,33088, +18015,33089,33090,33091,19826,21833,18557,18767,20290,22562,12859,21355,33092, +22564,13171,33093,22312,18258,22567,19008,33094,18288,12667,21045,13396,13867, +19263,22569,33095,33096,33097,13866,33098,16701,20815,33099,18725,22573,33100, +14454,20798,25436,22096,33101,33102,14177,33103,13358,33104,16729,33105,22588, +33106,19816,13604,20010,22135,33107,16502,15961,22575,33108,33109,33110,17483, +33111,15939,33112,22577,17204,21093,33113,22062,20058,21799,14965,14118,16470, +33114,17977,17746,18247,33115,14676,33116,13131,21074,33117,33118,22591,15941, +18034,21042,20272,20327,33119,33120,33121,33122,19049,33123,33124,22592,33125, +33126,33127,33128,33129,33130,17010,16978,33131,18537,33132,33133,33134,33135, +33136,33137,33138,33139,33140,33141,18220,33142,33143,33144,33145,33146,33147, +33148,16715,33149,21352,21881,33150,19010,13950,22561,21338,16247,33152,21574, +15141,22593,20069,15918,33153,33154,22568,33155,20807,20521,33156,33157,33158, +22589,22895,19830,16186,33159,15675,14885,21088,12922,14944,17462,33160,20333, +15913,19748,16705,33161,33162,33163,18263,22897,33164,22900,33165,33166,33167, +33168,18507,22633,33169,33170,33171,21082,18994,18506,22636,22634,22598,15734, +17997,13168,33172,22635,15729,15721,33173,18516,13395,33174,33175,16984,33176, +12886,22352,19019,19323,21836,14390,20297,33177,33178,33179,22874,22640,18218, +33180,22638,33181,13434,16750,21076,33182,33183,22637,33184,21063,22639,17223, +33185,33186,33187,20854,33188,22105,22642,33189,22645,15486,15451,33190,33191, +33192,18510,33193,14173,33194,14146,33195,18035,33196,33197,33198,33199,33200, +33201,33202,22648,21057,33203,33204,20073,15423,14204,14117,20573,33205,33206, +33207,33208,33209,22106,21317,15215,15201,22641,33210,33211,18721,20016,13355, +33212,22643,33213,18763,22646,16983,22647,33214,33215,20017,22649,33216,33217, +33218,12846,14656,33219,22819,33220,12393,33221,16742,33222,18796,33223,19269, +33224,19270,22820,33225,33226,33227,33228,33229,13672,33230,33231,13611,33232, +33233,33234,33235,33236,33237,20027,13645,22305,22388,21331,33238,19557,33239, +14926,33240,22818,22876,21344,22653,14192,22391,22654,22650,22817,17507,33241, +33242,21302,22644,22877,33243,22651,33244,17765,33245,33246,16464,33247,33248, +20848,12379,33249,33250,15441,22822,33251,22821,33252,33253,33254,33255,22828, +22830,33256,22827,19001,33257,33258,33259,22825,22070,33260,33261,33262,13150, +22824,33263,16509,33264,19020,33265,22826,33266,22823,33267,33268,22832,33269, +33270,13873,33271,33272,33273,14633,33274,21056,33275,33276,20288,33277,33278, +16962,33344,15684,21868,12896,18248,16235,22829,33345,22831,33346,20074,14958, +33347,33348,33349,33350,33351,18262,33352,33353,33354,33355,33356,33357,33358, +33359,33360,12643,33361,33362,33363,13401,13933,22836,33364,33365,33366,33367, +16161,33368,33369,33370,22878,18254,16510,22840,33371,33372,33373,33374,33375, +19287,14205,33376,22837,33377,22839,12579,21345,22841,33378,20549,33379,22838, +33380,33381,22833,33382,22834,16681,22835,33383,33384,15475,20574,14377,33385, +15971,33386,22845,33387,33388,33389,33390,22842,33391,12339,33392,33393,33394, +22850,33395,33396,33397,33398,33399,33400,33401,33402,33403,33404,33405,33406, +33408,22852,12598,33409,22847,33410,33411,13625,33412,15987,33413,33414,33415, +19528,14962,21072,33416,22851,33417,33418,15720,33419,13099,33420,33421,33422, +22853,15979,33423,22854,22843,17503,33424,22846,22849,22848,33425,33426,33427, +33428,33429,33430,33431,33432,33433,33434,33435,21806,33436,22069,33437,18275, +33438,33439,33440,33441,22856,33442,33443,33444,15449,22858,33445,33446,33447, +22844,33448,22859,17963,33449,33450,33451,33452,33453,22857,33454,33455,33456, +33457,22390,33458,19747,33459,33460,33461,33462,33463,33464,33465,33466,15649, +33467,33468,33469,33470,33471,33472,22860,33473,33474,33475,33476,33477,33478, +33479,33480,33481,17724,19765,33482,33483,33484,22861,33485,33486,22855,13093, +16254,33487,33488,33489,33490,14389,33491,33492,16508,33493,33494,33495,33496, +12408,33497,33498,33499,33500,33501,33502,33503,33504,33505,33506,33507,33508, +33509,33510,33511,33512,33513,33514,33515,33516,33517,13430,33518,22862,33519, +22863,13346,22864,33520,33521,13407,33522,33523,33524,33525,33526,12353,33527, +33528,33529,33530,33531,33532,33533,22865,18741,33534,33600,33601,33602,33603, +33604,33605,33606,33607,33608,33609,33610,33611,33612,33613,33614,33615,33616, +33617,20337,33618,33619,33620,33621,33622,33623,22866,33624,33625,33626,16709, +33627,33628,33629,33630,33631,33632,33633,33634,33635,33636,33637,22870,18734, +33638,33639,33640,33641,22869,22868,22871,33642,33643,33644,33645,19291,33646, +15657,33647,33648,33649,33650,33651,17959,33652,33653,33654,33655,33656,33657, +33658,33659,33660,33661,22867,22872,33662,33664,33665,22873,33666,33667,33668, +33669,33670,33671,18533,33672,33673,33674,33675,33676,33677,33678,33679,33680, +33681,33682,33683,33684,33685,16476,33686,33687,33688,33689,33690,33691,33692, +33693,33694,33695,33696,33697,33698,33699,33700,33701,33702,33703,33704,33705, +33706,33707,33708,33709,33710,33711,33712,33713,33714,13945,22563,21578,33715, +21546,20566,13156,21847,33716,20296,14690,33717,16203,33718,17250,33719,33720, +33721,13906,33722,33723,19779,22894,22896,33724,33725,33726,13619,33727,13877, +33728,33729,33730,33731,33732,15908,33733,33734,18539,33735,33736,18475,33737, +33738,12363,14635,16761,22882,33739,16444,14642,33740,14680,20555,12664,18020, +15967,13668,22344,33741,20856,15462,19038,33742,33743,15421,22886,22631,33744, +33745,17498,33746,33747,14420,18493,33748,33749,12897,21593,33750,33751,33752, +33753,17200,33754,33755,17249,23074,18527,33756,20532,33757,15996,17705,33758, +33759,33760,14682,33761,23075,33762,21545,23076,33763,33764,33765,33766,33767, +22907,13868,33768,33769,14187,12665,22908,13157,15990,33770,16246,21041,16484, +33771,33772,33773,13875,22910,22909,33774,33775,15931,33776,33777,33778,18016, +33779,22332,23073,33780,16697,33781,13682,16744,33782,33783,15477,33784,13397, +33785,33786,33787,33788,33789,33790,33856,33857,33858,16733,33859,17533,33860, +33861,15416,14130,33862,33863,14191,33864,33865,33866,33867,33868,33869,22892, +33870,17982,33871,16173,15179,33872,33873,13642,33874,23369,20567,33875,19769, +12348,13174,15223,23370,14895,33876,21604,13622,13683,22614,18512,33877,33878, +14166,18256,22615,33879,16175,33880,33881,23355,22616,33882,33883,20556,15150, +33884,33885,33886,27454,16720,16757,21618,14421,13364,33887,13173,33888,33889, +18750,33890,33891,33892,17744,33893,33894,33895,17753,16507,33896,12656,33897, +22617,14670,33898,13629,33899,33900,22618,33901,33902,22086,19234,18479,18738, +13388,16204,33903,14708,33904,22619,22620,13927,15425,19562,33905,33906,33907, +33908,33909,33910,20343,33911,22621,18224,33912,33913,14672,15651,33914,33915, +19550,33916,17994,33917,33918,33920,33921,33922,22624,33923,22622,33924,33925, +22623,33926,33927,33928,12414,33929,15975,33930,18979,15476,33931,33932,33933, +33934,14385,33935,33936,14446,33937,33938,33939,33940,33941,33942,33943,33944, +33945,33946,22626,33947,15691,33948,22628,22627,33949,33950,33951,33952,33953, +17788,33954,33955,33956,33957,33958,33959,33960,22629,33961,33962,22630,33963, +33964,33965,33966,33967,33968,33969,16678,33970,18480,12396,14630,15443,20081, +23357,16723,33971,33972,33973,33974,13871,22138,17708,15705,23358,23359,33975, +33976,33977,16504,15906,16461,33978,33979,33980,33981,33982,33983,33984,33985, +33986,33987,23360,19014,33988,33989,33990,12842,33991,33992,33993,21314,33994, +17251,33995,20779,33996,33997,33998,33999,23362,34000,16469,34001,34002,34003, +23363,34004,16177,34005,34006,34007,34008,34009,34010,17468,34011,34012,34013, +34014,18266,34015,34016,34017,34018,34019,34020,34021,34022,34023,34024,34025, +23364,34026,34027,34028,34029,34030,34031,34032,34033,22888,18775,34034,34035, +34036,14644,20080,21576,34037,34038,34039,34040,12412,13394,34041,20569,34042, +34043,34044,34045,22889,34046,24139,22891,34112,34113,34114,34115,22576,15151, +12593,34116,13143,22606,34117,34118,21585,34119,34120,15667,16239,34121,20283, +34122,34123,22608,34124,34125,34126,14155,34127,34128,34129,22609,34130,34131, +34132,34133,34134,34135,34136,34137,34138,34139,17957,18296,21053,34140,34141, +22610,17508,34142,18990,34143,18215,34144,22566,34145,18813,20071,15196,12395, +34146,34147,34148,15146,20525,34149,12592,22372,22335,34150,13605,17012,17487, +34151,34152,12841,34153,12855,34154,12645,24370,21820,16168,16940,22613,16945, +34155,22612,20052,34156,23136,34157,20032,34158,34159,22580,17198,21281,20003, +34160,15412,18484,16977,34161,15981,20534,34162,23137,34163,34164,34165,34166, +18276,34167,34168,13095,34169,13938,19580,16506,34170,34171,16503,34172,20793, +20833,22599,34173,34174,34176,34177,34178,34179,34180,12894,34181,34182,16485, +34183,14961,34184,34185,22600,34186,21549,34187,34188,20321,22601,34189,22602, +20291,34190,13176,15943,34191,34192,34193,34194,22603,34195,34196,34197,34198, +34199,34200,34201,23372,34202,34203,34204,34205,18469,34206,34207,34208,20312, +34209,18558,12878,34210,34211,34212,34213,34214,21334,12902,15408,21329,19243, +14132,34215,34216,34217,14114,34218,34219,19045,34220,18465,19036,12644,20592, +34221,17745,34222,34223,34224,23365,13694,34225,34226,16218,14661,15972,16749, +34227,24374,24373,22075,15696,21849,12360,13859,16201,19496,24371,18999,21330, +34228,22607,21046,14917,19262,19518,34229,24375,13680,24372,34230,34231,34232, +21365,34233,13140,14455,34234,24378,34235,14927,15402,13685,34236,19756,17275, +14963,16500,19778,20338,24376,20293,34237,16960,24377,17008,34238,34239,34240, +15997,34241,16735,19788,21111,14157,24385,34242,24388,34243,34244,14193,12361, +13910,14164,34245,14892,19581,16212,19249,18036,34246,22056,24389,34247,20066, +13107,34248,34249,20092,13365,34250,20039,14960,34251,20065,34252,20797,34253, +34254,24384,34255,34256,13428,34257,13130,34258,14438,24379,34259,34260,34261, +34262,17477,34263,24380,24381,24382,17723,24383,24386,21553,24387,34264,18234, +20056,34265,34266,34267,34268,34269,17496,34270,24394,34271,24399,34272,22108, +34273,34274,34275,34276,34277,34278,34279,34280,24393,24410,20022,34281,14919, +24398,24392,17758,34282,34283,18795,14964,17276,34284,34285,15959,34286,24390, +34287,24397,34288,17752,34289,34290,34291,34292,21798,14925,34293,15948,21309, +14400,34294,22116,34295,24391,14654,16167,34296,34297,16764,24395,24396,34298, +24400,34299,34300,34301,34302,34368,24411,24421,34369,24407,24406,22345,24419, +24420,25963,21031,24402,34370,16169,34371,21595,34372,16200,24404,34373,34374, +34375,20300,34376,34377,24413,34378,20810,34379,24414,12327,17975,24403,34380, +14949,34381,13919,19803,14718,21589,34382,34383,24415,20332,12325,24423,24401, +20806,24405,24408,24409,24412,34384,15145,34385,24416,24417,34386,24418,24422, +24424,21300,34387,34388,34389,34390,34391,14439,17718,24426,18778,16680,17476, +34392,34393,16222,20344,34394,34395,34396,21852,24430,34397,34398,34399,34400, +34401,34402,12856,34403,14943,24428,34404,23361,34405,20836,34406,34407,34408, +34409,19316,13373,34410,12326,34411,34412,34413,34414,34415,24433,19526,24434, +34416,34417,24429,34418,34419,34420,34421,34422,34423,24425,34424,34425,34426, +34427,24427,34428,24431,24432,15165,34429,34430,24435,34432,34433,24436,34434, +15139,34435,19035,20008,24615,13098,34436,24614,34437,34438,34439,24609,34440, +34441,34442,34443,24446,34444,19801,24444,34445,24442,34446,16208,22340,34447, +18764,34448,34449,24440,12321,34450,34451,34452,34453,34454,24445,34455,34456, +34457,34458,24443,24610,34459,34460,34461,34462,34463,24616,34464,34465,34466, +34467,14152,34468,34469,17953,18742,16434,24437,34470,34471,17726,34472,22596, +24441,17526,34473,34474,34475,34476,34477,34478,24611,24612,24613,20517,34479, +34480,24628,19556,34481,24625,34482,16166,24623,20025,24619,18758,34483,34484, +16430,24622,14957,14896,24617,34485,34486,34487,24438,34488,24627,34489,34490, +24632,34491,34492,34493,13357,24633,34494,34495,20274,14920,34496,24624,34497, +34498,34499,34500,34501,34502,34503,20602,34504,34505,34506,34507,34508,34509, +34510,34511,34512,24620,34513,21627,34514,24439,34515,17767,34516,24621,34517, +21367,34518,24630,24631,34519,34520,34521,34522,34523,24644,20577,34524,34525, +34526,24636,34527,34528,24649,24650,34529,34530,34531,24638,24618,18724,24641, +34532,24626,34533,34534,34535,34536,34537,19016,24643,34538,24629,34539,20043, +34540,19267,24653,24646,24642,34541,24651,34542,24634,24639,24640,34543,34544, +24645,34545,34546,24647,24648,34547,24652,34548,24635,34549,34550,34551,34552, +34553,19284,24661,34554,24662,24658,34555,34556,34557,34558,34624,34625,24656, +15438,34626,34627,24657,34628,14402,22597,34629,34630,34631,34632,34633,34634, +34635,34636,20586,34637,34638,17007,34639,34640,24655,24637,34641,34642,34643, +24660,24659,34644,34645,24663,34646,34647,34648,34649,24668,24664,34650,34651, +34652,22134,13104,34653,22380,34654,19259,34655,34656,24666,34657,20091,34658, +34659,34660,14937,34661,34662,34663,34664,34665,34666,34667,34668,34669,34670, +34671,34672,24673,24669,21037,34673,34674,34675,34676,34677,24674,34678,34679, +24667,24665,24671,34680,34681,24672,34682,34683,34684,34685,34686,24670,34688, +24676,34689,34690,34691,18039,22572,21611,24678,19017,34692,34693,34694,34695, +24677,34696,34697,34698,34699,14401,34700,34701,34702,34703,24679,24680,34704, +34705,34706,34707,34708,34709,34710,34711,24681,24675,34712,34713,34714,34715, +34716,34717,34718,14911,19559,34719,34720,34721,24682,34722,34723,34724,34725, +34726,34727,34728,34729,34730,34731,34732,34733,34734,34735,34736,20345,34737, +34738,34739,34740,34741,34742,34743,34744,34745,34746,34747,24683,34748,34749, +34750,34751,34752,34753,34754,18498,34755,34756,34757,34758,15680,34759,34760, +34761,34762,34763,34764,34765,34766,34767,34768,34769,34770,34771,17490,34772, +34773,34774,34775,34776,34777,34778,34779,34780,24684,34781,34782,24685,34783, +34784,18292,19268,34785,24686,15192,22582,21106,24687,19781,34786,13914,34787, +34788,34789,34790,34791,34792,24689,34793,21552,34794,34795,16423,13393,34796, +34797,20007,24688,34798,34799,34800,24690,14668,34801,34802,14714,19772,24691, +34803,34804,34805,18004,24692,34806,21554,34807,18470,24694,24693,34808,34809, +34810,34811,34812,34813,34814,34880,34881,34882,34883,34884,34885,34886,34887, +34888,34889,24695,34890,34891,19777,34892,34893,34894,18981,34895,34896,34897, +34898,21594,23383,23385,34899,23384,14695,23388,23389,13656,34900,34901,23386, +34902,34903,34904,34905,34906,23387,13089,23391,34907,34908,15224,34909,22071, +34910,23392,34911,34912,34913,34914,15993,34915,34916,14139,34917,23376,19502, +16178,15157,22392,16211,34918,34919,34920,34921,34922,16233,34923,34924,15457, +19507,23390,12371,20075,14168,22329,17986,34925,34926,16420,34927,19513,34928, +23399,23393,17978,23395,34929,23400,34930,17783,34931,34932,34933,23402,34934, +34935,23401,16192,34936,34937,34938,23398,23397,34939,34940,34941,34942,34944, +13369,16428,16930,23394,23396,34945,34946,34947,34948,20557,23405,34949,34950, +34951,34952,34953,16477,23410,34954,34955,34956,34957,34958,34959,34960,13922, +34961,34962,34963,34964,23411,23378,14648,21547,23404,34965,16209,23408,34966, +23377,34967,13670,34968,23403,16229,34969,34970,34971,23406,34972,23409,34973, +34974,34975,23417,34976,34977,34978,34979,34980,34981,34982,34983,34984,14625, +12323,34985,34986,34987,34988,34989,34990,34991,17009,34992,34993,13127,23407, +34994,34995,23416,34996,18002,23412,34997,34998,23413,23415,23414,34999,35000, +23422,35001,21362,12858,35002,35003,35004,23421,35005,35006,35007,35008,35009, +35010,35011,35012,23588,35013,23419,35014,35015,35016,35017,23418,35018,35019, +35020,23420,17760,15225,35021,35022,23587,35023,35024,23589,35025,19523,35026, +35027,35028,13905,23872,35029,35030,35031,23585,35032,23586,35033,35034,35035, +18229,35036,35037,35038,13929,35039,35040,35041,23591,35042,35043,35044,35045, +23590,35046,23593,12580,35047,35048,13644,35049,35050,35051,35052,35053,16176, +35054,35055,35056,35057,35058,20831,35059,35060,35061,35062,13890,35063,35064, +35065,35066,35067,35068,35069,35070,35136,35137,35138,35139,35140,35141,23592, +35142,35143,35144,35145,35146,35147,35148,19322,27507,35149,35150,35151,19292, +35152,35153,19326,35154,35155,35156,19521,35157,35158,35159,35160,35161,18555, +35162,35163,35164,35165,35166,35167,23594,35168,35169,35170,35171,35172,19566, +23595,35173,35174,35175,35176,35177,35178,35179,35180,35181,35182,35183,35184, +35185,35186,35187,35188,35189,23379,35190,23599,23596,35191,15923,35192,19067, +35193,35194,35195,23597,35196,35197,35198,35200,35201,35202,35203,35204,18762, +17465,35205,35206,35207,35208,35209,18237,23598,35210,35211,35212,21622,20582, +35213,35214,35215,35216,35217,35218,35219,35220,17451,13909,35221,35222,35223, +35224,35225,35226,35227,35228,35229,35230,35231,35232,35233,35234,35235,35236, +35237,35238,23380,35239,35240,35241,35242,12634,35243,35244,35245,23381,35246, +35247,35248,35249,35250,35251,35252,35253,35254,35255,35256,23382,35257,35258, +35259,14910,35260,35261,35262,35263,35264,35265,35266,35267,35268,35269,35270, +35271,35272,35273,18496,35274,35275,35276,35277,35278,35279,19007,18505,35280, +22323,35281,18809,35282,35283,16199,35284,35285,14968,35286,35287,21052,35288, +35289,35290,35291,35292,35293,35294,35295,25146,35296,13350,35297,35298,12600, +35299,35300,35301,35302,35303,14388,35304,20292,35305,35306,35307,35308,22887, +20262,19810,35309,35310,22893,13920,35311,21049,35312,35313,14651,35314,35315, +35316,35317,25145,25143,35318,13427,35319,19564,19499,14194,35320,22578,20843, +14907,35321,18983,35322,35323,19767,35324,35325,21060,16228,15440,13921,35326, +24133,35392,35393,35394,35395,24134,23356,35396,20825,35397,35398,18022,17486, +14190,35399,14172,35400,35401,16252,22368,35402,18037,35403,35404,12604,24136, +15665,19543,24138,35405,24137,35406,35407,35408,35409,35410,13676,35411,18781, +35412,35413,12354,35414,35415,35416,35417,35418,35419,35420,35421,35422,35423, +35424,35425,35426,17710,17707,35427,17484,35428,15465,19325,35429,35430,35431, +14915,35432,35433,35434,25977,18535,25978,19837,35435,22321,14398,17000,35436, +18513,35437,35438,25979,35439,35440,35441,35442,13898,15435,35443,35444,20861, +26145,35445,17262,35446,35447,35448,35449,26148,35450,35451,35452,35453,25982, +26149,19799,35454,35456,14145,25980,25981,26147,35457,35458,17501,26152,35459, +35460,26151,35461,35462,35463,35464,35465,35466,17219,35467,18014,35468,35469, +26154,35470,35471,35472,35473,35474,35475,35476,17463,35477,35478,35479,26146, +19004,35480,35481,35482,35483,15715,14659,26150,20565,20015,35484,35485,26153, +26160,35486,21030,35487,15658,26157,35488,35489,35490,35491,35492,26159,35493, +16465,35494,35495,21068,35496,35497,35498,15399,35499,35500,35501,35502,35503, +35504,35505,35506,35507,35508,35509,35510,26161,35511,21110,35512,35513,35514, +22347,35515,19838,35516,19806,16934,26155,26156,15679,26158,26163,35517,35518, +26162,35519,35520,35521,35522,26166,35523,26168,35524,35525,35526,35527,17519, +35528,35529,35530,17480,35531,35532,15978,18799,35533,35534,26167,35535,13936, +35536,35537,35538,17252,35539,35540,35541,35542,35543,35544,35545,21353,26164, +35546,26165,35547,18466,35548,35549,35550,35551,35552,26173,35553,35554,35555, +26169,35556,35557,35558,35559,35560,17989,35561,35562,19825,26171,35563,35564, +35565,35566,35567,35568,35569,35570,35571,35572,26172,35573,35574,35575,35576, +15209,35577,35578,35579,35580,35581,35582,35648,26174,35649,35650,35651,35652, +26170,35653,35654,16439,35655,35656,35657,35658,35659,35660,35661,35662,35663, +21284,26175,18804,26179,35664,35665,26180,35666,35667,35668,35669,20598,35670, +35671,35672,35673,35674,35675,35676,35677,35678,35679,35680,35681,35682,35683, +35684,35685,35686,35687,17213,35688,35689,35690,35691,35692,35693,35694,17220, +26178,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706, +35707,35708,26177,35709,35710,35712,35713,35714,35715,35716,26183,20273,35717, +27508,35718,35719,26186,35720,35721,35722,35723,35724,26181,35725,35726,15454, +18729,35727,35728,35729,35730,35731,35732,15413,35733,35734,20307,35735,35736, +35737,35738,35739,26184,35740,26185,35741,26190,35742,26192,35743,35744,35745, +26193,35746,35747,35748,26187,13653,35749,26188,35750,35751,26191,35752,35753, +17499,35754,26182,35755,35756,35757,35758,35759,26189,35760,35761,35762,35763, +35764,35765,35766,35767,35768,35769,35770,35771,35772,35773,35774,35775,35776, +35777,35778,35779,35780,35781,35782,26194,35783,35784,35785,35786,35787,35788, +35789,35790,35791,35792,35793,35794,26196,26195,35795,35796,35797,35798,35799, +35800,35801,35802,35803,35804,35805,35806,35807,35808,35809,35810,35811,35812, +35813,35814,35815,35816,35817,35818,35819,35820,26197,35821,22904,35822,35823, +26198,35824,35825,35826,35827,35828,35829,35830,35831,26199,35832,35833,35834, +35835,35836,35837,35838,35904,35905,35906,35907,35908,35909,35910,35911,22355, +26205,35912,26206,16215,21584,35913,22358,13414,19311,26202,22595,22350,20514, +35914,17231,35915,35916,26207,15422,14658,26203,20775,35917,35918,14882,16975, +35919,22571,35920,35921,35922,19051,25966,35923,26204,35924,14197,35925,35926, +35927,35928,18534,35929,35930,17525,35931,35932,25906,17534,35933,19324,25907, +21804,35934,21358,19032,12338,35935,19278,19818,35936,35937,14954,35938,35939, +35940,25909,35941,25908,35942,22362,14681,22118,13864,19824,21067,12582,18997, +35943,13160,18803,16205,20603,19026,25910,15170,35944,35945,35946,20316,14636, +35947,35948,35949,35950,21591,35951,35952,14886,20839,20348,15442,35953,25911, +18525,35954,35955,35956,16237,12662,19294,35957,35958,15429,35959,15428,21114, +17244,16220,35960,35961,35962,35963,14395,35964,35965,35966,17218,35968,14894, +21538,35969,35970,35971,35972,35973,35974,35975,35976,35977,18270,17455,12908, +35978,14673,35979,35980,25915,16712,35981,35982,21807,35983,35984,35985,35986, +35987,25916,35988,25918,35989,35990,35991,35992,35993,35994,35995,13415,13908, +19266,20784,13628,35996,35997,19033,35998,14178,35999,36000,18788,36001,15659, +36002,36003,20030,22384,36004,36005,36006,36007,20513,36008,18777,36009,36010, +13947,26200,15458,36011,13118,36012,18768,36013,26201,13090,36014,36015,36016, +36017,24140,36018,21320,24141,36019,21026,36020,36021,36022,36023,24142,36024, +36025,36026,36027,15949,36028,36029,24143,36030,36031,36032,18988,21116,13151, +25962,17505,15905,20018,17522,15958,17960,12899,36033,36034,15955,36035,36036, +18300,19563,15724,20061,36037,36038,19002,17985,25964,20540,36039,36040,36041, +21817,36042,36043,36044,25965,36045,36046,36047,36048,19060,36049,19776,16965, +36050,25967,36051,16964,25968,36052,36053,36054,36055,36056,36057,36058,25976, +19789,36059,18749,36060,36061,36062,36063,36064,36065,36066,21081,24872,36067, +36068,36069,36070,21356,36071,19306,18033,36072,36073,36074,36075,36076,24876, +36077,36078,36079,24871,24873,36080,36081,24874,24879,36082,36083,12909,36084, +24875,14426,24877,24878,24880,13626,24881,36085,36086,36087,36088,36089,24883, +24888,36090,36091,36092,36093,36094,20818,36160,24886,24885,16747,36161,36162, +36163,24887,36164,21568,36165,24882,36166,24890,12342,36167,36168,36169,36170, +24884,36171,16249,36172,24889,36173,36174,24891,36175,36176,36177,36178,36179, +36180,24894,36181,36182,36183,36184,36185,36186,24892,36187,36188,36189,36190, +36191,36192,22085,36193,36194,36195,36196,36197,36198,36199,20287,36200,36201, +24893,24895,16973,36202,13931,36203,21368,36204,36205,18253,36206,36207,14181, +36208,36209,36210,36211,36212,36213,36214,36215,36216,36217,15998,36218,36219, +36220,36221,36222,36224,24896,24897,36225,36226,24903,13159,36227,36228,36229, +36230,36231,36232,18025,36233,36234,36235,36236,36237,13406,36238,20802,36239, +36240,36241,36242,24904,36243,36244,24902,36245,36246,36247,36248,36249,24901, +36250,24899,24898,36251,12608,36252,36253,36254,21816,24900,36255,36256,36257, +36258,36259,24907,36260,36261,36262,36263,36264,36265,36266,36267,24908,24906, +36268,36269,36270,36271,36272,36273,36274,36275,28538,36276,36277,24915,24914, +18230,36278,36279,36280,36281,36282,36283,36284,36285,36286,36287,36288,24905, +36289,36290,24910,36291,24912,36292,36293,36294,36295,36296,36297,36298,36299, +36300,36301,36302,24916,36303,24913,24909,36304,36305,24911,36306,36307,36308, +36309,24917,36310,36311,36312,36313,36314,36315,36316,36317,36318,36319,36320, +36321,36322,24918,36323,36324,36325,36326,36327,36328,36329,36330,36331,36332, +36333,36334,36335,36336,36337,36338,36339,36340,36341,36342,36343,36344,24919, +36345,36346,36347,24920,36348,36349,36350,36416,36417,36418,36419,36420,36421, +36422,36423,36424,36425,36426,36427,36428,36429,36430,36431,36432,36433,36434, +36435,36436,36437,24922,36438,36439,36440,36441,36442,36443,36444,36445,36446, +36447,36448,36449,36450,24923,36451,36452,36453,36454,36455,36456,36457,20001, +36458,36459,36460,36461,36462,36463,36464,36465,36466,36467,36468,36469,36470, +26461,36471,13352,22109,36472,36473,20786,13106,36474,36475,14628,22387,18249, +15966,14638,36476,20055,36477,36478,12910,23375,36480,15418,21073,19272,12365, +36481,36482,20335,36483,36484,36485,36486,36487,22883,15725,36488,36489,12626, +19024,12860,36490,19239,14123,36491,18982,36492,36493,36494,20259,36495,36496, +24696,21834,24699,36497,36498,24698,17729,19579,36499,16689,24697,22115,12847, +22084,13659,36500,36501,36502,36503,36504,36505,36506,36507,13432,22049,36508, +36509,36510,36511,36512,20271,12399,36513,36514,24700,36515,36516,36517,36518, +36519,24865,13091,36520,36521,24701,24702,17201,36522,36523,36524,36525,17245, +36526,24866,14201,36527,36528,36529,36530,36531,36532,15183,36533,36534,36535, +36536,36537,36538,36539,24867,17467,36540,36541,36542,36543,36544,24868,36545, +36546,24869,36547,36548,24870,13361,36549,36550,36551,36552,36553,36554,36555, +36556,36557,36558,36559,36560,36561,36562,36563,14409,17981,17514,36564,12834, +36565,20562,36566,26459,15171,21335,21316,36567,14691,25167,36568,36569,36570, +22319,36571,18284,12627,36572,36573,13362,25169,36574,36575,36576,20594,16942, +25168,36577,16226,21286,13655,25170,13674,36578,17261,14461,36579,14382,36580, +17747,14159,25172,36581,36582,36583,36584,25171,13896,22393,36585,36586,36587, +36588,36589,19749,36590,36591,36592,36593,36594,25176,36595,25174,19068,16181, +21305,25173,36596,36597,36598,36599,25175,36600,36601,36602,36603,36604,36605, +36606,36672,36673,36674,16686,16456,36675,36676,36677,36678,36679,36680,25179, +25178,16426,36681,36682,16718,36683,36684,36685,36686,25180,36687,36688,36689, +36690,36691,36692,36693,36694,36695,36696,36697,36698,25181,36699,25182,36700, +36701,36702,36703,36704,36705,36706,36707,36708,23368,36709,20819,19746,36710, +36711,15656,36712,36713,36714,24131,22565,16170,23373,21100,18042,17706,36715, +36716,36717,24132,36718,12631,24366,36719,36720,36721,19005,36722,24369,36723, +14637,36724,21117,36725,14373,14955,36726,36727,13146,36728,36729,36730,13660, +21829,36731,36732,36733,36734,17238,20306,15137,36736,25971,25970,36737,36738, +25972,36739,19812,36740,18549,36741,36742,36743,36744,36745,36746,36747,13615, +18239,36748,25974,36749,36750,36751,27696,36752,36753,36754,36755,36756,36757, +36758,36759,36760,36761,36762,36763,36764,36765,36766,25958,36767,14697,13617, +36768,16956,25960,25959,25961,36769,36770,36771,36772,21069,36773,36774,36775, +24938,20558,36776,19758,36777,20837,36778,36779,12874,12651,36780,12658,17773, +36781,36782,21827,21296,36783,24924,36784,36785,36786,24925,36787,21083,36788, +13113,12619,36789,36790,36791,19833,21879,24926,36792,15926,13437,36793,24927, +14940,24928,15154,16969,24929,36794,36795,36796,20588,36797,19773,36798,36799, +24930,36800,13635,17735,24931,36801,36802,24932,36803,36804,36805,36806,21369, +36807,36808,36809,36810,36811,36812,24933,36813,20781,36814,36815,24934,20002, +36816,36817,36818,36819,36820,36821,24935,36822,13634,36823,36824,36825,36826, +24936,15189,36827,36828,36829,36830,36831,20548,25184,12632,21092,36832,36833, +25185,36834,36835,15433,18508,36836,25187,27774,27773,24367,36837,36838,36839, +25186,22078,19836,17190,36840,36841,36842,25411,36843,36844,22098,25191,36845, +36846,25192,36847,36848,21319,36849,36850,25196,16236,36851,25197,25189,36852, +36853,13120,36854,36855,36856,17518,36857,36858,25198,36859,36860,20547,36861, +14966,25193,14174,15155,19500,19275,25188,25190,25194,25195,36862,36928,36929, +25207,36930,36931,25204,21621,25203,36932,36933,17709,36934,21882,17730,12864, +36935,36936,25199,36937,25202,16687,19260,36938,36939,13601,25209,36940,36941, +36942,15409,25201,20564,21561,25205,14678,25206,36943,36944,36945,18259,36946, +36947,36948,36949,36950,25200,36951,36952,36953,36954,36955,22364,27937,36956, +36957,25208,36958,27941,25214,19025,36959,36960,36961,36962,36963,36964,36965, +16693,36966,15184,36967,36968,16214,36969,14947,36970,36971,19233,36972,36973, +36974,27942,27939,36975,36976,27938,36977,36978,36979,36980,15190,27943,20596, +36981,36982,27940,14942,13943,25377,13874,19569,14631,36983,20258,18209,36984, +36985,16210,36986,36987,13937,36988,25210,25211,25213,25212,17493,25378,36989, +21313,36990,36992,36993,25383,18244,36994,36995,36996,36997,20260,36998,36999, +25385,14903,37000,37001,37002,37003,25384,37004,15194,37005,25379,37006,37007, +37008,25380,25386,37009,25382,37010,20082,21318,37011,37012,15164,37013,37014, +21571,37015,17530,37016,37017,27944,20604,25381,37018,17269,37019,25389,12591, +37020,25394,37021,37022,37023,15426,37024,37025,25388,13631,37026,37027,37028, +37029,37030,37031,37032,37033,18281,25392,37034,37035,37036,15914,19823,37037, +37038,37039,37040,37041,15219,37042,37043,37044,19560,37045,37046,25391,37047, +25393,37048,20263,25390,37049,20009,15197,37050,37051,37052,37053,37054,13675, +15973,12882,13133,37055,12601,25387,12881,13612,14687,13928,37056,37057,20331, +25399,37058,15180,37059,37060,18503,20554,37061,37062,37063,37064,37065,25400, +13166,37066,37067,37068,37069,27945,37070,21370,21348,37071,37072,37073,27946, +25401,21090,37074,37075,37076,37077,37078,25397,37079,37080,37081,37082,21342, +37083,37084,37085,37086,14416,25395,37087,37088,25398,14175,37089,25396,16418, +37090,37091,37092,25402,37093,37094,37095,37096,37097,37098,37099,37100,37101, +37102,37103,37104,37105,37106,37107,37108,37109,37110,37111,21560,37112,37113, +37114,37115,37116,37117,37118,37184,13384,37185,25403,37186,15173,37187,18807, +37188,37189,18789,37190,37191,37192,17469,37193,37194,37195,37196,37197,37198, +37199,27947,37200,37201,37202,37203,17021,37204,37205,37206,37207,15195,16174, +37208,37209,37210,37211,37212,37213,37214,20031,37215,37216,37217,37218,25404, +37219,16182,37220,37221,37222,37223,37224,37225,37226,37227,37228,37229,37230, +37231,37232,37233,37234,37235,37236,37237,37238,12655,37239,37240,21623,37241, +37242,37243,37244,37245,25406,37246,37248,37249,37250,37251,37252,37253,37254, +27949,37255,37256,37257,37258,37259,37260,37261,37262,37263,25407,14889,27948, +37264,37265,25405,37266,37267,37268,37269,37270,37271,37272,37273,37274,37275, +25408,37276,37277,37278,37279,37280,37281,14902,37282,37283,37284,13870,37285, +37286,37287,37288,37289,20536,37290,12355,27950,37291,37292,37293,37294,37295, +27951,16449,37296,25409,37297,37298,37299,37300,37301,37302,37303,37304,37305, +37306,37307,37308,37309,37310,37311,37312,37313,17715,37314,37315,37316,37317, +37318,37319,37320,37321,37322,37323,37324,37325,37326,37327,25410,37328,37329, +37330,37331,37332,37333,37334,37335,37336,23602,37337,37338,37339,37340,37341, +37342,27952,37343,14442,37344,20076,27175,20583,19065,18518,20279,13129,20050, +15716,37345,37346,25438,15218,27176,21821,37347,18013,27177,37348,37349,37350, +27178,37351,27180,27179,37352,27182,27181,37353,37354,37355,37356,15704,37357, +27183,37358,16958,37359,37360,37361,37362,13377,13431,37363,37364,15143,37365, +37366,37367,37368,37369,27750,27749,14143,19321,12642,37370,27751,37371,37372, +37373,18760,27752,27753,37374,19030,24144,12869,21626,37440,37441,17995,12359, +13426,18515,37442,37443,37444,19792,37445,37446,16184,37447,37448,37449,37450, +37451,37452,37453,16219,37454,37455,18212,22068,37456,16425,24145,18728,20847, +17700,12391,13110,18501,37457,37458,12386,37459,37460,14198,37461,37462,17786, +37463,37464,13939,37465,21842,13136,15420,37466,37467,37468,13101,37469,37470, +37471,37472,15985,12369,37473,37474,37475,37476,37477,37478,21078,19043,22309, +37479,19766,13878,16185,21851,37480,14375,17751,37481,37482,37483,24146,16217, +16981,18240,37484,15140,12584,37485,37486,17770,37487,37488,17787,19495,37489, +37490,37491,37492,12583,37493,37494,37495,13654,37496,37497,37498,17448,37499, +24147,20794,13161,37500,17266,37501,37502,14199,37504,22132,13603,12912,17460, +17513,16429,24148,37505,12392,17732,16736,37506,14677,37507,15964,19800,12366, +37508,19791,24150,15952,22334,24149,21840,12381,37509,37510,17506,37511,37512, +16931,15472,37513,21301,16441,17697,12838,21617,37514,37515,16424,19011,24151, +21884,37516,14640,37517,18477,19241,37518,24153,16189,37519,37520,37521,37522, +17972,22311,18992,17475,37523,13142,14674,37524,37525,37526,37527,22072,27260, +12340,37528,37529,37530,37531,16230,37532,37533,19572,37534,37535,37536,37537, +19802,37538,37539,37540,22079,16974,37541,20046,19490,20526,17491,13618,24152, +21877,15415,15187,37542,37543,12324,37544,17714,13420,37545,37546,37547,21873, +37548,37549,27261,37550,37551,37552,37553,37554,37555,24154,19750,37556,37557, +19820,37558,37559,37560,37561,20070,24156,37562,19761,16422,37563,37564,22333, +37565,24155,12358,14900,18771,17523,15976,37566,37567,37568,37569,12854,37570, +37571,37572,37573,37574,37575,37576,37577,16460,19312,37578,15473,15163,13623, +37579,37580,37581,17781,37582,24166,37583,37584,37585,24163,15965,37586,37587, +24159,37588,37589,37590,37591,13367,15709,37592,37593,24160,17517,37594,37595, +37596,37597,20294,37598,13664,37599,37600,37601,37602,13918,19034,13684,24165, +37603,21830,37604,24161,19533,18046,37605,17733,37606,37607,37608,21044,37609, +15986,37610,37611,37612,37613,37614,37615,37616,16979,37617,19517,13112,37618, +15699,37619,16216,19782,20826,13419,37620,24164,24157,24167,37621,27262,37622, +37623,16944,24162,37624,37625,22080,13607,37626,12916,37627,24168,37628,24178, +37629,37630,37696,37697,37698,24173,37699,24177,37700,37701,18528,37702,37703, +37704,22369,24175,17256,19553,37705,12901,37706,37707,37708,21054,37709,37710, +37711,37712,37713,37714,37715,24174,37716,24171,20053,37717,13351,37718,37719, +37720,37721,37722,16171,15934,37723,37724,15698,37725,37726,37727,37728,24169, +37729,21550,37730,24158,37731,24170,37732,37733,37734,37735,16447,37736,24172, +12915,14441,16935,37737,37738,15681,37739,37740,37741,37742,37743,24181,24184, +37744,37745,12843,13348,37746,37747,13418,18726,37748,37749,37750,37751,37752, +37753,24182,19281,37754,14435,37755,24183,24186,37756,37757,37758,37760,24185, +37761,37762,37763,19522,37764,12385,13422,37765,37766,37767,37768,37769,37770, +25914,37771,37772,37773,37774,37775,20527,37776,37777,12907,37778,27425,37779, +24180,37780,37781,18787,24179,12378,21025,12663,37782,19503,37783,37784,37785, +37786,37787,37788,37789,24176,37790,19236,37791,37792,37793,21802,37794,37795, +37796,37797,37798,24187,37799,37800,37801,37802,37803,37804,37805,37806,13405, +37807,17446,37808,37809,37810,24189,37811,37812,37813,37814,37815,37816,37817, +37818,37819,37820,17278,17441,24353,37821,37822,37823,37824,37825,37826,37827, +16716,37828,24188,15983,37829,17970,37830,37831,37832,37833,37834,37835,37836, +37837,37838,13125,18550,37839,37840,19258,24190,37841,37842,24356,37843,37844, +37845,37846,22322,37847,37848,37849,37850,37851,13111,37852,37853,37854,37855, +16707,37856,37857,18251,12837,13417,37858,22315,37859,37860,37861,37862,17516, +37863,24354,24355,37864,24357,37865,14899,37866,37867,37868,24358,37869,16478, +37870,37871,18755,37872,37873,37874,37875,37876,37877,37878,12889,18278,37879, +24359,37880,18268,37881,37882,37883,37884,24360,27426,37885,37886,37952,37953, +37954,19283,37955,37956,37957,24362,37958,24361,37959,12865,37960,37961,37962, +37963,37964,37965,37966,37967,37968,37969,37970,37971,37972,37973,37974,37975, +37976,37977,37978,37979,37980,37981,37982,37983,37984,17738,37985,37986,37987, +37988,37989,37990,37991,37992,24363,37993,37994,37995,37996,37997,37998,37999, +38000,21596,38001,38002,38003,38004,38005,18497,38006,38007,38008,38009,38010, +38011,38012,38013,38014,38016,38017,38018,24364,38019,38020,38021,38022,38023, +15984,38024,38025,24365,22055,38026,38027,38028,38029,27191,27446,19029,38030, +22652,14404,38031,14629,38032,38033,14149,21886,38034,38035,38036,38037,38038, +14666,38039,38040,20519,29773,38041,38042,13648,38043,38044,17268,38045,15944, +38046,38047,38048,27447,12349,38049,38050,15692,38051,16690,38052,12630,13096, +38053,38054,38055,14418,18722,38056,38057,13912,38058,38059,38060,38061,27448, +15924,38062,38063,38064,19069,38065,18243,38066,21883,38067,38068,14195,38069, +38070,38071,38072,38073,38074,38075,38076,38077,38078,38079,38080,38081,38082, +38083,20036,38084,38085,38086,21803,12659,38087,38088,38089,27699,12383,38090, +27701,38091,38092,38093,13879,38094,16719,38095,30074,20529,38096,38097,21861, +38098,20051,38099,38100,15727,13154,38101,14379,38102,21814,38103,27965,38104, +13903,38105,19257,20546,38106,38107,38108,38109,38110,38111,38112,38113,14141, +38114,38115,27702,18985,38116,38117,38118,17748,38119,27705,27704,16963,27703, +38120,38121,38122,38123,20605,27706,38124,27707,22373,38125,38126,27708,38127, +38128,38129,27709,18028,38130,38131,38132,38133,38134,38135,38136,38137,20062, +38138,15432,38139,38140,18517,13609,15945,22076,21607,38141,38142,20782,20593, +27192,27193,27194,14901,38208,38209,38210,38211,18993,16245,38212,38213,19834, +38214,38215,38216,38217,38218,27200,38219,12346,27198,38220,38221,16421,38222, +38223,38224,27195,38225,12925,38226,17271,15208,38227,38228,38229,21079,20084, +27199,38230,38231,38232,27196,38233,38234,38235,27203,38236,20551,21299,38237, +38238,38239,38240,13370,38241,17217,22386,38242,38243,38244,38245,21841,38246, +19015,38247,27205,38248,38249,27204,27207,27206,38250,38251,38252,38253,38254, +22119,38255,20308,38256,38257,27211,38258,15182,38259,38260,38261,38262,38263, +38264,38265,15738,18766,38266,38267,27212,38268,38269,18745,20350,27210,21582, +27213,27215,38270,38272,19821,38273,38274,38275,38276,27209,38277,27214,38278, +38279,20078,38280,15198,38281,13119,38282,38283,38284,38285,38286,18005,15920, +20090,38287,38288,38289,18279,38290,15911,27216,38291,38292,22087,38293,38294, +38295,16704,38296,38297,38298,21597,38299,27217,38300,38301,20286,38302,38303, +38304,38305,27218,38306,38307,38308,38309,19054,38310,38311,38312,38313,17711, +12341,38314,38315,38316,38317,38318,27220,38319,38320,38321,38322,38323,38324, +38325,38326,38327,27219,29791,38328,38329,38330,38331,38332,17466,38333,38334, +38335,38336,38337,12585,38338,38339,38340,38341,25951,38342,38343,38344,38345, +27221,38346,38347,38348,38349,38350,38351,38352,38353,38354,38355,38356,38357, +38358,38359,38360,38361,38362,38363,38364,38365,38366,38367,38368,38369,38370, +38371,19055,38372,27222,27223,18008,38373,38374,38375,38376,38377,38378,38379, +38380,27224,38381,38382,27225,38383,38384,38385,38386,38387,38388,21563,38389, +18298,21047,14460,38390,38391,27202,38392,12892,38393,38394,17020,38395,21624, +19558,22382,38396,38397,38398,38464,38465,38466,38467,21570,21328,27459,17779, +38468,14206,38469,38470,27476,38471,38472,38473,19255,27486,38474,16458,38475, +38476,38477,19835,38478,13103,38479,18010,38480,38481,38482,38483,38484,38485, +27516,38486,17470,38487,20020,17449,12606,21629,38488,19061,38489,22124,38490, +38491,18003,13924,38492,38493,38494,38495,15226,38496,38497,20576,38498,38499, +18737,38500,21587,18472,38501,38502,14411,38503,26686,18748,38504,38505,26683, +38506,16494,20563,12868,13413,38507,26684,38508,38509,21832,38510,38511,38512, +38513,38514,13893,38515,26685,19064,14428,19573,38516,38517,38518,16436,38519, +38520,20846,26687,26690,38521,38522,14908,38523,12589,15708,38524,27197,26691, +38525,26694,38526,26699,38528,38529,38530,38531,26700,38532,19273,12389,38533, +15403,38534,38535,14649,38536,38537,26689,38538,19831,38539,26698,38540,38541, +38542,38543,20086,38544,38545,38546,38547,21869,38548,16726,26692,38549,17206, +38550,14715,22054,26696,38551,38552,38553,19040,21606,38554,26688,38555,26693, +26695,38556,18233,14179,38557,26697,38558,16221,26706,38559,38560,26711,38561, +26709,15452,15439,26715,38562,38563,38564,38565,38566,38567,38568,38569,26718, +38570,26714,12666,38571,38572,38573,38574,38575,38576,38577,38578,38579,38580, +12376,17459,14412,18018,18494,18529,38581,38582,38583,26703,26708,26710,38584, +14705,26712,22389,38585,17531,38586,26716,38587,38588,12905,38589,38590,38591, +26705,38592,38593,15469,38594,38595,16194,26701,22137,38596,16760,12913,38597, +38598,38599,38600,38601,38602,38603,38604,26719,38605,19009,26713,38606,38607, +38608,38609,21796,38610,12650,21819,26702,26704,13872,26707,38611,26717,16440, +38612,19063,38613,19240,38614,38615,18012,16501,38616,38617,38618,38619,38620, +26729,38621,38622,38623,20515,38624,38625,38626,38627,38628,38629,38630,26738, +22122,38631,38632,38633,38634,38635,38636,38637,26720,26721,38638,38639,38640, +20857,14923,14457,38641,38642,14449,21588,26735,38643,26734,26732,14704,19538, +26726,20006,16242,38644,12344,26737,26736,38645,22336,38646,26724,38647,19753, +18723,38648,15160,15707,26730,38649,38650,38651,38652,38653,38654,38720,38721, +38722,38723,26722,26723,26725,13621,26727,18245,26731,26733,15664,22318,38724, +26744,38725,38726,38727,38728,38729,38730,38731,38732,26741,38733,19760,26742, +38734,38735,38736,38737,38738,38739,38740,38741,38742,16698,38743,26728,38744, +17207,12400,38745,38746,38747,38748,38749,38750,38751,38752,26740,38753,38754, +38755,26743,38756,38757,38758,14627,38759,38760,38761,38762,38763,38764,38765, +38766,38767,38768,18770,38769,38770,38771,17230,20064,16486,38772,38773,38774, +38775,19315,38776,19549,20533,38777,38778,19041,38779,26739,38780,38781,38782, +38784,38785,38786,38787,38788,38789,38790,15468,38791,26745,38792,38793,38794, +38795,38796,38797,17246,38798,18021,38799,14711,38800,38801,38802,38803,12404, +38804,38805,22360,38806,38807,15404,38808,17775,38809,38810,38811,38812,38813, +19524,38814,38815,26918,38816,38817,38818,38819,38820,38821,38822,38823,38824, +38825,18733,38826,26914,16482,38827,38828,38829,16195,38830,38831,38832,26750, +14679,38833,26747,38834,38835,38836,38837,26916,38838,38839,38840,21070,38841, +38842,38843,38844,38845,26915,38846,22066,22325,38847,26919,38848,15671,38849, +38850,38851,38852,38853,38854,38855,38856,38857,38858,38859,38860,26748,26749, +38861,38862,38863,26913,38864,38865,38866,38867,38868,38869,38870,38871,19798, +38872,38873,21036,38874,38875,38876,26930,38877,38878,38879,38880,26921,38881, +38882,38883,13354,38884,13371,38885,38886,26923,38887,38888,38889,38890,38891, +38892,38893,38894,38895,38896,38897,38898,38899,38900,38901,38902,38903,20520, +38904,38905,26917,38906,38907,13182,38908,38909,26924,16483,38910,26922,38976, +38977,26937,38978,38979,26936,38980,38981,38982,38983,26926,38984,38985,26746, +38986,38987,26920,38988,38989,38990,38991,38992,16172,26929,26938,38993,38994, +16933,38995,38996,38997,26927,38998,14405,38999,26925,39000,21340,26932,26933, +26935,39001,39002,39003,26951,39004,39005,39006,39007,39008,39009,16454,26949, +39010,39011,26928,39012,39013,26939,12401,39014,39015,39016,39017,39018,39019, +39020,39021,39022,39023,26940,21797,39024,39025,26942,39026,26943,39027,39028, +39029,26945,39030,39031,16753,39032,39033,18486,39034,39035,39036,26941,39037, +39038,39040,39041,39042,26946,39043,39044,39045,39046,39047,39048,39049,39050, +26947,39051,26931,39052,26934,39053,15153,39054,39055,39056,26944,39057,39058, +39059,39060,39061,39062,15479,39063,39064,39065,26948,26950,39066,39067,39068, +39069,39070,39071,39072,39073,39074,39075,39076,39077,26954,39078,39079,39080, +39081,26958,39082,39083,39084,39085,39086,39087,39088,39089,39090,39091,12891, +39092,26952,39093,39094,39095,39096,39097,39098,39099,39100,39101,39102,14126, +39103,39104,39105,39106,39107,39108,39109,39110,39111,39112,39113,39114,26955, +26956,39115,39116,39117,39118,39119,39120,21825,39121,17443,39122,39123,39124, +39125,39126,39127,26968,39128,14945,39129,39130,39131,39132,26953,39133,21283, +39134,39135,39136,26964,39137,39138,39139,39140,39141,39142,39143,26967,26960, +39144,39145,39146,39147,39148,26959,39149,39150,18241,39151,39152,39153,39154, +39155,39156,39157,39158,26962,39159,39160,39161,39162,39163,39164,39165,26969, +13128,39166,26963,39232,39233,39234,39235,39236,20336,39237,39238,39239,26957, +39240,39241,39242,39243,39244,39245,39246,39247,39248,39249,39250,13175,39251, +39252,39253,39254,39255,39256,39257,26966,39258,39259,26970,39260,39261,39262, +19508,39263,39264,39265,20269,39266,39267,39268,39269,39270,39271,39272,39273, +39274,26965,39275,26972,26971,39276,39277,39278,39279,39280,26974,39281,39282, +39283,39284,39285,39286,39287,39288,26961,39289,39290,39291,39292,39293,39294, +39296,39297,26973,39298,26975,17226,39299,39300,39301,39302,39303,39304,39305, +39306,39307,39308,39309,39310,39311,39312,39313,39314,39315,39316,39317,39318, +39319,39320,39321,39322,39323,39324,39325,39326,39327,39328,39329,39330,39331, +39332,39333,39334,39335,39336,39337,39338,39339,39340,39341,39342,39343,39344, +39345,39346,39347,39348,39349,39350,39351,39352,39353,39354,39355,39356,39357, +39358,39359,39360,39361,39362,39363,39364,39365,39366,39367,39368,39369,39370, +39371,39372,39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383, +39384,39385,39386,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396, +39397,39398,39399,39400,39401,39402,39403,39404,39405,39406,39407,39408,39409, +39410,39411,39412,39413,18231,13390,15158,20544,27683,39414,39415,17719,39416, +39417,39418,39419,39420,39421,39422,39488,39489,39490,21371,39491,39492,39493, +39494,27684,39495,27685,18011,39496,39497,39498,16238,39499,39500,39501,39502, +27686,39503,39504,27687,20522,39505,18232,39506,39507,14440,39508,39509,39510, +39511,39512,39513,39514,39515,39516,39517,39518,39519,27688,39520,39521,39522, +39523,39524,39525,39526,39527,22073,21885,13387,12861,20068,18023,39528,39529, +19809,39530,39531,39532,39533,39534,39535,39536,39537,39538,39539,39540,39541, +39542,39543,13429,39544,19264,15455,39545,39546,39547,39548,26978,26979,20842, +26981,39549,13433,26980,39550,20787,19042,12880,39552,26984,39553,39554,39555, +39556,26982,26983,39557,39558,22067,39559,39560,39561,26985,26986,39562,39563, +39564,39565,39566,26987,39567,39568,39569,39570,39571,39572,39573,39574,26988, +39575,39576,39577,39578,39579,39580,39581,39582,27695,17721,13902,39583,21107, +39584,39585,39586,39587,39588,39589,39590,13678,39591,15193,27697,39592,39593, +21091,39594,39595,39596,39597,39598,20067,39599,17464,39600,17215,39601,39602, +13886,22585,12616,12623,12625,17790,39603,12624,39604,17195,39605,39606,39607, +39608,39609,21809,39610,39611,39612,39613,39614,39615,39616,39617,27428,14913, +39618,39619,39620,19514,39621,39622,39623,27429,39624,27431,39625,39626,39627, +27432,39628,39629,39630,27430,39631,39632,39633,39634,39635,39636,39637,27433, +27435,27434,39638,39639,39640,39641,39642,27436,39643,19023,22581,17265,39644, +17189,18040,27437,17482,39645,27438,27439,27440,14165,39646,39647,39648,14202, +39649,27441,18274,39650,27443,39651,14884,20853,12337,27442,27444,39652,39653, +39654,13610,16968,18280,39655,27445,39656,19246,25439,39657,39658,21312,39659, +39660,39661,39662,22875,39663,39664,19745,22061,18291,39665,39666,39667,22880, +15203,39668,14906,25442,39669,39670,39671,39672,39673,20267,39674,39675,39676, +25440,18759,39677,14905,39678,39744,39745,20788,25441,18538,14639,15661,13144, +20059,39746,39747,19520,39748,39749,39750,25448,25449,19828,39751,39752,39753, +39754,39755,19501,39756,15411,39757,25450,39758,25451,39759,39760,20570,39761, +39762,39763,18043,14170,39764,39765,18271,21066,20054,39766,25444,25452,39767, +18802,13121,39768,39769,25447,39770,39771,18019,25445,39772,39773,27955,25446, +39774,39775,39776,39777,18739,39778,17766,39779,39780,39781,14645,39782,17211, +39783,25443,17725,16676,16985,12887,39784,25453,15142,17453,39785,25456,15962, +39786,39787,25467,25461,14931,39788,39789,39790,39791,14160,21325,39792,22094, +21843,14657,21812,20824,39793,39794,39795,39796,20537,18294,39797,39798,39799, +18474,12852,39800,17242,39801,39802,39803,25454,39804,39805,25468,25455,14120, +25463,25460,39806,39808,39809,14138,39810,39811,17698,39812,25462,17757,12840, +18044,39813,17504,39814,39815,22306,39816,16481,25465,39817,39818,25466,25469, +19497,25459,39819,21310,39820,12611,27956,25457,25458,39821,25464,20538,17987, +21619,25470,39822,39823,15712,39824,39825,25639,39826,39827,25638,39828,39829, +39830,20851,25635,39831,25641,39832,39833,39834,18551,39835,39836,39837,39838, +20276,39839,25640,25646,16997,39840,39841,13876,39842,39843,39844,39845,39846, +39847,15730,39848,25634,39849,39850,14953,25642,39851,39852,25644,39853,39854, +13949,22110,25650,39855,25645,39856,39857,39858,25633,39859,15214,19805,18210, +17737,39860,39861,16759,39862,25636,39863,18227,15660,15677,25637,39864,22343, +12898,39865,25643,15427,25647,39866,15211,25648,17704,25649,39867,39868,39869, +39870,21859,16163,39871,25658,39872,25655,39873,25659,39874,39875,25661,39876, +39877,18006,39878,39879,14918,16459,39880,39881,39882,14369,25652,39883,39884, +39885,39886,21537,39887,39888,14883,15742,39889,39890,39891,25660,39892,39893, +39894,39895,39896,19775,39897,39898,17529,39899,39900,20347,18790,39901,39902, +21311,39903,20305,39904,39905,25651,39906,25656,25657,19561,39907,39908,39909, +39910,39911,19534,39912,16468,25653,16688,25654,20048,39913,15169,13651,39914, +18547,15655,21831,18732,14370,25674,39915,39916,25676,20804,39917,39918,21050, +39919,39920,14893,39921,39922,14932,39923,39924,39925,39926,39927,39928,25667, +13677,39929,39930,39931,22349,25664,20349,25663,39932,39933,39934,16732,19530, +40000,40001,40002,40003,19047,40004,40005,40006,40007,17495,40008,19540,25672, +40009,40010,40011,25671,25665,40012,25668,13613,40013,40014,21337,40015,25670, +40016,40017,40018,40019,21113,13411,40020,15156,40021,40022,18798,40023,13374, +40024,40025,40026,15212,40027,20813,40028,19565,27957,40029,40030,40031,40032, +40033,40034,40035,40036,18277,40037,40038,40039,40040,21544,40041,25675,22357, +25666,40042,15653,25669,40043,40044,21350,40045,25673,18808,40046,40047,25662, +40048,40049,21349,40050,40051,18302,13897,40052,21628,12851,25687,40053,40054, +40055,20034,40056,25677,40057,20028,40058,14427,40059,40060,25686,40061,16202, +40062,40064,40065,21326,40066,17260,40067,40068,40069,40070,40071,40072,40073, +40074,17736,25688,40075,40076,40077,40078,40079,40080,40081,40082,19780,25679, +40083,40084,40085,40086,25684,25685,40087,14974,40088,20326,40089,40090,21823, +40091,40092,40093,25682,40094,40095,40096,40097,40098,40099,40100,40101,40102, +40103,40104,25680,40105,40106,25678,40107,40108,40109,40110,40111,40112,40113, +40114,40115,40116,40117,40118,40119,40120,40121,19813,18986,40122,40123,40124, +16419,40125,15654,25683,40126,40127,14408,40128,40129,40130,40131,40132,25703, +21556,40133,40134,40135,40136,40137,40138,40139,25691,40140,40141,40142,16751, +40143,40144,25705,40145,40146,21095,40147,40148,25695,40149,25696,40150,40151, +20266,40152,40153,40154,40155,19293,40156,25690,25681,40157,25701,40158,18524, +25699,40159,40160,17511,25698,40161,25697,40162,40163,40164,13180,25704,40165, +40166,40167,40168,13665,40169,40170,40171,22348,40172,40173,40174,25702,40175, +15148,40176,22354,19535,27512,40177,25700,40178,40179,14710,40180,40181,40182, +22093,25689,25692,17018,25694,40183,16971,16452,16976,40184,12661,19506,40185, +40186,40187,40188,40189,40190,40256,40257,40258,40259,13646,40260,40261,40262, +40263,25711,40264,40265,40266,40267,40268,40269,40270,40271,17967,40272,40273, +40274,18017,40275,40276,25717,40277,40278,40279,40280,40281,16937,40282,40283, +40284,16492,20829,25710,40285,40286,40287,40288,40289,40290,40291,40292,40293, +40294,17454,40295,40296,40297,25709,40298,40299,40300,40301,25718,25716,17022, +40302,25693,40303,25712,40304,19070,40305,21828,40306,40307,25713,40308,40309, +40310,40311,40312,40313,40314,20858,40315,40316,40317,40318,40320,40321,40322, +25707,25708,40323,40324,40325,25714,40326,20011,40327,40328,40329,40330,40331, +40332,40333,40334,40335,40336,17739,40337,40338,40339,18225,40340,16954,40341, +40342,40343,25706,40344,40345,40346,16714,40347,40348,40349,40350,40351,40352, +19510,13105,40353,40354,40355,25723,40356,25715,40357,40358,40359,25722,40360, +25725,40361,25724,40362,40363,40364,40365,40366,40367,40368,13134,40369,40370, +40371,13114,25719,40372,40373,25721,25720,17772,40374,40375,40376,40377,40378, +40379,40380,40381,40382,40383,40384,40385,40386,16445,40387,40388,40389,40390, +21608,40391,40392,40393,40394,40395,25890,40396,40397,40398,40399,40400,40401, +40402,40403,40404,40405,40406,12356,40407,40408,25892,40409,40410,25891,40411, +40412,40413,40414,40415,40416,15396,40417,25893,40418,40419,40420,40421,40422, +40423,25889,40424,40425,40426,40427,40428,40429,40430,25726,12660,40431,40432, +40433,40434,40435,40436,40437,40438,40439,40440,40441,25896,40442,25897,25894, +40443,40444,40445,40446,40512,40513,40514,40515,40516,40517,40518,40519,25895, +25898,40520,40521,40522,40523,40524,40525,40526,40527,40528,40529,40530,40531, +40532,40533,40534,40535,40536,40537,40538,40539,40540,40541,40542,40543,40544, +40545,40546,40547,40548,40549,40550,40551,40552,18009,40553,40554,40555,40556, +40557,40558,40559,40560,25899,25901,40561,40562,40563,40564,40565,40566,40567, +25900,40568,40569,40570,40571,40572,40573,40574,40576,40577,40578,40579,40580, +40581,40582,40583,40584,40585,25903,40586,40587,40588,25902,40589,40590,40591, +40592,40593,40594,40595,40596,40597,40598,40599,40600,40601,40602,40603,40604, +40605,40606,14688,40607,40608,25904,40609,40610,40611,40612,40613,40614,40615, +40616,40617,40618,40619,40620,40621,40622,25905,40623,40624,40625,40626,40627, +40628,40629,40630,40631,40632,40633,40634,15216,27745,17264,40635,13638,15186, +40636,40637,40638,40639,16745,21614,40640,15940,40641,40642,40643,22342,40644, +21590,12883,27710,40645,40646,40647,40648,27201,40649,40650,40651,16943,13366, +40652,40653,40654,20823,40655,40656,40657,13108,40658,18482,16187,27712,40659, +40660,22091,40661,40662,27711,27713,40663,40664,40665,40666,40667,40668,40669, +40670,40671,40672,40673,40674,40675,27717,15974,19519,17754,15932,40676,27718, +40677,12670,40678,40679,40680,27716,21800,13667,40681,27714,16694,13155,40682, +40683,27715,19256,16451,19582,40684,40685,40686,40687,16722,40688,27720,40689, +40690,40691,40692,40693,40694,40695,40696,40697,40698,40699,40700,40701,14950, +16467,40702,22130,40768,40769,40770,20812,40771,40772,40773,40774,16190,40775, +14131,18773,27719,15202,40776,19532,15741,18504,40777,20265,40778,40779,40780, +40781,40782,40783,40784,19817,40785,17771,40786,40787,40788,14185,40789,40790, +40791,40792,40793,40794,40795,40796,40797,40798,40799,20809,14904,40800,40801, +40802,40803,40804,27721,40805,40806,27722,40807,15168,27723,40808,27746,12602, +14169,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818,40819,15673, +40820,40821,40822,40823,40824,40825,40826,40827,27724,20838,27725,40828,40829, +40830,40832,18491,40833,40834,40835,40836,40837,40838,40839,40840,40841,40842, +40843,40844,40845,40846,27729,40847,40848,40849,40850,27731,40851,15181,40852, +15461,40853,40854,40855,40856,40857,40858,40859,40860,40861,40862,40863,40864, +40865,27727,40866,18743,40867,40868,40869,40870,40871,17210,40872,27747,21845, +27728,40873,40874,40875,40876,40877,22131,40878,40879,40880,27730,27726,40881, +40882,40883,40884,27732,40885,27733,40886,40887,18751,40888,40889,40890,40891, +40892,40893,20264,40894,40895,40896,40897,40898,20572,40899,40900,40901,40902, +20780,40903,40904,40905,40906,18523,40907,40908,40909,27734,20085,40910,40911, +40912,40913,40914,19052,27738,40915,40916,40917,40918,40919,40920,40921,27737, +40922,40923,40924,12350,40925,40926,40927,40928,40929,40930,27735,40931,27736, +40932,40933,40934,27748,40935,40936,40937,40938,40939,40940,40941,40942,40943, +18492,40944,40945,40946,40947,40948,40949,40950,40951,40952,40953,16711,40954, +40955,40956,40957,40958,27740,20832,41024,41025,41026,41027,41028,41029,41030, +41031,41032,41033,27739,41034,41035,41036,41037,21615,41038,27741,41039,41040, +41041,41042,41043,41044,23366,41045,41046,41047,41048,41049,41050,41051,41052, +41053,41054,27742,41055,41056,41057,41058,41059,41060,41061,41062,41063,41064, +41065,41066,12588,41067,41068,41069,41070,41071,41072,41073,41074,41075,41076, +41077,41078,41079,41080,41081,41082,41083,41084,41085,41086,41088,41089,27743, +41090,41091,41092,41093,41094,41095,41096,41097,41098,41099,27744,41100,22310, +41101,17728,41102,41103,41104,27452,12334,41105,41106,41107,15988,14392,21039, +12374,13689,41108,22579,41109,19244,41110,25437,41111,41112,41113,41114,41115, +41116,41117,17964,12390,41118,41119,41120,17734,27449,41121,41122,41123,41124, +27450,41125,41126,41127,27451,41128,41129,20800,41130,17699,41131,27250,41132, +17458,41133,17461,16462,41134,41135,41136,27251,17473,41137,20079,41138,41139, +41140,41141,27248,27252,41142,41143,18812,41144,41145,18211,41146,41147,41148, +19544,20094,41149,41150,41151,27253,27254,20268,16487,41152,41153,27255,41154, +41155,41156,41157,41158,13887,27256,41159,27257,41160,27258,41161,41162,27259, +41163,41164,41165,41166,41167,41168,41169,41170,41171,41172,41173,41174,27249, +41175,41176,41177,41178,41179,41180,41181,41182,41183,41184,41185,41186,18478, +24939,41187,14136,24940,41188,41189,41190,24941,41191,22324,24942,24943,21324, +41192,41193,41194,41195,41196,41197,41198,24945,16241,24944,13650,41199,41200, +41201,12599,41202,41203,41204,41205,24947,24946,41206,14972,41207,24948,41208, +41209,41210,41211,14647,41212,15953,41213,41214,43584,43585,17532,43586,14941, +15686,43587,43588,43589,43590,43591,43592,24949,24951,43593,43594,13888,20289, +18984,24950,21880,21372,24952,24956,24953,43595,43596,24954,16490,43597,24958, +25121,16455,43598,43599,43600,43601,24955,43602,24957,43603,43604,43605,43606, +43607,43608,25125,43609,43610,43611,16724,43612,43613,43614,43615,25123,43616, +25128,12926,25122,43617,43618,43619,17229,12866,25127,25126,43620,43621,25124, +25129,43622,43623,25131,43624,43625,43626,20553,22125,17192,25132,43627,20311, +43628,43629,25134,43630,43631,14959,43632,43633,26976,25133,25130,43634,43635, +43636,43637,15147,21555,43638,43639,43640,43641,43642,43643,43644,43645,43646, +43648,43649,43650,43651,25136,43652,43653,25135,43654,26977,43655,43656,43657, +43658,25137,43659,43660,43661,43662,43663,43664,43665,43666,25138,43667,43668, +43669,43670,43671,43672,43673,43674,43675,43676,43677,25139,19489,43678,25140, +43679,43680,43840,43841,43842,43843,43844,43845,43846,43847,43848,43849,43850, +43851,25141,43852,43853,43854,43855,43856,20606,43857,43858,16970,43859,21361, +43860,19829,43861,43862,26464,43863,43864,26465,43865,43866,43867,43868,15937, +43869,43870,43871,43872,17002,43873,43874,43875,26468,43876,43877,26467,43878, +43879,43880,43881,43882,43883,19814,43884,17205,43885,43886,26466,15159,20310, +43887,16737,26473,43888,43889,43890,26472,43891,43892,26484,12835,43893,43894, +43895,43896,26474,43897,26470,43898,43899,43900,43901,43902,26476,26475,18746, +43904,43905,21860,43906,26469,14121,26471,43907,43908,43909,43910,43911,43912, +43913,26478,43914,43915,43916,43917,26483,43918,22121,43919,43920,43921,43922, +26477,43923,26482,43924,26481,43925,43926,43927,12384,43928,43929,43930,43931, +26485,43932,43933,43934,43935,43936,44096,44097,44098,44099,44100,44101,44102, +44103,44104,44105,44106,18290,44107,16453,16493,44108,44109,16752,26480,44110, +44111,44112,44113,26486,19318,44114,44115,44116,44117,44118,44119,44120,44121, +44122,26658,26657,44123,44124,44125,44126,44127,44128,22337,44129,44130,26490, +26489,44131,26491,44132,26487,44133,26494,44134,26493,44135,26492,44136,44137, +16725,18265,17789,17731,44138,44139,44140,44141,44142,18285,44143,44144,44145, +44146,26659,44147,44148,44149,44150,44151,44152,44153,44154,44155,44156,44157, +44158,44160,44161,44162,44163,44164,44165,44166,26662,44167,26661,44168,26663, +14967,26488,26660,44169,18544,18730,44170,44171,44172,44173,44174,44175,44176, +44177,44178,44179,44180,44181,44182,26665,44183,44184,14693,44185,44186,44187, +44188,44189,20862,26664,44190,44191,44192,44352,44353,44354,26666,44355,26669, +26670,44356,16679,44357,44358,44359,26671,44360,44361,44362,26672,44363,44364, +26668,44365,26676,44366,44367,44368,44369,44370,44371,44372,44373,44374,44375, +44376,26667,44377,26673,44378,44379,44380,44381,44382,44383,44384,44385,26677, +26674,26675,44386,44387,44388,44389,44390,44391,44392,44393,44394,44395,44396, +44397,44398,44399,44400,44401,26679,44402,44403,44404,44405,44406,44407,44408, +44409,44410,44411,44412,44413,44414,44416,44417,44418,44419,44420,44421,44422, +44423,44424,44425,26678,44426,44427,44428,44429,44430,44431,44432,44433,44434, +14671,44435,28716,44436,28717,44437,17968,12394,18495,44438,19807,44439,44440, +44441,44442,44443,44444,44445,20045,27185,44446,44447,44448,44608,27186,44609, +17983,13385,44610,44611,44612,44613,44614,44615,44616,27187,44617,44618,44619, +44620,21863,44621,44622,44623,44624,44625,44626,44627,44628,23929,44629,27188, +44630,27189,44631,27190,44632,44633,44634,44635,14410,24368,18805,44636,19568, +44637,44638,18810,44639,44640,44641,44642,44643,18811,44644,44645,21315,19238, +44646,14374,28718,12610,44647,25912,19567,21321,15447,18794,44648,13671,44649, +17488,13673,44650,28206,15149,44651,44652,26462,44653,28207,44654,44655,44656, +44657,13097,44658,44659,28210,44660,44661,28209,15719,44662,28208,20023,44663, +44664,44665,44666,17743,44667,44668,44669,44670,16756,23374,28211,20595,44672, +44673,44674,44675,44676,44677,44678,44679,16980,18024,44680,44681,44682,14124, +44683,44684,44685,44686,44687,44688,44689,28212,44690,13163,44691,44692,44693, +15227,28213,44694,44695,44696,44697,44698,26460,44699,44700,44701,28214,44702, +44703,15662,44704,44864,44865,44866,29026,44867,44868,44869,19048,44870,21065, +28762,44871,28763,44872,28764,16710,44873,14445,15950,44874,44875,28766,44876, +17713,28765,20849,44877,28768,12364,15722,44878,44879,44880,44881,44882,21087, +28767,44883,13359,14184,28774,28773,17955,28769,28770,13379,44884,44885,28771, +21870,44886,44887,19547,15954,15410,44888,44889,44890,28776,28775,28772,12833, +44891,22050,21304,15927,18476,44892,44893,28778,44894,44895,44896,44897,20855, +44898,22092,14939,28777,44899,13883,44900,44901,19764,44902,44903,17958,44904, +44905,44906,16673,28779,28782,44907,28781,28784,28780,44908,15166,28783,44909, +44910,44911,44912,19509,28786,44913,44914,13141,44915,44916,44917,44918,12628, +44919,44920,28787,44921,44922,28788,28790,13409,44923,28785,44924,28791,44925, +44926,44928,44929,28794,44930,28792,44931,44932,44933,28789,44934,44935,44936, +44937,28797,44938,28793,28796,28798,44939,28961,44940,44941,44942,20033,28964, +44943,28963,44944,16758,28795,19037,44945,44946,13425,12657,19505,44947,28966, +44948,44949,28967,44950,44951,28972,21838,28969,44952,44953,18483,44954,44955, +44956,28962,44957,28971,28968,28965,44958,44959,28970,44960,45120,45121,45122, +45123,45124,45125,45126,12329,28973,45127,45128,45129,45130,45131,45132,28975, +45133,28977,45134,45135,45136,45137,45138,28976,45139,28974,45140,45141,45142, +45143,20770,45144,45145,45146,45147,45148,45149,45150,28978,45151,45152,45153, +28979,45154,45155,45156,45157,45158,45159,45160,45161,14703,45162,45163,13639, +45164,12375,12377,45165,45166,45167,21613,45168,13636,45169,15700,15178,28711, +45170,45171,14430,45172,45173,28712,45174,45175,12328,45176,28713,45177,45178, +19822,45179,45180,28714,45181,45182,45184,45185,45186,45187,45188,45189,45190, +45191,28715,45192,45193,45194,45195,45196,45197,45198,45199,45200,17956,45201, +45202,22117,29028,45203,29029,45204,45205,45206,45207,45208,45209,45210,45211, +45212,45213,17267,45214,45215,21339,45216,45376,22097,17768,45377,21295,45378, +21094,45379,45380,28225,12347,21813,20814,15456,14928,45381,16248,45382,14407, +13633,17740,45383,45384,18978,45385,45386,45387,17227,45388,45389,45390,45391, +45392,28226,45393,45394,45395,45396,45397,45398,45399,45400,17471,13858,45401, +28012,17188,45402,22065,45403,45404,45405,20320,28015,45406,45407,17742,45408, +13916,45409,45410,18977,45411,45412,28013,45413,45414,28016,28017,17212,45415, +16180,45416,28014,45417,45418,45419,45420,45421,45422,45423,45424,45425,45426, +45427,28020,28018,45428,45429,45430,45431,21862,17247,45432,28019,45433,45434, +45435,28022,45436,21795,20771,45437,45438,45440,28021,45441,17232,45442,45443, +45444,45445,45446,28023,16244,15980,28024,45447,19575,45448,20827,45449,45450, +45451,22341,21878,45452,28028,45453,45454,45455,28027,45456,45457,45458,45459, +45460,45461,45462,45463,28025,28026,45464,45465,45466,45467,45468,45469,45470, +45471,28029,15910,45472,45632,45633,45634,45635,19247,28193,13885,45636,28194, +17472,45637,28030,45638,45639,15710,12871,45640,45641,45642,45643,45644,45645, +45646,45647,45648,45649,45650,45651,13891,45652,45653,45654,28197,22586,28195, +28198,45655,45656,45657,17257,13170,45658,45659,45660,45661,45662,45663,28199, +28196,20281,45664,45665,28200,17015,45666,45667,45668,45669,45670,45671,45672, +45673,45674,45675,45676,45677,28201,28202,45678,24107,45679,45680,17971,45681, +18246,45682,22133,13641,45683,19250,45684,45685,45686,28203,45687,45688,19755, +45689,28204,45690,45691,45692,45693,45694,21808,45696,28205,45697,30276,45698, +45699,45700,45701,45702,45703,45704,45705,45706,45707,45708,45709,45710,23367, +45711,45712,45713,45714,45715,45716,45717,45718,45719,13347,45720,45721,45722, +17196,29030,45723,45724,45725,45726,45727,19000,21075,45728,22058,45888,28530, +45889,15960,45890,15683,28531,13900,12331,45891,45892,45893,45894,18991,45895, +45896,27958,45897,27959,45898,45899,45900,45901,20089,14127,16243,27960,17003, +18736,45902,45903,45904,45905,45906,45907,27961,45908,45909,18038,16179,45910, +45911,45912,27964,17784,45913,20816,45914,22313,27962,27963,45915,20834,45916, +27967,27968,45917,27972,45918,45919,45920,27976,45921,27974,27982,21864,45922, +27977,45923,45924,27975,27966,45925,45926,17769,45927,45928,45929,17990,45930, +45931,18793,21586,27969,27970,27971,27973,45932,16505,45933,13345,45934,45935, +45936,45937,14696,45938,27984,45939,45940,45941,45942,27985,45943,27978,45944, +27983,45945,20088,45946,45947,19254,27980,27981,45948,45949,45950,45952,45953, +20341,45954,45955,45956,45957,45958,45959,45960,45961,45962,45963,45964,45965, +27986,16754,21298,27979,18487,45966,45967,45968,45969,45970,45971,45972,45973, +15471,45974,45975,45976,45977,17776,45978,45979,45980,45981,45982,45983,45984, +46144,46145,46146,27990,46147,13679,46148,46149,16949,12333,19305,46150,46151, +12590,46152,27988,46153,46154,46155,19819,13666,46156,27989,27987,27991,46157, +46158,13690,46159,27992,46160,27993,46161,27996,46162,12620,46163,46164,46165, +46166,46167,46168,46169,46170,17782,15470,27994,19516,12906,46171,46172,46173, +46174,27995,46175,46176,46177,46178,17515,46179,46180,13381,46181,46182,46183, +12405,46184,46185,46186,27999,16474,13416,46187,46188,46189,46190,17741,46191, +46192,46193,27997,16196,46194,46195,46196,27998,46197,46198,46199,46200,46201, +46202,46203,46204,46205,46206,46208,46209,46210,46211,17445,46212,46213,46214, +28000,46215,46216,46217,46218,46219,28001,46220,28003,46221,46222,16727,46223, +46224,15175,46225,46226,46227,46228,46229,46230,15672,46231,46232,46233,28002, +46234,46235,46236,46237,46238,46239,46240,46400,46401,46402,46403,46404,46405, +28004,46406,46407,46408,46409,46410,46411,46412,46413,46414,46415,28006,46416, +46417,46418,46419,46420,28005,46421,46422,46423,46424,46425,46426,46427,46428, +46429,46430,46431,46432,46433,46434,46435,28007,46436,46437,46438,46439,46440, +19006,27754,16497,46441,18791,46442,27755,18030,46443,46444,46445,46446,27756, +46447,18029,27757,46448,46449,46450,46451,46452,46453,46454,46455,46456,27760, +46457,46458,22374,27763,46459,46460,27761,27758,27759,22307,18801,19310,27764, +46461,27762,46462,46464,20329,46465,27766,17969,46466,46467,46468,46469,15424, +46470,27765,46471,46472,46473,46474,46475,46476,46477,13627,15222,46478,27767, +46479,46480,46481,46482,46483,22903,15739,46484,46485,16955,27768,46486,46487, +46488,46489,27769,46490,46491,46492,46493,14371,46494,46495,46496,46656,46657, +46658,46659,46660,46661,46662,27770,46663,46664,46665,46666,46667,46668,46669, +46670,46671,46672,46673,46674,27771,46675,46676,46677,46678,46679,46680,46681, +46682,46683,46684,46685,27772,46686,46687,46688,46689,46690,21357,22574,16491, +46691,18269,14924,46692,20579,19261,46693,19770,46694,46695,14417,46696,46697, +12668,46698,18287,46699,22102,46700,46701,46702,16198,17259,46703,46704,28533, +46705,46706,17240,46707,46708,46709,46710,46711,46712,22370,46713,46714,46715, +28535,13139,46716,18264,20845,46717,22088,46718,28536,46720,28534,46721,15229, +13126,46722,46723,46724,46725,46726,46727,46728,15701,46729,46730,21062,46731, +15200,46732,46733,20257,46734,28540,28539,46735,46736,28537,46737,46738,46739, +46740,13132,46741,18772,19248,46742,46743,46744,46745,46746,28542,46747,46748, +12382,46749,46750,22089,46751,46752,46912,28541,46913,13165,46914,46915,30293, +46916,46917,46918,46919,46920,46921,46922,46923,46924,46925,46926,46927,46928, +46929,46930,20040,46931,46932,46933,28706,46934,28705,46935,13630,15450,15228, +46936,14437,46937,46938,46939,46940,46941,46942,17474,46943,46944,46945,46946, +46947,46948,46949,46950,46951,46952,28707,46953,46954,46955,46956,46957,19307, +46958,46959,46960,46961,46962,46963,46964,46965,46966,46967,46968,46969,46970, +46971,46972,46973,46974,46976,46977,46978,46979,46980,46981,46982,28710,46983, +46984,46985,20776,46986,15935,18286,28982,28983,16213,46987,46988,46989,46990, +13353,28984,19771,46991,18260,21805,46992,28985,46993,28986,46994,46995,46996, +46997,18255,46998,46999,47000,21028,22095,47001,47002,28987,15697,13360,15933, +47003,47004,47005,13404,20049,47006,16223,28989,47007,47008,47168,47169,16250, +28988,47170,28991,47171,47172,47173,28990,28992,47174,47175,47176,47177,47178, +28993,47179,47180,47181,47182,47183,47184,47185,47186,47187,47188,47189,16766, +47190,47191,47192,47193,47194,47195,47196,47197,47198,47199,47200,16674,47201, +47202,47203,47204,47205,47206,47207,47208,47209,47210,19066,47211,47212,21822, +47213,47214,47215,47216,15930,15929,21826,47217,47218,16162,47219,19759,28981, +47220,47221,47222,47223,47224,47225,15711,47226,13899,47227,47228,47229,47230, +47232,47233,47234,47235,47236,22129,29507,47237,47238,29508,47239,14413,47240, +47241,47242,29510,29511,47243,12362,47244,29509,47245,29513,19313,47246,47247, +47248,29515,47249,20518,47250,47251,12618,29512,47252,47253,47254,29519,47255, +13649,47256,47257,29527,47258,29522,47259,47260,47261,29524,29523,14203,47262, +12607,47263,29518,29514,13658,47264,29520,47424,47425,29521,47426,29525,47427, +47428,47429,47430,29517,47431,15459,47432,16765,47433,29526,47434,47435,47436, +47437,47438,47439,29530,47440,29516,47441,13640,47442,15726,29532,47443,47444, +14116,16240,22142,19762,47445,13424,47446,12895,47447,29528,47448,29529,18744, +47449,29533,47450,47451,29534,47452,29537,47453,47454,47455,47456,47457,47458, +47459,47460,47461,47462,47463,29535,47464,47465,29539,29538,47466,47467,29531, +47468,16234,47469,13167,47470,29536,47471,47472,18217,47473,15474,47474,47475, +47476,47477,29547,47478,47479,47480,47481,47482,47483,47484,14655,47485,47486, +29540,47488,47489,47490,12845,15230,47491,19299,47492,47493,47494,47495,29549, +29545,47496,47497,47498,14684,29550,47499,47500,47501,29541,29542,29546,16993, +29548,29551,29544,15485,47502,47503,47504,20324,47505,47506,29552,47507,47508, +47509,29543,47510,47511,47512,47513,47514,47515,47516,47517,29554,47518,47519, +47520,47680,22317,17962,47681,47682,47683,47684,29555,47685,47686,47687,47688, +29553,47689,16936,47690,47691,47692,47693,47694,14429,29557,47695,47696,29556, +47697,47698,47699,13403,47700,47701,47702,29558,29559,47703,47704,47705,29560, +47706,47707,47708,16442,47709,47710,16489,47711,47712,47713,47714,47715,17777, +47716,47717,47718,47719,29563,47720,29562,47721,47722,47723,47724,47725,47726, +47727,47728,13400,47729,47730,47731,29566,29561,47732,47733,29564,47734,47735, +47736,47737,47738,47739,29565,47740,47741,47742,47744,47745,47746,47747,47748, +29729,47749,47750,47751,47752,47753,47754,29731,15177,47755,47756,29730,47757, +47758,47759,47760,47761,47762,47763,47764,47765,47766,47767,47768,47769,29732, +47770,47771,47772,47773,47774,47775,12862,29734,29733,47776,47936,47937,47938, +47939,47940,47941,47942,47943,47944,47945,15406,47946,47947,47948,47949,47950, +47951,47952,47953,47954,47955,47956,47957,47958,47959,47960,47961,47962,47963, +47964,47965,47966,47967,47968,47969,47970,47971,47972,47973,47974,47975,47976, +47977,47978,47979,47980,47981,47982,17239,22881,47983,47984,47985,47986,47987, +47988,16480,29772,22353,47989,47990,47991,47992,47993,47994,47995,47996,47997, +47998,48000,14171,48001,48002,48003,48004,48005,48006,48007,29774,16675,48008, +48009,17993,48010,13398,21811,48011,48012,48013,29776,29775,29777,19290,48014, +48015,29778,48016,21569,22112,48017,48018,48019,48020,14176,48021,48022,48023, +16696,48024,48025,16699,29779,15916,48026,48027,48028,48029,48030,13410,48031, +48032,29780,29781,15915,48192,48193,29782,48194,48195,48196,29787,48197,29783, +29786,48198,14973,48199,29784,29785,48200,48201,48202,48203,48204,48205,48206, +14434,19527,29788,48207,12890,48208,48209,17235,48210,48211,21603,16183,48212, +48213,48214,48215,48216,48217,48218,29789,48219,48220,48221,48222,48223,48224, +17716,48225,48226,48227,48228,48229,48230,48231,48232,29801,48233,48234,20277, +48235,48236,48237,48238,48239,48240,48241,48242,48243,48244,48245,48246,48247, +48248,20041,48249,48250,48251,48252,48253,48254,48256,48257,48258,48259,48260, +48261,48262,48263,48264,48265,48266,48267,48268,48269,48270,19288,48271,19319, +48272,48273,48274,48275,15732,48276,48277,48278,22351,48279,48280,48281,16475, +48282,48283,48284,48285,48286,48287,48288,48448,48449,48450,48451,48452,48453, +48454,48455,48456,48457,48458,48459,48460,48461,48462,48463,48464,48465,48466, +48467,48468,48469,48470,48471,48472,48473,48474,48475,48476,48477,48478,48479, +48480,48481,48482,48483,48484,48485,48486,48487,48488,48489,48490,48491,48492, +48493,48494,48495,48496,48497,48498,48499,48500,48501,48502,20597,48503,48504, +48505,48506,48507,48508,48509,48510,29802,48512,48513,48514,48515,48516,48517, +48518,48519,48520,48521,48522,48523,48524,48525,48526,48527,48528,48529,48530, +48531,48532,48533,48534,48535,48536,48537,48538,48539,48540,48541,48542,48543, +48544,48704,48705,48706,48707,48708,48709,48710,48711,48712,48713,48714,48715, +48716,29803,48717,48718,48719,48720,48721,48722,48723,29804,48724,48725,48726, +48727,48728,48729,48730,48731,48732,48733,48734,48735,48736,48737,48738,48739, +48740,48741,48742,48743,48744,48745,48746,48747,48748,48749,48750,48751,48752, +48753,48754,48755,48756,48757,48758,48759,48760,48761,48762,48763,48764,48765, +48766,48768,48769,48770,48771,48772,48773,48774,48775,48776,48777,48778,48779, +48780,48781,48782,48783,48784,48785,48786,48787,48788,48789,48790,48791,48792, +48793,48794,48795,48796,48797,48798,48799,48800,48960,48961,48962,48963,48964, +48965,48966,48967,48968,48969,48970,48971,48972,48973,48974,48975,48976,48977, +48978,48979,48980,48981,48982,48983,48984,48985,48986,48987,48988,48989,48990, +48991,48992,48993,48994,48995,48996,48997,48998,48999,49000,49001,49002,49003, +49004,49005,49006,49007,49008,49009,49010,49011,49012,49013,49014,49015,49016, +49017,49018,49019,49020,49021,49022,49024,30563,49025,49026,49027,49028,49029, +14129,49030,49031,49032,49033,49034,29805,49035,49036,49037,49038,49039,49040, +49041,49042,49043,49044,49045,49046,49047,49048,49049,49050,49051,49052,49053, +49054,49055,49056,49216,49217,49218,49219,49220,49221,49222,49223,49224,49225, +49226,49227,49228,49229,49230,49231,49232,49233,49234,49235,49236,49237,49238, +49239,49240,49241,49242,49243,49244,49245,49246,49247,49248,49249,49250,49251, +22379,49252,49253,49254,49255,49256,49257,49258,49259,49260,49261,49262,49263, +49264,49265,49266,49267,49268,49269,49270,49271,49272,49273,49274,49275,29806, +49276,49277,49278,26233,15936,26234,14956,26235,20299,26236,21564,15414,26237, +26238,15437,18514,20019,26401,49280,13375,26402,18740,14425,17481,49281,22365, +16986,14167,22077,20038,14148,49282,49283,17702,26403,20319,26404,26405,26406, +16695,22377,18800,20280,22063,22101,26407,12397,26408,26409,18780,21103,15917, +26410,12403,18526,15713,26411,18502,49284,26412,15206,14456,20772,26413,16999, +15992,15690,19763,26414,26415,15982,20581,49285,19303,19536,15436,26416,15400, +20599,26417,49286,20600,26418,26419,13378,26420,26421,18814,20012,17248,26423, +12609,13169,49287,26424,26425,22363,21824,26426,16972,22330,26427,26428,26429, +15466,17253,16450,26430,26431,15401,49288,26432,26433,26422,13904,26434,49289, +26435,26436,15162,13662,16966,12640,26437,21557,26438,14399,26440,26439,14188, +49290,26441,12920,26442,26443,26444,26445,26446,26447,26448,21287,19317,26449, +26450,26451,26452,18761,26453,26454,26455,26456,26457,15689,26458,29502,49291, +14423,49292,18481,49293,49294,49295,49296,49297,49298,49299,29503,49300,29504, +29505,49301,49302,49303,49304,49305,49306,49307,49308,49309,49310,14686,19832, +49311,49312,22632,14897,49472,16990,28215,49473,14115,49474,49475,49476,49477, +28217,49478,28216,12373,49479,49480,49481,49482,49483,28219,21846,22383,49484, +49485,49486,22083,49487,49488,28221,19056,49489,28220,49490,49491,49492,49493, +28222,49494,49495,49496,49497,28224,49498,49499,28223,49500,49501,49502,49503, +49504,49505,49506,49507,20850,49508,18236,49509,17216,49510,49511,49512,49513, +49514,14433,49515,49516,49517,49518,49519,16743,49520,49521,29766,20575,29767, +49522,20315,49523,49524,18490,49525,49526,29768,49527,49528,49529,49530,49531, +49532,49533,29769,29770,49534,29771,49536,49537,49538,49539,49540,22906,14462, +49541,49542,25969,21360,49543,29792,49544,20044,49545,49546,49547,13153,49548, +49549,49550,49551,28980,49552,21102,49553,29793,49554,49555,49556,49557,49558, +20328,29794,49559,49560,18252,49561,49562,49563,49564,49565,49566,13652,13412, +29796,49567,49568,49728,29795,29797,49729,49730,29798,49731,49732,49733,49734, +29799,49735,14898,12351,49736,29800,49737,49738,49739,49740,49741,49742,49743, +14125,21101,49744,49745,49746,21035,16463,49747,16188,27427,21855,27208,49748, +49749,49750,49751,29043,13944,19235,49752,49753,17485,49754,29031,49755,29032, +14459,29033,14916,21573,12370,49756,49757,29034,49758,49759,49760,29035,49761, +29036,49762,49763,29037,29038,29039,29041,29040,17749,49764,49765,49766,49767, +49768,49769,29042,49770,13946,49771,29044,21038,24135,19274,49772,49773,13148, +49774,13602,49775,14626,49776,49777,17524,29045,49778,49779,29046,49780,49781, +49782,16708,16763,22064,29047,49783,49784,49785,49786,29048,49787,16682,49788, +49789,49790,17976,49792,15963,49793,49794,49795,49796,49797,49798,49799,49800, +49801,49802,49803,49804,49805,49806,29049,13391,49807,49808,49809,49810,49811, +49812,29050,49813,49814,49815,49816,49817,49818,49819,49820,49821,49822,49823, +49824,49984,27954,27953,49985,49986,19296,21086,49987,19265,21848,49988,18530, +49989,16479,15393,49990,49991,49992,49993,49994,49995,27457,49996,49997,20516, +49998,22114,49999,13895,14424,27456,14414,50000,27455,13094,14665,22059,50001, +14196,14154,50002,50003,50004,15463,14142,27462,50005,27463,12345,16207,50006, +27461,21373,50007,27464,50008,50009,27465,50010,50011,14158,50012,27458,27460, +18806,22103,21837,20530,27471,20024,27472,50013,13608,50014,50015,50016,50017, +50018,12595,27474,19493,50019,50020,50021,50022,50023,50024,50025,17750,27475, +50026,27473,17759,27470,18980,27477,12411,50027,50028,14970,50029,50030,22583, +29027,50031,27466,27467,27468,27469,27478,26176,27481,50032,16232,21064,27479, +27484,14444,27480,50033,15674,50034,20568,50035,12343,50036,27485,17500,50037, +50038,50039,50040,22060,50041,50042,50043,13408,50044,50045,17014,15417,50046, +50048,27482,27483,21600,18026,17492,27487,17703,22901,50049,12849,50050,27492, +50051,15685,50052,50053,50054,27490,50055,50056,50057,50058,50059,50060,50061, +50062,50063,50064,50065,50066,50067,27491,50068,50069,14380,50070,19793,27493, +50071,50072,50073,27489,50074,16691,50075,50076,50077,50078,50079,17954,50080, +50240,50241,50242,50243,50244,50245,19571,50246,27494,50247,16432,21048,27495, +50248,50249,50250,14383,14381,50251,27496,18235,19827,50252,50253,50254,27498, +27499,50255,50256,50257,50258,50259,27501,50260,50261,50262,50263,20552,50264, +27506,50265,27502,50266,50267,50268,27505,18553,50269,20860,27500,50270,50271, +27497,50272,50273,50274,50275,14393,20313,17509,27503,27504,19546,19784,12402, +50276,27510,50277,50278,50279,50280,50281,27509,50282,12850,50283,50284,50285, +50286,14432,50287,27511,50288,50289,50290,50291,50292,50293,12652,50294,50295, +19525,17444,20261,50296,50297,50298,50299,50300,27513,50301,50302,27682,50304, +17778,50305,27514,50306,50307,50308,50309,50310,50311,50312,50313,18757,50314, +50315,50316,50317,50318,50319,25183,27518,50320,50321,50322,50323,19790,27681, +12635,21303,50324,50325,21084,50326,50327,50328,27517,50329,27515,50330,50331, +50332,50333,50334,50335,50336,50496,50497,50498,50499,50500,50501,50502,50503, +50504,50505,50506,50507,50508,50509,50510,13116,50511,50512,50513,27184,50514, +50515,22356,50516,29739,13172,50517,50518,50519,50520,50521,22081,22082,50522, +50523,50524,50525,50526,50527,21865,15946,50528,29735,50529,21032,29736,29737, +50530,29738,15947,21343,50531,50532,50533,50534,50535,18784,18785,50536,50537, +29506,50538,19046,50539,19570,50540,50541,50542,50543,50544,50545,25142,19252, +50546,20072,22107,50547,29741,29742,29743,50548,50549,50550,50551,29746,50552, +14909,29747,12387,29744,50553,29745,15650,12885,50554,29750,29751,13926,12848, +20303,29748,13356,50555,29749,50556,50557,29752,50558,50560,50561,50562,50563, +29753,50564,50565,19751,50566,29754,50567,29755,50568,50569,50570,29756,50571, +50572,50573,50574,50575,50576,50577,50578,19282,50579,29757,50580,50581,50582, +50583,29758,50584,50585,50586,50587,50588,50589,50590,50591,29759,50592,50752, +50753,50754,50755,29790,16700,15464,50756,18731,20830,25973,50757,50758,50759, +50760,23603,21077,50761,50762,23604,12332,23605,50763,50764,15706,50765,23609, +50766,50767,50768,22594,50769,23607,21363,50770,18774,23610,23606,50771,23611, +17186,50772,50773,50774,50775,23612,23621,23613,50776,50777,20063,22053,50778, +23631,50779,23629,50780,50781,23634,15718,16939,50782,23608,23627,23630,23614, +14162,12357,23623,20542,23617,15144,50783,14140,23628,50784,50785,23622,23615, +18267,50786,50787,50788,20799,23616,50789,50790,23626,50791,50792,23632,50793, +50794,20013,23618,50795,23619,23624,23625,12884,23633,19285,50796,21559,23643, +23647,19494,23654,50797,17255,23644,50798,50799,16193,23641,50800,12410,14646, +23653,23635,50801,23620,23638,18548,16224,50802,50803,50804,50805,18747,50806, +50807,50808,12605,50809,21282,50810,50811,23642,50812,50813,23637,50814,17979, +50816,23646,50817,50818,50819,50820,50821,22338,17199,14134,18257,17193,23650, +23640,23659,23636,50822,50823,23645,50824,15909,23639,50825,23648,50826,50827, +23651,23652,50828,23672,50829,50830,23649,23842,23655,50831,50832,50833,50834, +50835,50836,50837,50838,50839,50840,15467,13380,50841,50842,17187,12903,23674, +50843,23666,50844,23663,50845,23676,23662,21104,12904,50846,18519,18531,23675, +50847,23661,50848,51008,51009,23671,51010,51011,23669,51012,51013,15907,23668, +51014,12893,51015,51016,51017,51018,51019,23667,15478,23656,15172,51020,16499, +51021,51022,51023,51024,51025,15444,23657,23658,51026,23665,23670,23673,13620, +51027,18521,15207,23678,23677,21291,23841,23843,23845,21105,23844,23846,23847, +21033,51028,51029,51030,51031,51032,51033,51034,14921,23849,51035,51036,23862, +23857,23860,51037,51038,51039,51040,51041,51042,51043,23856,17998,51044,51045, +16498,51046,51047,51048,51049,18735,51050,51051,51052,23660,23854,51053,51054, +51055,51056,23863,51057,51058,23664,23855,51059,23864,51060,23852,51061,51062, +51063,51064,51065,51066,51067,23865,23859,23853,17450,51068,51069,51070,51072, +23848,16435,16683,23850,23851,51073,23858,15217,23861,21288,23866,51074,23867, +17191,51075,51076,23890,23868,51077,51078,51079,23889,51080,14653,51081,51082, +15957,51083,15994,51084,51085,14922,51086,51087,51088,51089,23882,51090,23877, +51091,23871,51092,51093,51094,12875,23875,51095,23883,12836,23893,51096,51097, +51098,23870,51099,51100,51101,18000,23888,51102,51103,51104,51264,51265,23892, +16738,14150,51266,51267,51268,51269,51270,23886,23887,51271,51272,51273,23876, +51274,51275,51276,23869,51277,23885,19537,51278,23881,51279,51280,51281,51282, +23874,17224,17980,20014,23884,51283,23880,51284,51285,51286,51287,51288,51289, +23873,51290,51291,51292,23878,16988,51293,51294,51295,51296,51297,51298,21289, +21290,23891,20340,18552,51299,51300,51301,51302,51303,51304,51305,51306,23910, +51307,51308,51309,51310,51311,51312,23879,51313,51314,51315,23904,16996,51316, +51317,51318,51319,51320,51321,51322,51323,23905,51324,51325,51326,51328,51329, +51330,51331,51332,51333,51334,23895,51335,51336,51337,51338,51339,22136,51340, +23897,23896,14448,23894,51341,51342,51343,51344,17999,51345,13869,51346,51347, +51348,51349,51350,23906,51351,14969,21601,23911,51352,51353,51354,13392,51355, +23898,51356,16251,23907,51357,23903,51358,23901,51359,51360,51520,51521,51522, +51523,51524,13657,51525,51526,51527,51528,23899,23900,23902,51529,15663,23908, +51530,23909,51531,51532,51533,51534,51535,51536,51537,51538,23925,51539,17225, +51540,51541,19298,51542,51543,51544,51545,23922,51546,51547,51548,51549,51550, +51551,51552,51553,51554,51555,51556,51557,51558,22625,51559,51560,18001,51561, +23924,51562,51563,51564,21876,23923,23920,51565,51566,23916,51567,23919,51568, +23912,51569,51570,20590,51571,51572,51573,51574,18520,23918,51575,51576,23913, +51577,51578,23914,19314,51579,23917,51580,51581,12621,51582,51584,51585,51586, +51587,51588,16438,51589,15419,23921,51590,51591,23927,51592,23926,23915,51593, +51594,51595,51596,51597,17774,51598,51599,51600,23931,51601,51602,51603,51604, +51605,51606,51607,51608,51609,51610,51611,24100,51612,51613,24099,51614,51615, +51616,51776,51777,51778,51779,51780,51781,51782,51783,51784,23928,51785,51786, +51787,51788,17263,51789,17019,51790,51791,51792,21857,51793,51794,20021,51795, +51796,51797,51798,23933,51799,12876,51800,51801,51802,51803,51804,51805,51806, +51807,51808,17512,19039,51809,51810,51811,51812,51813,51814,51815,51816,51817, +51818,18238,23930,23932,23934,24098,12330,12622,51819,51820,51821,51822,51823, +24108,51824,51825,51826,51827,24102,15670,18543,51828,51829,51830,51831,51832, +51833,51834,51835,51836,51837,51838,24097,51840,51841,24101,51842,51843,51844, +51845,24105,51846,51847,51848,51849,51850,24104,51851,51852,51853,24103,51854, +51855,51856,51857,51858,51859,51860,51861,51862,24109,51863,21580,51864,51865, +51866,51867,24115,24106,24110,51868,51869,16473,51870,51871,51872,52032,52033, +12577,24118,52034,24113,52035,52036,52037,52038,52039,52040,52041,24114,52042, +52043,52044,52045,52046,52047,52048,52049,52050,52051,52052,20774,24117,52053, +52054,52055,52056,52057,52058,52059,24111,52060,52061,52062,24112,52063,20541, +52064,52065,52066,24116,19053,24121,52067,52068,52069,52070,52071,52072,24120, +52073,24119,52074,52075,52076,52077,52078,52079,52080,24123,52081,52082,52083, +52084,52085,52086,52087,15717,52088,52089,52090,52091,52092,12888,17258,52093, +52094,24122,52096,17722,52097,52098,52099,52100,52101,52102,24124,52103,52104, +52105,52106,52107,52108,52109,19545,52110,52111,52112,52113,14122,52114,52115, +52116,52117,52118,52119,52120,52121,52122,52123,52124,52125,52126,52127,52128, +52288,52289,21605,52290,52291,52292,24125,52293,52294,52295,52296,52297,24127, +52298,52299,52300,52301,52302,52303,52304,52305,52306,52307,52308,17442,52309, +52310,52311,52312,24129,52313,52314,52315,52316,52317,52318,52319,52320,52321, +52322,52323,52324,52325,52326,52327,52328,24126,52329,24128,52330,52331,52332, +52333,52334,52335,52336,52337,52338,52339,52340,52341,52342,52343,21818,52344, +52345,52346,24130,52347,52348,52349,52350,52352,52353,52354,52355,52356,52357, +52358,52359,52360,52361,52362,52363,29230,15138,16946,17712,16967,52364,52365, +29231,52366,52367,52368,52369,52370,20585,52371,52372,52373,21341,52374,52375, +52376,27453,52377,52378,52379,52380,52381,52382,52383,52384,13158,29232,52544, +29233,52545,52546,18989,52547,52548,52549,52550,52551,52552,52553,14951,29235, +29237,29236,19300,20282,29234,18996,21071,17004,52554,52555,52556,52557,52558, +52559,52560,20035,29240,12406,29239,52561,52562,52563,52564,52565,29246,52566, +12879,52567,52568,52569,52570,52571,52572,20801,29242,52573,52574,52575,52576, +52577,29244,21609,52578,52579,29243,29238,29247,29245,52580,29241,52581,52582, +29255,29252,29254,52583,52584,29258,29250,29248,52585,52586,52587,29253,52588, +52589,52590,52591,52592,22139,52593,52594,52595,29249,52596,18297,18783,52597, +29256,14662,13616,52598,52599,29251,29257,29264,29270,52600,52601,15191,52602, +52603,52604,29269,19804,52605,22123,52606,52608,29266,29268,52609,52610,52611, +52612,14450,52613,52614,52615,52616,29259,52617,52618,52619,29262,17017,52620, +21853,29260,29261,29263,29267,52621,52622,52623,29273,21308,52624,52625,52626, +52627,13930,52628,19057,52629,14180,29271,52630,52631,52632,29272,29274,29277, +29275,52633,52634,29276,52635,52636,52637,52638,20817,29265,52639,19785,52640, +20047,22057,52800,29283,52801,17243,52802,29280,52803,52804,16431,29292,29278, +52805,29281,52806,52807,52808,29288,52809,52810,52811,52812,29282,52813,52814, +29287,52815,52816,29286,52817,52818,29289,52819,52820,52821,29279,52822,52823, +29284,29290,52824,52825,52826,52827,52828,52829,52830,21292,29285,12917,52831, +52832,29298,52833,20523,52834,52835,52836,52837,29301,52838,52839,52840,15176, +52841,29305,52842,52843,52844,52845,52846,52847,29296,52848,52849,29302,29304, +29306,52850,52851,52852,52853,52854,52855,52856,52857,29299,52858,29297,52859, +52860,52861,14971,52862,13691,52864,52865,52866,52867,29295,29303,29293,29294, +52868,52869,52870,29291,29478,52871,29475,52872,52873,29474,52874,52875,29300, +52876,18522,52877,52878,52879,52880,52881,29307,52882,52883,52884,29477,52885, +52886,52887,52888,52889,52890,52891,17272,52892,52893,52894,52895,52896,53056, +53057,53058,29309,53059,53060,29479,29481,29476,53061,29308,53062,53063,53064, +29483,53065,29482,53066,53067,53068,53069,16989,53070,53071,29486,53072,53073, +29488,53074,53075,53076,53077,53078,29473,53079,53080,53081,29489,29484,53082, +53083,53084,53085,53086,29487,29310,29485,53087,53088,53089,53090,53091,53092, +53093,29490,53094,53095,53096,53097,29492,53098,53099,53100,53101,29480,53102, +53103,53104,53105,29491,53106,53107,53108,29493,53109,53110,53111,53112,53113, +53114,53115,53116,53117,53118,20535,53120,53121,53122,53123,29496,53124,53125, +53126,53127,22905,53128,53129,53130,53131,53132,53133,29497,53134,53135,53136, +53137,53138,53139,53140,53141,29495,53142,18532,29494,53143,53144,53145,53146, +29498,53147,53148,53149,53150,53151,29499,13376,53152,53312,53313,53314,53315, +53316,53317,53318,53319,53320,53321,53322,53323,53324,53325,28227,53326,53327, +53328,53329,53330,53331,29500,53332,53333,29501,53334,53335,53336,20778,53337, +53338,53339,29740,20550,53340,53341,53342,53343,53344,53345,20560,20828,53346, +53347,53348,53349,53350,53351,20302,53352,53353,15702,53354,20803,53355,53356, +53357,53358,53359,53360,53361,14946,24937,21058,28994,12857,53362,53363,12653, +28995,53364,18752,13124,53365,22898,53366,19237,53367,28996,53368,53369,53370, +53371,22100,53372,53373,53374,53376,53377,28997,29760,28998,53378,21548,28999, +53379,12352,29761,53380,53381,29762,53382,53383,13436,53384,17755,53385,53386, +53387,53388,19515,53389,53390,53391,20580,53392,53393,53394,53395,53396,19808, +53397,53398,53399,53400,53401,29000,53402,22899,53403,53404,53405,53406,53407, +53408,12603,53568,20270,53569,53570,53571,14372,53572,53573,53574,53575,53576, +29002,53577,53578,53579,53580,29003,53581,53582,53583,53584,12867,16721,53585, +53586,22320,29001,53587,53588,29004,53589,53590,53591,53592,29006,53593,53594, +53595,22902,53596,21089,21539,53597,53598,29763,18489,53599,53600,53601,53602, +53603,29764,53604,53605,29005,29007,16227,29008,53606,53607,29012,53608,53609, +53610,53611,53612,53613,53614,29014,29009,53615,18769,17761,53616,53617,53618, +16995,14716,53619,53620,29011,53621,29013,53622,53623,53624,14675,53625,53626, +53627,53628,53629,53630,53632,29019,53633,53634,53635,53636,53637,14934,53638, +12413,29017,53639,53640,53641,53642,53643,29016,29010,29018,53644,53645,53646, +53647,53648,29015,53649,53650,53651,18540,53652,53653,53654,53655,19786,29021, +53656,53657,53658,53659,25917,53660,53661,53662,29020,53663,29022,53664,53824, +53825,53826,53827,53828,53829,53830,53831,53832,29023,53833,53834,20325,53835, +53836,53837,53838,53839,53840,53841,53842,53843,53844,53845,53846,53847,53848, +53849,53850,53851,53852,53853,53854,53855,53856,53857,53858,53859,29765,15731, +53860,53861,53862,53863,53864,53865,29024,53866,53867,53868,53869,53870,53871, +53872,53873,53874,53875,53876,53877,53878,53879,53880,53881,53882,53883,53884, +53885,29025,53886,53888,53889,20087,53890,21034,53891,29051,53892,53893,14386, +53894,53895,53896,53897,53898,53899,53900,53901,53902,53903,53904,53905,53906, +53907,53908,53909,53910,53911,53912,53913,53914,53915,53916,53917,53918,53919, +53920,54080,54081,54082,54083,54084,54085,54086,54087,54088,54089,54090,54091, +54092,54093,54094,54095,54096,54097,54098,54099,54100,54101,54102,54103,54104, +54105,54106,54107,54108,54109,54110,15483,14683,54111,14694,17241,19027,27240, +16448,15989,27241,27242,27243,54112,27244,27245,27246,27247,15687,54113,54114, +54115,30075,54116,54117,54118,30077,54119,30078,54120,30076,54121,54122,54123, +54124,15714,54125,30241,13349,54126,54127,54128,54129,30242,54130,54131,54132, +30243,54133,54134,54135,27698,54136,54137,54138,54139,54140,54141,54142,54144, +54145,54146,54147,54148,20820,54149,54150,54151,54152,54153,54154,22890,54155, +54156,54157,54158,54159,54160,54161,54162,54163,54164,54165,54166,54167,54168, +54169,54170,54171,54172,54173,54174,54175,54176,54336,54337,54338,54339,54340, +54341,54342,54343,54344,54345,54346,54347,54348,54349,54350,54351,54352,54353, +54354,54355,54356,54357,54358,54359,54360,54361,54362,54363,54364,54365,54366, +54367,30244,54368,54369,54370,54371,54372,54373,54374,54375,54376,28218,54377, +54378,54379,54380,54381,54382,54383,54384,54385,54386,54387,54388,54389,54390, +54391,54392,54393,54394,54395,54396,54397,54398,54400,54401,54402,54403,54404, +54405,54406,54407,54408,54409,54410,54411,54412,54413,54414,54415,54416,54417, +54418,54419,54420,54421,54422,54423,54424,54425,21810,54426,54427,54428,54429, +54430,54431,54432,54592,54593,54594,54595,54596,54597,54598,54599,21374,19548, +54600,54601,54602,54603,54604,54605,54606,54607,19012,54608,54609,54610,54611, +54612,54613,54614,54615,54616,54617,54618,54619,54620,54621,54622,54623,54624, +54625,54626,54627,54628,54629,54630,54631,54632,54633,54634,54635,54636,54637, +54638,54639,54640,54641,54642,54643,54644,54645,54646,54647,54648,54649,54650, +54651,54652,54653,54654,54656,54657,54658,54659,54660,54661,54662,54663,54664, +54665,54666,54667,54668,54669,54670,54671,54672,54673,54674,54675,54676,54677, +54678,54679,54680,54681,54682,54683,54684,54685,54686,54687,54688,54848,54849, +54850,54851,54852,54853,54854,54855,54856,54857,54858,54859,54860,54861,54862, +54863,54864,54865,54866,54867,54868,54869,54870,54871,54872,54873,54874,54875, +54876,54877,54878,54879,54880,54881,54882,25920,54883,54884,54885,54886,54887, +54888,54889,54890,54891,54892,54893,54894,54895,54896,54897,54898,54899,54900, +54901,54902,54903,54904,54905,54906,54907,54908,54909,54910,54912,54913,30245, +54914,54915,54916,54917,54918,54919,54920,54921,54922,54923,54924,54925,54926, +54927,54928,54929,54930,54931,54932,54933,54934,54935,54936,54937,54938,54939, +54940,54941,54942,54943,54944,55104,55105,55106,55107,55108,55109,55110,55111, +55112,55113,55114,55115,55116,55117,55118,55119,55120,55121,55122,55123,55124, +55125,55126,55127,55128,55129,55130,55131,55132,55133,55134,55135,15919,55136, +55137,55138,55139,55140,17961,55141,55142,55143,55144,55145,55146,55147,55148, +55149,55150,55151,55152,55153,55154,55155,55156,55157,55158,55159,55160,55161, +55162,55163,55164,55165,55166,55168,55169,55170,55171,55172,55173,55174,55175, +55176,55177,55178,55179,55180,55181,55182,55183,55184,55185,55186,55187,55188, +55189,55190,55191,55192,23077,15430,13865,14396,18511,15397,23078,23079,19542, +18499,23080,18045,55193,20789,21097,20790,15431,55194,15666,15204,23081,23082, +20808,23083,20589,13935,16987,55195,19279,14189,18792,14147,15991,22052,23084, +23085,17984,22375,18998,55196,21801,19295,21871,23086,22111,13386,23088,23087, +55197,21099,23089,23090,23091,19028,23092,18987,23093,23094,13135,22127,23095, +15152,13614,23096,23097,14702,20783,21096,23098,14403,20330,12911,23099,23100, +55198,15723,20060,21359,23101,20083,23102,21333,15205,23103,19253,19280,23104, +18283,22126,23105,17717,13889,23106,14156,16206,23107,23108,19245,23109,13687, +23110,16706,22331,23111,19512,55199,21098,17457,23112,13693,15185,23113,20531, +23114,23115,20029,23116,23117,23118,12919,23121,23119,20840,23120,17237,23122, +55200,23123,23124,23125,20539,21029,12409,23126,18219,23127,15735,17185,23128, +23129,17277,19511,23130,23131,16446,18007,23132,23133,18228,23134,23135,14664, +55360,55361,55362,55363,55364,55365,55366,55367,55368,15213,55369,55370,55371, +55372,13881,29816,55373,29817,55374,55375,19811,55376,55377,55378,55379,55380, +55381,55382,55383,30009,55384,55385,55386,55387,27488,55388,55389,55390,55391, +55392,55393,20339,15167,55394,55395,55396,55397,55398,55399,55400,14912,21541, +55401,55402,55403,55404,55405,55406,55407,24921,55408,55409,55410,55411,30068, +12586,12914,55412,55413,55414,55415,55416,55417,55418,30069,55419,55420,30071, +55421,55422,55424,14929,30070,55425,17202,55426,55427,55428,55429,55430,55431, +55432,30073,55433,55434,55435,30072,55436,55437,55438,55439,55440,55441,55442, +55443,55444,55445,55446,55447,55448,55449,55450,55451,55452,55453,55454,55455, +55456,55616,55617,55618,55619,55620,55621,55622,55623,55624,55625,55626,55627, +55628,55629,55630,55631,55632,55633,55634,55635,55636,55637,55638,55639,55640, +55641,55642,55643,55644,55645,55646,55647,55648,55649,55650,55651,55652,55653, +55654,55655,55656,55657,55658,55659,55660,55661,55662,55663,55664,55665,55666, +55667,55668,55669,55670,55671,55672,55673,55674,55675,55676,55677,55678,55680, +55681,55682,55683,55684,55685,55686,55687,55688,55689,55690,55691,55692,55693, +55694,55695,55696,55697,55698,55699,55700,55701,55702,55703,55704,55705,55706, +55707,55708,55709,55710,55711,55712,55872,55873,55874,55875,55876,55877,55878, +55879,55880,55881,55882,55883,55884,55885,55886,12596,21866,14394,55887,14641, +12870,21616,20301,12380,21835,15221,22090,14135,19504,17974,12641,14650,22140, +14689,14113,15482,27226,27227,19577,14707,27228,13435,17203,14161,14936,27229, +21620,27230,15446,15199,27231,16734,16952,21599,22346,27232,27233,27236,27234, +27235,18782,14387,13892,27237,19050,18765,13389,55888,55889,25177,17762,27238, +16437,55890,22328,27239,22316,18556,22611,22605,21598,55891,21625,18756,21294, +14419,13152,55892,18786,29814,55893,55894,55895,14933,55896,29815,55897,55898, +22367,55899,55900,29809,14384,21844,14415,18032,55901,55902,55903,55904,55905, +55906,55907,55908,55909,13123,55910,55911,29810,13100,55912,55913,55914,55915, +21565,18295,55916,55917,55918,55919,55920,29812,55921,55922,29811,55923,55924, +55925,55926,55927,55928,55929,55930,55931,55932,19531,55933,55934,55936,18468, +55937,55938,55939,55940,55941,55942,55943,55944,55945,55946,55947,55948,55949, +29813,55950,22371,17727,30016,55951,55952,30011,55953,30019,55954,30018,55955, +22074,30017,55956,55957,55958,21566,30020,55959,30028,55960,55961,55962,55963, +12367,13688,55964,30025,30026,55965,17756,55966,55967,55968,56128,30021,30022, +56129,56130,30023,30027,56131,15968,30024,14458,56132,56133,56134,30032,30035, +56135,56136,56137,16231,56138,14706,30012,30029,56139,56140,16951,56141,56142, +56143,19576,56144,15481,56145,30030,30031,30033,13925,30034,56146,30037,56147, +56148,56149,56150,56151,56152,56153,30013,56154,56155,56156,30036,21307,56157, +13164,56158,56159,19492,56160,56161,56162,56163,30038,56164,56165,56166,56167, +56168,56169,56170,56171,30039,15969,30040,56172,56173,19551,30043,56174,56175, +56176,56177,56178,12872,22361,56179,30041,56180,30042,30044,56181,30050,56182, +56183,56184,30048,56185,56186,56187,30047,30045,56188,56189,30049,56190,56192, +30046,30052,30053,56193,19555,56194,56195,25919,13624,30051,30056,19491,56196, +56197,56198,56199,56200,30054,30055,56201,56202,56203,56204,56205,56206,30014, +56207,56208,56209,56210,56211,56212,56213,56214,56215,56216,56217,56218,12612, +56219,56220,30015,56221,56222,13637,12900,56223,30060,30057,56224,13911,56384, +30061,56385,30058,56386,56387,56388,56389,56390,30059,56391,56392,13402,56393, +21610,56394,56395,56396,30062,56397,13177,56398,56399,56400,56401,56402,56403, +56404,30063,30065,56405,56406,56407,30064,56408,56409,56410,56411,56412,56413, +56414,30066,56415,30067,56416,56417,56418,56419,56420,56421,56422,56423,56424, +56425,56426,56427,18797,14634,56428,56429,18299,56430,56431,13923,56432,56433, +56434,56435,56436,56437,56438,19529,56439,56440,56441,56442,56443,56444,56445, +56446,56448,56449,56450,56451,56452,56453,56454,56455,56456,56457,56458,27174, +56459,56460,56461,56462,56463,56464,56465,56466,56467,56468,56469,56470,56471, +56472,56473,56474,56475,56476,56477,56478,56479,56480,56640,56641,56642,56643, +56644,56645,56646,56647,56648,56649,56650,56651,56652,56653,56654,56655,56656, +56657,56658,56659,56660,56661,56662,56663,56664,56665,56666,56667,56668,56669, +56670,56671,56672,56673,56674,56675,56676,56677,56678,56679,56680,56681,56682, +56683,56684,56685,56686,56687,56688,56689,56690,56691,56692,56693,56694,56695, +56696,56697,56698,56699,56700,56701,56702,56704,56705,56706,56707,56708,56709, +56710,56711,56712,56713,56714,56715,56716,56717,56718,56719,56720,56721,56722, +56723,56724,56725,56726,56727,56728,56729,56730,56731,56732,56733,56734,56735, +56736,56896,56897,56898,56899,56900,56901,56902,56903,56904,56905,56906,56907, +56908,56909,56910,56911,56912,56913,56914,56915,56916,56917,56918,56919,56920, +56921,56922,56923,56924,56925,56926,56927,56928,13109,21630,14700,20601,56929, +26989,22314,26990,16982,18541,14948,26991,26992,26993,22113,26994,26995,26997, +26996,26998,26999,18273,27000,21592,27001,15694,56930,27002,27003,15695,27004, +14376,16702,27005,12594,15188,14709,27006,56931,27169,27170,27171,14200,15405, +56932,19044,24654,21551,20285,21815,27172,21854,27173,20545,14652,56933,13383, +12633,56934,56935,56936,16433,56937,56938,56939,56940,12646,12647,56941,12648, +56942,56943,56944,56945,13117,18536,56946,56947,56948,56949,25921,56950,56951, +12639,56952,56953,56954,16713,13423,56955,56956,18216,21336,56957,18041,20792, +56958,14717,17013,56960,56961,56962,56963,56964,21293,56965,21579,15740,56966, +25922,14133,25923,56967,56968,15161,21858,56969,15736,21558,20005,16684,13145, +56970,56971,19574,56972,25926,25924,25928,56973,25930,25927,13647,17992,56974, +13692,25925,56975,19062,56976,56977,25929,56978,56979,56980,17236,12613,15395, +56981,56982,56983,22327,56984,56985,19787,19277,19018,19539,25932,25931,17510, +56986,56987,20769,20791,25933,56988,25936,56989,19768,22128,25935,13661,56990, +19774,56991,25937,13882,56992,57152,19752,14692,57153,19013,13137,19289,21612, +25938,14186,57154,57155,57156,25934,57157,57158,57159,57160,57161,57162,25941, +13438,25942,57163,57164,57165,57166,57167,25939,25940,57168,21085,57169,57170, +16991,12614,57171,21346,57172,57173,13917,19308,57174,25943,57175,57176,21366, +57177,57178,57179,57180,57181,12649,57182,13940,25946,25944,25945,13632,57183, +57184,57185,21061,25948,57186,57187,25950,57188,57189,57190,57191,57192,57193, +25949,18226,57194,21027,57195,57196,25947,57197,57198,57199,57200,21602,21850, +57201,57202,57203,57204,57205,25952,22385,57206,57207,57208,57209,57210,57211, +57212,25953,57213,12636,20859,57214,25954,25956,57216,57217,57218,57219,25955, +57220,57221,25957,57222,57223,57224,57225,57226,21080,57227,13643,57228,26463, +57229,23157,57230,23160,57231,23158,57232,23159,57233,57234,57235,23162,20559, +17479,57236,57237,12398,57238,57239,57240,20528,57241,23161,57242,21322,14890, +23330,18289,57243,23164,23163,18779,23165,57244,23329,22366,23166,16730,57245, +57246,23333,57247,57248,21364,57408,57409,23335,23332,57410,23336,57411,57412, +15676,57413,57414,57415,16457,23331,23334,22051,57416,23337,57417,57418,57419, +23341,57420,57421,57422,23342,23340,14914,57423,57424,57425,16164,23339,57426, +57427,57428,23338,21575,12863,57429,57430,23343,57431,14713,57432,23344,57433, +57434,57435,57436,13115,57437,57438,57439,13606,57440,57441,57442,57443,13884, +23345,57444,57445,57446,13941,57447,23346,57448,57449,57450,57451,57452,57453, +57454,57455,57456,57457,57458,57459,57460,57461,57462,57463,57464,57465,57466, +57467,12617,57468,57469,57470,57472,23348,57473,57474,57475,23347,23349,57476, +57477,57478,57479,57480,57481,57482,57483,57484,57485,57486,23351,57487,23350, +57488,57489,57490,57491,57492,57493,57494,23352,57495,57496,57497,57498,57499, +57500,57501,57502,57503,23353,57504,57664,23354,57665,57666,21327,29818,18293, +22339,17764,29820,29821,29819,57667,15942,57668,57669,57670,57671,20591,57672, +57673,14163,57674,57675,21581,19498,57676,57677,29986,29985,14888,29822,19286, +57678,57679,57680,29988,16466,57681,13162,57682,19754,29989,29987,15668,29992, +57683,29993,15693,17208,16225,19297,29994,57684,57685,57686,29990,29991,17520, +57687,57688,57689,57690,57691,29996,57692,13372,57693,22381,57694,13399,29995, +29998,57695,57696,29997,29999,20561,57697,57698,57699,57700,57701,57702,57703, +17233,18473,57704,57705,57706,57707,57708,57709,30000,30001,57710,57711,57712, +57713,57714,57715,30002,57716,57717,30003,30004,30005,57718,57719,57720,57721, +30007,30006,57722,57723,57724,57725,30008,57726,57728,57729,57730,57731,57732, +57733,57734,57735,57736,57737,57738,12873,57739,21332,19021,57740,16495,22104, +21040,16703,57741,15728,57742,57743,57744,57745,57746,57747,57748,57749,57750, +57751,14378,57752,57753,57754,57755,57756,57757,57758,57759,57760,57920,57921, +57922,57923,57924,57925,57926,57927,57928,57929,57930,57931,57932,57933,57934, +57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946,57947, +57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959,57960, +57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972,57973, +57974,57975,57976,57977,57978,57979,57980,57981,57982,57984,57985,57986,57987, +57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998,57999,58000, +58001,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011,58012,58013, +58014,58015,58016,58176,58177,58178,58179,58180,58181,58182,58183,58184,58185, +58186,58187,58188,58189,58190,58191,58192,58193,58194,58195,58196,58197,58198, +58199,58200,58201,58202,58203,58204,58205,58206,58207,58208,58209,58210,58211, +58212,58213,58214,58215,58216,58217,58218,58219,58220,58221,15480,58222,58223, +58224,58225,58226,58227,58228,58229,58230,58231,58232,58233,58234,58235,58236, +58237,58238,58240,58241,58242,58243,58244,58245,58246,58247,30278,58248,58249, +58250,58251,58252,58253,58254,58255,58256,58257,58258,58259,58260,58261,58262, +58263,58264,58265,58266,58267,58268,58269,58270,58271,58272,58432,58433,58434, +58435,58436,58437,30279,58438,58439,58440,58441,58442,58443,58444,58445,58446, +58447,58448,58449,58450,58451,58452,58453,58454,58455,58456,58457,58458,58459, +58460,58461,58462,30280,58463,58464,58465,58466,58467,58468,58469,58470,58471, +58472,58473,58474,58475,58476,58477,58478,58479,58480,58481,58482,58483,58484, +58485,58486,58487,58488,58489,58490,58491,58492,58493,58494,58496,58497,58498, +58499,58500,58501,58502,58503,58504,58505,58506,58507,58508,58509,58510,58511, +58512,58513,58514,58515,58516,58517,58518,58519,58520,58521,58522,58523,58524, +58525,58526,58527,58528,58688,58689,58690,58691,58692,58693,58694,58695,58696, +58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707,58708,58709, +58710,58711,58712,58713,58714,58715,58716,58717,58718,58719,58720,58721,58722, +58723,58724,58725,58726,58727,58728,58729,58730,58731,58732,58733,58734,58735, +58736,58737,58738,58739,30281,58740,58741,58742,58743,58744,58745,58746,58747, +58748,58749,58750,58752,58753,58754,58755,58756,58757,58758,58759,58760,58761, +58762,58763,58764,58765,58766,58767,58768,58769,58770,58771,58772,58773,58774, +58775,58776,58777,58778,58779,58780,58781,58782,58783,30282,58784,58944,58945, +58946,58947,58948,58949,58950,58951,58952,58953,58954,58955,58956,58957,58958, +58959,58960,58961,58962,58963,58964,58965,58966,58967,58968,58969,58970,58971, +58972,58973,58974,58975,58976,58977,58978,30284,58979,58980,58981,58982,58983, +58984,58985,58986,58987,58988,58989,58990,58991,58992,58993,58994,58995,58996, +58997,58998,58999,59000,59001,59002,59003,59004,59005,59006,59008,59009,59010, +59011,59012,59013,59014,59015,59016,59017,59018,59019,59020,59021,59022,59023, +59024,59025,59026,59027,59028,59029,59030,59031,59032,59033,59034,59035,59036, +59037,30283,59038,59039,59040,59200,59201,59202,59203,59204,59205,59206,59207, +30569,59208,59209,59210,59211,59212,59213,59214,59215,59216,59217,59218,59219, +59220,59221,59222,59223,59224,59225,59226,59227,59228,59229,59230,59231,59232, +59233,59234,59235,59236,59237,59238,59239,59240,59241,59242,59243,59244,59245, +59246,59247,59248,59249,59250,59251,59252,59253,59254,59255,59256,59257,59258, +59259,59260,59261,59262,59264,59265,59266,59267,59268,59269,59270,59271,59272, +59273,59274,59275,59276,59277,59278,59279,59280,59281,59282,59283,59284,59285, +59286,59287,59288,59289,59290,59291,59292,59293,59294,59295,59296,59456,59457, +59458,59459,59460,59461,59462,59463,59464,59465,59466,59467,59468,59469,59470, +30285,59471,59472,59473,59474,59475,59476,59477,59478,59479,59480,59481,59482, +59483,59484,59485,59486,59487,59488,59489,59490,59491,59492,59493,59494,59495, +59496,59497,59498,59499,59500,59501,59502,59503,59504,59505,59506,59507,59508, +59509,59510,59511,59512,59513,59514,30286,59515,59516,59517,59518,59520,59521, +59522,59523,59524,59525,59526,59527,59528,59529,59530,59531,59532,59533,59534, +59535,59536,59537,59538,59539,59540,28228,28229,28230,21867,13860,28232,28231, +28233,28234,18213,28235,28236,59541,14128,13686,28237,28239,59542,28238,59543, +14406,28240,28241,28242,13915,13102,22099,17478,12597,14422,28243,28244,21567, +18261,15995,20057,14643,28246,28245,28248,28247,17701,28249,28250,18222,28251, +18223,28252,12839,28253,28254,28255,28256,28257,22378,28258,28259,15448,28260, +21323,19578,12844,16741,28261,18214,17197,59544,28262,28263,28264,28265,28266, +28267,28268,59545,28269,28270,28271,59546,59547,28272,28273,28274,28276,28275, +59548,28277,19757,16961,28278,28279,28280,21793,28281,20275,28282,28283,59549, +28284,28285,28449,28286,28450,14453,17274,28451,28452,15682,21055,12921,28453, +28454,28455,21112,28456,22141,28457,17996,59550,28458,28459,16692,28460,20346, +19320,28462,28461,13178,14712,28463,28464,20578,28465,28466,14182,20543,28467, +28468,28469,18545,19552,28470,28471,28472,28473,28474,21856,28475,13421,17194, +28476,59551,28477,28478,28479,59552,20093,28480,16992,13368,22326,15733,59712, +20295,28483,28481,28482,28484,13863,15484,15970,17228,28485,28486,59713,28487, +28495,28488,28489,28490,18242,28529,13901,28491,59714,28492,28493,13894,17214, +28494,59715,28496,28497,28498,21874,59716,28499,17527,59717,28500,17528,28501, +28502,14436,12407,28503,28504,28505,59718,28506,28507,28508,28509,59719,28510, +15925,28513,28511,28512,59720,28514,28515,16717,28516,28517,28518,28519,28520, +28521,28522,28523,28524,16472,59721,28525,16685,28526,28527,28528,59722,59723, +20322,59724,59725,59726,59727,59728,59729,59730,59731,13092,59732,59733,59734, +59735,59736,59737,59738,59739,59740,59741,59742,59743,59744,59745,59746,59747, +59748,59749,59750,59751,59752,59753,59754,59755,59756,59757,59758,59759,59760, +59761,59762,59763,59764,59765,59766,59767,59768,59769,59770,59771,59772,59773, +59774,59776,59777,59778,59779,59780,59781,59782,59783,59784,59785,59786,59787, +59788,59789,59790,59791,59792,59793,59794,59795,59796,59797,59798,59799,59800, +59801,59802,59803,59804,59805,59806,59807,59808,59968,59969,59970,59971,59972, +59973,59974,59975,59976,59977,59978,59979,59980,59981,59982,59983,59984,59985, +59986,59987,59988,59989,59990,59991,59992,59993,59994,59995,17221,25413,18753, +25414,59996,12629,20042,13363,18546,25415,20304,25416,15460,25417,25418,17222, +21794,17494,14699,20037,25419,17270,25420,59997,14119,14451,14930,25421,25422, +21572,25423,59998,25424,20811,25425,25426,25427,25428,20822,25429,12923,16443, +25430,59999,16427,25431,25432,25433,60000,25434,25435,60001,14391,23138,60002, +13907,60003,23140,23139,60004,60005,60006,60007,60008,60009,60010,23142,60011, +60012,60013,18542,60014,60015,23141,14144,20852,21109,21875,15703,60016,60017, +60018,60019,22376,23144,23143,60020,12322,19795,60021,23145,60022,14397,15434, +16957,16932,13122,23146,60023,16938,17456,15669,60024,60025,20318,60026,60027, +60028,23147,18754,60029,60030,60032,60033,60034,12637,60035,60036,60037,23148, +60038,13880,21562,60039,13181,60040,60041,23149,21577,20309,17763,60042,23150, +60043,60044,60045,60046,60047,23151,60048,23152,16746,19541,20317,60049,60050, +60051,60052,60053,60054,60055,60056,60057,60058,60059,60060,60061,21351,16929, +60062,23153,60063,60064,19301,60224,23154,60225,19302,21118,60226,60227,60228, +14452,60229,60230,23155,12335,20278,60231,60232,21839,60233,60234,60235,60236, +60237,60238,60239,60240,60241,60242,19309,60243,60244,60245,60246,60247,60248, +60249,60250,23156,60251,60252,25412,60253,60254,16677,60255,60256,30271,60257, +60258,30272,30273,17489,60259,18488,20835,60260,60261,20571,20805,15407,14669, +60262,28532,60263,60264,13382,21306,30274,13179,60265,60266,30275,60267,60268, +13681,60269,60270,60271,60272,60273,60274,60275,60276,60277,60278,30277,60279, +60280,60281,60282,60283,60284,60285,21354,30247,20777,60286,60288,60289,60290, +30249,60291,60292,60293,30248,60294,60295,16739,16471,60296,12578,60297,60298, +60299,60300,20077,60301,20584,30251,60302,60303,20342,60304,30250,21872,30252, +17209,60305,60306,60307,15220,30254,30253,60308,60309,60310,17502,60311,60312, +16728,60313,60314,60315,60316,60317,19242,60318,20284,60319,60320,60480,60481, +60482,60483,60484,60485,60486,60487,60488,30255,60489,60490,30256,60491,60492, +30257,60493,16950,60494,60495,60496,60497,60498,12372,17785,60499,60500,60501, +60502,30258,60503,60504,60505,60506,60507,60508,60509,60510,60511,60512,60513, +60514,60515,60516,60517,60518,60519,60520,60521,18272,30246,60522,60523,15928, +60524,60525,15922,60526,13669,60527,60528,14151,60529,16191,17234,17254,60530, +60531,22604,60532,60533,60534,14447,60535,60536,60537,60538,60539,60540,60541, +60542,60544,15737,20773,60545,12368,60546,60547,60548,60549,60550,30512,60551, +60552,60553,60554,60555,60556,60557,60558,30513,60559,60560,60561,60562,60563, +20524,60564,12336,60565,60566,60567,30514,30515,60568,30516,60569,60570,60571, +18250,60572,60573,60574,60575,60576,60736,60737,15951,60738,60739,30519,60740, +60741,60742,60743,60744,60745,60746,30518,60747,12638,60748,30517,60749,60750, +30520,60751,30521,60752,60753,60754,60755,60756,60757,60758,60759,60760,60761, +60762,60763,60764,60765,60766,60767,60768,60769,60770,60771,60772,60773,60774, +60775,60776,60777,60778,60779,60780,60781,60782,60783,60784,60785,60786,60787, +60788,60789,60790,60791,60792,60793,60794,60795,60796,60797,60798,60800,60801, +20004,18509,60802,14891,26680,26681,26682,15938,60803,60804,60805,60806,60807, +21108,60808,21583,18776,60809,60810,60811,60812,60813,60814,60815,60816,60817, +60818,60819,60820,60821,60822,60823,60824,60825,60826,60827,60828,60829,60830, +60831,60832,60992,60993,60994,60995,60996,60997,60998,60999,61000,61001,61002, +61003,61004,61005,61006,61007,61008,61009,61010,61011,61012,61013,61014,61015, +61016,61017,61018,61019,61020,61021,61022,61023,61024,61025,61026,61027,61028, +61029,61030,61031,61032,61033,61034,61035,61036,61037,61038,61039,61040,61041, +61042,61043,61044,61045,61046,61047,61048,61049,61050,61051,61052,61053,61054, +61056,61057,61058,61059,61060,61061,61062,61063,61064,61065,61066,61067,61068, +61069,61070,61071,61072,61073,61074,61075,61076,61077,61078,61079,61080,61081, +61082,61083,61084,61085,61086,61087,61088,61248,61249,61250,61251,61252,61253, +21043,13861,18282,29052,20334,19251,20587,26479,19815,14667,13913,29053,12388, +19276,29054,21540,16941,16748,17988,15921,29217,15445,61254,29218,29219,61255, +29220,21059,17973,61256,19783,29221,61257,21297,16197,19554,61258,29222,29223, +20821,13934,29224,29225,13663,29226,29227,61259,12924,29228,29229,18471,61260, +61261,61262,61263,61264,61265,61266,61267,61268,61269,61270,61271,61272,61273, +61274,61275,61276,61277,61278,61279,61280,61281,61282,61283,61284,61285,61286, +61287,61288,61289,61290,61291,61292,61293,61294,61295,61296,61297,14183,61298, +61299,27689,27690,27691,61300,27692,61301,61302,17966,27693,27694,61303,61304, +61305,14153,18995,61306,61307,61308,61309,61310,61312,61313,25144,30543,61314, +61315,61316,61317,61318,61319,61320,61321,61322,61323,61324,61325,61326,61327, +61328,61329,61330,61331,61332,61333,61334,61335,61336,61337,61338,61339,61340, +61341,61342,61343,61344,61504,61505,61506,61507,61508,30544,61509,61510,12877, +61511,61512,61513,61514,61515,61516,61517,61518,61519,61520,61521,61522,61523, +61524,61525,61526,61527,61528,61529,61530,61531,61532,61533,61534,61535,61536, +61537,61538,61539,30545,61540,61541,61542,61543,61544,61545,61546,61547,61548, +61549,61550,61551,61552,61553,61554,61555,61556,61557,61558,61559,61560,61561, +61562,61563,61564,61565,61566,61568,61569,61570,61571,61572,61573,61574,61575, +61576,61577,30547,30546,61578,61579,61580,61581,61582,61583,61584,61585,61586, +61587,61588,61589,61590,25147,61591,15394,61592,25148,25149,25150,25151,25152, +25153,14137,21115,15652,19022,12581,19271,61593,25154,13948,18500,25155,61594, +61595,15688,61596,12669,25156,61597,13942,25157,17497,61598,61599,25158,20314, +14685,25159,16417,61600,25160,12918,61760,25161,61761,16755,25162,25163,17016, +25164,25165,25166,19031,22584,22885,20323,61762,61763,61764,61765,61766,61767, +61768,61769,61770,61771,61772,28709,61773,61774,23600,61775,61776,61777,61778, +61779,61780,61781,61782,61783,61784,61785,61786,61787,61788,61789,61790,61791, +61792,61793,61794,61795,61796,61797,61798,61799,61800,61801,61802,61803,61804, +61805,61806,61807,61808,61809,61810,61811,61812,61813,61814,61815,61816,61817, +61818,61819,61820,61821,61822,61824,61825,61826,61827,61828,61829,61830,61831, +61832,61833,61834,61835,61836,61837,61838,61839,61840,61841,61842,61843,61844, +61845,61846,61847,61848,61849,61850,61851,61852,61853,61854,61855,61856,62016, +62017,62018,62019,62020,62021,62022,62023,62024,62025,62026,62027,62028,62029, +62030,62031,62032,62033,62034,62035,62036,62037,62038,62039,62040,62041,62042, +62043,62044,62045,62046,62047,62048,62049,62050,62051,62052,62053,62054,62055, +62056,62057,62058,62059,62060,62061,62062,62063,62064,62065,62066,62067,62068, +62069,62070,62071,62072,62073,62074,62075,62076,62077,62078,62080,62081,62082, +62083,62084,62085,62086,62087,62088,62089,62090,62091,62092,62093,62094,62095, +62096,62097,62098,62099,62100,62101,62102,62103,62104,62105,62106,62107,62108, +62109,62110,62111,62112,62272,62273,62274,62275,62276,62277,62278,62279,62280, +62281,62282,62283,62284,62285,62286,62287,62288,62289,17005,21542,19796,20785, +13147,18301,62290,12853,16959,26208,19003,26209,26210,15956,26211,22308,19797, +26213,15453,26212,26214,26215,17006,62291,15678,26216,16998,14887,26217,62292, +26218,13138,20841,62293,62294,16165,26219,18031,26220,26221,62295,62296,26222, +17965,26223,62297,18727,26224,26225,26226,25913,26227,26228,16994,26229,26230, +22120,26231,62298,26232,14663,62299,62300,62301,62302,62303,62304,62305,30523, +30522,62306,62307,62308,62309,30526,30524,14881,62310,30527,62311,30528,62312, +62313,62314,30530,30529,30532,62315,62316,30531,62317,62318,62319,62320,62321, +30533,30534,62322,62323,62324,62325,30535,62326,19304,62327,62328,62329,62330, +14431,62331,62332,62333,62334,62336,62337,30548,62338,30549,62339,62340,62341, +62342,30550,62343,62344,62345,62346,30552,62347,30554,62348,30551,62349,62350, +62351,62352,62353,62354,62355,62356,62357,30555,62358,30553,62359,62360,62361, +62362,62363,62364,62365,22359,62366,62367,62368,62528,30556,62529,62530,62531, +62532,62533,62534,30557,62535,62536,62537,30558,62538,62539,62540,62541,62542, +62543,62544,62545,62546,62547,62548,30559,62549,62550,62551,30560,62552,62553, +62554,62555,62556,62557,62558,62559,62560,62561,62562,23371,62563,62564,22570, +62565,62566,62567,62568,62569,62570,62571,62572,25975,14701,62573,62574,62575, +62576,16253,15210,30537,17991,30536,62577,30538,30540,30539,62578,62579,62580, +30541,62581,20026,62582,30542,62583,62584,17447,62585,62586,62587,62588,62589, +62590,62592,62593,62594,62595,62596,62597,62598,62599,62600,62601,62602,62603, +62604,62605,62606,62607,62608,62609,62610,62611,62612,62613,62614,62615,62616, +62617,62618,62619,62620,62621,62622,62623,62624,62784,62785,62786,62787,62788, +62789,62790,62791,62792,62793,62794,62795,62796,62797,62798,62799,62800,62801, +62802,62803,62804,62805,62806,62807,62808,62809,62810,62811,62812,62813,62814, +62815,62816,62817,62818,62819,62820,62821,62822,62823,62824,62825,62826,62827, +62828,62829,62830,62831,62832,62833,62834,62835,62836,62837,62838,62839,62840, +62841,62842,62843,62844,62845,62846,62848,62849,62850,62851,62852,62853,62854, +62855,62856,62857,62858,62859,62860,62861,62862,62863,62864,62865,62866,62867, +62868,62869,62870,62871,62872,62873,62874,62875,62876,62877,62878,62879,62880, +63040,63041,63042,63043,63044,63045,63046,63047,63048,63049,63050,63051,63052, +63053,63054,63055,63056,63057,63058,63059,63060,63061,63062,63063,63064,63065, +63066,63067,63068,63069,63070,63071,63072,63073,63074,63075,63076,63077,63078, +63079,63080,63081,63082,63083,63084,63085,63086,63087,63088,63089,63090,63091, +63092,63093,63094,63095,63096,63097,63098,63099,63100,63101,63102,63104,63105, +63106,63107,63108,63109,63110,63111,63112,63113,63114,63115,63116,63117,63118, +63119,63120,63121,63122,63123,63124,63125,63126,63127,63128,63129,63130,63131, +63132,63133,63134,63135,63136,63296,63297,63298,63299,63300,63301,63302,63303, +63304,63305,63306,63307,63308,63309,63310,63311,63312,63313,63314,63315,63316, +63317,63318,63319,63320,63321,63322,63323,63324,63325,63326,63327,63328,63329, +63330,63331,63332,63333,63334,63335,63336,63337,63338,63339,63340,63341,63342, +63343,63344,63345,63346,63347,63348,63349,63350,63351,63352,63353,63354,63355, +63356,63357,63358,63360,21347,63361,63362,30287,63363,16947,30288,63364,63365, +30289,30290,30291,30292,63366,63367,30294,63368,12587,30295,63369,30296,30297, +30298,63370,30299,30300,63371,63372,63373,63374,30301,30302,20298,63375,30303, +30304,30305,30306,30307,30308,16496,30309,30310,30311,30312,30313,63376,30314, +63377,30315,30316,63378,30317,30318,30319,30320,30321,30322,30323,30324,15912, +63379,30325,30326,30327,30328,63380,63381,63382,63383,63384,18554,30329,30330, +30331,30332,63385,63386,30333,30334,30497,30498,30499,30500,30501,63387,63388, +30502,30503,30504,12654,30505,30506,30507,63389,63390,30508,30509,16731,30510, +63391,63392,30511,63552,63553,63554,63555,63556,63557,63558,63559,63560,63561, +63562,63563,63564,63565,63566,63567,63568,63569,63570,63571,63572,63573,63574, +63575,63576,63577,63578,63579,63580,63581,63582,63583,63584,63585,63586,63587, +63588,63589,63590,63591,63592,63593,63594,63595,63596,63597,63598,63599,63600, +63601,63602,63603,63604,63605,63606,63607,63608,63609,63610,63611,63612,63613, +63614,63616,63617,63618,63619,63620,63621,63622,63623,63624,63625,63626,63627, +63628,63629,63630,63631,63632,63633,63634,63635,63636,63637,63638,63639,63640, +63641,63642,63643,63644,63645,63646,63647,63648,63808,63809,63810,63811,63812, +63813,63814,63815,63816,63817,63818,63819,63820,63821,63822,63823,63824,63825, +63826,63827,63828,63829,63830,63831,63832,63833,63834,63835,63836,63837,63838, +63839,63840,63841,63842,63843,63844,63845,63846,63847,63848,63849,63850,63851, +63852,63853,63854,63855,63856,63857,63858,63859,63860,63861,63862,63863,63864, +63865,63866,63867,63868,63869,63870,63872,63873,63874,63875,63876,63877,63878, +63879,63880,63881,63882,63883,63884,63885,63886,63887,63888,63889,63890,63891, +63892,63893,63894,63895,63896,63897,63898,63899,63900,63901,63902,63903,63904, +64064,64065,64066,64067,64068,64069,64070,64071,64072,64073,64074,64075,64076, +64077,64078,64079,64080,64081,64082,64083,64084,64085,64086,64087,64088,64089, +64090,64091,64092,64093,64094,64095,64096,64097,64098,64099,64100,64101,64102, +64103,64104,64105,64106,64107,64108,64109,64110,64111,64112,64113,64114,64115, +64116,64117,64118,64119,64120,64121,64122,64123,64124,64125,64126,64128,64129, +64130,64131,64132,64133,64134,64135,64136,64137,64138,64139,64140,64141,64142, +64143,64144,64145,64146,64147,64148,64149,64150,64151,64152,64153,64154,64155, +64156,64157,64158,64159,64160,64320,64321,64322,64323,64324,64325,64326,64327, +64328,64329,64330,64331,64332,64333,64334,64335,64336,64337,64338,64339,64340, +64341,64342,64343,64344,64345,64346,64347,17521,28719,15398,28720,17273,64348, +17720,20795,64349,28721,28722,28723,28724,28725,20796,64350,20844,64351,28727, +28726,21543,64352,19794,28728,28730,28729,28731,28732,64353,64354,14443,28733, +14952,64355,28734,28735,15977,28736,13932,28737,28738,28739,28740,18485,28741, +28742,64356,28743,17780,64357,28744,64358,64359,64360,28745,64361,28746,30525, +64362,28747,28748,28749,64363,28750,64364,64365,64366,64367,28751,14935,64368, +28752,28753,28754,28755,28756,28757,28758,28760,64369,64370,21285,28759,64371, +28761,64372,64373,64374,64375,64376,64377,64378,64379,64380,64381,30010,16953, +64382,64384,30564,64385,64386,64387,64388,30565,30566,64389,64390,30567,64391, +64392,64393,64394,64395,64396,30568,16948,64397,64398,64399,64400,64401,64402, +64403,64404,64405,30570,64406,30571,64407,64408,64409,64410,64411,64412,17011, +64413,64414,64415,64416,64576,64577,64578,64579,64580,64581,64582,64583,64584, +29808,64585,64586,64587,29807,64588,64589,17001,64590,30561,30562,64591,64592, +64593,64594,64595,15174,64596,64597,64598,64599,22884,64600,64601,64602,19058, +16488,28708,64603,14938,64604,64605,18221,64606,64607,64608,17452,64609,64610, +30572,30573,30574,64611,30576,30575,64612,30577,64613,64614,30580,64615,30579, +64616,30578,30581,64617,64618,64619,64620,30582,64621,64622,64623,64624,64625, +64626,64627,64628,64629,28009,64630,28010,28011,64631,30268,64632,64633,64634, +64635,64636,64637,64638,64640,64641,64642,64643,64644,30269,64645,30270,13862, +64646,22590,64647,64648,14660,64649,64650,64651,22587,64652,23601,64653,64654, +64655,64656,64657,64658,19059,64659,30583,64660,64661,64662,64663,64664,64665, +64666,64667,64668,30584,64669,64670,30585,64671,64672,64832,64833,64834,64835, +64836,30587,64837,30586,64838,12615,64839,30588,30589,64840,64841,64842,64843, +64844,30590,64845,64846,64847,64848,64849,64850,64851,64852,64853,64854,64855, +18027,27700,64856,64857,64858,64859,64860,64861,64862,64863,64864,64865,64866, +64867,64868,64869,64870,64871,64872,64873,64874,64875,64876,64877,64878,64879, +64880,64881,64882,64883,64884,64885,64886,64887,64888,64889,64890,64891,64892, +64893,64894,64896,64897,64898,64899,64900,64901,13149,30259,64902,64903,30260, +16740,30261,30262,30263,30264,30265,30266,18467,30267,64904,64905,64906,64907, +64908,64909,64910,64911,64912,64913,64914,64915,16762,14632,28008,64916,64917, +64918,14698,22879,64919,64920,64921,64922,64923,64924,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64925,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64926,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64927,N,N,N,N,N,N,N,N,N,64928, +65088,65089,65090,65091,N,65092,N,65093,65094,N,N,N,65095,N,N,N,N,N,N,65096, +65097,65098,N,65099,65100,N,N,65101,65102,65103,43349,42738,N,42740,42741, +42720,42721,42736,42737,42722,42723,42734,42735,42726,42727,42724,42725,42728, +42729,42730,42731,N,N,N,N,43368,43369,43370,43371,43372,43373,43374,43375, +43376,43377,N,43378,43379,43380,43381,N,43382,43383,43384,43385,43386,43387, +43388,43389,43390,43392,43393,43394,43395,43396,N,43397,43398,43399,43400, +8993,8994,8995,8551,8997,8998,8999,9000,9001,9002,9003,9004,9005,9006,9007, +9008,9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,9020,9021,9022, +9023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037, +9038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052, +9053,9054,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064,9065,9066,9067, +9068,9069,9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082, +9083,9084,9085,8491,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8553,8554,43350,9086,43351,8996, +}; + +static const struct unim_index gbcommon_encmap[256] = { +{__gbcommon_encmap+0,164,252},{__gbcommon_encmap+89,1,220},{__gbcommon_encmap+ +309,81,217},{__gbcommon_encmap+446,145,201},{__gbcommon_encmap+503,1,81},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gbcommon_encmap+584, +16,59},{__gbcommon_encmap+628,3,153},{__gbcommon_encmap+779,8,191},{ +__gbcommon_encmap+963,18,18},{__gbcommon_encmap+964,96,155},{__gbcommon_encmap ++1024,0,229},{__gbcommon_encmap+1254,5,66},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gbcommon_encmap+1316,0,254},{ +__gbcommon_encmap+1571,5,41},{__gbcommon_encmap+1608,32,163},{ +__gbcommon_encmap+1740,142,213},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{__gbcommon_encmap+1812,0,255},{__gbcommon_encmap+2068,0,255},{ +__gbcommon_encmap+2324,0,255},{__gbcommon_encmap+2580,0,255},{ +__gbcommon_encmap+2836,0,255},{__gbcommon_encmap+3092,0,255},{ +__gbcommon_encmap+3348,0,255},{__gbcommon_encmap+3604,0,255},{ +__gbcommon_encmap+3860,0,255},{__gbcommon_encmap+4116,0,255},{ +__gbcommon_encmap+4372,0,255},{__gbcommon_encmap+4628,0,255},{ +__gbcommon_encmap+4884,0,255},{__gbcommon_encmap+5140,0,255},{ +__gbcommon_encmap+5396,0,255},{__gbcommon_encmap+5652,0,255},{ +__gbcommon_encmap+5908,0,255},{__gbcommon_encmap+6164,0,255},{ +__gbcommon_encmap+6420,0,255},{__gbcommon_encmap+6676,0,255},{ +__gbcommon_encmap+6932,0,255},{__gbcommon_encmap+7188,0,255},{ +__gbcommon_encmap+7444,0,255},{__gbcommon_encmap+7700,0,255},{ +__gbcommon_encmap+7956,0,255},{__gbcommon_encmap+8212,0,255},{ +__gbcommon_encmap+8468,0,255},{__gbcommon_encmap+8724,0,255},{ +__gbcommon_encmap+8980,0,255},{__gbcommon_encmap+9236,0,255},{ +__gbcommon_encmap+9492,0,255},{__gbcommon_encmap+9748,0,255},{ +__gbcommon_encmap+10004,0,255},{__gbcommon_encmap+10260,0,255},{ +__gbcommon_encmap+10516,0,255},{__gbcommon_encmap+10772,0,255},{ +__gbcommon_encmap+11028,0,255},{__gbcommon_encmap+11284,0,255},{ +__gbcommon_encmap+11540,0,255},{__gbcommon_encmap+11796,0,255},{ +__gbcommon_encmap+12052,0,255},{__gbcommon_encmap+12308,0,255},{ +__gbcommon_encmap+12564,0,255},{__gbcommon_encmap+12820,0,255},{ +__gbcommon_encmap+13076,0,255},{__gbcommon_encmap+13332,0,255},{ +__gbcommon_encmap+13588,0,255},{__gbcommon_encmap+13844,0,255},{ +__gbcommon_encmap+14100,0,255},{__gbcommon_encmap+14356,0,255},{ +__gbcommon_encmap+14612,0,255},{__gbcommon_encmap+14868,0,255},{ +__gbcommon_encmap+15124,0,255},{__gbcommon_encmap+15380,0,255},{ +__gbcommon_encmap+15636,0,255},{__gbcommon_encmap+15892,0,255},{ +__gbcommon_encmap+16148,0,255},{__gbcommon_encmap+16404,0,255},{ +__gbcommon_encmap+16660,0,255},{__gbcommon_encmap+16916,0,255},{ +__gbcommon_encmap+17172,0,255},{__gbcommon_encmap+17428,0,255},{ +__gbcommon_encmap+17684,0,255},{__gbcommon_encmap+17940,0,255},{ +__gbcommon_encmap+18196,0,255},{__gbcommon_encmap+18452,0,255},{ +__gbcommon_encmap+18708,0,255},{__gbcommon_encmap+18964,0,255},{ +__gbcommon_encmap+19220,0,255},{__gbcommon_encmap+19476,0,255},{ +__gbcommon_encmap+19732,0,255},{__gbcommon_encmap+19988,0,255},{ +__gbcommon_encmap+20244,0,255},{__gbcommon_encmap+20500,0,255},{ +__gbcommon_encmap+20756,0,255},{__gbcommon_encmap+21012,0,255},{ +__gbcommon_encmap+21268,0,255},{__gbcommon_encmap+21524,0,255},{ +__gbcommon_encmap+21780,0,255},{__gbcommon_encmap+22036,0,255},{ +__gbcommon_encmap+22292,0,255},{__gbcommon_encmap+22548,0,165},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{__gbcommon_encmap+22714,44,241},{__gbcommon_encmap+22912,12,41},{0,0,0},{0, +0,0},{0,0,0},{__gbcommon_encmap+22942,48,107},{__gbcommon_encmap+23002,1,229}, +}; + +static const ucs2_t __gb18030ext_decmap[2729] = { +58566,58567,58568,58569,58570,58571,58572,58573,58574,58575,58576,58577,58578, +58579,58580,58581,58582,58583,58584,58585,58586,58587,58588,58589,58590,58591, +58592,58593,58594,58595,58596,58597,58598,58599,58600,58601,58602,58603,58604, +58605,58606,58607,58608,58609,58610,58611,58612,58613,58614,58615,58616,58617, +58618,58619,58620,58621,58622,58623,58624,58625,58626,58627,58628,U,58629, +58630,58631,58632,58633,58634,58635,58636,58637,58638,58639,58640,58641,58642, +58643,58644,58645,58646,58647,58648,58649,58650,58651,58652,58653,58654,58655, +58656,58657,58658,58659,58660,58661,58662,58663,58664,58665,58666,58667,58668, +58669,58670,58671,58672,58673,58674,58675,58676,58677,58678,58679,58680,58681, +58682,58683,58684,58685,58686,58687,58688,58689,58690,58691,58692,58693,58694, +58695,58696,58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707, +58708,58709,58710,58711,58712,58713,58714,58715,58716,58717,58718,58719,58720, +58721,58722,58723,58724,U,58725,58726,58727,58728,58729,58730,58731,58732, +58733,58734,58735,58736,58737,58738,58739,58740,58741,58742,58743,58744,58745, +58746,58747,58748,58749,58750,58751,58752,58753,58754,58755,58756,58757,U,U,U, +U,U,U,U,U,U,U,59238,59239,59240,59241,59242,59243,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,8364, +59245,U,U,U,U,U,U,U,U,U,U,59246,59247,U,U,U,U,U,U,U,U,U,U,U,U,59248,59249, +58758,58759,58760,58761,58762,58763,58764,58765,58766,58767,58768,58769,58770, +58771,58772,58773,58774,58775,58776,58777,58778,58779,58780,58781,58782,58783, +58784,58785,58786,58787,58788,58789,58790,58791,58792,58793,58794,58795,58796, +58797,58798,58799,58800,58801,58802,58803,58804,58805,58806,58807,58808,58809, +58810,58811,58812,58813,58814,58815,58816,58817,58818,58819,58820,U,58821, +58822,58823,58824,58825,58826,58827,58828,58829,58830,58831,58832,58833,58834, +58835,58836,58837,58838,58839,58840,58841,58842,58843,58844,58845,58846,58847, +58848,58849,58850,58851,58852,58853,58854,58855,58856,58857,58858,58859,58860, +58861,58862,58863,58864,58865,58866,58867,58868,58869,58870,58871,58872,58873, +58874,58875,58876,58877,58878,58879,58880,58881,58882,58883,58884,58885,58886, +58887,58888,58889,58890,58891,58892,58893,58894,58895,58896,58897,58898,58899, +58900,58901,58902,58903,58904,58905,58906,58907,58908,58909,58910,58911,58912, +58913,58914,58915,58916,U,58917,58918,58919,58920,58921,58922,58923,58924, +58925,58926,58927,58928,58929,58930,58931,58932,58933,58934,58935,58936,58937, +58938,58939,58940,58941,58942,58943,58944,58945,58946,58947,58948,58949,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,59250,59251,59252,59253,59254,59255,59256,59257,59258,59259,59260,58950, +58951,58952,58953,58954,58955,58956,58957,58958,58959,58960,58961,58962,58963, +58964,58965,58966,58967,58968,58969,58970,58971,58972,58973,58974,58975,58976, +58977,58978,58979,58980,58981,58982,58983,58984,58985,58986,58987,58988,58989, +58990,58991,58992,58993,58994,58995,58996,58997,58998,58999,59000,59001,59002, +59003,59004,59005,59006,59007,59008,59009,59010,59011,59012,U,59013,59014, +59015,59016,59017,59018,59019,59020,59021,59022,59023,59024,59025,59026,59027, +59028,59029,59030,59031,59032,59033,59034,59035,59036,59037,59038,59039,59040, +59041,59042,59043,59044,59045,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59261,59262,59263,59264,59265, +59266,59267,59268,59046,59047,59048,59049,59050,59051,59052,59053,59054,59055, +59056,59057,59058,59059,59060,59061,59062,59063,59064,59065,59066,59067,59068, +59069,59070,59071,59072,59073,59074,59075,59076,59077,59078,59079,59080,59081, +59082,59083,59084,59085,59086,59087,59088,59089,59090,59091,59092,59093,59094, +59095,59096,59097,59098,59099,59100,59101,59102,59103,59104,59105,59106,59107, +59108,U,59109,59110,59111,59112,59113,59114,59115,59116,59117,59118,59119, +59120,59121,59122,59123,59124,59125,59126,59127,59128,59129,59130,59131,59132, +59133,59134,59135,59136,59137,59138,59139,59140,59141,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,59269,59270,59271,59272,59273,59274,59275,59276,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59277,59278,59279,59280,59281,59282, +59283,U,U,U,U,U,U,U,U,U,U,U,U,59284,59285,U,U,U,U,U,59286,U,U,59287,59288, +59289,59290,59291,59292,59293,59294,59295,59142,59143,59144,59145,59146,59147, +59148,59149,59150,59151,59152,59153,59154,59155,59156,59157,59158,59159,59160, +59161,59162,59163,59164,59165,59166,59167,59168,59169,59170,59171,59172,59173, +59174,59175,59176,59177,59178,59179,59180,59181,59182,59183,59184,59185,59186, +59187,59188,59189,59190,59191,59192,59193,59194,59195,59196,59197,59198,59199, +59200,59201,59202,59203,59204,U,59205,59206,59207,59208,59209,59210,59211, +59212,59213,59214,59215,59216,59217,59218,59219,59220,59221,59222,59223,59224, +59225,59226,59227,59228,59229,59230,59231,59232,59233,59234,59235,59236,59237, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59296,59297, +59298,59299,59300,59301,59302,59303,59304,59305,59306,59307,59308,59309,59310, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59311,59312, +59313,59314,59315,59316,59317,59318,59319,59320,59321,59322,59323,59324,59325, +59326,59327,59328,59329,59330,59331,59332,59333,59334,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59335,U,U,505,U,59337,59338,59339,59340,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59341,59342, +59343,59344,59345,59346,59347,59348,59349,59350,59351,59352,59353,59354,59355, +59356,59357,59358,59359,59360,59361,59362,U,U,59363,U,59364,59365,59366,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +12350,12272,12273,12274,12275,12276,12277,12278,12279,12280,12281,12282,12283, +U,59380,59381,59382,59383,59384,59385,59386,59387,59388,59389,59390,59391, +59392,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,59393,59394,59395,59396,59397,59398,59399,59400,59401,59402,59403,59404, +59405,59406,59407,57344,57345,57346,57347,57348,57349,57350,57351,57352,57353, +57354,57355,57356,57357,57358,57359,57360,57361,57362,57363,57364,57365,57366, +57367,57368,57369,57370,57371,57372,57373,57374,57375,57376,57377,57378,57379, +57380,57381,57382,57383,57384,57385,57386,57387,57388,57389,57390,57391,57392, +57393,57394,57395,57396,57397,57398,57399,57400,57401,57402,57403,57404,57405, +57406,57407,57408,57409,57410,57411,57412,57413,57414,57415,57416,57417,57418, +57419,57420,57421,57422,57423,57424,57425,57426,57427,57428,57429,57430,57431, +57432,57433,57434,57435,57436,57437,57438,57439,57440,57441,57442,57443,57444, +57445,57446,57447,57448,57449,57450,57451,57452,57453,57454,57455,57456,57457, +57458,57459,57460,57461,57462,57463,57464,57465,57466,57467,57468,57469,57470, +57471,57472,57473,57474,57475,57476,57477,57478,57479,57480,57481,57482,57483, +57484,57485,57486,57487,57488,57489,57490,57491,57492,57493,57494,57495,57496, +57497,57498,57499,57500,57501,57502,57503,57504,57505,57506,57507,57508,57509, +57510,57511,57512,57513,57514,57515,57516,57517,57518,57519,57520,57521,57522, +57523,57524,57525,57526,57527,57528,57529,57530,57531,57532,57533,57534,57535, +57536,57537,57538,57539,57540,57541,57542,57543,57544,57545,57546,57547,57548, +57549,57550,57551,57552,57553,57554,57555,57556,57557,57558,57559,57560,57561, +57562,57563,57564,57565,57566,57567,57568,57569,57570,57571,57572,57573,57574, +57575,57576,57577,57578,57579,57580,57581,57582,57583,57584,57585,57586,57587, +57588,57589,57590,57591,57592,57593,57594,57595,57596,57597,57598,57599,57600, +57601,57602,57603,57604,57605,57606,57607,57608,57609,57610,57611,57612,57613, +57614,57615,57616,57617,57618,57619,57620,57621,57622,57623,57624,57625,57626, +57627,57628,57629,57630,57631,57632,57633,57634,57635,57636,57637,57638,57639, +57640,57641,57642,57643,57644,57645,57646,57647,57648,57649,57650,57651,57652, +57653,57654,57655,57656,57657,57658,57659,57660,57661,57662,57663,57664,57665, +57666,57667,57668,57669,57670,57671,57672,57673,57674,57675,57676,57677,57678, +57679,57680,57681,57682,57683,57684,57685,57686,57687,57688,57689,57690,57691, +57692,57693,57694,57695,57696,57697,57698,57699,57700,57701,57702,57703,57704, +57705,57706,57707,57708,57709,57710,57711,57712,57713,57714,57715,57716,57717, +57718,57719,57720,57721,57722,57723,57724,57725,57726,57727,57728,57729,57730, +57731,57732,57733,57734,57735,57736,57737,57738,57739,57740,57741,57742,57743, +57744,57745,57746,57747,57748,57749,57750,57751,57752,57753,57754,57755,57756, +57757,57758,57759,57760,57761,57762,57763,57764,57765,57766,57767,57768,57769, +57770,57771,57772,57773,57774,57775,57776,57777,57778,57779,57780,57781,57782, +57783,57784,57785,57786,57787,57788,57789,57790,57791,57792,57793,57794,57795, +57796,57797,57798,57799,57800,57801,57802,57803,57804,57805,57806,57807,57808, +57809,57810,57811,57812,57813,57814,57815,57816,57817,57818,57819,57820,57821, +57822,57823,57824,57825,57826,57827,57828,57829,57830,57831,57832,57833,57834, +57835,57836,57837,57838,57839,57840,57841,57842,57843,57844,57845,57846,57847, +57848,57849,57850,57851,57852,57853,57854,57855,57856,57857,57858,57859,57860, +57861,57862,57863,57864,57865,57866,57867,57868,57869,57870,57871,57872,57873, +57874,57875,57876,57877,57878,57879,57880,57881,57882,57883,57884,57885,57886, +57887,57888,57889,57890,57891,57892,57893,57894,57895,57896,57897,57898,57899, +57900,57901,57902,57903,57904,57905,57906,57907,59408,59409,59410,59411,59412, +57908,57909,57910,57911,57912,57913,57914,57915,57916,57917,57918,57919,57920, +57921,57922,57923,57924,57925,57926,57927,57928,57929,57930,57931,57932,57933, +57934,57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946, +57947,57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959, +57960,57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972, +57973,57974,57975,57976,57977,57978,57979,57980,57981,57982,57983,57984,57985, +57986,57987,57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998, +57999,58000,58001,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011, +58012,58013,58014,58015,58016,58017,58018,58019,58020,58021,58022,58023,58024, +58025,58026,58027,58028,58029,58030,58031,58032,58033,58034,58035,58036,58037, +58038,58039,58040,58041,58042,58043,58044,58045,58046,58047,58048,58049,58050, +58051,58052,58053,58054,58055,58056,58057,58058,58059,58060,58061,58062,58063, +58064,58065,58066,58067,58068,58069,58070,58071,58072,58073,58074,58075,58076, +58077,58078,58079,58080,58081,58082,58083,58084,58085,58086,58087,58088,58089, +58090,58091,58092,58093,58094,58095,58096,58097,58098,58099,58100,58101,58102, +58103,58104,58105,58106,58107,58108,58109,58110,58111,58112,58113,58114,58115, +58116,58117,58118,58119,58120,58121,58122,58123,58124,58125,58126,58127,58128, +58129,58130,58131,58132,58133,58134,58135,58136,58137,58138,58139,58140,58141, +58142,58143,58144,58145,58146,58147,58148,58149,58150,58151,58152,58153,58154, +58155,58156,58157,58158,58159,58160,58161,58162,58163,58164,58165,58166,58167, +58168,58169,58170,58171,58172,58173,58174,58175,58176,58177,58178,58179,58180, +58181,58182,58183,58184,58185,58186,58187,58188,58189,58190,58191,58192,58193, +58194,58195,58196,58197,58198,58199,58200,58201,58202,58203,58204,58205,58206, +58207,58208,58209,58210,58211,58212,58213,58214,58215,58216,58217,58218,58219, +58220,58221,58222,58223,58224,58225,58226,58227,58228,58229,58230,58231,58232, +58233,58234,58235,58236,58237,58238,58239,58240,58241,58242,58243,58244,58245, +58246,58247,58248,58249,58250,58251,58252,58253,58254,58255,58256,58257,58258, +58259,58260,58261,58262,58263,58264,58265,58266,58267,58268,58269,58270,58271, +58272,58273,58274,58275,58276,58277,58278,58279,58280,58281,58282,58283,58284, +58285,58286,58287,58288,58289,58290,58291,58292,58293,58294,58295,58296,58297, +58298,58299,58300,58301,58302,58303,58304,58305,58306,58307,58308,58309,58310, +58311,58312,58313,58314,58315,58316,58317,58318,58319,58320,58321,58322,58323, +58324,58325,58326,58327,58328,58329,58330,58331,58332,58333,58334,58335,58336, +58337,58338,58339,58340,58341,58342,58343,58344,58345,58346,58347,58348,58349, +58350,58351,58352,58353,58354,58355,58356,58357,58358,58359,58360,58361,58362, +58363,58364,58365,58366,58367,58368,58369,58370,58371,58372,58373,58374,58375, +58376,58377,58378,58379,58380,58381,58382,58383,58384,58385,58386,58387,58388, +58389,58390,58391,58392,58393,58394,58395,58396,58397,58398,58399,58400,58401, +58402,58403,58404,58405,58406,58407,58408,58409,58410,58411,58412,58413,58414, +58415,58416,58417,58418,58419,58420,58421,58422,58423,58424,58425,58426,58427, +58428,58429,58430,58431,58432,58433,58434,58435,58436,58437,58438,58439,58440, +58441,58442,58443,58444,58445,58446,58447,58448,58449,58450,58451,58452,58453, +58454,58455,58456,58457,58458,58459,58460,58461,58462,58463,58464,58465,58466, +58467,58468,58469,58470,58471,11905,59414,59415,59416,11908,13427,13383,11912, +11915,59422,13726,13850,13838,11916,11927,14702,14616,59430,14799,14815,14963, +14800,59435,59436,15182,15470,15584,11943,59441,59442,11946,16470,16735,11950, +17207,11955,11958,11959,59451,17329,17324,11963,17373,17622,18017,17996,59459, +U,18211,18217,18300,18317,11978,18759,18810,18813,18818,18819,18821,18822, +18847,18843,18871,18870,59476,59477,19619,19615,19616,19617,19575,19618,19731, +19732,19733,19734,19735,19736,19737,19886,59492,58472,58473,58474,58475,58476, +58477,58478,58479,58480,58481,58482,58483,58484,58485,58486,58487,58488,58489, +58490,58491,58492,58493,58494,58495,58496,58497,58498,58499,58500,58501,58502, +58503,58504,58505,58506,58507,58508,58509,58510,58511,58512,58513,58514,58515, +58516,58517,58518,58519,58520,58521,58522,58523,58524,58525,58526,58527,58528, +58529,58530,58531,58532,58533,58534,58535,58536,58537,58538,58539,58540,58541, +58542,58543,58544,58545,58546,58547,58548,58549,58550,58551,58552,58553,58554, +58555,58556,58557,58558,58559,58560,58561,58562,58563,58564,58565, +}; + +static const struct dbcs_index gb18030ext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_decmap+0,64, +160},{__gb18030ext_decmap+97,64,254},{__gb18030ext_decmap+288,64,160},{ +__gb18030ext_decmap+385,64,254},{__gb18030ext_decmap+576,64,254},{ +__gb18030ext_decmap+767,64,254},{__gb18030ext_decmap+958,64,254},{ +__gb18030ext_decmap+1149,150,254},{__gb18030ext_decmap+1254,88,254},{ +__gb18030ext_decmap+1421,161,254},{__gb18030ext_decmap+1515,161,254},{ +__gb18030ext_decmap+1609,161,254},{__gb18030ext_decmap+1703,161,254},{ +__gb18030ext_decmap+1797,161,254},{__gb18030ext_decmap+1891,161,254},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__gb18030ext_decmap+1985,250,254},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_decmap ++1990,161,254},{__gb18030ext_decmap+2084,161,254},{__gb18030ext_decmap+2178, +161,254},{__gb18030ext_decmap+2272,161,254},{__gb18030ext_decmap+2366,161,254 +},{__gb18030ext_decmap+2460,161,254},{__gb18030ext_decmap+2554,80,254},{0,0,0 +}, +}; + +static const DBCHAR __gb18030ext_encmap[3227] = { +43199,41699,65104,N,N,65108,N,N,N,65111,N,N,65112,65117,N,N,N,N,N,N,N,N,N,N, +65118,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65131,N,N,65134,N,N,N,65137,N,N,N,N,65139, +N,N,65140,65141,N,N,N,65145,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65156,43402,43403, +43404,43405,43406,43407,43408,43409,43410,43411,43412,43413,43401,65110,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,65109,65114,65116,N,N,N,N,N,N,N,N,N,N,N,65115,65120,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65119,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65122,65125,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65123, +65124,65128,65129,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,65130,65135,65136,65138,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65144,N,N,N,N,65143,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65146,65147,65149, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65148,65152,N,N,N,N,N,65153,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +65154,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65155,65157,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65158, +N,N,65159,N,N,N,N,65160,65161,N,65162,65163,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,65165,N,N,N,65164,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65167, +65166,65174,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,65171,65172,65173,65175,65170,65176,65177,65178,65179,65180,65181, +65182,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65183, +43681,43682,43683,43684,43685,43686,43687,43688,43689,43690,43691,43692,43693, +43694,43695,43696,43697,43698,43699,43700,43701,43702,43703,43704,43705,43706, +43707,43708,43709,43710,43711,43712,43713,43714,43715,43716,43717,43718,43719, +43720,43721,43722,43723,43724,43725,43726,43727,43728,43729,43730,43731,43732, +43733,43734,43735,43736,43737,43738,43739,43740,43741,43742,43743,43744,43745, +43746,43747,43748,43749,43750,43751,43752,43753,43754,43755,43756,43757,43758, +43759,43760,43761,43762,43763,43764,43765,43766,43767,43768,43769,43770,43771, +43772,43773,43774,43937,43938,43939,43940,43941,43942,43943,43944,43945,43946, +43947,43948,43949,43950,43951,43952,43953,43954,43955,43956,43957,43958,43959, +43960,43961,43962,43963,43964,43965,43966,43967,43968,43969,43970,43971,43972, +43973,43974,43975,43976,43977,43978,43979,43980,43981,43982,43983,43984,43985, +43986,43987,43988,43989,43990,43991,43992,43993,43994,43995,43996,43997,43998, +43999,44000,44001,44002,44003,44004,44005,44006,44007,44008,44009,44010,44011, +44012,44013,44014,44015,44016,44017,44018,44019,44020,44021,44022,44023,44024, +44025,44026,44027,44028,44029,44030,44193,44194,44195,44196,44197,44198,44199, +44200,44201,44202,44203,44204,44205,44206,44207,44208,44209,44210,44211,44212, +44213,44214,44215,44216,44217,44218,44219,44220,44221,44222,44223,44224,44225, +44226,44227,44228,44229,44230,44231,44232,44233,44234,44235,44236,44237,44238, +44239,44240,44241,44242,44243,44244,44245,44246,44247,44248,44249,44250,44251, +44252,44253,44254,44255,44256,44257,44258,44259,44260,44261,44262,44263,44264, +44265,44266,44267,44268,44269,44270,44271,44272,44273,44274,44275,44276,44277, +44278,44279,44280,44281,44282,44283,44284,44285,44286,44449,44450,44451,44452, +44453,44454,44455,44456,44457,44458,44459,44460,44461,44462,44463,44464,44465, +44466,44467,44468,44469,44470,44471,44472,44473,44474,44475,44476,44477,44478, +44479,44480,44481,44482,44483,44484,44485,44486,44487,44488,44489,44490,44491, +44492,44493,44494,44495,44496,44497,44498,44499,44500,44501,44502,44503,44504, +44505,44506,44507,44508,44509,44510,44511,44512,44513,44514,44515,44516,44517, +44518,44519,44520,44521,44522,44523,44524,44525,44526,44527,44528,44529,44530, +44531,44532,44533,44534,44535,44536,44537,44538,44539,44540,44541,44542,44705, +44706,44707,44708,44709,44710,44711,44712,44713,44714,44715,44716,44717,44718, +44719,44720,44721,44722,44723,44724,44725,44726,44727,44728,44729,44730,44731, +44732,44733,44734,44735,44736,44737,44738,44739,44740,44741,44742,44743,44744, +44745,44746,44747,44748,44749,44750,44751,44752,44753,44754,44755,44756,44757, +44758,44759,44760,44761,44762,44763,44764,44765,44766,44767,44768,44769,44770, +44771,44772,44773,44774,44775,44776,44777,44778,44779,44780,44781,44782,44783, +44784,44785,44786,44787,44788,44789,44790,44791,44792,44793,44794,44795,44796, +44797,44798,44961,44962,44963,44964,44965,44966,44967,44968,44969,44970,44971, +44972,44973,44974,44975,44976,44977,44978,44979,44980,44981,44982,44983,44984, +44985,44986,44987,44988,44989,44990,44991,44992,44993,44994,44995,44996,44997, +44998,44999,45000,45001,45002,45003,45004,45005,45006,45007,45008,45009,45010, +45011,45012,45013,45014,45015,45016,45017,45018,45019,45020,45021,45022,45023, +45024,45025,45026,45027,45028,45029,45030,45031,45032,45033,45034,45035,45036, +45037,45038,45039,45040,45041,45042,45043,45044,45045,45046,45047,45048,45049, +45050,45051,45052,45053,45054,63649,63650,63651,63652,63653,63654,63655,63656, +63657,63658,63659,63660,63661,63662,63663,63664,63665,63666,63667,63668,63669, +63670,63671,63672,63673,63674,63675,63676,63677,63678,63679,63680,63681,63682, +63683,63684,63685,63686,63687,63688,63689,63690,63691,63692,63693,63694,63695, +63696,63697,63698,63699,63700,63701,63702,63703,63704,63705,63706,63707,63708, +63709,63710,63711,63712,63713,63714,63715,63716,63717,63718,63719,63720,63721, +63722,63723,63724,63725,63726,63727,63728,63729,63730,63731,63732,63733,63734, +63735,63736,63737,63738,63739,63740,63741,63742,63905,63906,63907,63908,63909, +63910,63911,63912,63913,63914,63915,63916,63917,63918,63919,63920,63921,63922, +63923,63924,63925,63926,63927,63928,63929,63930,63931,63932,63933,63934,63935, +63936,63937,63938,63939,63940,63941,63942,63943,63944,63945,63946,63947,63948, +63949,63950,63951,63952,63953,63954,63955,63956,63957,63958,63959,63960,63961, +63962,63963,63964,63965,63966,63967,63968,63969,63970,63971,63972,63973,63974, +63975,63976,63977,63978,63979,63980,63981,63982,63983,63984,63985,63986,63987, +63988,63989,63990,63991,63992,63993,63994,63995,63996,63997,63998,64161,64162, +64163,64164,64165,64166,64167,64168,64169,64170,64171,64172,64173,64174,64175, +64176,64177,64178,64179,64180,64181,64182,64183,64184,64185,64186,64187,64188, +64189,64190,64191,64192,64193,64194,64195,64196,64197,64198,64199,64200,64201, +64202,64203,64204,64205,64206,64207,64208,64209,64210,64211,64212,64213,64214, +64215,64216,64217,64218,64219,64220,64221,64222,64223,64224,64225,64226,64227, +64228,64229,64230,64231,64232,64233,64234,64235,64236,64237,64238,64239,64240, +64241,64242,64243,64244,64245,64246,64247,64248,64249,64250,64251,64252,64253, +64254,64417,64418,64419,64420,64421,64422,64423,64424,64425,64426,64427,64428, +64429,64430,64431,64432,64433,64434,64435,64436,64437,64438,64439,64440,64441, +64442,64443,64444,64445,64446,64447,64448,64449,64450,64451,64452,64453,64454, +64455,64456,64457,64458,64459,64460,64461,64462,64463,64464,64465,64466,64467, +64468,64469,64470,64471,64472,64473,64474,64475,64476,64477,64478,64479,64480, +64481,64482,64483,64484,64485,64486,64487,64488,64489,64490,64491,64492,64493, +64494,64495,64496,64497,64498,64499,64500,64501,64502,64503,64504,64505,64506, +64507,64508,64509,64510,64673,64674,64675,64676,64677,64678,64679,64680,64681, +64682,64683,64684,64685,64686,64687,64688,64689,64690,64691,64692,64693,64694, +64695,64696,64697,64698,64699,64700,64701,64702,64703,64704,64705,64706,64707, +64708,64709,64710,64711,64712,64713,64714,64715,64716,64717,64718,64719,64720, +64721,64722,64723,64724,64725,64726,64727,64728,64729,64730,64731,64732,64733, +64734,64735,64736,64737,64738,64739,64740,64741,64742,64743,64744,64745,64746, +64747,64748,64749,64750,64751,64752,64753,64754,64755,64756,64757,64758,64759, +64760,64761,64762,64763,64764,64765,64766,64929,64930,64931,64932,64933,64934, +64935,64936,64937,64938,64939,64940,64941,64942,64943,64944,64945,64946,64947, +64948,64949,64950,64951,64952,64953,64954,64955,64956,64957,64958,64959,64960, +64961,64962,64963,64964,64965,64966,64967,64968,64969,64970,64971,64972,64973, +64974,64975,64976,64977,64978,64979,64980,64981,64982,64983,64984,64985,64986, +64987,64988,64989,64990,64991,64992,64993,64994,64995,64996,64997,64998,64999, +65000,65001,65002,65003,65004,65005,65006,65007,65008,65009,65010,65011,65012, +65013,65014,65015,65016,65017,65018,65019,65020,65021,65022,65185,65186,65187, +65188,65189,65190,65191,65192,65193,65194,65195,65196,65197,65198,65199,65200, +65201,65202,65203,65204,65205,65206,65207,65208,65209,65210,65211,65212,65213, +65214,65215,65216,65217,65218,65219,65220,65221,65222,65223,65224,65225,65226, +65227,65228,65229,65230,65231,65232,65233,65234,65235,65236,65237,65238,65239, +65240,65241,65242,65243,65244,65245,65246,65247,65248,65249,65250,65251,65252, +65253,65254,65255,65256,65257,65258,65259,65260,65261,65262,65263,65264,65265, +65266,65267,65268,65269,65270,65271,65272,65273,65274,65275,65276,65277,65278, +41280,41281,41282,41283,41284,41285,41286,41287,41288,41289,41290,41291,41292, +41293,41294,41295,41296,41297,41298,41299,41300,41301,41302,41303,41304,41305, +41306,41307,41308,41309,41310,41311,41312,41313,41314,41315,41316,41317,41318, +41319,41320,41321,41322,41323,41324,41325,41326,41327,41328,41329,41330,41331, +41332,41333,41334,41335,41336,41337,41338,41339,41340,41341,41342,41344,41345, +41346,41347,41348,41349,41350,41351,41352,41353,41354,41355,41356,41357,41358, +41359,41360,41361,41362,41363,41364,41365,41366,41367,41368,41369,41370,41371, +41372,41373,41374,41375,41376,41536,41537,41538,41539,41540,41541,41542,41543, +41544,41545,41546,41547,41548,41549,41550,41551,41552,41553,41554,41555,41556, +41557,41558,41559,41560,41561,41562,41563,41564,41565,41566,41567,41568,41569, +41570,41571,41572,41573,41574,41575,41576,41577,41578,41579,41580,41581,41582, +41583,41584,41585,41586,41587,41588,41589,41590,41591,41592,41593,41594,41595, +41596,41597,41598,41600,41601,41602,41603,41604,41605,41606,41607,41608,41609, +41610,41611,41612,41613,41614,41615,41616,41617,41618,41619,41620,41621,41622, +41623,41624,41625,41626,41627,41628,41629,41630,41631,41632,41792,41793,41794, +41795,41796,41797,41798,41799,41800,41801,41802,41803,41804,41805,41806,41807, +41808,41809,41810,41811,41812,41813,41814,41815,41816,41817,41818,41819,41820, +41821,41822,41823,41824,41825,41826,41827,41828,41829,41830,41831,41832,41833, +41834,41835,41836,41837,41838,41839,41840,41841,41842,41843,41844,41845,41846, +41847,41848,41849,41850,41851,41852,41853,41854,41856,41857,41858,41859,41860, +41861,41862,41863,41864,41865,41866,41867,41868,41869,41870,41871,41872,41873, +41874,41875,41876,41877,41878,41879,41880,41881,41882,41883,41884,41885,41886, +41887,41888,42048,42049,42050,42051,42052,42053,42054,42055,42056,42057,42058, +42059,42060,42061,42062,42063,42064,42065,42066,42067,42068,42069,42070,42071, +42072,42073,42074,42075,42076,42077,42078,42079,42080,42081,42082,42083,42084, +42085,42086,42087,42088,42089,42090,42091,42092,42093,42094,42095,42096,42097, +42098,42099,42100,42101,42102,42103,42104,42105,42106,42107,42108,42109,42110, +42112,42113,42114,42115,42116,42117,42118,42119,42120,42121,42122,42123,42124, +42125,42126,42127,42128,42129,42130,42131,42132,42133,42134,42135,42136,42137, +42138,42139,42140,42141,42142,42143,42144,42304,42305,42306,42307,42308,42309, +42310,42311,42312,42313,42314,42315,42316,42317,42318,42319,42320,42321,42322, +42323,42324,42325,42326,42327,42328,42329,42330,42331,42332,42333,42334,42335, +42336,42337,42338,42339,42340,42341,42342,42343,42344,42345,42346,42347,42348, +42349,42350,42351,42352,42353,42354,42355,42356,42357,42358,42359,42360,42361, +42362,42363,42364,42365,42366,42368,42369,42370,42371,42372,42373,42374,42375, +42376,42377,42378,42379,42380,42381,42382,42383,42384,42385,42386,42387,42388, +42389,42390,42391,42392,42393,42394,42395,42396,42397,42398,42399,42400,42560, +42561,42562,42563,42564,42565,42566,42567,42568,42569,42570,42571,42572,42573, +42574,42575,42576,42577,42578,42579,42580,42581,42582,42583,42584,42585,42586, +42587,42588,42589,42590,42591,42592,42593,42594,42595,42596,42597,42598,42599, +42600,42601,42602,42603,42604,42605,42606,42607,42608,42609,42610,42611,42612, +42613,42614,42615,42616,42617,42618,42619,42620,42621,42622,42624,42625,42626, +42627,42628,42629,42630,42631,42632,42633,42634,42635,42636,42637,42638,42639, +42640,42641,42642,42643,42644,42645,42646,42647,42648,42649,42650,42651,42652, +42653,42654,42655,42656,42816,42817,42818,42819,42820,42821,42822,42823,42824, +42825,42826,42827,42828,42829,42830,42831,42832,42833,42834,42835,42836,42837, +42838,42839,42840,42841,42842,42843,42844,42845,42846,42847,42848,42849,42850, +42851,42852,42853,42854,42855,42856,42857,42858,42859,42860,42861,42862,42863, +42864,42865,42866,42867,42868,42869,42870,42871,42872,42873,42874,42875,42876, +42877,42878,42880,42881,42882,42883,42884,42885,42886,42887,42888,42889,42890, +42891,42892,42893,42894,42895,42896,42897,42898,42899,42900,42901,42902,42903, +42904,42905,42906,42907,42908,42909,42910,42911,42912,41643,41644,41645,41646, +41647,41648,N,41700,41711,41712,41725,41726,42228,42229,42230,42231,42232, +42233,42234,42235,42236,42237,42238,42487,42488,42489,42490,42491,42492,42493, +42494,42681,42682,42683,42684,42685,42686,42687,42688,42713,42714,42715,42716, +42717,42718,42719,42732,42733,42739,42742,42743,42744,42745,42746,42747,42748, +42749,42750,42946,42947,42948,42949,42950,42951,42952,42953,42954,42955,42956, +42957,42958,42959,42960,42994,42995,42996,42997,42998,42999,43000,43001,43002, +43003,43004,43005,43006,43158,43159,43160,43161,43162,43163,43164,43165,43166, +43167,43168,43196,N,43201,43202,43203,43204,43242,43243,43244,43245,43246, +43247,43248,43249,43250,43251,43252,43253,43254,43255,43256,43257,43258,43259, +43260,43261,43262,43352,43355,43357,43358,43359,N,N,N,N,N,N,N,N,N,N,N,N,N, +43415,43416,43417,43418,43419,43420,43421,43422,43423,43424,43425,43426,43427, +43504,43505,43506,43507,43508,43509,43510,43511,43512,43513,43514,43515,43516, +43517,43518,55290,55291,55292,55293,55294,N,65105,65106,65107,N,N,N,N,N,65113, +N,N,N,N,N,N,N,65121,N,N,N,N,65126,65127,N,N,N,N,65132,65133,N,N,N,N,N,N,N,N, +65142,N,N,N,N,N,N,N,65150,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65168,65169,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,65184, +}; + +static const struct unim_index gb18030ext_encmap[256] = { +{0,0,0},{__gb18030ext_encmap+0,249,249},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_encmap+1,172,172 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_encmap+2,129,202},{ +__gb18030ext_encmap+76,240,251},{__gb18030ext_encmap+88,62,62},{0,0,0},{0,0,0 +},{0,0,0},{__gb18030ext_encmap+89,71,115},{__gb18030ext_encmap+134,158,158},{ +__gb18030ext_encmap+135,14,26},{0,0,0},{0,0,0},{__gb18030ext_encmap+148,24,223 +},{__gb18030ext_encmap+348,115,115},{__gb18030ext_encmap+349,78,78},{ +__gb18030ext_encmap+350,110,224},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_encmap+ +465,86,86},{__gb18030ext_encmap+466,95,95},{0,0,0},{__gb18030ext_encmap+467, +55,221},{__gb18030ext_encmap+634,214,214},{0,0,0},{__gb18030ext_encmap+635,76, +97},{__gb18030ext_encmap+657,35,141},{0,0,0},{__gb18030ext_encmap+764,71,183}, +{0,0,0},{0,0,0},{__gb18030ext_encmap+877,119,163},{__gb18030ext_encmap+922,19, +174},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{__gb18030ext_encmap+1078,0,255},{__gb18030ext_encmap+1334,0,255 +},{__gb18030ext_encmap+1590,0,255},{__gb18030ext_encmap+1846,0,255},{ +__gb18030ext_encmap+2102,0,255},{__gb18030ext_encmap+2358,0,255},{ +__gb18030ext_encmap+2614,0,255},{__gb18030ext_encmap+2870,0,255},{ +__gb18030ext_encmap+3126,0,100},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + + +static const struct _gb18030_to_unibmp_ranges { + Py_UNICODE first, last; + DBCHAR base; +} gb18030_to_unibmp_ranges[] = { +{128,163,0},{165,166,36},{169,175,38},{178,182,45},{184,214,50},{216,223,81},{ +226,231,89},{235,235,95},{238,241,96},{244,246,100},{248,248,103},{251,251,104 +},{253,256,105},{258,274,109},{276,282,126},{284,298,133},{300,323,148},{325, +327,172},{329,332,175},{334,362,179},{364,461,208},{463,463,306},{465,465,307 +},{467,467,308},{469,469,309},{471,471,310},{473,473,311},{475,475,312},{477, +504,313},{506,592,341},{594,608,428},{610,710,443},{712,712,544},{716,728,545 +},{730,912,558},{930,930,741},{938,944,742},{962,962,749},{970,1024,750},{1026 +,1039,805},{1104,1104,819},{1106,8207,820},{8209,8210,7922},{8215,8215,7924},{ +8218,8219,7925},{8222,8228,7927},{8231,8239,7934},{8241,8241,7943},{8244,8244, +7944},{8246,8250,7945},{8252,8363,7950},{8365,8450,8062},{8452,8452,8148},{ +8454,8456,8149},{8458,8469,8152},{8471,8480,8164},{8482,8543,8174},{8556,8559, +8236},{8570,8591,8240},{8596,8597,8262},{8602,8711,8264},{8713,8718,8374},{ +8720,8720,8380},{8722,8724,8381},{8726,8729,8384},{8731,8732,8388},{8737,8738, +8390},{8740,8740,8392},{8742,8742,8393},{8748,8749,8394},{8751,8755,8396},{ +8760,8764,8401},{8766,8775,8406},{8777,8779,8416},{8781,8785,8419},{8787,8799, +8424},{8802,8803,8437},{8808,8813,8439},{8816,8852,8445},{8854,8856,8482},{ +8858,8868,8485},{8870,8894,8496},{8896,8977,8521},{8979,9311,8603},{9322,9331, +8936},{9372,9471,8946},{9548,9551,9046},{9588,9600,9050},{9616,9618,9063},{ +9622,9631,9066},{9634,9649,9076},{9652,9659,9092},{9662,9669,9100},{9672,9674, +9108},{9676,9677,9111},{9680,9697,9113},{9702,9732,9131},{9735,9736,9162},{ +9738,9791,9164},{9793,9793,9218},{9795,11904,9219},{11906,11907,11329},{11909, +11911,11331},{11913,11914,11334},{11917,11926,11336},{11928,11942,11346},{ +11944,11945,11361},{11947,11949,11363},{11951,11954,11366},{11956,11957,11370 +},{11960,11962,11372},{11964,11977,11375},{11979,12271,11389},{12284,12287, +11682},{12292,12292,11686},{12312,12316,11687},{12319,12320,11692},{12330, +12349,11694},{12351,12352,11714},{12436,12442,11716},{12447,12448,11723},{ +12535,12539,11725},{12543,12548,11730},{12586,12831,11736},{12842,12848,11982 +},{12850,12962,11989},{12964,13197,12102},{13200,13211,12336},{13215,13216, +12348},{13218,13251,12350},{13253,13261,12384},{13263,13264,12393},{13267, +13268,12395},{13270,13382,12397},{13384,13426,12510},{13428,13725,12553},{ +13727,13837,12851},{13839,13849,12962},{13851,14615,12973},{14617,14701,13738 +},{14703,14798,13823},{14801,14814,13919},{14816,14962,13933},{14964,15181, +14080},{15183,15469,14298},{15471,15583,14585},{15585,16469,14698},{16471, +16734,15583},{16736,17206,15847},{17208,17323,16318},{17325,17328,16434},{ +17330,17372,16438},{17374,17621,16481},{17623,17995,16729},{17997,18016,17102 +},{18018,18210,17122},{18212,18216,17315},{18218,18299,17320},{18301,18316, +17402},{18318,18758,17418},{18760,18809,17859},{18811,18812,17909},{18814, +18817,17911},{18820,18820,17915},{18823,18842,17916},{18844,18846,17936},{ +18848,18869,17939},{18872,19574,17961},{19576,19614,18664},{19620,19730,18703 +},{19738,19885,18814},{19887,19967,18962},{40870,55295,19043},{59244,59244, +33469},{59336,59336,33470},{59367,59379,33471},{59413,59413,33484},{59417, +59421,33485},{59423,59429,33490},{59431,59434,33497},{59437,59440,33501},{ +59443,59450,33505},{59452,59458,33513},{59460,59475,33520},{59478,59491,33536 +},{59493,63787,33550},{63789,63864,37845},{63866,63892,37921},{63894,63974, +37948},{63976,63984,38029},{63986,64011,38038},{64016,64016,38064},{64018, +64018,38065},{64021,64023,38066},{64025,64030,38069},{64034,64034,38075},{ +64037,64038,38076},{64042,65071,38078},{65074,65074,39108},{65093,65096,39109 +},{65107,65107,39113},{65112,65112,39114},{65127,65127,39115},{65132,65280, +39116},{65375,65503,39265},{65510,65535,39394},{0,0,39420}}; diff --git a/pypy/translator/c/src/cjkcodecs/mappings_hk.h b/pypy/translator/c/src/cjkcodecs/mappings_hk.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/mappings_hk.h @@ -0,0 +1,2378 @@ +static const ucs2_t __big5hkscs_decmap[6219] = { +17392,19506,17923,17830,17784,29287,19831,17843,31921,19682,31941,15253,18230, +18244,19527,19520,17087,13847,29522,28299,28882,19543,41809,18255,17882,19589, +31852,19719,19108,18081,27427,29221,23124,6755,15878,16225,26189,22267,U, +32149,22813,35769,15860,38708,31727,23515,7518,23204,13861,40624,23249,23479, +23804,26478,34195,39237,29793,29853,12736,12737,12738,12739,12740,268,12741, +209,205,12742,12743,203,8168,12744,202,12745,12746,12747,12748,270,12749, +12750,256,193,461,192,274,201,282,200,332,211,465,210,U,7870,U,7872,202,257, +225,462,224,593,275,233,283,232,299,237,464,236,333,243,466,242,363,250,468, +249,470,472,474,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,476,252,U,7871,U,7873,234,609,9178,9179,41897,4421,U,25866,U,U,20029, +28381,40270,37343,U,U,30517,25745,20250,20264,20392,20822,20852,20892,20964, +21153,21160,21307,21326,21457,21464,22242,22768,22788,22791,22834,22836,23398, +23454,23455,23706,24198,24635,25993,26622,26628,26725,27982,28860,30005,32420, +32428,32442,32455,32463,32479,32518,32567,33402,33487,33647,35270,35774,35810, +36710,36711,36718,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,29713,31996,32205,26950,31433,21031,U,U,U,U,37260,30904,37214,32956,U, +36107,33014,2535,U,U,32927,40647,19661,40393,40460,19518,40438,28686,40458, +41267,13761,U,28314,33342,29977,U,18705,39532,39567,40857,31111,33900,7626, +1488,10982,20004,20097,20096,20103,20159,20203,20279,13388,20413,15944,20483, +20616,13437,13459,13477,20870,22789,20955,20988,20997,20105,21113,21136,21287, +13767,21417,13649,21424,13651,21442,21539,13677,13682,13953,21651,21667,21684, +21689,21712,21743,21784,21795,21800,13720,21823,13733,13759,21975,13765,32132, +21797,U,3138,3349,20779,21904,11462,14828,833,36422,19896,38117,16467,32958, +30586,11320,14900,18389,33117,27122,19946,25821,3452,4020,3285,4340,25741, +36478,3734,3083,3940,11433,33366,17619,U,3398,39501,33001,18420,20135,11458, +39602,14951,38388,16365,13574,21191,38868,30920,11588,40302,38933,U,17369, +24741,25780,21731,11596,11210,4215,14843,4207,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,26330,26390,31136,25834,20562,3139,36456, +8609,35660,1841,U,18443,425,16378,22643,11661,U,17864,1276,24727,3916,3478, +21881,16571,17338,U,19124,10854,4253,33194,39157,3484,25465,14846,10101,36288, +22177,25724,15939,U,42497,3593,10959,11465,U,4296,14786,14738,14854,33435, +13688,24137,8391,22098,3889,11442,38688,13500,27709,20027,U,U,30068,11915, +8712,42587,36045,3706,3124,26652,32659,4303,10243,10553,13819,20963,3724,3981, +3754,16275,3888,3399,4431,3660,U,3755,2985,3400,4288,4413,16377,9878,25650, +4013,13300,30265,11214,3454,3455,11345,11349,14872,3736,4295,3886,42546,27472, +36050,36249,36042,38314,21708,33476,21945,U,40643,39974,39606,30558,11758, +28992,33133,33004,23580,25970,33076,14231,21343,32957,37302,3834,3599,3703, +3835,13789,19947,13833,3286,22191,10165,4297,3600,3704,4216,4424,33287,5205, +3705,20048,11684,23124,4125,4126,4341,4342,22428,3601,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30356,33485,4021,3707,20862,14083, +4022,4480,21208,41661,18906,6202,16759,33404,22681,21096,13850,22333,31666, +23400,18432,19244,40743,18919,39967,39821,23412,12605,22011,13810,22153,20008, +22786,7105,63608,38737,134,20059,20155,13630,23587,24401,24516,14586,25164, +25909,27514,27701,27706,28780,29227,20012,29357,18665,32594,31035,31993,32595, +25194,13505,U,25419,32770,32896,26130,26961,21341,34916,35265,30898,35744, +36125,38021,38264,38271,38376,36367,38886,39029,39118,39134,39267,38928,40060, +40479,40644,27503,63751,20023,135,38429,25143,38050,20539,28158,40051,40870, +15817,34959,16718,28791,23797,19232,20941,13657,23856,24866,35378,36775,37366, +29073,26393,29626,12929,41223,15499,6528,19216,30948,29698,20910,34575,16393, +27235,41658,16931,34319,2671,31274,39239,35562,38741,28749,21284,8318,37876, +30425,35299,40871,30685,20131,20464,20668,20015,20247,40872,21556,32139,22674, +22736,7606,24210,24217,24514,10002,25995,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,13305,26905,27203,15459,27903,U,29184,17669, +29580,16091,18963,23317,29881,35715,23716,22165,31379,31724,31939,32364,33528, +34199,40873,34960,40874,36537,40875,36815,34143,39392,37409,40876,36281,5183, +16497,17058,23066,U,U,U,39016,26475,17014,22333,U,34262,18811,33471,28941, +19585,28020,23931,27413,28606,40877,40878,23446,40879,26343,32347,28247,31178, +15752,17603,12886,10134,17306,17718,U,23765,15130,35577,23672,15634,13649, +23928,40882,29015,17752,16620,7715,19575,14712,13386,420,27713,35532,20404, +569,22975,33132,38998,39162,24379,2975,U,8641,35181,16642,18107,36985,16135, +40883,41397,16632,14294,18167,27718,16764,34482,29695,17773,14548,21658,17761, +17691,19849,19579,19830,17898,16328,19215,13921,17630,17597,16877,23870,23880, +23894,15868,14351,23972,23993,14368,14392,24130,24253,24357,24451,14600,14612, +14655,14669,24791,24893,23781,14729,25015,25017,25039,14776,25132,25232,25317, +25368,14840,22193,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,14851,25570,25595,25607,25690,14923,25792,23829,22049,40863,14999, +25990,15037,26111,26195,15090,26258,15138,26390,15170,26532,26624,15192,26698, +26756,15218,15217,15227,26889,26947,29276,26980,27039,27013,15292,27094,15325, +27237,27252,27249,27266,15340,27289,15346,27307,27317,27348,27382,27521,27585, +27626,27765,27818,15563,27906,27910,27942,28033,15599,28068,28081,28181,28184, +28201,28294,35264,28347,28386,28378,40831,28392,28393,28452,28468,15686,16193, +28545,28606,15722,15733,29111,23705,15754,28716,15761,28752,28756,28783,28799, +28809,805,17345,13809,3800,16087,22462,28371,28990,22496,13902,27042,35817, +23412,31305,22753,38105,31333,31357,22956,31419,31408,31426,31427,29137,25741, +16842,31450,31453,31466,16879,21682,23553,31499,31573,31529,21262,23806,31650, +31599,33692,23476,27775,31696,33825,31634,U,23840,15789,23653,33938,31738,U, +31797,23745,31812,31875,18562,31910,26237,17784,31945,31943,31974,31860,31987, +31989,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +32359,17693,28228,32093,28374,29837,32137,32171,28981,32179,U,16471,24617, +32228,15635,32245,6137,32229,33645,U,24865,24922,32366,32402,17195,37996, +32295,32576,32577,32583,31030,25296,39393,32663,25425,32675,5729,104,17756, +14182,17667,33594,32762,25737,U,32776,32797,U,32815,41095,27843,32827,32828, +32865,10004,18825,26150,15843,26344,26405,32935,35400,33031,33050,22704,9974, +27775,25752,20408,25831,5258,33304,6238,27219,19045,19093,17530,33321,2829, +27218,15742,20473,5373,34018,33634,27402,18855,13616,6003,15864,33450,26907, +63892,16859,34123,33488,33562,3606,6068,14017,12669,13658,33403,33506,33560, +16011,28067,27397,27543,13774,15807,33565,21996,33669,17675,28069,33708,U, +33747,13438,28372,27223,34138,13462,28226,12015,33880,23524,33905,15827,17636, +27303,33866,15541,31064,U,27542,28279,28227,34014,U,33681,17568,33939,34020, +23697,16960,23744,17731,34100,23282,28313,17703,34163,17686,26559,34326,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34341,34363, +34241,28808,34306,5506,28877,63922,17770,34344,13896,6306,21495,29594,34430, +34673,41208,34798,11303,34737,34778,34831,22113,34412,26710,17935,34885,34886, +30176,15801,30180,34910,34972,18011,34996,34997,25537,35013,30583,30479,35207, +35210,U,U,35239,35260,35365,35303,31012,31421,35484,30611,37374,35472,31321, +31465,31546,16271,18195,31544,29052,35596,35615,21552,21861,35647,35660,35661, +35497,19066,35728,35739,35503,5855,17941,34895,35995,32084,32143,63956,14117, +32083,36054,32152,32189,36114,36099,6416,36059,28764,36113,19657,16080,36265, +32770,4116,18826,15228,33212,28940,31463,36525,36534,36547,37588,36633,36653, +33637,33810,36773,37635,41631,2640,36787,18730,35294,34109,15803,24312,12898, +36857,40980,34492,34049,8997,14720,28375,36919,34108,31422,36961,34156,34315, +37032,34579,37060,34534,37038,U,37223,15088,37289,37316,31916,35123,7817, +37390,27807,37441,37474,21945,U,35526,15515,35596,21979,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,3377,37676,37739,35553,35819, +28815,23235,35554,35557,18789,37444,35820,35897,35839,37747,37979,36540,38277, +38310,37926,38304,28662,17081,9850,34520,4732,15918,18911,27676,38523,38550, +16748,38563,28373,25050,38582,30965,35552,38589,21452,18849,27832,628,25616, +37039,37093,19153,6421,13066,38705,34370,38710,18959,17725,17797,19177,28789, +23361,38683,U,37333,38743,23370,37355,38751,37925,20688,12471,12476,38793, +38815,38833,38846,38848,38866,38880,21612,38894,29724,37939,U,38901,37917, +31098,19153,38964,38963,38987,39014,15118,29045,15697,1584,16732,22278,39114, +39095,39112,39111,19199,27943,5843,21936,39137,39142,39148,37752,39225,18985, +19314,38999,39173,39413,39436,39483,39440,39512,22309,14020,37041,39893,39648, +39650,39685,39668,19470,39700,39725,34304,20532,39732,27048,14531,12413,39760, +39744,40254,23109,6243,39822,16971,39938,39935,39948,40552,40404,40887,41362, +41387,41185,41251,41439,40318,40323,41268,40462,26760,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40388,8539,41363,41504,6459,41523, +40249,41145,41652,40592,40597,40606,40610,19764,40618,40623,17252,40641,15200, +14821,15645,20274,14270,35883,40706,40712,19350,37924,28066,40727,U,40761, +22175,22154,40773,39352,37003,38898,33919,40802,40809,31452,40846,29206,19390, +18805,18875,29047,18936,17224,19025,29598,35802,6394,31135,35198,36406,37737, +37875,35396,37612,37761,37835,35180,17593,29207,16107,30578,31299,28880,17523, +17400,29054,6127,28835,6334,13721,16071,6277,21551,6136,14114,5883,6201,14049, +6004,6353,24395,14115,5824,22363,18981,5118,4776,5062,5302,34051,13990,U, +33877,18836,29029,15921,21852,16123,28754,17652,14062,39325,28454,26617,14131, +15381,15847,22636,6434,26640,16471,14143,16609,16523,16655,27681,21707,22174, +26289,22162,4063,2984,3597,37830,35603,37788,20216,20779,14361,17462,20156, +1125,895,20299,20362,22097,23144,427,971,14745,778,1044,13365,20265,704,36531, +629,35546,524,20120,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,20685,20749,20386,20227,18958,16010,20290,20526,20588,20609,20428, +20453,20568,20732,U,U,U,U,28278,13717,15929,16063,28018,6276,16009,20904, +20931,1504,17629,1187,1170,1169,36218,35484,1806,21081,21156,2163,21217,U, +18042,29068,17292,3104,18860,4324,27089,3613,U,16094,29849,29716,29782,29592, +19342,19132,16525,21456,13700,29199,16585,21940,837,21709,3014,22301,37469, +38644,37734,22493,22413,22399,13886,22731,23193,35398,5882,5999,5904,23084, +22968,37519,23166,23247,23058,22854,6643,6241,17045,14069,27909,29763,23073, +24195,23169,35799,1043,37856,29836,4867,28933,18802,37896,35323,37821,14240, +23582,23710,24158,24136,6550,6524,15086,24269,23375,6403,6404,14081,6304, +14045,5886,14035,33066,35399,7610,13426,35240,24332,24334,6439,6059,23147, +5947,23364,34324,30205,34912,24702,10336,9771,24539,16056,9647,9662,37000, +28531,25024,62,70,9755,24985,24984,24693,11419,11527,18132,37197,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25713,18021,11114, +14889,11042,13392,39146,11896,25399,42075,25782,25393,25553,18915,11623,25252, +11425,25659,25963,26994,15348,12430,12973,18825,12971,21773,13024,6361,37951, +26318,12937,12723,15072,16784,21892,35618,21903,5884,21851,21541,30958,12547, +6186,12852,13412,12815,12674,17097,26254,27940,26219,19347,26160,30832,7659, +26211,13010,13025,26142,22642,14545,14394,14268,15257,14242,13310,29904,15254, +26511,17962,26806,26654,15300,27326,14435,14293,17543,27187,27218,27337,27397, +6418,25873,26776,27212,15319,27258,27479,16320,15514,37792,37618,35818,35531, +37513,32798,35292,37991,28069,28427,18924,U,16255,15759,28164,16444,23101, +28170,22599,27940,30786,28987,17178,17014,28913,29264,29319,29332,18319,18213, +20857,19108,1515,29818,16120,13919,19018,18711,24545,16134,16049,19167,35875, +16181,24743,16115,29900,29756,37767,29751,17567,28138,17745,30083,16227,19673, +19718,16216,30037,30323,42438,15129,29800,35532,18859,18830,15099,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,15821,19022,16127, +18885,18675,37370,22322,37698,35555,6244,20703,21025,20967,30584,12850,30478, +30479,30587,18071,14209,14942,18672,29752,29851,16063,19130,19143,16584,19094, +25006,37639,21889,30750,30861,30856,30930,29648,31065,30529,22243,16654,U, +33942,31141,27181,16122,31290,31220,16750,5862,16690,37429,31217,3404,18828, +665,15802,5998,13719,21867,13680,13994,468,3085,31458,23129,9973,23215,23196, +23053,603,30960,23082,23494,31486,16889,31837,31853,16913,23475,24252,24230, +31949,18937,6064,31886,31868,31918,27314,32220,32263,32211,32590,25185,24924, +31560,32151,24194,17002,27509,2326,26582,78,13775,22468,25618,25592,18786, +32733,31527,2092,23273,23875,31500,24078,39398,34373,39523,27164,13375,14818, +18935,26029,39455,26016,33920,28967,27857,17642,33079,17410,32966,33033,33090, +26548,39107,27202,33378,33381,27217,33875,28071,34320,29211,23174,16767,6208, +23339,6305,23268,6360,34464,63932,15759,34861,29730,23042,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34926,20293,34951,35007,35046, +35173,35149,22147,35156,30597,30596,35829,35801,35740,35321,16045,33955,18165, +18127,14322,35389,35356,37960,24397,37419,17028,26068,28969,28868,6213,40301, +35999,36073,32220,22938,30659,23024,17262,14036,36394,36519,19465,36656,36682, +17140,27736,28603,8993,18587,28537,28299,6106,39913,14005,18735,37051,U,21873, +18694,37307,37892,35403,16482,35580,37927,35869,35899,34021,35371,38297,38311, +38295,38294,36148,29765,16066,18687,19010,17386,16103,12837,38543,36583,36454, +36453,16076,18925,19064,16366,29714,29803,16124,38721,37040,26695,18973,37011, +22495,U,37736,35209,35878,35631,25534,37562,23313,35689,18748,29689,16923, +38811,38769,39224,3878,24001,35781,19122,38943,38106,37622,38359,37349,17600, +35664,19047,35684,39132,35397,16128,37418,18725,33812,39227,39245,31494,15869, +39323,19311,39338,39516,35685,22728,27279,39457,23294,39471,39153,19344,39240, +39356,19389,19351,37757,22642,4866,22562,18872,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,5352,30788,10015,15800,26821,15741, +37976,14631,24912,10113,10603,24839,40015,40019,40059,39989,39952,39807,39887, +40493,39839,41461,41214,40225,19630,16644,40472,19632,40204,41396,41197,41203, +39215,40357,33981,28178,28639,27522,34300,17715,28068,28292,28144,33824,34286, +28160,14295,24676,31202,13724,13888,18733,18910,15714,37851,37566,37704,703, +30905,37495,37965,20452,13376,36964,21853,30781,30804,30902,30795,5975,12745, +18753,13978,20338,28634,28633,U,28702,21524,16821,22459,22771,22410,40214, +22487,28980,13487,16812,29163,27712,20375,U,6069,35401,24844,23246,23051, +17084,17544,14124,19323,35324,37819,37816,6358,3869,33906,27840,5139,17146, +11302,17345,22932,15799,26433,32168,24923,24740,18873,18827,35322,37605,29666, +16105,29876,35683,6303,16097,19123,27352,29683,29691,16086,19006,19092,6105, +19046,935,5156,18917,29768,18710,28837,18806,37508,29670,37727,1278,37681, +35534,35350,37766,35815,21973,18741,35458,29035,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,18755,3327,22180,1562,3051,3256,21762, +31172,6138,32254,5826,19024,6226,17710,37889,14090,35520,18861,22960,6335, +6275,29828,23201,14050,15707,14000,37471,23161,35457,6242,37748,15565,2740, +19094,14730,20724,15721,15692,5020,29045,17147,33304,28175,37092,17643,27991, +32335,28775,27823,15574,16365,15917,28162,28428,15727,1013,30033,14012,13512, +18048,16090,18545,22980,37486,18750,36673,35868,27584,22546,22472,14038,5202, +28926,17250,19057,12259,4784,9149,26809,26983,5016,13541,31732,14047,35459, +14294,13306,19615,27162,13997,27831,33854,17631,17614,27942,27985,27778,28638, +28439,28937,33597,5946,33773,27776,28755,6107,22921,23170,6067,23137,23153, +6405,16892,14125,23023,5948,14023,29070,37776,26266,17061,23150,23083,17043, +27179,16121,30518,17499,17098,28957,16985,35297,20400,27944,23746,17614,32333, +17341,27148,16982,4868,28838,28979,17385,15781,27871,63525,19023,32357,23019, +23855,15859,24412,19037,6111,32164,33830,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,21637,15098,13056,532,22398,2261,1561,16357, +8094,41654,28675,37211,23920,29583,31955,35417,37920,20424,32743,29389,29456, +31476,29496,29497,22262,29505,29512,16041,31512,36972,29173,18674,29665,33270, +16074,30476,16081,27810,22269,29721,29726,29727,16098,16112,16116,16122,29907, +16142,16211,30018,30061,30066,30093,16252,30152,30172,16320,30285,16343,30324, +16348,30330,20316,29064,22051,35200,22633,16413,30531,16441,26465,16453,13787, +30616,16490,16495,23646,30654,30667,22770,30744,28857,30748,16552,30777,30791, +30801,30822,33864,21813,31027,26627,31026,16643,16649,31121,31129,36795,31238, +36796,16743,31377,16818,31420,33401,16836,31439,31451,16847,20001,31586,31596, +31611,31762,31771,16992,17018,31867,31900,17036,31928,17044,31981,36755,28864, +3279,32207,32212,32208,32253,32686,32692,29343,17303,32800,32805,31545,32814, +32817,32852,15820,22452,28832,32951,33001,17389,33036,29482,33038,33042,30048, +33044,17409,15161,33110,33113,33114,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,17427,22586,33148,33156,17445,33171,17453,33189, +22511,33217,33252,33364,17551,33446,33398,33482,33496,33535,17584,33623,38505, +27018,33797,28917,33892,24803,33928,17668,33982,34017,34040,34064,34104,34130, +17723,34159,34160,34272,17783,34418,34450,34482,34543,38469,34699,17926,17943, +34990,35071,35108,35143,35217,31079,35369,35384,35476,35508,35921,36052,36082, +36124,18328,22623,36291,18413,20206,36410,21976,22356,36465,22005,36528,18487, +36558,36578,36580,36589,36594,36791,36801,36810,36812,36915,39364,18605,39136, +37395,18718,37416,37464,37483,37553,37550,37567,37603,37611,37619,37620,37629, +37699,37764,37805,18757,18769,40639,37911,21249,37917,37933,37950,18794,37972, +38009,38189,38306,18855,38388,38451,18917,26528,18980,38720,18997,38834,38850, +22100,19172,24808,39097,19225,39153,22596,39182,39193,20916,39196,39223,39234, +39261,39266,19312,39365,19357,39484,39695,31363,39785,39809,39901,39921,39924, +19565,39968,14191,7106,40265,39994,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,40702,22096,40339,40381,40384,40444,38134,36790, +40571,40620,40625,40637,40646,38108,40674,40689,40696,31432,40772,148,695,928, +26906,38083,22956,1239,22592,38081,14265,1493,1557,1654,5818,22359,29043,2754, +2765,3007,21610,63547,3019,21662,3067,3131,3155,3173,3196,24807,3213,22138, +3253,3293,3309,3439,3506,3528,26965,39983,34725,3588,3598,3799,3984,3885,3699, +23584,4028,24075,4188,4175,4214,26398,4219,4232,4246,13895,4287,4307,4399, +4411,21348,33965,4835,4981,4918,35713,5495,5657,6083,6087,20088,28859,6189, +6506,6701,6725,7210,7280,7340,7880,25283,7893,7957,29080,26709,8261,27113, +14024,8828,9175,9210,10026,10353,10575,33533,10599,10643,10965,35237,10984, +36768,11022,38840,11071,38983,39613,11340,U,11400,11447,23528,11528,11538, +11703,11669,11842,12148,12236,12339,12390,13087,13278,24497,26184,26303,31353, +13671,13811,U,18874,U,13850,14102,U,838,22709,26382,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,26904,15015,30295,24546,15889,16057, +30206,8346,18640,19128,16665,35482,17134,17165,16443,17204,17302,19013,1482, +20946,1553,22943,7848,15294,15615,17412,17622,22408,18036,14747,18223,34280, +39369,14178,8643,35678,35662,U,18450,18683,18965,29193,19136,3192,22885,20133, +20358,1913,36570,20524,21135,22335,29041,21145,21529,16202,19111,21948,21574, +21614,27474,U,13427,21823,30258,21854,18200,21858,21862,22471,18751,22621, +20582,13563,13260,U,22787,18300,35144,23214,23433,23558,7568,22433,29009,U, +24834,31762,36950,25010,20378,35682,25602,25674,23899,27639,U,25732,6428, +35562,18934,25736,16367,25874,19392,26047,26293,10011,37989,22497,24981,23079, +63693,U,22201,17697,26364,20074,18740,38486,28047,27837,13848,35191,26521, +26734,25617,26718,U,26823,31554,37056,2577,26918,U,26937,31301,U,27130,39462, +27181,13919,25705,33,31107,27188,27483,23852,13593,U,27549,18128,27812,30011, +34917,28078,22710,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,14108,9613,28747,29133,15444,29312,29317,37505,8570,29323,37680,29414, +18896,27705,38047,29776,3832,34855,35061,10534,33907,6065,28344,18986,6176, +14756,14009,U,U,17727,26294,40109,39076,35139,30668,30808,22230,16607,5642, +14753,14127,33000,5061,29101,33638,31197,37288,U,19639,28847,35243,31229, +31242,31499,32102,16762,31555,31102,32777,28597,41695,27139,33560,21410,28167, +37823,26678,38749,33135,32803,27061,5101,12847,32840,23941,35888,32899,22293, +38947,35145,23979,18824,26046,27093,21458,19109,16257,15377,26422,32912,33012, +33070,8097,33103,33161,33199,33306,33542,33583,33674,13770,33896,34474,18682, +25574,35158,30728,37461,35256,17394,35303,17375,35304,35654,35796,23032,35849, +U,36805,37100,U,37136,37180,15863,37214,19146,36816,29327,22155,38119,38377, +38320,38328,38706,39121,39241,39274,39363,39464,39694,40282,40347,32415,40696, +40739,19620,38215,41619,29090,41727,19857,36882,42443,19868,3228,36798,21953, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,36794, +9392,36793,19091,17673,32383,28502,27313,20202,13540,35628,30877,14138,36480, +6133,32804,35692,35737,31294,26287,15851,30293,15543,22069,22870,20122,24193, +25176,22207,3693,36366,23405,16008,19614,25566,U,6134,6267,25904,22061,23626, +21530,21265,15814,40344,19581,22050,22046,32585,24280,22901,15680,34672,19996, +4074,3401,14010,33047,40286,36120,30267,40005,30286,30649,37701,21554,33096, +33527,22053,33074,33816,32957,21994,31074,22083,21526,3741,13774,22021,22001, +26353,33506,13869,30004,22000,21946,21655,21874,3137,3222,24272,20808,3702, +11362,3746,40619,32090,21982,4213,25245,38765,21652,36045,29174,37238,25596, +25529,25598,21865,11075,40050,11955,20890,13535,3495,20903,21581,21790,21779, +30310,36397,26762,30129,32950,34820,34694,35015,33206,33820,4289,17644,29444, +18182,23440,33547,26771,22139,9972,32047,16803,32115,28368,29366,37232,4569, +37384,15612,42665,3756,3833,29286,7330,18254,20418,32761,4075,16634,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40029,25887,11680, +18675,18400,40316,4076,3594,U,30115,4077,U,24648,4487,29091,32398,40272,19994, +19972,13687,23309,27826,21351,13996,14812,21373,13989,17944,22682,19310,33325, +21579,22442,23189,2425,U,14930,9317,29556,40620,19721,39917,15614,40752,19547, +20393,38302,40926,33884,15798,29362,26547,14112,25390,32037,16119,15916,14890, +36872,21196,15988,13946,17897,1166,30272,23280,3766,30842,32558,22695,16575, +22140,39819,23924,30292,42036,40581,19681,U,14331,24857,12506,17394,U,22109, +4777,22439,18787,40454,21044,28846,13741,U,40316,31830,39737,22494,5996,23635, +25811,38096,25397,29028,34477,3368,27938,19170,3441,U,20990,7951,23950,38659, +7633,40577,36940,31519,39682,23761,31651,25192,25397,39679,31695,39722,31870, +U,31810,31878,39957,31740,39689,U,39963,18750,40794,21875,23491,20477,40600, +20466,21088,15878,21201,22375,20566,22967,24082,38856,40363,36700,21609,38836, +39232,38842,21292,24880,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,26924,21466,39946,40194,19515,38465,27008,20646,30022,5997, +39386,21107,U,37209,38529,37212,U,37201,36503,25471,27939,27338,22033,37262, +30074,25221,1020,29519,31856,23585,15613,U,18713,30422,39837,20010,3284,33726, +34882,U,23626,27072,U,22394,21023,24053,20174,27697,498,20281,21660,21722, +21146,36226,13822,U,13811,U,27474,37244,40869,39831,38958,39092,39610,40616, +40580,29050,31508,U,27642,34840,32632,U,22048,42570,36471,40787,U,36308,36431, +40476,36353,25218,33661,36392,36469,31443,19063,31294,30936,27882,35431,30215, +35418,40742,27854,34774,30147,41650,30803,63552,36108,29410,29553,35629,29442, +29937,36075,19131,34351,24506,34976,17591,U,6203,28165,U,35454,9499,U,24829, +30311,39639,40260,37742,39823,34805,U,U,36087,29484,38689,39856,13782,29362, +19463,31825,39242,24921,24921,19460,40598,24957,U,22367,24943,25254,25145,U, +14940,25058,21418,13301,25444,26626,13778,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23895,35778,36826,36409,U,20697,7494,30982, +21298,38456,3899,16485,U,30718,U,31938,24346,31962,31277,32870,32867,32077, +29957,29938,35220,33306,26380,32866,29830,32859,29936,33027,30500,35209,26572, +30035,28369,34729,34766,33224,34700,35401,36013,35651,30507,29944,34010,13877, +27058,36262,U,35241,U,28089,34753,16401,29927,15835,29046,24740,24988,15569,U, +24695,U,32625,35629,U,24809,19326,21024,15384,15559,24279,30294,21809,6468, +4862,39171,28124,28845,23745,25005,35343,13943,238,26694,20238,17762,23327, +25420,40784,40614,25195,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321, +9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,8560,8561,8562,8563,8564, +8565,8566,8567,8568,8569,20022,20031,20101,20128,20866,20886,20907,21241, +21304,21353,21430,22794,23424,24027,12083,24191,U,24400,24417,25908,U,30098,U, +36789,U,168,710,12541,12542,12445,12446,U,U,12293,12294,12295,12540,65339, +65341,10045,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363, +12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376, +12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389, +12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402, +12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415, +12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428, +12429,12430,12431,12432,12433,12434,12435,12449,12450,12451,12452,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12453,12454,12455, +12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468, +12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481, +12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494, +12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507, +12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520, +12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533, +12534,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052, +1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067, +1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081, +1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096, +1097,1098,1099,1100,1101,1102,1103,8679,8632,8633,12751,204,20058,138,20994, +17553,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +40880,20872,40881,30215,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,65506,65508,65287,65282,12849,8470,8481,12443,12444, +11904,11908,11910,11911,11912,11914,11916,11917,11925,11932,11933,11941,11943, +11946,11948,11950,11958,11964,11966,11974,11978,11980,11981,11983,11990,11991, +11998,12003,U,U,U,643,592,603,596,629,339,248,331,650,618,30849,37561,35023, +22715,24658,31911,23290,9556,9574,9559,9568,9580,9571,9562,9577,9565,9554, +9572,9557,9566,9578,9569,9560,9575,9563,9555,9573,9558,9567,9579,9570,9561, +9576,9564,9553,9552,9581,9582,9584,9583,65517,1351,37595,1503,16325,34124, +17077,29679,20917,13897,18754,35300,37700,6619,33518,15560,30780,26436,25311, +18739,35242,672,27571,4869,20395,9453,20488,27945,31364,13824,19121,9491,U, +894,24484,896,839,28379,1055,U,20737,13434,20750,39020,14147,33814,18852,1159, +20832,13236,20842,3071,8444,741,9520,1422,12851,6531,23426,34685,1459,15513, +20914,20920,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,40244,20937,20943,20945,15580,20947,19110,20915,20962,21314,20973,33741, +26942,14125,24443,21003,21030,21052,21173,21079,21140,21177,21189,31765,34114, +21216,34317,27411,U,35550,21833,28377,16256,2388,16364,21299,U,3042,27851, +5926,26651,29653,24650,16042,14540,5864,29149,17570,21357,21364,34475,21374,U, +5526,5651,30694,21395,35483,21408,21419,21422,29607,22386,16217,29596,21441, +21445,27721,20041,22526,21465,15019,2959,21472,16363,11683,21494,3191,21523, +28793,21803,26199,27995,21613,27475,3444,21853,21647,21668,18342,5901,3805, +15796,3405,35260,9880,21831,19693,21551,29719,21894,21929,U,6359,16442,17746, +17461,26291,4276,22071,26317,12938,26276,26285,22093,22095,30961,22257,38791, +21502,22272,22255,22253,35686,13859,4687,22342,16805,27758,28811,22338,14001, +27774,22502,5142,22531,5204,17251,22566,19445,22620,22698,13665,22752,22748, +4668,22779,23551,22339,41296,17016,37843,13729,22815,26790,14019,28249,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,5694,23076, +21843,5778,34053,22985,3406,27777,27946,6108,23001,6139,6066,28070,28017,6184, +5845,23033,28229,23211,23139,14054,18857,U,14088,23190,29797,23251,28577,9556, +15749,6417,14130,5816,24195,21200,23414,25992,23420,31246,16388,18525,516, +23509,24928,6708,22988,1445,23539,23453,19728,23557,6980,23571,29646,23572, +7333,27432,23625,18653,23685,23785,23791,23947,7673,7735,23824,23832,23878, +7844,23738,24023,33532,14381,18689,8265,8563,33415,14390,15298,24110,27274,U, +24186,17596,3283,21414,20151,U,21416,6001,24073,24308,33922,24313,24315,14496, +24316,26686,37915,24333,449,63636,15070,18606,4922,24378,26760,9168,U,9329, +24419,38845,28270,24434,37696,35382,24487,23990,15711,21072,8042,28920,9832, +37334,670,35369,24625,26245,6263,14691,15815,13881,22416,10164,31089,15936, +24734,U,24755,18818,18831,31315,29860,20705,23200,24932,33828,24898,63654, +28370,24961,20980,1622,24967,23466,16311,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,10335,25043,35741,39261,25040,14642,10624, +10433,24611,24924,25886,25483,280,25285,6000,25301,11789,25452,18911,14871, +25656,25592,5006,6140,U,28554,11830,38932,16524,22301,25825,25829,38011,14950, +25658,14935,25933,28438,18984,18979,25989,25965,25951,12414,26037,18752,19255, +26065,16600,6185,26080,26083,24543,13312,26136,12791,12792,26180,12708,12709, +26187,3701,26215,20966,26227,U,7741,12849,34292,12744,21267,30661,10487,39332, +26370,17308,18977,15147,27130,14274,U,26471,26466,16845,37101,26583,17641, +26658,28240,37436,26625,13286,28064,26717,13423,27105,27147,35551,26995,26819, +13773,26881,26880,15666,14849,13884,15232,26540,26977,35402,17148,26934,27032, +15265,969,33635,20624,27129,13913,8490,27205,14083,27293,15347,26545,27336, +37276,15373,27421,2339,24798,27445,27508,10189,28341,15067,949,6488,14144, +21537,15194,27617,16124,27612,27703,9355,18673,27473,27738,33318,27769,15804, +17605,15805,16804,18700,18688,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,15561,14053,15595,3378,39811,12793,9361,32655,26679,27941, +28065,28139,28054,27996,28284,28420,18815,16517,28274,34099,28532,20935,U,U, +33838,35617,U,15919,29779,16258,31180,28239,23185,12363,28664,14093,28573, +15920,28410,5271,16445,17749,37872,28484,28508,15694,28532,37232,15675,28575, +16708,28627,16529,16725,16441,16368,16308,16703,20959,16726,16727,16704,25053, +28747,28798,28839,28801,28876,28885,28886,28895,16644,15848,29108,29078,17015, +28971,28997,23176,29002,U,23708,17253,29007,37730,17089,28972,17498,18983, +18978,29114,35816,28861,29198,37954,29205,22801,37955,29220,37697,22021,29230, +29248,18804,26813,29269,29271,15957,12356,26637,28477,29314,U,29483,18467, +34859,18669,34820,29480,29486,29647,29610,3130,27182,29641,29769,16866,5863, +18980,26147,14021,18871,18829,18939,29687,29717,26883,18982,29753,1475,16087, +U,10413,29792,36530,29767,29668,29814,33721,29804,14128,29812,37873,27180, +29826,18771,19084,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,16735,19065,35727,23366,35843,6302,29896,6536,29966,U,29982,36569, +6731,23511,36524,37765,30029,30026,30055,30062,20354,16132,19731,30094,29789, +30110,30132,30210,30252,30289,30287,30319,30326,25589,30352,33263,14328,26897, +26894,30369,30373,30391,30412,28575,33890,20637,20861,7708,30494,30502,30528, +25775,21024,30552,12972,30639,35172,35176,5825,30708,U,4982,18962,26826,30895, +30919,30931,38565,31022,21984,30935,31028,30897,30220,36792,34948,35627,24707, +9756,31110,35072,26882,31104,22615,31133,31545,31036,31145,28202,28966,16040, +31174,37133,31188, +}; + +static const struct dbcs_index big5hkscs_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__big5hkscs_decmap+0,64,121},{__big5hkscs_decmap+58,64,170},{ +__big5hkscs_decmap+165,64,254},{__big5hkscs_decmap+356,64,254},{ +__big5hkscs_decmap+547,64,253},{__big5hkscs_decmap+737,64,254},{ +__big5hkscs_decmap+928,64,254},{__big5hkscs_decmap+1119,64,254},{ +__big5hkscs_decmap+1310,64,253},{__big5hkscs_decmap+1500,64,254},{ +__big5hkscs_decmap+1691,64,254},{__big5hkscs_decmap+1882,64,254},{ +__big5hkscs_decmap+2073,64,254},{__big5hkscs_decmap+2264,64,254},{ +__big5hkscs_decmap+2455,64,254},{__big5hkscs_decmap+2646,64,254},{ +__big5hkscs_decmap+2837,64,254},{__big5hkscs_decmap+3028,64,254},{ +__big5hkscs_decmap+3219,64,254},{__big5hkscs_decmap+3410,64,254},{ +__big5hkscs_decmap+3601,64,254},{__big5hkscs_decmap+3792,64,254},{ +__big5hkscs_decmap+3983,64,254},{__big5hkscs_decmap+4174,64,254},{ +__big5hkscs_decmap+4365,64,254},{__big5hkscs_decmap+4556,64,254},{0,0,0},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5hkscs_decmap+4747, +161,254},{__big5hkscs_decmap+4841,64,254},{__big5hkscs_decmap+5032,64,254},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__big5hkscs_decmap+5223,214,254},{__big5hkscs_decmap+5264,64,254},{ +__big5hkscs_decmap+5455,64,254},{__big5hkscs_decmap+5646,64,254},{ +__big5hkscs_decmap+5837,64,254},{__big5hkscs_decmap+6028,64,254},{0,0,0}, +}; + +static const unsigned char big5hkscs_phint_0[] = { +32,5,95,68,15,82,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,208,44,4,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,4,0,0,0,0,0,0,0,0,0,0,0,0,1,22,0,15,0,0,0,0,0, +32,87,43,247,252,110,242,144,11,0,0,0,192,237,164,15,38,193,155,118,242,239, +222,251,250,247,15,50,68,175,254,239,5,0,0,0,224,251,71,128,193,2,0,132,100,4, +130,64,32,162,130,133,164,145,0,16,1,0,0,0,144,72,12,0,48,0,84,3,48,68,24,19, +53,137,38,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,64,0,32,43,153,32,16,99,40,36, +1,0,0,0,0,80,96,212,0,210,42,24,157,104,53,151,79,216,248,32,196,130,28,40,2, +0,0,0,0,214,81,10,224,0,129,134,22,67,196,53,17,55,96,230,122,109,5,12,61,0,0, +0,0,153,57,128,7,34,254,129,144,24,144,12,116,48,208,160,9,41,21,253,4,0,0,0, +0,223,128,64,8,8,176,219,196,96,237,118,125,249,29,228,211,133,166,205,5,0,0, +0,0,12,0,110,186,9,47,96,84,0,30,120,104,34,112,86,158,37,243,142,7,0,0,0,192, +94,44,188,155,223,93,108,109,4,67,96,54,74,96,216,62,7,196,200,1,0,0,0,160, +177,197,98,11,12,34,62,204,37,184,1,174,237,92,104,13,148,74,181,0,0,0,0,0, +244,3,18,17,16,68,2,53,144,235,14,153,7,209,202,5,130,161,160,0,0,0,0,52,24, +160,137,231,156,91,8,132,3,2,218,144,236,219,135,133,191,162,45,0,0,0,0,118, +58,118,98,130,148,24,1,24,125,254,141,87,39,19,210,91,55,25,12,0,0,0,0,110, +139,33,145,0,0,0,64,0,0,0,2,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,142,120,110,95,63,126,221,61,247,252,155,252,174, +210,255,143,107,1,0,0,0,192,159,255,234,186,186,93,188,115,159,250,216,214, +222,37,75,94,151,218,42,1,0,0,0,224,182,153,27,216,116,230,79,21,191,41,230, +255,38,117,109,227,255,155,82,0,0,0,0,80,96,126,111,153,169,80,14,0,128,16, +216,35,0,37,16,144,244,235,117,0,0,0,0,208,219,0,160,152,178,123,6,82,32,152, +22,200,61,9,0,0,1,0,0,0,0,0,0,0,4,40,200,34,0,2,0,0,16,32,130,80,64,48,1,0,16, +0,4,0,0,0,0,74,4,1,16,20,0,128,0,4,255,253,36, +}; + +static const unsigned char big5hkscs_phint_12130[] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,128,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0, +}; + +static const unsigned char big5hkscs_phint_21924[] = { +0,0,0,0,0,26,172,248,250,90,192,250,51,0,0,0,0,0,129,0,160,156,130,144,9,1, +180,192,176,3,86,2,160,66,45,136,1,0,0,0,0,146,119,139,96,5,201,33,6,70,56,96, +72,192,180,36,222,132,224,192,36,0,0,0,0,205,80,197,52,192,40,162,173,124,153, +24,88,18,34,196,66,162,83,142,30,0,0,0,128,52,135,11,21,209,64,250,61,0,4,210, +5,72,8,22,230,28,165,0,8,0,0,0,192,45,22,20,128,24,58,212,25,136,28,138,4, +}; + +static const DBCHAR __big5hkscs_bmp_encmap[26401] = { +50904,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34905,34903,N,N,N,N,N,N, +34909,34907,M,N,N,N,N,N,N,N,34913,34911,N,N,N,N,N,N,N,N,N,N,N,N,34922,34920,N, +N,N,N,N,N,34927,34925,M,N,34931,34929,N,N,N,N,34935,34933,N,N,N,N,51451,34939, +34937,N,34978,34902,34919,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34906,34924,N,N,N,N, +N,N,34908,34926,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34928,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,51452,34910,34932,N,N,N,N,N,51450,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34936,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,34904,34921,N,34930,34912,34934,N,34938,N,34940,N,34941,N,34942,N,34977, +51446,34923,N,N,51448,N,N,N,N,N,N,51447,N,N,N,N,N,34984,N,N,N,N,N,N,N,N,51454, +N,N,N,N,N,N,N,N,N,N,51449,N,N,N,N,N,N,N,N,N,N,N,N,N,51445,N,N,N,N,N,N,51453,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,50905,51193,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +51187,51188,51189,51190,51191,51192,51194,51195,51196,51197,51198,51264,51265, +51266,51267,51268,51269,51270,51271,51272,51273,51274,51275,51276,51277,51278, +51279,51280,51281,51282,51283,51284,51285,51286,51287,51288,51289,51290,51292, +51293,51294,51295,51296,51297,51298,51299,51300,51301,51302,51303,51304,51305, +51306,51307,51308,51309,51310,51311,51312,51313,51314,51315,51316,51317,N, +51291,34915,34980,34917,34982,51410,N,N,N,N,N,N,N,N,N,N,51411,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,50869,50870, +50871,50872,50873,50874,50875,50876,50877,50878,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,51319,51320,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,51318,34985,34986,50849,50850,50851, +50852,50853,50854,50855,50856,50857,50858,N,N,N,N,N,N,N,N,N,N,50859,50860, +50861,50862,50863,50864,50865,50866,50867,50868,63993,63992,63974,63983,63965, +63976,63985,63967,63980,63989,63971,63982,63991,63973,63977,63986,63968,63979, +63988,63970,63975,63984,63966,63981,63990,63972,63978,63987,63969,63994,63995, +63997,63996,50918,51414,N,N,N,51415,N,51416,51417,51418,N,51419,N,51420,51421, +N,N,N,N,N,N,N,51422,N,N,N,N,N,N,51423,51424,N,N,N,N,N,N,N,51425,N,51426,N,N, +51427,N,51428,N,51429,N,N,N,N,N,N,N,51430,N,N,N,N,N,51431,N,51432,N,N,N,N,N,N, +N,51433,N,N,N,51434,N,51435,51436,N,51437,N,N,N,N,N,N,51438,51439,N,N,N,N,N,N, +51440,N,N,N,N,51441,50893,50912,50913,50914,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,50919,50920,50921,50922,50923,50924,50925,50926,50927,50928,50929,50930, +50931,50932,50933,50934,50935,50936,50937,50938,50939,50940,50941,50942,51008, +51009,51010,51011,51012,51013,51014,51015,51016,51017,51018,51019,51020,51021, +51022,51023,51024,51025,51026,51027,51028,51029,51030,51031,51032,51033,51034, +51035,51036,51037,51038,51039,51040,51041,51042,51043,51044,51045,51046,51047, +51048,51049,51050,51051,51052,51053,51054,51055,51056,51057,51058,51059,51060, +51061,51062,51063,51064,51065,51066,N,N,N,N,N,N,N,51412,51413,50908,50909,N,N, +51067,51068,51069,51070,51105,51106,51107,51108,51109,51110,51111,51112,51113, +51114,51115,51116,51117,51118,51119,51120,51121,51122,51123,51124,51125,51126, +51127,51128,51129,51130,51131,51132,51133,51134,51135,51136,51137,51138,51139, +51140,51141,51142,51143,51144,51145,51146,51147,51148,51149,51150,51151,51152, +51153,51154,51155,51156,51157,51158,51159,51160,51161,51162,51163,51164,51165, +51166,51167,51168,51169,51170,51171,51172,51173,51174,51175,51176,51177,51178, +51179,51180,51181,51182,51183,51184,51185,51186,N,N,N,N,N,50915,50906,50907, +34880,34881,34882,34883,34884,34886,34889,34890,34893,34895,34896,34897,34898, +34900,34901,51321,51409,37495,N,N,N,N,N,N,N,N,N,N,38623,N,N,N,N,N,N,N,N,N, +36084,N,35285,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37837,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39903,N,N,N,N,N,N,64104,N,N,35290,36697,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,35291,N,N,36701,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35292,N,N,N,N,N, +N,N,N,N,38647,N,N,N,N,N,N,N,N,N,N,N,N,35546,N,N,N,N,35804,N,N,N,N,N,N,38875,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40531,N,N,N,N,40362,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,39914,35438,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35784, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35304,N,35306,N,N,N,N,N,35915,N,N,N,N,N,N, +N,64368,N,N,N,N,N,N,N,N,N,N,N,35309,N,N,38109,N,35310,N,N,N,N,40628,35539,N,N, +N,N,N,N,N,N,N,N,N,37595,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38107,35321,N,N,N, +N,N,N,N,N,64378,N,N,N,35323,N,N,N,N,N,N,N,40700,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,35324,N,35263,N,N,N,35326,N,35302,N,N,40262,N,N,N,40430,N,N,N,41086,N,N,N, +41064,N,N,N,N,39145,N,35688,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36349,35774, +40921,N,N,N,N,N,N,N,35563,N,N,40919,35690,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40028,N, +35761,N,N,N,N,N,N,N,N,64350,N,34672,N,N,N,N,N,N,N,40435,N,N,N,N,N,N,N,41168,N, +N,N,64614,N,N,N,N,37609,N,N,N,N,N,N,N,N,39660,36779,64072,N,N,N,N,36421,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40047,N,36188,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40670,N,N,N,N,N,N,35311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,38633,N,N,N,N,N,N,N,N,N,N,40635,N,N,N,N,38110,N,40632,N,N,N,38842,64357,N, +N,N,38358,N,N,N,40123,N,N,38874,N,N,N,N,36677,N,64381,37208,65124,N,38998, +39757,N,N,N,N,N,N,N,N,N,N,37723,38343,N,38887,N,N,N,N,N,N,37721,N,N,N,37365, +38840,N,N,64930,64438,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37626,37719,N,35750,N,N,N,N, +64441,N,38832,N,N,64964,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40097,N,N,N,N,N,37362, +37369,N,36849,N,N,N,N,N,N,38725,38995,N,N,65144,N,64449,37457,N,N,N,N,N,N, +40365,N,N,N,N,N,64876,N,N,64107,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,39874,N,N,N,N,N,N,N,N,N,N,N,N,39547,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35680,N,N,N,N,N,N,N,N,37707, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39613,N,N,N,N,37303,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36171,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,38324,N,N,N,N,N,65221,N,N,40688,36196,N,N,N,N,N,N,N,N,N, +37481,N,N,N,N,N,N,36199,N,N,N,N,N,N,N,N,N,N,N,N,64490,N,N,N,N,N,N,N,N,64495,N, +36200,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,37867,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64578,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37222,N,N,N,N,N,N,N,N, +64205,N,N,N,N,37853,N,N,36178,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,35788,36205,N,N,N,N,N,N,N,N,N,N,N,36206,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,38568,N,N,N,N,N,N,N,N,N,N,64678,N,N,N,N,N,N,N,N,N,N,N, +N,36207,N,N,N,N,N,N,N,N,N,N,N,N,N,36208,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64612,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36083,N,N,N,N,N,N,N,36960,N, +N,N,N,N,N,N,N,36212,38851,N,N,N,N,N,N,N,35536,N,N,N,N,N,N,37492,N,39870,N,N,N, +N,N,40136,N,N,40122,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36216,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40633,N,N,N,N,N,38234, +N,N,37300,N,N,N,N,N,N,35400,N,N,N,N,N,N,N,N,N,N,N,36221,N,N,35453,N,N,35522, +64842,N,36257,N,N,35537,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64692,35655,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37796,40666,N,N,N,N,N,N,N,N,N,35409,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36262,N,N,N,N,N,N,40645,N,N,N,N,64708,N,N,N,N,41080,N, +38069,N,N,N,N,N,N,N,64706,35435,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36267,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64232,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36269,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64585,N,37825,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36975,N,36272,N,N,N,N,N,N,N,N,38014,37114,N,N,N,N,N,N,N,N,N,N, +38009,N,N,N,N,N,N,N,N,36274,N,N,N,N,N,N,N,N,64750,N,N,N,N,N,N,N,N,N,N,N,N,N, +39291,N,N,N,N,N,N,N,N,36276,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36279,N, +N,N,N,N,N,N,37299,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36283,36282,N,N,N,N,N,N,N,N, +36284,36932,N,N,N,64844,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34635,37860,N, +N,37856,N,N,N,N,N,N,N,64851,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,36291,N,39864,N,N,N,64496,N,37865,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37878, +N,N,N,N,N,36293,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36298,N,N,N,N,N,36300,64861,37813, +64865,N,N,N,40184,N,N,N,37458,N,N,41192,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40101,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35926,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,36310,N,38848,N,N,N,41182,N,N,N,N,38866,N,N,N,N,N,64165,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,64931,N,N,N,36315,36074,36527,N,N,N,N,N,N,N,N,N,37301,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64841,N,N,N,N,N,N,N,N,64977,N,N,N,N,N,N,N, +N,N,N,36331,N,N,N,N,N,38854,N,64974,N,N,37116,N,N,N,N,N,N,N,N,N,N,N,N,N,64601, +N,N,38614,N,N,N,N,N,N,38853,36335,N,N,N,N,38871,N,N,N,N,N,36336,N,N,N,N,N,N,N, +38566,N,N,N,N,N,N,N,64447,N,N,36063,N,36339,N,N,N,N,37961,N,36341,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,39026,N,N,N,N,N,N,N,36459,N,N,N,N,N,N,64253,N,N,N,N, +N,N,N,N,N,N,36688,N,N,N,N,N,N,40396,64613,N,35908,N,N,39278,38049,N,N,N,N,N, +36707,N,N,N,N,N,N,N,41178,N,N,N,N,N,N,N,N,N,N,N,37459,65001,N,N,40373,N,N,N,N, +N,N,N,39033,34666,N,N,40285,N,N,N,N,36195,38505,40816,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64618,N,N,35527,N,N,N,N,35287,N,N,N,N,N,N,N,N,N,N,N,N,65101,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40669,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,65275,39100,64204,N,N,38320,N,N,N,37988,N,N,N,N,N,N,37743,N,N,N,N,N,N, +38073,N,N,38380,N,N,N,N,37358,N,N,39107,N,38390,N,N,N,36861,39109,N,N,N,N, +38758,65134,N,N,38877,36010,N,N,37586,N,N,38753,39115,N,N,N,N,38384,N,38749,N, +37347,N,N,N,N,39116,N,N,37993,39117,N,N,N,N,N,39118,N,38396,N,N,38051,38498,N, +N,N,65206,N,37987,36167,N,N,N,N,N,N,39120,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39121,N,N,N,N,38005,64224,N,N,N,N,N,N,N,N,N,38002,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39126,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,35568,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39129,N,N,N,N,N,N,N,36186,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,39131,N,N,N,N,39133,N,N,N,N,N,N,N,N,39080,N,N,N,N,N,N,N,35437,N,N,N,N,N, +N,N,N,N,N,N,35579,35502,64457,N,N,N,N,35933,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39140,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39142,N,N,N,N, +N,N,N,N,N,N,N,39144,N,N,N,N,N,N,N,N,N,N,N,N,N,35405,N,N,N,37463,N,N,N,N,N,N,N, +N,N,N,38367,N,N,41132,N,N,N,N,39147,N,N,N,N,39148,N,36035,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39156,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35512,N,N,N,40679,N,N,N,N, +N,N,N,N,38076,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64721,N,N,N,N,N,N,40134,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36170,N,40574,36164,39166,65000,N,N,N,N, +39232,N,N,N,N,38089,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,38099,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39238,N,N,N,N,37056,N,38097,N,N,N, +N,N,N,N,N,N,N,N,N,N,36174,N,N,38259,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37826,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39240,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39243,N,N,N,N,N,36437,N,N,N,N,39246,N,N,N,N,N,N,N,N,N, +N,N,36606,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36191,N,36441,N,N,N,N,N,N,N,N,N, +38124,38127,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35936,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36724,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,39253,N,N,N,N,N,N,N,N,N,38212,N,N,N,N,N,N,N,N,N,N,N,36043, +N,N,N,39254,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39257,N,N,N,N,N,N,N,39259,N,N,N, +N,N,N,N,N,N,N,N,N,N,36036,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64069,N,N,N, +37047,N,N,38723,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38349,N,N,N,N,N,N,38857,64848, +36537,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38342,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39271,N,N, +36067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35513,N,N, +N,N,N,N,36348,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35446,N,N,N,N,N, +40273,N,N,N,N,N,N,N,N,N,N,N,N,N,39283,N,N,34624,N,40271,39290,38244,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39329,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39333,N,N,N,N,N, +N,N,39335,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36589,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39341,N,51326,N,N,N,N,N,N, +N,N,N,N,N,N,N,37998,36720,N,64208,N,N,N,N,N,N,N,N,N,N,N,N,N,39347,N,N,N,N,N,N, +41043,N,N,N,N,N,36190,N,N,38492,N,N,36064,N,64890,N,N,N,N,N,N,N,N,38910,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37565,36189,38909,N,N,N,N,36708,N,N,N,N,64759,38242, +38861,40548,N,N,N,N,N,N,N,37452,36553,39356,N,N,N,N,40357,N,36692,N,N,N,N,N,N, +N,N,N,N,36732,N,N,N,N,36181,N,36514,N,N,N,N,N,N,N,N,N,36730,N,N,N,N,N,N,38830, +N,N,N,N,38600,N,N,36068,N,N,N,N,39363,N,37078,N,40126,N,N,N,36726,N,N,N,N,N,N, +N,N,N,N,N,N,N,38000,64331,N,N,64970,N,N,36079,N,N,N,36551,N,N,N,N,36180,41209, +N,N,N,N,N,N,N,36777,N,N,36177,N,N,N,N,N,N,N,N,N,39367,34628,N,N,N,N,N,N,N,N,N, +N,N,N,37079,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +34627,N,N,N,N,N,N,N,N,N,N,N,N,34631,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34648,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40671, +36185,34626,N,N,39374,N,N,N,N,N,N,N,N,36794,N,N,N,N,N,36843,N,39375,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36802,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37577,N,N,N,N,N,38876,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34653,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,36165,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38323,40057,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38322,N, +36172,36827,N,N,N,N,39907,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,34636,N,N,N,N,N,N,N,N,N,N,N,N,N,34637,N,N,N,N,N,N,N,N,N,40570,34647,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,39918,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39390,N,N,N, +N,N,N,N,N,N,N,N,N,N,64250,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35410,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,39393,N,N,N,N,N,N,35431,35765,N,N,N,N,N,N,N,N,N,N,35500,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39401,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64458,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38878,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38353,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,39413,64586,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,39849,N,N,N,N,N,N,N,N,N,N,N,N,64476,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,65110,N,N,N,N,N,40612,N,N,N,N,N,N,40265,38363,N,N,N,N,N,N,N,N,N,N,35269, +N,N,N,N,N,N,N,N,N,N,N,N,39416,N,N,N,N,N,N,38500,N,N,N,N,36949,N,N,38612,N,N,N, +N,N,N,N,38780,N,N,N,N,N,N,38477,N,38881,N,N,N,N,N,N,39496,N,N,N,N,N,N,N,N,N,N, +N,39497,N,65149,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37034,N,N,N,N,39504,N,N,N,N, +N,N,N,37703,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36568,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37065,N,N,N,N,N,39509,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37052,N,N,N,N,N,39512,N,35768,37077,N,N,N,N,N,N,N,N,N,N,N,N,N,38465,N,N, +N,N,N,N,39514,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39516,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,38850,N,N,N,N,N,N,N,N,N,N,N,N,N,34652,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35515,N,N,N,39850,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37109,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39520,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,37189,35928,N,N,N,N,N,N,N,N,39523,N,N,N,N,N,N,35913,N,N,N,N,N,N,N,N, +N,N,N,35766,N,N,N,N,N,N,N,N,N,N,64719,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38507, +39534,N,37199,N,N,N,N,N,N,N,N,38726,N,N,41190,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37591,N,38517,N,N,37844,N,N,37307,38521,N,N,N,N,N,39536,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38520,37325,N,40010,41071,N,N,41066,N, +N,N,N,N,N,37215,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,34625,N,N,N,N,N,N,N,N,40869,N,N,35258,N,34639,N,N,N,N,N,N,34638,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,34645,N,N,N,40653,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39545,N,N,N,N,N,N,N,N,N,36082,N,N,N,36183,N,40398,N,N,N,36050,N,N,N,34649,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40307,N,N,N,N,N,N,N,N, +N,38585,N,38588,N,N,N,N,N,N,40145,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35255,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40686,34633,N,N,N,N,N,N,N,N,N,N, +64323,34651,N,40649,N,N,N,N,N,N,64467,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37294,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36184,34630,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36182,N,N,N,N,N,N,N, +40312,N,N,N,N,N,N,N,N,N,N,40315,40627,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40626,N,40406,N,N,N,N,39247,N,N,35278,N,N,N,35776,N,40900,N,35796,N,N,35954, +N,N,N,N,N,N,50879,35833,N,N,N,N,N,35142,N,50880,N,N,N,N,N,N,N,N,N,64229,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,51323,35782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40023,N,N,N, +N,N,N,N,N,N,N,N,N,N,39675,N,N,N,N,N,N,N,35280,35279,N,N,N,50881,N,35281,N, +35298,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37502,N,40378,N,N,N,N,N,50882,N,N,35951,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64504,N,N,N,35783,37483,N,N,35282,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40911,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40361,35283,N,N,39394,N,N,N,N,N,N,N,N,N,37479,37540,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,35955,N,N,35150,N,N,N,N,N,N,N,N,N,N,N,N,N,35151,37496,N,N,N,N,N,N, +N,N,37302,N,N,N,N,35284,N,40914,N,N,N,N,N,N,N,N,37543,N,N,38306,N,N,N,N,N, +37486,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,38634,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37487,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37539,N,N,N,N,N,35152,N,N,64087,N,N,N,N,39014,N, +N,N,36088,N,N,N,N,N,N,N,N,35286,N,N,N,N,N,N,N,N,N,N,39090,N,N,N,37547,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38622,37548,N,N,N,N,N,N,N,N,N,N,35952,N, +40814,N,N,N,N,N,N,36594,N,N,N,40812,35288,N,N,N,N,64089,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37544,N,N,N,N,N,37219,N,N, +N,N,N,N,35904,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40819,N, +37549,N,N,N,N,N,N,N,N,N,N,N,N,N,39913,N,N,N,N,N,37545,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,37546,N,N,N,N,N,N,35289,N,N,N,N,N,N,N,64854,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40872,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35953, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37537,N,N,37091,N,N,N,N,N,N,N,N,41126,N,N,N,N, +N,38059,N,64626,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38852,N,N,N,N,N,N,N,37550, +64103,N,N,N,N,N,N,N,N,N,N,N,37538,64105,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,37480,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35153,N,N,N,N,N,N,N,N,N,64111,N,N,N,N,N,N,N,N,N, +64113,N,N,N,N,N,N,N,N,N,35154,N,N,N,N,37978,N,N,N,N,N,N,N,N,50883,N,N,N,35293, +N,51362,N,N,N,N,N,N,N,N,N,N,N,N,N,50884,N,N,N,40530,N,35155,N,N,N,N,N,N,N,N,N, +N,40533,37562,N,N,50885,N,N,35931,N,N,N,64125,64168,39528,64071,N,N,64126,N,N, +N,N,N,N,N,N,N,N,37563,N,N,N,64950,N,64162,N,N,N,N,N,64163,N,64164,39860,64166, +N,N,N,N,N,N,N,35295,N,N,N,64987,N,N,64169,N,35156,N,N,N,N,N,N,N,N,64171,N,N,N, +N,N,N,64634,N,N,N,N,N,N,N,35296,N,40783,51325,N,N,35297,N,N,N,N,N,64176,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40909,41191,N,N,N,N,N,64177,35238,N,N,N,N,N,N, +N,N,N,N,N,N,40698,N,N,N,N,N,N,N,64178,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64180,N,37572,N,N,N,N,N,N,40815,N,N,N,N,N,N,N,35760,N,N,N,N,N,N,N, +N,N,N,40876,N,N,N,N,N,35299,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39891, +35300,N,N,N,64181,N,N,N,N,N,40917,N,N,N,N,N,N,35157,N,N,37573,N,N,N,35158,N,N, +N,N,N,N,N,N,N,N,N,N,64179,N,N,N,64182,N,N,N,N,N,N,N,N,N,N,N,64183,N,N,N,N,N,N, +40668,N,N,N,64452,40817,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64186,37575,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,50886,39500,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35944,N,N,35301,N,N,N,N,40829,N,N,N,N,N, +41129,64196,N,N,N,N,50887,N,N,35159,N,N,N,N,N,N,64170,N,N,N,N,N,N,N,N,N,N,N, +35160,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35811,N,35681,N,N,N,N,39665,N,N,40631,N, +50888,N,N,N,64209,N,N,N,N,N,N,64210,N,N,N,N,N,N,N,N,40634,64212,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64217,N,N,N,N,N,N,N,N,N,N,N,N,64219,N,40160,N,N,N, +64503,N,64506,35303,41082,64220,N,N,64221,N,35305,N,N,N,N,N,50889,N,N,N,N,N,N, +N,N,N,N,64226,35307,N,N,64227,N,N,N,N,N,N,37064,N,N,N,37594,35161,40181,N,N,N, +N,N,35162,64231,40866,N,N,N,N,N,64234,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64237,36781,N,N,N,N,N,N,64345,64239,38639,N,40428,N,N,N,40394,N,N,N,N,N,N, +64877,N,35308,N,N,N,N,N,N,N,N,N,N,N,64324,N,N,40418,N,35957,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40640,N,40534,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40825,39623,N,N,64244,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,39073,N,N,N,N,N,N,N,N,N,64248,N,N,N,35312,40519,N,N,40439,N,N,N,N,40915, +N,39626,N,N,N,N,35313,64249,N,N,N,N,N,N,N,N,N,N,N,N,N,36442,N,35314,N,N,N,N, +35315,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37469,35665,37600,N,N,35316,N,N,N,N,N, +N,N,N,N,40916,N,N,N,N,N,N,N,N,35449,N,N,N,N,N,N,N,N,N,N,N,35317,38823,N,N,N,N, +N,N,N,N,N,N,37818,N,N,N,N,N,40536,N,N,N,N,35318,N,N,N,N,N,40535,N,N,N,N,35319, +N,35393,N,N,35320,N,N,64241,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35322,N,N,N, +N,N,N,N,64322,N,64191,N,N,N,N,N,N,N,N,N,64419,N,N,N,N,N,N,N,N,N,64247,N,N,N,N, +N,N,N,N,N,N,N,40526,N,38108,N,N,N,N,N,38362,40440,40810,N,N,N,N,N,35511,N,N,N, +N,N,N,N,N,N,N,N,N,64326,N,N,N,N,N,N,N,N,N,35398,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64327,N,N,N,N,N,N,37192,N,N,N,37598,N,N,N,N,35667,40438,N, +39898,N,N,N,N,40318,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35325,39396,N,N, +N,N,N,40515,N,N,N,N,N,N,N,N,N,N,N,40425,N,36690,N,N,N,40437,40432,N,N,N,39399, +N,N,N,N,N,35773,40431,N,N,N,N,N,N,N,N,N,N,N,40887,N,N,N,N,N,N,N,N,N,N,N,N, +40400,N,40939,36265,40399,39137,N,40421,N,N,N,N,N,N,N,40392,N,N,N,N,N,N,N,N,N, +64335,N,N,N,N,N,N,N,N,N,N,N,40427,N,N,N,N,N,N,N,N,N,64340,N,64341,39586,N, +35542,N,39519,N,N,N,N,N,N,N,N,40693,N,N,N,36791,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,39634,40554,40680,N,N,N,N,N,N,N,N,N,N,N,N,35775,37314,40290, +N,N,N,N,N,N,37472,N,N,N,N,N,N,N,N,N,N,N,37470,37313,N,35525,N,N,38819,N,N,N,N, +N,N,N,N,N,N,35692,N,36222,N,N,N,N,N,N,N,40020,N,N,N,N,N,40381,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,40133,N,N,N,N,N,N,N,N,N,N,N,35163,N,N,N,N,N,N,N,N, +N,N,64348,N,64347,N,64343,N,N,N,N,N,N,N,N,N,34661,N,39111,64346,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40174,N,N,N,N,N,N,N,37602,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,38055,N,N,N,N,N,N,N,N,N,N,36044,N,39892,N,N,64356,64374,N,N, +64352,N,N,N,N,N,N,N,N,N,N,N,N,N,39397,N,N,39618,N,N,N,37371,N,N,N,41075,N,N,N, +N,N,N,N,40818,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40908,N,N,N,39077,37608,N,N, +N,N,N,N,N,N,39868,N,38643,N,N,37607,N,N,64615,N,N,N,N,N,N,N,N,N,N,N,35709,N,N, +N,N,39924,N,N,N,N,N,40695,N,N,40641,N,N,N,N,N,N,N,N,N,39279,N,N,N,N,N,N,38641, +N,N,36417,N,N,N,N,N,38218,N,N,N,38886,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38645,N,N,N, +N,N,37606,40770,N,N,N,N,N,N,N,64359,N,N,N,N,N,N,N,N,39337,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,64230,64361,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38885,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,38525,N,N,N,64364,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39330,N,N,N,N,N, +39611,N,N,N,39525,N,N,37966,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64366,N,N, +39391,N,N,N,N,N,N,N,N,N,39139,N,N,37460,N,N,N,N,N,38523,35503,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35959,N,N,N,N,N,N,35759,40637,N,N, +N,N,N,N,N,N,N,N,N,N,40678,N,N,64367,N,N,N,N,N,36577,N,N,N,N,39805,40062,N,N,N, +N,63961,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37610,N,N,N,N,35960,N,N,N,N,N,N,N,N,N,N, +N,64370,N,N,N,64369,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35164,N,39152,38642,N,N,N,N, +N,N,N,64372,35777,N,35165,35294,N,35166,N,N,50890,N,N,N,N,N,N,65090,N,N,N,N,N, +N,N,N,N,N,N,34664,N,64379,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35167,N,35168,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39885,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40403,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,38988,N,N,N,N,N,N,N,N,N,N,38738,N,N,N,N,N,38339,N,N,N,N, +39862,N,N,N,N,N,N,N,N,N,N,N,N,39609,N,N,N,38835,N,N,N,N,N,N,40820,37617,N,N,N, +N,N,N,36090,N,N,N,N,38879,N,N,N,N,64422,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64427,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39031,N,N,N,38996,38341,N,N,N,N,N,N,N,40277, +64434,38270,N,N,N,N,N,N,N,N,38722,N,38118,N,N,N,N,37621,N,N,N,N,N,N,N,36037,N, +N,N,N,N,N,37629,N,N,64418,N,N,40017,N,N,38121,39004,37616,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,37964,N,N,N,N,N,N,N,37227,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35704,N,N,N, +N,38114,N,N,N,N,N,N,N,38991,N,64437,N,N,N,N,37489,N,N,37733,N,N,39003,N,N, +38992,N,N,N,N,N,N,N,38844,N,N,N,N,37619,N,N,37696,38989,N,N,N,38258,N,65007,N, +N,N,N,N,N,N,N,64961,N,N,N,N,64442,N,N,37611,N,N,N,N,N,N,64627,38839,N,N,34671, +N,N,N,N,N,N,64436,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37031,N,N,N,N, +N,N,N,N,N,N,38721,37620,N,34674,N,64444,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38263, +N,N,N,N,N,N,N,N,N,N,N,40674,N,36728,N,N,N,N,N,N,N,63964,N,N,N,38514,40629,N,N, +N,38475,N,N,N,36012,N,N,N,N,N,N,N,N,N,41210,N,N,N,N,N,N,N,N,N,N,N,38261,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37082,N,N,37735,N,65188,N,N,N,37087,N,N,N, +N,37716,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35169,N,35764,N,N,N,N, +40384,N,N,N,N,N,N,36424,N,64453,N,N,N,N,N,64455,N,N,N,50891,N,64121,N,N,N,N,N, +N,N,N,N,N,N,N,N,40551,N,N,N,N,N,36057,N,N,N,N,N,N,64466,35170,35171,N,N,N,N,N, +N,N,N,N,N,64637,N,N,N,N,N,N,N,N,N,N,N,N,34675,N,N,N,N,N,N,N,N,N,N,N,40811,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64460,N,65198,N,N,N,34669,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64465,N,N,N,N,N,N,N,N,N,N,N,64373,64468,N,N,N,N,N,N,N, +N,N,N,N,N,N,64470,64472,N,N,N,N,N,N,N,35677,N,37708,N,39650,N,N,35785,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64475,40905, +N,N,N,N,N,N,N,N,40772,N,N,N,N,N,N,N,N,N,N,39149,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,36073,N,N,N,N,N,N,N,N,N,N,N,N,64477,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,36338,35172,N,65010,N,37709,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,64487,N,N,N,N,N,N,41202,39016,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40792,N,N,N,36070,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36211,N,N,N,64478,N,N,N,N,N, +64479,N,N,N,N,N,35912,N,N,N,N,N,N,34676,64483,N,N,N,N,36264,N,N,64484,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40053,N,N,39032,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36192,N,N,N,N,N,N,N,64485,N,36193,N,N,N,N,N,N,N,N,N,N,N,N,N,36194,41121,N,N,N, +40000,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39085,N,N,N,40682,N,N,N,36076,N, +N,36052,N,N,N,N,N,N,N,N,N,40171,N,N,N,N,N,64480,N,N,40785,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36197,N,N,N,N,N,N,40177,N,N,N,N,N,N,N,N,N,N,64600,N,N, +36198,N,N,N,N,N,N,N,38484,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64488,N,N, +N,50892,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40910,64508,N,39652, +N,N,N,N,N,N,40821,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64497, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36201,N,N,N,N,N,37711,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37710,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,64500,N,N,N,N,50894,N,N,N,64451,N,N,35173,N,N,N,N,N,N,N,N,N,N,N,35962,N, +N,N,N,N,N,35963,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,36202,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37715,N,N,40443,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64509,N,N,N,36953,64576,N, +64577,64579,37729,64582,37730,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36203,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64588,36094,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,38328,N,N,50896,35786,N,N,N,N,N,N,N,N,N,N,39034,N,N,N,N,50897,N, +64593,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64596,N,N,N,N,N,N,N,N,64175,N,N,N,N,N,N,N, +36204,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64097,N, +N,64599,N,N,N,N,N,N,N,N,N,39792,N,N,N,N,N,N,N,N,41041,N,N,N,N,N,N,N,35964,N, +35787,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37742,N,N,N,64725,64681,N,N, +N,N,N,N,N,N,N,N,N,N,N,64609,N,N,N,N,N,N,N,N,N,35174,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64203,N,N,N,N,N,N,N,63962,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,37754,N,41184,N,N,N,N,N,N,37739,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64619,N,N,N,N,N,41180,N,N,37992,N,N,N,N,N,N, +N,N,N,N,N,64621,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,36209,N,N,N,N,N,N,64868,N,N,N,N,39354,N,N,N,39632,39521,41189,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41051,38572,N,N,N,N,38720,N,N,N,N,N,N,N,N,N,N,N, +N,40689,N,N,N,N,N,N,N,N,35917,N,N,N,N,N,N,N,N,N,N,N,N,N,40830,N,N,N,N,N,N,N,N, +N,N,N,N,36210,N,N,N,N,64630,N,N,N,N,N,N,N,N,N,N,N,N,N,38569,N,N,N,N,N,N,N,N, +41070,N,N,64682,N,N,N,64461,N,N,N,64628,N,N,N,N,N,N,N,N,N,N,41076,N,N,N,N,N,N, +N,N,N,N,N,N,N,41073,N,N,N,64633,N,N,N,N,N,64636,N,N,N,N,N,N,N,N,N,N,N,N,N, +40016,N,N,37753,37752,N,N,41181,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36213,N,36214,N,N,N,N,N,N,37748,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36215,64677, +N,N,64674,N,N,N,N,N,N,37059,N,N,N,N,N,N,N,41081,36217,N,N,N,N,N,N,N,N,N,N, +35836,N,41078,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35789,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40794,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40948,N,N,40890,N,N,N,N,N,N,N,N,N,N,36218,N,N,N,N,N,N,N,N,N,N,N,N, +40517,N,N,N,N,N,N,37808,N,41077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39750,N,64686,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64688,N,N,N,N,N,N,N,N,N, +64081,N,N,N,N,N,36219,36220,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40662,N, +N,37804,N,N,N,40795,N,37801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41084,N,N,N,N,N,N,N,64690,N,N,N,N,N,N,N, +N,N,N,N,N,35521,N,N,N,N,N,40884,N,N,N,N,N,N,N,N,N,N,N,64684,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40524, +N,N,N,N,N,N,N,36805,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37805,N,N,N,N,N,N,N,N,N,N,N, +N,40387,N,N,N,36258,N,N,N,40266,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64694,N,N, +36259,40523,N,40525,36260,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35581,N,N,N,N,N,64693,N,64707,37810,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36261,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37793,N,N,N,N,N,N,N,N,N,N,35526,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,35419,N,N,N,35149,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,65236,N,N,N,N,35448,N,37803,N,N,N,N,N,N,N,N,N,36263,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40773,N,N,N,N,N,N,N,N,N,35414,N,N,N,64703,N,N,N,64704,N,36582, +N,N,35492,35139,N,N,N,N,N,N,37875,N,N,N,N,N,N,N,N,N,N,N,N,64683,40610,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40391,N,N,N,50898,35790,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,64709,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64715,N,N,N,N,N,N,N,N, +N,N,N,37811,N,64714,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64713,36268, +N,64454,35175,N,35966,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64717,N,N,N,N,N,N,N,N,40179,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64720,N,N,38331,N,N,N,N,N,N,N,N,N,N,N,64723,N,N,64724,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36270,64727,N,N,N,N,N,37851,N,N,N,N, +65123,N,N,N,N,N,N,N,N,N,N,N,N,37845,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64730,N,N,N,39793,N,N,64733,N,34660,N,N,N,N,N,36271,N,N,N,64242,N,N,N,N,N,N,N, +N,N,N,N,37848,N,N,N,64735,N,N,N,37843,N,N,N,N,N,N,N,64737,N,N,N,N,N,N,N,N,N, +36470,N,N,N,N,N,N,N,64610,N,N,N,N,N,N,N,N,37841,N,N,N,36273,N,N,N,N,N,N,N, +39001,N,N,N,N,N,N,N,N,N,64338,N,N,N,N,N,N,N,N,64339,N,N,N,N,N,64333,N,N,40127, +N,N,N,N,N,N,N,N,39794,N,N,N,N,N,N,N,N,N,N,N,N,N,64336,37822,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36059,N,N,N,N,N,N,N,N,N,40433,64747,N,N,N,N,N,N, +N,N,N,41147,N,39806,N,N,N,N,N,N,N,36275,N,N,35922,N,N,N,N,39656,N,N,N,N,N,N, +36572,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40185,N,N,N,N,N,N,N,N,N,N,N,N,N,64080,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39143,64755,N,N,N,N, +64754,N,N,N,36042,N,N,34677,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,37861,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39513,N,N,N,36277,N,N,N,N, +N,N,N,64845,N,N,N,N,64862,N,N,N,N,N,N,N,N,N,N,N,N,N,36733,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,38215,64758,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37456,N,N,N,N,35176,36278,64763,41085,39164,35177,N,N, +N,N,N,N,N,N,65103,N,N,37462,N,N,N,N,N,N,N,N,N,N,64201,N,N,37864,N,N,N,64760,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40163,64937,N,N,N,N,N,N,64580,N,N,N,N,N,N, +N,N,38464,N,N,36280,N,N,N,N,N,N,N,N,N,N,39754,36793,N,N,N,N,N,N,64766,N,N,N,N, +N,N,N,35178,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36281, +N,N,N,37246,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37876,N,N,N,N,N,N,N,N,N,N,N,N,N, +64380,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37863,N,N,38895,N,N,N,65098,N,N,N,N,N, +64837,N,38565,N,N,N,N,65248,64840,64839,65266,65130,N,N,N,N,N,36285,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,39841,36002,39607,36604,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40865,N,N,N,N,N,N,N,N,N,64849,N,N,N,N,N,N,N,64173,N,N,N,N,36286,N,N,35236,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39641,N,N,N,N,N,N,N,N,N,N,N,64846,N,N,36288,N,N,38896, +N,N,N,N,N,N,N,N,N,N,37812,64836,N,N,N,N,N,N,N,N,N,N,N,N,40871,N,N,N,N,36290,N, +N,N,N,39350,N,N,N,N,N,N,N,N,N,N,N,N,N,64850,N,N,N,N,N,N,36289,N,N,36422,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,41169,N,N,N,N,N,N,N,N,N,N,N,N,N,40906,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,37583,N,N,N,40180,36292,N,N,N,N,N,N,N,N,N,N,64833,N,N,N,N,N,N, +N,39756,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64855,64751,40158,N,N,N,N,N,N,N,64834, +39020,N,N,N,N,N,N,N,N,N,N,N,N,N,38905,N,38232,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39006,65147,38093,N,N,N,N,N,37870,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36003,N,64858, +N,N,N,N,N,N,37877,N,N,N,N,N,37871,36586,N,N,N,36699,N,N,N,N,N,N,N,N,N,N,N, +35934,N,36294,N,N,N,N,N,N,N,N,N,N,N,36296,N,N,36295,N,N,N,N,N,37879,N,N,N,N,N, +N,N,36297,N,N,N,N,N,N,N,64498,N,N,N,N,38512,N,N,N,N,N,N,N,N,N,36299,N,N,N, +64860,N,N,N,N,N,N,N,N,N,36709,N,N,N,36301,N,N,N,N,N,40360,38137,N,N,36302,N,N, +N,N,N,N,N,N,37866,N,N,N,N,N,N,N,N,N,64863,37872,40886,N,N,N,N,N,N,N,N,N,36303, +N,N,N,38755,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36304, +37873,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64866,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64869,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40923,N,N,N,N,37880,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35831,N,N,N,N,64870,N,N,N,N,N,35791,N,N,N,N,N,N,36305,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36306,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64881,N,N,N,N,64879,N,N,N,N,N,N,N,N,36307,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40935,37053,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40912,N,N,N,35792,N,64882, +N,40110,35793,N,N,35547,N,N,N,N,N,N,N,N,N,N,N,64228,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,38350,N,64886,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64354,N,N,N,N,N,N,36308, +N,N,N,64888,N,N,N,N,N,36579,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36982,N,N,39110,N,N,N,N,N,N,N,36309,N,N,N,N,38865,N,N,40630,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64199,N,N,41026,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,39027,N,N,N,N,N,N,N,N,N,N,40956,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36005,36311,N,N,37627,36312,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,37967,N,36313,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,35179,N,N,N,N,N,N,N,N,38862,N,N,N,64243,64942,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64431,37559,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36314,N,N,N,N,N,N,N,N,N,N,N,N,N,40026,N,N,N,N,N,N,64941,N,N,N,N,N,N,N,N,N,N,N, +N,N,36316,37956,N,N,N,N,N,N,N,N,N,N,N,36317,N,N,N,N,N,N,N,41174,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35905,38869,N,37962,N,N,N,N,N, +37965,N,N,N,N,38859,N,N,N,N,N,36318,N,N,36319,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36320,65273,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,64960,64761,N,N,N,N,N,N,36061,N,64382,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37555,N,N,N,N,N,64943,N,N,N,N,N,N,N,N,N,36321,N,N,N,N, +38355,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35265,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64872,N,N,40119,N,N,36323,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,64192,36325,64100,N,35143,N,N,N,N,36324,N,N,N,N,N,36327, +36328,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64967,64944,N,N,N,N,N,N,37957,38870,N,N, +N,N,N,N,N,N,N,64710,38980,N,N,N,N,N,N,N,N,N,N,N,N,36329,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,36330,N,N,N,N,N,N,N,N,65104,N,N,N,N,N,N,64972,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40359,N,N,N,N,N,64973,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64975,N,N,N,N,38354,N,N,N,N,N,N,N,36333,N,N,N,N,N,N,N,N,64698,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,64965,N,64978,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40156,N,N,N,N,N,38351,N,N,36334,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64980, +N,N,N,N,N,38636,38635,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37046,N,64963,39083,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38638, +N,N,N,N,N,N,N,N,N,N,N,N,N,36340,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64992,N,35943,N,N,36342,N,N,N,36343,N,N,N,N,N,N,N,36858,N,N,N,N, +N,N,N,N,N,N,38864,N,N,N,N,35794,N,N,36344,N,N,N,N,N,37081,N,35911,N,64240,N,N, +N,N,64993,36345,N,64995,N,N,N,N,N,N,N,36346,N,64355,N,N,N,37030,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,39280,N,N,37355,N,38768,39023,64994,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39154,N,39676,35180,65021,N,N,39262,N,N,N,38333,N,N,N,N,N,N,N,64996, +N,N,N,37350,N,N,N,N,64997,64998,N,N,N,N,N,N,N,N,64999,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,37972,N,N,N,39352,N,N,N,N,N,N,N,N,38889,37702,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39011,N,N,N,N,N,N,N,N,N,N,N,38332,N,65005,65015,N,N,N, +N,N,N,39024,38646,36521,N,N,N,N,N,37969,N,N,36419,N,35674,N,N,N,N,65006,N,N,N, +N,65008,N,N,N,N,65012,N,39925,N,N,N,N,N,36078,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,38782,N,N,N,N,N,39893,N,39619,N,38856,41179,37328,N,N,40932,N,36829,N, +37353,N,N,N,N,N,N,N,N,N,39136,N,N,N,37578,N,38999,N,N,35921,N,N,N,N,65003,N, +39753,N,N,N,N,N,N,N,N,N,40310,40623,N,N,N,N,N,N,N,N,N,40140,N,N,N,N,N,N,65002, +N,N,36337,N,N,65019,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36435,N,N,N,N, +N,N,N,N,N,N,N,64207,N,N,N,N,N,N,N,N,N,N,N,N,N,38649,N,N,N,N,N,N,N,N,N,39103, +40521,36007,N,N,N,N,N,N,N,N,39882,N,N,N,N,65022,37596,N,N,N,N,N,65089,37324, +37346,N,N,N,N,N,N,N,N,N,N,N,N,65092,34655,N,N,N,N,N,35795,N,N,65095,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,65096,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37973,N,N,N,N, +65099,N,65100,N,N,N,N,36287,N,N,N,N,N,N,N,N,N,40568,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,65105,N,N,N,N,37974,N,N,N,N,N,N,N,40289,N,N,N,N, +37975,N,N,N,N,N,N,N,N,N,N,39270,N,N,N,N,N,N,N,N,N,N,N,N,N,35797,N,N,N,N,41065, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39092,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,41033,41036,N,40549,N,N,N,N,N,N,N,N,N,N,N,39093,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65112,N,39285,65107,41061,N,65113,N,N,N,N, +N,N,N,N,N,39095,39096,N,N,N,N,N,N,N,39098,N,N,N,N,N,N,39099,N,N,N,N,N,N,40892, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41034,N,N, +40647,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36009,N,N,39086,N,N,N,N,N, +N,N,N,37590,N,N,N,64225,N,37332,N,N,N,N,N,N,N,N,64222,N,N,65115,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,35923,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65118,N,N,N,N,64471,65114, +38085,N,N,N,N,64202,N,N,N,N,N,N,N,N,N,N,N,39105,38748,N,65140,N,38771,N,N,N,N, +N,N,N,N,64070,N,N,N,38756,N,N,N,65128,N,38478,N,38757,35930,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35233,38394,N,37588,65129,N,64325,N,39112,N,N,37103,N,39113,39114,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37997,38071,65132,N,N,37995,N,N,N, +N,N,N,37628,N,38379,N,65139,38766,65119,N,N,N,N,N,N,N,N,N,64957,N,N,37589,N,N, +N,N,N,N,65209,N,N,65137,34680,N,N,N,64443,N,N,38010,N,N,38395,65143,N,N,N,N,N, +N,N,65145,N,65141,N,N,N,37981,N,N,N,N,N,N,N,65148,N,N,N,N,N,N,N,N,N,37700, +36518,N,N,N,N,N,N,N,N,N,N,N,37587,N,38072,N,34681,N,N,N,N,N,N,64625,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,38750,N,N,N,N,36013,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65191,N,N, +N,37994,N,N,N,37859,N,N,39119,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41177,N,N, +N,N,N,N,N,N,41151,41037,41144,N,N,N,N,N,41166,41143,N,N,N,N,N,N,N,N,65193,N,N, +N,N,N,N,N,N,N,N,35267,N,N,N,N,65195,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40436,35181,N,N,N,N,N,40059,N,N,N,N,N,N,39122,N,N,N,40873,N,N,N,65202,N,N, +65201,N,N,N,38873,N,41156,N,38006,N,N,N,N,N,N,N,N,N,N,39288,N,N,N,N,N,N,65203, +N,N,N,N,N,39123,65204,N,N,N,39124,N,N,N,N,N,N,N,40889,N,N,N,N,N,N,N,N,38001,N, +N,N,N,N,N,N,N,N,39125,65208,N,N,N,50900,N,N,N,N,N,N,N,N,N,N,N,65210,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40540,N,N,65211,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41028,N, +N,N,N,39127,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39128,65212,N,N,N,N,40958,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65213,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40413,N,N,N,N,40673,N,N,N,N,N,N,N,N,N,N,N,N,39130, +40415,65215,N,65214,N,N,40683,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40537,41052,N, +N,N,N,N,N,N,65216,N,N,N,38007,39132,N,65217,N,N,N,39134,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,65219,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65224,N,N,N,65225,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65226,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +65227,N,N,N,N,N,N,N,N,N,40898,N,N,35947,39108,N,38064,38065,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,65233,N,N,N,N,N,41153,N,65234,N,N,N,N,41165,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,65235,N,N,39141,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65238, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37348,N,N,N,N,36807,38062,N, +35407,38066,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36820,N,N,N,N,39146, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65240,N,N,N,N,N,N,N,N,N,40416,N,N, +N,N,39150,N,N,N,N,38340,N,64744,N,N,N,N,N,39151,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,35950,N,N,N,N,N,N,N,N,64216,N,N,N,N,N,N,N,N,N,N,N,N,N,65244,N,N,N,N,N,N,N, +N,N,41134,40268,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39153,N,N,N,39155,N,38081,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39157,N,N,64079,38626,N,N,N,N, +37968,N,38562,N,N,39158,N,N,N,38629,N,N,N,N,N,39159,N,41030,38627,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39160,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40676,N,N,N, +N,N,N,63958,N,N,N,N,N,N,38083,N,N,N,N,38082,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65249,N,65257,N,N,N,N,38628,N,35244,38619,N,N, +N,N,N,N,N,N,N,N,N,N,N,65250,N,N,N,N,N,N,N,N,N,N,38084,65251,N,N,N,65255,40955, +N,N,N,N,N,N,N,N,N,N,N,35929,N,N,N,N,N,N,N,N,N,37833,N,38120,64342,N,N,N,37061, +41128,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,65253,N,N,N,39165,39163,65256,N,36543,N,N,N,N,35800,65271,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36712,38086,N,N,N,N,N,N,N,N,40426,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64617,N,N,N,N,N,N,N,N,N,N,N,N,40154,N,65267,N,N,40050, +N,N,65264,35273,N,N,N,N,N,N,N,N,N,39233,N,N,N,N,N,N,N,39234,N,N,N,65269,N, +37335,N,N,N,N,N,38092,N,N,N,65272,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,38824,N,65276,N,N,N,36062,N,64959,N,N,N,N,N,N,N,65278,N,N,N,N,N,N,N,N, +N,N,N,N,N,38609,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38101,N,N,38096,39236,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35939,N,N,41139,N,N, +N,N,N,N,N,N,N,N,N,N,38095,N,N,N,40954,N,N,N,N,37349,N,40042,N,N,N,36425,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36428,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36429,N,N,N,N,N,39539,N,N,N,N,N,N,N,N,N,N,N,N,N,39239,N, +36017,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36432,N,N,N,N,N, +N,N,N,N,N,36431,39241,N,N,N,N,N,36433,36434,N,N,N,N,39602,35237,N,N,N,N,N, +39244,N,N,N,40952,N,N,N,N,N,N,36438,39245,37322,36439,N,N,N,N,38113,N,N,N,N, +36935,N,36824,36440,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38123,36444,38227,N, +N,N,N,N,N,N,40933,N,N,N,N,N,N,N,N,N,N,40790,N,N,N,N,N,N,N,38223,N,36446,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39274,N,N,N,N,N,N,N,N,40036,40153,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,36445,N,N,N,N,N,N,N,N,N,N,N,N,39248,N,N,N,N,N,N,N,N,N,39249,N,N, +36450,N,N,N,N,N,N,N,N,N,N,N,39250,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36456,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36449,40793,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35763,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40797,36454,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36018,N,N,N,N,N,N,N,N,N,N,N, +N,N,36462,N,40804,39251,N,N,64184,N,N,N,N,N,39252,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36464,N,N,N,N,N,N,N,N,N,N,N,N,40801,N,36466,N,N,N,N,N,N, +N,N,N,N,N,N,41067,N,N,N,N,40768,N,N,N,N,N,N,38125,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,38126,N,N,40893,N,N,N,36475,N,N,N,N,N,N,39255,38135,N,40799,N,N,N,N,36467,N, +N,40802,N,N,N,N,N,N,N,38134,N,N,N,N,N,N,N,N,N,N,N,N,N,39256,N,N,N,N,N,N,N,N,N, +36469,63963,N,N,N,N,36978,N,38136,N,N,N,N,N,N,N,N,N,39258,N,N,N,N,N,N,N,N,N, +41136,36019,N,N,N,36473,N,36472,N,N,N,38131,N,N,N,N,N,39087,N,N,N,N,N,N,41138, +N,N,N,N,N,N,N,N,N,N,N,36474,N,N,N,N,N,N,39260,N,N,N,N,N,36476,N,36477,N,N,N, +35801,N,N,35234,40663,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,41142,N,N,N,N,N,N,N,N,N,N,N,N,40514,N,N,36516,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36519,N,35958,N,N,N,N,N,N,N,N,N,34663,N,38210,N,N,N,N,N,N,N,N,N,N,N,N,39037,N, +N,N,38741,N,N,36520,N,N,N,N,N,N,N,36522,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,35235,N,39264,39266,N,N,38140,39265,N,N,N,N,N,N,N,38138,N,N,N,N,N, +N,N,36526,36530,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36528,N,N,N,N,N,N,N,39267,38826, +38139,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36539,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,36060,N,N,N,N,N,N,N,N,N,39030,N,36513,N,N,N,N,36020,N, +36535,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40358,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40624, +N,N,N,36536,N,N,N,N,N,N,N,N,N,N,N,N,40304,N,N,N,N,35182,N,N,N,N,N,N,N,35183,N, +N,N,N,N,N,N,N,N,N,N,N,N,35184,N,N,N,N,N,N,N,N,N,N,N,N,35185,N,N,N,N,N,N,N, +35186,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35187,35188,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35189,N,N,N, +N,N,N,N,N,36540,36541,N,N,N,N,N,36542,N,40401,N,N,N,N,38141,N,N,N,35799,35802, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41186,N,N,N,N,N,N, +40937,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64936,N,N,N,35559,N,N,N, +36546,N,N,N,N,N,N,N,N,N,N,N,36548,N,N,N,N,N,N,N,N,N,N,39268,N,N,N,N,N,39269,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38222,N,N,N,N,N,N,N,N,N,39091,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36555,35807, +N,N,N,N,N,36558,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36559,N,N,39272,N,N,N, +N,39273,N,N,N,N,N,N,N,N,39275,36561,N,39276,N,N,N,N,N,N,N,N,N,36564,36565,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39277,N,N,N,N,N,N,41150,N,N,N,N,N, +36566,41148,41141,N,N,41140,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35253,N,N,N, +N,N,N,N,36573,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40541,39281,N,N,N,N,35246,40424,N,N, +N,N,N,N,N,N,38245,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,39282,N,N,35676,N,N,N,N,N,N,N,N,N,35249,41152,N,N,N,36575,N,38246,N,N, +39284,N,39286,N,N,N,39287,N,39289,N,N,40410,N,N,36576,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37724,N,N,N,N,N,N,N,40422,N,35679,N,N,38243,N,N,N,N,N,N,N,N,N,N,38247,N, +N,N,N,N,40419,N,N,N,N,N,N,N,N,N,N,N,N,N,39292,N,N,39293,39294,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,36091,35675,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39331,N,N,N,N,N,N,N, +39332,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39334,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39336,N,N,N,N,35518,N,N,N,N,N,N,N,N,N,N,N,40545,N,N,N,N,N,N,N,N,N,N,39338,N,N, +N,N,N,N,41160,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39339,N,N, +N,N,N,N,N,N,N,N,65220,N,N,N,N,N,N,39106,36584,N,41146,N,N,N,N,N,N,N,N,N,N,N, +64887,N,N,36590,N,N,N,40639,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35266,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39340,N,N,N,N,N,N,N,N,N,N,N,N,N,38251,N,N,38252, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39343,N,N,39242,35190,36680,N,N,N,N,N,N,N,N,N, +N,N,64494,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39342,N, +N,N,36603,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36048,N,N,N,N,35666,N,N,N,N, +N,39344,N,N,N,N,35191,36673,N,N,N,N,N,N,N,39345,N,N,N,N,N,N,N,N,N,36681,N,N,N, +N,N,N,N,N,N,N,N,64077,N,N,N,N,N,N,N,N,40420,36021,N,N,N,64489,39764,N,39346, +40552,N,N,N,N,N,N,N,N,N,N,N,N,36682,N,36674,N,N,36689,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38982,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39348,N,N,N,N,N,N,N,N,N,N,36597,64853,N,N,40141,N,N,N,N,N,N,N, +N,35192,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36691,N,N,N,N,N,N,N,N,N,N,N, +36719,N,N,N,N,N,N,N,N,N,N,36451,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36694,N,N,N,N,N, +N,N,N,N,N,N,N,65142,N,N,N,N,40902,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64172,N,N,N,N,N, +36696,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38984,39351,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,38501,N,64108,N,40423,N,N,N,40546,N,N,N,38604,36455,N,N, +64629,N,39038,N,N,N,N,N,N,N,64953,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38908,N,N,N,N, +N,N,N,N,N,39161,N,36710,N,N,N,N,N,N,N,N,38254,N,37445,N,N,36704,N,N,N,40657,N, +N,N,N,N,65229,N,39353,N,N,N,N,N,N,N,N,N,N,N,N,36706,38732,N,N,N,N,N,N,N,N,N,N, +N,N,37319,38239,N,N,N,N,N,N,N,39355,N,N,N,N,N,N,N,N,N,36461,36721,N,N,38091,N, +N,N,N,N,N,N,N,N,N,N,N,38321,N,N,N,N,N,N,N,N,N,39666,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,38595,39357,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41167,N, +N,N,36717,N,N,39358,36596,N,36722,38372,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39359,37442,N,64421,N,N,N,N,N,N,N,N,N,N,39360,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64948,36727,N,N,N,39361,N,N,N,N,N,N,N,N,N, +64185,N,N,N,N,N,N,N,N,36672,64068,N,N,N,N,N,39362,N,N,N,N,N,N,N,36700,N,N,N,N, +36029,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39364,39365,N,N,36731,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34678,N,N,N,36022,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36771,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36046,N,N,N,N,N,N,N,N,N,39366,N,N,N,N,N,N,N,N, +N,N,N,N,N,38605,N,N,N,N,N,N,N,N,N,N,N,N,N,38599,36773,N,N,N,N,N,N,N,N,N,N, +64187,N,35937,38256,N,N,N,37736,N,36734,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36778,N,N,N,N,N,N,41040,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37075,N,N,38230,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36792,N,N,N,N,N,39368,N,N,N,N,N,N,N,N,N,N,N,36783,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39369,N,N,N,N,N,N,N,N,N,N,N,N,N,38265,N,N,N,N,N,N,N,N,N,N,N,N,40777, +N,N,N,N,39370,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39371,40405,36784,N,N, +N,N,N,N,N,N,N,N,N,64122,N,N,N,N,N,N,N,N,40543,N,N,N,N,39373,41161,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39643,N,N,N,41158,N,N,N,N,N,N,N,36788,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,41175,N,N,N,N,N,N,N,N,N,N,N,N,41159,N,N,N,N,N,N,N, +41027,N,N,N,36789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36786,N,N,N,N,N,N, +41057,40542,N,N,N,N,N,N,N,N,N,N,36790,N,N,N,N,N,N,N,N,40936,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40114,N,N,N,N,N,38268,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40903, +N,N,36795,36796,N,N,N,N,N,N,N,N,36844,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36800,N, +37738,N,N,N,35812,40060,N,N,N,N,N,N,N,N,38305,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,65260,N,N,38307,N,N,N,N,N,N,N,35909,36024,N,N,N,N,N,N,N,N,N,N,N, +36801,N,N,N,41042,N,N,N,N,N,N,N,N,N,N,N,N,N,39376,N,N,N,N,N,36803,36804,N,N,N, +N,N,N,N,N,N,38308,N,N,N,N,N,36806,N,40544,N,N,N,N,N,N,N,63960,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,38309,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40115,N,N,N,N,N, +N,N,N,N,39377,65265,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,39378,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40130,N,N,N,39379,N,N,N,N,N,38311,N,N,N,N,N,N,38313,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,38310,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40029,N,N,N,N,N,N,N,N,39138,N,N, +N,N,N,N,36809,N,41154,36810,N,N,N,N,N,N,39380,N,N,41145,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39768,N,36813,N,41172,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36814,N,N, +N,N,35813,N,N,N,N,35193,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36816,38326,N,N,N,N,N,N,N,N,N,N,N,N,39382,N,38373,N,N,N,N,N,N,N,N,N, +N,N,N,39383,N,N,N,N,38325,N,N,N,N,N,N,N,N,N,N,N,41162,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40957,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,41048,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36822,N,N,N,39384,N,N,N,N,N,N,N, +36819,N,N,N,N,N,N,N,N,N,N,N,N,36837,N,N,N,N,N,36841,N,N,N,N,39385,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36087,N,N,N,N,N,N,N,N,N,N,N,N,N,37500,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40005,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36072,36830,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,36831,N,N,N,N,N,N,N,N,N,N,N,N,N,41035,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36834,N,N,N,41164,N,N,N,N,N,N,N,N,36835,36836,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39876,N,N,N,39932,N,N,N,N,N,N,38476,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,39670,N,36014,N,N,N,N,N,N,N,N,N,N,N,N,36839,N,N,N,N, +N,N,N,N,N,N,36840,N,N,N,N,35815,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,35194,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35195,39386,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36845,N,N,N,38336,N,N,N,N,N,N,N,N,N,N,N,N,N,41163,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40520,N,N,N,N,N,N,39387,N,36851, +N,N,N,N,36857,N,N,N,N,N,N,N,N,N,N,N,N,N,38337,N,41038,N,N,N,N,N,N,39388,N,N,N, +N,41060,36855,N,N,N,N,N,N,N,35248,41032,N,N,N,N,36859,36854,N,N,N,N,N,40412,N, +N,N,39389,35816,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37569,N,N,N,N,N,N,N,40918,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41170,N,N,36928, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35524,N,N,39392,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,40944,40947,N,N,N,N,N,N,N,N,N,N,N,N,40383,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,40950,N,38344,N,N,40538,N,N,N,N,N,N,N,N,N,N,N,N, +39395,N,N,N,N,N,N,N,N,N,N,N,35402,N,N,N,N,N,N,N,N,40945,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,35495,N,N,N,N,N,N,N,N,39398,N,N,N,40951,N,40941,N,N, +N,N,N,N,35420,N,40366,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,38345,N,N,N,N,N,36936,N,N,39400,N,N,N,N,N,36937,N,N,36026, +N,N,37041,N,N,N,N,N,N,36938,N,N,N,N,N,N,N,N,N,N,39402,N,N,N,N,N,N,N,N,N,N,N, +39889,N,N,N,N,N,N,N,39403,N,39404,N,N,N,N,N,N,N,N,39405,N,N,N,N,39406,36940,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36941,N,N,38347,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,38882,N,N,N,N,N,N,N,N,38348,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40824,N,N, +N,N,N,N,N,N,N,35196,35197,N,N,N,N,N,N,35198,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39261,N,N,N,N,N,N,N,N,N,N,N,N,39770,N,N, +N,N,36944,N,35919,N,N,N,N,N,N,N,N,N,N,N,36948,N,50902,39592,39407,65259,40355, +40353,39235,39237,N,40317,N,N,39408,N,N,N,N,N,N,N,N,39409,N,39410,N,N,36028, +40288,N,N,N,N,N,N,N,N,N,41123,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36955,40667,N,N,N,N,N,N,N,N,N,40313,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39411,N,N,N,36962,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,40789,N,N,N,N,N,N,N,N,N,39929,N,N,N,N,N,N,N,N,N,N,36965,N,N, +38624,N,N,N,N,N,N,N,39102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36968,N,N,N, +N,N,36972,N,N,N,N,N,N,N,N,N,N,N,N,38360,N,N,N,N,N,N,N,N,36970,40882,N,N,N,N,N, +N,N,40878,N,N,40880,N,35245,N,N,N,N,N,N,N,N,36974,N,N,N,N,N,N,N,N,40561,N,N,N, +N,N,40522,N,N,N,N,N,40924,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35243,N,40888,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36976,N,N,N,N,N,N,N,N,N,N,N,N, +35683,N,N,N,N,38364,N,N,N,N,N,N,N,N,36977,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64606,N,N,N,N,N,N,N,N,35145,N,N,N,N,N,38491,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35920,N,N,N,38054,N,N,N,36821,40563,N,N,N,N,N,36981,N,N,N,N,39415,N,N,N,N,N,N, +N,N,N,N,N,N,N,36031,N,N,N,N,N,N,39417,N,38499,38329,N,N,N,N,N,N,N,N,N,38100,N, +N,N,N,N,N,64762,N,N,N,N,36983,N,N,37035,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40269, +N,N,39418,N,N,N,N,37603,N,38843,N,N,36984,N,N,N,N,N,N,N,N,39419,N,N,38880,N,N, +N,N,N,N,N,N,38620,N,N,N,N,N,N,N,N,N,40104,N,N,38770,N,N,N,N,37952,N,N,N,N,N, +37618,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39421,N,N, +39420,N,N,N,N,N,N,N,63959,38474,N,N,N,38616,39422,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36939,N,N,N,N,N,N,64065,N,N,N,N,N,N,N,39488,N,38747,N,N,N,N,N, +39489,37341,N,N,N,N,N,37884,39490,39491,N,38489,N,N,N,N,N,N,39492,36945,N,N,N, +38079,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37026,N,N,N,40107,38774,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64597,65093,38056,39493, +64075,40417,N,N,38617,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38772,N,N, +65013,N,N,N,37605,N,38469,37338,N,37027,N,N,41055,N,N,N,N,37039,38847,N,N,N, +37196,N,N,N,N,38522,N,N,N,37342,N,N,39494,65200,38777,37996,N,N,N,N,N,N,N,N, +39000,N,N,N,N,N,N,N,N,N,N,N,37478,N,N,N,37883,N,N,N,N,N,N,N,N,N,N,N,N,39495,N, +N,N,N,N,N,N,N,N,N,38729,N,N,38728,N,37706,N,40162,N,N,N,N,N,N,37476,N,N,N,N, +37343,N,N,N,N,N,N,N,64377,N,N,N,N,N,N,N,38615,N,N,N,N,37699,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64971,65146,N,37339,35946,38831,N,N,38365,N,N,N,37704,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39499,N,N,N,64581,N,39501,N,N,N,N,N,N,37308,37090,37044,38369, +N,N,N,N,N,39502,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39503,N,N,N,65088,65091,N,N,N, +N,N,N,N,N,N,38621,N,N,N,N,N,N,39505,N,N,N,38567,N,N,37040,N,N,N,N,N,N,N,N,N, +40014,N,37955,N,N,N,N,36538,N,N,N,N,N,N,N,N,N,N,N,N,39506,N,64705,N,N,N,N,N,N, +N,N,N,35817,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40111,N,N,35837, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39612,N,39608,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39598,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39591,39507,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,40308,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35818,N,N,N,N,N,N,35819,N,N,N,N,N,37042,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,38377,38376,N,38374,N,N,N,N,N,N,37045,N,39508,N,N,N, +37043,38375,N,N,35664,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35820,N,N,N, +N,N,N,N,N,N,N,N,39510,35835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39511,N, +N,N,N,41130,N,N,N,N,N,N,N,N,40870,N,N,N,39372,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40025,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39349,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37054,N,N,N,N,N,40879,N,N,N,N,N,N,N,N,N,N,N,N,N,38386,N,N,N,N,N,N,37055,N, +N,N,N,N,N,N,N,N,N,N,N,37057,N,65252,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37060,N,N, +N,N,N,N,37063,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37604,40786,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37083,N,N,N,N,N,41062,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37074,N,N,34667,N,37076,N,N,N,N,N,N,N,N,N,39515,38397,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,35780,N,N,N,35942,N,37086,N,N,N,N,N,40164,N,37089,N,N,N,N,N,N,N,N,N,N,N, +N,N,40518,N,N,N,38481,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64344,N,37094, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38480,N,N,N,37095,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,37096,39517,N,40826,N,N,N,39772,N,40828,N,N,64594,37097,N,37098,N, +39518,N,N,N,N,N,40822,N,N,N,N,N,N,N,N,N,37099,N,N,N,N,N,N,N,N,N,N,N,N,N,37100, +N,N,N,N,N,35822,N,N,N,N,N,N,N,37102,N,N,N,37318,N,N,37106,64700,35444,N,N,N,N, +N,N,N,N,N,38487,N,N,N,40175,N,N,N,N,N,N,N,N,N,N,40927,N,N,N,N,37111,37110,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39774,N,N,N,37112,N,N,N,N,N,N,N,N,N,N,36092,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37113,N,36041,N,N,N,64106,N,N,N,N,N,N,N,N,35823,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40928,N,N,37186,N,39522,N,N,N,N,N, +N,N,N,N,38249,N,N,N,37188,37187,N,37185,N,N,N,35824,N,N,N,N,N,N,N,N,N,N,N,N,N, +38496,N,35825,N,39414,37193,N,N,N,N,37194,N,N,N,N,N,37195,N,N,N,N,39524,N,N,N, +35519,39526,N,N,N,N,N,N,N,N,N,N,39527,N,N,39529,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39530,38482,37197,N,38502,N,N,N,N,40827,N,39531,N,N,N,N, +N,N,N,41068,N,N,38503,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39532,N,N,N,N,39533,35826, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38506,N,N,N,N,N,N,N,N,64746,N,N,N,N,N,38508,N, +N,N,N,N,N,N,N,N,N,N,N,N,37316,N,N,N,38519,N,N,N,N,N,N,N,39412,39535,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40875,N,N,N,N,N,36030,36545,N,N,N,N,38229,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37202,37203,N,N,N,37205,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38237,N,38513,N,N,N,N,40045,N,N,N,N,N,N,N,N,38515,N,N,N,N,N,N,N,N,N,N,N,37204, +39537,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37206,N,N,N,38509, +N,N,N,N,N,N,38231,N,N,N,N,N,N,N,N,35270,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35271,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,35434,N,N,N,35671,N,N,N,40929,N,N,39775,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41053,N,N,N,N,N,N,N,N,37211,N,37212,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37214,N,N,N,N,N,N,N,N,N,N,40796,40791,N,N,N,N,N, +N,40805,N,N,N,N,N,39538,N,N,N,N,37216,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40798,N,N,37217,N,N,N,N,N,N,37220,N,N,N,N,40769,N,N,N,N,N,N,37225,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37224,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39540,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38578,N,39541,N,64933,N,N,N,N, +N,N,N,40681,N,35770,37229,41056,N,N,N,N,N,N,N,40926,N,N,N,N,N,40899,N,38581,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41063,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,38579,N,N,N,N,N,N,N,N,N,N,N,N,N,39542,N,N,N,N,N,N,N,N,N,N,N, +38357,N,N,N,40650,N,N,N,39543,N,N,39544,N,N,N,N,N,N,N,N,N,N,37232,37231,N,N,N, +N,N,N,N,40867,N,37233,N,N,N,38577,N,N,N,N,40803,N,N,N,N,N,40807,N,N,N,35769, +39546,N,N,N,N,N,35670,N,N,N,N,N,N,N,N,39642,N,N,N,N,N,38576,N,N,N,N,39550,N,N, +N,N,N,N,N,N,N,N,40414,N,N,N,N,N,N,N,N,N,38573,N,N,N,38574,N,N,N,N,N,N,N,N,N, +40609,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40528,N,N,N,N,N,N,N,N,38575, +35828,40868,N,N,N,N,N,N,N,N,N,38589,N,N,N,N,N,N,N,N,N,38644,N,N,N,N,N,N,N,N,N, +N,38584,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64161,N,N,N,N,37287,N,N,N,N,N,N,N, +N,N,N,41054,N,N,N,N,39549,N,N,N,N,35144,N,40625,N,N,N,N,N,N,N,N,N,N,N,N,N, +40411,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38335,35443,N,N,N,N,N,N,N,N,N,N,N,N,N,40702, +N,37242,N,N,N,N,37243,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39587,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,38594,N,N,N,N,N,40823,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39588,N, +N,39589,N,N,N,37281,N,N,N,N,35256,N,N,N,N,N,N,N,N,N,N,37235,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39590,35261,N, +35257,N,37245,N,N,N,N,N,N,N,N,N,38587,N,N,N,40946,N,N,35829,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,39593,N,N,N,N,N,40788,N,N,40931,40685,N,N,N,N,N,N,N,N,N,N,37290,N,N,N, +N,37291,41072,N,40813,N,N,N,N,N,37292,N,N,N,37293,N,N,N,41213,N,40930,N,37295, +40513,39594,N,N,37296,N,39595,N,N,N,N,N,N,N,N,N,N,N,39596,N,39498,N,37298,N,N, +35830,N,39597,35254,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39599, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,39600,N,N,N,N,N,N,39601,N,N,N,N,N,39585,37305,N,N, +N,N,N,37306,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37310,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41025,35767,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37312,N,N,N,N,N,N,N,N,N,N,39603, +37315,N,N,N,N,N,N,N,N,N,N,41212,N,N,40942,N,N,N,N,N,N,40809,N,N,N,N,N,N,N, +37320,N,N,N,N,N,N,37321,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36326,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37323,N,N,N,N,N,N,N,N,N,N,35272,N,N,N,N,N,36266,N,N,N,N, +N,40925,35907,35949,35956,36023,36025,36027,36032,36055,36056,36058,51361, +51363,36077,36168,35832,51408,N,N,N,N,51407,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,50916,N, +50917,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,51405,N,51406,N,N,N,N,N,N,N,N,63998, +}; + +static const struct unim_index big5hkscs_bmp_encmap[256] = { +{__big5hkscs_bmp_encmap+0,168,252},{__big5hkscs_bmp_encmap+85,0,220},{ +__big5hkscs_bmp_encmap+306,80,198},{0,0,0},{__big5hkscs_bmp_encmap+425,1,81},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5hkscs_bmp_encmap+506,190, +193},{0,0,0},{0,0,0},{__big5hkscs_bmp_encmap+510,22,231},{0,0,0},{ +__big5hkscs_bmp_encmap+720,218,219},{__big5hkscs_bmp_encmap+722,96,125},{ +__big5hkscs_bmp_encmap+752,80,112},{0,0,0},{__big5hkscs_bmp_encmap+785,61,61}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5hkscs_bmp_encmap+786, +128,227},{__big5hkscs_bmp_encmap+886,51,51},{__big5hkscs_bmp_encmap+887,5,254 +},{__big5hkscs_bmp_encmap+1137,192,207},{__big5hkscs_bmp_encmap+1153,49,49},{ +0,0,0},{__big5hkscs_bmp_encmap+1154,53,251},{__big5hkscs_bmp_encmap+1353,6,254 +},{__big5hkscs_bmp_encmap+1602,9,245},{__big5hkscs_bmp_encmap+1839,1,251},{ +__big5hkscs_bmp_encmap+2090,15,250},{__big5hkscs_bmp_encmap+2326,8,254},{ +__big5hkscs_bmp_encmap+2573,1,251},{__big5hkscs_bmp_encmap+2824,14,244},{ +__big5hkscs_bmp_encmap+3055,13,239},{__big5hkscs_bmp_encmap+3282,18,253},{ +__big5hkscs_bmp_encmap+3518,6,255},{__big5hkscs_bmp_encmap+3768,0,250},{ +__big5hkscs_bmp_encmap+4019,4,250},{__big5hkscs_bmp_encmap+4266,2,249},{ +__big5hkscs_bmp_encmap+4514,17,252},{__big5hkscs_bmp_encmap+4750,43,242},{ +__big5hkscs_bmp_encmap+4950,1,244},{__big5hkscs_bmp_encmap+5194,3,234},{ +__big5hkscs_bmp_encmap+5426,3,247},{__big5hkscs_bmp_encmap+5671,19,244},{ +__big5hkscs_bmp_encmap+5897,0,250},{__big5hkscs_bmp_encmap+6148,6,231},{ +__big5hkscs_bmp_encmap+6374,15,255},{__big5hkscs_bmp_encmap+6615,16,192},{ +__big5hkscs_bmp_encmap+6792,4,237},{__big5hkscs_bmp_encmap+7026,7,156},{ +__big5hkscs_bmp_encmap+7176,4,248},{__big5hkscs_bmp_encmap+7421,3,253},{ +__big5hkscs_bmp_encmap+7672,3,252},{__big5hkscs_bmp_encmap+7922,1,254},{ +__big5hkscs_bmp_encmap+8176,2,249},{__big5hkscs_bmp_encmap+8424,1,254},{ +__big5hkscs_bmp_encmap+8678,19,239},{__big5hkscs_bmp_encmap+8899,2,251},{ +__big5hkscs_bmp_encmap+9149,5,253},{__big5hkscs_bmp_encmap+9398,0,254},{ +__big5hkscs_bmp_encmap+9653,3,251},{__big5hkscs_bmp_encmap+9902,2,249},{ +__big5hkscs_bmp_encmap+10150,2,254},{__big5hkscs_bmp_encmap+10403,13,255},{ +__big5hkscs_bmp_encmap+10646,5,252},{__big5hkscs_bmp_encmap+10894,16,245},{ +__big5hkscs_bmp_encmap+11124,9,252},{__big5hkscs_bmp_encmap+11368,12,223},{ +__big5hkscs_bmp_encmap+11580,35,253},{__big5hkscs_bmp_encmap+11799,7,226},{ +__big5hkscs_bmp_encmap+12019,44,229},{__big5hkscs_bmp_encmap+12205,24,254},{ +__big5hkscs_bmp_encmap+12436,7,234},{__big5hkscs_bmp_encmap+12664,10,255},{ +__big5hkscs_bmp_encmap+12910,24,241},{__big5hkscs_bmp_encmap+13128,2,254},{ +__big5hkscs_bmp_encmap+13381,0,202},{__big5hkscs_bmp_encmap+13584,0,250},{ +__big5hkscs_bmp_encmap+13835,3,246},{__big5hkscs_bmp_encmap+14079,5,250},{ +__big5hkscs_bmp_encmap+14325,28,255},{__big5hkscs_bmp_encmap+14553,2,254},{ +__big5hkscs_bmp_encmap+14806,2,250},{__big5hkscs_bmp_encmap+15055,4,248},{ +__big5hkscs_bmp_encmap+15300,3,254},{__big5hkscs_bmp_encmap+15552,5,246},{ +__big5hkscs_bmp_encmap+15794,0,226},{__big5hkscs_bmp_encmap+16021,2,251},{ +__big5hkscs_bmp_encmap+16271,2,248},{__big5hkscs_bmp_encmap+16518,5,220},{ +__big5hkscs_bmp_encmap+16734,2,217},{__big5hkscs_bmp_encmap+16950,12,254},{ +__big5hkscs_bmp_encmap+17193,8,245},{__big5hkscs_bmp_encmap+17431,6,244},{ +__big5hkscs_bmp_encmap+17670,6,254},{__big5hkscs_bmp_encmap+17919,11,252},{ +__big5hkscs_bmp_encmap+18161,18,252},{__big5hkscs_bmp_encmap+18396,37,254},{ +__big5hkscs_bmp_encmap+18614,7,223},{__big5hkscs_bmp_encmap+18831,6,250},{ +__big5hkscs_bmp_encmap+19076,2,246},{__big5hkscs_bmp_encmap+19321,3,246},{ +__big5hkscs_bmp_encmap+19565,24,255},{__big5hkscs_bmp_encmap+19797,11,237},{ +__big5hkscs_bmp_encmap+20024,5,248},{__big5hkscs_bmp_encmap+20268,3,252},{ +__big5hkscs_bmp_encmap+20518,2,239},{__big5hkscs_bmp_encmap+20756,112,245},{ +__big5hkscs_bmp_encmap+20890,4,255},{__big5hkscs_bmp_encmap+21142,0,231},{ +__big5hkscs_bmp_encmap+21374,28,249},{__big5hkscs_bmp_encmap+21596,12,226},{ +__big5hkscs_bmp_encmap+21811,81,247},{__big5hkscs_bmp_encmap+21978,3,212},{ +__big5hkscs_bmp_encmap+22188,1,242},{__big5hkscs_bmp_encmap+22430,25,249},{ +__big5hkscs_bmp_encmap+22655,8,196},{__big5hkscs_bmp_encmap+22844,81,254},{ +__big5hkscs_bmp_encmap+23018,8,253},{__big5hkscs_bmp_encmap+23264,3,244},{ +__big5hkscs_bmp_encmap+23506,1,246},{__big5hkscs_bmp_encmap+23752,45,244},{ +__big5hkscs_bmp_encmap+23952,29,244},{__big5hkscs_bmp_encmap+24168,3,245},{ +__big5hkscs_bmp_encmap+24411,20,245},{__big5hkscs_bmp_encmap+24637,14,245},{ +__big5hkscs_bmp_encmap+24869,12,255},{__big5hkscs_bmp_encmap+25113,2,255},{ +__big5hkscs_bmp_encmap+25367,2,124},{__big5hkscs_bmp_encmap+25490,2,252},{ +__big5hkscs_bmp_encmap+25741,10,254},{__big5hkscs_bmp_encmap+25986,2,179},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{__big5hkscs_bmp_encmap+26164,7,7},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{__big5hkscs_bmp_encmap+26165,2,237}, +}; + +static const DBCHAR __big5hkscs_nonbmp_encmap[29306] = { +40049,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37749,N,N,N,N,N, +N,N,37750,N,N,N,N,N,N,N,38216,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,36550,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35781,35834, +N,N,51324,N,N,N,N,N,N,N,N,N,39604,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34894,34891, +51322,34888,N,N,N,34887,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,41206,34885,N,34899,N,N,N,N,N,N,N,N,N,64685,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36085,N,N,N,N,35501,N,37490,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64583,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38111,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40913,64459,N,N,N,N,N,N,N,37501,N,N,N,N,N,N,N, +39076,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36089,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38119, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37067,37499,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38104,N,N,N,N,64607,N, +64084,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39605,N,N,N,N,N,N,N,38618, +37497,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64116,37493,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36347,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35401,N,N,N,37599,39804,64099,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64096,37485,64098,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39606,N,N,N,N,N,N,38763,N,N,N,N,N,N,N,N,N,N,N,N, +N,64874,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64852,N,37491,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38872,N,N,N,N, +N,N,40891,37698,37494,N,N,N,N,N,N,N,N,N,N,64101,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37484,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64110,N,N,N,N,N,N,40672,N,N,37568,37567,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,37566,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39610,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35507,N,38773,64064,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64118,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64464,N,N,N,N,N,N,N,N,N,N,N,N,N,64123,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,65133,N,N,N,N,N,N,39859,N,N,N,N,N,35276,N,N,N,N,39614,N,N,N,N,N, +N,N,N,N,64066,37564,N,N,N,N,N,N,N,N,N,N,37980,39861,N,N,N,39615,N,N,N,39079, +38820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37117,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64635,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39616,37571,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35498,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39888,38224,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37574,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39078,38214,N,N,N,N,N,N,N,N,N,N,N,N,64867,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64194,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40643,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35250,40038,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36947,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,35938,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,38849,N,N,N,N,N,N,N,N,N,N,N,N,N,39620,N,N,N,N,N,N,N,N,N,N,39621,36591,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,64233,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36160,N,N,N,N,N,N,N,N, +37474,35575,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39622,N,N,N,N,N,N,37601, +N,N,N,N,39625,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64198,N,N,N,N,N,N,N, +N,38821,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39627,N,N,N,64114,35422,N,38112,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37580,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35557, +N,N,N,N,N,65116,39628,N,N,N,N,N,40441,35395,35494,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,39629,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39630,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64238,39884,N,N,N,39631,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39633,N,N,N,N,N,N, +N,N,40442,N,N,N,N,N,40316,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39635,N,N,38822,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39263,N,N,N,64502, +40901,35417,35691,N,N,N,N,N,N,39636,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39637,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,38818,35396,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40778,N,N,N,N,N,N,N,N,37025,64932,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35428, +35570,35576,40408,N,N,38102,64254,64423,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,39638,N,40781,N,N,64246,N,N,N,N,N,N,N,35415,N,35651, +35652,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35510,N,N,N,N,N,35520,N,N,N, +N,N,N,N,N,N,N,40532,N,N,N,N,N,N,N,N,N,N,39639,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39640,39644,N,N,N,N,35530,40616,N,N,37475,39645,35685,35695,35710,N, +N,N,N,36675,N,N,N,N,N,N,37584,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35572,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40382,N,N,N,N,N,39649,N,64734,40445,35686, +35696,35701,35556,35748,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35565,N,N,N,N,N,N,N,N, +N,35421,N,35656,N,N,N,N,40429,N,N,N,N,40512,N,N,N,N,N,N,N,35567,35574,40566,N, +N,N,N,N,N,N,N,N,40675,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,39646,36350,N,N,N,N,64252,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,40113,40567,35684,35687,38731,N,N,N,N,N,N,N,N,38483,N,N,N,N,N,N,39648, +35658,N,35569,35543,N,N,N,N,N,N,N,N,N,41131,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35509,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35423,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35566,N,N,39647,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35582,N,N,N,N,N,N,35416, +35747,35751,N,N,N,N,N,39651,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,37473,N,N,N,N,N,N,N,N,N,N,40407,40573,40615,40619,36930,N,N, +N,N,N,N,N,N,35705,35706,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39654,N,N,N,N,N,N,N,N,N,N,N,N,39653, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35454,N,N,N,N,N,40516,39655,35452,35697,N, +N,39657,N,N,N,N,N,N,N,N,N,N,N,N,39658,N,N,N,N,N,N,N,N,N,N,N,N,N,39659,N,N,N,N, +N,N,35517,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64334,N,N,N,N,N,N,N,N,N, +N,39661,35577,40547,N,N,N,N,N,35657,35534,35694,N,N,N,N,N,35560,N,N,N,39662,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37582,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35418,35707, +35708,39663,N,N,N,N,N,N,N,N,N,N,N,39664,N,35578,N,N,N,N,N,N,N,35137,N,N,35698, +N,N,N,N,N,N,35571,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35752,N,N,N,N,N,N,40622,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40562,64371, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64351,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37050,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37374,40694, +N,N,N,N,N,N,38893,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39667,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,41198,38524,37701,39022,64086,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39669,N,N, +N,64587,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39668,65246,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64695,N,N,N,N,N,N,N,N,N,38897,N,N,N,38855,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40139, +37440,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,40168,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37373,38734,N,N,64360,N,N,N,N,N,N,N, +N,N,N,N,N,N,38764,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36034,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38888,N,64362,35700,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,36583,N,N,N,N,N,N,N,N,N,N,N,N,64968,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37441,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38561,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,36595,39671,N,N,N,N,N,N,N,N,N,N,36774,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64214,40135,N,N,N,N,N,N,N,N,64215,N,N,N,N,N,39672,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64417,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36549,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64420,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64450,N,39617,N,N,N,N,N,37370,65243,38827,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37191,N,64433,N,N,N,N,N,N,N,N,N,36842,N,N,N,N,N,N,38098,65121,64206,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37613,37363,37830,N,37722,64251,N,N,37615,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64200,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38983,37734,38997,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38630,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40771,40874,38106,37614,64687,64507,N, +36601,37366,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37732,N,N,N,N,38133,40118,64429, +38990,36676,38653,N,N,N,N,N,N,N,N,N,N,N,N,N,39673,N,N,N,39674,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,38761,38356,38987,64426,N,N,39036,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37354,N,N,N,N,N,40367,40389,N,37361,36529,38825,64428,64696,40121,N,N,N,N, +N,N,N,64432,64722,37835,N,N,39677,N,N,N,N,N,N,N,N,N,N,N,37364,35756,41045,N,N, +N,N,38260,N,N,N,N,38334,N,N,N,N,N,N,N,N,N,N,N,N,38829,N,N,N,N,N,N,N,N,N,N,N, +36585,N,N,37624,38846,37228,38058,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64611,N, +N,N,40390,N,N,N,N,N,N,N,38837,37560,37359,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,65190,38752,37720,38262,36780,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,37356,38836,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37367,N,N,N,N, +38730,64329,38264,37820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,37334,37717,37718,38993,N,N,N,N,N,N,N,N,N,N,36856,64448,37874,N,N, +37072,N,N,N,N,N,N,40004,N,N,N,N,N,37461,N,N,N,N,37731,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,37285,N,N,N,N,N,N,N,N,41197,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64875,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39678,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37713,N,N,N,35927,N,N,64120,N,N,N,N,65192,N,N,N,N,N,N,N,N,N,N,N,N,N,37712, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64076,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37623,39744,N,N,N,N,N,N,64462,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39745,N,N,N,N,N,65197,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,34657,64469,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35778,39548,39746,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39747,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40569,N,N,64473,N,N, +N,N,N,N,39748,41127,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34670,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,39923,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,35961,N,N,N,37726,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35275,N,N,N,N, +N,N,40787,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37847,N,N,N,N,N,N, +N,N,N,N,N,N,N,64481,65232,N,N,N,N,N,N,36081,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64482,N,N,N,N,N,64739,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,36980,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64486,N,N,N,39863,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,39749,N,N,N,N,N,N,N,N,N,N,N,N,39751,40784,N,N,N,N,N,39752,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64603, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39081,N,N,40189,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,34892,39755,N,N,N,64492,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35945,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39848,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35541,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64115,64857,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37282,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64493,N,N,N,N,N,N,40105,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35496,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36162,N,39875,35553,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39758,38352,N, +N,N,36959,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38894,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64590,N,N,N,N,N,N,39759,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39760,40646,N,N,N,N,N, +N,N,N,N,N,N,64592,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64883,N,N, +N,N,N,64935,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40354, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64088,64094,N,N,N,N,N,N,N,41049,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64117,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64446,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40098,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37744, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37745,37751,65263,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37741,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64605,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,37048,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35580,N, +64321,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40555,38115,36578,35965,N,36567,N,N,N,N,N,N, +40013,N,N,N,38563,N,N,N,N,N,N,N,N,N,N,39761,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35523,N,N,N,N,N,N,N,N,N,N,N,38570,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36066,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64616,35693,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64871,35561,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64673,37740,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39762,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65136,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,64680,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64745,40116,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,35562,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39763,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39765,N,N,N,38571,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,64679,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39766,35516,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35531,N,N,N,N,N,39767,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,35277,N,39769,39771,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37797,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39773,N,N, +N,40527,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37795,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35451,N,N,N,35650,38736,36787,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35408,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39776,N,N,N,N,35653,N,N,N,35654,N,N,N,N,N,N,N,N,N,N,N,N,40446,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39778,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37755,N,N,N,N,N,37809,N,N,N,N,N,N,N,35424,N,N,N,N,N,N,N, +N,35544,N,N,N,N,39779,N,N,N,N,N,N,N,N,N,N,35433,N,N,N,35399,N,N,35532,37756, +39781,N,N,N,N,N,N,N,N,N,39782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35442,N,N,N,N,N,N,N,35450,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37807,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35504,N,N,N,N,N,N,N,39784, +N,N,N,N,N,N,N,N,N,N,40611,N,N,64236,35703,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39783,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35673,64689,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64699,N,N,N,N,N,N,N,N,N,N,N, +39785,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37800,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35552,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,40529,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36703,39786,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39787,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38892,39788,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,65102,N,N,N,N,N,N,64962,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,39789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37223, +64716,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37814,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37092,N,N,N,N,37093,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40690,37834,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,35772,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36678,N,N, +N,N,37839,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64731,64732,N,N,N,N,N,N,N,N,N,N,N,N,N,37824,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,64742,38631,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64728,64729,64934,37838,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,38385,N,N,N,N,N,N,N,N,N,40169,N,64740,38063,64119,37836,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36065,N,N,N,N,N, +N,N,N,N,N,N,36954,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35924,N,N,N,N,N,N,N,37823,64337,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,37817,65239,37815,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37849,N,N,N,N,N,N,N,N,N,N,N,N,N,37819,37850, +39075,N,N,N,N,N,N,N,N,N,37073,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39790,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64112,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39915,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39791,N,N,N,N,N,N,N,64764,N,N,N,N,N,N,N,N,N,N,N,N,N,35648,41083,N,N,N,36001, +38903,N,N,N,37858,64726,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38233,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37798,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64832,N,N,37727,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,38898,40054,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36600,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36075,N,N,N,N,N,N,N,N,36679,N,N,N,N,N,N,N,N,N,N,N,N,39796,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37556,N, +N,N,37357,N,N,38610,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64838,36687,38217,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39797,64092,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,34641,N,N,39801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64843,N,N,N,38611,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64856,N,N,N,N,N,37983,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,41205,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37443,N,N,N,N,N,N,38906,N,N,N,N,N,N,N,N,N,N,N,N, +40409,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38900,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37453,64859,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39802,N,N,N,N,N,N,N,N,N,40661,N,N,N,N,N,N,N,N,N,N,N,N,64174,N,40137,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37464,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,36552,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,38068,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37857,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37855,N,N,N,N,N,64752, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37868,38902,38607,37854,35535,39842,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64873,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37714,N,N,N,N,N,N, +N,N,N,N,N,39074,36071,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64878, +36004,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64124,37882,36988,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36711,N,40375,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41193, +64078,64929,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40564,40895,40651,39865,40404,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38841,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36593,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38267, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40658,38739,38564,36798,38105,36952,64889,64891,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36570,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36602,34658,N,N,N,N,N,N,N,N,N,N,39845,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40665,38868,37051,64956,64966,37448,N,N,N,N,N,N,N, +37557,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,40385,37561,37542,36683,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39846,N,N,N,N,N,37558,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36416,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40664,37982,39007,38094,37450,64880,37991,N,N,N,N,N,N,N, +N,N,N,N,36332,N,N,N,N,N,N,N,N,39896,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,34659,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37960,64193, +40183,64958,N,N,N,N,N,N,N,N,N,N,N,N,36826,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64985,N,N,64638,N,N,N,N,N,N,N,N,37881,N,N, +N,N,64067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,64235,64195,38867,38393,40008,64984,41176,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64983,64330,39855,37963,64969, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36524,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64946,N,N, +N,N,N,37466,64701,37593,N,N,N,64981,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37597,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37465,N,N,N,N,N,N,N,N,N,N,36080, +38586,N,N,N,N,N,N,N,N,N,N,37467,N,N,N,N,N,N,N,N,N,39851,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64986,64990,N,N,N,64979,N, +N,N,N,N,N,N,N,N,35910,N,N,N,N,N,N,64982,64988,64989,N,N,N,N,37118,N,N,65185,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35757,N,N,40152,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40557,64892, +64353,N,N,N,N,N,N,38648,N,N,N,N,N,N,N,N,38640,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64756,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65120,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38994,38479,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37230,N,N,N, +N,N,N,N,N,N,N,39021,N,N,39012,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,37971,65004,64376,N,N,N,N,N,N,N,N,N,N,N,38330,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39005,N,37625,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39002,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,34640,N,65014,N,N,N,N,N,N,N,37840,39010,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39853,N,N,N,N,N,N,N, +N,N,N,N,38735,39854,N,N,N,N,N,N,N,N,N,N,N,N,37970,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39856,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37330,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38890,64363,37297,65011,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37579,N,N,N, +N,N,N,N,N,N,39857,N,N,N,N,N,64748,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,39019,N,N,N,38737,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39025,38383,N,N,N,N,N,N,N,40691,N,N,N,N, +N,37352,39866,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64332,37482,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65016,39009,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,37351,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37869,38724,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,37345,N,N,64501,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39017,N,N,N,N, +35426,N,N,39867,36008,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40021,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36471,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35506,40636,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37862,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37794,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39869,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37757,40550,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37977,N,N,N,N,N,N,N,N,N,39871,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37976,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40613,39879,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,65108,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36468,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,35798,N,N,N,N,N,N,38070,64884,39104,38053,N,N,N,N,N,N,N, +39880,N,N,N,38381,64894,64491,N,N,N,N,N,N,N,N,N,N,64893,N,N,N,N,N,N,N,N,N, +38767,37985,N,40897,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38359,N,N,N, +64082,40024,N,N,N,N,N,N,N,N,N,40808,39911,64718,38632,64073,38817,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38221,40696,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,65097,37326,38769,N,N,N,N,36047,N,N,N,64945,N,N,64622,N,N,N,N,N, +40178,37816,36931,38745,38103,65126,38013,64623,N,N,N,N,37446,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64109,N,N,36599,N,64439,N,38012,37581,38834,N,N,N,N,N,N,N,N,N, +65125,38526,38744,39799,37327,N,N,N,N,N,N,N,N,N,38052,N,N,N,N,N,N,N,N,N,N, +40109,N,N,N,N,N,N,N,N,N,35755,N,N,N,38613,64691,N,N,N,37806,N,38765,N,N,N,N,N, +N,37958,38391,N,N,N,N,N,N,N,N,40006,38235,37329,38132,N,65127,37541,N,N,N, +65247,36011,N,39881,N,N,N,N,N,N,N,N,N,N,N,64749,65018,64712,65122,37372,65131, +65017,64711,37198,40120,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38759,N,N,N, +38382,N,N,39858,N,N,N,N,37984,N,N,N,38050,39029,38828,37331,N,N,N,N,N,N,N,N,N, +N,N,39035,N,N,N,N,N,N,N,36587,38762,38494,N,N,N,N,N,N,N,N,N,38891,N,N,N,N,N, +40953,38392,65186,36838,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65150,N,N,N,N,N,N, +40356,38760,36588,38077,N,N,N,N,N,N,N,N,N,N,N,N,N,37979,40182,64167,39897,N,N, +N,N,N,N,N,N,N,64093,38486,38754,N,N,N,N,N,N,38074,41039,37592,N,N,N,39883,N,N, +N,N,N,N,38075,N,N,40287,N,N,N,N,N,N,37071,N,N,N,N,N,N,N,N,N,N,N,N,N,37989,N,N, +40780,N,N,N,N,N,N,37080,36187,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40638,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64365,38346,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,40386,38904,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36860,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38003, +38004,N,N,N,N,N,N,N,N,N,N,N,N,65207,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35403,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35413,35689,35548,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35702,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39886,N,35432,41208,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,39135,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,65205,N,N,N,39887,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38651,N, +N,39931,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40654,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36581,N, +N,N,N,N,N,N,N,N,40571,39890,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,35493,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,65230,35397,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,40444,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65231,35749,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35914,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,35564,N,N,64736,38061,65237,38060,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64602,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39894, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,35439,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35753,36447,N,N,40395,N, +64743,39895,N,N,N,N,N,N,N,N,N,N,N,37832,N,N,N,N,N,N,N,N,N,37360,36832,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39899,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37101,N,39900,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36179,41196,N,N,N, +39162,N,N,N,N,N,N,N,N,N,39904,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37831,37449,38625,39906,N,N,N,39908,N,N,36833,39909,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38080,N,N,37827,N,N,N,N,N,N,N,N,N,N,37829,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36985,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38779,N,N,N,N,N, +36990,N,N,N,N,65254,65094,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40376,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37488,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38312,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36016,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,38088,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39097,37184,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64702,N,N,N,N,N,N,N,37207,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35762,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64223,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,39910,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38467,36420,40015,65268, +N,N,N,N,N,39912,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37852,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38511,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36426,39917,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37622,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40377,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,36430,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,64463,34656,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40642, +N,N,N,N,N,N,38117,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39920,38116,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,38225,35771,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39921,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,38128,36452,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38122,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36705,N,N,N,39780,36443,N,N,N,N, +39922,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40894,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40393,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36460,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36723,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36015,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36725,36465,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36448,36458,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,35916,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38226,38228, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35540,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40379,38211,37630,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,38130,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38129,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41194,40402,41137,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37368, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37986,39844, +36525,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40621,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38608,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65262,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,35508,N,N,N,N,N,N,N,N,N,N,N,N,38743,35447,39927,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36533,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41069, +36534,38742,38208,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,41203,38078,N,N,N,39930,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64991,40380,N,N,N,N,N,N,N, +N,38142,N,N,N,N,N,N,N,N,35803,41214,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,36544,40775,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35806,41211,N,N,N,N, +36547,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38473,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,65218,N,N,38220,39933,N,N,N,N,N,N,N,N,N,N,N,N,N,37068, +40032,38219,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39934,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40048,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,40003,N,N,N,40007,36556,N,N,N,36436,N,N,N,N,N,N,N,N,N,N,36580, +40009,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35678,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38238,N,N,N,N,N,N,N, +N,N,N,N,N,38236,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40011,35809,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36569,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40372,N, +37471,N,N,N,40012,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,35489,N,N,N,N,N,N,N,N,N,N,N,N,N,36571,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40022,35490,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,38740,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40030,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40660,38248,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,41155,35558,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,41207,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40033,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64589,N,40539,N,N,N,N,N,N,N,N,40553,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40035,65223,N,N,65222,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40039,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40041,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37221,N,N,N,N,N,N,N,N,N,N,N,N,40167,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,35412,N,N,N,N,N,N,N,40044,40046,65117,N,N,N,N,N,40051,N, +N,N,N,N,N,N,N,N,N,N,N,N,38250,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38253,36592,36685,N, +N,N,N,36598,N,N,N,N,N,N,N,N,64188,N,36053,N,N,N,N,N,N,N,N,N,N,N,N,N,34654,N,N, +N,N,64474,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35660,64885,39901,64245,N,N,N,N,N,N,N,40052,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,38213,N,N,N,N,N,N,N,N,N,N,N,N,38598,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36714,36686,N,N,N,N,N,40056,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64085,N,N,N,N,N,N,N,N,N,N,N,N,38884,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40001,37468,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38650,36086,N,N,N,N,36173,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64358,36453,38985, +64424,38978,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40058,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38907,37066,N,N,N,N,40027,N,N,38733, +N,N,36563,N,N,N,N,N,N,N,N,N,N,N,N,N,38241,40779,40885,37842,64938,38976,37190, +39015,64090,64425,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,38977,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36051,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64765,64939,37309,36684,38601,36693,64430,38255,N,N, +N,N,N,N,40061,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,41200,N,N,N,N,N,N,N,N,N,N,N,N,N,37999,64940,N,N,N,N, +38603,38606,N,N,N,N,41046,N,40161,N,N,N,N,N,N,N,N,N,N,38596,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36702,36716,36515,64435,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64595,N,N,N,64947,N,N,N,N,36715,N,N,N,N,N,N,N,N,N,N, +N,N,38602,N,N,N,N,N,N,34643,N,N,N,N,N,N,N,N,N,N,N,N,N,36729,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,40559,41157,64632,36418,36698,37058,36517,36961,37455,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37747,64949,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,65228,N,64445,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36054, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38979,38597, +35260,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40099,N,N,N,N,N,N,37451,38986, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,36772,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,41201,40699,40146,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36775,N,N,N,N,34644,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64604,38981,N,N,36934,36049,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65274,38240,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,40776,37447,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37115,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40100,38257,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,34629,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40102,N,N,N,N, +40103,N,N,N,N,N,40106,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,40659,N,N,N,40560,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40108,34642,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36782,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36176,38269,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40112,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38838,N,41149,35551,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40618,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,36797,N,N,N,36799,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37737, +39847,51364,N,N,N,N,65258,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39905,N,N,N,N,N,N,35649,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40374,41195,39843,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,35745,36808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,35148,39008,N,N,N,N,N,N,N,N,N,N,38087,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,35672,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38315,38314,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40131,40132,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37846,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40364,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35814,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35441,36817,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,39381,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37108,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35491,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40142,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40148,40149,N,N,N,64456,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40371,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64624,N,N,N,N,N,36823,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39795,N,N,N,N,N,N,N,N,N,N,64091,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36818,36964,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39094, +38504,N,N,N,N,40150,N,N,N,N,N,N,N,N,N,N,N,N,39101,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36828,65270,36825,N,N,N,N,N,N,N,N,N,N,N,N,N, +38209,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,34668,N,N,N,N,38899,39928,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +34650,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34632,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34634,40556,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36850,36846,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40151,N,N,N,N,N,N,N,N,N,N,N,N,40558,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35392,N, +N,N,N,N,N,N,N,N,N,36847,N,N,N,N,N,N,N,N,36852,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36853,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,38338,39018,N,38863,40677,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40572, +36929,N,N,N,N,N,N,40155,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37953,N,N,N,N, +40166,40368,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,40170,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40173,N,N,N,N,N,N,N,N,N,N,N,N, +40186,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,35682,35406,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40138,35430,N,N,N,N,N,N,N,N,N,N,40187,40188,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40190,N,N,N,N,N, +N,N,N,N,N,N,N,N,35411,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40165,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40256,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40257,N,N,N,N,N,N,N,N,N,N,N,N,36933,35699, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38858,N,40258,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,35425,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35758,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35538,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,35746,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40434, +40259,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40159,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,40260,N,N,N,N,N,N,N,N,N,N,36554,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36942,N,N,N,N,N,N,N,36531,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,40949,N,N,N,N,N,N,N,N,N,N,N,N,40261,36943,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,40263,N,N,N,35274,N,N,N,N,N,N,40117,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64510, +36958,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36963,36951,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36966,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39872,N,N,N,N,N,N,N,N,N,N,N,64741,37218,N,N,N,N,N,N,N,N,N,N,36967,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36769,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,36770,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40264,64211,N,N,N,N,N,N,36175,N,N,N,N,N,N,N,N,N,36957,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37049,N,N,N,N,N,N,N,N,N,N,N,N,N,36971, +35932,N,N,N,36969,65111,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,65109,36979,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39919,40176,N,N,N,N,N,N,N,N,N,N,N,N,40267,N,N,N,N,N,N,N,N,N,N,N,N,N,65241,N,N, +N,65242,N,N,N,37344,36163,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37336,N,N,N,N,N,N,N, +N,N,N,38470,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37728, +N,64083,40147,N,N,N,N,N,N,N,N,N,N,N,N,40270,N,N,N,64320,N,N,N,36322,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37954,N,36950,N,N,39013,N,35948, +64074,N,N,40272,40274,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38319,38746,37705,38727, +41204,N,N,N,N,N,N,38776,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36815,N,N,N,64608,N,N,N,N, +N,N,N,N,35918,N,N,N,64598,N,N,N,N,N,N,N,N,N,N,N,N,N,37340,38497,37612,37725, +36574,38654,64847,38366,N,N,N,N,N,N,N,N,N,N,N,N,N,39088,41024,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38845,38781,38901, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39852,64218,37570,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38833,N,N,N,N,N,36987,N, +N,N,N,37886,38011,N,38775,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64190,64835,37062, +37028,37032,38057,N,37033,N,N,N,N,35941,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38368,36989,N,N,N,N,N,N,37477,N,N,N,N,N,N,N,N,N,N,N,N,N,64954,37828,N,N,N,N,N, +N,N,N,65261,40363,41187,N,38472,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40275,N,N,N,N,N,35497,N,39877,N,38493,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38751,38495,38510,64349,N,N,N,N,N,40369,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65187,N,N,N,N,N,N,N,N,N,40370,N,N,38318,64675,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34665,N,N,N,N,N,N,N,N, +41122,N,N,38485,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40276,N,N,37697,N,38317,37333,N,N, +N,N,N,N,N,N,N,N,N,N,38778,65020,36423,37885,37029,37036,N,N,N,N,N,N,N,N,38316, +N,N,N,N,N,N,N,N,N,37038,65189,N,N,N,N,N,40278,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,38883,38370,N,N,N,N,N,37990,N,N,38471,N,N,N,N,37304,N,N,N,N,40172,N,N,N,N, +N,N,N,N,37037,N,38371,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35663, +N,N,35555,N,N,N,N,35661,38378,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35662,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36033, +35821,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37337,N,N,41124,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,38389,38388,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40883,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,65199,N,N,N,N,N,65138,37498,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65196,N,N,N,N,N,N,N,N,N,N,N, +N,N,38387,40280,36166,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37746,N,N,37317,N,N,N,N,N,N, +N,38466,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37069,38398, +37209,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40037,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38860,37070,N,N,N,N,N,N,40281,64757,65277,N,N, +40283,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,40284,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37758,N,N,N,N,N,N,N,N,N,N, +N,N,N,39084,N,N,40286,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64976,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64864,N, +N,N,N,N,N,N,N,N,N,N,40143,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37085,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37088,37107,N,N,39089,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37104,N,N,N,N, +N,N,N,N,N,N,N,37821,N,N,N,N,N,N,N,N,38327,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40774,N,N,N,N,N,N,N,N,36427,38488,N,N,N,N,N,N,N,N,N,N,35404,N,40291,40655,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40293,N,N,N,N,N,N,N,40294,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38490,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40292,N,N,N,N,N,N,N,N,N,N,35436,35545,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40295, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35440,35827,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37200,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,40129,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40296,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37799,N,N,N,N,N,N,38516,N,N,N,N,N,N,N,N,36093,41199,N,37201,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38593,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34679,N,35940,38518,40297,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,64676,N,N,N,N,N,N,N,N,N,N,N,N,40298,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37454,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40299,N,N,N,N,N,39873,40300,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,35429,37213,N,N,N,N,N,N,N,N,40301,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37210,35906,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40128,37226,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40302,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40614,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40397,N,N,40303,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35259,40697,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38580,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,37234,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40648,N,N,N,34673,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35669,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,40305,40306,N,N,N,N,N,N,N,N,N,N,N,N,40652,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37236,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40656,36956,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,36562,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37288,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37239,N,N,N,N,N,N,N,N,N,N,N, +38591,N,N,N,N,N,38592,N,N,N,N,36785,N,N,N,N,N,38583,35925,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37240,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35262, +37244,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64375,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37237,37283,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37238,N,N,N,N,N,N,N,N,38590,36169,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37241,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,38582,37284,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37286,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40309,N,N,N,N,N,N,N,N,N,N,N,36946,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41029,N,37289,N,39082,N,N,N,35935,N,N,35754,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40157,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40311,34646,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,35136,40684,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,37802,38008,N,N,N,N,40314,35529,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35659,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40940,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35554,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,40565,39028,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39624,N,N,N,N,41031, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35779,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64584,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64631,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40018,36605,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36776,N,N,N,N,N,N,N,N,N, +38266,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36848, +}; + +static const struct unim_index big5hkscs_nonbmp_encmap[256] = { +{__big5hkscs_nonbmp_encmap+0,33,238},{__big5hkscs_nonbmp_encmap+206,12,242},{ +__big5hkscs_nonbmp_encmap+437,4,229},{__big5hkscs_nonbmp_encmap+663,10,252},{ +__big5hkscs_nonbmp_encmap+906,19,254},{__big5hkscs_nonbmp_encmap+1142,71,235}, +{__big5hkscs_nonbmp_encmap+1307,17,118},{__big5hkscs_nonbmp_encmap+1409,14,121 +},{__big5hkscs_nonbmp_encmap+1517,44,213},{__big5hkscs_nonbmp_encmap+1687,22, +231},{__big5hkscs_nonbmp_encmap+1897,17,205},{__big5hkscs_nonbmp_encmap+2086, +13,255},{__big5hkscs_nonbmp_encmap+2329,11,255},{__big5hkscs_nonbmp_encmap+ +2574,21,200},{__big5hkscs_nonbmp_encmap+2754,4,251},{__big5hkscs_nonbmp_encmap ++3002,29,237},{__big5hkscs_nonbmp_encmap+3211,20,246},{ +__big5hkscs_nonbmp_encmap+3438,47,217},{__big5hkscs_nonbmp_encmap+3609,60,254 +},{__big5hkscs_nonbmp_encmap+3804,2,254},{__big5hkscs_nonbmp_encmap+4057,19, +253},{__big5hkscs_nonbmp_encmap+4292,119,150},{__big5hkscs_nonbmp_encmap+4324, +10,254},{__big5hkscs_nonbmp_encmap+4569,13,252},{__big5hkscs_nonbmp_encmap+ +4809,32,250},{__big5hkscs_nonbmp_encmap+5028,3,243},{__big5hkscs_nonbmp_encmap ++5269,45,99},{__big5hkscs_nonbmp_encmap+5324,68,194},{ +__big5hkscs_nonbmp_encmap+5451,42,172},{__big5hkscs_nonbmp_encmap+5582,70,249 +},{__big5hkscs_nonbmp_encmap+5762,28,213},{__big5hkscs_nonbmp_encmap+5948,15, +232},{__big5hkscs_nonbmp_encmap+6166,69,252},{__big5hkscs_nonbmp_encmap+6350, +42,195},{__big5hkscs_nonbmp_encmap+6504,8,124},{__big5hkscs_nonbmp_encmap+6621 +,33,250},{__big5hkscs_nonbmp_encmap+6839,101,237},{__big5hkscs_nonbmp_encmap+ +6976,19,190},{__big5hkscs_nonbmp_encmap+7148,27,246},{ +__big5hkscs_nonbmp_encmap+7368,18,205},{__big5hkscs_nonbmp_encmap+7556,3,247}, +{__big5hkscs_nonbmp_encmap+7801,38,147},{__big5hkscs_nonbmp_encmap+7911,102, +232},{__big5hkscs_nonbmp_encmap+8042,14,206},{__big5hkscs_nonbmp_encmap+8235, +38,201},{__big5hkscs_nonbmp_encmap+8399,7,238},{__big5hkscs_nonbmp_encmap+8631 +,13,239},{__big5hkscs_nonbmp_encmap+8858,116,227},{__big5hkscs_nonbmp_encmap+ +8970,51,218},{__big5hkscs_nonbmp_encmap+9138,3,249},{__big5hkscs_nonbmp_encmap ++9385,15,225},{__big5hkscs_nonbmp_encmap+9596,0,254},{ +__big5hkscs_nonbmp_encmap+9851,0,229},{__big5hkscs_nonbmp_encmap+10081,25,243 +},{__big5hkscs_nonbmp_encmap+10300,0,238},{__big5hkscs_nonbmp_encmap+10539,3, +215},{__big5hkscs_nonbmp_encmap+10752,58,58},{__big5hkscs_nonbmp_encmap+10753, +194,194},{__big5hkscs_nonbmp_encmap+10754,167,250},{__big5hkscs_nonbmp_encmap+ +10838,26,90},{__big5hkscs_nonbmp_encmap+10903,99,255},{ +__big5hkscs_nonbmp_encmap+11060,64,248},{__big5hkscs_nonbmp_encmap+11245,6,252 +},{__big5hkscs_nonbmp_encmap+11492,53,240},{__big5hkscs_nonbmp_encmap+11680, +17,236},{__big5hkscs_nonbmp_encmap+11900,4,252},{__big5hkscs_nonbmp_encmap+ +12149,27,250},{__big5hkscs_nonbmp_encmap+12373,13,248},{ +__big5hkscs_nonbmp_encmap+12609,4,214},{__big5hkscs_nonbmp_encmap+12820,5,200 +},{__big5hkscs_nonbmp_encmap+13016,24,212},{__big5hkscs_nonbmp_encmap+13205,6, +224},{__big5hkscs_nonbmp_encmap+13424,18,255},{__big5hkscs_nonbmp_encmap+13662 +,0,251},{__big5hkscs_nonbmp_encmap+13914,14,233},{__big5hkscs_nonbmp_encmap+ +14134,15,245},{__big5hkscs_nonbmp_encmap+14365,9,217},{ +__big5hkscs_nonbmp_encmap+14574,6,235},{__big5hkscs_nonbmp_encmap+14804,59,167 +},{__big5hkscs_nonbmp_encmap+14913,14,194},{__big5hkscs_nonbmp_encmap+15094, +44,157},{__big5hkscs_nonbmp_encmap+15208,43,231},{__big5hkscs_nonbmp_encmap+ +15397,32,216},{__big5hkscs_nonbmp_encmap+15582,14,19},{ +__big5hkscs_nonbmp_encmap+15588,25,154},{__big5hkscs_nonbmp_encmap+15718,49, +224},{__big5hkscs_nonbmp_encmap+15894,5,246},{__big5hkscs_nonbmp_encmap+16136, +6,225},{__big5hkscs_nonbmp_encmap+16356,87,225},{__big5hkscs_nonbmp_encmap+ +16495,3,204},{__big5hkscs_nonbmp_encmap+16697,84,233},{ +__big5hkscs_nonbmp_encmap+16847,116,232},{__big5hkscs_nonbmp_encmap+16964,1, +254},{__big5hkscs_nonbmp_encmap+17218,32,67},{__big5hkscs_nonbmp_encmap+17254, +14,216},{__big5hkscs_nonbmp_encmap+17457,26,226},{__big5hkscs_nonbmp_encmap+ +17658,41,165},{__big5hkscs_nonbmp_encmap+17783,2,221},{ +__big5hkscs_nonbmp_encmap+18003,88,208},{__big5hkscs_nonbmp_encmap+18124,53, +248},{__big5hkscs_nonbmp_encmap+18320,2,152},{__big5hkscs_nonbmp_encmap+18471, +18,191},{__big5hkscs_nonbmp_encmap+18645,18,252},{__big5hkscs_nonbmp_encmap+ +18880,22,204},{__big5hkscs_nonbmp_encmap+19063,28,199},{ +__big5hkscs_nonbmp_encmap+19235,14,250},{__big5hkscs_nonbmp_encmap+19472,45,82 +},{__big5hkscs_nonbmp_encmap+19510,5,247},{__big5hkscs_nonbmp_encmap+19753,33, +209},{__big5hkscs_nonbmp_encmap+19930,34,240},{__big5hkscs_nonbmp_encmap+20137 +,0,215},{__big5hkscs_nonbmp_encmap+20353,38,223},{__big5hkscs_nonbmp_encmap+ +20539,14,248},{__big5hkscs_nonbmp_encmap+20774,9,205},{ +__big5hkscs_nonbmp_encmap+20971,27,230},{__big5hkscs_nonbmp_encmap+21175,82, +255},{__big5hkscs_nonbmp_encmap+21349,34,134},{__big5hkscs_nonbmp_encmap+21450 +,116,254},{__big5hkscs_nonbmp_encmap+21589,7,148},{__big5hkscs_nonbmp_encmap+ +21731,15,204},{__big5hkscs_nonbmp_encmap+21921,88,200},{ +__big5hkscs_nonbmp_encmap+22034,36,253},{__big5hkscs_nonbmp_encmap+22252,10, +244},{__big5hkscs_nonbmp_encmap+22487,6,244},{__big5hkscs_nonbmp_encmap+22726, +18,197},{__big5hkscs_nonbmp_encmap+22906,47,220},{__big5hkscs_nonbmp_encmap+ +23080,77,79},{__big5hkscs_nonbmp_encmap+23083,46,249},{ +__big5hkscs_nonbmp_encmap+23287,2,244},{__big5hkscs_nonbmp_encmap+23530,46,188 +},{__big5hkscs_nonbmp_encmap+23673,7,226},{__big5hkscs_nonbmp_encmap+23893,6, +138},{__big5hkscs_nonbmp_encmap+24026,18,130},{__big5hkscs_nonbmp_encmap+24139 +,1,244},{__big5hkscs_nonbmp_encmap+24383,0,230},{__big5hkscs_nonbmp_encmap+ +24614,15,19},{__big5hkscs_nonbmp_encmap+24619,4,43},{__big5hkscs_nonbmp_encmap ++24659,51,252},{__big5hkscs_nonbmp_encmap+24861,15,252},{ +__big5hkscs_nonbmp_encmap+25099,12,255},{__big5hkscs_nonbmp_encmap+25343,3,210 +},{__big5hkscs_nonbmp_encmap+25551,52,185},{__big5hkscs_nonbmp_encmap+25685, +15,231},{__big5hkscs_nonbmp_encmap+25902,197,197},{__big5hkscs_nonbmp_encmap+ +25903,121,237},{__big5hkscs_nonbmp_encmap+26020,13,235},{0,0,0},{0,0,0},{ +__big5hkscs_nonbmp_encmap+26243,29,231},{__big5hkscs_nonbmp_encmap+26446,158, +244},{0,0,0},{__big5hkscs_nonbmp_encmap+26533,32,212},{ +__big5hkscs_nonbmp_encmap+26714,16,250},{__big5hkscs_nonbmp_encmap+26949,3,201 +},{__big5hkscs_nonbmp_encmap+27148,40,77},{__big5hkscs_nonbmp_encmap+27186,5, +213},{__big5hkscs_nonbmp_encmap+27395,115,173},{__big5hkscs_nonbmp_encmap+ +27454,62,246},{__big5hkscs_nonbmp_encmap+27639,6,248},{ +__big5hkscs_nonbmp_encmap+27882,35,222},{__big5hkscs_nonbmp_encmap+28070,20, +254},{__big5hkscs_nonbmp_encmap+28305,7,245},{__big5hkscs_nonbmp_encmap+28544, +32,255},{__big5hkscs_nonbmp_encmap+28768,81,169},{__big5hkscs_nonbmp_encmap+ +28857,52,91},{__big5hkscs_nonbmp_encmap+28897,198,203},{ +__big5hkscs_nonbmp_encmap+28903,1,169},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__big5hkscs_nonbmp_encmap+29072,37,205},{__big5hkscs_nonbmp_encmap+29241,148, +212},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + diff --git a/pypy/translator/c/src/cjkcodecs/mappings_jisx0213_pair.h b/pypy/translator/c/src/cjkcodecs/mappings_jisx0213_pair.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/mappings_jisx0213_pair.h @@ -0,0 +1,59 @@ +#define JISX0213_ENCPAIRS 46 +#ifdef EXTERN_JISX0213_PAIR +static const struct widedbcs_index *jisx0213_pair_decmap; +static const struct pair_encodemap *jisx0213_pair_encmap; +#else +static const ucs4_t __jisx0213_pair_decmap[49] = { +810234010,810365082,810496154,810627226,810758298,816525466,816656538, +816787610,816918682,817049754,817574042,818163866,818426010,838283418, +15074048,U,U,U,39060224,39060225,42730240,42730241,39387904,39387905,39453440, +39453441,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,48825061,48562921, +}; + +static const struct widedbcs_index jisx0213_pair_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_pair_decmap ++0,119,123},{__jisx0213_pair_decmap+5,119,126},{__jisx0213_pair_decmap+13,120, +120},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_pair_decmap+14,68,102},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const struct pair_encodemap jisx0213_pair_encmap[JISX0213_ENCPAIRS] = { +{0x00e60000,0x295c},{0x00e60300,0x2b44},{0x02540000,0x2b38},{0x02540300,0x2b48 +},{0x02540301,0x2b49},{0x02590000,0x2b30},{0x02590300,0x2b4c},{0x02590301, +0x2b4d},{0x025a0000,0x2b43},{0x025a0300,0x2b4e},{0x025a0301,0x2b4f},{ +0x028c0000,0x2b37},{0x028c0300,0x2b4a},{0x028c0301,0x2b4b},{0x02e50000,0x2b60 +},{0x02e502e9,0x2b66},{0x02e90000,0x2b64},{0x02e902e5,0x2b65},{0x304b0000, +0x242b},{0x304b309a,0x2477},{0x304d0000,0x242d},{0x304d309a,0x2478},{ +0x304f0000,0x242f},{0x304f309a,0x2479},{0x30510000,0x2431},{0x3051309a,0x247a +},{0x30530000,0x2433},{0x3053309a,0x247b},{0x30ab0000,0x252b},{0x30ab309a, +0x2577},{0x30ad0000,0x252d},{0x30ad309a,0x2578},{0x30af0000,0x252f},{ +0x30af309a,0x2579},{0x30b10000,0x2531},{0x30b1309a,0x257a},{0x30b30000,0x2533 +},{0x30b3309a,0x257b},{0x30bb0000,0x253b},{0x30bb309a,0x257c},{0x30c40000, +0x2544},{0x30c4309a,0x257d},{0x30c80000,0x2548},{0x30c8309a,0x257e},{ +0x31f70000,0x2675},{0x31f7309a,0x2678}, +}; +#endif diff --git a/pypy/translator/c/src/cjkcodecs/mappings_jp.h b/pypy/translator/c/src/cjkcodecs/mappings_jp.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/mappings_jp.h @@ -0,0 +1,4765 @@ +static const ucs2_t __jisx0208_decmap[6956] = { +12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,180, +65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,12293,12294, +12295,12540,8213,8208,65295,92,12316,8214,65372,8230,8229,8216,8217,8220,8221, +65288,65289,12308,12309,65339,65341,65371,65373,12296,12297,12298,12299,12300, +12301,12302,12303,12304,12305,65291,8722,177,215,247,65309,8800,65308,65310, +8806,8807,8734,8756,9794,9792,176,8242,8243,8451,65509,65284,162,163,65285, +65283,65286,65290,65312,167,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651, +9650,9661,9660,8251,12306,8594,8592,8593,8595,12307,U,U,U,U,U,U,U,U,U,U,U, +8712,8715,8838,8839,8834,8835,8746,8745,U,U,U,U,U,U,U,U,8743,8744,172,8658, +8660,8704,8707,U,U,U,U,U,U,U,U,U,U,U,8736,8869,8978,8706,8711,8801,8786,8810, +8811,8730,8765,8733,8757,8747,8748,U,U,U,U,U,U,U,8491,8240,9839,9837,9834, +8224,8225,182,U,U,U,U,9711,65296,65297,65298,65299,65300,65301,65302,65303, +65304,65305,U,U,U,U,U,U,U,65313,65314,65315,65316,65317,65318,65319,65320, +65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333, +65334,65335,65336,65337,65338,U,U,U,U,U,U,65345,65346,65347,65348,65349,65350, +65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363, +65364,65365,65366,65367,65368,65369,65370,12353,12354,12355,12356,12357,12358, +12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371, +12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384, +12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397, +12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410, +12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423, +12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,12449, +12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462, +12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475, +12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488, +12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501, +12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514, +12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527, +12528,12529,12530,12531,12532,12533,12534,913,914,915,916,917,918,919,920,921, +922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,U,U,U,U,U,U,U,U, +945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964, +965,966,967,968,969,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049, +1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064, +1065,1066,1067,1068,1069,1070,1071,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,1072,1073, +1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087, +1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102, +1103,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487, +9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520, +9509,9528,9538,20124,21782,23043,38463,21696,24859,25384,23030,36898,33909, +33564,31312,24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201, +23451,22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353, +26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,22996, +23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,32173,32239, +32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,32946,37057,30959, +19968,22769,28322,36920,31282,33576,33419,39983,20801,21360,21693,21729,22240, +23035,24341,39154,28139,32996,34093,38498,38512,38560,38907,21515,21491,23431, +28879,32701,36802,38632,21359,40284,31418,19985,30867,33276,28198,22040,21764, +27421,34074,39995,23013,21417,28006,29916,38287,22082,20113,36939,38642,33615, +39180,21473,21942,23344,24433,26144,26355,26628,27704,27891,27945,29787,30408, +31310,38964,33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234, +38322,27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839, +28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,40219, +22633,26044,27738,29989,20985,22830,22885,24448,24540,25276,26106,27178,27431, +27572,29579,32705,35158,40236,40206,40644,23713,27798,33659,20740,23627,25014, +33222,26742,29281,20057,20474,21368,24681,28201,31311,38899,19979,21270,20206, +20309,20285,20385,20339,21152,21487,22025,22799,23233,23478,23521,31185,26247, +26524,26550,27468,27827,28779,29634,31117,31166,31292,31623,33457,33499,33540, +33655,33775,33747,34662,35506,22057,36008,36838,36942,38686,34442,20420,23784, +25105,29273,30011,33253,33469,34558,36032,38597,39187,39381,20171,20250,35299, +22238,22602,22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,39745, +26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,35997,20977, +21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,34903,35442,37799, +39608,28012,39336,34521,22435,26623,34510,37390,21123,22151,21508,24275,25313, +25785,26684,26680,27579,29554,30906,31339,35226,35282,36203,36611,37101,38307, +38548,38761,23398,23731,27005,38989,38990,25499,31520,27179,27263,26806,39949, +28511,21106,21917,24688,25324,27963,28167,28369,33883,35088,36676,19988,39993, +21494,26907,27194,38788,26666,20828,31427,33970,37340,37772,22107,40232,26658, +33541,33841,31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223, +24059,21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022, +25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,29976, +30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,35251,35532, +36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,20024,21547,23736, +24012,29609,30284,30524,23721,32747,36107,38593,38929,38996,39000,20225,20238, +21361,21916,22120,22522,22855,23305,23492,23696,24076,24190,24524,25582,26426, +26071,26082,26399,26827,26820,27231,24112,27589,27671,27773,30079,31048,23395, +31232,32000,24509,35215,35352,36020,36215,36556,36637,39138,39438,39740,20096, +20605,20736,22931,23452,25135,25216,25836,27450,29344,30097,31047,32681,34811, +35516,35696,25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485, +40653,21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470, +24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,32026, +31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,34394,35377, +36317,37624,28417,31142,39770,20136,20139,20140,20379,20384,20689,20807,31478, +20849,20982,21332,21281,21375,21483,21932,22659,23777,24375,24394,24623,24656, +24685,25375,25945,27211,27841,29378,29421,30703,33016,33029,33288,34126,37111, +37857,38911,39255,39514,20208,20957,23597,26241,26989,23616,26354,26997,29577, +26704,31873,20677,21220,22343,24062,37670,26020,27427,27453,29748,31105,31165, +31563,32202,33465,33740,34943,35167,35641,36817,37329,21535,37504,20061,20534, +21477,21306,29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398, +21936,31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,25496,31391, +27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,37740,21234,21531, +34219,35347,32676,36557,37089,21350,34952,31041,20418,20670,21009,20804,21843, +22317,29674,22411,22865,24418,24452,24693,24950,24935,25001,25522,25658,25964, +26223,26690,28179,30054,31293,31995,32076,32153,32331,32619,33550,33610,34509, +35336,35427,35686,36605,38938,40335,33464,36814,39912,21127,25119,25731,28608, +38553,26689,20625,27424,27770,28500,31348,32080,34880,35363,26376,20214,20537, +20518,20581,20860,21048,21091,21927,22287,22533,23244,24314,25010,25080,25331, +25458,26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609, +36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,24358, +28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,21476,21628, +22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,29392,31946,34996, +32929,32993,33776,34382,35463,36328,37431,38599,39015,40723,20116,20114,20237, +21320,21577,21566,23087,24460,24481,24735,26791,27278,29786,30849,35486,35492, +35703,37264,20062,39881,20132,20348,20399,20505,20502,20809,20844,21151,21177, +21246,21402,21475,21521,21518,21897,22353,22434,22909,23380,23389,23439,24037, +24039,24055,24184,24195,24218,24247,24344,24658,24908,25239,25304,25511,25915, +26114,26179,26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002, +30343,30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108, +33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,37628, +38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,25335,28640, +35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,40658,29508,28425, +33136,29969,24573,24794,39592,29403,36796,27492,38915,20170,22256,22372,22718, +23130,24680,25031,26127,26118,26681,26801,28151,30165,32058,33390,39746,20123, +20304,21449,21766,23919,24038,24046,26619,27801,29811,30722,35408,37782,35039, +22352,24231,25387,20661,20652,20877,26368,21705,22622,22971,23472,24425,25165, +25505,26685,27507,28168,28797,37319,29312,30741,30758,31085,25998,32048,33756, +35009,36617,38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018, +32948,21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613, +31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,23519,25334,25774, +25830,26413,27578,34217,38609,30352,39894,25420,37638,39851,30399,26194,19977, +20632,21442,23665,24808,25746,25955,26719,29158,29642,29987,31639,32386,34453, +35715,36059,37240,39184,26028,26283,27531,20181,20180,20282,20351,21050,21496, +21490,21987,22235,22763,22987,22985,23039,23376,23629,24066,24107,24535,24605, +25351,25903,23388,26031,26045,26088,26525,27490,27515,27663,29509,31049,31169, +31992,32025,32043,32930,33026,33267,35222,35422,35433,35430,35468,35566,36039, +36060,38604,39164,27503,20107,20284,20365,20816,23383,23546,24904,25345,26178, +27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,36766, +27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,22519,22833, +23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,20594,26612,33437, +23649,34122,32286,33294,20889,23556,25448,36198,26012,29038,31038,32023,32773, +35613,36554,36974,34503,37034,20511,21242,23610,26451,28796,29237,37196,37320, +37675,33509,23490,24369,24825,20027,21462,23432,25163,26417,27530,29417,29664, +31278,33131,36259,37202,39318,20754,21463,21610,23551,25480,27193,32172,38656, +22234,21454,21608,23447,23601,24030,20462,24833,25342,27954,31168,31179,32066, +32333,32722,33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228, +38598,37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294, +37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,34899, +36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,26991,27529, +28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,21021,25152,26257, +26329,28186,24246,32210,32626,26360,34223,34295,35576,21161,21465,22899,24207, +24464,24661,37604,38500,20663,20767,21213,21280,21319,21484,21736,21830,21809, +22039,22888,22974,23100,23477,23558,23567,23569,23578,24196,24202,24288,24432, +25215,25220,25307,25484,25463,26119,26124,26157,26230,26494,26786,27167,27189, +27836,28040,28169,28248,28988,28966,29031,30151,30465,30813,30977,31077,31216, +31456,31505,31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412, +35443,35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055, +20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,29366, +30067,31331,33976,35698,37304,37664,22065,22516,39166,25325,26893,27542,29165, +32340,32887,33394,35302,39135,34645,36785,23611,20280,20449,20405,21767,23072, +23517,23529,24515,24910,25391,26032,26187,26862,27035,28024,28145,30003,30137, +30495,31070,31206,32051,33251,33455,34218,35242,35386,36523,36763,36914,37341, +38663,20154,20161,20995,22645,22764,23563,29978,23613,33102,35338,36805,38499, +38765,31525,35535,38920,37218,22259,21416,36887,21561,22402,24101,25512,27700, +28810,30561,31883,32736,34928,36930,37204,37648,37656,38543,29790,39620,23815, +23913,25968,26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,28548, +25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,24615,25104, +25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,30427,31934,32854, +22768,35069,35199,35488,35475,35531,36893,37266,38738,38745,25993,31246,33030, +38587,24109,24796,25114,26021,26132,26512,30707,31309,31821,32318,33034,36012, +36196,36321,36447,30889,20999,25305,25509,25666,25240,35373,31363,31680,35500, +38634,32118,33292,34633,20185,20808,21315,21344,23459,23554,23574,24029,25126, +25159,25776,26643,26676,27849,27973,27927,26579,28508,29006,29053,26059,31359, +31661,32218,32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983, +37549,37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950, +22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,31199, +31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,21474,20489, +21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,25475,25407,25531, +25805,26089,26361,24035,27085,27133,28437,29157,20105,30185,30456,31379,31967, +32207,32156,32865,33609,33624,33900,33980,34299,35013,36208,36865,36973,37783, +38684,39442,20687,22679,24974,33235,34101,36104,36896,20419,20596,21063,21363, +24687,25417,26463,28204,36275,36895,20439,23646,36042,26063,32154,21330,34966, +20854,25539,23384,23403,23562,25613,26449,36956,20182,22810,22826,27760,35409, +21822,22549,22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534, +23550,32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151, +33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,37261, +38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,28655,29730, +35351,37944,28609,35582,33592,20967,34552,21482,21481,20294,36948,36784,22890, +33073,24061,31466,36799,26842,35895,29432,40008,27197,35504,20025,21336,22022, +22374,25285,25506,26086,27470,28129,28251,28845,30701,31471,31658,32187,32829, +32966,34507,35477,37723,22243,22727,24382,26029,26262,27264,27573,30007,35527, +20516,30693,22320,24347,24677,26234,27744,30196,31258,32622,33268,34584,36933, +39347,31689,30044,31481,31569,33988,36880,31209,31378,33590,23265,30528,20013, +20210,23449,24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376, +27159,28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,24086,24115, +24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,29266,30010,30522, +32884,33081,33144,34678,35519,35548,36229,36339,37530,38263,38914,40165,21189, +25431,30452,26389,27784,29645,36035,37806,38515,27941,22684,26894,27084,36861, +37786,30171,36890,22618,26626,25524,27131,20291,28460,26584,36795,34086,32180, +37716,26943,28528,22378,22775,23340,32044,29226,21514,37347,40372,20141,20302, +20572,20597,21059,35998,21576,22564,23450,24093,24213,24237,24311,24351,24716, +25269,25402,25552,26799,27712,30855,31118,31243,32224,33351,35330,35558,36420, +36883,37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969, +37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,24215, +28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,38651,20814, +21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,33759,36077,36884, +37117,37709,30757,30778,21162,24230,22303,22900,24594,20498,20826,20908,20941, +20992,21776,22612,22616,22871,23445,23798,23947,24764,25237,25645,26481,26691, +26812,26847,30423,28120,28271,28059,28783,29128,24403,30168,31095,31561,31572, +31570,31958,32113,21040,33891,34153,34276,35342,35588,35910,36367,36867,36879, +37913,38518,38957,39472,38360,20685,21205,21516,22530,23566,24999,25758,27934, +30643,31461,33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305, +30563,31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182, +33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,21585, +26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,37707,26978, +39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,24336,36841,21250, +36049,32905,34425,24319,26085,20083,20837,22914,23615,38894,20219,22922,24525, +35469,28641,31152,31074,23527,33905,29483,29105,24180,24565,25467,25754,29123, +31896,20035,24316,20043,22492,22178,24745,28611,32013,33021,33075,33215,36786, +35223,34468,24052,25226,25773,35207,26487,27874,27966,29750,30772,23110,32629, +33453,39340,20467,24259,25309,25490,25943,26479,30403,29260,32972,32954,36649, +37197,20493,22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889, +34687,31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893, +33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,20989,31665,30834, +31672,32903,31560,27368,24161,32908,30033,30048,20843,37474,28300,30330,37271, +39658,20240,32624,25244,31567,38309,40169,22138,22617,34532,38588,20276,21028, +21322,21453,21467,24070,25644,26001,26495,27710,27726,29256,29359,29677,30036, +32321,33324,34281,36009,31684,37318,29033,38930,39151,25405,26217,30058,30436, +30928,34115,34542,21290,21329,21542,22915,24199,24444,24754,25161,25209,25259, +26000,27604,27852,30130,30382,30865,31192,32203,32631,32933,34987,35513,36027, +36991,38750,39131,27147,31800,20633,23614,24494,26503,27608,29749,30473,32654, +40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,30050, +31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,27703,28418, +29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,37672,37618,33948, +34541,39981,21697,24428,25996,27996,28693,36007,36051,38971,25935,29942,19981, +20184,22496,22827,23142,23500,20904,24067,24220,24598,25206,25975,26023,26222, +28014,29238,31526,33104,33178,33433,35676,36000,36070,36212,38428,38468,20398, +25771,27494,33310,33889,34154,37096,23553,26963,39080,33914,34135,20239,21103, +24489,24133,26381,31119,33145,35079,35206,28149,24343,25173,27832,20175,29289, +39826,20998,21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640, +25991,32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281, +38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,22793, +29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,20445,33303, +37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,24917,25098,26286, +27597,31807,33769,20515,20472,21253,21574,22577,22857,23453,23792,23791,23849, +24214,25265,25447,25918,26041,26379,27861,27873,28921,30770,32299,32990,33459, +33804,34028,34562,35090,35370,35914,37030,37586,39165,40179,40300,20047,20129, +20621,21078,22346,22952,24125,24536,24537,25151,26292,26395,26576,26834,20882, +32033,32938,33192,35584,35980,36031,37502,38450,21536,38956,21271,20693,21340, +22696,25778,26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868, +26412,32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598, +21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,25273, +26411,27819,36804,20397,32365,40639,19975,24930,28288,28459,34067,21619,26410, +39749,24051,31637,23724,23494,34588,28234,34001,31252,33032,22937,31885,27665, +30496,21209,22818,28961,29279,30683,38695,40289,26891,23167,23064,20901,21517, +21629,26126,30431,36855,37528,40180,23018,29277,28357,20813,26825,32191,32236, +38754,40634,25720,27169,33538,22916,23391,27611,29467,30450,32178,32791,33945, +20786,26408,40665,30446,26466,21247,39173,23588,25147,31870,36016,21839,24758, +32011,38272,21249,20063,20918,22812,29242,32822,37326,24357,30690,21380,24441, +32004,34220,35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,35565, +36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,26377,26586, +28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,37109,38596,34701, +22805,20104,20313,19982,35465,36671,38928,20653,24188,22934,23481,24248,25562, +25594,25793,26332,26954,27096,27915,28342,29076,29992,31407,32650,32768,33865, +33993,35201,35617,36362,36965,38525,39178,24958,25233,27442,27779,28020,32716, +32764,28096,32645,34746,35064,26469,33713,38972,38647,27931,32097,33853,37226, +20081,21365,23888,27396,28651,34253,34349,35239,21033,21519,23653,26446,26792, +29702,29827,30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504, +30053,21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942, +26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,30274, +30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,20523,21400, +26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,22593,28057,32047, +39006,20196,20278,20363,20919,21169,23994,24604,29618,31036,33491,37428,38583, +38646,38666,40599,40802,26278,27508,21015,21155,28872,35010,24265,24651,24976, +28451,29001,31806,32244,32879,34030,36899,37676,21570,39791,27347,28809,36034, +36335,38706,21172,23105,24266,24324,26391,27004,27028,28010,28431,29282,29436, +31725,32769,32894,34635,37070,20845,40595,31108,32907,37682,35542,20525,21644, +35441,27498,36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152, +26880,28286,30871,33109,24332,19984,19989,20010,20017,20022,20028,20031,20034, +20054,20056,20098,20101,35947,20106,33298,24333,20110,20126,20127,20128,20130, +20144,20147,20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215, +20233,20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329, +20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,20442, +20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,20513,20521, +20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,20552,20570,20566, +20588,20600,20608,20634,20613,20660,20658,20681,20682,20659,20674,20694,20702, +20709,20717,20707,20718,20729,20725,20745,20737,20738,20758,20757,20756,20762, +20769,20794,20791,20796,20795,20799,20800,20818,20812,20820,20834,31480,20841, +20842,20846,20864,20866,22232,20876,20873,20879,20881,20883,20885,20886,20900, +20902,20898,20905,20906,20907,20915,20913,20914,20912,20917,20925,20933,20937, +20955,20960,34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031, +21034,21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097, +21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,36775,21164,21165, +21180,21173,21185,21197,21207,21214,21219,21222,39149,21216,21235,21237,21240, +21241,21254,21256,30008,21261,21264,21263,21269,21274,21283,21295,21297,21299, +21304,21312,21318,21317,19991,21321,21325,20950,21342,21353,21358,22808,21371, +21367,21378,21398,21408,21414,21413,21422,21424,21430,21443,31762,38617,21471, +26364,29166,21486,21480,21485,21498,21505,21565,21568,21548,21549,21564,21550, +21558,21545,21533,21582,21647,21621,21646,21599,21617,21623,21616,21650,21627, +21632,21622,21636,21648,21638,21703,21666,21688,21669,21676,21700,21704,21672, +21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,21741, +21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,21816,21811, +21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,21934,21884,21891, +21929,21895,21928,21978,21957,21983,21956,21980,21988,21972,22036,22007,22038, +22014,22013,22043,22009,22094,22096,29151,22068,22070,22066,22072,22123,22116, +22063,22124,22122,22150,22144,22154,22176,22164,22159,22181,22190,22198,22196, +22210,22204,22209,22211,22208,22216,22222,22225,22227,22231,22254,22265,22272, +22271,22276,22281,22280,22283,22285,22291,22296,22294,21959,22300,22310,22327, +22328,22350,22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432, +22451,22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539, +22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,22713, +22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,22745,22744, +22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,22786,22794,22800, +22811,26790,22821,22828,22829,22834,22840,22846,31442,22869,22864,22862,22874, +22872,22882,22880,22887,22892,22889,22904,22913,22941,20318,20395,22947,22962, +22982,23016,23004,22925,23001,23002,23077,23071,23057,23068,23049,23066,23104, +23148,23113,23093,23094,23138,23146,23194,23228,23230,23243,23234,23229,23267, +23255,23270,23273,23254,23290,23291,23308,23307,23318,23346,23248,23338,23350, +23358,23363,23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413, +23416,25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524, +23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,23571, +23584,23586,23592,23608,23609,23617,23622,23630,23635,23632,23631,23409,23660, +23662,20066,23670,23673,23692,23697,23700,22939,23723,23739,23734,23740,23735, +23749,23742,23751,23769,23785,23805,23802,23789,23948,23786,23819,23829,23831, +23900,23839,23835,23825,23828,23842,23834,23833,23832,23884,23890,23886,23883, +23916,23923,23926,23943,23940,23938,23970,23965,23980,23982,23997,23952,23991, +23996,24009,24013,24019,24018,24022,24027,24043,24050,24053,24075,24090,24089, +24081,24091,24118,24119,24132,24131,24128,24142,24151,24148,24159,24162,24164, +24135,24181,24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,24278, +24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,24304,24308, +24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,24365,24376,24385, +24392,24396,24398,24367,24401,24406,24407,24409,24417,24429,24435,24439,24451, +24450,24447,24458,24456,24465,24455,24478,24473,24472,24480,24488,24493,24508, +24534,24571,24548,24568,24561,24541,24755,24575,24609,24672,24601,24592,24617, +24590,24625,24603,24597,24619,24614,24591,24634,24666,24641,24682,24695,24671, +24650,24646,24653,24675,24643,24676,24642,24684,24683,24665,24705,24717,24807, +24707,24730,24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787, +24756,24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820, +24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,24895, +24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,24939,24948, +24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,25004,24980,24986, +24970,24977,25003,25006,25036,25034,25033,25079,25032,25027,25030,25018,25035, +32633,25037,25062,25059,25078,25082,25076,25087,25085,25084,25086,25088,25096, +25097,25101,25100,25108,25115,25118,25121,25130,25134,25136,25138,25139,25153, +25166,25182,25187,25179,25184,25192,25212,25218,25225,25214,25234,25235,25238, +25300,25219,25236,25303,25297,25275,25295,25343,25286,25812,25288,25308,25292, +25290,25282,25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333, +25424,25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481, +25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,25540, +25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,25711,25718, +25678,25898,25749,25747,25765,25769,25736,25788,25818,25810,25797,25799,25787, +25816,25794,25841,25831,33289,25824,25825,25260,25827,25839,25900,25846,25844, +25842,25850,25856,25853,25880,25884,25861,25892,25891,25899,25908,25909,25911, +25910,25912,30027,25928,25942,25941,25933,25944,25950,25949,25970,25976,25986, +25987,35722,26011,26015,26027,26039,26051,26054,26049,26052,26060,26066,26075, +26073,26080,26081,26097,26482,26122,26115,26107,26483,26165,26166,26164,26140, +26191,26180,26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243, +26248,26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,26308,26296, +26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,26390,26398,26406, +26407,38712,26414,26431,26422,26433,26424,26423,26438,26462,26464,26457,26467, +26468,26505,26480,26537,26492,26474,26508,26507,26534,26529,26501,26551,26607, +26548,26604,26547,26601,26552,26596,26590,26589,26594,26606,26553,26574,26566, +26599,27292,26654,26694,26665,26688,26701,26674,26702,26803,26667,26713,26723, +26743,26751,26783,26767,26797,26772,26781,26779,26755,27310,26809,26740,26805, +26784,26810,26895,26765,26750,26881,26826,26888,26840,26914,26918,26849,26892, +26829,26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863, +26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,27006, +26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,27058,27054, +27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,27075,27047,27182, +27025,27040,27036,27029,27060,27102,27112,27138,27163,27135,27402,27129,27122, +27111,27141,27057,27166,27117,27156,27115,27146,27154,27329,27171,27155,27204, +27148,27250,27190,27256,27207,27234,27225,27238,27208,27192,27170,27280,27277, +27296,27268,27298,27299,27287,34327,27323,27331,27330,27320,27315,27308,27358, +27345,27359,27306,27354,27370,27387,27397,34326,27386,27410,27414,39729,27423, +27448,27447,30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487, +27489,27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562, +27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,27627, +27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,27746,27754, +27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,27844,27889,27859, +27837,27863,27845,27869,27822,27825,27838,27834,27867,27887,27865,27882,27935, +34893,27958,27947,27965,27960,27929,27957,27955,27922,27916,28003,28051,28004, +27994,28025,27993,28046,28053,28644,28037,28153,28181,28170,28085,28103,28134, +28088,28102,28140,28126,28108,28136,28114,28101,28154,28121,28132,28117,28138, +28142,28205,28270,28206,28185,28274,28255,28222,28195,28267,28203,28278,28237, +28191,28227,28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343, +28371,28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433, +28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,28478,28435,28407, +28550,28538,28536,28545,28544,28527,28507,28659,28525,28546,28540,28504,28558, +28561,28610,28518,28595,28579,28577,28580,28601,28614,28586,28639,28629,28652, +28628,28632,28657,28654,28635,28681,28683,28666,28689,28673,28687,28670,28699, +28698,28532,28701,28696,28703,28720,28734,28722,28753,28771,28825,28818,28847, +28913,28844,28856,28851,28846,28895,28875,28893,28889,28937,28925,28956,28953, +29029,29013,29064,29030,29026,29004,29014,29036,29071,29179,29060,29077,29096, +29100,29143,29113,29118,29138,29129,29140,29134,29152,29164,29159,29173,29180, +29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,29247, +29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,29346,29351, +29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,29433,29431,20495, +29463,29450,29468,29462,29469,29492,29487,29481,29477,29502,29518,29519,40664, +29527,29546,29544,29552,29560,29557,29563,29562,29640,29619,29646,29627,29632, +29669,29678,29662,29858,29701,29807,29733,29688,29746,29754,29781,29759,29791, +29785,29761,29788,29801,29808,29795,29802,29814,29822,29835,29854,29863,29898, +29903,29908,29681,29920,29923,29927,29929,29934,29938,29936,29937,29944,29943, +29956,29955,29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020, +30029,30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070, +30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,30131, +30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,30174,30206, +30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,30239,30247,30240, +30241,30242,30244,30260,30256,30267,30279,30280,30278,30300,30296,30305,30306, +30312,30313,30314,30311,30316,30320,30322,30326,30328,30332,30336,30339,30344, +30347,30350,30358,30355,30361,30362,30384,30388,30392,30393,30394,30402,30413, +30422,30418,30430,30433,30437,30439,30442,34351,30459,30472,30471,30468,30505, +30500,30494,30501,30502,30491,30519,30520,30535,30554,30568,30571,30555,30565, +30591,30590,30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652, +30653,30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014, +30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,30895, +30929,30918,30923,30932,30910,30908,30917,30922,30956,30951,30938,30973,30964, +30983,30994,30993,31001,31020,31019,31040,31072,31063,31071,31066,31061,31059, +31098,31103,31114,31133,31143,40779,31146,31150,31155,31161,31162,31177,31189, +31207,31212,31201,31203,31240,31245,31256,31257,31264,31263,31104,31281,31291, +31294,31287,31299,31319,31305,31329,31330,31337,40861,31344,31353,31357,31368, +31383,31381,31384,31382,31401,31432,31408,31414,31429,31428,31423,36995,31431, +31434,31437,31439,31445,31443,31449,31450,31453,31457,31458,31462,31469,31472, +31490,31503,31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,31610, +31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,31596,31598, +31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,31641,31691,31681, +31692,31695,31668,31686,31709,31721,31761,31764,31718,31717,31840,31744,31751, +31763,31731,31735,31767,31757,31734,31779,31783,31786,31775,31799,31787,31805, +31820,31811,31828,31823,31808,31824,31832,31839,31844,31830,31845,31852,31861, +31875,31888,31908,31917,31906,31915,31905,31912,31923,31922,31921,31918,31929, +31933,31936,31941,31938,31960,31954,31964,31970,39739,31983,31986,31988,31990, +31994,32006,32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070, +32115,32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125, +32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,32184, +32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,32291,32289, +32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,32313,32323,32311, +32306,32314,32359,32349,32342,32350,32345,32346,32377,32362,32361,32380,32379, +32387,32213,32381,36782,32383,32392,32393,32396,32402,32400,32403,32404,32406, +32398,32411,32412,32568,32570,32581,32588,32589,32590,32592,32593,32597,32596, +32600,32607,32608,32616,32617,32615,32632,32642,32646,32643,32648,32647,32652, +32660,32670,32669,32666,32675,32687,32690,32697,32686,32694,32696,35697,32709, +32710,32714,32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779, +32786,32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858, +32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,32901, +32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,32986,32982, +33033,33007,33009,33051,33065,33059,33071,33099,38539,33094,33086,33107,33105, +33020,33137,33134,33125,33126,33140,33155,33160,33162,33152,33154,33184,33173, +33188,33187,33119,33171,33193,33200,33205,33214,33208,33213,33216,33218,33210, +33225,33229,33233,33241,33240,33224,33242,33247,33248,33255,33274,33275,33278, +33281,33282,33285,33287,33290,33293,33296,33302,33321,33323,33336,33331,33344, +33369,33368,33373,33370,33375,33380,33378,33384,33386,33387,33326,33393,33399, +33400,33406,33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524, +33523,33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,33589,33588, +33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,33560,33669,33690, +33706,33695,33698,33686,33571,33678,33671,33674,33660,33717,33651,33653,33696, +33673,33704,33780,33811,33771,33742,33789,33795,33752,33803,33729,33783,33799, +33760,33778,33805,33826,33824,33725,33848,34054,33787,33901,33834,33852,34138, +33924,33911,33899,33965,33902,33922,33897,33862,33836,33903,33913,33845,33994, +33890,33977,33983,33951,34009,33997,33979,34010,34000,33985,33990,34006,33953, +34081,34047,34036,34071,34072,34092,34079,34069,34068,34044,34112,34147,34136, +34120,34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196, +34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,34261, +34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,34330,34352, +34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,34474,34443,34444, +34486,34479,34500,34502,34480,34505,34851,34475,34516,34526,34537,34540,34527, +34523,34543,34578,34566,34568,34560,34563,34555,34577,34569,34573,34553,34570, +34612,34623,34615,34619,34597,34601,34586,34656,34655,34680,34636,34638,34676, +34647,34664,34670,34649,34643,34659,34666,34821,34722,34719,34690,34735,34763, +34749,34752,34768,38614,34731,34756,34739,34759,34758,34747,34799,34802,34784, +34831,34829,34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865, +34870,34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942, +34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,34980, +34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,35068,35060, +35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,35115,35137,35140, +35131,35126,35128,35148,35101,35168,35166,35174,35172,35181,35178,35183,35188, +35191,35198,35203,35208,35210,35219,35224,35233,35241,35238,35244,35247,35250, +35258,35261,35263,35264,35290,35292,35293,35303,35316,35320,35331,35350,35344, +35340,35355,35357,35365,35382,35393,35419,35410,35398,35400,35452,35437,35436, +35426,35461,35458,35460,35496,35489,35473,35493,35494,35482,35491,35524,35533, +35522,35546,35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547, +35596,35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646, +35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,35679,35692,35695, +35700,35709,35712,35724,35726,35730,35731,35734,35737,35738,35898,35905,35903, +35912,35916,35918,35920,35925,35938,35948,35960,35962,35970,35977,35973,35978, +35981,35982,35988,35964,35992,25117,36013,36010,36029,36018,36019,36014,36022, +36040,36033,36068,36067,36058,36093,36090,36091,36100,36101,36106,36103,36111, +36109,36112,40782,36115,36045,36116,36118,36199,36205,36209,36211,36225,36249, +36290,36286,36282,36303,36314,36310,36300,36315,36299,36330,36331,36319,36323, +36348,36360,36361,36351,36381,36382,36368,36383,36418,36405,36400,36404,36426, +36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,36466, +36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,36522,36513, +36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,36604,36603,36587, +36606,36618,36613,36629,36626,36633,36627,36636,36639,36635,36620,36646,36659, +36667,36665,36677,36674,36670,36684,36681,36678,36686,36695,36700,36706,36707, +36708,36764,36767,36771,36781,36783,36791,36826,36837,36834,36842,36847,36999, +36852,36869,36857,36858,36881,36885,36897,36877,36894,36886,36875,36903,36918, +36917,36921,36856,36943,36944,36945,36946,36878,36937,36926,36950,36952,36958, +36968,36975,36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032, +37039,37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194, +37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,37295, +37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,37345,37339, +37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,37463,37445,37449, +37476,37448,37525,37439,37451,37456,37532,37526,37523,37531,37466,37583,37561, +37559,37609,37647,37626,37700,37678,37657,37666,37658,37667,37690,37685,37691, +37724,37728,37756,37742,37718,37808,37804,37805,37780,37817,37846,37847,37864, +37861,37848,37827,37853,37840,37832,37860,37914,37908,37907,37891,37895,37904, +37942,37931,37941,37921,37946,37953,37970,37956,37979,37984,37986,37982,37994, +37417,38000,38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282, +38292,38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346, +28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,38440, +38446,38447,38466,38476,38479,38475,38519,38492,38494,38493,38495,38502,38514, +38508,38541,38552,38549,38551,38570,38567,38577,38578,38576,38580,38582,38584, +38585,38606,38603,38601,38605,35149,38620,38669,38613,38649,38660,38662,38664, +38675,38670,38673,38671,38678,38681,38692,38698,38704,38713,38717,38718,38724, +38726,38728,38722,38729,38748,38752,38756,38758,38760,21202,38763,38769,38777, +38789,38780,38785,38778,38790,38795,38799,38800,38812,38824,38822,38819,38835, +38836,38851,38854,38856,38859,38876,38893,40783,38898,31455,38902,38901,38927, +38924,38968,38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,39025, +39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,39171,39177, +39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,39229,39230,39234, +39241,39237,39248,39243,39249,39250,39244,39253,39319,39320,39333,39341,39342, +39356,39391,39387,39389,39384,39377,39405,39406,39409,39410,39419,39416,39425, +39439,39429,39394,39449,39467,39479,39493,39490,39488,39491,39486,39509,39501, +39515,39511,39519,39522,39525,39524,39529,39531,39530,39597,39600,39612,39616, +39631,39633,39635,39636,39646,39647,39650,39651,39654,39663,39659,39662,39668, +39665,39671,39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721, +39722,39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827, +39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,39887, +39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,39957,39956, +39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,39973,39972,39969, +39984,40007,39986,40006,39998,40026,40032,40039,40054,40056,40167,40172,40176, +40201,40200,40171,40195,40198,40234,40230,40367,40227,40223,40260,40213,40210, +40257,40255,40254,40262,40264,40285,40286,40292,40273,40272,40281,40306,40329, +40327,40363,40303,40314,40346,40356,40361,40370,40388,40385,40379,40376,40378, +40390,40399,40386,40409,40403,40440,40422,40429,40431,40445,40474,40475,40478, +40565,40569,40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617, +40632,40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672, +40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,30391, +40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,40806,40807, +40812,40810,40823,40818,40822,40853,40860,40864,22575,27079,36953,29796,20956, +29081, +}; + +static const struct dbcs_index jisx0208_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0208_decmap+0,33,126},{__jisx0208_decmap ++94,33,126},{__jisx0208_decmap+188,48,122},{__jisx0208_decmap+263,33,115},{ +__jisx0208_decmap+346,33,118},{__jisx0208_decmap+432,33,88},{__jisx0208_decmap ++488,33,113},{__jisx0208_decmap+569,33,64},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{__jisx0208_decmap+601,33,126},{__jisx0208_decmap+695,33, +126},{__jisx0208_decmap+789,33,126},{__jisx0208_decmap+883,33,126},{ +__jisx0208_decmap+977,33,126},{__jisx0208_decmap+1071,33,126},{ +__jisx0208_decmap+1165,33,126},{__jisx0208_decmap+1259,33,126},{ +__jisx0208_decmap+1353,33,126},{__jisx0208_decmap+1447,33,126},{ +__jisx0208_decmap+1541,33,126},{__jisx0208_decmap+1635,33,126},{ +__jisx0208_decmap+1729,33,126},{__jisx0208_decmap+1823,33,126},{ +__jisx0208_decmap+1917,33,126},{__jisx0208_decmap+2011,33,126},{ +__jisx0208_decmap+2105,33,126},{__jisx0208_decmap+2199,33,126},{ +__jisx0208_decmap+2293,33,126},{__jisx0208_decmap+2387,33,126},{ +__jisx0208_decmap+2481,33,126},{__jisx0208_decmap+2575,33,126},{ +__jisx0208_decmap+2669,33,126},{__jisx0208_decmap+2763,33,126},{ +__jisx0208_decmap+2857,33,126},{__jisx0208_decmap+2951,33,126},{ +__jisx0208_decmap+3045,33,126},{__jisx0208_decmap+3139,33,126},{ +__jisx0208_decmap+3233,33,126},{__jisx0208_decmap+3327,33,126},{ +__jisx0208_decmap+3421,33,126},{__jisx0208_decmap+3515,33,83},{ +__jisx0208_decmap+3566,33,126},{__jisx0208_decmap+3660,33,126},{ +__jisx0208_decmap+3754,33,126},{__jisx0208_decmap+3848,33,126},{ +__jisx0208_decmap+3942,33,126},{__jisx0208_decmap+4036,33,126},{ +__jisx0208_decmap+4130,33,126},{__jisx0208_decmap+4224,33,126},{ +__jisx0208_decmap+4318,33,126},{__jisx0208_decmap+4412,33,126},{ +__jisx0208_decmap+4506,33,126},{__jisx0208_decmap+4600,33,126},{ +__jisx0208_decmap+4694,33,126},{__jisx0208_decmap+4788,33,126},{ +__jisx0208_decmap+4882,33,126},{__jisx0208_decmap+4976,33,126},{ +__jisx0208_decmap+5070,33,126},{__jisx0208_decmap+5164,33,126},{ +__jisx0208_decmap+5258,33,126},{__jisx0208_decmap+5352,33,126},{ +__jisx0208_decmap+5446,33,126},{__jisx0208_decmap+5540,33,126},{ +__jisx0208_decmap+5634,33,126},{__jisx0208_decmap+5728,33,126},{ +__jisx0208_decmap+5822,33,126},{__jisx0208_decmap+5916,33,126},{ +__jisx0208_decmap+6010,33,126},{__jisx0208_decmap+6104,33,126},{ +__jisx0208_decmap+6198,33,126},{__jisx0208_decmap+6292,33,126},{ +__jisx0208_decmap+6386,33,126},{__jisx0208_decmap+6480,33,126},{ +__jisx0208_decmap+6574,33,126},{__jisx0208_decmap+6668,33,126},{ +__jisx0208_decmap+6762,33,126},{__jisx0208_decmap+6856,33,126},{ +__jisx0208_decmap+6950,33,38},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const ucs2_t __jisx0212_decmap[6179] = { +728,711,184,729,733,175,731,730,126,900,901,U,U,U,U,U,U,U,U,161,166,191,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,186,170, +169,174,8482,164,8470,902,904,905,906,938,U,908,U,910,939,U,911,U,U,U,U,940, +941,942,943,970,912,972,962,973,971,944,974,1026,1027,1028,1029,1030,1031, +1032,1033,1034,1035,1036,1038,1039,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115, +1116,1118,1119,198,272,U,294,U,306,U,321,319,U,330,216,338,U,358,222,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,230,273,240,295,305,307,312,322,320,329,331,248,339, +223,359,254,193,192,196,194,258,461,256,260,197,195,262,264,268,199,266,270, +201,200,203,202,282,278,274,280,U,284,286,290,288,292,205,204,207,206,463,304, +298,302,296,308,310,313,317,315,323,327,325,209,211,210,214,212,465,336,332, +213,340,344,342,346,348,352,350,356,354,218,217,220,219,364,467,368,362,370, +366,360,471,475,473,469,372,221,376,374,377,381,379,225,224,228,226,259,462, +257,261,229,227,263,265,269,231,267,271,233,232,235,234,283,279,275,281,501, +285,287,U,289,293,237,236,239,238,464,U,299,303,297,309,311,314,318,316,324, +328,326,241,243,242,246,244,466,337,333,245,341,345,343,347,349,353,351,357, +355,250,249,252,251,365,468,369,363,371,367,361,472,476,474,470,373,253,255, +375,378,382,380,19970,19972,19973,19980,19986,19999,20003,20004,20008,20011, +20014,20015,20016,20021,20032,20033,20036,20039,20049,20058,20060,20067,20072, +20073,20084,20085,20089,20095,20109,20118,20119,20125,20143,20153,20163,20176, +20186,20187,20192,20193,20194,20200,20207,20209,20211,20213,20221,20222,20223, +20224,20226,20227,20232,20235,20236,20242,20245,20246,20247,20249,20270,20273, +20320,20275,20277,20279,20281,20283,20286,20288,20290,20296,20297,20299,20300, +20306,20308,20310,20312,20319,20323,20330,20332,20334,20337,20343,20344,20345, +20346,20349,20350,20353,20354,20356,20357,20361,20362,20364,20366,20368,20370, +20371,20372,20375,20377,20378,20382,20383,20402,20407,20409,20411,20412,20413, +20414,20416,20417,20421,20422,20424,20425,20427,20428,20429,20431,20434,20444, +20448,20450,20464,20466,20476,20477,20479,20480,20481,20484,20487,20490,20492, +20494,20496,20499,20503,20504,20507,20508,20509,20510,20514,20519,20526,20528, +20530,20531,20533,20544,20545,20546,20549,20550,20554,20556,20558,20561,20562, +20563,20567,20569,20575,20576,20578,20579,20582,20583,20586,20589,20592,20593, +20539,20609,20611,20612,20614,20618,20622,20623,20624,20626,20627,20628,20630, +20635,20636,20638,20639,20640,20641,20642,20650,20655,20656,20665,20666,20669, +20672,20675,20676,20679,20684,20686,20688,20691,20692,20696,20700,20701,20703, +20706,20708,20710,20712,20713,20719,20721,20726,20730,20734,20739,20742,20743, +20744,20747,20748,20749,20750,20722,20752,20759,20761,20763,20764,20765,20766, +20771,20775,20776,20780,20781,20783,20785,20787,20788,20789,20792,20793,20802, +20810,20815,20819,20821,20823,20824,20831,20836,20838,20862,20867,20868,20875, +20878,20888,20893,20897,20899,20909,20920,20922,20924,20926,20927,20930,20936, +20943,20945,20946,20947,20949,20952,20958,20962,20965,20974,20978,20979,20980, +20983,20993,20994,20997,21010,21011,21013,21014,21016,21026,21032,21041,21042, +21045,21052,21061,21065,21077,21079,21080,21082,21084,21087,21088,21089,21094, +21102,21111,21112,21113,21120,21122,21125,21130,21132,21139,21141,21142,21143, +21144,21146,21148,21156,21157,21158,21159,21167,21168,21174,21175,21176,21178, +21179,21181,21184,21188,21190,21192,21196,21199,21201,21204,21206,21211,21212, +21217,21221,21224,21225,21226,21228,21232,21233,21236,21238,21239,21248,21251, +21258,21259,21260,21265,21267,21272,21275,21276,21278,21279,21285,21287,21288, +21289,21291,21292,21293,21296,21298,21301,21308,21309,21310,21314,21324,21323, +21337,21339,21345,21347,21349,21356,21357,21362,21369,21374,21379,21383,21384, +21390,21395,21396,21401,21405,21409,21412,21418,21419,21423,21426,21428,21429, +21431,21432,21434,21437,21440,21445,21455,21458,21459,21461,21466,21469,21470, +21472,21478,21479,21493,21506,21523,21530,21537,21543,21544,21546,21551,21553, +21556,21557,21571,21572,21575,21581,21583,21598,21602,21604,21606,21607,21609, +21611,21613,21614,21620,21631,21633,21635,21637,21640,21641,21645,21649,21653, +21654,21660,21663,21665,21670,21671,21673,21674,21677,21678,21681,21687,21689, +21690,21691,21695,21702,21706,21709,21710,21728,21738,21740,21743,21750,21756, +21758,21759,21760,21761,21765,21768,21769,21772,21773,21774,21781,21802,21803, +21810,21813,21814,21819,21820,21821,21825,21831,21833,21834,21837,21840,21841, +21848,21850,21851,21854,21856,21857,21860,21862,21887,21889,21890,21894,21896, +21902,21903,21905,21906,21907,21908,21911,21923,21924,21933,21938,21951,21953, +21955,21958,21961,21963,21964,21966,21969,21970,21971,21975,21976,21979,21982, +21986,21993,22006,22015,22021,22024,22026,22029,22030,22031,22032,22033,22034, +22041,22060,22064,22067,22069,22071,22073,22075,22076,22077,22079,22080,22081, +22083,22084,22086,22089,22091,22093,22095,22100,22110,22112,22113,22114,22115, +22118,22121,22125,22127,22129,22130,22133,22148,22149,22152,22155,22156,22165, +22169,22170,22173,22174,22175,22182,22183,22184,22185,22187,22188,22189,22193, +22195,22199,22206,22213,22217,22218,22219,22223,22224,22220,22221,22233,22236, +22237,22239,22241,22244,22245,22246,22247,22248,22257,22251,22253,22262,22263, +22273,22274,22279,22282,22284,22289,22293,22298,22299,22301,22304,22306,22307, +22308,22309,22313,22314,22316,22318,22319,22323,22324,22333,22334,22335,22341, +22342,22348,22349,22354,22370,22373,22375,22376,22379,22381,22382,22383,22384, +22385,22387,22388,22389,22391,22393,22394,22395,22396,22398,22401,22403,22412, +22420,22423,22425,22426,22428,22429,22430,22431,22433,22421,22439,22440,22441, +22444,22456,22461,22471,22472,22476,22479,22485,22493,22494,22500,22502,22503, +22505,22509,22512,22517,22518,22520,22525,22526,22527,22531,22532,22536,22537, +22497,22540,22541,22555,22558,22559,22560,22566,22567,22573,22578,22585,22591, +22601,22604,22605,22607,22608,22613,22623,22625,22628,22631,22632,22648,22652, +22655,22656,22657,22663,22664,22665,22666,22668,22669,22671,22672,22676,22678, +22685,22688,22689,22690,22694,22697,22705,22706,22724,22716,22722,22728,22733, +22734,22736,22738,22740,22742,22746,22749,22753,22754,22761,22771,22789,22790, +22795,22796,22802,22803,22804,34369,22813,22817,22819,22820,22824,22831,22832, +22835,22837,22838,22847,22851,22854,22866,22867,22873,22875,22877,22878,22879, +22881,22883,22891,22893,22895,22898,22901,22902,22905,22907,22908,22923,22924, +22926,22930,22933,22935,22943,22948,22951,22957,22958,22959,22960,22963,22967, +22970,22972,22977,22979,22980,22984,22986,22989,22994,23005,23006,23007,23011, +23012,23015,23022,23023,23025,23026,23028,23031,23040,23044,23052,23053,23054, +23058,23059,23070,23075,23076,23079,23080,23082,23085,23088,23108,23109,23111, +23112,23116,23120,23125,23134,23139,23141,23143,23149,23159,23162,23163,23166, +23179,23184,23187,23190,23193,23196,23198,23199,23200,23202,23207,23212,23217, +23218,23219,23221,23224,23226,23227,23231,23236,23238,23240,23247,23258,23260, +23264,23269,23274,23278,23285,23286,23293,23296,23297,23304,23319,23348,23321, +23323,23325,23329,23333,23341,23352,23361,23371,23372,23378,23382,23390,23400, +23406,23407,23420,23421,23422,23423,23425,23428,23430,23434,23438,23440,23441, +23443,23444,23446,23464,23465,23468,23469,23471,23473,23474,23479,23482,23484, +23488,23489,23501,23503,23510,23511,23512,23513,23514,23520,23535,23537,23540, +23549,23564,23575,23582,23583,23587,23590,23593,23595,23596,23598,23600,23602, +23605,23606,23641,23642,23644,23650,23651,23655,23656,23657,23661,23664,23668, +23669,23674,23675,23676,23677,23687,23688,23690,23695,23698,23709,23711,23712, +23714,23715,23718,23722,23730,23732,23733,23738,23753,23755,23762,23773,23767, +23790,23793,23794,23796,23809,23814,23821,23826,23851,23843,23844,23846,23847, +23857,23860,23865,23869,23871,23874,23875,23878,23880,23893,23889,23897,23882, +23903,23904,23905,23906,23908,23914,23917,23920,23929,23930,23934,23935,23937, +23939,23944,23946,23954,23955,23956,23957,23961,23963,23967,23968,23975,23979, +23984,23988,23992,23993,24003,24007,24011,24016,24014,24024,24025,24032,24036, +24041,24056,24057,24064,24071,24077,24082,24084,24085,24088,24095,24096,24110, +24104,24114,24117,24126,24139,24144,24137,24145,24150,24152,24155,24156,24158, +24168,24170,24171,24172,24173,24174,24176,24192,24203,24206,24226,24228,24229, +24232,24234,24236,24241,24243,24253,24254,24255,24262,24268,24267,24270,24273, +24274,24276,24277,24284,24286,24293,24299,24322,24326,24327,24328,24334,24345, +24348,24349,24353,24354,24355,24356,24360,24363,24364,24366,24368,24372,24374, +24379,24381,24383,24384,24388,24389,24391,24397,24400,24404,24408,24411,24416, +24419,24420,24423,24431,24434,24436,24437,24440,24442,24445,24446,24457,24461, +24463,24470,24476,24477,24482,24487,24491,24484,24492,24495,24496,24497,24504, +24516,24519,24520,24521,24523,24528,24529,24530,24531,24532,24542,24545,24546, +24552,24553,24554,24556,24557,24558,24559,24562,24563,24566,24570,24572,24583, +24586,24589,24595,24596,24599,24600,24602,24607,24612,24621,24627,24629,24640, +24647,24648,24649,24652,24657,24660,24662,24663,24669,24673,24679,24689,24702, +24703,24706,24710,24712,24714,24718,24721,24723,24725,24728,24733,24734,24738, +24740,24741,24744,24752,24753,24759,24763,24766,24770,24772,24776,24777,24778, +24779,24782,24783,24788,24789,24793,24795,24797,24798,24802,24805,24818,24821, +24824,24828,24829,24834,24839,24842,24844,24848,24849,24850,24851,24852,24854, +24855,24857,24860,24862,24866,24874,24875,24880,24881,24885,24886,24887,24889, +24897,24901,24902,24905,24926,24928,24940,24946,24952,24955,24956,24959,24960, +24961,24963,24964,24971,24973,24978,24979,24983,24984,24988,24989,24991,24992, +24997,25000,25002,25005,25016,25017,25020,25024,25025,25026,25038,25039,25045, +25052,25053,25054,25055,25057,25058,25063,25065,25061,25068,25069,25071,25089, +25091,25092,25095,25107,25109,25116,25120,25122,25123,25127,25129,25131,25145, +25149,25154,25155,25156,25158,25164,25168,25169,25170,25172,25174,25178,25180, +25188,25197,25199,25203,25210,25213,25229,25230,25231,25232,25254,25256,25267, +25270,25271,25274,25278,25279,25284,25294,25301,25302,25306,25322,25330,25332, +25340,25341,25347,25348,25354,25355,25357,25360,25363,25366,25368,25385,25386, +25389,25397,25398,25401,25404,25409,25410,25411,25412,25414,25418,25419,25422, +25426,25427,25428,25432,25435,25445,25446,25452,25453,25457,25460,25461,25464, +25468,25469,25471,25474,25476,25479,25482,25488,25492,25493,25497,25498,25502, +25508,25510,25517,25518,25519,25533,25537,25541,25544,25550,25553,25555,25556, +25557,25564,25568,25573,25578,25580,25586,25587,25589,25592,25593,25609,25610, +25616,25618,25620,25624,25630,25632,25634,25636,25637,25641,25642,25647,25648, +25653,25661,25663,25675,25679,25681,25682,25683,25684,25690,25691,25692,25693, +25695,25696,25697,25699,25709,25715,25716,25723,25725,25733,25735,25743,25744, +25745,25752,25753,25755,25757,25759,25761,25763,25766,25768,25772,25779,25789, +25790,25791,25796,25801,25802,25803,25804,25806,25808,25809,25813,25815,25828, +25829,25833,25834,25837,25840,25845,25847,25851,25855,25857,25860,25864,25865, +25866,25871,25875,25876,25878,25881,25883,25886,25887,25890,25894,25897,25902, +25905,25914,25916,25917,25923,25927,25929,25936,25938,25940,25951,25952,25959, +25963,25978,25981,25985,25989,25994,26002,26005,26008,26013,26016,26019,26022, +26030,26034,26035,26036,26047,26050,26056,26057,26062,26064,26068,26070,26072, +26079,26096,26098,26100,26101,26105,26110,26111,26112,26116,26120,26121,26125, +26129,26130,26133,26134,26141,26142,26145,26146,26147,26148,26150,26153,26154, +26155,26156,26158,26160,26161,26163,26169,26167,26176,26181,26182,26186,26188, +26193,26190,26199,26200,26201,26203,26204,26208,26209,26363,26218,26219,26220, +26238,26227,26229,26239,26231,26232,26233,26235,26240,26236,26251,26252,26253, +26256,26258,26265,26266,26267,26268,26271,26272,26276,26285,26289,26290,26293, +26299,26303,26304,26306,26307,26312,26316,26318,26319,26324,26331,26335,26344, +26347,26348,26350,26362,26373,26375,26382,26387,26393,26396,26400,26402,26419, +26430,26437,26439,26440,26444,26452,26453,26461,26470,26476,26478,26484,26486, +26491,26497,26500,26510,26511,26513,26515,26518,26520,26521,26523,26544,26545, +26546,26549,26555,26556,26557,26617,26560,26562,26563,26565,26568,26569,26578, +26583,26585,26588,26593,26598,26608,26610,26614,26615,26706,26644,26649,26653, +26655,26664,26663,26668,26669,26671,26672,26673,26675,26683,26687,26692,26693, +26698,26700,26709,26711,26712,26715,26731,26734,26735,26736,26737,26738,26741, +26745,26746,26747,26748,26754,26756,26758,26760,26774,26776,26778,26780,26785, +26787,26789,26793,26794,26798,26802,26811,26821,26824,26828,26831,26832,26833, +26835,26838,26841,26844,26845,26853,26856,26858,26859,26860,26861,26864,26865, +26869,26870,26875,26876,26877,26886,26889,26890,26896,26897,26899,26902,26903, +26929,26931,26933,26936,26939,26946,26949,26953,26958,26967,26971,26979,26980, +26981,26982,26984,26985,26988,26992,26993,26994,27002,27003,27007,27008,27021, +27026,27030,27032,27041,27045,27046,27048,27051,27053,27055,27063,27064,27066, +27068,27077,27080,27089,27094,27095,27106,27109,27118,27119,27121,27123,27125, +27134,27136,27137,27139,27151,27153,27157,27162,27165,27168,27172,27176,27184, +27186,27188,27191,27195,27198,27199,27205,27206,27209,27210,27214,27216,27217, +27218,27221,27222,27227,27236,27239,27242,27249,27251,27262,27265,27267,27270, +27271,27273,27275,27281,27291,27293,27294,27295,27301,27307,27311,27312,27313, +27316,27325,27326,27327,27334,27337,27336,27340,27344,27348,27349,27350,27356, +27357,27364,27367,27372,27376,27377,27378,27388,27389,27394,27395,27398,27399, +27401,27407,27408,27409,27415,27419,27422,27428,27432,27435,27436,27439,27445, +27446,27451,27455,27462,27466,27469,27474,27478,27480,27485,27488,27495,27499, +27502,27504,27509,27517,27518,27522,27525,27543,27547,27551,27552,27554,27555, +27560,27561,27564,27565,27566,27568,27576,27577,27581,27582,27587,27588,27593, +27596,27606,27610,27617,27619,27622,27623,27630,27633,27639,27641,27647,27650, +27652,27653,27657,27661,27662,27664,27666,27673,27679,27686,27687,27688,27692, +27694,27699,27701,27702,27706,27707,27711,27722,27723,27725,27727,27730,27732, +27737,27739,27740,27755,27757,27759,27764,27766,27768,27769,27771,27781,27782, +27783,27785,27796,27797,27799,27800,27804,27807,27824,27826,27828,27842,27846, +27853,27855,27856,27857,27858,27860,27862,27866,27868,27872,27879,27881,27883, +27884,27886,27890,27892,27908,27911,27914,27918,27919,27921,27923,27930,27942, +27943,27944,27751,27950,27951,27953,27961,27964,27967,27991,27998,27999,28001, +28005,28007,28015,28016,28028,28034,28039,28049,28050,28052,28054,28055,28056, +28074,28076,28084,28087,28089,28093,28095,28100,28104,28106,28110,28111,28118, +28123,28125,28127,28128,28130,28133,28137,28143,28144,28148,28150,28156,28160, +28164,28190,28194,28199,28210,28214,28217,28219,28220,28228,28229,28232,28233, +28235,28239,28241,28242,28243,28244,28247,28252,28253,28254,28258,28259,28264, +28275,28283,28285,28301,28307,28313,28320,28327,28333,28334,28337,28339,28347, +28351,28352,28353,28355,28359,28360,28362,28365,28366,28367,28395,28397,28398, +28409,28411,28413,28420,28424,28426,28428,28429,28438,28440,28442,28443,28454, +28457,28458,28463,28464,28467,28470,28475,28476,28461,28495,28497,28498,28499, +28503,28505,28506,28509,28510,28513,28514,28520,28524,28541,28542,28547,28551, +28552,28555,28556,28557,28560,28562,28563,28564,28566,28570,28575,28576,28581, +28582,28583,28584,28590,28591,28592,28597,28598,28604,28613,28615,28616,28618, +28634,28638,28648,28649,28656,28661,28665,28668,28669,28672,28677,28678,28679, +28685,28695,28704,28707,28719,28724,28727,28729,28732,28739,28740,28744,28745, +28746,28747,28756,28757,28765,28766,28750,28772,28773,28780,28782,28789,28790, +28798,28801,28805,28806,28820,28821,28822,28823,28824,28827,28836,28843,28848, +28849,28852,28855,28874,28881,28883,28884,28885,28886,28888,28892,28900,28922, +28931,28932,28933,28934,28935,28939,28940,28943,28958,28960,28971,28973,28975, +28976,28977,28984,28993,28997,28998,28999,29002,29003,29008,29010,29015,29018, +29020,29022,29024,29032,29049,29056,29061,29063,29068,29074,29082,29083,29088, +29090,29103,29104,29106,29107,29114,29119,29120,29121,29124,29131,29132,29139, +29142,29145,29146,29148,29176,29182,29184,29191,29192,29193,29203,29207,29210, +29213,29215,29220,29227,29231,29236,29240,29241,29249,29250,29251,29253,29262, +29263,29264,29267,29269,29270,29274,29276,29278,29280,29283,29288,29291,29294, +29295,29297,29303,29304,29307,29308,29311,29316,29321,29325,29326,29331,29339, +29352,29357,29358,29361,29364,29374,29377,29383,29385,29388,29397,29398,29400, +29407,29413,29427,29428,29434,29435,29438,29442,29444,29445,29447,29451,29453, +29458,29459,29464,29465,29470,29474,29476,29479,29480,29484,29489,29490,29493, +29498,29499,29501,29507,29517,29520,29522,29526,29528,29533,29534,29535,29536, +29542,29543,29545,29547,29548,29550,29551,29553,29559,29561,29564,29568,29569, +29571,29573,29574,29582,29584,29587,29589,29591,29592,29596,29598,29599,29600, +29602,29605,29606,29610,29611,29613,29621,29623,29625,29628,29629,29631,29637, +29638,29641,29643,29644,29647,29650,29651,29654,29657,29661,29665,29667,29670, +29671,29673,29684,29685,29687,29689,29690,29691,29693,29695,29696,29697,29700, +29703,29706,29713,29722,29723,29732,29734,29736,29737,29738,29739,29740,29741, +29742,29743,29744,29745,29753,29760,29763,29764,29766,29767,29771,29773,29777, +29778,29783,29789,29794,29798,29799,29800,29803,29805,29806,29809,29810,29824, +29825,29829,29830,29831,29833,29839,29840,29841,29842,29848,29849,29850,29852, +29855,29856,29857,29859,29862,29864,29865,29866,29867,29870,29871,29873,29874, +29877,29881,29883,29887,29896,29897,29900,29904,29907,29912,29914,29915,29918, +29919,29924,29928,29930,29931,29935,29940,29946,29947,29948,29951,29958,29970, +29974,29975,29984,29985,29988,29991,29993,29994,29999,30006,30009,30013,30014, +30015,30016,30019,30023,30024,30030,30032,30034,30039,30046,30047,30049,30063, +30065,30073,30074,30075,30076,30077,30078,30081,30085,30096,30098,30099,30101, +30105,30108,30114,30116,30132,30138,30143,30144,30145,30148,30150,30156,30158, +30159,30167,30172,30175,30176,30177,30180,30183,30188,30190,30191,30193,30201, +30208,30210,30211,30212,30215,30216,30218,30220,30223,30226,30227,30229,30230, +30233,30235,30236,30237,30238,30243,30245,30246,30249,30253,30258,30259,30261, +30264,30265,30266,30268,30282,30272,30273,30275,30276,30277,30281,30283,30293, +30297,30303,30308,30309,30317,30318,30319,30321,30324,30337,30341,30348,30349, +30357,30363,30364,30365,30367,30368,30370,30371,30372,30373,30374,30375,30376, +30378,30381,30397,30401,30405,30409,30411,30412,30414,30420,30425,30432,30438, +30440,30444,30448,30449,30454,30457,30460,30464,30470,30474,30478,30482,30484, +30485,30487,30489,30490,30492,30498,30504,30509,30510,30511,30516,30517,30518, +30521,30525,30526,30530,30533,30534,30538,30541,30542,30543,30546,30550,30551, +30556,30558,30559,30560,30562,30564,30567,30570,30572,30576,30578,30579,30580, +30586,30589,30592,30596,30604,30605,30612,30613,30614,30618,30623,30626,30631, +30634,30638,30639,30641,30645,30654,30659,30665,30673,30674,30677,30681,30686, +30687,30688,30692,30694,30698,30700,30704,30705,30708,30712,30715,30725,30726, +30729,30733,30734,30737,30749,30753,30754,30755,30765,30766,30768,30773,30775, +30787,30788,30791,30792,30796,30798,30802,30812,30814,30816,30817,30819,30820, +30824,30826,30830,30842,30846,30858,30863,30868,30872,30881,30877,30878,30879, +30884,30888,30892,30893,30896,30897,30898,30899,30907,30909,30911,30919,30920, +30921,30924,30926,30930,30931,30933,30934,30948,30939,30943,30944,30945,30950, +30954,30962,30963,30976,30966,30967,30970,30971,30975,30982,30988,30992,31002, +31004,31006,31007,31008,31013,31015,31017,31021,31025,31028,31029,31035,31037, +31039,31044,31045,31046,31050,31051,31055,31057,31060,31064,31067,31068,31079, +31081,31083,31090,31097,31099,31100,31102,31115,31116,31121,31123,31124,31125, +31126,31128,31131,31132,31137,31144,31145,31147,31151,31153,31156,31160,31163, +31170,31172,31175,31176,31178,31183,31188,31190,31194,31197,31198,31200,31202, +31205,31210,31211,31213,31217,31224,31228,31234,31235,31239,31241,31242,31244, +31249,31253,31259,31262,31265,31271,31275,31277,31279,31280,31284,31285,31288, +31289,31290,31300,31301,31303,31304,31308,31317,31318,31321,31324,31325,31327, +31328,31333,31335,31338,31341,31349,31352,31358,31360,31362,31365,31366,31370, +31371,31376,31377,31380,31390,31392,31395,31404,31411,31413,31417,31419,31420, +31430,31433,31436,31438,31441,31451,31464,31465,31467,31468,31473,31476,31483, +31485,31486,31495,31508,31519,31523,31527,31529,31530,31531,31533,31534,31535, +31536,31537,31540,31549,31551,31552,31553,31559,31566,31573,31584,31588,31590, +31593,31594,31597,31599,31602,31603,31607,31620,31625,31630,31632,31633,31638, +31643,31646,31648,31653,31660,31663,31664,31666,31669,31670,31674,31675,31676, +31677,31682,31685,31688,31690,31700,31702,31703,31705,31706,31707,31720,31722, +31730,31732,31733,31736,31737,31738,31740,31742,31745,31746,31747,31748,31750, +31753,31755,31756,31758,31759,31769,31771,31776,31781,31782,31784,31788,31793, +31795,31796,31798,31801,31802,31814,31818,31829,31825,31826,31827,31833,31834, +31835,31836,31837,31838,31841,31843,31847,31849,31853,31854,31856,31858,31865, +31868,31869,31878,31879,31887,31892,31902,31904,31910,31920,31926,31927,31930, +31931,31932,31935,31940,31943,31944,31945,31949,31951,31955,31956,31957,31959, +31961,31962,31965,31974,31977,31979,31989,32003,32007,32008,32009,32015,32017, +32018,32019,32022,32029,32030,32035,32038,32042,32045,32049,32060,32061,32062, +32064,32065,32071,32072,32077,32081,32083,32087,32089,32090,32092,32093,32101, +32103,32106,32112,32120,32122,32123,32127,32129,32130,32131,32133,32134,32136, +32139,32140,32141,32145,32150,32151,32157,32158,32166,32167,32170,32179,32182, +32183,32185,32194,32195,32196,32197,32198,32204,32205,32206,32215,32217,32256, +32226,32229,32230,32234,32235,32237,32241,32245,32246,32249,32250,32264,32272, +32273,32277,32279,32284,32285,32288,32295,32296,32300,32301,32303,32307,32310, +32319,32324,32325,32327,32334,32336,32338,32344,32351,32353,32354,32357,32363, +32366,32367,32371,32376,32382,32385,32390,32391,32394,32397,32401,32405,32408, +32410,32413,32414,32572,32571,32573,32574,32575,32579,32580,32583,32591,32594, +32595,32603,32604,32605,32609,32611,32612,32613,32614,32621,32625,32637,32638, +32639,32640,32651,32653,32655,32656,32657,32662,32663,32668,32673,32674,32678, +32682,32685,32692,32700,32703,32704,32707,32712,32718,32719,32731,32735,32739, +32741,32744,32748,32750,32751,32754,32762,32765,32766,32767,32775,32776,32778, +32781,32782,32783,32785,32787,32788,32790,32797,32798,32799,32800,32804,32806, +32812,32814,32816,32820,32821,32823,32825,32826,32828,32830,32832,32836,32864, +32868,32870,32877,32881,32885,32897,32904,32910,32924,32926,32934,32935,32939, +32952,32953,32968,32973,32975,32978,32980,32981,32983,32984,32992,33005,33006, +33008,33010,33011,33014,33017,33018,33022,33027,33035,33046,33047,33048,33052, +33054,33056,33060,33063,33068,33072,33077,33082,33084,33093,33095,33098,33100, +33106,33111,33120,33121,33127,33128,33129,33133,33135,33143,33153,33168,33156, +33157,33158,33163,33166,33174,33176,33179,33182,33186,33198,33202,33204,33211, +33227,33219,33221,33226,33230,33231,33237,33239,33243,33245,33246,33249,33252, +33259,33260,33264,33265,33266,33269,33270,33272,33273,33277,33279,33280,33283, +33295,33299,33300,33305,33306,33309,33313,33314,33320,33330,33332,33338,33347, +33348,33349,33350,33355,33358,33359,33361,33366,33372,33376,33379,33383,33389, +33396,33403,33405,33407,33408,33409,33411,33412,33415,33417,33418,33422,33425, +33428,33430,33432,33434,33435,33440,33441,33443,33444,33447,33448,33449,33450, +33454,33456,33458,33460,33463,33466,33468,33470,33471,33478,33488,33493,33498, +33504,33506,33508,33512,33514,33517,33519,33526,33527,33533,33534,33536,33537, +33543,33544,33546,33547,33620,33563,33565,33566,33567,33569,33570,33580,33581, +33582,33584,33587,33591,33594,33596,33597,33602,33603,33604,33607,33613,33614, +33617,33621,33622,33623,33648,33656,33661,33663,33664,33666,33668,33670,33677, +33682,33684,33685,33688,33689,33691,33692,33693,33702,33703,33705,33708,33726, +33727,33728,33735,33737,33743,33744,33745,33748,33757,33619,33768,33770,33782, +33784,33785,33788,33793,33798,33802,33807,33809,33813,33817,33709,33839,33849, +33861,33863,33864,33866,33869,33871,33873,33874,33878,33880,33881,33882,33884, +33888,33892,33893,33895,33898,33904,33907,33908,33910,33912,33916,33917,33921, +33925,33938,33939,33941,33950,33958,33960,33961,33962,33967,33969,33972,33978, +33981,33982,33984,33986,33991,33992,33996,33999,34003,34012,34023,34026,34031, +34032,34033,34034,34039,34098,34042,34043,34045,34050,34051,34055,34060,34062, +34064,34076,34078,34082,34083,34084,34085,34087,34090,34091,34095,34099,34100, +34102,34111,34118,34127,34128,34129,34130,34131,34134,34137,34140,34141,34142, +34143,34144,34145,34146,34148,34155,34159,34169,34170,34171,34173,34175,34177, +34181,34182,34185,34187,34188,34191,34195,34200,34205,34207,34208,34210,34213, +34215,34228,34230,34231,34232,34236,34237,34238,34239,34242,34247,34250,34251, +34254,34221,34264,34266,34271,34272,34278,34280,34285,34291,34294,34300,34303, +34304,34308,34309,34317,34318,34320,34321,34322,34328,34329,34331,34334,34337, +34343,34345,34358,34360,34362,34364,34365,34368,34370,34374,34386,34387,34390, +34391,34392,34393,34397,34400,34401,34402,34403,34404,34409,34412,34415,34421, +34422,34423,34426,34445,34449,34454,34456,34458,34460,34465,34470,34471,34472, +34477,34481,34483,34484,34485,34487,34488,34489,34495,34496,34497,34499,34501, +34513,34514,34517,34519,34522,34524,34528,34531,34533,34535,34440,34554,34556, +34557,34564,34565,34567,34571,34574,34575,34576,34579,34580,34585,34590,34591, +34593,34595,34600,34606,34607,34609,34610,34617,34618,34620,34621,34622,34624, +34627,34629,34637,34648,34653,34657,34660,34661,34671,34673,34674,34683,34691, +34692,34693,34694,34695,34696,34697,34699,34700,34704,34707,34709,34711,34712, +34713,34718,34720,34723,34727,34732,34733,34734,34737,34741,34750,34751,34753, +34760,34761,34762,34766,34773,34774,34777,34778,34780,34783,34786,34787,34788, +34794,34795,34797,34801,34803,34808,34810,34815,34817,34819,34822,34825,34826, +34827,34832,34841,34834,34835,34836,34840,34842,34843,34844,34846,34847,34856, +34861,34862,34864,34866,34869,34874,34876,34881,34883,34885,34888,34889,34890, +34891,34894,34897,34901,34902,34904,34906,34908,34911,34912,34916,34921,34929, +34937,34939,34944,34968,34970,34971,34972,34975,34976,34984,34986,35002,35005, +35006,35008,35018,35019,35020,35021,35022,35025,35026,35027,35035,35038,35047, +35055,35056,35057,35061,35063,35073,35078,35085,35086,35087,35093,35094,35096, +35097,35098,35100,35104,35110,35111,35112,35120,35121,35122,35125,35129,35130, +35134,35136,35138,35141,35142,35145,35151,35154,35159,35162,35163,35164,35169, +35170,35171,35179,35182,35184,35187,35189,35194,35195,35196,35197,35209,35213, +35216,35220,35221,35227,35228,35231,35232,35237,35248,35252,35253,35254,35255, +35260,35284,35285,35286,35287,35288,35301,35305,35307,35309,35313,35315,35318, +35321,35325,35327,35332,35333,35335,35343,35345,35346,35348,35349,35358,35360, +35362,35364,35366,35371,35372,35375,35381,35383,35389,35390,35392,35395,35397, +35399,35401,35405,35406,35411,35414,35415,35416,35420,35421,35425,35429,35431, +35445,35446,35447,35449,35450,35451,35454,35455,35456,35459,35462,35467,35471, +35472,35474,35478,35479,35481,35487,35495,35497,35502,35503,35507,35510,35511, +35515,35518,35523,35526,35528,35529,35530,35537,35539,35540,35541,35543,35549, +35551,35564,35568,35572,35573,35574,35580,35583,35589,35590,35595,35601,35612, +35614,35615,35594,35629,35632,35639,35644,35650,35651,35652,35653,35654,35656, +35666,35667,35668,35673,35661,35678,35683,35693,35702,35704,35705,35708,35710, +35713,35716,35717,35723,35725,35727,35732,35733,35740,35742,35743,35896,35897, +35901,35902,35909,35911,35913,35915,35919,35921,35923,35924,35927,35928,35931, +35933,35929,35939,35940,35942,35944,35945,35949,35955,35957,35958,35963,35966, +35974,35975,35979,35984,35986,35987,35993,35995,35996,36004,36025,36026,36037, +36038,36041,36043,36047,36054,36053,36057,36061,36065,36072,36076,36079,36080, +36082,36085,36087,36088,36094,36095,36097,36099,36105,36114,36119,36123,36197, +36201,36204,36206,36223,36226,36228,36232,36237,36240,36241,36245,36254,36255, +36256,36262,36267,36268,36271,36274,36277,36279,36281,36283,36288,36293,36294, +36295,36296,36298,36302,36305,36308,36309,36311,36313,36324,36325,36327,36332, +36336,36284,36337,36338,36340,36349,36353,36356,36357,36358,36363,36369,36372, +36374,36384,36385,36386,36387,36390,36391,36401,36403,36406,36407,36408,36409, +36413,36416,36417,36427,36429,36430,36431,36436,36443,36444,36445,36446,36449, +36450,36457,36460,36461,36463,36464,36465,36473,36474,36475,36482,36483,36489, +36496,36498,36501,36506,36507,36509,36510,36514,36519,36521,36525,36526,36531, +36533,36538,36539,36544,36545,36547,36548,36551,36559,36561,36564,36572,36584, +36590,36592,36593,36599,36601,36602,36589,36608,36610,36615,36616,36623,36624, +36630,36631,36632,36638,36640,36641,36643,36645,36647,36648,36652,36653,36654, +36660,36661,36662,36663,36666,36672,36673,36675,36679,36687,36689,36690,36691, +36692,36693,36696,36701,36702,36709,36765,36768,36769,36772,36773,36774,36789, +36790,36792,36798,36800,36801,36806,36810,36811,36813,36816,36818,36819,36821, +36832,36835,36836,36840,36846,36849,36853,36854,36859,36862,36866,36868,36872, +36876,36888,36891,36904,36905,36911,36906,36908,36909,36915,36916,36919,36927, +36931,36932,36940,36955,36957,36962,36966,36967,36972,36976,36980,36985,36997, +37000,37003,37004,37006,37008,37013,37015,37016,37017,37019,37024,37025,37026, +37029,37040,37042,37043,37044,37046,37053,37068,37054,37059,37060,37061,37063, +37064,37077,37079,37080,37081,37084,37085,37087,37093,37074,37110,37099,37103, +37104,37108,37118,37119,37120,37124,37125,37126,37128,37133,37136,37140,37142, +37143,37144,37146,37148,37150,37152,37157,37154,37155,37159,37161,37166,37167, +37169,37172,37174,37175,37177,37178,37180,37181,37187,37191,37192,37199,37203, +37207,37209,37210,37211,37217,37220,37223,37229,37236,37241,37242,37243,37249, +37251,37253,37254,37258,37262,37265,37267,37268,37269,37272,37278,37281,37286, +37288,37292,37293,37294,37296,37297,37298,37299,37302,37307,37308,37309,37311, +37314,37315,37317,37331,37332,37335,37337,37338,37342,37348,37349,37353,37354, +37356,37357,37358,37359,37360,37361,37367,37369,37371,37373,37376,37377,37380, +37381,37382,37383,37385,37386,37388,37392,37394,37395,37398,37400,37404,37405, +37411,37412,37413,37414,37416,37422,37423,37424,37427,37429,37430,37432,37433, +37434,37436,37438,37440,37442,37443,37446,37447,37450,37453,37454,37455,37457, +37464,37465,37468,37469,37472,37473,37477,37479,37480,37481,37486,37487,37488, +37493,37494,37495,37496,37497,37499,37500,37501,37503,37512,37513,37514,37517, +37518,37522,37527,37529,37535,37536,37540,37541,37543,37544,37547,37551,37554, +37558,37560,37562,37563,37564,37565,37567,37568,37569,37570,37571,37573,37574, +37575,37576,37579,37580,37581,37582,37584,37587,37589,37591,37592,37593,37596, +37597,37599,37600,37601,37603,37605,37607,37608,37612,37614,37616,37625,37627, +37631,37632,37634,37640,37645,37649,37652,37653,37660,37661,37662,37663,37665, +37668,37669,37671,37673,37674,37683,37684,37686,37687,37703,37704,37705,37712, +37713,37714,37717,37719,37720,37722,37726,37732,37733,37735,37737,37738,37741, +37743,37744,37745,37747,37748,37750,37754,37757,37759,37760,37761,37762,37768, +37770,37771,37773,37775,37778,37781,37784,37787,37790,37793,37795,37796,37798, +37800,37803,37812,37813,37814,37818,37801,37825,37828,37829,37830,37831,37833, +37834,37835,37836,37837,37843,37849,37852,37854,37855,37858,37862,37863,37881, +37879,37880,37882,37883,37885,37889,37890,37892,37896,37897,37901,37902,37903, +37909,37910,37911,37919,37934,37935,37937,37938,37939,37940,37947,37951,37949, +37955,37957,37960,37962,37964,37973,37977,37980,37983,37985,37987,37992,37995, +37997,37998,37999,38001,38002,38020,38019,38264,38265,38270,38276,38280,38284, +38285,38286,38301,38302,38303,38305,38310,38313,38315,38316,38324,38326,38330, +38333,38335,38342,38344,38345,38347,38352,38353,38354,38355,38361,38362,38365, +38366,38367,38368,38372,38374,38429,38430,38434,38436,38437,38438,38444,38449, +38451,38455,38456,38457,38458,38460,38461,38465,38482,38484,38486,38487,38488, +38497,38510,38516,38523,38524,38526,38527,38529,38530,38531,38532,38537,38545, +38550,38554,38557,38559,38564,38565,38566,38569,38574,38575,38579,38586,38602, +38610,23986,38616,38618,38621,38622,38623,38633,38639,38641,38650,38658,38659, +38661,38665,38682,38683,38685,38689,38690,38691,38696,38705,38707,38721,38723, +38730,38734,38735,38741,38743,38744,38746,38747,38755,38759,38762,38766,38771, +38774,38775,38776,38779,38781,38783,38784,38793,38805,38806,38807,38809,38810, +38814,38815,38818,38828,38830,38833,38834,38837,38838,38840,38841,38842,38844, +38846,38847,38849,38852,38853,38855,38857,38858,38860,38861,38862,38864,38865, +38868,38871,38872,38873,38877,38878,38880,38875,38881,38884,38895,38897,38900, +38903,38904,38906,38919,38922,38937,38925,38926,38932,38934,38940,38942,38944, +38947,38950,38955,38958,38959,38960,38962,38963,38965,38949,38974,38980,38983, +38986,38993,38994,38995,38998,38999,39001,39002,39010,39011,39013,39014,39018, +39020,39083,39085,39086,39088,39092,39095,39096,39098,39099,39103,39106,39109, +39112,39116,39137,39139,39141,39142,39143,39146,39155,39158,39170,39175,39176, +39185,39189,39190,39191,39194,39195,39196,39199,39202,39206,39207,39211,39217, +39218,39219,39220,39221,39225,39226,39227,39228,39232,39233,39238,39239,39240, +39245,39246,39252,39256,39257,39259,39260,39262,39263,39264,39323,39325,39327, +39334,39344,39345,39346,39349,39353,39354,39357,39359,39363,39369,39379,39380, +39385,39386,39388,39390,39399,39402,39403,39404,39408,39412,39413,39417,39421, +39422,39426,39427,39428,39435,39436,39440,39441,39446,39454,39456,39458,39459, +39460,39463,39469,39470,39475,39477,39478,39480,39495,39489,39492,39498,39499, +39500,39502,39505,39508,39510,39517,39594,39596,39598,39599,39602,39604,39605, +39606,39609,39611,39614,39615,39617,39619,39622,39624,39630,39632,39634,39637, +39638,39639,39643,39644,39648,39652,39653,39655,39657,39660,39666,39667,39669, +39673,39674,39677,39679,39680,39681,39682,39683,39684,39685,39688,39689,39691, +39692,39693,39694,39696,39698,39702,39705,39707,39708,39712,39718,39723,39725, +39731,39732,39733,39735,39737,39738,39741,39752,39755,39756,39765,39766,39767, +39771,39774,39777,39779,39781,39782,39784,39786,39787,39788,39789,39790,39795, +39797,39799,39800,39801,39807,39808,39812,39813,39814,39815,39817,39818,39819, +39821,39823,39824,39828,39834,39837,39838,39846,39847,39849,39852,39856,39857, +39858,39863,39864,39867,39868,39870,39871,39873,39879,39880,39886,39888,39895, +39896,39901,39903,39909,39911,39914,39915,39919,39923,39927,39928,39929,39930, +39933,39935,39936,39938,39947,39951,39953,39958,39960,39961,39962,39964,39966, +39970,39971,39974,39975,39976,39977,39978,39985,39989,39990,39991,39997,40001, +40003,40004,40005,40009,40010,40014,40015,40016,40019,40020,40022,40024,40027, +40029,40030,40031,40035,40041,40042,40028,40043,40040,40046,40048,40050,40053, +40055,40059,40166,40178,40183,40185,40203,40194,40209,40215,40216,40220,40221, +40222,40239,40240,40242,40243,40244,40250,40252,40261,40253,40258,40259,40263, +40266,40275,40276,40287,40291,40290,40293,40297,40298,40299,40304,40310,40311, +40315,40316,40318,40323,40324,40326,40330,40333,40334,40338,40339,40341,40342, +40343,40344,40353,40362,40364,40366,40369,40373,40377,40380,40383,40387,40391, +40393,40394,40404,40405,40406,40407,40410,40414,40415,40416,40421,40423,40425, +40427,40430,40432,40435,40436,40446,40458,40450,40455,40462,40464,40465,40466, +40469,40470,40473,40476,40477,40570,40571,40572,40576,40578,40579,40580,40581, +40583,40590,40591,40598,40600,40603,40606,40612,40616,40620,40622,40623,40624, +40627,40628,40629,40646,40648,40651,40661,40671,40676,40679,40684,40685,40686, +40688,40689,40690,40693,40696,40703,40706,40707,40713,40719,40720,40721,40722, +40724,40726,40727,40729,40730,40731,40735,40738,40742,40746,40747,40751,40753, +40754,40756,40759,40761,40762,40764,40765,40767,40769,40771,40772,40773,40774, +40775,40787,40789,40790,40791,40792,40794,40797,40798,40808,40809,40813,40814, +40815,40816,40817,40819,40821,40826,40829,40847,40848,40849,40850,40852,40854, +40855,40862,40865,40866,40867,40869, +}; + +static const struct dbcs_index jisx0212_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0212_decmap+0,47,113},{0,0,0},{ +0,0,0},{0,0,0},{__jisx0212_decmap+67,97,124},{__jisx0212_decmap+95,66,126},{0, +0,0},{__jisx0212_decmap+156,33,80},{__jisx0212_decmap+204,33,119},{ +__jisx0212_decmap+291,33,119},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0212_decmap+378,33,126},{__jisx0212_decmap+472,33,126},{ +__jisx0212_decmap+566,33,126},{__jisx0212_decmap+660,33,126},{ +__jisx0212_decmap+754,33,126},{__jisx0212_decmap+848,33,126},{ +__jisx0212_decmap+942,33,126},{__jisx0212_decmap+1036,33,126},{ +__jisx0212_decmap+1130,33,126},{__jisx0212_decmap+1224,33,126},{ +__jisx0212_decmap+1318,33,126},{__jisx0212_decmap+1412,33,126},{ +__jisx0212_decmap+1506,33,126},{__jisx0212_decmap+1600,33,126},{ +__jisx0212_decmap+1694,33,126},{__jisx0212_decmap+1788,33,126},{ +__jisx0212_decmap+1882,33,126},{__jisx0212_decmap+1976,33,126},{ +__jisx0212_decmap+2070,33,126},{__jisx0212_decmap+2164,33,126},{ +__jisx0212_decmap+2258,33,126},{__jisx0212_decmap+2352,33,126},{ +__jisx0212_decmap+2446,33,126},{__jisx0212_decmap+2540,33,126},{ +__jisx0212_decmap+2634,33,126},{__jisx0212_decmap+2728,33,126},{ +__jisx0212_decmap+2822,33,126},{__jisx0212_decmap+2916,33,126},{ +__jisx0212_decmap+3010,33,126},{__jisx0212_decmap+3104,33,126},{ +__jisx0212_decmap+3198,33,126},{__jisx0212_decmap+3292,33,126},{ +__jisx0212_decmap+3386,33,126},{__jisx0212_decmap+3480,33,126},{ +__jisx0212_decmap+3574,33,126},{__jisx0212_decmap+3668,33,126},{ +__jisx0212_decmap+3762,33,126},{__jisx0212_decmap+3856,33,126},{ +__jisx0212_decmap+3950,33,126},{__jisx0212_decmap+4044,33,126},{ +__jisx0212_decmap+4138,33,126},{__jisx0212_decmap+4232,33,126},{ +__jisx0212_decmap+4326,33,126},{__jisx0212_decmap+4420,33,126},{ +__jisx0212_decmap+4514,33,126},{__jisx0212_decmap+4608,33,126},{ +__jisx0212_decmap+4702,33,126},{__jisx0212_decmap+4796,33,126},{ +__jisx0212_decmap+4890,33,126},{__jisx0212_decmap+4984,33,126},{ +__jisx0212_decmap+5078,33,126},{__jisx0212_decmap+5172,33,126},{ +__jisx0212_decmap+5266,33,126},{__jisx0212_decmap+5360,33,126},{ +__jisx0212_decmap+5454,33,126},{__jisx0212_decmap+5548,33,126},{ +__jisx0212_decmap+5642,33,126},{__jisx0212_decmap+5736,33,126},{ +__jisx0212_decmap+5830,33,126},{__jisx0212_decmap+5924,33,126},{ +__jisx0212_decmap+6018,33,126},{__jisx0212_decmap+6112,33,99},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __jisxcommon_encmap[22016] = { +8512,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41527, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41538, +8561,8562,41584,N,41539,8568,8495,41581,41580,N,8780,N,41582,41524,8555,8542, +N,N,8493,N,8825,N,41521,N,41579,N,N,N,N,41540,43554,43553,43556,43562,43555, +43561,43297,43566,43570,43569,43572,43571,43584,43583,43586,43585,N,43600, +43602,43601,43604,43608,43603,8543,43308,43619,43618,43621,43620,43634,43312, +43342,43810,43809,43812,43818,43811,43817,43329,43822,43826,43825,43828,43827, +43840,43839,43842,43841,43331,43856,43858,43857,43860,43864,43859,8544,43340, +43875,43874,43877,43876,43890,43344,43891,43559,43815,43557,43813,43560,43816, +43563,43819,43564,43820,43567,43823,43565,43821,43568,43824,43298,43330,43575, +43831,N,N,43574,43830,43576,43832,43573,43829,43578,43834,43579,43835,43581, +43837,43580,N,43582,43838,43300,43332,43591,43847,43589,43845,N,N,43590,43846, +43588,43333,43302,43334,43592,43848,43593,43849,43335,43594,43850,43596,43852, +43595,43851,43305,43337,43304,43336,43597,43853,43599,43855,43598,43854,43338, +43307,43339,43607,43863,N,N,43606,43862,43309,43341,43609,43865,43611,43867, +43610,43866,43612,43868,43613,43869,43615,43871,43614,43870,43617,43873,43616, +43872,43311,43343,43628,43884,43625,43881,43622,43878,43627,43883,43624,43880, +43626,43882,43633,43889,43636,43892,43635,43637,43893,43639,43895,43638,43894, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43558,43814,43587,43843,43605,43861,43623,43879,43632,43888,43629,43885,43631, +43887,43630,43886,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43833,41520, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41519,41522,41526,41525,N,41523,41528,41529, +42593,N,42594,42595,42596,N,42599,N,42601,42604,42614,9761,9762,9763,9764, +9765,9766,9767,9768,9769,9770,9771,9772,9773,9774,9775,9776,9777,N,9778,9779, +9780,9781,9782,9783,9784,42597,42602,42609,42610,42611,42612,42619,9793,9794, +9795,9796,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806,9807,9808,9809, +42616,9810,9811,9812,9813,9814,9815,9816,42613,42618,42615,42617,42620,10023, +42818,42819,42820,42821,42822,42823,42824,42825,42826,42827,42828,N,42829, +42830,10017,10018,10019,10020,10021,10022,10024,10025,10026,10027,10028,10029, +10030,10031,10032,10033,10034,10035,10036,10037,10038,10039,10040,10041,10042, +10043,10044,10045,10046,10047,10048,10049,10065,10066,10067,10068,10069,10070, +10072,10073,10074,10075,10076,10077,10078,10079,10080,10081,10082,10083,10084, +10085,10086,10087,10088,10089,10090,10091,10092,10093,10094,10095,10096,10097, +N,10071,42866,42867,42868,42869,42870,42871,42872,42873,42874,42875,42876,N, +42877,42878,8510,N,N,N,N,8509,8514,N,8518,8519,N,N,8520,8521,N,N,8823,8824,N, +N,N,8517,8516,N,N,N,N,N,N,N,N,N,8819,N,8556,8557,N,N,N,N,N,N,N,8744,8558,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41585,N,N,N,N,N,N,N,N,N,N,N,41583,N,N,N,N,N,N, +N,N,8818,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8747,8748,8746,8749,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8781,N,8782,8783,N,8799,8784,N,N,N, +8800,8762,N,N,8763,N,N,N,N,N,N,8541,N,N,N,N,N,N,N,8805,N,N,8807,8551,N,8796,N, +N,N,N,N,N,8778,8779,8769,8768,8809,8810,N,N,N,N,N,N,N,8552,8808,N,N,N,N,N,N,N, +8806,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8802,N,N,N,N,N,N,N,N,N,N,N,N,N, +8546,8801,N,N,N,N,8549,8550,N,N,8803,8804,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,8766,8767,N,N,8764,8765,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,8797,8798,10273,10284,10274,10285,N,N,N,N,N,N,N,N,10275,N,N,10286, +10276,N,N,10287,10278,N,N,10289,10277,N,N,10288,10279,10300,N,N,10295,N,N, +10290,10281,10302,N,N,10297,N,N,10292,10280,N,N,10296,10301,N,N,10291,10282,N, +N,10298,10303,N,N,10293,10283,N,N,10299,N,N,10304,N,N,N,N,N,N,N,N,10294,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,8739,8738,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8741,8740,N,N,N,N,N,N,N,N, +8743,8742,N,N,N,N,N,N,N,N,8737,8574,N,N,N,8571,N,N,8573,8572,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8830,8570,8569,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,8554,N,8553,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8822,N,N,8821,N,8820,8481,8482,8483,8503,N, +8505,8506,8507,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,8745,8750, +8524,8525,N,N,N,N,N,N,8513,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258,9259, +9260,9261,9262,9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273,9274, +9275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289, +9290,9291,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9304, +9305,9306,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319, +9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,N,N,N,N,N,N,N, +8491,8492,8501,8502,N,N,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514, +9515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529, +9530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544, +9545,9546,9547,9548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559, +9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574, +9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588,9589, +9590,N,N,N,N,8486,8508,8499,8500,12396,17274,45089,15415,45090,45091,N,19324, +15974,15152,15973,12860,45092,18772,19775,N,20514,12591,45093,N,13166,20515, +16420,21058,13654,19002,N,N,N,N,15975,45094,N,20030,N,45095,45096,N,19010,N, +45097,N,20516,45098,N,17254,45099,45100,45101,20517,13946,N,N,45102,20518,N, +13405,17200,N,15463,20519,N,N,20520,45103,45104,20521,18229,45105,13655,N, +45106,N,N,N,18231,N,18019,14403,19251,N,45107,N,N,N,26953,20522,15976,20523, +12853,45108,N,45109,13925,14448,19561,N,N,22054,45110,N,N,N,N,45111,45112,N,N, +N,N,N,N,N,19824,N,18045,45113,45114,N,N,N,45115,N,N,N,N,13349,45116,13621,N, +20524,N,N,20525,20027,N,19773,16744,20527,15222,18035,45117,20530,N,N,12606, +14431,N,14430,12390,45118,45119,20299,20298,N,14899,12321,45120,20531,20532, +20533,19252,20534,N,14450,12391,19314,N,13692,N,N,13693,13694,17506,20028, +45121,20535,N,N,20536,N,N,20537,N,N,45122,16205,N,N,N,N,N,15674,16206,20542, +45123,20540,N,20541,13656,N,N,14883,12912,N,20539,20538,18985,45124,N,N,N, +15174,15173,16958,20543,18773,16487,45125,45126,N,8504,20544,20546,45127, +45128,45129,16997,20065,12362,N,N,45130,N,N,N,N,20545,12862,45131,13892,45132, +17255,45133,N,45134,14191,20547,N,N,N,18212,N,45135,45136,45137,45138,13419, +45139,45140,N,N,N,N,45141,20548,12363,45142,45143,14432,13420,18810,18482, +13657,45144,N,N,45145,45146,45147,N,45148,12913,N,20583,17729,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,45149,18284,20550,45150,N,45152,18492,45153,20066,45154,16173, +45155,15175,45156,15223,12864,45157,N,45158,N,45159,17489,N,N,17186,20554, +45160,45161,N,45162,45163,12364,17507,15675,14900,19748,45164,16974,45165, +12863,45166,20553,45167,19774,20549,20551,14958,20552,21796,45168,45151,N,N, +45169,N,N,N,N,N,20560,45170,N,45171,N,45172,20563,20561,45173,N,12866,N,19003, +20555,45174,45175,45176,45177,20559,14451,45178,45179,15176,N,45180,45181, +13350,45182,45345,20564,N,20556,45346,45347,20067,45348,15224,45349,20557, +45350,20562,45351,45352,45353,N,20565,45354,20558,45355,45356,13857,N,12365, +45357,45358,13858,12865,N,N,N,N,N,N,N,N,N,21797,N,19321,18798,14452,N,N,45359, +N,N,16175,20023,45360,N,45361,N,45362,45363,45364,45365,19032,45366,45367, +14136,16933,12900,45368,45369,N,45370,45371,15699,45372,45373,45374,20569, +45375,20574,20572,45376,N,20567,N,N,16943,20570,N,20573,20571,45377,19037,N, +20568,45378,16174,45379,19315,20575,20576,N,N,N,N,N,N,N,N,15652,20589,45380,N, +45381,18256,N,18742,20584,N,19056,N,12854,N,45382,45383,20588,45384,45385, +45386,N,N,45387,20582,20591,45388,N,16722,45389,14404,45390,18268,45391,24647, +45392,20590,17757,45393,20579,N,14454,45394,45395,14453,20577,45396,45397, +45398,45399,15450,N,20585,45400,19055,17229,20581,14193,45401,20578,20586, +20580,20049,20587,20289,45402,N,45403,N,45404,45405,N,45406,13926,N,N,14192,N, +45430,N,N,N,N,45407,45408,45409,20592,N,45410,45411,20593,20597,12366,45412,N, +45413,N,45414,19024,20596,45415,45416,45417,N,20595,20599,45418,N,45419,20598, +N,17508,N,N,45420,45421,N,45422,45423,N,14194,45424,45425,N,N,45426,N,20600, +45427,N,N,45428,45429,15429,N,16934,17509,13942,N,20601,N,N,N,N,13622,N,N, +20602,45431,N,45432,45433,20604,45434,N,N,N,45435,N,N,19253,45436,45437,45438, +14182,45601,45602,45603,N,45604,N,15153,18551,20603,45605,45606,N,45607,45608, +45609,45610,45611,N,N,N,N,N,N,N,45612,N,14917,19779,N,45613,45614,N,20606, +20771,20605,14916,N,15741,N,45615,45616,N,N,45617,14137,N,45618,N,20772,45619, +45620,13903,N,45621,N,20769,20770,N,45622,17967,45623,16764,45624,13859,N, +45625,45626,19277,20773,N,45627,N,20029,N,45628,45629,20774,45630,N,N,45631, +20777,45632,20775,45633,16718,45634,45635,N,N,N,20776,20778,45636,N,45637, +45649,N,N,20780,45638,N,N,20779,45639,19016,N,N,45640,13623,20782,20783,45641, +12847,N,45642,45643,45644,20781,N,45645,45646,45647,45648,N,45650,N,15476,N, +20786,20785,20784,45651,20566,45652,20787,45653,45654,45655,45656,15742,N, +20788,N,45657,N,N,N,45658,45659,N,19749,N,45660,45661,N,45662,N,45663,19545, +45664,45665,45666,N,20790,45667,45668,20789,20792,20791,N,N,20793,20794,12404, +45669,14389,14139,15676,17275,13860,16488,14455,45670,14702,20796,19528,17734, +45671,15225,N,20795,45672,20797,45673,N,45674,45675,N,17758,N,13173,N,N,45676, +N,N,20798,N,45677,18046,45678,N,16692,20800,20801,18476,14456,20283,20802,N,N, +13862,N,N,N,19004,16950,13937,17717,N,N,N,14195,N,45679,N,20803,N,20804,45680, +45681,18018,12639,N,N,20807,14973,45682,20806,14918,45683,20808,26222,20809, +19265,20810,N,20811,20812,15977,45684,15436,N,N,N,45685,N,N,13351,45686,20815, +45687,20813,19517,20814,N,18778,20816,20817,20818,17759,45688,N,N,20822,20820, +20821,20819,14947,20823,19562,20068,45689,N,45690,N,45691,20824,45692,45693,N, +N,45694,N,16424,20825,15706,N,45857,20826,N,17276,20031,17760,N,45858,N,45859, +45860,45861,N,45862,21061,N,45863,N,N,20827,29733,13893,45864,N,20828,19294, +45865,N,N,45866,15720,17020,N,20830,18020,N,N,20831,45867,N,20832,13102,45868, +45869,45870,20833,13863,45871,17996,12666,15696,N,N,18465,20834,17761,45872, +45873,16207,20835,45874,18988,16474,13346,N,13353,20836,N,N,20838,N,N,14138, +45875,45876,20837,45877,45878,20083,45879,N,N,N,N,15721,N,N,N,N,45880,N,18493, +19020,N,20839,45881,19832,20840,N,N,N,20841,N,17790,45882,45883,20842,N,45884, +16425,14974,14196,20843,15177,14703,45885,N,N,N,N,N,N,17510,20845,45886,N, +16935,N,45887,14959,20846,20847,16688,N,20844,N,N,N,N,20849,45888,19254,45889, +45890,N,45891,14692,45892,N,20848,45893,45894,45895,N,14197,14942,18285,45896, +N,N,20852,20850,N,N,N,45897,18811,15978,20859,13156,20853,20851,16719,N,45898, +45899,45900,N,N,N,20855,N,20854,45901,N,45902,13124,N,45903,N,14176,20860, +20013,45904,N,45905,20856,N,N,N,20861,20858,45906,20857,45907,45908,45909, +45910,N,45911,20047,45912,N,N,14457,12867,N,N,20084,45913,45914,45915,45916,N, +15733,17752,14693,21026,21027,N,45917,45918,20069,N,N,20267,21029,45919,45920, +45921,14458,45922,45923,21028,45924,13103,N,45925,21030,N,19286,45926,17468, +45927,19750,45928,19033,N,N,45929,21031,N,45930,N,45931,28757,N,45932,17968, +45933,21032,13354,19507,N,45934,45935,15905,21033,19047,21037,45936,16426, +21034,13904,45937,21035,13355,45938,45939,45940,N,45941,N,N,N,45942,45943, +14126,21038,45944,21039,45945,45946,21040,21041,15451,N,N,N,14459,19550,45947, +19560,18039,45948,N,19057,21042,N,21043,N,45949,45950,46113,21045,N,21047, +21046,46114,N,46115,N,21048,12861,19276,46116,14972,21049,46117,46118,16729, +46119,46120,15906,13865,N,21050,N,46121,N,46122,46123,46124,18523,46125,46126, +46127,N,21051,46128,21052,46129,21053,N,46130,N,N,21054,18724,13928,12389, +46131,46132,46133,17983,21055,15677,46134,16489,N,21057,21056,15907,14433, +21059,18494,46136,46135,21060,N,N,N,18524,16948,17006,13864,N,N,18030,17201, +46137,18286,46138,19278,N,21062,N,16490,46139,N,46140,N,46141,14133,N,N,21063, +N,N,46142,46143,21064,12588,12405,13421,46144,16936,13649,19825,N,21067,12855, +46145,N,21066,N,N,46146,13866,N,N,21068,46147,19569,N,N,46148,46149,N,N,N,N,N, +46150,N,N,N,N,46151,46152,N,21069,N,20050,46153,14460,N,N,46154,N,14390,21070, +46155,N,N,46156,21072,21071,N,16223,12601,46157,46158,N,12638,21073,46159, +21074,N,46160,14391,46161,46162,21075,46163,46164,N,46165,13678,N,46166,N,N, +46167,N,15154,21076,N,46168,N,N,19316,14901,13658,19751,16720,18495,15485, +46169,N,N,46170,46171,15687,46172,15464,15477,N,15734,46173,18496,N,46174, +46175,21079,46176,12611,16721,14461,14405,13927,46177,46178,21083,17185,17022, +13867,15908,21084,21082,12868,16998,15416,15179,12582,N,46179,13168,14694, +15178,N,21085,21086,46180,13641,13126,N,N,N,14695,13640,17503,12581,17969, +19518,14625,19833,17735,14462,N,46181,N,N,N,N,N,N,46182,14127,N,21095,N,13923, +19274,46183,N,N,N,N,18525,46184,46185,21094,46186,13406,21089,21090,21092, +46187,N,46188,N,N,46189,46190,21093,N,13659,16225,N,18989,21091,21087,14435,N, +21088,N,20260,46191,46192,N,19058,46193,17512,14434,14704,N,N,46194,21096, +46195,N,18013,N,N,N,N,N,N,N,N,N,N,N,N,46196,21100,N,N,46197,N,46198,N,46199, +46200,15486,46201,15478,46202,N,46203,46204,N,21103,21101,N,19491,46205,21098, +21107,21102,N,N,N,21105,14406,19519,N,46206,21106,46369,N,46370,21108,46371, +21110,N,46372,46373,N,14960,20290,46374,21099,21097,21109,46375,21104,N,N, +46376,46377,N,N,N,N,N,46378,N,N,46379,N,46380,21112,N,21283,21114,46381,46382, +21118,46383,46384,21281,21115,46385,46386,21310,N,46387,14953,13105,N,N,N, +46388,21113,46389,46390,46391,21285,12406,21284,46392,12325,18762,21282,N, +21116,N,46393,21111,21117,14920,46394,N,N,46395,46396,N,N,N,N,N,N,N,N,N,21286, +N,N,N,N,N,N,N,46397,12407,21295,N,N,21287,21288,N,15909,19305,46398,N,46399, +21293,21292,46400,N,N,17711,N,N,N,46401,N,N,N,21294,N,46402,21291,46403,46404, +46405,46406,N,N,12596,46407,14902,16176,46408,46409,N,N,46410,46411,46412, +21289,17762,N,N,N,21290,46413,12322,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +46414,46415,N,N,21300,19747,N,15911,46416,21306,N,46417,46418,N,21305,21296,N, +46419,46420,46421,16963,N,21297,46422,N,N,17007,21302,15910,46423,N,46424, +46425,N,21299,46426,N,19556,46427,46428,N,14140,N,N,21303,21304,46429,N,46430, +46431,21301,21307,46432,N,46433,46434,N,21298,46435,N,46436,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,21313,21318,N,21314,46437,21309,46438,46439,21319,16689, +N,46440,21321,46441,14626,21311,17277,N,N,46442,46443,N,46444,46445,46446, +46447,N,N,46448,21315,21308,13357,N,13422,13157,21316,21312,N,N,N,46449,46450, +N,N,14198,21322,21320,16723,13642,13868,46451,21317,N,13940,N,46452,N,N,N, +12612,N,N,N,N,N,N,N,N,46453,N,46454,N,46455,21326,21324,46456,21543,N,46457,N, +46458,46459,N,46460,N,N,46461,46462,46625,21329,N,N,46626,46627,N,21323,46628, +21327,N,46629,21325,N,N,46630,15180,21328,N,N,N,N,46631,N,N,N,N,N,N,N,N,N,N,N, +N,46632,21331,N,21336,N,N,N,21334,21333,46633,46634,17202,N,46635,12869,46636, +N,N,46637,46638,46639,46640,46641,46642,N,21330,N,21332,15912,12595,46643,N, +21335,N,N,N,N,N,N,N,N,N,N,N,N,N,12894,N,N,46644,N,N,21346,46645,15996,21342, +46646,21340,46647,21341,46648,21343,46649,N,46650,46651,46652,N,46653,46654, +46655,12605,46656,46657,N,46658,N,N,46659,N,46660,16697,46661,21337,46662, +21338,N,N,N,46663,N,N,N,N,N,N,13178,N,N,46664,N,46665,46666,46667,46668,21345, +N,46669,N,13423,46670,21348,21344,21347,46671,N,46672,N,46673,46674,N,18990, +46675,N,N,18005,N,18488,N,N,N,N,N,21350,N,N,N,46676,46677,21349,13125,46678,N, +21351,46679,46680,N,N,21354,N,N,N,N,21353,46681,N,N,N,46682,46683,N,N,46684, +46685,46686,21352,N,18233,N,N,21355,46687,46688,46689,46690,N,46691,46692, +46693,21356,N,N,46694,N,46695,21358,N,21357,46696,N,N,N,N,21360,N,46697,N, +21363,21361,21359,21362,N,46698,N,N,21364,46699,46700,46701,46704,46705,21365, +46702,46703,21366,N,21367,N,N,N,21368,20805,46706,15484,15181,46707,46708, +12915,46709,12408,46710,N,17220,46711,46712,46713,46714,46715,N,N,46717,N, +46718,21369,N,14884,46716,12367,16222,N,N,46881,46882,N,21370,14407,N,N,14705, +N,21372,21371,46883,46884,19040,21373,N,N,46885,21537,21374,46886,21538,46887, +21539,N,14199,N,46888,12640,21540,N,46889,21542,N,21541,N,46890,46891,21544, +46892,N,17754,46893,N,46894,46895,46896,46897,21545,12341,14943,46898,46899,N, +46900,14141,46901,46902,17231,N,N,46903,46904,N,N,21546,21547,N,N,21549,N, +46905,46906,46907,21550,N,14948,N,N,46908,46909,13905,N,N,19255,N,46910,46911, +21548,21551,14913,14627,46912,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21555,46913,N,14885, +46914,17203,46915,46916,21552,17498,46917,N,46918,46919,46920,46921,46922,N, +46923,46924,46925,N,46926,N,46927,46928,46929,46930,N,46931,21556,N,46932, +16226,46933,N,N,N,N,21554,21557,N,14143,46934,N,N,N,N,N,N,21558,46935,46944,N, +46936,N,46937,46938,N,46939,46940,46941,46942,21559,46943,14628,13120,21561,N, +N,46945,46946,46947,21562,N,46948,N,N,N,21563,N,N,21560,N,N,N,N,46949,N,N,N,N, +46950,N,N,21553,N,N,21564,N,N,21565,46951,46952,N,N,19300,46953,N,15979,46954, +N,N,21567,21568,21566,46955,21570,N,N,N,N,N,18232,46956,46957,12392,18774, +46974,N,21571,46958,N,46959,46960,N,46961,N,N,N,46962,N,N,46963,N,N,N,15997, +46964,46965,15417,46966,18269,13424,N,14955,46967,46968,46969,19289,N,17970, +46970,46971,14200,16975,N,46972,46973,21569,21572,47137,47138,N,N,N,N,N,N,N, +16964,N,N,N,21573,N,47139,N,21574,47140,47141,47142,21576,N,N,17513,N,47143, +47144,N,N,13358,N,N,47145,N,29729,12641,19059,47146,N,15980,17736,N,N,N,47147, +14950,N,N,21582,N,47148,19005,20061,N,N,N,N,N,N,N,47149,12916,21578,47150, +47151,N,47152,47153,16698,21581,N,17763,47154,N,17737,17764,18489,17485,N,N,N, +14921,47155,N,47156,21577,N,47157,N,N,47158,47159,12662,N,17718,N,N,N,N,21579, +N,21575,N,N,16208,N,N,47160,21583,N,N,47161,N,15694,47162,47163,47164,N,13869, +N,21584,N,47165,47166,47167,47168,N,47169,47170,N,47171,47172,N,N,19048,47173, +N,47174,16765,N,N,N,N,17478,47175,N,21586,47176,47177,47178,N,N,N,47179,N, +19279,47180,N,21587,N,N,21592,N,N,47181,47182,18991,N,N,N,N,21591,21585,21588, +21590,47184,N,14886,N,N,19017,47185,N,47183,21593,N,17221,47186,N,12917,N, +15981,47187,47188,N,47189,21595,47190,21594,47191,14696,47192,21596,21598, +21597,47193,N,21600,47194,21589,21602,N,47195,47196,N,21601,21599,N,N,N,47197, +N,15182,16209,N,16724,21603,16444,12397,18276,47198,N,N,N,17499,N,21605,21604, +21606,21607,21608,21609,N,N,47199,47200,N,N,19025,21610,47201,47202,N,N,12870, +21611,N,47203,47204,47205,19772,13104,N,21065,15688,16959,21612,19563,47207,N, +N,N,47208,19508,47209,47210,21614,N,16999,47211,17719,16960,18775,21615,21616, +12667,47212,47213,15418,21617,47214,N,47215,47216,12368,21618,N,N,N,N,N,21619, +47217,N,N,N,47218,12642,N,47219,13425,18016,19060,N,N,N,N,21623,16725,21622, +14144,47220,47221,19291,21621,N,17765,21625,47222,21624,47223,N,47224,47225, +47226,21627,47227,21626,47228,N,12668,N,21628,15913,21630,17189,47229,21629, +47230,18995,47393,N,N,47394,15735,17755,47395,47396,N,21793,47397,N,47398, +47399,14629,N,N,N,21794,18209,18526,19537,N,N,N,N,N,18213,47400,47401,21803, +47402,N,N,N,47403,13624,N,47404,19781,47405,N,19503,N,22060,N,21795,N,47406,N, +N,N,21798,47407,16965,N,47408,19256,N,N,N,17738,47409,47410,47411,47412,N, +21799,47413,N,N,N,47414,N,19301,47415,14922,47416,N,15914,N,N,47417,N,47418, +47419,N,21800,N,47420,15184,47421,15183,N,47422,N,N,12345,14408,47423,16427, +12369,N,N,N,N,21804,21805,N,21802,47424,47425,47426,N,N,N,47427,47428,12600, +13359,47429,21801,N,19525,18737,N,N,47430,47431,N,47432,47433,N,47434,N,12328, +47435,N,N,N,12409,N,N,N,15185,47436,12370,N,12323,47437,N,N,N,N,21810,N,N, +47438,47439,47440,N,N,21808,47441,47442,N,N,N,N,19516,N,21811,N,21809,N,47443, +21807,16177,N,N,47444,47445,21806,N,47446,47447,19034,47448,N,N,47449,N,14436, +47450,N,N,N,N,21815,21816,N,N,N,N,N,15915,N,N,N,21812,20268,N,N,47451,47452, +18252,47453,47454,21814,N,N,47455,N,N,N,47456,N,N,N,N,47457,N,N,N,N,14887,N,N, +N,47458,N,N,N,21817,47459,N,47460,18776,47461,N,N,21818,N,21813,47462,N,N,N,N, +N,N,N,N,N,47463,N,N,47464,47465,N,N,47466,19515,N,N,N,N,N,N,N,N,N,N,N,47467,N, +N,N,N,47468,N,18270,47469,N,N,47470,N,N,47471,21819,18738,47472,N,47473,47474, +47475,N,47476,N,N,N,N,47477,N,N,N,N,47478,N,N,N,N,47479,47480,47481,N,47482,N, +N,47483,N,47484,47485,21820,21824,21821,47486,N,12871,21823,N,47649,N,47650,N, +47651,15419,N,21822,14201,N,N,47652,21836,N,N,N,N,N,21829,21826,N,N,47653,N, +47654,N,N,N,47655,17252,N,21825,N,47656,21827,N,N,21828,47657,N,N,N,47658,N,N, +N,N,N,N,47659,47660,N,N,N,21830,21831,N,47661,47662,47663,N,N,N,N,N,N,47664, +13426,N,21833,21832,N,N,N,N,N,N,N,N,N,21834,47665,N,47667,N,47668,N,47669,N,N, +N,47670,15982,N,N,47671,N,N,N,N,21837,N,17500,47672,N,N,12613,N,21835,N,47666, +N,21838,N,47673,N,N,N,N,N,21839,N,21842,47674,N,21840,N,21841,N,N,N,N,N,47675, +47676,N,N,N,15186,21843,47677,N,14630,21844,47678,15226,16952,N,21845,21846, +15194,14631,47679,19538,N,N,N,13608,14409,21847,13144,N,47680,21848,N,16953,N, +N,47681,47682,21849,22051,N,21850,N,21851,N,N,21852,N,21854,N,47683,47684, +47685,47686,21855,47687,N,21856,47688,17008,47689,12583,15465,12354,47690, +16727,13360,15413,47691,14632,47692,47693,N,47694,47695,17766,47696,15649, +13361,17256,17514,12344,13625,19061,N,15426,N,N,13650,16491,15420,19752,21857, +N,47697,47698,N,N,47699,47700,13660,47701,14923,47702,47703,13106,12643,15916, +12872,47704,21858,19782,47705,N,47706,N,N,15689,47707,47708,15460,21859,13427, +18002,19497,21860,N,21861,N,N,18777,47709,N,47710,21863,N,13352,13943,21862,N, +47711,47712,47713,47714,47715,13362,N,16178,21867,15137,47716,12873,21866,N, +21864,21868,21865,18219,23629,16179,N,21869,N,N,20032,47717,21870,47718,N, +21872,47719,17278,21871,N,16419,N,15227,N,N,47720,16976,15479,18805,16492,N, +15437,21873,15917,21874,21875,12371,16954,16210,47721,21876,17971,15918,N, +15919,N,21877,N,N,16493,47722,N,N,15920,N,N,N,47723,47724,21878,N,21879,47725, +19552,N,47726,N,21880,47727,N,47728,47729,13894,47730,N,47731,15650,47732,N,N, +47733,47734,N,21881,21882,15452,16172,18036,16212,18552,18210,13897,21883,N,N, +N,13679,21884,N,13950,N,17999,12848,N,15187,21885,22050,22049,13949,N,21886,N, +17720,N,N,N,47735,47736,N,47737,N,16944,N,17739,15432,47738,47739,16728,19834, +N,47740,47741,47742,N,N,22052,47905,22053,18006,47906,15155,N,N,47907,47908, +22055,N,N,22056,47909,47910,47911,47912,N,N,N,N,N,N,N,N,N,47913,47914,N,47915, +N,22057,N,N,47916,13428,22058,47917,N,22059,N,N,N,N,N,N,N,N,47918,N,47919, +47920,12844,47921,47922,N,N,47923,N,16699,13412,47924,22061,19496,N,N,N,N, +16978,47925,13145,47926,47927,22063,22065,13407,N,47928,22062,22064,N,22067,N, +N,N,N,N,N,22066,N,22068,N,47929,N,47930,N,N,N,N,N,N,47931,N,N,N,N,47933,N, +22069,N,N,N,47932,N,N,17981,13870,N,N,N,N,N,N,12901,22070,22075,N,N,22073, +47934,19063,19062,47935,47936,N,47937,N,17767,N,N,N,22072,15700,N,22071,47938, +N,N,N,N,47939,16242,N,N,N,22076,N,47940,14954,N,N,22082,47941,N,22083,22077, +13107,22078,22087,22086,22085,22081,N,N,N,22080,N,N,22084,47943,47944,N,47945, +47946,N,19064,N,47942,N,N,N,N,N,47947,N,N,47948,N,N,N,N,47949,N,N,N,47950,N, +47951,N,N,47952,47953,N,N,47954,N,47955,N,47959,22091,22088,N,22090,N,19826, +47957,22089,N,N,47956,N,N,N,47958,N,N,22079,N,N,47960,47961,47962,47963,N, +47964,N,N,N,N,16243,47965,N,22092,47966,N,14903,47967,N,N,22093,N,N,22094,N,N, +47968,47969,N,N,N,47970,47971,N,47972,22097,47973,22096,N,N,22095,47974,N, +47975,17768,22074,N,N,N,22103,N,47976,47977,47978,47979,N,N,N,47980,N,47981,N, +22099,N,47982,47983,N,22098,N,N,N,N,47984,N,N,N,47985,22100,N,22101,N,47986,N, +58996,N,47987,N,N,22104,47988,47989,20070,N,22105,22102,N,N,N,N,N,47990,N,N,N, +47991,N,22106,N,47992,13408,22107,47994,N,47993,N,22109,22108,N,N,22110,N, +47995,47996,N,22111,N,16494,15651,N,47997,15716,N,16739,47998,14633,14904, +14634,13680,48161,N,22112,N,N,14905,N,N,14410,22113,19494,18243,22114,N,14635, +48162,48163,N,13356,N,17191,13906,48164,N,15188,18779,N,N,18497,48165,N,N,N, +22115,13429,48166,N,N,N,22118,48167,N,48168,48169,17441,N,48170,22117,22116, +22119,N,17515,N,48171,48172,N,N,N,N,16227,N,N,48174,N,N,15189,N,16458,48173, +16979,13602,N,48175,17442,N,48176,22120,22121,15983,N,N,N,N,19257,48177,N, +22124,N,N,22123,22122,18813,N,22131,N,48180,N,48178,19290,N,22125,N,48179, +48181,N,N,22127,19307,48182,22126,48183,N,N,48184,48185,N,48186,22128,N,18472, +22129,19006,22130,N,N,N,48187,N,48188,48189,48190,48191,48192,N,48193,N,13363, +19007,18223,22132,22133,N,14636,13364,22134,14392,19780,19753,13430,22136, +48194,17443,N,14637,15921,N,N,18527,N,N,15922,48195,N,N,48196,15736,N,N,N,N,N, +17516,19065,17721,N,N,14638,N,18780,N,N,N,22137,N,48197,N,48198,48199,17753, +14914,48200,N,48201,14411,48202,17517,N,N,N,48203,N,48204,N,12355,15726,14639, +19783,N,N,N,N,48205,48206,48207,N,22138,22139,18257,N,N,48208,N,22140,20087, +20269,48210,48209,N,48211,22142,22141,48212,48213,13127,48214,48215,22305,N,N, +N,22308,22309,48216,22307,48217,18752,15923,22311,22310,22306,N,48218,N,N, +22312,22313,N,48219,22314,N,N,N,22317,22315,N,22316,22318,N,12644,17518,22319, +N,14202,12918,18230,N,22320,18043,19035,48220,22321,20270,N,48221,48222,48223, +22322,19008,22325,20513,20529,48224,15408,18037,22326,N,13661,17444,12410, +22327,18982,14640,48225,N,17232,48226,48227,N,17519,N,48228,48229,48230,48231, +19567,14393,14412,48232,22328,N,48233,48234,22329,48235,22335,48236,15461,N,N, +48237,17445,48238,13871,22330,N,N,48239,18731,48240,17222,48241,48242,22331,N, +N,48243,48244,N,48245,22332,N,13872,N,22333,48246,22334,N,48247,22336,N,17782, +48248,N,22337,22338,48249,22339,N,48250,22324,22323,N,N,48251,22340,14145, +48252,48253,N,18727,48254,N,14924,18743,17446,18763,22341,N,48417,15924,12614, +48418,22342,48419,48420,N,22343,48421,19570,48422,N,18528,48423,48424,22346, +12669,16428,22345,22344,14146,16980,N,22350,22348,48425,22347,20007,14437, +48426,N,48427,15737,22349,17740,15678,N,N,48428,17984,22353,22352,N,N,48429, +48430,22351,N,22354,14438,48431,N,48434,N,N,48432,22355,18812,15707,48433, +48435,22356,18553,48436,48437,48438,N,17985,17447,N,N,N,48439,17712,N,N,22357, +13611,N,N,N,N,N,16180,48440,18732,N,48441,48442,48443,N,48444,13431,18214,N,N, +48445,48446,48447,48448,48449,N,22358,15190,19258,19259,N,N,12670,22363,48450, +N,17257,48451,48452,N,22360,N,N,N,48453,48454,48455,12919,48456,48457,48458, +48459,22573,22362,48460,48461,N,18224,48462,N,22361,N,48463,22359,48464,14714, +N,22365,48465,N,N,48466,N,N,48467,22371,22377,22369,N,17756,48468,48469,22374, +18781,48470,48471,22368,48472,22373,20071,15191,N,48473,16981,22366,N,N,48474, +13662,22376,16429,12645,22370,12920,22375,N,48475,N,13873,N,22372,N,48476,N, +48477,N,N,N,N,22378,N,N,N,N,N,48478,22380,22390,22388,N,N,22385,48479,48480, +48481,22384,20088,48482,22386,N,N,13874,48483,14641,N,48484,15738,48485,48486, +N,22393,22379,N,N,48487,N,22383,22367,48488,12922,22387,22389,17233,N,48489, +14888,12856,22381,22392,22391,13875,N,16937,13158,48490,N,N,N,14147,N,22382,N, +N,N,N,N,N,48491,48492,N,22394,48493,22397,22561,N,48494,N,48495,15421,48496, +22567,17520,22395,48497,N,N,48498,22565,48499,12921,48500,22563,22564,48501,N, +22398,22562,N,48502,48503,14439,19754,N,48504,13365,48505,48506,12633,22566, +48507,18234,12333,N,N,N,N,N,48508,48509,18529,22364,22572,22576,19557,48510, +22569,N,N,48673,17769,22574,48674,N,N,N,48675,N,48676,15984,22575,18007,48677, +48678,48679,48680,N,N,48681,48682,N,20295,N,22571,48683,48684,N,N,22577,48685, +14715,48686,16459,48687,48688,12372,22570,22568,48689,16730,N,48690,N,22396, +15156,N,N,N,N,N,N,N,16966,22589,48691,16731,22584,48692,22581,22582,48693, +15462,22585,22588,48694,48695,22583,15653,48696,22586,N,N,22580,48697,19580, +19579,48698,N,48699,22590,22591,12373,48700,48701,48702,48703,48704,22579, +48705,48706,N,48707,13938,12326,48708,N,48709,13366,N,22587,48710,N,N,N,N, +22595,22594,N,48711,48712,22599,N,N,N,48713,48714,N,N,22600,48715,48716,48717, +N,48718,N,N,22598,22601,22593,22597,N,48719,22602,N,22603,48720,48721,22592, +15228,48722,22596,16982,14642,22578,16181,N,N,N,N,22616,N,19049,N,N,22606, +22607,22608,N,N,22615,48723,22614,48724,N,19325,13367,N,22612,N,14149,13108,N, +N,22609,48725,N,20024,22611,12374,22613,48726,22604,22610,22617,14148,22605, +48727,N,N,48728,48729,N,19805,48730,48731,48732,19755,48733,48734,N,N,22620,N, +N,22624,48735,N,48736,16766,N,20089,22625,48737,48738,22622,N,22619,48739, +48740,22618,22623,N,48741,48742,N,48743,48744,N,N,N,18992,48745,N,17972,48746, +14150,48747,22626,22621,48748,22627,N,N,N,14203,N,N,N,12849,N,48749,48750, +22635,N,48751,N,13368,N,48752,48753,48754,22633,N,N,22634,14889,22632,22630, +22629,22636,22628,22638,48755,48756,12923,N,N,N,N,48757,N,N,N,N,N,N,48758, +48759,48760,48761,N,48762,48763,22640,N,48766,22639,48764,N,48765,N,N,48929, +48930,N,48931,N,N,17448,N,22643,N,22641,22631,14204,N,22642,N,22646,22645, +22647,22644,22648,48932,N,48933,48934,N,N,48935,22649,22650,19050,N,22652, +22651,15679,N,16430,12902,12924,48936,22653,48937,12351,N,N,N,16460,22654, +48938,27715,22817,14177,48939,22818,48940,48941,N,N,16495,48942,N,48943,22819, +48944,N,N,22820,13626,22821,N,22822,22823,16983,N,N,N,14413,48945,N,19553,N, +48946,N,19260,15722,22824,48947,48948,48949,N,48950,16496,28221,18530,N,15466, +48951,14925,22825,N,48952,48953,48954,16967,48955,18983,48956,N,17009,N,48957, +22828,48958,N,22826,N,22829,N,N,22827,48959,N,N,N,22830,N,N,N,N,48960,18993, +48961,N,12343,N,48962,N,N,18782,N,N,18531,48963,N,22831,48964,22834,15925, +13627,N,22832,22839,15926,N,N,N,N,22833,18244,N,N,48965,48966,48967,48968, +19806,22835,22836,22840,17770,22837,14643,16478,N,N,22854,18484,N,17010,N,N,N, +N,N,N,N,48969,N,48970,N,N,18532,23085,N,N,N,N,19066,N,48971,N,17521,48972, +48973,N,19317,48974,22843,12833,17258,48975,48976,N,N,22852,N,48977,17204, +22846,22853,22848,22855,22851,N,22850,18287,48978,22844,12925,22842,13681, +17011,22838,48979,48980,22841,14644,16475,48981,15927,22849,18258,N,N,13682, +13128,N,N,N,N,N,N,N,N,48982,N,13159,16161,22857,22862,N,22858,48983,14205, +48984,22863,15138,14697,N,N,N,N,48985,48986,15654,22845,15229,22860,48987, +48988,N,N,15192,22861,12356,48989,48990,22856,48991,N,N,48992,17449,N,48993,N, +N,48994,N,48995,13683,N,N,N,N,N,13876,N,N,N,N,N,N,N,22859,12327,48996,48997, +14915,N,48998,N,16182,N,N,N,N,N,48999,49000,N,N,49001,17522,N,49002,18516, +22865,16734,N,49003,49004,49005,49006,N,49007,N,N,16938,49008,49009,15147, +22866,49010,22868,22864,N,49011,49012,49013,19041,N,17469,49014,N,N,49015, +16732,N,N,N,N,N,N,N,N,49016,49017,19067,15438,22880,N,22879,49018,49019,16248, +N,N,49020,14206,N,49021,49022,22873,15929,49185,N,18024,18225,49186,49187,N, +49188,22871,N,49189,16733,49190,N,N,49191,15480,22876,49192,N,15928,N,22870, +22875,49193,N,18259,N,49194,49195,22869,N,14113,49196,49197,13149,N,N,49198, +22877,20011,14926,17205,22874,49199,16476,49200,14645,16228,12646,16700,22872, +13637,49201,49202,49203,N,N,14151,N,17487,22878,N,N,N,N,N,16735,N,49204,22881, +N,22883,49205,N,16951,22889,49206,22884,N,49207,22886,N,N,N,N,49208,18753, +17523,49209,22887,49210,49211,49212,19756,N,N,N,19784,13369,49213,N,N,N,49214, +12334,N,22885,N,49215,N,N,N,22882,49216,N,49217,N,13432,N,N,N,49218,49219, +12647,49220,22888,N,49221,49222,19785,22892,N,N,49223,49224,N,N,16955,N,22899, +49225,N,49226,22893,49227,N,22890,22897,49228,N,N,N,22867,N,49229,N,49230,N, +49231,N,49232,49233,22894,N,22898,49234,49235,N,18498,17771,N,49236,49237,N,N, +N,22891,49238,22895,N,N,N,14152,N,N,49239,14961,49240,N,N,16477,N,N,N,N,N,N,N, +N,49241,N,N,22903,49242,N,49243,49244,49245,49246,N,N,N,17702,N,49247,49248, +49249,49250,N,49251,49252,49253,N,49254,N,N,N,22900,N,19296,N,N,N,49255,N, +22901,N,N,N,49256,49257,N,22902,N,19534,N,16418,49258,N,49259,N,N,N,N,N,14178, +N,49260,N,49261,22909,N,N,N,N,N,N,49262,49263,49264,15157,22906,N,22905,N,N, +49265,49266,18226,49267,N,49268,17973,49269,N,49270,N,49271,17713,22907,49272, +N,49273,22908,N,18799,49274,18245,15139,N,16497,N,19280,49275,N,N,N,N,N,13129, +N,23077,22910,49276,49277,49278,N,19786,23079,N,49441,23075,N,23076,N,49442, +49443,49444,49445,16736,49446,N,49447,49448,23074,N,22847,49449,N,49450,23078, +N,23073,N,N,N,N,N,23083,23084,17703,23086,49451,49452,15140,23081,N,49453, +49454,N,13628,49455,N,23087,49456,23080,23091,N,23090,49457,23089,49458,N,N, +23092,49459,N,23094,15985,49460,23093,49461,N,N,49462,23097,N,N,49463,49464, +49465,N,N,N,N,49466,N,N,N,49467,49468,N,49469,N,23095,49470,N,49471,23096, +22896,49472,49473,N,N,49474,23099,23098,N,49475,N,N,49476,22904,23100,23088,N, +49477,15193,N,49478,N,N,23101,23102,23104,23103,23105,12926,49479,14646,49480, +49481,19068,16431,N,N,N,49482,N,14414,N,49483,23107,49484,N,N,N,23110,N,18770, +49485,13663,49486,N,49487,23109,23108,18260,23111,13877,N,N,N,23113,23112, +49488,49489,N,13370,15158,N,N,18008,49490,N,N,N,49491,14153,N,N,N,16244,N, +23114,N,16432,17704,N,18783,23115,N,49492,N,N,49493,N,N,N,49494,23116,23117,N, +49495,N,19000,21853,16454,49496,N,18764,N,14936,N,18533,18499,49497,N,N,49498, +N,17741,49499,20033,N,23119,15440,49500,N,23120,49501,12342,N,49502,13908, +16461,49503,18784,N,N,N,23121,15170,17223,49504,15195,16183,N,49505,49506, +49507,N,N,23122,N,19069,N,N,12663,15196,N,49508,N,23125,49509,23123,23126, +20025,23124,N,49510,49511,N,16507,23127,N,49512,16946,49513,N,23128,N,49514,N, +49515,13434,49516,23130,N,23129,N,N,N,49517,23131,23132,13435,N,N,18044,17206, +13676,15197,16737,N,N,15708,12336,N,N,49518,23133,49519,N,49520,49521,N,N,N, +49522,12834,23137,N,N,49523,49524,49525,N,14647,23136,49526,N,14891,15930, +49527,49528,23135,N,15931,49529,19520,14890,N,49530,49531,12375,16462,49532, +49533,N,N,N,N,N,23142,49534,49697,16433,12615,49698,49699,49700,49701,15701, +49702,19302,14962,49703,49704,49705,49706,15932,49707,16423,49708,49709,N, +49710,23141,23139,23140,49712,N,49711,N,N,17259,N,N,23334,49713,23146,15230, +14648,23144,49714,49715,N,N,23145,49716,16184,49717,N,49719,23143,N,49718, +15151,N,N,N,N,49720,49721,49722,N,49723,49724,23148,23147,23152,49725,49726, +23153,N,23149,N,13090,23150,23151,18517,49728,49729,49730,N,18785,14154,23154, +N,N,49732,16434,49733,15933,49735,49736,49737,17234,49738,49740,N,49731,49734, +49739,13895,N,23155,23159,N,N,12875,23156,23158,N,49741,49742,49743,23157,N, +49744,15723,49745,N,N,N,17224,12357,23160,49746,49747,49748,49749,23161,N, +49750,49751,N,17450,N,49752,N,20081,N,N,N,N,15171,N,49753,19051,N,N,49754, +49755,N,19261,49756,N,N,23330,23163,N,49757,23166,N,23165,49758,49759,23162, +49760,49761,23329,N,N,18014,49762,23164,N,N,49763,N,49764,49765,N,N,N,N,49766, +N,23331,N,N,15724,23332,49767,19787,18296,N,49768,23333,N,N,N,N,N,23335,N, +49769,23336,N,49770,49771,N,49772,N,23337,N,13898,12616,14649,23338,N,23339, +15729,16738,49773,49727,21080,16702,16701,16984,14919,N,N,20594,N,49774,N, +49775,14190,19757,N,19070,N,18814,49776,23340,N,N,N,49777,14963,17471,23341, +20271,N,49778,N,19262,49779,17451,23342,13436,49780,N,49781,N,N,N,23343,23344, +19546,N,19492,19318,19292,15141,23346,N,N,15467,N,49782,19281,N,23348,23351, +23350,N,13433,N,N,13664,49783,23347,N,23349,N,N,N,49784,23352,49785,49786, +16249,N,N,49787,N,19835,12361,14944,16956,N,15453,49788,49789,15987,N,N,23355, +N,N,17742,49790,23353,16939,23354,15986,19549,23356,23357,19816,49953,N,N,N, +23362,N,49954,14650,49955,18261,23359,17772,23134,23138,49956,13647,49957, +18247,N,N,N,49958,23361,N,15934,18500,N,49959,N,N,49960,23367,N,18554,N,23358, +N,23364,23363,N,49961,49962,16463,49963,N,49964,N,19309,49965,20051,49966, +49967,19303,49968,12876,15198,N,N,20296,23366,16245,N,N,N,23365,N,N,23360,N,N, +N,N,N,14415,49969,49970,49971,23372,23370,49972,12877,23368,23374,23380,N, +49973,49974,49975,N,N,49977,16968,49978,49979,19009,49980,23382,N,49981,49982, +18722,N,N,N,23381,18288,19263,13371,49983,16503,15680,N,N,49984,17491,49985, +19758,N,49986,23377,23376,N,N,49987,23378,N,23375,N,49988,23383,N,23373,N,N, +23371,N,23379,23369,49989,17260,49990,19576,15430,14964,49991,49992,N,49976,N, +14906,N,N,19311,13121,17486,17994,12617,N,N,N,N,N,N,N,N,N,N,N,N,N,N,16498, +49994,N,16436,14122,N,49995,N,N,N,49996,23385,49997,N,14651,13180,N,N,N,N, +49999,49998,23387,13172,23393,50000,50001,N,50002,50003,50004,23390,50005, +16499,N,N,N,13131,14892,N,50006,13130,14927,N,50007,23388,14181,14155,17773, +50008,50009,23386,N,12358,N,50010,N,50011,23389,23391,N,13901,14124,49993, +13372,13643,50012,N,50013,50014,23394,N,50015,14969,19313,N,15159,N,N,N,23395, +N,N,N,18736,N,N,N,50016,N,N,50017,50018,50019,50020,50021,N,23407,50022,12851, +23396,N,50023,50024,50025,50026,N,23413,23397,N,20034,50027,23404,50028,18271, +50029,N,50030,N,N,N,N,23412,N,23399,N,N,N,12340,23401,N,50031,14652,50032,N, +50033,23403,50034,23402,N,23398,23409,50035,15935,50036,N,50037,21613,14440, +19836,50038,50039,N,N,23400,50040,17524,13091,14893,50041,23392,N,23408,13153, +N,N,23406,23410,50042,17774,N,N,N,N,N,N,N,13438,50043,23602,N,50044,19529, +23415,13437,50045,23422,N,50046,50209,50210,19264,50211,23585,23587,50212, +23591,23417,50213,17194,N,50214,50215,N,17775,23595,23420,N,23592,N,50216,N, +23586,50217,N,50218,50219,50220,50221,16185,23596,50222,50223,16435,N,N,50224, +50225,N,N,23594,13373,50226,50227,50228,20304,23414,N,N,23590,12376,50229,N, +23416,50230,50231,19514,23421,16162,17479,23411,50232,50233,23589,50234,N,N, +50235,50236,N,16250,23599,13169,14369,N,N,N,N,23601,23418,23600,N,23593,23419, +N,23597,N,23598,N,N,N,N,N,23615,50237,N,50238,17998,50239,23588,N,50240,23611, +N,50241,N,23613,N,17496,N,N,50242,N,N,50243,N,N,N,50244,19788,N,N,N,50245,N,N, +N,N,18806,23608,16970,N,50246,N,23614,16703,50247,23605,23618,23617,N,18031, +23616,18026,50248,50249,50250,50251,N,50252,50253,23620,23607,50254,13896, +23610,15709,50255,50256,50257,18272,23612,13899,N,23604,23606,23603,50258, +50259,20272,13146,23609,50260,50261,23619,13109,N,N,N,N,N,N,N,14951,N,N,50262, +12637,N,N,23636,50263,N,20273,23639,50264,N,50265,N,N,16186,23638,N,N,N,23637, +50266,N,N,N,50267,50268,23634,50269,N,N,50270,N,50271,23622,50272,N,23651, +23621,N,23640,N,N,50273,50274,N,50275,23632,50276,N,23627,23624,N,23625,N, +23633,N,50277,N,29730,50278,N,23630,14653,17480,16740,23628,N,23623,50279,N, +23626,N,N,50280,50281,19789,19306,N,N,N,23631,23641,N,N,N,50282,N,N,50283,N, +23649,23642,N,N,23655,N,23653,50284,50285,N,50286,23648,50287,N,50288,N,N,N, +23647,N,17488,N,16741,50289,23645,50290,50291,23643,50292,N,23650,N,N,N,N, +23656,18549,23662,N,N,50293,N,50294,23657,23660,23654,50295,N,17268,N,18744, +50296,23644,N,50297,23652,15936,50298,19535,23672,23659,50299,N,N,N,50300, +14370,12835,13151,N,N,23635,N,50301,N,50302,N,50465,15937,23664,50466,23671, +15481,13170,50467,N,17198,50468,50469,N,N,N,N,23661,50470,50471,23666,23670, +50472,50473,13878,N,N,50474,N,50475,50476,50477,N,N,50478,50479,N,13644,23668, +N,50480,N,N,N,13601,N,17995,23667,N,50481,N,23669,50482,N,N,50483,N,N,N,N,N,N, +50484,23663,50485,N,N,N,N,23665,N,N,N,N,N,50486,13152,17225,50487,N,50488, +23676,N,50489,50490,N,50491,N,50492,N,23674,14441,N,23673,50493,N,N,N,N,N, +23841,N,N,N,50494,23384,50495,50496,50497,23675,N,23677,23678,N,50498,N,N,N,N, +23852,50499,23848,N,23405,50500,50501,50502,N,23847,50503,N,N,N,23846,N,N, +23843,N,50504,50505,50506,N,23658,23845,23844,N,N,50507,N,50509,50508,N,N, +50510,N,N,N,50511,23850,N,20262,50512,50513,50514,N,N,N,23853,13947,50515, +50516,23849,23851,N,N,N,N,50517,N,N,50518,18471,N,23854,N,50519,N,N,N,50520, +50521,50522,N,N,N,N,N,N,N,23858,23855,50523,50524,50525,50526,19827,23856, +50527,50528,N,50529,23646,N,N,N,N,50530,50531,50532,23859,N,N,N,23860,50533,N, +N,N,50534,N,12597,50535,23862,14183,15393,N,13909,50536,N,N,12836,50537,N,N, +50538,50539,N,N,50540,N,N,19807,N,N,50541,50542,23864,23863,23866,13629,50543, +N,13910,13374,50544,N,N,N,23869,N,N,50545,23868,N,23870,50546,N,12878,50547, +17207,N,23871,N,50548,13375,23873,N,50549,N,50550,23872,N,23874,N,50551,N, +23875,50552,23876,15199,16437,14881,N,18800,50553,N,19042,20292,50554,N,N, +50555,15221,50556,N,N,14928,20082,50557,N,N,23877,23878,N,15200,N,50558,50721, +23879,23880,N,50722,23882,23881,50723,19288,N,N,15710,15468,15172,N,23883,N,N, +N,N,N,N,N,23885,16163,50724,23884,N,N,50725,N,N,23886,50726,50727,N,50728, +50729,23887,N,N,N,50730,50731,23888,23889,50732,50733,50734,23890,50735,23892, +23891,23893,12837,17226,N,23894,50736,50737,15142,13132,23895,50738,50739, +17730,21580,N,N,50740,50741,13603,23896,N,N,50742,N,23897,50743,19052,19304,N, +N,N,17991,23898,18534,N,50744,N,18555,N,50745,19539,N,N,N,23899,N,50746,N, +50747,N,N,50748,50749,N,N,N,23901,23900,N,50750,23903,N,50751,N,23902,N,N,N, +50752,N,50753,N,N,N,N,N,50754,50755,N,50756,50757,N,N,23905,50758,N,N,N,50759, +50760,15201,50761,19505,50762,23906,23907,N,N,13604,N,50763,N,23908,N,N,N, +50764,N,N,N,23910,23909,N,50765,50766,50767,N,N,N,50768,N,50769,N,N,N,N,50770, +16229,50771,50772,18745,12618,N,50773,50774,N,N,18501,50775,17525,15681,13665, +N,N,N,N,N,N,N,50776,50777,N,50778,18502,50779,15406,N,50780,N,50781,23912,N, +13376,N,50782,12664,50783,50784,18034,23911,14654,17235,N,23913,N,N,N,N,50998, +23921,N,23914,50785,N,50786,N,50787,16961,N,13666,23922,50788,N,50789,N,50790, +50791,14184,50792,N,13605,23920,N,N,23918,23915,19808,N,50793,50794,50795, +17472,50796,N,N,18009,23916,N,N,23924,N,23923,14115,50797,50798,12845,50799, +50800,14907,23917,23919,50801,N,N,50802,N,19287,17012,N,N,N,N,N,N,N,N,19319,N, +N,23932,N,50803,23933,50804,12879,50805,N,N,N,18984,19581,24097,15395,15938, +23928,23934,12648,N,13879,50806,N,23925,23930,50807,N,N,16500,18289,N,18535, +50808,N,50809,50810,50811,50812,23927,50813,19233,50814,23929,N,24100,50977, +24098,50978,23931,N,N,50979,19234,18248,13667,N,17701,N,50980,17261,50981, +24101,50982,50983,N,50984,24099,16985,23926,50985,12619,50986,50987,N,N,50988, +N,N,50989,19790,24112,N,50990,50991,N,50992,24111,50993,N,N,N,16502,N,24108, +50994,19820,N,N,17974,24102,N,N,N,N,N,17477,50995,50996,50997,12620,14655, +24105,N,N,50999,51000,N,51001,15655,24110,N,24109,24104,N,24107,51002,N,13160, +51003,24106,18249,51004,N,20014,N,N,15988,16501,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,51005,N,24118,24116,N,18765,N,51006,51007,N,51008,N,24113,24115,51009, +12602,51010,N,14656,20274,N,13117,N,18786,51011,51012,N,N,N,19809,N,N,13092, +16187,24117,N,N,51013,N,N,N,N,N,51014,N,N,24122,N,51015,15939,N,N,N,19760,N, +24119,N,N,51016,51017,24114,51018,24120,51019,51020,51021,20062,N,17779,17986, +N,N,N,N,N,N,N,N,N,N,N,N,N,51022,N,51023,N,N,13110,N,N,12629,N,51024,24126,N, +51025,24129,51026,N,N,20035,51027,N,51028,19812,N,N,N,51029,24136,24130,24127, +51030,N,51031,20052,24133,N,51032,51033,N,15690,24135,N,N,24140,51034,N,17777, +24138,N,51035,N,51036,24132,51037,51038,17208,51039,N,24139,51040,24128,N, +24134,51041,24141,12412,24131,N,24142,51042,51043,16188,N,15711,51044,18981, +51045,14894,N,24123,24137,17722,51046,51047,N,N,N,51048,16438,N,13161,14929, +15940,24125,15682,N,N,N,N,N,N,N,14156,N,24124,N,N,N,24146,15725,14394,N,24161, +51049,24155,13684,17743,51050,24150,24159,12335,12594,51051,N,12857,N,24152, +16940,24143,24145,14657,N,N,51052,N,N,N,51053,N,24162,51054,24157,51055,51056, +N,24149,N,N,N,N,24156,51057,51058,N,N,51059,51060,19499,51061,N,24154,24158, +51062,N,51063,51064,51065,51066,N,14416,51067,15941,N,N,17209,51068,51069, +51070,24148,N,N,51233,51234,N,N,N,19759,51235,N,N,24151,N,N,24144,17778,N,N, +24147,51236,N,N,24153,N,N,N,N,51237,N,51238,20305,15422,19326,N,24163,N,N,N,N, +N,N,N,N,N,18478,51239,N,24175,14395,N,N,51240,N,N,15712,N,24165,51241,N,N, +20015,14658,N,24178,51242,N,12398,N,N,24176,N,51243,N,N,24164,N,N,51244,51245, +24170,N,51246,24172,51247,N,N,19791,24167,N,N,17710,51248,N,24169,N,51249, +51250,51251,24177,51252,24171,19527,N,51253,51254,24166,51255,15394,24190, +51256,51257,51258,N,13162,N,24168,24173,24174,N,N,N,N,N,N,N,17004,16986,N,N,N, +N,N,N,N,N,N,N,N,N,51259,24182,51260,51261,24188,N,N,24186,N,17705,N,N,24355, +24183,51262,N,51263,N,51264,24184,24160,13689,18746,N,51265,N,15423,N,51266, +14711,51267,N,51268,51269,N,20275,N,24180,N,24354,12649,16742,51270,N,51271,N, +51272,51273,N,N,N,N,18297,N,13377,20090,N,N,51274,N,N,51275,51276,19489,17490, +51283,N,51277,51278,24187,24189,51279,N,N,51280,N,16690,N,N,51281,51282,N, +24353,24185,N,24179,N,N,N,13379,N,N,N,N,N,N,N,N,N,51284,N,51285,51286,51287, +14185,N,N,51288,24367,51289,51290,24362,16504,51291,51292,13155,N,51293,51294, +N,15713,N,24371,N,51295,N,N,N,51296,24364,17452,24361,17497,N,N,N,24396,N,N,N, +24358,N,24357,N,24366,51297,51298,N,24360,24359,24365,51299,16417,N,24356, +51300,51301,N,N,51302,51303,51304,24368,N,51305,24369,51306,51307,51308,N, +51309,13378,N,N,51310,N,N,N,N,51311,51312,24374,N,24373,24375,51313,51314, +51315,51316,N,24378,N,N,N,51317,51318,51319,17731,N,24372,N,51320,51321,N,N, +24376,N,N,51322,N,N,N,14179,17017,24370,18235,N,51323,24377,51324,51325,N, +51326,N,N,N,N,N,N,N,N,N,24382,24380,N,N,24383,N,51489,24386,N,N,51490,24379, +14698,18216,N,N,24121,N,N,N,51491,51492,N,19828,24381,N,24385,17013,51493, +24384,N,24363,N,51494,28521,N,N,51495,24389,N,51496,51497,24393,51498,24391,N, +N,N,51499,51500,51501,N,24387,N,24388,N,51502,N,24392,N,24390,N,N,N,18766,N, +51503,24398,N,24395,24394,N,24397,18004,24399,51504,N,N,51505,N,N,17269,17005, +N,N,N,N,16421,N,N,51506,24400,N,24402,N,51507,N,N,51508,N,51509,N,N,51510,N, +24401,N,N,N,N,51511,51512,N,N,N,51513,51514,51515,51516,24181,N,51521,N,N, +24403,N,N,51517,51518,N,N,18023,N,N,N,N,51519,51520,N,N,N,N,24404,51522,51523, +N,N,N,N,N,12880,51524,N,51525,17780,13093,N,N,N,N,51526,51527,N,13668,N,N,N, +15454,14930,51528,N,N,51529,N,N,N,51530,51531,N,N,20263,16230,N,N,N,12650,N,N, +N,24406,N,51532,51533,51534,51535,51536,24405,N,51537,N,N,N,N,N,N,N,N,51538,N, +N,N,N,N,N,51539,24409,17210,24412,24407,51540,51541,N,24411,51542,N,N,51543, +24410,17728,12377,N,N,N,N,N,N,N,N,N,N,N,N,N,20085,N,51544,24414,N,N,N,12584,N, +51545,N,51546,51547,51548,51549,N,51550,24416,N,N,51551,24415,N,24413,N,N,N,N, +51552,N,N,N,N,N,N,N,N,N,N,N,N,24408,N,N,N,N,N,N,N,19235,51553,N,N,24418,51554, +51555,51556,51557,51558,N,24417,N,51559,51560,N,N,51561,N,N,N,N,12651,N,N,N,N, +24420,18994,N,24419,N,51562,N,51563,19509,N,N,N,N,15943,N,N,N,N,51564,N,51565, +N,51566,51567,51568,N,N,N,N,16691,N,51569,N,N,N,15942,N,N,N,N,51570,N,N,N, +51571,51572,51573,N,20091,51574,51575,24426,N,16505,N,51576,N,51577,N,N,24422, +24427,51578,N,12652,51579,N,51580,N,51581,N,51582,N,24425,N,18273,24421,24424, +15944,51745,18513,N,N,24428,N,15441,N,N,N,N,N,N,N,N,N,N,51746,N,N,N,16506,N,N, +51747,N,N,N,24431,51748,N,51749,24423,N,14119,N,51750,N,N,24429,N,N,51751,N, +19792,24432,N,N,N,29734,51752,51753,N,N,N,15695,51754,N,51755,N,N,N,N,N,24433, +N,N,N,24434,N,N,51756,51757,18222,51758,51759,N,N,N,N,N,24436,51760,N,N,N, +24437,51761,51762,51763,N,18227,51764,N,N,N,17781,24439,N,51765,51766,N,24441, +N,20053,N,24438,51767,24440,12653,51768,24435,N,51769,51770,N,51771,N,N,21339, +24442,N,N,N,N,16743,15160,24444,N,N,N,N,24443,16164,21081,N,N,N,N,N,N,24445,N, +N,51772,24609,N,24430,24446,N,51773,24610,51774,N,N,N,N,N,18298,51775,51776, +51777,N,N,N,24611,N,N,24612,N,N,51778,N,N,N,51779,N,N,51780,24613,N,51781,N, +51782,N,N,N,N,51783,N,N,N,24614,N,17502,51784,24616,24615,N,51785,24617,N, +24618,N,51786,15455,18787,N,51787,51788,19564,24619,24620,16726,15396,24621, +24622,51789,51790,51791,N,51792,24623,19026,18503,N,N,24624,18263,N,51793, +51794,51795,N,17453,51796,N,51797,51798,N,24625,12903,51799,13677,51800,19526, +51801,19510,51802,12852,20276,51803,N,N,N,19282,51804,18986,N,51805,N,N,51806, +51807,N,51808,16439,N,24626,N,N,51809,51810,17987,N,51811,51812,14371,24627, +51813,14932,24629,24628,N,51814,N,N,24630,N,51815,N,N,N,51816,51817,N,N,N, +24631,51818,N,N,24632,N,N,N,N,51819,N,N,N,N,13630,N,24633,N,N,N,N,24634,51820, +N,N,N,14372,51821,51822,18504,N,51823,24636,N,51824,N,15989,N,N,24635,N,N,N,N, +51825,N,N,51826,13880,24637,24639,N,24638,51827,N,51828,N,N,51829,N,24640,N, +14417,N,24641,N,N,51830,51831,13929,51832,16704,N,14717,N,N,N,51833,24643, +24644,24642,N,N,51834,N,N,N,15469,N,N,17992,13881,N,N,N,N,N,51835,51836,N,N, +24646,17196,24645,51837,51838,20277,18274,52001,52002,N,52003,52004,N,52005,N, +N,24649,52006,N,52007,N,N,N,N,52008,52009,N,N,24651,24648,52010,52011,N,19540, +24650,24652,52012,20036,N,N,52013,N,52014,24656,N,52015,52016,24655,17270, +18221,52017,N,14373,24654,N,52018,52019,N,24653,52020,19761,19762,N,N,52021, +52022,N,52023,24657,12654,N,N,N,52024,14710,15202,N,N,N,N,N,N,N,52025,24658, +24659,52026,N,52027,N,N,N,52028,24661,52029,N,N,N,N,52030,52031,52032,52033,N, +N,15683,N,N,52034,52035,24663,52036,24662,52037,52038,N,52039,52040,24664, +52041,13133,N,N,24666,N,52042,24665,52043,24668,24667,52044,N,N,N,52045,52046, +N,52047,14396,52048,52049,20008,N,13900,N,12838,N,N,52050,N,52051,N,N,52052,N, +52053,13930,52054,52055,N,N,N,52056,N,52057,52058,52059,N,52060,N,N,52061, +52062,N,N,13409,52063,52064,N,52065,N,N,N,N,20072,24670,N,52066,N,52067,N, +52068,N,24672,52069,52070,N,52071,24673,N,12881,N,N,52072,52073,N,24669,52074, +15161,52075,52076,17473,24671,52077,N,N,52078,52079,N,N,52080,N,N,52081,N,N,N, +52082,24676,N,15470,52083,N,52084,N,24674,52085,52086,N,52087,14142,N,N,18505, +24675,N,N,24702,N,N,52088,52089,N,52090,24681,52091,52092,52093,N,52094,14397, +52257,52258,52259,N,13669,52260,24678,19837,52261,N,20016,52262,N,N,N,N,N,N, +52263,N,N,N,N,N,N,N,N,52264,52265,N,N,N,N,N,N,17014,N,52266,24680,52267,N, +52268,52269,52270,52271,52272,52273,52274,52275,52276,52277,24682,20054,13911, +18556,18250,N,N,52278,24683,N,N,N,N,24685,52279,24688,N,52280,52281,N,52282, +52283,N,N,N,52284,N,52285,N,N,N,52286,52287,N,N,24684,N,52288,N,24687,14442, +12621,24689,52289,16240,24686,20060,N,52290,24692,29732,N,52291,52292,52293, +24690,24693,52294,N,52295,52296,24679,24691,52297,52298,14908,N,N,24694,N,N,N, +N,N,N,N,24695,N,52299,52300,N,19838,N,52301,52302,52303,N,52304,N,24696,N,N,N, +52305,52306,52307,52308,N,N,N,N,N,52309,52310,52311,N,52312,N,24697,52313, +52314,52315,24677,52316,N,N,52317,24698,52318,52319,52320,52321,N,N,52322, +52323,13380,52324,52325,N,N,52326,N,N,N,52327,N,52328,N,15397,N,52329,N,N,N,N, +N,N,N,N,52330,52331,24699,N,52332,N,N,24700,52333,N,N,52334,24701,N,N,N,52335, +N,52336,52337,12603,N,52338,52339,24865,N,18747,24866,52340,N,13348,24867, +52341,24868,52342,52343,N,N,24869,52344,24871,24872,24870,N,52345,N,18771, +24874,24873,N,52346,52347,52348,N,N,52349,24876,24875,24877,52350,N,N,N,N,N, +24878,24880,24879,N,N,14713,52513,24882,N,24881,52514,52515,13381,N,16211,N, +17724,N,24883,16440,52516,52517,N,15162,52518,12665,24884,52519,19793,52520, +52521,19043,24885,N,N,52522,17732,19763,14659,16189,N,N,52523,17227,21044, +52524,17454,12904,24886,52525,52526,52527,52528,N,N,52529,24887,N,24892,52530, +52531,24890,24889,23106,13094,24888,52532,12378,52533,18474,52534,N,18506,N,N, +52535,N,20017,24893,24891,17244,16422,52536,52537,18475,52538,18733,N,24895, +20012,14157,24896,N,24894,18518,24897,N,24898,N,52539,12379,52540,N,15990, +24903,N,24900,18029,24899,52541,52542,52543,52544,52545,52546,13606,N,52547, +24906,N,N,52548,24901,24902,N,24905,24904,18725,N,N,16706,16705,52549,13631, +52550,52551,24907,52552,N,N,N,52553,24908,N,52554,24909,N,N,N,N,52555,24911, +52556,24910,N,N,N,N,N,12630,N,N,N,N,N,24919,18536,24913,52557,24915,N,N,24917, +16190,52558,N,24918,24916,15424,52559,52560,52561,24912,24914,52562,18754, +52563,15945,N,N,24921,N,52564,24920,52565,52566,N,N,24922,N,15398,14895,N, +52567,17783,24923,N,17483,52568,N,24925,52569,52570,52571,20001,24924,52572,N, +N,52573,N,16745,N,N,52574,N,52575,52576,24930,52577,24932,24933,17236,N,N,N,N, +52578,24931,N,24928,N,24926,24927,52579,24929,52580,52581,52582,N,N,52583, +52584,24936,52585,24934,52586,24935,N,52587,N,N,52588,52589,N,52590,52591,N,N, +52592,N,52593,52594,52595,52596,24937,24939,24940,24941,52597,24942,52598, +52599,24938,N,52600,N,N,N,52601,N,N,24944,N,52602,52603,24943,52604,N,N,52605, +52606,52769,24945,52770,N,N,N,52772,52773,20037,52774,52775,52776,24948,24946, +24947,52777,52771,52778,13410,N,N,N,N,N,19582,N,N,52779,19018,N,24950,52780,N, +N,24949,N,N,52781,N,24951,24952,N,52782,52783,N,24956,24953,24954,24955,N, +24957,52784,52785,52786,24958,52787,25121,N,52788,N,25122,N,25123,N,18479, +17744,25124,18290,18740,N,25125,52789,N,25126,17706,52790,13095,14660,25127,N, +N,25128,52791,52792,25129,N,15145,N,N,25131,N,52793,25130,N,N,25132,25133, +52794,52795,52796,N,52797,52798,N,52799,52800,52801,52802,52803,52804,52805,N, +52806,N,N,52807,18537,N,25134,N,N,N,25135,N,N,29545,25136,25137,25138,N,N, +52808,N,15150,N,52809,25139,18262,N,52810,19295,N,12622,52811,12631,52812, +52813,25140,52814,N,N,N,25142,N,52815,N,25141,17776,N,52816,N,16441,23865,N, +25143,19521,52817,25144,N,13382,18519,25145,52818,25146,52819,N,25147,N,52820, +N,19548,N,52821,52822,19541,N,17470,N,52823,N,16746,52824,N,25149,52825,N, +15714,52826,15946,N,N,25152,N,52827,25151,25150,18557,52828,13383,14377,N, +52829,N,N,N,52830,N,52831,52832,N,52833,N,52834,52835,25158,52836,N,25155, +16191,19506,N,52837,N,25154,25156,25157,N,52838,25153,N,N,N,52839,52840,52841, +N,N,N,N,52842,52843,52844,25159,25160,52845,17455,N,13411,52846,52847,N,17253, +N,52848,N,N,52849,52850,25161,N,N,52851,N,N,52852,52853,52854,N,N,52855,N,N,N, +52856,52857,N,N,25162,25165,52858,N,52859,52860,52861,16231,52862,17988,53025, +25166,19283,53026,25163,N,53027,25164,53028,N,N,N,53029,N,53030,53031,53032,N, +N,N,N,25169,53033,N,N,53034,25168,25167,53035,N,N,N,53036,N,N,N,N,N,N,25171, +53037,53038,25170,N,N,25172,N,N,53039,53040,53041,N,N,N,53042,N,N,N,25174, +53043,25173,N,53044,N,N,19021,N,53045,N,N,53046,N,15702,20038,53047,53048, +25175,53049,N,17975,N,53050,25176,N,N,25177,N,25181,25179,25180,53051,25178,N, +N,N,53052,N,N,N,25182,N,53053,N,N,N,25183,N,N,N,53054,53055,N,N,53056,N,25184, +N,53057,25185,19511,25186,N,53058,53059,53060,N,19568,25187,53061,17230,53062, +18282,N,13931,53063,N,53064,17211,25188,13882,53065,53066,N,16464,53067,N,N,N, +53068,N,N,53069,25189,14909,N,N,53070,53071,N,N,53072,N,N,25190,53073,53074,N, +N,53075,25191,N,14374,14933,N,N,N,N,N,N,N,53076,N,N,25193,53077,53078,53079,N, +17750,14934,13646,N,N,N,N,N,53080,53081,N,53082,N,19236,N,18251,53083,N,53084, +N,N,17751,N,N,N,N,14684,N,N,N,53085,53086,25195,N,53087,53088,N,N,N,53089,N, +53090,N,N,N,53091,N,N,N,N,N,N,N,N,N,53092,15947,53093,N,53094,53095,N,53096, +53097,N,N,N,53098,N,53099,20018,14661,N,53100,14375,N,N,18467,N,25197,N,N,N,N, +N,53101,N,25199,N,53102,N,N,14443,N,N,N,N,25198,17526,N,N,53103,N,25201,13111, +25196,53104,N,18538,N,12592,53105,14956,N,20306,53106,N,25200,N,N,53108,53109, +53110,N,53107,N,25202,53111,N,N,19019,53112,16473,25204,N,53113,53114,N,25205, +53115,53116,53117,53118,N,25203,N,N,N,N,13134,53281,25211,53282,25210,53283,N, +15399,N,N,N,25212,25207,53284,53285,53286,25213,25208,53287,N,53288,N,18520, +25206,53289,53290,25209,53291,53292,N,N,N,25378,53294,N,N,N,53295,53296,53297, +N,N,53293,N,53298,25377,19297,N,53299,N,25214,N,N,12395,N,N,53300,53301,25380, +N,53303,53304,N,N,53305,53306,N,25379,N,53307,53302,15948,N,N,N,N,53308,25381, +N,N,N,N,53309,N,16707,N,53310,25383,25382,N,N,N,N,N,N,25384,53311,N,53312,N, +53313,53314,53315,N,N,N,N,53316,25192,53317,N,53318,25194,25386,25385,53319,N, +N,N,53320,N,N,53321,53322,N,N,N,N,15400,53323,20073,53324,15442,53325,25387, +14135,N,N,53326,53327,53328,13632,13607,15203,53329,53330,N,N,N,53331,19764, +53332,N,25393,53333,25392,16708,25389,53334,N,25391,53335,53336,15691,16192, +25390,25388,N,18218,N,N,15949,N,53337,18748,53338,N,53339,N,14935,N,N,N,N, +53340,N,N,N,N,17784,N,53341,25394,53342,53343,N,53344,25395,25417,13912,N,N, +20285,16693,N,N,N,N,25396,53345,53346,12882,17527,18977,N,53347,N,53348,53349, +53350,53351,N,53352,N,N,53353,53354,25397,N,N,N,53355,N,N,N,N,13690,25398, +53356,53357,25400,53358,N,N,25401,53359,18217,53360,N,25402,53361,N,N,N,53362, +25403,25404,53363,N,13913,12883,17989,15656,15204,53364,N,53365,N,N,53366, +53367,25405,53368,15657,N,N,N,53369,N,12874,18755,N,53370,25406,53371,N,18539, +N,53372,N,N,53373,53374,16709,53537,25409,53538,25410,18281,53539,16193,25407, +N,17249,53540,53541,25408,53542,N,N,15950,53543,N,N,N,N,N,N,53544,N,N,12380, +53545,13609,N,53546,53547,N,N,N,53548,25411,53549,53550,17528,53551,25412, +16455,N,N,53552,N,N,19501,53553,N,18723,25413,25414,17237,53554,20039,N,53555, +25416,25415,53556,N,N,N,N,N,53557,N,N,N,53558,N,53559,15471,53560,53561,25418, +12400,N,53562,53563,N,25421,53564,53565,53566,25419,12884,14158,25420,14662, +14706,N,19046,25422,53567,53568,19284,53569,53570,25424,N,N,53571,16465,12623, +12858,12332,N,N,N,N,53572,53573,25423,N,53574,N,N,53575,53576,N,53577,53578, +25425,25426,15991,N,53579,N,53580,N,25427,53581,13135,N,53582,N,N,25429,N,N,N, +14186,53583,13670,N,53584,25430,13941,N,N,25431,53585,16508,53586,17997,53587, +16480,14965,53588,53589,N,25432,N,53590,53591,N,N,N,N,53592,53593,17250,16747, +53594,25434,25436,25433,25435,N,N,N,N,N,53595,14114,53596,N,N,53597,N,N,N,N,N, +25437,14118,N,53598,N,13671,19794,25439,N,N,53599,N,53600,25440,N,N,53601, +12590,53602,53603,N,N,25443,N,N,N,13174,25442,25441,53604,25445,25438,53605, +25446,20009,53606,25447,53607,25448,N,53608,21620,25450,N,25449,N,N,N,25451, +25452,53609,20021,25453,N,28783,15951,25454,25455,15703,N,17976,25456,N,53610, +53611,17192,53612,53613,25457,N,17212,25458,53614,N,N,53615,N,13861,N,20799, +17245,15411,53616,N,53617,53618,13384,25459,N,25634,N,25462,53619,13672,N, +25461,25636,N,N,N,25460,N,15952,N,N,53620,N,N,N,25464,25465,N,17707,N,N,25466, +53621,13150,N,N,53622,N,16218,18788,53623,25468,53624,53625,53626,17000,53627, +53628,53629,53630,53793,N,25463,53794,25467,25469,N,N,14971,N,N,N,53795,N, +53796,53797,53798,N,N,N,25638,18734,53799,18470,17785,N,13914,25637,25635, +53800,18485,25470,17246,17787,N,17786,53801,14966,N,N,N,N,N,N,25656,N,N,53802, +N,N,N,53803,25640,53804,25642,N,53805,53806,N,25645,53807,25646,53808,25643, +25644,53809,53810,25641,25639,N,53811,N,N,25633,N,N,N,N,N,N,N,N,N,53812,N, +19023,12885,N,53813,N,25653,N,25650,53814,25655,53815,53816,25654,N,18291, +19495,53817,15163,25648,25657,25652,53818,25651,25647,53819,25649,53820,13385, +N,N,N,53821,N,N,N,N,17213,N,53822,16509,N,53823,53824,18466,53825,N,25662, +53826,53827,N,18468,N,53828,53829,53830,53831,N,N,16481,25659,53832,N,18511, +53833,25663,19027,53834,17243,53835,25658,25660,N,N,25661,N,N,N,N,53836,N, +53837,53838,N,53839,53840,53841,N,25664,N,N,15428,N,N,N,17990,25669,25668,N, +53842,25665,53843,N,N,20278,N,N,N,N,53844,25674,53845,53846,25678,25675,53847, +53848,53849,N,53850,N,53851,25671,53852,53853,53854,53855,N,53856,25672,N, +53857,N,53858,53859,25677,53860,53861,N,25666,21077,25673,25667,N,N,25676,N, +53862,N,53863,N,N,N,25682,53864,13386,N,25679,N,53865,53866,25680,53867,N, +25681,25684,53868,N,N,N,N,53869,N,53870,53871,N,53872,25683,18550,53873,53874, +N,N,25685,20092,19053,25690,N,N,25687,N,N,53875,N,N,N,53876,N,25686,16466,N, +25689,25691,53878,53879,53880,25688,53877,25695,N,25692,53881,53882,53883, +53884,53885,53886,25693,25670,54049,N,54050,25694,25696,N,54051,N,54052,N,N, +25697,54053,54054,N,54055,N,54056,19014,N,25698,N,N,N,54057,N,N,54058,54059, +19554,N,N,13902,14121,25699,N,N,54060,54061,N,18996,N,16232,N,19504,N,54062, +25700,N,20019,N,54063,18292,N,16710,18228,N,N,15693,N,N,54064,12352,54065, +25705,25703,N,25701,13345,54066,15953,25706,N,N,25704,N,25702,25710,N,54067, +25709,25708,25707,N,N,54068,54069,N,25711,54070,54071,54072,25712,16442,54073, +25713,N,25715,N,54074,25714,N,54075,54076,54077,14418,N,N,54078,16696,54079,N, +N,25717,54080,54081,54082,17788,54083,25716,54084,54085,N,25718,54086,18997, +16748,14663,N,25719,N,N,N,54087,20040,N,54088,N,54089,N,N,N,25721,N,N,25722,N, +25723,54090,25724,N,15205,N,25725,14159,N,N,13674,13610,N,25889,54091,19571, +14664,25726,54092,54093,54094,25892,19558,N,18236,N,54095,18739,54096,54097, +54098,15715,25891,54099,15443,14665,15206,13673,18998,25890,54100,54101,N, +16711,19266,14967,54102,N,N,54103,N,N,N,54104,15207,17501,54105,25895,20063, +14937,54106,25896,16194,N,25898,N,N,N,15954,14896,N,54107,54108,54109,25897, +54110,54111,15658,14398,16712,25893,25899,54112,54113,N,N,25894,14160,54114, +25902,25906,14187,54115,N,54116,N,N,25901,54117,N,54118,54119,25910,54120, +54121,14666,N,N,19821,12348,25907,N,54122,13675,54123,25904,N,54124,N,N,N, +25905,N,54125,17789,25903,25900,N,13096,16484,N,54126,14376,54127,54128,N, +25912,N,54129,N,54130,54131,54132,N,54133,54134,N,54135,25909,N,54136,54137, +54138,N,25911,N,54139,N,25908,N,N,54140,54141,N,14161,16947,25913,16750,54142, +54305,25926,N,N,25922,25916,N,N,54306,54307,N,N,54308,25920,15482,12381,25915, +25923,25927,14667,19542,54309,17494,25917,54310,54311,25925,54312,25914,17214, +N,25919,12349,19530,N,N,54313,54314,54315,54316,54317,25918,N,N,13915,18540, +54318,54319,54320,16749,N,20048,15727,N,N,25966,N,54321,25928,54322,16510,N, +25924,25929,25931,N,17529,25934,54324,N,25930,54325,54326,N,19028,13387,54327, +54328,19531,54329,N,12382,N,54330,25933,N,20093,54331,54332,N,N,54333,54334, +25932,54323,12655,N,N,18028,25935,N,N,54335,25942,25936,25943,N,N,N,N,54336, +54337,25939,N,N,54338,N,54339,N,N,N,18299,54340,54341,15434,25941,54342,25938, +25944,25937,N,N,15684,54343,54344,N,N,19237,54345,54346,15692,54347,N,25940, +25952,54348,N,25948,54349,25951,N,25949,25953,25947,N,25921,16467,54350,N, +18507,N,25950,54351,54352,25945,54353,N,N,16673,14162,N,15659,54354,N,54355,N, +54356,N,16165,16694,25956,N,54357,25958,25959,N,N,25955,25957,54358,N,54359, +54360,N,N,54361,25946,25954,N,25962,25961,54362,N,19322,54363,54364,14123,N,N, +54365,N,N,N,N,54366,25960,N,25964,25963,25967,54367,25969,N,54368,15164,25965, +N,N,54369,54370,25970,25971,54371,N,25972,54372,25978,17723,25974,54373,25973, +25975,25976,54374,25977,N,54375,N,54376,25979,25980,54377,54378,13388,N,25981, +N,25982,54380,54379,54381,54382,54383,N,N,N,54384,54385,26145,N,54386,N,N,N,N, +26146,26147,26148,54387,26149,26150,54388,54389,26152,26151,N,N,26153,N,N, +54390,54391,54392,N,26154,26155,54393,N,54394,54395,54396,54397,26158,26156, +26157,14945,14163,N,54398,17238,N,18483,54561,15728,N,N,18253,N,18541,26159, +22637,N,N,N,54562,54563,54564,54565,N,26160,26162,N,19813,26161,26164,26163,N, +19795,54566,26165,54567,18558,54568,54569,54570,N,N,26166,N,54571,54572,N,N, +26169,N,54573,26168,26167,N,N,54574,54575,26170,14130,N,54576,N,16674,13633, +54577,N,N,54578,26174,26171,N,N,26172,N,54579,N,26175,N,26176,26173,N,N,54580, +12585,N,54581,54582,12839,N,54583,N,26178,26179,N,54584,N,26180,N,19810,N, +54585,54586,N,N,15660,N,26182,26181,N,N,N,N,N,54587,N,N,N,54588,16233,26183,N, +54589,N,54590,26184,N,54591,26185,N,13413,54592,N,54593,54594,13389,N,54595, +26186,N,N,N,N,N,26187,54596,19293,19811,54597,54598,54599,19796,20279,N,14669, +26190,15444,26189,54600,54601,N,54602,26191,15401,54603,54604,54605,16977, +54606,26192,54607,54608,14668,54609,19543,26193,26194,N,N,26195,54610,54611, +54612,54613,26196,N,N,54614,N,54615,N,26197,N,N,N,54616,N,54617,N,54618,N,N, +15402,54619,54620,19565,54621,N,54622,54623,26199,54624,17215,54625,26198, +54626,N,N,N,54627,N,26201,N,N,N,26200,N,N,N,N,N,N,N,26202,N,N,N,16443,N,26203, +N,26204,N,N,N,19001,26205,54628,16751,26206,N,54629,N,54630,N,26207,N,N,N,N, +54631,N,20094,26210,54632,26209,26208,17456,54633,26211,16166,N,26212,N,N,N, +26213,20280,26214,N,54634,N,N,26215,26217,26216,18469,54635,18041,N,20286, +18473,N,54636,N,N,N,N,26219,N,N,15955,N,18730,N,26220,26218,54637,13390,54638, +N,N,14420,15208,N,N,18542,54639,54640,N,14378,19267,54641,26223,26221,N,14670, +N,14671,12393,N,14952,N,N,N,54642,54643,18265,N,N,N,N,N,N,N,N,12383,26228,N, +17216,N,54644,N,N,N,18264,54645,16987,54646,N,N,54647,N,54648,54649,26230, +54650,54651,26226,26229,26224,N,26227,19238,N,54652,14421,N,N,12413,26225,N,N, +N,N,N,N,N,54653,54654,26232,54817,26233,54818,54819,17977,N,54820,N,13883, +54821,54822,N,26406,18237,54823,15209,54824,N,13884,16456,20294,19502,26231, +16468,54825,N,N,N,N,N,N,N,N,N,N,54826,54827,54828,N,13651,26234,54829,N,54830, +N,54831,N,N,26236,54832,N,N,54833,N,26235,N,N,54834,N,N,26237,54835,17190,N, +18238,N,54836,N,N,N,17457,54837,N,54838,N,26403,N,N,N,N,N,N,54839,26402,54840, +N,N,54841,26238,54842,N,16213,N,18789,26405,54843,26404,14672,20307,N,54844,N, +N,N,N,N,N,N,26421,54845,54846,N,N,N,26409,26410,54847,54848,54849,N,15472,N, +54850,26408,54851,14712,26407,N,N,26411,N,N,54852,17458,18978,16675,N,N,N,N, +16988,26415,54853,26416,26412,54855,54856,54857,N,26413,N,26414,54858,N,N, +54859,14673,54854,N,N,26422,N,26418,54860,N,54861,N,18790,54862,19308,18728, +54863,N,26417,N,54864,26420,26419,N,N,N,19268,26423,N,N,N,N,54865,N,26424,N, +54866,16695,54867,26425,N,N,26427,N,26431,54868,N,26428,26426,18239,26429,N, +26430,54870,N,54871,12850,N,26437,26432,54872,54869,N,26433,54873,54874,N, +26434,N,16929,N,54875,N,54876,26436,26435,26438,54877,N,54878,54879,26439, +26440,54880,N,16195,54881,12905,N,26441,20055,N,15403,54882,54883,15661,N,N, +54884,54885,54886,15210,17239,54887,54888,N,54889,54890,26442,26443,12593, +54891,26444,54892,54893,26445,26446,54894,N,26447,N,26448,13885,23082,26449,N, +16485,26450,15435,54895,26451,N,20528,54896,54897,N,26452,19038,13404,54898, +54899,16676,15704,54900,18801,15662,N,54901,54902,N,N,N,N,N,54903,26453,14674, +26454,18508,N,26468,N,N,N,54904,26456,54905,16969,18293,14399,26455,16677, +54906,N,N,N,N,N,26457,N,N,54907,54908,54909,54910,17530,N,N,N,55073,N,N,55074, +55075,N,55076,N,N,N,N,55077,N,26459,26458,26461,N,55078,26460,N,26462,55079,N, +26464,55080,26463,N,13391,55081,26465,N,26466,26467,N,55082,14897,20041,N, +26469,16167,N,55083,N,12656,26470,26471,N,N,55084,N,55085,26472,55086,55087, +55088,N,55089,55090,N,N,55091,N,55092,55093,12402,N,26473,55094,N,N,55095, +26474,N,55096,N,55097,N,55098,18791,55099,55100,N,15431,N,26476,55101,55102,N, +55103,55104,13097,12338,55105,55106,55107,55108,26475,26478,18254,55109,16196, +55110,12886,55111,19239,55112,N,N,55113,14173,13916,55114,26477,55115,12906, +55116,55117,N,N,N,N,N,13347,55118,N,N,N,N,N,N,N,N,N,55119,12657,26482,20074, +16989,55120,N,18756,N,26494,55121,12887,26492,N,26490,26481,55122,26479,55123, +26480,55124,15459,13932,17271,55125,N,55126,18001,N,55127,N,55128,N,12625,N, +26484,26483,N,55129,55130,N,26489,26485,26488,N,55131,55132,55133,55134,19536, +26487,12888,13181,26491,55135,55136,26493,55137,55138,N,N,14164,N,N,N,N,N,N,N, +26659,26668,26669,N,N,55140,12331,55141,55142,55143,N,55144,55145,26676,N,N,N, +N,12401,N,N,26667,55146,55147,55148,26666,55149,26661,26660,55150,26658,26657, +17251,55151,17019,26663,55152,N,55153,55154,N,N,26662,N,55155,55156,55157, +26665,N,55158,N,16752,14165,N,N,55159,55160,12609,26664,55161,14675,55358, +55139,55162,55163,55164,16753,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +55165,N,N,26682,N,26683,N,12889,55166,N,N,12846,26680,55329,N,55330,55331,N, +55332,N,55333,26670,55334,26678,N,26685,26679,N,N,55335,26677,N,N,N,55336, +26486,55337,55338,26675,N,55339,55340,26671,55341,55342,55343,13392,26673, +26684,N,26674,N,N,N,55344,55345,26686,55346,26672,18300,55347,55372,N,N,N, +19817,N,N,N,26681,N,N,N,N,N,N,N,26703,55348,55349,55350,26695,N,N,N,16251,N, +55351,N,55352,13638,N,13917,N,26690,55353,55354,55355,N,12891,55356,N,15956,N, +26693,N,N,N,14938,55357,N,17745,26698,N,N,N,N,N,N,N,55359,19054,55360,26689,N, +N,N,12890,14422,18729,26699,N,26687,N,55361,26696,55362,55363,N,26706,55364, +26691,55365,N,26692,17978,N,55366,26697,N,N,55367,26694,19240,26700,12384, +55368,N,55369,N,26688,N,55370,N,N,N,55371,N,N,N,N,N,N,26702,N,26701,N,N,N,N,N, +N,18283,26708,N,26719,N,N,55373,N,13182,N,N,N,26722,N,N,26704,55374,N,N,26709, +19822,N,N,N,N,N,N,N,55375,26718,55376,55377,19797,55378,N,N,55379,20010,55380, +N,55381,55382,N,N,N,55383,17272,55384,55385,55386,13163,55387,N,N,N,55388, +18802,26724,17953,55389,55390,12337,55391,N,26717,55392,26713,16754,26707, +26715,26720,55393,18220,N,55394,55395,12330,55396,26712,55397,26721,18808,N, +55398,55399,N,N,N,55400,26716,N,26711,55401,N,N,N,N,N,15957,N,N,N,N,15663,N, +55402,55403,15404,55404,N,N,N,19544,N,N,18759,N,55405,26727,N,26736,N,N,N,N, +55406,N,55407,55408,55409,N,N,26714,N,55410,N,55411,13175,N,55412,N,N,N,15992, +26725,55413,26730,16755,55414,55415,26726,55416,26733,55417,N,17247,N,26734, +55418,55419,19798,26723,13112,55420,26729,N,55421,26732,19500,N,55422,N,N, +26735,N,N,26728,26731,N,55585,N,N,N,N,N,N,N,N,N,N,55586,N,N,55587,N,19241,N, +20257,55588,55589,55590,55591,N,26739,N,N,55592,N,N,55594,55595,26746,55596,N, +26738,15427,N,55597,55598,N,N,26705,55599,N,N,N,N,55600,N,55601,N,55602,19022, +N,19490,26745,26744,N,26740,26741,N,12598,N,55603,N,55604,26743,N,26737,55605, +55606,55607,55608,17493,55609,N,N,55610,55611,26742,12414,N,55612,N,N,55593, +55613,55614,16930,55615,N,N,N,N,N,N,19011,N,55616,26747,26913,N,18521,N,N, +55617,N,26750,15958,15433,26915,N,N,13886,55618,55619,55620,55621,55622,N, +26916,55623,18809,26749,55624,26710,N,55625,55626,55627,55628,55629,55630, +55631,26748,55632,N,N,N,20303,17954,18803,55633,N,26923,N,55634,N,N,N,N,N,N,N, +26929,N,55635,55636,55637,N,55638,26930,55639,26917,55640,N,N,18294,55641, +55642,26927,26919,55643,26921,55644,55645,N,N,55646,26931,26920,N,55647,26924, +N,N,12658,55648,18021,N,26925,26928,55649,N,55650,55651,N,55652,N,26918,55653, +16678,55654,26922,15143,16197,14128,19572,55668,19577,15730,N,N,N,N,55655,N, +55656,55657,55658,26935,26933,N,55659,55660,55661,55662,N,20302,55663,N,N,N,N, +55664,N,26932,55665,55666,N,19829,55667,26934,26936,N,N,N,N,26937,N,N,55669,N, +55670,N,26940,26938,N,55671,55672,N,N,N,17955,26939,55673,N,55674,18509,26926, +N,N,55675,N,N,N,N,N,55676,N,N,55677,15731,N,26941,26946,16756,55678,N,26945, +55841,55842,N,26914,N,55843,55844,26947,16713,N,N,26942,26944,N,55845,55846,N, +55847,55848,55849,26943,N,N,23857,23842,55850,55851,26949,55852,N,N,55853,N,N, +55854,26948,N,N,N,N,55855,N,55856,N,N,N,19830,N,25148,26950,N,N,N,N,N,55857,N, +55858,N,55859,N,55860,55861,N,26951,55862,47206,55863,N,N,N,55864,N,N,N,N,N,N, +26952,14423,N,13652,N,55865,55866,26954,20829,55867,55868,55869,55870,13685,N, +20026,55871,13939,26955,55872,55873,55874,55875,55876,N,N,26956,N,55877,N, +17262,55878,N,N,55879,N,26957,N,N,N,55880,55881,55882,N,18042,55883,12346,N,N, +N,N,N,N,N,N,N,N,N,N,55917,N,12899,26962,26963,55884,N,N,N,55885,N,26958,N, +15165,55886,N,55887,N,55888,N,55889,N,N,N,N,55890,N,26959,18242,N,55891,55892, +55893,26960,26961,26971,N,55894,N,26965,26968,55895,N,55896,55897,55898,26964, +55899,55900,55901,N,N,N,N,N,55902,55903,55904,N,55905,26966,55906,26967,15448, +N,26969,N,17217,N,14166,13122,N,N,55907,55908,N,26972,55909,N,55910,N,13119, +55911,26977,55912,N,26973,26976,55913,N,N,55914,18490,55915,N,55916,N,26974,N, +N,26975,18760,18522,26978,N,N,N,N,N,N,N,N,17021,26988,55918,26984,55919,55920, +12907,26982,N,19242,26983,55921,55922,26980,55923,26981,26986,26989,55924,N, +26987,55925,55926,55927,26985,26979,55928,55929,N,N,N,17240,55930,26996,N, +19498,N,55931,55932,N,55933,N,55934,N,26994,N,N,56097,26995,N,N,N,N,56098, +56099,N,56100,56101,N,26990,N,N,26992,N,56102,56103,26993,56104,56105,56106, +26991,56107,N,N,56108,N,56109,N,N,N,16486,N,20281,27000,56110,27001,N,N,N,N, +27169,N,16170,N,27003,56111,27006,N,N,N,56112,N,26998,26997,56113,N,27170, +56114,56115,12892,N,27004,N,27171,N,N,N,27005,56116,N,56117,56118,N,27002,N, +17459,N,26999,N,N,56119,N,N,N,18280,N,N,27175,56120,56121,56122,56123,56124, +56125,56126,N,56127,56128,19771,N,N,56129,N,N,56130,N,56131,N,56132,56133, +56134,N,N,N,N,56135,27174,56136,N,27173,56137,N,N,N,56138,N,N,N,27182,56139, +56140,56141,27176,N,56142,N,27184,N,56143,N,N,N,N,19814,27187,N,27178,56144, +56145,27179,56146,N,N,27183,N,27186,27185,56147,56148,56149,27177,N,N,56150,N, +27180,N,27197,N,N,56151,56152,N,N,56153,56154,N,56155,N,N,56156,27190,N,56157, +56158,56159,N,N,N,N,N,56160,56161,N,56162,N,27188,N,56163,27189,56164,N,N, +27194,27195,56165,13098,56166,13634,N,N,27193,56167,56168,N,56169,N,27172, +56170,N,N,56171,56172,56173,N,27192,27196,27191,56174,27198,56176,56177,56178, +27200,27199,N,56179,56175,56180,56181,56182,N,56183,56184,N,27202,27201,26970, +N,N,N,27206,56185,N,N,N,N,56186,56187,N,56188,27203,56189,N,N,56190,27204,N,N, +27205,56353,27207,56354,N,N,N,14188,56355,27209,56356,27208,56357,15664,N, +56358,56359,56360,56361,14676,24103,56362,N,N,56363,27210,15697,N,56364,56365, +13113,56366,27211,56367,12626,56368,15959,27212,56369,56370,14677,27213,12385, +56371,N,N,N,18749,56372,N,27214,N,N,N,N,16234,56373,27221,N,N,27218,N,17263,N, +56374,N,56375,N,27219,27216,13918,56376,27215,27222,N,N,N,N,N,14134,N,N,16990, +N,27228,N,N,N,N,27224,N,N,N,16949,27223,56377,27226,56378,56379,56380,N,27217, +56381,56382,N,27227,N,27229,N,N,N,56383,N,56384,18543,N,N,27225,N,27230,27232, +N,N,14419,27220,N,12353,N,N,56385,N,N,56386,56387,27231,56388,14939,20086, +27233,27234,16757,N,N,N,N,56389,56390,56391,56392,56393,20002,N,56394,56395, +56396,27235,19765,N,N,27236,27237,N,56397,19044,27238,56398,14912,N,20003,N,N, +N,N,N,56399,27243,N,N,N,N,N,N,56400,56401,56402,27244,15960,27242,56403,N, +56404,19815,27239,N,N,27241,16445,16254,56405,27240,N,27245,N,56406,18979,N,N, +27247,N,27246,56407,56408,56409,13164,N,19243,27248,N,56410,56411,N,56412, +56413,56414,N,56415,27260,27250,N,56416,N,N,N,N,27251,56417,56418,56419,N, +27252,27253,N,N,N,N,56420,56421,56422,N,N,56423,27257,N,27258,56424,56425, +27256,N,N,56426,N,56427,27254,56428,27249,27255,56429,56430,N,N,56431,N,N, +27259,28727,N,56432,N,N,56433,N,N,N,12840,56434,N,N,56435,56436,56437,N,27262, +13919,27261,56438,56439,56440,27426,N,27425,N,N,N,27428,56441,N,27427,56442, +27429,56443,N,15665,56444,27430,56445,N,27431,N,N,56446,56609,56610,56611, +27432,16446,N,19799,N,27433,N,N,18980,18246,27434,56612,27435,14379,N,56613,N, +13612,56614,N,N,27436,56615,56616,15211,18241,27437,N,13136,56617,56618,N,N, +56619,56620,27438,N,N,N,56621,27440,19831,N,27439,16198,N,27441,N,N,27442, +56622,N,27443,13393,56623,56624,56625,56626,N,N,27444,N,56627,27445,N,27446, +27447,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,13137,N,56628,56629,56630,56631,56632, +N,27448,N,27449,27450,N,N,N,N,N,12914,N,56633,16168,27451,N,56634,N,56635,N, +56636,N,N,N,56637,N,56638,27452,N,56639,N,27453,56640,N,N,N,56641,N,56642, +14400,N,17531,27454,56643,56644,N,56645,14167,N,16214,N,27457,N,17956,56646, +27456,56647,56648,14129,56649,56650,27455,17015,13613,N,N,27458,N,27459,56651, +15961,56652,N,56653,14189,56654,27460,56655,N,N,N,19244,56656,56657,16479,N, +56658,N,13686,N,19573,16714,56659,27461,56660,N,N,16199,17264,15962,56661, +56662,N,56663,27462,N,56664,N,56665,27465,56666,27466,56667,N,N,N,56668,56669, +N,14910,16962,27464,56670,15963,18750,56671,56672,56673,N,N,27463,56674,56675, +15212,N,12627,56676,27470,14168,N,56677,15214,56678,N,15213,N,20301,27469, +27468,16679,N,13645,20291,13114,15964,N,56679,56680,56681,N,56682,56683,56684, +27467,N,56685,56686,56687,N,27472,56688,27473,27471,56689,14424,N,19776,N, +56690,15215,18215,N,56691,56692,27476,56693,16448,N,17218,56694,56695,19766, +56696,27479,N,N,N,14444,56697,16447,27475,N,27480,14445,27477,27478,56698, +27474,56699,N,N,16482,17993,56700,56701,17199,N,12893,56702,N,N,56865,56866,N, +18544,N,56867,13635,N,56868,17460,N,N,27483,56869,27481,N,56870,17228,56871, +56872,56873,16449,13394,27482,N,16219,N,56874,20042,56875,56876,56877,20288, +56878,N,N,27484,27495,17461,56879,27494,56880,27491,27499,27492,N,27488,N, +17532,27487,N,N,N,27485,56881,19745,15216,N,56882,27489,N,27486,56883,56884, +56885,27493,15732,N,14401,N,56886,N,17018,56887,19269,12634,12386,N,17957, +56888,56889,27497,N,N,56895,56890,27496,N,18022,N,27501,56891,N,N,27490,N, +27500,27502,N,14380,27498,14678,56892,15445,56893,56894,27503,19800,N,N,N,N, +27506,N,27509,N,N,27507,18741,56896,N,N,56897,N,N,27504,N,N,N,56898,N,13920,N, +N,56899,N,27508,N,N,27510,56900,56901,56902,56903,56904,N,56905,27514,N,N, +27511,56910,27513,27512,N,N,56906,56907,56908,N,27515,N,15409,56909,27517, +27516,18792,N,56911,27681,N,N,N,56912,N,N,14169,N,N,N,N,27518,27682,56913,N, +27683,13636,26177,15993,N,27684,N,56914,14446,56915,56916,N,N,56917,27685, +56918,N,27686,56919,N,15166,56920,56921,N,N,N,N,23118,56922,27687,56923,27688, +56924,15666,N,27689,27690,56925,56926,27691,N,N,27692,27693,N,56927,N,56928, +56929,17195,56930,56931,27694,N,N,56932,56933,27696,N,27695,N,N,N,56934,17958, +56935,27697,56936,19245,56937,27698,N,27699,56938,27700,56939,N,56940,56941, +27701,N,56942,56943,56946,18010,56944,N,56945,N,N,N,15965,27702,56947,56948,N, +56949,N,56950,56951,14699,20526,27703,56952,N,N,N,N,N,56953,N,56954,56955,N, +27704,18751,27705,56956,27713,N,56957,N,N,N,27706,N,N,27708,56958,57121,N, +27707,27709,57122,19270,27710,27711,N,57123,N,57124,57125,27712,N,N,N,27714, +57126,N,57127,57128,13101,17511,N,18793,14946,14679,N,57129,N,N,18767,12895, +18510,27717,13395,16469,27716,27721,17273,19555,N,27719,27720,13614,N,27722, +18275,16991,57130,57131,18545,17725,27718,N,19271,12908,27724,20264,17474, +20293,57132,57133,15217,27723,57134,16945,57135,N,27740,16680,57136,N,18040,N, +18768,N,57138,57137,N,N,57139,27727,15167,15218,57140,15966,N,18277,57141, +14381,27726,27725,N,18794,N,57142,N,15425,N,57143,17746,N,57144,57145,N,57146, +N,N,57147,N,57148,57149,N,27729,27730,14680,27728,57150,57151,57152,N,57153, +27731,27732,N,27734,16931,57154,27733,13414,N,27736,N,27735,27737,N,57155, +27739,27741,N,27742,57156,N,N,N,57157,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,16470,57158,15439,27743,N,57159,N,13138,57160,27744, +57161,N,16758,27745,N,27746,18795,N,N,13615,N,N,N,N,N,N,N,57162,N,27747,57163, +N,57164,17462,N,N,57165,N,12635,N,N,57166,N,N,57167,57168,N,N,N,57169,N,N,N, +27748,N,N,N,N,57170,57171,57172,N,N,15473,N,N,57173,N,16246,N,N,57174,57175,N, +N,57176,N,N,57177,16941,N,57178,N,57179,N,57180,27751,57181,57199,N,27750,N, +57182,N,27749,N,N,57183,57184,57185,57186,N,57187,27757,27755,N,57188,27752,N, +57189,N,N,57190,57191,27754,57192,N,57193,27753,27756,N,13687,N,27760,N,16471, +N,27761,57194,57195,N,57196,14425,N,27758,27759,57197,N,N,20265,57198,57200, +57201,17463,57202,16681,N,N,N,N,N,N,27762,57203,N,27765,57204,N,N,57205,57206, +57207,N,27763,27764,19801,57208,N,N,N,17959,27768,57209,N,N,57210,N,57211,N,N, +N,N,N,N,27766,27767,27769,57212,57213,57214,57377,N,N,57378,57379,N,N,27945,N, +N,N,N,N,27772,57380,N,57381,27773,27771,57382,57383,57384,57385,N,N,N,57386,N, +N,57387,57388,27770,N,17533,N,N,27937,27941,27938,27774,57389,27939,57390, +57391,57392,27940,N,N,N,57393,27947,N,N,N,27942,N,57394,57395,57396,57397, +16472,27944,57398,57399,27946,27943,N,N,N,N,57400,N,N,57401,57402,N,57403, +57404,57405,27949,N,15667,N,27948,N,N,57406,57407,57408,27950,N,N,N,N,27951, +57409,57410,27954,27953,N,27952,N,57411,27956,27955,N,19574,N,N,57412,27958, +57413,27957,27959,57414,N,N,N,27960,57415,57416,N,57417,57418,N,N,27962,57419, +N,N,N,N,57420,N,57421,27961,16200,27963,57422,57423,13933,27964,27966,N,57424, +N,57425,N,N,N,N,57426,57427,N,N,27967,N,57428,57429,N,57430,57431,27968,27965, +57432,27969,N,15446,27970,13616,14131,N,57433,N,57434,14382,N,57435,N,N,N,N,N, +N,27971,57436,N,N,18032,N,N,17726,27972,N,N,N,N,57437,N,N,27975,N,57444,57438, +N,57439,57440,N,N,N,N,N,57441,15412,57442,57443,27974,27973,14170,27976,57445, +N,57446,13139,N,27978,N,57447,57448,14940,27977,N,27986,N,N,57449,57450,N, +27980,27982,19045,27979,57451,57452,57453,27981,N,27985,27983,13617,57454, +27984,57455,57456,N,57457,N,57458,27987,57459,57460,18266,20056,N,57461,57462, +57463,15668,N,N,N,27988,57464,57465,57466,57467,19746,27990,57468,27989,N,N, +27993,19777,57469,57470,27992,57633,13165,27991,27996,57634,N,27995,N,N,27994, +17714,27997,57635,N,57636,57637,57638,57639,57640,N,27998,57641,N,N,N,27999, +57642,57643,14700,N,14117,28000,28001,28002,57644,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +16201,28003,57645,15405,28004,57646,57647,N,28005,57648,57649,57650,21025, +20862,N,N,N,N,28006,25968,28007,17188,16171,18240,N,N,57651,57652,28008,57653, +N,19029,17492,14718,N,57654,17193,57655,57656,12586,N,19320,16215,57657,N,N,N, +57658,57659,N,57660,14174,N,57661,13921,57662,57663,19030,57664,N,N,N,N,28009, +N,N,N,N,N,57665,N,28011,57666,57667,28010,12896,N,57668,18038,28012,18295,N, +17715,57669,28013,15698,57670,N,N,28015,57671,57672,19522,28030,28017,28018, +57673,N,17481,57674,16992,16759,57675,17960,57676,28016,13653,N,57677,N,N, +28025,57678,28022,28197,17961,17248,28019,N,17534,17747,28020,28024,16224, +57679,18279,17484,57680,N,16450,28023,16942,16932,28021,12329,20258,N,N,N, +28026,57681,57682,57684,N,57685,57686,16993,57683,N,15669,16202,57687,57688, +28028,28027,57689,12399,28029,N,N,18735,N,28199,57690,N,18011,16235,57691, +57692,17241,N,13944,N,28198,19767,12607,57693,19031,12897,28193,28194,28195, +28196,17979,17187,12387,28200,N,28201,29731,N,57694,16957,57695,28202,N,12659, +16716,57696,14383,N,19802,57697,57698,28203,17708,N,N,57699,16760,15447,28204, +57700,N,28207,N,57701,15717,28205,16683,16682,57702,12388,N,20043,28209,N, +18546,28211,28210,28208,25444,13396,57703,N,28014,57704,28213,28212,57705, +57706,N,57707,28214,57708,19768,N,N,N,57709,N,57710,57711,57712,N,57713,N,N,N, +N,57714,57715,57716,18017,N,57717,19246,N,28215,N,15449,N,N,N,N,28216,57718, +28217,57719,57720,57721,28218,57722,N,17697,N,N,N,N,57723,57725,N,N,12394,N, +57726,57889,57890,N,57891,57892,N,14681,N,57724,N,20282,N,N,N,57901,N,N,57893, +N,57894,57895,57896,N,28222,57897,57898,N,57899,N,14132,28219,N,28220,57900,N, +N,18804,N,N,57903,N,13140,N,57904,57905,N,N,N,57906,19769,57902,13887,N,N,N,N, +N,17748,57907,57908,57909,N,28223,N,57910,57911,57912,N,57913,N,N,N,N,57914,N, +N,57915,N,28224,N,57916,N,57917,57918,57919,28225,57920,N,57921,N,57922,N, +57923,N,57925,57926,N,57924,N,57927,N,57928,N,N,N,17698,57929,57930,28227, +57931,28226,N,57932,N,57933,57934,N,57935,57936,N,57937,57938,N,N,N,N,N,57939, +N,N,N,57940,57941,18003,28228,15670,15456,18267,17265,57942,N,N,15474,57943, +16236,N,28229,57944,28230,57945,57946,57947,N,N,N,N,N,57948,16221,28231,57949, +28232,N,57950,N,28233,19823,N,15671,57951,N,N,N,N,28235,28234,57952,14682,N, +14707,15168,57953,57954,57955,N,N,N,N,N,57956,28238,57957,N,57958,57959,15718, +N,28237,57960,28236,N,17001,57961,N,14447,57962,16451,57963,57964,57965,N, +18480,57966,N,N,N,15673,N,57967,N,N,57968,28239,N,15967,N,57969,N,57970,N, +28242,28240,57971,57972,57973,28241,57974,57975,57976,57977,28244,28243,57978, +N,15994,N,28245,57979,57980,57981,N,57982,28246,28247,58145,58146,N,58147, +18512,14931,15457,28248,N,28249,20004,15685,19566,20044,28250,13922,N,58148, +58149,N,28251,58150,17699,58151,58152,28254,13176,16203,58153,28252,N,28253,N, +17504,58154,58155,19285,13948,N,58156,58157,N,58158,58159,58160,58161,58162, +58163,N,N,N,28256,28257,58164,N,58165,N,58166,28255,58167,N,28259,58168,58169, +N,N,58170,58171,58172,58173,N,58174,58175,N,58176,18015,13123,N,58177,28263, +58178,58179,28260,28262,58180,N,58181,N,N,N,58182,58183,28258,N,N,N,N,58184, +58185,58186,58187,N,58188,28495,N,N,28261,N,58189,58190,58191,N,N,58192,20075, +58193,58194,14426,58195,58196,58197,N,58198,N,58199,28271,58200,N,58201,58202, +17716,28266,58203,58204,28269,28267,58205,28272,N,58206,58207,58208,28273, +58209,N,N,N,N,N,28265,58210,58211,28278,12660,58212,58213,28264,N,58214,58215, +18477,N,28268,58216,15968,58217,58218,58219,N,N,N,N,58220,58221,58222,14683,N, +N,N,58223,58224,58225,58226,58227,N,58228,58229,58230,19272,58231,13924,N,N, +15686,N,17980,N,N,58232,58233,58234,N,N,58235,58236,N,N,16685,58237,28276,N, +28270,28275,58238,19523,58401,17464,28277,28274,N,N,58402,58403,N,N,N,58404, +58405,N,58406,58407,N,N,58408,N,16684,N,58409,N,N,58410,N,N,N,58411,28281, +58412,28280,58413,58414,58415,58416,N,58417,58418,58419,58420,58421,N,58422, +58423,58424,58425,N,N,58426,58427,58428,58429,28279,58430,N,19247,58431,N, +58432,N,58433,58434,58435,N,N,58436,58437,N,58438,58439,58440,N,58441,15739, +58442,N,58443,58444,28282,19039,N,58445,12628,58446,N,58447,N,18758,17266,N,N, +N,N,13688,58448,28284,58449,14685,N,N,58450,58451,N,58452,N,N,N,15148,N,58453, +N,N,N,N,58454,N,28283,16237,58455,N,N,58456,58457,N,N,16238,28449,28451,N, +58458,58459,58460,58461,15995,58462,28450,28452,58463,58464,13907,58465,18757, +58466,58467,15458,20259,N,28286,14968,N,N,20287,58468,58469,28454,58470,58471, +N,N,28453,28455,N,N,N,N,N,N,N,N,28285,N,N,58472,58473,58474,N,18025,N,17749,N, +N,58475,58476,58477,N,17495,58478,28460,58479,58480,N,58481,17219,28456,N, +58482,N,28457,N,N,N,58483,58484,N,58485,N,58486,58487,N,14125,58488,28459, +58489,58490,58491,N,58492,58493,14384,58494,N,N,N,58657,N,28458,58658,15969, +58659,58660,58661,58662,N,N,N,N,N,58663,N,58664,58665,13177,58666,N,58667,N,N, +58668,N,28464,58669,14911,16761,58670,N,17482,58671,N,N,58672,N,N,58673,N, +58674,58675,N,58676,13115,58677,58683,N,58678,28462,28463,17475,N,28461,N,N,N, +58679,58680,58681,N,N,28465,58682,N,N,N,N,N,N,58684,N,28471,58685,58686,58687, +58688,28474,58689,58690,58691,58692,58693,N,N,28473,17709,N,58694,N,N,28466, +28467,28470,58695,N,N,58696,28472,58697,58698,N,13888,58699,N,28475,28469, +58700,58701,28468,N,N,N,N,N,N,N,N,N,N,N,N,N,N,58703,58704,58702,58705,58706,N, +58707,58708,58709,28479,58710,N,N,28480,58711,58712,N,N,N,58713,58714,58715, +28481,N,N,28478,28477,58716,58717,58718,15970,17962,28476,N,N,N,N,58719,N, +28485,N,N,N,N,N,N,N,N,N,28483,N,N,58720,58721,N,58722,58723,58724,58725,28484, +28482,N,17016,N,28486,58726,N,58728,N,58727,N,28487,N,58729,28489,58730,N,N, +58731,N,58732,N,58733,N,N,N,N,13397,28488,19578,N,58734,N,N,N,58735,28500, +28490,58736,N,28493,58737,28491,58738,28492,58739,N,N,N,N,58740,N,28494,58741, +N,58742,58743,58744,28496,58745,58746,N,N,28497,N,28498,N,N,N,N,28501,28499, +28502,28504,N,28503,N,58748,58747,17465,58749,58750,N,N,N,N,58913,N,19559,N, +28505,16686,58914,N,N,28506,58915,19012,28507,13099,58916,58917,58918,12604,N, +13399,N,13398,28508,N,28509,N,28510,28511,N,N,N,58919,58920,58921,28512,58922, +13400,13141,14686,18486,58923,28514,28513,58924,N,58925,58926,28515,N,N,N,N, +12636,N,58927,N,58928,N,N,28518,58929,28517,28516,58930,28519,58931,N,N,N, +28522,N,N,58932,12359,58933,58934,28520,58935,28524,28523,N,N,58936,58937, +58938,58939,28526,28525,28527,N,17966,58940,58941,N,28528,58942,58943,58944, +58945,28529,28531,N,58946,28530,58947,18796,58948,58949,N,N,28532,58950,N, +58951,58952,58953,N,28533,N,14949,N,58954,N,28534,28535,N,58955,19273,58956,N, +N,N,58957,58958,58959,58960,16715,58961,58962,N,12324,16971,58963,28536,N, +18797,N,N,N,N,N,N,28539,28537,14687,N,28538,14402,N,58964,N,58965,N,58966, +58967,58968,N,N,19013,28541,28705,28542,28706,N,58969,12577,16216,15740,13401, +28707,N,N,N,18278,N,28709,N,58970,N,12578,N,28708,17476,58971,20045,17963, +28540,20006,N,14385,58972,58973,19803,58974,58975,N,58976,58977,58978,58979, +13945,20020,N,14120,58980,16994,26401,N,28710,13100,16239,N,58981,N,N,13142, +28712,58982,28713,28711,14180,58983,14941,15971,58984,N,58985,12579,N,N,20057, +58986,58987,58988,28715,28206,58989,28714,N,N,N,58990,58991,28718,28716,28717, +58992,28719,N,28720,20076,28721,28722,58993,16457,18491,N,N,N,16253,13415,N,N, +19770,12909,15672,14427,N,28725,58994,28724,15219,28726,28723,N,N,15144,58995, +N,N,28730,27181,N,58997,21078,58998,16247,28728,58999,59000,59001,N,N,20005, +18033,N,N,N,N,12587,59002,16483,15414,N,N,N,59003,18999,59004,12608,N,N,N, +20077,19819,N,28731,59005,17733,15483,N,59006,59169,28732,59170,28733,16204, +28734,59171,20078,N,N,28729,28736,28738,N,28737,N,28735,N,N,28739,N,N,28740, +59172,59173,16762,59174,12898,N,N,59175,59176,59177,28741,N,N,19512,59178,N, +28742,N,N,N,N,N,28743,59179,20266,59180,N,N,N,N,23345,28744,N,N,N,28745,28746, +N,N,59181,28750,59182,28747,N,28748,N,28749,28751,59183,N,N,N,59184,59185,N,N, +16452,N,N,59186,19575,59187,59188,16453,59189,59190,28752,N,18547,N,28753, +29523,19532,59191,28754,N,28755,59192,28756,13143,59193,28758,N,16217,59194,N, +N,28759,N,59195,14116,N,59196,59197,59198,28760,28764,59199,28762,59200,N, +59201,59202,28763,N,N,13171,28761,28765,N,N,59203,N,28766,N,12360,N,28767, +28768,N,N,N,N,59204,59205,59206,15972,59207,59208,N,28769,N,59209,59210,13639, +N,59211,28772,N,N,28771,N,28770,N,N,27505,59212,19036,59213,N,N,59214,59215, +28773,28774,59216,59217,N,59218,59219,59220,N,59221,N,59222,59223,N,59224,N, +28775,59225,59226,28776,59227,28777,59228,59229,28778,59230,59231,59232,N, +59233,59234,N,13402,59235,N,N,59236,59237,59238,N,59242,28779,59239,59240,N, +59241,59243,N,N,59244,N,N,N,N,N,N,N,N,28780,18211,59245,N,59246,28782,12859, +59247,28785,28784,59248,59249,N,59250,12580,N,N,N,13889,19015,17466,14882,N, +14688,15719,59251,16220,N,59252,N,28787,59254,59255,28786,19778,13416,18514, +18012,59256,N,59257,16252,20046,59253,14171,N,59258,N,59259,N,59260,28790,N, +59261,28789,59432,59262,N,N,N,N,59425,19275,17964,59426,59427,59428,N,59429, +59430,12624,59431,N,28791,28788,N,N,18769,19818,28792,59433,N,N,N,N,N,59434,N, +28793,59435,N,N,59436,28795,17002,13147,13148,28794,N,59437,59438,59439,13417, +14386,59440,59441,13418,59442,59443,17727,N,N,20064,N,N,N,59444,59445,N,59446, +59447,14428,N,N,59448,28796,59449,N,N,28797,28798,28961,N,28963,28962,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,18807,N,28964,59450,N,59451,59452,28965,59453,28966,N,N,59454, +N,28967,59455,59456,N,59457,59458,N,N,N,59459,N,N,59460,28969,28968,59461, +28970,N,59462,N,N,N,59463,N,N,N,N,N,N,N,N,N,N,N,N,N,N,18548,26188,N,N,16169,N, +59464,13618,59465,N,59466,59467,59468,N,28971,59469,28972,N,21036,23867,18515, +N,N,12411,59470,12347,N,59471,N,N,N,N,N,15220,19248,15998,59472,28973,N,19551, +N,59473,59474,28974,19804,N,12610,N,N,N,15169,59475,28975,12910,28976,59476, +59477,59478,28977,N,59479,59480,59481,28979,28980,59482,28982,28978,59483,N, +28981,N,59484,59485,13403,N,N,59486,28983,N,28984,N,N,59487,59488,59489,59490, +59491,N,N,N,59492,59493,59494,59495,28985,28986,N,59496,59497,28987,N,N,28989, +59498,59499,59500,28988,N,28991,28994,59501,59502,N,28990,28992,28993,N,59503, +28995,N,13890,59504,59505,N,59506,59507,N,59508,59509,59510,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,15475,28996,28997,14689,N,59511,N,59512,N,59513,N,N,N,N,N,28998, +59514,N,13118,N,N,N,18255,28999,29000,N,59515,59516,59517,17242,18027,59518,N, +N,N,59681,59682,N,29001,59683,N,59684,N,18301,N,59685,16972,12632,13934,N, +13935,59686,N,N,N,N,N,N,17267,29006,13936,59687,59688,12911,N,N,29005,59689, +59690,29003,59691,29004,59692,29002,N,N,29016,N,N,N,N,59693,N,N,59694,59695, +59696,29007,29008,N,59697,29009,29010,N,59698,59699,N,N,29012,59700,N,29011,N, +59701,59702,15705,29013,59703,59704,59705,29015,N,N,N,N,N,59706,59707,N,13619, +29014,59708,59709,16763,14387,N,N,59710,N,N,29017,N,N,N,N,59711,N,59712,N, +59713,59714,59715,N,N,59716,16973,N,N,29018,N,59717,59718,N,17965,N,N,59719,N, +59720,59721,29019,59722,N,N,N,N,N,29024,N,29022,59724,29021,29023,59725,29020, +N,59723,N,N,59726,59727,59728,29026,59729,N,N,59730,N,N,59731,29025,59732, +29028,N,N,13891,29027,N,59733,N,29029,N,N,29030,N,29032,29031,N,N,N,29033, +29035,29034,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,14716,N,59734,N,59735, +29036,59736,59737,29037,N,59738,N,59739,59740,59741,N,13116,59742,N,59743, +29038,N,59744,59745,29039,59746,N,59747,16241,N,59748,N,59749,N,N,N,N,N,59750, +29040,59751,29041,59752,29042,29043,59753,59754,59755,14690,N,N,59756,59757,N, +29044,29045,59758,N,29046,29047,59759,59760,29048,59761,N,59762,18481,29050, +59763,18726,29051,29049,N,29053,59764,59765,29052,59766,N,29054,N,59767,59768, +29217,N,59769,N,59770,59771,59772,59773,59774,59937,59938,29218,N,59939,59940, +N,59941,59942,59943,59944,N,59945,N,59946,N,N,N,59947,N,29219,59948,29220, +59949,59950,N,N,29221,59951,N,29222,29223,N,29224,59952,29225,29226,29227, +29228,59953,N,59954,29229,29230,N,23861,29231,59955,59956,59957,N,59958,N, +59959,59960,25720,13620,59961,N,N,N,13089,14898,29233,29232,19493,N,N,59962,N, +N,59963,59964,29235,29236,29234,N,29237,N,N,19298,59965,59966,59967,29238,N, +13691,59968,N,N,59969,N,N,59970,N,59971,N,59972,59973,N,59974,N,59975,59976, +59977,59978,59979,20261,N,N,N,59980,29239,59981,N,59982,59983,59984,N,N,N,N,N, +59985,59986,N,N,29241,59987,59988,59989,59990,N,59991,59992,59993,N,59994, +12350,59995,59996,29242,18987,29240,59997,N,29243,29244,N,N,59998,N,N,59999, +60000,29245,29246,N,N,N,N,N,60001,60002,29247,60003,19310,15149,60004,14970, +16687,N,60005,60006,60007,N,29248,N,N,60008,60009,29251,N,60010,60011,N,60012, +60013,29249,60014,N,N,N,N,29252,60015,60016,14449,29250,N,N,N,60017,29253, +60018,29254,29255,N,29259,N,15146,60019,60020,N,N,16996,N,60021,N,60022,N, +29260,29257,29256,29258,60023,N,60024,14175,N,60025,60026,N,N,N,60027,29264, +29263,29262,60028,N,12339,N,60029,60030,60193,60194,N,N,60195,N,60196,60197,N, +60198,N,29274,N,29270,N,29271,29267,29273,60199,29269,13154,N,60200,20300, +60201,29272,29268,29266,29265,60202,N,60203,60204,60205,29276,60206,N,60207,N, +N,29279,60208,60209,29278,29277,60210,60211,60212,60213,60214,N,N,18761,29275, +12403,29280,60215,29282,N,N,60216,60217,60218,N,13167,29261,12599,N,60219, +29284,N,N,60220,N,60221,60222,60223,29283,29281,17197,60224,60225,N,N,N,60226, +60227,60228,N,19312,60229,60230,N,60231,20058,60232,N,29285,60233,60240,60234, +60235,60236,29286,N,N,60237,N,N,N,29287,60242,60238,60239,60241,N,N,60243,N, +60244,N,60245,N,N,60246,29288,60247,29289,N,N,60248,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,17467,60249,29290,N,18487,N,29295,29291,N,N,N, +29292,N,60250,19249,19524,N,18000,60251,N,60252,60254,29296,N,N,29297,17982, +29294,29293,N,60253,N,N,12842,N,N,60255,29305,N,N,29304,N,60256,60257,N,N, +12661,60258,60259,60260,29302,N,N,N,29301,N,N,29299,N,13179,N,29298,15410, +12841,N,N,60261,60262,N,60263,60264,60265,N,N,N,N,N,60266,14691,60267,60269, +29308,29307,N,29306,60270,60271,29303,60268,29309,60272,29310,N,60273,N,N,N,N, +N,29477,29476,N,60274,60275,N,N,N,N,29478,N,N,12589,29473,29474,60276,14708, +19513,60278,60277,29475,60279,N,N,N,60280,60281,60282,19250,N,N,29483,60283,N, +29479,N,N,N,60284,60285,N,N,29484,60286,60449,N,60450,N,N,N,N,60451,60452,N, +60453,29481,N,29480,60454,N,N,60455,60456,14172,N,N,60457,60458,N,60459,60460, +60461,60462,N,29485,N,N,N,N,N,N,60463,N,N,29486,N,N,N,N,29487,60464,29482, +60465,N,60466,29300,N,60467,29488,N,17505,60468,N,N,29492,60469,29493,29491, +60470,N,N,60471,N,29490,29496,60472,29489,N,29494,60473,N,60474,60475,N,N,N,N, +29495,N,N,N,29498,60476,60477,60478,60479,N,29497,60480,N,N,N,60481,60482, +60483,N,N,N,N,60484,29500,60485,N,60486,N,60487,N,29501,60488,29502,60489,N, +20297,60490,60491,N,N,N,29499,17003,14957,N,N,29503,60492,60494,N,N,N,N,60495, +N,N,60493,N,N,N,60496,N,60497,60498,60499,N,N,60500,60501,N,N,60502,29504, +29505,60503,60504,29506,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29507,N,N,14388,29508,60505,60506, +60507,29509,N,15407,60508,29510,60509,60510,60511,60512,N,60513,29511,N,N, +29512,29513,N,60514,60515,N,29516,29514,20284,N,29515,60516,20079,60517,N,N, +60518,N,29517,60519,20059,N,N,N,N,60520,29518,18302,N,60521,29519,29521,N, +60522,29522,60523,60524,60525,N,N,60526,60527,60528,N,N,29520,14701,19533, +19299,22135,N,23904,19323,N,N,N,N,12843,N,60529,N,60530,N,N,60531,29524,13648, +29525,29526,29527,N,14709,N,29528,60532,N,N,24660,19547,N,16995,29529,29531, +29530,60533,29532,N,N,N,60534,29533,N,60535,29534,N,N,N,60536,60537,60538, +29535,60539,60540,60541,N,29536,60542,29537,29538,60705,29539,N,29540,29541, +29542,N,60706,60707,60708,N,N,N,29543,29544,60709,N,N,N,N,17700,60710,60711, +60712,60713,14429,60714,29546,60715,60716,N,60717,60718,60719,N,N,N,60720, +16717,29547,60721,N,N,N,60722,N,N,N,60723,60724,29548,N,N,60725,N,60726,60727, +N,60728,N,N,60729,N,60730,60731,18721,60732,60733,29549,60734,N,60735,N,60736, +60737,60738,60739,60740,N,N,29550,25399,N,N,27738,28781,N,N,29551,60741,29552, +60742,60743,60744,60745,N,60746,N,N,60747,60748,29554,29555,29556,20080,29553, +N,N,29557,29558,60749,60750,29560,N,29559,60751,60752,60753,60754,60755,29562, +60756,N,60757,29563,29561,N,N,60758,N,N,60759,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +20022,N,60760,60761,60762,60763,N,60764,29564,60765,60766,N,N,N,N,29565,25428, +60767,N,29566,60768,60769,60770,N,60771,8490,N,8564,8560,8563,8565,N,8522, +8523,8566,8540,8484,N,8485,8511,9008,9009,9010,9011,9012,9013,9014,9015,9016, +9017,8487,8488,8547,8545,8548,8489,8567,9025,9026,9027,9028,9029,9030,9031, +9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,9043,9044,9045,9046, +9047,9048,9049,9050,8526,N,8527,8496,8498,8494,9057,9058,9059,9060,9061,9062, +9063,9064,9065,9066,9067,9068,9069,9070,9071,9072,9073,9074,9075,9076,9077, +9078,9079,9080,9081,9082,8528,8515,8529,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8497, +N,8559, +}; + +static const struct unim_index jisxcommon_encmap[256] = { +{__jisxcommon_encmap+0,92,255},{__jisxcommon_encmap+164,0,245},{ +__jisxcommon_encmap+410,199,221},{__jisxcommon_encmap+433,132,206},{ +__jisxcommon_encmap+508,1,95},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{__jisxcommon_encmap+603,16,59},{__jisxcommon_encmap+647,3,212},{ +__jisxcommon_encmap+857,0,165},{__jisxcommon_encmap+1023,18,18},{0,0,0},{ +__jisxcommon_encmap+1024,0,239},{__jisxcommon_encmap+1264,5,111},{0,0,0},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisxcommon_encmap+1371,0,254},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisxcommon_encmap+1626,0,255},{ +__jisxcommon_encmap+1882,0,255},{__jisxcommon_encmap+2138,0,254},{ +__jisxcommon_encmap+2393,0,254},{__jisxcommon_encmap+2648,0,255},{ +__jisxcommon_encmap+2904,0,250},{__jisxcommon_encmap+3155,1,255},{ +__jisxcommon_encmap+3410,0,255},{__jisxcommon_encmap+3666,5,255},{ +__jisxcommon_encmap+3917,0,255},{__jisxcommon_encmap+4173,0,253},{ +__jisxcommon_encmap+4427,2,255},{__jisxcommon_encmap+4681,0,253},{ +__jisxcommon_encmap+4935,0,255},{__jisxcommon_encmap+5191,1,253},{ +__jisxcommon_encmap+5444,1,254},{__jisxcommon_encmap+5698,0,255},{ +__jisxcommon_encmap+5954,1,255},{__jisxcommon_encmap+6209,7,253},{ +__jisxcommon_encmap+6456,0,255},{__jisxcommon_encmap+6712,0,255},{ +__jisxcommon_encmap+6968,1,250},{__jisxcommon_encmap+7218,6,255},{ +__jisxcommon_encmap+7468,0,255},{__jisxcommon_encmap+7724,0,255},{ +__jisxcommon_encmap+7980,0,255},{__jisxcommon_encmap+8236,2,253},{ +__jisxcommon_encmap+8488,0,255},{__jisxcommon_encmap+8744,0,253},{ +__jisxcommon_encmap+8998,2,255},{__jisxcommon_encmap+9252,2,244},{ +__jisxcommon_encmap+9495,4,252},{__jisxcommon_encmap+9744,0,255},{ +__jisxcommon_encmap+10000,1,254},{__jisxcommon_encmap+10254,0,253},{ +__jisxcommon_encmap+10508,3,255},{__jisxcommon_encmap+10761,0,254},{ +__jisxcommon_encmap+11016,2,255},{__jisxcommon_encmap+11270,0,255},{ +__jisxcommon_encmap+11526,3,255},{__jisxcommon_encmap+11779,0,254},{ +__jisxcommon_encmap+12034,0,252},{__jisxcommon_encmap+12287,2,255},{ +__jisxcommon_encmap+12541,0,252},{__jisxcommon_encmap+12794,0,255},{ +__jisxcommon_encmap+13050,2,254},{__jisxcommon_encmap+13303,0,254},{ +__jisxcommon_encmap+13558,0,251},{__jisxcommon_encmap+13810,0,158},{ +__jisxcommon_encmap+13969,54,255},{__jisxcommon_encmap+14171,0,254},{ +__jisxcommon_encmap+14426,2,255},{__jisxcommon_encmap+14680,0,254},{ +__jisxcommon_encmap+14935,0,253},{__jisxcommon_encmap+15189,1,255},{ +__jisxcommon_encmap+15444,0,255},{__jisxcommon_encmap+15700,0,254},{ +__jisxcommon_encmap+15955,0,255},{__jisxcommon_encmap+16211,1,254},{ +__jisxcommon_encmap+16465,1,255},{__jisxcommon_encmap+16720,0,255},{ +__jisxcommon_encmap+16976,0,159},{__jisxcommon_encmap+17136,55,255},{ +__jisxcommon_encmap+17337,1,255},{__jisxcommon_encmap+17592,1,254},{ +__jisxcommon_encmap+17846,0,254},{__jisxcommon_encmap+18101,0,255},{ +__jisxcommon_encmap+18357,0,255},{__jisxcommon_encmap+18613,0,255},{ +__jisxcommon_encmap+18869,0,253},{__jisxcommon_encmap+19123,1,132},{ +__jisxcommon_encmap+19255,119,230},{__jisxcommon_encmap+19367,28,251},{ +__jisxcommon_encmap+19591,0,255},{__jisxcommon_encmap+19847,1,254},{ +__jisxcommon_encmap+20101,2,255},{__jisxcommon_encmap+20355,1,255},{ +__jisxcommon_encmap+20610,0,255},{__jisxcommon_encmap+20866,0,249},{ +__jisxcommon_encmap+21116,2,254},{__jisxcommon_encmap+21369,2,255},{ +__jisxcommon_encmap+21623,2,165},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{__jisxcommon_encmap+21787,1,229}, +}; + +static const ucs2_t __cp932ext_decmap[969] = { +65340,65374,8741,65372,8230,8229,8216,8217,8220,8221,65288,65289,12308,12309, +65339,65341,65371,65373,12296,12297,12298,12299,12300,12301,12302,12303,12304, +12305,65291,65293,177,215,U,247,65309,8800,65308,65310,8806,8807,8734,8756, +9794,9792,176,8242,8243,8451,65509,65284,65504,65505,65285,65283,65286,65290, +65312,167,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660, +8251,12306,8594,8592,8593,8595,12307,U,U,U,U,U,U,U,U,U,U,U,8712,8715,8838, +8839,8834,8835,8746,8745,U,U,U,U,U,U,U,U,8743,8744,65506,9312,9313,9314,9315, +9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330, +9331,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,U,13129,13076,13090, +13133,13080,13095,13059,13110,13137,13143,13069,13094,13091,13099,13130,13115, +13212,13213,13214,13198,13199,13252,13217,U,U,U,U,U,U,U,U,13179,U,12317,12319, +8470,13261,8481,12964,12965,12966,12967,12968,12849,12850,12857,13182,13181, +13180,8786,8801,8747,8750,8721,8730,8869,8736,8735,8895,8757,8745,8746,32394, +35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193, +20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479, +20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013, +21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660, +21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,U,64016,22686, +22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532, +23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353, +24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887, +24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121, +26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362, +26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032, +27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759, +27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199, +28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020, +28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654, +29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063, +30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024, +64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072, +32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782, +33864,33972,34131,34137,U,34155,64031,34224,64032,64033,34823,35061,35346, +35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214, +64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357, +37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433, +37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669, +37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880, +37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735, +38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797, +39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,U,U,8560,8561, +8562,8563,8564,8565,8566,8567,8568,8569,65506,65508,65287,65282,8560,8561, +8562,8563,8564,8565,8566,8567,8568,8569,8544,8545,8546,8547,8548,8549,8550, +8551,8552,8553,65506,65508,65287,65282,12849,8470,8481,8757,32394,35100,37704, +37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224, +20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550, +20592,20546,20628,20724,20696,20810,U,20836,20893,20926,20972,21013,21148, +21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642, +21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795, +22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718, +23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423, +24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984, +25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142, +26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785, +26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184, +27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908, +28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351, +28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999, +64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650, +29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364, +30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025, +U,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092, +32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864, +33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449, +35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559, +64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348, +37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543, +37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627, +64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957, +37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741, +38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823, +39857,39867,39936,40304,40299,64045,40473,40657, +}; + +static const struct dbcs_index cp932ext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{__cp932ext_decmap+0,95,202},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{__cp932ext_decmap+108,64,156},{0,0,0},{0,0,0},{0,0,0},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{__cp932ext_decmap+201,64,252},{__cp932ext_decmap+390,64,252},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__cp932ext_decmap+579,64,252},{__cp932ext_decmap+768,64,252},{ +__cp932ext_decmap+957,64,75},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __cp932ext_encmap[9686] = { +34690,N,N,N,N,N,N,N,N,N,N,34692,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +34644,34645,34646,34647,34648,34649,34650,34651,34652,34653,N,N,N,N,N,N,61167, +61168,61169,61170,61171,61172,61173,61174,61175,61176,34708,N,N,N,N,N,N,N,N,N, +N,N,N,N,34712,N,N,N,N,N,33121,N,N,N,N,N,N,N,N,34707,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,34713,34624,34625,34626,34627,34628,34629,34630, +34631,34632,34633,34634,34635,34636,34637,34638,34639,34640,34641,34642,34643, +34688,N,34689,34698,34699,N,N,N,N,N,N,34700,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,34693,34694,34695,34696,34697,34661,N,N,N,N,N,N,N,N,N, +34665,N,N,N,N,N,N,34656,N,N,N,34659,N,N,N,N,N,N,N,N,N,34657,34667,N,N,34666, +34660,N,N,N,34668,N,N,N,N,N,N,N,N,N,N,34662,N,N,N,N,34670,N,N,N,N,N,N,N,N,N,N, +N,N,N,34655,34669,N,N,34658,N,N,N,34663,N,N,N,N,N,34664,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34686,34703,34702,34701,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,34674,34675,N,N,N,N,N,N,N,N,N,N,N,N,34671,34672,34673, +N,N,34677,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +34676,N,N,N,N,N,N,N,N,34691,60748,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,60749,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60750, +60751,N,N,60752,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60753,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,60754,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60756,N,N,N,N,N,N,N, +60755,N,60758,N,N,N,N,N,60757,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60741,N,N,N,60759,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,60762,60763,N,N,N,60761,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,60760,N,60766,N,N,N,60764,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60765,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60767,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,60769,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,60768,60770,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60771,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,60772,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,60773,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60774,60775,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,60776,N,N,N,N,N,N,N,N,N,60777,N,N,N,N,N,N,N,N,61019,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,60778,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60779, +60780,N,N,N,N,N,N,60781,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,60782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60783,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60784,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60785,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60786,60789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60788,N,N,N,N,N,N,N,N,N,N,N,N, +60790,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,60791,60792,60793,N,N,N,N,N,N,N,N,N,N,N,60794,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60795,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60797,60796,60801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,60802,60803,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60804,N,N,N,N,N,N,N,60805,N,60806,N,N,N,N,N,60807,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,60808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60809,60810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60811,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60813,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60814,60815,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60816,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,60817,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60818,60819,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60822,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,60820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60823,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60824,60825,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60826,60827,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,60828,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60747,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60829,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60830,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60831,60832,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60833,N,N, +N,N,60834,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,60836,N,N,N,N,N,N,N,N,60835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60838, +60839,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60837,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60841,N, +N,N,N,N,N,60840,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60842,60843,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60844,60845,60846,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,60847,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60848,60849,60850,N,N,N,N,N, +N,N,N,60853,N,N,N,N,N,N,N,N,N,N,N,60851,N,N,N,N,N,N,N,N,60855,N,N,N,N,N,60856, +N,N,N,N,N,N,N,N,N,60854,N,N,60743,N,N,N,N,N,N,N,N,N,60852,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60858,N,60859,N,N,N,N,N,N,N,N,N,N,N,60857,N, +N,N,N,N,N,N,N,N,N,N,N,N,60861,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,60862,N,N,N,N,N,N,60863,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60864,N,N,N,N,N,N,N,N,N,N,N,N,60865,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,60866,60746,60867,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60869,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60870,N,N,N,N,60872, +60873,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60874,N,N,N,N,N,N, +N,N,N,N,N,N,N,60871,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,60744,N,N,N,N,N,N,60875,60877,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60879,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60880,60881,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60883,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60882,N,N,N,N,N,N,N,60884,N,N,N,N,N,N,N, +N,N,N,60885,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60886,N,60887,60888, +60889,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60890,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,60892,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60891,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,60893,60894,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60896,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60895,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,60897,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60898,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60899,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60901,N,N,N,N,N,60900,N, +N,N,60902,60905,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60903,N,N,60906,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60904,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,60907,60908,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60909,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,60910,60911,N,60912,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,60913,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60914,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60915,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,60742,60917,N,N,N,N,N,N,N,N,N,N,60916,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60919,60920,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60918,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60922,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60923,60924,N,N,N,N,N,N,N,N,N,N,N,N,60992,60993,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60995,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60996,N,N,N,N,N,N,N,N,N,N,N,60997, +N,N,N,N,N,N,N,N,61000,N,N,N,60998,N,N,N,N,N,N,N,N,N,N,N,N,60999,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,61002,61001,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,61003,N,N,61005,61004,N,N,N,61006,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61007, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61008,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61009,61010,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60812, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61011,61012,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61015,61013,N,61014,N,N,N,N,N,N,N,61016,61018, +61020,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61021,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61022,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61023,61024,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,61028,N,N,N,N,N,N,61030,61031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,61032,N,N,N,61034,61035,61037,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61038, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61040,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61039,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61041,61042,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60736,61043,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61044,61046,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61047,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61048,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61049,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61050,61051,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61052,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60740,61053,N,N,N,N, +N,61054,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61056,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61058,61061,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61062,60737,61063,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61064,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61065,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61066,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,61068,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61070, +61071,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,61072,61073,N,N,N,61074,61075,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,61076,61078,61081,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61082,61084,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61085,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61087,N,N,61086,N,N,N,61088,N,N,N, +N,N,61091,61092,N,N,N,N,N,N,N,61089,61090,61093,N,N,N,61095,N,N,N,N,N,61094,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61102,61096,N,61098,N,N,N,61097,N,N,N,N,N,N,N,N,N,N,N,N,N,61099,N,N,61101,N,N, +N,N,N,N,N,61100,N,N,N,N,N,N,N,N,N,N,N,N,N,61103,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61105,61106,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60739,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61104,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61110,N,N,61114,N,61112,N,61108,N,61109, +N,N,N,N,N,N,61113,N,N,N,N,N,N,61107,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60745,N, +61117,N,N,N,61120,61122,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61121,61119,N,N,61116,N,N,N,61115,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,60738,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61124,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61123,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61125,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61126,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61127,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,61128,61129,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61130,N,N,61131, +61132,61135,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61136,61137,N,N,N,N,N,N,N,61138, +N,N,N,N,N,N,N,61139,N,N,N,N,N,N,N,N,N,61140,N,61141,N,61142,N,N,N,61143,61144, +N,N,N,N,N,N,N,N,N,N,N,N,N,61145,61148,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61150,61151,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61152,N,N,61153,61155,N,N,61154,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,61156,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,61157,N,N,N,N,N,N,N,N,N,61158,61159,61161,N,N,N,N,61160,61163,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61164,60868,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61133,60787,60798,60800,60821,60860,60876,60878, +60921,60994,61017,61025,61026,61027,61029,61033,61036,61045,61057,61059,61060, +61069,61077,61079,61080,61083,61111,61118,61134,61146,61147,61149,61162,61180, +N,N,N,N,61179,N,N,N,N,N,33148,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,33119,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,33120,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,33169, +33170,33226,N,61178, +}; + +static const struct unim_index cp932ext_encmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp932ext_encmap+0,22,121},{__cp932ext_encmap ++100,17,191},{0,0,0},{__cp932ext_encmap+275,96,115},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__cp932ext_encmap+295,29,31},{0,0,0},{__cp932ext_encmap+298,49,168},{ +__cp932ext_encmap+418,3,205},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{__cp932ext_encmap+621,40,252},{__cp932ext_encmap+834,0,255},{ +__cp932ext_encmap+1090,30,244},{__cp932ext_encmap+1305,74,236},{ +__cp932ext_encmap+1468,21,219},{__cp932ext_encmap+1667,0,221},{ +__cp932ext_encmap+1889,138,255},{__cp932ext_encmap+2007,134,134},{0,0,0},{ +__cp932ext_encmap+2008,89,200},{__cp932ext_encmap+2120,158,178},{ +__cp932ext_encmap+2141,11,186},{0,0,0},{__cp932ext_encmap+2317,86,236},{ +__cp932ext_encmap+2468,30,245},{__cp932ext_encmap+2684,39,208},{0,0,0},{ +__cp932ext_encmap+2854,33,222},{__cp932ext_encmap+3044,93,242},{ +__cp932ext_encmap+3194,17,152},{__cp932ext_encmap+3330,19,166},{ +__cp932ext_encmap+3478,245,245},{__cp932ext_encmap+3479,96,206},{ +__cp932ext_encmap+3590,78,78},{__cp932ext_encmap+3591,0,251},{ +__cp932ext_encmap+3843,14,192},{__cp932ext_encmap+4022,1,207},{ +__cp932ext_encmap+4229,104,226},{__cp932ext_encmap+4352,48,228},{ +__cp932ext_encmap+4533,214,214},{__cp932ext_encmap+4534,63,218},{ +__cp932ext_encmap+4690,4,252},{__cp932ext_encmap+4939,39,191},{ +__cp932ext_encmap+5092,136,245},{__cp932ext_encmap+5202,5,187},{ +__cp932ext_encmap+5385,4,254},{__cp932ext_encmap+5636,177,190},{ +__cp932ext_encmap+5650,36,245},{__cp932ext_encmap+5860,7,159},{ +__cp932ext_encmap+6013,1,111},{__cp932ext_encmap+6124,130,166},{ +__cp932ext_encmap+6161,70,70},{__cp932ext_encmap+6162,33,122},{ +__cp932ext_encmap+6252,48,155},{__cp932ext_encmap+6360,209,235},{ +__cp932ext_encmap+6387,158,158},{0,0,0},{__cp932ext_encmap+6388,72,214},{ +__cp932ext_encmap+6531,82,138},{__cp932ext_encmap+6588,71,161},{0,0,0},{0,0,0 +},{0,0,0},{__cp932ext_encmap+6679,1,246},{__cp932ext_encmap+6925,72,220},{ +__cp932ext_encmap+7074,83,176},{0,0,0},{0,0,0},{__cp932ext_encmap+7168,7,245}, +{__cp932ext_encmap+7407,28,28},{__cp932ext_encmap+7408,18,246},{ +__cp932ext_encmap+7637,83,127},{__cp932ext_encmap+7682,240,244},{ +__cp932ext_encmap+7687,18,118},{__cp932ext_encmap+7788,207,207},{0,0,0},{ +__cp932ext_encmap+7789,103,222},{__cp932ext_encmap+7909,21,238},{ +__cp932ext_encmap+8127,6,255},{__cp932ext_encmap+8377,2,248},{ +__cp932ext_encmap+8624,49,72},{__cp932ext_encmap+8648,146,146},{ +__cp932ext_encmap+8649,157,175},{__cp932ext_encmap+8668,51,85},{ +__cp932ext_encmap+8703,87,101},{__cp932ext_encmap+8718,39,158},{ +__cp932ext_encmap+8838,78,220},{__cp932ext_encmap+8981,114,187},{ +__cp932ext_encmap+9055,0,0},{__cp932ext_encmap+9056,107,112},{ +__cp932ext_encmap+9062,25,209},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp932ext_encmap+9247 +,41,220},{__cp932ext_encmap+9427,14,45},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__cp932ext_encmap+9459,2,228}, +}; + +static const ucs2_t __jisx0213_1_bmp_decmap[2197] = { +65287,65282,65293,126,12339,12340,12341,12347,12348,12543,12447,U,U,U,U,U,U,U, +U,8836,8837,8842,8843,8713,8709,8965,8966,U,U,U,U,U,U,U,8853,8854,8855,8741, +8742,10629,10630,12312,12313,12310,12311,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,8802, +8771,8773,8776,8822,8823,8596,U,U,U,U,U,U,U,U,9838,9835,9836,9833,9655,9654, +9665,9664,8599,8600,8598,8601,8644,8680,8678,8679,8681,10548,10549,U,U,U,U,U, +U,U,U,U,U,10687,9673,12349,65094,65093,9702,8226,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,8723,8501,8463,13259,8467,8487,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12448,8211,10746,10747,12363,U,12365,U,12367,U, +12369,U,12371,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12436,12437, +12438,12459,U,12461,U,12463,U,12465,U,12467,U,U,U,U,U,U,U,12475,U,U,U,U,U,U,U, +U,12484,U,U,U,12488,9828,9824,9826,9830,9825,9829,9831,9827,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,962,9461,9462,9463,9464,9465,9466,9467,9468, +9469,9470,9750,9751,12320,9742,9728,9729,9730,9731,9832,9649,12784,12785, +12786,12787,12788,12789,12790,12791,12792,12793,U,12794,12795,12796,12797, +12798,12799,9150,9151,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162, +9163,9164,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +12535,12536,12537,12538,8922,8923,8531,8532,8533,10003,8984,9251,9166,12881, +12882,12883,12884,12885,12886,12887,12888,12889,12890,12891,12892,12893,12894, +12895,12977,12978,12979,12980,12981,12982,12983,12984,12985,12986,12987,12988, +12989,12990,12991,U,U,U,U,U,U,U,U,9680,9681,9682,9683,8252,8263,8264,8265,461, +462,464,7742,7743,504,505,465,466,468,470,472,474,476,8364,160,161,164,166, +169,170,171,173,174,175,178,179,183,184,185,186,187,188,189,190,191,192,193, +194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212, +213,214,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232, +233,234,235,236,237,238,239,240,241,242,243,244,245,246,248,249,250,251,252, +253,254,255,256,298,362,274,332,257,299,363,275,333,260,728,321,317,346,352, +350,356,377,381,379,261,731,322,318,347,711,353,351,357,378,733,382,380,340, +258,313,262,268,280,282,270,323,327,336,344,366,368,354,341,259,314,263,269, +281,283,271,273,324,328,337,345,367,369,355,729,264,284,292,308,348,364,265, +285,293,309,349,365,625,651,638,643,658,620,622,633,648,598,627,637,642,656, +635,621,607,626,669,654,609,331,624,641,295,661,660,614,664,450,595,599,644, +608,403,339,338,616,649,600,629,601,604,606,592,623,650,612,652,596,593,594, +653,613,674,673,597,657,634,615,602,U,509,8048,8049,U,U,U,U,U,U,U,U,8050,8051, +865,712,716,720,721,774,8255,779,769,772,768,783,780,770,741,742,743,744,745, +U,U,805,812,825,796,799,800,776,829,809,815,734,804,816,828,820,797,798,792, +793,810,826,827,771,794,10102,10103,10104,10105,10106,10107,10108,10109,10110, +10111,9451,9452,9453,9454,9455,9456,9457,9458,9459,9460,8560,8561,8562,8563, +8564,8565,8566,8567,8568,8569,8570,8571,9424,9425,9426,9427,9428,9429,9430, +9431,9432,9433,9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445, +9446,9447,9448,9449,13008,13009,13010,13011,13012,13013,13014,13015,13016, +13017,13018,13019,13020,13021,13022,13023,13024,13025,13026,13027,13050,13033, +13029,13037,13036,U,U,U,U,U,U,U,U,U,8273,8258,9312,9313,9314,9315,9316,9317, +9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,8544, +8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,13129,13076,13090,13133, +13080,13095,13059,13110,13137,13143,13069,13094,13091,13099,13130,13115,13212, +13213,13214,13198,13199,13252,13217,8555,U,U,U,U,U,U,U,13179,12317,12319,8470, +13261,8481,12964,12965,12966,12967,12968,12849,12850,12857,13182,13181,13180, +U,U,U,8750,U,U,U,U,8735,8895,U,U,U,10070,9758,20465,U,13314,20008,20015,20016, +20109,20193,20221,20223,20227,20235,20320,20296,20297,20310,20319,20330,20332, +20350,20362,20372,20375,64048,20425,20448,20481,20482,20494,20504,20519,20526, +20544,20539,20545,20628,20684,20722,20688,20710,64049,20742,20739,20747,20766, +20789,20810,64050,20821,20823,13493,20893,20931,20938,20958,20962,20974,20993, +13531,21011,21013,21065,21079,21089,21139,21192,64051,21196,21200,21206,21211, +64052,21232,21243,21248,21255,21276,64053,21345,21347,21373,21395,21405,21426, +21522,21543,21581,21660,21611,21620,21631,21640,21654,21665,21673,21702,21759, +21774,21803,21813,21840,21854,21889,21894,21902,64054,21933,21966,64055,22024, +22030,22075,22089,22134,22118,64056,22127,22129,22130,22169,22174,22185,22188, +22195,22217,22218,22282,U,22305,22319,22323,22324,22384,22391,22396,22428, +64015,U,22456,22471,22472,22479,22500,22509,22517,22518,22527,22537,64016, +22625,22628,64057,22652,22665,22686,64058,22697,U,22738,22734,22740,22746, +22752,22761,22796,34369,22877,22893,22923,22930,22948,22979,22994,23005,23059, +23075,23143,23149,23159,23166,23172,23198,23207,23236,U,23321,23333,21085, +23361,23382,23421,23443,23512,23532,23570,23582,23587,23595,14221,23650,64059, +64060,U,23674,23695,23711,23715,23722,23738,23755,23760,23762,23796,U,14306, +23821,23847,64017,23878,23879,23891,23882,23917,23937,23968,23972,23975,23992, +24011,21534,22099,24034,24084,24088,24152,24158,24254,63784,24267,24313,24320, +24322,24327,24349,24355,24372,24374,24381,24384,24389,24404,24408,24420,24423, +24445,24457,24476,24487,24495,24501,24503,24521,24542,24545,24553,24589,24596, +24600,24627,24629,24647,64061,24733,24734,24779,24788,24789,24797,24824,24860, +24875,24880,24887,64062,24973,64063,25020,25017,64064,25122,25150,25155,25174, +25178,25199,25221,25284,25302,25340,25354,25368,25401,25411,25445,25468,25573, +25581,25589,25616,25620,25634,25721,25681,25696,25709,25806,25790,25791,25796, +25802,25808,25847,25851,25890,25897,64065,25959,26013,64066,26112,26121,26133, +26142,26170,26146,26148,26155,26160,26161,26163,26363,26184,26188,U,26201, +26202,26209,26213,26227,26231,26232,26253,64067,26272,26290,26299,26310,26312, +15138,26331,26344,26362,26387,63785,26419,26470,26439,26440,26491,26497,26515, +26520,26523,26555,26617,26560,26583,26620,26625,26706,26653,26668,26673,26715, +26738,26741,64068,26787,26789,26802,26824,26832,26856,26861,26864,26865,26876, +26890,26953,U,26933,26946,26967,26979,26980,26984,27008,64020,27045,27053, +27087,15286,15299,27106,27113,27114,27125,27126,27151,27157,U,27195,27198, +27205,27216,27222,27227,27243,27251,U,27273,27284,27293,27294,27301,27364, +27367,15375,63773,27419,27422,27436,27445,27462,27478,27488,27493,27495,27511, +27522,27561,27565,63856,27599,27606,27607,27647,27653,27664,27699,27737,27740, +27818,27764,27766,27781,27782,27800,27804,27899,27846,27860,27872,27883,27886, +U,27908,27918,27950,27953,27961,27967,27992,28005,64069,28034,28039,28041, +28052,28074,28076,28095,28100,28118,28122,28123,28125,28156,64070,28212,28228, +28252,28254,28331,28337,28353,28359,28366,28432,28442,64071,28458,28463,28467, +28497,28505,28510,28513,28514,28542,28552,28556,28557,28564,28576,28583,28598, +28604,28615,28618,28665,28656,28661,28677,28678,28712,28746,28765,28766,28750, +28772,28789,28805,28836,28843,28855,28884,28888,28900,28943,28971,28958,28960, +28974,28976,28998,28999,29009,64072,29010,29020,29024,29032,64021,29061,29063, +29074,29121,29114,29124,29182,29184,29205,29269,29270,15935,29325,29339,29374, +29376,29435,U,29479,29480,64022,29520,29542,29564,29589,29599,29600,29602, +29606,29611,29641,29647,29654,29657,29667,29673,29703,29706,29722,29723,64074, +29734,29736,29738,29739,29740,29742,29743,29744,29764,29766,29767,29771,29783, +29794,29803,29805,29830,29831,29833,29848,29852,29855,29859,29840,29862,29864, +29865,29877,29887,29896,29897,29914,29951,29953,29975,29999,30063,30073,30098, +16242,30158,30180,30208,30210,30216,30229,30230,30233,30238,30253,30261,30275, +30283,30308,30309,30317,30319,30321,30337,30363,30365,30366,30374,30378,30390, +30405,30412,30414,30420,30438,30449,30460,30474,30489,30516,30518,30534,30541, +30542,30556,30559,30562,30586,30592,30612,30634,30688,30765,30787,30798,30799, +30801,30824,30830,64075,30896,U,30893,30948,30962,30976,30967,31004,31022, +31025,31028,64076,64077,31045,31046,64078,64079,64080,31068,64081,64025,64026, +31097,64082,64083,64027,31128,31153,31160,31176,31178,U,31188,31198,31211, +31213,31235,64084,31289,31325,31341,64085,31365,31392,U,31411,31419,31438, +31467,31485,31506,31533,31547,31559,31566,31584,31597,31599,31602,31646,64086, +31703,31705,31745,31793,31774,31776,31795,31798,16996,U,31833,31853,31865, +31887,31892,31904,31932,31957,31961,31965,32007,32008,32019,32029,32035,32049, +32065,32072,32083,32092,32122,32131,32139,32160,32166,32194,32204,32214,32227, +64087,32296,32264,32273,32277,64089,32327,32338,32353,32394,32397,32583,64090, +32657,32663,32703,32718,32731,32735,32748,32750,32762,64091,32788,32806,32821, +32823,32828,32970,32983,32992,33011,33048,33098,33120,33127,33128,33133,33211, +33226,33231,33239,64092,17491,17499,33376,33396,U,33422,33441,33443,33444, +33449,33454,33463,33470,33471,33478,33493,33533,33534,33536,33537,33634,33570, +33581,33594,33603,33607,33617,33621,33661,33670,33682,33688,33703,33705,33727, +33728,33735,33743,33745,33761,33770,33793,33798,33802,64095,33864,33887,33904, +33907,33925,33950,33967,33972,33978,33984,33986,U,34098,34078,34083,34095, +34137,34148,64031,34221,34170,34188,34191,34210,34224,34251,34254,34285,34322, +34303,34308,34309,34320,U,34328,34345,34360,34391,34395,63798,34402,17821, +34412,34421,34456,34488,34554,34556,34557,34571,34673,34695,34696,34732,34733, +34741,17898,34774,34796,34822,34826,34832,34836,34847,34968,34986,35018,35022, +U,35061,35100,64096,35096,35097,35098,35111,35120,35122,35129,35136,35220, +64097,35284,35301,35318,35346,35349,35362,35383,35399,35406,35421,35425,35445, +35449,35495,35536,35551,35572,35574,64034,64098,64099,35654,35668,35673,35689, +35741,35913,35944,64100,36065,36084,36088,36094,64101,36114,36123,36271,36302, +36305,36311,36384,36387,36413,36464,36475,U,36544,18500,36602,36638,36653, +36662,36692,U,36774,36789,36836,36840,36846,36872,36909,64103,37000,37013, +37015,37017,37019,37026,37043,37054,37060,37061,37063,37079,37085,37086,37103, +37108,64038,37140,37141,37142,37154,37155,37159,37167,37169,37172,37181,37192, +37211,37251,37278,37292,37297,37308,37335,37371,37348,37349,37357,37361,37383, +37392,37432,37433,37434,37436,37440,37443,37455,37496,37512,37570,37579,37580, +37587,37600,37631,37636,37663,37665,37669,37704,37705,37706,37732,37733,37738, +37744,37787,37795,37818,37830,37854,37855,37892,37885,37939,37962,37987,37995, +38001,38002,38286,38303,38310,38313,38316,38326,38333,38347,38352,38355,18864, +38362,38366,38488,38532,63964,38557,38564,38565,38610,38622,64104,38633,38639, +38707,38715,38733,38734,38735,38746,38766,38771,38805,38830,38842,38849,38857, +38878,38875,38900,64105,38922,38942,38955,38960,64106,38994,38995,38998,38999, +39001,39002,63952,39013,39020,39098,39112,39143,39256,39326,39426,39427,39460, +39469,39470,39480,39498,39502,39506,39606,39617,39619,39630,39638,39673,39682, +39688,39712,19479,39725,39774,39801,39782,39794,39797,39812,39818,39823,39838, +39847,39873,39886,39909,39928,39933,39936,39971,40001,40015,40016,40019,40035, +40037,40055,40221,40222,40259,40263,40274,40291,40304,40316,40330,40342,40384, +40364,40380,40407,U,40423,40455,40469,40572,40606,40612,40620,40623,40628, +40629,40643,40657,40720,40761,40791,40848,40852,40855,40866,23032,23643,24183, +30246,32363, +}; + +static const struct dbcs_index jisx0213_1_bmp_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_1_bmp_decmap+0,47,125},{ +__jisx0213_1_bmp_decmap+79,33,126},{__jisx0213_1_bmp_decmap+173,43,118},{ +__jisx0213_1_bmp_decmap+249,43,72},{__jisx0213_1_bmp_decmap+279,57,126},{ +__jisx0213_1_bmp_decmap+349,66,126},{__jisx0213_1_bmp_decmap+410,65,124},{ +__jisx0213_1_bmp_decmap+470,33,126},{__jisx0213_1_bmp_decmap+564,33,126},{ +__jisx0213_1_bmp_decmap+658,33,126},{__jisx0213_1_bmp_decmap+752,33,126},{ +__jisx0213_1_bmp_decmap+846,33,126},{__jisx0213_1_bmp_decmap+940,33,126},{ +__jisx0213_1_bmp_decmap+1034,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_1_bmp_decmap+ +1128,85,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_1_bmp_decmap+1170,39,126},{__jisx0213_1_bmp_decmap+1258,33,126},{ +__jisx0213_1_bmp_decmap+1352,33,126},{__jisx0213_1_bmp_decmap+1446,33,126},{ +__jisx0213_1_bmp_decmap+1540,33,125},{__jisx0213_1_bmp_decmap+1633,33,126},{ +__jisx0213_1_bmp_decmap+1727,33,126},{__jisx0213_1_bmp_decmap+1821,33,126},{ +__jisx0213_1_bmp_decmap+1915,33,126},{__jisx0213_1_bmp_decmap+2009,33,126},{ +__jisx0213_1_bmp_decmap+2103,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const ucs2_t __jisx0213_2_bmp_decmap[2425] = { +19970,19983,19986,20009,20011,20014,20032,20039,20040,U,20049,13318,U,20058, +20073,20125,13356,13358,20153,20155,U,20156,20163,20168,20176,20203,20186, +20209,20213,20224,20246,20324,20279,20286,20308,20312,U,20343,20344,20346, +20349,20354,20357,20370,20378,20454,20402,20414,20421,20427,20431,20434,13418, +20466,20480,20496,20499,20508,20510,20514,13416,20546,20550,20558,20563,20567, +20579,20582,20586,20592,20643,20616,20626,20627,20629,20630,20636,20650,U, +20657,20666,20667,20676,20679,20723,U,20686,U,20692,20697,20705,20713,13458, +20744,U,20759,20763,U,20832,U,20851,20867,20875,13500,20888,20899,20909,13511, +20924,U,U,20979,20980,20994,21010,21014,U,21077,21084,21100,21111,21124,21122, +U,21144,U,21156,21158,21167,21178,21179,21194,13599,21201,U,21239,21258,21259, +21284,21301,21310,21314,U,U,21351,21356,21370,21412,21428,U,21431,21440,U, +13661,13662,21461,21466,13667,21492,21493,21589,21540,21544,13678,21571,21602, +21606,21612,21642,21645,21653,21664,21670,21677,21678,21687,21690,21695,21699, +U,21740,21743,21745,21747,21760,21761,21769,21820,21825,13734,21831,21834, +13736,21856,21857,21860,U,21885,21890,21896,21905,13765,21970,U,U,21951,21961, +21964,21969,21981,13786,21986,U,21993,22056,U,22023,22032,22064,22071,13812, +22077,22079,22080,22087,22110,22112,22125,13829,22152,22156,22165,22170,22173, +22184,22189,22194,22213,22221,22239,22248,22262,22263,U,22293,22307,U,22313,U, +22341,22342,22348,22349,U,22376,22383,22387,22388,22389,22395,U,U,22444,22426, +22429,22430,22440,22487,U,22476,U,U,22494,22502,22512,13898,22520,22523,22525, +22532,22558,22560,22567,22578,22585,U,22601,22604,22631,22666,22667,22669, +22671,22672,22676,22685,22698,22705,U,22723,22733,22754,22771,22772,22789, +22790,22795,22797,22804,22820,U,13969,22845,13977,22854,13974,U,22875,22879,U, +22901,22902,22908,22943,22958,22972,22984,22989,23006,23011,23012,23015,23022, +U,U,14031,23052,23053,23063,23079,23085,23125,23141,23162,23179,23196,23199, +23200,23202,23217,23219,23221,23226,23231,23258,23260,23264,23269,23280,23278, +23285,23296,23304,23319,23348,23341,23372,23378,23400,23407,23420,23423,23425, +23428,23446,23468,14177,23488,14178,23502,23510,14188,14187,23537,23549,14197, +23555,23593,23600,U,23647,23651,23655,23656,23657,23664,U,U,23676,U,U,23688, +23690,14273,U,U,23712,23714,23718,23719,U,23725,23733,U,23753,U,U,23814,23824, +23851,23837,23840,23844,23846,23857,23865,23874,14312,23905,23914,14324,23920, +U,14333,23944,14336,23954,23956,23959,23961,23984,23986,23988,U,23993,24017, +24023,24024,24032,U,24036,24041,14383,24064,14390,24082,24085,14400,24095, +24110,24126,24137,14428,24150,14433,24171,24172,24173,24174,U,24229,24234, +24236,24249,24255,24262,24274,24281,U,24317,24328,24334,24348,U,24350,24391, +24419,24434,24446,24463,24482,24484,24504,24516,14586,24519,24523,24530,24531, +24532,24546,24558,24559,24563,24572,14615,24599,24610,24612,14618,24652,24703, +24714,24725,24744,U,24752,24753,24766,24776,24793,24795,24814,24818,24821, +24848,24850,24851,24857,24862,24890,14703,24897,24902,24928,24956,U,24978, +24979,24983,24984,24997,25000,25005,U,25045,25053,25055,25077,U,25109,25123, +25129,25158,25164,25169,25170,25185,25188,25211,25197,25203,25241,25254,25301, +U,25341,25347,25357,25360,U,U,25394,25397,25403,25404,25409,25412,25422,U, +25433,U,U,25452,25476,25497,U,25492,25533,25591,25556,25557,25564,25568,25579, +25580,25586,25609,25630,25637,25641,25647,25690,25691,25693,25715,25725,25735, +25745,25757,25759,25803,25804,25813,25815,U,25828,25829,25855,25860,14958, +25871,25876,25878,14963,25886,25906,25924,25940,25963,25978,25985,25988,25989, +25994,26034,26037,26040,26047,26050,26057,26068,15062,26098,26105,26108,26116, +26120,26145,26154,26181,26193,26190,15082,U,26199,26203,26211,U,U,26218,26219, +26220,26221,26235,26240,26256,26258,26265,15118,26285,26289,26293,15130,26303, +15132,26348,15063,26369,26373,26386,U,26393,U,U,26444,26445,26452,26461,U,U,U, +26484,26486,U,26514,U,33635,26640,26544,26546,26563,26568,26578,26585,26587, +26608,26615,U,U,U,26648,26655,26669,U,26675,26683,26686,26692,26693,26697, +26700,26709,26711,15223,26731,26734,26746,26748,26754,26768,26774,15213,26776, +26777,26778,26780,26794,26795,26804,26811,26875,U,U,64019,26819,26821,26828, +26831,26838,26841,26852,26853,26860,26871,26883,26887,15239,15240,U,26939, +15245,26950,26985,26988,26994,27002,27007,27026,15268,27030,27032,27046,27056, +27063,27066,27068,27072,27089,27094,U,U,27184,U,U,27107,27118,27119,27123, +15309,27124,27134,27153,27162,27165,U,27186,27187,27188,27199,27206,27209, +27258,27214,27218,27236,U,27262,27267,27275,15344,27281,27295,27297,U,27307, +27325,27334,27348,27344,27356,27357,U,U,27372,27377,27378,27379,27389,U,27403, +27407,27408,27409,U,27415,15398,27439,27466,27480,27500,27509,27514,27521, +27547,27566,U,27581,27582,27591,27592,27593,27610,27622,27623,27630,27633, +27650,27658,27662,27701,27702,27706,U,27711,27725,27739,27757,27780,27785, +15555,27796,27797,27799,27821,27842,27856,15570,27862,27866,27868,27881,27884, +27885,U,27904,27914,27940,27942,27943,27751,27951,27964,27995,27998,28000, +28016,28032,28033,28042,28045,28049,28056,U,28183,U,U,U,28075,28078,28084, +28098,27956,28104,28110,28111,28112,28127,28137,28150,28214,28190,28194,28199, +15633,28210,28220,28232,28233,28235,28236,28239,28241,28243,28244,28247,28259, +15646,28307,28327,28340,28351,28355,28362,28377,28469,28395,28409,28411,28426, +28428,28440,28453,28470,28476,U,28498,28503,28506,28512,28520,28568,28541, +28560,28566,28606,28575,28581,28591,15716,28597,28616,28617,28634,28638,28649, +U,28668,28672,28679,28682,28707,U,28729,28730,28732,28739,28743,28747,15770, +28756,28773,28777,28780,28782,28790,28798,28801,28806,28821,28823,28859,U, +28831,28849,U,28908,28874,28881,28883,28892,28931,28932,28934,28935,28936, +28940,15808,28975,28977,29008,29002,29011,29022,15828,29078,29056,29083,29088, +29090,29102,29103,29107,U,29131,29139,29145,29148,29191,15877,64073,29227, +29236,29240,29241,20012,29250,29267,29271,29283,U,29294,29295,29304,29311, +29326,U,29357,29358,29360,29361,29377,15968,29388,15974,15976,29427,29434, +29447,29458,29464,29465,16003,29497,29484,29489,29491,29501,29522,16020,29547, +29548,U,29550,29551,29553,29559,29569,29573,29578,29588,29592,29596,29598, +29605,29608,29621,29623,29625,29628,29631,29637,29643,29665,29671,29689,29715, +29690,29697,29732,29745,29753,29779,29760,29763,29773,29778,29789,29809,29825, +29829,29832,U,29842,29847,29849,29856,29857,29861,29866,29867,29881,29883, +29882,29910,29912,29918,29935,29931,U,29946,U,29984,29988,29994,16215,U,30013, +30014,30016,30024,30030,30032,30034,30060,30066,30065,30074,30077,30078,30081, +U,30092,16245,30114,16247,30128,30135,30143,30144,30150,30159,30163,30173, +30175,30176,30183,30188,30190,30193,30201,30211,30232,30215,30223,16302,U, +30227,30235,30236,U,30245,30248,30268,30259,U,16329,30273,U,30281,30293,16343, +30318,30357,30364,30369,30368,30375,30376,30383,U,30409,U,30440,30444,U,30487, +30490,30509,30517,16441,U,U,30552,30560,30570,U,30578,30588,30589,U,16472, +30618,30623,30626,30628,30633,30686,30687,30692,30694,30698,30700,16531,30704, +30708,30715,U,30725,30726,30729,30733,30745,30753,30764,30791,30820,30826,U, +30858,30868,30884,30877,30878,30879,30907,30920,30924,30926,30933,30944,30945, +30950,30969,30970,30971,30974,U,30992,31003,31024,31013,31035,31050,31064, +31067,16645,31079,31090,31124,31125,31126,31131,31137,31145,31156,31163,31170, +31175,31180,31181,31190,16712,U,U,16719,31242,31249,31253,31259,31262,16739, +31277,31288,31303,31308,31318,31321,31324,31327,31328,31335,31338,31349,31352, +31362,31370,31376,31395,31404,U,16820,31417,31420,31422,16831,31436,31441, +31463,31464,31476,U,U,31495,U,31549,31527,31530,31534,31535,31537,16870,16883, +31615,31553,16878,31573,31609,31588,31590,31593,31603,U,16903,31632,31633, +31643,16910,31663,31669,31676,31685,31690,U,U,31700,31702,31706,31722,31728, +31747,31755,31758,31759,31782,31813,31818,31825,31831,31838,31841,31849,31854, +31855,31856,U,U,U,31910,U,31926,31927,31935,U,31940,U,31944,31949,U,31959,U, +31974,31979,U,31989,32003,32009,17094,32018,32030,U,U,32061,32062,32064,32071, +U,U,17110,32089,32090,32106,32112,17117,32127,U,32134,32136,32140,32151,U, +32157,32167,32170,32182,32183,32192,32215,32217,32230,32241,32249,17154,U, +64088,32272,32279,32285,32288,32295,32300,32325,32371,32373,32382,32390,32391, +17195,32401,32408,32410,17219,32572,32571,32574,32579,32580,32591,13505,U, +32594,U,32609,32611,32612,32621,32637,32638,U,32656,20859,U,32662,32668,32685, +U,32707,32719,32739,32741,32751,32754,32770,32778,32776,32782,32785,32790, +32804,32812,32816,32835,32870,32881,32885,32891,32921,32924,32932,32935,32952, +U,32965,32981,32984,32998,U,33037,33013,33019,17390,33077,33046,33054,17392, +33060,33063,33068,U,33085,17416,33129,17431,33153,17436,33156,33157,17442, +33176,33202,33217,33219,33238,33243,U,33252,U,33260,U,33277,33279,U,33284,U, +33305,33313,33314,U,33330,33332,33340,33350,33353,33349,U,33355,17526,33359, +17530,33367,U,33372,33379,U,64093,64094,33401,17553,33405,33407,33411,33418, +33427,33447,33448,33458,33460,33466,33468,33506,33512,33527,33543,33544,33548, +33620,33563,33565,33584,33596,33604,33623,17598,33663,17620,17587,33677,33684, +33685,33691,33693,33737,33744,33748,33757,33765,33785,33807,33809,33813,U, +33815,33849,33866,33871,33873,33874,33881,33882,33884,U,33893,33910,33912, +33916,33921,17677,34012,33943,33958,33982,17672,33998,33999,34003,U,34023, +34026,34031,34032,34033,34042,34045,34060,34075,34084,34085,34091,34100,34127, +34159,17701,17731,34110,34129,34131,34142,34145,34146,U,34171,34173,34175, +34177,34182,34195,34205,34207,34231,34236,34247,34250,34264,34265,34271,34273, +34278,34294,34304,34321,34334,34337,34340,34343,U,34361,34364,U,34368,64032, +34387,34390,34415,34423,34426,34439,34441,34445,34449,34460,34461,34472,64033, +34481,34483,34497,34499,34513,34517,34519,34531,34534,17848,34565,34567,34574, +34576,34579,34585,34591,34593,34595,34609,34618,34622,34624,34627,34641,34648, +34660,34661,34674,34684,U,U,34727,34697,34699,34707,34720,U,17893,34750,U, +34753,34766,34805,34783,U,34787,34789,34790,34794,34795,34797,34817,34819, +34827,34835,34856,34862,34866,34876,17935,34890,34904,34911,34916,U,U,34921,U, +34927,34976,35004,35005,35006,35008,35026,U,35025,35027,35035,35056,35057, +17985,35073,U,35127,U,35138,35141,35145,U,18021,35170,35200,35209,35216,35231, +35248,35255,35286,35288,35307,18081,35313,35315,35325,35327,18095,35345,35348, +U,35361,35381,35390,35397,35405,35416,35502,35472,35511,35518,35543,35580,U, +35594,35589,35597,35612,35615,35629,35651,18188,35665,35678,35702,35711,35713, +35723,35732,35733,35740,35742,35897,U,35901,U,U,35909,35911,35919,35924,35927, +35945,35949,35955,U,35987,35986,35993,18276,35995,36004,36054,36053,36057,U, +36080,36081,U,36105,36110,36204,36228,36245,36262,U,36294,36296,36313,36332, +36364,18429,36349,36358,U,36372,36374,36385,36386,36391,U,18454,36406,36409, +36427,36436,36450,36460,36461,36463,36504,36510,36526,36531,36533,36534,36539, +U,36561,36564,18510,36601,U,36608,36616,36631,36651,36672,36682,36696,U,36772, +36788,64102,36790,U,36801,36806,64036,36810,36813,36819,36821,36832,36849, +36853,36859,36866,36876,36919,U,36931,36932,36957,36997,37004,37008,38429, +37025,18613,37040,37046,37059,37064,U,37084,37087,U,37110,37106,37120,37099, +37118,37119,37124,37126,37144,37148,37150,37175,37177,37178,37190,37191,37207, +37209,37217,37220,37236,37241,37253,37262,37288,37294,37299,37302,37315,37316, +37338,U,U,37356,37358,37377,37386,37398,37399,U,37427,37442,37447,37450,37454, +37457,37462,37465,37472,37473,37477,37479,37480,U,U,37500,37501,37503,37513, +37517,37527,37529,37535,37543,37547,U,U,37554,37567,37568,37574,37582,37584, +37591,37593,37605,37607,37649,37623,37625,37627,37634,37645,37653,37661,37662, +37671,37673,U,U,37703,37713,37719,37722,37739,37745,37747,37793,U,U,37768, +37771,37775,37790,37877,U,U,37873,37825,37831,37852,37858,37863,37897,37903, +37910,37911,37883,37938,37940,37947,37957,U,U,37997,37999,38264,38265,38278, +38284,38285,U,38315,38324,U,38344,U,U,38444,38451,38452,U,38460,38465,38497,U, +38530,U,38554,U,18919,38569,38575,38579,38586,38589,18938,U,38616,38618,38621, +18948,38676,38691,18985,38710,38721,38727,38741,38743,38747,38762,U,U,38806, +38810,38814,38818,38833,38834,38846,38860,38865,38868,38872,38873,38881,38897, +38916,38925,38926,38932,38934,19132,U,38947,38962,38963,38949,38983,39014, +39083,39085,39088,U,39095,39096,39099,39100,39103,39106,39111,39115,39136,U, +39137,39139,39141,39146,39152,39153,39155,39176,19259,U,39190,39191,U,39194, +39195,39196,U,39217,39218,39219,39226,39227,39228,39232,39233,39238,39245, +39246,39260,39263,39264,39331,39334,39353,39357,39359,39363,39369,39380,39385, +39390,U,39408,39417,39420,39434,39441,39446,39450,39456,39473,39478,39492, +39500,39512,19394,39599,19402,39607,19410,39609,U,39622,39632,39634,39637, +19432,39644,39648,39653,39657,39683,39692,39696,39698,39702,39708,39723,39731, +39741,19488,39755,39779,39781,39787,39788,39795,39798,39799,39846,39852,39857, +U,U,39858,39864,39870,39879,39923,39896,39901,39911,39914,39915,39919,39918,U, +39930,U,39927,U,39958,39960,39961,39962,39965,39970,39975,39977,39978,U,39985, +39990,39991,40005,40028,U,40009,40010,U,40020,40024,40027,40029,40031,40041, +40042,40043,40045,40046,40048,40050,40053,40058,40166,40178,40203,40194,U, +40209,40215,40216,U,19652,U,40242,19665,40258,40266,40287,40290,U,40297,40299, +U,40307,40310,40311,40318,40324,40333,40345,40353,40383,40373,40377,40381, +40387,40391,40393,40406,40410,40415,40416,40419,40436,19719,40458,40450,40461, +40473,40476,40477,40571,U,40576,40581,40603,40616,U,40637,U,40671,40679,40686, +40703,40706,19831,40707,40727,40729,40751,40759,40762,40765,40769,40773,40774, +40787,40789,40792,U,40797,U,40809,U,40813,40816,40821, +}; + +static const struct dbcs_index jisx0213_2_bmp_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_2_bmp_decmap+0,34,126},{0,0,0},{ +__jisx0213_2_bmp_decmap+93,33,126},{__jisx0213_2_bmp_decmap+187,33,126},{ +__jisx0213_2_bmp_decmap+281,33,125},{0,0,0},{0,0,0},{__jisx0213_2_bmp_decmap+ +374,33,126},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_2_bmp_decmap+468,33,126},{ +__jisx0213_2_bmp_decmap+562,33,126},{__jisx0213_2_bmp_decmap+656,33,126},{ +__jisx0213_2_bmp_decmap+750,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_2_bmp_decmap+844,33,126},{__jisx0213_2_bmp_decmap+938,33,126},{ +__jisx0213_2_bmp_decmap+1032,33,126},{__jisx0213_2_bmp_decmap+1126,33,126},{ +__jisx0213_2_bmp_decmap+1220,34,126},{__jisx0213_2_bmp_decmap+1313,33,126},{ +__jisx0213_2_bmp_decmap+1407,33,126},{__jisx0213_2_bmp_decmap+1501,33,126},{ +__jisx0213_2_bmp_decmap+1595,33,125},{__jisx0213_2_bmp_decmap+1688,35,126},{ +__jisx0213_2_bmp_decmap+1780,33,126},{__jisx0213_2_bmp_decmap+1874,33,125},{ +__jisx0213_2_bmp_decmap+1967,34,125},{__jisx0213_2_bmp_decmap+2059,34,126},{ +__jisx0213_2_bmp_decmap+2152,33,126},{__jisx0213_2_bmp_decmap+2246,33,126},{ +__jisx0213_2_bmp_decmap+2340,33,117},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __jisx0213_bmp_encmap[27287] = { +8754,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10530, +10531,N,N,10532,N,10533,N,N,10534,10535,10536,N,10537,10538,10539,N,N,10540, +10541,N,N,N,10542,10543,10544,10545,10546,10547,10548,10549,10550,10551,10552, +10553,10554,10555,10556,10557,10558,10559,10560,10561,10562,10563,10564,10565, +10566,10567,10568,10569,10570,10571,10572,10573,N,10574,10575,10576,10577, +10578,10579,10580,10581,10582,10583,10584,10585,10586,10587,M,10589,10590, +10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10601,10602,10603, +10604,N,10605,10606,10607,10608,10609,10610,10611,10612,10613,10618,10810, +10825,10785,10796,10812,10827,10841,10847,N,N,10813,10828,10816,10831,N,10832, +10616,10621,N,N,N,N,10814,10829,10815,10830,10842,10848,N,N,N,N,N,N,10843, +10849,N,10877,N,N,10614,10619,N,N,N,N,N,N,N,N,10844,10850,N,N,N,10811,10826,N, +N,10788,10799,N,N,10787,10798,10817,10833,N,N,10818,10834,N,N,10874,10617, +10622,N,N,10819,10835,11051,11050,10809,10824,N,N,10820,10836,10789,10800, +10845,10851,10791,10803,10790,10802,10823,10839,10792,10804,N,N,N,N,10615, +10620,10846,10852,10821,10837,10822,10838,N,N,N,N,N,N,N,10793,10805,10795, +10808,10794,10807,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11049,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +11044,N,N,N,N,N,N,N,N,N,N,10351,10352,N,10353,10358,10359,N,10360,N,10361,N, +10362,N,10363,N,10364,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +10356,10357,N,N,N,11077,11059,11065,11066,11045,M,11071,10862,11046,11054,M,M, +N,11057,N,11058,10869,11048,10873,N,N,11062,11068,11042,11074,11052,N,N,N, +10858,10868,10859,11060,10875,10853,10870,10863,N,11055,N,N,N,10860,11073, +10867,N,10864,10855,N,N,10876,10865,10856,11047,N,N,N,10861,11053,11061,10854, +M,11067,10872,N,10866,11072,10857,N,11041,10878,N,N,11043,N,N,N,N,10871,N,N,N, +11070,11069,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,10801,11091,N,N,N,11092,N,N,N,11093,11094,N,N,N,N,N,N,10786,10840,N, +10797,N,10806,11121,N,N,N,N,N,N,M,11105,11106,11107,M,11100,11098,11103,11133, +11099,N,11095,N,11117,N,N,11097,11102,N,N,11101,N,N,N,N,N,N,N,N,11128,11129, +11134,N,11114,11126,11127,11115,11116,N,N,N,11122,11111,N,N,N,11119,11130,N, +11112,N,N,11120,11123,N,N,N,11125,N,N,N,N,11113,11131,11132,11124,11118,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11090,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,9817,10354,10355,11078,11079,11088,11089,9084,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,9024,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,10347,N,N,11096,N,N,11390,N,N,N,N,10348,10349,10350,N,N,N,N,N,N,N,11389,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,10529,9053,N,N,N,9055,N,N,11618,N,N,N,N,N,N,N,N,N,N,11620, +N,N,N,N,N,9056,N,N,N,N,N,N,N,N,N,N,N,N,N,9052,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,10104,10105,10106,N,N,N,N,N,N,N,N,N,N,11573,11574, +11575,11576,11577,11578,11579,11580,11581,11582,11583,11607,N,N,N,N,11317, +11318,11319,11320,11321,11322,11323,11324,11325,11326,11327,11328,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8817,N,8999,8997,8998,9000,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9001,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9003,9004, +9002,9005,8775,N,N,N,8774,N,N,N,N,N,N,N,N,N,9051,N,N,N,N,N,N,N,N,N,N,N,11640, +N,N,N,N,N,8788,8789,N,N,N,N,N,N,N,11635,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,8812,N,8813,N,N,8814,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8811, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8815,8816,N,N,N,N,N,N,N,N,N,N,N,N,8770, +8771,N,N,N,N,8772,8773,N,N,N,N,N,N,N,N,N,8785,8786,8787,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11641,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10102,10103,8776,8777,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,10108,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10050,10051,10052,10053,10054,10055, +10056,10057,10058,10059,10060,10061,10062,10063,10064,N,10110,10109,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11553,11554,11555,11556,11557,11558,11559, +11560,11561,11562,11563,11564,11565,11566,11567,11568,11569,11570,11571,11572, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,11329,11330,11331,11332,11333,11334,11335,11336, +11337,11338,11339,11340,11341,11342,11343,11344,11345,11346,11347,11348,11349, +11350,11351,11352,11353,11354,N,11307,11308,11309,11310,11311,11312,11313, +11314,11315,11316,9818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9837,N,N, +N,N,8994,8993,N,N,N,N,N,N,N,N,8996,8995,N,N,N,N,N,N,N,9019,N,N,N,N,N,N,10343, +10344,10345,10346,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9023,9832,9833,9834, +9835,N,N,N,N,N,N,N,N,N,N,9831,N,N,N,N,N,N,N,9828,9829,N,N,N,N,N,N,11646,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9786,9789,9787,9792,9785,9790, +9788,9791,9836,8829,N,8827,8828,N,8826,10107,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,11645,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,11297,11298,11299,11300,11301,11302,11303,11304,11305,11306,9006, +9007,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,8790,8791,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9018,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,9085,9086,8794,8795,8792,8793,N,N,N,11616,N,11617,9830,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8755,8756,8757,N,N,N,N,N,8758,8759,9020,N,N,N, +N,N,N,N,N,N,N,N,N,N,M,N,M,N,M,N,M,N,M,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,9332,9333,9334,N,N,N,N,N,N,N,N,8761,9083,N,N,N,N,N,N,N,N,N,N,M,N,M, +N,M,N,M,N,M,N,N,N,N,N,N,N,M,N,N,N,N,N,N,N,N,M,N,N,N,M,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10098, +10099,10100,10101,N,N,N,N,8760,9838,9839,9840,9841,9842,9843,9844,M,9846,9847, +9849,9850,9851,9852,9853,9854,11626,11627,N,N,N,N,N,N,11628,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,10305,10306,10307,10308,10309,10310,10311,10312, +10313,10314,10315,10316,10317,10318,10319,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,11621,11622,11623,11624,11625,N,N,N,N,N,N,N,N,10320, +10321,10322,10323,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333, +10334,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11355,11356,11357,11358,11359,11360, +11361,11362,11363,11364,11365,11366,11367,11368,11369,11370,11371,11372,11373, +11374,N,11377,N,N,N,11376,N,N,11379,11378,N,N,N,N,N,N,N,N,N,N,N,N,11375,11590, +N,N,N,N,N,N,N,N,N,11594,N,N,N,N,N,N,11585,N,N,N,11588,N,N,N,N,N,N,N,N,N,11586, +11596,N,N,11595,11589,N,N,N,11597,N,N,N,N,N,N,N,N,N,N,11591,N,N,N,N,11599,N,N, +N,N,N,N,N,N,N,N,N,N,N,11584,11598,N,N,11587,N,N,N,11592,N,N,N,N,N,11593,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11615,11631, +11630,11629,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11603,11604,N,N,N,N,N,N,N,N,N,N,N,N, +11600,11601,11602,N,N,11606,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,11605,N,N,N,N,N,N,9054,N,11619,11811,N,N,N,41261,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41266,N,41267, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41310,N,41302,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41342,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11859,N,N,N,N,N,N,41771,N,N,N,N, +62568,N,N,N,N,N,41775,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11867,41800,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41821,41822,N,N,N,N,41825,N,N,N,N,N,N,N, +N,N,N,41831,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42019,N,42022,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,42040,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42050,42058,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42105,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42303,N,N,N,N,42307,N,N,42305,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,42327,43043,43045,N,N,N,N,N,N,N,N,43049,43048,N,N,N,N,N, +N,N,N,43052,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20319,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,43070,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,20335,N,N,N,N,N,43094,N,N,N,N,N,N,N,N,N,N,N,43097,N,N,N,N,N,N,N,N,43100, +43102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,43119,N,N,N,N,N,N,43121,N,N,N,N,N,N,N,N,N,43124,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43129,N,N,N,N,43131,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44091,44102,N,N,44106, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44128,44379,N,N,N,N,44383,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44401,44598,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44412,44590,N,N,N,N,N,N,N,N,N, +N,N,44594,N,44596,N,N,N,N,N,30025,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,44653,N,N,N,N,N,N,N,N,N,44645,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,44840,44841,N,N,N,N,44844,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44852,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30078,N,N,N,N,N,N,N,N,N,N,N,N,30241,N, +N,N,N,N,N,N,N,N,44872,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44893,30266,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44919,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60987,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60994,61041,N,N,N,N,N,N,N,N,N,N,N,N,61054,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61248,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,61268,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61296,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61303,61480,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30566,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,61503,N,N,N,N,N,61505,N,61506,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,61513,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61520,61748,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30797,N,N,61766,N,61768,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,61788,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,61799,N,N,N,N,N,N,N,N,N,N,N,N,N,61804,61986,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61997,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62009,62052,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62068,N,N,N, +N,N,N,62071,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62077,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62259,N,N,N,N,N,N, +N,N,N,N,62263,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,62279,N,N,N,N,N,N,N,62283,N,N,N,N,62280,62291,N,N,N,N,N,N,62295,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,31085,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62507,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,62518,N,N,N,N,N,N,62523,62542,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62557,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,62561,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62782,N,62786,62792,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,62794,N,N,N,N,62796,N,N,N,N,N,62799,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +31321,N,N,N,N,N,N,N,31322,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62828,N,N,N,62830,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62839,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63029,N,N,N,N,N,N,N,N, +N,N,63026,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63028,63065,N,N,N,N,63060, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63085,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63086,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31569,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63340,N,N,N,N,31584, +63524,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,63546,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,63555,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63566,N, +N,N,N,N,N,N,N,N,N,N,N,N,63571,63595,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63785,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63807,63817,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +31819,N,N,N,N,N,N,N,N,N,63836,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64039,32088,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64362,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,64368,64373,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64376,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64567,64597,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64806,N,N,N,N,N,N,N,64808,N,N,N, +N,N,N,N,64810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64817,32318,N,N,N,N,N, +N,N,N,64831,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,65066,N,N,N,N,N,N,N,N,N,N,N,N,65069,65099,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65120,41250,N,N,N,N,N, +N,N,N,N,N,N,N,41251,N,N,41252,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11812, +41253,N,41254,61486,N,41255,11813,11814,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41256,N, +N,N,N,N,N,41257,41258,N,N,N,N,N,N,N,N,41260,N,N,N,N,N,N,N,N,41263,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,41264,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,11815,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41265,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41268,N,41269,41271,N,N,N,N,N,N,41272,N,N,N,N, +41273,N,N,N,N,N,N,N,41274,N,N,N,N,N,N,N,N,N,41276,N,N,N,N,N,N,11816,N,N,N,N,N, +N,N,N,N,41275,N,N,N,N,N,41277,N,N,N,41278,N,N,N,N,N,N,N,11817,N,11818,41279,N, +N,11819,N,N,N,N,N,N,N,11820,N,N,N,N,N,N,N,N,N,N,41280,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41282,N,N,N,N,N,N,41283,N,N,N,N,N,N,N, +N,N,11822,11823,N,N,N,N,N,N,N,N,N,N,41284,N,11824,N,41285,N,N,N,N,N,N,11825, +11821,N,N,N,41281,N,N,N,N,N,11826,N,11827,N,N,N,N,N,N,N,N,N,N,41287,41288,N, +41289,N,N,41290,11828,N,N,N,41291,N,N,41292,N,N,N,N,11829,N,N,N,N,N,N,N,41293, +N,11830,N,N,11831,N,N,41294,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41296,N,N,N,N,N,N,N,N,N,N,N,41297,N,N,N,N,N,N,41298,N,N,N,11833,N,41299,N,N,N, +41300,N,N,41301,N,N,N,N,N,N,N,N,N,N,N,N,N,11834,N,N,N,N,N,41295,N,N,N,N,N,N,N, +N,N,N,11809,41303,41304,11835,11836,N,N,N,N,N,N,N,N,N,N,N,11837,N,41305,N,N, +41306,N,N,N,N,11838,N,N,N,41307,N,41308,N,N,N,41309,N,N,N,N,11839,N,N,N,N,N,N, +11840,N,N,N,N,N,N,N,N,N,N,N,N,11842,N,N,N,N,11841,11843,41311,N,N,N,41312,N,N, +N,N,N,N,N,41313,N,N,N,N,41314,N,N,N,41315,N,N,N,N,N,N,N,N,N,N,N,41316,N,N, +41317,N,N,N,41318,N,N,N,N,N,41319,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,41321,N,N,N,N,N,N,N,N,N,41322,41323,11844,41324,41325,N,N,N,N,N,41326,N,N,N, +N,N,N,41320,N,N,N,N,N,N,41327,N,N,N,N,N,N,41329,N,N,N,N,N,N,N,N,41330,41331,N, +N,N,N,N,N,N,N,41332,N,N,41333,N,N,N,N,11845,N,41336,N,11847,N,N,N,41338,N,N,N, +N,41339,N,N,N,N,N,N,N,41340,N,N,N,N,11848,N,N,41341,N,N,N,N,N,N,N,N,11846, +41334,11851,N,N,11850,N,41761,N,N,11852,N,N,N,N,N,N,N,N,N,N,N,41763,N,N,N, +41764,N,N,11853,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11854,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,11855,N,N,N,N,N,N,N,N,N,N,11857,N,11858,N,N,N,N,N, +N,N,N,41766,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41768,N,N,N,N,N,N,N,62580,N,N, +N,N,N,N,N,41769,N,N,N,N,N,N,N,41770,N,N,N,N,N,N,N,N,N,N,N,N,41772,N,N,N,N, +11860,N,N,N,N,N,41773,N,N,N,N,N,N,N,N,N,41774,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41776,N,N,N,N,N,N,11861,N,N,N,N,N,N,11862,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,11863,N,N,N,11864,N,N,N,N,N,N,N,N,N,N,N,11865,N,N,N,N,41779,41780,11866, +41781,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41782,11868,N,11869,41783,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,11870,N,N,N,N,N,N,N,N,N,N,N,41785,N,11871,N,N,N,N,41786,12158,N,N,N, +11872,N,N,N,N,N,N,N,N,N,N,41787,N,N,N,N,N,N,N,N,N,N,41788,N,N,N,N,N,N,N,N,N,N, +41790,N,41789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11873,N,N,N,N,41792,N,N,N,N,N,N,N,N, +N,N,N,41794,N,41795,N,N,N,N,N,N,N,N,41796,N,N,N,N,N,N,N,N,N,N,41797,41798,N,N, +N,N,N,N,N,N,N,N,N,N,11874,N,41799,N,11876,N,N,N,11877,41801,N,N,N,N,11878,N,N, +N,N,11879,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11881,N,N,N,N,N,N,41803,N,N, +N,11882,11883,N,N,N,N,N,N,11884,N,N,41804,41805,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,11885,N,N,N,N,N,N,N,41806,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41807,N,N,N,N,N,N, +N,N,41808,N,N,N,41809,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,11887,N,11888,N,N,N,41812,N,N,N,N,41813,N,N,N,N,N,N,N,N,N,N,N,N,N,41814,N, +N,11889,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11890,N,N,N,N,N,N,N,N,N, +11891,N,N,N,N,N,N,41815,N,N,N,N,N,N,N,N,N,N,N,N,N,11892,N,41816,N,N,41818,N,N, +N,N,N,N,N,N,41819,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41823,N,N,N,N,41824, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41826,41827,11893,N,N,N,N,N, +N,N,N,N,N,N,20350,N,N,N,N,N,41829,N,N,11894,41830,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,41832,N,N,N,N,N,N,N,N,N,11895,N,N,N,N,N,N,N,41828,N,N, +N,N,N,N,N,N,N,N,N,N,41833,N,N,N,41834,N,N,N,N,11897,41835,N,N,N,N,N,N,N,11898, +N,N,N,N,N,N,N,N,N,N,11899,N,N,N,N,N,N,N,N,11900,N,41836,N,N,41837,N,N,N,N,N,N, +N,41838,11901,N,N,N,N,N,11896,N,N,N,41839,11902,N,N,N,N,41840,N,N,12065,N,N,N, +41841,41842,N,N,N,N,N,N,N,N,41843,N,N,41844,N,N,N,N,41845,N,N,N,41846,N,N, +12066,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,41848,N,N,41849,N,41850,N,41851,N,N,N,N,N,N,N,N,N,N,N,12067,41852,41853,N,N, +N,N,N,N,N,41854,N,N,N,N,12068,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,12069,N,N,N,N,N,N,N,N,N,12070,N,N,N,N,N,N,42017,N,N,N,N,42018,N,N,N,N, +N,42020,N,N,42021,N,N,N,N,N,12071,N,N,N,N,N,N,N,N,N,N,N,N,N,12072,N,42023, +42024,N,N,42025,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42027,N,N,N, +12073,42028,N,N,N,12074,N,42029,N,N,N,N,N,12075,N,N,42030,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,12077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +42035,N,N,N,N,N,N,N,N,N,42036,N,N,42037,N,12078,N,N,42038,42032,N,N,N,N,N,N,N, +N,N,N,42039,N,N,N,N,42041,N,N,N,N,N,N,42043,42046,12080,N,N,N,N,N,12081,N, +42047,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42044,N,N,N,N,N,N,N,42048, +N,N,N,N,N,N,42049,N,N,N,12082,N,42051,N,42052,42053,N,N,N,N,N,N,42054,N,12083, +N,N,N,N,N,N,N,N,N,29735,N,N,N,N,N,N,N,N,N,N,42055,N,42056,N,N,N,N,N,12085,N,N, +N,N,N,N,42057,N,12087,N,12088,12089,N,N,N,12084,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,42059,N,N,N,42060,N,N,N,N,N,N,N,N,42061,N,N,N,12090,42062,N,N,42063,12091, +N,N,N,N,N,N,N,N,N,42064,12092,N,N,12093,42065,N,N,N,N,42066,12094,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,42067,N,N,N,12095,12096,N,N,42068,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,42069,N,N,N,N,N,N,N,N,42070,N,N,N,N,N,N,N,N,N,N,N,N,N,42071,42072, +12097,N,N,N,N,N,N,N,N,N,N,42074,N,N,N,N,N,N,N,N,N,N,N,12099,N,42075,N,N,N,N,N, +42077,N,N,N,N,N,12100,N,N,N,12101,12102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42079, +42080,N,N,N,N,N,42081,42082,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,42084,N,N,N,N,N,N,42085,12103,N,N,42086,42087,42088,N,12104,N,N,N,42089, +12105,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42093,N,12106, +42094,42095,N,N,N,N,N,N,N,N,N,42096,N,N,N,42092,N,N,N,N,N,N,N,N,N,N,N,12109,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,12110,12111,N,N,N,42099,N,N,12112,N,N,N,N,N,N,N, +42097,N,N,N,N,N,N,42102,N,N,N,N,N,12113,N,42103,N,N,N,N,N,N,12114,N,N,42104,N, +N,N,N,12115,12116,N,42106,N,N,42107,N,42108,N,12117,42109,N,N,N,N,12118,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42110,N,42273,N,N,N,N,N,N,42274,N,N,N,N,N,N, +N,N,N,N,42275,N,N,N,N,N,N,42276,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42278,N,N,42279, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,12120,N,N,12121,N,N,42280,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,12123,N,N,N,N,N,N,N,N,N,N,N,N,12124,42281,42282,N, +42283,N,42284,42285,N,N,N,42286,N,N,N,N,N,N,N,N,42287,12125,N,N,N,N,N,N,N,N,N, +N,12127,42288,N,N,N,N,N,N,42289,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42291,N,N,N, +N,N,N,N,N,N,42292,12130,N,N,N,12129,N,12131,N,N,N,N,N,12132,N,N,N,N,N,12133,N, +42293,N,N,N,N,N,N,12134,N,N,N,N,N,N,N,N,N,42294,42295,42296,42297,N,N,N,N, +42298,12135,42299,N,N,N,N,N,N,42300,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42301,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42304,N,N,N,N,N,N,N,N,42306,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42309,N,12137,N,42310,N,N,N,N,N,N,N,N,N,N,N,N, +N,12138,N,N,N,N,N,N,N,42312,42313,N,N,N,N,N,42314,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +12139,N,N,N,N,N,N,12140,N,N,N,N,N,N,N,N,N,N,N,N,42315,N,N,N,N,12141,N,N,N,N,N, +N,N,N,N,42316,N,N,N,N,N,N,N,N,N,N,N,N,N,42317,N,N,N,N,N,N,12142,N,N,N,N,42318, +N,N,N,N,42319,N,N,N,N,12143,N,N,N,N,N,N,N,N,N,N,12144,42320,N,N,N,N,42321, +42322,N,N,42323,N,N,N,N,N,N,42324,N,N,N,N,N,N,N,N,N,32378,42328,42329,N,N,N,N, +N,12145,N,N,N,42330,N,N,N,N,N,N,N,N,N,N,N,12146,N,N,N,42331,N,N,N,N,N,42332,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +42333,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42334,N,12147,N,N,N,N,N,12148,N,N,N,N,N,N, +N,N,N,12149,N,N,42335,N,N,N,12150,N,N,N,N,N,12151,N,N,N,N,N,N,42336,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,42337,N,12152,42338,42339,N,42340,N,N,N,N,12153,N,N,N,N, +N,N,N,N,N,42341,N,42342,N,42343,N,N,N,N,42344,N,N,N,N,42345,N,N,N,N,12154,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42346,N,42347,N,N,N,42348,N,N,N,N,42349, +N,N,N,N,N,N,N,N,42351,N,42350,N,N,N,N,42352,42353,N,N,N,N,N,N,N,42354,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,42355,N,12156,N,N,N,N,N,N,N,N,N,N,N,12157,N,N,N,N,N,N,N, +42357,N,N,N,N,N,N,42356,N,N,N,N,N,N,N,N,N,N,N,N,20309,N,N,N,N,N,N,N,N,N,N, +42358,N,N,N,N,N,42359,N,N,N,20310,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42360,N,N, +N,N,N,N,42361,N,N,N,N,N,N,N,N,N,N,N,N,42362,20311,N,42363,N,42364,N,N,42365,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,20312,N,N,43041,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,43042,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43044,N,N,N,N,N,N,N,N,N,N,N, +N,N,43046,N,N,N,N,N,N,N,43047,N,20313,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +20314,N,N,N,N,43050,N,N,N,N,N,N,N,N,N,N,N,43051,43053,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,20315,N,N,N,N,N,N,N,N,N,N,N,20316,N,N,N,N,20317,N,N,N,N,N,43054,N,20318,N, +N,N,N,43055,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,32379,N,N,N,43057,N,N,20320,43058,N,N,N,43059,43060,43061,N, +N,N,N,N,N,43062,N,N,N,N,N,N,N,N,N,20324,N,43065,N,N,N,N,N,N,N,N,N,N,N,43068,N, +43069,N,N,N,N,20325,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20326,43073,N,43074,20327,N, +N,43075,43076,N,N,20328,N,N,43078,N,N,N,N,N,N,N,43079,N,N,N,N,20329,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,43081,N,20330,N,N,N,N,20331,N,20332,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20333,43084,N,N,N,N,N,N,20336,N,N, +43085,N,N,N,N,N,N,N,N,N,N,N,N,43087,N,N,43088,N,N,N,43089,N,43090,20337,N,N,N, +43086,N,N,N,N,N,43091,N,N,N,N,N,N,N,43092,N,N,N,N,N,N,N,N,43093,N,N,N,20339, +20340,N,N,20342,N,N,N,N,N,N,N,N,20341,N,N,N,N,N,N,N,N,N,N,N,N,N,43095,N,N,N,N, +N,N,N,N,43096,N,N,20343,N,N,43098,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20344,N,N,N, +N,N,N,43101,N,N,N,N,N,N,N,N,N,43103,N,43104,N,N,43105,N,43106,N,N,N,N,N,N, +20345,N,N,N,20346,N,N,20347,N,N,N,N,N,N,N,N,43107,N,43108,N,43109,N,N,N,20348, +43111,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20349,N,N,N,N,N,43112,N,N,N,N,N,43113, +43114,N,N,N,N,N,N,N,43115,N,29736,N,43117,N,N,N,N,43118,43120,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,43122,N,29737,43123,N,N,29738,N,N,N,N,N,N,43125,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,43126,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43127,N,N,N,N,N,N,N,N,N,N, +43128,N,N,N,N,N,N,N,N,N,N,N,N,43130,N,29739,N,N,N,N,N,29740,N,N,N,N,N,N,N,N,N, +N,N,N,43132,43133,43134,44065,N,N,N,N,N,N,N,N,32380,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44067,N,N,N,N, +44068,N,44069,N,N,N,N,N,N,N,N,N,N,N,N,44070,N,N,N,N,29741,44071,N,N,N,N,N,N, +44072,N,N,N,N,29743,N,N,N,N,N,N,44073,N,N,N,N,N,N,44074,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29744,N,N,N,44076,29745,N,29746,N,N,N, +N,29747,44077,N,N,N,N,N,44078,N,N,N,N,N,N,N,N,N,N,N,N,N,44079,29748,44081,N,N, +N,N,29749,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29750,N,29751,N,N,N,N,N,N,29752,N,N, +29753,N,N,N,N,29754,N,44082,N,N,N,N,N,N,N,N,N,N,N,N,29755,N,N,N,29756,N,N,N,N, +N,N,N,N,N,N,44083,29757,N,N,29758,N,N,N,N,N,N,N,N,N,N,44084,N,N,N,N,N,N,N,N,N, +N,29759,44085,N,N,N,N,N,N,N,N,N,N,29760,N,N,N,N,N,44086,N,N,N,N,N,N,N,N,N,N,N, +N,29761,N,N,N,N,N,44087,N,44088,N,N,29762,N,N,N,N,N,N,N,29763,N,N,N,N,N,29764, +N,29765,44089,N,N,N,N,N,N,N,N,N,N,N,44090,N,N,44092,N,29766,N,44093,N,N,N,N,N, +N,44094,44095,44096,N,N,N,N,N,N,N,N,N,29767,N,N,29768,44097,N,N,N,N,N,N,29769, +N,N,N,N,44098,44099,N,N,N,44100,N,N,N,N,N,N,N,N,44101,29770,N,N,N,N,N,N,29771, +N,N,44103,29772,N,N,N,N,N,N,N,N,N,44104,N,44105,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +29773,N,29774,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29775,N,N,N,N,44107,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44108,N,N,N,N,N,N,N,N,N,N,44109,N,N,N,N,N,N,N,N,N,N,44110,N,N,N,N, +N,N,N,29777,29778,N,N,N,N,N,N,N,N,N,44111,N,N,N,N,N,N,N,44113,44114,N,N,N,N,N, +N,N,N,N,N,N,N,44115,N,N,N,N,N,N,N,N,N,44116,N,N,29779,N,N,N,N,N,N,N,N,29780, +29781,N,N,N,44117,N,44118,N,29782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44119,N,N,N, +44120,N,N,44121,N,N,29783,44122,N,44123,44124,N,N,N,N,N,44125,N,N,29784,N, +44126,N,N,N,N,N,N,N,N,N,N,N,N,29785,N,N,N,N,29786,N,N,N,N,N,N,29787,N,N,44127, +N,N,N,N,N,N,44129,N,N,N,N,44130,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,44131,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44132,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,29789,N,N,N,N,44134,44135,N,N,N,44136,44137,N,N,N,N,N, +N,N,N,N,N,N,N,44138,N,N,44139,N,N,N,N,44140,N,N,N,N,N,N,N,N,N,N,N,29792,N,N, +29791,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44142,N,N,N,N,N,N,N, +44143,N,44144,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44145,44147,N,N,N,N,N, +N,N,N,N,N,N,N,29794,44148,N,N,N,N,N,44149,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,29795,N,N,N,N,29796,N,N,44150,N,N,N,N,N,44151,N,N,N,N,44152,44153,N,N,N, +29797,N,N,N,29798,N,N,N,N,N,N,44154,N,N,44155,N,N,N,N,N,N,N,N,44157,N,29799,N, +N,N,44158,N,N,N,N,N,N,N,44156,N,N,N,N,N,N,N,N,N,29800,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,44321,N,N,N,N,N,N,N,N,N,N,N,N,44322,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44323, +29802,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,29803,44325,44326,N,N,N,N,N,N,29804,N,N,44327,N,N,44328,N,N,N,N,N,N,N,29805, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44331,N,N,44332,N,N,N,29806, +N,44333,44334,N,N,N,N,44335,N,29807,44336,N,N,N,N,N,N,N,N,N,44337,N,N,N,N,N,N, +N,N,N,N,44339,N,N,N,N,N,N,N,N,N,N,N,29808,N,N,N,N,N,N,44342,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,29809,N,N,N,N,N,N,N,44343,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44346,N,N, +N,N,44344,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,44347,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44349,44350,N,N,N,N,N,N, +44351,N,N,N,44352,N,N,N,N,29810,N,N,N,N,N,44353,44354,29811,N,N,N,N,44355,N,N, +29812,N,44348,44356,N,N,N,N,N,N,29813,N,N,N,29814,N,N,N,N,N,N,N,N,N,44357,N,N, +N,29815,N,N,44358,N,N,N,44359,N,N,N,N,N,44360,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29817,N,N,N,N,N,N,N,N,44361,44362,N,44363,N, +N,29818,N,N,N,N,N,N,N,N,N,N,N,N,29819,N,N,N,N,N,44364,N,N,N,N,N,29816,N,N,N, +44365,N,N,N,N,N,N,N,N,N,44366,N,N,N,N,N,N,N,N,N,44367,N,N,N,N,N,N,N,N,N,N,N, +44368,N,44369,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +29821,29822,N,N,N,N,29985,N,N,N,N,N,29986,44370,44371,N,29820,N,29987,N,N,N,N, +44372,N,44373,N,N,N,N,N,N,N,N,N,N,N,N,44375,44376,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,29988,N,N,N,29989,N,N,N,44377,44378,N,N,N,N,N,N,N,N,N,N,44380,N,N,N,N, +44381,N,44382,N,N,N,N,N,N,N,44384,N,N,N,29990,N,N,N,N,N,N,29991,N,N,N,N,N,N,N, +N,44385,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44386,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44387,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29993,N,N,N,44388,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,44389,N,N,N,N,N,N,44390,N,N,44391,44392,N,N,N,N,44393,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,29994,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44394,N,N, +44395,N,N,44396,N,N,N,N,N,N,44397,N,N,44398,N,N,N,N,N,N,44399,N,N,N,N,N,N,N,N, +N,N,44400,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44402,N,N, +N,N,N,N,44403,N,N,44404,29996,N,N,N,44405,N,N,N,44406,29997,N,N,N,N,N,N,N,N,N, +N,N,29998,N,N,N,N,N,N,N,N,29999,N,N,44407,30001,N,30002,N,N,N,N,N,44408,30003, +N,N,N,N,30004,30005,N,30006,N,N,N,N,N,N,30000,N,N,N,N,N,N,N,N,N,N,44409,N,N, +30008,N,N,N,30009,N,44411,N,N,44410,N,N,N,N,N,44414,N,30011,30012,44577,N,N,N, +N,N,30013,N,44578,N,30014,N,N,N,N,44581,44582,44583,44584,N,N,N,N,N,30015,N,N, +N,30016,30017,N,N,44585,N,N,N,N,44586,N,N,N,N,N,N,N,N,N,N,N,N,30018,N,N,44587, +N,44588,N,N,N,N,N,N,44589,N,N,N,N,N,N,30020,N,N,N,N,N,N,N,N,N,N,N,N,44591,N,N, +N,44592,30021,N,N,44593,N,N,N,N,N,30022,N,N,N,44595,N,N,N,N,N,N,30023,N,30024, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30026,N,N,N,N,N,N,N,N,N,N,N,N,30027,N,N,N, +44597,N,N,N,N,N,N,N,N,N,N,N,N,N,30028,30007,44599,N,N,N,44600,N,N,N,N,N,N,N,N, +N,N,N,N,44601,30029,N,N,N,N,N,44603,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,30031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30033,30034,N,N,N,44606, +44607,N,N,N,N,N,N,44608,N,N,N,N,N,N,N,N,44609,N,N,N,N,N,N,N,N,30032,N,N,N,N,N, +N,N,N,N,N,N,N,N,44613,N,44614,N,N,N,N,30035,N,N,N,N,N,30036,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,44616,30037,N,N,N,N,30038,N,N,30039,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44620,N,44621,N,N,N,N,N,N,N,N,30040,N,N,N,N,30042,N,N,44622,N,N,N, +N,44623,N,N,N,N,N,N,N,N,N,44624,N,N,N,N,30043,N,44625,N,44626,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,44627,N,N,N,N,N,N,44628,N,30041,N,N,30044,30045,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,44619,N,N,N,N,N,N,N,44632,N,N,N,N,30047,N,44633,N,N,N,N, +N,N,N,N,N,N,N,N,30048,44634,N,N,N,30049,N,44636,N,N,N,N,N,N,N,44637,N,N,44638, +N,N,N,N,N,44639,44640,N,N,N,44641,N,N,44642,N,N,N,N,N,30046,N,N,44643,N,44644, +N,N,N,30050,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44646,N,N,44647,N,N,N,30051,N,N, +30052,N,N,N,N,44648,N,44649,N,N,N,N,N,44650,N,N,N,N,N,N,N,N,N,N,N,N,N,44651,N, +N,N,N,N,44652,N,44654,44655,44656,N,44657,N,N,N,N,N,N,30054,N,30055,N,N,N,N, +44658,44659,N,N,N,N,N,N,30056,N,44660,N,N,N,N,N,N,44661,N,N,N,N,N,N,N,44666,N, +44667,N,N,30057,N,N,N,44668,N,N,44669,30058,N,N,N,N,N,44670,N,N,44833,N,N,N,N, +N,N,N,N,N,N,44834,44835,N,N,30059,N,N,N,44836,30060,N,N,30061,30062,N,N,N,N,N, +44837,N,N,N,44662,30063,44838,N,N,N,44839,N,N,30064,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30067,N,N,N,N,N, +44843,N,N,N,N,N,N,30068,N,N,N,44845,N,N,30065,N,N,N,N,N,N,N,N,N,N,N,N,N,30069, +N,N,N,N,N,N,N,N,N,N,N,30070,30071,N,N,N,30072,44846,N,N,44847,N,N,N,N,N,44848, +N,N,N,N,N,N,N,44849,N,N,N,N,44850,30073,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44851,N,N,N,44853,N,44854,N,N,N,N,N,N,N,N,N,N,N,N,30075,44855,N,N,N,N,N,N, +30076,N,N,44856,N,N,N,N,N,N,44857,N,N,44858,N,44859,N,N,N,44860,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,30077,N,44861,N,N,N,N,44862,N,N,N,N,N,N,N,N,N,N,N,30242,44868,N, +N,N,N,N,30243,30244,N,N,N,44869,44870,N,N,N,44871,44873,30245,30246,N,N,N,N,N, +N,N,44874,30247,N,44875,N,N,N,30248,N,N,N,N,44876,N,N,44877,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,44865,N,44879,44880,44881,N,N,N,N,N,N,30250,N,N,30251,44882, +N,N,N,N,N,30252,44883,N,N,44884,N,N,N,N,44886,N,30253,N,44887,N,N,N,30254,N,N, +N,N,30255,N,N,N,N,N,N,N,N,44888,N,N,N,N,N,N,30256,N,N,N,N,N,N,N,30257,N,N,N,N, +N,N,44885,N,N,N,44890,N,N,N,N,44891,N,N,N,N,N,30259,N,44892,N,N,N,N,N,44894,N, +N,30260,N,N,N,N,N,N,N,N,30261,30262,44895,N,44896,N,N,N,30263,N,N,N,N,N,44898, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44899,N,N,N,N,N,N,N,N,44900,N,N,N,N,N,N,N,N, +N,44902,N,N,N,44901,N,N,N,N,N,N,N,44903,44904,N,N,N,N,N,N,30264,N,N,30265,N,N, +N,N,44907,N,N,N,N,44908,44909,44910,N,N,N,N,N,N,N,N,N,44911,44913,N,N,N,44914, +44915,44916,N,N,N,N,N,44918,N,N,N,30268,N,N,30269,N,N,N,N,N,N,N,N,N,N,N,N,N, +30270,N,N,44920,N,N,N,N,N,30271,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30272,N,N,N, +44921,N,N,N,N,N,N,N,N,N,N,N,30273,N,44922,N,N,N,N,N,N,N,30274,N,N,N,N,30275,N, +30276,N,N,N,N,44923,N,N,N,N,N,N,N,N,44924,N,30277,N,N,44925,N,N,N,N,N,N,44926, +30278,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60961,N,N,N,N,N,N,N,N,N, +N,N,N,N,30279,N,N,N,30280,60962,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60964,60965,N,N,N, +N,N,N,N,N,60966,60967,60968,N,N,N,N,N,30282,N,N,N,N,N,N,30283,30284,N,N,60969, +N,N,N,N,N,N,N,N,N,N,N,60970,60971,N,N,N,N,N,N,60972,N,N,60973,N,N,N,N,N,N,N,N, +N,N,N,N,N,30285,60974,N,N,30286,N,N,N,N,60975,N,N,N,60976,N,30287,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30288,N,60977,60978,N, +N,N,60979,N,N,N,N,60981,N,N,N,N,N,N,N,N,N,N,N,N,N,60982,N,N,N,N,N,N,N,N,N,N,N, +30289,N,60983,30290,N,N,N,N,N,N,N,N,N,N,61007,N,N,N,N,N,60984,N,N,N,N,N,N, +30292,N,30293,N,N,N,N,N,N,N,N,N,N,N,N,N,60985,30294,30295,N,N,60986,N,N,N,N,N, +N,N,N,N,N,60988,60989,N,60990,30296,N,N,N,30297,N,N,N,N,N,N,N,N,N,N,N,N,N, +30291,N,N,60991,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60992,N,N,N,30299,N,N, +N,N,N,N,N,N,N,60993,N,N,N,30300,N,60995,N,N,N,60996,N,60997,N,N,N,30301,N,N,N, +N,N,N,N,N,60998,N,30302,60999,61000,30303,N,N,N,N,N,N,N,N,N,N,N,N,30298,61002, +N,N,N,30305,N,N,N,N,N,61003,N,N,N,30306,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,61004,N,61005,61006,N,N,N,N,N,N,30307,61008,N,30308,N,N,61029,N,N,N,N, +30309,N,N,61009,N,N,30310,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30311,N,N,61010,N,N,61011,N,61012,N,N,N,N,30312,N,N,N,N,N,N,N,N,N,N,61013,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,61014,61015,30314,N,N,N,N,30315,N,30316,61016,N,N, +61017,N,N,N,61018,N,N,30317,N,N,N,61019,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30318,61025,30319,N,61026,N,N,N,N,N,61027,N,N,N,N,N,N,N,N,N,N,30320,N,N,61028, +N,30321,N,N,N,61030,N,N,N,N,N,61031,61032,61033,N,N,N,N,N,30322,N,N,N,30323, +30324,N,30325,N,61034,N,N,N,N,N,N,N,N,N,61035,N,N,N,N,N,N,N,N,N,N,N,N,61036,N, +N,N,N,N,30326,61021,N,N,N,N,N,N,61038,N,N,N,61039,N,N,N,N,61040,N,N,N,N,N,N,N, +N,N,N,61042,N,30328,N,61037,N,N,N,N,N,61043,N,N,N,N,N,N,N,30329,N,N,N,61044, +61045,N,61046,61047,N,N,61048,N,61049,N,61050,61051,N,N,61052,N,N,N,N,30330,N, +30331,N,N,N,N,61053,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61217,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,61218,N,N,N,30332,N,N,N,N,N,30333,N,N,61219,N,N,N,N,N,N,N,N,N,N,61220,N, +30334,N,61221,N,N,N,30497,N,N,61222,N,N,N,30498,N,N,N,N,N,N,N,N,N,N,61223,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61225,N,N,N,N,N,N,N,N,N,N,N,N,N,61226,N,61227, +61228,N,61229,N,N,N,30499,N,N,N,N,N,N,N,61230,N,30500,N,N,N,N,N,N,N,N,N,N, +61231,N,N,N,N,30502,N,N,N,N,30503,N,N,N,30504,N,61224,61232,N,N,N,N,N,61233,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30505,61235,N,N,N,N,61236,N,30506,61237, +N,N,N,30507,N,61238,30508,30509,N,N,N,N,N,61239,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,61241,30510,N,N,N,N,N,N,N,N,N,30511,N,N,N,30512,30513,N,N,61242,N,N, +N,30514,N,61243,N,61240,N,N,N,N,N,N,61245,30515,N,N,N,N,61246,N,30516,N,N,N,N, +N,N,N,61247,N,N,N,N,N,61249,30517,N,N,N,N,N,30518,N,61244,N,N,N,N,N,N,N,N, +30519,61250,61251,30520,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61252,N,N,N,61253,N,N,N, +N,N,N,N,N,N,N,61254,N,N,N,N,N,N,30522,N,N,N,N,30523,N,N,N,30521,N,N,61256, +61257,N,N,N,N,30524,30525,61258,N,N,61259,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,61260,N,N,N,N,30526,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61262,61263,N, +61264,N,N,N,N,N,N,61265,N,N,N,61266,N,N,30527,61267,N,N,30530,N,N,N,N,N,61269, +N,N,N,N,N,N,N,N,30528,30529,N,N,N,N,N,30531,61270,N,N,N,61271,N,N,61272,N, +61273,N,N,N,N,N,N,30532,61274,N,N,N,N,N,N,N,61275,N,N,61276,N,N,N,30533,61277, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61278,N,61279,N,N,N,N,N,N,N,61282,N,N,N,N,30534,N, +N,N,N,N,N,30535,N,N,N,N,N,61283,N,N,N,N,N,30536,N,N,N,61280,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,61286,N,N,N,N,N,N,61287,N,61288,30537,N,N,N,30538,N,N,N,61289,N,N,N, +N,N,N,N,30539,N,N,N,N,N,N,N,61285,61290,61291,N,61292,61293,61294,N,N,N,61295, +N,N,30540,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30542,N,30543,N,N,N,N,N,N,N,N,N,N,30541, +N,N,30544,61297,30545,61298,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30546, +30547,N,N,61300,N,N,N,N,N,61299,30548,30550,61301,N,N,N,N,N,N,N,N,30551,N, +61302,N,30552,N,N,N,N,N,N,N,30553,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,61305,N,N,N,N,30555,N,30556,N,N,N,N,N,N,N,N,N,N,30557,N,N,N,61304,N,N,N,N, +61306,N,N,N,N,61307,N,61308,N,N,N,N,N,N,N,N,N,N,N,61309,61310,N,N,N,61473,N,N, +N,N,N,N,30559,N,N,N,N,N,N,30558,N,N,30560,N,N,N,N,N,N,61475,N,N,N,N,N,N,N, +61476,N,N,N,N,N,61477,N,N,61478,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,30561,30562,N,N,N,N,N,N,61479,N,N,N,N,N,N,N,N,N,N,N,N,N, +30563,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61482,N,N,N,N,N,N,N,N,61483,N, +N,N,61484,61485,N,N,N,N,N,N,N,N,61487,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61488,N, +30564,30565,61489,N,N,N,N,N,N,N,N,N,N,N,61490,N,N,N,N,N,N,N,N,N,N,61492,61493, +N,N,N,N,N,N,N,N,61494,N,N,N,N,N,N,61495,N,N,N,N,N,N,N,N,N,N,N,N,N,30567,61496, +N,N,N,N,N,N,N,N,N,N,N,N,30568,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61498,61499,N, +61500,61501,N,N,N,N,N,N,N,N,N,N,N,N,30569,N,30570,61502,N,N,N,N,N,N,N,N,N,N, +61504,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,61507,N,N,N,N,N,N,61508,30571,61509,N,N,N,N,N,N,N,N,N,N,61510,N,N,N,N,N, +61511,61512,N,N,N,N,N,N,N,N,N,N,N,N,N,30573,30574,N,N,N,61515,N,N,N,N,61516,N, +61517,N,N,N,N,N,61514,N,N,N,61518,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30576,N, +61519,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30577,N,N,N,N,61521,61522,N,61524, +61525,N,61526,N,N,N,N,N,61527,N,N,N,N,30578,N,N,N,N,61528,N,N,N,61529,N,N,N,N, +61530,N,N,N,N,N,N,N,N,N,61531,30579,N,N,61532,N,N,N,61533,N,61534,30580,30581, +N,30582,N,N,61535,30583,N,61536,N,N,30584,N,N,N,N,N,N,N,N,N,61537,N,61538,N, +61539,N,N,61540,N,N,61541,N,N,N,N,N,61542,N,N,N,30585,N,61543,N,N,N,30586,N,N, +N,N,N,N,30587,N,N,30588,N,N,N,N,N,N,N,61544,N,30589,N,N,N,61545,N,30590,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,61546,61548,61549,N,N,N,N,N,30753,N,N,30754,N,N,N,N,N, +N,N,N,61547,N,N,N,N,N,N,30755,30756,N,N,N,N,N,N,N,N,61550,N,30758,N,30759,N, +30760,30761,30762,N,30763,30764,30765,61551,N,N,N,N,N,N,N,61552,N,N,N,N,N,N, +61554,N,N,61555,30766,N,30767,30768,N,N,N,30769,N,61556,N,N,N,N,61557,61553,N, +N,N,30770,N,N,N,N,N,61558,N,N,N,N,30771,N,N,N,N,N,N,N,N,30772,N,30773,N,N,N, +61559,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61560,N,N,N,61561,30774,30775,61562,30776, +N,N,N,N,N,N,30781,N,61564,N,N,N,N,61565,30777,61566,N,N,30778,N,N,30779,61729, +61730,N,30780,N,61731,30782,N,30783,30784,61732,61733,N,N,N,N,N,N,N,N,N,30785, +N,N,N,61734,61736,61735,N,N,N,30786,N,N,N,N,N,N,N,N,30787,30788,N,N,N,N,N,N,N, +N,N,N,N,N,61737,N,61738,N,30789,N,N,N,61739,N,N,N,N,N,N,N,N,N,N,N,N,61741,N,N, +N,61740,N,N,N,N,N,N,N,N,N,N,61743,N,N,N,N,30790,30791,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,30792,N,N,N,N,N,N,N,N,61745,N,N,N,61746,N,N,N,N,N,61747,N,N, +N,N,30793,N,N,N,N,N,N,N,N,N,N,N,N,N,61750,61751,N,61752,N,N,N,N,N,N,N,61753,N, +N,N,N,N,61754,N,61755,N,61756,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,61757,N,N,30794,N,61759,61758,N,N,N,N,N,N,30795,61760,N,N,61761,61762,N,N, +61763,N,N,N,N,N,N,N,N,N,N,61765,N,N,N,N,N,30796,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61767,N,N,N,N,N,N,N,N,N,N,N,N,N,61769,N,N,N,N,N,N,61770,N,N,N,N,N,N,N,61771, +61772,N,N,N,N,N,61773,N,N,N,N,N,N,N,30798,61774,N,N,N,61775,N,N,N,N,N,N,N,N,N, +61776,N,61777,61778,N,N,N,30799,N,N,61779,N,N,N,N,61780,N,61781,N,N,61782,N,N, +N,N,N,N,N,61783,30800,N,30801,61784,N,N,N,61786,30802,N,N,N,N,N,N,61787,N,N,N, +61790,N,30803,30804,N,61785,30805,N,61791,61792,N,30806,N,N,N,N,N,N,61794, +32381,N,61795,N,N,N,N,30807,N,N,N,N,N,61797,N,30808,N,N,N,N,N,N,61796,N,N,N,N, +61800,N,30809,N,N,N,N,N,61802,N,30810,N,N,N,N,N,N,N,N,N,61803,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,30811,30812,N,N,N,N,N,N,N,30813,61805,30814,N,30815,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,30816,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61806,N,N,N,N,N, +30817,61807,30818,30819,N,61809,61808,N,N,N,N,30820,61810,61811,N,30821,N,N,N, +N,61812,N,N,N,N,N,N,30822,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30823,N,N,N,61814,N,N, +30824,N,30825,N,N,N,N,N,30826,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30827,N,61816, +N,N,N,61817,N,N,N,N,30828,N,N,N,N,N,N,N,N,N,N,30829,30830,N,N,N,N,N,N,N,N,N,N, +N,N,61819,N,30831,61820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61821,N,N,N,N,N,N, +30832,61822,30833,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30834,N,N,N,N,N,N,30835,30836, +N,N,N,N,N,N,N,N,N,61989,N,N,N,30837,N,N,30838,61990,N,30839,N,N,N,N,N,N,N, +61991,N,N,N,N,N,N,N,61993,N,N,N,N,N,N,N,30840,N,61994,61995,N,N,30841,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30842,N,N,N,N,N,61998,N,N,N,N,61999,N,N,62000,N, +62001,N,N,N,N,62002,30843,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62003,62004,30844,N,N,N, +62005,N,62006,N,N,N,62007,N,62008,N,N,N,62010,N,N,N,62011,N,N,N,N,N,N,62012, +62014,62015,N,N,62016,N,N,N,62017,N,N,N,N,N,N,N,N,N,N,N,62018,N,N,N,N,N,N,N, +62019,N,N,N,N,N,N,N,N,N,N,62020,30845,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,31009,N,N,N,62021,N,N,N,N,N,N,31010,31011,N,31012,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,62022,N,N,N,31013,N,62023,N,N,N,31014,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,62025,N,N,N,N,N,N,N,N,N,62026,N,N,N,N,N,N,N,N,62028, +62029,62030,N,N,N,N,62027,N,N,N,N,N,N,N,N,31018,N,N,31016,N,N,N,N,N,N,N,N,N,N, +62031,N,N,N,N,N,N,N,N,N,N,N,N,62032,N,N,N,62033,N,62034,N,N,N,N,N,N,62035,N,N, +N,N,N,N,N,N,N,N,62036,62037,N,N,31019,N,62038,N,N,N,N,N,N,N,N,N,N,N,31020,N,N, +N,N,31022,N,62039,62040,62041,N,N,62042,31021,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62044,N,N,N,N,N,N,N,N,N,N,62045,31023,N,N,N,N,N,N,N,N,62047,N,N,N,N,N,N,N,N, +31024,N,62046,31025,N,N,31026,N,N,N,N,N,N,62048,N,N,N,N,N,N,N,N,N,31029,31030, +N,N,N,62049,N,N,N,N,N,N,N,N,N,N,N,N,N,62050,N,N,62051,31034,N,N,N,N,N,N,N,N,N, +N,62053,N,N,N,N,N,N,N,N,N,N,62054,N,N,N,N,N,N,31038,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,62055,62056,62057,N,31042,N,N,62058,N,N,N,N,N,62059, +N,N,N,N,N,N,N,62060,N,N,N,N,N,N,N,31043,N,N,62061,N,N,N,31044,N,N,62062,N,N,N, +N,N,N,62063,N,N,N,N,62064,31045,N,31046,N,62065,62066,N,N,N,N,N,N,31048,N, +62067,N,N,N,N,N,N,N,31049,N,N,N,N,N,N,N,N,N,N,N,N,31050,N,31051,31052,N,N,N,N, +N,N,62072,N,N,N,N,N,N,62073,N,N,N,62074,N,N,N,N,N,62075,N,N,62076,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,62078,N,N,N,N,N,N,N,N,N,N,62241,31054,N,N,N,N,N,N,N,N,N,N,N,N, +N,62242,N,N,N,N,62243,N,N,N,N,N,N,N,N,N,62244,N,N,62245,N,N,62246,31055,N, +62247,62248,N,N,N,N,N,N,62249,N,N,62250,N,N,31056,N,N,N,N,N,N,N,62251,N,N, +62252,N,N,N,N,N,N,N,N,N,62253,N,N,31058,N,N,N,N,62254,N,N,N,N,N,62255,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,31059,N,N,62256,N,N,N,N,N,N,N,N,62257,N,N,N,N,N,N,31061, +N,N,N,N,N,62260,N,31062,62261,N,62262,N,N,N,N,N,N,N,N,N,N,N,N,N,62264,N,31063, +N,N,62265,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62266,62267,N,N,31064,N,N, +N,N,N,N,N,N,62268,N,N,N,N,N,N,N,N,31065,62271,N,N,N,N,N,N,N,N,N,N,31066,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62274,N,N,62275,N,N,31067,62276,62277,N, +62278,N,N,N,N,N,N,N,N,N,31068,N,62273,N,N,N,62282,N,N,N,N,N,31069,N,N,N,N,N,N, +31070,N,N,N,N,N,N,62284,N,N,N,N,N,N,N,N,N,N,31071,N,N,N,62286,N,62287,N,N, +62288,N,N,N,31072,N,31073,N,N,31074,62289,N,N,N,N,N,62285,N,N,N,N,N,62281,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,62292,62293,N,N,N,N,N,N,N,N,N,62294,N,N,31075,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,62296,N,N,N,N,N,62297,N,N,N,N,N,N,62298,N,N,N,N,N, +N,N,N,62299,N,N,N,N,62300,N,N,N,N,N,N,N,N,N,62303,N,62304,31077,N,31078,62305, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62306,N,N,N,N,N,62307,31079,N,62308,N,N,N,N,N,N, +N,62309,N,N,62310,62311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31081,N,31082,N,N,N,N,N, +62312,N,N,N,N,N,N,N,N,N,N,31080,N,31083,N,N,31084,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62313,N,N,N,N,62314,N,N,N,N,N,N,62315,N,N,N,N,N,62316,N,31087,N,N,N,N,62317,N, +N,62318,N,N,N,N,N,N,N,62319,N,N,N,31088,62320,62321,62322,N,N,N,N,N,N,N,N, +31089,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31090,N,N,N,N,31091,N,N,N,N,N, +N,N,N,N,N,N,31092,N,N,N,N,N,62326,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62328,62329,N, +N,N,N,31093,N,N,62330,N,N,N,N,62332,N,N,N,62334,N,N,N,N,62497,N,N,N,N,N,N,N, +31094,N,62499,N,31095,N,N,N,31096,N,N,N,N,N,N,N,N,62501,N,N,N,N,62502,N,N,N,N, +N,N,N,N,N,62504,62505,N,N,N,31097,31098,62506,N,N,N,N,N,N,N,N,62508,31099,N,N, +N,N,N,N,N,N,N,31100,62509,N,N,N,N,31101,N,N,N,N,N,N,N,N,N,N,N,N,N,31102,N,N,N, +N,N,N,N,N,N,N,N,62512,62513,N,62514,31265,N,N,N,N,N,62515,31266,N,N,N,N,N,N,N, +N,N,N,31267,N,N,N,N,N,62519,62520,N,31268,N,N,N,N,N,N,N,N,N,N,N,N,N,62521,N,N, +N,N,N,62522,N,N,N,N,N,N,N,N,N,31269,N,N,N,N,62524,N,N,N,31270,N,N,62526,N, +62527,N,N,31271,62528,N,N,N,N,N,N,N,N,N,N,62529,N,N,N,N,N,62531,N,N,31272,N,N, +N,N,N,31273,62532,N,N,62533,N,N,N,N,N,N,N,N,N,N,N,62534,62535,N,N,N,N,N,N,N,N, +62536,N,31274,N,N,N,N,N,N,N,N,N,31275,N,N,N,N,N,N,N,N,N,31276,62537,N,62538,N, +N,N,N,N,N,N,N,N,31277,N,N,62539,N,N,N,N,N,N,N,N,N,N,62540,N,N,N,N,N,N,N,62541, +31280,N,N,N,N,N,N,N,62545,31281,N,N,N,31282,N,62546,N,N,N,N,N,62547,N,N,62548, +N,N,N,N,N,N,62549,31279,N,N,N,62550,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,62551,N,31284,N,N,N,N,N,N,N,N,N,N,31285,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +31286,N,N,N,N,N,N,N,N,N,32382,N,N,N,N,N,N,N,62552,N,62553,N,N,N,N,N,N,N,N, +62554,N,N,N,N,N,N,N,62555,62556,N,N,31287,N,N,31288,N,N,N,62558,N,N,N,N,N,N, +62559,N,62560,62563,62562,N,62564,N,N,N,N,62565,62566,N,N,31289,N,N,N,N,N,N,N, +62567,N,N,62570,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62572,N,62573,62574,N,N,N,N,N,N,N, +N,62575,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62576,62577,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,62579,31291,N,N,N,N,62582,31292,N,N,N,N,62583,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,62584,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31293,N,N,N,62586,N,N,N,N,N,N,N, +N,N,N,31294,62587,N,N,N,N,N,N,N,N,N,N,N,31295,N,N,N,31296,N,N,N,62588,N,62589, +N,N,N,N,N,N,31297,N,31298,62590,N,N,62753,N,N,N,N,N,N,N,31299,62754,N,N,N,N,N, +62756,N,62755,N,N,N,62757,N,N,62758,N,N,31301,N,62759,N,N,N,N,N,N,N,N,N,N,N,N, +N,62760,N,31302,N,N,N,N,N,62761,N,N,N,62762,N,N,N,N,31303,N,31304,N,N,N,N, +31305,N,N,N,N,N,N,62763,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,62764,N,N,N,N,N,N,N,N,N,N,62765,N,N,N,62766,N,N,N,N,N,62767,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62768,N,N,62769,N,N,N,N, +N,N,N,62770,N,N,62771,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62772,N,N,N,N,N,N,N,N,N, +N,N,N,62774,N,N,N,N,31306,N,N,N,N,N,N,N,N,N,N,62775,N,31307,62776,N,N,N,N,N,N, +N,31308,N,N,N,N,N,62777,N,N,N,N,N,N,N,N,N,N,N,N,31309,N,62780,N,N,N,N,N,62781, +62779,N,N,N,N,N,N,N,N,62784,N,31310,N,N,N,N,N,62785,N,N,N,N,N,62787,N,N,62788, +N,N,N,N,62789,N,N,N,N,N,N,N,N,62783,N,N,N,N,N,N,N,62791,N,N,N,N,N,N,N,N,N,N,N, +N,31311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31312,N,N,N,N,N,N,31313, +31314,62793,N,N,N,31315,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62795,N,N,62797, +62798,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62800,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,62801,N,N,N,N,N,N,N,N,31316,N,N,N,N,N,62802,N,62803,N,N,N, +N,N,N,31317,N,N,N,N,31318,N,N,N,N,N,N,62804,31319,N,N,N,62805,N,N,N,N,N,N,N,N, +62807,N,N,N,N,N,N,N,62809,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62811,N,62812,62814, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62816,N,N,N,N,N,N,N,62817,62818,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,62820,N,62821,N,N,N,N,N,N,N,62822,N,N,N,N,N,N,N,N, +62825,62823,N,N,62824,N,62827,N,N,N,62829,N,N,N,N,N,N,N,62831,N,N,N,N,62833,N, +N,N,31323,N,N,62834,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31324,N,N,N,N,62838,N,N,N, +62840,N,62841,N,N,N,62842,N,N,N,N,N,N,62843,N,N,N,31326,N,N,N,N,62844,N,N,N,N, +N,N,N,N,N,N,N,N,N,31327,N,31328,31329,N,N,62845,62846,31330,N,N,N,N,31331,N,N, +N,63009,N,63010,N,N,31332,N,N,63011,N,63012,N,31333,31334,N,N,N,N,N,N,31335,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,31336,N,N,N,N,N,N,N,N,N,N,N,N,63013,N,N,N,N,N,63014, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,63015,N,N,N,N,N,31337,31338,31339,31340,N,N,N,N,N, +63016,63017,N,N,N,63018,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63020,N,63021,N,N,N,N, +31342,N,N,N,N,N,N,N,N,N,N,31343,N,N,63022,N,N,N,N,N,N,N,N,N,31344,N,63023,N,N, +N,N,N,N,31345,63024,N,N,31346,N,N,N,N,N,N,N,N,N,31347,N,N,63019,31348,N,63025, +N,N,N,N,N,N,N,N,N,N,31341,44618,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,31349,N,63027,N,N,N,N,N,N,31350,N,N,N,N,N,N,63030,N,N,N,N,31351,N,63031, +63032,N,N,31352,N,N,63033,N,63034,N,N,N,N,N,N,N,N,N,31353,N,31354,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31355,31356,N,N,N,N,N,N,31357,N,63035,N,N,N,N,N, +31358,63036,31521,N,N,63037,N,N,N,N,N,N,N,N,63038,N,N,N,31522,N,N,N,63039,N,N, +N,N,31523,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63040,31524,N,N,N,N,31525,N,N,N,31526,N, +N,N,N,63041,N,63042,N,N,N,63043,N,63045,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,63046,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31528,N,63047,N, +N,N,N,63048,N,63049,63050,N,N,N,N,N,N,63051,63052,N,63053,N,N,31529,N,N,N,N,N, +63055,N,N,N,N,N,N,N,N,N,N,31530,N,N,31531,N,N,63056,N,63057,N,N,N,63058,N,N,N, +N,63059,N,N,N,31532,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63062,N,N,N,N,N,N,31533, +N,N,N,N,N,N,N,63063,N,N,N,N,N,N,N,N,31534,N,N,N,N,31535,N,N,N,N,N,31536,N,N,N, +63064,N,31537,N,31538,N,N,N,N,N,N,N,N,N,N,N,63066,63067,N,N,N,63068,N,N,N,N,N, +N,N,N,63061,N,N,N,N,N,N,N,N,N,N,63070,N,N,63071,N,N,N,N,63072,63073,63074,N,N, +N,N,N,N,N,N,63075,N,N,63076,63077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63078,N,N,31541, +N,N,N,N,31542,63079,63080,N,N,N,N,N,63081,N,N,N,31543,N,N,31540,N,63082,N,N,N, +N,N,N,N,N,N,63087,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63083,N,63088,N,63089,N,N,N, +N,N,31544,N,N,N,N,63090,N,N,63091,63092,N,31545,N,N,N,N,N,N,N,N,N,N,63084,N,N, +N,N,N,N,N,N,N,N,31548,63094,N,63095,N,63096,N,63097,N,N,N,N,63098,N,N,N,N,N, +31549,N,N,31550,N,N,N,63099,N,N,N,N,N,N,N,N,N,63100,N,63101,N,N,31551,N,N,N,N, +N,N,N,N,N,N,31547,N,N,31552,N,N,N,N,N,N,63267,N,N,N,N,63268,N,N,N,N,N,N,N,N,N, +N,63269,N,N,63270,31553,N,N,31554,N,N,N,N,N,N,N,N,N,63271,63272,N,N,N,N,N, +63273,N,63274,N,N,N,N,63275,N,N,N,N,N,N,31555,N,N,N,N,N,N,N,N,63276,N,N,N,N,N, +N,N,N,31557,63277,N,N,N,31558,31559,N,N,N,N,N,N,N,N,N,N,31560,63278,31556,N,N, +N,N,N,31562,N,N,N,N,N,63279,N,N,63280,N,N,63281,N,N,63282,N,31563,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,31564,63284,N,N,63285,N,N,N,63287,12136,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,63289,N,N,63290,31565,N,N,N,31566,N,N,N,N,N,N,31568,N,N,N,N,N,N,N, +N,N,31570,N,N,63291,N,N,N,N,N,31571,N,63292,N,N,63293,N,N,N,N,N,N,N,N,N,N,N,N, +63294,N,63295,N,N,N,63296,N,N,N,63297,N,N,N,N,N,N,31572,N,N,N,63298,63299,N,N, +N,N,N,N,N,N,N,N,63300,N,N,N,N,N,N,N,N,63302,N,63303,N,N,N,N,31573,N,N,N,N,N,N, +N,N,63304,N,63305,N,N,N,N,N,N,N,N,N,N,N,N,N,63306,N,N,N,63307,N,63308,N,N,N,N, +N,N,N,N,N,N,N,63309,N,N,63310,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31574,N, +31575,31576,63312,N,63313,N,N,N,31577,N,N,63314,N,63315,N,N,63316,N,N,N,N,N, +63317,N,N,N,N,N,63318,N,63319,N,63320,N,N,N,N,N,N,N,N,N,N,N,N,N,63321,N,N,N,N, +N,N,N,N,63322,N,N,N,63323,N,63324,N,N,63325,N,N,N,N,N,N,N,N,N,N,N,N,N,63326,N, +N,N,N,N,N,63327,N,N,N,N,N,N,N,N,N,N,N,63328,63329,N,N,N,N,N,N,N,N,N,N,N,31578, +63330,N,N,N,N,N,N,N,N,N,63331,N,N,N,N,N,N,N,N,N,N,31579,31580,63335,N,63336,N, +N,N,N,N,N,N,63337,N,N,N,N,N,N,N,N,N,N,N,N,63338,N,N,N,N,N,N,63334,N,N,N,N, +31581,31582,N,N,N,N,N,N,N,31583,N,N,N,N,N,N,N,N,63341,N,N,63343,N,N,N,N,N,N,N, +N,N,N,N,N,63344,N,N,N,N,N,N,N,31585,N,N,N,N,N,N,N,N,63346,N,N,N,63348,N,63349, +63350,N,N,N,63351,63352,31586,63353,N,N,N,N,N,N,N,63345,63354,N,63355,N,N, +31587,N,N,N,31588,63356,N,N,N,N,31589,N,N,63357,31590,N,N,N,N,N,N,N,N,N,N, +31591,N,N,N,N,N,N,N,N,63358,N,N,N,N,N,63521,N,N,N,63522,N,N,N,N,N,N,N,N,N, +63523,N,N,N,N,N,N,N,N,N,N,N,N,N,63525,N,N,N,N,N,N,N,N,N,N,N,N,N,63526,N,N,N,N, +N,N,63527,N,N,N,N,63528,N,N,N,N,63531,N,N,N,N,N,63533,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31592,N,N,N,N,N,N,N, +63534,N,N,N,N,N,N,N,N,N,31593,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63535,63536, +63537,N,63538,N,N,N,N,N,N,N,N,N,31594,N,N,N,31595,N,N,63541,63539,63542,N,N,N, +N,N,N,N,63543,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63544,63545,N,N,N,31597, +63547,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31600,31601,31602,N,31598,N, +N,N,N,N,N,N,N,N,N,31603,N,N,N,N,N,N,N,N,31604,N,31605,N,N,N,N,63549,N,31606,N, +N,N,N,N,N,31607,N,63551,N,N,63552,N,N,N,63553,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,63556,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,63557,N,N,N,N,N,N,N,N,63558,N,N,N,N,N,N,63559,N,N,N,31608,N,N,N,N,N,N,N,N,N, +N,63560,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63561,N,N,N,N,N,N,63562,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31610,N,63563,N,63564,N,N,N,N,N,N,N, +N,N,N,N,N,31611,N,N,N,N,N,63565,N,N,N,N,N,63567,N,63568,N,N,31612,N,N,N,N,N,N, +63569,N,63570,63572,31613,N,63573,31614,N,N,N,N,N,N,N,N,N,N,N,63575,31777,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63576,N,31778,N,N,N,N,N,N,63577,N,N,N,N,N,N, +63578,N,31779,N,N,N,N,N,63579,31780,N,N,N,N,N,N,N,N,N,63580,N,N,N,N,31781,N,N, +N,31782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31783,N,N,N,31784,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63582,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,31785,N,N,N,N,N,N,63581,N,N,N,N,N,N,N,N,63583,N,N,N,N,N,N,63584,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,31786,N,N,N,N,N,N,63585,N,N,N,N,N,N,N,31787,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,31788,N,31789,N,N,N,N,N,63586,63589,N,N,N,N,63588, +N,N,63590,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63591,N,N,63592,N,N,N,N,N,N,N,N,N,N,N,N, +N,63593,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63594,N,N,31793,N,N,N,N,N,N, +N,N,N,N,63596,N,N,31794,N,N,N,N,31795,N,N,N,N,63597,N,N,N,N,N,N,N,N,N,N,31796, +N,N,N,N,N,N,N,N,N,N,N,N,63598,N,N,N,N,N,N,N,N,63599,N,63600,N,N,N,N,N,N,N,N,N, +63601,N,N,N,N,N,N,N,N,63602,63603,N,N,N,N,N,N,63604,31797,63605,63606,N,N,N, +63608,N,N,N,N,N,N,N,63611,N,63612,N,31798,N,N,N,N,N,63613,N,N,N,N,63614,N,N, +63777,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31799,63778,N,N,N,63779,N,N,N,N,N,63780, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63783,63782,N,N,N, +N,N,63784,N,63786,N,N,N,N,N,N,N,N,63787,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63789,63788,N,N, +63790,N,N,N,N,N,N,N,31801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63792,63793,N,N,31802,N, +N,N,31803,N,N,N,N,N,31804,63795,N,N,N,N,63796,N,N,N,31806,N,N,N,N,N,N,N,N, +31807,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,63797,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63798,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,63799,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63800,N,N,N,N,N,N, +N,N,31808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63802,N,63803,N,N,N,N,N, +31809,N,N,31810,N,N,N,N,N,31811,N,63804,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +63805,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63808,63809,N,N,N,N,N,63806,N,N,N,N,N,N, +N,63811,N,63812,N,N,N,N,N,N,N,N,N,31812,63813,63814,31813,N,N,N,63815,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,63818,N,N,63819,N,N,N,31814,N,N,N,N,N,N,N,N,N,N,N,N,N, +63820,N,N,N,N,N,N,N,N,63821,N,N,N,N,N,N,N,N,N,N,N,N,N,63822,N,N,N,N,N,N,N,N,N, +63823,63824,N,63825,31815,N,N,N,N,N,N,N,N,N,N,31816,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63826,N,N,N,N,N,63827,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,63828,N,N,N,N,63829,N,63830,63831,N,N,N,N,63832,N,N,N,N,31818,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,63834,N,N,63835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63837,31820,63839,N,N,N,N,N,N,N,63840,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,63841,N,N,N,N,N,N,31821,N,N,N,N,N,N,N,N,N,N,N,N,63842,N, +31822,N,N,N,N,N,N,N,N,31823,N,N,N,N,N,N,N,N,N,63843,N,N,N,N,N,N,N,N,N,63844,N, +N,N,N,N,N,N,N,N,31824,N,N,N,63845,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,63847,N,31826,N,N,N,N,N,N,N,N,N,N,N,N,N,63848, +31827,63850,N,N,N,N,N,N,N,N,N,N,63852,N,N,N,N,63853,N,N,N,63855,N,N,63856,N,N, +N,N,N,63857,N,63858,N,N,N,N,N,N,N,N,N,N,63859,N,N,N,31828,N,N,N,31829,N,N,N,N, +N,31830,N,N,63860,N,N,N,63861,N,N,N,N,N,63862,63863,N,N,N,N,N,31831,N,N,N, +63864,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31832,N, +N,N,N,N,N,N,N,N,63865,N,N,N,N,N,N,N,N,N,N,N,63867,63868,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,63869,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64034,N,N,31834,N,N,N,64035,N,N,N,64036,N,N,N, +N,31835,N,31836,N,31837,N,31838,N,N,N,N,N,64038,31839,N,N,N,N,N,N,N,N,N,N,N,N, +N,64040,N,N,31840,N,N,64041,N,N,N,N,N,N,N,31841,N,N,N,N,64042,31842,31843,N, +31844,64043,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31845,N,N,N,N,64045,31846,31847,64046, +N,N,N,N,N,N,N,N,N,N,N,64051,N,N,N,31848,N,N,64049,N,31849,N,64048,N,N,N,N,N,N, +N,64052,64053,64050,N,N,N,64054,N,64055,N,N,N,N,N,N,N,N,N,N,N,N,N,31851,31852, +31853,N,64056,N,N,N,64057,N,64058,N,N,N,31854,31855,N,N,N,31856,N,N,N,N,N,N,N, +31857,N,31858,N,N,31859,N,N,64059,N,64060,64061,N,N,31860,N,N,N,N,N,N,N,N, +64062,64063,31861,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64064,N,64065,N,31862,N,N,N,N,N, +64066,N,N,64067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64068,N,N,N,N,64069,N,N,N,N,N,N, +N,N,N,31863,N,64070,N,N,N,N,N,N,N,N,64071,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31864, +N,N,N,N,N,N,N,N,N,64072,N,N,N,31865,N,64073,N,N,31866,N,64074,N,N,64075,N,N,N, +N,N,31867,N,N,N,N,N,N,64076,64077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31868,N, +N,64078,N,N,N,N,N,N,N,N,N,31870,32033,N,N,N,N,N,N,64081,32034,64082,N,N,32035, +N,N,N,N,N,N,N,N,N,31869,64083,N,N,N,N,N,32036,N,N,64084,N,N,N,N,N,32037,N,N,N, +N,N,64085,64086,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64088,N, +N,N,N,32038,32039,32040,N,32041,N,N,N,32042,N,64089,32043,N,N,N,64090,N,N, +64091,N,N,N,64092,32044,N,64093,N,N,N,N,64094,N,N,64095,N,N,N,N,N,N,64096, +64097,N,N,N,64098,N,64099,64100,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32045,N,N,N, +64103,64104,N,64105,N,N,N,N,N,N,N,N,32046,64106,N,N,N,64107,N,N,N,N,N,N,N,N,N, +64108,N,64109,N,N,N,N,N,64110,N,N,N,N,N,N,N,64111,N,N,N,64112,N,N,N,N,N,N, +64115,N,N,N,N,N,N,N,N,N,N,N,N,64116,64117,N,32047,N,N,N,64118,N,N,N,N,32048, +32049,N,64119,N,64120,N,N,32050,N,N,N,64121,N,64122,N,N,N,N,N,N,32051,N,N,N,N, +64123,N,64124,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64290,N,64291,N,64292,N,N,N,32052, +64293,N,32053,N,N,N,N,N,N,N,N,64294,N,N,N,64125,N,N,N,64295,N,N,N,N,N,N,N, +64296,64297,32054,N,32055,N,N,N,32056,N,64298,N,64299,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64302,32057,32058,32059,N,N,N,N,N,N,64303,N, +N,N,N,N,64304,N,N,64305,N,N,N,N,N,N,N,N,N,32060,32061,N,N,N,N,32062,64306,N,N, +N,N,32063,64307,N,64308,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64312,N,N, +64313,N,N,N,64314,N,N,N,N,N,N,N,N,N,N,N,32064,N,N,64315,N,N,64309,N,32065,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32066,N,N,N,N,N,N,64320,N,N,N,N,32067, +64321,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64322,N,32068,32069,N,N,64323,N, +N,N,N,64324,N,N,N,N,N,N,N,N,N,64319,N,N,N,64316,N,N,N,N,N,64329,N,32071,32070, +N,N,N,N,64325,N,N,N,N,N,64326,N,N,N,N,N,N,64327,64328,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64330,32072,64331,N,N,N,N,N,N,64332,N,N,N,N,N,N,N, +N,N,64333,N,N,N,N,32073,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32074, +N,N,N,N,N,N,N,32075,N,64336,N,64337,N,32076,32077,64338,64339,N,N,N,N,N,N,N,N, +N,N,N,N,64340,N,N,N,N,N,64341,64342,32078,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +32079,N,N,N,N,N,N,32080,N,N,32081,N,64344,32082,N,N,N,N,N,N,N,64345,N,32083,N, +N,N,N,N,N,32084,N,N,N,N,N,N,N,N,N,N,64347,N,N,32085,N,N,N,N,32086,N,N,32087,N, +N,N,N,N,N,32089,N,N,N,32090,64037,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64350,N,N,N,N,N, +N,64351,64352,N,N,N,N,N,N,N,64354,N,N,N,N,64355,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,32091,N,N,N,N,N,N,N,N,64356,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64358,N,32092,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,64360,N,N,32094,N,N,N,N,N,N,32095,32096,N,N,N,64363,N,N,N,N,N,64364,N,N, +N,64365,N,N,N,N,N,N,64366,N,N,64367,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +32097,N,N,N,N,N,64370,N,64371,N,N,64372,32098,N,N,N,N,N,N,N,N,N,N,32100,N,N,N, +N,N,32101,64374,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64375,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,32102,N,N,64377,N,N,N,N,32103,N,N,N,N,N,64378,N,N,N,N,N,64379,N,N,N,N,N, +32104,32105,32106,N,N,N,N,N,64380,N,64381,N,N,32107,64382,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,64545,N,N,N,32108,N,N,N,N,32109,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,32110,64548,N,N,N,64549,N,N,N,64550,N,N,N,64551,N, +N,N,N,N,N,N,N,N,N,N,32111,N,N,64552,64553,N,N,N,N,N,N,N,32112,N,N,N,64554,N,N, +32113,N,N,N,N,N,N,N,32114,N,N,64555,N,N,N,N,64556,N,N,64557,N,N,N,64558,64559, +N,32116,N,N,32115,N,N,64560,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64561,N,N,32117, +64562,N,N,N,N,N,32119,N,N,64563,64564,N,N,N,N,N,64565,N,64566,N,N,N,N,N,N,N, +32120,N,N,N,N,64569,N,64572,N,N,N,N,N,32121,N,N,N,N,32122,N,64570,64571,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64573,N,N,N,N,N,N,N,N,N,N,32124,32125,N,N, +32126,32289,N,32290,32291,N,N,N,N,N,N,N,N,N,N,32293,64574,N,N,N,N,N,32294,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64575,N,64576,N,N,64577,N,N,N,N,N,N, +64579,64580,N,32295,64581,64582,N,N,64583,N,N,64584,N,N,N,N,64585,32296,N,N, +64586,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64587,64589,N,64590,N,64591,N, +32297,N,N,64592,N,N,N,N,N,64593,64594,N,64595,64596,N,N,N,N,N,N,N,N,N,N,N,N,N, +64599,64600,N,N,64602,64603,64604,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64606,64607,64608,N,N,N,N,N,N,64609,64610,64611,N,N,N,64612,64613,N,N,N,N, +64614,N,N,N,N,N,N,64615,64616,N,N,N,N,N,N,N,N,N,32298,N,N,N,64617,N,N,64618, +64619,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32299,N,N,N,N,64620,N,N, +64621,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64622,N,N,N,64623,N,64624,N,N,N, +64625,N,N,N,N,N,64626,N,N,N,N,N,N,N,N,N,N,64627,N,N,N,N,64628,N,N,N,N,64629,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64631,N,N,N,N,N,N,N,N,64632,N,N,64633,32300, +32301,N,N,N,N,N,N,64634,N,N,N,N,N,N,64635,N,N,N,N,64636,N,N,N,64637,N,N,N,N,N, +64638,N,N,N,32302,N,N,N,N,N,N,N,N,32303,32304,N,N,64801,N,N,N,N,64802,N,32305, +N,N,N,N,N,N,N,N,N,N,N,64803,N,N,N,N,N,32306,N,64804,N,32307,N,N,N,32308,N,N,N, +N,N,64805,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64807,N,N,N,N,N,N,32309,64809,N,64811,N,N,N,N,N,N,N, +32310,N,32311,N,N,64813,N,N,N,N,N,N,N,32312,N,64814,N,64815,N,N,64816,32313,N, +N,N,N,N,64818,N,N,N,64819,N,N,N,N,64820,N,N,N,64821,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,32314,32315,64822,N,N,N,N,32316,N,N,N,64823,N,N,N,64824,N,64825,N,N,N, +64826,N,N,N,N,N,64827,N,N,N,32317,N,N,N,N,N,N,N,N,N,N,64828,N,32319,N,N,N,N,N, +64829,N,N,N,N,N,N,N,N,N,64830,N,N,N,N,N,N,N,N,N,N,N,N,N,64832,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,32320,N,N,N,N,64833,N,64834,32322,N,N,N,N,64835,64836,N,N, +N,N,N,32323,64837,N,32324,64838,64839,N,32321,N,N,N,N,N,N,N,N,N,N,32325,N,N,N, +N,N,32326,N,N,N,N,32327,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32328,N,N,N,N,N,N,N,64840, +32329,N,N,N,N,64841,N,N,N,N,64842,64845,N,N,N,N,N,64846,N,N,N,N,N,64847,N,N, +32330,N,N,N,N,N,64848,N,N,N,N,N,N,32331,N,N,N,N,N,N,N,N,N,64850,N,N,N,N,64851, +N,N,N,N,N,N,N,32332,N,64852,N,N,64853,64854,N,N,64856,64855,N,N,N,64849,N,N,N, +64860,32333,N,64858,N,N,32334,32335,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64862,N,64863,64864,64865,N,N,64866,N,N,N,N,64867,32336,N,N,N,64868,N,64869, +64870,N,N,N,N,N,N,64872,N,N,N,N,64873,64874,N,N,N,N,N,N,N,N,N,32337,N,N,N, +64875,N,N,N,64878,64879,N,N,N,N,32338,32339,N,N,32340,64881,N,N,N,64882,N,N, +64883,64876,64884,N,64885,N,N,N,32341,N,32342,N,N,N,64886,64887,64888,N,64889, +64890,N,64891,N,64892,N,N,64893,N,32343,N,N,64894,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65057,N,N,N,N,N,N,N,N,N,N,N,65058,65060,N,N,N,N, +N,N,N,N,65059,N,N,N,N,N,65062,N,N,N,N,N,65063,65064,N,N,N,N,32344,32345,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65068,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65070, +32346,N,N,N,32347,N,N,65071,N,N,N,N,N,N,N,32348,N,N,N,N,N,N,N,N,N,N,N,N,65072, +N,N,65073,32349,N,N,N,N,N,65075,N,65076,N,N,N,N,32350,N,N,65078,N,N,65079, +65080,N,N,N,N,32351,N,65081,N,N,N,N,N,65082,N,N,N,N,N,32352,N,N,65083,N,N,N,N, +N,N,N,N,32353,N,N,65084,N,N,N,N,N,N,N,65085,N,N,N,N,N,N,N,N,N,N,32355,N,N,N,N, +N,N,N,N,65087,N,N,N,65088,N,N,32356,65089,N,65086,32354,N,N,65090,N,N,N,65091, +N,65092,N,N,N,N,N,N,N,N,N,N,N,N,65093,32357,N,N,65094,N,N,N,N,65095,65096,N,N, +65097,N,N,N,32359,N,N,N,N,N,N,N,N,N,N,N,N,65098,65101,N,N,N,N,32360,N,N,65100, +N,N,65102,N,N,N,N,N,N,N,32361,N,N,N,65103,N,N,65104,65105,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,65106,32362,N,N,N,65108,N,N,N,N,65109,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,65110,N,N,32363,N,N,N,N,N,32364,N,N,N,65111,N,N,N,32365,N,N,32366, +N,N,N,N,32367,32368,N,N,N,N,N,N,N,65113,N,N,N,N,N,32369,N,N,N,N,N,N,N,N,N,N,N, +N,N,32370,N,N,N,N,N,N,N,N,N,N,N,N,N,65115,N,N,N,N,N,N,N,65116,N,N,N,N,N,N, +65117,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65118,65119,65121,N,N,N,N,N,N,N,N,N,N,N, +N,32371,N,N,N,N,N,N,65122,N,65123,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +65124,N,N,N,N,N,N,N,65125,N,32372,65126,N,N,65127,N,N,N,65128,N,N,N,65129, +65130,N,N,N,N,N,N,N,N,N,N,N,N,65131,N,65132,N,32373,65133,N,N,N,N,65135,N,N,N, +N,N,N,N,N,N,N,N,65137,N,N,N,65139,N,N,65140,N,N,N,N,65141,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32374,N,N,N,32375,N,N,32376,N,N,N,N,N,N,N,N,N, +N,32377,30267,N,N,N,N,N,N,N,N,N,N,29742,30030,N,N,N,N,N,N,N,N,N,N,N,N,31567,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30281,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +32292,N,N,N,N,N,N,N,N,N,N,N,32093,12107,12119,20338,N,44665,30074,30554,30575, +N,N,31036,31037,31041,N,N,N,31546,63288,63301,31790,N,63854,N,31850,N,N,N,N,N, +N,N,N,N,11832,11849,11856,11875,11880,11886,12076,12079,12086,12122,12126, +20321,20322,29776,29788,29790,29793,29992,29995,30019,30053,30313,30327,30501, +30549,61481,30757,31015,31027,31028,31031,31032,31033,31035,31039,31040,31053, +31057,31076,31278,62544,31283,31290,31300,31320,62836,62837,31527,31599,31609, +31791,31792,31800,31805,63849,31833,32099,32118,32123,9022,9021,8752,N,N,N,N, +8751,N,N,N,N,N,8753, +}; + +static const struct unim_index jisx0213_bmp_encmap[256] = { +{__jisx0213_bmp_encmap+0,126,255},{__jisx0213_bmp_encmap+130,0,253},{ +__jisx0213_bmp_encmap+384,80,233},{__jisx0213_bmp_encmap+538,0,194},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_bmp_encmap+733,62,63 +},{__jisx0213_bmp_encmap+735,112,115},{__jisx0213_bmp_encmap+739,19,172},{ +__jisx0213_bmp_encmap+893,15,233},{__jisx0213_bmp_encmap+1112,5,219},{ +__jisx0213_bmp_encmap+1327,5,206},{__jisx0213_bmp_encmap+1529,35,254},{ +__jisx0213_bmp_encmap+1749,177,230},{__jisx0213_bmp_encmap+1803,0,110},{ +__jisx0213_bmp_encmap+1914,19,127},{0,0,0},{__jisx0213_bmp_encmap+2023,52,251 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_bmp_encmap+2223, +22,255},{__jisx0213_bmp_encmap+2457,240,255},{__jisx0213_bmp_encmap+2473,49, +250},{__jisx0213_bmp_encmap+2675,3,205},{__jisx0213_bmp_encmap+2878,2,219},{ +__jisx0213_bmp_encmap+3096,31,244},{__jisx0213_bmp_encmap+3310,5,207},{ +__jisx0213_bmp_encmap+3513,97,253},{__jisx0213_bmp_encmap+3670,0,250},{ +__jisx0213_bmp_encmap+3921,23,111},{__jisx0213_bmp_encmap+4010,110,234},{ +__jisx0213_bmp_encmap+4135,14,240},{__jisx0213_bmp_encmap+4362,15,210},{ +__jisx0213_bmp_encmap+4558,17,212},{__jisx0213_bmp_encmap+4754,5,148},{ +__jisx0213_bmp_encmap+4898,87,215},{__jisx0213_bmp_encmap+5027,57,147},{ +__jisx0213_bmp_encmap+5118,5,243},{__jisx0213_bmp_encmap+5357,7,221},{ +__jisx0213_bmp_encmap+5572,2,240},{__jisx0213_bmp_encmap+5811,8,212},{ +__jisx0213_bmp_encmap+6016,8,234},{__jisx0213_bmp_encmap+6243,15,175},{ +__jisx0213_bmp_encmap+6404,12,253},{__jisx0213_bmp_encmap+6646,22,181},{ +__jisx0213_bmp_encmap+6806,176,250},{__jisx0213_bmp_encmap+6881,4,188},{ +__jisx0213_bmp_encmap+7066,59,232},{__jisx0213_bmp_encmap+7240,23,209},{ +__jisx0213_bmp_encmap+7427,7,119},{__jisx0213_bmp_encmap+7540,2,255},{ +__jisx0213_bmp_encmap+7794,0,242},{__jisx0213_bmp_encmap+8037,0,243},{ +__jisx0213_bmp_encmap+8281,3,244},{__jisx0213_bmp_encmap+8523,1,251},{ +__jisx0213_bmp_encmap+8774,0,245},{__jisx0213_bmp_encmap+9020,18,255},{ +__jisx0213_bmp_encmap+9258,0,233},{__jisx0213_bmp_encmap+9492,7,247},{ +__jisx0213_bmp_encmap+9733,10,255},{__jisx0213_bmp_encmap+9979,4,244},{ +__jisx0213_bmp_encmap+10220,5,248},{__jisx0213_bmp_encmap+10464,12,245},{ +__jisx0213_bmp_encmap+10698,0,253},{__jisx0213_bmp_encmap+10952,3,244},{ +__jisx0213_bmp_encmap+11194,6,233},{__jisx0213_bmp_encmap+11422,0,253},{ +__jisx0213_bmp_encmap+11676,0,252},{__jisx0213_bmp_encmap+11929,13,248},{ +__jisx0213_bmp_encmap+12165,16,245},{__jisx0213_bmp_encmap+12395,21,253},{ +__jisx0213_bmp_encmap+12628,3,247},{__jisx0213_bmp_encmap+12873,9,255},{ +__jisx0213_bmp_encmap+13120,4,252},{__jisx0213_bmp_encmap+13369,0,251},{ +__jisx0213_bmp_encmap+13621,1,252},{__jisx0213_bmp_encmap+13873,1,252},{ +__jisx0213_bmp_encmap+14125,3,254},{__jisx0213_bmp_encmap+14377,15,253},{ +__jisx0213_bmp_encmap+14616,11,255},{__jisx0213_bmp_encmap+14861,2,251},{ +__jisx0213_bmp_encmap+15111,0,252},{__jisx0213_bmp_encmap+15364,23,251},{ +__jisx0213_bmp_encmap+15593,10,252},{__jisx0213_bmp_encmap+15836,0,236},{ +__jisx0213_bmp_encmap+16073,3,254},{__jisx0213_bmp_encmap+16325,0,251},{ +__jisx0213_bmp_encmap+16577,7,250},{__jisx0213_bmp_encmap+16821,1,255},{ +__jisx0213_bmp_encmap+17076,1,249},{__jisx0213_bmp_encmap+17325,0,252},{ +__jisx0213_bmp_encmap+17578,10,251},{__jisx0213_bmp_encmap+17820,5,254},{ +__jisx0213_bmp_encmap+18070,0,237},{__jisx0213_bmp_encmap+18308,3,253},{ +__jisx0213_bmp_encmap+18559,7,240},{__jisx0213_bmp_encmap+18793,1,245},{ +__jisx0213_bmp_encmap+19038,3,249},{__jisx0213_bmp_encmap+19285,8,154},{ +__jisx0213_bmp_encmap+19432,59,250},{__jisx0213_bmp_encmap+19624,2,251},{ +__jisx0213_bmp_encmap+19874,13,255},{__jisx0213_bmp_encmap+20117,4,254},{ +__jisx0213_bmp_encmap+20368,0,249},{__jisx0213_bmp_encmap+20618,1,253},{ +__jisx0213_bmp_encmap+20871,12,255},{__jisx0213_bmp_encmap+21115,0,253},{ +__jisx0213_bmp_encmap+21369,5,245},{__jisx0213_bmp_encmap+21610,1,245},{ +__jisx0213_bmp_encmap+21855,1,255},{__jisx0213_bmp_encmap+22110,17,252},{ +__jisx0213_bmp_encmap+22346,5,158},{__jisx0213_bmp_encmap+22500,57,254},{ +__jisx0213_bmp_encmap+22698,9,253},{__jisx0213_bmp_encmap+22943,6,250},{ +__jisx0213_bmp_encmap+23188,0,251},{__jisx0213_bmp_encmap+23440,2,255},{ +__jisx0213_bmp_encmap+23694,0,251},{__jisx0213_bmp_encmap+23946,1,255},{ +__jisx0213_bmp_encmap+24201,2,253},{__jisx0213_bmp_encmap+24453,4,114},{ +__jisx0213_bmp_encmap+24564,120,222},{__jisx0213_bmp_encmap+24667,29,239},{ +__jisx0213_bmp_encmap+24878,20,244},{__jisx0213_bmp_encmap+25103,4,243},{ +__jisx0213_bmp_encmap+25343,8,252},{__jisx0213_bmp_encmap+25588,2,249},{ +__jisx0213_bmp_encmap+25836,2,253},{__jisx0213_bmp_encmap+26088,0,242},{ +__jisx0213_bmp_encmap+26331,2,244},{__jisx0213_bmp_encmap+26574,2,255},{ +__jisx0213_bmp_encmap+26828,2,162},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_bmp_encmap+26989 +,29,220},{__jisx0213_bmp_encmap+27181,15,106},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_bmp_encmap+27273,69,70},{__jisx0213_bmp_encmap+27275,2,13}, +}; + +static const ucs2_t __jisx0213_1_emp_decmap[340] = { +11,4669,U,U,U,U,U,U,U,U,U,4891,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,5230,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,6333,2975,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,5812,U,U,U,U,U,U,U,U,U,U,7732,12740,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +13764,14143,U,U,U,U,U,U,U,U,14179,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,15614,18417,21646,21774,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22385,U,U,U,U,U,U,U,U,U,U,U, +U,22980,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23969,27391,28224,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28916,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30340,33399,U,U,U,U,U,U,U,33741,41360, +}; + +static const struct dbcs_index jisx0213_1_emp_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_1_emp_decmap+0,34,34},{__jisx0213_1_emp_decmap+1,66,123},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{__jisx0213_1_emp_decmap+59,84,110},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_1_emp_decmap+86,58,114},{ +__jisx0213_1_emp_decmap+143,41,96},{__jisx0213_1_emp_decmap+199,108,108},{ +__jisx0213_1_emp_decmap+200,126,126},{__jisx0213_1_emp_decmap+201,41,110},{ +__jisx0213_1_emp_decmap+271,93,93},{__jisx0213_1_emp_decmap+272,51,108},{ +__jisx0213_1_emp_decmap+330,73,81},{0,0,0},{__jisx0213_1_emp_decmap+339,102, +102},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const ucs2_t __jisx0213_2_emp_decmap[2053] = { +137,U,U,U,U,U,U,U,U,U,162,U,U,164,U,U,U,U,U,U,U,418,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,531,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,811,U,U,U,U,U,U,897,U,881,1017,U,U,1098,U,1289,U,U,U,U,U,U,U,U,U, +1494,1576,U,U,U,U,U,1871,U,U,U,U,U,U,2055,U,2106,U,U,U,U,U,U,U,U,2233,U,U,U,U, +U,U,U,2428,2461,U,U,U,U,U,2771,U,U,2845,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,3397,3553,U,U,U,U,U,U,3733,3693,U,U,U,U,U,U,U,3684,U,U,3935,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,4609,U,U,4693,U,4731,U,U,U, +U,4724,U,U,U,U,U,U,4836,4823,U,U,U,U,U,U,4861,U,4918,4932,5060,U,U,U,U,U,U,U, +U,U,U,U,U,5229,U,U,U,U,U,U,U,U,U,U,U,5591,U,U,U,U,U,27689,U,U,5703,U,U,U,U,U, +U,U,U,U,U,U,U,U,5894,5954,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,6595,7254,U,U,U,U,U,U,7469,7493,U,7544,7522,U,U,U, +7585,7580,U,U,U,U,7570,U,U,7607,U,7648,7731,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +7966,U,U,U,U,U,U,U,U,U,U,8054,U,U,U,U,U,8186,8571,U,U,U,U,U,U,U,U,8990,U,U,U, +U,9133,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,9971,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,10331,U,U,U,U,U,U,U,10411,U,U,U,U,10639, +10936,U,U,U,U,11087,11088,U,U,U,U,U,U,U,11078,U,11293,11174,U,U,U,11300,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,11745,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12739,12789,12726,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,13170,U,13267,13266,U,U,U,U,13264,13284, +13269,U,U,13274,U,13279,U,U,U,U,U,U,U,U,U,U,U,13386,13393,13387,U,U,U,13413,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,13540,13658,13716,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,13881,13895,U,13880,13882,U,U,U,U,U,U,U,U,U,U, +14108,U,U,U,U,U,U,U,U,U,U,14092,U,U,U,U,U,U,U,14180,U,U,U,U,U,U,U,14335,14311, +U,U,U,U,U,14372,U,U,U,U,14397,15000,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,15487,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,15616,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +15680,U,15866,15865,15827,16254,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,16534, +U,U,U,U,U,16643,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,16838,U,U,16894,17340,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,17961,U,U,U,U,U,18085,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,18582,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,19021,19286,U,19311,U,U,U,U,19478,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,19732,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,19982,U,U, +U,20023,U,U,U,U,20074,U,U,20107,U,U,U,U,U,U,U,U,U,U,U,20554,U,20565,U,U,20770, +20905,U,20965,20941,U,U,U,21022,U,U,U,21068,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +21550,U,U,U,U,U,U,U,U,U,U,21721,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,21927,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22441,22452,22996,U,U,U,U,U,U,U, +U,U,U,23268,23267,U,23281,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23474,U,U,U,U,U,U, +U,U,U,U,23627,23652,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24110,24150,24165, +U,24162,U,U,U,24280,U,24258,24296,U,24355,U,U,24412,U,U,U,U,U,U,24544,24532,U, +U,U,U,24588,24571,U,U,U,U,U,U,U,24599,U,U,U,U,24672,U,U,U,U,U,U,U,U,U,U,U,U, +24813,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25200,U,25222,U,U,U,U, +U,U,25420,U,U,15630,U,U,U,25602,26238,U,U,U,U,26288,U,U,U,U,U,U,U,U,U,U,U, +26397,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,26845,U,26858,U,26961,U,U,26991,U,27101,U, +U,U,27166,U,U,U,U,U,U,27224,U,U,U,U,U,27276,U,U,27319,27763,U,U,U,U,U,U,U,U,U, +27869,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28261,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,28564,U,U,U,U,U,U,U,U,28664,28662,28663,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,28941,U,U,28985,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29659,29658,U,U,U,U,U,29694,U,U,29712,U,U,U,U, +29769,30229,30228,U,30257,U,U,U,U,U,U,U,30355,U,U,U,U,U,U,U,30478,U,30499,U,U, +U,30546,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31109,U,U,U,U,U,U,U,U,U,U,U,U, +31364,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31667,U,31678,31687,31928,U,U,U,U, +U,U,U,U,U,32160,U,U,32272,U,U,U,U,U,U,32695,U,U,U,U,U,U,U,U,32906,U,U,U,U,U, +32955,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33410,U,U,U,U,33523,U,U,U,U,U,U,U,33804, +U,U,U,U,33877,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34155,U,U,U,34248,34249,U,U,U,U,U,U, +U,U,U,U,34519,U,U,34554,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,35145,35142,U,U,U,U,U,U,35179,U,U,U,U,U,U,U,U,U,U,U,U,U,35207,35208,U, +U,U,U,U,U,U,U,U,U,35258,35259,U,U,U,U,U,U,U,U,U,U,U,35358,35369,U,U,U,U,U,U,U, +U,U,U,35441,35395,U,U,U,U,U,U,U,U,35481,35533,U,U,U,U,U,35556,35549,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,35777,35823,U,U,U,U,U,U,U,36112,U,U,36209,U,36347,36383,U, +U,U,36406,U,U,U,36489,U,36587,U,36658,U,U,U,U,U,U,U,36856,37536,37553,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38032,U,U,U,U,U,U,U,U,U,38351,U,U,U,U,U,U,U,U, +U,38527,U,U,U,U,U,U,U,U,U,38640,U,U,38681,U,U,U,38736,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,39110,39538,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,40411,40509,U,U,U,U,U,U,U,U,U,U,U,U,40469,U,40586,U,40521,U, +U,U,U,U,U,U,U,U,40644,U,U,U,U,U,40681,U,U,40667,40910,U,U,U,41007,U,40986,U,U, +U,U,U,U,41209,U,U,41090,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,8728,U,U,U,U,41868,U,42039,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,42481,U, +42498,U,42522,U,U,U,42674, +}; + +static const struct dbcs_index jisx0213_2_emp_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_2_emp_decmap+0,33,121},{0,0,0},{ +__jisx0213_2_emp_decmap+89,34,119},{__jisx0213_2_emp_decmap+175,42,117},{ +__jisx0213_2_emp_decmap+251,37,126},{0,0,0},{0,0,0},{__jisx0213_2_emp_decmap+ +341,48,108},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_2_emp_decmap+402,34,114},{ +__jisx0213_2_emp_decmap+483,36,125},{__jisx0213_2_emp_decmap+573,35,120},{ +__jisx0213_2_emp_decmap+659,42,117},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_2_emp_decmap+735,35,96},{__jisx0213_2_emp_decmap+797,50,100},{ +__jisx0213_2_emp_decmap+848,34,123},{__jisx0213_2_emp_decmap+938,46,122},{ +__jisx0213_2_emp_decmap+1015,33,118},{__jisx0213_2_emp_decmap+1101,50,125},{ +__jisx0213_2_emp_decmap+1177,34,121},{__jisx0213_2_emp_decmap+1265,53,115},{ +__jisx0213_2_emp_decmap+1328,68,126},{__jisx0213_2_emp_decmap+1387,33,115},{ +__jisx0213_2_emp_decmap+1470,41,122},{__jisx0213_2_emp_decmap+1552,37,126},{ +__jisx0213_2_emp_decmap+1642,33,126},{__jisx0213_2_emp_decmap+1736,33,113},{ +__jisx0213_2_emp_decmap+1817,34,118},{__jisx0213_2_emp_decmap+1902,44,112},{ +__jisx0213_2_emp_decmap+1971,37,118},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __jisx0213_emp_encmap[8787] = { +11810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,41249,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41259,N,41262,41270,41286,41328,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,41337,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41335,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41762,41765,41767, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,41777,41778,41784,41791,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41793,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,41802,41810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,41811,41817,41820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20308,41847,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42026,42042,N,N,N, +N,N,N,N,N,42034,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,42033,42045,42073,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +12098,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42076,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42083,N,N,N,N,N,N,42078,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,42091,N,N,N,N,N,N,N,N,N,N,N,N,42090,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,42098,12108,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,42100,N,N,N,N,N,N,N,N,N,N,N,N,N,42101,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42277,42290, +12128,42302,42311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +20323,42325,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42326,12155,42366,43056, +43063,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43064,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,43066,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43077,N,N,N,N,N, +N,N,N,N,43072,N,N,N,N,43071,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43080,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43082,43083,20334,43099,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43110,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43116,44066,65107,44075,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44080,44112,44133,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,44141,44146,44324,44338,N,N,N,N,N,N,N,N,44329,44330,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,44341,44340,N,N,N,N,N,N,44345,44374,44580,N,N,N,N,N,N,N,N,N,N,N,N, +44413,30010,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44579,44602,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44610, +N,44605,44604,N,44612,N,N,N,N,44615,N,N,N,N,44617,N,N,N,N,44611,44629,44631,N, +N,N,N,N,44630,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44635,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44663,44664,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44842,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30066, +44866,44863,44867,N,N,N,N,N,N,N,N,N,N,N,N,44864,44889,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,44878,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,30249,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30258,44897,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44906,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44905,44912,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44917, +60963,60980,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30304,61001,N,N,N,N,N,N,N,N,N,N,N,N,N,62581,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61020,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,61024,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,61023,61022,61234,61255,61261,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61281,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61284, +61474,61491,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,61497,30572,61523,61563,61742,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,61744,61749,61764,61789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61793,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61798,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61801, +61813,N,N,N,N,N,N,N,N,N,N,61815,61818,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61985, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61988,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61987,61992,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61996, +62013,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30846,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62024,31017,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62043,31047,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,62069,N,N,N,N,N,N,N,N,N,N,62070,31060,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62258,62270,62269,N,N,N,N,N,N,N,N,N,N,N,N,62272,62290,62301,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62302,31086,62323,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62324,N,N,N,N,N,N,N,N,N,N,N, +62327,N,N,62325,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62333,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,62331,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62498,62500,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,62503,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,62511,N,N,N,N,N,N,N,N,N,N,N,62510,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62517,62516,N,N,N,N,N,N,N,N,N,N,62525,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62530,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62543,62569,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,62571,62578,62585,62773,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62778,62790,62806,N,N, +N,N,N,N,N,N,N,N,N,N,62808,62810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,62813,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,62815,62819,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62826,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,62832,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,62835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,31325,42308,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,63044,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63054, +31539,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +63069,63093,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63265,63266,63102,31561, +63283,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,63286,63333,63332,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,63339,63342,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63347, +63530,63529,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63532,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,31596,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63540,63548,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,63550,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63554,63574,63587,63607,N,N,N,N,N,N,N,N,N,N, +63609,N,N,N,N,N,N,N,N,63610,63781,63791,63794,63801,63810,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +63816,31817,N,N,N,N,N,N,N,N,N,N,63833,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,63838,31825,63846,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63851,63866,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +63870,64033,64044,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,64047,64080,N,N,64079,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64087,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64101,64102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64113,64114,64126,N,N,N,N,N,N,N,N,N,N,64289,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64301,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64300,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64310, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64318,N,N,N,N,N,N, +64317,64334,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64335,64343,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64346, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64348,64349,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64353,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64357,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64359,64361,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,64369,64546,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64547,64568,64578, +64588,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64598,64601,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64605,64630,64812,64843,64857,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64844, +N,N,N,N,N,N,N,N,N,N,N,64861,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64859,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64871,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64880,N,N,N,N,N,N,N,N,N,N,N,N,N,64877,65061,65067,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,65065,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65074,32358,65112,65114,65134, +65136,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65138,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65142, +}; + +static const struct unim_index jisx0213_emp_encmap[256] = { +{__jisx0213_emp_encmap+0,11,164},{__jisx0213_emp_encmap+154,162,162},{ +__jisx0213_emp_encmap+155,19,19},{__jisx0213_emp_encmap+156,43,249},{ +__jisx0213_emp_encmap+363,74,74},{__jisx0213_emp_encmap+364,9,214},{ +__jisx0213_emp_encmap+570,40,40},{__jisx0213_emp_encmap+571,79,79},{ +__jisx0213_emp_encmap+572,7,185},{__jisx0213_emp_encmap+751,124,157},{ +__jisx0213_emp_encmap+785,211,211},{__jisx0213_emp_encmap+786,29,159},{0,0,0}, +{__jisx0213_emp_encmap+917,69,225},{__jisx0213_emp_encmap+1074,100,149},{ +__jisx0213_emp_encmap+1124,95,95},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+1125, +1,253},{__jisx0213_emp_encmap+1378,27,196},{__jisx0213_emp_encmap+1548,109,110 +},{__jisx0213_emp_encmap+1550,215,215},{__jisx0213_emp_encmap+1551,71,180},{ +__jisx0213_emp_encmap+1661,6,66},{__jisx0213_emp_encmap+1722,189,189},{ +__jisx0213_emp_encmap+1723,195,195},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+ +1724,86,86},{__jisx0213_emp_encmap+1725,45,224},{__jisx0213_emp_encmap+1905, +51,52},{__jisx0213_emp_encmap+1907,30,250},{0,0,0},{__jisx0213_emp_encmap+2128 +,123,123},{__jisx0213_emp_encmap+2129,24,24},{__jisx0213_emp_encmap+2130,30, +173},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+2274,243,243},{0,0,0},{ +__jisx0213_emp_encmap+2275,91,171},{__jisx0213_emp_encmap+2356,143,143},{ +__jisx0213_emp_encmap+2357,184,184},{__jisx0213_emp_encmap+2358,70,166},{ +__jisx0213_emp_encmap+2455,29,36},{__jisx0213_emp_encmap+2463,225,225},{0,0,0 +},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+2464,182,245},{0,0,0},{ +__jisx0213_emp_encmap+2528,114,228},{__jisx0213_emp_encmap+2643,74,228},{ +__jisx0213_emp_encmap+2798,90,196},{__jisx0213_emp_encmap+2905,56,71},{ +__jisx0213_emp_encmap+2921,12,255},{__jisx0213_emp_encmap+3165,36,61},{0,0,0}, +{__jisx0213_emp_encmap+3191,152,152},{0,0,0},{__jisx0213_emp_encmap+3192,127, +254},{__jisx0213_emp_encmap+3320,0,250},{0,0,0},{__jisx0213_emp_encmap+3571, +126,126},{__jisx0213_emp_encmap+3572,150,150},{__jisx0213_emp_encmap+3573,3, +254},{0,0,0},{__jisx0213_emp_encmap+3825,188,188},{0,0,0},{0,0,0},{ +__jisx0213_emp_encmap+3826,41,165},{__jisx0213_emp_encmap+3951,241,241},{ +__jisx0213_emp_encmap+3952,150,150},{0,0,0},{__jisx0213_emp_encmap+3953,77,77 +},{__jisx0213_emp_encmap+3954,86,111},{__jisx0213_emp_encmap+3980,22,22},{ +__jisx0213_emp_encmap+3981,20,20},{__jisx0213_emp_encmap+3982,14,139},{0,0,0}, +{__jisx0213_emp_encmap+4108,74,85},{__jisx0213_emp_encmap+4120,34,229},{ +__jisx0213_emp_encmap+4316,30,76},{0,0,0},{__jisx0213_emp_encmap+4363,46,217}, +{__jisx0213_emp_encmap+4535,14,167},{0,0,0},{__jisx0213_emp_encmap+4689,113, +180},{0,0,0},{__jisx0213_emp_encmap+4757,196,212},{__jisx0213_emp_encmap+4774, +227,241},{__jisx0213_emp_encmap+4789,178,178},{__jisx0213_emp_encmap+4790,75, +100},{__jisx0213_emp_encmap+4816,161,161},{__jisx0213_emp_encmap+4817,46,232}, +{__jisx0213_emp_encmap+5004,35,251},{__jisx0213_emp_encmap+5221,12,237},{0,0,0 +},{__jisx0213_emp_encmap+5447,112,134},{__jisx0213_emp_encmap+5470,76,76},{ +__jisx0213_emp_encmap+5471,2,2},{0,0,0},{__jisx0213_emp_encmap+5472,126,176},{ +__jisx0213_emp_encmap+5523,29,29},{__jisx0213_emp_encmap+5524,221,234},{ +__jisx0213_emp_encmap+5538,81,221},{__jisx0213_emp_encmap+5679,30,255},{0,0,0 +},{__jisx0213_emp_encmap+5905,41,221},{0,0,0},{__jisx0213_emp_encmap+6086,64, +101},{__jisx0213_emp_encmap+6124,148,248},{__jisx0213_emp_encmap+6225,244,244 +},{__jisx0213_emp_encmap+6226,13,57},{0,0,0},{__jisx0213_emp_encmap+6271,218, +254},{__jisx0213_emp_encmap+6308,16,73},{0,0,0},{__jisx0213_emp_encmap+6366, +20,147},{__jisx0213_emp_encmap+6494,14,82},{0,0,0},{__jisx0213_emp_encmap+6563 +,133,133},{__jisx0213_emp_encmap+6564,132,132},{__jisx0213_emp_encmap+6565, +179,199},{__jisx0213_emp_encmap+6586,184,184},{__jisx0213_emp_encmap+6587,160, +160},{__jisx0213_emp_encmap+6588,16,16},{__jisx0213_emp_encmap+6589,183,183},{ +__jisx0213_emp_encmap+6590,138,187},{0,0,0},{__jisx0213_emp_encmap+6640,119, +243},{__jisx0213_emp_encmap+6765,205,205},{__jisx0213_emp_encmap+6766,12,85},{ +__jisx0213_emp_encmap+6840,107,201},{__jisx0213_emp_encmap+6935,215,250},{0,0, +0},{0,0,0},{__jisx0213_emp_encmap+6971,70,187},{__jisx0213_emp_encmap+7089,30, +228},{__jisx0213_emp_encmap+7288,193,239},{0,0,0},{__jisx0213_emp_encmap+7335, +16,251},{__jisx0213_emp_encmap+7571,31,235},{__jisx0213_emp_encmap+7776,50,248 +},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+7975,160,177},{0,0,0},{ +__jisx0213_emp_encmap+7993,144,144},{__jisx0213_emp_encmap+7994,207,207},{ +__jisx0213_emp_encmap+7995,127,240},{__jisx0213_emp_encmap+8109,25,80},{ +__jisx0213_emp_encmap+8165,198,198},{0,0,0},{__jisx0213_emp_encmap+8166,114, +114},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+8167,219,219},{ +__jisx0213_emp_encmap+8168,21,233},{__jisx0213_emp_encmap+8381,206,206},{ +__jisx0213_emp_encmap+8382,26,249},{__jisx0213_emp_encmap+8606,144,144},{0,0,0 +},{__jisx0213_emp_encmap+8607,140,140},{__jisx0213_emp_encmap+8608,55,55},{ +__jisx0213_emp_encmap+8609,241,241},{__jisx0213_emp_encmap+8610,2,178},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0}, +}; + diff --git a/pypy/translator/c/src/cjkcodecs/mappings_kr.h b/pypy/translator/c/src/cjkcodecs/mappings_kr.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/mappings_kr.h @@ -0,0 +1,3251 @@ +static const ucs2_t __ksx1001_decmap[8264] = { +12288,12289,12290,183,8229,8230,168,12291,173,8213,8741,65340,8764,8216,8217, +8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12304, +12305,177,215,247,8800,8804,8805,8734,8756,176,8242,8243,8451,8491,65504, +65505,65509,9794,9792,8736,8869,8978,8706,8711,8801,8786,167,8251,9734,9733, +9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8594,8592,8593,8595, +8596,12307,8810,8811,8730,8765,8733,8757,8747,8748,8712,8715,8838,8839,8834, +8835,8746,8745,8743,8744,65506,8658,8660,8704,8707,180,65374,711,728,733,730, +729,184,731,161,191,720,8750,8721,8719,164,8457,8240,9665,9664,9655,9654,9828, +9824,9825,9829,9831,9827,8857,9672,9635,9680,9681,9618,9636,9637,9640,9639, +9638,9641,9832,9743,9742,9756,9758,182,8224,8225,8597,8599,8601,8598,8600, +9837,9833,9834,9836,12927,12828,8470,13255,8482,13250,13272,8481,8364,174, +65281,65282,65283,65284,65285,65286,65287,65288,65289,65290,65291,65292,65293, +65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306, +65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319, +65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332, +65333,65334,65335,65336,65337,65338,65339,65510,65341,65342,65343,65344,65345, +65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358, +65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371, +65372,65373,65507,12593,12594,12595,12596,12597,12598,12599,12600,12601,12602, +12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615, +12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628, +12629,12630,12631,12632,12633,12634,12635,12636,12637,12638,12639,12640,12641, +12642,12643,12644,12645,12646,12647,12648,12649,12650,12651,12652,12653,12654, +12655,12656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667, +12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679,12680, +12681,12682,12683,12684,12685,12686,8560,8561,8562,8563,8564,8565,8566,8567, +8568,8569,U,U,U,U,U,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,U,U,U,U, +U,U,U,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931, +932,933,934,935,936,937,U,U,U,U,U,U,U,U,945,946,947,948,949,950,951,952,953, +954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,9472,9474,9484, +9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507, +9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,9490, +9489,9498,9497,9494,9493,9486,9485,9502,9503,9505,9506,9510,9511,9513,9514, +9517,9518,9521,9522,9525,9526,9529,9530,9533,9534,9536,9537,9539,9540,9541, +9542,9543,9544,9545,9546,13205,13206,13207,8467,13208,13252,13219,13220,13221, +13222,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13258,13197, +13198,13199,13263,13192,13193,13256,13223,13224,13232,13233,13234,13235,13236, +13237,13238,13239,13240,13241,13184,13185,13186,13187,13188,13242,13243,13244, +13245,13246,13247,13200,13201,13202,13203,13204,8486,13248,13249,13194,13195, +13196,13270,13253,13229,13230,13231,13275,13225,13226,13227,13228,13277,13264, +13267,13251,13257,13276,13254,198,208,170,294,U,306,U,319,321,216,338,186,222, +358,330,U,12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906, +12907,12908,12909,12910,12911,12912,12913,12914,12915,12916,12917,12918,12919, +12920,12921,12922,12923,9424,9425,9426,9427,9428,9429,9430,9431,9432,9433, +9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446,9447,9448, +9449,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325, +9326,189,8531,8532,188,190,8539,8540,8541,8542,230,273,240,295,305,307,312, +320,322,248,339,223,254,359,331,329,12800,12801,12802,12803,12804,12805,12806, +12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,12818,12819, +12820,12821,12822,12823,12824,12825,12826,12827,9372,9373,9374,9375,9376,9377, +9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392, +9393,9394,9395,9396,9397,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341, +9342,9343,9344,9345,9346,185,178,179,8308,8319,8321,8322,8323,8324,12353, +12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366, +12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379, +12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392, +12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405, +12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418, +12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431, +12432,12433,12434,12435,12449,12450,12451,12452,12453,12454,12455,12456,12457, +12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470, +12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483, +12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496, +12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509, +12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522, +12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,1040, +1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054, +1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069, +1070,1071,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,1072,1073,1074,1075,1076,1077,1105, +1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092, +1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,44032,44033,44036, +44039,44040,44041,44042,44048,44049,44050,44051,44052,44053,44054,44055,44057, +44058,44059,44060,44061,44064,44068,44076,44077,44079,44080,44081,44088,44089, +44092,44096,44107,44109,44116,44120,44124,44144,44145,44148,44151,44152,44154, +44160,44161,44163,44164,44165,44166,44169,44170,44171,44172,44176,44180,44188, +44189,44191,44192,44193,44200,44201,44202,44204,44207,44208,44216,44217,44219, +44220,44221,44225,44228,44232,44236,44245,44247,44256,44257,44260,44263,44264, +44266,44268,44271,44272,44273,44275,44277,44278,44284,44285,44288,44292,44294, +44300,44301,44303,44305,44312,44316,44320,44329,44332,44333,44340,44341,44344, +44348,44356,44357,44359,44361,44368,44372,44376,44385,44387,44396,44397,44400, +44403,44404,44405,44406,44411,44412,44413,44415,44417,44418,44424,44425,44428, +44432,44444,44445,44452,44471,44480,44481,44484,44488,44496,44497,44499,44508, +44512,44516,44536,44537,44540,44543,44544,44545,44552,44553,44555,44557,44564, +44592,44593,44596,44599,44600,44602,44608,44609,44611,44613,44614,44618,44620, +44621,44622,44624,44628,44630,44636,44637,44639,44640,44641,44645,44648,44649, +44652,44656,44664,44665,44667,44668,44669,44676,44677,44684,44732,44733,44734, +44736,44740,44748,44749,44751,44752,44753,44760,44761,44764,44776,44779,44781, +44788,44792,44796,44807,44808,44813,44816,44844,44845,44848,44850,44852,44860, +44861,44863,44865,44866,44867,44872,44873,44880,44892,44893,44900,44901,44921, +44928,44932,44936,44944,44945,44949,44956,44984,44985,44988,44992,44999,45000, +45001,45003,45005,45006,45012,45020,45032,45033,45040,45041,45044,45048,45056, +45057,45060,45068,45072,45076,45084,45085,45096,45124,45125,45128,45130,45132, +45134,45139,45140,45141,45143,45145,45149,45180,45181,45184,45188,45196,45197, +45199,45201,45208,45209,45210,45212,45215,45216,45217,45218,45224,45225,45227, +45228,45229,45230,45231,45233,45235,45236,45237,45240,45244,45252,45253,45255, +45256,45257,45264,45265,45268,45272,45280,45285,45320,45321,45323,45324,45328, +45330,45331,45336,45337,45339,45340,45341,45347,45348,45349,45352,45356,45364, +45365,45367,45368,45369,45376,45377,45380,45384,45392,45393,45396,45397,45400, +45404,45408,45432,45433,45436,45440,45442,45448,45449,45451,45453,45458,45459, +45460,45464,45468,45480,45516,45520,45524,45532,45533,45535,45544,45545,45548, +45552,45561,45563,45565,45572,45573,45576,45579,45580,45588,45589,45591,45593, +45600,45620,45628,45656,45660,45664,45672,45673,45684,45685,45692,45700,45701, +45705,45712,45713,45716,45720,45721,45722,45728,45729,45731,45733,45734,45738, +45740,45744,45748,45768,45769,45772,45776,45778,45784,45785,45787,45789,45794, +45796,45797,45798,45800,45803,45804,45805,45806,45807,45811,45812,45813,45815, +45816,45817,45818,45819,45823,45824,45825,45828,45832,45840,45841,45843,45844, +45845,45852,45908,45909,45910,45912,45915,45916,45918,45919,45924,45925,45927, +45929,45931,45934,45936,45937,45940,45944,45952,45953,45955,45956,45957,45964, +45968,45972,45984,45985,45992,45996,46020,46021,46024,46027,46028,46030,46032, +46036,46037,46039,46041,46043,46045,46048,46052,46056,46076,46096,46104,46108, +46112,46120,46121,46123,46132,46160,46161,46164,46168,46176,46177,46179,46181, +46188,46208,46216,46237,46244,46248,46252,46261,46263,46265,46272,46276,46280, +46288,46293,46300,46301,46304,46307,46308,46310,46316,46317,46319,46321,46328, +46356,46357,46360,46363,46364,46372,46373,46375,46376,46377,46378,46384,46385, +46388,46392,46400,46401,46403,46404,46405,46411,46412,46413,46416,46420,46428, +46429,46431,46432,46433,46496,46497,46500,46504,46506,46507,46512,46513,46515, +46516,46517,46523,46524,46525,46528,46532,46540,46541,46543,46544,46545,46552, +46572,46608,46609,46612,46616,46629,46636,46644,46664,46692,46696,46748,46749, +46752,46756,46763,46764,46769,46804,46832,46836,46840,46848,46849,46853,46888, +46889,46892,46895,46896,46904,46905,46907,46916,46920,46924,46932,46933,46944, +46948,46952,46960,46961,46963,46965,46972,46973,46976,46980,46988,46989,46991, +46992,46993,46994,46998,46999,47000,47001,47004,47008,47016,47017,47019,47020, +47021,47028,47029,47032,47047,47049,47084,47085,47088,47092,47100,47101,47103, +47104,47105,47111,47112,47113,47116,47120,47128,47129,47131,47133,47140,47141, +47144,47148,47156,47157,47159,47160,47161,47168,47172,47185,47187,47196,47197, +47200,47204,47212,47213,47215,47217,47224,47228,47245,47272,47280,47284,47288, +47296,47297,47299,47301,47308,47312,47316,47325,47327,47329,47336,47337,47340, +47344,47352,47353,47355,47357,47364,47384,47392,47420,47421,47424,47428,47436, +47439,47441,47448,47449,47452,47456,47464,47465,47467,47469,47476,47477,47480, +47484,47492,47493,47495,47497,47498,47501,47502,47532,47533,47536,47540,47548, +47549,47551,47553,47560,47561,47564,47566,47567,47568,47569,47570,47576,47577, +47579,47581,47582,47585,47587,47588,47589,47592,47596,47604,47605,47607,47608, +47609,47610,47616,47617,47624,47637,47672,47673,47676,47680,47682,47688,47689, +47691,47693,47694,47699,47700,47701,47704,47708,47716,47717,47719,47720,47721, +47728,47729,47732,47736,47747,47748,47749,47751,47756,47784,47785,47787,47788, +47792,47794,47800,47801,47803,47805,47812,47816,47832,47833,47868,47872,47876, +47885,47887,47889,47896,47900,47904,47913,47915,47924,47925,47926,47928,47931, +47932,47933,47934,47940,47941,47943,47945,47949,47951,47952,47956,47960,47969, +47971,47980,48008,48012,48016,48036,48040,48044,48052,48055,48064,48068,48072, +48080,48083,48120,48121,48124,48127,48128,48130,48136,48137,48139,48140,48141, +48143,48145,48148,48149,48150,48151,48152,48155,48156,48157,48158,48159,48164, +48165,48167,48169,48173,48176,48177,48180,48184,48192,48193,48195,48196,48197, +48201,48204,48205,48208,48221,48260,48261,48264,48267,48268,48270,48276,48277, +48279,48281,48282,48288,48289,48292,48295,48296,48304,48305,48307,48308,48309, +48316,48317,48320,48324,48333,48335,48336,48337,48341,48344,48348,48372,48373, +48374,48376,48380,48388,48389,48391,48393,48400,48404,48420,48428,48448,48456, +48457,48460,48464,48472,48473,48484,48488,48512,48513,48516,48519,48520,48521, +48522,48528,48529,48531,48533,48537,48538,48540,48548,48560,48568,48596,48597, +48600,48604,48617,48624,48628,48632,48640,48643,48645,48652,48653,48656,48660, +48668,48669,48671,48708,48709,48712,48716,48718,48724,48725,48727,48729,48730, +48731,48736,48737,48740,48744,48746,48752,48753,48755,48756,48757,48763,48764, +48765,48768,48772,48780,48781,48783,48784,48785,48792,48793,48808,48848,48849, +48852,48855,48856,48864,48867,48868,48869,48876,48897,48904,48905,48920,48921, +48923,48924,48925,48960,48961,48964,48968,48976,48977,48981,49044,49072,49093, +49100,49101,49104,49108,49116,49119,49121,49212,49233,49240,49244,49248,49256, +49257,49296,49297,49300,49304,49312,49313,49315,49317,49324,49325,49327,49328, +49331,49332,49333,49334,49340,49341,49343,49344,49345,49349,49352,49353,49356, +49360,49368,49369,49371,49372,49373,49380,49381,49384,49388,49396,49397,49399, +49401,49408,49412,49416,49424,49429,49436,49437,49438,49439,49440,49443,49444, +49446,49447,49452,49453,49455,49456,49457,49462,49464,49465,49468,49472,49480, +49481,49483,49484,49485,49492,49493,49496,49500,49508,49509,49511,49512,49513, +49520,49524,49528,49541,49548,49549,49550,49552,49556,49558,49564,49565,49567, +49569,49573,49576,49577,49580,49584,49597,49604,49608,49612,49620,49623,49624, +49632,49636,49640,49648,49649,49651,49660,49661,49664,49668,49676,49677,49679, +49681,49688,49689,49692,49695,49696,49704,49705,49707,49709,49711,49713,49714, +49716,49736,49744,49745,49748,49752,49760,49765,49772,49773,49776,49780,49788, +49789,49791,49793,49800,49801,49808,49816,49819,49821,49828,49829,49832,49836, +49837,49844,49845,49847,49849,49884,49885,49888,49891,49892,49899,49900,49901, +49903,49905,49910,49912,49913,49915,49916,49920,49928,49929,49932,49933,49939, +49940,49941,49944,49948,49956,49957,49960,49961,49989,50024,50025,50028,50032, +50034,50040,50041,50044,50045,50052,50056,50060,50112,50136,50137,50140,50143, +50144,50146,50152,50153,50157,50164,50165,50168,50184,50192,50212,50220,50224, +50228,50236,50237,50248,50276,50277,50280,50284,50292,50293,50297,50304,50324, +50332,50360,50364,50409,50416,50417,50420,50424,50426,50431,50432,50433,50444, +50448,50452,50460,50472,50473,50476,50480,50488,50489,50491,50493,50500,50501, +50504,50505,50506,50508,50509,50510,50515,50516,50517,50519,50520,50521,50525, +50526,50528,50529,50532,50536,50544,50545,50547,50548,50549,50556,50557,50560, +50564,50567,50572,50573,50575,50577,50581,50583,50584,50588,50592,50601,50612, +50613,50616,50617,50619,50620,50621,50622,50628,50629,50630,50631,50632,50633, +50634,50636,50638,50640,50641,50644,50648,50656,50657,50659,50661,50668,50669, +50670,50672,50676,50678,50679,50684,50685,50686,50687,50688,50689,50693,50694, +50695,50696,50700,50704,50712,50713,50715,50716,50724,50725,50728,50732,50733, +50734,50736,50739,50740,50741,50743,50745,50747,50752,50753,50756,50760,50768, +50769,50771,50772,50773,50780,50781,50784,50796,50799,50801,50808,50809,50812, +50816,50824,50825,50827,50829,50836,50837,50840,50844,50852,50853,50855,50857, +50864,50865,50868,50872,50873,50874,50880,50881,50883,50885,50892,50893,50896, +50900,50908,50909,50912,50913,50920,50921,50924,50928,50936,50937,50941,50948, +50949,50952,50956,50964,50965,50967,50969,50976,50977,50980,50984,50992,50993, +50995,50997,50999,51004,51005,51008,51012,51018,51020,51021,51023,51025,51026, +51027,51028,51029,51030,51031,51032,51036,51040,51048,51051,51060,51061,51064, +51068,51069,51070,51075,51076,51077,51079,51080,51081,51082,51086,51088,51089, +51092,51094,51095,51096,51098,51104,51105,51107,51108,51109,51110,51116,51117, +51120,51124,51132,51133,51135,51136,51137,51144,51145,51148,51150,51152,51160, +51165,51172,51176,51180,51200,51201,51204,51208,51210,51216,51217,51219,51221, +51222,51228,51229,51232,51236,51244,51245,51247,51249,51256,51260,51264,51272, +51273,51276,51277,51284,51312,51313,51316,51320,51322,51328,51329,51331,51333, +51334,51335,51339,51340,51341,51348,51357,51359,51361,51368,51388,51389,51396, +51400,51404,51412,51413,51415,51417,51424,51425,51428,51445,51452,51453,51456, +51460,51461,51462,51468,51469,51471,51473,51480,51500,51508,51536,51537,51540, +51544,51552,51553,51555,51564,51568,51572,51580,51592,51593,51596,51600,51608, +51609,51611,51613,51648,51649,51652,51655,51656,51658,51664,51665,51667,51669, +51670,51673,51674,51676,51677,51680,51682,51684,51687,51692,51693,51695,51696, +51697,51704,51705,51708,51712,51720,51721,51723,51724,51725,51732,51736,51753, +51788,51789,51792,51796,51804,51805,51807,51808,51809,51816,51837,51844,51864, +51900,51901,51904,51908,51916,51917,51919,51921,51923,51928,51929,51936,51948, +51956,51976,51984,51988,51992,52000,52001,52033,52040,52041,52044,52048,52056, +52057,52061,52068,52088,52089,52124,52152,52180,52196,52199,52201,52236,52237, +52240,52244,52252,52253,52257,52258,52263,52264,52265,52268,52270,52272,52280, +52281,52283,52284,52285,52286,52292,52293,52296,52300,52308,52309,52311,52312, +52313,52320,52324,52326,52328,52336,52341,52376,52377,52380,52384,52392,52393, +52395,52396,52397,52404,52405,52408,52412,52420,52421,52423,52425,52432,52436, +52452,52460,52464,52481,52488,52489,52492,52496,52504,52505,52507,52509,52516, +52520,52524,52537,52572,52576,52580,52588,52589,52591,52593,52600,52616,52628, +52629,52632,52636,52644,52645,52647,52649,52656,52676,52684,52688,52712,52716, +52720,52728,52729,52731,52733,52740,52744,52748,52756,52761,52768,52769,52772, +52776,52784,52785,52787,52789,52824,52825,52828,52831,52832,52833,52840,52841, +52843,52845,52852,52853,52856,52860,52868,52869,52871,52873,52880,52881,52884, +52888,52896,52897,52899,52900,52901,52908,52909,52929,52964,52965,52968,52971, +52972,52980,52981,52983,52984,52985,52992,52993,52996,53000,53008,53009,53011, +53013,53020,53024,53028,53036,53037,53039,53040,53041,53048,53076,53077,53080, +53084,53092,53093,53095,53097,53104,53105,53108,53112,53120,53125,53132,53153, +53160,53168,53188,53216,53217,53220,53224,53232,53233,53235,53237,53244,53248, +53252,53265,53272,53293,53300,53301,53304,53308,53316,53317,53319,53321,53328, +53332,53336,53344,53356,53357,53360,53364,53372,53373,53377,53412,53413,53416, +53420,53428,53429,53431,53433,53440,53441,53444,53448,53449,53456,53457,53459, +53460,53461,53468,53469,53472,53476,53484,53485,53487,53488,53489,53496,53517, +53552,53553,53556,53560,53562,53568,53569,53571,53572,53573,53580,53581,53584, +53588,53596,53597,53599,53601,53608,53612,53628,53636,53640,53664,53665,53668, +53672,53680,53681,53683,53685,53690,53692,53696,53720,53748,53752,53767,53769, +53776,53804,53805,53808,53812,53820,53821,53823,53825,53832,53852,53860,53888, +53889,53892,53896,53904,53905,53909,53916,53920,53924,53932,53937,53944,53945, +53948,53951,53952,53954,53960,53961,53963,53972,53976,53980,53988,53989,54000, +54001,54004,54008,54016,54017,54019,54021,54028,54029,54030,54032,54036,54038, +54044,54045,54047,54048,54049,54053,54056,54057,54060,54064,54072,54073,54075, +54076,54077,54084,54085,54140,54141,54144,54148,54156,54157,54159,54160,54161, +54168,54169,54172,54176,54184,54185,54187,54189,54196,54200,54204,54212,54213, +54216,54217,54224,54232,54241,54243,54252,54253,54256,54260,54268,54269,54271, +54273,54280,54301,54336,54340,54364,54368,54372,54381,54383,54392,54393,54396, +54399,54400,54402,54408,54409,54411,54413,54420,54441,54476,54480,54484,54492, +54495,54504,54508,54512,54520,54523,54525,54532,54536,54540,54548,54549,54551, +54588,54589,54592,54596,54604,54605,54607,54609,54616,54617,54620,54624,54629, +54632,54633,54635,54637,54644,54645,54648,54652,54660,54661,54663,54664,54665, +54672,54693,54728,54729,54732,54736,54738,54744,54745,54747,54749,54756,54757, +54760,54764,54772,54773,54775,54777,54784,54785,54788,54792,54800,54801,54803, +54804,54805,54812,54816,54820,54829,54840,54841,54844,54848,54853,54856,54857, +54859,54861,54865,54868,54869,54872,54876,54887,54889,54896,54897,54900,54915, +54917,54924,54925,54928,54932,54941,54943,54945,54952,54956,54960,54969,54971, +54980,54981,54984,54988,54993,54996,54999,55001,55008,55012,55016,55024,55029, +55036,55037,55040,55044,55057,55064,55065,55068,55072,55080,55081,55083,55085, +55092,55093,55096,55100,55108,55111,55113,55120,55121,55124,55126,55127,55128, +55129,55136,55137,55139,55141,55145,55148,55152,55156,55164,55165,55169,55176, +55177,55180,55184,55192,55193,55195,55197,20285,20339,20551,20729,21152,21487, +21621,21733,22025,23233,23478,26247,26550,26551,26607,27468,29634,30146,31292, +33499,33540,34903,34952,35382,36040,36303,36603,36838,39381,21051,21364,21508, +24682,24932,27580,29647,33050,35258,35282,38307,20355,21002,22718,22904,23014, +24178,24185,25031,25536,26438,26604,26751,28567,30286,30475,30965,31240,31487, +31777,32925,33390,33393,35563,38291,20075,21917,26359,28212,30883,31469,33883, +35088,34638,38824,21208,22350,22570,23884,24863,25022,25121,25954,26577,27204, +28187,29976,30131,30435,30640,32058,37039,37969,37970,40853,21283,23724,30002, +32987,37440,38296,21083,22536,23004,23713,23831,24247,24378,24394,24951,27743, +30074,30086,31968,32115,32177,32652,33108,33313,34193,35137,35611,37628,38477, +40007,20171,20215,20491,20977,22607,24887,24894,24936,25913,27114,28433,30117, +30342,30422,31623,33445,33995,63744,37799,38283,21888,23458,22353,63745,31923, +32697,37301,20520,21435,23621,24040,25298,25454,25818,25831,28192,28844,31067, +36317,36382,63746,36989,37445,37624,20094,20214,20581,24062,24314,24838,26967, +33137,34388,36423,37749,39467,20062,20625,26480,26688,20745,21133,21138,27298, +30652,37392,40660,21163,24623,36850,20552,25001,25581,25802,26684,27268,28608, +33160,35233,38548,22533,29309,29356,29956,32121,32365,32937,35211,35700,36963, +40273,25225,27770,28500,32080,32570,35363,20860,24906,31645,35609,37463,37772, +20140,20435,20510,20670,20742,21185,21197,21375,22384,22659,24218,24465,24950, +25004,25806,25964,26223,26299,26356,26775,28039,28805,28913,29855,29861,29898, +30169,30828,30956,31455,31478,32069,32147,32789,32831,33051,33686,35686,36629, +36885,37857,38915,38968,39514,39912,20418,21843,22586,22865,23395,23622,24760, +25106,26690,26800,26856,28330,30028,30328,30926,31293,31995,32363,32380,35336, +35489,35903,38542,40388,21476,21481,21578,21617,22266,22993,23396,23611,24235, +25335,25911,25925,25970,26272,26543,27073,27837,30204,30352,30590,31295,32660, +32771,32929,33167,33510,33533,33776,34241,34865,34996,35493,63747,36764,37678, +38599,39015,39640,40723,21741,26011,26354,26767,31296,35895,40288,22256,22372, +23825,26118,26801,26829,28414,29736,34974,39908,27752,63748,39592,20379,20844, +20849,21151,23380,24037,24656,24685,25329,25511,25915,29657,31354,34467,36002, +38799,20018,23521,25096,26524,29916,31185,33747,35463,35506,36328,36942,37707, +38982,24275,27112,34303,37101,63749,20896,23448,23532,24931,26874,27454,28748, +29743,29912,31649,32592,33733,35264,36011,38364,39208,21038,24669,25324,36866, +20362,20809,21281,22745,24291,26336,27960,28826,29378,29654,31568,33009,37979, +21350,25499,32619,20054,20608,22602,22750,24618,24871,25296,27088,39745,23439, +32024,32945,36703,20132,20689,21676,21932,23308,23968,24039,25898,25934,26657, +27211,29409,30350,30703,32094,32761,33184,34126,34527,36611,36686,37066,39171, +39509,39851,19992,20037,20061,20167,20465,20855,21246,21312,21475,21477,21646, +22036,22389,22434,23495,23943,24272,25084,25304,25937,26552,26601,27083,27472, +27590,27628,27714,28317,28792,29399,29590,29699,30655,30697,31350,32127,32777, +33276,33285,33290,33503,34914,35635,36092,36544,36881,37041,37476,37558,39378, +39493,40169,40407,40860,22283,23616,33738,38816,38827,40628,21531,31384,32676, +35033,36557,37089,22528,23624,25496,31391,23470,24339,31353,31406,33422,36524, +20518,21048,21240,21367,22280,25331,25458,27402,28099,30519,21413,29527,34152, +36470,38357,26426,27331,28528,35437,36556,39243,63750,26231,27512,36020,39740, +63751,21483,22317,22862,25542,27131,29674,30789,31418,31429,31998,33909,35215, +36211,36917,38312,21243,22343,30023,31584,33740,37406,63752,27224,20811,21067, +21127,25119,26840,26997,38553,20677,21156,21220,25027,26020,26681,27135,29822, +31563,33465,33771,35250,35641,36817,39241,63753,20170,22935,25810,26129,27278, +29748,31105,31165,33449,34942,34943,35167,63754,37670,20235,21450,24613,25201, +27762,32026,32102,20120,20834,30684,32943,20225,20238,20854,20864,21980,22120, +22331,22522,22524,22804,22855,22931,23492,23696,23822,24049,24190,24524,25216, +26071,26083,26398,26399,26462,26827,26820,27231,27450,27683,27773,27778,28103, +29592,29734,29738,29826,29859,30072,30079,30849,30959,31041,31047,31048,31098, +31637,32000,32186,32648,32774,32813,32908,35352,35663,35912,36215,37665,37668, +39138,39249,39438,39439,39525,40594,32202,20342,21513,25326,26708,37329,21931, +20794,63755,63756,23068,25062,63757,25295,25343,63758,63759,63760,63761,63762, +63763,37027,63764,63765,63766,63767,63768,35582,63769,63770,63771,63772,26262, +63773,29014,63774,63775,38627,63776,25423,25466,21335,63777,26511,26976,28275, +63778,30007,63779,63780,63781,32013,63782,63783,34930,22218,23064,63784,63785, +63786,63787,63788,20035,63789,20839,22856,26608,32784,63790,22899,24180,25754, +31178,24565,24684,25288,25467,23527,23511,21162,63791,22900,24361,24594,63792, +63793,63794,29785,63795,63796,63797,63798,63799,63800,39377,63801,63802,63803, +63804,63805,63806,63807,63808,63809,63810,63811,28611,63812,63813,33215,36786, +24817,63814,63815,33126,63816,63817,23615,63818,63819,63820,63821,63822,63823, +63824,63825,23273,35365,26491,32016,63826,63827,63828,63829,63830,63831,33021, +63832,63833,23612,27877,21311,28346,22810,33590,20025,20150,20294,21934,22296, +22727,24406,26039,26086,27264,27573,28237,30701,31471,31774,32222,34507,34962, +37170,37723,25787,28606,29562,30136,36948,21846,22349,25018,25812,26311,28129, +28251,28525,28601,30192,32835,33213,34113,35203,35527,35674,37663,27795,30035, +31572,36367,36957,21776,22530,22616,24162,25095,25758,26848,30070,31958,34739, +40680,20195,22408,22382,22823,23565,23729,24118,24453,25140,25825,29619,33274, +34955,36024,38538,40667,23429,24503,24755,20498,20992,21040,22294,22581,22615, +23566,23648,23798,23947,24230,24466,24764,25361,25481,25623,26691,26873,27330, +28120,28193,28372,28644,29182,30428,30585,31153,31291,33796,35241,36077,36339, +36424,36867,36884,36947,37117,37709,38518,38876,27602,28678,29272,29346,29544, +30563,31167,31716,32411,35712,22697,24775,25958,26109,26302,27788,28958,29129, +35930,38931,20077,31361,20189,20908,20941,21205,21516,24999,26481,26704,26847, +27934,28540,30140,30643,31461,33012,33891,37509,20828,26007,26460,26515,30168, +31431,33651,63834,35910,36887,38957,23663,33216,33434,36929,36975,37389,24471, +23965,27225,29128,30331,31561,34276,35588,37159,39472,21895,25078,63835,30313, +32645,34367,34746,35064,37007,63836,27931,28889,29662,32097,33853,63837,37226, +39409,63838,20098,21365,27396,27410,28734,29211,34349,40478,21068,36771,23888, +25829,25900,27414,28651,31811,32412,34253,35172,35261,25289,33240,34847,24266, +26391,28010,29436,29701,29807,34690,37086,20358,23821,24480,33802,20919,25504, +30053,20142,20486,20841,20937,26753,27153,31918,31921,31975,33391,35538,36635, +37327,20406,20791,21237,21570,24300,24942,25150,26053,27354,28670,31018,34268, +34851,38317,39522,39530,40599,40654,21147,26310,27511,28701,31019,36706,38722, +24976,25088,25891,28451,29001,29833,32244,32879,34030,36646,36899,37706,20925, +21015,21155,27916,28872,35010,24265,25986,27566,28610,31806,29557,20196,20278, +22265,63839,23738,23994,24604,29618,31533,32666,32718,32838,36894,37428,38646, +38728,38936,40801,20363,28583,31150,37300,38583,21214,63840,25736,25796,27347, +28510,28696,29200,30439,32769,34310,34396,36335,36613,38706,39791,40442,40565, +30860,31103,32160,33737,37636,40575,40595,35542,22751,24324,26407,28711,29903, +31840,32894,20769,28712,29282,30922,36034,36058,36084,38647,20102,20698,23534, +24278,26009,29134,30274,30637,32842,34044,36988,39719,40845,22744,23105,23650, +27155,28122,28431,30267,32047,32311,34078,35128,37860,38475,21129,26066,26611, +27060,27969,28316,28687,29705,29792,30041,30244,30827,35628,39006,20845,25134, +38520,20374,20523,23833,28138,32184,36650,24459,24900,26647,63841,38534,21202, +32907,20956,20940,26974,31260,32190,33777,38517,20442,21033,21400,21519,21774, +23653,24743,26446,26792,28012,29313,29432,29702,29827,63842,30178,31852,32633, +32696,33673,35023,35041,37324,37328,38626,39881,21533,28542,29136,29848,34298, +36522,38563,40023,40607,26519,28107,29747,33256,38678,30764,31435,31520,31890, +25705,29802,30194,30908,30952,39340,39764,40635,23518,24149,28448,33180,33707, +37000,19975,21325,23081,24018,24398,24930,25405,26217,26364,28415,28459,28771, +30622,33836,34067,34875,36627,39237,39995,21788,25273,26411,27819,33545,35178, +38778,20129,22916,24536,24537,26395,32178,32596,33426,33579,33725,36638,37017, +22475,22969,23186,23504,26151,26522,26757,27599,29028,32629,36023,36067,36993, +39749,33032,35978,38476,39488,40613,23391,27667,29467,30450,30431,33804,20906, +35219,20813,20885,21193,26825,27796,30468,30496,32191,32236,38754,40629,28357, +34065,20901,21517,21629,26126,26269,26919,28319,30399,30609,33559,33986,34719, +37225,37528,40180,34946,20398,20882,21215,22982,24125,24917,25720,25721,26286, +26576,27169,27597,27611,29279,29281,29761,30520,30683,32791,33468,33541,35584, +35624,35980,26408,27792,29287,30446,30566,31302,40361,27519,27794,22818,26406, +33945,21359,22675,22937,24287,25551,26164,26483,28218,29483,31447,33495,37672, +21209,24043,25006,25035,25098,25287,25771,26080,26969,27494,27595,28961,29687, +30045,32326,33310,33538,34154,35491,36031,38695,40289,22696,40664,20497,21006, +21563,21839,25991,27766,32010,32011,32862,34442,38272,38639,21247,27797,29289, +21619,23194,23614,23883,24396,24494,26410,26806,26979,28220,28228,30473,31859, +32654,34183,35598,36855,38753,40692,23735,24758,24845,25003,25935,26107,26108, +27665,27887,29599,29641,32225,38292,23494,34588,35600,21085,21338,25293,25615, +25778,26420,27192,27850,29632,29854,31636,31893,32283,33162,33334,34180,36843, +38649,39361,20276,21322,21453,21467,25292,25644,25856,26001,27075,27886,28504, +29677,30036,30242,30436,30460,30928,30971,31020,32070,33324,34784,36820,38930, +39151,21187,25300,25765,28196,28497,30332,36299,37297,37474,39662,39747,20515, +20621,22346,22952,23592,24135,24439,25151,25918,26041,26049,26121,26507,27036, +28354,30917,32033,32938,33152,33323,33459,33953,34444,35370,35607,37030,38450, +40848,20493,20467,63843,22521,24472,25308,25490,26479,28227,28953,30403,32972, +32986,35060,35061,35097,36064,36649,37197,38506,20271,20336,24091,26575,26658, +30333,30334,39748,24161,27146,29033,29140,30058,63844,32321,34115,34281,39132, +20240,31567,32624,38309,20961,24070,26805,27710,27726,27867,29359,31684,33539, +27861,29754,20731,21128,22721,25816,27287,29863,30294,30887,34327,38370,38713, +63845,21342,24321,35722,36776,36783,37002,21029,30629,40009,40712,19993,20482, +20853,23643,24183,26142,26170,26564,26821,28851,29953,30149,31177,31453,36647, +39200,39432,20445,22561,22577,23542,26222,27493,27921,28282,28541,29668,29995, +33769,35036,35091,35676,36628,20239,20693,21264,21340,23443,24489,26381,31119, +33145,33583,34068,35079,35206,36665,36667,39333,39954,26412,20086,20472,22857, +23553,23791,23792,25447,26834,28925,29090,29739,32299,34028,34562,36898,37586, +40179,19981,20184,20463,20613,21078,21103,21542,21648,22496,22827,23142,23386, +23413,23500,24220,63846,25206,25975,26023,28014,28325,29238,31526,31807,32566, +33104,33105,33178,33344,33433,33705,35331,36000,36070,36091,36212,36282,37096, +37340,38428,38468,39385,40167,21271,20998,21545,22132,22707,22868,22894,24575, +24996,25198,26128,27774,28954,30406,31881,31966,32027,33452,36033,38640,63847, +20315,24343,24447,25282,23849,26379,26842,30844,32323,40300,19989,20633,21269, +21290,21329,22915,23138,24199,24754,24970,25161,25209,26000,26503,27047,27604, +27606,27607,27608,27832,63848,29749,30202,30738,30865,31189,31192,31875,32203, +32737,32933,33086,33218,33778,34586,35048,35513,35692,36027,37145,38750,39131, +40763,22188,23338,24428,25996,27315,27567,27996,28657,28693,29277,29613,36007, +36051,38971,24977,27703,32856,39425,20045,20107,20123,20181,20282,20284,20351, +20447,20735,21490,21496,21766,21987,22235,22763,22882,23057,23531,23546,23556, +24051,24107,24473,24605,25448,26012,26031,26614,26619,26797,27515,27801,27863, +28195,28681,29509,30722,31038,31040,31072,31169,31721,32023,32114,32902,33293, +33678,34001,34503,35039,35408,35422,35613,36060,36198,36781,37034,39164,39391, +40605,21066,63849,26388,63850,20632,21034,23665,25955,27733,29642,29987,30109, +31639,33948,37240,38704,20087,25746,27578,29022,34217,19977,63851,26441,26862, +28183,33439,34072,34923,25591,28545,37394,39087,19978,20663,20687,20767,21830, +21930,22039,23360,23577,23776,24120,24202,24224,24258,24819,26705,27233,28248, +29245,29248,29376,30456,31077,31665,32724,35059,35316,35443,35937,36062,38684, +22622,29885,36093,21959,63852,31329,32034,33394,29298,29983,29989,63853,31513, +22661,22779,23996,24207,24246,24464,24661,25234,25471,25933,26257,26329,26360, +26646,26866,29312,29790,31598,32110,32214,32626,32997,33298,34223,35199,35475, +36893,37604,40653,40736,22805,22893,24109,24796,26132,26227,26512,27728,28101, +28511,30707,30889,33990,37323,37675,20185,20682,20808,21892,23307,23459,25159, +25982,26059,28210,29053,29697,29764,29831,29887,30316,31146,32218,32341,32680, +33146,33203,33337,34330,34796,35445,36323,36984,37521,37925,39245,39854,21352, +23633,26964,27844,27945,28203,33292,34203,35131,35373,35498,38634,40807,21089, +26297,27570,32406,34814,36109,38275,38493,25885,28041,29166,63854,22478,22995, +23468,24615,24826,25104,26143,26207,29481,29689,30427,30465,31596,32854,32882, +33125,35488,37266,19990,21218,27506,27927,31237,31545,32048,63855,36016,21484, +22063,22609,23477,23567,23569,24034,25152,25475,25620,26157,26803,27836,28040, +28335,28703,28836,29138,29990,30095,30094,30233,31505,31712,31787,32032,32057, +34092,34157,34311,35380,36877,36961,37045,37559,38902,39479,20439,23660,26463, +28049,31903,32396,35606,36118,36895,23403,24061,25613,33984,36956,39137,29575, +23435,24730,26494,28126,35359,35494,36865,38924,21047,63856,28753,30862,37782, +34928,37335,20462,21463,22013,22234,22402,22781,23234,23432,23723,23744,24101, +24833,25101,25163,25480,25628,25910,25976,27193,27530,27700,27929,28465,29159, +29417,29560,29703,29874,30246,30561,31168,31319,31466,31929,32143,32172,32353, +32670,33065,33585,33936,34010,34282,34966,35504,35728,36664,36930,36995,37228, +37526,37561,38539,38567,38568,38614,38656,38920,39318,39635,39706,21460,22654, +22809,23408,23487,28113,28506,29087,29729,29881,32901,33789,24033,24455,24490, +24642,26092,26642,26991,27219,27529,27957,28147,29667,30462,30636,31565,32020, +33059,33308,33600,34036,34147,35426,35524,37255,37662,38918,39348,25100,34899, +36848,37477,23815,23847,23913,29791,33181,34664,28629,25342,32722,35126,35186, +19998,20056,20711,21213,21319,25215,26119,32361,34821,38494,20365,21273,22070, +22987,23204,23608,23630,23629,24066,24337,24643,26045,26159,26178,26558,26612, +29468,30690,31034,32709,33940,33997,35222,35430,35433,35553,35925,35962,22516, +23508,24335,24687,25325,26893,27542,28252,29060,31698,34645,35672,36606,39135, +39166,20280,20353,20449,21627,23072,23480,24892,26032,26216,29180,30003,31070, +32051,33102,33251,33688,34218,34254,34563,35338,36523,36763,63857,36805,22833, +23460,23526,24713,23529,23563,24515,27777,63858,28145,28683,29978,33455,35574, +20160,21313,63859,38617,27663,20126,20420,20818,21854,23077,23784,25105,29273, +33469,33706,34558,34905,35357,38463,38597,39187,40201,40285,22538,23731,23997, +24132,24801,24853,25569,27138,28197,37122,37716,38990,39952,40823,23433,23736, +25353,26191,26696,30524,38593,38797,38996,39839,26017,35585,36555,38332,21813, +23721,24022,24245,26263,30284,33780,38343,22739,25276,29390,40232,20208,22830, +24591,26171,27523,31207,40230,21395,21696,22467,23830,24859,26326,28079,30861, +33406,38552,38724,21380,25212,25494,28082,32266,33099,38989,27387,32588,40367, +40474,20063,20539,20918,22812,24825,25590,26928,29242,32822,63860,37326,24369, +63861,63862,32004,33509,33903,33979,34277,36493,63863,20335,63864,63865,22756, +23363,24665,25562,25880,25965,26264,63866,26954,27171,27915,28673,29036,30162, +30221,31155,31344,63867,32650,63868,35140,63869,35731,37312,38525,63870,39178, +22276,24481,26044,28417,30208,31142,35486,39341,39770,40812,20740,25014,25233, +27277,33222,20547,22576,24422,28937,35328,35578,23420,34326,20474,20796,22196, +22852,25513,28153,23978,26989,20870,20104,20313,63871,63872,63873,22914,63874, +63875,27487,27741,63876,29877,30998,63877,33287,33349,33593,36671,36701,63878, +39192,63879,63880,63881,20134,63882,22495,24441,26131,63883,63884,30123,32377, +35695,63885,36870,39515,22181,22567,23032,23071,23476,63886,24310,63887,63888, +25424,25403,63889,26941,27783,27839,28046,28051,28149,28436,63890,28895,28982, +29017,63891,29123,29141,63892,30799,30831,63893,31605,32227,63894,32303,63895, +34893,36575,63896,63897,63898,37467,63899,40182,63900,63901,63902,24709,28037, +63903,29105,63904,63905,38321,21421,63906,63907,63908,26579,63909,28814,28976, +29744,33398,33490,63910,38331,39653,40573,26308,63911,29121,33865,63912,63913, +22603,63914,63915,23992,24433,63916,26144,26254,27001,27054,27704,27891,28214, +28481,28634,28699,28719,29008,29151,29552,63917,29787,63918,29908,30408,31310, +32403,63919,63920,33521,35424,36814,63921,37704,63922,38681,63923,63924,20034, +20522,63925,21000,21473,26355,27757,28618,29450,30591,31330,33454,34269,34306, +63926,35028,35427,35709,35947,63927,37555,63928,38675,38928,20116,20237,20425, +20658,21320,21566,21555,21978,22626,22714,22887,23067,23524,24735,63929,25034, +25942,26111,26212,26791,27738,28595,28879,29100,29522,31613,34568,35492,39986, +40711,23627,27779,29508,29577,37434,28331,29797,30239,31337,32277,34314,20800, +22725,25793,29934,29973,30320,32705,37013,38605,39252,28198,29926,31401,31402, +33253,34521,34680,35355,23113,23436,23451,26785,26880,28003,29609,29715,29740, +30871,32233,32747,33048,33109,33694,35916,38446,38929,26352,24448,26106,26505, +27754,29579,20525,23043,27498,30702,22806,23916,24013,29477,30031,63930,63931, +20709,20985,22575,22829,22934,23002,23525,63932,63933,23970,25303,25622,25747, +25854,63934,26332,63935,27208,63936,29183,29796,63937,31368,31407,32327,32350, +32768,33136,63938,34799,35201,35616,36953,63939,36992,39250,24958,27442,28020, +32287,35109,36785,20433,20653,20887,21191,22471,22665,23481,24248,24898,27029, +28044,28263,28342,29076,29794,29992,29996,32883,33592,33993,36362,37780,37854, +63940,20110,20305,20598,20778,21448,21451,21491,23431,23507,23588,24858,24962, +26100,29275,29591,29760,30402,31056,31121,31161,32006,32701,33419,34261,34398, +36802,36935,37109,37354,38533,38632,38633,21206,24423,26093,26161,26671,29020, +31286,37057,38922,20113,63941,27218,27550,28560,29065,32792,33464,34131,36939, +38549,38642,38907,34074,39729,20112,29066,38596,20803,21407,21729,22291,22290, +22435,23195,23236,23491,24616,24895,25588,27781,27961,28274,28304,29232,29503, +29783,33489,34945,36677,36960,63942,38498,39000,40219,26376,36234,37470,20301, +20553,20702,21361,22285,22996,23041,23561,24944,26256,28205,29234,29771,32239, +32963,33806,33894,34111,34655,34907,35096,35586,36949,38859,39759,20083,20369, +20754,20842,63943,21807,21929,23418,23461,24188,24189,24254,24736,24799,24840, +24841,25540,25912,26377,63944,26580,26586,63945,26977,26978,27833,27943,63946, +28216,63947,28641,29494,29495,63948,29788,30001,63949,30290,63950,63951,32173, +33278,33848,35029,35480,35547,35565,36400,36418,36938,36926,36986,37193,37321, +37742,63952,63953,22537,63954,27603,32905,32946,63955,63956,20801,22891,23609, +63957,63958,28516,29607,32996,36103,63959,37399,38287,63960,63961,63962,63963, +32895,25102,28700,32104,34701,63964,22432,24681,24903,27575,35518,37504,38577, +20057,21535,28139,34093,38512,38899,39150,25558,27875,37009,20957,25033,33210, +40441,20381,20506,20736,23452,24847,25087,25836,26885,27589,30097,30691,32681, +33380,34191,34811,34915,35516,35696,37291,20108,20197,20234,63965,63966,22839, +23016,63967,24050,24347,24411,24609,63968,63969,63970,63971,29246,29669,63972, +30064,30157,63973,31227,63974,32780,32819,32900,33505,33617,63975,63976,36029, +36019,36999,63977,63978,39156,39180,63979,63980,28727,30410,32714,32716,32764, +35610,20154,20161,20995,21360,63981,21693,22240,23035,23493,24341,24525,28270, +63982,63983,32106,33589,63984,34451,35469,63985,38765,38775,63986,63987,19968, +20314,20350,22777,26085,28322,36920,37808,39353,20219,22764,22922,23001,24641, +63988,63989,31252,63990,33615,36035,20837,21316,63991,63992,63993,20173,21097, +23381,33471,20180,21050,21672,22985,23039,23376,23383,23388,24675,24904,28363, +28825,29038,29574,29943,30133,30913,32043,32773,33258,33576,34071,34249,35566, +36039,38604,20316,21242,22204,26027,26152,28796,28856,29237,32189,33421,37196, +38592,40306,23409,26855,27544,28538,30430,23697,26283,28507,31668,31786,34870, +38620,19976,20183,21280,22580,22715,22767,22892,23559,24115,24196,24373,25484, +26290,26454,27167,27299,27404,28479,29254,63994,29520,29835,31456,31911,33144, +33247,33255,33674,33900,34083,34196,34255,35037,36115,37292,38263,38556,20877, +21705,22312,23472,25165,26448,26685,26771,28221,28371,28797,32289,35009,36001, +36617,40779,40782,29229,31631,35533,37658,20295,20302,20786,21632,22992,24213, +25269,26485,26990,27159,27822,28186,29401,29482,30141,31672,32053,33511,33785, +33879,34295,35419,36015,36487,36889,37048,38606,40799,21219,21514,23265,23490, +25688,25973,28404,29380,63995,30340,31309,31515,31821,32318,32735,33659,35627, +36042,36196,36321,36447,36842,36857,36969,37841,20291,20346,20659,20840,20856, +21069,21098,22625,22652,22880,23560,23637,24283,24731,25136,26643,27583,27656, +28593,29006,29728,30000,30008,30033,30322,31564,31627,31661,31686,32399,35438, +36670,36681,37439,37523,37666,37931,38651,39002,39019,39198,20999,25130,25240, +27993,30308,31434,31680,32118,21344,23742,24215,28472,28857,31896,38673,39822, +40670,25509,25722,34678,19969,20117,20141,20572,20597,21576,22979,23450,24128, +24237,24311,24449,24773,25402,25919,25972,26060,26230,26232,26622,26984,27273, +27491,27712,28096,28136,28191,28254,28702,28833,29582,29693,30010,30555,30855, +31118,31243,31357,31934,32142,33351,35330,35562,35998,37165,37194,37336,37478, +37580,37664,38662,38742,38748,38914,40718,21046,21137,21884,22564,24093,24351, +24716,25552,26799,28639,31085,31532,33229,34234,35069,35576,36420,37261,38500, +38555,38717,38988,40778,20430,20806,20939,21161,22066,24340,24427,25514,25805, +26089,26177,26362,26361,26397,26781,26839,27133,28437,28526,29031,29157,29226, +29866,30522,31062,31066,31199,31264,31381,31895,31967,32068,32368,32903,34299, +34468,35412,35519,36249,36481,36896,36973,37347,38459,38613,40165,26063,31751, +36275,37827,23384,23562,21330,25305,29469,20519,23447,24478,24752,24939,26837, +28121,29742,31278,32066,32156,32305,33131,36394,36405,37758,37912,20304,22352, +24038,24231,25387,32618,20027,20303,20367,20570,23005,32964,21610,21608,22014, +22863,23449,24030,24282,26205,26417,26609,26666,27880,27954,28234,28557,28855, +29664,30087,31820,32002,32044,32162,33311,34523,35387,35461,36208,36490,36659, +36913,37198,37202,37956,39376,31481,31909,20426,20737,20934,22472,23535,23803, +26201,27197,27994,28310,28652,28940,30063,31459,34850,36897,36981,38603,39423, +33537,20013,20210,34886,37325,21373,27355,26987,27713,33914,22686,24974,26366, +25327,28893,29969,30151,32338,33976,35657,36104,20043,21482,21675,22320,22336, +24535,25345,25351,25711,25903,26088,26234,26525,26547,27490,27744,27802,28460, +30693,30757,31049,31063,32025,32930,33026,33267,33437,33463,34584,35468,63996, +36100,36286,36978,30452,31257,31287,32340,32887,21767,21972,22645,25391,25634, +26185,26187,26733,27035,27524,27941,28337,29645,29800,29857,30043,30137,30433, +30494,30603,31206,32265,32285,33275,34095,34967,35386,36049,36587,36784,36914, +37805,38499,38515,38663,20356,21489,23018,23241,24089,26702,29894,30142,31209, +31378,33187,34541,36074,36300,36845,26015,26389,63997,22519,28503,32221,36655, +37878,38598,24501,25074,28548,19988,20376,20511,21449,21983,23919,24046,27425, +27492,30923,31642,63998,36425,36554,36974,25417,25662,30528,31364,37679,38015, +40810,25776,28591,29158,29864,29914,31428,31762,32386,31922,32408,35738,36106, +38013,39184,39244,21049,23519,25830,26413,32046,20717,21443,22649,24920,24921, +25082,26028,31449,35730,35734,20489,20513,21109,21809,23100,24288,24432,24884, +25950,26124,26166,26274,27085,28356,28466,29462,30241,31379,33081,33369,33750, +33980,20661,22512,23488,23528,24425,25505,30758,32181,33756,34081,37319,37365, +20874,26613,31574,36012,20932,22971,24765,34389,20508,63999,21076,23610,24957, +25114,25299,25842,26021,28364,30240,33034,36448,38495,38587,20191,21315,21912, +22825,24029,25797,27849,28154,29588,31359,33307,34214,36068,36368,36983,37351, +38369,38433,38854,20984,21746,21894,24505,25764,28552,32180,36639,36685,37941, +20681,23574,27838,28155,29979,30651,31805,31844,35449,35522,22558,22974,24086, +25463,29266,30090,30571,35548,36028,36626,24307,26228,28152,32893,33729,35531, +38737,39894,64000,21059,26367,28053,28399,32224,35558,36910,36958,39636,21021, +21119,21736,24980,25220,25307,26786,26898,26970,27189,28818,28966,30813,30977, +30990,31186,31245,32918,33400,33493,33609,34121,35970,36229,37218,37259,37294, +20419,22225,29165,30679,34560,35320,23544,24534,26449,37032,21474,22618,23541, +24740,24961,25696,32317,32880,34085,37507,25774,20652,23828,26368,22684,25277, +25512,26894,27000,27166,28267,30394,31179,33467,33833,35535,36264,36861,37138, +37195,37276,37648,37656,37786,38619,39478,39949,19985,30044,31069,31482,31569, +31689,32302,33988,36441,36468,36600,36880,26149,26943,29763,20986,26414,40668, +20805,24544,27798,34802,34909,34935,24756,33205,33795,36101,21462,21561,22068, +23094,23601,28810,32736,32858,33030,33261,36259,37257,39519,40434,20596,20164, +21408,24827,28204,23652,20360,20516,21988,23769,24159,24677,26772,27835,28100, +29118,30164,30196,30305,31258,31305,32199,32251,32622,33268,34473,36636,38601, +39347,40786,21063,21189,39149,35242,19971,26578,28422,20405,23522,26517,27784, +28024,29723,30759,37341,37756,34756,31204,31281,24555,20182,21668,21822,22702, +22949,24816,25171,25302,26422,26965,33333,38464,39345,39389,20524,21331,21828, +22396,64001,25176,64002,25826,26219,26589,28609,28655,29730,29752,35351,37944, +21585,22022,22374,24392,24986,27470,28760,28845,32187,35477,22890,33067,25506, +30472,32829,36010,22612,25645,27067,23445,24081,28271,64003,34153,20812,21488, +22826,24608,24907,27526,27760,27888,31518,32974,33492,36294,37040,39089,64004, +25799,28580,25745,25860,20814,21520,22303,35342,24927,26742,64005,30171,31570, +32113,36890,22534,27084,33151,35114,36864,38969,20600,22871,22956,25237,36879, +39722,24925,29305,38358,22369,23110,24052,25226,25773,25850,26487,27874,27966, +29228,29750,30772,32631,33453,36315,38935,21028,22338,26495,29256,29923,36009, +36774,37393,38442,20843,21485,25420,20329,21764,24726,25943,27803,28031,29260, +29437,31255,35207,35997,24429,28558,28921,33192,24846,20415,20559,25153,29255, +31687,32232,32745,36941,38829,39449,36022,22378,24179,26544,33805,35413,21536, +23318,24163,24290,24330,25987,32954,34109,38281,38491,20296,21253,21261,21263, +21638,21754,22275,24067,24598,25243,25265,25429,64006,27873,28006,30129,30770, +32990,33071,33502,33889,33970,34957,35090,36875,37610,39165,39825,24133,26292, +26333,28689,29190,64007,20469,21117,24426,24915,26451,27161,28418,29922,31080, +34920,35961,39111,39108,39491,21697,31263,26963,35575,35914,39080,39342,24444, +25259,30130,30382,34987,36991,38466,21305,24380,24517,27852,29644,30050,30091, +31558,33534,39325,20047,36924,19979,20309,21414,22799,24264,26160,27827,29781, +33655,34662,36032,36944,38686,39957,22737,23416,34384,35604,40372,23506,24680, +24717,26097,27735,28450,28579,28698,32597,32752,38289,38290,38480,38867,21106, +36676,20989,21547,21688,21859,21898,27323,28085,32216,33382,37532,38519,40569, +21512,21704,30418,34532,38308,38356,38492,20130,20233,23022,23270,24055,24658, +25239,26477,26689,27782,28207,32568,32923,33322,64008,64009,38917,20133,20565, +21683,22419,22874,23401,23475,25032,26999,28023,28707,34809,35299,35442,35559, +36994,39405,39608,21182,26680,20502,24184,26447,33607,34892,20139,21521,22190, +29670,37141,38911,39177,39255,39321,22099,22687,34395,35377,25010,27382,29563, +36562,27463,38570,39511,22869,29184,36203,38761,20436,23796,24358,25080,26203, +27883,28843,29572,29625,29694,30505,30541,32067,32098,32291,33335,34898,64010, +36066,37449,39023,23377,31348,34880,38913,23244,20448,21332,22846,23805,25406, +28025,29433,33029,33031,33698,37583,38960,20136,20804,21009,22411,24418,27842, +28366,28677,28752,28847,29074,29673,29801,33610,34722,34913,36872,37026,37795, +39336,20846,24407,24800,24935,26291,34137,36426,37295,38795,20046,20114,21628, +22741,22778,22909,23733,24359,25142,25160,26122,26215,27627,28009,28111,28246, +28408,28564,28640,28649,28765,29392,29733,29786,29920,30355,31068,31946,32286, +32993,33446,33899,33983,34382,34399,34676,35703,35946,37804,38912,39013,24785, +25110,37239,23130,26127,28151,28222,29759,39746,24573,24794,31503,21700,24344, +27742,27859,27946,28888,32005,34425,35340,40251,21270,21644,23301,27194,28779, +30069,31117,31166,33457,33775,35441,35649,36008,38772,64011,25844,25899,30906, +30907,31339,20024,21914,22864,23462,24187,24739,25563,27489,26213,26707,28185, +29029,29872,32008,36996,39529,39973,27963,28369,29502,35905,38346,20976,24140, +24488,24653,24822,24880,24908,26179,26180,27045,27841,28255,28361,28514,29004, +29852,30343,31681,31783,33618,34647,36945,38541,40643,21295,22238,24315,24458, +24674,24724,25079,26214,26371,27292,28142,28590,28784,29546,32362,33214,33588, +34516,35496,36036,21123,29554,23446,27243,37892,21742,22150,23389,25928,25989, +26313,26783,28045,28102,29243,32948,37237,39501,20399,20505,21402,21518,21564, +21897,21957,24127,24460,26429,29030,29661,36869,21211,21235,22628,22734,28932, +29071,29179,34224,35347,26248,34216,21927,26244,29002,33841,21321,21913,27585, +24409,24509,25582,26249,28999,35569,36637,40638,20241,25658,28875,30054,34407, +24676,35662,40440,20807,20982,21256,27958,33016,40657,26133,27427,28824,30165, +21507,23673,32007,35350,27424,27453,27462,21560,24688,27965,32725,33288,20694, +20958,21916,22123,22221,23020,23305,24076,24985,24984,25137,26206,26342,29081, +29113,29114,29351,31143,31232,32690,35440, +}; + +static const struct dbcs_index ksx1001_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__ksx1001_decmap+0,33,126},{__ksx1001_decmap+ +94,33,103},{__ksx1001_decmap+165,33,126},{__ksx1001_decmap+259,33,126},{ +__ksx1001_decmap+353,33,120},{__ksx1001_decmap+441,33,100},{__ksx1001_decmap+ +509,33,111},{__ksx1001_decmap+588,33,126},{__ksx1001_decmap+682,33,126},{ +__ksx1001_decmap+776,33,115},{__ksx1001_decmap+859,33,118},{__ksx1001_decmap+ +945,33,113},{0,0,0},{0,0,0},{0,0,0},{__ksx1001_decmap+1026,33,126},{ +__ksx1001_decmap+1120,33,126},{__ksx1001_decmap+1214,33,126},{__ksx1001_decmap ++1308,33,126},{__ksx1001_decmap+1402,33,126},{__ksx1001_decmap+1496,33,126},{ +__ksx1001_decmap+1590,33,126},{__ksx1001_decmap+1684,33,126},{__ksx1001_decmap ++1778,33,126},{__ksx1001_decmap+1872,33,126},{__ksx1001_decmap+1966,33,126},{ +__ksx1001_decmap+2060,33,126},{__ksx1001_decmap+2154,33,126},{__ksx1001_decmap ++2248,33,126},{__ksx1001_decmap+2342,33,126},{__ksx1001_decmap+2436,33,126},{ +__ksx1001_decmap+2530,33,126},{__ksx1001_decmap+2624,33,126},{__ksx1001_decmap ++2718,33,126},{__ksx1001_decmap+2812,33,126},{__ksx1001_decmap+2906,33,126},{ +__ksx1001_decmap+3000,33,126},{__ksx1001_decmap+3094,33,126},{__ksx1001_decmap ++3188,33,126},{__ksx1001_decmap+3282,33,126},{0,0,0},{__ksx1001_decmap+3376, +33,126},{__ksx1001_decmap+3470,33,126},{__ksx1001_decmap+3564,33,126},{ +__ksx1001_decmap+3658,33,126},{__ksx1001_decmap+3752,33,126},{__ksx1001_decmap ++3846,33,126},{__ksx1001_decmap+3940,33,126},{__ksx1001_decmap+4034,33,126},{ +__ksx1001_decmap+4128,33,126},{__ksx1001_decmap+4222,33,126},{__ksx1001_decmap ++4316,33,126},{__ksx1001_decmap+4410,33,126},{__ksx1001_decmap+4504,33,126},{ +__ksx1001_decmap+4598,33,126},{__ksx1001_decmap+4692,33,126},{__ksx1001_decmap ++4786,33,126},{__ksx1001_decmap+4880,33,126},{__ksx1001_decmap+4974,33,126},{ +__ksx1001_decmap+5068,33,126},{__ksx1001_decmap+5162,33,126},{__ksx1001_decmap ++5256,33,126},{__ksx1001_decmap+5350,33,126},{__ksx1001_decmap+5444,33,126},{ +__ksx1001_decmap+5538,33,126},{__ksx1001_decmap+5632,33,126},{__ksx1001_decmap ++5726,33,126},{__ksx1001_decmap+5820,33,126},{__ksx1001_decmap+5914,33,126},{ +__ksx1001_decmap+6008,33,126},{__ksx1001_decmap+6102,33,126},{__ksx1001_decmap ++6196,33,126},{__ksx1001_decmap+6290,33,126},{__ksx1001_decmap+6384,33,126},{ +__ksx1001_decmap+6478,33,126},{__ksx1001_decmap+6572,33,126},{__ksx1001_decmap ++6666,33,126},{__ksx1001_decmap+6760,33,126},{__ksx1001_decmap+6854,33,126},{ +__ksx1001_decmap+6948,33,126},{__ksx1001_decmap+7042,33,126},{__ksx1001_decmap ++7136,33,126},{__ksx1001_decmap+7230,33,126},{__ksx1001_decmap+7324,33,126},{ +__ksx1001_decmap+7418,33,126},{__ksx1001_decmap+7512,33,126},{__ksx1001_decmap ++7606,33,126},{__ksx1001_decmap+7700,33,126},{__ksx1001_decmap+7794,33,126},{ +__ksx1001_decmap+7888,33,126},{__ksx1001_decmap+7982,33,126},{__ksx1001_decmap ++8076,33,126},{__ksx1001_decmap+8170,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +}, +}; + +static const ucs2_t __cp949ext_decmap[9650] = { +44034,44035,44037,44038,44043,44044,44045,44046,44047,44056,44062,44063,44065, +44066,44067,44069,44070,44071,44072,44073,44074,44075,44078,44082,44083,44084, +U,U,U,U,U,U,44085,44086,44087,44090,44091,44093,44094,44095,44097,44098,44099, +44100,44101,44102,44103,44104,44105,44106,44108,44110,44111,44112,44113,44114, +44115,44117,U,U,U,U,U,U,44118,44119,44121,44122,44123,44125,44126,44127,44128, +44129,44130,44131,44132,44133,44134,44135,44136,44137,44138,44139,44140,44141, +44142,44143,44146,44147,44149,44150,44153,44155,44156,44157,44158,44159,44162, +44167,44168,44173,44174,44175,44177,44178,44179,44181,44182,44183,44184,44185, +44186,44187,44190,44194,44195,44196,44197,44198,44199,44203,44205,44206,44209, +44210,44211,44212,44213,44214,44215,44218,44222,44223,44224,44226,44227,44229, +44230,44231,44233,44234,44235,44237,44238,44239,44240,44241,44242,44243,44244, +44246,44248,44249,44250,44251,44252,44253,44254,44255,44258,44259,44261,44262, +44265,44267,44269,44270,44274,44276,44279,44280,44281,44282,44283,44286,44287, +44289,44290,44291,44293,44295,44296,44297,44298,44299,44302,44304,44306,44307, +44308,44309,44310,44311,44313,44314,44315,44317,44318,44319,44321,44322,44323, +44324,44325,44326,44327,44328,44330,44331,44334,44335,44336,44337,44338,44339, +U,U,U,U,U,U,44342,44343,44345,44346,44347,44349,44350,44351,44352,44353,44354, +44355,44358,44360,44362,44363,44364,44365,44366,44367,44369,44370,44371,44373, +44374,44375,U,U,U,U,U,U,44377,44378,44379,44380,44381,44382,44383,44384,44386, +44388,44389,44390,44391,44392,44393,44394,44395,44398,44399,44401,44402,44407, +44408,44409,44410,44414,44416,44419,44420,44421,44422,44423,44426,44427,44429, +44430,44431,44433,44434,44435,44436,44437,44438,44439,44440,44441,44442,44443, +44446,44447,44448,44449,44450,44451,44453,44454,44455,44456,44457,44458,44459, +44460,44461,44462,44463,44464,44465,44466,44467,44468,44469,44470,44472,44473, +44474,44475,44476,44477,44478,44479,44482,44483,44485,44486,44487,44489,44490, +44491,44492,44493,44494,44495,44498,44500,44501,44502,44503,44504,44505,44506, +44507,44509,44510,44511,44513,44514,44515,44517,44518,44519,44520,44521,44522, +44523,44524,44525,44526,44527,44528,44529,44530,44531,44532,44533,44534,44535, +44538,44539,44541,44542,44546,44547,44548,44549,44550,44551,44554,44556,44558, +44559,44560,44561,44562,44563,44565,44566,44567,44568,44569,44570,44571,44572, +U,U,U,U,U,U,44573,44574,44575,44576,44577,44578,44579,44580,44581,44582,44583, +44584,44585,44586,44587,44588,44589,44590,44591,44594,44595,44597,44598,44601, +44603,44604,U,U,U,U,U,U,44605,44606,44607,44610,44612,44615,44616,44617,44619, +44623,44625,44626,44627,44629,44631,44632,44633,44634,44635,44638,44642,44643, +44644,44646,44647,44650,44651,44653,44654,44655,44657,44658,44659,44660,44661, +44662,44663,44666,44670,44671,44672,44673,44674,44675,44678,44679,44680,44681, +44682,44683,44685,44686,44687,44688,44689,44690,44691,44692,44693,44694,44695, +44696,44697,44698,44699,44700,44701,44702,44703,44704,44705,44706,44707,44708, +44709,44710,44711,44712,44713,44714,44715,44716,44717,44718,44719,44720,44721, +44722,44723,44724,44725,44726,44727,44728,44729,44730,44731,44735,44737,44738, +44739,44741,44742,44743,44744,44745,44746,44747,44750,44754,44755,44756,44757, +44758,44759,44762,44763,44765,44766,44767,44768,44769,44770,44771,44772,44773, +44774,44775,44777,44778,44780,44782,44783,44784,44785,44786,44787,44789,44790, +44791,44793,44794,44795,44797,44798,44799,44800,44801,44802,44803,44804,44805, +U,U,U,U,U,U,44806,44809,44810,44811,44812,44814,44815,44817,44818,44819,44820, +44821,44822,44823,44824,44825,44826,44827,44828,44829,44830,44831,44832,44833, +44834,44835,U,U,U,U,U,U,44836,44837,44838,44839,44840,44841,44842,44843,44846, +44847,44849,44851,44853,44854,44855,44856,44857,44858,44859,44862,44864,44868, +44869,44870,44871,44874,44875,44876,44877,44878,44879,44881,44882,44883,44884, +44885,44886,44887,44888,44889,44890,44891,44894,44895,44896,44897,44898,44899, +44902,44903,44904,44905,44906,44907,44908,44909,44910,44911,44912,44913,44914, +44915,44916,44917,44918,44919,44920,44922,44923,44924,44925,44926,44927,44929, +44930,44931,44933,44934,44935,44937,44938,44939,44940,44941,44942,44943,44946, +44947,44948,44950,44951,44952,44953,44954,44955,44957,44958,44959,44960,44961, +44962,44963,44964,44965,44966,44967,44968,44969,44970,44971,44972,44973,44974, +44975,44976,44977,44978,44979,44980,44981,44982,44983,44986,44987,44989,44990, +44991,44993,44994,44995,44996,44997,44998,45002,45004,45007,45008,45009,45010, +45011,45013,45014,45015,45016,45017,45018,45019,45021,45022,45023,45024,45025, +U,U,U,U,U,U,45026,45027,45028,45029,45030,45031,45034,45035,45036,45037,45038, +45039,45042,45043,45045,45046,45047,45049,45050,45051,45052,45053,45054,45055, +45058,45059,U,U,U,U,U,U,45061,45062,45063,45064,45065,45066,45067,45069,45070, +45071,45073,45074,45075,45077,45078,45079,45080,45081,45082,45083,45086,45087, +45088,45089,45090,45091,45092,45093,45094,45095,45097,45098,45099,45100,45101, +45102,45103,45104,45105,45106,45107,45108,45109,45110,45111,45112,45113,45114, +45115,45116,45117,45118,45119,45120,45121,45122,45123,45126,45127,45129,45131, +45133,45135,45136,45137,45138,45142,45144,45146,45147,45148,45150,45151,45152, +45153,45154,45155,45156,45157,45158,45159,45160,45161,45162,45163,45164,45165, +45166,45167,45168,45169,45170,45171,45172,45173,45174,45175,45176,45177,45178, +45179,45182,45183,45185,45186,45187,45189,45190,45191,45192,45193,45194,45195, +45198,45200,45202,45203,45204,45205,45206,45207,45211,45213,45214,45219,45220, +45221,45222,45223,45226,45232,45234,45238,45239,45241,45242,45243,45245,45246, +45247,45248,45249,45250,45251,45254,45258,45259,45260,45261,45262,45263,45266, +U,U,U,U,U,U,45267,45269,45270,45271,45273,45274,45275,45276,45277,45278,45279, +45281,45282,45283,45284,45286,45287,45288,45289,45290,45291,45292,45293,45294, +45295,45296,U,U,U,U,U,U,45297,45298,45299,45300,45301,45302,45303,45304,45305, +45306,45307,45308,45309,45310,45311,45312,45313,45314,45315,45316,45317,45318, +45319,45322,45325,45326,45327,45329,45332,45333,45334,45335,45338,45342,45343, +45344,45345,45346,45350,45351,45353,45354,45355,45357,45358,45359,45360,45361, +45362,45363,45366,45370,45371,45372,45373,45374,45375,45378,45379,45381,45382, +45383,45385,45386,45387,45388,45389,45390,45391,45394,45395,45398,45399,45401, +45402,45403,45405,45406,45407,45409,45410,45411,45412,45413,45414,45415,45416, +45417,45418,45419,45420,45421,45422,45423,45424,45425,45426,45427,45428,45429, +45430,45431,45434,45435,45437,45438,45439,45441,45443,45444,45445,45446,45447, +45450,45452,45454,45455,45456,45457,45461,45462,45463,45465,45466,45467,45469, +45470,45471,45472,45473,45474,45475,45476,45477,45478,45479,45481,45482,45483, +45484,45485,45486,45487,45488,45489,45490,45491,45492,45493,45494,45495,45496, +U,U,U,U,U,U,45497,45498,45499,45500,45501,45502,45503,45504,45505,45506,45507, +45508,45509,45510,45511,45512,45513,45514,45515,45517,45518,45519,45521,45522, +45523,45525,U,U,U,U,U,U,45526,45527,45528,45529,45530,45531,45534,45536,45537, +45538,45539,45540,45541,45542,45543,45546,45547,45549,45550,45551,45553,45554, +45555,45556,45557,45558,45559,45560,45562,45564,45566,45567,45568,45569,45570, +45571,45574,45575,45577,45578,45581,45582,45583,45584,45585,45586,45587,45590, +45592,45594,45595,45596,45597,45598,45599,45601,45602,45603,45604,45605,45606, +45607,45608,45609,45610,45611,45612,45613,45614,45615,45616,45617,45618,45619, +45621,45622,45623,45624,45625,45626,45627,45629,45630,45631,45632,45633,45634, +45635,45636,45637,45638,45639,45640,45641,45642,45643,45644,45645,45646,45647, +45648,45649,45650,45651,45652,45653,45654,45655,45657,45658,45659,45661,45662, +45663,45665,45666,45667,45668,45669,45670,45671,45674,45675,45676,45677,45678, +45679,45680,45681,45682,45683,45686,45687,45688,45689,45690,45691,45693,45694, +45695,45696,45697,45698,45699,45702,45703,45704,45706,45707,45708,45709,45710, +U,U,U,U,U,U,45711,45714,45715,45717,45718,45719,45723,45724,45725,45726,45727, +45730,45732,45735,45736,45737,45739,45741,45742,45743,45745,45746,45747,45749, +45750,45751,U,U,U,U,U,U,45752,45753,45754,45755,45756,45757,45758,45759,45760, +45761,45762,45763,45764,45765,45766,45767,45770,45771,45773,45774,45775,45777, +45779,45780,45781,45782,45783,45786,45788,45790,45791,45792,45793,45795,45799, +45801,45802,45808,45809,45810,45814,45820,45821,45822,45826,45827,45829,45830, +45831,45833,45834,45835,45836,45837,45838,45839,45842,45846,45847,45848,45849, +45850,45851,45853,45854,45855,45856,45857,45858,45859,45860,45861,45862,45863, +45864,45865,45866,45867,45868,45869,45870,45871,45872,45873,45874,45875,45876, +45877,45878,45879,45880,45881,45882,45883,45884,45885,45886,45887,45888,45889, +45890,45891,45892,45893,45894,45895,45896,45897,45898,45899,45900,45901,45902, +45903,45904,45905,45906,45907,45911,45913,45914,45917,45920,45921,45922,45923, +45926,45928,45930,45932,45933,45935,45938,45939,45941,45942,45943,45945,45946, +45947,45948,45949,45950,45951,45954,45958,45959,45960,45961,45962,45963,45965, +U,U,U,U,U,U,45966,45967,45969,45970,45971,45973,45974,45975,45976,45977,45978, +45979,45980,45981,45982,45983,45986,45987,45988,45989,45990,45991,45993,45994, +45995,45997,U,U,U,U,U,U,45998,45999,46000,46001,46002,46003,46004,46005,46006, +46007,46008,46009,46010,46011,46012,46013,46014,46015,46016,46017,46018,46019, +46022,46023,46025,46026,46029,46031,46033,46034,46035,46038,46040,46042,46044, +46046,46047,46049,46050,46051,46053,46054,46055,46057,46058,46059,46060,46061, +46062,46063,46064,46065,46066,46067,46068,46069,46070,46071,46072,46073,46074, +46075,46077,46078,46079,46080,46081,46082,46083,46084,46085,46086,46087,46088, +46089,46090,46091,46092,46093,46094,46095,46097,46098,46099,46100,46101,46102, +46103,46105,46106,46107,46109,46110,46111,46113,46114,46115,46116,46117,46118, +46119,46122,46124,46125,46126,46127,46128,46129,46130,46131,46133,46134,46135, +46136,46137,46138,46139,46140,46141,46142,46143,46144,46145,46146,46147,46148, +46149,46150,46151,46152,46153,46154,46155,46156,46157,46158,46159,46162,46163, +46165,46166,46167,46169,46170,46171,46172,46173,46174,46175,46178,46180,46182, +U,U,U,U,U,U,46183,46184,46185,46186,46187,46189,46190,46191,46192,46193,46194, +46195,46196,46197,46198,46199,46200,46201,46202,46203,46204,46205,46206,46207, +46209,46210,U,U,U,U,U,U,46211,46212,46213,46214,46215,46217,46218,46219,46220, +46221,46222,46223,46224,46225,46226,46227,46228,46229,46230,46231,46232,46233, +46234,46235,46236,46238,46239,46240,46241,46242,46243,46245,46246,46247,46249, +46250,46251,46253,46254,46255,46256,46257,46258,46259,46260,46262,46264,46266, +46267,46268,46269,46270,46271,46273,46274,46275,46277,46278,46279,46281,46282, +46283,46284,46285,46286,46287,46289,46290,46291,46292,46294,46295,46296,46297, +46298,46299,46302,46303,46305,46306,46309,46311,46312,46313,46314,46315,46318, +46320,46322,46323,46324,46325,46326,46327,46329,46330,46331,46332,46333,46334, +46335,46336,46337,46338,46339,46340,46341,46342,46343,46344,46345,46346,46347, +46348,46349,46350,46351,46352,46353,46354,46355,46358,46359,46361,46362,46365, +46366,46367,46368,46369,46370,46371,46374,46379,46380,46381,46382,46383,46386, +46387,46389,46390,46391,46393,46394,46395,46396,46397,46398,46399,46402,46406, +U,U,U,U,U,U,46407,46408,46409,46410,46414,46415,46417,46418,46419,46421,46422, +46423,46424,46425,46426,46427,46430,46434,46435,46436,46437,46438,46439,46440, +46441,46442,U,U,U,U,U,U,46443,46444,46445,46446,46447,46448,46449,46450,46451, +46452,46453,46454,46455,46456,46457,46458,46459,46460,46461,46462,46463,46464, +46465,46466,46467,46468,46469,46470,46471,46472,46473,46474,46475,46476,46477, +46478,46479,46480,46481,46482,46483,46484,46485,46486,46487,46488,46489,46490, +46491,46492,46493,46494,46495,46498,46499,46501,46502,46503,46505,46508,46509, +46510,46511,46514,46518,46519,46520,46521,46522,46526,46527,46529,46530,46531, +46533,46534,46535,46536,46537,46538,46539,46542,46546,46547,46548,46549,46550, +46551,46553,46554,46555,46556,46557,46558,46559,46560,46561,46562,46563,46564, +46565,46566,46567,46568,46569,46570,46571,46573,46574,46575,46576,46577,46578, +46579,46580,46581,46582,46583,46584,46585,46586,46587,46588,46589,46590,46591, +46592,46593,46594,46595,46596,46597,46598,46599,46600,46601,46602,46603,46604, +46605,46606,46607,46610,46611,46613,46614,46615,46617,46618,46619,46620,46621, +U,U,U,U,U,U,46622,46623,46624,46625,46626,46627,46628,46630,46631,46632,46633, +46634,46635,46637,46638,46639,46640,46641,46642,46643,46645,46646,46647,46648, +46649,46650,U,U,U,U,U,U,46651,46652,46653,46654,46655,46656,46657,46658,46659, +46660,46661,46662,46663,46665,46666,46667,46668,46669,46670,46671,46672,46673, +46674,46675,46676,46677,46678,46679,46680,46681,46682,46683,46684,46685,46686, +46687,46688,46689,46690,46691,46693,46694,46695,46697,46698,46699,46700,46701, +46702,46703,46704,46705,46706,46707,46708,46709,46710,46711,46712,46713,46714, +46715,46716,46717,46718,46719,46720,46721,46722,46723,46724,46725,46726,46727, +46728,46729,46730,46731,46732,46733,46734,46735,46736,46737,46738,46739,46740, +46741,46742,46743,46744,46745,46746,46747,46750,46751,46753,46754,46755,46757, +46758,46759,46760,46761,46762,46765,46766,46767,46768,46770,46771,46772,46773, +46774,46775,46776,46777,46778,46779,46780,46781,46782,46783,46784,46785,46786, +46787,46788,46789,46790,46791,46792,46793,46794,46795,46796,46797,46798,46799, +46800,46801,46802,46803,46805,46806,46807,46808,46809,46810,46811,46812,46813, +U,U,U,U,U,U,46814,46815,46816,46817,46818,46819,46820,46821,46822,46823,46824, +46825,46826,46827,46828,46829,46830,46831,46833,46834,46835,46837,46838,46839, +46841,46842,U,U,U,U,U,U,46843,46844,46845,46846,46847,46850,46851,46852,46854, +46855,46856,46857,46858,46859,46860,46861,46862,46863,46864,46865,46866,46867, +46868,46869,46870,46871,46872,46873,46874,46875,46876,46877,46878,46879,46880, +46881,46882,46883,46884,46885,46886,46887,46890,46891,46893,46894,46897,46898, +46899,46900,46901,46902,46903,46906,46908,46909,46910,46911,46912,46913,46914, +46915,46917,46918,46919,46921,46922,46923,46925,46926,46927,46928,46929,46930, +46931,46934,46935,46936,46937,46938,46939,46940,46941,46942,46943,46945,46946, +46947,46949,46950,46951,46953,46954,46955,46956,46957,46958,46959,46962,46964, +46966,46967,46968,46969,46970,46971,46974,46975,46977,46978,46979,46981,46982, +46983,46984,46985,46986,46987,46990,46995,46996,46997,47002,47003,47005,47006, +47007,47009,47010,47011,47012,47013,47014,47015,47018,47022,47023,47024,47025, +47026,47027,47030,47031,47033,47034,47035,47036,47037,47038,47039,47040,47041, +U,U,U,U,U,U,47042,47043,47044,47045,47046,47048,47050,47051,47052,47053,47054, +47055,47056,47057,47058,47059,47060,47061,47062,47063,47064,47065,47066,47067, +47068,47069,U,U,U,U,U,U,47070,47071,47072,47073,47074,47075,47076,47077,47078, +47079,47080,47081,47082,47083,47086,47087,47089,47090,47091,47093,47094,47095, +47096,47097,47098,47099,47102,47106,47107,47108,47109,47110,47114,47115,47117, +47118,47119,47121,47122,47123,47124,47125,47126,47127,47130,47132,47134,47135, +47136,47137,47138,47139,47142,47143,47145,47146,47147,47149,47150,47151,47152, +47153,47154,47155,47158,47162,47163,47164,47165,47166,47167,47169,47170,47171, +47173,47174,47175,47176,47177,47178,47179,47180,47181,47182,47183,47184,47186, +47188,47189,47190,47191,47192,47193,47194,47195,47198,47199,47201,47202,47203, +47205,47206,47207,47208,47209,47210,47211,47214,47216,47218,47219,47220,47221, +47222,47223,47225,47226,47227,47229,47230,47231,47232,47233,47234,47235,47236, +47237,47238,47239,47240,47241,47242,47243,47244,47246,47247,47248,47249,47250, +47251,47252,47253,47254,47255,47256,47257,47258,47259,47260,47261,47262,47263, +U,U,U,U,U,U,47264,47265,47266,47267,47268,47269,47270,47271,47273,47274,47275, +47276,47277,47278,47279,47281,47282,47283,47285,47286,47287,47289,47290,47291, +47292,47293,U,U,U,U,U,U,47294,47295,47298,47300,47302,47303,47304,47305,47306, +47307,47309,47310,47311,47313,47314,47315,47317,47318,47319,47320,47321,47322, +47323,47324,47326,47328,47330,47331,47332,47333,47334,47335,47338,47339,47341, +47342,47343,47345,47346,47347,47348,47349,47350,47351,47354,47356,47358,47359, +47360,47361,47362,47363,47365,47366,47367,47368,47369,47370,47371,47372,47373, +47374,47375,47376,47377,47378,47379,47380,47381,47382,47383,47385,47386,47387, +47388,47389,47390,47391,47393,47394,47395,47396,47397,47398,47399,47400,47401, +47402,47403,47404,47405,47406,47407,47408,47409,47410,47411,47412,47413,47414, +47415,47416,47417,47418,47419,47422,47423,47425,47426,47427,47429,47430,47431, +47432,47433,47434,47435,47437,47438,47440,47442,47443,47444,47445,47446,47447, +47450,47451,47453,47454,47455,47457,47458,47459,47460,47461,47462,47463,47466, +47468,47470,47471,47472,47473,47474,47475,47478,47479,47481,47482,47483,47485, +U,U,U,U,U,U,47486,47487,47488,47489,47490,47491,47494,47496,47499,47500,47503, +47504,47505,47506,47507,47508,47509,47510,47511,47512,47513,47514,47515,47516, +47517,47518,U,U,U,U,U,U,47519,47520,47521,47522,47523,47524,47525,47526,47527, +47528,47529,47530,47531,47534,47535,47537,47538,47539,47541,47542,47543,47544, +47545,47546,47547,47550,47552,47554,47555,47556,47557,47558,47559,47562,47563, +47565,47571,47572,47573,47574,47575,47578,47580,47583,47584,47586,47590,47591, +47593,47594,47595,47597,47598,47599,47600,47601,47602,47603,47606,47611,47612, +47613,47614,47615,47618,47619,47620,47621,47622,47623,47625,47626,47627,47628, +47629,47630,47631,47632,47633,47634,47635,47636,47638,47639,47640,47641,47642, +47643,47644,47645,47646,47647,47648,47649,47650,47651,47652,47653,47654,47655, +47656,47657,47658,47659,47660,47661,47662,47663,47664,47665,47666,47667,47668, +47669,47670,47671,47674,47675,47677,47678,47679,47681,47683,47684,47685,47686, +47687,47690,47692,47695,47696,47697,47698,47702,47703,47705,47706,47707,47709, +47710,47711,47712,47713,47714,47715,47718,47722,47723,47724,47725,47726,47727, +U,U,U,U,U,U,47730,47731,47733,47734,47735,47737,47738,47739,47740,47741,47742, +47743,47744,47745,47746,47750,47752,47753,47754,47755,47757,47758,47759,47760, +47761,47762,U,U,U,U,U,U,47763,47764,47765,47766,47767,47768,47769,47770,47771, +47772,47773,47774,47775,47776,47777,47778,47779,47780,47781,47782,47783,47786, +47789,47790,47791,47793,47795,47796,47797,47798,47799,47802,47804,47806,47807, +47808,47809,47810,47811,47813,47814,47815,47817,47818,47819,47820,47821,47822, +47823,47824,47825,47826,47827,47828,47829,47830,47831,47834,47835,47836,47837, +47838,47839,47840,47841,47842,47843,47844,47845,47846,47847,47848,47849,47850, +47851,47852,47853,47854,47855,47856,47857,47858,47859,47860,47861,47862,47863, +47864,47865,47866,47867,47869,47870,47871,47873,47874,47875,47877,47878,47879, +47880,47881,47882,47883,47884,47886,47888,47890,47891,47892,47893,47894,47895, +47897,47898,47899,47901,47902,47903,47905,47906,47907,47908,47909,47910,47911, +47912,47914,47916,47917,47918,47919,47920,47921,47922,47923,47927,47929,47930, +47935,47936,47937,47938,47939,47942,47944,47946,47947,47948,47950,47953,47954, +U,U,U,U,U,U,47955,47957,47958,47959,47961,47962,47963,47964,47965,47966,47967, +47968,47970,47972,47973,47974,47975,47976,47977,47978,47979,47981,47982,47983, +47984,47985,U,U,U,U,U,U,47986,47987,47988,47989,47990,47991,47992,47993,47994, +47995,47996,47997,47998,47999,48000,48001,48002,48003,48004,48005,48006,48007, +48009,48010,48011,48013,48014,48015,48017,48018,48019,48020,48021,48022,48023, +48024,48025,48026,48027,48028,48029,48030,48031,48032,48033,48034,48035,48037, +48038,48039,48041,48042,48043,48045,48046,48047,48048,48049,48050,48051,48053, +48054,48056,48057,48058,48059,48060,48061,48062,48063,48065,48066,48067,48069, +48070,48071,48073,48074,48075,48076,48077,48078,48079,48081,48082,48084,48085, +48086,48087,48088,48089,48090,48091,48092,48093,48094,48095,48096,48097,48098, +48099,48100,48101,48102,48103,48104,48105,48106,48107,48108,48109,48110,48111, +48112,48113,48114,48115,48116,48117,48118,48119,48122,48123,48125,48126,48129, +48131,48132,48133,48134,48135,48138,48142,48144,48146,48147,48153,48154,48160, +48161,48162,48163,48166,48168,48170,48171,48172,48174,48175,48178,48179,48181, +U,U,U,U,U,U,48182,48183,48185,48186,48187,48188,48189,48190,48191,48194,48198, +48199,48200,48202,48203,48206,48207,48209,48210,48211,48212,48213,48214,48215, +48216,48217,U,U,U,U,U,U,48218,48219,48220,48222,48223,48224,48225,48226,48227, +48228,48229,48230,48231,48232,48233,48234,48235,48236,48237,48238,48239,48240, +48241,48242,48243,48244,48245,48246,48247,48248,48249,48250,48251,48252,48253, +48254,48255,48256,48257,48258,48259,48262,48263,48265,48266,48269,48271,48272, +48273,48274,48275,48278,48280,48283,48284,48285,48286,48287,48290,48291,48293, +48294,48297,48298,48299,48300,48301,48302,48303,48306,48310,48311,48312,48313, +48314,48315,48318,48319,48321,48322,48323,48325,48326,48327,48328,48329,48330, +48331,48332,48334,48338,48339,48340,48342,48343,48345,48346,48347,48349,48350, +48351,48352,48353,48354,48355,48356,48357,48358,48359,48360,48361,48362,48363, +48364,48365,48366,48367,48368,48369,48370,48371,48375,48377,48378,48379,48381, +48382,48383,48384,48385,48386,48387,48390,48392,48394,48395,48396,48397,48398, +48399,48401,48402,48403,48405,48406,48407,48408,48409,48410,48411,48412,48413, +U,U,U,U,U,U,48414,48415,48416,48417,48418,48419,48421,48422,48423,48424,48425, +48426,48427,48429,48430,48431,48432,48433,48434,48435,48436,48437,48438,48439, +48440,48441,U,U,U,U,U,U,48442,48443,48444,48445,48446,48447,48449,48450,48451, +48452,48453,48454,48455,48458,48459,48461,48462,48463,48465,48466,48467,48468, +48469,48470,48471,48474,48475,48476,48477,48478,48479,48480,48481,48482,48483, +48485,48486,48487,48489,48490,48491,48492,48493,48494,48495,48496,48497,48498, +48499,48500,48501,48502,48503,48504,48505,48506,48507,48508,48509,48510,48511, +48514,48515,48517,48518,48523,48524,48525,48526,48527,48530,48532,48534,48535, +48536,48539,48541,48542,48543,48544,48545,48546,48547,48549,48550,48551,48552, +48553,48554,48555,48556,48557,48558,48559,48561,48562,48563,48564,48565,48566, +48567,48569,48570,48571,48572,48573,48574,48575,48576,48577,48578,48579,48580, +48581,48582,48583,48584,48585,48586,48587,48588,48589,48590,48591,48592,48593, +48594,48595,48598,48599,48601,48602,48603,48605,48606,48607,48608,48609,48610, +48611,48612,48613,48614,48615,48616,48618,48619,48620,48621,48622,48623,48625, +U,U,U,U,U,U,48626,48627,48629,48630,48631,48633,48634,48635,48636,48637,48638, +48639,48641,48642,48644,48646,48647,48648,48649,48650,48651,48654,48655,48657, +48658,48659,U,U,U,U,U,U,48661,48662,48663,48664,48665,48666,48667,48670,48672, +48673,48674,48675,48676,48677,48678,48679,48680,48681,48682,48683,48684,48685, +48686,48687,48688,48689,48690,48691,48692,48693,48694,48695,48696,48697,48698, +48699,48700,48701,48702,48703,48704,48705,48706,48707,48710,48711,48713,48714, +48715,48717,48719,48720,48721,48722,48723,48726,48728,48732,48733,48734,48735, +48738,48739,48741,48742,48743,48745,48747,48748,48749,48750,48751,48754,48758, +48759,48760,48761,48762,48766,48767,48769,48770,48771,48773,48774,48775,48776, +48777,48778,48779,48782,48786,48787,48788,48789,48790,48791,48794,48795,48796, +48797,48798,48799,48800,48801,48802,48803,48804,48805,48806,48807,48809,48810, +48811,48812,48813,48814,48815,48816,48817,48818,48819,48820,48821,48822,48823, +48824,48825,48826,48827,48828,48829,48830,48831,48832,48833,48834,48835,48836, +48837,48838,48839,48840,48841,48842,48843,48844,48845,48846,48847,48850,48851, +U,U,U,U,U,U,48853,48854,48857,48858,48859,48860,48861,48862,48863,48865,48866, +48870,48871,48872,48873,48874,48875,48877,48878,48879,48880,48881,48882,48883, +48884,48885,U,U,U,U,U,U,48886,48887,48888,48889,48890,48891,48892,48893,48894, +48895,48896,48898,48899,48900,48901,48902,48903,48906,48907,48908,48909,48910, +48911,48912,48913,48914,48915,48916,48917,48918,48919,48922,48926,48927,48928, +48929,48930,48931,48932,48933,48934,48935,48936,48937,48938,48939,48940,48941, +48942,48943,48944,48945,48946,48947,48948,48949,48950,48951,48952,48953,48954, +48955,48956,48957,48958,48959,48962,48963,48965,48966,48967,48969,48970,48971, +48972,48973,48974,48975,48978,48979,48980,48982,48983,48984,48985,48986,48987, +48988,48989,48990,48991,48992,48993,48994,48995,48996,48997,48998,48999,49000, +49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,49012,49013, +49014,49015,49016,49017,49018,49019,49020,49021,49022,49023,49024,49025,49026, +49027,49028,49029,49030,49031,49032,49033,49034,49035,49036,49037,49038,49039, +49040,49041,49042,49043,49045,49046,49047,49048,49049,49050,49051,49052,49053, +U,U,U,U,U,U,49054,49055,49056,49057,49058,49059,49060,49061,49062,49063,49064, +49065,49066,49067,49068,49069,49070,49071,49073,49074,49075,49076,49077,49078, +49079,49080,U,U,U,U,U,U,49081,49082,49083,49084,49085,49086,49087,49088,49089, +49090,49091,49092,49094,49095,49096,49097,49098,49099,49102,49103,49105,49106, +49107,49109,49110,49111,49112,49113,49114,49115,49117,49118,49120,49122,49123, +49124,49125,49126,49127,49128,49129,49130,49131,49132,49133,49134,49135,49136, +49137,49138,49139,49140,49141,49142,49143,49144,49145,49146,49147,49148,49149, +49150,49151,49152,49153,49154,49155,49156,49157,49158,49159,49160,49161,49162, +49163,49164,49165,49166,49167,49168,49169,49170,49171,49172,49173,49174,49175, +49176,49177,49178,49179,49180,49181,49182,49183,49184,49185,49186,49187,49188, +49189,49190,49191,49192,49193,49194,49195,49196,49197,49198,49199,49200,49201, +49202,49203,49204,49205,49206,49207,49208,49209,49210,49211,49213,49214,49215, +49216,49217,49218,49219,49220,49221,49222,49223,49224,49225,49226,49227,49228, +49229,49230,49231,49232,49234,49235,49236,49237,49238,49239,49241,49242,49243, +U,U,U,U,U,U,49245,49246,49247,49249,49250,49251,49252,49253,49254,49255,49258, +49259,49260,49261,49262,49263,49264,49265,49266,49267,49268,49269,49270,49271, +49272,49273,U,U,U,U,U,U,49274,49275,49276,49277,49278,49279,49280,49281,49282, +49283,49284,49285,49286,49287,49288,49289,49290,49291,49292,49293,49294,49295, +49298,49299,49301,49302,49303,49305,49306,49307,49308,49309,49310,49311,49314, +49316,49318,49319,49320,49321,49322,49323,49326,49329,49330,49335,49336,49337, +49338,49339,49342,49346,49347,49348,49350,49351,49354,49355,49357,49358,49359, +49361,49362,49363,49364,49365,49366,49367,49370,49374,49375,49376,49377,49378, +49379,49382,49383,49385,49386,49387,49389,49390,49391,49392,49393,49394,49395, +49398,49400,49402,49403,49404,49405,49406,49407,49409,49410,49411,49413,49414, +49415,49417,49418,49419,49420,49421,49422,49423,49425,49426,49427,49428,49430, +49431,49432,49433,49434,49435,49441,49442,49445,49448,49449,49450,49451,49454, +49458,49459,49460,49461,49463,49466,49467,49469,49470,49471,49473,49474,49475, +49476,49477,49478,49479,49482,49486,49487,49488,49489,49490,49491,49494,49495, +U,U,U,U,U,U,49497,49498,49499,49501,49502,49503,49504,49505,49506,49507,49510, +49514,49515,49516,49517,49518,49519,49521,49522,49523,49525,49526,49527,49529, +49530,49531,U,U,U,U,U,U,49532,49533,49534,49535,49536,49537,49538,49539,49540, +49542,49543,49544,49545,49546,49547,49551,49553,49554,49555,49557,49559,49560, +49561,49562,49563,49566,49568,49570,49571,49572,49574,49575,49578,49579,49581, +49582,49583,49585,49586,49587,49588,49589,49590,49591,49592,49593,49594,49595, +49596,49598,49599,49600,49601,49602,49603,49605,49606,49607,49609,49610,49611, +49613,49614,49615,49616,49617,49618,49619,49621,49622,49625,49626,49627,49628, +49629,49630,49631,49633,49634,49635,49637,49638,49639,49641,49642,49643,49644, +49645,49646,49647,49650,49652,49653,49654,49655,49656,49657,49658,49659,49662, +49663,49665,49666,49667,49669,49670,49671,49672,49673,49674,49675,49678,49680, +49682,49683,49684,49685,49686,49687,49690,49691,49693,49694,49697,49698,49699, +49700,49701,49702,49703,49706,49708,49710,49712,49715,49717,49718,49719,49720, +49721,49722,49723,49724,49725,49726,49727,49728,49729,49730,49731,49732,49733, +U,U,U,U,U,U,49734,49735,49737,49738,49739,49740,49741,49742,49743,49746,49747, +49749,49750,49751,49753,49754,49755,49756,49757,49758,49759,49761,49762,49763, +49764,49766,U,U,U,U,U,U,49767,49768,49769,49770,49771,49774,49775,49777,49778, +49779,49781,49782,49783,49784,49785,49786,49787,49790,49792,49794,49795,49796, +49797,49798,49799,49802,49803,49804,49805,49806,49807,49809,49810,49811,49812, +49813,49814,49815,49817,49818,49820,49822,49823,49824,49825,49826,49827,49830, +49831,49833,49834,49835,49838,49839,49840,49841,49842,49843,49846,49848,49850, +49851,49852,49853,49854,49855,49856,49857,49858,49859,49860,49861,49862,49863, +49864,49865,49866,49867,49868,49869,49870,49871,49872,49873,49874,49875,49876, +49877,49878,49879,49880,49881,49882,49883,49886,49887,49889,49890,49893,49894, +49895,49896,49897,49898,49902,49904,49906,49907,49908,49909,49911,49914,49917, +49918,49919,49921,49922,49923,49924,49925,49926,49927,49930,49931,49934,49935, +49936,49937,49938,49942,49943,49945,49946,49947,49949,49950,49951,49952,49953, +49954,49955,49958,49959,49962,49963,49964,49965,49966,49967,49968,49969,49970, +U,U,U,U,U,U,49971,49972,49973,49974,49975,49976,49977,49978,49979,49980,49981, +49982,49983,49984,49985,49986,49987,49988,49990,49991,49992,49993,49994,49995, +49996,49997,U,U,U,U,U,U,49998,49999,50000,50001,50002,50003,50004,50005,50006, +50007,50008,50009,50010,50011,50012,50013,50014,50015,50016,50017,50018,50019, +50020,50021,50022,50023,50026,50027,50029,50030,50031,50033,50035,50036,50037, +50038,50039,50042,50043,50046,50047,50048,50049,50050,50051,50053,50054,50055, +50057,50058,50059,50061,50062,50063,50064,50065,50066,50067,50068,50069,50070, +50071,50072,50073,50074,50075,50076,50077,50078,50079,50080,50081,50082,50083, +50084,50085,50086,50087,50088,50089,50090,50091,50092,50093,50094,50095,50096, +50097,50098,50099,50100,50101,50102,50103,50104,50105,50106,50107,50108,50109, +50110,50111,50113,50114,50115,50116,50117,50118,50119,50120,50121,50122,50123, +50124,50125,50126,50127,50128,50129,50130,50131,50132,50133,50134,50135,50138, +50139,50141,50142,50145,50147,50148,50149,50150,50151,50154,50155,50156,50158, +50159,50160,50161,50162,50163,50166,50167,50169,50170,50171,50172,50173,50174, +U,U,U,U,U,U,50175,50176,50177,50178,50179,50180,50181,50182,50183,50185,50186, +50187,50188,50189,50190,50191,50193,50194,50195,50196,50197,50198,50199,50200, +50201,50202,U,U,U,U,U,U,50203,50204,50205,50206,50207,50208,50209,50210,50211, +50213,50214,50215,50216,50217,50218,50219,50221,50222,50223,50225,50226,50227, +50229,50230,50231,50232,50233,50234,50235,50238,50239,50240,50241,50242,50243, +50244,50245,50246,50247,50249,50250,50251,50252,50253,50254,50255,50256,50257, +50258,50259,50260,50261,50262,50263,50264,50265,50266,50267,50268,50269,50270, +50271,50272,50273,50274,50275,50278,50279,50281,50282,50283,50285,50286,50287, +50288,50289,50290,50291,50294,50295,50296,50298,50299,50300,50301,50302,50303, +50305,50306,50307,50308,50309,50310,50311,50312,50313,50314,50315,50316,50317, +50318,50319,50320,50321,50322,50323,50325,50326,50327,50328,50329,50330,50331, +50333,50334,50335,50336,50337,50338,50339,50340,50341,50342,50343,50344,50345, +50346,50347,50348,50349,50350,50351,50352,50353,50354,50355,50356,50357,50358, +50359,50361,50362,50363,50365,50366,50367,50368,50369,50370,50371,50372,50373, +U,U,U,U,U,U,50374,50375,50376,50377,50378,50379,50380,50381,50382,50383,50384, +50385,50386,50387,50388,50389,50390,50391,50392,50393,50394,50395,50396,50397, +50398,50399,U,U,U,U,U,U,50400,50401,50402,50403,50404,50405,50406,50407,50408, +50410,50411,50412,50413,50414,50415,50418,50419,50421,50422,50423,50425,50427, +50428,50429,50430,50434,50435,50436,50437,50438,50439,50440,50441,50442,50443, +50445,50446,50447,50449,50450,50451,50453,50454,50455,50456,50457,50458,50459, +50461,50462,50463,50464,50465,50466,50467,50468,50469,50470,50471,50474,50475, +50477,50478,50479,50481,50482,50483,50484,50485,50486,50487,50490,50492,50494, +50495,50496,50497,50498,50499,50502,50503,50507,50511,50512,50513,50514,50518, +50522,50523,50524,50527,50530,50531,50533,50534,50535,50537,50538,50539,50540, +50541,50542,50543,50546,50550,50551,50552,50553,50554,50555,50558,50559,50561, +50562,50563,50565,50566,50568,50569,50570,50571,50574,50576,50578,50579,50580, +50582,50585,50586,50587,50589,50590,50591,50593,50594,50595,50596,50597,50598, +50599,50600,50602,50603,50604,50605,50606,50607,50608,50609,50610,50611,50614, +U,U,U,U,U,U,50615,50618,50623,50624,50625,50626,50627,50635,50637,50639,50642, +50643,50645,50646,50647,50649,50650,50651,50652,50653,50654,50655,50658,50660, +50662,50663,U,U,U,U,U,U,50664,50665,50666,50667,50671,50673,50674,50675,50677, +50680,50681,50682,50683,50690,50691,50692,50697,50698,50699,50701,50702,50703, +50705,50706,50707,50708,50709,50710,50711,50714,50717,50718,50719,50720,50721, +50722,50723,50726,50727,50729,50730,50731,50735,50737,50738,50742,50744,50746, +50748,50749,50750,50751,50754,50755,50757,50758,50759,50761,50762,50763,50764, +50765,50766,50767,50770,50774,50775,50776,50777,50778,50779,50782,50783,50785, +50786,50787,50788,50789,50790,50791,50792,50793,50794,50795,50797,50798,50800, +50802,50803,50804,50805,50806,50807,50810,50811,50813,50814,50815,50817,50818, +50819,50820,50821,50822,50823,50826,50828,50830,50831,50832,50833,50834,50835, +50838,50839,50841,50842,50843,50845,50846,50847,50848,50849,50850,50851,50854, +50856,50858,50859,50860,50861,50862,50863,50866,50867,50869,50870,50871,50875, +50876,50877,50878,50879,50882,50884,50886,50887,50888,50889,50890,50891,50894, +U,U,U,U,U,U,50895,50897,50898,50899,50901,50902,50903,50904,50905,50906,50907, +50910,50911,50914,50915,50916,50917,50918,50919,50922,50923,50925,50926,50927, +50929,50930,U,U,U,U,U,U,50931,50932,50933,50934,50935,50938,50939,50940,50942, +50943,50944,50945,50946,50947,50950,50951,50953,50954,50955,50957,50958,50959, +50960,50961,50962,50963,50966,50968,50970,50971,50972,50973,50974,50975,50978, +50979,50981,50982,50983,50985,50986,50987,50988,50989,50990,50991,50994,50996, +50998,51000,51001,51002,51003,51006,51007,51009,51010,51011,51013,51014,51015, +51016,51017,51019,51022,51024,51033,51034,51035,51037,51038,51039,51041,51042, +51043,51044,51045,51046,51047,51049,51050,51052,51053,51054,51055,51056,51057, +51058,51059,51062,51063,51065,51066,51067,51071,51072,51073,51074,51078,51083, +51084,51085,51087,51090,51091,51093,51097,51099,51100,51101,51102,51103,51106, +51111,51112,51113,51114,51115,51118,51119,51121,51122,51123,51125,51126,51127, +51128,51129,51130,51131,51134,51138,51139,51140,51141,51142,51143,51146,51147, +51149,51151,51153,51154,51155,51156,51157,51158,51159,51161,51162,51163,51164, +U,U,U,U,U,U,51166,51167,51168,51169,51170,51171,51173,51174,51175,51177,51178, +51179,51181,51182,51183,51184,51185,51186,51187,51188,51189,51190,51191,51192, +51193,51194,U,U,U,U,U,U,51195,51196,51197,51198,51199,51202,51203,51205,51206, +51207,51209,51211,51212,51213,51214,51215,51218,51220,51223,51224,51225,51226, +51227,51230,51231,51233,51234,51235,51237,51238,51239,51240,51241,51242,51243, +51246,51248,51250,51251,51252,51253,51254,51255,51257,51258,51259,51261,51262, +51263,51265,51266,51267,51268,51269,51270,51271,51274,51275,51278,51279,51280, +51281,51282,51283,51285,51286,51287,51288,51289,51290,51291,51292,51293,51294, +51295,51296,51297,51298,51299,51300,51301,51302,51303,51304,51305,51306,51307, +51308,51309,51310,51311,51314,51315,51317,51318,51319,51321,51323,51324,51325, +51326,51327,51330,51332,51336,51337,51338,51342,51343,51344,51345,51346,51347, +51349,51350,51351,51352,51353,51354,51355,51356,51358,51360,51362,51363,51364, +51365,51366,51367,51369,51370,51371,51372,51373,51374,51375,51376,51377,51378, +51379,51380,51381,51382,51383,51384,51385,51386,51387,51390,51391,51392,51393, +U,U,U,U,U,U,51394,51395,51397,51398,51399,51401,51402,51403,51405,51406,51407, +51408,51409,51410,51411,51414,51416,51418,51419,51420,51421,51422,51423,51426, +51427,51429,U,U,U,U,U,U,51430,51431,51432,51433,51434,51435,51436,51437,51438, +51439,51440,51441,51442,51443,51444,51446,51447,51448,51449,51450,51451,51454, +51455,51457,51458,51459,51463,51464,51465,51466,51467,51470,51472,51474,51475, +51476,51477,51478,51479,51481,51482,51483,51484,51485,51486,51487,51488,51489, +51490,51491,51492,51493,51494,51495,51496,51497,51498,51499,U,U,U,U,U,U,51501, +51502,51503,51504,51505,51506,51507,51509,51510,51511,51512,51513,51514,51515, +51516,51517,51518,51519,51520,51521,51522,51523,51524,51525,51526,51527,U,U,U, +U,U,U,51528,51529,51530,51531,51532,51533,51534,51535,51538,51539,51541,51542, +51543,51545,51546,51547,51548,51549,51550,51551,51554,51556,51557,51558,51559, +51560,51561,51562,51563,51565,51566,51567,51569,51570,51571,51573,51574,51575, +51576,51577,51578,51579,51581,51582,51583,51584,51585,51586,51587,51588,51589, +51590,51591,51594,51595,51597,51598,51599,U,U,U,U,U,U,51601,51602,51603,51604, +51605,51606,51607,51610,51612,51614,51615,51616,51617,51618,51619,51620,51621, +51622,51623,51624,51625,51626,51627,51628,51629,51630,U,U,U,U,U,U,51631,51632, +51633,51634,51635,51636,51637,51638,51639,51640,51641,51642,51643,51644,51645, +51646,51647,51650,51651,51653,51654,51657,51659,51660,51661,51662,51663,51666, +51668,51671,51672,51675,51678,51679,51681,51683,51685,51686,51688,51689,51690, +51691,51694,51698,51699,51700,51701,51702,51703,51706,51707,51709,51710,51711, +51713,51714,51715,51716,U,U,U,U,U,U,51717,51718,51719,51722,51726,51727,51728, +51729,51730,51731,51733,51734,51735,51737,51738,51739,51740,51741,51742,51743, +51744,51745,51746,51747,51748,51749,U,U,U,U,U,U,51750,51751,51752,51754,51755, +51756,51757,51758,51759,51760,51761,51762,51763,51764,51765,51766,51767,51768, +51769,51770,51771,51772,51773,51774,51775,51776,51777,51778,51779,51780,51781, +51782,51783,51784,51785,51786,51787,51790,51791,51793,51794,51795,51797,51798, +51799,51800,51801,51802,51803,51806,51810,51811,51812,51813,51814,51815,51817, +51818,U,U,U,U,U,U,51819,51820,51821,51822,51823,51824,51825,51826,51827,51828, +51829,51830,51831,51832,51833,51834,51835,51836,51838,51839,51840,51841,51842, +51843,51845,51846,U,U,U,U,U,U,51847,51848,51849,51850,51851,51852,51853,51854, +51855,51856,51857,51858,51859,51860,51861,51862,51863,51865,51866,51867,51868, +51869,51870,51871,51872,51873,51874,51875,51876,51877,51878,51879,51880,51881, +51882,51883,51884,51885,51886,51887,51888,51889,51890,51891,51892,51893,51894, +51895,51896,51897,51898,51899,51902,51903,51905,51906,51907,51909,U,U,U,U,U,U, +51910,51911,51912,51913,51914,51915,51918,51920,51922,51924,51925,51926,51927, +51930,51931,51932,51933,51934,51935,51937,51938,51939,51940,51941,51942,51943, +U,U,U,U,U,U,51944,51945,51946,51947,51949,51950,51951,51952,51953,51954,51955, +51957,51958,51959,51960,51961,51962,51963,51964,51965,51966,51967,51968,51969, +51970,51971,51972,51973,51974,51975,51977,51978,51979,51980,51981,51982,51983, +51985,51986,51987,51989,51990,51991,51993,51994,51995,51996,51997,51998,51999, +52002,52003,52004,52005,52006,52007,52008,52009,U,U,U,U,U,U,52010,52011,52012, +52013,52014,52015,52016,52017,52018,52019,52020,52021,52022,52023,52024,52025, +52026,52027,52028,52029,52030,52031,52032,52034,52035,52036,U,U,U,U,U,U,52037, +52038,52039,52042,52043,52045,52046,52047,52049,52050,52051,52052,52053,52054, +52055,52058,52059,52060,52062,52063,52064,52065,52066,52067,52069,52070,52071, +52072,52073,52074,52075,52076,52077,52078,52079,52080,52081,52082,52083,52084, +52085,52086,52087,52090,52091,52092,52093,52094,52095,52096,52097,52098,52099, +52100,52101,52102,52103,52104,U,U,U,U,U,U,52105,52106,52107,52108,52109,52110, +52111,52112,52113,52114,52115,52116,52117,52118,52119,52120,52121,52122,52123, +52125,52126,52127,52128,52129,52130,52131,U,U,U,U,U,U,52132,52133,52134,52135, +52136,52137,52138,52139,52140,52141,52142,52143,52144,52145,52146,52147,52148, +52149,52150,52151,52153,52154,52155,52156,52157,52158,52159,52160,52161,52162, +52163,52164,52165,52166,52167,52168,52169,52170,52171,52172,52173,52174,52175, +52176,52177,52178,52179,52181,52182,52183,52184,52185,52186,52187,52188,52189, +52190,52191,U,U,U,U,U,U,52192,52193,52194,52195,52197,52198,52200,52202,52203, +52204,52205,52206,52207,52208,52209,52210,52211,52212,52213,52214,52215,52216, +52217,52218,52219,52220,U,U,U,U,U,U,52221,52222,52223,52224,52225,52226,52227, +52228,52229,52230,52231,52232,52233,52234,52235,52238,52239,52241,52242,52243, +52245,52246,52247,52248,52249,52250,52251,52254,52255,52256,52259,52260,52261, +52262,52266,52267,52269,52271,52273,52274,52275,52276,52277,52278,52279,52282, +52287,52288,52289,52290,52291,52294,52295,52297,52298,52299,52301,52302,U,U,U, +U,U,U,52303,52304,52305,52306,52307,52310,52314,52315,52316,52317,52318,52319, +52321,52322,52323,52325,52327,52329,52330,52331,52332,52333,52334,52335,52337, +52338,U,U,U,U,U,U,52339,52340,52342,52343,52344,52345,52346,52347,52348,52349, +52350,52351,52352,52353,52354,52355,52356,52357,52358,52359,52360,52361,52362, +52363,52364,52365,52366,52367,52368,52369,52370,52371,52372,52373,52374,52375, +52378,52379,52381,52382,52383,52385,52386,52387,52388,52389,52390,52391,52394, +52398,52399,52400,52401,52402,52403,52406,52407,52409,U,U,U,U,U,U,52410,52411, +52413,52414,52415,52416,52417,52418,52419,52422,52424,52426,52427,52428,52429, +52430,52431,52433,52434,52435,52437,52438,52439,52440,52441,52442,U,U,U,U,U,U, +52443,52444,52445,52446,52447,52448,52449,52450,52451,52453,52454,52455,52456, +52457,52458,52459,52461,52462,52463,52465,52466,52467,52468,52469,52470,52471, +52472,52473,52474,52475,52476,52477,52478,52479,52480,52482,52483,52484,52485, +52486,52487,52490,52491,52493,52494,52495,52497,52498,52499,52500,52501,52502, +52503,52506,52508,52510,52511,52512,U,U,U,U,U,U,52513,52514,52515,52517,52518, +52519,52521,52522,52523,52525,52526,52527,52528,52529,52530,52531,52532,52533, +52534,52535,52536,52538,52539,52540,52541,52542,U,U,U,U,U,U,52543,52544,52545, +52546,52547,52548,52549,52550,52551,52552,52553,52554,52555,52556,52557,52558, +52559,52560,52561,52562,52563,52564,52565,52566,52567,52568,52569,52570,52571, +52573,52574,52575,52577,52578,52579,52581,52582,52583,52584,52585,52586,52587, +52590,52592,52594,52595,52596,52597,52598,52599,52601,52602,52603,52604,52605, +52606,52607,52608,U,U,U,U,U,U,52609,52610,52611,52612,52613,52614,52615,52617, +52618,52619,52620,52621,52622,52623,52624,52625,52626,52627,52630,52631,52633, +52634,52635,52637,52638,52639,U,U,U,U,U,U,52640,52641,52642,52643,52646,52648, +52650,52651,52652,52653,52654,52655,52657,52658,52659,52660,52661,52662,52663, +52664,52665,52666,52667,52668,52669,52670,52671,52672,52673,52674,52675,52677, +52678,52679,52680,52681,52682,52683,52685,52686,52687,52689,52690,52691,52692, +52693,52694,52695,52696,52697,52698,52699,52700,52701,52702,52703,52704,52705, +U,U,U,U,U,U,52706,52707,52708,52709,52710,52711,52713,52714,52715,52717,52718, +52719,52721,52722,52723,52724,52725,52726,52727,52730,52732,52734,52735,52736, +52737,52738,U,U,U,U,U,U,52739,52741,52742,52743,52745,52746,52747,52749,52750, +52751,52752,52753,52754,52755,52757,52758,52759,52760,52762,52763,52764,52765, +52766,52767,52770,52771,52773,52774,52775,52777,52778,52779,52780,52781,52782, +52783,52786,52788,52790,52791,52792,52793,52794,52795,52796,52797,52798,52799, +52800,52801,52802,52803,52804,52805,52806,52807,52808,52809,U,U,U,U,U,U,52810, +52811,52812,52813,52814,52815,52816,52817,52818,52819,52820,52821,52822,52823, +52826,52827,52829,52830,52834,52835,52836,52837,52838,52839,52842,52844,U,U,U, +U,U,U,52846,52847,52848,52849,52850,52851,52854,52855,52857,52858,52859,52861, +52862,52863,52864,52865,52866,52867,52870,52872,52874,52875,52876,52877,52878, +52879,52882,52883,52885,52886,52887,52889,52890,52891,52892,52893,52894,52895, +52898,52902,52903,52904,52905,52906,52907,52910,52911,52912,52913,52914,52915, +52916,52917,52918,52919,52920,52921,52922,U,U,U,U,U,U,52923,52924,52925,52926, +52927,52928,52930,52931,52932,52933,52934,52935,52936,52937,52938,52939,52940, +52941,52942,52943,52944,52945,52946,52947,52948,52949,U,U,U,U,U,U,52950,52951, +52952,52953,52954,52955,52956,52957,52958,52959,52960,52961,52962,52963,52966, +52967,52969,52970,52973,52974,52975,52976,52977,52978,52979,52982,52986,52987, +52988,52989,52990,52991,52994,52995,52997,52998,52999,53001,53002,53003,53004, +53005,53006,53007,53010,53012,53014,53015,53016,53017,53018,53019,53021,53022, +53023,53025,53026,53027,U,U,U,U,U,U,53029,53030,53031,53032,53033,53034,53035, +53038,53042,53043,53044,53045,53046,53047,53049,53050,53051,53052,53053,53054, +53055,53056,53057,53058,53059,53060,U,U,U,U,U,U,53061,53062,53063,53064,53065, +53066,53067,53068,53069,53070,53071,53072,53073,53074,53075,53078,53079,53081, +53082,53083,53085,53086,53087,53088,53089,53090,53091,53094,53096,53098,53099, +53100,53101,53102,53103,53106,53107,53109,53110,53111,53113,53114,53115,53116, +53117,53118,53119,53121,53122,53123,53124,53126,53127,53128,53129,53130,53131, +53133,U,U,U,U,U,U,53134,53135,53136,53137,53138,53139,53140,53141,53142,53143, +53144,53145,53146,53147,53148,53149,53150,53151,53152,53154,53155,53156,53157, +53158,53159,53161,U,U,U,U,U,U,53162,53163,53164,53165,53166,53167,53169,53170, +53171,53172,53173,53174,53175,53176,53177,53178,53179,53180,53181,53182,53183, +53184,53185,53186,53187,53189,53190,53191,53192,53193,53194,53195,53196,53197, +53198,53199,53200,53201,53202,53203,53204,53205,53206,53207,53208,53209,53210, +53211,53212,53213,53214,53215,53218,53219,53221,53222,53223,53225,U,U,U,U,U,U, +53226,53227,53228,53229,53230,53231,53234,53236,53238,53239,53240,53241,53242, +53243,53245,53246,53247,53249,53250,53251,53253,53254,53255,53256,53257,53258, +U,U,U,U,U,U,53259,53260,53261,53262,53263,53264,53266,53267,53268,53269,53270, +53271,53273,53274,53275,53276,53277,53278,53279,53280,53281,53282,53283,53284, +53285,53286,53287,53288,53289,53290,53291,53292,53294,53295,53296,53297,53298, +53299,53302,53303,53305,53306,53307,53309,53310,53311,53312,53313,53314,53315, +53318,53320,53322,53323,53324,53325,53326,53327,U,U,U,U,U,U,53329,53330,53331, +53333,53334,53335,53337,53338,53339,53340,53341,53342,53343,53345,53346,53347, +53348,53349,53350,53351,53352,53353,53354,53355,53358,53359,U,U,U,U,U,U,53361, +53362,53363,53365,53366,53367,53368,53369,53370,53371,53374,53375,53376,53378, +53379,53380,53381,53382,53383,53384,53385,53386,53387,53388,53389,53390,53391, +53392,53393,53394,53395,53396,53397,53398,53399,53400,53401,53402,53403,53404, +53405,53406,53407,53408,53409,53410,53411,53414,53415,53417,53418,53419,53421, +53422,53423,53424,53425,53426,U,U,U,U,U,U,53427,53430,53432,53434,53435,53436, +53437,53438,53439,53442,53443,53445,53446,53447,53450,53451,53452,53453,53454, +53455,53458,53462,53463,53464,53465,53466,U,U,U,U,U,U,53467,53470,53471,53473, +53474,53475,53477,53478,53479,53480,53481,53482,53483,53486,53490,53491,53492, +53493,53494,53495,53497,53498,53499,53500,53501,53502,53503,53504,53505,53506, +53507,53508,53509,53510,53511,53512,53513,53514,53515,53516,53518,53519,53520, +53521,53522,53523,53524,53525,53526,53527,53528,53529,53530,53531,53532,53533, +53534,53535,U,U,U,U,U,U,53536,53537,53538,53539,53540,53541,53542,53543,53544, +53545,53546,53547,53548,53549,53550,53551,53554,53555,53557,53558,53559,53561, +53563,53564,53565,53566,U,U,U,U,U,U,53567,53570,53574,53575,53576,53577,53578, +53579,53582,53583,53585,53586,53587,53589,53590,53591,53592,53593,53594,53595, +53598,53600,53602,53603,53604,53605,53606,53607,53609,53610,53611,53613,53614, +53615,53616,53617,53618,53619,53620,53621,53622,53623,53624,53625,53626,53627, +53629,53630,53631,53632,53633,53634,53635,53637,53638,53639,53641,53642,U,U,U, +U,U,U,53643,53644,53645,53646,53647,53648,53649,53650,53651,53652,53653,53654, +53655,53656,53657,53658,53659,53660,53661,53662,53663,53666,53667,53669,53670, +53671,U,U,U,U,U,U,53673,53674,53675,53676,53677,53678,53679,53682,53684,53686, +53687,53688,53689,53691,53693,53694,53695,53697,53698,53699,53700,53701,53702, +53703,53704,53705,53706,53707,53708,53709,53710,53711,53712,53713,53714,53715, +53716,53717,53718,53719,53721,53722,53723,53724,53725,53726,53727,53728,53729, +53730,53731,53732,53733,53734,53735,53736,53737,53738,U,U,U,U,U,U,53739,53740, +53741,53742,53743,53744,53745,53746,53747,53749,53750,53751,53753,53754,53755, +53756,53757,53758,53759,53760,53761,53762,53763,53764,53765,53766,U,U,U,U,U,U, +53768,53770,53771,53772,53773,53774,53775,53777,53778,53779,53780,53781,53782, +53783,53784,53785,53786,53787,53788,53789,53790,53791,53792,53793,53794,53795, +53796,53797,53798,53799,53800,53801,53802,53803,53806,53807,53809,53810,53811, +53813,53814,53815,53816,53817,53818,53819,53822,53824,53826,53827,53828,53829, +53830,53831,53833,53834,53835,53836,U,U,U,U,U,U,53837,53838,53839,53840,53841, +53842,53843,53844,53845,53846,53847,53848,53849,53850,53851,53853,53854,53855, +53856,53857,53858,53859,53861,53862,53863,53864,U,U,U,U,U,U,53865,53866,53867, +53868,53869,53870,53871,53872,53873,53874,53875,53876,53877,53878,53879,53880, +53881,53882,53883,53884,53885,53886,53887,53890,53891,53893,53894,53895,53897, +53898,53899,53900,53901,53902,53903,53906,53907,53908,53910,53911,53912,53913, +53914,53915,53917,53918,53919,53921,53922,53923,53925,53926,53927,53928,53929, +53930,53931,53933,U,U,U,U,U,U,53934,53935,53936,53938,53939,53940,53941,53942, +53943,53946,53947,53949,53950,53953,53955,53956,53957,53958,53959,53962,53964, +53965,53966,53967,53968,53969,U,U,U,U,U,U,53970,53971,53973,53974,53975,53977, +53978,53979,53981,53982,53983,53984,53985,53986,53987,53990,53991,53992,53993, +53994,53995,53996,53997,53998,53999,54002,54003,54005,54006,54007,54009,54010, +54011,54012,54013,54014,54015,54018,54020,54022,54023,54024,54025,54026,54027, +54031,54033,54034,54035,54037,54039,54040,54041,54042,54043,54046,54050,54051, +U,U,U,U,U,U,54052,54054,54055,54058,54059,54061,54062,54063,54065,54066,54067, +54068,54069,54070,54071,54074,54078,54079,54080,54081,54082,54083,54086,54087, +54088,54089,U,U,U,U,U,U,54090,54091,54092,54093,54094,54095,54096,54097,54098, +54099,54100,54101,54102,54103,54104,54105,54106,54107,54108,54109,54110,54111, +54112,54113,54114,54115,54116,54117,54118,54119,54120,54121,54122,54123,54124, +54125,54126,54127,54128,54129,54130,54131,54132,54133,54134,54135,54136,54137, +54138,54139,54142,54143,54145,54146,54147,54149,54150,54151,U,U,U,U,U,U,54152, +54153,54154,54155,54158,54162,54163,54164,54165,54166,54167,54170,54171,54173, +54174,54175,54177,54178,54179,54180,54181,54182,54183,54186,54188,54190,U,U,U, +U,U,U,54191,54192,54193,54194,54195,54197,54198,54199,54201,54202,54203,54205, +54206,54207,54208,54209,54210,54211,54214,54215,54218,54219,54220,54221,54222, +54223,54225,54226,54227,54228,54229,54230,54231,54233,54234,54235,54236,54237, +54238,54239,54240,54242,54244,54245,54246,54247,54248,54249,54250,54251,54254, +54255,54257,54258,54259,54261,54262,54263,U,U,U,U,U,U,54264,54265,54266,54267, +54270,54272,54274,54275,54276,54277,54278,54279,54281,54282,54283,54284,54285, +54286,54287,54288,54289,54290,54291,54292,54293,54294,U,U,U,U,U,U,54295,54296, +54297,54298,54299,54300,54302,54303,54304,54305,54306,54307,54308,54309,54310, +54311,54312,54313,54314,54315,54316,54317,54318,54319,54320,54321,54322,54323, +54324,54325,54326,54327,54328,54329,54330,54331,54332,54333,54334,54335,54337, +54338,54339,54341,54342,54343,54344,54345,54346,54347,54348,54349,54350,54351, +54352,54353,54354,54355,U,U,U,U,U,U,54356,54357,54358,54359,54360,54361,54362, +54363,54365,54366,54367,54369,54370,54371,54373,54374,54375,54376,54377,54378, +54379,54380,54382,54384,54385,54386,U,U,U,U,U,U,54387,54388,54389,54390,54391, +54394,54395,54397,54398,54401,54403,54404,54405,54406,54407,54410,54412,54414, +54415,54416,54417,54418,54419,54421,54422,54423,54424,54425,54426,54427,54428, +54429,54430,54431,54432,54433,54434,54435,54436,54437,54438,54439,54440,54442, +54443,54444,54445,54446,54447,54448,54449,54450,54451,54452,54453,54454,54455, +54456,U,U,U,U,U,U,54457,54458,54459,54460,54461,54462,54463,54464,54465,54466, +54467,54468,54469,54470,54471,54472,54473,54474,54475,54477,54478,54479,54481, +54482,54483,54485,U,U,U,U,U,U,54486,54487,54488,54489,54490,54491,54493,54494, +54496,54497,54498,54499,54500,54501,54502,54503,54505,54506,54507,54509,54510, +54511,54513,54514,54515,54516,54517,54518,54519,54521,54522,54524,54526,54527, +54528,54529,54530,54531,54533,54534,54535,54537,54538,54539,54541,54542,54543, +54544,54545,54546,54547,54550,54552,54553,54554,54555,54556,54557,U,U,U,U,U,U, +54558,54559,54560,54561,54562,54563,54564,54565,54566,54567,54568,54569,54570, +54571,54572,54573,54574,54575,54576,54577,54578,54579,54580,54581,54582,54583, +U,U,U,U,U,U,54584,54585,54586,54587,54590,54591,54593,54594,54595,54597,54598, +54599,54600,54601,54602,54603,54606,54608,54610,54611,54612,54613,54614,54615, +54618,54619,54621,54622,54623,54625,54626,54627,54628,54630,54631,54634,54636, +54638,54639,54640,54641,54642,54643,54646,54647,54649,54650,54651,54653,54654, +54655,54656,54657,54658,54659,54662,54666,54667,U,U,U,U,U,U,54668,54669,54670, +54671,54673,54674,54675,54676,54677,54678,54679,54680,54681,54682,54683,54684, +54685,54686,54687,54688,54689,54690,54691,54692,54694,54695,U,U,U,U,U,U,54696, +54697,54698,54699,54700,54701,54702,54703,54704,54705,54706,54707,54708,54709, +54710,54711,54712,54713,54714,54715,54716,54717,54718,54719,54720,54721,54722, +54723,54724,54725,54726,54727,54730,54731,54733,54734,54735,54737,54739,54740, +54741,54742,54743,54746,54748,54750,54751,54752,54753,54754,54755,54758,54759, +54761,54762,54763,54765,54766,U,U,U,U,U,U,54767,54768,54769,54770,54771,54774, +54776,54778,54779,54780,54781,54782,54783,54786,54787,54789,54790,54791,54793, +54794,54795,54796,54797,54798,54799,54802,U,U,U,U,U,U,54806,54807,54808,54809, +54810,54811,54813,54814,54815,54817,54818,54819,54821,54822,54823,54824,54825, +54826,54827,54828,54830,54831,54832,54833,54834,54835,54836,54837,54838,54839, +54842,54843,54845,54846,54847,54849,54850,54851,54852,54854,54855,54858,54860, +54862,54863,54864,54866,54867,54870,54871,54873,54874,54875,54877,54878,54879, +54880,54881,U,U,U,U,U,U,54882,54883,54884,54885,54886,54888,54890,54891,54892, +54893,54894,54895,54898,54899,54901,54902,54903,54904,54905,54906,54907,54908, +54909,54910,54911,54912,U,U,U,U,U,U,54913,54914,54916,54918,54919,54920,54921, +54922,54923,54926,54927,54929,54930,54931,54933,54934,54935,54936,54937,54938, +54939,54940,54942,54944,54946,54947,54948,54949,54950,54951,54953,54954,54955, +54957,54958,54959,54961,54962,54963,54964,54965,54966,54967,54968,54970,54972, +54973,54974,54975,54976,54977,54978,54979,54982,54983,54985,54986,54987,U,U,U, +U,U,U,54989,54990,54991,54992,54994,54995,54997,54998,55000,55002,55003,55004, +55005,55006,55007,55009,55010,55011,55013,55014,55015,55017,55018,55019,55020, +55021,U,U,U,U,U,U,55022,55023,55025,55026,55027,55028,55030,55031,55032,55033, +55034,55035,55038,55039,55041,55042,55043,55045,55046,55047,55048,55049,55050, +55051,55052,55053,55054,55055,55056,55058,55059,55060,55061,55062,55063,55066, +55067,55069,55070,55071,55073,55074,55075,55076,55077,55078,55079,55082,55084, +55086,55087,55088,55089,55090,55091,55094,55095,55097,U,U,U,U,U,U,55098,55099, +55101,55102,55103,55104,55105,55106,55107,55109,55110,55112,55114,55115,55116, +55117,55118,55119,55122,55123,55125,55130,55131,55132,55133,55134,U,U,U,U,U,U, +55135,55138,55140,55142,55143,55144,55146,55147,55149,55150,55151,55153,55154, +55155,55157,55158,55159,55160,55161,55162,55163,55166,55167,55168,55170,55171, +55172,55173,55174,55175,55178,55179,55181,55182,55183,55185,55186,55187,55188, +55189,55190,55191,55194,55196,55198,55199,55200,55201,55202,55203, +}; + +static const struct dbcs_index cp949ext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{__cp949ext_decmap+0,65,254},{__cp949ext_decmap+190, +65,254},{__cp949ext_decmap+380,65,254},{__cp949ext_decmap+570,65,254},{ +__cp949ext_decmap+760,65,254},{__cp949ext_decmap+950,65,254},{ +__cp949ext_decmap+1140,65,254},{__cp949ext_decmap+1330,65,254},{ +__cp949ext_decmap+1520,65,254},{__cp949ext_decmap+1710,65,254},{ +__cp949ext_decmap+1900,65,254},{__cp949ext_decmap+2090,65,254},{ +__cp949ext_decmap+2280,65,254},{__cp949ext_decmap+2470,65,254},{ +__cp949ext_decmap+2660,65,254},{__cp949ext_decmap+2850,65,254},{ +__cp949ext_decmap+3040,65,254},{__cp949ext_decmap+3230,65,254},{ +__cp949ext_decmap+3420,65,254},{__cp949ext_decmap+3610,65,254},{ +__cp949ext_decmap+3800,65,254},{__cp949ext_decmap+3990,65,254},{ +__cp949ext_decmap+4180,65,254},{__cp949ext_decmap+4370,65,254},{ +__cp949ext_decmap+4560,65,254},{__cp949ext_decmap+4750,65,254},{ +__cp949ext_decmap+4940,65,254},{__cp949ext_decmap+5130,65,254},{ +__cp949ext_decmap+5320,65,254},{__cp949ext_decmap+5510,65,254},{ +__cp949ext_decmap+5700,65,254},{__cp949ext_decmap+5890,65,254},{ +__cp949ext_decmap+6080,65,160},{__cp949ext_decmap+6176,65,160},{ +__cp949ext_decmap+6272,65,160},{__cp949ext_decmap+6368,65,160},{ +__cp949ext_decmap+6464,65,160},{__cp949ext_decmap+6560,65,160},{ +__cp949ext_decmap+6656,65,160},{__cp949ext_decmap+6752,65,160},{ +__cp949ext_decmap+6848,65,160},{__cp949ext_decmap+6944,65,160},{ +__cp949ext_decmap+7040,65,160},{__cp949ext_decmap+7136,65,160},{ +__cp949ext_decmap+7232,65,160},{__cp949ext_decmap+7328,65,160},{ +__cp949ext_decmap+7424,65,160},{__cp949ext_decmap+7520,65,160},{ +__cp949ext_decmap+7616,65,160},{__cp949ext_decmap+7712,65,160},{ +__cp949ext_decmap+7808,65,160},{__cp949ext_decmap+7904,65,160},{ +__cp949ext_decmap+8000,65,160},{__cp949ext_decmap+8096,65,160},{ +__cp949ext_decmap+8192,65,160},{__cp949ext_decmap+8288,65,160},{ +__cp949ext_decmap+8384,65,160},{__cp949ext_decmap+8480,65,160},{ +__cp949ext_decmap+8576,65,160},{__cp949ext_decmap+8672,65,160},{ +__cp949ext_decmap+8768,65,160},{__cp949ext_decmap+8864,65,160},{ +__cp949ext_decmap+8960,65,160},{__cp949ext_decmap+9056,65,160},{ +__cp949ext_decmap+9152,65,160},{__cp949ext_decmap+9248,65,160},{ +__cp949ext_decmap+9344,65,160},{__cp949ext_decmap+9440,65,160},{ +__cp949ext_decmap+9536,65,160},{__cp949ext_decmap+9632,65,82},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __cp949_encmap[33133] = { +8750,N,N,8756,N,N,8535,8487,N,10275,N,N,8489,8807,N,8518,8510,10615,10616, +8741,N,8786,8484,8748,10614,10284,N,10361,10358,10362,8751,N,N,N,N,N,N,10273, +N,N,N,N,N,N,N,N,N,10274,N,N,N,N,N,N,8511,10282,N,N,N,N,N,10285,10540,N,N,N,N, +N,N,10529,N,N,N,N,N,N,N,N,N,10531,N,N,N,N,N,N,8512,10538,N,N,N,N,N,10541, +10530,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10276,10532,N,N,N,N,N,N,N,N,N, +10533,10278,10534,N,N,N,N,10535,N,N,N,N,N,N,10280,10536,10281,10537,N,N,N,N,N, +N,10544,10287,10543,N,N,N,N,N,N,10283,10539,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,10286,10542,8743,N,N,N,N,N,N,N,N,8752,N,N,N,N,N,N,N,8744,8747,8746,8749,N, +8745,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,9548,9549,9550, +9551,9552,9553,N,9554,9555,9556,9557,9558,9559,9560,N,N,N,N,N,N,N,9569,9570, +9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,N, +9586,9587,9588,9589,9590,9591,9592,11303,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11297, +11298,11299,11300,11301,11302,11304,11305,11306,11307,11308,11309,11310,11311, +11312,11313,11314,11315,11316,11317,11318,11319,11320,11321,11322,11323,11324, +11325,11326,11327,11328,11329,11345,11346,11347,11348,11349,11350,11352,11353, +11354,11355,11356,11357,11358,11359,11360,11361,11362,11363,11364,11365,11366, +11367,11368,11369,11370,11371,11372,11373,11374,11375,11376,11377,N,11351, +8490,N,N,8494,8495,N,N,8496,8497,N,N,8787,8788,N,N,N,8485,8486,N,N,N,N,N,N,N, +N,N,8758,N,8519,8520,N,N,N,N,N,N,N,8536,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +10617,N,N,N,N,N,N,N,N,N,N,10618,N,10619,10620,10621,10622,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8806,8521,N,N,N,N,N, +8757,N,N,N,N,N,N,N,N,N,10020,N,N,8800,N,N,N,N,N,N,N,N,N,N,8805,8802,N,N,N, +10073,N,N,N,N,8522,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,10359,10360,N,N,N,N,N,N,10363,10364,10365,10366,N,9520, +9521,9522,9523,9524,9525,9526,9527,9528,9529,N,N,N,N,N,N,9505,9506,9507,9508, +9509,9510,9511,9512,9513,9514,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +8551,8552,8550,8553,8554,8789,8792,8790,8793,8791,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,8737,N,8738,8739,N,8531,8740,N,N,N,8532,8564,N,N,8565,N,N,N,8755,N,8754, +N,N,N,N,N,N,N,N,8558,N,N,8560,8516,N,8528,N,N,N,N,8491,N,8572,8573,8571,8570, +8562,8563,N,8753,N,N,N,N,N,8517,8561,N,N,N,N,N,N,8493,8559,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,8534,N,N,N,N,N,N,N,N,N,N,N,N,N,8513,8533,N,N,8514,8515, +N,N,N,N,8556,8557,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8568,8569,N,N, +8566,8567,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8769,N,N,N,N,N,N,N,N,N,N,N,8529, +8530,10343,10344,10345,10346,10347,10348,10349,10350,10351,10352,10353,10354, +10355,10356,10357,N,N,N,N,N,10599,10600,10601,10602,10603,10604,10605,10606, +10607,10608,10609,10610,10611,10612,10613,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582, +10583,10584,10585,10586,10587,10588,10589,10590,10591,10592,10593,10594,10595, +10596,10597,10598,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10317, +10318,10319,10320,10321,10322,10323,10324,10325,10326,10327,10328,10329,10330, +10331,10332,10333,10334,10335,10336,10337,10338,10339,10340,10341,10342,9761, +9772,9762,9773,N,N,N,N,N,N,N,N,9763,9800,9799,9774,9764,9794,9793,9775,9766, +9798,9797,9777,9765,9796,9795,9776,9767,9788,9801,9802,9783,9803,9804,9778, +9769,9790,9805,9806,9785,9807,9808,9780,9768,9809,9810,9784,9789,9811,9812, +9779,9770,9813,9814,9786,9791,9815,9816,9781,9771,9817,9818,9787,9819,9820, +9792,9821,9822,9823,9824,9825,9826,9827,9828,9782,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8774,N,N,N,N,N,N,N,N,N,N,N,N,N,8545,8544,N, +8771,8775,8776,8779,8778,8777,8780,N,N,N,N,N,N,N,N,8547,8546,N,N,8762,8761,N, +N,N,N,8549,8548,N,N,8760,8759,N,N,N,N,8543,8542,8770,N,N,8539,N,N,8541,8540, +8772,8773,8538,8537,N,N,N,N,N,N,N,8783,8782,N,N,N,N,N,N,N,N,N,N,N,N,8784,N, +8785,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8527,N, +8526,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8764,8765,N, +8768,8763,8766,N,8767,8781,8795,8796,N,8797,8794,8481,8482,8483,8488,N,N,N,N, +8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,N,8555,8498,8499,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +10785,10786,10787,10788,10789,10790,10791,10792,10793,10794,10795,10796,10797, +10798,10799,10800,10801,10802,10803,10804,10805,10806,10807,10808,10809,10810, +10811,10812,10813,10814,10815,10816,10817,10818,10819,10820,10821,10822,10823, +10824,10825,10826,10827,10828,10829,10830,10831,10832,10833,10834,10835,10836, +10837,10838,10839,10840,10841,10842,10843,10844,10845,10846,10847,10848,10849, +10850,10851,10852,10853,10854,10855,10856,10857,10858,10859,10860,10861,10862, +10863,10864,10865,10866,10867,N,N,N,N,N,N,N,N,N,N,N,N,N,11041,11042,11043, +11044,11045,11046,11047,11048,11049,11050,11051,11052,11053,11054,11055,11056, +11057,11058,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069, +11070,11071,11072,11073,11074,11075,11076,11077,11078,11079,11080,11081,11082, +11083,11084,11085,11086,11087,11088,11089,11090,11091,11092,11093,11094,11095, +11096,11097,11098,11099,11100,11101,11102,11103,11104,11105,11106,11107,11108, +11109,11110,11111,11112,11113,11114,11115,11116,11117,11118,11119,11120,11121, +11122,11123,11124,11125,11126,9249,9250,9251,9252,9253,9254,9255,9256,9257, +9258,9259,9260,9261,9262,9263,9264,9265,9266,9267,9268,9269,9270,9271,9272, +9273,9274,9275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287, +9288,9289,9290,9291,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,9302, +9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317, +9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,9332, +9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,10545,10546,10547,10548, +10549,10550,10551,10552,10553,10554,10555,10556,10557,10558,10559,10560,10561, +10562,10563,10564,10565,10566,10567,10568,10569,10570,10571,10572,8799,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10289,10290,10291,10292, +10293,10294,10295,10296,10297,10298,10299,10300,10301,10302,10303,10304,10305, +10306,10307,10308,10309,10310,10311,10312,10313,10314,10315,10316,N,N,N,8798, +10057,10058,10059,10060,10061,N,N,N,10042,10043,10076,10077,10078,10038,10039, +10040,10068,10069,10070,10071,10072,10017,10018,10019,10021,10027,10028,10029, +10030,10031,10032,10033,10034,10035,10036,10023,10024,10025,10026,10045,10046, +10085,10086,10087,10088,10081,10082,10083,10047,10048,10049,10050,10051,10052, +10053,10054,10055,10056,10062,10063,10064,10065,10066,10067,10074,10075,8803, +10092,10022,10080,10095,8801,10044,10093,10037,N,N,N,N,10041,10090,N,N,10091, +N,N,10079,N,8804,N,N,10084,10094,10089,27753,28491,N,30290,N,N,N,22578,27995, +24370,24382,31035,N,23668,N,N,N,30052,N,N,29478,23904,24870,N,20088,23600,N,N, +N,N,25386,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29033,N,N,N,N,19834,N,N,N,N,N,31791, +21281,N,28971,N,N,N,N,N,N,26449,21036,N,20089,N,N,N,N,N,29053,N,24127,31546, +31033,N,N,N,N,N,N,20050,N,25387,27488,N,N,N,20090,19319,25893,N,N,N,N,N,N,N,N, +N,N,N,19041,N,21580,N,N,N,N,N,27233,N,N,23651,24365,N,N,N,N,N,N,19307,N,N,N, +21807,N,N,N,22133,N,25976,N,N,24128,27683,N,26957,N,27175,26998,31547,N,26473, +28492,N,N,20582,N,N,24129,N,N,25644,N,N,22604,31089,N,20063,31268,26162,N, +31355,N,N,31293,19528,28493,21845,N,N,N,N,N,N,N,21282,N,N,N,27729,N,N,N,N,N, +25639,27730,N,N,30257,N,N,20091,N,N,20561,19263,N,27940,N,N,N,N,N,N,27944, +24130,30306,27996,23669,24633,N,N,N,21582,N,29749,N,N,N,21339,22069,27684,N,N, +N,N,N,N,N,N,N,N,25702,N,29034,N,N,N,19308,19264,N,N,N,27762,20586,N,N,N,N,N,N, +N,31090,27685,20575,N,26474,20587,23633,23401,32076,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23383,N,N,N,N,23137,N,22070,N,25439,N,24131,N, +24132,18977,N,N,N,N,N,28268,N,N,21283,28215,30799,N,N,N,N,27208,28216,28972, +28965,26958,N,N,N,31036,N,N,N,25977,27754,23894,27970,N,N,N,N,N,N,N,N,N,N,N,N, +30757,N,N,N,N,N,25914,23384,N,N,18978,N,N,20813,N,N,N,28269,N,N,N,27755,24133, +N,25440,N,19017,29289,N,21838,N,30262,N,20034,22087,N,25396,N,28973,N,27234,N, +N,N,N,22338,N,29479,N,N,19818,N,27502,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22834, +32037,N,N,N,N,N,30293,21858,N,N,N,N,N,N,N,N,30773,N,N,19573,30005,25645,N,N,N, +N,26475,29013,N,N,N,28731,N,N,26933,N,19529,31317,N,N,24916,N,N,22358,N,N, +23617,N,24134,31343,25441,N,N,N,N,N,N,N,N,N,N,N,N,24947,23670,N,20092,N,23364, +N,30833,N,N,23652,N,25967,23601,N,N,N,21846,N,N,29530,N,19265,N,23363,N,N,N, +22906,21358,N,N,N,31288,N,N,32038,27503,N,29734,N,19530,29480,N,29531,N,23335, +30263,N,20326,28786,19290,N,26450,22339,30320,26718,N,N,N,N,N,N,N,N,N,N,N,N,N, +25894,N,N,N,N,N,N,N,25959,N,N,N,18979,19495,27209,N,N,N,N,N,30774,N,N,N,N,N, +31269,N,N,N,N,28974,N,28494,N,N,N,N,N,N,N,N,19309,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30256,28495,26959,N,30558,N,N,N,N,N,N,N,20051,N,N,N,N,23671,N,N,N,N,N,N,N, +23336,N,N,N,19320,N,N,N,N,N,N,24353,23905,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30026,26934,N,N,N,N,26476,28270,N,29552,N,24383,N,N,N,N,N,N,19531,N,N,N,N,N,N, +20545,N,N,N,29778,24634,N,N,N,N,24384,N,20064,N,N,N,23634,32106,N,N,N,22134,N, +N,N,27210,N,N,N,N,N,N,26729,N,25388,N,N,N,N,N,29520,N,N,N,N,N,N,N,N,N,N,N, +18980,N,23416,N,N,N,24135,27504,29014,N,N,25954,N,19532,N,N,19323,N,N,N,N,N,N, +N,N,27235,N,N,N,N,N,N,N,N,N,N,N,N,24385,N,22125,N,N,N,N,N,N,N,N,26960,N,N,N,N, +N,N,N,28217,N,N,N,N,21859,N,N,20819,N,25968,N,N,N,26676,27459,N,27178,31356, +30070,28732,32084,24635,20035,N,20538,30522,22643,30541,N,N,N,25646,N,N,N,N,N, +N,N,N,N,21599,N,N,N,N,N,20583,N,N,27773,N,21038,28271,21847,27236,30754,19819, +22335,31537,N,N,19820,N,N,N,23602,20588,20093,28272,N,N,N,19522,N,N,N,20589,N, +N,N,N,N,25975,N,N,N,29564,N,N,28194,N,N,N,N,22835,N,N,22644,N,26935,N,N,N,N,N, +N,N,N,20014,N,N,N,N,22818,N,N,N,N,22641,N,21583,N,N,N,N,N,N,N,N,N,25895,21842, +N,N,N,N,N,22057,N,N,N,N,N,N,29730,N,29015,N,N,21848,N,28733,22352,21584,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,22351,27498,32107,N,N,23405,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +31813,19266,N,N,N,N,32085,N,29768,26730,30067,N,N,31070,21359,N,N,27731,N,N, +23874,28471,26452,N,19018,N,N,N,22907,N,N,31357,N,N,N,N,N,22058,N,N,N,N,N, +29816,N,N,N,N,N,N,30583,23596,N,N,N,22359,24354,N,N,N,20030,N,21360,N,N,N,N,N, +28708,24940,20327,29515,27945,19006,N,N,N,N,N,N,N,29807,N,N,N,30286,N,N,24187, +20539,21815,28273,N,N,N,N,N,N,29736,N,23672,N,N,N,N,19239,N,23118,N,N,N,24678, +N,N,N,N,N,N,N,27941,28274,N,N,N,N,23673,N,N,31068,N,N,29532,N,N,N,N,N,N,N, +30834,N,29817,N,N,N,31857,N,N,N,20540,23417,22321,N,N,N,19324,N,N,N,28709, +19325,N,N,N,N,N,N,N,N,21876,N,N,N,19821,18981,N,N,22059,20546,N,N,N,N,28734, +21053,19492,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31286,N,N,19533,N,23162,N, +30287,N,26936,N,22645,N,N,N,19534,N,N,N,N,22349,N,N,21585,26989,N,19051,22882, +N,32050,N,25389,22092,22836,N,N,24871,28243,20547,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +32051,N,21860,N,N,20328,N,27971,20530,N,N,20094,23080,30800,N,N,32086,N,N,N,N, +30801,N,30802,23635,N,N,N,N,23906,31609,23873,N,25397,N,N,N,N,N,N,27997,20036, +N,19233,N,N,N,N,N,N,23907,N,N,N,N,31837,N,N,N,N,N,N,N,N,N,31023,N,N,N,N,N, +21115,20257,25640,N,29750,27774,N,N,25390,26477,32065,23138,N,N,22579,N,N,N, +23908,28783,30321,31344,N,N,20853,N,N,23119,N,23636,N,23590,N,28479,N,N,N,N,N, +20047,N,24665,N,N,N,N,N,N,22870,27732,27211,N,N,19007,21808,N,20329,N,N,N,N,N, +29037,N,19535,N,N,N,N,25720,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25709,N,N,N,N,22360,N, +32039,N,N,N,N,27179,30258,N,N,N,N,20336,31037,N,N,N,N,N,N,26228,N,N,N,N,N,N,N, +N,N,N,N,N,N,19291,N,N,N,N,N,N,N,29521,N,N,N,N,26961,29481,20576,26962,N,23139, +N,N,N,N,N,N,25170,N,30242,24948,N,N,N,23140,N,N,N,N,N,26453,30015,20258,19759, +20259,N,N,N,19760,29054,20515,24879,30755,N,18982,30523,29290,24136,26963,N,N, +N,N,24137,32094,19008,N,N,N,31082,20814,28244,N,21586,22819,32040,22361,30542, +31294,N,N,N,N,N,N,N,N,N,20310,N,22384,N,27489,30789,N,N,N,N,N,23674,N,N,23875, +N,31071,N,N,N,N,N,N,N,26479,N,N,N,N,32101,30243,N,22908,32041,N,26478,N,N,N, +21861,N,N,N,N,N,28496,N,19761,N,N,N,N,N,N,30498,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,28978,N,28977,N,N,N,N,N,N,19762,N,23083,N,18983,N,N,N,N,N,25442, +31548,22820,N,N,28218,N,N,N,N,N,30803,N,N,N,N,N,31610,N,20260,N,23675,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30307,N,N,N,27946,N,N,29217,20065,N,N,N,N,N,N, +31270,N,N,N,N,31072,N,N,N,N,27734,N,N,25710,31009,N,N,31599,N,N,N,31083,28195, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27180,N,N,N,18984,N,N,29818,N,N, +N,N,19798,31862,N,N,N,29769,N,N,N,N,N,N,N,30804,30758,N,24138,29254,N,N,N,N,N, +N,22362,N,21328,N,N,N,N,N,N,N,N,N,N,N,22597,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,27238,N,29533,N,N,N,25690,N,N,N,N,N,N,N,N,30308,N,N,N,N,N,30322,N,24386,N,N, +N,N,N,N,N,N,22909,N,N,N,19574,N,N,21306,N,N,N,N,N,N,N,25647,N,N,N,N,31073,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28710,N,N,N,19283,N,N,N,24636,N, +29770,21626,N,32042,31074,N,N,N,N,N,N,N,N,N,N,N,N,N,29751,32066,31792,N,32108, +19042,N,N,N,N,N,N,N,N,N,32061,N,27239,24387,20818,20066,N,21284,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32043,N,24416,N,N,N,N,N,N,N,N,N,N,N,N,29255,N,N, +N,N,N,26480,N,20590,N,N,29482,N,N,N,24139,30264,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,24949,28979,30499,N,N,18985,N,N,N,N,N,N,N,N,N,N,20261,N,N, +24388,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24880,N,N,28735,N,30244,N, +25398,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31302,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20591,N,N,32109,N,N,N,N,N,N,N,N,23876,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,31863,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,26175,N,N,N,N,N,N,24109,N,31295,N,N,N,N,N,25969,N,N,N,N,N,N,N, +27972,N,N,N,N,N,N,N,N,N,N,N,N,N,21029,N,N,32110,N,N,N,30006,N,N,N,N,N,N,N,N, +24950,24140,N,N,31838,N,27735,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19805,N,N,N,N,N,N, +N,N,22071,19763,30805,25944,N,N,N,20330,N,N,20304,N,27212,N,N,N,N,27182,27181, +N,N,21361,N,21285,N,N,N,N,N,N,30543,N,N,N,N,N,N,N,N,28196,N,N,N,N,20516,N,N, +29218,N,N,N,N,N,N,N,N,N,N,20592,N,N,N,N,29219,N,30584,N,N,N,N,20531,N,N,23337, +N,N,21307,19052,N,28966,19285,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30567,N,N,19806,N, +30500,N,N,N,30784,N,N,N,21341,N,19536,N,N,N,N,20262,N,N,N,N,N,N,30323,N,N,N,N, +N,24951,N,N,N,N,N,21340,N,N,31358,N,N,N,N,N,N,N,31271,N,N,N,N,N,N,N,N,N,N,N,N, +27481,N,20263,27183,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,25711,N,N,N,26937,29016,N,N,22616,N,N,24690,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,26164,23676,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29553,N,N,N,25424,N,N,29307,N, +23366,20593,N,20594,20316,N,21329,N,N,19505,30552,N,19240,27452,25662,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29788,N,N,23618,N,N,28711,N,N,26176,N,N,19053,N, +N,N,N,26731,25960,23619,N,N,27998,21362,N,N,N,N,19575,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,20052,26411,N,N,N,19267,N,24881,N,N,30514,N,N,21363,21330,N,30016,N,N,N, +24413,N,N,28275,26481,N,32052,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29256,N,N,N, +29522,N,N,28276,N,25171,N,N,N,N,19537,N,24426,N,N,N,26938,N,N,N,N,N,N,N,N,N, +22871,N,N,N,N,N,N,N,N,30029,N,29042,31303,N,N,N,N,N,N,N,N,22904,21570,N,N,N,N, +30309,N,N,N,N,23877,N,N,N,N,N,N,26482,27999,N,N,19019,N,N,23418,N,N,N,26677,N, +21286,N,N,N,N,N,N,32053,N,N,31049,N,25698,N,31549,N,N,22308,20037,N,N,N,N, +20053,22118,N,N,N,N,25917,N,N,N,N,N,N,24141,27763,N,N,28000,N,N,N,N,N,N,N,N,N, +27756,31550,24427,N,24952,31038,N,N,N,N,20595,24618,26722,N,N,25172,21117,N, +25896,N,N,N,N,N,22867,N,N,N,N,21342,N,29752,30524,23677,N,26732,25703,N,N, +25463,N,N,N,N,N,27688,N,N,N,N,N,N,31345,N,N,N,N,N,25970,N,N,20596,21039,23653, +N,N,N,N,20517,28980,31793,19576,N,N,23878,31313,N,30559,N,N,31272,N,N,N,N,N, +28277,N,24142,N,N,N,N,26483,N,N,30508,27460,28001,24619,23879,N,N,N,N,21043, +21055,N,N,N,19020,N,N,N,N,31551,N,N,N,N,25981,23909,22605,N,N,N,N,N,27764,N,N, +N,N,N,N,N,N,20597,N,N,26733,20562,N,22872,N,N,N,N,N,N,N,N,N,N,N,30310,N,N, +23338,N,N,N,30560,N,N,N,N,N,N,N,N,N,N,N,N,22617,N,29731,N,N,29789,N,N,N,N, +28497,N,N,22837,N,N,27947,N,25399,N,N,N,N,28219,19764,N,24691,27213,N,N,N,N, +27765,26734,N,19241,28975,N,N,N,N,N,N,N,N,19021,N,27689,N,29291,N,32111,N, +31091,N,N,N,N,N,N,N,N,N,26177,N,N,27736,N,N,N,27948,27214,N,26719,N,N,N,N,N,N, +N,N,N,N,N,N,N,24143,N,N,N,N,N,N,21030,N,N,26484,20822,N,N,26178,25443,N,N,N,N, +25648,N,N,N,22580,N,N,N,N,N,N,N,N,N,N,N,N,30245,N,N,N,N,N,29534,N,N,N,N,22309, +N,N,N,N,30568,N,N,26694,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31590,N,N,N,N,N,N,N, +23910,N,N,N,23678,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,22618,N,N,N,N,N,N,N,23084,27184,N,N,N,N,N,N,N,N, +25400,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,18986,24953,N, +27185,N,N,N,N,29292,N,N,31342,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28245,N, +N,N,N,31092,N,N,21100,31611,N,N,N,32112,N,24637,20067,N,N,N,N,N,N,N,N,N,30790, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24110,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,24389,N,N,25918,N,N,N,N,N,N,N,N,N,N,N,N,27949,31338,N,N,19822,27942,N, +27950,28781,N,23841,N,27951,31864,N,22635,N,N,N,19577,19765,N,N,N,N,31273,N, +24925,N,N,N,N,25173,27983,N,N,N,23842,N,N,31050,N,27240,N,25965,N,N,N,N,N,N,N, +N,21355,N,26964,24954,25676,N,24932,26695,N,N,20059,N,N,N,23637,N,30517,31859, +28787,20015,28981,28498,26696,27505,N,N,N,N,N,19284,24638,25464,27241,31794,N, +N,N,N,N,24692,N,20320,N,28197,N,N,31274,26179,24882,18987,N,25444,26939,N,N,N, +N,N,25174,29554,N,28246,27186,20598,27737,23115,20264,N,N,N,N,23843,N,N,N, +22619,N,31054,26965,25425,N,N,21052,N,N,N,N,N,N,22572,29516,N,19835,30294,N, +26485,26735,25465,21051,29555,25467,N,24144,20016,N,22135,29017,N,N,N,N,N, +30017,23620,N,30011,N,24145,23654,N,N,24146,N,N,28002,28278,27215,28782,25468, +N,21343,21364,24883,N,24884,N,N,N,N,29779,N,N,24390,N,N,N,N,N,N,N,N,N,N,26966, +N,N,N,23339,N,N,N,N,N,N,N,N,30246,N,N,N,N,N,N,25401,27461,29737,19766,21113,N, +23085,21091,20305,N,N,N,N,19292,19578,N,20317,N,N,26665,N,25403,25402,N,N, +24666,N,N,N,28279,N,N,N,N,N,23603,N,N,N,N,21365,N,22310,N,30261,22363,N,N,N,N, +N,N,24917,N,N,21610,N,24355,N,N,N,N,N,N,N,32095,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,20599,27988,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19242,N,N,N,N,N,N,N, +25691,N,24955,19234,N,N,N,N,21344,N,25663,N,31552,N,23102,25677,N,22073,N,N,N, +28480,N,24956,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30265,N,N,N,N,N, +N,24391,N,N,N,N,N,N,N,25649,N,N,N,N,N,N,23655,23656,N,N,N,31318,N,21366,N,N,N, +N,29018,N,31346,25213,N,N,N,N,N,21839,20600,N,N,19807,N,N,30027,N,25712,19243, +N,22340,N,N,N,N,N,N,N,N,N,N,N,N,N,25214,N,23898,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23086,19054,N,N,N,21817,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25377,N,N,26723,N,N,29483,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,20265,N,N,N,21367,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +21617,N,N,20068,N,26738,N,N,N,N,N,N,N,25973,N,N,N,N,N,N,N,N,N,N,N,N,N,26414,N, +22074,N,24428,25664,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26724,N,N,N,N,22581,N,N,N, +25692,N,N,N,N,N,N,29753,28982,N,N,25182,24885,N,N,19823,28967,20069,19293,N,N, +22883,N,N,29484,N,N,20601,27691,24147,30569,N,N,31093,N,N,N,N,N,24926,19310, +25404,30806,N,N,23406,N,N,N,N,N,32113,N,N,N,N,30518,N,N,N,N,29790,N,N,29293,N, +23385,N,28712,N,N,N,N,N,N,N,24957,N,N,N,N,N,24148,N,24620,N,N,N,N,N,28003,N,N, +21345,N,24392,N,N,N,N,22838,N,32044,28499,N,N,N,25665,30827,N,23340,N,N,N,N, +31814,N,N,N,N,N,N,N,N,22573,N,N,N,N,N,N,N,N,N,30266,N,23391,21331,30791,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,19022,30785,21044,N,N,23604,31289,19023,N,31795,27242, +27243,20602,N,N,N,N,N,28004,N,N,23911,N,N,24393,N,N,N,N,24429,N,N,N,N,N,28220, +N,28481,N,N,19538,N,23844,N,N,N,24394,N,N,N,N,N,21368,28968,N,N,N,19767,N, +28500,N,N,N,N,N,N,N,25693,24430,19244,26940,N,N,N,N,N,27244,N,N,N,24395,N,N,N, +N,N,31039,22063,21830,N,N,N,N,N,20266,N,N,20009,N,N,22136,N,N,N,28983,28280,N, +N,N,22873,29535,N,30792,20038,N,N,N,N,N,N,N,N,21862,N,N,N,N,N,N,29798,N,N, +26181,28501,N,N,19311,31839,23591,N,N,22119,N,N,N,N,N,30793,N,N,N,N,25426,N, +25405,N,20321,28736,27738,N,23895,31600,N,N,27692,N,N,N,28713,N,N,N,N,N,N, +31319,31553,N,21056,N,N,N,N,N,N,N,25904,N,N,N,28005,N,N,N,N,19245,N,31024,N,N, +N,N,N,N,N,N,N,N,N,30501,N,19246,N,23087,N,22582,N,N,N,N,N,N,N,21287,31538,N, +32068,N,27693,N,N,N,N,N,N,31521,N,N,N,25961,26990,N,29556,30835,28737,24111, +30768,N,N,29536,26415,N,N,N,N,N,23341,N,26165,N,N,31016,N,N,23896,26713,28502, +N,N,N,21346,N,25183,N,N,31840,22344,32045,N,N,N,24431,19539,21369,N,N,N,N, +21616,23367,24149,N,N,N,N,28788,N,21840,25945,N,N,N,N,N,N,31815,23638,25184,N, +N,N,23088,N,N,N,N,N,N,29475,N,21356,N,29771,N,N,N,32069,N,N,N,N,N,25469,N, +31025,N,N,N,N,N,N,20603,27739,N,N,N,N,N,N,N,N,30012,29220,22606,22607,N,N,N,N, +N,N,30071,N,N,N,N,N,N,N,N,N,N,30305,N,N,N,N,N,N,N,N,N,21047,N,N,N,N,N,N,N, +31596,N,23880,25704,N,N,21057,N,N,N,30807,N,N,N,N,N,22075,24150,N,N,30525, +27694,N,N,N,20577,N,24693,27187,N,20054,N,N,N,N,19493,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,27766,25185,25406,N,N,N,N,N,N,N,N,N,31816,N,N,19824,N,31094,N,N, +24432,N,N,N,25919,N,N,N,20031,N,N,N,N,31841,27952,32081,30267,N,N,31055,27482, +19009,N,21048,19825,N,25427,32102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +26221,N,N,N,25466,N,N,28714,31056,N,N,N,N,N,N,31842,N,30759,N,N,N,24933,28281, +N,N,N,26486,27245,N,N,31796,30018,N,N,22364,N,N,N,N,N,N,N,N,28789,N,23912, +21357,30076,N,23103,N,19579,N,N,N,21370,29732,N,N,N,N,N,N,N,28503,N,21571,N,N, +N,N,N,N,N,N,N,31587,N,N,N,N,N,N,N,N,31597,N,24621,N,N,27246,31539,25666,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,30311,21085,N,24396,N,N,31817,N,N,25897,24694,30259, +24958,N,N,N,N,19312,N,27247,27248,N,N,N,23104,30772,27506,N,N,N,N,N,25667,N,N, +N,N,26967,25713,N,N,N,19055,N,N,N,N,N,N,N,20055,N,N,N,N,N,N,N,N,31818,N,N,N, +29537,N,N,19268,N,N,N,N,25445,N,19269,27188,N,N,26941,N,22345,N,N,27483,27953, +N,19523,30526,31819,N,N,N,N,N,N,30836,N,22839,N,N,29523,29524,N,N,N,30564,N, +30545,N,N,22583,20017,19010,N,N,31540,19270,N,N,28790,N,N,21863,N,27216,N,N,N, +N,N,19540,19247,N,N,N,N,N,29738,26927,N,N,30019,26968,N,N,N,N,N,N,N,23913,N,N, +N,29043,N,21883,24123,N,N,29819,N,N,N,32115,32114,30502,N,N,N,N,N,N,N,N,N, +23881,N,N,21587,N,19496,N,23105,19541,N,22884,N,N,N,31306,N,N,N,25955,N,N,N, +21308,N,N,N,19056,N,N,N,N,20548,N,N,N,19024,31275,27499,26488,22885,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20823,N,N,N,N,N,N,N,N,N,N,N,29476,N, +N,N,21627,31843,31320,N,29525,N,20267,N,N,27507,21884,N,N,N,N,N,N,21332,19836, +N,22886,N,25209,25121,27476,N,24695,25650,19580,N,N,N,31588,N,N,N,29739,N,N,N, +N,20541,N,19057,N,N,N,N,N,N,N,N,28472,N,N,N,22336,N,28282,32116,N,N,21347,N, +31554,N,N,N,N,N,N,N,21864,23342,24886,30775,N,N,N,N,N,24639,31555,23914,N, +25122,N,28198,N,N,N,N,N,30312,N,N,N,N,30325,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,23882,N,N,20578,N,N,N,N,23846,N,N,23915,N,N,25721,N,N,25391,20604,N,N, +N,29820,N,N,N,N,19516,30570,N,N,N,N,N,N,25956,24433,N,N,30561,N,31095,28473,N, +N,30808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31017,N,N,N,N,N,30809,N,N,N,28221,N,N,N, +22598,N,N,25699,30030,N,N,N,N,23897,N,N,N,N,22887,21049,21827,N,N,23141,23120, +N,20825,20056,N,19294,29740,23163,N,30313,26739,20268,28784,N,29821,23368,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,20032,25428,20815,29045,N,19826,N,20331,N,N,N,19768, +N,N,N,N,N,N,25382,20826,29221,N,N,N,N,N,29222,N,25678,N,N,N,N,N,N,N,21371,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28969,N,N,N,29257,N,N,N,N,N,N,N, +N,N,N,28504,26185,N,22584,31347,N,N,N,N,N,N,N,N,N,N,29493,N,N,30756,N,N,20851, +26184,N,N,N,N,30810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23657,24151,N,N,N,N,N, +19295,N,N,N,20332,N,N,N,N,29791,N,N,20852,21050,N,N,N,24434,N,N,N,24887,N,N,N, +N,25123,21372,N,N,28006,N,N,N,N,N,23369,N,N,N,25722,N,20318,N,N,20048,N,N,N,N, +21843,29557,30510,N,N,28488,N,19827,30031,25971,28738,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,19025,N,N,N,27249,N,20518,N,N,N,N,N,N,N,N,22874,28715,N,N,N, +N,N,27495,N,N,N,25920,31797,N,N,N,N,N,25668,N,N,N,N,N,N,N,N,N,N,N,19497,32070, +N,N,N,N,N,27189,N,25898,24378,24927,N,23121,N,N,N,N,24888,N,26740,21373,N,N,N, +N,25124,N,N,N,N,N,29258,N,N,N,N,N,N,N,N,N,23142,30515,N,N,N,N,N,N,N,N,N,N,N,N, +32077,N,N,N,29494,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28247,N,N, +N,N,N,N,N,30020,N,N,N,N,N,N,N,N,22564,N,N,N,N,N,29223,N,N,N,N,N,N,N,N,22840, +22841,28489,N,N,N,N,N,N,N,N,N,N,N,N,N,22094,N,N,N,N,N,N,N,N,30539,24366,26741, +N,N,N,N,N,N,21045,N,N,N,21333,N,N,N,N,N,29772,23164,N,N,N,N,N,22888,N,30571, +30025,N,29500,N,23122,N,N,N,N,N,N,N,N,21301,N,N,N,N,N,26678,N,N,22095,29754,N, +30537,N,N,19498,N,N,28739,19542,N,N,N,20563,N,21309,N,N,N,23419,N,19296,N,N,N, +N,N,N,21348,30327,N,N,21818,29517,19297,N,N,N,N,27508,N,N,N,N,N,29741,N,31786, +N,N,N,N,N,30572,N,N,N,26742,23143,N,N,N,30540,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,25921,N,N,N,N,24686,N,N,N,N,N,21885,N,N,N,N,N,N,20070,31787,21819,N,N, +29224,N,N,N,N,N,N,25125,19769,27250,19271,N,19828,N,N,23343,28505,N,N,N,N,N, +19770,N,N,31865,N,N,N,N,24435,20071,23106,N,20269,N,N,N,N,26489,30760,N,N,N,N, +N,N,29538,N,N,N,19058,24356,N,N,21572,N,N,N,N,N,19543,25922,N,N,N,N,19771,N, +28506,28248,N,23847,25126,N,N,N,N,N,24640,N,N,N,22064,30794,N,31866,N,22910,N, +N,N,N,24112,N,N,N,23916,23144,N,N,N,N,N,21600,N,22137,N,19799,24152,N,N,29304, +N,25686,N,N,20549,29742,N,23848,N,N,N,27973,29526,N,N,24153,25446,N,N,N,N,N,N, +21288,N,23344,N,N,25946,25407,N,N,N,23345,N,N,N,21865,N,N,N,N,N,24641,28507,N, +N,28777,N,N,22322,N,N,N,N,20605,N,N,N,N,N,N,N,N,22889,N,N,20606,N,27757,21289, +N,29225,28740,N,N,25186,26991,N,N,N,31057,N,N,26969,N,N,N,N,N,26714,23107, +23108,21573,N,26490,19808,25392,N,23346,31556,N,29539,N,22821,31591,23883, +20564,N,26166,24622,32090,N,N,N,N,N,N,N,N,23605,24696,26417,N,N,N,N,30064,N, +22620,27974,N,N,N,N,24889,N,25408,31040,26992,N,N,22875,N,29540,N,N,N,23606, +25705,N,N,N,N,N,28741,25409,31820,31821,N,N,N,N,29259,N,29260,N,N,N,25679,N,N, +N,N,N,N,N,N,N,29019,N,31321,N,28984,32117,24697,N,N,N,N,26491,31799,31844, +31557,25447,22585,N,30328,N,N,23621,19544,N,N,N,24623,29799,N,28508,20348, +28509,N,29226,N,N,N,N,N,N,N,N,N,32062,N,N,18988,32059,32071,N,N,N,N,26418,N, +27217,24436,N,N,N,N,20844,25694,25923,N,N,N,N,22822,N,N,19772,N,29541,N,N,N,N, +N,N,N,N,27989,N,N,22842,N,N,N,28007,31541,30828,N,N,N,N,24679,N,19545,N,N, +21574,N,N,N,N,N,26405,N,21877,21310,N,31867,N,N,N,N,N,N,N,N,N,N,N,N,25714,N,N, +24437,N,N,26744,30829,N,N,20039,N,N,N,N,N,32118,N,N,N,N,N,N,N,N,N,26712,N, +19800,26454,19546,N,N,19043,24438,28743,28742,N,22586,N,29044,29808,30028,N,N, +31845,N,N,N,N,27205,27251,N,23899,N,23639,N,N,N,N,N,N,24189,29305,N,21831,N,N, +N,22608,N,28744,20769,20770,N,N,N,N,N,N,22868,22120,22858,N,23089,22599,23650, +29518,30068,N,N,28985,N,N,23123,N,30314,N,N,N,20341,N,N,32046,N,N,N,N,N,N,N,N, +19026,N,N,24372,N,N,N,N,22365,31290,28199,30013,N,30837,N,N,28008,N,N,N,N,N, +21601,N,20771,24918,N,N,N,N,N,N,N,N,N,N,N,N,N,31096,N,23370,19321,21588,N, +22876,N,28222,N,30573,N,N,N,21102,N,N,24934,30585,N,N,N,N,N,N,N,23917,N,26715, +N,23347,N,N,N,20855,24624,N,N,21602,N,30295,N,22393,N,N,22621,N,19837,29227,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19773,30786,N,N,29228,N,N,18989,18990,20270,N, +N,N,N,N,25410,N,N,N,N,N,23607,N,N,N,N,N,N,N,N,N,N,23386,22843,19059,30291, +26232,27253,N,N,N,N,N,27254,N,N,30329,N,N,N,N,N,N,N,N,N,N,N,20271,N,N,19027,N, +N,18991,21040,28986,N,22323,25411,29565,24154,N,N,N,N,24155,N,N,28510,25187, +28283,N,N,24439,22346,N,N,N,N,N,N,N,N,N,20072,23387,N,N,N,N,N,N,N,28987,N,N,N, +N,26993,N,N,N,N,N,N,N,N,31287,20550,N,N,19499,28200,N,N,19322,31097,19581, +21374,N,N,N,N,25680,N,N,N,N,N,29294,N,21589,24397,N,31800,20816,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29261,N,N,N,N,N,N,N,N,30546,N,N,N,N,N,N,N,N, +19028,N,21849,N,N,N,22622,N,N,N,N,N,N,N,N,N,19801,N,N,N,28201,30268,N,N,19547, +N,N,N,N,N,28745,N,31868,N,26697,29822,N,N,N,N,26492,22366,N,N,N,N,24156,N, +28716,19582,19809,N,24890,N,23407,23090,N,N,N,N,N,N,N,N,N,N,N,N,N,20773,23608, +N,N,N,22646,N,20772,N,19810,N,N,N,N,23658,N,N,28791,N,28746,20542,N,23900,N,N, +N,N,21590,21334,N,N,N,N,N,N,27984,19745,N,N,N,N,N,24373,N,N,N,24440,N,N,N,N,N, +N,21537,20018,26698,N,N,N,N,27509,N,N,N,N,N,N,N,25429,30032,N,N,N,29985,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22823,N,N,N,N,N,N,N,N,25899,N,N,N,N,N,N,N,N, +N,N,N,N,26187,N,30065,N,N,N,N,N,N,N,N,N,N,25925,N,N,N,N,N,N,N,N,31011,24667, +30315,N,19313,N,22890,29986,N,N,N,22353,N,20856,27256,27257,23091,N,N,N,N, +28511,N,N,29039,N,25974,28223,25188,N,N,N,N,N,20543,N,31276,30033,26419,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26942,N,N,N,N,N,29262,23348,N, +N,N,N,N,N,N,N,31822,N,23918,N,N,N,N,N,N,26420,N,N,N,N,N,22324,N,N,N,N,N,N, +30516,N,N,N,N,N,19774,N,23145,N,N,N,N,N,N,N,20272,30553,29542,N,N,20057,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20010,N,19272,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,20519,N,28747,N,20551,25669,N,N,N,N,N,N,N,23392,N,N,N,N,N,N,21850,N, +22311,N,N,N,28224,N,30838,N,N,N,N,30034,28009,N,22844,N,25926,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,29987,N,N,23124,25127,31612,N,N,29020,N,N,N,N,N,N,19060,N,N, +N,26746,N,N,20073,N,N,N,N,N,N,27000,25189,N,N,N,N,20537,21618,N,N,N,N,N,20774, +N,24398,N,N,N,N,N,N,N,N,N,31860,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21290, +N,N,N,19500,N,N,N,N,28512,N,N,N,25957,20565,N,N,N,N,N,N,N,N,23420,N,N,N,N, +31846,N,N,N,N,N,19326,28010,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24113,N,N,N,N,N,N,N, +31075,N,N,N,N,N,N,21538,20342,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22096,N,N,N,N,N,N, +21866,29038,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31307,N,N,N,N, +25889,21809,N,N,N,N,N,20333,N,28011,N,N,N,N,N,21810,N,N,N,21820,N,N,N,N,N,N,N, +N,N,32098,29485,N,32091,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26928,N,N,N,N,N,N,N,20775, +N,N,32099,20019,N,N,N,N,N,N,N,32100,31310,N,N,N,N,18992,N,30503,N,20273,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,26146,N,31798,29229,28513,29486,23622,22891,N,N,N,26720, +N,N,N,N,N,N,N,24872,N,N,N,N,21878,20349,N,N,24157,N,N,N,22865,N,N,N,25706, +29263,N,30527,N,N,25190,25128,N,N,N,N,N,N,N,N,N,N,N,25430,N,27985,N,N,N,N,N, +27001,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22065,24114,N,N,24680,N,N,21291,N,27484,N, +N,24367,N,19011,N,N,28284,N,32067,N,N,N,27510,20274,N,N,N,N,22892,N,22845,N, +22623,N,N,21560,27454,23919,N,23920,23921,23922,N,N,22846,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,31558,20275,28285,N,N,N,N,N,N,25643,N,23109,N,22636,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,20776,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25129,N,N,24124,26421,N,N, +N,N,N,23408,N,28514,29040,20276,N,N,N,N,N,N,N,N,N,N,N,23409,N,24625,N,N,N,N, +24357,N,31058,N,N,26493,N,N,26147,31601,19248,29230,N,N,N,N,N,N,N,19815,N, +26716,N,N,26455,N,N,30528,N,20579,N,N,N,23073,N,N,N,19517,N,N,20777,23884,N,N, +25470,20778,26666,N,27190,31098,26188,30296,N,N,N,21575,N,N,N,22859,N,22866, +21323,22647,23081,30072,N,N,24158,29231,30761,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +22600,N,N,28225,N,N,N,N,31041,N,N,N,N,23923,27258,N,30269,24891,19775,29780, +26189,N,31823,31522,N,24668,N,N,N,N,29755,23125,N,31026,N,N,N,N,N,N,31602,N, +23414,N,24159,N,N,N,23410,N,N,N,N,N,30812,30574,27496,N,21114,N,N,28988,N,N, +31322,N,N,23146,23110,30529,N,N,26422,25927,22060,N,N,N,N,23623,N,N,N,N,N, +24873,N,25130,N,21798,N,N,21591,N,N,N,N,N,N,29264,N,27259,N,24669,31603,N,N,N, +N,N,N,N,28989,N,N,25191,32087,N,20040,27191,N,31808,N,32103,30575,N,N,22325,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28474,29021,N,24115,N,N,N,N,N,N, +26699,N,N,30813,N,N,31559,21832,N,22367,N,23849,N,N,N,N,N,26929,N,N,31277, +30297,31348,N,N,N,N,N,30762,N,N,N,N,N,26222,N,19548,24892,24687,N,N,26943, +31869,26190,N,N,24919,N,26191,N,29809,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,25715,N,N,25723,N,N,31076,N,N,N,N,N,N,N,N,N,N,28515,N,N,20334,30270, +24626,31870,20779,N,N,N,22394,N,N,N,31560,N,25175,N,N,N,N,N,N,21539,28792, +22312,N,N,N,24935,N,N,21311,N,N,N,N,N,N,28516,N,22341,27490,N,N,31847,N,N, +25634,N,25192,N,26192,N,31592,29800,25972,29756,29781,24374,N,31801,28226, +19061,N,N,N,28517,19298,21540,N,24160,23165,25670,26686,N,N,N,N,24670,30260, +27218,N,31099,N,N,24642,N,19044,N,26423,N,27261,N,22877,N,23092,28202,31593,N, +N,N,N,23371,23093,N,N,N,N,N,28990,N,N,21292,N,N,N,N,N,N,N,N,31561,N,24399,N,N, +21312,25431,N,28518,31824,N,N,N,N,N,N,N,26944,N,N,N,30035,N,N,27740,30519,N,N, +27192,20857,N,N,N,N,N,N,23624,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27193, +N,N,N,N,N,29022,N,N,N,N,N,22326,20277,N,22824,N,N,27758,N,N,23850,N,N,N,N, +19746,26670,N,N,N,24893,N,29265,N,N,N,N,26945,N,N,N,21116,N,N,N,N,N,N,N,23349, +N,29543,22654,N,N,N,31825,N,27954,29743,N,31523,N,N,31809,N,28203,21541,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29810,N,N,N,N,28249,N,N,N,31562, +N,N,N,N,N,19811,22587,25947,30839,N,N,N,30292,N,N,N,N,N,N,N,N,22313,N,19273,N, +N,26193,28748,N,N,N,N,N,N,N,N,N,N,22574,N,31059,21886,N,N,N,N,N,N,N,22588, +29232,N,N,N,N,25131,29544,N,N,N,N,N,28482,N,N,N,N,N,N,28012,N,26424,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,23166,N,N,19518,N,N,29308,23147,N,25176,27990,N,N,22097, +24627,N,N,31826,N,27464,N,N,N,N,N,N,N,N,21313,28749,N,20343,N,N,N,N,N,N,N,N,N, +27986,N,21592,23625,22385,N,N,24379,N,N,29477,N,N,N,29773,N,N,N,N,28991,30769, +N,27002,N,N,N,31563,N,N,19029,N,N,N,N,N,N,N,N,N,N,N,31060,30538,N,N,22088,N,N, +N,N,N,N,31848,29501,N,28286,N,26494,N,N,N,N,N,21314,N,N,N,N,21302,N,19501, +30330,22066,21080,N,N,N,N,N,N,26456,N,N,N,N,N,N,N,N,N,N,25381,N,N,N,N,26425,N, +N,N,N,28717,31564,27425,N,N,21542,N,N,N,N,31565,N,21821,29023,N,N,30331,N, +24116,N,N,N,N,N,N,N,N,N,N,N,N,21867,25928,N,N,N,31524,21561,N,N,24161,N,25635, +N,N,N,22327,N,30830,N,N,N,24117,N,N,22098,N,31061,26426,27477,21879,28519, +24894,N,N,N,31278,N,N,N,22121,22126,N,N,N,N,N,N,26427,N,N,N,N,N,N,N,27723,N,N, +N,N,N,N,21811,N,N,N,N,N,N,N,N,N,N,N,N,N,20020,N,N,N,31525,24942,N,N,N,N,N,N, +30504,N,N,N,N,31566,N,N,N,N,N,22589,N,N,N,N,N,N,N,31613,N,N,N,N,31849,N,N,N,N, +N,N,N,20278,N,N,N,27975,28204,N,N,N,N,N,N,N,19549,N,N,N,N,30247,N,N,N,26234,N, +N,N,29988,N,N,N,N,N,32092,27955,20041,N,N,N,N,N,N,28520,N,N,24895,N,N,N,N,N,N, +31323,19299,30505,N,31526,N,N,N,23609,N,N,N,28992,27976,28483,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,22061,N,N,32078,N,N,N,26657,N,N,N,N,N,N,N,N,31604,21799,N,N,N, +29046,N,26195,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19550,N,N,N,N,N,N,N,30770,N,N, +N,23659,32054,N,N,N,N,25962,N,N,29024,N,N,N,N,N,N,N,N,N,N,N,N,23372,23885,N,N, +N,21576,N,N,22893,N,N,N,N,29989,N,N,N,N,N,N,N,N,N,26235,N,N,N,N,N,26196,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,32072,N,22049,32063,N,31827,N,28449,N,26428,N,N,N,N, +N,20846,N,N,26197,N,N,26994,N,24368,N,N,N,N,N,22624,31802,32047,28750,N,23393, +N,N,25929,N,27956,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24643,N,N,N,N,N,N,25432,N,N,N,N, +27003,27176,N,N,N,N,32055,N,N,31527,N,26946,N,N,N,N,32119,N,N,N,N,N,25177,N,N, +23660,N,N,N,N,N,N,N,N,N,26658,N,N,N,N,26224,N,N,N,N,N,N,N,32120,32121,N,N,N, +30271,N,N,26407,N,26199,N,N,N,N,21619,21577,N,N,N,N,22138,N,22386,N,24896,N, +23394,26200,N,N,N,N,N,N,N,N,N,26429,N,N,N,N,N,28751,29502,25132,N,N,N,N,N, +30007,24688,N,N,N,N,N,N,N,N,N,N,N,N,32056,25448,N,21543,26748,31314,N,N,N,N,N, +30831,N,N,N,N,N,N,N,N,N,22099,N,N,N,N,N,N,N,N,N,N,21812,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,28752,N,30576,28211,N,N,27194,N,27219,N,N,27977,23851,N,N,N,25900,32033, +N,24400,27699,N,24401,N,N,N,N,N,28013,30776,30586,N,N,N,30763,N,N,N,N,N,29792, +N,N,N,N,N,21562,25651,N,26970,N,24118,N,22847,N,22848,22127,N,N,N,N,22860,N, +23082,N,N,N,N,N,N,N,N,24421,N,N,N,N,N,N,30565,N,N,N,19506,N,N,24441,22368,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21563,N,N,N,N, +32122,N,N,N,N,19507,N,N,23411,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24402,N,20042,N, +28250,N,N,N,N,N,N,N,N,N,25700,N,31567,N,N,N,N,N,N,20279,N,28227,N,N,N,N,N,N,N, +20074,N,N,N,N,N,N,N,25133,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22369,31349,N,N,21833, +30764,26457,N,N,N,N,N,N,N,N,N,N,N,29545,N,N,N,N,22637,25412,28785,N,N,N,N,N,N, +N,26725,N,N,N,24698,28228,22878,N,N,N,N,N,N,N,N,N,N,27426,27427,N,N,N,N,N,N, +31810,27195,N,N,N,N,26667,24162,N,N,N,N,N,N,N,N,N,N,28015,N,26659,N,N,N,N, +20337,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21564,N,31850,N,N,N,N,N,26430,N,31858,N, +N,22068,N,N,25134,N,21303,31308,N,N,N,N,N,N,N,N,31324,N,27957,24931,N,26668,N, +26717,N,N,28521,N,N,N,N,N,29757,N,20280,26971,20780,N,N,N,N,N,N,23111,N,N,N,N, +N,N,N,27465,N,26700,N,N,N,24119,N,N,N,N,22076,21349,N,N,N,N,N,31325,N,N,N,N,N, +N,23126,N,18993,N,N,N,N,N,N,23112,24358,N,31027,29266,N,19012,N,N,N,N,N,N, +20043,N,N,19829,N,N,N,32048,21800,N,28993,N,N,25193,23626,27700,31296,N,N, +31528,20520,N,N,23148,N,N,N,N,N,N,N,N,N,22894,N,24699,N,N,N,28522,31326,24644, +N,20281,N,21834,22370,25135,N,22328,N,N,N,N,N,N,N,N,N,26701,N,N,N,N,N,N,N, +30298,N,N,N,N,28450,25178,30332,N,N,31568,20781,N,19812,N,20782,23661,26702,N, +28793,20021,26236,N,N,22395,20566,23925,30577,N,30333,N,23415,N,N,N,N,31594, +26972,22849,N,30066,24645,N,N,N,N,N,N,27220,N,N,N,N,N,N,N,N,N,31042,N,27196,N, +21061,31569,26432,27429,N,24442,25378,22329,N,26947,N,26749,26671,N,N,29267, +31529,22565,N,N,N,N,21835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20552,N,N,N,20783,22371, +N,N,N,24646,N,22050,N,28016,N,N,N,N,N,N,N,N,N,N,N,N,22387,N,N,N,31828,N,23127, +19551,N,29268,N,20784,N,19552,N,23421,29503,N,28753,N,N,N,N,N,31803,N,25136,N, +N,26149,N,N,N,25179,N,N,N,24414,N,24647,N,N,N,N,N,N,29295,N,N,N,19553,N,N,N,N, +22122,N,N,N,N,26434,N,N,N,20022,N,29504,N,19838,N,N,N,31570,N,30840,30587,N,N, +26687,N,N,N,N,N,N,N,26679,N,N,N,N,N,N,N,N,27958,23610,N,N,19508,N,N,N,N,N,N,N, +N,N,N,N,N,29047,N,N,N,26680,N,N,19062,N,25636,29782,N,N,N,24422,N,N,N,24359,N, +24423,24897,N,26948,N,N,23627,26949,N,N,N,28451,27430,19235,25449,N,N,N,20859, +28452,N,28523,N,N,N,N,N,N,N,N,N,N,N,N,20532,N,N,N,N,19747,N,N,26726,N,28453,N, +21324,23149,N,N,N,N,22330,N,29269,30053,22895,N,N,N,N,31028,N,N,21844,32079,N, +N,N,23395,N,N,N,N,29025,27702,N,N,N,N,31614,21335,N,20785,N,19249,N,N,N,N, +20786,N,N,N,N,N,N,19250,28994,N,N,29793,31029,N,N,24899,24898,N,27511,N,N,N,N, +N,N,N,N,N,N,N,24360,N,N,N,N,N,N,N,19274,N,N,N,N,N,26169,N,N,N,N,N,30814,31018, +19063,N,27959,N,N,21304,29270,N,N,21593,28229,29296,N,N,N,18994,N,N,23611,N, +29048,N,N,N,N,N,27703,N,N,N,N,25930,N,30272,32093,N,N,21603,19554,N,30548,N,N, +N,N,N,N,22373,N,N,N,N,N,N,N,N,N,N,N,N,N,21315,N,22566,N,30273,N,N,N,N,N,23926, +N,19776,25948,N,N,N,N,N,N,N,N,N,N,N,N,25931,N,N,N,N,N,N,N,N,N,N,N,24900,N,N,N, +N,N,26672,29744,29546,23150,N,22331,N,25137,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,22314,N,N,N,N,N,N,22139,N,N,N,N,N,N,N,N,N,25695,N,19030,N,N,N,27432,N,N, +N,23422,N,N,N,N,N,N,N,N,N,N,30274,N,N,28475,N,N,N,N,21629,N,N,24648,N,N,N, +26681,N,28454,N,N,N,N,N,19748,N,N,21620,23329,23388,23389,N,N,N,N,N,28252,N, +19275,31829,N,N,N,N,N,N,20075,N,19777,N,N,31571,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,31019,N,N,N,N,N,N,N,N,N,N,N,30036,N,N,N,N,22825,N,N, +26973,23373,N,N,23886,N,26435,N,27724,N,N,N,N,N,N,N,31084,N,N,N,19276,N,N,N,N, +24700,21544,N,27987,22639,N,29271,N,19064,23151,N,N,22100,N,N,N,N,N,N,22861,N, +N,N,22638,N,29249,N,N,N,24403,N,N,N,23152,N,25194,24701,N,N,22648,N,N,N,30511, +23094,N,19031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29272,N,22649,N,N,N,N,N,N,N, +N,31327,N,N,N,N,N,N,N,N,N,N,N,N,N,20335,22850,N,28754,N,25681,N,N,N,29495,N,N, +N,N,N,N,N,N,N,N,N,N,31328,N,N,N,N,N,N,N,N,N,N,N,N,N,28524,N,N,N,N,N,25138,N, +21565,N,N,22862,N,N,N,N,29794,N,N,N,N,N,N,N,N,N,N,N,N,N,21545,N,N,N,N,19778, +26458,N,N,N,N,N,N,N,N,N,N,N,29273,N,N,N,N,N,22826,N,N,N,N,N,N,N,N,N,N,N,N, +22590,N,N,N,N,N,N,23597,N,N,N,N,N,N,25195,22140,N,N,19065,N,N,21594,N,N,N,N,N, +N,N,29783,19489,N,N,20282,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30008, +N,N,N,22851,20584,N,N,N,N,N,25413,27512,N,29233,N,N,N,20283,N,N,N,21293,26721, +20076,N,N,N,24628,24163,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23927,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,29234,29558,30299,N,N,N,N,22398,N,N,N,N,N,30815,N,30578,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,20521,N,N,N,N,N,N,N,N,N,26202,N,N,N,N,N,N,N,N,N,N, +N,N,N,29990,N,N,N,N,N,N,N,N,N,N,N,N,N,22332,19555,N,N,26203,N,N,N,N,N,N,N,N,N, +N,N,N,23901,N,N,N,N,20787,N,N,N,N,N,28525,N,N,N,N,22110,25716,24943,N,N,23928, +N,N,N,N,N,26703,N,N,N,N,N,N,N,N,N,N,N,19045,N,N,N,23585,N,24629,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,31788,31789,22567,N,N,N,N,27960,N,N,N,23350,N,N,N,N,22128, +29487,N,N,19749,N,23153,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22568,N, +N,N,19556,N,N,20788,N,N,N,N,N,19032,N,N,N,N,N,23154,29991,N,N,N,N,N,N,N,N,N,N, +N,N,29992,N,N,N,N,N,N,N,26150,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21868, +21880,23155,N,N,N,N,N,N,N,N,N,N,N,N,N,25414,N,N,N,24164,N,24165,20789,N,N,N,N, +N,20790,20791,29235,N,N,N,N,N,N,26974,N,N,N,N,N,28755,29236,N,N,28756,19300, +31572,30054,25450,N,24166,N,N,N,N,24404,N,N,30841,N,N,N,N,28718,N,N,N,N,N,N,N, +N,N,N,N,N,20792,N,N,N,N,22111,N,20567,N,N,N,N,N,N,N,N,N,N,N,31777,28526,23640, +N,26975,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25949,32123,N,N,24649,N,N,N, +22089,N,N,21546,N,25932,N,N,N,N,N,26976,N,N,N,20568,31778,21566,25139,24167,N, +N,N,N,N,N,N,23612,21046,30037,N,N,N,N,N,20001,29993,N,N,23929,N,N,23930,N,N,N, +N,N,N,28757,N,N,N,N,30303,N,29274,25707,N,29297,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,27705,32124,N,N,N,N,24874,N,N,19033,N,N,28527,N,29994,N,N,N,N,N,N,27769,N, +N,30765,N,29250,30275,N,22354,N,N,31010,28758,N,N,N,N,N,N,N,N,N,N,N,N,N,28794, +N,N,30304,N,N,N,N,26995,29251,N,N,N,21547,18995,19750,N,19779,19802,N,N,N,N,N, +22863,N,N,30276,N,N,N,28253,26436,N,N,N,N,N,N,N,N,25140,N,N,N,N,N,N,N,N,N, +24418,26459,N,N,N,N,N,N,26673,N,31790,N,N,N,N,25933,N,N,N,31339,N,20284,N,N, +20322,19830,N,N,28528,N,29758,N,21581,N,N,29496,N,N,N,26913,N,N,N,N,N,N,N,N,N, +29298,29547,N,28759,N,N,20311,N,N,N,N,N,N,20319,N,N,N,N,N,N,N,N,N,26688,26689, +N,N,N,20323,26914,N,N,N,N,N,N,N,N,N,N,20522,N,N,N,N,N,N,N,N,N,29505,20523,N, +21604,N,N,28476,22561,N,N,N,N,N,N,N,N,N,N,N,22879,N,29527,N,N,N,23613,N,19557, +28017,N,N,29026,N,21595,N,N,N,N,25141,N,N,19046,N,21294,N,N,N,N,N,N,19558,N,N, +29011,30055,N,N,N,N,19034,31598,N,24901,N,N,N,N,N,N,N,24425,N,28254,N,N,30530, +N,22562,N,N,N,N,N,23852,N,N,N,N,N,28719,22077,N,N,N,N,N,N,N,N,N,N,N,24875,N,N, +N,N,N,N,N,N,N,N,N,N,31030,N,N,21621,N,20553,28455,25196,N,23402,20044,30056, +30549,N,21325,N,29566,N,N,N,N,N,N,N,N,N,20533,N,N,N,N,N,N,N,N,N,N,N,24702,N, +24443,N,N,N,N,N,N,26205,N,N,N,N,N,N,N,26660,N,N,N,N,N,N,N,N,N,19277,N,N,N, +28456,N,N,N,28212,N,N,N,N,23128,20793,N,24361,N,N,29488,N,N,19524,N,N,N,20023, +N,N,N,N,N,N,N,N,N,N,N,28457,N,N,N,24405,N,N,27991,N,N,N,28230,N,N,N,N,N,N,N, +28477,31830,N,N,23412,N,28458,30777,N,30057,N,N,N,N,N,N,N,N,25433,N,N,N,N,N,N, +N,N,N,N,N,N,N,24902,N,N,N,21567,N,N,N,N,24168,28778,N,N,N,N,N,N,N,N,N,N,29506, +N,N,N,N,N,N,N,N,N,N,N,21295,N,N,19035,N,N,N,N,N,31831,N,N,27992,24903,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,29784,22067,23853,N,N,N,21822,N,N,N,N,N,N,N,N,28995, +28255,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22123,N,N,N,29785,N,N,N,N,N,N,N, +22374,N,N,N,N,N,N,23095,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23931,N,N,N,N,N,23887,N, +N,N,N,N,N,N,N,22563,N,N,23129,N,28760,28484,N,N,N,N,N,N,24920,N,N,N,N,N,29012, +N,28018,N,N,N,N,N,N,21851,N,N,21852,29508,19287,N,N,N,N,N,25142,N,N,N,N,28529, +N,N,N,N,N,N,N,N,N,N,N,31573,N,N,N,N,N,N,N,N,N,N,N,21336,N,N,N,N,N,N,N,23888, +28761,19251,N,N,N,N,N,N,21853,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19751,N,N, +20524,20794,N,28996,N,25907,31605,26977,32096,31804,N,23074,23075,N,21025,N,N, +21103,N,N,N,25197,N,N,24169,20060,29237,20580,23889,N,N,N,N,24904,23351,24419, +N,N,N,N,N,N,N,N,27961,28997,N,29519,22315,24876,N,N,25451,N,28231,N,N,N,24905, +19066,N,N,N,N,N,N,N,28795,31329,28762,19559,23156,N,N,N,N,N,N,N,N,N,19519,N,N, +N,N,N,N,N,N,N,N,N,N,N,20077,N,N,21801,31330,N,N,N,20581,N,27478,N,27743,N,N,N, +24444,N,N,30550,24170,19252,N,N,28478,N,N,19509,N,N,N,N,N,20285,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,28530,25143,N,N,N,19560,N,N,N,N,N,N,N,N,28796,N,N,N,22112,N, +28998,N,N,N,N,N,N,N,N,N,25144,27435,N,N,N,19253,22609,N,29774,29559,N,N,22342, +N,20795,30506,N,27978,22355,22650,N,N,N,N,N,N,N,30277,N,N,20812,23932,N,N,N,N, +N,N,N,N,N,N,24445,N,31077,N,24650,N,N,29309,21296,N,29811,23113,N,26206,N,N,N, +N,30778,26704,N,N,22651,N,N,27221,N,N,N,N,22051,N,N,N,N,N,N,30278,29275,25724, +N,N,N,N,N,N,N,N,N,N,26674,N,N,N,N,N,23130,N,29276,31574,26930,N,28205,N,31331, +N,N,N,N,N,N,N,23662,N,N,30058,26208,N,28797,N,N,N,N,N,22316,N,N,N,N,N,30021, +28256,N,N,23397,N,23902,N,N,22896,26915,N,N,N,N,N,N,N,N,N,N,29049,N,29252, +24651,N,N,N,N,N,N,N,N,26916,N,N,25145,N,N,N,N,N,N,N,25393,31851,19752,N,19510, +N,N,28763,N,N,N,N,N,N,N,N,26170,N,N,19753,N,N,N,N,N,29507,N,N,N,N,N,N,N,N,N, +24921,N,N,28459,N,N,N,26437,N,N,24681,N,29509,N,N,21568,21823,23854,N,31100,N, +19520,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25890,N,N,N,20024,N,N,N,22610,31062,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28970,20049,N,N,30279,N,23403,N,24446,N, +N,22625,N,30579,N,22375,N,N,N,N,N,N,N,N,N,N,N,21630,N,N,20796,N,25935,N,19254, +N,23096,N,N,N,N,N,19780,N,N,N,N,N,22078,N,N,N,25146,N,N,N,N,N,20312,N,N,N, +24652,27513,N,N,N,N,N,N,N,N,32125,N,N,N,N,N,22376,19288,N,N,N,26978,N,N,N, +26682,N,N,N,25415,N,N,N,N,27725,N,27726,N,22079,N,N,N,25383,N,24406,32104,N,N, +N,N,N,N,N,N,N,28257,30248,23933,N,N,N,N,N,N,N,30779,N,26705,N,N,N,N,31063,N,N, +N,N,N,N,N,N,20078,N,N,27727,26917,22101,N,19781,N,27962,20797,N,N,20286,N,N, +27707,N,N,N,21041,N,N,N,N,19561,N,22852,27004,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,20798,N,N,N,N,N,27708,N,N,25901,N,N,N,N,N,N,30512,N,19562,N,N,N,21316, +N,N,22080,N,N,N,22141,N,N,N,N,N,N,N,N,N,N,N,24865,N,24125,N,30249,N,N,N,23076, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22052,30022,N,24866,26950,N,N,N,29253,N,N,N,N, +N,29801,22124,27475,N,N,N,N,27709,25180,24171,28764,N,27455,N,22350,20799,N,N, +N,N,N,N,N,N,N,29995,N,N,N,N,31101,N,19036,N,N,N,19782,29238,N,N,23934,N,N,N, +19511,23352,N,N,N,N,20585,N,20061,27456,N,32034,N,N,N,N,N,30795,N,N,N,N,N,N,N, +N,27222,28976,N,N,N,N,N,N,N,23374,N,30531,N,N,N,N,N,N,N,N,N,N,N,23375,19236,N, +N,30816,N,N,31575,N,N,27466,24609,N,N,N,N,N,N,N,N,N,N,N,20045,N,N,21596,N,N,N, +32088,N,N,N,N,21110,29239,N,N,31350,30250,31351,22630,N,29745,N,N,N,N,N,N,N,N, +N,N,N,N,N,26706,N,19013,19563,N,N,N,N,N,N,N,25198,N,N,N,N,N,25147,N,30509,N,N, +N,30817,N,N,N,N,N,N,N,N,N,29548,N,N,N,N,24097,N,N,N,N,N,N,N,N,N,N,N,N,25725,N, +N,25452,N,23855,23856,N,N,19255,26707,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24867, +21088,N,N,N,N,28798,N,N,N,N,26918,19314,N,N,N,N,N,N,28019,23641,24653,N,N,N,N, +30554,23353,N,N,N,N,N,N,N,19502,N,23131,N,N,N,N,19783,N,N,N,N,N,N,N,N,N,N, +23857,N,22575,25379,N,N,20079,N,N,29299,N,N,N,N,30771,N,N,N,N,N,N,N,N,N,N, +24654,N,30077,N,N,N,N,27500,N,N,21317,31852,21083,21611,N,24098,N,N,N,25958,N, +N,N,N,N,N,28720,N,N,N,N,N,N,N,N,N,N,21828,N,N,N,N,N,N,28020,N,N,N,25453,N, +26690,N,28021,22396,N,27963,N,N,30251,N,N,N,N,N,29240,30280,N,N,N,N,N,21350, +29277,20287,N,27436,20288,N,26152,32105,N,20289,N,24671,24172,N,N,N,N,24610,N, +N,N,N,N,N,N,N,29759,25199,N,22897,28999,N,19256,N,N,N,N,N,N,N,N,31102,23354, +23157,N,N,N,N,N,N,N,N,30316,23132,31332,N,24655,N,N,N,N,N,N,23858,N,N,N,N, +26153,N,28531,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29549,N,N,N,N,N,N,N,N,N,N, +27514,N,31078,N,N,N,N,N,N,N,19037,21854,N,19038,24420,N,N,N,26237,N,29996,N,N, +N,N,N,25717,N,N,N,N,N,N,N,N,N,N,N,N,26979,N,27979,20324,N,N,N,22611,N,N,N,N,N, +N,23859,21612,N,N,29241,N,24375,N,N,N,N,N,19278,31576,N,N,20569,N,N,23890, +30580,26460,25637,N,31779,N,23355,N,N,N,29242,27005,20554,N,30038,22853,25652, +N,27943,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27197,26238,N,30532,29997,N,22880,N, +N,N,18996,N,N,30818,20290,N,27710,N,N,N,25908,19784,28232,N,N,N,N,N,N,N,N,N, +26440,N,N,N,N,N,N,N,N,N,N,N,19785,31031,29032,22898,23413,18997,22854,N,N,N, +22601,N,N,N,N,N,N,N,N,N,N,N,N,N,22827,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27964,N, +N,22612,N,N,N,23642,N,25148,N,N,31853,27744,21118,N,26951,26154,N,N,N,N,N,N, +25200,N,N,N,N,N,N,31291,N,29998,31530,N,N,N,N,27771,N,27711,31832,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21605,N,N,N,31043,N,N,N, +28258,N,N,N,N,N,N,N,N,N,N,N,N,N,22377,28022,N,N,N,24173,N,N,N,N,N,N,N,19564,N, +25454,N,N,N,N,N,26708,N,N,N,31352,N,N,N,N,N,N,23860,25653,22576,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,22613,N,N,N,29802,N,N,N,20025,N,N,N,22113,20306,N,20534,N, +N,N,N,N,N,20002,N,N,29550,N,N,N,N,N,29560,N,N,N,N,N,N,N,N,N,N,N,N,23628,N, +20555,N,N,N,31780,19786,22356,24099,N,25696,N,N,N,N,28233,N,N,N,25181,30078, +21548,N,N,N,N,N,21841,N,22640,30787,27223,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,30039,N,N,22591,N,N,N,N,32064,N,N,N,N,N,N,27437,N,N,N,N,21802, +N,N,N,N,N,N,N,N,N,N,N,26408,N,N,N,N,N,N,N,N,N,N,N,N,N,28234,N,N,N,19047,N,N,N, +N,N,30819,N,21597,N,N,27224,N,N,N,N,31577,28023,N,N,25909,N,N,N,N,N,20525,N,N, +N,N,29041,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25149,N,N,N,25416,N,N,N,N, +22869,N,N,24362,N,N,N,N,23356,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30820,N,N,N,N,N, +29050,N,N,25910,29551,N,N,31578,24928,N,22828,N,30059,N,24630,N,N,26952,N, +19279,N,25417,N,N,N,24174,N,N,N,N,N,N,N,N,25150,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,23663,N,22053,N,N,N,N,N,25201,N,N,N,N,N,N,N,22142,22817,N,22592,23643,N,N, +27965,24376,N,27173,N,N,N,22317,N,N,29561,N,28024,N,30023,N,N,N,N,N,N,24906, +27491,N,29278,N,N,N,N,N,N,N,N,N,N,N,N,N,30796,N,27225,N,21318,N,23398,N,N,N,N, +N,29999,N,N,N,N,20080,N,N,N,N,27006,N,N,N,N,N,31542,N,N,N,N,N,N,N,N,N,25202,N, +N,N,N,20338,30521,22899,N,N,24907,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +23133,N,N,23097,N,N,N,N,N,N,N,27515,N,19257,N,N,28025,N,N,N,N,N,N,24672,N,N,N, +N,N,N,N,N,N,N,29760,N,32060,24369,25455,N,N,N,N,24611,32057,N,N,N,N,N,N,N,N,N, +28721,N,N,N,N,N,N,19787,N,N,N,N,N,N,N,27966,N,N,N,21824,25456,28026,N,N,N,N,N, +26980,N,N,N,N,N,N,21869,26461,N,N,N,N,N,N,21622,25911,N,N,N,23399,25151,N,N,N, +N,N,N,N,N,N,N,N,N,28235,N,N,22388,28765,N,N,N,20011,26462,N,N,N,22102,24908,N, +N,26675,N,N,N,N,N,N,N,N,N,N,N,25966,23586,N,N,24656,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,21813,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21793,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,31579,N,31051,N,N,N,19315,29733,N,N,N,N,N,31304,22103,N,26981,31580,N,N, +N,N,N,N,N,32080,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31606,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,23077,N,23357,N,N,N,N,N,N,27746,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19831, +28766,N,N,N,N,30281,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +24175,N,N,N,21297,N,N,N,N,N,N,N,N,31854,N,N,N,N,26691,N,29000,N,N,N,20081,N,N, +N,N,31085,N,N,N,N,N,N,N,N,29300,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25654,30009,N, +23664,25457,N,N,N,N,26661,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29243,N,24100,N,23116, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,19049,N,N,N,N,N,N,25434,N,31833,N,N,N,N,N,N,N,27226,N,N,N, +N,N,N,31044,N,25380,N,N,N,N,N,N,N,N,N,N,N,31581,N,28490,N,26692,N,N,N,N,N,N,N, +N,N,21836,N,N,N,N,N,N,N,N,N,N,27479,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22829,N, +N,31531,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21337,N,N,N,N,N,N,21794,N,N,N,N,N,N,N, +N,N,30302,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23158,N,N,N,N, +N,N,N,N,N,N,N,24657,N,N,26920,N,N,30073,N,N,N,N,N,N,31279,N,27516,N,N,24682, +25394,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21829,N,N,29027,21870, +N,N,N,N,N,N,N,N,N,N,N,N,N,19788,N,N,N,N,27993,N,N,N,N,22593,N,N,N,N,31340,N,N, +N,N,N,29035,N,N,N,N,N,31292,26210,N,N,N,N,31333,25210,N,N,N,18998,N,25655,N, +27227,N,30074,N,N,N,31532,20291,27517,N,N,N,N,30842,N,N,24377,N,N,N,N,24945,N, +21028,N,N,N,N,30075,N,N,N,N,N,N,20570,20571,N,27198,22833,N,N,N,N,N,18999,N,N, +21351,N,30821,N,N,N,N,21298,N,N,N,25152,29279,N,N,N,N,N,N,19813,N,N,N,N,N,N,N, +N,N,N,N,N,31020,N,N,N,N,N,N,N,N,19789,N,N,N,N,N,N,N,N,N,N,N,N,28206,22062,N,N, +N,N,N,N,N,N,N,N,N,N,22378,N,N,N,N,26464,27438,N,N,N,20313,N,N,23629,28027,N, +24176,N,22379,N,N,N,N,N,N,24101,N,N,N,N,N,N,N,N,N,N,24407,23376,23377,N,N, +21795,N,N,N,N,28722,23644,N,N,N,N,N,N,N,N,19048,N,30822,23630,N,N,N,N,27228, +23378,N,N,N,N,N,N,N,N,N,N,N,26931,N,N,N,N,30555,N,N,N,N,N,N,N,N,N,N,N,25384,N, +22318,N,N,24673,N,N,N,N,N,19258,N,N,25937,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,20572,N,N,N,N,21825,N,N,N,N,N,22602,N,N,N,N,N,N,N,25385,N,N,N, +N,N,N,N,N,N,N,N,N,24612,N,26921,N,21319,N,N,23645,30766,N,N,N,19512,N,N,N, +20526,N,N,N,22642,N,N,25418,N,N,N,N,N,N,N,N,N,N,19503,N,N,N,N,N,N,N,21549, +30289,N,N,N,N,N,N,N,20556,N,N,N,N,N,N,N,19014,N,N,21826,N,N,20026,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,19015,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31280,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,24408,N,N,N,30010,25963,N,28532,23861,N,N,N,N,19754,N, +25458,N,31607,N,30544,N,N,N,N,32058,N,N,32097,30334,20800,N,N,26693,N,25656,N, +24936,N,N,N,19521,N,21101,N,N,N,N,23358,N,N,24674,N,N,N,31305,N,N,24909,N, +19000,N,N,N,29280,29001,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24177,N,N,N, +28767,30788,N,N,N,N,N,28236,N,N,24178,N,26441,N,25203,26465,N,N,25419,N,N, +25420,N,N,N,20344,28460,N,32126,31781,31281,24409,N,24658,N,N,N,29786,N,N,N,N, +N,N,N,N,N,N,N,29002,N,20003,N,N,N,N,29244,27747,N,N,N,N,N,24613,N,30507,N,N, +27439,N,N,N,N,N,25950,N,24868,19755,N,22900,26662,19790,24937,N,31855,N,24675, +N,N,N,N,N,25153,N,20004,N,N,N,N,N,N,24102,N,N,27518,N,27485,28768,N,N,29787,N, +25204,N,N,21320,N,N,N,29803,N,28213,N,30040,N,N,21855,N,N,N,22117,N,N,N,N, +27440,29795,N,N,N,N,25421,N,N,N,N,29812,31282,N,N,28533,19039,N,27441,27967,N, +N,32073,N,N,N,N,25638,31012,28723,N,25964,N,N,N,20839,22855,25687,27229,N, +21623,N,N,N,N,N,N,N,N,N,23098,N,23117,N,N,N,31052,N,24922,23359,N,19525,27728, +19259,N,24179,N,N,26922,N,N,N,N,N,N,N,22856,N,N,28259,22333,N,N,N,N,N,N,20292, +N,N,N,N,N,20557,N,N,N,N,N,N,N,31782,N,N,N,N,N,N,N,29051,N,N,N,N,32082,20801,N, +N,N,N,N,N,N,N,25435,N,21321,N,23631,N,N,N,N,N,N,N,N,N,19565,N,N,N,N,N,24103,N, +N,26171,27681,N,N,N,19513,N,N,31582,N,N,N,N,N,26466,N,N,21569,N,N,N,N,N,N,N,N, +N,23592,N,N,N,N,N,25154,N,29528,25939,N,N,29529,N,N,N,29510,19803,N,N,N,N,N,N, +N,19756,N,31811,N,N,N,N,21607,N,20802,N,31013,N,26709,N,N,N,N,N,N,N,N,25422,N, +N,N,N,21578,N,N,N,N,N,N,24410,N,N,N,N,N,N,N,N,31583,26467,N,N,N,N,N,N,N,N,N,N, +N,N,N,30843,25423,N,N,N,N,N,N,N,30000,N,N,N,N,N,N,N,22631,N,22857,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,30767,28534,N,23862,28207,19832,N,N,N,N,24120,31783,30588, +30513,20027,29729,N,N,28237,24878,N,N,27715,20350,N,30783,22626,21352,N,N, +24104,29796,27714,N,22901,31045,23891,22129,27772,31856,N,N,27968,19001,N, +28260,N,N,N,N,N,N,29281,N,24121,N,N,N,N,N,N,22130,N,24180,N,24411,N,23379,N, +31335,22627,29761,N,23863,N,N,N,29301,N,N,21550,N,N,N,N,N,N,22131,N,N,N,N,N,N, +23864,20293,24415,29246,30241,N,27467,29052,N,29511,N,N,24683,N,N,N,N,N,28028, +N,N,24923,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,28261,N,24181,N,N,N,N,31315,N,N,N,N,29003,N,N,20527,23865,N,N,20803,N, +N,N,N,N,N,N,N,N,N,N,N,N,30001,N,N,N,N,27206,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28769, +N,N,N,N,N,N,N,N,N,30252,N,N,N,N,30041,N,N,N,N,N,N,N,N,N,N,28779,N,N,N,N,N,N, +23866,N,N,N,29247,N,N,N,N,N,N,N,30533,N,N,N,N,23330,29302,N,N,19002,N,N,N,N,N, +N,N,N,N,N,N,30581,N,19301,N,N,N,28262,N,24659,N,N,N,N,20005,N,N,N,N,N,N,22104, +N,N,N,21551,26953,N,N,N,N,21326,29762,N,N,N,N,N,N,N,N,N,N,N,N,N,19302,N,N,N,N, +N,N,N,N,N,N,N,28961,N,N,N,N,N,27442,N,N,N,N,28962,N,N,N,N,N,N,N,N,N,N,N,N, +27443,N,28724,N,N,19316,21552,29490,31543,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30060,N, +N,N,N,N,28263,29746,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30061,N,20339,N,N,N, +N,N,N,N,N,N,N,28770,N,N,N,N,N,28238,N,N,29004,N,N,25912,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22389,25459,20325,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,20294,N,N,N,N,N,N,N,N,N,29491,25688,20345,20314,N,N,N,N,31309,N,N, +N,N,N,N,N,N,N,N,N,N,26211,N,N,N,N,N,N,N,N,N,N,N,29282,N,N,N,N,N,N,N,N,N,N,N,N, +30062,N,N,19003,N,N,25436,20082,N,22105,N,N,N,28208,N,N,N,N,N,N,N,N,29797, +22594,23632,19566,N,N,N,N,N,21856,30282,32074,22614,29775,N,N,N,N,N,N,22054, +23614,N,23380,22343,N,N,N,N,29310,N,N,N,29005,N,N,N,N,25155,23646,N,23647,N,N, +28461,26155,N,N,N,N,31069,27199,N,N,N,28462,N,N,N,29776,20083,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,26156,N,20062,N,N,21881,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25460, +19792,N,N,N,N,N,N,21816,N,N,30589,N,23593,N,N,N,N,24182,N,23594,29283,26932, +21084,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26982,N,N,25462,N,N,N,N,N,N,N,N,26442,N,N, +20558,N,N,23159,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19004,N,N,N,28264,23134,N, +29303,N,N,25211,N,19494,N,N,N,N,23099,N,28265,N,N,N,30042,30556,24938,20033, +21553,N,32049,26173,N,31533,N,N,30823,N,24910,N,30562,30063,20295,N,N,21554, +19567,N,21608,N,28239,30551,N,N,24614,22081,24924,28771,29028,23665,22055,N,N, +N,N,N,N,N,N,N,N,29813,N,N,29006,29284,N,N,20528,N,N,27759,N,N,N,31034,N,27445, +N,N,21613,25156,N,N,N,N,26983,N,N,27444,27169,N,30780,20006,N,31046,31834,N, +21555,21305,27230,N,N,N,26923,N,N,24929,21327,29814,N,27200,24911,N,19514,N,N, +N,N,N,28266,N,N,N,28772,29492,21614,N,N,29248,N,N,29029,N,29763,24660,N,27446, +N,22305,19304,N,31021,26925,22628,31283,25157,31805,N,N,27716,22577,N,23595,N, +N,N,N,21796,N,27497,N,N,N,26683,N,N,N,22615,N,N,N,N,N,N,N,N,31534,20833,N,N, +23360,N,30014,N,24183,N,N,N,N,19067,30534,20296,N,N,N,24912,N,N,28240,N,N,N,N, +N,N,N,N,26996,N,N,N,N,N,N,N,N,20084,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +21837,N,N,20315,N,N,N,N,N,N,23867,N,N,N,N,20012,N,N,N,N,N,N,N,26984,N,N,N,N,N, +N,N,21556,25671,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30043,N,N,31297,N,N,N,24105,N,N, +N,N,N,N,N,N,N,N,N,N,N,21624,N,N,N,N,N,28535,N,N,N,N,21299,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,27447,28536,30044,27980,23381,29007,N,N,N,29008,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,30002,N,N,N,N,N,N,22830,21804,N,25158,N,N,N,N,N,N,N,N, +32035,N,31589,24363,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25205,N,30253,N,30003,N,28725, +N,N,N,N,24869,N,N,N,N,N,N,N,N,N,30045,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27682,28029, +N,30004,31544,N,23331,N,N,22090,19289,N,N,N,N,N,N,N,N,N,N,25940,N,N,N,N,N,N, +29562,N,27448,N,24631,22380,29036,25903,21857,22381,20817,N,N,N,N,N,24946, +28537,N,N,N,23868,30300,N,N,N,N,N,28773,N,N,N,29764,N,N,26985,N,N,N,N,N,N,N,N, +N,N,29563,21615,N,N,19490,30590,24380,N,N,N,N,27469,N,N,N,N,N,N,20535,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22082,N,N,N,N,N,26669,N,N,N,N,28463,19237,N, +N,N,N,19305,N,N,N,31336,N,N,N,N,N,N,N,N,N,N,N,N,N,19526,N,N,N,26215,N,N,27207, +N,N,N,23332,N,20297,25212,28538,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,27486,N,N,30024,N,21598,N,N,N,N,N,N,N,N,N,N,N,24661,N,28464,N,N,25159,N, +22831,N,N,N,31079,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26469,N,N,20298, +24913,N,25160,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28539,N,N,31353,N,N,23666,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24615,N,N,N,N,N,30824,N,N,N,N,N,N,N,N,N,N,N,N, +N,19306,N,N,N,19260,22114,N,N,N,N,N,N,N,N,N,N,N,30046,N,N,N,N,N,N,N,30047,N, +28214,N,N,N,25206,21322,28540,20804,28465,N,20805,N,20574,N,22881,N,N,24632,N, +N,19793,29497,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26444,N,22056, +20007,N,21557,N,N,N,N,N,N,25672,N,N,N,N,N,N,21300,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,27449,N,N,N,N,N,N,19317,N,N,N,N,N,N,30301,N,28963,N,N,N,N,N,N,N,N,N,N, +N,N,N,19527,N,N,N,N,N,N,N,26954,N,24944,N,N,N,30048,N,N,N,N,N,N,N,N,31535,N,N, +N,19281,N,N,N,N,31584,29285,N,N,27760,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +28780,N,N,N,N,N,N,N,N,N,N,N,N,N,28267,N,N,N,N,N,N,N,N,N,N,N,N,26955,N,N,19568, +N,N,22319,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29473,31861,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,28964,N,N,N,N,N,N,N,N,N,N,N,N,24662,N,N,N,N,N,28466,N,N,N,N,N, +N,N,N,N,29777,N,N,30497,N,N,N,N,N,N,N,N,N,N,N,29009,N,N,N,N,N,N,N,N,N,N,N,N, +19068,19069,N,N,N,N,N,N,N,N,20046,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,29512,N,29498,28030,N,N,N,N,N,N,N,N,23078,N,N,24684,N,N, +N,N,N,30797,N,19282,N,N,N,27470,N,31064,31065,19040,23114,N,N,N,19238,N,N,N,N, +N,N,N,N,N,N,19016,31086,23404,N,N,20529,N,N,N,N,21871,N,N,N,26227,N,N,N,N,N,N, +N,N,N,26402,25689,N,N,N,N,N,N,N,N,N,N,25697,N,N,31812,N,N,N,N,N,N,N,N,N,31087, +20340,30566,N,N,N,N,N,20028,N,N,N,N,29765,23587,23869,N,N,N,N,29766,N,N,N,N,N, +N,N,N,30753,N,N,N,26710,N,N,N,23361,N,N,N,N,N,N,N,N,28774,N,N,N,25657,30317,N, +31022,N,23870,N,N,N,N,N,N,22320,22632,19261,N,N,31066,N,N,N,N,N,N,N,N,N,N, +30798,31088,24685,25395,29747,N,N,27202,29286,28726,N,N,N,N,N,23382,N,N,N,N,N, +27492,N,N,29287,N,22357,21558,31080,22337,N,N,N,N,25941,N,N,N,N,N,N,N,26986, +22348,N,N,N,21353,25161,N,31835,19757,N,N,N,N,N,19504,27170,N,N,25718,20544,N, +28727,28193,N,N,N,N,N,N,22390,N,N,N,25162,25163,N,31311,N,N,N,N,N,N,27487,N,N, +N,N,N,22091,N,N,N,29748,N,N,N,N,27981,25682,N,N,27177,25658,29474,19794,N, +30283,N,29030,27969,26684,28241,N,N,N,N,N,N,28775,25164,N,N,25642,N,30049, +27994,N,N,N,N,N,22382,20849,N,N,N,N,26987,26988,24676,N,N,N,N,23079,23892,N, +27171,N,N,N,22083,22132,N,23135,N,28467,25165,N,N,N,N,N,28541,29288,N,N,N,N,N, +N,N,N,N,28485,N,26471,N,N,22397,N,N,26446,N,N,24412,N,31047,N,N,N,N,N,N,N,N, +22902,N,N,N,N,N,N,N,N,24364,N,22106,N,N,N,N,N,N,23588,N,N,N,28728,N,N,N,N, +21882,N,25719,N,N,N,22084,N,N,N,N,N,N,N,N,29804,N,N,N,N,28542,N,N,N,N,N,28705, +N,24106,N,N,23100,22652,N,N,N,N,N,N,31316,N,N,N,27749,N,N,N,N,N,N,31784,N,N, +27750,N,N,22603,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31545,N,25683,N,19833,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,20307,N,N,N,N,N,N,N,19050,N,N,20308,N,30781,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29767,N,N,N,N,27231,N,N,N,N,N,N,N,31067, +N,N,N,N,N,N,N,N,21559,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27493,N,N, +24914,N,N,N,N,27172,N,N,N,31298,31585,31341,28706,19569,N,31267,25207,N,25166, +N,26997,N,24939,N,N,N,26472,26711,23160,21579,N,N,N,30582,22085,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,21609,N,N,31354,N,N,N,N,N,N,N,19570,30557,N,24122,N, +N,N,N,N,N,N,N,N,N,20008,N,N,N,N,N,28729,25726,25673,N,N,N,N,N,25684,N,N,N, +27203,N,28468,N,N,N,22334,N,N,N,N,N,N,31586,N,19795,N,N,N,28469,N,N,N,31337,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31014,N,N,N,N,N,N,24381,N,30535,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,30845,N,N,30844,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +24107,23400,N,N,25437,N,24930,20806,N,N,N,N,N,N,N,N,N,N,30288,27494,23161,N,N, +N,N,27719,N,N,N,N,N,N,N,24184,30825,25438,20085,N,N,N,N,N,31299,25943,N,27720, +N,N,N,29513,N,N,25659,N,N,N,N,26158,N,N,N,N,N,28470,N,23615,N,N,N,N,N,N,N, +20029,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22595,N,N,N, +20559,N,20346,29514,24663,N,N,N,20807,26926,N,26685,N,N,31300,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25167,N,N,31301,N,N,N,31032,N,N,N,N,N,N,N,23648, +N,N,31536,N,N,N,22569,25951,31015,N,N,30318,N,30284,25208,N,N,N,N,27761,N,N,N, +N,N,N,N,23136,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29010,21068,20299,N,N,19005,N,N,N, +23871,N,N,N,30319,N,24185,N,N,N,N,N,N,N,N,N,N,N,N,N,31284,N,N,N,21805,N,N,N,N, +N,N,N,N,N,N,N,N,N,29031,24126,N,N,N,N,N,N,23616,N,N,N,N,N,20808,20809,N,N,N,N, +N,N,N,N,N,30782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19318,N,N,N,N,21625,N,N,N,N, +N,30050,24915,N,N,N,N,N,N,N,N,22633,N,N,30846,N,20300,N,N,N,N,N,N,N,32036,N,N, +N,N,N,N,N,20086,N,31312,N,N,19571,26174,N,N,N,30254,N,N,21872,N,N,20810,N,N,N, +31806,21873,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19817,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,31285,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25168, +29815,N,N,N,19796,N,N,N,N,N,N,N,N,N,N,N,N,26403,N,N,N,N,N,N,N,N,23333,25169,N, +N,N,N,N,N,N,N,N,N,N,N,22306,N,N,30563,N,N,N,N,N,N,27174,N,N,N,N,N,N,N,N,N,N, +20513,N,N,N,N,20058,31595,23334,23390,22629,N,N,N,N,N,N,N,N,N,27232,N,N,N,N, +22570,N,N,N,N,N,25952,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22107,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28486,N,N,30826,N,N,N,N,N,N, +N,N,N,N,N,N,N,25685,N,N,N,N,N,N,N,N,N,N,N,20087,N,N,24664,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22383,N,N,N,N,N,N,N,N,N,N,N,N,29805,N,N,N,N,N, +N,N,N,N,N,N,N,N,19814,N,N,N,19572,30051,N,N,25674,N,23649,N,N,31048,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,31807,N,N,N,N,N,N,N,N,N,N,N,N,26663,N,N,N,N,N,N,N,N,22596, +N,N,N,N,N,N,N,N,N,N,N,19262,N,23598,N,N,N,N,N,N,N,N,N,N,N,N,N,22391,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28776,N,23872,N,20301,N,N,N,N,N,N,N,N,N, +23667,22832,N,26217,25660,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27204,N,N,N,N,N,N, +N,N,N,N,25708,N,25701,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31608,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,19515,N,N,N,N,N,N,N,N,N,N,N,25661,N,N,19804,22903, +N,N,N,N,N,N,N,N,N,N,23903,N,N,N,N,N,27982,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22864, +N,N,N,N,N,25891,N,N,N,N,31053,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19758,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,20302,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,30255,N,N,N,N,N,32083,27501,22108,25892,N,N,N,21814,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22109, +N,N,N,31081,N,N,N,26404,N,22115,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20811, +22116,N,N,N,21874,N,N,N,N,N,24186,N,22392,N,N,N,N,N,22634,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,20309,22653,N,N,N,N,N,22571,N,N,32075,N,N,N,N,31836,N,N,N,N,N,N,N,N,N, +24616,21875,N,N,32089,N,N,19491,N,N,N,22905,N,N,21354,30069,N,28487,N,N,N,N,N, +N,N,N,N,21338,N,N,N,N,N,N,N,N,N,N,N,23101,26664,23599,N,N,N,N,N,28707,N,N,N,N, +19797,N,N,N,N,N,N,N,N,N,N,N,N,24617,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,24108,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28730,28209,N,N,28210,N,N,N,30285, +N,N,N,N,N,N,N,N,N,N,N,N,28242,N,22086,N,N,N,N,N,24677,N,N,29499,N,25953,N,N,N, +N,N,N,N,N,N,N,25675,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22307,N,N,23362, +N,N,N,N,19070,N,N,N,N,N,N,20303,12321,12322,33089,33090,12323,33091,33092, +12324,12325,12326,12327,33093,33094,33095,33096,33097,12328,12329,12330,12331, +12332,12333,12334,12335,33098,12336,12337,12338,12339,12340,33099,33100,12341, +33101,33102,33103,12342,33104,33105,33106,33107,33108,33109,33110,12343,12344, +33111,12345,12346,12347,33112,33113,33114,33121,33122,33123,12348,12349,33124, +33125,12350,33126,33127,33128,12351,33129,33130,33131,33132,33133,33134,33135, +33136,33137,33138,12352,33139,12353,33140,33141,33142,33143,33144,33145,12354, +33146,33153,33154,12355,33155,33156,33157,12356,33158,33159,33160,33161,33162, +33163,33164,33165,33166,33167,33168,33169,33170,33171,33172,33173,33174,33175, +33176,12357,12358,33177,33178,12359,33179,33180,12360,12361,33181,12362,33182, +33183,33184,33185,33186,12363,12364,33187,12365,12366,12367,12368,33188,33189, +12369,12370,12371,12372,33190,33191,33192,12373,33193,33194,33195,12374,33196, +33197,33198,33199,33200,33201,33202,12375,12376,33203,12377,12378,12379,33204, +33205,33206,33207,33208,33209,12380,12381,12382,33210,12383,33211,33212,12384, +12385,33213,33214,33215,33216,33217,33218,33219,12386,12387,33220,12388,12389, +12390,33221,33222,33223,12391,33224,33225,12392,33226,33227,33228,12393,33229, +33230,33231,12394,33232,33233,33234,33235,33236,33237,33238,33239,12395,33240, +12396,33241,33242,33243,33244,33245,33246,33247,33248,12397,12398,33249,33250, +12399,33251,33252,12400,12401,33253,12402,33254,12403,33255,33256,12404,12405, +12406,33257,12407,33258,12408,12409,33259,33260,33261,33262,33263,12410,12411, +33264,33265,12412,33266,33267,33268,12413,33269,12414,33270,33271,33272,33273, +33274,12577,12578,33275,12579,33276,12580,33277,33278,33345,33346,33347,33348, +12581,33349,33350,33351,12582,33352,33353,33354,12583,33355,33356,33357,33358, +33359,33360,33361,33362,12584,33363,33364,12585,12586,33365,33366,33367,33368, +33369,33370,12587,12588,33377,33378,12589,33379,33380,33381,12590,33382,33383, +33384,33385,33386,33387,33388,12591,12592,33389,12593,33390,12594,33391,33392, +33393,33394,33395,33396,12595,33397,33398,33399,12596,33400,33401,33402,12597, +33409,33410,33411,33412,33413,33414,33415,33416,12598,33417,12599,33418,33419, +33420,33421,33422,33423,33424,33425,12600,12601,33426,33427,12602,33428,33429, +12603,12604,12605,12606,33430,33431,33432,33433,12607,12608,12609,33434,12610, +33435,12611,12612,33436,33437,33438,33439,33440,12613,12614,33441,33442,12615, +33443,33444,33445,12616,33446,33447,33448,33449,33450,33451,33452,33453,33454, +33455,33456,12617,12618,33457,33458,33459,33460,33461,33462,12619,33463,33464, +33465,33466,33467,33468,33469,33470,33471,33472,33473,33474,33475,33476,33477, +33478,33479,33480,12620,33481,33482,33483,33484,33485,33486,33487,33488,12621, +12622,33489,33490,12623,33491,33492,33493,12624,33494,33495,33496,33497,33498, +33499,33500,12625,12626,33501,12627,33502,33503,33504,33505,33506,33507,33508, +33509,12628,33510,33511,33512,12629,33513,33514,33515,12630,33516,33517,33518, +33519,33520,33521,33522,33523,33524,33525,33526,33527,33528,33529,33530,33531, +33532,33533,33534,12631,12632,33601,33602,12633,33603,33604,12634,12635,12636, +33605,33606,33607,33608,33609,33610,12637,12638,33611,12639,33612,12640,33613, +33614,33615,33616,33617,33618,12641,33619,33620,33621,33622,33623,33624,33625, +33626,33633,33634,33635,33636,33637,33638,33639,33640,33641,33642,33643,33644, +33645,33646,33647,33648,33649,33650,33651,12642,12643,33652,33653,12644,33654, +33655,12645,12646,33656,12647,33657,33658,33665,33666,33667,12648,12649,33668, +12650,33669,12651,12652,33670,33671,33672,12653,33673,12654,12655,12656,33674, +12657,33675,33676,33677,12658,33678,12659,33679,33680,33681,33682,33683,12660, +12661,33684,12662,12663,12664,33685,33686,33687,12665,33688,33689,12666,12667, +33690,33691,12668,33692,33693,33694,12669,33695,33696,33697,33698,33699,33700, +33701,12670,12833,33702,12834,12835,12836,33703,33704,33705,33706,33707,33708, +12837,12838,33709,33710,33711,33712,33713,33714,12839,33715,33716,33717,33718, +33719,33720,33721,33722,33723,33724,33725,33726,33727,33728,33729,33730,33731, +33732,33733,33734,33735,33736,33737,33738,33739,33740,33741,33742,33743,33744, +33745,33746,33747,33748,33749,33750,33751,33752,33753,33754,33755,33756,33757, +33758,33759,33760,33761,12840,12841,12842,33762,12843,33763,33764,33765,12844, +33766,33767,33768,33769,33770,33771,33772,12845,12846,33773,12847,12848,12849, +33774,33775,33776,33777,33778,33779,12850,12851,33780,33781,12852,33782,33783, +33784,33785,33786,33787,33788,33789,33790,33857,33858,12853,33859,33860,12854, +33861,12855,33862,33863,33864,33865,33866,33867,12856,33868,33869,33870,12857, +33871,33872,33873,12858,33874,33875,33876,33877,33878,33879,33880,33881,33882, +33889,12859,12860,33890,33891,33892,33893,12861,33894,33895,12862,33896,33897, +33898,33899,33900,33901,33902,33903,33904,33905,33906,33907,33908,33909,33910, +33911,33912,33913,33914,33921,33922,33923,33924,33925,33926,33927,33928,12863, +12864,33929,33930,12865,33931,12866,33932,12867,33933,33934,33935,33936,33937, +33938,33939,12868,12869,33940,12870,33941,12871,12872,12873,33942,33943,33944, +33945,12874,12875,33946,33947,33948,33949,33950,33951,12876,33952,33953,33954, +33955,33956,33957,33958,33959,33960,33961,33962,12877,12878,33963,33964,33965, +33966,33967,33968,12879,12880,33969,33970,33971,33972,33973,33974,33975,33976, +33977,33978,33979,33980,33981,33982,33983,33984,33985,33986,33987,12881,33988, +33989,33990,33991,33992,33993,12882,33994,33995,33996,12883,33997,33998,33999, +12884,34000,34001,34002,34003,34004,34005,34006,12885,12886,34007,34008,34009, +12887,34010,34011,34012,34013,34014,34015,12888,34016,34017,34018,34019,34020, +34021,34022,34023,34024,34025,34026,34027,34028,34029,34030,34031,34032,34033, +34034,34035,34036,34037,34038,34039,34040,34041,34042,12889,12890,34043,34044, +12891,34045,34046,34113,12892,34114,34115,34116,34117,34118,34119,12893,12894, +12895,34120,12896,34121,12897,12898,34122,34123,34124,34125,34126,12899,34127, +34128,34129,34130,34131,34132,34133,12900,34134,34135,34136,34137,34138,34145, +34146,34147,34148,34149,34150,12901,12902,34151,34152,34153,34154,34155,34156, +12903,12904,34157,34158,12905,34159,34160,34161,12906,34162,34163,34164,34165, +34166,34167,34168,12907,12908,34169,34170,12909,34177,34178,34179,34180,34181, +34182,34183,12910,34184,34185,34186,12911,34187,34188,34189,12912,34190,34191, +34192,34193,34194,34195,34196,12913,12914,34197,34198,34199,34200,34201,34202, +34203,34204,34205,34206,12915,34207,34208,34209,34210,34211,34212,34213,34214, +34215,34216,34217,34218,34219,34220,34221,34222,34223,34224,34225,34226,34227, +34228,34229,34230,34231,34232,34233,12916,12917,34234,34235,12918,34236,12919, +34237,12920,34238,12921,34239,34240,34241,34242,12922,12923,12924,34243,12925, +34244,12926,34245,34246,34247,13089,34248,34249,34250,34251,34252,34253,34254, +34255,34256,34257,34258,34259,34260,34261,34262,34263,34264,34265,34266,34267, +34268,34269,34270,34271,34272,34273,34274,34275,34276,34277,13090,13091,34278, +34279,13092,34280,34281,34282,13093,34283,34284,34285,34286,34287,34288,34289, +13094,13095,34290,13096,34291,13097,34292,34293,34294,34295,34296,34297,13098, +13099,13100,34298,13101,34299,34300,13102,13103,13104,13105,34301,34302,34369, +34370,34371,13106,13107,34372,13108,13109,13110,13111,13112,34373,13113,34374, +13114,13115,13116,34375,34376,13117,34377,34378,34379,13118,34380,34381,34382, +34383,34384,34385,34386,13119,13120,34387,13121,13122,13123,34388,34389,34390, +34391,34392,34393,13124,13125,34394,34401,13126,34402,34403,34404,13127,34405, +34406,34407,34408,34409,34410,34411,13128,34412,34413,34414,34415,13129,34416, +34417,34418,34419,34420,34421,34422,34423,34424,34425,34426,34433,34434,34435, +34436,34437,34438,34439,34440,34441,34442,34443,34444,34445,34446,34447,34448, +34449,34450,34451,34452,34453,34454,34455,13130,13131,34456,13132,13133,34457, +34458,34459,13134,34460,13135,13136,34461,34462,34463,34464,13137,13138,34465, +13139,13140,13141,34466,34467,34468,34469,34470,13142,13143,13144,34471,34472, +13145,34473,34474,34475,13146,34476,34477,34478,34479,34480,34481,34482,13147, +13148,34483,13149,13150,13151,34484,34485,34486,34487,34488,34489,13152,13153, +34490,34491,13154,34492,34493,34494,13155,34495,34496,34497,34498,34499,34500, +34501,13156,13157,34502,34503,13158,13159,34504,34505,13160,34506,34507,34508, +13161,34509,34510,34511,13162,34512,34513,34514,34515,34516,34517,34518,34519, +34520,34521,34522,34523,34524,34525,34526,34527,34528,34529,34530,34531,34532, +34533,34534,13163,13164,34535,34536,13165,34537,34538,34539,13166,34540,13167, +34541,34542,34543,34544,34545,13168,13169,34546,13170,34547,13171,34548,34549, +34550,34551,13172,13173,13174,34552,34553,34554,13175,34555,34556,34557,13176, +34558,34625,34626,34627,34628,34629,34630,34631,34632,34633,34634,13177,34635, +34636,34637,34638,34639,34640,34641,34642,34643,34644,34645,34646,34647,34648, +34649,34650,34657,34658,34659,34660,34661,34662,34663,34664,34665,34666,34667, +34668,34669,34670,34671,34672,34673,34674,34675,13178,34676,34677,34678,13179, +34679,34680,34681,13180,34682,34689,34690,34691,34692,34693,34694,13181,13182, +34695,13345,34696,34697,34698,34699,34700,34701,34702,34703,13346,13347,34704, +34705,13348,34706,34707,34708,13349,34709,34710,34711,34712,34713,34714,34715, +34716,13350,34717,13351,34718,13352,34719,34720,34721,34722,34723,34724,13353, +13354,34725,34726,13355,34727,34728,13356,13357,34729,34730,34731,34732,34733, +34734,34735,13358,13359,34736,13360,34737,13361,34738,34739,34740,34741,34742, +34743,13362,34744,34745,34746,34747,34748,34749,34750,34751,34752,34753,34754, +34755,34756,34757,34758,34759,34760,34761,34762,13363,34763,34764,34765,34766, +34767,34768,34769,13364,34770,34771,34772,34773,34774,34775,34776,34777,34778, +34779,34780,34781,34782,34783,34784,34785,34786,34787,34788,34789,34790,34791, +34792,34793,34794,34795,34796,13365,34797,34798,34799,13366,34800,34801,34802, +13367,34803,34804,34805,34806,34807,34808,34809,13368,13369,34810,34811,34812, +34813,34814,34881,34882,34883,34884,34885,13370,13371,34886,34887,34888,34889, +34890,34891,13372,34892,34893,34894,34895,34896,34897,34898,13373,13374,34899, +34900,34901,13375,34902,34903,34904,34905,34906,34913,13376,13377,34914,34915, +13378,34916,34917,34918,13379,13380,13381,34919,34920,34921,34922,34923,13382, +13383,34924,13384,34925,13385,13386,34926,34927,34928,13387,34929,13388,34930, +34931,34932,13389,34933,34934,34935,13390,34936,34937,34938,34945,34946,34947, +34948,34949,34950,34951,34952,34953,34954,34955,34956,34957,34958,34959,34960, +13391,13392,34961,34962,13393,34963,34964,34965,13394,34966,13395,34967,34968, +34969,34970,34971,13396,13397,34972,13398,34973,13399,34974,34975,34976,34977, +13400,34978,13401,13402,13403,34979,13404,34980,34981,13405,13406,13407,13408, +13409,34982,34983,34984,13410,13411,13412,34985,13413,13414,13415,13416,13417, +34986,34987,34988,13418,13419,13420,34989,34990,13421,34991,34992,34993,13422, +34994,34995,34996,34997,34998,34999,35000,13423,13424,35001,13425,13426,13427, +35002,35003,35004,35005,35006,35007,13428,35008,35009,35010,35011,35012,35013, +35014,35015,35016,35017,35018,35019,35020,35021,35022,35023,35024,35025,35026, +35027,35028,35029,35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, +35040,35041,35042,35043,35044,35045,35046,35047,35048,35049,35050,35051,35052, +35053,35054,35055,35056,35057,35058,35059,35060,35061,35062,13429,13430,13431, +35063,13432,35064,35065,13433,13434,35066,13435,13436,35067,35068,35069,35070, +13437,13438,35137,13601,35138,13602,35139,13603,35140,35141,13604,35142,13605, +13606,35143,35144,13607,35145,35146,35147,13608,35148,35149,35150,35151,35152, +35153,35154,13609,13610,35155,13611,13612,13613,35156,35157,35158,35159,35160, +35161,13614,35162,35169,35170,13615,35171,35172,35173,13616,35174,35175,35176, +35177,35178,35179,35180,35181,35182,35183,35184,13617,13618,35185,35186,35187, +35188,35189,35190,13619,35191,35192,35193,13620,35194,35201,35202,35203,35204, +35205,35206,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217, +35218,35219,35220,35221,35222,13621,13622,35223,35224,13623,35225,35226,13624, +13625,35227,13626,35228,13627,35229,35230,35231,13628,13629,35232,13630,35233, +13631,35234,13632,35235,13633,35236,35237,13634,35238,35239,35240,13635,35241, +35242,35243,13636,35244,35245,35246,35247,35248,35249,35250,35251,35252,35253, +35254,35255,35256,35257,35258,35259,35260,35261,35262,13637,35263,35264,35265, +35266,35267,35268,35269,35270,35271,35272,35273,35274,35275,35276,35277,35278, +35279,35280,35281,13638,35282,35283,35284,35285,35286,35287,35288,13639,35289, +35290,35291,13640,35292,35293,35294,13641,35295,35296,35297,35298,35299,35300, +35301,13642,13643,35302,13644,35303,35304,35305,35306,35307,35308,35309,35310, +13645,35311,35312,35313,35314,35315,35316,35317,35318,35319,35320,35321,35322, +35323,35324,35325,35326,35393,35394,35395,35396,35397,35398,35399,35400,35401, +35402,35403,13646,13647,35404,35405,13648,35406,35407,35408,13649,35409,35410, +35411,35412,35413,35414,35415,13650,13651,35416,13652,35417,13653,35418,35425, +35426,35427,35428,35429,13654,35430,35431,35432,35433,35434,35435,35436,35437, +35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,13655,35449, +35450,35457,35458,35459,35460,35461,13656,35462,35463,35464,35465,35466,35467, +35468,35469,35470,35471,35472,35473,35474,35475,35476,35477,35478,35479,35480, +35481,13657,35482,35483,35484,35485,35486,35487,13658,35488,35489,35490,13659, +35491,35492,35493,13660,35494,35495,35496,35497,35498,35499,35500,35501,13661, +35502,13662,35503,13663,35504,35505,35506,35507,35508,35509,13664,35510,35511, +35512,13665,35513,35514,35515,13666,35516,35517,35518,35519,35520,35521,35522, +13667,35523,35524,35525,35526,13668,35527,35528,35529,35530,35531,35532,13669, +13670,35533,35534,13671,35535,35536,13672,13673,35537,13674,35538,35539,35540, +35541,35542,13675,13676,35543,13677,35544,13678,35545,35546,35547,35548,35549, +35550,13679,35551,35552,35553,35554,35555,35556,35557,35558,35559,35560,35561, +35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573,35574, +35575,35576,35577,13680,13681,35578,35579,13682,35580,35581,13683,13684,35582, +35649,35650,35651,35652,35653,35654,13685,13686,35655,13687,13688,13689,13690, +35656,35657,35658,35659,35660,13691,13692,35661,35662,13693,35663,35664,35665, +13694,35666,35667,35668,35669,35670,35671,35672,13857,13858,35673,13859,13860, +13861,35674,35681,35682,35683,35684,13862,13863,13864,35685,35686,13865,35687, +35688,35689,13866,35690,35691,35692,35693,35694,35695,35696,13867,13868,35697, +13869,13870,13871,35698,35699,35700,35701,35702,35703,35704,35705,35706,35713, +35714,35715,35716,35717,35718,35719,35720,35721,35722,35723,35724,35725,35726, +35727,35728,35729,35730,35731,35732,35733,35734,35735,35736,35737,35738,35739, +35740,35741,35742,35743,35744,35745,35746,35747,35748,35749,35750,35751,35752, +35753,35754,35755,35756,35757,35758,35759,35760,35761,35762,35763,35764,35765, +13872,13873,35766,35767,13874,35768,35769,35770,13875,35771,13876,13877,35772, +35773,35774,35775,13878,13879,35776,13880,13881,13882,35777,35778,35779,35780, +35781,13883,13884,13885,35782,35783,13886,35784,35785,35786,13887,35787,35788, +35789,35790,35791,35792,35793,13888,13889,35794,13890,13891,13892,35795,35796, +35797,35798,35799,35800,13893,35801,35802,35803,35804,35805,35806,35807,35808, +35809,35810,35811,35812,35813,35814,35815,35816,35817,35818,35819,13894,35820, +35821,35822,35823,35824,35825,35826,35827,35828,35829,35830,35831,35832,35833, +35834,35835,35836,35837,35838,35905,35906,35907,35908,35909,35910,35911,35912, +35913,35914,35915,35916,35917,35918,35919,35920,13895,13896,35921,35922,13897, +35923,35924,35925,13898,35926,35927,35928,35929,35930,35937,35938,35939,35940, +35941,35942,35943,13899,35944,35945,35946,35947,35948,35949,13900,35950,35951, +35952,35953,35954,35955,35956,13901,35957,35958,35959,35960,35961,35962,35969, +35970,35971,35972,35973,35974,35975,35976,35977,35978,35979,35980,35981,13902, +35982,35983,35984,35985,35986,35987,35988,35989,35990,35991,35992,35993,35994, +35995,35996,35997,35998,35999,36000,36001,36002,36003,36004,36005,36006,36007, +36008,13903,36009,36010,36011,13904,36012,36013,36014,36015,36016,36017,36018, +36019,36020,36021,36022,36023,36024,36025,36026,36027,36028,36029,36030,36031, +36032,36033,36034,36035,36036,36037,36038,36039,36040,36041,36042,36043,36044, +36045,36046,36047,36048,36049,36050,36051,36052,36053,36054,36055,36056,36057, +36058,36059,36060,36061,36062,13905,13906,36063,36064,13907,36065,36066,36067, +13908,36068,36069,36070,36071,36072,36073,13909,13910,36074,36075,36076,36077, +13911,36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089, +36090,36091,36092,36093,36094,36161,36162,36163,36164,36165,36166,36167,36168, +36169,36170,36171,36172,36173,36174,36175,36176,36177,13912,36178,36179,36180, +36181,36182,36183,36184,36185,36186,36193,36194,36195,36196,36197,36198,36199, +36200,36201,36202,36203,36204,36205,36206,36207,36208,36209,36210,13913,36211, +36212,36213,13914,36214,36215,36216,13915,36217,36218,36225,36226,36227,36228, +36229,13916,13917,36230,36231,36232,13918,36233,36234,36235,36236,36237,36238, +36239,36240,36241,36242,36243,36244,36245,36246,36247,36248,36249,36250,36251, +36252,36253,36254,36255,36256,36257,36258,36259,36260,36261,36262,36263,36264, +36265,36266,13919,13920,36267,36268,13921,36269,36270,13922,13923,36271,36272, +36273,36274,36275,36276,36277,13924,13925,36278,13926,36279,36280,36281,36282, +36283,36284,36285,36286,13927,36287,36288,36289,13928,36290,36291,36292,13929, +36293,36294,36295,36296,36297,36298,36299,13930,13931,36300,36301,36302,36303, +36304,36305,36306,36307,36308,36309,13932,36310,36311,36312,13933,36313,36314, +36315,13934,36316,36317,36318,36319,36320,36321,36322,13935,13936,36323,13937, +36324,13938,36325,36326,36327,36328,36329,36330,13939,13940,36331,36332,13941, +36333,36334,36335,13942,36336,36337,36338,36339,36340,36341,36342,13943,13944, +36343,13945,13946,13947,13948,36344,36345,36346,13949,13950,14113,14114,36347, +36348,14115,36349,36350,36417,14116,36418,36419,36420,36421,36422,36423,36424, +14117,14118,36425,14119,14120,14121,36426,36427,36428,36429,36430,36431,14122, +14123,36432,36433,14124,36434,36435,36436,36437,36438,36439,36440,36441,36442, +36449,36450,36451,36452,36453,14125,36454,14126,36455,36456,36457,36458,36459, +36460,36461,36462,36463,36464,36465,36466,36467,36468,36469,36470,36471,36472, +36473,36474,36481,36482,36483,36484,36485,36486,36487,36488,36489,36490,36491, +36492,36493,36494,14127,14128,36495,36496,14129,36497,36498,36499,14130,36500, +36501,36502,36503,36504,36505,36506,14131,14132,36507,14133,14134,14135,36508, +36509,36510,36511,36512,14136,14137,14138,36513,36514,14139,36515,36516,36517, +14140,36518,36519,36520,36521,36522,36523,36524,14141,14142,36525,14143,36526, +14144,36527,36528,36529,36530,36531,36532,14145,14146,36533,36534,14147,36535, +36536,36537,14148,36538,36539,36540,36541,36542,36543,36544,14149,14150,36545, +14151,14152,14153,36546,36547,36548,36549,36550,36551,14154,36552,36553,36554, +14155,36555,36556,36557,36558,36559,36560,36561,36562,36563,36564,36565,36566, +14156,36567,14157,36568,36569,36570,36571,36572,36573,36574,36575,14158,14159, +36576,36577,14160,36578,36579,36580,14161,36581,36582,36583,36584,36585,36586, +36587,14162,14163,36588,14164,36589,14165,36590,36591,36592,36593,36594,36595, +14166,36596,36597,36598,14167,36599,36600,36601,36602,36603,36604,36605,36606, +36673,36674,36675,36676,36677,36678,36679,36680,14168,36681,36682,36683,36684, +36685,36686,36687,36688,36689,36690,36691,36692,36693,36694,36695,36696,36697, +36698,36705,36706,36707,36708,36709,36710,36711,36712,14169,36713,36714,36715, +36716,36717,36718,36719,14170,36720,36721,36722,14171,36723,36724,36725,14172, +36726,36727,36728,36729,36730,36737,36738,14173,14174,36739,14175,36740,14176, +36741,36742,36743,36744,36745,36746,14177,36747,36748,36749,14178,36750,36751, +36752,14179,36753,36754,36755,36756,36757,36758,36759,36760,14180,36761,14181, +36762,14182,36763,36764,36765,36766,36767,36768,14183,14184,36769,36770,14185, +36771,36772,36773,14186,36774,36775,36776,36777,36778,36779,36780,14187,14188, +36781,14189,36782,14190,36783,36784,36785,36786,36787,36788,14191,36789,36790, +36791,36792,36793,36794,36795,36796,36797,36798,36799,36800,36801,36802,36803, +36804,36805,36806,36807,14192,36808,36809,36810,36811,36812,36813,36814,14193, +36815,36816,36817,36818,36819,36820,36821,36822,36823,36824,36825,36826,36827, +36828,36829,36830,36831,36832,36833,36834,36835,36836,36837,36838,36839,36840, +36841,14194,14195,36842,36843,14196,36844,36845,36846,14197,36847,36848,36849, +36850,36851,36852,36853,14198,36854,36855,14199,36856,14200,36857,36858,36859, +36860,36861,36862,14201,14202,36929,36930,14203,36931,36932,36933,14204,36934, +36935,36936,36937,36938,36939,36940,14205,14206,36941,14369,36942,14370,36943, +36944,36945,36946,36947,36948,14371,14372,36949,36950,14373,36951,36952,36953, +14374,36954,36961,36962,36963,36964,36965,36966,14375,14376,36967,14377,36968, +14378,14379,36969,36970,14380,14381,36971,36972,36973,36974,36975,36976,36977, +36978,36979,36980,36981,36982,36983,36984,36985,36986,36993,36994,36995,36996, +36997,36998,36999,37000,37001,37002,37003,37004,37005,14382,14383,37006,37007, +14384,37008,37009,37010,14385,37011,37012,37013,37014,37015,37016,37017,14386, +14387,37018,14388,37019,14389,37020,37021,37022,37023,37024,37025,14390,14391, +37026,37027,14392,37028,14393,14394,14395,14396,14397,37029,37030,37031,37032, +37033,14398,14399,37034,14400,37035,14401,14402,37036,37037,14403,37038,14404, +14405,14406,37039,37040,14407,37041,37042,37043,14408,37044,37045,37046,37047, +37048,37049,37050,14409,14410,37051,14411,14412,14413,14414,37052,37053,37054, +37055,37056,14415,14416,37057,37058,37059,37060,37061,37062,14417,37063,37064, +37065,37066,37067,37068,37069,37070,37071,37072,37073,37074,14418,37075,37076, +37077,37078,37079,37080,37081,37082,37083,37084,37085,37086,37087,37088,37089, +37090,37091,37092,37093,37094,37095,37096,37097,37098,37099,37100,37101,37102, +37103,37104,37105,37106,37107,37108,14419,14420,37109,37110,14421,37111,37112, +37113,14422,37114,14423,37115,37116,37117,37118,37185,14424,14425,37186,14426, +37187,14427,14428,37188,37189,37190,37191,14429,14430,14431,37192,37193,14432, +37194,37195,37196,14433,37197,37198,37199,37200,37201,37202,37203,14434,14435, +37204,14436,14437,14438,37205,37206,37207,37208,37209,37210,14439,14440,37217, +37218,14441,37219,37220,37221,14442,37222,37223,37224,37225,37226,37227,37228, +37229,37230,37231,14443,14444,14445,37232,14446,37233,37234,37235,37236,14447, +37237,37238,37239,37240,37241,37242,37249,37250,37251,37252,37253,37254,37255, +37256,37257,37258,37259,37260,37261,37262,37263,37264,37265,37266,37267,37268, +37269,14448,14449,37270,14450,14451,37271,37272,37273,14452,37274,14453,37275, +37276,37277,37278,37279,14454,14455,37280,14456,37281,14457,37282,37283,37284, +37285,37286,37287,14458,37288,37289,37290,14459,37291,37292,37293,37294,37295, +37296,37297,37298,37299,37300,37301,37302,37303,37304,37305,14460,14461,37306, +37307,37308,37309,37310,37311,37312,37313,37314,37315,37316,37317,37318,37319, +37320,37321,37322,37323,37324,37325,37326,37327,37328,37329,37330,37331,37332, +37333,37334,37335,37336,37337,37338,37339,14462,37340,37341,37342,14625,37343, +37344,37345,14626,37346,37347,37348,37349,37350,37351,37352,37353,14627,37354, +14628,37355,14629,37356,37357,37358,37359,37360,37361,14630,37362,37363,37364, +14631,37365,37366,37367,14632,37368,37369,37370,37371,37372,37373,37374,37441, +14633,37442,14634,37443,37444,37445,37446,37447,37448,37449,37450,14635,14636, +14637,37451,14638,37452,37453,14639,14640,14641,14642,37454,37455,37456,37457, +37458,14643,14644,37459,14645,37460,14646,37461,37462,37463,14647,37464,14648, +14649,37465,37466,37473,14650,37474,37475,37476,14651,37477,37478,37479,37480, +37481,37482,37483,37484,14652,37485,14653,37486,37487,37488,37489,37490,37491, +37492,37493,14654,37494,37495,37496,37497,37498,37505,37506,37507,37508,37509, +37510,37511,37512,37513,37514,37515,37516,37517,37518,37519,37520,37521,37522, +37523,37524,37525,37526,14655,37527,37528,37529,14656,37530,37531,37532,14657, +37533,37534,37535,37536,37537,37538,37539,37540,37541,37542,37543,37544,37545, +37546,37547,37548,37549,37550,37551,14658,37552,37553,37554,14659,37555,37556, +37557,14660,37558,37559,37560,37561,37562,37563,37564,14661,37565,37566,14662, +37567,37568,37569,37570,37571,37572,37573,37574,14663,37575,37576,37577,14664, +37578,37579,37580,14665,37581,37582,37583,37584,37585,37586,37587,14666,37588, +37589,14667,37590,37591,37592,37593,37594,37595,37596,37597,37598,37599,37600, +37601,37602,37603,37604,37605,37606,37607,37608,37609,37610,37611,37612,37613, +37614,37615,37616,37617,37618,37619,37620,37621,37622,37623,37624,37625,14668, +14669,37626,37627,14670,37628,37629,14671,14672,37630,14673,37697,37698,37699, +37700,37701,14674,14675,37702,14676,14677,14678,37703,14679,37704,14680,37705, +37706,14681,14682,14683,14684,14685,37707,37708,14686,14687,14688,14689,14690, +37709,37710,37711,37712,14691,14692,37713,14693,37714,14694,37715,37716,37717, +14695,37718,37719,14696,14697,37720,37721,14698,37722,37729,37730,14699,37731, +37732,37733,37734,37735,37736,37737,14700,14701,37738,14702,14703,14704,37739, +37740,37741,14705,37742,37743,14706,14707,37744,37745,14708,37746,37747,37748, +37749,37750,37751,37752,37753,37754,37761,37762,37763,14709,37764,37765,37766, +37767,37768,37769,37770,37771,37772,37773,37774,37775,37776,37777,37778,37779, +37780,37781,37782,37783,37784,37785,37786,37787,37788,37789,37790,37791,37792, +37793,37794,37795,37796,37797,37798,37799,37800,37801,14710,14711,37802,37803, +14712,37804,37805,14713,14714,37806,14715,37807,37808,37809,37810,37811,14716, +14717,37812,14718,37813,14881,14882,37814,37815,37816,37817,37818,14883,14884, +37819,37820,14885,37821,37822,14886,14887,37823,37824,37825,37826,37827,37828, +37829,14888,14889,37830,14890,14891,14892,37831,37832,37833,37834,37835,37836, +14893,14894,37837,37838,14895,37839,37840,37841,14896,37842,37843,37844,37845, +37846,37847,37848,37849,14897,37850,14898,14899,14900,37851,37852,37853,14901, +37854,37855,14902,37856,37857,37858,14903,37859,37860,37861,37862,37863,37864, +37865,37866,37867,37868,37869,37870,37871,37872,37873,37874,37875,37876,37877, +37878,37879,37880,37881,14904,14905,14906,37882,14907,37883,37884,37885,14908, +37886,37953,37954,37955,37956,37957,37958,14909,14910,37959,14911,37960,14912, +37961,37962,37963,37964,37965,37966,14913,37967,37968,37969,14914,37970,37971, +37972,37973,37974,37975,37976,37977,37978,37985,37986,37987,37988,37989,37990, +14915,37991,37992,37993,37994,37995,37996,37997,14916,37998,37999,38000,38001, +38002,38003,38004,38005,38006,38007,38008,38009,38010,38017,38018,38019,38020, +38021,38022,14917,38023,38024,38025,38026,38027,38028,38029,14918,14919,38030, +38031,14920,38032,38033,38034,14921,38035,38036,38037,38038,38039,38040,38041, +14922,14923,38042,38043,38044,38045,38046,38047,38048,38049,38050,38051,14924, +38052,38053,38054,14925,38055,38056,38057,38058,38059,38060,38061,38062,38063, +38064,38065,38066,38067,38068,38069,38070,38071,38072,38073,38074,38075,38076, +38077,14926,14927,38078,38079,14928,38080,38081,14929,14930,14931,14932,38082, +38083,38084,38085,38086,14933,14934,38087,14935,38088,14936,38089,38090,38091, +14937,14938,38092,14939,38093,38094,38095,38096,38097,38098,38099,14940,38100, +38101,38102,38103,38104,38105,38106,38107,38108,38109,38110,14941,38111,38112, +38113,38114,38115,38116,38117,14942,38118,38119,38120,38121,38122,38123,38124, +38125,38126,38127,38128,38129,38130,38131,38132,38133,38134,38135,38136,38137, +38138,38139,38140,38141,38142,38209,38210,14943,14944,38211,38212,14945,38213, +38214,38215,14946,38216,38217,38218,38219,38220,38221,38222,38223,38224,38225, +38226,38227,14947,38228,38229,38230,38231,38232,38233,14948,38234,38241,38242, +14949,38243,38244,38245,14950,38246,38247,38248,38249,38250,38251,38252,14951, +38253,38254,14952,38255,14953,38256,38257,38258,38259,38260,38261,14954,14955, +38262,38263,14956,38264,38265,38266,14957,38273,38274,38275,38276,38277,38278, +38279,14958,14959,38280,14960,38281,38282,38283,38284,38285,38286,38287,38288, +38289,38290,38291,38292,38293,38294,38295,38296,38297,38298,38299,38300,38301, +38302,38303,38304,38305,38306,38307,38308,38309,38310,38311,38312,38313,38314, +38315,38316,14961,14962,38317,38318,14963,38319,38320,38321,14964,38322,14965, +38323,38324,38325,38326,38327,14966,14967,38328,14968,38329,14969,14970,14971, +38330,38331,38332,38333,14972,14973,38334,38335,14974,38336,38337,38338,15137, +38339,15138,38340,38341,38342,38343,38344,15139,15140,38345,15141,15142,15143, +38346,38347,38348,38349,38350,15144,15145,15146,38351,38352,15147,38353,38354, +38355,15148,38356,38357,38358,38359,38360,38361,38362,15149,15150,38363,15151, +15152,15153,38364,38365,38366,38367,38368,38369,15154,15155,38370,38371,38372, +38373,38374,38375,38376,38377,38378,38379,38380,38381,38382,38383,15156,38384, +38385,38386,38387,38388,38389,38390,38391,38392,38393,38394,38395,38396,38397, +38398,38465,38466,38467,38468,38469,38470,38471,38472,38473,38474,38475,38476, +38477,38478,38479,38480,38481,38482,38483,38484,38485,38486,38487,38488,15157, +15158,38489,38490,15159,38497,38498,15160,15161,38499,38500,38501,38502,38503, +38504,38505,15162,38506,38507,15163,15164,15165,38508,38509,38510,38511,38512, +38513,15166,38514,38515,38516,38517,38518,38519,38520,38521,38522,38529,38530, +38531,38532,38533,38534,38535,38536,38537,38538,38539,15167,38540,38541,38542, +38543,38544,38545,15168,15169,38546,38547,38548,38549,38550,38551,38552,38553, +38554,38555,38556,38557,38558,38559,15170,15171,38560,15172,15173,15174,38561, +38562,38563,38564,38565,38566,38567,38568,38569,38570,38571,38572,38573,38574, +38575,38576,38577,38578,38579,38580,38581,38582,38583,38584,38585,38586,38587, +38588,38589,38590,38591,38592,38593,38594,15175,15176,38595,38596,15177,38597, +38598,38599,15178,38600,38601,38602,38603,38604,38605,38606,15179,15180,38607, +38608,38609,15181,38610,38611,38612,38613,38614,38615,38616,38617,38618,38619, +38620,38621,38622,38623,38624,38625,38626,38627,38628,38629,38630,38631,38632, +38633,38634,38635,38636,38637,38638,38639,38640,38641,38642,38643,38644,38645, +38646,38647,38648,38649,38650,38651,38652,38653,38654,38721,38722,38723,38724, +38725,38726,38727,38728,38729,38730,38731,38732,38733,38734,38735,38736,38737, +15182,38738,38739,38740,38741,38742,38743,38744,38745,38746,38753,38754,38755, +38756,38757,38758,38759,38760,38761,38762,38763,38764,38765,38766,38767,38768, +38769,38770,15183,38771,38772,38773,38774,38775,38776,38777,38778,38785,38786, +38787,38788,38789,38790,38791,38792,38793,38794,38795,38796,15184,38797,38798, +38799,38800,38801,38802,15185,15186,38803,38804,15187,38805,38806,38807,15188, +38808,38809,38810,38811,38812,38813,38814,15189,38815,38816,15190,38817,15191, +38818,38819,38820,38821,38822,38823,38824,38825,38826,38827,38828,38829,38830, +38831,38832,38833,38834,38835,38836,38837,38838,38839,38840,38841,38842,38843, +38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856, +38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869, +38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882, +38883,38884,38885,38886,38887,38888,38889,38890,38891,38892,38893,38894,38895, +38896,38897,38898,38899,38900,38901,38902,38903,38904,38905,38906,38907,15192, +38908,38909,38910,38977,38978,38979,38980,38981,38982,38983,38984,38985,38986, +38987,38988,38989,38990,38991,38992,38993,15193,38994,38995,38996,38997,38998, +38999,15194,39000,39001,39002,15195,39009,39010,39011,15196,39012,39013,39014, +39015,39016,39017,39018,15197,15198,39019,39020,39021,39022,39023,39024,39025, +39026,39027,39028,39029,39030,39031,39032,39033,39034,39041,39042,39043,39044, +39045,39046,39047,39048,39049,39050,39051,39052,39053,39054,39055,39056,39057, +39058,39059,39060,39061,39062,15199,15200,39063,39064,15201,39065,39066,39067, +15202,39068,39069,39070,39071,39072,39073,39074,15203,15204,39075,15205,39076, +15206,39077,39078,39079,39080,39081,39082,15207,15208,39083,15209,15210,39084, +39085,15211,15212,15213,15214,39086,39087,39088,39089,39090,15215,15216,39091, +15217,15218,15219,39092,39093,39094,15220,39095,39096,15221,15222,39097,39098, +15223,39099,39100,39101,15224,39102,39103,39104,39105,39106,39107,39108,15225, +15226,39109,15227,15228,15229,39110,39111,39112,39113,39114,39115,15230,15393, +39116,39117,15394,39118,39119,39120,15395,39121,39122,39123,39124,39125,39126, +39127,15396,15397,39128,15398,39129,15399,39130,39131,39132,39133,39134,39135, +15400,39136,39137,39138,15401,39139,39140,39141,15402,39142,39143,39144,39145, +39146,39147,39148,15403,39149,39150,39151,39152,15404,39153,39154,39155,39156, +39157,39158,15405,15406,15407,15408,15409,39159,39160,15410,15411,39161,15412, +15413,39162,39163,39164,39165,15414,15415,39166,15416,15417,15418,39233,39234, +39235,39236,15419,39237,15420,15421,39238,39239,15422,39240,39241,39242,15423, +39243,39244,39245,39246,39247,39248,39249,15424,15425,39250,15426,15427,15428, +39251,39252,39253,39254,39255,39256,15429,15430,39257,39258,15431,39265,39266, +39267,15432,39268,39269,39270,39271,39272,39273,39274,15433,15434,39275,15435, +15436,15437,39276,39277,39278,39279,39280,39281,15438,39282,39283,39284,15439, +39285,39286,39287,15440,39288,39289,39290,39297,39298,39299,39300,39301,39302, +39303,39304,39305,15441,39306,39307,39308,39309,39310,39311,15442,15443,15444, +39312,15445,39313,39314,39315,15446,39316,15447,39317,39318,39319,39320,39321, +15448,15449,39322,15450,39323,15451,39324,39325,39326,15452,39327,39328,15453, +15454,39329,39330,15455,39331,39332,39333,15456,39334,39335,39336,39337,39338, +39339,39340,39341,39342,39343,39344,39345,15457,39346,39347,39348,39349,39350, +39351,15458,39352,39353,39354,15459,39355,39356,39357,15460,39358,39359,39360, +39361,39362,39363,39364,15461,39365,39366,15462,15463,39367,39368,39369,39370, +39371,39372,39373,15464,39374,39375,39376,15465,39377,39378,39379,15466,39380, +39381,39382,39383,39384,39385,39386,15467,15468,39387,15469,39388,39389,39390, +39391,39392,39393,39394,39395,15470,15471,39396,39397,15472,39398,39399,39400, +15473,39401,39402,39403,39404,39405,39406,39407,15474,15475,39408,15476,39409, +15477,39410,39411,39412,39413,39414,39415,15478,15479,39416,39417,15480,39418, +39419,15481,15482,39420,39421,39422,39489,39490,39491,39492,15483,15484,39493, +15485,39494,15486,39495,15649,39496,15650,15651,39497,15652,39498,39499,39500, +39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39511,39512,39513, +39514,39521,39522,15653,39523,39524,39525,39526,39527,39528,39529,15654,15655, +39530,39531,15656,39532,39533,39534,15657,39535,39536,39537,39538,39539,39540, +39541,15658,39542,39543,39544,39545,15659,39546,39553,39554,39555,39556,39557, +15660,15661,39558,39559,15662,39560,39561,39562,15663,39563,39564,39565,39566, +39567,39568,39569,15664,15665,39570,15666,39571,15667,39572,39573,39574,39575, +39576,39577,15668,15669,39578,39579,39580,39581,39582,39583,15670,39584,39585, +39586,39587,39588,39589,39590,15671,39591,39592,15672,39593,15673,39594,39595, +39596,39597,39598,39599,15674,15675,39600,39601,15676,39602,39603,39604,15677, +15678,39605,39606,39607,39608,39609,39610,15679,15680,39611,15681,39612,15682, +39613,39614,39615,39616,39617,39618,39619,39620,39621,39622,39623,39624,39625, +39626,39627,39628,39629,39630,39631,39632,39633,39634,39635,39636,39637,39638, +39639,39640,39641,39642,39643,39644,39645,39646,15683,15684,39647,39648,15685, +39649,39650,15686,15687,39651,39652,39653,39654,39655,39656,15688,15689,15690, +39657,15691,39658,15692,39659,39660,39661,39662,15693,39663,15694,15695,39664, +15696,15697,39665,39666,39667,15698,39668,39669,39670,39671,39672,39673,39674, +15699,15700,39675,39676,15701,15702,39677,39678,39745,39746,39747,15703,15704, +15705,39748,39749,15706,39750,39751,39752,15707,39753,39754,39755,39756,39757, +39758,39759,15708,15709,39760,39761,15710,15711,39762,39763,39764,39765,39766, +39767,39768,39769,39770,39777,39778,39779,39780,39781,39782,39783,39784,39785, +39786,39787,39788,39789,39790,39791,39792,39793,39794,15712,39795,39796,39797, +39798,39799,39800,39801,39802,39809,39810,39811,39812,39813,39814,39815,39816, +39817,39818,39819,39820,39821,39822,39823,39824,39825,39826,39827,39828,39829, +39830,39831,39832,39833,39834,15713,15714,39835,39836,15715,39837,39838,39839, +15716,39840,15717,39841,39842,39843,39844,39845,15718,15719,39846,39847,15720, +15721,39848,39849,39850,39851,39852,39853,15722,39854,39855,39856,15723,39857, +39858,39859,15724,39860,39861,39862,39863,39864,39865,39866,39867,39868,39869, +39870,39871,39872,39873,39874,39875,39876,39877,39878,39879,39880,39881,39882, +39883,39884,39885,39886,39887,39888,39889,39890,39891,39892,39893,39894,39895, +39896,39897,39898,39899,39900,39901,39902,39903,39904,39905,39906,39907,39908, +39909,39910,15725,39911,39912,39913,39914,39915,39916,39917,39918,39919,39920, +39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933, +15726,15727,39934,40001,15728,40002,40003,15729,15730,40004,15731,40005,40006, +40007,40008,40009,15732,15733,40010,40011,40012,15734,40013,40014,40015,40016, +40017,40018,15735,15736,40019,40020,15737,40021,40022,40023,40024,40025,40026, +40033,40034,40035,40036,40037,40038,40039,40040,40041,15738,40042,40043,40044, +40045,40046,40047,40048,15739,40049,40050,40051,40052,40053,40054,40055,40056, +40057,40058,40065,40066,40067,40068,40069,40070,40071,40072,40073,15740,40074, +40075,40076,40077,40078,40079,40080,15741,40081,40082,40083,15742,40084,40085, +40086,15905,40087,40088,40089,40090,40091,40092,40093,15906,15907,40094,40095, +40096,40097,40098,40099,40100,40101,40102,40103,15908,40104,40105,40106,40107, +40108,40109,40110,40111,40112,40113,40114,40115,40116,40117,40118,40119,40120, +40121,40122,40123,40124,40125,40126,40127,40128,40129,40130,15909,15910,40131, +40132,15911,40133,40134,40135,15912,40136,40137,40138,40139,40140,40141,40142, +15913,15914,40143,40144,40145,15915,40146,40147,40148,40149,40150,40151,15916, +40152,40153,40154,40155,40156,40157,40158,40159,40160,40161,40162,40163,40164, +40165,40166,40167,40168,40169,40170,15917,40171,40172,40173,40174,40175,40176, +40177,15918,40178,40179,40180,40181,40182,40183,40184,40185,40186,40187,40188, +40189,40190,40257,40258,40259,40260,40261,40262,40263,40264,40265,40266,40267, +40268,40269,40270,15919,40271,40272,40273,15920,40274,40275,40276,40277,40278, +40279,40280,40281,40282,40289,40290,40291,40292,40293,40294,40295,40296,40297, +40298,40299,40300,40301,40302,40303,40304,40305,40306,40307,40308,40309,40310, +40311,40312,40313,40314,40321,40322,40323,40324,40325,40326,40327,40328,40329, +15921,40330,40331,40332,40333,40334,40335,15922,15923,40336,40337,15924,40338, +40339,40340,15925,40341,15926,40342,40343,40344,40345,15927,15928,15929,40346, +40347,40348,40349,40350,40351,40352,40353,40354,40355,15930,40356,40357,40358, +15931,40359,40360,40361,15932,40362,40363,40364,40365,40366,40367,40368,15933, +40369,40370,40371,40372,40373,40374,40375,40376,40377,40378,40379,15934,15935, +40380,40381,15936,40382,40383,40384,15937,40385,40386,40387,40388,40389,40390, +40391,15938,15939,40392,15940,40393,15941,40394,40395,40396,40397,40398,40399, +15942,15943,40400,40401,15944,15945,15946,40402,15947,15948,15949,40403,40404, +40405,40406,15950,15951,15952,40407,15953,15954,15955,40408,40409,40410,15956, +15957,40411,15958,15959,40412,40413,15960,40414,40415,40416,15961,40417,40418, +40419,40420,40421,40422,40423,15962,15963,40424,15964,15965,15966,40425,40426, +40427,40428,40429,40430,15967,15968,40431,40432,15969,40433,40434,40435,15970, +40436,40437,15971,40438,40439,40440,40441,15972,15973,40442,15974,40443,15975, +40444,40445,40446,15976,40513,15977,15978,40514,40515,40516,15979,40517,40518, +40519,15980,40520,40521,40522,40523,40524,40525,40526,40527,15981,40528,40529, +40530,40531,40532,40533,40534,40535,40536,40537,15982,15983,40538,40545,15984, +15985,40546,15986,15987,15988,15989,40547,40548,40549,40550,40551,15990,15991, +15992,15993,15994,15995,15996,40552,15997,40553,15998,40554,16161,16162,40555, +40556,16163,40557,40558,40559,16164,40560,40561,40562,40563,40564,40565,40566, +16165,16166,40567,16167,40568,16168,40569,40570,40577,40578,40579,40580,16169, +16170,16171,40581,16172,40582,40583,40584,16173,40585,16174,16175,40586,40587, +40588,40589,16176,16177,16178,16179,16180,16181,40590,40591,40592,16182,16183, +16184,16185,40593,40594,40595,16186,40596,40597,40598,16187,40599,40600,40601, +40602,40603,40604,40605,16188,16189,40606,16190,16191,40607,40608,40609,40610, +40611,40612,40613,16192,16193,40614,40615,16194,40616,40617,40618,16195,16196, +16197,40619,16198,40620,40621,16199,16200,16201,40622,16202,40623,16203,40624, +16204,40625,40626,40627,40628,16205,16206,40629,40630,16207,40631,40632,40633, +16208,40634,40635,40636,40637,40638,40639,40640,16209,16210,40641,16211,16212, +16213,40642,40643,40644,40645,40646,40647,16214,16215,40648,40649,16216,40650, +40651,40652,40653,40654,40655,40656,40657,40658,40659,40660,16217,40661,40662, +16218,40663,16219,40664,40665,40666,40667,40668,40669,16220,16221,40670,40671, +16222,40672,40673,40674,16223,40675,40676,40677,40678,40679,40680,40681,16224, +16225,40682,16226,40683,16227,40684,40685,40686,40687,40688,40689,16228,16229, +40690,40691,16230,40692,40693,40694,16231,40695,40696,40697,40698,40699,40700, +40701,16232,16233,40702,16234,40769,16235,40770,40771,40772,40773,40774,40775, +16236,16237,40776,40777,16238,40778,40779,40780,16239,16240,16241,40781,40782, +40783,40784,40785,16242,16243,40786,16244,40787,16245,40788,40789,40790,40791, +40792,40793,16246,16247,40794,40801,16248,40802,40803,40804,16249,40805,40806, +40807,40808,40809,40810,40811,16250,16251,40812,40813,16252,16253,40814,40815, +40816,40817,40818,40819,16254,16417,40820,40821,16418,40822,40823,40824,16419, +40825,40826,40833,40834,40835,40836,40837,16420,16421,40838,40839,40840,16422, +40841,40842,40843,40844,40845,40846,16423,16424,40847,40848,16425,40849,40850, +40851,16426,40852,40853,40854,40855,40856,40857,40858,16427,16428,40859,16429, +40860,16430,40861,40862,40863,40864,40865,40866,16431,16432,40867,40868,16433, +40869,40870,40871,16434,40872,40873,40874,40875,40876,40877,40878,16435,16436, +40879,16437,40880,16438,40881,16439,40882,40883,40884,40885,16440,16441,40886, +40887,16442,40888,40889,40890,16443,40891,40892,40893,40894,40895,16444,40896, +16445,16446,40897,16447,40898,16448,16449,16450,16451,16452,16453,16454,16455, +40899,40900,40901,16456,40902,40903,40904,16457,40905,40906,40907,40908,40909, +40910,40911,16458,40912,40913,16459,40914,40915,40916,40917,40918,40919,40920, +40921,16460,16461,40922,40923,16462,40924,40925,40926,16463,16464,16465,40927, +40928,40929,40930,16466,16467,16468,40931,16469,16470,16471,16472,40932,40933, +40934,16473,40935,16474,16475,40936,40937,16476,40938,16477,16478,16479,40939, +16480,40940,40941,40942,40943,40944,16481,16482,40945,16483,16484,16485,16486, +40946,40947,40948,40949,40950,16487,16488,40951,40952,16489,40953,40954,40955, +16490,40956,40957,40958,41025,41026,41027,41028,16491,16492,41029,16493,16494, +16495,41030,41031,41032,41033,41034,41035,16496,16497,41036,41037,16498,41038, +16499,41039,16500,41040,41041,41042,41043,41044,41045,41046,16501,41047,41048, +41049,41050,16502,41057,41058,41059,41060,41061,41062,16503,41063,41064,41065, +16504,41066,41067,41068,16505,41069,41070,41071,41072,41073,41074,41075,41076, +41077,41078,41079,41080,41081,41082,41089,41090,41091,41092,41093,16506,16507, +41094,41095,16508,41096,41097,41098,16509,41099,16510,41100,41101,41102,41103, +41104,16673,16674,41105,16675,41106,16676,16677,41107,41108,41109,41110,41111, +16678,16679,41112,41113,16680,41114,41115,41116,16681,41117,41118,41119,41120, +41121,41122,41123,16682,16683,41124,16684,41125,16685,41126,41127,41128,41129, +41130,41131,16686,41132,41133,41134,16687,41135,41136,41137,16688,41138,41139, +41140,41141,41142,41143,41144,16689,16690,41145,41146,16691,16692,41147,41148, +41149,41150,41151,41152,16693,41153,41154,41155,41156,41157,41158,41159,41160, +41161,41162,41163,41164,41165,41166,41167,41168,41169,41170,41171,41172,41173, +41174,41175,41176,41177,41178,41179,16694,16695,41180,41181,16696,41182,41183, +41184,16697,41185,16698,41186,41187,41188,41189,41190,16699,16700,41191,16701, +41192,16702,16703,16704,41193,41194,41195,16705,16706,16707,41196,41197,41198, +41199,41200,41201,16708,41202,41203,41204,41205,41206,41207,41208,41209,16709, +41210,16710,41211,16711,41212,41213,41214,41281,41282,41283,16712,41284,41285, +41286,41287,41288,41289,41290,41291,41292,41293,41294,41295,41296,41297,41298, +41299,41300,41301,41302,16713,16714,41303,41304,41305,41306,41313,41314,16715, +41315,41316,41317,16716,41318,41319,41320,16717,41321,41322,41323,41324,41325, +41326,41327,16718,16719,41328,16720,41329,16721,41330,41331,41332,41333,41334, +41335,16722,16723,41336,41337,16724,41338,41345,41346,41347,41348,41349,41350, +41351,41352,41353,41354,41355,41356,41357,41358,41359,16725,41360,41361,41362, +41363,41364,41365,16726,16727,41366,41367,16728,41368,41369,41370,16729,16730, +16731,41371,41372,41373,41374,41375,16732,16733,41376,16734,41537,16735,41538, +41539,41540,41541,41542,41543,16736,41544,41545,41546,41547,41548,41549,41550, +41551,41552,41553,41554,41555,41556,41557,41558,41559,41560,41561,41562,16737, +41569,41570,41571,41572,41573,41574,41575,16738,41576,41577,41578,41579,41580, +41581,41582,41583,41584,41585,41586,41587,41588,41589,41590,41591,41592,41593, +41594,41601,41602,41603,41604,41605,41606,41607,41608,16739,16740,41609,41610, +16741,41611,41612,41613,16742,41614,41615,41616,41617,41618,41619,41620,16743, +16744,41621,16745,41622,41623,41624,41625,41626,41627,41628,41629,16746,41630, +41631,41632,16747,41793,41794,41795,16748,41796,41797,41798,41799,41800,41801, +41802,16749,41803,41804,41805,41806,41807,41808,41809,41810,41811,41812,41813, +16750,16751,41814,41815,16752,41816,41817,41818,16753,41825,41826,41827,41828, +41829,41830,41831,16754,16755,41832,16756,41833,16757,41834,41835,41836,41837, +41838,41839,41840,41841,41842,41843,41844,41845,41846,41847,41848,41849,41850, +41857,41858,41859,41860,41861,41862,41863,41864,41865,41866,41867,41868,41869, +41870,41871,41872,41873,16758,16759,41874,41875,16760,41876,41877,16761,16762, +41878,16763,41879,41880,41881,41882,41883,16764,16765,41884,16766,41885,16929, +16930,41886,41887,16931,16932,41888,16933,16934,42049,42050,16935,42051,16936, +42052,16937,42053,42054,16938,42055,42056,42057,42058,16939,16940,42059,16941, +16942,16943,42060,42061,42062,42063,42064,42065,16944,16945,42066,42067,16946, +42068,42069,42070,16947,42071,42072,42073,42074,42081,42082,42083,16948,16949, +42084,16950,16951,16952,42085,42086,42087,42088,42089,42090,16953,42091,42092, +42093,16954,42094,42095,42096,42097,42098,42099,42100,42101,42102,42103,42104, +42105,42106,42113,42114,42115,16955,42116,42117,42118,42119,42120,42121,42122, +42123,42124,42125,42126,42127,42128,42129,42130,42131,42132,42133,42134,42135, +42136,42137,42138,42139,42140,42141,42142,42143,42144,42305,42306,42307,42308, +42309,16956,16957,42310,42311,16958,42312,42313,42314,16959,42315,42316,42317, +42318,42319,42320,42321,16960,16961,42322,16962,16963,16964,42323,42324,42325, +42326,42327,42328,16965,42329,42330,42337,42338,42339,42340,42341,42342,42343, +42344,42345,42346,42347,42348,42349,42350,42351,42352,42353,42354,16966,42355, +42356,42357,42358,42359,42360,16967,42361,42362,42369,42370,42371,42372,42373, +42374,42375,42376,42377,42378,42379,42380,42381,42382,42383,42384,42385,16968, +42386,42387,42388,42389,42390,42391,42392,42393,42394,42395,42396,42397,42398, +42399,42400,42561,42562,42563,42564,42565,42566,42567,42568,42569,42570,42571, +42572,42573,42574,42575,42576,42577,42578,42579,42580,16969,16970,42581,42582, +16971,42583,42584,42585,16972,42586,42593,42594,42595,42596,42597,42598,16973, +16974,42599,16975,42600,16976,42601,16977,42602,42603,42604,42605,16978,16979, +42606,42607,42608,42609,42610,42611,16980,42612,42613,42614,42615,42616,42617, +42618,42625,42626,42627,42628,16981,42629,42630,42631,42632,42633,42634,42635, +16982,42636,42637,42638,42639,42640,42641,42642,42643,42644,42645,42646,42647, +42648,42649,42650,42651,42652,42653,42654,16983,42655,42656,42817,42818,42819, +42820,42821,16984,42822,42823,42824,16985,42825,42826,42827,16986,42828,42829, +42830,42831,42832,42833,42834,16987,16988,42835,42836,42837,42838,42839,42840, +42841,42842,42849,42850,42851,42852,42853,42854,42855,42856,42857,42858,42859, +42860,42861,42862,42863,42864,42865,42866,42867,42868,42869,42870,42871,16989, +42872,42873,42874,42881,42882,42883,16990,16991,42884,42885,16992,42886,42887, +42888,16993,42889,42890,42891,42892,42893,42894,42895,16994,16995,42896,42897, +42898,16996,42899,42900,42901,42902,42903,42904,16997,42905,42906,42907,42908, +42909,42910,42911,42912,43073,43074,43075,43076,43077,43078,43079,43080,43081, +43082,43083,16998,16999,43084,43085,43086,43087,43088,43089,43090,43091,43092, +43093,43094,43095,43096,43097,43098,43105,43106,43107,43108,43109,43110,43111, +43112,43113,43114,43115,43116,43117,43118,43119,43120,43121,43122,43123,17000, +43124,43125,43126,43127,43128,43129,43130,43137,43138,43139,43140,43141,43142, +43143,43144,43145,43146,43147,43148,43149,43150,43151,43152,43153,43154,43155, +43156,17001,43157,43158,43159,43160,43161,43162,43163,43164,43165,43166,43167, +43168,43329,43330,43331,43332,43333,43334,43335,43336,43337,43338,43339,43340, +43341,43342,43343,17002,43344,43345,43346,43347,43348,43349,43350,43351,43352, +43353,43354,43361,43362,43363,43364,17003,43365,43366,17004,43367,17005,43368, +43369,43370,43371,43372,43373,43374,43375,43376,43377,43378,43379,43380,43381, +43382,43383,43384,43385,43386,43393,43394,43395,43396,43397,43398,43399,43400, +43401,43402,43403,43404,43405,43406,43407,17006,17007,43408,43409,17008,43410, +43411,43412,17009,43413,43414,43415,43416,43417,43418,43419,17010,17011,43420, +43421,43422,17012,17013,43423,43424,43585,43586,17014,17015,17016,43587,43588, +17017,43589,17018,43590,17019,43591,43592,43593,43594,43595,43596,43597,17020, +17021,43598,17022,17185,17186,17187,43599,43600,43601,43602,43603,17188,17189, +43604,43605,17190,43606,43607,43608,17191,43609,43610,43617,43618,43619,43620, +43621,17192,17193,43622,17194,17195,17196,43623,43624,43625,43626,43627,43628, +17197,43629,43630,43631,17198,43632,17199,43633,17200,43634,43635,43636,43637, +43638,43639,43640,17201,43641,43642,43649,43650,17202,43651,43652,43653,43654, +43655,43656,43657,43658,43659,43660,43661,43662,43663,43664,43665,43666,43667, +43668,43669,43670,43671,43672,43673,43674,43675,43676,43677,43678,43679,43680, +43841,43842,43843,43844,17203,17204,43845,43846,17205,43847,43848,43849,17206, +43850,43851,43852,43853,43854,43855,43856,17207,17208,43857,17209,17210,17211, +43858,43859,43860,43861,43862,43863,17212,17213,43864,43865,17214,43866,43873, +43874,17215,43875,43876,43877,43878,43879,43880,43881,17216,17217,43882,17218, +43883,17219,43884,43885,43886,43887,43888,43889,17220,43890,43891,43892,17221, +43893,43894,43895,43896,43897,43898,43905,43906,43907,43908,43909,43910,43911, +43912,43913,17222,43914,43915,43916,43917,43918,43919,43920,17223,43921,43922, +43923,17224,43924,43925,43926,43927,43928,43929,43930,43931,43932,43933,43934, +43935,43936,44097,44098,44099,17225,44100,44101,44102,44103,44104,44105,17226, +17227,44106,44107,17228,44108,44109,44110,17229,44111,44112,44113,44114,44115, +44116,44117,17230,17231,44118,17232,44119,17233,44120,44121,44122,44129,44130, +44131,17234,44132,44133,44134,17235,44135,44136,44137,17236,44138,44139,44140, +44141,44142,44143,44144,44145,44146,44147,44148,44149,17237,44150,44151,44152, +44153,44154,44161,44162,44163,44164,44165,44166,44167,44168,44169,44170,44171, +44172,44173,44174,44175,44176,44177,44178,44179,44180,44181,44182,44183,44184, +44185,44186,44187,44188,44189,17238,44190,44191,44192,17239,44353,44354,44355, +17240,44356,44357,44358,44359,44360,44361,44362,17241,17242,44363,17243,44364, +17244,44365,44366,44367,44368,44369,44370,17245,44371,44372,44373,44374,44375, +44376,44377,44378,44385,44386,44387,44388,44389,44390,44391,17246,44392,44393, +44394,44395,44396,44397,44398,44399,44400,44401,44402,17247,17248,44403,44404, +17249,44405,44406,44407,17250,44408,44409,44410,44417,44418,44419,44420,17251, +17252,44421,17253,44422,17254,44423,44424,44425,44426,44427,44428,17255,44429, +44430,44431,44432,44433,44434,44435,44436,44437,44438,44439,44440,44441,44442, +44443,44444,44445,44446,44447,17256,44448,44609,44610,44611,44612,44613,44614, +17257,44615,44616,44617,17258,44618,44619,44620,44621,44622,44623,44624,44625, +44626,44627,44628,44629,44630,44631,44632,44633,44634,44641,44642,44643,44644, +44645,44646,17259,44647,44648,44649,17260,44650,44651,44652,17261,44653,44654, +44655,44656,44657,44658,44659,17262,17263,44660,17264,44661,17265,44662,44663, +44664,44665,44666,44673,17266,44674,44675,44676,17267,44677,44678,44679,17268, +44680,44681,44682,44683,44684,44685,44686,17269,44687,44688,44689,44690,17270, +44691,44692,44693,44694,44695,44696,17271,17272,44697,44698,17273,44699,44700, +44701,17274,44702,44703,44704,44865,44866,44867,44868,17275,17276,44869,17277, +44870,17278,44871,44872,44873,44874,44875,44876,44877,44878,44879,44880,44881, +44882,44883,44884,44885,44886,44887,44888,44889,44890,44897,44898,44899,44900, +44901,44902,44903,44904,44905,44906,44907,44908,44909,44910,17441,17442,44911, +44912,17443,44913,44914,17444,17445,17446,44915,44916,44917,44918,44919,44920, +17447,17448,44921,17449,44922,17450,44929,44930,44931,44932,44933,44934,17451, +17452,44935,44936,17453,44937,44938,44939,17454,44940,44941,44942,44943,44944, +44945,44946,17455,17456,44947,17457,44948,17458,44949,44950,44951,44952,44953, +44954,17459,17460,44955,44956,17461,44957,44958,44959,17462,44960,45121,45122, +45123,45124,45125,45126,17463,17464,45127,17465,17466,17467,45128,45129,45130, +45131,45132,45133,17468,17469,45134,45135,45136,45137,45138,45139,45140,45141, +45142,45143,45144,45145,45146,45153,45154,45155,45156,45157,45158,17470,45159, +45160,45161,45162,45163,45164,45165,45166,45167,45168,45169,45170,45171,45172, +45173,45174,45175,45176,45177,45178,45185,45186,45187,45188,45189,45190,45191, +45192,45193,45194,45195,45196,45197,45198,17471,17472,45199,45200,17473,45201, +45202,17474,17475,45203,45204,45205,45206,45207,45208,45209,17476,17477,45210, +17478,17479,17480,45211,45212,45213,45214,45215,45216,17481,17482,45377,45378, +17483,45379,45380,45381,17484,45382,45383,45384,45385,45386,45387,45388,17485, +17486,45389,17487,45390,17488,45391,45392,45393,45394,45395,45396,17489,45397, +45398,45399,17490,45400,45401,45402,17491,45409,45410,45411,45412,45413,45414, +45415,17492,17493,45416,17494,17495,17496,45417,45418,45419,45420,45421,45422, +17497,45423,45424,45425,45426,45427,45428,45429,45430,45431,45432,45433,45434, +45441,45442,45443,45444,45445,45446,45447,45448,45449,45450,45451,45452,45453, +45454,45455,17498,17499,45456,45457,17500,45458,45459,45460,17501,45461,45462, +45463,45464,45465,45466,45467,17502,17503,45468,17504,45469,17505,45470,45471, +45472,45633,45634,45635,17506,17507,45636,45637,17508,45638,45639,45640,17509, +45641,45642,45643,45644,45645,45646,45647,17510,45648,45649,45650,45651,17511, +45652,45653,45654,45655,45656,45657,17512,45658,45665,45666,45667,45668,45669, +45670,45671,45672,45673,45674,45675,45676,45677,45678,45679,45680,45681,45682, +45683,17513,45684,45685,45686,45687,45688,45689,17514,45690,45697,45698,45699, +45700,45701,45702,17515,45703,45704,45705,45706,45707,45708,45709,45710,45711, +45712,45713,45714,45715,45716,45717,45718,45719,45720,45721,17516,45722,45723, +45724,45725,45726,45727,45728,45889,45890,45891,45892,45893,45894,45895,45896, +45897,45898,45899,45900,45901,45902,45903,45904,45905,45906,45907,45908,17517, +17518,45909,45910,17519,45911,45912,45913,17520,45914,45921,45922,45923,45924, +45925,45926,17521,17522,45927,17523,45928,17524,45929,45930,45931,45932,45933, +45934,17525,45935,45936,45937,17526,45938,45939,45940,17527,45941,45942,45943, +45944,45945,45946,45953,45954,45955,45956,45957,45958,17528,45959,45960,45961, +45962,45963,45964,17529,45965,45966,45967,45968,45969,45970,45971,45972,45973, +45974,45975,45976,45977,45978,45979,45980,45981,45982,45983,45984,17530,46145, +46146,46147,46148,46149,46150,17531,17532,46151,46152,17533,46153,46154,46155, +17534,46156,46157,46158,46159,46160,46161,46162,17697,17698,46163,17699,46164, +17700,46165,46166,46167,46168,46169,46170,17701,46177,46178,46179,17702,46180, +46181,46182,17703,46183,46184,46185,46186,46187,46188,46189,17704,46190,46191, +46192,46193,46194,46195,46196,46197,46198,46199,46200,17705,17706,46201,46202, +17707,46209,46210,46211,17708,46212,46213,46214,46215,46216,46217,46218,17709, +17710,46219,46220,46221,17711,46222,46223,46224,46225,46226,46227,46228,46229, +46230,46231,46232,46233,46234,46235,46236,46237,46238,46239,46240,46401,46402, +46403,46404,46405,46406,46407,46408,46409,46410,46411,46412,46413,46414,46415, +17712,17713,46416,46417,17714,46418,46419,46420,17715,46421,46422,46423,46424, +46425,46426,46433,17716,17717,46434,17718,46435,17719,46436,46437,46438,46439, +46440,46441,17720,17721,46442,46443,17722,46444,46445,46446,17723,17724,46447, +46448,46449,46450,46451,46452,17725,17726,46453,17727,17728,17729,46454,46455, +46456,46457,46458,46465,17730,17731,46466,46467,17732,46468,46469,46470,17733, +46471,46472,46473,46474,46475,46476,46477,17734,17735,46478,17736,17737,17738, +46479,46480,46481,46482,46483,46484,17739,46485,46486,46487,46488,46489,46490, +46491,46492,46493,46494,46495,46496,46657,46658,46659,46660,46661,46662,46663, +46664,17740,46665,46666,46667,46668,46669,46670,46671,46672,46673,46674,46675, +46676,46677,46678,46679,46680,46681,46682,46689,46690,46691,46692,46693,46694, +46695,46696,46697,46698,46699,46700,46701,46702,46703,46704,17741,17742,46705, +46706,17743,46707,46708,46709,17744,46710,17745,46711,46712,46713,46714,46721, +17746,17747,46722,17748,17749,17750,46723,46724,46725,46726,46727,46728,17751, +17752,46729,46730,17753,46731,46732,46733,17754,46734,46735,46736,46737,46738, +46739,46740,17755,17756,46741,17757,46742,17758,46743,46744,46745,46746,46747, +46748,17759,46749,46750,46751,17760,46752,46913,46914,46915,46916,46917,46918, +46919,46920,46921,46922,46923,46924,46925,46926,17761,46927,46928,46929,46930, +46931,46932,46933,17762,46934,46935,46936,17763,46937,46938,46945,46946,46947, +46948,46949,46950,46951,46952,46953,46954,46955,46956,46957,46958,46959,46960, +46961,46962,46963,46964,46965,17764,17765,46966,46967,17766,46968,46969,46970, +17767,46977,46978,46979,46980,46981,46982,46983,17768,17769,46984,17770,46985, +17771,46986,46987,46988,46989,17772,46990,17773,46991,46992,46993,17774,46994, +46995,46996,46997,46998,46999,47000,47001,47002,47003,47004,47005,47006,47007, +47008,47169,47170,47171,47172,47173,47174,47175,47176,17775,47177,47178,47179, +47180,47181,47182,47183,47184,47185,47186,47187,47188,47189,47190,47191,47192, +47193,47194,47201,47202,47203,47204,47205,47206,47207,47208,47209,17776,47210, +47211,47212,17777,47213,47214,47215,47216,47217,47218,47219,47220,47221,47222, +47223,47224,47225,47226,17778,47233,17779,47234,47235,47236,47237,47238,47239, +17780,47240,47241,47242,47243,47244,47245,47246,47247,47248,47249,47250,47251, +47252,47253,47254,47255,47256,47257,47258,47259,47260,47261,47262,47263,47264, +47425,47426,17781,17782,47427,47428,17783,47429,47430,47431,17784,47432,47433, +47434,47435,47436,47437,47438,17785,17786,47439,17787,47440,17788,47441,47442, +47443,47444,47445,47446,17789,47447,47448,47449,47450,47457,47458,47459,47460, +47461,47462,47463,47464,47465,47466,47467,47468,47469,47470,47471,17790,47472, +47473,47474,47475,47476,47477,47478,17953,47479,47480,47481,47482,47489,47490, +47491,47492,47493,47494,47495,47496,47497,47498,47499,47500,47501,47502,47503, +47504,47505,47506,47507,47508,47509,47510,47511,17954,17955,47512,47513,17956, +47514,47515,47516,17957,47517,47518,47519,47520,47681,47682,47683,17958,17959, +47684,47685,47686,17960,47687,47688,47689,47690,47691,47692,17961,47693,47694, +47695,17962,47696,47697,47698,17963,47699,47700,47701,47702,47703,47704,47705, +17964,47706,47713,47714,47715,17965,47716,47717,47718,47719,47720,47721,17966, +17967,47722,47723,17968,47724,47725,17969,17970,47726,17971,47727,47728,47729, +47730,47731,17972,17973,47732,17974,47733,47734,47735,47736,47737,47738,47745, +47746,17975,47747,47748,47749,17976,47750,47751,47752,17977,47753,47754,47755, +47756,47757,47758,47759,17978,17979,47760,47761,47762,47763,47764,47765,47766, +47767,47768,47769,17980,17981,47770,47771,17982,47772,47773,47774,17983,47775, +47776,47937,47938,47939,47940,47941,17984,17985,47942,17986,47943,17987,47944, +47945,47946,47947,47948,47949,17988,17989,17990,47950,17991,47951,47952,47953, +17992,47954,17993,47955,47956,47957,47958,47959,17994,17995,47960,17996,17997, +17998,47961,47962,47969,17999,47970,47971,18000,18001,47972,47973,18002,47974, +47975,47976,18003,47977,47978,47979,47980,47981,47982,47983,18004,18005,47984, +18006,18007,18008,47985,47986,47987,47988,47989,47990,18009,18010,47991,47992, +47993,47994,48001,48002,48003,48004,48005,48006,48007,48008,48009,48010,48011, +48012,48013,48014,48015,48016,48017,48018,48019,48020,48021,48022,48023,48024, +48025,48026,48027,48028,48029,48030,48031,48032,48193,48194,48195,48196,48197, +48198,48199,48200,48201,48202,48203,48204,48205,48206,48207,48208,48209,48210, +18011,18012,48211,48212,18013,48213,48214,48215,18014,48216,48217,48218,48225, +48226,48227,48228,18015,18016,48229,18017,18018,18019,48230,48231,48232,48233, +48234,48235,18020,18021,48236,48237,18022,48238,48239,48240,18023,48241,48242, +48243,48244,48245,48246,48247,18024,18025,48248,18026,48249,18027,48250,48257, +48258,48259,48260,48261,18028,48262,48263,48264,18029,48265,48266,48267,18030, +48268,48269,48270,48271,48272,48273,48274,18031,18032,48275,48276,18033,18034, +48277,48278,48279,48280,48281,48282,18035,48283,48284,48285,48286,48287,48288, +48449,18036,48450,48451,48452,48453,48454,48455,48456,48457,18037,48458,18038, +48459,48460,48461,48462,48463,48464,48465,48466,18039,18040,48467,48468,18041, +48469,48470,48471,18042,48472,48473,48474,48481,48482,48483,48484,18043,18044, +48485,18045,48486,18046,48487,48488,48489,48490,48491,48492,18209,48493,48494, +48495,48496,48497,48498,48499,48500,48501,48502,48503,48504,48505,48506,48513, +48514,48515,48516,48517,48518,18210,48519,48520,48521,48522,48523,48524,48525, +48526,48527,48528,48529,48530,48531,48532,48533,48534,48535,48536,48537,48538, +48539,48540,48541,48542,48543,48544,48705,48706,48707,48708,48709,48710,48711, +48712,18211,48713,48714,48715,18212,48716,48717,48718,48719,48720,48721,48722, +48723,48724,48725,48726,48727,48728,48729,48730,48737,48738,48739,48740,48741, +48742,48743,48744,18213,48745,48746,48747,18214,48748,48749,48750,18215,48751, +48752,48753,48754,48755,48756,48757,48758,18216,48759,18217,48760,48761,48762, +48769,48770,48771,48772,48773,18218,18219,48774,48775,18220,48776,48777,18221, +18222,48778,18223,48779,48780,48781,48782,48783,18224,18225,48784,18226,48785, +18227,48786,48787,48788,48789,48790,48791,18228,48792,48793,48794,48795,48796, +48797,48798,48799,48800,48961,48962,48963,48964,48965,48966,48967,48968,48969, +48970,48971,18229,48972,48973,48974,48975,48976,48977,48978,48979,48980,48981, +48982,48983,48984,48985,48986,48993,48994,48995,48996,48997,48998,48999,49000, +49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,18230,49012, +49013,49014,18231,49015,49016,49017,18232,49018,49025,49026,49027,49028,49029, +49030,18233,49031,49032,18234,49033,49034,49035,49036,49037,49038,49039,49040, +18235,49041,49042,49043,18236,49044,49045,49046,18237,49047,49048,49049,49050, +49051,49052,49053,18238,49054,49055,18239,49056,18240,49217,49218,49219,49220, +49221,49222,18241,49223,49224,49225,18242,49226,49227,49228,18243,49229,49230, +49231,49232,49233,49234,49235,18244,18245,49236,18246,49237,49238,49239,49240, +49241,49242,49249,49250,49251,49252,49253,49254,49255,49256,49257,49258,49259, +49260,49261,49262,49263,49264,49265,49266,49267,49268,49269,49270,49271,49272, +49273,49274,49281,49282,49283,49284,18247,18248,49285,49286,18249,49287,49288, +49289,18250,49290,49291,49292,49293,49294,49295,49296,18251,18252,49297,18253, +49298,18254,49299,49300,49301,49302,49303,49304,18255,18256,49305,49306,18257, +49307,49308,49309,18258,49310,49311,49312,49473,18259,49474,49475,18260,18261, +49476,18262,49477,18263,49478,49479,49480,49481,49482,49483,18264,18265,49484, +49485,18266,49486,49487,49488,18267,49489,49490,49491,49492,49493,49494,49495, +18268,18269,49496,18270,18271,18272,49497,49498,49505,49506,49507,49508,18273, +49509,49510,49511,49512,49513,49514,49515,49516,49517,49518,49519,49520,49521, +49522,49523,49524,49525,49526,49527,49528,18274,49529,49530,49537,49538,49539, +49540,49541,49542,49543,49544,49545,49546,49547,49548,49549,49550,49551,49552, +49553,49554,49555,49556,49557,49558,49559,49560,49561,49562,49563,49564,49565, +49566,49567,49568,18275,18276,49729,49730,18277,49731,49732,49733,18278,49734, +18279,49735,49736,49737,49738,49739,18280,18281,49740,18282,49741,18283,49742, +49743,49744,49745,49746,49747,18284,18285,49748,49749,18286,49750,49751,49752, +18287,49753,49754,49761,49762,49763,49764,49765,18288,18289,49766,18290,49767, +18291,49768,49769,49770,49771,49772,49773,18292,18293,49774,49775,18294,49776, +49777,49778,18295,49779,49780,49781,49782,49783,49784,49785,18296,18297,49786, +18298,18299,18300,49793,49794,49795,49796,49797,49798,18301,49799,49800,49801, +18302,49802,49803,49804,18465,49805,49806,49807,49808,49809,49810,49811,49812, +18466,49813,49814,49815,49816,49817,49818,49819,49820,49821,49822,18467,18468, +49823,49824,18469,49985,49986,49987,18470,49988,49989,49990,49991,18471,49992, +49993,18472,18473,49994,18474,49995,18475,49996,49997,49998,18476,49999,50000, +18477,18478,50001,50002,18479,50003,50004,50005,18480,50006,50007,50008,50009, +50010,50017,50018,50019,50020,50021,18481,50022,18482,50023,50024,50025,50026, +50027,50028,18483,18484,50029,50030,18485,50031,50032,50033,50034,50035,50036, +50037,50038,50039,50040,50041,50042,50049,50050,18486,50051,18487,50052,50053, +50054,50055,50056,50057,18488,18489,50058,50059,18490,50060,50061,50062,18491, +50063,50064,50065,50066,50067,50068,50069,50070,18492,50071,18493,50072,18494, +50073,50074,50075,50076,50077,50078,18495,50079,50080,50241,18496,50242,50243, +50244,18497,50245,50246,50247,50248,50249,50250,50251,50252,18498,50253,18499, +50254,50255,50256,50257,50258,50259,50260,50261,18500,18501,50262,50263,18502, +50264,50265,50266,18503,50273,50274,50275,50276,18504,50277,50278,18505,50279, +50280,18506,50281,18507,50282,50283,50284,50285,50286,50287,18508,50288,50289, +50290,18509,50291,50292,50293,18510,50294,50295,50296,50297,50298,50305,50306, +18511,50307,50308,50309,50310,18512,50311,50312,50313,50314,50315,50316,18513, +18514,50317,50318,18515,50319,50320,50321,18516,50322,50323,50324,50325,50326, +50327,50328,50329,50330,50331,50332,50333,18517,50334,50335,50336,50497,50498, +50499,18518,18519,50500,50501,18520,50502,50503,50504,18521,50505,50506,50507, +50508,50509,50510,50511,18522,18523,50512,18524,50513,18525,50514,50515,50516, +50517,50518,50519,18526,18527,50520,50521,18528,50522,50529,50530,18529,50531, +50532,50533,50534,50535,50536,50537,18530,50538,50539,18531,50540,18532,50541, +50542,50543,50544,50545,50546,18533,18534,50547,50548,18535,50549,18536,18537, +18538,18539,50550,50551,50552,50553,50554,50561,18540,18541,50562,18542,50563, +18543,50564,50565,50566,18544,50567,50568,18545,50569,50570,50571,18546,50572, +50573,50574,18547,50575,50576,50577,50578,50579,50580,50581,18548,18549,50582, +50583,50584,18550,50585,50586,50587,50588,50589,50590,18551,18552,50591,50592, +18553,50753,50754,50755,18554,50756,50757,50758,50759,50760,50761,50762,18555, +18556,50763,18557,50764,18558,50765,50766,50767,50768,50769,50770,19280,19286, +19303,19791,19816,20013,20347,20514,20536,20560,20573,20820,20821,20824,20827, +20828,20829,20830,20831,20832,20834,20835,20836,20837,20838,20840,20841,20842, +20843,20845,20847,20848,20850,20854,20858,20860,20861,20862,21026,21027,21031, +21032,21033,21034,21035,21037,21042,21054,21058,21059,21060,21062,21063,21064, +21065,21066,21067,21069,21070,21071,21072,21073,21074,21075,21076,21077,21078, +21079,21081,21082,21086,21087,21089,21090,21092,21093,21094,21095,21096,21097, +21098,21099,21104,21105,21106,21107,21108,21109,21111,21112,21606,21628,21797, +21803,21806,22072,22093,22347,22372,23365,23396,23589,23845,23893,23924,24188, +24190,24371,24417,24424,24689,24877,24941,25461,25633,25641,25902,25905,25906, +25913,25915,25916,25924,25934,25936,25938,25942,25978,25979,25980,25982,26145, +26148,26151,26157,26159,26160,26161,26163,26167,26168,26172,26180,26182,26183, +26186,26194,26198,26201,26204,26207,26209,26212,26213,26214,26216,26218,26219, +26220,26223,26225,26226,26229,26230,26231,26233,26401,26406,26409,26410,26412, +26413,26416,26431,26433,26438,26439,26443,26445,26447,26448,26451,26463,26468, +26470,26487,26727,26728,26736,26737,26743,26745,26747,26750,26919,26924,26956, +26999,27201,27237,27252,27255,27260,27262,27428,27431,27433,27434,27450,27451, +27453,27457,27458,27462,27463,27468,27471,27472,27473,27474,27480,27686,27687, +27690,27695,27696,27697,27698,27701,27704,27706,27712,27713,27717,27718,27721, +27722,27733,27741,27742,27745,27748,27751,27752,27767,27768,27770,27937,27938, +27939,28014,28251,29245,29306,29489,29735,29806,30324,30326,30520,30536,30547, +30811,30832,31265,31266,31334,31785,8993,8994,8995,8996,8997,8998,8999,9000, +9001,9002,9003,9004,9005,9006,9007,9008,9009,9010,9011,9012,9013,9014,9015, +9016,9017,9018,9019,9020,9021,9022,9023,9024,9025,9026,9027,9028,9029,9030, +9031,9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,9043,9044,9045, +9046,9047,9048,9049,9050,9051,8492,9053,9054,9055,9056,9057,9058,9059,9060, +9061,9062,9063,9064,9065,9066,9067,9068,9069,9070,9071,9072,9073,9074,9075, +9076,9077,9078,9079,9080,9081,9082,9083,9084,9085,8742,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,8523,8524,8574,9086,N,8525,9052, +}; + +static const struct unim_index cp949_encmap[256] = { +{__cp949_encmap+0,161,254},{__cp949_encmap+94,17,103},{__cp949_encmap+181,199, +221},{__cp949_encmap+204,145,201},{__cp949_encmap+261,1,81},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp949_encmap+342,21,172},{ +__cp949_encmap+494,3,212},{__cp949_encmap+704,0,165},{__cp949_encmap+870,18,18 +},{__cp949_encmap+871,96,233},{__cp949_encmap+1009,0,209},{__cp949_encmap+1219 +,5,109},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{__cp949_encmap+1324,0,246},{__cp949_encmap+1571,49,142},{__cp949_encmap+ +1665,0,127},{__cp949_encmap+1793,128,221},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{__cp949_encmap+1887,0,251},{__cp949_encmap+2139,1,250},{ +__cp949_encmap+2389,2,255},{__cp949_encmap+2643,0,253},{__cp949_encmap+2897,0, +255},{__cp949_encmap+3153,5,248},{__cp949_encmap+3397,3,250},{__cp949_encmap+ +3645,4,254},{__cp949_encmap+3896,6,250},{__cp949_encmap+4141,3,252},{ +__cp949_encmap+4391,0,253},{__cp949_encmap+4645,15,255},{__cp949_encmap+4886, +1,233},{__cp949_encmap+5119,5,250},{__cp949_encmap+5365,1,253},{__cp949_encmap ++5618,7,254},{__cp949_encmap+5866,2,251},{__cp949_encmap+6116,1,255},{ +__cp949_encmap+6371,15,251},{__cp949_encmap+6608,1,255},{__cp949_encmap+6863, +0,255},{__cp949_encmap+7119,1,247},{__cp949_encmap+7366,13,254},{ +__cp949_encmap+7608,0,255},{__cp949_encmap+7864,6,255},{__cp949_encmap+8114,0, +254},{__cp949_encmap+8369,18,250},{__cp949_encmap+8602,0,255},{__cp949_encmap+ +8858,2,251},{__cp949_encmap+9108,4,236},{__cp949_encmap+9341,8,243},{ +__cp949_encmap+9577,11,251},{__cp949_encmap+9818,23,255},{__cp949_encmap+10051 +,1,254},{__cp949_encmap+10305,1,253},{__cp949_encmap+10558,4,255},{ +__cp949_encmap+10810,0,253},{__cp949_encmap+11064,10,254},{__cp949_encmap+ +11309,1,247},{__cp949_encmap+11556,1,252},{__cp949_encmap+11808,0,254},{ +__cp949_encmap+12063,1,243},{__cp949_encmap+12306,2,251},{__cp949_encmap+12556 +,1,251},{__cp949_encmap+12807,0,255},{__cp949_encmap+13063,15,233},{ +__cp949_encmap+13282,7,254},{__cp949_encmap+13530,0,251},{__cp949_encmap+13782 +,9,156},{__cp949_encmap+13930,54,252},{__cp949_encmap+14129,0,253},{ +__cp949_encmap+14383,2,254},{__cp949_encmap+14636,5,254},{__cp949_encmap+14886 +,1,253},{__cp949_encmap+15139,3,252},{__cp949_encmap+15389,17,255},{ +__cp949_encmap+15628,2,254},{__cp949_encmap+15881,0,254},{__cp949_encmap+16136 +,5,253},{__cp949_encmap+16385,7,248},{__cp949_encmap+16627,0,254},{ +__cp949_encmap+16882,0,154},{__cp949_encmap+17037,55,253},{__cp949_encmap+ +17236,4,243},{__cp949_encmap+17476,10,254},{__cp949_encmap+17721,3,253},{ +__cp949_encmap+17972,0,253},{__cp949_encmap+18226,2,245},{__cp949_encmap+18470 +,13,252},{__cp949_encmap+18710,4,246},{__cp949_encmap+18953,4,127},{ +__cp949_encmap+19077,119,226},{__cp949_encmap+19185,28,251},{__cp949_encmap+ +19409,0,255},{__cp949_encmap+19665,0,254},{__cp949_encmap+19920,3,255},{ +__cp949_encmap+20173,1,238},{__cp949_encmap+20411,26,232},{__cp949_encmap+ +20618,13,246},{__cp949_encmap+20852,9,250},{__cp949_encmap+21094,26,244},{ +__cp949_encmap+21313,7,156},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp949_encmap+21463,0,255},{ +__cp949_encmap+21719,0,255},{__cp949_encmap+21975,0,255},{__cp949_encmap+22231 +,0,255},{__cp949_encmap+22487,0,255},{__cp949_encmap+22743,0,255},{ +__cp949_encmap+22999,0,255},{__cp949_encmap+23255,0,255},{__cp949_encmap+23511 +,0,255},{__cp949_encmap+23767,0,255},{__cp949_encmap+24023,0,255},{ +__cp949_encmap+24279,0,255},{__cp949_encmap+24535,0,255},{__cp949_encmap+24791 +,0,255},{__cp949_encmap+25047,0,255},{__cp949_encmap+25303,0,255},{ +__cp949_encmap+25559,0,255},{__cp949_encmap+25815,0,255},{__cp949_encmap+26071 +,0,255},{__cp949_encmap+26327,0,255},{__cp949_encmap+26583,0,255},{ +__cp949_encmap+26839,0,255},{__cp949_encmap+27095,0,255},{__cp949_encmap+27351 +,0,255},{__cp949_encmap+27607,0,255},{__cp949_encmap+27863,0,255},{ +__cp949_encmap+28119,0,255},{__cp949_encmap+28375,0,255},{__cp949_encmap+28631 +,0,255},{__cp949_encmap+28887,0,255},{__cp949_encmap+29143,0,255},{ +__cp949_encmap+29399,0,255},{__cp949_encmap+29655,0,255},{__cp949_encmap+29911 +,0,255},{__cp949_encmap+30167,0,255},{__cp949_encmap+30423,0,255},{ +__cp949_encmap+30679,0,255},{__cp949_encmap+30935,0,255},{__cp949_encmap+31191 +,0,255},{__cp949_encmap+31447,0,255},{__cp949_encmap+31703,0,255},{ +__cp949_encmap+31959,0,255},{__cp949_encmap+32215,0,255},{__cp949_encmap+32471 +,0,163},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp949_encmap+32635,0,255},{ +__cp949_encmap+32891,0,11},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp949_encmap+ +32903,1,230}, +}; diff --git a/pypy/translator/c/src/cjkcodecs/mappings_tw.h b/pypy/translator/c/src/cjkcodecs/mappings_tw.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/mappings_tw.h @@ -0,0 +1,2633 @@ +static const ucs2_t __big5_decmap[16702] = { +12288,65292,12289,12290,65294,8226,65307,65306,65311,65281,65072,8230,8229, +65104,65380,65106,183,65108,65109,65110,65111,65372,8211,65073,8212,65075, +9588,65076,65103,65288,65289,65077,65078,65371,65373,65079,65080,12308,12309, +65081,65082,12304,12305,65083,65084,12298,12299,65085,65086,12296,12297,65087, +65088,12300,12301,65089,65090,12302,12303,65091,65092,65113,65114,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,65115,65116,65117, +65118,8216,8217,8220,8221,12317,12318,8245,8242,65283,65286,65290,8251,167, +12291,9675,9679,9651,9650,9678,9734,9733,9671,9670,9633,9632,9661,9660,12963, +8453,8254,65507,65343,717,65097,65098,65101,65102,65099,65100,65119,65120, +65121,65291,65293,215,247,177,8730,65308,65310,65309,8806,8807,8800,8734,8786, +8801,65122,65123,65124,65125,65126,8764,8745,8746,8869,8736,8735,8895,13266, +13265,8747,8750,8757,8756,9792,9794,9793,9737,8593,8595,8592,8594,8598,8599, +8601,8600,8741,8739,65295,65340,65295,65340,65284,165,12306,162,163,65285, +65312,8451,8457,65129,65130,65131,13269,13212,13213,13214,13262,13217,13198, +13199,13252,176,20825,20827,20830,20829,20833,20835,21991,29929,31950,9601, +9602,9603,9604,9605,9606,9607,9608,9615,9614,9613,9612,9611,9610,9609,9532, +9524,9516,9508,9500,9620,9472,9474,9621,9484,9488,9492,9496,9581,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,9582,9584,9583,9552, +9566,9578,9569,9698,9699,9701,9700,9585,9586,9587,65296,65297,65298,65299, +65300,65301,65302,65303,65304,65305,8544,8545,8546,8547,8548,8549,8550,8551, +8552,8553,12321,12322,12323,12324,12325,12326,12327,12328,12329,21313,21316, +21317,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324, +65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337, +65338,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356, +65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369, +65370,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931, +932,933,934,935,936,937,945,946,947,948,949,950,951,952,953,954,955,956,957, +958,959,960,961,963,964,965,966,967,968,969,12549,12550,12551,12552,12553, +12554,12555,12556,12557,12558,12559,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,12560,12561,12562,12563,12564,12565,12566,12567, +12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580, +12581,12582,12583,12584,12585,729,713,714,711,715,19968,20057,19969,19971, +20035,20061,20102,20108,20154,20799,20837,20843,20960,20992,20993,21147,21269, +21313,21340,21448,19977,19979,19976,19978,20011,20024,20961,20037,20040,20063, +20062,20110,20129,20800,20995,21242,21315,21449,21475,22303,22763,22805,22823, +22899,23376,23377,23379,23544,23567,23586,23608,23665,24029,24037,24049,24050, +24051,24062,24178,24318,24331,24339,25165,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,19985,19984,19981,20013,20016,20025,20043, +23609,20104,20113,20117,20114,20116,20130,20161,20160,20163,20166,20167,20173, +20170,20171,20164,20803,20801,20839,20845,20846,20844,20887,20982,20998,20999, +21000,21243,21246,21247,21270,21305,21320,21319,21317,21342,21380,21451,21450, +21453,22764,22825,22827,22826,22829,23380,23569,23588,23610,23663,24052,24187, +24319,24340,24341,24515,25096,25142,25163,25166,25903,25991,26007,26020,26041, +26085,26352,26376,26408,27424,27490,27513,27595,27604,27611,27663,27700,28779, +29226,29238,29243,29255,29273,29275,29356,29579,19993,19990,19989,19988,19992, +20027,20045,20047,20046,20197,20184,20180,20181,20182,20183,20195,20196,20185, +20190,20805,20804,20873,20874,20908,20985,20986,20984,21002,21152,21151,21253, +21254,21271,21277,20191,21322,21321,21345,21344,21359,21358,21435,21487,21476, +21491,21484,21486,21481,21480,21500,21496,21493,21483,21478,21482,21490,21489, +21488,21477,21485,21499,22235,22234,22806,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22830,22833,22900,22902,23381,23427,23612, +24040,24039,24038,24066,24067,24179,24188,24321,24344,24343,24517,25098,25171, +25172,25170,25169,26021,26086,26414,26412,26410,26411,26413,27491,27597,27665, +27664,27704,27713,27712,27710,29359,29572,29577,29916,29926,29976,29983,29992, +29993,30000,30001,30002,30003,30091,30333,30382,30399,30446,30683,30690,30707, +31034,31166,31348,31435,19998,19999,20050,20051,20073,20121,20132,20134,20133, +20223,20233,20249,20234,20245,20237,20240,20241,20239,20210,20214,20219,20208, +20211,20221,20225,20235,20809,20807,20806,20808,20840,20849,20877,20912,21015, +21009,21010,21006,21014,21155,21256,21281,21280,21360,21361,21513,21519,21516, +21514,21520,21505,21515,21508,21521,21517,21512,21507,21518,21510,21522,22240, +22238,22237,22323,22320,22312,22317,22316,22319,22313,22809,22810,22839,22840, +22916,22904,22915,22909,22905,22914,22913,23383,23384,23431,23432,23429,23433, +23546,23574,23673,24030,24070,24182,24180,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24335,24347,24537,24534,25102,25100,25101, +25104,25187,25179,25176,25910,26089,26088,26092,26093,26354,26355,26377,26429, +26420,26417,26421,27425,27492,27515,27670,27741,27735,27737,27743,27744,27728, +27733,27745,27739,27725,27726,28784,29279,29277,30334,31481,31859,31992,32566, +32650,32701,32769,32771,32780,32786,32819,32895,32905,32907,32908,33251,33258, +33267,33276,33292,33307,33311,33390,33394,33406,34411,34880,34892,34915,35199, +38433,20018,20136,20301,20303,20295,20311,20318,20276,20315,20309,20272,20304, +20305,20285,20282,20280,20291,20308,20284,20294,20323,20316,20320,20271,20302, +20278,20313,20317,20296,20314,20812,20811,20813,20853,20918,20919,21029,21028, +21033,21034,21032,21163,21161,21162,21164,21283,21363,21365,21533,21549,21534, +21566,21542,21582,21543,21574,21571,21555,21576,21570,21531,21545,21578,21561, +21563,21560,21550,21557,21558,21536,21564,21568,21553,21547,21535,21548,22250, +22256,22244,22251,22346,22353,22336,22349,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22343,22350,22334,22352,22351,22331,22767, +22846,22941,22930,22952,22942,22947,22937,22934,22925,22948,22931,22922,22949, +23389,23388,23386,23387,23436,23435,23439,23596,23616,23617,23615,23614,23696, +23697,23700,23692,24043,24076,24207,24199,24202,24311,24324,24351,24420,24418, +24439,24441,24536,24524,24535,24525,24561,24555,24568,24554,25106,25105,25220, +25239,25238,25216,25206,25225,25197,25226,25212,25214,25209,25203,25234,25199, +25240,25198,25237,25235,25233,25222,25913,25915,25912,26097,26356,26463,26446, +26447,26448,26449,26460,26454,26462,26441,26438,26464,26451,26455,27493,27599, +27714,27742,27801,27777,27784,27785,27781,27803,27754,27770,27792,27760,27788, +27752,27798,27794,27773,27779,27762,27774,27764,27782,27766,27789,27796,27800, +27778,28790,28796,28797,28792,29282,29281,29280,29380,29378,29590,29996,29995, +30007,30008,30338,30447,30691,31169,31168,31167,31350,31995,32597,32918,32915, +32925,32920,32923,32922,32946,33391,33426,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33419,33421,35211,35282,35328,35895,35910, +35925,35997,36196,36208,36275,36523,36554,36763,36784,36802,36806,36805,36804, +24033,37009,37026,37034,37030,37027,37193,37318,37324,38450,38446,38449,38442, +38444,20006,20054,20083,20107,20123,20126,20139,20140,20335,20381,20365,20339, +20351,20332,20379,20363,20358,20355,20336,20341,20360,20329,20347,20374,20350, +20367,20369,20346,20820,20818,20821,20841,20855,20854,20856,20925,20989,21051, +21048,21047,21050,21040,21038,21046,21057,21182,21179,21330,21332,21331,21329, +21350,21367,21368,21369,21462,21460,21463,21619,21621,21654,21624,21653,21632, +21627,21623,21636,21650,21638,21628,21648,21617,21622,21644,21658,21602,21608, +21643,21629,21646,22266,22403,22391,22378,22377,22369,22374,22372,22396,22812, +22857,22855,22856,22852,22868,22974,22971,22996,22969,22958,22993,22982,22992, +22989,22987,22995,22986,22959,22963,22994,22981,23391,23396,23395,23447,23450, +23448,23452,23449,23451,23578,23624,23621,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23622,23735,23713,23736,23721,23723,23729, +23731,24088,24090,24086,24085,24091,24081,24184,24218,24215,24220,24213,24214, +24310,24358,24359,24361,24448,24449,24447,24444,24541,24544,24573,24565,24575, +24591,24596,24623,24629,24598,24618,24597,24609,24615,24617,24619,24603,25110, +25109,25151,25150,25152,25215,25289,25292,25284,25279,25282,25273,25298,25307, +25259,25299,25300,25291,25288,25256,25277,25276,25296,25305,25287,25293,25269, +25306,25265,25304,25302,25303,25286,25260,25294,25918,26023,26044,26106,26132, +26131,26124,26118,26114,26126,26112,26127,26133,26122,26119,26381,26379,26477, +26507,26517,26481,26524,26483,26487,26503,26525,26519,26479,26480,26495,26505, +26494,26512,26485,26522,26515,26492,26474,26482,27427,27494,27495,27519,27667, +27675,27875,27880,27891,27825,27852,27877,27827,27837,27838,27836,27874,27819, +27861,27859,27832,27844,27833,27841,27822,27863,27845,27889,27839,27835,27873, +27867,27850,27820,27887,27868,27862,27872,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28821,28814,28818,28810,28825,29228,29229, +29240,29256,29287,29289,29376,29390,29401,29399,29392,29609,29608,29599,29611, +29605,30013,30109,30105,30106,30340,30402,30450,30452,30693,30717,31038,31040, +31041,31177,31176,31354,31353,31482,31998,32596,32652,32651,32773,32954,32933, +32930,32945,32929,32939,32937,32948,32938,32943,33253,33278,33293,33459,33437, +33433,33453,33469,33439,33465,33457,33452,33445,33455,33464,33443,33456,33470, +33463,34382,34417,21021,34920,36555,36814,36820,36817,37045,37048,37041,37046, +37319,37329,38263,38272,38428,38464,38463,38459,38468,38466,38585,38632,38738, +38750,20127,20141,20142,20449,20405,20399,20415,20448,20433,20431,20445,20419, +20406,20440,20447,20426,20439,20398,20432,20420,20418,20442,20430,20446,20407, +20823,20882,20881,20896,21070,21059,21066,21069,21068,21067,21063,21191,21193, +21187,21185,21261,21335,21371,21402,21467,21676,21696,21672,21710,21705,21688, +21670,21683,21703,21698,21693,21674,21697,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,21700,21704,21679,21675,21681,21691,21673, +21671,21695,22271,22402,22411,22432,22435,22434,22478,22446,22419,22869,22865, +22863,22862,22864,23004,23000,23039,23011,23016,23043,23013,23018,23002,23014, +23041,23035,23401,23459,23462,23460,23458,23461,23553,23630,23631,23629,23627, +23769,23762,24055,24093,24101,24095,24189,24224,24230,24314,24328,24365,24421, +24456,24453,24458,24459,24455,24460,24457,24594,24605,24608,24613,24590,24616, +24653,24688,24680,24674,24646,24643,24684,24683,24682,24676,25153,25308,25366, +25353,25340,25325,25345,25326,25341,25351,25329,25335,25327,25324,25342,25332, +25361,25346,25919,25925,26027,26045,26082,26149,26157,26144,26151,26159,26143, +26152,26161,26148,26359,26623,26579,26609,26580,26576,26604,26550,26543,26613, +26601,26607,26564,26577,26548,26586,26597,26552,26575,26590,26611,26544,26585, +26594,26589,26578,27498,27523,27526,27573,27602,27607,27679,27849,27915,27954, +27946,27969,27941,27916,27953,27934,27927,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,27963,27965,27966,27958,27931,27893,27961, +27943,27960,27945,27950,27957,27918,27947,28843,28858,28851,28844,28847,28845, +28856,28846,28836,29232,29298,29295,29300,29417,29408,29409,29623,29642,29627, +29618,29645,29632,29619,29978,29997,30031,30028,30030,30027,30123,30116,30117, +30114,30115,30328,30342,30343,30344,30408,30406,30403,30405,30465,30457,30456, +30473,30475,30462,30460,30471,30684,30722,30740,30732,30733,31046,31049,31048, +31047,31161,31162,31185,31186,31179,31359,31361,31487,31485,31869,32002,32005, +32000,32009,32007,32004,32006,32568,32654,32703,32772,32784,32781,32785,32822, +32982,32997,32986,32963,32964,32972,32993,32987,32974,32990,32996,32989,33268, +33314,33511,33539,33541,33507,33499,33510,33540,33509,33538,33545,33490,33495, +33521,33537,33500,33492,33489,33502,33491,33503,33519,33542,34384,34425,34427, +34426,34893,34923,35201,35284,35336,35330,35331,35998,36000,36212,36211,36276, +36557,36556,36848,36838,36834,36842,36837,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,36845,36843,36836,36840,37066,37070,37057, +37059,37195,37194,37325,38274,38480,38475,38476,38477,38754,38761,38859,38893, +38899,38913,39080,39131,39135,39318,39321,20056,20147,20492,20493,20515,20463, +20518,20517,20472,20521,20502,20486,20540,20511,20506,20498,20497,20474,20480, +20500,20520,20465,20513,20491,20505,20504,20467,20462,20525,20522,20478,20523, +20489,20860,20900,20901,20898,20941,20940,20934,20939,21078,21084,21076,21083, +21085,21290,21375,21407,21405,21471,21736,21776,21761,21815,21756,21733,21746, +21766,21754,21780,21737,21741,21729,21769,21742,21738,21734,21799,21767,21757, +21775,22275,22276,22466,22484,22475,22467,22537,22799,22871,22872,22874,23057, +23064,23068,23071,23067,23059,23020,23072,23075,23081,23077,23052,23049,23403, +23640,23472,23475,23478,23476,23470,23477,23481,23480,23556,23633,23637,23632, +23789,23805,23803,23786,23784,23792,23798,23809,23796,24046,24109,24107,24235, +24237,24231,24369,24466,24465,24464,24665,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24675,24677,24656,24661,24685,24681,24687, +24708,24735,24730,24717,24724,24716,24709,24726,25159,25331,25352,25343,25422, +25406,25391,25429,25410,25414,25423,25417,25402,25424,25405,25386,25387,25384, +25421,25420,25928,25929,26009,26049,26053,26178,26185,26191,26179,26194,26188, +26181,26177,26360,26388,26389,26391,26657,26680,26696,26694,26707,26681,26690, +26708,26665,26803,26647,26700,26705,26685,26612,26704,26688,26684,26691,26666, +26693,26643,26648,26689,27530,27529,27575,27683,27687,27688,27686,27684,27888, +28010,28053,28040,28039,28006,28024,28023,27993,28051,28012,28041,28014,27994, +28020,28009,28044,28042,28025,28037,28005,28052,28874,28888,28900,28889,28872, +28879,29241,29305,29436,29433,29437,29432,29431,29574,29677,29705,29678,29664, +29674,29662,30036,30045,30044,30042,30041,30142,30149,30151,30130,30131,30141, +30140,30137,30146,30136,30347,30384,30410,30413,30414,30505,30495,30496,30504, +30697,30768,30759,30776,30749,30772,30775,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30757,30765,30752,30751,30770,31061,31056, +31072,31071,31062,31070,31069,31063,31066,31204,31203,31207,31199,31206,31209, +31192,31364,31368,31449,31494,31505,31881,32033,32023,32011,32010,32032,32034, +32020,32016,32021,32026,32028,32013,32025,32027,32570,32607,32660,32709,32705, +32774,32792,32789,32793,32791,32829,32831,33009,33026,33008,33029,33005,33012, +33030,33016,33011,33032,33021,33034,33020,33007,33261,33260,33280,33296,33322, +33323,33320,33324,33467,33579,33618,33620,33610,33592,33616,33609,33589,33588, +33615,33586,33593,33590,33559,33600,33585,33576,33603,34388,34442,34474,34451, +34468,34473,34444,34467,34460,34928,34935,34945,34946,34941,34937,35352,35344, +35342,35340,35349,35338,35351,35347,35350,35343,35345,35912,35962,35961,36001, +36002,36215,36524,36562,36564,36559,36785,36865,36870,36855,36864,36858,36852, +36867,36861,36869,36856,37013,37089,37085,37090,37202,37197,37196,37336,37341, +37335,37340,37337,38275,38498,38499,38497,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38491,38493,38500,38488,38494,38587,39138, +39340,39592,39640,39717,39730,39740,20094,20602,20605,20572,20551,20547,20556, +20570,20553,20581,20598,20558,20565,20597,20596,20599,20559,20495,20591,20589, +20828,20885,20976,21098,21103,21202,21209,21208,21205,21264,21263,21273,21311, +21312,21310,21443,26364,21830,21866,21862,21828,21854,21857,21827,21834,21809, +21846,21839,21845,21807,21860,21816,21806,21852,21804,21859,21811,21825,21847, +22280,22283,22281,22495,22533,22538,22534,22496,22500,22522,22530,22581,22519, +22521,22816,22882,23094,23105,23113,23142,23146,23104,23100,23138,23130,23110, +23114,23408,23495,23493,23492,23490,23487,23494,23561,23560,23559,23648,23644, +23645,23815,23814,23822,23835,23830,23842,23825,23849,23828,23833,23844,23847, +23831,24034,24120,24118,24115,24119,24247,24248,24246,24245,24254,24373,24375, +24407,24428,24425,24427,24471,24473,24478,24472,24481,24480,24476,24703,24739, +24713,24736,24744,24779,24756,24806,24765,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24773,24763,24757,24796,24764,24792,24789, +24774,24799,24760,24794,24775,25114,25115,25160,25504,25511,25458,25494,25506, +25509,25463,25447,25496,25514,25457,25513,25481,25475,25499,25451,25512,25476, +25480,25497,25505,25516,25490,25487,25472,25467,25449,25448,25466,25949,25942, +25937,25945,25943,21855,25935,25944,25941,25940,26012,26011,26028,26063,26059, +26060,26062,26205,26202,26212,26216,26214,26206,26361,21207,26395,26753,26799, +26786,26771,26805,26751,26742,26801,26791,26775,26800,26755,26820,26797,26758, +26757,26772,26781,26792,26783,26785,26754,27442,27578,27627,27628,27691,28046, +28092,28147,28121,28082,28129,28108,28132,28155,28154,28165,28103,28107,28079, +28113,28078,28126,28153,28088,28151,28149,28101,28114,28186,28085,28122,28139, +28120,28138,28145,28142,28136,28102,28100,28074,28140,28095,28134,28921,28937, +28938,28925,28911,29245,29309,29313,29468,29467,29462,29459,29465,29575,29701, +29706,29699,29702,29694,29709,29920,29942,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29943,29980,29986,30053,30054,30050,30064, +30095,30164,30165,30133,30154,30157,30350,30420,30418,30427,30519,30526,30524, +30518,30520,30522,30827,30787,30798,31077,31080,31085,31227,31378,31381,31520, +31528,31515,31532,31526,31513,31518,31534,31890,31895,31893,32070,32067,32113, +32046,32057,32060,32064,32048,32051,32068,32047,32066,32050,32049,32573,32670, +32666,32716,32718,32722,32796,32842,32838,33071,33046,33059,33067,33065,33072, +33060,33282,33333,33335,33334,33337,33678,33694,33688,33656,33698,33686,33725, +33707,33682,33674,33683,33673,33696,33655,33659,33660,33670,33703,34389,24426, +34503,34496,34486,34500,34485,34502,34507,34481,34479,34505,34899,34974,34952, +34987,34962,34966,34957,34955,35219,35215,35370,35357,35363,35365,35377,35373, +35359,35355,35362,35913,35930,36009,36012,36011,36008,36010,36007,36199,36198, +36286,36282,36571,36575,36889,36877,36890,36887,36899,36895,36893,36880,36885, +36894,36896,36879,36898,36886,36891,36884,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,37096,37101,37117,37207,37326,37365,37350, +37347,37351,37357,37353,38281,38506,38517,38515,38520,38512,38516,38518,38519, +38508,38592,38634,38633,31456,31455,38914,38915,39770,40165,40565,40575,40613, +40635,20642,20621,20613,20633,20625,20608,20630,20632,20634,26368,20977,21106, +21108,21109,21097,21214,21213,21211,21338,21413,21883,21888,21927,21884,21898, +21917,21912,21890,21916,21930,21908,21895,21899,21891,21939,21934,21919,21822, +21938,21914,21947,21932,21937,21886,21897,21931,21913,22285,22575,22570,22580, +22564,22576,22577,22561,22557,22560,22777,22778,22880,23159,23194,23167,23186, +23195,23207,23411,23409,23506,23500,23507,23504,23562,23563,23601,23884,23888, +23860,23879,24061,24133,24125,24128,24131,24190,24266,24257,24258,24260,24380, +24429,24489,24490,24488,24785,24801,24754,24758,24800,24860,24867,24826,24853, +24816,24827,24820,24936,24817,24846,24822,24841,24832,24850,25119,25161,25507, +25484,25551,25536,25577,25545,25542,25549,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25554,25571,25552,25569,25558,25581,25582, +25462,25588,25578,25563,25682,25562,25593,25950,25958,25954,25955,26001,26000, +26031,26222,26224,26228,26230,26223,26257,26234,26238,26231,26366,26367,26399, +26397,26874,26837,26848,26840,26839,26885,26847,26869,26862,26855,26873,26834, +26866,26851,26827,26829,26893,26898,26894,26825,26842,26990,26875,27454,27450, +27453,27544,27542,27580,27631,27694,27695,27692,28207,28216,28244,28193,28210, +28263,28234,28192,28197,28195,28187,28251,28248,28196,28246,28270,28205,28198, +28271,28212,28237,28218,28204,28227,28189,28222,28363,28297,28185,28238,28259, +28228,28274,28265,28255,28953,28954,28966,28976,28961,28982,29038,28956,29260, +29316,29312,29494,29477,29492,29481,29754,29738,29747,29730,29733,29749,29750, +29748,29743,29723,29734,29736,29989,29990,30059,30058,30178,30171,30179,30169, +30168,30174,30176,30331,30332,30358,30355,30388,30428,30543,30701,30813,30828, +30831,31245,31240,31243,31237,31232,31384,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31383,31382,31461,31459,31561,31574,31558, +31568,31570,31572,31565,31563,31567,31569,31903,31909,32094,32080,32104,32085, +32043,32110,32114,32097,32102,32098,32112,32115,21892,32724,32725,32779,32850, +32901,33109,33108,33099,33105,33102,33081,33094,33086,33100,33107,33140,33298, +33308,33769,33795,33784,33805,33760,33733,33803,33729,33775,33777,33780,33879, +33802,33776,33804,33740,33789,33778,33738,33848,33806,33796,33756,33799,33748, +33759,34395,34527,34521,34541,34516,34523,34532,34512,34526,34903,35009,35010, +34993,35203,35222,35387,35424,35413,35422,35388,35393,35412,35419,35408,35398, +35380,35386,35382,35414,35937,35970,36015,36028,36019,36029,36033,36027,36032, +36020,36023,36022,36031,36024,36234,36229,36225,36302,36317,36299,36314,36305, +36300,36315,36294,36603,36600,36604,36764,36910,36917,36913,36920,36914,36918, +37122,37109,37129,37118,37219,37221,37327,37396,37397,37411,37385,37406,37389, +37392,37383,37393,38292,38287,38283,38289,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38291,38290,38286,38538,38542,38539,38525, +38533,38534,38541,38514,38532,38593,38597,38596,38598,38599,38639,38642,38860, +38917,38918,38920,39143,39146,39151,39145,39154,39149,39342,39341,40643,40653, +40657,20098,20653,20661,20658,20659,20677,20670,20652,20663,20667,20655,20679, +21119,21111,21117,21215,21222,21220,21218,21219,21295,21983,21992,21971,21990, +21966,21980,21959,21969,21987,21988,21999,21978,21985,21957,21958,21989,21961, +22290,22291,22622,22609,22616,22615,22618,22612,22635,22604,22637,22602,22626, +22610,22603,22887,23233,23241,23244,23230,23229,23228,23219,23234,23218,23913, +23919,24140,24185,24265,24264,24338,24409,24492,24494,24858,24847,24904,24863, +24819,24859,24825,24833,24840,24910,24908,24900,24909,24894,24884,24871,24845, +24838,24887,25121,25122,25619,25662,25630,25642,25645,25661,25644,25615,25628, +25620,25613,25654,25622,25623,25606,25964,26015,26032,26263,26249,26247,26248, +26262,26244,26264,26253,26371,27028,26989,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,26970,26999,26976,26964,26997,26928,27010, +26954,26984,26987,26974,26963,27001,27014,26973,26979,26971,27463,27506,27584, +27583,27603,27645,28322,28335,28371,28342,28354,28304,28317,28359,28357,28325, +28312,28348,28346,28331,28369,28310,28316,28356,28372,28330,28327,28340,29006, +29017,29033,29028,29001,29031,29020,29036,29030,29004,29029,29022,28998,29032, +29014,29242,29266,29495,29509,29503,29502,29807,29786,29781,29791,29790,29761, +29759,29785,29787,29788,30070,30072,30208,30192,30209,30194,30193,30202,30207, +30196,30195,30430,30431,30555,30571,30566,30558,30563,30585,30570,30572,30556, +30565,30568,30562,30702,30862,30896,30871,30872,30860,30857,30844,30865,30867, +30847,31098,31103,31105,33836,31165,31260,31258,31264,31252,31263,31262,31391, +31392,31607,31680,31584,31598,31591,31921,31923,31925,32147,32121,32145,32129, +32143,32091,32622,32617,32618,32626,32681,32680,32676,32854,32856,32902,32900, +33137,33136,33144,33125,33134,33139,33131,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33145,33146,33126,33285,33351,33922,33911, +33853,33841,33909,33894,33899,33865,33900,33883,33852,33845,33889,33891,33897, +33901,33862,34398,34396,34399,34553,34579,34568,34567,34560,34558,34555,34562, +34563,34566,34570,34905,35039,35028,35033,35036,35032,35037,35041,35018,35029, +35026,35228,35299,35435,35442,35443,35430,35433,35440,35463,35452,35427,35488, +35441,35461,35437,35426,35438,35436,35449,35451,35390,35432,35938,35978,35977, +36042,36039,36040,36036,36018,36035,36034,36037,36321,36319,36328,36335,36339, +36346,36330,36324,36326,36530,36611,36617,36606,36618,36767,36786,36939,36938, +36947,36930,36948,36924,36949,36944,36935,36943,36942,36941,36945,36926,36929, +37138,37143,37228,37226,37225,37321,37431,37463,37432,37437,37440,37438,37467, +37451,37476,37457,37428,37449,37453,37445,37433,37439,37466,38296,38552,38548, +38549,38605,38603,38601,38602,38647,38651,38649,38646,38742,38772,38774,38928, +38929,38931,38922,38930,38924,39164,39156,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,39165,39166,39347,39345,39348,39649,40169, +40578,40718,40723,40736,20711,20718,20709,20694,20717,20698,20693,20687,20689, +20721,20686,20713,20834,20979,21123,21122,21297,21421,22014,22016,22043,22039, +22013,22036,22022,22025,22029,22030,22007,22038,22047,22024,22032,22006,22296, +22294,22645,22654,22659,22675,22666,22649,22661,22653,22781,22821,22818,22820, +22890,22889,23265,23270,23273,23255,23254,23256,23267,23413,23518,23527,23521, +23525,23526,23528,23522,23524,23519,23565,23650,23940,23943,24155,24163,24149, +24151,24148,24275,24278,24330,24390,24432,24505,24903,24895,24907,24951,24930, +24931,24927,24922,24920,24949,25130,25735,25688,25684,25764,25720,25695,25722, +25681,25703,25652,25709,25723,25970,26017,26071,26070,26274,26280,26269,27036, +27048,27029,27073,27054,27091,27083,27035,27063,27067,27051,27060,27088,27085, +27053,27084,27046,27075,27043,27465,27468,27699,28467,28436,28414,28435,28404, +28457,28478,28448,28460,28431,28418,28450,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28415,28399,28422,28465,28472,28466,28451, +28437,28459,28463,28552,28458,28396,28417,28402,28364,28407,29076,29081,29053, +29066,29060,29074,29246,29330,29334,29508,29520,29796,29795,29802,29808,29805, +29956,30097,30247,30221,30219,30217,30227,30433,30435,30596,30589,30591,30561, +30913,30879,30887,30899,30889,30883,31118,31119,31117,31278,31281,31402,31401, +31469,31471,31649,31637,31627,31605,31639,31645,31636,31631,31672,31623,31620, +31929,31933,31934,32187,32176,32156,32189,32190,32160,32202,32180,32178,32177, +32186,32162,32191,32181,32184,32173,32210,32199,32172,32624,32736,32737,32735, +32862,32858,32903,33104,33152,33167,33160,33162,33151,33154,33255,33274,33287, +33300,33310,33355,33993,33983,33990,33988,33945,33950,33970,33948,33995,33976, +33984,34003,33936,33980,34001,33994,34623,34588,34619,34594,34597,34612,34584, +34645,34615,34601,35059,35074,35060,35065,35064,35069,35048,35098,35055,35494, +35468,35486,35491,35469,35489,35475,35492,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,35498,35493,35496,35480,35473,35482,35495, +35946,35981,35980,36051,36049,36050,36203,36249,36245,36348,36628,36626,36629, +36627,36771,36960,36952,36956,36963,36953,36958,36962,36957,36955,37145,37144, +37150,37237,37240,37239,37236,37496,37504,37509,37528,37526,37499,37523,37532, +37544,37500,37521,38305,38312,38313,38307,38309,38308,38553,38556,38555,38604, +38610,38656,38780,38789,38902,38935,38936,39087,39089,39171,39173,39180,39177, +39361,39599,39600,39654,39745,39746,40180,40182,40179,40636,40763,40778,20740, +20736,20731,20725,20729,20738,20744,20745,20741,20956,21127,21128,21129,21133, +21130,21232,21426,22062,22075,22073,22066,22079,22068,22057,22099,22094,22103, +22132,22070,22063,22064,22656,22687,22686,22707,22684,22702,22697,22694,22893, +23305,23291,23307,23285,23308,23304,23534,23532,23529,23531,23652,23653,23965, +23956,24162,24159,24161,24290,24282,24287,24285,24291,24288,24392,24433,24503, +24501,24950,24935,24942,24925,24917,24962,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24956,24944,24939,24958,24999,24976,25003, +24974,25004,24986,24996,24980,25006,25134,25705,25711,25721,25758,25778,25736, +25744,25776,25765,25747,25749,25769,25746,25774,25773,25771,25754,25772,25753, +25762,25779,25973,25975,25976,26286,26283,26292,26289,27171,27167,27112,27137, +27166,27161,27133,27169,27155,27146,27123,27138,27141,27117,27153,27472,27470, +27556,27589,27590,28479,28540,28548,28497,28518,28500,28550,28525,28507,28536, +28526,28558,28538,28528,28516,28567,28504,28373,28527,28512,28511,29087,29100, +29105,29096,29270,29339,29518,29527,29801,29835,29827,29822,29824,30079,30240, +30249,30239,30244,30246,30241,30242,30362,30394,30436,30606,30599,30604,30609, +30603,30923,30917,30906,30922,30910,30933,30908,30928,31295,31292,31296,31293, +31287,31291,31407,31406,31661,31665,31684,31668,31686,31687,31681,31648,31692, +31946,32224,32244,32239,32251,32216,32236,32221,32232,32227,32218,32222,32233, +32158,32217,32242,32249,32629,32631,32687,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,32745,32806,33179,33180,33181,33184,33178, +33176,34071,34109,34074,34030,34092,34093,34067,34065,34083,34081,34068,34028, +34085,34047,34054,34690,34676,34678,34656,34662,34680,34664,34649,34647,34636, +34643,34907,34909,35088,35079,35090,35091,35093,35082,35516,35538,35527,35524, +35477,35531,35576,35506,35529,35522,35519,35504,35542,35533,35510,35513,35547, +35916,35918,35948,36064,36062,36070,36068,36076,36077,36066,36067,36060,36074, +36065,36205,36255,36259,36395,36368,36381,36386,36367,36393,36383,36385,36382, +36538,36637,36635,36639,36649,36646,36650,36636,36638,36645,36969,36974,36968, +36973,36983,37168,37165,37159,37169,37255,37257,37259,37251,37573,37563,37559, +37610,37548,37604,37569,37555,37564,37586,37575,37616,37554,38317,38321,38660, +38662,38663,38665,38752,38797,38795,38799,38945,38955,38940,39091,39178,39187, +39186,39192,39389,39376,39391,39387,39377,39381,39378,39385,39607,39662,39663, +39719,39749,39748,39799,39791,40198,40201,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40195,40617,40638,40654,22696,40786,20754, +20760,20756,20752,20757,20864,20906,20957,21137,21139,21235,22105,22123,22137, +22121,22116,22136,22122,22120,22117,22129,22127,22124,22114,22134,22721,22718, +22727,22725,22894,23325,23348,23416,23536,23566,24394,25010,24977,25001,24970, +25037,25014,25022,25034,25032,25136,25797,25793,25803,25787,25788,25818,25796, +25799,25794,25805,25791,25810,25812,25790,25972,26310,26313,26297,26308,26311, +26296,27197,27192,27194,27225,27243,27224,27193,27204,27234,27233,27211,27207, +27189,27231,27208,27481,27511,27653,28610,28593,28577,28611,28580,28609,28583, +28595,28608,28601,28598,28582,28576,28596,29118,29129,29136,29138,29128,29141, +29113,29134,29145,29148,29123,29124,29544,29852,29859,29848,29855,29854,29922, +29964,29965,30260,30264,30266,30439,30437,30624,30622,30623,30629,30952,30938, +30956,30951,31142,31309,31310,31302,31308,31307,31418,31705,31761,31689,31716, +31707,31713,31721,31718,31957,31958,32266,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,32273,32264,32283,32291,32286,32285,32265, +32272,32633,32690,32752,32753,32750,32808,33203,33193,33192,33275,33288,33368, +33369,34122,34137,34120,34152,34153,34115,34121,34157,34154,34142,34691,34719, +34718,34722,34701,34913,35114,35122,35109,35115,35105,35242,35238,35558,35578, +35563,35569,35584,35548,35559,35566,35582,35585,35586,35575,35565,35571,35574, +35580,35947,35949,35987,36084,36420,36401,36404,36418,36409,36405,36667,36655, +36664,36659,36776,36774,36981,36980,36984,36978,36988,36986,37172,37266,37664, +37686,37624,37683,37679,37666,37628,37675,37636,37658,37648,37670,37665,37653, +37678,37657,38331,38567,38568,38570,38613,38670,38673,38678,38669,38675,38671, +38747,38748,38758,38808,38960,38968,38971,38967,38957,38969,38948,39184,39208, +39198,39195,39201,39194,39405,39394,39409,39608,39612,39675,39661,39720,39825, +40213,40227,40230,40232,40210,40219,40664,40660,40845,40860,20778,20767,20769, +20786,21237,22158,22144,22160,22149,22151,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22159,22741,22739,22737,22734,23344,23338, +23332,23418,23607,23656,23996,23994,23997,23992,24171,24396,24509,25033,25026, +25031,25062,25035,25138,25140,25806,25802,25816,25824,25840,25830,25836,25841, +25826,25837,25986,25987,26329,26326,27264,27284,27268,27298,27292,27355,27299, +27262,27287,27280,27296,27484,27566,27610,27656,28632,28657,28639,28640,28635, +28644,28651,28655,28544,28652,28641,28649,28629,28654,28656,29159,29151,29166, +29158,29157,29165,29164,29172,29152,29237,29254,29552,29554,29865,29872,29862, +29864,30278,30274,30284,30442,30643,30634,30640,30636,30631,30637,30703,30967, +30970,30964,30959,30977,31143,31146,31319,31423,31751,31757,31742,31735,31756, +31712,31968,31964,31966,31970,31967,31961,31965,32302,32318,32326,32311,32306, +32323,32299,32317,32305,32325,32321,32308,32313,32328,32309,32319,32303,32580, +32755,32764,32881,32882,32880,32879,32883,33222,33219,33210,33218,33216,33215, +33213,33225,33214,33256,33289,33393,34218,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34180,34174,34204,34193,34196,34223,34203, +34183,34216,34186,34407,34752,34769,34739,34770,34758,34731,34747,34746,34760, +34763,35131,35126,35140,35128,35133,35244,35598,35607,35609,35611,35594,35616, +35613,35588,35600,35905,35903,35955,36090,36093,36092,36088,36091,36264,36425, +36427,36424,36426,36676,36670,36674,36677,36671,36991,36989,36996,36993,36994, +36992,37177,37283,37278,37276,37709,37762,37672,37749,37706,37733,37707,37656, +37758,37740,37723,37744,37722,37716,38346,38347,38348,38344,38342,38577,38584, +38614,38684,38686,38816,38867,38982,39094,39221,39425,39423,39854,39851,39850, +39853,40251,40255,40587,40655,40670,40668,40669,40667,40766,40779,21474,22165, +22190,22745,22744,23352,24413,25059,25139,25844,25842,25854,25862,25850,25851, +25847,26039,26332,26406,27315,27308,27331,27323,27320,27330,27310,27311,27487, +27512,27567,28681,28683,28670,28678,28666,28689,28687,29179,29180,29182,29176, +29559,29557,29863,29887,29973,30294,30296,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30290,30653,30655,30651,30652,30990,31150, +31329,31330,31328,31428,31429,31787,31783,31786,31774,31779,31777,31975,32340, +32341,32350,32346,32353,32338,32345,32584,32761,32763,32887,32886,33229,33231, +33290,34255,34217,34253,34256,34249,34224,34234,34233,34214,34799,34796,34802, +34784,35206,35250,35316,35624,35641,35628,35627,35920,36101,36441,36451,36454, +36452,36447,36437,36544,36681,36685,36999,36995,37000,37291,37292,37328,37780, +37770,37782,37794,37811,37806,37804,37808,37784,37786,37783,38356,38358,38352, +38357,38626,38620,38617,38619,38622,38692,38819,38822,38829,38905,38989,38991, +38988,38990,38995,39098,39230,39231,39229,39214,39333,39438,39617,39683,39686, +39759,39758,39757,39882,39881,39933,39880,39872,40273,40285,40288,40672,40725, +40748,20787,22181,22750,22751,22754,23541,40848,24300,25074,25079,25078,25077, +25856,25871,26336,26333,27365,27357,27354,27347,28699,28703,28712,28698,28701, +28693,28696,29190,29197,29272,29346,29560,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29562,29885,29898,29923,30087,30086,30303, +30305,30663,31001,31153,31339,31337,31806,31807,31800,31805,31799,31808,32363, +32365,32377,32361,32362,32645,32371,32694,32697,32696,33240,34281,34269,34282, +34261,34276,34277,34295,34811,34821,34829,34809,34814,35168,35167,35158,35166, +35649,35676,35672,35657,35674,35662,35663,35654,35673,36104,36106,36476,36466, +36487,36470,36460,36474,36468,36692,36686,36781,37002,37003,37297,37294,37857, +37841,37855,37827,37832,37852,37853,37846,37858,37837,37848,37860,37847,37864, +38364,38580,38627,38698,38695,38753,38876,38907,39006,39000,39003,39100,39237, +39241,39446,39449,39693,39912,39911,39894,39899,40329,40289,40306,40298,40300, +40594,40599,40595,40628,21240,22184,22199,22198,22196,22204,22756,23360,23363, +23421,23542,24009,25080,25082,25880,25876,25881,26342,26407,27372,28734,28720, +28722,29200,29563,29903,30306,30309,31014,31018,31020,31019,31431,31478,31820, +31811,31821,31983,31984,36782,32381,32380,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,32386,32588,32768,33242,33382,34299,34297, +34321,34298,34310,34315,34311,34314,34836,34837,35172,35258,35320,35696,35692, +35686,35695,35679,35691,36111,36109,36489,36481,36485,36482,37300,37323,37912, +37891,37885,38369,38704,39108,39250,39249,39336,39467,39472,39479,39477,39955, +39949,40569,40629,40680,40751,40799,40803,40801,20791,20792,22209,22208,22210, +22804,23660,24013,25084,25086,25885,25884,26005,26345,27387,27396,27386,27570, +28748,29211,29351,29910,29908,30313,30675,31824,32399,32396,32700,34327,34349, +34330,34851,34850,34849,34847,35178,35180,35261,35700,35703,35709,36115,36490, +36493,36491,36703,36783,37306,37934,37939,37941,37946,37944,37938,37931,38370, +38712,38713,38706,38911,39015,39013,39255,39493,39491,39488,39486,39631,39764, +39761,39981,39973,40367,40372,40386,40376,40605,40687,40729,40796,40806,40807, +20796,20795,22216,22218,22217,23423,24020,24018,24398,25087,25892,27402,27489, +28753,28760,29568,29924,30090,30318,30316,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31155,31840,31839,32894,32893,33247,35186, +35183,35324,35712,36118,36119,36497,36499,36705,37192,37956,37969,37970,38717, +38718,38851,38849,39019,39253,39509,39501,39634,39706,40009,39985,39998,39995, +40403,40407,40756,40812,40810,40852,22220,24022,25088,25891,25899,25898,26348, +27408,29914,31434,31844,31843,31845,32403,32406,32404,33250,34360,34367,34865, +35722,37008,37007,37987,37984,37988,38760,39023,39260,39514,39515,39511,39635, +39636,39633,40020,40023,40022,40421,40607,40692,22225,22761,25900,28766,30321, +30322,30679,32592,32648,34870,34873,34914,35731,35730,35734,33399,36123,37312, +37994,38722,38728,38724,38854,39024,39519,39714,39768,40031,40441,40442,40572, +40573,40711,40823,40818,24307,27414,28771,31852,31854,34875,35264,36513,37313, +38002,38000,39025,39262,39638,39715,40652,28772,30682,35738,38007,38857,39522, +39525,32412,35740,36522,37317,38013,38014,38012,40055,40056,40695,35924,38015, +40474,29224,39530,39729,40475,40478,31858,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12542,12445,12446,12293,12353,12354,12355, +12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368, +12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381, +12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394, +12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407, +12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420, +12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433, +12434,12435,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459, +12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472, +12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485, +12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498, +12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511, +12512,12513,12514,12515,12516,12517,12518,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12519,12520,12521,12522,12523,12524,12525, +12526,12527,12528,12529,12530,12531,12532,12533,12534,1044,1045,1025,1046, +1047,1048,1049,1050,1051,1052,1059,1060,1061,1062,1063,1064,1065,1066,1067, +1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081, +1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096, +1097,1098,1099,1100,1101,1102,1103,9312,9313,9314,9315,9316,9317,9318,9319, +9320,9321,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,20034,20060,20981, +21274,21378,19975,19980,20039,20109,22231,64012,23662,24435,19983,20871,19982, +20014,20115,20162,20169,20168,20888,21244,21356,21433,22304,22787,22828,23568, +24063,26081,27571,27596,27668,29247,20017,20028,20200,20188,20201,20193,20189, +20186,21004,21276,21324,22306,22307,22807,22831,23425,23428,23570,23611,23668, +23667,24068,24192,24194,24521,25097,25168,27669,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,27702,27715,27711,27707,29358,29360, +29578,31160,32906,38430,20238,20248,20268,20213,20244,20209,20224,20215,20232, +20253,20226,20229,20258,20243,20228,20212,20242,20913,21011,21001,21008,21158, +21282,21279,21325,21386,21511,22241,22239,22318,22314,22324,22844,22912,22908, +22917,22907,22910,22903,22911,23382,23573,23589,23676,23674,23675,23678,24031, +24181,24196,24322,24346,24436,24533,24532,24527,25180,25182,25188,25185,25190, +25186,25177,25184,25178,25189,26095,26094,26430,26425,26424,26427,26426,26431, +26428,26419,27672,27718,27730,27740,27727,27722,27732,27723,27724,28785,29278, +29364,29365,29582,29994,30335,31349,32593,33400,33404,33408,33405,33407,34381, +35198,37017,37015,37016,37019,37012,38434,38436,38432,38435,20310,20283,20322, +20297,20307,20324,20286,20327,20306,20319,20289,20312,20269,20275,20287,20321, +20879,20921,21020,21022,21025,21165,21166,21257,21347,21362,21390,21391,21552, +21559,21546,21588,21573,21529,21532,21541,21528,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,21565,21583,21569,21544,21540,21575, +22254,22247,22245,22337,22341,22348,22345,22347,22354,22790,22848,22950,22936, +22944,22935,22926,22946,22928,22927,22951,22945,23438,23442,23592,23594,23693, +23695,23688,23691,23689,23698,23690,23686,23699,23701,24032,24074,24078,24203, +24201,24204,24200,24205,24325,24349,24440,24438,24530,24529,24528,24557,24552, +24558,24563,24545,24548,24547,24570,24559,24567,24571,24576,24564,25146,25219, +25228,25230,25231,25236,25223,25201,25211,25210,25200,25217,25224,25207,25213, +25202,25204,25911,26096,26100,26099,26098,26101,26437,26439,26457,26453,26444, +26440,26461,26445,26458,26443,27600,27673,27674,27768,27751,27755,27780,27787, +27791,27761,27759,27753,27802,27757,27783,27797,27804,27750,27763,27749,27771, +27790,28788,28794,29283,29375,29373,29379,29382,29377,29370,29381,29589,29591, +29587,29588,29586,30010,30009,30100,30101,30337,31037,32820,32917,32921,32912, +32914,32924,33424,33423,33413,33422,33425,33427,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33418,33411,33412,35960,36809,36799, +37023,37025,37029,37022,37031,37024,38448,38440,38447,38445,20019,20376,20348, +20357,20349,20352,20359,20342,20340,20361,20356,20343,20300,20375,20330,20378, +20345,20353,20344,20368,20380,20372,20382,20370,20354,20373,20331,20334,20894, +20924,20926,21045,21042,21043,21062,21041,21180,21258,21259,21308,21394,21396, +21639,21631,21633,21649,21634,21640,21611,21626,21630,21605,21612,21620,21606, +21645,21615,21601,21600,21656,21603,21607,21604,22263,22265,22383,22386,22381, +22379,22385,22384,22390,22400,22389,22395,22387,22388,22370,22376,22397,22796, +22853,22965,22970,22991,22990,22962,22988,22977,22966,22972,22979,22998,22961, +22973,22976,22984,22964,22983,23394,23397,23443,23445,23620,23623,23726,23716, +23712,23733,23727,23720,23724,23711,23715,23725,23714,23722,23719,23709,23717, +23734,23728,23718,24087,24084,24089,24360,24354,24355,24356,24404,24450,24446, +24445,24542,24549,24621,24614,24601,24626,24587,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24628,24586,24599,24627,24602,24606, +24620,24610,24589,24592,24622,24595,24593,24588,24585,24604,25108,25149,25261, +25268,25297,25278,25258,25270,25290,25262,25267,25263,25275,25257,25264,25272, +25917,26024,26043,26121,26108,26116,26130,26120,26107,26115,26123,26125,26117, +26109,26129,26128,26358,26378,26501,26476,26510,26514,26486,26491,26520,26502, +26500,26484,26509,26508,26490,26527,26513,26521,26499,26493,26497,26488,26489, +26516,27429,27520,27518,27614,27677,27795,27884,27883,27886,27865,27830,27860, +27821,27879,27831,27856,27842,27834,27843,27846,27885,27890,27858,27869,27828, +27786,27805,27776,27870,27840,27952,27853,27847,27824,27897,27855,27881,27857, +28820,28824,28805,28819,28806,28804,28817,28822,28802,28826,28803,29290,29398, +29387,29400,29385,29404,29394,29396,29402,29388,29393,29604,29601,29613,29606, +29602,29600,29612,29597,29917,29928,30015,30016,30014,30092,30104,30383,30451, +30449,30448,30453,30712,30716,30713,30715,30714,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30711,31042,31039,31173,31352,31355, +31483,31861,31997,32821,32911,32942,32931,32952,32949,32941,33312,33440,33472, +33451,33434,33432,33435,33461,33447,33454,33468,33438,33466,33460,33448,33441, +33449,33474,33444,33475,33462,33442,34416,34415,34413,34414,35926,36818,36811, +36819,36813,36822,36821,36823,37042,37044,37039,37043,37040,38457,38461,38460, +38458,38467,20429,20421,20435,20402,20425,20427,20417,20436,20444,20441,20411, +20403,20443,20423,20438,20410,20416,20409,20460,21060,21065,21184,21186,21309, +21372,21399,21398,21401,21400,21690,21665,21677,21669,21711,21699,33549,21687, +21678,21718,21686,21701,21702,21664,21616,21692,21666,21694,21618,21726,21680, +22453,22430,22431,22436,22412,22423,22429,22427,22420,22424,22415,22425,22437, +22426,22421,22772,22797,22867,23009,23006,23022,23040,23025,23005,23034,23037, +23036,23030,23012,23026,23031,23003,23017,23027,23029,23008,23038,23028,23021, +23464,23628,23760,23768,23756,23767,23755,23771,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23774,23770,23753,23751,23754,23766, +23763,23764,23759,23752,23750,23758,23775,23800,24057,24097,24098,24099,24096, +24100,24240,24228,24226,24219,24227,24229,24327,24366,24406,24454,24631,24633, +24660,24690,24670,24645,24659,24647,24649,24667,24652,24640,24642,24671,24612, +24644,24664,24678,24686,25154,25155,25295,25357,25355,25333,25358,25347,25323, +25337,25359,25356,25336,25334,25344,25363,25364,25338,25365,25339,25328,25921, +25923,26026,26047,26166,26145,26162,26165,26140,26150,26146,26163,26155,26170, +26141,26164,26169,26158,26383,26384,26561,26610,26568,26554,26588,26555,26616, +26584,26560,26551,26565,26603,26596,26591,26549,26573,26547,26615,26614,26606, +26595,26562,26553,26574,26599,26608,26546,26620,26566,26605,26572,26542,26598, +26587,26618,26569,26570,26563,26602,26571,27432,27522,27524,27574,27606,27608, +27616,27680,27681,27944,27956,27949,27935,27964,27967,27922,27914,27866,27955, +27908,27929,27962,27930,27921,27904,27933,27970,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,27905,27928,27959,27907,27919,27968, +27911,27936,27948,27912,27938,27913,27920,28855,28831,28862,28849,28848,28833, +28852,28853,28841,29249,29257,29258,29292,29296,29299,29294,29386,29412,29416, +29419,29407,29418,29414,29411,29573,29644,29634,29640,29637,29625,29622,29621, +29620,29675,29631,29639,29630,29635,29638,29624,29643,29932,29934,29998,30023, +30024,30119,30122,30329,30404,30472,30467,30468,30469,30474,30455,30459,30458, +30695,30696,30726,30737,30738,30725,30736,30735,30734,30729,30723,30739,31050, +31052,31051,31045,31044,31189,31181,31183,31190,31182,31360,31358,31441,31488, +31489,31866,31864,31865,31871,31872,31873,32003,32008,32001,32600,32657,32653, +32702,32775,32782,32783,32788,32823,32984,32967,32992,32977,32968,32962,32976, +32965,32995,32985,32988,32970,32981,32969,32975,32983,32998,32973,33279,33313, +33428,33497,33534,33529,33543,33512,33536,33493,33594,33515,33494,33524,33516, +33505,33522,33525,33548,33531,33526,33520,33514,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33508,33504,33530,33523,33517,34423, +34420,34428,34419,34881,34894,34919,34922,34921,35283,35332,35335,36210,36835, +36833,36846,36832,37105,37053,37055,37077,37061,37054,37063,37067,37064,37332, +37331,38484,38479,38481,38483,38474,38478,20510,20485,20487,20499,20514,20528, +20507,20469,20468,20531,20535,20524,20470,20471,20503,20508,20512,20519,20533, +20527,20529,20494,20826,20884,20883,20938,20932,20933,20936,20942,21089,21082, +21074,21086,21087,21077,21090,21197,21262,21406,21798,21730,21783,21778,21735, +21747,21732,21786,21759,21764,21768,21739,21777,21765,21745,21770,21755,21751, +21752,21728,21774,21763,21771,22273,22274,22476,22578,22485,22482,22458,22470, +22461,22460,22456,22454,22463,22471,22480,22457,22465,22798,22858,23065,23062, +23085,23086,23061,23055,23063,23050,23070,23091,23404,23463,23469,23468,23555, +23638,23636,23788,23807,23790,23793,23799,23808,23801,24105,24104,24232,24238, +24234,24236,24371,24368,24423,24669,24666,24679,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24641,24738,24712,24704,24722,24705, +24733,24707,24725,24731,24727,24711,24732,24718,25113,25158,25330,25360,25430, +25388,25412,25413,25398,25411,25572,25401,25419,25418,25404,25385,25409,25396, +25432,25428,25433,25389,25415,25395,25434,25425,25400,25431,25408,25416,25930, +25926,26054,26051,26052,26050,26186,26207,26183,26193,26386,26387,26655,26650, +26697,26674,26675,26683,26699,26703,26646,26673,26652,26677,26667,26669,26671, +26702,26692,26676,26653,26642,26644,26662,26664,26670,26701,26682,26661,26656, +27436,27439,27437,27441,27444,27501,32898,27528,27622,27620,27624,27619,27618, +27623,27685,28026,28003,28004,28022,27917,28001,28050,27992,28002,28013,28015, +28049,28045,28143,28031,28038,27998,28007,28000,28055,28016,28028,27999,28034, +28056,27951,28008,28043,28030,28032,28036,27926,28035,28027,28029,28021,28048, +28892,28883,28881,28893,28875,32569,28898,28887,28882,28894,28896,28884,28877, +28869,28870,28871,28890,28878,28897,29250,29304,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29303,29302,29440,29434,29428,29438, +29430,29427,29435,29441,29651,29657,29669,29654,29628,29671,29667,29673,29660, +29650,29659,29652,29661,29658,29655,29656,29672,29918,29919,29940,29941,29985, +30043,30047,30128,30145,30139,30148,30144,30143,30134,30138,30346,30409,30493, +30491,30480,30483,30482,30499,30481,30485,30489,30490,30498,30503,30755,30764, +30754,30773,30767,30760,30766,30763,30753,30761,30771,30762,30769,31060,31067, +31055,31068,31059,31058,31057,31211,31212,31200,31214,31213,31210,31196,31198, +31197,31366,31369,31365,31371,31372,31370,31367,31448,31504,31492,31507,31493, +31503,31496,31498,31502,31497,31506,31876,31889,31882,31884,31880,31885,31877, +32030,32029,32017,32014,32024,32022,32019,32031,32018,32015,32012,32604,32609, +32606,32608,32605,32603,32662,32658,32707,32706,32704,32790,32830,32825,33018, +33010,33017,33013,33025,33019,33024,33281,33327,33317,33587,33581,33604,33561, +33617,33573,33622,33599,33601,33574,33564,33570,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33602,33614,33563,33578,33544,33596, +33613,33558,33572,33568,33591,33583,33577,33607,33605,33612,33619,33566,33580, +33611,33575,33608,34387,34386,34466,34472,34454,34445,34449,34462,34439,34455, +34438,34443,34458,34437,34469,34457,34465,34471,34453,34456,34446,34461,34448, +34452,34883,34884,34925,34933,34934,34930,34944,34929,34943,34927,34947,34942, +34932,34940,35346,35911,35927,35963,36004,36003,36214,36216,36277,36279,36278, +36561,36563,36862,36853,36866,36863,36859,36868,36860,36854,37078,37088,37081, +37082,37091,37087,37093,37080,37083,37079,37084,37092,37200,37198,37199,37333, +37346,37338,38492,38495,38588,39139,39647,39727,20095,20592,20586,20577,20574, +20576,20563,20555,20573,20594,20552,20557,20545,20571,20554,20578,20501,20549, +20575,20585,20587,20579,20580,20550,20544,20590,20595,20567,20561,20944,21099, +21101,21100,21102,21206,21203,21293,21404,21877,21878,21820,21837,21840,21812, +21802,21841,21858,21814,21813,21808,21842,21829,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,21772,21810,21861,21838,21817,21832, +21805,21819,21824,21835,22282,22279,22523,22548,22498,22518,22492,22516,22528, +22509,22525,22536,22520,22539,22515,22479,22535,22510,22499,22514,22501,22508, +22497,22542,22524,22544,22503,22529,22540,22513,22505,22512,22541,22532,22876, +23136,23128,23125,23143,23134,23096,23093,23149,23120,23135,23141,23148,23123, +23140,23127,23107,23133,23122,23108,23131,23112,23182,23102,23117,23097,23116, +23152,23145,23111,23121,23126,23106,23132,23410,23406,23489,23488,23641,23838, +23819,23837,23834,23840,23820,23848,23821,23846,23845,23823,23856,23826,23843, +23839,23854,24126,24116,24241,24244,24249,24242,24243,24374,24376,24475,24470, +24479,24714,24720,24710,24766,24752,24762,24787,24788,24783,24804,24793,24797, +24776,24753,24795,24759,24778,24767,24771,24781,24768,25394,25445,25482,25474, +25469,25533,25502,25517,25501,25495,25515,25486,25455,25479,25488,25454,25519, +25461,25500,25453,25518,25468,25508,25403,25503,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25464,25477,25473,25489,25485,25456, +25939,26061,26213,26209,26203,26201,26204,26210,26392,26745,26759,26768,26780, +26733,26734,26798,26795,26966,26735,26787,26796,26793,26741,26740,26802,26767, +26743,26770,26748,26731,26738,26794,26752,26737,26750,26779,26774,26763,26784, +26761,26788,26744,26747,26769,26764,26762,26749,27446,27443,27447,27448,27537, +27535,27533,27534,27532,27690,28096,28075,28084,28083,28276,28076,28137,28130, +28087,28150,28116,28160,28104,28128,28127,28118,28094,28133,28124,28125,28123, +28148,28106,28093,28141,28144,28090,28117,28098,28111,28105,28112,28146,28115, +28157,28119,28109,28131,28091,28922,28941,28919,28951,28916,28940,28912,28932, +28915,28944,28924,28927,28934,28947,28928,28920,28918,28939,28930,28942,29310, +29307,29308,29311,29469,29463,29447,29457,29464,29450,29448,29439,29455,29470, +29576,29686,29688,29685,29700,29697,29693,29703,29696,29690,29692,29695,29708, +29707,29684,29704,30052,30051,30158,30162,30159,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30155,30156,30161,30160,30351,30345, +30419,30521,30511,30509,30513,30514,30516,30515,30525,30501,30523,30517,30792, +30802,30793,30797,30794,30796,30758,30789,30800,31076,31079,31081,31082,31075, +31083,31073,31163,31226,31224,31222,31223,31375,31380,31376,31541,31559,31540, +31525,31536,31522,31524,31539,31512,31530,31517,31537,31531,31533,31535,31538, +31544,31514,31523,31892,31896,31894,31907,32053,32061,32056,32054,32058,32069, +32044,32041,32065,32071,32062,32063,32074,32059,32040,32611,32661,32668,32669, +32667,32714,32715,32717,32720,32721,32711,32719,32713,32799,32798,32795,32839, +32835,32840,33048,33061,33049,33051,33069,33055,33068,33054,33057,33045,33063, +33053,33058,33297,33336,33331,33338,33332,33330,33396,33680,33699,33704,33677, +33658,33651,33700,33652,33679,33665,33685,33689,33653,33684,33705,33661,33667, +33676,33693,33691,33706,33675,33662,33701,33711,33672,33687,33712,33663,33702, +33671,33710,33654,33690,34393,34390,34495,34487,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34498,34497,34501,34490,34480,34504, +34489,34483,34488,34508,34484,34491,34492,34499,34493,34494,34898,34953,34965, +34984,34978,34986,34970,34961,34977,34975,34968,34983,34969,34971,34967,34980, +34988,34956,34963,34958,35202,35286,35289,35285,35376,35367,35372,35358,35897, +35899,35932,35933,35965,36005,36221,36219,36217,36284,36290,36281,36287,36289, +36568,36574,36573,36572,36567,36576,36577,36900,36875,36881,36892,36876,36897, +37103,37098,37104,37108,37106,37107,37076,37099,37100,37097,37206,37208,37210, +37203,37205,37356,37364,37361,37363,37368,37348,37369,37354,37355,37367,37352, +37358,38266,38278,38280,38524,38509,38507,38513,38511,38591,38762,38916,39141, +39319,20635,20629,20628,20638,20619,20643,20611,20620,20622,20637,20584,20636, +20626,20610,20615,20831,20948,21266,21265,21412,21415,21905,21928,21925,21933, +21879,22085,21922,21907,21896,21903,21941,21889,21923,21906,21924,21885,21900, +21926,21887,21909,21921,21902,22284,22569,22583,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22553,22558,22567,22563,22568,22517, +22600,22565,22556,22555,22579,22591,22582,22574,22585,22584,22573,22572,22587, +22881,23215,23188,23199,23162,23202,23198,23160,23206,23164,23205,23212,23189, +23214,23095,23172,23178,23191,23171,23179,23209,23163,23165,23180,23196,23183, +23187,23197,23530,23501,23499,23508,23505,23498,23502,23564,23600,23863,23875, +23915,23873,23883,23871,23861,23889,23886,23893,23859,23866,23890,23869,23857, +23897,23874,23865,23881,23864,23868,23858,23862,23872,23877,24132,24129,24408, +24486,24485,24491,24777,24761,24780,24802,24782,24772,24852,24818,24842,24854, +24837,24821,24851,24824,24828,24830,24769,24835,24856,24861,24848,24831,24836, +24843,25162,25492,25521,25520,25550,25573,25576,25583,25539,25757,25587,25546, +25568,25590,25557,25586,25589,25697,25567,25534,25565,25564,25540,25560,25555, +25538,25543,25548,25547,25544,25584,25559,25561,25906,25959,25962,25956,25948, +25960,25957,25996,26013,26014,26030,26064,26066,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,26236,26220,26235,26240,26225,26233, +26218,26226,26369,26892,26835,26884,26844,26922,26860,26858,26865,26895,26838, +26871,26859,26852,26870,26899,26896,26867,26849,26887,26828,26888,26992,26804, +26897,26863,26822,26900,26872,26832,26877,26876,26856,26891,26890,26903,26830, +26824,26845,26846,26854,26868,26833,26886,26836,26857,26901,26917,26823,27449, +27451,27455,27452,27540,27543,27545,27541,27581,27632,27634,27635,27696,28156, +28230,28231,28191,28233,28296,28220,28221,28229,28258,28203,28223,28225,28253, +28275,28188,28211,28235,28224,28241,28219,28163,28206,28254,28264,28252,28257, +28209,28200,28256,28273,28267,28217,28194,28208,28243,28261,28199,28280,28260, +28279,28245,28281,28242,28262,28213,28214,28250,28960,28958,28975,28923,28974, +28977,28963,28965,28962,28978,28959,28968,28986,28955,29259,29274,29320,29321, +29318,29317,29323,29458,29451,29488,29474,29489,29491,29479,29490,29485,29478, +29475,29493,29452,29742,29740,29744,29739,29718,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29722,29729,29741,29745,29732,29731, +29725,29737,29728,29746,29947,29999,30063,30060,30183,30170,30177,30182,30173, +30175,30180,30167,30357,30354,30426,30534,30535,30532,30541,30533,30538,30542, +30539,30540,30686,30700,30816,30820,30821,30812,30829,30833,30826,30830,30832, +30825,30824,30814,30818,31092,31091,31090,31088,31234,31242,31235,31244,31236, +31385,31462,31460,31562,31547,31556,31560,31564,31566,31552,31576,31557,31906, +31902,31912,31905,32088,32111,32099,32083,32086,32103,32106,32079,32109,32092, +32107,32082,32084,32105,32081,32095,32078,32574,32575,32613,32614,32674,32672, +32673,32727,32849,32847,32848,33022,32980,33091,33098,33106,33103,33095,33085, +33101,33082,33254,33262,33271,33272,33273,33284,33340,33341,33343,33397,33595, +33743,33785,33827,33728,33768,33810,33767,33764,33788,33782,33808,33734,33736, +33771,33763,33727,33793,33757,33765,33752,33791,33761,33739,33742,33750,33781, +33737,33801,33807,33758,33809,33798,33730,33779,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33749,33786,33735,33745,33770,33811, +33731,33772,33774,33732,33787,33751,33762,33819,33755,33790,34520,34530,34534, +34515,34531,34522,34538,34525,34539,34524,34540,34537,34519,34536,34513,34888, +34902,34901,35002,35031,35001,35000,35008,35006,34998,35004,34999,35005,34994, +35073,35017,35221,35224,35223,35293,35290,35291,35406,35405,35385,35417,35392, +35415,35416,35396,35397,35410,35400,35409,35402,35404,35407,35935,35969,35968, +36026,36030,36016,36025,36021,36228,36224,36233,36312,36307,36301,36295,36310, +36316,36303,36309,36313,36296,36311,36293,36591,36599,36602,36601,36582,36590, +36581,36597,36583,36584,36598,36587,36593,36588,36596,36585,36909,36916,36911, +37126,37164,37124,37119,37116,37128,37113,37115,37121,37120,37127,37125,37123, +37217,37220,37215,37218,37216,37377,37386,37413,37379,37402,37414,37391,37388, +37376,37394,37375,37373,37382,37380,37415,37378,37404,37412,37401,37399,37381, +37398,38267,38285,38284,38288,38535,38526,38536,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38537,38531,38528,38594,38600,38595, +38641,38640,38764,38768,38766,38919,39081,39147,40166,40697,20099,20100,20150, +20669,20671,20678,20654,20676,20682,20660,20680,20674,20656,20673,20666,20657, +20683,20681,20662,20664,20951,21114,21112,21115,21116,21955,21979,21964,21968, +21963,21962,21981,21952,21972,21956,21993,21951,21970,21901,21967,21973,21986, +21974,21960,22002,21965,21977,21954,22292,22611,22632,22628,22607,22605,22601, +22639,22613,22606,22621,22617,22629,22619,22589,22627,22641,22780,23239,23236, +23243,23226,23224,23217,23221,23216,23231,23240,23227,23238,23223,23232,23242, +23220,23222,23245,23225,23184,23510,23512,23513,23583,23603,23921,23907,23882, +23909,23922,23916,23902,23912,23911,23906,24048,24143,24142,24138,24141,24139, +24261,24268,24262,24267,24263,24384,24495,24493,24823,24905,24906,24875,24901, +24886,24882,24878,24902,24879,24911,24873,24896,25120,37224,25123,25125,25124, +25541,25585,25579,25616,25618,25609,25632,25636,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25651,25667,25631,25621,25624,25657, +25655,25634,25635,25612,25638,25648,25640,25665,25653,25647,25610,25626,25664, +25637,25639,25611,25575,25627,25646,25633,25614,25967,26002,26067,26246,26252, +26261,26256,26251,26250,26265,26260,26232,26400,26982,26975,26936,26958,26978, +26993,26943,26949,26986,26937,26946,26967,26969,27002,26952,26953,26933,26988, +26931,26941,26981,26864,27000,26932,26985,26944,26991,26948,26998,26968,26945, +26996,26956,26939,26955,26935,26972,26959,26961,26930,26962,26927,27003,26940, +27462,27461,27459,27458,27464,27457,27547,64013,27643,27644,27641,27639,27640, +28315,28374,28360,28303,28352,28319,28307,28308,28320,28337,28345,28358,28370, +28349,28353,28318,28361,28343,28336,28365,28326,28367,28338,28350,28355,28380, +28376,28313,28306,28302,28301,28324,28321,28351,28339,28368,28362,28311,28334, +28323,28999,29012,29010,29027,29024,28993,29021,29026,29042,29048,29034,29025, +28994,29016,28995,29003,29040,29023,29008,29011,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28996,29005,29018,29263,29325,29324, +29329,29328,29326,29500,29506,29499,29498,29504,29514,29513,29764,29770,29771, +29778,29777,29783,29760,29775,29776,29774,29762,29766,29773,29780,29921,29951, +29950,29949,29981,30073,30071,27011,30191,30223,30211,30199,30206,30204,30201, +30200,30224,30203,30198,30189,30197,30205,30361,30389,30429,30549,30559,30560, +30546,30550,30554,30569,30567,30548,30553,30573,30688,30855,30874,30868,30863, +30852,30869,30853,30854,30881,30851,30841,30873,30848,30870,30843,31100,31106, +31101,31097,31249,31256,31257,31250,31255,31253,31266,31251,31259,31248,31395, +31394,31390,31467,31590,31588,31597,31604,31593,31602,31589,31603,31601,31600, +31585,31608,31606,31587,31922,31924,31919,32136,32134,32128,32141,32127,32133, +32122,32142,32123,32131,32124,32140,32148,32132,32125,32146,32621,32619,32615, +32616,32620,32678,32677,32679,32731,32732,32801,33124,33120,33143,33116,33129, +33115,33122,33138,26401,33118,33142,33127,33135,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33092,33121,33309,33353,33348,33344, +33346,33349,34033,33855,33878,33910,33913,33935,33933,33893,33873,33856,33926, +33895,33840,33869,33917,33882,33881,33908,33907,33885,34055,33886,33847,33850, +33844,33914,33859,33912,33842,33861,33833,33753,33867,33839,33858,33837,33887, +33904,33849,33870,33868,33874,33903,33989,33934,33851,33863,33846,33843,33896, +33918,33860,33835,33888,33876,33902,33872,34571,34564,34551,34572,34554,34518, +34549,34637,34552,34574,34569,34561,34550,34573,34565,35030,35019,35021,35022, +35038,35035,35034,35020,35024,35205,35227,35295,35301,35300,35297,35296,35298, +35292,35302,35446,35462,35455,35425,35391,35447,35458,35460,35445,35459,35457, +35444,35450,35900,35915,35914,35941,35940,35942,35974,35972,35973,36044,36200, +36201,36241,36236,36238,36239,36237,36243,36244,36240,36242,36336,36320,36332, +36337,36334,36304,36329,36323,36322,36327,36338,36331,36340,36614,36607,36609, +36608,36613,36615,36616,36610,36619,36946,36927,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,36932,36937,36925,37136,37133,37135, +37137,37142,37140,37131,37134,37230,37231,37448,37458,37424,37434,37478,37427, +37477,37470,37507,37422,37450,37446,37485,37484,37455,37472,37479,37487,37430, +37473,37488,37425,37460,37475,37456,37490,37454,37459,37452,37462,37426,38303, +38300,38302,38299,38546,38547,38545,38551,38606,38650,38653,38648,38645,38771, +38775,38776,38770,38927,38925,38926,39084,39158,39161,39343,39346,39344,39349, +39597,39595,39771,40170,40173,40167,40576,40701,20710,20692,20695,20712,20723, +20699,20714,20701,20708,20691,20716,20720,20719,20707,20704,20952,21120,21121, +21225,21227,21296,21420,22055,22037,22028,22034,22012,22031,22044,22017,22035, +22018,22010,22045,22020,22015,22009,22665,22652,22672,22680,22662,22657,22655, +22644,22667,22650,22663,22673,22670,22646,22658,22664,22651,22676,22671,22782, +22891,23260,23278,23269,23253,23274,23258,23277,23275,23283,23266,23264,23259, +23276,23262,23261,23257,23272,23263,23415,23520,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23523,23651,23938,23936,23933,23942, +23930,23937,23927,23946,23945,23944,23934,23932,23949,23929,23935,24152,24153, +24147,24280,24273,24279,24270,24284,24277,24281,24274,24276,24388,24387,24431, +24502,24876,24872,24897,24926,24945,24947,24914,24915,24946,24940,24960,24948, +24916,24954,24923,24933,24891,24938,24929,24918,25129,25127,25131,25643,25677, +25691,25693,25716,25718,25714,25715,25725,25717,25702,25766,25678,25730,25694, +25692,25675,25683,25696,25680,25727,25663,25708,25707,25689,25701,25719,25971, +26016,26273,26272,26271,26373,26372,26402,27057,27062,27081,27040,27086,27030, +27056,27052,27068,27025,27033,27022,27047,27021,27049,27070,27055,27071,27076, +27069,27044,27092,27065,27082,27034,27087,27059,27027,27050,27041,27038,27097, +27031,27024,27074,27061,27045,27078,27466,27469,27467,27550,27551,27552,27587, +27588,27646,28366,28405,28401,28419,28453,28408,28471,28411,28462,28425,28494, +28441,28442,28455,28440,28475,28434,28397,28426,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28470,28531,28409,28398,28461,28480, +28464,28476,28469,28395,28423,28430,28483,28421,28413,28406,28473,28444,28412, +28474,28447,28429,28446,28424,28449,29063,29072,29065,29056,29061,29058,29071, +29051,29062,29057,29079,29252,29267,29335,29333,29331,29507,29517,29521,29516, +29794,29811,29809,29813,29810,29799,29806,29952,29954,29955,30077,30096,30230, +30216,30220,30229,30225,30218,30228,30392,30593,30588,30597,30594,30574,30592, +30575,30590,30595,30898,30890,30900,30893,30888,30846,30891,30878,30885,30880, +30892,30882,30884,31128,31114,31115,31126,31125,31124,31123,31127,31112,31122, +31120,31275,31306,31280,31279,31272,31270,31400,31403,31404,31470,31624,31644, +31626,31633,31632,31638,31629,31628,31643,31630,31621,31640,21124,31641,31652, +31618,31931,31935,31932,31930,32167,32183,32194,32163,32170,32193,32192,32197, +32157,32206,32196,32198,32203,32204,32175,32185,32150,32188,32159,32166,32174, +32169,32161,32201,32627,32738,32739,32741,32734,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,32804,32861,32860,33161,33158,33155, +33159,33165,33164,33163,33301,33943,33956,33953,33951,33978,33998,33986,33964, +33966,33963,33977,33972,33985,33997,33962,33946,33969,34000,33949,33959,33979, +33954,33940,33991,33996,33947,33961,33967,33960,34006,33944,33974,33999,33952, +34007,34004,34002,34011,33968,33937,34401,34611,34595,34600,34667,34624,34606, +34590,34593,34585,34587,34627,34604,34625,34622,34630,34592,34610,34602,34605, +34620,34578,34618,34609,34613,34626,34598,34599,34616,34596,34586,34608,34577, +35063,35047,35057,35058,35066,35070,35054,35068,35062,35067,35056,35052,35051, +35229,35233,35231,35230,35305,35307,35304,35499,35481,35467,35474,35471,35478, +35901,35944,35945,36053,36047,36055,36246,36361,36354,36351,36365,36349,36362, +36355,36359,36358,36357,36350,36352,36356,36624,36625,36622,36621,37155,37148, +37152,37154,37151,37149,37146,37156,37153,37147,37242,37234,37241,37235,37541, +37540,37494,37531,37498,37536,37524,37546,37517,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,37542,37530,37547,37497,37527,37503, +37539,37614,37518,37506,37525,37538,37501,37512,37537,37514,37510,37516,37529, +37543,37502,37511,37545,37533,37515,37421,38558,38561,38655,38744,38781,38778, +38782,38787,38784,38786,38779,38788,38785,38783,38862,38861,38934,39085,39086, +39170,39168,39175,39325,39324,39363,39353,39355,39354,39362,39357,39367,39601, +39651,39655,39742,39743,39776,39777,39775,40177,40178,40181,40615,20735,20739, +20784,20728,20742,20743,20726,20734,20747,20748,20733,20746,21131,21132,21233, +21231,22088,22082,22092,22069,22081,22090,22089,22086,22104,22106,22080,22067, +22077,22060,22078,22072,22058,22074,22298,22699,22685,22705,22688,22691,22703, +22700,22693,22689,22783,23295,23284,23293,23287,23286,23299,23288,23298,23289, +23297,23303,23301,23311,23655,23961,23959,23967,23954,23970,23955,23957,23968, +23964,23969,23962,23966,24169,24157,24160,24156,32243,24283,24286,24289,24393, +24498,24971,24963,24953,25009,25008,24994,24969,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24987,24979,25007,25005,24991,24978, +25002,24993,24973,24934,25011,25133,25710,25712,25750,25760,25733,25751,25756, +25743,25739,25738,25740,25763,25759,25704,25777,25752,25974,25978,25977,25979, +26034,26035,26293,26288,26281,26290,26295,26282,26287,27136,27142,27159,27109, +27128,27157,27121,27108,27168,27135,27116,27106,27163,27165,27134,27175,27122, +27118,27156,27127,27111,27200,27144,27110,27131,27149,27132,27115,27145,27140, +27160,27173,27151,27126,27174,27143,27124,27158,27473,27557,27555,27554,27558, +27649,27648,27647,27650,28481,28454,28542,28551,28614,28562,28557,28553,28556, +28514,28495,28549,28506,28566,28534,28524,28546,28501,28530,28498,28496,28503, +28564,28563,28509,28416,28513,28523,28541,28519,28560,28499,28555,28521,28543, +28565,28515,28535,28522,28539,29106,29103,29083,29104,29088,29082,29097,29109, +29085,29093,29086,29092,29089,29098,29084,29095,29107,29336,29338,29528,29522, +29534,29535,29536,29533,29531,29537,29530,29529,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29538,29831,29833,29834,29830,29825, +29821,29829,29832,29820,29817,29960,29959,30078,30245,30238,30233,30237,30236, +30243,30234,30248,30235,30364,30365,30366,30363,30605,30607,30601,30600,30925, +30907,30927,30924,30929,30926,30932,30920,30915,30916,30921,31130,31137,31136, +31132,31138,31131,27510,31289,31410,31412,31411,31671,31691,31678,31660,31694, +31663,31673,31690,31669,31941,31944,31948,31947,32247,32219,32234,32231,32215, +32225,32259,32250,32230,32246,32241,32240,32238,32223,32630,32684,32688,32685, +32749,32747,32746,32748,32742,32744,32868,32871,33187,33183,33182,33173,33186, +33177,33175,33302,33359,33363,33362,33360,33358,33361,34084,34107,34063,34048, +34089,34062,34057,34061,34079,34058,34087,34076,34043,34091,34042,34056,34060, +34036,34090,34034,34069,34039,34027,34035,34044,34066,34026,34025,34070,34046, +34088,34077,34094,34050,34045,34078,34038,34097,34086,34023,34024,34032,34031, +34041,34072,34080,34096,34059,34073,34095,34402,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34646,34659,34660,34679,34785,34675, +34648,34644,34651,34642,34657,34650,34641,34654,34669,34666,34640,34638,34655, +34653,34671,34668,34682,34670,34652,34661,34639,34683,34677,34658,34663,34665, +34906,35077,35084,35092,35083,35095,35096,35097,35078,35094,35089,35086,35081, +35234,35236,35235,35309,35312,35308,35535,35526,35512,35539,35537,35540,35541, +35515,35543,35518,35520,35525,35544,35523,35514,35517,35545,35902,35917,35983, +36069,36063,36057,36072,36058,36061,36071,36256,36252,36257,36251,36384,36387, +36389,36388,36398,36373,36379,36374,36369,36377,36390,36391,36372,36370,36376, +36371,36380,36375,36378,36652,36644,36632,36634,36640,36643,36630,36631,36979, +36976,36975,36967,36971,37167,37163,37161,37162,37170,37158,37166,37253,37254, +37258,37249,37250,37252,37248,37584,37571,37572,37568,37593,37558,37583,37617, +37599,37592,37609,37591,37597,37580,37615,37570,37608,37578,37576,37582,37606, +37581,37589,37577,37600,37598,37607,37585,37587,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,37557,37601,37574,37556,38268,38316, +38315,38318,38320,38564,38562,38611,38661,38664,38658,38746,38794,38798,38792, +38864,38863,38942,38941,38950,38953,38952,38944,38939,38951,39090,39176,39162, +39185,39188,39190,39191,39189,39388,39373,39375,39379,39380,39374,39369,39382, +39384,39371,39383,39372,39603,39660,39659,39667,39666,39665,39750,39747,39783, +39796,39793,39782,39798,39797,39792,39784,39780,39788,40188,40186,40189,40191, +40183,40199,40192,40185,40187,40200,40197,40196,40579,40659,40719,40720,20764, +20755,20759,20762,20753,20958,21300,21473,22128,22112,22126,22131,22118,22115, +22125,22130,22110,22135,22300,22299,22728,22717,22729,22719,22714,22722,22716, +22726,23319,23321,23323,23329,23316,23315,23312,23318,23336,23322,23328,23326, +23535,23980,23985,23977,23975,23989,23984,23982,23978,23976,23986,23981,23983, +23988,24167,24168,24166,24175,24297,24295,24294,24296,24293,24395,24508,24989, +25000,24982,25029,25012,25030,25025,25036,25018,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25023,25016,24972,25815,25814,25808, +25807,25801,25789,25737,25795,25819,25843,25817,25907,25983,25980,26018,26312, +26302,26304,26314,26315,26319,26301,26299,26298,26316,26403,27188,27238,27209, +27239,27186,27240,27198,27229,27245,27254,27227,27217,27176,27226,27195,27199, +27201,27242,27236,27216,27215,27220,27247,27241,27232,27196,27230,27222,27221, +27213,27214,27206,27477,27476,27478,27559,27562,27563,27592,27591,27652,27651, +27654,28589,28619,28579,28615,28604,28622,28616,28510,28612,28605,28574,28618, +28584,28676,28581,28590,28602,28588,28586,28623,28607,28600,28578,28617,28587, +28621,28591,28594,28592,29125,29122,29119,29112,29142,29120,29121,29131,29140, +29130,29127,29135,29117,29144,29116,29126,29146,29147,29341,29342,29545,29542, +29543,29548,29541,29547,29546,29823,29850,29856,29844,29842,29845,29857,29963, +30080,30255,30253,30257,30269,30259,30268,30261,30258,30256,30395,30438,30618, +30621,30625,30620,30619,30626,30627,30613,30617,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30615,30941,30953,30949,30954,30942, +30947,30939,30945,30946,30957,30943,30944,31140,31300,31304,31303,31414,31416, +31413,31409,31415,31710,31715,31719,31709,31701,31717,31706,31720,31737,31700, +31722,31714,31708,31723,31704,31711,31954,31956,31959,31952,31953,32274,32289, +32279,32268,32287,32288,32275,32270,32284,32277,32282,32290,32267,32271,32278, +32269,32276,32293,32292,32579,32635,32636,32634,32689,32751,32810,32809,32876, +33201,33190,33198,33209,33205,33195,33200,33196,33204,33202,33207,33191,33266, +33365,33366,33367,34134,34117,34155,34125,34131,34145,34136,34112,34118,34148, +34113,34146,34116,34129,34119,34147,34110,34139,34161,34126,34158,34165,34133, +34151,34144,34188,34150,34141,34132,34149,34156,34403,34405,34404,34715,34703, +34711,34707,34706,34696,34689,34710,34712,34681,34695,34723,34693,34704,34705, +34717,34692,34708,34716,34714,34697,35102,35110,35120,35117,35118,35111,35121, +35106,35113,35107,35119,35116,35103,35313,35552,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,35554,35570,35572,35573,35549,35604, +35556,35551,35568,35528,35550,35553,35560,35583,35567,35579,35985,35986,35984, +36085,36078,36081,36080,36083,36204,36206,36261,36263,36403,36414,36408,36416, +36421,36406,36412,36413,36417,36400,36415,36541,36662,36654,36661,36658,36665, +36663,36660,36982,36985,36987,36998,37114,37171,37173,37174,37267,37264,37265, +37261,37263,37671,37662,37640,37663,37638,37647,37754,37688,37692,37659,37667, +37650,37633,37702,37677,37646,37645,37579,37661,37626,37669,37651,37625,37623, +37684,37634,37668,37631,37673,37689,37685,37674,37652,37644,37643,37630,37641, +37632,37627,37654,38332,38349,38334,38329,38330,38326,38335,38325,38333,38569, +38612,38667,38674,38672,38809,38807,38804,38896,38904,38965,38959,38962,39204, +39199,39207,39209,39326,39406,39404,39397,39396,39408,39395,39402,39401,39399, +39609,39615,39604,39611,39670,39674,39673,39671,39731,39808,39813,39815,39804, +39806,39803,39810,39827,39826,39824,39802,39829,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,39805,39816,40229,40215,40224,40222, +40212,40233,40221,40216,40226,40208,40217,40223,40584,40582,40583,40622,40621, +40661,40662,40698,40722,40765,20774,20773,20770,20772,20768,20777,21236,22163, +22156,22157,22150,22148,22147,22142,22146,22143,22145,22742,22740,22735,22738, +23341,23333,23346,23331,23340,23335,23334,23343,23342,23419,23537,23538,23991, +24172,24170,24510,24507,25027,25013,25020,25063,25056,25061,25060,25064,25054, +25839,25833,25827,25835,25828,25832,25985,25984,26038,26074,26322,27277,27286, +27265,27301,27273,27295,27291,27297,27294,27271,27283,27278,27285,27267,27304, +27300,27281,27263,27302,27290,27269,27276,27282,27483,27565,27657,28620,28585, +28660,28628,28643,28636,28653,28647,28646,28638,28658,28637,28642,28648,29153, +29169,29160,29170,29156,29168,29154,29555,29550,29551,29847,29874,29867,29840, +29866,29869,29873,29861,29871,29968,29969,29970,29967,30084,30275,30280,30281, +30279,30372,30441,30645,30635,30642,30647,30646,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30644,30641,30632,30704,30963,30973, +30978,30971,30972,30962,30981,30969,30974,30980,31147,31144,31324,31323,31318, +31320,31316,31322,31422,31424,31425,31749,31759,31730,31744,31743,31739,31758, +31732,31755,31731,31746,31753,31747,31745,31736,31741,31750,31728,31729,31760, +31754,31976,32301,32316,32322,32307,38984,32312,32298,32329,32320,32327,32297, +32332,32304,32315,32310,32324,32314,32581,32639,32638,32637,32756,32754,32812, +33211,33220,33228,33226,33221,33223,33212,33257,33371,33370,33372,34179,34176, +34191,34215,34197,34208,34187,34211,34171,34212,34202,34206,34167,34172,34185, +34209,34170,34168,34135,34190,34198,34182,34189,34201,34205,34177,34210,34178, +34184,34181,34169,34166,34200,34192,34207,34408,34750,34730,34733,34757,34736, +34732,34745,34741,34748,34734,34761,34755,34754,34764,34743,34735,34756,34762, +34740,34742,34751,34744,34749,34782,34738,35125,35123,35132,35134,35137,35154, +35127,35138,35245,35247,35246,35314,35315,35614,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,35608,35606,35601,35589,35595,35618, +35599,35602,35605,35591,35597,35592,35590,35612,35603,35610,35919,35952,35954, +35953,35951,35989,35988,36089,36207,36430,36429,36435,36432,36428,36423,36675, +36672,36997,36990,37176,37274,37282,37275,37273,37279,37281,37277,37280,37793, +37763,37807,37732,37718,37703,37756,37720,37724,37750,37705,37712,37713,37728, +37741,37775,37708,37738,37753,37719,37717,37714,37711,37745,37751,37755,37729, +37726,37731,37735,37760,37710,37721,38343,38336,38345,38339,38341,38327,38574, +38576,38572,38688,38687,38680,38685,38681,38810,38817,38812,38814,38813,38869, +38868,38897,38977,38980,38986,38985,38981,38979,39205,39211,39212,39210,39219, +39218,39215,39213,39217,39216,39320,39331,39329,39426,39418,39412,39415,39417, +39416,39414,39419,39421,39422,39420,39427,39614,39678,39677,39681,39676,39752, +39834,39848,39838,39835,39846,39841,39845,39844,39814,39842,39840,39855,40243, +40257,40295,40246,40238,40239,40241,40248,40240,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40261,40258,40259,40254,40247,40256, +40253,32757,40237,40586,40585,40589,40624,40648,40666,40699,40703,40740,40739, +40738,40788,40864,20785,20781,20782,22168,22172,22167,22170,22173,22169,22896, +23356,23657,23658,24000,24173,24174,25048,25055,25069,25070,25073,25066,25072, +25067,25046,25065,25855,25860,25853,25848,25857,25859,25852,26004,26075,26330, +26331,26328,27333,27321,27325,27361,27334,27322,27318,27319,27335,27316,27309, +27486,27593,27659,28679,28684,28685,28673,28677,28692,28686,28671,28672,28667, +28710,28668,28663,28682,29185,29183,29177,29187,29181,29558,29880,29888,29877, +29889,29886,29878,29883,29890,29972,29971,30300,30308,30297,30288,30291,30295, +30298,30374,30397,30444,30658,30650,30975,30988,30995,30996,30985,30992,30994, +30993,31149,31148,31327,31772,31785,31769,31776,31775,31789,31773,31782,31784, +31778,31781,31792,32348,32336,32342,32355,32344,32354,32351,32337,32352,32343, +32339,32693,32691,32759,32760,32885,33233,33234,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33232,33375,33374,34228,34246,34240, +34243,34242,34227,34229,34237,34247,34244,34239,34251,34254,34248,34245,34225, +34230,34258,34340,34232,34231,34238,34409,34791,34790,34786,34779,34795,34794, +34789,34783,34803,34788,34772,34780,34771,34797,34776,34787,34724,34775,34777, +34817,34804,34792,34781,35155,35147,35151,35148,35142,35152,35153,35145,35626, +35623,35619,35635,35632,35637,35655,35631,35644,35646,35633,35621,35639,35622, +35638,35630,35620,35643,35645,35642,35906,35957,35993,35992,35991,36094,36100, +36098,36096,36444,36450,36448,36439,36438,36446,36453,36455,36443,36442,36449, +36445,36457,36436,36678,36679,36680,36683,37160,37178,37179,37182,37288,37285, +37287,37295,37290,37813,37772,37778,37815,37787,37789,37769,37799,37774,37802, +37790,37798,37781,37768,37785,37791,37773,37809,37777,37810,37796,37800,37812, +37795,37797,38354,38355,38353,38579,38615,38618,24002,38623,38616,38621,38691, +38690,38693,38828,38830,38824,38827,38820,38826,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38818,38821,38871,38873,38870,38872, +38906,38992,38993,38994,39096,39233,39228,39226,39439,39435,39433,39437,39428, +39441,39434,39429,39431,39430,39616,39644,39688,39684,39685,39721,39733,39754, +39756,39755,39879,39878,39875,39871,39873,39861,39864,39891,39862,39876,39865, +39869,40284,40275,40271,40266,40283,40267,40281,40278,40268,40279,40274,40276, +40287,40280,40282,40590,40588,40671,40705,40704,40726,40741,40747,40746,40745, +40744,40780,40789,20788,20789,21142,21239,21428,22187,22189,22182,22183,22186, +22188,22746,22749,22747,22802,23357,23358,23359,24003,24176,24511,25083,25863, +25872,25869,25865,25868,25870,25988,26078,26077,26334,27367,27360,27340,27345, +27353,27339,27359,27356,27344,27371,27343,27341,27358,27488,27568,27660,28697, +28711,28704,28694,28715,28705,28706,28707,28713,28695,28708,28700,28714,29196, +29194,29191,29186,29189,29349,29350,29348,29347,29345,29899,29893,29879,29891, +29974,30304,30665,30666,30660,30705,31005,31003,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31009,31004,30999,31006,31152,31335, +31336,31795,31804,31801,31788,31803,31980,31978,32374,32373,32376,32368,32375, +32367,32378,32370,32372,32360,32587,32586,32643,32646,32695,32765,32766,32888, +33239,33237,33380,33377,33379,34283,34289,34285,34265,34273,34280,34266,34263, +34284,34290,34296,34264,34271,34275,34268,34257,34288,34278,34287,34270,34274, +34816,34810,34819,34806,34807,34825,34828,34827,34822,34812,34824,34815,34826, +34818,35170,35162,35163,35159,35169,35164,35160,35165,35161,35208,35255,35254, +35318,35664,35656,35658,35648,35667,35670,35668,35659,35669,35665,35650,35666, +35671,35907,35959,35958,35994,36102,36103,36105,36268,36266,36269,36267,36461, +36472,36467,36458,36463,36475,36546,36690,36689,36687,36688,36691,36788,37184, +37183,37296,37293,37854,37831,37839,37826,37850,37840,37881,37868,37836,37849, +37801,37862,37834,37844,37870,37859,37845,37828,37838,37824,37842,37863,38269, +38362,38363,38625,38697,38699,38700,38696,38694,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38835,38839,38838,38877,38878,38879, +39004,39001,39005,38999,39103,39101,39099,39102,39240,39239,39235,39334,39335, +39450,39445,39461,39453,39460,39451,39458,39456,39463,39459,39454,39452,39444, +39618,39691,39690,39694,39692,39735,39914,39915,39904,39902,39908,39910,39906, +39920,39892,39895,39916,39900,39897,39909,39893,39905,39898,40311,40321,40330, +40324,40328,40305,40320,40312,40326,40331,40332,40317,40299,40308,40309,40304, +40297,40325,40307,40315,40322,40303,40313,40319,40327,40296,40596,40593,40640, +40700,40749,40768,40769,40781,40790,40791,40792,21303,22194,22197,22195,22755, +23365,24006,24007,24302,24303,24512,24513,25081,25879,25878,25877,25875,26079, +26344,26339,26340,27379,27376,27370,27368,27385,27377,27374,27375,28732,28725, +28719,28727,28724,28721,28738,28728,28735,28730,28729,28736,28731,28723,28737, +29203,29204,29352,29565,29564,29882,30379,30378,30398,30445,30668,30670,30671, +30669,30706,31013,31011,31015,31016,31012,31017,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31154,31342,31340,31341,31479,31817, +31816,31818,31815,31813,31982,32379,32382,32385,32384,32698,32767,32889,33243, +33241,33291,33384,33385,34338,34303,34305,34302,34331,34304,34294,34308,34313, +34309,34316,34301,34841,34832,34833,34839,34835,34838,35171,35174,35257,35319, +35680,35690,35677,35688,35683,35685,35687,35693,36270,36486,36488,36484,36697, +36694,36695,36693,36696,36698,37005,37187,37185,37303,37301,37298,37299,37899, +37907,37883,37920,37903,37908,37886,37909,37904,37928,37913,37901,37877,37888, +37879,37895,37902,37910,37906,37882,37897,37880,37898,37887,37884,37900,37878, +37905,37894,38366,38368,38367,38702,38703,38841,38843,38909,38910,39008,39010, +39011,39007,39105,39106,39248,39246,39257,39244,39243,39251,39474,39476,39473, +39468,39466,39478,39465,39470,39480,39469,39623,39626,39622,39696,39698,39697, +39947,39944,39927,39941,39954,39928,40000,39943,39950,39942,39959,39956,39945, +40351,40345,40356,40349,40338,40344,40336,40347,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40352,40340,40348,40362,40343,40353, +40346,40354,40360,40350,40355,40383,40361,40342,40358,40359,40601,40603,40602, +40677,40676,40679,40678,40752,40750,40795,40800,40798,40797,40793,40849,20794, +20793,21144,21143,22211,22205,22206,23368,23367,24011,24015,24305,25085,25883, +27394,27388,27395,27384,27392,28739,28740,28746,28744,28745,28741,28742,29213, +29210,29209,29566,29975,30314,30672,31021,31025,31023,31828,31827,31986,32394, +32391,32392,32395,32390,32397,32589,32699,32816,33245,34328,34346,34342,34335, +34339,34332,34329,34343,34350,34337,34336,34345,34334,34341,34857,34845,34843, +34848,34852,34844,34859,34890,35181,35177,35182,35179,35322,35705,35704,35653, +35706,35707,36112,36116,36271,36494,36492,36702,36699,36701,37190,37188,37189, +37305,37951,37947,37942,37929,37949,37948,37936,37945,37930,37943,37932,37952, +37937,38373,38372,38371,38709,38714,38847,38881,39012,39113,39110,39104,39256, +39254,39481,39485,39494,39492,39490,39489,39482,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,39487,39629,39701,39703,39704,39702, +39738,39762,39979,39965,39964,39980,39971,39976,39977,39972,39969,40375,40374, +40380,40385,40391,40394,40399,40382,40389,40387,40379,40373,40398,40377,40378, +40364,40392,40369,40365,40396,40371,40397,40370,40570,40604,40683,40686,40685, +40731,40728,40730,40753,40782,40805,40804,40850,20153,22214,22213,22219,22897, +23371,23372,24021,24017,24306,25889,25888,25894,25890,27403,27400,27401,27661, +28757,28758,28759,28754,29214,29215,29353,29567,29912,29909,29913,29911,30317, +30381,31029,31156,31344,31345,31831,31836,31833,31835,31834,31988,31985,32401, +32591,32647,33246,33387,34356,34357,34355,34348,34354,34358,34860,34856,34854, +34858,34853,35185,35263,35262,35323,35710,35716,35714,35718,35717,35711,36117, +36501,36500,36506,36498,36496,36502,36503,36704,36706,37191,37964,37968,37962, +37963,37967,37959,37957,37960,37961,37958,38719,38883,39018,39017,39115,39252, +39259,39502,39507,39508,39500,39503,39496,39498,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,39497,39506,39504,39632,39705,39723, +39739,39766,39765,40006,40008,39999,40004,39993,39987,40001,39996,39991,39988, +39986,39997,39990,40411,40402,40414,40410,40395,40400,40412,40401,40415,40425, +40409,40408,40406,40437,40405,40413,40630,40688,40757,40755,40754,40770,40811, +40853,40866,20797,21145,22760,22759,22898,23373,24024,34863,24399,25089,25091, +25092,25897,25893,26006,26347,27409,27410,27407,27594,28763,28762,29218,29570, +29569,29571,30320,30676,31847,31846,32405,33388,34362,34368,34361,34364,34353, +34363,34366,34864,34866,34862,34867,35190,35188,35187,35326,35724,35726,35723, +35720,35909,36121,36504,36708,36707,37308,37986,37973,37981,37975,37982,38852, +38853,38912,39510,39513,39710,39711,39712,40018,40024,40016,40010,40013,40011, +40021,40025,40012,40014,40443,40439,40431,40419,40427,40440,40420,40438,40417, +40430,40422,40434,40432,40418,40428,40436,40435,40424,40429,40642,40656,40690, +40691,40710,40732,40760,40759,40758,40771,40783,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40817,40816,40814,40815,22227,22221, +23374,23661,25901,26349,26350,27411,28767,28769,28765,28768,29219,29915,29925, +30677,31032,31159,31158,31850,32407,32649,33389,34371,34872,34871,34869,34891, +35732,35733,36510,36511,36512,36509,37310,37309,37314,37995,37992,37993,38629, +38726,38723,38727,38855,38885,39518,39637,39769,40035,40039,40038,40034,40030, +40032,40450,40446,40455,40451,40454,40453,40448,40449,40457,40447,40445,40452, +40608,40734,40774,40820,40821,40822,22228,25902,26040,27416,27417,27415,27418, +28770,29222,29354,30680,30681,31033,31849,31851,31990,32410,32408,32411,32409, +33248,33249,34374,34375,34376,35193,35194,35196,35195,35327,35736,35737,36517, +36516,36515,37998,37997,37999,38001,38003,38729,39026,39263,40040,40046,40045, +40459,40461,40464,40463,40466,40465,40609,40693,40713,40775,40824,40827,40826, +40825,22302,28774,31855,34876,36274,36518,37315,38004,38008,38006,38005,39520, +40052,40051,40049,40053,40468,40467,40694,40714,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40868,28776,28773,31991,34410,34878, +34877,34879,35742,35996,36521,36553,38731,39027,39028,39116,39265,39339,39524, +39526,39527,39716,40469,40471,40776,25095,27422,29223,34380,36520,38018,38016, +38017,39529,39528,39726,40473,29225,34379,35743,38019,40057,40631,30325,39531, +40058,40477,28777,28778,40612,40830,40777,40856, +}; + +static const struct dbcs_index big5_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5_decmap+0,64,254},{ +__big5_decmap+191,64,254},{__big5_decmap+382,64,191},{__big5_decmap+510,64,254 +},{__big5_decmap+701,64,254},{__big5_decmap+892,64,254},{__big5_decmap+1083, +64,254},{__big5_decmap+1274,64,254},{__big5_decmap+1465,64,254},{__big5_decmap ++1656,64,254},{__big5_decmap+1847,64,254},{__big5_decmap+2038,64,254},{ +__big5_decmap+2229,64,254},{__big5_decmap+2420,64,254},{__big5_decmap+2611,64, +254},{__big5_decmap+2802,64,254},{__big5_decmap+2993,64,254},{__big5_decmap+ +3184,64,254},{__big5_decmap+3375,64,254},{__big5_decmap+3566,64,254},{ +__big5_decmap+3757,64,254},{__big5_decmap+3948,64,254},{__big5_decmap+4139,64, +254},{__big5_decmap+4330,64,254},{__big5_decmap+4521,64,254},{__big5_decmap+ +4712,64,254},{__big5_decmap+4903,64,254},{__big5_decmap+5094,64,254},{ +__big5_decmap+5285,64,254},{__big5_decmap+5476,64,254},{__big5_decmap+5667,64, +254},{__big5_decmap+5858,64,254},{__big5_decmap+6049,64,254},{__big5_decmap+ +6240,64,254},{__big5_decmap+6431,64,254},{__big5_decmap+6622,64,254},{ +__big5_decmap+6813,64,254},{__big5_decmap+7004,64,254},{__big5_decmap+7195,64, +252},{0,0,0},{__big5_decmap+7384,64,254},{__big5_decmap+7575,64,254},{ +__big5_decmap+7766,64,254},{__big5_decmap+7957,64,254},{__big5_decmap+8148,64, +254},{__big5_decmap+8339,64,254},{__big5_decmap+8530,64,254},{__big5_decmap+ +8721,64,254},{__big5_decmap+8912,64,254},{__big5_decmap+9103,64,254},{ +__big5_decmap+9294,64,254},{__big5_decmap+9485,64,254},{__big5_decmap+9676,64, +254},{__big5_decmap+9867,64,254},{__big5_decmap+10058,64,254},{__big5_decmap+ +10249,64,254},{__big5_decmap+10440,64,254},{__big5_decmap+10631,64,254},{ +__big5_decmap+10822,64,254},{__big5_decmap+11013,64,254},{__big5_decmap+11204, +64,254},{__big5_decmap+11395,64,254},{__big5_decmap+11586,64,254},{ +__big5_decmap+11777,64,254},{__big5_decmap+11968,64,254},{__big5_decmap+12159, +64,254},{__big5_decmap+12350,64,254},{__big5_decmap+12541,64,254},{ +__big5_decmap+12732,64,254},{__big5_decmap+12923,64,254},{__big5_decmap+13114, +64,254},{__big5_decmap+13305,64,254},{__big5_decmap+13496,64,254},{ +__big5_decmap+13687,64,254},{__big5_decmap+13878,64,254},{__big5_decmap+14069, +64,254},{__big5_decmap+14260,64,254},{__big5_decmap+14451,64,254},{ +__big5_decmap+14642,64,254},{__big5_decmap+14833,64,254},{__big5_decmap+15024, +64,254},{__big5_decmap+15215,64,254},{__big5_decmap+15406,64,254},{ +__big5_decmap+15597,64,254},{__big5_decmap+15788,64,254},{__big5_decmap+15979, +64,254},{__big5_decmap+16170,64,254},{__big5_decmap+16361,64,254},{ +__big5_decmap+16552,64,213},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __big5_encmap[21764] = { +41542,41543,N,41540,N,41393,N,N,N,N,N,N,N,N,41560,41427,N,N,N,N,N,41296,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41425,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41426,41918,N,41916,41917,41919, +N,41413,N,N,N,N,N,N,N,N,N,N,N,41915,41796,41797,41798,41799,41800,41801,41802, +41803,41804,41805,41806,41807,41808,41809,41810,41811,41812,N,41813,41814, +41815,41816,41817,41818,41819,N,N,N,N,N,N,N,41820,41821,41822,41823,41824, +41825,41826,41827,41828,41829,41830,41831,41832,41833,41834,41835,41836,N, +41837,41838,41839,41840,41841,41842,41843,51123,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,51121,51122,51124,51125,51126,51127,51128,51129,51130,N,N,N,N,N,N,51131, +51132,51133,51134,51135,51136,51137,51138,51139,51140,51141,51142,51143,51144, +51145,51146,51147,51148,51149,51151,51152,51153,51154,51155,51156,51157,51158, +51159,51160,51161,51162,51163,51164,51165,51166,51167,51168,51169,51170,51171, +51172,51173,51174,51175,51176,N,51150,41302,41304,N,N,N,41381,41382,N,N,41383, +41384,N,N,N,N,41285,N,N,41292,41291,N,N,N,N,N,N,N,N,N,N,N,41388,N,N,41387,N,N, +N,N,N,41392,N,N,41410,41546,N,41409,N,N,N,41547,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41657,41658, +41659,41660,41661,41662,41663,41664,41665,41666,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41462,41460,41463,41461,N,N, +41464,41465,41467,41466,41428,N,N,N,41435,41448,41447,N,N,41469,N,41468,N,N,N, +41444,41445,41452,N,N,41453,N,N,N,N,N,41455,41454,N,N,N,N,N,N,41443,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41436,N,N,N,N,N,N,N,N,N,N,N,N,N,41434,41437,N, +N,N,N,41432,41433,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41446,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41449,51177,51178,51179,51180,51181, +51182,51183,51184,51185,51186,N,N,N,N,N,N,N,N,N,N,51187,51188,51189,51190, +51191,51192,51193,51194,51195,51196,41591,N,41592,N,N,N,N,N,N,N,N,N,41594,N,N, +N,41595,N,N,N,41596,N,N,N,41597,N,N,N,41589,N,N,N,N,N,N,N,41588,N,N,N,N,N,N,N, +41587,N,N,N,N,N,N,N,41586,N,N,N,N,N,N,N,41585,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,41636,N,N,N,N,N,N,N,N,N,N,N,N,N,41637,N,N,41639,N,N,N,N,N,N,N,N,41638,N, +N,41598,41633,41635,41634,41644,41645,41646,41306,N,N,N,N,N,N,N,N,N,N,N,N, +41570,41571,41572,41573,41574,41575,41576,41577,41584,41583,41582,41581,41580, +41579,41578,N,N,N,N,41590,41593,N,N,N,N,N,N,N,N,N,N,41405,41404,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,41398,41397,N,N,N,N,N,N,N,N,41407,41406,N,N,N,N,N,N,N,N, +41403,41402,N,N,N,41395,N,N,41399,41396,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41640,41641,41643,41642,41401,41400,N,N,41459,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41456,41458,41457,41280,41282,41283,41394,N,50852,N,N,41329,41330,41325,41326, +41333,41334,41337,41338,41321,41322,41541,N,41317,41318,N,N,N,N,N,N,N,41385, +41386,N,N,41667,41668,41669,41670,41671,41672,41673,41674,41675,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,50853,50854,50855,50856,50857,50858,50859, +50860,50861,50862,50863,50864,50865,50866,50867,50868,50869,50870,50871,50872, +50873,50874,50875,50876,50877,50878,50879,50880,50881,50882,50883,50884,50885, +50886,50887,50888,50889,50890,50891,50892,50893,50894,50895,50896,50897,50898, +50899,50900,50901,50902,50903,50904,50905,50906,50907,50908,50909,50910,50911, +50912,50913,50914,50915,50916,50917,50918,50919,50920,50921,50922,50923,50924, +50925,50926,50927,50928,50929,50930,50931,50932,50933,50934,50935,N,N,N,N,N,N, +N,N,N,50850,50851,N,N,50936,50937,50938,50939,50940,50941,50942,51008,51009, +51010,51011,51012,51013,51014,51015,51016,51017,51018,51019,51020,51021,51022, +51023,51024,51025,51026,51027,51028,51029,51030,51031,51032,51033,51034,51035, +51036,51037,51038,51039,51040,51041,51042,51043,51044,51045,51046,51047,51048, +51049,51050,51051,51052,51053,51054,51055,51056,51057,51058,51059,51060,51061, +51062,51063,51064,51065,51066,51067,51068,51069,51070,51105,51106,51107,51108, +51109,51110,51111,51112,51113,51114,51115,51116,51117,51118,51119,51120,N,N,N, +N,N,N,N,50849,41844,41845,41846,41847,41848,41849,41850,41851,41852,41853, +41854,41889,41890,41891,41892,41893,41894,41895,41896,41897,41898,41899,41900, +41901,41902,41903,41904,41905,41906,41907,41908,41909,41910,41911,41912,41913, +41914,41408,41557,41558,N,N,N,N,N,N,N,N,N,N,N,N,41552,41553,41554,N,N,41556,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41559,N,N,N, +N,N,N,N,N,N,41555,N,N,41451,41450,N,N,41551,42048,42050,N,42051,N,N,N,51525, +42070,42068,42071,42069,51526,42147,51535,51533,42146,42145,N,N,42306,42305, +42304,N,42307,42238,N,N,N,N,42464,42465,N,N,N,N,N,N,43203,N,N,N,N,42072,N, +42148,51536,N,42149,51555,42730,52145,N,N,N,N,42073,42150,N,42308,51556,N,N,N, +N,N,51520,42052,N,42075,N,51527,42076,N,N,42151,N,42309,42311,42310,N,N,42466, +42467,N,N,43204,N,44476,42049,N,N,51521,42053,42078,42077,N,N,N,N,N,N,N,N,N, +42468,N,N,N,N,N,N,N,N,N,43205,N,N,N,N,N,N,N,N,N,N,45230,54347,N,N,46787,56497, +56498,N,42054,N,42153,N,N,43206,42055,51528,42079,N,N,42154,42156,51537,42157, +42155,N,N,N,42469,N,43207,N,N,43208,43845,N,42080,42158,N,42470,42472,42471,N, +42731,N,N,43209,43210,43846,43847,N,N,N,N,44477,N,N,56499,N,N,63190,42056,N,N, +N,N,N,42160,42159,51538,42161,42167,N,42162,42163,51540,51539,42165,42166,N, +42164,N,N,N,N,N,N,42314,42315,42316,42317,42313,42320,51562,N,51558,51561, +42321,42337,N,51560,N,42318,42319,42312,N,N,51557,51559,N,N,N,N,N,N,42485, +51632,42482,42486,51642,51630,42483,51634,N,N,N,42484,N,42487,N,42473,51633, +42488,51637,N,51641,51638,N,N,51635,42474,42476,42489,N,42478,51627,42481, +42479,42480,51643,51640,51631,42477,N,N,51628,42475,N,N,N,51636,N,N,N,N,51639, +N,N,N,N,N,N,N,N,N,51629,51814,N,42818,42740,N,N,51815,42737,N,42820,N,42745,N, +42744,51803,42748,42743,51808,51816,N,51812,N,42746,N,N,42749,42734,42823, +51805,N,N,52157,42732,42819,42733,42741,42742,51810,51806,42747,42739,51802, +42735,51813,42821,42824,42738,42816,42822,42736,51811,42817,51817,51804,42750, +51807,N,N,51809,N,43224,52159,52171,43216,N,52172,43211,43221,N,N,43214,52153, +43222,52152,52156,52163,52161,43230,43225,52147,52149,43227,43215,52150,52162, +52169,43220,52155,52148,43219,52151,43223,52154,N,43218,N,43213,N,43228,52164, +43229,52168,N,52166,52170,43226,52158,52146,N,52160,43217,52165,43212,52167,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,43862,43850,N,N,52704,52712,N,43849,43857,43869,N, +52718,52716,52711,N,N,N,43851,52717,52707,43865,43856,43864,52702,N,52714,N, +52705,43860,52706,N,52701,43867,43854,43863,43853,N,52703,52708,N,52715,43861, +43858,52710,43866,52713,52709,43855,43868,43859,43852,43848,N,N,N,N,N,N,N,N,N, +N,52719,N,44503,44481,N,44497,N,44502,53456,53455,53460,53461,44484,N,44493,N, +N,N,44506,44494,N,N,N,N,53449,44487,53450,N,44508,N,44499,44478,44479,53469, +45247,N,44492,44491,53451,44495,54363,44486,53462,44501,44500,44490,53454, +53463,N,53448,44489,53464,44498,53452,44480,N,44483,44482,53465,44496,44485, +44505,44507,53459,44504,N,53467,53453,53468,N,53457,N,53466,N,53458,N,N,N,N, +44488,N,N,N,54371,54359,N,45235,N,54364,54370,45234,54357,45238,54361,54354, +45236,54358,45241,45246,N,54375,N,54353,N,45242,N,54374,N,N,45237,54360,45233, +54355,54351,54365,54352,54350,54362,54368,54369,45239,N,N,55387,54366,54349, +54367,N,45249,54372,45248,54348,N,54356,54373,45244,45243,45240,45245,N,N, +45231,N,N,45232,N,N,46024,N,55390,55383,N,46021,N,55391,N,N,N,55381,55384, +46020,55385,N,N,46023,55389,N,55379,55378,46025,N,46026,46022,46027,55377, +55388,55386,55380,N,N,N,46019,55382,N,N,N,N,N,N,N,N,46794,46788,56503,46797, +56509,56512,46790,46791,56506,46789,56515,46795,56516,N,56511,46796,N,56500, +46793,56501,N,56510,56508,N,56504,46792,56502,46798,56507,56514,56505,56513,N, +N,47542,47539,N,47540,N,57593,57585,47538,47535,57586,N,N,47537,57589,N,57591, +N,N,57598,N,N,57597,57592,47534,57584,47532,57587,47543,57590,N,57594,47536, +47533,57596,57595,47541,N,57588,N,48120,58604,N,58601,48121,N,48119,N,58608, +58605,58598,48118,N,48122,58599,48117,48125,58602,58603,48123,48124,58609, +58606,58607,N,N,N,48810,59640,48807,59637,48809,48811,N,59638,48808,N,59639,N, +59636,N,N,49270,60605,49271,60603,N,60604,60602,60601,N,N,60606,49269,N,N, +61368,61369,N,58600,61367,49272,50015,61931,61932,N,50391,50392,62913,62912, +50540,50539,63440,N,42057,42081,42169,N,42168,42323,42322,42492,42491,42493, +42490,N,42826,42825,42827,N,N,N,N,43232,N,43231,43233,N,43870,N,41561,53470, +41562,45250,41564,41563,55392,N,41565,47544,41566,N,42058,N,42170,42494,43234, +N,42059,42173,42171,42172,N,N,42560,N,N,N,42828,43236,43235,43237,N,N,N,44509, +N,N,N,48812,N,N,N,N,N,N,51534,N,42324,42325,N,N,42561,N,51818,N,43872,43871, +53472,53471,45251,N,42174,51541,N,N,N,N,N,52173,N,43873,N,44512,N,44510,44511, +N,N,N,N,48813,N,42326,N,N,N,42562,51644,N,N,N,N,42829,42830,N,51819,N,N,52174, +43238,52175,N,N,N,N,N,53474,53475,44515,N,53476,N,53473,44516,44514,44513, +53477,N,54376,N,N,N,55393,N,N,56517,57664,N,N,N,48126,48814,59641,N,42060, +42074,N,N,N,N,N,N,N,N,N,N,N,N,N,N,45252,46029,N,47545,N,51522,42175,N,42329, +42327,42328,N,N,43239,42061,42062,N,42082,N,N,42176,42177,42178,51646,42330,N, +51563,N,42566,N,51647,42564,42565,51645,N,N,42567,42563,N,N,N,N,51820,43756, +51821,N,N,51822,N,N,42832,42831,N,N,42835,42833,42834,N,N,N,43245,N,43244, +52180,52177,52178,N,52176,43246,43242,43241,N,43243,43240,N,N,N,N,N,43247,N, +43875,52720,N,52179,43880,N,52721,43876,43879,43878,43877,43874,N,N,N,53480,N, +44519,53483,44517,N,N,N,53479,44520,44518,44521,53481,53482,N,53478,53484,N,N, +N,N,N,N,46033,45253,54377,54379,54378,54380,45254,N,N,46030,N,46031,46032,N, +46800,56519,N,56518,56520,56521,46801,N,46799,57665,57666,47547,47546,58202,N, +N,48192,48193,48194,48196,58610,58611,48195,N,N,N,48815,N,48816,N,N,61933, +62915,62914,63441,N,42063,N,N,N,42332,42331,N,N,42568,N,N,51648,N,N,42837, +42838,42836,42839,51823,51824,N,N,N,N,N,N,N,N,N,N,N,N,43249,52181,N,43248,N, +52722,43884,52723,43883,N,N,N,43881,N,43882,N,N,N,53485,N,N,N,N,45255,54382,N, +45258,54381,45541,45257,45256,N,46036,N,46035,46034,46802,N,N,46805,46806, +46804,N,46803,N,N,57667,N,57668,N,N,N,58613,48197,58612,N,48817,60607,49273,N, +61934,50261,N,42083,42179,51542,N,42180,42181,42333,42334,N,42569,51825,52182, +52183,N,43885,53486,45260,45259,55395,55394,N,N,42064,42182,42335,N,45261, +51523,N,51564,42336,N,51650,42571,42570,51649,42840,N,N,N,N,N,N,44522,N,N, +54383,N,46807,57669,47548,N,N,59642,N,N,62461,N,42183,N,N,52184,52724,45264, +45262,45263,42065,N,42084,41677,42186,N,42185,42184,42339,42338,N,51565,51651, +N,N,N,43253,43250,43252,43251,N,N,43886,N,N,46037,N,42066,N,42187,N,42341, +42340,N,51826,N,N,43254,N,N,N,N,N,51543,N,42343,42342,42572,42573,51827,42841, +N,42842,N,43255,43256,43257,N,43887,52725,N,N,44523,N,N,51524,N,42188,N,N,N,N, +N,51652,N,N,N,51828,51829,N,N,52185,N,52186,N,52727,52726,52729,52728,43888,N, +54384,44525,53487,44524,N,N,N,N,55396,46038,N,55397,N,N,N,N,57670,47549,N,N,N, +N,48198,N,61935,N,N,N,N,51544,N,42344,N,N,N,N,N,N,N,45265,N,N,N,N,42067,42085, +42190,42189,N,42191,N,N,N,N,N,N,43259,N,43258,43260,N,N,N,43889,N,N,N,44526,N, +59643,49743,42086,42346,42361,42356,N,42351,42350,42357,42355,42348,42362, +42349,42345,42360,42359,42358,42347,N,42354,N,N,42353,N,N,42363,42352,42579,N, +42585,42581,N,42587,51653,42584,42574,42577,42580,42576,42583,42586,42575, +42578,42582,42588,N,N,N,N,N,51838,51835,N,42855,51836,42843,42845,42869,42864, +N,N,N,51877,51837,42847,42849,51876,42856,51832,42868,42870,42844,42861,N, +51830,42867,N,42852,N,42862,42863,51831,42860,42858,N,42859,42865,51873,42846, +N,42866,51875,42854,42851,N,51834,42850,51878,42853,N,42857,N,N,N,42848,51874, +N,N,N,N,51833,N,N,N,N,N,N,N,N,N,N,N,52203,52202,43343,52205,52207,52196,52199, +52206,43344,N,N,52193,52197,N,N,52201,52809,43339,52813,43261,52198,43262, +43340,43333,43329,N,52194,43332,43337,43346,52195,52188,43331,52189,52191,N, +43334,N,43336,52187,52192,N,N,43345,43341,52200,43347,N,43338,52190,43335,N,N, +43330,43328,N,52204,N,43342,N,N,N,N,N,52808,52731,52811,N,N,52733,43896,43944, +43892,43943,43901,43940,43890,52732,52803,43939,52815,43941,N,43897,N,N,52805, +52802,43895,N,52730,43942,52810,43900,52812,43945,43891,43902,43899,52800, +43937,52806,52807,43898,43938,43894,N,N,N,N,43893,52734,N,N,N,N,N,N,52804,N,N, +N,N,N,N,N,52814,N,53572,44539,53489,N,53494,44532,44608,53492,44527,44537, +44542,53499,N,44538,44541,N,N,53502,44533,53493,N,N,N,53570,53571,N,44535, +53569,44531,44611,N,53496,44529,N,53574,53497,53501,44534,44610,53498,44540, +53568,53575,54433,N,53573,44612,44528,53500,53491,N,44536,N,N,53490,N,N,53495, +N,N,N,N,N,N,N,N,N,N,N,53488,44609,N,N,54391,N,45284,54439,45282,45279,54396, +45275,54434,45286,54390,54395,54394,44530,45281,54437,N,54440,54387,N,46056,N, +54441,45287,N,45273,45270,54398,45267,N,54438,N,45274,54442,N,54388,54436, +45277,54389,54392,54397,N,N,45278,45276,45288,N,N,N,N,45283,N,45271,45522,N, +45272,54393,45285,45280,54435,45269,N,N,N,45268,N,N,N,N,N,N,N,N,N,N,54385, +54386,55402,N,N,N,46039,46042,55413,46062,55416,46040,55409,46046,46052,46525, +N,N,46050,55406,46063,46043,46051,55414,56535,55419,55407,N,55398,55411,55405, +46049,55417,N,N,46045,46065,46058,N,46047,46044,N,46055,N,55418,55404,55410, +55412,55400,55415,46041,55399,N,46048,46064,46060,55401,46054,N,N,46061,46057, +46053,N,55408,N,N,N,N,N,46059,N,N,N,56533,56529,N,56544,56522,56531,46821, +46822,46814,56540,46824,56527,56526,56524,56542,46812,56536,56525,46815,56534, +46810,56530,56537,56539,N,N,56543,46819,56523,46813,56528,N,46808,N,46820, +56538,46816,46817,46823,46811,41567,46809,56532,N,N,N,N,N,46818,N,N,56541,N,N, +N,47565,47560,N,57685,57681,N,57675,47554,47550,57684,47551,57678,57680,N, +57683,N,47556,N,47563,47557,N,N,57673,47558,47559,57676,47564,N,57674,57679, +47555,57672,47561,47553,N,N,N,47552,57677,57682,N,47562,N,N,N,N,N,N,N,57671,N, +48205,58695,N,58692,N,48199,48211,48212,N,48202,58690,48204,58617,48210,N, +58694,48201,58696,48200,N,58691,58693,48203,58689,58618,58615,N,N,55403,58621, +N,58614,58620,58619,N,58616,N,48207,N,N,N,N,48206,N,N,N,48208,58622,48818, +58688,N,N,N,59717,N,59645,N,48830,59714,48822,48826,59713,N,48825,48821,48824, +48819,48829,59715,59646,48828,59644,48827,59716,59712,48209,N,48831,59718, +48823,48820,N,N,N,N,60614,60616,49275,60617,60615,60613,60612,49277,60611, +49278,N,N,N,N,60609,60610,49274,49313,49276,N,N,60608,N,49744,N,61372,61370, +61375,61373,N,61371,61374,N,N,N,N,N,N,N,50016,61938,61939,50262,N,61940,61936, +61941,61937,49745,N,N,N,62462,62529,50265,62528,50264,50263,N,N,N,N,50266, +62917,62918,N,50394,50393,50395,62916,N,63192,63191,N,50541,50543,50542,63193, +50632,63654,N,N,N,50673,N,63653,63726,N,N,51529,N,N,42365,42364,N,42591,42590, +51655,42589,51654,N,N,42873,51881,N,51880,N,N,42871,42874,N,N,51879,N,42872,N, +N,N,N,N,N,52208,N,52209,43348,N,N,N,N,43946,53576,53577,44613,44614,N,N,54444, +45289,45291,54443,45290,55420,46066,N,N,N,N,46825,46826,56545,N,47567,N,47566, +N,58697,59720,59719,N,63851,42087,51545,N,51566,51567,N,N,N,N,42594,42598, +51657,N,42596,42595,51656,42597,42593,N,N,42592,51658,N,N,N,N,N,N,42918,N,N, +42915,N,42877,51882,N,N,N,51883,N,42913,N,51885,42875,51886,51884,42878,42914, +42917,42916,42876,51887,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43353,52222,N,43355,N, +43354,N,52288,43352,43351,52213,N,52212,N,52210,52215,52214,52211,52220,52221, +52218,52216,43350,N,N,N,52219,43356,52289,N,N,52217,N,43947,43349,N,N,N,N,N,N, +N,43948,52820,N,N,52826,N,N,N,43954,52824,52830,N,52821,52825,52827,52829, +52823,N,52822,52817,52818,43949,N,43951,43950,52819,52828,N,N,N,N,N,N,N,N, +43953,N,N,N,N,N,N,52816,53587,N,53586,53591,53582,N,53585,53584,N,53588,N, +53592,44615,44618,N,N,53583,53589,N,N,N,44617,53578,N,43952,54458,53590,N, +53581,N,44616,53580,N,N,N,N,N,N,54449,N,N,45292,45296,54465,54447,54461,45297, +54463,N,54469,N,54473,N,N,54464,54452,54460,N,54474,54472,54462,54457,54450, +55462,54448,45301,54455,45302,45298,54445,54467,54453,54451,54470,45299,N, +54476,45293,45295,54459,54454,44619,45294,54456,54471,54475,54466,N,54468,N,N, +N,54446,N,N,N,N,55457,N,55466,55465,46074,55458,N,46075,46073,N,55460,46070, +55464,N,55459,55461,55421,46068,N,55474,55473,55470,46067,46071,46072,53579, +55467,46069,45300,55469,55422,55472,55471,N,55475,N,56559,N,55468,N,N,N,N,N,N, +N,N,55463,56551,46836,46839,46834,56550,56554,56549,N,46828,46838,56546,46832, +56553,N,46830,46829,56556,46831,56558,N,56555,46827,N,N,N,46837,56560,56548, +56557,N,N,56547,N,N,46833,N,46835,N,56552,N,56561,N,N,57693,47568,57699,N,N, +47573,57695,57702,57687,47575,47569,57692,48213,57691,57700,47570,N,47574, +57690,57696,57701,57686,47572,57694,N,N,57698,57704,57688,57697,N,47571,57703, +N,N,N,57689,N,N,N,48217,58699,48215,48214,58701,58706,N,58702,N,58705,48220,N, +48805,48219,N,58698,58704,N,48218,58703,N,58700,N,48216,N,N,N,N,N,N,59725,N, +59727,59722,48833,59724,N,48832,59726,N,N,48835,59728,48834,59721,59723,N,N,N, +N,49317,60620,N,49316,60621,49315,60619,49314,60618,N,49747,49746,61942,61944, +N,61943,50017,50018,N,N,50019,62530,50267,N,N,63443,63442,50674,N,42088,42192, +N,N,42919,N,N,N,N,52831,N,N,N,N,46076,46077,N,56562,47576,57705,58707,51546,N, +N,51888,N,N,N,N,N,52290,52832,53593,44620,N,N,61945,N,50396,42089,42366,51568, +N,42599,42600,N,43357,N,N,N,45303,N,47578,N,47579,47577,N,42090,N,42193,42195, +42194,51547,42196,42401,51569,N,42402,N,N,N,N,N,42601,42602,N,N,N,51659,N, +42920,N,51889,N,N,N,43361,52291,N,43359,43360,43358,53594,N,N,N,43958,43957, +43959,43956,N,52833,43362,43955,N,44621,44622,N,44623,N,54477,N,N,N,46078, +55476,45304,N,N,N,N,46840,N,47581,47580,57706,N,48221,48836,N,61376,63194, +63444,42091,42403,N,42404,51665,42604,42607,N,51663,51661,42606,51664,51666, +51660,42609,42608,42605,42603,51662,N,N,N,N,42931,N,N,42928,51894,51897,51896, +N,42922,42930,N,N,42927,51893,51891,42926,N,N,N,42921,42924,N,51892,51899, +51895,42925,42929,42932,51890,51898,42923,N,N,N,N,N,43367,43375,N,52303,52296, +43376,52307,52292,52299,N,N,43366,52293,43364,52300,52304,43363,N,52305,52298, +N,52301,N,43378,43369,52308,52306,N,43374,43372,52297,43371,52295,52294,43370, +43368,43377,43373,43365,N,52302,N,43961,N,43968,52847,43960,52839,52835,N, +52851,52834,N,43963,52844,43966,43969,N,43964,52848,43967,N,44630,52854,52836, +N,N,52838,52845,52849,52853,52850,52843,52846,N,N,52840,43971,52842,52841, +52852,43962,52837,43970,N,43965,N,N,N,N,N,44636,53602,N,44635,N,N,53600,N, +44624,N,44629,N,53599,53596,53601,44625,53595,N,44628,44626,N,53603,44627, +44631,N,N,44632,N,44634,N,N,N,44633,N,N,N,53597,53598,N,N,N,N,53604,N,54484, +45305,55490,54483,54502,N,N,45376,N,54500,N,45310,45306,54509,54493,54496,N, +45379,54506,54498,45307,45380,N,54503,54501,N,N,54486,54507,54495,54490,N, +54480,54508,54492,54479,N,45378,54497,54510,54494,54482,54487,54478,N,45377,N, +54491,54488,45308,54481,N,54505,45309,N,54489,54485,N,N,54504,N,N,N,N,N,N, +46144,55483,N,55480,55497,55485,55498,N,46146,N,N,N,55494,55491,N,N,N,N,N, +55492,55495,55499,N,54499,55501,56647,N,46147,55502,55478,55488,N,55493,N,N, +46145,46148,55500,55503,55482,55479,N,N,55481,N,N,55486,55484,46149,N,55496,N, +N,55487,N,55489,55477,56570,56568,46914,46912,56643,56569,56644,56640,56567, +56646,56566,56573,46846,46845,46844,56571,56641,46841,46913,N,56564,N,56574, +56563,56572,46842,56642,56565,46843,56645,N,N,N,N,N,N,N,57710,47586,47585, +47587,57722,57712,57718,57707,57721,57720,57724,57717,47582,57716,47588,N, +57709,47583,N,57723,47584,57711,57714,57719,57713,57708,N,N,N,N,57715,58709, +48225,58712,58711,58714,58716,N,48223,N,58710,N,58708,58717,58715,58713,N, +58719,N,58718,48227,48222,N,48224,48226,N,N,58720,59735,N,N,59734,59733,N, +59736,59729,N,59730,59738,59731,N,48837,59740,N,59739,59732,N,60625,49320, +60623,60628,60627,59737,N,49319,N,60626,60622,60630,60629,49318,N,60624,N, +48838,N,N,N,49748,N,N,N,61377,61946,61947,61948,50268,N,N,50269,N,62531,N, +62920,62919,N,N,63195,63196,63445,63655,N,42092,42093,N,42094,42197,42405, +51667,42610,42611,N,42935,42936,42934,42933,N,43379,N,N,52309,43381,43380, +52310,N,N,N,43972,N,44637,53605,N,54512,N,45381,46151,54511,46150,N,47589,N, +57725,48839,N,49321,60631,N,50270,N,50544,N,51570,N,42406,51571,42614,N,42612, +42613,42615,N,42938,42937,N,51900,42939,N,N,51901,52311,N,52312,N,43382,43384, +43386,43383,43387,43385,N,N,N,N,N,43976,43973,43975,43977,43974,53606,52855,N, +N,N,53608,53607,44643,N,44639,N,N,44640,44642,44644,44641,N,44646,44645,N,N,N, +N,N,45386,54514,54513,45385,N,45384,45383,45387,45382,N,N,55509,55506,46153, +55505,55510,N,46155,55508,46152,46154,55507,N,56648,N,56649,56650,N,N,N,N, +47590,47598,57726,47592,47596,57761,47597,47593,47594,47591,47595,48230,55504, +48231,48229,N,48228,59741,48840,60632,60633,N,N,50020,50271,N,42095,N,42616, +43978,N,53609,44647,N,N,45390,45389,45388,46156,46157,55511,47599,48841,42096, +51548,42198,51572,N,N,51668,42617,N,N,N,43388,N,N,N,N,56651,N,N,42097,N,42199, +51669,N,N,51902,N,51903,N,42940,N,N,N,55512,46158,N,56652,N,N,N,49322,42098, +42152,42200,51573,42407,N,42944,42943,42941,42942,N,N,52313,43390,43425,52314, +43389,N,N,43982,52856,43981,43979,43980,44650,44648,N,N,53611,44649,53610,N, +44638,54515,N,N,45392,45393,N,N,45391,N,47600,57762,48232,48233,N,58721,49323, +61378,61379,N,50397,63656,51531,42201,N,42099,N,51575,51574,N,N,N,N,42618, +51671,51672,51670,N,51673,N,N,N,N,N,N,N,51911,N,51906,51908,51910,51907,42948, +51904,N,51905,42945,42946,51909,51912,42947,51913,N,N,N,N,N,N,N,52328,N,52322, +52317,43427,52325,52323,52316,52329,52332,52327,52320,43429,52326,43430,52321, +52324,52315,52319,52331,43431,N,43432,N,52318,52330,43426,43428,N,N,N,N,N,N,N, +N,N,N,N,N,N,52907,52900,52906,52899,52901,52861,52859,N,52908,52905,52857,N, +43984,52903,52904,N,52902,52860,52858,43983,52898,52862,N,N,52897,52909,N,N,N, +N,N,N,N,N,44655,N,44654,N,53612,44651,53614,N,44656,53615,N,N,44659,N,44657, +53616,52910,53618,N,44653,N,44652,N,53613,53617,44658,N,N,N,N,45395,45394,N,N, +N,54517,54521,54523,45396,54526,N,45400,54593,N,45402,N,45398,45406,N,45403, +54519,45397,N,54518,54516,54595,54520,N,45399,54594,45404,54525,54524,45405, +54522,45401,N,N,N,N,54596,N,54592,55527,55534,55523,46161,55519,55535,55513, +55532,55530,55524,N,55533,55526,N,55518,55536,55516,55529,55514,N,55537,N, +46162,N,55531,56655,55517,46159,N,55521,N,46160,55520,55525,N,N,55522,N,N,N, +55528,N,N,N,N,56659,N,N,N,56662,56654,N,56656,N,56661,56660,46915,N,55515, +56658,N,N,46916,N,56653,56657,N,N,N,N,57769,N,57776,57767,N,57774,57765,57773, +57777,57764,57768,57763,N,47601,N,57766,47602,57772,57771,57770,N,N,57775,N,N, +N,N,58725,58727,48235,58728,N,58723,N,58722,58732,N,58730,48234,58733,58724, +58729,58731,58726,N,N,N,N,59745,59750,59744,59749,N,59742,59752,59748,59753, +59747,59743,59751,N,59754,59746,N,60634,49327,N,49325,N,49324,49326,N,N,61380, +N,61810,61949,N,N,62532,62533,N,50272,N,62921,N,50398,N,62922,N,63198,50546,N, +50545,63197,50633,N,63446,N,N,N,N,42100,42619,51674,51914,43189,45407,N,N, +42101,42410,42409,42408,N,N,42949,N,N,44660,N,56663,42102,42103,42104,42202,N, +N,43985,N,52911,N,N,N,46163,42105,51549,42411,42412,51576,N,42620,N,N,N,51915, +N,42950,N,51916,N,N,43438,N,N,52334,43436,43435,52333,43433,52335,43434,43437, +N,43986,N,43988,52915,52912,52913,52914,52916,43987,N,N,53620,53619,N,44662,N, +44661,N,N,N,N,N,45410,54598,N,45409,45411,45408,N,N,N,N,46165,54597,N,46166, +55539,N,46167,55538,46164,N,N,N,N,56666,56668,46917,56667,56665,56664,N,N,N, +57780,47607,47605,N,47606,57778,57779,N,47603,58737,58735,N,48237,58736,48238, +48236,47604,N,N,59757,59755,59756,58734,60636,49328,60635,61381,61382,59758, +61950,N,42106,42413,42622,51675,42621,N,43439,46918,N,42203,42414,43989,46168, +N,51577,N,51578,N,51676,N,N,42952,51920,51918,42953,51917,51919,51921,N,42951, +N,N,N,N,N,43443,43444,43441,N,N,43440,52920,43442,N,N,N,43990,N,52919,52921, +52918,52922,43991,44665,53621,N,53623,44663,53624,44664,53622,N,52917,54599, +54602,54603,54600,45415,45414,45412,45413,54601,N,N,N,N,45416,N,N,46170,46171, +N,46172,56669,56671,56673,46920,46919,46169,56672,56670,N,57784,N,N,57782, +57788,47608,57789,57786,47609,57783,57781,57787,48240,58739,57785,48242,58740, +48241,48244,58741,48239,48243,N,59763,59761,59760,59762,59759,N,N,50022,N, +62534,62535,N,62923,63199,50773,N,N,43445,42954,N,N,43992,N,N,N,42107,42204, +42415,51677,N,42955,51922,N,52923,43993,N,47610,42108,N,N,N,42657,N,N,46921, +42109,42205,42206,N,42417,42416,N,51678,42658,N,51923,N,42956,N,N,52337,52338, +52339,N,43446,43447,52336,43448,N,N,N,43994,52924,N,53626,44666,N,53625,N, +45417,54604,45418,54605,N,N,N,46173,N,N,N,56674,N,N,57791,57790,N,47611,N, +48245,58742,48842,59764,49329,N,50547,63448,N,N,N,N,52340,N,52925,45419,55540, +46922,N,N,N,49749,N,N,N,N,42958,N,42957,43995,N,53627,N,45421,45891,45422, +45420,46174,N,57792,47612,48246,N,51532,51679,N,51925,42959,51924,42960,N,N, +43452,52343,52342,43451,43449,43450,52341,N,N,43997,52926,44000,43996,44002, +43998,43999,44001,N,N,N,44669,44668,44667,N,N,N,54607,45423,45426,45424,N, +54606,45429,N,45425,54608,45428,45427,N,N,N,55542,55541,N,46177,46175,46176, +55543,46923,56676,46924,56675,N,N,58743,N,N,48248,57793,48247,N,47613,N,60638, +59765,49330,60637,62016,62536,62537,N,42207,N,42418,N,N,N,51579,N,N,42962, +42964,N,51682,51928,51927,51926,N,51681,51680,42660,42963,42961,42659,N,N,N, +43453,52344,N,43454,51933,N,51935,51934,52345,N,N,51930,N,42968,42966,N,51929, +51931,51937,N,42965,N,51932,51941,43456,N,51938,42967,N,51936,51939,N,43455,N, +43457,51940,N,N,N,N,N,N,N,N,52399,52386,52350,52398,52393,44007,43458,52394, +52397,44003,52396,43459,43464,43462,52387,N,52348,52389,43469,52400,44004, +52390,N,44005,43465,52392,N,52941,44006,52347,43466,44008,43467,43463,43468, +52391,52346,52395,43460,N,N,52349,52388,52385,43461,N,52927,N,52928,N,N,N,N,N, +N,52938,53665,52939,44014,52942,52932,44013,52934,N,52935,N,N,52937,44009,N,N, +44707,N,N,52933,52929,44708,N,N,52943,44670,53629,52936,N,53628,52931,52940,N, +N,44012,44705,44018,44706,52944,53630,44011,44710,44017,44016,44015,44709, +52945,44711,44010,N,52930,N,N,N,N,N,N,N,N,N,N,N,N,45430,53668,53670,N,53672, +44712,44718,54611,53676,53667,45432,54609,N,44717,44715,53678,N,54610,N,53669, +N,44716,53673,44719,53675,N,N,44714,53674,53677,53671,N,44713,45433,N,53666, +45431,N,N,N,N,45434,N,N,N,N,N,N,N,54613,54622,46180,N,45436,45475,46181,54624, +45482,55545,54614,45474,45477,45438,54612,54626,54629,55625,N,54627,55549, +45473,45480,45484,54621,55544,54625,45435,55546,54628,55548,54617,N,46178,N, +54615,54616,45479,N,N,45478,54619,45483,54623,45476,54620,N,45481,46182,46179, +55547,N,54618,N,45437,N,N,N,N,N,N,N,N,N,46187,46191,55616,46929,46189,55620, +46193,56677,55622,46931,46185,46188,55623,N,55624,55630,46195,46932,N,55626, +55631,55619,46942,N,46933,46194,55617,55632,N,46941,46192,46926,55629,N,46196, +55621,55550,46186,55618,N,55627,N,46925,46930,46183,55628,N,46928,N,N,N,46184, +N,N,N,46940,57795,56688,N,56680,57794,N,56684,56686,N,N,56683,N,46939,N,56682, +46943,N,N,N,57810,N,N,46938,47680,56689,57796,N,N,46936,56681,56685,47614, +46927,56678,56679,47681,46935,46937,46934,56687,N,N,57800,57801,57806,48253, +57813,N,47687,N,47686,57808,N,48252,57797,47685,N,57812,47683,47684,N,57809, +58794,48250,46190,N,57811,48291,57803,N,48251,N,48290,57798,57802,57799,57805, +47688,48249,47682,N,58746,57807,N,48289,N,48292,N,57804,N,48254,58745,N,N,N,N, +N,58750,48846,58744,59811,58793,48296,N,48294,48844,58790,58786,48300,N,59768, +N,N,N,48298,58785,N,59766,N,58789,N,58792,58749,N,48299,N,N,48293,59767,48845, +58791,48295,48297,58788,48301,58787,58748,58747,48843,58795,59770,60640,48848, +N,59810,N,59774,N,60641,N,48849,59809,N,59772,49332,60639,N,59769,59771,49333, +48851,49331,48850,49335,59773,48847,N,N,N,N,N,N,N,N,61391,N,61383,N,N,N,N,N, +60647,61384,60643,N,N,49750,60645,60644,49334,60642,60646,61392,61388,61390,N, +61385,61386,N,61389,61387,50023,N,N,50026,50025,50024,50273,62538,50274,62017, +50399,62924,50400,50548,50634,63449,N,63450,63451,N,N,63930,42208,51580,42419, +N,42662,42663,42661,N,42664,42970,42969,N,52401,43471,43470,N,N,53679,45485, +45486,N,N,N,46197,56690,46944,46945,56692,56694,56693,N,57815,N,57814,47689, +57816,N,58796,48302,N,48852,N,49336,49751,49337,N,42209,N,N,N,51942,N,N,52402, +43473,43472,43474,44019,52946,52947,N,N,53680,44720,45487,46198,55633,42210,N, +42110,42211,N,51581,42423,42422,42420,42421,N,N,N,42667,51689,51691,42666, +51683,N,51684,N,51690,51686,51688,42665,51685,51692,51687,N,N,N,N,N,N,42977, +42986,42984,51952,51949,51957,42982,51958,N,42975,51955,N,42981,51951,51950, +42979,51956,42980,43475,42974,51953,N,51943,42971,N,42990,51948,51954,42976, +42978,N,51944,N,51945,51946,N,42989,42983,42988,51947,42987,42973,42972,42985, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43489,52414,52407,43484,43503,52403,52410,52412, +52415,43498,N,52411,52404,43496,52408,N,52416,43481,N,52413,43491,43490,52406, +43479,N,N,43480,N,43478,N,43502,43494,43488,43476,52409,43487,43477,43495, +43504,52948,43492,52405,43482,43485,43486,N,43500,43501,43499,43493,43497, +43483,44020,N,N,N,N,N,N,N,N,N,N,N,N,N,N,52954,44097,44024,44026,44096,52966, +44029,53681,44721,44099,52951,52959,44030,52958,52955,52963,52965,44023,44027, +44098,44723,52960,44025,44101,52953,N,N,N,44028,44722,44022,N,52950,52957, +52949,52952,52956,53682,44100,N,52961,52962,52964,44021,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44737,53694,44735,44736,53684,53700,N,44726,N,N,54630,53702,53696, +N,53687,N,53705,53690,44732,54653,53693,44734,44725,N,53707,53695,44728,53688, +53685,53686,44729,53701,53708,44731,53692,53691,44739,44738,44724,44730,44733, +53704,N,N,53698,44727,53683,53706,53697,53699,53703,N,N,N,N,N,N,N,N,N,N,54631, +N,45495,45515,45514,N,45503,N,54649,54645,54642,54694,45498,45490,N,N,54647, +46248,45494,54689,N,45516,45513,54651,54634,N,N,45512,54691,54633,45501,45505, +54690,N,54643,45506,45500,54632,N,46200,54693,54641,45511,54644,54692,45510,N, +55634,N,45491,54639,45496,45507,N,45502,54648,54638,54636,54654,45488,45508, +45492,46199,54652,45493,N,45489,45504,45499,45497,54640,45509,54637,54650, +54646,55636,55635,N,N,N,N,N,N,N,N,N,N,N,54635,55652,N,46202,N,55658,55641, +55655,56695,46205,55659,55662,46204,55644,55661,55660,46206,55637,46201,46243, +N,46241,55657,N,55647,46245,55664,55656,55665,46253,46251,55654,55653,N,55651, +55645,46244,N,46242,53689,55638,N,56759,55639,46203,46250,56697,N,46246,46247, +55640,55663,56696,55648,55643,46249,55649,55646,N,N,46254,46960,N,N,56700, +56753,56758,56746,46956,56763,46953,56698,N,56699,46946,46955,56740,46958, +46959,56741,N,56754,56760,46954,N,46948,56739,56701,56762,56744,56745,56702, +56756,56747,56757,56749,N,46949,57817,46952,46950,56761,56752,56748,N,N,56737, +47699,56751,46957,56743,N,56742,N,N,N,46951,46947,57838,56755,56750,N,56738,N, +N,N,N,N,N,N,57833,N,57818,57829,N,57836,47697,46252,57834,47692,N,N,N,47691, +57841,N,57819,57832,57820,57831,47695,57835,55650,N,N,N,57842,57827,47698, +58810,48303,N,57840,57839,47700,58797,48304,58798,N,57823,57824,57821,57826, +57822,57843,47694,48305,47696,47701,N,57825,N,57837,N,N,57830,N,N,58801,N, +47690,48308,59818,58806,58805,58807,N,N,58804,48309,N,48315,48312,N,48313, +58799,58802,58812,48321,48319,N,58803,55642,48306,58809,58800,N,48322,58808, +47693,48311,57828,N,N,48314,N,48318,48320,48317,48316,N,48310,58811,48307, +48323,N,N,N,N,N,N,N,48856,48857,59817,48866,48863,N,48854,48861,59819,48859, +48853,N,48860,N,59816,49339,48855,N,48862,49338,59815,59814,N,48864,N,48865,N, +59813,59812,49340,59822,48858,59820,N,N,N,N,49341,N,49346,60650,60652,N,49343, +N,60653,60649,N,60651,49344,49347,N,60648,49342,49345,49753,59821,49752,N,N, +49758,61396,N,49756,49757,61399,61395,49754,61393,50027,61397,N,61398,61394,N, +49755,62018,N,62021,N,N,62022,62020,62023,50028,62019,N,N,62542,50276,62541, +62540,62539,50275,50277,N,62925,50402,50401,N,N,63201,63200,63203,50635,50549, +63453,63202,N,N,63452,50637,50636,50675,63657,63727,42212,N,N,55666,59823,N,N, +42668,51959,42993,42991,N,42992,N,52417,43505,44102,N,52967,N,52968,N,44103, +53710,N,44740,44741,53709,N,N,N,N,45523,N,45519,N,54695,45526,45525,45518, +45521,45524,45520,N,N,55670,45517,46255,N,N,N,46257,46258,55669,55672,46256, +55667,55671,N,55668,N,46961,N,N,56764,N,N,47702,57844,48867,48324,58813,48325, +48326,58815,58814,58816,59825,N,N,59824,60655,60654,49348,49349,62024,N,N, +42213,N,N,N,N,55673,N,N,N,46260,46259,56765,N,61400,50403,63454,42214,N,44742, +N,45528,45527,55674,55675,46962,57845,47703,59826,N,42215,42424,N,43506,52418, +N,52969,44104,45529,N,55676,46261,46963,N,58817,58818,N,N,60656,49759,63728, +42216,N,52419,43507,44105,N,52970,N,44743,53714,53712,53713,44744,53711,N,N,N, +N,45531,45532,54696,45533,45530,55677,N,55678,56766,N,N,47705,47704,N,N,60657, +61401,N,62026,62025,62543,N,51550,44106,N,N,42217,42425,N,42670,42669,N,N, +42671,42672,51694,51693,51960,42994,51963,51962,51961,51964,N,N,N,N,43508, +52425,52421,52430,43515,N,43513,52426,52422,52429,43512,43584,52424,52420, +43518,52427,43511,52428,43514,43516,52432,52431,52423,43510,43509,43517,N,N,N, +N,N,N,52975,52981,N,44112,44109,52972,52977,N,44115,44107,52976,44110,44113,N, +N,52979,N,44108,52984,44111,N,44114,52973,52978,52982,52974,52971,N,N,52983, +52980,N,N,N,N,N,N,44752,44745,44748,N,44751,N,53717,N,44746,53715,N,44750,N,N, +44747,N,53718,44749,N,N,N,N,N,N,54700,45535,54699,54701,45534,45539,53716,N, +54698,54702,N,45536,54697,45538,N,45537,N,55719,N,55714,N,46262,46266,46263, +55717,55720,N,46264,N,46265,46270,56775,55718,46268,55715,55713,N,46269,N, +55716,N,N,N,46969,N,56767,46966,46967,46965,56772,56771,56768,46971,N,N,56770, +46267,N,N,56774,56769,46968,46964,46970,56773,N,N,N,47708,N,57848,57847,57846, +47706,N,N,N,N,N,47707,58821,58824,48328,N,N,48327,58825,58820,48330,58822,N, +48329,58819,N,58823,48873,48870,59835,59834,N,59833,59828,N,59829,N,N,N,48871, +N,48868,48872,59827,48869,59830,59831,59836,N,N,59832,N,N,60658,N,N,N,49351,N, +61404,49350,61402,61403,49760,50030,62027,N,50029,N,N,62545,62546,N,50278,N, +62544,50404,N,63455,50638,63658,63659,N,42218,N,42673,42674,42995,N,52433, +44116,44753,45540,N,N,45266,N,46271,46272,46028,55721,N,46972,57850,57849,N,N, +42219,42675,52434,43586,N,43585,N,52985,52986,N,53719,53720,44754,44755,N, +44756,54703,N,N,45542,N,46274,N,46273,56776,57210,57851,59837,N,N,49761,50279, +42220,N,42428,42429,42427,42430,42426,N,N,42678,N,51702,42677,42679,N,N,51697, +51696,51699,51698,51701,42676,51695,51700,N,N,N,N,N,51965,43005,51966,52035, +43004,N,52039,52034,52037,42997,42998,42999,43000,N,43072,N,52033,43002,43073, +N,52032,52038,N,43001,52036,43003,42996,43006,N,N,N,N,N,N,N,N,N,43607,N,52436, +43587,N,43597,43598,43590,43608,43592,52444,43603,52439,43593,52454,52455, +52447,52440,43606,52452,43601,43599,N,52453,N,52451,52443,52435,52442,43594,N, +43600,N,43588,52446,52445,52437,N,43602,52449,52438,43605,52456,43589,N,43596, +52441,52450,43604,N,43591,43595,N,52448,N,N,N,N,N,N,N,N,N,N,N,N,N,N,53083, +44124,44137,N,53078,53068,44130,53066,44123,53061,44133,53074,52990,53057,N,N, +N,N,53060,52987,53073,53089,44128,53062,53080,N,52989,53087,53088,53091,53082, +53067,53075,44134,44121,44129,44141,44118,44120,N,N,N,53059,44138,44131,53085, +53056,44140,44135,53065,N,N,44139,53072,53064,44132,53084,53076,N,44126,53090, +53063,44122,53081,53071,44127,53077,44119,52988,44136,44771,44125,53070,53069, +53058,N,53086,N,53079,N,N,44117,53740,44778,53741,N,53729,44767,44779,N,53722, +N,53731,53739,N,53721,53748,44757,N,N,N,53747,53742,N,53743,44765,44776,53733, +N,53734,53744,53735,N,53730,53724,53725,53738,53732,N,N,44758,44762,53746, +53726,44774,44770,N,N,44773,44780,44763,44775,53737,44777,44760,N,44759,53723, +N,53727,44768,53745,53736,53728,44772,44769,N,44761,44764,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,54724,N,54708,54709,54713,N,54728,54725,N,54718,54717, +45549,54721,54736,54704,N,54737,54723,54741,54729,45548,54727,45543,45564, +45554,N,45558,45557,54705,N,54734,54740,54732,54739,N,N,54720,54706,54738, +54722,45546,45559,N,54731,45552,N,N,N,54730,54707,45560,N,45562,54733,45563, +45545,54714,54735,N,N,45551,45561,54716,54726,54711,54715,45556,54710,45544, +45553,45550,54719,44766,55744,45547,N,N,N,N,N,N,N,N,N,N,N,N,N,N,45555,N,55747, +55769,55758,46294,N,46289,55741,46290,55757,N,55750,55763,46286,55723,55765, +46276,55731,46279,46278,N,46295,N,55725,55759,55760,46281,46277,55739,N,46288, +55734,N,55761,46284,55753,55766,55728,55733,55727,N,46283,55746,56798,55729, +46287,55738,55762,46282,55735,55732,55749,46285,46275,46297,55752,55751,55724, +46280,55764,55740,55742,N,55755,55754,55722,46291,46293,55730,55737,55745, +46292,55736,55748,55767,N,55756,N,N,N,N,N,N,N,N,N,N,N,N,N,55768,N,N,N,N,55726, +N,N,N,N,56818,47014,N,56816,56795,56800,56793,N,56812,56779,56786,N,56810, +56820,56796,N,56783,56802,56807,56787,N,56804,56784,N,N,56791,56792,47016, +56811,56809,N,56780,56814,N,56815,56817,47020,47012,N,54712,56788,56806,56789, +47009,47025,56813,47023,47019,56778,47011,N,56781,47024,N,56797,56777,N,47017, +56801,56785,47018,56794,46974,46296,56803,55743,56782,N,N,56808,47013,56805, +47010,56799,47021,56790,56819,N,N,N,N,N,N,47015,57030,N,N,47022,N,N,N,N,N,N, +57930,57928,N,57950,57926,N,57944,46973,47711,57922,57949,N,57927,57941,47716, +47709,N,57947,N,57920,57946,N,47727,57937,57953,47725,57929,47710,57931,57945, +47719,57924,47723,47713,57933,57923,57852,N,57943,47720,57952,57853,47717,N, +57939,N,47718,57925,57936,57932,57934,N,47712,57951,47726,57935,N,57954,N,N, +57854,57940,47715,47724,47722,57921,57942,47721,N,N,47714,57938,N,N,N,N,57948, +N,N,N,N,N,N,N,N,58837,N,58833,58829,58849,58846,48333,N,N,58853,58836,48344, +58843,N,N,58832,58842,48341,58862,N,58859,58845,58830,N,N,58850,58852,48337, +58840,58835,58826,48334,48342,N,58855,48343,58827,58861,58848,58854,48340,N,N, +58851,N,58858,N,48345,N,48339,58844,58831,58863,58828,58856,48336,N,58838,N, +58839,48335,48332,58834,48338,N,48331,N,58857,58860,58841,59850,N,N,N,N,N,N,N, +N,N,59842,N,59838,48886,N,N,48875,48880,48876,59852,59863,48874,59844,59853, +58847,59854,N,N,48881,N,59869,48885,48888,59840,N,48884,N,59867,59868,59858, +59857,59849,N,N,59859,59866,59865,N,48879,48877,59851,59848,N,59845,59864, +48887,59862,48883,48882,N,59856,N,59839,59841,59843,59861,59855,48878,N,59846, +N,59860,N,N,N,N,N,N,59847,N,N,N,N,N,N,N,49359,60741,49352,60661,N,60737,49354, +60744,N,60668,N,60663,N,N,60745,60659,60670,N,49361,60740,60746,60669,49353, +60736,60660,49360,N,N,60743,60665,49356,N,60667,60664,49362,60666,49355,49358, +60739,60662,60742,N,60738,N,N,N,49763,61415,49768,49769,N,N,N,49762,61414,N, +61411,61412,49766,61406,61410,49765,N,61407,N,N,N,N,49767,49764,N,61405,61409, +61413,N,N,N,62033,62030,62039,N,62038,62036,62031,N,50034,N,N,N,N,N,62032, +50033,49357,62035,50032,62040,62034,62029,61408,N,N,N,50031,N,62028,62550,N, +62549,62037,50280,N,62553,62554,62548,62552,N,62547,N,N,N,N,62929,62551,50407, +50405,62927,62930,N,62926,62928,50406,N,N,N,63205,63206,50550,63204,N,N,N, +63458,50639,63456,63457,63660,N,N,50774,63731,63729,63730,63732,N,N,N,63931,N, +42221,42680,N,43609,N,52457,N,N,53092,N,N,N,53749,53751,N,53750,N,53752,45565, +54743,53753,N,54742,54744,54745,55770,46299,55771,55773,46300,46298,55772,N, +56826,56824,56823,N,56822,56821,47026,56825,47728,57955,57957,47729,57956, +48347,N,48346,58864,N,N,59871,59870,59872,N,N,48889,N,60747,49363,N,61416, +49770,62041,50551,42222,42431,42681,43074,43610,43611,N,N,44142,N,N,53754,N,N, +N,N,47027,N,N,N,59089,48890,49771,42223,N,42682,N,N,52459,43612,52458,N,53093, +44143,53094,N,44144,N,53756,44782,44781,N,54750,54748,54749,54747,N,54746,N,N, +55774,55777,46302,55775,46301,55776,N,56827,N,N,57958,57959,57960,N,58867, +58866,48348,58865,58868,59873,N,N,59874,59875,N,60748,49364,49772,62042,N, +50408,51551,N,44145,53095,44783,N,N,45566,N,46303,55778,N,47029,47028,N,N, +57961,57962,48349,48350,59877,59876,61417,63459,42224,51552,42432,N,43075, +52040,N,44146,47030,42225,N,53096,44147,53097,N,49365,42226,N,N,52460,N,53098, +N,53826,53825,53758,N,53757,53827,53824,N,N,45632,45633,N,N,46304,55779,N, +55780,55781,N,N,N,56897,56898,56896,N,56829,56830,47031,57963,58871,58870, +58869,58872,59879,59878,48891,59880,N,49366,60749,N,61418,62043,63207,N,42227, +42434,42433,N,43613,51553,51582,42683,N,51703,52041,52042,43614,N,52461,N, +44148,53099,53100,N,44784,44788,53828,44787,44785,44786,N,54751,45634,46307,N, +46305,46306,55782,N,N,47730,42228,N,51617,N,42435,N,N,51620,N,N,42438,51619, +42437,42436,43076,51618,N,N,51704,N,N,N,51708,51710,51776,42693,42694,51707, +42689,N,51705,N,51709,42690,N,42685,N,42686,N,42692,51706,42684,43077,42687, +42688,42691,N,N,N,52059,52057,52044,43089,52051,43084,52045,N,52053,N,52050, +43087,52049,43094,52058,43096,N,43098,N,52043,N,43085,52060,N,43092,43095,N, +52549,43079,43102,43093,52046,43082,43097,52054,43080,43081,52547,52047,43088, +43099,52061,52048,43086,N,43091,52462,43100,52055,43090,N,43101,43078,52052, +43083,52056,52548,N,N,N,N,N,N,N,N,N,N,N,N,N,43626,43642,52469,43633,N,52555, +43618,N,43621,52546,N,52467,52471,43629,43631,52474,43638,43624,43622,43623, +43637,52551,43632,52473,52475,43630,43635,52476,52554,N,44149,43641,N,43619, +52553,N,52557,52472,52559,52544,43628,52468,43627,43645,43634,N,52466,53109, +43640,43644,52545,52550,N,43646,43639,43625,43615,N,43620,N,52470,43616,52558, +N,52464,52463,52477,52465,43643,44789,43636,52478,43617,N,44198,N,N,N,52556, +53116,53153,N,53156,53111,N,N,53159,53162,53164,53108,44150,44155,53833,44205, +53157,53165,53115,53107,N,N,N,53860,44158,53154,53112,53114,44197,N,53117, +44157,53104,53160,N,53163,N,N,44154,N,44200,53101,44202,44152,44206,53161, +53103,44203,53854,52552,44156,44151,53110,53102,44204,44196,53155,44201,44199, +53113,44193,53105,44194,44195,53106,53158,44153,53118,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,53836,44797,44867,N,N,N,53845,53851,53847,53834,53837,53830, +53831,44874,44794,53846,53855,44869,44790,N,44864,53838,44866,53839,53849,N,N, +N,44868,53864,53832,44796,44795,44872,53829,53862,53850,53863,53857,53843, +53858,N,53852,53861,53859,44873,53844,44793,44792,44865,44871,53856,44870, +53841,45635,N,53865,53840,53835,44798,44875,44791,N,53848,53853,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,45669,54753,54757,N,45650,45648,N,N,45639,54755,54754, +45659,N,54760,45653,N,54778,54855,45636,54775,54768,45671,54752,N,54780,N, +45668,45656,45667,45646,54764,54782,54774,45647,45641,54853,N,54781,54848, +45649,45657,54850,54762,54779,54767,54852,45662,45638,45660,54772,54770,54771, +45651,54766,54765,45640,54759,54854,45642,54769,45672,N,45666,54758,45663, +45661,45670,54776,45665,53842,54777,45664,54849,45637,54773,45655,54761,45654, +N,45652,45644,45643,55783,54851,54763,N,N,55804,N,45645,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,46401,45658,46318,55798,46332,N,55786,46315,46311,55881,46317, +46321,46316,46325,55885,55876,N,N,55793,46330,46324,55805,46308,55882,55875, +46312,55799,46327,55893,55894,N,46309,55880,46329,55803,55789,55790,46333, +55794,55801,55795,N,46331,46404,55791,55784,55785,N,55787,46314,55800,N,46328, +46402,N,N,55802,55891,55883,46310,55889,46322,N,46320,N,55895,46319,55873, +55796,55806,46407,55877,55874,55792,46403,55887,55884,55892,46313,55872,46406, +N,55879,N,N,46323,46326,N,55878,46405,55797,54756,N,N,55888,55886,55890,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,55788,46400,N,N,N,56929,56928,56902,47037,N,56927,56905, +56906,N,47047,56936,47042,56926,N,56899,47048,47038,56914,56904,56907,56931, +47032,56938,56930,47041,56919,47052,N,N,47051,47045,N,N,56937,47033,56917, +56908,56921,56933,47053,N,47035,56916,N,56909,47044,N,47043,56912,56922,56932, +56903,56913,47036,56923,47049,47040,56910,47039,56901,56915,56935,46334,47792, +56918,57964,56920,56934,47046,56911,47034,47050,48368,56900,N,56925,N,N,N, +56924,N,N,N,N,N,N,N,N,N,N,N,N,N,N,58026,47789,57981,58020,47778,N,57966,47791, +N,47735,57965,58032,47793,57969,58019,N,57971,58035,58031,47733,47777,58963, +47790,47741,57967,N,58030,47779,58027,58040,57973,57982,N,N,58038,58028,47740, +N,N,57980,47734,47732,47784,N,N,57978,57975,57976,N,58034,N,58039,58037,47738, +58041,47742,47783,N,57968,58874,57977,N,47736,47788,47785,47739,58021,57972, +47786,58023,47780,47782,47731,N,58025,58017,57970,47781,58033,58036,57979, +58024,N,47737,48351,58022,58873,N,58029,N,N,N,N,N,N,N,N,N,N,57974,58948,58958, +48354,58957,58969,48356,58955,N,58959,48367,N,58950,48359,N,58962,59888,48371, +48370,58964,58947,58974,48365,N,48355,58967,N,58971,58976,58965,58953,48358, +48361,48369,48364,N,58956,58018,N,N,58952,58975,48360,N,48363,58977,48352, +58966,58875,58972,49375,N,58954,N,48353,58949,48357,58876,47787,58945,N,58970, +58946,58944,48362,N,58968,N,58878,58961,58960,58973,58951,48366,N,N,N,N,N,N, +59891,N,48969,48894,59968,59883,48961,59895,48968,48963,59893,60751,59899, +59970,59898,59881,59896,59972,59974,48893,59973,48964,48970,N,48967,N,59902, +48966,59897,N,59885,59890,N,59901,48965,48962,48892,48960,59889,N,58877,59884, +59887,59969,59892,59882,60750,59971,59886,59900,N,N,N,N,60753,49379,N,N,49367, +N,N,49371,60755,60761,60759,49369,49370,49377,60762,60754,49372,N,60758,60757, +60763,49378,N,49373,49376,60756,49380,49374,49381,49368,60760,N,60752,N,N, +61431,N,N,49777,61428,61430,N,49775,61426,61427,61422,N,N,59894,61423,49776, +61419,N,49773,61432,49774,61420,61421,61425,49779,N,49778,N,N,61424,50040, +62047,62053,50041,62044,50038,50035,62055,50039,N,50036,62046,62049,62050, +62051,62054,N,61429,62045,50037,62052,62056,62048,N,N,N,62557,50282,62560, +50283,62568,62559,62556,N,62558,62562,62565,62564,62567,62555,N,50281,62563, +62566,62569,62561,62931,62932,62936,62937,N,62934,62935,62933,N,50409,N,N,N,N, +50552,63211,N,N,63208,63209,63210,50553,N,63461,63460,N,63663,50676,63661, +63664,63662,63733,50775,50789,63907,63852,N,63906,63952,63953,42229,N,N,N,N, +42695,51777,N,N,52062,N,43103,N,43106,N,52063,N,43104,43105,N,N,N,N,52568, +52570,52565,52562,52564,N,N,N,43684,N,N,N,43682,N,N,52566,43683,52563,52560, +43681,52567,N,52561,43685,52569,N,N,N,N,53167,N,53171,N,N,44215,N,N,N,N,53174, +N,44207,44210,44212,44214,44211,53170,53169,N,44209,53172,53173,N,53166,44213, +N,44208,N,N,N,53168,N,N,N,N,N,N,53879,53880,53881,44880,N,44876,53870,N,53878, +53883,44881,N,53868,53874,53867,53877,N,N,53873,44877,44879,53882,N,53866, +53869,53875,N,53876,53884,53872,N,44878,N,N,N,N,N,N,N,N,N,N,45677,54862,N,N, +54864,54860,N,54872,54858,54871,45673,54856,55899,54866,45676,N,54867,54870,N, +54874,N,54863,N,54868,N,N,45674,45675,54873,54861,54857,54875,N,54865,N,N, +54869,N,N,N,54859,N,46408,46409,55909,46415,N,55897,55906,55896,46412,55904, +55902,N,55903,46410,N,55907,N,N,N,N,N,55900,55898,46411,55901,55905,N,N,N, +46413,N,N,N,55908,N,N,N,N,N,N,56944,56951,56953,56993,N,47066,56939,N,47058,N, +56954,47063,56994,47054,N,56957,N,56941,56958,56940,N,47068,N,56952,47055, +56995,N,47060,56945,47065,56956,56943,56950,56946,56942,47057,47064,47062, +47059,47067,47056,56949,N,47061,N,46414,N,56955,N,56947,N,N,N,N,N,56948,N,N, +58049,N,47796,N,N,58045,58051,58047,N,47798,58046,58050,58042,N,58044,47797,N, +N,N,N,58048,58043,N,47799,N,47794,N,N,58052,N,47795,58983,58980,58992,58986, +58988,48372,58982,58990,N,N,58989,58987,N,58993,48375,58984,58991,N,48373,N,N, +58979,58981,48374,58978,58994,N,58985,N,N,59978,48977,N,N,59989,59987,48971, +59977,59980,59981,59976,48981,48982,59975,59990,59985,48975,48972,59984,59982, +N,N,48978,59986,48973,N,48974,N,59983,48976,59979,N,59988,48979,59991,59992, +48980,N,N,49383,49390,60764,60770,N,60768,49386,49385,49382,60766,N,N,N,49388, +49387,49384,N,60769,60765,60767,N,49389,N,N,N,49783,61435,N,49780,49781,61437, +49782,61434,61433,62060,61436,N,62061,50042,62059,N,N,62058,N,62057,50043,N,N, +50284,N,N,62570,62571,N,N,N,N,62940,62939,50410,N,62938,63212,63213,N,N,63462, +63665,N,N,63734,63932,50809,63942,42230,N,43686,43687,N,N,44216,N,N,N,N,49391, +42231,N,43688,44882,47069,42232,N,45678,47800,51554,N,53175,53885,N,58053,N, +49392,42233,43689,53176,53177,55910,46416,N,N,56996,N,N,47070,58054,N,N,48376, +N,50044,42234,55911,42235,N,42697,51778,42696,43109,43108,43107,52064,N,N,N, +43690,N,43691,52571,N,53178,N,53181,44218,53179,N,44217,53180,44219,N,53922, +53921,53886,44883,N,54877,54878,45679,54876,54879,46418,45680,N,N,46417,55915, +55914,N,55912,55913,N,55916,56998,56997,57001,N,57000,56999,47801,58057,N, +58056,47802,58055,58995,N,58996,48377,N,59993,59994,N,N,62066,50045,62065, +62064,62062,62063,50411,62572,63214,63735,N,42236,N,51621,42439,51622,N,N,N, +51779,51780,N,N,N,N,52070,N,N,52066,N,52065,43692,52069,43111,52067,43110, +52071,52068,N,N,52575,53182,52573,52580,N,43693,N,43696,52581,52577,N,52578,N, +52572,43695,52574,43694,52579,N,52576,N,N,53186,44221,44222,N,53189,53183,N, +53188,N,53184,44220,53187,53185,N,N,N,N,N,N,N,53928,53925,N,53927,44888,44887, +44885,53924,53929,44884,44886,53926,54887,53923,53930,N,N,N,N,N,54882,54886,N, +54885,55918,55929,N,N,54888,N,54883,55917,45684,N,N,45683,54881,54884,45685,N, +45682,45681,54880,54889,N,N,N,55920,55927,N,46420,55926,55923,N,46422,N,N,N, +55925,N,N,55919,55921,55924,55922,46421,55928,46419,47071,N,N,57005,57004, +57002,N,47074,47073,57006,N,57003,58058,47803,47072,N,N,N,57008,57007,N,58061, +58059,48378,N,47804,58060,58998,N,N,N,N,48379,58997,59006,59005,59003,N,59002, +58999,59000,59001,59004,59041,N,N,59999,59996,59997,48983,59995,60001,60000, +59998,N,60772,60773,49393,N,49394,60771,N,49785,61438,49784,50046,N,50081, +50285,62574,62573,62941,63215,50554,63464,63463,63465,42440,53190,44889,45686, +54890,42441,51623,42237,N,N,51781,N,N,N,52076,52074,52075,52072,43112,52073,N, +N,N,N,N,52589,N,43699,52587,52583,52586,N,52582,43701,52585,N,43698,43697,N, +43700,52588,52584,N,N,N,N,44226,44229,53198,53197,53196,44223,53205,53195,N, +44225,53935,N,53202,53200,44228,N,53192,53203,N,53194,53204,53201,53193,N, +44224,53206,53191,44227,N,N,N,N,53940,53931,53942,N,53934,53945,53946,53932, +53944,53941,53939,53943,44895,N,44893,N,N,53937,N,53933,N,53936,53947,53938, +44894,53199,N,44890,44892,N,N,N,N,N,54904,54893,54891,N,54892,N,54899,N,54900, +54896,45691,54901,54898,54895,N,45689,54894,45687,45690,54897,54905,44891, +45688,54903,54902,45692,N,N,N,N,N,N,N,N,55934,N,N,N,55969,46432,N,55975,N,N, +55977,55970,46426,55974,55973,46427,46433,N,46434,55976,46424,55933,55931, +55971,55930,46431,55932,55972,55978,46425,46430,46428,46429,N,N,N,46423,N,N,N, +N,47081,57015,47080,57019,N,57009,N,57020,N,N,N,57010,57011,N,57021,57018, +57016,57017,57013,57012,N,57022,47077,N,57014,N,47082,47076,47083,47084,N, +47079,47078,N,N,58062,47806,47805,N,N,58067,N,48380,47807,N,N,47809,58068, +47075,47808,58064,58066,58063,N,58065,N,N,N,59051,N,N,59050,59047,48448,60002, +48449,59046,N,48382,N,59048,59045,59042,59049,59043,59044,48381,N,N,N,N,60777, +N,60006,N,60005,60007,N,60774,48986,N,60003,N,48984,N,48988,48987,60004,60008, +N,48985,N,60781,49397,49786,49398,49395,60778,60776,N,60779,N,60782,49396, +60780,60775,N,N,61506,61509,62069,61504,N,62575,61510,N,50082,61508,49787, +61505,61507,61511,62070,N,62068,N,N,N,N,50083,62067,N,N,N,50286,N,N,N,N,50413, +63217,50412,63219,63216,63218,50640,63666,42442,52590,53948,53949,45693,57023, +48989,50084,50555,63667,42443,N,52591,41568,N,N,53207,N,53208,N,N,N,N,N,53950, +53951,45694,45729,N,N,N,55979,N,57026,57025,57024,58069,N,58070,58071,47810,N, +N,59053,59052,N,N,60009,48990,48991,N,60786,60783,60784,60785,61513,61512, +49788,62071,62942,42444,N,44230,N,45730,57027,N,42445,N,53952,45731,N,N,46435, +46436,N,42446,42447,51782,43114,43113,44231,53209,55980,42448,42449,42450, +42451,N,N,N,43115,43116,52078,52077,N,N,43702,52594,52592,52593,N,N,N,N,N,N, +53210,53211,N,N,44235,44233,N,44234,44232,N,N,N,N,44896,N,N,N,N,44900,44899, +53953,44898,44897,N,53954,N,N,45734,54907,54906,45732,45733,N,N,N,46438,46437, +55982,N,N,55981,45735,N,N,N,N,N,47085,57029,47086,57028,N,N,N,58072,59054, +48450,60010,N,N,N,60787,N,50086,50085,N,N,50556,42452,52595,N,N,45736,58073, +47811,N,N,52079,52080,N,N,52596,43704,43705,N,N,43703,N,N,N,N,44239,44240, +44237,44238,N,53212,N,N,53213,44236,N,N,N,N,53955,N,44904,44905,N,45739,53961, +N,44910,44908,53962,53957,44907,44906,44901,53960,53959,53956,44909,N,53958, +44902,N,44903,N,N,45740,54945,54946,45741,54908,54910,54948,54947,54909,N, +45737,45738,N,55990,46443,46442,55984,46440,N,55987,46444,55988,46445,55985, +46439,46441,55989,N,55986,55983,N,N,N,N,N,57042,N,57031,47088,47091,47090, +47095,47094,57043,57041,57034,57038,57037,47092,57040,57036,57044,57035,47093, +47087,47089,N,57033,N,N,N,N,58075,47815,58079,47814,58076,47813,N,57032,57039, +58078,N,47816,58080,58077,58074,N,N,59057,59061,59063,59059,59058,59056,48453, +48451,48456,48457,59060,48454,59055,48455,47812,59062,48452,N,N,N,60012,N, +60011,60019,60013,60018,60015,48992,60017,N,N,48993,N,48994,N,60016,60014,N,N, +N,N,49400,60788,N,N,49399,60791,60789,60790,N,N,49401,N,N,N,61517,N,49825, +61518,N,N,49789,61519,49790,61516,61520,N,61514,N,N,50087,62072,50088,50287,N, +61515,50288,N,N,N,50414,62943,N,50558,63220,50557,N,63466,50677,50678,N,N, +63948,N,N,44241,53214,N,46446,46447,42453,42698,51783,N,52081,43117,N,43706,N, +44242,44243,44244,54950,53963,44911,N,N,45742,54949,N,N,55992,46449,N,55991, +46448,N,N,57045,48458,59067,59064,59065,59066,N,N,N,N,N,60792,N,61521,N,N,N, +62577,62576,N,63221,42454,52597,44912,N,N,N,46450,57046,N,N,58081,N,48459, +60020,N,61522,62578,42455,N,N,43707,44247,53215,44248,44246,N,44245,53964, +44913,N,N,44914,44915,N,N,N,45744,54951,45743,N,N,N,N,N,55993,45745,46451, +57047,47096,47097,N,47817,N,47818,48460,48996,60021,48995,N,60793,49402,N, +61523,62579,42456,43118,52600,52599,43708,52598,43709,52601,N,53221,44251, +44250,53223,53222,44255,N,44254,44249,N,53217,53218,53219,N,44256,53216,44252, +53220,44253,N,N,N,N,53967,53971,53969,53968,N,53972,N,N,N,53973,53974,53966,N, +53965,N,44917,44918,N,53975,53970,N,54960,N,53976,44919,44916,N,N,N,54954,N, +54953,N,54955,54956,54958,54957,54962,45749,45746,45750,54952,45751,54961, +45748,54959,45747,N,N,N,N,N,55996,55998,55994,55995,N,N,55999,56001,56002, +55997,56000,46452,N,N,57051,N,57056,57048,57052,N,N,57057,57053,47098,47171,N, +47101,57049,57050,47822,47174,47102,N,47172,47100,57055,47173,57054,47169, +47099,47170,57058,58086,58088,N,N,N,N,N,N,N,N,N,47168,N,N,58083,47820,58089, +47821,58087,58082,58085,58090,47819,58084,N,48462,59071,59070,N,48465,48463, +59068,48461,59069,N,48464,N,N,N,60029,N,60065,N,60030,60022,60026,60025,60023, +48998,48999,48997,60024,60027,60028,N,49000,N,49472,60835,N,49404,60795,49406, +49473,N,N,49405,60834,60796,49403,60833,60794,60798,60797,N,N,61525,49828, +49829,49826,N,49827,N,N,61524,N,62075,N,N,50089,N,62073,62074,N,62580,62583, +62581,62582,62944,N,N,50415,63467,63668,N,50679,63736,63737,50790,42457,44257, +N,56003,N,57059,N,42458,43119,N,43710,N,53224,53225,44920,N,N,56004,46453, +47175,49474,60836,62076,62584,42459,N,N,N,52641,52602,52604,52606,52605,52603, +43711,44258,53234,N,53229,53226,N,N,53233,N,N,44260,44261,53232,53231,53230, +53227,53228,53235,44259,N,N,N,N,N,N,N,N,44924,N,44964,44963,53985,53979,53977, +N,44961,54969,44922,53982,53986,53988,53984,53978,44962,53983,53981,44921, +53989,44965,53987,44925,53980,N,44926,44923,N,N,N,N,N,N,N,N,N,N,45753,N,54970, +N,N,54963,54965,54967,N,54968,54966,45754,N,54971,N,54964,N,N,N,N,N,N,N,N,N, +56008,46454,56016,N,56005,N,56017,N,56006,56007,N,N,56015,56014,56011,45752, +46455,56009,56012,46456,56013,56010,N,N,N,N,N,N,N,57070,N,57074,47182,N,58096, +47185,57072,N,N,57069,57064,57066,57067,57060,N,47181,N,N,47180,N,47176,57063, +N,47183,N,47184,57062,57065,57073,47178,47179,57071,57061,N,N,N,58098,47824, +58100,57068,58102,47828,58103,58099,N,47825,58095,47827,58092,58097,58101, +58094,N,N,47177,N,58091,47826,58093,N,N,N,N,N,48468,59073,48472,N,48470,N,N, +47823,N,59080,59081,48467,N,N,59079,59082,48469,48466,59075,59072,59077,59074, +48473,59076,N,N,59078,48471,N,N,N,N,49002,60072,N,60066,60070,60076,60077, +60073,60074,60071,N,60068,N,49004,49001,60067,60069,N,49003,60075,N,49478,N,N, +60842,60837,49477,N,N,49475,N,60844,49476,60840,60841,60838,60845,61526,49479, +60839,N,60846,60843,N,N,N,61530,N,N,61527,N,49830,N,61531,61533,61532,61528, +61529,N,N,62115,N,50090,N,62078,62114,62077,62116,N,N,62113,N,62586,62589, +62585,50289,62587,62588,62590,50290,50292,50291,62945,N,62947,N,62946,N,N,N, +63222,N,N,63669,63738,42460,N,N,52082,43712,52643,43713,43714,52642,N,53240, +53239,44262,44265,44264,44263,53236,53238,53237,N,N,53992,44967,53996,53995, +53994,53990,44966,44970,44973,N,N,44974,53991,53993,44972,44971,44969,44968, +54978,N,54976,54972,45755,N,54973,45756,54974,54975,54977,N,45757,N,N,56021,N, +56020,56019,56018,N,N,N,N,57078,47186,N,57075,57077,N,47187,N,47188,57076,N,N, +N,N,N,58177,N,58105,58106,N,47831,47829,47830,58179,N,58178,58110,58109,58108, +58107,58176,58104,N,59083,59088,59086,N,N,N,59085,59084,59087,N,60078,N,49005, +49480,60848,N,49481,60847,61535,61534,49831,N,62117,50091,62625,50593,63223,N, +63671,63670,51624,44266,44267,54979,N,47190,42461,43122,43121,43120,N,N,N, +52644,N,N,43716,43715,N,44270,N,53242,53245,53243,N,44268,44269,N,N,53241, +53244,N,44981,N,N,N,54003,54005,54004,44978,53999,N,N,44976,44975,N,44979, +44977,N,44980,54002,53997,53998,54001,54000,N,N,N,N,N,N,N,54982,54983,54981,N, +54980,45758,46461,N,56022,56024,56026,46460,N,N,46458,N,56023,46459,56025, +46457,N,N,57153,57079,57082,57086,47194,57084,N,57083,57080,57081,47192,57152, +47191,N,47196,47195,47193,N,57085,N,N,N,58185,N,58184,N,N,58180,N,N,47832, +58183,58182,47833,N,N,N,N,N,48478,N,59090,N,48479,48475,48477,N,48474,48476,N, +N,N,60079,N,49008,60081,60080,N,58181,49010,49009,49006,49007,N,N,N,N,N,60853, +N,60851,49482,60852,N,60854,60850,60849,N,N,61536,49834,49832,49833,N,N,N,N, +62118,62119,50093,N,50092,62627,62628,62626,N,63224,63225,N,N,42462,51784, +43123,N,52645,43718,43717,52646,N,N,53312,44271,53246,44272,N,N,44982,54008, +54006,54012,44983,54007,54011,54009,54010,N,N,54984,54986,N,45759,N,54985, +45760,46498,46497,46462,56027,N,N,N,N,57156,47197,47198,N,57155,57154,N,N,N,N, +58186,47835,47834,58187,58188,N,48481,48480,N,60085,59091,59093,59092,60084, +60082,60086,60083,N,49011,N,N,N,60855,49483,60856,60857,N,N,49835,49836,N, +50293,N,N,50641,42463,N,N,N,N,N,53313,N,N,N,N,N,N,54013,44984,N,N,N,N,N,46010, +46009,N,N,46500,56029,46499,56028,N,N,N,N,57157,N,47836,58189,47837,N,N,N,N,N, +N,50294,62629,N,42699,43719,52647,N,44274,N,44273,53314,53315,N,N,54080,54082, +44985,N,54084,54087,54085,N,N,N,54086,54083,54014,44986,54088,54081,N,N,N,N, +54995,45766,55004,45763,N,54997,45767,N,45761,N,54992,55005,54993,54990,45765, +N,45762,N,54996,54999,45764,55000,45768,55001,54991,54998,55002,54994,54989, +54987,N,N,55003,N,N,56031,N,N,N,N,56036,N,N,N,56032,56038,46503,54988,56033, +46501,56030,46508,56034,46507,56035,46509,46504,46510,46505,N,46506,N,46502,N, +56037,N,N,N,N,N,N,N,47201,57168,N,57171,57159,57164,57158,47203,N,57162,N,N,N, +57160,47202,N,57167,57166,57163,57165,57161,47841,57170,47199,57169,N,N,N,N,N, +N,N,N,N,58205,N,47848,58200,N,47847,58190,N,58192,47840,58197,58196,58199, +47845,58194,58193,N,N,47844,47839,58195,47842,58201,58203,N,58198,58191,47843, +N,N,48489,47838,N,N,58204,N,N,N,N,N,N,N,59097,48482,N,59099,N,48483,N,N,48485, +59102,N,59094,47846,59100,N,N,N,N,59096,N,47200,48488,N,N,48484,N,48486,48487, +N,49014,59101,59095,48490,N,59098,N,N,N,N,N,60096,60091,N,N,60101,49012,60093, +49016,60099,60090,60087,60102,49489,49017,60098,60088,49015,60092,49019,60089, +60094,49018,60097,60100,N,N,N,N,60875,60876,60860,60867,60865,N,N,49487,60872, +60095,N,60863,N,60873,49486,60862,60861,60871,60868,60870,N,60858,60874,49484, +N,60869,60878,60866,49488,49485,60864,60859,60877,49013,N,N,N,N,N,N,N,61539,N, +N,61537,61543,49840,61541,61540,49842,61546,49841,N,61547,61544,49838,61545, +61538,49839,49837,62123,61542,N,N,61548,N,N,62120,N,N,N,50098,50096,62122,N, +62124,62121,50097,50094,50095,50099,N,N,50296,N,62634,N,62633,62631,62630, +62632,N,50295,50297,N,N,50416,N,N,62949,62948,N,N,63226,N,63228,63230,63229, +63227,N,N,50595,50594,N,N,50643,50642,50644,63469,63468,N,63739,63672,63740, +50776,N,50777,63853,N,N,50814,42700,N,52648,N,N,53317,53318,53316,N,N,44275,N, +53319,53320,53321,N,N,54089,54095,N,N,54093,44987,54091,N,54092,54094,N,N,N, +54090,45769,N,55006,45771,55008,45770,55007,N,N,N,N,N,56040,46511,N,56042, +56039,55009,N,46512,N,N,56041,N,N,N,N,N,N,57174,N,47204,57172,47205,57173, +47206,N,N,N,47849,58209,58206,58208,47850,47851,58207,N,N,N,N,N,59103,N,N, +59104,N,48491,59106,59105,N,41569,N,60106,60107,60103,N,60104,49020,49021, +60105,N,49495,N,N,49491,49496,49492,49494,49490,N,49493,N,N,N,N,49843,60879,N, +62126,N,62125,N,62635,50298,50299,63297,62950,N,63296,N,63741,63908,42701,N,N, +43124,N,52649,43720,44278,53324,44276,53322,44281,44277,44282,44280,53323, +44279,44991,44990,54106,44999,54099,54105,44995,54098,54104,54102,44994,44996, +54101,44989,54100,45000,44997,45001,44998,54097,54096,54103,44992,44988,44993, +N,N,N,N,N,55024,55017,N,46517,55016,N,45775,45782,45779,45785,45784,45780,N, +55010,55013,N,55012,45776,55014,55023,45777,55011,55020,55021,45778,55018, +45783,45773,45781,55015,45772,55019,N,N,55022,N,N,N,56059,56050,46514,56057, +56054,56046,56055,46516,56047,N,56043,N,N,47212,56052,N,46513,56058,N,46520, +46522,56045,N,N,46521,56048,46515,56056,56049,56053,N,56051,46518,56044,46523, +45774,46519,46524,N,N,N,N,N,47208,57181,57183,57185,57189,N,57179,57177,47210, +N,57184,57188,57180,57176,N,57175,N,N,N,57186,57178,57182,47211,N,47209,57190, +47207,57187,N,58226,N,N,N,N,N,47854,58218,48504,58228,47857,58232,47863,58213, +N,N,58229,58210,N,58231,58214,N,47870,47867,58230,58224,47853,47861,47860,N, +47859,47865,N,58211,47866,58225,47862,47852,58227,47855,47856,47864,58216, +58215,58212,N,58220,58217,58221,47869,N,58233,47858,58222,58223,N,58219,N,N,N, +47868,N,N,N,N,59111,48496,48505,48501,59108,N,48498,48502,59120,48492,59112,N, +48500,N,N,59115,59110,48499,48503,59109,N,48497,N,59119,48494,59118,59117, +48506,58738,48493,N,59116,59107,N,48507,59114,48495,59113,N,N,N,N,49058,49063, +49022,60120,60111,60123,60115,60121,49064,49057,60108,60114,60124,60117,60122, +60110,N,N,60118,49059,60116,49062,49061,60112,60113,60109,60119,49060,60126, +60125,N,N,N,60890,60886,49503,N,60880,49497,49513,60892,49505,49501,60883, +49508,49511,60894,49500,60885,49509,60896,60893,60881,49504,49498,49512,60888, +49507,60882,49502,60895,49506,49499,60889,49510,60887,N,N,60891,N,N,N,61550, +61556,49849,61559,49844,49845,61551,61558,61553,49850,49847,N,61549,N,49846, +61555,61557,49848,61554,61552,N,N,N,N,62136,50103,50104,50100,N,50101,N,62132, +62130,N,62134,50106,62135,62128,62127,62131,62129,50102,62133,62636,50302, +50301,62637,N,62639,62638,50337,N,N,N,62955,62952,62953,N,62951,62954,50418, +62956,N,50417,N,63298,N,50645,50647,63470,50646,63673,63808,63810,63742,63809, +50796,42702,N,44283,53871,45002,N,N,45786,56060,56061,N,N,N,60127,49514,60897, +N,N,49851,N,62138,62137,50338,62957,N,63299,50680,51785,N,N,43721,43125,N,N, +53325,N,N,54112,54107,54111,54109,45003,54110,54108,N,55025,N,56062,56128, +57193,57194,47214,47215,57192,57195,57191,47213,N,47936,N,47216,58234,N,48508, +59121,48509,N,49065,60130,60128,60129,60900,60899,60898,N,N,N,62139,N,50105, +62140,63300,50681,63674,42703,43723,43722,53327,44284,N,N,53326,54114,N,45004, +55026,54113,N,N,N,45788,55029,55027,55028,45787,N,56130,56131,56129,N,47219, +57197,57196,57198,47218,47217,N,N,59122,59124,N,48510,59123,60131,49066,61561, +N,61560,50107,62141,50109,50108,62640,62958,50419,42704,53328,44285,54117, +45006,54116,54115,N,45005,N,55035,N,55037,55030,55031,45789,55032,45790,55036, +55033,55034,45791,N,46526,46527,N,56132,N,N,N,57199,57200,N,58238,47939,47937, +47938,58235,58236,N,58237,59129,N,59130,48545,59127,59126,59128,59125,49069, +60132,49067,49068,60902,49515,60901,61352,N,61562,61563,49852,N,49853,49516, +62142,62143,62641,50339,42705,N,42706,44286,43724,45007,53329,N,N,N,46528, +42707,44353,53330,53331,44352,44354,42708,N,53332,45009,54118,45011,45008, +45010,N,55105,45792,N,55104,55038,N,57201,N,N,58273,N,48546,N,49070,60134, +60133,N,60903,N,N,N,62959,N,N,42709,52083,52650,44355,53333,N,54120,N,N,N, +45012,54119,45013,N,N,N,55107,N,N,45794,55106,55108,N,45793,N,N,N,N,56134, +56135,56133,46529,N,N,N,47220,N,47221,N,47941,N,58275,58274,47940,N,N,N,N,N, +59131,N,N,59132,N,N,N,N,60135,N,N,49520,49519,49517,49518,49521,N,61564,49855, +49854,62144,62642,N,N,N,50597,50596,42710,N,N,53755,N,47223,46530,47222,47942, +N,42711,51625,42712,42713,N,N,52651,52086,N,52087,43127,N,52084,43126,N,43129, +52085,43131,43130,52088,43128,N,N,N,43729,43727,52653,N,43726,N,N,N,43731, +43733,43730,N,52656,52652,43734,N,43728,43132,N,43732,52655,N,N,52654,N,43725, +N,N,N,N,N,N,N,53339,44359,44360,53341,N,53335,53338,53347,53345,N,44361,53351, +44364,53348,53340,53337,N,N,56137,53346,44356,53349,53334,53343,44358,44363, +53344,44367,44365,N,53336,44362,N,53342,44366,44357,53350,N,N,N,N,N,N,45018,N, +45027,45016,45014,54122,45022,45019,54124,N,N,45021,54123,54121,54126,45026, +45024,56136,54127,54125,45015,N,N,45017,45020,N,45023,N,45025,N,N,N,N,N,N,N,N, +N,N,55118,45796,N,55109,55111,N,55112,N,55120,55116,55114,N,55117,55121,45797, +45801,55110,N,55119,N,45799,N,45798,55115,55113,N,45795,45800,N,N,N,N,N,N,N,N, +46536,56145,N,N,56143,46538,N,N,N,N,56138,57249,N,46537,56142,N,N,56139,46533, +46539,56144,46535,56141,47943,46534,56140,46540,46532,46531,N,N,N,N,N,57207, +57205,N,57211,N,57203,57250,57208,N,57202,47227,47267,57213,N,57206,N,47230,N, +N,47228,57214,47225,47224,57209,47229,46541,N,57212,57204,47226,47265,47266,N, +N,N,N,47948,47944,N,47949,58278,N,N,58277,58279,47946,58276,47947,58282,58281, +58280,N,47945,N,N,N,N,N,59201,N,59204,48552,59203,48551,48547,48548,48549, +59200,59134,48550,N,59202,59133,N,N,60137,60147,49073,49072,N,60141,60143,N, +60138,N,60142,60136,60145,49071,60144,60140,N,60146,N,60139,49524,60904,60910, +49528,49530,49527,49526,N,49525,49523,60905,60908,49522,60909,N,49529,60907,N, +60906,49856,N,49857,61601,61565,61566,N,N,62146,N,62145,50110,62644,50340, +62643,N,62960,63301,50598,63811,63812,50648,42714,N,43735,56146,47950,49531, +60911,42715,N,45029,45028,56147,N,N,N,60148,42716,44368,N,N,56148,56149,56150, +47951,49074,42717,N,43736,53352,45030,54128,45802,N,56151,47268,N,47952,49075, +49532,49858,62645,42718,43737,N,N,45031,55122,46542,N,47953,58283,59205,N,N,N, +N,42719,46543,57251,47954,42720,52657,53353,44369,N,N,54130,N,N,45034,N,45032, +45033,45035,N,N,54129,N,N,55127,55124,55126,45803,45805,45804,55123,45806, +55125,N,56152,56153,N,56154,57254,N,57255,N,57253,57256,N,47269,N,57252,N, +47955,N,N,59210,59206,59209,59211,59208,59207,N,60149,60150,60151,49076,49077, +60913,60912,60914,N,61603,61602,N,62148,N,62149,62147,N,50341,N,62646,62647,N, +63302,63471,63675,42721,43133,N,49533,42722,N,55128,56155,N,50753,51786,N,N,N, +51787,51789,42723,51790,51788,N,N,52130,52131,52091,N,N,N,N,52129,43169,N, +43170,52092,52090,52089,52093,43134,52094,53354,N,N,N,52662,43740,52661,52663, +N,43739,52668,43743,52658,52672,52678,43750,52675,43747,N,52665,52671,52673,N, +52660,43746,43741,52666,43748,43751,43745,N,43738,52670,52664,52677,43753, +43749,43744,52669,45036,52667,43742,43752,N,52659,N,52674,52676,N,N,N,N,N,N,N, +N,N,N,N,N,N,44386,44380,44388,44385,53361,53364,44381,N,53355,N,44374,44384,N, +44387,44389,53410,53367,N,44373,53409,44377,44375,44370,53359,N,53374,53363, +53366,53413,N,44390,53373,44382,53368,53412,53365,53369,53372,N,N,53357,53411, +53371,N,N,53356,53360,44383,44378,44371,44376,44372,44391,53358,54181,44379,N, +N,53370,52801,N,N,N,N,N,N,N,N,54184,45050,N,54134,N,54179,54141,N,54194,N, +54186,N,54142,N,54185,54136,54140,54197,45053,54189,54180,45037,54195,54132,N, +54188,N,45052,45047,54131,45045,45044,45049,54187,45041,45048,53362,56156, +54182,N,N,54138,45051,54139,54177,45054,54133,54191,N,54190,54198,45043,45040, +54196,54192,54183,54178,45046,45042,54135,45038,54193,45039,N,54137,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,55134,55136,55141,55161,45820, +45810,N,55133,45821,45822,55144,55151,55157,N,55138,N,55145,N,N,45888,55159, +55154,45818,45816,55150,55146,55132,45807,55137,55129,N,45815,45817,55142, +55139,45812,55155,45809,55140,55162,55148,N,55147,45808,N,45819,N,45811,55130, +55135,55152,55158,45889,55131,55143,55149,45814,N,N,55160,55153,55156,N,N,N,N, +N,N,N,N,N,N,N,N,45813,N,56172,56160,46551,56189,56231,56234,46549,56168,56227, +56169,56183,46562,56179,46559,N,56180,56157,N,56228,N,N,46568,56225,56181, +56236,56176,57288,N,56239,46566,56174,56186,46569,46548,56178,56237,56171, +56164,56175,N,56163,56161,46544,56229,56170,56232,N,56233,46552,46557,46553, +46561,56190,46554,56182,56166,N,46546,56158,56226,56235,56165,46560,56240, +56177,56173,N,46545,46565,N,56188,46567,N,56184,46556,46550,46558,46547,46564, +56185,56167,56187,56162,56230,N,N,N,N,N,N,N,56238,N,N,N,N,N,N,N,56159,N,N,N,N, +N,57287,N,57309,47189,57292,N,57290,57269,47273,57285,57305,57281,47281,57304, +57279,46563,57295,57280,57302,47280,47272,N,57258,57266,N,57291,57283,57308, +57286,47286,57303,N,47277,N,57289,57297,57270,57296,N,57313,57265,57298,N, +57311,N,57259,46555,N,57273,57272,47279,N,57276,57278,57293,57310,47282,N, +47283,N,57264,47275,57268,57306,47284,N,47276,47278,47285,57312,57299,57294,N, +N,57275,57274,47274,57260,47271,57284,57261,57282,N,N,57271,57307,N,N,N,47270, +N,N,N,57267,N,N,N,N,N,N,57263,57301,57262,47968,58323,N,N,58306,N,N,58284, +58314,47960,58299,58309,47963,58302,47961,58287,58317,58286,58305,N,58285,N,N, +58303,58312,58310,58298,58293,58291,N,58292,58311,58322,58300,47962,N,58295,N, +58315,N,47965,58294,58288,58304,47969,N,N,47957,47966,58296,58290,N,47959, +57300,47958,58307,N,47956,47971,47964,58308,58297,58289,58316,58301,47970, +58320,47967,58319,N,58313,58318,N,N,N,58321,N,N,N,N,N,N,N,N,N,N,N,59251,59252, +59239,59238,59234,48564,N,48556,59254,59253,57257,59231,59235,59229,N,59248, +59233,N,59255,59226,59224,59236,59246,59241,48566,59215,N,59245,N,N,N,48567, +57277,59227,59218,59221,59259,59228,59219,59217,59214,N,48560,59237,48559, +48563,59232,59240,48553,59256,59260,48555,N,59223,59243,59247,59220,59257, +48562,N,48561,59212,48565,59250,59222,59242,59216,59230,59225,48557,48558, +59244,59261,59258,59249,N,N,N,N,N,N,N,N,N,59213,N,48554,60233,N,60224,60227,N, +49083,60229,60153,60225,60231,49080,49084,49078,N,N,60155,60236,N,N,60230,N, +60156,60245,60239,60152,60998,60158,49079,N,60234,N,60244,49087,N,60241,60157, +60228,60232,60226,60246,60243,60240,49081,49082,49086,60154,60247,49085,60237, +N,N,60235,N,N,N,60238,61011,60992,60997,61010,60996,60923,60993,N,49570,N, +60916,61005,61007,60915,49569,61009,61001,49576,61008,60994,49578,60921,60242, +61002,60999,60917,61013,49572,N,N,49573,60919,61000,N,61012,61003,60925,49575, +49571,61004,60926,61014,60920,60995,61006,60922,60924,N,49867,60918,49577, +49860,49534,N,N,N,N,49574,49864,61619,N,61609,61604,61610,61620,61624,61623, +49866,49865,N,N,61611,61625,61614,61606,N,61608,61607,61613,61618,61605,61612, +61617,49863,N,61615,N,49861,61616,49859,49862,62165,61621,N,N,50114,N,62157, +62161,62153,62156,N,62164,50112,62169,62162,N,62154,62170,62163,50115,50116, +62167,N,62155,50111,50113,62150,62158,62152,N,62168,62166,62151,62159,N,N,N, +62654,50117,62160,50343,50345,50342,N,62659,62651,62649,62653,62650,N,N,62655, +62657,50346,50348,N,62656,50349,50347,62658,N,N,N,N,50344,N,N,N,N,N,50420, +62961,62967,50422,62652,62966,N,62973,62964,62971,62970,62648,62965,61622, +62974,62963,62968,N,62972,62962,N,63306,50421,62969,N,N,63476,63307,63305, +63303,63304,63308,N,50649,63474,63472,63477,63475,N,63478,50650,63473,N,N, +63676,N,N,63813,63814,63815,N,N,63943,63933,51791,43754,N,44392,N,54200,54199, +45120,45890,55164,N,N,55163,N,46570,47288,N,47287,47289,N,58324,59262,60248, +60250,60249,N,49579,61015,61626,63909,42724,N,52681,52682,52680,52679,43755,N, +53417,53415,N,N,53414,N,44393,44395,44394,53416,N,N,N,N,N,N,N,N,54212,54209, +54207,N,N,45121,54210,45126,54204,54219,N,54221,54205,N,45123,54222,54217, +54203,54208,54218,54214,54211,N,45128,54220,54206,N,N,54215,54201,45127,45124, +54213,N,54216,54202,45125,45122,N,N,N,N,45900,55205,45899,N,55208,55211,45896, +45894,55166,55209,55207,55204,55212,55213,55215,55216,55165,45893,55202,55201, +55214,45895,55203,45897,45892,55206,45901,N,45898,55210,N,N,N,46577,56255,N, +56244,46574,N,57319,56253,56241,46572,56246,46575,56250,56248,46578,46571,N,N, +56242,56245,46576,N,56243,N,56254,56252,56247,56249,56251,46573,N,N,N,N,N,N,N, +57320,57326,57316,57322,47290,57318,47296,N,N,47295,47294,57325,47297,47298, +57315,57328,47299,47293,47292,57324,47300,57314,57317,57327,57323,N,N,58356, +58345,47291,N,N,N,N,47978,58333,58354,58334,47973,N,58331,N,58340,58332,47975, +58326,58353,47976,58350,58351,58327,47981,58342,N,58336,58343,58330,N,58355, +58347,58341,58325,47977,58348,N,47980,58352,N,58346,47974,58344,N,58338,47972, +58329,58337,58349,58335,N,N,58339,N,N,N,N,N,48577,57321,59314,59323,59313, +59309,59306,48578,59304,47979,59297,48576,59303,48575,59308,59305,59321,59316, +59310,59315,48571,59307,59326,59298,59299,59322,48572,59327,48574,59328,59312, +58328,59318,59311,59320,59317,N,N,N,59302,48569,59325,48570,59300,48573,60260, +59319,59324,N,N,N,N,N,60257,48568,49088,60267,60263,N,60261,60256,60271,N,N,N, +49092,N,60252,60264,60265,60255,60254,60268,N,60258,60253,60259,N,60270,60251, +60269,60266,49090,49089,N,N,49091,60262,61643,N,N,N,N,N,61017,49585,61021, +61018,61025,61031,61020,N,61040,49582,61034,61023,61035,61030,61037,61022, +49587,49586,61024,61038,61016,61036,49580,N,61028,61027,61032,61019,49584,N, +49588,61026,61033,49589,61029,N,N,N,N,49581,49583,61639,61637,N,N,61644,61641, +61645,N,61630,61638,61649,61039,61634,49871,59301,61629,61642,61636,61633, +61628,61627,61648,N,61632,61631,49869,61640,N,49868,N,N,49870,61635,61647,N, +62174,62175,N,50121,62172,50118,62180,N,50122,62182,62171,61646,62184,62173,N, +50119,62179,N,62181,62176,62183,62178,62177,50120,N,N,62661,62662,N,62664, +50350,50351,62665,62663,N,62660,N,63042,63045,63041,N,50426,63043,50425,50424, +50423,63044,63313,63311,N,63310,63040,63312,63046,63309,N,63481,63447,63479, +50651,63480,63482,N,63679,50682,63678,63677,50683,N,50778,63854,63911,63910, +63912,42725,53418,N,54223,54224,N,N,N,56256,N,63047,63680,42726,44396,53419,N, +N,N,55217,45902,N,56258,56257,46579,N,47301,59329,48579,N,48580,N,N,N,49093, +50684,42727,N,N,N,53420,43757,53422,53421,44397,N,54225,N,54232,45129,54230, +54228,N,54235,54226,54227,45130,N,45134,N,N,54236,45133,54234,54231,54229, +45131,45132,54233,N,N,N,N,45904,55218,N,45909,55234,45908,55236,N,N,55224, +45906,55235,N,55219,45907,55231,55227,55229,55223,55230,N,N,45903,55226,N, +55225,55221,N,55232,N,N,55228,55220,N,55222,45905,55233,N,N,N,N,46582,56269,N, +N,N,56265,56267,56262,56261,56259,N,56266,56268,56264,N,56263,46580,46581,N,N, +N,N,N,N,56271,47309,57330,57336,57331,57332,N,57337,N,47311,N,47303,47310, +57329,56260,47306,47304,57335,57334,47305,47307,57333,47302,N,47308,N,N,N,N,N, +58358,47988,N,N,58434,58433,N,58363,47990,58432,58359,58360,47982,47984,N, +58365,58357,47986,47985,58361,58366,58364,47987,58362,56270,47983,N,N,59330, +59337,48582,N,59341,48586,59333,59331,N,59340,N,48581,59339,48583,48584,59332, +48585,59338,59334,59335,59336,47989,N,N,N,60272,60284,N,49098,60279,60281,N, +49096,60273,60277,N,60280,49094,49097,60283,60275,60276,60282,60274,60278, +49095,61042,N,61041,49591,61047,49593,N,N,49590,61043,49594,61044,N,N,61045, +61048,N,49592,N,61654,N,N,61657,N,61651,61653,N,N,61652,61655,61656,61046, +61650,N,N,50125,62188,62191,62193,62186,62187,62190,62192,50126,50124,50123, +62189,62185,62666,50352,N,62667,N,N,63049,50427,63051,50428,63048,63050,50600, +N,63314,50599,63485,63484,N,63483,N,N,63816,63817,63819,63818,N,51792,42728,N, +44398,55237,46583,N,57338,49872,N,62194,N,N,43171,N,N,N,45911,N,N,N,45910,N, +56272,46584,56274,56273,N,N,57339,47312,58435,58438,58437,N,58436,59342,59344, +59343,N,49100,N,N,N,49099,N,49595,61049,61051,61050,N,N,49873,N,N,N,62196, +62195,N,62668,50353,N,N,50429,63316,63315,50779,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,43172,53423,44399,55240,55238,N,N,55239,56276,56277,57411,56275,N,57340, +57409,57408,57410,47313,57342,57341,57412,N,58441,58439,N,58440,59347,59345,N, +N,59346,60285,61052,61053,49874,N,62197,62669,50354,N,63052,63317,50601,N, +63486,63820,43173,N,44401,44402,53424,N,N,53425,44400,N,45140,N,45138,N,45137, +45144,45136,45145,54237,45142,N,45139,45143,45141,45135,N,N,45919,N,45913, +55244,45918,N,N,45920,45914,N,45915,N,55242,N,N,45912,N,55243,45917,N,N,55241, +45916,N,N,46660,N,46662,N,N,56280,46661,46585,46589,N,47332,57417,56282,46590, +N,N,56285,56286,46659,N,56288,N,56290,N,56291,56279,56278,56292,46658,56289, +56287,N,46656,46587,46663,56283,56284,56281,N,46657,N,N,46588,N,46586,57416, +47327,47322,N,N,47317,N,47333,47318,N,47314,47329,47326,47328,N,47319,47324, +47315,47316,57424,57421,57413,57418,N,47330,57425,47331,47321,N,N,57415,N, +57423,57419,57422,57420,47325,57414,47320,N,N,N,58444,47992,47995,N,58446,N, +48037,58445,47997,N,48591,58447,N,48036,58443,48038,N,N,N,47993,N,47323,47996, +N,47994,47998,48034,47991,48039,48035,N,48033,58442,N,N,N,N,48598,N,48594,N,N, +N,48601,N,59350,48602,59362,59355,48587,59363,59357,48597,59358,N,48596,59361, +48590,59359,59349,48589,60330,48595,N,48592,N,48600,N,59348,N,59352,48588, +59351,59353,59354,48599,59356,59360,59364,N,48603,49106,60325,60331,60328, +60286,60332,60321,N,60327,N,49101,49107,60333,N,N,49103,N,49113,49108,60335, +60329,49104,60322,49114,60323,60324,49115,49112,48593,N,49102,60336,49116,N, +49109,60334,49105,49110,49111,N,49603,61092,61101,61098,61100,N,49600,61093,N, +61099,49596,61095,49604,61091,61096,61103,60326,61097,61090,49597,61089,49598, +61104,49599,61102,49602,61054,N,49601,N,61094,61660,61674,61669,61671,61659, +49875,N,61658,49878,49877,N,61673,61665,61662,61668,N,61661,N,61663,61672, +61670,N,49876,61677,61675,61666,61676,61667,N,62201,50127,62273,N,N,63055, +50134,61664,62199,50130,62200,62205,N,N,50132,50133,62198,62272,62274,62202, +62204,62206,62203,62275,50129,50135,50131,N,50128,62672,N,50359,62670,N,N, +62674,N,62675,50357,62676,62673,N,62671,50360,50356,62677,N,50358,50355,N,N,N, +50430,N,N,50496,63054,63053,63056,63057,N,50497,63318,63323,50602,N,63320,N, +63319,63322,63321,N,63555,N,50652,63554,63552,N,63553,N,N,N,50686,50685,63681, +63682,50752,N,63821,63822,50791,N,50797,N,63913,63944,43174,N,55245,N,55246, +57426,58448,59365,49606,N,49605,61678,62276,N,63556,43175,54238,45146,45921, +57428,57427,48604,59366,48605,61105,49879,N,N,N,50806,43176,52683,54239,N,N, +45922,N,55247,55248,N,56293,N,46664,47334,N,57430,57429,57431,N,58449,58450, +48040,49117,48606,49118,N,61109,61106,61108,61107,49607,N,61679,62278,62277, +52132,45148,45147,54240,N,55249,N,N,56295,56294,46665,N,57433,57434,57432,N,N, +47336,47335,N,48042,48041,N,59367,60339,60337,60338,49119,61111,61110,N,61682, +61681,61680,62279,N,63914,43177,44403,N,44404,45149,45150,54242,54241,55250,N, +45928,45926,45923,45927,45925,45924,N,N,46666,56298,N,47341,46668,46673,56300, +46675,46674,46677,56299,56296,46671,46667,46669,56297,46676,46672,46670,47343, +47342,47340,47344,N,47338,47339,N,47337,N,57435,N,N,58452,N,48044,48045,48043, +N,58451,N,58453,N,59370,59372,N,48615,59373,48608,59369,48607,48617,48613, +48614,48610,59368,48609,59374,59371,N,48616,N,48611,48612,60341,N,60343,60342, +N,60344,49120,60340,N,N,49611,61112,49608,49612,49610,49609,61683,61686,N, +61685,N,61684,49880,62280,62281,50136,62282,50137,N,N,50362,N,50361,63058,N,N, +50498,63059,63324,50603,50604,N,63557,N,50754,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43178,N,45930,45929,57436,57437,N,48046, +60345,48618,60346,61113,43179,N,53426,44406,44405,N,54243,45151,54244,55253,N, +55252,N,55251,N,N,56302,46680,N,N,56301,46679,N,N,N,56303,46678,N,57439,57442, +57440,57441,57445,57438,57446,57443,57444,48048,58454,N,N,48047,N,59378,59376, +N,N,48619,59375,59377,N,48620,N,60347,N,60348,49613,N,62284,62286,62283,62285, +62678,63060,N,N,63855,43180,44407,54245,54247,54246,N,55256,45932,N,55254,N, +45931,55257,N,55258,55255,N,N,56315,46688,56307,56313,N,N,46683,46686,56306, +46681,56310,57452,46685,N,56305,N,56311,56308,56314,56304,56312,46684,46687, +56309,46682,N,47346,57448,47345,57455,57454,47352,N,47353,57456,47347,57453, +47351,57458,57449,N,57451,47348,57447,57450,57457,47349,57459,N,N,N,N,N,47350, +N,48049,58459,58465,58457,58466,N,58456,58461,58467,58464,58463,58462,N,58455, +58460,N,N,58458,N,48625,48622,59387,59457,59459,59456,59384,59386,59461,59458, +59388,59462,59385,59460,48623,48629,48627,59379,48628,48624,59380,59382,59381, +59389,59390,N,48626,N,48621,N,N,59383,N,60358,49122,N,60349,49123,49126,60354, +N,60351,49125,N,N,60355,60356,60350,60359,60352,60357,49124,N,49121,60353,N, +61119,49616,49614,49617,49615,61118,61115,61114,N,61117,N,N,61116,61765,49886, +61691,61690,N,49881,61761,61760,61687,61763,61692,49885,61689,61762,61688, +49882,49884,61693,49883,61694,N,61764,62290,N,50142,62287,N,62291,N,N,50139, +62289,50144,N,50141,N,62288,N,50143,62292,50138,N,N,N,N,50364,50366,N,62681, +50365,62679,50140,62680,50363,50499,50501,63062,50500,63061,N,63329,50605, +63328,50606,63326,63325,63330,63331,63558,N,63327,N,N,63686,63683,63684,63685, +50780,N,63825,63824,63823,63856,N,63934,63915,50798,43181,45152,N,N,N,N,N, +47354,N,N,N,N,N,N,N,48630,N,N,60360,N,N,49887,N,62293,N,N,N,N,N,N,63916,43182, +43758,44409,44408,N,45155,N,54248,45153,54249,45154,N,N,55263,55259,N,N,45933, +55262,55261,55260,45934,55264,55265,N,N,N,56387,56385,56389,56390,56396,N, +56392,56394,N,56386,56316,N,56393,N,N,56395,56388,56391,56317,46690,56384, +56318,46689,46691,N,47357,57461,57463,57462,57467,47355,N,57464,57460,57465, +57466,47356,47358,57468,N,58471,58470,N,58468,58469,48051,48053,48050,48052, +59469,59470,59465,N,59466,48632,48637,48631,48638,48633,59467,N,N,59468,59464, +48704,48635,N,N,48634,48636,N,59463,N,60362,49128,N,N,60364,49130,60367,60363, +60361,60366,49129,60365,N,49127,N,N,49619,49622,61121,N,49620,61120,49618, +49621,61766,61767,61768,49888,N,61769,N,49889,50146,62296,62297,62295,62294, +62298,50145,62685,62683,62684,62686,62682,62687,63064,N,63065,63063,50502, +63332,50607,63333,63560,63559,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43183,46692,N,N, +47424,N,N,N,48054,N,N,49132,N,49131,N,N,N,N,50147,50300,50503,43184,45156, +47425,N,62299,N,N,N,N,N,N,N,N,N,N,52134,N,N,43185,N,43188,43187,43186,N,N, +52133,N,52685,N,52687,43759,N,N,43761,52684,52686,43760,52689,52688,52690,N,N, +N,N,N,N,N,N,53430,53428,44412,53427,44451,44414,44411,N,44452,N,44413,44450,N, +44449,53429,N,44410,N,N,N,45162,54251,54257,45159,45166,N,45161,54254,54256, +45164,54250,54253,45160,45157,54252,45163,54255,45165,45158,N,N,N,N,55267, +55270,45936,N,45946,45942,55268,N,N,45950,45943,45948,45938,N,45935,45937, +45949,55269,45941,45944,45940,45945,55271,45947,45939,55266,N,N,N,N,N,N,N,N, +56397,46693,56399,N,46695,46697,N,56398,46694,46698,N,46696,N,N,N,47431,57507, +47439,57470,N,47440,47429,N,57505,N,N,47434,N,57506,47427,47426,N,47437,47436, +47435,47433,47438,57469,47428,47430,47432,N,N,48056,48059,N,48063,48057,48062, +48060,N,48055,N,48061,48058,N,N,N,59474,48707,48705,N,59475,N,48708,48706, +59473,59472,N,49136,59471,49134,49133,60368,48709,49135,60369,49138,60370, +49137,49624,61123,49623,49628,49626,49627,49891,49625,61122,60371,49890,49892, +N,50148,50149,N,62688,N,50654,50653,43190,N,N,51797,45167,N,51794,51795,51793, +N,51796,N,N,52138,52135,52140,52136,43191,43194,N,52137,43193,52139,N,N,43192, +N,N,N,N,52693,52695,43764,52691,52694,52692,43762,43765,N,43763,N,N,N,N,53432, +53436,53433,N,44455,N,44456,N,53435,N,53437,53439,N,44453,53438,N,N,44454,N,N, +N,N,N,55278,53434,54258,54267,54265,54260,54261,54266,54268,45169,N,54263, +54259,45168,45170,54262,54269,54264,N,N,45985,55281,55273,55279,55280,45986,N, +55272,55274,53431,55276,55277,55275,46700,N,N,N,56406,60372,56407,56404,45987, +46702,56403,56409,56408,46699,56412,56402,56411,56400,56410,56405,46701,N, +57514,N,57509,57515,57510,57508,57511,47441,N,57513,N,57512,47442,48065,48064, +58478,58481,58473,58477,48066,58476,58474,58480,58475,58472,58479,N,59481, +48712,61770,59478,59479,59477,56401,48711,59482,59476,48710,48713,59480,60373, +49139,60374,60375,N,61124,49629,61771,61772,N,N,61773,62301,62300,62690,N, +62689,63067,63068,63066,63334,50608,43195,44458,44457,45173,45172,54336,54337, +54270,N,45171,55285,N,55286,55282,45988,55283,N,55284,N,N,N,N,56415,56417, +56413,56416,46703,56414,46704,N,N,56691,47445,47444,N,47443,N,57516,57517,N,N, +58483,58485,48070,48067,N,48069,48068,58484,58482,N,N,N,N,N,59489,59486,59487, +48717,59488,59483,59484,48714,N,48715,59485,48716,N,60379,N,60380,60377,60378, +49140,60376,N,N,N,N,N,61128,61125,61127,49632,61131,49631,61129,61132,61130, +61126,49630,N,61775,N,61776,61774,N,61778,49893,49894,62303,50151,61777,62302, +50150,62693,62694,50367,62692,N,62691,N,63069,50504,N,63561,63688,63687,N, +50755,50781,63689,63857,N,50799,43196,43766,N,47446,N,50368,43197,44459,45989, +46705,49895,43767,N,53441,53440,54338,N,45176,45174,45178,54340,N,45177,45175, +N,N,N,N,54339,45992,55292,N,45991,45993,55362,45995,55294,55360,55287,45994, +55363,N,N,55289,N,55290,55288,45990,N,55361,55291,55293,N,N,N,56429,N,56428, +56426,56418,56433,56421,56431,56438,56430,46713,N,46709,56419,N,56425,46711,N, +56424,46712,46714,56427,N,46706,46707,56439,56437,N,56436,56422,N,56434,N, +46710,N,N,N,N,46708,56435,56420,56423,56432,N,N,N,N,N,58554,57527,N,57520, +57539,57548,57523,47457,N,57536,47447,47449,47461,57521,N,N,47450,47452,47462, +47451,N,N,N,N,47460,57529,N,57518,47458,57528,47454,57546,47459,57544,57532, +57542,47456,57519,57545,57540,N,57547,47448,N,N,47463,47453,N,N,57525,N,57533, +57537,N,57541,47455,57524,57522,57534,N,N,N,N,57531,57530,N,57535,57538,N, +57543,N,N,N,58488,N,48071,58532,58490,48076,48080,58541,58549,58534,48072,N, +58538,57526,N,48073,58545,58550,58542,N,58544,58553,58546,58494,58537,N,N, +48081,N,48077,58492,58539,48075,58533,48074,58547,58530,58489,48078,58552,N,N, +58491,58543,58540,58535,58487,58486,58529,58548,48079,58551,58493,58531,48722, +N,N,N,N,N,48730,48725,59556,59553,59495,48720,N,N,N,48719,48726,N,N,N,59493, +48724,59505,59491,59492,48718,59555,48728,59508,59513,59507,60398,59503,59511, +59509,59496,59490,59517,48727,59518,N,59512,N,59501,59499,59494,N,N,N,59502, +59515,59498,59514,59554,N,N,48723,N,59510,59516,59506,59500,48721,N,N,N,58536, +59504,48729,59497,N,N,N,N,N,60404,49143,60403,60400,60484,49147,N,60481,60408, +60483,60393,60406,N,49149,N,60385,N,60383,60482,N,60480,60414,60397,60396, +60386,49216,N,60392,60402,60413,49219,60485,N,49640,49221,49150,60390,N,60399, +60382,60384,49141,49218,49146,60391,60407,60401,49217,60381,49635,60409,60412, +49148,N,60395,49220,49145,N,N,N,49144,60405,60411,49142,N,60388,60410,N,N, +60389,N,N,N,N,N,N,N,N,N,60394,61138,N,61143,49637,49639,61149,49633,61164, +61155,61144,61145,61154,N,49646,61153,61137,61152,61140,61165,49645,49643, +61141,N,61160,N,61146,61159,N,61161,61136,49638,N,61162,N,N,61150,N,49642, +61147,N,N,49644,61156,N,N,N,49636,61142,61157,N,61151,60387,61158,61139,N, +49641,N,61163,N,49634,61134,N,N,N,N,61792,61785,49897,N,61780,61795,61787, +61148,N,61797,61781,N,49896,61791,49898,49906,49904,61793,49905,61783,N,61784, +61789,61794,N,61133,49899,61802,61799,61803,61790,61786,61800,62314,61788,N, +49902,N,49901,61135,49903,61796,61798,49900,61801,61779,N,61782,N,N,N,N,N,N,N, +N,62323,N,62307,50155,62321,N,N,62305,50156,N,62316,N,62312,50161,62322,62306, +62309,50153,62324,N,62317,62320,50159,50164,50162,62313,62308,N,50157,50158, +62304,50154,N,50152,50160,62319,50163,N,62315,62325,50165,N,N,N,62311,N,62318, +N,N,N,N,N,N,62707,62786,62709,62716,62310,62714,62697,62784,50371,62701,62718, +62708,N,N,50370,N,N,62788,62710,N,62715,62717,62695,62785,62706,62711,62699, +62703,62787,62713,62696,62700,62702,62712,N,50369,62705,N,N,N,N,N,N,62698,N,N, +N,N,N,N,N,62704,63073,63078,50511,63080,N,50505,N,63076,63082,50510,50506,N, +50507,63072,63079,50509,63077,50508,63071,63075,63074,N,63070,63081,N,N,N, +50609,63341,63344,63340,63342,63343,63337,63338,63335,N,N,63339,63336,50610, +50611,N,N,63563,N,63565,N,N,N,N,N,63564,63566,N,50656,N,63562,50655,50657,N,N, +N,63691,63692,50756,63690,N,63827,63826,63828,50783,63829,50782,63830,63858, +63861,63860,50792,63859,N,N,N,50802,50800,50801,50807,63936,63937,63935,63945, +43768,N,N,55364,56440,59557,62326,N,N,43769,N,44460,45179,N,N,55365,N,55366, +45996,N,46717,56442,56441,46755,46716,56443,46718,46754,46753,46715,N,N,N, +47464,N,N,57552,57550,N,57551,57549,N,48082,N,48085,48087,48086,N,N,48083, +48084,N,59559,59558,48731,59560,N,59561,48732,N,N,N,60493,60491,61171,N,60489, +60490,49222,60486,60494,60488,60492,61167,N,N,61169,N,61170,49651,61166,49650, +61168,49647,49648,49649,60487,N,N,49909,61806,61804,61805,49907,49910,49908,N, +N,N,62327,62328,50166,N,62789,62791,62790,50372,50512,63085,63084,63083,43770, +N,51626,N,51800,42729,51798,51801,51799,N,N,N,52142,N,43201,N,43202,52144, +43199,52143,52141,43200,43198,N,N,N,N,N,N,52696,52699,43773,52698,52697,N, +43772,43771,N,43840,52700,43774,N,N,N,N,N,53446,44462,44463,44464,53447,53443, +44461,53444,N,53445,53442,N,N,N,45220,N,N,45217,54341,45218,45221,54342,N, +45182,45180,45181,45219,N,N,N,N,N,45997,55369,46005,55368,N,55371,46001,55370, +46763,45999,46002,45998,46003,46004,46000,N,N,N,55367,46759,56445,N,56483,N,N, +56482,46764,46760,46761,56444,56446,56481,46756,46758,N,46762,46757,N,N,57555, +57553,57554,47466,47467,N,57556,47465,48088,N,48090,48089,N,58555,N,N,58556, +59563,N,59562,N,N,49223,49224,60495,49225,N,61174,N,61172,N,61173,49652,N, +61807,50167,N,N,N,49653,43841,N,45222,54343,N,N,55372,46006,46765,56484,56486, +46767,46766,46768,46769,56485,47470,47471,47469,48091,47468,57557,N,N,N,48092, +59564,60496,49226,49654,61808,61812,49913,61809,49914,49912,61813,49915,61811, +N,62329,49911,50168,N,63693,N,N,43842,46008,46007,N,N,N,N,46770,56488,56487, +46771,N,N,57561,47475,47472,57560,47474,57558,47473,N,57559,N,58557,48093,N, +59567,N,48733,59565,48734,48735,59566,48736,N,60497,N,49230,49227,49232,60499, +49228,60498,49231,N,N,49229,N,61177,61179,N,N,49655,61178,49656,61176,61175,N, +61815,61814,49916,61816,62334,50170,62333,62330,50169,62331,62332,N,62792, +62793,50373,N,50515,N,N,63086,N,N,50513,50514,63087,N,N,50612,50613,63345,N,N, +50757,63695,50759,N,63694,63696,50758,63831,N,63917,N,N,N,N,N,N,43843,N,N,N, +47476,N,58558,N,59568,49233,49234,N,43844,N,48737,50171,44465,N,N,N,49235,N, +50658,44466,55373,N,56489,N,56491,N,56490,N,57565,57562,47477,N,47478,57563, +57564,N,58560,58565,48094,58559,58561,58568,58563,58567,58564,58562,58566, +48095,N,N,59571,N,59569,48739,N,48738,59570,48740,N,N,N,N,60502,N,N,60501, +49236,60500,61180,N,61182,61249,61248,N,49657,61181,61857,49917,61821,61858, +49918,N,61819,N,61822,61820,61817,49984,61818,N,N,N,N,62369,N,N,62371,62370,N, +62794,N,62795,N,N,N,63088,N,50615,N,50614,63567,63568,50760,63697,N,50793,N, +44467,46772,58570,58569,59573,59572,N,N,49658,61251,61250,61861,61859,61862, +61860,N,N,50172,62372,62373,62374,N,63089,N,63346,N,63698,N,N,N,N,N,N,N,44468, +N,N,60503,61252,N,44469,N,N,48096,N,60504,49985,61863,50173,N,62796,62797, +50516,63569,44470,46011,46012,55374,46773,46774,56492,46775,N,47482,N,47484, +57567,57568,57566,47479,47480,47483,47481,N,N,58571,48097,48098,N,N,59580, +48743,59575,59574,N,59579,48741,N,N,49243,N,59576,59581,59578,59577,N,48742,N, +49241,N,60506,49237,N,60507,N,N,60505,N,49240,49238,49242,N,49239,N,N,N,N,N, +61253,N,61258,61254,61257,49659,N,60884,61256,61255,N,49988,49986,49989,49987, +61864,61865,61866,49990,N,N,N,62378,50240,62376,N,50241,62375,62377,50174, +62801,62798,N,62799,62800,63090,50518,N,50517,N,63348,63347,50616,N,N,N,50659, +50761,50784,63832,63918,63919,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44471,56493,N,N,57569, +58572,58573,48099,N,48100,59582,48744,N,N,49660,N,61867,N,49991,62381,50242, +62380,62382,62379,63093,62802,62803,N,50374,N,63092,N,N,63091,N,63349,63920,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,44472,N,N,N,44473,N,N,45223,54344,N,55375,N,46776,N, +46779,46777,56494,N,46781,N,46778,N,N,46780,N,47486,N,57570,N,N,57571,59584,N, +47485,47521,47522,58575,N,58574,48101,N,48102,N,58576,59583,48104,48745,N, +48103,N,N,N,49244,59585,48747,48746,59586,59589,59587,59588,48748,N,49249, +49247,N,N,49246,60509,N,49248,N,N,60508,61259,N,60510,49245,60511,61262,61260, +61261,61266,49995,61265,61268,61267,61264,61263,N,49661,N,N,N,N,61870,N,61869, +49994,49992,49993,N,61868,N,62385,N,50243,N,62384,62383,50244,N,62808,62807,N, +62805,N,62804,50376,50375,62809,63350,50617,63095,50519,63094,62806,N,63351, +50660,N,50785,63833,N,63921,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44474,55376,61269,44475, +N,N,58578,58577,60512,N,N,61271,N,61270,N,49996,62386,62387,50377,N,N,63922, +45224,46783,46782,57572,57574,47524,57573,47523,47525,57575,N,N,N,58580,58582, +58581,N,58584,N,N,N,48105,58583,58579,N,N,N,58585,N,59596,N,59599,59601,59591, +59595,59592,48750,48753,48755,59593,59594,48754,59597,59600,59598,48756,N, +48752,59590,48749,N,48751,N,N,49251,60518,60516,60515,N,60521,N,60520,60519,N, +60514,49250,60513,N,60517,49252,N,N,61274,N,61278,61275,61277,61276,61273, +61279,61282,61280,61281,49728,49662,61272,61283,61875,61878,61880,61879,N, +61873,61877,61872,N,61874,49997,61871,N,61876,N,N,62400,62389,50245,N,N,50246, +62388,62393,62399,62391,62398,N,62395,N,62394,62397,62392,62390,N,62396,N, +62816,62814,50378,62813,62819,62817,N,50379,62812,62810,N,62811,50381,62815, +50380,62818,63096,63102,N,N,63097,50523,63137,50522,63101,63100,50521,63099, +50520,63098,N,63357,63393,63358,N,63355,50619,63352,63356,63395,N,63394,63353, +63354,50618,63570,50663,N,63571,50661,50662,N,N,63699,50762,63862,N,50794,N, +63923,50795,63924,63925,63939,63938,50810,63949,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,45225,N,N,57577,N,57576,N,48106,48107,58586,N,59602,60524,N,N, +48757,49253,60522,N,60525,49254,N,61284,60523,61881,49998,62401,N,N,N,62822, +62820,N,N,62821,N,N,63138,N,50524,63396,50666,50620,50664,50665,63700,50786,N, +45226,N,N,N,61882,N,N,54345,N,47526,N,58587,N,N,48108,58588,N,N,N,59604,59603, +49256,48758,48759,N,59607,59606,59605,N,N,60526,60529,N,60528,60527,49255, +61288,61286,61285,61287,N,49999,61884,61885,50000,N,61883,N,62403,62402,62405, +50247,62404,N,62823,62825,62824,N,N,63139,63142,63140,63141,63397,50621,N,N,N, +63572,63573,63574,N,50763,50787,63926,45227,N,48760,49257,61886,N,63398,N,N, +63940,54346,N,50811,45228,60530,N,61887,N,62406,N,N,63143,63399,45229,N,58589, +58590,N,48109,48110,59609,48762,48761,59608,N,61289,N,61888,61890,61889,50003, +50002,50001,N,50526,63144,N,50525,63401,63400,N,50764,63701,46013,57578,N,N,N, +58593,58591,58592,N,N,59618,N,59613,59610,59617,N,N,N,59619,N,N,48764,59616, +59612,N,N,59611,59615,59614,48763,N,N,60541,60536,60534,60577,60535,N,60531,N, +60537,N,N,60532,61298,60533,60578,N,N,N,N,N,N,N,60540,49258,60539,60538,N, +60542,N,N,N,N,61290,61293,N,N,61292,N,61300,61295,61299,N,61297,61296,61294,N, +61291,N,49731,49730,N,49732,49729,61301,N,N,N,N,N,61896,61899,N,61897,61901,N, +N,N,61902,N,61894,50008,61895,N,61893,61900,N,61892,61891,50007,50005,50004,N, +N,N,N,N,N,N,N,61898,62415,62421,50250,62416,N,62419,62423,50251,62418,N,62410, +N,62409,62422,62413,N,62411,62420,62412,50249,50248,N,62407,62408,62417,N,N,N, +62414,N,N,N,N,N,N,62828,62831,N,N,N,N,50006,62829,62835,62833,62827,62838,N, +62826,N,50383,62834,N,N,N,62830,50382,62837,N,N,62836,N,N,N,N,63147,63146,N,N, +N,63153,N,63149,63152,50528,N,N,63150,63151,N,63145,63148,50527,N,N,N,50623, +63412,63407,63411,N,63414,63410,N,63406,N,50625,63409,63413,50624,63404,62832, +63408,N,N,63405,N,63402,N,63403,50622,63578,63580,63583,63579,63584,N,63577,N, +63575,N,50667,63581,50669,50668,63576,63582,N,N,N,N,63706,50765,63707,N,63705, +63702,N,N,63704,63703,63834,N,N,N,N,63836,63835,N,N,63865,N,63864,63863,63866, +N,50803,50804,63946,63950,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,46014,56495,57581,N,47527,57579,N,N,57580,N,N,N,58594,58595,48113,48111, +58596,48112,59624,N,59627,59621,59628,59620,59622,N,59623,59626,N,N,48801, +59631,59630,48765,59625,59629,48766,N,N,N,N,N,N,60588,N,49263,N,60583,49259,N, +60580,60586,60589,N,49264,N,60585,60582,60590,60581,N,60587,49260,N,60579, +49261,N,49262,60584,N,N,N,61353,61306,61307,61310,61308,N,61302,N,N,61305, +61349,61309,N,N,49733,N,61351,61348,49734,61350,61303,61346,61347,N,61345,N,N, +N,N,61906,61908,61911,N,N,61905,N,50009,61913,61904,61914,N,61910,61912,61916, +61909,61917,61907,61903,50010,N,61915,50011,50253,N,N,N,N,N,61304,62449,62440, +50255,62436,50256,N,N,62445,62439,62429,50254,62442,62437,62438,N,62424,62431, +62446,N,62443,N,62435,N,62447,62430,62425,62444,N,62427,62441,62432,62448, +62428,50252,62426,62433,62434,N,N,N,62845,N,62843,N,62882,N,62894,62885,62844, +62840,62887,62846,62883,62842,62890,62839,62881,62886,62888,62891,62841,N, +62895,62896,62889,62893,62884,N,63169,63172,N,50529,N,63171,63176,63174,50530, +63165,63155,63154,50532,63167,63168,63164,63156,N,63161,62892,N,63157,50531, +63163,N,63162,N,63158,63170,N,63159,63419,63173,63175,63166,63160,63420,63422, +63416,50626,N,63429,63427,50627,63426,63425,63418,63415,63421,63430,63417, +63423,N,63593,63598,63588,63591,50670,63595,N,63602,63424,N,63589,63599,63603, +63594,63587,63597,N,63596,63601,63600,63428,63592,63586,63590,50766,50767, +63585,N,63718,63709,63717,63714,63715,63708,63711,63719,63713,63712,63710,N, +63716,N,63837,N,63838,N,63840,63839,63842,63841,63868,63867,63927,N,63928,N, +63941,50808,50812,N,63951,50813,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,46015,N,N,N,50384,63177,N, +50768,50769,N,46016,57582,N,47528,59632,N,N,60592,60593,60591,61355,61354, +49735,61919,61356,61918,N,N,62451,50257,50259,62450,N,N,50258,N,62897,62899, +62898,63178,50533,N,50671,63720,63843,N,N,63954,46017,N,58597,N,48802,N,N,N, +60595,60594,N,61357,N,N,N,50260,50385,63431,63947,N,N,N,46018,48114,N,48803,N, +62452,N,63604,46784,N,N,N,N,61358,N,N,N,50788,46785,48804,49736,63605,46786,N, +59633,49266,60596,60597,N,49265,N,61359,49740,49738,49739,49737,61920,50012,N, +N,N,62901,62900,62903,62902,50386,N,N,63179,N,63181,63180,50534,63432,N,63606, +63607,50672,63844,63869,50805,N,56496,60598,61360,62453,57583,N,61361,61922, +61921,N,N,N,N,63608,50770,N,63845,63870,N,N,N,47529,59634,59635,N,60599,47530, +N,50013,61923,N,63183,50535,63184,63182,63609,N,63721,N,47531,N,61364,61363, +61362,61924,N,N,61928,61927,61926,61925,50014,62454,62905,50387,62904,63185, +63435,63434,50628,63433,63612,63611,63610,N,N,48115,N,60600,49741,N,62455, +62456,63436,63613,N,N,63722,63846,63929,63956,48116,49742,61929,62457,63186, +63614,N,N,48806,N,61365,61930,62458,62459,62460,62910,N,62906,50536,62909, +62908,50388,62907,50390,N,50389,63188,63187,50537,50538,N,N,50630,63437,50629, +N,63651,63652,63650,63649,50772,N,63723,63724,63725,50771,63847,63850,63849, +63848,N,N,63955,N,N,N,N,N,N,N,N,N,N,N,N,N,N,49267,N,N,50021,62911,63189,N, +50631,63438,N,N,63957,N,N,N,49268,N,N,N,61366,N,63439,N,63905,51530,56828, +41290,41303,N,41305,41307,41311,41312,41315,41316,41319,41320,41323,41324, +41327,41328,41331,41332,41335,41336,41339,41340,N,N,N,N,41414,41415,41418, +41419,41416,41417,41308,41293,N,41295,N,41297,41298,41299,41300,N,41341,41342, +41377,41378,41379,41380,41420,41421,41422,41438,41439,41440,41441,41442,N,N, +41548,41549,41550,41289,N,41389,41539,41544,41390,N,41309,41310,41391,41423, +41281,41424,41284,41537,41647,41648,41649,41650,41651,41652,41653,41654,41655, +41656,41287,41286,41429,41431,41430,41288,41545,41679,41680,41681,41682,41683, +41684,41685,41686,41687,41688,41689,41690,41691,41692,41693,41694,41695,41696, +41697,41698,41699,41700,41701,41702,41703,41704,N,41538,N,N,41412,N,41705, +41706,41707,41708,41709,41710,41711,41712,41713,41714,41715,41716,41717,41718, +41719,41720,41721,41722,41723,41724,41725,41726,41792,41793,41794,41795,41313, +41301,41314,N,N,N,N,N,N,41294,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41411, +}; + +static const struct unim_index big5_encmap[256] = { +{__big5_encmap+0,162,247},{0,0,0},{__big5_encmap+86,199,217},{__big5_encmap+ +105,145,201},{__big5_encmap+162,1,81},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{__big5_encmap+243,19,62},{__big5_encmap+287,3,153},{ +__big5_encmap+438,26,191},{0,0,0},{__big5_encmap+604,96,125},{__big5_encmap+ +634,0,229},{__big5_encmap+864,5,66},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5_encmap+926,0,254},{__big5_encmap+1181, +5,41},{__big5_encmap+1218,163,163},{__big5_encmap+1219,142,213},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5_encmap+1291,0,255},{ +__big5_encmap+1547,0,254},{__big5_encmap+1802,0,255},{__big5_encmap+2058,0,253 +},{__big5_encmap+2312,0,255},{__big5_encmap+2568,5,252},{__big5_encmap+2816,1, +255},{__big5_encmap+3071,1,255},{__big5_encmap+3326,0,255},{__big5_encmap+3582 +,1,253},{__big5_encmap+3835,0,255},{__big5_encmap+4091,3,255},{__big5_encmap+ +4344,0,255},{__big5_encmap+4600,1,250},{__big5_encmap+4850,1,255},{ +__big5_encmap+5105,0,255},{__big5_encmap+5361,2,255},{__big5_encmap+5615,1,255 +},{__big5_encmap+5870,0,255},{__big5_encmap+6126,0,255},{__big5_encmap+6382,0, +255},{__big5_encmap+6638,0,249},{__big5_encmap+6888,6,255},{__big5_encmap+7138 +,0,253},{__big5_encmap+7392,0,255},{__big5_encmap+7648,0,255},{__big5_encmap+ +7904,18,253},{__big5_encmap+8140,4,255},{__big5_encmap+8392,0,252},{ +__big5_encmap+8645,0,255},{__big5_encmap+8901,0,249},{__big5_encmap+9151,0,253 +},{__big5_encmap+9405,0,255},{__big5_encmap+9661,0,255},{__big5_encmap+9917,0, +255},{__big5_encmap+10173,0,255},{__big5_encmap+10429,1,255},{__big5_encmap+ +10684,0,255},{__big5_encmap+10940,0,255},{__big5_encmap+11196,0,255},{ +__big5_encmap+11452,0,254},{__big5_encmap+11707,1,253},{__big5_encmap+11960,2, +255},{__big5_encmap+12214,1,251},{__big5_encmap+12465,0,255},{__big5_encmap+ +12721,0,255},{__big5_encmap+12977,0,254},{__big5_encmap+13232,0,251},{ +__big5_encmap+13484,3,156},{__big5_encmap+13638,54,255},{__big5_encmap+13840, +0,254},{__big5_encmap+14095,0,255},{__big5_encmap+14351,0,254},{__big5_encmap+ +14606,0,255},{__big5_encmap+14862,1,255},{__big5_encmap+15117,0,255},{ +__big5_encmap+15373,0,254},{__big5_encmap+15628,0,255},{__big5_encmap+15884,0, +254},{__big5_encmap+16139,1,255},{__big5_encmap+16394,0,255},{__big5_encmap+ +16650,0,159},{__big5_encmap+16810,55,254},{__big5_encmap+17010,0,255},{ +__big5_encmap+17266,0,255},{__big5_encmap+17522,0,255},{__big5_encmap+17778,0, +255},{__big5_encmap+18034,0,255},{__big5_encmap+18290,0,255},{__big5_encmap+ +18546,0,255},{__big5_encmap+18802,0,131},{__big5_encmap+18934,119,229},{ +__big5_encmap+19045,28,255},{__big5_encmap+19273,0,255},{__big5_encmap+19529, +0,254},{__big5_encmap+19784,0,255},{__big5_encmap+20040,1,254},{__big5_encmap+ +20294,1,253},{__big5_encmap+20547,5,255},{__big5_encmap+20798,0,255},{ +__big5_encmap+21054,0,255},{__big5_encmap+21310,0,164},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{__big5_encmap+21475,12,13},{0,0,0},{0,0,0},{0,0,0},{__big5_encmap+21477,48, +107},{__big5_encmap+21537,1,227}, +}; + +static const ucs2_t __cp950ext_decmap[224] = { +8231,U,U,U,U,U,U,U,U,65105,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,175,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,65374,U,U,U,U,U,U,U,U,U,U,U,U,U,U,8853,8857,8725,65128,U,65509, +U,65504,65505,8364,30849,37561,35023,22715,24658,31911,23290,9556,9574,9559, +9568,9580,9571,9562,9577,9565,9554,9572,9557,9566,9578,9569,9560,9575,9563, +9555,9573,9558,9567,9579,9570,9561,9576,9564,9553,9552,9581,9582,9584,9583, +9619, +}; + +static const struct dbcs_index cp950ext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_decmap+0,69,243 +},{__cp950ext_decmap+175,65,71},{__cp950ext_decmap+182,225,225},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_decmap+183,214,254 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __cp950ext_encmap[581] = { +41410,41285,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41953,41537,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41458,N,N,N,41459,63992,63974,63983,63965,63976,63985,63967,63980,63989,63971, +63982,63991,63973,N,63986,63968,N,63988,63970,63975,63984,63966,63981,63990, +63972,N,63987,63969,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,63998,63961,63964,63962,63958,63963,63960,63959,41294,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41538,41470,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41536,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41443,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,41542,41543,N,N,N,41540, +}; + +static const struct unim_index cp950ext_encmap[256] = { +{__cp950ext_encmap+0,175,175},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+1,39,172},{0, +0,0},{__cp950ext_encmap+135,21,153},{0,0,0},{0,0,0},{__cp950ext_encmap+268,81, +147},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{__cp950ext_encmap+335,187,187},{0,0,0},{__cp950ext_encmap+ +336,250,250},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+337, +82,82},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+338,129,129},{0,0,0},{ +0,0,0},{0,0,0},{__cp950ext_encmap+339,167,167},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+ +340,207,207},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{__cp950ext_encmap+341,185,185},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+342,81,104},{ +__cp950ext_encmap+366,15,229}, +}; diff --git a/pypy/translator/c/src/cjkcodecs/multibytecodec.c b/pypy/translator/c/src/cjkcodecs/multibytecodec.c new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/multibytecodec.c @@ -0,0 +1,211 @@ +#include +#include "src/cjkcodecs/multibytecodec.h" + + +struct pypy_cjk_dec_s *pypy_cjk_dec_init(const MultibyteCodec *codec, + char *inbuf, Py_ssize_t inlen) +{ + struct pypy_cjk_dec_s *d = malloc(sizeof(struct pypy_cjk_dec_s)); + if (!d) + return NULL; + if (codec->decinit != NULL && codec->decinit(&d->state, codec->config) != 0) + goto errorexit; + + d->codec = codec; + d->inbuf_start = inbuf; + d->inbuf = inbuf; + d->inbuf_end = inbuf + inlen; + d->outbuf_start = (inlen <= (PY_SSIZE_T_MAX / sizeof(Py_UNICODE)) ? + malloc(inlen * sizeof(Py_UNICODE)) : + NULL); + if (!d->outbuf_start) + goto errorexit; + d->outbuf = d->outbuf_start; + d->outbuf_end = d->outbuf_start + inlen; + return d; + + errorexit: + free(d); + return NULL; +} + +void pypy_cjk_dec_free(struct pypy_cjk_dec_s *d) +{ + free(d->outbuf_start); + free(d); +} + +static int expand_decodebuffer(struct pypy_cjk_dec_s *d, Py_ssize_t esize) +{ + Py_ssize_t orgpos, orgsize; + Py_UNICODE *newbuf; + + orgpos = d->outbuf - d->outbuf_start; + orgsize = d->outbuf_end - d->outbuf_start; + esize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize); + newbuf = (esize <= (PY_SSIZE_T_MAX / sizeof(Py_UNICODE) - orgsize) ? + realloc(d->outbuf_start, (orgsize + esize) * sizeof(Py_UNICODE)) : + NULL); + if (!newbuf) + return -1; + d->outbuf_start = newbuf; + d->outbuf = newbuf + orgpos; + d->outbuf_end = newbuf + orgsize + esize; + return 0; +} + +Py_ssize_t pypy_cjk_dec_chunk(struct pypy_cjk_dec_s *d) +{ + while (1) + { + Py_ssize_t r; + Py_ssize_t inleft = (Py_ssize_t)(d->inbuf_end - d->inbuf); + Py_ssize_t outleft = (Py_ssize_t)(d->outbuf_end - d->outbuf); + if (inleft == 0) + return 0; + r = d->codec->decode(&d->state, d->codec->config, + &d->inbuf, inleft, &d->outbuf, outleft); + if (r != MBERR_TOOSMALL) + return r; + /* output buffer too small; grow it and continue. */ + if (expand_decodebuffer(d, -1) == -1) + return MBERR_NOMEMORY; + } +} + +Py_UNICODE *pypy_cjk_dec_outbuf(struct pypy_cjk_dec_s *d) +{ + return d->outbuf_start; +} + +Py_ssize_t pypy_cjk_dec_outlen(struct pypy_cjk_dec_s *d) +{ + return d->outbuf - d->outbuf_start; +} + +Py_ssize_t pypy_cjk_dec_inbuf_remaining(struct pypy_cjk_dec_s *d) +{ + return d->inbuf_end - d->inbuf; +} + +Py_ssize_t pypy_cjk_dec_inbuf_consumed(struct pypy_cjk_dec_s* d) +{ + return d->inbuf - d->inbuf_start; +} + +/************************************************************/ + +struct pypy_cjk_enc_s *pypy_cjk_enc_init(const MultibyteCodec *codec, + Py_UNICODE *inbuf, Py_ssize_t inlen) +{ + Py_ssize_t outlen; + struct pypy_cjk_enc_s *d = malloc(sizeof(struct pypy_cjk_enc_s)); + if (!d) + return NULL; + if (codec->encinit != NULL && codec->encinit(&d->state, codec->config) != 0) + goto errorexit; + + d->codec = codec; + d->inbuf_start = inbuf; + d->inbuf = inbuf; + d->inbuf_end = inbuf + inlen; + + if (inlen > (PY_SSIZE_T_MAX - 16) / 2) + goto errorexit; + outlen = inlen * 2 + 16; + d->outbuf_start = malloc(outlen); + if (!d->outbuf_start) + goto errorexit; + d->outbuf = d->outbuf_start; + d->outbuf_end = d->outbuf_start + outlen; + return d; + + errorexit: + free(d); + return NULL; +} + +void pypy_cjk_enc_free(struct pypy_cjk_enc_s *d) +{ + free(d->outbuf_start); + free(d); +} + +static int expand_encodebuffer(struct pypy_cjk_enc_s *d, Py_ssize_t esize) +{ + Py_ssize_t orgpos, orgsize; + unsigned char *newbuf; + + orgpos = d->outbuf - d->outbuf_start; + orgsize = d->outbuf_end - d->outbuf_start; + esize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize); + newbuf = (esize <= PY_SSIZE_T_MAX - orgsize ? + realloc(d->outbuf_start, orgsize + esize) : + NULL); + if (!newbuf) + return -1; + d->outbuf_start = newbuf; + d->outbuf = newbuf + orgpos; + d->outbuf_end = newbuf + orgsize + esize; + return 0; +} + +#define MBENC_RESET MBENC_MAX<<1 + +Py_ssize_t pypy_cjk_enc_chunk(struct pypy_cjk_enc_s *d) +{ + int flags = MBENC_FLUSH | MBENC_RESET; /* XXX always, for now */ + while (1) + { + Py_ssize_t r; + Py_ssize_t inleft = (Py_ssize_t)(d->inbuf_end - d->inbuf); + Py_ssize_t outleft = (Py_ssize_t)(d->outbuf_end - d->outbuf); + if (inleft == 0) + return 0; + r = d->codec->encode(&d->state, d->codec->config, + &d->inbuf, inleft, &d->outbuf, outleft, flags); + if (r != MBERR_TOOSMALL) + return r; + /* output buffer too small; grow it and continue. */ + if (expand_encodebuffer(d, -1) == -1) + return MBERR_NOMEMORY; + } +} + +Py_ssize_t pypy_cjk_enc_reset(struct pypy_cjk_enc_s *d) +{ + if (d->codec->encreset == NULL) + return 0; + + while (1) + { + Py_ssize_t r; + Py_ssize_t outleft = (Py_ssize_t)(d->outbuf_end - d->outbuf); + r = d->codec->encreset(&d->state, d->codec->config, &d->outbuf, outleft); + if (r != MBERR_TOOSMALL) + return r; + /* output buffer too small; grow it and continue. */ + if (expand_encodebuffer(d, -1) == -1) + return MBERR_NOMEMORY; + } +} + +char *pypy_cjk_enc_outbuf(struct pypy_cjk_enc_s *d) +{ + return d->outbuf_start; +} + +Py_ssize_t pypy_cjk_enc_outlen(struct pypy_cjk_enc_s *d) +{ + return d->outbuf - d->outbuf_start; +} + +Py_ssize_t pypy_cjk_enc_inbuf_remaining(struct pypy_cjk_enc_s *d) +{ + return d->inbuf_end - d->inbuf; +} + +Py_ssize_t pypy_cjk_enc_inbuf_consumed(struct pypy_cjk_enc_s* d) +{ + return d->inbuf - d->inbuf_start; +} diff --git a/pypy/translator/c/src/cjkcodecs/multibytecodec.h b/pypy/translator/c/src/cjkcodecs/multibytecodec.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/cjkcodecs/multibytecodec.h @@ -0,0 +1,165 @@ + +#ifndef _PYPY_MULTIBYTECODEC_H_ +#define _PYPY_MULTIBYTECODEC_H_ + + +#include +#include + +#ifdef _WIN64 +typedef __int64 ssize_t +#elif defined(_WIN32) +typedef int ssize_t; +#else +#include +#endif + +#ifndef Py_UNICODE_SIZE +#ifdef _WIN32 +#define Py_UNICODE_SIZE 2 +#else +#define Py_UNICODE_SIZE 4 +#endif +typedef wchar_t Py_UNICODE; +typedef ssize_t Py_ssize_t; +#define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t) -1) >> 1)) +#endif + +#ifdef _WIN32 +typedef unsigned int ucs4_t; +typedef unsigned short ucs2_t, DBCHAR; +#else +#include +typedef uint32_t ucs4_t; +typedef uint16_t ucs2_t, DBCHAR; +#endif + + + +typedef union { + void *p; + int i; + unsigned char c[8]; + ucs2_t u2[4]; + ucs4_t u4[2]; +} MultibyteCodec_State; + +typedef int (*mbcodec_init)(const void *config); +typedef Py_ssize_t (*mbencode_func)(MultibyteCodec_State *state, + const void *config, + const Py_UNICODE **inbuf, Py_ssize_t inleft, + unsigned char **outbuf, Py_ssize_t outleft, + int flags); +typedef int (*mbencodeinit_func)(MultibyteCodec_State *state, + const void *config); +typedef Py_ssize_t (*mbencodereset_func)(MultibyteCodec_State *state, + const void *config, + unsigned char **outbuf, Py_ssize_t outleft); +typedef Py_ssize_t (*mbdecode_func)(MultibyteCodec_State *state, + const void *config, + const unsigned char **inbuf, Py_ssize_t inleft, + Py_UNICODE **outbuf, Py_ssize_t outleft); +typedef int (*mbdecodeinit_func)(MultibyteCodec_State *state, + const void *config); +typedef Py_ssize_t (*mbdecodereset_func)(MultibyteCodec_State *state, + const void *config); + +typedef struct MultibyteCodec_s { + const char *encoding; + const void *config; + mbcodec_init codecinit; + mbencode_func encode; + mbencodeinit_func encinit; + mbencodereset_func encreset; + mbdecode_func decode; + mbdecodeinit_func decinit; + mbdecodereset_func decreset; +} MultibyteCodec; + + +/* positive values for illegal sequences */ +#define MBERR_TOOSMALL (-1) /* insufficient output buffer space */ +#define MBERR_TOOFEW (-2) /* incomplete input buffer */ +#define MBERR_INTERNAL (-3) /* internal runtime error */ +#define MBERR_NOMEMORY (-4) /* out of memory */ + +#define MBENC_FLUSH 0x0001 /* encode all characters encodable */ +#define MBENC_MAX MBENC_FLUSH + + +struct pypy_cjk_dec_s { + const MultibyteCodec *codec; + MultibyteCodec_State state; + const unsigned char *inbuf_start, *inbuf, *inbuf_end; + Py_UNICODE *outbuf_start, *outbuf, *outbuf_end; +}; + +struct pypy_cjk_dec_s *pypy_cjk_dec_init(const MultibyteCodec *codec, + char *inbuf, Py_ssize_t inlen); +void pypy_cjk_dec_free(struct pypy_cjk_dec_s *); +Py_ssize_t pypy_cjk_dec_chunk(struct pypy_cjk_dec_s *); +Py_UNICODE *pypy_cjk_dec_outbuf(struct pypy_cjk_dec_s *); +Py_ssize_t pypy_cjk_dec_outlen(struct pypy_cjk_dec_s *); +Py_ssize_t pypy_cjk_dec_inbuf_remaining(struct pypy_cjk_dec_s *d); +Py_ssize_t pypy_cjk_dec_inbuf_consumed(struct pypy_cjk_dec_s* d); + +struct pypy_cjk_enc_s { + const MultibyteCodec *codec; + MultibyteCodec_State state; + const Py_UNICODE *inbuf_start, *inbuf, *inbuf_end; + unsigned char *outbuf_start, *outbuf, *outbuf_end; +}; + +struct pypy_cjk_enc_s *pypy_cjk_enc_init(const MultibyteCodec *codec, + Py_UNICODE *inbuf, Py_ssize_t inlen); +void pypy_cjk_enc_free(struct pypy_cjk_enc_s *); +Py_ssize_t pypy_cjk_enc_chunk(struct pypy_cjk_enc_s *); +Py_ssize_t pypy_cjk_enc_reset(struct pypy_cjk_enc_s *); +char *pypy_cjk_enc_outbuf(struct pypy_cjk_enc_s *); +Py_ssize_t pypy_cjk_enc_outlen(struct pypy_cjk_enc_s *); +Py_ssize_t pypy_cjk_enc_inbuf_remaining(struct pypy_cjk_enc_s *d); +Py_ssize_t pypy_cjk_enc_inbuf_consumed(struct pypy_cjk_enc_s* d); + +/* list of codecs defined in the .c files */ + +#define DEFINE_CODEC(name) \ + const MultibyteCodec *pypy_cjkcodec_##name(void); + +// _codecs_cn +DEFINE_CODEC(gb2312) +DEFINE_CODEC(gbk) +DEFINE_CODEC(gb18030) +DEFINE_CODEC(hz) + +//_codecs_hk +DEFINE_CODEC(big5hkscs) + +//_codecs_iso2022 +DEFINE_CODEC(iso2022_kr) +DEFINE_CODEC(iso2022_jp) +DEFINE_CODEC(iso2022_jp_1) +DEFINE_CODEC(iso2022_jp_2) +DEFINE_CODEC(iso2022_jp_2004) +DEFINE_CODEC(iso2022_jp_3) +DEFINE_CODEC(iso2022_jp_ext) + +//_codecs_jp +DEFINE_CODEC(shift_jis) +DEFINE_CODEC(cp932) +DEFINE_CODEC(euc_jp) +DEFINE_CODEC(shift_jis_2004) +DEFINE_CODEC(euc_jis_2004) +DEFINE_CODEC(euc_jisx0213) +DEFINE_CODEC(shift_jisx0213) + +//_codecs_kr +DEFINE_CODEC(euc_kr) +DEFINE_CODEC(cp949) +DEFINE_CODEC(johab) + +//_codecs_tw +DEFINE_CODEC(big5) +DEFINE_CODEC(cp950) + + +#endif diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -204,9 +204,11 @@ dirname = resolvedirof(search) if dirname == search: # not found! let's hope that the compiled-in path is ok - print >> sys.stderr, ('debug: WARNING: library path not found, ' - 'using compiled-in sys.path ' - 'and sys.prefix will be unset') + print >> sys.stderr, """\ +debug: WARNING: Library path not found, using compiled-in sys.path. +debug: WARNING: 'sys.prefix' will not be set. +debug: WARNING: Make sure the pypy binary is kept inside its tree of files. +debug: WARNING: It is ok to create a symlink to it from somewhere else.""" newpath = sys.path[:] break newpath = sys.pypy_initial_path(dirname) From noreply at buildbot.pypy.org Fri Jul 1 16:16:02 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 1 Jul 2011 16:16:02 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: merge up to a98d7b4c1f16 Message-ID: <20110701141602.100618293A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45231:4a6d9d2ae42a Date: 2011-07-01 15:45 +0200 http://bitbucket.org/pypy/pypy/changeset/4a6d9d2ae42a/ Log: merge up to a98d7b4c1f16 diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -25,6 +25,8 @@ ^pypy/translator/c/src/libffi_msvc/.+\.dll$ ^pypy/translator/c/src/libffi_msvc/.+\.lib$ ^pypy/translator/c/src/libffi_msvc/.+\.exp$ +^pypy/translator/c/src/cjkcodecs/.+\.o$ +^pypy/translator/c/src/cjkcodecs/.+\.obj$ ^pypy/translator/jvm/\.project$ ^pypy/translator/jvm/\.classpath$ ^pypy/translator/jvm/eclipse-bin$ diff --git a/README b/README --- a/README +++ b/README @@ -15,10 +15,10 @@ The getting-started document will help guide you: - http://codespeak.net/pypy/dist/pypy/doc/getting-started.html + http://doc.pypy.org/en/latest/getting-started.html It will also point you to the rest of the documentation which is generated from files in the pypy/doc directory within the source repositories. Enjoy and send us feedback! - the pypy-dev team + the pypy-dev team diff --git a/lib-python/TODO b/lib-python/TODO deleted file mode 100644 --- a/lib-python/TODO +++ /dev/null @@ -1,100 +0,0 @@ -TODO list for 2.7.0 -=================== - -You can find the results of the most recent buildbot run at: -http://buildbot.pypy.org/ - - -Probably easy tasks -------------------- - -- (unicode|bytearray).(index|find) should accept None as indices (see - test_unicode.py) - -- missing posix.confstr and posix.confstr_names - -- remove code duplication: bit_length() and _count_bits() in rlib/rbigint.py, - objspace/std/longobject.py and objspace/std/longtype.py. - -- missing module pyexpat.errors - -- support for PYTHONIOENCODING, this needs a way to update file.encoding - -- implement format__Complex_ANY() in pypy/objspace/std/complexobject.py - -- Code like this does not work, for two reasons:: - - \ - from __future__ import (with_statement, - unicode_literals) - assert type("") is unicode - -- Code like:: - - assert(x is not None, "error message") - - should emit a SyntaxWarning when compiled (the tuple is always true) - - -Medium tasks ------------- - -- socket module has a couple of changes (including AF_TIPC packet range) - -Longer tasks ------------- - -- Fix usage of __cmp__ in subclasses:: - - class badint(int): - def __cmp__(self, other): - raise RuntimeError - raises(RuntimeError, cmp, 0, badint(1)) - -- Fix comparison of objects layout: if two classes have the same __slots__, it - should be possible to change the instances __class__:: - - class A(object): __slots__ = ('a', 'b') - class B(object): __slots__ = ('b', 'a') - a = A() - a.__class__ = B - -- Show a ResourceWarning when a file/socket is not explicitely closed, like - CPython did for 3.2: http://svn.python.org/view?view=rev&revision=85920 - in PyPy this should be enabled by default - -Won't do for this release -------------------------- - -Note: when you give up with a missing feature, please mention it here, as well -as the various skips added to the test suite. - -- py3k warnings - - * the -3 flag is accepted on the command line, but displays a warning (see - `translator/goal/app_main.py`) - -- CJK codecs. - - * In `./conftest.py`, skipped all `test_codecencodings_*.py` and - `test_codecmaps_*.py`. - - * In test_codecs, commented out various items in `all_unicode_encodings`. - -- Error messages about ill-formed calls (like "argument after ** must be a - mapping") don't always show the function name. That's hard to fix for - the case of errors raised when the Argument object is created (as opposed - to when parsing for a given target function, which occurs later). - - * Some "..." were added to doctests in test_extcall.py - -- CPython's builtin methods are both functions and unbound methods (for - example, `str.upper is dict(str.__dict__)['upper']`). This is not the case - in pypy, and assertions like `object.__str__ is object.__str__` are False - with pypy. Use the `==` operator instead. - - * pprint.py, _threading_local.py - -- When importing a nested module fails, the ImportError message mentions the - name of the package up to the component that could not be imported (CPython - prefers to display the names starting with the failing part). diff --git a/lib-python/modified-2.7/distutils/sysconfig.py b/lib-python/modified-2.7/distutils/sysconfig.py --- a/lib-python/modified-2.7/distutils/sysconfig.py +++ b/lib-python/modified-2.7/distutils/sysconfig.py @@ -20,8 +20,10 @@ if '__pypy__' in sys.builtin_module_names: from distutils.sysconfig_pypy import * from distutils.sysconfig_pypy import _config_vars # needed by setuptools + from distutils.sysconfig_pypy import _variable_rx # read_setup_file() else: from distutils.sysconfig_cpython import * from distutils.sysconfig_cpython import _config_vars # needed by setuptools + from distutils.sysconfig_cpython import _variable_rx # read_setup_file() diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,3 +116,7 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + +from sysconfig_cpython import ( + parse_makefile, _variable_rx, expand_makefile_vars) + diff --git a/lib_pypy/_pypy_wait.py b/lib_pypy/_pypy_wait.py --- a/lib_pypy/_pypy_wait.py +++ b/lib_pypy/_pypy_wait.py @@ -6,12 +6,12 @@ libc = CDLL(find_library("c")) c_wait3 = libc.wait3 - c_wait3.argtypes = [POINTER(c_int), c_int, POINTER(_struct_rusage)] +c_wait3.restype = c_int c_wait4 = libc.wait4 - c_wait4.argtypes = [c_int, POINTER(c_int), c_int, POINTER(_struct_rusage)] +c_wait4.restype = c_int def create_struct_rusage(c_struct): return struct_rusage(( diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -127,8 +127,6 @@ SQLITE_FUNCTION = 31 # SQLite C API -sqlite.sqlite3_bind_double.argtypes = [c_void_p, c_int, c_double] -sqlite.sqlite3_bind_int64.argtypes = [c_void_p, c_int, c_int64] sqlite.sqlite3_value_int.argtypes = [c_void_p] sqlite.sqlite3_value_int.restype = c_int @@ -151,7 +149,16 @@ sqlite.sqlite3_value_type.argtypes = [c_void_p] sqlite.sqlite3_value_type.restype = c_int +sqlite.sqlite3_bind_blob.argtypes = [c_void_p, c_int, c_void_p, c_int,c_void_p] +sqlite.sqlite3_bind_blob.restype = c_int +sqlite.sqlite3_bind_double.argtypes = [c_void_p, c_int, c_double] +sqlite.sqlite3_bind_double.restype = c_int sqlite.sqlite3_bind_int.argtypes = [c_void_p, c_int, c_int] +sqlite.sqlite3_bind_int.restype = c_int +sqlite.sqlite3_bind_int64.argtypes = [c_void_p, c_int, c_int64] +sqlite.sqlite3_bind_int64.restype = c_int +sqlite.sqlite3_bind_null.argtypes = [c_void_p, c_int] +sqlite.sqlite3_bind_null.restype = c_int sqlite.sqlite3_bind_parameter_count.argtypes = [c_void_p] sqlite.sqlite3_bind_parameter_count.restype = c_int sqlite.sqlite3_bind_parameter_index.argtypes = [c_void_p, c_char_p] @@ -159,45 +166,69 @@ sqlite.sqlite3_bind_parameter_name.argtypes = [c_void_p, c_int] sqlite.sqlite3_bind_parameter_name.restype = c_char_p sqlite.sqlite3_bind_text.argtypes = [c_void_p, c_int, c_char_p, c_int,c_void_p] -sqlite.sqlite3_bind_blob.argtypes = [c_void_p, c_int, c_void_p, c_int,c_void_p] -sqlite.sqlite3_bind_blob.restype = c_int +sqlite.sqlite3_bind_text.restype = c_int +sqlite.sqlite3_busy_timeout.argtypes = [c_void_p, c_int] +sqlite.sqlite3_busy_timeout.restype = c_int sqlite.sqlite3_changes.argtypes = [c_void_p] sqlite.sqlite3_changes.restype = c_int sqlite.sqlite3_close.argtypes = [c_void_p] sqlite.sqlite3_close.restype = c_int +sqlite.sqlite3_column_blob.argtypes = [c_void_p, c_int] sqlite.sqlite3_column_blob.restype = c_void_p +sqlite.sqlite3_column_bytes.argtypes = [c_void_p, c_int] sqlite.sqlite3_column_bytes.restype = c_int +sqlite.sqlite3_column_count.argtypes = [c_void_p] +sqlite.sqlite3_column_count.restype = c_int +sqlite.sqlite3_column_decltype.argtypes = [c_void_p, c_int] +sqlite.sqlite3_column_decltype.restype = c_char_p +sqlite.sqlite3_column_double.argtypes = [c_void_p, c_int] sqlite.sqlite3_column_double.restype = c_double +sqlite.sqlite3_column_int64.argtypes = [c_void_p, c_int] sqlite.sqlite3_column_int64.restype = c_int64 +sqlite.sqlite3_column_name.argtypes = [c_void_p, c_int] sqlite.sqlite3_column_name.restype = c_char_p +sqlite.sqlite3_column_text.argtypes = [c_void_p, c_int] sqlite.sqlite3_column_text.restype = c_char_p +sqlite.sqlite3_column_type.argtypes = [c_void_p, c_int] +sqlite.sqlite3_column_type.restype = c_int sqlite.sqlite3_complete.argtypes = [c_char_p] sqlite.sqlite3_complete.restype = c_int sqlite.sqlite3_errcode.restype = c_int +sqlite.sqlite3_errmsg.argtypes = [c_void_p] sqlite.sqlite3_errmsg.restype = c_char_p +sqlite.sqlite3_finalize.argtypes = [c_void_p] +sqlite.sqlite3_finalize.restype = c_int sqlite.sqlite3_get_autocommit.argtypes = [c_void_p] sqlite.sqlite3_get_autocommit.restype = c_int +sqlite.sqlite3_last_insert_rowid.argtypes = [c_void_p] +sqlite.sqlite3_last_insert_rowid.restype = c_int64 sqlite.sqlite3_libversion.argtypes = [] sqlite.sqlite3_libversion.restype = c_char_p sqlite.sqlite3_open.argtypes = [c_char_p, c_void_p] sqlite.sqlite3_open.restype = c_int +sqlite.sqlite3_prepare.argtypes = [c_void_p, c_char_p, c_int, c_void_p, POINTER(c_char_p)] +sqlite.sqlite3_prepare.restype = c_int sqlite.sqlite3_prepare_v2.argtypes = [c_void_p, c_char_p, c_int, c_void_p, POINTER(c_char_p)] sqlite.sqlite3_prepare_v2.restype = c_int -sqlite.sqlite3_column_decltype.argtypes = [c_void_p, c_int] -sqlite.sqlite3_column_decltype.restype = c_char_p sqlite.sqlite3_step.argtypes = [c_void_p] sqlite.sqlite3_step.restype = c_int sqlite.sqlite3_reset.argtypes = [c_void_p] sqlite.sqlite3_reset.restype = c_int -sqlite.sqlite3_column_count.argtypes = [c_void_p] -sqlite.sqlite3_column_count.restype = c_int +sqlite.sqlite3_total_changes.argtypes = [c_void_p] +sqlite.sqlite3_total_changes.restype = c_int sqlite.sqlite3_result_blob.argtypes = [c_void_p, c_char_p, c_int, c_void_p] +sqlite.sqlite3_result_blob.restype = None sqlite.sqlite3_result_int64.argtypes = [c_void_p, c_int64] +sqlite.sqlite3_result_int64.restype = None sqlite.sqlite3_result_null.argtypes = [c_void_p] +sqlite.sqlite3_result_null.restype = None sqlite.sqlite3_result_double.argtypes = [c_void_p, c_double] +sqlite.sqlite3_result_double.restype = None sqlite.sqlite3_result_error.argtypes = [c_void_p, c_char_p, c_int] +sqlite.sqlite3_result_error.restype = None sqlite.sqlite3_result_text.argtypes = [c_void_p, c_char_p, c_int, c_void_p] +sqlite.sqlite3_result_text.restype = None ########################################## # END Wrapped SQLite C API and constants diff --git a/lib_pypy/stackless.py b/lib_pypy/stackless.py --- a/lib_pypy/stackless.py +++ b/lib_pypy/stackless.py @@ -200,14 +200,15 @@ # I can't think of a better solution without a real transform. def rewrite_stackless_primitive(coro_state, alive, tempval): - flags, state, thunk, parent = coro_state - for i, frame in enumerate(state): + flags, frame, thunk, parent = coro_state + while frame is not None: retval_expr = _stackless_primitive_registry.get(frame.f_code) if retval_expr: # this tasklet needs to stop pickling here and return its value. tempval = eval(retval_expr, globals(), frame.f_locals) - state = state[:i] - coro_state = flags, state, thunk, parent + coro_state = flags, frame, thunk, parent + break + frame = frame.f_back return coro_state, alive, tempval # @@ -492,23 +493,22 @@ assert two == () # we want to get rid of the parent thing. # for now, we just drop it - a, b, c, d = coro_state - + a, frame, c, d = coro_state + # Removing all frames related to stackless.py. # They point to stuff we don't want to be pickled. - frame_list = list(b) - new_frame_list = [] - for frame in frame_list: + + pickleframe = frame + while frame is not None: if frame.f_code == schedule.func_code: # Removing everything including and after the # call to stackless.schedule() + pickleframe = frame.f_back break - new_frame_list.append(frame) - b = tuple(new_frame_list) - + frame = frame.f_back if d: assert isinstance(d, coroutine) - coro_state = a, b, c, None + coro_state = a, pickleframe, c, None coro_state, alive, tempval = rewrite_stackless_primitive(coro_state, self.alive, self.tempval) inst_dict = self.__dict__.copy() inst_dict.pop('tempval', None) diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py --- a/pypy/annotation/annrpython.py +++ b/pypy/annotation/annrpython.py @@ -228,7 +228,7 @@ # graph -- it's already low-level operations! for a, s_newarg in zip(graph.getargs(), cells): s_oldarg = self.binding(a) - assert s_oldarg.contains(s_newarg) + assert annmodel.unionof(s_oldarg, s_newarg) == s_oldarg else: assert not self.frozen for a in cells: diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py --- a/pypy/annotation/description.py +++ b/pypy/annotation/description.py @@ -565,7 +565,7 @@ if self.is_exception_class(): if self.pyobj.__module__ == 'exceptions': return True - if self.pyobj is py.code._AssertionError: + if issubclass(self.pyobj, AssertionError): return True return False diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py --- a/pypy/annotation/model.py +++ b/pypy/annotation/model.py @@ -32,13 +32,15 @@ import pypy from pypy.tool import descriptor from pypy.tool.pairtype import pair, extendabletype -from pypy.tool.tls import tlsobject from pypy.rlib.rarithmetic import r_uint, r_ulonglong, base_int from pypy.rlib.rarithmetic import r_singlefloat, r_longfloat import inspect, weakref DEBUG = False # set to False to disable recording of debugging information -TLS = tlsobject() + +class State(object): + pass +TLS = State() class SomeObject(object): """The set of all objects. Each instance stands diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -33,7 +33,7 @@ "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", "_bisect", "binascii", "_multiprocessing", '_warnings', - "_collections", "_multibytecodec"] + "_collections", "_multibytecodec", "micronumpy"] )) translation_modules = default_modules.copy() @@ -242,6 +242,10 @@ "(the empty string and potentially single-char strings)", default=False), + BoolOption("withsmalltuple", + "use small tuples", + default=False), + BoolOption("withrope", "use ropes as the string implementation", default=False, requires=[("objspace.std.withstrslice", False), @@ -269,7 +273,7 @@ "make instances really small but slow without the JIT", default=False, requires=[("objspace.std.getattributeshortcut", True), - ("objspace.std.withtypeversion", True), + ("objspace.std.withmethodcache", True), ]), BoolOption("withrangelist", diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -221,17 +221,17 @@ StrOption("profile_based_inline", "Use call count profiling to drive inlining" ", specify arguments", - default=None, cmdline="--prof-based-inline"), + default=None), # cmdline="--prof-based-inline" fix me FloatOption("profile_based_inline_threshold", "Threshold when to inline functions " "for profile based inlining", default=DEFL_PROF_BASED_INLINE_THRESHOLD, - cmdline="--prof-based-inline-threshold"), + ), # cmdline="--prof-based-inline-threshold" fix me StrOption("profile_based_inline_heuristic", "Dotted name of an heuristic function " "for profile based inlining", default="pypy.translator.backendopt.inline.inlining_heuristic", - cmdline="--prof-based-inline-heuristic"), + ), # cmdline="--prof-based-inline-heuristic" fix me # control clever malloc removal BoolOption("clever_malloc_removal", "Drives inlining to remove mallocs in a clever way", diff --git a/pypy/conftest.py b/pypy/conftest.py --- a/pypy/conftest.py +++ b/pypy/conftest.py @@ -46,6 +46,10 @@ group.addoption('-P', '--platform', action="callback", type="string", default="host", callback=_set_platform, help="set up tests to use specified platform as compile/run target") + group = parser.getgroup("JIT options") + group.addoption('--viewloops', action="store_true", + default=False, dest="viewloops", + help="show only the compiled loops") def pytest_sessionstart(): # have python subprocesses avoid startup customizations by default diff --git a/pypy/doc/config/objspace.std.withsmalltuple.txt b/pypy/doc/config/objspace.std.withsmalltuple.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withsmalltuple.txt @@ -0,0 +1,1 @@ +Use small tuple objects for sizes from 1 to 3 diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -136,6 +136,11 @@ next access. Any code that uses weak proxies must carefully catch such ``ReferenceError`` at any place that uses them. +As a side effect, the ``finally`` clause inside a generator will be executed +only when the generator object is garbage collected (see `issue 736`__). + +.. __: http://bugs.pypy.org/issue736 + There are a few extra implications for the difference in the GC. Most notably, if an object has a ``__del__``, the ``__del__`` is never called more than once in PyPy; but CPython will call the same ``__del__`` several times diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/project-ideas.rst @@ -0,0 +1,49 @@ + +Potential project list +====================== + +This is a list of projects that are interesting for potential contributors +who are seriously interested in the PyPy project. They mostly share common +patterns - they're mid-to-large in size, they're usually well defined as +a standalone projects and they're not being actively worked on. For small +projects that you might want to work on, it's much better to either look +at the `issue tracker`_, pop up on #pypy on irc.freenode.net or write to the +`mailing list`_. This is simply for the reason that small possible projects +tend to change very rapidly. + +Numpy improvements +------------------ + +This is more of a project-container than a single project. Possible ideas: + +* experiment with auto-vectorization using SSE or implement vectorization + without automatically detecting it for array operations. + +* improve numpy, for example implement memory views. + +* interface with fortran/C libraries. + +Potential mentors: fijal + +JIT tooling +----------- + +xxx + +Work on some of other languages +------------------------------- + +xxx + +Various GCs +----------- + +xxx + +Remove the GIL +-------------- + +xxx + +.. _`issue tracker`: ... +.. _`mailing list`: ... diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -31,11 +31,12 @@ future_lineno = 0 future_column = 0 have_docstring = False + body = None if isinstance(tree, ast.Module): body = tree.body elif isinstance(tree, ast.Interactive): body = tree.body - else: + if body is None: return 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -82,7 +82,7 @@ raise def getaddrstring(self, space): - # XXX slowish + # slowish w_id = space.id(self) w_4 = space.wrap(4) w_0x0F = space.wrap(0x0F) @@ -616,7 +616,6 @@ def createcompiler(self): "Factory function creating a compiler object." - # XXX simple selection logic for now try: return self.default_compiler except AttributeError: @@ -821,11 +820,11 @@ def call_obj_args(self, w_callable, w_obj, args): if not self.config.objspace.disable_call_speedhacks: - # XXX start of hack for performance + # start of hack for performance from pypy.interpreter.function import Function if isinstance(w_callable, Function): return w_callable.call_obj_args(w_obj, args) - # XXX end of hack for performance + # end of hack for performance return self.call_args(w_callable, args.prepend(w_obj)) def call(self, w_callable, w_args, w_kwds=None): @@ -835,7 +834,7 @@ def call_function(self, w_func, *args_w): nargs = len(args_w) # used for pruning funccall versions if not self.config.objspace.disable_call_speedhacks and nargs < 5: - # XXX start of hack for performance + # start of hack for performance from pypy.interpreter.function import Function, Method if isinstance(w_func, Method): w_inst = w_func.w_instance @@ -850,7 +849,7 @@ if isinstance(w_func, Function): return w_func.funccall(*args_w) - # XXX end of hack for performance + # end of hack for performance args = Arguments(self, list(args_w)) return self.call_args(w_func, args) @@ -864,7 +863,7 @@ return self.call_args_and_c_profile(frame, w_func, args) if not self.config.objspace.disable_call_speedhacks: - # XXX start of hack for performance + # start of hack for performance if isinstance(w_func, Method): w_inst = w_func.w_instance if w_inst is not None: @@ -879,7 +878,7 @@ if isinstance(w_func, Function): return w_func.funccall_valuestack(nargs, frame) - # XXX end of hack for performance + # end of hack for performance args = frame.make_arguments(nargs) return self.call_args(w_func, args) @@ -1338,7 +1337,7 @@ source = source.lstrip() assert source.startswith('('), "incorrect header in:\n%s" % (source,) source = py.code.Source("def anonymous%s\n" % source) - w_glob = space.newdict() + w_glob = space.newdict(module=True) space.exec_(str(source), w_glob, w_glob) return space.getitem(w_glob, space.wrap('anonymous')) diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -11,14 +11,14 @@ """Interpreter-level exception that signals an exception that should be sent to the application level. - OperationError instances have three public attributes (and no .args), - w_type, w_value and application_traceback, which contain the wrapped + OperationError instances have three attributes (and no .args), + w_type, _w_value and _application_traceback, which contain the wrapped type and value describing the exception, and a chained list of PyTraceback objects making the application-level traceback. """ _w_value = None - application_traceback = None + _application_traceback = None def __init__(self, w_type, w_value, tb=None): if not we_are_translated() and w_type is None: @@ -26,7 +26,7 @@ raise FlowingError(w_value) self.setup(w_type) self._w_value = w_value - self.application_traceback = tb + self._application_traceback = tb def setup(self, w_type): self.w_type = w_type @@ -37,7 +37,7 @@ # for sys.exc_clear() self.w_type = space.w_None self._w_value = space.w_None - self.application_traceback = None + self._application_traceback = None if not we_are_translated(): del self.debug_excs[:] @@ -103,7 +103,7 @@ def print_app_tb_only(self, file): "NOT_RPYTHON" - tb = self.application_traceback + tb = self._application_traceback if tb: import linecache print >> file, "Traceback (application-level):" @@ -251,6 +251,30 @@ def _compute_value(self): raise NotImplementedError + def get_traceback(self): + """Calling this marks the PyTraceback as escaped, i.e. it becomes + accessible and inspectable by app-level Python code. For the JIT. + Note that this has no effect if there are already several traceback + frames recorded, because in this case they are already marked as + escaping by executioncontext.leave() being called with + got_exception=True. + """ + from pypy.interpreter.pytraceback import PyTraceback + tb = self._application_traceback + if tb is not None and isinstance(tb, PyTraceback): + tb.frame.mark_as_escaped() + return tb + + def set_traceback(self, traceback): + """Set the current traceback. It should either be a traceback + pointing to some already-escaped frame, or a traceback for the + current frame. To support the latter case we do not mark the + frame as escaped. The idea is that it will be marked as escaping + only if the exception really propagates out of this frame, by + executioncontext.leave() being called with got_exception=True. + """ + self._application_traceback = traceback + # ____________________________________________________________ # optimization only: avoid the slowest operation -- the string # formatting with '%' -- in the common case were we don't diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -2,6 +2,7 @@ This module defines the abstract base classes that support execution: Code and Frame. """ +from pypy.rlib import jit from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable @@ -97,6 +98,7 @@ "Abstract. Get the expected number of locals." raise TypeError, "abstract" + @jit.dont_look_inside def fast2locals(self): # Copy values from self.fastlocals_w to self.w_locals if self.w_locals is None: @@ -110,6 +112,7 @@ w_name = self.space.wrap(name) self.space.setitem(self.w_locals, w_name, w_value) + @jit.dont_look_inside def locals2fast(self): # Copy values from self.w_locals to self.fastlocals_w assert self.w_locals is not None diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -24,6 +24,8 @@ # XXX [fijal] but they're not. is_being_profiled is guarded a bit all # over the place as well as w_tracefunc + _immutable_fields_ = ['profilefunc?', 'w_tracefunc?'] + def __init__(self, space): self.space = space self.topframeref = jit.vref_None @@ -56,13 +58,23 @@ frame.f_backref = self.topframeref self.topframeref = jit.virtual_ref(frame) - def leave(self, frame, w_exitvalue): + def leave(self, frame, w_exitvalue, got_exception): try: if self.profilefunc: self._trace(frame, 'leaveframe', w_exitvalue) finally: + frame_vref = self.topframeref self.topframeref = frame.f_backref - jit.virtual_ref_finish(frame) + if frame.escaped or got_exception: + # if this frame escaped to applevel, we must ensure that also + # f_back does + f_back = frame.f_backref() + if f_back: + f_back.mark_as_escaped() + # force the frame (from the JIT point of view), so that it can + # be accessed also later + frame_vref() + jit.virtual_ref_finish(frame_vref, frame) if self.w_tracefunc is not None and not frame.hide(): self.space.frame_trace_action.fire() @@ -100,18 +112,16 @@ # the following interface is for pickling and unpickling def getstate(self, space): - # XXX we could just save the top frame, which brings - # the whole frame stack, but right now we get the whole stack - items = [space.wrap(f) for f in self.getframestack()] - return space.newtuple(items) + if self.topframe is None: + return space.w_None + return self.topframe def setstate(self, space, w_state): from pypy.interpreter.pyframe import PyFrame - frames_w = space.unpackiterable(w_state) - if len(frames_w) > 0: - self.topframe = space.interp_w(PyFrame, frames_w[-1]) + if space.is_w(w_state, space.w_None): + self.topframe = None else: - self.topframe = None + self.topframe = space.interp_w(PyFrame, w_state) def getframestack(self): lst = [] @@ -276,7 +286,7 @@ if operr is not None: w_value = operr.get_w_value(space) w_arg = space.newtuple([operr.w_type, w_value, - space.wrap(operr.application_traceback)]) + space.wrap(operr.get_traceback())]) frame.fast2locals() self.is_tracing += 1 diff --git a/pypy/interpreter/main.py b/pypy/interpreter/main.py --- a/pypy/interpreter/main.py +++ b/pypy/interpreter/main.py @@ -118,7 +118,7 @@ operationerr.normalize_exception(space) w_type = operationerr.w_type w_value = operationerr.get_w_value(space) - w_traceback = space.wrap(operationerr.application_traceback) + w_traceback = space.wrap(operationerr.get_traceback()) # for debugging convenience we also insert the exception into # the interpreter-level sys.last_xxx diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -127,6 +127,7 @@ if self.cells is not None: self.cells[:ncellvars] = cellvars + @jit.dont_look_inside def fast2locals(self): super_fast2locals(self) # cellvars are values exported to inner scopes @@ -145,6 +146,7 @@ w_name = self.space.wrap(name) self.space.setitem(self.w_locals, w_name, w_value) + @jit.dont_look_inside def locals2fast(self): super_locals2fast(self) freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -101,9 +101,9 @@ """ def __init__(self, space, override_version=None): PyCodeCompiler.__init__(self, space) - self.parser = pyparse.PythonParser(space) + self.future_flags = future.futureFlags_2_7 + self.parser = pyparse.PythonParser(space, self.future_flags) self.additional_rules = {} - self.future_flags = future.futureFlags_2_7 self.compiler_flags = self.future_flags.allowed_flags def compile_ast(self, node, filename, mode, flags): @@ -140,9 +140,6 @@ def _compile_to_ast(self, source, info): space = self.space try: - f_flags, future_info = future.get_futures(self.future_flags, source) - info.last_future_import = future_info - info.flags |= f_flags parse_tree = self.parser.parse_source(source, info) mod = astbuilder.ast_from_node(space, parse_tree, info) except parseerror.IndentationError, e: diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -11,7 +11,7 @@ from pypy.rlib.jit import hint from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import intmask -from pypy.rlib import jit, rstack +from pypy.rlib import jit from pypy.tool import stdlib_opcode from pypy.tool.stdlib_opcode import host_bytecode_spec @@ -49,6 +49,7 @@ instr_ub = 0 instr_prev_plus_one = 0 is_being_profiled = False + escaped = False # see mark_as_escaped() def __init__(self, space, code, w_globals, closure): self = hint(self, access_directly=True, fresh_virtualizable=True) @@ -67,6 +68,15 @@ make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno + def mark_as_escaped(self): + """ + Must be called on frames that are exposed to applevel, e.g. by + sys._getframe(). This ensures that the virtualref holding the frame + is properly forced by ec.leave(), and thus the frame will be still + accessible even after the corresponding C stack died. + """ + self.escaped = True + def append_block(self, block): block.previous = self.lastblock self.lastblock = block @@ -138,6 +148,7 @@ not self.space.config.translating) executioncontext = self.space.getexecutioncontext() executioncontext.enter(self) + got_exception = True w_exitvalue = self.space.w_None try: executioncontext.call_trace(self) @@ -157,8 +168,6 @@ try: w_exitvalue = self.dispatch(self.pycode, next_instr, executioncontext) - rstack.resume_point("execute_frame", self, executioncontext, - returns=w_exitvalue) except Exception: executioncontext.return_trace(self, self.space.w_None) raise @@ -166,8 +175,9 @@ # clean up the exception, might be useful for not # allocating exception objects in some cases self.last_exception = None + got_exception = False finally: - executioncontext.leave(self, w_exitvalue) + executioncontext.leave(self, w_exitvalue, got_exception) return w_exitvalue execute_frame.insert_stack_check_here = True @@ -314,7 +324,7 @@ w_tb = space.w_None else: w_exc_value = self.last_exception.get_w_value(space) - w_tb = w(self.last_exception.application_traceback) + w_tb = w(self.last_exception.get_traceback()) tup_state = [ w(self.f_backref()), @@ -415,6 +425,7 @@ "Get the fast locals as a list." return self.fastlocals_w + @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" @@ -634,7 +645,7 @@ while f is not None and f.last_exception is None: f = f.f_backref() if f is not None: - return space.wrap(f.last_exception.application_traceback) + return space.wrap(f.last_exception.get_traceback()) return space.w_None def fget_f_restricted(self, space): diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -11,7 +11,7 @@ from pypy.interpreter.pycode import PyCode from pypy.tool.sourcetools import func_with_new_name from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib import jit, rstackovf, rstack +from pypy.rlib import jit, rstackovf from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import check_nonneg @@ -83,16 +83,12 @@ try: while True: next_instr = self.handle_bytecode(co_code, next_instr, ec) - rstack.resume_point("dispatch", self, co_code, ec, - returns=next_instr) except ExitFrame: return self.popvalue() def handle_bytecode(self, co_code, next_instr, ec): try: next_instr = self.dispatch_bytecode(co_code, next_instr, ec) - rstack.resume_point("handle_bytecode", self, co_code, ec, - returns=next_instr) except OperationError, operr: next_instr = self.handle_operation_error(ec, operr) except Reraise: @@ -248,9 +244,6 @@ # dispatch to the opcode method meth = getattr(self, opdesc.methodname) res = meth(oparg, next_instr) - if opdesc.index == self.opcodedesc.CALL_FUNCTION.index: - rstack.resume_point("dispatch_call", self, co_code, - next_instr, ec) # !! warning, for the annotator the next line is not # comparing an int and None - you can't do that. # Instead, it's constant-folded to either True or False @@ -573,7 +566,7 @@ else: msg = "raise: arg 3 must be a traceback or None" tb = pytraceback.check_traceback(space, w_traceback, msg) - operror.application_traceback = tb + operror.set_traceback(tb) # special 3-arguments raise, no new traceback obj will be attached raise RaiseWithExplicitTraceback(operror) @@ -953,7 +946,7 @@ isinstance(unroller, SApplicationException)) if is_app_exc: operr = unroller.operr - w_traceback = self.space.wrap(operr.application_traceback) + w_traceback = self.space.wrap(operr.get_traceback()) w_suppress = self.call_contextmanager_exit_function( w_exitfunc, operr.w_type, @@ -997,7 +990,6 @@ args) else: w_result = self.space.call_args(w_function, args) - rstack.resume_point("call_function", self, returns=w_result) self.pushvalue(w_result) def CALL_FUNCTION(self, oparg, next_instr): @@ -1008,8 +1000,6 @@ w_function = self.peekvalue(nargs) try: w_result = self.space.call_valuestack(w_function, nargs, self) - rstack.resume_point("CALL_FUNCTION", self, nargs, - returns=w_result) finally: self.dropvalues(nargs + 1) self.pushvalue(w_result) @@ -1099,6 +1089,7 @@ w_dict = self.space.newdict() self.pushvalue(w_dict) + @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): w_set = self.space.call_function(self.space.w_set) if itemcount: diff --git a/pypy/interpreter/pyparser/pyparse.py b/pypy/interpreter/pyparser/pyparse.py --- a/pypy/interpreter/pyparser/pyparse.py +++ b/pypy/interpreter/pyparser/pyparse.py @@ -1,6 +1,6 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.pyparser import parser, pytokenizer, pygram, error +from pypy.interpreter.pyparser import future, parser, pytokenizer, pygram, error from pypy.interpreter.astcompiler import consts @@ -88,9 +88,11 @@ class PythonParser(parser.Parser): - def __init__(self, space, grammar=pygram.python_grammar): + def __init__(self, space, future_flags=future.futureFlags_2_7, + grammar=pygram.python_grammar): parser.Parser.__init__(self, grammar) self.space = space + self.future_flags = future_flags def parse_source(self, textsrc, compile_info): """Main entry point for parsing Python source. @@ -133,6 +135,10 @@ raise error.SyntaxError(space.str_w(w_message)) raise + f_flags, future_info = future.get_futures(self.future_flags, textsrc) + compile_info.last_future_import = future_info + compile_info.flags |= f_flags + flags = compile_info.flags if flags & consts.CO_FUTURE_PRINT_FUNCTION: diff --git a/pypy/interpreter/pytraceback.py b/pypy/interpreter/pytraceback.py --- a/pypy/interpreter/pytraceback.py +++ b/pypy/interpreter/pytraceback.py @@ -51,9 +51,9 @@ def record_application_traceback(space, operror, frame, last_instruction): if frame.pycode.hidden_applevel: return - tb = operror.application_traceback + tb = operror.get_traceback() tb = PyTraceback(space, frame, last_instruction, tb) - operror.application_traceback = tb + operror.set_traceback(tb) def offset2lineno(c, stopat): tab = c.co_lnotab diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -714,6 +714,12 @@ class AppTestCompiler: + def test_bom_with_future(self): + s = '\xef\xbb\xbffrom __future__ import division\nx = 1/2' + ns = {} + exec s in ns + assert ns["x"] == .5 + def test_values_of_different_types(self): exec "a = 0; b = 0L; c = 0.0; d = 0j" assert type(a) is int diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py --- a/pypy/interpreter/test/test_pyframe.py +++ b/pypy/interpreter/test/test_pyframe.py @@ -98,6 +98,15 @@ return sys._getframe().f_back.f_code.co_name f() + def test_f_back_virtualref(self): + import sys + def f(): + return g() + def g(): + return sys._getframe() + frame = f() + assert frame.f_back.f_code.co_name == 'f' + def test_f_exc_xxx(self): import sys @@ -122,6 +131,21 @@ except: g(sys.exc_info()) + def test_virtualref_through_traceback(self): + import sys + def g(): + try: + raise ValueError + except: + _, _, tb = sys.exc_info() + return tb + def f(): + return g() + # + tb = f() + assert tb.tb_frame.f_code.co_name == 'g' + assert tb.tb_frame.f_back.f_code.co_name == 'f' + def test_trace_basic(self): import sys l = [] diff --git a/pypy/jit/backend/arm/test/test_zrpy_gc.py b/pypy/jit/backend/arm/test/test_zrpy_gc.py --- a/pypy/jit/backend/arm/test/test_zrpy_gc.py +++ b/pypy/jit/backend/arm/test/test_zrpy_gc.py @@ -524,8 +524,8 @@ glob = A() def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): a = A() - glob.v = virtual_ref(a) - virtual_ref_finish(a) + glob.v = vref = virtual_ref(a) + virtual_ref_finish(vref, a) n -= 1 return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s return None, f, None diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -209,7 +209,7 @@ llimpl.compile_add_fail_arg(c, var2index[box]) else: llimpl.compile_add_fail_arg(c, -1) - + x = op.result if x is not None: if isinstance(x, history.BoxInt): diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -143,11 +143,11 @@ STACK_CHECK_SLOWPATH = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) def insert_stack_check(): - startaddr = rstack._stack_get_start_adr() - length = rstack._stack_get_length() + endaddr = rstack._stack_get_end_adr() + lengthaddr = rstack._stack_get_length_adr() f = llhelper(STACK_CHECK_SLOWPATH, rstack.stack_check_slowpath) slowpathaddr = rffi.cast(lltype.Signed, f) - return startaddr, length, slowpathaddr + return endaddr, lengthaddr, slowpathaddr self.pos_exception = pos_exception self.pos_exc_value = pos_exc_value diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py --- a/pypy/jit/backend/llsupport/regalloc.py +++ b/pypy/jit/backend/llsupport/regalloc.py @@ -221,18 +221,6 @@ del self.reg_bindings[var] self.free_regs.append(loc) except KeyError: - if not we_are_translated(): - import pdb; pdb.set_trace() - else: - raise ValueError - - def force_spill_var(self, var): - self._sync_var(var) - try: - loc = self.reg_bindings[var] - del self.reg_bindings[var] - self.free_regs.append(loc) - except KeyError: pass # 'var' is already not in a register def loc(self, box): diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -137,10 +137,11 @@ self.current_clt = looptoken.compiled_loop_token self.pending_guard_tokens = [] self.mc = codebuf.MachineCodeBlockWrapper() - if self.datablockwrapper is None: - allblocks = self.get_asmmemmgr_blocks(looptoken) - self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr, - allblocks) + #assert self.datablockwrapper is None --- but obscure case + # possible, e.g. getting MemoryError and continuing + allblocks = self.get_asmmemmgr_blocks(looptoken) + self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr, + allblocks) def teardown(self): self.pending_guard_tokens = None @@ -620,11 +621,11 @@ if self.stack_check_slowpath == 0: pass # no stack check (e.g. not translated) else: - startaddr, length, _ = self.cpu.insert_stack_check() - self.mc.MOV(eax, esp) # MOV eax, current - self.mc.SUB(eax, heap(startaddr)) # SUB eax, [startaddr] - self.mc.CMP(eax, imm(length)) # CMP eax, length - self.mc.J_il8(rx86.Conditions['B'], 0) # JB .skip + endaddr, lengthaddr, _ = self.cpu.insert_stack_check() + self.mc.MOV(eax, heap(endaddr)) # MOV eax, [start] + self.mc.SUB(eax, esp) # SUB eax, current + self.mc.CMP(eax, heap(lengthaddr)) # CMP eax, [length] + self.mc.J_il8(rx86.Conditions['BE'], 0) # JBE .skip jb_location = self.mc.get_relative_pos() self.mc.CALL(imm(self.stack_check_slowpath))# CALL slowpath # patch the JB above # .skip: @@ -678,27 +679,29 @@ nonfloatlocs, floatlocs = arglocs self._call_header_with_stack_check() self.mc.LEA_rb(esp.value, self._get_offset_of_ebp_from_esp(stackdepth)) - for i in range(len(nonfloatlocs)): - loc = nonfloatlocs[i] - if isinstance(loc, RegLoc): - assert not loc.is_xmm - self.mc.MOV_rb(loc.value, (2 + i) * WORD) - loc = floatlocs[i] - if isinstance(loc, RegLoc): - assert loc.is_xmm - self.mc.MOVSD_xb(loc.value, (1 + i) * 2 * WORD) + offset = 2 * WORD tmp = eax xmmtmp = xmm0 for i in range(len(nonfloatlocs)): loc = nonfloatlocs[i] - if loc is not None and not isinstance(loc, RegLoc): - self.mc.MOV_rb(tmp.value, (2 + i) * WORD) - self.mc.MOV(loc, tmp) + if loc is not None: + if isinstance(loc, RegLoc): + assert not loc.is_xmm + self.mc.MOV_rb(loc.value, offset) + else: + self.mc.MOV_rb(tmp.value, offset) + self.mc.MOV(loc, tmp) + offset += WORD loc = floatlocs[i] - if loc is not None and not isinstance(loc, RegLoc): - self.mc.MOVSD_xb(xmmtmp.value, (1 + i) * 2 * WORD) - assert isinstance(loc, StackLoc) - self.mc.MOVSD_bx(loc.value, xmmtmp.value) + if loc is not None: + if isinstance(loc, RegLoc): + assert loc.is_xmm + self.mc.MOVSD_xb(loc.value, offset) + else: + self.mc.MOVSD_xb(xmmtmp.value, offset) + assert isinstance(loc, StackLoc) + self.mc.MOVSD_bx(loc.value, xmmtmp.value) + offset += 2 * WORD endpos = self.mc.get_relative_pos() + 5 self.mc.JMP_l(jmppos - endpos) assert endpos == self.mc.get_relative_pos() @@ -1099,6 +1102,8 @@ self.mc.MOV_bi(FORCE_INDEX_OFS, force_index) return force_index else: + # the return value is ignored, apart from the fact that it + # is not negative. return 0 genop_int_neg = _unaryop("NEG") @@ -2182,7 +2187,8 @@ # a no-op. # reserve room for the argument to the real malloc and the - # 8 saved XMM regs + # saved XMM regs (on 32 bit: 8 * 2 words; on 64 bit: 16 * 1 + # word) self._regalloc.reserve_param(1+16) gcrootmap = self.cpu.gc_ll_descr.gcrootmap diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -326,7 +326,7 @@ if not we_are_translated(): self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) self.assembler.regalloc_perform_llong(op, arglocs, result_loc) - + def PerformMath(self, op, arglocs, result_loc): if not we_are_translated(): self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) @@ -634,7 +634,7 @@ loc0 = self.xrm.force_result_in_reg(op.result, op.getarg(0)) self.Perform(op, [loc0], loc0) self.xrm.possibly_free_var(op.getarg(0)) - + consider_float_neg = _consider_float_unary_op consider_float_abs = _consider_float_unary_op @@ -722,7 +722,7 @@ loc1 = self.rm.make_sure_var_in_reg(op.getarg(1)) self.PerformLLong(op, [loc1], loc0) self.rm.possibly_free_vars_for_op(op) - + def _consider_math_sqrt(self, op): loc0 = self.xrm.force_result_in_reg(op.result, op.getarg(1)) self.PerformMath(op, [loc0], loc0) @@ -1229,12 +1229,12 @@ xmmtmploc = self.xrm.force_allocate_reg(box1, selected_reg=xmmtmp) # Part about non-floats # XXX we don't need a copy, we only just the original list - src_locations1 = [self.loc(op.getarg(i)) for i in range(op.numargs()) + src_locations1 = [self.loc(op.getarg(i)) for i in range(op.numargs()) if op.getarg(i).type != FLOAT] assert tmploc not in nonfloatlocs dst_locations1 = [loc for loc in nonfloatlocs if loc is not None] # Part about floats - src_locations2 = [self.loc(op.getarg(i)) for i in range(op.numargs()) + src_locations2 = [self.loc(op.getarg(i)) for i in range(op.numargs()) if op.getarg(i).type == FLOAT] dst_locations2 = [loc for loc in floatlocs if loc is not None] remap_frame_layout_mixed(assembler, diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -508,7 +508,9 @@ LEA = _binaryop('LEA') MOVSD = _binaryop('MOVSD') + MOVAPD = _binaryop('MOVAPD') ADDSD = _binaryop('ADDSD') + ADDPD = _binaryop('ADDPD') SUBSD = _binaryop('SUBSD') MULSD = _binaryop('MULSD') DIVSD = _binaryop('DIVSD') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -690,12 +690,17 @@ define_modrm_modes('MOVSD_x*', ['\xF2', rex_nw, '\x0F\x10', register(1,8)], regtype='XMM') define_modrm_modes('MOVSD_*x', ['\xF2', rex_nw, '\x0F\x11', register(2,8)], regtype='XMM') +define_modrm_modes('MOVAPD_x*', ['\x66', rex_nw, '\x0F\x28', register(1,8)], + regtype='XMM') +define_modrm_modes('MOVAPD_*x', ['\x66', rex_nw, '\x0F\x29', register(2,8)], + regtype='XMM') define_modrm_modes('SQRTSD_x*', ['\xF2', rex_nw, '\x0F\x51', register(1,8)], regtype='XMM') #define_modrm_modes('XCHG_r*', [rex_w, '\x87', register(1, 8)]) define_modrm_modes('ADDSD_x*', ['\xF2', rex_nw, '\x0F\x58', register(1, 8)], regtype='XMM') +define_modrm_modes('ADDPD_x*', ['\x66', rex_nw, '\x0F\x58', register(1, 8)], regtype='XMM') define_modrm_modes('SUBSD_x*', ['\xF2', rex_nw, '\x0F\x5C', register(1, 8)], regtype='XMM') define_modrm_modes('MULSD_x*', ['\xF2', rex_nw, '\x0F\x59', register(1, 8)], regtype='XMM') define_modrm_modes('DIVSD_x*', ['\xF2', rex_nw, '\x0F\x5E', register(1, 8)], regtype='XMM') diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -525,8 +525,8 @@ glob = A() def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): a = A() - glob.v = virtual_ref(a) - virtual_ref_finish(a) + glob.v = vref = virtual_ref(a) + virtual_ref_finish(vref, a) n -= 1 return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s return None, f, None diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -219,11 +219,10 @@ assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect + can_invalidate = self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE - elif self.quasiimmut_analyzer.analyze(op): - extraeffect = EffectInfo.EF_CAN_INVALIDATE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif pure: @@ -236,12 +235,14 @@ # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, - oopspecindex) + oopspecindex, can_invalidate) # if pure or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE - assert extraeffect != EffectInfo.EF_CAN_INVALIDATE + # XXX this should also say assert not can_invalidate, but + # it can't because our analyzer is not good enough for now + # (and getexecutioncontext() can't really invalidate) # return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT, effectinfo) diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -13,7 +13,6 @@ EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) - EF_CAN_INVALIDATE = 4 #can force all GUARD_NOT_INVALIDATED EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables # the 'oopspecindex' field is one of the following values: @@ -79,7 +78,8 @@ def __new__(cls, readonly_descrs_fields, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, - oopspecindex=OS_NONE): + oopspecindex=OS_NONE, + can_invalidate=False): key = (frozenset(readonly_descrs_fields), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), @@ -97,19 +97,21 @@ result.write_descrs_fields = write_descrs_fields result.write_descrs_arrays = write_descrs_arrays result.extraeffect = extraeffect + result.can_invalidate = can_invalidate result.oopspecindex = oopspecindex cls._cache[key] = result return result def check_can_invalidate(self): - return self.extraeffect >= self.EF_CAN_INVALIDATE + return self.can_invalidate def check_forces_virtual_or_virtualizable(self): return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, - oopspecindex=EffectInfo.OS_NONE): + oopspecindex=EffectInfo.OS_NONE, + can_invalidate=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: return None @@ -147,7 +149,8 @@ write_descrs_fields, write_descrs_arrays, extraeffect, - oopspecindex) + oopspecindex, + can_invalidate) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: diff --git a/pypy/jit/codewriter/jitcode.py b/pypy/jit/codewriter/jitcode.py --- a/pypy/jit/codewriter/jitcode.py +++ b/pypy/jit/codewriter/jitcode.py @@ -100,6 +100,9 @@ def __repr__(self): return '' % self.name + def _clone_if_mutable(self): + raise NotImplementedError + class MissingLiveness(Exception): pass @@ -111,6 +114,9 @@ dict = getattr(self, 'dict', '?') return '' % (dict,) + def _clone_if_mutable(self): + raise NotImplementedError + class LiveVarsInfo(object): def __init__(self, live_i, live_r, live_f): diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -209,7 +209,6 @@ def rewrite_op_cast_int_to_unichar(self, op): pass def rewrite_op_cast_int_to_uint(self, op): pass def rewrite_op_cast_uint_to_int(self, op): pass - def rewrite_op_resume_point(self, op): pass def _rewrite_symmetric(self, op): """Rewrite 'c1+v2' into 'v2+c1' in an attempt to avoid generating diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -63,12 +63,27 @@ contains_loop = contains_loop and not getattr( func, '_jit_unroll_safe_', False) - res = see_function and not contains_unsupported_variable_type(graph, - self.supports_floats, - self.supports_longlong) + unsupported = contains_unsupported_variable_type(graph, + self.supports_floats, + self.supports_longlong) + res = see_function and not unsupported if res and contains_loop: self.unsafe_loopy_graphs.add(graph) - return res and not contains_loop + res = res and not contains_loop + if (see_function and not res and + getattr(graph, "access_directly", False)): + # This happens when we have a function which has an argument with + # the access_directly flag, and the annotator has determined we will + # see the function. (See + # pypy/annotation/specialize.py:default_specialize) However, + # look_inside_graph just decided that we will not see it. (It has a + # loop or unsupported variables.) If we return False, the call will + # be turned into a residual call, but the graph is access_directly! + # If such a function is called and accesses a virtualizable, the JIT + # will not notice, and the virtualizable will fall out of sync. So, + # we fail loudly now. + raise ValueError("access_directly on a function which we don't see %s" % graph) + return res def contains_unsupported_variable_type(graph, supports_floats, supports_longlong): diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -1,4 +1,5 @@ import sys +import py from pypy.jit.codewriter.policy import contains_unsupported_variable_type from pypy.jit.codewriter.policy import JitPolicy from pypy.jit.codewriter import support @@ -107,3 +108,19 @@ mod = called_graph.func.__module__ assert (mod == 'pypy.rpython.rlist' or mod == 'pypy.rpython.lltypesystem.rlist') + +def test_access_directly_but_not_seen(): + class X: + _virtualizable2_ = ["a"] + def h(x, y): + w = 0 + for i in range(y): + w += 4 + return w + def f(y): + x = jit.hint(X(), access_directly=True) + h(x, y) + rtyper = support.annotate(f, [3]) + h_graph = rtyper.annotator.translator.graphs[1] + assert h_graph.func is h + py.test.raises(ValueError, JitPolicy().look_inside_graph, h_graph) diff --git a/pypy/jit/conftest.py b/pypy/jit/conftest.py --- a/pypy/jit/conftest.py +++ b/pypy/jit/conftest.py @@ -5,7 +5,4 @@ group.addoption('--slow', action="store_true", default=False, dest="run_slow_tests", help="run all the compiled tests (instead of just a few)") - group.addoption('--viewloops', action="store_true", - default=False, dest="viewloops", - help="show only the compiled loops") diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -97,7 +97,7 @@ history = metainterp.history loop = create_empty_loop(metainterp) - loop.inputargs = history.inputargs + loop.inputargs = history.inputargs[:] for box in loop.inputargs: assert isinstance(box, Box) # make a copy, because optimize_loop can mutate the ops and descrs @@ -124,18 +124,21 @@ return old_loop_token if loop.preamble.operations is not None: - send_loop_to_backend(metainterp_sd, loop, "loop") + send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, + "loop") record_loop_or_bridge(metainterp_sd, loop) token = loop.preamble.token if full_preamble_needed: - send_loop_to_backend(metainterp_sd, loop.preamble, "entry bridge") + send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, + loop.preamble, "entry bridge") insert_loop_token(old_loop_tokens, loop.preamble.token) jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp( greenkey, loop.preamble.token) record_loop_or_bridge(metainterp_sd, loop.preamble) return token else: - send_loop_to_backend(metainterp_sd, loop, "loop") + send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, + "loop") insert_loop_token(old_loop_tokens, loop_token) jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp( greenkey, loop.token) @@ -150,7 +153,9 @@ # XXX do we still need a list? old_loop_tokens.append(loop_token) -def send_loop_to_backend(metainterp_sd, loop, type): +def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type): + jitdriver_sd.on_compile(metainterp_sd.logger_ops, loop.token, + loop.operations, type, greenkey) globaldata = metainterp_sd.globaldata loop_token = loop.token loop_token.number = n = globaldata.loopnumbering @@ -186,8 +191,11 @@ if metainterp_sd.warmrunnerdesc is not None: # for tests metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(loop.token) -def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations, - original_loop_token): +def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs, + operations, original_loop_token): + n = metainterp_sd.cpu.get_fail_descr_number(faildescr) + jitdriver_sd.on_compile_bridge(metainterp_sd.logger_ops, + original_loop_token, operations, n) if not we_are_translated(): show_loop(metainterp_sd) TreeLoop.check_consistency_of(inputargs, operations) @@ -204,7 +212,6 @@ metainterp_sd.stats.compiled() metainterp_sd.log("compiled new bridge") # - n = metainterp_sd.cpu.get_fail_descr_number(faildescr) metainterp_sd.logger_ops.log_bridge(inputargs, operations, n, ops_offset) # if metainterp_sd.warmrunnerdesc is not None: # for tests @@ -390,8 +397,9 @@ inputargs = metainterp.history.inputargs if not we_are_translated(): self._debug_suboperations = new_loop.operations - send_bridge_to_backend(metainterp.staticdata, self, inputargs, - new_loop.operations, new_loop.token) + send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata, + self, inputargs, new_loop.operations, + new_loop.token) def copy_all_attributes_into(self, res): # XXX a bit ugly to have to list them all here @@ -570,7 +578,8 @@ # to every guard in the loop. new_loop_token = make_loop_token(len(redargs), jitdriver_sd) new_loop.token = new_loop_token - send_loop_to_backend(metainterp_sd, new_loop, "entry bridge") + send_loop_to_backend(self.original_greenkey, metainterp.jitdriver_sd, + metainterp_sd, new_loop, "entry bridge") # send the new_loop to warmspot.py, to be called directly the next time jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp( self.original_greenkey, @@ -600,7 +609,7 @@ # Attempt to use optimize_bridge(). This may return None in case # it does not work -- i.e. none of the existing old_loop_tokens match. new_loop = create_empty_loop(metainterp) - new_loop.inputargs = metainterp.history.inputargs + new_loop.inputargs = metainterp.history.inputargs[:] # clone ops, as optimize_bridge can mutate the ops new_loop.operations = [op.clone() for op in metainterp.history.operations] metainterp_sd = metainterp.staticdata diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -294,8 +294,8 @@ cpu.set_future_value_int(j, self.value) def same_constant(self, other): - if isinstance(other, Const): - return self.value == other.getint() + if isinstance(other, ConstInt): + return self.value == other.value return False def nonnull(self): @@ -787,7 +787,6 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) - class TreeLoop(object): inputargs = None operations = None @@ -957,7 +956,7 @@ compiled_count = 0 enter_count = 0 aborted_count = 0 - history = None + operations = None def __init__(self): self.loops = [] @@ -965,7 +964,7 @@ self.aborted_keys = [] def set_history(self, history): - self.history = history + self.operations = history.operations def aborted(self): self.aborted_count += 1 @@ -995,7 +994,7 @@ def check_history(self, expected=None, **check): insns = {} - for op in self.history.operations: + for op in self.operations: opname = op.getopname() insns[opname] = insns.get(opname, 0) + 1 if expected is not None: diff --git a/pypy/jit/metainterp/jitdriver.py b/pypy/jit/metainterp/jitdriver.py --- a/pypy/jit/metainterp/jitdriver.py +++ b/pypy/jit/metainterp/jitdriver.py @@ -20,6 +20,7 @@ # self.portal_finishtoken... pypy.jit.metainterp.pyjitpl # self.index ... pypy.jit.codewriter.call # self.mainjitcode ... pypy.jit.codewriter.call + # self.on_compile ... pypy.jit.metainterp.warmstate # These attributes are read by the backend in CALL_ASSEMBLER: # self.assembler_helper_adr diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py --- a/pypy/jit/metainterp/logger.py +++ b/pypy/jit/metainterp/logger.py @@ -75,6 +75,40 @@ else: return '?' + def repr_of_resop(self, memo, op, ops_offset=None): + if op.getopnum() == rop.DEBUG_MERGE_POINT: + loc = op.getarg(0)._get_str() + reclev = op.getarg(1).getint() + return "debug_merge_point('%s', %s)" % (loc, reclev) + if ops_offset is None: + offset = -1 + else: + offset = ops_offset.get(op, -1) + if offset == -1: + s_offset = "" + else: + s_offset = "+%d: " % offset + args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())]) + if op.result is not None: + res = self.repr_of_arg(memo, op.result) + " = " + else: + res = "" + is_guard = op.is_guard() + if op.getdescr() is not None: + descr = op.getdescr() + if is_guard and self.guard_number: + index = self.metainterp_sd.cpu.get_fail_descr_number(descr) + r = "" % index + else: + r = self.repr_of_descr(descr) + args += ', descr=' + r + if is_guard and op.getfailargs() is not None: + fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg) + for arg in op.getfailargs()]) + ']' + else: + fail_args = '' + return s_offset + res + op.getopname() + '(' + args + ')' + fail_args + def _log_operations(self, inputargs, operations, ops_offset): if not have_debug_prints(): return @@ -86,37 +120,7 @@ debug_print('[' + args + ']') for i in range(len(operations)): op = operations[i] - if op.getopnum() == rop.DEBUG_MERGE_POINT: - loc = op.getarg(0)._get_str() - reclev = op.getarg(1).getint() - debug_print("debug_merge_point('%s', %s)" % (loc, reclev)) - continue - offset = ops_offset.get(op, -1) - if offset == -1: - s_offset = "" - else: - s_offset = "+%d: " % offset - args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())]) - if op.result is not None: - res = self.repr_of_arg(memo, op.result) + " = " - else: - res = "" - is_guard = op.is_guard() - if op.getdescr() is not None: - descr = op.getdescr() - if is_guard and self.guard_number: - index = self.metainterp_sd.cpu.get_fail_descr_number(descr) - r = "" % index - else: - r = self.repr_of_descr(descr) - args += ', descr=' + r - if is_guard and op.getfailargs() is not None: - fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg) - for arg in op.getfailargs()]) + ']' - else: - fail_args = '' - debug_print(s_offset + res + op.getopname() + - '(' + args + ')' + fail_args) + debug_print(self.repr_of_resop(memo, operations[i], ops_offset)) if ops_offset and None in ops_offset: offset = ops_offset[None] debug_print("+%d: --end of the loop--" % offset) diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -161,6 +161,9 @@ if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW: # Synthesize the non overflowing op for optimize_default to reuse self.pure(rop.INT_ADD, op.getarglist()[:], op.result) + # Synthesize the reverse op for optimize_default to reuse + self.pure(rop.INT_SUB, [op.result, op.getarg(1)], op.getarg(0)) + self.pure(rop.INT_SUB, [op.result, op.getarg(0)], op.getarg(1)) def optimize_INT_SUB_OVF(self, op): @@ -180,6 +183,10 @@ if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW: # Synthesize the non overflowing op for optimize_default to reuse self.pure(rop.INT_SUB, op.getarglist()[:], op.result) + # Synthesize the reverse ops for optimize_default to reuse + self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0)) + self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1)) + def optimize_INT_MUL_OVF(self, op): v1 = self.getvalue(op.getarg(0)) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -415,14 +415,22 @@ dest_start_box = self.get_constant_box(op.getarg(4)) length = self.get_constant_box(op.getarg(5)) if (source_value.is_virtual() and source_start_box and dest_start_box - and length and dest_value.is_virtual()): - # XXX optimize the case where dest value is not virtual, - # but we still can avoid a mess + and length and (dest_value.is_virtual() or length.getint() <= 8)): + from pypy.jit.metainterp.optimizeopt.virtualize import VArrayValue + assert isinstance(source_value, VArrayValue) source_start = source_start_box.getint() dest_start = dest_start_box.getint() for index in range(length.getint()): val = source_value.getitem(index + source_start) - dest_value.setitem(index + dest_start, val) + if dest_value.is_virtual(): + dest_value.setitem(index + dest_start, val) + else: + newop = ResOperation(rop.SETARRAYITEM_GC, + [op.getarg(2), + ConstInt(index + dest_start), + val.force_box()], None, + descr=source_value.arraydescr) + self.emit_operation(newop) return True if length and length.getint() == 0: return True # 0-length arraycopy @@ -432,6 +440,9 @@ v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) + if v2.is_constant() and v2.box.getint() == 1: + self.make_equal_to(op.result, v1) + return if v1.intbound.known_ge(IntBound(0, 0)) and v2.is_constant(): val = v2.box.getint() if val & (val - 1) == 0 and val > 0: # val == 2**shift diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -330,18 +330,28 @@ vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox)) def optimize_VIRTUAL_REF_FINISH(self, op): - # Set the 'forced' field of the virtual_ref. - # In good cases, this is all virtual, so has no effect. - # Otherwise, this forces the real object -- but only now, as - # opposed to much earlier. This is important because the object is - # typically a PyPy PyFrame, and now is the end of its execution, so - # forcing it now does not have catastrophic effects. + # This operation is used in two cases. In normal cases, it + # is the end of the frame, and op.getarg(1) is NULL. In this + # case we just clear the vref.virtual_token, because it contains + # a stack frame address and we are about to leave the frame. + # In that case vref.forced should still be NULL, and remains + # NULL; and accessing the frame through the vref later is + # *forbidden* and will raise InvalidVirtualRef. + # + # In the other (uncommon) case, the operation is produced + # earlier, because the vref was forced during tracing already. + # In this case, op.getarg(1) is the virtual to force, and we + # have to store it in vref.forced. + # vrefinfo = self.optimizer.metainterp_sd.virtualref_info - # op.getarg(1) should really never point to null here + seo = self.optimizer.send_extra_operation + # - set 'forced' to point to the real object - seo = self.optimizer.send_extra_operation - seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None, - descr = vrefinfo.descr_forced)) + objbox = op.getarg(1) + if not self.optimizer.cpu.ts.CONST_NULL.same_constant(objbox): + seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None, + descr = vrefinfo.descr_forced)) + # - set 'virtual_token' to TOKEN_NONE args = [op.getarg(0), ConstInt(vrefinfo.TOKEN_NONE)] seo(ResOperation(rop.SETFIELD_GC, args, None, diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -4,7 +4,7 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib.debug import make_sure_not_resized -from pypy.rlib import nonconst +from pypy.rlib import nonconst, rstack from pypy.jit.metainterp import history, compile, resume from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat @@ -867,7 +867,6 @@ any_operation = len(self.metainterp.history.operations) > 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - # xxx we may disable the following line in some context later self.debug_merge_point(jitdriver_sd, self.metainterp.in_recursion, greenboxes) @@ -1049,8 +1048,10 @@ vrefinfo = metainterp.staticdata.virtualref_info vref = vrefbox.getref_base() if vrefinfo.is_virtual_ref(vref): + # XXX write a comment about nullbox + nullbox = self.metainterp.cpu.ts.CONST_NULL metainterp.history.record(rop.VIRTUAL_REF_FINISH, - [vrefbox, lastbox], None) + [vrefbox, nullbox], None) @arguments() def opimpl_ll_read_timestamp(self): @@ -1844,9 +1845,9 @@ else: self.compile(original_boxes, live_arg_boxes, start, resumedescr) # creation of the loop was cancelled! - #self.staticdata.log('cancelled, tracing more...') - self.staticdata.log('cancelled, stopping tracing') - raise SwitchToBlackhole(ABORT_BAD_LOOP) + self.staticdata.log('cancelled, tracing more...') + #self.staticdata.log('cancelled, stopping tracing') + #raise SwitchToBlackhole(ABORT_BAD_LOOP) # Otherwise, no loop found so far, so continue tracing. start = len(self.history.operations) @@ -1911,6 +1912,7 @@ def compile(self, original_boxes, live_arg_boxes, start, start_resumedescr): num_green_args = self.jitdriver_sd.num_green_args + original_inputargs = self.history.inputargs self.history.inputargs = original_boxes[num_green_args:] greenkey = original_boxes[:num_green_args] old_loop_tokens = self.get_compiled_merge_points(greenkey) @@ -1919,7 +1921,11 @@ greenkey, start, start_resumedescr) if loop_token is not None: # raise if it *worked* correctly self.set_compiled_merge_points(greenkey, old_loop_tokens) + self.history.inputargs = None + self.history.operations = None raise GenerateMergePoint(live_arg_boxes, loop_token) + + self.history.inputargs = original_inputargs self.history.operations.pop() # remove the JUMP # FIXME: Why is self.history.inputargs not restored? @@ -1936,10 +1942,12 @@ target_loop_token = compile.compile_new_bridge(self, old_loop_tokens, self.resumekey) - if target_loop_token is not None: # raise if it *worked* correctly - raise GenerateMergePoint(live_arg_boxes, target_loop_token) finally: self.history.operations.pop() # remove the JUMP + if target_loop_token is not None: # raise if it *worked* correctly + self.history.inputargs = None + self.history.operations = None + raise GenerateMergePoint(live_arg_boxes, target_loop_token) def compile_bridge_and_loop(self, original_boxes, live_arg_boxes, start, bridge_arg_boxes, start_resumedescr): @@ -1974,7 +1982,8 @@ assert False assert target_loop_token is not None - self.history.operations = original_operations + self.history.inputargs = None + self.history.operations = None raise GenerateMergePoint(live_arg_boxes, old_loop_tokens[0]) def compile_done_with_this_frame(self, exitbox): @@ -2044,10 +2053,16 @@ def initialize_state_from_guard_failure(self, resumedescr): # guard failure: rebuild a complete MIFrame stack - self.in_recursion = -1 # always one portal around - self.history = history.History() - inputargs_and_holes = self.rebuild_state_after_failure(resumedescr) - self.history.inputargs = [box for box in inputargs_and_holes if box] + # This is stack-critical code: it must not be interrupted by StackOverflow, + # otherwise the jit_virtual_refs are left in a dangling state. + rstack._stack_criticalcode_start() + try: + self.in_recursion = -1 # always one portal around + self.history = history.History() + inputargs_and_holes = self.rebuild_state_after_failure(resumedescr) + self.history.inputargs = [box for box in inputargs_and_holes if box] + finally: + rstack._stack_criticalcode_stop() def initialize_virtualizable(self, original_boxes): vinfo = self.jitdriver_sd.virtualizable_info diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr -from pypy.rlib import rarithmetic +from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert from pypy.rlib.debug import debug_start, debug_stop, debug_print @@ -978,12 +978,18 @@ def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage, all_virtuals=None): - resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd, - storage, all_virtuals) - vinfo = jitdriver_sd.virtualizable_info - ginfo = jitdriver_sd.greenfield_info - vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info - resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo) + # The initialization is stack-critical code: it must not be interrupted by + # StackOverflow, otherwise the jit_virtual_refs are left in a dangling state. + rstack._stack_criticalcode_start() + try: + resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd, + storage, all_virtuals) + vinfo = jitdriver_sd.virtualizable_info + ginfo = jitdriver_sd.greenfield_info + vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info + resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo) + finally: + rstack._stack_criticalcode_stop() # # First get a chain of blackhole interpreters whose length is given # by the depth of rd_frame_info_list. The first one we get must be diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -26,6 +26,10 @@ def attach_unoptimized_bridge_from_interp(self, greenkey, newloop): pass + def helper_func(self, FUNCPTR, func): + from pypy.rpython.annlowlevel import llhelper + return llhelper(FUNCPTR, func) + def jit_cell_at_key(self, greenkey): assert greenkey == [] return self._cell @@ -37,6 +41,7 @@ func._jit_unroll_safe_ = True rtyper = support.annotate(func, values, type_system=type_system) graphs = rtyper.annotator.translator.graphs + testself.all_graphs = graphs result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0] class FakeJitDriverSD: @@ -46,6 +51,8 @@ greenfield_info = None result_type = result_kind portal_runner_ptr = "???" + on_compile = lambda *args: None + on_compile_bridge = lambda *args: None stats = history.Stats() cpu = CPUClass(rtyper, stats, None, False) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1864,7 +1864,7 @@ return a1.val + b1.val res = self.meta_interp(g, [3, 23]) assert res == 7068153 - self.check_loop_count(6) + self.check_loop_count(7) self.check_loops(guard_true=4, guard_class=0, int_add=2, int_mul=2, guard_false=2) @@ -2101,6 +2101,79 @@ assert self.meta_interp(f, [5, 100]) == 0 self.check_loops(int_rshift=1, everywhere=True) + def test_inputarg_reset_bug(self): + ## j = 0 + ## while j < 100: + ## j += 1 + + ## c = 0 + ## j = 0 + ## while j < 2: + ## j += 1 + ## if c == 0: + ## c = 1 + ## else: + ## c = 0 + + ## j = 0 + ## while j < 100: + ## j += 1 + + def get_printable_location(i): + return str(i) + + myjitdriver = JitDriver(greens = ['i'], reds = ['j', 'c', 'a'], + get_printable_location=get_printable_location) + bytecode = "0j10jc20a3" + def f(): + myjitdriver.set_param('threshold', 7) + myjitdriver.set_param('trace_eagerness', 1) + i = j = c = a = 1 + while True: + myjitdriver.jit_merge_point(i=i, j=j, c=c, a=a) + if i >= len(bytecode): + break + op = bytecode[i] + if op == 'j': + j += 1 + elif op == 'c': + c = hint(c, promote=True) + c = 1 - c + elif op == '2': + if j < 3: + i -= 3 + myjitdriver.can_enter_jit(i=i, j=j, c=c, a=a) + elif op == '1': + k = j*a + if j < 100: + i -= 2 + a += k + myjitdriver.can_enter_jit(i=i, j=j, c=c, a=a) + else: + a += k*2 + elif op == '0': + j = c = a = 0 + elif op == 'a': + j += 1 + a += 1 + elif op == '3': + if a < 100: + i -= 2 + myjitdriver.can_enter_jit(i=i, j=j, c=c, a=a) + + else: + return ord(op) + i += 1 + return 42 + assert f() == 42 + def g(): + res = 1 + for i in range(10): + res = f() + return res + res = self.meta_interp(g, []) + assert res == 42 + def test_read_timestamp(self): import time from pypy.rlib.rtimer import read_timestamp diff --git a/pypy/jit/metainterp/test/test_history.py b/pypy/jit/metainterp/test/test_history.py --- a/pypy/jit/metainterp/test/test_history.py +++ b/pypy/jit/metainterp/test/test_history.py @@ -9,3 +9,20 @@ s = lltype.cast_pointer(lltype.Ptr(S), t) const = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)) assert const._getrepr_() == "*T" + +def test_same_constant(): + c1a = ConstInt(0) + c1b = ConstInt(0) + c2a = ConstPtr(lltype.nullptr(llmemory.GCREF.TO)) + c2b = ConstPtr(lltype.nullptr(llmemory.GCREF.TO)) + c3a = Const._new(0.0) + c3b = Const._new(0.0) + assert c1a.same_constant(c1b) + assert not c1a.same_constant(c2b) + assert not c1a.same_constant(c3b) + assert not c2a.same_constant(c1b) + assert c2a.same_constant(c2b) + assert not c2a.same_constant(c3b) + assert not c3a.same_constant(c1b) + assert not c3a.same_constant(c2b) + assert c3a.same_constant(c3b) diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py --- a/pypy/jit/metainterp/test/test_jitdriver.py +++ b/pypy/jit/metainterp/test/test_jitdriver.py @@ -10,8 +10,59 @@ def getloc2(g): return "in jitdriver2, with g=%d" % g +class JitDriverTests(object): + def test_on_compile(self): + called = {} + + class MyJitDriver(JitDriver): + def on_compile(self, logger, looptoken, operations, type, n, m): + called[(m, n, type)] = looptoken -class MultipleJitDriversTests: + driver = MyJitDriver(greens = ['n', 'm'], reds = ['i']) + + def loop(n, m): + i = 0 + while i < n + m: + driver.can_enter_jit(n=n, m=m, i=i) + driver.jit_merge_point(n=n, m=m, i=i) + i += 1 + + self.meta_interp(loop, [1, 4]) + assert sorted(called.keys()) == [(4, 1, "entry bridge"), (4, 1, "loop")] + self.meta_interp(loop, [2, 4]) + assert sorted(called.keys()) == [(4, 1, "entry bridge"), (4, 1, "loop"), + (4, 2, "entry bridge"), (4, 2, "loop")] + + def test_on_compile_bridge(self): + called = {} + + class MyJitDriver(JitDriver): + def on_compile(self, logger, looptoken, operations, type, n, m): + called[(m, n, type)] = loop + def on_compile_bridge(self, logger, orig_token, operations, n): + assert 'bridge' not in called + called['bridge'] = orig_token + + driver = MyJitDriver(greens = ['n', 'm'], reds = ['i']) + + def loop(n, m): + i = 0 + while i < n + m: + driver.can_enter_jit(n=n, m=m, i=i) + driver.jit_merge_point(n=n, m=m, i=i) + if i >= 4: + i += 2 + i += 1 + + self.meta_interp(loop, [1, 10]) + assert sorted(called.keys()) == ['bridge', (10, 1, "entry bridge"), + (10, 1, "loop")] + + +class TestLLtypeSingle(JitDriverTests, LLJitMixin): + pass + +class MultipleJitDriversTests(object): def test_simple(self): myjitdriver1 = JitDriver(greens=[], reds=['n', 'm'], diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -236,4 +236,8 @@ return a * b res = self.meta_interp(f, [37]) assert res == f(37) - self.check_loops(getfield_gc=1, everywhere=True) + # There is the one actual field on a, plus 2 getfield's from the list + # itself, 1 to get the length (which is then incremented and passed to + # the resize func), and then a read of the items field to actually + # perform the setarrayitem on + self.check_loops(getfield_gc=5, everywhere=True) diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py --- a/pypy/jit/metainterp/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/test/test_optimizeopt.py @@ -3402,6 +3402,56 @@ ''' self.optimize_loop(ops, expected) + def test_arraycopy_dest_not_virtual(self): + ops = ''' + [] + p1 = new_array(3, descr=arraydescr) + p2 = new_array(3, descr=arraydescr) + setarrayitem_gc(p1, 2, 10, descr=arraydescr) + setarrayitem_gc(p2, 2, 13, descr=arraydescr) + escape(p2) + call(0, p1, p2, 0, 0, 3, descr=arraycopydescr) + escape(p2) + jump() + ''' + expected = ''' + [] + p2 = new_array(3, descr=arraydescr) + setarrayitem_gc(p2, 2, 13, descr=arraydescr) + escape(p2) + setarrayitem_gc(p2, 0, 0, descr=arraydescr) + setarrayitem_gc(p2, 1, 0, descr=arraydescr) + setarrayitem_gc(p2, 2, 10, descr=arraydescr) + escape(p2) + jump() + ''' + self.optimize_loop(ops, expected) + + def test_arraycopy_dest_not_virtual_too_long(self): + ops = ''' + [] + p1 = new_array(10, descr=arraydescr) + p2 = new_array(10, descr=arraydescr) + setarrayitem_gc(p1, 2, 10, descr=arraydescr) + setarrayitem_gc(p2, 2, 13, descr=arraydescr) + escape(p2) + call(0, p1, p2, 0, 0, 10, descr=arraycopydescr) + escape(p2) + jump() + ''' + expected = ''' + [] + p2 = new_array(10, descr=arraydescr) + setarrayitem_gc(p2, 2, 13, descr=arraydescr) + escape(p2) + p1 = new_array(10, descr=arraydescr) + setarrayitem_gc(p1, 2, 10, descr=arraydescr) + call(0, p1, p2, 0, 0, 10, descr=arraycopydescr) + escape(p2) + jump() + ''' + self.optimize_loop(ops, expected) + def test_bound_lt(self): ops = """ [i0] @@ -3900,6 +3950,50 @@ """ self.optimize_loop(ops, expected) + def test_add_sub_ovf(self): + ops = """ + [i1] + i2 = int_add_ovf(i1, 1) + guard_no_overflow() [] + i3 = int_sub_ovf(i2, 1) + guard_no_overflow() [] + escape(i3) + jump(i2) + """ + expected = """ + [i1] + i2 = int_add_ovf(i1, 1) + guard_no_overflow() [] + escape(i1) + jump(i2) + """ + self.optimize_loop(ops, expected) + + def test_add_sub_ovf_virtual_unroll(self): + ops = """ + [p15] + i886 = getfield_gc_pure(p15, descr=valuedescr) + i888 = int_sub_ovf(i886, 1) + guard_no_overflow() [] + escape(i888) + i4360 = getfield_gc_pure(p15, descr=valuedescr) + i4362 = int_add_ovf(i4360, 1) + guard_no_overflow() [] + i4360p = int_sub_ovf(i4362, 1) + guard_no_overflow() [] + p4364 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p4364, i4362, descr=valuedescr) + jump(p4364) + """ + expected = """ + [i0, i1] + escape(i1) + i2 = int_add_ovf(i0, 1) + guard_no_overflow() [] + jump(i2, i0) + """ + self.optimize_loop(ops, expected) + def test_framestackdepth_overhead(self): ops = """ [p0, i22] @@ -4376,7 +4470,6 @@ i8 = int_floordiv(4, i2) i9 = int_rshift(i1, 2) i10 = int_floordiv(i1, 0) - i11 = int_rshift(i1, 0) i12 = int_floordiv(i2, 2) i13 = int_floordiv(i2, 3) i14 = int_floordiv(i2, 4) @@ -4453,6 +4546,18 @@ """ self.optimize_loop(ops, expected) + def test_int_div_1(self): + ops = """ + [i0] + i1 = int_floordiv(i0, 1) + jump(i1) + """ + expected = """ + [i0] + jump(i0) + """ + self.optimize_loop(ops, expected) + def test_subsub_ovf(self): ops = """ [i0] diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/test/test_optimizeutil.py --- a/pypy/jit/metainterp/test/test_optimizeutil.py +++ b/pypy/jit/metainterp/test/test_optimizeutil.py @@ -133,7 +133,8 @@ EffectInfo([adescr], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([nextdescr], [], [], - EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE)) + EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, + can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) diff --git a/pypy/jit/metainterp/test/test_resoperation.py b/pypy/jit/metainterp/test/test_resoperation.py --- a/pypy/jit/metainterp/test/test_resoperation.py +++ b/pypy/jit/metainterp/test/test_resoperation.py @@ -72,7 +72,7 @@ def test_get_deep_immutable_oplist(): ops = [rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c')] newops = rop.get_deep_immutable_oplist(ops) - py.test.raises(AttributeError, "newops.append('foobar')") + py.test.raises(TypeError, "newops.append('foobar')") py.test.raises(TypeError, "newops[0] = 'foobar'") py.test.raises(AssertionError, "newops[0].setarg(0, 'd')") py.test.raises(AssertionError, "newops[0].setdescr('foobar')") diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -204,7 +204,6 @@ # InvalidLoop condition, and was then unrolled, giving two copies # of the body in a single bigger loop with no failing guard except # the final one. - py.test.skip('dissabled "try to trace some more when compile fails"') self.check_loop_count(1) self.check_loops(guard_class=0, int_add=2, int_sub=2) @@ -231,6 +230,7 @@ return self.y w1 = W1(10) w2 = W2(20) + def f(x, y): if x & 1: w = w1 @@ -246,7 +246,6 @@ assert res == f(3, 28) res = self.meta_interp(f, [4, 28]) assert res == f(4, 28) - py.test.skip('dissabled "try to trace some more when compile fails"') self.check_loop_count(1) self.check_loops(guard_class=0, int_add=2, int_sub=2) diff --git a/pypy/jit/metainterp/test/test_tl.py b/pypy/jit/metainterp/test/test_tl.py --- a/pypy/jit/metainterp/test/test_tl.py +++ b/pypy/jit/metainterp/test/test_tl.py @@ -58,7 +58,7 @@ exit: RETURN ''') - + codes = [code, code2] def main(n, inputarg): code = codes[n] @@ -116,7 +116,7 @@ codes = [code, ''] def main(num, arg): return interp(codes[num], inputarg=arg) - + res = self.meta_interp(main, [0, 20], enable_opts='', listops=listops, backendopt=True, policy=policy) assert res == 0 @@ -128,7 +128,6 @@ from pypy.jit.tl.tl import Stack methods = [Stack.put, Stack.pick, - Stack.roll, Stack.append, Stack.pop] for meth in methods: diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py --- a/pypy/jit/metainterp/test/test_virtualref.py +++ b/pypy/jit/metainterp/test/test_virtualref.py @@ -1,9 +1,10 @@ import py from pypy.rpython.lltypesystem import lltype, llmemory, lloperation +from pypy.rpython.llinterp import LLException from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None -from pypy.rlib.jit import virtual_ref, virtual_ref_finish +from pypy.rlib.jit import virtual_ref, virtual_ref_finish, InvalidVirtualRef from pypy.rlib.objectmodel import compute_unique_id -from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, _get_jitcodes from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.virtualref import VirtualRefInfo @@ -16,6 +17,29 @@ self.vrefinfo = VirtualRefInfo(self.warmrunnerstate) self.cw.setup_vrefinfo(self.vrefinfo) + def test_rewrite_graphs(self): + class X: + pass + def fn(): + x = X() + vref = virtual_ref(x) + x1 = vref() # jit_force_virtual + virtual_ref_finish(vref, x) + # + _get_jitcodes(self, self.CPUClass, fn, [], self.type_system) + graph = self.all_graphs[0] + assert graph.name == 'fn' + self.vrefinfo.replace_force_virtual_with_call([graph]) + # + def check_call(op, fname): + assert op.opname == 'direct_call' + assert op.args[0].value._obj._name == fname + # + ops = [op for block, op in graph.iterblockops()] + check_call(ops[-3], 'virtual_ref') + check_call(ops[-2], 'force_virtual_if_necessary') + check_call(ops[-1], 'virtual_ref_finish') + def test_make_vref_simple(self): class X: pass @@ -25,9 +49,9 @@ # def f(): x = X() - exctx.topframeref = virtual_ref(x) + exctx.topframeref = vref = virtual_ref(x) exctx.topframeref = vref_None - virtual_ref_finish(x) + virtual_ref_finish(vref, x) return 1 # self.interp_operations(f, []) @@ -60,8 +84,9 @@ exctx._frame = x exctx.topframeref = virtual_ref(x) def leave(): + vref = exctx.topframeref exctx.topframeref = vref_None - virtual_ref_finish(exctx._frame) + virtual_ref_finish(vref, exctx._frame) def f(n): enter(n) n = external(n) @@ -125,7 +150,8 @@ # @dont_look_inside def g(vref): - debug_print(lltype.Void, '-+-+-+-+- external read:', vref().n) + # we cannot do anything with the vref after the call to finish() + pass # def f(n): while n > 0: @@ -136,7 +162,7 @@ exctx.topframeref = vref = virtual_ref(x) # here, 'x' should be virtual exctx.topframeref = vref_None - virtual_ref_finish(x) + virtual_ref_finish(vref, x) # 'x' and 'vref' can randomly escape after the call to # finish(). g(vref) @@ -144,7 +170,7 @@ return 1 # self.meta_interp(f, [10]) - self.check_loops(new_with_vtable=2) # the vref and the X + self.check_loops(new_with_vtable=1) # the vref self.check_aborted_count(0) def test_simple_all_removed(self): @@ -169,13 +195,13 @@ xy.next1 = lltype.malloc(A, 0) xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) n -= externalfn(n) exctx.topframeref = vref_None xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) # self.meta_interp(f, [15]) self.check_loops(new_with_vtable=0, # all virtualized @@ -206,17 +232,17 @@ xy.next1 = lltype.malloc(A, 0) xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) n -= externalfn(n) exctx.topframeref = vref_None xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) # self.meta_interp(f, [15]) - self.check_loops(new_with_vtable=2, # the vref, and xy so far, - new_array=0) # but not xy.next1/2/3 + self.check_loops(new_with_vtable=1, # the vref: xy doesn't need to be forced + new_array=0) # and neither xy.next1/2/3 self.check_aborted_count(0) def test_simple_force_always(self): @@ -244,12 +270,12 @@ xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) n -= externalfn(n) xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) exctx.topframeref = vref_None # self.meta_interp(f, [15]) @@ -282,19 +308,19 @@ xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) n -= externalfn(n) xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) exctx.topframeref = vref_None return exctx.m # res = self.meta_interp(f, [30]) assert res == 13 - self.check_loops(new_with_vtable=2, # the vref, XY() at the end - new_array=0) # but not next1/2/3 + self.check_loops(new_with_vtable=1, # the vref, but not XY() + new_array=0) # and neither next1/2/3 self.check_loop_count(1) self.check_aborted_count(0) @@ -322,7 +348,7 @@ xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) if n == 13: externalfn(n) n -= 1 @@ -330,7 +356,7 @@ xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return exctx.m # res = self.meta_interp(f, [30]) @@ -366,7 +392,7 @@ xy.next4 = lltype.malloc(A, 0) xy.next5 = lltype.malloc(A, 0) xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) if n % 6 == 0: xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) @@ -379,7 +405,7 @@ xy.next3 = lltype.nullptr(A) xy.next4 = lltype.nullptr(A) xy.next5 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return exctx.m # res = self.meta_interp(f, [72]) @@ -389,36 +415,6 @@ new_array=2) # bridge: next4, next5 self.check_aborted_count(0) - def test_access_vref_later(self): - myjitdriver = JitDriver(greens = [], reds = ['n']) - # - class XY: - pass - class ExCtx: - pass - exctx = ExCtx() - # - @dont_look_inside - def g(): - return exctx.later().n - # - def f(n): - while n > 0: - myjitdriver.can_enter_jit(n=n) - myjitdriver.jit_merge_point(n=n) - xy = XY() - xy.n = n - exctx.topframeref = virtual_ref(xy) - exctx.later = exctx.topframeref - n -= 1 - exctx.topframeref = vref_None - virtual_ref_finish(xy) - return g() - # - res = self.meta_interp(f, [15]) - assert res == 1 - self.check_aborted_count(0) - def test_jit_force_virtual_seen(self): myjitdriver = JitDriver(greens = [], reds = ['n']) # @@ -435,12 +431,12 @@ myjitdriver.jit_merge_point(n=n) xy = XY() xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) xy.next1 = lltype.malloc(A, 0) n = exctx.topframeref().n - 1 xy.next1 = lltype.nullptr(A) exctx.topframeref = vref_None - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return 1 # res = self.meta_interp(f, [15]) @@ -465,12 +461,12 @@ if reclevel == 0: return n xy = XY() - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) m = f(xy, n, reclevel-1) assert m == n n -= 1 exctx.topframeref = vref_None - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return 2 def main(n, reclevel): return f(XY(), n, reclevel) @@ -495,7 +491,7 @@ frame.n += 1 xy = XY() xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) if reclevel > 0: m = f(xy, frame.n, reclevel-1) assert xy.n == m @@ -503,7 +499,7 @@ else: n -= 2 exctx.topframeref = vref_None - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return frame.n def main(n, reclevel): return f(XY(), n, reclevel) @@ -512,6 +508,93 @@ assert res == main(10, 2) self.check_aborted_count(0) + def test_alloc_virtualref_and_then_alloc_structure(self): + myjitdriver = JitDriver(greens = [], reds = ['n']) + # + class XY: + pass + class ExCtx: + pass + exctx = ExCtx() + @dont_look_inside + def escapexy(xy): + print 'escapexy:', xy.n + if xy.n % 5 == 0: + vr = exctx.vr + print 'accessing via vr:', vr() + assert vr() is xy + # + def f(n): + while n > 0: + myjitdriver.jit_merge_point(n=n) + xy = XY() + xy.n = n + vr = virtual_ref(xy) + # force the virtualref to be allocated + exctx.vr = vr + # force xy to be allocated + escapexy(xy) + # clean up + exctx.vr = vref_None + virtual_ref_finish(vr, xy) + n -= 1 + return 1 + # + res = self.meta_interp(f, [15]) + assert res == 1 + self.check_loops(new_with_vtable=2) # vref, xy + + def test_cannot_use_invalid_virtualref(self): + myjitdriver = JitDriver(greens = [], reds = ['n']) + # + class XY: + n = 0 + # + def fn(n): + res = False + while n > 0: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + xy = XY() + xy.n = n + vref = virtual_ref(xy) + virtual_ref_finish(vref, xy) + vref() # raises InvalidVirtualRef when jitted + n -= 1 + return res + # + py.test.raises(InvalidVirtualRef, "fn(10)") + py.test.raises(LLException, "self.meta_interp(fn, [10])") + + def test_call_virtualref_already_forced(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'res']) + # + class XY: + n = 0 + # + @dont_look_inside + def force_it(vref, n): + if n % 6 == 0: + return vref().n + return 0 + def fn(n): + res = 0 + while n > 0: + myjitdriver.can_enter_jit(n=n, res=res) + myjitdriver.jit_merge_point(n=n, res=res) + xy = XY() + xy.n = n + vref = virtual_ref(xy) + force_it(vref, n) + virtual_ref_finish(vref, xy) + res += force_it(vref, n) # doesn't raise, because it was already forced + n -= 1 + return res + # + assert fn(10) == 6 + res = self.meta_interp(fn, [10]) + assert res == 6 + class TestLLtype(VRefTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_ztranslation.py b/pypy/jit/metainterp/test/test_ztranslation.py --- a/pypy/jit/metainterp/test/test_ztranslation.py +++ b/pypy/jit/metainterp/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.jit.metainterp.warmspot import rpython_ll_meta_interp, ll_meta_interp from pypy.jit.backend.llgraph import runner from pypy.rlib.jit import JitDriver, unroll_parameters -from pypy.rlib.jit import PARAMETERS, dont_look_inside +from pypy.rlib.jit import PARAMETERS, dont_look_inside, hint from pypy.jit.metainterp.jitprof import Profiler from pypy.rpython.lltypesystem import lltype, llmemory @@ -24,16 +24,21 @@ # - string concatenation, slicing and comparison class Frame(object): - _virtualizable2_ = ['i'] + _virtualizable2_ = ['l[*]'] def __init__(self, i): - self.i = i + self = hint(self, fresh_virtualizable=True, + access_directly=True) + self.l = [i] class OtherFrame(object): - _virtualizable2_ = ['i'] + _virtualizable2_ = ['i', 'l[*]'] def __init__(self, i): + self = hint(self, fresh_virtualizable=True, + access_directly=True) self.i = i + self.l = [float(i)] class JitCellCache: entry = None @@ -57,39 +62,45 @@ jitdriver.set_param("trace_eagerness", 2) total = 0 frame = Frame(i) - while frame.i > 3: + while frame.l[0] > 3: jitdriver.can_enter_jit(frame=frame, total=total) jitdriver.jit_merge_point(frame=frame, total=total) - total += frame.i - if frame.i >= 20: - frame.i -= 2 - frame.i -= 1 + total += frame.l[0] + if frame.l[0] >= 20: + frame.l[0] -= 2 + frame.l[0] -= 1 return total * 10 # - myjitdriver2 = JitDriver(greens = ['g'], reds = ['m', 's', 'f'], + myjitdriver2 = JitDriver(greens = ['g'], + reds = ['m', 's', 'f', 'float_s'], virtualizables = ['f']) def f2(g, m, x): s = "" f = OtherFrame(x) + float_s = 0.0 while m > 0: - myjitdriver2.can_enter_jit(g=g, m=m, f=f, s=s) - myjitdriver2.jit_merge_point(g=g, m=m, f=f, s=s) + myjitdriver2.can_enter_jit(g=g, m=m, f=f, s=s, float_s=float_s) + myjitdriver2.jit_merge_point(g=g, m=m, f=f, s=s, + float_s=float_s) s += 'xy' if s[:2] == 'yz': return -666 m -= 1 f.i += 3 + float_s += f.l[0] return f.i # def main(i, j): return f(i) - f2(i+j, i, j) res = ll_meta_interp(main, [40, 5], CPUClass=self.CPUClass, - type_system=self.type_system) + type_system=self.type_system, + listops=True) assert res == main(40, 5) res = rpython_ll_meta_interp(main, [40, 5], CPUClass=self.CPUClass, type_system=self.type_system, - ProfilerClass=Profiler) + ProfilerClass=Profiler, + listops=True) assert res == main(40, 5) def test_external_exception_handling_translates(self): diff --git a/pypy/jit/metainterp/typesystem.py b/pypy/jit/metainterp/typesystem.py --- a/pypy/jit/metainterp/typesystem.py +++ b/pypy/jit/metainterp/typesystem.py @@ -5,7 +5,7 @@ from pypy.rpython.annlowlevel import cast_instance_to_base_obj from pypy.jit.metainterp import history from pypy.jit.codewriter import heaptracker -from pypy.rlib.objectmodel import r_dict +from pypy.rlib.objectmodel import r_dict, specialize def deref(T): if isinstance(T, lltype.Ptr): @@ -97,12 +97,15 @@ def cast_to_baseclass(self, value): return lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), value) + @specialize.ll() def getlength(self, array): return len(array) + @specialize.ll() def getarrayitem(self, array, i): return array[i] + @specialize.ll() def setarrayitem(self, array, i, newvalue): array[i] = newvalue @@ -201,12 +204,15 @@ def cast_to_baseclass(self, value): return ootype.cast_from_object(ootype.ROOT, value) + @specialize.ll() def getlength(self, array): return array.ll_length() + @specialize.ll() def getarrayitem(self, array, i): return array.ll_getitem_fast(i) + @specialize.ll() def setarrayitem(self, array, i, newvalue): array.ll_setitem_fast(i, newvalue) diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py --- a/pypy/jit/metainterp/virtualref.py +++ b/pypy/jit/metainterp/virtualref.py @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass from pypy.jit.metainterp import history from pypy.jit.codewriter import heaptracker - +from pypy.rlib.jit import InvalidVirtualRef class VirtualRefInfo: @@ -38,23 +38,24 @@ def replace_force_virtual_with_call(self, graphs): # similar to rvirtualizable2.replace_force_virtualizable_with_call(). - c_funcptr = None - count = 0 + c_force_virtual_ptr = None + force_virtual_count = 0 for graph in graphs: for block in graph.iterblocks(): for op in block.operations: if op.opname == 'jit_force_virtual': # first compute c_funcptr, but only if there is any # 'jit_force_virtual' around - if c_funcptr is None: - c_funcptr = self.get_force_virtual_fnptr() + if c_force_virtual_ptr is None: + c_force_virtual_ptr = self.get_force_virtual_fnptr() # op.opname = 'direct_call' - op.args = [c_funcptr, op.args[0]] - count += 1 - if c_funcptr is not None: - log("replaced %d 'jit_force_virtual' with %r" % (count, - c_funcptr.value)) + op.args = [c_force_virtual_ptr, op.args[0]] + force_virtual_count += 1 + # + if c_force_virtual_ptr is not None: + log("replaced %d 'jit_force_virtual' with %r" % (force_virtual_count, + c_force_virtual_ptr.value)) # ____________________________________________________________ @@ -145,7 +146,8 @@ ResumeGuardForcedDescr.force_now(self.cpu, token) assert vref.virtual_token == self.TOKEN_NONE assert vref.forced - else: - assert vref.forced + elif not vref.forced: + # token == TOKEN_NONE and the vref was not forced: it's invalid + raise InvalidVirtualRef return vref.forced force_virtual._dont_inline_ = True diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -566,6 +566,19 @@ return can_inline_greenargs(*greenargs) self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + if hasattr(jd.jitdriver, 'on_compile'): + def on_compile(logger, token, operations, type, greenkey): + greenargs = unwrap_greenkey(greenkey) + return jd.jitdriver.on_compile(logger, token, operations, type, + *greenargs) + def on_compile_bridge(logger, orig_token, operations, n): + return jd.jitdriver.on_compile_bridge(logger, orig_token, + operations, n) + jd.on_compile = on_compile + jd.on_compile_bridge = on_compile_bridge + else: + jd.on_compile = lambda *args: None + jd.on_compile_bridge = lambda *args: None def get_assembler_token(greenkey, redboxes): # 'redboxes' is only used to know the types of red arguments diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py --- a/pypy/jit/tl/pypyjit.py +++ b/pypy/jit/tl/pypyjit.py @@ -42,6 +42,7 @@ config.objspace.usemodules._lsprof = True # config.objspace.usemodules._ffi = True +config.objspace.usemodules.micronumpy = True # set_pypy_opt_level(config, level='jit') diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -1,11 +1,10 @@ try: - def f(x): - i = 0 - while i < x: - range(i) - i += 1 - f(10000) + import numpy + a = numpy.array(range(10)) + b = a + a + a + print b[3] + except Exception, e: print "Exception: ", type(e) print e diff --git a/pypy/jit/tl/tinyframe/test/test_tinyframe.py b/pypy/jit/tl/tinyframe/test/test_tinyframe.py --- a/pypy/jit/tl/tinyframe/test/test_tinyframe.py +++ b/pypy/jit/tl/tinyframe/test/test_tinyframe.py @@ -96,11 +96,12 @@ RETURN r1 ''') s = StringIO() + prev = sys.stdout sys.stdout = s try: interpret(code) finally: - sys.stdout = sys.__stdout__ + sys.stdout = prev lines = s.getvalue().splitlines() assert lines == [ '0', diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -40,6 +40,7 @@ assert n >= 0 self.stack[n] = elem + @dont_look_inside def roll(self, r): if r < -1: i = self.stackpos + r diff --git a/pypy/jit/tool/cpython.vmrss b/pypy/jit/tool/cpython.vmrss deleted file mode 100644 --- a/pypy/jit/tool/cpython.vmrss +++ /dev/null @@ -1,4101 +0,0 @@ -124 -16600 -20620 -20640 -22036 -94084 -94084 -94108 -94108 -94108 -94108 -94108 -94120 -94164 -94160 -94160 -94160 -94160 -94160 -94216 -110644 -123144 -135236 -143680 -148500 -153104 -157088 -160640 -164760 -167992 -163108 -163232 -163232 -163436 -163436 -163436 -163444 -163444 -163444 -163448 -163448 -163448 -163448 -163448 -163448 -167060 -170948 -174432 -177212 -177216 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176508 -176520 -176520 -176520 -176520 -176520 -176520 -176520 -176520 -176520 -176540 -176544 -176544 -176544 -176544 -176544 -176544 -176544 -176544 -176544 -176544 -176544 -176544 -179120 -187120 -189380 -191052 -192156 -193320 -194900 -195860 -198516 -201484 -202600 -202600 -202600 -202600 -202832 -202832 -202836 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -202840 -207784 -212136 -216320 -220508 -224696 -228876 -245088 -245088 -247844 -252032 -256212 -260400 -264592 -268776 -272776 -275060 -279244 -283428 -287616 -291032 -293900 -298080 -302272 -304364 -308548 -310644 -312740 -316924 -319016 -323208 -325296 -327392 -331572 -333668 -335760 -337856 -354328 -356424 -358520 -362700 -364792 -366892 -368984 -371080 -373168 -375260 -377356 -379448 -381540 -383636 -383636 -385732 -387820 -390032 -391160 -392292 -394552 -396816 -397092 -399072 -401340 -403600 -405860 -408008 -408148 -412640 -414900 -417164 -419420 -421680 -423944 -426204 -428464 -430724 -432768 -434980 -436476 -437932 -440332 -441984 -442740 -445152 -447688 -449148 -449960 -452436 -454712 -454896 -457180 -458888 -459688 -462040 -463480 -464408 -466812 -467244 -469224 -471096 -471684 -474136 -474328 -476508 -478872 -481356 -483472 -483780 -486072 -488480 -489668 -490888 -493420 -495704 -496836 -498116 -500520 -502756 -503668 -505400 -507760 -509296 -510204 -512764 -514708 -515508 -517372 -519764 -520648 -522188 -524596 -525524 -527004 -529412 -534224 -536632 -538080 -539216 -541588 -542560 -543384 -543384 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -518804 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519024 -519028 -519028 -519028 -519028 -519028 -519028 -519028 -519028 -519028 -519028 -519028 -519028 -519032 -519032 -519032 -519032 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519036 -519048 -519048 -519048 -519048 -519048 -519048 -519048 -519048 -519048 -519048 -519048 -519048 -519048 -519048 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519052 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519056 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519060 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519064 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -519068 -520592 -520592 -520904 -522740 -522740 -523212 -525256 -525256 -525316 -526552 -526552 -526560 -528508 -528508 -528508 -530040 -530040 -530040 -532684 -532684 -532684 -534948 -534948 -534948 -538028 -538028 -538028 -541404 -541448 -541448 -543784 -543784 -543784 -545184 -545476 -545768 -545832 -545832 -545832 -546016 -546016 -546128 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546184 -546228 -546228 -546228 -546228 -546228 -546228 -546228 -546228 -546228 -546228 -546228 -546228 -546228 -546228 -546228 -546708 -546708 -546708 -547988 -550420 -550420 -550420 -552896 -555796 -555796 -555796 -559136 -560280 -560280 -560996 -562504 -563772 -564672 -564672 -565268 -567936 -568884 -569028 -569236 -569292 -569292 -570236 -572960 -573980 -573980 -574508 -577404 -579188 -579188 -579508 -582836 -584468 -584468 -585544 -591292 -591292 -591292 -595868 -597588 -597588 -598404 -602772 -603964 -603964 -605488 -609740 -610468 -610468 -611884 -616440 -617108 -617108 -618156 -622276 -623784 -623784 -624128 -624376 -625544 -626736 -627112 -627112 -627116 -627656 -628836 -628836 -628836 -629160 -630180 -630488 -630488 -630492 -631288 -632144 -632144 -632144 -632172 -632688 -633220 -633220 -633220 -633284 -633756 -633916 -633916 -633916 -634012 -634608 -634608 -634608 -634624 -634732 -635144 -635144 -635144 -635196 -635680 -635868 -635868 -635944 -638440 -639964 -639980 -639980 -640056 -641052 -642064 -642064 -642064 -642248 -643080 -643832 -643832 -643832 -644116 -646500 -647424 -648236 -649032 -649156 -649156 -649256 -651556 -652056 -652504 -652860 -653168 -653440 -653876 -654096 -654304 -654304 -654304 -654756 -655648 -657064 -657064 -657064 -657064 -657488 -657756 -657756 -657756 -658112 -658736 -658736 -658736 -658796 -659304 -659376 -659376 -659376 -659848 -661000 -661172 -661172 -661236 -662240 -663240 -663508 -663508 -663660 -664324 -665512 -665764 -665764 -665764 -666448 -667692 -668112 -668112 -668112 -668624 -669508 -670388 -670536 -670536 -670536 -670564 -671288 -672268 -672268 -672268 -672676 -674504 -675072 -675072 -675072 -675156 -675896 -676700 -676700 -676700 -676820 -677988 -678628 -678628 -678628 -678776 -679744 -680400 -680400 -680400 -705092 -705156 -705156 -705156 -705156 -705156 -705156 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705160 -705264 -705264 -705264 -705400 -705476 -706168 -706292 -706292 -706292 -706504 -706568 -706980 -707012 -707012 -707012 -707196 -707280 -707904 -707904 -707904 -707924 -708112 -708176 -708676 -708676 -708676 -708696 -708892 -708984 -709588 -709588 -709588 -709612 -709804 -709848 -710300 -710300 -710300 -710676 -710520 -710604 -711156 -711156 -711156 -711336 -711352 -711576 -712080 -712080 -712080 -712300 -712408 -712500 -712648 -712648 -712648 -712648 -713060 -713300 -713716 -713716 -713716 -714072 -714196 -714568 -714568 -714568 -714596 -714956 -715112 -715808 -715808 -715808 -717504 -717628 -717660 -717660 -717660 -718620 -719048 -719424 -719424 -719424 -719480 -719924 -720612 -720612 -720612 -720620 -722584 -722848 -722848 -722848 -723060 -724108 -724604 -724604 -724604 -725108 -726168 -726348 -726348 -726348 -727216 -728204 -728204 -728204 -728324 -729396 -730152 -730152 -730152 -730396 -736796 -736800 -736800 -736800 -736800 -736800 -736800 -736800 -736800 -737136 -738296 -738400 -738400 -738400 -739092 -740128 -740128 -740128 -740140 -741092 -741980 -741980 -741980 -742060 -743060 -743796 -743796 -743796 -743836 -744440 -745348 -745348 -745348 -745400 -746108 -746848 -746952 -746952 -746952 -747496 -748608 -748744 -749084 -749084 -749084 -749172 -750172 -751468 -751592 -751592 -751592 -751688 -751928 -752152 -752308 -759152 -760152 -760152 -760152 -756356 -754816 -756356 -756356 -756356 -756688 -756688 -756820 -757152 -757200 -757400 -757432 -757432 -757432 -757632 -757956 -758404 -758844 -759480 -760064 -760552 -760552 -760552 -760560 -761180 -761632 -762288 -762800 -763700 -764504 -764716 -764716 -764716 -764940 -765388 -765936 -767748 -767056 -767300 -767484 -767868 -768316 -768316 -768316 -768316 -768700 -768828 -768700 -769340 -769260 -771008 -771552 -771652 -771716 -772580 -772708 -772740 -772740 -772740 -772292 -772740 -772944 -773188 -773700 -774084 -774084 -774404 -774020 -774532 -774020 -774596 -774340 -774468 -774468 -774468 -774724 -774792 -774980 -775368 -775816 -775816 -776264 -777480 -778292 -778408 -778440 -778440 -778440 -778440 -778440 -778440 -778440 -778440 -778440 -778440 -778440 -778632 -778696 -778952 -779016 -779016 -779016 -779016 -780812 -780812 -780812 -781068 -781580 -781772 -781712 -781868 -782092 -782420 -782796 -782796 -782796 -782796 -782668 -783128 -783436 -783820 -784076 -784332 -784908 -785164 -785500 -786188 -786188 -786188 -786188 -786188 -786188 -786188 -786412 -786896 -787084 -787404 -787532 -787724 -787568 -788108 -788428 -788748 -788752 -789520 -789520 -789520 -788880 -789440 -789452 -789516 -790092 -790284 -790604 -790860 -791052 -791372 -791628 -792012 -792012 -792396 -792780 -792780 -792780 -792780 -792780 -793228 -793228 -793868 -793868 -793996 -793996 -794636 -794636 -794636 -795084 -795084 -795468 -795532 -795980 -795980 -796300 -796364 -796364 -796364 -796364 -796748 -797132 -797132 -797516 -797644 -797644 -798380 -798604 -798860 -798924 -799372 -799564 -799756 -799756 -799756 -799756 -799816 -800292 -800792 -801312 -801816 -802364 -802880 -803456 -803660 -803660 -803660 -803812 -804388 -804960 -805516 -806084 -806668 -807324 -807980 -807980 -807980 -807980 -808416 -809084 -809784 -810492 -811160 -812900 -813476 -813876 -813876 -813876 -813876 -814508 -815152 -815864 -816556 -817260 -817916 -818708 -819272 -819352 -819352 -819352 -819352 -819884 -820308 -820888 -821012 -821012 -821204 -821588 -821588 -821588 -821972 -822228 -822164 -822932 -823252 -823252 -823252 -823252 -823252 -823256 -823612 -823920 -823936 -824140 -824168 -824220 -824280 -824400 -824664 -825776 -825776 -825776 -825776 -832168 -832168 -832168 -832168 -832808 -833492 -833492 -833492 -833492 -833700 -834308 -834428 -834428 -834428 -834780 -836216 -836216 -836216 -836836 -839308 -839308 -839308 -839308 -839416 -840344 -840344 -840344 -840344 -841724 -841724 -841724 -841724 -843800 -843800 -843800 -843800 -845692 -846072 -846072 -846072 -846096 -846736 -847096 -847156 -847156 -847156 -847160 -847180 -847360 -847360 -847360 -847360 -847416 -849248 -849248 -849248 -849248 -849716 -849716 -849716 -849716 -849740 -851168 -851168 -851168 -851168 -854544 -854544 -854544 -854544 -854564 -855332 -855332 -855332 -855332 -857092 -857092 -857092 -857092 -858000 -859388 -859388 -859388 -859388 -861584 -861584 -861584 -861584 -861584 -863464 -863464 -863464 -863464 -864304 -866500 -866500 -866500 -866500 -868952 -868952 -868952 -868952 -869740 -872108 -872108 -872108 -872108 -873208 -875564 -875564 -875564 -875564 -878568 -878568 -878568 -878568 -878576 -880780 -880780 -880780 -880780 -884048 -884048 -884048 -884048 -884048 -884048 -886516 -886516 -886516 -886516 -886516 -886536 -888112 -888112 -888112 -888112 -888112 -888112 -888656 -888984 -888984 -888984 -888984 -888984 -888984 -889076 -890288 -890288 -890288 -890288 -890288 -890288 -890404 -892900 -892900 -892900 -892900 -892900 -892900 -892900 -892900 -895760 -895760 -895760 -895760 -895760 -895760 -895920 -897624 -897624 -897624 -897624 -897624 -897624 -897624 -897624 -897628 -898024 -898024 -898024 -898024 -898024 -898060 -900024 -900024 -900024 -900024 -900024 -900024 -900240 -901436 -901436 -901436 -901436 -901436 -901556 -903116 -903116 -903116 -903116 -903116 -903128 -905084 -905084 -905084 -905084 -905084 -905084 -905096 -906832 -906832 -906832 -906832 -906832 -906832 -908916 -908916 -908916 -908916 -908916 -908916 -908916 -910720 -910720 -910720 -910720 -910720 -910720 -911780 -912072 -912072 -912072 -912072 -914472 -914472 -914472 -914472 -914472 -917120 -917120 -917120 -917120 -917120 -919056 -919056 -919056 -919056 -919056 -920316 -920316 -920316 -920316 -920316 -920892 -920892 -920892 -920892 -920892 -922996 -922996 -922996 -922996 -922996 -925564 -925564 -925564 -925564 -925564 -927780 -927780 -927780 -927780 -928016 -928936 -929048 -930864 -930864 -930864 -930864 -932980 -933304 -933304 -933304 -933304 -933540 -934292 -935452 -935528 -935528 -935528 -935528 -935528 -935528 -935528 -935528 -935600 -936112 -936112 -936208 -936208 -936208 -936208 -936308 -936308 -936316 -936368 -936368 -936368 -936368 -936368 -936368 -936368 -936368 -936368 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -936376 -937404 -937404 -937404 -937404 -939968 -939968 -939968 -939968 -939968 -939968 -939968 -939968 -939968 -939968 -939968 -939968 -939968 -940516 -940516 -940516 -940516 -947168 -947168 -947168 -947168 -951948 -951948 -951948 -951948 -953488 -956916 -956916 -956916 -956916 -952296 -955376 -953420 -953260 -953900 -953516 -953900 -955052 -953516 -953516 -954284 -953324 -953516 -956208 -956208 -956208 -956208 -954668 -948988 -948988 -948988 -948988 -948988 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -945908 -947704 -948068 -948068 -948068 -948068 -948068 -948552 -949024 -949024 -949024 -949024 -949024 -949944 -950492 -950616 -950616 -950616 -950616 -951416 -952000 -952564 -952564 -952564 -952564 -952620 -953296 -953952 -954332 -954332 -954332 -954332 -954532 -955532 -956216 -956216 -956216 -956216 -956216 -956584 -957396 -957704 -957704 -957704 -957704 -957740 -958620 -959444 -959444 -959444 -959444 -959444 -960224 -963784 -963868 -963868 -963868 -963868 -963872 -964684 -972452 -972452 -972452 -972452 -972452 -972452 -973220 -974548 -974548 -974548 -974548 -974548 -975540 -977704 -978792 -978792 -978792 -978792 -978792 -981296 -982700 -983180 -983180 -983180 -983180 -983368 -985060 -987512 -987688 -987688 -987688 -987688 -988180 -990724 -993084 -993124 -993124 -993124 -993124 -993604 -995444 -996640 -996640 -996640 -996640 -996640 -997892 -999160 -1001452 -1001452 -1001452 -1001452 -1001452 -1002264 -1004120 -1004916 -1004916 -1004916 -1004916 -1004916 -1006648 -1010244 -1010548 -1010548 -1010548 -1010548 -1010572 -1011860 -1013748 -1017264 -1017264 -1017264 -1017264 -1017264 -1019096 -1021044 -1021044 -1021044 -1021044 -1021044 -1021536 -1023636 -1024964 -1024964 -1024964 -1024964 -1024964 -1025592 -1027672 -1029384 -1029384 -1029384 -1029384 -1029384 -1030056 -1032244 -1033756 -1033756 -1033756 -1033756 -1033756 -1034384 -1035856 -1036588 -1038428 -1038428 -1038428 -1038428 -1038428 -1039288 -1041088 -1042508 -1042508 -1042508 -1042508 -1042508 -1043544 -1045280 -1046580 -1046580 -1046580 -1046580 -1046580 -1047040 -1048560 -1049872 -1050576 -1050576 -1050576 -1050576 -1050576 -1052016 -1056044 -1057360 -1057360 -1057360 -1057360 -1057360 -1058336 -1059900 -1061244 -1061704 -1061704 -1061704 -1061704 -1061704 -1063148 -1063972 -1065404 -1067064 -1067536 -1067536 -1067536 -1067536 -1067536 -1069284 -1070524 -1072340 -1072836 -1072836 -1072836 -1072836 -1072836 -1073584 -1074592 -1076404 -1076832 -1076832 -1076832 -1076832 -1076832 -1078124 -1079640 -1080220 -1080644 -1080736 -1080736 -1080736 -1080736 -1080924 -1082868 -1083368 -1084412 -1084412 -1084412 -1084412 -1084412 -1085216 -1087068 -1087960 -1087960 -1087960 -1087960 -1087960 -1089788 -1093132 -1095064 -1095064 -1095064 -1095064 -1095064 -1095140 -1097092 -1098948 -1098948 -1098948 -1098948 -1098948 -1098980 -1100812 -1102032 -1102032 -1102032 -1102032 -1102032 -1105464 -1116944 -1119248 -1120364 -1120364 -1120364 -1120364 -1120364 -1121568 -1122908 -1123680 -1124604 -1125076 -1125076 -1125076 -1125076 -1125076 -1126292 -1128160 -1129952 -1129952 -1129952 -1129952 -1129952 -1130496 -1131884 -1133032 -1134204 -1135460 -1135636 -1135636 -1135636 -1135636 -1135636 -1136764 -1138048 -1139412 -1140764 -1141164 -1141188 -1142440 -1142440 -1142440 -1142440 -1142440 -1142440 -1143980 -1145876 -1146576 -1146576 -1146576 -1146576 -1146576 -1146576 -1147680 -1148328 -1148960 -1148960 -1148960 -1148960 -1148960 -1149004 -1150700 -1152228 -1153364 -1153364 -1153520 -1153784 -1154588 -1154680 -1154712 -1154728 -1154784 -1154992 -1155356 -1155620 -1155856 -1156044 -1156420 -1157392 -1158760 -1158980 -1158988 -1159000 -1162724 -1162740 -1162788 -1163112 -1163188 -1163188 -1163188 -1163188 -1163188 -1163384 -1165668 -1166648 -1166652 -1166664 -1166676 -1166688 -1166692 -1166696 -1166700 -1166700 -1172848 -1172852 -1174888 -1176824 -1176836 -1176852 -1176860 -1176876 -1176880 -1176888 -1176892 -1176900 -1176912 -1176944 -1177248 -1177712 -1178172 -1178536 -1178656 -1178780 -1178920 -1179044 -1179188 -1179384 -1180296 -1180300 -1180300 -1180300 -1180300 -1180300 -1180300 -1180372 -1180380 -1180468 -1180524 -1180524 -1180524 -1180524 -1180524 -1180576 -1180580 -1180644 -1180684 -1180684 -1180684 -1180684 -1180684 -1180684 -1180724 -1180756 -1180852 -1180904 -1180904 -1180904 -1180904 -1180904 -1180904 -1181096 -1181400 -1181744 -1181744 -1181744 -1181744 -1181744 -1181744 -1181936 -1181936 -1181936 -1181936 -1181936 -1181936 -1181936 -1181936 -1181936 -1181972 -1182004 -1182004 -1182004 -1182004 -1182004 -1182004 -1182004 -1182004 -1182004 -1182128 -1182156 -1182156 -1182156 -1182156 -1182156 -1182156 -1182156 -1182156 -1182180 -1182180 -1182180 -1182180 -1182180 -1182180 -1182180 -1182368 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1182516 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183576 -1183596 -1183772 -1183772 -1183772 -1183772 -1183772 -1183772 -1183772 -1183772 -1183772 -1183776 -1183776 -1183776 -1183776 -1183776 -1183776 -1183776 -1183776 -1183776 -1183952 -1184000 -1184000 -1184000 -1184000 -1184000 -1184000 -1184000 -1184200 -1184832 -1184832 -1184832 -1184832 -1184832 -1184832 -1184928 -1184928 -1184940 -1184940 -1184940 -1184940 -1184940 -1184940 -1184940 -1184940 -1185144 -1185144 -1185144 -1185144 -1185144 -1185144 -1185144 -1185144 -1185144 -1185144 -1185144 -1185144 -1185144 -1185144 -1185196 -1185196 -1185196 -1185196 -1185196 -1185196 -1185196 -1185196 -1185196 -1185268 -1185268 -1185268 -1185268 -1185268 -1185268 -1185268 -1185268 -1186444 -1186776 -1186776 -1186776 -1186776 -1186776 -1187664 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188072 -1188168 -1188168 -1188168 -1188168 -1188168 -1188168 -1188168 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189240 -1189292 -1189292 -1189292 -1189292 -1189292 -1189292 -1189292 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189532 -1189704 -1189708 -1189708 -1189708 -1189708 -1189708 -1190160 -1190160 -1190160 -1190160 -1190160 -1190160 -1190160 -1190160 -1190160 -1191100 -1191100 -1191100 -1191100 -1191100 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191316 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191748 -1191772 -1191772 -1191772 -1191772 -1191772 -1191772 -1191772 -1191772 -1192964 -1192964 -1192964 -1192964 -1192964 -1192964 -1192964 -1193060 -1193060 -1193060 -1193060 -1193060 -1193060 -1193060 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193072 -1193076 -1193076 -1193076 -1193076 -1193076 -1193076 -1193124 -1193124 -1193360 -1194108 -1194108 -1194108 -1194108 -1194108 -1193380 -1193460 -1193460 -1193460 -1193460 -1193460 -1193460 -1193460 -1193460 -1193792 -1193792 -1193792 -1193792 -1193792 -1193792 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194000 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194048 -1194328 -1194328 -1194328 -1194328 -1194328 -1194328 -1194328 -1194328 -1194328 -1194328 -1194360 -1194360 -1194360 -1194360 -1194360 -1194360 -1194360 -1194508 -1194508 -1194508 -1194508 -1194508 -1194508 -1194512 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194668 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1194912 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196596 -1196660 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196764 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1196948 -1197236 -1197236 -1197236 -1197236 -1197236 -1197236 -1197236 -1197236 -1197236 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197288 -1197376 -1197384 -1197596 -1197596 -1197596 -1197596 -1197596 -1197596 -1197596 -1197596 -1197588 -1197588 -1197588 -1197588 -1197588 -1197588 -1197588 -1197588 -1197564 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197460 -1197492 -1197508 -1197516 -1197516 -1197516 -1197516 -1197516 -1197516 diff --git a/pypy/module/__builtin__/app_inspect.py b/pypy/module/__builtin__/app_inspect.py --- a/pypy/module/__builtin__/app_inspect.py +++ b/pypy/module/__builtin__/app_inspect.py @@ -5,6 +5,8 @@ import sys +from __pypy__ import lookup_special + def _caller_locals(): # note: the reason why this is working is because the functions in here are # compiled by geninterp, so they don't have a frame @@ -62,7 +64,22 @@ obj = args[0] - if isinstance(obj, types.ModuleType): + dir_meth = None + if isinstance(obj, types.InstanceType): + try: + dir_meth = getattr(obj, "__dir__") + except AttributeError: + pass + else: + dir_meth = lookup_special(obj, "__dir__") + if dir_meth is not None: + result = dir_meth() + if not isinstance(result, list): + raise TypeError("__dir__() must return a list, not %r" % ( + type(result),)) + result.sort() + return result + elif isinstance(obj, types.ModuleType): try: result = list(obj.__dict__) result.sort() @@ -76,14 +93,6 @@ result.sort() return result - elif hasattr(type(obj), '__dir__'): - result = type(obj).__dir__(obj) - if not isinstance(result, list): - raise TypeError("__dir__() must return a list, not %r" % ( - type(result),)) - result.sort() - return result - else: #(regular item) Dict = {} try: diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -120,15 +120,32 @@ def test_dir_custom(self): class Foo(object): def __dir__(self): - return [1, 3, 2] + return ["1", "2", "3"] f = Foo() - assert dir(f) == [1, 2, 3] - # + assert dir(f) == ["1", "2", "3"] + class Foo: + def __dir__(self): + return ["apple"] + assert dir(Foo()) == ["apple"] class Foo(object): def __dir__(self): return 42 f = Foo() raises(TypeError, dir, f) + import types + class Foo(types.ModuleType): + def __dir__(self): + return ["blah"] + assert dir(Foo("a_mod")) == ["blah"] + + def test_dir_custom_lookup(self): + class M(type): + def __dir__(self, *args): return ["14"] + class X(object): + __metaclass__ = M + x = X() + x.__dir__ = lambda x: ["14"] + assert dir(x) != ["14"] def test_format(self): assert format(4) == "4" diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -16,6 +16,7 @@ 'debug_stop' : 'interp_debug.debug_stop', 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', + 'lookup_special' : 'interp_magic.lookup_special', } def setup_after_space_initialization(self): diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -1,9 +1,9 @@ +from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.objectmodel import we_are_translated from pypy.objspace.std.typeobject import MethodCache from pypy.objspace.std.mapdict import IndexCache -from pypy.module._file.interp_file import W_File def internal_repr(space, w_object): @@ -59,3 +59,14 @@ func = space.interp_w(Function, w_func) bltn = BuiltinFunction(func) return space.wrap(bltn) + + at unwrap_spec(ObjSpace, W_Root, str) +def lookup_special(space, w_obj, meth): + """Lookup up a special method on an object.""" + if space.is_oldstyle_instance(w_obj): + w_msg = space.wrap("this doesn't do what you want on old-style classes") + raise OperationError(space.w_TypeError, w_msg) + w_descr = space.lookup(w_obj, meth) + if w_descr is None: + return space.w_None + return space.get(w_descr, w_obj) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -36,3 +36,16 @@ assert not hasattr(A.b, 'im_func') assert A.a is not A.__dict__['a'] assert A.b is A.__dict__['b'] + + def test_lookup_special(self): + from __pypy__ import lookup_special + class X(object): + def foo(self): return 42 + x = X() + x.foo = 23 + x.bar = 80 + assert lookup_special(x, "foo")() == 42 + assert lookup_special(x, "bar") is None + class X: + pass + raises(TypeError, lookup_special, X(), "foo") diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -128,6 +128,9 @@ assert ns["x"] == ns["lemon"] == 3 assert ns["apple"] == 4 + def test_empty_module(self): + compile(self.ast.Module([]), "", "exec") + def test_ast_types(self): ast = self.ast expr = ast.Expr() diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -4,13 +4,13 @@ import errno from pypy.rlib import streamio from pypy.rlib.rarithmetic import r_longlong -from pypy.module._file.interp_stream import W_AbstractStream -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror, wrap_oserror_as_ioerror +from pypy.rlib.rstring import StringBuilder +from pypy.module._file.interp_stream import (W_AbstractStream, StreamErrors, + wrap_streamerror, wrap_oserror_as_ioerror) from pypy.module.posix.interp_posix import dispatch_filename from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty, make_weakref_descr -from pypy.interpreter.typedef import interp_attrproperty_w +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, + interp_attrproperty, make_weakref_descr, interp_attrproperty_w) from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -43,7 +43,11 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() - self.direct_close() + try: + self.direct_close() + except StreamErrors, e: + operr = wrap_streamerror(self.space, e, self.w_name) + operr.write_unraisable(self.space, '__del__ of ', self) def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd @@ -160,14 +164,14 @@ if n < 0: return stream.readall() else: - result = [] + result = StringBuilder(n) while n > 0: data = stream.read(n) if not data: break n -= len(data) result.append(data) - return ''.join(result) + return result.build() @unwrap_spec(size=int) def direct_readline(self, size=-1): @@ -345,11 +349,11 @@ may be returned, even if no size parameter was given.""") _decl(locals(), "readline", - """readlines([size]) -> list of strings, each a line from the file. + """readline([size]) -> next line from the file, as a string. -Call readline() repeatedly and return a list of the lines so read. -The optional size argument, if given, is an approximate bound on the -total number of bytes in the lines returned.""") +Retain newline. A non-negative size argument limits the maximum +number of bytes to return (an incomplete line may be returned then). +Return an empty string at EOF.""") _decl(locals(), "readlines", """readlines([size]) -> list of strings, each a line from the file. @@ -553,4 +557,4 @@ @unwrap_spec(file=W_File, encoding="str_or_None", errors="str_or_None") def set_file_encoding(space, file, encoding=None, errors=None): file.encoding = encoding - file.errors = errors \ No newline at end of file + file.errors = errors diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py --- a/pypy/module/_file/test/test_file.py +++ b/pypy/module/_file/test/test_file.py @@ -232,6 +232,29 @@ data = f.read() assert data == "15" + def test_exception_from_close(self): + import os + f = self.file(self.temppath, 'w') + os.close(f.fileno()) + raises(IOError, f.close) # bad file descriptor + + def test_exception_from_del(self): + import os, gc, sys, cStringIO + f = self.file(self.temppath, 'w') + g = cStringIO.StringIO() + preverr = sys.stderr + try: + sys.stderr = g + os.close(f.fileno()) + del f + gc.collect() # bad file descriptor in f.__del__() + finally: + sys.stderr = preverr + import errno + assert os.strerror(errno.EBADF) in g.getvalue() + # the following is a "nice to have" feature that CPython doesn't have + if '__pypy__' in sys.builtin_module_names: + assert self.temppath in g.getvalue() class AppTestConcurrency(object): diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app +from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs @@ -11,6 +11,7 @@ self.name = name self.codec = codec + @unwrap_spec(input=str, errors="str_or_None") def decode(self, space, input, errors=None): if errors is not None and errors != 'strict': raise OperationError(space.w_NotImplementedError, # XXX @@ -33,8 +34,8 @@ space.wrap("internal codec error")) return space.newtuple([space.wrap(output), space.wrap(len(input))]) - decode.unwrap_spec = ['self', ObjSpace, str, 'str_or_None'] + @unwrap_spec(input=unicode, errors="str_or_None") def encode(self, space, input, errors=None): if errors is not None and errors != 'strict': raise OperationError(space.w_NotImplementedError, # XXX @@ -57,7 +58,6 @@ space.wrap("internal codec error")) return space.newtuple([space.wrap(output), space.wrap(len(input))]) - encode.unwrap_spec = ['self', ObjSpace, unicode, 'str_or_None'] MultibyteCodec.typedef = TypeDef( @@ -69,6 +69,7 @@ MultibyteCodec.typedef.acceptable_as_base_class = False + at unwrap_spec(name=str) def getcodec(space, name): try: codec = c_codecs.getcodec(name) @@ -76,4 +77,3 @@ raise OperationError(space.w_LookupError, space.wrap("no such codec is supported.")) return space.wrap(MultibyteCodec(name, codec)) -getcodec.unwrap_spec = [ObjSpace, str] diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -43,7 +43,7 @@ unwrap_value(space, push_elem, ll_res, 0, callback_ptr.result, w_res) except OperationError, e: - tbprint(space, space.wrap(e.application_traceback), + tbprint(space, space.wrap(e.get_traceback()), space.wrap(e.errorstr(space))) # force the result to be zero if callback_ptr.result is not None: diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -28,7 +28,7 @@ from pypy.module.exceptions.interp_exceptions import W_SystemExit, _new_exception -from pypy.rlib import rstack # for resume points +from pypy.rlib import rstack, jit # for resume points from pypy.tool import stdlib_opcode as pythonopcode class _AppThunk(AbstractThunk): @@ -47,9 +47,19 @@ def call(self): costate = self.costate w_result = self.space.call_args(self.w_func, self.args) - rstack.resume_point("appthunk", costate, returns=w_result) costate.w_tempval = w_result +class _ResumeThunk(AbstractThunk): + def __init__(self, space, costate, w_frame): + self.space = space + self.costate = costate + self.w_frame = w_frame + + def call(self): + w_result = resume_frame(self.space, self.w_frame) + # costate.w_tempval = w_result #XXX? + + W_CoroutineExit = _new_exception('CoroutineExit', W_SystemExit, """Coroutine killed manually.""") @@ -97,7 +107,6 @@ "cannot switch to an unbound Coroutine")) state = self.costate self.switch() - rstack.resume_point("w_switch", state, space) w_ret, state.w_tempval = state.w_tempval, space.w_None return w_ret @@ -116,7 +125,7 @@ if isinstance(operror, OperationError): w_exctype = operror.w_type w_excvalue = operror.get_w_value(space) - w_exctraceback = operror.application_traceback + w_exctraceback = operror.get_traceback() w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback]) if w_exctype is self.costate.w_CoroutineExit: @@ -151,7 +160,7 @@ space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) - operror.application_traceback = tb + operror.set_traceback(tb) self._kill(operror) @@ -217,75 +226,17 @@ self.parent = space.interp_w(AppCoroutine, w_parent) ec = self.space.getexecutioncontext() self.subctx.setstate(space, w_state) - self.reconstruct_framechain() if space.is_w(w_thunk, space.w_None): - self.thunk = None + if space.is_w(w_state, space.w_None): + self.thunk = None + else: + self.bind(_ResumeThunk(space, self.costate, self.subctx.topframe)) else: w_func, w_args, w_kwds = space.unpackiterable(w_thunk, expected_length=3) args = Arguments.frompacked(space, w_args, w_kwds) self.bind(_AppThunk(space, self.costate, w_func, args)) - def reconstruct_framechain(self): - from pypy.interpreter.pyframe import PyFrame - from pypy.rlib.rstack import resume_state_create - if self.subctx.topframe is None: - self.frame = None - return - - space = self.space - ec = space.getexecutioncontext() - costate = self.costate - # now the big fun of recreating tiny things... - bottom = resume_state_create(None, "yield_current_frame_to_caller_1") - # ("coroutine__bind", state) - _bind_frame = resume_state_create(bottom, "coroutine__bind", costate) - # ("appthunk", costate, returns=w_result) - appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate) - chain = appthunk_frame - for frame in self.subctx.getframestack(): - assert isinstance(frame, PyFrame) - # ("execute_frame", self, executioncontext, returns=w_exitvalue) - chain = resume_state_create(chain, "execute_frame", frame, ec) - code = frame.pycode.co_code - # ("dispatch", self, co_code, ec, returns=next_instr) - chain = resume_state_create(chain, "dispatch", frame, code, ec) - # ("handle_bytecode", self, co_code, ec, returns=next_instr) - chain = resume_state_create(chain, "handle_bytecode", frame, code, - ec) - instr = frame.last_instr - opcode = ord(code[instr]) - map = pythonopcode.opmap - call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], - map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] - assert opcode in call_ops - # ("dispatch_call", self, co_code, next_instr, ec) - chain = resume_state_create(chain, "dispatch_call", frame, code, - instr+3, ec) - instr += 1 - oparg = ord(code[instr]) | ord(code[instr + 1]) << 8 - nargs = oparg & 0xff - nkwds = (oparg >> 8) & 0xff - if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']: - if nkwds == 0: # only positional arguments - chain = resume_state_create(chain, 'CALL_METHOD', frame, - nargs) - else: # includes keyword arguments - chain = resume_state_create(chain, 'CALL_METHOD_KW', frame) - elif opcode == map['CALL_FUNCTION'] and nkwds == 0: - # Only positional arguments - # case1: ("CALL_FUNCTION", f, nargs, returns=w_result) - chain = resume_state_create(chain, 'CALL_FUNCTION', frame, - nargs) - else: - # case2: ("call_function", f, returns=w_result) - chain = resume_state_create(chain, 'call_function', frame) - - # ("w_switch", state, space) - w_switch_frame = resume_state_create(chain, 'w_switch', costate, space) - # ("coroutine_switch", state, returns=incoming_frame) - switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", costate) - self.frame = switch_frame # _mixin_ did not work for methname in StacklessFlags.__dict__: @@ -411,3 +362,45 @@ @unwrap_spec(limit=int) def set_stack_depth_limit(space, limit): rstack.set_stack_depth_limit(limit) + + +# ___________________________________________________________________ +# unpickling trampoline + +def resume_frame(space, w_frame): + from pypy.interpreter.pyframe import PyFrame + frame = space.interp_w(PyFrame, w_frame, can_be_None=True) + w_result = space.w_None + operr = None + executioncontext = frame.space.getexecutioncontext() + while frame is not None: + code = frame.pycode.co_code + instr = frame.last_instr + opcode = ord(code[instr]) + map = pythonopcode.opmap + call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], + map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] + assert opcode in call_ops + instr += 1 + oparg = ord(code[instr]) | ord(code[instr + 1]) << 8 + nargs = oparg & 0xff + nkwds = (oparg >> 8) & 0xff + if nkwds == 0: # only positional arguments + # fast paths leaves things on the stack, pop them + if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']: + frame.dropvalues(nargs + 2) + elif opcode == map['CALL_FUNCTION']: + frame.dropvalues(nargs + 1) + + # small hack: unlink frame out of the execution context, because + # execute_frame will add it there again + executioncontext.topframeref = jit.non_virtual_ref(frame.f_backref()) + frame.last_instr = instr + 1 # continue after the call + try: + w_result = frame.execute_frame(w_result, operr) + except OperationError, operr: + pass + frame = frame.f_backref() + if operr: + raise operr + return w_result diff --git a/pypy/module/_stackless/interp_greenlet.py b/pypy/module/_stackless/interp_greenlet.py --- a/pypy/module/_stackless/interp_greenlet.py +++ b/pypy/module/_stackless/interp_greenlet.py @@ -124,7 +124,7 @@ space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) - operror.application_traceback = tb + operror.set_traceback(tb) # Dead greenlet: turn GreenletExit into a regular return if self.isdead() and operror.match(space, self.costate.w_GreenletExit): args_w = [operror.get_w_value(space)] diff --git a/pypy/module/_stackless/test/test_coroutine.py b/pypy/module/_stackless/test/test_coroutine.py --- a/pypy/module/_stackless/test/test_coroutine.py +++ b/pypy/module/_stackless/test/test_coroutine.py @@ -8,33 +8,6 @@ space = gettestobjspace(usemodules=('_stackless',)) cls.space = space - def test_pickle_coroutine_empty(self): - # this test is limited to basic pickling. - # real stacks can only tested with a stackless pypy build. - import _stackless as stackless - co = stackless.coroutine() - import pickle - pckl = pickle.dumps(co) - co2 = pickle.loads(pckl) - # the empty unpickled coroutine can still be used: - result = [] - co2.bind(result.append, 42) - co2.switch() - assert result == [42] - - def test_pickle_coroutine_bound(self): - import pickle - import _stackless - lst = [4] - co = _stackless.coroutine() - co.bind(lst.append, 2) - pckl = pickle.dumps((co, lst)) - - (co2, lst2) = pickle.loads(pckl) - assert lst2 == [4] - co2.switch() - assert lst2 == [4, 2] - def test_raise_propagate(self): import _stackless as stackless co = stackless.coroutine() diff --git a/pypy/module/_stackless/test/test_pickle.py b/pypy/module/_stackless/test/test_pickle.py --- a/pypy/module/_stackless/test/test_pickle.py +++ b/pypy/module/_stackless/test/test_pickle.py @@ -19,9 +19,35 @@ class AppTestPickle: def setup_class(cls): - if not option.runappdirect: - py.test.skip('pure appdirect test (run with -A)') - cls.space = gettestobjspace(usemodules=('_stackless',)) + cls.space = gettestobjspace(usemodules=('_stackless',), CALL_METHOD=True) + + def test_pickle_coroutine_empty(self): + # this test is limited to basic pickling. + # real stacks can only tested with a stackless pypy build. + import _stackless as stackless + co = stackless.coroutine() + import pickle + pckl = pickle.dumps(co) + co2 = pickle.loads(pckl) + # the empty unpickled coroutine can still be used: + result = [] + co2.bind(result.append, 42) + co2.switch() + assert result == [42] + + def test_pickle_coroutine_bound(self): + import pickle + import _stackless + lst = [4] + co = _stackless.coroutine() + co.bind(lst.append, 2) + pckl = pickle.dumps((co, lst)) + + (co2, lst2) = pickle.loads(pckl) + assert lst2 == [4] + co2.switch() + assert lst2 == [4, 2] + def test_simple_ish(self): @@ -58,6 +84,113 @@ finally: del sys.modules['mod'] + def test_pickle_again(self): + + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +output = [] +import _stackless +def f(coro, n, x): + if n == 0: + coro.switch() + return + f(coro, n-1, 2*x) + output.append(x) + +def example(): + main_coro = _stackless.coroutine.getcurrent() + sub_coro = _stackless.coroutine() + sub_coro.bind(f, main_coro, 5, 1) + sub_coro.switch() + + import pickle + pckl = pickle.dumps(sub_coro) + new_coro = pickle.loads(pckl) + pckl = pickle.dumps(new_coro) + newer_coro = pickle.loads(pckl) + + newer_coro.switch() + +example() +assert output == [16, 8, 4, 2, 1] +''' in mod.__dict__ + finally: + del sys.modules['mod'] + + def test_kwargs(self): + + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +output = [] +import _stackless +def f(coro, n, x, step=4): + if n == 0: + coro.switch() + return + f(coro, n-1, 2*x, step=1) + output.append(x) + +def example(): + main_coro = _stackless.coroutine.getcurrent() + sub_coro = _stackless.coroutine() + sub_coro.bind(f, main_coro, 5, 1, 1) + sub_coro.switch() + + import pickle + pckl = pickle.dumps(sub_coro) + new_coro = pickle.loads(pckl) + + new_coro.switch() + +example() +assert output == [16, 8, 4, 2, 1] +''' in mod.__dict__ + finally: + del sys.modules['mod'] + + def test_starstarargs(self): + + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +output = [] +import _stackless +def f(coro, n, x, step=4): + if n == 0: + coro.switch() + return + f(coro, n-1, 2*x, **{'step': 1}) + output.append(x) + +def example(): + main_coro = _stackless.coroutine.getcurrent() + sub_coro = _stackless.coroutine() + sub_coro.bind(f, main_coro, 5, 1, 1) + sub_coro.switch() + + import pickle + pckl = pickle.dumps(sub_coro) + new_coro = pickle.loads(pckl) + + new_coro.switch() + +example() +assert output == [16, 8, 4, 2, 1] +''' in mod.__dict__ + finally: + del sys.modules['mod'] + def test_closure(self): import new, sys @@ -130,8 +263,55 @@ finally: del sys.modules['mod'] + def test_exception_after_unpickling(self): + + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +output = [] +import _stackless +def f(coro, n, x): + if n == 0: + coro.switch() + raise ValueError + try: + f(coro, n-1, 2*x) + finally: + output.append(x) + +def example(): + main_coro = _stackless.coroutine.getcurrent() + sub_coro = _stackless.coroutine() + sub_coro.bind(f, main_coro, 5, 1) + sub_coro.switch() + + import pickle + pckl = pickle.dumps(sub_coro) + new_coro = pickle.loads(pckl) + + try: + sub_coro.switch() + except ValueError: + pass + else: + assert 0 + try: + new_coro.switch() + except ValueError: + pass + else: + assert 0 + +example() +assert output == [16, 8, 4, 2, 1] * 2 +''' in mod.__dict__ + finally: + del sys.modules['mod'] + def test_loop(self): - #skip("happily segfaulting") import new, sys mod = new.module('mod') diff --git a/pypy/module/_stackless/test/test_pickle_infrastructure.py b/pypy/module/_stackless/test/test_pickle_infrastructure.py deleted file mode 100644 --- a/pypy/module/_stackless/test/test_pickle_infrastructure.py +++ /dev/null @@ -1,301 +0,0 @@ -from pypy.conftest import gettestobjspace -from py.test import skip - - -class BaseAppTestPicklePrerequisites(object): - OPTIONS = {} - def setup_class(cls): - space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS) - cls.space = space - - def test_pickle_switch_function(object): - import _stackless, pickle - - sw = _stackless.coroutine.switch.im_func - dump = pickle.dumps(sw) - res = pickle.loads(dump) - - assert res is sw - assert res.func_code is sw.func_code - assert res.func_doc is sw.func_doc - assert res.func_globals is sw.func_globals - - def test_pickle_switch_function_code(object): - import _stackless, pickle - - sw = _stackless.coroutine.switch.im_func.func_code - dump = pickle.dumps(sw) - res = pickle.loads(dump) - - assert res is sw - -class AppTestPicklePrerequisites(BaseAppTestPicklePrerequisites): - pass - -class AppTestPicklePrerequisitesBuiltinShortcut(BaseAppTestPicklePrerequisites): - OPTIONS = {"objspace.std.builtinshortcut": True} - -class FrameCheck(object): - - def __init__(self, name): - self.name = name - - def __eq__(self, frame): - return frame.pycode.co_name == self.name - -class BytecodeCheck(object): - - def __init__(self, code, op, arg): - self.code = code - self.op = chr(op)+chr(arg & 0xff) + chr(arg >> 8 & 0xff) - - def __eq__(self, pos): - return self.code[pos-3:pos] == self.op - -class BaseTestReconstructFrameChain(object): - OPTIONS = {} - - def setup_class(cls): - space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS) - cls.space = space - - from pypy.rlib import rstack - cls.old_resume_state_create = rstack.resume_state_create - - def tr(prevstate, label, *args): - if prevstate is None: - prevstate = [] - return prevstate+[(label, args)] - rstack.resume_state_create = tr - - w_opmap = space.appexec([], """(): - import opcode - - return opcode.opmap - """) - - opmap = space.unwrap(w_opmap) - cls.CALL_FUNCTION = opmap['CALL_FUNCTION'] - cls.CALL_FUNCTION_VAR = opmap['CALL_FUNCTION_VAR'] - cls.CALL_METHOD = opmap['CALL_METHOD'] - - cls.callmethod = getattr(cls, cls.callmethod_label) - - def teardown_class(cls): - from pypy.rlib import rstack - rstack.resume_state_create = cls.old_resume_state_create - - def start(self, w_coro): - self.i = 0 - self.frame_to_check = w_coro.frame - w_coro.frame = None # avoid exploding in kill > __del__ - - def end(self): - assert self.i == len(self.frame_to_check) - - def check_entry(self, label, *args): - frame = self.frame_to_check - assert frame[self.i] == (label, args) - self.i += 1 - - - def test_two_frames_simple(self): - space = self.space - - w_res = space.appexec([], """(): - import _stackless as stackless - import pickle - - main = stackless.coroutine.getcurrent() - d = {'main': main} - - exec \"\"\" -def f(): - g(1) - -def g(x): - main.switch() -\"\"\" in d - f = d['f'] - g = d['g'] - - co = stackless.coroutine() - co.bind(f) - co.switch() - - s = pickle.dumps(co) - co = pickle.loads(s) - - return co, f, g - """) - - w_co, w_f, w_g = space.fixedview(w_res) - - ec = space.getexecutioncontext() - fcode = w_f.code.co_code - gcode = w_g.code.co_code - - self.start(w_co) - e = self.check_entry - e('yield_current_frame_to_caller_1') - e('coroutine__bind', w_co.costate) - e('appthunk', w_co.costate) - # f - e('execute_frame', FrameCheck('f'), ec) - e('dispatch', FrameCheck('f'), fcode, ec) - e('handle_bytecode', FrameCheck('f'), fcode, ec) - e('dispatch_call', FrameCheck('f'), fcode, - BytecodeCheck(fcode, self.CALL_FUNCTION, 1), ec) - e('CALL_FUNCTION', FrameCheck('f'), 1) - # g - e('execute_frame', FrameCheck('g'), ec) - e('dispatch', FrameCheck('g'), gcode, ec) - e('handle_bytecode', FrameCheck('g'), gcode, ec) - e('dispatch_call', FrameCheck('g'), gcode, - BytecodeCheck(gcode, self.callmethod, 0), ec) - e(self.callmethod_label, FrameCheck('g'), 0) - e('w_switch', w_co.costate, space) - e('coroutine_switch', w_co.costate) - self.end() - - def test_two_frames_stararg(self): - space = self.space - - w_res = space.appexec([], """(): - import _stackless as stackless - import pickle - - main = stackless.coroutine.getcurrent() - d = {'main': main} - - exec \"\"\" -def f(): - g(4, 3, d=2, *(1,)) - -def g(a, b, c, d): - main.switch() -\"\"\" in d - f = d['f'] - g = d['g'] - - co = stackless.coroutine() - co.bind(f) - co.switch() - - s = pickle.dumps(co) - co = pickle.loads(s) - - return co, f, g - """) - - w_co, w_f, w_g = space.fixedview(w_res) - - ec = space.getexecutioncontext() - fcode = w_f.code.co_code - gcode = w_g.code.co_code - - self.start(w_co) - e = self.check_entry - e('yield_current_frame_to_caller_1') - e('coroutine__bind', w_co.costate) - e('appthunk', w_co.costate) - # f - e('execute_frame', FrameCheck('f'), ec) - e('dispatch', FrameCheck('f'), fcode, ec) - e('handle_bytecode', FrameCheck('f'), fcode, ec) - e('dispatch_call', FrameCheck('f'), fcode, - BytecodeCheck(fcode, self.CALL_FUNCTION_VAR, 2+(1<<8)), ec) - e('call_function', FrameCheck('f')) - # g - e('execute_frame', FrameCheck('g'), ec) - e('dispatch', FrameCheck('g'), gcode, ec) - e('handle_bytecode', FrameCheck('g'), gcode, ec) - e('dispatch_call', FrameCheck('g'), gcode, - BytecodeCheck(gcode, self.callmethod, 0), ec) - e(self.callmethod_label, FrameCheck('g'), 0) - e('w_switch', w_co.costate, space) - e('coroutine_switch', w_co.costate) - self.end() - - def test_two_frames_method(self): - space = self.space - - w_res = space.appexec([], """(): - import _stackless as stackless - import pickle - import new, sys - - mod = new.module('mod') - sys.modules['mod'] = mod - - main = stackless.coroutine.getcurrent() - d = {'main': main} - - exec \"\"\" -def f(): - a = A() - a.m(1) - -def g(_, x): - main.switch() - -class A(object): - m = g -\"\"\" in d - f = d['f'] - g = d['g'] - A = d['A'] - - # to make pickling work - mod.A = A - A.__module__ = 'mod' - - co = stackless.coroutine() - co.bind(f) - co.switch() - - s = pickle.dumps(co) - co = pickle.loads(s) - - return co, f, g - """) - - w_co, w_f, w_g = space.fixedview(w_res) - - ec = space.getexecutioncontext() - fcode = w_f.code.co_code - gcode = w_g.code.co_code - - self.start(w_co) - e = self.check_entry - e('yield_current_frame_to_caller_1') - e('coroutine__bind', w_co.costate) - e('appthunk', w_co.costate) - # f - e('execute_frame', FrameCheck('f'), ec) - e('dispatch', FrameCheck('f'), fcode, ec) - e('handle_bytecode', FrameCheck('f'), fcode, ec) - e('dispatch_call', FrameCheck('f'), fcode, - BytecodeCheck(fcode, self.callmethod, 1), ec) - e(self.callmethod_label, FrameCheck('f'), 1) - # g - e('execute_frame', FrameCheck('g'), ec) - e('dispatch', FrameCheck('g'), gcode, ec) - e('handle_bytecode', FrameCheck('g'), gcode, ec) - e('dispatch_call', FrameCheck('g'), gcode, - BytecodeCheck(gcode, self.callmethod, 0), ec) - e(self.callmethod_label, FrameCheck('g'), 0) - e('w_switch', w_co.costate, space) - e('coroutine_switch', w_co.costate) - self.end() - -class TestReconstructFrameChain(BaseTestReconstructFrameChain): - callmethod_label = 'CALL_FUNCTION' - -class TestReconstructFrameChain_CALL_METHOD(BaseTestReconstructFrameChain): - OPTIONS = {"objspace.opcodes.CALL_METHOD": True, - } - - callmethod_label = 'CALL_METHOD' - - diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,9 +1,10 @@ import py +from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root -from pypy.interpreter.argument import Arguments from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, ObjSpace from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.gateway import interp2app, ObjSpace +from pypy.rlib import jit import weakref @@ -13,7 +14,7 @@ self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 - + def __del__(self): """This runs when the interp-level object goes away, and allows its lifeline to go away. The purpose of this is to activate the @@ -37,6 +38,7 @@ # weakref callbacks are not invoked eagerly here. They are # invoked by self.__del__() anyway. + @jit.dont_look_inside def get_or_make_weakref(self, space, w_subtype, w_obj, w_callable): w_weakreftype = space.gettypeobject(W_Weakref.typedef) is_weakreftype = space.is_w(w_weakreftype, w_subtype) @@ -55,6 +57,7 @@ self.cached_weakref_index = index return w_ref + @jit.dont_look_inside def get_or_make_proxy(self, space, w_obj, w_callable): can_reuse = space.is_w(w_callable, space.w_None) if can_reuse and self.cached_proxy_index >= 0: @@ -81,7 +84,7 @@ w_weakreftype = space.gettypeobject(W_Weakref.typedef) for i in range(len(self.refs_weak)): w_ref = self.refs_weak[i]() - if (w_ref is not None and + if (w_ref is not None and space.is_true(space.isinstance(w_ref, w_weakreftype))): return w_ref return space.w_None @@ -106,6 +109,7 @@ w_self.w_obj_weak = weakref.ref(w_obj) w_self.w_callable = w_callable + @jit.dont_look_inside def dereference(self): w_obj = self.w_obj_weak() return w_obj @@ -244,7 +248,7 @@ lifeline = w_obj.getweakref() if lifeline is None: lifeline = WeakrefLifeline(space) - w_obj.setweakref(space, lifeline) + w_obj.setweakref(space, lifeline) return lifeline.get_or_make_proxy(space, w_obj, w_callable) def descr__new__proxy(space, w_subtype, w_obj, w_callable=None): diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -363,42 +363,44 @@ def seek(self, offset, whence): READMAX = 2**18 # 256KB - if whence == 1: - if offset >= 0: - read = r_longlong(0) - while read < offset: - count = offset - read - if count < READMAX: - count = intmask(count) - else: - count = READMAX - read += len(self.read(count)) - else: - pos = self.readlength + offset - self.seek(pos, 0) + + # Make offset relative to the start of the file + if whence == 2: + # Read everything to arrive at the end + while len(self.read(READMAX)) > 0: + pass + offset += self.readlength + elif whence == 1: + offset += self.readlength elif whence == 0: + pass + else: + raise operationerrfmt(self.space.w_ValueError, + "Invalid value for whence: %d", whence) + + # Make offset relative to the current pos + # Rewind iff necessary + if offset < self.readlength: self.stream.seek(0, 0) self.decompressor = W_BZ2Decompressor(self.space) self.readlength = r_longlong(0) self.buffer = "" self.finished = False - read = 0 - while read < offset: - count = offset - read - if count < READMAX: - count = intmask(count) - else: - count = READMAX - length = len(self.read(count)) - read += length - if not length: - break else: - # first measure the length by reading everything left - while len(self.read(READMAX)) > 0: - pass - pos = self.readlength + offset - self.seek(pos, 0) + offset -= self.readlength + + # Seek + read = r_longlong(0) + while read < offset: + count = offset - read + if count < READMAX: + count = intmask(count) + else: + count = READMAX + length = len(self.read(count)) + if not length: + break + read += length def readall(self): w_result = self.decompressor.decompress(self.stream.readall()) diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -561,6 +561,7 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: + print 'Fatal error in cpyext, calling', callable.__name__ if not we_are_translated(): import traceback traceback.print_exc() @@ -965,6 +966,7 @@ state = space.fromcache(State) if state.find_extension(name, path) is not None: return + old_context = state.package_context state.package_context = name, path try: from pypy.rlib import rdynload @@ -990,7 +992,7 @@ generic_cpy_call(space, initfunc) state.check_and_raise_exception() finally: - state.package_context = None, None + state.package_context = old_context state.fixup_extension(name, path) @specialize.ll() diff --git a/pypy/module/cpyext/classobject.py b/pypy/module/cpyext/classobject.py --- a/pypy/module/cpyext/classobject.py +++ b/pypy/module/cpyext/classobject.py @@ -31,4 +31,9 @@ return w_result return w_instance.w_class.lookup(space, name) + at cpython_api([PyObject, PyObject, PyObject], PyObject) +def PyClass_New(space, w_bases, w_dict, w_name): + w_classobj = space.gettypefor(W_ClassObject) + return space.call_function(w_classobj, + w_name, w_bases, w_dict) diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py --- a/pypy/module/cpyext/frameobject.py +++ b/pypy/module/cpyext/frameobject.py @@ -1,6 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( - cpython_api, bootstrap_function, PyObjectFields, cpython_struct) + cpython_api, bootstrap_function, PyObjectFields, cpython_struct, + CANNOT_FAIL) from pypy.module.cpyext.pyobject import ( PyObject, Py_DecRef, make_ref, from_ref, track_reference, make_typedescr, get_typedescr) @@ -9,6 +10,7 @@ from pypy.module.cpyext.funcobject import PyCodeObject from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pycode import PyCode +from pypy.interpreter.pytraceback import PyTraceback PyFrameObjectStruct = lltype.ForwardReference() PyFrameObject = lltype.Ptr(PyFrameObjectStruct) @@ -80,3 +82,8 @@ frame = space.interp_w(PyFrame, w_frame) record_application_traceback(space, state.operror, frame, 0) return 0 + + at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL) +def PyTraceBack_Check(space, w_obj): + obj = space.interpclass_w(w_obj) + return obj is not None and isinstance(obj, PyTraceback) diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py --- a/pypy/module/cpyext/funcobject.py +++ b/pypy/module/cpyext/funcobject.py @@ -69,6 +69,10 @@ assert isinstance(w_method, Method) return borrow_from(w_method, w_method.w_class) + at cpython_api([PyObject], PyObject) +def PyClassMethod_New(space, w_function): + return space.call_method(space.builtin, "classmethod", w_function) + def unwrap_list_of_strings(space, w_list): return [space.str_w(w_item) for w_item in space.fixedview(w_list)] diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py --- a/pypy/module/cpyext/intobject.py +++ b/pypy/module/cpyext/intobject.py @@ -4,7 +4,7 @@ from pypy.module.cpyext.api import ( cpython_api, build_type_checkers, PyObject, CONST_STRING, CANNOT_FAIL, Py_ssize_t) -from pypy.rlib.rarithmetic import r_uint +from pypy.rlib.rarithmetic import r_uint, intmask, LONG_TEST import sys PyInt_Check, PyInt_CheckExact = build_type_checkers("Int") @@ -73,13 +73,22 @@ space.wrap("an integer is required, got NULL")) return space.int_w(w_obj) # XXX this is wrong on win64 + at cpython_api([rffi.SIZE_T], PyObject) +def PyInt_FromSize_t(space, ival): + """Create a new integer object with a value of ival. If the value exceeds + LONG_MAX, a long integer object is returned. + """ + if ival < LONG_TEST: + return space.wrap(intmask(ival)) + return space.wrap(ival) + @cpython_api([Py_ssize_t], PyObject) def PyInt_FromSsize_t(space, ival): """Create a new integer object with a value of ival. If the value is larger than LONG_MAX or smaller than LONG_MIN, a long integer object is returned. """ - return space.wrap(ival) # XXX this is wrong on win64 + return space.wrap(ival) @cpython_api([CONST_STRING, rffi.CCHARPP, rffi.INT_real], PyObject) def PyInt_FromString(space, str, pend, base): diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -73,29 +73,29 @@ rffi.charp2str(self.ml.c_ml_name) + "() takes no keyword arguments")) func = rffi.cast(PyCFunction, self.ml.c_ml_meth) + length = space.int_w(space.len(w_args)) if flags & METH_KEYWORDS: func = rffi.cast(PyCFunctionKwArgs, self.ml.c_ml_meth) return generic_cpy_call(space, func, w_self, w_args, w_kw) elif flags & METH_NOARGS: - if len(w_args.wrappeditems) == 0: + if length == 0: return generic_cpy_call(space, func, w_self, None) raise OperationError(space.w_TypeError, space.wrap( rffi.charp2str(self.ml.c_ml_name) + "() takes no arguments")) elif flags & METH_O: - assert isinstance(w_args, W_TupleObject) - if len(w_args.wrappeditems) != 1: + if length != 1: raise OperationError(space.w_TypeError, space.wrap("%s() takes exactly one argument (%d given)" % ( rffi.charp2str(self.ml.c_ml_name), - len(w_args.wrappeditems)))) - w_arg = w_args.wrappeditems[0] + length))) + w_arg = space.getitem(w_args, space.wrap(0)) return generic_cpy_call(space, func, w_self, w_arg) elif flags & METH_VARARGS: return generic_cpy_call(space, func, w_self, w_args) else: # METH_OLDARGS, the really old style - size = len(w_args.wrappeditems) + size = length if size == 1: - w_arg = w_args.wrappeditems[0] + w_arg = space.getitem(w_args, space.wrap(0)) elif size == 0: w_arg = None else: diff --git a/pypy/module/cpyext/number.py b/pypy/module/cpyext/number.py --- a/pypy/module/cpyext/number.py +++ b/pypy/module/cpyext/number.py @@ -49,6 +49,13 @@ failure. This is the equivalent of the Python expression long(o).""" return space.long(w_obj) + at cpython_api([PyObject], PyObject) +def PyNumber_Index(space, w_obj): + """Returns the o converted to a Python int or long on success or NULL with a + TypeError exception raised on failure. + """ + return space.index(w_obj) + def func_rename(newname): return lambda func: func_with_new_name(func, newname) diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py --- a/pypy/module/cpyext/pyerrors.py +++ b/pypy/module/cpyext/pyerrors.py @@ -57,7 +57,7 @@ if operror: ptype[0] = make_ref(space, operror.w_type) pvalue[0] = make_ref(space, operror.get_w_value(space)) - ptraceback[0] = make_ref(space, space.wrap(operror.application_traceback)) + ptraceback[0] = make_ref(space, space.wrap(operror.get_traceback())) else: ptype[0] = lltype.nullptr(PyObject.TO) pvalue[0] = lltype.nullptr(PyObject.TO) @@ -268,7 +268,7 @@ w_type = operror.w_type w_value = operror.get_w_value(space) - w_tb = space.wrap(operror.application_traceback) + w_tb = space.wrap(operror.get_traceback()) if rffi.cast(lltype.Signed, set_sys_last_vars): space.sys.setdictvalue(space, "last_type", w_type) diff --git a/pypy/module/cpyext/src/modsupport.c b/pypy/module/cpyext/src/modsupport.c --- a/pypy/module/cpyext/src/modsupport.c +++ b/pypy/module/cpyext/src/modsupport.c @@ -611,8 +611,8 @@ if (result != NULL && n > 0) { for (i = 0; i < n; ++i) { tmp = (PyObject *)va_arg(va, PyObject *); + Py_INCREF(tmp); PyTuple_SET_ITEM(result, i, tmp); - Py_INCREF(tmp); } } return result; diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( cpython_api, cpython_struct, bootstrap_function, build_type_checkers, - PyObjectFields, Py_ssize_t, CONST_STRING) + PyObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL) from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.pyobject import ( PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference, @@ -203,6 +203,10 @@ ref[0] = rffi.cast(PyObject, py_newstr) return 0 + at cpython_api([PyObject, PyObject], rffi.INT, error=CANNOT_FAIL) +def _PyString_Eq(space, w_str1, w_str2): + return space.eq_w(w_str1, w_str2) + @cpython_api([PyObjectP, PyObject], lltype.Void) def PyString_Concat(space, ref, w_newpart): """Create a new string object in *string containing the contents of newpart diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -172,12 +172,6 @@ This is equivalent to (PyBUF_ND).""" raise NotImplementedError - at cpython_api([Py_buffer], lltype.Void) -def PyBuffer_Release(space, view): - """Release the buffer view. This should be called when the buffer - is no longer being used as it may free memory from it.""" - raise NotImplementedError - @cpython_api([rffi.CCHARP], Py_ssize_t, error=CANNOT_FAIL) def PyBuffer_SizeFromFormat(space, format): """Return the implied ~Py_buffer.itemsize from the struct-stype @@ -198,13 +192,6 @@ given shape with the given number of bytes per element.""" raise NotImplementedError - at cpython_api([Py_buffer, PyObject, rffi.VOIDP, Py_ssize_t, rffi.INT_real, rffi.INT_real], rffi.INT_real, error=-1) -def PyBuffer_FillInfo(space, view, obj, buf, len, readonly, infoflags): - """Fill in a buffer-info structure, view, correctly for an exporter that can - only share a contiguous chunk of memory of "unsigned bytes" of the given - length. Return 0 on success and -1 (with raising an error) on error.""" - raise NotImplementedError - @cpython_api([Py_buffer], PyObject) def PyMemoryView_FromBuffer(space, view): """Create a memoryview object wrapping the given buffer-info structure view. @@ -1094,14 +1081,6 @@ """ raise NotImplementedError - at cpython_api([PyObject], PyObject) -def PyImport_ReloadModule(space, m): - """Reload a module. This is best described by referring to the built-in - Python function reload(), as the standard reload() function calls this - function directly. Return a new reference to the reloaded module, or NULL - with an exception set on failure (the module still exists in this case).""" - raise NotImplementedError - @cpython_api([rffi.CCHARP, PyObject], PyObject) def PyImport_ExecCodeModule(space, name, co): """Given a module name (possibly of the form package.module) and a code @@ -1140,13 +1119,6 @@ of the bytecode file, in little-endian byte order.""" raise NotImplementedError - at cpython_api([], PyObject) -def PyImport_GetModuleDict(space): - """Return the dictionary used for the module administration (a.k.a. - sys.modules). Note that this is a per-interpreter variable.""" - borrow_from() - raise NotImplementedError - @cpython_api([PyObject], PyObject) def PyImport_GetImporter(space, path): """Return an importer object for a sys.path/pkg.__path__ item @@ -1701,13 +1673,6 @@ """ raise NotImplementedError - at cpython_api([rffi.SIZE_T], PyObject) -def PyInt_FromSize_t(space, ival): - """Create a new integer object with a value of ival. If the value exceeds - LONG_MAX, a long integer object is returned. - """ - raise NotImplementedError - @cpython_api([PyObject], rffi.ULONGLONG, error=-1) def PyInt_AsUnsignedLongLongMask(space, io): """Will first attempt to cast the object to a PyIntObject or @@ -1920,13 +1885,6 @@ Reference counts are still not increased in this case.""" raise NotImplementedError - at cpython_api([PyObject], PyObject) -def PyNumber_Index(space, o): - """Returns the o converted to a Python int or long on success or NULL with a - TypeError exception raised on failure. - """ - raise NotImplementedError - @cpython_api([PyObject, rffi.INT_real], PyObject) def PyNumber_ToBase(space, n, base): """Returns the integer n converted to base as a string with a base @@ -2254,15 +2212,6 @@ standard C library function exit(status).""" raise NotImplementedError - at cpython_api([PyObject, Py_ssize_t, Py_ssize_t], PyObject) -def PyTuple_GetSlice(space, p, low, high): - """Take a slice of the tuple pointed to by p from low to high and return it - as a new tuple. - - This function used an int type for low and high. This might - require changes in your code for properly supporting 64-bit systems.""" - raise NotImplementedError - @cpython_api([], rffi.INT_real, error=CANNOT_FAIL) def PyTuple_ClearFreeList(space): """Clear the free list. Return the total number of freed items. @@ -2275,14 +2224,6 @@ """ raise NotImplementedError - at cpython_api([PyTypeObjectPtr], lltype.Void) -def PyType_Modified(space, type): - """Invalidate the internal lookup cache for the type and all of its - subtypes. This function must be called after any manual - modification of the attributes or base classes of the type. - """ - raise NotImplementedError - @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL) def PyType_IS_GC(space, o): """Return true if the type object includes support for the cycle detector; this diff --git a/pypy/module/cpyext/test/test_classobject.py b/pypy/module/cpyext/test/test_classobject.py --- a/pypy/module/cpyext/test/test_classobject.py +++ b/pypy/module/cpyext/test/test_classobject.py @@ -40,3 +40,14 @@ assert not isinstance(api.PyObject_GetAttr(w_instance, space.wrap('f')), Function) # _PyInstance_Lookup returns the raw descriptor assert isinstance(api._PyInstance_Lookup(w_instance, space.wrap('f')), Function) + + def test_pyclass_new(self, space, api): + w_bases = space.newtuple([]) + w_dict = space.newdict() + w_name = space.wrap("C") + w_class = api.PyClass_New(w_bases, w_dict, w_name) + assert not space.isinstance_w(w_class, space.w_type) + w_instance = space.call_function(w_class) + assert api.PyInstance_Check(w_instance) + assert space.is_true(space.call_method(space.builtin, "isinstance", + w_instance, w_class)) diff --git a/pypy/module/cpyext/test/test_eval.py b/pypy/module/cpyext/test/test_eval.py --- a/pypy/module/cpyext/test/test_eval.py +++ b/pypy/module/cpyext/test/test_eval.py @@ -193,3 +193,32 @@ return args assert module.call_func(f) == ("text", 42, None) assert module.call_method("text") == 2 + + def test_CallFunctionObjArgs(self): + module = self.import_extension('foo', [ + ("call_func", "METH_VARARGS", + """ + PyObject *t = PyString_FromString("t"); + PyObject *res = PyObject_CallFunctionObjArgs( + PyTuple_GetItem(args, 0), + Py_None, NULL); + Py_DECREF(t); + return res; + """), + ("call_method", "METH_VARARGS", + """ + PyObject *t = PyString_FromString("t"); + PyObject *count = PyString_FromString("count"); + PyObject *res = PyObject_CallMethodObjArgs( + PyTuple_GetItem(args, 0), + count, t, NULL); + Py_DECREF(t); + Py_DECREF(count); + return res; + """), + ]) + def f(*args): + return args + assert module.call_func(f) == (None,) + assert module.call_method("text") == 2 + diff --git a/pypy/module/cpyext/test/test_frameobject.py b/pypy/module/cpyext/test/test_frameobject.py --- a/pypy/module/cpyext/test/test_frameobject.py +++ b/pypy/module/cpyext/test/test_frameobject.py @@ -64,3 +64,31 @@ # Cython does not work on CPython as well... assert exc.traceback.tb_lineno == 42 # should be 48 assert frame.f_lineno == 42 + + def test_traceback_check(self): + module = self.import_extension('foo', [ + ("traceback_check", "METH_NOARGS", + """ + int check; + PyObject *type, *value, *tb; + PyObject *ret = PyRun_String("XXX", Py_eval_input, + Py_None, Py_None); + if (ret) { + Py_DECREF(ret); + PyErr_SetString(PyExc_AssertionError, "should raise"); + return NULL; + } + PyErr_Fetch(&type, &value, &tb); + check = PyTraceBack_Check(tb); + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(tb); + if (check) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } + """), + ]) + assert module.traceback_check() diff --git a/pypy/module/cpyext/test/test_funcobject.py b/pypy/module/cpyext/test/test_funcobject.py --- a/pypy/module/cpyext/test/test_funcobject.py +++ b/pypy/module/cpyext/test/test_funcobject.py @@ -44,3 +44,19 @@ assert w_code.co_firstlineno == 3 rffi.free_charp(filename) rffi.free_charp(funcname) + + def test_classmethod(self, space, api): + w_function = space.appexec([], """(): + def method(x): return x + return method + """) + w_class = space.call_function(space.w_type, space.wrap("C"), + space.newtuple([]), space.newdict()) + w_instance = space.call_function(w_class) + # regular instance method + space.setattr(w_class, space.wrap("method"), w_function) + assert space.is_w(space.call_method(w_instance, "method"), w_instance) + # now a classmethod + w_classmethod = api.PyClassMethod_New(w_function) + space.setattr(w_class, space.wrap("classmethod"), w_classmethod) + assert space.is_w(space.call_method(w_instance, "classmethod"), w_class) diff --git a/pypy/module/cpyext/test/test_intobject.py b/pypy/module/cpyext/test/test_intobject.py --- a/pypy/module/cpyext/test/test_intobject.py +++ b/pypy/module/cpyext/test/test_intobject.py @@ -50,3 +50,19 @@ ]) assert module.from_string() == 0x1234 assert type(module.from_string()) is int + + def test_size_t(self): + module = self.import_extension('foo', [ + ("values", "METH_NOARGS", + """ + return Py_BuildValue("NNNN", + PyInt_FromSize_t(123), + PyInt_FromSize_t((size_t)-1), + PyInt_FromSsize_t(123), + PyInt_FromSsize_t((size_t)-1)); + """), + ]) + values = module.values() + types = [type(x) for x in values] + assert types == [int, long, int, int] + diff --git a/pypy/module/cpyext/test/test_number.py b/pypy/module/cpyext/test/test_number.py --- a/pypy/module/cpyext/test/test_number.py +++ b/pypy/module/cpyext/test/test_number.py @@ -25,6 +25,15 @@ assert api.PyInt_CheckExact(w_l) w_l = api.PyNumber_Int(space.wrap(2 << 65)) assert api.PyLong_CheckExact(w_l) + w_l = api.PyNumber_Int(space.wrap(42.3)) + assert api.PyInt_CheckExact(w_l) + + def test_number_index(self, space, api): + w_l = api.PyNumber_Index(space.wrap(123L)) + assert api.PyLong_CheckExact(w_l) + w_l = api.PyNumber_Index(space.wrap(42.3)) + assert w_l is None + api.PyErr_Clear() def test_numbermethods(self, space, api): assert "ab" == space.unwrap( diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -283,3 +283,7 @@ self.raises(space, api, TypeError, api.PyString_AsEncodedObject, space.wrap(2), lltype.nullptr(rffi.CCHARP.TO), lltype.nullptr(rffi.CCHARP.TO) ) + + def test_eq(self, space, api): + assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) + assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) diff --git a/pypy/module/cpyext/test/test_sysmodule.py b/pypy/module/cpyext/test/test_sysmodule.py --- a/pypy/module/cpyext/test/test_sysmodule.py +++ b/pypy/module/cpyext/test/test_sysmodule.py @@ -22,12 +22,13 @@ Py_RETURN_NONE; """)]) import sys, StringIO + prev = sys.stdout sys.stdout = StringIO.StringIO() try: module.writestdout() assert sys.stdout.getvalue() == "format: 42\n" finally: - sys.stdout = sys.__stdout__ + sys.stdout = prev class TestSysModule(BaseApiTest): def test_sysmodule(self, space, api): diff --git a/pypy/module/cpyext/test/test_tupleobject.py b/pypy/module/cpyext/test/test_tupleobject.py --- a/pypy/module/cpyext/test/test_tupleobject.py +++ b/pypy/module/cpyext/test/test_tupleobject.py @@ -3,8 +3,10 @@ from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref from pypy.module.cpyext.test.test_api import BaseApiTest from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace class TestTupleObject(BaseApiTest): + def test_tupleobject(self, space, api): assert not api.PyTuple_Check(space.w_None) assert api.PyTuple_SetItem(space.w_None, 0, space.w_None) == -1 @@ -20,11 +22,29 @@ ar[0] = rffi.cast(PyObject, make_ref(space, py_tuple)) api._PyTuple_Resize(ar, 2) py_tuple = from_ref(space, ar[0]) - assert len(py_tuple.wrappeditems) == 2 + assert space.int_w(space.len(py_tuple)) == 2 api._PyTuple_Resize(ar, 10) py_tuple = from_ref(space, ar[0]) - assert len(py_tuple.wrappeditems) == 10 + assert space.int_w(space.len(py_tuple)) == 10 api.Py_DecRef(ar[0]) lltype.free(ar, flavor='raw') + + def test_setitem(self, space, api): + atuple = space.newtuple([space.wrap(0), space.wrap("hello")]) + assert api.PyTuple_Size(atuple) == 2 + assert space.eq_w(space.getitem(atuple, space.wrap(0)), space.wrap(0)) + assert space.eq_w(space.getitem(atuple, space.wrap(1)), space.wrap("hello")) + w_obj = space.wrap(1) + api.Py_IncRef(w_obj) + api.PyTuple_SetItem(atuple, 1, w_obj) + assert api.PyTuple_Size(atuple) == 2 + assert space.eq_w(space.getitem(atuple, space.wrap(0)), space.wrap(0)) + assert space.eq_w(space.getitem(atuple, space.wrap(1)), space.wrap(1)) + + def test_getslice(self, space, api): + w_tuple = space.newtuple([space.wrap(i) for i in range(10)]) + w_slice = api.PyTuple_GetSlice(w_tuple, 3, -3) + assert space.eq_w(w_slice, + space.newtuple([space.wrap(i) for i in range(3, 7)])) diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py --- a/pypy/module/cpyext/tupleobject.py +++ b/pypy/module/cpyext/tupleobject.py @@ -6,7 +6,7 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.tupleobject import W_TupleObject - +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PyTuple_Check, PyTuple_CheckExact = build_type_checkers("Tuple") @@ -19,25 +19,30 @@ if not PyTuple_Check(space, w_t): # XXX this should also steal a reference, test it!!! PyErr_BadInternalCall(space) - assert isinstance(w_t, W_TupleObject) - w_t.wrappeditems[pos] = w_obj + _setitem_tuple(w_t, pos, w_obj) Py_DecRef(space, w_obj) # SetItem steals a reference! return 0 +def _setitem_tuple(w_t, pos, w_obj): + if isinstance(w_t, W_TupleObject): + w_t.wrappeditems[pos] = w_obj + elif isinstance(w_t, W_SmallTupleObject): + w_t.setitem(pos, w_obj) + else: + assert False + @cpython_api([PyObject, Py_ssize_t], PyObject) def PyTuple_GetItem(space, w_t, pos): if not PyTuple_Check(space, w_t): PyErr_BadInternalCall(space) - assert isinstance(w_t, W_TupleObject) - w_obj = w_t.wrappeditems[pos] + w_obj = space.getitem(w_t, space.wrap(pos)) return borrow_from(w_t, w_obj) @cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) def PyTuple_GET_SIZE(space, w_t): """Return the size of the tuple p, which must be non-NULL and point to a tuple; no error checking is performed. """ - assert isinstance(w_t, W_TupleObject) - return len(w_t.wrappeditems) + return space.int_w(space.len(w_t)) @cpython_api([PyObject], Py_ssize_t, error=-1) def PyTuple_Size(space, ref): @@ -63,15 +68,21 @@ py_tuple = from_ref(space, ref[0]) if not PyTuple_Check(space, py_tuple): PyErr_BadInternalCall(space) - assert isinstance(py_tuple, W_TupleObject) py_newtuple = PyTuple_New(space, newsize) to_cp = newsize - oldsize = len(py_tuple.wrappeditems) + oldsize = space.int_w(space.len(py_tuple)) if oldsize < newsize: to_cp = oldsize for i in range(to_cp): - py_newtuple.wrappeditems[i] = py_tuple.wrappeditems[i] + _setitem_tuple(py_newtuple, i, space.getitem(py_tuple, space.wrap(i))) Py_DecRef(space, ref[0]) ref[0] = make_ref(space, py_newtuple) return 0 + + at cpython_api([PyObject, Py_ssize_t, Py_ssize_t], PyObject) +def PyTuple_GetSlice(space, w_obj, low, high): + """Take a slice of the tuple pointed to by p from low to high and return it + as a new tuple. + """ + return space.getslice(w_obj, space.wrap(low), space.wrap(high)) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -650,3 +650,13 @@ name = space.str_w(w_name) w_obj = w_type.lookup(name) return borrow_from(w_type, w_obj) + + at cpython_api([PyTypeObjectPtr], lltype.Void) +def PyType_Modified(space, w_obj): + """Invalidate the internal lookup cache for the type and all of its + subtypes. This function must be called after any manual + modification of the attributes or base classes of the type. + """ + # PyPy already takes care of direct modifications to type.__dict__ + # (which is a W_DictProxyObject). + pass diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -1,13 +1,23 @@ -from pypy.interpreter.mixedmodule import MixedModule +from pypy.interpreter.mixedmodule import MixedModule class Module(MixedModule): applevel_name = 'numpy' - + interpleveldefs = { - 'zeros' : 'numarray.zeros', - 'minimum' : 'ufunc.minimum', - } + 'array': 'interp_numarray.SingleDimArray', + 'zeros': 'interp_numarray.zeros', + + # ufuncs + 'absolute': 'interp_ufuncs.absolute', + 'copysign': 'interp_ufuncs.copysign', + 'exp': 'interp_ufuncs.exp', + 'maximum': 'interp_ufuncs.maximum', + 'minimum': 'interp_ufuncs.minimum', + 'negative': 'interp_ufuncs.negative', + 'reciprocal': 'interp_ufuncs.reciprocal', + 'sign': 'interp_ufuncs.sign', + } appleveldefs = {} diff --git a/pypy/module/micronumpy/bench/add.py b/pypy/module/micronumpy/bench/add.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/bench/add.py @@ -0,0 +1,10 @@ + +import numpy + +def f(): + a = numpy.zeros(10000000) + a = a + a + a + a + a + # To ensure that the computation isn't totally optimized away. + a[0] = 3.0 + +f() diff --git a/pypy/module/micronumpy/bench/iterate.py b/pypy/module/micronumpy/bench/iterate.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/bench/iterate.py @@ -0,0 +1,11 @@ + +import numpy + +def f(): + sum = 0 + a = numpy.zeros(10000000) + for i in range(10000000): + sum += a[i] + return sum + +f() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_numarray.py @@ -0,0 +1,257 @@ +from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable +from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef +from pypy.rlib import jit +from pypy.rpython.lltypesystem import lltype +from pypy.tool.sourcetools import func_with_new_name + + +def dummy1(v): + assert isinstance(v, float) + return v + +def dummy2(v): + assert isinstance(v, float) + return v + +TP = lltype.Array(lltype.Float, hints={'nolength': True}) + +numpy_driver = jit.JitDriver(greens = ['signature'], + reds = ['result_size', 'i', 'self', 'result']) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new + +def add(v1, v2): + return v1 + v2 +def sub(v1, v2): + return v1 - v2 +def mul(v1, v2): + return v1 * v2 +def div(v1, v2): + return v1 / v2 + +class BaseArray(Wrappable): + def __init__(self): + self.invalidates = [] + + def invalidated(self): + for arr in self.invalidates: + arr.force_if_needed() + self.invalidates = [] + + def _binop_impl(function): + signature = Signature() + def impl(self, space, w_other): + new_sig = self.signature.transition(signature) + if isinstance(w_other, BaseArray): + res = Call2( + function, + self, + w_other, + new_sig.transition(w_other.signature) + ) + w_other.invalidates.append(res) + else: + w_other = FloatWrapper(space.float_w(w_other)) + res = Call2( + function, + self, + w_other, + new_sig.transition(w_other.signature) + ) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + + descr_add = _binop_impl(add) + descr_sub = _binop_impl(sub) + descr_mul = _binop_impl(mul) + descr_div = _binop_impl(div) + + def get_concrete(self): + raise NotImplementedError + + def descr_len(self, space): + return self.get_concrete().descr_len(space) + + @unwrap_spec(item=int) + def descr_getitem(self, space, item): + return self.get_concrete().descr_getitem(space, item) + + @unwrap_spec(item=int, value=float) + def descr_setitem(self, space, item, value): + self.invalidated() + return self.get_concrete().descr_setitem(space, item, value) + + +class FloatWrapper(BaseArray): + """ + Intermediate class representing a float literal. + """ + _immutable_fields_ = ["float_value"] + signature = Signature() + + def __init__(self, float_value): + BaseArray.__init__(self) + self.float_value = float_value + + def find_size(self): + raise ValueError + + def eval(self, i): + return self.float_value + +class VirtualArray(BaseArray): + """ + Class for representing virtual arrays, such as binary ops or ufuncs + """ + def __init__(self, signature): + BaseArray.__init__(self) + self.forced_result = None + self.signature = signature + + def compute(self): + i = 0 + signature = self.signature + result_size = self.find_size() + result = SingleDimArray(result_size) + while i < result_size: + numpy_driver.jit_merge_point(signature=signature, + result_size=result_size, i=i, + self=self, result=result) + result.storage[i] = self.eval(i) + i += 1 + return result + + def force_if_needed(self): + if self.forced_result is None: + self.forced_result = self.compute() + + def get_concrete(self): + self.force_if_needed() + return self.forced_result + + def eval(self, i): + if self.forced_result is not None: + return self.forced_result.eval(i) + return self._eval(i) + +class Call1(VirtualArray): + _immutable_fields_ = ["function", "values"] + + def __init__(self, function, values, signature): + VirtualArray.__init__(self, signature) + self.function = function + self.values = values + + def find_size(self): + return self.values.find_size() + + def _eval(self, i): + return self.function(self.values.eval(i)) + +class Call2(VirtualArray): + """ + Intermediate class for performing binary operations. + """ + _immutable_fields_ = ["function", "left", "right"] + def __init__(self, function, left, right, signature): + VirtualArray.__init__(self, signature) + self.function = function + self.left = left + self.right = right + + def find_size(self): + try: + return self.left.find_size() + except ValueError: + pass + return self.right.find_size() + + def _eval(self, i): + lhs, rhs = self.left.eval(i), self.right.eval(i) + return self.function(lhs, rhs) + + +class SingleDimArray(BaseArray): + signature = Signature() + + def __init__(self, size): + BaseArray.__init__(self) + self.size = size + self.storage = lltype.malloc(TP, size, zero=True, + flavor='raw', track_allocation=False) + # XXX find out why test_zjit explodes with trackign of allocations + + def get_concrete(self): + return self + + def find_size(self): + return self.size + + def eval(self, i): + return self.storage[i] + + def getindex(self, space, item): + if item >= self.size: + raise operationerrfmt(space.w_IndexError, + '%d above array size', item) + if item < 0: + item += self.size + if item < 0: + raise operationerrfmt(space.w_IndexError, + '%d below zero', item) + return item + + def descr_len(self, space): + return space.wrap(self.size) + + @unwrap_spec(item=int) + def descr_getitem(self, space, item): + item = self.getindex(space, item) + return space.wrap(self.storage[item]) + + @unwrap_spec(item=int, value=float) + def descr_setitem(self, space, item, value): + item = self.getindex(space, item) + self.invalidated() + self.storage[item] = value + + def __del__(self): + lltype.free(self.storage, flavor='raw') + +def descr_new_numarray(space, w_type, w_size_or_iterable): + l = space.listview(w_size_or_iterable) + arr = SingleDimArray(len(l)) + i = 0 + for w_elem in l: + arr.storage[i] = space.float_w(space.float(w_elem)) + i += 1 + return space.wrap(arr) + + at unwrap_spec(ObjSpace, int) +def zeros(space, size): + return space.wrap(SingleDimArray(size)) + + +BaseArray.typedef = TypeDef( + 'numarray', + __new__ = interp2app(descr_new_numarray), + __len__ = interp2app(BaseArray.descr_len), + __getitem__ = interp2app(BaseArray.descr_getitem), + __setitem__ = interp2app(BaseArray.descr_setitem), + + __add__ = interp2app(BaseArray.descr_add), + __sub__ = interp2app(BaseArray.descr_sub), + __mul__ = interp2app(BaseArray.descr_mul), + __div__ = interp2app(BaseArray.descr_div), +) \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -0,0 +1,66 @@ +import math + +from pypy.interpreter.gateway import unwrap_spec +from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature +from pypy.rlib import rfloat +from pypy.tool.sourcetools import func_with_new_name + + +def ufunc(func): + signature = Signature() + @unwrap_spec(array=BaseArray) + def impl(space, array): + w_res = Call1(func, array, array.signature.transition(signature)) + array.invalidates.append(w_res) + return w_res + return func_with_new_name(impl, "%s_dispatcher" % func.__name__) + +def ufunc2(func): + signature = Signature() + @unwrap_spec(larray=BaseArray, rarray=BaseArray) + def impl(space, larray, rarray): + new_sig = larray.signature.transition(signature).transition(rarray.signature) + w_res = Call2(func, larray, rarray, new_sig) + larray.invalidates.append(w_res) + rarray.invalidates.append(w_res) + return w_res + return func_with_new_name(impl, "%s_dispatcher" % func.__name__) + + at ufunc +def absolute(value): + return abs(value) + + at ufunc2 +def copysign(lvalue, rvalue): + return rfloat.copysign(lvalue, rvalue) + + at ufunc +def exp(value): + try: + return math.exp(value) + except OverflowError: + return rfloat.INFINITY + + at ufunc2 +def maximum(lvalue, rvalue): + return max(lvalue, rvalue) + + at ufunc2 +def minimum(lvalue, rvalue): + return min(lvalue, rvalue) + + at ufunc +def negative(value): + return -value + + at ufunc +def reciprocal(value): + if value == 0.0: + return rfloat.copysign(rfloat.INFINITY, value) + return 1.0 / value + + at ufunc +def sign(value): + if value == 0.0: + return 0.0 + return rfloat.copysign(1.0, value) diff --git a/pypy/module/micronumpy/numarray.py b/pypy/module/micronumpy/numarray.py deleted file mode 100644 --- a/pypy/module/micronumpy/numarray.py +++ /dev/null @@ -1,123 +0,0 @@ - -from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError -from pypy.interpreter.typedef import TypeDef -from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped -from pypy.rlib.debug import make_sure_not_resized - -class BaseNumArray(Wrappable): - pass - -class NumArray(BaseNumArray): - def __init__(self, space, dim, dtype): - self.dim = dim - self.space = space - # ignore dtype for now - self.storage = [0] * dim - make_sure_not_resized(self.storage) - - @unwrap_spec(index=int) - def descr_getitem(self, index): - space = self.space - try: - return space.wrap(self.storage[index]) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list index out of range")) - - @unwrap_spec(index=int, value=int) - def descr_setitem(self, index, value): - space = self.space - try: - self.storage[index] = value - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list index out of range")) - return space.w_None - - def descr_len(self): - return self.space.wrap(len(self.storage)) - -NumArray.typedef = TypeDef( - 'NumArray', - __getitem__ = interp2app(NumArray.descr_getitem), - __setitem__ = interp2app(NumArray.descr_setitem), - __len__ = interp2app(NumArray.descr_len), -) - -def compute_pos(space, indexes, dim): - current = 1 - pos = 0 - for i in range(len(indexes)): - index = indexes[i] - d = dim[i] - if index >= d or index <= -d - 1: - raise OperationError(space.w_IndexError, - space.wrap("invalid index")) - if index < 0: - index = d + index - pos += index * current - current *= d - return pos - -class MultiDimArray(BaseNumArray): - def __init__(self, space, dim, dtype): - self.dim = dim - self.space = space - # ignore dtype for now - size = 1 - for el in dim: - size *= el - self.storage = [0] * size - make_sure_not_resized(self.storage) - - def _unpack_indexes(self, space, w_index): - indexes = [space.int_w(w_i) for w_i in space.fixedview(w_index)] - if len(indexes) != len(self.dim): - raise OperationError(space.w_IndexError, space.wrap( - 'Wrong index')) - return indexes - - def descr_getitem(self, w_index): - space = self.space - indexes = self._unpack_indexes(space, w_index) - pos = compute_pos(space, indexes, self.dim) - return space.wrap(self.storage[pos]) - - @unwrap_spec(value=int) - def descr_setitem(self, w_index, value): - space = self.space - indexes = self._unpack_indexes(space, w_index) - pos = compute_pos(space, indexes, self.dim) - self.storage[pos] = value - return space.w_None - - def descr_len(self): - return self.space.wrap(self.dim[0]) - -MultiDimArray.typedef = TypeDef( - 'NumArray', - __getitem__ = interp2app(MultiDimArray.descr_getitem), - __setitem__ = interp2app(MultiDimArray.descr_setitem), - __len__ = interp2app(MultiDimArray.descr_len), -) - -def unpack_dim(space, w_dim): - if space.is_true(space.isinstance(w_dim, space.w_int)): - return [space.int_w(w_dim)] - dim_w = space.fixedview(w_dim) - return [space.int_w(w_i) for w_i in dim_w] - -def unpack_dtype(space, w_dtype): - if space.is_w(w_dtype, space.w_int): - return 'i' - else: - raise NotImplementedError - -def zeros(space, w_dim, w_dtype): - dim = unpack_dim(space, w_dim) - dtype = unpack_dtype(space, w_dtype) - if len(dim) == 1: - return space.wrap(NumArray(space, dim[0], dtype)) - else: - return space.wrap(MultiDimArray(space, dim, dtype)) diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_base.py @@ -0,0 +1,19 @@ +from pypy.conftest import gettestobjspace +from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper + + +class BaseNumpyAppTest(object): + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('micronumpy',)) + + +class TestSignature(object): + def test_binop_signature(self, space): + ar = SingleDimArray(10) + v1 = ar.descr_add(space, ar) + v2 = ar.descr_add(space, FloatWrapper(2.0)) + assert v1.signature is not v2.signature + v3 = ar.descr_add(space, FloatWrapper(1.0)) + assert v2.signature is v3.signature + v4 = ar.descr_add(space, ar) + assert v1.signature is v4.signature \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -0,0 +1,141 @@ +import py + +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + + +class AppTestNumArray(BaseNumpyAppTest): + def test_type(self): + from numpy import array + ar = array(range(5)) + assert type(ar) is type(ar + ar) + + def test_init(self): + from numpy import zeros + a = zeros(15) + # Check that storage was actually zero'd. + assert a[10] == 0.0 + # And check that changes stick. + a[13] = 5.3 + assert a[13] == 5.3 + + def test_iterator_init(self): + from numpy import array + a = array(range(5)) + assert a[3] == 3 + + def test_getitem(self): + from numpy import array + a = array(range(5)) + raises(IndexError, "a[5]") + a = a + a + raises(IndexError, "a[5]") + assert a[-1] == 8 + raises(IndexError, "a[-6]") + + def test_setitem(self): + from numpy import array + a = array(range(5)) + a[-1] = 5.0 + assert a[4] == 5.0 + raises(IndexError, "a[5] = 0.0") + raises(IndexError, "a[-6] = 3.0") + + def test_len(self): + from numpy import array + a = array(range(5)) + assert len(a) == 5 + assert len(a + a) == 5 + + def test_add(self): + from numpy import array + a = array(range(5)) + b = a + a + for i in range(5): + assert b[i] == i + i + + def test_add_other(self): + from numpy import array + a = array(range(5)) + b = array(reversed(range(5))) + c = a + b + for i in range(5): + assert c[i] == 4 + + def test_add_constant(self): + from numpy import array + a = array(range(5)) + b = a + 5 + for i in range(5): + assert b[i] == i + 5 + + def test_subtract(self): + from numpy import array + a = array(range(5)) + b = a - a + for i in range(5): + assert b[i] == 0 + + def test_subtract_other(self): + from numpy import array + a = array(range(5)) + b = array([1, 1, 1, 1, 1]) + c = a - b + for i in range(5): + assert c[i] == i - 1 + + def test_subtract_constant(self): + from numpy import array + a = array(range(5)) + b = a - 5 + for i in range(5): + assert b[i] == i - 5 + + def test_mul(self): + from numpy import array + a = array(range(5)) + b = a * a + for i in range(5): + assert b[i] == i * i + + def test_mul_constant(self): + from numpy import array + a = array(range(5)) + b = a * 5 + for i in range(5): + assert b[i] == i * 5 + + def test_div(self): + from numpy import array + a = array(range(1, 6)) + b = a / a + for i in range(5): + assert b[i] == 1 + + def test_div_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a / b + for i in range(5): + assert c[i] == i / 2.0 + + def test_div_constant(self): + from numpy import array + a = array(range(5)) + b = a / 5.0 + for i in range(5): + assert b[i] == i / 5.0 + + def test_auto_force(self): + from numpy import array + a = array(range(5)) + b = a - 1 + a[2] = 3 + for i in range(5): + assert b[i] == i - 1 + + a = array(range(5)) + b = a + a + c = b + b + b[1] = 5 + assert c[1] == 4 \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_numpy.py b/pypy/module/micronumpy/test/test_numpy.py deleted file mode 100644 --- a/pypy/module/micronumpy/test/test_numpy.py +++ /dev/null @@ -1,65 +0,0 @@ - -from pypy.conftest import gettestobjspace - -class AppTestNumpy(object): - def setup_class(cls): - cls.space = gettestobjspace(usemodules=('micronumpy',)) - - def test_zeroes(self): - from numpy import zeros - ar = zeros(3, dtype=int) - assert ar[0] == 0 - - def test_setitem_getitem(self): - from numpy import zeros - ar = zeros(8, dtype=int) - assert ar[0] == 0 - ar[1] = 3 - assert ar[1] == 3 - raises((TypeError, ValueError), ar.__getitem__, 'xyz') - raises(IndexError, ar.__getitem__, 38) - assert ar[-2] == 0 - assert ar[-7] == 3 - assert len(ar) == 8 - - def test_minimum(self): - from numpy import zeros, minimum - ar = zeros(5, dtype=int) - ar2 = zeros(5, dtype=int) - ar[0] = 3 - ar[1] = -3 - ar[2] = 8 - ar2[3] = -1 - ar2[4] = 8 - x = minimum(ar, ar2) - assert x[0] == 0 - assert x[1] == -3 - assert x[2] == 0 - assert x[3] == -1 - assert x[4] == 0 - assert len(x) == 5 - raises(ValueError, minimum, ar, zeros(3, dtype=int)) - -class AppTestMultiDim(object): - def setup_class(cls): - cls.space = gettestobjspace(usemodules=('micronumpy',)) - - def test_multidim(self): - from numpy import zeros - ar = zeros((3, 3), dtype=int) - assert ar[0, 2] == 0 - raises(IndexError, ar.__getitem__, (3, 0)) - assert ar[-2, 1] == 0 - - def test_multidim_getset(self): - from numpy import zeros - ar = zeros((3, 3, 3), dtype=int) - ar[1, 2, 1] = 3 - assert ar[1, 2, 1] == 3 - assert ar[-2, 2, 1] == 3 - assert ar[2, 2, 1] == 0 - assert ar[-2, 2, -2] == 3 - - def test_len(self): - from numpy import zeros - assert len(zeros((3, 2, 1), dtype=int)) == 3 diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -0,0 +1,85 @@ + +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + + +class AppTestUfuncs(BaseNumpyAppTest): + def test_negative(self): + from numpy import array, negative + + a = array([-5.0, 0.0, 1.0]) + b = negative(a) + for i in range(3): + assert b[i] == -a[i] + + a = array([-5.0, 1.0]) + b = negative(a) + a[0] = 5.0 + assert b[0] == 5.0 + + def test_abs(self): + from numpy import array, absolute + + a = array([-5.0, -0.0, 1.0]) + b = absolute(a) + for i in range(3): + assert b[i] == abs(a[i]) + + def test_minimum(self): + from numpy import array, minimum + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = minimum(a, b) + for i in range(3): + assert c[i] == min(a[i], b[i]) + + def test_maximum(self): + from numpy import array, maximum + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = maximum(a, b) + for i in range(3): + assert c[i] == max(a[i], b[i]) + + def test_sign(self): + from numpy import array, sign + + reference = [-1.0, 0.0, 0.0, 1.0] + a = array([-5.0, -0.0, 0.0, 6.0]) + b = sign(a) + for i in range(4): + assert b[i] == reference[i] + + def test_reciporocal(self): + from numpy import array, reciprocal + + reference = [-0.2, float("inf"), float("-inf"), 2.0] + a = array([-5.0, 0.0, -0.0, 0.5]) + b = reciprocal(a) + for i in range(4): + assert b[i] == reference[i] + + def test_copysign(self): + from numpy import array, copysign + + reference = [5.0, -0.0, 0.0, -6.0] + a = array([-5.0, 0.0, 0.0, 6.0]) + b = array([5.0, -0.0, 3.0, -6.0]) + c = copysign(a, b) + for i in range(4): + assert c[i] == reference[i] + + def test_exp(self): + import math + from numpy import array, exp + + a = array([-5.0, -0.0, 0.0, 12345678.0, float("inf"), + -float('inf'), -12343424.0]) + b = exp(a) + for i in range(4): + try: + res = math.exp(a[i]) + except OverflowError: + res = float('inf') + assert b[i] == res diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -0,0 +1,94 @@ +from pypy.jit.metainterp.test.support import LLJitMixin +from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, + FloatWrapper, Call1, Call2, add, mul) +from pypy.module.micronumpy.interp_ufuncs import negative + + +class FakeSpace(object): + pass + +class TestNumpyJIt(LLJitMixin): + def setup_class(cls): + cls.space = FakeSpace() + + def test_add(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + v = Call2(add, ar, ar, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + + def test_floatadd(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + v = Call2(add, ar, FloatWrapper(4.5), Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 1, "float_add": 1, + "setarrayitem_raw": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_already_forecd(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + v1 = Call2(add, ar, FloatWrapper(4.5), Signature()) + v2 = Call2(mul, v1, FloatWrapper(4.5), Signature()) + v1.force_if_needed() + return v2.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + # This is the sum of the ops for both loops, however if you remove the + # optimization then you end up with 2 float_adds, so we can still be + # sure it was optimized correctly. + self.check_loops({"getarrayitem_raw": 2, "float_mul": 1, "float_add": 1, + "setarrayitem_raw": 2, "int_add": 2, + "int_lt": 2, "guard_true": 2, "jump": 2}) + assert result == f(5) + + def test_ufunc(self): + space = self.space + def f(i): + ar = SingleDimArray(i) + v1 = Call2(add, ar, ar, Signature()) + v2 = negative(space, v1) + return v2.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "float_neg": 1, + "setarrayitem_raw": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1, + }) + assert result == f(5) + + def test_appropriate_specialization(self): + space = self.space + def f(i): + add_sig = Signature() + mul_sig = Signature() + ar = SingleDimArray(i) + + v1 = Call2(add, ar, ar, ar.signature.transition(add_sig)) + v2 = negative(space, v1) + v2.get_concrete() + + for i in xrange(5): + v1 = Call2(mul, ar, ar, ar.signature.transition(mul_sig)) + v2 = negative(space, v1) + v2.get_concrete() + + self.meta_interp(f, [5], listops=True, backendopt=True) + # This is 3, not 2 because there is a bridge for the exit. + self.check_loop_count(3) \ No newline at end of file diff --git a/pypy/module/micronumpy/ufunc.py b/pypy/module/micronumpy/ufunc.py deleted file mode 100644 --- a/pypy/module/micronumpy/ufunc.py +++ /dev/null @@ -1,21 +0,0 @@ - -from numarray import NumArray -from pypy.interpreter.baseobjspace import ObjSpace, W_Root -from pypy.interpreter.error import OperationError - -def minimum(space, w_a, w_b): - if not isinstance(w_a, NumArray) or not isinstance(w_b, NumArray): - raise OperationError(space.w_TypeError, - space.wrap("expecting NumArrat object")) - if w_a.dim != w_b.dim: - raise OperationError(space.w_ValueError, - space.wrap("minimum of arrays of different length")) - res = NumArray(space, w_a.dim, 'i') - for i in range(len(w_a.storage)): - one = w_a.storage[i] - two = w_b.storage[i] - if one < two: - res.storage[i] = one - else: - res.storage[i] = two - return space.wrap(res) diff --git a/pypy/module/oracle/__init__.py b/pypy/module/oracle/__init__.py --- a/pypy/module/oracle/__init__.py +++ b/pypy/module/oracle/__init__.py @@ -28,6 +28,7 @@ appleveldefs = { 'version': 'app_oracle.version', + 'paramstyle': 'app_oracle.paramstyle', 'makedsn': 'app_oracle.makedsn', 'TimestampFromTicks': 'app_oracle.TimestampFromTicks', } diff --git a/pypy/module/oracle/app_oracle.py b/pypy/module/oracle/app_oracle.py --- a/pypy/module/oracle/app_oracle.py +++ b/pypy/module/oracle/app_oracle.py @@ -1,4 +1,5 @@ version = '5.0.0' +paramstyle = 'named' class Warning(StandardError): pass diff --git a/pypy/module/oracle/config.py b/pypy/module/oracle/config.py --- a/pypy/module/oracle/config.py +++ b/pypy/module/oracle/config.py @@ -16,6 +16,7 @@ return space.str_w(w_obj) def w_string(space, buf, len=-1): + #assert type(len) is int if len < 0: return space.wrap(rffi.charp2str(buf)) else: diff --git a/pypy/module/oracle/interp_connect.py b/pypy/module/oracle/interp_connect.py --- a/pypy/module/oracle/interp_connect.py +++ b/pypy/module/oracle/interp_connect.py @@ -159,9 +159,20 @@ # set the internal and external names; these are needed for global # transactions but are limited in terms of the lengths of the strings if twophase: - raise OperationError( - interp_error.get(space).w_NotSupportedError, - space.wrap("XXX write me")) + status = roci.OCIAttrSet( + self.serverHandle, roci.OCI_HTYPE_SERVER, + "cx_Oracle", 0, + roci.OCI_ATTR_INTERNAL_NAME, + self.environment.errorHandle) + self.environment.checkForError( + status, "Connection_Connect(): set internal name") + status = roci.OCIAttrSet( + self.serverHandle, roci.OCI_HTYPE_SERVER, + "cx_Oracle", 0, + roci.OCI_ATTR_EXTERNAL_NAME, + self.environment.errorHandle) + self.environment.checkForError( + status, "Connection_Connect(): set external name") # allocate the session handle handleptr = lltype.malloc(rffi.CArrayPtr(roci.OCISession).TO, @@ -371,6 +382,7 @@ finally: stringBuffer.clear() lltype.free(foundptr, flavor='raw') + lltype.free(handleptr, flavor='raw') # eliminate the authorization handle immediately, if applicable if authInfo: diff --git a/pypy/module/oracle/interp_cursor.py b/pypy/module/oracle/interp_cursor.py --- a/pypy/module/oracle/interp_cursor.py +++ b/pypy/module/oracle/interp_cursor.py @@ -459,7 +459,7 @@ self.environment.checkForError( status, "Cursor_ItemDescription(): name") - name = rffi.charpsize2str(nameptr[0], lenptr[0]) + name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0])) finally: lltype.free(nameptr, flavor='raw') lltype.free(lenptr, flavor='raw') diff --git a/pypy/module/oracle/interp_object.py b/pypy/module/oracle/interp_object.py --- a/pypy/module/oracle/interp_object.py +++ b/pypy/module/oracle/interp_object.py @@ -38,7 +38,7 @@ self.environment.checkForError( status, "ObjectType_Initialize(): get schema name") - self.schema = rffi.charpsize2str(nameptr[0], lenptr[0]) + self.schema = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0])) # determine the name of the type status = roci.OCIAttrGet( @@ -50,7 +50,7 @@ self.environment.checkForError( status, "ObjectType_Initialize(): get schema name") - self.name = rffi.charpsize2str(nameptr[0], lenptr[0]) + self.name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0])) finally: lltype.free(nameptr, flavor='raw') lltype.free(lenptr, flavor='raw') @@ -301,7 +301,7 @@ connection.environment.checkForError( status, "ObjectAttribute_Initialize(): get name") - self.name = rffi.charpsize2str(nameptr[0], lenptr[0]) + self.name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0])) finally: lltype.free(nameptr, flavor='raw') lltype.free(lenptr, flavor='raw') @@ -428,7 +428,7 @@ strValue = rffi.cast(roci.Ptr(roci.OCIString), value)[0] ptr = roci.OCIStringPtr(environment.handle, strValue) size = roci.OCIStringSize(environment.handle, strValue) - return config.w_string(space, ptr, size) + return config.w_string(space, ptr, rffi.cast(lltype.Signed, size)) elif typeCode == roci.OCI_TYPECODE_NUMBER: return transform.OracleNumberToPythonFloat( environment, diff --git a/pypy/module/oracle/interp_pool.py b/pypy/module/oracle/interp_pool.py --- a/pypy/module/oracle/interp_pool.py +++ b/pypy/module/oracle/interp_pool.py @@ -100,11 +100,13 @@ status, "SessionPool_New(): create pool") self.w_name = config.w_string(space, poolnameptr[0], - poolnamelenptr[0]) + rffi.cast(lltype.Signed, poolnamelenptr[0])) finally: user_buf.clear() password_buf.clear() dsn_buf.clear() + lltype.free(poolnameptr, flavor='raw') + lltype.free(poolnamelenptr, flavor='raw') return space.wrap(self) @@ -128,10 +130,19 @@ self.checkConnected(space) + if __args__.keywords: + keywords = __args__.keywords + ["pool"] + else: + keywords = ["pool"] + if __args__.keywords_w: + keywords_w = __args__.keywords_w + [space.wrap(self)] + else: + keywords_w = [space.wrap(self)] + newargs = Arguments(space, __args__.arguments_w, - __args__.keywords + ["pool"], - __args__.keywords_w + [space.wrap(self)]) + keywords, + keywords_w) return space.call_args(self.w_connectionType, newargs) def release(self, space, w_connection): diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -279,6 +279,7 @@ self.actualLength, self.returnCode, allocatedElements, actualElementsPtr, roci.OCI_DEFAULT) + nameBuffer.clear() else: status = roci.OCIBindByPos( self.boundCursorHandle, bindHandlePtr, @@ -601,6 +602,7 @@ def getValueProc(self, space, pos): ptr = rffi.ptradd(self.data, pos * self.bufferSize) length = rffi.cast(roci.Ptr(roci.ub4), ptr)[0] + length = rffi.cast(lltype.Signed, length) ptr = rffi.ptradd(ptr, rffi.sizeof(roci.ub4)) return space.wrap(rffi.charpsize2str(ptr, length)) @@ -732,6 +734,7 @@ finally: rffi.keep_buffer_alive_until_here(textbuf, text) lltype.free(sizeptr, flavor='raw') + format_buf.clear() if isinstance(self, VT_NumberAsString): return w_strvalue @@ -778,6 +781,8 @@ format_buf.ptr, format_buf.size, None, 0, dataptr) + text_buf.clear() + format_buf.clear() self.environment.checkForError( status, "NumberVar_SetValue(): from long") return @@ -810,6 +815,8 @@ format_buf.ptr, format_buf.size, nls_params, len(nls_params), dataptr) + text_buf.clear() + format_buf.clear() self.environment.checkForError( status, "NumberVar_SetValue(): from decimal") return diff --git a/pypy/module/oracle/roci.py b/pypy/module/oracle/roci.py --- a/pypy/module/oracle/roci.py +++ b/pypy/module/oracle/roci.py @@ -73,7 +73,8 @@ defines = ''' OCI_ATTR_SERVER OCI_ATTR_SESSION OCI_ATTR_USERNAME OCI_ATTR_PASSWORD OCI_ATTR_STMT_TYPE OCI_ATTR_PARAM OCI_ATTR_PARAM_COUNT OCI_ATTR_ROW_COUNT - OCI_ATTR_NAME OCI_ATTR_SCALE OCI_ATTR_PRECISION OCI_ATTR_IS_NULL + OCI_ATTR_NAME OCI_ATTR_INTERNAL_NAME OCI_ATTR_EXTERNAL_NAME + OCI_ATTR_SCALE OCI_ATTR_PRECISION OCI_ATTR_IS_NULL OCI_ATTR_DATA_SIZE OCI_ATTR_DATA_TYPE OCI_ATTR_REF_TDO OCI_ATTR_SCHEMA_NAME OCI_ATTR_TYPE_NAME OCI_ATTR_TYPECODE OCI_ATTR_NUM_TYPE_ATTRS OCI_ATTR_LIST_TYPE_ATTRS diff --git a/pypy/module/oracle/test/test_connect.py b/pypy/module/oracle/test/test_connect.py --- a/pypy/module/oracle/test/test_connect.py +++ b/pypy/module/oracle/test/test_connect.py @@ -41,6 +41,10 @@ if hasattr(self, 'cnx'): self.cnx.close() + def test_constants(self): + assert '.' in oracle.version + assert oracle.paramstyle == 'named' + def test_connect(self): self.cnx = oracle.connect(self.username, self.password, self.tnsentry, threaded=True) @@ -49,6 +53,13 @@ assert self.cnx.tnsentry == self.tnsentry assert isinstance(self.cnx.version, str) + def test_connect_twophase(self): + self.cnx = oracle.connect(self.username, self.password, + self.tnsentry, twophase=True) + assert self.cnx.username == self.username + assert self.cnx.password == self.password + assert self.cnx.tnsentry == self.tnsentry + def test_singleArg(self): self.cnx = oracle.connect("%s/%s@%s" % (self.username, self.password, self.tnsentry)) diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -7,13 +7,15 @@ interpleveldefs = { 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', + 'set_compile_hook': 'interp_jit.set_compile_hook', } def setup_after_space_initialization(self): # force the __extend__ hacks to occur early - import pypy.module.pypyjit.interp_jit + from pypy.module.pypyjit.interp_jit import pypyjitdriver # add the 'defaults' attribute from pypy.rlib.jit import PARAMETERS space = self.space + pypyjitdriver.space = space w_obj = space.wrap(PARAMETERS) space.setattr(space.wrap(self), space.wrap('defaults'), w_obj) diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -12,6 +12,8 @@ from pypy.interpreter.pycode import PyCode, CO_GENERATOR from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pyopcode import ExitFrame +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap from pypy.rlib.objectmodel import we_are_translated @@ -49,13 +51,43 @@ greens = ['next_instr', 'is_being_profiled', 'pycode'] virtualizables = ['frame'] -## def compute_invariants(self, reds, next_instr, pycode): -## # compute the information that really only depends on next_instr -## # and pycode -## frame = reds.frame -## valuestackdepth = frame.valuestackdepth -## blockstack = frame.blockstack -## return (valuestackdepth, blockstack) + def on_compile(self, logger, looptoken, operations, type, next_instr, + is_being_profiled, ll_pycode): + from pypy.rpython.annlowlevel import cast_base_ptr_to_instance + + space = self.space + cache = space.fromcache(Cache) + if space.is_true(cache.w_compile_hook): + memo = {} + list_w = [space.wrap(logger.repr_of_resop(memo, op)) + for op in operations] + pycode = cast_base_ptr_to_instance(PyCode, ll_pycode) + try: + space.call_function(cache.w_compile_hook, + space.wrap('main'), + space.wrap(type), + space.newtuple([pycode, + space.wrap(next_instr), + space.wrap(is_being_profiled)]), + space.newlist(list_w)) + except OperationError, e: + e.write_unraisable(space, "jit hook ", cache.w_compile_hook) + + def on_compile_bridge(self, logger, orig_looptoken, operations, n): + space = self.space + cache = space.fromcache(Cache) + if space.is_true(cache.w_compile_hook): + memo = {} + list_w = [space.wrap(logger.repr_of_resop(memo, op)) + for op in operations] + try: + space.call_function(cache.w_compile_hook, + space.wrap('main'), + space.wrap('bridge'), + space.wrap(n), + space.newlist(list_w)) + except OperationError, e: + e.write_unraisable(space, "jit hook ", cache.w_compile_hook) pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location, get_jitcell_at = get_jitcell_at, @@ -157,3 +189,28 @@ '''For testing. Invokes callable(...), but without letting the JIT follow the call.''' return space.call_args(w_callable, __args__) + +class Cache(object): + def __init__(self, space): + self.w_compile_hook = space.w_None + + at unwrap_spec(ObjSpace, W_Root) +def set_compile_hook(space, w_hook): + """ set_compile_hook(hook) + + Set a compiling hook that will be called each time a loop is compiled. + The hook will be called with the following signature: + hook(merge_point_type, loop_type, greenkey or guard_number, operations) + + for now merge point type is always `main` + + loop_type can be either `loop` `entry_bridge` or `bridge` + in case loop is not `bridge`, greenkey will be a set of constants + for jit merge point. in case it's `main` it'll be a tuple + (code, offset, is_being_profiled) + + XXX write down what else + """ + cache = space.fromcache(Cache) + cache.w_compile_hook = w_hook + return space.w_None diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,7 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof']: + 'posix', '_socket', '_sre', '_lsprof', '_weakref']: return True return False diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -0,0 +1,89 @@ + +import py +from pypy.conftest import gettestobjspace, option +from pypy.interpreter.pycode import PyCode +from pypy.interpreter.gateway import interp2app +from pypy.jit.metainterp.history import LoopToken +from pypy.jit.metainterp.resoperation import ResOperation, rop +from pypy.jit.metainterp.logger import Logger +from pypy.rpython.annlowlevel import (cast_instance_to_base_ptr, + cast_base_ptr_to_instance) +from pypy.module.pypyjit.interp_jit import pypyjitdriver +from pypy.jit.tool.oparser import parse +from pypy.jit.metainterp.typesystem import llhelper + +class MockSD(object): + class cpu: + ts = llhelper + +class AppTestJitHook(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("Can't run this test with -A") + space = gettestobjspace(usemodules=('pypyjit',)) + cls.space = space + w_f = space.appexec([], """(): + def f(): + pass + return f + """) + ll_code = cast_instance_to_base_ptr(w_f.code) + logger = Logger(MockSD()) + + oplist = parse(""" + [i1, i2] + i3 = int_add(i1, i2) + guard_true(i3) [] + """).operations + + def interp_on_compile(): + pypyjitdriver.on_compile(logger, LoopToken(), oplist, 'loop', + 0, False, ll_code) + + def interp_on_compile_bridge(): + pypyjitdriver.on_compile_bridge(logger, LoopToken(), oplist, 0) + + cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) + cls.w_on_compile_bridge = space.wrap(interp2app(interp_on_compile_bridge)) + + def test_on_compile(self): + import pypyjit + all = [] + + def hook(*args): + assert args[0] == 'main' + assert args[1] in ['loop', 'bridge'] + all.append(args[2:]) + + self.on_compile() + pypyjit.set_compile_hook(hook) + assert not all + self.on_compile() + assert len(all) == 1 + assert all[0][0][0].co_name == 'f' + assert all[0][0][1] == 0 + assert all[0][0][2] == False + assert len(all[0][1]) == 2 + assert 'int_add' in all[0][1][0] + self.on_compile_bridge() + assert len(all) == 2 + pypyjit.set_compile_hook(None) + self.on_compile() + assert len(all) == 2 + + def test_on_compile_exception(self): + import pypyjit, sys, cStringIO + + def hook(*args): + 1/0 + + pypyjit.set_compile_hook(hook) + s = cStringIO.StringIO() + prev = sys.stderr + sys.stderr = s + try: + self.on_compile() + finally: + sys.stderr = prev + assert 'jit hook' in s.getvalue() + assert 'ZeroDivisionError' in s.getvalue() diff --git a/pypy/module/pypyjit/test_pypy_c/test_model.py b/pypy/module/pypyjit/test_pypy_c/test_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_model.py @@ -20,7 +20,7 @@ def setup_method(self, meth): self.filepath = self.tmpdir.join(meth.im_func.func_name + '.py') - def run(self, func_or_src, args=[], **jitopts): + def run(self, func_or_src, args=[], import_site=False, **jitopts): src = py.code.Source(func_or_src) if isinstance(func_or_src, types.FunctionType): funcname = func_or_src.func_name @@ -39,7 +39,9 @@ # run a child pypy-c with logging enabled logfile = self.filepath.new(ext='.log') # - cmdline = [sys.executable, '-S'] + cmdline = [sys.executable] + if not import_site: + cmdline.append('-S') for key, value in jitopts.iteritems(): cmdline += ['--jit', '%s=%s' % (key, value)] cmdline.append(str(self.filepath)) @@ -465,7 +467,7 @@ j = ntohs(1) # ID: ntohs a = 0 return i - log = self.run(f) + log = self.run(f, import_site=True) loop, = log.loops_by_id('ntohs') assert loop.match_by_id('ntohs', """ guard_not_invalidated(descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py --- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py +++ b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py @@ -270,9 +270,8 @@ i17 = int_add_ovf(i8, 1) guard_no_overflow(descr=) i18 = force_token() - i20 = int_sub(i17, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i20, p7, i17, i9, p10, p11, p12, descr=) + jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) """) def test_default_and_kw(self): @@ -481,10 +480,14 @@ assert log.result == (1000, 998) loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('append', """ - p14 = new_with_vtable(ConstClass(W_IntObject)) - setfield_gc(p14, i12, descr=) - call(ConstClass(ll_append__listPtr_objectPtr), p8, p14, descr=...) + i13 = getfield_gc(p8, descr=) + i15 = int_add(i13, 1) + call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) guard_no_exception(descr=) + p17 = getfield_gc(p8, descr=) + p19 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p19, i12, descr=) + setarrayitem_gc(p17, i13, p19, descr=) """) def test_range_iter(self): @@ -1676,3 +1679,55 @@ loop, = log.loops_by_filename(self.filepath) import pdb;pdb.set_trace() assert loop.match_by_id('div', "") # optimized away + + def test_oldstyle_newstyle_mix(self): + def main(): + class A: + pass + + class B(object, A): + def __init__(self, x): + self.x = x + + i = 0 + b = B(1) + while i < 100: + v = b.x # ID: loadattr + i += v + return i + + log = self.run(main, [], threshold=80) + loop, = log.loops_by_filename(self.filepath) + loop.match_by_id('loadattr', + ''' + guard_not_invalidated(descr=...) + i19 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) + guard_no_exception(descr=...) + i21 = int_and(i19, _) + i22 = int_is_true(i21) + guard_true(i22, descr=...) + i26 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) + guard_no_exception(descr=...) + i28 = int_and(i26, _) + i29 = int_is_true(i28) + guard_true(i29, descr=...) + ''') + + def test_python_contains(self): + def main(): + class A(object): + def __contains__(self, v): + return True + + i = 0 + a = A() + while i < 100: + i += i in a # ID: contains + + log = self.run(main, [], threshold=80) + loop, = log.loops_by_filename(self.filemath) + # XXX: haven't confirmed his is correct, it's probably missing a + # few instructions + loop.match_by_id("contains", """ + i1 = int_add(i0, 1) + """) diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -150,7 +150,7 @@ if operror is None: return space.w_None else: - return space.wrap(operror.application_traceback) + return space.wrap(operror.get_traceback()) return None def get_w_default_encoder(self): diff --git a/pypy/module/sys/interp_encoding.py b/pypy/module/sys/interp_encoding.py --- a/pypy/module/sys/interp_encoding.py +++ b/pypy/module/sys/interp_encoding.py @@ -43,16 +43,21 @@ # encoding = base_encoding if rlocale.HAVE_LANGINFO and rlocale.CODESET: - oldlocale = rlocale.setlocale(rlocale.LC_CTYPE, None) - rlocale.setlocale(rlocale.LC_CTYPE, "") - loc_codeset = rlocale.nl_langinfo(rlocale.CODESET) - if loc_codeset: - codecmod = space.getbuiltinmodule('_codecs') - w_res = space.call_function(space.getattr(codecmod, - space.wrap('lookup')), - space.wrap(loc_codeset)) - if space.is_true(w_res): - encoding = loc_codeset + try: + oldlocale = rlocale.setlocale(rlocale.LC_CTYPE, None) + rlocale.setlocale(rlocale.LC_CTYPE, "") + try: + loc_codeset = rlocale.nl_langinfo(rlocale.CODESET) + if loc_codeset: + codecmod = space.getbuiltinmodule('_codecs') + w_res = space.call_method(codecmod, 'lookup', + space.wrap(loc_codeset)) + if space.is_true(w_res): + encoding = loc_codeset + finally: + rlocale.setlocale(rlocale.LC_CTYPE, oldlocale) + except rlocale.LocaleError: + pass return encoding def getfilesystemencoding(space): diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -40,24 +40,24 @@ break depth -= 1 f = ec.getnextframe_nohidden(f) + f.mark_as_escaped() return space.wrap(f) def setrecursionlimit(space, w_new_limit): - """setrecursionlimit() is ignored (and not needed) on PyPy. - -On CPython it would set the maximum number of nested calls that can -occur before a RuntimeError is raised. On PyPy overflowing the stack -also causes RuntimeErrors, but the limit is checked at a lower level. -(The limit is currenty hard-coded at 768 KB, corresponding to roughly -1480 Python calls on Linux.)""" + """setrecursionlimit() sets the maximum number of nested calls that +can occur before a RuntimeError is raised. On PyPy the limit is +approximative and checked at a lower level. The default 1000 +reserves 768KB of stack space, which should suffice (on Linux, +depending on the compiler settings) for ~1400 calls. Setting the +value to N reserves N/1000 times 768KB of stack space. +""" + from pypy.rlib.rstack import _stack_set_length_fraction new_limit = space.int_w(w_new_limit) if new_limit <= 0: raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) - # for now, don't rewrite a warning but silently ignore the - # recursion limit. - #space.warn('setrecursionlimit() is ignored (and not needed) on PyPy', space.w_RuntimeWarning) space.sys.recursionlimit = new_limit + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). @@ -91,7 +91,7 @@ return space.newtuple([space.w_None,space.w_None,space.w_None]) else: return space.newtuple([operror.w_type, operror.get_w_value(space), - space.wrap(operror.application_traceback)]) + space.wrap(operror.get_traceback())]) def exc_clear(space): """Clear global information on the current exception. Subsequent calls diff --git a/pypy/module/test_lib_pypy/test_stackless.py b/pypy/module/test_lib_pypy/test_stackless.py --- a/pypy/module/test_lib_pypy/test_stackless.py +++ b/pypy/module/test_lib_pypy/test_stackless.py @@ -8,15 +8,12 @@ space = gettestobjspace(usemodules=('_stackless', '_socket')) cls.space = space # cannot test the unpickle part on top of py.py - cls.w_can_unpickle = space.wrap(bool(option.runappdirect)) def test_pickle(self): import new, sys mod = new.module('mod') sys.modules['mod'] = mod - mod.can_unpickle = self.can_unpickle - mod.skip = skip try: exec ''' import pickle, sys @@ -45,8 +42,6 @@ t = stackless.tasklet(demo)(lev) stackless.run() assert seen == range(1, lev+1) + range(lev, 0, -1) -if not can_unpickle: - skip("cannot test the unpickling part on top of py.py") print "now running the clone" tt = pickle.loads(blob) tt.insert() @@ -64,8 +59,6 @@ mod = new.module('mod') sys.modules['mod'] = mod - mod.can_unpickle = self.can_unpickle - mod.skip = skip try: exec ''' import pickle, sys diff --git a/pypy/module/test_lib_pypy/test_tputil.py b/pypy/module/test_lib_pypy/test_tputil.py --- a/pypy/module/test_lib_pypy/test_tputil.py +++ b/pypy/module/test_lib_pypy/test_tputil.py @@ -28,9 +28,9 @@ from tputil import make_proxy l = [] tp = make_proxy(l.append, type=list) - x = len(tp) + x = tp[0:1] assert len(l) == 1 - assert l[0].opname == '__len__' + assert l[0].opname == '__getslice__' def test_simple(self): from tputil import make_proxy diff --git a/pypy/module/zipimport/test/test_zipimport.py b/pypy/module/zipimport/test/test_zipimport.py --- a/pypy/module/zipimport/test/test_zipimport.py +++ b/pypy/module/zipimport/test/test_zipimport.py @@ -1,7 +1,7 @@ from pypy.conftest import gettestobjspace import marshal -import py +import py, os import time import struct from pypy.module.imp.importing import get_pyc_magic, _w_long @@ -15,6 +15,7 @@ cpy's regression tests """ compression = ZIP_STORED + pathsep = '/' def make_pyc(cls, space, co, mtime): data = marshal.dumps(co) @@ -57,6 +58,7 @@ test_pyc = cls.make_pyc(space, co, now) cls.w_test_pyc = space.wrap(test_pyc) cls.w_compression = space.wrap(cls.compression) + cls.w_pathsep = space.wrap(cls.pathsep) #ziptestmodule = tmpdir.ensure('ziptestmodule.zip').write( ziptestmodule = tmpdir.join("somezip.zip") cls.w_tmpzip = space.wrap(str(ziptestmodule)) @@ -100,6 +102,7 @@ from zipfile import ZipFile, ZipInfo z = ZipFile(self.zipfile, 'w') write_files = self.write_files + filename = filename.replace('/', self.pathsep) write_files.append((filename, data)) for filename, data in write_files: zinfo = ZipInfo(filename, time.localtime(self.now)) @@ -121,6 +124,7 @@ del _zip_directory_cache[self.zipfile] def test_cache_subdir(self): + import os self.writefile('x.py', '') self.writefile('sub/__init__.py', '') self.writefile('sub/yy.py', '') @@ -130,7 +134,7 @@ assert main_importer is not sub_importer assert main_importer.prefix == "" - assert sub_importer.prefix == "sub/" + assert sub_importer.prefix == "sub" + os.path.sep def test_good_bad_arguments(self): from zipimport import zipimporter @@ -262,7 +266,7 @@ import zipimport data = "saddsadsa" self.writefile("xxx", data) - self.writefile("xx"+os.sep+"__init__.py", "5") + self.writefile("xx/__init__.py", "5") self.writefile("yy.py", "3") self.writefile('uu.pyc', self.test_pyc) z = zipimport.zipimporter(self.zipfile) @@ -287,8 +291,7 @@ """ import os import zipimport - self.writefile( - os.sep.join(("directory", "package", "__init__.py")), "") + self.writefile("directory/package/__init__.py", "") importer = zipimport.zipimporter(self.zipfile + "/directory") # Grab this so if the assertion fails, py.test will display its # value. Not sure why it doesn't the assertion uses import.archive @@ -296,15 +299,14 @@ archive = importer.archive realprefix = importer.prefix allbutlast = self.zipfile.split(os.path.sep)[:-1] - prefix = 'directory/' + prefix = 'directory' + os.path.sep assert archive == self.zipfile assert realprefix == prefix def test_subdirectory_importer(self): import os import zipimport - self.writefile( - os.sep.join(("directory", "package", "__init__.py")), "") + self.writefile("directory/package/__init__.py", "") z = zipimport.zipimporter(self.zipfile + "/directory") mod = z.load_module("package") assert z.is_package("package") @@ -313,14 +315,9 @@ def test_subdirectory_twice(self): import os, zipimport - self.writefile( - os.sep.join(("package", "__init__.py")), "") - self.writefile( - os.sep.join(("package", "subpackage", - "__init__.py")), "") - self.writefile( - os.sep.join(("package", "subpackage", - "foo.py")), "") + self.writefile("package/__init__.py", "") + self.writefile("package/subpackage/__init__.py", "") + self.writefile("package/subpackage/foo.py", "") import sys print sys.path mod = __import__('package.subpackage.foo', None, None, []) @@ -331,8 +328,7 @@ """ import os import zipimport - self.writefile( - os.sep.join(("directory", "package", "__init__.py")), "") + self.writefile("directory/package/__init__.py", "") importer = zipimport.zipimporter(self.zipfile + "/directory") l = [i for i in zipimport._zip_directory_cache] assert len(l) @@ -370,3 +366,8 @@ except ImportError: py.test.skip("zlib not available, cannot test compressed zipfiles") cls.make_class() + + +if os.sep != '/': + class AppTestNativePathSep(AppTestZipimport): + pathsep = os.sep diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -207,34 +207,51 @@ return space.get_and_call_function(w_descr, w_obj, w_name) def is_true(space, w_obj): - w_descr = space.lookup(w_obj, '__nonzero__') + method = "__nonzero__" + w_descr = space.lookup(w_obj, method) if w_descr is None: - w_descr = space.lookup(w_obj, '__len__') + method = "__len__" + w_descr = space.lookup(w_obj, method) if w_descr is None: return True w_res = space.get_and_call_function(w_descr, w_obj) # more shortcuts for common cases - if w_res is space.w_False: + if space.is_w(w_res, space.w_False): return False - if w_res is space.w_True: + if space.is_w(w_res, space.w_True): return True w_restype = space.type(w_res) - if (space.is_w(w_restype, space.w_bool) or - space.is_w(w_restype, space.w_int)): + # Note there is no check for bool here because the only possible + # instances of bool are w_False and w_True, which are checked above. + if (space.is_w(w_restype, space.w_int) or + space.is_w(w_restype, space.w_long)): return space.int_w(w_res) != 0 else: - raise OperationError(space.w_TypeError, - space.wrap('__nonzero__ should return ' - 'bool or int')) + msg = "%s should return bool or integer" % (method,) + raise OperationError(space.w_TypeError, space.wrap(msg)) - def nonzero(self, w_obj): - if self.is_true(w_obj): - return self.w_True + def nonzero(space, w_obj): + if space.is_true(w_obj): + return space.w_True else: - return self.w_False + return space.w_False -## def len(self, w_obj): -## XXX needs to check that the result is an int (or long?) >= 0 + def len(space, w_obj): + w_descr = space.lookup(w_obj, '__len__') + if w_descr is None: + name = space.type(w_obj).getname(space) + msg = "'%s' has no length" % (name,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_res = space.get_and_call_function(w_descr, w_obj) + space._check_len_result(w_res) + return w_res + + def _check_len_result(space, w_obj): + # Will complain if result is too big. + result = space.int_w(w_obj) + if result < 0: + raise OperationError(space.w_ValueError, + space.wrap("__len__() should return >= 0")) def iter(space, w_obj): w_descr = space.lookup(w_obj, '__iter__') @@ -376,6 +393,9 @@ w_descr = space.lookup(w_container, '__contains__') if w_descr is not None: return space.get_and_call_function(w_descr, w_container, w_item) + return space._contains(w_container, w_item) + + def _contains(space, w_container, w_item): w_iter = space.iter(w_container) while 1: try: diff --git a/pypy/objspace/std/callmethod.py b/pypy/objspace/std/callmethod.py --- a/pypy/objspace/std/callmethod.py +++ b/pypy/objspace/std/callmethod.py @@ -12,7 +12,7 @@ from pypy.interpreter import function from pypy.objspace.descroperation import object_getattribute -from pypy.rlib import jit, rstack # for resume points +from pypy.rlib import jit from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict, \ LOOKUP_METHOD_mapdict_fill_cache_method @@ -51,6 +51,7 @@ # this handles directly the common case # module.function(args..) w_value = w_obj.getdictvalue(space, name) + # xxx we could also use the mapdict cache in that case, probably else: typ = type(w_descr) if typ is function.Function or typ is function.FunctionWithFixedCode: @@ -64,7 +65,7 @@ not jit.we_are_jitted()): # let mapdict cache stuff LOOKUP_METHOD_mapdict_fill_cache_method( - f.getcode(), nameindex, w_obj, w_type, w_descr) + space, f.getcode(), name, nameindex, w_obj, w_type) return if w_value is None: w_value = space.getattr(w_obj, w_name) @@ -83,7 +84,6 @@ w_callable = f.peekvalue(n_args + (2 * n_kwargs) + 1) try: w_result = f.space.call_valuestack(w_callable, n, f) - rstack.resume_point("CALL_METHOD", f, n_args, returns=w_result) finally: f.dropvalues(n_args + 2) else: @@ -108,7 +108,6 @@ w_result = f.space.call_args_and_c_profile(f, w_callable, args) else: w_result = f.space.call_args(w_callable, args) - rstack.resume_point("CALL_METHOD_KW", f, returns=w_result) f.pushvalue(w_result) diff --git a/pypy/objspace/std/floattype.py b/pypy/objspace/std/floattype.py --- a/pypy/objspace/std/floattype.py +++ b/pypy/objspace/std/floattype.py @@ -14,10 +14,8 @@ float_as_integer_ratio = SMM("as_integer_ratio", 1) float_hex = SMM("hex", 1) -float_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any float.") - -def float_conjugate__ANY(space, w_float): - return space.pos(w_float) +def descr_conjugate(space, w_float): + return space.float(w_float) register_all(vars(), globals()) @@ -168,10 +166,10 @@ if total_digits > min(const_one, const_two) // 4: raise OperationError(space.w_ValueError, space.wrap("way too long")) if i < length and (s[i] == "p" or s[i] == "P"): + i += 1 if i == length: raise OperationError(space.w_ValueError, space.wrap("invalid hex string")) - i += 1 exp_sign = 1 if s[i] == "-" or s[i] == "+": if s[i] == "-": @@ -264,7 +262,7 @@ return space.call_function(w_cls, w_float) def descr_get_real(space, w_obj): - return w_obj + return space.float(w_obj) def descr_get_imag(space, w_obj): return space.wrap(0.0) @@ -280,6 +278,7 @@ as_classmethod=True), fromhex = gateway.interp2app(descr_fromhex, as_classmethod=True), + conjugate = gateway.interp2app(descr_conjugate), real = typedef.GetSetProperty(descr_get_real), imag = typedef.GetSetProperty(descr_get_imag), ) diff --git a/pypy/objspace/std/inttype.py b/pypy/objspace/std/inttype.py --- a/pypy/objspace/std/inttype.py +++ b/pypy/objspace/std/inttype.py @@ -11,14 +11,19 @@ # ____________________________________________________________ -int_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any int.") +def descr_conjugate(space, w_int): + "Returns self, the complex conjugate of any int." + return space.int(w_int) -def int_conjugate__ANY(space, w_int): - return space.pos(w_int) +def descr_bit_length(space, w_int): + """int.bit_length() -> int -int_bit_length = SMM("bit_length", 1, doc="int.bit_length() -> int\n\nNumber of bits necessary to represent self in binary.\n>>> bin(37)\n'0b100101'\n>>> (37).bit_length()\n6") - -def int_bit_length__ANY(space, w_int): + Number of bits necessary to represent self in binary. + >>> bin(37) + '0b100101' + >>> (37).bit_length() + 6 + """ val = space.int_w(w_int) if val < 0: val = -val @@ -28,8 +33,6 @@ val >>= 1 return space.wrap(bits) -register_all(vars(), globals()) - def wrapint(space, x): if space.config.objspace.std.withsmallint: @@ -179,7 +182,7 @@ return space.wrap(1) def descr_get_real(space, w_obj): - return w_obj + return space.int(w_obj) def descr_get_imag(space, w_obj): return space.wrap(0) @@ -196,6 +199,8 @@ non-string. If the argument is outside the integer range a long object will be returned instead.''', __new__ = gateway.interp2app(descr__new__), + conjugate = gateway.interp2app(descr_conjugate), + bit_length = gateway.interp2app(descr_bit_length), numerator = typedef.GetSetProperty(descr_get_numerator), denominator = typedef.GetSetProperty(descr_get_denominator), real = typedef.GetSetProperty(descr_get_real), diff --git a/pypy/objspace/std/longtype.py b/pypy/objspace/std/longtype.py --- a/pypy/objspace/std/longtype.py +++ b/pypy/objspace/std/longtype.py @@ -4,12 +4,8 @@ from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from pypy.objspace.std.strutil import string_to_bigint, ParseStringError -long_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any long.") - -def long_conjugate__ANY(space, w_int): - return space.pos(w_int) - -register_all(vars(), globals()) +def descr_conjugate(space, w_int): + return space.long(w_int) def descr__new__(space, w_longtype, w_x=0, w_base=gateway.NoneNotWrapped): @@ -104,7 +100,7 @@ return space.newlong(1) def descr_get_real(space, w_obj): - return w_obj + return space.long(w_obj) def descr_get_imag(space, w_obj): return space.newlong(0) @@ -128,6 +124,7 @@ string, use the optional base. It is an error to supply a base when converting a non-string.''', __new__ = gateway.interp2app(descr__new__), + conjugate = gateway.interp2app(descr_conjugate), numerator = typedef.GetSetProperty(descr_get_numerator), denominator = typedef.GetSetProperty(descr_get_denominator), real = typedef.GetSetProperty(descr_get_real), diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -8,6 +8,7 @@ from pypy.objspace.std.dictmultiobject import IteratorImplementation from pypy.objspace.std.dictmultiobject import _is_sane_hash from pypy.objspace.std.objectobject import W_ObjectObject +from pypy.objspace.std.typeobject import TypeCell # ____________________________________________________________ # attribute shapes @@ -753,22 +754,40 @@ w_descr = w_type.getattribute_if_not_from_object() if w_descr is not None: return space._handle_getattribute(w_descr, w_obj, w_name) - version_tag = w_type.version_tag() if version_tag is not None: name = space.str_w(w_name) - w_descr = w_type.lookup(name) + # We need to care for obscure cases in which the w_descr is + # a TypeCell, which may change without changing the version_tag + assert space.config.objspace.std.withmethodcache + _, w_descr = w_type._pure_lookup_where_with_method_cache( + name, version_tag) + # selector = ("", INVALID) - if w_descr is not None and space.is_data_descr(w_descr): + if w_descr is None: + selector = (name, DICT) #common case: no such attr in the class + elif isinstance(w_descr, TypeCell): + pass # we have a TypeCell in the class: give up + elif space.is_data_descr(w_descr): + # we have a data descriptor, which means the dictionary value + # (if any) has no relevance. from pypy.interpreter.typedef import Member descr = space.interpclass_w(w_descr) - if isinstance(descr, Member): + if isinstance(descr, Member): # it is a slot -- easy case selector = ("slot", SLOTS_STARTING_FROM + descr.index) else: + # There is a non-data descriptor in the class. If there is + # also a dict attribute, use the latter, caching its position. + # If not, we loose. We could do better in this case too, + # but we don't care too much; the common case of a method + # invocation is handled by LOOKUP_METHOD_xxx below. selector = (name, DICT) + # if selector[1] != INVALID: index = map.index(selector) if index >= 0: + # Note that if map.terminator is a DevolvedDictTerminator, + # map.index() will always return -1 if selector[1]==DICT. _fill_cache(pycode, nameindex, map, version_tag, index) return w_obj._mapdict_read_storage(index) if space.config.objspace.std.withmethodcachecounter: @@ -788,11 +807,26 @@ return True return False -def LOOKUP_METHOD_mapdict_fill_cache_method(pycode, nameindex, w_obj, w_type, w_method): +def LOOKUP_METHOD_mapdict_fill_cache_method(space, pycode, name, nameindex, + w_obj, w_type): version_tag = w_type.version_tag() if version_tag is None: return map = w_obj._get_mapdict_map() - if map is None: + if map is None or isinstance(map.terminator, DevolvedDictTerminator): + return + # We know here that w_obj.getdictvalue(space, name) just returned None, + # so the 'name' is not in the instance. We repeat the lookup to find it + # in the class, this time taking care of the result: it can be either a + # quasi-constant class attribute, or actually a TypeCell --- which we + # must not cache. (It should not be None here, but you never know...) + assert space.config.objspace.std.withmethodcache + _, w_method = w_type._pure_lookup_where_with_method_cache(name, + version_tag) + if w_method is None or isinstance(w_method, TypeCell): return _fill_cache(pycode, nameindex, map, version_tag, -1, w_method) + +# XXX fix me: if a function contains a loop with both LOAD_ATTR and +# XXX LOOKUP_METHOD on the same attribute name, it keeps trashing and +# XXX rebuilding the cache diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -15,6 +15,7 @@ _registered_implementations.add(implcls) option_to_typename = { + "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"], "withsmallint" : ["smallintobject.W_SmallIntObject"], "withsmalllong" : ["smalllongobject.W_SmallLongObject"], "withstrslice" : ["strsliceobject.W_StringSliceObject"], @@ -71,6 +72,7 @@ from pypy.objspace.std import smallintobject from pypy.objspace.std import smalllongobject from pypy.objspace.std import tupleobject + from pypy.objspace.std import smalltupleobject from pypy.objspace.std import listobject from pypy.objspace.std import dictmultiobject from pypy.objspace.std import stringobject @@ -253,6 +255,9 @@ (listobject.W_ListObject, rangeobject.delegate_range2list), ] + if config.objspace.std.withsmalltuple: + self.typeorder[smalltupleobject.W_SmallTupleObject] += [ + (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)] # put W_Root everywhere self.typeorder[W_Root] = [] diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -266,6 +266,7 @@ return None def unwrap(self, w_obj): + """NOT_RPYTHON""" if isinstance(w_obj, Wrappable): return w_obj if isinstance(w_obj, model.W_Object): @@ -295,9 +296,10 @@ return newlong(self, val) def newtuple(self, list_w): + from pypy.objspace.std.tupletype import wraptuple assert isinstance(list_w, list) make_sure_not_resized(list_w) - return W_TupleObject(list_w) + return wraptuple(self, list_w) def newlist(self, list_w): return W_ListObject(list_w) diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/smalltupleobject.py @@ -0,0 +1,157 @@ +from pypy.interpreter.error import OperationError +from pypy.objspace.std.model import registerimplementation, W_Object +from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import intmask +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std import slicetype +from pypy.interpreter import gateway +from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.unroll import unrolling_iterable +from pypy.objspace.std.tupleobject import W_TupleObject + +class W_SmallTupleObject(W_Object): + from pypy.objspace.std.tupletype import tuple_typedef as typedef + + def tolist(self): + raise NotImplementedError + + def length(self): + raise NotImplementedError + + def getitem(self, index): + raise NotImplementedError + + def hash(self, space): + raise NotImplementedError + + def eq(self, space, w_other): + raise NotImplementedError + + def setitem(self, index, w_item): + raise NotImplementedError + + def unwrap(w_tuple, space): + items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] + return tuple(items) + +def make_specialized_class(n): + iter_n = unrolling_iterable(range(n)) + class cls(W_SmallTupleObject): + + def __init__(self, values): + assert len(values) == n + for i in iter_n: + setattr(self, 'w_value%s' % i, values[i]) + + def tolist(self): + l = [None] * n + for i in iter_n: + l[i] = getattr(self, 'w_value%s' % i) + return l + + def length(self): + return n + + def getitem(self, index): + for i in iter_n: + if index == i: + return getattr(self,'w_value%s' % i) + raise IndexError + + def setitem(self, index, w_item): + for i in iter_n: + if index == i: + setattr(self, 'w_value%s' % i, w_item) + return + raise IndexError + + def eq(self, space, w_other): + if self.length() != w_other.length(): + return space.w_False + for i in iter_n: + item1 = self.getitem(i) + item2 = w_other.getitem(i) + if not space.eq_w(item1, item2): + return space.w_False + return space.w_True + + def hash(self, space): + mult = 1000003 + x = 0x345678 + z = self.length() + for i in iter_n: + w_item = self.getitem(i) + y = space.int_w(space.hash(w_item)) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return space.wrap(intmask(x)) + + cls.__name__ = "W_SmallTupleObject%s" % n + return cls + +W_SmallTupleObject2 = make_specialized_class(2) +W_SmallTupleObject3 = make_specialized_class(3) +W_SmallTupleObject4 = make_specialized_class(4) +W_SmallTupleObject5 = make_specialized_class(5) +W_SmallTupleObject6 = make_specialized_class(6) +W_SmallTupleObject7 = make_specialized_class(7) +W_SmallTupleObject8 = make_specialized_class(8) + +registerimplementation(W_SmallTupleObject) + +def delegate_SmallTuple2Tuple(space, w_small): + return W_TupleObject(w_small.tolist()) + +def len__SmallTuple(space, w_tuple): + return space.wrap(w_tuple.length()) + +def getitem__SmallTuple_ANY(space, w_tuple, w_index): + index = space.getindex_w(w_index, space.w_IndexError, "tuple index") + if index < 0: + index += w_tuple.length() + try: + return w_tuple.getitem(index) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) + +def getitem__SmallTuple_Slice(space, w_tuple, w_slice): + length = w_tuple.length() + start, stop, step, slicelength = w_slice.indices4(space, length) + assert slicelength >= 0 + subitems = [None] * slicelength + for i in range(slicelength): + subitems[i] = w_tuple.getitem(start) + start += step + return space.newtuple(subitems) + +def mul_smalltuple_times(space, w_tuple, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + raise FailedToImplement + raise + if times == 1 and space.type(w_tuple) == space.w_tuple: + return w_tuple + items = w_tuple.tolist() + return space.newtuple(items * times) + +def mul__SmallTuple_ANY(space, w_tuple, w_times): + return mul_smalltuple_times(space, w_tuple, w_times) + +def mul__ANY_SmallTuple(space, w_times, w_tuple): + return mul_smalltuple_times(space, w_tuple, w_times) + +def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2): + return w_tuple1.eq(space, w_tuple2) + +def hash__SmallTuple(space, w_tuple): + return w_tuple.hash(space) + +from pypy.objspace.std import tupletype +register_all(vars(), tupletype) diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -252,15 +252,30 @@ res_w = [] start = 0 - while maxsplit != 0: - next = value.find(by, start) - if next < 0: - break - res_w.append(sliced(space, value, start, next, w_self)) - start = next + bylen - maxsplit -= 1 # NB. if it's already < 0, it stays < 0 + if bylen == 1 and maxsplit < 0: + # fast path: uses str.rfind(character) and str.count(character) + by = by[0] # annotator hack: string -> char + count = value.count(by) + res_w = [None] * (count + 1) + end = len(value) + while count >= 0: + assert end >= 0 + prev = value.rfind(by, 0, end) + start = prev + 1 + assert start >= 0 + res_w[count] = sliced(space, value, start, end, w_self) + count -= 1 + end = prev + else: + while maxsplit != 0: + next = value.find(by, start) + if next < 0: + break + res_w.append(sliced(space, value, start, next, w_self)) + start = next + bylen + maxsplit -= 1 # NB. if it's already < 0, it stays < 0 + res_w.append(sliced(space, value, start, len(value), w_self)) - res_w.append(sliced(space, value, start, len(value), w_self)) return space.newlist(res_w) def str_rsplit__String_None_ANY(space, w_self, w_none, w_maxsplit=-1): diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py --- a/pypy/objspace/std/test/test_floatobject.py +++ b/pypy/objspace/std/test/test_floatobject.py @@ -63,6 +63,19 @@ def setup_class(cls): cls.w_py26 = cls.space.wrap(sys.version_info >= (2, 6)) + def test_conjugate(self): + assert (1.).conjugate() == 1. + assert (-1.).conjugate() == -1. + + class F(float): + pass + assert F(1.).conjugate() == 1. + + class F(float): + def __pos__(self): + return 42. + assert F(1.).conjugate() == 1. + def test_negatives(self): assert -1.1 < 0 assert -0.1 < 0 @@ -417,6 +430,11 @@ f = 1.1234e200 assert f.__format__("G") == "1.1234E+200" + def test_float_real(self): + class A(float): pass + b = A(5).real + assert type(b) is float + class AppTestFloatHex: def w_identical(self, x, y): @@ -746,3 +764,6 @@ pass else: self.identical(x, float.fromhex(x.hex())) + + def test_invalid(self): + raises(ValueError, float.fromhex, "0P") diff --git a/pypy/objspace/std/test/test_intobject.py b/pypy/objspace/std/test/test_intobject.py --- a/pypy/objspace/std/test/test_intobject.py +++ b/pypy/objspace/std/test/test_intobject.py @@ -285,6 +285,19 @@ class AppTestInt: + def test_conjugate(self): + assert (1).conjugate() == 1 + assert (-1).conjugate() == -1 + + class I(int): + pass + assert I(1).conjugate() == 1 + + class I(int): + def __pos__(self): + return 42 + assert I(1).conjugate() == 1 + def test_trunc(self): import math assert math.trunc(1) == 1 @@ -480,6 +493,11 @@ ]: assert val.bit_length() == bits + def test_int_real(self): + class A(int): pass + b = A(5).real + assert type(b) is int + class AppTestIntOptimizedAdd(AppTestInt): def setup_class(cls): diff --git a/pypy/objspace/std/test/test_longobject.py b/pypy/objspace/std/test/test_longobject.py --- a/pypy/objspace/std/test/test_longobject.py +++ b/pypy/objspace/std/test/test_longobject.py @@ -300,6 +300,11 @@ assert type(L(7).conjugate()) is long + class L(long): + def __pos__(self): + return 43 + assert L(7).conjugate() == 7L + def test_bit_length(self): assert 8L.bit_length() == 4 assert (-1<<40).bit_length() == 41 @@ -323,3 +328,7 @@ assert type(as_long) is long assert as_long == 64 + def test_long_real(self): + class A(long): pass + b = A(5).real + assert type(b) is long diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -902,7 +902,53 @@ return c.m() val = f() assert val == 42 - f() + f() + + def test_bug_lookup_method_devolved_dict_caching(self): + class A(object): + def method(self): + return 42 + a = A() + a.__dict__[1] = 'foo' + got = a.method() + assert got == 42 + a.__dict__['method'] = lambda: 43 + got = a.method() + assert got == 43 + + def test_bug_method_change(self): + class A(object): + def method(self): + return 42 + a = A() + got = a.method() + assert got == 42 + A.method = lambda self: 43 + got = a.method() + assert got == 43 + A.method = lambda self: 44 + got = a.method() + assert got == 44 + + def test_bug_slot_via_changing_member_descr(self): + class A(object): + __slots__ = ['a', 'b', 'c', 'd'] + x = A() + x.a = 'a' + x.b = 'b' + x.c = 'c' + x.d = 'd' + got = x.a + assert got == 'a' + A.a = A.b + got = x.a + assert got == 'b' + A.a = A.c + got = x.a + assert got == 'c' + A.a = A.d + got = x.a + assert got == 'd' class AppTestGlobalCaching(AppTestWithMapDict): def setup_class(cls): diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_smalltupleobject.py @@ -0,0 +1,86 @@ +from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject +from pypy.interpreter.error import OperationError +from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject +from pypy.conftest import gettestobjspace + +class AppTestW_SmallTupleObject(AppTestW_TupleObject): + + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True}) + cls.w_issmall = cls.space.appexec([], """(): + import __pypy__ + def issmall(obj): + assert "SmallTuple" in __pypy__.internal_repr(obj) + return issmall + """) + + def test_smalltuple(self): + self.issmall((1,2)) + self.issmall((1,2,3)) + + def test_slicing_to_small(self): + self.issmall((1, 2, 3)[0:2]) # SmallTuple2 + self.issmall((1, 2, 3)[0:2:1]) + + self.issmall((1, 2, 3, 4)[0:3]) # SmallTuple3 + self.issmall((1, 2, 3, 4)[0:3:1]) + + def test_adding_to_small(self): + self.issmall((1,)+(2,)) # SmallTuple2 + self.issmall((1,1)+(2,)) # SmallTuple3 + self.issmall((1,)+(2,3)) + + def test_multiply_to_small(self): + self.issmall((1,)*2) + self.issmall((1,)*3) + + def test_slicing_from_small(self): + assert (1,2)[0:1:1] == (1,) + assert (1,2,3)[0:2:1] == (1,2) + + def test_eq(self): + a = (1,2,3) + b = (1,2,3) + assert a == b + + c = (1,3,2) + assert a != c + + def test_hash(self): + a = (1,2,3) + b = (1,2,3) + assert hash(a) == hash(b) + + c = (1,3,2) + assert hash(a) != hash(c) + +class TestW_SmallTupleObject(): + + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True}) + + def test_issmalltupleobject(self): + w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) + assert isinstance(w_tuple, W_SmallTupleObject) + + def test_hash_agains_normal_tuple(self): + normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False}) + w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) + + smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True}) + w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) + + assert isinstance(w_smalltuple, W_SmallTupleObject) + assert isinstance(w_tuple, W_TupleObject) + assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple)) + assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple)) + assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple))) + + def test_setitem(self): + w_smalltuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) + w_smalltuple.setitem(0, self.space.wrap(5)) + list_w = w_smalltuple.tolist() + assert len(list_w) == 2 + assert self.space.eq_w(list_w[0], self.space.wrap(5)) + assert self.space.eq_w(list_w[1], self.space.wrap(2)) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -23,7 +23,7 @@ return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist)) def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] # XXX generic mixed types unwrap + items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] return tuple(items) registerimplementation(W_TupleObject) @@ -56,12 +56,12 @@ for i in range(slicelength): subitems[i] = items[start] start += step - return W_TupleObject(subitems) + return space.newtuple(subitems) def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop): length = len(w_tuple.wrappeditems) start, stop = normalize_simple_slice(space, length, w_start, w_stop) - return W_TupleObject(w_tuple.wrappeditems[start:stop]) + return space.newtuple(w_tuple.wrappeditems[start:stop]) def contains__Tuple_ANY(space, w_tuple, w_obj): for w_item in w_tuple.wrappeditems: @@ -76,7 +76,7 @@ def add__Tuple_Tuple(space, w_tuple1, w_tuple2): items1 = w_tuple1.wrappeditems items2 = w_tuple2.wrappeditems - return W_TupleObject(items1 + items2) + return space.newtuple(items1 + items2) def mul_tuple_times(space, w_tuple, w_times): try: @@ -88,7 +88,7 @@ if times == 1 and space.type(w_tuple) == space.w_tuple: return w_tuple items = w_tuple.wrappeditems - return W_TupleObject(items * times) + return space.newtuple(items * times) def mul__Tuple_ANY(space, w_tuple, w_times): return mul_tuple_times(space, w_tuple, w_times) @@ -162,7 +162,7 @@ return intmask(x) def getnewargs__Tuple(space, w_tuple): - return space.newtuple([W_TupleObject(w_tuple.wrappeditems)]) + return space.newtuple([space.newtuple(w_tuple.wrappeditems)]) def tuple_count__Tuple_ANY(space, w_tuple, w_obj): count = 0 diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py --- a/pypy/objspace/std/tupletype.py +++ b/pypy/objspace/std/tupletype.py @@ -3,6 +3,31 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.stdtypedef import StdTypeDef, SMM +def wraptuple(space, list_w): + from pypy.objspace.std.tupleobject import W_TupleObject + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8 + if space.config.objspace.std.withsmalltuple: + if len(list_w) == 2: + return W_SmallTupleObject2(list_w) + if len(list_w) == 3: + return W_SmallTupleObject3(list_w) + if len(list_w) == 4: + return W_SmallTupleObject4(list_w) + if len(list_w) == 5: + return W_SmallTupleObject5(list_w) + if len(list_w) == 6: + return W_SmallTupleObject6(list_w) + if len(list_w) == 7: + return W_SmallTupleObject7(list_w) + if len(list_w) == 8: + return W_SmallTupleObject8(list_w) + return W_TupleObject(list_w) tuple_count = SMM("count", 2, doc="count(obj) -> number of times obj appears in the tuple") diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py --- a/pypy/objspace/test/test_descroperation.py +++ b/pypy/objspace/test/test_descroperation.py @@ -524,6 +524,31 @@ assert issubclass(B, B) assert issubclass(23, B) + def test_truth_of_long(self): + class X(object): + def __len__(self): return 1L + __nonzero__ = __len__ + assert X() + del X.__nonzero__ + assert X() + + def test_len_overflow(self): + import sys + class X(object): + def __len__(self): + return sys.maxsize + 1 + raises(OverflowError, len, X()) + + def test_len_underflow(self): + import sys + class X(object): + def __len__(self): + return -1 + raises(ValueError, len, X()) + class Y(object): + def __len__(self): + return -1L + raises(ValueError, len, Y()) class AppTestWithBuiltinShortcut(AppTest_Descroperation): OPTIONS = {'objspace.std.builtinshortcut': True} diff --git a/pypy/objspace/trace.py b/pypy/objspace/trace.py --- a/pypy/objspace/trace.py +++ b/pypy/objspace/trace.py @@ -110,10 +110,10 @@ self.result.append(EnterFrame(frame)) self.ec.enter(frame) - def leave(self, frame, w_exitvalue): + def leave(self, frame, w_exitvalue, got_exception): """ called just after evaluating of a frame is suspended/finished. """ self.result.append(LeaveFrame(frame)) - self.ec.leave(frame, w_exitvalue) + self.ec.leave(frame, w_exitvalue, got_exception) def bytecode_trace(self, frame): """ called just before execution of a bytecode. """ diff --git a/pypy/rlib/_jit_vref.py b/pypy/rlib/_jit_vref.py --- a/pypy/rlib/_jit_vref.py +++ b/pypy/rlib/_jit_vref.py @@ -50,6 +50,7 @@ def rtype_simple_call(self, hop): [v] = hop.inputargs(self) + hop.exception_is_here() v = hop.genop('jit_force_virtual', [v], resulttype = OBJECTPTR) return hop.genop('cast_pointer', [v], resulttype = hop.r_result) @@ -65,6 +66,7 @@ lowleveltype = OBJECT def rtype_simple_call(self, hop): [v] = hop.inputargs(self) + hop.exception_is_here() v = hop.genop('jit_force_virtual', [v], resulttype = OBJECT) return hop.genop('oodowncast', [v], resulttype = hop.r_result) diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -140,6 +140,40 @@ return hop.inputconst(lltype.Bool, False) +def debug_offset(): + """ Return an offset in log file + """ + return -1 + +class Entry(ExtRegistryEntry): + _about_ = debug_offset + + def compute_result_annotation(self): + from pypy.annotation import model as annmodel + return annmodel.SomeInteger() + + def specialize_call(self, hop): + from pypy.rpython.lltypesystem import lltype + hop.exception_cannot_occur() + return hop.genop('debug_offset', [], resulttype=lltype.Signed) + + +def debug_flush(): + """ Flushes the debug file + """ + pass + +class Entry(ExtRegistryEntry): + _about_ = debug_flush + + def compute_result_annotation(self): + return None + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.genop('debug_flush', []) + + def llinterpcall(RESTYPE, pythonfunction, *args): """When running on the llinterp, this causes the llinterp to call to the provided Python function with the run-time value of the given args. diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -113,7 +113,7 @@ flags['fresh_virtualizable'] = True s_x = annmodel.SomeInstance(s_x.classdef, s_x.can_be_None, - flags) + flags) return s_x def specialize_call(self, hop, **kwds_i): @@ -179,29 +179,10 @@ pass -##def force_virtualizable(virtualizable): -## pass - -##class Entry(ExtRegistryEntry): -## _about_ = force_virtualizable - -## def compute_result_annotation(self): -## from pypy.annotation import model as annmodel -## return annmodel.s_None - -## def specialize_call(self, hop): -## [vinst] = hop.inputargs(hop.args_r[0]) -## cname = inputconst(lltype.Void, None) -## cflags = inputconst(lltype.Void, {}) -## hop.exception_cannot_occur() -## return hop.genop('jit_force_virtualizable', [vinst, cname, cflags], -## resulttype=lltype.Void) - # ____________________________________________________________ # VRefs def virtual_ref(x): - """Creates a 'vref' object that contains a reference to 'x'. Calls to virtual_ref/virtual_ref_finish must be properly nested. The idea is that the object 'x' is supposed to be JITted as a virtual between @@ -212,10 +193,10 @@ return DirectJitVRef(x) virtual_ref.oopspec = 'virtual_ref(x)' -def virtual_ref_finish(x): - """See docstring in virtual_ref(x). Note that virtual_ref_finish - takes as argument the real object, not the vref.""" +def virtual_ref_finish(vref, x): + """See docstring in virtual_ref(x)""" keepalive_until_here(x) # otherwise the whole function call is removed + _virtual_ref_finish(vref, x) virtual_ref_finish.oopspec = 'virtual_ref_finish(x)' def non_virtual_ref(x): @@ -223,19 +204,39 @@ Used for None or for frames outside JIT scope.""" return DirectVRef(x) +class InvalidVirtualRef(Exception): + """ + Raised if we try to call a non-forced virtualref after the call to + virtual_ref_finish + """ + # ---------- implementation-specific ---------- class DirectVRef(object): def __init__(self, x): self._x = x + self._state = 'non-forced' + def __call__(self): + if self._state == 'non-forced': + self._state = 'forced' + elif self._state == 'invalid': + raise InvalidVirtualRef return self._x + def _finish(self): + if self._state == 'non-forced': + self._state = 'invalid' + class DirectJitVRef(DirectVRef): def __init__(self, x): assert x is not None, "virtual_ref(None) is not allowed" DirectVRef.__init__(self, x) +def _virtual_ref_finish(vref, x): + assert vref._x is x, "Invalid call to virtual_ref_finish" + vref._finish() + class Entry(ExtRegistryEntry): _about_ = (non_virtual_ref, DirectJitVRef) @@ -255,17 +256,26 @@ s_obj = self.bookkeeper.immutablevalue(self.instance()) return _jit_vref.SomeVRef(s_obj) +class Entry(ExtRegistryEntry): + _about_ = _virtual_ref_finish + + def compute_result_annotation(self, s_vref, s_obj): + pass + + def specialize_call(self, hop): + pass + vref_None = non_virtual_ref(None) # ____________________________________________________________ -# User interface for the hotpath JIT policy +# User interface for the warmspot JIT policy class JitHintError(Exception): """Inconsistency in the JIT hints.""" PARAMETERS = {'threshold': 1000, 'trace_eagerness': 200, - 'trace_limit': 10000, + 'trace_limit': 12000, 'inlining': 0, 'loop_longevity': 1000, 'retrace_limit': 5, @@ -275,7 +285,7 @@ # ____________________________________________________________ -class JitDriver(object): +class JitDriver(object): """Base class to declare fine-grained user control on the JIT. So far, there must be a singleton instance of JitDriver. This style will allow us (later) to support a single RPython program with @@ -360,6 +370,24 @@ raise set_user_param._annspecialcase_ = 'specialize:arg(0)' + + def on_compile(self, logger, looptoken, operations, type, *greenargs): + """ A hook called when loop is compiled. Overwrite + for your own jitdriver if you want to do something special, like + call applevel code + """ + + def on_compile_bridge(self, logger, orig_looptoken, operations, n): + """ A hook called when a bridge is compiled. Overwrite + for your own jitdriver if you want to do something special + """ + + # note: if you overwrite this functions with the above signature it'll + # work, but the *greenargs is different for each jitdriver, so we + # can't share the same methods + del on_compile + del on_compile_bridge + def _make_extregistryentries(self): # workaround: we cannot declare ExtRegistryEntries for functions # used as methods of a frozen object, but we can attach the @@ -477,8 +505,6 @@ r_green = hop.args_r[i] v_green = hop.inputarg(r_green, arg=i) else: - #if hop.rtyper.type_system.name == 'ootypesystem': - #py.test.skip("lltype only") objname, fieldname = name.split('.') # see test_green_field assert objname in driver.reds i = kwds_i['i_' + objname] @@ -557,7 +583,7 @@ def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr - + hop.exception_cannot_occur() driver = self.instance.im_self name = hop.args_s[0].const diff --git a/pypy/rlib/nonconst.py b/pypy/rlib/nonconst.py --- a/pypy/rlib/nonconst.py +++ b/pypy/rlib/nonconst.py @@ -18,6 +18,12 @@ def __nonzero__(self): return bool(self.__dict__['constant']) + def __eq__(self, other): + return self.__dict__['constant'] == other + + def __add__(self, other): + return self.__dict__['constant'] + other + class EntryNonConstant(ExtRegistryEntry): _about_ = NonConstant diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -1345,6 +1345,7 @@ # XXX make sure that we don't ignore this! # YYY no, we decided to do ignore this! + at jit.dont_look_inside def _AsDouble(n): """ Get a C double from a bigint object. """ # This is a "correctly-rounded" version from Python 2.7. diff --git a/pypy/rlib/rcoroutine.py b/pypy/rlib/rcoroutine.py --- a/pypy/rlib/rcoroutine.py +++ b/pypy/rlib/rcoroutine.py @@ -29,7 +29,7 @@ The type of a switch is determined by the target's costate. """ -from pypy.rlib.rstack import yield_current_frame_to_caller, resume_point +from pypy.rlib.rstack import yield_current_frame_to_caller from pypy.rlib.objectmodel import we_are_translated from pypy.interpreter.error import OperationError @@ -228,7 +228,6 @@ self.thunk = None syncstate.switched(incoming_frame) thunk.call() - resume_point("coroutine__bind", state) except Exception, e: exc = e raise @@ -257,7 +256,6 @@ raise CoroutineDamage state = self.costate incoming_frame = state.update(self).switch() - resume_point("coroutine_switch", state, returns=incoming_frame) syncstate.switched(incoming_frame) def kill(self): diff --git a/pypy/rlib/rsre/rsre_core.py b/pypy/rlib/rsre/rsre_core.py --- a/pypy/rlib/rsre/rsre_core.py +++ b/pypy/rlib/rsre/rsre_core.py @@ -759,17 +759,27 @@ @specializectx def find_repetition_end(ctx, ppos, ptr, maxcount): end = ctx.end - if maxcount <= 1: - if maxcount == 1 and ptr < end: - # Relatively common case: maxcount == 1. If we are not at the - # end of the string, it's done by a single direct check. - op = ctx.pat(ppos) - for op1, checkerfn in unroll_char_checker: - if op1 == op: - if checkerfn(ctx, ptr, ppos): - return ptr + 1 + ptrp1 = ptr + 1 + # First get rid of the cases where we don't have room for any match. + if maxcount <= 0 or ptrp1 > end: return ptr - elif maxcount != 65535: + # Check the first character directly. If it doesn't match, we are done. + # The idea is to be fast for cases like re.search("b+"), where we expect + # the common case to be a non-match. It's much faster with the JIT to + # have the non-match inlined here rather than detect it in the fre() call. + op = ctx.pat(ppos) + for op1, checkerfn in unroll_char_checker: + if op1 == op: + if checkerfn(ctx, ptr, ppos): + break + else: + return ptr + # It matches at least once. If maxcount == 1 (relatively common), + # then we are done. + if maxcount == 1: + return ptrp1 + # Else we really need to count how many times it matches. + if maxcount != 65535: # adjust end end1 = ptr + maxcount if end1 <= end: @@ -777,7 +787,7 @@ op = ctx.pat(ppos) for op1, fre in unroll_fre_checker: if op1 == op: - return fre(ctx, ptr, end, ppos) + return fre(ctx, ptrp1, end, ppos) raise Error("rsre.find_repetition_end[%d]" % op) @specializectx diff --git a/pypy/rlib/rsre/test/test_zjit.py b/pypy/rlib/rsre/test/test_zjit.py --- a/pypy/rlib/rsre/test/test_zjit.py +++ b/pypy/rlib/rsre/test/test_zjit.py @@ -160,3 +160,9 @@ res = self.meta_interp_match(r"<[\S ]+>", "<..a .. aa>") assert res == 13 self.check_enter_count(1) + + + def test_find_repetition_end_fastpath(self): + res = self.meta_interp_search(r"b+", "a"*30 + "b") + assert res == 30 + self.check_loops(call=0) diff --git a/pypy/rlib/rstack.py b/pypy/rlib/rstack.py --- a/pypy/rlib/rstack.py +++ b/pypy/rlib/rstack.py @@ -42,16 +42,26 @@ sandboxsafe=True, _nowrapper=True, _callable=_callable) -_stack_get_start = llexternal('LL_stack_get_start', [], lltype.Signed, - lambda: 0) +_stack_get_end = llexternal('LL_stack_get_end', [], lltype.Signed, + lambda: 0) _stack_get_length = llexternal('LL_stack_get_length', [], lltype.Signed, lambda: 1) +_stack_set_length_fraction = llexternal('LL_stack_set_length_fraction', + [lltype.Float], lltype.Void, + lambda frac: None) _stack_too_big_slowpath = llexternal('LL_stack_too_big_slowpath', [lltype.Signed], lltype.Char, lambda cur: '\x00') # the following is used by the JIT -_stack_get_start_adr = llexternal('LL_stack_get_start_adr', [], lltype.Signed) +_stack_get_end_adr = llexternal('LL_stack_get_end_adr', [], lltype.Signed) +_stack_get_length_adr= llexternal('LL_stack_get_length_adr',[], lltype.Signed) +# the following is also used by the JIT: "critical code" paths are paths in +# which we should not raise StackOverflow at all, but just ignore the stack limit +_stack_criticalcode_start = llexternal('LL_stack_criticalcode_start', [], + lltype.Void, lambda: None) +_stack_criticalcode_stop = llexternal('LL_stack_criticalcode_stop', [], + lltype.Void, lambda: None) def stack_check(): if not we_are_translated(): @@ -62,13 +72,13 @@ current = llop.stack_current(lltype.Signed) # # Load these variables from C code - start = _stack_get_start() + end = _stack_get_end() length = _stack_get_length() # - # Common case: if 'current' is within [start:start+length], everything + # Common case: if 'current' is within [end-length:end], everything # is fine - ofs = r_uint(current - start) - if ofs < r_uint(length): + ofs = r_uint(end - current) + if ofs <= r_uint(length): return # # Else call the slow path @@ -140,111 +150,6 @@ return var -def resume_point(label, *args, **kwds): - pass - - - -class ResumePointFnEntry(ExtRegistryEntry): - _about_ = resume_point - - def compute_result_annotation(self, s_label, *args_s, **kwds_s): - from pypy.annotation import model as annmodel - return annmodel.s_None - - def specialize_call(self, hop, **kwds_i): - from pypy.rpython.lltypesystem import lltype - from pypy.objspace.flow import model - - assert hop.args_s[0].is_constant() - c_label = hop.inputconst(lltype.Void, hop.args_s[0].const) - args_v = hop.args_v[1:] - if 'i_returns' in kwds_i: - assert len(kwds_i) == 1 - returns_index = kwds_i['i_returns'] - v_return = args_v.pop(returns_index-1) - assert isinstance(v_return, model.Variable), \ - "resume_point returns= argument must be a Variable" - else: - assert not kwds_i - v_return = hop.inputconst(lltype.Void, None) - - for v in args_v: - assert isinstance(v, model.Variable), "resume_point arguments must be Variables" - - hop.exception_is_here() - return hop.genop('resume_point', [c_label, v_return] + args_v, - hop.r_result) - -def resume_state_create(prevstate, label, *args): - raise RuntimeError("cannot resume states in non-translated versions") - -def concretify_argument(hop, index): - from pypy.objspace.flow import model - - v_arg = hop.args_v[index] - if isinstance(v_arg, model.Variable): - return v_arg - - r_arg = hop.rtyper.bindingrepr(v_arg) - return hop.inputarg(r_arg, arg=index) - -class ResumeStateCreateFnEntry(FrameStackTopReturningFnEntry): - _about_ = resume_state_create - - def compute_result_annotation(self, s_prevstate, s_label, *args_s): - return FrameStackTopReturningFnEntry.compute_result_annotation(self) - - def specialize_call(self, hop): - from pypy.rpython.lltypesystem import lltype - - assert hop.args_s[1].is_constant() - c_label = hop.inputconst(lltype.Void, hop.args_s[1].const) - - v_state = hop.inputarg(hop.r_result, arg=0) - - args_v = [] - for i in range(2, len(hop.args_v)): - args_v.append(concretify_argument(hop, i)) - - hop.exception_is_here() - return hop.genop('resume_state_create', [v_state, c_label] + args_v, - hop.r_result) - -def resume_state_invoke(type, state, **kwds): - raise NotImplementedError("only works in translated versions") - -class ResumeStateInvokeFnEntry(ExtRegistryEntry): - _about_ = resume_state_invoke - - def compute_result_annotation(self, s_type, s_state, **kwds): - from pypy.annotation.bookkeeper import getbookkeeper - assert s_type.is_constant() - return getbookkeeper().valueoftype(s_type.const) - - def specialize_call(self, hop, **kwds_i): - from pypy.rpython.lltypesystem import lltype - v_state = hop.args_v[1] - - if 'i_returning' in kwds_i: - assert len(kwds_i) == 1 - returning_index = kwds_i['i_returning'] - v_returning = concretify_argument(hop, returning_index) - v_raising = hop.inputconst(lltype.Void, None) - elif 'i_raising' in kwds_i: - assert len(kwds_i) == 1 - raising_index = kwds_i['i_raising'] - v_returning = hop.inputconst(lltype.Void, None) - v_raising = concretify_argument(hop, raising_index) - else: - assert not kwds_i - v_returning = hop.inputconst(lltype.Void, None) - v_raising = hop.inputconst(lltype.Void, None) - - hop.exception_is_here() - return hop.genop('resume_state_invoke', [v_state, v_returning, v_raising], - hop.r_result) - # ____________________________________________________________ def get_stack_depth_limit(): diff --git a/pypy/rlib/test/test__jit_vref.py b/pypy/rlib/test/test__jit_vref.py --- a/pypy/rlib/test/test__jit_vref.py +++ b/pypy/rlib/test/test__jit_vref.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import virtual_ref, virtual_ref_finish -from pypy.rlib.jit import vref_None, non_virtual_ref +from pypy.rlib.jit import vref_None, non_virtual_ref, InvalidVirtualRef from pypy.rlib._jit_vref import SomeVRef from pypy.annotation import model as annmodel from pypy.annotation.annrpython import RPythonAnnotator @@ -23,18 +23,23 @@ pass -def test_direct_1(): +def test_direct_forced(): x1 = X() vref = virtual_ref(x1) + assert vref._state == 'non-forced' assert vref() is x1 - virtual_ref_finish(x1) + assert vref._state == 'forced' + virtual_ref_finish(vref, x1) + assert vref._state == 'forced' assert vref() is x1 -def test_direct_2(): +def test_direct_invalid(): x1 = X() vref = virtual_ref(x1) - virtual_ref_finish(x1) - assert vref() is x1 + assert vref._state == 'non-forced' + virtual_ref_finish(vref, x1) + assert vref._state == 'invalid' + py.test.raises(InvalidVirtualRef, "vref()") def test_annotate_1(): def f(): @@ -50,7 +55,7 @@ x1 = X() vref = virtual_ref(x1) x2 = vref() - virtual_ref_finish(x1) + virtual_ref_finish(vref, x1) return x2 a = RPythonAnnotator() s = a.build_types(f, []) @@ -95,7 +100,7 @@ x1 = X() vref = virtual_ref(x1) x2 = vref() - virtual_ref_finish(x2) + virtual_ref_finish(vref, x2) return x2 x = self.interpret(f, []) assert self.castable(self.OBJECTTYPE, x) @@ -119,6 +124,18 @@ assert lltype.typeOf(x) == self.OBJECTTYPE assert not x + def test_rtype_5(self): + def f(): + vref = virtual_ref(X()) + try: + vref() + return 42 + except InvalidVirtualRef: + return -1 + x = self.interpret(f, []) + assert x == 42 + + class TestLLtype(BaseTestVRef, LLRtypeMixin): OBJECTTYPE = OBJECTPTR def castable(self, TO, var): diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -2,7 +2,7 @@ import py from pypy.rlib.debug import check_annotation, make_sure_not_resized from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints +from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative from pypy.rlib import debug from pypy.rpython.test.test_llinterp import interpret @@ -60,6 +60,8 @@ debug_start("mycat") debug_print("foo", 2, "bar", x) debug_stop("mycat") + debug_flush() # does nothing + debug_offset() # should not explode at least return have_debug_prints() try: diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -52,9 +52,12 @@ import sys s = StringIO() + prev = sys.stdout sys.stdout = s - dis.dis(g) - sys.stdout = sys.__stdout__ + try: + dis.dis(g) + finally: + sys.stdout = prev x = s.getvalue().find('CALL_FUNCTION') assert x != -1 x = s.getvalue().find('CALL_FUNCTION', x) diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -513,13 +513,6 @@ from pypy.translator.tool.lltracker import track track(*ll_objects) - def op_debug_pdb(self, *ll_args): - if self.llinterpreter.tracer: - self.llinterpreter.tracer.flush() - print "entering pdb...", ll_args - import pdb - pdb.set_trace() - def op_debug_assert(self, x, msg): assert x, msg @@ -570,15 +563,6 @@ def op_hint(self, x, hints): return x - def op_resume_point(self, *args): - pass - - def op_resume_state_create(self, *args): - raise RuntimeError("resume_state_create can not be called.") - - def op_resume_state_invoke(self, *args): - raise RuntimeError("resume_state_invoke can not be called.") - def op_decode_arg(self, fname, i, name, vargs, vkwds): raise NotImplementedError("decode_arg") diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -20,7 +20,6 @@ from pypy.rpython.extfunc import ExtRegistryEntry from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic from pypy.tool.uid import fixid -from pypy.tool.tls import tlsobject from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longfloat, intmask from pypy.annotation import model as annmodel from pypy.rpython.llinterp import LLInterpreter, LLException @@ -28,6 +27,7 @@ from pypy.rpython import raddress from pypy.translator.platform import platform from array import array +from thread import _local as tlsobject # ____________________________________________________________ diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -521,10 +521,6 @@ RuntimeError)), # can always unwind, not just if stackless gc - 'resume_point': LLOp(canraise=(Exception,)), - 'resume_state_create': LLOp(canraise=(MemoryError,), canunwindgc=True), - 'resume_state_invoke': LLOp(canraise=(Exception, StackException, - RuntimeError)), 'stack_frames_depth': LLOp(sideeffects=False, canraise=(StackException, RuntimeError)), 'stack_switch': LLOp(canraise=(StackException, RuntimeError)), @@ -553,7 +549,8 @@ 'debug_start': LLOp(canrun=True), 'debug_stop': LLOp(canrun=True), 'have_debug_prints': LLOp(canrun=True), - 'debug_pdb': LLOp(), + 'debug_offset': LLOp(canrun=True), + 'debug_flush': LLOp(canrun=True), 'debug_assert': LLOp(tryfold=True), 'debug_fatalerror': LLOp(), 'debug_llinterpcall': LLOp(canraise=(Exception,)), diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -4,14 +4,16 @@ base_int, normalizedinttype) from pypy.rlib.objectmodel import Symbolic from pypy.tool.uid import Hashable -from pypy.tool.tls import tlsobject from pypy.tool.identity_dict import identity_dict from pypy.tool import leakfinder from types import NoneType from sys import maxint import weakref -TLS = tlsobject() +class State(object): + pass + +TLS = State() class WeakValueDictionary(weakref.WeakValueDictionary): """A subclass of weakref.WeakValueDictionary diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -513,6 +513,12 @@ def op_debug_stop(category): debug.debug_stop(_normalize(category)) +def op_debug_offset(): + return debug.debug_offset() + +def op_debug_flush(): + pass + def op_have_debug_prints(): return debug.have_debug_prints() diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py --- a/pypy/rpython/lltypesystem/rlist.py +++ b/pypy/rpython/lltypesystem/rlist.py @@ -237,6 +237,7 @@ l.length = newsize else: _ll_list_resize_really(l, newsize) +_ll_list_resize_ge.oopspec = 'list._resize_ge(l, newsize)' def _ll_list_resize_le(l, newsize): if newsize >= (len(l.items) >> 1) - 5: diff --git a/pypy/rpython/lltypesystem/rpbc.py b/pypy/rpython/lltypesystem/rpbc.py --- a/pypy/rpython/lltypesystem/rpbc.py +++ b/pypy/rpython/lltypesystem/rpbc.py @@ -198,7 +198,6 @@ inputargs = [varoftype(t) for t in [Char] + argtypes] startblock = Block(inputargs) startblock.exitswitch = inputargs[0] - #startblock.operations.append(SpaceOperation('debug_pdb', [], varoftype(Void))) graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype)) row_of_graphs = self.callfamily.calltables[shape][index] links = [] diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -568,7 +568,6 @@ length = l.ll_length() l._ll_resize_ge(length+1) # see "a note about overflows" above l.ll_setitem_fast(length, newitem) -ll_append.oopspec = 'list.append(l, newitem)' # this one is for the special case of insert(0, x) def ll_prepend(l, newitem): @@ -793,7 +792,6 @@ raise MemoryError l1._ll_resize_ge(newlength) ll_arraycopy(l2, l1, 0, len1, len2) -ll_extend.oopspec = 'list.extend(l1, l2)' def ll_extend_with_str(lst, s, getstrlen, getstritem): return ll_extend_with_str_slice_startonly(lst, s, getstrlen, getstritem, 0) diff --git a/pypy/tool/memusage/__init__.py b/pypy/tool/memusage/__init__.py new file mode 100644 diff --git a/pypy/jit/tool/log-template.gnumeric b/pypy/tool/memusage/log-template.gnumeric rename from pypy/jit/tool/log-template.gnumeric rename to pypy/tool/memusage/log-template.gnumeric diff --git a/pypy/jit/tool/log2gnumeric.py b/pypy/tool/memusage/log2gnumeric.py old mode 100644 new mode 100755 rename from pypy/jit/tool/log2gnumeric.py rename to pypy/tool/memusage/log2gnumeric.py --- a/pypy/jit/tool/log2gnumeric.py +++ b/pypy/tool/memusage/log2gnumeric.py @@ -1,12 +1,34 @@ #! /usr/bin/env python """ -Usage: log2gnumeric logfile - Produces a logfile.gnumeric file which contains the data extracted from the logfile generated with the PYPYLOG env variable. -Currently, it expects log to contain the translation-task and gc-collect -categories. +Run your program like this:: + + $ PYPYLOG=gc-collect,jit-mem:logfile pypy your-program.py + +This will produce "logfile", containing informations about the memory used by +the GC and the number of loops created/freed by the JIT. + +If you want, you can also measure the amout of used memory as seen by the OS +(the VmRSS) using memusage.py:: + + $ PYPYLOG=gc-collect,jit-mem:logfile ./memusage.py -o logfile.vmrss /path/to/pypy your-program.py + +log2gnumeric will automatically pick logfile.vmrss, if present. + +If you want to compare PyPy to CPython, you can add its VmRSS to the graph, by +using the -c option. To produce the .vmrss file, use again ./memusage.py:: + + $ ./memusage.py -o cpython.vmrss python your-program.py + $ ./log2gnumeric.py -c cpython.vmrss logfile + +Note that on CPython it will take a different amout of time to complete, but +on the graph the plot will be scaled to match the duration of the PyPy run +(i.e., the two lines will end "at the same time"). + +If you are benchmarking translate.py, you can add the "translation-task" +category to the log, by setting PYPYLOG=gc-collect,jit-mem,translation-task. You can freely edit the graph in log-template.gnumeric: this script will create a new file replacing the 'translation-task' and 'gc-collect' sheets. @@ -18,7 +40,6 @@ def main(logname, options): - logname = sys.argv[1] outname = logname + '.gnumeric' data = open(logname).read() data = data.replace('\n', '') @@ -151,11 +172,11 @@ def vmrss_rows(filename, maxtime): lines = [] - if options.cpython_vmrss: + if filename: try: lines = open(filename).readlines() except IOError: - print 'Warning: cannot find file %s, skipping this sheet' + print 'Warning: cannot find file %s, skipping this sheet' % filename for row in vmrss_rows_impl(lines, maxtime): yield row @@ -171,8 +192,11 @@ if __name__ == '__main__': CLOCK_FACTOR = 1000000000.0 # report GigaTicks instead of Ticks parser = optparse.OptionParser(usage="%prog logfile [options]") + parser.format_description = lambda fmt: __doc__ + parser.description = __doc__ parser.add_option('-c', '--cpython-vmrss', dest='cpython_vmrss', default=None, metavar='FILE', type=str, help='the .vmrss file produced by CPython') + options, args = parser.parse_args() if len(args) != 1: parser.print_help() diff --git a/pypy/tool/memusage/memusage.py b/pypy/tool/memusage/memusage.py new file mode 100755 --- /dev/null +++ b/pypy/tool/memusage/memusage.py @@ -0,0 +1,63 @@ +#! /usr/bin/env python +""" +Usage: memusage.py [-o filename] command [args...] + +Runs a subprocess, and measure its RSS (resident set size) every second. +At the end, print the maximum RSS measured, and some statistics. + +Also writes "filename", reporting every second the RSS. If filename is not +given, the output is written to "memusage.log" +""" + +import sys, os, re, time + +def parse_args(): + args = sys.argv[1:] + if args[0] == '-o': + args.pop(0) + outname = args.pop(0) + else: + outname = 'memusage.log' + args[0] # make sure there is at least one argument left + return outname, args + +try: + outname, args = parse_args() +except IndexError: + print >> sys.stderr, __doc__.strip() + sys.exit(2) + +childpid = os.fork() +if childpid == 0: + os.execvp(args[0], args) + sys.exit(1) + +r = re.compile("VmRSS:\s*(\d+)") + +filename = '/proc/%d/status' % childpid +rss_max = 0 +rss_sum = 0 +rss_count = 0 + +f = open(outname, 'w', 0) +while os.waitpid(childpid, os.WNOHANG)[0] == 0: + g = open(filename) + s = g.read() + g.close() + match = r.search(s) + if not match: # VmRSS is missing if the process just finished + break + rss = int(match.group(1)) + print >> f, rss + if rss > rss_max: rss_max = rss + rss_sum += rss + rss_count += 1 + time.sleep(1) +f.close() + +if rss_count > 0: + print + print 'Memory usage:' + print '\tmaximum RSS: %10d kb' % rss_max + print '\tmean RSS: %10d kb' % (rss_sum / rss_count) + print '\trun time: %10d s' % rss_count diff --git a/pypy/jit/tool/test/test_log2gnumeric.py b/pypy/tool/memusage/test/test_log2gnumeric.py rename from pypy/jit/tool/test/test_log2gnumeric.py rename to pypy/tool/memusage/test/test_log2gnumeric.py --- a/pypy/jit/tool/test/test_log2gnumeric.py +++ b/pypy/tool/memusage/test/test_log2gnumeric.py @@ -1,4 +1,4 @@ -from pypy.jit.tool import log2gnumeric +from pypy.tool.memusage import log2gnumeric log = """ [1000] ... diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -81,7 +81,7 @@ self.space = space self.operr = operr self.typename = operr.w_type.getname(space, "?") - self.traceback = AppTraceback(space, self.operr.application_traceback) + self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: self._excinfo = debug_excs[0] diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -36,6 +36,10 @@ class PyPyCNotFound(Exception): pass +def fix_permissions(basedir): + if sys.platform != 'win32': + os.system("chmod -R a+rX %s" % basedir) + def package(basedir, name='pypy-nightly', rename_pypy_c='pypy', copy_to_dir = None, override_pypy_c = None): basedir = py.path.local(basedir) @@ -93,6 +97,7 @@ archive = bindir.join(target) shutil.copy(str(source), str(archive)) old_dir = os.getcwd() + fix_permissions(builddir) try: os.chdir(str(builddir)) # @@ -117,7 +122,7 @@ zf.close() else: archive = str(builddir.join(name + '.tar.bz2')) - e = os.system('tar cvjf ' + archive + " " + name) + e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) if e: raise OSError('"tar" returned exit status %r' % e) finally: diff --git a/pypy/tool/release/test/test_package.py b/pypy/tool/release/test/test_package.py --- a/pypy/tool/release/test/test_package.py +++ b/pypy/tool/release/test/test_package.py @@ -10,12 +10,15 @@ if sys.platform == 'win32': basename = 'pypy-c.exe' rename_pypy_c = 'pypy-c' + exe_name_in_archive = 'pypy-c.exe' else: basename = 'pypy-c' rename_pypy_c = 'pypy' + exe_name_in_archive = 'bin/pypy' pypy_c = py.path.local(pypydir).join('translator', 'goal', basename) if not pypy_c.check(): os.system("echo faked_pypy_c> %s" % (pypy_c,)) + pypy_c.chmod(0755) fake_pypy_c = True else: fake_pypy_c = False @@ -25,10 +28,7 @@ prefix = builddir.join(test) cpyver = '%d.%d' % CPYTHON_VERSION[:2] assert prefix.join('lib-python', cpyver, 'test').check() - if sys.platform == 'win32': - assert prefix.join('pypy-c.exe').check() - else: - assert prefix.join('bin', 'pypy').check() + assert prefix.join(exe_name_in_archive).check() assert prefix.join('lib_pypy', 'syslog.py').check() assert not prefix.join('lib_pypy', 'py').check() assert not prefix.join('lib_pypy', 'ctypes_configure').check() @@ -39,7 +39,14 @@ assert zh.open('%s/lib_pypy/syslog.py' % test) else: th = tarfile.open(str(builddir.join('%s.tar.bz2' % test))) - assert th.getmember('%s/lib_pypy/syslog.py' % test) + syslog = th.getmember('%s/lib_pypy/syslog.py' % test) + exe = th.getmember('%s/%s' % (test, exe_name_in_archive)) + assert syslog.mode == 0644 + assert exe.mode == 0755 + assert exe.uname == '' + assert exe.gname == '' + assert exe.uid == 0 + assert exe.gid == 0 # the headers file could be not there, because they are copied into # trunk/include only during translation @@ -66,3 +73,26 @@ test_dir_structure(test='testzipfile') finally: package.USE_ZIPFILE_MODULE = prev + +def test_fix_permissions(tmpdir): + def check(f, mode): + assert f.stat().mode & 0777 == mode + # + mydir = tmpdir.join('mydir').ensure(dir=True) + bin = tmpdir.join('bin') .ensure(dir=True) + file1 = tmpdir.join('file1').ensure(file=True) + file2 = mydir .join('file2').ensure(file=True) + pypy = bin .join('pypy') .ensure(file=True) + # + mydir.chmod(0700) + bin.chmod(0700) + file1.chmod(0600) + file2.chmod(0640) + pypy.chmod(0700) + # + package.fix_permissions(tmpdir) + check(mydir, 0755) + check(bin, 0755) + check(file1, 0644) + check(file2, 0644) + check(pypy, 0755) diff --git a/pypy/tool/tls.py b/pypy/tool/tls.py deleted file mode 100644 --- a/pypy/tool/tls.py +++ /dev/null @@ -1,8 +0,0 @@ - -"""Thread-local storage.""" - -try: - from thread import _local as tlsobject -except ImportError: - class tlsobject(object): - pass diff --git a/pypy/translator/backendopt/inline.py b/pypy/translator/backendopt/inline.py --- a/pypy/translator/backendopt/inline.py +++ b/pypy/translator/backendopt/inline.py @@ -541,7 +541,6 @@ 'cast_pointer': 0, 'malloc': 2, 'yield_current_frame_to_caller': sys.maxint, # XXX bit extreme - 'resume_point': sys.maxint, # XXX bit extreme 'instrument_count': 0, 'debug_assert': -1, } diff --git a/pypy/translator/backendopt/removenoops.py b/pypy/translator/backendopt/removenoops.py --- a/pypy/translator/backendopt/removenoops.py +++ b/pypy/translator/backendopt/removenoops.py @@ -81,8 +81,6 @@ num_removed += 1 else: available[key] = op.result - elif op.opname == 'resume_point': - available.clear() if num_removed: remove_same_as(graph) # remove casts with unused results diff --git a/pypy/translator/c/funcgen.py b/pypy/translator/c/funcgen.py --- a/pypy/translator/c/funcgen.py +++ b/pypy/translator/c/funcgen.py @@ -705,7 +705,7 @@ offset = self.expr(op.args[2]) value = self.expr(op.args[3]) typename = cdecl(self.db.gettype(TYPE).replace('@', '*@'), '') - return "*(((%(typename)s) %(addr)s ) + %(offset)s) = %(value)s;" % locals() + return "((%(typename)s) %(addr)s)[%(offset)s] = %(value)s;" % locals() def OP_RAW_LOAD(self, op): addr = self.expr(op.args[0]) @@ -713,7 +713,7 @@ offset = self.expr(op.args[2]) result = self.expr(op.result) typename = cdecl(self.db.gettype(TYPE).replace('@', '*@'), '') - return "%(result)s = *(((%(typename)s) %(addr)s ) + %(offset)s);" % locals() + return "%(result)s = ((%(typename)s) %(addr)s)[%(offset)s];" % locals() def OP_CAST_PRIMITIVE(self, op): TYPE = self.lltypemap(op.result) diff --git a/pypy/translator/c/src/debug_print.c b/pypy/translator/c/src/debug_print.c --- a/pypy/translator/c/src/debug_print.c +++ b/pypy/translator/c/src/debug_print.c @@ -6,6 +6,8 @@ #include #ifndef _WIN32 #include +#include +#include #else #define WIN32_LEAN_AND_MEAN #include @@ -65,6 +67,15 @@ debug_ready = 1; } +long pypy_debug_offset(void) +{ + if (!debug_ready) + return -1; + // note that we deliberately ignore errno, since -1 is fine + // in case this is not a real file + return ftell(pypy_debug_file); +} + void pypy_debug_ensure_opened(void) { if (!debug_ready) diff --git a/pypy/translator/c/src/debug_print.h b/pypy/translator/c/src/debug_print.h --- a/pypy/translator/c/src/debug_print.h +++ b/pypy/translator/c/src/debug_print.h @@ -26,8 +26,9 @@ #define PYPY_DEBUG_FILE pypy_debug_file #define PYPY_DEBUG_START(cat) pypy_debug_start(cat) #define PYPY_DEBUG_STOP(cat) pypy_debug_stop(cat) +#define OP_DEBUG_OFFSET(res) res = pypy_debug_offset() #define OP_HAVE_DEBUG_PRINTS(r) r = (pypy_have_debug_prints & 1) - +#define OP_DEBUG_FLUSH() fflush(pypy_debug_file) /************************************************************/ @@ -35,6 +36,7 @@ void pypy_debug_ensure_opened(void); void pypy_debug_start(const char *category); void pypy_debug_stop(const char *category); +long pypy_debug_offset(void); extern long pypy_have_debug_prints; extern FILE *pypy_debug_file; @@ -51,8 +53,6 @@ # ifdef _WIN32 # define READ_TIMESTAMP(val) QueryPerformanceCounter((LARGE_INTEGER*)&(val)) # else -# include -# include long long pypy_read_timestamp(); diff --git a/pypy/translator/c/src/debug_traceback.h b/pypy/translator/c/src/debug_traceback.h --- a/pypy/translator/c/src/debug_traceback.h +++ b/pypy/translator/c/src/debug_traceback.h @@ -21,7 +21,11 @@ line to the f:17/KeyError line. */ -#define PYPY_DEBUG_TRACEBACK_DEPTH 128 /* a power of two */ +#ifdef RPY_LL_ASSERT +# define PYPY_DEBUG_TRACEBACK_DEPTH 8192 /* a power of two */ +#else +# define PYPY_DEBUG_TRACEBACK_DEPTH 128 /* a power of two */ +#endif #define PYPYDTPOS_RERAISE ((struct pypydtpos_s *) -1) #define PYPYDTSTORE(loc, etype) \ diff --git a/pypy/translator/c/src/float.h b/pypy/translator/c/src/float.h --- a/pypy/translator/c/src/float.h +++ b/pypy/translator/c/src/float.h @@ -43,3 +43,4 @@ #define OP_CAST_FLOAT_TO_LONGLONG(x,r) r = (long long)(x) #define OP_CAST_FLOAT_TO_ULONGLONG(x,r) r = (unsigned long long)(x) #endif + diff --git a/pypy/translator/c/src/stack.h b/pypy/translator/c/src/stack.h --- a/pypy/translator/c/src/stack.h +++ b/pypy/translator/c/src/stack.h @@ -11,15 +11,22 @@ * It is needed to have RPyThreadStaticTLS, too. */ #include "thread.h" -extern char *_LLstacktoobig_stack_start; +extern char *_LLstacktoobig_stack_end; +extern long _LLstacktoobig_stack_length; +extern char _LLstacktoobig_report_error; void LL_stack_unwind(void); char LL_stack_too_big_slowpath(long); /* returns 0 (ok) or 1 (too big) */ +void LL_stack_set_length_fraction(double); /* some macros referenced from pypy.rlib.rstack */ -#define LL_stack_get_start() ((long)_LLstacktoobig_stack_start) -#define LL_stack_get_length() MAX_STACK_SIZE -#define LL_stack_get_start_adr() ((long)&_LLstacktoobig_stack_start) /* JIT */ +#define LL_stack_get_end() ((long)_LLstacktoobig_stack_end) +#define LL_stack_get_length() _LLstacktoobig_stack_length +#define LL_stack_get_end_adr() ((long)&_LLstacktoobig_stack_end) /* JIT */ +#define LL_stack_get_length_adr() ((long)&_LLstacktoobig_stack_length)/* JIT */ + +#define LL_stack_criticalcode_start() (_LLstacktoobig_report_error = 0) +#define LL_stack_criticalcode_stop() (_LLstacktoobig_report_error = 1) #ifdef __GNUC__ @@ -32,93 +39,67 @@ #ifndef PYPY_NOT_MAIN_FILE #include -#ifndef PYPY_NOINLINE -# if defined __GNUC__ -# define PYPY_NOINLINE __attribute__((noinline)) -# else -// add hints for other compilers here ... -# define PYPY_NOINLINE -# endif -#endif +/* the current stack is in the interval [end-length:end]. We assume a + stack that grows downward here. */ +char *_LLstacktoobig_stack_end = NULL; +long _LLstacktoobig_stack_length = MAX_STACK_SIZE; +char _LLstacktoobig_report_error = 1; +static RPyThreadStaticTLS end_tls_key; -long PYPY_NOINLINE _LL_stack_growing_direction(char *parent) +void LL_stack_set_length_fraction(double fraction) { - char local; - if (parent == NULL) - return _LL_stack_growing_direction(&local); - else - return &local - parent; + _LLstacktoobig_stack_length = (long)(MAX_STACK_SIZE * fraction); } -char *_LLstacktoobig_stack_start = NULL; -int stack_direction = 0; -RPyThreadStaticTLS start_tls_key; - char LL_stack_too_big_slowpath(long current) { - long diff; + long diff, max_stack_size; char *baseptr, *curptr = (char*)current; - /* The stack_start variable is updated to match the current value + /* The stack_end variable is updated to match the current value if it is still 0 or if we later find a 'curptr' position - that is below it. The real stack_start pointer is stored in + that is above it. The real stack_end pointer is stored in thread-local storage, but we try to minimize its overhead by - keeping a local copy in _LLstacktoobig_stack_start. */ + keeping a local copy in _LLstacktoobig_stack_end. */ - if (stack_direction == 0) { + if (_LLstacktoobig_stack_end == NULL) { /* not initialized */ /* XXX We assume that initialization is performed early, when there is still only one thread running. This allows us to ignore race conditions here */ - char *errmsg = RPyThreadStaticTLS_Create(&start_tls_key); + char *errmsg = RPyThreadStaticTLS_Create(&end_tls_key); if (errmsg) { /* XXX should we exit the process? */ fprintf(stderr, "Internal PyPy error: %s\n", errmsg); return 1; } - if (_LL_stack_growing_direction(NULL) > 0) - stack_direction = +1; - else - stack_direction = -1; } - baseptr = (char *) RPyThreadStaticTLS_Get(start_tls_key); - if (baseptr != NULL) { - diff = curptr - baseptr; - if (((unsigned long)diff) < (unsigned long)MAX_STACK_SIZE) { + baseptr = (char *) RPyThreadStaticTLS_Get(end_tls_key); + max_stack_size = _LLstacktoobig_stack_length; + if (baseptr == NULL) { + /* first time we see this thread */ + } + else { + diff = baseptr - curptr; + if (((unsigned long)diff) <= (unsigned long)max_stack_size) { /* within bounds, probably just had a thread switch */ - _LLstacktoobig_stack_start = baseptr; + _LLstacktoobig_stack_end = baseptr; return 0; } - - if (stack_direction > 0) { - if (diff < 0 && diff > -MAX_STACK_SIZE) - ; /* stack underflow */ - else - return 1; /* stack overflow (probably) */ + if (((unsigned long)-diff) <= (unsigned long)max_stack_size) { + /* stack underflowed: the initial estimation of + the stack base must be revised */ } - else { - if (diff >= MAX_STACK_SIZE && diff < 2*MAX_STACK_SIZE) - ; /* stack underflow */ - else - return 1; /* stack overflow (probably) */ + else { /* stack overflow (probably) */ + return _LLstacktoobig_report_error; } - /* else we underflowed the stack, which means that - the initial estimation of the stack base must - be revised */ } /* update the stack base pointer to the current value */ - if (stack_direction > 0) { - /* the valid range is [curptr:curptr+MAX_STACK_SIZE] */ - baseptr = curptr; - } - else { - /* the valid range is [curptr-MAX_STACK_SIZE+1:curptr+1] */ - baseptr = curptr - MAX_STACK_SIZE + 1; - } - RPyThreadStaticTLS_Set(start_tls_key, baseptr); - _LLstacktoobig_stack_start = baseptr; + baseptr = curptr; + RPyThreadStaticTLS_Set(end_tls_key, baseptr); + _LLstacktoobig_stack_end = baseptr; return 0; } diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -3,8 +3,8 @@ from pypy.rlib.objectmodel import keepalive_until_here from pypy.rlib.rarithmetic import r_longlong -from pypy.rlib.debug import ll_assert, have_debug_prints -from pypy.rlib.debug import debug_print, debug_start, debug_stop +from pypy.rlib.debug import ll_assert, have_debug_prints, debug_flush +from pypy.rlib.debug import debug_print, debug_start, debug_stop, debug_offset from pypy.translator.translator import TranslationContext from pypy.translator.backendopt import all from pypy.translator.c.genc import CStandaloneBuilder, ExternalCompilationInfo @@ -110,6 +110,7 @@ assert counters == (0,3,2) def test_prof_inline(self): + py.test.skip("broken by 5b0e029514d4, but we don't use it any more") if sys.platform == 'win32': py.test.skip("instrumentation support is unix only for now") def add(a,b): @@ -163,13 +164,13 @@ return 0 from pypy.translator.interactive import Translation # XXX this is mostly a "does not crash option" - t = Translation(entry_point, backend='c', standalone=True, profopt="") + t = Translation(entry_point, backend='c', standalone=True, profopt="100") # no counters t.backendopt() exe = t.compile() out = py.process.cmdexec("%s 500" % exe) assert int(out) == 500*501/2 - t = Translation(entry_point, backend='c', standalone=True, profopt="", + t = Translation(entry_point, backend='c', standalone=True, profopt="100", noprofopt=True) # no counters t.backendopt() @@ -283,12 +284,13 @@ debug_stop ("mycat") if have_debug_prints(): x += "a" debug_print("toplevel") - os.write(1, x + '.\n') + debug_flush() + os.write(1, x + "." + str(debug_offset()) + '.\n') return 0 t, cbuilder = self.compile(entry_point) # check with PYPYLOG undefined out, err = cbuilder.cmdexec("", err=True, env={}) - assert out.strip() == 'got:a.' + assert out.strip() == 'got:a.-1.' assert 'toplevel' in err assert 'mycat' not in err assert 'foo 2 bar 3' not in err @@ -297,7 +299,7 @@ assert 'bok' not in err # check with PYPYLOG defined to an empty string (same as undefined) out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ''}) - assert out.strip() == 'got:a.' + assert out.strip() == 'got:a.-1.' assert 'toplevel' in err assert 'mycat' not in err assert 'foo 2 bar 3' not in err @@ -306,7 +308,7 @@ assert 'bok' not in err # check with PYPYLOG=:- (means print to stderr) out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ':-'}) - assert out.strip() == 'got:bcda.' + assert out.strip() == 'got:bcda.-1.' assert 'toplevel' in err assert '{mycat' in err assert 'mycat}' in err @@ -319,7 +321,8 @@ path = udir.join('test_debug_xxx.log') out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ':%s' % path}) - assert out.strip() == 'got:bcda.' + size = os.stat(str(path)).st_size + assert out.strip() == 'got:bcda.' + str(size) + '.' assert not err assert path.check(file=1) data = path.read() @@ -334,7 +337,8 @@ # check with PYPYLOG=somefilename path = udir.join('test_debug_xxx_prof.log') out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': str(path)}) - assert out.strip() == 'got:a.' + size = os.stat(str(path)).st_size + assert out.strip() == 'got:a.' + str(size) + '.' assert not err assert path.check(file=1) data = path.read() @@ -350,7 +354,8 @@ path = udir.join('test_debug_xxx_myc.log') out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': 'myc:%s' % path}) - assert out.strip() == 'got:bda.' + size = os.stat(str(path)).st_size + assert out.strip() == 'got:bda.' + str(size) + '.' assert not err assert path.check(file=1) data = path.read() @@ -365,7 +370,8 @@ path = udir.join('test_debug_xxx_cat.log') out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': 'cat:%s' % path}) - assert out.strip() == 'got:ca.' + size = os.stat(str(path)).st_size + assert out.strip() == 'got:ca.' + str(size) + '.' assert not err assert path.check(file=1) data = path.read() @@ -379,7 +385,8 @@ path = udir.join('test_debug_xxx_myc_cat2.log') out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': 'myc,cat2:%s' % path}) - assert out.strip() == 'got:bcda.' + size = os.stat(str(path)).st_size + assert out.strip() == 'got:bcda.' + str(size) + '.' assert not err assert path.check(file=1) data = path.read() @@ -400,7 +407,7 @@ path = udir.join('test_debug_does_not_show_up.log') out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ':%s' % path}) - assert out.strip() == 'got:.' + assert out.strip() == 'got:.-1.' assert not err assert path.check(file=0) @@ -682,6 +689,78 @@ out = cbuilder.cmdexec("") assert out.strip() == "hi!" + def test_set_length_fraction(self): + # check for pypy.rlib.rstack._stack_set_length_fraction() + from pypy.rlib.rstack import _stack_set_length_fraction + from pypy.rlib.rstackovf import StackOverflow + class A: + n = 0 + glob = A() + def f(n): + glob.n += 1 + if n <= 0: + return 42 + return f(n+1) + def entry_point(argv): + _stack_set_length_fraction(0.1) + try: + return f(1) + except StackOverflow: + glob.n = 0 + _stack_set_length_fraction(float(argv[1])) + try: + return f(1) + except StackOverflow: + print glob.n + return 0 + t, cbuilder = self.compile(entry_point, stackcheck=True) + counts = {} + for fraction in [0.1, 0.4, 1.0]: + out = cbuilder.cmdexec(str(fraction)) + print 'counts[%s]: %r' % (fraction, out) + counts[fraction] = int(out.strip()) + # + assert counts[1.0] >= 1000 + # ^^^ should actually be much more than 1000 for this small test + assert counts[0.1] < counts[0.4] / 3 + assert counts[0.4] < counts[1.0] / 2 + assert counts[0.1] > counts[0.4] / 7 + assert counts[0.4] > counts[1.0] / 4 + + def test_stack_criticalcode(self): + # check for pypy.rlib.rstack._stack_criticalcode_start/stop() + from pypy.rlib.rstack import _stack_criticalcode_start + from pypy.rlib.rstack import _stack_criticalcode_stop + from pypy.rlib.rstackovf import StackOverflow + class A: + pass + glob = A() + def f(n): + if n <= 0: + return 42 + try: + return f(n+1) + except StackOverflow: + if glob.caught: + print 'Oups! already caught!' + glob.caught = True + _stack_criticalcode_start() + critical(100) # recurse another 100 times here + _stack_criticalcode_stop() + return 789 + def critical(n): + if n > 0: + n = critical(n - 1) + return n - 42 + def entry_point(argv): + glob.caught = False + print f(1) + return 0 + t, cbuilder = self.compile(entry_point, stackcheck=True) + out = cbuilder.cmdexec('') + assert out.strip() == '789' + + class TestMaemo(TestStandalone): def setup_class(cls): py.test.skip("TestMaemo: tests skipped for now") diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py --- a/pypy/translator/cli/opcodes.py +++ b/pypy/translator/cli/opcodes.py @@ -77,7 +77,6 @@ 'cast_ptr_to_weakadr': [PushAllArgs, 'newobj instance void class %s::.ctor(object)' % WEAKREF], 'gc__collect': 'call void class [mscorlib]System.GC::Collect()', 'gc_set_max_heap_size': Ignore, - 'resume_point': Ignore, 'debug_assert': Ignore, 'debug_start_traceback': Ignore, 'debug_record_traceback': Ignore, @@ -85,6 +84,8 @@ 'debug_reraise_traceback': Ignore, 'debug_print_traceback': Ignore, 'debug_print': [DebugPrint], + 'debug_flush': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_FLUSH()'], + 'debug_offset': [PushAllArgs, 'call int32 [pypylib]pypy.runtime.DebugPrint::DEBUG_OFFSET()'], 'debug_start': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_START(string)'], 'debug_stop': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_STOP(string)'], 'have_debug_prints': [PushAllArgs, 'call bool [pypylib]pypy.runtime.DebugPrint::HAVE_DEBUG_PRINTS()'], diff --git a/pypy/translator/cli/src/debug.cs b/pypy/translator/cli/src/debug.cs --- a/pypy/translator/cli/src/debug.cs +++ b/pypy/translator/cli/src/debug.cs @@ -38,6 +38,20 @@ return false; } + public static void DEBUG_FLUSH() + { + if (debug_file != null) + debug_file.Flush(); + } + + public static int DEBUG_OFFSET() + { + StreamWriter sw = debug_file as StreamWriter; + if (sw == null) + return -1; + return (int)sw.BaseStream.Position; // XXX: the cast might be incorrect + } + public static bool HAVE_DEBUG_PRINTS() { if ((have_debug_prints & 1) != 0) { diff --git a/pypy/translator/goal/targetnumpystandalone.py b/pypy/translator/goal/targetnumpystandalone.py new file mode 100644 --- /dev/null +++ b/pypy/translator/goal/targetnumpystandalone.py @@ -0,0 +1,57 @@ + +""" Usage: + +./targetnumpystandalone-c array_size + +Will execute a give numpy bytecode. Arrays will be ranges (in float) modulo 10, +constants would be consecutive starting from one. + +Bytecode should contain letters 'a' 'l' and 'f' so far and be correct +""" + +import time +from pypy.module.micronumpy.numarray import SingleDimArray, Code, compute +from pypy.jit.codewriter.policy import JitPolicy + +def create_array(size): + a = SingleDimArray(size) + for i in range(size): + a.storage[i] = float(i % 10) + return a + +def entry_point(argv): + if len(argv) != 3: + print __doc__ + return 1 + bytecode = argv[1] + for b in bytecode: + if b not in 'alf': + print "WRONG BYTECODE" + print __doc__ + return 2 + try: + size = int(argv[2]) + except ValueError: + print "INVALID LITERAL FOR INT:", argv[2] + print __doc__ + return 3 + no_arrays = bytecode.count('l') + no_floats = bytecode.count('f') + arrays = [] + floats = [] + for i in range(no_arrays): + arrays.append(create_array(size)) + for i in range(no_floats): + floats.append(float(i + 1)) + code = Code(bytecode, arrays, floats) + t0 = time.time() + compute(code) + print "bytecode:", bytecode, "size:", size + print "took:", time.time() - t0 + return 0 + +def target(*args): + return entry_point, None + +def jitpolicy(driver): + return JitPolicy() diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py --- a/pypy/translator/goal/targetpypystandalone.py +++ b/pypy/translator/goal/targetpypystandalone.py @@ -105,7 +105,8 @@ return parser def handle_config(self, config, translateconfig): - if translateconfig._cfgimpl_value_owners['opt'] == 'default': + if (not translateconfig.help and + translateconfig._cfgimpl_value_owners['opt'] == 'default'): raise Exception("You have to specify the --opt level.\n" "Try --opt=2 or --opt=jit, or equivalently -O2 or -Ojit .") self.translateconfig = translateconfig diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -95,7 +95,6 @@ 'gc__collect': jvm.SYSTEMGC, 'gc_set_max_heap_size': Ignore, - 'resume_point': Ignore, 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py --- a/pypy/translator/oosupport/test_template/operations.py +++ b/pypy/translator/oosupport/test_template/operations.py @@ -107,12 +107,6 @@ return res assert self.interpret(fn, [sys.maxint, 2]) == 1 - def test_ignore_resume_point(self): - def fn(x): - rstack.resume_point('hello world', x) - return x - assert self.interpret(fn, [42]) == 42 - def test_rshift(self): def fn(x, y): return x >> y diff --git a/pypy/translator/platform/posix.py b/pypy/translator/platform/posix.py --- a/pypy/translator/platform/posix.py +++ b/pypy/translator/platform/posix.py @@ -129,7 +129,9 @@ m.cfiles = rel_cfiles rel_includedirs = [pypyrel(incldir) for incldir in - self._preprocess_include_dirs(eci.include_dirs)] + self.preprocess_include_dirs(eci.include_dirs)] + rel_libdirs = [pypyrel(libdir) for libdir in + self.preprocess_library_dirs(eci.library_dirs)] m.comment('automatically generated makefile') definitions = [ @@ -139,7 +141,7 @@ ('SOURCES', rel_cfiles), ('OBJECTS', rel_ofiles), ('LIBS', self._libs(eci.libraries)), - ('LIBDIRS', self._libdirs(eci.library_dirs)), + ('LIBDIRS', self._libdirs(rel_libdirs)), ('INCLUDEDIRS', self._includedirs(rel_includedirs)), ('CFLAGS', cflags), ('CFLAGSEXTRA', list(eci.compile_extra)), diff --git a/pypy/translator/platform/test/test_posix.py b/pypy/translator/platform/test/test_posix.py --- a/pypy/translator/platform/test/test_posix.py +++ b/pypy/translator/platform/test/test_posix.py @@ -3,7 +3,7 @@ from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.udir import udir from StringIO import StringIO -import sys +import sys, os def test_echo(): res = host.execute('echo', '42 24') @@ -49,6 +49,19 @@ mk.write() assert 'LINKFILES = /foo/bar.a' in tmpdir.join('Makefile').read() + def test_preprocess_localbase(self): + tmpdir = udir.join('test_preprocess_localbase').ensure(dir=1) + eci = ExternalCompilationInfo() + os.environ['PYPY_LOCALBASE'] = '/foo/baz' + try: + mk = self.platform.gen_makefile(['blip.c'], eci, path=tmpdir) + mk.write() + finally: + del os.environ['PYPY_LOCALBASE'] + Makefile = tmpdir.join('Makefile').read() + assert 'INCLUDEDIRS = -I/foo/baz/include' in Makefile + assert 'LIBDIRS = -L/foo/baz/lib' in Makefile + class TestMaemo(TestMakefile): strict_on_stderr = False diff --git a/pypy/translator/stackless/frame.py b/pypy/translator/stackless/frame.py --- a/pypy/translator/stackless/frame.py +++ b/pypy/translator/stackless/frame.py @@ -104,10 +104,8 @@ class RestartInfo(object): - """A RestartInfo is created (briefly) for each graph that contains - a resume point. - - In addition, a RestartInfo is created for each function that needs + """ + A RestartInfo is created for each function that needs to do explicit stackless manipulations (e.g. code.yield_current_frame_to_caller).""" diff --git a/pypy/translator/stackless/test/test_coroutine_reconstruction.py b/pypy/translator/stackless/test/test_coroutine_reconstruction.py deleted file mode 100644 --- a/pypy/translator/stackless/test/test_coroutine_reconstruction.py +++ /dev/null @@ -1,68 +0,0 @@ -from pypy.rlib import rcoroutine -from pypy.rlib import rstack -from pypy.rlib.rstack import resume_state_create -from pypy.translator.stackless.test.test_transform import llinterp_stackless_function -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rpython.lltypesystem import lltype - -namespace = rcoroutine.make_coroutine_classes(object) -syncstate = namespace['syncstate'] -AbstractThunk = namespace['AbstractThunk'] -Coroutine = namespace['Coroutine'] - -class TestCoroutineReconstruction: - - def setup_meth(self): - syncstate.reset() - - def test_simple_ish(self): - - output = [] - def f(coro, n, x): - if n == 0: - coro.switch() - rstack.resume_point("f_0") - assert rstack.stack_frames_depth() == 9 - return - f(coro, n-1, 2*x) - rstack.resume_point("f_1", coro, n, x) - output.append(x) - - class T(AbstractThunk): - def __init__(self, arg_coro, arg_n, arg_x): - self.arg_coro = arg_coro - self.arg_n = arg_n - self.arg_x = arg_x - def call(self): - f(self.arg_coro, self.arg_n, self.arg_x) - - def example(): - main_coro = Coroutine.getcurrent() - sub_coro = Coroutine() - thunk_f = T(main_coro, 5, 1) - sub_coro.bind(thunk_f) - sub_coro.switch() - - new_coro = Coroutine() - new_thunk_f = T(main_coro, 5, 1) - new_coro.bind(new_thunk_f) - - costate = Coroutine._get_default_costate() - bottom = resume_state_create(None, "yield_current_frame_to_caller_1") - _bind_frame = resume_state_create(bottom, "coroutine__bind", costate) - f_frame_1 = resume_state_create(_bind_frame, "f_1", main_coro, 5, 1) - f_frame_2 = resume_state_create(f_frame_1, "f_1", main_coro, 4, 2) - f_frame_3 = resume_state_create(f_frame_2, "f_1", main_coro, 3, 4) - f_frame_4 = resume_state_create(f_frame_3, "f_1", main_coro, 2, 8) - f_frame_5 = resume_state_create(f_frame_4, "f_1", main_coro, 1, 16) - f_frame_0 = resume_state_create(f_frame_5, "f_0") - switch_frame = resume_state_create(f_frame_0, "coroutine_switch", costate) - - new_coro.frame = switch_frame - - new_coro.switch() - return output == [16, 8, 4, 2, 1] - - res = llinterp_stackless_function(example) - assert res == 1 - diff --git a/pypy/translator/stackless/test/test_resume_point.py b/pypy/translator/stackless/test/test_resume_point.py deleted file mode 100644 --- a/pypy/translator/stackless/test/test_resume_point.py +++ /dev/null @@ -1,457 +0,0 @@ -from pypy.translator.stackless.transform import StacklessTransformer -from pypy.translator.stackless.test.test_transform import llinterp_stackless_function, rtype_stackless_function, one, run_stackless_function -from pypy import conftest -import py -from pypy.rlib import rstack - -def do_backendopt(t): - from pypy.translator.backendopt import all - all.backend_optimizations(t) - -def transform_stackless_function(fn, callback_for_transform=None): - def wrapper(argv): - return fn() - t = rtype_stackless_function(wrapper) - if callback_for_transform: - callback_for_transform(t) - if conftest.option.view: - t.view() - st = StacklessTransformer(t, wrapper, False) - st.transform_all() - -def test_no_call(): - def f(x, y): - x = x-1 - rstack.resume_point("rp0", x, y) - r = x+y - rstack.stack_unwind() - return r - def example(): - v1 = f(one(),one()+one()) - state = rstack.resume_state_create(None, "rp0", one(), one()+one()+one()) - v2 = rstack.resume_state_invoke(int, state) - return v1*10 + v2 -## transform_stackless_function(example) - res = llinterp_stackless_function(example, assert_unwind=False) - assert res == 24 - -def test_bogus_restart_state_create(): - def f(x, y): - x = x-1 - rstack.resume_point("rp0", x, y) - return x+y - def example(): - v1 = f(one(),one()+one()) - state = rstack.resume_state_create(None, "rp0", one()) - return v1 - info = py.test.raises(AssertionError, "transform_stackless_function(example)") - assert 'rp0' in str(info.value) - - -def test_call(): - def g(x,y): - return x*y - def f(x, y): - z = g(x,y) - rstack.resume_point("rp1", y, returns=z) - return z+y - def example(): - v1 = f(one(),one()+one()) - s = rstack.resume_state_create(None, "rp1", 5*one()) - v2 = rstack.resume_state_invoke(int, s, returning=one()*7) - return v1*100 + v2 - res = llinterp_stackless_function(example) - assert res == 412 - res = run_stackless_function(example) - assert res == 412 - -def test_returns_with_instance(): - class C: - def __init__(self, x): - self.x = x - def g(x): - return C(x+1) - def f(x, y): - r = g(x) - rstack.resume_point("rp1", y, returns=r) - return r.x + y - def example(): - v1 = f(one(),one()+one()) - s = rstack.resume_state_create(None, "rp1", 5*one()) - v2 = rstack.resume_state_invoke(int, s, returning=C(one()*3)) - return v1*100 + v2 - res = llinterp_stackless_function(example, assert_unwind=False) - assert res == 408 - res = run_stackless_function(example) - assert res == 408 - -def test_call_uncovered(): - def g(x,y): - return x*y - def f(x, y): - z = g(x,y) - rstack.resume_point("rp1", y, returns=z) - return z+y+x - def example(): - f(one(),one()+one()) - return 0 - e = py.test.raises(Exception, transform_stackless_function, example) - msg, = e.value.args - assert msg.startswith('not covered needed value at resume_point') and 'rp1' in msg - -def test_chained_states(): - def g(x, y): - x += 1 - rstack.resume_point("rp1", x, y) - return x + y - def f(x, y, z): - y += 1 - r = g(x, y) - rstack.resume_point("rp2", z, returns=r) - return r + z - def example(): - v1 = f(one(), 2*one(), 3*one()) - s2 = rstack.resume_state_create(None, "rp2", 2*one()) - s1 = rstack.resume_state_create(s2, "rp1", 4*one(), 5*one()) - return 100*v1 + rstack.resume_state_invoke(int, s1) - res = llinterp_stackless_function(example) - assert res == 811 - res = run_stackless_function(example) - assert res == 811 - -def test_return_instance(): - class C: - pass - def g(x): - c = C() - c.x = x + 1 - rstack.resume_point("rp1", c) - return c - def f(x, y): - r = g(x) - rstack.resume_point("rp2", y, returns=r) - return r.x + y - def example(): - v1 = f(one(), 2*one()) - s2 = rstack.resume_state_create(None, "rp2", 2*one()) - c = C() - c.x = 4*one() - s1 = rstack.resume_state_create(s2, "rp1", c) - return v1*100 + rstack.resume_state_invoke(int, s1) - res = llinterp_stackless_function(example) - assert res == 406 - res = run_stackless_function(example) - assert res == 406 - -def test_really_return_instance(): - class C: - pass - def g(x): - c = C() - c.x = x + 1 - rstack.resume_point("rp1", c) - return c - def example(): - v1 = g(one()).x - c = C() - c.x = 4*one() - s1 = rstack.resume_state_create(None, "rp1", c) - return v1*100 + rstack.resume_state_invoke(C, s1).x - res = llinterp_stackless_function(example) - assert res == 204 - res = run_stackless_function(example) - assert res == 204 - -def test_resume_and_raise(): - def g(x): - rstack.resume_point("rp0", x) - if x == 0: - raise KeyError - return x + 1 - def example(): - v1 = g(one()) - s = rstack.resume_state_create(None, "rp0", one()-1) - try: - v2 = rstack.resume_state_invoke(int, s) - except KeyError: - v2 = 42 - return v1*100 + v2 - res = llinterp_stackless_function(example) - assert res == 242 - res = run_stackless_function(example) - assert res == 242 - -def test_resume_and_raise_and_catch(): - def g(x): - rstack.resume_point("rp0", x) - if x == 0: - raise KeyError - return x + 1 - def f(x): - x = x - 1 - try: - r = g(x) - rstack.resume_point("rp1", returns=r) - except KeyError: - r = 42 - return r - 1 - def example(): - v1 = f(one()+one()) - s1 = rstack.resume_state_create(None, "rp1") - s0 = rstack.resume_state_create(s1, "rp0", one()-1) - v2 = rstack.resume_state_invoke(int, s0) - return v1*100 + v2 - res = llinterp_stackless_function(example) - assert res == 141 - res = run_stackless_function(example) - assert res == 141 - -def test_invoke_raising(): - def g(x): - rstack.resume_point("rp0", x) - return x + 1 - def f(x): - x = x - 1 - try: - r = g(x) - rstack.resume_point("rp1", returns=r) - except KeyError: - r = 42 - return r - 1 - def example(): - v1 = f(one()+one()) - s1 = rstack.resume_state_create(None, "rp1") - s0 = rstack.resume_state_create(s1, "rp0", 0) - v2 = rstack.resume_state_invoke(int, s0, raising=KeyError()) - return v1*100 + v2 - res = llinterp_stackless_function(example) - assert res == 141 - res = run_stackless_function(example) - assert res == 141 - - -def test_finally(): - def f(x): - rstack.resume_point("rp1", x) - return 1/x - def in_finally(x): - rstack.resume_point("rp1.5", x) - return 2/x - def g(x): - r = y = 0 - r += f(x) - try: - y = f(x) - rstack.resume_point("rp0", x, r, returns=y) - finally: - r += in_finally(x) - return r + y - def example(): - return g(one()) - transform_stackless_function(example) - -def test_except(): - py.test.skip("please don't write code like this") - def f(x): - rstack.resume_point("rp1", x) - return 1/x - def g(x): - r = y = 0 - r += f(x) - try: - y = f(x) - rstack.resume_point("rp0", x, r, y, returns=y) - except ZeroDivisionError: - r += f(x) - return r + y - def example(): - return g(one()) - transform_stackless_function(example) - -def test_using_pointers(): - from pypy.interpreter.miscutils import FixedStack - class Arguments: - def __init__(self, a, b, c, d, e): - pass - class W_Root: - pass - class FakeFrame: - def __init__(self, space): - self.space = space - self.valuestack = FixedStack() - self.valuestack.setup(10) - self.valuestack.push(W_Root()) - class FakeSpace: - def call_args(self, args, kw): - return W_Root() - def str_w(self, ob): - return 'a string' - def call_function(f, oparg, w_star=None, w_starstar=None): - n_arguments = oparg & 0xff - n_keywords = (oparg>>8) & 0xff - keywords = None - if n_keywords: - keywords = {} - for i in range(n_keywords): - w_value = f.valuestack.pop() - w_key = f.valuestack.pop() - key = f.space.str_w(w_key) - keywords[key] = w_value - arguments = [None] * n_arguments - for i in range(n_arguments - 1, -1, -1): - arguments[i] = f.valuestack.pop() - args = Arguments(f.space, arguments, keywords, w_star, w_starstar) - w_function = f.valuestack.pop() - w_result = f.space.call_args(w_function, args) - rstack.resume_point("call_function", f, returns=w_result) - f.valuestack.push(w_result) - def example(): - s = FakeSpace() - f = FakeFrame(s) - call_function(f, 100, W_Root(), W_Root()) - return one() - transform_stackless_function(example, do_backendopt) - -def test_always_raising(): - def g(out): - out.append(3) - rstack.resume_point('g') - raise KeyError - - def h(out): - try: - # g is always raising, good enough to put the resume point - # before, instead of after! - rstack.resume_point('h', out) - g(out) - except KeyError: - return 0 - return -1 - - def example(): - out = [] - x = h(out) - l = len(out) - chain = rstack.resume_state_create(None, 'h', out) - chain = rstack.resume_state_create(chain, 'g') - x += rstack.resume_state_invoke(int, chain) - l += len(out) - return l*100+x - - res = llinterp_stackless_function(example) - assert res == 200 - res = run_stackless_function(example) - assert res == 200 - -def test_more_mess(): - from pypy.interpreter.miscutils import Stack - - def new_framestack(): - return Stack() - - class FakeFrame: - pass - class FakeSlpFrame: - def switch(self): - rstack.stack_unwind() - return FakeSlpFrame() - - class FakeCoState: - def update(self, new): - self.last, self.current = self.current, new - frame, new.frame = new.frame, None - return frame - def do_things_to_do(self): - self.do_things_to_do() - - costate = FakeCoState() - costate.current = None - - class FakeExecutionContext: - def __init__(self): - self.space = space - self.framestack = new_framestack() - - def subcontext_new(coobj): - coobj.framestack = new_framestack() - subcontext_new = staticmethod(subcontext_new) - - def subcontext_enter(self, next): - self.framestack = next.framestack - - def subcontext_leave(self, current): - current.framestack = self.framestack - - class FakeSpace: - def __init__(self): - self.ec = None - def getexecutioncontext(self): - if self.ec is None: - self.ec = FakeExecutionContext() - return self.ec - - space = FakeSpace() - - class MainCoroutineGetter(object): - def __init__(self): - self.costate = None - def _get_default_costate(self): - if self.costate is None: - costate = FakeCoState() - self.costate = costate - return costate - return self.costate - - main_coroutine_getter = MainCoroutineGetter() - - class FakeCoroutine: - def __init__(self): - self.frame = None - self.costate = costate - space.getexecutioncontext().subcontext_new(self) - - def switch(self): - if self.frame is None: - raise RuntimeError - state = self.costate - incoming_frame = state.update(self).switch() - rstack.resume_point("coroutine_switch", self, state, returns=incoming_frame) - left = state.last - left.frame = incoming_frame - left.goodbye() - self.hello() - #main_coroutine_getter._get_default_costate().do_things_to_do() - - def hello(self): - pass - - def goodbye(self): - pass - - class FakeAppCoroutine(FakeCoroutine): - def __init__(self): - FakeCoroutine.__init__(self) - self.space = space - - def hello(self): - ec = self.space.getexecutioncontext() - ec.subcontext_enter(self) - - def goodbye(self): - ec = self.space.getexecutioncontext() - ec.subcontext_leave(self) - - def example(): - coro = FakeAppCoroutine() - othercoro = FakeCoroutine() - othercoro.frame = FakeSlpFrame() - if one(): - coro.frame = FakeSlpFrame() - if one() - one(): - coro.costate = FakeCoState() - coro.costate.last = coro.costate.current = othercoro - space.getexecutioncontext().framestack.push(FakeFrame()) - coro.switch() - return one() - - transform_stackless_function(example, do_backendopt) diff --git a/pypy/translator/stackless/transform.py b/pypy/translator/stackless/transform.py --- a/pypy/translator/stackless/transform.py +++ b/pypy/translator/stackless/transform.py @@ -112,19 +112,6 @@ # abort() # return retval + x + 1 -class SymbolicRestartNumber(ComputedIntSymbolic): - def __init__(self, label, value=None): - ComputedIntSymbolic.__init__(self, self._getvalue) - self.label = label - self.value = value - - def _getvalue(self): - # argh, we'd like to assert-fail if value is None here, but we - # get called too early (during databasing) for this to be - # valid. so we might return None and rely on the database - # checking that this only happens before the database is - # complete. - return self.value # the strategy for sharing parts of the resume code: # @@ -248,8 +235,7 @@ self.stackless_gc = stackless_gc def analyze_simple_operation(self, op, graphinfo): - if op.opname in ('yield_current_frame_to_caller', 'resume_point', - 'resume_state_invoke', 'resume_state_create', 'stack_frames_depth', + if op.opname in ('yield_current_frame_to_caller', 'stack_frames_depth', 'stack_switch', 'stack_unwind', 'stack_capture', 'get_stack_depth_limit', 'set_stack_depth_limit'): return True @@ -458,24 +444,11 @@ self.is_finished = False - # only for sanity checking, but still very very important - self.explicit_resume_point_data = {} - - self.symbolic_restart_numbers = {} - - # register the prebuilt restartinfos & give them names for use - # with resume_state_create # the mauling of frame_typer internals should be a method on FrameTyper. for restartinfo in frame.RestartInfo.prebuilt: name = restartinfo.func_or_graph.__name__ for i in range(len(restartinfo.frame_types)): - label = name + '_' + str(i) - assert label not in self.symbolic_restart_numbers - # XXX we think this is right: - self.symbolic_restart_numbers[label] = SymbolicRestartNumber( - label, len(self.masterarray1) + i) frame_type = restartinfo.frame_types[i] - self.explicit_resume_point_data[label] = frame_type self.frametyper.ensure_frame_type_for_types(frame_type) self.register_restart_info(restartinfo) @@ -589,156 +562,6 @@ # yes convertblock.exits[0].args[index] = newvar # end ouch! - - def handle_resume_point(self, block, i): - # in some circumstances we might be able to reuse - # an already inserted resume point - op = block.operations[i] - if i == len(block.operations) - 1: - link = block.exits[0] - nextblock = None - else: - link = split_block(None, block, i+1) - i = 0 - nextblock = link.target - - label = op.args[0].value - - parms = op.args[1:] - if not isinstance(parms[0], model.Variable): - assert parms[0].value is None - parms[0] = None - args = vars_to_save(block) - for a in args: - if a not in parms: - raise Exception, "not covered needed value at resume_point %r"%(label,) - if parms[0] is not None: # returns= case - res = parms[0] - args = [arg for arg in args if arg is not res] - else: - args = args - res = op.result - - (FRAME_TYPE, varsforcall, saver) = self.frametyper.frame_type_for_vars(parms[1:]) - - if label in self.explicit_resume_point_data: - OTHER_TYPE = self.explicit_resume_point_data[label] - assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,) - else: - self.explicit_resume_point_data[label] = FRAME_TYPE - - self._make_resume_handling(FRAME_TYPE, varsforcall, res, block.exits) - - restart_number = len(self.masterarray1) + len(self.resume_blocks) - 1 - - if label in self.symbolic_restart_numbers: - symb = self.symbolic_restart_numbers[label] - assert symb.value is None - symb.value = restart_number - else: - symb = SymbolicRestartNumber(label, restart_number) - self.symbolic_restart_numbers[label] = symb - - return nextblock - - def handle_resume_state_create(self, block, i): - op = block.operations[i] - llops = LowLevelOpList() - label = op.args[1].value - parms = op.args[2:] - FRAME_TYPE, varsforcall, saver = self.frametyper.frame_type_for_vars(parms) - - if label in self.explicit_resume_point_data: - OTHER_TYPE = self.explicit_resume_point_data[label] - assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,) - else: - self.explicit_resume_point_data[label] = FRAME_TYPE - - if label in self.symbolic_restart_numbers: - symb = self.symbolic_restart_numbers[label] - else: - symb = SymbolicRestartNumber(label) - self.symbolic_restart_numbers[label] = symb - - # this is rather insane: we create an exception object, pass - # it to the saving function, then read the thus created state - # out of and then clear global_state.top - c_EXC = model.Constant(self.unwind_exception_type.TO, lltype.Void) - c_flags = model.Constant({'flavor': 'gc'}, lltype.Void) - v_exc = llops.genop('malloc', [c_EXC, c_flags], - resulttype = self.unwind_exception_type) - llops.genop('setfield', [v_exc, - model.Constant('inst_depth', lltype.Void), - model.Constant(0, lltype.Signed)]) - - realvarsforcall = [] - for v in varsforcall: - if v.concretetype != lltype.Void: - realvarsforcall.append(gen_cast(llops, storage_type(v.concretetype), v)) - - llops.genop('direct_call', - [model.Constant(saver, lltype.typeOf(saver)), v_exc, - model.Constant(symb, lltype.Signed)] + realvarsforcall, - resulttype = lltype.Void) - v_state = varoftype(lltype.Ptr(frame.STATE_HEADER)) - v_state_hdr = llops.genop("getfield", - [self.ll_global_state, self.c_inst_top_name], - resulttype=lltype.Ptr(STATE_HEADER)) - v_state = gen_cast(llops, lltype.Ptr(FRAME_TYPE), v_state_hdr) - llops.genop("setfield", - [self.ll_global_state, self.c_inst_top_name, self.c_null_state]) - - v_prevstate = gen_cast(llops, lltype.Ptr(frame.STATE_HEADER), op.args[0]) - llops.genop('direct_call', [self.set_back_pointer_ptr, - v_state_hdr, v_prevstate]) - llops.append(model.SpaceOperation('cast_opaque_ptr', [v_state_hdr], op.result)) - block.operations[i:i+1] = llops - - def handle_resume_state_invoke(self, block): - op = block.operations[-1] - assert op.opname == 'resume_state_invoke' - # some commentary. - # - # we don't want to write 155 or so different versions of - # resume_after_foo that appear to the annotator to return - # different types. we take advantage of the fact that this - # function always raises UnwindException and have it (appear - # to) return Void. then to placate all the other machinery, - # we pass a constant zero-of-the-appropriate-type along the - # non-exceptional link (which we know will never be taken). - # Nota Bene: only mutate a COPY of the non-exceptional link - # because the non-exceptional link has been stored in - # self.resume_blocks and we don't want a constant "zero" in - # there. - v_state = op.args[0] - v_returning = op.args[1] - v_raising = op.args[2] - llops = LowLevelOpList() - - if v_raising.concretetype == lltype.Void: - erased_type = storage_type(v_returning.concretetype) - resume_after_ptr = self.resume_afters[erased_type] - v_param = v_returning - else: - assert v_returning.concretetype == lltype.Void - erased_type = self.exception_type - resume_after_ptr = self.resume_after_raising_ptr - v_param = v_raising - - if erased_type != v_param.concretetype: - v_param = gen_cast(llops, erased_type, v_param) - llops.genop('direct_call', [resume_after_ptr, v_state, v_param], - resulttype=lltype.Void) - - del block.operations[-1] - block.operations.extend(llops) - - noexclink = block.exits[0].copy() - realrettype = op.result.concretetype - for i, a in enumerate(noexclink.args): - if a is op.result: - noexclink.args[i] = model.Constant(realrettype._defl(), realrettype) - block.recloseblock(*((noexclink,) + block.exits[1:])) def insert_unwind_handling(self, block, i): # for the case where we are resuming to an except: @@ -821,19 +644,8 @@ op = replace_with_call(self.operation_replacement[op.opname]) stackless_op = True - if op.opname == 'resume_state_create': - self.handle_resume_state_create(block, i) - continue # go back and look at that malloc - if (op.opname in ('direct_call', 'indirect_call') or self.analyzer.analyze(op)): - if op.opname == 'resume_point': - block = self.handle_resume_point(block, i) - if block is None: - return - else: - i = 0 - continue if not stackless_op and not self.analyzer.analyze(op): i += 1 @@ -849,9 +661,7 @@ continue nextblock = self.insert_unwind_handling(block, i) - if op.opname == 'resume_state_invoke': - self.handle_resume_state_invoke(block) - + if nextblock is None: return diff --git a/pypy/translator/transform.py b/pypy/translator/transform.py --- a/pypy/translator/transform.py +++ b/pypy/translator/transform.py @@ -175,41 +175,6 @@ # make sure the bookkeeper knows about AssertionError self.bookkeeper.getuniqueclassdef(AssertionError) -def insert_stackcheck(ann): - from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles - edges = [] - graphs_to_patch = {} - for callposition, (caller, callee) in ann.translator.callgraph.items(): - if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False): - graphs_to_patch[callee] = True - continue - edge = Edge(caller, callee) - edge.callposition = callposition - edges.append(edge) - - for graph in graphs_to_patch: - v = Variable() - ann.setbinding(v, annmodel.SomeImpossibleValue()) - unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v) - graph.startblock.operations.insert(0, unwind_op) - - edgedict = make_edge_dict(edges) - for edge in break_cycles(edgedict, edgedict): - caller = edge.source - _, _, call_tag = edge.callposition - if call_tag: - caller_block, _ = call_tag - else: - ann.warning("cycle detected but no information on where to insert " - "stack_check()") - continue - # caller block found, insert stack_check() - v = Variable() - # push annotation on v - ann.setbinding(v, annmodel.SomeImpossibleValue()) - unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v) - caller_block.operations.insert(0, unwind_op) - def insert_ll_stackcheck(translator): from pypy.translator.backendopt.support import find_calls_from from pypy.rlib.rstack import stack_check From noreply at buildbot.pypy.org Fri Jul 1 16:16:03 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 1 Jul 2011 16:16:03 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: Translation fix. Message-ID: <20110701141603.528228293A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: arm-backend-2 Changeset: r45232:9b56c79751ff Date: 2011-06-04 07:26 +0200 http://bitbucket.org/pypy/pypy/changeset/9b56c79751ff/ Log: Translation fix. diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py --- a/pypy/module/cpyext/intobject.py +++ b/pypy/module/cpyext/intobject.py @@ -73,12 +73,14 @@ space.wrap("an integer is required, got NULL")) return space.int_w(w_obj) # XXX this is wrong on win64 +LONG_MAX = int(LONG_TEST - 1) + @cpython_api([rffi.SIZE_T], PyObject) def PyInt_FromSize_t(space, ival): """Create a new integer object with a value of ival. If the value exceeds LONG_MAX, a long integer object is returned. """ - if ival < LONG_TEST: + if ival <= LONG_MAX: return space.wrap(intmask(ival)) return space.wrap(ival) From noreply at buildbot.pypy.org Fri Jul 1 16:23:29 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 16:23:29 +0200 (CEST) Subject: [pypy-commit] pypy default: add warnings Message-ID: <20110701142329.2A1578293A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45233:cfb5827cec9c Date: 2011-07-01 16:30 +0200 http://bitbucket.org/pypy/pypy/changeset/cfb5827cec9c/ Log: add warnings diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -21,8 +21,10 @@ func._elidable_function_ = True return func -# keep "purefunction" for not breaking external projects, deprecated -purefunction = elidable +def purefunction(*args, **args): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **args) def hint(x, **kwds): """ Hint for the JIT @@ -88,8 +90,11 @@ return result return decorator -# keep "purefunction_promote" for not breaking external projects, deprecated -purefunction_promote = elidable_promote +def purefunction_promote(*args, **args): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **args) + def oopspec(spec): def decorator(func): From noreply at buildbot.pypy.org Fri Jul 1 16:28:27 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 1 Jul 2011 16:28:27 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: finetuning Message-ID: <20110701142827.B1EC38293A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: extradoc Changeset: r3818:795cd344f88e Date: 2011-07-01 16:35 +0200 http://bitbucket.org/pypy/extradoc/changeset/795cd344f88e/ Log: finetuning diff --git a/talk/iwtc11/paper.tex b/talk/iwtc11/paper.tex --- a/talk/iwtc11/paper.tex +++ b/talk/iwtc11/paper.tex @@ -122,7 +122,7 @@ \begin{abstract} One of the nice properties of a tracing JIT is that many of its optimization -are simple requiring one forward pass. This is not true for loop-invariant code +are simple requiring one forward pass only. This is not true for loop-invariant code motion which is a very important optimization for code with tight kernels. In this paper we present a scheme for making simple optimizations loop-aware by using a simple pre-processing step on the trace and not changing the @@ -246,7 +246,7 @@ \end{lstlisting} The iteration of the loop that was peeled off (lines 1-4) is called the -\emph{preamble}, the loop afterwards the \emph{peeled loop}. +\emph{preamble}, the loop afterwards (lines 6-9) the \emph{peeled loop}. Now the optimizer optimizes both of these two iterations of the loop together, disregarding the \lstinline{jump} and the label in lines 4-6. Doing this, common @@ -438,7 +438,7 @@ \section{Making Trace Optimizations Loop Aware} -Before the trace is passed to a backend compiling it into machine code +Before a trace is passed to the backend compiling it into machine code it is optimized to achieve better performance. One goal of that is to move operations out of the loop making them executed only once @@ -446,8 +446,8 @@ leaves the loop body intact, but prefixes it with one iteration of the loop. This operation by itself will not achieve anything. But if it is combined with other optimizations it can increase the effectiveness of -those optimizations. For many optimization of interest some care has -to be taken when they are combined with loop peeling. This is +those optimizations. For many optimization of interest only a few +additional details has to be considered when they are combined with loop peeling. These are described below by explaining the loop peeling optimization followed by a set of other optimizations and how they interact with loop peeling. From noreply at buildbot.pypy.org Fri Jul 1 16:46:40 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 16:46:40 +0200 (CEST) Subject: [pypy-commit] pypy default: grumble, nonsense Message-ID: <20110701144640.D5B518293A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45234:582d4749d05b Date: 2011-07-01 16:53 +0200 http://bitbucket.org/pypy/pypy/changeset/582d4749d05b/ Log: grumble, nonsense diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -21,10 +21,10 @@ func._elidable_function_ = True return func -def purefunction(*args, **args): +def purefunction(*args, **kwargs): import warnings warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) - return elidable(*args, **args) + return elidable(*args, **kwargs) def hint(x, **kwds): """ Hint for the JIT @@ -90,10 +90,10 @@ return result return decorator -def purefunction_promote(*args, **args): +def purefunction_promote(*args, **kwargs): import warnings warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) - return elidable_promote(*args, **args) + return elidable_promote(*args, **kwargs) def oopspec(spec): From noreply at buildbot.pypy.org Fri Jul 1 17:10:22 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Fri, 1 Jul 2011 17:10:22 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: yet another hack on test_all Message-ID: <20110701151022.2792E8293D@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45237:ee16ef84f5b9 Date: 2011-07-01 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/ee16ef84f5b9/ Log: yet another hack on test_all diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -76,7 +76,6 @@ n &= LONG_MASK if n >= LONG_TEST: n -= 2*LONG_TEST - # return int(n) return n def longlongmask(n): @@ -117,7 +116,6 @@ assert not isinstance(r, r_uint), "unexpected ovf check on unsigned" assert not isinstance(r, r_longlong), "ovfcheck not supported on r_longlong" assert not isinstance(r,r_ulonglong),"ovfcheck not supported on r_ulonglong" - # if type(r) is long: if abs(r) > sys.maxint: raise OverflowError, "signed integer expression did overflow" return r From noreply at buildbot.pypy.org Fri Jul 1 18:43:30 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 18:43:30 +0200 (CEST) Subject: [pypy-commit] pypy dict-strategies: fix botched merge Message-ID: <20110701164330.ED6678293D@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: dict-strategies Changeset: r45238:13fc1a92e93b Date: 2011-07-01 18:50 +0200 http://bitbucket.org/pypy/pypy/changeset/13fc1a92e93b/ Log: fix botched merge diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -58,7 +58,6 @@ self.space = space self.strategy = strategy self.dstorage = storage - force_non_null=True) def __repr__(w_self): """ representation for debugging purposes """ From noreply at buildbot.pypy.org Fri Jul 1 19:16:25 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 19:16:25 +0200 (CEST) Subject: [pypy-commit] pypy default: add a shortcut promote(x) for x = hint(x, promote=True). replace most places Message-ID: <20110701171625.8298E8293D@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45239:b1ffa113af6d Date: 2011-07-01 19:23 +0200 http://bitbucket.org/pypy/pypy/changeset/b1ffa113af6d/ Log: add a shortcut promote(x) for x = hint(x, promote=True). replace most places that use the latter with the former. Cannot replace them all, due to some issues around provable non-negativeness. diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant, elidable +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -309,7 +309,7 @@ return x * y externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -1252,7 +1252,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1312,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1343,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1496,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1531,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1595,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1817,7 +1817,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2002,7 +2002,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2047,7 +2047,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2082,7 +2082,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2139,7 +2139,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2208,7 +2208,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, elidable +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -28,7 +28,7 @@ if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) + self = jit.promote(self) return self._getcell_makenew(key) return self.content.get(key, None) diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -322,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,7 +9,7 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, elidable_promote, we_are_jitted +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint @@ -351,9 +351,9 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup @@ -447,8 +447,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +774,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -41,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -253,7 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) From noreply at buildbot.pypy.org Fri Jul 1 19:39:11 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 19:39:11 +0200 (CEST) Subject: [pypy-commit] pypy dict-strategies: another difference with dict strategies Message-ID: <20110701173911.129AC8293D@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: dict-strategies Changeset: r45240:91a6ba5c733e Date: 2011-07-01 19:46 +0200 http://bitbucket.org/pypy/pypy/changeset/91a6ba5c733e/ Log: another difference with dict strategies diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -72,7 +72,7 @@ # away # XXX could be improved ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_isnull"] + assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value"] # # two LOAD_GLOBAL of f, the second is folded away ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') From noreply at buildbot.pypy.org Fri Jul 1 21:00:09 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 21:00:09 +0200 (CEST) Subject: [pypy-commit] pypy dict-strategies: add popitem for mapdicts Message-ID: <20110701190009.9C92D8293D@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: dict-strategies Changeset: r45241:481069cbe647 Date: 2011-07-01 21:07 +0200 http://bitbucket.org/pypy/pypy/changeset/481069cbe647/ Log: add popitem for mapdicts diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -668,6 +668,14 @@ new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) + def _clear_fields(self, w_dict): self.w_obj = None diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -468,6 +468,19 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + + def test_slot_name_conflict(self): class A(object): From noreply at buildbot.pypy.org Fri Jul 1 21:01:28 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 21:01:28 +0200 (CEST) Subject: [pypy-commit] pypy dict-strategies: no longer needed Message-ID: <20110701190128.90B8C8293D@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: dict-strategies Changeset: r45242:cd3882d509f3 Date: 2011-07-01 21:08 +0200 http://bitbucket.org/pypy/pypy/changeset/cd3882d509f3/ Log: no longer needed diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -115,7 +115,7 @@ # ---------------------- loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i9 = int_lt(i8, i7) + i9 = int_lt(i7, i8) guard_true(i9, descr=.*) guard_not_invalidated(descr=.*) i11 = int_add(i8, 1) @@ -124,7 +124,7 @@ p20 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p20, i11, descr=) setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i8, descr=) """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -148,18 +148,6 @@ w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new) - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): - if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None - class ModuleDictIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) From noreply at buildbot.pypy.org Fri Jul 1 21:05:42 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 21:05:42 +0200 (CEST) Subject: [pypy-commit] pypy dict-strategies: same here Message-ID: <20110701190542.08B3A8293D@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: dict-strategies Changeset: r45243:25b860fc29de Date: 2011-07-01 21:12 +0200 http://bitbucket.org/pypy/pypy/changeset/25b860fc29de/ Log: same here diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -676,9 +676,6 @@ self.delitem(w_dict, w_key) return (w_key, w_value) - def _clear_fields(self, w_dict): - self.w_obj = None - def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() new_obj = map.materialize_r_dict(space, obj, dict_w) From noreply at buildbot.pypy.org Fri Jul 1 21:16:17 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 1 Jul 2011 21:16:17 +0200 (CEST) Subject: [pypy-commit] pypy default: Rollback adding __objclass__ to method, it had incorrect semantics. Message-ID: <20110701191617.A97E38293D@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45244:7481ef60be9f Date: 2011-07-01 12:22 -0700 http://bitbucket.org/pypy/pypy/changeset/7481ef60be9f/ Log: Rollback adding __objclass__ to method, it had incorrect semantics. diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -214,15 +214,6 @@ bm = A().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self - assert bm.im_class is A - if '__pypy__' in sys.builtin_module_names: - assert bm.__objclass__ is A assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) - l = [] - assert l.append.__self__ is l - if '__pypy__' in sys.builtin_module_names: - assert l.append.__objclass__ is list - assert l.__add__.__self__ is l - assert l.__add__.__objclass__ is list diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -771,7 +771,6 @@ im_self = interp_attrproperty_w('w_instance', cls=Method), __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), - __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, From noreply at buildbot.pypy.org Fri Jul 1 21:16:19 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 1 Jul 2011 21:16:19 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream. Message-ID: <20110701191619.3691C8293D@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45245:dde728abfaa5 Date: 2011-07-01 12:23 -0700 http://bitbucket.org/pypy/pypy/changeset/dde728abfaa5/ Log: merged upstream. diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -357,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -385,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -92,7 +92,7 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -847,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1233,7 +1233,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -1252,7 +1252,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1312,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1343,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1496,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1531,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1595,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1817,7 +1817,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2002,7 +2002,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2047,7 +2047,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2082,7 +2082,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2139,7 +2139,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2208,7 +2208,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -28,11 +28,11 @@ if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) + self = jit.promote(self) return self._getcell_makenew(key) return self.content.get(key, None) - @jit.purefunction + @jit.elidable def _getcell_makenew(self, key): return self.content.setdefault(key, ModuleCell()) diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -322,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -447,8 +447,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +774,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +820,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -74,7 +74,7 @@ raise KeyError @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) @@ -253,7 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,8 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - # it's pure but it does not look like it - @purefunction + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -342,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -352,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -370,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -387,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -428,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -451,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -471,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -487,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -504,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -516,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -527,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -595,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -718,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -816,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -831,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -842,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError From noreply at buildbot.pypy.org Fri Jul 1 22:34:35 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 22:34:35 +0200 (CEST) Subject: [pypy-commit] pypy dict-strategies: this test is passing on trunk completely by chance. make it more robust Message-ID: <20110701203435.18E2B8293E@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: dict-strategies Changeset: r45246:7ab27311fa65 Date: 2011-07-01 22:41 +0200 http://bitbucket.org/pypy/pypy/changeset/7ab27311fa65/ Log: this test is passing on trunk completely by chance. make it more robust diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -209,6 +209,26 @@ i16 = force_token() """) + def test_kwargs_empty(self): + def main(x): + def g(**args): + return len(args) + 1 + # + s = 0 + d = {} + i = 0 + while i < x: + s += g(**d) # ID: call + i += 1 + return s + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('call') + ops = log.opnames(loop.ops_by_id('call')) + guards = [ops for ops in ops if ops.startswith('guard')] + assert guards == ["guard_no_overflow"] + def test_kwargs(self): # this is not a very precise test, could be improved def main(x): @@ -216,20 +236,24 @@ return len(args) # s = 0 - d = {} - for i in range(x): + d = {"a": 1} + i = 0 + while i < x: s += g(**d) # ID: call d[str(i)] = i if i % 100 == 99: - d = {} + d = {"a": 1} + i += 1 return s # log = self.run(main, [1000]) - assert log.result == 49500 + assert log.result == 50500 loop, = log.loops_by_id('call') + print loop.ops_by_id('call') ops = log.opnames(loop.ops_by_id('call')) guards = [ops for ops in ops if ops.startswith('guard')] - assert len(guards) <= 5 + print guards + assert len(guards) <= 20 def test_stararg_virtual(self): def main(x): From noreply at buildbot.pypy.org Fri Jul 1 22:51:04 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 22:51:04 +0200 (CEST) Subject: [pypy-commit] pypy dict-strategies: close to be merged branch Message-ID: <20110701205104.CE9248293E@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: dict-strategies Changeset: r45247:c6bfe0a2263f Date: 2011-07-01 22:43 +0200 http://bitbucket.org/pypy/pypy/changeset/c6bfe0a2263f/ Log: close to be merged branch From noreply at buildbot.pypy.org Fri Jul 1 22:51:06 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 22:51:06 +0200 (CEST) Subject: [pypy-commit] pypy default: merge dict-strategies: Message-ID: <20110701205106.7D0FA8293E@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45248:afcb8d4c0fc5 Date: 2011-07-01 22:46 +0200 http://bitbucket.org/pypy/pypy/changeset/afcb8d4c0fc5/ Log: merge dict-strategies: - refactor dicts to make it possible to freely switch between implementations - this means user dicts can be string dicts now diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -129,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -266,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -355,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -248,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1060,18 +1060,6 @@ def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -631,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -799,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -829,8 +828,6 @@ return struct.unpack(') setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i8, descr=) """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup + w_dict = jit.hint(w_dict, promote=True) self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,79 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): - if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -5,15 +5,16 @@ from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS from pypy.rlib.objectmodel import r_dict, we_are_translated from pypy.rlib.debug import mark_dict_non_null +from pypy.rlib import rerased + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -29,49 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w, - force_non_null=True) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -90,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -142,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -151,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -161,106 +140,83 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def __init__(self, space): + self.space = space - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + return - def impl_fallback_length(self): - return len(self.r_dict_content) + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError + def length(self, w_dict): + return 0 -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) + def clear(self, w_dict): + return -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -302,100 +258,194 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): +class AbtractTypedStrategy(object): + _mixin_ = True + + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): + space = self.space + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return + else: + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) + + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) + + def setdefault(self, w_dict, w_key, w_default): + space = self.space + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) + else: + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) + + def delitem(self, w_dict, w_key): + space = self.space + w_key_type = space.type(w_key) + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] + return + else: + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) + + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) + + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) + + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + + +class ObjectDictStrategy(AbtractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def iter(self, w_dict): + return RDictIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbtractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - mark_dict_non_null(self.content) - def impl_setitem(self, w_key, w_value): + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) - else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + return space.is_w(space.type(w_obj), space.w_str) - def impl_setitem_str(self, key, w_value): + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def setitem_str(self, w_dict, key, w_value): assert key is not None - self.content[key] = w_value + self.unerase(w_dict.dstorage)[key] = w_value - def impl_setdefault(self, w_key, w_default): - space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) - else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) - - - def impl_delitem(self, w_key): - space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] - return - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): - return len(self.content) - - def impl_getitem_str(self, key): - assert key is not None - return self.content.get(key, None) - - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif _never_equal_to_string(space, space.type(w_key)): return None else: - return self._as_rdict().impl_fallback_getitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most @@ -405,39 +455,11 @@ return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) - - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value - - def impl_delitem(self, w_key): - space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] - - class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + d = strategy.unerase(dictimplementation.dstorage) + self.iterator = d.iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most @@ -447,179 +469,6 @@ return None, None - -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 - else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - - - init_signature = Signature(['seq_or_map'], None, 'kwargs') init_defaults = [None] diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,119 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -233,6 +234,31 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2:2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a",1) in l + assert (2,2) in l + assert ("c",3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a",1) in l + assert ("b",2) in l + assert ("c",3) in l + def test_setdefault(self): d = {1:2, 3:4} dd = d.copy() @@ -527,6 +553,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +738,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +753,59 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class FakeString(str): @@ -790,6 +877,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +890,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +922,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1007,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1022,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1066,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1078,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1099,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,19 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + + def test_slot_name_conflict(self): class A(object): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: From noreply at buildbot.pypy.org Fri Jul 1 22:51:08 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 22:51:08 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110701205108.0F30E8293E@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45249:779dd8c23bdf Date: 2011-07-01 22:58 +0200 http://bitbucket.org/pypy/pypy/changeset/779dd8c23bdf/ Log: merge diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -357,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -385,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -214,15 +214,6 @@ bm = A().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self - assert bm.im_class is A - if '__pypy__' in sys.builtin_module_names: - assert bm.__objclass__ is A assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) - l = [] - assert l.append.__self__ is l - if '__pypy__' in sys.builtin_module_names: - assert l.append.__objclass__ is list - assert l.__add__.__self__ is l - assert l.__add__.__objclass__ is list diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -771,7 +771,6 @@ im_self = interp_attrproperty_w('w_instance', cls=Method), __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), - __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -92,7 +92,7 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -847,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1233,7 +1233,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -1252,7 +1252,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1312,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1343,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1496,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1531,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1595,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1817,7 +1817,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2002,7 +2002,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2047,7 +2047,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2082,7 +2082,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2139,7 +2139,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2208,7 +2208,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -15,7 +15,7 @@ if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', 'posix', '_socket', '_sre', '_lsprof', '_weakref', - '__pypy__']: + '__pypy__', 'cStringIO']: return True return False diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -36,12 +36,12 @@ if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - w_dict = jit.hint(w_dict, promote=True) - self = jit.hint(self, promote=True) + w_dict = jit.promote(w_dict) + self = jit.promote(self) return self._getcell_makenew(w_dict, key) return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction + @jit.elidable def _getcell_makenew(self, w_dict, key): return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -322,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -450,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -777,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -823,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -74,7 +74,7 @@ raise KeyError @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) @@ -253,7 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -845,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -857,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,8 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - # it's pure but it does not look like it - @purefunction + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -342,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -352,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -370,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -387,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -428,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -451,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -471,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -487,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -504,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -516,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -527,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -595,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -718,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -816,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -831,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -842,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,30 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] + class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): def func(i): From noreply at buildbot.pypy.org Fri Jul 1 23:00:04 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 23:00:04 +0200 (CEST) Subject: [pypy-commit] pypy celldict-versions: merge default Message-ID: <20110701210004.10C778293E@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: celldict-versions Changeset: r45250:aee8e28319e3 Date: 2011-07-01 23:07 +0200 http://bitbucket.org/pypy/pypy/changeset/aee8e28319e3/ Log: merge default diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -64,6 +64,7 @@ ^pypy/doc/image/lattice3\.png$ ^pypy/doc/image/stackless_informal\.png$ ^pypy/doc/image/parsing_example.+\.png$ +^pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test\.o$ ^compiled ^.git/ ^release/ diff --git a/_pytest/__init__.py b/_pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.0.3' +__version__ = '2.1.0.dev4' diff --git a/_pytest/assertion.py b/_pytest/assertion.py deleted file mode 100644 --- a/_pytest/assertion.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -support for presented detailed information in failing assertions. -""" -import py -import sys -from _pytest.monkeypatch import monkeypatch - -def pytest_addoption(parser): - group = parser.getgroup("debugconfig") - group._addoption('--no-assert', action="store_true", default=False, - dest="noassert", - help="disable python assert expression reinterpretation."), - -def pytest_configure(config): - # The _reprcompare attribute on the py.code module is used by - # py._code._assertionnew to detect this plugin was loaded and in - # turn call the hooks defined here as part of the - # DebugInterpreter. - m = monkeypatch() - config._cleanup.append(m.undo) - warn_about_missing_assertion() - if not config.getvalue("noassert") and not config.getvalue("nomagic"): - def callbinrepr(op, left, right): - hook_result = config.hook.pytest_assertrepr_compare( - config=config, op=op, left=left, right=right) - for new_expl in hook_result: - if new_expl: - return '\n~'.join(new_expl) - m.setattr(py.builtin.builtins, - 'AssertionError', py.code._AssertionError) - m.setattr(py.code, '_reprcompare', callbinrepr) - -def warn_about_missing_assertion(): - try: - assert False - except AssertionError: - pass - else: - sys.stderr.write("WARNING: failing tests may report as passing because " - "assertions are turned off! (are you using python -O?)\n") - -# Provide basestring in python3 -try: - basestring = basestring -except NameError: - basestring = str - - -def pytest_assertrepr_compare(op, left, right): - """return specialised explanations for some operators/operands""" - width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op - left_repr = py.io.saferepr(left, maxsize=int(width/2)) - right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) - summary = '%s %s %s' % (left_repr, op, right_repr) - - issequence = lambda x: isinstance(x, (list, tuple)) - istext = lambda x: isinstance(x, basestring) - isdict = lambda x: isinstance(x, dict) - isset = lambda x: isinstance(x, set) - - explanation = None - try: - if op == '==': - if istext(left) and istext(right): - explanation = _diff_text(left, right) - elif issequence(left) and issequence(right): - explanation = _compare_eq_sequence(left, right) - elif isset(left) and isset(right): - explanation = _compare_eq_set(left, right) - elif isdict(left) and isdict(right): - explanation = _diff_text(py.std.pprint.pformat(left), - py.std.pprint.pformat(right)) - elif op == 'not in': - if istext(left) and istext(right): - explanation = _notin_text(left, right) - except py.builtin._sysex: - raise - except: - excinfo = py.code.ExceptionInfo() - explanation = ['(pytest_assertion plugin: representation of ' - 'details failed. Probably an object has a faulty __repr__.)', - str(excinfo) - ] - - - if not explanation: - return None - - # Don't include pageloads of data, should be configurable - if len(''.join(explanation)) > 80*8: - explanation = ['Detailed information too verbose, truncated'] - - return [summary] + explanation - - -def _diff_text(left, right): - """Return the explanation for the diff between text - - This will skip leading and trailing characters which are - identical to keep the diff minimal. - """ - explanation = [] - i = 0 # just in case left or right has zero length - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - break - if i > 42: - i -= 10 # Provide some context - explanation = ['Skipping %s identical ' - 'leading characters in diff' % i] - left = left[i:] - right = right[i:] - if len(left) == len(right): - for i in range(len(left)): - if left[-i] != right[-i]: - break - if i > 42: - i -= 10 # Provide some context - explanation += ['Skipping %s identical ' - 'trailing characters in diff' % i] - left = left[:-i] - right = right[:-i] - explanation += [line.strip('\n') - for line in py.std.difflib.ndiff(left.splitlines(), - right.splitlines())] - return explanation - - -def _compare_eq_sequence(left, right): - explanation = [] - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - explanation += ['At index %s diff: %r != %r' % - (i, left[i], right[i])] - break - if len(left) > len(right): - explanation += ['Left contains more items, ' - 'first extra item: %s' % py.io.saferepr(left[len(right)],)] - elif len(left) < len(right): - explanation += ['Right contains more items, ' - 'first extra item: %s' % py.io.saferepr(right[len(left)],)] - return explanation # + _diff_text(py.std.pprint.pformat(left), - # py.std.pprint.pformat(right)) - - -def _compare_eq_set(left, right): - explanation = [] - diff_left = left - right - diff_right = right - left - if diff_left: - explanation.append('Extra items in the left set:') - for item in diff_left: - explanation.append(py.io.saferepr(item)) - if diff_right: - explanation.append('Extra items in the right set:') - for item in diff_right: - explanation.append(py.io.saferepr(item)) - return explanation - - -def _notin_text(term, text): - index = text.find(term) - head = text[:index] - tail = text[index+len(term):] - correct_text = head + tail - diff = _diff_text(correct_text, text) - newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] - for line in diff: - if line.startswith('Skipping'): - continue - if line.startswith('- '): - continue - if line.startswith('+ '): - newdiff.append(' ' + line[2:]) - else: - newdiff.append(line) - return newdiff diff --git a/_pytest/assertion/__init__.py b/_pytest/assertion/__init__.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/__init__.py @@ -0,0 +1,128 @@ +""" +support for presenting detailed information in failing assertions. +""" +import py +import imp +import marshal +import struct +import sys +import pytest +from _pytest.monkeypatch import monkeypatch +from _pytest.assertion import reinterpret, util + +try: + from _pytest.assertion.rewrite import rewrite_asserts +except ImportError: + rewrite_asserts = None +else: + import ast + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption('--assertmode', action="store", dest="assertmode", + choices=("on", "old", "off", "default"), default="default", + metavar="on|old|off", + help="""control assertion debugging tools. +'off' performs no assertion debugging. +'old' reinterprets the expressions in asserts to glean information. +'on' (the default) rewrites the assert statements in test modules to provide +sub-expression results.""") + group.addoption('--no-assert', action="store_true", default=False, + dest="noassert", help="DEPRECATED equivalent to --assertmode=off") + group.addoption('--nomagic', action="store_true", default=False, + dest="nomagic", help="DEPRECATED equivalent to --assertmode=off") + +class AssertionState: + """State for the assertion plugin.""" + + def __init__(self, config, mode): + self.mode = mode + self.trace = config.trace.root.get("assertion") + +def pytest_configure(config): + warn_about_missing_assertion() + mode = config.getvalue("assertmode") + if config.getvalue("noassert") or config.getvalue("nomagic"): + if mode not in ("off", "default"): + raise pytest.UsageError("assertion options conflict") + mode = "off" + elif mode == "default": + mode = "on" + if mode != "off": + def callbinrepr(op, left, right): + hook_result = config.hook.pytest_assertrepr_compare( + config=config, op=op, left=left, right=right) + for new_expl in hook_result: + if new_expl: + return '\n~'.join(new_expl) + m = monkeypatch() + config._cleanup.append(m.undo) + m.setattr(py.builtin.builtins, 'AssertionError', + reinterpret.AssertionError) + m.setattr(util, '_reprcompare', callbinrepr) + if mode == "on" and rewrite_asserts is None: + mode = "old" + config._assertstate = AssertionState(config, mode) + config._assertstate.trace("configured with mode set to %r" % (mode,)) + +def _write_pyc(co, source_path): + if hasattr(imp, "cache_from_source"): + # Handle PEP 3147 pycs. + pyc = py.path.local(imp.cache_from_source(str(source_path))) + pyc.ensure() + else: + pyc = source_path + "c" + mtime = int(source_path.mtime()) + fp = pyc.open("wb") + try: + fp.write(imp.get_magic()) + fp.write(struct.pack(">", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + + +class DebugInterpreter(ast.NodeVisitor): + """Interpret AST nodes to gleam useful debugging information. """ + + def __init__(self, frame): + self.frame = frame + + def generic_visit(self, node): + # Fallback when we don't have a special implementation. + if _is_ast_expr(node): + mod = ast.Expression(node) + co = self._compile(mod) + try: + result = self.frame.eval(co) + except Exception: + raise Failure() + explanation = self.frame.repr(result) + return explanation, result + elif _is_ast_stmt(node): + mod = ast.Module([node]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co) + except Exception: + raise Failure() + return None, None + else: + raise AssertionError("can't handle %s" %(node,)) + + def _compile(self, source, mode="eval"): + return compile(source, "", mode) + + def visit_Expr(self, expr): + return self.visit(expr.value) + + def visit_Module(self, mod): + for stmt in mod.body: + self.visit(stmt) + + def visit_Name(self, name): + explanation, result = self.generic_visit(name) + # See if the name is local. + source = "%r in locals() is not globals()" % (name.id,) + co = self._compile(source) + try: + local = self.frame.eval(co) + except Exception: + # have to assume it isn't + local = None + if local is None or not self.frame.is_true(local): + return name.id, result + return explanation, result + + def visit_Compare(self, comp): + left = comp.left + left_explanation, left_result = self.visit(left) + for op, next_op in zip(comp.ops, comp.comparators): + next_explanation, next_result = self.visit(next_op) + op_symbol = operator_map[op.__class__] + explanation = "%s %s %s" % (left_explanation, op_symbol, + next_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=next_result) + except Exception: + raise Failure(explanation) + try: + if not self.frame.is_true(result): + break + except KeyboardInterrupt: + raise + except: + break + left_explanation, left_result = next_explanation, next_result + + if util._reprcompare is not None: + res = util._reprcompare(op_symbol, left_result, next_result) + if res: + explanation = res + return explanation, result + + def visit_BoolOp(self, boolop): + is_or = isinstance(boolop.op, ast.Or) + explanations = [] + for operand in boolop.values: + explanation, result = self.visit(operand) + explanations.append(explanation) + if result == is_or: + break + name = is_or and " or " or " and " + explanation = "(" + name.join(explanations) + ")" + return explanation, result + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_explanation, operand_result = self.visit(unary.operand) + explanation = pattern % (operand_explanation,) + co = self._compile(pattern % ("__exprinfo_expr",)) + try: + result = self.frame.eval(co, __exprinfo_expr=operand_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_BinOp(self, binop): + left_explanation, left_result = self.visit(binop.left) + right_explanation, right_result = self.visit(binop.right) + symbol = operator_map[binop.op.__class__] + explanation = "(%s %s %s)" % (left_explanation, symbol, + right_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=right_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_Call(self, call): + func_explanation, func = self.visit(call.func) + arg_explanations = [] + ns = {"__exprinfo_func" : func} + arguments = [] + for arg in call.args: + arg_explanation, arg_result = self.visit(arg) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + arguments.append(arg_name) + arg_explanations.append(arg_explanation) + for keyword in call.keywords: + arg_explanation, arg_result = self.visit(keyword.value) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + keyword_source = "%s=%%s" % (keyword.arg) + arguments.append(keyword_source % (arg_name,)) + arg_explanations.append(keyword_source % (arg_explanation,)) + if call.starargs: + arg_explanation, arg_result = self.visit(call.starargs) + arg_name = "__exprinfo_star" + ns[arg_name] = arg_result + arguments.append("*%s" % (arg_name,)) + arg_explanations.append("*%s" % (arg_explanation,)) + if call.kwargs: + arg_explanation, arg_result = self.visit(call.kwargs) + arg_name = "__exprinfo_kwds" + ns[arg_name] = arg_result + arguments.append("**%s" % (arg_name,)) + arg_explanations.append("**%s" % (arg_explanation,)) + args_explained = ", ".join(arg_explanations) + explanation = "%s(%s)" % (func_explanation, args_explained) + args = ", ".join(arguments) + source = "__exprinfo_func(%s)" % (args,) + co = self._compile(source) + try: + result = self.frame.eval(co, **ns) + except Exception: + raise Failure(explanation) + pattern = "%s\n{%s = %s\n}" + rep = self.frame.repr(result) + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def _is_builtin_name(self, name): + pattern = "%r not in globals() and %r not in locals()" + source = pattern % (name.id, name.id) + co = self._compile(source) + try: + return self.frame.eval(co) + except Exception: + return False + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + source_explanation, source_result = self.visit(attr.value) + explanation = "%s.%s" % (source_explanation, attr.attr) + source = "__exprinfo_expr.%s" % (attr.attr,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + raise Failure(explanation) + explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), + self.frame.repr(result), + source_explanation, attr.attr) + # Check if the attr is from an instance. + source = "%r in getattr(__exprinfo_expr, '__dict__', {})" + source = source % (attr.attr,) + co = self._compile(source) + try: + from_instance = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + from_instance = None + if from_instance is None or self.frame.is_true(from_instance): + rep = self.frame.repr(result) + pattern = "%s\n{%s = %s\n}" + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def visit_Assert(self, assrt): + test_explanation, test_result = self.visit(assrt.test) + explanation = "assert %s" % (test_explanation,) + if not self.frame.is_true(test_result): + try: + raise BuiltinAssertionError + except Exception: + raise Failure(explanation) + return explanation, test_result + + def visit_Assign(self, assign): + value_explanation, value_result = self.visit(assign.value) + explanation = "... = %s" % (value_explanation,) + name = ast.Name("__exprinfo_expr", ast.Load(), + lineno=assign.value.lineno, + col_offset=assign.value.col_offset) + new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, + col_offset=assign.col_offset) + mod = ast.Module([new_assign]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co, __exprinfo_expr=value_result) + except Exception: + raise Failure(explanation) + return explanation, value_result diff --git a/_pytest/assertion/oldinterpret.py b/_pytest/assertion/oldinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/oldinterpret.py @@ -0,0 +1,552 @@ +import py +import sys, inspect +from compiler import parse, ast, pycodegen +from _pytest.assertion.util import format_explanation +from _pytest.assertion.reinterpret import BuiltinAssertionError + +passthroughex = py.builtin._sysex + +class Failure: + def __init__(self, node): + self.exc, self.value, self.tb = sys.exc_info() + self.node = node + +class View(object): + """View base class. + + If C is a subclass of View, then C(x) creates a proxy object around + the object x. The actual class of the proxy is not C in general, + but a *subclass* of C determined by the rules below. To avoid confusion + we call view class the class of the proxy (a subclass of C, so of View) + and object class the class of x. + + Attributes and methods not found in the proxy are automatically read on x. + Other operations like setting attributes are performed on the proxy, as + determined by its view class. The object x is available from the proxy + as its __obj__ attribute. + + The view class selection is determined by the __view__ tuples and the + optional __viewkey__ method. By default, the selected view class is the + most specific subclass of C whose __view__ mentions the class of x. + If no such subclass is found, the search proceeds with the parent + object classes. For example, C(True) will first look for a subclass + of C with __view__ = (..., bool, ...) and only if it doesn't find any + look for one with __view__ = (..., int, ...), and then ..., object,... + If everything fails the class C itself is considered to be the default. + + Alternatively, the view class selection can be driven by another aspect + of the object x, instead of the class of x, by overriding __viewkey__. + See last example at the end of this module. + """ + + _viewcache = {} + __view__ = () + + def __new__(rootclass, obj, *args, **kwds): + self = object.__new__(rootclass) + self.__obj__ = obj + self.__rootclass__ = rootclass + key = self.__viewkey__() + try: + self.__class__ = self._viewcache[key] + except KeyError: + self.__class__ = self._selectsubclass(key) + return self + + def __getattr__(self, attr): + # attributes not found in the normal hierarchy rooted on View + # are looked up in the object's real class + return getattr(self.__obj__, attr) + + def __viewkey__(self): + return self.__obj__.__class__ + + def __matchkey__(self, key, subclasses): + if inspect.isclass(key): + keys = inspect.getmro(key) + else: + keys = [key] + for key in keys: + result = [C for C in subclasses if key in C.__view__] + if result: + return result + return [] + + def _selectsubclass(self, key): + subclasses = list(enumsubclasses(self.__rootclass__)) + for C in subclasses: + if not isinstance(C.__view__, tuple): + C.__view__ = (C.__view__,) + choices = self.__matchkey__(key, subclasses) + if not choices: + return self.__rootclass__ + elif len(choices) == 1: + return choices[0] + else: + # combine the multiple choices + return type('?', tuple(choices), {}) + + def __repr__(self): + return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) + + +def enumsubclasses(cls): + for subcls in cls.__subclasses__(): + for subsubclass in enumsubclasses(subcls): + yield subsubclass + yield cls + + +class Interpretable(View): + """A parse tree node with a few extra methods.""" + explanation = None + + def is_builtin(self, frame): + return False + + def eval(self, frame): + # fall-back for unknown expression nodes + try: + expr = ast.Expression(self.__obj__) + expr.filename = '' + self.__obj__.filename = '' + co = pycodegen.ExpressionCodeGenerator(expr).getCode() + result = frame.eval(co) + except passthroughex: + raise + except: + raise Failure(self) + self.result = result + self.explanation = self.explanation or frame.repr(self.result) + + def run(self, frame): + # fall-back for unknown statement nodes + try: + expr = ast.Module(None, ast.Stmt([self.__obj__])) + expr.filename = '' + co = pycodegen.ModuleCodeGenerator(expr).getCode() + frame.exec_(co) + except passthroughex: + raise + except: + raise Failure(self) + + def nice_explanation(self): + return format_explanation(self.explanation) + + +class Name(Interpretable): + __view__ = ast.Name + + def is_local(self, frame): + source = '%r in locals() is not globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_global(self, frame): + source = '%r in globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_builtin(self, frame): + source = '%r not in locals() and %r not in globals()' % ( + self.name, self.name) + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + super(Name, self).eval(frame) + if not self.is_local(frame): + self.explanation = self.name + +class Compare(Interpretable): + __view__ = ast.Compare + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + for operation, expr2 in self.ops: + if hasattr(self, 'result'): + # shortcutting in chained expressions + if not frame.is_true(self.result): + break + expr2 = Interpretable(expr2) + expr2.eval(frame) + self.explanation = "%s %s %s" % ( + expr.explanation, operation, expr2.explanation) + source = "__exprinfo_left %s __exprinfo_right" % operation + try: + self.result = frame.eval(source, + __exprinfo_left=expr.result, + __exprinfo_right=expr2.result) + except passthroughex: + raise + except: + raise Failure(self) + expr = expr2 + +class And(Interpretable): + __view__ = ast.And + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if not frame.is_true(expr.result): + break + self.explanation = '(' + ' and '.join(explanations) + ')' + +class Or(Interpretable): + __view__ = ast.Or + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if frame.is_true(expr.result): + break + self.explanation = '(' + ' or '.join(explanations) + ')' + + +# == Unary operations == +keepalive = [] +for astclass, astpattern in { + ast.Not : 'not __exprinfo_expr', + ast.Invert : '(~__exprinfo_expr)', + }.items(): + + class UnaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + expr = Interpretable(self.expr) + expr.eval(frame) + self.explanation = astpattern.replace('__exprinfo_expr', + expr.explanation) + try: + self.result = frame.eval(astpattern, + __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(UnaryArith) + +# == Binary operations == +for astclass, astpattern in { + ast.Add : '(__exprinfo_left + __exprinfo_right)', + ast.Sub : '(__exprinfo_left - __exprinfo_right)', + ast.Mul : '(__exprinfo_left * __exprinfo_right)', + ast.Div : '(__exprinfo_left / __exprinfo_right)', + ast.Mod : '(__exprinfo_left % __exprinfo_right)', + ast.Power : '(__exprinfo_left ** __exprinfo_right)', + }.items(): + + class BinaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + left = Interpretable(self.left) + left.eval(frame) + right = Interpretable(self.right) + right.eval(frame) + self.explanation = (astpattern + .replace('__exprinfo_left', left .explanation) + .replace('__exprinfo_right', right.explanation)) + try: + self.result = frame.eval(astpattern, + __exprinfo_left=left.result, + __exprinfo_right=right.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(BinaryArith) + + +class CallFunc(Interpretable): + __view__ = ast.CallFunc + + def is_bool(self, frame): + source = 'isinstance(__exprinfo_value, bool)' + try: + return frame.is_true(frame.eval(source, + __exprinfo_value=self.result)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + node = Interpretable(self.node) + node.eval(frame) + explanations = [] + vars = {'__exprinfo_fn': node.result} + source = '__exprinfo_fn(' + for a in self.args: + if isinstance(a, ast.Keyword): + keyword = a.name + a = a.expr + else: + keyword = None + a = Interpretable(a) + a.eval(frame) + argname = '__exprinfo_%d' % len(vars) + vars[argname] = a.result + if keyword is None: + source += argname + ',' + explanations.append(a.explanation) + else: + source += '%s=%s,' % (keyword, argname) + explanations.append('%s=%s' % (keyword, a.explanation)) + if self.star_args: + star_args = Interpretable(self.star_args) + star_args.eval(frame) + argname = '__exprinfo_star' + vars[argname] = star_args.result + source += '*' + argname + ',' + explanations.append('*' + star_args.explanation) + if self.dstar_args: + dstar_args = Interpretable(self.dstar_args) + dstar_args.eval(frame) + argname = '__exprinfo_kwds' + vars[argname] = dstar_args.result + source += '**' + argname + ',' + explanations.append('**' + dstar_args.explanation) + self.explanation = "%s(%s)" % ( + node.explanation, ', '.join(explanations)) + if source.endswith(','): + source = source[:-1] + source += ')' + try: + self.result = frame.eval(source, **vars) + except passthroughex: + raise + except: + raise Failure(self) + if not node.is_builtin(frame) or not self.is_bool(frame): + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +class Getattr(Interpretable): + __view__ = ast.Getattr + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + source = '__exprinfo_expr.%s' % self.attrname + try: + self.result = frame.eval(source, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + self.explanation = '%s.%s' % (expr.explanation, self.attrname) + # if the attribute comes from the instance, its value is interesting + source = ('hasattr(__exprinfo_expr, "__dict__") and ' + '%r in __exprinfo_expr.__dict__' % self.attrname) + try: + from_instance = frame.is_true( + frame.eval(source, __exprinfo_expr=expr.result)) + except passthroughex: + raise + except: + from_instance = True + if from_instance: + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +# == Re-interpretation of full statements == + +class Assert(Interpretable): + __view__ = ast.Assert + + def run(self, frame): + test = Interpretable(self.test) + test.eval(frame) + # print the result as 'assert ' + self.result = test.result + self.explanation = 'assert ' + test.explanation + if not frame.is_true(test.result): + try: + raise BuiltinAssertionError + except passthroughex: + raise + except: + raise Failure(self) + +class Assign(Interpretable): + __view__ = ast.Assign + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = '... = ' + expr.explanation + # fall-back-run the rest of the assignment + ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) + mod = ast.Module(None, ast.Stmt([ass])) + mod.filename = '' + co = pycodegen.ModuleCodeGenerator(mod).getCode() + try: + frame.exec_(co, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + +class Discard(Interpretable): + __view__ = ast.Discard + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = expr.explanation + +class Stmt(Interpretable): + __view__ = ast.Stmt + + def run(self, frame): + for stmt in self.nodes: + stmt = Interpretable(stmt) + stmt.run(frame) + + +def report_failure(e): + explanation = e.node.nice_explanation() + if explanation: + explanation = ", in: " + explanation + else: + explanation = "" + sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) + +def check(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + expr = parse(s, 'eval') + assert isinstance(expr, ast.Expression) + node = Interpretable(expr.node) + try: + node.eval(frame) + except passthroughex: + raise + except Failure: + e = sys.exc_info()[1] + report_failure(e) + else: + if not frame.is_true(node.result): + sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) + + +########################################################### +# API / Entry points +# ######################################################### + +def interpret(source, frame, should_fail=False): + module = Interpretable(parse(source, 'exec').node) + #print "got module", module + if isinstance(frame, py.std.types.FrameType): + frame = py.code.Frame(frame) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + return getfailure(e) + except passthroughex: + raise + except: + import traceback + traceback.print_exc() + if should_fail: + return ("(assertion failed, but when it was re-run for " + "printing intermediate values, it did not fail. Suggestions: " + "compute assert expression before the assert or use --nomagic)") + else: + return None + +def getmsg(excinfo): + if isinstance(excinfo, tuple): + excinfo = py.code.ExceptionInfo(excinfo) + #frame, line = gettbline(tb) + #frame = py.code.Frame(frame) + #return interpret(line, frame) + + tb = excinfo.traceback[-1] + source = str(tb.statement).strip() + x = interpret(source, tb.frame, should_fail=True) + if not isinstance(x, str): + raise TypeError("interpret returned non-string %r" % (x,)) + return x + +def getfailure(e): + explanation = e.node.nice_explanation() + if str(e.value): + lines = explanation.split('\n') + lines[0] += " << %s" % (e.value,) + explanation = '\n'.join(lines) + text = "%s: %s" % (e.exc.__name__, explanation) + if text.startswith('AssertionError: assert '): + text = text[16:] + return text + +def run(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + module = Interpretable(parse(s, 'exec').node) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + report_failure(e) + + +if __name__ == '__main__': + # example: + def f(): + return 5 + def g(): + return 3 + def h(x): + return 'never' + check("f() * g() == 5") + check("not f()") + check("not (f() and g() or 0)") + check("f() == g()") + i = 4 + check("i == f()") + check("len(f()) == 0") + check("isinstance(2+3+4, float)") + + run("x = i") + check("x == 5") + + run("assert not f(), 'oops'") + run("a, b, c = 1, 2") + run("a, b, c = f()") + + check("max([f(),g()]) == 4") + check("'hello'[g()] == 'h'") + run("'guk%d' % h(f())") diff --git a/_pytest/assertion/reinterpret.py b/_pytest/assertion/reinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/reinterpret.py @@ -0,0 +1,48 @@ +import sys +import py + +BuiltinAssertionError = py.builtin.builtins.AssertionError + +class AssertionError(BuiltinAssertionError): + def __init__(self, *args): + BuiltinAssertionError.__init__(self, *args) + if args: + try: + self.msg = str(args[0]) + except py.builtin._sysex: + raise + except: + self.msg = "<[broken __repr__] %s at %0xd>" %( + args[0].__class__, id(args[0])) + else: + f = py.code.Frame(sys._getframe(1)) + try: + source = f.code.fullsource + if source is not None: + try: + source = source.getstatement(f.lineno, assertion=True) + except IndexError: + source = None + else: + source = str(source.deindent()).strip() + except py.error.ENOENT: + source = None + # this can also occur during reinterpretation, when the + # co_filename is set to "". + if source: + self.msg = reinterpret(source, f, should_fail=True) + else: + self.msg = "" + if not self.args: + self.args = (self.msg,) + +if sys.version_info > (3, 0): + AssertionError.__module__ = "builtins" + reinterpret_old = "old reinterpretation not available for py3" +else: + from _pytest.assertion.oldinterpret import interpret as reinterpret_old +if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): + from _pytest.assertion.newinterpret import interpret as reinterpret +else: + reinterpret = reinterpret_old + diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/rewrite.py @@ -0,0 +1,340 @@ +"""Rewrite assertion AST to produce nice error messages""" + +import ast +import collections +import itertools +import sys + +import py +from _pytest.assertion import util + + +def rewrite_asserts(mod): + """Rewrite the assert statements in mod.""" + AssertionRewriter().run(mod) + + +_saferepr = py.io.saferepr +from _pytest.assertion.util import format_explanation as _format_explanation + +def _format_boolop(operands, explanations, is_or): + show_explanations = [] + for operand, expl in zip(operands, explanations): + show_explanations.append(expl) + if operand == is_or: + break + return "(" + (is_or and " or " or " and ").join(show_explanations) + ")" + +def _call_reprcompare(ops, results, expls, each_obj): + for i, res, expl in zip(range(len(ops)), results, expls): + try: + done = not res + except Exception: + done = True + if done: + break + if util._reprcompare is not None: + custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1]) + if custom is not None: + return custom + return expl + + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + +binop_map = { + ast.BitOr : "|", + ast.BitXor : "^", + ast.BitAnd : "&", + ast.LShift : "<<", + ast.RShift : ">>", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + + +def set_location(node, lineno, col_offset): + """Set node location information recursively.""" + def _fix(node, lineno, col_offset): + if "lineno" in node._attributes: + node.lineno = lineno + if "col_offset" in node._attributes: + node.col_offset = col_offset + for child in ast.iter_child_nodes(node): + _fix(child, lineno, col_offset) + _fix(node, lineno, col_offset) + return node + + +class AssertionRewriter(ast.NodeVisitor): + + def run(self, mod): + """Find all assert statements in *mod* and rewrite them.""" + if not mod.body: + # Nothing to do. + return + # Insert some special imports at the top of the module but after any + # docstrings and __future__ imports. + aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"), + ast.alias("_pytest.assertion.rewrite", "@pytest_ar")] + expect_docstring = True + pos = 0 + lineno = 0 + for item in mod.body: + if (expect_docstring and isinstance(item, ast.Expr) and + isinstance(item.value, ast.Str)): + doc = item.value.s + if "PYTEST_DONT_REWRITE" in doc: + # The module has disabled assertion rewriting. + return + lineno += len(doc) - 1 + expect_docstring = False + elif (not isinstance(item, ast.ImportFrom) or item.level > 0 and + item.identifier != "__future__"): + lineno = item.lineno + break + pos += 1 + imports = [ast.Import([alias], lineno=lineno, col_offset=0) + for alias in aliases] + mod.body[pos:pos] = imports + # Collect asserts. + nodes = collections.deque([mod]) + while nodes: + node = nodes.popleft() + for name, field in ast.iter_fields(node): + if isinstance(field, list): + new = [] + for i, child in enumerate(field): + if isinstance(child, ast.Assert): + # Transform assert. + new.extend(self.visit(child)) + else: + new.append(child) + if isinstance(child, ast.AST): + nodes.append(child) + setattr(node, name, new) + elif (isinstance(field, ast.AST) and + # Don't recurse into expressions as they can't contain + # asserts. + not isinstance(field, ast.expr)): + nodes.append(field) + + def variable(self): + """Get a new variable.""" + # Use a character invalid in python identifiers to avoid clashing. + name = "@py_assert" + str(next(self.variable_counter)) + self.variables.add(name) + return name + + def assign(self, expr): + """Give *expr* a name.""" + name = self.variable() + self.statements.append(ast.Assign([ast.Name(name, ast.Store())], expr)) + return ast.Name(name, ast.Load()) + + def display(self, expr): + """Call py.io.saferepr on the expression.""" + return self.helper("saferepr", expr) + + def helper(self, name, *args): + """Call a helper in this module.""" + py_name = ast.Name("@pytest_ar", ast.Load()) + attr = ast.Attribute(py_name, "_" + name, ast.Load()) + return ast.Call(attr, list(args), [], None, None) + + def builtin(self, name): + """Return the builtin called *name*.""" + builtin_name = ast.Name("@py_builtins", ast.Load()) + return ast.Attribute(builtin_name, name, ast.Load()) + + def explanation_param(self, expr): + specifier = "py" + str(next(self.variable_counter)) + self.explanation_specifiers[specifier] = expr + return "%(" + specifier + ")s" + + def push_format_context(self): + self.explanation_specifiers = {} + self.stack.append(self.explanation_specifiers) + + def pop_format_context(self, expl_expr): + current = self.stack.pop() + if self.stack: + self.explanation_specifiers = self.stack[-1] + keys = [ast.Str(key) for key in current.keys()] + format_dict = ast.Dict(keys, list(current.values())) + form = ast.BinOp(expl_expr, ast.Mod(), format_dict) + name = "@py_format" + str(next(self.variable_counter)) + self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form)) + return ast.Name(name, ast.Load()) + + def generic_visit(self, node): + """Handle expressions we don't have custom code for.""" + assert isinstance(node, ast.expr) + res = self.assign(node) + return res, self.explanation_param(self.display(res)) + + def visit_Assert(self, assert_): + if assert_.msg: + # There's already a message. Don't mess with it. + return [assert_] + self.statements = [] + self.variables = set() + self.variable_counter = itertools.count() + self.stack = [] + self.on_failure = [] + self.push_format_context() + # Rewrite assert into a bunch of statements. + top_condition, explanation = self.visit(assert_.test) + # Create failure message. + body = self.on_failure + negation = ast.UnaryOp(ast.Not(), top_condition) + self.statements.append(ast.If(negation, body, [])) + explanation = "assert " + explanation + template = ast.Str(explanation) + msg = self.pop_format_context(template) + fmt = self.helper("format_explanation", msg) + err_name = ast.Name("AssertionError", ast.Load()) + exc = ast.Call(err_name, [fmt], [], None, None) + if sys.version_info[0] >= 3: + raise_ = ast.Raise(exc, None) + else: + raise_ = ast.Raise(exc, None, None) + body.append(raise_) + # Delete temporary variables. + names = [ast.Name(name, ast.Del()) for name in self.variables] + if names: + delete = ast.Delete(names) + self.statements.append(delete) + # Fix line numbers. + for stmt in self.statements: + set_location(stmt, assert_.lineno, assert_.col_offset) + return self.statements + + def visit_Name(self, name): + # Check if the name is local or not. + locs = ast.Call(self.builtin("locals"), [], [], None, None) + globs = ast.Call(self.builtin("globals"), [], [], None, None) + ops = [ast.In(), ast.IsNot()] + test = ast.Compare(ast.Str(name.id), ops, [locs, globs]) + expr = ast.IfExp(test, self.display(name), ast.Str(name.id)) + return name, self.explanation_param(expr) + + def visit_BoolOp(self, boolop): + operands = [] + explanations = [] + self.push_format_context() + for operand in boolop.values: + res, explanation = self.visit(operand) + operands.append(res) + explanations.append(explanation) + expls = ast.Tuple([ast.Str(expl) for expl in explanations], ast.Load()) + is_or = ast.Num(isinstance(boolop.op, ast.Or)) + expl_template = self.helper("format_boolop", + ast.Tuple(operands, ast.Load()), expls, + is_or) + expl = self.pop_format_context(expl_template) + res = self.assign(ast.BoolOp(boolop.op, operands)) + return res, self.explanation_param(expl) + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_res, operand_expl = self.visit(unary.operand) + res = self.assign(ast.UnaryOp(unary.op, operand_res)) + return res, pattern % (operand_expl,) + + def visit_BinOp(self, binop): + symbol = binop_map[binop.op.__class__] + left_expr, left_expl = self.visit(binop.left) + right_expr, right_expl = self.visit(binop.right) + explanation = "(%s %s %s)" % (left_expl, symbol, right_expl) + res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) + return res, explanation + + def visit_Call(self, call): + new_func, func_expl = self.visit(call.func) + arg_expls = [] + new_args = [] + new_kwargs = [] + new_star = new_kwarg = None + for arg in call.args: + res, expl = self.visit(arg) + new_args.append(res) + arg_expls.append(expl) + for keyword in call.keywords: + res, expl = self.visit(keyword.value) + new_kwargs.append(ast.keyword(keyword.arg, res)) + arg_expls.append(keyword.arg + "=" + expl) + if call.starargs: + new_star, expl = self.visit(call.starargs) + arg_expls.append("*" + expl) + if call.kwargs: + new_kwarg, expl = self.visit(call.kwarg) + arg_expls.append("**" + expl) + expl = "%s(%s)" % (func_expl, ', '.join(arg_expls)) + new_call = ast.Call(new_func, new_args, new_kwargs, new_star, new_kwarg) + res = self.assign(new_call) + res_expl = self.explanation_param(self.display(res)) + outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl) + return res, outer_expl + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + value, value_expl = self.visit(attr.value) + res = self.assign(ast.Attribute(value, attr.attr, ast.Load())) + res_expl = self.explanation_param(self.display(res)) + pat = "%s\n{%s = %s.%s\n}" + expl = pat % (res_expl, res_expl, value_expl, attr.attr) + return res, expl + + def visit_Compare(self, comp): + self.push_format_context() + left_res, left_expl = self.visit(comp.left) + res_variables = [self.variable() for i in range(len(comp.ops))] + load_names = [ast.Name(v, ast.Load()) for v in res_variables] + store_names = [ast.Name(v, ast.Store()) for v in res_variables] + it = zip(range(len(comp.ops)), comp.ops, comp.comparators) + expls = [] + syms = [] + results = [left_res] + for i, op, next_operand in it: + next_res, next_expl = self.visit(next_operand) + results.append(next_res) + sym = binop_map[op.__class__] + syms.append(ast.Str(sym)) + expl = "%s %s %s" % (left_expl, sym, next_expl) + expls.append(ast.Str(expl)) + res_expr = ast.Compare(left_res, [op], [next_res]) + self.statements.append(ast.Assign([store_names[i]], res_expr)) + left_res, left_expl = next_res, next_expl + # Use py.code._reprcompare if that's available. + expl_call = self.helper("call_reprcompare", + ast.Tuple(syms, ast.Load()), + ast.Tuple(load_names, ast.Load()), + ast.Tuple(expls, ast.Load()), + ast.Tuple(results, ast.Load())) + if len(comp.ops) > 1: + res = ast.BoolOp(ast.And(), load_names) + else: + res = load_names[0] + return res, self.explanation_param(self.pop_format_context(expl_call)) diff --git a/_pytest/assertion/util.py b/_pytest/assertion/util.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/util.py @@ -0,0 +1,213 @@ +"""Utilities for assertion debugging""" + +import py + + +# The _reprcompare attribute on the util module is used by the new assertion +# interpretation code and assertion rewriter to detect this plugin was +# loaded and in turn call the hooks defined here as part of the +# DebugInterpreter. +_reprcompare = None + +def format_explanation(explanation): + """This formats an explanation + + Normally all embedded newlines are escaped, however there are + three exceptions: \n{, \n} and \n~. The first two are intended + cover nested explanations, see function and attribute explanations + for examples (.visit_Call(), visit_Attribute()). The last one is + for when one explanation needs to span multiple lines, e.g. when + displaying diffs. + """ + # simplify 'assert False where False = ...' + where = 0 + while True: + start = where = explanation.find("False\n{False = ", where) + if where == -1: + break + level = 0 + for i, c in enumerate(explanation[start:]): + if c == "{": + level += 1 + elif c == "}": + level -= 1 + if not level: + break + else: + raise AssertionError("unbalanced braces: %r" % (explanation,)) + end = start + i + where = end + if explanation[end - 1] == '\n': + explanation = (explanation[:start] + explanation[start+15:end-1] + + explanation[end+1:]) + where -= 17 + raw_lines = (explanation or '').split('\n') + # escape newlines not followed by {, } and ~ + lines = [raw_lines[0]] + for l in raw_lines[1:]: + if l.startswith('{') or l.startswith('}') or l.startswith('~'): + lines.append(l) + else: + lines[-1] += '\\n' + l + + result = lines[:1] + stack = [0] + stackcnt = [0] + for line in lines[1:]: + if line.startswith('{'): + if stackcnt[-1]: + s = 'and ' + else: + s = 'where ' + stack.append(len(result)) + stackcnt[-1] += 1 + stackcnt.append(0) + result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) + elif line.startswith('}'): + assert line.startswith('}') + stack.pop() + stackcnt.pop() + result[stack[-1]] += line[1:] + else: + assert line.startswith('~') + result.append(' '*len(stack) + line[1:]) + assert len(stack) == 1 + return '\n'.join(result) + + +# Provide basestring in python3 +try: + basestring = basestring +except NameError: + basestring = str + + +def assertrepr_compare(op, left, right): + """return specialised explanations for some operators/operands""" + width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op + left_repr = py.io.saferepr(left, maxsize=int(width/2)) + right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) + summary = '%s %s %s' % (left_repr, op, right_repr) + + issequence = lambda x: isinstance(x, (list, tuple)) + istext = lambda x: isinstance(x, basestring) + isdict = lambda x: isinstance(x, dict) + isset = lambda x: isinstance(x, set) + + explanation = None + try: + if op == '==': + if istext(left) and istext(right): + explanation = _diff_text(left, right) + elif issequence(left) and issequence(right): + explanation = _compare_eq_sequence(left, right) + elif isset(left) and isset(right): + explanation = _compare_eq_set(left, right) + elif isdict(left) and isdict(right): + explanation = _diff_text(py.std.pprint.pformat(left), + py.std.pprint.pformat(right)) + elif op == 'not in': + if istext(left) and istext(right): + explanation = _notin_text(left, right) + except py.builtin._sysex: + raise + except: + excinfo = py.code.ExceptionInfo() + explanation = ['(pytest_assertion plugin: representation of ' + 'details failed. Probably an object has a faulty __repr__.)', + str(excinfo) + ] + + + if not explanation: + return None + + # Don't include pageloads of data, should be configurable + if len(''.join(explanation)) > 80*8: + explanation = ['Detailed information too verbose, truncated'] + + return [summary] + explanation + + +def _diff_text(left, right): + """Return the explanation for the diff between text + + This will skip leading and trailing characters which are + identical to keep the diff minimal. + """ + explanation = [] + i = 0 # just in case left or right has zero length + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + break + if i > 42: + i -= 10 # Provide some context + explanation = ['Skipping %s identical ' + 'leading characters in diff' % i] + left = left[i:] + right = right[i:] + if len(left) == len(right): + for i in range(len(left)): + if left[-i] != right[-i]: + break + if i > 42: + i -= 10 # Provide some context + explanation += ['Skipping %s identical ' + 'trailing characters in diff' % i] + left = left[:-i] + right = right[:-i] + explanation += [line.strip('\n') + for line in py.std.difflib.ndiff(left.splitlines(), + right.splitlines())] + return explanation + + +def _compare_eq_sequence(left, right): + explanation = [] + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + explanation += ['At index %s diff: %r != %r' % + (i, left[i], right[i])] + break + if len(left) > len(right): + explanation += ['Left contains more items, ' + 'first extra item: %s' % py.io.saferepr(left[len(right)],)] + elif len(left) < len(right): + explanation += ['Right contains more items, ' + 'first extra item: %s' % py.io.saferepr(right[len(left)],)] + return explanation # + _diff_text(py.std.pprint.pformat(left), + # py.std.pprint.pformat(right)) + + +def _compare_eq_set(left, right): + explanation = [] + diff_left = left - right + diff_right = right - left + if diff_left: + explanation.append('Extra items in the left set:') + for item in diff_left: + explanation.append(py.io.saferepr(item)) + if diff_right: + explanation.append('Extra items in the right set:') + for item in diff_right: + explanation.append(py.io.saferepr(item)) + return explanation + + +def _notin_text(term, text): + index = text.find(term) + head = text[:index] + tail = text[index+len(term):] + correct_text = head + tail + diff = _diff_text(correct_text, text) + newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] + for line in diff: + if line.startswith('Skipping'): + continue + if line.startswith('- '): + continue + if line.startswith('+ '): + newdiff.append(' ' + line[2:]) + else: + newdiff.append(line) + return newdiff diff --git a/_pytest/doctest.py b/_pytest/doctest.py --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -59,7 +59,7 @@ inner_excinfo = py.code.ExceptionInfo(excinfo.value.exc_info) lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)] - + lines += py.std.traceback.format_exception(*excinfo.value.exc_info) return ReprFailDoctest(reprlocation, lines) else: return super(DoctestItem, self).repr_failure(excinfo) diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -16,9 +16,6 @@ group.addoption('--traceconfig', action="store_true", dest="traceconfig", default=False, help="trace considerations of conftest.py files."), - group._addoption('--nomagic', - action="store_true", dest="nomagic", default=False, - help="don't reinterpret asserts, no traceback cutting. ") group.addoption('--debug', action="store_true", dest="debug", default=False, help="generate and show internal debugging information.") diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -65,7 +65,8 @@ class LogXML(object): def __init__(self, logfile, prefix): - self.logfile = logfile + logfile = os.path.expanduser(os.path.expandvars(logfile)) + self.logfile = os.path.normpath(logfile) self.prefix = prefix self.test_logs = [] self.passed = self.skipped = 0 @@ -76,7 +77,7 @@ names = report.nodeid.split("::") names[0] = names[0].replace("/", '.') names = tuple(names) - d = {'time': self._durations.pop(names, "0")} + d = {'time': self._durations.pop(report.nodeid, "0")} names = [x.replace(".py", "") for x in names if x != "()"] classnames = names[:-1] if self.prefix: @@ -170,12 +171,11 @@ self.append_skipped(report) def pytest_runtest_call(self, item, __multicall__): - names = tuple(item.listnames()) start = time.time() try: return __multicall__.execute() finally: - self._durations[names] = time.time() - start + self._durations[item.nodeid] = time.time() - start def pytest_collectreport(self, report): if not report.passed: diff --git a/_pytest/main.py b/_pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -46,23 +46,25 @@ def pytest_namespace(): - return dict(collect=dict(Item=Item, Collector=Collector, File=File)) + collect = dict(Item=Item, Collector=Collector, File=File, Session=Session) + return dict(collect=collect) def pytest_configure(config): py.test.config = config # compatibiltiy if config.option.exitfirst: config.option.maxfail = 1 -def pytest_cmdline_main(config): - """ default command line protocol for initialization, session, - running tests and reporting. """ +def wrap_session(config, doit): + """Skeleton command line program""" session = Session(config) session.exitstatus = EXIT_OK + initstate = 0 try: config.pluginmanager.do_configure(config) + initstate = 1 config.hook.pytest_sessionstart(session=session) - config.hook.pytest_collection(session=session) - config.hook.pytest_runtestloop(session=session) + initstate = 2 + doit(config, session) except pytest.UsageError: raise except KeyboardInterrupt: @@ -77,18 +79,24 @@ sys.stderr.write("mainloop: caught Spurious SystemExit!\n") if not session.exitstatus and session._testsfailed: session.exitstatus = EXIT_TESTSFAILED - config.hook.pytest_sessionfinish(session=session, - exitstatus=session.exitstatus) - config.pluginmanager.do_unconfigure(config) + if initstate >= 2: + config.hook.pytest_sessionfinish(session=session, + exitstatus=session.exitstatus) + if initstate >= 1: + config.pluginmanager.do_unconfigure(config) return session.exitstatus +def pytest_cmdline_main(config): + return wrap_session(config, _main) + +def _main(config, session): + """ default command line protocol for initialization, session, + running tests and reporting. """ + config.hook.pytest_collection(session=session) + config.hook.pytest_runtestloop(session=session) + def pytest_collection(session): - session.perform_collect() - hook = session.config.hook - hook.pytest_collection_modifyitems(session=session, - config=session.config, items=session.items) - hook.pytest_collection_finish(session=session) - return True + return session.perform_collect() def pytest_runtestloop(session): if session.config.option.collectonly: @@ -374,6 +382,16 @@ return HookProxy(fspath, self.config) def perform_collect(self, args=None, genitems=True): + hook = self.config.hook + try: + items = self._perform_collect(args, genitems) + hook.pytest_collection_modifyitems(session=self, + config=self.config, items=items) + finally: + hook.pytest_collection_finish(session=self) + return items + + def _perform_collect(self, args, genitems): if args is None: args = self.config.args self.trace("perform_collect", self, args) diff --git a/_pytest/mark.py b/_pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -153,7 +153,7 @@ def __repr__(self): return "" % ( - self._name, self.args, self.kwargs) + self.name, self.args, self.kwargs) def pytest_itemcollected(item): if not isinstance(item, pytest.Function): diff --git a/_pytest/pytester.py b/_pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -6,7 +6,7 @@ import inspect import time from fnmatch import fnmatch -from _pytest.main import Session +from _pytest.main import Session, EXIT_OK from py.builtin import print_ from _pytest.core import HookRelay @@ -292,13 +292,19 @@ assert '::' not in str(arg) p = py.path.local(arg) x = session.fspath.bestrelpath(p) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def getpathnode(self, path): - config = self.parseconfig(path) + config = self.parseconfigure(path) session = Session(config) x = session.fspath.bestrelpath(path) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def genitems(self, colitems): session = colitems[0].session @@ -312,7 +318,9 @@ config = self.parseconfigure(*args) rec = self.getreportrecorder(config) session = Session(config) + config.hook.pytest_sessionstart(session=session) session.perform_collect() + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) return session.items, rec def runitem(self, source): @@ -382,6 +390,8 @@ c.basetemp = py.path.local.make_numbered_dir(prefix="reparse", keep=0, rootdir=self.tmpdir, lock_timeout=None) c.parse(args) + c.pluginmanager.do_configure(c) + self.request.addfinalizer(lambda: c.pluginmanager.do_unconfigure(c)) return c finally: py.test.config = oldconfig diff --git a/_pytest/python.py b/_pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -226,8 +226,13 @@ def _importtestmodule(self): # we assume we are only called once per module + from _pytest import assertion + assertion.before_module_import(self) try: - mod = self.fspath.pyimport(ensuresyspath=True) + try: + mod = self.fspath.pyimport(ensuresyspath=True) + finally: + assertion.after_module_import(self) except SyntaxError: excinfo = py.code.ExceptionInfo() raise self.CollectError(excinfo.getrepr(style="short")) @@ -374,7 +379,7 @@ # test generators are seen as collectors but they also # invoke setup/teardown on popular request # (induced by the common "test_*" naming shared with normal tests) - self.config._setupstate.prepare(self) + self.session._setupstate.prepare(self) # see FunctionMixin.setup and test_setupstate_is_preserved_134 self._preservedparent = self.parent.obj l = [] @@ -721,7 +726,7 @@ def _addfinalizer(self, finalizer, scope): colitem = self._getscopeitem(scope) - self.config._setupstate.addfinalizer( + self._pyfuncitem.session._setupstate.addfinalizer( finalizer=finalizer, colitem=colitem) def __repr__(self): @@ -742,8 +747,10 @@ raise self.LookupError(msg) def showfuncargs(config): - from _pytest.main import Session - session = Session(config) + from _pytest.main import wrap_session + return wrap_session(config, _showfuncargs_main) + +def _showfuncargs_main(config, session): session.perform_collect() if session.items: plugins = session.items[0].getplugins() diff --git a/_pytest/runner.py b/_pytest/runner.py --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -14,17 +14,15 @@ # # pytest plugin hooks -# XXX move to pytest_sessionstart and fix py.test owns tests -def pytest_configure(config): - config._setupstate = SetupState() +def pytest_sessionstart(session): + session._setupstate = SetupState() def pytest_sessionfinish(session, exitstatus): - if hasattr(session.config, '_setupstate'): - hook = session.config.hook - rep = hook.pytest__teardown_final(session=session) - if rep: - hook.pytest__teardown_final_logerror(session=session, report=rep) - session.exitstatus = 1 + hook = session.config.hook + rep = hook.pytest__teardown_final(session=session) + if rep: + hook.pytest__teardown_final_logerror(session=session, report=rep) + session.exitstatus = 1 class NodeInfo: def __init__(self, location): @@ -46,16 +44,16 @@ return reports def pytest_runtest_setup(item): - item.config._setupstate.prepare(item) + item.session._setupstate.prepare(item) def pytest_runtest_call(item): item.runtest() def pytest_runtest_teardown(item): - item.config._setupstate.teardown_exact(item) + item.session._setupstate.teardown_exact(item) def pytest__teardown_final(session): - call = CallInfo(session.config._setupstate.teardown_all, when="teardown") + call = CallInfo(session._setupstate.teardown_all, when="teardown") if call.excinfo: ntraceback = call.excinfo.traceback .cut(excludepath=py._pydir) call.excinfo.traceback = ntraceback.filter() diff --git a/lib-python/TODO b/lib-python/TODO deleted file mode 100644 --- a/lib-python/TODO +++ /dev/null @@ -1,100 +0,0 @@ -TODO list for 2.7.0 -=================== - -You can find the results of the most recent buildbot run at: -http://buildbot.pypy.org/ - - -Probably easy tasks -------------------- - -- (unicode|bytearray).(index|find) should accept None as indices (see - test_unicode.py) - -- missing posix.confstr and posix.confstr_names - -- remove code duplication: bit_length() and _count_bits() in rlib/rbigint.py, - objspace/std/longobject.py and objspace/std/longtype.py. - -- missing module pyexpat.errors - -- support for PYTHONIOENCODING, this needs a way to update file.encoding - -- implement format__Complex_ANY() in pypy/objspace/std/complexobject.py - -- Code like this does not work, for two reasons:: - - \ - from __future__ import (with_statement, - unicode_literals) - assert type("") is unicode - -- Code like:: - - assert(x is not None, "error message") - - should emit a SyntaxWarning when compiled (the tuple is always true) - - -Medium tasks ------------- - -- socket module has a couple of changes (including AF_TIPC packet range) - -Longer tasks ------------- - -- Fix usage of __cmp__ in subclasses:: - - class badint(int): - def __cmp__(self, other): - raise RuntimeError - raises(RuntimeError, cmp, 0, badint(1)) - -- Fix comparison of objects layout: if two classes have the same __slots__, it - should be possible to change the instances __class__:: - - class A(object): __slots__ = ('a', 'b') - class B(object): __slots__ = ('b', 'a') - a = A() - a.__class__ = B - -- Show a ResourceWarning when a file/socket is not explicitely closed, like - CPython did for 3.2: http://svn.python.org/view?view=rev&revision=85920 - in PyPy this should be enabled by default - -Won't do for this release -------------------------- - -Note: when you give up with a missing feature, please mention it here, as well -as the various skips added to the test suite. - -- py3k warnings - - * the -3 flag is accepted on the command line, but displays a warning (see - `translator/goal/app_main.py`) - -- CJK codecs. - - * In `./conftest.py`, skipped all `test_codecencodings_*.py` and - `test_codecmaps_*.py`. - - * In test_codecs, commented out various items in `all_unicode_encodings`. - -- Error messages about ill-formed calls (like "argument after ** must be a - mapping") don't always show the function name. That's hard to fix for - the case of errors raised when the Argument object is created (as opposed - to when parsing for a given target function, which occurs later). - - * Some "..." were added to doctests in test_extcall.py - -- CPython's builtin methods are both functions and unbound methods (for - example, `str.upper is dict(str.__dict__)['upper']`). This is not the case - in pypy, and assertions like `object.__str__ is object.__str__` are False - with pypy. Use the `==` operator instead. - - * pprint.py, _threading_local.py - -- When importing a nested module fails, the ImportError message mentions the - name of the package up to the component that could not be imported (CPython - prefers to display the names starting with the failing part). diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -569,7 +569,6 @@ # import os import time -import socket import getpass class ReallyRunFileExternal(py.test.collect.Item): diff --git a/lib-python/modified-2.7/ctypes/__init__.py b/lib-python/modified-2.7/ctypes/__init__.py --- a/lib-python/modified-2.7/ctypes/__init__.py +++ b/lib-python/modified-2.7/ctypes/__init__.py @@ -7,6 +7,7 @@ __version__ = "1.1.0" +import _ffi from _ctypes import Union, Structure, Array from _ctypes import _Pointer from _ctypes import CFuncPtr as _CFuncPtr @@ -350,7 +351,7 @@ self._FuncPtr = _FuncPtr if handle is None: - self._handle = _dlopen(self._name, mode) + self._handle = _ffi.CDLL(name) else: self._handle = handle diff --git a/lib-python/modified-2.7/ctypes/test/test_cfuncs.py b/lib-python/modified-2.7/ctypes/test/test_cfuncs.py --- a/lib-python/modified-2.7/ctypes/test/test_cfuncs.py +++ b/lib-python/modified-2.7/ctypes/test/test_cfuncs.py @@ -3,8 +3,8 @@ import unittest from ctypes import * - import _ctypes_test +from test.test_support import impl_detail class CFunctions(unittest.TestCase): _dll = CDLL(_ctypes_test.__file__) @@ -158,12 +158,14 @@ self.assertEqual(self._dll.tf_bd(0, 42.), 14.) self.assertEqual(self.S(), 42) + @impl_detail('long double not supported by PyPy', pypy=False) def test_longdouble(self): self._dll.tf_D.restype = c_longdouble self._dll.tf_D.argtypes = (c_longdouble,) self.assertEqual(self._dll.tf_D(42.), 14.) self.assertEqual(self.S(), 42) - + + @impl_detail('long double not supported by PyPy', pypy=False) def test_longdouble_plus(self): self._dll.tf_bD.restype = c_longdouble self._dll.tf_bD.argtypes = (c_byte, c_longdouble) diff --git a/lib-python/modified-2.7/ctypes/test/test_functions.py b/lib-python/modified-2.7/ctypes/test/test_functions.py --- a/lib-python/modified-2.7/ctypes/test/test_functions.py +++ b/lib-python/modified-2.7/ctypes/test/test_functions.py @@ -8,6 +8,7 @@ from ctypes import * import sys, unittest from ctypes.test import xfail +from test.test_support import impl_detail try: WINFUNCTYPE @@ -144,6 +145,7 @@ self.assertEqual(result, -21) self.assertEqual(type(result), float) + @impl_detail('long double not supported by PyPy', pypy=False) def test_longdoubleresult(self): f = dll._testfunc_D_bhilfD f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble] diff --git a/lib-python/modified-2.7/ctypes/test/test_libc.py b/lib-python/modified-2.7/ctypes/test/test_libc.py --- a/lib-python/modified-2.7/ctypes/test/test_libc.py +++ b/lib-python/modified-2.7/ctypes/test/test_libc.py @@ -26,6 +26,7 @@ self.assertEqual(chars.raw, " ,,aaaadmmmnpppsss\x00") def test_no_more_xfail(self): + import socket import ctypes.test self.assertTrue(not hasattr(ctypes.test, 'xfail'), "You should incrementally grep for '@xfail' and remove them, they are real failures") diff --git a/lib-python/modified-2.7/distutils/sysconfig.py b/lib-python/modified-2.7/distutils/sysconfig.py --- a/lib-python/modified-2.7/distutils/sysconfig.py +++ b/lib-python/modified-2.7/distutils/sysconfig.py @@ -20,8 +20,10 @@ if '__pypy__' in sys.builtin_module_names: from distutils.sysconfig_pypy import * from distutils.sysconfig_pypy import _config_vars # needed by setuptools + from distutils.sysconfig_pypy import _variable_rx # read_setup_file() else: from distutils.sysconfig_cpython import * from distutils.sysconfig_cpython import _config_vars # needed by setuptools + from distutils.sysconfig_cpython import _variable_rx # read_setup_file() diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,3 +116,7 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + +from sysconfig_cpython import ( + parse_makefile, _variable_rx, expand_makefile_vars) + diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,14 +4399,8 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) - self.assertTrue(l.__add__.im_class is list) + self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__objclass__ is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/lib-python/modified-2.7/test/test_extcall.py b/lib-python/modified-2.7/test/test_extcall.py --- a/lib-python/modified-2.7/test/test_extcall.py +++ b/lib-python/modified-2.7/test/test_extcall.py @@ -299,7 +299,7 @@ def f(a): return a self.assertEqual(f(**{u'a': 4}), 4) - self.assertRaises(TypeError, lambda: f(**{u'stören': 4})) + self.assertRaises(TypeError, f, **{u'stören': 4}) self.assertRaises(TypeError, f, **{u'someLongString':2}) try: f(a=4, **{u'a': 4}) diff --git a/lib-python/2.7/test/test_multibytecodec.py b/lib-python/modified-2.7/test/test_multibytecodec.py copy from lib-python/2.7/test/test_multibytecodec.py copy to lib-python/modified-2.7/test/test_multibytecodec.py --- a/lib-python/2.7/test/test_multibytecodec.py +++ b/lib-python/modified-2.7/test/test_multibytecodec.py @@ -42,7 +42,7 @@ dec = codecs.getdecoder('euc-kr') myreplace = lambda exc: (u'', sys.maxint+1) codecs.register_error('test.cjktest', myreplace) - self.assertRaises(IndexError, dec, + self.assertRaises((IndexError, OverflowError), dec, 'apple\x92ham\x93spam', 'test.cjktest') def test_codingspec(self): diff --git a/lib-python/2.7/test/test_multibytecodec_support.py b/lib-python/modified-2.7/test/test_multibytecodec_support.py copy from lib-python/2.7/test/test_multibytecodec_support.py copy to lib-python/modified-2.7/test/test_multibytecodec_support.py --- a/lib-python/2.7/test/test_multibytecodec_support.py +++ b/lib-python/modified-2.7/test/test_multibytecodec_support.py @@ -107,8 +107,8 @@ def myreplace(exc): return (u'x', sys.maxint + 1) codecs.register_error("test.cjktest", myreplace) - self.assertRaises(IndexError, self.encode, self.unmappedunicode, - 'test.cjktest') + self.assertRaises((IndexError, OverflowError), self.encode, + self.unmappedunicode, 'test.cjktest') def test_callback_None_index(self): def myreplace(exc): diff --git a/lib-python/modified-2.7/test/test_support.py b/lib-python/modified-2.7/test/test_support.py --- a/lib-python/modified-2.7/test/test_support.py +++ b/lib-python/modified-2.7/test/test_support.py @@ -1066,7 +1066,7 @@ if '--pdb' in sys.argv: import pdb, traceback traceback.print_tb(exc_info[2]) - pdb.post_mortem(exc_info[2], pdb.Pdb) + pdb.post_mortem(exc_info[2]) # ---------------------------------- diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py --- a/lib_pypy/_ctypes/array.py +++ b/lib_pypy/_ctypes/array.py @@ -208,6 +208,9 @@ def _get_buffer_value(self): return self._buffer.buffer + def _to_ffi_param(self): + return self._get_buffer_value() + ARRAY_CACHE = {} def create_array_type(base, length): diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -1,5 +1,6 @@ import _rawffi +import _ffi import sys keepalive_key = str # XXX fix this when provided with test @@ -46,6 +47,14 @@ else: return self.from_param(as_parameter) + def get_ffi_param(self, value): + return self.from_param(value)._to_ffi_param() + + def get_ffi_argtype(self): + if self._ffiargtype: + return self._ffiargtype + return _shape_to_ffi_type(self._ffiargshape) + def _CData_output(self, resbuffer, base=None, index=-1): #assert isinstance(resbuffer, _rawffi.ArrayInstance) """Used when data exits ctypes and goes into user code. @@ -99,6 +108,7 @@ """ __metaclass__ = _CDataMeta _objects = None + _ffiargtype = None def __init__(self, *args, **kwds): raise TypeError("%s has no type" % (type(self),)) @@ -119,6 +129,12 @@ def _get_buffer_value(self): return self._buffer[0] + def _to_ffi_param(self): + if self.__class__._is_pointer_like(): + return self._get_buffer_value() + else: + return self.value + def __buffer__(self): return buffer(self._buffer) @@ -150,7 +166,7 @@ return pointer(cdata) def cdata_from_address(self, address): - # fix the address, in case it's unsigned + # fix the address: turn it into as unsigned, in case it's a negative number address = address & (sys.maxint * 2 + 1) instance = self.__new__(self) lgt = getattr(self, '_length_', 1) @@ -159,3 +175,48 @@ def addressof(tp): return tp._buffer.buffer + + +# ---------------------------------------------------------------------- + +def is_struct_shape(shape): + # see the corresponding code to set the shape in + # _ctypes.structure._set_shape + return (isinstance(shape, tuple) and + len(shape) == 2 and + isinstance(shape[0], _rawffi.Structure) and + shape[1] == 1) + +def _shape_to_ffi_type(shape): + try: + return _shape_to_ffi_type.typemap[shape] + except KeyError: + pass + if is_struct_shape(shape): + return shape[0].get_ffi_type() + # + assert False, 'unknown shape %s' % (shape,) + + +_shape_to_ffi_type.typemap = { + 'c' : _ffi.types.char, + 'b' : _ffi.types.sbyte, + 'B' : _ffi.types.ubyte, + 'h' : _ffi.types.sshort, + 'u' : _ffi.types.unichar, + 'H' : _ffi.types.ushort, + 'i' : _ffi.types.sint, + 'I' : _ffi.types.uint, + 'l' : _ffi.types.slong, + 'L' : _ffi.types.ulong, + 'q' : _ffi.types.slonglong, + 'Q' : _ffi.types.ulonglong, + 'f' : _ffi.types.float, + 'd' : _ffi.types.double, + 's' : _ffi.types.void_p, + 'P' : _ffi.types.void_p, + 'z' : _ffi.types.void_p, + 'O' : _ffi.types.void_p, + 'Z' : _ffi.types.void_p, + } + diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -1,12 +1,15 @@ + +from _ctypes.basics import _CData, _CDataMeta, cdata_from_address +from _ctypes.primitive import SimpleType, _SimpleCData +from _ctypes.basics import ArgumentError, keepalive_key +from _ctypes.basics import is_struct_shape +from _ctypes.builtin import set_errno, set_last_error import _rawffi +import _ffi import sys import traceback import warnings -from _ctypes.basics import ArgumentError, keepalive_key -from _ctypes.basics import _CData, _CDataMeta, cdata_from_address -from _ctypes.builtin import set_errno, set_last_error -from _ctypes.primitive import SimpleType # XXX this file needs huge refactoring I fear @@ -24,6 +27,7 @@ WIN64 = sys.platform == 'win32' and sys.maxint == 2**63 - 1 + def get_com_error(errcode, riid, pIunk): "Win32 specific: build a COM Error exception" # XXX need C support code @@ -36,6 +40,7 @@ funcptr.restype = int return funcptr(*args) + class CFuncPtrType(_CDataMeta): # XXX write down here defaults and such things @@ -50,6 +55,7 @@ from_address = cdata_from_address + class CFuncPtr(_CData): __metaclass__ = CFuncPtrType @@ -65,10 +71,12 @@ callable = None _ptr = None _buffer = None + _address = None # win32 COM properties _paramflags = None _com_index = None _com_iid = None + _is_fastpath = False __restype_set = False @@ -85,8 +93,11 @@ raise TypeError( "item %d in _argtypes_ has no from_param method" % ( i + 1,)) - self._argtypes_ = argtypes - + # + if all([hasattr(argtype, '_ffiargshape') for argtype in argtypes]): + fastpath_cls = make_fastpath_subclass(self.__class__) + fastpath_cls.enable_fastpath_maybe(self) + self._argtypes_ = list(argtypes) argtypes = property(_getargtypes, _setargtypes) def _getparamflags(self): @@ -133,6 +144,7 @@ paramflags = property(_getparamflags, _setparamflags) + def _getrestype(self): return self._restype_ @@ -146,27 +158,24 @@ callable(restype)): raise TypeError("restype must be a type, a callable, or None") self._restype_ = restype - + def _delrestype(self): self._ptr = None del self._restype_ - + restype = property(_getrestype, _setrestype, _delrestype) def _geterrcheck(self): return getattr(self, '_errcheck_', None) - def _seterrcheck(self, errcheck): if not callable(errcheck): raise TypeError("The errcheck attribute must be callable") self._errcheck_ = errcheck - def _delerrcheck(self): try: del self._errcheck_ except AttributeError: pass - errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck) def _ffishapes(self, args, restype): @@ -181,6 +190,14 @@ restype = 'O' # void return argtypes, restype + def _set_address(self, address): + if not self._buffer: + self._buffer = _rawffi.Array('P')(1) + self._buffer[0] = address + + def _get_address(self): + return self._buffer[0] + def __init__(self, *args): self.name = None self._objects = {keepalive_key(0):self} @@ -188,7 +205,7 @@ # Empty function object -- this is needed for casts if not args: - self._buffer = _rawffi.Array('P')(1) + self._set_address(0) return argsl = list(args) @@ -196,20 +213,24 @@ # Direct construction from raw address if isinstance(argument, (int, long)) and not argsl: - ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) - self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires, self._flags_) - self._buffer = self._ptr.byptr() + self._set_address(argument) + restype = self._restype_ + if restype is None: + import ctypes + restype = ctypes.c_int + self._ptr = self._getfuncptr_fromaddress(self._argtypes_, restype) return - # A callback into Python + + # A callback into python if callable(argument) and not argsl: self.callable = argument ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) if self._restype_ is None: ffires = None - self._ptr = _rawffi.CallbackPtr(self._wrap_callable( - argument, self.argtypes - ), ffiargs, ffires, self._flags_) + self._ptr = _rawffi.CallbackPtr(self._wrap_callable(argument, + self.argtypes), + ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() return @@ -218,7 +239,7 @@ import ctypes self.name, dll = argument if isinstance(dll, str): - self.dll = ctypes.CDLL(dll) + self.dll = ctypes.CDLL(self.dll) else: self.dll = dll if argsl: @@ -227,7 +248,7 @@ raise TypeError("Unknown constructor %s" % (args,)) # We need to check dll anyway ptr = self._getfuncptr([], ctypes.c_int) - self._buffer = ptr.byptr() + self._set_address(ptr.getaddr()) return # A COM function call, by index @@ -270,15 +291,15 @@ # than the length of the argtypes tuple. args = args[:len(self._argtypes_)] else: - plural = len(argtypes) > 1 and "s" or "" + plural = len(self._argtypes_) > 1 and "s" or "" raise TypeError( "This function takes %d argument%s (%s given)" - % (len(argtypes), plural, len(args))) + % (len(self._argtypes_), plural, len(args))) # check that arguments are convertible ## XXX Not as long as ctypes.cast is a callback function with ## py_object arguments... - ## self._convert_args(argtypes, args, {}) + ## self._convert_args(self._argtypes_, args, {}) try: res = self.callable(*args) @@ -301,6 +322,7 @@ RuntimeWarning, stacklevel=2) if self._com_index: + assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( @@ -312,77 +334,63 @@ args[0] = args[0].value else: thisarg = None + + newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) - args, outargs = self._convert_args(argtypes, args, kwargs) - argtypes = [type(arg) for arg in args] + funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) + result = self._call_funcptr(funcptr, *newargs) + result = self._do_errcheck(result, args) - restype = self._restype_ - funcptr = self._getfuncptr(argtypes, restype, thisarg) + if not outargs: + return result + if len(outargs) == 1: + return outargs[0] + return tuple(outargs) + + def _call_funcptr(self, funcptr, *newargs): + if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: set_errno(_rawffi.get_errno()) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) try: - resbuffer = funcptr(*[arg._get_buffer_for_param()._buffer - for arg in args]) + result = funcptr(*newargs) finally: if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: set_errno(_rawffi.get_errno()) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) + # + return self._build_result(self._restype_, result, newargs) - result = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, args[0]) - else: - result = int(resbuffer[0]) - elif restype is not None: - checker = getattr(self.restype, '_check_retval_', None) - if checker: - val = restype(resbuffer[0]) - # the original ctypes seems to make the distinction between - # classes defining a new type, and their subclasses - if '_type_' in restype.__dict__: - val = val.value - result = checker(val) - elif not isinstance(restype, _CDataMeta): - result = restype(resbuffer[0]) - else: - result = restype._CData_retval(resbuffer) - + def _do_errcheck(self, result, args): # The 'errcheck' protocol if self._errcheck_: v = self._errcheck_(result, self, args) # If the errcheck funtion failed, let it throw - # If the errcheck function returned callargs unchanged, + # If the errcheck function returned newargs unchanged, # continue normal processing. # If the errcheck function returned something else, # use that as result. if v is not args: - result = v + return v + return result - if not outargs: - return result - - if len(outargs) == 1: - return outargs[0] - - return tuple(outargs) + def _getfuncptr_fromaddress(self, argtypes, restype): + address = self._get_address() + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires) def _getfuncptr(self, argtypes, restype, thisarg=None): - if self._ptr is not None and argtypes is self._argtypes_: + if self._ptr is not None and (argtypes is self._argtypes_ or argtypes == self._argtypes_): return self._ptr if restype is None or not isinstance(restype, _CDataMeta): import ctypes restype = ctypes.c_int - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape if self._buffer is not None: - ptr = _rawffi.FuncPtr(self._buffer[0], argshapes, resshape, - self._flags_) - if argtypes is self._argtypes_: + ptr = self._getfuncptr_fromaddress(argtypes, restype) + if argtypes == self._argtypes_: self._ptr = ptr return ptr @@ -391,14 +399,20 @@ if not thisarg: raise ValueError("COM method call without VTable") ptr = thisarg[self._com_index - 0x1000] + argshapes = [arg._ffiargshape for arg in argtypes] + resshape = restype._ffiargshape return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) - + cdll = self.dll._handle try: - return cdll.ptr(self.name, argshapes, resshape, self._flags_) + ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes] + ffi_restype = restype.get_ffi_argtype() + self._ptr = cdll.getfunc(self.name, ffi_argtypes, ffi_restype) + return self._ptr except AttributeError: if self._flags_ & _rawffi.FUNCFLAG_CDECL: raise + # Win64 has no stdcall calling conv, so it should also not have the # name mangling of it. if WIN64: @@ -409,23 +423,33 @@ for i in range(33): mangled_name = "_%s@%d" % (self.name, i*4) try: - return cdll.ptr(mangled_name, argshapes, resshape, - self._flags_) + return cdll.getfunc(mangled_name, + ffi_argtypes, ffi_restype, + # XXX self._flags_ + ) except AttributeError: pass raise - @staticmethod - def _conv_param(argtype, arg): - from ctypes import c_char_p, c_wchar_p, c_void_p, c_int + @classmethod + def _conv_param(cls, argtype, arg): + if isinstance(argtype, _CDataMeta): + #arg = argtype.from_param(arg) + arg = argtype.get_ffi_param(arg) + return arg, argtype + if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - # The usual case when argtype is defined - cobj = arg - elif isinstance(arg, str): + return arg._to_ffi_param(), type(arg) + # + # non-usual case: we do the import here to save a lot of code in the + # jit trace of the normal case + from ctypes import c_char_p, c_wchar_p, c_void_p, c_int + # + if isinstance(arg, str): cobj = c_char_p(arg) elif isinstance(arg, unicode): cobj = c_wchar_p(arg) @@ -435,11 +459,13 @@ cobj = c_int(arg) else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj + + return cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): - callargs = [] + newargs = [] outargs = [] + newargtypes = [] total = len(args) paramflags = self._paramflags @@ -470,8 +496,9 @@ val = defval if val is marker: val = 0 - wrapped = self._conv_param(argtype, val) - callargs.append(wrapped) + newarg, newargtype = self._conv_param(argtype, val) + newargs.append(newarg) + newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): if inargs_idx < total: val = args[inargs_idx] @@ -485,38 +512,102 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - wrapped = self._conv_param(argtype, val) - callargs.append(wrapped) + newarg, newargtype = self._conv_param(argtype, val) + newargs.append(newarg) + newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - wrapped = self._conv_param(argtype, defval) + newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) - wrapped = ctypes.byref(val) - callargs.append(wrapped) + newarg = ctypes.byref(val) + newargtype = type(newarg) + newargs.append(newarg) + newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - wrapped = self._conv_param(argtype, args[i]) + newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) - callargs.append(wrapped) + newargs.append(newarg) + newargtypes.append(newargtype) inargs_idx += 1 - if len(callargs) < total: - extra = args[len(callargs):] + if len(newargs) < len(args): + extra = args[len(newargs):] for i, arg in enumerate(extra): try: - wrapped = self._conv_param(None, arg) + newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) - callargs.append(wrapped) + newargs.append(newarg) + newargtypes.append(newargtype) + return newargs, newargtypes, outargs - return callargs, outargs + + def _wrap_result(self, restype, result): + """ + Convert from low-level repr of the result to the high-level python + one. + """ + # hack for performance: if restype is a "simple" primitive type, don't + # allocate the buffer because it's going to be thrown away immediately + if restype.__bases__[0] is _SimpleCData and not restype._is_pointer_like(): + return result + # + shape = restype._ffishape + if is_struct_shape(shape): + buf = result + else: + buf = _rawffi.Array(shape)(1, autofree=True) + buf[0] = result + retval = restype._CData_retval(buf) + return retval + + def _build_result(self, restype, result, argsandobjs): + """Build the function result: + If there is no OUT parameter, return the actual function result + If there is one OUT parameter, return it + If there are many OUT parameters, return a tuple""" + + # XXX: note for the future: the function used to take a "resbuffer", + # i.e. an array of ints. Now it takes a result, which is already a + # python object. All places that do "resbuffer[0]" should check that + # result is actually an int and just use it. + # + # Also, argsandobjs used to be "args" in __call__, now it's "newargs" + # (i.e., the already unwrapped objects). It's used only when we have a + # PARAMFLAG_FOUT and it's probably wrong, I'll fix it when I find a + # failing test + + retval = None + + if self._com_index: + if resbuffer[0] & 0x80000000: + raise get_com_error(resbuffer[0], + self._com_iid, argsandobjs[0]) + else: + retval = int(resbuffer[0]) + elif restype is not None: + checker = getattr(self.restype, '_check_retval_', None) + if checker: + val = restype(result) + # the original ctypes seems to make the distinction between + # classes defining a new type, and their subclasses + if '_type_' in restype.__dict__: + val = val.value + retval = checker(val) + elif not isinstance(restype, _CDataMeta): + retval = restype(result) + else: + retval = self._wrap_result(restype, result) + + return retval def __nonzero__(self): return self._com_index is not None or bool(self._buffer[0]) @@ -532,3 +623,61 @@ self._ptr.free() self._ptr = None self._needs_free = False + + +def make_fastpath_subclass(CFuncPtr): + if CFuncPtr._is_fastpath: + return CFuncPtr + # + try: + return make_fastpath_subclass.memo[CFuncPtr] + except KeyError: + pass + + class CFuncPtrFast(CFuncPtr): + + _is_fastpath = True + _slowpath_allowed = True # set to False by tests + + @classmethod + def enable_fastpath_maybe(cls, obj): + if (obj.callable is None and + obj._com_index is None): + obj.__class__ = cls + + def __rollback(self): + assert self._slowpath_allowed + self.__class__ = CFuncPtr + + # disable the fast path if we reset argtypes + def _setargtypes(self, argtypes): + self.__rollback() + self._setargtypes(argtypes) + argtypes = property(CFuncPtr._getargtypes, _setargtypes) + + def _setcallable(self, func): + self.__rollback() + self.callable = func + callable = property(lambda x: None, _setcallable) + + def _setcom_index(self, idx): + self.__rollback() + self._com_index = idx + _com_index = property(lambda x: None, _setcom_index) + + def __call__(self, *args): + thisarg = None + argtypes = self._argtypes_ + restype = self._restype_ + funcptr = self._getfuncptr(argtypes, restype, thisarg) + try: + result = self._call_funcptr(funcptr, *args) + result = self._do_errcheck(result, args) + except (TypeError, ArgumentError): # XXX, should be FFITypeError + assert self._slowpath_allowed + return CFuncPtr.__call__(self, *args) + return result + + make_fastpath_subclass.memo[CFuncPtr] = CFuncPtrFast + return CFuncPtrFast +make_fastpath_subclass.memo = {} diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py --- a/lib_pypy/_ctypes/pointer.py +++ b/lib_pypy/_ctypes/pointer.py @@ -1,6 +1,7 @@ import _rawffi -from _ctypes.basics import _CData, _CDataMeta, cdata_from_address +import _ffi +from _ctypes.basics import _CData, _CDataMeta, cdata_from_address, ArgumentError from _ctypes.basics import keepalive_key, store_reference, ensure_objects from _ctypes.basics import sizeof, byref from _ctypes.array import Array, array_get_slice_params, array_slice_getitem,\ @@ -19,7 +20,7 @@ length = 1, _ffiargshape = 'P', _ffishape = 'P', - _fficompositesize = None + _fficompositesize = None, ) # XXX check if typedict['_type_'] is any sane # XXX remember about paramfunc @@ -66,6 +67,7 @@ self._ffiarray = ffiarray self.__init__ = __init__ self._type_ = TP + self._ffiargtype = _ffi.types.Pointer(TP.get_ffi_argtype()) from_address = cdata_from_address @@ -114,6 +116,17 @@ contents = property(getcontents, setcontents) + def _as_ffi_pointer_(self, ffitype): + return as_ffi_pointer(self, ffitype) + +def as_ffi_pointer(value, ffitype): + my_ffitype = type(value).get_ffi_argtype() + # for now, we always allow types.pointer, else a lot of tests + # break. We need to rethink how pointers are represented, though + if my_ffitype is not ffitype and ffitype is not _ffi.types.void_p: + raise ArgumentError, "expected %s instance, got %s" % (type(value), ffitype) + return value._get_buffer_value() + def _cast_addr(obj, _, tp): if not (isinstance(tp, _CDataMeta) and tp._is_pointer_like()): raise TypeError("cast() argument 2 must be a pointer type, not %s" diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -1,3 +1,4 @@ +import _ffi import _rawffi import weakref import sys @@ -8,7 +9,7 @@ CArgObject from _ctypes.builtin import ConvMode from _ctypes.array import Array -from _ctypes.pointer import _Pointer +from _ctypes.pointer import _Pointer, as_ffi_pointer class NULL(object): pass @@ -140,6 +141,8 @@ value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) + result._ffiargtype = _ffi.types.Pointer(_ffi.types.char) + elif tp == 'Z': # c_wchar_p def _getvalue(self): @@ -162,6 +165,7 @@ value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) + result._ffiargtype = _ffi.types.Pointer(_ffi.types.unichar) elif tp == 'P': # c_void_p @@ -248,6 +252,12 @@ self._buffer[0] = 0 # VARIANT_FALSE result.value = property(_getvalue, _setvalue) + # make pointer-types compatible with the _ffi fast path + if result._is_pointer_like(): + def _as_ffi_pointer_(self, ffitype): + return as_ffi_pointer(self, ffitype) + result._as_ffi_pointer_ = _as_ffi_pointer_ + return result from_address = cdata_from_address diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -240,6 +240,9 @@ def _get_buffer_value(self): return self._buffer.buffer + def _to_ffi_param(self): + return self._buffer + class StructureMeta(StructOrUnionMeta): _is_union = False diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -275,7 +275,8 @@ return unicode(x, 'utf-8') class Connection(object): - def __init__(self, database, isolation_level="", detect_types=0, timeout=None, cached_statements=None, factory=None): + def __init__(self, database, timeout=5.0, detect_types=0, isolation_level="", + check_same_thread=True, factory=None, cached_statements=100): self.db = c_void_p() if sqlite.sqlite3_open(database, byref(self.db)) != SQLITE_OK: raise OperationalError("Could not open database") @@ -308,7 +309,8 @@ self._aggregates = {} self.aggregate_instances = {} self._collations = {} - self.thread_ident = thread_get_ident() + if check_same_thread: + self.thread_ident = thread_get_ident() def _get_exception(self, error_code = None): if error_code is None: diff --git a/lib_pypy/ctypes_support.py b/lib_pypy/ctypes_support.py --- a/lib_pypy/ctypes_support.py +++ b/lib_pypy/ctypes_support.py @@ -10,8 +10,8 @@ # __________ the standard C library __________ if sys.platform == 'win32': - import _rawffi - standard_c_lib = ctypes.CDLL('msvcrt', handle=_rawffi.get_libc()) + import _ffi + standard_c_lib = ctypes.CDLL('msvcrt', handle=_ffi.get_libc()) else: standard_c_lib = ctypes.CDLL(ctypes.util.find_library('c')) diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py --- a/lib_pypy/datetime.py +++ b/lib_pypy/datetime.py @@ -1422,12 +1422,17 @@ converter = _time.localtime else: converter = _time.gmtime - if 1 - (t % 1.0) < 0.000001: - t = float(int(t)) + 1 - if t < 0: - t -= 1 + if t < 0.0: + us = int(round(((-t) % 1.0) * 1000000)) + if us > 0: + us = 1000000 - us + t -= 1.0 + else: + us = int(round((t % 1.0) * 1000000)) + if us == 1000000: + us = 0 + t += 1.0 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) - us = int((t % 1.0) * 1000000) ss = min(ss, 59) # clamp out leap seconds if the platform has them result = cls(y, m, d, hh, mm, ss, us, tz) if tz is not None: diff --git a/lib_pypy/msvcrt.py b/lib_pypy/msvcrt.py --- a/lib_pypy/msvcrt.py +++ b/lib_pypy/msvcrt.py @@ -46,4 +46,42 @@ e = get_errno() raise IOError(e, errno.errorcode[e]) +# Console I/O routines + +kbhit = _c._kbhit +kbhit.argtypes = [] +kbhit.restype = ctypes.c_int + +getch = _c._getch +getch.argtypes = [] +getch.restype = ctypes.c_char + +getwch = _c._getwch +getwch.argtypes = [] +getwch.restype = ctypes.c_wchar + +getche = _c._getche +getche.argtypes = [] +getche.restype = ctypes.c_char + +getwche = _c._getwche +getwche.argtypes = [] +getwche.restype = ctypes.c_wchar + +putch = _c._putch +putch.argtypes = [ctypes.c_char] +putch.restype = None + +putwch = _c._putwch +putwch.argtypes = [ctypes.c_wchar] +putwch.restype = None + +ungetch = _c._ungetch +ungetch.argtypes = [ctypes.c_char] +ungetch.restype = None + +ungetwch = _c._ungetwch +ungetwch.argtypes = [ctypes.c_wchar] +ungetwch.restype = None + del ctypes diff --git a/lib_pypy/pypy_test/test_datetime.py b/lib_pypy/pypy_test/test_datetime.py --- a/lib_pypy/pypy_test/test_datetime.py +++ b/lib_pypy/pypy_test/test_datetime.py @@ -32,4 +32,28 @@ assert datetime.datetime.utcfromtimestamp(a).microsecond == 0 assert datetime.datetime.utcfromtimestamp(a).second == 1 - +def test_more_datetime_rounding(): + # this test verified on top of CPython 2.7 (using a plain + # "import datetime" above) + expected_results = { + -1000.0: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.9999996: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.4: 'datetime.datetime(1970, 1, 1, 0, 43, 20, 600000)', + -999.0000004: 'datetime.datetime(1970, 1, 1, 0, 43, 21)', + -1.0: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.9999996: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.4: 'datetime.datetime(1970, 1, 1, 0, 59, 59, 600000)', + -0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.4: 'datetime.datetime(1970, 1, 1, 1, 0, 0, 400000)', + 0.9999996: 'datetime.datetime(1970, 1, 1, 1, 0, 1)', + 1000.0: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.0000004: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.4: 'datetime.datetime(1970, 1, 1, 1, 16, 40, 400000)', + 1000.9999996: 'datetime.datetime(1970, 1, 1, 1, 16, 41)', + 1293843661.191: 'datetime.datetime(2011, 1, 1, 2, 1, 1, 191000)', + } + for t in sorted(expected_results): + dt = datetime.datetime.fromtimestamp(t) + assert repr(dt) == expected_results[t] diff --git a/lib_pypy/resource.py b/lib_pypy/resource.py --- a/lib_pypy/resource.py +++ b/lib_pypy/resource.py @@ -7,7 +7,7 @@ from ctypes_support import standard_c_lib as libc from ctypes_support import get_errno -from ctypes import Structure, c_int, c_long, byref, sizeof +from ctypes import Structure, c_int, c_long, byref, sizeof, POINTER from errno import EINVAL, EPERM import _structseq @@ -25,6 +25,8 @@ _setrlimit = libc.setrlimit try: _getpagesize = libc.getpagesize + _getpagesize.argtypes = () + _getpagesize.restype = c_int except AttributeError: from os import sysconf _getpagesize = None @@ -61,6 +63,10 @@ ("ru_nivcsw", c_long), ) +_getrusage.argtypes = (c_int, POINTER(_struct_rusage)) +_getrusage.restype = c_int + + class struct_rusage: __metaclass__ = _structseq.structseqtype @@ -94,6 +100,12 @@ ("rlim_max", rlim_t), ) +_getrlimit.argtypes = (c_int, POINTER(rlimit)) +_getrlimit.restype = c_int +_setrlimit.argtypes = (c_int, POINTER(rlimit)) +_setrlimit.restype = c_int + + @builtinify def getrusage(who): ru = _struct_rusage() diff --git a/lib_pypy/stackless.py b/lib_pypy/stackless.py --- a/lib_pypy/stackless.py +++ b/lib_pypy/stackless.py @@ -200,14 +200,15 @@ # I can't think of a better solution without a real transform. def rewrite_stackless_primitive(coro_state, alive, tempval): - flags, state, thunk, parent = coro_state - for i, frame in enumerate(state): + flags, frame, thunk, parent = coro_state + while frame is not None: retval_expr = _stackless_primitive_registry.get(frame.f_code) if retval_expr: # this tasklet needs to stop pickling here and return its value. tempval = eval(retval_expr, globals(), frame.f_locals) - state = state[:i] - coro_state = flags, state, thunk, parent + coro_state = flags, frame, thunk, parent + break + frame = frame.f_back return coro_state, alive, tempval # @@ -492,23 +493,22 @@ assert two == () # we want to get rid of the parent thing. # for now, we just drop it - a, b, c, d = coro_state - + a, frame, c, d = coro_state + # Removing all frames related to stackless.py. # They point to stuff we don't want to be pickled. - frame_list = list(b) - new_frame_list = [] - for frame in frame_list: + + pickleframe = frame + while frame is not None: if frame.f_code == schedule.func_code: # Removing everything including and after the # call to stackless.schedule() + pickleframe = frame.f_back break - new_frame_list.append(frame) - b = tuple(new_frame_list) - + frame = frame.f_back if d: assert isinstance(d, coroutine) - coro_state = a, b, c, None + coro_state = a, pickleframe, c, None coro_state, alive, tempval = rewrite_stackless_primitive(coro_state, self.alive, self.tempval) inst_dict = self.__dict__.copy() inst_dict.pop('tempval', None) diff --git a/py/__init__.py b/py/__init__.py --- a/py/__init__.py +++ b/py/__init__.py @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2010 """ -__version__ = '1.4.3' +__version__ = '1.4.4.dev1' from py import _apipkg @@ -70,10 +70,6 @@ 'getrawcode' : '._code.code:getrawcode', 'patch_builtins' : '._code.code:patch_builtins', 'unpatch_builtins' : '._code.code:unpatch_builtins', - '_AssertionError' : '._code.assertion:AssertionError', - '_reinterpret_old' : '._code.assertion:reinterpret_old', - '_reinterpret' : '._code.assertion:reinterpret', - '_reprcompare' : '._code.assertion:_reprcompare', }, # backports and additions of builtins diff --git a/py/_code/_assertionnew.py b/py/_code/_assertionnew.py deleted file mode 100644 --- a/py/_code/_assertionnew.py +++ /dev/null @@ -1,339 +0,0 @@ -""" -Find intermediate evalutation results in assert statements through builtin AST. -This should replace _assertionold.py eventually. -""" - -import sys -import ast - -import py -from py._code.assertion import _format_explanation, BuiltinAssertionError - - -if sys.platform.startswith("java") and sys.version_info < (2, 5, 2): - # See http://bugs.jython.org/issue1497 - _exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict", - "ListComp", "GeneratorExp", "Yield", "Compare", "Call", - "Repr", "Num", "Str", "Attribute", "Subscript", "Name", - "List", "Tuple") - _stmts = ("FunctionDef", "ClassDef", "Return", "Delete", "Assign", - "AugAssign", "Print", "For", "While", "If", "With", "Raise", - "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom", - "Exec", "Global", "Expr", "Pass", "Break", "Continue") - _expr_nodes = set(getattr(ast, name) for name in _exprs) - _stmt_nodes = set(getattr(ast, name) for name in _stmts) - def _is_ast_expr(node): - return node.__class__ in _expr_nodes - def _is_ast_stmt(node): - return node.__class__ in _stmt_nodes -else: - def _is_ast_expr(node): - return isinstance(node, ast.expr) - def _is_ast_stmt(node): - return isinstance(node, ast.stmt) - - -class Failure(Exception): - """Error found while interpreting AST.""" - - def __init__(self, explanation=""): - self.cause = sys.exc_info() - self.explanation = explanation - - -def interpret(source, frame, should_fail=False): - mod = ast.parse(source) - visitor = DebugInterpreter(frame) - try: - visitor.visit(mod) - except Failure: - failure = sys.exc_info()[1] - return getfailure(failure) - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --no-assert)") - -def run(offending_line, frame=None): - if frame is None: - frame = py.code.Frame(sys._getframe(1)) - return interpret(offending_line, frame) - -def getfailure(failure): - explanation = _format_explanation(failure.explanation) - value = failure.cause[1] - if str(value): - lines = explanation.splitlines() - if not lines: - lines.append("") - lines[0] += " << %s" % (value,) - explanation = "\n".join(lines) - text = "%s: %s" % (failure.cause[0].__name__, explanation) - if text.startswith("AssertionError: assert "): - text = text[16:] - return text - - -operator_map = { - ast.BitOr : "|", - ast.BitXor : "^", - ast.BitAnd : "&", - ast.LShift : "<<", - ast.RShift : ">>", - ast.Add : "+", - ast.Sub : "-", - ast.Mult : "*", - ast.Div : "/", - ast.FloorDiv : "//", - ast.Mod : "%", - ast.Eq : "==", - ast.NotEq : "!=", - ast.Lt : "<", - ast.LtE : "<=", - ast.Gt : ">", - ast.GtE : ">=", - ast.Pow : "**", - ast.Is : "is", - ast.IsNot : "is not", - ast.In : "in", - ast.NotIn : "not in" -} - -unary_map = { - ast.Not : "not %s", - ast.Invert : "~%s", - ast.USub : "-%s", - ast.UAdd : "+%s" -} - - -class DebugInterpreter(ast.NodeVisitor): - """Interpret AST nodes to gleam useful debugging information. """ - - def __init__(self, frame): - self.frame = frame - - def generic_visit(self, node): - # Fallback when we don't have a special implementation. - if _is_ast_expr(node): - mod = ast.Expression(node) - co = self._compile(mod) - try: - result = self.frame.eval(co) - except Exception: - raise Failure() - explanation = self.frame.repr(result) - return explanation, result - elif _is_ast_stmt(node): - mod = ast.Module([node]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co) - except Exception: - raise Failure() - return None, None - else: - raise AssertionError("can't handle %s" %(node,)) - - def _compile(self, source, mode="eval"): - return compile(source, "", mode) - - def visit_Expr(self, expr): - return self.visit(expr.value) - - def visit_Module(self, mod): - for stmt in mod.body: - self.visit(stmt) - - def visit_Name(self, name): - explanation, result = self.generic_visit(name) - # See if the name is local. - source = "%r in locals() is not globals()" % (name.id,) - co = self._compile(source) - try: - local = self.frame.eval(co) - except Exception: - # have to assume it isn't - local = False - if not local: - return name.id, result - return explanation, result - - def visit_Compare(self, comp): - left = comp.left - left_explanation, left_result = self.visit(left) - for op, next_op in zip(comp.ops, comp.comparators): - next_explanation, next_result = self.visit(next_op) - op_symbol = operator_map[op.__class__] - explanation = "%s %s %s" % (left_explanation, op_symbol, - next_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=next_result) - except Exception: - raise Failure(explanation) - try: - if not result: - break - except KeyboardInterrupt: - raise - except: - break - left_explanation, left_result = next_explanation, next_result - - rcomp = py.code._reprcompare - if rcomp: - res = rcomp(op_symbol, left_result, next_result) - if res: - explanation = res - return explanation, result - - def visit_BoolOp(self, boolop): - is_or = isinstance(boolop.op, ast.Or) - explanations = [] - for operand in boolop.values: - explanation, result = self.visit(operand) - explanations.append(explanation) - if result == is_or: - break - name = is_or and " or " or " and " - explanation = "(" + name.join(explanations) + ")" - return explanation, result - - def visit_UnaryOp(self, unary): - pattern = unary_map[unary.op.__class__] - operand_explanation, operand_result = self.visit(unary.operand) - explanation = pattern % (operand_explanation,) - co = self._compile(pattern % ("__exprinfo_expr",)) - try: - result = self.frame.eval(co, __exprinfo_expr=operand_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_BinOp(self, binop): - left_explanation, left_result = self.visit(binop.left) - right_explanation, right_result = self.visit(binop.right) - symbol = operator_map[binop.op.__class__] - explanation = "(%s %s %s)" % (left_explanation, symbol, - right_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=right_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_Call(self, call): - func_explanation, func = self.visit(call.func) - arg_explanations = [] - ns = {"__exprinfo_func" : func} - arguments = [] - for arg in call.args: - arg_explanation, arg_result = self.visit(arg) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - arguments.append(arg_name) - arg_explanations.append(arg_explanation) - for keyword in call.keywords: - arg_explanation, arg_result = self.visit(keyword.value) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - keyword_source = "%s=%%s" % (keyword.arg) - arguments.append(keyword_source % (arg_name,)) - arg_explanations.append(keyword_source % (arg_explanation,)) - if call.starargs: - arg_explanation, arg_result = self.visit(call.starargs) - arg_name = "__exprinfo_star" - ns[arg_name] = arg_result - arguments.append("*%s" % (arg_name,)) - arg_explanations.append("*%s" % (arg_explanation,)) - if call.kwargs: - arg_explanation, arg_result = self.visit(call.kwargs) - arg_name = "__exprinfo_kwds" - ns[arg_name] = arg_result - arguments.append("**%s" % (arg_name,)) - arg_explanations.append("**%s" % (arg_explanation,)) - args_explained = ", ".join(arg_explanations) - explanation = "%s(%s)" % (func_explanation, args_explained) - args = ", ".join(arguments) - source = "__exprinfo_func(%s)" % (args,) - co = self._compile(source) - try: - result = self.frame.eval(co, **ns) - except Exception: - raise Failure(explanation) - pattern = "%s\n{%s = %s\n}" - rep = self.frame.repr(result) - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def _is_builtin_name(self, name): - pattern = "%r not in globals() and %r not in locals()" - source = pattern % (name.id, name.id) - co = self._compile(source) - try: - return self.frame.eval(co) - except Exception: - return False - - def visit_Attribute(self, attr): - if not isinstance(attr.ctx, ast.Load): - return self.generic_visit(attr) - source_explanation, source_result = self.visit(attr.value) - explanation = "%s.%s" % (source_explanation, attr.attr) - source = "__exprinfo_expr.%s" % (attr.attr,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - raise Failure(explanation) - explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), - self.frame.repr(result), - source_explanation, attr.attr) - # Check if the attr is from an instance. - source = "%r in getattr(__exprinfo_expr, '__dict__', {})" - source = source % (attr.attr,) - co = self._compile(source) - try: - from_instance = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - from_instance = True - if from_instance: - rep = self.frame.repr(result) - pattern = "%s\n{%s = %s\n}" - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def visit_Assert(self, assrt): - test_explanation, test_result = self.visit(assrt.test) - if test_explanation.startswith("False\n{False =") and \ - test_explanation.endswith("\n"): - test_explanation = test_explanation[15:-2] - explanation = "assert %s" % (test_explanation,) - if not test_result: - try: - raise BuiltinAssertionError - except Exception: - raise Failure(explanation) - return explanation, test_result - - def visit_Assign(self, assign): - value_explanation, value_result = self.visit(assign.value) - explanation = "... = %s" % (value_explanation,) - name = ast.Name("__exprinfo_expr", ast.Load(), - lineno=assign.value.lineno, - col_offset=assign.value.col_offset) - new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, - col_offset=assign.col_offset) - mod = ast.Module([new_assign]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co, __exprinfo_expr=value_result) - except Exception: - raise Failure(explanation) - return explanation, value_result diff --git a/py/_code/_assertionold.py b/py/_code/_assertionold.py deleted file mode 100644 --- a/py/_code/_assertionold.py +++ /dev/null @@ -1,555 +0,0 @@ -import py -import sys, inspect -from compiler import parse, ast, pycodegen -from py._code.assertion import BuiltinAssertionError, _format_explanation - -passthroughex = py.builtin._sysex - -class Failure: - def __init__(self, node): - self.exc, self.value, self.tb = sys.exc_info() - self.node = node - -class View(object): - """View base class. - - If C is a subclass of View, then C(x) creates a proxy object around - the object x. The actual class of the proxy is not C in general, - but a *subclass* of C determined by the rules below. To avoid confusion - we call view class the class of the proxy (a subclass of C, so of View) - and object class the class of x. - - Attributes and methods not found in the proxy are automatically read on x. - Other operations like setting attributes are performed on the proxy, as - determined by its view class. The object x is available from the proxy - as its __obj__ attribute. - - The view class selection is determined by the __view__ tuples and the - optional __viewkey__ method. By default, the selected view class is the - most specific subclass of C whose __view__ mentions the class of x. - If no such subclass is found, the search proceeds with the parent - object classes. For example, C(True) will first look for a subclass - of C with __view__ = (..., bool, ...) and only if it doesn't find any - look for one with __view__ = (..., int, ...), and then ..., object,... - If everything fails the class C itself is considered to be the default. - - Alternatively, the view class selection can be driven by another aspect - of the object x, instead of the class of x, by overriding __viewkey__. - See last example at the end of this module. - """ - - _viewcache = {} - __view__ = () - - def __new__(rootclass, obj, *args, **kwds): - self = object.__new__(rootclass) - self.__obj__ = obj - self.__rootclass__ = rootclass - key = self.__viewkey__() - try: - self.__class__ = self._viewcache[key] - except KeyError: - self.__class__ = self._selectsubclass(key) - return self - - def __getattr__(self, attr): - # attributes not found in the normal hierarchy rooted on View - # are looked up in the object's real class - return getattr(self.__obj__, attr) - - def __viewkey__(self): - return self.__obj__.__class__ - - def __matchkey__(self, key, subclasses): - if inspect.isclass(key): - keys = inspect.getmro(key) - else: - keys = [key] - for key in keys: - result = [C for C in subclasses if key in C.__view__] - if result: - return result - return [] - - def _selectsubclass(self, key): - subclasses = list(enumsubclasses(self.__rootclass__)) - for C in subclasses: - if not isinstance(C.__view__, tuple): - C.__view__ = (C.__view__,) - choices = self.__matchkey__(key, subclasses) - if not choices: - return self.__rootclass__ - elif len(choices) == 1: - return choices[0] - else: - # combine the multiple choices - return type('?', tuple(choices), {}) - - def __repr__(self): - return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) - - -def enumsubclasses(cls): - for subcls in cls.__subclasses__(): - for subsubclass in enumsubclasses(subcls): - yield subsubclass - yield cls - - -class Interpretable(View): - """A parse tree node with a few extra methods.""" - explanation = None - - def is_builtin(self, frame): - return False - - def eval(self, frame): - # fall-back for unknown expression nodes - try: - expr = ast.Expression(self.__obj__) - expr.filename = '' - self.__obj__.filename = '' - co = pycodegen.ExpressionCodeGenerator(expr).getCode() - result = frame.eval(co) - except passthroughex: - raise - except: - raise Failure(self) - self.result = result - self.explanation = self.explanation or frame.repr(self.result) - - def run(self, frame): - # fall-back for unknown statement nodes - try: - expr = ast.Module(None, ast.Stmt([self.__obj__])) - expr.filename = '' - co = pycodegen.ModuleCodeGenerator(expr).getCode() - frame.exec_(co) - except passthroughex: - raise - except: - raise Failure(self) - - def nice_explanation(self): - return _format_explanation(self.explanation) - - -class Name(Interpretable): - __view__ = ast.Name - - def is_local(self, frame): - source = '%r in locals() is not globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_global(self, frame): - source = '%r in globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_builtin(self, frame): - source = '%r not in locals() and %r not in globals()' % ( - self.name, self.name) - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - super(Name, self).eval(frame) - if not self.is_local(frame): - self.explanation = self.name - -class Compare(Interpretable): - __view__ = ast.Compare - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - for operation, expr2 in self.ops: - if hasattr(self, 'result'): - # shortcutting in chained expressions - if not frame.is_true(self.result): - break - expr2 = Interpretable(expr2) - expr2.eval(frame) - self.explanation = "%s %s %s" % ( - expr.explanation, operation, expr2.explanation) - source = "__exprinfo_left %s __exprinfo_right" % operation - try: - self.result = frame.eval(source, - __exprinfo_left=expr.result, - __exprinfo_right=expr2.result) - except passthroughex: - raise - except: - raise Failure(self) - expr = expr2 - -class And(Interpretable): - __view__ = ast.And - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if not frame.is_true(expr.result): - break - self.explanation = '(' + ' and '.join(explanations) + ')' - -class Or(Interpretable): - __view__ = ast.Or - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if frame.is_true(expr.result): - break - self.explanation = '(' + ' or '.join(explanations) + ')' - - -# == Unary operations == -keepalive = [] -for astclass, astpattern in { - ast.Not : 'not __exprinfo_expr', - ast.Invert : '(~__exprinfo_expr)', - }.items(): - - class UnaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - expr = Interpretable(self.expr) - expr.eval(frame) - self.explanation = astpattern.replace('__exprinfo_expr', - expr.explanation) - try: - self.result = frame.eval(astpattern, - __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(UnaryArith) - -# == Binary operations == -for astclass, astpattern in { - ast.Add : '(__exprinfo_left + __exprinfo_right)', - ast.Sub : '(__exprinfo_left - __exprinfo_right)', - ast.Mul : '(__exprinfo_left * __exprinfo_right)', - ast.Div : '(__exprinfo_left / __exprinfo_right)', - ast.Mod : '(__exprinfo_left % __exprinfo_right)', - ast.Power : '(__exprinfo_left ** __exprinfo_right)', - }.items(): - - class BinaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - left = Interpretable(self.left) - left.eval(frame) - right = Interpretable(self.right) - right.eval(frame) - self.explanation = (astpattern - .replace('__exprinfo_left', left .explanation) - .replace('__exprinfo_right', right.explanation)) - try: - self.result = frame.eval(astpattern, - __exprinfo_left=left.result, - __exprinfo_right=right.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(BinaryArith) - - -class CallFunc(Interpretable): - __view__ = ast.CallFunc - - def is_bool(self, frame): - source = 'isinstance(__exprinfo_value, bool)' - try: - return frame.is_true(frame.eval(source, - __exprinfo_value=self.result)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - node = Interpretable(self.node) - node.eval(frame) - explanations = [] - vars = {'__exprinfo_fn': node.result} - source = '__exprinfo_fn(' - for a in self.args: - if isinstance(a, ast.Keyword): - keyword = a.name - a = a.expr - else: - keyword = None - a = Interpretable(a) - a.eval(frame) - argname = '__exprinfo_%d' % len(vars) - vars[argname] = a.result - if keyword is None: - source += argname + ',' - explanations.append(a.explanation) - else: - source += '%s=%s,' % (keyword, argname) - explanations.append('%s=%s' % (keyword, a.explanation)) - if self.star_args: - star_args = Interpretable(self.star_args) - star_args.eval(frame) - argname = '__exprinfo_star' - vars[argname] = star_args.result - source += '*' + argname + ',' - explanations.append('*' + star_args.explanation) - if self.dstar_args: - dstar_args = Interpretable(self.dstar_args) - dstar_args.eval(frame) - argname = '__exprinfo_kwds' - vars[argname] = dstar_args.result - source += '**' + argname + ',' - explanations.append('**' + dstar_args.explanation) - self.explanation = "%s(%s)" % ( - node.explanation, ', '.join(explanations)) - if source.endswith(','): - source = source[:-1] - source += ')' - try: - self.result = frame.eval(source, **vars) - except passthroughex: - raise - except: - raise Failure(self) - if not node.is_builtin(frame) or not self.is_bool(frame): - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -class Getattr(Interpretable): - __view__ = ast.Getattr - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - source = '__exprinfo_expr.%s' % self.attrname - try: - self.result = frame.eval(source, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - self.explanation = '%s.%s' % (expr.explanation, self.attrname) - # if the attribute comes from the instance, its value is interesting - source = ('hasattr(__exprinfo_expr, "__dict__") and ' - '%r in __exprinfo_expr.__dict__' % self.attrname) - try: - from_instance = frame.is_true( - frame.eval(source, __exprinfo_expr=expr.result)) - except passthroughex: - raise - except: - from_instance = True - if from_instance: - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -# == Re-interpretation of full statements == - -class Assert(Interpretable): - __view__ = ast.Assert - - def run(self, frame): - test = Interpretable(self.test) - test.eval(frame) - # simplify 'assert False where False = ...' - if (test.explanation.startswith('False\n{False = ') and - test.explanation.endswith('\n}')): - test.explanation = test.explanation[15:-2] - # print the result as 'assert ' - self.result = test.result - self.explanation = 'assert ' + test.explanation - if not frame.is_true(test.result): - try: - raise BuiltinAssertionError - except passthroughex: - raise - except: - raise Failure(self) - -class Assign(Interpretable): - __view__ = ast.Assign - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = '... = ' + expr.explanation - # fall-back-run the rest of the assignment - ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) - mod = ast.Module(None, ast.Stmt([ass])) - mod.filename = '' - co = pycodegen.ModuleCodeGenerator(mod).getCode() - try: - frame.exec_(co, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - -class Discard(Interpretable): - __view__ = ast.Discard - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = expr.explanation - -class Stmt(Interpretable): - __view__ = ast.Stmt - - def run(self, frame): - for stmt in self.nodes: - stmt = Interpretable(stmt) - stmt.run(frame) - - -def report_failure(e): - explanation = e.node.nice_explanation() - if explanation: - explanation = ", in: " + explanation - else: - explanation = "" - sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) - -def check(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - expr = parse(s, 'eval') - assert isinstance(expr, ast.Expression) - node = Interpretable(expr.node) - try: - node.eval(frame) - except passthroughex: - raise - except Failure: - e = sys.exc_info()[1] - report_failure(e) - else: - if not frame.is_true(node.result): - sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) - - -########################################################### -# API / Entry points -# ######################################################### - -def interpret(source, frame, should_fail=False): - module = Interpretable(parse(source, 'exec').node) - #print "got module", module - if isinstance(frame, py.std.types.FrameType): - frame = py.code.Frame(frame) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - return getfailure(e) - except passthroughex: - raise - except: - import traceback - traceback.print_exc() - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --nomagic)") - else: - return None - -def getmsg(excinfo): - if isinstance(excinfo, tuple): - excinfo = py.code.ExceptionInfo(excinfo) - #frame, line = gettbline(tb) - #frame = py.code.Frame(frame) - #return interpret(line, frame) - - tb = excinfo.traceback[-1] - source = str(tb.statement).strip() - x = interpret(source, tb.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - return x - -def getfailure(e): - explanation = e.node.nice_explanation() - if str(e.value): - lines = explanation.split('\n') - lines[0] += " << %s" % (e.value,) - explanation = '\n'.join(lines) - text = "%s: %s" % (e.exc.__name__, explanation) - if text.startswith('AssertionError: assert '): - text = text[16:] - return text - -def run(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - module = Interpretable(parse(s, 'exec').node) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - report_failure(e) - - -if __name__ == '__main__': - # example: - def f(): - return 5 - def g(): - return 3 - def h(x): - return 'never' - check("f() * g() == 5") - check("not f()") - check("not (f() and g() or 0)") - check("f() == g()") - i = 4 - check("i == f()") - check("len(f()) == 0") - check("isinstance(2+3+4, float)") - - run("x = i") - check("x == 5") - - run("assert not f(), 'oops'") - run("a, b, c = 1, 2") - run("a, b, c = f()") - - check("max([f(),g()]) == 4") - check("'hello'[g()] == 'h'") - run("'guk%d' % h(f())") diff --git a/py/_code/assertion.py b/py/_code/assertion.py deleted file mode 100644 --- a/py/_code/assertion.py +++ /dev/null @@ -1,94 +0,0 @@ -import sys -import py - -BuiltinAssertionError = py.builtin.builtins.AssertionError - -_reprcompare = None # if set, will be called by assert reinterp for comparison ops - -def _format_explanation(explanation): - """This formats an explanation - - Normally all embedded newlines are escaped, however there are - three exceptions: \n{, \n} and \n~. The first two are intended - cover nested explanations, see function and attribute explanations - for examples (.visit_Call(), visit_Attribute()). The last one is - for when one explanation needs to span multiple lines, e.g. when - displaying diffs. - """ - raw_lines = (explanation or '').split('\n') - # escape newlines not followed by {, } and ~ - lines = [raw_lines[0]] - for l in raw_lines[1:]: - if l.startswith('{') or l.startswith('}') or l.startswith('~'): - lines.append(l) - else: - lines[-1] += '\\n' + l - - result = lines[:1] - stack = [0] - stackcnt = [0] - for line in lines[1:]: - if line.startswith('{'): - if stackcnt[-1]: - s = 'and ' - else: - s = 'where ' - stack.append(len(result)) - stackcnt[-1] += 1 - stackcnt.append(0) - result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) - elif line.startswith('}'): - assert line.startswith('}') - stack.pop() - stackcnt.pop() - result[stack[-1]] += line[1:] - else: - assert line.startswith('~') - result.append(' '*len(stack) + line[1:]) - assert len(stack) == 1 - return '\n'.join(result) - - -class AssertionError(BuiltinAssertionError): - def __init__(self, *args): - BuiltinAssertionError.__init__(self, *args) - if args: - try: - self.msg = str(args[0]) - except py.builtin._sysex: - raise - except: - self.msg = "<[broken __repr__] %s at %0xd>" %( - args[0].__class__, id(args[0])) - else: - f = py.code.Frame(sys._getframe(1)) - try: - source = f.code.fullsource - if source is not None: - try: - source = source.getstatement(f.lineno, assertion=True) - except IndexError: - source = None - else: - source = str(source.deindent()).strip() - except py.error.ENOENT: - source = None - # this can also occur during reinterpretation, when the - # co_filename is set to "". - if source: - self.msg = reinterpret(source, f, should_fail=True) - else: - self.msg = "" - if not self.args: - self.args = (self.msg,) - -if sys.version_info > (3, 0): - AssertionError.__module__ = "builtins" - reinterpret_old = "old reinterpretation not available for py3" -else: - from py._code._assertionold import interpret as reinterpret_old -if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): - from py._code._assertionnew import interpret as reinterpret -else: - reinterpret = reinterpret_old - diff --git a/py/_code/code.py b/py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -145,17 +145,6 @@ return self.frame.f_locals locals = property(getlocals, None, None, "locals of underlaying frame") - def reinterpret(self): - """Reinterpret the failing statement and returns a detailed information - about what operations are performed.""" - if self.exprinfo is None: - source = str(self.statement).strip() - x = py.code._reinterpret(source, self.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - self.exprinfo = x - return self.exprinfo - def getfirstlinesource(self): # on Jython this firstlineno can be -1 apparently return max(self.frame.code.firstlineno, 0) @@ -310,7 +299,7 @@ # ExceptionInfo-like classes may have different attributes. if tup is None: tup = sys.exc_info() - if exprinfo is None and isinstance(tup[1], py.code._AssertionError): + if exprinfo is None and isinstance(tup[1], AssertionError): exprinfo = getattr(tup[1], 'msg', None) if exprinfo is None: exprinfo = str(tup[1]) @@ -690,22 +679,15 @@ oldbuiltins = {} -def patch_builtins(assertion=True, compile=True): - """ put compile and AssertionError builtins to Python's builtins. """ - if assertion: - from py._code import assertion - l = oldbuiltins.setdefault('AssertionError', []) - l.append(py.builtin.builtins.AssertionError) - py.builtin.builtins.AssertionError = assertion.AssertionError +def patch_builtins(compile=True): + """ put compile builtins to Python's builtins. """ if compile: l = oldbuiltins.setdefault('compile', []) l.append(py.builtin.builtins.compile) py.builtin.builtins.compile = py.code.compile -def unpatch_builtins(assertion=True, compile=True): +def unpatch_builtins(compile=True): """ remove compile and AssertionError builtins from Python builtins. """ - if assertion: - py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop() if compile: py.builtin.builtins.compile = oldbuiltins['compile'].pop() diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py --- a/pypy/annotation/annrpython.py +++ b/pypy/annotation/annrpython.py @@ -228,7 +228,7 @@ # graph -- it's already low-level operations! for a, s_newarg in zip(graph.getargs(), cells): s_oldarg = self.binding(a) - assert s_oldarg.contains(s_newarg) + assert annmodel.unionof(s_oldarg, s_newarg) == s_oldarg else: assert not self.frozen for a in cells: diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -279,13 +279,13 @@ desc = self.getdesc(cls) return desc.getuniqueclassdef() - def getlistdef(self, **flags): + def getlistdef(self, **flags_if_new): """Get the ListDef associated with the current position.""" try: listdef = self.listdefs[self.position_key] except KeyError: listdef = self.listdefs[self.position_key] = ListDef(self) - listdef.listitem.__dict__.update(flags) + listdef.listitem.__dict__.update(flags_if_new) return listdef def newlist(self, *s_values, **flags): @@ -294,14 +294,18 @@ listdef = self.getlistdef(**flags) for s_value in s_values: listdef.generalize(s_value) + if flags: + assert flags.keys() == ['range_step'] + listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) @@ -351,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -379,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py --- a/pypy/annotation/description.py +++ b/pypy/annotation/description.py @@ -565,7 +565,7 @@ if self.is_exception_class(): if self.pyobj.__module__ == 'exceptions': return True - if self.pyobj is py.code._AssertionError: + if issubclass(self.pyobj, AssertionError): return True return False diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/annotation/listdef.py b/pypy/annotation/listdef.py --- a/pypy/annotation/listdef.py +++ b/pypy/annotation/listdef.py @@ -184,6 +184,11 @@ def generalize(self, s_value): self.listitem.generalize(s_value) + def generalize_range_step(self, range_step): + newlistitem = ListItem(self.listitem.bookkeeper, s_ImpossibleValue) + newlistitem.range_step = range_step + self.listitem.merge(newlistitem) + def __repr__(self): return '<[%r]%s%s%s%s>' % (self.listitem.s_value, self.listitem.mutated and 'm' or '', diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py --- a/pypy/annotation/model.py +++ b/pypy/annotation/model.py @@ -32,13 +32,15 @@ import pypy from pypy.tool import descriptor from pypy.tool.pairtype import pair, extendabletype -from pypy.tool.tls import tlsobject from pypy.rlib.rarithmetic import r_uint, r_ulonglong, base_int from pypy.rlib.rarithmetic import r_singlefloat, r_longfloat import inspect, weakref DEBUG = False # set to False to disable recording of debugging information -TLS = tlsobject() + +class State(object): + pass +TLS = State() class SomeObject(object): """The set of all objects. Each instance stands diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py --- a/pypy/annotation/test/test_annrpython.py +++ b/pypy/annotation/test/test_annrpython.py @@ -3483,6 +3483,17 @@ a = self.RPythonAnnotator() raises(Exception, a.build_types, f, [int]) + def test_range_variable_step(self): + def g(n): + return range(0, 10, n) + def f(n): + r = g(1) # constant step, at first + s = g(n) # but it becomes a variable step + return r + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.listdef.listitem.range_step == 0 + def g(n): return [0,1,2,n] diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -33,13 +33,17 @@ "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", "_bisect", "binascii", "_multiprocessing", '_warnings', - "_collections", "_multibytecodec", "micronumpy"] + "_collections", "_multibytecodec", "micronumpy", "_ffi"] )) translation_modules = default_modules.copy() translation_modules.update(dict.fromkeys( ["fcntl", "rctime", "select", "signal", "_rawffi", "zlib", - "struct", "_md5", "cStringIO", "array"])) + "struct", "_md5", "cStringIO", "array", "_ffi", + # the following are needed for pyrepl (and hence for the + # interactive prompt/pdb) + "termios", "_minimal_curses", + ])) working_oo_modules = default_modules.copy() working_oo_modules.update(dict.fromkeys( @@ -80,6 +84,7 @@ "_rawffi": [("objspace.usemodules.struct", True)], "cpyext": [("translation.secondaryentrypoints", "cpyext"), ("translation.shared", sys.platform == "win32")], + "_ffi": [("translation.jit_ffi", True)], } module_import_dependencies = { diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py --- a/pypy/config/test/test_pypyoption.py +++ b/pypy/config/test/test_pypyoption.py @@ -73,3 +73,7 @@ fn = prefix + "." + path + ".txt" yield check_file_exists, fn +def test__ffi_opt(): + config = get_pypy_config(translating=True) + config.objspace.usemodules._ffi = True + assert config.translation.jit_ffi diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -117,6 +117,8 @@ ChoiceOption("jit_profiler", "integrate profiler support into the JIT", ["off", "oprofile"], default="off"), + # jit_ffi is automatically turned on by withmod-_ffi (which is enabled by default) + BoolOption("jit_ffi", "optimize libffi calls", default=False, cmdline=None), # misc BoolOption("verbose", "Print extra information", default=False), diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -136,6 +136,11 @@ next access. Any code that uses weak proxies must carefully catch such ``ReferenceError`` at any place that uses them. +As a side effect, the ``finally`` clause inside a generator will be executed +only when the generator object is garbage collected (see `issue 736`__). + +.. __: http://bugs.pypy.org/issue736 + There are a few extra implications for the difference in the GC. Most notably, if an object has a ``__del__``, the ``__del__`` is never called more than once in PyPy; but CPython will call the same ``__del__`` several times @@ -168,6 +173,11 @@ >>>> A.__del__ = lambda self: None __main__:1: RuntimeWarning: a __del__ method added to an existing type will not be called +Even more obscure: the same is true, for old-style classes, if you attach +the ``__del__`` to an instance (even in CPython this does not work with +new-style classes). You get a RuntimeWarning in PyPy. To fix these cases +just make sure there is a ``__del__`` method in the class to start with. + Subclasses of built-in types ---------------------------- @@ -238,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/doc/garbage_collection.rst b/pypy/doc/garbage_collection.rst --- a/pypy/doc/garbage_collection.rst +++ b/pypy/doc/garbage_collection.rst @@ -212,90 +212,4 @@ becomes free garbage, to be collected at the next major collection. -Minimark GC ------------ - -This is a simplification and rewrite of the ideas from the Hybrid GC. -It uses a nursery for the young objects, and mark-and-sweep for the old -objects. This is a moving GC, but objects may only move once (from -the nursery to the old stage). - -The main difference with the Hybrid GC is that the mark-and-sweep -objects (the "old stage") are directly handled by the GC's custom -allocator, instead of being handled by malloc() calls. The gain is that -it is then possible, during a major collection, to walk through all old -generation objects without needing to store a list of pointers to them. -So as a first approximation, when compared to the Hybrid GC, the -Minimark GC saves one word of memory per old object. - -There are a number of environment variables that can be tweaked to -influence the GC. (Their default value should be ok for most usages.) -You can read more about them at the start of -`pypy/rpython/memory/gc/minimark.py`_. - -In more details: - -- The small newly malloced objects are allocated in the nursery (case 1). - All objects living in the nursery are "young". - -- The big objects are always handled directly by the system malloc(). - But the big newly malloced objects are still "young" when they are - allocated (case 2), even though they don't live in the nursery. - -- When the nursery is full, we do a minor collection, i.e. we find - which "young" objects are still alive (from cases 1 and 2). The - "young" flag is then removed. The surviving case 1 objects are moved - to the old stage. The dying case 2 objects are immediately freed. - -- The old stage is an area of memory containing old (small) objects. It - is handled by `pypy/rpython/memory/gc/minimarkpage.py`_. It is organized - as "arenas" of 256KB or 512KB, subdivided into "pages" of 4KB or 8KB. - Each page can either be free, or contain small objects of all the same - size. Furthermore at any point in time each object location can be - either allocated or freed. The basic design comes from ``obmalloc.c`` - from CPython (which itself comes from the same source as the Linux - system malloc()). - -- New objects are added to the old stage at every minor collection. - Immediately after a minor collection, when we reach some threshold, we - trigger a major collection. This is the mark-and-sweep step. It walks - over *all* objects (mark), and then frees some fraction of them (sweep). - This means that the only time when we want to free objects is while - walking over all of them; we never ask to free an object given just its - address. This allows some simplifications and memory savings when - compared to ``obmalloc.c``. - -- As with all generational collectors, this GC needs a write barrier to - record which old objects have a reference to young objects. - -- Additionally, we found out that it is useful to handle the case of - big arrays specially: when we allocate a big array (with the system - malloc()), we reserve a small number of bytes before. When the array - grows old, we use the extra bytes as a set of bits. Each bit - represents 128 entries in the array. Whenever the write barrier is - called to record a reference from the Nth entry of the array to some - young object, we set the bit number ``(N/128)`` to 1. This can - considerably speed up minor collections, because we then only have to - scan 128 entries of the array instead of all of them. - -- As usual, we need special care about weak references, and objects with - finalizers. Weak references are allocated in the nursery, and if they - survive they move to the old stage, as usual for all objects; the - difference is that the reference they contain must either follow the - object, or be set to NULL if the object dies. And the objects with - finalizers, considered rare enough, are immediately allocated old to - simplify the design. In particular their ``__del__`` method can only - be called just after a major collection. - -- The objects move once only, so we can use a trick to implement id() - and hash(). If the object is not in the nursery, it won't move any - more, so its id() and hash() are the object's address, cast to an - integer. If the object is in the nursery, and we ask for its id() - or its hash(), then we pre-reserve a location in the old stage, and - return the address of that location. If the object survives the - next minor collection, we move it there, and so its id() and hash() - are preserved. If the object dies then the pre-reserved location - becomes free garbage, to be collected at the next major collection. - - .. include:: _ref.txt diff --git a/pypy/doc/image/jitviewer.png b/pypy/doc/image/jitviewer.png new file mode 100644 index 0000000000000000000000000000000000000000..ad2abca5c88125061fa519dcf3f9fada577573ee GIT binary patch [cut] diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -21,6 +21,8 @@ * `speed.pypy.org`_: Daily benchmarks of how fast PyPy is +* `potential project ideas`_: In case you want to get your feet wet... + Documentation for the PyPy Python Interpreter =============================================== @@ -59,8 +61,6 @@ (if they are not already developed in the FAQ_). You can find logs of the channel here_. -.. XXX play1? - Meeting PyPy developers ======================= @@ -83,7 +83,7 @@ .. _`Release 1.5`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html - +.. _`potential project ideas`: project-ideas.html Project Documentation ===================================== diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/project-ideas.rst @@ -0,0 +1,149 @@ + +Potential project list +====================== + +This is a list of projects that are interesting for potential contributors +who are seriously interested in the PyPy project. They mostly share common +patterns - they're mid-to-large in size, they're usually well defined as +a standalone projects and they're not being actively worked on. For small +projects that you might want to work on, it's much better to either look +at the `issue tracker`_, pop up on #pypy on irc.freenode.net or write to the +`mailing list`_. This is simply for the reason that small possible projects +tend to change very rapidly. + +This list is mostly for having on overview on potential projects. This list is +by definition not exhaustive and we're pleased if people come up with their +own improvement ideas. In any case, if you feel like working on some of those +projects, or anything else in PyPy, pop up on IRC or write to us on the +`mailing list`_. + +Numpy improvements +------------------ + +This is more of a project-container than a single project. Possible ideas: + +* experiment with auto-vectorization using SSE or implement vectorization + without automatically detecting it for array operations. + +* improve numpy, for example implement memory views. + +* interface with fortran/C libraries. + +Improving the jitviewer +------------------------ + +Analyzing performance of applications is always tricky. We have various +tools, for example a `jitviewer`_ that help us analyze performance. + +The jitviewer shows the code generated by the PyPy JIT in a hierarchical way, +as shown by the screenshot below: + + - at the bottom level, it shows the Python source code of the compiled loops + + - for each source code line, it shows the corresponding Python bytecode + + - for each opcode, it shows the corresponding jit operations, which are the + ones actually sent to the backend for compiling (such as ``i15 = i10 < + 2000`` in the example) + +.. image:: image/jitviewer.png + +We would like to add one level to this hierarchy, by showing the generated +machine code for each jit operation. The necessary information is already in +the log file produced by the JIT, so it is "only" a matter of teaching the +jitviewer to display it. Ideally, the machine code should be hidden by +default and viewable on request. + +The jitviewer is a web application based on flask and jinja2 (and jQuery on +the client): if you have great web developing skills and want to help PyPy, +this is an ideal task to get started, because it does not require any deep +knowledge of the internals. + +Translation Toolchain +--------------------- + +* Incremental or distributed translation. + +* Allow separate compilation of extension modules. + +Work on some of other languages +------------------------------- + +There are various languages implemented using the RPython translation toolchain. +One of the most interesting is the `JavaScript implementation`_, but there +are others like scheme or prolog. An interesting project would be to improve +the jittability of those or to experiment with various optimizations. + +Various GCs +----------- + +PyPy has pluggable garbage collection policy. This means that various garbage +collectors can be written for specialized purposes, or even various +experiments can be done for the general purpose. Examples + +* An incremental garbage collector that has specified maximal pause times, + crucial for games + +* A garbage collector that compact memory better for mobile devices + +* A concurrent garbage collector (a lot of work) + +Remove the GIL +-------------- + +This is a major task that requires lots of thinking. However, few subprojects +can be potentially specified, unless a better plan can be thought out: + +* A thread-aware garbage collector + +* Better RPython primitives for dealing with concurrency + +* JIT passes to remove locks on objects + +* (maybe) implement locking in Python interpreter + +* alternatively, look at Software Transactional Memory + +Introduce new benchmarks +------------------------ + +We're usually happy to introduce new benchmarks. Please consult us +before, but in general something that's real-world python code +and is not already represented is welcome. We need at least a standalone +script that can run without parameters. Example ideas (benchmarks need +to be got from them!): + +* `hg` + +* `sympy` + +Experiment (again) with LLVM backend for RPython compilation +------------------------------------------------------------ + +We already tried working with LLVM and at the time, LLVM was not mature enough +for our needs. It's possible that this has changed, reviving the LLVM backend +(or writing new from scratch) for static compilation would be a good project. + +(On the other hand, just generating C code and using clang might be enough. +The issue with that is the so-called "asmgcc GC root finder", which has tons +of issues of this own. In my opinion (arigo), it would be definitely a +better project to try to optimize the alternative, the "shadowstack" GC root +finder, which is nicely portable. So far it gives a pypy that is around +7% slower.) + +Embedding PyPy +---------------------------------------- + +Being able to embed PyPy, say with its own limited C API, would be +useful. But here is the most interesting variant, straight from +EuroPython live discussion :-) We can have a generic "libpypy.so" that +can be used as a placeholder dynamic library, and when it gets loaded, +it runs a .py module that installs (via ctypes) the interface it wants +exported. This would give us a one-size-fits-all generic .so file to be +imported by any application that wants to load .so files :-) + + +.. _`issue tracker`: http://bugs.pypy.org +.. _`mailing list`: http://mail.python.org/mailman/listinfo/pypy-dev +.. _`jitviewer`: http://bitbucket.org/pypy/jitviewer +.. _`JavaScript implementation`: https://bitbucket.org/pypy/lang-js/overview diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) @@ -90,15 +90,18 @@ ### Construction ### def __init__(self, space, args_w, keywords=None, keywords_w=None, - w_stararg=None, w_starstararg=None): + w_stararg=None, w_starstararg=None, keyword_names_w=None): self.space = space assert isinstance(args_w, list) self.arguments_w = args_w self.keywords = keywords self.keywords_w = keywords_w + self.keyword_names_w = keyword_names_w # matches the tail of .keywords if keywords is not None: assert keywords_w is not None assert len(keywords_w) == len(keywords) + assert (keyword_names_w is None or + len(keyword_names_w) <= len(keywords)) make_sure_not_resized(self.keywords) make_sure_not_resized(self.keywords_w) @@ -132,7 +135,8 @@ def replace_arguments(self, args_w): "Return a new Arguments with a args_w as positional arguments." - return Arguments(self.space, args_w, self.keywords, self.keywords_w) + return Arguments(self.space, args_w, self.keywords, self.keywords_w, + keyword_names_w = self.keyword_names_w) def prepend(self, w_firstarg): "Return a new Arguments with a new argument inserted first." @@ -201,15 +205,16 @@ space.w_TypeError, space.wrap("keywords must be strings")) if e.match(space, space.w_UnicodeEncodeError): - raise OperationError( - space.w_TypeError, - space.wrap("keyword cannot be encoded to ascii")) - raise - if self.keywords and key in self.keywords: - raise operationerrfmt(self.space.w_TypeError, - "got multiple values " - "for keyword argument " - "'%s'", key) + # Allow this to pass through + key = None + else: + raise + else: + if self.keywords and key in self.keywords: + raise operationerrfmt(self.space.w_TypeError, + "got multiple values " + "for keyword argument " + "'%s'", key) keywords[i] = key keywords_w[i] = space.getitem(w_starstararg, w_key) i += 1 @@ -219,6 +224,7 @@ else: self.keywords = self.keywords + keywords self.keywords_w = self.keywords_w + keywords_w + self.keyword_names_w = keys_w def fixedunpack(self, argcount): """The simplest argument parsing: get the 'argcount' arguments, @@ -339,6 +345,10 @@ used_keywords = [False] * num_kwds for i in range(num_kwds): name = keywords[i] + # If name was not encoded as a string, it could be None. In that + # case, it's definitely not going to be in the signature. + if name is None: + continue j = signature.find_argname(name) if j < 0: continue @@ -374,17 +384,26 @@ if has_kwarg: w_kwds = self.space.newdict() if num_remainingkwds: + # + limit = len(keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(keywords)): if not used_keywords[i]: - key = keywords[i] - self.space.setitem(w_kwds, self.space.wrap(key), keywords_w[i]) + if i < limit: + w_key = self.space.wrap(keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + self.space.setitem(w_kwds, w_key, keywords_w[i]) + # scope_w[co_argcount + has_vararg] = w_kwds elif num_remainingkwds: if co_argcount == 0: raise ArgErrCount(avail, num_kwds, co_argcount, has_vararg, has_kwarg, defaults_w, missing) - raise ArgErrUnknownKwds(num_remainingkwds, keywords, used_keywords) + raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords, + used_keywords, self.keyword_names_w) if missing: raise ArgErrCount(avail, num_kwds, @@ -443,9 +462,15 @@ w_args = space.newtuple(self.arguments_w) w_kwds = space.newdict() if self.keywords is not None: + limit = len(self.keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(self.keywords)): - space.setitem(w_kwds, space.wrap(self.keywords[i]), - self.keywords_w[i]) + if i < limit: + w_key = space.wrap(self.keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + space.setitem(w_kwds, w_key, self.keywords_w[i]) return w_args, w_kwds class ArgumentsForTranslation(Arguments): @@ -666,14 +691,33 @@ class ArgErrUnknownKwds(ArgErr): - def __init__(self, num_remainingkwds, keywords, used_keywords): - self.kwd_name = '' + def __init__(self, space, num_remainingkwds, keywords, used_keywords, + keyword_names_w): + name = '' self.num_kwds = num_remainingkwds if num_remainingkwds == 1: for i in range(len(keywords)): if not used_keywords[i]: - self.kwd_name = keywords[i] + name = keywords[i] + if name is None: + # We'll assume it's unicode. Encode it. + # Careful, I *think* it should not be possible to + # get an IndexError here but you never know. + try: + if keyword_names_w is None: + raise IndexError + # note: negative-based indexing from the end + w_name = keyword_names_w[i - len(keywords)] + except IndexError: + name = '?' + else: + w_enc = space.wrap(space.sys.defaultencoding) + w_err = space.wrap("replace") + w_name = space.call_method(w_name, "encode", w_enc, + w_err) + name = space.str_w(w_name) break + self.kwd_name = name def getmsg(self, fnname): if self.num_kwds == 1: diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -133,7 +133,7 @@ def accept_comp_iteration(self, codegen, index): self.elt.walkabout(codegen) - codegen.emit_op_arg(ops.SET_ADD, index) + codegen.emit_op_arg(ops.SET_ADD, index + 1) class __extend__(ast.DictComp): @@ -147,7 +147,7 @@ def accept_comp_iteration(self, codegen, index): self.value.walkabout(codegen) self.key.walkabout(codegen) - codegen.emit_op_arg(ops.MAP_ADD, index) + codegen.emit_op_arg(ops.MAP_ADD, index + 1) # These are frame blocks. diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -31,11 +31,12 @@ future_lineno = 0 future_column = 0 have_docstring = False + body = None if isinstance(tree, ast.Module): body = tree.body elif isinstance(tree, ast.Interactive): body = tree.body - else: + if body is None: return 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): @@ -91,7 +92,10 @@ return name if len(name) + 2 >= MANGLE_LEN: return name - if name.endswith('__'): + # Don't mangle __id__ or names with dots. The only time a name with a dot + # can occur is when we are compiling an import statement that has a package + # name. + if name.endswith('__') or '.' in name: return name try: i = 0 diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -55,7 +55,7 @@ co_expr = compile(evalexpr, '', 'eval') space = self.space pyco_expr = PyCode._from_code(space, co_expr) - w_res = pyco_expr.exec_host_bytecode(space, w_dict, w_dict) + w_res = pyco_expr.exec_host_bytecode(w_dict, w_dict) res = space.str_w(space.repr(w_res)) if not isinstance(expected, float): assert res == repr(expected) @@ -308,6 +308,15 @@ "p.__name__", os.path.__name__) yield (self.st, 'from os import *', "path.__name__, sep", (os.path.__name__, os.sep)) + yield (self.st, ''' + class A(object): + def m(self): + from __foo__.bar import x + try: + A().m() + except ImportError, e: + msg = str(e) + ''', "msg", "No module named __foo__") def test_if_stmts(self): yield self.st, "a = 42\nif a > 10: a += 2", "a", 44 diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -986,10 +986,7 @@ compiler = self.createcompiler() expression = compiler.compile(expression, '?', 'eval', 0, hidden_applevel=hidden_applevel) - if isinstance(expression, types.CodeType): - # XXX only used by appsupport - expression = PyCode._from_code(self, expression) - if not isinstance(expression, PyCode): + else: raise TypeError, 'space.eval(): expected a string, code or PyCode object' return expression.exec_code(self, w_globals, w_locals) @@ -1004,9 +1001,6 @@ compiler = self.createcompiler() statement = compiler.compile(statement, filename, 'exec', 0, hidden_applevel=hidden_applevel) - if isinstance(statement, types.CodeType): - # XXX only used by appsupport - statement = PyCode._from_code(self, statement) if not isinstance(statement, PyCode): raise TypeError, 'space.exec_(): expected a string, code or PyCode object' w_key = self.wrap('__builtins__') diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -11,14 +11,14 @@ """Interpreter-level exception that signals an exception that should be sent to the application level. - OperationError instances have three public attributes (and no .args), - w_type, w_value and application_traceback, which contain the wrapped + OperationError instances have three attributes (and no .args), + w_type, _w_value and _application_traceback, which contain the wrapped type and value describing the exception, and a chained list of PyTraceback objects making the application-level traceback. """ _w_value = None - application_traceback = None + _application_traceback = None def __init__(self, w_type, w_value, tb=None): if not we_are_translated() and w_type is None: @@ -26,7 +26,7 @@ raise FlowingError(w_value) self.setup(w_type) self._w_value = w_value - self.application_traceback = tb + self._application_traceback = tb def setup(self, w_type): self.w_type = w_type @@ -37,7 +37,7 @@ # for sys.exc_clear() self.w_type = space.w_None self._w_value = space.w_None - self.application_traceback = None + self._application_traceback = None if not we_are_translated(): del self.debug_excs[:] @@ -103,7 +103,7 @@ def print_app_tb_only(self, file): "NOT_RPYTHON" - tb = self.application_traceback + tb = self._application_traceback if tb: import linecache print >> file, "Traceback (application-level):" @@ -251,6 +251,30 @@ def _compute_value(self): raise NotImplementedError + def get_traceback(self): + """Calling this marks the PyTraceback as escaped, i.e. it becomes + accessible and inspectable by app-level Python code. For the JIT. + Note that this has no effect if there are already several traceback + frames recorded, because in this case they are already marked as + escaping by executioncontext.leave() being called with + got_exception=True. + """ + from pypy.interpreter.pytraceback import PyTraceback + tb = self._application_traceback + if tb is not None and isinstance(tb, PyTraceback): + tb.frame.mark_as_escaped() + return tb + + def set_traceback(self, traceback): + """Set the current traceback. It should either be a traceback + pointing to some already-escaped frame, or a traceback for the + current frame. To support the latter case we do not mark the + frame as escaped. The idea is that it will be marked as escaping + only if the exception really propagates out of this frame, by + executioncontext.leave() being called with got_exception=True. + """ + self._application_traceback = traceback + # ____________________________________________________________ # optimization only: avoid the slowest operation -- the string # formatting with '%' -- in the common case were we don't diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -2,6 +2,7 @@ This module defines the abstract base classes that support execution: Code and Frame. """ +from pypy.rlib import jit from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable @@ -97,21 +98,23 @@ "Abstract. Get the expected number of locals." raise TypeError, "abstract" + @jit.dont_look_inside def fast2locals(self): - # Copy values from self.fastlocals_w to self.w_locals + # Copy values from the fastlocals to self.w_locals if self.w_locals is None: self.w_locals = self.space.newdict() varnames = self.getcode().getvarnames() fastscope_w = self.getfastscope() - for i in range(min(len(varnames), len(fastscope_w))): + for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] if w_value is not None: w_name = self.space.wrap(name) self.space.setitem(self.w_locals, w_name, w_value) + @jit.dont_look_inside def locals2fast(self): - # Copy values from self.w_locals to self.fastlocals_w + # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None varnames = self.getcode().getvarnames() numlocals = self.getfastscopelength() diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -58,13 +58,23 @@ frame.f_backref = self.topframeref self.topframeref = jit.virtual_ref(frame) - def leave(self, frame, w_exitvalue): + def leave(self, frame, w_exitvalue, got_exception): try: if self.profilefunc: self._trace(frame, 'leaveframe', w_exitvalue) finally: + frame_vref = self.topframeref self.topframeref = frame.f_backref - jit.virtual_ref_finish(frame) + if frame.escaped or got_exception: + # if this frame escaped to applevel, we must ensure that also + # f_back does + f_back = frame.f_backref() + if f_back: + f_back.mark_as_escaped() + # force the frame (from the JIT point of view), so that it can + # be accessed also later + frame_vref() + jit.virtual_ref_finish(frame_vref, frame) if self.w_tracefunc is not None and not frame.hide(): self.space.frame_trace_action.fire() @@ -102,18 +112,16 @@ # the following interface is for pickling and unpickling def getstate(self, space): - # XXX we could just save the top frame, which brings - # the whole frame stack, but right now we get the whole stack - items = [space.wrap(f) for f in self.getframestack()] - return space.newtuple(items) + if self.topframe is None: + return space.w_None + return self.topframe def setstate(self, space, w_state): from pypy.interpreter.pyframe import PyFrame - frames_w = space.unpackiterable(w_state) - if len(frames_w) > 0: - self.topframe = space.interp_w(PyFrame, frames_w[-1]) + if space.is_w(w_state, space.w_None): + self.topframe = None else: - self.topframe = None + self.topframe = space.interp_w(PyFrame, w_state) def getframestack(self): lst = [] @@ -278,7 +286,7 @@ if operr is not None: w_value = operr.get_w_value(space) w_arg = space.newtuple([operr.w_type, w_value, - space.wrap(operr.application_traceback)]) + space.wrap(operr.get_traceback())]) frame.fast2locals() self.is_tracing += 1 diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack @@ -98,7 +98,7 @@ self.closure) for i in funccallunrolling: if i < nargs: - new_frame.fastlocals_w[i] = args_w[i] + new_frame.locals_stack_w[i] = args_w[i] return new_frame.run() elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1: assert isinstance(code, gateway.BuiltinCodePassThroughArguments1) @@ -158,7 +158,7 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg return new_frame.run() @@ -169,13 +169,13 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = self.defs_w[j] + new_frame.locals_stack_w[i] = self.defs_w[j] i += 1 return new_frame.run() diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/main.py b/pypy/interpreter/main.py --- a/pypy/interpreter/main.py +++ b/pypy/interpreter/main.py @@ -118,7 +118,7 @@ operationerr.normalize_exception(space) w_type = operationerr.w_type w_value = operationerr.get_w_value(space) - w_traceback = space.wrap(operationerr.application_traceback) + w_traceback = space.wrap(operationerr.get_traceback()) # for debugging convenience we also insert the exception into # the interpreter-level sys.last_xxx diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -127,6 +127,7 @@ if self.cells is not None: self.cells[:ncellvars] = cellvars + @jit.dont_look_inside def fast2locals(self): super_fast2locals(self) # cellvars are values exported to inner scopes @@ -145,6 +146,7 @@ w_name = self.space.wrap(name) self.space.setitem(self.w_locals, w_name, w_value) + @jit.dont_look_inside def locals2fast(self): super_locals2fast(self) freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars @@ -168,7 +170,7 @@ for i in range(len(args_to_copy)): argnum = args_to_copy[i] if argnum >= 0: - self.cells[i].set(self.fastlocals_w[argnum]) + self.cells[i].set(self.locals_stack_w[argnum]) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -63,6 +63,7 @@ the pypy compiler""" self.space = space eval.Code.__init__(self, name) + assert nlocals >= 0 self.co_argcount = argcount self.co_nlocals = nlocals self.co_stacksize = stacksize @@ -95,7 +96,7 @@ if self.co_flags & CO_VARKEYWORDS: argcount += 1 # Cell vars could shadow already-set arguments. - # astcompiler.pyassem used to be clever about the order of + # The compiler used to be clever about the order of # the variables in both co_varnames and co_cellvars, but # it no longer is for the sake of simplicity. Moreover # code objects loaded from CPython don't necessarily follow @@ -202,7 +203,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -215,7 +216,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -256,7 +257,7 @@ tuple(self.co_freevars), tuple(self.co_cellvars) ) - def exec_host_bytecode(self, w_dict, w_globals, w_locals): + def exec_host_bytecode(self, w_globals, w_locals): from pypy.interpreter.pyframe import CPythonFrame frame = CPythonFrame(self.space, self, w_globals, None) frame.setdictscope(w_locals) diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -101,9 +101,9 @@ """ def __init__(self, space, override_version=None): PyCodeCompiler.__init__(self, space) - self.parser = pyparse.PythonParser(space) + self.future_flags = future.futureFlags_2_7 + self.parser = pyparse.PythonParser(space, self.future_flags) self.additional_rules = {} - self.future_flags = future.futureFlags_2_7 self.compiler_flags = self.future_flags.allowed_flags def compile_ast(self, node, filename, mode, flags): @@ -140,9 +140,6 @@ def _compile_to_ast(self, source, info): space = self.space try: - f_flags, future_info = future.get_futures(self.future_flags, source) - info.last_future_import = future_info - info.flags |= f_flags parse_tree = self.parser.parse_source(source, info) mod = astbuilder.ast_from_node(space, parse_tree, info) except parseerror.IndentationError, e: diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -9,9 +9,9 @@ from pypy.interpreter import pytraceback from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib.jit import hint -from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.debug import make_sure_not_resized, check_nonneg from pypy.rlib.rarithmetic import intmask -from pypy.rlib import jit, rstack +from pypy.rlib import jit from pypy.tool import stdlib_opcode from pypy.tool.stdlib_opcode import host_bytecode_spec @@ -49,24 +49,36 @@ instr_ub = 0 instr_prev_plus_one = 0 is_being_profiled = False + escaped = False # see mark_as_escaped() def __init__(self, space, code, w_globals, closure): self = hint(self, access_directly=True, fresh_virtualizable=True) assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals) - self.valuestack_w = [None] * code.co_stacksize - self.valuestackdepth = 0 + self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize) + self.nlocals = code.co_nlocals + self.valuestackdepth = code.co_nlocals self.lastblock = None + make_sure_not_resized(self.locals_stack_w) + check_nonneg(self.nlocals) + # if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure, code) - self.fastlocals_w = [None] * code.co_nlocals - make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno + def mark_as_escaped(self): + """ + Must be called on frames that are exposed to applevel, e.g. by + sys._getframe(). This ensures that the virtualref holding the frame + is properly forced by ec.leave(), and thus the frame will be still + accessible even after the corresponding C stack died. + """ + self.escaped = True + def append_block(self, block): block.previous = self.lastblock self.lastblock = block @@ -138,6 +150,7 @@ not self.space.config.translating) executioncontext = self.space.getexecutioncontext() executioncontext.enter(self) + got_exception = True w_exitvalue = self.space.w_None try: executioncontext.call_trace(self) @@ -157,8 +170,6 @@ try: w_exitvalue = self.dispatch(self.pycode, next_instr, executioncontext) - rstack.resume_point("execute_frame", self, executioncontext, - returns=w_exitvalue) except Exception: executioncontext.return_trace(self, self.space.w_None) raise @@ -166,22 +177,23 @@ # clean up the exception, might be useful for not # allocating exception objects in some cases self.last_exception = None + got_exception = False finally: - executioncontext.leave(self, w_exitvalue) + executioncontext.leave(self, w_exitvalue, got_exception) return w_exitvalue execute_frame.insert_stack_check_here = True # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth - self.valuestack_w[depth] = w_object + self.locals_stack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 - assert depth >= 0, "pop from empty value stack" - w_object = self.valuestack_w[depth] - self.valuestack_w[depth] = None + assert depth >= self.nlocals, "pop from empty value stack" + w_object = self.locals_stack_w[depth] + self.locals_stack_w[depth] = None self.valuestackdepth = depth return w_object @@ -207,24 +219,24 @@ def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n - assert base >= 0 + assert base >= self.nlocals while True: n -= 1 if n < 0: break - values_w[n] = self.valuestack_w[base+n] + values_w[n] = self.locals_stack_w[base+n] return values_w @jit.unroll_safe def dropvalues(self, n): n = hint(n, promote=True) finaldepth = self.valuestackdepth - n - assert finaldepth >= 0, "stack underflow in dropvalues()" + assert finaldepth >= self.nlocals, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break - self.valuestack_w[finaldepth+n] = None + self.locals_stack_w[finaldepth+n] = None self.valuestackdepth = finaldepth @jit.unroll_safe @@ -251,30 +263,30 @@ # Contrast this with CPython where it's PEEK(-1). index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "peek past the bottom of the stack" - return self.valuestack_w[index] + assert index >= self.nlocals, "peek past the bottom of the stack" + return self.locals_stack_w[index] def settopvalue(self, w_object, index_from_top=0): index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "settop past the bottom of the stack" - self.valuestack_w[index] = w_object + assert index >= self.nlocals, "settop past the bottom of the stack" + self.locals_stack_w[index] = w_object @jit.unroll_safe def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 finaldepth = hint(finaldepth, promote=True) while depth >= finaldepth: - self.valuestack_w[depth] = None + self.locals_stack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth - def savevaluestack(self): - return self.valuestack_w[:self.valuestackdepth] + def save_locals_stack(self): + return self.locals_stack_w[:self.valuestackdepth] - def restorevaluestack(self, items_w): - assert None not in items_w - self.valuestack_w[:len(items_w)] = items_w + def restore_locals_stack(self, items_w): + self.locals_stack_w[:len(items_w)] = items_w + self.init_cells() self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): @@ -304,17 +316,18 @@ else: f_lineno = self.f_lineno - values_w = self.valuestack_w[0:self.valuestackdepth] + values_w = self.locals_stack_w[self.nlocals:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) - w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) + w_fastlocals = maker.slp_into_tuple_with_nulls( + space, self.locals_stack_w[:self.nlocals]) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None else: w_exc_value = self.last_exception.get_w_value(space) - w_tb = w(self.last_exception.application_traceback) + w_tb = w(self.last_exception.get_traceback()) tup_state = [ w(self.f_backref()), @@ -389,7 +402,8 @@ new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) - new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None @@ -413,27 +427,28 @@ @jit.dont_look_inside def getfastscope(self): "Get the fast locals as a list." - return self.fastlocals_w + return self.locals_stack_w + @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) - if scope_len > len(self.fastlocals_w): + if scope_len > self.nlocals: raise ValueError, "new fastscope is longer than the allocated area" - # don't assign directly to 'fastlocals_w[:scope_len]' to be + # don't assign directly to 'locals_stack_w[:scope_len]' to be # virtualizable-friendly for i in range(scope_len): - self.fastlocals_w[i] = scope_w[i] + self.locals_stack_w[i] = scope_w[i] self.init_cells() def init_cells(self): - """Initialize cellvars from self.fastlocals_w + """Initialize cellvars from self.locals_stack_w. This is overridden in nestedscope.py""" pass def getfastscopelength(self): - return self.pycode.co_nlocals + return self.nlocals def getclosure(self): return None @@ -634,7 +649,7 @@ while f is not None and f.last_exception is None: f = f.f_backref() if f is not None: - return space.wrap(f.last_exception.application_traceback) + return space.wrap(f.last_exception.get_traceback()) return space.w_None def fget_f_restricted(self, space): diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -11,7 +11,7 @@ from pypy.interpreter.pycode import PyCode from pypy.tool.sourcetools import func_with_new_name from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib import jit, rstackovf, rstack +from pypy.rlib import jit, rstackovf from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import check_nonneg @@ -83,16 +83,12 @@ try: while True: next_instr = self.handle_bytecode(co_code, next_instr, ec) - rstack.resume_point("dispatch", self, co_code, ec, - returns=next_instr) except ExitFrame: return self.popvalue() def handle_bytecode(self, co_code, next_instr, ec): try: next_instr = self.dispatch_bytecode(co_code, next_instr, ec) - rstack.resume_point("handle_bytecode", self, co_code, ec, - returns=next_instr) except OperationError, operr: next_instr = self.handle_operation_error(ec, operr) except Reraise: @@ -248,9 +244,6 @@ # dispatch to the opcode method meth = getattr(self, opdesc.methodname) res = meth(oparg, next_instr) - if opdesc.index == self.opcodedesc.CALL_FUNCTION.index: - rstack.resume_point("dispatch_call", self, co_code, - next_instr, ec) # !! warning, for the annotator the next line is not # comparing an int and None - you can't do that. # Instead, it's constant-folded to either True or False @@ -331,7 +324,7 @@ def LOAD_FAST(self, varindex, next_instr): # access a local variable directly - w_value = self.fastlocals_w[varindex] + w_value = self.locals_stack_w[varindex] if w_value is None: self._load_fast_failed(varindex) self.pushvalue(w_value) @@ -350,7 +343,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self.fastlocals_w[varindex] = w_newvalue + self.locals_stack_w[varindex] = w_newvalue def POP_TOP(self, oparg, next_instr): self.popvalue() @@ -573,7 +566,7 @@ else: msg = "raise: arg 3 must be a traceback or None" tb = pytraceback.check_traceback(space, w_traceback, msg) - operror.application_traceback = tb + operror.set_traceback(tb) # special 3-arguments raise, no new traceback obj will be attached raise RaiseWithExplicitTraceback(operror) @@ -703,12 +696,12 @@ LOAD_GLOBAL._always_inline_ = True def DELETE_FAST(self, varindex, next_instr): - if self.fastlocals_w[varindex] is None: + if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise operationerrfmt(self.space.w_UnboundLocalError, message, varname) - self.fastlocals_w[varindex] = None + self.locals_stack_w[varindex] = None def BUILD_TUPLE(self, itemcount, next_instr): items = self.popvalues(itemcount) @@ -953,7 +946,7 @@ isinstance(unroller, SApplicationException)) if is_app_exc: operr = unroller.operr - w_traceback = self.space.wrap(operr.application_traceback) + w_traceback = self.space.wrap(operr.get_traceback()) w_suppress = self.call_contextmanager_exit_function( w_exitfunc, operr.w_type, @@ -997,7 +990,6 @@ args) else: w_result = self.space.call_args(w_function, args) - rstack.resume_point("call_function", self, returns=w_result) self.pushvalue(w_result) def CALL_FUNCTION(self, oparg, next_instr): @@ -1008,8 +1000,6 @@ w_function = self.peekvalue(nargs) try: w_result = self.space.call_valuestack(w_function, nargs, self) - rstack.resume_point("CALL_FUNCTION", self, nargs, - returns=w_result) finally: self.dropvalues(nargs + 1) self.pushvalue(w_result) @@ -1058,13 +1048,13 @@ def SET_ADD(self, oparg, next_instr): w_value = self.popvalue() - w_set = self.peekvalue(oparg) + w_set = self.peekvalue(oparg - 1) self.space.call_method(w_set, 'add', w_value) def MAP_ADD(self, oparg, next_instr): w_key = self.popvalue() w_value = self.popvalue() - w_dict = self.peekvalue(oparg) + w_dict = self.peekvalue(oparg - 1) self.space.setitem(w_dict, w_key, w_value) def SET_LINENO(self, lineno, next_instr): @@ -1087,13 +1077,12 @@ w_dict = self.space.newdict() self.pushvalue(w_dict) + @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): - w_set = self.space.call_function(self.space.w_set) - if itemcount: - w_add = self.space.getattr(w_set, self.space.wrap("add")) - for i in range(itemcount): - w_item = self.popvalue() - self.space.call_function(w_add, w_item) + w_set = self.space.newset() + for i in range(itemcount): + w_item = self.popvalue() + self.space.call_method(w_set, 'add', w_item) self.pushvalue(w_set) def STORE_MAP(self, oparg, next_instr): diff --git a/pypy/interpreter/pyparser/pyparse.py b/pypy/interpreter/pyparser/pyparse.py --- a/pypy/interpreter/pyparser/pyparse.py +++ b/pypy/interpreter/pyparser/pyparse.py @@ -1,6 +1,6 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.pyparser import parser, pytokenizer, pygram, error +from pypy.interpreter.pyparser import future, parser, pytokenizer, pygram, error from pypy.interpreter.astcompiler import consts @@ -88,9 +88,11 @@ class PythonParser(parser.Parser): - def __init__(self, space, grammar=pygram.python_grammar): + def __init__(self, space, future_flags=future.futureFlags_2_7, + grammar=pygram.python_grammar): parser.Parser.__init__(self, grammar) self.space = space + self.future_flags = future_flags def parse_source(self, textsrc, compile_info): """Main entry point for parsing Python source. @@ -133,6 +135,10 @@ raise error.SyntaxError(space.str_w(w_message)) raise + f_flags, future_info = future.get_futures(self.future_flags, textsrc) + compile_info.last_future_import = future_info + compile_info.flags |= f_flags + flags = compile_info.flags if flags & consts.CO_FUTURE_PRINT_FUNCTION: diff --git a/pypy/interpreter/pytraceback.py b/pypy/interpreter/pytraceback.py --- a/pypy/interpreter/pytraceback.py +++ b/pypy/interpreter/pytraceback.py @@ -51,9 +51,9 @@ def record_application_traceback(space, operror, frame, last_instruction): if frame.pycode.hidden_applevel: return - tb = operror.application_traceback + tb = operror.get_traceback() tb = PyTraceback(space, frame, last_instruction, tb) - operror.application_traceback = tb + operror.set_traceback(tb) def offset2lineno(c, stopat): tab = c.co_lnotab diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import py from pypy.interpreter.argument import (Arguments, ArgumentsForTranslation, ArgErr, ArgErrUnknownKwds, ArgErrMultipleValues, ArgErrCount, rawshape, @@ -126,6 +127,7 @@ w_AttributeError = AttributeError w_UnicodeEncodeError = UnicodeEncodeError w_dict = dict + w_str = str class TestArgumentsNormal(object): @@ -485,26 +487,6 @@ args._match_signature(None, l, Signature(['abc'])) assert len(l) == 1 assert l[0] == space.wrap(5) - # - def str_w(w): - try: - return str(w) - except UnicodeEncodeError: - raise OperationError(space.w_UnicodeEncodeError, - space.wrap("oups")) - space.str_w = str_w - w_starstar = space.wrap({u'\u1234': 5}) - err = py.test.raises(OperationError, Arguments, - space, [], w_starstararg=w_starstar) - # Check that we get a TypeError. On CPython it is because of - # "no argument called '?'". On PyPy we get a TypeError too, but - # earlier: "keyword cannot be encoded to ascii". The - # difference, besides the error message, is only apparent if the - # receiver also takes a **arg. Then CPython passes the - # non-ascii unicode unmodified, whereas PyPy complains. We will - # not care until someone has a use case for that. - assert not err.value.match(space, space.w_UnicodeEncodeError) - assert err.value.match(space, space.w_TypeError) class TestErrorHandling(object): def test_missing_args(self): @@ -559,13 +541,26 @@ assert 0, "did not raise" def test_unknown_keywords(self): - err = ArgErrUnknownKwds(1, ['a', 'b'], [True, False]) + space = DummySpace() + err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [True, False], None) s = err.getmsg('foo') assert s == "foo() got an unexpected keyword argument 'b'" - err = ArgErrUnknownKwds(2, ['a', 'b', 'c'], [True, False, False]) + err = ArgErrUnknownKwds(space, 2, ['a', 'b', 'c'], + [True, False, False], None) s = err.getmsg('foo') assert s == "foo() got 2 unexpected keyword arguments" + def test_unknown_unicode_keyword(self): + class DummySpaceUnicode(DummySpace): + class sys: + defaultencoding = 'utf-8' + space = DummySpaceUnicode() + err = ArgErrUnknownKwds(space, 1, ['a', None, 'b', 'c'], + [True, False, True, True], + [unichr(0x1234), u'b', u'c']) + s = err.getmsg('foo') + assert s == "foo() got an unexpected keyword argument '\xe1\x88\xb4'" + def test_multiple_values(self): err = ArgErrMultipleValues('bla') s = err.getmsg('foo') @@ -592,6 +587,14 @@ exc = raises(TypeError, (lambda a, b, **kw: 0), a=1) assert exc.value.message == "() takes exactly 2 non-keyword arguments (0 given)" + def test_unicode_keywords(self): + def f(**kwargs): + assert kwargs[u"美"] == 42 + f(**{u"美" : 42}) + def f(x): pass + e = raises(TypeError, "f(**{u'ü' : 19})") + assert "?" in str(e.value) + def make_arguments_for_translation(space, args_w, keywords_w={}, w_stararg=None, w_starstararg=None): return ArgumentsForTranslation(space, args_w, keywords_w.keys(), diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -714,6 +714,12 @@ class AppTestCompiler: + def test_bom_with_future(self): + s = '\xef\xbb\xbffrom __future__ import division\nx = 1/2' + ns = {} + exec s in ns + assert ns["x"] == .5 + def test_values_of_different_types(self): exec "a = 0; b = 0L; c = 0.0; d = 0j" assert type(a) is int diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py --- a/pypy/interpreter/test/test_eval.py +++ b/pypy/interpreter/test/test_eval.py @@ -15,16 +15,16 @@ self.code = code Frame.__init__(self, space) self.numlocals = numlocals - self.fastlocals_w = [None] * self.numlocals + self._fastlocals_w = [None] * self.numlocals def getcode(self): return self.code def setfastscope(self, scope_w): - self.fastlocals_w = scope_w + self._fastlocals_w = scope_w def getfastscope(self): - return self.fastlocals_w + return self._fastlocals_w def getfastscopelength(self): return self.numlocals @@ -38,11 +38,11 @@ self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({})) - self.f.fastlocals_w[0] = w(5) + self.f._fastlocals_w[0] = w(5) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5})) - self.f.fastlocals_w[2] = w(7) + self.f._fastlocals_w[2] = w(7) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5, 'args': 7})) @@ -57,13 +57,13 @@ w = self.space.wrap self.f.w_locals = self.space.wrap({}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [None]*5) + self.sameList(self.f._fastlocals_w, [None]*5) self.f.w_locals = self.space.wrap({'x': 5}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) + self.sameList(self.f._fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.wrap({'x':5, 'args':7}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), None, w(7), - None, None]) + self.sameList(self.f._fastlocals_w, [w(5), None, w(7), + None, None]) diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py --- a/pypy/interpreter/test/test_pyframe.py +++ b/pypy/interpreter/test/test_pyframe.py @@ -98,6 +98,15 @@ return sys._getframe().f_back.f_code.co_name f() + def test_f_back_virtualref(self): + import sys + def f(): + return g() + def g(): + return sys._getframe() + frame = f() + assert frame.f_back.f_code.co_name == 'f' + def test_f_exc_xxx(self): import sys @@ -122,6 +131,21 @@ except: g(sys.exc_info()) + def test_virtualref_through_traceback(self): + import sys + def g(): + try: + raise ValueError + except: + _, _, tb = sys.exc_info() + return tb + def f(): + return g() + # + tb = f() + assert tb.tb_frame.f_code.co_name == 'g' + assert tb.tb_frame.f_back.f_code.co_name == 'f' + def test_trace_basic(self): import sys l = [] diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -203,3 +203,17 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + import sys + class A(object): + def m(self): + "aaa" + m.x = 3 + + bm = A().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -761,12 +761,15 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -136,6 +136,7 @@ 'call' : (('ref', 'varargs'), 'intorptr'), 'call_assembler' : (('varargs',), 'intorptr'), 'cond_call_gc_wb' : (('ptr', 'ptr'), None), + 'cond_call_gc_wb_array': (('ptr', 'int', 'ptr'), None), 'oosend' : (('varargs',), 'intorptr'), 'oosend_pure' : (('varargs',), 'intorptr'), 'guard_true' : (('bool',), None), @@ -600,15 +601,15 @@ # return _op_default_implementation - def op_debug_merge_point(self, _, value, recdepth): + def op_debug_merge_point(self, _, *args): from pypy.jit.metainterp.warmspot import get_stats - loc = ConstPtr(value)._get_str() try: stats = get_stats() except AttributeError: pass else: - stats.add_merge_point_location(loc) + stats.add_merge_point_location(args[1:]) + pass def op_guard_true(self, _, value): if not value: @@ -820,6 +821,12 @@ raise NotImplementedError def op_call(self, calldescr, func, *args): + return self._do_call(calldescr, func, args, call_with_llptr=False) + + def op_call_release_gil(self, calldescr, func, *args): + return self._do_call(calldescr, func, args, call_with_llptr=True) + + def _do_call(self, calldescr, func, args, call_with_llptr): global _last_exception assert _last_exception is None, "exception left behind" assert _call_args_i == _call_args_r == _call_args_f == [] @@ -838,7 +845,8 @@ else: raise TypeError(x) try: - return _do_call_common(func, args_in_order, calldescr) + return _do_call_common(func, args_in_order, calldescr, + call_with_llptr) except LLException, lle: _last_exception = lle d = {'v': None, @@ -850,6 +858,9 @@ def op_cond_call_gc_wb(self, descr, a, b): py.test.skip("cond_call_gc_wb not supported") + def op_cond_call_gc_wb_array(self, descr, a, b, c): + py.test.skip("cond_call_gc_wb_array not supported") + def op_oosend(self, descr, obj, *args): raise NotImplementedError("oosend for lltype backend??") @@ -1480,17 +1491,20 @@ 'v': lltype.Void, } -def _do_call_common(f, args_in_order=None, calldescr=None): +def _do_call_common(f, args_in_order=None, calldescr=None, + call_with_llptr=False): ptr = llmemory.cast_int_to_adr(f).ptr PTR = lltype.typeOf(ptr) if PTR == rffi.VOIDP: # it's a pointer to a C function, so we don't have a precise # signature: create one from the descr + assert call_with_llptr is True ARGS = map(kind2TYPE.get, calldescr.arg_types) RESULT = kind2TYPE[calldescr.typeinfo] FUNC = lltype.FuncType(ARGS, RESULT) func_to_call = rffi.cast(lltype.Ptr(FUNC), ptr) else: + assert call_with_llptr is False FUNC = PTR.TO ARGS = FUNC.ARGS func_to_call = ptr._obj._callable diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -134,7 +134,7 @@ old, oldindex = faildescr._compiled_fail llimpl.compile_redirect_fail(old, oldindex, c) - def compile_loop(self, inputargs, operations, looptoken, log=True): + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): """In a real assembler backend, this should assemble the given list of operations. Here we just generate a similar CompiledLoop instance. The code here is RPython, whereas the code in llimpl diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -1,5 +1,6 @@ import py from pypy.rpython.lltypesystem import lltype, rffi, llmemory, rclass +from pypy.rpython.lltypesystem.lloperation import llop from pypy.jit.backend.llsupport import symbolic, support from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr from pypy.jit.metainterp.history import BasicFailDescr, LoopToken, BoxFloat @@ -45,6 +46,8 @@ size = 0 # help translation is_immutable = False + tid = llop.combine_ushort(lltype.Signed, 0, 0) + def __init__(self, size, count_fields_if_immut=-1): self.size = size self.count_fields_if_immut = count_fields_if_immut @@ -149,6 +152,7 @@ class BaseArrayDescr(AbstractDescr): _clsname = '' + tid = llop.combine_ushort(lltype.Signed, 0, 0) def get_base_size(self, translate_support_code): basesize, _, _ = symbolic.get_array_token(_A, translate_support_code) @@ -263,6 +267,9 @@ def __repr__(self): res = '%s(%s)' % (self.__class__.__name__, self.arg_classes) + extraeffect = getattr(self.extrainfo, 'extraeffect', None) + if extraeffect is not None: + res += ' EF=%r' % extraeffect oopspecindex = getattr(self.extrainfo, 'oopspecindex', 0) if oopspecindex: from pypy.jit.codewriter.effectinfo import EffectInfo diff --git a/pypy/jit/backend/llsupport/ffisupport.py b/pypy/jit/backend/llsupport/ffisupport.py --- a/pypy/jit/backend/llsupport/ffisupport.py +++ b/pypy/jit/backend/llsupport/ffisupport.py @@ -3,13 +3,16 @@ from pypy.jit.backend.llsupport.descr import DynamicIntCallDescr, NonGcPtrCallDescr,\ FloatCallDescr, VoidCallDescr +class UnsupportedKind(Exception): + pass + def get_call_descr_dynamic(ffi_args, ffi_result, extrainfo=None): """Get a call descr: the types of result and args are represented by rlib.libffi.types.*""" try: reskind = get_ffi_type_kind(ffi_result) argkinds = [get_ffi_type_kind(arg) for arg in ffi_args] - except KeyError: + except UnsupportedKind: return None # ?? arg_classes = ''.join(argkinds) if reskind == history.INT: @@ -33,7 +36,7 @@ return history.FLOAT elif kind == 'v': return history.VOID - assert False, "Unsupported kind '%s'" % kind + raise UnsupportedKind("Unsupported kind '%s'" % kind) def is_ffi_type_signed(ffi_type): from pypy.rlib.libffi import types diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -34,7 +34,7 @@ pass def do_write_barrier(self, gcref_struct, gcref_newptr): pass - def rewrite_assembler(self, cpu, operations): + def rewrite_assembler(self, cpu, operations, gcrefs_output_list): return operations def can_inline_malloc(self, descr): return False @@ -146,78 +146,6 @@ # All code below is for the hybrid or minimark GC -class GcRefList: - """Handles all references from the generated assembler to GC objects. - This is implemented as a nonmovable, but GC, list; the assembler contains - code that will (for now) always read from this list.""" - - GCREF_LIST = lltype.GcArray(llmemory.GCREF) # followed by the GC - - HASHTABLE = rffi.CArray(llmemory.Address) # ignored by the GC - HASHTABLE_BITS = 10 - HASHTABLE_SIZE = 1 << HASHTABLE_BITS - - def initialize(self): - if we_are_translated(): n = 2000 - else: n = 10 # tests only - self.list = self.alloc_gcref_list(n) - self.nextindex = 0 - self.oldlists = [] - # A pseudo dictionary: it is fixed size, and it may contain - # random nonsense after a collection moved the objects. It is only - # used to avoid too many duplications in the GCREF_LISTs. - self.hashtable = lltype.malloc(self.HASHTABLE, - self.HASHTABLE_SIZE+1, - flavor='raw', track_allocation=False) - dummy = lltype.direct_ptradd(lltype.direct_arrayitems(self.hashtable), - self.HASHTABLE_SIZE) - dummy = llmemory.cast_ptr_to_adr(dummy) - for i in range(self.HASHTABLE_SIZE+1): - self.hashtable[i] = dummy - - def alloc_gcref_list(self, n): - # Important: the GRREF_LISTs allocated are *non-movable*. This - # requires support in the gc (hybrid GC or minimark GC so far). - if we_are_translated(): - list = rgc.malloc_nonmovable(self.GCREF_LIST, n) - assert list, "malloc_nonmovable failed!" - else: - list = lltype.malloc(self.GCREF_LIST, n) # for tests only - return list - - def get_address_of_gcref(self, gcref): - assert lltype.typeOf(gcref) == llmemory.GCREF - # first look in the hashtable, using an inexact hash (fails after - # the object moves) - addr = llmemory.cast_ptr_to_adr(gcref) - hash = llmemory.cast_adr_to_int(addr, "forced") - hash -= hash >> self.HASHTABLE_BITS - hash &= self.HASHTABLE_SIZE - 1 - addr_ref = self.hashtable[hash] - # the following test is safe anyway, because the addresses found - # in the hashtable are always the addresses of nonmovable stuff - # ('addr_ref' is an address inside self.list, not directly the - # address of a real moving GC object -- that's 'addr_ref.address[0]'.) - if addr_ref.address[0] == addr: - return addr_ref - # if it fails, add an entry to the list - if self.nextindex == len(self.list): - # reallocate first, increasing a bit the size every time - self.oldlists.append(self.list) - self.list = self.alloc_gcref_list(len(self.list) // 4 * 5) - self.nextindex = 0 - # add it - index = self.nextindex - self.list[index] = gcref - addr_ref = lltype.direct_ptradd(lltype.direct_arrayitems(self.list), - index) - addr_ref = llmemory.cast_ptr_to_adr(addr_ref) - self.nextindex = index + 1 - # record it in the hashtable - self.hashtable[hash] = addr_ref - return addr_ref - - class GcRootMap_asmgcc(object): """Handles locating the stack roots in the assembler. This is the class supporting --gcrootfinder=asmgcc. @@ -527,6 +455,7 @@ def __init__(self, gc_ll_descr): self.llop1 = gc_ll_descr.llop1 self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR + self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR self.fielddescr_tid = get_field_descr(gc_ll_descr, gc_ll_descr.GCClass.HDR, 'tid') self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG @@ -546,6 +475,14 @@ funcaddr = llmemory.cast_ptr_to_adr(funcptr) return cpu.cast_adr_to_int(funcaddr) + def get_write_barrier_from_array_fn(self, cpu): + # returns a function with arguments [array, index, newvalue] + llop1 = self.llop1 + funcptr = llop1.get_write_barrier_from_array_failing_case( + self.WB_ARRAY_FUNCPTR) + funcaddr = llmemory.cast_ptr_to_adr(funcptr) + return cpu.cast_adr_to_int(funcaddr) # this may return 0 + class GcLLDescr_framework(GcLLDescription): DEBUG = False # forced to True by x86/test/test_zrpy_gc.py @@ -559,7 +496,7 @@ self.translator = translator self.llop1 = llop1 - # we need the hybrid or minimark GC for GcRefList.alloc_gcref_list() + # we need the hybrid or minimark GC for rgc._make_sure_does_not_move() # to work if gcdescr.config.translation.gc not in ('hybrid', 'minimark'): raise NotImplementedError("--gc=%s not implemented with the JIT" % @@ -574,8 +511,6 @@ " with the JIT" % (name,)) gcrootmap = cls(gcdescr) self.gcrootmap = gcrootmap - self.gcrefs = GcRefList() - self.single_gcref_descr = GcPtrFieldDescr('', 0) # make a TransformerLayoutBuilder and save it on the translator # where it can be fished and reused by the FrameworkGCTransformer @@ -617,6 +552,8 @@ [lltype.Signed, lltype.Signed], llmemory.GCREF)) self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType( [llmemory.Address, llmemory.Address], lltype.Void)) + self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType( + [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void)) self.write_barrier_descr = WriteBarrierDescr(self) # def malloc_array(itemsize, tid, num_elem): @@ -706,7 +643,6 @@ return rffi.cast(lltype.Signed, fptr) def initialize(self): - self.gcrefs.initialize() self.gcrootmap.initialize() def init_size_descr(self, S, descr): @@ -768,54 +704,32 @@ funcptr(llmemory.cast_ptr_to_adr(gcref_struct), llmemory.cast_ptr_to_adr(gcref_newptr)) - def replace_constptrs_with_getfield_raw(self, cpu, newops, op): - # xxx some performance issue here - newargs = [None] * op.numargs() - needs_copy = False + def record_constptrs(self, op, gcrefs_output_list): for i in range(op.numargs()): v = op.getarg(i) - newargs[i] = v if isinstance(v, ConstPtr) and bool(v.value): - addr = self.gcrefs.get_address_of_gcref(v.value) - # ^^^even for non-movable objects, to record their presence - if rgc.can_move(v.value): - box = BoxPtr(v.value) - addr = cpu.cast_adr_to_int(addr) - newops.append(ResOperation(rop.GETFIELD_RAW, - [ConstInt(addr)], box, - self.single_gcref_descr)) - newargs[i] = box - needs_copy = True - # - if needs_copy: - return op.copy_and_change(op.getopnum(), args=newargs) - else: - return op + p = v.value + rgc._make_sure_does_not_move(p) + gcrefs_output_list.append(p) - - def rewrite_assembler(self, cpu, operations): + def rewrite_assembler(self, cpu, operations, gcrefs_output_list): # Perform two kinds of rewrites in parallel: # # - Add COND_CALLs to the write barrier before SETFIELD_GC and # SETARRAYITEM_GC operations. # - # - Remove all uses of ConstPtrs away from the assembler. - # Idea: when running on a moving GC, we can't (easily) encode - # the ConstPtrs in the assembler, because they can move at any - # point in time. Instead, we store them in 'gcrefs.list', a GC - # but nonmovable list; and here, we modify 'operations' to - # replace direct usage of ConstPtr with a BoxPtr loaded by a - # GETFIELD_RAW from the array 'gcrefs.list'. + # - Record the ConstPtrs from the assembler. # newops = [] + known_lengths = {} # we can only remember one malloc since the next malloc can possibly # collect last_malloc = None for op in operations: if op.getopnum() == rop.DEBUG_MERGE_POINT: continue - # ---------- replace ConstPtrs with GETFIELD_RAW ---------- - op = self.replace_constptrs_with_getfield_raw(cpu, newops, op) + # ---------- record the ConstPtrs ---------- + self.record_constptrs(op, gcrefs_output_list) if op.is_malloc(): last_malloc = op.result elif op.can_malloc(): @@ -838,10 +752,14 @@ v = op.getarg(2) if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and bool(v.value)): # store a non-NULL - # XXX detect when we should produce a - # write_barrier_from_array - self._gen_write_barrier(newops, op.getarg(0), v) + self._gen_write_barrier_array(newops, op.getarg(0), + op.getarg(1), v, + cpu, known_lengths) op = op.copy_and_change(rop.SETARRAYITEM_RAW) + elif op.getopnum() == rop.NEW_ARRAY: + v_length = op.getarg(0) + if isinstance(v_length, ConstInt): + known_lengths[op.result] = v_length.getint() # ---------- newops.append(op) return newops @@ -851,6 +769,24 @@ newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None, descr=self.write_barrier_descr)) + def _gen_write_barrier_array(self, newops, v_base, v_index, v_value, + cpu, known_lengths): + if self.write_barrier_descr.get_write_barrier_from_array_fn(cpu) != 0: + # If we know statically the length of 'v', and it is not too + # big, then produce a regular write_barrier. If it's unknown or + # too big, produce instead a write_barrier_from_array. + LARGE = 130 + length = known_lengths.get(v_base, LARGE) + if length >= LARGE: + # unknown or too big: produce a write_barrier_from_array + args = [v_base, v_index, v_value] + newops.append(ResOperation(rop.COND_CALL_GC_WB_ARRAY, args, + None, + descr=self.write_barrier_descr)) + return + # fall-back case: produce a write_barrier + self._gen_write_barrier(newops, v_base, v_value) + def can_inline_malloc(self, descr): assert isinstance(descr, BaseSizeDescr) if descr.size < self.max_size_of_young_obj: diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -143,11 +143,11 @@ STACK_CHECK_SLOWPATH = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) def insert_stack_check(): - startaddr = rstack._stack_get_start_adr() - length = rstack._stack_get_length() + endaddr = rstack._stack_get_end_adr() + lengthaddr = rstack._stack_get_length_adr() f = llhelper(STACK_CHECK_SLOWPATH, rstack.stack_check_slowpath) slowpathaddr = rffi.cast(lltype.Signed, f) - return startaddr, length, slowpathaddr + return endaddr, lengthaddr, slowpathaddr self.pos_exception = pos_exception self.pos_exc_value = pos_exc_value diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py --- a/pypy/jit/backend/llsupport/regalloc.py +++ b/pypy/jit/backend/llsupport/regalloc.py @@ -37,6 +37,11 @@ self.frame_depth += size return newloc + def reserve_location_in_frame(self, size): + frame_depth = self.frame_depth + self.frame_depth += size + return frame_depth + # abstract methods that need to be overwritten for specific assemblers @staticmethod def frame_pos(loc, type): @@ -213,6 +218,15 @@ self.reg_bindings[v] = loc return loc + def force_spill_var(self, var): + self._sync_var(var) + try: + loc = self.reg_bindings[var] + del self.reg_bindings[var] + self.free_regs.append(loc) + except KeyError: + pass # 'var' is already not in a register + def loc(self, box): """ Return the location of 'box'. """ diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py --- a/pypy/jit/backend/llsupport/test/test_gc.py +++ b/pypy/jit/backend/llsupport/test/test_gc.py @@ -9,7 +9,7 @@ from pypy.jit.metainterp.resoperation import get_deep_immutable_oplist from pypy.jit.tool.oparser import parse from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists def test_boehm(): gc_ll_descr = GcLLDescr_boehm(None, None, None) @@ -49,19 +49,6 @@ # ____________________________________________________________ -def test_GcRefList(): - S = lltype.GcStruct('S') - order = range(50) * 4 - random.shuffle(order) - allocs = [lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S)) - for i in range(50)] - allocs = [allocs[i] for i in order] - # - gcrefs = GcRefList() - gcrefs.initialize() - addrs = [gcrefs.get_address_of_gcref(ptr) for ptr in allocs] - for i in range(len(allocs)): - assert addrs[i].address[0] == llmemory.cast_ptr_to_adr(allocs[i]) class TestGcRootMapAsmGcc: @@ -288,6 +275,18 @@ def get_write_barrier_failing_case(self, FPTRTYPE): return llhelper(FPTRTYPE, self._write_barrier_failing_case) + _have_wb_from_array = False + + def _write_barrier_from_array_failing_case(self, adr_struct, v_index): + self.record.append(('barrier_from_array', adr_struct, v_index)) + + def get_write_barrier_from_array_failing_case(self, FPTRTYPE): + if self._have_wb_from_array: + return llhelper(FPTRTYPE, + self._write_barrier_from_array_failing_case) + else: + return lltype.nullptr(FPTRTYPE.TO) + class TestFramework(object): gc = 'hybrid' @@ -303,9 +302,20 @@ config = config_ class FakeCPU(object): def cast_adr_to_int(self, adr): - ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR) - assert ptr._obj._callable == llop1._write_barrier_failing_case - return 42 + if not adr: + return 0 + try: + ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR) + assert ptr._obj._callable == \ + llop1._write_barrier_failing_case + return 42 + except lltype.InvalidCast: + ptr = llmemory.cast_adr_to_ptr( + adr, gc_ll_descr.WB_ARRAY_FUNCPTR) + assert ptr._obj._callable == \ + llop1._write_barrier_from_array_failing_case + return 43 + gcdescr = get_description(config_) translator = FakeTranslator() llop1 = FakeLLOp() @@ -414,11 +424,11 @@ ResOperation(rop.DEBUG_MERGE_POINT, ['dummy', 2], None), ] gc_ll_descr = self.gc_ll_descr - operations = gc_ll_descr.rewrite_assembler(None, operations) + operations = gc_ll_descr.rewrite_assembler(None, operations, []) assert len(operations) == 0 def test_rewrite_assembler_1(self): - # check rewriting of ConstPtrs + # check recording of ConstPtrs class MyFakeCPU(object): def cast_adr_to_int(self, adr): assert adr == "some fake address" @@ -438,56 +448,12 @@ ] gc_ll_descr = self.gc_ll_descr gc_ll_descr.gcrefs = MyFakeGCRefList() + gcrefs = [] operations = get_deep_immutable_oplist(operations) - operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) - assert len(operations) == 2 - assert operations[0].getopnum() == rop.GETFIELD_RAW - assert operations[0].getarg(0) == ConstInt(43) - assert operations[0].getdescr() == gc_ll_descr.single_gcref_descr - v_box = operations[0].result - assert isinstance(v_box, BoxPtr) - assert operations[1].getopnum() == rop.PTR_EQ - assert operations[1].getarg(0) == v_random_box - assert operations[1].getarg(1) == v_box - assert operations[1].result == v_result - - def test_rewrite_assembler_1_cannot_move(self): - # check rewriting of ConstPtrs - class MyFakeCPU(object): - def cast_adr_to_int(self, adr): - xxx # should not be called - class MyFakeGCRefList(object): - def get_address_of_gcref(self, s_gcref1): - seen.append(s_gcref1) - assert s_gcref1 == s_gcref - return "some fake address" - seen = [] - S = lltype.GcStruct('S') - s = lltype.malloc(S) - s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s) - v_random_box = BoxPtr() - v_result = BoxInt() - operations = [ - ResOperation(rop.PTR_EQ, [v_random_box, ConstPtr(s_gcref)], - v_result), - ] - gc_ll_descr = self.gc_ll_descr - gc_ll_descr.gcrefs = MyFakeGCRefList() - old_can_move = rgc.can_move - operations = get_deep_immutable_oplist(operations) - try: - rgc.can_move = lambda s: False - operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) - finally: - rgc.can_move = old_can_move - assert len(operations) == 1 - assert operations[0].getopnum() == rop.PTR_EQ - assert operations[0].getarg(0) == v_random_box - assert operations[0].getarg(1) == ConstPtr(s_gcref) - assert operations[0].result == v_result - # check that s_gcref gets added to the list anyway, to make sure - # that the GC sees it - assert seen == [s_gcref] + operations2 = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations, + gcrefs) + assert operations2 == operations + assert gcrefs == [s_gcref] def test_rewrite_assembler_2(self): # check write barriers before SETFIELD_GC @@ -500,7 +466,8 @@ ] gc_ll_descr = self.gc_ll_descr operations = get_deep_immutable_oplist(operations) - operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations, + []) assert len(operations) == 2 # assert operations[0].getopnum() == rop.COND_CALL_GC_WB @@ -515,29 +482,93 @@ def test_rewrite_assembler_3(self): # check write barriers before SETARRAYITEM_GC - v_base = BoxPtr() - v_index = BoxInt() - v_value = BoxPtr() - array_descr = AbstractDescr() - operations = [ - ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value], None, - descr=array_descr), - ] - gc_ll_descr = self.gc_ll_descr - operations = get_deep_immutable_oplist(operations) - operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) - assert len(operations) == 2 - # - assert operations[0].getopnum() == rop.COND_CALL_GC_WB - assert operations[0].getarg(0) == v_base - assert operations[0].getarg(1) == v_value - assert operations[0].result is None - # - assert operations[1].getopnum() == rop.SETARRAYITEM_RAW - assert operations[1].getarg(0) == v_base - assert operations[1].getarg(1) == v_index - assert operations[1].getarg(2) == v_value - assert operations[1].getdescr() == array_descr + for v_new_length in (None, ConstInt(5), ConstInt(5000), BoxInt()): + v_base = BoxPtr() + v_index = BoxInt() + v_value = BoxPtr() + array_descr = AbstractDescr() + operations = [ + ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value], + None, descr=array_descr), + ] + if v_new_length is not None: + operations.insert(0, ResOperation(rop.NEW_ARRAY, + [v_new_length], v_base, + descr=array_descr)) + # we need to insert another, unrelated NEW_ARRAY here + # to prevent the initialization_store optimization + operations.insert(1, ResOperation(rop.NEW_ARRAY, + [ConstInt(12)], BoxPtr(), + descr=array_descr)) + gc_ll_descr = self.gc_ll_descr + operations = get_deep_immutable_oplist(operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) + if v_new_length is not None: + assert operations[0].getopnum() == rop.NEW_ARRAY + assert operations[1].getopnum() == rop.NEW_ARRAY + del operations[:2] + assert len(operations) == 2 + # + assert operations[0].getopnum() == rop.COND_CALL_GC_WB + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_value + assert operations[0].result is None + # + assert operations[1].getopnum() == rop.SETARRAYITEM_RAW + assert operations[1].getarg(0) == v_base + assert operations[1].getarg(1) == v_index + assert operations[1].getarg(2) == v_value + assert operations[1].getdescr() == array_descr + + def test_rewrite_assembler_4(self): + # check write barriers before SETARRAYITEM_GC, + # if we have actually a write_barrier_from_array. + self.llop1._have_wb_from_array = True + for v_new_length in (None, ConstInt(5), ConstInt(5000), BoxInt()): + v_base = BoxPtr() + v_index = BoxInt() + v_value = BoxPtr() + array_descr = AbstractDescr() + operations = [ + ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value], + None, descr=array_descr), + ] + if v_new_length is not None: + operations.insert(0, ResOperation(rop.NEW_ARRAY, + [v_new_length], v_base, + descr=array_descr)) + # we need to insert another, unrelated NEW_ARRAY here + # to prevent the initialization_store optimization + operations.insert(1, ResOperation(rop.NEW_ARRAY, + [ConstInt(12)], BoxPtr(), + descr=array_descr)) + gc_ll_descr = self.gc_ll_descr + operations = get_deep_immutable_oplist(operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) + if v_new_length is not None: + assert operations[0].getopnum() == rop.NEW_ARRAY + assert operations[1].getopnum() == rop.NEW_ARRAY + del operations[:2] + assert len(operations) == 2 + # + if isinstance(v_new_length, ConstInt) and v_new_length.value < 130: + assert operations[0].getopnum() == rop.COND_CALL_GC_WB + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_value + else: + assert operations[0].getopnum() == rop.COND_CALL_GC_WB_ARRAY + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_index + assert operations[0].getarg(2) == v_value + assert operations[0].result is None + # + assert operations[1].getopnum() == rop.SETARRAYITEM_RAW + assert operations[1].getarg(0) == v_base + assert operations[1].getarg(1) == v_index + assert operations[1].getarg(2) == v_value + assert operations[1].getdescr() == array_descr def test_rewrite_assembler_initialization_store(self): S = lltype.GcStruct('S', ('parent', OBJECT), @@ -558,7 +589,8 @@ jump() """, namespace=locals()) operations = get_deep_immutable_oplist(ops.operations) - operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) equaloplists(operations, expected.operations) def test_rewrite_assembler_initialization_store_2(self): @@ -583,7 +615,8 @@ jump() """, namespace=locals()) operations = get_deep_immutable_oplist(ops.operations) - operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) equaloplists(operations, expected.operations) def test_rewrite_assembler_initialization_store_3(self): @@ -602,7 +635,8 @@ jump() """, namespace=locals()) operations = get_deep_immutable_oplist(ops.operations) - operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) equaloplists(operations, expected.operations) class TestFrameworkMiniMark(TestFramework): diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py --- a/pypy/jit/backend/model.py +++ b/pypy/jit/backend/model.py @@ -53,7 +53,7 @@ """Called once by the front-end when the program stops.""" pass - def compile_loop(self, inputargs, operations, looptoken, log=True): + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): """Assemble the given loop. Should create and attach a fresh CompiledLoopToken to looptoken.compiled_loop_token and stick extra attributes diff --git a/pypy/jit/backend/test/calling_convention_test.py b/pypy/jit/backend/test/calling_convention_test.py --- a/pypy/jit/backend/test/calling_convention_test.py +++ b/pypy/jit/backend/test/calling_convention_test.py @@ -23,6 +23,7 @@ def constfloat(x): return ConstFloat(longlong.getfloatstorage(x)) + class FakeStats(object): pass class TestCallingConv(Runner): @@ -30,56 +31,172 @@ Ptr = lltype.Ptr FuncType = lltype.FuncType - def __init__(self): - self.cpu = getcpuclass()(rtyper=None, stats=FakeStats()) - self.cpu.setup_once() + def setup_class(cls): + cls.cpu = getcpuclass()(rtyper=None, stats=FakeStats()) + cls.cpu.setup_once() + + def _prepare_args(self, args, floats, ints): + local_floats = list(floats) + local_ints = list(ints) + expected_result = 0.0 + for i in range(len(args)): + x = args[i] + if x[0] == 'f': + x = local_floats.pop() + t = longlong.getfloatstorage(x) + self.cpu.set_future_value_float(i, t) + else: + x = local_ints.pop() + self.cpu.set_future_value_int(i, x) + expected_result += x + return expected_result @classmethod def get_funcbox(cls, cpu, func_ptr): addr = llmemory.cast_ptr_to_adr(func_ptr) return ConstInt(heaptracker.adr2int(addr)) + def test_call_aligned_with_spilled_values(self): + from pypy.rlib.libffi import types + cpu = self.cpu + if not cpu.supports_floats: + py.test.skip('requires floats') + + + def func(*args): + return float(sum(args)) + + F = lltype.Float + I = lltype.Signed + floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] + ints = [7, 11, 23, 13, -42, 1111, 95, 1] + for case in range(256): + local_floats = list(floats) + local_ints = list(ints) + args = [] + spills = [] + funcargs = [] + float_count = 0 + int_count = 0 + for i in range(8): + if case & (1< 0 + del glob.lst[:] + + cpu = self.cpu + func_adr = llmemory.cast_ptr_to_adr(c_qsort.funcsym) + funcbox = ConstInt(heaptracker.adr2int(func_adr)) + calldescr = cpu.calldescrof_dynamic([types.pointer, types_size_t, + types_size_t, types.pointer], + types.void) + i0 = BoxInt() + i1 = BoxInt() + i2 = BoxInt() + i3 = BoxInt() + tok = BoxInt() + faildescr = BasicFailDescr(1) + ops = [ + ResOperation(rop.CALL_RELEASE_GIL, [funcbox, i0, i1, i2, i3], None, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [], None, descr=BasicFailDescr(0)) + ] + ops[1].setfailargs([]) + looptoken = LoopToken() + self.cpu.compile_loop([i0, i1, i2, i3], ops, looptoken) + self.cpu.set_future_value_int(0, rffi.cast(lltype.Signed, raw)) + self.cpu.set_future_value_int(1, 2) + self.cpu.set_future_value_int(2, 4) + self.cpu.set_future_value_int(3, rffi.cast(lltype.Signed, fn)) + assert glob.lst == [] + fail = self.cpu.execute_token(looptoken) + assert fail.identifier == 0 + assert len(glob.lst) > 0 + lltype.free(raw, flavor='raw') + def test_guard_not_invalidated(self): cpu = self.cpu i0 = BoxInt() diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -128,6 +128,8 @@ if gc_ll_descr.get_malloc_slowpath_addr is not None: self._build_malloc_slowpath() self._build_stack_check_slowpath() + if gc_ll_descr.gcrootmap: + self._build_release_gil(gc_ll_descr.gcrootmap) debug_start('jit-backend-counts') self.set_debug(have_debug_prints()) debug_stop('jit-backend-counts') @@ -137,10 +139,11 @@ self.current_clt = looptoken.compiled_loop_token self.pending_guard_tokens = [] self.mc = codebuf.MachineCodeBlockWrapper() - if self.datablockwrapper is None: - allblocks = self.get_asmmemmgr_blocks(looptoken) - self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr, - allblocks) + #assert self.datablockwrapper is None --- but obscure case + # possible, e.g. getting MemoryError and continuing + allblocks = self.get_asmmemmgr_blocks(looptoken) + self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr, + allblocks) def teardown(self): self.pending_guard_tokens = None @@ -305,7 +308,66 @@ rawstart = mc.materialize(self.cpu.asmmemmgr, []) self.stack_check_slowpath = rawstart - def assemble_loop(self, inputargs, operations, looptoken, log): + @staticmethod + def _release_gil_asmgcc(css): + # similar to trackgcroot.py:pypy_asm_stackwalk, first part + from pypy.rpython.memory.gctransform import asmgcroot + new = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css) + next = asmgcroot.gcrootanchor.next + new.next = next + new.prev = asmgcroot.gcrootanchor + asmgcroot.gcrootanchor.next = new + next.prev = new + # and now release the GIL + before = rffi.aroundstate.before + if before: + before() + + @staticmethod + def _reacquire_gil_asmgcc(css): + # first reacquire the GIL + after = rffi.aroundstate.after + if after: + after() + # similar to trackgcroot.py:pypy_asm_stackwalk, second part + from pypy.rpython.memory.gctransform import asmgcroot + old = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css) + prev = old.prev + next = old.next + prev.next = next + next.prev = prev + + @staticmethod + def _release_gil_shadowstack(): + before = rffi.aroundstate.before + if before: + before() + + @staticmethod + def _reacquire_gil_shadowstack(): + after = rffi.aroundstate.after + if after: + after() + + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) + _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP], + lltype.Void)) + + def _build_release_gil(self, gcrootmap): + if gcrootmap.is_shadow_stack: + releasegil_func = llhelper(self._NOARG_FUNC, + self._release_gil_shadowstack) + reacqgil_func = llhelper(self._NOARG_FUNC, + self._reacquire_gil_shadowstack) + else: + releasegil_func = llhelper(self._CLOSESTACK_FUNC, + self._release_gil_asmgcc) + reacqgil_func = llhelper(self._CLOSESTACK_FUNC, + self._reacquire_gil_asmgcc) + self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) + self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + + def assemble_loop(self, loopname, inputargs, operations, looptoken, log): '''adds the following attributes to looptoken: _x86_loop_code (an integer giving an address) _x86_bootstrap_code (an integer giving an address) @@ -321,6 +383,7 @@ # for the duration of compiling one loop or a one bridge. clt = CompiledLoopToken(self.cpu, looptoken.number) + clt.allgcrefs = [] looptoken.compiled_loop_token = clt if not we_are_translated(): # Arguments should be unique @@ -328,13 +391,13 @@ self.setup(looptoken) self.currently_compiling_loop = looptoken - funcname = self._find_debug_merge_point(operations) if log: self._register_counter() operations = self._inject_debugging_code(looptoken, operations) regalloc = RegAlloc(self, self.cpu.translate_support_code) - arglocs, operations = regalloc.prepare_loop(inputargs, operations, looptoken) + arglocs, operations = regalloc.prepare_loop(inputargs, operations, + looptoken, clt.allgcrefs) looptoken._x86_arglocs = arglocs bootstrappos = self.mc.get_relative_pos() @@ -354,7 +417,7 @@ # rawstart = self.materialize_loop(looptoken) debug_print("Loop #%d (%s) has address %x to %x" % ( - looptoken.number, funcname, + looptoken.number, loopname, rawstart + self.looppos, rawstart + directbootstrappos)) self._patch_stackadjust(rawstart + stackadjustpos, @@ -374,7 +437,7 @@ self.teardown() # oprofile support if self.cpu.profile_agent is not None: - name = "Loop # %s: %s" % (looptoken.number, funcname) + name = "Loop # %s: %s" % (looptoken.number, loopname) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) return ops_offset @@ -394,7 +457,6 @@ return self.setup(original_loop_token) - funcname = self._find_debug_merge_point(operations) if log: self._register_counter() operations = self._inject_debugging_code(faildescr, operations) @@ -406,7 +468,8 @@ regalloc = RegAlloc(self, self.cpu.translate_support_code) fail_depths = faildescr._x86_current_depths operations = regalloc.prepare_bridge(fail_depths, inputargs, arglocs, - operations) + operations, + self.current_clt.allgcrefs) stackadjustpos = self._patchable_stackadjust() frame_depth, param_depth = self._assemble(regalloc, operations) @@ -416,8 +479,8 @@ # rawstart = self.materialize_loop(original_loop_token) - debug_print("Bridge out of guard %d (%s) has address %x to %x" % - (descr_number, funcname, rawstart, rawstart + codeendpos)) + debug_print("Bridge out of guard %d has address %x to %x" % + (descr_number, rawstart, rawstart + codeendpos)) self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -431,7 +494,7 @@ self.teardown() # oprofile support if self.cpu.profile_agent is not None: - name = "Bridge # %s: %s" % (descr_number, funcname) + name = "Bridge # %s" % (descr_number,) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) return ops_offset @@ -491,17 +554,6 @@ return self.mc.materialize(self.cpu.asmmemmgr, allblocks, self.cpu.gc_ll_descr.gcrootmap) - def _find_debug_merge_point(self, operations): - - for op in operations: - if op.getopnum() == rop.DEBUG_MERGE_POINT: - funcname = op.getarg(0)._get_str() - break - else: - funcname = "" % len(self.loop_run_counters) - # invent the counter, so we don't get too confused - return funcname - def _register_counter(self): if self._debug: # YYY very minor leak -- we need the counters to stay alive @@ -620,11 +672,11 @@ if self.stack_check_slowpath == 0: pass # no stack check (e.g. not translated) else: - startaddr, length, _ = self.cpu.insert_stack_check() - self.mc.MOV(eax, esp) # MOV eax, current - self.mc.SUB(eax, heap(startaddr)) # SUB eax, [startaddr] - self.mc.CMP(eax, imm(length)) # CMP eax, length - self.mc.J_il8(rx86.Conditions['B'], 0) # JB .skip + endaddr, lengthaddr, _ = self.cpu.insert_stack_check() + self.mc.MOV(eax, heap(endaddr)) # MOV eax, [start] + self.mc.SUB(eax, esp) # SUB eax, current + self.mc.CMP(eax, heap(lengthaddr)) # CMP eax, [length] + self.mc.J_il8(rx86.Conditions['BE'], 0) # JBE .skip jb_location = self.mc.get_relative_pos() self.mc.CALL(imm(self.stack_check_slowpath))# CALL slowpath # patch the JB above # .skip: @@ -651,22 +703,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: @@ -837,7 +895,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -849,7 +907,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) @@ -1101,6 +1159,8 @@ self.mc.MOV_bi(FORCE_INDEX_OFS, force_index) return force_index else: + # the return value is ignored, apart from the fact that it + # is not negative. return 0 genop_int_neg = _unaryop("NEG") @@ -1984,6 +2044,102 @@ self.mc.CMP_bi(FORCE_INDEX_OFS, 0) self.implement_guard(guard_token, 'L') + def genop_guard_call_release_gil(self, op, guard_op, guard_token, + arglocs, result_loc): + # first, close the stack in the sense of the asmgcc GC root tracker + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + if gcrootmap: + self.call_release_gil(gcrootmap, arglocs) + # do the call + faildescr = guard_op.getdescr() + fail_index = self.cpu.get_fail_descr_number(faildescr) + self.mc.MOV_bi(FORCE_INDEX_OFS, fail_index) + self._genop_call(op, arglocs, result_loc, fail_index) + # then reopen the stack + if gcrootmap: + self.call_reacquire_gil(gcrootmap, result_loc) + # finally, the guard_not_forced + self.mc.CMP_bi(FORCE_INDEX_OFS, 0) + self.implement_guard(guard_token, 'L') + + def call_release_gil(self, gcrootmap, save_registers): + # First, we need to save away the registers listed in + # 'save_registers' that are not callee-save. XXX We assume that + # the XMM registers won't be modified. We store them in + # [ESP+4], [ESP+8], etc., leaving enough room in [ESP] for the + # single argument to closestack_addr below. + p = WORD + for reg in self._regalloc.rm.save_around_call_regs: + if reg in save_registers: + self.mc.MOV_sr(p, reg.value) + p += WORD + self._regalloc.reserve_param(p//WORD) + # + if gcrootmap.is_shadow_stack: + args = [] + else: + # note that regalloc.py used save_all_regs=True to save all + # registers, so we don't have to care about saving them (other + # than ebp) in the close_stack_struct. But if they are registers + # like %eax that would be destroyed by this call, *and* they are + # used by arglocs for the *next* call, then trouble; for now we + # will just push/pop them. + from pypy.rpython.memory.gctransform import asmgcroot + css = self._regalloc.close_stack_struct + if css == 0: + use_words = (2 + max(asmgcroot.INDEX_OF_EBP, + asmgcroot.FRAME_PTR) + 1) + pos = self._regalloc.fm.reserve_location_in_frame(use_words) + css = get_ebp_ofs(pos + use_words - 1) + self._regalloc.close_stack_struct = css + # The location where the future CALL will put its return address + # will be [ESP-WORD], so save that as the next frame's top address + self.mc.LEA_rs(eax.value, -WORD) # LEA EAX, [ESP-4] + frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) + self.mc.MOV_br(frame_ptr, eax.value) # MOV [css.frame], EAX + # Save ebp + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_br(index_of_ebp, ebp.value) # MOV [css.ebp], EBP + # Call the closestack() function (also releasing the GIL) + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rb(reg.value, css) + args = [reg] + # + self._emit_call(-1, imm(self.releasegil_addr), args) + # Finally, restore the registers saved above. + p = WORD + for reg in self._regalloc.rm.save_around_call_regs: + if reg in save_registers: + self.mc.MOV_rs(reg.value, p) + p += WORD + + def call_reacquire_gil(self, gcrootmap, save_loc): + # save the previous result (eax/xmm0) into the stack temporarily. + # XXX like with call_release_gil(), we assume that we don't need + # to save xmm0 in this case. + if isinstance(save_loc, RegLoc) and not save_loc.is_xmm: + self.mc.MOV_sr(WORD, save_loc.value) + self._regalloc.reserve_param(2) + # call the reopenstack() function (also reacquiring the GIL) + if gcrootmap.is_shadow_stack: + args = [] + else: + css = self._regalloc.close_stack_struct + assert css != 0 + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rb(reg.value, css) + args = [reg] + self._emit_call(-1, imm(self.reacqgil_addr), args) + # restore the result from the stack + if isinstance(save_loc, RegLoc) and not save_loc.is_xmm: + self.mc.MOV_rs(save_loc.value, WORD) + def genop_guard_call_assembler(self, op, guard_op, guard_token, arglocs, result_loc): faildescr = guard_op.getdescr() @@ -2073,13 +2229,26 @@ def genop_discard_cond_call_gc_wb(self, op, arglocs): # Write code equivalent to write_barrier() in the GC: it checks # a flag in the object at arglocs[0], and if set, it calls the - # function remember_young_pointer() from the GC. The two arguments - # to the call are in arglocs[:2]. The rest, arglocs[2:], contains + # function remember_young_pointer() from the GC. The arguments + # to the call are in arglocs[:N]. The rest, arglocs[N:], contains # registers that need to be saved and restored across the call. + # N is either 2 (regular write barrier) or 3 (array write barrier). descr = op.getdescr() if we_are_translated(): cls = self.cpu.gc_ll_descr.has_write_barrier_class() assert cls is not None and isinstance(descr, cls) + # + opnum = op.getopnum() + if opnum == rop.COND_CALL_GC_WB: + N = 2 + func = descr.get_write_barrier_fn(self.cpu) + elif opnum == rop.COND_CALL_GC_WB_ARRAY: + N = 3 + func = descr.get_write_barrier_from_array_fn(self.cpu) + assert func != 0 + else: + raise AssertionError(opnum) + # loc_base = arglocs[0] self.mc.TEST8(addr_add_const(loc_base, descr.jit_wb_if_flag_byteofs), imm(descr.jit_wb_if_flag_singlebyte)) @@ -2090,33 +2259,37 @@ if IS_X86_32: limit = -1 # push all arglocs on the stack elif IS_X86_64: - limit = 1 # push only arglocs[2:] on the stack + limit = N - 1 # push only arglocs[N:] on the stack for i in range(len(arglocs)-1, limit, -1): loc = arglocs[i] if isinstance(loc, RegLoc): self.mc.PUSH_r(loc.value) else: - assert not IS_X86_64 # there should only be regs in arglocs[2:] + assert not IS_X86_64 # there should only be regs in arglocs[N:] self.mc.PUSH_i32(loc.getint()) if IS_X86_64: # We clobber these registers to pass the arguments, but that's # okay, because consider_cond_call_gc_wb makes sure that any # caller-save registers with values in them are present in - # arglocs[2:] too, so they are saved on the stack above and + # arglocs[N:] too, so they are saved on the stack above and # restored below. - remap_frame_layout(self, arglocs[:2], [edi, esi], + if N == 2: + callargs = [edi, esi] + else: + callargs = [edi, esi, edx] + remap_frame_layout(self, arglocs[:N], callargs, X86_64_SCRATCH_REG) - + # # misaligned stack in the call, but it's ok because the write barrier # is not going to call anything more. Also, this assumes that the # write barrier does not touch the xmm registers. (Slightly delicate # assumption, given that the write barrier can end up calling the # platform's malloc() from AddressStack.append(). XXX may need to # be done properly) - self.mc.CALL(imm(descr.get_write_barrier_fn(self.cpu))) + self.mc.CALL(imm(func)) if IS_X86_32: - self.mc.ADD_ri(esp.value, 2*WORD) - for i in range(2, len(arglocs)): + self.mc.ADD_ri(esp.value, N*WORD) + for i in range(N, len(arglocs)): loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) @@ -2125,6 +2298,8 @@ assert 0 < offset <= 127 self.mc.overwrite(jz_location-1, chr(offset)) + genop_discard_cond_call_gc_wb_array = genop_discard_cond_call_gc_wb + def genop_force_token(self, op, arglocs, resloc): # RegAlloc.consider_force_token ensures this: assert isinstance(resloc, RegLoc) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -156,12 +156,14 @@ self.translate_support_code = translate_support_code # to be read/used by the assembler too self.jump_target_descr = None + self.close_stack_struct = 0 - def _prepare(self, inputargs, operations): + def _prepare(self, inputargs, operations, allgcrefs): self.fm = X86FrameManager() self.param_depth = 0 cpu = self.assembler.cpu - operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations) + operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations, + allgcrefs) # compute longevity of variables longevity = self._compute_vars_longevity(inputargs, operations) self.longevity = longevity @@ -172,15 +174,16 @@ assembler = self.assembler) return operations - def prepare_loop(self, inputargs, operations, looptoken): - operations = self._prepare(inputargs, operations) + def prepare_loop(self, inputargs, operations, looptoken, allgcrefs): + operations = self._prepare(inputargs, operations, allgcrefs) jump = operations[-1] loop_consts = self._compute_loop_consts(inputargs, jump, looptoken) self.loop_consts = loop_consts return self._process_inputargs(inputargs), operations - def prepare_bridge(self, prev_depths, inputargs, arglocs, operations): - operations = self._prepare(inputargs, operations) + def prepare_bridge(self, prev_depths, inputargs, arglocs, operations, + allgcrefs): + operations = self._prepare(inputargs, operations, allgcrefs) self.loop_consts = {} self._update_bindings(arglocs, inputargs) self.fm.frame_depth = prev_depths[0] @@ -268,6 +271,12 @@ return self.rm.force_allocate_reg(var, forbidden_vars, selected_reg, need_lower_byte) + def force_spill_var(self, var): + if var.type == FLOAT: + return self.xrm.force_spill_var(var) + else: + return self.rm.force_spill_var(var) + def load_xmm_aligned_16_bytes(self, var, forbidden_vars=[]): # Load 'var' in a register; but if it is a constant, we can return # a 16-bytes-aligned ConstFloatLoc. @@ -382,7 +391,9 @@ self.assembler.regalloc_perform_discard(op, arglocs) def can_merge_with_next_guard(self, op, i, operations): - if op.getopnum() == rop.CALL_MAY_FORCE or op.getopnum() == rop.CALL_ASSEMBLER: + if (op.getopnum() == rop.CALL_MAY_FORCE or + op.getopnum() == rop.CALL_ASSEMBLER or + op.getopnum() == rop.CALL_RELEASE_GIL): assert operations[i + 1].getopnum() == rop.GUARD_NOT_FORCED return True if not op.is_comparison(): @@ -418,6 +429,8 @@ if self.can_merge_with_next_guard(op, i, operations): oplist_with_guard[op.getopnum()](self, op, operations[i + 1]) i += 1 + elif not we_are_translated() and op.getopnum() == -124: + self._consider_force_spill(op) else: oplist[op.getopnum()](self, op) if op.result is not None: @@ -771,6 +784,19 @@ self.xrm.possibly_free_var(op.getarg(1)) def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None): + # we need to save registers on the stack: + # + # - at least the non-callee-saved registers + # + # - for shadowstack, we assume that any call can collect, and we + # save also the callee-saved registers that contain GC pointers, + # so that they can be found by follow_stack_frame_of_assembler() + # + # - for CALL_MAY_FORCE or CALL_ASSEMBLER, we have to save all regs + # anyway, in case we need to do cpu.force(). The issue is that + # grab_frame_values() would not be able to locate values in + # callee-saved registers. + # save_all_regs = guard_not_forced_op is not None self.xrm.before_call(force_store, save_all_regs=save_all_regs) if not save_all_regs: @@ -837,6 +863,8 @@ assert guard_op is not None self._consider_call(op, guard_op) + consider_call_release_gil = consider_call_may_force + def consider_call_assembler(self, op, guard_op): descr = op.getdescr() assert isinstance(descr, LoopToken) @@ -856,12 +884,12 @@ def consider_cond_call_gc_wb(self, op): assert op.result is None args = op.getarglist() - loc_newvalue = self.rm.make_sure_var_in_reg(op.getarg(1), args) - # ^^^ we force loc_newvalue in a reg (unless it's a Const), - # because it will be needed anyway by the following setfield_gc. - # It avoids loading it twice from the memory. - loc_base = self.rm.make_sure_var_in_reg(op.getarg(0), args) - arglocs = [loc_base, loc_newvalue] + N = len(args) + # we force all arguments in a reg (unless they are Consts), + # because it will be needed anyway by the following setfield_gc + # or setarrayitem_gc. It avoids loading it twice from the memory. + arglocs = [self.rm.make_sure_var_in_reg(op.getarg(i), args) + for i in range(N)] # add eax, ecx and edx as extra "arguments" to ensure they are # saved and restored. Fish in self.rm to know which of these # registers really need to be saved (a bit of a hack). Moreover, @@ -875,6 +903,8 @@ self.PerformDiscard(op, arglocs) self.rm.possibly_free_vars_for_op(op) + consider_cond_call_gc_wb_array = consider_cond_call_gc_wb + def fastpath_malloc_fixedsize(self, op, descr): assert isinstance(descr, BaseSizeDescr) self._do_fastpath_malloc(op, descr.size, descr.tid) @@ -1293,6 +1323,10 @@ def consider_jit_debug(self, op): pass + def _consider_force_spill(self, op): + # This operation is used only for testing + self.force_spill_var(op.getarg(0)) + def get_mark_gc_roots(self, gcrootmap, use_copy_area=False): shape = gcrootmap.get_basic_shape(IS_X86_64) for v, val in self.fm.frame_bindings.items(): @@ -1346,7 +1380,9 @@ name = name[len('consider_'):] num = getattr(rop, name.upper()) if (is_comparison_or_ovf_op(num) - or num == rop.CALL_MAY_FORCE or num == rop.CALL_ASSEMBLER): + or num == rop.CALL_MAY_FORCE + or num == rop.CALL_ASSEMBLER + or num == rop.CALL_RELEASE_GIL): oplist_with_guard[num] = value oplist[num] = add_none_argument(value) else: diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py --- a/pypy/jit/backend/x86/runner.py +++ b/pypy/jit/backend/x86/runner.py @@ -22,6 +22,7 @@ BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) dont_keepalive_stuff = False # for tests + with_threads = False def __init__(self, rtyper, stats, opts=None, translate_support_code=False, gcdescr=None): @@ -38,6 +39,7 @@ if not oprofile.OPROFILE_AVAILABLE: log.WARNING('oprofile support was explicitly enabled, but oprofile headers seem not to be available') profile_agent = oprofile.OProfileAgent() + self.with_threads = config.translation.thread self.profile_agent = profile_agent @@ -77,9 +79,9 @@ lines = machine_code_dump(data, addr, self.backend_name, label_list) print ''.join(lines) - def compile_loop(self, inputargs, operations, looptoken, log=True): - return self.assembler.assemble_loop(inputargs, operations, looptoken, - log=log) + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): + return self.assembler.assemble_loop(name, inputargs, operations, + looptoken, log=log) def compile_bridge(self, faildescr, inputargs, operations, original_loop_token, log=True): @@ -122,8 +124,8 @@ addr = executable_token._x86_bootstrap_code #llop.debug_print(lltype.Void, ">>>> Entering", addr) func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr) + fail_index = self._execute_call(func) #llop.debug_print(lltype.Void, "<<<< Back") - fail_index = self._execute_call(func) return self.get_fail_descr_from_number(fail_index) def _execute_call(self, func): @@ -140,10 +142,11 @@ LLInterpreter.current_interpreter = prev_interpreter return res - @staticmethod def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return CPU386.cast_adr_to_int(adr) + cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)' + cast_ptr_to_int = staticmethod(cast_ptr_to_int) all_null_registers = lltype.malloc(rffi.LONGP.TO, 24, flavor='raw', zero=True, diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -467,13 +469,13 @@ # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) @@ -530,6 +532,7 @@ POP_b = insn(rex_nw, '\x8F', orbyte(0<<3), stack_bp(1)) LEA_rb = insn(rex_w, '\x8D', register(1,8), stack_bp(2)) + LEA_rs = insn(rex_w, '\x8D', register(1,8), stack_sp(2)) LEA32_rb = insn(rex_w, '\x8D', register(1,8),stack_bp(2,force_32bits=True)) LEA_ra = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_scaled_reg_plus_const(2)) LEA_rm = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_const(2)) diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_gc_integration.py b/pypy/jit/backend/x86/test/test_gc_integration.py --- a/pypy/jit/backend/x86/test/test_gc_integration.py +++ b/pypy/jit/backend/x86/test/test_gc_integration.py @@ -16,7 +16,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.annlowlevel import llhelper from pypy.rpython.lltypesystem import rclass, rstr -from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList, GcPtrFieldDescr +from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcPtrFieldDescr from pypy.jit.backend.x86.test.test_regalloc import MockAssembler from pypy.jit.backend.x86.test.test_regalloc import BaseTestRegalloc @@ -51,11 +51,9 @@ gcrootmap = MockGcRootMap() def initialize(self): - self.gcrefs = GcRefList() - self.gcrefs.initialize() - self.single_gcref_descr = GcPtrFieldDescr('', 0) + pass - replace_constptrs_with_getfield_raw = GcLLDescr_framework.replace_constptrs_with_getfield_raw.im_func + record_constptrs = GcLLDescr_framework.record_constptrs.im_func rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func class TestRegallocDirectGcIntegration(object): diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] @@ -330,6 +348,7 @@ assert result != expected def test_compile_bridge_check_profile_info(self): + py.test.skip("does not work, reinvestigate") class FakeProfileAgent(object): def __init__(self): self.functions = [] @@ -362,7 +381,7 @@ operations[3].setfailargs([i1]) self.cpu.compile_loop(inputargs, operations, looptoken) name, loopaddress, loopsize = agent.functions[0] - assert name == "Loop # 17: hello" + assert name == "Loop # 17: hello (loop counter 0)" assert loopaddress <= looptoken._x86_loop_code assert loopsize >= 40 # randomish number @@ -378,7 +397,7 @@ self.cpu.compile_bridge(faildescr1, [i1b], bridge, looptoken) name, address, size = agent.functions[1] - assert name == "Bridge # 0: bye" + assert name == "Bridge # 0: bye (loop counter 1)" # Would be exactly ==, but there are some guard failure recovery # stubs in-between assert address >= loopaddress + loopsize diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,6 +185,13 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -1,8 +1,7 @@ """ -This is a test that translates a complete JIT to C and runs it. It is -not testing much, expect that it basically works. What it *is* testing, -however, is the correct handling of GC, i.e. if objects are freed as -soon as possible (at least in a simple case). +This is a test that translates a complete JIT together with a GC and runs it. +It is testing that the GC-dependent aspects basically work, mostly the mallocs +and the various cases of write barrier. """ import weakref @@ -10,16 +9,11 @@ from pypy.annotation import policy as annpolicy from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe -from pypy.jit.backend.x86.runner import CPU386 -from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir -from pypy.jit.backend.x86.arch import IS_X86_64 from pypy.config.translationoption import DEFL_GC -import py.test class X(object): def __init__(self, x=0): @@ -86,7 +80,7 @@ # return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2} -def compile(f, gc, **kwds): +def compile(f, gc, enable_opts='', **kwds): from pypy.annotation.listdef import s_list_of_strings from pypy.translator.translator import TranslationContext from pypy.jit.metainterp.warmspot import apply_jit @@ -110,14 +104,14 @@ old_value[obj, attr] = getattr(obj, attr) setattr(obj, attr, value) # - apply_jit(t, enable_opts='') + apply_jit(t, enable_opts=enable_opts) # finally: for (obj, attr), oldvalue in old_value.items(): setattr(obj, attr, oldvalue) cbuilder = genc.CStandaloneBuilder(t, f, t.config) - cbuilder.generate_source() + cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) cbuilder.compile() return cbuilder @@ -154,8 +148,10 @@ # ______________________________________________________________________ -class CompileFrameworkTests(object): - # Test suite using (so far) the minimark GC. + +class BaseFrameworkTests(object): + compile_kwds = {} + def setup_class(cls): funcs = [] name_to_func = {} @@ -205,7 +201,8 @@ try: GcLLDescr_framework.DEBUG = True cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC, - gcrootfinder=cls.gcrootfinder, jit=True) + gcrootfinder=cls.gcrootfinder, jit=True, + **cls.compile_kwds) finally: GcLLDescr_framework.DEBUG = OLD_DEBUG @@ -224,32 +221,36 @@ def run_orig(self, name, n, x): self.main_allfuncs(name, n, x) - def define_libffi_workaround(cls): - # XXX: this is a workaround for a bug in database.py. It seems that - # the problem is triggered by optimizeopt/fficall.py, and in - # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in - # these tests, that line is the only place where libffi.Func is - # referenced. - # - # The problem occurs because the gctransformer tries to annotate a - # low-level helper to call the __del__ of libffi.Func when it's too - # late. - # - # This workaround works by forcing the annotator (and all the rest of - # the toolchain) to see libffi.Func in a "proper" context, not just as - # the target of cast_base_ptr_to_instance. Note that the function - # below is *never* called by any actual test, it's just annotated. - # - from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain - libc_name = get_libc_name() - def f(n, x, *args): - libc = CDLL(libc_name) - ptr = libc.getpointer('labs', [types.slong], types.slong) - chain = ArgChain() - chain.arg(n) - n = ptr.call(chain, lltype.Signed) - return (n, x) + args - return None, f, None + +class CompileFrameworkTests(BaseFrameworkTests): + # Test suite using (so far) the minimark GC. + +## def define_libffi_workaround(cls): +## # XXX: this is a workaround for a bug in database.py. It seems that +## # the problem is triggered by optimizeopt/fficall.py, and in +## # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in +## # these tests, that line is the only place where libffi.Func is +## # referenced. +## # +## # The problem occurs because the gctransformer tries to annotate a +## # low-level helper to call the __del__ of libffi.Func when it's too +## # late. +## # +## # This workaround works by forcing the annotator (and all the rest of +## # the toolchain) to see libffi.Func in a "proper" context, not just as +## # the target of cast_base_ptr_to_instance. Note that the function +## # below is *never* called by any actual test, it's just annotated. +## # +## from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain +## libc_name = get_libc_name() +## def f(n, x, *args): +## libc = CDLL(libc_name) +## ptr = libc.getpointer('labs', [types.slong], types.slong) +## chain = ArgChain() +## chain.arg(n) +## n = ptr.call(chain, lltype.Signed) +## return (n, x) + args +## return None, f, None def define_compile_framework_1(cls): # a moving GC. Supports malloc_varsize_nonmovable. Simple test, works @@ -456,6 +457,73 @@ def test_compile_framework_7(self): self.run('compile_framework_7') + def define_compile_framework_8(cls): + # Array of pointers, of unknown length (test write_barrier_from_array) + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + l = [None] * (16 + (n & 7)) + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[8] = X(n+70) + l[9] = X(n+80) + l[10] = X(n+90) + l[11] = X(n+100) + l[12] = X(n+110) + l[13] = X(n+120) + l[14] = X(n+130) + l[15] = X(n+140) + if n < 1800: + check(len(l) == 16 + (n & 7)) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[8].x == n+70) + check(l[9].x == n+80) + check(l[10].x == n+90) + check(l[11].x == n+100) + check(l[12].x == n+110) + check(l[13].x == n+120) + check(l[14].x == n+130) + check(l[15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 16) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[8].x == 72) + check(l[9].x == 82) + check(l[10].x == 92) + check(l[11].x == 102) + check(l[12].x == 112) + check(l[13].x == 122) + check(l[14].x == 132) + check(l[15].x == 142) + return before, f, after + + def test_compile_framework_8(self): + self.run('compile_framework_8') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) @@ -493,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): @@ -525,8 +593,8 @@ glob = A() def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): a = A() - glob.v = virtual_ref(a) - virtual_ref_finish(a) + glob.v = vref = virtual_ref(a) + virtual_ref_finish(vref, a) n -= 1 return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s return None, f, None diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_releasegil.py copy from pypy/jit/backend/x86/test/test_zrpy_gc.py copy to pypy/jit/backend/x86/test/test_zrpy_releasegil.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_releasegil.py @@ -1,618 +1,110 @@ -""" -This is a test that translates a complete JIT to C and runs it. It is -not testing much, expect that it basically works. What it *is* testing, -however, is the correct handling of GC, i.e. if objects are freed as -soon as possible (at least in a simple case). -""" +from pypy.rpython.lltypesystem import lltype, llmemory, rffi +from pypy.rlib.jit import dont_look_inside +from pypy.jit.metainterp.optimizeopt import ALL_OPTS_NAMES -import weakref -import py, os -from pypy.annotation import policy as annpolicy -from pypy.rlib import rgc -from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe -from pypy.jit.backend.x86.runner import CPU386 -from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc -from pypy.jit.backend.llsupport.gc import GcLLDescr_framework -from pypy.tool.udir import udir -from pypy.jit.backend.x86.arch import IS_X86_64 -from pypy.config.translationoption import DEFL_GC -import py.test +from pypy.rlib.libffi import CDLL, types, ArgChain, clibffi +from pypy.rpython.lltypesystem.ll2ctypes import libc_name +from pypy.rpython.annlowlevel import llhelper -class X(object): - def __init__(self, x=0): - self.x = x +from pypy.jit.backend.x86.test.test_zrpy_gc import BaseFrameworkTests +from pypy.jit.backend.x86.test.test_zrpy_gc import check - next = None -class CheckError(Exception): - pass +class ReleaseGILTests(BaseFrameworkTests): + compile_kwds = dict(enable_opts=ALL_OPTS_NAMES, thread=True) -def check(flag): - if not flag: - raise CheckError - -def get_g(main): - main._dont_inline_ = True - def g(name, n): - x = X() - x.foo = 2 - main(n, x) - x.foo = 5 - return weakref.ref(x) - g._dont_inline_ = True - return g - - -def get_entry(g): - - def entrypoint(args): - name = '' - n = 2000 - argc = len(args) - if argc > 1: - name = args[1] - if argc > 2: - n = int(args[2]) - r_list = [] - for i in range(20): - r = g(name, n) - r_list.append(r) - rgc.collect() - rgc.collect(); rgc.collect() - freed = 0 - for r in r_list: - if r() is None: - freed += 1 - print freed - return 0 - - return entrypoint - - -def get_functions_to_patch(): - from pypy.jit.backend.llsupport import gc - # - can_inline_malloc1 = gc.GcLLDescr_framework.can_inline_malloc - def can_inline_malloc2(*args): - try: - if os.environ['PYPY_NO_INLINE_MALLOC']: - return False - except KeyError: + def define_simple(self): + class Glob: pass - return can_inline_malloc1(*args) - # - return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2} - -def compile(f, gc, **kwds): - from pypy.annotation.listdef import s_list_of_strings - from pypy.translator.translator import TranslationContext - from pypy.jit.metainterp.warmspot import apply_jit - from pypy.translator.c import genc - # - t = TranslationContext() - t.config.translation.gc = gc - if gc != 'boehm': - t.config.translation.gcremovetypeptr = True - for name, value in kwds.items(): - setattr(t.config.translation, name, value) - ann = t.buildannotator(policy=annpolicy.StrictAnnotatorPolicy()) - ann.build_types(f, [s_list_of_strings], main_entry_point=True) - t.buildrtyper().specialize() - - if kwds['jit']: - patch = get_functions_to_patch() - old_value = {} - try: - for (obj, attr), value in patch.items(): - old_value[obj, attr] = getattr(obj, attr) - setattr(obj, attr, value) - # - apply_jit(t, enable_opts='') - # - finally: - for (obj, attr), oldvalue in old_value.items(): - setattr(obj, attr, oldvalue) - - cbuilder = genc.CStandaloneBuilder(t, f, t.config) - cbuilder.generate_source() - cbuilder.compile() - return cbuilder - -def run(cbuilder, args=''): - # - pypylog = udir.join('test_zrpy_gc.log') - data = cbuilder.cmdexec(args, env={'PYPYLOG': ':%s' % pypylog}) - return data.strip() - -def compile_and_run(f, gc, **kwds): - cbuilder = compile(f, gc, **kwds) - return run(cbuilder) - - - -def test_compile_boehm(): - myjitdriver = JitDriver(greens = [], reds = ['n', 'x']) - @dont_look_inside - def see(lst, n): - assert len(lst) == 3 - assert lst[0] == n+10 - assert lst[1] == n+20 - assert lst[2] == n+30 - def main(n, x): - while n > 0: - myjitdriver.can_enter_jit(n=n, x=x) - myjitdriver.jit_merge_point(n=n, x=x) - y = X() - y.foo = x.foo - n -= y.foo - see([n+10, n+20, n+30], n) - res = compile_and_run(get_entry(get_g(main)), "boehm", jit=True) - assert int(res) >= 16 - -# ______________________________________________________________________ - -class CompileFrameworkTests(object): - # Test suite using (so far) the minimark GC. - def setup_class(cls): - funcs = [] - name_to_func = {} - for fullname in dir(cls): - if not fullname.startswith('define'): - continue - definefunc = getattr(cls, fullname) - _, name = fullname.split('_', 1) - beforefunc, loopfunc, afterfunc = definefunc.im_func(cls) - if beforefunc is None: - def beforefunc(n, x): - return n, x, None, None, None, None, None, None, None, None, None, '' - if afterfunc is None: - def afterfunc(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - pass - beforefunc.func_name = 'before_'+name - loopfunc.func_name = 'loop_'+name - afterfunc.func_name = 'after_'+name - funcs.append((beforefunc, loopfunc, afterfunc)) - assert name not in name_to_func - name_to_func[name] = len(name_to_func) - print name_to_func - def allfuncs(name, n): - x = X() - x.foo = 2 - main_allfuncs(name, n, x) - x.foo = 5 - return weakref.ref(x) - def main_allfuncs(name, n, x): - num = name_to_func[name] - n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s = funcs[num][0](n, x) - while n > 0: - myjitdriver.can_enter_jit(num=num, n=n, x=x, x0=x0, x1=x1, - x2=x2, x3=x3, x4=x4, x5=x5, x6=x6, x7=x7, l=l, s=s) - myjitdriver.jit_merge_point(num=num, n=n, x=x, x0=x0, x1=x1, - x2=x2, x3=x3, x4=x4, x5=x5, x6=x6, x7=x7, l=l, s=s) - - n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s = funcs[num][1]( - n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s) - funcs[num][2](n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s) - myjitdriver = JitDriver(greens = ['num'], - reds = ['n', 'x', 'x0', 'x1', 'x2', 'x3', 'x4', - 'x5', 'x6', 'x7', 'l', 's']) - cls.main_allfuncs = staticmethod(main_allfuncs) - cls.name_to_func = name_to_func - OLD_DEBUG = GcLLDescr_framework.DEBUG - try: - GcLLDescr_framework.DEBUG = True - cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC, - gcrootfinder=cls.gcrootfinder, jit=True) - finally: - GcLLDescr_framework.DEBUG = OLD_DEBUG - - def _run(self, name, n, env): - res = self.cbuilder.cmdexec("%s %d" %(name, n), env=env) - assert int(res) == 20 - - def run(self, name, n=2000): - pypylog = udir.join('TestCompileFramework.log') - env = {'PYPYLOG': ':%s' % pypylog, - 'PYPY_NO_INLINE_MALLOC': '1'} - self._run(name, n, env) - env['PYPY_NO_INLINE_MALLOC'] = '' - self._run(name, n, env) - - def run_orig(self, name, n, x): - self.main_allfuncs(name, n, x) - - def define_libffi_workaround(cls): - # XXX: this is a workaround for a bug in database.py. It seems that - # the problem is triggered by optimizeopt/fficall.py, and in - # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in - # these tests, that line is the only place where libffi.Func is - # referenced. + glob = Glob() # - # The problem occurs because the gctransformer tries to annotate a - # low-level helper to call the __del__ of libffi.Func when it's too - # late. - # - # This workaround works by forcing the annotator (and all the rest of - # the toolchain) to see libffi.Func in a "proper" context, not just as - # the target of cast_base_ptr_to_instance. Note that the function - # below is *never* called by any actual test, it's just annotated. - # - from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain - libc_name = get_libc_name() - def f(n, x, *args): - libc = CDLL(libc_name) - ptr = libc.getpointer('labs', [types.slong], types.slong) - chain = ArgChain() - chain.arg(n) - n = ptr.call(chain, lltype.Signed) - return (n, x) + args - return None, f, None - - def define_compile_framework_1(cls): - # a moving GC. Supports malloc_varsize_nonmovable. Simple test, works - # without write_barriers and root stack enumeration. - def f(n, x, *args): - y = X() - y.foo = x.foo - n -= y.foo - return (n, x) + args - return None, f, None - - def test_compile_framework_1(self): - self.run('compile_framework_1') - - def define_compile_framework_2(cls): - # More complex test, requires root stack enumeration but - # not write_barriers. - def f(n, x, *args): - prev = x - for j in range(101): # f() runs 20'000 times, thus allocates - y = X() # a total of 2'020'000 objects - y.foo = prev.foo - prev = y - n -= prev.foo - return (n, x) + args - return None, f, None - - def test_compile_framework_2(self): - self.run('compile_framework_2') - - def define_compile_framework_3(cls): - # Third version of the test. Really requires write_barriers. - def f(n, x, *args): - x.next = None - for j in range(101): # f() runs 20'000 times, thus allocates - y = X() # a total of 2'020'000 objects - y.foo = j+1 - y.next = x.next - x.next = y - check(x.next.foo == 101) - total = 0 - y = x - for j in range(101): - y = y.next - total += y.foo - check(not y.next) - check(total == 101*102/2) - n -= x.foo - return (n, x) + args - return None, f, None - - - - def test_compile_framework_3(self): - x_test = X() - x_test.foo = 5 - self.run_orig('compile_framework_3', 6, x_test) # check that it does not raise CheckError - self.run('compile_framework_3') - - def define_compile_framework_3_extra(cls): - # Extra version of the test, with tons of live vars around the residual - # call that all contain a GC pointer. - @dont_look_inside - def residual(n=26): - x = X() - x.next = X() - x.next.foo = n - return x + def f42(n): + c_strchr = glob.c_strchr + raw = rffi.str2charp("foobar" + chr((n & 63) + 32)) + argchain = ArgChain() + argchain = argchain.arg(rffi.cast(lltype.Signed, raw)) + argchain = argchain.arg(rffi.cast(rffi.INT, ord('b'))) + res = c_strchr.call(argchain, rffi.CCHARP) + check(rffi.charp2str(res) == "bar" + chr((n & 63) + 32)) + rffi.free_charp(raw) # def before(n, x): - residual(5) - x0 = residual() - x1 = residual() - x2 = residual() - x3 = residual() - x4 = residual() - x5 = residual() - x6 = residual() - x7 = residual() - n *= 19 - return n, None, x0, x1, x2, x3, x4, x5, x6, x7, None, None - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - x8 = residual() - x9 = residual() - check(x0.next.foo == 26) - check(x1.next.foo == 26) - check(x2.next.foo == 26) - check(x3.next.foo == 26) - check(x4.next.foo == 26) - check(x5.next.foo == 26) - check(x6.next.foo == 26) - check(x7.next.foo == 26) - check(x8.next.foo == 26) - check(x9.next.foo == 26) - x0, x1, x2, x3, x4, x5, x6, x7 = x7, x4, x6, x5, x3, x2, x9, x8 + libc = CDLL(libc_name) + c_strchr = libc.getpointer('strchr', [types.pointer, types.sint], + types.pointer) + glob.c_strchr = c_strchr + return (n, None, None, None, None, None, + None, None, None, None, None, None) + # + def f(n, x, *args): + f42(n) n -= 1 - return n, None, x0, x1, x2, x3, x4, x5, x6, x7, None, None - return before, f, None - - def test_compile_framework_3_extra(self): - self.run_orig('compile_framework_3_extra', 6, None) # check that it does not raise CheckError - self.run('compile_framework_3_extra') - - def define_compile_framework_4(cls): - # Fourth version of the test, with __del__. - from pypy.rlib.debug import debug_print - class Counter: - cnt = 0 - counter = Counter() - class Z: - def __del__(self): - counter.cnt -= 1 - def before(n, x): - debug_print('counter.cnt =', counter.cnt) - check(counter.cnt < 5) - counter.cnt = n // x.foo - return n, x, None, None, None, None, None, None, None, None, None, None - def f(n, x, *args): - Z() - n -= x.foo return (n, x) + args return before, f, None - def test_compile_framework_4(self): - self.run('compile_framework_4') + def test_simple(self): + self.run('simple') - def define_compile_framework_5(cls): - # Test string manipulation. - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - n -= x.foo - s += str(n) - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - check(len(s) == 1*5 + 2*45 + 3*450 + 4*500) - return None, f, after - - def test_compile_framework_5(self): - self.run('compile_framework_5') - - def define_compile_framework_7(cls): - # Array of pointers (test the write barrier for setarrayitem_gc) + def define_close_stack(self): + # + class Glob(object): + pass + glob = Glob() + class X(object): + pass + # + def callback(p1, p2): + for i in range(100): + glob.lst.append(X()) + return rffi.cast(rffi.INT, 1) + CALLBACK = lltype.Ptr(lltype.FuncType([lltype.Signed, + lltype.Signed], rffi.INT)) + # + @dont_look_inside + def alloc1(): + return llmemory.raw_malloc(16) + @dont_look_inside + def free1(p): + llmemory.raw_free(p) + # + def f42(): + length = len(glob.lst) + c_qsort = glob.c_qsort + raw = alloc1() + fn = llhelper(CALLBACK, rffi._make_wrapper_for(CALLBACK, callback)) + argchain = ArgChain() + argchain = argchain.arg(rffi.cast(lltype.Signed, raw)) + argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 2)) + argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 8)) + argchain = argchain.arg(rffi.cast(lltype.Signed, fn)) + c_qsort.call(argchain, lltype.Void) + free1(raw) + check(len(glob.lst) > length) + del glob.lst[:] + # def before(n, x): - return n, x, None, None, None, None, None, None, None, None, [X(123)], None - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - if n < 1900: - check(l[0].x == 123) - l = [None] * 16 - l[0] = X(123) - l[1] = X(n) - l[2] = X(n+10) - l[3] = X(n+20) - l[4] = X(n+30) - l[5] = X(n+40) - l[6] = X(n+50) - l[7] = X(n+60) - l[8] = X(n+70) - l[9] = X(n+80) - l[10] = X(n+90) - l[11] = X(n+100) - l[12] = X(n+110) - l[13] = X(n+120) - l[14] = X(n+130) - l[15] = X(n+140) - if n < 1800: - check(len(l) == 16) - check(l[0].x == 123) - check(l[1].x == n) - check(l[2].x == n+10) - check(l[3].x == n+20) - check(l[4].x == n+30) - check(l[5].x == n+40) - check(l[6].x == n+50) - check(l[7].x == n+60) - check(l[8].x == n+70) - check(l[9].x == n+80) - check(l[10].x == n+90) - check(l[11].x == n+100) - check(l[12].x == n+110) - check(l[13].x == n+120) - check(l[14].x == n+130) - check(l[15].x == n+140) - n -= x.foo - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - check(len(l) == 16) - check(l[0].x == 123) - check(l[1].x == 2) - check(l[2].x == 12) - check(l[3].x == 22) - check(l[4].x == 32) - check(l[5].x == 42) - check(l[6].x == 52) - check(l[7].x == 62) - check(l[8].x == 72) - check(l[9].x == 82) - check(l[10].x == 92) - check(l[11].x == 102) - check(l[12].x == 112) - check(l[13].x == 122) - check(l[14].x == 132) - check(l[15].x == 142) - return before, f, after - - def test_compile_framework_7(self): - self.run('compile_framework_7') - - def define_compile_framework_external_exception_handling(cls): - def before(n, x): - x = X(0) - return n, x, None, None, None, None, None, None, None, None, None, None - - @dont_look_inside - def g(x): - if x > 200: - return 2 - raise ValueError - @dont_look_inside - def h(x): - if x > 150: - raise ValueError - return 2 - - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - try: - x.x += g(n) - except ValueError: - x.x += 1 - try: - x.x += h(n) - except ValueError: - x.x -= 1 + libc = CDLL(libc_name) + types_size_t = clibffi.cast_type_to_ffitype(rffi.SIZE_T) + c_qsort = libc.getpointer('qsort', [types.pointer, types_size_t, + types_size_t, types.pointer], + types.void) + glob.c_qsort = c_qsort + glob.lst = [] + return (n, None, None, None, None, None, + None, None, None, None, None, None) + # + def f(n, x, *args): + f42() n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - - def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - check(x.x == 1800 * 2 + 1850 * 2 + 200 - 150) - + return (n, x) + args return before, f, None - def test_compile_framework_external_exception_handling(self): - self.run('compile_framework_external_exception_handling') + def test_close_stack(self): + self.run('close_stack') - def define_compile_framework_bug1(self): - @purefunction - def nonmoving(): - x = X(1) - for i in range(7): - rgc.collect() - return x - @dont_look_inside - def do_more_stuff(): - x = X(5) - for i in range(7): - rgc.collect() - return x - - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - x0 = do_more_stuff() - check(nonmoving().x == 1) - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - - return None, f, None - - def test_compile_framework_bug1(self): - self.run('compile_framework_bug1', 200) - - def define_compile_framework_vref(self): - from pypy.rlib.jit import virtual_ref, virtual_ref_finish - class A: - pass - glob = A() - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - a = A() - glob.v = virtual_ref(a) - virtual_ref_finish(a) - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - return None, f, None - - def test_compile_framework_vref(self): - self.run('compile_framework_vref', 200) - - def define_compile_framework_float(self): - # test for a bug: the fastpath_malloc does not save and restore - # xmm registers around the actual call to the slow path - class A: - x0 = x1 = x2 = x3 = x4 = x5 = x6 = x7 = 0 - @dont_look_inside - def escape1(a): - a.x0 += 0 - a.x1 += 6 - a.x2 += 12 - a.x3 += 18 - a.x4 += 24 - a.x5 += 30 - a.x6 += 36 - a.x7 += 42 - @dont_look_inside - def escape2(n, f0, f1, f2, f3, f4, f5, f6, f7): - check(f0 == n + 0.0) - check(f1 == n + 0.125) - check(f2 == n + 0.25) - check(f3 == n + 0.375) - check(f4 == n + 0.5) - check(f5 == n + 0.625) - check(f6 == n + 0.75) - check(f7 == n + 0.875) - @unroll_safe - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - i = 0 - while i < 42: - m = n + i - f0 = m + 0.0 - f1 = m + 0.125 - f2 = m + 0.25 - f3 = m + 0.375 - f4 = m + 0.5 - f5 = m + 0.625 - f6 = m + 0.75 - f7 = m + 0.875 - a1 = A() - # at this point, all or most f's are still in xmm registers - escape1(a1) - escape2(m, f0, f1, f2, f3, f4, f5, f6, f7) - i += 1 - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - return None, f, None - - def test_compile_framework_float(self): - self.run('compile_framework_float') - - def define_compile_framework_minimal_size_in_nursery(self): - S = lltype.GcStruct('S') # no fields! - T = lltype.GcStruct('T', ('i', lltype.Signed)) - @unroll_safe - def f42(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - lst1 = [] - lst2 = [] - i = 0 - while i < 42: - s1 = lltype.malloc(S) - t1 = lltype.malloc(T) - t1.i = 10000 + i + n - lst1.append(s1) - lst2.append(t1) - i += 1 - i = 0 - while i < 42: - check(lst2[i].i == 10000 + i + n) - i += 1 - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - return None, f42, None - - def test_compile_framework_minimal_size_in_nursery(self): - self.run('compile_framework_minimal_size_in_nursery') - - -class TestShadowStack(CompileFrameworkTests): +class TestShadowStack(ReleaseGILTests): gcrootfinder = "shadowstack" -class TestAsmGcc(CompileFrameworkTests): +class TestAsmGcc(ReleaseGILTests): gcrootfinder = "asmgcc" diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/assembler.py b/pypy/jit/codewriter/assembler.py --- a/pypy/jit/codewriter/assembler.py +++ b/pypy/jit/codewriter/assembler.py @@ -76,7 +76,8 @@ TYPE = llmemory.Address if TYPE == llmemory.Address: value = heaptracker.adr2int(value) - elif not isinstance(value, ComputedIntSymbolic): + if not isinstance(value, (llmemory.AddressAsInt, + ComputedIntSymbolic)): value = lltype.cast_primitive(lltype.Signed, value) if allow_short and -128 <= value <= 127: # emit the constant as a small integer diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -237,7 +237,9 @@ self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, oopspecindex, can_invalidate) # - if pure or loopinvariant: + if oopspecindex != EffectInfo.OS_NONE: + assert effectinfo is not None + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -75,12 +75,13 @@ # OS_MATH_SQRT = 100 - def __new__(cls, readonly_descrs_fields, + def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, can_invalidate=False): key = (frozenset(readonly_descrs_fields), + frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, @@ -89,8 +90,9 @@ return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields + result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: @@ -108,6 +110,9 @@ def check_forces_virtual_or_virtualizable(self): return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE + def has_random_effects(self): + return self.oopspecindex == self.OS_LIBFFI_CALL + def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, @@ -116,7 +121,7 @@ if effects is top_set: return None readonly_descrs_fields = [] - # readonly_descrs_arrays = [] --- not enabled for now + readonly_descrs_arrays = [] write_descrs_fields = [] write_descrs_arrays = [] @@ -142,10 +147,13 @@ elif tup[0] == "array": add_array(write_descrs_arrays, tup) elif tup[0] == "readarray": - pass + tupw = ("array",) + tup[1:] + if tupw not in effects: + add_array(readonly_descrs_arrays, tup) else: assert 0 return EffectInfo(readonly_descrs_fields, + readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect, diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -209,7 +209,6 @@ def rewrite_op_cast_int_to_unichar(self, op): pass def rewrite_op_cast_int_to_uint(self, op): pass def rewrite_op_cast_uint_to_int(self, op): pass - def rewrite_op_resume_point(self, op): pass def _rewrite_symmetric(self, op): """Rewrite 'c1+v2' into 'v2+c1' in an attempt to avoid generating @@ -769,10 +768,10 @@ from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof from pypy.rlib.rarithmetic import intmask assert not self._is_gc(op.args[0]) - size1, unsigned1 = size_and_sign(op.args[0].concretetype) size2, unsigned2 = size_and_sign(op.result.concretetype) if size2 >= sizeof(lltype.Signed): return # the target type is LONG or ULONG + size1, unsigned1 = size_and_sign(op.args[0].concretetype) # def bounds(size, unsigned): if unsigned: @@ -848,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1329,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1381,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' @@ -44,10 +44,6 @@ return True if mod.startswith('pypy.translator.'): # XXX wtf? return True - # string builder interface - if mod == 'pypy.rpython.lltypesystem.rbuilder': - return True - return False def look_inside_graph(self, graph): @@ -63,12 +59,27 @@ contains_loop = contains_loop and not getattr( func, '_jit_unroll_safe_', False) - res = see_function and not contains_unsupported_variable_type(graph, - self.supports_floats, - self.supports_longlong) + unsupported = contains_unsupported_variable_type(graph, + self.supports_floats, + self.supports_longlong) + res = see_function and not unsupported if res and contains_loop: self.unsafe_loopy_graphs.add(graph) - return res and not contains_loop + res = res and not contains_loop + if (see_function and not res and + getattr(graph, "access_directly", False)): + # This happens when we have a function which has an argument with + # the access_directly flag, and the annotator has determined we will + # see the function. (See + # pypy/annotation/specialize.py:default_specialize) However, + # look_inside_graph just decided that we will not see it. (It has a + # loop or unsupported variables.) If we return False, the call will + # be turned into a residual call, but the graph is access_directly! + # If such a function is called and accesses a virtualizable, the JIT + # will not notice, and the virtualizable will fall out of sync. So, + # we fail loudly now. + raise ValueError("access_directly on a function which we don't see %s" % graph) + return res def contains_unsupported_variable_type(graph, supports_floats, supports_longlong): diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -34,6 +34,15 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays +def test_include_read_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo.write_descrs_fields + assert not effectinfo.write_descrs_arrays + def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) @@ -51,6 +60,16 @@ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.write_descrs_arrays +def test_dont_include_read_and_write_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A)), + ("array", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert not effectinfo.readonly_descrs_arrays + assert not effectinfo.write_descrs_fields + assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -1,4 +1,5 @@ import sys +import py from pypy.jit.codewriter.policy import contains_unsupported_variable_type from pypy.jit.codewriter.policy import JitPolicy from pypy.jit.codewriter import support @@ -44,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) @@ -107,3 +108,19 @@ mod = called_graph.func.__module__ assert (mod == 'pypy.rpython.rlist' or mod == 'pypy.rpython.lltypesystem.rlist') + +def test_access_directly_but_not_seen(): + class X: + _virtualizable2_ = ["a"] + def h(x, y): + w = 0 + for i in range(y): + w += 4 + return w + def f(y): + x = jit.hint(X(), access_directly=True) + h(x, y) + rtyper = support.annotate(f, [3]) + h_graph = rtyper.annotator.translator.graphs[1] + assert h_graph.func is h + py.test.raises(ValueError, JitPolicy().look_inside_graph, h_graph) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLException diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,8 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print +from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -13,8 +14,8 @@ from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper -from pypy.jit.metainterp.optimizeutil import InvalidLoop -from pypy.jit.metainterp.resume import NUMBERING +from pypy.jit.metainterp.optimize import InvalidLoop +from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong def giveup(): @@ -118,24 +119,28 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") return old_loop_token if loop.preamble.operations is not None: - send_loop_to_backend(metainterp_sd, loop, "loop") + send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, + "loop") record_loop_or_bridge(metainterp_sd, loop) token = loop.preamble.token if full_preamble_needed: - send_loop_to_backend(metainterp_sd, loop.preamble, "entry bridge") + send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, + loop.preamble, "entry bridge") insert_loop_token(old_loop_tokens, loop.preamble.token) jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp( greenkey, loop.preamble.token) record_loop_or_bridge(metainterp_sd, loop.preamble) return token else: - send_loop_to_backend(metainterp_sd, loop, "loop") + send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, + "loop") insert_loop_token(old_loop_tokens, loop_token) jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp( greenkey, loop.token) @@ -150,7 +155,10 @@ # XXX do we still need a list? old_loop_tokens.append(loop_token) -def send_loop_to_backend(metainterp_sd, loop, type): +def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type): + jitdriver_sd.on_compile(metainterp_sd.logger_ops, loop.token, + loop.operations, type, greenkey) + loopname = jitdriver_sd.warmstate.get_location_str(greenkey) globaldata = metainterp_sd.globaldata loop_token = loop.token loop_token.number = n = globaldata.loopnumbering @@ -165,7 +173,7 @@ debug_start("jit-backend") try: ops_offset = metainterp_sd.cpu.compile_loop(loop.inputargs, operations, - loop.token) + loop.token, name=loopname) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() @@ -186,8 +194,11 @@ if metainterp_sd.warmrunnerdesc is not None: # for tests metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(loop.token) -def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations, - original_loop_token): +def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs, + operations, original_loop_token): + n = metainterp_sd.cpu.get_fail_descr_number(faildescr) + jitdriver_sd.on_compile_bridge(metainterp_sd.logger_ops, + original_loop_token, operations, n) if not we_are_translated(): show_loop(metainterp_sd) TreeLoop.check_consistency_of(inputargs, operations) @@ -204,7 +215,6 @@ metainterp_sd.stats.compiled() metainterp_sd.log("compiled new bridge") # - n = metainterp_sd.cpu.get_fail_descr_number(faildescr) metainterp_sd.logger_ops.log_bridge(inputargs, operations, n, ops_offset) # if metainterp_sd.warmrunnerdesc is not None: # for tests @@ -293,7 +303,7 @@ rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) CNT_INT = -0x20000000 CNT_REF = -0x40000000 @@ -390,8 +400,9 @@ inputargs = metainterp.history.inputargs if not we_are_translated(): self._debug_suboperations = new_loop.operations - send_bridge_to_backend(metainterp.staticdata, self, inputargs, - new_loop.operations, new_loop.token) + send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata, + self, inputargs, new_loop.operations, + new_loop.token) def copy_all_attributes_into(self, res): # XXX a bit ugly to have to list them all here @@ -444,9 +455,17 @@ # Called during a residual call from the assembler, if the code # actually needs to force one of the virtualrefs or the virtualizable. # Implemented by forcing *all* virtualrefs and the virtualizable. - faildescr = cpu.force(token) - assert isinstance(faildescr, ResumeGuardForcedDescr) - faildescr.handle_async_forcing(token) + + # don't interrupt me! If the stack runs out in force_from_resumedata() + # then we have seen cpu.force() but not self.save_data(), leaving in + # an inconsistent state + rstack._stack_criticalcode_start() + try: + faildescr = cpu.force(token) + assert isinstance(faildescr, ResumeGuardForcedDescr) + faildescr.handle_async_forcing(token) + finally: + rstack._stack_criticalcode_stop() def handle_async_forcing(self, force_token): from pypy.jit.metainterp.resume import force_from_resumedata @@ -570,7 +589,8 @@ # to every guard in the loop. new_loop_token = make_loop_token(len(redargs), jitdriver_sd) new_loop.token = new_loop_token - send_loop_to_backend(metainterp_sd, new_loop, "entry bridge") + send_loop_to_backend(self.original_greenkey, metainterp.jitdriver_sd, + metainterp_sd, new_loop, "entry bridge") # send the new_loop to warmspot.py, to be called directly the next time jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp( self.original_greenkey, @@ -614,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -82,9 +82,6 @@ do_call_loopinvariant = do_call do_call_may_force = do_call -def do_call_c(cpu, metainterp, argboxes, descr): - raise NotImplementedError("Should never be called directly") - def do_getarrayitem_gc(cpu, _, arraybox, indexbox, arraydescr): array = arraybox.getref_base() index = indexbox.getint() @@ -319,9 +316,11 @@ if value in (rop.FORCE_TOKEN, rop.CALL_ASSEMBLER, rop.COND_CALL_GC_WB, + rop.COND_CALL_GC_WB_ARRAY, rop.DEBUG_MERGE_POINT, rop.JIT_DEBUG, rop.SETARRAYITEM_RAW, + rop.CALL_RELEASE_GIL, rop.QUASIIMMUT_FIELD, ): # list of opcodes never executed by pyjitpl continue diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -4,7 +4,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rlib.objectmodel import we_are_translated, r_dict, Symbolic from pypy.rlib.objectmodel import compute_unique_id -from pypy.rlib.rarithmetic import intmask, r_int64 +from pypy.rlib.rarithmetic import r_int64 from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop @@ -712,10 +712,14 @@ return -2 # xxx risk of changing hash... def make_hashable_int(i): + from pypy.rpython.lltypesystem.ll2ctypes import NotCtypesAllocatedStructure if not we_are_translated() and isinstance(i, llmemory.AddressAsInt): # Warning: such a hash changes at the time of translation adr = heaptracker.int2adr(i) - return llmemory.cast_adr_to_int(adr, "emulated") + try: + return llmemory.cast_adr_to_int(adr, "emulated") + except NotCtypesAllocatedStructure: + return 12345 # use an arbitrary number for the hash return i def get_const_ptr_for_string(s): @@ -787,11 +791,13 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None token = None call_pure_results = None + logops = None quasi_immutable_deps = None def __init__(self, name): diff --git a/pypy/jit/metainterp/jitdriver.py b/pypy/jit/metainterp/jitdriver.py --- a/pypy/jit/metainterp/jitdriver.py +++ b/pypy/jit/metainterp/jitdriver.py @@ -20,6 +20,7 @@ # self.portal_finishtoken... pypy.jit.metainterp.pyjitpl # self.index ... pypy.jit.codewriter.call # self.mainjitcode ... pypy.jit.codewriter.call + # self.on_compile ... pypy.jit.metainterp.warmstate # These attributes are read by the backend in CALL_ASSEMBLER: # self.assembler_helper_adr diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py --- a/pypy/jit/metainterp/logger.py +++ b/pypy/jit/metainterp/logger.py @@ -11,47 +11,71 @@ def __init__(self, metainterp_sd, guard_number=False): self.metainterp_sd = metainterp_sd - self.ts = metainterp_sd.cpu.ts self.guard_number = guard_number def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): if type is None: debug_start("jit-log-noopt-loop") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-loop") else: debug_start("jit-log-opt-loop") debug_print("# Loop", number, ":", type, "with", len(operations), "ops") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-opt-loop") + return logops def log_bridge(self, inputargs, operations, number=-1, ops_offset=None): if number == -1: debug_start("jit-log-noopt-bridge") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-bridge") else: debug_start("jit-log-opt-bridge") debug_print("# bridge out of Guard", number, "with", len(operations), "ops") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-opt-bridge") + return logops def log_short_preamble(self, inputargs, operations): debug_start("jit-log-short-preamble") - self._log_operations(inputargs, operations, ops_offset=None) - debug_stop("jit-log-short-preamble") + logops = self._log_operations(inputargs, operations, ops_offset=None) + debug_stop("jit-log-short-preamble") + return logops + + def _log_operations(self, inputargs, operations, ops_offset): + if not have_debug_prints(): + return None + logops = self._make_log_operations() + logops._log_operations(inputargs, operations, ops_offset) + return logops + + def _make_log_operations(self): + return LogOperations(self.metainterp_sd, self.guard_number) + + +class LogOperations(object): + """ + ResOperation logger. Each instance contains a memo giving numbers + to boxes, and is typically used to log a single loop. + """ + def __init__(self, metainterp_sd, guard_number): + self.metainterp_sd = metainterp_sd + self.ts = metainterp_sd.cpu.ts + self.guard_number = guard_number + self.memo = {} def repr_of_descr(self, descr): return descr.repr_of_descr() - def repr_of_arg(self, memo, arg): + def repr_of_arg(self, arg): try: - mv = memo[arg] + mv = self.memo[arg] except KeyError: - mv = len(memo) - memo[arg] = mv + mv = len(self.memo) + self.memo[arg] = mv if isinstance(arg, ConstInt): if int_could_be_an_address(arg.value): addr = arg.getaddr() @@ -75,48 +99,53 @@ else: return '?' + def repr_of_resop(self, op, ops_offset=None): + if op.getopnum() == rop.DEBUG_MERGE_POINT: + jd_sd = self.metainterp_sd.jitdrivers_sd[op.getarg(0).getint()] + s = jd_sd.warmstate.get_location_str(op.getarglist()[2:]) + s = s.replace(',', '.') # we use comma for argument splitting + return "debug_merge_point(%d, '%s')" % (op.getarg(1).getint(), s) + if ops_offset is None: + offset = -1 + else: + offset = ops_offset.get(op, -1) + if offset == -1: + s_offset = "" + else: + s_offset = "+%d: " % offset + args = ", ".join([self.repr_of_arg(op.getarg(i)) for i in range(op.numargs())]) + + if op.result is not None: + res = self.repr_of_arg(op.result) + " = " + else: + res = "" + is_guard = op.is_guard() + if op.getdescr() is not None: + descr = op.getdescr() + if is_guard and self.guard_number: + index = self.metainterp_sd.cpu.get_fail_descr_number(descr) + r = "" % index + else: + r = self.repr_of_descr(descr) + args += ', descr=' + r + if is_guard and op.getfailargs() is not None: + fail_args = ' [' + ", ".join([self.repr_of_arg(arg) + for arg in op.getfailargs()]) + ']' + else: + fail_args = '' + return s_offset + res + op.getopname() + '(' + args + ')' + fail_args + def _log_operations(self, inputargs, operations, ops_offset): if not have_debug_prints(): return if ops_offset is None: ops_offset = {} - memo = {} if inputargs is not None: - args = ", ".join([self.repr_of_arg(memo, arg) for arg in inputargs]) + args = ", ".join([self.repr_of_arg(arg) for arg in inputargs]) debug_print('[' + args + ']') for i in range(len(operations)): op = operations[i] - if op.getopnum() == rop.DEBUG_MERGE_POINT: - loc = op.getarg(0)._get_str() - reclev = op.getarg(1).getint() - debug_print("debug_merge_point('%s', %s)" % (loc, reclev)) - continue - offset = ops_offset.get(op, -1) - if offset == -1: - s_offset = "" - else: - s_offset = "+%d: " % offset - args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())]) - if op.result is not None: - res = self.repr_of_arg(memo, op.result) + " = " - else: - res = "" - is_guard = op.is_guard() - if op.getdescr() is not None: - descr = op.getdescr() - if is_guard and self.guard_number: - index = self.metainterp_sd.cpu.get_fail_descr_number(descr) - r = "" % index - else: - r = self.repr_of_descr(descr) - args += ', descr=' + r - if is_guard and op.getfailargs() is not None: - fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg) - for arg in op.getfailargs()]) + ']' - else: - fail_args = '' - debug_print(s_offset + res + op.getopname() + - '(' + args + ')' + fail_args) + debug_print(self.repr_of_resop(operations[i], ops_offset)) if ops_offset and None in ops_offset: offset = ops_offset[None] debug_print("+%d: --end of the loop--" % offset) diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py --- a/pypy/jit/metainterp/optimize.py +++ b/pypy/jit/metainterp/optimize.py @@ -1,9 +1,20 @@ from pypy.rlib.debug import debug_start, debug_stop +from pypy.jit.metainterp.jitexc import JitException + +class InvalidLoop(JitException): + """Raised when the optimize*.py detect that the loop that + we are trying to build cannot possibly make sense as a + long-running loop (e.g. it cannot run 2 complete iterations).""" + +class RetraceLoop(JitException): + """ Raised when inlining a short preamble resulted in an + InvalidLoop. This means the optimized loop is too specialized + to be useful here, so we trace it again and produced a second + copy specialized in some different way. + """ # ____________________________________________________________ -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, optimize_bridge_1 - def optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): debug_start("jit-optimize") try: @@ -13,8 +24,9 @@ debug_stop("jit-optimize") def _optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): - cpu = metainterp_sd.cpu - metainterp_sd.logger_noopt.log_loop(loop.inputargs, loop.operations) + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 + loop.logops = metainterp_sd.logger_noopt.log_loop(loop.inputargs, + loop.operations) # XXX do we really still need a list? if old_loop_tokens: return old_loop_tokens[0] @@ -35,8 +47,9 @@ def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts, inline_short_preamble, retraced=False): - cpu = metainterp_sd.cpu - metainterp_sd.logger_noopt.log_loop(bridge.inputargs, bridge.operations) + from pypy.jit.metainterp.optimizeopt import optimize_bridge_1 + bridge.logops = metainterp_sd.logger_noopt.log_loop(bridge.inputargs, + bridge.operations) if old_loop_tokens: old_loop_token = old_loop_tokens[0] bridge.operations[-1].setdescr(old_loop_token) # patch jump target diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -15,7 +15,7 @@ ('virtualize', OptVirtualize), ('string', OptString), ('heap', OptHeap), - ('ffi', OptFfiCall), + ('ffi', None), ('unroll', None)] # no direct instantiation of unroll unroll_all_opts = unrolling_iterable(ALL_OPTS) @@ -25,10 +25,9 @@ ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) PARAMETERS['enable_opts'] = ALL_OPTS_NAMES -def optimize_loop_1(metainterp_sd, loop, enable_opts, +def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): - """Optimize loop.operations to remove internal overheadish operations. - """ + config = metainterp_sd.config optimizations = [] unroll = 'unroll' in enable_opts for name, opt in unroll_all_opts: @@ -40,6 +39,11 @@ # FIXME: Workaround to disable string optimisation # during preamble but to keep it during the loop optimizations.append(o) + elif name == 'ffi' and config.translation.jit_ffi: + # we cannot put the class directly in the unrolling_iterable, + # because we do not want it to be seen at all (to avoid to + # introduce a dependency on libffi in case we do not need it) + optimizations.append(OptFfiCall()) if ('rewrite' not in enable_opts or 'virtualize' not in enable_opts or 'heap' not in enable_opts): @@ -48,6 +52,17 @@ if inline_short_preamble: optimizations = [OptInlineShortPreamble(retraced)] + optimizations + return optimizations, unroll + + +def optimize_loop_1(metainterp_sd, loop, enable_opts, + inline_short_preamble=True, retraced=False): + """Optimize loop.operations to remove internal overheadish operations. + """ + + optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, + inline_short_preamble, retraced) + if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -1,10 +1,13 @@ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.libffi import Func +from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall from pypy.jit.metainterp.optimizeopt.optimizer import Optimization +from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind + class FuncInfo(object): @@ -12,14 +15,18 @@ restype = None descr = None prepare_op = None - force_token_op = None def __init__(self, funcval, cpu, prepare_op): self.funcval = funcval self.opargs = [] argtypes, restype = self._get_signature(funcval) - self.descr = cpu.calldescrof_dynamic(argtypes, restype) + try: + self.descr = cpu.calldescrof_dynamic(argtypes, restype) + except UnsupportedKind: + # e.g., I or U for long longs + self.descr = None self.prepare_op = prepare_op + self.delayed_ops = [] def _get_signature(self, funcval): """ @@ -64,37 +71,51 @@ class OptFfiCall(Optimization): - def __init__(self): + def setup(self): self.funcinfo = None + if self.optimizer.loop is not None: + self.logops = self.optimizer.loop.logops + else: + self.logops = None + + def propagate_begin_forward(self): + debug_start('jit-log-ffiopt') + Optimization.propagate_begin_forward(self) + + def propagate_end_forward(self): + debug_stop('jit-log-ffiopt') + Optimization.propagate_end_forward(self) def reconstruct_for_next_iteration(self, optimizer, valuemap): return OptFfiCall() # FIXME: Should any status be saved for next iteration? def begin_optimization(self, funcval, op): - self.rollback_maybe() + self.rollback_maybe('begin_optimization', op) self.funcinfo = FuncInfo(funcval, self.optimizer.cpu, op) def commit_optimization(self): self.funcinfo = None - def rollback_maybe(self): + def rollback_maybe(self, msg, op): if self.funcinfo is None: return # nothing to rollback # # we immediately set funcinfo to None to prevent recursion when # calling emit_op + if self.logops is not None: + debug_print('rollback: ' + msg + ': ', self.logops.repr_of_resop(op)) funcinfo = self.funcinfo self.funcinfo = None self.emit_operation(funcinfo.prepare_op) for op in funcinfo.opargs: self.emit_operation(op) - if funcinfo.force_token_op: - self.emit_operation(funcinfo.force_token_op) + for delayed_op in funcinfo.delayed_ops: + self.emit_operation(delayed_op) def emit_operation(self, op): # we cannot emit any operation during the optimization - self.rollback_maybe() + self.rollback_maybe('invalid op', op) Optimization.emit_operation(self, op) def optimize_CALL(self, op): @@ -135,13 +156,18 @@ # call_may_force and the setfield_gc, so the final result we get is # again force_token/setfield_gc/call_may_force. # + # However, note that nowadays we also allow to have any setfield_gc + # between libffi_prepare and libffi_call, so while the comment above + # it's a bit superfluous, it has been left there for future reference. if self.funcinfo is None: self.emit_operation(op) else: - self.funcinfo.force_token_op = op + self.funcinfo.delayed_ops.append(op) + + optimize_SETFIELD_GC = optimize_FORCE_TOKEN def do_prepare_call(self, op): - self.rollback_maybe() + self.rollback_maybe('prepare call', op) funcval = self._get_funcval(op) if not funcval.is_constant(): return [op] # cannot optimize @@ -165,16 +191,18 @@ for push_op in funcinfo.opargs: argval = self.getvalue(push_op.getarg(2)) arglist.append(argval.force_box()) - newop = ResOperation(rop.CALL_MAY_FORCE, arglist, op.result, + newop = ResOperation(rop.CALL_RELEASE_GIL, arglist, op.result, descr=funcinfo.descr) self.commit_optimization() ops = [] - if funcinfo.force_token_op: - ops.append(funcinfo.force_token_op) + for delayed_op in funcinfo.delayed_ops: + ops.append(delayed_op) ops.append(newop) return ops def propagate_forward(self, op): + if self.logops is not None: + debug_print(self.logops.repr_of_resop(op)) opnum = op.getopnum() for value, func in optimize_ops: if opnum == value: diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -8,8 +8,8 @@ class CachedField(object): def __init__(self): - # Cache information for a field descr. It can be in one - # of two states: + # Cache information for a field descr, or for an (array descr, index) + # pair. It can be in one of two states: # # 1. 'cached_fields' is a dict mapping OptValues of structs # to OptValues of fields. All fields on-heap are @@ -27,19 +27,19 @@ self._lazy_setfield_registered = False def do_setfield(self, optheap, op): - # Update the state with the SETFIELD_GC operation 'op'. + # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) if self.possible_aliasing(optheap, structvalue): self.force_lazy_setfield(optheap) assert not self.possible_aliasing(optheap, structvalue) cached_fieldvalue = self._cached_fields.get(structvalue, None) if cached_fieldvalue is not fieldvalue: # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields list + # myself in the optheap's _lazy_setfields_and_arrayitems list self._lazy_setfield = op if not self._lazy_setfield_registered: - optheap._lazy_setfields.append(self) + optheap._lazy_setfields_and_arrayitems.append(self) self._lazy_setfield_registered = True else: # this is the case where the pending setfield ends up @@ -65,7 +65,7 @@ if self._lazy_setfield is not None: op = self._lazy_setfield assert optheap.getvalue(op.getarg(0)) is structvalue - return optheap.getvalue(op.getarg(1)) + return optheap.getvalue(op.getarglist()[-1]) else: return self._cached_fields.get(structvalue, None) @@ -87,7 +87,7 @@ # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) def get_reconstructed(self, optimizer, valuemap): @@ -100,25 +100,20 @@ return cf -class CachedArrayItems(object): - def __init__(self): - self.fixed_index_items = {} - self.var_index_item = None - self.var_index_indexvalue = None - class BogusPureField(JitException): pass class OptHeap(Optimization): """Cache repeated heap accesses""" - + def __init__(self): # cached fields: {descr: CachedField} self.cached_fields = {} - self._lazy_setfields = [] - # cached array items: {descr: CachedArrayItems} + # cached array items: {array descr: {index: CachedField}} self.cached_arrayitems = {} + # + self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -126,34 +121,23 @@ new = OptHeap() if True: - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() else: assert 0 # was: new.lazy_setfields = self.lazy_setfields - + for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) - new.cached_arrayitems = {} - for descr, d in self.cached_arrayitems.items(): - newd = {} - new.cached_arrayitems[descr] = newd - for value, cache in d.items(): - newcache = CachedArrayItems() - newd[value.get_reconstructed(optimizer, valuemap)] = newcache - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_reconstructed(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) - for index, fieldvalue in cache.fixed_index_items.items(): - newcache.fixed_index_items[index] = \ - fieldvalue.get_reconstructed(optimizer, valuemap) + for descr, submap in self.cached_arrayitems.items(): + newdict = {} + for index, d in submap.items(): + newdict[index] = d.get_reconstructed(optimizer, valuemap) + new.cached_arrayitems[descr] = newdict return new def clean_caches(self): - del self._lazy_setfields[:] + del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() self.cached_arrayitems.clear() @@ -164,50 +148,16 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): - d = self.cached_arrayitems.get(descr, None) - if d is None: - d = self.cached_arrayitems[descr] = {} - cache = d.get(value, None) - if cache is None: - cache = d[value] = CachedArrayItems() - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - index = indexbox.getint() - if write: - for value, othercache in d.iteritems(): - # fixed index, clean the variable index cache, in case the - # index is the same - othercache.var_index_indexvalue = None - othercache.var_index_item = None - try: - del othercache.fixed_index_items[index] - except KeyError: - pass - cache.fixed_index_items[index] = fieldvalue - else: - if write: - for value, othercache in d.iteritems(): - # variable index, clear all caches for this descr - othercache.var_index_indexvalue = None - othercache.var_index_item = None - othercache.fixed_index_items.clear() - cache.var_index_indexvalue = indexvalue - cache.var_index_item = fieldvalue - - def read_cached_arrayitem(self, descr, value, indexvalue): - d = self.cached_arrayitems.get(descr, None) - if d is None: - return None - cache = d.get(value, None) - if cache is None: - return None - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - return cache.fixed_index_items.get(indexbox.getint(), None) - elif cache.var_index_indexvalue is indexvalue: - return cache.var_index_item - return None + def arrayitem_cache(self, descr, index): + try: + submap = self.cached_arrayitems[descr] + except KeyError: + submap = self.cached_arrayitems[descr] = {} + try: + cf = submap[index] + except KeyError: + cf = submap[index] = CachedField() + return cf def emit_operation(self, op): self.emitting_operation(op) @@ -219,7 +169,8 @@ if op.is_ovf(): return if op.is_guard(): - self.optimizer.pendingfields = self.force_lazy_setfields_for_guard() + self.optimizer.pendingfields = ( + self.force_lazy_setfields_and_arrayitems_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -235,6 +186,7 @@ assert opnum != rop.CALL_PURE if (opnum == rop.CALL or opnum == rop.CALL_MAY_FORCE or + opnum == rop.CALL_RELEASE_GIL or opnum == rop.CALL_ASSEMBLER): if opnum == rop.CALL_ASSEMBLER: effectinfo = None @@ -242,11 +194,13 @@ effectinfo = op.getdescr().get_extra_info() if effectinfo is None or effectinfo.check_can_invalidate(): self._seen_guard_not_invalidated = False - if effectinfo is not None: + if effectinfo is not None and not effectinfo.has_random_effects(): # XXX we can get the wrong complexity here, if the lists # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: self.force_lazy_setfield(fielddescr) + for arraydescr in effectinfo.readonly_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: self.force_lazy_setfield(fielddescr) try: @@ -255,8 +209,11 @@ except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) try: - del self.cached_arrayitems[arraydescr] + submap = self.cached_arrayitems[arraydescr] + for cf in submap.itervalues(): + cf._cached_fields.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -265,7 +222,7 @@ # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. return - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() self.clean_caches() @@ -276,6 +233,10 @@ for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] + for submap in self.cached_arrayitems.itervalues(): + for cf in submap.itervalues(): + if value in cf._cached_fields: + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -284,6 +245,14 @@ return cf.force_lazy_setfield(self) + def force_lazy_setarrayitem(self, arraydescr): + try: + submap = self.cached_arrayitems[arraydescr] + except KeyError: + return + for cf in submap.values(): + cf.force_lazy_setfield(self) + def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes # sense to avoid a situation like "int_eq/setfield_gc/guard_true", @@ -308,30 +277,49 @@ newoperations[-2] = lastop newoperations[-1] = prevop - def force_all_lazy_setfields(self): - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + def _assert_valid_cf(self, cf): + # check that 'cf' is in cached_fields or cached_arrayitems + if not we_are_translated(): + if cf not in self.cached_fields.values(): + for submap in self.cached_arrayitems.values(): + if cf in submap.values(): + break + else: + assert 0, "'cf' not in cached_fields/cached_arrayitems" + + def force_all_lazy_setfields_and_arrayitems(self): + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) cf.force_lazy_setfield(self) - def force_lazy_setfields_for_guard(self): + def force_lazy_setfields_and_arrayitems_for_guard(self): pendingfields = [] - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) op = cf._lazy_setfield if op is None: continue # the only really interesting case that we need to handle in the # guards' resume data is that of a virtual object that is stored - # into a field of a non-virtual object. + # into a field of a non-virtual object. Here, 'op' in either + # SETFIELD_GC or SETARRAYITEM_GC. value = self.getvalue(op.getarg(0)) assert not value.is_virtual() # it must be a non-virtual - fieldvalue = self.getvalue(op.getarg(1)) + fieldvalue = self.getvalue(op.getarglist()[-1]) if fieldvalue.is_virtual(): # this is the case that we leave to resume.py + opnum = op.getopnum() + if opnum == rop.SETFIELD_GC: + itemindex = -1 + elif opnum == rop.SETARRAYITEM_GC: + indexvalue = self.getvalue(op.getarg(1)) + assert indexvalue.is_constant() + itemindex = indexvalue.box.getint() + assert itemindex >= 0 + else: + assert 0 pendingfields.append((op.getdescr(), value.box, - fieldvalue.get_key_box())) + fieldvalue.get_key_box(), itemindex)) else: cf.force_lazy_setfield(self) self.fixup_guard_situation() @@ -363,24 +351,45 @@ cf.do_setfield(self, op) def optimize_GETARRAYITEM_GC(self, op): - value = self.getvalue(op.getarg(0)) + arrayvalue = self.getvalue(op.getarg(0)) indexvalue = self.getvalue(op.getarg(1)) - fieldvalue = self.read_cached_arrayitem(op.getdescr(), value, indexvalue) - if fieldvalue is not None: - self.make_equal_to(op.result, fieldvalue) - return - ###self.optimizer.optimize_default(op) + cf = None + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + fieldvalue = cf.getfield_from_cache(self, arrayvalue) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # default case: produce the operation + arrayvalue.ensure_nonnull() self.emit_operation(op) - fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) + # the remember the result of reading the array item + if cf is not None: + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(arrayvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): - self.emit_operation(op) - value = self.getvalue(op.getarg(0)) - fieldvalue = self.getvalue(op.getarg(2)) + if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), + op.getarg(1)], + op.getdescr()): + os.write(2, '[bogus immutable array declaration: %s]\n' % + (op.getdescr().repr_of_descr())) + raise BogusPureField + # indexvalue = self.getvalue(op.getarg(1)) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - write=True) + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + cf.do_setfield(self, op) + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # and then emit the operation + self.emit_operation(op) def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeutil import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -17,6 +17,14 @@ assert self.posponedop is None return self + def setup(self): + self.posponedop = None + self.nextop = None + + def reconstruct_for_next_iteration(self, optimizer, valuemap): + assert self.posponedop is None + return self + def propagate_forward(self, op): if op.is_ovf(): self.posponedop = op @@ -186,7 +194,7 @@ # Synthesize the reverse ops for optimize_default to reuse self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0)) self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1)) - + def optimize_INT_MUL_OVF(self, op): v1 = self.getvalue(op.getarg(0)) @@ -284,6 +292,11 @@ v1.intbound.make_ge(IntLowerBound(0)) v1.intbound.make_lt(IntUpperBound(256)) + def optimize_UNICODEGETITEM(self, op): + self.emit_operation(op) + v1 = self.getvalue(op.result) + v1.intbound.make_ge(IntLowerBound(0)) + def make_int_lt(self, box1, box2): v1 = self.getvalue(box1) v2 = self.getvalue(box2) @@ -360,6 +373,15 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -405,5 +427,6 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL + optimize_ops = _findall(OptIntBounds, 'optimize_') propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,9 +4,9 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs -from pypy.jit.metainterp.optimizeutil import descrlist_dict -from pypy.jit.metainterp.optimizeutil import InvalidLoop, args_dict +from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.rpython.lltypesystem import lltype @@ -141,6 +141,9 @@ # meaning it has been forced. return self.box is None + def is_forced_virtual(self): + return False + def getfield(self, ofs, default): raise NotImplementedError @@ -175,6 +178,14 @@ def __init__(self): pass # make rpython happy + def propagate_begin_forward(self): + if self.next_optimization: + self.next_optimization.propagate_begin_forward() + + def propagate_end_forward(self): + if self.next_optimization: + self.next_optimization.propagate_end_forward() + def propagate_forward(self, op): raise NotImplementedError @@ -406,11 +417,13 @@ # ^^^ at least at the start of bridges. For loops, we could set # it to False, but we probably don't care self.newoperations = [] + self.first_optimization.propagate_begin_forward() self.i = 0 while self.i < len(self.loop.operations): op = self.loop.operations[self.i] self.first_optimization.propagate_forward(op) self.i += 1 + self.first_optimization.propagate_end_forward() self.loop.operations = self.newoperations self.loop.quasi_immutable_deps = self.quasi_immutable_deps # accumulate counters diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -184,6 +184,32 @@ else: self.emit_operation(op) + def optimize_FLOAT_MUL(self, op): + arg1 = op.getarg(0) + arg2 = op.getarg(1) + + # Constant fold f0 * 1.0 and turn f0 * -1.0 into a FLOAT_NEG, these + # work in all cases, including NaN and inf + for lhs, rhs in [(arg1, arg2), (arg2, arg1)]: + v1 = self.getvalue(lhs) + v2 = self.getvalue(rhs) + + if v1.is_constant(): + if v1.box.getfloat() == 1.0: + self.make_equal_to(op.result, v2) + return + elif v1.box.getfloat() == -1.0: + self.emit_operation(ResOperation( + rop.FLOAT_NEG, [rhs], op.result + )) + return + self.emit_operation(op) + + def optimize_FLOAT_NEG(self, op): + v1 = op.getarg(0) + self.emit_operation(op) + self.pure(rop.FLOAT_NEG, [op.result], v1) + def optimize_CALL_PURE(self, op): arg_consts = [] for i in range(op.numargs()): @@ -193,7 +219,7 @@ break arg_consts.append(const) else: - # all constant arguments: check if we already know the reslut + # all constant arguments: check if we already know the result try: result = self.optimizer.call_pure_results[arg_consts] except KeyError: @@ -415,14 +441,22 @@ dest_start_box = self.get_constant_box(op.getarg(4)) length = self.get_constant_box(op.getarg(5)) if (source_value.is_virtual() and source_start_box and dest_start_box - and length and dest_value.is_virtual()): - # XXX optimize the case where dest value is not virtual, - # but we still can avoid a mess + and length and (dest_value.is_virtual() or length.getint() <= 8)): + from pypy.jit.metainterp.optimizeopt.virtualize import VArrayValue + assert isinstance(source_value, VArrayValue) source_start = source_start_box.getint() dest_start = dest_start_box.getint() for index in range(length.getint()): val = source_value.getitem(index + source_start) - dest_value.setitem(index + dest_start, val) + if dest_value.is_virtual(): + dest_value.setitem(index + dest_start, val) + else: + newop = ResOperation(rop.SETARRAYITEM_GC, + [op.getarg(2), + ConstInt(index + dest_start), + val.force_box()], None, + descr=source_value.arraydescr) + self.emit_operation(newop) return True if length and length.getint() == 0: return True # 0-length arraycopy @@ -432,6 +466,9 @@ v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) + if v2.is_constant() and v2.box.getint() == 1: + self.make_equal_to(op.result, v1) + return if v1.intbound.known_ge(IntBound(0, 0)) and v2.is_constant(): val = v2.box.getint() if val & (val - 1) == 0 and val > 0: # val == 2**shift diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/string.py --- a/pypy/jit/metainterp/optimizeopt/string.py +++ b/pypy/jit/metainterp/optimizeopt/string.py @@ -8,7 +8,7 @@ from pypy.jit.metainterp.optimizeopt import optimizer, virtualize from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1 from pypy.jit.metainterp.optimizeopt.optimizer import llhelper -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter import heaptracker from pypy.rlib.unroll import unrolling_iterable @@ -348,7 +348,7 @@ optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimizer, strbox, indexbox, mode): +def _strgetitem(optimization, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimizer.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,8 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self.optimizer, - value.force_box(),vindex.force_box(), mode) + resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/test/__init__.py b/pypy/jit/metainterp/optimizeopt/test/__init__.py new file mode 100644 diff --git a/pypy/jit/metainterp/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py rename from pypy/jit/metainterp/test/test_optimizebasic.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1,37 +1,15 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, FakeMetaInterpStaticData) +from pypy.jit.metainterp.test.test_compile import FakeLogger import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt -from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation -from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.optimizeutil import args_dict - -##class FakeFrame(object): -## parent_resumedata_snapshot = None -## parent_resumedata_frame_info_list = None - -## def __init__(self, code="", pc=0): -## self.jitcode = code -## self.pc = pc - -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() + def test_store_final_boxes_in_guard(): from pypy.jit.metainterp.compile import ResumeGuardDescr @@ -101,7 +79,7 @@ assert vinfo3 is vinfo4 def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil + from pypy.jit.metainterp.optimizeopt import util as optimizeutil h1 = optimizeutil.descrlist_hash([]) h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) h3 = optimizeutil.descrlist_hash( @@ -130,159 +108,55 @@ # ____________________________________________________________ -def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}, - text_right=None): - # try to use the full width of the terminal to display the list - # unfortunately, does not work with the default capture method of py.test - # (which is fd), you you need to use either -s or --capture=sys, else you - # get the standard 80 columns width - totwidth = py.io.get_terminal_width() - width = totwidth / 2 - 1 - print ' Comparing lists '.center(totwidth, '-') - text_right = text_right or 'expected' - print '%s| %s' % ('optimized'.center(width), text_right.center(width)) - for op1, op2 in zip(oplist1, oplist2): - txt1 = str(op1) - txt2 = str(op2) - while txt1 or txt2: - print '%s| %s' % (txt1[:width].ljust(width), txt2[:width]) - txt1 = txt1[width:] - txt2 = txt2[width:] - assert op1.getopnum() == op2.getopnum() - assert op1.numargs() == op2.numargs() - for i in range(op1.numargs()): - x = op1.getarg(i) - y = op2.getarg(i) - assert x == remap.get(y, y) - if op2.result in remap: - assert op1.result == remap[op2.result] - else: - remap[op2.result] = op1.result - if op1.getopnum() != rop.JUMP: # xxx obscure - assert op1.getdescr() == op2.getdescr() - if op1.getfailargs() or op2.getfailargs(): - assert len(op1.getfailargs()) == len(op2.getfailargs()) - if strict_fail_args: - for x, y in zip(op1.getfailargs(), op2.getfailargs()): - assert x == remap.get(y, y) - else: - fail_args1 = set(op1.getfailargs()) - fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()]) - assert fail_args1 == fail_args2 - assert len(oplist1) == len(oplist2) - print '-'*totwidth - return True - -def test_equaloplists(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops, namespace=namespace) - loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), - namespace=namespace) - assert equaloplists(loop1.operations, loop2.operations) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -def test_equaloplists_fail_args(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2, i1] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop2.operations)") - assert equaloplists(loop1.operations, loop2.operations, - strict_fail_args=False) - loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -# ____________________________________________________________ - -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) class BaseTestBasic(BaseTest): - def invent_fail_descr(self, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap) + enable_opts = "intbounds:rewrite:virtualize:string:heap" def optimize_loop(self, ops, optops, call_pure_results=None): + loop = self.parse(ops) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v - metainterp_sd = FakeMetaInterpStaticData(self.cpu) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - # - # XXX list the exact optimizations that are needed for each test - from pypy.jit.metainterp.optimizeopt import (OptIntBounds, - OptRewrite, - OptVirtualize, - OptString, - OptHeap, - Optimizer) - from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall - - optimizations = [OptIntBounds(), - OptRewrite(), - OptVirtualize(), - OptString(), - OptHeap(), - OptFfiCall(), - ] - optimizer = Optimizer(metainterp_sd, loop, optimizations) - optimizer.propagate_all_forward() - # expected = self.parse(optops) + self._do_optimize_loop(loop, call_pure_results) print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + + class BaseTestOptimizeBasic(BaseTestBasic): @@ -1231,8 +1105,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1597,9 +1471,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) jump(p1, i1, i2, p3) """ @@ -1773,6 +1647,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2035,7 +1910,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2053,7 +1927,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2071,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2287,25 +2159,83 @@ """ self.optimize_loop(ops, expected) + def test_fold_constant_partial_ops_float(self): + ops = """ + [f0] + f1 = float_mul(f0, 1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + + ops = """ + [f0] + f1 = float_mul(f0, -1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(-1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + def test_fold_repeated_float_neg(self): + ops = """ + [f0] + f1 = float_neg(f0) + f2 = float_neg(f1) + f3 = float_neg(f2) + f4 = float_neg(f3) + escape(f4) + jump(f4) + """ + expected = """ + [f0] + # The backend removes this dead op. + f1 = float_neg(f0) + escape(f0) + jump(f0) + """ + self.optimize_loop(ops, expected) + # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2414,7 +2344,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2435,7 +2364,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2455,7 +2383,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2481,7 +2408,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2506,7 +2433,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2530,7 +2456,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2551,7 +2476,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2572,7 +2496,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2594,7 +2517,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2636,7 +2558,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2662,7 +2583,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2686,9 +2606,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2980,7 +2897,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3026,7 +2942,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3065,7 +2980,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3092,7 +3006,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -4566,6 +4479,47 @@ # not obvious, because of the exception UnicodeDecodeError that # can be raised by ll_str2unicode() + def test_strgetitem_repeated(self): + ops = """ + [p0, i0] + i1 = strgetitem(p0, i0) + i2 = strgetitem(p0, i0) + i3 = int_eq(i1, i2) + guard_true(i3) [] + escape(i2) + jump(p0, i0) + """ + expected = """ + [p0, i0] + i1 = strgetitem(p0, i0) + escape(i1) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py rename from pypy/jit/metainterp/test/test_optimizefficall.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py --- a/pypy/jit/metainterp/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py @@ -2,8 +2,8 @@ from pypy.rlib.libffi import Func, types from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.metainterp.test.test_optimizebasic import BaseTestBasic -from pypy.jit.metainterp.test.test_optimizebasic import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import BaseTestBasic +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import LLtypeMixin class MyCallDescr(AbstractDescr): """ @@ -32,12 +32,15 @@ class TestFfiCall(BaseTestBasic, LLtypeMixin): - jit_ffi = True + + enable_opts = "intbounds:rewrite:virtualize:string:heap:ffi" class namespace: cpu = LLtypeMixin.cpu FUNC = LLtypeMixin.FUNC vable_token_descr = LLtypeMixin.valuedescr + valuedescr = LLtypeMixin.valuedescr + int_float__int = MyCallDescr('if', 'i') funcptr = FakeLLObject() func = FakeLLObject(_fake_class=Func, @@ -48,7 +51,7 @@ restype=types.sint) # def calldescr(cpu, FUNC, oopspecindex, extraeffect=None): - einfo = EffectInfo([], [], [], oopspecindex=oopspecindex, + einfo = EffectInfo([], [], [], [], oopspecindex=oopspecindex, extraeffect=extraeffect) return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo) # @@ -76,7 +79,7 @@ """ expected = """ [i0, f1] - i3 = call_may_force(12345, i0, f1, descr=int_float__int) + i3 = call_release_gil(12345, i0, f1, descr=int_float__int) guard_not_forced() [] guard_no_exception() [] jump(i3, f1) @@ -99,7 +102,7 @@ def test_handle_virtualizables(self): # this test needs an explanation to understand what goes on: see the - # coment in optimize_FORCE_TOKEN + # comment in optimize_FORCE_TOKEN ops = """ [i0, f1, p2] call(0, ConstPtr(func), descr=libffi_prepare) @@ -116,7 +119,7 @@ [i0, f1, p2] i4 = force_token() setfield_gc(p2, i4, descr=vable_token_descr) - i3 = call_may_force(12345, i0, f1, descr=int_float__int) + i3 = call_release_gil(12345, i0, f1, descr=int_float__int) guard_not_forced() [p2] guard_no_exception() [p2] jump(i3, f1, p2) @@ -213,7 +216,7 @@ call(0, ConstPtr(func), descr=libffi_prepare) # # this "nested" call is nicely optimized - i4 = call_may_force(67890, i0, f1, descr=int_float__int) + i4 = call_release_gil(67890, i0, f1, descr=int_float__int) guard_not_forced() [] guard_no_exception() [] # @@ -242,3 +245,25 @@ """ expected = ops loop = self.optimize_loop(ops, expected) + + def test_allow_setfields_in_between(self): + ops = """ + [i0, f1, p2] + call(0, ConstPtr(func), descr=libffi_prepare) + call(0, ConstPtr(func), i0, descr=libffi_push_arg) + call(0, ConstPtr(func), f1, descr=libffi_push_arg) + setfield_gc(p2, i0, descr=valuedescr) + i3 = call_may_force(0, ConstPtr(func), 12345, descr=libffi_call) + guard_not_forced() [] + guard_no_exception() [] + jump(i3, f1, p2) + """ + expected = """ + [i0, f1, p2] + setfield_gc(p2, i0, descr=valuedescr) + i3 = call_release_gil(12345, i0, f1, descr=int_float__int) + guard_not_forced() [] + guard_no_exception() [] + jump(i3, f1, p2) + """ + loop = self.optimize_loop(ops, expected) diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py rename from pypy/jit/metainterp/test/test_optimizeopt.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1,202 +1,88 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, Storage, _sortboxes) import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT, build_opt_chain +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.test.test_optimizebasic import equaloplists -from pypy.jit.metainterp.optimizeutil import args_dict - -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu, jit_ffi=False): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() - self.jit_ffi = jit_ffi - -def test_store_final_boxes_in_guard(): - from pypy.jit.metainterp.compile import ResumeGuardDescr - from pypy.jit.metainterp.resume import tag, TAGBOX - b0 = BoxInt() - b1 = BoxInt() - opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu), - None) - fdescr = ResumeGuardDescr() - op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr) - # setup rd data - fi0 = resume.FrameInfo(None, "code0", 11) - fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33) - snapshot0 = resume.Snapshot(None, [b0]) - fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1]) +from pypy.jit.metainterp.optimizeopt.util import args_dict +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import FakeMetaInterpStaticData +from pypy.config.pypyoption import get_pypy_config + + +def test_build_opt_chain(): + def check(chain, expected_names): + names = [opt.__class__.__name__ for opt in chain] + assert names == expected_names # - opt.store_final_boxes_in_guard(op) - if op.getfailargs() == [b0, b1]: - assert list(fdescr.rd_numb.nums) == [tag(1, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)] - else: - assert op.getfailargs() == [b1, b0] - assert list(fdescr.rd_numb.nums) == [tag(0, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(1, TAGBOX)] - assert fdescr.rd_virtuals is None - assert fdescr.rd_consts == [] - -def test_sharing_field_lists_of_virtual(): - class FakeOptimizer(object): - class cpu(object): - pass - opt = FakeOptimizer() - virt1 = virtualize.AbstractVirtualStructValue(opt, None) - lst1 = virt1._get_field_descr_list() - assert lst1 == [] - lst2 = virt1._get_field_descr_list() - assert lst1 is lst2 - virt1.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst3 = virt1._get_field_descr_list() - assert lst3 == [LLtypeMixin.valuedescr] - lst4 = virt1._get_field_descr_list() - assert lst3 is lst4 - - virt2 = virtualize.AbstractVirtualStructValue(opt, None) - lst5 = virt2._get_field_descr_list() - assert lst5 is lst1 - virt2.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst6 = virt1._get_field_descr_list() - assert lst6 is lst3 - -def test_reuse_vinfo(): - class FakeVInfo(object): - def set_content(self, fieldnums): - self.fieldnums = fieldnums - def equals(self, fieldnums): - return self.fieldnums == fieldnums - class FakeVirtualValue(virtualize.AbstractVirtualValue): - def _make_virtual(self, *args): - return FakeVInfo() - v1 = FakeVirtualValue(None, None, None) - vinfo1 = v1.make_virtual_info(None, [1, 2, 4]) - vinfo2 = v1.make_virtual_info(None, [1, 2, 4]) - assert vinfo1 is vinfo2 - vinfo3 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is not vinfo2 - vinfo4 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is vinfo4 - -def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil - h1 = optimizeutil.descrlist_hash([]) - h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) - h3 = optimizeutil.descrlist_hash( - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert h1 != h2 - assert h2 != h3 - assert optimizeutil.descrlist_eq([], []) - assert not optimizeutil.descrlist_eq([], [LLtypeMixin.valuedescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.nextdescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr, LLtypeMixin.nextdescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.nextdescr, LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - - # descrlist_eq should compare by identity of the descrs, not by the result - # of sort_key - class FakeDescr(object): - def sort_key(self): - return 1 - - assert not optimizeutil.descrlist_eq([FakeDescr()], [FakeDescr()]) + metainterp_sd = FakeMetaInterpStaticData(None) + chain, _ = build_opt_chain(metainterp_sd, "", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "heap:intbounds") + check(chain, ["OptInlineShortPreamble", "OptIntBounds", "OptHeap", "OptSimplify"]) + # + chain, unroll = build_opt_chain(metainterp_sd, "unroll") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + assert unroll + # + chain, _ = build_opt_chain(metainterp_sd, "aaa:bbb", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptFfiCall", "OptSimplify"]) + # + metainterp_sd.config = get_pypy_config(translating=True) + assert not metainterp_sd.config.translation.jit_ffi + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # ____________________________________________________________ -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure + + +class FakeDescr(compile.ResumeGuardDescr): + class rd_snapshot: + class prev: + prev = None + boxes = [] + boxes = [] def clone_if_mutable(self): - res = Storage(self.metainterp_sd, self.original_greenkey) - self.copy_all_attributes_into(res) - return res - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) - -class BaseTestOptimizeOpt(BaseTest): - jit_ffi = False - - def invent_fail_descr(self, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected, text_right=None): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap, text_right) - - def optimize_loop(self, ops, optops, expected_preamble=None, + return self + + +class BaseTestWithUnroll(BaseTest): + + enable_opts = "intbounds:rewrite:virtualize:string:heap:unroll" + + def optimize_loop(self, ops, expected, expected_preamble=None, call_pure_results=None): loop = self.parse(ops) - if optops != "crash!": - expected = self.parse(optops) - else: - expected = "crash!" + if expected != "crash!": + expected = self.parse(expected) if expected_preamble: expected_preamble = self.parse(expected_preamble) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v + loop.preamble = TreeLoop('preamble') loop.preamble.inputargs = loop.inputargs loop.preamble.token = LoopToken() - metainterp_sd = FakeMetaInterpStaticData(self.cpu, self.jit_ffi) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - class FakeDescr(compile.ResumeGuardDescr): - class rd_snapshot: - class prev: - prev = None - boxes = [] - boxes = [] - def clone_if_mutable(self): - return self loop.preamble.start_resumedescr = FakeDescr() - optimize_loop_1(metainterp_sd, loop, ALL_OPTS_DICT) # - + self._do_optimize_loop(loop, call_pure_results) + # print print loop.preamble.inputargs print '\n'.join([str(o) for o in loop.preamble.operations]) @@ -204,16 +90,14 @@ print loop.inputargs print '\n'.join([str(o) for o in loop.operations]) print - assert expected != "crash!", "should have raised an exception" self.assert_equal(loop, expected) if expected_preamble: self.assert_equal(loop.preamble, expected_preamble, text_right='expected preamble') - return loop -class OptimizeOptTest(BaseTestOptimizeOpt): +class OptimizeOptTest(BaseTestWithUnroll): def setup_method(self, meth=None): class FailDescr(compile.ResumeGuardDescr): @@ -1497,8 +1381,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1922,9 +1806,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -1934,9 +1818,9 @@ # i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -2171,6 +2055,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2857,8 +2742,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -3402,6 +3285,56 @@ ''' self.optimize_loop(ops, expected) + def test_arraycopy_dest_not_virtual(self): + ops = ''' + [] + p1 = new_array(3, descr=arraydescr) + p2 = new_array(3, descr=arraydescr) + setarrayitem_gc(p1, 2, 10, descr=arraydescr) + setarrayitem_gc(p2, 2, 13, descr=arraydescr) + escape(p2) + call(0, p1, p2, 0, 0, 3, descr=arraycopydescr) + escape(p2) + jump() + ''' + expected = ''' + [] + p2 = new_array(3, descr=arraydescr) + setarrayitem_gc(p2, 2, 13, descr=arraydescr) + escape(p2) + setarrayitem_gc(p2, 0, 0, descr=arraydescr) + setarrayitem_gc(p2, 1, 0, descr=arraydescr) + setarrayitem_gc(p2, 2, 10, descr=arraydescr) + escape(p2) + jump() + ''' + self.optimize_loop(ops, expected) + + def test_arraycopy_dest_not_virtual_too_long(self): + ops = ''' + [] + p1 = new_array(10, descr=arraydescr) + p2 = new_array(10, descr=arraydescr) + setarrayitem_gc(p1, 2, 10, descr=arraydescr) + setarrayitem_gc(p2, 2, 13, descr=arraydescr) + escape(p2) + call(0, p1, p2, 0, 0, 10, descr=arraycopydescr) + escape(p2) + jump() + ''' + expected = ''' + [] + p2 = new_array(10, descr=arraydescr) + setarrayitem_gc(p2, 2, 13, descr=arraydescr) + escape(p2) + p1 = new_array(10, descr=arraydescr) + setarrayitem_gc(p1, 2, 10, descr=arraydescr) + call(0, p1, p2, 0, 0, 10, descr=arraycopydescr) + escape(p2) + jump() + ''' + self.optimize_loop(ops, expected) + def test_bound_lt(self): ops = """ [i0] @@ -3899,7 +3832,7 @@ jump(i4, i10) """ self.optimize_loop(ops, expected) - + def test_add_sub_ovf(self): ops = """ [i1] @@ -3939,7 +3872,7 @@ [i0, i1] escape(i1) i2 = int_add_ovf(i0, 1) - guard_no_overflow() [] + guard_no_overflow() [] jump(i2, i0) """ self.optimize_loop(ops, expected) @@ -4420,7 +4353,6 @@ i8 = int_floordiv(4, i2) i9 = int_rshift(i1, 2) i10 = int_floordiv(i1, 0) - i11 = int_rshift(i1, 0) i12 = int_floordiv(i2, 2) i13 = int_floordiv(i2, 3) i14 = int_floordiv(i2, 4) @@ -4497,6 +4429,18 @@ """ self.optimize_loop(ops, expected) + def test_int_div_1(self): + ops = """ + [i0] + i1 = int_floordiv(i0, 1) + jump(i1) + """ + expected = """ + [i0] + jump(i0) + """ + self.optimize_loop(ops, expected) + def test_subsub_ovf(self): ops = """ [i0] @@ -5366,7 +5310,7 @@ """ self.optimize_strunicode_loop(ops, expected) - def test_strgetitem_small(self): + def test_strgetitem_bounds(self): ops = """ [p0, i0] i1 = strgetitem(p0, i0) @@ -5378,7 +5322,20 @@ """ expected = """ [p0, i0] - i1 = strgetitem(p0, i0) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_unicodegetitem_bounds(self): + ops = """ + [p0, i0] + i1 = unicodegetitem(p0, i0) + i2 = int_lt(i1, 0) + guard_false(i2) [] + jump(p0, i0) + """ + expected = """ + [p0, i0] jump(p0, i0) """ self.optimize_loop(ops, expected) @@ -5892,3 +5849,54 @@ jump(i3, i4) """ self.optimize_loop(ops, expected) + + def test_forced_virtual_pure_getfield(self): + ops = """ + [p0] + p1 = getfield_gc_pure(p0, descr=valuedescr) + jump(p1) + """ + self.optimize_loop(ops, ops) + + ops = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + p2 = getfield_gc_pure(p1, descr=valuedescr) + escape(p2) + jump(p0) + """ + expected = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + escape(p0) + jump(p0) + """ + self.optimize_loop(ops, expected) + + def test_setarrayitem_lazy(self): + ops = """ + [i0, i1] + p0 = escape() + i2 = escape() + p1 = new_with_vtable(ConstClass(node_vtable)) + setarrayitem_gc(p0, 2, p1, descr=arraydescr) + guard_true(i2) [] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + expected = """ + [i0, i1] + p0 = escape() + i2 = escape() + guard_true(i2) [p0] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py rename from pypy/jit/metainterp/test/test_optimizeutil.py rename to pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/test/test_optimizeutil.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -9,11 +9,15 @@ from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, Const, TreeLoop, BoxObj, ConstObj, AbstractDescr) -from pypy.jit.metainterp.optimizeutil import sort_descrs, InvalidLoop +from pypy.jit.metainterp.optimizeopt.util import sort_descrs, equaloplists +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter.heaptracker import register_known_gctype, adr2int -from pypy.jit.tool.oparser import parse +from pypy.jit.tool.oparser import parse, pure_parse from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr +from pypy.jit.metainterp import compile, resume, history +from pypy.jit.metainterp.jitprof import EmptyProfiler +from pypy.config.pypyoption import get_pypy_config def test_sort_descrs(): class PseudoDescr(AbstractDescr): @@ -28,6 +32,44 @@ sort_descrs(lst2) assert lst2 == lst +def test_equaloplists(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops, namespace=namespace) + loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), + namespace=namespace) + assert equaloplists(loop1.operations, loop2.operations) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + +def test_equaloplists_fail_args(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2, i1] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop2.operations)") + assert equaloplists(loop1.operations, loop2.operations, + strict_fail_args=False) + loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + # ____________________________________________________________ class LLtypeMixin(object): @@ -124,19 +166,19 @@ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [])) + EffectInfo([], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [])) + EffectInfo([], [], [adescr], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [arraydescr])) + EffectInfo([], [], [adescr], [arraydescr])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([adescr], [], [])) + EffectInfo([adescr], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([nextdescr], [], [], + EffectInfo([nextdescr], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), @@ -153,15 +195,15 @@ _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): @@ -256,8 +298,45 @@ ## u_vtable_adr: cpu.typedescrof(U)} ## namespace = locals() +# ____________________________________________________________ + + + +class Fake(object): + failargs_limit = 1000 + storedebug = None + + +class FakeMetaInterpStaticData(object): + + def __init__(self, cpu): + self.cpu = cpu + self.profiler = EmptyProfiler() + self.options = Fake() + self.globaldata = Fake() + self.config = get_pypy_config(translating=True) + self.config.translation.jit_ffi = True + + +class Storage(compile.ResumeGuardDescr): + "for tests." + def __init__(self, metainterp_sd=None, original_greenkey=None): + self.metainterp_sd = metainterp_sd + self.original_greenkey = original_greenkey + def store_final_boxes(self, op, boxes): + op.setfailargs(boxes) + def __eq__(self, other): + return type(self) is type(other) # xxx obscure + def clone_if_mutable(self): + res = Storage(self.metainterp_sd, self.original_greenkey) + self.copy_all_attributes_into(res) + return res + +def _sortboxes(boxes): + _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} + return sorted(boxes, key=lambda box: _kind2count[box.type]) + class BaseTest(object): - invent_fail_descr = None def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, @@ -265,5 +344,40 @@ boxkinds=boxkinds, invent_fail_descr=self.invent_fail_descr) + def invent_fail_descr(self, model, fail_args): + if fail_args is None: + return None + descr = Storage() + descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) + descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) + return descr + + def assert_equal(self, optimized, expected, text_right=None): + from pypy.jit.metainterp.optimizeopt.util import equaloplists + assert len(optimized.inputargs) == len(expected.inputargs) + remap = {} + for box1, box2 in zip(optimized.inputargs, expected.inputargs): + assert box1.__class__ == box2.__class__ + remap[box2] = box1 + assert equaloplists(optimized.operations, + expected.operations, False, remap, text_right) + + def _do_optimize_loop(self, loop, call_pure_results): + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 + from pypy.jit.metainterp.optimizeopt.util import args_dict + + self.loop = loop + loop.call_pure_results = args_dict() + if call_pure_results is not None: + for k, v in call_pure_results.items(): + loop.call_pure_results[list(k)] = v + metainterp_sd = FakeMetaInterpStaticData(self.cpu) + if hasattr(self, 'vrefinfo'): + metainterp_sd.virtualref_info = self.vrefinfo + if hasattr(self, 'callinfocollection'): + metainterp_sd.callinfocollection = self.callinfocollection + # + optimize_loop_1(metainterp_sd, loop, self.enable_opts) + # ____________________________________________________________ diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -5,7 +5,7 @@ from pypy.jit.metainterp.resume import Snapshot from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop, RetraceLoop +from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.history import make_hashable_int from pypy.jit.codewriter.effectinfo import EffectInfo @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False diff --git a/pypy/jit/metainterp/optimizeutil.py b/pypy/jit/metainterp/optimizeopt/util.py rename from pypy/jit/metainterp/optimizeutil.py rename to pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeutil.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -1,21 +1,10 @@ +import py from pypy.rlib.objectmodel import r_dict, compute_identity_hash from pypy.rlib.rarithmetic import intmask from pypy.rlib.unroll import unrolling_iterable from pypy.jit.metainterp import resoperation, history -from pypy.jit.metainterp.jitexc import JitException from pypy.rlib.debug import make_sure_not_resized - -class InvalidLoop(JitException): - """Raised when the optimize*.py detect that the loop that - we are trying to build cannot possibly make sense as a - long-running loop (e.g. it cannot run 2 complete iterations).""" - -class RetraceLoop(JitException): - """ Raised when inlining a short preamble resulted in an - InvalidLoop. This means the optimized loop is too specialized - to be useful here, so we trace it again and produced a second - copy specialized in some different way. - """ +from pypy.jit.metainterp.resoperation import rop # ____________________________________________________________ # Misc. utilities @@ -113,3 +102,49 @@ def args_dict_box(): return r_dict(args_eq, args_hash) + + +# ____________________________________________________________ + +def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}, + text_right=None): + # try to use the full width of the terminal to display the list + # unfortunately, does not work with the default capture method of py.test + # (which is fd), you you need to use either -s or --capture=sys, else you + # get the standard 80 columns width + totwidth = py.io.get_terminal_width() + width = totwidth / 2 - 1 + print ' Comparing lists '.center(totwidth, '-') + text_right = text_right or 'expected' + print '%s| %s' % ('optimized'.center(width), text_right.center(width)) + for op1, op2 in zip(oplist1, oplist2): + txt1 = str(op1) + txt2 = str(op2) + while txt1 or txt2: + print '%s| %s' % (txt1[:width].ljust(width), txt2[:width]) + txt1 = txt1[width:] + txt2 = txt2[width:] + assert op1.getopnum() == op2.getopnum() + assert op1.numargs() == op2.numargs() + for i in range(op1.numargs()): + x = op1.getarg(i) + y = op2.getarg(i) + assert x == remap.get(y, y) + if op2.result in remap: + assert op1.result == remap[op2.result] + else: + remap[op2.result] = op1.result + if op1.getopnum() != rop.JUMP: # xxx obscure + assert op1.getdescr() == op2.getdescr() + if op1.getfailargs() or op2.getfailargs(): + assert len(op1.getfailargs()) == len(op2.getfailargs()) + if strict_fail_args: + for x, y in zip(op1.getfailargs(), op2.getfailargs()): + assert x == remap.get(y, y) + else: + fail_args1 = set(op1.getfailargs()) + fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()]) + assert fail_args1 == fail_args2 + assert len(oplist1) == len(oplist2) + print '-'*totwidth + return True diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.history import Const, ConstInt, BoxInt from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs -from pypy.jit.metainterp.optimizeutil import descrlist_dict +from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.optimizeopt import optimizer from pypy.jit.metainterp.executor import execute @@ -20,6 +20,9 @@ self.source_op = source_op # the NEW_WITH_VTABLE/NEW_ARRAY operation # that builds this box + def is_forced_virtual(self): + return self.box is not None + def get_key_box(self): if self.box is None: return self.keybox @@ -120,7 +123,6 @@ op = ResOperation(rop.SETFIELD_GC, [box, subbox], None, descr=ofs) newoperations.append(op) - self._fields = None def _get_field_descr_list(self): _cached_sorted_fields = self._cached_sorted_fields @@ -330,18 +332,28 @@ vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox)) def optimize_VIRTUAL_REF_FINISH(self, op): - # Set the 'forced' field of the virtual_ref. - # In good cases, this is all virtual, so has no effect. - # Otherwise, this forces the real object -- but only now, as - # opposed to much earlier. This is important because the object is - # typically a PyPy PyFrame, and now is the end of its execution, so - # forcing it now does not have catastrophic effects. + # This operation is used in two cases. In normal cases, it + # is the end of the frame, and op.getarg(1) is NULL. In this + # case we just clear the vref.virtual_token, because it contains + # a stack frame address and we are about to leave the frame. + # In that case vref.forced should still be NULL, and remains + # NULL; and accessing the frame through the vref later is + # *forbidden* and will raise InvalidVirtualRef. + # + # In the other (uncommon) case, the operation is produced + # earlier, because the vref was forced during tracing already. + # In this case, op.getarg(1) is the virtual to force, and we + # have to store it in vref.forced. + # vrefinfo = self.optimizer.metainterp_sd.virtualref_info - # op.getarg(1) should really never point to null here + seo = self.optimizer.send_extra_operation + # - set 'forced' to point to the real object - seo = self.optimizer.send_extra_operation - seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None, - descr = vrefinfo.descr_forced)) + objbox = op.getarg(1) + if not self.optimizer.cpu.ts.CONST_NULL.same_constant(objbox): + seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None, + descr = vrefinfo.descr_forced)) + # - set 'virtual_token' to TOKEN_NONE args = [op.getarg(0), ConstInt(vrefinfo.TOKEN_NONE)] seo(ResOperation(rop.SETFIELD_GC, args, None, @@ -355,6 +367,14 @@ def optimize_GETFIELD_GC(self, op): value = self.getvalue(op.getarg(0)) + # If this is an immutable field (as indicated by op.is_always_pure()) + # then it's safe to reuse the virtual's field, even if it has been + # forced, because it should never be written to again. + if value.is_forced_virtual() and op.is_always_pure(): + fieldvalue = value.getfield(op.getdescr(), None) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return if value.is_virtual(): assert isinstance(value, AbstractVirtualValue) fieldvalue = value.getfield(op.getdescr(), None) @@ -372,6 +392,7 @@ def optimize_SETFIELD_GC(self, op): value = self.getvalue(op.getarg(0)) + if value.is_virtual(): fieldvalue = self.getvalue(op.getarg(1)) value.setfield(op.getdescr(), fieldvalue) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1,10 +1,10 @@ -import py, os, sys -from pypy.rpython.lltypesystem import lltype, llmemory, rclass +import py, sys +from pypy.rpython.lltypesystem import lltype, rclass from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib.debug import make_sure_not_resized -from pypy.rlib import nonconst +from pypy.rlib import nonconst, rstack from pypy.jit.metainterp import history, compile, resume from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat @@ -15,13 +15,13 @@ from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE, \ - ABORT_BAD_LOOP, ABORT_FORCE_QUASIIMMUT + ABORT_FORCE_QUASIIMMUT from pypy.jit.metainterp.jitexc import JitException, get_llexception -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize -from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr, MissingLiveness -from pypy.jit.codewriter import heaptracker, longlong -from pypy.jit.metainterp.optimizeutil import RetraceLoop, args_dict_box, args_dict +from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr +from pypy.jit.codewriter import heaptracker +from pypy.jit.metainterp.optimizeopt.util import args_dict_box +from pypy.jit.metainterp.optimize import RetraceLoop # ____________________________________________________________ @@ -867,8 +867,7 @@ any_operation = len(self.metainterp.history.operations) > 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - # xxx we may disable the following line in some context later - self.debug_merge_point(jitdriver_sd, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -915,13 +914,12 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jitdriver_sd, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation loc = jitdriver_sd.warmstate.get_location_str(greenkey) debug_print(loc) - constloc = self.metainterp.cpu.ts.conststr(loc) - self.metainterp.history.record(rop.DEBUG_MERGE_POINT, - [constloc, ConstInt(in_recursion)], None) + args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey + self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @arguments("box", "label") def opimpl_goto_if_exception_mismatch(self, vtablebox, next_exc_target): @@ -1049,8 +1047,10 @@ vrefinfo = metainterp.staticdata.virtualref_info vref = vrefbox.getref_base() if vrefinfo.is_virtual_ref(vref): + # XXX write a comment about nullbox + nullbox = self.metainterp.cpu.ts.CONST_NULL metainterp.history.record(rop.VIRTUAL_REF_FINISH, - [vrefbox, lastbox], None) + [vrefbox, nullbox], None) @arguments() def opimpl_ll_read_timestamp(self): @@ -1233,7 +1233,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: @@ -1264,8 +1264,7 @@ logger_ops = None def __init__(self, cpu, options, - ProfilerClass=EmptyProfiler, warmrunnerdesc=None, - jit_ffi=True): + ProfilerClass=EmptyProfiler, warmrunnerdesc=None): self.cpu = cpu self.stats = self.cpu.stats self.options = options @@ -1275,7 +1274,11 @@ self.profiler = ProfilerClass() self.profiler.cpu = cpu self.warmrunnerdesc = warmrunnerdesc - self.jit_ffi = jit_ffi + if warmrunnerdesc: + self.config = warmrunnerdesc.translator.config + else: + from pypy.config.pypyoption import get_pypy_config + self.config = get_pypy_config(translating=True) backendmodule = self.cpu.__module__ backendmodule = backendmodule.split('.')[-2] @@ -1926,7 +1929,6 @@ self.history.inputargs = original_inputargs self.history.operations.pop() # remove the JUMP - # FIXME: Why is self.history.inputargs not restored? def compile_bridge(self, live_arg_boxes): num_green_args = self.jitdriver_sd.num_green_args @@ -1962,6 +1964,8 @@ start_resumedescr, False) self.history.operations.pop() # remove the JUMP if loop_token is None: + self.history.inputargs = original_inputargs + self.history.operations = original_operations return if loop_token.short_preamble: @@ -2052,10 +2056,16 @@ def initialize_state_from_guard_failure(self, resumedescr): # guard failure: rebuild a complete MIFrame stack - self.in_recursion = -1 # always one portal around - self.history = history.History() - inputargs_and_holes = self.rebuild_state_after_failure(resumedescr) - self.history.inputargs = [box for box in inputargs_and_holes if box] + # This is stack-critical code: it must not be interrupted by StackOverflow, + # otherwise the jit_virtual_refs are left in a dangling state. + rstack._stack_criticalcode_start() + try: + self.in_recursion = -1 # always one portal around + self.history = history.History() + inputargs_and_holes = self.rebuild_state_after_failure(resumedescr) + self.history.inputargs = [box for box in inputargs_and_holes if box] + finally: + rstack._stack_criticalcode_stop() def initialize_virtualizable(self, original_boxes): vinfo = self.jitdriver_sd.virtualizable_info @@ -2110,7 +2120,6 @@ def vrefs_after_residual_call(self): vrefinfo = self.staticdata.virtualref_info for i in range(0, len(self.virtualref_boxes), 2): - virtualbox = self.virtualref_boxes[i] vrefbox = self.virtualref_boxes[i+1] vref = vrefbox.getref_base() if vrefinfo.tracing_after_residual_call(vref): diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -191,9 +191,15 @@ # of the operation. It must inherit from AbstractDescr. The # backend provides it with cpu.fielddescrof(), cpu.arraydescrof(), # cpu.calldescrof(), and cpu.typedescrof(). + self._check_descr(descr) + self._descr = descr + + def _check_descr(self, descr): + if not we_are_translated() and getattr(descr, 'I_am_a_descr', False): + return # needed for the mock case in oparser_model from pypy.jit.metainterp.history import check_descr check_descr(descr) - self._descr = descr + class GuardResOp(ResOpWithDescr): @@ -471,8 +477,9 @@ 'STRSETITEM/3', 'UNICODESETITEM/3', #'RUNTIMENEW/1', # ootype operation - 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier) - 'DEBUG_MERGE_POINT/2', # debugging only + 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier) + 'COND_CALL_GC_WB_ARRAY/3d', # [objptr, arrayindex, newvalue] (write barr.) + 'DEBUG_MERGE_POINT/*', # debugging only 'JIT_DEBUG/*', # debugging only 'VIRTUAL_REF_FINISH/2', # removed before it's passed to the backend 'COPYSTRCONTENT/5', # src, dst, srcstart, dststart, length @@ -485,6 +492,7 @@ 'CALL_ASSEMBLER/*d', # call already compiled assembler 'CALL_MAY_FORCE/*d', 'CALL_LOOPINVARIANT/*d', + 'CALL_RELEASE_GIL/*d', # release the GIL and "close the stack" for asmgcc #'OOSEND', # ootype operation #'OOSEND_PURE', # ootype operation 'CALL_PURE/*d', # removed before it's passed to the backend diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -2,15 +2,17 @@ from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr -from pypy.rlib import rarithmetic +from pypy.rpython import annlowlevel +from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop # Logic to encode the chain of frames and the state of the boxes at a # guard operation, and to decode it again. This is a bit advanced, @@ -82,6 +84,13 @@ ('nums', lltype.Array(rffi.SHORT))) NUMBERINGP.TO.become(NUMBERING) +PENDINGFIELDSTRUCT = lltype.Struct('PendingField', + ('lldescr', annlowlevel.base_ptr_lltype()), + ('num', rffi.SHORT), + ('fieldnum', rffi.SHORT), + ('itemindex', rffi.INT)) +PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) + TAGMASK = 3 def tag(value, tagbits): @@ -329,7 +338,7 @@ value = values[box] value.get_args_for_fail(self) - for _, box, fieldbox in pending_setfields: + for _, box, fieldbox, _ in pending_setfields: self.register_box(box) self.register_box(fieldbox) value = values[fieldbox] @@ -405,13 +414,25 @@ return False def _add_pending_fields(self, pending_setfields): - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) if pending_setfields: - rd_pendingfields = [] - for descr, box, fieldbox in pending_setfields: + n = len(pending_setfields) + rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) + for i in range(n): + descr, box, fieldbox, itemindex = pending_setfields[i] + lldescr = annlowlevel.cast_instance_to_base_ptr(descr) num = self._gettagged(box) fieldnum = self._gettagged(fieldbox) - rd_pendingfields.append((descr, num, fieldnum)) + # the index is limited to 2147483647 (64-bit machines only) + if itemindex > 2147483647: + from pypy.jit.metainterp import compile + compile.giveup() + itemindex = rffi.cast(rffi.INT, itemindex) + # + rd_pendingfields[i].lldescr = lldescr + rd_pendingfields[i].num = num + rd_pendingfields[i].fieldnum = fieldnum + rd_pendingfields[i].itemindex= itemindex self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): @@ -727,10 +748,28 @@ self.virtuals_cache = [self.virtual_default] * len(virtuals) def _prepare_pendingfields(self, pendingfields): - if pendingfields is not None: - for descr, num, fieldnum in pendingfields: + if pendingfields: + for i in range(len(pendingfields)): + lldescr = pendingfields[i].lldescr + num = pendingfields[i].num + fieldnum = pendingfields[i].fieldnum + itemindex= pendingfields[i].itemindex + descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, + lldescr) struct = self.decode_ref(num) - self.setfield(descr, struct, fieldnum) + itemindex = rffi.cast(lltype.Signed, itemindex) + if itemindex < 0: + self.setfield(descr, struct, fieldnum) + else: + self.setarrayitem(descr, struct, itemindex, fieldnum) + + def setarrayitem(self, arraydescr, array, index, fieldnum): + if arraydescr.is_array_of_pointers(): + self.setarrayitem_ref(arraydescr, array, index, fieldnum) + elif arraydescr.is_array_of_floats(): + self.setarrayitem_float(arraydescr, array, index, fieldnum) + else: + self.setarrayitem_int(arraydescr, array, index, fieldnum) def _prepare_next_section(self, info): # Use info.enumerate_vars(), normally dispatching to @@ -903,15 +942,15 @@ structbox, fieldbox) def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, INT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT) def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, REF) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF) def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) - def setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): + def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): itembox = self.decode_box(fieldnum, kind) self.metainterp.execute_and_record(rop.SETARRAYITEM_GC, arraydescr, arraybox, @@ -978,12 +1017,18 @@ def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage, all_virtuals=None): - resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd, - storage, all_virtuals) - vinfo = jitdriver_sd.virtualizable_info - ginfo = jitdriver_sd.greenfield_info - vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info - resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo) + # The initialization is stack-critical code: it must not be interrupted by + # StackOverflow, otherwise the jit_virtual_refs are left in a dangling state. + rstack._stack_criticalcode_start() + try: + resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd, + storage, all_virtuals) + vinfo = jitdriver_sd.virtualizable_info + ginfo = jitdriver_sd.greenfield_info + vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info + resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo) + finally: + rstack._stack_criticalcode_stop() # # First get a chain of blackhole interpreters whose length is given # by the depth of rd_frame_info_list. The first one we get must be diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -15,17 +15,24 @@ supports_longlong=False, **kwds): from pypy.jit.codewriter import support - class FakeJitCell: + class FakeJitCell(object): __compiled_merge_points = [] def get_compiled_merge_points(self): return self.__compiled_merge_points[:] def set_compiled_merge_points(self, lst): self.__compiled_merge_points = lst - class FakeWarmRunnerState: + class FakeWarmRunnerState(object): def attach_unoptimized_bridge_from_interp(self, greenkey, newloop): pass + def helper_func(self, FUNCPTR, func): + from pypy.rpython.annlowlevel import llhelper + return llhelper(FUNCPTR, func) + + def get_location_str(self, args): + return 'location' + def jit_cell_at_key(self, greenkey): assert greenkey == [] return self._cell @@ -37,6 +44,7 @@ func._jit_unroll_safe_ = True rtyper = support.annotate(func, values, type_system=type_system) graphs = rtyper.annotator.translator.graphs + testself.all_graphs = graphs result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0] class FakeJitDriverSD: @@ -46,6 +54,8 @@ greenfield_info = None result_type = result_kind portal_runner_ptr = "???" + on_compile = lambda *args: None + on_compile_bridge = lambda *args: None stats = history.Stats() cpu = CPUClass(rtyper, stats, None, False) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -500,7 +500,7 @@ y -= x return y # - res = self.meta_interp(f, [3, 6], repeat=7) + res = self.meta_interp(f, [3, 6], repeat=7, function_threshold=0) assert res == 6 - 4 - 5 self.check_history(call=0) # because the trace starts in the middle # @@ -1252,7 +1252,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1312,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1343,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1496,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1531,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1595,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1677,6 +1677,8 @@ res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) self.check_loop_count(9) + self.check_loops(getarrayitem_gc=8, everywhere=True) + py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) def test_multiple_specialied_versions_bridge(self): @@ -1815,7 +1817,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2000,7 +2002,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2045,7 +2047,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2080,7 +2082,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2137,7 +2139,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2206,7 +2208,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2230,6 +2233,87 @@ self.check_loops(getfield_gc_pure=0) self.check_loops(getfield_gc_pure=2, everywhere=True) + def test_frame_finished_during_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 1 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 1000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'a']) + def f(): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 2) + a = A(0) + sa = 0 + while a.val < 8: + myjitdriver.jit_merge_point(a=a, sa=sa) + a = a.inc() + if a.val > 4: + a = B(a.val) + sa += a.num + return sa + res = self.meta_interp(f, []) + assert res == f() + + def test_frame_finished_during_continued_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 100 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 10000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'b', 'a']) + def f(b): + myjitdriver.set_param('threshold', 6) + myjitdriver.set_param('trace_eagerness', 4) + a = A(0) + sa = 0 + while a.val < 15: + myjitdriver.jit_merge_point(a=a, b=b, sa=sa) + a = a.inc() + if a.val > 8: + a = B(a.val) + if b == 1: + b = 2 + else: + b = 1 + sa += a.num + b + return sa + res = self.meta_interp(f, [1]) + assert res == f(1) + + def test_remove_array_operations(self): + myjitdriver = JitDriver(greens = [], reds = ['a']) + class W_Int: + def __init__(self, intvalue): + self.intvalue = intvalue + def f(x): + a = [W_Int(x)] + while a[0].intvalue > 0: + myjitdriver.jit_merge_point(a=a) + a[0] = W_Int(a[0].intvalue - 3) + return a[0].intvalue + res = self.meta_interp(f, [100]) + assert res == -2 + #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py --- a/pypy/jit/metainterp/test/test_compile.py +++ b/pypy/jit/metainterp/test/test_compile.py @@ -1,3 +1,4 @@ +from pypy.config.pypyoption import get_pypy_config from pypy.jit.metainterp.history import LoopToken, ConstInt, History, Stats from pypy.jit.metainterp.history import BoxInt, INT from pypy.jit.metainterp.compile import insert_loop_token, compile_new_loop @@ -5,7 +6,7 @@ from pypy.jit.metainterp.compile import ResumeGuardCountersInt from pypy.jit.metainterp.compile import compile_tmp_callback from pypy.jit.metainterp import jitprof, typesystem, compile -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.tool.oparser import parse from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT @@ -30,13 +31,16 @@ ts = typesystem.llhelper def __init__(self): self.seen = [] - def compile_loop(self, inputargs, operations, token): + def compile_loop(self, inputargs, operations, token, name=''): self.seen.append((inputargs, operations, token)) class FakeLogger(object): def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): pass + def repr_of_resop(self, op): + return repr(op) + class FakeState(object): enable_opts = ALL_OPTS_DICT.copy() enable_opts.pop('unroll') @@ -44,6 +48,9 @@ def attach_unoptimized_bridge_from_interp(*args): pass + def get_location_str(self, args): + return 'location' + class FakeGlobalData(object): loopnumbering = 0 @@ -51,11 +58,11 @@ logger_noopt = FakeLogger() logger_ops = FakeLogger() + config = get_pypy_config(translating=True) stats = Stats() profiler = jitprof.EmptyProfiler() warmrunnerdesc = None - jit_ffi = False def log(self, msg, event_kind=None): pass @@ -63,6 +70,8 @@ call_pure_results = {} class jitdriver_sd: warmstate = FakeState() + on_compile = staticmethod(lambda *args: None) + on_compile_bridge = staticmethod(lambda *args: None) def test_compile_new_loop(): cpu = FakeCPU() diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -130,6 +130,38 @@ assert res == 50 self.check_loops(int_mod=1) + def test_repeated_lookup(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'd']) + class Wrapper(object): + _immutable_fields_ = ["value"] + def __init__(self, value): + self.value = value + def eq_func(a, b): + return a.value == b.value + def hash_func(x): + return objectmodel.compute_hash(x.value) + + def f(n): + d = None + while n > 0: + myjitdriver.jit_merge_point(n=n, d=d) + d = objectmodel.r_dict(eq_func, hash_func) + y = Wrapper(str(n)) + d[y] = n - 1 + n = d[y] + return d[Wrapper(str(n + 1))] + + res = self.meta_interp(f, [100], listops=True) + assert res == f(50) + # XXX: ideally there would be 7 calls here, but repeated CALL_PURE with + # the same arguments are not folded, because we have conflicting + # definitions of pure, once strhash can be appropriately folded + # this should be decreased to seven. + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + "guard_true": 1, "int_and": 1, "int_gt": 1, + "int_is_true": 1, "int_sub": 1, "jump": 1, + "new_with_vtable": 1, "setfield_gc": 1}) + class TestOOtype(DictTests, OOJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,28 +1,46 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.libffi import ArgChain +from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong +from pypy.rlib.libffi import IS_32_BIT from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall from pypy.rpython.lltypesystem import lltype, rffi +from pypy.rlib.objectmodel import specialize +from pypy.tool.sourcetools import func_with_new_name from pypy.jit.metainterp.test.support import LLJitMixin - class TestFfiCall(LLJitMixin, _TestLibffiCall): # ===> ../../../rlib/test/test_libffi.py - def call(self, funcspec, args, RESULT, init_result=0): + def call(self, funcspec, args, RESULT, init_result=0, is_struct=False): """ Call the function specified by funcspec in a loop, and let the jit to see and optimize it. """ # lib, name, argtypes, restype = funcspec - args = unrolling_iterable(args) + method_and_args = [] + for argval in args: + if type(argval) is r_singlefloat: + method_name = 'arg_singlefloat' + argval = float(argval) + elif IS_32_BIT and type(argval) in [r_longlong, r_ulonglong]: + method_name = 'arg_longlong' + argval = rffi.cast(rffi.LONGLONG, argval) + argval = longlong2float(argval) + elif isinstance(argval, tuple): + method_name, argval = argval + else: + method_name = 'arg' + method_and_args.append((method_name, argval)) + method_and_args = unrolling_iterable(method_and_args) # reds = ['n', 'res', 'func'] - if type(init_result) is float: + if (RESULT in [rffi.FLOAT, rffi.DOUBLE] or + IS_32_BIT and RESULT in [rffi.LONGLONG, rffi.ULONGLONG]): reds = ['n', 'func', 'res'] # floats must be *after* refs driver = JitDriver(reds=reds, greens=[]) # @@ -31,15 +49,19 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() - for argval in args: # this loop is unrolled - argchain.arg(argval) - res = func.call(argchain, RESULT) + # this loop is unrolled + for method_name, argval in method_and_args: + getattr(argchain, method_name)(argval) + res = func.call(argchain, RESULT, is_struct=is_struct) n += 1 return res # - res = self.meta_interp(f, [0]) + res = self.meta_interp(f, [0], backendopt=True) return res + def test_byval_result(self): + _TestLibffiCall.test_byval_result(self) + test_byval_result.__doc__ = _TestLibffiCall.test_byval_result.__doc__ + test_byval_result.dont_track_allocations = True diff --git a/pypy/jit/metainterp/test/test_history.py b/pypy/jit/metainterp/test/test_history.py --- a/pypy/jit/metainterp/test/test_history.py +++ b/pypy/jit/metainterp/test/test_history.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.history import * -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi def test_repr(): @@ -10,6 +10,18 @@ const = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)) assert const._getrepr_() == "*T" +def test_repr_ll2ctypes(): + ptr = lltype.malloc(rffi.VOIDPP.TO, 10, flavor='raw') + # force it to be a ll2ctypes object + ptr = rffi.cast(rffi.VOIDPP, rffi.cast(rffi.LONG, ptr)) + adr = llmemory.cast_ptr_to_adr(ptr) + lltype.free(ptr, flavor='raw') + intval = llmemory.cast_adr_to_int(adr, 'symbolic') + box = BoxInt(intval) + s = box.repr_rpython() + assert s.startswith('12345/') # the arbitrary hash value used by + # make_hashable_int + def test_same_constant(): c1a = ConstInt(0) c1b = ConstInt(0) diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py --- a/pypy/jit/metainterp/test/test_jitdriver.py +++ b/pypy/jit/metainterp/test/test_jitdriver.py @@ -10,8 +10,59 @@ def getloc2(g): return "in jitdriver2, with g=%d" % g +class JitDriverTests(object): + def test_on_compile(self): + called = {} + + class MyJitDriver(JitDriver): + def on_compile(self, logger, looptoken, operations, type, n, m): + called[(m, n, type)] = looptoken -class MultipleJitDriversTests: + driver = MyJitDriver(greens = ['n', 'm'], reds = ['i']) + + def loop(n, m): + i = 0 + while i < n + m: + driver.can_enter_jit(n=n, m=m, i=i) + driver.jit_merge_point(n=n, m=m, i=i) + i += 1 + + self.meta_interp(loop, [1, 4]) + assert sorted(called.keys()) == [(4, 1, "entry bridge"), (4, 1, "loop")] + self.meta_interp(loop, [2, 4]) + assert sorted(called.keys()) == [(4, 1, "entry bridge"), (4, 1, "loop"), + (4, 2, "entry bridge"), (4, 2, "loop")] + + def test_on_compile_bridge(self): + called = {} + + class MyJitDriver(JitDriver): + def on_compile(self, logger, looptoken, operations, type, n, m): + called[(m, n, type)] = loop + def on_compile_bridge(self, logger, orig_token, operations, n): + assert 'bridge' not in called + called['bridge'] = orig_token + + driver = MyJitDriver(greens = ['n', 'm'], reds = ['i']) + + def loop(n, m): + i = 0 + while i < n + m: + driver.can_enter_jit(n=n, m=m, i=i) + driver.jit_merge_point(n=n, m=m, i=i) + if i >= 4: + i += 2 + i += 1 + + self.meta_interp(loop, [1, 10]) + assert sorted(called.keys()) == ['bridge', (10, 1, "entry bridge"), + (10, 1, "loop")] + + +class TestLLtypeSingle(JitDriverTests, LLJitMixin): + pass + +class MultipleJitDriversTests(object): def test_simple(self): myjitdriver1 = JitDriver(greens=[], reds=['n', 'm'], @@ -62,6 +113,7 @@ return n # def loop2(g, r): + myjitdriver1.set_param('function_threshold', 0) while r > 0: myjitdriver2.can_enter_jit(g=g, r=r) myjitdriver2.jit_merge_point(g=g, r=r) diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -49,7 +49,7 @@ x = l[n] l = [3] * 100 l[3] = x - l[3] = x + 1 + l[4] = x + 1 n -= 1 return l[0] @@ -236,4 +236,8 @@ return a * b res = self.meta_interp(f, [37]) assert res == f(37) - self.check_loops(getfield_gc=1, everywhere=True) + # There is the one actual field on a, plus 2 getfield's from the list + # itself, 1 to get the length (which is then incremented and passed to + # the resize func), and then a read of the items field to actually + # perform the setarrayitem on + self.check_loops(getfield_gc=5, everywhere=True) diff --git a/pypy/jit/metainterp/test/test_logger.py b/pypy/jit/metainterp/test/test_logger.py --- a/pypy/jit/metainterp/test/test_logger.py +++ b/pypy/jit/metainterp/test/test_logger.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp import logger from pypy.jit.metainterp.typesystem import llhelper from StringIO import StringIO -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.metainterp.history import AbstractDescr, LoopToken, BasicFailDescr from pypy.jit.backend.model import AbstractCPU @@ -36,19 +36,29 @@ return capturing(logger.Logger.log_loop, self, loop.inputargs, loop.operations, ops_offset=ops_offset) - def repr_of_descr(self, descr): - for k, v in self.namespace.items(): - if v == descr: - return k - return descr.repr_of_descr() + def _make_log_operations(self1): + class LogOperations(logger.LogOperations): + def repr_of_descr(self, descr): + for k, v in self1.namespace.items(): + if v == descr: + return k + return descr.repr_of_descr() + logops = LogOperations(self1.metainterp_sd, self1.guard_number) + self1.logops = logops + return logops class TestLogger(object): ts = llhelper def make_metainterp_sd(self): + class FakeJitDriver(object): + class warmstate(object): + get_location_str = staticmethod(lambda args: "dupa") + class FakeMetaInterpSd: cpu = AbstractCPU() cpu.ts = self.ts + jitdrivers_sd = [FakeJitDriver()] def get_name_from_address(self, addr): return 'Name' return FakeMetaInterpSd() @@ -66,7 +76,7 @@ if check_equal: equaloplists(loop.operations, oloop.operations) assert oloop.inputargs == loop.inputargs - return loop, oloop + return logger, loop, oloop def test_simple(self): inp = ''' @@ -106,18 +116,18 @@ def test_debug_merge_point(self): inp = ''' [] - debug_merge_point("info", 0) + debug_merge_point(0, 0) ''' - loop, oloop = self.reparse(inp, check_equal=False) - assert loop.operations[0].getarg(0)._get_str() == 'info' - assert oloop.operations[0].getarg(0)._get_str() == 'info' + _, loop, oloop = self.reparse(inp, check_equal=False) + assert loop.operations[0].getarg(1).getint() == 0 + assert oloop.operations[0].getarg(1)._get_str() == "dupa" def test_floats(self): inp = ''' [f0] f1 = float_add(3.5, f0) ''' - loop, oloop = self.reparse(inp) + _, loop, oloop = self.reparse(inp) equaloplists(loop.operations, oloop.operations) def test_jump(self): @@ -179,6 +189,17 @@ assert output.splitlines()[0] == "# bridge out of Guard 3 with 0 ops" pure_parse(output) + def test_repr_single_op(self): + inp = ''' + [i0, i1, i2, p3, p4, p5] + i6 = int_add(i1, i2) + i8 = int_add(i6, 3) + jump(i0, i8, i6, p3, p4, p5) + ''' + logger, loop, _ = self.reparse(inp) + op = loop.operations[1] + assert logger.logops.repr_of_resop(op) == "i8 = int_add(i6, 3)" + def test_ops_offset(self): inp = ''' [i0] diff --git a/pypy/jit/metainterp/test/test_pyjitpl.py b/pypy/jit/metainterp/test/test_pyjitpl.py --- a/pypy/jit/metainterp/test/test_pyjitpl.py +++ b/pypy/jit/metainterp/test/test_pyjitpl.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.history import BoxInt, ConstInt from pypy.jit.metainterp.history import History from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.codewriter.jitcode import JitCode diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -483,6 +483,7 @@ def main(inline): myjitdriver.set_param("threshold", 10) + myjitdriver.set_param('function_threshold', 60) if inline: myjitdriver.set_param('inlining', True) else: @@ -925,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 @@ -1193,6 +1194,51 @@ i -= 1 self.meta_interp(portal, [0, 10], inline=True) + def test_trace_from_start_always(self): + from pypy.rlib.nonconst import NonConstant + + driver = JitDriver(greens = ['c'], reds = ['i', 'v']) + + def portal(c, i, v): + while i > 0: + driver.jit_merge_point(c=c, i=i, v=v) + portal(c, i - 1, v) + if v: + driver.can_enter_jit(c=c, i=i, v=v) + break + + def main(c, i, set_param, v): + if set_param: + driver.set_param('function_threshold', 0) + portal(c, i, v) + + self.meta_interp(main, [10, 10, False, False], inline=True) + self.check_tree_loop_count(1) + self.check_loop_count(0) + self.meta_interp(main, [3, 10, True, False], inline=True) + self.check_tree_loop_count(0) + self.check_loop_count(0) + + def test_trace_from_start_does_not_prevent_inlining(self): + driver = JitDriver(greens = ['c', 'bc'], reds = ['i']) + + def portal(bc, c, i): + while True: + driver.jit_merge_point(c=c, bc=bc, i=i) + if bc == 0: + portal(1, 8, 0) + c += 1 + else: + return + if c == 10: # bc == 0 + c = 0 + if i >= 100: + return + driver.can_enter_jit(c=c, bc=bc, i=i) + i += 1 + + self.meta_interp(portal, [0, 0, 0], inline=True) + self.check_loops(call=0, call_may_force=0) class TestLLtype(RecursiveTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py --- a/pypy/jit/metainterp/test/test_resume.py +++ b/pypy/jit/metainterp/test/test_resume.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.resume import * from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt from pypy.jit.metainterp.history import ConstPtr, ConstFloat -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.metainterp import executor from pypy.jit.codewriter import heaptracker, longlong @@ -1238,7 +1238,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, values, 0) assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)]) + modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s, -1)]) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume @@ -1259,6 +1259,106 @@ assert len(expected) == len(trace) assert demo55.next == demo66 +def test_virtual_adder_pending_fields_and_arrayitems(): + class Storage(object): + pass + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier._add_pending_fields([]) + assert not storage.rd_pendingfields + # + class FieldDescr(object): + pass + field_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061)} + modifier._add_pending_fields([(field_a, 42, 61, -1)]) + pf = storage.rd_pendingfields + assert len(pf) == 1 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is field_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + # + array_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061), + 62: rffi.cast(rffi.SHORT, 1062), + 63: rffi.cast(rffi.SHORT, 1063)} + modifier._add_pending_fields([(array_a, 42, 61, 0), + (array_a, 42, 62, 2147483647)]) + pf = storage.rd_pendingfields + assert len(pf) == 2 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[1].num) == 1042 + assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 + assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + # + from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole + py.test.raises(SwitchToBlackhole, modifier._add_pending_fields, + [(array_a, 42, 63, 2147483648)]) + +def test_resume_reader_fields_and_arrayitems(): + class ResumeReader(AbstractResumeDataReader): + def __init__(self, got=None, got_array=None): + self.got = got + self.got_array = got_array + def setfield(self, descr, struct, fieldnum): + assert lltype.typeOf(struct) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got.append((descr, struct, fieldnum)) + def setarrayitem(self, arraydescr, array, index, fieldnum): + assert lltype.typeOf(array) is lltype.Signed + assert lltype.typeOf(index) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got_array.append((arraydescr, array, index, fieldnum)) + def decode_ref(self, num): + return rffi.cast(lltype.Signed, num) * 100 + got = [] + pf = lltype.nullptr(PENDINGFIELDSP.TO) + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [] + # + class FieldDescr(AbstractDescr): + pass + field_a = FieldDescr() + field_b = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 2) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) + pf[0].itemindex = rffi.cast(rffi.INT, -1) + pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) + pf[1].num = rffi.cast(rffi.SHORT, 2042) + pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) + pf[1].itemindex = rffi.cast(rffi.INT, -1) + got = [] + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] + # + array_a = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 1) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) + pf[0].itemindex = rffi.cast(rffi.INT, 123) + got_array = [] + ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + assert got_array == [(array_a, 104200, 123, 1063)] + def test_invalidation_needed(): class options: diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_tl.py b/pypy/jit/metainterp/test/test_tl.py --- a/pypy/jit/metainterp/test/test_tl.py +++ b/pypy/jit/metainterp/test/test_tl.py @@ -58,7 +58,7 @@ exit: RETURN ''') - + codes = [code, code2] def main(n, inputarg): code = codes[n] @@ -116,7 +116,7 @@ codes = [code, ''] def main(num, arg): return interp(codes[num], inputarg=arg) - + res = self.meta_interp(main, [0, 20], enable_opts='', listops=listops, backendopt=True, policy=policy) assert res == 0 @@ -128,7 +128,6 @@ from pypy.jit.tl.tl import Stack methods = [Stack.put, Stack.pick, - Stack.roll, Stack.append, Stack.pop] for meth in methods: diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,13 +5,13 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor from pypy.jit.metainterp.warmspot import get_stats, get_translator from pypy.jit.metainterp import history -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin def promote_virtualizable(*args): pass @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py --- a/pypy/jit/metainterp/test/test_virtualref.py +++ b/pypy/jit/metainterp/test/test_virtualref.py @@ -1,9 +1,10 @@ import py from pypy.rpython.lltypesystem import lltype, llmemory, lloperation +from pypy.rpython.llinterp import LLException from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None -from pypy.rlib.jit import virtual_ref, virtual_ref_finish +from pypy.rlib.jit import virtual_ref, virtual_ref_finish, InvalidVirtualRef from pypy.rlib.objectmodel import compute_unique_id -from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, _get_jitcodes from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.virtualref import VirtualRefInfo @@ -16,6 +17,29 @@ self.vrefinfo = VirtualRefInfo(self.warmrunnerstate) self.cw.setup_vrefinfo(self.vrefinfo) + def test_rewrite_graphs(self): + class X: + pass + def fn(): + x = X() + vref = virtual_ref(x) + x1 = vref() # jit_force_virtual + virtual_ref_finish(vref, x) + # + _get_jitcodes(self, self.CPUClass, fn, [], self.type_system) + graph = self.all_graphs[0] + assert graph.name == 'fn' + self.vrefinfo.replace_force_virtual_with_call([graph]) + # + def check_call(op, fname): + assert op.opname == 'direct_call' + assert op.args[0].value._obj._name == fname + # + ops = [op for block, op in graph.iterblockops()] + check_call(ops[-3], 'virtual_ref') + check_call(ops[-2], 'force_virtual_if_necessary') + check_call(ops[-1], 'virtual_ref_finish') + def test_make_vref_simple(self): class X: pass @@ -25,9 +49,9 @@ # def f(): x = X() - exctx.topframeref = virtual_ref(x) + exctx.topframeref = vref = virtual_ref(x) exctx.topframeref = vref_None - virtual_ref_finish(x) + virtual_ref_finish(vref, x) return 1 # self.interp_operations(f, []) @@ -60,8 +84,9 @@ exctx._frame = x exctx.topframeref = virtual_ref(x) def leave(): + vref = exctx.topframeref exctx.topframeref = vref_None - virtual_ref_finish(exctx._frame) + virtual_ref_finish(vref, exctx._frame) def f(n): enter(n) n = external(n) @@ -125,7 +150,8 @@ # @dont_look_inside def g(vref): - debug_print(lltype.Void, '-+-+-+-+- external read:', vref().n) + # we cannot do anything with the vref after the call to finish() + pass # def f(n): while n > 0: @@ -136,7 +162,7 @@ exctx.topframeref = vref = virtual_ref(x) # here, 'x' should be virtual exctx.topframeref = vref_None - virtual_ref_finish(x) + virtual_ref_finish(vref, x) # 'x' and 'vref' can randomly escape after the call to # finish(). g(vref) @@ -144,7 +170,7 @@ return 1 # self.meta_interp(f, [10]) - self.check_loops(new_with_vtable=2) # the vref and the X + self.check_loops(new_with_vtable=1) # the vref self.check_aborted_count(0) def test_simple_all_removed(self): @@ -169,13 +195,13 @@ xy.next1 = lltype.malloc(A, 0) xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) n -= externalfn(n) exctx.topframeref = vref_None xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) # self.meta_interp(f, [15]) self.check_loops(new_with_vtable=0, # all virtualized @@ -206,17 +232,17 @@ xy.next1 = lltype.malloc(A, 0) xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) n -= externalfn(n) exctx.topframeref = vref_None xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) # self.meta_interp(f, [15]) - self.check_loops(new_with_vtable=2, # the vref, and xy so far, - new_array=0) # but not xy.next1/2/3 + self.check_loops(new_with_vtable=1, # the vref: xy doesn't need to be forced + new_array=0) # and neither xy.next1/2/3 self.check_aborted_count(0) def test_simple_force_always(self): @@ -244,12 +270,12 @@ xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) n -= externalfn(n) xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) exctx.topframeref = vref_None # self.meta_interp(f, [15]) @@ -282,19 +308,19 @@ xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) n -= externalfn(n) xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) exctx.topframeref = vref_None return exctx.m # res = self.meta_interp(f, [30]) assert res == 13 - self.check_loops(new_with_vtable=2, # the vref, XY() at the end - new_array=0) # but not next1/2/3 + self.check_loops(new_with_vtable=1, # the vref, but not XY() + new_array=0) # and neither next1/2/3 self.check_loop_count(1) self.check_aborted_count(0) @@ -322,7 +348,7 @@ xy.next2 = lltype.malloc(A, 0) xy.next3 = lltype.malloc(A, 0) xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) if n == 13: externalfn(n) n -= 1 @@ -330,7 +356,7 @@ xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) xy.next3 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return exctx.m # res = self.meta_interp(f, [30]) @@ -366,7 +392,7 @@ xy.next4 = lltype.malloc(A, 0) xy.next5 = lltype.malloc(A, 0) xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) if n % 6 == 0: xy.next1 = lltype.nullptr(A) xy.next2 = lltype.nullptr(A) @@ -379,7 +405,7 @@ xy.next3 = lltype.nullptr(A) xy.next4 = lltype.nullptr(A) xy.next5 = lltype.nullptr(A) - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return exctx.m # res = self.meta_interp(f, [72]) @@ -389,36 +415,6 @@ new_array=2) # bridge: next4, next5 self.check_aborted_count(0) - def test_access_vref_later(self): - myjitdriver = JitDriver(greens = [], reds = ['n']) - # - class XY: - pass - class ExCtx: - pass - exctx = ExCtx() - # - @dont_look_inside - def g(): - return exctx.later().n - # - def f(n): - while n > 0: - myjitdriver.can_enter_jit(n=n) - myjitdriver.jit_merge_point(n=n) - xy = XY() - xy.n = n - exctx.topframeref = virtual_ref(xy) - exctx.later = exctx.topframeref - n -= 1 - exctx.topframeref = vref_None - virtual_ref_finish(xy) - return g() - # - res = self.meta_interp(f, [15]) - assert res == 1 - self.check_aborted_count(0) - def test_jit_force_virtual_seen(self): myjitdriver = JitDriver(greens = [], reds = ['n']) # @@ -435,12 +431,12 @@ myjitdriver.jit_merge_point(n=n) xy = XY() xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) xy.next1 = lltype.malloc(A, 0) n = exctx.topframeref().n - 1 xy.next1 = lltype.nullptr(A) exctx.topframeref = vref_None - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return 1 # res = self.meta_interp(f, [15]) @@ -465,12 +461,12 @@ if reclevel == 0: return n xy = XY() - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) m = f(xy, n, reclevel-1) assert m == n n -= 1 exctx.topframeref = vref_None - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return 2 def main(n, reclevel): return f(XY(), n, reclevel) @@ -495,7 +491,7 @@ frame.n += 1 xy = XY() xy.n = n - exctx.topframeref = virtual_ref(xy) + exctx.topframeref = vref = virtual_ref(xy) if reclevel > 0: m = f(xy, frame.n, reclevel-1) assert xy.n == m @@ -503,7 +499,7 @@ else: n -= 2 exctx.topframeref = vref_None - virtual_ref_finish(xy) + virtual_ref_finish(vref, xy) return frame.n def main(n, reclevel): return f(XY(), n, reclevel) @@ -540,7 +536,7 @@ escapexy(xy) # clean up exctx.vr = vref_None - virtual_ref_finish(xy) + virtual_ref_finish(vr, xy) n -= 1 return 1 # @@ -548,6 +544,57 @@ assert res == 1 self.check_loops(new_with_vtable=2) # vref, xy + def test_cannot_use_invalid_virtualref(self): + myjitdriver = JitDriver(greens = [], reds = ['n']) + # + class XY: + n = 0 + # + def fn(n): + res = False + while n > 0: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + xy = XY() + xy.n = n + vref = virtual_ref(xy) + virtual_ref_finish(vref, xy) + vref() # raises InvalidVirtualRef when jitted + n -= 1 + return res + # + py.test.raises(InvalidVirtualRef, "fn(10)") + py.test.raises(LLException, "self.meta_interp(fn, [10])") + + def test_call_virtualref_already_forced(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'res']) + # + class XY: + n = 0 + # + @dont_look_inside + def force_it(vref, n): + if n % 6 == 0: + return vref().n + return 0 + def fn(n): + res = 0 + while n > 0: + myjitdriver.can_enter_jit(n=n, res=res) + myjitdriver.jit_merge_point(n=n, res=res) + xy = XY() + xy.n = n + vref = virtual_ref(xy) + force_it(vref, n) + virtual_ref_finish(vref, xy) + res += force_it(vref, n) # doesn't raise, because it was already forced + n -= 1 + return res + # + assert fn(10) == 6 + res = self.meta_interp(fn, [10]) + assert res == 6 + class TestLLtype(VRefTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py --- a/pypy/jit/metainterp/test/test_warmspot.py +++ b/pypy/jit/metainterp/test/test_warmspot.py @@ -80,7 +80,7 @@ self.meta_interp(f, [123, 10]) assert len(get_stats().locations) >= 4 for loc in get_stats().locations: - assert loc == 'GREEN IS 123.' + assert loc == (0, 123) def test_set_param_enable_opts(self): from pypy.rpython.annlowlevel import llstr, hlstr diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -181,6 +181,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = None @@ -207,6 +208,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = llhelper(GET_LOCATION, get_location) _confirm_enter_jit_ptr = None @@ -230,6 +232,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = llhelper(ENTER_JIT, confirm_enter_jit) @@ -253,6 +256,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = None diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py --- a/pypy/jit/metainterp/virtualref.py +++ b/pypy/jit/metainterp/virtualref.py @@ -1,8 +1,8 @@ from pypy.rpython.rmodel import inputconst, log -from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass +from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.jit.metainterp import history from pypy.jit.codewriter import heaptracker - +from pypy.rlib.jit import InvalidVirtualRef class VirtualRefInfo: @@ -38,23 +38,24 @@ def replace_force_virtual_with_call(self, graphs): # similar to rvirtualizable2.replace_force_virtualizable_with_call(). - c_funcptr = None - count = 0 + c_force_virtual_ptr = None + force_virtual_count = 0 for graph in graphs: for block in graph.iterblocks(): for op in block.operations: if op.opname == 'jit_force_virtual': # first compute c_funcptr, but only if there is any # 'jit_force_virtual' around - if c_funcptr is None: - c_funcptr = self.get_force_virtual_fnptr() + if c_force_virtual_ptr is None: + c_force_virtual_ptr = self.get_force_virtual_fnptr() # op.opname = 'direct_call' - op.args = [c_funcptr, op.args[0]] - count += 1 - if c_funcptr is not None: - log("replaced %d 'jit_force_virtual' with %r" % (count, - c_funcptr.value)) + op.args = [c_force_virtual_ptr, op.args[0]] + force_virtual_count += 1 + # + if c_force_virtual_ptr is not None: + log("replaced %d 'jit_force_virtual' with %r" % (force_virtual_count, + c_force_virtual_ptr.value)) # ____________________________________________________________ @@ -145,7 +146,8 @@ ResumeGuardForcedDescr.force_now(self.cpu, token) assert vref.virtual_token == self.TOKEN_NONE assert vref.forced - else: - assert vref.forced + elif not vref.forced: + # token == TOKEN_NONE and the vref was not forced: it's invalid + raise InvalidVirtualRef return vref.forced force_virtual._dont_inline_ = True diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -1,6 +1,5 @@ import sys, py -from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr -from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.annlowlevel import llhelper, MixLevelHelperAnnotator,\ cast_base_ptr_to_instance, hlstr from pypy.annotation import model as annmodel @@ -10,16 +9,12 @@ from pypy.objspace.flow.model import checkgraph, Link, copygraph from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import r_uint, intmask -from pypy.rlib.debug import debug_print, fatalerror -from pypy.rlib.debug import debug_start, debug_stop -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.translator.simplify import get_funcobj, get_functype +from pypy.rlib.debug import fatalerror +from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function from pypy.jit.metainterp import history, pyjitpl, gc, memmgr -from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp -from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper +from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.jitdriver import JitDriverStaticData @@ -66,6 +61,7 @@ def jittify_and_run(interp, graph, args, repeat=1, backendopt=False, trace_limit=sys.maxint, inline=False, loop_longevity=0, retrace_limit=5, + function_threshold=4, enable_opts=ALL_OPTS_NAMES, **kwds): from pypy.config.config import ConfigError translator = interp.typer.annotator.translator @@ -77,9 +73,14 @@ translator.config.translation.list_comprehension_operations = True except ConfigError: pass + try: + translator.config.translation.jit_ffi = True + except ConfigError: + pass warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds) for jd in warmrunnerdesc.jitdrivers_sd: jd.warmstate.set_param_threshold(3) # for tests + jd.warmstate.set_param_function_threshold(function_threshold) jd.warmstate.set_param_trace_eagerness(2) # for tests jd.warmstate.set_param_trace_limit(trace_limit) jd.warmstate.set_param_inlining(inline) @@ -291,9 +292,6 @@ self.stats = stats if translate_support_code: self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper) - annhelper = self.annhelper - else: - annhelper = None cpu = CPUClass(self.translator.rtyper, self.stats, self.opt, translate_support_code, gcdescr=self.gcdescr) self.cpu = cpu @@ -422,7 +420,7 @@ if self.translator.rtyper.type_system.name == 'lltypesystem': def maybe_enter_jit(*args): try: - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) except JitException: raise # go through except Exception, e: @@ -430,15 +428,12 @@ maybe_enter_jit._always_inline_ = True else: def maybe_enter_jit(*args): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) maybe_enter_jit._always_inline_ = True jd._maybe_enter_jit_fn = maybe_enter_jit - can_inline = state.can_inline_greenargs - num_green_args = jd.num_green_args def maybe_enter_from_start(*args): - if not can_inline(*args[:num_green_args]): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_function_threshold, *args) maybe_enter_from_start._always_inline_ = True jd._maybe_enter_from_start_fn = maybe_enter_from_start @@ -549,7 +544,6 @@ self.rewrite_can_enter_jit(jd, sublist) def rewrite_can_enter_jit(self, jd, can_enter_jits): - FUNC = jd._JIT_ENTER_FUNCTYPE FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -1,7 +1,7 @@ import sys, weakref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi from pypy.rpython.ootypesystem import ootype -from pypy.rpython.annlowlevel import hlstr, llstr, cast_base_ptr_to_instance +from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance from pypy.rpython.annlowlevel import cast_object_to_ptr from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict from pypy.rlib.rarithmetic import intmask @@ -208,15 +208,20 @@ meth = getattr(self, 'set_param_' + name) meth(default_value) - def set_param_threshold(self, threshold): + def _compute_threshold(self, threshold): if threshold <= 0: - self.increment_threshold = 0 # never reach the THRESHOLD_LIMIT - return + return 0 # never reach the THRESHOLD_LIMIT if threshold < 2: threshold = 2 - self.increment_threshold = (self.THRESHOLD_LIMIT // threshold) + 1 + return (self.THRESHOLD_LIMIT // threshold) + 1 # the number is at least 1, and at most about half THRESHOLD_LIMIT + def set_param_threshold(self, threshold): + self.increment_threshold = self._compute_threshold(threshold) + + def set_param_function_threshold(self, threshold): + self.increment_function_threshold = self._compute_threshold(threshold) + def set_param_trace_eagerness(self, value): self.trace_eagerness = value @@ -291,7 +296,7 @@ self.make_jitdriver_callbacks() confirm_enter_jit = self.confirm_enter_jit - def maybe_compile_and_run(*args): + def maybe_compile_and_run(threshold, *args): """Entry point to the JIT. Called at the point with the can_enter_jit() hint. """ @@ -307,7 +312,7 @@ if cell.counter >= 0: # update the profiling counter - n = cell.counter + self.increment_threshold + n = cell.counter + threshold if n <= self.THRESHOLD_LIMIT: # bound not reached cell.counter = n return @@ -497,7 +502,6 @@ if hasattr(self, 'set_future_values'): return self.set_future_values - warmrunnerdesc = self.warmrunnerdesc jitdriver_sd = self.jitdriver_sd cpu = self.cpu vinfo = jitdriver_sd.virtualizable_info @@ -513,7 +517,6 @@ # if vinfo is not None: i0 = len(jitdriver_sd._red_args_types) - num_green_args = jitdriver_sd.num_green_args index_of_virtualizable = jitdriver_sd.index_of_virtualizable vable_static_fields = unrolling_iterable( zip(vinfo.static_extra_types, vinfo.static_fields)) @@ -566,6 +569,19 @@ return can_inline_greenargs(*greenargs) self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + if hasattr(jd.jitdriver, 'on_compile'): + def on_compile(logger, token, operations, type, greenkey): + greenargs = unwrap_greenkey(greenkey) + return jd.jitdriver.on_compile(logger, token, operations, type, + *greenargs) + def on_compile_bridge(logger, orig_token, operations, n): + return jd.jitdriver.on_compile_bridge(logger, orig_token, + operations, n) + jd.on_compile = on_compile + jd.on_compile_bridge = on_compile_bridge + else: + jd.on_compile = lambda *args: None + jd.on_compile_bridge = lambda *args: None def get_assembler_token(greenkey, redboxes): # 'redboxes' is only used to know the types of red arguments @@ -586,12 +602,8 @@ get_location_ptr = self.jitdriver_sd._get_printable_location_ptr if get_location_ptr is None: missing = '(no jitdriver.get_printable_location!)' - missingll = llstr(missing) def get_location_str(greenkey): - if we_are_translated(): - return missingll - else: - return missing + return missing else: rtyper = self.warmrunnerdesc.rtyper unwrap_greenkey = self.make_unwrap_greenkey() @@ -599,10 +611,10 @@ def get_location_str(greenkey): greenargs = unwrap_greenkey(greenkey) fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr) - res = fn(*greenargs) - if not we_are_translated() and not isinstance(res, str): - res = hlstr(res) - return res + llres = fn(*greenargs) + if not we_are_translated() and isinstance(llres, str): + return llres + return hlstr(llres) self.get_location_str = get_location_str # confirm_enter_jit_ptr = self.jitdriver_sd._confirm_enter_jit_ptr diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py --- a/pypy/jit/tl/pypyjit.py +++ b/pypy/jit/tl/pypyjit.py @@ -30,6 +30,7 @@ BACKEND = 'c' config = get_pypy_config(translating=True) +config.translation.backendopt.inline_threshold = 0.1 config.translation.gc = 'boehm' config.objspace.nofaking = True config.translating = True diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tinyframe/test/test_tinyframe.py b/pypy/jit/tl/tinyframe/test/test_tinyframe.py --- a/pypy/jit/tl/tinyframe/test/test_tinyframe.py +++ b/pypy/jit/tl/tinyframe/test/test_tinyframe.py @@ -96,11 +96,12 @@ RETURN r1 ''') s = StringIO() + prev = sys.stdout sys.stdout = s try: interpret(code) finally: - sys.stdout = sys.__stdout__ + sys.stdout = prev lines = s.getvalue().splitlines() assert lines == [ '0', diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -40,6 +40,7 @@ assert n >= 0 self.stack[n] = elem + @dont_look_inside def roll(self, r): if r < -1: i = self.stackpos + r @@ -80,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -3,22 +3,15 @@ in a nicer fashion """ -from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat,\ - LoopToken, get_const_ptr_for_string, get_const_ptr_for_unicode -from pypy.jit.metainterp.resoperation import rop, ResOperation, ResOpWithDescr, N_aryOp -from pypy.jit.metainterp.typesystem import llhelper -from pypy.jit.codewriter.heaptracker import adr2int -from pypy.jit.codewriter import longlong -from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.rpython.ootypesystem import ootype +from pypy.jit.tool.oparser_model import get_model + +from pypy.jit.metainterp.resoperation import rop, ResOperation, \ + ResOpWithDescr, N_aryOp, \ + UnaryOp, PlainResOp class ParseError(Exception): pass -class Boxes(object): - pass - class ESCAPE_OP(N_aryOp, ResOpWithDescr): OPNUM = -123 @@ -35,37 +28,32 @@ def clone(self): return ESCAPE_OP(self.OPNUM, self.getarglist()[:], self.result, self.getdescr()) -class ExtendedTreeLoop(TreeLoop): +class FORCE_SPILL(UnaryOp, PlainResOp): - def getboxes(self): - def opboxes(operations): - for op in operations: - yield op.result - for box in op.getarglist(): - yield box - def allboxes(): - for box in self.inputargs: - yield box - for box in opboxes(self.operations): - yield box + OPNUM = -124 - boxes = Boxes() - for box in allboxes(): - if isinstance(box, Box): - name = str(box) - setattr(boxes, name, box) - return boxes + def __init__(self, opnum, args, result=None, descr=None): + assert result is None + assert descr is None + assert opnum == self.OPNUM + self.result = result + self.initarglist(args) - def setvalues(self, **kwds): - boxes = self.getboxes() - for name, value in kwds.iteritems(): - getattr(boxes, name).value = value + def getopnum(self): + return self.OPNUM -def default_fail_descr(fail_args=None): - return BasicFailDescr() + def clone(self): + return FORCE_SPILL(self.OPNUM, self.getarglist()[:]) + + +def default_fail_descr(model, fail_args=None): + return model.BasicFailDescr() class OpParser(object): + + use_mock_model = False + def __init__(self, input, cpu, namespace, type_system, boxkinds, invent_fail_descr=default_fail_descr, nonstrict=False): @@ -81,7 +69,8 @@ self._cache = {} self.invent_fail_descr = invent_fail_descr self.nonstrict = nonstrict - self.looptoken = LoopToken() + self.model = get_model(self.use_mock_model) + self.looptoken = self.model.LoopToken() def get_const(self, name, typ): if self._consts is None: @@ -89,16 +78,16 @@ obj = self._consts[name] if self.type_system == 'lltype': if typ == 'ptr': - return ConstPtr(obj) + return self.model.ConstPtr(obj) else: assert typ == 'class' - return ConstInt(adr2int(llmemory.cast_ptr_to_adr(obj))) + return self.model.ConstInt(self.model.ptr_to_int(obj)) else: if typ == 'ptr': - return ConstObj(obj) + return self.model.ConstObj(obj) else: assert typ == 'class' - return ConstObj(ootype.cast_to_object(obj)) + return self.model.ConstObj(ootype.cast_to_object(obj)) def get_descr(self, poss_descr): if poss_descr.startswith('<'): @@ -113,16 +102,16 @@ pass if elem.startswith('i'): # integer - box = BoxInt() - _box_counter_more_than(elem[1:]) + box = self.model.BoxInt() + _box_counter_more_than(self.model, elem[1:]) elif elem.startswith('f'): - box = BoxFloat() - _box_counter_more_than(elem[1:]) + box = self.model.BoxFloat() + _box_counter_more_than(self.model, elem[1:]) elif elem.startswith('p'): # pointer - ts = getattr(self.cpu, 'ts', llhelper) + ts = getattr(self.cpu, 'ts', self.model.llhelper) box = ts.BoxRef() - _box_counter_more_than(elem[1:]) + _box_counter_more_than(self.model, elem[1:]) else: for prefix, boxclass in self.boxkinds.iteritems(): if elem.startswith(prefix): @@ -156,21 +145,21 @@ def getvar(self, arg): if not arg: - return ConstInt(0) + return self.model.ConstInt(0) try: - return ConstInt(int(arg)) + return self.model.ConstInt(int(arg)) except ValueError: if self.is_float(arg): - return ConstFloat(longlong.getfloatstorage(float(arg))) + return self.model.ConstFloat(self.model.convert_to_floatstorage(arg)) if (arg.startswith('"') or arg.startswith("'") or arg.startswith('s"')): # XXX ootype info = arg[1:].strip("'\"") - return get_const_ptr_for_string(info) + return self.model.get_const_ptr_for_string(info) if arg.startswith('u"'): # XXX ootype info = arg[1:].strip("'\"") - return get_const_ptr_for_unicode(info) + return self.model.get_const_ptr_for_unicode(info) if arg.startswith('ConstClass('): name = arg[len('ConstClass('):-1] return self.get_const(name, 'class') @@ -178,9 +167,9 @@ return None elif arg == 'NULL': if self.type_system == 'lltype': - return ConstPtr(ConstPtr.value) + return self.model.ConstPtr(self.model.ConstPtr.value) else: - return ConstObj(ConstObj.value) + return self.model.ConstObj(self.model.ConstObj.value) elif arg.startswith('ConstPtr('): name = arg[len('ConstPtr('):-1] return self.get_const(name, 'ptr') @@ -192,11 +181,8 @@ args = [] descr = None if argspec.strip(): - if opname == 'debug_merge_point': - allargs = argspec.rsplit(', ', 1) - else: - allargs = [arg for arg in argspec.split(",") - if arg != ''] + allargs = [arg for arg in argspec.split(",") + if arg != ''] poss_descr = allargs[-1].strip() if poss_descr.startswith('descr='): @@ -220,6 +206,8 @@ except AttributeError: if opname == 'escape': opnum = ESCAPE_OP.OPNUM + elif opname == 'force_spill': + opnum = FORCE_SPILL.OPNUM else: raise ParseError("unknown op: %s" % opname) endnum = line.rfind(')') @@ -245,14 +233,14 @@ "Unknown var in fail_args: %s" % arg) fail_args.append(fail_arg) if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr(fail_args) + descr = self.invent_fail_descr(self.model, fail_args) if hasattr(descr, '_oparser_uses_descr_of_guard'): descr._oparser_uses_descr_of_guard(self, fail_args) else: fail_args = None if opnum == rop.FINISH: if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr() + descr = self.invent_fail_descr(self.model) elif opnum == rop.JUMP: if descr is None and self.invent_fail_descr: descr = self.looptoken @@ -261,6 +249,8 @@ def create_op(self, opnum, args, result, descr): if opnum == ESCAPE_OP.OPNUM: return ESCAPE_OP(opnum, args, result, descr) + if opnum == FORCE_SPILL.OPNUM: + return FORCE_SPILL(opnum, args, result, descr) else: return ResOperation(opnum, args, result, descr) @@ -315,7 +305,7 @@ num, ops, last_offset = self.parse_ops(base_indent, newlines, 0) if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) - loop = ExtendedTreeLoop("loop") + loop = self.model.ExtendedTreeLoop("loop") loop.comment = first_comment loop.token = self.looptoken loop.operations = ops @@ -371,7 +361,7 @@ def parse(input, cpu=None, namespace=None, type_system='lltype', boxkinds=None, invent_fail_descr=default_fail_descr, - no_namespace=False, nonstrict=False): + no_namespace=False, nonstrict=False, OpParser=OpParser): if namespace is None and not no_namespace: namespace = {} return OpParser(input, cpu, namespace, type_system, boxkinds, @@ -382,6 +372,6 @@ return parse(*args, **kwds) -def _box_counter_more_than(s): +def _box_counter_more_than(model, s): if s.isdigit(): - Box._counter = max(Box._counter, int(s)+1) + model.Box._counter = max(model.Box._counter, int(s)+1) diff --git a/pypy/jit/tool/oparser_model.py b/pypy/jit/tool/oparser_model.py new file mode 100644 --- /dev/null +++ b/pypy/jit/tool/oparser_model.py @@ -0,0 +1,148 @@ +class Boxes(object): + pass + +def get_real_model(): + class LoopModel(object): + from pypy.jit.metainterp.history import TreeLoop, LoopToken + from pypy.jit.metainterp.history import Box, BoxInt, BoxFloat + from pypy.jit.metainterp.history import ConstInt, ConstObj, ConstPtr, ConstFloat + from pypy.jit.metainterp.history import BasicFailDescr + from pypy.jit.metainterp.typesystem import llhelper + + from pypy.jit.metainterp.history import get_const_ptr_for_string + from pypy.jit.metainterp.history import get_const_ptr_for_unicode + get_const_ptr_for_string = staticmethod(get_const_ptr_for_string) + get_const_ptr_for_unicode = staticmethod(get_const_ptr_for_unicode) + + @staticmethod + def convert_to_floatstorage(arg): + from pypy.jit.codewriter import longlong + return longlong.getfloatstorage(float(arg)) + + @staticmethod + def ptr_to_int(obj): + from pypy.jit.codewriter.heaptracker import adr2int + from pypy.rpython.lltypesystem import llmemory + return adr2int(llmemory.cast_ptr_to_adr(obj)) + + @staticmethod + def ootype_cast_to_object(obj): + from pypy.rpython.ootypesystem import ootype + return ootype.cast_to_object(obj) + + return LoopModel + +def get_mock_model(): + class LoopModel(object): + + class TreeLoop(object): + def __init__(self, name): + self.name = name + + class LoopToken(object): + I_am_a_descr = True + + class BasicFailDescr(object): + I_am_a_descr = True + + class Box(object): + _counter = 0 + type = 'b' + + def __init__(self, value=0): + self.value = value + + def __repr__(self): + result = str(self) + result += '(%s)' % self.value + return result + + def __str__(self): + if not hasattr(self, '_str'): + self._str = '%s%d' % (self.type, Box._counter) + Box._counter += 1 + return self._str + + class BoxInt(Box): + type = 'i' + + class BoxFloat(Box): + type = 'f' + + class BoxRef(Box): + type = 'p' + + class Const(object): + def __init__(self, value=None): + self.value = value + + def _get_str(self): + return str(self.value) + + class ConstInt(Const): + pass + + class ConstPtr(Const): + pass + + class ConstFloat(Const): + pass + + @classmethod + def get_const_ptr_for_string(cls, s): + return cls.ConstPtr(s) + + @classmethod + def get_const_ptr_for_unicode(cls, s): + return cls.ConstPtr(s) + + @staticmethod + def convert_to_floatstorage(arg): + return float(arg) + + @staticmethod + def ptr_to_int(obj): + return id(obj) + + class llhelper(object): + pass + + LoopModel.llhelper.BoxRef = LoopModel.BoxRef + + return LoopModel + + +def get_model(use_mock): + if use_mock: + model = get_mock_model() + else: + model = get_real_model() + + class ExtendedTreeLoop(model.TreeLoop): + + def getboxes(self): + def opboxes(operations): + for op in operations: + yield op.result + for box in op.getarglist(): + yield box + def allboxes(): + for box in self.inputargs: + yield box + for box in opboxes(self.operations): + yield box + + boxes = Boxes() + for box in allboxes(): + if isinstance(box, model.Box): + name = str(box) + setattr(boxes, name, box) + return boxes + + def setvalues(self, **kwds): + boxes = self.getboxes() + for name, value in kwds.iteritems(): + getattr(boxes, name).value = value + + model.ExtendedTreeLoop = ExtendedTreeLoop + return model diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -8,10 +8,16 @@ (defun set-truncate-lines () (setq truncate-lines t)) +;; to generate the list of keywords: +;; from pypy.jit.metainterp import resoperation +;; print ' '.join(sorted('"%s"' % op.lower() for op in resoperation.opname.values() if not op.startswith('GUARD'))) + + + (define-generic-mode 'pypytrace-mode ;; name of the mode to create nil - '("jump" "finish" "int_add" "int_sub" "int_mul" "int_floordiv" "uint_floordiv" "int_mod" "int_and" "int_or" "int_xor" "int_rshift" "int_lshift" "uint_rshift" "float_add" "float_sub" "float_mul" "float_truediv" "float_neg" "float_abs" "cast_float_to_int" "cast_int_to_float" "int_lt" "int_le" "int_eq" "int_ne" "int_gt" "int_ge" "uint_lt" "uint_le" "uint_gt" "uint_ge" "float_lt" "float_le" "float_eq" "float_ne" "float_gt" "float_ge" "int_is_zero" "int_is_true" "int_neg" "int_invert" "same_as" "ptr_eq" "ptr_ne" "arraylen_gc" "strlen" "strgetitem" "getfield_gc_pure" "getfield_raw_pure" "getarrayitem_gc_pure" "unicodelen" "unicodegetitem" "getarrayitem_gc" "getarrayitem_raw" "getfield_gc" "getfield_raw" "new" "new_with_vtable" "new_array" "force_token" "virtual_ref" "setarrayitem_gc" "setarrayitem_raw" "setfield_gc" "setfield_raw" "arraycopy" "newstr" "strsetitem" "unicodesetitem" "newunicode" "cond_call_gc_wb" "virtual_ref_finish" "call" "call_assembler" "call_may_force" "call_loopinvariant" "call_pure" "int_add_ovf" "int_sub_ovf" "int_mul_ovf") ;; keywords + '("arraylen_gc" "call" "call_assembler" "call_loopinvariant" "call_may_force" "call_pure" "call_release_gil" "cast_float_to_int" "cast_int_to_float" "cond_call_gc_wb" "copystrcontent" "copyunicodecontent" "debug_merge_point" "finish" "float_abs" "float_add" "float_eq" "float_ge" "float_gt" "float_le" "float_lt" "float_mul" "float_ne" "float_neg" "float_sub" "float_truediv" "force_token" "getarrayitem_gc" "getarrayitem_gc_pure" "getarrayitem_raw" "getfield_gc" "getfield_gc_pure" "getfield_raw" "getfield_raw_pure" "int_add" "int_add_ovf" "int_and" "int_eq" "int_floordiv" "int_ge" "int_gt" "int_invert" "int_is_true" "int_is_zero" "int_le" "int_lshift" "int_lt" "int_mod" "int_mul" "int_mul_ovf" "int_ne" "int_neg" "int_or" "int_rshift" "int_sub" "int_sub_ovf" "int_xor" "jit_debug" "jump" "new" "new_array" "new_with_vtable" "newstr" "newunicode" "ptr_eq" "ptr_ne" "quasiimmut_field" "read_timestamp" "same_as" "setarrayitem_gc" "setarrayitem_raw" "setfield_gc" "setfield_raw" "strgetitem" "strlen" "strsetitem" "uint_floordiv" "uint_ge" "uint_gt" "uint_le" "uint_lt" "uint_rshift" "unicodegetitem" "unicodelen" "unicodesetitem" "virtual_ref" "virtual_ref_finish") ;; keywords '( ;; additional regexps ("^# Loop.*" . 'hi-blue) ("\\[.*\\]" . 'font-lock-comment-face) ;; comment out argument lists @@ -26,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/jit/tool/test/test_oparser.py b/pypy/jit/tool/test/test_oparser.py --- a/pypy/jit/tool/test/test_oparser.py +++ b/pypy/jit/tool/test/test_oparser.py @@ -1,227 +1,274 @@ import py +import sys from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.jit.tool.oparser import parse, ParseError +from pypy.jit.tool.oparser import parse, OpParser from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken,\ - BoxFloat +from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken -def test_basic_parse(): - x = """ - [i0, i1] - # a comment - i2 = int_add(i0, i1) - i3 = int_sub(i2, 3) # another comment - finish() # (tricky) - """ - loop = parse(x) - assert len(loop.operations) == 3 - assert [op.getopnum() for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, - rop.FINISH] - assert len(loop.inputargs) == 2 - assert loop.operations[-1].getdescr() +class BaseTestOparser(object): -def test_const_ptr_subops(): - x = """ - [p0] - guard_class(p0, ConstClass(vtable)) [] - """ - S = lltype.Struct('S') - vtable = lltype.nullptr(S) - loop = parse(x, None, locals()) - assert len(loop.operations) == 1 - assert loop.operations[0].getdescr() - assert loop.operations[0].getfailargs() == [] + OpParser = None -def test_descr(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - i1 = getfield_gc(p0, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff + def parse(self, *args, **kwds): + kwds['OpParser'] = self.OpParser + return parse(*args, **kwds) -def test_after_fail(): - x = """ - [i0] - guard_value(i0, 3) [] - i1 = int_add(1, 2) - """ - loop = parse(x, None, {}) - assert len(loop.operations) == 2 + def test_basic_parse(self): + x = """ + [i0, i1] + # a comment + i2 = int_add(i0, i1) + i3 = int_sub(i2, 3) # another comment + finish() # (tricky) + """ + loop = self.parse(x) + assert len(loop.operations) == 3 + assert [op.getopnum() for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, + rop.FINISH] + assert len(loop.inputargs) == 2 + assert loop.operations[-1].getdescr() -def test_descr_setfield(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - setfield_gc(p0, 3, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff + def test_const_ptr_subops(self): + x = """ + [p0] + guard_class(p0, ConstClass(vtable)) [] + """ + S = lltype.Struct('S') + vtable = lltype.nullptr(S) + loop = self.parse(x, None, locals()) + assert len(loop.operations) == 1 + assert loop.operations[0].getdescr() + assert loop.operations[0].getfailargs() == [] -def test_boxname(): - x = """ - [i42] - i50 = int_add(i42, 1) - """ - loop = parse(x, None, {}) - assert str(loop.inputargs[0]) == 'i42' - assert str(loop.operations[0].result) == 'i50' + def test_descr(self): + class Xyz(AbstractDescr): + I_am_a_descr = True # for the mock case -def test_getboxes(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - boxes = loop.getboxes() - assert boxes.i0 is loop.inputargs[0] - assert boxes.i1 is loop.operations[0].result - -def test_setvalues(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - loop.setvalues(i0=32, i1=42) - assert loop.inputargs[0].value == 32 - assert loop.operations[0].result.value == 42 + x = """ + [p0] + i1 = getfield_gc(p0, descr=stuff) + """ + stuff = Xyz() + loop = self.parse(x, None, locals()) + assert loop.operations[0].getdescr() is stuff -def test_boxkind(): - x = """ - [sum0] - """ - loop = parse(x, None, {}, boxkinds={'sum': BoxInt}) - b = loop.getboxes() - assert isinstance(b.sum0, BoxInt) - -def test_getvar_const_ptr(): - x = ''' - [] - call(ConstPtr(func_ptr)) + def test_after_fail(self): + x = """ + [i0] + guard_value(i0, 3) [] + i1 = int_add(1, 2) + """ + loop = self.parse(x, None, {}) + assert len(loop.operations) == 2 + + def test_descr_setfield(self): + class Xyz(AbstractDescr): + I_am_a_descr = True # for the mock case + + x = """ + [p0] + setfield_gc(p0, 3, descr=stuff) + """ + stuff = Xyz() + loop = self.parse(x, None, locals()) + assert loop.operations[0].getdescr() is stuff + + def test_boxname(self): + x = """ + [i42] + i50 = int_add(i42, 1) + """ + loop = self.parse(x, None, {}) + assert str(loop.inputargs[0]) == 'i42' + assert str(loop.operations[0].result) == 'i50' + + def test_getboxes(self): + x = """ + [i0] + i1 = int_add(i0, 10) + """ + loop = self.parse(x, None, {}) + boxes = loop.getboxes() + assert boxes.i0 is loop.inputargs[0] + assert boxes.i1 is loop.operations[0].result + + def test_setvalues(self): + x = """ + [i0] + i1 = int_add(i0, 10) + """ + loop = self.parse(x, None, {}) + loop.setvalues(i0=32, i1=42) + assert loop.inputargs[0].value == 32 + assert loop.operations[0].result.value == 42 + + def test_getvar_const_ptr(self): + x = ''' + [] + call(ConstPtr(func_ptr)) + ''' + TP = lltype.GcArray(lltype.Signed) + NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) + loop = self.parse(x, None, {'func_ptr' : NULL}) + assert loop.operations[0].getarg(0).value == NULL + + def test_jump_target(self): + x = ''' + [] + jump() + ''' + loop = self.parse(x) + assert loop.operations[0].getdescr() is loop.token + + def test_jump_target_other(self): + looptoken = LoopToken() + looptoken.I_am_a_descr = True # for the mock case + x = ''' + [] + jump(descr=looptoken) + ''' + loop = self.parse(x, namespace=locals()) + assert loop.operations[0].getdescr() is looptoken + + def test_floats(self): + x = ''' + [f0] + f1 = float_add(f0, 3.5) + ''' + loop = self.parse(x) + box = loop.operations[0].getarg(0) + # we cannot use isinstance, because in case of mock the class will be + # constructed on the fly + assert box.__class__.__name__ == 'BoxFloat' + + def test_debug_merge_point(self): + x = ''' + [] + debug_merge_point(0, "info") + debug_merge_point(0, 'info') + debug_merge_point(1, ' info') + debug_merge_point(0, '(stuff) #1') + ''' + loop = self.parse(x) + assert loop.operations[0].getarg(1)._get_str() == 'info' + assert loop.operations[1].getarg(1)._get_str() == 'info' + assert loop.operations[2].getarg(1)._get_str() == " info" + assert loop.operations[3].getarg(1)._get_str() == "(stuff) #1" + + + def test_descr_with_obj_print(self): + x = ''' + [p0] + setfield_gc(p0, 1, descr=) + ''' + loop = self.parse(x) + # assert did not explode + + example_loop_log = '''\ + # bridge out of Guard12, 6 ops + [i0, i1, i2] + i4 = int_add(i0, 2) + i6 = int_sub(i1, 1) + i8 = int_gt(i6, 3) + guard_true(i8, descr=) [i4, i6] + debug_merge_point('(no jitdriver.get_printable_location!)', 0) + jump(i6, i4, descr=) ''' - TP = lltype.GcArray(lltype.Signed) - NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) - loop = parse(x, None, {'func_ptr' : NULL}) - assert loop.operations[0].getarg(0).value == NULL -def test_jump_target(): - x = ''' - [] - jump() - ''' - loop = parse(x) - assert loop.operations[0].getdescr() is loop.token + def test_parse_no_namespace(self): + loop = self.parse(self.example_loop_log, no_namespace=True) -def test_jump_target_other(): - looptoken = LoopToken() - x = ''' - [] - jump(descr=looptoken) - ''' - loop = parse(x, namespace=locals()) - assert loop.operations[0].getdescr() is looptoken + def test_attach_comment_to_loop(self): + loop = self.parse(self.example_loop_log, no_namespace=True) + assert loop.comment == ' # bridge out of Guard12, 6 ops' -def test_floats(): - x = ''' - [f0] - f1 = float_add(f0, 3.5) - ''' - loop = parse(x) - assert isinstance(loop.operations[0].getarg(0), BoxFloat) - -def test_debug_merge_point(): - x = ''' - [] - debug_merge_point("info", 0) - debug_merge_point('info', 1) - debug_merge_point(' info', 1) - debug_merge_point('(stuff) #1', 1) - ''' - loop = parse(x) - assert loop.operations[0].getarg(0)._get_str() == 'info' - assert loop.operations[1].getarg(0)._get_str() == 'info' - assert loop.operations[2].getarg(0)._get_str() == " info" - assert loop.operations[3].getarg(0)._get_str() == "(stuff) #1" - + def test_parse_new_with_comma(self): + # this is generated by PYPYJITLOG, check that we can handle it + x = ''' + [] + p0 = new(, descr=) + ''' + loop = self.parse(x) + assert loop.operations[0].getopname() == 'new' -def test_descr_with_obj_print(): - x = ''' - [p0] - setfield_gc(p0, 1, descr=) - ''' - loop = parse(x) - # assert did not explode + def test_no_fail_args(self): + x = ''' + [i0] + guard_true(i0, descr=) + ''' + loop = self.parse(x, nonstrict=True) + assert loop.operations[0].getfailargs() == [] -example_loop_log = '''\ -# bridge out of Guard12, 6 ops -[i0, i1, i2] -i4 = int_add(i0, 2) -i6 = int_sub(i1, 1) -i8 = int_gt(i6, 3) -guard_true(i8, descr=) [i4, i6] -debug_merge_point('(no jitdriver.get_printable_location!)', 0) -jump(i6, i4, descr=) -''' + def test_no_inputargs(self): + x = ''' + i2 = int_add(i0, i1) + ''' + loop = self.parse(x, nonstrict=True) + assert loop.inputargs == [] + assert loop.operations[0].getopname() == 'int_add' -def test_parse_no_namespace(): - loop = parse(example_loop_log, no_namespace=True) + def test_offsets(self): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + """ + # +30: --end of the loop-- + loop = self.parse(x) + assert loop.operations[0].offset == 10 + assert not hasattr(loop.operations[1], 'offset') -def test_attach_comment_to_loop(): - loop = parse(example_loop_log, no_namespace=True) - assert loop.comment == '# bridge out of Guard12, 6 ops' + def test_last_offset(self): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + +30: --end of the loop-- + """ + loop = self.parse(x) + assert len(loop.operations) == 2 + assert loop.last_offset == 30 -def test_parse_new_with_comma(): - # this is generated by PYPYJITLOG, check that we can handle it - x = ''' - [] - p0 = new(, descr=) - ''' - loop = parse(x) - assert loop.operations[0].getopname() == 'new' -def test_no_fail_args(): - x = ''' - [i0] - guard_true(i0, descr=) - ''' - loop = parse(x, nonstrict=True) - assert loop.operations[0].getfailargs() == [] +class TestOpParser(BaseTestOparser): -def test_no_inputargs(): - x = ''' - i2 = int_add(i0, i1) - ''' - loop = parse(x, nonstrict=True) - assert loop.inputargs == [] - assert loop.operations[0].getopname() == 'int_add' + OpParser = OpParser -def test_offsets(): - x = """ - [i0, i1] - +10: i2 = int_add(i0, i1) - i3 = int_add(i2, 3) - """ - # +30: --end of the loop-- - loop = parse(x) - assert loop.operations[0].offset == 10 - assert not hasattr(loop.operations[1], 'offset') + def test_boxkind(self): + x = """ + [sum0] + """ + loop = self.parse(x, None, {}, boxkinds={'sum': BoxInt}) + b = loop.getboxes() + assert isinstance(b.sum0, BoxInt) -def test_last_offset(): - x = """ - [i0, i1] - +10: i2 = int_add(i0, i1) - i3 = int_add(i2, 3) - +30: --end of the loop-- - """ - loop = parse(x) - assert len(loop.operations) == 2 - assert loop.last_offset == 30 + +class ForbiddenModule(object): + def __init__(self, name, old_mod): + self.name = name + self.old_mod = old_mod + + def __getattr__(self, attr): + assert False, "You should not import module %s" % self.name + + +class TestOpParserWithMock(BaseTestOparser): + + class OpParser(OpParser): + use_mock_model = True + + def setup_class(cls): + forbidden_mods = [ + 'pypy.jit.metainterp.history', + 'pypy.rpython.lltypesystem.lltype', + ] + for modname in forbidden_mods: + if modname in sys.modules: + newmod = ForbiddenModule(modname, sys.modules[modname]) + sys.modules[modname] = newmod + + def teardown_class(cls): + for modname, mod in sys.modules.iteritems(): + if isinstance(mod, ForbiddenModule): + sys.modules[modname] = mod.old_mod diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -17,6 +17,8 @@ 'apply' : 'app_functional.apply', 'sorted' : 'app_functional.sorted', + 'any' : 'app_functional.any', + 'all' : 'app_functional.all', 'vars' : 'app_inspect.vars', 'dir' : 'app_inspect.dir', @@ -81,8 +83,6 @@ 'range' : 'functional.range_int', 'xrange' : 'functional.W_XRange', 'enumerate' : 'functional.W_Enumerate', - 'all' : 'functional.all', - 'any' : 'functional.any', 'min' : 'functional.min', 'max' : 'functional.max', 'sum' : 'functional.sum', diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py --- a/pypy/module/__builtin__/app_functional.py +++ b/pypy/module/__builtin__/app_functional.py @@ -16,3 +16,21 @@ sorted_lst = list(lst) sorted_lst.sort(cmp, key, reverse) return sorted_lst + +def any(seq): + """any(iterable) -> bool + +Return True if bool(x) is True for any x in the iterable.""" + for x in seq: + if x: + return True + return False + +def all(seq): + """all(iterable) -> bool + +Return True if bool(x) is True for all values x in the iterable.""" + for x in seq: + if not x: + return False + return True diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -294,7 +294,7 @@ break new_frame = space.createframe(code, w_func.w_func_globals, w_func.closure) - new_frame.fastlocals_w[0] = w_item + new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) return result_w @@ -452,40 +452,6 @@ w_empty = space.call_function(w_str_type) return space.call_method(w_empty, "join", space.newlist(result_w)) -def all(space, w_S): - """all(iterable) -> bool - -Return True if bool(x) is True for all values x in the iterable.""" - w_iter = space.iter(w_S) - while True: - try: - w_next = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise # re-raise other app-level exceptions - break - if not space.is_true(w_next): - return space.w_False - return space.w_True - - -def any(space, w_S): - """any(iterable) -> bool - -Return True if bool(x) is True for any x in the iterable.""" - w_iter = space.iter(w_S) - while True: - try: - w_next = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise # re-raise other app-level exceptions - break - if space.is_true(w_next): - return space.w_True - return space.w_False - - class W_Enumerate(Wrappable): def __init__(self, w_iter, w_start): diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -1,5 +1,6 @@ import autopath import sys +from pypy import conftest class AppTestBuiltinApp: def setup_class(cls): @@ -15,6 +16,15 @@ cls.w_sane_lookup = cls.space.wrap(True) except KeyError: cls.w_sane_lookup = cls.space.wrap(False) + # starting with CPython 2.6, when the stack is almost out, we + # can get a random error, instead of just a RuntimeError. + # For example if an object x has a __getattr__, we can get + # AttributeError if attempting to call x.__getattr__ runs out + # of stack. That's annoying, so we just work around it. + if conftest.option.runappdirect: + cls.w_safe_runtimerror = cls.space.wrap(True) + else: + cls.w_safe_runtimerror = cls.space.wrap(sys.version_info < (2, 6)) def test_bytes_alias(self): assert bytes is str @@ -399,6 +409,8 @@ def test_cmp_cyclic(self): if not self.sane_lookup: skip("underlying Python implementation has insane dict lookup") + if not self.safe_runtimerror: + skip("underlying Python may raise random exceptions on stack ovf") a = []; a.append(a) b = []; b.append(b) from UserList import UserList diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -3,6 +3,14 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.imp.importing import get_pyc_magic + +class BuildersModule(MixedModule): + appleveldefs = {} + + interpleveldefs = { + "UnicodeBuilder": "interp_builders.W_UnicodeBuilder", + } + class Module(MixedModule): appleveldefs = { } @@ -19,6 +27,10 @@ 'lookup_special' : 'interp_magic.lookup_special', } + submodules = { + "builders": BuildersModule, + } + def setup_after_space_initialization(self): """NOT_RPYTHON""" if not self.space.config.translating: diff --git a/pypy/module/__pypy__/interp_builders.py b/pypy/module/__pypy__/interp_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_builders.py @@ -0,0 +1,50 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef +from pypy.rlib.rstring import UnicodeBuilder + + +class W_UnicodeBuilder(Wrappable): + def __init__(self, space, size): + if size == -1: + self.builder = UnicodeBuilder() + else: + self.builder = UnicodeBuilder(size) + self.done = False + + def _check_done(self, space): + if self.done: + raise OperationError(space.w_ValueError, space.wrap("Can't operate on a done builder")) + + @unwrap_spec(size=int) + def descr__new__(space, w_subtype, size=-1): + return W_UnicodeBuilder(space, size) + + @unwrap_spec(s=unicode) + def descr_append(self, space, s): + self._check_done(space) + self.builder.append(s) + + @unwrap_spec(s=unicode, start=int, end=int) + def descr_append_slice(self, space, s, start, end): + self._check_done(space) + if not 0 <= start <= end <= len(s): + raise OperationError(space.w_ValueError, space.wrap("bad start/stop")) + self.builder.append_slice(s, start, end) + + def descr_build(self, space): + self._check_done(space) + w_s = space.wrap(self.builder.build()) + self.done = True + return w_s + + +W_UnicodeBuilder.typedef = TypeDef("UnicodeBuilder", + __new__ = interp2app(W_UnicodeBuilder.descr__new__.im_func), + + append = interp2app(W_UnicodeBuilder.descr_append), + append_slice = interp2app(W_UnicodeBuilder.descr_append_slice), + build = interp2app(W_UnicodeBuilder.descr_build), +) +W_UnicodeBuilder.typedef.acceptable_as_base_class = False \ No newline at end of file diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,15 +1,19 @@ from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.error import OperationError -from pypy.rlib import debug +from pypy.rlib import debug, jit + + at jit.dont_look_inside @unwrap_spec(category=str) def debug_start(space, category): debug.debug_start(category) + at jit.dont_look_inside def debug_print(space, args_w): parts = [space.str_w(space.str(w_item)) for w_item in args_w] debug.debug_print(' '.join(parts)) + at jit.dont_look_inside @unwrap_spec(category=str) def debug_stop(space, category): debug.debug_stop(category) diff --git a/pypy/module/__pypy__/test/test_builders.py b/pypy/module/__pypy__/test/test_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_builders.py @@ -0,0 +1,34 @@ +from pypy.conftest import gettestobjspace + + +class AppTestBuilders(object): + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['__pypy__']) + + def test_simple(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append(u"abc") + b.append(u"123") + b.append(u"1") + s = b.build() + assert s == u"abc1231" + raises(ValueError, b.build) + raises(ValueError, b.append, u"123") + + def test_preallocate(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder(10) + b.append(u"abc") + b.append(u"123") + s = b.build() + assert s == u"abc123" + + def test_append_slice(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append_slice(u"abcdefgh", 2, 5) + raises(ValueError, b.append_slice, u"1", 2, 1) + s = b.build() + assert s == "cde" + raises(ValueError, b.append_slice, u"abc", 1, 2) \ No newline at end of file diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -128,6 +128,9 @@ assert ns["x"] == ns["lemon"] == 3 assert ns["apple"] == 4 + def test_empty_module(self): + compile(self.ast.Module([]), "", "exec") + def test_ast_types(self): ast = self.ast expr = ast.Expr() diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -32,15 +32,22 @@ space.wrap(reason)) w_res = space.call_function(w_errorhandler, w_exc) if (not space.is_true(space.isinstance(w_res, space.w_tuple)) - or space.len_w(w_res) != 2): + or space.len_w(w_res) != 2 + or not space.is_true(space.isinstance( + space.getitem(w_res, space.wrap(0)), + space.w_unicode))): + if decode: + msg = ("decoding error handler must return " + "(unicode, int) tuple, not %s") + else: + msg = ("encoding error handler must return " + "(unicode, int) tuple, not %s") raise operationerrfmt( - space.w_TypeError, - "encoding error handler must return " - "(unicode, int) tuple, not %s", + space.w_TypeError, msg, space.str_w(space.repr(w_res))) w_replace, w_newpos = space.fixedview(w_res, 2) newpos = space.int_w(w_newpos) - if (newpos < 0): + if newpos < 0: newpos = len(input) + newpos if newpos < 0 or newpos > len(input): raise operationerrfmt( @@ -50,7 +57,9 @@ replace = space.unicode_w(w_replace) return replace, newpos else: - replace = space.str_w(w_replace) + from pypy.objspace.std.unicodetype import encode_object + w_str = encode_object(space, w_replace, encoding, None) + replace = space.str_w(w_str) return replace, newpos return unicode_call_errorhandler @@ -160,15 +169,7 @@ def ignore_errors(space, w_exc): check_exception(space, w_exc) w_end = space.getattr(w_exc, space.wrap('end')) - if space.isinstance_w(w_exc, space.w_UnicodeEncodeError): - return space.newtuple([space.wrap(''), w_end]) - elif (space.isinstance_w(w_exc, space.w_UnicodeDecodeError) or - space.isinstance_w(w_exc, space.w_UnicodeTranslateError)): - return space.newtuple([space.wrap(u''), w_end]) - else: - typename = space.type(w_exc).getname(space, '?') - raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + return space.newtuple([space.wrap(u''), w_end]) def replace_errors(space, w_exc): check_exception(space, w_exc) @@ -176,7 +177,7 @@ w_end = space.getattr(w_exc, space.wrap('end')) size = space.int_w(w_end) - space.int_w(w_start) if space.isinstance_w(w_exc, space.w_UnicodeEncodeError): - text = '?' * size + text = u'?' * size return space.newtuple([space.wrap(text), w_end]) elif space.isinstance_w(w_exc, space.w_UnicodeDecodeError): text = u'\ufffd' diff --git a/pypy/module/_codecs/test/test_codecs.py b/pypy/module/_codecs/test/test_codecs.py --- a/pypy/module/_codecs/test/test_codecs.py +++ b/pypy/module/_codecs/test/test_codecs.py @@ -540,6 +540,17 @@ else: assert res == u"\x00\x00\x01\x00\x00" # UCS2 build + def test_encode_error_bad_handler(self): + import codecs + codecs.register_error("test.bad_handler", lambda e: (repl, 1)) + assert u"xyz".encode("latin-1", "test.bad_handler") == "xyz" + repl = u"\u1234" + raises(UnicodeEncodeError, u"\u5678".encode, "latin-1", + "test.bad_handler") + repl = u"\u00E9" + s = u"\u5678".encode("latin-1", "test.bad_handler") + assert s == '\xe9' + def test_charmap_encode(self): assert 'xxx'.encode('charmap') == 'xxx' @@ -593,3 +604,11 @@ assert u'caf\xe9'.encode('mbcs') == 'caf\xe9' assert u'\u040a'.encode('mbcs') == '?' # some cyrillic letter assert 'cafx\e9'.decode('mbcs') == u'cafx\e9' + + def test_bad_handler_string_result(self): + import _codecs + def f(exc): + return ('foo', exc.end) + _codecs.register_error("test.test_codecs_not_a_string", f) + raises(TypeError, u'\u1234'.encode, 'ascii', + 'test.test_codecs_not_a_string') diff --git a/pypy/module/_ffi/__init__.py b/pypy/module/_ffi/__init__.py --- a/pypy/module/_ffi/__init__.py +++ b/pypy/module/_ffi/__init__.py @@ -4,8 +4,10 @@ class Module(MixedModule): interpleveldefs = { - 'CDLL' : 'interp_ffi.W_CDLL', - 'types': 'interp_ffi.W_types', + 'CDLL': 'interp_ffi.W_CDLL', + 'types': 'interp_ffi.W_types', + 'FuncPtr': 'interp_ffi.W_FuncPtr', + 'get_libc':'interp_ffi.get_libc', } appleveldefs = {} diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -4,63 +4,170 @@ operationerrfmt from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi # from pypy.rlib import jit from pypy.rlib import libffi from pypy.rlib.rdynload import DLOpenError -from pypy.rlib.rarithmetic import intmask +from pypy.rlib.rarithmetic import intmask, r_uint class W_FFIType(Wrappable): - def __init__(self, name, ffitype): + + _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to'] + + def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None): self.name = name self.ffitype = ffitype + self.w_datashape = w_datashape + self.w_pointer_to = w_pointer_to + if self.is_struct(): + assert w_datashape is not None - def str(self, space): - return space.wrap('' % self.name) + def descr_deref_pointer(self, space): + if self.w_pointer_to is None: + return space.w_None + return self.w_pointer_to + def repr(self, space): + return space.wrap(self.__repr__()) + def __repr__(self): + return "" % self.name + + def is_signed(self): + return (self is app_types.slong or + self is app_types.sint or + self is app_types.sshort or + self is app_types.sbyte or + self is app_types.slonglong) + + def is_unsigned(self): + return (self is app_types.ulong or + self is app_types.uint or + self is app_types.ushort or + self is app_types.ubyte or + self is app_types.ulonglong) + + def is_pointer(self): + return self.ffitype is libffi.types.pointer + + def is_char(self): + return self is app_types.char + + def is_unichar(self): + return self is app_types.unichar + + def is_longlong(self): + return libffi.IS_32_BIT and (self is app_types.slonglong or + self is app_types.ulonglong) + + def is_double(self): + return self is app_types.double + + def is_singlefloat(self): + return self is app_types.float + + def is_void(self): + return self is app_types.void + + def is_struct(self): + return libffi.types.is_struct(self.ffitype) W_FFIType.typedef = TypeDef( 'FFIType', - __str__ = interp2app(W_FFIType.str), + __repr__ = interp2app(W_FFIType.repr), + deref_pointer = interp2app(W_FFIType.descr_deref_pointer), ) +def build_ffi_types(): + from pypy.rlib.clibffi import FFI_TYPE_P + types = [ + # note: most of the type name directly come from the C equivalent, + # with the exception of bytes: in C, ubyte and char are equivalent, + # but for _ffi the first expects a number while the second a 1-length + # string + W_FFIType('slong', libffi.types.slong), + W_FFIType('sint', libffi.types.sint), + W_FFIType('sshort', libffi.types.sshort), + W_FFIType('sbyte', libffi.types.schar), + W_FFIType('slonglong', libffi.types.slonglong), + # + W_FFIType('ulong', libffi.types.ulong), + W_FFIType('uint', libffi.types.uint), + W_FFIType('ushort', libffi.types.ushort), + W_FFIType('ubyte', libffi.types.uchar), + W_FFIType('ulonglong', libffi.types.ulonglong), + # + W_FFIType('char', libffi.types.uchar), + W_FFIType('unichar', libffi.types.wchar_t), + # + W_FFIType('double', libffi.types.double), + W_FFIType('float', libffi.types.float), + W_FFIType('void', libffi.types.void), + W_FFIType('void_p', libffi.types.pointer), + # + # missing types: + + ## 's' : ffi_type_pointer, + ## 'z' : ffi_type_pointer, + ## 'O' : ffi_type_pointer, + ## 'Z' : ffi_type_pointer, + + ] + return dict([(t.name, t) for t in types]) + +class app_types: + pass +app_types.__dict__ = build_ffi_types() + +def descr_new_pointer(space, w_cls, w_pointer_to): + try: + return descr_new_pointer.cache[w_pointer_to] + except KeyError: + w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) + name = '(pointer to %s)' % w_pointer_to.name + w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to) + descr_new_pointer.cache[w_pointer_to] = w_result + return w_result +descr_new_pointer.cache = {} + class W_types(Wrappable): pass - -def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P - tdict = {} - for key, value in libffi.types.__dict__.iteritems(): - if key == 'getkind' or key.startswith('__'): - continue - assert lltype.typeOf(value) == FFI_TYPE_P - tdict[key] = W_FFIType(key, value) - return tdict - W_types.typedef = TypeDef( 'types', - **build_ffi_types()) + Pointer = interp2app(descr_new_pointer, as_classmethod=True), + **app_types.__dict__) + + +def unwrap_ffitype(space, w_argtype, allow_void=False): + res = w_argtype.ffitype + if res is libffi.types.void and not allow_void: + msg = 'void is not a valid argument type' + raise OperationError(space.w_TypeError, space.wrap(msg)) + return res + # ======================================================================== class W_FuncPtr(Wrappable): - _immutable_fields_ = ['func'] + _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype'] - def __init__(self, func): + def __init__(self, func, argtypes_w, w_restype): self.func = func + self.argtypes_w = argtypes_w + self.w_restype = w_restype @jit.unroll_safe - def build_argchain(self, space, argtypes, args_w): - expected = len(argtypes) + def build_argchain(self, space, args_w): + expected = len(self.argtypes_w) given = len(args_w) if given != expected: arg = 'arguments' - if len(argtypes) == 1: + if len(self.argtypes_w) == 1: arg = 'argument' raise operationerrfmt(space.w_TypeError, '%s() takes exactly %d %s (%d given)', @@ -68,34 +175,103 @@ # argchain = libffi.ArgChain() for i in range(expected): - argtype = argtypes[i] + w_argtype = self.argtypes_w[i] w_arg = args_w[i] - kind = libffi.types.getkind(argtype) - if kind == 'i': + if w_argtype.is_longlong(): + # note that we must check for longlong first, because either + # is_signed or is_unsigned returns true anyway + assert libffi.IS_32_BIT + kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind + self.arg_longlong(space, argchain, kind, w_arg) + elif w_argtype.is_signed(): argchain.arg(space.int_w(w_arg)) - elif kind == 'u': + elif w_argtype.is_pointer(): + w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) - elif kind == 'f': + elif w_argtype.is_unsigned(): + argchain.arg(intmask(space.uint_w(w_arg))) + elif w_argtype.is_char(): + w_arg = space.ord(w_arg) + argchain.arg(space.int_w(w_arg)) + elif w_argtype.is_unichar(): + w_arg = space.ord(w_arg) + argchain.arg(space.int_w(w_arg)) + elif w_argtype.is_double(): argchain.arg(space.float_w(w_arg)) + elif w_argtype.is_singlefloat(): + argchain.arg_singlefloat(space.float_w(w_arg)) + elif w_argtype.is_struct(): + # arg_raw directly takes value to put inside ll_args + w_arg = space.interp_w(W_StructureInstance, w_arg) + ptrval = w_arg.ll_buffer + argchain.arg_raw(ptrval) else: - assert False, "Argument kind '%s' not supported" % kind + assert False, "Argument shape '%s' not supported" % w_argtype return argchain + def convert_pointer_arg_maybe(self, space, w_arg, w_argtype): + """ + Try to convert the argument by calling _as_ffi_pointer_() + """ + meth = space.lookup(w_arg, '_as_ffi_pointer_') # this also promotes the type + if meth: + return space.call_function(meth, w_arg, w_argtype) + else: + return w_arg + + @jit.dont_look_inside + def arg_longlong(self, space, argchain, kind, w_arg): + bigarg = space.bigint_w(w_arg) + if kind == 'I': + llval = bigarg.tolonglong() + elif kind == 'U': + ullval = bigarg.toulonglong() + llval = rffi.cast(rffi.LONGLONG, ullval) + else: + assert False + # this is a hack: we store the 64 bits of the long long into the + # 64 bits of a float (i.e., a C double) + floatval = libffi.longlong2float(llval) + argchain.arg_longlong(floatval) + def call(self, space, args_w): - self = jit.hint(self, promote=True) - argchain = self.build_argchain(space, self.func.argtypes, args_w) - reskind = libffi.types.getkind(self.func.restype) - if reskind == 'i': + self = jit.promote(self) + argchain = self.build_argchain(space, args_w) + w_restype = self.w_restype + if w_restype.is_longlong(): + # note that we must check for longlong first, because either + # is_signed or is_unsigned returns true anyway + assert libffi.IS_32_BIT + reskind = libffi.types.getkind(self.func.restype) # XXX: remove the kind + return self._call_longlong(space, argchain, reskind) + elif w_restype.is_signed(): return self._call_int(space, argchain) - elif reskind == 'u': + elif w_restype.is_unsigned() or w_restype.is_pointer(): return self._call_uint(space, argchain) - elif reskind == 'f': + elif w_restype.is_char(): + intres = self.func.call(argchain, rffi.UCHAR) + return space.wrap(chr(intres)) + elif w_restype.is_unichar(): + intres = self.func.call(argchain, rffi.WCHAR_T) + return space.wrap(unichr(intres)) + elif w_restype.is_double(): floatres = self.func.call(argchain, rffi.DOUBLE) return space.wrap(floatres) - else: + elif w_restype.is_singlefloat(): + # the result is a float, but widened to be inside a double + floatres = self.func.call(argchain, rffi.FLOAT) + return space.wrap(floatres) + elif w_restype.is_struct(): + w_datashape = w_restype.w_datashape + assert isinstance(w_datashape, W_Structure) + ptrval = self.func.call(argchain, rffi.ULONG, is_struct=True) + return w_datashape.fromaddress(space, ptrval) + elif w_restype.is_void(): voidres = self.func.call(argchain, lltype.Void) assert voidres is None return space.w_None + else: + assert False, "Return value shape '%s' not supported" % w_restype def _call_int(self, space, argchain): # if the declared return type of the function is smaller than LONG, @@ -138,6 +314,10 @@ # special case uintres = call(argchain, rffi.ULONG) return space.wrap(uintres) + elif restype is libffi.types.pointer: + ptrres = call(argchain, rffi.VOIDP) + uintres = rffi.cast(rffi.ULONG, ptrres) + return space.wrap(uintres) elif restype is libffi.types.uint: intres = rffi.cast(rffi.LONG, call(argchain, rffi.UINT)) elif restype is libffi.types.ushort: @@ -149,16 +329,52 @@ space.wrap('Unsupported restype')) return space.wrap(intres) + @jit.dont_look_inside + def _call_longlong(self, space, argchain, reskind): + # this is a hack: we store the 64 bits of the long long into the 64 + # bits of a float (i.e., a C double) + floatres = self.func.call(argchain, rffi.LONGLONG) + llres = libffi.float2longlong(floatres) + if reskind == 'I': + return space.wrap(llres) + elif reskind == 'U': + ullres = rffi.cast(rffi.ULONGLONG, llres) + return space.wrap(ullres) + else: + assert False + def getaddr(self, space): """ Return the physical address in memory of the function """ return space.wrap(rffi.cast(rffi.LONG, self.func.funcsym)) + + +def unpack_argtypes(space, w_argtypes, w_restype): + argtypes_w = [space.interp_w(W_FFIType, w_argtype) + for w_argtype in space.listview(w_argtypes)] + argtypes = [unwrap_ffitype(space, w_argtype) for w_argtype in + argtypes_w] + w_restype = space.interp_w(W_FFIType, w_restype) + restype = unwrap_ffitype(space, w_restype, allow_void=True) + return argtypes_w, argtypes, w_restype, restype + + at unwrap_spec(addr=r_uint, name=str) +def descr_fromaddr(space, w_cls, addr, name, w_argtypes, w_restype): + argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space, + w_argtypes, + w_restype) + addr = rffi.cast(rffi.VOIDP, addr) + func = libffi.Func(name, argtypes, restype, addr) + return W_FuncPtr(func, argtypes_w, w_restype) + + W_FuncPtr.typedef = TypeDef( - 'FuncPtr', + '_ffi.FuncPtr', __call__ = interp2app(W_FuncPtr.call), getaddr = interp2app(W_FuncPtr.getaddr), + fromaddr = interp2app(descr_fromaddr, as_classmethod=True) ) @@ -167,40 +383,57 @@ class W_CDLL(Wrappable): def __init__(self, space, name): + self.space = space + if name is None: + self.name = "" + else: + self.name = name try: self.cdll = libffi.CDLL(name) except DLOpenError, e: - raise operationerrfmt(space.w_OSError, '%s: %s', name, + raise operationerrfmt(space.w_OSError, '%s: %s', self.name, e.msg or 'unspecified error') - self.name = name - self.space = space - - def ffitype(self, w_argtype, allow_void=False): - res = self.space.interp_w(W_FFIType, w_argtype).ffitype - if res is libffi.types.void and not allow_void: - space = self.space - msg = 'void is not a valid argument type' - raise OperationError(space.w_TypeError, space.wrap(msg)) - return res @unwrap_spec(name=str) def getfunc(self, space, name, w_argtypes, w_restype): - argtypes = [self.ffitype(w_argtype) for w_argtype in - space.listview(w_argtypes)] - restype = self.ffitype(w_restype, allow_void=True) - func = self.cdll.getpointer(name, argtypes, restype) - return W_FuncPtr(func) + argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space, + w_argtypes, + w_restype) + try: + func = self.cdll.getpointer(name, argtypes, restype) + except KeyError: + raise operationerrfmt(space.w_AttributeError, + "No symbol %s found in library %s", name, self.name) + + return W_FuncPtr(func, argtypes_w, w_restype) + @unwrap_spec(name=str) + def getaddressindll(self, space, name): + try: + address_as_uint = rffi.cast(lltype.Unsigned, + self.cdll.getaddressindll(name)) + except KeyError: + raise operationerrfmt(space.w_ValueError, + "No symbol %s found in library %s", name, self.name) + return space.wrap(address_as_uint) - at unwrap_spec(name=str) + at unwrap_spec(name='str_or_None') def descr_new_cdll(space, w_type, name): return space.wrap(W_CDLL(space, name)) W_CDLL.typedef = TypeDef( - 'CDLL', + '_ffi.CDLL', __new__ = interp2app(descr_new_cdll), getfunc = interp2app(W_CDLL.getfunc), + getaddressindll = interp2app(W_CDLL.getaddressindll), ) # ======================================================================== + +def get_libc(space): + from pypy.rlib.clibffi import get_libc_name + try: + return space.wrap(W_CDLL(space, get_libc_name())) + except OSError, e: + raise wrap_oserror(space, e) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -17,7 +17,13 @@ c_file = udir.ensure("test__ffi", dir=1).join("foolib.c") # automatically collect the C source from the docstrings of the tests - snippets = [] + snippets = [""" + #ifdef _WIN32 + #define DLLEXPORT __declspec(dllexport) + #else + #define DLLEXPORT + #endif + """] for name in dir(cls): if name.startswith('test_'): meth = getattr(cls, name) @@ -35,8 +41,9 @@ from pypy.rpython.lltypesystem import rffi from pypy.rlib.libffi import get_libc_name, CDLL, types from pypy.rlib.test.test_libffi import get_libm_name - space = gettestobjspace(usemodules=('_ffi',)) + space = gettestobjspace(usemodules=('_ffi', '_rawffi')) cls.space = space + cls.w_iswin32 = space.wrap(sys.platform == 'win32') cls.w_libfoo_name = space.wrap(cls.prepare_c_example()) cls.w_libc_name = space.wrap(get_libc_name()) libm_name = get_libm_name(sys.platform) @@ -45,6 +52,13 @@ pow = libm.getpointer('pow', [], types.void) pow_addr = rffi.cast(rffi.LONG, pow.funcsym) cls.w_pow_addr = space.wrap(pow_addr) + # + # these are needed for test_single_float_args + from ctypes import c_float + f_12_34 = c_float(12.34).value + f_56_78 = c_float(56.78).value + f_result = c_float(f_12_34 + f_56_78).value + cls.w_f_12_34_plus_56_78 = space.wrap(f_result) def test_libload(self): import _ffi @@ -54,10 +68,20 @@ import _ffi raises(OSError, _ffi.CDLL, "xxxxx_this_name_does_not_exist_xxxxx") + def test_libload_None(self): + if self.iswin32: + skip("unix specific") + from _ffi import CDLL, types + # this should return *all* loaded libs, dlopen(NULL) + dll = CDLL(None) + # Assume CPython, or PyPy compiled with cpyext + res = dll.getfunc('Py_IsInitialized', [], types.slong)() + assert res == 1 + def test_simple_types(self): from _ffi import types - assert str(types.sint) == '' - assert str(types.uint) == '' + assert str(types.sint) == "" + assert str(types.uint) == "" def test_callfunc(self): from _ffi import CDLL, types @@ -70,10 +94,27 @@ libm = CDLL(self.libm_name) pow = libm.getfunc('pow', [types.double, types.double], types.double) assert pow.getaddr() == self.pow_addr - + + def test_getaddressindll(self): + import sys + from _ffi import CDLL, types + libm = CDLL(self.libm_name) + pow_addr = libm.getaddressindll('pow') + assert pow_addr == self.pow_addr & (sys.maxint*2-1) + + def test_func_fromaddr(self): + import sys + from _ffi import CDLL, types, FuncPtr + libm = CDLL(self.libm_name) + pow_addr = libm.getaddressindll('pow') + pow = FuncPtr.fromaddr(pow_addr, 'pow', [types.double, types.double], + types.double) + assert pow(2, 3) == 8 + + def test_int_args(self): """ - int sum_xy(int x, int y) + DLLEXPORT int sum_xy(int x, int y) { return x+y; } @@ -86,8 +127,8 @@ def test_void_result(self): """ int dummy = 0; - void set_dummy(int val) { dummy = val; } - int get_dummy() { return dummy; } + DLLEXPORT void set_dummy(int val) { dummy = val; } + DLLEXPORT int get_dummy() { return dummy; } """ from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) @@ -96,10 +137,105 @@ assert get_dummy() == 0 assert set_dummy(42) is None assert get_dummy() == 42 + set_dummy(0) + + def test_pointer_args(self): + """ + extern int dummy; // defined in test_void_result + DLLEXPORT int* get_dummy_ptr() { return &dummy; } + DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + get_dummy = libfoo.getfunc('get_dummy', [], types.sint) + get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p) + set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', + [types.void_p, types.sint], + types.void) + assert get_dummy() == 0 + ptr = get_dummy_ptr() + set_val_to_ptr(ptr, 123) + assert get_dummy() == 123 + set_val_to_ptr(ptr, 0) + + def test_convert_pointer_args(self): + """ + extern int dummy; // defined in test_void_result + DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args + DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto + """ + from _ffi import CDLL, types + + class MyPointerWrapper(object): + def __init__(self, value): + self.value = value + def _as_ffi_pointer_(self, ffitype): + assert ffitype is types.void_p + return self.value + + libfoo = CDLL(self.libfoo_name) + get_dummy = libfoo.getfunc('get_dummy', [], types.sint) + get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p) + set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', + [types.void_p, types.sint], + types.void) + assert get_dummy() == 0 + ptr = get_dummy_ptr() + assert type(ptr) in (int, long) + ptr2 = MyPointerWrapper(ptr) + set_val_to_ptr(ptr2, 123) + assert get_dummy() == 123 + set_val_to_ptr(ptr2, 0) + + def test_typed_pointer(self): + from _ffi import types + intptr = types.Pointer(types.sint) # create a typed pointer to sint + assert intptr.deref_pointer() is types.sint + assert str(intptr) == '' + assert types.sint.deref_pointer() is None + raises(TypeError, "types.Pointer(42)") + + def test_pointer_identity(self): + from _ffi import types + x = types.Pointer(types.slong) + y = types.Pointer(types.slong) + z = types.Pointer(types.char) + assert x is y + assert x is not z + + def test_typed_pointer_args(self): + """ + extern int dummy; // defined in test_void_result + DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args + DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto + """ + from _ffi import CDLL, types + + libfoo = CDLL(self.libfoo_name) + intptr = types.Pointer(types.sint) + get_dummy = libfoo.getfunc('get_dummy', [], types.sint) + get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], intptr) + set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', [intptr, types.sint], types.void) + assert get_dummy() == 0 + ptr = get_dummy_ptr() + set_val_to_ptr(ptr, 123) + assert get_dummy() == 123 + set_val_to_ptr(ptr, 0) + + def test_huge_pointer_args(self): + """ + #include + DLLEXPORT long is_null_ptr(void* ptr) { return ptr == NULL; } + """ + import sys + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + is_null_ptr = libfoo.getfunc('is_null_ptr', [types.void_p], types.ulong) + assert not is_null_ptr(sys.maxint+1) def test_unsigned_long_args(self): """ - unsigned long sum_xy_ul(unsigned long x, unsigned long y) + DLLEXPORT unsigned long sum_xy_ul(unsigned long x, unsigned long y) { return x+y; } @@ -114,12 +250,11 @@ def test_unsigned_short_args(self): """ - unsigned short sum_xy_us(unsigned short x, unsigned short y) + DLLEXPORT unsigned short sum_xy_us(unsigned short x, unsigned short y) { return x+y; } """ - import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy_us', [types.ushort, types.ushort], @@ -127,6 +262,166 @@ assert sum_xy(32000, 8000) == 40000 assert sum_xy(60000, 30000) == 90000 % 65536 + def test_unsigned_byte_args(self): + """ + DLLEXPORT unsigned char sum_xy_ub(unsigned char x, unsigned char y) + { + return x+y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_us', [types.ubyte, types.ubyte], + types.ubyte) + assert sum_xy(100, 40) == 140 + assert sum_xy(200, 60) == 260 % 256 + + def test_signed_byte_args(self): + """ + DLLEXPORT signed char sum_xy_sb(signed char x, signed char y) + { + return x+y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_sb', [types.sbyte, types.sbyte], + types.sbyte) + assert sum_xy(10, 20) == 30 + assert sum_xy(100, 28) == -128 + + def test_char_args(self): + """ + DLLEXPORT char my_toupper(char x) + { + return x - ('a'-'A'); + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + my_toupper = libfoo.getfunc('my_toupper', [types.char], + types.char) + assert my_toupper('c') == 'C' + + def test_unichar_args(self): + """ + #include + DLLEXPORT wchar_t sum_xy_wc(wchar_t x, wchar_t y) + { + return x + y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_wc', [types.unichar, types.unichar], + types.unichar) + res = sum_xy(unichr(1000), unichr(2000)) + assert type(res) is unicode + assert ord(res) == 3000 + + def test_single_float_args(self): + """ + DLLEXPORT float sum_xy_float(float x, float y) + { + return x+y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_float', [types.float, types.float], + types.float) + res = sum_xy(12.34, 56.78) + assert res == self.f_12_34_plus_56_78 + + + def test_slonglong_args(self): + """ + DLLEXPORT long long sum_xy_longlong(long long x, long long y) + { + return x+y; + } + """ + from _ffi import CDLL, types + maxint32 = 2147483647 # we cannot really go above maxint on 64 bits + # (and we would not test anything, as there long + # is the same as long long) + + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_longlong', [types.slonglong, types.slonglong], + types.slonglong) + x = maxint32+1 + y = maxint32+2 + res = sum_xy(x, y) + expected = maxint32*2 + 3 + assert res == expected + + def test_ulonglong_args(self): + """ + DLLEXPORT unsigned long long sum_xy_ulonglong(unsigned long long x, + unsigned long long y) + { + return x+y; + } + """ + from _ffi import CDLL, types + maxint64 = 9223372036854775807 # maxint64+1 does not fit into a + # longlong, but it does into a + # ulonglong + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_ulonglong', [types.ulonglong, types.ulonglong], + types.ulonglong) + x = maxint64+1 + y = 2 + res = sum_xy(x, y) + expected = maxint64 + 3 + assert res == expected + + def test_byval_argument(self): + """ + struct Point { + long x; + long y; + }; + + DLLEXPORT long sum_point(struct Point p) { + return p.x + p.y; + } + """ + import _rawffi + from _ffi import CDLL, types + POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')]) + ffi_point = POINT.get_ffi_type() + libfoo = CDLL(self.libfoo_name) + sum_point = libfoo.getfunc('sum_point', [ffi_point], types.slong) + # + p = POINT() + p.x = 30 + p.y = 12 + res = sum_point(p) + assert res == 42 + p.free() + + def test_byval_result(self): + """ + DLLEXPORT struct Point make_point(long x, long y) { + struct Point p; + p.x = x; + p.y = y; + return p; + } + """ + import _rawffi + from _ffi import CDLL, types + POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')]) + ffi_point = POINT.get_ffi_type() + libfoo = CDLL(self.libfoo_name) + make_point = libfoo.getfunc('make_point', [types.slong, types.slong], ffi_point) + # + p = make_point(12, 34) + assert p.x == 12 + assert p.y == 34 + p.free() + def test_TypeError_numargs(self): from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) @@ -142,3 +437,10 @@ def test_OSError_loading(self): from _ffi import CDLL, types raises(OSError, "CDLL('I do not exist')") + + def test_AttributeError_missing_function(self): + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + raises(AttributeError, "libfoo.getfunc('I_do_not_exist', [], types.void)") + libnone = CDLL(None) + raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)") diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -4,13 +4,13 @@ import errno from pypy.rlib import streamio from pypy.rlib.rarithmetic import r_longlong -from pypy.module._file.interp_stream import W_AbstractStream -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror, wrap_oserror_as_ioerror +from pypy.rlib.rstring import StringBuilder +from pypy.module._file.interp_stream import (W_AbstractStream, StreamErrors, + wrap_streamerror, wrap_oserror_as_ioerror) from pypy.module.posix.interp_posix import dispatch_filename from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty, make_weakref_descr -from pypy.interpreter.typedef import interp_attrproperty_w +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, + interp_attrproperty, make_weakref_descr, interp_attrproperty_w) from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -43,7 +43,11 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() - self.direct_close() + try: + self.direct_close() + except StreamErrors, e: + operr = wrap_streamerror(self.space, e, self.w_name) + operr.write_unraisable(self.space, '__del__ of ', self) def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd @@ -160,14 +164,14 @@ if n < 0: return stream.readall() else: - result = [] + result = StringBuilder(n) while n > 0: data = stream.read(n) if not data: break n -= len(data) result.append(data) - return ''.join(result) + return result.build() @unwrap_spec(size=int) def direct_readline(self, size=-1): @@ -345,11 +349,11 @@ may be returned, even if no size parameter was given.""") _decl(locals(), "readline", - """readlines([size]) -> list of strings, each a line from the file. + """readline([size]) -> next line from the file, as a string. -Call readline() repeatedly and return a list of the lines so read. -The optional size argument, if given, is an approximate bound on the -total number of bytes in the lines returned.""") +Retain newline. A non-negative size argument limits the maximum +number of bytes to return (an incomplete line may be returned then). +Return an empty string at EOF.""") _decl(locals(), "readlines", """readlines([size]) -> list of strings, each a line from the file. @@ -553,4 +557,4 @@ @unwrap_spec(file=W_File, encoding="str_or_None", errors="str_or_None") def set_file_encoding(space, file, encoding=None, errors=None): file.encoding = encoding - file.errors = errors \ No newline at end of file + file.errors = errors diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py --- a/pypy/module/_file/test/test_file.py +++ b/pypy/module/_file/test/test_file.py @@ -232,6 +232,29 @@ data = f.read() assert data == "15" + def test_exception_from_close(self): + import os + f = self.file(self.temppath, 'w') + os.close(f.fileno()) + raises(IOError, f.close) # bad file descriptor + + def test_exception_from_del(self): + import os, gc, sys, cStringIO + f = self.file(self.temppath, 'w') + g = cStringIO.StringIO() + preverr = sys.stderr + try: + sys.stderr = g + os.close(f.fileno()) + del f + gc.collect() # bad file descriptor in f.__del__() + finally: + sys.stderr = preverr + import errno + assert os.strerror(errno.EBADF) in g.getvalue() + # the following is a "nice to have" feature that CPython doesn't have + if '__pypy__' in sys.builtin_module_names: + assert self.temppath in g.getvalue() class AppTestConcurrency(object): diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -3,6 +3,8 @@ from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir +UNICODE_REPLACEMENT_CHARACTER = u'\uFFFD' + class EncodeDecodeError(Exception): def __init__(self, start, end, reason): @@ -103,8 +105,12 @@ [DECODEBUF_P], rffi.SSIZE_T) pypy_cjk_dec_inbuf_consumed = llexternal('pypy_cjk_dec_inbuf_consumed', [DECODEBUF_P], rffi.SSIZE_T) +pypy_cjk_dec_replace_on_error = llexternal('pypy_cjk_dec_replace_on_error', + [DECODEBUF_P, rffi.CWCHARP, + rffi.SSIZE_T, rffi.SSIZE_T], + rffi.SSIZE_T) -def decode(codec, stringdata): +def decode(codec, stringdata, errors="strict", errorcb=None, namecb=None): inleft = len(stringdata) inbuf = rffi.get_nonmovingbuffer(stringdata) try: @@ -112,10 +118,12 @@ if not decodebuf: raise MemoryError try: - r = pypy_cjk_dec_chunk(decodebuf) - if r != 0: - multibytecodec_decerror(decodebuf, r) - assert False + while True: + r = pypy_cjk_dec_chunk(decodebuf) + if r == 0: + break + multibytecodec_decerror(decodebuf, r, errors, + errorcb, namecb, stringdata) src = pypy_cjk_dec_outbuf(decodebuf) length = pypy_cjk_dec_outlen(decodebuf) return rffi.wcharpsize2unicode(src, length) @@ -126,7 +134,8 @@ finally: rffi.free_nonmovingbuffer(stringdata, inbuf) -def multibytecodec_decerror(decodebuf, e): +def multibytecodec_decerror(decodebuf, e, errors, + errorcb, namecb, stringdata): if e > 0: reason = "illegal multibyte sequence" esize = e @@ -138,12 +147,27 @@ else: raise RuntimeError # - # if errors == ERROR_REPLACE:... - # if errors == ERROR_IGNORE or errors == ERROR_REPLACE:... + # compute the unicode to use as a replacement -> 'replace', and + # the current position in the input 'unicodedata' -> 'end' start = pypy_cjk_dec_inbuf_consumed(decodebuf) end = start + esize - if 1: # errors == ERROR_STRICT: + if errors == "strict": raise EncodeDecodeError(start, end, reason) + elif errors == "ignore": + replace = u"" + elif errors == "replace": + replace = UNICODE_REPLACEMENT_CHARACTER + else: + assert errorcb + replace, end = errorcb(errors, namecb, reason, + stringdata, start, end) + inbuf = rffi.get_nonmoving_unicodebuffer(replace) + try: + r = pypy_cjk_dec_replace_on_error(decodebuf, inbuf, len(replace), end) + finally: + rffi.free_nonmoving_unicodebuffer(replace, inbuf) + if r == MBERR_NOMEMORY: + raise MemoryError # ____________________________________________________________ # Encoding @@ -165,8 +189,12 @@ [ENCODEBUF_P], rffi.SSIZE_T) pypy_cjk_enc_inbuf_consumed = llexternal('pypy_cjk_enc_inbuf_consumed', [ENCODEBUF_P], rffi.SSIZE_T) +pypy_cjk_enc_replace_on_error = llexternal('pypy_cjk_enc_replace_on_error', + [ENCODEBUF_P, rffi.CCHARP, + rffi.SSIZE_T, rffi.SSIZE_T], + rffi.SSIZE_T) -def encode(codec, unicodedata): +def encode(codec, unicodedata, errors="strict", errorcb=None, namecb=None): inleft = len(unicodedata) inbuf = rffi.get_nonmoving_unicodebuffer(unicodedata) try: @@ -174,14 +202,18 @@ if not encodebuf: raise MemoryError try: - r = pypy_cjk_enc_chunk(encodebuf) - if r != 0: - multibytecodec_encerror(encodebuf, r) - assert False - r = pypy_cjk_enc_reset(encodebuf) - if r != 0: - multibytecodec_encerror(encodebuf, r) - assert False + while True: + r = pypy_cjk_enc_chunk(encodebuf) + if r == 0: + break + multibytecodec_encerror(encodebuf, r, errors, + codec, errorcb, namecb, unicodedata) + while True: + r = pypy_cjk_enc_reset(encodebuf) + if r == 0: + break + multibytecodec_encerror(encodebuf, r, errors, + codec, errorcb, namecb, unicodedata) src = pypy_cjk_enc_outbuf(encodebuf) length = pypy_cjk_enc_outlen(encodebuf) return rffi.charpsize2str(src, length) @@ -192,7 +224,8 @@ finally: rffi.free_nonmoving_unicodebuffer(unicodedata, inbuf) -def multibytecodec_encerror(encodebuf, e): +def multibytecodec_encerror(encodebuf, e, errors, + codec, errorcb, namecb, unicodedata): if e > 0: reason = "illegal multibyte sequence" esize = e @@ -204,9 +237,27 @@ else: raise RuntimeError # - # if errors == ERROR_REPLACE:... - # if errors == ERROR_IGNORE or errors == ERROR_REPLACE:... + # compute the string to use as a replacement -> 'replace', and + # the current position in the input 'unicodedata' -> 'end' start = pypy_cjk_enc_inbuf_consumed(encodebuf) end = start + esize - if 1: # errors == ERROR_STRICT: + if errors == "strict": raise EncodeDecodeError(start, end, reason) + elif errors == "ignore": + replace = "" + elif errors == "replace": + try: + replace = encode(codec, u"?") + except EncodeDecodeError: + replace = "?" + else: + assert errorcb + replace, end = errorcb(errors, namecb, reason, + unicodedata, start, end) + inbuf = rffi.get_nonmovingbuffer(replace) + try: + r = pypy_cjk_enc_replace_on_error(encodebuf, inbuf, len(replace), end) + finally: + rffi.free_nonmovingbuffer(replace, inbuf) + if r == MBERR_NOMEMORY: + raise MemoryError diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -3,6 +3,7 @@ from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs +from pypy.module._codecs.interp_codecs import CodecState class MultibyteCodec(Wrappable): @@ -13,13 +14,13 @@ @unwrap_spec(input=str, errors="str_or_None") def decode(self, space, input, errors=None): - if errors is not None and errors != 'strict': - raise OperationError(space.w_NotImplementedError, # XXX - space.wrap("errors='%s' in _multibytecodec" - % errors)) + if errors is None: + errors = 'strict' + state = space.fromcache(CodecState) # try: - output = c_codecs.decode(self.codec, input) + output = c_codecs.decode(self.codec, input, errors, + state.decode_error_handler, self.name) except c_codecs.EncodeDecodeError, e: raise OperationError( space.w_UnicodeDecodeError, @@ -37,13 +38,13 @@ @unwrap_spec(input=unicode, errors="str_or_None") def encode(self, space, input, errors=None): - if errors is not None and errors != 'strict': - raise OperationError(space.w_NotImplementedError, # XXX - space.wrap("errors='%s' in _multibytecodec" - % errors)) + if errors is None: + errors = 'strict' + state = space.fromcache(CodecState) # try: - output = c_codecs.encode(self.codec, input) + output = c_codecs.encode(self.codec, input, errors, + state.encode_error_handler, self.name) except c_codecs.EncodeDecodeError, e: raise OperationError( space.w_UnicodeEncodeError, diff --git a/pypy/module/_multibytecodec/test/test_app_codecs.py b/pypy/module/_multibytecodec/test/test_app_codecs.py --- a/pypy/module/_multibytecodec/test/test_app_codecs.py +++ b/pypy/module/_multibytecodec/test/test_app_codecs.py @@ -36,6 +36,37 @@ e = raises(UnicodeDecodeError, codec.decode, "~{xyz}").value assert e.args == ('hz', '~{xyz}', 2, 4, 'illegal multibyte sequence') + def test_decode_hz_ignore(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.decode("def~{}abc", errors='ignore') + assert r == (u'def\u5fcf', 9) + r = codec.decode("def~{}abc", 'ignore') + assert r == (u'def\u5fcf', 9) + + def test_decode_hz_replace(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.decode("def~{}abc", errors='replace') + assert r == (u'def\ufffd\u5fcf', 9) + r = codec.decode("def~{}abc", 'replace') + assert r == (u'def\ufffd\u5fcf', 9) + + def test_decode_custom_error_handler(self): + import codecs + codecs.register_error("test.decode_custom_error_handler", + lambda e: (u'\u1234\u5678', e.end)) + u = "abc\xDD".decode("hz", "test.decode_custom_error_handler") + assert u == u'abc\u1234\u5678' + + def test_decode_custom_error_handler_overflow(self): + import codecs + import sys + codecs.register_error("test.test_decode_custom_error_handler_overflow", + lambda e: (u'', sys.maxint + 1)) + raises((IndexError, OverflowError), "abc\xDD".decode, "hz", + "test.test_decode_custom_error_handler_overflow") + def test_encode_hz(self): import _codecs_cn codec = _codecs_cn.getcodec("hz") @@ -54,3 +85,24 @@ assert e.start == 3 assert e.end == 4 assert e.reason == 'illegal multibyte sequence' + + def test_encode_hz_ignore(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.encode(u'abc\u1234def', 'ignore') + assert r == ('abcdef', 7) + assert type(r[0]) is str + + def test_encode_hz_replace(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.encode(u'abc\u1234def', 'replace') + assert r == ('abc?def', 7) + assert type(r[0]) is str + + def test_encode_custom_error_handler(self): + import codecs + codecs.register_error("test.multi_bad_handler", lambda e: (repl, 1)) + repl = u"\u2014" + s = u"\uDDA1".encode("gbk", "test.multi_bad_handler") + assert s == '\xA1\xAA' diff --git a/pypy/module/_multibytecodec/test/test_c_codecs.py b/pypy/module/_multibytecodec/test/test_c_codecs.py --- a/pypy/module/_multibytecodec/test/test_c_codecs.py +++ b/pypy/module/_multibytecodec/test/test_c_codecs.py @@ -36,6 +36,16 @@ assert e.end == 4 assert e.reason == "illegal multibyte sequence" +def test_decode_hz_ignore(): + c = getcodec("hz") + u = decode(c, 'def~{}abc', 'ignore') + assert u == u'def\u5fcf' + +def test_decode_hz_replace(): + c = getcodec("hz") + u = decode(c, 'def~{}abc', 'replace') + assert u == u'def\ufffd\u5fcf' + def test_encode_hz(): c = getcodec("hz") s = encode(c, u'foobar') @@ -51,6 +61,16 @@ assert e.end == 4 assert e.reason == "illegal multibyte sequence" +def test_encode_hz_ignore(): + c = getcodec("hz") + s = encode(c, u'abc\u1234def', 'ignore') + assert s == 'abcdef' + +def test_encode_hz_replace(): + c = getcodec("hz") + s = encode(c, u'abc\u1234def', 'replace') + assert s == 'abc?def' + def test_encode_jisx0208(): c = getcodec('iso2022_jp') s = encode(c, u'\u83ca\u5730\u6642\u592b') diff --git a/pypy/module/_multiprocessing/test/test_memory.py b/pypy/module/_multiprocessing/test/test_memory.py --- a/pypy/module/_multiprocessing/test/test_memory.py +++ b/pypy/module/_multiprocessing/test/test_memory.py @@ -3,7 +3,7 @@ class AppTestMemory: def setup_class(cls): space = gettestobjspace( - usemodules=('_multiprocessing', 'mmap', '_rawffi')) + usemodules=('_multiprocessing', 'mmap', '_rawffi', '_ffi')) cls.space = space def test_address_of(self): diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -43,7 +43,7 @@ unwrap_value(space, push_elem, ll_res, 0, callback_ptr.result, w_res) except OperationError, e: - tbprint(space, space.wrap(e.application_traceback), + tbprint(space, space.wrap(e.get_traceback()), space.wrap(e.errorstr(space))) # force the result to be zero if callback_ptr.result is not None: diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -176,7 +176,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + elif (_MS_WINDOWS and space.is_true(space.isinstance(w_name, space.w_int))): ordinal = space.int_w(w_name) @@ -250,11 +250,18 @@ def get_basic_ffi_type(self): raise NotImplementedError + def descr_get_ffi_type(self, space): + # XXX: this assumes that you have the _ffi module enabled. In the long + # term, probably we will move the code for build structures and arrays + # from _rawffi to _ffi + from pypy.module._ffi.interp_ffi import W_FFIType + return W_FFIType('', self.get_basic_ffi_type(), self) + @unwrap_spec(n=int) def descr_size_alignment(self, space, n=1): return space.newtuple([space.wrap(self.size * n), space.wrap(self.alignment)]) - + class W_DataInstance(Wrappable): def __init__(self, space, size, address=r_uint(0)): @@ -420,7 +427,7 @@ if not (argletter in TYPEMAP_PTR_LETTERS and letter in TYPEMAP_PTR_LETTERS): msg = "Argument %d should be typecode %s, got %s" - raise operationerrfmt(space.w_TypeError, msg, + raise operationerrfmt(space.w_TypeError, msg, i+1, argletter, letter) args_ll.append(arg.ll_buffer) # XXX we could avoid the intermediate list args_ll @@ -473,17 +480,25 @@ alignment = _create_new_accessor('alignment', 'c_alignment') @unwrap_spec(address=r_uint, maxlength=int) -def charp2string(space, address, maxlength=sys.maxint): +def charp2string(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.charp2strn(rffi.cast(rffi.CCHARP, address), maxlength) + charp_addr = rffi.cast(rffi.CCHARP, address) + if maxlength == -1: + s = rffi.charp2str(charp_addr) + else: + s = rffi.charp2strn(charp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) -def wcharp2unicode(space, address, maxlength=sys.maxint): +def wcharp2unicode(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.wcharp2unicoden(rffi.cast(rffi.CWCHARP, address), maxlength) + wcharp_addr = rffi.cast(rffi.CWCHARP, address) + if maxlength == -1: + s = rffi.wcharp2unicode(wcharp_addr) + else: + s = rffi.wcharp2unicoden(wcharp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) diff --git a/pypy/module/_rawffi/structure.py b/pypy/module/_rawffi/structure.py --- a/pypy/module/_rawffi/structure.py +++ b/pypy/module/_rawffi/structure.py @@ -248,7 +248,8 @@ alignment = interp_attrproperty('alignment', W_Structure), fieldoffset = interp2app(W_Structure.descr_fieldoffset), fieldsize = interp2app(W_Structure.descr_fieldsize), - size_alignment = interp2app(W_Structure.descr_size_alignment) + size_alignment = interp2app(W_Structure.descr_size_alignment), + get_ffi_type = interp2app(W_Structure.descr_get_ffi_type), ) W_Structure.typedef.acceptable_as_base_class = False diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,3 +1,4 @@ +from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable @@ -899,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -28,7 +28,7 @@ from pypy.module.exceptions.interp_exceptions import W_SystemExit, _new_exception -from pypy.rlib import rstack # for resume points +from pypy.rlib import rstack, jit # for resume points from pypy.tool import stdlib_opcode as pythonopcode class _AppThunk(AbstractThunk): @@ -47,9 +47,19 @@ def call(self): costate = self.costate w_result = self.space.call_args(self.w_func, self.args) - rstack.resume_point("appthunk", costate, returns=w_result) costate.w_tempval = w_result +class _ResumeThunk(AbstractThunk): + def __init__(self, space, costate, w_frame): + self.space = space + self.costate = costate + self.w_frame = w_frame + + def call(self): + w_result = resume_frame(self.space, self.w_frame) + # costate.w_tempval = w_result #XXX? + + W_CoroutineExit = _new_exception('CoroutineExit', W_SystemExit, """Coroutine killed manually.""") @@ -97,7 +107,6 @@ "cannot switch to an unbound Coroutine")) state = self.costate self.switch() - rstack.resume_point("w_switch", state, space) w_ret, state.w_tempval = state.w_tempval, space.w_None return w_ret @@ -116,7 +125,7 @@ if isinstance(operror, OperationError): w_exctype = operror.w_type w_excvalue = operror.get_w_value(space) - w_exctraceback = operror.application_traceback + w_exctraceback = operror.get_traceback() w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback]) if w_exctype is self.costate.w_CoroutineExit: @@ -151,7 +160,7 @@ space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) - operror.application_traceback = tb + operror.set_traceback(tb) self._kill(operror) @@ -217,75 +226,17 @@ self.parent = space.interp_w(AppCoroutine, w_parent) ec = self.space.getexecutioncontext() self.subctx.setstate(space, w_state) - self.reconstruct_framechain() if space.is_w(w_thunk, space.w_None): - self.thunk = None + if space.is_w(w_state, space.w_None): + self.thunk = None + else: + self.bind(_ResumeThunk(space, self.costate, self.subctx.topframe)) else: w_func, w_args, w_kwds = space.unpackiterable(w_thunk, expected_length=3) args = Arguments.frompacked(space, w_args, w_kwds) self.bind(_AppThunk(space, self.costate, w_func, args)) - def reconstruct_framechain(self): - from pypy.interpreter.pyframe import PyFrame - from pypy.rlib.rstack import resume_state_create - if self.subctx.topframe is None: - self.frame = None - return - - space = self.space - ec = space.getexecutioncontext() - costate = self.costate - # now the big fun of recreating tiny things... - bottom = resume_state_create(None, "yield_current_frame_to_caller_1") - # ("coroutine__bind", state) - _bind_frame = resume_state_create(bottom, "coroutine__bind", costate) - # ("appthunk", costate, returns=w_result) - appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate) - chain = appthunk_frame - for frame in self.subctx.getframestack(): - assert isinstance(frame, PyFrame) - # ("execute_frame", self, executioncontext, returns=w_exitvalue) - chain = resume_state_create(chain, "execute_frame", frame, ec) - code = frame.pycode.co_code - # ("dispatch", self, co_code, ec, returns=next_instr) - chain = resume_state_create(chain, "dispatch", frame, code, ec) - # ("handle_bytecode", self, co_code, ec, returns=next_instr) - chain = resume_state_create(chain, "handle_bytecode", frame, code, - ec) - instr = frame.last_instr - opcode = ord(code[instr]) - map = pythonopcode.opmap - call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], - map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] - assert opcode in call_ops - # ("dispatch_call", self, co_code, next_instr, ec) - chain = resume_state_create(chain, "dispatch_call", frame, code, - instr+3, ec) - instr += 1 - oparg = ord(code[instr]) | ord(code[instr + 1]) << 8 - nargs = oparg & 0xff - nkwds = (oparg >> 8) & 0xff - if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']: - if nkwds == 0: # only positional arguments - chain = resume_state_create(chain, 'CALL_METHOD', frame, - nargs) - else: # includes keyword arguments - chain = resume_state_create(chain, 'CALL_METHOD_KW', frame) - elif opcode == map['CALL_FUNCTION'] and nkwds == 0: - # Only positional arguments - # case1: ("CALL_FUNCTION", f, nargs, returns=w_result) - chain = resume_state_create(chain, 'CALL_FUNCTION', frame, - nargs) - else: - # case2: ("call_function", f, returns=w_result) - chain = resume_state_create(chain, 'call_function', frame) - - # ("w_switch", state, space) - w_switch_frame = resume_state_create(chain, 'w_switch', costate, space) - # ("coroutine_switch", state, returns=incoming_frame) - switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", costate) - self.frame = switch_frame # _mixin_ did not work for methname in StacklessFlags.__dict__: @@ -411,3 +362,45 @@ @unwrap_spec(limit=int) def set_stack_depth_limit(space, limit): rstack.set_stack_depth_limit(limit) + + +# ___________________________________________________________________ +# unpickling trampoline + +def resume_frame(space, w_frame): + from pypy.interpreter.pyframe import PyFrame + frame = space.interp_w(PyFrame, w_frame, can_be_None=True) + w_result = space.w_None + operr = None + executioncontext = frame.space.getexecutioncontext() + while frame is not None: + code = frame.pycode.co_code + instr = frame.last_instr + opcode = ord(code[instr]) + map = pythonopcode.opmap + call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], + map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] + assert opcode in call_ops + instr += 1 + oparg = ord(code[instr]) | ord(code[instr + 1]) << 8 + nargs = oparg & 0xff + nkwds = (oparg >> 8) & 0xff + if nkwds == 0: # only positional arguments + # fast paths leaves things on the stack, pop them + if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']: + frame.dropvalues(nargs + 2) + elif opcode == map['CALL_FUNCTION']: + frame.dropvalues(nargs + 1) + + # small hack: unlink frame out of the execution context, because + # execute_frame will add it there again + executioncontext.topframeref = jit.non_virtual_ref(frame.f_backref()) + frame.last_instr = instr + 1 # continue after the call + try: + w_result = frame.execute_frame(w_result, operr) + except OperationError, operr: + pass + frame = frame.f_backref() + if operr: + raise operr + return w_result diff --git a/pypy/module/_stackless/interp_greenlet.py b/pypy/module/_stackless/interp_greenlet.py --- a/pypy/module/_stackless/interp_greenlet.py +++ b/pypy/module/_stackless/interp_greenlet.py @@ -124,7 +124,7 @@ space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) - operror.application_traceback = tb + operror.set_traceback(tb) # Dead greenlet: turn GreenletExit into a regular return if self.isdead() and operror.match(space, self.costate.w_GreenletExit): args_w = [operror.get_w_value(space)] diff --git a/pypy/module/_stackless/test/test_coroutine.py b/pypy/module/_stackless/test/test_coroutine.py --- a/pypy/module/_stackless/test/test_coroutine.py +++ b/pypy/module/_stackless/test/test_coroutine.py @@ -8,33 +8,6 @@ space = gettestobjspace(usemodules=('_stackless',)) cls.space = space - def test_pickle_coroutine_empty(self): - # this test is limited to basic pickling. - # real stacks can only tested with a stackless pypy build. - import _stackless as stackless - co = stackless.coroutine() - import pickle - pckl = pickle.dumps(co) - co2 = pickle.loads(pckl) - # the empty unpickled coroutine can still be used: - result = [] - co2.bind(result.append, 42) - co2.switch() - assert result == [42] - - def test_pickle_coroutine_bound(self): - import pickle - import _stackless - lst = [4] - co = _stackless.coroutine() - co.bind(lst.append, 2) - pckl = pickle.dumps((co, lst)) - - (co2, lst2) = pickle.loads(pckl) - assert lst2 == [4] - co2.switch() - assert lst2 == [4, 2] - def test_raise_propagate(self): import _stackless as stackless co = stackless.coroutine() diff --git a/pypy/module/_stackless/test/test_greenlet.py b/pypy/module/_stackless/test/test_greenlet.py --- a/pypy/module/_stackless/test/test_greenlet.py +++ b/pypy/module/_stackless/test/test_greenlet.py @@ -72,6 +72,23 @@ g1 = greenlet(f) raises(ValueError, g2.switch) + + def test_exc_info_save_restore(self): + from _stackless import greenlet + import sys + def f(): + try: + raise ValueError('fun') + except: + exc_info = sys.exc_info() + greenlet(h).switch() + assert exc_info == sys.exc_info() + + def h(): + assert sys.exc_info() == (None, None, None) + + greenlet(f).switch() + def test_exception(self): from _stackless import greenlet import sys diff --git a/pypy/module/_stackless/test/test_pickle.py b/pypy/module/_stackless/test/test_pickle.py --- a/pypy/module/_stackless/test/test_pickle.py +++ b/pypy/module/_stackless/test/test_pickle.py @@ -19,9 +19,35 @@ class AppTestPickle: def setup_class(cls): - if not option.runappdirect: - py.test.skip('pure appdirect test (run with -A)') - cls.space = gettestobjspace(usemodules=('_stackless',)) + cls.space = gettestobjspace(usemodules=('_stackless',), CALL_METHOD=True) + + def test_pickle_coroutine_empty(self): + # this test is limited to basic pickling. + # real stacks can only tested with a stackless pypy build. + import _stackless as stackless + co = stackless.coroutine() + import pickle + pckl = pickle.dumps(co) + co2 = pickle.loads(pckl) + # the empty unpickled coroutine can still be used: + result = [] + co2.bind(result.append, 42) + co2.switch() + assert result == [42] + + def test_pickle_coroutine_bound(self): + import pickle + import _stackless + lst = [4] + co = _stackless.coroutine() + co.bind(lst.append, 2) + pckl = pickle.dumps((co, lst)) + + (co2, lst2) = pickle.loads(pckl) + assert lst2 == [4] + co2.switch() + assert lst2 == [4, 2] + def test_simple_ish(self): @@ -58,6 +84,113 @@ finally: del sys.modules['mod'] + def test_pickle_again(self): + + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +output = [] +import _stackless +def f(coro, n, x): + if n == 0: + coro.switch() + return + f(coro, n-1, 2*x) + output.append(x) + +def example(): + main_coro = _stackless.coroutine.getcurrent() + sub_coro = _stackless.coroutine() + sub_coro.bind(f, main_coro, 5, 1) + sub_coro.switch() + + import pickle + pckl = pickle.dumps(sub_coro) + new_coro = pickle.loads(pckl) + pckl = pickle.dumps(new_coro) + newer_coro = pickle.loads(pckl) + + newer_coro.switch() + +example() +assert output == [16, 8, 4, 2, 1] +''' in mod.__dict__ + finally: + del sys.modules['mod'] + + def test_kwargs(self): + + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +output = [] +import _stackless +def f(coro, n, x, step=4): + if n == 0: + coro.switch() + return + f(coro, n-1, 2*x, step=1) + output.append(x) + +def example(): + main_coro = _stackless.coroutine.getcurrent() + sub_coro = _stackless.coroutine() + sub_coro.bind(f, main_coro, 5, 1, 1) + sub_coro.switch() + + import pickle + pckl = pickle.dumps(sub_coro) + new_coro = pickle.loads(pckl) + + new_coro.switch() + +example() +assert output == [16, 8, 4, 2, 1] +''' in mod.__dict__ + finally: + del sys.modules['mod'] + + def test_starstarargs(self): + + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +output = [] +import _stackless +def f(coro, n, x, step=4): + if n == 0: + coro.switch() + return + f(coro, n-1, 2*x, **{'step': 1}) + output.append(x) + +def example(): + main_coro = _stackless.coroutine.getcurrent() + sub_coro = _stackless.coroutine() + sub_coro.bind(f, main_coro, 5, 1, 1) + sub_coro.switch() + + import pickle + pckl = pickle.dumps(sub_coro) + new_coro = pickle.loads(pckl) + + new_coro.switch() + +example() +assert output == [16, 8, 4, 2, 1] +''' in mod.__dict__ + finally: + del sys.modules['mod'] + def test_closure(self): import new, sys @@ -130,8 +263,55 @@ finally: del sys.modules['mod'] + def test_exception_after_unpickling(self): + + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +output = [] +import _stackless +def f(coro, n, x): + if n == 0: + coro.switch() + raise ValueError + try: + f(coro, n-1, 2*x) + finally: + output.append(x) + +def example(): + main_coro = _stackless.coroutine.getcurrent() + sub_coro = _stackless.coroutine() + sub_coro.bind(f, main_coro, 5, 1) + sub_coro.switch() + + import pickle + pckl = pickle.dumps(sub_coro) + new_coro = pickle.loads(pckl) + + try: + sub_coro.switch() + except ValueError: + pass + else: + assert 0 + try: + new_coro.switch() + except ValueError: + pass + else: + assert 0 + +example() +assert output == [16, 8, 4, 2, 1] * 2 +''' in mod.__dict__ + finally: + del sys.modules['mod'] + def test_loop(self): - #skip("happily segfaulting") import new, sys mod = new.module('mod') diff --git a/pypy/module/_stackless/test/test_pickle_infrastructure.py b/pypy/module/_stackless/test/test_pickle_infrastructure.py deleted file mode 100644 --- a/pypy/module/_stackless/test/test_pickle_infrastructure.py +++ /dev/null @@ -1,301 +0,0 @@ -from pypy.conftest import gettestobjspace -from py.test import skip - - -class BaseAppTestPicklePrerequisites(object): - OPTIONS = {} - def setup_class(cls): - space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS) - cls.space = space - - def test_pickle_switch_function(object): - import _stackless, pickle - - sw = _stackless.coroutine.switch.im_func - dump = pickle.dumps(sw) - res = pickle.loads(dump) - - assert res is sw - assert res.func_code is sw.func_code - assert res.func_doc is sw.func_doc - assert res.func_globals is sw.func_globals - - def test_pickle_switch_function_code(object): - import _stackless, pickle - - sw = _stackless.coroutine.switch.im_func.func_code - dump = pickle.dumps(sw) - res = pickle.loads(dump) - - assert res is sw - -class AppTestPicklePrerequisites(BaseAppTestPicklePrerequisites): - pass - -class AppTestPicklePrerequisitesBuiltinShortcut(BaseAppTestPicklePrerequisites): - OPTIONS = {"objspace.std.builtinshortcut": True} - -class FrameCheck(object): - - def __init__(self, name): - self.name = name - - def __eq__(self, frame): - return frame.pycode.co_name == self.name - -class BytecodeCheck(object): - - def __init__(self, code, op, arg): - self.code = code - self.op = chr(op)+chr(arg & 0xff) + chr(arg >> 8 & 0xff) - - def __eq__(self, pos): - return self.code[pos-3:pos] == self.op - -class BaseTestReconstructFrameChain(object): - OPTIONS = {} - - def setup_class(cls): - space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS) - cls.space = space - - from pypy.rlib import rstack - cls.old_resume_state_create = rstack.resume_state_create - - def tr(prevstate, label, *args): - if prevstate is None: - prevstate = [] - return prevstate+[(label, args)] - rstack.resume_state_create = tr - - w_opmap = space.appexec([], """(): - import opcode - - return opcode.opmap - """) - - opmap = space.unwrap(w_opmap) - cls.CALL_FUNCTION = opmap['CALL_FUNCTION'] - cls.CALL_FUNCTION_VAR = opmap['CALL_FUNCTION_VAR'] - cls.CALL_METHOD = opmap['CALL_METHOD'] - - cls.callmethod = getattr(cls, cls.callmethod_label) - - def teardown_class(cls): - from pypy.rlib import rstack - rstack.resume_state_create = cls.old_resume_state_create - - def start(self, w_coro): - self.i = 0 - self.frame_to_check = w_coro.frame - w_coro.frame = None # avoid exploding in kill > __del__ - - def end(self): - assert self.i == len(self.frame_to_check) - - def check_entry(self, label, *args): - frame = self.frame_to_check - assert frame[self.i] == (label, args) - self.i += 1 - - - def test_two_frames_simple(self): - space = self.space - - w_res = space.appexec([], """(): - import _stackless as stackless - import pickle - - main = stackless.coroutine.getcurrent() - d = {'main': main} - - exec \"\"\" -def f(): - g(1) - -def g(x): - main.switch() -\"\"\" in d - f = d['f'] - g = d['g'] - - co = stackless.coroutine() - co.bind(f) - co.switch() - - s = pickle.dumps(co) - co = pickle.loads(s) - - return co, f, g - """) - - w_co, w_f, w_g = space.fixedview(w_res) - - ec = space.getexecutioncontext() - fcode = w_f.code.co_code - gcode = w_g.code.co_code - - self.start(w_co) - e = self.check_entry - e('yield_current_frame_to_caller_1') - e('coroutine__bind', w_co.costate) - e('appthunk', w_co.costate) - # f - e('execute_frame', FrameCheck('f'), ec) - e('dispatch', FrameCheck('f'), fcode, ec) - e('handle_bytecode', FrameCheck('f'), fcode, ec) - e('dispatch_call', FrameCheck('f'), fcode, - BytecodeCheck(fcode, self.CALL_FUNCTION, 1), ec) - e('CALL_FUNCTION', FrameCheck('f'), 1) - # g - e('execute_frame', FrameCheck('g'), ec) - e('dispatch', FrameCheck('g'), gcode, ec) - e('handle_bytecode', FrameCheck('g'), gcode, ec) - e('dispatch_call', FrameCheck('g'), gcode, - BytecodeCheck(gcode, self.callmethod, 0), ec) - e(self.callmethod_label, FrameCheck('g'), 0) - e('w_switch', w_co.costate, space) - e('coroutine_switch', w_co.costate) - self.end() - - def test_two_frames_stararg(self): - space = self.space - - w_res = space.appexec([], """(): - import _stackless as stackless - import pickle - - main = stackless.coroutine.getcurrent() - d = {'main': main} - - exec \"\"\" -def f(): - g(4, 3, d=2, *(1,)) - -def g(a, b, c, d): - main.switch() -\"\"\" in d - f = d['f'] - g = d['g'] - - co = stackless.coroutine() - co.bind(f) - co.switch() - - s = pickle.dumps(co) - co = pickle.loads(s) - - return co, f, g - """) - - w_co, w_f, w_g = space.fixedview(w_res) - - ec = space.getexecutioncontext() - fcode = w_f.code.co_code - gcode = w_g.code.co_code - - self.start(w_co) - e = self.check_entry - e('yield_current_frame_to_caller_1') - e('coroutine__bind', w_co.costate) - e('appthunk', w_co.costate) - # f - e('execute_frame', FrameCheck('f'), ec) - e('dispatch', FrameCheck('f'), fcode, ec) - e('handle_bytecode', FrameCheck('f'), fcode, ec) - e('dispatch_call', FrameCheck('f'), fcode, - BytecodeCheck(fcode, self.CALL_FUNCTION_VAR, 2+(1<<8)), ec) - e('call_function', FrameCheck('f')) - # g - e('execute_frame', FrameCheck('g'), ec) - e('dispatch', FrameCheck('g'), gcode, ec) - e('handle_bytecode', FrameCheck('g'), gcode, ec) - e('dispatch_call', FrameCheck('g'), gcode, - BytecodeCheck(gcode, self.callmethod, 0), ec) - e(self.callmethod_label, FrameCheck('g'), 0) - e('w_switch', w_co.costate, space) - e('coroutine_switch', w_co.costate) - self.end() - - def test_two_frames_method(self): - space = self.space - - w_res = space.appexec([], """(): - import _stackless as stackless - import pickle - import new, sys - - mod = new.module('mod') - sys.modules['mod'] = mod - - main = stackless.coroutine.getcurrent() - d = {'main': main} - - exec \"\"\" -def f(): - a = A() - a.m(1) - -def g(_, x): - main.switch() - -class A(object): - m = g -\"\"\" in d - f = d['f'] - g = d['g'] - A = d['A'] - - # to make pickling work - mod.A = A - A.__module__ = 'mod' - - co = stackless.coroutine() - co.bind(f) - co.switch() - - s = pickle.dumps(co) - co = pickle.loads(s) - - return co, f, g - """) - - w_co, w_f, w_g = space.fixedview(w_res) - - ec = space.getexecutioncontext() - fcode = w_f.code.co_code - gcode = w_g.code.co_code - - self.start(w_co) - e = self.check_entry - e('yield_current_frame_to_caller_1') - e('coroutine__bind', w_co.costate) - e('appthunk', w_co.costate) - # f - e('execute_frame', FrameCheck('f'), ec) - e('dispatch', FrameCheck('f'), fcode, ec) - e('handle_bytecode', FrameCheck('f'), fcode, ec) - e('dispatch_call', FrameCheck('f'), fcode, - BytecodeCheck(fcode, self.callmethod, 1), ec) - e(self.callmethod_label, FrameCheck('f'), 1) - # g - e('execute_frame', FrameCheck('g'), ec) - e('dispatch', FrameCheck('g'), gcode, ec) - e('handle_bytecode', FrameCheck('g'), gcode, ec) - e('dispatch_call', FrameCheck('g'), gcode, - BytecodeCheck(gcode, self.callmethod, 0), ec) - e(self.callmethod_label, FrameCheck('g'), 0) - e('w_switch', w_co.costate, space) - e('coroutine_switch', w_co.costate) - self.end() - -class TestReconstructFrameChain(BaseTestReconstructFrameChain): - callmethod_label = 'CALL_FUNCTION' - -class TestReconstructFrameChain_CALL_METHOD(BaseTestReconstructFrameChain): - OPTIONS = {"objspace.opcodes.CALL_METHOD": True, - } - - callmethod_label = 'CALL_METHOD' - - diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -526,15 +526,7 @@ def array_tostring__Array(space, self): cbuf = self.charbuf() - s = ''.join([cbuf[i] for i in xrange(self.len * mytype.bytes)]) - return self.space.wrap(s) -## -## s = '' -## i = 0 -## while i < self.len * mytype.bytes: -## s += cbuf[i] -## i += 1 -## return self.space.wrap(s) + return self.space.wrap(rffi.charpsize2str(cbuf, self.len * mytype.bytes)) def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): if not isinstance(w_f, W_File): diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -363,42 +363,44 @@ def seek(self, offset, whence): READMAX = 2**18 # 256KB - if whence == 1: - if offset >= 0: - read = r_longlong(0) - while read < offset: - count = offset - read - if count < READMAX: - count = intmask(count) - else: - count = READMAX - read += len(self.read(count)) - else: - pos = self.readlength + offset - self.seek(pos, 0) + + # Make offset relative to the start of the file + if whence == 2: + # Read everything to arrive at the end + while len(self.read(READMAX)) > 0: + pass + offset += self.readlength + elif whence == 1: + offset += self.readlength elif whence == 0: + pass + else: + raise operationerrfmt(self.space.w_ValueError, + "Invalid value for whence: %d", whence) + + # Make offset relative to the current pos + # Rewind iff necessary + if offset < self.readlength: self.stream.seek(0, 0) self.decompressor = W_BZ2Decompressor(self.space) self.readlength = r_longlong(0) self.buffer = "" self.finished = False - read = 0 - while read < offset: - count = offset - read - if count < READMAX: - count = intmask(count) - else: - count = READMAX - length = len(self.read(count)) - read += length - if not length: - break else: - # first measure the length by reading everything left - while len(self.read(READMAX)) > 0: - pass - pos = self.readlength + offset - self.seek(pos, 0) + offset -= self.readlength + + # Seek + read = r_longlong(0) + while read < offset: + count = offset - read + if count < READMAX: + count = intmask(count) + else: + count = READMAX + length = len(self.read(count)) + if not length: + break + read += length def readall(self): w_result = self.decompressor.decompress(self.stream.readall()) diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -39,6 +39,7 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject +import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject import pypy.module.cpyext.longobject @@ -64,6 +65,7 @@ import pypy.module.cpyext.memoryobject import pypy.module.cpyext.codecs import pypy.module.cpyext.pyfile +import pypy.module.cpyext.pystrtod # now that all rffi_platform.Struct types are registered, configure them api.configure_types() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -348,6 +348,7 @@ '_Py_TrueStruct#': ('PyObject*', 'space.w_True'), '_Py_ZeroStruct#': ('PyObject*', 'space.w_False'), '_Py_NotImplementedStruct#': ('PyObject*', 'space.w_NotImplemented'), + '_Py_EllipsisObject#': ('PyObject*', 'space.w_Ellipsis'), 'PyDateTimeAPI': ('PyDateTime_CAPI*', 'None'), } FORWARD_DECLS = [] @@ -561,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() @@ -966,6 +968,7 @@ state = space.fromcache(State) if state.find_extension(name, path) is not None: return + old_context = state.package_context state.package_context = name, path try: from pypy.rlib import rdynload @@ -991,7 +994,7 @@ generic_cpy_call(space, initfunc) state.check_and_raise_exception() finally: - state.package_context = None, None + state.package_context = old_context state.fixup_extension(name, path) @specialize.ll() diff --git a/pypy/module/cpyext/classobject.py b/pypy/module/cpyext/classobject.py --- a/pypy/module/cpyext/classobject.py +++ b/pypy/module/cpyext/classobject.py @@ -31,4 +31,9 @@ return w_result return w_instance.w_class.lookup(space, name) + at cpython_api([PyObject, PyObject, PyObject], PyObject) +def PyClass_New(space, w_bases, w_dict, w_name): + w_classobj = space.gettypefor(W_ClassObject) + return space.call_function(w_classobj, + w_name, w_bases, w_dict) diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py --- a/pypy/module/cpyext/frameobject.py +++ b/pypy/module/cpyext/frameobject.py @@ -1,6 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( - cpython_api, bootstrap_function, PyObjectFields, cpython_struct) + cpython_api, bootstrap_function, PyObjectFields, cpython_struct, + CANNOT_FAIL) from pypy.module.cpyext.pyobject import ( PyObject, Py_DecRef, make_ref, from_ref, track_reference, make_typedescr, get_typedescr) @@ -9,6 +10,7 @@ from pypy.module.cpyext.funcobject import PyCodeObject from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pycode import PyCode +from pypy.interpreter.pytraceback import PyTraceback PyFrameObjectStruct = lltype.ForwardReference() PyFrameObject = lltype.Ptr(PyFrameObjectStruct) @@ -80,3 +82,8 @@ frame = space.interp_w(PyFrame, w_frame) record_application_traceback(space, state.operror, frame, 0) return 0 + + at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL) +def PyTraceBack_Check(space, w_obj): + obj = space.interpclass_w(w_obj) + return obj is not None and isinstance(obj, PyTraceback) diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py --- a/pypy/module/cpyext/funcobject.py +++ b/pypy/module/cpyext/funcobject.py @@ -69,6 +69,10 @@ assert isinstance(w_method, Method) return borrow_from(w_method, w_method.w_class) + at cpython_api([PyObject], PyObject) +def PyClassMethod_New(space, w_function): + return space.call_method(space.builtin, "classmethod", w_function) + def unwrap_list_of_strings(space, w_list): return [space.str_w(w_item) for w_item in space.fixedview(w_list)] diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py --- a/pypy/module/cpyext/intobject.py +++ b/pypy/module/cpyext/intobject.py @@ -4,7 +4,7 @@ from pypy.module.cpyext.api import ( cpython_api, build_type_checkers, PyObject, CONST_STRING, CANNOT_FAIL, Py_ssize_t) -from pypy.rlib.rarithmetic import r_uint +from pypy.rlib.rarithmetic import r_uint, intmask, LONG_TEST import sys PyInt_Check, PyInt_CheckExact = build_type_checkers("Int") @@ -73,13 +73,24 @@ space.wrap("an integer is required, got NULL")) return space.int_w(w_obj) # XXX this is wrong on win64 +LONG_MAX = int(LONG_TEST - 1) + + at cpython_api([rffi.SIZE_T], PyObject) +def PyInt_FromSize_t(space, ival): + """Create a new integer object with a value of ival. If the value exceeds + LONG_MAX, a long integer object is returned. + """ + if ival <= LONG_MAX: + return space.wrap(intmask(ival)) + return space.wrap(ival) + @cpython_api([Py_ssize_t], PyObject) def PyInt_FromSsize_t(space, ival): """Create a new integer object with a value of ival. If the value is larger than LONG_MAX or smaller than LONG_MIN, a long integer object is returned. """ - return space.wrap(ival) # XXX this is wrong on win64 + return space.wrap(ival) @cpython_api([CONST_STRING, rffi.CCHARPP, rffi.INT_real], PyObject) def PyInt_FromString(space, str, pend, base): diff --git a/pypy/module/cpyext/number.py b/pypy/module/cpyext/number.py --- a/pypy/module/cpyext/number.py +++ b/pypy/module/cpyext/number.py @@ -49,6 +49,13 @@ failure. This is the equivalent of the Python expression long(o).""" return space.long(w_obj) + at cpython_api([PyObject], PyObject) +def PyNumber_Index(space, w_obj): + """Returns the o converted to a Python int or long on success or NULL with a + TypeError exception raised on failure. + """ + return space.index(w_obj) + def func_rename(newname): return lambda func: func_with_new_name(func, newname) diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py --- a/pypy/module/cpyext/pyerrors.py +++ b/pypy/module/cpyext/pyerrors.py @@ -57,7 +57,7 @@ if operror: ptype[0] = make_ref(space, operror.w_type) pvalue[0] = make_ref(space, operror.get_w_value(space)) - ptraceback[0] = make_ref(space, space.wrap(operror.application_traceback)) + ptraceback[0] = make_ref(space, space.wrap(operror.get_traceback())) else: ptype[0] = lltype.nullptr(PyObject.TO) pvalue[0] = lltype.nullptr(PyObject.TO) @@ -268,7 +268,7 @@ w_type = operror.w_type w_value = operror.get_w_value(space) - w_tb = space.wrap(operror.application_traceback) + w_tb = space.wrap(operror.get_traceback()) if rffi.cast(lltype.Signed, set_sys_last_vars): space.sys.setdictvalue(space, "last_type", w_type) diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/pystrtod.py @@ -0,0 +1,68 @@ +import errno +from pypy.interpreter.error import OperationError +from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.pyobject import PyObject +from pypy.rlib import rdtoa +from pypy.rlib import rfloat +from pypy.rlib import rposix +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi + + + at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +def PyOS_string_to_double(space, s, endptr, w_overflow_exception): + """Convert a string s to a double, raising a Python + exception on failure. The set of accepted strings corresponds to + the set of strings accepted by Python's float() constructor, + except that s must not have leading or trailing whitespace. + The conversion is independent of the current locale. + + If endptr is NULL, convert the whole string. Raise + ValueError and return -1.0 if the string is not a valid + representation of a floating-point number. + + If endptr is not NULL, convert as much of the string as + possible and set *endptr to point to the first unconverted + character. If no initial segment of the string is the valid + representation of a floating-point number, set *endptr to point + to the beginning of the string, raise ValueError, and return + -1.0. + + If s represents a value that is too large to store in a float + (for example, "1e500" is such a string on many platforms) then + if overflow_exception is NULL return Py_HUGE_VAL (with + an appropriate sign) and don't set any exception. Otherwise, + overflow_exception must point to a Python exception object; + raise that exception and return -1.0. In both cases, set + *endptr to point to the first character after the converted value. + + If any other error occurs during the conversion (for example an + out-of-memory error), set the appropriate Python exception and + return -1.0. + """ + user_endptr = True + try: + if not endptr: + endptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + user_endptr = False + result = rdtoa.dg_strtod(s, endptr) + endpos = (rffi.cast(rffi.LONG, endptr[0]) - + rffi.cast(rffi.LONG, s)) + if endpos == 0 or (not user_endptr and not endptr[0][0] == '\0'): + raise OperationError( + space.w_ValueError, + space.wrap('invalid input at position %s' % endpos)) + if rposix.get_errno() == errno.ERANGE: + rposix.set_errno(0) + if w_overflow_exception is None: + if result > 0: + return rfloat.INFINITY + else: + return -rfloat.INFINITY + else: + raise OperationError(w_overflow_exception, + space.wrap('value too large')) + return result + finally: + if not user_endptr: + lltype.free(endptr, flavor='raw') diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/setobject.py @@ -0,0 +1,46 @@ +from pypy.interpreter.error import OperationError +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, + build_type_checkers) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, + borrow_from, make_ref, from_ref) +from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall +from pypy.objspace.std.setobject import W_SetObject, newset +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject + + +PySet_Check, PySet_CheckExact = build_type_checkers("Set") + + + at cpython_api([PyObject], PyObject) +def PySet_New(space, w_iterable): + if w_iterable is None: + return space.call_function(space.w_set) + else: + return space.call_function(space.w_set, w_iterable) + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Add(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'add', w_obj) + return 0 + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Discard(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'discard', w_obj) + return 0 + + + at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +def PySet_GET_SIZE(space, w_s): + return space.int_w(space.len(w_s)) + + at cpython_api([PyObject], Py_ssize_t, error=-1) +def PySet_Size(space, ref): + if not PySet_Check(space, ref): + raise OperationError(space.w_TypeError, + space.wrap("expected set object")) + return PySet_GET_SIZE(space, ref) diff --git a/pypy/module/cpyext/src/modsupport.c b/pypy/module/cpyext/src/modsupport.c --- a/pypy/module/cpyext/src/modsupport.c +++ b/pypy/module/cpyext/src/modsupport.c @@ -611,8 +611,8 @@ if (result != NULL && n > 0) { for (i = 0; i < n; ++i) { tmp = (PyObject *)va_arg(va, PyObject *); + Py_INCREF(tmp); PyTuple_SET_ITEM(result, i, tmp); - Py_INCREF(tmp); } } return result; diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( cpython_api, cpython_struct, bootstrap_function, build_type_checkers, - PyObjectFields, Py_ssize_t, CONST_STRING) + PyObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL) from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.pyobject import ( PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference, @@ -203,6 +203,10 @@ ref[0] = rffi.cast(PyObject, py_newstr) return 0 + at cpython_api([PyObject, PyObject], rffi.INT, error=CANNOT_FAIL) +def _PyString_Eq(space, w_str1, w_str2): + return space.eq_w(w_str1, w_str2) + @cpython_api([PyObjectP, PyObject], lltype.Void) def PyString_Concat(space, ref, w_newpart): """Create a new string object in *string containing the contents of newpart diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -172,12 +172,6 @@ This is equivalent to (PyBUF_ND).""" raise NotImplementedError - at cpython_api([Py_buffer], lltype.Void) -def PyBuffer_Release(space, view): - """Release the buffer view. This should be called when the buffer - is no longer being used as it may free memory from it.""" - raise NotImplementedError - @cpython_api([rffi.CCHARP], Py_ssize_t, error=CANNOT_FAIL) def PyBuffer_SizeFromFormat(space, format): """Return the implied ~Py_buffer.itemsize from the struct-stype @@ -198,13 +192,6 @@ given shape with the given number of bytes per element.""" raise NotImplementedError - at cpython_api([Py_buffer, PyObject, rffi.VOIDP, Py_ssize_t, rffi.INT_real, rffi.INT_real], rffi.INT_real, error=-1) -def PyBuffer_FillInfo(space, view, obj, buf, len, readonly, infoflags): - """Fill in a buffer-info structure, view, correctly for an exporter that can - only share a contiguous chunk of memory of "unsigned bytes" of the given - length. Return 0 on success and -1 (with raising an error) on error.""" - raise NotImplementedError - @cpython_api([Py_buffer], PyObject) def PyMemoryView_FromBuffer(space, view): """Create a memoryview object wrapping the given buffer-info structure view. @@ -493,39 +480,6 @@ """Create a new Python complex number object from a C Py_complex value.""" raise NotImplementedError - at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) -def PyOS_string_to_double(space, s, endptr, overflow_exception): - """Convert a string s to a double, raising a Python - exception on failure. The set of accepted strings corresponds to - the set of strings accepted by Python's float() constructor, - except that s must not have leading or trailing whitespace. - The conversion is independent of the current locale. - - If endptr is NULL, convert the whole string. Raise - ValueError and return -1.0 if the string is not a valid - representation of a floating-point number. - - If endptr is not NULL, convert as much of the string as - possible and set *endptr to point to the first unconverted - character. If no initial segment of the string is the valid - representation of a floating-point number, set *endptr to point - to the beginning of the string, raise ValueError, and return - -1.0. - - If s represents a value that is too large to store in a float - (for example, "1e500" is such a string on many platforms) then - if overflow_exception is NULL return Py_HUGE_VAL (with - an appropriate sign) and don't set any exception. Otherwise, - overflow_exception must point to a Python exception object; - raise that exception and return -1.0. In both cases, set - *endptr to point to the first character after the converted value. - - If any other error occurs during the conversion (for example an - out-of-memory error), set the appropriate Python exception and - return -1.0. - """ - raise NotImplementedError - @cpython_api([rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_strtod(space, nptr, endptr): """Convert a string to a double. This function behaves like the Standard C @@ -1094,14 +1048,6 @@ """ raise NotImplementedError - at cpython_api([PyObject], PyObject) -def PyImport_ReloadModule(space, m): - """Reload a module. This is best described by referring to the built-in - Python function reload(), as the standard reload() function calls this - function directly. Return a new reference to the reloaded module, or NULL - with an exception set on failure (the module still exists in this case).""" - raise NotImplementedError - @cpython_api([rffi.CCHARP, PyObject], PyObject) def PyImport_ExecCodeModule(space, name, co): """Given a module name (possibly of the form package.module) and a code @@ -1140,13 +1086,6 @@ of the bytecode file, in little-endian byte order.""" raise NotImplementedError - at cpython_api([], PyObject) -def PyImport_GetModuleDict(space): - """Return the dictionary used for the module administration (a.k.a. - sys.modules). Note that this is a per-interpreter variable.""" - borrow_from() - raise NotImplementedError - @cpython_api([PyObject], PyObject) def PyImport_GetImporter(space, path): """Return an importer object for a sys.path/pkg.__path__ item @@ -1701,13 +1640,6 @@ """ raise NotImplementedError - at cpython_api([rffi.SIZE_T], PyObject) -def PyInt_FromSize_t(space, ival): - """Create a new integer object with a value of ival. If the value exceeds - LONG_MAX, a long integer object is returned. - """ - raise NotImplementedError - @cpython_api([PyObject], rffi.ULONGLONG, error=-1) def PyInt_AsUnsignedLongLongMask(space, io): """Will first attempt to cast the object to a PyIntObject or @@ -1920,13 +1852,6 @@ Reference counts are still not increased in this case.""" raise NotImplementedError - at cpython_api([PyObject], PyObject) -def PyNumber_Index(space, o): - """Returns the o converted to a Python int or long on success or NULL with a - TypeError exception raised on failure. - """ - raise NotImplementedError - @cpython_api([PyObject, rffi.INT_real], PyObject) def PyNumber_ToBase(space, n, base): """Returns the integer n converted to base as a string with a base @@ -2254,15 +2179,6 @@ standard C library function exit(status).""" raise NotImplementedError - at cpython_api([PyObject, Py_ssize_t, Py_ssize_t], PyObject) -def PyTuple_GetSlice(space, p, low, high): - """Take a slice of the tuple pointed to by p from low to high and return it - as a new tuple. - - This function used an int type for low and high. This might - require changes in your code for properly supporting 64-bit systems.""" - raise NotImplementedError - @cpython_api([], rffi.INT_real, error=CANNOT_FAIL) def PyTuple_ClearFreeList(space): """Clear the free list. Return the total number of freed items. @@ -2275,14 +2191,6 @@ """ raise NotImplementedError - at cpython_api([PyTypeObjectPtr], lltype.Void) -def PyType_Modified(space, type): - """Invalidate the internal lookup cache for the type and all of its - subtypes. This function must be called after any manual - modification of the attributes or base classes of the type. - """ - raise NotImplementedError - @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL) def PyType_IS_GC(space, o): """Return true if the type object includes support for the cycle detector; this diff --git a/pypy/module/cpyext/test/test_classobject.py b/pypy/module/cpyext/test/test_classobject.py --- a/pypy/module/cpyext/test/test_classobject.py +++ b/pypy/module/cpyext/test/test_classobject.py @@ -40,3 +40,14 @@ assert not isinstance(api.PyObject_GetAttr(w_instance, space.wrap('f')), Function) # _PyInstance_Lookup returns the raw descriptor assert isinstance(api._PyInstance_Lookup(w_instance, space.wrap('f')), Function) + + def test_pyclass_new(self, space, api): + w_bases = space.newtuple([]) + w_dict = space.newdict() + w_name = space.wrap("C") + w_class = api.PyClass_New(w_bases, w_dict, w_name) + assert not space.isinstance_w(w_class, space.w_type) + w_instance = space.call_function(w_class) + assert api.PyInstance_Check(w_instance) + assert space.is_true(space.call_method(space.builtin, "isinstance", + w_instance, w_class)) diff --git a/pypy/module/cpyext/test/test_eval.py b/pypy/module/cpyext/test/test_eval.py --- a/pypy/module/cpyext/test/test_eval.py +++ b/pypy/module/cpyext/test/test_eval.py @@ -193,3 +193,32 @@ return args assert module.call_func(f) == ("text", 42, None) assert module.call_method("text") == 2 + + def test_CallFunctionObjArgs(self): + module = self.import_extension('foo', [ + ("call_func", "METH_VARARGS", + """ + PyObject *t = PyString_FromString("t"); + PyObject *res = PyObject_CallFunctionObjArgs( + PyTuple_GetItem(args, 0), + Py_None, NULL); + Py_DECREF(t); + return res; + """), + ("call_method", "METH_VARARGS", + """ + PyObject *t = PyString_FromString("t"); + PyObject *count = PyString_FromString("count"); + PyObject *res = PyObject_CallMethodObjArgs( + PyTuple_GetItem(args, 0), + count, t, NULL); + Py_DECREF(t); + Py_DECREF(count); + return res; + """), + ]) + def f(*args): + return args + assert module.call_func(f) == (None,) + assert module.call_method("text") == 2 + diff --git a/pypy/module/cpyext/test/test_frameobject.py b/pypy/module/cpyext/test/test_frameobject.py --- a/pypy/module/cpyext/test/test_frameobject.py +++ b/pypy/module/cpyext/test/test_frameobject.py @@ -64,3 +64,31 @@ # Cython does not work on CPython as well... assert exc.traceback.tb_lineno == 42 # should be 48 assert frame.f_lineno == 42 + + def test_traceback_check(self): + module = self.import_extension('foo', [ + ("traceback_check", "METH_NOARGS", + """ + int check; + PyObject *type, *value, *tb; + PyObject *ret = PyRun_String("XXX", Py_eval_input, + Py_None, Py_None); + if (ret) { + Py_DECREF(ret); + PyErr_SetString(PyExc_AssertionError, "should raise"); + return NULL; + } + PyErr_Fetch(&type, &value, &tb); + check = PyTraceBack_Check(tb); + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(tb); + if (check) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } + """), + ]) + assert module.traceback_check() diff --git a/pypy/module/cpyext/test/test_funcobject.py b/pypy/module/cpyext/test/test_funcobject.py --- a/pypy/module/cpyext/test/test_funcobject.py +++ b/pypy/module/cpyext/test/test_funcobject.py @@ -44,3 +44,19 @@ assert w_code.co_firstlineno == 3 rffi.free_charp(filename) rffi.free_charp(funcname) + + def test_classmethod(self, space, api): + w_function = space.appexec([], """(): + def method(x): return x + return method + """) + w_class = space.call_function(space.w_type, space.wrap("C"), + space.newtuple([]), space.newdict()) + w_instance = space.call_function(w_class) + # regular instance method + space.setattr(w_class, space.wrap("method"), w_function) + assert space.is_w(space.call_method(w_instance, "method"), w_instance) + # now a classmethod + w_classmethod = api.PyClassMethod_New(w_function) + space.setattr(w_class, space.wrap("classmethod"), w_classmethod) + assert space.is_w(space.call_method(w_instance, "classmethod"), w_class) diff --git a/pypy/module/cpyext/test/test_intobject.py b/pypy/module/cpyext/test/test_intobject.py --- a/pypy/module/cpyext/test/test_intobject.py +++ b/pypy/module/cpyext/test/test_intobject.py @@ -50,3 +50,19 @@ ]) assert module.from_string() == 0x1234 assert type(module.from_string()) is int + + def test_size_t(self): + module = self.import_extension('foo', [ + ("values", "METH_NOARGS", + """ + return Py_BuildValue("NNNN", + PyInt_FromSize_t(123), + PyInt_FromSize_t((size_t)-1), + PyInt_FromSsize_t(123), + PyInt_FromSsize_t((size_t)-1)); + """), + ]) + values = module.values() + types = [type(x) for x in values] + assert types == [int, long, int, int] + diff --git a/pypy/module/cpyext/test/test_number.py b/pypy/module/cpyext/test/test_number.py --- a/pypy/module/cpyext/test/test_number.py +++ b/pypy/module/cpyext/test/test_number.py @@ -25,6 +25,15 @@ assert api.PyInt_CheckExact(w_l) w_l = api.PyNumber_Int(space.wrap(2 << 65)) assert api.PyLong_CheckExact(w_l) + w_l = api.PyNumber_Int(space.wrap(42.3)) + assert api.PyInt_CheckExact(w_l) + + def test_number_index(self, space, api): + w_l = api.PyNumber_Index(space.wrap(123L)) + assert api.PyLong_CheckExact(w_l) + w_l = api.PyNumber_Index(space.wrap(42.3)) + assert w_l is None + api.PyErr_Clear() def test_numbermethods(self, space, api): assert "ab" == space.unwrap( diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -0,0 +1,93 @@ +import math + +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype + + +class TestPyOS_string_to_double(BaseApiTest): + + def test_simple_float(self, api): + s = rffi.str2charp('0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == 0.4 + rffi.free_charp(s) + + def test_empty_string(self, api): + s = rffi.str2charp('') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_bad_string(self, api): + s = rffi.str2charp(' 0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_overflow_pos(self, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r > 0 + rffi.free_charp(s) + + def test_overflow_neg(self, api): + s = rffi.str2charp('-1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r < 0 + rffi.free_charp(s) + + def test_overflow_exc(self, space, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, space.w_ValueError) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_endptr_number(self, api): + s = rffi.str2charp('0.4') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_tail(self, api): + s = rffi.str2charp('0.4 foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_no_conversion(self, api): + s = rffi.str2charp('foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == -1.0 + raises(ValueError) + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + api.PyErr_Clear() + rffi.free_charp(s) + lltype.free(endp, flavor='raw') diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_setobject.py @@ -0,0 +1,29 @@ +import py + +from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace + + +class TestTupleObject(BaseApiTest): + def test_setobj(self, space, api): + assert not api.PySet_Check(space.w_None) + assert api.PySet_Add(space.w_None, space.w_None) == -1 + api.PyErr_Clear() + w_set = space.call_function(space.w_set) + space.call_method(w_set, 'update', space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + assert api.PySet_GET_SIZE(w_set) == 4 + raises(TypeError, api.PySet_Size(space.newlist([]))) + api.PyErr_Clear() + + def test_set_add_discard(self, space, api): + w_set = api.PySet_New(None) + assert api.PySet_Size(w_set) == 0 + w_set = api.PySet_New(space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + api.PySet_Add(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 5 + api.PySet_Discard(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 4 diff --git a/pypy/module/cpyext/test/test_sliceobject.py b/pypy/module/cpyext/test/test_sliceobject.py --- a/pypy/module/cpyext/test/test_sliceobject.py +++ b/pypy/module/cpyext/test/test_sliceobject.py @@ -67,3 +67,14 @@ """), ]) assert module.nullslice() == slice(None, None, None) + + def test_ellipsis(self): + module = self.import_extension('foo', [ + ("get_ellipsis", "METH_NOARGS", + """ + PyObject *ret = Py_Ellipsis; + Py_INCREF(ret); + return ret; + """), + ]) + assert module.get_ellipsis() is Ellipsis diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -283,3 +283,7 @@ self.raises(space, api, TypeError, api.PyString_AsEncodedObject, space.wrap(2), lltype.nullptr(rffi.CCHARP.TO), lltype.nullptr(rffi.CCHARP.TO) ) + + def test_eq(self, space, api): + assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) + assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) diff --git a/pypy/module/cpyext/test/test_sysmodule.py b/pypy/module/cpyext/test/test_sysmodule.py --- a/pypy/module/cpyext/test/test_sysmodule.py +++ b/pypy/module/cpyext/test/test_sysmodule.py @@ -22,12 +22,13 @@ Py_RETURN_NONE; """)]) import sys, StringIO + prev = sys.stdout sys.stdout = StringIO.StringIO() try: module.writestdout() assert sys.stdout.getvalue() == "format: 42\n" finally: - sys.stdout = sys.__stdout__ + sys.stdout = prev class TestSysModule(BaseApiTest): def test_sysmodule(self, space, api): diff --git a/pypy/module/cpyext/test/test_tupleobject.py b/pypy/module/cpyext/test/test_tupleobject.py --- a/pypy/module/cpyext/test/test_tupleobject.py +++ b/pypy/module/cpyext/test/test_tupleobject.py @@ -42,3 +42,9 @@ assert api.PyTuple_Size(atuple) == 2 assert space.eq_w(space.getitem(atuple, space.wrap(0)), space.wrap(0)) assert space.eq_w(space.getitem(atuple, space.wrap(1)), space.wrap(1)) + + def test_getslice(self, space, api): + w_tuple = space.newtuple([space.wrap(i) for i in range(10)]) + w_slice = api.PyTuple_GetSlice(w_tuple, 3, -3) + assert space.eq_w(w_slice, + space.newtuple([space.wrap(i) for i in range(3, 7)])) diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -367,3 +367,14 @@ data, len(u), lltype.nullptr(rffi.CCHARP.TO)) rffi.free_wcharp(data) + def test_format(self, space, api): + w_format = space.wrap(u'hi %s') + w_args = space.wrap((u'test',)) + w_formated = api.PyUnicode_Format(w_format, w_args) + assert space.unwrap(w_formated) == space.unwrap(space.mod(w_format, w_args)) + + def test_join(self, space, api): + w_sep = space.wrap(u'') + w_seq = space.wrap([u'a', u'b']) + w_joined = api.PyUnicode_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == u'ab' diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,6 +7,7 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) + assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py --- a/pypy/module/cpyext/tupleobject.py +++ b/pypy/module/cpyext/tupleobject.py @@ -79,3 +79,10 @@ Py_DecRef(space, ref[0]) ref[0] = make_ref(space, py_newtuple) return 0 + + at cpython_api([PyObject, Py_ssize_t, Py_ssize_t], PyObject) +def PyTuple_GetSlice(space, w_obj, low, high): + """Take a slice of the tuple pointed to by p from low to high and return it + as a new tuple. + """ + return space.getslice(w_obj, space.wrap(low), space.wrap(high)) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -650,3 +650,13 @@ name = space.str_w(w_name) w_obj = w_type.lookup(name) return borrow_from(w_type, w_obj) + + at cpython_api([PyTypeObjectPtr], lltype.Void) +def PyType_Modified(space, w_obj): + """Invalidate the internal lookup cache for the type and all of its + subtypes. This function must be called after any manual + modification of the attributes or base classes of the type. + """ + # PyPy already takes care of direct modifications to type.__dict__ + # (which is a W_DictProxyObject). + pass diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -523,3 +523,11 @@ copies sizeof(Py_UNICODE) * length bytes from source to target""" for i in range(0, length): target[i] = source[i] + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Format(space, w_format, w_args): + return space.mod(w_format, w_args) + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -21,6 +21,10 @@ """Return the referenced object from a weak reference. If the referent is no longer live, returns None. This function returns a borrowed reference. """ + return PyWeakref_GET_OBJECT(space, w_ref) + + at cpython_api([PyObject], PyObject) +def PyWeakref_GET_OBJECT(space, w_ref): return borrow_from(w_ref, space.call_function(w_ref)) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -622,7 +622,13 @@ try: if find_info: w_mod = load_module(space, w_modulename, find_info) - w_mod = space.getitem(space.sys.get("modules"), w_modulename) + try: + w_mod = space.getitem(space.sys.get("modules"), + w_modulename) + except OperationError, oe: + if not oe.match(space, space.w_KeyError): + raise + raise OperationError(space.w_ImportError, w_modulename) if w_parent is not None: space.setattr(w_parent, space.wrap(partname), w_mod) return w_mod diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py --- a/pypy/module/imp/test/test_import.py +++ b/pypy/module/imp/test/test_import.py @@ -37,6 +37,7 @@ ambig = "imamodule = 1", test_reload = "def test():\n raise ValueError\n", infinite_reload = "import infinite_reload; reload(infinite_reload)", + del_sys_module = "import sys\ndel sys.modules['del_sys_module']\n", ) root.ensure("notapackage", dir=1) # empty, no __init__.py setuppkg("pkg", @@ -562,6 +563,14 @@ except ImportError: pass + def test_del_from_sys_modules(self): + try: + import del_sys_module + except ImportError: + pass # ok + else: + assert False, 'should not work' + class TestAbi: def test_abi_tag(self): space1 = gettestobjspace(soabi='TEST') diff --git a/pypy/module/math/__init__.py b/pypy/module/math/__init__.py --- a/pypy/module/math/__init__.py +++ b/pypy/module/math/__init__.py @@ -4,6 +4,7 @@ class Module(MixedModule): appleveldefs = { + 'factorial' : 'app_math.factorial' } interpleveldefs = { @@ -40,7 +41,6 @@ 'isnan' : 'interp_math.isnan', 'trunc' : 'interp_math.trunc', 'fsum' : 'interp_math.fsum', - 'factorial' : 'interp_math.factorial', 'asinh' : 'interp_math.asinh', 'acosh' : 'interp_math.acosh', 'atanh' : 'interp_math.atanh', diff --git a/pypy/module/math/app_math.py b/pypy/module/math/app_math.py new file mode 100644 --- /dev/null +++ b/pypy/module/math/app_math.py @@ -0,0 +1,13 @@ +def factorial(x): + """Find x!.""" + if isinstance(x, float): + fl = int(x) + if fl != x: + raise ValueError("float arguments must be integral") + x = fl + if x < 0: + raise ValueError("x must be >= 0") + res = 1 + for i in range(1, x + 1): + res *= i + return res diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -373,22 +373,6 @@ hi = v return space.wrap(hi) -def factorial(space, w_x): - """Find x!.""" - if space.isinstance_w(w_x, space.w_float): - fl = space.float_w(w_x) - if math.floor(fl) != fl: - raise OperationError(space.w_ValueError, - space.wrap("float arguments must be integral")) - w_x = space.long(w_x) - x = space.int_w(w_x) - if x < 0: - raise OperationError(space.w_ValueError, space.wrap("x must be >= 0")) - w_res = space.wrap(1) - for i in range(1, x + 1): - w_res = space.mul(w_res, space.wrap(i)) - return w_res - def log1p(space, w_x): """Find log(x + 1).""" return math1(space, rfloat.log1p, w_x) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -8,11 +8,15 @@ interpleveldefs = { 'array': 'interp_numarray.SingleDimArray', 'zeros': 'interp_numarray.zeros', + 'empty': 'interp_numarray.zeros', + 'ones': 'interp_numarray.ones', # ufuncs + 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', 'copysign': 'interp_ufuncs.copysign', 'exp': 'interp_ufuncs.exp', + 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', 'negative': 'interp_ufuncs.negative', @@ -20,4 +24,7 @@ 'sign': 'interp_ufuncs.sign', } - appleveldefs = {} + appleveldefs = { + 'average': 'app_numpy.average', + 'mean': 'app_numpy.mean', + } diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/app_numpy.py @@ -0,0 +1,11 @@ +import numpy + +def average(a): + # This implements a weighted average, for now we don't implement the + # weighting, just the average part! + return mean(a) + +def mean(a): + if not hasattr(a, "mean"): + a = numpy.array(a) + return a.mean() \ No newline at end of file diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/compile.py @@ -0,0 +1,49 @@ + +""" This is a set of tools for standalone compiling of numpy expressions. +It should not be imported by the module itself +""" + +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray + +class BogusBytecode(Exception): + pass + +def create_array(size): + a = SingleDimArray(size) + for i in range(size): + a.storage[i] = float(i % 10) + return a + +class TrivialSpace(object): + def wrap(self, x): + return x + +def numpy_compile(bytecode, array_size): + space = TrivialSpace() + stack = [] + i = 0 + for b in bytecode: + if b == 'a': + stack.append(create_array(array_size)) + i += 1 + elif b == 'f': + stack.append(FloatWrapper(1.2)) + elif b == '+': + right = stack.pop() + stack.append(stack.pop().descr_add(space, right)) + elif b == '-': + right = stack.pop() + stack.append(stack.pop().descr_sub(space, right)) + elif b == '*': + right = stack.pop() + stack.append(stack.pop().descr_mul(space, right)) + elif b == '/': + right = stack.pop() + stack.append(stack.pop().descr_div(space, right)) + else: + print "Unknown opcode: %s" % b + raise BogusBytecode() + if len(stack) != 1: + print "Bogus bytecode, uneven stack length" + raise BogusBytecode() + return stack[0] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,7 +1,7 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable from pypy.interpreter.error import operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name @@ -44,9 +44,13 @@ self.invalidates = [] def invalidated(self): + if self.invalidates: + self._invalidated() + + def _invalidated(self): for arr in self.invalidates: arr.force_if_needed() - self.invalidates = [] + del self.invalidates[:] def _binop_impl(function): signature = Signature() @@ -80,18 +84,36 @@ def get_concrete(self): raise NotImplementedError + def descr_get_shape(self, space): + return space.newtuple([self.descr_len(space)]) + def descr_len(self, space): return self.get_concrete().descr_len(space) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - return self.get_concrete().descr_getitem(space, item) + def descr_getitem(self, space, w_idx): + # TODO: indexing by tuples + start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) + if step == 0: + # Single index + return space.wrap(self.get_concrete().getitem(start)) + else: + # Slice + res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) + return space.wrap(res) @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): self.invalidated() return self.get_concrete().descr_setitem(space, item, value) + def descr_mean(self, space): + s = 0 + concrete = self.get_concrete() + size = concrete.find_size() + for i in xrange(size): + s += concrete.getitem(i) + return space.wrap(s / size) + class FloatWrapper(BaseArray): """ @@ -119,6 +141,10 @@ self.forced_result = None self.signature = signature + def _del_sources(self): + # Function for deleting references to source arrays, to allow garbage-collecting them + raise NotImplementedError + def compute(self): i = 0 signature = self.signature @@ -135,6 +161,7 @@ def force_if_needed(self): if self.forced_result is None: self.forced_result = self.compute() + self._del_sources() def get_concrete(self): self.force_if_needed() @@ -145,6 +172,13 @@ return self.forced_result.eval(i) return self._eval(i) + def find_size(self): + if self.forced_result is not None: + # The result has been computed and sources may be unavailable + return self.forced_result.find_size() + return self._find_size() + + class Call1(VirtualArray): _immutable_fields_ = ["function", "values"] @@ -153,7 +187,10 @@ self.function = function self.values = values - def find_size(self): + def _del_sources(self): + self.values = None + + def _find_size(self): return self.values.find_size() def _eval(self, i): @@ -164,13 +201,18 @@ Intermediate class for performing binary operations. """ _immutable_fields_ = ["function", "left", "right"] + def __init__(self, function, left, right, signature): VirtualArray.__init__(self, signature) self.function = function self.left = left self.right = right - def find_size(self): + def _del_sources(self): + self.left = None + self.right = None + + def _find_size(self): try: return self.left.find_size() except ValueError: @@ -181,6 +223,58 @@ lhs, rhs = self.left.eval(i), self.right.eval(i) return self.function(lhs, rhs) +class ViewArray(BaseArray): + """ + Class for representing views of arrays, they will reflect changes of parent + arrays. Example: slices + """ + _immutable_fields_ = ["parent"] + + def __init__(self, parent, signature): + BaseArray.__init__(self) + self.signature = signature + self.parent = parent + self.invalidates = parent.invalidates + + def get_concrete(self): + # in fact, ViewArray never gets "concrete" as it never stores data. + # This implementation is needed for BaseArray getitem/setitem to work, + # can be refactored. + return self + + def eval(self, i): + return self.parent.eval(self.calc_index(i)) + + def getitem(self, item): + return self.parent.getitem(self.calc_index(item)) + + @unwrap_spec(item=int, value=float) + def descr_setitem(self, space, item, value): + return self.parent.descr_setitem(space, self.calc_index(item), value) + + def descr_len(self, space): + return space.wrap(self.find_size()) + + def calc_index(self, item): + raise NotImplementedError + +class SingleDimSlice(ViewArray): + _immutable_fields_ = ["start", "stop", "step", "size"] + static_signature = Signature() + + def __init__(self, start, stop, step, slice_length, parent, signature): + ViewArray.__init__(self, parent, signature) + self.start = start + self.stop = stop + self.step = step + self.size = slice_length + + def find_size(self): + return self.size + + def calc_index(self, item): + return (self.start + item * self.step) + class SingleDimArray(BaseArray): signature = Signature() @@ -215,10 +309,8 @@ def descr_len(self, space): return space.wrap(self.size) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - item = self.getindex(space, item) - return space.wrap(self.storage[item]) + def getitem(self, item): + return self.storage[item] @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): @@ -238,14 +330,23 @@ i += 1 return space.wrap(arr) - at unwrap_spec(ObjSpace, int) + at unwrap_spec(size=int) def zeros(space, size): return space.wrap(SingleDimArray(size)) + at unwrap_spec(size=int) +def ones(space, size): + arr = SingleDimArray(size) + for i in xrange(size): + arr.storage[i] = 1.0 + return space.wrap(arr) BaseArray.typedef = TypeDef( 'numarray', __new__ = interp2app(descr_new_numarray), + + shape = GetSetProperty(BaseArray.descr_get_shape), + __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), __setitem__ = interp2app(BaseArray.descr_setitem), @@ -254,4 +355,6 @@ __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), __div__ = interp2app(BaseArray.descr_div), -) \ No newline at end of file + + mean = interp2app(BaseArray.descr_mean), +) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -8,22 +8,24 @@ def ufunc(func): signature = Signature() - @unwrap_spec(array=BaseArray) - def impl(space, array): - w_res = Call1(func, array, array.signature.transition(signature)) - array.invalidates.append(w_res) - return w_res + def impl(space, w_obj): + if isinstance(w_obj, BaseArray): + w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) + w_obj.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() - @unwrap_spec(larray=BaseArray, rarray=BaseArray) - def impl(space, larray, rarray): - new_sig = larray.signature.transition(signature).transition(rarray.signature) - w_res = Call2(func, larray, rarray, new_sig) - larray.invalidates.append(w_res) - rarray.invalidates.append(w_res) - return w_res + def impl(space, w_lhs, w_rhs): + if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): + new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) + w_res = Call2(func, w_lhs, w_rhs, new_sig) + w_lhs.invalidates.append(w_res) + w_rhs.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @ufunc @@ -60,6 +62,10 @@ return 1.0 / value @ufunc +def floor(value): + return math.floor(value) + + at ufunc def sign(value): if value == 0.0: return 0.0 diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -16,4 +16,14 @@ v3 = ar.descr_add(space, FloatWrapper(1.0)) assert v2.signature is v3.signature v4 = ar.descr_add(space, ar) - assert v1.signature is v4.signature \ No newline at end of file + assert v1.signature is v4.signature + + def test_slice_signature(self, space): + ar = SingleDimArray(10) + v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1))) + v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1))) + assert v1.signature is v2.signature + + v3 = ar.descr_add(space, v1) + v4 = ar.descr_add(space, v2) + assert v3.signature is v4.signature \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_module.py b/pypy/module/micronumpy/test/test_module.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_module.py @@ -0,0 +1,13 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + + +class AppTestNumPyModule(BaseNumpyAppTest): + def test_mean(self): + from numpy import array, mean + assert mean(array(range(5))) == 2.0 + assert mean(range(5)) == 2.0 + + def test_average(self): + from numpy import array, average + assert average(range(10)) == 4.5 + assert average(array(range(10))) == 4.5 \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,6 +18,25 @@ a[13] = 5.3 assert a[13] == 5.3 + def test_empty(self): + """ + Test that empty() works. + """ + + from numpy import empty + a = empty(2) + a[1] = 1.0 + assert a[1] == 1.0 + + def test_ones(self): + from numpy import ones + a = ones(3) + assert len(a) == 3 + assert a[0] == 1 + raises(IndexError, "a[3]") + a[2] = 4 + assert a[2] == 4 + def test_iterator_init(self): from numpy import array a = array(range(5)) @@ -46,6 +65,15 @@ assert len(a) == 5 assert len(a + a) == 5 + def test_shape(self): + from numpy import array + a = array(range(5)) + assert a.shape == (5,) + b = a + a + assert b.shape == (5,) + c = a[:3] + assert c.shape == (3,) + def test_add(self): from numpy import array a = array(range(5)) @@ -138,4 +166,51 @@ b = a + a c = b + b b[1] = 5 - assert c[1] == 4 \ No newline at end of file + assert c[1] == 4 + + def test_getslice(self): + from numpy import array + a = array(range(5)) + s = a[1:5] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[i+1] + + def test_getslice_step(self): + from numpy import array + a = array(range(10)) + s = a[1:9:2] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[2*i+1] + + def test_slice_update(self): + from numpy import array + a = array(range(5)) + s = a[0:3] + s[1] = 10 + assert a[1] == 10 + a[2] = 20 + assert s[2] == 20 + + + def test_slice_invaidate(self): + # check that slice shares invalidation list with + from numpy import array + a = array(range(5)) + s = a[0:2] + b = array([10,11]) + c = s + b + a[0] = 100 + assert c[0] == 10 + assert c[1] == 12 + d = s + b + a[1] = 101 + assert d[0] == 110 + assert d[1] == 12 + + def test_mean(self): + from numpy import array, mean + a = array(range(5)) + assert a.mean() == 2.0 + assert a[:4].mean() == 1.5 \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -3,6 +3,13 @@ class AppTestUfuncs(BaseNumpyAppTest): + def test_single_item(self): + from numpy import negative, sign, minimum + + assert negative(5.0) == -5.0 + assert sign(-0.0) == 0.0 + assert minimum(2.0, 3.0) == 2.0 + def test_negative(self): from numpy import array, negative @@ -60,6 +67,15 @@ for i in range(4): assert b[i] == reference[i] + def test_floor(self): + from numpy import array, floor + + reference = [-2.0, -1.0, 0.0, 1.0, 1.0] + a = array([-1.4, -1.0, 0.0, 1.0, 1.4]) + b = floor(a) + for i in range(5): + assert b[i] == reference[i] + def test_copysign(self): from numpy import array, copysign diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,8 +1,9 @@ from pypy.jit.metainterp.test.support import LLJitMixin +from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call1, Call2, add, mul) + FloatWrapper, Call1, Call2, SingleDimSlice, add, mul) from pypy.module.micronumpy.interp_ufuncs import negative - +from pypy.module.micronumpy.compile import numpy_compile class FakeSpace(object): pass @@ -91,4 +92,54 @@ self.meta_interp(f, [5], listops=True, backendopt=True) # This is 3, not 2 because there is a bridge for the exit. - self.check_loop_count(3) \ No newline at end of file + self.check_loop_count(3) + + def test_slice(self): + space = self.space + + def f(i): + step = 3 + ar = SingleDimArray(step*i) + s = SingleDimSlice(0, step*i, step, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s, s, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 1, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + + def test_slice2(self): + space = self.space + + def f(i): + step1 = 2 + step2 = 3 + ar = SingleDimArray(step2*i) + s1 = SingleDimSlice(0, step1*i, step1, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + s2 = SingleDimSlice(0, step2*i, step2, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s1, s2, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 2, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + +class TestTranslation(object): + def test_compile(self): + x = numpy_compile('aa+f*f/a-', 10) + x = x.compute() + assert isinstance(x, SingleDimArray) + assert x.size == 10 + assert x.storage[0] == 0 + assert x.storage[1] == ((1 + 1) * 1.2) / 1.2 - 1 + + def test_translation(self): + # we import main to check if the target compiles + from pypy.translator.goal.targetnumpystandalone import main + from pypy.rpython.annlowlevel import llstr + + interpret(main, [llstr('af+'), 100]) diff --git a/pypy/module/operator/app_operator.py b/pypy/module/operator/app_operator.py --- a/pypy/module/operator/app_operator.py +++ b/pypy/module/operator/app_operator.py @@ -4,6 +4,7 @@ This module exports a set of operators as functions. E.g. operator.add(x,y) is equivalent to x+y. ''' +from __pypy__ import builtinify def countOf(a,b): 'countOf(a, b) -- Return the number of times b occurs in a.' @@ -66,50 +67,56 @@ a[b:c] = d __setslice__ = setslice -class attrgetter(object): - def __init__(self, attr, *attrs): - self.attrs = (attr,) + attrs +def attrgetter(attr, *attrs): + if attrs: + getters = [single_attr_getter(a) for a in (attr,) + attrs] + def getter(obj): + return tuple([getter(obj) for getter in getters]) + else: + getter = single_attr_getter(attr) + return builtinify(getter) - def _resolve_attr(self, obj, attr): - last = 0 - while True: - try: - dot = attr.find(".", last) - except AttributeError: - raise TypeError - if dot > 0: - obj = getattr(obj, attr[last:dot]) - last = dot + 1 - else: - return getattr(obj, attr[last:]) +def single_attr_getter(attr): + if not isinstance(attr, str): + if not isinstance(attr, unicode): + def _raise_typeerror(obj): + raise TypeError("argument must be a string, not %r" % + (type(attr).__name__,)) + return _raise_typeerror + attr = attr.encode('ascii') + # + def make_getter(name, prevfn=None): + if prevfn is None: + def getter(obj): + return getattr(obj, name) + else: + def getter(obj): + return getattr(prevfn(obj), name) + return getter + # + last = 0 + getter = None + while True: + dot = attr.find(".", last) + if dot < 0: break + getter = make_getter(attr[last:dot], getter) + last = dot + 1 + return make_getter(attr[last:], getter) - def __call__(self, obj): - if len(self.attrs) == 1: - return self._resolve_attr(obj, self.attrs[0]) - return tuple(self._resolve_attr(obj, attr) for attr in self.attrs) -class itemgetter(object): +def itemgetter(item, *items): + if items: + list_of_indices = [item] + list(items) + def getter(obj): + return tuple([obj[i] for i in list_of_indices]) + else: + def getter(obj): + return obj[item] + return builtinify(getter) - def __init__(self, item, *args): - self.items = args - self.item = item - def __call__(self, obj): - result = obj[self.item] - - if self.items: - list = [result] + [obj[item] for item in self.items] - return tuple(list) - - return result - -class methodcaller(object): - - def __init__(self, method_name, *args, **kwargs): - self.method_name = method_name - self.args = args - self.kwargs = kwargs - - def __call__(self, obj): - return getattr(obj, self.method_name)(*self.args, **self.kwargs) +def methodcaller(method_name, *args, **kwargs): + def call(obj): + return getattr(obj, method_name)(*args, **kwargs) + return builtinify(call) diff --git a/pypy/module/oracle/__init__.py b/pypy/module/oracle/__init__.py --- a/pypy/module/oracle/__init__.py +++ b/pypy/module/oracle/__init__.py @@ -28,6 +28,7 @@ appleveldefs = { 'version': 'app_oracle.version', + 'paramstyle': 'app_oracle.paramstyle', 'makedsn': 'app_oracle.makedsn', 'TimestampFromTicks': 'app_oracle.TimestampFromTicks', } diff --git a/pypy/module/oracle/app_oracle.py b/pypy/module/oracle/app_oracle.py --- a/pypy/module/oracle/app_oracle.py +++ b/pypy/module/oracle/app_oracle.py @@ -1,4 +1,5 @@ version = '5.0.0' +paramstyle = 'named' class Warning(StandardError): pass diff --git a/pypy/module/oracle/config.py b/pypy/module/oracle/config.py --- a/pypy/module/oracle/config.py +++ b/pypy/module/oracle/config.py @@ -16,6 +16,7 @@ return space.str_w(w_obj) def w_string(space, buf, len=-1): + #assert type(len) is int if len < 0: return space.wrap(rffi.charp2str(buf)) else: diff --git a/pypy/module/oracle/interp_connect.py b/pypy/module/oracle/interp_connect.py --- a/pypy/module/oracle/interp_connect.py +++ b/pypy/module/oracle/interp_connect.py @@ -159,9 +159,20 @@ # set the internal and external names; these are needed for global # transactions but are limited in terms of the lengths of the strings if twophase: - raise OperationError( - interp_error.get(space).w_NotSupportedError, - space.wrap("XXX write me")) + status = roci.OCIAttrSet( + self.serverHandle, roci.OCI_HTYPE_SERVER, + "cx_Oracle", 0, + roci.OCI_ATTR_INTERNAL_NAME, + self.environment.errorHandle) + self.environment.checkForError( + status, "Connection_Connect(): set internal name") + status = roci.OCIAttrSet( + self.serverHandle, roci.OCI_HTYPE_SERVER, + "cx_Oracle", 0, + roci.OCI_ATTR_EXTERNAL_NAME, + self.environment.errorHandle) + self.environment.checkForError( + status, "Connection_Connect(): set external name") # allocate the session handle handleptr = lltype.malloc(rffi.CArrayPtr(roci.OCISession).TO, @@ -371,6 +382,7 @@ finally: stringBuffer.clear() lltype.free(foundptr, flavor='raw') + lltype.free(handleptr, flavor='raw') # eliminate the authorization handle immediately, if applicable if authInfo: diff --git a/pypy/module/oracle/interp_cursor.py b/pypy/module/oracle/interp_cursor.py --- a/pypy/module/oracle/interp_cursor.py +++ b/pypy/module/oracle/interp_cursor.py @@ -459,7 +459,7 @@ self.environment.checkForError( status, "Cursor_ItemDescription(): name") - name = rffi.charpsize2str(nameptr[0], lenptr[0]) + name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0])) finally: lltype.free(nameptr, flavor='raw') lltype.free(lenptr, flavor='raw') diff --git a/pypy/module/oracle/interp_object.py b/pypy/module/oracle/interp_object.py --- a/pypy/module/oracle/interp_object.py +++ b/pypy/module/oracle/interp_object.py @@ -38,7 +38,7 @@ self.environment.checkForError( status, "ObjectType_Initialize(): get schema name") - self.schema = rffi.charpsize2str(nameptr[0], lenptr[0]) + self.schema = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0])) # determine the name of the type status = roci.OCIAttrGet( @@ -50,7 +50,7 @@ self.environment.checkForError( status, "ObjectType_Initialize(): get schema name") - self.name = rffi.charpsize2str(nameptr[0], lenptr[0]) + self.name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0])) finally: lltype.free(nameptr, flavor='raw') lltype.free(lenptr, flavor='raw') @@ -301,7 +301,7 @@ connection.environment.checkForError( status, "ObjectAttribute_Initialize(): get name") - self.name = rffi.charpsize2str(nameptr[0], lenptr[0]) + self.name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0])) finally: lltype.free(nameptr, flavor='raw') lltype.free(lenptr, flavor='raw') @@ -428,7 +428,7 @@ strValue = rffi.cast(roci.Ptr(roci.OCIString), value)[0] ptr = roci.OCIStringPtr(environment.handle, strValue) size = roci.OCIStringSize(environment.handle, strValue) - return config.w_string(space, ptr, size) + return config.w_string(space, ptr, rffi.cast(lltype.Signed, size)) elif typeCode == roci.OCI_TYPECODE_NUMBER: return transform.OracleNumberToPythonFloat( environment, diff --git a/pypy/module/oracle/interp_pool.py b/pypy/module/oracle/interp_pool.py --- a/pypy/module/oracle/interp_pool.py +++ b/pypy/module/oracle/interp_pool.py @@ -100,11 +100,13 @@ status, "SessionPool_New(): create pool") self.w_name = config.w_string(space, poolnameptr[0], - poolnamelenptr[0]) + rffi.cast(lltype.Signed, poolnamelenptr[0])) finally: user_buf.clear() password_buf.clear() dsn_buf.clear() + lltype.free(poolnameptr, flavor='raw') + lltype.free(poolnamelenptr, flavor='raw') return space.wrap(self) @@ -128,10 +130,19 @@ self.checkConnected(space) + if __args__.keywords: + keywords = __args__.keywords + ["pool"] + else: + keywords = ["pool"] + if __args__.keywords_w: + keywords_w = __args__.keywords_w + [space.wrap(self)] + else: + keywords_w = [space.wrap(self)] + newargs = Arguments(space, __args__.arguments_w, - __args__.keywords + ["pool"], - __args__.keywords_w + [space.wrap(self)]) + keywords, + keywords_w) return space.call_args(self.w_connectionType, newargs) def release(self, space, w_connection): diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -279,6 +279,7 @@ self.actualLength, self.returnCode, allocatedElements, actualElementsPtr, roci.OCI_DEFAULT) + nameBuffer.clear() else: status = roci.OCIBindByPos( self.boundCursorHandle, bindHandlePtr, @@ -601,6 +602,7 @@ def getValueProc(self, space, pos): ptr = rffi.ptradd(self.data, pos * self.bufferSize) length = rffi.cast(roci.Ptr(roci.ub4), ptr)[0] + length = rffi.cast(lltype.Signed, length) ptr = rffi.ptradd(ptr, rffi.sizeof(roci.ub4)) return space.wrap(rffi.charpsize2str(ptr, length)) @@ -732,6 +734,7 @@ finally: rffi.keep_buffer_alive_until_here(textbuf, text) lltype.free(sizeptr, flavor='raw') + format_buf.clear() if isinstance(self, VT_NumberAsString): return w_strvalue @@ -778,6 +781,8 @@ format_buf.ptr, format_buf.size, None, 0, dataptr) + text_buf.clear() + format_buf.clear() self.environment.checkForError( status, "NumberVar_SetValue(): from long") return @@ -810,6 +815,8 @@ format_buf.ptr, format_buf.size, nls_params, len(nls_params), dataptr) + text_buf.clear() + format_buf.clear() self.environment.checkForError( status, "NumberVar_SetValue(): from decimal") return diff --git a/pypy/module/oracle/roci.py b/pypy/module/oracle/roci.py --- a/pypy/module/oracle/roci.py +++ b/pypy/module/oracle/roci.py @@ -73,7 +73,8 @@ defines = ''' OCI_ATTR_SERVER OCI_ATTR_SESSION OCI_ATTR_USERNAME OCI_ATTR_PASSWORD OCI_ATTR_STMT_TYPE OCI_ATTR_PARAM OCI_ATTR_PARAM_COUNT OCI_ATTR_ROW_COUNT - OCI_ATTR_NAME OCI_ATTR_SCALE OCI_ATTR_PRECISION OCI_ATTR_IS_NULL + OCI_ATTR_NAME OCI_ATTR_INTERNAL_NAME OCI_ATTR_EXTERNAL_NAME + OCI_ATTR_SCALE OCI_ATTR_PRECISION OCI_ATTR_IS_NULL OCI_ATTR_DATA_SIZE OCI_ATTR_DATA_TYPE OCI_ATTR_REF_TDO OCI_ATTR_SCHEMA_NAME OCI_ATTR_TYPE_NAME OCI_ATTR_TYPECODE OCI_ATTR_NUM_TYPE_ATTRS OCI_ATTR_LIST_TYPE_ATTRS diff --git a/pypy/module/oracle/test/test_connect.py b/pypy/module/oracle/test/test_connect.py --- a/pypy/module/oracle/test/test_connect.py +++ b/pypy/module/oracle/test/test_connect.py @@ -41,6 +41,10 @@ if hasattr(self, 'cnx'): self.cnx.close() + def test_constants(self): + assert '.' in oracle.version + assert oracle.paramstyle == 'named' + def test_connect(self): self.cnx = oracle.connect(self.username, self.password, self.tnsentry, threaded=True) @@ -49,6 +53,13 @@ assert self.cnx.tnsentry == self.tnsentry assert isinstance(self.cnx.version, str) + def test_connect_twophase(self): + self.cnx = oracle.connect(self.username, self.password, + self.tnsentry, twophase=True) + assert self.cnx.username == self.username + assert self.cnx.password == self.password + assert self.cnx.tnsentry == self.tnsentry + def test_singleArg(self): self.cnx = oracle.connect("%s/%s@%s" % (self.username, self.password, self.tnsentry)) diff --git a/pypy/module/posix/app_posix.py b/pypy/module/posix/app_posix.py --- a/pypy/module/posix/app_posix.py +++ b/pypy/module/posix/app_posix.py @@ -107,6 +107,9 @@ def tmpnam(): """Return an absolute pathname of a file that did not exist at the time the call is made.""" + from warnings import warn + warn(RuntimeWarning("tmpnam is a potential security risk to your program")) + import tempfile return tempfile.mktemp() @@ -114,6 +117,9 @@ """Return an absolute pathname of a file that did not exist at the time the call is made. The directory and a prefix may be specified as strings; they may be omitted or None if not needed.""" + from warnings import warn + warn(RuntimeWarning("tempnam is a potential security risk to your program")) + import tempfile return tempfile.mktemp('', prefix or 'tmp', dir) diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -847,6 +847,21 @@ assert os.path.basename(s1).startswith(prefix or 'tmp') assert os.path.basename(s2).startswith(prefix or 'tmp') + def test_tmpnam_warning(self): + import warnings, os + # + def f_tmpnam_warning(): os.tmpnam() # a single line + # + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + f_tmpnam_warning() + assert len(w) == 1 + assert issubclass(w[-1].category, RuntimeWarning) + assert "potential security risk" in str(w[-1].message) + # check that the warning points to the call to os.tmpnam(), + # not to some code inside app_posix.py + assert w[-1].lineno == f_tmpnam_warning.func_code.co_firstlineno + class AppTestEnvironment(object): def setup_class(cls): diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -7,13 +7,16 @@ interpleveldefs = { 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', + 'set_compile_hook': 'interp_jit.set_compile_hook', + 'DebugMergePoint': 'interp_resop.W_DebugMergePoint', } def setup_after_space_initialization(self): # force the __extend__ hacks to occur early - import pypy.module.pypyjit.interp_jit + from pypy.module.pypyjit.interp_jit import pypyjitdriver # add the 'defaults' attribute from pypy.rlib.jit import PARAMETERS space = self.space + pypyjitdriver.space = space w_obj = space.wrap(PARAMETERS) space.setattr(space.wrap(self), space.wrap('defaults'), w_obj) diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -12,12 +12,16 @@ from pypy.interpreter.pycode import PyCode, CO_GENERATOR from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pyopcode import ExitFrame +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap from pypy.rlib.objectmodel import we_are_translated +from pypy.rlib.nonconst import NonConstant +from pypy.jit.metainterp.resoperation import rop +from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes PyFrame._virtualizable2_ = ['last_instr', 'pycode', - 'valuestackdepth', 'valuestack_w[*]', - 'fastlocals_w[*]', + 'valuestackdepth', 'locals_stack_w[*]', 'last_exception', 'lastblock', 'is_being_profiled', @@ -44,11 +48,65 @@ return (bytecode.co_flags & CO_GENERATOR) != 0 +def wrap_oplist(space, logops, operations): + list_w = [] + for op in operations: + if op.getopnum() == rop.DEBUG_MERGE_POINT: + list_w.append(space.wrap(debug_merge_point_from_boxes( + op.getarglist()))) + else: + list_w.append(space.wrap(logops.repr_of_resop(op))) + return list_w + class PyPyJitDriver(JitDriver): reds = ['frame', 'ec'] greens = ['next_instr', 'is_being_profiled', 'pycode'] virtualizables = ['frame'] + def on_compile(self, logger, looptoken, operations, type, next_instr, + is_being_profiled, ll_pycode): + from pypy.rpython.annlowlevel import cast_base_ptr_to_instance + + space = self.space + cache = space.fromcache(Cache) + if cache.in_recursion: + return + if space.is_true(cache.w_compile_hook): + logops = logger._make_log_operations() + list_w = wrap_oplist(space, logops, operations) + pycode = cast_base_ptr_to_instance(PyCode, ll_pycode) + cache.in_recursion = True + try: + space.call_function(cache.w_compile_hook, + space.wrap('main'), + space.wrap(type), + space.newtuple([pycode, + space.wrap(next_instr), + space.wrap(is_being_profiled)]), + space.newlist(list_w)) + except OperationError, e: + e.write_unraisable(space, "jit hook ", cache.w_compile_hook) + cache.in_recursion = False + + def on_compile_bridge(self, logger, orig_looptoken, operations, n): + space = self.space + cache = space.fromcache(Cache) + if cache.in_recursion: + return + if space.is_true(cache.w_compile_hook): + logops = logger._make_log_operations() + list_w = wrap_oplist(space, logops, operations) + cache.in_recursion = True + try: + space.call_function(cache.w_compile_hook, + space.wrap('main'), + space.wrap('bridge'), + space.wrap(n), + space.newlist(list_w)) + except OperationError, e: + e.write_unraisable(space, "jit hook ", cache.w_compile_hook) + cache.in_recursion = False + pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location, get_jitcell_at = get_jitcell_at, set_jitcell_at = set_jitcell_at, @@ -149,3 +207,35 @@ '''For testing. Invokes callable(...), but without letting the JIT follow the call.''' return space.call_args(w_callable, __args__) + +class Cache(object): + in_recursion = False + + def __init__(self, space): + self.w_compile_hook = space.w_None + + at unwrap_spec(ObjSpace, W_Root) +def set_compile_hook(space, w_hook): + """ set_compile_hook(hook) + + Set a compiling hook that will be called each time a loop is compiled. + The hook will be called with the following signature: + hook(merge_point_type, loop_type, greenkey or guard_number, operations) + + for now merge point type is always `main` + + loop_type can be either `loop` `entry_bridge` or `bridge` + in case loop is not `bridge`, greenkey will be a set of constants + for jit merge point. in case it's `main` it'll be a tuple + (code, offset, is_being_profiled) + + Note that jit hook is not reentrant. It means that if the code + inside the jit hook is itself jitted, it will get compiled, but the + jit hook won't be called for that. + + XXX write down what else + """ + cache = space.fromcache(Cache) + cache.w_compile_hook = w_hook + cache.in_recursion = NonConstant(False) + return space.w_None diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/interp_resop.py @@ -0,0 +1,41 @@ + +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.gateway import unwrap_spec, interp2app +from pypy.interpreter.pycode import PyCode +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.annlowlevel import cast_base_ptr_to_instance +from pypy.rpython.lltypesystem.rclass import OBJECT + +class W_DebugMergePoint(Wrappable): + """ A class representing debug_merge_point JIT operation + """ + + def __init__(self, mp_no, offset, pycode): + self.mp_no = mp_no + self.offset = offset + self.pycode = pycode + + def descr_repr(self, space): + return space.wrap('DebugMergePoint()') + + at unwrap_spec(mp_no=int, offset=int, pycode=PyCode) +def new_debug_merge_point(space, w_tp, mp_no, offset, pycode): + return W_DebugMergePoint(mp_no, offset, pycode) + +def debug_merge_point_from_boxes(boxes): + mp_no = boxes[0].getint() + offset = boxes[2].getint() + llcode = lltype.cast_opaque_ptr(lltype.Ptr(OBJECT), + boxes[4].getref_base()) + pycode = cast_base_ptr_to_instance(PyCode, llcode) + assert pycode is not None + return W_DebugMergePoint(mp_no, offset, pycode) + +W_DebugMergePoint.typedef = TypeDef( + 'DebugMergePoint', + __new__ = interp2app(new_debug_merge_point), + __doc__ = W_DebugMergePoint.__doc__, + __repr__ = interp2app(W_DebugMergePoint.descr_repr), + code = interp_attrproperty('pycode', W_DebugMergePoint), +) diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,8 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof', '_weakref']: + 'posix', '_socket', '_sre', '_lsprof', '_weakref', + '__pypy__', 'cStringIO']: return True return False diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -0,0 +1,126 @@ + +import py +from pypy.conftest import gettestobjspace, option +from pypy.interpreter.pycode import PyCode +from pypy.interpreter.gateway import interp2app +from pypy.jit.metainterp.history import LoopToken +from pypy.jit.metainterp.resoperation import ResOperation, rop +from pypy.jit.metainterp.logger import Logger +from pypy.rpython.annlowlevel import (cast_instance_to_base_ptr, + cast_base_ptr_to_instance) +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.module.pypyjit.interp_jit import pypyjitdriver +from pypy.jit.tool.oparser import parse +from pypy.jit.metainterp.typesystem import llhelper + +class MockSD(object): + class cpu(object): + ts = llhelper + +class AppTestJitHook(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("Can't run this test with -A") + space = gettestobjspace(usemodules=('pypyjit',)) + cls.space = space + w_f = space.appexec([], """(): + def f(): + pass + return f + """) + cls.w_f = w_f + ll_code = cast_instance_to_base_ptr(w_f.code) + code_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, ll_code) + logger = Logger(MockSD()) + + oplist = parse(""" + [i1, i2] + i3 = int_add(i1, i2) + debug_merge_point(0, 0, 0, 0, ConstPtr(ptr0)) + guard_true(i3) [] + """, namespace={'ptr0': code_gcref}).operations + + def interp_on_compile(): + pypyjitdriver.on_compile(logger, LoopToken(), oplist, 'loop', + 0, False, ll_code) + + def interp_on_compile_bridge(): + pypyjitdriver.on_compile_bridge(logger, LoopToken(), oplist, 0) + + cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) + cls.w_on_compile_bridge = space.wrap(interp2app(interp_on_compile_bridge)) + + def test_on_compile(self): + import pypyjit + all = [] + + def hook(*args): + assert args[0] == 'main' + assert args[1] in ['loop', 'bridge'] + all.append(args[2:]) + + self.on_compile() + pypyjit.set_compile_hook(hook) + assert not all + self.on_compile() + assert len(all) == 1 + assert all[0][0][0].co_name == 'f' + assert all[0][0][1] == 0 + assert all[0][0][2] == False + assert len(all[0][1]) == 3 + assert 'int_add' in all[0][1][0] + self.on_compile_bridge() + assert len(all) == 2 + pypyjit.set_compile_hook(None) + self.on_compile() + assert len(all) == 2 + + def test_on_compile_exception(self): + import pypyjit, sys, cStringIO + + def hook(*args): + 1/0 + + pypyjit.set_compile_hook(hook) + s = cStringIO.StringIO() + prev = sys.stderr + sys.stderr = s + try: + self.on_compile() + finally: + sys.stderr = prev + assert 'jit hook' in s.getvalue() + assert 'ZeroDivisionError' in s.getvalue() + + def test_non_reentrant(self): + import pypyjit + l = [] + + def hook(*args): + l.append(None) + self.on_compile() + self.on_compile_bridge() + + pypyjit.set_compile_hook(hook) + self.on_compile() + assert len(l) == 1 # and did not crash + self.on_compile_bridge() + assert len(l) == 2 # and did not crash + + def test_on_compile_types(self): + import pypyjit + l = [] + + def hook(*args): + l.append(args) + + pypyjit.set_compile_hook(hook) + self.on_compile() + dmp = l[0][3][1] + assert isinstance(dmp, pypyjit.DebugMergePoint) + assert dmp.code is self.f.func_code + + def test_creation(self): + import pypyjit + dmp = pypyjit.DebugMergePoint(0, 0, self.f.func_code) + assert dmp.code is self.f.func_code diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -24,3 +24,13 @@ i += 1 assert list(gen(3)) == [0, 1, 4] + +def test_interface_residual_call(): + space = gettestobjspace(usemodules=['pypyjit']) + space.appexec([], """(): + import pypyjit + def f(*args, **kwds): + return (args, kwds) + res = pypyjit.residual_call(f, 4, x=6) + assert res == ((4,), {'x': 6}) + """) diff --git a/pypy/module/pypyjit/test/test_pypy_c.py b/pypy/module/pypyjit/test/test_pypy_c.py deleted file mode 100644 --- a/pypy/module/pypyjit/test/test_pypy_c.py +++ /dev/null @@ -1,430 +0,0 @@ -from pypy.conftest import gettestobjspace, option -from pypy.tool.udir import udir -import py -from py.test import skip -import sys, os, re -import subprocess - -class BytecodeTrace(list): - def get_opnames(self, prefix=""): - return [op.getopname() for op in self - if op.getopname().startswith(prefix)] - - def __repr__(self): - return "%s%s" % (self.bytecode, list.__repr__(self)) - -ZERO_OP_BYTECODES = [ - 'POP_TOP', - 'ROT_TWO', - 'ROT_THREE', - 'DUP_TOP', - 'ROT_FOUR', - 'NOP', - 'DUP_TOPX', - 'LOAD_CONST', - 'JUMP_FORWARD', - #'JUMP_ABSOLUTE' in theory, but contains signals stuff - #'LOAD_FAST' should be here, but currently needs a guard for nonzeroness - 'STORE_FAST', - ] - - -r_bridge = re.compile(r"bridge out of Guard (\d+)") - -def from_entry_bridge(text, allparts): - firstline = text.splitlines()[0] - if 'entry bridge' in firstline: - return True - match = r_bridge.search(firstline) - if match: - search = '' - for part in allparts: - if search in part: - break - else: - raise AssertionError, "%s not found??" % (search,) - return from_entry_bridge(part, allparts) - return False - -def test_from_entry_bridge(): - assert from_entry_bridge( - "# Loop 4 : entry bridge with 31 ops\n[p0, etc", []) - assert not from_entry_bridge( - "# Loop 1 : loop with 31 ops\n[p0, p1, etc", []) - assert not from_entry_bridge( - "# bridge out of Guard 5 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : loop with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n"]) - assert from_entry_bridge( - "# bridge out of Guard 5 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : entry bridge with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n"]) - assert not from_entry_bridge( - "# bridge out of Guard 51 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : loop with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n", - "# bridge out of Guard 5 with 13 ops\n" - "[p0, p1]\n" - "guard_other(p1, descr=)\n"]) - assert from_entry_bridge( - "# bridge out of Guard 51 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : entry bridge with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n", - "# bridge out of Guard 5 with 13 ops\n" - "[p0, p1]\n" - "guard_other(p1, descr=)\n"]) - - -class PyPyCJITTests(object): - def run_source(self, source, expected_max_ops, *testcases, **kwds): - assert isinstance(expected_max_ops, int) - threshold = kwds.pop('threshold', 3) - self.count_debug_merge_point = \ - kwds.pop('count_debug_merge_point', True) - if kwds: - raise TypeError, 'Unsupported keyword arguments: %s' % kwds.keys() - source = py.code.Source(source) - filepath = self.tmpdir.join('case%d.py' % self.counter) - logfilepath = filepath.new(ext='.log') - self.__class__.counter += 1 - f = filepath.open('w') - print >> f, source - # some support code... - print >> f, py.code.Source(""" - import sys - # we don't want to see the small bridges created - # by the checkinterval reaching the limit - sys.setcheckinterval(10000000) - try: # make the file runnable by CPython - import pypyjit - pypyjit.set_param(threshold=%d) - except ImportError: - pass - - def check(args, expected): - #print >> sys.stderr, 'trying:', args - result = main(*args) - #print >> sys.stderr, 'got:', repr(result) - assert result == expected - assert type(result) is type(expected) - """ % threshold) - for testcase in testcases * 2: - print >> f, "check(%r, %r)" % testcase - print >> f, "print 'OK :-)'" - f.close() - - print logfilepath - env = os.environ.copy() - env['PYPYLOG'] = ":%s" % (logfilepath,) - p = subprocess.Popen([self.pypy_c, str(filepath)], - env=env, stdout=subprocess.PIPE) - result, _ = p.communicate() - assert result - if result.strip().startswith('SKIP:'): - py.test.skip(result.strip()) - assert result.splitlines()[-1].strip() == 'OK :-)' - self.parse_loops(logfilepath) - self.print_loops() - print logfilepath - if self.total_ops > expected_max_ops: - assert 0, "too many operations: got %d, expected maximum %d" % ( - self.total_ops, expected_max_ops) - return result - - def parse_loops(self, opslogfile): - from pypy.tool import logparser - assert opslogfile.check() - log = logparser.parse_log_file(str(opslogfile)) - parts = logparser.extract_category(log, 'jit-log-opt-') - self.rawloops = [part for part in parts - if not from_entry_bridge(part, parts)] - self.loops, self.sliced_loops, self.total_ops = \ - self.parse_rawloops(self.rawloops) - self.check_0_op_bytecodes() - self.rawentrybridges = [part for part in parts - if from_entry_bridge(part, parts)] - _, self.sliced_entrybridge, _ = \ - self.parse_rawloops(self.rawentrybridges) - - from pypy.jit.tool.jitoutput import parse_prof - summaries = logparser.extract_category(log, 'jit-summary') - if len(summaries) > 0: - self.jit_summary = parse_prof(summaries[-1]) - else: - self.jit_summary = None - - - def parse_rawloops(self, rawloops): - from pypy.jit.tool.oparser import parse - loops = [parse(part, no_namespace=True) for part in rawloops] - sliced_loops = [] # contains all bytecodes of all loops - total_ops = 0 - for loop in loops: - for op in loop.operations: - if op.getopname() == "debug_merge_point": - sliced_loop = BytecodeTrace() - sliced_loop.bytecode = op.getarg(0)._get_str().rsplit(" ", 1)[1] - sliced_loops.append(sliced_loop) - if self.count_debug_merge_point: - total_ops += 1 - else: - sliced_loop.append(op) - total_ops += 1 - return loops, sliced_loops, total_ops - - def check_0_op_bytecodes(self): - for bytecodetrace in self.sliced_loops: - if bytecodetrace.bytecode not in ZERO_OP_BYTECODES: - continue - assert not bytecodetrace - - def get_by_bytecode(self, name, from_entry_bridge=False): - if from_entry_bridge: - sliced_loops = self.sliced_entrybridge - else: - sliced_loops = self.sliced_loops - return [ops for ops in sliced_loops if ops.bytecode == name] - - def print_loops(self): - for rawloop in self.rawloops: - print - print '@' * 79 - print - print rawloop.rstrip() - print - print '@' * 79 - - - def test_richards(self): - self.run_source(''' - import sys; sys.path[:] = %r - from pypy.translator.goal import richards - - def main(): - return richards.main(iterations = 1) - ''' % (sys.path,), 7200, - ([], 42)) - - - def test_overflow_checking(self): - startvalue = sys.maxint - 2147483647 - self.run_source(''' - def main(): - def f(a,b): - if a < 0: return -1 - return a-b - total = %d - for i in range(100000): - total += f(i, 5) - return total - ''' % startvalue, 170, ([], startvalue + 4999450000L)) - - def test_shift(self): - from sys import maxint - maxvals = (-maxint-1, -maxint, maxint-1, maxint) - for a in (-4, -3, -2, -1, 0, 1, 2, 3, 4) + maxvals: - for b in (0, 1, 2, 31, 32, 33, 61, 62, 63): - r = 0 - if (a >> b) >= 0: - r += 2000 - if (a << b) > 2: - r += 20000000 - if abs(a) < 10 and b < 5: - ops = 13 - else: - ops = 29 - - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 2000: - if a > 0: # Specialises the loop - pass - if b < 2 and b > 0: - pass - if (a >> b) >= 0: - sa += 1 - if (a << b) > 2: - sa += 10000 - i += 1 - return sa - ''', ops, ([a, b], r), count_debug_merge_point=False) - - def test_revert_shift(self): - from sys import maxint - tests = [] - for a in (1, 4, 8, 100): - for b in (-10, 10, -201, 201, -maxint/3, maxint/3): - for c in (-10, 10, -maxint/3, maxint/3): - tests.append(([a, b, c], long(4000*(a+b+c)))) - self.run_source(''' - def main(a, b, c): - from sys import maxint - i = sa = 0 - while i < 2000: - if 0 < a < 10: pass - if -100 < b < 100: pass - if -maxint/2 < c < maxint/2: pass - sa += (a<>a - sa += (b<>a - sa += (c<>a - sa += (a<<100)>>100 - sa += (b<<100)>>100 - sa += (c<<100)>>100 - i += 1 - return long(sa) - ''', 93, count_debug_merge_point=False, *tests) - - def test_division_to_rshift(self): - avalues = ('a', 'b', 7, -42, 8) - bvalues = ['b'] + range(-10, 0) + range(1,10) - code = '' - a1, b1, res1 = 10, 20, 0 - a2, b2, res2 = 10, -20, 0 - a3, b3, res3 = -10, -20, 0 - def dd(a, b, aval, bval): - m = {'a': aval, 'b': bval} - if not isinstance(a, int): - a=m[a] - if not isinstance(b, int): - b=m[b] - return a/b - for a in avalues: - for b in bvalues: - code += ' sa += %s / %s\n' % (a, b) - res1 += dd(a, b, a1, b1) - res2 += dd(a, b, a2, b2) - res3 += dd(a, b, a3, b3) - # The purpose of this test is to check that we get - # the correct results, not really to count operations. - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 2000: -%s - i += 1 - return sa - ''' % code, sys.maxint, ([a1, b1], 2000 * res1), - ([a2, b2], 2000 * res2), - ([a3, b3], 2000 * res3)) - - def test_mod(self): - avalues = ('a', 'b', 7, -42, 8) - bvalues = ['b'] + range(-10, 0) + range(1,10) - code = '' - a1, b1, res1 = 10, 20, 0 - a2, b2, res2 = 10, -20, 0 - a3, b3, res3 = -10, -20, 0 - def dd(a, b, aval, bval): - m = {'a': aval, 'b': bval} - if not isinstance(a, int): - a=m[a] - if not isinstance(b, int): - b=m[b] - return a % b - for a in avalues: - for b in bvalues: - code += ' sa += %s %% %s\n' % (a, b) - res1 += dd(a, b, a1, b1) - res2 += dd(a, b, a2, b2) - res3 += dd(a, b, a3, b3) - # The purpose of this test is to check that we get - # the correct results, not really to count operations. - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 2000: - if a > 0: pass - if 1 < b < 2: pass -%s - i += 1 - return sa - ''' % code, sys.maxint, ([a1, b1], 2000 * res1), - ([a2, b2], 2000 * res2), - ([a3, b3], 2000 * res3)) - - def test_dont_trace_every_iteration(self): - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 200: - if a > 0: pass - if 1 < b < 2: pass - sa += a % b - i += 1 - return sa - ''', 22, ([10, 20], 200 * (10 % 20)), - ([-10, -20], 200 * (-10 % -20)), - count_debug_merge_point=False) - assert self.jit_summary.tracing_no == 2 - def test_id_compare_optimization(self): - # XXX: lower the instruction count, 35 is the old value. - self.run_source(""" - class A(object): - pass - def main(): - i = 0 - a = A() - while i < 5: - if A() != a: - pass - i += 1 - """, 35, ([], None)) - _, compare = self.get_by_bytecode("COMPARE_OP") - assert "call" not in compare.get_opnames() - -class AppTestJIT(PyPyCJITTests): - def setup_class(cls): - if not option.runappdirect: - py.test.skip("meant only for pypy-c") - # the next line skips stuff if the pypy-c is not a jit build - cls.space = gettestobjspace(usemodules=['pypyjit']) - cls.tmpdir = udir.join('pypy-jit') - cls.tmpdir.ensure(dir=1) - cls.counter = 0 - cls.pypy_c = sys.executable - -class TestJIT(PyPyCJITTests): - def setup_class(cls): - if option.pypy_c is None: - py.test.skip("pass --pypy!") - if not has_info(option.pypy_c, 'translation.jit'): - py.test.skip("must give a pypy-c with the jit enabled") - cls.tmpdir = udir.join('pypy-jit') - cls.tmpdir.ensure(dir=1) - cls.counter = 0 - cls.pypy_c = option.pypy_c - - -def test_interface_residual_call(): - space = gettestobjspace(usemodules=['pypyjit']) - space.appexec([], """(): - import pypyjit - def f(*args, **kwds): - return (args, kwds) - res = pypyjit.residual_call(f, 4, x=6) - assert res == ((4,), {'x': 6}) - """) - - -def has_info(pypy_c, option): - g = os.popen('"%s" --info' % pypy_c, 'r') - lines = g.readlines() - g.close() - if not lines: - raise ValueError("cannot execute %r" % pypy_c) - for line in lines: - line = line.strip() - if line.startswith(option + ':'): - line = line[len(option)+1:].strip() - if line == 'True': - return True - elif line == 'False': - return False - else: - return line - raise ValueError(option + ' not found in ' + pypy_c) diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -2,6 +2,7 @@ import sys import re import os.path +from _pytest.assertion import newinterpret from pypy.tool.jitlogparser.parser import SimpleParser, Function, TraceForOpcode from pypy.tool.jitlogparser.storage import LoopStorage @@ -194,7 +195,7 @@ # transform self._assert(x, 'foo') into assert x, 'foo' source = source.replace('self._assert(', 'assert ') source = source[:-1] # remove the trailing ')' - self.msg = py.code._reinterpret(source, f, should_fail=True) + self.msg = newinterpret.interpret(source, f, should_fail=True) else: self.msg = "" diff --git a/pypy/module/pypyjit/test_pypy_c/test_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py rename from pypy/module/pypyjit/test_pypy_c/test_model.py rename to pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -5,6 +5,7 @@ from lib_pypy import disassembler from pypy.tool.udir import udir from pypy.tool import logparser +from pypy.jit.tool.jitoutput import parse_prof from pypy.module.pypyjit.test_pypy_c.model import Log, find_ids_range, find_ids, \ LoopWithIds, OpMatcher @@ -21,6 +22,7 @@ self.filepath = self.tmpdir.join(meth.im_func.func_name + '.py') def run(self, func_or_src, args=[], import_site=False, **jitopts): + jitopts.setdefault('threshold', 200) src = py.code.Source(func_or_src) if isinstance(func_or_src, types.FunctionType): funcname = func_or_src.func_name @@ -56,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log @@ -63,6 +67,13 @@ rawtraces = logparser.extract_category(rawlog, 'jit-log-opt-') log = Log(rawtraces) log.result = eval(stdout) + # + summaries = logparser.extract_category(rawlog, 'jit-summary') + if len(summaries) > 0: + log.jit_summary = parse_prof(summaries[-1]) + else: + log.jit_summary = None + # return log def run_and_check(self, src, args=[], **jitopts): diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -0,0 +1,133 @@ +import py +import sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class Test__ffi(BaseTestPyPyC): + + def test__ffi_call(self): + from pypy.rlib.test.test_libffi import get_libm_name + def main(libm_name): + try: + from _ffi import CDLL, types + except ImportError: + sys.stderr.write('SKIP: cannot import _ffi\n') + return 0 + + libm = CDLL(libm_name) + pow = libm.getfunc('pow', [types.double, types.double], + types.double) + i = 0 + res = 0 + while i < 300: + tmp = pow(2, 3) # ID: fficall + res += tmp + i += 1 + return pow.getaddr(), res + # + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + pow_addr, res = log.result + assert res == 8.0 * 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('fficall', """ + p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>) + guard_not_invalidated(descr=...) + i17 = force_token() + setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>) + f21 = call_release_gil(%d, 2.000000, 3.000000, descr=) + guard_not_forced(descr=...) + guard_no_exception(descr=...) + """ % pow_addr) + + + def test__ffi_call_frame_does_not_escape(self): + from pypy.rlib.test.test_libffi import get_libm_name + def main(libm_name): + try: + from _ffi import CDLL, types + except ImportError: + sys.stderr.write('SKIP: cannot import _ffi\n') + return 0 + + libm = CDLL(libm_name) + pow = libm.getfunc('pow', [types.double, types.double], + types.double) + + def mypow(a, b): + return pow(a, b) + + i = 0 + res = 0 + while i < 300: + tmp = mypow(2, 3) + res += tmp + i += 1 + return pow.getaddr(), res + # + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + pow_addr, res = log.result + assert res == 8.0 * 300 + loop, = log.loops_by_filename(self.filepath) + opnames = log.opnames(loop.allops()) + # we only force the virtualref, not its content + assert opnames.count('new_with_vtable') == 1 + + def test__ffi_call_releases_gil(self): + from pypy.rlib.test.test_libffi import get_libc_name + def main(libc_name, n): + import time + from threading import Thread + from _ffi import CDLL, types + # + libc = CDLL(libc_name) + sleep = libc.getfunc('sleep', [types.uint], types.uint) + delays = [0]*n + [1] + # + def loop_of_sleeps(i, delays): + for delay in delays: + sleep(delay) # ID: sleep + # + threads = [Thread(target=loop_of_sleeps, args=[i, delays]) for i in range(5)] + start = time.time() + for i, thread in enumerate(threads): + thread.start() + for thread in threads: + thread.join() + end = time.time() + return end - start + # + log = self.run(main, [get_libc_name(), 200], threshold=150) + assert 1 <= log.result <= 1.5 # at most 0.5 seconds of overhead + loops = log.loops_by_id('sleep') + assert len(loops) == 1 # make sure that we actually JITted the loop + + + def test_ctypes_call(self): + from pypy.rlib.test.test_libffi import get_libm_name + def main(libm_name): + import ctypes + libm = ctypes.CDLL(libm_name) + fabs = libm.fabs + fabs.argtypes = [ctypes.c_double] + fabs.restype = ctypes.c_double + x = -4 + i = 0 + while i < 300: + x = fabs(x) + x = x - 100 + i += 1 + return fabs._ptr.getaddr(), x + + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + fabs_addr, res = log.result + assert res == -4.0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.allops() + opnames = log.opnames(ops) + assert opnames.count('new_with_vtable') == 1 # only the virtualref + assert opnames.count('call_release_gil') == 1 + idx = opnames.index('call_release_gil') + call = ops[idx] + assert int(call.args[0]) == fabs_addr diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -0,0 +1,186 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestArray(BaseTestPyPyC): + + def test_arraycopy_disappears(self): + def main(n): + i = 0 + while i < n: + t = (1, 2, 3, i + 1) + t2 = t[:] + del t + i = t2[3] + del t2 + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i5, i6) + guard_true(i7, descr=) + i9 = int_add(i5, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i9, i6, descr=) + """) + + def test_array_sum(self): + def main(): + from array import array + img = array("i", range(128) * 5) * 480 + l, i = 0, 0 + while i < len(img): + l += img[i] + i += 1 + return l + # + log = self.run(main, []) + assert log.result == 19507200 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i13 = int_lt(i7, i9) + guard_true(i13, descr=) + i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) + i16 = int_add_ovf(i8, i15) + guard_no_overflow(descr=) + i18 = int_add(i7, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) + """) + + def test_array_intimg(self): + def main(): + from array import array + img = array('i', range(3)) * (350 * 480) + intimg = array('i', (0,)) * (640 * 480) + l, i = 0, 640 + while i < 640 * 480: + assert len(img) == 3*350*480 + assert len(intimg) == 640*480 + l = l + img[i] + intimg[i] = (intimg[i-640] + l) + i += 1 + return intimg[i - 1] + # + log = self.run(main, []) + assert log.result == 73574560 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i13 = int_lt(i8, 307200) + guard_true(i13, descr=) + # the bound check guard on img has been killed (thanks to the asserts) + i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) + i15 = int_add_ovf(i9, i14) + guard_no_overflow(descr=) + i17 = int_sub(i8, 640) + # the bound check guard on intimg has been killed (thanks to the asserts) + i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) + i19 = int_add_ovf(i18, i15) + guard_no_overflow(descr=) + # on 64bit, there is a guard checking that i19 actually fits into 32bit + ... + setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) + i28 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) + """) + + + def test_zeropadded(self): + def main(): + from array import array + class ZeroPadded(array): + def __new__(cls, l): + self = array.__new__(cls, 'd', range(l)) + return self + + def __getitem__(self, i): + if i < 0 or i >= len(self): + return 0 + return array.__getitem__(self, i) # ID: get + # + buf = ZeroPadded(2000) + i = 10 + sa = 0 + while i < 2000 - 10: + sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] + i += 1 + return sa + + log = self.run(main, []) + assert log.result == 9895050.0 + loop, = log.loops_by_filename(self.filepath) + # + # check that the overloaded __getitem__ does not introduce double + # array bound checks. + # + # The force_token()s are still there, but will be eliminated by the + # backend regalloc, so they are harmless + assert loop.match(ignore_ops=['force_token'], + expected_src=""" + ... + i20 = int_ge(i18, i8) + guard_false(i20, descr=...) + f21 = getarrayitem_raw(i13, i18, descr=...) + f23 = getarrayitem_raw(i13, i14, descr=...) + f24 = float_add(f21, f23) + f26 = getarrayitem_raw(i13, i6, descr=...) + f27 = float_add(f24, f26) + i29 = int_add(i6, 1) + i31 = int_ge(i29, i8) + guard_false(i31, descr=...) + f33 = getarrayitem_raw(i13, i29, descr=...) + f34 = float_add(f27, f33) + i36 = int_add(i6, 2) + i38 = int_ge(i36, i8) + guard_false(i38, descr=...) + f39 = getarrayitem_raw(i13, i36, descr=...) + ... + """) + + def test_circular(self): + def main(): + from array import array + class Circular(array): + def __new__(cls): + self = array.__new__(cls, 'd', range(256)) + return self + def __getitem__(self, i): + assert len(self) == 256 + return array.__getitem__(self, i & 255) + # + buf = Circular() + i = 10 + sa = 0 + while i < 2000 - 10: + sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] + i += 1 + return sa + # + log = self.run(main, []) + assert log.result == 1239690.0 + loop, = log.loops_by_filename(self.filepath) + # + # check that the array bound checks are removed + # + # The force_token()s are still there, but will be eliminated by the + # backend regalloc, so they are harmless + assert loop.match(ignore_ops=['force_token'], + expected_src=""" + ... + i17 = int_and(i14, 255) + f18 = getarrayitem_raw(i8, i17, descr=...) + f20 = getarrayitem_raw(i8, i9, descr=...) + f21 = float_add(f18, f20) + f23 = getarrayitem_raw(i8, i10, descr=...) + f24 = float_add(f21, f23) + i26 = int_add(i6, 1) + i29 = int_and(i26, 255) + f30 = getarrayitem_raw(i8, i29, descr=...) + f31 = float_add(f24, f30) + i33 = int_add(i6, 2) + i36 = int_and(i33, 255) + f37 = getarrayitem_raw(i8, i36, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_boolrewrite.py b/pypy/module/pypyjit/test_pypy_c/test_boolrewrite.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_boolrewrite.py @@ -0,0 +1,233 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestBoolRewrite(BaseTestPyPyC): + + def test_boolrewrite_inverse(self): + """ + Test for this case:: + guard(i < x) + ... + guard(i >= y) + + where x and y can be either constants or variables. There are cases in + which the second guard is proven to be always true. + """ + + for a, b, res, opt_expected in (('2000', '2000', 20001000, True), + ( '500', '500', 15001500, True), + ( '300', '600', 16001700, False), + ( 'a', 'b', 16001700, False), + ( 'a', 'a', 13001700, True)): + src = """ + def main(): + sa = 0 + a = 300 + b = 600 + for i in range(1000): + if i < %s: # ID: lt + sa += 1 + else: + sa += 2 + # + if i >= %s: # ID: ge + sa += 10000 + else: + sa += 20000 + return sa + """ % (a, b) + # + log = self.run(src, [], threshold=400) + assert log.result == res + loop, = log.loops_by_filename(self.filepath) + le_ops = log.opnames(loop.ops_by_id('lt')) + ge_ops = log.opnames(loop.ops_by_id('ge')) + assert le_ops.count('int_lt') == 1 + # + if opt_expected: + assert ge_ops.count('int_ge') == 0 + else: + # if this assert fails it means that the optimization was + # applied even if we don't expect to. Check whether the + # optimization is valid, and either fix the code or fix the + # test :-) + assert ge_ops.count('int_ge') == 1 + + def test_boolrewrite_reflex(self): + """ + Test for this case:: + guard(i < x) + ... + guard(y > i) + + where x and y can be either constants or variables. There are cases in + which the second guard is proven to be always true. + """ + for a, b, res, opt_expected in (('2000', '2000', 10001000, True), + ( '500', '500', 15001500, True), + ( '300', '600', 14001700, False), + ( 'a', 'b', 14001700, False), + ( 'a', 'a', 17001700, True)): + + src = """ + def main(): + sa = 0 + a = 300 + b = 600 + for i in range(1000): + if i < %s: # ID: lt + sa += 1 + else: + sa += 2 + if %s > i: # ID: gt + sa += 10000 + else: + sa += 20000 + return sa + """ % (a, b) + log = self.run(src, [], threshold=400) + assert log.result == res + loop, = log.loops_by_filename(self.filepath) + le_ops = log.opnames(loop.ops_by_id('lt')) + gt_ops = log.opnames(loop.ops_by_id('gt')) + assert le_ops.count('int_lt') == 1 + # + if opt_expected: + assert gt_ops.count('int_gt') == 0 + else: + # if this assert fails it means that the optimization was + # applied even if we don't expect to. Check whether the + # optimization is valid, and either fix the code or fix the + # test :-) + assert gt_ops.count('int_gt') == 1 + + + def test_boolrewrite_allcases_inverse(self): + """ + Test for this case:: + guard(i < x) + ... + guard(i > y) + + with all possible combination of binary comparison operators. This + test only checks that we get the expected result, not that any + optimization has been applied. + """ + ops = ('<', '>', '<=', '>=', '==', '!=') + for op1 in ops: + for op2 in ops: + for a,b in ((500, 500), (300, 600)): + src = """ + def main(): + sa = 0 + for i in range(300): + if i %s %d: + sa += 1 + else: + sa += 2 + if i %s %d: + sa += 10000 + else: + sa += 20000 + return sa + """ % (op1, a, op2, b) + yield self.run_and_check, src + + src = """ + def main(): + sa = 0 + i = 0.0 + while i < 250.0: + if i %s %f: + sa += 1 + else: + sa += 2 + if i %s %f: + sa += 10000 + else: + sa += 20000 + i += 0.25 + return sa + """ % (op1, float(a)/4.0, op2, float(b)/4.0) + yield self.run_and_check, src + + + def test_boolrewrite_allcases_reflex(self): + """ + Test for this case:: + guard(i < x) + ... + guard(x > i) + + with all possible combination of binary comparison operators. This + test only checks that we get the expected result, not that any + optimization has been applied. + """ + ops = ('<', '>', '<=', '>=', '==', '!=') + for op1 in ops: + for op2 in ops: + for a,b in ((500, 500), (300, 600)): + src = """ + def main(): + sa = 0 + for i in range(300): + if i %s %d: + sa += 1 + else: + sa += 2 + if %d %s i: + sa += 10000 + else: + sa += 20000 + return sa + """ % (op1, a, b, op2) + yield self.run_and_check, src + + src = """ + def main(): + sa = 0 + i = 0.0 + while i < 250.0: + if i %s %f: + sa += 1 + else: + sa += 2 + if %f %s i: + sa += 10000 + else: + sa += 20000 + i += 0.25 + return sa + """ % (op1, float(a)/4.0, float(b)/4.0, op2) + yield self.run_and_check, src + + def test_boolrewrite_ptr(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b') + for e1 in compares: + for e2 in compares: + src = """ + class tst(object): + pass + def main(): + a = tst() + b = tst() + c = tst() + sa = 0 + for i in range(300): + if %s: + sa += 1 + else: + sa += 2 + if %s: + sa += 10000 + else: + sa += 20000 + if i > 750: + a = b + return sa + """ % (e1, e2) + yield self.run_and_check, src diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -0,0 +1,412 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestCall(BaseTestPyPyC): + + def test_recursive_call(self): + def fn(): + def rec(n): + if n == 0: + return 0 + return 1 + rec(n-1) + # + # this loop is traced and then aborted, because the trace is too + # long. But then "rec" is marked as "don't inline". Since we + # already traced function from the start (because of number), + # now we can inline it as call assembler + i = 0 + j = 0 + while i < 20: + i += 1 + j += rec(100) # ID: call_rec + return j + # + log = self.run(fn, [], threshold=18) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('call_rec', """ + ... + p53 = call_assembler(..., descr=...) + guard_not_forced(descr=...) + guard_no_exception(descr=...) + ... + """) + + def test_fib(self): + def fib(n): + if n == 0 or n == 1: + return 1 + return fib(n - 1) + fib(n - 2) # ID: call_rec + + log = self.run(fib, [7], function_threshold=15) + loop, = log.loops_by_filename(self.filepath, is_entry_bridge='*') + #assert loop.match_by_id('call_rec', ''' + #... + #p1 = call_assembler(..., descr=...) + #... + #''') + + def test_simple_call(self): + src = """ + OFFSET = 0 + def f(i): + return i + 1 + OFFSET # ID: add + def main(n): + i = 0 + while i < n+OFFSET: # ID: cond + i = f(f(i)) # ID: call + a = 0 + return i + """ + log = self.run(src, [1000]) + assert log.result == 1000 + # first, we test what is inside the entry bridge + # ----------------------------------------------- + entry_bridge, = log.loops_by_id('call', is_entry_bridge=True) + # LOAD_GLOBAL of OFFSET + ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') + assert log.opnames(ops) == ["guard_value", + "getfield_gc", "guard_value", + "getfield_gc", "guard_value", + "getfield_gc", "guard_nonnull_class"] + # LOAD_GLOBAL of OFFSET but in different function partially folded + # away + # XXX could be improved + ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') + assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value"] + # + # two LOAD_GLOBAL of f, the second is folded away + ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') + assert log.opnames(ops) == ["getfield_gc", "guard_nonnull_class"] + # + assert entry_bridge.match_by_id('call', """ + p29 = getfield_gc(ConstPtr(ptr28), descr=) + guard_nonnull_class(p29, ConstClass(Function), descr=) + p33 = getfield_gc(p29, descr=) + guard_value(p33, ConstPtr(ptr34), descr=) + p35 = getfield_gc(p29, descr=) + p36 = getfield_gc(p29, descr=) + p38 = call(ConstClass(getexecutioncontext), descr=) + p39 = getfield_gc(p38, descr=) + i40 = force_token() + p41 = getfield_gc(p38, descr=) + guard_isnull(p41, descr=) + i42 = getfield_gc(p38, descr=) + i43 = int_is_zero(i42) + guard_true(i43, descr=) + i50 = force_token() + """) + # + # then, we test the actual loop + # ----------------------------- + loop, = log.loops_by_id('call') + assert loop.match(""" + i12 = int_lt(i5, i6) + guard_true(i12, descr=) + i13 = force_token() + i15 = int_add(i5, 1) + i16 = int_add_ovf(i15, i7) + guard_no_overflow(descr=) + i18 = force_token() + i20 = int_add_ovf(i16, 1) + guard_no_overflow(descr=) + i21 = int_add_ovf(i20, i7) + guard_no_overflow(descr=) + --TICK-- + jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) + """) + + def test_method_call(self): + def fn(n): + class A(object): + def __init__(self, a): + self.a = a + def f(self, i): + return self.a + i + i = 0 + a = A(1) + while i < n: + x = a.f(i) # ID: meth1 + i = a.f(x) # ID: meth2 + return i + # + log = self.run(fn, [1000]) + assert log.result == 1000 + # + # first, we test the entry bridge + # ------------------------------- + entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) + ops = entry_bridge.ops_by_id('meth1', opcode='LOOKUP_METHOD') + assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', + 'guard_not_invalidated'] + # the second LOOKUP_METHOD is folded away + assert list(entry_bridge.ops_by_id('meth2', opcode='LOOKUP_METHOD')) == [] + # + # then, the actual loop + # ---------------------- + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i15 = int_lt(i6, i9) + guard_true(i15, descr=) + guard_not_invalidated(descr=) + i16 = force_token() + i17 = int_add_ovf(i10, i6) + guard_no_overflow(descr=) + i18 = force_token() + i19 = int_add_ovf(i10, i17) + guard_no_overflow(descr=) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) + """) + + def test_static_classmethod_call(self): + def fn(n): + class A(object): + @classmethod + def f(cls, i): + return i + (cls is A) + 1 + @staticmethod + def g(i): + return i - 1 + # + i = 0 + a = A() + while i < n: + x = a.f(i) + i = a.g(x) + return i + # + log = self.run(fn, [1000]) + assert log.result == 1000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i14 = int_lt(i6, i9) + guard_true(i14, descr=) + guard_not_invalidated(descr=) + i15 = force_token() + i17 = int_add_ovf(i8, 1) + guard_no_overflow(descr=) + i18 = force_token() + --TICK-- + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) + """) + + def test_default_and_kw(self): + def main(n): + def f(i, j=1): + return i + j + # + i = 0 + while i < n: + i = f(f(i), j=1) # ID: call + a = 0 + return i + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('call') + assert loop.match_by_id('call', """ + i14 = force_token() + i16 = force_token() + """) + + def test_kwargs_empty(self): + def main(x): + def g(**args): + return len(args) + 1 + # + s = 0 + d = {} + i = 0 + while i < x: + s += g(**d) # ID: call + i += 1 + return s + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('call') + ops = log.opnames(loop.ops_by_id('call')) + guards = [ops for ops in ops if ops.startswith('guard')] + assert guards == ["guard_no_overflow"] + + def test_kwargs(self): + # this is not a very precise test, could be improved + def main(x): + def g(**args): + return len(args) + # + s = 0 + d = {"a": 1} + i = 0 + while i < x: + s += g(**d) # ID: call + d[str(i)] = i + if i % 100 == 99: + d = {"a": 1} + i += 1 + return s + # + log = self.run(main, [1000]) + assert log.result == 50500 + loop, = log.loops_by_id('call') + print loop.ops_by_id('call') + ops = log.opnames(loop.ops_by_id('call')) + guards = [ops for ops in ops if ops.startswith('guard')] + print guards + assert len(guards) <= 20 + + def test_stararg_virtual(self): + def main(x): + def g(*args): + return len(args) + def h(a, b, c): + return c + # + s = 0 + for i in range(x): + l = [i, x, 2] + s += g(*l) # ID: g1 + s += h(*l) # ID: h1 + s += g(i, x, 2) # ID: g2 + a = 0 + for i in range(x): + l = [x, 2] + s += g(i, *l) # ID: g3 + s += h(i, *l) # ID: h2 + a = 0 + return s + # + log = self.run(main, [1000]) + assert log.result == 13000 + loop0, = log.loops_by_id('g1') + assert loop0.match_by_id('g1', """ + i20 = force_token() + setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) + i22 = int_add_ovf(i8, 3) + guard_no_overflow(descr=) + """) + assert loop0.match_by_id('h1', """ + i20 = force_token() + i22 = int_add_ovf(i8, 2) + guard_no_overflow(descr=) + """) + assert loop0.match_by_id('g2', """ + i27 = force_token() + i29 = int_add_ovf(i26, 3) + guard_no_overflow(descr=) + """) + # + loop1, = log.loops_by_id('g3') + assert loop1.match_by_id('g3', """ + i21 = force_token() + setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) + i23 = int_add_ovf(i9, 3) + guard_no_overflow(descr=) + """) + assert loop1.match_by_id('h2', """ + i25 = force_token() + i27 = int_add_ovf(i23, 2) + guard_no_overflow(descr=) + """) + + def test_stararg(self): + def main(x): + def g(*args): + return args[-1] + def h(*args): + return len(args) + # + s = 0 + l = [] + i = 0 + while i < x: + l.append(1) + s += g(*l) # ID: g + i = h(*l) # ID: h + a = 0 + return s + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('g') + ops_g = log.opnames(loop.ops_by_id('g')) + ops_h = log.opnames(loop.ops_by_id('h')) + ops = ops_g + ops_h + assert 'new_with_vtable' not in ops + assert 'call_may_force' not in ops + + def test_call_builtin_function(self): + def main(n): + i = 2 + l = [] + while i < n: + i += 1 + l.append(i) # ID: append + a = 0 + return i, len(l) + # + log = self.run(main, [1000]) + assert log.result == (1000, 998) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('append', """ + i13 = getfield_gc(p8, descr=) + i15 = int_add(i13, 1) + call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) + guard_no_exception(descr=) + p17 = getfield_gc(p8, descr=) + p19 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p19, i12, descr=) + setarrayitem_gc(p17, i13, p19, descr=) + """) + + def test_blockstack_virtualizable(self): + def main(n): + from pypyjit import residual_call + i = 0 + while i < n: + try: + residual_call(len, []) # ID: call + except: + pass + i += 1 + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_id('call') + assert loop.match_by_id('call', opcode='CALL_FUNCTION', expected_src=""" + # make sure that the "block" is not allocated + ... + i20 = force_token() + setfield_gc(p0, i20, descr=) + p22 = new_with_vtable(19511408) + p24 = new_array(1, descr=) + p26 = new_with_vtable(ConstClass(W_ListObject)) + p27 = new(descr=) + p29 = new_array(0, descr=) + setfield_gc(p27, p29, descr=) + setfield_gc(p26, p27, descr=<.* .*W_ListObject.inst_wrappeditems .*>) + setarrayitem_gc(p24, 0, p26, descr=) + setfield_gc(p22, p24, descr=) + p32 = call_may_force(11376960, p18, p22, descr=) + ... + """) + + def test_func_defaults(self): + def main(n): + i = 1 + while i < n: + i += len(xrange(i+1)) - i + return i + + log = self.run(main, [10000]) + assert log.result == 10000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i5, i6) + guard_true(i10, descr=) + i120 = int_add(i5, 1) + guard_not_invalidated(descr=) + --TICK-- + jump(..., descr=) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py @@ -0,0 +1,93 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestException(BaseTestPyPyC): + + def test_cmp_exc(self): + def f1(n): + # So we don't get a LOAD_GLOBAL op + KE = KeyError + i = 0 + while i < n: + try: + raise KE + except KE: # ID: except + i += 1 + return i + + log = self.run(f1, [10000]) + assert log.result == 10000 + loop, = log.loops_by_id("except") + ops = list(loop.ops_by_id("except", opcode="COMPARE_OP")) + assert ops == [] + + def test_exception_inside_loop_1(self): + def main(n): + while n: + try: + raise ValueError + except ValueError: + pass + n -= 1 + return n + # + log = self.run(main, [1000]) + assert log.result == 0 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i5 = int_is_true(i3) + guard_true(i5, descr=) + guard_not_invalidated(descr=) + --EXC-TICK-- + i12 = int_sub_ovf(i3, 1) + guard_no_overflow(descr=) + --TICK-- + jump(..., descr=) + """) + + def test_exception_inside_loop_2(self): + def main(n): + def g(n): + raise ValueError(n) # ID: raise + def f(n): + g(n) + # + while n: + try: + f(n) + except ValueError: + pass + n -= 1 + return n + # + log = self.run(main, [1000]) + assert log.result == 0 + loop, = log.loops_by_filename(self.filepath) + ops = log.opnames(loop.ops_by_id('raise')) + assert 'new' not in ops + + def test_reraise(self): + def f(n): + i = 0 + while i < n: + try: + try: + raise KeyError + except KeyError: + raise + except KeyError: + i += 1 + return i + + log = self.run(f, [100000]) + assert log.result == 100000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i4, i5) + guard_true(i7, descr=) + guard_not_invalidated(descr=) + --EXC-TICK-- + i14 = int_add(i4, 1) + --TICK-- + jump(..., descr=) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -0,0 +1,46 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestImport(BaseTestPyPyC): + + def test_import_in_function(self): + def main(n): + i = 0 + while i < n: + from sys import version # ID: import + i += 1 + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_id('import') + assert loop.match_by_id('import', """ + p11 = getfield_gc(ConstPtr(ptr10), descr=) + guard_value(p11, ConstPtr(ptr12), descr=) + guard_not_invalidated(descr=) + p14 = getfield_gc(ConstPtr(ptr13), descr=) + p16 = getfield_gc(ConstPtr(ptr15), descr=) + guard_value(p14, ConstPtr(ptr17), descr=) + guard_isnull(p16, descr=) + """) + + def test_import_fast_path(self, tmpdir): + pkg = tmpdir.join('mypkg').ensure(dir=True) + pkg.join('__init__.py').write("") + pkg.join('mod.py').write(str(py.code.Source(""" + def do_the_import(): + import sys + """))) + def main(path, n): + import sys + sys.path.append(path) + from mypkg.mod import do_the_import + for i in range(n): + do_the_import() + # + log = self.run(main, [str(tmpdir), 300]) + loop, = log.loops_by_filename(self.filepath) + # this is a check for a slow-down that introduced a + # call_may_force(absolute_import_with_lock). + for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")): + assert 'call' not in opname # no call-like opcode diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -0,0 +1,201 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestInstance(BaseTestPyPyC): + + def test_virtual_instance(self): + def main(n): + class A(object): + pass + # + i = 0 + while i < n: + a = A() + assert isinstance(a, A) + assert not isinstance(a, int) + a.x = 2 + i = i + a.x + return i + # + log = self.run(main, [1000], threshold = 400) + assert log.result == 1000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i5, i6) + guard_true(i7, descr=) + guard_not_invalidated(descr=) + i9 = int_add_ovf(i5, 2) + guard_no_overflow(descr=) + --TICK-- + jump(p0, p1, p2, p3, p4, i9, i6, descr=) + """) + + def test_load_attr(self): + src = ''' + class A(object): + pass + a = A() + a.x = 2 + def main(n): + i = 0 + while i < n: + i = i + a.x + return i + ''' + log = self.run(src, [1000]) + assert log.result == 1000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i9 = int_lt(i5, i6) + guard_true(i9, descr=) + guard_not_invalidated(descr=) + i10 = int_add_ovf(i5, i7) + guard_no_overflow(descr=) + --TICK-- + jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) + """) + + def test_getattr_with_dynamic_attribute(self): + src = """ + class A(object): + pass + + l = ["x", "y"] + + def main(): + sum = 0 + a = A() + a.a1 = 0 + a.a2 = 0 + a.a3 = 0 + a.a4 = 0 + a.a5 = 0 # workaround, because the first five attributes need a promotion + a.x = 1 + a.y = 2 + i = 0 + while i < 500: + name = l[i % 2] + sum += getattr(a, name) + i += 1 + return sum + """ + log = self.run(src, []) + assert log.result == 250 + 250*2 + loops = log.loops_by_filename(self.filepath) + assert len(loops) == 1 + + def test_mutate_class(self): + def fn(n): + class A(object): + count = 1 + def __init__(self, a): + self.a = a + def f(self): + return self.count + i = 0 + a = A(1) + while i < n: + A.count += 1 # ID: mutate + i = a.f() # ID: meth1 + return i + # + log = self.run(fn, [1000], threshold=10) + assert log.result == 1000 + # + # first, we test the entry bridge + # ------------------------------- + entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) + ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') + assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', + 'getfield_gc', 'guard_nonnull_class'] + # the STORE_ATTR is folded away + assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] + # + # then, the actual loop + # ---------------------- + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i9 = int_lt(i7, i8) + guard_true(i9, descr=.*) + guard_not_invalidated(descr=.*) + i11 = int_add(i8, 1) + i12 = force_token() + --TICK-- + p20 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p20, i11, descr=) + setfield_gc(ConstPtr(ptr21), p20, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i8, descr=) + """) + + def test_oldstyle_newstyle_mix(self): + def main(): + class A: + pass + + class B(object, A): + def __init__(self, x): + self.x = x + + i = 0 + b = B(1) + while i < 100: + v = b.x # ID: loadattr + i += v + return i + + log = self.run(main, [], threshold=80) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('loadattr', + ''' + guard_not_invalidated(descr=...) + i19 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) + guard_no_exception(descr=...) + i21 = int_and(i19, _) + i22 = int_is_true(i21) + guard_true(i22, descr=...) + i26 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) + guard_no_exception(descr=...) + i28 = int_and(i26, _) + i29 = int_is_true(i28) + guard_true(i29, descr=...) + ''') + + def test_python_contains(self): + def main(): + class A(object): + def __contains__(self, v): + return True + + i = 0 + a = A() + while i < 100: + i += i in a # ID: contains + b = 0 # to make sure that JUMP_ABSOLUTE is not part of the ID + + log = self.run(main, [], threshold=80) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("contains", """ + guard_not_invalidated(descr=...) + i11 = force_token() + i12 = int_add_ovf(i5, i7) + guard_no_overflow(descr=...) + """) + + def test_id_compare_optimization(self): + def main(): + class A(object): + pass + # + i = 0 + a = A() + while i < 300: + new_a = A() + if new_a != a: # ID: compare + pass + i += 1 + return i + # + log = self.run(main, []) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("compare", "") # optimized away + diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -0,0 +1,296 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestIntbound(BaseTestPyPyC): + + def test_intbound_simple(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + ops = ('<', '>', '<=', '>=', '==', '!=') + nbr = (3, 7) + for o1 in ops: + for o2 in ops: + for n1 in nbr: + for n2 in nbr: + src = ''' + def f(i): + a, b = 3, 3 + if i %s %d: + a = 0 + else: + a = 1 + if i %s %d: + b = 0 + else: + b = 1 + return a + b * 2 + + def main(): + res = [0] * 4 + idx = [] + for i in range(15): + idx.extend([i] * 15) + for i in idx: + res[f(i)] += 1 + return res + + ''' % (o1, n1, o2, n2) + yield self.run_and_check, src + + def test_intbound_addsub_mix(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + tests = ('i > 4', 'i > 2', 'i + 1 > 2', '1 + i > 4', + 'i - 1 > 1', '1 - i > 1', '1 - i < -3', + 'i == 1', 'i == 5', 'i != 1', '-2 * i < -4') + for t1 in tests: + for t2 in tests: + src = ''' + def f(i): + a, b = 3, 3 + if %s: + a = 0 + else: + a = 1 + if %s: + b = 0 + else: + b = 1 + return a + b * 2 + + def main(): + res = [0] * 4 + idx = [] + for i in range(15): + idx.extend([i] * 15) + for i in idx: + res[f(i)] += 1 + return res + + ''' % (t1, t2) + yield self.run_and_check, src + + def test_intbound_gt(self): + def main(n): + i, a, b = 0, 0, 0 + while i < n: + if i > -1: + a += 1 + if i > -2: + b += 1 + i += 1 + return (a, b) + # + log = self.run(main, [300]) + assert log.result == (300, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, i9) + guard_true(i10, descr=...) + i12 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i14 = int_add_ovf(i6, 1) + guard_no_overflow(descr=...) + i17 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) + """) + + def test_intbound_sub_lt(self): + def main(): + i, a = 0, 0 + while i < 300: + if i - 10 < 295: + a += 1 + i += 1 + return a + # + log = self.run(main, []) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i5, 300) + guard_true(i7, descr=...) + i9 = int_sub_ovf(i5, 10) + guard_no_overflow(descr=...) + i11 = int_add_ovf(i4, 1) + guard_no_overflow(descr=...) + i13 = int_add(i5, 1) + --TICK-- + jump(p0, p1, p2, p3, i11, i13, descr=) + """) + + def test_intbound_addsub_ge(self): + def main(n): + i, a, b = 0, 0, 0 + while i < n: + if i + 5 >= 5: + a += 1 + if i - 1 >= -1: + b += 1 + i += 1 + return (a, b) + # + log = self.run(main, [300]) + assert log.result == (300, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, i9) + guard_true(i10, descr=...) + i12 = int_add_ovf(i8, 5) + guard_no_overflow(descr=...) + i14 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i16 = int_add_ovf(i6, 1) + guard_no_overflow(descr=...) + i19 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) + """) + + def test_intbound_addmul_ge(self): + def main(n): + i, a, b = 0, 0, 0 + while i < 300: + if i + 5 >= 5: + a += 1 + if 2 * i >= 0: + b += 1 + i += 1 + return (a, b) + # + log = self.run(main, [300]) + assert log.result == (300, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, 300) + guard_true(i10, descr=...) + i12 = int_add(i8, 5) + i14 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i16 = int_lshift(i8, 1) + i18 = int_add_ovf(i6, 1) + guard_no_overflow(descr=...) + i21 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) + """) + + def test_intbound_eq(self): + def main(a, n): + i, s = 0, 0 + while i < 300: + if a == 7: + s += a + 1 + elif i == 10: + s += i + else: + s += 1 + i += 1 + return s + # + log = self.run(main, [7, 300]) + assert log.result == main(7, 300) + log = self.run(main, [10, 300]) + assert log.result == main(10, 300) + log = self.run(main, [42, 300]) + assert log.result == main(42, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, 300) + guard_true(i10, descr=...) + i12 = int_eq(i8, 10) + guard_false(i12, descr=...) + i14 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i16 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) + """) + + def test_intbound_mul(self): + def main(a): + i, s = 0, 0 + while i < 300: + assert i >= 0 + if 2 * i < 30000: + s += 1 + else: + s += a + i += 1 + return s + # + log = self.run(main, [7]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i8 = int_lt(i6, 300) + guard_true(i8, descr=...) + i10 = int_lshift(i6, 1) + i12 = int_add_ovf(i5, 1) + guard_no_overflow(descr=...) + i14 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i12, i14, descr=) + """) + + def test_assert(self): + def main(a): + i, s = 0, 0 + while i < 300: + assert a == 7 + s += a + 1 + i += 1 + return s + log = self.run(main, [7]) + assert log.result == 300*8 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i8 = int_lt(i6, 300) + guard_true(i8, descr=...) + i10 = int_add_ovf(i5, 8) + guard_no_overflow(descr=...) + i12 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i10, i12, descr=) + """) + + def test_xor(self): + def main(b): + a = sa = 0 + while a < 300: + if a > 0: # Specialises the loop + pass + if b > 10: + pass + if a^b >= 0: # ID: guard + sa += 1 + sa += a^a # ID: a_xor_a + a += 1 + return sa + + log = self.run(main, [11]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # if both are >=0, a^b is known to be >=0 + # note that we know that b>10 + assert loop.match_by_id('guard', """ + i10 = int_xor(i5, i7) + """) + # + # x^x is always optimized to 0 + assert loop.match_by_id('a_xor_a', "") + + log = self.run(main, [9]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # we don't know that b>10, hence we cannot optimize it + assert loop.match_by_id('guard', """ + i10 = int_xor(i5, i7) + i12 = int_ge(i10, 0) + guard_true(i12, descr=...) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -0,0 +1,67 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestMinMax(BaseTestPyPyC): + + def test_min_max(self): + def main(): + i=0 + sa=0 + while i < 300: + sa+=min(max(i, 3000), 4000) + i+=1 + return sa + log = self.run(main, []) + assert log.result == 300*3000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i4, 300) + guard_true(i7, descr=...) + i9 = int_add_ovf(i5, 3000) + guard_no_overflow(descr=...) + i11 = int_add(i4, 1) + --TICK-- + jump(p0, p1, p2, p3, i11, i9, descr=) + """) + + def test_silly_max(self): + def main(): + i = 2 + sa = 0 + while i < 300: + lst = range(i) + sa += max(*lst) # ID: max + i += 1 + return sa + log = self.run(main, []) + assert log.result == main() + loop, = log.loops_by_filename(self.filepath) + # We dont want too many guards, but a residual call to min_max_loop + guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] + assert len(guards) < 20 + assert loop.match_by_id('max',""" + ... + p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) + ... + """) + + def test_iter_max(self): + def main(): + i = 2 + sa = 0 + while i < 300: + lst = range(i) + sa += max(lst) # ID: max + i += 1 + return sa + log = self.run(main, []) + assert log.result == main() + loop, = log.loops_by_filename(self.filepath) + # We dont want too many guards, but a residual call to min_max_loop + guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] + assert len(guards) < 20 + assert loop.match_by_id('max',""" + ... + p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py rename from pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py rename to pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -1,13 +1,8 @@ -import py, sys, re -import subprocess -from lib_pypy import disassembler -from pypy.tool.udir import udir -from pypy.tool import logparser -from pypy.module.pypyjit.test_pypy_c.model import Log -from pypy.module.pypyjit.test_pypy_c.test_model import BaseTestPyPyC +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC -class TestPyPyCNew(BaseTestPyPyC): +class TestMisc(BaseTestPyPyC): def test_f1(self): def f1(n): "Arbitrary test function." @@ -76,378 +71,6 @@ """) - def test_recursive_call(self): - def fn(): - def rec(n): - if n == 0: - return 0 - return 1 + rec(n-1) - # - # this loop is traced and then aborted, because the trace is too - # long. But then "rec" is marked as "don't inline" - i = 0 - j = 0 - while i < 20: - i += 1 - j += rec(100) - # - # next time we try to trace "rec", instead of inlining we compile - # it separately and generate a call_assembler - i = 0 - j = 0 - while i < 20: - i += 1 - j += rec(100) # ID: call_rec - a = 0 - return j - # - log = self.run(fn, [], threshold=18) - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('call_rec', """ - ... - p53 = call_assembler(..., descr=...) - guard_not_forced(descr=...) - guard_no_exception(descr=...) - ... - """) - - def test_cmp_exc(self): - def f1(n): - # So we don't get a LOAD_GLOBAL op - KE = KeyError - i = 0 - while i < n: - try: - raise KE - except KE: # ID: except - i += 1 - return i - - log = self.run(f1, [10000]) - assert log.result == 10000 - loop, = log.loops_by_id("except") - ops = list(loop.ops_by_id("except", opcode="COMPARE_OP")) - assert ops == [] - - def test_simple_call(self): - src = """ - OFFSET = 0 - def f(i): - return i + 1 + OFFSET # ID: add - def main(n): - i = 0 - while i < n+OFFSET: # ID: cond - i = f(f(i)) # ID: call - a = 0 - return i - """ - log = self.run(src, [1000], threshold=400) - assert log.result == 1000 - # first, we test what is inside the entry bridge - # ----------------------------------------------- - entry_bridge, = log.loops_by_id('call', is_entry_bridge=True) - # LOAD_GLOBAL of OFFSET - ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", - "getfield_gc", "guard_value", - "getfield_gc", "guard_isnull", - "getfield_gc", "guard_nonnull_class"] - # LOAD_GLOBAL of OFFSET but in different function partially folded - # away - # XXX could be improved - ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_isnull"] - # - # two LOAD_GLOBAL of f, the second is folded away - ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["getfield_gc", "guard_nonnull_class"] - # - assert entry_bridge.match_by_id('call', """ - p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) - p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) - p35 = getfield_gc(p29, descr=) - p36 = getfield_gc(p29, descr=) - p38 = call(ConstClass(getexecutioncontext), descr=) - p39 = getfield_gc(p38, descr=) - i40 = force_token() - p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) - i42 = getfield_gc(p38, descr=) - i43 = int_is_zero(i42) - guard_true(i43, descr=) - i50 = force_token() - """) - # - # then, we test the actual loop - # ----------------------------- - loop, = log.loops_by_id('call') - assert loop.match(""" - i12 = int_lt(i5, i6) - guard_true(i12, descr=) - i13 = force_token() - i15 = int_add(i5, 1) - i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) - i18 = force_token() - i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=) - i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) - """) - - def test_method_call(self): - def fn(n): - class A(object): - def __init__(self, a): - self.a = a - def f(self, i): - return self.a + i - i = 0 - a = A(1) - while i < n: - x = a.f(i) # ID: meth1 - i = a.f(x) # ID: meth2 - return i - # - log = self.run(fn, [1000], threshold=400) - assert log.result == 1000 - # - # first, we test the entry bridge - # ------------------------------- - entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) - ops = entry_bridge.ops_by_id('meth1', opcode='LOOKUP_METHOD') - assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', - 'guard_not_invalidated'] - # the second LOOKUP_METHOD is folded away - assert list(entry_bridge.ops_by_id('meth2', opcode='LOOKUP_METHOD')) == [] - # - # then, the actual loop - # ---------------------- - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i15 = int_lt(i6, i9) - guard_true(i15, descr=) - guard_not_invalidated(descr=) - i16 = force_token() - i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) - i18 = force_token() - i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) - """) - - def test_static_classmethod_call(self): - def fn(n): - class A(object): - @classmethod - def f(cls, i): - return i + (cls is A) + 1 - @staticmethod - def g(i): - return i - 1 - # - i = 0 - a = A() - while i < n: - x = a.f(i) - i = a.g(x) - return i - # - log = self.run(fn, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i14 = int_lt(i6, i9) - guard_true(i14, descr=) - guard_not_invalidated(descr=) - i15 = force_token() - i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) - i18 = force_token() - i20 = int_sub(i17, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i20, p7, i17, i9, p10, p11, p12, descr=) - """) - - def test_default_and_kw(self): - def main(n): - def f(i, j=1): - return i + j - # - i = 0 - while i < n: - i = f(f(i), j=1) # ID: call - a = 0 - return i - # - log = self.run(main, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_id('call') - assert loop.match_by_id('call', """ - i14 = force_token() - i16 = force_token() - """) - - def test_kwargs(self): - # this is not a very precise test, could be improved - def main(x): - def g(**args): - return len(args) - # - s = 0 - d = {} - for i in range(x): - s += g(**d) # ID: call - d[str(i)] = i - if i % 100 == 99: - d = {} - return s - # - log = self.run(main, [1000], threshold=400) - assert log.result == 49500 - loop, = log.loops_by_id('call') - ops = log.opnames(loop.ops_by_id('call')) - guards = [ops for ops in ops if ops.startswith('guard')] - assert len(guards) <= 5 - - def test_stararg_virtual(self): - def main(x): - def g(*args): - return len(args) - def h(a, b, c): - return c - # - s = 0 - for i in range(x): - l = [i, x, 2] - s += g(*l) # ID: g1 - s += h(*l) # ID: h1 - s += g(i, x, 2) # ID: g2 - a = 0 - for i in range(x): - l = [x, 2] - s += g(i, *l) # ID: g3 - s += h(i, *l) # ID: h2 - a = 0 - return s - # - log = self.run(main, [1000], threshold=400) - assert log.result == 13000 - loop0, = log.loops_by_id('g1') - assert loop0.match_by_id('g1', """ - i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) - i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) - """) - assert loop0.match_by_id('h1', """ - i20 = force_token() - i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) - """) - assert loop0.match_by_id('g2', """ - i27 = force_token() - i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) - """) - # - loop1, = log.loops_by_id('g3') - assert loop1.match_by_id('g3', """ - i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) - """) - assert loop1.match_by_id('h2', """ - i25 = force_token() - i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) - """) - - def test_stararg(self): - def main(x): - def g(*args): - return args[-1] - def h(*args): - return len(args) - # - s = 0 - l = [] - i = 0 - while i < x: - l.append(1) - s += g(*l) # ID: g - i = h(*l) # ID: h - a = 0 - return s - # - log = self.run(main, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_id('g') - ops_g = log.opnames(loop.ops_by_id('g')) - ops_h = log.opnames(loop.ops_by_id('h')) - ops = ops_g + ops_h - assert 'new_with_vtable' not in ops - assert 'call_may_force' not in ops - - def test_virtual_instance(self): - def main(n): - class A(object): - pass - # - i = 0 - while i < n: - a = A() - assert isinstance(a, A) - assert not isinstance(a, int) - a.x = 2 - i = i + a.x - return i - # - log = self.run(main, [1000], threshold = 400) - assert log.result == 1000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i5, i6) - guard_true(i7, descr=) - guard_not_invalidated(descr=) - i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, i9, i6, descr=) - """) - - def test_load_attr(self): - src = ''' - class A(object): - pass - a = A() - a.x = 2 - def main(n): - i = 0 - while i < n: - i = i + a.x - return i - ''' - log = self.run(src, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i9 = int_lt(i5, i6) - guard_true(i9, descr=) - guard_not_invalidated(descr=) - i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) - """) - def test_mixed_type_loop(self): def main(n): i = 0.0 @@ -456,7 +79,7 @@ i = j + i return i # - log = self.run(main, [1000], threshold=400) + log = self.run(main, [1000]) assert log.result == 1000.0 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" @@ -467,25 +90,6 @@ jump(p0, p1, p2, p3, p4, f10, p6, f7, f8, descr=) """) - def test_call_builtin_function(self): - def main(n): - i = 2 - l = [] - while i < n: - i += 1 - l.append(i) # ID: append - a = 0 - return i, len(l) - # - log = self.run(main, [1000], threshold=400) - assert log.result == (1000, 998) - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('append', """ - p14 = new_with_vtable(ConstClass(W_IntObject)) - setfield_gc(p14, i12, descr=) - call(ConstClass(ll_append__listPtr_objectPtr), p8, p14, descr=...) - guard_no_exception(descr=) - """) def test_range_iter(self): def main(n): @@ -498,7 +102,7 @@ a = 0 return s # - log = self.run(main, [1000], threshold=400) + log = self.run(main, [1000]) assert log.result == 1000 * 999 / 2 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" @@ -520,76 +124,6 @@ jump(..., descr=) """) - def test_exception_inside_loop_1(self): - def main(n): - while n: - try: - raise ValueError - except ValueError: - pass - n -= 1 - return n - # - log = self.run(main, [1000], threshold=400) - assert log.result == 0 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i5 = int_is_true(i3) - guard_true(i5, descr=) - guard_not_invalidated(descr=) - --EXC-TICK-- - i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) - --TICK-- - jump(..., descr=) - """) - - def test_exception_inside_loop_2(self): - def main(n): - def g(n): - raise ValueError(n) # ID: raise - def f(n): - g(n) - # - while n: - try: - f(n) - except ValueError: - pass - n -= 1 - return n - # - log = self.run(main, [1000], threshold=400) - assert log.result == 0 - loop, = log.loops_by_filename(self.filepath) - ops = log.opnames(loop.ops_by_id('raise')) - assert 'new' not in ops - - def test_reraise(self): - def f(n): - i = 0 - while i < n: - try: - try: - raise KeyError - except KeyError: - raise - except KeyError: - i += 1 - return i - - log = self.run(f, [100000]) - assert log.result == 100000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i4, i5) - guard_true(i7, descr=) - guard_not_invalidated(descr=) - --EXC-TICK-- - i14 = int_add(i4, 1) - --TICK-- - jump(..., descr=) - """) def test_chain_of_guards(self): src = """ @@ -609,445 +143,11 @@ i += 1 return sum """ - log = self.run(src, [0], threshold=400) + log = self.run(src, [0]) assert log.result == 500*3 loops = log.loops_by_filename(self.filepath) assert len(loops) == 1 - def test_getattr_with_dynamic_attribute(self): - src = """ - class A(object): - pass - - l = ["x", "y"] - - def main(): - sum = 0 - a = A() - a.a1 = 0 - a.a2 = 0 - a.a3 = 0 - a.a4 = 0 - a.a5 = 0 # workaround, because the first five attributes need a promotion - a.x = 1 - a.y = 2 - i = 0 - while i < 500: - name = l[i % 2] - sum += getattr(a, name) - i += 1 - return sum - """ - log = self.run(src, [], threshold=400) - assert log.result == 250 + 250*2 - loops = log.loops_by_filename(self.filepath) - assert len(loops) == 1 - - def test_blockstack_virtualizable(self): - def main(n): - from pypyjit import residual_call - i = 0 - while i < n: - try: - residual_call(len, []) # ID: call - except: - pass - i += 1 - return i - # - log = self.run(main, [500], threshold=400) - assert log.result == 500 - loop, = log.loops_by_id('call') - assert loop.match_by_id('call', opcode='CALL_FUNCTION', expected_src=""" - # make sure that the "block" is not allocated - ... - i20 = force_token() - setfield_gc(p0, i20, descr=) - p22 = new_with_vtable(19511408) - p24 = new_array(1, descr=) - p26 = new_with_vtable(ConstClass(W_ListObject)) - p27 = new(descr=) - p29 = new_array(0, descr=) - setfield_gc(p27, p29, descr=) - setfield_gc(p26, p27, descr=<.* .*W_ListObject.inst_wrappeditems .*>) - setarrayitem_gc(p24, 0, p26, descr=) - setfield_gc(p22, p24, descr=) - p32 = call_may_force(11376960, p18, p22, descr=) - ... - """) - - def test_import_in_function(self): - def main(n): - i = 0 - while i < n: - from sys import version # ID: import - i += 1 - return i - # - log = self.run(main, [500], threshold=400) - assert log.result == 500 - loop, = log.loops_by_id('import') - assert loop.match_by_id('import', """ - p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) - p14 = getfield_gc(ConstPtr(ptr13), descr=) - p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) - """) - - def test_import_fast_path(self, tmpdir): - pkg = tmpdir.join('mypkg').ensure(dir=True) - pkg.join('__init__.py').write("") - pkg.join('mod.py').write(str(py.code.Source(""" - def do_the_import(): - import sys - """))) - def main(path, n): - import sys - sys.path.append(path) - from mypkg.mod import do_the_import - for i in range(n): - do_the_import() - # - log = self.run(main, [str(tmpdir), 300], threshold=200) - loop, = log.loops_by_filename(self.filepath) - # this is a check for a slow-down that introduced a - # call_may_force(absolute_import_with_lock). - for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")): - assert 'call' not in opname # no call-like opcode - - def test_arraycopy_disappears(self): - def main(n): - i = 0 - while i < n: - t = (1, 2, 3, i + 1) - t2 = t[:] - del t - i = t2[3] - del t2 - return i - # - log = self.run(main, [500], threshold=400) - assert log.result == 500 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i5, i6) - guard_true(i7, descr=) - i9 = int_add(i5, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, i9, i6, descr=) - """) - - def test_boolrewrite_inverse(self): - """ - Test for this case:: - guard(i < x) - ... - guard(i >= y) - - where x and y can be either constants or variables. There are cases in - which the second guard is proven to be always true. - """ - - for a, b, res, opt_expected in (('2000', '2000', 20001000, True), - ( '500', '500', 15001500, True), - ( '300', '600', 16001700, False), - ( 'a', 'b', 16001700, False), - ( 'a', 'a', 13001700, True)): - src = """ - def main(): - sa = 0 - a = 300 - b = 600 - for i in range(1000): - if i < %s: # ID: lt - sa += 1 - else: - sa += 2 - # - if i >= %s: # ID: ge - sa += 10000 - else: - sa += 20000 - return sa - """ % (a, b) - # - log = self.run(src, [], threshold=400) - assert log.result == res - loop, = log.loops_by_filename(self.filepath) - le_ops = log.opnames(loop.ops_by_id('lt')) - ge_ops = log.opnames(loop.ops_by_id('ge')) - assert le_ops.count('int_lt') == 1 - # - if opt_expected: - assert ge_ops.count('int_ge') == 0 - else: - # if this assert fails it means that the optimization was - # applied even if we don't expect to. Check whether the - # optimization is valid, and either fix the code or fix the - # test :-) - assert ge_ops.count('int_ge') == 1 - - def test_boolrewrite_reflex(self): - """ - Test for this case:: - guard(i < x) - ... - guard(y > i) - - where x and y can be either constants or variables. There are cases in - which the second guard is proven to be always true. - """ - for a, b, res, opt_expected in (('2000', '2000', 10001000, True), - ( '500', '500', 15001500, True), - ( '300', '600', 14001700, False), - ( 'a', 'b', 14001700, False), - ( 'a', 'a', 17001700, True)): - - src = """ - def main(): - sa = 0 - a = 300 - b = 600 - for i in range(1000): - if i < %s: # ID: lt - sa += 1 - else: - sa += 2 - if %s > i: # ID: gt - sa += 10000 - else: - sa += 20000 - return sa - """ % (a, b) - log = self.run(src, [], threshold=400) - assert log.result == res - loop, = log.loops_by_filename(self.filepath) - le_ops = log.opnames(loop.ops_by_id('lt')) - gt_ops = log.opnames(loop.ops_by_id('gt')) - assert le_ops.count('int_lt') == 1 - # - if opt_expected: - assert gt_ops.count('int_gt') == 0 - else: - # if this assert fails it means that the optimization was - # applied even if we don't expect to. Check whether the - # optimization is valid, and either fix the code or fix the - # test :-) - assert gt_ops.count('int_gt') == 1 - - - def test_boolrewrite_allcases_inverse(self): - """ - Test for this case:: - guard(i < x) - ... - guard(i > y) - - with all possible combination of binary comparison operators. This - test only checks that we get the expected result, not that any - optimization has been applied. - """ - ops = ('<', '>', '<=', '>=', '==', '!=') - for op1 in ops: - for op2 in ops: - for a,b in ((500, 500), (300, 600)): - src = """ - def main(): - sa = 0 - for i in range(300): - if i %s %d: - sa += 1 - else: - sa += 2 - if i %s %d: - sa += 10000 - else: - sa += 20000 - return sa - """ % (op1, a, op2, b) - self.run_and_check(src, threshold=200) - - src = """ - def main(): - sa = 0 - i = 0.0 - while i < 250.0: - if i %s %f: - sa += 1 - else: - sa += 2 - if i %s %f: - sa += 10000 - else: - sa += 20000 - i += 0.25 - return sa - """ % (op1, float(a)/4.0, op2, float(b)/4.0) - self.run_and_check(src, threshold=300) - - - def test_boolrewrite_allcases_reflex(self): - """ - Test for this case:: - guard(i < x) - ... - guard(x > i) - - with all possible combination of binary comparison operators. This - test only checks that we get the expected result, not that any - optimization has been applied. - """ - ops = ('<', '>', '<=', '>=', '==', '!=') - for op1 in ops: - for op2 in ops: - for a,b in ((500, 500), (300, 600)): - src = """ - def main(): - sa = 0 - for i in range(300): - if i %s %d: - sa += 1 - else: - sa += 2 - if %d %s i: - sa += 10000 - else: - sa += 20000 - return sa - """ % (op1, a, b, op2) - self.run_and_check(src, threshold=200) - - src = """ - def main(): - sa = 0 - i = 0.0 - while i < 250.0: - if i %s %f: - sa += 1 - else: - sa += 2 - if %f %s i: - sa += 10000 - else: - sa += 20000 - i += 0.25 - return sa - """ % (op1, float(a)/4.0, float(b)/4.0, op2) - self.run_and_check(src, threshold=300) - - def test_boolrewrite_ptr(self): - """ - This test only checks that we get the expected result, not that any - optimization has been applied. - """ - compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b') - for e1 in compares: - for e2 in compares: - src = """ - class tst(object): - pass - def main(): - a = tst() - b = tst() - c = tst() - sa = 0 - for i in range(300): - if %s: - sa += 1 - else: - sa += 2 - if %s: - sa += 10000 - else: - sa += 20000 - if i > 750: - a = b - return sa - """ % (e1, e2) - self.run_and_check(src, threshold=200) - - def test_array_sum(self): - def main(): - from array import array - img = array("i", range(128) * 5) * 480 - l, i = 0, 0 - while i < len(img): - l += img[i] - i += 1 - return l - # - log = self.run(main, []) - assert log.result == 19507200 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i13 = int_lt(i7, i9) - guard_true(i13, descr=) - i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) - i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) - i18 = int_add(i7, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) - """) - - def test_array_intimg(self): - def main(): - from array import array - img = array('i', range(3)) * (350 * 480) - intimg = array('i', (0,)) * (640 * 480) - l, i = 0, 640 - while i < 640 * 480: - assert len(img) == 3*350*480 - assert len(intimg) == 640*480 - l = l + img[i] - intimg[i] = (intimg[i-640] + l) - i += 1 - return intimg[i - 1] - # - log = self.run(main, []) - assert log.result == 73574560 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i13 = int_lt(i8, 307200) - guard_true(i13, descr=) - # the bound check guard on img has been killed (thanks to the asserts) - i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) - i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) - i17 = int_sub(i8, 640) - # the bound check guard on intimg has been killed (thanks to the asserts) - i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) - i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) - # on 64bit, there is a guard checking that i19 actually fits into 32bit - ... - setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) - i28 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) - """) - - def test_func_defaults(self): - def main(n): - i = 1 - while i < n: - i += len(xrange(i+1)) - i - return i - - log = self.run(main, [10000]) - assert log.result == 10000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i5, i6) - guard_true(i10, descr=) - i120 = int_add(i5, 1) - guard_not_invalidated(descr=) - --TICK-- - jump(..., descr=) - """) def test_unpack_iterable_non_list_tuple(self): def main(n): @@ -1067,7 +167,7 @@ guard_false(i16, descr=) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) + setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, 146982464, descr=) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) @@ -1079,652 +179,56 @@ i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) - def test_mutate_class(self): - def fn(n): - class A(object): - count = 1 - def __init__(self, a): - self.a = a - def f(self): - return self.count - i = 0 - a = A(1) - while i < n: - A.count += 1 # ID: mutate - i = a.f() # ID: meth1 - return i + + def test_dont_trace_every_iteration(self): + def main(a, b): + i = sa = 0 + while i < 300: + if a > 0: + pass + if 1 < b < 2: + pass + sa += a % b + i += 1 + return sa # - log = self.run(fn, [1000], threshold=10) - assert log.result == 1000 - # - # first, we test the entry bridge - # ------------------------------- - entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) - ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') - assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc', 'guard_nonnull_class'] - # the STORE_ATTR is folded away - assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] - # - # then, the actual loop - # ---------------------- + log = self.run(main, [10, 20]) + assert log.result == 300 * (10 % 20) + assert log.jit_summary.tracing_no == 1 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i8 = getfield_gc_pure(p5, descr=) - i9 = int_lt(i8, i7) - guard_true(i9, descr=.*) - guard_not_invalidated(descr=.*) - i11 = int_add(i8, 1) - i12 = force_token() + i11 = int_lt(i7, 300) + guard_true(i11, descr=) + i12 = int_add_ovf(i8, i9) + guard_no_overflow(descr=) + i14 = int_add(i7, 1) --TICK-- - p20 = new_with_vtable(ConstClass(W_IntObject)) - setfield_gc(p20, i11, descr=) - setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i7, descr=) + jump(..., descr=...) """) + # + log = self.run(main, [-10, -20]) + assert log.result == 300 * (-10 % -20) + assert log.jit_summary.tracing_no == 1 - def test_intbound_simple(self): + def test_overflow_checking(self): """ This test only checks that we get the expected result, not that any optimization has been applied. """ - ops = ('<', '>', '<=', '>=', '==', '!=') - nbr = (3, 7) - for o1 in ops: - for o2 in ops: - for n1 in nbr: - for n2 in nbr: - src = ''' - def f(i): - a, b = 3, 3 - if i %s %d: - a = 0 - else: - a = 1 - if i %s %d: - b = 0 - else: - b = 1 - return a + b * 2 - - def main(): - res = [0] * 4 - idx = [] - for i in range(15): - idx.extend([i] * 15) - for i in idx: - res[f(i)] += 1 - return res - - ''' % (o1, n1, o2, n2) - self.run_and_check(src, threshold=200) - - def test_intbound_addsub_mix(self): - """ - This test only checks that we get the expected result, not that any - optimization has been applied. - """ - tests = ('i > 4', 'i > 2', 'i + 1 > 2', '1 + i > 4', - 'i - 1 > 1', '1 - i > 1', '1 - i < -3', - 'i == 1', 'i == 5', 'i != 1', '-2 * i < -4') - for t1 in tests: - for t2 in tests: - src = ''' - def f(i): - a, b = 3, 3 - if %s: - a = 0 - else: - a = 1 - if %s: - b = 0 - else: - b = 1 - return a + b * 2 - - def main(): - res = [0] * 4 - idx = [] - for i in range(15): - idx.extend([i] * 15) - for i in idx: - res[f(i)] += 1 - return res - - ''' % (t1, t2) - self.run_and_check(src, threshold=200) - - def test_intbound_gt(self): - def main(n): - i, a, b = 0, 0, 0 - while i < n: - if i > -1: - a += 1 - if i > -2: - b += 1 - i += 1 - return (a, b) + def main(): + import sys + def f(a,b): + if a < 0: return -1 + return a-b + # + total = sys.maxint - 2147483647 + for i in range(100000): + total += f(i, 5) + # + return total # - log = self.run(main, [300], threshold=200) - assert log.result == (300, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, i9) - guard_true(i10, descr=...) - i12 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i14 = int_add_ovf(i6, 1) - guard_no_overflow(descr=...) - i17 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) - """) - - def test_intbound_sub_lt(self): - def main(): - i, a = 0, 0 - while i < 300: - if i - 10 < 295: - a += 1 - i += 1 - return a - # - log = self.run(main, [], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i5, 300) - guard_true(i7, descr=...) - i9 = int_sub_ovf(i5, 10) - guard_no_overflow(descr=...) - i11 = int_add_ovf(i4, 1) - guard_no_overflow(descr=...) - i13 = int_add(i5, 1) - --TICK-- - jump(p0, p1, p2, p3, i11, i13, descr=) - """) - - def test_intbound_addsub_ge(self): - def main(n): - i, a, b = 0, 0, 0 - while i < n: - if i + 5 >= 5: - a += 1 - if i - 1 >= -1: - b += 1 - i += 1 - return (a, b) - # - log = self.run(main, [300], threshold=200) - assert log.result == (300, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, i9) - guard_true(i10, descr=...) - i12 = int_add_ovf(i8, 5) - guard_no_overflow(descr=...) - i14 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i16 = int_add_ovf(i6, 1) - guard_no_overflow(descr=...) - i19 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) - """) - - def test_intbound_addmul_ge(self): - def main(n): - i, a, b = 0, 0, 0 - while i < 300: - if i + 5 >= 5: - a += 1 - if 2 * i >= 0: - b += 1 - i += 1 - return (a, b) - # - log = self.run(main, [300], threshold=200) - assert log.result == (300, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, 300) - guard_true(i10, descr=...) - i12 = int_add(i8, 5) - i14 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i16 = int_lshift(i8, 1) - i18 = int_add_ovf(i6, 1) - guard_no_overflow(descr=...) - i21 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) - """) - - def test_intbound_eq(self): - def main(a, n): - i, s = 0, 0 - while i < 300: - if a == 7: - s += a + 1 - elif i == 10: - s += i - else: - s += 1 - i += 1 - return s - # - log = self.run(main, [7, 300], threshold=200) - assert log.result == main(7, 300) - log = self.run(main, [10, 300], threshold=200) - assert log.result == main(10, 300) - log = self.run(main, [42, 300], threshold=200) - assert log.result == main(42, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, 300) - guard_true(i10, descr=...) - i12 = int_eq(i8, 10) - guard_false(i12, descr=...) - i14 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i16 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) - """) - - def test_intbound_mul(self): - def main(a): - i, s = 0, 0 - while i < 300: - assert i >= 0 - if 2 * i < 30000: - s += 1 - else: - s += a - i += 1 - return s - # - log = self.run(main, [7], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i8 = int_lt(i6, 300) - guard_true(i8, descr=...) - i10 = int_lshift(i6, 1) - i12 = int_add_ovf(i5, 1) - guard_no_overflow(descr=...) - i14 = int_add(i6, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, i12, i14, descr=) - """) - - def test_assert(self): - def main(a): - i, s = 0, 0 - while i < 300: - assert a == 7 - s += a + 1 - i += 1 - return s - log = self.run(main, [7], threshold=200) - assert log.result == 300*8 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i8 = int_lt(i6, 300) - guard_true(i8, descr=...) - i10 = int_add_ovf(i5, 8) - guard_no_overflow(descr=...) - i12 = int_add(i6, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, i10, i12, descr=) - """) - - def test_zeropadded(self): - def main(): - from array import array - class ZeroPadded(array): - def __new__(cls, l): - self = array.__new__(cls, 'd', range(l)) - return self - - def __getitem__(self, i): - if i < 0 or i >= len(self): - return 0 - return array.__getitem__(self, i) # ID: get - # - buf = ZeroPadded(2000) - i = 10 - sa = 0 - while i < 2000 - 10: - sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] - i += 1 - return sa - - log = self.run(main, [], threshold=200) - assert log.result == 9895050.0 - loop, = log.loops_by_filename(self.filepath) - # - # check that the overloaded __getitem__ does not introduce double - # array bound checks. - # - # The force_token()s are still there, but will be eliminated by the - # backend regalloc, so they are harmless - assert loop.match(ignore_ops=['force_token'], - expected_src=""" - ... - i20 = int_ge(i18, i8) - guard_false(i20, descr=...) - f21 = getarrayitem_raw(i13, i18, descr=...) - f23 = getarrayitem_raw(i13, i14, descr=...) - f24 = float_add(f21, f23) - f26 = getarrayitem_raw(i13, i6, descr=...) - f27 = float_add(f24, f26) - i29 = int_add(i6, 1) - i31 = int_ge(i29, i8) - guard_false(i31, descr=...) - f33 = getarrayitem_raw(i13, i29, descr=...) - f34 = float_add(f27, f33) - i36 = int_add(i6, 2) - i38 = int_ge(i36, i8) - guard_false(i38, descr=...) - f39 = getarrayitem_raw(i13, i36, descr=...) - ... - """) - - - def test_circular(self): - def main(): - from array import array - class Circular(array): - def __new__(cls): - self = array.__new__(cls, 'd', range(256)) - return self - def __getitem__(self, i): - assert len(self) == 256 - return array.__getitem__(self, i & 255) - # - buf = Circular() - i = 10 - sa = 0 - while i < 2000 - 10: - sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] - i += 1 - return sa - # - log = self.run(main, [], threshold=200) - assert log.result == 1239690.0 - loop, = log.loops_by_filename(self.filepath) - # - # check that the array bound checks are removed - # - # The force_token()s are still there, but will be eliminated by the - # backend regalloc, so they are harmless - assert loop.match(ignore_ops=['force_token'], - expected_src=""" - ... - i17 = int_and(i14, 255) - f18 = getarrayitem_raw(i8, i17, descr=...) - f20 = getarrayitem_raw(i8, i9, descr=...) - f21 = float_add(f18, f20) - f23 = getarrayitem_raw(i8, i10, descr=...) - f24 = float_add(f21, f23) - i26 = int_add(i6, 1) - i29 = int_and(i26, 255) - f30 = getarrayitem_raw(i8, i29, descr=...) - f31 = float_add(f24, f30) - i33 = int_add(i6, 2) - i36 = int_and(i33, 255) - f37 = getarrayitem_raw(i8, i36, descr=...) - ... - """) - - def test_min_max(self): - def main(): - i=0 - sa=0 - while i < 300: - sa+=min(max(i, 3000), 4000) - i+=1 - return sa - log = self.run(main, [], threshold=200) - assert log.result == 300*3000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i4, 300) - guard_true(i7, descr=...) - i9 = int_add_ovf(i5, 3000) - guard_no_overflow(descr=...) - i11 = int_add(i4, 1) - --TICK-- - jump(p0, p1, p2, p3, i11, i9, descr=) - """) - - def test_silly_max(self): - def main(): - i = 2 - sa = 0 - while i < 300: - lst = range(i) - sa += max(*lst) # ID: max - i += 1 - return sa - log = self.run(main, [], threshold=200) - assert log.result == main() - loop, = log.loops_by_filename(self.filepath) - # We dont want too many guards, but a residual call to min_max_loop - guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] - assert len(guards) < 20 - assert loop.match_by_id('max',""" - ... - p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) - ... - """) - - def test_iter_max(self): - def main(): - i = 2 - sa = 0 - while i < 300: - lst = range(i) - sa += max(lst) # ID: max - i += 1 - return sa - log = self.run(main, [], threshold=200) - assert log.result == main() - loop, = log.loops_by_filename(self.filepath) - # We dont want too many guards, but a residual call to min_max_loop - guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] - assert len(guards) < 20 - assert loop.match_by_id('max',""" - ... - p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) - ... - """) - - def test__ffi_call(self): - from pypy.rlib.test.test_libffi import get_libm_name - def main(libm_name): - try: - from _ffi import CDLL, types - except ImportError: - sys.stderr.write('SKIP: cannot import _ffi\n') - return 0 - - libm = CDLL(libm_name) - pow = libm.getfunc('pow', [types.double, types.double], - types.double) - i = 0 - res = 0 - while i < 300: - res += pow(2, 3) - i += 1 - return pow.getaddr(), res - # - libm_name = get_libm_name(sys.platform) - log = self.run(main, [libm_name], threshold=200) - pow_addr, res = log.result - assert res == 8.0 * 300 - loop, = log.loops_by_filename(self.filepath) - # XXX: write the actual test when we merge this to jitypes2 - ## ops = self.get_by_bytecode('CALL_FUNCTION') - ## assert len(ops) == 2 # we get two loops, because of specialization - ## call_function = ops[0] - ## last_ops = [op.getopname() for op in call_function[-5:]] - ## assert last_ops == ['force_token', - ## 'setfield_gc', - ## 'call_may_force', - ## 'guard_not_forced', - ## 'guard_no_exception'] - ## call = call_function[-3] - ## assert call.getarg(0).value == pow_addr - ## assert call.getarg(1).value == 2.0 - ## assert call.getarg(2).value == 3.0 - - def test_xor(self): - def main(b): - a = sa = 0 - while a < 300: - if a > 0: # Specialises the loop - pass - if b > 10: - pass - if a^b >= 0: # ID: guard - sa += 1 - sa += a^a # ID: a_xor_a - a += 1 - return sa - - log = self.run(main, [11], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - # if both are >=0, a^b is known to be >=0 - # note that we know that b>10 - assert loop.match_by_id('guard', """ - i10 = int_xor(i5, i7) - """) - # - # x^x is always optimized to 0 - assert loop.match_by_id('a_xor_a', "") - - log = self.run(main, [9], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - # we don't know that b>10, hence we cannot optimize it - assert loop.match_by_id('guard', """ - i10 = int_xor(i5, i7) - i12 = int_ge(i10, 0) - guard_true(i12, descr=...) - """) - - def test_shift_intbound(self): - def main(b): - res = 0 - a = 0 - while a < 300: - assert a >= 0 - assert 0 <= b <= 10 - val = a >> b - if val >= 0: # ID: rshift - res += 1 - val = a << b - if val >= 0: # ID: lshift - res += 2 - a += 1 - return res - # - log = self.run(main, [2], threshold=200) - assert log.result == 300*3 - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('rshift', "") # guard optimized away - assert loop.match_by_id('lshift', "") # guard optimized away - - def test_lshift_and_then_rshift(self): - py.test.skip('fixme, this optimization is disabled') - def main(b): - res = 0 - a = 0 - while res < 300: - assert a >= 0 - assert 0 <= b <= 10 - res = (a << b) >> b # ID: shift - a += 1 - return res - # - log = self.run(main, [2], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('shift', "") # optimized away - - def test_division_to_rshift(self): - py.test.skip('in-progress') - def main(b): - res = 0 - a = 0 - while a < 300: - assert a >= 0 - assert 0 <= b <= 10 - res = a/b # ID: div - a += 1 - return res - # - log = self.run(main, [3], threshold=200) - #assert log.result == 149 - loop, = log.loops_by_filename(self.filepath) - import pdb;pdb.set_trace() - assert loop.match_by_id('div', "") # optimized away - - def test_oldstyle_newstyle_mix(self): - def main(): - class A: - pass - - class B(object, A): - def __init__(self, x): - self.x = x - - i = 0 - b = B(1) - while i < 100: - v = b.x # ID: loadattr - i += v - return i - - log = self.run(main, [], threshold=80) - loop, = log.loops_by_filename(self.filepath) - loop.match_by_id('loadattr', - ''' - guard_not_invalidated(descr=...) - i19 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) - guard_no_exception(descr=...) - i21 = int_and(i19, _) - i22 = int_is_true(i21) - guard_true(i22, descr=...) - i26 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) - guard_no_exception(descr=...) - i28 = int_and(i26, _) - i29 = int_is_true(i28) - guard_true(i29, descr=...) - ''') - - def test_python_contains(self): - def main(): - class A(object): - def __contains__(self, v): - return True - - i = 0 - a = A() - while i < 100: - i += i in a # ID: contains - - log = self.run(main, [], threshold=80) - loop, = log.loops_by_filename(self.filemath) - # XXX: haven't confirmed his is correct, it's probably missing a - # few instructions - loop.match_by_id("contains", """ - i1 = int_add(i0, 1) - """) \ No newline at end of file + self.run_and_check(main, []) diff --git a/pypy/module/pypyjit/test_pypy_c/test_shift.py b/pypy/module/pypyjit/test_pypy_c/test_shift.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_shift.py @@ -0,0 +1,166 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestShift(BaseTestPyPyC): + + def test_shift_intbound(self): + def main(b): + res = 0 + a = 0 + while a < 300: + assert a >= 0 + assert 0 <= b <= 10 + val = a >> b + if val >= 0: # ID: rshift + res += 1 + val = a << b + if val >= 0: # ID: lshift + res += 2 + a += 1 + return res + # + log = self.run(main, [2]) + assert log.result == 300*3 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('rshift', "") # guard optimized away + assert loop.match_by_id('lshift', "") # guard optimized away + + def test_lshift_and_then_rshift(self): + py.test.skip('fixme, this optimization is disabled') + def main(b): + res = 0 + a = 0 + while res < 300: + assert a >= 0 + assert 0 <= b <= 10 + res = (a << b) >> b # ID: shift + a += 1 + return res + # + log = self.run(main, [2]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('shift', "") # optimized away + + def test_division_to_rshift(self): + def main(b): + res = 0 + a = 0 + while a < 300: + assert a >= 0 + assert 0 <= b <= 10 + res = a/b # ID: div + a += 1 + return res + # + log = self.run(main, [3]) + assert log.result == 99 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('div', """ + i10 = int_floordiv(i6, i7) + i11 = int_mul(i10, i7) + i12 = int_sub(i6, i11) + i14 = int_rshift(i12, 63) + i15 = int_add(i10, i14) + """) + + def test_division_to_rshift_allcases(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + avalues = ('a', 'b', 7, -42, 8) + bvalues = ['b'] + range(-10, 0) + range(1,10) + code = '' + for a in avalues: + for b in bvalues: + code += ' sa += %s / %s\n' % (a, b) + src = """ + def main(a, b): + i = sa = 0 + while i < 300: +%s + i += 1 + return sa + """ % code + self.run_and_check(src, [ 10, 20]) + self.run_and_check(src, [ 10, -20]) + self.run_and_check(src, [-10, -20]) + + def test_mod(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + avalues = ('a', 'b', 7, -42, 8) + bvalues = ['b'] + range(-10, 0) + range(1,10) + code = '' + for a in avalues: + for b in bvalues: + code += ' sa += %s %% %s\n' % (a, b) + src = """ + def main(a, b): + i = sa = 0 + while i < 2000: + if a > 0: pass + if 1 < b < 2: pass +%s + i += 1 + return sa + """ % code + self.run_and_check(src, [ 10, 20]) + self.run_and_check(src, [ 10, -20]) + self.run_and_check(src, [-10, -20]) + + def test_shift_allcases(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + from sys import maxint + def main(a, b): + i = sa = 0 + while i < 300: + if a > 0: # Specialises the loop + pass + if b < 2 and b > 0: + pass + if (a >> b) >= 0: + sa += 1 + if (a << b) > 2: + sa += 10000 + i += 1 + return sa + # + maxvals = (-maxint-1, -maxint, maxint-1, maxint) + for a in (-4, -3, -2, -1, 0, 1, 2, 3, 4) + maxvals: + for b in (0, 1, 2, 31, 32, 33, 61, 62, 63): + yield self.run_and_check, main, [a, b] + + def test_revert_shift_allcases(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + from sys import maxint + + def main(a, b, c): + from sys import maxint + i = sa = 0 + while i < 300: + if 0 < a < 10: pass + if -100 < b < 100: pass + if -maxint/2 < c < maxint/2: pass + sa += (a<>a + sa += (b<>a + sa += (c<>a + sa += (a<<100)>>100 + sa += (b<<100)>>100 + sa += (c<<100)>>100 + i += 1 + return long(sa) + + for a in (1, 4, 8, 100): + for b in (-10, 10, -201, 201, -maxint/3, maxint/3): + for c in (-10, 10, -maxint/3, maxint/3): + yield self.run_and_check, main, [a, b, c] diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -0,0 +1,42 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestString(BaseTestPyPyC): + def test_lookup_default_encoding(self): + def main(n): + import string + i = 0 + letters = string.letters + uletters = unicode(string.letters) + while i < n: + i += letters[i % len(letters)] == uletters[i % len(letters)] + return i + + log = self.run(main, [300]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i14 = int_lt(i6, i9) + guard_true(i14, descr=) + i15 = int_mod(i6, i10) + i17 = int_rshift(i15, 63) + i18 = int_and(i10, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=) + i22 = int_ge(i19, i10) + guard_false(i22, descr=) + i23 = strgetitem(p11, i19) + i24 = int_ge(i19, i12) + guard_false(i24, descr=) + i25 = unicodegetitem(p13, i19) + guard_not_invalidated(descr=) + p27 = newstr(1) + strsetitem(p27, 0, i23) + p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) + guard_no_exception(descr=) + i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) + guard_true(i32, descr=) + i34 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) \ No newline at end of file diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -7,6 +7,8 @@ class Module(MixedModule): """Sys Builtin Module. """ + _immutable_fields_ = ["defaultencoding?"] + def __init__(self, space, w_name): """NOT_RPYTHON""" # because parent __init__ isn't if space.config.translating: @@ -150,7 +152,7 @@ if operror is None: return space.w_None else: - return space.wrap(operror.application_traceback) + return space.wrap(operror.get_traceback()) return None def get_w_default_encoder(self): diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -40,24 +40,24 @@ break depth -= 1 f = ec.getnextframe_nohidden(f) + f.mark_as_escaped() return space.wrap(f) def setrecursionlimit(space, w_new_limit): - """setrecursionlimit() is ignored (and not needed) on PyPy. - -On CPython it would set the maximum number of nested calls that can -occur before a RuntimeError is raised. On PyPy overflowing the stack -also causes RuntimeErrors, but the limit is checked at a lower level. -(The limit is currenty hard-coded at 768 KB, corresponding to roughly -1480 Python calls on Linux.)""" + """setrecursionlimit() sets the maximum number of nested calls that +can occur before a RuntimeError is raised. On PyPy the limit is +approximative and checked at a lower level. The default 1000 +reserves 768KB of stack space, which should suffice (on Linux, +depending on the compiler settings) for ~1400 calls. Setting the +value to N reserves N/1000 times 768KB of stack space. +""" + from pypy.rlib.rstack import _stack_set_length_fraction new_limit = space.int_w(w_new_limit) if new_limit <= 0: raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) - # for now, don't rewrite a warning but silently ignore the - # recursion limit. - #space.warn('setrecursionlimit() is ignored (and not needed) on PyPy', space.w_RuntimeWarning) space.sys.recursionlimit = new_limit + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). @@ -91,7 +91,7 @@ return space.newtuple([space.w_None,space.w_None,space.w_None]) else: return space.newtuple([operror.w_type, operror.get_w_value(space), - space.wrap(operror.application_traceback)]) + space.wrap(operror.get_traceback())]) def exc_clear(space): """Clear global information on the current exception. Subsequent calls diff --git a/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c b/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c --- a/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c +++ b/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c @@ -43,6 +43,12 @@ qsort(base, num, width, compare); } +EXPORT(char) deref_LP_c_char_p(char** argv) +{ + char* s = *argv; + return s[0]; +} + EXPORT(int *) _testfunc_ai8(int a[8]) { return a; diff --git a/pypy/module/test_lib_pypy/ctypes_tests/support.py b/pypy/module/test_lib_pypy/ctypes_tests/support.py --- a/pypy/module/test_lib_pypy/ctypes_tests/support.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/support.py @@ -1,4 +1,5 @@ import py +import sys import ctypes py.test.importorskip("ctypes", "1.0.2") @@ -14,6 +15,16 @@ if _rawffi: py.test.skip("white-box tests for pypy _rawffi based ctypes impl") +def del_funcptr_refs_maybe(obj, attrname): + dll = getattr(obj, attrname, None) + if not dll: + return + _FuncPtr = dll._FuncPtr + for name in dir(dll): + obj = getattr(dll, name, None) + if isinstance(obj, _FuncPtr): + delattr(dll, name) + class BaseCTypesTestChecker: def setup_class(cls): if _rawffi: @@ -21,8 +32,21 @@ for _ in range(4): gc.collect() cls.old_num = _rawffi._num_of_allocated_objects() - + + def teardown_class(cls): + if sys.pypy_translation_info['translation.gc'] == 'boehm': + return # it seems that boehm has problems with __del__, so not + # everything is freed + # + mod = sys.modules[cls.__module__] + del_funcptr_refs_maybe(mod, 'dll') + del_funcptr_refs_maybe(mod, 'dll2') + del_funcptr_refs_maybe(mod, 'lib') + del_funcptr_refs_maybe(mod, 'testdll') + del_funcptr_refs_maybe(mod, 'ctdll') + del_funcptr_refs_maybe(cls, '_dll') + # if hasattr(cls, 'old_num'): import gc for _ in range(4): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py @@ -0,0 +1,103 @@ +from ctypes import CDLL, POINTER, pointer, c_byte, c_int, c_char_p +import sys +import py +from support import BaseCTypesTestChecker + +class MyCDLL(CDLL): + def __getattr__(self, attr): + fn = self[attr] # this way it's not cached as an attribute + fn._slowpath_allowed = False + return fn + +def setup_module(mod): + import conftest + _ctypes_test = str(conftest.sofile) + mod.dll = MyCDLL(_ctypes_test) # slowpath not allowed + mod.dll2 = CDLL(_ctypes_test) # slowpath allowed + + +class TestFastpath(BaseCTypesTestChecker): + + def test_fastpath_forbidden(self): + def myfunc(): + pass + # + tf_b = dll.tf_b + tf_b.restype = c_byte + # + # so far, it's still using the slowpath + assert not tf_b._is_fastpath + tf_b.callable = myfunc + tf_b.argtypes = (c_byte,) + # errcheck prevented the fastpath to kick in + assert not tf_b._is_fastpath + # + del tf_b.callable + tf_b.argtypes = (c_byte,) # try to re-enable the fastpath + assert tf_b._is_fastpath + # + assert not tf_b._slowpath_allowed + py.test.raises(AssertionError, "tf_b.callable = myfunc") + py.test.raises(AssertionError, "tf_b('aaa')") # force a TypeError + + def test_simple_args(self): + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + assert tf_b(-126) == -42 + + def test_pointer_args(self): + f = dll._testfunc_p_p + f.restype = POINTER(c_int) + f.argtypes = [POINTER(c_int)] + v = c_int(42) + result = f(pointer(v)) + assert type(result) == POINTER(c_int) + assert result.contents.value == 42 + + def test_simple_pointer_args(self): + f = dll.my_strchr + f.argtypes = [c_char_p, c_int] + f.restype = c_char_p + mystr = c_char_p("abcd") + result = f(mystr, ord("b")) + assert result == "bcd" + + @py.test.mark.xfail + def test_strings(self): + f = dll.my_strchr + f.argtypes = [c_char_p, c_int] + f.restype = c_char_p + # python strings need to be converted to c_char_p, but this is + # supported only in the slow path so far + result = f("abcd", ord("b")) + assert result == "bcd" + + def test_errcheck(self): + def errcheck(result, func, args): + return 'hello' + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + tf_b.errcheck = errcheck + assert tf_b(-126) == 'hello' + + +class TestFallbackToSlowpath(BaseCTypesTestChecker): + + def test_argtypes_is_None(self): + tf_b = dll2.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_char_p,) # this is intentionally wrong + tf_b.argtypes = None # kill the fast path + assert not tf_b._is_fastpath + assert tf_b(-126) == -42 + + def test_callable_is_None(self): + tf_b = dll2.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + tf_b.callable = lambda x: x+1 + assert not tf_b._is_fastpath + assert tf_b(-126) == -125 + tf_b.callable = None diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -91,6 +91,13 @@ result = f(0, 0, 0, 0, 0, 0) assert result == u'\x00' + def test_char_result(self): + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_char + result = f(0, 0, 0, 0, 0, 0) + assert result == '\x00' + def test_voidresult(self): f = dll._testfunc_v f.restype = None @@ -211,8 +218,19 @@ result = f(byref(c_int(99))) assert not result.contents == 99 + def test_convert_pointers(self): + f = dll.deref_LP_c_char_p + f.restype = c_char + f.argtypes = [POINTER(c_char_p)] + # + s = c_char_p('hello world') + ps = pointer(s) + assert f(ps) == 'h' + assert f(s) == 'h' # automatic conversion from char** to char* + def test_errors_1(self): f = dll._testfunc_p_p + f.argtypes = [POINTER(c_int)] f.restype = c_int class X(Structure): @@ -428,6 +446,16 @@ u = dll.ret_un_func(a[1]) assert u.y == 33*10000 + def test_cache_funcptr(self): + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + assert tf_b(-126) == -42 + ptr = tf_b._ptr + assert ptr is not None + assert tf_b(-126) == -42 + assert tf_b._ptr is ptr + def test_warnings(self): import warnings warnings.simplefilter("always") @@ -439,6 +467,22 @@ assert "C function without declared arguments called" in str(w[0].message) assert "C function without declared return type called" in str(w[1].message) + def test_errcheck(self): + py.test.skip('fixme') + def errcheck(result, func, args): + assert result == -42 + assert type(result) is int + arg, = args + assert arg == -126 + assert type(arg) is int + return result + # + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + tf_b.errcheck = errcheck + assert tf_b(-126) == -42 + del tf_b.errcheck with warnings.catch_warnings(record=True) as w: dll.get_an_integer.argtypes = [] dll.get_an_integer() diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py @@ -12,8 +12,10 @@ from _ctypes.function import CFuncPtr def guess(value): - cobj = CFuncPtr._conv_param(None, value) - return type(cobj) + cobj, ctype = CFuncPtr._conv_param(None, value) + return ctype + ## cobj = CFuncPtr._conv_param(None, value) + ## return type(cobj) assert guess(13) == c_int assert guess(0) == c_int diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py @@ -125,6 +125,9 @@ if t is c_longdouble: # no support for 'g' in the struct module continue code = t._type_ # the typecode + if code == 'g': + # typecode not supported by "struct" + continue align = struct.calcsize("c%c" % code) - struct.calcsize(code) # alignment of the type... diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py @@ -12,6 +12,13 @@ mod._ctypes_test = str(conftest.sofile) class TestPointers(BaseCTypesTestChecker): + + def test_get_ffi_argtype(self): + P = POINTER(c_int) + ffitype = P.get_ffi_argtype() + assert P.get_ffi_argtype() is ffitype + assert ffitype.deref_pointer() is c_int.get_ffi_argtype() + def test_pointer_crash(self): class A(POINTER(c_ulong)): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py b/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py @@ -15,6 +15,10 @@ mod.wcslen.argtypes = [ctypes.c_wchar_p] mod.func = dll._testfunc_p_p + def teardown_module(mod): + del mod.func + del mod.wcslen + class TestUnicode(BaseCTypesTestChecker): def setup_method(self, method): self.prev_conv_mode = ctypes.set_conversion_mode("ascii", "strict") diff --git a/pypy/module/test_lib_pypy/test_stackless.py b/pypy/module/test_lib_pypy/test_stackless.py --- a/pypy/module/test_lib_pypy/test_stackless.py +++ b/pypy/module/test_lib_pypy/test_stackless.py @@ -8,15 +8,12 @@ space = gettestobjspace(usemodules=('_stackless', '_socket')) cls.space = space # cannot test the unpickle part on top of py.py - cls.w_can_unpickle = space.wrap(bool(option.runappdirect)) def test_pickle(self): import new, sys mod = new.module('mod') sys.modules['mod'] = mod - mod.can_unpickle = self.can_unpickle - mod.skip = skip try: exec ''' import pickle, sys @@ -45,8 +42,6 @@ t = stackless.tasklet(demo)(lev) stackless.run() assert seen == range(1, lev+1) + range(lev, 0, -1) -if not can_unpickle: - skip("cannot test the unpickling part on top of py.py") print "now running the clone" tt = pickle.loads(blob) tt.insert() @@ -64,8 +59,6 @@ mod = new.module('mod') sys.modules['mod'] = mod - mod.can_unpickle = self.can_unpickle - mod.skip = skip try: exec ''' import pickle, sys diff --git a/pypy/module/test_lib_pypy/test_tputil.py b/pypy/module/test_lib_pypy/test_tputil.py --- a/pypy/module/test_lib_pypy/test_tputil.py +++ b/pypy/module/test_lib_pypy/test_tputil.py @@ -28,9 +28,9 @@ from tputil import make_proxy l = [] tp = make_proxy(l.append, type=list) - x = len(tp) + x = tp[0:1] assert len(l) == 1 - assert l[0].opname == '__len__' + assert l[0].opname == '__getslice__' def test_simple(self): from tputil import make_proxy diff --git a/pypy/module/zipimport/test/test_zipimport.py b/pypy/module/zipimport/test/test_zipimport.py --- a/pypy/module/zipimport/test/test_zipimport.py +++ b/pypy/module/zipimport/test/test_zipimport.py @@ -1,7 +1,7 @@ from pypy.conftest import gettestobjspace import marshal -import py +import py, os import time import struct from pypy.module.imp.importing import get_pyc_magic, _w_long @@ -15,6 +15,7 @@ cpy's regression tests """ compression = ZIP_STORED + pathsep = '/' def make_pyc(cls, space, co, mtime): data = marshal.dumps(co) @@ -57,6 +58,7 @@ test_pyc = cls.make_pyc(space, co, now) cls.w_test_pyc = space.wrap(test_pyc) cls.w_compression = space.wrap(cls.compression) + cls.w_pathsep = space.wrap(cls.pathsep) #ziptestmodule = tmpdir.ensure('ziptestmodule.zip').write( ziptestmodule = tmpdir.join("somezip.zip") cls.w_tmpzip = space.wrap(str(ziptestmodule)) @@ -100,6 +102,7 @@ from zipfile import ZipFile, ZipInfo z = ZipFile(self.zipfile, 'w') write_files = self.write_files + filename = filename.replace('/', self.pathsep) write_files.append((filename, data)) for filename, data in write_files: zinfo = ZipInfo(filename, time.localtime(self.now)) @@ -121,6 +124,7 @@ del _zip_directory_cache[self.zipfile] def test_cache_subdir(self): + import os self.writefile('x.py', '') self.writefile('sub/__init__.py', '') self.writefile('sub/yy.py', '') @@ -130,7 +134,7 @@ assert main_importer is not sub_importer assert main_importer.prefix == "" - assert sub_importer.prefix == "sub/" + assert sub_importer.prefix == "sub" + os.path.sep def test_good_bad_arguments(self): from zipimport import zipimporter @@ -262,7 +266,7 @@ import zipimport data = "saddsadsa" self.writefile("xxx", data) - self.writefile("xx"+os.sep+"__init__.py", "5") + self.writefile("xx/__init__.py", "5") self.writefile("yy.py", "3") self.writefile('uu.pyc', self.test_pyc) z = zipimport.zipimporter(self.zipfile) @@ -287,8 +291,7 @@ """ import os import zipimport - self.writefile( - os.sep.join(("directory", "package", "__init__.py")), "") + self.writefile("directory/package/__init__.py", "") importer = zipimport.zipimporter(self.zipfile + "/directory") # Grab this so if the assertion fails, py.test will display its # value. Not sure why it doesn't the assertion uses import.archive @@ -296,15 +299,14 @@ archive = importer.archive realprefix = importer.prefix allbutlast = self.zipfile.split(os.path.sep)[:-1] - prefix = 'directory/' + prefix = 'directory' + os.path.sep assert archive == self.zipfile assert realprefix == prefix def test_subdirectory_importer(self): import os import zipimport - self.writefile( - os.sep.join(("directory", "package", "__init__.py")), "") + self.writefile("directory/package/__init__.py", "") z = zipimport.zipimporter(self.zipfile + "/directory") mod = z.load_module("package") assert z.is_package("package") @@ -313,14 +315,9 @@ def test_subdirectory_twice(self): import os, zipimport - self.writefile( - os.sep.join(("package", "__init__.py")), "") - self.writefile( - os.sep.join(("package", "subpackage", - "__init__.py")), "") - self.writefile( - os.sep.join(("package", "subpackage", - "foo.py")), "") + self.writefile("package/__init__.py", "") + self.writefile("package/subpackage/__init__.py", "") + self.writefile("package/subpackage/foo.py", "") import sys print sys.path mod = __import__('package.subpackage.foo', None, None, []) @@ -331,8 +328,7 @@ """ import os import zipimport - self.writefile( - os.sep.join(("directory", "package", "__init__.py")), "") + self.writefile("directory/package/__init__.py", "") importer = zipimport.zipimporter(self.zipfile + "/directory") l = [i for i in zipimport._zip_directory_cache] assert len(l) @@ -370,3 +366,8 @@ except ImportError: py.test.skip("zlib not available, cannot test compressed zipfiles") cls.make_class() + + +if os.sep != '/': + class AppTestNativePathSep(AppTestZipimport): + pathsep = os.sep diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -207,34 +207,51 @@ return space.get_and_call_function(w_descr, w_obj, w_name) def is_true(space, w_obj): - w_descr = space.lookup(w_obj, '__nonzero__') + method = "__nonzero__" + w_descr = space.lookup(w_obj, method) if w_descr is None: - w_descr = space.lookup(w_obj, '__len__') + method = "__len__" + w_descr = space.lookup(w_obj, method) if w_descr is None: return True w_res = space.get_and_call_function(w_descr, w_obj) # more shortcuts for common cases - if w_res is space.w_False: + if space.is_w(w_res, space.w_False): return False - if w_res is space.w_True: + if space.is_w(w_res, space.w_True): return True w_restype = space.type(w_res) - if (space.is_w(w_restype, space.w_bool) or - space.is_w(w_restype, space.w_int)): + # Note there is no check for bool here because the only possible + # instances of bool are w_False and w_True, which are checked above. + if (space.is_w(w_restype, space.w_int) or + space.is_w(w_restype, space.w_long)): return space.int_w(w_res) != 0 else: - raise OperationError(space.w_TypeError, - space.wrap('__nonzero__ should return ' - 'bool or int')) + msg = "%s should return bool or integer" % (method,) + raise OperationError(space.w_TypeError, space.wrap(msg)) - def nonzero(self, w_obj): - if self.is_true(w_obj): - return self.w_True + def nonzero(space, w_obj): + if space.is_true(w_obj): + return space.w_True else: - return self.w_False + return space.w_False -## def len(self, w_obj): -## XXX needs to check that the result is an int (or long?) >= 0 + def len(space, w_obj): + w_descr = space.lookup(w_obj, '__len__') + if w_descr is None: + name = space.type(w_obj).getname(space) + msg = "'%s' has no length" % (name,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_res = space.get_and_call_function(w_descr, w_obj) + space._check_len_result(w_res) + return w_res + + def _check_len_result(space, w_obj): + # Will complain if result is too big. + result = space.int_w(w_obj) + if result < 0: + raise OperationError(space.w_ValueError, + space.wrap("__len__() should return >= 0")) def iter(space, w_obj): w_descr = space.lookup(w_obj, '__iter__') diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -384,8 +384,9 @@ # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) - stack_items_w = self.crnt_frame.valuestack_w - for i in range(self.crnt_frame.valuestackdepth-1, -1, -1): + f = self.crnt_frame + stack_items_w = f.locals_stack_w + for i in range(f.valuestackdepth-1, f.nlocals-1, -1): w_v = stack_items_w[i] if isinstance(w_v, Constant): if w_v.value is oldvalue: diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py --- a/pypy/objspace/flow/framestate.py +++ b/pypy/objspace/flow/framestate.py @@ -10,7 +10,7 @@ def __init__(self, state): if isinstance(state, PyFrame): # getfastscope() can return real None, for undefined locals - data = state.getfastscope() + state.savevaluestack() + data = state.save_locals_stack() if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -36,11 +36,9 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): - fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) # Nones == undefined locals - frame.restorevaluestack(data[fastlocals:-2]) + frame.restore_locals_stack(data[:-2]) # Nones == undefined locals if data[-2] == Constant(None): assert data[-1] == Constant(None) frame.last_exception = None diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py --- a/pypy/objspace/flow/test/test_framestate.py +++ b/pypy/objspace/flow/test/test_framestate.py @@ -25,7 +25,7 @@ dummy = Constant(None) #dummy.dummy = True arg_list = ([Variable() for i in range(formalargcount)] + - [dummy] * (len(frame.fastlocals_w) - formalargcount)) + [dummy] * (frame.nlocals - formalargcount)) frame.setfastscope(arg_list) return frame @@ -42,7 +42,7 @@ def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1 != fs2 @@ -55,7 +55,7 @@ def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general @@ -63,7 +63,7 @@ def test_restore_frame(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs1.restoreframe(frame) assert fs1 == FrameState(frame) @@ -82,25 +82,26 @@ def test_getoutputargs(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable - # fastlocals_w[-1] -> fastlocals_w[-1] is Constant(None) - assert outputargs == [frame.fastlocals_w[0], Constant(None)] + # locals_w[n-1] -> locals_w[n-1] is Constant(None) + assert outputargs == [frame.locals_stack_w[0], Constant(None)] def test_union_different_constants(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(42) + frame.locals_stack_w[frame.nlocals-1] = Constant(42) fs2 = FrameState(frame) fs3 = fs1.union(fs2) fs3.restoreframe(frame) - assert isinstance(frame.fastlocals_w[-1], Variable) # generalized + assert isinstance(frame.locals_stack_w[frame.nlocals-1], Variable) + # ^^^ generalized def test_union_spectag(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(SpecTag()) + frame.locals_stack_w[frame.nlocals-1] = Constant(SpecTag()) fs2 = FrameState(frame) assert fs1.union(fs2) is None # UnionError diff --git a/pypy/objspace/std/callmethod.py b/pypy/objspace/std/callmethod.py --- a/pypy/objspace/std/callmethod.py +++ b/pypy/objspace/std/callmethod.py @@ -12,7 +12,7 @@ from pypy.interpreter import function from pypy.objspace.descroperation import object_getattribute -from pypy.rlib import jit, rstack # for resume points +from pypy.rlib import jit from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict, \ LOOKUP_METHOD_mapdict_fill_cache_method @@ -84,7 +84,6 @@ w_callable = f.peekvalue(n_args + (2 * n_kwargs) + 1) try: w_result = f.space.call_valuestack(w_callable, n, f) - rstack.resume_point("CALL_METHOD", f, n_args, returns=w_result) finally: f.dropvalues(n_args + 2) else: @@ -109,7 +108,6 @@ w_result = f.space.call_args_and_c_profile(f, w_callable, args) else: w_result = f.space.call_args(w_callable, args) - rstack.resume_point("CALL_METHOD_KW", f, returns=w_result) f.pushvalue(w_result) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -45,7 +45,7 @@ def getdictvalue_no_unwrapping(self, w_dict, key): return self._getdictvalue_no_unwrapping_pure(self.version, w_dict, key) - @jit.purefunction_promote('0,1,2') + @jit.elidablefunction_promote('0,1,2') def _getdictvalue_no_unwrapping_pure(self, version, w_dict, key): return self.unerase(w_dict.dstorage).get(key, None) @@ -148,9 +148,6 @@ w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new) - def _clear_fields(self): - self.content = None - class ModuleDictIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,12 +1,13 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.debug import mark_dict_non_null from pypy.rlib import rerased @@ -216,7 +217,8 @@ def clear(self, w_dict): return - + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -380,7 +382,8 @@ return True def get_empty_storage(self): - new_dict = r_dict(self.space.eq_w, self.space.hash_w) + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) return self.erase(new_dict) def iter(self, w_dict): @@ -409,9 +412,12 @@ return space.is_w(space.type(w_obj), space.w_str) def get_empty_storage(self): - return self.erase({}) + res = {} + mark_dict_non_null(res) + return self.erase(res) def setitem_str(self, w_dict, key, w_value): + assert key is not None self.unerase(w_dict.dstorage)[key] = w_value def getitem(self, w_dict, w_key): @@ -430,6 +436,7 @@ return w_dict.getitem(w_key) def getitem_str(self, w_dict, key): + assert key is not None return self.unerase(w_dict.dstorage).get(key, None) def iter(self, w_dict): diff --git a/pypy/objspace/std/floattype.py b/pypy/objspace/std/floattype.py --- a/pypy/objspace/std/floattype.py +++ b/pypy/objspace/std/floattype.py @@ -14,10 +14,8 @@ float_as_integer_ratio = SMM("as_integer_ratio", 1) float_hex = SMM("hex", 1) -float_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any float.") - -def float_conjugate__ANY(space, w_float): - return space.pos(w_float) +def descr_conjugate(space, w_float): + return space.float(w_float) register_all(vars(), globals()) @@ -168,10 +166,10 @@ if total_digits > min(const_one, const_two) // 4: raise OperationError(space.w_ValueError, space.wrap("way too long")) if i < length and (s[i] == "p" or s[i] == "P"): + i += 1 if i == length: raise OperationError(space.w_ValueError, space.wrap("invalid hex string")) - i += 1 exp_sign = 1 if s[i] == "-" or s[i] == "+": if s[i] == "-": @@ -280,6 +278,7 @@ as_classmethod=True), fromhex = gateway.interp2app(descr_fromhex, as_classmethod=True), + conjugate = gateway.interp2app(descr_conjugate), real = typedef.GetSetProperty(descr_get_real), imag = typedef.GetSetProperty(descr_get_imag), ) diff --git a/pypy/objspace/std/inttype.py b/pypy/objspace/std/inttype.py --- a/pypy/objspace/std/inttype.py +++ b/pypy/objspace/std/inttype.py @@ -11,14 +11,19 @@ # ____________________________________________________________ -int_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any int.") +def descr_conjugate(space, w_int): + "Returns self, the complex conjugate of any int." + return space.int(w_int) -def int_conjugate__ANY(space, w_int): - return space.pos(w_int) +def descr_bit_length(space, w_int): + """int.bit_length() -> int -int_bit_length = SMM("bit_length", 1, doc="int.bit_length() -> int\n\nNumber of bits necessary to represent self in binary.\n>>> bin(37)\n'0b100101'\n>>> (37).bit_length()\n6") - -def int_bit_length__ANY(space, w_int): + Number of bits necessary to represent self in binary. + >>> bin(37) + '0b100101' + >>> (37).bit_length() + 6 + """ val = space.int_w(w_int) if val < 0: val = -val @@ -28,8 +33,6 @@ val >>= 1 return space.wrap(bits) -register_all(vars(), globals()) - def wrapint(space, x): if space.config.objspace.std.withsmallint: @@ -196,6 +199,8 @@ non-string. If the argument is outside the integer range a long object will be returned instead.''', __new__ = gateway.interp2app(descr__new__), + conjugate = gateway.interp2app(descr_conjugate), + bit_length = gateway.interp2app(descr_bit_length), numerator = typedef.GetSetProperty(descr_get_numerator), denominator = typedef.GetSetProperty(descr_get_denominator), real = typedef.GetSetProperty(descr_get_real), diff --git a/pypy/objspace/std/longtype.py b/pypy/objspace/std/longtype.py --- a/pypy/objspace/std/longtype.py +++ b/pypy/objspace/std/longtype.py @@ -4,12 +4,8 @@ from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from pypy.objspace.std.strutil import string_to_bigint, ParseStringError -long_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any long.") - -def long_conjugate__ANY(space, w_int): - return space.pos(w_int) - -register_all(vars(), globals()) +def descr_conjugate(space, w_int): + return space.long(w_int) def descr__new__(space, w_longtype, w_x=0, w_base=gateway.NoneNotWrapped): @@ -128,6 +124,7 @@ string, use the optional base. It is an error to supply a base when converting a non-string.''', __new__ = gateway.interp2app(descr__new__), + conjugate = gateway.interp2app(descr_conjugate), numerator = typedef.GetSetProperty(descr_get_numerator), denominator = typedef.GetSetProperty(descr_get_denominator), real = typedef.GetSetProperty(descr_get_real), diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -668,8 +668,13 @@ new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self, w_dict): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -266,6 +266,7 @@ return None def unwrap(self, w_obj): + """NOT_RPYTHON""" if isinstance(w_obj, Wrappable): return w_obj if isinstance(w_obj, model.W_Object): @@ -310,6 +311,10 @@ classofinstance=classofinstance, strdict=strdict) + def newset(self): + from pypy.objspace.std.setobject import newset + return W_SetObject(self, newset(self)) + def newslice(self, w_start, w_end, w_step): return W_SliceObject(w_start, w_end, w_step) @@ -317,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py --- a/pypy/objspace/std/smalltupleobject.py +++ b/pypy/objspace/std/smalltupleobject.py @@ -33,7 +33,7 @@ raise NotImplementedError def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] # XXX generic mixed types unwrap + items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] return tuple(items) def make_specialized_class(n): diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -252,15 +252,30 @@ res_w = [] start = 0 - while maxsplit != 0: - next = value.find(by, start) - if next < 0: - break - res_w.append(sliced(space, value, start, next, w_self)) - start = next + bylen - maxsplit -= 1 # NB. if it's already < 0, it stays < 0 + if bylen == 1 and maxsplit < 0: + # fast path: uses str.rfind(character) and str.count(character) + by = by[0] # annotator hack: string -> char + count = value.count(by) + res_w = [None] * (count + 1) + end = len(value) + while count >= 0: + assert end >= 0 + prev = value.rfind(by, 0, end) + start = prev + 1 + assert start >= 0 + res_w[count] = sliced(space, value, start, end, w_self) + count -= 1 + end = prev + else: + while maxsplit != 0: + next = value.find(by, start) + if next < 0: + break + res_w.append(sliced(space, value, start, next, w_self)) + start = next + bylen + maxsplit -= 1 # NB. if it's already < 0, it stays < 0 + res_w.append(sliced(space, value, start, len(value), w_self)) - res_w.append(sliced(space, value, start, len(value), w_self)) return space.newlist(res_w) def str_rsplit__String_None_ANY(space, w_self, w_none, w_maxsplit=-1): diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,3 +1,4 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ @@ -5,7 +6,7 @@ StringDictStrategy, ObjectDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -232,6 +233,31 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2:2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a",1) in l + assert (2,2) in l + assert ("c",3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a",1) in l + assert ("b",2) in l + assert ("c",3) in l + def test_setdefault(self): d = {1:2, 3:4} dd = d.copy() @@ -526,6 +552,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -702,8 +734,14 @@ set([('a', 1), ('b', 2), ('d', 4), ('e', 5)])) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + def w_get_strategy(self, obj): import __pypy__ r = __pypy__.internal_repr(obj) diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py --- a/pypy/objspace/std/test/test_floatobject.py +++ b/pypy/objspace/std/test/test_floatobject.py @@ -63,6 +63,19 @@ def setup_class(cls): cls.w_py26 = cls.space.wrap(sys.version_info >= (2, 6)) + def test_conjugate(self): + assert (1.).conjugate() == 1. + assert (-1.).conjugate() == -1. + + class F(float): + pass + assert F(1.).conjugate() == 1. + + class F(float): + def __pos__(self): + return 42. + assert F(1.).conjugate() == 1. + def test_negatives(self): assert -1.1 < 0 assert -0.1 < 0 @@ -751,3 +764,6 @@ pass else: self.identical(x, float.fromhex(x.hex())) + + def test_invalid(self): + raises(ValueError, float.fromhex, "0P") diff --git a/pypy/objspace/std/test/test_intobject.py b/pypy/objspace/std/test/test_intobject.py --- a/pypy/objspace/std/test/test_intobject.py +++ b/pypy/objspace/std/test/test_intobject.py @@ -285,6 +285,19 @@ class AppTestInt: + def test_conjugate(self): + assert (1).conjugate() == 1 + assert (-1).conjugate() == -1 + + class I(int): + pass + assert I(1).conjugate() == 1 + + class I(int): + def __pos__(self): + return 42 + assert I(1).conjugate() == 1 + def test_trunc(self): import math assert math.trunc(1) == 1 diff --git a/pypy/objspace/std/test/test_longobject.py b/pypy/objspace/std/test/test_longobject.py --- a/pypy/objspace/std/test/test_longobject.py +++ b/pypy/objspace/std/test/test_longobject.py @@ -300,6 +300,11 @@ assert type(L(7).conjugate()) is long + class L(long): + def __pos__(self): + return 43 + assert L(7).conjugate() == 7L + def test_bit_length(self): assert 8L.bit_length() == 4 assert (-1<<40).bit_length() == 41 diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -468,6 +468,19 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + + def test_slot_name_conflict(self): class A(object): diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -50,6 +50,10 @@ u = self.space.wrap(set('simsalabim')) assert self.space.eq_w(s,u) + def test_space_newset(self): + s = self.space.newset() + assert self.space.str_w(self.space.repr(s)) == 'set([])' + class AppTestAppSetTest: def test_subtype(self): class subset(set):pass diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -23,7 +23,7 @@ return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist)) def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] # XXX generic mixed types unwrap + items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] return tuple(items) registerimplementation(W_TupleObject) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -450,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -777,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -823,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py --- a/pypy/objspace/test/test_descroperation.py +++ b/pypy/objspace/test/test_descroperation.py @@ -524,6 +524,31 @@ assert issubclass(B, B) assert issubclass(23, B) + def test_truth_of_long(self): + class X(object): + def __len__(self): return 1L + __nonzero__ = __len__ + assert X() + del X.__nonzero__ + assert X() + + def test_len_overflow(self): + import sys + class X(object): + def __len__(self): + return sys.maxsize + 1 + raises(OverflowError, len, X()) + + def test_len_underflow(self): + import sys + class X(object): + def __len__(self): + return -1 + raises(ValueError, len, X()) + class Y(object): + def __len__(self): + return -1L + raises(ValueError, len, Y()) class AppTestWithBuiltinShortcut(AppTest_Descroperation): OPTIONS = {'objspace.std.builtinshortcut': True} diff --git a/pypy/objspace/trace.py b/pypy/objspace/trace.py --- a/pypy/objspace/trace.py +++ b/pypy/objspace/trace.py @@ -110,10 +110,10 @@ self.result.append(EnterFrame(frame)) self.ec.enter(frame) - def leave(self, frame, w_exitvalue): + def leave(self, frame, w_exitvalue, got_exception): """ called just after evaluating of a frame is suspended/finished. """ self.result.append(LeaveFrame(frame)) - self.ec.leave(frame, w_exitvalue) + self.ec.leave(frame, w_exitvalue, got_exception) def bytecode_trace(self, frame): """ called just before execution of a bytecode. """ diff --git a/pypy/pytest.ini b/pypy/pytest.ini new file mode 100644 --- /dev/null +++ b/pypy/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --assertmode=old \ No newline at end of file diff --git a/pypy/rlib/_jit_vref.py b/pypy/rlib/_jit_vref.py --- a/pypy/rlib/_jit_vref.py +++ b/pypy/rlib/_jit_vref.py @@ -50,6 +50,7 @@ def rtype_simple_call(self, hop): [v] = hop.inputargs(self) + hop.exception_is_here() v = hop.genop('jit_force_virtual', [v], resulttype = OBJECTPTR) return hop.genop('cast_pointer', [v], resulttype = hop.r_result) @@ -65,6 +66,7 @@ lowleveltype = OBJECT def rtype_simple_call(self, hop): [v] = hop.inputargs(self) + hop.exception_is_here() v = hop.genop('jit_force_virtual', [v], resulttype = OBJECT) return hop.genop('oodowncast', [v], resulttype = hop.r_result) diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py --- a/pypy/rlib/clibffi.py +++ b/pypy/rlib/clibffi.py @@ -10,6 +10,7 @@ from pypy.rlib.rmmap import alloc from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal from pypy.rlib.rdynload import DLOpenError, DLLHANDLE +from pypy.rlib import jit from pypy.tool.autopath import pypydir from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform @@ -18,6 +19,10 @@ import sys import ctypes.util +from pypy.tool.ansi_print import ansi_log +log = py.log.Producer("libffi") +py.log.setconsumer("libffi", ansi_log) + # maaaybe isinstance here would be better. Think _MSVC = platform.name == "msvc" _MINGW = platform.name == "mingw32" @@ -67,12 +72,17 @@ result = os.path.join(dir, 'libffi.a') if os.path.exists(result): return result - raise ImportError("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("trying to use the dynamic library instead...") + return None + path_libffi_a = None if hasattr(platform, 'library_dirs_for_libffi_a'): + path_libffi_a = find_libffi_a() + if path_libffi_a is not None: # platforms on which we want static linking libraries = [] - link_files = [find_libffi_a()] + link_files = [path_libffi_a] else: # platforms on which we want dynamic linking libraries = ['ffi'] @@ -261,6 +271,7 @@ elif _MSVC: get_libc_handle = external('pypy_get_libc_handle', [], DLLHANDLE) + @jit.dont_look_inside def get_libc_name(): return rwin32.GetModuleFileName(get_libc_handle()) diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec @@ -183,7 +198,6 @@ # VRefs def virtual_ref(x): - """Creates a 'vref' object that contains a reference to 'x'. Calls to virtual_ref/virtual_ref_finish must be properly nested. The idea is that the object 'x' is supposed to be JITted as a virtual between @@ -194,10 +208,10 @@ return DirectJitVRef(x) virtual_ref.oopspec = 'virtual_ref(x)' -def virtual_ref_finish(x): - """See docstring in virtual_ref(x). Note that virtual_ref_finish - takes as argument the real object, not the vref.""" +def virtual_ref_finish(vref, x): + """See docstring in virtual_ref(x)""" keepalive_until_here(x) # otherwise the whole function call is removed + _virtual_ref_finish(vref, x) virtual_ref_finish.oopspec = 'virtual_ref_finish(x)' def non_virtual_ref(x): @@ -205,19 +219,39 @@ Used for None or for frames outside JIT scope.""" return DirectVRef(x) +class InvalidVirtualRef(Exception): + """ + Raised if we try to call a non-forced virtualref after the call to + virtual_ref_finish + """ + # ---------- implementation-specific ---------- class DirectVRef(object): def __init__(self, x): self._x = x + self._state = 'non-forced' + def __call__(self): + if self._state == 'non-forced': + self._state = 'forced' + elif self._state == 'invalid': + raise InvalidVirtualRef return self._x + def _finish(self): + if self._state == 'non-forced': + self._state = 'invalid' + class DirectJitVRef(DirectVRef): def __init__(self, x): assert x is not None, "virtual_ref(None) is not allowed" DirectVRef.__init__(self, x) +def _virtual_ref_finish(vref, x): + assert vref._x is x, "Invalid call to virtual_ref_finish" + vref._finish() + class Entry(ExtRegistryEntry): _about_ = (non_virtual_ref, DirectJitVRef) @@ -237,6 +271,15 @@ s_obj = self.bookkeeper.immutablevalue(self.instance()) return _jit_vref.SomeVRef(s_obj) +class Entry(ExtRegistryEntry): + _about_ = _virtual_ref_finish + + def compute_result_annotation(self, s_vref, s_obj): + pass + + def specialize_call(self, hop): + pass + vref_None = non_virtual_ref(None) # ____________________________________________________________ @@ -245,7 +288,8 @@ class JitHintError(Exception): """Inconsistency in the JIT hints.""" -PARAMETERS = {'threshold': 1000, +PARAMETERS = {'threshold': 1032, # just above 1024 + 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, 'inlining': 0, @@ -342,6 +386,24 @@ raise set_user_param._annspecialcase_ = 'specialize:arg(0)' + + def on_compile(self, logger, looptoken, operations, type, *greenargs): + """ A hook called when loop is compiled. Overwrite + for your own jitdriver if you want to do something special, like + call applevel code + """ + + def on_compile_bridge(self, logger, orig_looptoken, operations, n): + """ A hook called when a bridge is compiled. Overwrite + for your own jitdriver if you want to do something special + """ + + # note: if you overwrite this functions with the above signature it'll + # work, but the *greenargs is different for each jitdriver, so we + # can't share the same methods + del on_compile + del on_compile_bridge + def _make_extregistryentries(self): # workaround: we cannot declare ExtRegistryEntries for functions # used as methods of a frozen object, but we can attach the diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -1,12 +1,15 @@ +from __future__ import with_statement + from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.objectmodel import specialize, enforceargs, we_are_translated -from pypy.rlib.rarithmetic import intmask, r_uint +from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat from pypy.rlib import jit from pypy.rlib import clibffi from pypy.rlib.clibffi import get_libc_name, FUNCFLAG_CDECL, AbstractFuncPtr, \ - push_arg_as_ffiptr, c_ffi_call + push_arg_as_ffiptr, c_ffi_call, FFI_TYPE_STRUCT from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal from pypy.rlib.rdynload import DLLHANDLE +from pypy.rlib.longlong2float import longlong2float, float2longlong class types(object): """ @@ -31,17 +34,21 @@ setattr(cls, name, value) cls.slong = clibffi.cast_type_to_ffitype(rffi.LONG) cls.ulong = clibffi.cast_type_to_ffitype(rffi.ULONG) + cls.slonglong = clibffi.cast_type_to_ffitype(rffi.LONGLONG) + cls.ulonglong = clibffi.cast_type_to_ffitype(rffi.ULONGLONG) + cls.wchar_t = clibffi.cast_type_to_ffitype(lltype.UniChar) del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. """ if ffi_type is types.void: return 'v' elif ffi_type is types.double: return 'f' - elif ffi_type is types.pointer: return 'i' + elif ffi_type is types.float: return 's' + elif ffi_type is types.pointer: return 'u' # elif ffi_type is types.schar: return 'i' elif ffi_type is types.uchar: return 'u' @@ -58,13 +65,19 @@ elif ffi_type is types.uint16: return 'u' elif ffi_type is types.sint32: return 'i' elif ffi_type is types.uint32: return 'u' - ## we only support integers that fit in a lltype.Signed (==rffi.LONG) - ## (on 64-bit platforms, types.sint64 is types.slong and the case is - ## caught above) - ## elif ffi_type is types.sint64: return 'i' - ## elif ffi_type is types.uint64: return 'u' + ## (note that on 64-bit platforms, types.sint64 is types.slong and the + ## case is caught above) + elif ffi_type is types.sint64: return 'I' + elif ffi_type is types.uint64: return 'U' + # + elif types.is_struct(ffi_type): return 'S' raise KeyError + @staticmethod + @jit.elidable + def is_struct(ffi_type): + return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) + types._import() @specialize.arg(0) @@ -78,8 +91,11 @@ sz = rffi.sizeof(TYPE) return sz <= rffi.sizeof(rffi.LONG) + # ====================================================================== +IS_32_BIT = (r_uint.BITS == 32) + @specialize.memo() def _check_type(TYPE): if isinstance(TYPE, lltype.Ptr): @@ -105,11 +121,37 @@ val = rffi.cast(rffi.LONG, val) elif TYPE is rffi.DOUBLE: cls = FloatArg + elif TYPE is rffi.LONGLONG or TYPE is rffi.ULONGLONG: + raise TypeError, 'r_(u)longlong not supported by arg(), use arg_(u)longlong()' + elif TYPE is rffi.FLOAT: + raise TypeError, 'r_singlefloat not supported by arg(), use arg_singlefloat()' else: raise TypeError, 'Unsupported argument type: %s' % TYPE self._append(cls(val)) return self + def arg_raw(self, val): + self._append(RawArg(val)) + + def arg_longlong(self, val): + """ + Note: this is a hack. So far, the JIT does not support long longs, so + you must pass it as if it were a python Float (rffi.DOUBLE). You can + use the convenience functions longlong2float and float2longlong to do + the conversions. Note that if you use long longs, the call won't + be jitted at all. + """ + assert IS_32_BIT # use a normal integer on 64-bit platforms + self._append(LongLongArg(val)) + + def arg_singlefloat(self, val): + """ + Note: you must pass a python Float (rffi.DOUBLE), not a r_singlefloat + (else the jit complains). Note that if you use single floats, the + call won't be jitted at all. + """ + self._append(SingleFloatArg(val)) + def _append(self, arg): if self.first is None: self.first = self.last = arg @@ -132,8 +174,9 @@ def push(self, func, ll_args, i): func._push_int(self.intval, ll_args, i) + class FloatArg(AbstractArg): - """ An argument holding a float + """ An argument holding a python float (i.e. a C double) """ def __init__(self, floatval): @@ -142,6 +185,37 @@ def push(self, func, ll_args, i): func._push_float(self.floatval, ll_args, i) +class RawArg(AbstractArg): + """ An argument holding a raw pointer to put inside ll_args + """ + + def __init__(self, ptrval): + self.ptrval = ptrval + + def push(self, func, ll_args, i): + func._push_raw(self.ptrval, ll_args, i) + +class SingleFloatArg(AbstractArg): + """ An argument representing a C float (but holding a C double) + """ + + def __init__(self, floatval): + self.floatval = floatval + + def push(self, func, ll_args, i): + func._push_single_float(self.floatval, ll_args, i) + + +class LongLongArg(AbstractArg): + """ An argument representing a C long long (but holding a C double) + """ + + def __init__(self, floatval): + self.floatval = floatval + + def push(self, func, ll_args, i): + func._push_longlong(self.floatval, ll_args, i) + # ====================================================================== @@ -164,8 +238,8 @@ # ======================================================================== @jit.unroll_safe - @specialize.arg(2) - def call(self, argchain, RESULT): + @specialize.arg(2, 3) + def call(self, argchain, RESULT, is_struct=False): # WARNING! This code is written carefully in a way that the JIT # optimizer will see a sequence of calls like the following: # @@ -179,6 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) @@ -190,10 +265,24 @@ i += 1 arg = arg.next # - if _fits_into_long(RESULT): + if is_struct: + assert types.is_struct(self.restype) + res = self._do_call_raw(self.funcsym, ll_args) + elif _fits_into_long(RESULT): + assert not types.is_struct(self.restype) res = self._do_call_int(self.funcsym, ll_args) elif RESULT is rffi.DOUBLE: return self._do_call_float(self.funcsym, ll_args) + elif RESULT is rffi.FLOAT: + # XXX: even if RESULT is FLOAT, we still return a DOUBLE, else the + # jit complains. Note that the jit is disabled in this case + return self._do_call_single_float(self.funcsym, ll_args) + elif RESULT is rffi.LONGLONG or RESULT is rffi.ULONGLONG: + # XXX: even if RESULT is LONGLONG, we still return a DOUBLE, else the + # jit complains. Note that the jit is disabled in this case + # (it's not a typo, we really return a DOUBLE) + assert IS_32_BIT + return self._do_call_longlong(self.funcsym, ll_args) elif RESULT is lltype.Void: return self._do_call_void(self.funcsym, ll_args) else: @@ -222,11 +311,26 @@ def _push_int(self, value, ll_args, i): self._push_arg(value, ll_args, i) + @jit.dont_look_inside + def _push_raw(self, value, ll_args, i): + ll_args[i] = value + @jit.oopspec('libffi_push_float(self, value, ll_args, i)') @enforceargs( None, float, None, int) # fix the annotation for tests def _push_float(self, value, ll_args, i): self._push_arg(value, ll_args, i) + @jit.dont_look_inside + def _push_single_float(self, value, ll_args, i): + self._push_arg(r_singlefloat(value), ll_args, i) + + @jit.dont_look_inside + def _push_longlong(self, floatval, ll_args, i): + """ + Takes a longlong represented as a python Float. It's a hack for the + jit, else we could not see the whole libffi module at all""" + self._push_arg(float2longlong(floatval), ll_args, i) + @jit.oopspec('libffi_call_int(self, funcsym, ll_args)') def _do_call_int(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, rffi.LONG) @@ -235,6 +339,21 @@ def _do_call_float(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, rffi.DOUBLE) + @jit.dont_look_inside + def _do_call_single_float(self, funcsym, ll_args): + single_res = self._do_call(funcsym, ll_args, rffi.FLOAT) + return float(single_res) + + @jit.dont_look_inside + def _do_call_raw(self, funcsym, ll_args): + # same as _do_call_int, but marked as jit.dont_look_inside + return self._do_call(funcsym, ll_args, rffi.LONG) + + @jit.dont_look_inside + def _do_call_longlong(self, funcsym, ll_args): + llres = self._do_call(funcsym, ll_args, rffi.LONGLONG) + return longlong2float(llres) + @jit.oopspec('libffi_call_void(self, funcsym, ll_args)') def _do_call_void(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, lltype.Void) @@ -265,7 +384,14 @@ rffi.cast(rffi.VOIDPP, ll_args)) if RESULT is not lltype.Void: TP = lltype.Ptr(rffi.CArray(RESULT)) - res = rffi.cast(TP, ll_result)[0] + buf = rffi.cast(TP, ll_result) + if types.is_struct(self.restype): + assert RESULT == rffi.LONG + # for structs, we directly return the buffer and transfer the + # ownership + res = rffi.cast(RESULT, buf) + else: + res = buf[0] else: res = None self._free_buffers(ll_result, ll_args) @@ -274,11 +400,19 @@ def _free_buffers(self, ll_result, ll_args): if ll_result: - lltype.free(ll_result, flavor='raw') + self._free_buffer_maybe(rffi.cast(rffi.VOIDP, ll_result), self.restype) for i in range(len(self.argtypes)): - lltype.free(ll_args[i], flavor='raw') + argtype = self.argtypes[i] + self._free_buffer_maybe(ll_args[i], argtype) lltype.free(ll_args, flavor='raw') + def _free_buffer_maybe(self, buf, ffitype): + # if it's a struct, the buffer is not freed and the ownership is + # already of the caller (in case of ll_args buffers) or transferred to + # it (in case of ll_result buffer) + if not types.is_struct(ffitype): + lltype.free(buf, flavor='raw') + # ====================================================================== @@ -288,11 +422,8 @@ def __init__(self, libname): """Load the library, or raises DLOpenError.""" self.lib = rffi.cast(DLLHANDLE, 0) - ll_libname = rffi.str2charp(libname) - try: + with rffi.scoped_str2charp(libname) as ll_libname: self.lib = dlopen(ll_libname) - finally: - lltype.free(ll_libname, flavor='raw') def __del__(self): if self.lib: @@ -302,3 +433,6 @@ def getpointer(self, name, argtypes, restype, flags=FUNCFLAG_CDECL): return Func(name, argtypes, restype, dlsym(self.lib, name), flags=flags, keepalive=self) + + def getaddressindll(self, name): + return dlsym(self.lib, name) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -30,23 +30,28 @@ return llval from pypy.translator.tool.cbuild import ExternalCompilationInfo -eci = ExternalCompilationInfo(post_include_bits=[""" +eci = ExternalCompilationInfo(includes=['string.h', 'assert.h'], + post_include_bits=[""" static double pypy__longlong2float(long long x) { - char *p = (char*)&x; - return *((double*)p); + double dd; + assert(sizeof(double) == 8 && sizeof(long long) == 8); + memcpy(&dd, &x, 8); + return dd; } static long long pypy__float2longlong(double x) { - char *p = (char*)&x; - return *((long long*)p); + long long ll; + assert(sizeof(double) == 8 && sizeof(long long) == 8); + memcpy(&ll, &x, 8); + return ll; } """]) longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. @@ -1345,6 +1345,7 @@ # XXX make sure that we don't ignore this! # YYY no, we decided to do ignore this! + at jit.dont_look_inside def _AsDouble(n): """ Get a C double from a bigint object. """ # This is a "correctly-rounded" version from Python 2.7. diff --git a/pypy/rlib/rcoroutine.py b/pypy/rlib/rcoroutine.py --- a/pypy/rlib/rcoroutine.py +++ b/pypy/rlib/rcoroutine.py @@ -29,7 +29,7 @@ The type of a switch is determined by the target's costate. """ -from pypy.rlib.rstack import yield_current_frame_to_caller, resume_point +from pypy.rlib.rstack import yield_current_frame_to_caller from pypy.rlib.objectmodel import we_are_translated from pypy.interpreter.error import OperationError @@ -228,7 +228,6 @@ self.thunk = None syncstate.switched(incoming_frame) thunk.call() - resume_point("coroutine__bind", state) except Exception, e: exc = e raise @@ -257,7 +256,6 @@ raise CoroutineDamage state = self.costate incoming_frame = state.update(self).switch() - resume_point("coroutine_switch", state, returns=incoming_frame) syncstate.switched(incoming_frame) def kill(self): diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -191,6 +191,21 @@ hop.exception_cannot_occur() return hop.genop('gc_can_move', hop.args_v, resulttype=hop.r_result) +def _make_sure_does_not_move(p): + """'p' is a non-null GC object. This (tries to) make sure that the + object does not move any more, by forcing collections if needed. + Warning: should ideally only be used with the minimark GC, and only + on objects that are already a bit old, so have a chance to be + already non-movable.""" + if not we_are_translated(): + return + i = 0 + while can_move(p): + if i > 6: + raise NotImplementedError("can't make object non-movable!") + collect(i) + i += 1 + def _heap_stats(): raise NotImplementedError # can't be run directly @@ -257,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -134,7 +134,8 @@ def external(name, argtypes, restype, **kw): kw['compilation_info'] = eci - eci.export_symbols += (name,) + if not kw.get('macro', False): + eci.export_symbols += (name,) return rffi.llexternal( name, argtypes, restype, **kw) @@ -150,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rrandom.py b/pypy/rlib/rrandom.py --- a/pypy/rlib/rrandom.py +++ b/pypy/rlib/rrandom.py @@ -24,8 +24,7 @@ def __init__(self, seed=r_uint(0)): self.state = [r_uint(0)] * N self.index = 0 - if seed: - self.init_genrand(seed) + self.init_genrand(seed) def init_genrand(self, s): mt = self.state diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rlib/rsre/rsre_core.py b/pypy/rlib/rsre/rsre_core.py --- a/pypy/rlib/rsre/rsre_core.py +++ b/pypy/rlib/rsre/rsre_core.py @@ -759,17 +759,27 @@ @specializectx def find_repetition_end(ctx, ppos, ptr, maxcount): end = ctx.end - if maxcount <= 1: - if maxcount == 1 and ptr < end: - # Relatively common case: maxcount == 1. If we are not at the - # end of the string, it's done by a single direct check. - op = ctx.pat(ppos) - for op1, checkerfn in unroll_char_checker: - if op1 == op: - if checkerfn(ctx, ptr, ppos): - return ptr + 1 + ptrp1 = ptr + 1 + # First get rid of the cases where we don't have room for any match. + if maxcount <= 0 or ptrp1 > end: return ptr - elif maxcount != 65535: + # Check the first character directly. If it doesn't match, we are done. + # The idea is to be fast for cases like re.search("b+"), where we expect + # the common case to be a non-match. It's much faster with the JIT to + # have the non-match inlined here rather than detect it in the fre() call. + op = ctx.pat(ppos) + for op1, checkerfn in unroll_char_checker: + if op1 == op: + if checkerfn(ctx, ptr, ppos): + break + else: + return ptr + # It matches at least once. If maxcount == 1 (relatively common), + # then we are done. + if maxcount == 1: + return ptrp1 + # Else we really need to count how many times it matches. + if maxcount != 65535: # adjust end end1 = ptr + maxcount if end1 <= end: @@ -777,7 +787,7 @@ op = ctx.pat(ppos) for op1, fre in unroll_fre_checker: if op1 == op: - return fre(ctx, ptr, end, ppos) + return fre(ctx, ptrp1, end, ppos) raise Error("rsre.find_repetition_end[%d]" % op) @specializectx diff --git a/pypy/rlib/rsre/test/test_zjit.py b/pypy/rlib/rsre/test/test_zjit.py --- a/pypy/rlib/rsre/test/test_zjit.py +++ b/pypy/rlib/rsre/test/test_zjit.py @@ -160,3 +160,9 @@ res = self.meta_interp_match(r"<[\S ]+>", "<..a .. aa>") assert res == 13 self.check_enter_count(1) + + + def test_find_repetition_end_fastpath(self): + res = self.meta_interp_search(r"b+", "a"*30 + "b") + assert res == 30 + self.check_loops(call=0) diff --git a/pypy/rlib/rstack.py b/pypy/rlib/rstack.py --- a/pypy/rlib/rstack.py +++ b/pypy/rlib/rstack.py @@ -42,16 +42,26 @@ sandboxsafe=True, _nowrapper=True, _callable=_callable) -_stack_get_start = llexternal('LL_stack_get_start', [], lltype.Signed, - lambda: 0) +_stack_get_end = llexternal('LL_stack_get_end', [], lltype.Signed, + lambda: 0) _stack_get_length = llexternal('LL_stack_get_length', [], lltype.Signed, lambda: 1) +_stack_set_length_fraction = llexternal('LL_stack_set_length_fraction', + [lltype.Float], lltype.Void, + lambda frac: None) _stack_too_big_slowpath = llexternal('LL_stack_too_big_slowpath', [lltype.Signed], lltype.Char, lambda cur: '\x00') # the following is used by the JIT -_stack_get_start_adr = llexternal('LL_stack_get_start_adr', [], lltype.Signed) +_stack_get_end_adr = llexternal('LL_stack_get_end_adr', [], lltype.Signed) +_stack_get_length_adr= llexternal('LL_stack_get_length_adr',[], lltype.Signed) +# the following is also used by the JIT: "critical code" paths are paths in +# which we should not raise StackOverflow at all, but just ignore the stack limit +_stack_criticalcode_start = llexternal('LL_stack_criticalcode_start', [], + lltype.Void, lambda: None) +_stack_criticalcode_stop = llexternal('LL_stack_criticalcode_stop', [], + lltype.Void, lambda: None) def stack_check(): if not we_are_translated(): @@ -62,13 +72,13 @@ current = llop.stack_current(lltype.Signed) # # Load these variables from C code - start = _stack_get_start() + end = _stack_get_end() length = _stack_get_length() # - # Common case: if 'current' is within [start:start+length], everything + # Common case: if 'current' is within [end-length:end], everything # is fine - ofs = r_uint(current - start) - if ofs < r_uint(length): + ofs = r_uint(end - current) + if ofs <= r_uint(length): return # # Else call the slow path @@ -140,111 +150,6 @@ return var -def resume_point(label, *args, **kwds): - pass - - - -class ResumePointFnEntry(ExtRegistryEntry): - _about_ = resume_point - - def compute_result_annotation(self, s_label, *args_s, **kwds_s): - from pypy.annotation import model as annmodel - return annmodel.s_None - - def specialize_call(self, hop, **kwds_i): - from pypy.rpython.lltypesystem import lltype - from pypy.objspace.flow import model - - assert hop.args_s[0].is_constant() - c_label = hop.inputconst(lltype.Void, hop.args_s[0].const) - args_v = hop.args_v[1:] - if 'i_returns' in kwds_i: - assert len(kwds_i) == 1 - returns_index = kwds_i['i_returns'] - v_return = args_v.pop(returns_index-1) - assert isinstance(v_return, model.Variable), \ - "resume_point returns= argument must be a Variable" - else: - assert not kwds_i - v_return = hop.inputconst(lltype.Void, None) - - for v in args_v: - assert isinstance(v, model.Variable), "resume_point arguments must be Variables" - - hop.exception_is_here() - return hop.genop('resume_point', [c_label, v_return] + args_v, - hop.r_result) - -def resume_state_create(prevstate, label, *args): - raise RuntimeError("cannot resume states in non-translated versions") - -def concretify_argument(hop, index): - from pypy.objspace.flow import model - - v_arg = hop.args_v[index] - if isinstance(v_arg, model.Variable): - return v_arg - - r_arg = hop.rtyper.bindingrepr(v_arg) - return hop.inputarg(r_arg, arg=index) - -class ResumeStateCreateFnEntry(FrameStackTopReturningFnEntry): - _about_ = resume_state_create - - def compute_result_annotation(self, s_prevstate, s_label, *args_s): - return FrameStackTopReturningFnEntry.compute_result_annotation(self) - - def specialize_call(self, hop): - from pypy.rpython.lltypesystem import lltype - - assert hop.args_s[1].is_constant() - c_label = hop.inputconst(lltype.Void, hop.args_s[1].const) - - v_state = hop.inputarg(hop.r_result, arg=0) - - args_v = [] - for i in range(2, len(hop.args_v)): - args_v.append(concretify_argument(hop, i)) - - hop.exception_is_here() - return hop.genop('resume_state_create', [v_state, c_label] + args_v, - hop.r_result) - -def resume_state_invoke(type, state, **kwds): - raise NotImplementedError("only works in translated versions") - -class ResumeStateInvokeFnEntry(ExtRegistryEntry): - _about_ = resume_state_invoke - - def compute_result_annotation(self, s_type, s_state, **kwds): - from pypy.annotation.bookkeeper import getbookkeeper - assert s_type.is_constant() - return getbookkeeper().valueoftype(s_type.const) - - def specialize_call(self, hop, **kwds_i): - from pypy.rpython.lltypesystem import lltype - v_state = hop.args_v[1] - - if 'i_returning' in kwds_i: - assert len(kwds_i) == 1 - returning_index = kwds_i['i_returning'] - v_returning = concretify_argument(hop, returning_index) - v_raising = hop.inputconst(lltype.Void, None) - elif 'i_raising' in kwds_i: - assert len(kwds_i) == 1 - raising_index = kwds_i['i_raising'] - v_returning = hop.inputconst(lltype.Void, None) - v_raising = concretify_argument(hop, raising_index) - else: - assert not kwds_i - v_returning = hop.inputconst(lltype.Void, None) - v_raising = hop.inputconst(lltype.Void, None) - - hop.exception_is_here() - return hop.genop('resume_state_invoke', [v_state, v_returning, v_raising], - hop.r_result) - # ____________________________________________________________ def get_stack_depth_limit(): diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -141,7 +141,8 @@ def construct_stream_tower(stream, buffering, universal, reading, writing, binary): if buffering == 0: # no buffering - pass + if reading: # force some minimal buffering for readline() + stream = ReadlineInputStream(stream) elif buffering == 1: # line-buffering if writing: stream = LineBufferingOutputStream(stream) @@ -749,6 +750,113 @@ flush_buffers=False) +class ReadlineInputStream(Stream): + + """Minimal buffering input stream. + + Only does buffering for readline(). The other kinds of reads, and + all writes, are not buffered at all. + """ + + bufsize = 2**13 # 8 K + + def __init__(self, base, bufsize=-1): + self.base = base + self.do_read = base.read # function to fill buffer some more + self.do_seek = base.seek # seek to a byte offset + if bufsize == -1: # Get default from the class + bufsize = self.bufsize + self.bufsize = bufsize # buffer size (hint only) + self.buf = None # raw data (may contain "\n") + self.bufstart = 0 + + def flush_buffers(self): + if self.buf is not None: + try: + self.do_seek(self.bufstart-len(self.buf), 1) + except MyNotImplementedError: + pass + else: + self.buf = None + self.bufstart = 0 + + def readline(self): + if self.buf is not None: + i = self.buf.find('\n', self.bufstart) + else: + self.buf = '' + i = -1 + # + if i < 0: + self.buf = self.buf[self.bufstart:] + self.bufstart = 0 + while True: + bufsize = max(self.bufsize, len(self.buf) >> 2) + data = self.do_read(bufsize) + if not data: + result = self.buf # end-of-file reached + self.buf = None + return result + startsearch = len(self.buf) # there is no '\n' in buf so far + self.buf += data + i = self.buf.find('\n', startsearch) + if i >= 0: + break + # + i += 1 + result = self.buf[self.bufstart:i] + self.bufstart = i + return result + + def peek(self): + if self.buf is None: + return '' + if self.bufstart > 0: + self.buf = self.buf[self.bufstart:] + self.bufstart = 0 + return self.buf + + def tell(self): + pos = self.base.tell() + if self.buf is not None: + pos -= (len(self.buf) - self.bufstart) + return pos + + def readall(self): + result = self.base.readall() + if self.buf is not None: + result = self.buf[self.bufstart:] + result + self.buf = None + self.bufstart = 0 + return result + + def read(self, n): + if self.buf is None: + return self.do_read(n) + else: + m = n - (len(self.buf) - self.bufstart) + start = self.bufstart + if m > 0: + result = self.buf[start:] + self.do_read(m) + self.buf = None + self.bufstart = 0 + return result + elif n >= 0: + self.bufstart = start + n + return self.buf[start : self.bufstart] + else: + return '' + + seek = PassThrough("seek", flush_buffers=True) + write = PassThrough("write", flush_buffers=True) + truncate = PassThrough("truncate", flush_buffers=True) + flush = PassThrough("flush", flush_buffers=True) + flushable = PassThrough("flushable", flush_buffers=False) + close = PassThrough("close", flush_buffers=False) + try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", + flush_buffers=False) + + class BufferingOutputStream(Stream): """Standard buffering output stream. diff --git a/pypy/rlib/test/test__jit_vref.py b/pypy/rlib/test/test__jit_vref.py --- a/pypy/rlib/test/test__jit_vref.py +++ b/pypy/rlib/test/test__jit_vref.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import virtual_ref, virtual_ref_finish -from pypy.rlib.jit import vref_None, non_virtual_ref +from pypy.rlib.jit import vref_None, non_virtual_ref, InvalidVirtualRef from pypy.rlib._jit_vref import SomeVRef from pypy.annotation import model as annmodel from pypy.annotation.annrpython import RPythonAnnotator @@ -23,18 +23,23 @@ pass -def test_direct_1(): +def test_direct_forced(): x1 = X() vref = virtual_ref(x1) + assert vref._state == 'non-forced' assert vref() is x1 - virtual_ref_finish(x1) + assert vref._state == 'forced' + virtual_ref_finish(vref, x1) + assert vref._state == 'forced' assert vref() is x1 -def test_direct_2(): +def test_direct_invalid(): x1 = X() vref = virtual_ref(x1) - virtual_ref_finish(x1) - assert vref() is x1 + assert vref._state == 'non-forced' + virtual_ref_finish(vref, x1) + assert vref._state == 'invalid' + py.test.raises(InvalidVirtualRef, "vref()") def test_annotate_1(): def f(): @@ -50,7 +55,7 @@ x1 = X() vref = virtual_ref(x1) x2 = vref() - virtual_ref_finish(x1) + virtual_ref_finish(vref, x1) return x2 a = RPythonAnnotator() s = a.build_types(f, []) @@ -95,7 +100,7 @@ x1 = X() vref = virtual_ref(x1) x2 = vref() - virtual_ref_finish(x2) + virtual_ref_finish(vref, x2) return x2 x = self.interpret(f, []) assert self.castable(self.OBJECTTYPE, x) @@ -119,6 +124,18 @@ assert lltype.typeOf(x) == self.OBJECTTYPE assert not x + def test_rtype_5(self): + def f(): + vref = virtual_ref(X()) + try: + vref() + return 42 + except InvalidVirtualRef: + return -1 + x = self.interpret(f, []) + assert x == 42 + + class TestLLtype(BaseTestVRef, LLRtypeMixin): OBJECTTYPE = OBJECTPTR def castable(self, TO, var): diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): @@ -52,9 +52,12 @@ import sys s = StringIO() + prev = sys.stdout sys.stdout = s - dis.dis(g) - sys.stdout = sys.__stdout__ + try: + dis.dis(g) + finally: + sys.stdout = prev x = s.getvalue().find('CALL_FUNCTION') assert x != -1 x = s.getvalue().find('CALL_FUNCTION', x) diff --git a/pypy/rlib/test/test_libffi.py b/pypy/rlib/test/test_libffi.py --- a/pypy/rlib/test/test_libffi.py +++ b/pypy/rlib/test/test_libffi.py @@ -2,8 +2,10 @@ import sys from pypy.rpython.lltypesystem import rffi, lltype from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED -from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name +from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong +from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name, make_struct_ffitype_e from pypy.rlib.libffi import CDLL, Func, get_libc_name, ArgChain, types +from pypy.rlib.libffi import longlong2float, float2longlong, IS_32_BIT class TestLibffiMisc(BaseFfiTest): @@ -50,6 +52,18 @@ del lib assert not ALLOCATED + def test_longlong_as_float(self): + from pypy.translator.c.test.test_genc import compile + maxint64 = r_longlong(9223372036854775807) + def fn(x): + d = longlong2float(x) + ll = float2longlong(d) + return ll + assert fn(maxint64) == maxint64 + # + fn2 = compile(fn, [r_longlong]) + res = fn2(maxint64) + assert res == maxint64 class TestLibffiCall(BaseFfiTest): """ @@ -97,7 +111,7 @@ def get_libfoo(self): return self.CDLL(self.libfoo_name) - def call(self, funcspec, args, RESULT, init_result=0): + def call(self, funcspec, args, RESULT, init_result=0, is_struct=False): """ Call the specified function after constructing and ArgChain with the arguments in ``args``. @@ -114,8 +128,20 @@ func = lib.getpointer(name, argtypes, restype) chain = ArgChain() for arg in args: - chain.arg(arg) - return func.call(chain, RESULT) + if isinstance(arg, r_singlefloat): + chain.arg_singlefloat(float(arg)) + elif IS_32_BIT and isinstance(arg, r_longlong): + chain.arg_longlong(longlong2float(arg)) + elif IS_32_BIT and isinstance(arg, r_ulonglong): + arg = rffi.cast(rffi.LONGLONG, arg) + chain.arg_longlong(longlong2float(arg)) + elif isinstance(arg, tuple): + methname, arg = arg + meth = getattr(chain, methname) + meth(arg) + else: + chain.arg(arg) + return func.call(chain, RESULT, is_struct=is_struct) def check_loops(self, *args, **kwds): """ @@ -137,7 +163,7 @@ res = self.call(func, [38, 4.2], rffi.LONG) assert res == 42 self.check_loops({ - 'call_may_force': 1, + 'call_release_gil': 1, 'guard_no_exception': 1, 'guard_not_forced': 1, 'int_add': 1, @@ -150,7 +176,7 @@ func = (libm, 'pow', [types.double, types.double], types.double) res = self.call(func, [2.0, 3.0], rffi.DOUBLE, init_result=0.0) assert res == 8.0 - self.check_loops(call_may_force=1, guard_no_exception=1, guard_not_forced=1) + self.check_loops(call_release_gil=1, guard_no_exception=1, guard_not_forced=1) def test_cast_result(self): """ @@ -163,7 +189,7 @@ func = (libfoo, 'cast_to_uchar_and_ovf', [types.sint], types.uchar) res = self.call(func, [0], rffi.UCHAR) assert res == 200 - self.check_loops(call_may_force=1, guard_no_exception=1, guard_not_forced=1) + self.check_loops(call_release_gil=1, guard_no_exception=1, guard_not_forced=1) def test_cast_argument(self): """ @@ -267,6 +293,76 @@ res = self.call(get_dummy, [], rffi.LONG) assert res == initval+1 + def test_single_float_args(self): + """ + float sum_xy_float(float x, float y) + { + return x+y; + } + """ + from ctypes import c_float # this is used only to compute the expected result + libfoo = self.get_libfoo() + func = (libfoo, 'sum_xy_float', [types.float, types.float], types.float) + x = r_singlefloat(12.34) + y = r_singlefloat(56.78) + res = self.call(func, [x, y], rffi.FLOAT, init_result=0.0) + expected = c_float(c_float(12.34).value + c_float(56.78).value).value + assert res == expected + + def test_slonglong_args(self): + """ + long long sum_xy_longlong(long long x, long long y) + { + return x+y; + } + """ + maxint32 = 2147483647 # we cannot really go above maxint on 64 bits + # (and we would not test anything, as there long + # is the same as long long) + libfoo = self.get_libfoo() + func = (libfoo, 'sum_xy_longlong', [types.slonglong, types.slonglong], + types.slonglong) + if IS_32_BIT: + x = r_longlong(maxint32+1) + y = r_longlong(maxint32+2) + zero = longlong2float(r_longlong(0)) + else: + x = maxint32+1 + y = maxint32+2 + zero = 0 + res = self.call(func, [x, y], rffi.LONGLONG, init_result=zero) + if IS_32_BIT: + # obscure, on 32bit it's really a long long, so it returns a + # DOUBLE because of the JIT hack + res = float2longlong(res) + expected = maxint32*2 + 3 + assert res == expected + + def test_ulonglong_args(self): + """ + unsigned long long sum_xy_ulonglong(unsigned long long x, + unsigned long long y) + { + return x+y; + } + """ + maxint64 = 9223372036854775807 # maxint64+1 does not fit into a + # longlong, but it does into a + # ulonglong + libfoo = self.get_libfoo() + func = (libfoo, 'sum_xy_ulonglong', [types.ulonglong, types.ulonglong], + types.ulonglong) + x = r_ulonglong(maxint64+1) + y = r_ulonglong(2) + res = self.call(func, [x, y], rffi.ULONGLONG, init_result=0) + if IS_32_BIT: + # obscure, on 32bit it's really a long long, so it returns a + # DOUBLE because of the JIT hack + res = float2longlong(res) + res = rffi.cast(rffi.ULONGLONG, res) + expected = maxint64 + 3 + assert res == expected + def test_wrong_number_of_arguments(self): from pypy.rpython.llinterp import LLException libfoo = self.get_libfoo() @@ -287,3 +383,57 @@ my_raises("self.call(func, [38], rffi.LONG)") # one less my_raises("self.call(func, [38, 12.3, 42], rffi.LONG)") # one more + + + def test_byval_argument(self): + """ + struct Point { + long x; + long y; + }; + + long sum_point(struct Point p) { + return p.x + p.y; + } + """ + libfoo = CDLL(self.libfoo_name) + ffi_point_struct = make_struct_ffitype_e(0, 0, [types.slong, types.slong]) + ffi_point = ffi_point_struct.ffistruct + sum_point = (libfoo, 'sum_point', [ffi_point], types.slong) + # + ARRAY = rffi.CArray(rffi.LONG) + buf = lltype.malloc(ARRAY, 2, flavor='raw') + buf[0] = 30 + buf[1] = 12 + adr = rffi.cast(rffi.VOIDP, buf) + res = self.call(sum_point, [('arg_raw', adr)], rffi.LONG, init_result=0) + assert res == 42 + # check that we still have the ownership on the buffer + assert buf[0] == 30 + assert buf[1] == 12 + lltype.free(buf, flavor='raw') + lltype.free(ffi_point_struct, flavor='raw') + + def test_byval_result(self): + """ + struct Point make_point(long x, long y) { + struct Point p; + p.x = x; + p.y = y; + return p; + } + """ + libfoo = CDLL(self.libfoo_name) + ffi_point_struct = make_struct_ffitype_e(0, 0, [types.slong, types.slong]) + ffi_point = ffi_point_struct.ffistruct + + libfoo = CDLL(self.libfoo_name) + make_point = (libfoo, 'make_point', [types.slong, types.slong], ffi_point) + # + PTR = lltype.Ptr(rffi.CArray(rffi.LONG)) + p = self.call(make_point, [12, 34], PTR, init_result=lltype.nullptr(PTR.TO), + is_struct=True) + assert p[0] == 12 + assert p[1] == 34 + lltype.free(p, flavor='raw') + lltype.free(ffi_point_struct, flavor='raw') diff --git a/pypy/rlib/test/test_rrandom.py b/pypy/rlib/test/test_rrandom.py --- a/pypy/rlib/test/test_rrandom.py +++ b/pypy/rlib/test/test_rrandom.py @@ -3,6 +3,12 @@ # the numbers were created by using CPython's _randommodule.c +def test_init_from_zero(): + rnd = Random(0) + assert rnd.state[:14] == [0, 1, 1812433255, 1900727105, 1208447044, + 2481403966, 4042607538, 337614300, 3232553940, + 1018809052, 3202401494, 1775180719, 3192392114, 594215549] + def test_init_from_seed(): rnd = Random(1000) assert rnd.state[:14] == [1000, 4252021385, 1724402292, 571538732, diff --git a/pypy/rlib/test/test_streamio.py b/pypy/rlib/test/test_streamio.py --- a/pypy/rlib/test/test_streamio.py +++ b/pypy/rlib/test/test_streamio.py @@ -1008,6 +1008,75 @@ assert base.buf == data +class TestReadlineInputStream: + + packets = ["a", "b", "\n", "def", "\nxy\npq\nuv", "wx"] + lines = ["ab\n", "def\n", "xy\n", "pq\n", "uvwx"] + + def makeStream(self, seek=False, tell=False, bufsize=-1): + base = TSource(self.packets) + self.source = base + def f(*args): + if seek is False: + raise NotImplementedError # a bug! + if seek is None: + raise streamio.MyNotImplementedError # can be caught + raise ValueError(seek) # uh? + if not tell: + base.tell = f + if not seek: + base.seek = f + return streamio.ReadlineInputStream(base, bufsize) + + def test_readline(self): + for file in [self.makeStream(), self.makeStream(bufsize=2)]: + i = 0 + while 1: + r = file.readline() + if r == "": + break + assert self.lines[i] == r + i += 1 + assert i == len(self.lines) + + def test_readline_and_read_interleaved(self): + for file in [self.makeStream(seek=True), + self.makeStream(seek=True, bufsize=2)]: + i = 0 + while 1: + firstchar = file.read(1) + if firstchar == "": + break + r = file.readline() + assert r != "" + assert self.lines[i] == firstchar + r + i += 1 + assert i == len(self.lines) + + def test_readline_and_read_interleaved_no_seek(self): + for file in [self.makeStream(seek=None), + self.makeStream(seek=None, bufsize=2)]: + i = 0 + while 1: + firstchar = file.read(1) + if firstchar == "": + break + r = file.readline() + assert r != "" + assert self.lines[i] == firstchar + r + i += 1 + assert i == len(self.lines) + + def test_readline_and_readall(self): + file = self.makeStream(seek=True, tell=True, bufsize=2) + r = file.readline() + assert r == 'ab\n' + assert file.tell() == 3 + r = file.readall() + assert r == 'def\nxy\npq\nuvwx' + r = file.readall() + assert r == '' + # Speed test diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -563,15 +563,6 @@ def op_hint(self, x, hints): return x - def op_resume_point(self, *args): - pass - - def op_resume_state_create(self, *args): - raise RuntimeError("resume_state_create can not be called.") - - def op_resume_state_invoke(self, *args): - raise RuntimeError("resume_state_invoke can not be called.") - def op_decode_arg(self, fname, i, name, vargs, vkwds): raise NotImplementedError("decode_arg") @@ -746,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -20,7 +20,6 @@ from pypy.rpython.extfunc import ExtRegistryEntry from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic from pypy.tool.uid import fixid -from pypy.tool.tls import tlsobject from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longfloat, intmask from pypy.annotation import model as annmodel from pypy.rpython.llinterp import LLInterpreter, LLException @@ -28,6 +27,7 @@ from pypy.rpython import raddress from pypy.translator.platform import platform from array import array +from thread import _local as tlsobject # ____________________________________________________________ @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: @@ -418,6 +420,9 @@ instance._storage = ctypes_storage assert ctypes_storage # null pointer? +class NotCtypesAllocatedStructure(ValueError): + pass + class _parentable_mixin(object): """Mixin added to _parentable containers when they become ctypes-based. (This is done by changing the __class__ of the instance to reference @@ -436,7 +441,7 @@ def _addressof_storage(self): "Returns the storage address as an int" if self._storage is None or self._storage is True: - raise ValueError("Not a ctypes allocated structure") + raise NotCtypesAllocatedStructure("Not a ctypes allocated structure") return intmask(ctypes.cast(self._storage, ctypes.c_void_p).value) def _free(self): diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -521,10 +521,6 @@ RuntimeError)), # can always unwind, not just if stackless gc - 'resume_point': LLOp(canraise=(Exception,)), - 'resume_state_create': LLOp(canraise=(MemoryError,), canunwindgc=True), - 'resume_state_invoke': LLOp(canraise=(Exception, StackException, - RuntimeError)), 'stack_frames_depth': LLOp(sideeffects=False, canraise=(StackException, RuntimeError)), 'stack_switch': LLOp(canraise=(StackException, RuntimeError)), diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -4,14 +4,16 @@ base_int, normalizedinttype) from pypy.rlib.objectmodel import Symbolic from pypy.tool.uid import Hashable -from pypy.tool.tls import tlsobject from pypy.tool.identity_dict import identity_dict from pypy.tool import leakfinder from types import NoneType from sys import maxint import weakref -TLS = tlsobject() +class State(object): + pass + +TLS = State() class WeakValueDictionary(weakref.WeakValueDictionary): """A subclass of weakref.WeakValueDictionary @@ -829,7 +831,7 @@ raise TypeError, "unsupported cast" def _cast_whatever(TGT, value): - from pypy.rpython.lltypesystem import llmemory + from pypy.rpython.lltypesystem import llmemory, rffi ORIG = typeOf(value) if ORIG == TGT: return value @@ -845,6 +847,8 @@ return cast_pointer(TGT, value) elif ORIG == llmemory.Address: return llmemory.cast_adr_to_ptr(value, TGT) + elif TGT == rffi.VOIDP and ORIG == Unsigned: + return rffi.cast(TGT, value) elif ORIG == Signed: return cast_int_to_ptr(TGT, value) elif TGT == llmemory.Address and isinstance(ORIG, Ptr): diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -206,7 +215,7 @@ if dictobj is None: return lltype.nullptr(self.DICT) if not isinstance(dictobj, (dict, objectmodel.r_dict)): - raise TyperError("expected a dict: %r" % (dictobj,)) + raise TypeError("expected a dict: %r" % (dictobj,)) try: key = Constant(dictobj) return self.dict_cache[key] @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) @@ -833,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -845,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive @@ -139,10 +139,10 @@ source = py.code.Source(""" def call_external_function(%(argnames)s): before = aroundstate.before - after = aroundstate.after if before: before() # NB. it is essential that no exception checking occurs here! res = funcptr(%(argnames)s) + after = aroundstate.after if after: after() return res """ % locals()) @@ -244,7 +244,7 @@ def __init__(self): self.callbacks = {} -def _make_wrapper_for(TP, callable, callbackholder, aroundstate=None): +def _make_wrapper_for(TP, callable, callbackholder=None, aroundstate=None): """ Function creating wrappers for callbacks. Note that this is cheating as we assume constant callbacks and we just memoize wrappers """ @@ -253,21 +253,18 @@ if hasattr(callable, '_errorcode_'): errorcode = callable._errorcode_ else: - errorcode = TP.TO.RESULT._example() + errorcode = TP.TO.RESULT._defl() callable_name = getattr(callable, '__name__', '?') - callbackholder.callbacks[callable] = True + if callbackholder is not None: + callbackholder.callbacks[callable] = True args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))]) source = py.code.Source(r""" def wrapper(%s): # no *args - no GIL for mallocing the tuple llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py if aroundstate is not None: - before = aroundstate.before after = aroundstate.after - else: - before = None - after = None - if after: - after() + if after: + after() # from now on we hold the GIL stackcounter.stacks_counter += 1 try: @@ -281,8 +278,10 @@ traceback.print_exc() result = errorcode stackcounter.stacks_counter -= 1 - if before: - before() + if aroundstate is not None: + before = aroundstate.before + if before: + before() # here we don't hold the GIL any more. As in the wrapper() produced # by llexternal, it is essential that no exception checking occurs # after the call to before(). diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py --- a/pypy/rpython/lltypesystem/rlist.py +++ b/pypy/rpython/lltypesystem/rlist.py @@ -237,6 +237,7 @@ l.length = newsize else: _ll_list_resize_really(l, newsize) +_ll_list_resize_ge.oopspec = 'list._resize_ge(l, newsize)' def _ll_list_resize_le(l, newsize): if newsize >= (len(l.items) >> 1) - 5: @@ -249,12 +250,11 @@ length = l.length l.length = length + 1 l.ll_setitem_fast(length, newitem) -ll_append_noresize.oopspec = 'list.append(l, newitem)' def ll_both_none(lst1, lst2): return not lst1 and not lst2 - + # ____________________________________________________________ # diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -57,6 +57,8 @@ llmemory.itemoffsetof(TP.chars, 0) + llmemory.sizeof(CHAR_TP) * item) + # It'd be nice to be able to look inside this function. + @dont_look_inside @enforceargs(None, None, int, int, int) def copy_string_contents(src, dst, srcstart, dststart, length): assert srcstart >= 0 @@ -142,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -157,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -256,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -278,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -323,6 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -334,12 +337,11 @@ x = 29872897 s.hash = x return x - ll_strhash._pure_function_ = True # it's pure but it does not look like it def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -349,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -367,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -384,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -425,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -448,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -468,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -484,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -501,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -513,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -524,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -592,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -715,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -813,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -828,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -839,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,23 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + class Cls(self.AddressStack): + def append(self2, addr): + assert addr not in self2.tolist() + self.AddressStack.append(self2, addr) + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +637,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +655,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +698,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +789,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +882,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +922,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,13 +933,13 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded - self.remember_young_pointer_from_array(addr_array, index) + self.remember_young_pointer_from_array2(addr_array, index) else: self.remember_young_pointer(addr_array, newvalue) @@ -943,20 +955,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -976,20 +991,22 @@ def _init_writebarrier_with_card_marker(self): DEBUG = self.DEBUG - def remember_young_pointer_from_array(addr_array, index): + def remember_young_pointer_from_array2(addr_array, index): # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,26 +1019,85 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return # # We set the flag (even if the newly written address does not # actually point to the nursery, which seems to be ok -- actually - # it seems more important that remember_young_pointer_from_array() + # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET - remember_young_pointer_from_array._dont_inline_ = True - self.remember_young_pointer_from_array = ( - remember_young_pointer_from_array) + remember_young_pointer_from_array2._dont_inline_ = True + assert self.card_page_indices > 0 + self.remember_young_pointer_from_array2 = ( + remember_young_pointer_from_array2) + + # xxx trying it out for the JIT: a 3-arguments version of the above + def remember_young_pointer_from_array3(addr_array, index, newvalue): + objhdr = self.header(addr_array) + # + # a single check for the common case of neither GCFLAG_HAS_CARDS + # nor GCFLAG_NO_HEAP_PTRS + if objhdr.tid & (GCFLAG_HAS_CARDS | GCFLAG_NO_HEAP_PTRS) == 0: + # common case: fast path, jump to the end of the function + pass + elif objhdr.tid & GCFLAG_HAS_CARDS == 0: + # no cards, but GCFLAG_NO_HEAP_PTRS is set. + objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS + self.prebuilt_root_objects.append(addr_array) + # jump to the end of the function + else: + # case with cards. + # + # If the newly written address does not actually point to a + # young object, leave now. + if not self.appears_to_be_young(newvalue): + return + # + # 'addr_array' is a raw_malloc'ed array with card markers + # in front. Compute the index of the bit to set: + bitindex = index >> self.card_page_shift + byteindex = bitindex >> 3 + bitmask = 1 << (bitindex & 7) + # + # If the bit is already set, leave now. + addr_byte = self.get_card(addr_array, byteindex) + byte = ord(addr_byte.char[0]) + if byte & bitmask: + return + addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET + return + # + # Logic for the no-cards case, put here to minimize the number + # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # + if self.appears_to_be_young(newvalue): + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS + + remember_young_pointer_from_array3._dont_inline_ = True + assert self.card_page_indices > 0 + self.remember_young_pointer_from_array3 = ( + remember_young_pointer_from_array3) + + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) def assume_young_pointers(self, addr_struct): @@ -1029,15 +1105,16 @@ may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1045,15 +1122,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1061,6 +1159,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1077,20 +1191,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1123,7 +1245,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1131,7 +1253,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1147,11 +1269,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1187,19 +1309,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1238,7 +1371,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1285,11 +1430,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,78 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag + # + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert not res # there might be young ptrs, let ll_arraycopy to find them + + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -463,7 +464,7 @@ annmodel.SomeInteger()], annmodel.s_None, inline=True) - func = getattr(gcdata.gc, 'remember_young_pointer_from_array', + func = getattr(gcdata.gc, 'remember_young_pointer_from_array3', None) if func is not None: # func should not be a bound method, but a real function @@ -471,7 +472,8 @@ self.write_barrier_from_array_failing_case_ptr = \ getfn(func, [annmodel.SomeAddress(), - annmodel.SomeInteger()], + annmodel.SomeInteger(), + annmodel.SomeAddress()], annmodel.s_None) self.statistics_ptr = getfn(GCClass.statistics.im_func, [s_gc, annmodel.SomeInteger()], @@ -860,9 +862,9 @@ def gct_get_write_barrier_from_array_failing_case(self, hop): op = hop.spaceop - hop.genop("same_as", - [self.write_barrier_from_array_failing_case_ptr], - resultvar=op.result) + v = getattr(self, 'write_barrier_from_array_failing_case_ptr', + lltype.nullptr(op.result.concretetype.TO)) + hop.genop("same_as", [v], resultvar=op.result) def gct_zero_gc_pointers_inside(self, hop): if not self.malloc_zero_filled: @@ -883,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/module/test/test_posix.py b/pypy/rpython/module/test/test_posix.py --- a/pypy/rpython/module/test/test_posix.py +++ b/pypy/rpython/module/test/test_posix.py @@ -43,6 +43,17 @@ for i in range(len(stat)): assert long(getattr(func, 'item%d' % i)) == stat[i] + def test_stat_exception(self): + def fo(): + try: + posix.stat('I/do/not/exist') + except OSError: + return True + else: + return False + res = self.interpret(fo,[]) + assert res + def test_times(self): import py; py.test.skip("llinterp does not like tuple returns") from pypy.rpython.test.test_llinterp import interpret @@ -205,5 +216,8 @@ def test_stat(self): py.test.skip("ootypesystem does not support os.stat") + def test_stat_exception(self): + py.test.skip("ootypesystem does not support os.stat") + def test_chown(self): py.test.skip("ootypesystem does not support os.chown") diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -568,7 +568,6 @@ length = l.ll_length() l._ll_resize_ge(length+1) # see "a note about overflows" above l.ll_setitem_fast(length, newitem) -ll_append.oopspec = 'list.append(l, newitem)' # this one is for the special case of insert(0, x) def ll_prepend(l, newitem): @@ -793,7 +792,6 @@ raise MemoryError l1._ll_resize_ge(newlength) ll_arraycopy(l2, l1, 0, len1, len2) -ll_extend.oopspec = 'list.extend(l1, l2)' def ll_extend_with_str(lst, s, getstrlen, getstritem): return ll_extend_with_str_slice_startonly(lst, s, getstrlen, getstritem, 0) diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,29 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): @@ -860,6 +883,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/tool/gcc_cache.py b/pypy/tool/gcc_cache.py --- a/pypy/tool/gcc_cache.py +++ b/pypy/tool/gcc_cache.py @@ -39,7 +39,16 @@ data = '' if not (data.startswith('True') or data.startswith('FAIL\n')): try: - platform.compile(c_files, eci) + _previous = platform.log_errors + try: + platform.log_errors = False + platform.compile(c_files, eci) + finally: + del platform.log_errors + # ^^^remove from the instance --- needed so that it can + # compare equal to another instance without it + if platform.log_errors != _previous: + platform.log_errors = _previous data = 'True' path.write(data) except CompilationError, e: diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,4 +1,5 @@ import re, sys + from pypy.jit.metainterp.resoperation import rop, opname from pypy.jit.tool.oparser import OpParser @@ -51,6 +52,7 @@ # factory method Op = Op + use_mock_model = True @classmethod def parse_from_input(cls, input): @@ -61,7 +63,7 @@ if not argspec.strip(): return [], None if opname == 'debug_merge_point': - return argspec.rsplit(", ", 1), None + return argspec.split(", ", 1), None else: args = argspec.split(', ') descr = None @@ -95,12 +97,12 @@ def __init__(self, operations, storage): if operations[0].name == 'debug_merge_point': - self.inline_level = int(operations[0].args[1]) - m = re.search('\w]+), file \'(.+?)\', line (\d+)> #(\d+) (\w+)', - operations[0].getarg(0)) + self.inline_level = int(operations[0].args[0]) + m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', + operations[0].getarg(1)) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[0].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1].split(" ")[0][1:] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) @@ -119,6 +121,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -218,6 +223,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -29,7 +29,7 @@ def test_parse_non_code(): ops = parse(''' [] - debug_merge_point("SomeRandomStuff", 0) + debug_merge_point(0, "SomeRandomStuff") ''') res = Function.from_operations(ops.operations, LoopStorage()) assert len(res.chunks) == 1 @@ -38,10 +38,10 @@ def test_split(): ops = parse(''' [i0] - debug_merge_point(" #10 ADD", 0) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -54,12 +54,12 @@ def test_inlined_call(): ops = parse(""" [] - debug_merge_point(' #28 CALL_FUNCTION', 0) + debug_merge_point(0, ' #28 CALL_FUNCTION') i18 = getfield_gc(p0, descr=) - debug_merge_point(' #0 LOAD_FAST', 1) - debug_merge_point(' #3 LOAD_CONST', 1) - debug_merge_point(' #7 RETURN_VALUE', 1) - debug_merge_point(' #31 STORE_FAST', 0) + debug_merge_point(1, ' #0 LOAD_FAST') + debug_merge_point(1, ' #3 LOAD_CONST') + debug_merge_point(1, ' #7 RETURN_VALUE') + debug_merge_point(0, ' #31 STORE_FAST') """) res = Function.from_operations(ops.operations, LoopStorage()) assert len(res.chunks) == 3 # two chunks + inlined call @@ -72,10 +72,10 @@ def test_name(): ops = parse(''' [i0] - debug_merge_point(" #10 ADD", 0) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -89,10 +89,10 @@ ops = parse(''' [i0] i3 = int_add(i0, 1) - debug_merge_point(" #10 ADD", 0) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -102,10 +102,10 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(" #0 LOAD_FAST", 0) - debug_merge_point(" #3 LOAD_FAST", 0) - debug_merge_point(" #6 BINARY_ADD", 0) - debug_merge_point(" #7 RETURN_VALUE", 0) + debug_merge_point(0, " #0 LOAD_FAST") + debug_merge_point(0, " #3 LOAD_FAST") + debug_merge_point(0, " #6 BINARY_ADD") + debug_merge_point(0, " #7 RETURN_VALUE") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.chunks[1].lineno == 3 @@ -114,11 +114,11 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(" #9 LOAD_FAST", 0) - debug_merge_point(" #12 LOAD_CONST", 0) - debug_merge_point(" #22 LOAD_CONST", 0) - debug_merge_point(" #28 LOAD_CONST", 0) - debug_merge_point(" #6 SETUP_LOOP", 0) + debug_merge_point(0, " #9 LOAD_FAST") + debug_merge_point(0, " #12 LOAD_CONST") + debug_merge_point(0, " #22 LOAD_CONST") + debug_merge_point(0, " #28 LOAD_CONST") + debug_merge_point(0, " #6 SETUP_LOOP") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.linerange == (7, 9) @@ -128,7 +128,7 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] - debug_merge_point(' #17 FOR_ITER', 0) + debug_merge_point(0, ' #17 FOR_ITER') guard_class(p6, 144264192, descr=) p12 = getfield_gc(p6, descr=) """ % locals()) @@ -168,13 +168,13 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' def test_parsing_strliteral(): loop = parse(""" - debug_merge_point('StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]', 0) + debug_merge_point(0, 'StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]') """) ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -1,8 +1,13 @@ import autopath import py -from pypy.interpreter import gateway +from pypy.interpreter import gateway, pycode from pypy.interpreter.error import OperationError +try: + from _pytest.assertion.newinterpret import interpret +except ImportError: + from _pytest.assertion.oldinterpret import interpret + # ____________________________________________________________ class AppCode(object): @@ -51,13 +56,11 @@ space = self.space for key, w_value in vars.items(): space.setitem(self.w_locals, space.wrap(key), w_value) - return space.eval(code, self.w_globals, self.w_locals) - - def exec_(self, code, **vars): - space = self.space - for key, w_value in vars.items(): - space.setitem(self.w_locals, space.wrap(key), w_value) - space.exec_(code, self.w_globals, self.w_locals) + if isinstance(code, str): + return space.eval(code, self.w_globals, self.w_locals) + pyc = pycode.PyCode._from_code(space, code) + return pyc.exec_host_bytecode(self.w_globals, self.w_locals) + exec_ = eval def repr(self, w_value): return self.space.unwrap(self.space.repr(w_value)) @@ -81,7 +84,7 @@ self.space = space self.operr = operr self.typename = operr.w_type.getname(space, "?") - self.traceback = AppTraceback(space, self.operr.application_traceback) + self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: self._excinfo = debug_excs[0] @@ -163,8 +166,8 @@ except py.error.ENOENT: source = None from pypy import conftest - if source and not py.test.config.option.nomagic: - msg = py.code._reinterpret_old(source, runner, should_fail=True) + if source and py.test.config._assertstate.mode != "off": + msg = interpret(source, runner, should_fail=True) space.setattr(w_self, space.wrap('args'), space.newtuple([space.wrap(msg)])) w_msg = space.wrap(msg) diff --git a/pypy/tool/pytest/test/test_pytestsupport.py b/pypy/tool/pytest/test/test_pytestsupport.py --- a/pypy/tool/pytest/test/test_pytestsupport.py +++ b/pypy/tool/pytest/test/test_pytestsupport.py @@ -4,7 +4,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.pyframe import PyFrame from pypy.tool.pytest.appsupport import (AppFrame, build_pytest_assertion, - AppExceptionInfo) + AppExceptionInfo, interpret) import py from pypy.tool.udir import udir import os @@ -22,8 +22,8 @@ co = PyCode._from_code(space, somefunc.func_code) pyframe = PyFrame(space, co, space.newdict(), None) runner = AppFrame(space, pyframe) - py.code._reinterpret_old("f = lambda x: x+1", runner, should_fail=False) - msg = py.code._reinterpret_old("assert isinstance(f(2), float)", runner) + interpret("f = lambda x: x+1", runner, should_fail=False) + msg = interpret("assert isinstance(f(2), float)", runner) assert msg.startswith("assert isinstance(3, float)\n" " + where 3 = ") @@ -58,6 +58,12 @@ except AssertionError, e: assert e.msg == "Failed" +def app_test_comparison(): + try: + assert 3 > 4 + except AssertionError, e: + assert "3 > 4" in e.msg + def test_appexecinfo(space): try: diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -3,9 +3,9 @@ It uses 'pypy/translator/goal/pypy-c' and parts of the rest of the working copy. Usage: - package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] + package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] [destination-for-tarball] [pypy-c-path] -Usually you would do: package.py ../../.. pypy-VER-PLATFORM. +Usually you would do: package.py ../../.. pypy-VER-PLATFORM The output is found in the directory /tmp/usession-YOURNAME/build/. """ @@ -122,7 +122,10 @@ zf.close() else: archive = str(builddir.join(name + '.tar.bz2')) - e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) + if sys.platform == 'darwin': + e = os.system('tar --numeric-owner -cvjf ' + archive + " " + name) + else: + e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) if e: raise OSError('"tar" returned exit status %r' % e) finally: diff --git a/pypy/tool/test/test_gcc_cache.py b/pypy/tool/test/test_gcc_cache.py --- a/pypy/tool/test/test_gcc_cache.py +++ b/pypy/tool/test/test_gcc_cache.py @@ -1,11 +1,13 @@ - +import sys from pypy.tool.gcc_cache import * from pypy.tool.udir import udir -import md5 +import md5, cStringIO from pypy.translator.tool.cbuild import ExternalCompilationInfo +localudir = udir.join('test_gcc_cache').ensure(dir=1) + def test_gcc_exec(): - f = udir.join("x.c") + f = localudir.join("x.c") f.write(""" #include #include @@ -15,8 +17,8 @@ return 0; } """) - dir1 = udir.join('test_gcc_exec_dir1').ensure(dir=1) - dir2 = udir.join('test_gcc_exec_dir2').ensure(dir=1) + dir1 = localudir.join('test_gcc_exec_dir1').ensure(dir=1) + dir2 = localudir.join('test_gcc_exec_dir2').ensure(dir=1) dir1.join('test_gcc_exec.h').write('#define ANSWER 3\n') dir2.join('test_gcc_exec.h').write('#define ANSWER 42\n') eci = ExternalCompilationInfo(include_dirs=[str(dir1)]) @@ -36,7 +38,7 @@ print '>>>' def test_gcc_ask(): - f = udir.join("y.c") + f = localudir.join("y.c") f.write(""" #include #include @@ -46,8 +48,8 @@ return 0; } """) - dir1 = udir.join('test_gcc_ask_dir1').ensure(dir=1) - dir2 = udir.join('test_gcc_ask_dir2').ensure(dir=1) + dir1 = localudir.join('test_gcc_ask_dir1').ensure(dir=1) + dir2 = localudir.join('test_gcc_ask_dir2').ensure(dir=1) dir1.join('test_gcc_ask.h').write('/* hello world */\n') dir2.join('test_gcc_ask.h').write('#error boom\n') eci = ExternalCompilationInfo(include_dirs=[str(dir1)]) @@ -63,3 +65,15 @@ print '<<<' print err print '>>>' + +def test_gcc_ask_doesnt_log_errors(): + f = localudir.join('z.c') + f.write("""this file is not valid C code\n""") + eci = ExternalCompilationInfo() + oldstderr = sys.stderr + try: + sys.stderr = capture = cStringIO.StringIO() + py.test.raises(CompilationError, try_compile_cache, [f], eci) + finally: + sys.stderr = oldstderr + assert 'ERROR' not in capture.getvalue().upper() diff --git a/pypy/tool/tls.py b/pypy/tool/tls.py deleted file mode 100644 --- a/pypy/tool/tls.py +++ /dev/null @@ -1,8 +0,0 @@ - -"""Thread-local storage.""" - -try: - from thread import _local as tlsobject -except ImportError: - class tlsobject(object): - pass diff --git a/pypy/translator/backendopt/inline.py b/pypy/translator/backendopt/inline.py --- a/pypy/translator/backendopt/inline.py +++ b/pypy/translator/backendopt/inline.py @@ -541,7 +541,6 @@ 'cast_pointer': 0, 'malloc': 2, 'yield_current_frame_to_caller': sys.maxint, # XXX bit extreme - 'resume_point': sys.maxint, # XXX bit extreme 'instrument_count': 0, 'debug_assert': -1, } diff --git a/pypy/translator/backendopt/removenoops.py b/pypy/translator/backendopt/removenoops.py --- a/pypy/translator/backendopt/removenoops.py +++ b/pypy/translator/backendopt/removenoops.py @@ -81,8 +81,6 @@ num_removed += 1 else: available[key] = op.result - elif op.opname == 'resume_point': - available.clear() if num_removed: remove_same_as(graph) # remove casts with unused results diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -297,6 +297,13 @@ gc_startup_code = RefcountingGcPolicy.gc_startup_code.im_func + def compilation_info(self): + eci = BasicGcPolicy.compilation_info(self) + eci = eci.merge(ExternalCompilationInfo( + post_include_bits=['#define USING_NO_GC_AT_ALL'], + )) + return eci + class FrameworkGcPolicy(BasicGcPolicy): transformerclass = framework.FrameworkGCTransformer diff --git a/pypy/translator/c/gcc/instruction.py b/pypy/translator/c/gcc/instruction.py --- a/pypy/translator/c/gcc/instruction.py +++ b/pypy/translator/c/gcc/instruction.py @@ -187,8 +187,8 @@ def requestgcroots(self, tracker): # no need to track the value of these registers in the caller - # function if we are the main(), or if we are flagged as a - # "bottom" function (a callback from C code) + # function if we are flagged as a "bottom" function (a callback + # from C code, or pypy_main_function()) if tracker.is_stack_bottom: return {} else: diff --git a/pypy/translator/c/gcc/test/elf/track10.s b/pypy/translator/c/gcc/test/elf/track10.s --- a/pypy/translator/c/gcc/test/elf/track10.s +++ b/pypy/translator/c/gcc/test/elf/track10.s @@ -1,5 +1,5 @@ - .type main, @function -main: + .type main1, @function +main1: pushl %ebx call pypy_f ;; expected {4(%esp) | (%esp), %esi, %edi, %ebp | %ebx} @@ -11,4 +11,4 @@ /* GCROOT %ebx */ popl %ebx ret - .size main, .-main + .size main1, .-main1 diff --git a/pypy/translator/c/gcc/test/elf/track12.s b/pypy/translator/c/gcc/test/elf/track12.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf/track12.s @@ -0,0 +1,9 @@ + .type pypy_f, @function +pypy_f: + pushl 4(%esp) + call pypy_other + ;; expected {4(%esp) | %ebx, %esi, %edi, %ebp | (%esp)} + popl %eax + /* GCROOT %eax */ + ret + .size pypy_f, .-pypy_f diff --git a/pypy/translator/c/gcc/test/elf/track13.s b/pypy/translator/c/gcc/test/elf/track13.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf/track13.s @@ -0,0 +1,9 @@ + .type pypy_f, @function +pypy_f: + call pypy_other + ;; expected {(%esp) | %ebx, %esi, %edi, %ebp | 8(%esp)} + pushl 8(%esp) + popl %eax + /* GCROOT %eax */ + ret + .size pypy_f, .-pypy_f diff --git a/pypy/translator/c/gcc/test/elf/track4.s b/pypy/translator/c/gcc/test/elf/track4.s deleted file mode 100644 --- a/pypy/translator/c/gcc/test/elf/track4.s +++ /dev/null @@ -1,52 +0,0 @@ - .type main, @function -main: - ;; this is an artificial example showing what kind of code gcc - ;; can produce for main() - pushl %ebp - movl %eax, $globalptr1 - movl %esp, %ebp - pushl %edi - subl $8, %esp - andl $-16, %esp - movl %ebx, -8(%ebp) - movl 8(%ebp), %edi - call foobar - ;; expected {4(%ebp) | -8(%ebp), %esi, -4(%ebp), (%ebp) | %edi} -.L1: - cmpl $0, %eax - je .L3 -.L2: - ;; inlined function here with -fomit-frame-pointer - movl %eax, -12(%ebp) - movl %edi, %edx - subl $16, %esp - movl %eax, (%esp) - movl $42, %edi - movl %edx, 4(%esp) - movl %esi, %ebx - movl $nonsense, %esi - call foobar - ;; expected {4(%ebp) | -8(%ebp), %ebx, -4(%ebp), (%ebp) | 4(%esp), -12(%ebp)} - addl %edi, %eax - movl 4(%esp), %eax - movl %ebx, %esi - addl $16, %esp - movl %eax, %edi - movl -12(%ebp), %eax -#APP - /* GCROOT %eax */ -#NO_APP - ;; end of inlined function -.L3: - call foobar - ;; expected {4(%ebp) | -8(%ebp), %esi, -4(%ebp), (%ebp) | %edi} -#APP - /* GCROOT %edi */ -#NO_APP - movl -8(%ebp), %ebx - movl -4(%ebp), %edi - movl %ebp, %esp - popl %ebp - ret - - .size main, .-main diff --git a/pypy/translator/c/gcc/test/elf/track6.s b/pypy/translator/c/gcc/test/elf/track6.s deleted file mode 100644 --- a/pypy/translator/c/gcc/test/elf/track6.s +++ /dev/null @@ -1,26 +0,0 @@ - .type main, @function -main: - ;; a minimal example showing what kind of code gcc - ;; can produce for main(): some local variable accesses - ;; are relative to %ebp, while others are relative to - ;; %esp, and the difference %ebp-%esp is not constant - ;; because of the 'andl' to align the stack - pushl %ebp - movl %esp, %ebp - subl $8, %esp - andl $-16, %esp - movl $globalptr1, -4(%ebp) - movl $globalptr2, (%esp) - pushl $0 - call foobar - ;; expected {4(%ebp) | %ebx, %esi, %edi, (%ebp) | 4(%esp), -4(%ebp)} - popl %eax -#APP - /* GCROOT -4(%ebp) */ - /* GCROOT (%esp) */ -#NO_APP - movl %ebp, %esp - popl %ebp - ret - - .size main, .-main diff --git a/pypy/translator/c/gcc/test/elf/track7.s b/pypy/translator/c/gcc/test/elf/track7.s --- a/pypy/translator/c/gcc/test/elf/track7.s +++ b/pypy/translator/c/gcc/test/elf/track7.s @@ -1,5 +1,5 @@ - .type main, @function -main: + .type main1, @function +main1: ;; cmovCOND tests. pushl %ebx movl 12(%esp), %ebx @@ -16,4 +16,4 @@ popl %ebx ret - .size main, .-main + .size main1, .-main1 diff --git a/pypy/translator/c/gcc/test/msvc/track6.s b/pypy/translator/c/gcc/test/msvc/track6.s deleted file mode 100644 --- a/pypy/translator/c/gcc/test/msvc/track6.s +++ /dev/null @@ -1,15 +0,0 @@ -_TEXT SEGMENT -_pypy_g_foo PROC ; COMDAT - - push ebp - mov ebp, esp - and esp, -64 - sub esp, 12 - push esi - call _pypy_g_something_else - ;; expected {4(%ebp) | %ebx, (%esp), %edi, (%ebp) | } - pop esi - mov esp, ebp - pop ebp - ret 0 -_pypy_g_foo ENDP diff --git a/pypy/translator/c/gcc/test/msvc/track_and_esp.s b/pypy/translator/c/gcc/test/msvc/track_and_esp.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/msvc/track_and_esp.s @@ -0,0 +1,474 @@ +PUBLIC ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ ; `string' +PUBLIC _pypy_g_ll_math_ll_math_frexp +; COMDAT ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ +CONST SEGMENT +??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ DB 'pypy_g_ll_math_l' + DB 'l_math_frexp', 00H ; `string' +; Function compile flags: /Ogtpy +CONST ENDS +; COMDAT _pypy_g_ll_math_ll_math_frexp +_TEXT SEGMENT +_l_mantissa_0$ = -8 ; size = 8 +_l_v21638$ = -8 ; size = 8 +_l_x_14$ = 8 ; size = 8 +_pypy_g_ll_math_ll_math_frexp PROC ; COMDAT + +; 58245: struct pypy_tuple2_0 *pypy_g_ll_math_ll_math_frexp(double l_x_14) { + + push ebp + mov ebp, esp + and esp, -64 ; ffffffc0H + +; 58246: long *l_exp_p_0; double l_mantissa_0; bool_t l_v21641; +; 58247: bool_t l_v21643; bool_t l_v21644; bool_t l_v21646; bool_t l_v21647; +; 58248: bool_t l_v21652; bool_t l_v21653; bool_t l_v21660; bool_t l_v21666; +; 58249: bool_t l_v21670; bool_t l_v21674; bool_t l_v21676; double l_v21638; +; 58250: long l_v21637; long l_v21649; long l_v21651; long l_v21677; +; 58251: long l_v21678; struct pypy_exceptions_Exception0 *l_v21687; +; 58252: struct pypy_header0 *l_v21654; struct pypy_object0 *l_v21682; +; 58253: struct pypy_object0 *l_v21691; struct pypy_object_vtable0 *l_v21665; +; 58254: struct pypy_object_vtable0 *l_v21669; +; 58255: struct pypy_object_vtable0 *l_v21675; +; 58256: struct pypy_object_vtable0 *l_v21683; struct pypy_tuple2_0 *l_v21640; +; 58257: struct pypy_tuple2_0 *l_v21695; void* l_v21639; void* l_v21648; +; 58258: void* l_v21650; void* l_v21656; void* l_v21658; void* l_v21659; +; 58259: void* l_v21668; void* l_v21672; void* l_v21679; void* l_v21688; +; 58260: void* l_v21696; +; 58261: goto block0; +; 58262: +; 58263: block0: +; 58264: l_v21641 = pypy_g_ll_math_ll_math_isnan(l_x_14); + + fld QWORD PTR _l_x_14$[ebp] + sub esp, 52 ; 00000034H + push ebx + push esi + push edi + sub esp, 8 + fstp QWORD PTR [esp] +$block0$88239: + call _pypy_g_ll_math_ll_math_isnan + +; 58265: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isnan); +; 58266: l_v21643 = l_v21641; +; 58267: if (l_v21643) { +; 58268: l_v21637 = 0L; +; 58269: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] + add esp, 8 + test al, al + +; 58270: goto block3; + + jne SHORT $LN10 at pypy_g_ll_@159 + +; 58271: } +; 58272: goto block1; +; 58273: +; 58274: block1: +; 58275: l_v21644 = pypy_g_ll_math_ll_math_isinf(l_x_14); + + sub esp, 8 + fstp QWORD PTR [esp] +$block1$88243: + call _pypy_g_ll_math_ll_math_isinf + add esp, 8 + +; 58276: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isinf); +; 58277: l_v21646 = l_v21644; +; 58278: if (l_v21646) { + + test al, al + je SHORT $block2$88245 + +; 58279: l_v21637 = 0L; +; 58280: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] +$LN10 at pypy_g_ll_@159: + +; 58288: goto block14; +; 58289: } +; 58290: l_v21637 = 0L; + + xor edi, edi +$LN30 at pypy_g_ll_@159: + +; 58291: l_v21638 = l_x_14; +; 58292: goto block3; +; 58293: +; 58294: block3: +; 58295: l_v21648 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free; + + mov esi, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4 + fstp QWORD PTR _l_v21638$[esp+64] + +; 58296: OP_RAW_MALLOC_USAGE((0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21649); +; 58297: l_v21650 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_top_of_space; +; 58298: OP_ADR_DELTA(l_v21650, l_v21648, l_v21651); + + mov eax, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+12 + sub eax, esi + +; 58299: OP_INT_GT(l_v21649, l_v21651, l_v21652); + + cmp eax, 24 ; 00000018H +$block3$88242: + +; 58300: if (l_v21652) { + + jge $block4$88260 + +; 58334: l_v21695 = l_v21640; +; 58335: goto block8; +; 58336: +; 58337: block8: +; 58338: RPY_DEBUG_RETURN(); +; 58339: return l_v21695; +; 58340: +; 58341: block9: +; 58342: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58343: l_v21695 = ((struct pypy_tuple2_0 *) NULL); +; 58344: goto block8; +; 58345: +; 58346: block10: +; 58347: abort(); /* debug_llinterpcall should be unreachable */ +; 58348: l_v21665 = (&pypy_g_ExcData)->ed_exc_type; +; 58349: l_v21666 = (l_v21665 == NULL); +; 58350: if (!l_v21666) { +; 58351: goto block11; +; 58352: } +; 58353: goto block5; +; 58354: +; 58355: block11: +; 58356: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58357: l_v21696 = NULL; +; 58358: goto block6; +; 58359: +; 58360: block12: +; 58361: l_v21668 = pypy_g_SemiSpaceGC_obtain_free_space((&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC), (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0)))); + + push 24 ; 00000018H + push OFFSET _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC +$block12$88259: + call _pypy_g_SemiSpaceGC_obtain_free_space + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58362: l_v21669 = (&pypy_g_ExcData)->ed_exc_type; +; 58363: l_v21670 = (l_v21669 == NULL); + + xor ecx, ecx + add esp, 8 + cmp DWORD PTR _pypy_g_ExcData, ecx + +; 58364: if (!l_v21670) { + + je $LN5 at pypy_g_ll_@159 + +; 58368: goto block4; +; 58369: +; 58370: block13: +; 58371: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?N@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?8??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block13$88313: +$block9$88285: + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block2$88245: + +; 58281: goto block3; +; 58282: } +; 58283: goto block2; +; 58284: +; 58285: block2: +; 58286: OP_FLOAT_IS_TRUE(l_x_14, l_v21647); + + fldz + fld QWORD PTR _l_x_14$[ebp] + fucom ST(1) + fnstsw ax + fstp ST(1) + test ah, 68 ; 00000044H + +; 58287: if (l_v21647) { + + jnp $LN10 at pypy_g_ll_@159 + +; 58372: l_v21696 = NULL; +; 58373: goto block6; +; 58374: +; 58375: block14: +; 58376: l_v21672 = pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign(1L, (0 + 0), sizeof(long)); + + push 4 + fstp ST(0) + push 0 + push 1 +$block14$88247: + call _pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } + mov esi, eax + +; 58377: OP_TRACK_ALLOC_START(l_v21672, /* nothing */); + + push OFFSET ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ + push esi + call _pypy_debug_alloc_start + ;; expected {4(%ebp) | 28(%esp), 24(%esp), 20(%esp), (%ebp) | } + add esp, 20 ; 00000014H + +; 58378: l_exp_p_0 = (long *)l_v21672; +; 58379: l_v21674 = (l_exp_p_0 != NULL); + + test esi, esi + +; 58380: if (!l_v21674) { + + jne SHORT $block15$88324 + +; 58418: goto block8; +; 58419: +; 58420: block18: +; 58421: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BB@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], esi + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block18$88323: + +; 58422: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block15$88324: + +; 58381: goto block18; +; 58382: } +; 58383: goto block15; +; 58384: +; 58385: block15: +; 58386: l_mantissa_0 = pypy_g_frexp__Float_arrayPtr_star_2(l_x_14, l_exp_p_0); + + fld QWORD PTR _l_x_14$[ebp] + push esi + sub esp, 8 + fstp QWORD PTR [esp] + call _pypy_g_frexp__Float_arrayPtr_star_2 + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } + +; 58387: l_v21675 = (&pypy_g_ExcData)->ed_exc_type; +; 58388: l_v21676 = (l_v21675 == NULL); + + mov edi, DWORD PTR _pypy_g_ExcData + fstp QWORD PTR _l_mantissa_0$[esp+76] + add esp, 12 ; 0000000cH + test edi, edi + +; 58389: if (!l_v21676) { + + je SHORT $block16$88328 + +; 58403: +; 58404: block17: +; 58405: l_v21682 = (&pypy_g_ExcData)->ed_exc_value; +; 58406: l_v21683 = (&pypy_g_ExcData)->ed_exc_type; +; 58407: PYPY_DEBUG_CATCH_EXCEPTION("ll_math_ll_math_frexp", l_v21683, l_v21683 == (&pypy_g_py__code_assertion_AssertionError_vtable.ae_super.ae_super.se_super.e_super) || l_v21683 == (&pypy_g_exceptions_NotImplementedError_vtable.nie_super.re_super.se_super.e_super)); + + mov eax, DWORD PTR _pypydtcount + mov ebx, DWORD PTR _pypy_g_ExcData+4 + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BA@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], edi + inc eax + and eax, 8191 ; 00001fffH +$block17$88327: + mov DWORD PTR _pypydtcount, eax + cmp edi, OFFSET _pypy_g_py__code_assertion_AssertionError_vtable + je SHORT $LN1 at pypy_g_ll_@159 + cmp edi, OFFSET _pypy_g_exceptions_NotImplementedError_vtable + jne SHORT $LN2 at pypy_g_ll_@159 +$LN1 at pypy_g_ll_@159: + call _pypy_debug_catch_fatal_exception +$LN2 at pypy_g_ll_@159: + +; 58408: (&pypy_g_ExcData)->ed_exc_value = ((struct pypy_object0 *) NULL); + + xor eax, eax + +; 58409: (&pypy_g_ExcData)->ed_exc_type = ((struct pypy_object_vtable0 *) NULL); +; 58410: l_v21687 = (struct pypy_exceptions_Exception0 *)l_v21682; +; 58411: l_v21688 = (void*)l_exp_p_0; +; 58412: OP_TRACK_ALLOC_STOP(l_v21688, /* nothing */); + + push esi + mov DWORD PTR _pypy_g_ExcData+4, eax + mov DWORD PTR _pypy_g_ExcData, eax + call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } + +; 58413: OP_RAW_FREE(l_v21688, /* nothing */); + + push esi + call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58414: l_v21691 = (struct pypy_object0 *)l_v21687; +; 58415: pypy_g_RPyReRaiseException(l_v21683, l_v21691); + + push ebx + push edi + call _pypy_g_RPyReRaiseException + add esp, 16 ; 00000010H + +; 58416: pypy_asm_gc_nocollect(pypy_g_RPyReRaiseException); +; 58417: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block16$88328: + +; 58390: goto block17; +; 58391: } +; 58392: goto block16; +; 58393: +; 58394: block16: +; 58395: l_v21677 = RPyBareItem(l_exp_p_0, 0L); +; 58396: l_v21678 = (long)(l_v21677); + + mov edi, DWORD PTR [esi] + +; 58397: l_v21679 = (void*)l_exp_p_0; +; 58398: OP_TRACK_ALLOC_STOP(l_v21679, /* nothing */); + + push esi + call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } + +; 58399: OP_RAW_FREE(l_v21679, /* nothing */); + + push esi + call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58400: l_v21637 = l_v21678; +; 58401: l_v21638 = l_mantissa_0; + + fld QWORD PTR _l_mantissa_0$[esp+72] + add esp, 8 + +; 58402: goto block3; + + jmp $LN30 at pypy_g_ll_@159 +$LN5 at pypy_g_ll_@159: + +; 58365: goto block13; +; 58366: } +; 58367: l_v21639 = l_v21668; + + mov esi, eax +$block4$88260: +$block5$88263: + +; 58301: goto block12; +; 58302: } +; 58303: l_v21639 = l_v21648; +; 58304: goto block4; +; 58305: +; 58306: block4: +; 58307: OP_INT_IS_TRUE(RUNNING_ON_LLINTERP, l_v21653); +; 58308: if (l_v21653) { +; 58309: goto block10; +; 58310: } +; 58311: goto block5; +; 58312: +; 58313: block5: +; 58314: l_v21654 = (struct pypy_header0 *)l_v21639; +; 58315: RPyField(l_v21654, h_tid) = (GROUP_MEMBER_OFFSET(struct group_pypy_g_typeinfo_s, member20)+0L); + + test esi, esi + jne SHORT $LN18 at pypy_g_ll_@159 + call _RPyAbort +$LN18 at pypy_g_ll_@159: + +; 58316: OP_ADR_ADD(l_v21639, (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21656); +; 58317: (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free = l_v21656; +; 58318: OP_ADR_ADD(l_v21639, 0, l_v21658); +; 58319: l_v21659 = (void*)l_v21658; +; 58320: l_v21696 = l_v21659; +; 58321: goto block6; +; 58322: +; 58323: block6: +; 58324: l_v21640 = (struct pypy_tuple2_0 *)l_v21696; +; 58325: l_v21660 = (l_v21640 != NULL); +; 58326: if (!l_v21660) { +; 58327: goto block9; +; 58328: } +; 58329: goto block7; +; 58330: +; 58331: block7: +; 58332: RPyField(l_v21640, t_item0) = l_v21638; + + fld QWORD PTR _l_v21638$[esp+64] + mov DWORD PTR [esi], 81 ; 00000051H + lea ecx, DWORD PTR [esi+24] + mov DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4, ecx + fstp QWORD PTR [esi+8] + +; 58333: RPyField(l_v21640, t_item1) = l_v21637; + + mov DWORD PTR [esi+16], edi + +; 58423: goto block8; +; 58424: } + + pop edi + mov eax, esi + pop esi +$block6$88281: +$block8$88289: + pop ebx + mov esp, ebp + pop ebp + ret 0 +_pypy_g_ll_math_ll_math_frexp ENDP +_TEXT ENDS diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -39,10 +39,15 @@ self.uses_frame_pointer = False self.r_localvar = self.r_localvarnofp self.filetag = filetag - # a "stack bottom" function is either main() or a callback from C code + # a "stack bottom" function is either pypy_main_function() or a + # callback from C code. In both cases they are identified by + # the presence of pypy_asm_stack_bottom(). self.is_stack_bottom = False def computegcmaptable(self, verbose=0): + if self.funcname in ['main', '_main']: + return [] # don't analyze main(), its prologue may contain + # strange instructions self.findlabels() self.parse_instructions() try: @@ -226,7 +231,7 @@ # in the frame at this point. This doesn't count the return address # which is the word immediately following the frame in memory. # The 'framesize' is set to an odd value if it is only an estimate - # (see visit_andl()). + # (see InsnCannotFollowEsp). def walker(insn, size_delta): check = deltas.setdefault(insn, size_delta) @@ -266,7 +271,8 @@ match = self.r_localvar_esp.match(localvar) if match: - if localvar == self.TOP_OF_STACK: # for pushl and popl, by + if localvar == self.TOP_OF_STACK_MINUS_WORD: + # for pushl and popl, by hint = None # default ebp addressing is else: # a bit nicer hint = 'esp' @@ -521,9 +527,8 @@ target = match.group("target") if target == self.ESP: # only for andl $-16, %esp used to align the stack in main(). - # The exact amount of adjutment is not known yet, so we use - # an odd-valued estimate to make sure the real value is not used - # elsewhere by the FunctionGcRootTracker. + # main() should not be seen at all. But on e.g. MSVC we see + # the instruction somewhere else too... return InsnCannotFollowEsp() else: return self.binary_insn(line) @@ -588,10 +593,12 @@ def _visit_push(self, line): match = self.r_unaryinsn.match(line) source = match.group(1) - return [InsnStackAdjust(-self.WORD)] + self.insns_for_copy(source, self.TOP_OF_STACK) + return self.insns_for_copy(source, self.TOP_OF_STACK_MINUS_WORD) + \ + [InsnStackAdjust(-self.WORD)] def _visit_pop(self, target): - return self.insns_for_copy(self.TOP_OF_STACK, target) + [InsnStackAdjust(+self.WORD)] + return [InsnStackAdjust(+self.WORD)] + \ + self.insns_for_copy(self.TOP_OF_STACK_MINUS_WORD, target) def _visit_prologue(self): # for the prologue of functions that use %ebp as frame pointer @@ -983,15 +990,15 @@ OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' LABEL = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)' OFFSET_LABELS = 2**30 - TOP_OF_STACK = '0(%esp)' + TOP_OF_STACK_MINUS_WORD = '-4(%esp)' r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$") r_functionend = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$") - LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|\d*[(]%esp[)]" + LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|-?\d*[(]%esp[)]" LOCALVARFP = LOCALVAR + r"|-?\d*[(]%ebp[)]" r_localvarnofp = re.compile(LOCALVAR) r_localvarfp = re.compile(LOCALVARFP) - r_localvar_esp = re.compile(r"(\d*)[(]%esp[)]") + r_localvar_esp = re.compile(r"(-?\d*)[(]%esp[)]") r_localvar_ebp = re.compile(r"(-?\d*)[(]%ebp[)]") r_rel_label = re.compile(r"(\d+):\s*$") @@ -1044,7 +1051,7 @@ OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' LABEL = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)' OFFSET_LABELS = 2**30 - TOP_OF_STACK = '0(%rsp)' + TOP_OF_STACK_MINUS_WORD = '-8(%rsp)' r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$") r_functionend = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$") @@ -1140,7 +1147,7 @@ CALLEE_SAVE_REGISTERS = ['ebx', 'esi', 'edi', 'ebp'] REG2LOC = dict((_reg, LOC_REG | ((_i+1)<<2)) for _i, _reg in enumerate(CALLEE_SAVE_REGISTERS)) - TOP_OF_STACK = 'DWORD PTR [esp]' + TOP_OF_STACK_MINUS_WORD = 'DWORD PTR [esp-4]' OPERAND = r'(?:(:?WORD|DWORD|BYTE) PTR |OFFSET )?[_\w?:@$]*(?:[-+0-9]+)?(:?\[[-+*\w0-9]+\])?' LABEL = r'([a-zA-Z_$@.][a-zA-Z0-9_$@.]*)' @@ -1170,7 +1177,7 @@ r_gcroot_marker = re.compile(r"$1") # never matches r_gcroot_marker_var = re.compile(r"DWORD PTR .+_constant_always_one_.+pypy_asm_gcroot") r_gcnocollect_marker = re.compile(r"\spypy_asm_gc_nocollect\(("+OPERAND+")\);") - r_bottom_marker = re.compile(r"; .+\tpypy_asm_stack_bottom\(\);") + r_bottom_marker = re.compile(r"; .+\spypy_asm_stack_bottom\(\);") FUNCTIONS_NOT_RETURNING = { '__exit': None, @@ -1323,12 +1330,11 @@ self.verbose = verbose self.shuffle = shuffle self.gcmaptable = [] - self.seen_main = False - def process(self, iterlines, newfile, entrypoint='main', filename='?'): + def process(self, iterlines, newfile, filename='?'): for in_function, lines in self.find_functions(iterlines): if in_function: - tracker = self.process_function(lines, entrypoint, filename) + tracker = self.process_function(lines, filename) lines = tracker.lines self.write_newfile(newfile, lines, filename.split('.')[0]) if self.verbose == 1: @@ -1337,11 +1343,9 @@ def write_newfile(self, newfile, lines, grist): newfile.writelines(lines) - def process_function(self, lines, entrypoint, filename): + def process_function(self, lines, filename): tracker = self.FunctionGcRootTracker( lines, filetag=getidentifier(filename)) - is_main = tracker.funcname == entrypoint - tracker.is_stack_bottom = is_main if self.verbose == 1: sys.stderr.write('.') elif self.verbose > 1: @@ -1356,7 +1360,6 @@ self.gcmaptable[:0] = table else: self.gcmaptable.extend(table) - self.seen_main |= is_main return tracker class ElfAssemblerParser(AssemblerParser): @@ -1432,11 +1435,6 @@ if functionlines: yield in_function, functionlines - def process_function(self, lines, entrypoint, filename): - entrypoint = '_' + entrypoint - return super(DarwinAssemblerParser, self).process_function( - lines, entrypoint, filename) - class DarwinAssemblerParser64(DarwinAssemblerParser): format = "darwin64" FunctionGcRootTracker = DarwinFunctionGcRootTracker64 @@ -1494,11 +1492,6 @@ "missed the end of the previous function") yield False, functionlines - def process_function(self, lines, entrypoint, filename): - entrypoint = '_' + entrypoint - return super(MsvcAssemblerParser, self).process_function( - lines, entrypoint, filename) - def write_newfile(self, newfile, lines, grist): newlines = [] for line in lines: @@ -1560,24 +1553,21 @@ self.shuffle = shuffle # to debug the sorting logic in asmgcroot.py self.format = format self.gcmaptable = [] - self.seen_main = False def dump_raw_table(self, output): - print >> output, "seen_main = %d" % (self.seen_main,) + print 'raw table' for entry in self.gcmaptable: print >> output, entry def reload_raw_table(self, input): firstline = input.readline() - assert firstline.startswith("seen_main = ") - self.seen_main |= bool(int(firstline[len("seen_main = "):].strip())) + assert firstline == 'raw table\n' for line in input: entry = eval(line) assert type(entry) is tuple self.gcmaptable.append(entry) def dump(self, output): - assert self.seen_main def _globalname(name, disp=""): return tracker_cls.function_names_prefix + name @@ -1649,8 +1639,8 @@ s = """\ /* See description in asmgcroot.py */ .cfi_startproc - movq\t%rdi, %rdx\t/* 1st argument, which is the callback */ - movq\t%rsi, %rcx\t/* 2nd argument, which is gcrootanchor */ + /* %rdi is the 1st argument, which is the callback */ + /* %rsi is the 2nd argument, which is gcrootanchor */ movq\t%rsp, %rax\t/* my frame top address */ pushq\t%rax\t\t/* ASM_FRAMEDATA[8] */ pushq\t%rbp\t\t/* ASM_FRAMEDATA[7] */ @@ -1663,15 +1653,15 @@ /* Add this ASM_FRAMEDATA to the front of the circular linked */ /* list. Let's call it 'self'. */ - movq\t8(%rcx), %rax\t/* next = gcrootanchor->next */ + movq\t8(%rsi), %rax\t/* next = gcrootanchor->next */ pushq\t%rax\t\t\t\t/* self->next = next */ - pushq\t%rcx\t\t\t/* self->prev = gcrootanchor */ - movq\t%rsp, 8(%rcx)\t/* gcrootanchor->next = self */ + pushq\t%rsi\t\t\t/* self->prev = gcrootanchor */ + movq\t%rsp, 8(%rsi)\t/* gcrootanchor->next = self */ movq\t%rsp, 0(%rax)\t\t\t/* next->prev = self */ .cfi_def_cfa_offset 80\t/* 9 pushes + the retaddr = 80 bytes */ /* note: the Mac OS X 16 bytes aligment must be respected. */ - call\t*%rdx\t\t/* invoke the callback */ + call\t*%rdi\t\t/* invoke the callback */ /* Detach this ASM_FRAMEDATA from the circular linked list */ popq\t%rsi\t\t/* prev = self->prev */ @@ -1688,7 +1678,7 @@ popq\t%rcx\t\t/* ignored ASM_FRAMEDATA[8] */ /* the return value is the one of the 'call' above, */ - /* because %rax (and possibly %rdx) are unmodified */ + /* because %rax is unmodified */ ret .cfi_endproc """ @@ -1835,11 +1825,11 @@ """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) - def process(self, iterlines, newfile, entrypoint='main', filename='?'): + def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) for in_function, lines in parser.find_functions(iterlines): if in_function: - tracker = parser.process_function(lines, entrypoint, filename) + tracker = parser.process_function(lines, filename) lines = tracker.lines parser.write_newfile(newfile, lines, filename.split('.')[0]) if self.verbose == 1: @@ -1848,7 +1838,6 @@ self.gcmaptable[:0] = parser.gcmaptable else: self.gcmaptable.extend(parser.gcmaptable) - self.seen_main |= parser.seen_main class UnrecognizedOperation(Exception): @@ -1915,7 +1904,6 @@ format = 'elf64' else: format = 'elf' - entrypoint = 'main' while len(sys.argv) > 1: if sys.argv[1] == '-v': del sys.argv[1] @@ -1929,9 +1917,9 @@ elif sys.argv[1].startswith('-f'): format = sys.argv[1][2:] del sys.argv[1] - elif sys.argv[1].startswith('-m'): - entrypoint = sys.argv[1][2:] - del sys.argv[1] + elif sys.argv[1].startswith('-'): + print >> sys.stderr, "unrecognized option:", sys.argv[1] + sys.exit(1) else: break tracker = GcRootTracker(verbose=verbose, shuffle=shuffle, format=format) @@ -1940,7 +1928,7 @@ firstline = f.readline() f.seek(0) assert firstline, "file %r is empty!" % (fn,) - if firstline.startswith('seen_main = '): + if firstline == 'raw table\n': tracker.reload_raw_table(f) f.close() else: @@ -1948,7 +1936,7 @@ lblfn = fn[:-2] + '.lbl.s' g = open(lblfn, 'w') try: - tracker.process(f, g, entrypoint=entrypoint, filename=fn) + tracker.process(f, g, filename=fn) except: g.close() os.unlink(lblfn) diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -570,7 +570,10 @@ mk.definition('ASMFILES', sfiles) mk.definition('ASMLBLFILES', lblsfiles) mk.definition('GCMAPFILES', gcmapfiles) - mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') if self.config.translation.shared: mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup") @@ -602,7 +605,7 @@ 'cmd /c $(MASM) /nologo /Cx /Cp /Zm /coff /Fo$@ /c $< $(INCLUDEDIRS)') mk.rule('.c.gcmap', '', ['$(CC) /nologo $(ASM_CFLAGS) /c /FAs /Fa$*.s $< $(INCLUDEDIRS)', - 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -m$(PYPY_MAIN_FUNCTION) -t $*.s > $@'] + 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -t $*.s > $@'] ) mk.rule('gcmaptable.c', '$(GCMAPFILES)', 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@') @@ -613,7 +616,7 @@ mk.rule('%.lbl.s %.gcmap', '%.s', [python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py ' - '-m$(PYPY_MAIN_FUNCTION) -t $< > $*.gctmp', + '-t $< > $*.gctmp', 'mv $*.gctmp $*.gcmap']) mk.rule('gcmaptable.s', '$(GCMAPFILES)', [python + @@ -623,7 +626,10 @@ mk.rule('.PRECIOUS', '%.s', "# don't remove .s files if Ctrl-C'ed") else: - mk.definition('DEBUGFLAGS', '-O1 -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O1 -g') mk.write() #self.translator.platform, # , @@ -900,8 +906,9 @@ print >> f, '}' def commondefs(defines): - from pypy.rlib.rarithmetic import LONG_BIT + from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT defines['PYPY_LONG_BIT'] = LONG_BIT + defines['PYPY_LONGLONG_BIT'] = LONGLONG_BIT def add_extra_files(eci): srcdir = py.path.local(autopath.pypydir).join('translator', 'c', 'src') diff --git a/pypy/translator/c/node.py b/pypy/translator/c/node.py --- a/pypy/translator/c/node.py +++ b/pypy/translator/c/node.py @@ -1031,7 +1031,7 @@ if (issubclass(value, BaseException) and value.__module__ == 'exceptions'): return 'PyExc_' + value.__name__ - if value is py.code._AssertionError: + if issubclass(value, AssertionError): return 'PyExc_AssertionError' if value is _StackOverflow: return 'PyExc_RuntimeError' diff --git a/pypy/translator/c/src/cjkcodecs/multibytecodec.c b/pypy/translator/c/src/cjkcodecs/multibytecodec.c --- a/pypy/translator/c/src/cjkcodecs/multibytecodec.c +++ b/pypy/translator/c/src/cjkcodecs/multibytecodec.c @@ -1,4 +1,5 @@ #include +#include #include "src/cjkcodecs/multibytecodec.h" @@ -93,6 +94,22 @@ return d->inbuf - d->inbuf_start; } +Py_ssize_t pypy_cjk_dec_replace_on_error(struct pypy_cjk_dec_s* d, + Py_UNICODE *newbuf, Py_ssize_t newlen, + Py_ssize_t in_offset) +{ + if (newlen > 0) + { + if (d->outbuf + newlen > d->outbuf_end) + if (expand_decodebuffer(d, newlen) == -1) + return MBERR_NOMEMORY; + memcpy(d->outbuf, newbuf, newlen * sizeof(Py_UNICODE)); + d->outbuf += newlen; + } + d->inbuf = d->inbuf_start + in_offset; + return 0; +} + /************************************************************/ struct pypy_cjk_enc_s *pypy_cjk_enc_init(const MultibyteCodec *codec, @@ -209,3 +226,19 @@ { return d->inbuf - d->inbuf_start; } + +Py_ssize_t pypy_cjk_enc_replace_on_error(struct pypy_cjk_enc_s* d, + char *newbuf, Py_ssize_t newlen, + Py_ssize_t in_offset) +{ + if (newlen > 0) + { + if (d->outbuf + newlen > d->outbuf_end) + if (expand_encodebuffer(d, newlen) == -1) + return MBERR_NOMEMORY; + memcpy(d->outbuf, newbuf, newlen); + d->outbuf += newlen; + } + d->inbuf = d->inbuf_start + in_offset; + return 0; +} diff --git a/pypy/translator/c/src/cjkcodecs/multibytecodec.h b/pypy/translator/c/src/cjkcodecs/multibytecodec.h --- a/pypy/translator/c/src/cjkcodecs/multibytecodec.h +++ b/pypy/translator/c/src/cjkcodecs/multibytecodec.h @@ -102,6 +102,8 @@ Py_ssize_t pypy_cjk_dec_outlen(struct pypy_cjk_dec_s *); Py_ssize_t pypy_cjk_dec_inbuf_remaining(struct pypy_cjk_dec_s *d); Py_ssize_t pypy_cjk_dec_inbuf_consumed(struct pypy_cjk_dec_s* d); +Py_ssize_t pypy_cjk_dec_replace_on_error(struct pypy_cjk_dec_s* d, + Py_UNICODE *, Py_ssize_t, Py_ssize_t); struct pypy_cjk_enc_s { const MultibyteCodec *codec; @@ -119,6 +121,8 @@ Py_ssize_t pypy_cjk_enc_outlen(struct pypy_cjk_enc_s *); Py_ssize_t pypy_cjk_enc_inbuf_remaining(struct pypy_cjk_enc_s *d); Py_ssize_t pypy_cjk_enc_inbuf_consumed(struct pypy_cjk_enc_s* d); +Py_ssize_t pypy_cjk_enc_replace_on_error(struct pypy_cjk_enc_s* d, + char *, Py_ssize_t, Py_ssize_t); /* list of codecs defined in the .c files */ diff --git a/pypy/translator/c/src/debug_print.c b/pypy/translator/c/src/debug_print.c --- a/pypy/translator/c/src/debug_print.c +++ b/pypy/translator/c/src/debug_print.c @@ -6,6 +6,8 @@ #include #ifndef _WIN32 #include +#include +#include #else #define WIN32_LEAN_AND_MEAN #include diff --git a/pypy/translator/c/src/debug_print.h b/pypy/translator/c/src/debug_print.h --- a/pypy/translator/c/src/debug_print.h +++ b/pypy/translator/c/src/debug_print.h @@ -53,8 +53,6 @@ # ifdef _WIN32 # define READ_TIMESTAMP(val) QueryPerformanceCounter((LARGE_INTEGER*)&(val)) # else -# include -# include long long pypy_read_timestamp(); diff --git a/pypy/translator/c/src/debug_traceback.h b/pypy/translator/c/src/debug_traceback.h --- a/pypy/translator/c/src/debug_traceback.h +++ b/pypy/translator/c/src/debug_traceback.h @@ -21,7 +21,11 @@ line to the f:17/KeyError line. */ -#define PYPY_DEBUG_TRACEBACK_DEPTH 128 /* a power of two */ +#ifdef RPY_LL_ASSERT +# define PYPY_DEBUG_TRACEBACK_DEPTH 8192 /* a power of two */ +#else +# define PYPY_DEBUG_TRACEBACK_DEPTH 128 /* a power of two */ +#endif #define PYPYDTPOS_RERAISE ((struct pypydtpos_s *) -1) #define PYPYDTSTORE(loc, etype) \ diff --git a/pypy/translator/c/src/int.h b/pypy/translator/c/src/int.h --- a/pypy/translator/c/src/int.h +++ b/pypy/translator/c/src/int.h @@ -73,15 +73,28 @@ /* NB. shifting has same limitations as C: the shift count must be >= 0 and < LONG_BITS. */ -#define OP_INT_RSHIFT(x,y,r) r = Py_ARITHMETIC_RIGHT_SHIFT(long, x, y) -#define OP_UINT_RSHIFT(x,y,r) r = (x) >> (y) -#define OP_LLONG_RSHIFT(x,y,r) r = Py_ARITHMETIC_RIGHT_SHIFT(PY_LONG_LONG,x,y) -#define OP_ULLONG_RSHIFT(x,y,r) r = (x) >> (y) +#define CHECK_SHIFT_RANGE(y, bits) RPyAssert(y >= 0 && y < bits, \ + "The shift count is outside of the supported range") -#define OP_INT_LSHIFT(x,y,r) r = (x) << (y) -#define OP_UINT_LSHIFT(x,y,r) r = (x) << (y) -#define OP_LLONG_LSHIFT(x,y,r) r = (x) << (y) -#define OP_ULLONG_LSHIFT(x,y,r) r = (x) << (y) + +#define OP_INT_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = Py_ARITHMETIC_RIGHT_SHIFT(long, x, (y)) +#define OP_UINT_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = (x) >> (y) +#define OP_LLONG_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = Py_ARITHMETIC_RIGHT_SHIFT(PY_LONG_LONG,x, (y)) +#define OP_ULLONG_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = (x) >> (y) + + +#define OP_INT_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = (x) << (y) +#define OP_UINT_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = (x) << (y) +#define OP_LLONG_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = (x) << (y) +#define OP_ULLONG_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = (x) << (y) #define OP_INT_LSHIFT_OVF(x,y,r) \ OP_INT_LSHIFT(x,y,r); \ diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h --- a/pypy/translator/c/src/main.h +++ b/pypy/translator/c/src/main.h @@ -23,12 +23,19 @@ #include "src/winstuff.c" #endif -int PYPY_MAIN_FUNCTION(int argc, char *argv[]) +#ifdef __GNUC__ +/* Hack to prevent this function from being inlined. Helps asmgcc + because the main() function has often a different prologue/epilogue. */ +int pypy_main_function(int argc, char *argv[]) __attribute__((__noinline__)); +#endif + +int pypy_main_function(int argc, char *argv[]) { char *errmsg; int i, exitcode; RPyListOfString *list; + pypy_asm_stack_bottom(); instrument_setup(); if (sizeof(void*) != SIZEOF_LONG) { @@ -72,6 +79,12 @@ fprintf(stderr, "Fatal error during initialization: %s\n", errmsg); #endif abort(); + return 1; +} + +int PYPY_MAIN_FUNCTION(int argc, char *argv[]) +{ + return pypy_main_function(argc, argv); } #endif /* PYPY_NOT_MAIN_FILE */ diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h --- a/pypy/translator/c/src/mem.h +++ b/pypy/translator/c/src/mem.h @@ -222,6 +222,15 @@ #endif /* USING_BOEHM_GC */ + +#ifdef USING_NO_GC_AT_ALL +#define OP_BOEHM_ZERO_MALLOC(size, r, restype, is_atomic, is_varsize) \ + r = (restype) calloc(1, size); +#define OP_BOEHM_DISAPPEARING_LINK(link, obj, r) /* nothing */ +#define OP_GC__DISABLE_FINALIZERS(r) /* nothing */ +#define OP_GC__ENABLE_FINALIZERS(r) /* nothing */ +#endif + /************************************************************/ /* weakref support */ diff --git a/pypy/translator/c/src/stack.h b/pypy/translator/c/src/stack.h --- a/pypy/translator/c/src/stack.h +++ b/pypy/translator/c/src/stack.h @@ -11,15 +11,22 @@ * It is needed to have RPyThreadStaticTLS, too. */ #include "thread.h" -extern char *_LLstacktoobig_stack_start; +extern char *_LLstacktoobig_stack_end; +extern long _LLstacktoobig_stack_length; +extern char _LLstacktoobig_report_error; void LL_stack_unwind(void); char LL_stack_too_big_slowpath(long); /* returns 0 (ok) or 1 (too big) */ +void LL_stack_set_length_fraction(double); /* some macros referenced from pypy.rlib.rstack */ -#define LL_stack_get_start() ((long)_LLstacktoobig_stack_start) -#define LL_stack_get_length() MAX_STACK_SIZE -#define LL_stack_get_start_adr() ((long)&_LLstacktoobig_stack_start) /* JIT */ +#define LL_stack_get_end() ((long)_LLstacktoobig_stack_end) +#define LL_stack_get_length() _LLstacktoobig_stack_length +#define LL_stack_get_end_adr() ((long)&_LLstacktoobig_stack_end) /* JIT */ +#define LL_stack_get_length_adr() ((long)&_LLstacktoobig_stack_length)/* JIT */ + +#define LL_stack_criticalcode_start() (_LLstacktoobig_report_error = 0) +#define LL_stack_criticalcode_stop() (_LLstacktoobig_report_error = 1) #ifdef __GNUC__ @@ -32,93 +39,67 @@ #ifndef PYPY_NOT_MAIN_FILE #include -#ifndef PYPY_NOINLINE -# if defined __GNUC__ -# define PYPY_NOINLINE __attribute__((noinline)) -# else -// add hints for other compilers here ... -# define PYPY_NOINLINE -# endif -#endif +/* the current stack is in the interval [end-length:end]. We assume a + stack that grows downward here. */ +char *_LLstacktoobig_stack_end = NULL; +long _LLstacktoobig_stack_length = MAX_STACK_SIZE; +char _LLstacktoobig_report_error = 1; +static RPyThreadStaticTLS end_tls_key; -long PYPY_NOINLINE _LL_stack_growing_direction(char *parent) +void LL_stack_set_length_fraction(double fraction) { - char local; - if (parent == NULL) - return _LL_stack_growing_direction(&local); - else - return &local - parent; + _LLstacktoobig_stack_length = (long)(MAX_STACK_SIZE * fraction); } -char *_LLstacktoobig_stack_start = NULL; -int stack_direction = 0; -RPyThreadStaticTLS start_tls_key; - char LL_stack_too_big_slowpath(long current) { - long diff; + long diff, max_stack_size; char *baseptr, *curptr = (char*)current; - /* The stack_start variable is updated to match the current value + /* The stack_end variable is updated to match the current value if it is still 0 or if we later find a 'curptr' position - that is below it. The real stack_start pointer is stored in + that is above it. The real stack_end pointer is stored in thread-local storage, but we try to minimize its overhead by - keeping a local copy in _LLstacktoobig_stack_start. */ + keeping a local copy in _LLstacktoobig_stack_end. */ - if (stack_direction == 0) { + if (_LLstacktoobig_stack_end == NULL) { /* not initialized */ /* XXX We assume that initialization is performed early, when there is still only one thread running. This allows us to ignore race conditions here */ - char *errmsg = RPyThreadStaticTLS_Create(&start_tls_key); + char *errmsg = RPyThreadStaticTLS_Create(&end_tls_key); if (errmsg) { /* XXX should we exit the process? */ fprintf(stderr, "Internal PyPy error: %s\n", errmsg); return 1; } - if (_LL_stack_growing_direction(NULL) > 0) - stack_direction = +1; - else - stack_direction = -1; } - baseptr = (char *) RPyThreadStaticTLS_Get(start_tls_key); - if (baseptr != NULL) { - diff = curptr - baseptr; - if (((unsigned long)diff) < (unsigned long)MAX_STACK_SIZE) { + baseptr = (char *) RPyThreadStaticTLS_Get(end_tls_key); + max_stack_size = _LLstacktoobig_stack_length; + if (baseptr == NULL) { + /* first time we see this thread */ + } + else { + diff = baseptr - curptr; + if (((unsigned long)diff) <= (unsigned long)max_stack_size) { /* within bounds, probably just had a thread switch */ - _LLstacktoobig_stack_start = baseptr; + _LLstacktoobig_stack_end = baseptr; return 0; } - - if (stack_direction > 0) { - if (diff < 0 && diff > -MAX_STACK_SIZE) - ; /* stack underflow */ - else - return 1; /* stack overflow (probably) */ + if (((unsigned long)-diff) <= (unsigned long)max_stack_size) { + /* stack underflowed: the initial estimation of + the stack base must be revised */ } - else { - if (diff >= MAX_STACK_SIZE && diff < 2*MAX_STACK_SIZE) - ; /* stack underflow */ - else - return 1; /* stack overflow (probably) */ + else { /* stack overflow (probably) */ + return _LLstacktoobig_report_error; } - /* else we underflowed the stack, which means that - the initial estimation of the stack base must - be revised */ } /* update the stack base pointer to the current value */ - if (stack_direction > 0) { - /* the valid range is [curptr:curptr+MAX_STACK_SIZE] */ - baseptr = curptr; - } - else { - /* the valid range is [curptr-MAX_STACK_SIZE+1:curptr+1] */ - baseptr = curptr - MAX_STACK_SIZE + 1; - } - RPyThreadStaticTLS_Set(start_tls_key, baseptr); - _LLstacktoobig_stack_start = baseptr; + baseptr = curptr; + RPyThreadStaticTLS_Set(end_tls_key, baseptr); + _LLstacktoobig_stack_end = baseptr; return 0; } diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -1117,6 +1117,7 @@ S = lltype.GcStruct('S', ('u', lltype.Ptr(U))) A = lltype.GcArray(lltype.Ptr(S)) filename = self.filename_dump_typeids_z + open_flags = os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0) def fn(): s = lltype.malloc(S) @@ -1128,7 +1129,7 @@ # p = rgc.get_typeids_z() s = ''.join([p[i] for i in range(len(p))]) - fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0666) + fd = os.open(filename, open_flags, 0666) os.write(fd, s) os.close(fd) return 0 @@ -1137,7 +1138,7 @@ def test_write_typeids_z(self): self.run("write_typeids_z") - f = open(self.filename_dump_typeids_z) + f = open(self.filename_dump_typeids_z, 'rb') data_z = f.read() f.close() import zlib diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -596,6 +596,42 @@ # The traceback stops at f() because it's the first function that # captures the AssertionError, which makes the program abort. + def test_int_lshift_too_large(self): + from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT + def entry_point(argv): + a = int(argv[1]) + b = int(argv[2]) + print a << b + return 0 + + t, cbuilder = self.compile(entry_point, debug=True) + out = cbuilder.cmdexec("10 2", expect_crash=False) + assert out.strip() == str(10 << 2) + cases = [-4, LONG_BIT, LONGLONG_BIT] + for x in cases: + out, err = cbuilder.cmdexec("%s %s" % (1, x), expect_crash=True) + lines = err.strip() + assert 'The shift count is outside of the supported range' in lines + + def test_llong_rshift_too_large(self): + from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT + def entry_point(argv): + a = r_longlong(int(argv[1])) + b = r_longlong(int(argv[2])) + print a >> b + return 0 + + t, cbuilder = self.compile(entry_point, debug=True) + out = cbuilder.cmdexec("10 2", expect_crash=False) + assert out.strip() == str(10 >> 2) + out = cbuilder.cmdexec("%s %s" % (-42, LONGLONG_BIT - 1), expect_crash=False) + assert out.strip() == '-1' + cases = [-4, LONGLONG_BIT] + for x in cases: + out, err = cbuilder.cmdexec("%s %s" % (1, x), expect_crash=True) + lines = err.strip() + assert 'The shift count is outside of the supported range' in lines + def test_ll_assert_error_debug(self): def entry_point(argv): ll_assert(len(argv) != 1, "foobar") @@ -689,6 +725,78 @@ out = cbuilder.cmdexec("") assert out.strip() == "hi!" + def test_set_length_fraction(self): + # check for pypy.rlib.rstack._stack_set_length_fraction() + from pypy.rlib.rstack import _stack_set_length_fraction + from pypy.rlib.rstackovf import StackOverflow + class A: + n = 0 + glob = A() + def f(n): + glob.n += 1 + if n <= 0: + return 42 + return f(n+1) + def entry_point(argv): + _stack_set_length_fraction(0.1) + try: + return f(1) + except StackOverflow: + glob.n = 0 + _stack_set_length_fraction(float(argv[1])) + try: + return f(1) + except StackOverflow: + print glob.n + return 0 + t, cbuilder = self.compile(entry_point, stackcheck=True) + counts = {} + for fraction in [0.1, 0.4, 1.0]: + out = cbuilder.cmdexec(str(fraction)) + print 'counts[%s]: %r' % (fraction, out) + counts[fraction] = int(out.strip()) + # + assert counts[1.0] >= 1000 + # ^^^ should actually be much more than 1000 for this small test + assert counts[0.1] < counts[0.4] / 3 + assert counts[0.4] < counts[1.0] / 2 + assert counts[0.1] > counts[0.4] / 7 + assert counts[0.4] > counts[1.0] / 4 + + def test_stack_criticalcode(self): + # check for pypy.rlib.rstack._stack_criticalcode_start/stop() + from pypy.rlib.rstack import _stack_criticalcode_start + from pypy.rlib.rstack import _stack_criticalcode_stop + from pypy.rlib.rstackovf import StackOverflow + class A: + pass + glob = A() + def f(n): + if n <= 0: + return 42 + try: + return f(n+1) + except StackOverflow: + if glob.caught: + print 'Oups! already caught!' + glob.caught = True + _stack_criticalcode_start() + critical(100) # recurse another 100 times here + _stack_criticalcode_stop() + return 789 + def critical(n): + if n > 0: + n = critical(n - 1) + return n - 42 + def entry_point(argv): + glob.caught = False + print f(1) + return 0 + t, cbuilder = self.compile(entry_point, stackcheck=True) + out = cbuilder.cmdexec('') + assert out.strip() == '789' + + class TestMaemo(TestStandalone): def setup_class(cls): py.test.skip("TestMaemo: tests skipped for now") diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py --- a/pypy/translator/cli/opcodes.py +++ b/pypy/translator/cli/opcodes.py @@ -77,7 +77,6 @@ 'cast_ptr_to_weakadr': [PushAllArgs, 'newobj instance void class %s::.ctor(object)' % WEAKREF], 'gc__collect': 'call void class [mscorlib]System.GC::Collect()', 'gc_set_max_heap_size': Ignore, - 'resume_point': Ignore, 'debug_assert': Ignore, 'debug_start_traceback': Ignore, 'debug_record_traceback': Ignore, @@ -85,6 +84,8 @@ 'debug_reraise_traceback': Ignore, 'debug_print_traceback': Ignore, 'debug_print': [DebugPrint], + 'debug_flush': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_FLUSH()'], + 'debug_offset': [PushAllArgs, 'call int32 [pypylib]pypy.runtime.DebugPrint::DEBUG_OFFSET()'], 'debug_start': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_START(string)'], 'debug_stop': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_STOP(string)'], 'have_debug_prints': [PushAllArgs, 'call bool [pypylib]pypy.runtime.DebugPrint::HAVE_DEBUG_PRINTS()'], diff --git a/pypy/translator/cli/src/debug.cs b/pypy/translator/cli/src/debug.cs --- a/pypy/translator/cli/src/debug.cs +++ b/pypy/translator/cli/src/debug.cs @@ -38,6 +38,20 @@ return false; } + public static void DEBUG_FLUSH() + { + if (debug_file != null) + debug_file.Flush(); + } + + public static int DEBUG_OFFSET() + { + StreamWriter sw = debug_file as StreamWriter; + if (sw == null) + return -1; + return (int)sw.BaseStream.Position; // XXX: the cast might be incorrect + } + public static bool HAVE_DEBUG_PRINTS() { if ((have_debug_prints & 1) != 0) { diff --git a/pypy/translator/driver.py b/pypy/translator/driver.py --- a/pypy/translator/driver.py +++ b/pypy/translator/driver.py @@ -559,6 +559,7 @@ shutil.copy(str(soname), str(newsoname)) self.log.info("copied: %s" % (newsoname,)) self.c_entryp = newexename + self.log.info('usession directory: %s' % (udir,)) self.log.info("created: %s" % (self.c_entryp,)) def task_compile_c(self): diff --git a/pypy/translator/goal/targetnumpystandalone.py b/pypy/translator/goal/targetnumpystandalone.py --- a/pypy/translator/goal/targetnumpystandalone.py +++ b/pypy/translator/goal/targetnumpystandalone.py @@ -10,46 +10,32 @@ """ import time -from pypy.module.micronumpy.numarray import SingleDimArray, Code, compute +from pypy.module.micronumpy.compile import numpy_compile from pypy.jit.codewriter.policy import JitPolicy - -def create_array(size): - a = SingleDimArray(size) - for i in range(size): - a.storage[i] = float(i % 10) - return a +from pypy.rpython.annlowlevel import hlstr def entry_point(argv): if len(argv) != 3: print __doc__ return 1 - bytecode = argv[1] - for b in bytecode: - if b not in 'alf': - print "WRONG BYTECODE" - print __doc__ - return 2 try: size = int(argv[2]) except ValueError: print "INVALID LITERAL FOR INT:", argv[2] print __doc__ return 3 - no_arrays = bytecode.count('l') - no_floats = bytecode.count('f') - arrays = [] - floats = [] - for i in range(no_arrays): - arrays.append(create_array(size)) - for i in range(no_floats): - floats.append(float(i + 1)) - code = Code(bytecode, arrays, floats) t0 = time.time() - compute(code) - print "bytecode:", bytecode, "size:", size + main(argv[0], size) + print "bytecode:", argv[0], "size:", size print "took:", time.time() - t0 return 0 +def main(bc, size): + if not isinstance(bc, str): + bc = hlstr(bc) # for tests + a = numpy_compile(bc, size) + a = a.compute() + def target(*args): return entry_point, None diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py --- a/pypy/translator/goal/targetpypystandalone.py +++ b/pypy/translator/goal/targetpypystandalone.py @@ -105,7 +105,8 @@ return parser def handle_config(self, config, translateconfig): - if translateconfig._cfgimpl_value_owners['opt'] == 'default': + if (not translateconfig.help and + translateconfig._cfgimpl_value_owners['opt'] == 'default'): raise Exception("You have to specify the --opt level.\n" "Try --opt=2 or --opt=jit, or equivalently -O2 or -Ojit .") self.translateconfig = translateconfig diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -103,6 +103,8 @@ specname = os.path.splitext(os.path.basename(targetspec))[0] sys.path.insert(0, os.path.dirname(targetspec)) mod = __import__(specname) + if 'target' not in mod.__dict__: + raise Exception("file %r is not a valid targetxxx.py." % (targetspec,)) return mod.__dict__ def parse_options_and_load_target(): @@ -149,6 +151,9 @@ log.ERROR("Could not find target %r" % (arg, )) sys.exit(1) + # apply the platform settings + set_platform(config) + targetspec = translateconfig.targetspec targetspec_dic = load_target(targetspec) @@ -164,9 +169,6 @@ existing_config=config, translating=True) - # apply the platform settings - set_platform(config) - # apply the optimization level settings set_opt_level(config, translateconfig.opt) diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -95,7 +95,6 @@ 'gc__collect': jvm.SYSTEMGC, 'gc_set_max_heap_size': Ignore, - 'resume_point': Ignore, 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py --- a/pypy/translator/oosupport/test_template/operations.py +++ b/pypy/translator/oosupport/test_template/operations.py @@ -107,12 +107,6 @@ return res assert self.interpret(fn, [sys.maxint, 2]) == 1 - def test_ignore_resume_point(self): - def fn(x): - rstack.resume_point('hello world', x) - return x - assert self.interpret(fn, [42]) == 42 - def test_rshift(self): def fn(x, y): return x >> y diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py --- a/pypy/translator/platform/__init__.py +++ b/pypy/translator/platform/__init__.py @@ -38,6 +38,7 @@ c_environ = None relevant_environ = () + log_errors = True so_prefixes = ('',) @@ -120,11 +121,12 @@ if returncode != 0: errorfile = outname.new(ext='errors') errorfile.write(stderr, 'wb') - stderrlines = stderr.splitlines() - for line in stderrlines: - log.Error(line) - # ^^^ don't use ERROR, because it might actually be fine. - # Also, ERROR confuses lib-python/conftest.py. + if self.log_errors: + stderrlines = stderr.splitlines() + for line in stderrlines: + log.Error(line) + # ^^^ don't use ERROR, because it might actually be fine. + # Also, ERROR confuses lib-python/conftest.py. raise CompilationError(stdout, stderr) else: for line in stderr.splitlines(): diff --git a/pypy/translator/platform/darwin.py b/pypy/translator/platform/darwin.py --- a/pypy/translator/platform/darwin.py +++ b/pypy/translator/platform/darwin.py @@ -68,12 +68,10 @@ class Darwin_i386(Darwin): name = "darwin_i386" - link_flags = ('-arch', 'i386', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'i386') + cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer') class Darwin_x86_64(Darwin): name = "darwin_x86_64" - link_flags = ('-arch', 'x86_64', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'x86_64') + cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer') diff --git a/pypy/translator/platform/posix.py b/pypy/translator/platform/posix.py --- a/pypy/translator/platform/posix.py +++ b/pypy/translator/platform/posix.py @@ -129,7 +129,9 @@ m.cfiles = rel_cfiles rel_includedirs = [pypyrel(incldir) for incldir in - self._preprocess_include_dirs(eci.include_dirs)] + self.preprocess_include_dirs(eci.include_dirs)] + rel_libdirs = [pypyrel(libdir) for libdir in + self.preprocess_library_dirs(eci.library_dirs)] m.comment('automatically generated makefile') definitions = [ @@ -139,7 +141,7 @@ ('SOURCES', rel_cfiles), ('OBJECTS', rel_ofiles), ('LIBS', self._libs(eci.libraries)), - ('LIBDIRS', self._libdirs(eci.library_dirs)), + ('LIBDIRS', self._libdirs(rel_libdirs)), ('INCLUDEDIRS', self._includedirs(rel_includedirs)), ('CFLAGS', cflags), ('CFLAGSEXTRA', list(eci.compile_extra)), diff --git a/pypy/translator/platform/test/test_posix.py b/pypy/translator/platform/test/test_posix.py --- a/pypy/translator/platform/test/test_posix.py +++ b/pypy/translator/platform/test/test_posix.py @@ -3,7 +3,7 @@ from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.udir import udir from StringIO import StringIO -import sys +import sys, os def test_echo(): res = host.execute('echo', '42 24') @@ -49,6 +49,19 @@ mk.write() assert 'LINKFILES = /foo/bar.a' in tmpdir.join('Makefile').read() + def test_preprocess_localbase(self): + tmpdir = udir.join('test_preprocess_localbase').ensure(dir=1) + eci = ExternalCompilationInfo() + os.environ['PYPY_LOCALBASE'] = '/foo/baz' + try: + mk = self.platform.gen_makefile(['blip.c'], eci, path=tmpdir) + mk.write() + finally: + del os.environ['PYPY_LOCALBASE'] + Makefile = tmpdir.join('Makefile').read() + assert 'INCLUDEDIRS = -I/foo/baz/include' in Makefile + assert 'LIBDIRS = -L/foo/baz/lib' in Makefile + class TestMaemo(TestMakefile): strict_on_stderr = False diff --git a/pypy/translator/stackless/frame.py b/pypy/translator/stackless/frame.py --- a/pypy/translator/stackless/frame.py +++ b/pypy/translator/stackless/frame.py @@ -104,10 +104,8 @@ class RestartInfo(object): - """A RestartInfo is created (briefly) for each graph that contains - a resume point. - - In addition, a RestartInfo is created for each function that needs + """ + A RestartInfo is created for each function that needs to do explicit stackless manipulations (e.g. code.yield_current_frame_to_caller).""" diff --git a/pypy/translator/stackless/test/test_coroutine_reconstruction.py b/pypy/translator/stackless/test/test_coroutine_reconstruction.py deleted file mode 100644 --- a/pypy/translator/stackless/test/test_coroutine_reconstruction.py +++ /dev/null @@ -1,68 +0,0 @@ -from pypy.rlib import rcoroutine -from pypy.rlib import rstack -from pypy.rlib.rstack import resume_state_create -from pypy.translator.stackless.test.test_transform import llinterp_stackless_function -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rpython.lltypesystem import lltype - -namespace = rcoroutine.make_coroutine_classes(object) -syncstate = namespace['syncstate'] -AbstractThunk = namespace['AbstractThunk'] -Coroutine = namespace['Coroutine'] - -class TestCoroutineReconstruction: - - def setup_meth(self): - syncstate.reset() - - def test_simple_ish(self): - - output = [] - def f(coro, n, x): - if n == 0: - coro.switch() - rstack.resume_point("f_0") - assert rstack.stack_frames_depth() == 9 - return - f(coro, n-1, 2*x) - rstack.resume_point("f_1", coro, n, x) - output.append(x) - - class T(AbstractThunk): - def __init__(self, arg_coro, arg_n, arg_x): - self.arg_coro = arg_coro - self.arg_n = arg_n - self.arg_x = arg_x - def call(self): - f(self.arg_coro, self.arg_n, self.arg_x) - - def example(): - main_coro = Coroutine.getcurrent() - sub_coro = Coroutine() - thunk_f = T(main_coro, 5, 1) - sub_coro.bind(thunk_f) - sub_coro.switch() - - new_coro = Coroutine() - new_thunk_f = T(main_coro, 5, 1) - new_coro.bind(new_thunk_f) - - costate = Coroutine._get_default_costate() - bottom = resume_state_create(None, "yield_current_frame_to_caller_1") - _bind_frame = resume_state_create(bottom, "coroutine__bind", costate) - f_frame_1 = resume_state_create(_bind_frame, "f_1", main_coro, 5, 1) - f_frame_2 = resume_state_create(f_frame_1, "f_1", main_coro, 4, 2) - f_frame_3 = resume_state_create(f_frame_2, "f_1", main_coro, 3, 4) - f_frame_4 = resume_state_create(f_frame_3, "f_1", main_coro, 2, 8) - f_frame_5 = resume_state_create(f_frame_4, "f_1", main_coro, 1, 16) - f_frame_0 = resume_state_create(f_frame_5, "f_0") - switch_frame = resume_state_create(f_frame_0, "coroutine_switch", costate) - - new_coro.frame = switch_frame - - new_coro.switch() - return output == [16, 8, 4, 2, 1] - - res = llinterp_stackless_function(example) - assert res == 1 - diff --git a/pypy/translator/stackless/test/test_resume_point.py b/pypy/translator/stackless/test/test_resume_point.py deleted file mode 100644 --- a/pypy/translator/stackless/test/test_resume_point.py +++ /dev/null @@ -1,457 +0,0 @@ -from pypy.translator.stackless.transform import StacklessTransformer -from pypy.translator.stackless.test.test_transform import llinterp_stackless_function, rtype_stackless_function, one, run_stackless_function -from pypy import conftest -import py -from pypy.rlib import rstack - -def do_backendopt(t): - from pypy.translator.backendopt import all - all.backend_optimizations(t) - -def transform_stackless_function(fn, callback_for_transform=None): - def wrapper(argv): - return fn() - t = rtype_stackless_function(wrapper) - if callback_for_transform: - callback_for_transform(t) - if conftest.option.view: - t.view() - st = StacklessTransformer(t, wrapper, False) - st.transform_all() - -def test_no_call(): - def f(x, y): - x = x-1 - rstack.resume_point("rp0", x, y) - r = x+y - rstack.stack_unwind() - return r - def example(): - v1 = f(one(),one()+one()) - state = rstack.resume_state_create(None, "rp0", one(), one()+one()+one()) - v2 = rstack.resume_state_invoke(int, state) - return v1*10 + v2 -## transform_stackless_function(example) - res = llinterp_stackless_function(example, assert_unwind=False) - assert res == 24 - -def test_bogus_restart_state_create(): - def f(x, y): - x = x-1 - rstack.resume_point("rp0", x, y) - return x+y - def example(): - v1 = f(one(),one()+one()) - state = rstack.resume_state_create(None, "rp0", one()) - return v1 - info = py.test.raises(AssertionError, "transform_stackless_function(example)") - assert 'rp0' in str(info.value) - - -def test_call(): - def g(x,y): - return x*y - def f(x, y): - z = g(x,y) - rstack.resume_point("rp1", y, returns=z) - return z+y - def example(): - v1 = f(one(),one()+one()) - s = rstack.resume_state_create(None, "rp1", 5*one()) - v2 = rstack.resume_state_invoke(int, s, returning=one()*7) - return v1*100 + v2 - res = llinterp_stackless_function(example) - assert res == 412 - res = run_stackless_function(example) - assert res == 412 - -def test_returns_with_instance(): - class C: - def __init__(self, x): - self.x = x - def g(x): - return C(x+1) - def f(x, y): - r = g(x) - rstack.resume_point("rp1", y, returns=r) - return r.x + y - def example(): - v1 = f(one(),one()+one()) - s = rstack.resume_state_create(None, "rp1", 5*one()) - v2 = rstack.resume_state_invoke(int, s, returning=C(one()*3)) - return v1*100 + v2 - res = llinterp_stackless_function(example, assert_unwind=False) - assert res == 408 - res = run_stackless_function(example) - assert res == 408 - -def test_call_uncovered(): - def g(x,y): - return x*y - def f(x, y): - z = g(x,y) - rstack.resume_point("rp1", y, returns=z) - return z+y+x - def example(): - f(one(),one()+one()) - return 0 - e = py.test.raises(Exception, transform_stackless_function, example) - msg, = e.value.args - assert msg.startswith('not covered needed value at resume_point') and 'rp1' in msg - -def test_chained_states(): - def g(x, y): - x += 1 - rstack.resume_point("rp1", x, y) - return x + y - def f(x, y, z): - y += 1 - r = g(x, y) - rstack.resume_point("rp2", z, returns=r) - return r + z - def example(): - v1 = f(one(), 2*one(), 3*one()) - s2 = rstack.resume_state_create(None, "rp2", 2*one()) - s1 = rstack.resume_state_create(s2, "rp1", 4*one(), 5*one()) - return 100*v1 + rstack.resume_state_invoke(int, s1) - res = llinterp_stackless_function(example) - assert res == 811 - res = run_stackless_function(example) - assert res == 811 - -def test_return_instance(): - class C: - pass - def g(x): - c = C() - c.x = x + 1 - rstack.resume_point("rp1", c) - return c - def f(x, y): - r = g(x) - rstack.resume_point("rp2", y, returns=r) - return r.x + y - def example(): - v1 = f(one(), 2*one()) - s2 = rstack.resume_state_create(None, "rp2", 2*one()) - c = C() - c.x = 4*one() - s1 = rstack.resume_state_create(s2, "rp1", c) - return v1*100 + rstack.resume_state_invoke(int, s1) - res = llinterp_stackless_function(example) - assert res == 406 - res = run_stackless_function(example) - assert res == 406 - -def test_really_return_instance(): - class C: - pass - def g(x): - c = C() - c.x = x + 1 - rstack.resume_point("rp1", c) - return c - def example(): - v1 = g(one()).x - c = C() - c.x = 4*one() - s1 = rstack.resume_state_create(None, "rp1", c) - return v1*100 + rstack.resume_state_invoke(C, s1).x - res = llinterp_stackless_function(example) - assert res == 204 - res = run_stackless_function(example) - assert res == 204 - -def test_resume_and_raise(): - def g(x): - rstack.resume_point("rp0", x) - if x == 0: - raise KeyError - return x + 1 - def example(): - v1 = g(one()) - s = rstack.resume_state_create(None, "rp0", one()-1) - try: - v2 = rstack.resume_state_invoke(int, s) - except KeyError: - v2 = 42 - return v1*100 + v2 - res = llinterp_stackless_function(example) - assert res == 242 - res = run_stackless_function(example) - assert res == 242 - -def test_resume_and_raise_and_catch(): - def g(x): - rstack.resume_point("rp0", x) - if x == 0: - raise KeyError - return x + 1 - def f(x): - x = x - 1 - try: - r = g(x) - rstack.resume_point("rp1", returns=r) - except KeyError: - r = 42 - return r - 1 - def example(): - v1 = f(one()+one()) - s1 = rstack.resume_state_create(None, "rp1") - s0 = rstack.resume_state_create(s1, "rp0", one()-1) - v2 = rstack.resume_state_invoke(int, s0) - return v1*100 + v2 - res = llinterp_stackless_function(example) - assert res == 141 - res = run_stackless_function(example) - assert res == 141 - -def test_invoke_raising(): - def g(x): - rstack.resume_point("rp0", x) - return x + 1 - def f(x): - x = x - 1 - try: - r = g(x) - rstack.resume_point("rp1", returns=r) - except KeyError: - r = 42 - return r - 1 - def example(): - v1 = f(one()+one()) - s1 = rstack.resume_state_create(None, "rp1") - s0 = rstack.resume_state_create(s1, "rp0", 0) - v2 = rstack.resume_state_invoke(int, s0, raising=KeyError()) - return v1*100 + v2 - res = llinterp_stackless_function(example) - assert res == 141 - res = run_stackless_function(example) - assert res == 141 - - -def test_finally(): - def f(x): - rstack.resume_point("rp1", x) - return 1/x - def in_finally(x): - rstack.resume_point("rp1.5", x) - return 2/x - def g(x): - r = y = 0 - r += f(x) - try: - y = f(x) - rstack.resume_point("rp0", x, r, returns=y) - finally: - r += in_finally(x) - return r + y - def example(): - return g(one()) - transform_stackless_function(example) - -def test_except(): - py.test.skip("please don't write code like this") - def f(x): - rstack.resume_point("rp1", x) - return 1/x - def g(x): - r = y = 0 - r += f(x) - try: - y = f(x) - rstack.resume_point("rp0", x, r, y, returns=y) - except ZeroDivisionError: - r += f(x) - return r + y - def example(): - return g(one()) - transform_stackless_function(example) - -def test_using_pointers(): - from pypy.interpreter.miscutils import FixedStack - class Arguments: - def __init__(self, a, b, c, d, e): - pass - class W_Root: - pass - class FakeFrame: - def __init__(self, space): - self.space = space - self.valuestack = FixedStack() - self.valuestack.setup(10) - self.valuestack.push(W_Root()) - class FakeSpace: - def call_args(self, args, kw): - return W_Root() - def str_w(self, ob): - return 'a string' - def call_function(f, oparg, w_star=None, w_starstar=None): - n_arguments = oparg & 0xff - n_keywords = (oparg>>8) & 0xff - keywords = None - if n_keywords: - keywords = {} - for i in range(n_keywords): - w_value = f.valuestack.pop() - w_key = f.valuestack.pop() - key = f.space.str_w(w_key) - keywords[key] = w_value - arguments = [None] * n_arguments - for i in range(n_arguments - 1, -1, -1): - arguments[i] = f.valuestack.pop() - args = Arguments(f.space, arguments, keywords, w_star, w_starstar) - w_function = f.valuestack.pop() - w_result = f.space.call_args(w_function, args) - rstack.resume_point("call_function", f, returns=w_result) - f.valuestack.push(w_result) - def example(): - s = FakeSpace() - f = FakeFrame(s) - call_function(f, 100, W_Root(), W_Root()) - return one() - transform_stackless_function(example, do_backendopt) - -def test_always_raising(): - def g(out): - out.append(3) - rstack.resume_point('g') - raise KeyError - - def h(out): - try: - # g is always raising, good enough to put the resume point - # before, instead of after! - rstack.resume_point('h', out) - g(out) - except KeyError: - return 0 - return -1 - - def example(): - out = [] - x = h(out) - l = len(out) - chain = rstack.resume_state_create(None, 'h', out) - chain = rstack.resume_state_create(chain, 'g') - x += rstack.resume_state_invoke(int, chain) - l += len(out) - return l*100+x - - res = llinterp_stackless_function(example) - assert res == 200 - res = run_stackless_function(example) - assert res == 200 - -def test_more_mess(): - from pypy.interpreter.miscutils import Stack - - def new_framestack(): - return Stack() - - class FakeFrame: - pass - class FakeSlpFrame: - def switch(self): - rstack.stack_unwind() - return FakeSlpFrame() - - class FakeCoState: - def update(self, new): - self.last, self.current = self.current, new - frame, new.frame = new.frame, None - return frame - def do_things_to_do(self): - self.do_things_to_do() - - costate = FakeCoState() - costate.current = None - - class FakeExecutionContext: - def __init__(self): - self.space = space - self.framestack = new_framestack() - - def subcontext_new(coobj): - coobj.framestack = new_framestack() - subcontext_new = staticmethod(subcontext_new) - - def subcontext_enter(self, next): - self.framestack = next.framestack - - def subcontext_leave(self, current): - current.framestack = self.framestack - - class FakeSpace: - def __init__(self): - self.ec = None - def getexecutioncontext(self): - if self.ec is None: - self.ec = FakeExecutionContext() - return self.ec - - space = FakeSpace() - - class MainCoroutineGetter(object): - def __init__(self): - self.costate = None - def _get_default_costate(self): - if self.costate is None: - costate = FakeCoState() - self.costate = costate - return costate - return self.costate - - main_coroutine_getter = MainCoroutineGetter() - - class FakeCoroutine: - def __init__(self): - self.frame = None - self.costate = costate - space.getexecutioncontext().subcontext_new(self) - - def switch(self): - if self.frame is None: - raise RuntimeError - state = self.costate - incoming_frame = state.update(self).switch() - rstack.resume_point("coroutine_switch", self, state, returns=incoming_frame) - left = state.last - left.frame = incoming_frame - left.goodbye() - self.hello() - #main_coroutine_getter._get_default_costate().do_things_to_do() - - def hello(self): - pass - - def goodbye(self): - pass - - class FakeAppCoroutine(FakeCoroutine): - def __init__(self): - FakeCoroutine.__init__(self) - self.space = space - - def hello(self): - ec = self.space.getexecutioncontext() - ec.subcontext_enter(self) - - def goodbye(self): - ec = self.space.getexecutioncontext() - ec.subcontext_leave(self) - - def example(): - coro = FakeAppCoroutine() - othercoro = FakeCoroutine() - othercoro.frame = FakeSlpFrame() - if one(): - coro.frame = FakeSlpFrame() - if one() - one(): - coro.costate = FakeCoState() - coro.costate.last = coro.costate.current = othercoro - space.getexecutioncontext().framestack.push(FakeFrame()) - coro.switch() - return one() - - transform_stackless_function(example, do_backendopt) diff --git a/pypy/translator/stackless/transform.py b/pypy/translator/stackless/transform.py --- a/pypy/translator/stackless/transform.py +++ b/pypy/translator/stackless/transform.py @@ -112,19 +112,6 @@ # abort() # return retval + x + 1 -class SymbolicRestartNumber(ComputedIntSymbolic): - def __init__(self, label, value=None): - ComputedIntSymbolic.__init__(self, self._getvalue) - self.label = label - self.value = value - - def _getvalue(self): - # argh, we'd like to assert-fail if value is None here, but we - # get called too early (during databasing) for this to be - # valid. so we might return None and rely on the database - # checking that this only happens before the database is - # complete. - return self.value # the strategy for sharing parts of the resume code: # @@ -248,8 +235,7 @@ self.stackless_gc = stackless_gc def analyze_simple_operation(self, op, graphinfo): - if op.opname in ('yield_current_frame_to_caller', 'resume_point', - 'resume_state_invoke', 'resume_state_create', 'stack_frames_depth', + if op.opname in ('yield_current_frame_to_caller', 'stack_frames_depth', 'stack_switch', 'stack_unwind', 'stack_capture', 'get_stack_depth_limit', 'set_stack_depth_limit'): return True @@ -458,24 +444,11 @@ self.is_finished = False - # only for sanity checking, but still very very important - self.explicit_resume_point_data = {} - - self.symbolic_restart_numbers = {} - - # register the prebuilt restartinfos & give them names for use - # with resume_state_create # the mauling of frame_typer internals should be a method on FrameTyper. for restartinfo in frame.RestartInfo.prebuilt: name = restartinfo.func_or_graph.__name__ for i in range(len(restartinfo.frame_types)): - label = name + '_' + str(i) - assert label not in self.symbolic_restart_numbers - # XXX we think this is right: - self.symbolic_restart_numbers[label] = SymbolicRestartNumber( - label, len(self.masterarray1) + i) frame_type = restartinfo.frame_types[i] - self.explicit_resume_point_data[label] = frame_type self.frametyper.ensure_frame_type_for_types(frame_type) self.register_restart_info(restartinfo) @@ -589,156 +562,6 @@ # yes convertblock.exits[0].args[index] = newvar # end ouch! - - def handle_resume_point(self, block, i): - # in some circumstances we might be able to reuse - # an already inserted resume point - op = block.operations[i] - if i == len(block.operations) - 1: - link = block.exits[0] - nextblock = None - else: - link = split_block(None, block, i+1) - i = 0 - nextblock = link.target - - label = op.args[0].value - - parms = op.args[1:] - if not isinstance(parms[0], model.Variable): - assert parms[0].value is None - parms[0] = None - args = vars_to_save(block) - for a in args: - if a not in parms: - raise Exception, "not covered needed value at resume_point %r"%(label,) - if parms[0] is not None: # returns= case - res = parms[0] - args = [arg for arg in args if arg is not res] - else: - args = args - res = op.result - - (FRAME_TYPE, varsforcall, saver) = self.frametyper.frame_type_for_vars(parms[1:]) - - if label in self.explicit_resume_point_data: - OTHER_TYPE = self.explicit_resume_point_data[label] - assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,) - else: - self.explicit_resume_point_data[label] = FRAME_TYPE - - self._make_resume_handling(FRAME_TYPE, varsforcall, res, block.exits) - - restart_number = len(self.masterarray1) + len(self.resume_blocks) - 1 - - if label in self.symbolic_restart_numbers: - symb = self.symbolic_restart_numbers[label] - assert symb.value is None - symb.value = restart_number - else: - symb = SymbolicRestartNumber(label, restart_number) - self.symbolic_restart_numbers[label] = symb - - return nextblock - - def handle_resume_state_create(self, block, i): - op = block.operations[i] - llops = LowLevelOpList() - label = op.args[1].value - parms = op.args[2:] - FRAME_TYPE, varsforcall, saver = self.frametyper.frame_type_for_vars(parms) - - if label in self.explicit_resume_point_data: - OTHER_TYPE = self.explicit_resume_point_data[label] - assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,) - else: - self.explicit_resume_point_data[label] = FRAME_TYPE - - if label in self.symbolic_restart_numbers: - symb = self.symbolic_restart_numbers[label] - else: - symb = SymbolicRestartNumber(label) - self.symbolic_restart_numbers[label] = symb - - # this is rather insane: we create an exception object, pass - # it to the saving function, then read the thus created state - # out of and then clear global_state.top - c_EXC = model.Constant(self.unwind_exception_type.TO, lltype.Void) - c_flags = model.Constant({'flavor': 'gc'}, lltype.Void) - v_exc = llops.genop('malloc', [c_EXC, c_flags], - resulttype = self.unwind_exception_type) - llops.genop('setfield', [v_exc, - model.Constant('inst_depth', lltype.Void), - model.Constant(0, lltype.Signed)]) - - realvarsforcall = [] - for v in varsforcall: - if v.concretetype != lltype.Void: - realvarsforcall.append(gen_cast(llops, storage_type(v.concretetype), v)) - - llops.genop('direct_call', - [model.Constant(saver, lltype.typeOf(saver)), v_exc, - model.Constant(symb, lltype.Signed)] + realvarsforcall, - resulttype = lltype.Void) - v_state = varoftype(lltype.Ptr(frame.STATE_HEADER)) - v_state_hdr = llops.genop("getfield", - [self.ll_global_state, self.c_inst_top_name], - resulttype=lltype.Ptr(STATE_HEADER)) - v_state = gen_cast(llops, lltype.Ptr(FRAME_TYPE), v_state_hdr) - llops.genop("setfield", - [self.ll_global_state, self.c_inst_top_name, self.c_null_state]) - - v_prevstate = gen_cast(llops, lltype.Ptr(frame.STATE_HEADER), op.args[0]) - llops.genop('direct_call', [self.set_back_pointer_ptr, - v_state_hdr, v_prevstate]) - llops.append(model.SpaceOperation('cast_opaque_ptr', [v_state_hdr], op.result)) - block.operations[i:i+1] = llops - - def handle_resume_state_invoke(self, block): - op = block.operations[-1] - assert op.opname == 'resume_state_invoke' - # some commentary. - # - # we don't want to write 155 or so different versions of - # resume_after_foo that appear to the annotator to return - # different types. we take advantage of the fact that this - # function always raises UnwindException and have it (appear - # to) return Void. then to placate all the other machinery, - # we pass a constant zero-of-the-appropriate-type along the - # non-exceptional link (which we know will never be taken). - # Nota Bene: only mutate a COPY of the non-exceptional link - # because the non-exceptional link has been stored in - # self.resume_blocks and we don't want a constant "zero" in - # there. - v_state = op.args[0] - v_returning = op.args[1] - v_raising = op.args[2] - llops = LowLevelOpList() - - if v_raising.concretetype == lltype.Void: - erased_type = storage_type(v_returning.concretetype) - resume_after_ptr = self.resume_afters[erased_type] - v_param = v_returning - else: - assert v_returning.concretetype == lltype.Void - erased_type = self.exception_type - resume_after_ptr = self.resume_after_raising_ptr - v_param = v_raising - - if erased_type != v_param.concretetype: - v_param = gen_cast(llops, erased_type, v_param) - llops.genop('direct_call', [resume_after_ptr, v_state, v_param], - resulttype=lltype.Void) - - del block.operations[-1] - block.operations.extend(llops) - - noexclink = block.exits[0].copy() - realrettype = op.result.concretetype - for i, a in enumerate(noexclink.args): - if a is op.result: - noexclink.args[i] = model.Constant(realrettype._defl(), realrettype) - block.recloseblock(*((noexclink,) + block.exits[1:])) def insert_unwind_handling(self, block, i): # for the case where we are resuming to an except: @@ -821,19 +644,8 @@ op = replace_with_call(self.operation_replacement[op.opname]) stackless_op = True - if op.opname == 'resume_state_create': - self.handle_resume_state_create(block, i) - continue # go back and look at that malloc - if (op.opname in ('direct_call', 'indirect_call') or self.analyzer.analyze(op)): - if op.opname == 'resume_point': - block = self.handle_resume_point(block, i) - if block is None: - return - else: - i = 0 - continue if not stackless_op and not self.analyzer.analyze(op): i += 1 @@ -849,9 +661,7 @@ continue nextblock = self.insert_unwind_handling(block, i) - if op.opname == 'resume_state_invoke': - self.handle_resume_state_invoke(block) - + if nextblock is None: return diff --git a/pypy/translator/transform.py b/pypy/translator/transform.py --- a/pypy/translator/transform.py +++ b/pypy/translator/transform.py @@ -175,41 +175,6 @@ # make sure the bookkeeper knows about AssertionError self.bookkeeper.getuniqueclassdef(AssertionError) -def insert_stackcheck(ann): - from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles - edges = [] - graphs_to_patch = {} - for callposition, (caller, callee) in ann.translator.callgraph.items(): - if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False): - graphs_to_patch[callee] = True - continue - edge = Edge(caller, callee) - edge.callposition = callposition - edges.append(edge) - - for graph in graphs_to_patch: - v = Variable() - ann.setbinding(v, annmodel.SomeImpossibleValue()) - unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v) - graph.startblock.operations.insert(0, unwind_op) - - edgedict = make_edge_dict(edges) - for edge in break_cycles(edgedict, edgedict): - caller = edge.source - _, _, call_tag = edge.callposition - if call_tag: - caller_block, _ = call_tag - else: - ann.warning("cycle detected but no information on where to insert " - "stack_check()") - continue - # caller block found, insert stack_check() - v = Variable() - # push annotation on v - ann.setbinding(v, annmodel.SomeImpossibleValue()) - unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v) - caller_block.operations.insert(0, unwind_op) - def insert_ll_stackcheck(translator): from pypy.translator.backendopt.support import find_calls_from from pypy.rlib.rstack import stack_check diff --git a/pytest.py b/pytest.py old mode 100644 new mode 100755 --- a/pytest.py +++ b/pytest.py @@ -1,7 +1,6 @@ +#!/usr/bin/env python """ unit and functional testing with Python. -(pypy version of startup script) -see http://pytest.org for details. """ __all__ = ['main'] @@ -9,23 +8,6 @@ from _pytest import core as cmdline from _pytest import __version__ -# This pytest.py script is located in the pypy source tree -# which has a copy of pytest and py within its source tree. -# If the environment also has an installed version of pytest/py -# we are bound to get warnings so we disable them. -# XXX eventually pytest and py should not be inlined shipped -# with the pypy source code but become a requirement for installation. - -import warnings -warnings.filterwarnings("ignore", - "Module py was already imported", category=UserWarning) -warnings.filterwarnings("ignore", - "Module _pytest was already imported", - category=UserWarning) -warnings.filterwarnings("ignore", - "Module pytest was already imported", - category=UserWarning) - if __name__ == '__main__': # if run as a script or by 'python -m pytest' raise SystemExit(main()) else: From noreply at buildbot.pypy.org Fri Jul 1 23:05:26 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 23:05:26 +0200 (CEST) Subject: [pypy-commit] pypy celldict-versions: typos (?!) Message-ID: <20110701210526.ED1868293E@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: celldict-versions Changeset: r45251:461d9041e1d7 Date: 2011-07-01 23:12 +0200 http://bitbucket.org/pypy/pypy/changeset/461d9041e1d7/ Log: typos (?!) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -45,7 +45,7 @@ def getdictvalue_no_unwrapping(self, w_dict, key): return self._getdictvalue_no_unwrapping_pure(self.version, w_dict, key) - @jit.elidablefunction_promote('0,1,2') + @jit.elidable_promote('0,1,2') def _getdictvalue_no_unwrapping_pure(self, version, w_dict, key): return self.unerase(w_dict.dstorage).get(key, None) diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -2,7 +2,7 @@ from pypy.conftest import gettestobjspace, option from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy -from pypy.objspace.std.test.test_dictmultiobject import FakeSpace. \ +from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, \ BaseTestRDictImplementation, BaseTestDevolvedDictImplementation from pypy.interpreter import gateway From noreply at buildbot.pypy.org Fri Jul 1 23:29:51 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 1 Jul 2011 23:29:51 +0200 (CEST) Subject: [pypy-commit] pypy default: a test that checks that mutating a string dict does not change any caches Message-ID: <20110701212951.933678293E@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45252:a36842c12c80 Date: 2011-07-01 23:36 +0200 http://bitbucket.org/pypy/pypy/changeset/a36842c12c80/ Log: a test that checks that mutating a string dict does not change any caches diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] From noreply at buildbot.pypy.org Fri Jul 1 23:38:30 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 1 Jul 2011 23:38:30 +0200 (CEST) Subject: [pypy-commit] pypy default: First fix some typos (Abtract -> Abstract), then simplify StrDictStrategy.getitem by calling the parent's method. Message-ID: <20110701213830.F2D308293E@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45253:ad23bd2e7615 Date: 2011-07-01 14:43 -0700 http://bitbucket.org/pypy/pypy/changeset/ad23bd2e7615/ Log: First fix some typos (Abtract -> Abstract), then simplify StrDictStrategy.getitem by calling the parent's method. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -266,7 +266,7 @@ # concrete subclasses of the above -class AbtractTypedStrategy(object): +class AbstractTypedStrategy(object): _mixin_ = True @staticmethod @@ -364,7 +364,7 @@ w_dict.dstorage = strategy.erase(d_new) -class ObjectDictStrategy(AbtractTypedStrategy, DictStrategy): +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) @@ -390,7 +390,7 @@ def keys(self, w_dict): return self.unerase(w_dict.dstorage).keys() -class StringDictStrategy(AbtractTypedStrategy, DictStrategy): +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) @@ -424,14 +424,10 @@ if type(w_key) is space.StringObjectCls: return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- + if _never_equal_to_string(space, space.type(w_key)): + return None - if self.is_correct_type(w_key): - return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) - elif _never_equal_to_string(space, space.type(w_key)): - return None - else: - self.switch_to_object_strategy(w_dict) - return w_dict.getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) def getitem_str(self, w_dict, key): assert key is not None From noreply at buildbot.pypy.org Fri Jul 1 23:38:32 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 1 Jul 2011 23:38:32 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20110701213832.392F58293E@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45254:058e65eeb377 Date: 2011-07-01 14:45 -0700 http://bitbucket.org/pypy/pypy/changeset/058e65eeb377/ Log: merged upstream diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] From noreply at buildbot.pypy.org Sat Jul 2 04:50:26 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 2 Jul 2011 04:50:26 +0200 (CEST) Subject: [pypy-commit] pypy default: Added an integer specialized dictionary. Message-ID: <20110702025027.0158E8293F@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45255:5f925529d17a Date: 2011-07-01 19:57 -0700 http://bitbucket.org/pypy/pypy/changeset/5f925529d17a/ Log: Added an integer specialized dictionary. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -6,7 +6,7 @@ from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.rlib.objectmodel import r_dict, we_are_translated +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize from pypy.rlib.debug import mark_dict_non_null from pypy.rlib import rerased @@ -163,15 +163,22 @@ #XXX implement other strategies later if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) - return + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - strategy = self.space.fromcache(ObjectDictStrategy) + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) storage = strategy.get_empty_storage() w_dict.strategy = strategy w_dict.dstorage = storage - def switch_to_string_strategy(self, w_dict): - strategy = self.space.fromcache(StringDictStrategy) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) storage = strategy.get_empty_storage() w_dict.strategy = strategy w_dict.dstorage = storage @@ -289,6 +296,9 @@ def get_empty_storage(self): raise NotImplementedError("abstract base class") + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + def setitem(self, w_dict, w_key, w_value): space = self.space if self.is_correct_type(w_key): @@ -331,6 +341,8 @@ if self.is_correct_type(w_key): return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None else: self.switch_to_object_strategy(w_dict) return w_dict.getitem(w_key) @@ -363,7 +375,6 @@ w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new) - class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("object") @@ -384,8 +395,11 @@ force_non_null=True) return self.erase(new_dict) + def _never_equal_to(self, w_lookup_type): + return False + def iter(self, w_dict): - return RDictIteratorImplementation(self.space, self, w_dict) + return ObjectIteratorImplementation(self.space, self, w_dict) def keys(self, w_dict): return self.unerase(w_dict.dstorage).keys() @@ -414,6 +428,9 @@ mark_dict_non_null(res) return self.erase(res) + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + def setitem_str(self, w_dict, key, w_value): assert key is not None self.unerase(w_dict.dstorage)[key] = w_value @@ -424,9 +441,6 @@ if type(w_key) is space.StringObjectCls: return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - if _never_equal_to_string(space, space.type(w_key)): - return None - return AbstractTypedStrategy.getitem(self, w_dict, w_key) def getitem_str(self, w_dict, key): @@ -440,27 +454,67 @@ class StrIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - dict_w = strategy.unerase(dictimplementation.dstorage) - self.iterator = dict_w.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.dictimplementation.strategy.wrap(key), w_value else: return None, None -class RDictIteratorImplementation(IteratorImplementation): +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_int) + + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) + +class IntIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - d = strategy.unerase(dictimplementation.dstorage) - self.iterator = d.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.dictimplementation.strategy.wrap(key), w_value + else: + return None, None + + +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for key, w_value in self.iterator: + return self.dictimplementation.strategy.wrap(key), w_value else: return None, None diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -805,7 +805,12 @@ o.a = 1 assert "StringDictStrategy" in self.get_strategy(d) - + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -846,6 +851,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj From noreply at buildbot.pypy.org Sat Jul 2 05:46:58 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 2 Jul 2011 05:46:58 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove some dead code. Message-ID: <20110702034658.386968293F@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45256:feda7cdc88e3 Date: 2011-07-01 20:54 -0700 http://bitbucket.org/pypy/pypy/changeset/feda7cdc88e3/ Log: Remove some dead code. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -153,9 +153,6 @@ erase = staticmethod(erase) unerase = staticmethod(unerase) - def __init__(self, space): - self.space = space - def get_empty_storage(self): return self.erase(None) @@ -410,9 +407,6 @@ erase = staticmethod(erase) unerase = staticmethod(unerase) - def __init__(self, space): - self.space = space - def wrap(self, unwrapped): return self.space.wrap(unwrapped) From noreply at buildbot.pypy.org Sat Jul 2 06:04:22 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 2 Jul 2011 06:04:22 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix translation. Message-ID: <20110702040422.271728293F@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45257:826ab6a098e6 Date: 2011-07-01 21:11 -0700 http://bitbucket.org/pypy/pypy/changeset/826ab6a098e6/ Log: Fix translation. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -453,7 +453,7 @@ def next_entry(self): # note that this 'for' loop only runs once, at most for key, w_value in self.iterator: - return self.dictimplementation.strategy.wrap(key), w_value + return self.space.wrap(key), w_value else: return None, None @@ -495,7 +495,7 @@ def next_entry(self): # note that this 'for' loop only runs once, at most for key, w_value in self.iterator: - return self.dictimplementation.strategy.wrap(key), w_value + return self.space.wrap(key), w_value else: return None, None @@ -507,8 +507,8 @@ def next_entry(self): # note that this 'for' loop only runs once, at most - for key, w_value in self.iterator: - return self.dictimplementation.strategy.wrap(key), w_value + for w_key, w_value in self.iterator: + return w_key, w_value else: return None, None From noreply at buildbot.pypy.org Sat Jul 2 06:42:04 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 2 Jul 2011 06:42:04 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Clean up the language slightly. Message-ID: <20110702044204.C514D8293F@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r203:dffbce54dcfe Date: 2011-07-01 21:49 -0700 http://bitbucket.org/pypy/pypy.org/changeset/dffbce54dcfe/ Log: Clean up the language slightly. diff --git a/source/success.txt b/source/success.txt --- a/source/success.txt +++ b/source/success.txt @@ -9,8 +9,9 @@ LWN short experiment -------------------- -LWN did `an experiment`_ with parsing "git log" and got a speedup from 63s to -21s using PyPy over CPython. +LWN has a tool they use for parsing "git log"'s output in order to do analysis +on the contributors to the Linux kernel. Simply by switching to PyPy they were +able to get a 3x speedup, from 63 seconds to 21 seconds, compared to CPython. "In other ways, PyPy is ready for prime time; it implements the (Python 2.x) language faithfully, and it is fast." @@ -19,8 +20,8 @@ MyHDL ----- -MyHDL got speed up by 6-12x according to their `performance page`_, putting -it in the same league as other HDL implementations. +MyHDL got a speed up by 6-12x, on various benchmarks, according to their +`performance page`_, putting it in the same league as other HDL implementations. "By simply changing the Python interpreter, MyHDL is playing in the same league as Verilog and VHDL simulators. This is a remarkable achievement, given that Python's power stays completely available. There is no reason anymore to avoid MyHDL because of performance concerns." From noreply at buildbot.pypy.org Sat Jul 2 06:44:59 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 2 Jul 2011 06:44:59 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Make sure not to lose the links. Message-ID: <20110702044459.A65538293F@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r204:6f55ab31a383 Date: 2011-07-01 21:52 -0700 http://bitbucket.org/pypy/pypy.org/changeset/6f55ab31a383/ Log: Make sure not to lose the links. diff --git a/source/success.txt b/source/success.txt --- a/source/success.txt +++ b/source/success.txt @@ -10,19 +10,20 @@ -------------------- LWN has a tool they use for parsing "git log"'s output in order to do analysis -on the contributors to the Linux kernel. Simply by switching to PyPy they were -able to get a 3x speedup, from 63 seconds to 21 seconds, compared to CPython. +on the contributors to the Linux kernel. Simply `by switching to PyPy`_ they +were able to get a 3x speedup, from 63 seconds to 21 seconds, compared to +CPython. "In other ways, PyPy is ready for prime time; it implements the (Python 2.x) language faithfully, and it is fast." -.. _`an experiment`: http://lwn.net/Articles/442268/ +.. _`by switching to PyPy`: http://lwn.net/Articles/442268/ MyHDL ----- -MyHDL got a speed up by 6-12x, on various benchmarks, according to their -`performance page`_, putting it in the same league as other HDL implementations. +MyHDL got a speed up by `6-12x compared to CPython`_, on a range of benchmarks, +putting it in the same league as other HDL implementations. "By simply changing the Python interpreter, MyHDL is playing in the same league as Verilog and VHDL simulators. This is a remarkable achievement, given that Python's power stays completely available. There is no reason anymore to avoid MyHDL because of performance concerns." -.. _`performance page`: http://www.myhdl.org/doku.php/performance +.. _`6-12x compared to CPython`: http://www.myhdl.org/doku.php/performance From noreply at buildbot.pypy.org Sat Jul 2 12:03:57 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 12:03:57 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: hg merge default Message-ID: <20110702100357.7810082940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45258:d49eacf66926 Date: 2011-07-01 12:03 +0200 http://bitbucket.org/pypy/pypy/changeset/d49eacf66926/ Log: hg merge default diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,14 +4399,8 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) - self.assertTrue(l.__add__.im_class is list) + self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__objclass__ is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -299,12 +299,13 @@ listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -134,7 +134,7 @@ def accept_comp_iteration(self, codegen, index): self.elt.walkabout(codegen) - codegen.emit_op_arg(ops.SET_ADD, index) + codegen.emit_op_arg(ops.SET_ADD, index + 1) class __extend__(ast.DictComp): @@ -148,7 +148,7 @@ def accept_comp_iteration(self, codegen, index): self.value.walkabout(codegen) self.key.walkabout(codegen) - codegen.emit_op_arg(ops.MAP_ADD, index) + codegen.emit_op_arg(ops.MAP_ADD, index + 1) # These are frame blocks. diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -92,7 +92,10 @@ return name if len(name) + 2 >= MANGLE_LEN: return name - if name.endswith('__'): + # Don't mangle __id__ or names with dots. The only time a name with a dot + # can occur is when we are compiling an import statement that has a package + # name. + if name.endswith('__') or '.' in name: return name try: i = 0 diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -308,6 +308,15 @@ "p.__name__", os.path.__name__) yield (self.st, 'from os import *', "path.__name__, sep", (os.path.__name__, os.sep)) + yield (self.st, ''' + class A(object): + def m(self): + from __foo__.bar import x + try: + A().m() + except ImportError, e: + msg = str(e) + ''', "msg", "No module named __foo__") def test_if_stmts(self): yield self.st, "a = 42\nif a > 10: a += 2", "a", 44 diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -100,12 +100,12 @@ @jit.dont_look_inside def fast2locals(self): - # Copy values from self.fastlocals_w to self.w_locals + # Copy values from the fastlocals to self.w_locals if self.w_locals is None: self.w_locals = self.space.newdict() varnames = self.getcode().getvarnames() fastscope_w = self.getfastscope() - for i in range(min(len(varnames), len(fastscope_w))): + for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] if w_value is not None: @@ -114,7 +114,7 @@ @jit.dont_look_inside def locals2fast(self): - # Copy values from self.w_locals to self.fastlocals_w + # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None varnames = self.getcode().getvarnames() numlocals = self.getfastscopelength() diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -98,7 +98,7 @@ self.closure) for i in funccallunrolling: if i < nargs: - new_frame.fastlocals_w[i] = args_w[i] + new_frame.locals_stack_w[i] = args_w[i] return new_frame.run() elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1: assert isinstance(code, gateway.BuiltinCodePassThroughArguments1) @@ -158,7 +158,7 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg return new_frame.run() @@ -169,13 +169,13 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = self.defs_w[j] + new_frame.locals_stack_w[i] = self.defs_w[j] i += 1 return new_frame.run() diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -170,7 +170,7 @@ for i in range(len(args_to_copy)): argnum = args_to_copy[i] if argnum >= 0: - self.cells[i].set(self.fastlocals_w[argnum]) + self.cells[i].set(self.locals_stack_w[argnum]) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -63,6 +63,7 @@ the pypy compiler""" self.space = space eval.Code.__init__(self, name) + assert nlocals >= 0 self.co_argcount = argcount self.co_nlocals = nlocals self.co_stacksize = stacksize @@ -202,7 +203,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -215,7 +216,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -9,7 +9,7 @@ from pypy.interpreter import pytraceback from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib.jit import hint -from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.debug import make_sure_not_resized, check_nonneg from pypy.rlib.rarithmetic import intmask from pypy.rlib import jit from pypy.tool import stdlib_opcode @@ -56,16 +56,18 @@ assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals) - self.valuestack_w = [None] * code.co_stacksize - self.valuestackdepth = 0 + self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize) + self.nlocals = code.co_nlocals + self.valuestackdepth = code.co_nlocals self.lastblock = None + make_sure_not_resized(self.locals_stack_w) + check_nonneg(self.nlocals) + # if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure, code) - self.fastlocals_w = [None] * code.co_nlocals - make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno def mark_as_escaped(self): @@ -184,14 +186,14 @@ # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth - self.valuestack_w[depth] = w_object + self.locals_stack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 - assert depth >= 0, "pop from empty value stack" - w_object = self.valuestack_w[depth] - self.valuestack_w[depth] = None + assert depth >= self.nlocals, "pop from empty value stack" + w_object = self.locals_stack_w[depth] + self.locals_stack_w[depth] = None self.valuestackdepth = depth return w_object @@ -217,24 +219,24 @@ def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n - assert base >= 0 + assert base >= self.nlocals while True: n -= 1 if n < 0: break - values_w[n] = self.valuestack_w[base+n] + values_w[n] = self.locals_stack_w[base+n] return values_w @jit.unroll_safe def dropvalues(self, n): n = hint(n, promote=True) finaldepth = self.valuestackdepth - n - assert finaldepth >= 0, "stack underflow in dropvalues()" + assert finaldepth >= self.nlocals, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break - self.valuestack_w[finaldepth+n] = None + self.locals_stack_w[finaldepth+n] = None self.valuestackdepth = finaldepth @jit.unroll_safe @@ -261,30 +263,30 @@ # Contrast this with CPython where it's PEEK(-1). index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "peek past the bottom of the stack" - return self.valuestack_w[index] + assert index >= self.nlocals, "peek past the bottom of the stack" + return self.locals_stack_w[index] def settopvalue(self, w_object, index_from_top=0): index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "settop past the bottom of the stack" - self.valuestack_w[index] = w_object + assert index >= self.nlocals, "settop past the bottom of the stack" + self.locals_stack_w[index] = w_object @jit.unroll_safe def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 finaldepth = hint(finaldepth, promote=True) while depth >= finaldepth: - self.valuestack_w[depth] = None + self.locals_stack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth - def savevaluestack(self): - return self.valuestack_w[:self.valuestackdepth] + def save_locals_stack(self): + return self.locals_stack_w[:self.valuestackdepth] - def restorevaluestack(self, items_w): - assert None not in items_w - self.valuestack_w[:len(items_w)] = items_w + def restore_locals_stack(self, items_w): + self.locals_stack_w[:len(items_w)] = items_w + self.init_cells() self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): @@ -314,11 +316,12 @@ else: f_lineno = self.f_lineno - values_w = self.valuestack_w[0:self.valuestackdepth] + values_w = self.locals_stack_w[self.nlocals:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) - w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) + w_fastlocals = maker.slp_into_tuple_with_nulls( + space, self.locals_stack_w[:self.nlocals]) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None @@ -399,7 +402,8 @@ new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) - new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None @@ -423,28 +427,28 @@ @jit.dont_look_inside def getfastscope(self): "Get the fast locals as a list." - return self.fastlocals_w + return self.locals_stack_w @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) - if scope_len > len(self.fastlocals_w): + if scope_len > self.nlocals: raise ValueError, "new fastscope is longer than the allocated area" - # don't assign directly to 'fastlocals_w[:scope_len]' to be + # don't assign directly to 'locals_stack_w[:scope_len]' to be # virtualizable-friendly for i in range(scope_len): - self.fastlocals_w[i] = scope_w[i] + self.locals_stack_w[i] = scope_w[i] self.init_cells() def init_cells(self): - """Initialize cellvars from self.fastlocals_w + """Initialize cellvars from self.locals_stack_w. This is overridden in nestedscope.py""" pass def getfastscopelength(self): - return self.pycode.co_nlocals + return self.nlocals def getclosure(self): return None diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -324,7 +324,7 @@ def LOAD_FAST(self, varindex, next_instr): # access a local variable directly - w_value = self.fastlocals_w[varindex] + w_value = self.locals_stack_w[varindex] if w_value is None: self._load_fast_failed(varindex) self.pushvalue(w_value) @@ -343,7 +343,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self.fastlocals_w[varindex] = w_newvalue + self.locals_stack_w[varindex] = w_newvalue def POP_TOP(self, oparg, next_instr): self.popvalue() @@ -696,12 +696,12 @@ LOAD_GLOBAL._always_inline_ = True def DELETE_FAST(self, varindex, next_instr): - if self.fastlocals_w[varindex] is None: + if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise operationerrfmt(self.space.w_UnboundLocalError, message, varname) - self.fastlocals_w[varindex] = None + self.locals_stack_w[varindex] = None def BUILD_TUPLE(self, itemcount, next_instr): items = self.popvalues(itemcount) @@ -1048,13 +1048,13 @@ def SET_ADD(self, oparg, next_instr): w_value = self.popvalue() - w_set = self.peekvalue(oparg) + w_set = self.peekvalue(oparg - 1) self.space.call_method(w_set, 'add', w_value) def MAP_ADD(self, oparg, next_instr): w_key = self.popvalue() w_value = self.popvalue() - w_dict = self.peekvalue(oparg) + w_dict = self.peekvalue(oparg - 1) self.space.setitem(w_dict, w_key, w_value) def SET_LINENO(self, lineno, next_instr): @@ -1091,12 +1091,10 @@ @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): - w_set = self.space.call_function(self.space.w_set) - if itemcount: - w_add = self.space.getattr(w_set, self.space.wrap("add")) - for i in range(itemcount): - w_item = self.popvalue() - self.space.call_function(w_add, w_item) + w_set = self.space.newset() + for i in range(itemcount): + w_item = self.popvalue() + self.space.call_method(w_set, 'add', w_item) self.pushvalue(w_set) def STORE_MAP(self, oparg, next_instr): diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py --- a/pypy/interpreter/test/test_eval.py +++ b/pypy/interpreter/test/test_eval.py @@ -15,16 +15,16 @@ self.code = code Frame.__init__(self, space) self.numlocals = numlocals - self.fastlocals_w = [None] * self.numlocals + self._fastlocals_w = [None] * self.numlocals def getcode(self): return self.code def setfastscope(self, scope_w): - self.fastlocals_w = scope_w + self._fastlocals_w = scope_w def getfastscope(self): - return self.fastlocals_w + return self._fastlocals_w def getfastscopelength(self): return self.numlocals @@ -38,11 +38,11 @@ self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({})) - self.f.fastlocals_w[0] = w(5) + self.f._fastlocals_w[0] = w(5) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5})) - self.f.fastlocals_w[2] = w(7) + self.f._fastlocals_w[2] = w(7) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5, 'args': 7})) @@ -57,13 +57,13 @@ w = self.space.wrap self.f.w_locals = self.space.wrap({}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [None]*5) + self.sameList(self.f._fastlocals_w, [None]*5) self.f.w_locals = self.space.wrap({'x': 5}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) + self.sameList(self.f._fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.wrap({'x':5, 'args':7}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), None, w(7), - None, None]) + self.sameList(self.f._fastlocals_w, [w(5), None, w(7), + None, None]) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -203,3 +203,26 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + import sys + class A(object): + def m(self): + "aaa" + m.x = 3 + + bm = A().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.im_class is A + if '__pypy__' in sys.builtin_module_names: + assert bm.__objclass__ is A + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + if '__pypy__' in sys.builtin_module_names: + assert l.append.__objclass__ is list + assert l.__add__.__self__ is l + assert l.__add__.__objclass__ is list diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -761,13 +761,17 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), + __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -703,22 +703,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: @@ -889,7 +895,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -901,7 +907,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -467,13 +469,13 @@ # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,6 +185,13 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -75,12 +75,13 @@ # OS_MATH_SQRT = 100 - def __new__(cls, readonly_descrs_fields, + def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, can_invalidate=False): key = (frozenset(readonly_descrs_fields), + frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, @@ -89,6 +90,7 @@ return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields + result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ extraeffect == EffectInfo.EF_PURE: result.write_descrs_fields = [] @@ -119,7 +121,7 @@ if effects is top_set: return None readonly_descrs_fields = [] - # readonly_descrs_arrays = [] --- not enabled for now + readonly_descrs_arrays = [] write_descrs_fields = [] write_descrs_arrays = [] @@ -145,10 +147,13 @@ elif tup[0] == "array": add_array(write_descrs_arrays, tup) elif tup[0] == "readarray": - pass + tupw = ("array",) + tup[1:] + if tupw not in effects: + add_array(readonly_descrs_arrays, tup) else: assert 0 return EffectInfo(readonly_descrs_fields, + readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect, diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -34,6 +34,15 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays +def test_include_read_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo.write_descrs_fields + assert not effectinfo.write_descrs_arrays + def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) @@ -51,6 +60,16 @@ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.write_descrs_arrays +def test_dont_include_read_and_write_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A)), + ("array", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert not effectinfo.readonly_descrs_arrays + assert not effectinfo.write_descrs_fields + assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLException diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -15,7 +15,7 @@ from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.jit.metainterp.optimize import InvalidLoop -from pypy.jit.metainterp.resume import NUMBERING +from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong def giveup(): @@ -119,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -302,7 +303,7 @@ rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) CNT_INT = -0x20000000 CNT_REF = -0x40000000 @@ -633,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -791,6 +791,7 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -8,8 +8,8 @@ class CachedField(object): def __init__(self): - # Cache information for a field descr. It can be in one - # of two states: + # Cache information for a field descr, or for an (array descr, index) + # pair. It can be in one of two states: # # 1. 'cached_fields' is a dict mapping OptValues of structs # to OptValues of fields. All fields on-heap are @@ -27,19 +27,19 @@ self._lazy_setfield_registered = False def do_setfield(self, optheap, op): - # Update the state with the SETFIELD_GC operation 'op'. + # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) if self.possible_aliasing(optheap, structvalue): self.force_lazy_setfield(optheap) assert not self.possible_aliasing(optheap, structvalue) cached_fieldvalue = self._cached_fields.get(structvalue, None) if cached_fieldvalue is not fieldvalue: # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields list + # myself in the optheap's _lazy_setfields_and_arrayitems list self._lazy_setfield = op if not self._lazy_setfield_registered: - optheap._lazy_setfields.append(self) + optheap._lazy_setfields_and_arrayitems.append(self) self._lazy_setfield_registered = True else: # this is the case where the pending setfield ends up @@ -65,7 +65,7 @@ if self._lazy_setfield is not None: op = self._lazy_setfield assert optheap.getvalue(op.getarg(0)) is structvalue - return optheap.getvalue(op.getarg(1)) + return optheap.getvalue(op.getarglist()[-1]) else: return self._cached_fields.get(structvalue, None) @@ -87,7 +87,7 @@ # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) def get_reconstructed(self, optimizer, valuemap): @@ -100,12 +100,6 @@ return cf -class CachedArrayItems(object): - def __init__(self): - self.fixed_index_items = {} - self.var_index_item = None - self.var_index_indexvalue = None - class BogusPureField(JitException): pass @@ -116,9 +110,10 @@ def __init__(self): # cached fields: {descr: CachedField} self.cached_fields = {} - self._lazy_setfields = [] - # cached array items: {descr: CachedArrayItems} + # cached array items: {array descr: {index: CachedField}} self.cached_arrayitems = {} + # + self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -126,34 +121,23 @@ new = OptHeap() if True: - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() else: assert 0 # was: new.lazy_setfields = self.lazy_setfields for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) - new.cached_arrayitems = {} - for descr, d in self.cached_arrayitems.items(): - newd = {} - new.cached_arrayitems[descr] = newd - for value, cache in d.items(): - newcache = CachedArrayItems() - newd[value.get_reconstructed(optimizer, valuemap)] = newcache - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_reconstructed(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) - for index, fieldvalue in cache.fixed_index_items.items(): - newcache.fixed_index_items[index] = \ - fieldvalue.get_reconstructed(optimizer, valuemap) + for descr, submap in self.cached_arrayitems.items(): + newdict = {} + for index, d in submap.items(): + newdict[index] = d.get_reconstructed(optimizer, valuemap) + new.cached_arrayitems[descr] = newdict return new def clean_caches(self): - del self._lazy_setfields[:] + del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() self.cached_arrayitems.clear() @@ -164,50 +148,16 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): - d = self.cached_arrayitems.get(descr, None) - if d is None: - d = self.cached_arrayitems[descr] = {} - cache = d.get(value, None) - if cache is None: - cache = d[value] = CachedArrayItems() - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - index = indexbox.getint() - if write: - for value, othercache in d.iteritems(): - # fixed index, clean the variable index cache, in case the - # index is the same - othercache.var_index_indexvalue = None - othercache.var_index_item = None - try: - del othercache.fixed_index_items[index] - except KeyError: - pass - cache.fixed_index_items[index] = fieldvalue - else: - if write: - for value, othercache in d.iteritems(): - # variable index, clear all caches for this descr - othercache.var_index_indexvalue = None - othercache.var_index_item = None - othercache.fixed_index_items.clear() - cache.var_index_indexvalue = indexvalue - cache.var_index_item = fieldvalue - - def read_cached_arrayitem(self, descr, value, indexvalue): - d = self.cached_arrayitems.get(descr, None) - if d is None: - return None - cache = d.get(value, None) - if cache is None: - return None - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - return cache.fixed_index_items.get(indexbox.getint(), None) - elif cache.var_index_indexvalue is indexvalue: - return cache.var_index_item - return None + def arrayitem_cache(self, descr, index): + try: + submap = self.cached_arrayitems[descr] + except KeyError: + submap = self.cached_arrayitems[descr] = {} + try: + cf = submap[index] + except KeyError: + cf = submap[index] = CachedField() + return cf def emit_operation(self, op): self.emitting_operation(op) @@ -219,7 +169,8 @@ if op.is_ovf(): return if op.is_guard(): - self.optimizer.pendingfields = self.force_lazy_setfields_for_guard() + self.optimizer.pendingfields = ( + self.force_lazy_setfields_and_arrayitems_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -248,6 +199,8 @@ # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: self.force_lazy_setfield(fielddescr) + for arraydescr in effectinfo.readonly_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: self.force_lazy_setfield(fielddescr) try: @@ -256,8 +209,11 @@ except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) try: - del self.cached_arrayitems[arraydescr] + submap = self.cached_arrayitems[arraydescr] + for cf in submap.itervalues(): + cf._cached_fields.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -266,7 +222,7 @@ # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. return - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() self.clean_caches() @@ -277,6 +233,10 @@ for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] + for submap in self.cached_arrayitems.itervalues(): + for cf in submap.itervalues(): + if value in cf._cached_fields: + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -285,6 +245,14 @@ return cf.force_lazy_setfield(self) + def force_lazy_setarrayitem(self, arraydescr): + try: + submap = self.cached_arrayitems[arraydescr] + except KeyError: + return + for cf in submap.values(): + cf.force_lazy_setfield(self) + def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes # sense to avoid a situation like "int_eq/setfield_gc/guard_true", @@ -309,30 +277,49 @@ newoperations[-2] = lastop newoperations[-1] = prevop - def force_all_lazy_setfields(self): - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + def _assert_valid_cf(self, cf): + # check that 'cf' is in cached_fields or cached_arrayitems + if not we_are_translated(): + if cf not in self.cached_fields.values(): + for submap in self.cached_arrayitems.values(): + if cf in submap.values(): + break + else: + assert 0, "'cf' not in cached_fields/cached_arrayitems" + + def force_all_lazy_setfields_and_arrayitems(self): + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) cf.force_lazy_setfield(self) - def force_lazy_setfields_for_guard(self): + def force_lazy_setfields_and_arrayitems_for_guard(self): pendingfields = [] - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) op = cf._lazy_setfield if op is None: continue # the only really interesting case that we need to handle in the # guards' resume data is that of a virtual object that is stored - # into a field of a non-virtual object. + # into a field of a non-virtual object. Here, 'op' in either + # SETFIELD_GC or SETARRAYITEM_GC. value = self.getvalue(op.getarg(0)) assert not value.is_virtual() # it must be a non-virtual - fieldvalue = self.getvalue(op.getarg(1)) + fieldvalue = self.getvalue(op.getarglist()[-1]) if fieldvalue.is_virtual(): # this is the case that we leave to resume.py + opnum = op.getopnum() + if opnum == rop.SETFIELD_GC: + itemindex = -1 + elif opnum == rop.SETARRAYITEM_GC: + indexvalue = self.getvalue(op.getarg(1)) + assert indexvalue.is_constant() + itemindex = indexvalue.box.getint() + assert itemindex >= 0 + else: + assert 0 pendingfields.append((op.getdescr(), value.box, - fieldvalue.get_key_box())) + fieldvalue.get_key_box(), itemindex)) else: cf.force_lazy_setfield(self) self.fixup_guard_situation() @@ -364,24 +351,45 @@ cf.do_setfield(self, op) def optimize_GETARRAYITEM_GC(self, op): - value = self.getvalue(op.getarg(0)) + arrayvalue = self.getvalue(op.getarg(0)) indexvalue = self.getvalue(op.getarg(1)) - fieldvalue = self.read_cached_arrayitem(op.getdescr(), value, indexvalue) - if fieldvalue is not None: - self.make_equal_to(op.result, fieldvalue) - return - ###self.optimizer.optimize_default(op) + cf = None + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + fieldvalue = cf.getfield_from_cache(self, arrayvalue) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # default case: produce the operation + arrayvalue.ensure_nonnull() self.emit_operation(op) - fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) + # the remember the result of reading the array item + if cf is not None: + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(arrayvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): - self.emit_operation(op) - value = self.getvalue(op.getarg(0)) - fieldvalue = self.getvalue(op.getarg(2)) + if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), + op.getarg(1)], + op.getdescr()): + os.write(2, '[bogus immutable array declaration: %s]\n' % + (op.getdescr().repr_of_descr())) + raise BogusPureField + # indexvalue = self.getvalue(op.getarg(1)) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - write=True) + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + cf.do_setfield(self, op) + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # and then emit the operation + self.emit_operation(op) def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 from pypy.jit.metainterp.optimizeopt.util import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -373,6 +373,15 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -418,5 +427,6 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL + optimize_ops = _findall(OptIntBounds, 'optimize_') propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -121,6 +121,41 @@ print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + class BaseTestOptimizeBasic(BaseTestBasic): @@ -1070,8 +1105,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1436,9 +1471,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) jump(p1, i1, i2, p3) """ @@ -1612,6 +1647,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -1874,7 +1910,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1892,7 +1927,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1910,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2203,23 +2236,6 @@ # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2328,7 +2344,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2349,7 +2364,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2369,7 +2383,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2395,7 +2408,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2420,7 +2433,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2444,7 +2456,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2465,7 +2476,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2486,7 +2496,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2508,7 +2517,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2550,7 +2558,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2576,7 +2583,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2600,9 +2606,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2894,7 +2897,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2940,7 +2942,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2979,7 +2980,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3006,7 +3006,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -4498,6 +4497,29 @@ """ self.optimize_loop(ops, expected) + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py @@ -51,7 +51,7 @@ restype=types.sint) # def calldescr(cpu, FUNC, oopspecindex, extraeffect=None): - einfo = EffectInfo([], [], [], oopspecindex=oopspecindex, + einfo = EffectInfo([], [], [], [], oopspecindex=oopspecindex, extraeffect=extraeffect) return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo) # diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1381,8 +1381,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1806,9 +1806,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -1818,9 +1818,9 @@ # i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -2055,6 +2055,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2741,8 +2742,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -5876,4 +5875,28 @@ escape(p0) jump(p0) """ - self.optimize_loop(ops, expected) \ No newline at end of file + self.optimize_loop(ops, expected) + + def test_setarrayitem_lazy(self): + ops = """ + [i0, i1] + p0 = escape() + i2 = escape() + p1 = new_with_vtable(ConstClass(node_vtable)) + setarrayitem_gc(p0, 2, p1, descr=arraydescr) + guard_true(i2) [] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + expected = """ + [i0, i1] + p0 = escape() + i2 = escape() + guard_true(i2) [p0] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/optimizeopt/test/test_util.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -166,19 +166,19 @@ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [])) + EffectInfo([], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [])) + EffectInfo([], [], [adescr], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [arraydescr])) + EffectInfo([], [], [adescr], [arraydescr])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([adescr], [], [])) + EffectInfo([adescr], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([nextdescr], [], [], + EffectInfo([nextdescr], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), @@ -195,15 +195,15 @@ _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -867,7 +867,7 @@ any_operation = len(self.metainterp.history.operations) > 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jdindex, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -914,8 +914,10 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jd_index, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation + loc = jitdriver_sd.warmstate.get_location_str(greenkey) + debug_print(loc) args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -2,10 +2,12 @@ from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr +from pypy.rpython import annlowlevel from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert @@ -82,6 +84,13 @@ ('nums', lltype.Array(rffi.SHORT))) NUMBERINGP.TO.become(NUMBERING) +PENDINGFIELDSTRUCT = lltype.Struct('PendingField', + ('lldescr', annlowlevel.base_ptr_lltype()), + ('num', rffi.SHORT), + ('fieldnum', rffi.SHORT), + ('itemindex', rffi.INT)) +PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) + TAGMASK = 3 def tag(value, tagbits): @@ -329,7 +338,7 @@ value = values[box] value.get_args_for_fail(self) - for _, box, fieldbox in pending_setfields: + for _, box, fieldbox, _ in pending_setfields: self.register_box(box) self.register_box(fieldbox) value = values[fieldbox] @@ -405,13 +414,25 @@ return False def _add_pending_fields(self, pending_setfields): - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) if pending_setfields: - rd_pendingfields = [] - for descr, box, fieldbox in pending_setfields: + n = len(pending_setfields) + rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) + for i in range(n): + descr, box, fieldbox, itemindex = pending_setfields[i] + lldescr = annlowlevel.cast_instance_to_base_ptr(descr) num = self._gettagged(box) fieldnum = self._gettagged(fieldbox) - rd_pendingfields.append((descr, num, fieldnum)) + # the index is limited to 2147483647 (64-bit machines only) + if itemindex > 2147483647: + from pypy.jit.metainterp import compile + compile.giveup() + itemindex = rffi.cast(rffi.INT, itemindex) + # + rd_pendingfields[i].lldescr = lldescr + rd_pendingfields[i].num = num + rd_pendingfields[i].fieldnum = fieldnum + rd_pendingfields[i].itemindex= itemindex self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): @@ -727,10 +748,28 @@ self.virtuals_cache = [self.virtual_default] * len(virtuals) def _prepare_pendingfields(self, pendingfields): - if pendingfields is not None: - for descr, num, fieldnum in pendingfields: + if pendingfields: + for i in range(len(pendingfields)): + lldescr = pendingfields[i].lldescr + num = pendingfields[i].num + fieldnum = pendingfields[i].fieldnum + itemindex= pendingfields[i].itemindex + descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, + lldescr) struct = self.decode_ref(num) - self.setfield(descr, struct, fieldnum) + itemindex = rffi.cast(lltype.Signed, itemindex) + if itemindex < 0: + self.setfield(descr, struct, fieldnum) + else: + self.setarrayitem(descr, struct, itemindex, fieldnum) + + def setarrayitem(self, arraydescr, array, index, fieldnum): + if arraydescr.is_array_of_pointers(): + self.setarrayitem_ref(arraydescr, array, index, fieldnum) + elif arraydescr.is_array_of_floats(): + self.setarrayitem_float(arraydescr, array, index, fieldnum) + else: + self.setarrayitem_int(arraydescr, array, index, fieldnum) def _prepare_next_section(self, info): # Use info.enumerate_vars(), normally dispatching to @@ -903,15 +942,15 @@ structbox, fieldbox) def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, INT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT) def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, REF) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF) def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) - def setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): + def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): itembox = self.decode_box(fieldnum, kind) self.metainterp.execute_and_record(rop.SETARRAYITEM_GC, arraydescr, arraybox, diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1677,6 +1677,8 @@ res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) self.check_loop_count(9) + self.check_loops(getarrayitem_gc=8, everywhere=True) + py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) def test_multiple_specialied_versions_bridge(self): @@ -2296,6 +2298,21 @@ res = self.meta_interp(f, [1]) assert res == f(1) + def test_remove_array_operations(self): + myjitdriver = JitDriver(greens = [], reds = ['a']) + class W_Int: + def __init__(self, intvalue): + self.intvalue = intvalue + def f(x): + a = [W_Int(x)] + while a[0].intvalue > 0: + myjitdriver.jit_merge_point(a=a) + a[0] = W_Int(a[0].intvalue - 3) + return a[0].intvalue + res = self.meta_interp(f, [100]) + assert res == -2 + #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -49,7 +49,7 @@ x = l[n] l = [3] * 100 l[3] = x - l[3] = x + 1 + l[4] = x + 1 n -= 1 return l[0] diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py --- a/pypy/jit/metainterp/test/test_resume.py +++ b/pypy/jit/metainterp/test/test_resume.py @@ -1238,7 +1238,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, values, 0) assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)]) + modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s, -1)]) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume @@ -1259,6 +1259,106 @@ assert len(expected) == len(trace) assert demo55.next == demo66 +def test_virtual_adder_pending_fields_and_arrayitems(): + class Storage(object): + pass + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier._add_pending_fields([]) + assert not storage.rd_pendingfields + # + class FieldDescr(object): + pass + field_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061)} + modifier._add_pending_fields([(field_a, 42, 61, -1)]) + pf = storage.rd_pendingfields + assert len(pf) == 1 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is field_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + # + array_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061), + 62: rffi.cast(rffi.SHORT, 1062), + 63: rffi.cast(rffi.SHORT, 1063)} + modifier._add_pending_fields([(array_a, 42, 61, 0), + (array_a, 42, 62, 2147483647)]) + pf = storage.rd_pendingfields + assert len(pf) == 2 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[1].num) == 1042 + assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 + assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + # + from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole + py.test.raises(SwitchToBlackhole, modifier._add_pending_fields, + [(array_a, 42, 63, 2147483648)]) + +def test_resume_reader_fields_and_arrayitems(): + class ResumeReader(AbstractResumeDataReader): + def __init__(self, got=None, got_array=None): + self.got = got + self.got_array = got_array + def setfield(self, descr, struct, fieldnum): + assert lltype.typeOf(struct) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got.append((descr, struct, fieldnum)) + def setarrayitem(self, arraydescr, array, index, fieldnum): + assert lltype.typeOf(array) is lltype.Signed + assert lltype.typeOf(index) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got_array.append((arraydescr, array, index, fieldnum)) + def decode_ref(self, num): + return rffi.cast(lltype.Signed, num) * 100 + got = [] + pf = lltype.nullptr(PENDINGFIELDSP.TO) + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [] + # + class FieldDescr(AbstractDescr): + pass + field_a = FieldDescr() + field_b = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 2) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) + pf[0].itemindex = rffi.cast(rffi.INT, -1) + pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) + pf[1].num = rffi.cast(rffi.SHORT, 2042) + pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) + pf[1].itemindex = rffi.cast(rffi.INT, -1) + got = [] + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] + # + array_a = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 1) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) + pf[0].itemindex = rffi.cast(rffi.INT, 123) + got_array = [] + ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + assert got_array == [(array_a, 104200, 123, 1063)] + def test_invalidation_needed(): class options: diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -32,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -294,7 +294,7 @@ break new_frame = space.createframe(code, w_func.w_func_globals, w_func.closure) - new_frame.fastlocals_w[0] = w_item + new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) return result_w diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -900,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/_stackless/test/test_greenlet.py b/pypy/module/_stackless/test/test_greenlet.py --- a/pypy/module/_stackless/test/test_greenlet.py +++ b/pypy/module/_stackless/test/test_greenlet.py @@ -72,6 +72,23 @@ g1 = greenlet(f) raises(ValueError, g2.switch) + + def test_exc_info_save_restore(self): + from _stackless import greenlet + import sys + def f(): + try: + raise ValueError('fun') + except: + exc_info = sys.exc_info() + greenlet(h).switch() + assert exc_info == sys.exc_info() + + def h(): + assert sys.exc_info() == (None, None, None) + + greenlet(f).switch() + def test_exception(self): from _stackless import greenlet import sys diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -39,6 +39,7 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject +import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject import pypy.module.cpyext.longobject @@ -64,6 +65,7 @@ import pypy.module.cpyext.memoryobject import pypy.module.cpyext.codecs import pypy.module.cpyext.pyfile +import pypy.module.cpyext.pystrtod # now that all rffi_platform.Struct types are registered, configure them api.configure_types() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -562,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/pystrtod.py @@ -0,0 +1,68 @@ +import errno +from pypy.interpreter.error import OperationError +from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.pyobject import PyObject +from pypy.rlib import rdtoa +from pypy.rlib import rfloat +from pypy.rlib import rposix +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi + + + at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +def PyOS_string_to_double(space, s, endptr, w_overflow_exception): + """Convert a string s to a double, raising a Python + exception on failure. The set of accepted strings corresponds to + the set of strings accepted by Python's float() constructor, + except that s must not have leading or trailing whitespace. + The conversion is independent of the current locale. + + If endptr is NULL, convert the whole string. Raise + ValueError and return -1.0 if the string is not a valid + representation of a floating-point number. + + If endptr is not NULL, convert as much of the string as + possible and set *endptr to point to the first unconverted + character. If no initial segment of the string is the valid + representation of a floating-point number, set *endptr to point + to the beginning of the string, raise ValueError, and return + -1.0. + + If s represents a value that is too large to store in a float + (for example, "1e500" is such a string on many platforms) then + if overflow_exception is NULL return Py_HUGE_VAL (with + an appropriate sign) and don't set any exception. Otherwise, + overflow_exception must point to a Python exception object; + raise that exception and return -1.0. In both cases, set + *endptr to point to the first character after the converted value. + + If any other error occurs during the conversion (for example an + out-of-memory error), set the appropriate Python exception and + return -1.0. + """ + user_endptr = True + try: + if not endptr: + endptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + user_endptr = False + result = rdtoa.dg_strtod(s, endptr) + endpos = (rffi.cast(rffi.LONG, endptr[0]) - + rffi.cast(rffi.LONG, s)) + if endpos == 0 or (not user_endptr and not endptr[0][0] == '\0'): + raise OperationError( + space.w_ValueError, + space.wrap('invalid input at position %s' % endpos)) + if rposix.get_errno() == errno.ERANGE: + rposix.set_errno(0) + if w_overflow_exception is None: + if result > 0: + return rfloat.INFINITY + else: + return -rfloat.INFINITY + else: + raise OperationError(w_overflow_exception, + space.wrap('value too large')) + return result + finally: + if not user_endptr: + lltype.free(endptr, flavor='raw') diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/setobject.py @@ -0,0 +1,46 @@ +from pypy.interpreter.error import OperationError +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, + build_type_checkers) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, + borrow_from, make_ref, from_ref) +from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall +from pypy.objspace.std.setobject import W_SetObject, newset +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject + + +PySet_Check, PySet_CheckExact = build_type_checkers("Set") + + + at cpython_api([PyObject], PyObject) +def PySet_New(space, w_iterable): + if w_iterable is None: + return space.call_function(space.w_set) + else: + return space.call_function(space.w_set, w_iterable) + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Add(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'add', w_obj) + return 0 + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Discard(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'discard', w_obj) + return 0 + + + at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +def PySet_GET_SIZE(space, w_s): + return space.int_w(space.len(w_s)) + + at cpython_api([PyObject], Py_ssize_t, error=-1) +def PySet_Size(space, ref): + if not PySet_Check(space, ref): + raise OperationError(space.w_TypeError, + space.wrap("expected set object")) + return PySet_GET_SIZE(space, ref) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -480,39 +480,6 @@ """Create a new Python complex number object from a C Py_complex value.""" raise NotImplementedError - at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) -def PyOS_string_to_double(space, s, endptr, overflow_exception): - """Convert a string s to a double, raising a Python - exception on failure. The set of accepted strings corresponds to - the set of strings accepted by Python's float() constructor, - except that s must not have leading or trailing whitespace. - The conversion is independent of the current locale. - - If endptr is NULL, convert the whole string. Raise - ValueError and return -1.0 if the string is not a valid - representation of a floating-point number. - - If endptr is not NULL, convert as much of the string as - possible and set *endptr to point to the first unconverted - character. If no initial segment of the string is the valid - representation of a floating-point number, set *endptr to point - to the beginning of the string, raise ValueError, and return - -1.0. - - If s represents a value that is too large to store in a float - (for example, "1e500" is such a string on many platforms) then - if overflow_exception is NULL return Py_HUGE_VAL (with - an appropriate sign) and don't set any exception. Otherwise, - overflow_exception must point to a Python exception object; - raise that exception and return -1.0. In both cases, set - *endptr to point to the first character after the converted value. - - If any other error occurs during the conversion (for example an - out-of-memory error), set the appropriate Python exception and - return -1.0. - """ - raise NotImplementedError - @cpython_api([rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_strtod(space, nptr, endptr): """Convert a string to a double. This function behaves like the Standard C diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -0,0 +1,93 @@ +import math + +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype + + +class TestPyOS_string_to_double(BaseApiTest): + + def test_simple_float(self, api): + s = rffi.str2charp('0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == 0.4 + rffi.free_charp(s) + + def test_empty_string(self, api): + s = rffi.str2charp('') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_bad_string(self, api): + s = rffi.str2charp(' 0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_overflow_pos(self, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r > 0 + rffi.free_charp(s) + + def test_overflow_neg(self, api): + s = rffi.str2charp('-1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r < 0 + rffi.free_charp(s) + + def test_overflow_exc(self, space, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, space.w_ValueError) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_endptr_number(self, api): + s = rffi.str2charp('0.4') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_tail(self, api): + s = rffi.str2charp('0.4 foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_no_conversion(self, api): + s = rffi.str2charp('foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == -1.0 + raises(ValueError) + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + api.PyErr_Clear() + rffi.free_charp(s) + lltype.free(endp, flavor='raw') diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_setobject.py @@ -0,0 +1,29 @@ +import py + +from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace + + +class TestTupleObject(BaseApiTest): + def test_setobj(self, space, api): + assert not api.PySet_Check(space.w_None) + assert api.PySet_Add(space.w_None, space.w_None) == -1 + api.PyErr_Clear() + w_set = space.call_function(space.w_set) + space.call_method(w_set, 'update', space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + assert api.PySet_GET_SIZE(w_set) == 4 + raises(TypeError, api.PySet_Size(space.newlist([]))) + api.PyErr_Clear() + + def test_set_add_discard(self, space, api): + w_set = api.PySet_New(None) + assert api.PySet_Size(w_set) == 0 + w_set = api.PySet_New(space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + api.PySet_Add(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 5 + api.PySet_Discard(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 4 diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -367,3 +367,14 @@ data, len(u), lltype.nullptr(rffi.CCHARP.TO)) rffi.free_wcharp(data) + def test_format(self, space, api): + w_format = space.wrap(u'hi %s') + w_args = space.wrap((u'test',)) + w_formated = api.PyUnicode_Format(w_format, w_args) + assert space.unwrap(w_formated) == space.unwrap(space.mod(w_format, w_args)) + + def test_join(self, space, api): + w_sep = space.wrap(u'') + w_seq = space.wrap([u'a', u'b']) + w_joined = api.PyUnicode_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == u'ab' diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,6 +7,7 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) + assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -523,3 +523,11 @@ copies sizeof(Py_UNICODE) * length bytes from source to target""" for i in range(0, length): target[i] = source[i] + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Format(space, w_format, w_args): + return space.mod(w_format, w_args) + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -21,6 +21,10 @@ """Return the referenced object from a weak reference. If the referent is no longer live, returns None. This function returns a borrowed reference. """ + return PyWeakref_GET_OBJECT(space, w_ref) + + at cpython_api([PyObject], PyObject) +def PyWeakref_GET_OBJECT(space, w_ref): return borrow_from(w_ref, space.call_function(w_ref)) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/math/__init__.py b/pypy/module/math/__init__.py --- a/pypy/module/math/__init__.py +++ b/pypy/module/math/__init__.py @@ -4,6 +4,7 @@ class Module(MixedModule): appleveldefs = { + 'factorial' : 'app_math.factorial' } interpleveldefs = { @@ -40,7 +41,6 @@ 'isnan' : 'interp_math.isnan', 'trunc' : 'interp_math.trunc', 'fsum' : 'interp_math.fsum', - 'factorial' : 'interp_math.factorial', 'asinh' : 'interp_math.asinh', 'acosh' : 'interp_math.acosh', 'atanh' : 'interp_math.atanh', diff --git a/pypy/module/math/app_math.py b/pypy/module/math/app_math.py new file mode 100644 --- /dev/null +++ b/pypy/module/math/app_math.py @@ -0,0 +1,13 @@ +def factorial(x): + """Find x!.""" + if isinstance(x, float): + fl = int(x) + if fl != x: + raise ValueError("float arguments must be integral") + x = fl + if x < 0: + raise ValueError("x must be >= 0") + res = 1 + for i in range(1, x + 1): + res *= i + return res diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -373,22 +373,6 @@ hi = v return space.wrap(hi) -def factorial(space, w_x): - """Find x!.""" - if space.isinstance_w(w_x, space.w_float): - fl = space.float_w(w_x) - if math.floor(fl) != fl: - raise OperationError(space.w_ValueError, - space.wrap("float arguments must be integral")) - w_x = space.long(w_x) - x = space.int_w(w_x) - if x < 0: - raise OperationError(space.w_ValueError, space.wrap("x must be >= 0")) - w_res = space.wrap(1) - for i in range(1, x + 1): - w_res = space.mul(w_res, space.wrap(i)) - return w_res - def log1p(space, w_x): """Find log(x + 1).""" return math1(space, rfloat.log1p, w_x) diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -21,8 +21,7 @@ from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes PyFrame._virtualizable2_ = ['last_instr', 'pycode', - 'valuestackdepth', 'valuestack_w[*]', - 'fastlocals_w[*]', + 'valuestackdepth', 'locals_stack_w[*]', 'last_exception', 'lastblock', 'is_being_profiled', diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -15,7 +15,7 @@ if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', 'posix', '_socket', '_sre', '_lsprof', '_weakref', - '__pypy__']: + '__pypy__', 'cStringIO']: return True return False diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -58,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -46,7 +46,7 @@ guard_no_overflow(descr=) i18 = int_add(i7, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) """) def test_array_intimg(self): @@ -83,7 +83,7 @@ setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) i28 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -187,7 +187,7 @@ guard_no_overflow(descr=) i18 = force_token() --TICK-- - jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) """) def test_default_and_kw(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py --- a/pypy/module/pypyjit/test_pypy_c/test_intbound.py +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -97,7 +97,7 @@ guard_no_overflow(descr=...) i17 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) """) def test_intbound_sub_lt(self): @@ -149,7 +149,7 @@ guard_no_overflow(descr=...) i19 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) """) def test_intbound_addmul_ge(self): @@ -177,7 +177,7 @@ guard_no_overflow(descr=...) i21 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) """) def test_intbound_eq(self): @@ -209,7 +209,7 @@ guard_no_overflow(descr=...) i16 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) """) def test_intbound_mul(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -167,7 +167,7 @@ guard_false(i16, descr=) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) + setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, 146982464, descr=) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) @@ -179,7 +179,7 @@ i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -384,8 +384,9 @@ # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) - stack_items_w = self.crnt_frame.valuestack_w - for i in range(self.crnt_frame.valuestackdepth-1, -1, -1): + f = self.crnt_frame + stack_items_w = f.locals_stack_w + for i in range(f.valuestackdepth-1, f.nlocals-1, -1): w_v = stack_items_w[i] if isinstance(w_v, Constant): if w_v.value is oldvalue: diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py --- a/pypy/objspace/flow/framestate.py +++ b/pypy/objspace/flow/framestate.py @@ -10,7 +10,7 @@ def __init__(self, state): if isinstance(state, PyFrame): # getfastscope() can return real None, for undefined locals - data = state.getfastscope() + state.savevaluestack() + data = state.save_locals_stack() if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -36,11 +36,9 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): - fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) # Nones == undefined locals - frame.restorevaluestack(data[fastlocals:-2]) + frame.restore_locals_stack(data[:-2]) # Nones == undefined locals if data[-2] == Constant(None): assert data[-1] == Constant(None) frame.last_exception = None diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py --- a/pypy/objspace/flow/test/test_framestate.py +++ b/pypy/objspace/flow/test/test_framestate.py @@ -25,7 +25,7 @@ dummy = Constant(None) #dummy.dummy = True arg_list = ([Variable() for i in range(formalargcount)] + - [dummy] * (len(frame.fastlocals_w) - formalargcount)) + [dummy] * (frame.nlocals - formalargcount)) frame.setfastscope(arg_list) return frame @@ -42,7 +42,7 @@ def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1 != fs2 @@ -55,7 +55,7 @@ def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general @@ -63,7 +63,7 @@ def test_restore_frame(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs1.restoreframe(frame) assert fs1 == FrameState(frame) @@ -82,25 +82,26 @@ def test_getoutputargs(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable - # fastlocals_w[-1] -> fastlocals_w[-1] is Constant(None) - assert outputargs == [frame.fastlocals_w[0], Constant(None)] + # locals_w[n-1] -> locals_w[n-1] is Constant(None) + assert outputargs == [frame.locals_stack_w[0], Constant(None)] def test_union_different_constants(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(42) + frame.locals_stack_w[frame.nlocals-1] = Constant(42) fs2 = FrameState(frame) fs3 = fs1.union(fs2) fs3.restoreframe(frame) - assert isinstance(frame.fastlocals_w[-1], Variable) # generalized + assert isinstance(frame.locals_stack_w[frame.nlocals-1], Variable) + # ^^^ generalized def test_union_spectag(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(SpecTag()) + frame.locals_stack_w[frame.nlocals-1] = Constant(SpecTag()) fs2 = FrameState(frame) assert fs1.union(fs2) is None # UnionError diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,13 +1,14 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.debug import mark_dict_non_null def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -59,7 +60,8 @@ def initialize_as_rdict(self): assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) + self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) return self.r_dict_content @@ -308,6 +310,7 @@ def __init__(self, space): self.space = space self.content = {} + mark_dict_non_null(self.content) def impl_setitem(self, w_key, w_value): space = self.space @@ -317,6 +320,7 @@ self._as_rdict().impl_fallback_setitem(w_key, w_value) def impl_setitem_str(self, key, w_value): + assert key is not None self.content[key] = w_value def impl_setdefault(self, w_key, w_default): @@ -342,6 +346,7 @@ return len(self.content) def impl_getitem_str(self, key): + assert key is not None return self.content.get(key, None) def impl_getitem(self, w_key): diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -311,6 +311,10 @@ classofinstance=classofinstance, strdict=strdict) + def newset(self): + from pypy.objspace.std.setobject import newset + return W_SetObject(self, newset(self)) + def newslice(self, w_start, w_end, w_step): return W_SliceObject(w_start, w_end, w_step) diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -50,6 +50,10 @@ u = self.space.wrap(set('simsalabim')) assert self.space.eq_w(s,u) + def test_space_newset(self): + s = self.space.newset() + assert self.space.str_w(self.space.repr(s)) == 'set([])' + class AppTestAppSetTest: def test_subtype(self): class subset(set):pass diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -272,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -151,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) @@ -833,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -845,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,23 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + class Cls(self.AddressStack): + def append(self2, addr): + assert addr not in self2.tolist() + self.AddressStack.append(self2, addr) + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +637,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +655,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +698,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +789,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +882,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +922,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,11 +933,11 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded self.remember_young_pointer_from_array2(addr_array, index) else: @@ -943,20 +955,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -980,16 +995,18 @@ # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,9 +1019,7 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return @@ -1016,7 +1031,7 @@ addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True @@ -1026,9 +1041,6 @@ # xxx trying it out for the JIT: a 3-arguments version of the above def remember_young_pointer_from_array3(addr_array, index, newvalue): - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") objhdr = self.header(addr_array) # # a single check for the common case of neither GCFLAG_HAS_CARDS @@ -1044,8 +1056,8 @@ else: # case with cards. # - # If the newly written address does not actually point to the - # nursery, leave now. + # If the newly written address does not actually point to a + # young object, leave now. if not self.appears_to_be_young(newvalue): return # @@ -1056,46 +1068,53 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + \ - (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True assert self.card_page_indices > 0 self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1103,15 +1122,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1119,6 +1159,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1135,20 +1191,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1181,7 +1245,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1189,7 +1253,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1205,11 +1269,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1245,19 +1309,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1296,7 +1371,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1343,11 +1430,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,78 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag + # + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert not res # there might be young ptrs, let ll_arraycopy to find them + + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -884,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,29 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): @@ -860,6 +883,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -121,6 +121,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -220,6 +223,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -168,7 +168,7 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' From noreply at buildbot.pypy.org Sat Jul 2 12:03:58 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 12:03:58 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Kill a few dependencies and move this file to the general section Message-ID: <20110702100358.B7ED782940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45259:ed878f98c383 Date: 2011-07-01 18:28 +0200 http://bitbucket.org/pypy/pypy/changeset/ed878f98c383/ Log: Kill a few dependencies and move this file to the general section pypy/tool/algo. diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/tool/algo/regalloc.py rename from pypy/jit/codewriter/regalloc.py rename to pypy/tool/algo/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/tool/algo/regalloc.py @@ -2,13 +2,11 @@ from pypy.objspace.flow.model import Variable from pypy.tool.algo.color import DependencyGraph from pypy.tool.algo.unionfind import UnionFind -from pypy.jit.metainterp.history import getkind -from pypy.jit.codewriter.flatten import ListOfKind -def perform_register_allocation(graph, kind): +def perform_register_allocation(graph, consider_var, ListOfKind=()): """Perform register allocation for the Variables of the given 'kind' in the 'graph'.""" - regalloc = RegAllocator(graph, kind) + regalloc = RegAllocator(graph, consider_var, ListOfKind) regalloc.make_dependencies() regalloc.coalesce_variables() regalloc.find_node_coloring() @@ -18,9 +16,10 @@ class RegAllocator(object): DEBUG_REGALLOC = False - def __init__(self, graph, kind): + def __init__(self, graph, consider_var, ListOfKind): self.graph = graph - self.kind = kind + self.consider_var = consider_var + self.ListOfKind = ListOfKind def make_dependencies(self): dg = DependencyGraph() @@ -31,7 +30,7 @@ for v in op.args: if isinstance(v, Variable): die_at[v] = i - elif isinstance(v, ListOfKind): + elif isinstance(v, self.ListOfKind): for v1 in v: if isinstance(v1, Variable): die_at[v1] = i @@ -51,7 +50,7 @@ # Done. XXX the code above this line runs 3 times # (for kind in KINDS) to produce the same result... livevars = [v for v in block.inputargs - if getkind(v.concretetype) == self.kind] + if self.consider_var(v)] # Add the variables of this block to the dependency graph for i, v in enumerate(livevars): dg.add_node(v) @@ -67,10 +66,10 @@ pass die_index += 1 if (op.result is not None and - getkind(op.result.concretetype) == self.kind): + self.consider_var(op.result)): dg.add_node(op.result) for v in livevars: - if getkind(v.concretetype) == self.kind: + if self.consider_var(v): dg.add_edge(v, op.result) livevars.add(op.result) self._depgraph = dg @@ -95,7 +94,7 @@ self._try_coalesce(v, link.target.inputargs[i]) def _try_coalesce(self, v, w): - if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: + if isinstance(v, Variable) and self.consider_var(v): dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) From noreply at buildbot.pypy.org Sat Jul 2 12:03:59 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 12:03:59 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Add this as a redirecting stub. Message-ID: <20110702100359.F384882940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45260:0cdaf4c98369 Date: 2011-07-01 18:28 +0200 http://bitbucket.org/pypy/pypy/changeset/0cdaf4c98369/ Log: Add this as a redirecting stub. diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py new file mode 100644 --- /dev/null +++ b/pypy/jit/codewriter/regalloc.py @@ -0,0 +1,8 @@ +from pypy.tool.algo import regalloc +from pypy.jit.metainterp.history import getkind +from pypy.jit.codewriter.flatten import ListOfKind + + +def perform_register_allocation(graph, kind): + checkkind = lambda v: getkind(v.concretetype) == kind + return regalloc.perform_register_allocation(graph, checkkind, ListOfKind) From noreply at buildbot.pypy.org Sat Jul 2 12:04:01 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 12:04:01 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Rewrite the gc_push_roots/gc_pop_roots logic, first version. Message-ID: <20110702100401.44FAE82940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45261:4a40f7db1471 Date: 2011-07-02 12:11 +0200 http://bitbucket.org/pypy/pypy/changeset/4a40f7db1471/ Log: Rewrite the gc_push_roots/gc_pop_roots logic, first version. This acquires a bunch of locations at the start of the function, and releases them only at the end. diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -1018,7 +1018,11 @@ def op_raw_store(self, addr, typ, offset, value): checkadr(addr) - assert lltype.typeOf(value) == typ + if typ is llmemory.Address: + if lltype.typeOf(value) != typ: + value = llmemory.cast_ptr_to_adr(value) + else: + assert lltype.typeOf(value) == typ getattr(addr, str(typ).lower())[offset] = value def op_stack_malloc(self, size): # mmh diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -250,9 +250,13 @@ [annmodel.SomeInteger()], annmodel.SomeAddress(), inline = True) + self.get_stack_top_ptr = getfn(root_walker.get_stack_top, + [], annmodel.SomeAddress(), + inline = True) else: self.incr_stack_ptr = None self.decr_stack_ptr = None + self.get_stack_top_ptr = None self.weakref_deref_ptr = self.inittime_helper( ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address) @@ -525,7 +529,11 @@ self.c_vtinfo_skip_offset = rmodel.inputconst(lltype.typeOf(sko), sko) def build_root_walker(self): - return ShadowStackRootWalker(self) + from pypy.rpython.memory.gctransform import shadowstack + return shadowstack.ShadowStackRootWalker(self) + + def postprocess_graph(self, graph): + self.root_walker.postprocess_graph(self, graph) def consider_constant(self, TYPE, value): self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc) @@ -1182,35 +1190,16 @@ if self.incr_stack_ptr is None: return livevars = self.get_livevars_for_roots(hop, keep_current_args) - self.num_pushs += len(livevars) - if not livevars: - return [] - c_len = rmodel.inputconst(lltype.Signed, len(livevars) ) - base_addr = hop.genop("direct_call", [self.incr_stack_ptr, c_len ], - resulttype=llmemory.Address) - c_type = rmodel.inputconst(lltype.Void, llmemory.Address) - for k,var in enumerate(livevars): - c_k = rmodel.inputconst(lltype.Signed, k) - v_adr = gen_cast(hop.llops, llmemory.Address, var) - hop.genop("raw_store", [base_addr, c_type, c_k, v_adr]) + if livevars: + self.num_pushs += len(livevars) + hop.genop("gc_push_roots", livevars) return livevars def pop_roots(self, hop, livevars): if self.decr_stack_ptr is None: return - if not livevars: - return - c_len = rmodel.inputconst(lltype.Signed, len(livevars) ) - base_addr = hop.genop("direct_call", [self.decr_stack_ptr, c_len ], - resulttype=llmemory.Address) - if self.gcdata.gc.moving_gc: - # for moving collectors, reload the roots into the local variables - c_type = rmodel.inputconst(lltype.Void, llmemory.Address) - for k,var in enumerate(livevars): - c_k = rmodel.inputconst(lltype.Signed, k) - v_newaddr = hop.genop("raw_load", [base_addr, c_type, c_k], - resulttype=llmemory.Address) - hop.genop("gc_reload_possibly_moved", [v_newaddr, var]) + if livevars: + hop.genop("gc_pop_roots", livevars) def compute_borrowed_vars(self, graph): # XXX temporary workaround, should be done more correctly @@ -1324,215 +1313,5 @@ raise Exception("%s does not support threads" % ( self.__class__.__name__,)) - -class ShadowStackRootWalker(BaseRootWalker): - need_root_stack = True - collect_stacks_from_other_threads = None - - def __init__(self, gctransformer): - BaseRootWalker.__init__(self, gctransformer) - self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth - # NB. 'self' is frozen, but we can use self.gcdata to store state - gcdata = self.gcdata - - def incr_stack(n): - top = gcdata.root_stack_top - gcdata.root_stack_top = top + n*sizeofaddr - return top - self.incr_stack = incr_stack - - def decr_stack(n): - top = gcdata.root_stack_top - n*sizeofaddr - gcdata.root_stack_top = top - return top - self.decr_stack = decr_stack - - self.rootstackhook = gctransformer.root_stack_jit_hook - if self.rootstackhook is None: - def collect_stack_root(callback, gc, addr): - if gc.points_to_valid_gc_object(addr): - callback(gc, addr) - return sizeofaddr - self.rootstackhook = collect_stack_root - - def push_stack(self, addr): - top = self.incr_stack(1) - top.address[0] = addr - - def pop_stack(self): - top = self.decr_stack(1) - return top.address[0] - - def allocate_stack(self): - return llmemory.raw_malloc(self.rootstacksize) - - def setup_root_walker(self): - stackbase = self.allocate_stack() - ll_assert(bool(stackbase), "could not allocate root stack") - self.gcdata.root_stack_top = stackbase - self.gcdata.root_stack_base = stackbase - BaseRootWalker.setup_root_walker(self) - - def walk_stack_roots(self, collect_stack_root): - gcdata = self.gcdata - gc = self.gc - rootstackhook = self.rootstackhook - addr = gcdata.root_stack_base - end = gcdata.root_stack_top - while addr != end: - addr += rootstackhook(collect_stack_root, gc, addr) - if self.collect_stacks_from_other_threads is not None: - self.collect_stacks_from_other_threads(collect_stack_root) - - def need_thread_support(self, gctransformer, getfn): - from pypy.module.thread import ll_thread # xxx fish - from pypy.rpython.memory.support import AddressDict - from pypy.rpython.memory.support import copy_without_null_values - gcdata = self.gcdata - # the interfacing between the threads and the GC is done via - # three completely ad-hoc operations at the moment: - # gc_thread_prepare, gc_thread_run, gc_thread_die. - # See docstrings below. - - def get_aid(): - """Return the thread identifier, cast to an (opaque) address.""" - return llmemory.cast_int_to_adr(ll_thread.get_ident()) - - def thread_setup(): - """Called once when the program starts.""" - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} - gcdata._fresh_rootstack = llmemory.NULL - gcdata.dead_threads_count = 0 - - def thread_prepare(): - """Called just before thread.start_new_thread(). This - allocates a new shadow stack to be used by the future - thread. If memory runs out, this raises a MemoryError - (which can be handled by the caller instead of just getting - ignored if it was raised in the newly starting thread). - """ - if not gcdata._fresh_rootstack: - gcdata._fresh_rootstack = self.allocate_stack() - if not gcdata._fresh_rootstack: - raise MemoryError - - def thread_run(): - """Called whenever the current thread (re-)acquired the GIL. - This should ensure that the shadow stack installed in - gcdata.root_stack_top/root_stack_base is the one corresponding - to the current thread. - """ - aid = get_aid() - if gcdata.active_thread != aid: - switch_shadow_stacks(aid) - - def thread_die(): - """Called just before the final GIL release done by a dying - thread. After a thread_die(), no more gc operation should - occur in this thread. - """ - aid = get_aid() - if aid == gcdata.main_thread: - return # ignore calls to thread_die() in the main thread - # (which can occur after a fork()). - gcdata.thread_stacks.setitem(aid, llmemory.NULL) - old = gcdata.root_stack_base - if gcdata._fresh_rootstack == llmemory.NULL: - gcdata._fresh_rootstack = old - else: - llmemory.raw_free(old) - install_new_stack(gcdata.main_thread) - # from time to time, rehash the dictionary to remove - # old NULL entries - gcdata.dead_threads_count += 1 - if (gcdata.dead_threads_count & 511) == 0: - gcdata.thread_stacks = copy_without_null_values( - gcdata.thread_stacks) - - def switch_shadow_stacks(new_aid): - save_away_current_stack() - install_new_stack(new_aid) - switch_shadow_stacks._dont_inline_ = True - - def save_away_current_stack(): - old_aid = gcdata.active_thread - # save root_stack_base on the top of the stack - self.push_stack(gcdata.root_stack_base) - # store root_stack_top into the dictionary - gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) - - def install_new_stack(new_aid): - # look for the new stack top - top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) - if top == llmemory.NULL: - # first time we see this thread. It is an error if no - # fresh new stack is waiting. - base = gcdata._fresh_rootstack - gcdata._fresh_rootstack = llmemory.NULL - ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") - gcdata.root_stack_top = base - gcdata.root_stack_base = base - else: - # restore the root_stack_base from the top of the stack - gcdata.root_stack_top = top - gcdata.root_stack_base = self.pop_stack() - # done - gcdata.active_thread = new_aid - - def collect_stack(aid, stacktop, callback): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - # collect all valid stacks from the dict (the entry - # corresponding to the current thread is not valid) - gc = self.gc - rootstackhook = self.rootstackhook - end = stacktop - sizeofaddr - addr = end.address[0] - while addr != end: - addr += rootstackhook(callback, gc, addr) - - def collect_more_stacks(callback): - ll_assert(get_aid() == gcdata.active_thread, - "collect_more_stacks(): invalid active_thread") - gcdata.thread_stacks.foreach(collect_stack, callback) - - def _free_if_not_current(aid, stacktop, _): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - end = stacktop - sizeofaddr - base = end.address[0] - llmemory.raw_free(base) - - def thread_after_fork(result_of_fork, opaqueaddr): - # we don't need a thread_before_fork in this case, so - # opaqueaddr == NULL. This is called after fork(). - if result_of_fork == 0: - # We are in the child process. Assumes that only the - # current thread survived, so frees the shadow stacks - # of all the other ones. - gcdata.thread_stacks.foreach(_free_if_not_current, None) - # Clears the dict (including the current thread, which - # was an invalid entry anyway and will be recreated by - # the next call to save_away_current_stack()). - gcdata.thread_stacks.clear() - # Finally, reset the stored thread IDs, in case it - # changed because of fork(). Also change the main - # thread to the current one (because there is not any - # other left). - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - - self.thread_setup = thread_setup - self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) - self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, - inline=True) - # no thread_start_ptr here - self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) - # no thread_before_fork_ptr here - self.thread_after_fork_ptr = getfn(thread_after_fork, - [annmodel.SomeInteger(), - annmodel.SomeAddress()], - annmodel.s_None) - self.collect_stacks_from_other_threads = collect_more_stacks + def postprocess_graph(self, gct, graph): + pass diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py new file mode 100644 --- /dev/null +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -0,0 +1,310 @@ +from pypy.rpython.rtyper import LowLevelOpList +from pypy.rpython.memory.gctransform.framework import BaseRootWalker +from pypy.rpython.memory.gctransform.framework import sizeofaddr +from pypy.rpython import rmodel +from pypy.rlib.debug import ll_assert +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.tool.algo.regalloc import perform_register_allocation +from pypy.translator.backendopt.ssa import DataFlowFamilyBuilder +from pypy.translator.unsimplify import copyvar +from pypy.objspace.flow.model import Block, Link, checkgraph + + +class ShadowStackRootWalker(BaseRootWalker): + need_root_stack = True + collect_stacks_from_other_threads = None + + def __init__(self, gctransformer): + BaseRootWalker.__init__(self, gctransformer) + self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth + # NB. 'self' is frozen, but we can use self.gcdata to store state + gcdata = self.gcdata + + def incr_stack(n): + top = gcdata.root_stack_top + gcdata.root_stack_top = top + n*sizeofaddr + return top + self.incr_stack = incr_stack + + def decr_stack(n): + top = gcdata.root_stack_top - n*sizeofaddr + gcdata.root_stack_top = top + return top + self.decr_stack = decr_stack + + def get_stack_top(): + return gcdata.root_stack_top + self.get_stack_top = get_stack_top + + self.rootstackhook = gctransformer.root_stack_jit_hook + if self.rootstackhook is None: + def collect_stack_root(callback, gc, addr): + if gc.points_to_valid_gc_object(addr): + callback(gc, addr) + return sizeofaddr + self.rootstackhook = collect_stack_root + + def push_stack(self, addr): + top = self.incr_stack(1) + top.address[0] = addr + + def pop_stack(self): + top = self.decr_stack(1) + return top.address[0] + + def allocate_stack(self): + return llmemory.raw_malloc(self.rootstacksize) + + def setup_root_walker(self): + stackbase = self.allocate_stack() + ll_assert(bool(stackbase), "could not allocate root stack") + self.gcdata.root_stack_top = stackbase + self.gcdata.root_stack_base = stackbase + BaseRootWalker.setup_root_walker(self) + + def walk_stack_roots(self, collect_stack_root): + gcdata = self.gcdata + gc = self.gc + rootstackhook = self.rootstackhook + addr = gcdata.root_stack_base + end = gcdata.root_stack_top + while addr != end: + addr += rootstackhook(collect_stack_root, gc, addr) + if self.collect_stacks_from_other_threads is not None: + self.collect_stacks_from_other_threads(collect_stack_root) + + def need_thread_support(self, gctransformer, getfn): + from pypy.module.thread import ll_thread # xxx fish + from pypy.rpython.memory.support import AddressDict + from pypy.rpython.memory.support import copy_without_null_values + gcdata = self.gcdata + # the interfacing between the threads and the GC is done via + # three completely ad-hoc operations at the moment: + # gc_thread_prepare, gc_thread_run, gc_thread_die. + # See docstrings below. + + def get_aid(): + """Return the thread identifier, cast to an (opaque) address.""" + return llmemory.cast_int_to_adr(ll_thread.get_ident()) + + def thread_setup(): + """Called once when the program starts.""" + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} + gcdata._fresh_rootstack = llmemory.NULL + gcdata.dead_threads_count = 0 + + def thread_prepare(): + """Called just before thread.start_new_thread(). This + allocates a new shadow stack to be used by the future + thread. If memory runs out, this raises a MemoryError + (which can be handled by the caller instead of just getting + ignored if it was raised in the newly starting thread). + """ + if not gcdata._fresh_rootstack: + gcdata._fresh_rootstack = self.allocate_stack() + if not gcdata._fresh_rootstack: + raise MemoryError + + def thread_run(): + """Called whenever the current thread (re-)acquired the GIL. + This should ensure that the shadow stack installed in + gcdata.root_stack_top/root_stack_base is the one corresponding + to the current thread. + """ + aid = get_aid() + if gcdata.active_thread != aid: + switch_shadow_stacks(aid) + + def thread_die(): + """Called just before the final GIL release done by a dying + thread. After a thread_die(), no more gc operation should + occur in this thread. + """ + aid = get_aid() + if aid == gcdata.main_thread: + return # ignore calls to thread_die() in the main thread + # (which can occur after a fork()). + gcdata.thread_stacks.setitem(aid, llmemory.NULL) + old = gcdata.root_stack_base + if gcdata._fresh_rootstack == llmemory.NULL: + gcdata._fresh_rootstack = old + else: + llmemory.raw_free(old) + install_new_stack(gcdata.main_thread) + # from time to time, rehash the dictionary to remove + # old NULL entries + gcdata.dead_threads_count += 1 + if (gcdata.dead_threads_count & 511) == 0: + gcdata.thread_stacks = copy_without_null_values( + gcdata.thread_stacks) + + def switch_shadow_stacks(new_aid): + save_away_current_stack() + install_new_stack(new_aid) + switch_shadow_stacks._dont_inline_ = True + + def save_away_current_stack(): + old_aid = gcdata.active_thread + # save root_stack_base on the top of the stack + self.push_stack(gcdata.root_stack_base) + # store root_stack_top into the dictionary + gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) + + def install_new_stack(new_aid): + # look for the new stack top + top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) + if top == llmemory.NULL: + # first time we see this thread. It is an error if no + # fresh new stack is waiting. + base = gcdata._fresh_rootstack + gcdata._fresh_rootstack = llmemory.NULL + ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") + gcdata.root_stack_top = base + gcdata.root_stack_base = base + else: + # restore the root_stack_base from the top of the stack + gcdata.root_stack_top = top + gcdata.root_stack_base = self.pop_stack() + # done + gcdata.active_thread = new_aid + + def collect_stack(aid, stacktop, callback): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + # collect all valid stacks from the dict (the entry + # corresponding to the current thread is not valid) + gc = self.gc + rootstackhook = self.rootstackhook + end = stacktop - sizeofaddr + addr = end.address[0] + while addr != end: + addr += rootstackhook(callback, gc, addr) + + def collect_more_stacks(callback): + ll_assert(get_aid() == gcdata.active_thread, + "collect_more_stacks(): invalid active_thread") + gcdata.thread_stacks.foreach(collect_stack, callback) + + def _free_if_not_current(aid, stacktop, _): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + end = stacktop - sizeofaddr + base = end.address[0] + llmemory.raw_free(base) + + def thread_after_fork(result_of_fork, opaqueaddr): + # we don't need a thread_before_fork in this case, so + # opaqueaddr == NULL. This is called after fork(). + if result_of_fork == 0: + # We are in the child process. Assumes that only the + # current thread survived, so frees the shadow stacks + # of all the other ones. + gcdata.thread_stacks.foreach(_free_if_not_current, None) + # Clears the dict (including the current thread, which + # was an invalid entry anyway and will be recreated by + # the next call to save_away_current_stack()). + gcdata.thread_stacks.clear() + # Finally, reset the stored thread IDs, in case it + # changed because of fork(). Also change the main + # thread to the current one (because there is not any + # other left). + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + + self.thread_setup = thread_setup + self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) + self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, + inline=True) + # no thread_start_ptr here + self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) + # no thread_before_fork_ptr here + self.thread_after_fork_ptr = getfn(thread_after_fork, + [annmodel.SomeInteger(), + annmodel.SomeAddress()], + annmodel.s_None) + self.collect_stacks_from_other_threads = collect_more_stacks + + + def postprocess_graph(self, gct, graph): + """Collect information about the gc_push_roots and gc_pop_roots + added in this complete graph, and replace them with real operations. + """ + # + # Use the SSA builder to find "spans" of variables that come a + # single point but may extend over several blocks. + spans = DataFlowFamilyBuilder(graph).get_variable_families() + interesting_vars = set() + for block in graph.iterblocks(): + for op in block.operations: + if op.opname in ('gc_push_roots', 'gc_pop_roots'): + for v in op.args: + interesting_vars.add(spans.find_rep(v)) + if not interesting_vars: + return + # + def is_interesting(v): + return spans.find_rep(v) in interesting_vars + regalloc = perform_register_allocation(graph, is_interesting) + numcolors = max([regalloc.getcolor(v) for v in interesting_vars]) + 1 + # + # Compute the set of "useless stores", i.e. the Variables in the + # gc_push_roots that are storing the same value as the one previously + # loaded from the same index. + #useless_stores = self.compute_useless_stores(graph) + # + # Put at the start of the graph: "incr_stack(); fill with zeroes" + llops = LowLevelOpList() + c_numcolors = rmodel.inputconst(lltype.Signed, numcolors) + base_addr = llops.genop("direct_call", [gct.incr_stack_ptr, + c_numcolors], + resulttype=llmemory.Address) + c_type = rmodel.inputconst(lltype.Void, llmemory.Address) + c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL) + for k in range(numcolors): + c_k = rmodel.inputconst(lltype.Signed, k) + llops.genop("raw_store", [base_addr, c_type, c_k, c_null]) + graph.startblock.operations[:0] = llops + # + # Put at the end of the graph: "decr_stack()" + llops = LowLevelOpList() + llops.genop("direct_call", [gct.decr_stack_ptr, c_numcolors], + resulttype=llmemory.Address) + block = graph.returnblock + block.operations = list(llops) + [v_return] = block.inputargs + v_return2 = copyvar(gct.translator.annotator, v_return) + newexitblock = Block([v_return2]) + newexitblock.operations = () + newexitblock.exits = () + block.recloseblock(Link([v_return], newexitblock)) + graph.returnblock = newexitblock + # + # We replace gc_push_roots/gc_pop_roots with individual + # operations raw_store/raw_load + for block in graph.iterblocks(): + if block.operations == (): + continue + llops = LowLevelOpList() + for op in block.operations: + if op.opname not in ("gc_push_roots", "gc_pop_roots"): + llops.append(op) + continue + top_addr = llops.genop("direct_call", + [gct.get_stack_top_ptr], + resulttype=llmemory.Address) + for v in op.args: + k = regalloc.getcolor(v) - numcolors + assert -numcolors <= k < 0 + c_k = rmodel.inputconst(lltype.Signed, k) + if op.opname == "gc_push_roots": + llops.genop("raw_store", [top_addr, c_type, c_k, v]) + else: + v_newaddr = llops.genop("raw_load", + [top_addr, c_type, c_k], + resulttype=llmemory.Address) + llops.genop("gc_reload_possibly_moved", [v_newaddr, v]) + block.operations[:] = llops + # + checkgraph(graph) diff --git a/pypy/rpython/memory/gctransform/transform.py b/pypy/rpython/memory/gctransform/transform.py --- a/pypy/rpython/memory/gctransform/transform.py +++ b/pypy/rpython/memory/gctransform/transform.py @@ -259,6 +259,8 @@ else: insert_empty_block(self.translator.annotator, link, llops) + self.postprocess_graph(graph) + # remove the empty block at the start of the graph, which should # still be empty (but let's check) if starts_with_empty_block(graph) and inserted_empty_startblock: @@ -277,6 +279,9 @@ graph.exc_cleanup = (v, list(llops)) return is_borrowed # xxx for tests only + def postprocess_graph(self, graph): + pass + def annotate_helper(self, ll_helper, ll_args, ll_result, inline=False): assert not self.finished_helpers args_s = map(annmodel.lltype_to_annotation, ll_args) diff --git a/pypy/tool/algo/regalloc.py b/pypy/tool/algo/regalloc.py --- a/pypy/tool/algo/regalloc.py +++ b/pypy/tool/algo/regalloc.py @@ -94,7 +94,8 @@ self._try_coalesce(v, link.target.inputargs[i]) def _try_coalesce(self, v, w): - if isinstance(v, Variable) and self.consider_var(v): + if (isinstance(v, Variable) and self.consider_var(v) + and self.consider_var(w)): dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) From noreply at buildbot.pypy.org Sat Jul 2 12:39:57 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 12:39:57 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Avoid useless stores. Not really unit-tested :-/ At least Message-ID: <20110702103957.6D2AB82940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45262:745670afcd4d Date: 2011-07-02 12:47 +0200 http://bitbucket.org/pypy/pypy/changeset/745670afcd4d/ Log: Avoid useless stores. Not really unit-tested :-/ At least it seems that test_transformed_gc passes. diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -188,6 +188,7 @@ gcdata.set_query_functions(gcdata.gc) gcdata.gc.set_root_walker(root_walker) self.num_pushs = 0 + self.num_raw_store_avoided = 0 self.write_barrier_calls = 0 self.write_barrier_from_array_calls = 0 @@ -570,6 +571,9 @@ log.info("assigned %s typeids" % (len(group.members), )) log.info("added %s push/pop stack root instructions" % ( self.num_pushs, )) + if self.num_raw_store_avoided: + log.info("avoided %s repeated raw_stores" % ( + self.num_raw_store_avoided,)) if self.write_barrier_ptr: log.info("inserted %s write barrier calls" % ( self.write_barrier_calls, )) diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -7,7 +7,7 @@ from pypy.tool.algo.regalloc import perform_register_allocation from pypy.translator.backendopt.ssa import DataFlowFamilyBuilder from pypy.translator.unsimplify import copyvar -from pypy.objspace.flow.model import Block, Link, checkgraph +from pypy.objspace.flow.model import Block, Link, checkgraph, mkentrymap class ShadowStackRootWalker(BaseRootWalker): @@ -252,7 +252,7 @@ # Compute the set of "useless stores", i.e. the Variables in the # gc_push_roots that are storing the same value as the one previously # loaded from the same index. - #useless_stores = self.compute_useless_stores(graph) + useless_stores = self.compute_useless_stores(gct, graph, spans) # # Put at the start of the graph: "incr_stack(); fill with zeroes" llops = LowLevelOpList() @@ -299,7 +299,9 @@ assert -numcolors <= k < 0 c_k = rmodel.inputconst(lltype.Signed, k) if op.opname == "gc_push_roots": - llops.genop("raw_store", [top_addr, c_type, c_k, v]) + if (block, op, v) not in useless_stores: + llops.genop("raw_store", [top_addr, c_type, + c_k, v]) else: v_newaddr = llops.genop("raw_load", [top_addr, c_type, c_k], @@ -308,3 +310,56 @@ block.operations[:] = llops # checkgraph(graph) + + + def compute_useless_stores(self, gct, graph, spans): + # A "useless store" is a Variable in a gc_push_roots instruction + # that is the "same" one, in all paths, as the one loaded by a + # previous gc_pop_roots. Two variables v and w are the "same" + # if spans.find_rep(v) is spans.find_rep(w). + entrymap = mkentrymap(graph) + # + def enumerate_previous_gc_pop_roots(block, index): + result = [] + seen = set() + pending = [(block, index)] + while pending: + block, index = pending.pop() + for i in range(index-1, -1, -1): + if block.operations[i].opname == 'gc_pop_roots': + # found gc_pop_roots, record it and stop + result.append(block.operations[i]) + break + else: + # find all blocks that go into this one + if block is graph.startblock: + return None + for link in entrymap[block]: + prevblock = link.prevblock + if prevblock in seen: + continue + seen.add(prevblock) + pending.append((prevblock, len(prevblock.operations))) + return result + # + useless = {} + for block in graph.iterblocks(): + for i, op in enumerate(block.operations): + if op.opname == 'gc_push_roots': + result = enumerate_previous_gc_pop_roots(block, i) + if not result: + continue + for original_v in op.args: + v = spans.find_rep(original_v) + # check if 'v' is in all prevop.args + for prevop in result: + for w in prevop.args: + if spans.find_rep(w) is v: + break # found 'v' in this prevop.args + else: + break # did not find 'v' in this prevop.args + else: + # yes, found 'v' in each prevop.args -> useless + useless[block, op, original_v] = True + gct.num_raw_store_avoided += 1 + return useless From noreply at buildbot.pypy.org Sat Jul 2 14:56:34 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 14:56:34 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Fix. Message-ID: <20110702125634.8E2CD82940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45263:124c0a91ec13 Date: 2011-07-02 13:05 +0200 http://bitbucket.org/pypy/pypy/changeset/124c0a91ec13/ Log: Fix. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -7,7 +7,8 @@ from pypy.tool.algo.regalloc import perform_register_allocation from pypy.translator.backendopt.ssa import DataFlowFamilyBuilder from pypy.translator.unsimplify import copyvar -from pypy.objspace.flow.model import Block, Link, checkgraph, mkentrymap +from pypy.objspace.flow.model import Block, Link, Constant +from pypy.objspace.flow.model import checkgraph, mkentrymap class ShadowStackRootWalker(BaseRootWalker): @@ -247,20 +248,51 @@ def is_interesting(v): return spans.find_rep(v) in interesting_vars regalloc = perform_register_allocation(graph, is_interesting) - numcolors = max([regalloc.getcolor(v) for v in interesting_vars]) + 1 # # Compute the set of "useless stores", i.e. the Variables in the # gc_push_roots that are storing the same value as the one previously # loaded from the same index. useless_stores = self.compute_useless_stores(gct, graph, spans) # + # We replace gc_push_roots/gc_pop_roots with individual + # operations raw_store/raw_load + negnumcolors = 0 + c_type = rmodel.inputconst(lltype.Void, llmemory.Address) + for block in graph.iterblocks(): + if block.operations == (): + continue + llops = LowLevelOpList() + for op in block.operations: + if op.opname not in ("gc_push_roots", "gc_pop_roots"): + llops.append(op) + continue + top_addr = llops.genop("direct_call", + [gct.get_stack_top_ptr], + resulttype=llmemory.Address) + for v in op.args: + if isinstance(v, Constant): + continue + k = ~regalloc.getcolor(v) + negnumcolors = min(negnumcolors, k) + c_k = rmodel.inputconst(lltype.Signed, k) + if op.opname == "gc_push_roots": + if (block, op, v) not in useless_stores: + llops.genop("raw_store", [top_addr, c_type, + c_k, v]) + else: + v_newaddr = llops.genop("raw_load", + [top_addr, c_type, c_k], + resulttype=llmemory.Address) + llops.genop("gc_reload_possibly_moved", [v_newaddr, v]) + block.operations[:] = llops + # # Put at the start of the graph: "incr_stack(); fill with zeroes" llops = LowLevelOpList() + numcolors = -negnumcolors c_numcolors = rmodel.inputconst(lltype.Signed, numcolors) base_addr = llops.genop("direct_call", [gct.incr_stack_ptr, c_numcolors], resulttype=llmemory.Address) - c_type = rmodel.inputconst(lltype.Void, llmemory.Address) c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL) for k in range(numcolors): c_k = rmodel.inputconst(lltype.Signed, k) @@ -281,34 +313,6 @@ block.recloseblock(Link([v_return], newexitblock)) graph.returnblock = newexitblock # - # We replace gc_push_roots/gc_pop_roots with individual - # operations raw_store/raw_load - for block in graph.iterblocks(): - if block.operations == (): - continue - llops = LowLevelOpList() - for op in block.operations: - if op.opname not in ("gc_push_roots", "gc_pop_roots"): - llops.append(op) - continue - top_addr = llops.genop("direct_call", - [gct.get_stack_top_ptr], - resulttype=llmemory.Address) - for v in op.args: - k = regalloc.getcolor(v) - numcolors - assert -numcolors <= k < 0 - c_k = rmodel.inputconst(lltype.Signed, k) - if op.opname == "gc_push_roots": - if (block, op, v) not in useless_stores: - llops.genop("raw_store", [top_addr, c_type, - c_k, v]) - else: - v_newaddr = llops.genop("raw_load", - [top_addr, c_type, c_k], - resulttype=llmemory.Address) - llops.genop("gc_reload_possibly_moved", [v_newaddr, v]) - block.operations[:] = llops - # checkgraph(graph) From noreply at buildbot.pypy.org Sat Jul 2 14:56:35 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 14:56:35 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Fix. Message-ID: <20110702125635.C8C4A82940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45264:c599b6bb9748 Date: 2011-07-02 14:55 +0200 http://bitbucket.org/pypy/pypy/changeset/c599b6bb9748/ Log: Fix. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -354,6 +354,8 @@ if not result: continue for original_v in op.args: + if isinstance(original_v, Constant): + continue v = spans.find_rep(original_v) # check if 'v' is in all prevop.args for prevop in result: From noreply at buildbot.pypy.org Sat Jul 2 14:56:37 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 14:56:37 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Seems to give better performance this way. Message-ID: <20110702125637.1255D82940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45265:f00b46ada731 Date: 2011-07-02 15:03 +0200 http://bitbucket.org/pypy/pypy/changeset/f00b46ada731/ Log: Seems to give better performance this way. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -290,13 +290,15 @@ llops = LowLevelOpList() numcolors = -negnumcolors c_numcolors = rmodel.inputconst(lltype.Signed, numcolors) - base_addr = llops.genop("direct_call", [gct.incr_stack_ptr, - c_numcolors], - resulttype=llmemory.Address) + llops.genop("direct_call", [gct.incr_stack_ptr, c_numcolors], + resulttype=llmemory.Address) + top_addr = llops.genop("direct_call", + [gct.get_stack_top_ptr], + resulttype=llmemory.Address) c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL) for k in range(numcolors): - c_k = rmodel.inputconst(lltype.Signed, k) - llops.genop("raw_store", [base_addr, c_type, c_k, c_null]) + c_k = rmodel.inputconst(lltype.Signed, ~k) + llops.genop("raw_store", [top_addr, c_type, c_k, c_null]) graph.startblock.operations[:0] = llops # # Put at the end of the graph: "decr_stack()" From noreply at buildbot.pypy.org Sat Jul 2 15:17:13 2011 From: noreply at buildbot.pypy.org (berdario) Date: Sat, 2 Jul 2011 15:17:13 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: Fixed ovfcheck, intmask and the objspace wrap Message-ID: <20110702131713.2F25282940@wyvern.cs.uni-duesseldorf.de> Author: Dario Bertini Branch: win64 test Changeset: r45266:9476f6f9941f Date: 2011-07-02 15:19 +0200 http://bitbucket.org/pypy/pypy/changeset/9476f6f9941f/ Log: Fixed ovfcheck, intmask and the objspace wrap Also: lessened other checks to allow for long types in place of ints diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -1,5 +1,6 @@ import __builtin__ import types +import sys from pypy.interpreter import pyframe, function, special from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.error import OperationError, operationerrfmt @@ -161,7 +162,7 @@ if isinstance(x, OperationError): raise TypeError, ("attempt to wrap already wrapped exception: %s"% (x,)) - if isinstance(x, int): + if isinstance(x, (int, long)) and -sys.maxint -1 <= x <= sys.maxint: if isinstance(x, bool): return self.newbool(x) else: diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -302,7 +302,7 @@ """Give a translation-time error if 'x' is not a plain int (e.g. if it's a r_longlong or an r_uint). """ - assert type(x) is int + assert type(x) in (int, long) return x class Entry(ExtRegistryEntry): diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -63,11 +63,11 @@ """ def intmask(n): - if isinstance(n, int): - return int(n) # possibly bool->int if isinstance(n, objectmodel.Symbolic): return n # assume Symbolics don't overflow assert not isinstance(n, float) + if -sys.maxint -1 < n < sys.maxint: + return int(n) n = long(n) n &= LONG_MASK if n >= LONG_TEST: @@ -111,8 +111,8 @@ # raise OverflowError if the operation did overflow assert not isinstance(r, r_uint), "unexpected ovf check on unsigned" assert not isinstance(r, r_longlong), "ovfcheck not supported on r_longlong" - assert not isinstance(r,r_ulonglong),"ovfcheck not supported on r_ulonglong" - if abs(r) > sys.maxint: + assert not isinstance(r, r_ulonglong), "ovfcheck not supported on r_ulonglong" + if r > sys.maxint or r < -sys.maxint - 1: raise OverflowError, "signed integer expression did overflow" return r diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -51,14 +51,14 @@ def _widen_digit(x): if not we_are_translated(): - assert type(x) is int, "widen_digit() takes an int, got a %r" % type(x) + assert type(x) in (int, long), "widen_digit() takes an int, got a %r" % type(x) if SHIFT <= 15: return int(x) return r_longlong(x) def _store_digit(x): if not we_are_translated(): - assert type(x) is int, "store_digit() takes an int, got a %r" % type(x) + assert type(x) in (int, long), "store_digit() takes an int, got a %r" % type(x) if SHIFT <= 15: return rffi.cast(rffi.SHORT, x) elif SHIFT <= 31: From noreply at buildbot.pypy.org Sat Jul 2 15:17:14 2011 From: noreply at buildbot.pypy.org (berdario) Date: Sat, 2 Jul 2011 15:17:14 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: merge heads Message-ID: <20110702131714.73FE882940@wyvern.cs.uni-duesseldorf.de> Author: Dario Bertini Branch: win64 test Changeset: r45267:4dcb9bc7322f Date: 2011-07-02 15:23 +0200 http://bitbucket.org/pypy/pypy/changeset/4dcb9bc7322f/ Log: merge heads diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -38,8 +38,12 @@ from pypy.rlib import objectmodel # set up of machine internals, using sys.maxint only. +# if sys.maxsize exists and is greater, it is used instead. +_maxnumber = sys.maxint +if hasattr(sys, "maxsize"): + _maxnumber = max(sys.maxint, sys.maxsize) _bits = 1 -_test = sys.maxint +_test = _maxnumber while _test: _bits += 1 _test >>= 1 @@ -103,7 +107,7 @@ r_class.BITS == LONG_BIT and r_class.SIGNED) _should_widen_type._annspecialcase_ = 'specialize:memo' -del _bits, _test +del _bits, _test, _maxnumber def ovfcheck(r): "NOT_RPYTHON" diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -397,7 +397,7 @@ return intmask(b) def op_cast_int_to_longlong(b): - assert isinstance(x, (int, long)) + assert isinstance(b, (int, long)) return r_longlong_result(b) def op_truncate_longlong_to_int(b): diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -904,16 +904,14 @@ offsetof._annspecialcase_ = 'specialize:memo' # check that we have a sane configuration -# temporary hack for tricking win64 -try: - maxint = sys.orig_maxint -except AttributeError: - maxint = sys.maxint +# XXX re-enable this after correcting the windows case +""" assert maxint == (1 << (8 * sizeof(lltype.Signed) - 1)) - 1, ( "Mixed configuration of the word size of the machine:\n\t" "the underlying Python was compiled with maxint=%d,\n\t" "but the C compiler says that 'long' is %d bytes" % ( maxint, sizeof(lltype.Signed))) +""" # ********************** some helpers ******************* diff --git a/pypy/rpython/test/test_rint.py b/pypy/rpython/test/test_rint.py --- a/pypy/rpython/test/test_rint.py +++ b/pypy/rpython/test/test_rint.py @@ -65,10 +65,8 @@ res = self.interpret(dummy, [-123]) assert self.ll_to_string(res) == '-123' - # hack for win64 - maxint = sys.orig_maxint if hasattr(sys, "orig_maxint") else sys.maxint - res = self.interpret(dummy, [-maxint-1]) - assert self.ll_to_string(res) == str(-maxint-1) + res = self.interpret(dummy, [-sys.maxint-1]) + assert self.ll_to_string(res) == str(-sys.maxint-1) def test_hex_of_int(self): def dummy(i): diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -10,9 +10,10 @@ For more information, use test_all.py -h. """ import sys, os -sys.orig_maxint = sys.maxint -sys.maxint = 2**63-1 - +# XXX hack for win64: +# this needs to be done without hacking maxint +if hasattr(sys, "maxsize"): + sys.maxint = max(sys.maxint, sys.maxsize) if len(sys.argv) == 1 and os.path.dirname(sys.argv[0]) in '.': print >> sys.stderr, __doc__ From noreply at buildbot.pypy.org Sat Jul 2 16:03:55 2011 From: noreply at buildbot.pypy.org (berdario) Date: Sat, 2 Jul 2011 16:03:55 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: Factored out code to check for int bounds, and changed some checks Message-ID: <20110702140355.5240982940@wyvern.cs.uni-duesseldorf.de> Author: Dario Bertini Branch: win64 test Changeset: r45268:b4558e71f05e Date: 2011-07-02 16:10 +0200 http://bitbucket.org/pypy/pypy/changeset/b4558e71f05e/ Log: Factored out code to check for int bounds, and changed some checks diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -1,6 +1,5 @@ import __builtin__ import types -import sys from pypy.interpreter import pyframe, function, special from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.error import OperationError, operationerrfmt @@ -10,7 +9,7 @@ from pypy.objspace.descroperation import DescrOperation, raiseattrerror from pypy.rlib.objectmodel import instantiate, r_dict, specialize from pypy.rlib.debug import make_sure_not_resized -from pypy.rlib.rarithmetic import base_int, widen +from pypy.rlib.rarithmetic import base_int, widen, is_valid_int from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.jit import hint from pypy.rlib.rbigint import rbigint @@ -162,7 +161,7 @@ if isinstance(x, OperationError): raise TypeError, ("attempt to wrap already wrapped exception: %s"% (x,)) - if isinstance(x, (int, long)) and -sys.maxint -1 <= x <= sys.maxint: + if isinstance(x, (int, long)) and is_valid_int(x): if isinstance(x, bool): return self.newbool(x) else: diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -70,7 +70,7 @@ if isinstance(n, objectmodel.Symbolic): return n # assume Symbolics don't overflow assert not isinstance(n, float) - if -sys.maxint -1 < n < sys.maxint: + if is_valid_int(n): return int(n) n = long(n) n &= LONG_MASK @@ -109,6 +109,9 @@ del _bits, _test, _maxnumber +def is_valid_int(r): + return -sys.maxint - 1 <= r <= sys.maxint + def ovfcheck(r): "NOT_RPYTHON" # to be used as ovfcheck(x y) @@ -116,7 +119,7 @@ assert not isinstance(r, r_uint), "unexpected ovf check on unsigned" assert not isinstance(r, r_longlong), "ovfcheck not supported on r_longlong" assert not isinstance(r, r_ulonglong), "ovfcheck not supported on r_ulonglong" - if r > sys.maxint or r < -sys.maxint - 1: + if not is_valid_int(r): raise OverflowError, "signed integer expression did overflow" return r diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -1,5 +1,5 @@ from pypy.rlib.rarithmetic import LONG_BIT, intmask, r_uint, r_ulonglong -from pypy.rlib.rarithmetic import ovfcheck, r_longlong, widen +from pypy.rlib.rarithmetic import ovfcheck, r_longlong, widen, is_valid_int from pypy.rlib.rarithmetic import most_neg_value_of_same_type from pypy.rlib.rfloat import isfinite from pypy.rlib.debug import make_sure_not_resized, check_regular_int @@ -51,14 +51,14 @@ def _widen_digit(x): if not we_are_translated(): - assert type(x) in (int, long), "widen_digit() takes an int, got a %r" % type(x) + assert type(x) in (int, long) and is_valid_int(x), "widen_digit() takes an int, got a %r" % type(x) if SHIFT <= 15: return int(x) return r_longlong(x) def _store_digit(x): if not we_are_translated(): - assert type(x) in (int, long), "store_digit() takes an int, got a %r" % type(x) + assert type(x) in (int, long) and is_valid_int(x), "store_digit() takes an int, got a %r" % type(x) if SHIFT <= 15: return rffi.cast(rffi.SHORT, x) elif SHIFT <= 31: From noreply at buildbot.pypy.org Sat Jul 2 17:18:46 2011 From: noreply at buildbot.pypy.org (hodgestar) Date: Sat, 2 Jul 2011 17:18:46 +0200 (CEST) Subject: [pypy-commit] pypy default: Add xml.parsers.expat.errors module. Message-ID: <20110702151846.6B4A382940@wyvern.cs.uni-duesseldorf.de> Author: Simon Cross Branch: Changeset: r45269:2d43f3bebc8d Date: 2011-07-02 17:20 +0200 http://bitbucket.org/pypy/pypy/changeset/2d43f3bebc8d/ Log: Add xml.parsers.expat.errors module. diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py --- a/pypy/module/pyexpat/__init__.py +++ b/pypy/module/pyexpat/__init__.py @@ -2,6 +2,22 @@ from pypy.interpreter.mixedmodule import MixedModule +class ErrorsModule(MixedModule): + "Definition of pyexpat.errors module." + + appleveldefs = { + } + + interpleveldefs = { + } + + def setup_after_space_initialization(self): + from pypy.module.pyexpat import interp_pyexpat + for name in interp_pyexpat.xml_error_list: + self.space.setattr(self, self.space.wrap(name), + interp_pyexpat.ErrorString(self.space, + getattr(interp_pyexpat, name))) + class Module(MixedModule): "Python wrapper for Expat parser." @@ -21,6 +37,10 @@ 'version_info': 'interp_pyexpat.get_expat_version_info(space)', } + submodules = { + 'errors': ErrorsModule, + } + for name in ['XML_PARAM_ENTITY_PARSING_NEVER', 'XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE', 'XML_PARAM_ENTITY_PARSING_ALWAYS']: diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -31,6 +31,48 @@ XML_Content_Ptr = lltype.Ptr(lltype.ForwardReference()) XML_Parser = rffi.COpaquePtr(typedef='XML_Parser') +xml_error_list = [ + "XML_ERROR_NO_MEMORY", + "XML_ERROR_SYNTAX", + "XML_ERROR_NO_ELEMENTS", + "XML_ERROR_INVALID_TOKEN", + "XML_ERROR_UNCLOSED_TOKEN", + "XML_ERROR_PARTIAL_CHAR", + "XML_ERROR_TAG_MISMATCH", + "XML_ERROR_DUPLICATE_ATTRIBUTE", + "XML_ERROR_JUNK_AFTER_DOC_ELEMENT", + "XML_ERROR_PARAM_ENTITY_REF", + "XML_ERROR_UNDEFINED_ENTITY", + "XML_ERROR_RECURSIVE_ENTITY_REF", + "XML_ERROR_ASYNC_ENTITY", + "XML_ERROR_BAD_CHAR_REF", + "XML_ERROR_BINARY_ENTITY_REF", + "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", + "XML_ERROR_MISPLACED_XML_PI", + "XML_ERROR_UNKNOWN_ENCODING", + "XML_ERROR_INCORRECT_ENCODING", + "XML_ERROR_UNCLOSED_CDATA_SECTION", + "XML_ERROR_EXTERNAL_ENTITY_HANDLING", + "XML_ERROR_NOT_STANDALONE", + "XML_ERROR_UNEXPECTED_STATE", + "XML_ERROR_ENTITY_DECLARED_IN_PE", + "XML_ERROR_FEATURE_REQUIRES_XML_DTD", + "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING", + # Added in Expat 1.95.7. + "XML_ERROR_UNBOUND_PREFIX", + # Added in Expat 1.95.8. + "XML_ERROR_UNDECLARING_PREFIX", + "XML_ERROR_INCOMPLETE_PE", + "XML_ERROR_XML_DECL", + "XML_ERROR_TEXT_DECL", + "XML_ERROR_PUBLICID", + "XML_ERROR_SUSPENDED", + "XML_ERROR_NOT_SUSPENDED", + "XML_ERROR_ABORTED", + "XML_ERROR_FINISHED", + "XML_ERROR_SUSPEND_PE", + ] + class CConfigure: _compilation_info_ = eci XML_Content = rffi_platform.Struct('XML_Content', [ @@ -56,6 +98,9 @@ XML_FALSE = rffi_platform.ConstantInteger('XML_FALSE') XML_TRUE = rffi_platform.ConstantInteger('XML_TRUE') + for name in xml_error_list: + locals()[name] = rffi_platform.ConstantInteger(name) + for k, v in rffi_platform.configure(CConfigure).items(): globals()[k] = v @@ -298,7 +343,8 @@ XML_GetErrorCode = expat_external( 'XML_GetErrorCode', [XML_Parser], rffi.INT) XML_ErrorString = expat_external( - 'XML_ErrorString', [rffi.INT], rffi.CCHARP) + 'XML_ErrorString', [rffi.INT], + rffi.CCHARP) XML_GetCurrentLineNumber = expat_external( 'XML_GetCurrentLineNumber', [XML_Parser], rffi.INT) XML_GetErrorLineNumber = XML_GetCurrentLineNumber diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py --- a/pypy/module/pyexpat/test/test_parser.py +++ b/pypy/module/pyexpat/test/test_parser.py @@ -38,7 +38,7 @@ parser = pyexpat.ParserCreate() raises(pyexpat.ExpatError, "parser.Parse(xml, True)") - def test_encoding(self): + def test_encoding_argument(self): import pyexpat for encoding_arg in (None, 'utf-8', 'iso-8859-1'): for namespace_arg in (None, '{'): @@ -68,7 +68,7 @@ assert p.buffer_size == 150 raises(TypeError, setattr, p, 'buffer_size', sys.maxint + 1) - def test_encoding(self): + def test_encoding_xml(self): # use one of the few encodings built-in in expat xml = "caf\xe9" import pyexpat @@ -120,3 +120,14 @@ return True p.ExternalEntityRefHandler = handler p.Parse(xml) + + def test_errors(self): + import types + import pyexpat + assert isinstance(pyexpat.errors, types.ModuleType) + # check a few random errors + assert pyexpat.errors.XML_ERROR_SYNTAX == 'syntax error' + assert (pyexpat.errors.XML_ERROR_INCORRECT_ENCODING == + 'encoding specified in XML declaration is incorrect') + assert (pyexpat.errors.XML_ERROR_XML_DECL == + 'XML declaration not well-formed') From noreply at buildbot.pypy.org Sat Jul 2 17:19:03 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 17:19:03 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Fix. Message-ID: <20110702151903.4E5D482940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45270:d01390c8d17f Date: 2011-07-02 17:26 +0200 http://bitbucket.org/pypy/pypy/changeset/d01390c8d17f/ Log: Fix. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -252,7 +252,8 @@ # Compute the set of "useless stores", i.e. the Variables in the # gc_push_roots that are storing the same value as the one previously # loaded from the same index. - useless_stores = self.compute_useless_stores(gct, graph, spans) + useless_stores = self.compute_useless_stores(gct, graph, spans, + regalloc) # # We replace gc_push_roots/gc_pop_roots with individual # operations raw_store/raw_load @@ -318,7 +319,7 @@ checkgraph(graph) - def compute_useless_stores(self, gct, graph, spans): + def compute_useless_stores(self, gct, graph, spans, regalloc): # A "useless store" is a Variable in a gc_push_roots instruction # that is the "same" one, in all paths, as the one loaded by a # previous gc_pop_roots. Two variables v and w are the "same" @@ -355,19 +356,23 @@ result = enumerate_previous_gc_pop_roots(block, i) if not result: continue - for original_v in op.args: - if isinstance(original_v, Constant): + for v in op.args: + if isinstance(v, Constant): continue - v = spans.find_rep(original_v) + vrep = spans.find_rep(v) # check if 'v' is in all prevop.args for prevop in result: for w in prevop.args: - if spans.find_rep(w) is v: - break # found 'v' in this prevop.args + # if we find 'v' in this prevop.args, we + # can reuse it if it maps to the same index + if (spans.find_rep(w) is vrep + and regalloc.getcolor(v) == + regalloc.getcolor(w)): + break else: break # did not find 'v' in this prevop.args else: - # yes, found 'v' in each prevop.args -> useless - useless[block, op, original_v] = True + # yes, found 'v' in each prevop.args. + useless[block, op, v] = True gct.num_raw_store_avoided += 1 return useless From noreply at buildbot.pypy.org Sat Jul 2 17:58:30 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Sat, 2 Jul 2011 17:58:30 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: slowly becoming independent from sys.maxint Message-ID: <20110702155830.1BF0082940@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45271:0730f63c9700 Date: 2011-07-02 15:34 +0200 http://bitbucket.org/pypy/pypy/changeset/0730f63c9700/ Log: slowly becoming independent from sys.maxint diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -45,7 +45,7 @@ res = ctypes2lltype(lltype.SingleFloat, ctypes.c_float(-3.5)) assert isinstance(res, rffi.r_singlefloat) assert float(res) == -3.5 - assert lltype2ctypes(rffi.r_ulong(-1)) == sys.maxint * 2 + 1 + assert lltype2ctypes(rffi.r_ulong(-1)) == (1 << rffi.r_ulong.BITS) - 1 res = ctypes2lltype(lltype.Unsigned, sys.maxint * 2 + 1) assert (res, type(res)) == (rffi.r_ulong(-1), rffi.r_ulong) assert ctypes2lltype(lltype.Bool, 0) is False From noreply at buildbot.pypy.org Sat Jul 2 17:58:31 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Sat, 2 Jul 2011 17:58:31 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: first test passes (ugh) Message-ID: <20110702155831.590FE82940@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45272:96228dadb878 Date: 2011-07-02 17:50 +0200 http://bitbucket.org/pypy/pypy/changeset/96228dadb878/ Log: first test passes (ugh) diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -15,7 +15,7 @@ from pypy.rpython.test.test_llinterp import interpret from pypy.annotation.annrpython import RPythonAnnotator from pypy.rpython.rtyper import RPythonTyper - +from pypy.rlib.rarithmetic import r_uint if False: # for now, please keep it False by default from pypy.rpython.lltypesystem import ll2ctypes @@ -47,13 +47,13 @@ assert float(res) == -3.5 assert lltype2ctypes(rffi.r_ulong(-1)) == (1 << rffi.r_ulong.BITS) - 1 res = ctypes2lltype(lltype.Unsigned, sys.maxint * 2 + 1) - assert (res, type(res)) == (rffi.r_ulong(-1), rffi.r_ulong) + assert (res, type(res)) == (r_uint(-1), r_uint) assert ctypes2lltype(lltype.Bool, 0) is False assert ctypes2lltype(lltype.Bool, 1) is True - res = lltype2ctypes(llmemory.sizeof(lltype.Signed)) + res = lltype2ctypes(llmemory.sizeof(rffi.LONG)) assert res == struct.calcsize("l") - S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed)) + S = lltype.Struct('S', ('x', rffi.LONG), ('y', rffi.LONG)) res = lltype2ctypes(llmemory.sizeof(S)) assert res == struct.calcsize("ll") From noreply at buildbot.pypy.org Sat Jul 2 17:58:32 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Sat, 2 Jul 2011 17:58:32 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: merge Message-ID: <20110702155832.9A6AA82940@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45273:0eac19d0869d Date: 2011-07-02 18:02 +0200 http://bitbucket.org/pypy/pypy/changeset/0eac19d0869d/ Log: merge diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -1,5 +1,6 @@ import __builtin__ import types +import sys from pypy.interpreter import pyframe, function, special from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.error import OperationError, operationerrfmt @@ -161,7 +162,7 @@ if isinstance(x, OperationError): raise TypeError, ("attempt to wrap already wrapped exception: %s"% (x,)) - if isinstance(x, int): + if isinstance(x, (int, long)) and -sys.maxint -1 <= x <= sys.maxint: if isinstance(x, bool): return self.newbool(x) else: diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -302,7 +302,7 @@ """Give a translation-time error if 'x' is not a plain int (e.g. if it's a r_longlong or an r_uint). """ - assert type(x) is int + assert type(x) in (int, long) return x class Entry(ExtRegistryEntry): diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -67,11 +67,11 @@ """ def intmask(n): - if isinstance(n, int): - return int(n) # possibly bool->int if isinstance(n, objectmodel.Symbolic): return n # assume Symbolics don't overflow assert not isinstance(n, float) + if -sys.maxint -1 < n < sys.maxint: + return int(n) n = long(n) n &= LONG_MASK if n >= LONG_TEST: @@ -115,8 +115,8 @@ # raise OverflowError if the operation did overflow assert not isinstance(r, r_uint), "unexpected ovf check on unsigned" assert not isinstance(r, r_longlong), "ovfcheck not supported on r_longlong" - assert not isinstance(r,r_ulonglong),"ovfcheck not supported on r_ulonglong" - if abs(r) > sys.maxint: + assert not isinstance(r, r_ulonglong), "ovfcheck not supported on r_ulonglong" + if r > sys.maxint or r < -sys.maxint - 1: raise OverflowError, "signed integer expression did overflow" return r diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -51,14 +51,14 @@ def _widen_digit(x): if not we_are_translated(): - assert type(x) is int, "widen_digit() takes an int, got a %r" % type(x) + assert type(x) in (int, long), "widen_digit() takes an int, got a %r" % type(x) if SHIFT <= 15: return int(x) return r_longlong(x) def _store_digit(x): if not we_are_translated(): - assert type(x) is int, "store_digit() takes an int, got a %r" % type(x) + assert type(x) in (int, long), "store_digit() takes an int, got a %r" % type(x) if SHIFT <= 15: return rffi.cast(rffi.SHORT, x) elif SHIFT <= 31: From noreply at buildbot.pypy.org Sat Jul 2 17:58:33 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Sat, 2 Jul 2011 17:58:33 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: merge heads Message-ID: <20110702155833.DB09F82940@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45274:573588bb0ab9 Date: 2011-07-02 18:05 +0200 http://bitbucket.org/pypy/pypy/changeset/573588bb0ab9/ Log: merge heads diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -15,7 +15,7 @@ from pypy.rpython.test.test_llinterp import interpret from pypy.annotation.annrpython import RPythonAnnotator from pypy.rpython.rtyper import RPythonTyper - +from pypy.rlib.rarithmetic import r_uint if False: # for now, please keep it False by default from pypy.rpython.lltypesystem import ll2ctypes @@ -45,15 +45,15 @@ res = ctypes2lltype(lltype.SingleFloat, ctypes.c_float(-3.5)) assert isinstance(res, rffi.r_singlefloat) assert float(res) == -3.5 - assert lltype2ctypes(rffi.r_ulong(-1)) == sys.maxint * 2 + 1 + assert lltype2ctypes(rffi.r_ulong(-1)) == (1 << rffi.r_ulong.BITS) - 1 res = ctypes2lltype(lltype.Unsigned, sys.maxint * 2 + 1) - assert (res, type(res)) == (rffi.r_ulong(-1), rffi.r_ulong) + assert (res, type(res)) == (r_uint(-1), r_uint) assert ctypes2lltype(lltype.Bool, 0) is False assert ctypes2lltype(lltype.Bool, 1) is True - res = lltype2ctypes(llmemory.sizeof(lltype.Signed)) + res = lltype2ctypes(llmemory.sizeof(rffi.LONG)) assert res == struct.calcsize("l") - S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed)) + S = lltype.Struct('S', ('x', rffi.LONG), ('y', rffi.LONG)) res = lltype2ctypes(llmemory.sizeof(S)) assert res == struct.calcsize("ll") From noreply at buildbot.pypy.org Sat Jul 2 18:00:22 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 18:00:22 +0200 (CEST) Subject: [pypy-commit] buildbot default: Trying to add symlinks to the latest revision (i.e. the most Message-ID: <20110702160022.BCDB982940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r520:c90683df63c9 Date: 2011-07-02 18:07 +0200 http://bitbucket.org/pypy/buildbot/changeset/c90683df63c9/ Log: Trying to add symlinks to the latest revision (i.e. the most recently uploaded one). diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -28,9 +28,15 @@ masterdest = os.path.join(masterdest, branch) if not os.path.exists(masterdest): os.makedirs(masterdest) + # + assert '%(final_file_name)s' in self.basename + symname = self.basename.replace('%(final_file_name)s', 'latest') + assert '%' not in symname + self.symlinkname = os.path.join(masterdest, symname) + # basename = WithProperties(self.basename).render(properties) - masterdest = os.path.join(masterdest, basename) - self.masterdest = masterdest + self.masterdest = os.path.join(masterdest, basename) + # transfer.FileUpload.start(self) def finished(self, *args, **kwds): @@ -39,6 +45,10 @@ os.chmod(self.masterdest, 0644) except OSError: pass + try: + os.symlink(os.path.basename(self.masterdest), self.symlinkname) + except OSError: + pass class Translate(ShellCmd): name = "translate" diff --git a/bot2/pypybuildbot/pypylist.py b/bot2/pypybuildbot/pypylist.py --- a/bot2/pypybuildbot/pypylist.py +++ b/bot2/pypybuildbot/pypylist.py @@ -13,6 +13,7 @@ # to get the desired order keep in mind that they are reversed at the end, # so the highest the value, the bigger the priority VCS_PRIORITY = { + 'latest': 150, 'hg': 100, 'svn': 50, } @@ -64,8 +65,13 @@ if dashes == 4: # svn based self.exe, self.backend, self.features, self.rev, self.platform = name.split('-') - self.numrev = int(self.rev) - self.vcs = 'svn' + if self.rev == 'latest': + self.rev = -1 + self.numrev = -1 + self.vcs = 'latest' + else: + self.numrev = int(self.rev) + self.vcs = 'svn' elif dashes == 5: # mercurial based self.exe, self.backend, self.features, num, hgid, self.platform = name.split('-') diff --git a/bot2/pypybuildbot/test/test_builds.py b/bot2/pypybuildbot/test/test_builds.py --- a/bot2/pypybuildbot/test/test_builds.py +++ b/bot2/pypybuildbot/test/test_builds.py @@ -8,6 +8,8 @@ return None if item == 'got_revision': return 123 + if item == 'final_file_name': + return '123-ea5ca8' def render(self, x): return x @@ -51,7 +53,7 @@ def test_pypy_upload(): pth = py.test.ensuretemp('buildbot') inst = builds.PyPyUpload(slavesrc='slavesrc', masterdest=str(pth.join('mstr')), - basename='base-%(got_revision)s', workdir='.', + basename='base-%(final_file_name)s', workdir='.', blocksize=100) factory, kw = inst.factory rebuilt = factory(**kw) @@ -60,7 +62,10 @@ rebuilt.runCommand = lambda *args: FakeDeferred() rebuilt.start() assert pth.join('mstr').check(dir=True) - assert rebuilt.masterdest == str(pth.join('mstr', 'trunk', 'base-123')) + assert rebuilt.masterdest == str(pth.join('mstr', 'trunk', + 'base-123-ea5ca8')) + assert rebuilt.symlinkname == str(pth.join('mstr', 'trunk', + 'base-latest')) class TestPytestCmd(object): From noreply at buildbot.pypy.org Sat Jul 2 18:25:25 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 2 Jul 2011 18:25:25 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Fix. Message-ID: <20110702162525.3953B82940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45275:e1cb1542e148 Date: 2011-07-02 18:34 +0200 http://bitbucket.org/pypy/pypy/changeset/e1cb1542e148/ Log: Fix. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -9,6 +9,7 @@ from pypy.translator.unsimplify import copyvar from pypy.objspace.flow.model import Block, Link, Constant from pypy.objspace.flow.model import checkgraph, mkentrymap +from pypy.annotation import model as annmodel class ShadowStackRootWalker(BaseRootWalker): From noreply at buildbot.pypy.org Sat Jul 2 19:13:32 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sat, 2 Jul 2011 19:13:32 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: some supoprt for caching setitems across loop bondaries Message-ID: <20110702171332.CDB3982940@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45276:94d5f21f714f Date: 2011-07-02 07:53 +0200 http://bitbucket.org/pypy/pypy/changeset/94d5f21f714f/ Log: some supoprt for caching setitems across loop bondaries diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -91,7 +91,7 @@ # field. structvalue = optheap.getvalue(op.getarg(0)) fieldvalue = optheap.getvalue(op.getarglist()[-1]) - self.remember_field_value(structvalue, fieldvalue) + self.remember_field_value(structvalue, fieldvalue, op) def clear(self): self._cached_fields.clear() @@ -121,9 +121,21 @@ potential_ops, descr): if self._lazy_setfield is not None: return - for structvalue, op in self._cached_fields_getfield_op.iteritems(): + for structvalue in self._cached_fields_getfield_op.keys(): + op = self._cached_fields_getfield_op[structvalue] if op and structvalue in self._cached_fields: - potential_ops[op.result] = op + if op.getopnum() == rop.SETFIELD_GC: + result = op.getarg(1) + if result in potential_ops: + result = result.clonebox() + # XXX this will not allow for chains of operations + getop = ResOperation(rop.GETFIELD_GC, [op.getarg(0)], + result, op.getdescr()) + potential_ops[result] = getop + self._cached_fields_getfield_op[structvalue] = getop + self._cached_fields[structvalue] = optimizer.getvalue(result) + elif op.result is not None: + potential_ops[op.result] = op class BogusPureField(JitException): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6412,6 +6412,23 @@ """ self.optimize_loop(ops, expected) + def test_setgetfield_counter(self): + ops = """ + [p1] + i2 = getfield_gc(p1, descr=valuedescr) + i3 = int_add(i2, 1) + setfield_gc(p1, i3, descr=valuedescr) + jump(p1) + """ + expected = """ + [p1, i1] + i2 = int_add(i1, 1) + setfield_gc(p1, i2, descr=valuedescr) + jump(p1, i2) + """ + self.optimize_loop(ops, expected) + + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass From noreply at buildbot.pypy.org Sat Jul 2 19:13:34 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sat, 2 Jul 2011 19:13:34 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: hg merge default Message-ID: <20110702171334.8D84F82940@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45277:2af475502586 Date: 2011-07-02 08:18 +0200 http://bitbucket.org/pypy/pypy/changeset/2af475502586/ Log: hg merge default diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -357,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -385,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -129,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -266,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -355,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -248,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1060,18 +1060,6 @@ def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -214,15 +214,6 @@ bm = A().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self - assert bm.im_class is A - if '__pypy__' in sys.builtin_module_names: - assert bm.__objclass__ is A assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) - l = [] - assert l.append.__self__ is l - if '__pypy__' in sys.builtin_module_names: - assert l.append.__objclass__ is list - assert l.__add__.__self__ is l - assert l.__add__.__objclass__ is list diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -771,7 +771,6 @@ im_self = interp_attrproperty_w('w_instance', cls=Method), __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), - __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -92,7 +92,7 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -847,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -552,7 +552,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1233,7 +1233,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -338,12 +338,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -351,10 +351,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -363,11 +363,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -380,11 +380,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -396,11 +396,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -416,19 +416,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -1286,7 +1286,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1346,7 +1346,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1411,7 +1411,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1530,7 +1530,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1565,7 +1565,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1629,9 +1629,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1850,7 +1850,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2138,7 +2138,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2183,7 +2183,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2259,7 +2259,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2328,7 +2328,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -605,7 +605,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -614,7 +614,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -631,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -799,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -829,8 +828,6 @@ return struct.unpack(') setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i8, descr=) """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + w_dict = jit.promote(w_dict) + self = jit.promote(self) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + @jit.elidable + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,79 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): - if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -5,15 +5,16 @@ from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS -from pypy.rlib.objectmodel import r_dict, we_are_translated +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize from pypy.rlib.debug import mark_dict_non_null +from pypy.rlib import rerased + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -29,49 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w, - force_non_null=True) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -90,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -142,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -151,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -161,106 +140,87 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_length(self): - return len(self.r_dict_content) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def length(self, w_dict): + return 0 + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def clear(self, w_dict): + return - -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -302,322 +262,255 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = {} - mark_dict_non_null(self.content) +class AbstractTypedStrategy(object): + _mixin_ = True - def impl_setitem(self, w_key, w_value): + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, key, w_value): - assert key is not None - self.content[key] = w_value + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] return - elif _is_sane_hash(space, w_key_type): - raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) - def impl_length(self): - return len(self.content) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) - def impl_getitem_str(self, key): + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) + + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return ObjectIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + + def setitem_str(self, w_dict, key, w_value): assert key is not None - return self.content.get(key, None) + self.unerase(w_dict.dstorage)[key] = w_value - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().impl_fallback_getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) - def impl_delitem(self, w_key): + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) + return space.is_w(space.type(w_obj), space.w_int) - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) -class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): +class IntIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - + return None, None init_signature = Signature(['seq_or_map'], None, 'kwargs') diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,119 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -322,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -233,6 +234,31 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2:2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a",1) in l + assert (2,2) in l + assert ("c",3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a",1) in l + assert ("b",2) in l + assert ("c",3) in l + def test_setdefault(self): d = {1:2, 3:4} dd = d.copy() @@ -527,6 +553,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +738,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +753,64 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -759,6 +851,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj @@ -790,6 +886,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +899,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +931,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1016,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1031,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1075,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1087,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1108,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,19 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + + def test_slot_name_conflict(self): class A(object): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: @@ -447,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,8 +6,8 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) @@ -16,13 +16,18 @@ (3) the function call can be moved around by optimizer, but only so it'll be called earlier and not later. - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -38,6 +43,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -62,13 +71,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -87,6 +96,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -74,7 +74,7 @@ raise KeyError @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) @@ -253,7 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -869,6 +869,7 @@ global_popitem_index.nextindex = base + counter return i + at jit.dont_look_inside def ll_popitem(ELEM, dic): i = _ll_getnextitem(dic) entry = dic.entries[i] diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,8 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - # it's pure but it does not look like it - @purefunction + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -342,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -352,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -370,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -387,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -428,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -451,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -471,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -487,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -504,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -516,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -527,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -595,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -718,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -816,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -831,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -842,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError From noreply at buildbot.pypy.org Sat Jul 2 19:13:35 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sat, 2 Jul 2011 19:13:35 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: test for retracelimit without external loop Message-ID: <20110702171335.CF7CC82940@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45278:08b9eca1a26f Date: 2011-07-02 09:34 +0200 http://bitbucket.org/pypy/pypy/changeset/08b9eca1a26f/ Log: test for retracelimit without external loop diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2623,6 +2623,59 @@ # 1 preamble and 6 speciealized versions of each loop self.check_tree_loop_count(2*(1 + 6)) + def test_nested_retrace(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'a', 'i', 'j', 'sa']) + bytecode = "ij+Jj+JI" + def f(n, a): + myjitdriver.set_param('threshold', 5) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 2) + pc = sa = i = j = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i, j=j, a=a) + a = hint(a, promote=True) + op = bytecode[pc] + if op == 'i': + i = 0 + elif op == 'j': + j = 0 + elif op == '+': + sa += a + elif op == 'J': + j += 1 + if j < 3: + pc -= 1 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i, j=j, a=a) + continue + elif op == 'I': + i += 1 + if i < n: + pc -= 6 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i, j=j, a=a) + continue + pc += 1 + return sa + + res = self.meta_interp(f, [10, 7]) + assert res == f(10, 7) + self.check_tree_loop_count(4) + + def g(n): + return f(n, 2) + f(n, 3) + + res = self.meta_interp(g, [10]) + assert res == g(10) + self.check_tree_loop_count(6) + + + def g(n): + return f(n, 2) + f(n, 3) + f(n, 4) + f(n, 5) + f(n, 6) + f(n, 7) + + res = self.meta_interp(g, [10]) + assert res == g(10) + self.check_tree_loop_count(8) + def test_frame_finished_during_retrace(self): class Base(object): pass From noreply at buildbot.pypy.org Sat Jul 2 19:13:37 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sat, 2 Jul 2011 19:13:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Cherry picked the retrace count bugfix from fcbb3a03ff88. The test is not working anymore. There seems to be two entry bridges created now, dont know why... Message-ID: <20110702171337.1E57982940@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: Changeset: r45279:72e8d0b95d88 Date: 2011-07-02 19:19 +0200 http://bitbucket.org/pypy/pypy/changeset/72e8d0b95d88/ Log: Cherry picked the retrace count bugfix from fcbb3a03ff88. The test is not working anymore. There seems to be two entry bridges created now, dont know why... diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count Author: Hakan Ardo Branch: Changeset: r45280:fa7e6a38b0da Date: 2011-07-02 19:20 +0200 http://bitbucket.org/pypy/pypy/changeset/fa7e6a38b0da/ Log: hg merge diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py --- a/pypy/module/pyexpat/__init__.py +++ b/pypy/module/pyexpat/__init__.py @@ -2,6 +2,22 @@ from pypy.interpreter.mixedmodule import MixedModule +class ErrorsModule(MixedModule): + "Definition of pyexpat.errors module." + + appleveldefs = { + } + + interpleveldefs = { + } + + def setup_after_space_initialization(self): + from pypy.module.pyexpat import interp_pyexpat + for name in interp_pyexpat.xml_error_list: + self.space.setattr(self, self.space.wrap(name), + interp_pyexpat.ErrorString(self.space, + getattr(interp_pyexpat, name))) + class Module(MixedModule): "Python wrapper for Expat parser." @@ -21,6 +37,10 @@ 'version_info': 'interp_pyexpat.get_expat_version_info(space)', } + submodules = { + 'errors': ErrorsModule, + } + for name in ['XML_PARAM_ENTITY_PARSING_NEVER', 'XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE', 'XML_PARAM_ENTITY_PARSING_ALWAYS']: diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -31,6 +31,48 @@ XML_Content_Ptr = lltype.Ptr(lltype.ForwardReference()) XML_Parser = rffi.COpaquePtr(typedef='XML_Parser') +xml_error_list = [ + "XML_ERROR_NO_MEMORY", + "XML_ERROR_SYNTAX", + "XML_ERROR_NO_ELEMENTS", + "XML_ERROR_INVALID_TOKEN", + "XML_ERROR_UNCLOSED_TOKEN", + "XML_ERROR_PARTIAL_CHAR", + "XML_ERROR_TAG_MISMATCH", + "XML_ERROR_DUPLICATE_ATTRIBUTE", + "XML_ERROR_JUNK_AFTER_DOC_ELEMENT", + "XML_ERROR_PARAM_ENTITY_REF", + "XML_ERROR_UNDEFINED_ENTITY", + "XML_ERROR_RECURSIVE_ENTITY_REF", + "XML_ERROR_ASYNC_ENTITY", + "XML_ERROR_BAD_CHAR_REF", + "XML_ERROR_BINARY_ENTITY_REF", + "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", + "XML_ERROR_MISPLACED_XML_PI", + "XML_ERROR_UNKNOWN_ENCODING", + "XML_ERROR_INCORRECT_ENCODING", + "XML_ERROR_UNCLOSED_CDATA_SECTION", + "XML_ERROR_EXTERNAL_ENTITY_HANDLING", + "XML_ERROR_NOT_STANDALONE", + "XML_ERROR_UNEXPECTED_STATE", + "XML_ERROR_ENTITY_DECLARED_IN_PE", + "XML_ERROR_FEATURE_REQUIRES_XML_DTD", + "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING", + # Added in Expat 1.95.7. + "XML_ERROR_UNBOUND_PREFIX", + # Added in Expat 1.95.8. + "XML_ERROR_UNDECLARING_PREFIX", + "XML_ERROR_INCOMPLETE_PE", + "XML_ERROR_XML_DECL", + "XML_ERROR_TEXT_DECL", + "XML_ERROR_PUBLICID", + "XML_ERROR_SUSPENDED", + "XML_ERROR_NOT_SUSPENDED", + "XML_ERROR_ABORTED", + "XML_ERROR_FINISHED", + "XML_ERROR_SUSPEND_PE", + ] + class CConfigure: _compilation_info_ = eci XML_Content = rffi_platform.Struct('XML_Content', [ @@ -56,6 +98,9 @@ XML_FALSE = rffi_platform.ConstantInteger('XML_FALSE') XML_TRUE = rffi_platform.ConstantInteger('XML_TRUE') + for name in xml_error_list: + locals()[name] = rffi_platform.ConstantInteger(name) + for k, v in rffi_platform.configure(CConfigure).items(): globals()[k] = v @@ -298,7 +343,8 @@ XML_GetErrorCode = expat_external( 'XML_GetErrorCode', [XML_Parser], rffi.INT) XML_ErrorString = expat_external( - 'XML_ErrorString', [rffi.INT], rffi.CCHARP) + 'XML_ErrorString', [rffi.INT], + rffi.CCHARP) XML_GetCurrentLineNumber = expat_external( 'XML_GetCurrentLineNumber', [XML_Parser], rffi.INT) XML_GetErrorLineNumber = XML_GetCurrentLineNumber diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py --- a/pypy/module/pyexpat/test/test_parser.py +++ b/pypy/module/pyexpat/test/test_parser.py @@ -38,7 +38,7 @@ parser = pyexpat.ParserCreate() raises(pyexpat.ExpatError, "parser.Parse(xml, True)") - def test_encoding(self): + def test_encoding_argument(self): import pyexpat for encoding_arg in (None, 'utf-8', 'iso-8859-1'): for namespace_arg in (None, '{'): @@ -68,7 +68,7 @@ assert p.buffer_size == 150 raises(TypeError, setattr, p, 'buffer_size', sys.maxint + 1) - def test_encoding(self): + def test_encoding_xml(self): # use one of the few encodings built-in in expat xml = "caf\xe9" import pyexpat @@ -120,3 +120,14 @@ return True p.ExternalEntityRefHandler = handler p.Parse(xml) + + def test_errors(self): + import types + import pyexpat + assert isinstance(pyexpat.errors, types.ModuleType) + # check a few random errors + assert pyexpat.errors.XML_ERROR_SYNTAX == 'syntax error' + assert (pyexpat.errors.XML_ERROR_INCORRECT_ENCODING == + 'encoding specified in XML declaration is incorrect') + assert (pyexpat.errors.XML_ERROR_XML_DECL == + 'XML declaration not well-formed') From noreply at buildbot.pypy.org Sat Jul 2 19:19:40 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sat, 2 Jul 2011 19:19:40 +0200 (CEST) Subject: [pypy-commit] pypy default: fix test Message-ID: <20110702171940.BBD3782940@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: Changeset: r45281:614fe9ee6621 Date: 2011-07-02 19:26 +0200 http://bitbucket.org/pypy/pypy/changeset/614fe9ee6621/ Log: fix test diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2322,6 +2322,7 @@ myjitdriver.set_param('threshold', 3) myjitdriver.set_param('trace_eagerness', 1) myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) pc = sa = i = 0 while pc < len(bytecode): myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) From noreply at buildbot.pypy.org Sat Jul 2 19:20:21 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 2 Jul 2011 19:20:21 +0200 (CEST) Subject: [pypy-commit] pypy default: Added popitem() to module dictionaries, and fixed a bug with degenerating them when there are invalidated cells. Message-ID: <20110702172021.0367F82940@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45282:ac31a98dad24 Date: 2011-07-02 10:26 -0700 http://bitbucket.org/pypy/pypy/changeset/ac31a98dad24/ Log: Added popitem() to module dictionaries, and fixed a bug with degenerating them when there are invalidated cells. diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -139,12 +139,24 @@ for k, cell in iterator(): cell.invalidate() + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): + if cell.w_value is not None: + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError + def switch_to_object_strategy(self, w_dict): d = self.unerase(w_dict.dstorage) strategy = self.space.fromcache(ObjectDictStrategy) d_new = strategy.unerase(strategy.get_empty_storage()) for key, cell in d.iteritems(): - d_new[self.space.wrap(key)] = cell.w_value + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new) diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -38,3 +38,31 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file From noreply at buildbot.pypy.org Sat Jul 2 19:20:22 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 2 Jul 2011 19:20:22 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20110702172022.44D3B82940@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45283:bfe1dfefd9a1 Date: 2011-07-02 10:27 -0700 http://bitbucket.org/pypy/pypy/changeset/bfe1dfefd9a1/ Log: merged upstream diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count Author: Alex Gaynor Branch: Changeset: r45284:e572b99a233b Date: 2011-07-02 10:27 -0700 http://bitbucket.org/pypy/pypy/changeset/e572b99a233b/ Log: merged upstream, again H: Enter commit message. Lines beginning with 'HG:' are removed. diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2322,6 +2322,7 @@ myjitdriver.set_param('threshold', 3) myjitdriver.set_param('trace_eagerness', 1) myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) pc = sa = i = 0 while pc < len(bytecode): myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) From noreply at buildbot.pypy.org Sun Jul 3 00:11:39 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Sun, 3 Jul 2011 00:11:39 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: some things are hard, see comment in test_ll2ctypes.py Message-ID: <20110702221139.BAF2082940@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45285:8b145e7769f3 Date: 2011-07-03 00:14 +0200 http://bitbucket.org/pypy/pypy/changeset/8b145e7769f3/ Log: some things are hard, see comment in test_ll2ctypes.py diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -177,8 +177,8 @@ MAX_SIZE = n/64 try: PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item) - except OverflowError, e: - pass + except (OverflowError, AttributeError), e: + pass # ^^^ bah, blame ctypes else: break else: diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -21,6 +21,21 @@ from pypy.rpython.lltypesystem import ll2ctypes ll2ctypes.do_allocation_in_far_regions() +""" +Win64: +To decouple the cpython machine level long from the faked integer +of the target rpython, I replaced most 'lltype.Signed' by 'rffi.LONG'. +It would be nicer to replace all lltypes constants by rffi equivalents, +or better if we had a way to address the specific different types of +the current and the target system layout explicitly. +Let's think of that when we go further and make the target completely +independent and configurable. +Why most and not all replaced? +Tests with direct tests become cumbersome, instead of direct number +assignment rffi.setintfield(s, 'x', 123) must be used. +So in cases with number constants, where the size is not relevant, +I kept lltype.signed . +""" class TestLL2Ctypes(object): @@ -32,7 +47,7 @@ assert lltype2ctypes('?') == ord('?') assert lltype2ctypes('\xE0') == 0xE0 assert lltype2ctypes(unichr(1234)) == 1234 - assert ctypes2lltype(lltype.Signed, 5) == 5 + assert ctypes2lltype(rffi.LONG, 5) == 5 assert ctypes2lltype(lltype.Char, ord('a')) == 'a' assert ctypes2lltype(lltype.UniChar, ord(u'x')) == u'x' assert ctypes2lltype(lltype.Char, 0xFF) == '\xFF' @@ -68,7 +83,7 @@ def test_simple_struct(self): S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed)) s = lltype.malloc(S, flavor='raw') - s.x = 123 + rffi.setintfield(s, 'x', 123) sc = lltype2ctypes(s) assert isinstance(sc.contents, ctypes.Structure) assert sc.contents.x == 123 @@ -124,7 +139,7 @@ def test_array_inside_struct(self): # like rstr.STR, but not Gc - STR = lltype.Struct('STR', ('x', lltype.Signed), ('y', lltype.Array(lltype.Char))) + STR = lltype.Struct('STR', ('x', rffi.LONG), ('y', lltype.Array(lltype.Char))) a = lltype.malloc(STR, 3, flavor='raw') a.y[0] = 'x' a.y[1] = 'y' @@ -139,6 +154,11 @@ assert not ALLOCATED def test_array_nolength(self): + # XXX cannot fix this test when lltype.Signed is faked for win64. + # Replacement with rffi.LONG does not work because then I cannot + # index an array. So I have to use lltype.Signed . But the rffi.sizeof + # at the end has a hard-coded mapping to LONG and ignores the faked + # maxint. So what should I do? A = lltype.Array(lltype.Signed, hints={'nolength': True}) a = lltype.malloc(A, 10, flavor='raw') a[0] = 100 @@ -151,7 +171,7 @@ assert a[2] == 456 a[3] = 789 assert ac.contents.items[3] == 789 - assert ctypes.sizeof(ac.contents) == 10 * ctypes.sizeof(ctypes.c_long) + assert ctypes.sizeof(ac.contents) == 10 * rffi.sizeof(lltype.Signed) lltype.free(a, flavor='raw') assert not ALLOCATED # detects memory leaks in the test @@ -203,20 +223,20 @@ def test_func_not_in_clib(self): eci = ExternalCompilationInfo(libraries=['m']) - foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed) + foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG) py.test.raises(NotImplementedError, foobar) - foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed, + foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG, compilation_info=eci) # math library py.test.raises(NotImplementedError, foobar) eci = ExternalCompilationInfo(libraries=['m', 'z']) - foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed, + foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG, compilation_info=eci) # math and zlib py.test.raises(NotImplementedError, foobar) eci = ExternalCompilationInfo(libraries=['I_really_dont_exist_either']) - foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed, + foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG, compilation_info=eci) py.test.raises(NotImplementedError, foobar) assert not ALLOCATED # detects memory leaks in the test @@ -398,7 +418,7 @@ assert e[i] == i*i c = lltype.nullptr(rffi.VOIDP.TO) - addr = rffi.cast(lltype.Signed, c) + addr = rffi.cast(rffi.LONG, c) assert addr == 0 lltype.free(a, flavor='raw') @@ -422,7 +442,7 @@ def dummy(n): return n+1 - FUNCTYPE = lltype.FuncType([lltype.Signed], lltype.Signed) + FUNCTYPE = lltype.FuncType([rffi.LONG], rffi.LONG) cdummy = lltype2ctypes(llhelper(lltype.Ptr(FUNCTYPE), dummy)) assert isinstance(cdummy, ctypes.CFUNCTYPE(ctypes.c_long, ctypes.c_long)) @@ -435,7 +455,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_funcptr2(self): - FUNCTYPE = lltype.FuncType([rffi.CCHARP], lltype.Signed) + FUNCTYPE = lltype.FuncType([rffi.CCHARP], rffi.LONG) cstrlen = standard_c_lib.strlen llstrlen = ctypes2lltype(lltype.Ptr(FUNCTYPE), cstrlen) assert lltype.typeOf(llstrlen) == lltype.Ptr(FUNCTYPE) @@ -459,13 +479,13 @@ export_symbols=['get_mul']) get_mul = rffi.llexternal( 'get_mul', [], - lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)), + lltype.Ptr(lltype.FuncType([rffi.LONG], rffi.LONG)), compilation_info=eci) # This call returns a pointer to a function taking one argument funcptr = get_mul() # cast it to the "real" function type - FUNCTYPE2 = lltype.FuncType([lltype.Signed, lltype.Signed], - lltype.Signed) + FUNCTYPE2 = lltype.FuncType([rffi.LONG, rffi.LONG], + rffi.LONG) cmul = rffi.cast(lltype.Ptr(FUNCTYPE2), funcptr) # and it can be called with the expected number of arguments res = cmul(41, 42) @@ -482,12 +502,12 @@ lltype.Void) lst = [23, 43, 24, 324, 242, 34, 78, 5, 3, 10] - A = lltype.Array(lltype.Signed, hints={'nolength': True}) + A = lltype.Array(rffi.LONG, hints={'nolength': True}) a = lltype.malloc(A, 10, flavor='raw') for i in range(10): a[i] = lst[i] - SIGNEDPTR = lltype.Ptr(lltype.FixedSizeArray(lltype.Signed, 1)) + SIGNEDPTR = lltype.Ptr(lltype.FixedSizeArray(rffi.LONG, 1)) def my_compar(p1, p2): p1 = rffi.cast(SIGNEDPTR, p1) @@ -497,7 +517,7 @@ qsort(rffi.cast(rffi.VOIDP, a), rffi.cast(rffi.SIZE_T, 10), - rffi.cast(rffi.SIZE_T, llmemory.sizeof(lltype.Signed)), + rffi.cast(rffi.SIZE_T, llmemory.sizeof(rffi.LONG)), llhelper(lltype.Ptr(CMPFUNC), my_compar)) for i in range(10): @@ -534,7 +554,7 @@ checkobj(uninitialized2ctypes(rffi.CCHARP), ctypes.sizeof(ctypes.c_void_p)) - S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed)) + S = lltype.Struct('S', ('x', rffi.LONG), ('y', rffi.LONG)) s = lltype.malloc(S, flavor='raw') sc = lltype2ctypes(s) checkval(sc.contents.x, 'l') @@ -543,7 +563,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_substructures(self): - S1 = lltype.Struct('S1', ('x', lltype.Signed)) + S1 = lltype.Struct('S1', ('x', rffi.LONG)) BIG = lltype.Struct('BIG', ('s1a', S1), ('s1b', S1)) s = lltype.malloc(BIG, flavor='raw') s.s1a.x = 123 @@ -593,7 +613,7 @@ def test_recursive_struct(self): SX = lltype.ForwardReference() - S1 = lltype.Struct('S1', ('p', lltype.Ptr(SX)), ('x', lltype.Signed)) + S1 = lltype.Struct('S1', ('p', lltype.Ptr(SX)), ('x', rffi.LONG)) SX.become(S1) # a chained list s1 = lltype.malloc(S1, flavor='raw') @@ -671,7 +691,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_arrayofstruct(self): - S1 = lltype.Struct('S1', ('x', lltype.Signed)) + S1 = lltype.Struct('S1', ('x', rffi.LONG)) A = lltype.Array(S1, hints={'nolength': True}) a = lltype.malloc(A, 5, flavor='raw') a[0].x = 100 @@ -710,7 +730,7 @@ buffer = lltype.malloc(rffi.CCHARP.TO, 5, flavor='raw') written = os_write(12312312, buffer, 5) lltype.free(buffer, flavor='raw') - assert rffi.cast(lltype.Signed, written) < 0 + assert rffi.cast(rffi.LONG, written) < 0 # the next line is a random external function call, # to check that it doesn't reset errno strlen("hi!") @@ -829,9 +849,9 @@ return one + get_x() def fy(): - one = rffi.cast(lltype.Signed, get_y()) + one = rffi.cast(rffi.LONG, get_y()) set_y(rffi.cast(rffi.INT, 13)) - return one + rffi.cast(lltype.Signed, get_y()) + return one + rffi.cast(rffi.LONG, get_y()) def g(): l = rffi.liststr2charpp(["a", "b", "c"]) @@ -896,7 +916,7 @@ lltype.free(a, flavor='raw') def test_array_type_bug(self): - A = lltype.Array(lltype.Signed) + A = lltype.Array(rffi.LONG) a1 = lltype.malloc(A, 0, flavor='raw') a2 = lltype.malloc(A, 0, flavor='raw') c1 = lltype2ctypes(a1) @@ -907,7 +927,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_varsized_struct(self): - S = lltype.Struct('S', ('x', lltype.Signed), + S = lltype.Struct('S', ('x', rffi.LONG), ('a', lltype.Array(lltype.Char))) s1 = lltype.malloc(S, 6, flavor='raw') s1.x = 5 @@ -930,7 +950,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_with_explicit_length(self): - A = lltype.Array(lltype.Signed) + A = lltype.Array(rffi.LONG) a1 = lltype.malloc(A, 5, flavor='raw') a1[0] = 42 c1 = lltype2ctypes(a1, normalize=False) @@ -986,7 +1006,7 @@ def test_recursive_struct_more(self): NODE = lltype.ForwardReference() - NODE.become(lltype.Struct('NODE', ('value', lltype.Signed), + NODE.become(lltype.Struct('NODE', ('value', rffi.LONG), ('next', lltype.Ptr(NODE)))) CNODEPTR = get_ctypes_type(NODE) pc = CNODEPTR() @@ -1014,11 +1034,11 @@ assert p.pong.ping == p def test_typedef(self): - assert ctypes2lltype(lltype.Typedef(lltype.Signed, 'test'), 6) == 6 + assert ctypes2lltype(lltype.Typedef(rffi.LONG, 'test'), 6) == 6 assert ctypes2lltype(lltype.Typedef(lltype.Float, 'test2'), 3.4) == 3.4 - assert get_ctypes_type(lltype.Signed) == get_ctypes_type( - lltype.Typedef(lltype.Signed, 'test3')) + assert get_ctypes_type(rffi.LONG) == get_ctypes_type( + lltype.Typedef(rffi.LONG, 'test3')) def test_cast_adr_to_int(self): class someaddr(object): @@ -1026,14 +1046,14 @@ return sys.maxint/2 * 3 res = cast_adr_to_int(someaddr()) - assert isinstance(res, int) + assert isinstance(res, (int, long)) assert res == -sys.maxint/2 - 3 def test_cast_gcref_back_and_forth(self): NODE = lltype.GcStruct('NODE') node = lltype.malloc(NODE) ref = lltype.cast_opaque_ptr(llmemory.GCREF, node) - back = rffi.cast(llmemory.GCREF, rffi.cast(lltype.Signed, ref)) + back = rffi.cast(llmemory.GCREF, rffi.cast(rffi.LONG, ref)) assert lltype.cast_opaque_ptr(lltype.Ptr(NODE), back) == node def test_gcref_forth_and_back(self): @@ -1060,12 +1080,12 @@ def test_cast_null_gcref(self): ref = lltype.nullptr(llmemory.GCREF.TO) - value = rffi.cast(lltype.Signed, ref) + value = rffi.cast(rffi.LONG, ref) assert value == 0 def test_cast_null_fakeaddr(self): ref = llmemory.NULL - value = rffi.cast(lltype.Signed, ref) + value = rffi.cast(rffi.LONG, ref) assert value == 0 def test_gcref_truth(self): @@ -1090,8 +1110,8 @@ node = lltype.malloc(NODE) ref1 = lltype.cast_opaque_ptr(llmemory.GCREF, node) - intval = rffi.cast(lltype.Signed, node) - intval1 = rffi.cast(lltype.Signed, ref1) + intval = rffi.cast(rffi.LONG, node) + intval1 = rffi.cast(rffi.LONG, ref1) assert intval == intval1 @@ -1123,7 +1143,7 @@ assert node._obj._storage is True # forced! - rffi.cast(lltype.Signed, ref1) + rffi.cast(rffi.LONG, ref1) assert node._obj._storage not in (True, None) assert ref1 != ref2 @@ -1136,7 +1156,7 @@ NODE = lltype.GcStruct('NODE') node = lltype.malloc(NODE) ref1 = lltype.cast_opaque_ptr(llmemory.GCREF, node) - numb = rffi.cast(lltype.Signed, ref1) + numb = rffi.cast(rffi.LONG, ref1) ref2 = rffi.cast(llmemory.GCREF, numb) assert ref1 == ref2 assert ref2 == ref1 @@ -1144,16 +1164,16 @@ assert not (ref2 != ref1) def test_convert_subarray(self): - A = lltype.GcArray(lltype.Signed) + A = lltype.GcArray(rffi.LONG) a = lltype.malloc(A, 20) inside = lltype.direct_ptradd(lltype.direct_arrayitems(a), 3) lltype2ctypes(inside) - start = rffi.cast(lltype.Signed, lltype.direct_arrayitems(a)) - inside_int = rffi.cast(lltype.Signed, inside) + start = rffi.cast(rffi.LONG, lltype.direct_arrayitems(a)) + inside_int = rffi.cast(rffi.LONG, inside) - assert inside_int == start+rffi.sizeof(lltype.Signed)*3 + assert inside_int == start+rffi.sizeof(rffi.LONG)*3 def test_gcref_comparisons_through_addresses(self): NODE = lltype.GcStruct('NODE') @@ -1161,7 +1181,7 @@ adr0 = llmemory.cast_ptr_to_adr(n0) n1 = lltype.malloc(NODE) - i1 = rffi.cast(lltype.Signed, n1) + i1 = rffi.cast(rffi.LONG, n1) ref1 = rffi.cast(llmemory.GCREF, i1) adr1 = llmemory.cast_ptr_to_adr(ref1) @@ -1184,7 +1204,7 @@ s = S() s.x = n ls = cast_instance_to_base_ptr(s) - as_num = rffi.cast(lltype.Signed, ls) + as_num = rffi.cast(rffi.LONG, ls) # --- around this point, only 'as_num' is passed t = rffi.cast(rclass.OBJECTPTR, as_num) u = cast_base_ptr_to_instance(S, t) @@ -1196,7 +1216,7 @@ from pypy.rpython.lltypesystem import rclass SCLASS = lltype.GcStruct('SCLASS', ('parent', rclass.OBJECT), - ('n', lltype.Signed)) + ('n', rffi.LONG)) sclass_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True, immortal=True) sclass_vtable.name = rclass.alloc_array_name('SClass') @@ -1205,7 +1225,7 @@ s = lltype.malloc(SCLASS) s.parent.typeptr = sclass_vtable s.n = n - as_num = rffi.cast(lltype.Signed, s) + as_num = rffi.cast(rffi.LONG, s) # --- around this point, only 'as_num' is passed t = rffi.cast(lltype.Ptr(SCLASS), as_num) return t.n @@ -1222,7 +1242,7 @@ s = S() s.x = n ls = cast_instance_to_base_ptr(s) - as_num = rffi.cast(lltype.Signed, ls) + as_num = rffi.cast(rffi.LONG, ls) # --- around this point, only 'as_num' is passed r = rffi.cast(llmemory.GCREF, as_num) t = lltype.cast_opaque_ptr(rclass.OBJECTPTR, r) @@ -1235,7 +1255,7 @@ from pypy.rpython.lltypesystem import rclass SCLASS = lltype.GcStruct('SCLASS', ('parent', rclass.OBJECT), - ('n', lltype.Signed)) + ('n', rffi.LONG)) sclass_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True, immortal=True) sclass_vtable.name = rclass.alloc_array_name('SClass') @@ -1244,7 +1264,7 @@ s = lltype.malloc(SCLASS) s.parent.typeptr = sclass_vtable s.n = n - as_num = rffi.cast(lltype.Signed, s) + as_num = rffi.cast(rffi.LONG, s) # --- around this point, only 'as_num' is passed r = rffi.cast(llmemory.GCREF, as_num) t = lltype.cast_opaque_ptr(lltype.Ptr(SCLASS), r) @@ -1263,7 +1283,7 @@ def f(): s = T() ls = cast_instance_to_base_ptr(s) - as_num = rffi.cast(lltype.Signed, ls) + as_num = rffi.cast(rffi.LONG, ls) # --- around this point, only 'as_num' is passed t = rffi.cast(rclass.OBJECTPTR, as_num) u = cast_base_ptr_to_instance(S, t) @@ -1281,7 +1301,7 @@ lltype.free(p, flavor='raw') def test_freelist(self): - S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed)) + S = lltype.Struct('S', ('x', rffi.LONG), ('y', rffi.LONG)) SP = lltype.Ptr(S) chunk = lltype.malloc(rffi.CArrayPtr(S).TO, 10, flavor='raw') assert lltype.typeOf(chunk) == rffi.CArrayPtr(S) From noreply at buildbot.pypy.org Sun Jul 3 00:11:41 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Sun, 3 Jul 2011 00:11:41 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: merge Message-ID: <20110702221141.065D182940@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45286:0caf6570c62d Date: 2011-07-03 00:16 +0200 http://bitbucket.org/pypy/pypy/changeset/0caf6570c62d/ Log: merge diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -1,6 +1,5 @@ import __builtin__ import types -import sys from pypy.interpreter import pyframe, function, special from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.error import OperationError, operationerrfmt @@ -10,7 +9,7 @@ from pypy.objspace.descroperation import DescrOperation, raiseattrerror from pypy.rlib.objectmodel import instantiate, r_dict, specialize from pypy.rlib.debug import make_sure_not_resized -from pypy.rlib.rarithmetic import base_int, widen +from pypy.rlib.rarithmetic import base_int, widen, is_valid_int from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.jit import hint from pypy.rlib.rbigint import rbigint @@ -162,7 +161,7 @@ if isinstance(x, OperationError): raise TypeError, ("attempt to wrap already wrapped exception: %s"% (x,)) - if isinstance(x, (int, long)) and -sys.maxint -1 <= x <= sys.maxint: + if isinstance(x, (int, long)) and is_valid_int(x): if isinstance(x, bool): return self.newbool(x) else: diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -70,7 +70,7 @@ if isinstance(n, objectmodel.Symbolic): return n # assume Symbolics don't overflow assert not isinstance(n, float) - if -sys.maxint -1 < n < sys.maxint: + if is_valid_int(n): return int(n) n = long(n) n &= LONG_MASK @@ -109,6 +109,9 @@ del _bits, _test, _maxnumber +def is_valid_int(r): + return -sys.maxint - 1 <= r <= sys.maxint + def ovfcheck(r): "NOT_RPYTHON" # to be used as ovfcheck(x y) @@ -116,7 +119,7 @@ assert not isinstance(r, r_uint), "unexpected ovf check on unsigned" assert not isinstance(r, r_longlong), "ovfcheck not supported on r_longlong" assert not isinstance(r, r_ulonglong), "ovfcheck not supported on r_ulonglong" - if r > sys.maxint or r < -sys.maxint - 1: + if not is_valid_int(r): raise OverflowError, "signed integer expression did overflow" return r diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -1,5 +1,5 @@ from pypy.rlib.rarithmetic import LONG_BIT, intmask, r_uint, r_ulonglong -from pypy.rlib.rarithmetic import ovfcheck, r_longlong, widen +from pypy.rlib.rarithmetic import ovfcheck, r_longlong, widen, is_valid_int from pypy.rlib.rarithmetic import most_neg_value_of_same_type from pypy.rlib.rfloat import isfinite from pypy.rlib.debug import make_sure_not_resized, check_regular_int @@ -51,14 +51,14 @@ def _widen_digit(x): if not we_are_translated(): - assert type(x) in (int, long), "widen_digit() takes an int, got a %r" % type(x) + assert type(x) in (int, long) and is_valid_int(x), "widen_digit() takes an int, got a %r" % type(x) if SHIFT <= 15: return int(x) return r_longlong(x) def _store_digit(x): if not we_are_translated(): - assert type(x) in (int, long), "store_digit() takes an int, got a %r" % type(x) + assert type(x) in (int, long) and is_valid_int(x), "store_digit() takes an int, got a %r" % type(x) if SHIFT <= 15: return rffi.cast(rffi.SHORT, x) elif SHIFT <= 31: From noreply at buildbot.pypy.org Sun Jul 3 00:56:31 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 00:56:31 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: x86 support for {get, set}interiorfield Message-ID: <20110702225631.97FB482940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45287:7ed3b28dad4a Date: 2011-07-03 00:31 +0200 http://bitbucket.org/pypy/pypy/changeset/7ed3b28dad4a/ Log: x86 support for {get,set}interiorfield diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -139,6 +139,13 @@ cachedict[fieldname] = fielddescr return fielddescr +# ____________________________________________________________ +# InteriorFieldDescr + +class InteriorFieldDescr(AbstractDescr): + def __init__(self, arraydescr, fielddescr): + self.arraydescr = arraydescr + self.fielddescr = fielddescr # ____________________________________________________________ # ArrayDescrs diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -8,12 +8,10 @@ from pypy.jit.backend.model import AbstractCPU from pypy.jit.backend.llsupport import symbolic from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes -from pypy.jit.backend.llsupport.descr import get_size_descr -from pypy.jit.backend.llsupport.descr import get_field_descr, BaseFieldDescr -from pypy.jit.backend.llsupport.descr import get_array_descr, BaseArrayDescr -from pypy.jit.backend.llsupport.descr import get_call_descr -from pypy.jit.backend.llsupport.descr import BaseIntCallDescr, GcPtrCallDescr -from pypy.jit.backend.llsupport.descr import FloatCallDescr, VoidCallDescr +from pypy.jit.backend.llsupport.descr import (get_size_descr, + get_field_descr, BaseFieldDescr, get_array_descr, BaseArrayDescr, + get_call_descr, BaseIntCallDescr, GcPtrCallDescr, FloatCallDescr, + VoidCallDescr, InteriorFieldDescr) from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager @@ -237,6 +235,11 @@ def arraydescrof(self, A): return get_array_descr(self.gc_ll_descr, A) + def interiorfielddescrof(self, A, fieldname): + arraydescr = get_array_descr(self.gc_ll_descr, A) + fielddescr = get_field_descr(self.gc_ll_descr, A.OF, fieldname) + return InteriorFieldDescr(arraydescr, fielddescr) + def unpack_arraydescr(self, arraydescr): assert isinstance(arraydescr, BaseArrayDescr) return arraydescr.get_base_size(self.translate_support_code) diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py --- a/pypy/jit/backend/llsupport/regalloc.py +++ b/pypy/jit/backend/llsupport/regalloc.py @@ -278,7 +278,6 @@ self.reg_bindings[to_v] = reg def _move_variable_away(self, v, prev_loc): - reg = None if self.free_regs: loc = self.free_regs.pop() self.reg_bindings[v] = loc diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -1,7 +1,7 @@ import sys, os from pypy.jit.backend.llsupport import symbolic from pypy.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper -from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat +from pypy.jit.metainterp.history import Const, Box, BoxInt, ConstInt from pypy.jit.metainterp.history import (AbstractFailDescr, INT, REF, FLOAT, LoopToken) from pypy.rpython.lltypesystem import lltype, rffi, rstr, llmemory @@ -35,7 +35,6 @@ have_debug_prints) from pypy.rlib import rgc from pypy.jit.backend.x86.jump import remap_frame_layout -from pypy.jit.metainterp.history import ConstInt, BoxInt from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter import longlong @@ -661,8 +660,8 @@ # Also, make sure this is consistent with FRAME_FIXED_SIZE. self.mc.PUSH_r(ebp.value) self.mc.MOV_rr(ebp.value, esp.value) - for regloc in self.cpu.CALLEE_SAVE_REGISTERS: - self.mc.PUSH_r(regloc.value) + for loc in self.cpu.CALLEE_SAVE_REGISTERS: + self.mc.PUSH_r(loc.value) gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap and gcrootmap.is_shadow_stack: @@ -1473,12 +1472,25 @@ genop_getarrayitem_gc_pure = genop_getarrayitem_gc genop_getarrayitem_raw = genop_getarrayitem_gc + def genop_getinteriorfield_gc(self, op, arglocs, resloc): + base_loc, ofs_loc, itemsize_loc, fieldsize_loc, index_loc, sign_loc = arglocs + self.mc.IMUL(index_loc, itemsize_loc) + src_addr = AddressLoc(base_loc, index_loc, 0, ofs_loc.value) + self.load_from_mem(resloc, src_addr, fieldsize_loc, sign_loc) + + def genop_discard_setfield_gc(self, op, arglocs): base_loc, ofs_loc, size_loc, value_loc = arglocs assert isinstance(size_loc, ImmedLoc) dest_addr = AddressLoc(base_loc, ofs_loc) self.save_into_mem(dest_addr, value_loc, size_loc) + def genop_discard_setinteriorfield_gc(self, op, arglocs): + base_loc, ofs_loc, itemsize_loc, fieldsize_loc, index_loc, value_loc = arglocs + self.mc.IMUL(index_loc, itemsize_loc) + dest_addr = AddressLoc(base_loc, index_loc, 0, ofs_loc.value) + self.save_into_mem(dest_addr, value_loc, fieldsize_loc) + def genop_discard_setarrayitem_gc(self, op, arglocs): base_loc, ofs_loc, value_loc, size_loc, baseofs = arglocs assert isinstance(baseofs, ImmedLoc) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -7,7 +7,7 @@ ResOperation, BoxPtr, ConstFloat, BoxFloat, LoopToken, INT, REF, FLOAT) from pypy.jit.backend.x86.regloc import * -from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr +from pypy.rpython.lltypesystem import lltype, rffi, rstr from pypy.rlib.objectmodel import we_are_translated from pypy.rlib import rgc from pypy.jit.backend.llsupport import symbolic @@ -17,11 +17,12 @@ from pypy.jit.metainterp.resoperation import rop from pypy.jit.backend.llsupport.descr import BaseFieldDescr, BaseArrayDescr from pypy.jit.backend.llsupport.descr import BaseCallDescr, BaseSizeDescr +from pypy.jit.backend.llsupport.descr import InteriorFieldDescr from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\ TempBox from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64, MY_COPY_OF_REGS -from pypy.rlib.rarithmetic import r_longlong, r_uint +from pypy.rlib.rarithmetic import r_longlong class X86RegisterManager(RegisterManager): @@ -800,7 +801,7 @@ save_all_regs = guard_not_forced_op is not None self.xrm.before_call(force_store, save_all_regs=save_all_regs) if not save_all_regs: - gcrootmap = gc_ll_descr = self.assembler.cpu.gc_ll_descr.gcrootmap + gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(force_store, save_all_regs=save_all_regs) @@ -1057,6 +1058,16 @@ sign = fielddescr.is_field_signed() return imm(ofs), imm(size), ptr, sign + def _unpack_interiorfielddescr(self, descr): + assert isinstance(descr, InteriorFieldDescr) + arraydescr = descr.arraydescr + ofs = arraydescr.get_base_size(self.translate_support_code) + itemsize = arraydescr.get_item_size(self.translate_support_code) + fieldsize = descr.fielddescr.get_field_size(self.translate_support_code) + sign = descr.fielddescr.is_field_signed() + ofs += descr.fielddescr.offset + return imm(ofs), imm(itemsize), imm(fieldsize), sign + def consider_setfield_gc(self, op): ofs_loc, size_loc, _, _ = self._unpack_fielddescr(op.getdescr()) assert isinstance(size_loc, ImmedLoc) @@ -1073,6 +1084,19 @@ consider_setfield_raw = consider_setfield_gc + def consider_setinteriorfield_gc(self, op): + t = self._unpack_interiorfielddescr(op.getdescr()) + ofs, itemsize, fieldsize, _ = t + args = op.getarglist() + base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args) + index_loc = self.rm.force_result_in_reg(op.getarg(1), op.getarg(1), + args) + # we're free to modify index now + value_loc = self.make_sure_var_in_reg(op.getarg(2), args) + self.possibly_free_vars(args) + self.PerformDiscard(op, [base_loc, ofs, itemsize, fieldsize, + index_loc, value_loc]) + def consider_strsetitem(self, op): args = op.getarglist() base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args) @@ -1134,6 +1158,22 @@ consider_getarrayitem_raw = consider_getarrayitem_gc consider_getarrayitem_gc_pure = consider_getarrayitem_gc + def consider_getinteriorfield_gc(self, op): + t = self._unpack_interiorfielddescr(op.getdescr()) + ofs, itemsize, fieldsize, sign = t + if sign: + sign_loc = imm1 + else: + sign_loc = imm0 + args = op.getarglist() + base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args) + index_loc = self.rm.force_result_in_reg(op.getarg(1), op.getarg(1), + args) + self.possibly_free_vars(args) + result_loc = self.force_allocate_reg(op.result) + self.Perform(op, [base_loc, ofs, itemsize, fieldsize, + index_loc, sign_loc], result_loc) + def consider_int_is_true(self, op, guard_op): # doesn't need arg to be in a register argloc = self.loc(op.getarg(0)) @@ -1239,7 +1279,6 @@ self.rm.possibly_free_var(srcaddr_box) def _gen_address_inside_string(self, baseloc, ofsloc, resloc, is_unicode): - cpu = self.assembler.cpu if is_unicode: ofs_items, _, _ = symbolic.get_array_token(rstr.UNICODE, self.translate_support_code) @@ -1298,7 +1337,7 @@ tmpreg = X86RegisterManager.all_regs[0] tmploc = self.rm.force_allocate_reg(box, selected_reg=tmpreg) xmmtmp = X86XMMRegisterManager.all_regs[0] - xmmtmploc = self.xrm.force_allocate_reg(box1, selected_reg=xmmtmp) + self.xrm.force_allocate_reg(box1, selected_reg=xmmtmp) # Part about non-floats # XXX we don't need a copy, we only just the original list src_locations1 = [self.loc(op.getarg(i)) for i in range(op.numargs()) @@ -1366,7 +1405,7 @@ return lambda self, op: fn(self, op, None) def is_comparison_or_ovf_op(opnum): - from pypy.jit.metainterp.resoperation import opclasses, AbstractResOp + from pypy.jit.metainterp.resoperation import opclasses cls = opclasses[opnum] # hack hack: in theory they are instance method, but they don't use # any instance field, we can use a fake object diff --git a/pypy/jit/backend/x86/test/test_del.py b/pypy/jit/backend/x86/test/test_del.py --- a/pypy/jit/backend/x86/test/test_del.py +++ b/pypy/jit/backend/x86/test/test_del.py @@ -1,5 +1,4 @@ -import py from pypy.jit.backend.x86.test.test_basic import Jit386Mixin from pypy.jit.metainterp.test.test_del import DelTests From noreply at buildbot.pypy.org Sun Jul 3 00:56:32 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 00:56:32 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: add test_dict for x86 backend Message-ID: <20110702225632.D408382940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45288:436d5fcdc19e Date: 2011-07-03 00:33 +0200 http://bitbucket.org/pypy/pypy/changeset/436d5fcdc19e/ Log: add test_dict for x86 backend diff --git a/pypy/jit/backend/x86/test/test_dict.py b/pypy/jit/backend/x86/test/test_dict.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/x86/test/test_dict.py @@ -0,0 +1,9 @@ + +from pypy.jit.backend.x86.test.test_basic import Jit386Mixin +from pypy.jit.metainterp.test.test_dict import DictTests + + +class TestDict(Jit386Mixin, DictTests): + # for the individual tests see + # ====> ../../../metainterp/test/test_dict.py + pass From noreply at buildbot.pypy.org Sun Jul 3 00:56:34 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 00:56:34 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: enough support to run basic tests, unskip the none one Message-ID: <20110702225634.244F282940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45289:5396eecdde05 Date: 2011-07-03 01:03 +0200 http://bitbucket.org/pypy/pypy/changeset/5396eecdde05/ Log: enough support to run basic tests, unskip the none one diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -147,6 +147,12 @@ self.arraydescr = arraydescr self.fielddescr = fielddescr + def is_pointer_field(self): + return self.fielddescr.is_pointer_field() + + def is_float_field(self): + return self.fielddescr.is_float_field() + # ____________________________________________________________ # ArrayDescrs diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -300,6 +300,25 @@ else: raise NotImplementedError("size = %d" % size) + def bh_getinteriorfield_gc_i(self, gcref, itemindex, descr): + arraydescr = descr.arraydescr + ofs, size, _ = self.unpack_arraydescr_size(arraydescr) + ofs += descr.fielddescr.offset + fieldsize = descr.fielddescr.get_field_size(self.translate_support_code) + ofs = itemindex * size + ofs + # --- start of GC unsafe code (no GC operation!) --- + items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs) + for STYPE, UTYPE, itemsize in unroll_basic_sizes: + if fieldsize == itemsize: + # XXX signedness + items = rffi.cast(rffi.CArrayPtr(STYPE), items) + val = items[0] + val = rffi.cast(lltype.Signed, val) + # --- end of GC unsafe code --- + return val + else: + raise NotImplementedError("size = %d" % fieldsize) + def bh_getarrayitem_gc_r(self, arraydescr, gcref, itemindex): ofs = self.unpack_arraydescr(arraydescr) # --- start of GC unsafe code (no GC operation!) --- @@ -357,6 +376,23 @@ bh_getarrayitem_raw_i = bh_getarrayitem_gc_i bh_getarrayitem_raw_f = bh_getarrayitem_gc_f + def bh_setinteriorfield_gc_i(self, gcref, itemindex, descr, value): + arraydescr = descr.arraydescr + ofs, size, _ = self.unpack_arraydescr_size(arraydescr) + ofs += descr.fielddescr.offset + fieldsize = descr.fielddescr.get_field_size(self.translate_support_code) + ofs = itemindex * size + ofs + # --- start of GC unsafe code (no GC operation!) --- + items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs) + for TYPE, _, itemsize in unroll_basic_sizes: + if fieldsize == itemsize: + items = rffi.cast(rffi.CArrayPtr(TYPE), items) + items[0] = rffi.cast(TYPE, value) + # --- end of GC unsafe code --- + return + else: + raise NotImplementedError("size = %d" % fieldsize) + def bh_strlen(self, string): s = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), string) return len(s.chars) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -1088,12 +1088,14 @@ t = self._unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, _ = t args = op.getarglist() + tmpvar = TempBox() base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args) - index_loc = self.rm.force_result_in_reg(op.getarg(1), op.getarg(1), + index_loc = self.rm.force_result_in_reg(tmpvar, op.getarg(1), args) # we're free to modify index now value_loc = self.make_sure_var_in_reg(op.getarg(2), args) self.possibly_free_vars(args) + self.rm.possibly_free_var(tmpvar) self.PerformDiscard(op, [base_loc, ofs, itemsize, fieldsize, index_loc, value_loc]) @@ -1166,10 +1168,12 @@ else: sign_loc = imm0 args = op.getarglist() + tmpvar = TempBox() base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args) - index_loc = self.rm.force_result_in_reg(op.getarg(1), op.getarg(1), + index_loc = self.rm.force_result_in_reg(tmpvar, op.getarg(1), args) - self.possibly_free_vars(args) + self.rm.possibly_free_vars_for_op(op) + self.rm.possibly_free_var(tmpvar) result_loc = self.force_allocate_reg(op.result) self.Perform(op, [base_loc, ofs, itemsize, fieldsize, index_loc, sign_loc], result_loc) diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -1,4 +1,3 @@ -import py from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rlib.jit import JitDriver from pypy.rlib import objectmodel @@ -6,7 +5,6 @@ class DictTests: def test_dict_set_none(self): - py.test.skip("annoying...") def fn(n): d = {} d[0] = None From noreply at buildbot.pypy.org Sun Jul 3 02:09:11 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 3 Jul 2011 02:09:11 +0200 (CEST) Subject: [pypy-commit] pypy default: propogate bounds from an int_is_zero(); guard_true(); onto int_is_true(); guard_false(); this pattern shows up in Python-level calls, checking on various profiling things. For calls this saves a resop + guard in the case where it isn't hoisted into the preamble. Message-ID: <20110703000911.9F3C382940@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45290:68019c81cf8d Date: 2011-07-02 17:16 -0700 http://bitbucket.org/pypy/pypy/changeset/68019c81cf8d/ Log: propogate bounds from an int_is_zero(); guard_true(); onto int_is_true(); guard_false(); this pattern shows up in Python-level calls, checking on various profiling things. For calls this saves a resop + guard in the case where it isn't hoisted into the preamble. diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -382,6 +382,18 @@ v1.intbound.make_gt(IntBound(0, 0)) self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -439,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] From noreply at buildbot.pypy.org Sun Jul 3 05:33:40 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sun, 3 Jul 2011 05:33:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Change signature to match how it is called. Fixes JVM exception when string-izing floats. Message-ID: <20110703033340.177DF82940@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45291:85913f63ba89 Date: 2011-06-27 19:22 -0700 http://bitbucket.org/pypy/pypy/changeset/85913f63ba89/ Log: Change signature to match how it is called. Fixes JVM exception when string-izing floats. diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,7 +964,7 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not From noreply at buildbot.pypy.org Sun Jul 3 05:33:41 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sun, 3 Jul 2011 05:33:41 +0200 (CEST) Subject: [pypy-commit] pypy default: Tell the JVM backend what to do with this operation. It's possible DoNothing is more correct in this case, but Ignore seems fine for now. Message-ID: <20110703033341.54E0A82940@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45292:c8344a91deef Date: 2011-06-27 20:20 -0700 http://bitbucket.org/pypy/pypy/changeset/c8344a91deef/ Log: Tell the JVM backend what to do with this operation. It's possible DoNothing is more correct in this case, but Ignore seems fine for now. diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, From noreply at buildbot.pypy.org Sun Jul 3 05:33:42 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sun, 3 Jul 2011 05:33:42 +0200 (CEST) Subject: [pypy-commit] pypy default: In later code these fields are expected to be mangled. Message-ID: <20110703033342.955CF82940@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45293:002c7b77a209 Date: 2011-06-27 20:26 -0700 http://bitbucket.org/pypy/pypy/changeset/002c7b77a209/ Log: In later code these fields are expected to be mangled. diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass From noreply at buildbot.pypy.org Sun Jul 3 05:33:43 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sun, 3 Jul 2011 05:33:43 +0200 (CEST) Subject: [pypy-commit] pypy default: Don't include stat_result.st_blksize on ootype. Message-ID: <20110703033343.D0B4082940@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45294:e9deaeb45961 Date: 2011-06-30 21:47 -0700 http://bitbucket.org/pypy/pypy/changeset/e9deaeb45961/ Log: Don't include stat_result.st_blksize on ootype. diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) From noreply at buildbot.pypy.org Sun Jul 3 05:33:45 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sun, 3 Jul 2011 05:33:45 +0200 (CEST) Subject: [pypy-commit] pypy default: This breaks translation, don't allow setting stack limit on ootype for now. Message-ID: <20110703033345.1853482940@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45295:a5691d418d1e Date: 2011-07-02 20:30 -0700 http://bitbucket.org/pypy/pypy/changeset/a5691d418d1e/ Log: This breaks translation, don't allow setting stack limit on ootype for now. diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). From noreply at buildbot.pypy.org Sun Jul 3 05:33:46 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sun, 3 Jul 2011 05:33:46 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge heads. Message-ID: <20110703033346.7EA0182940@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45296:afde3d9955e7 Date: 2011-07-02 20:30 -0700 http://bitbucket.org/pypy/pypy/changeset/afde3d9955e7/ Log: Merge heads. diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -203,3 +203,16 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + class A(object): + def m(self): + "aaa" + m.x = 3 + + bm = A().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -761,12 +761,15 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -703,22 +703,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -467,13 +469,13 @@ # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,6 +185,13 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLException diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -791,6 +791,7 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 from pypy.jit.metainterp.optimizeopt.util import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -373,6 +373,15 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -418,5 +427,6 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL + optimize_ops = _findall(OptIntBounds, 'optimize_') propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -121,6 +121,41 @@ print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + class BaseTestOptimizeBasic(BaseTestBasic): @@ -1875,7 +1910,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1893,7 +1927,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1911,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2204,23 +2236,6 @@ # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2329,7 +2344,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2350,7 +2364,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2370,7 +2383,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2396,7 +2408,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2421,7 +2433,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2445,7 +2456,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2466,7 +2476,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2487,7 +2496,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2509,7 +2517,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2551,7 +2558,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2577,7 +2583,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2601,9 +2606,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2895,7 +2897,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2941,7 +2942,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2980,7 +2980,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3007,7 +3006,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -4499,6 +4497,29 @@ """ self.optimize_loop(ops, expected) + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2742,8 +2742,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -5899,3 +5897,6 @@ jump(i0, i1) """ self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -32,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -900,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -58,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -46,7 +46,7 @@ guard_no_overflow(descr=) i18 = int_add(i7, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) """) def test_array_intimg(self): @@ -83,7 +83,7 @@ setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) i28 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -187,7 +187,7 @@ guard_no_overflow(descr=) i18 = force_token() --TICK-- - jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) """) def test_default_and_kw(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py --- a/pypy/module/pypyjit/test_pypy_c/test_intbound.py +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -97,7 +97,7 @@ guard_no_overflow(descr=...) i17 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) """) def test_intbound_sub_lt(self): @@ -149,7 +149,7 @@ guard_no_overflow(descr=...) i19 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) """) def test_intbound_addmul_ge(self): @@ -177,7 +177,7 @@ guard_no_overflow(descr=...) i21 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) """) def test_intbound_eq(self): @@ -209,7 +209,7 @@ guard_no_overflow(descr=...) i16 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) """) def test_intbound_mul(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -167,7 +167,7 @@ guard_false(i16, descr=) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) + setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, 146982464, descr=) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) @@ -179,7 +179,7 @@ i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -151,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -1107,8 +1107,11 @@ return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_CARDS_SET != 0: + # there might be young objects, let ll_arraycopy find them + return False + # + if source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: # there might be in source a pointer to a young object self.old_objects_pointing_to_young.append(dest_addr) dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,44 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_NO_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst) + assert res + assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_NO_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS == 0 # and we copied the flag + # + # in this case, we have cards, so GCFLAG_NO_YOUNG_PTRS is set (because + # cards takes precedence over it) + hdr_src.tid |= minimark.GCFLAG_NO_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_NO_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + res = self.gc.writebarrier_before_copy(addr_src, addr_dst) + assert not res # there might be young ptrs, let ll_arraycopy to find them + assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass From noreply at buildbot.pypy.org Sun Jul 3 05:33:48 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sun, 3 Jul 2011 05:33:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge heads again Message-ID: <20110703033348.8281C82940@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45297:a36aaf542bb2 Date: 2011-07-02 20:32 -0700 http://bitbucket.org/pypy/pypy/changeset/a36aaf542bb2/ Log: Merge heads again diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,14 +4399,8 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) - self.assertTrue(l.__add__.im_class is list) + self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__objclass__ is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -299,12 +299,13 @@ listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) @@ -351,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -379,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -129,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -266,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -355,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -248,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1060,18 +1060,6 @@ def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -205,6 +205,7 @@ raises(OSError, os.lseek, fd, 7, 0) def test_method_attrs(self): + import sys class A(object): def m(self): "aaa" diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -895,7 +895,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -907,7 +907,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -92,7 +92,7 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -847,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -119,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -633,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -382,6 +382,18 @@ v1.intbound.make_gt(IntBound(0, 0)) self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -439,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jdindex, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -914,8 +914,10 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jd_index, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation + loc = jitdriver_sd.warmstate.get_location_str(greenkey) + debug_print(loc) args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @@ -1231,7 +1233,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -1252,7 +1252,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1312,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1343,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1496,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1531,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1595,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1676,8 +1676,8 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) - self.check_loops(getarrayitem_gc=8, everywhere=True) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) @@ -1817,7 +1817,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2002,7 +2002,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2047,7 +2047,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2082,7 +2082,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2139,7 +2139,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2208,7 +2208,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2313,6 +2314,67 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + def test_retrace_ending_up_retrazing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -631,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -562,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -799,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -829,8 +828,6 @@ return struct.unpack(') setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i8, descr=) """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + w_dict = jit.promote(w_dict) + self = jit.promote(self) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + @jit.elidable + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,91 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,18 +1,20 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS -from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize +from pypy.rlib.debug import mark_dict_non_null + +from pypy.rlib import rerased def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -28,48 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -88,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -140,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -149,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -159,106 +140,87 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_length(self): - return len(self.r_dict_content) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def length(self, w_dict): + return 0 + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def clear(self, w_dict): + return - -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -300,319 +262,255 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = {} +class AbstractTypedStrategy(object): + _mixin_ = True - def impl_setitem(self, w_key, w_value): + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, key, w_value): - self.content[key] = w_value + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] return - elif _is_sane_hash(space, w_key_type): - raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) - def impl_length(self): - return len(self.content) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) - def impl_getitem_str(self, key): - return self.content.get(key, None) + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return ObjectIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + + def setitem_str(self, w_dict, key, w_value): + assert key is not None + self.unerase(w_dict.dstorage)[key] = w_value + + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().impl_fallback_getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) - def impl_delitem(self, w_key): + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) + return space.is_w(space.type(w_obj), space.w_int) - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) -class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): +class IntIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - + return None, None init_signature = Signature(['seq_or_map'], None, 'kwargs') diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,119 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -322,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) @@ -29,3 +38,31 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -233,6 +234,31 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2:2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a",1) in l + assert (2,2) in l + assert ("c",3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a",1) in l + assert ("b",2) in l + assert ("c",3) in l + def test_setdefault(self): d = {1:2, 3:4} dd = d.copy() @@ -527,6 +553,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +738,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +753,64 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -759,6 +851,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj @@ -790,6 +886,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +899,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +931,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1016,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1031,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1075,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1087,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1108,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,19 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + + def test_slot_name_conflict(self): class A(object): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: @@ -447,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -74,7 +74,7 @@ raise KeyError @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) @@ -253,7 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -272,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) @@ -833,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -845,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,8 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - # it's pure but it does not look like it - @purefunction + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -342,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -352,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -370,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -387,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -428,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -451,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -471,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -487,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -504,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -516,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -527,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -595,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -718,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -816,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -831,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -842,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,23 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + class Cls(self.AddressStack): + def append(self2, addr): + assert addr not in self2.tolist() + self.AddressStack.append(self2, addr) + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +637,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +655,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +698,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +789,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +882,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +922,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,11 +933,11 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded self.remember_young_pointer_from_array2(addr_array, index) else: @@ -943,20 +955,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -980,16 +995,18 @@ # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,9 +1019,7 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return @@ -1016,7 +1031,7 @@ addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True @@ -1026,9 +1041,6 @@ # xxx trying it out for the JIT: a 3-arguments version of the above def remember_young_pointer_from_array3(addr_array, index, newvalue): - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") objhdr = self.header(addr_array) # # a single check for the common case of neither GCFLAG_HAS_CARDS @@ -1044,8 +1056,8 @@ else: # case with cards. # - # If the newly written address does not actually point to the - # nursery, leave now. + # If the newly written address does not actually point to a + # young object, leave now. if not self.appears_to_be_young(newvalue): return # @@ -1056,46 +1068,53 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + \ - (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True assert self.card_page_indices > 0 self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1103,18 +1122,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if source_hdr.tid & GCFLAG_CARDS_SET != 0: - # there might be young objects, let ll_arraycopy find them - return False + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True # - if source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1122,6 +1159,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1138,20 +1191,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1184,7 +1245,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1192,7 +1253,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1208,11 +1269,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1248,19 +1309,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1299,7 +1371,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1346,11 +1430,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -539,27 +539,61 @@ hdr_src = self.gc.header(addr_src) hdr_dst = self.gc.header(addr_dst) # - assert hdr_src.tid & minimark.GCFLAG_NO_YOUNG_PTRS - assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS # - res = self.gc.writebarrier_before_copy(addr_src, addr_dst) + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) assert res - assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS # - hdr_src.tid &= ~minimark.GCFLAG_NO_YOUNG_PTRS # pretend we have young ptrs - res = self.gc.writebarrier_before_copy(addr_src, addr_dst) + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) assert res # we optimized it - assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS == 0 # and we copied the flag + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag # - # in this case, we have cards, so GCFLAG_NO_YOUNG_PTRS is set (because - # cards takes precedence over it) - hdr_src.tid |= minimark.GCFLAG_NO_YOUNG_PTRS - hdr_dst.tid |= minimark.GCFLAG_NO_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS hdr_src.tid |= minimark.GCFLAG_CARDS_SET - res = self.gc.writebarrier_before_copy(addr_src, addr_dst) + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) assert not res # there might be young ptrs, let ll_arraycopy to find them - assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS - + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -884,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,29 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): @@ -860,6 +883,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -121,6 +121,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -220,6 +223,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -168,7 +168,7 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' From noreply at buildbot.pypy.org Sun Jul 3 06:14:13 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 3 Jul 2011 06:14:13 +0200 (CEST) Subject: [pypy-commit] pypy default: Don't run these tests under -A Message-ID: <20110703041413.1B66782940@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45298:83f6ecc84a52 Date: 2011-07-02 21:21 -0700 http://bitbucket.org/pypy/pypy/changeset/83f6ecc84a52/ Log: Don't run these tests under -A diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -43,6 +43,8 @@ OPTIONS = {"objspace.std.withcelldict": True} def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") strategy = ModuleDictStrategy(cls.space) storage = strategy.get_empty_storage() cls.w_d = W_DictMultiObject(cls.space, strategy, storage) From noreply at buildbot.pypy.org Sun Jul 3 06:14:14 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 3 Jul 2011 06:14:14 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20110703041414.5FA3682940@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45299:37125e4baaff Date: 2011-07-02 21:21 -0700 http://bitbucket.org/pypy/pypy/changeset/37125e4baaff/ Log: merged upstream diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,7 +964,7 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not From noreply at buildbot.pypy.org Sun Jul 3 08:44:57 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sun, 3 Jul 2011 08:44:57 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: fixed test Message-ID: <20110703064457.8851682940@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45300:a2b71f3b9c8e Date: 2011-07-02 19:47 +0200 http://bitbucket.org/pypy/pypy/changeset/a2b71f3b9c8e/ Log: fixed test diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2572,6 +2572,7 @@ myjitdriver.set_param('threshold', 3) myjitdriver.set_param('trace_eagerness', 1) myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) pc = sa = i = 0 while pc < len(bytecode): myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) From noreply at buildbot.pypy.org Sun Jul 3 08:44:58 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sun, 3 Jul 2011 08:44:58 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: produce proper jump args in the preamble Message-ID: <20110703064458.CB72582940@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45301:c6e661dff09a Date: 2011-07-02 22:25 +0200 http://bitbucket.org/pypy/pypy/changeset/c6e661dff09a/ Log: produce proper jump args in the preamble diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -127,7 +127,9 @@ if op.getopnum() == rop.SETFIELD_GC: result = op.getarg(1) if result in potential_ops: - result = result.clonebox() + newresult = result.clonebox() + optimizer.make_equal_to(newresult, optimizer.getvalue(result)) + newresult = result # XXX this will not allow for chains of operations getop = ResOperation(rop.GETFIELD_GC, [op.getarg(0)], result, op.getdescr()) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1445,8 +1445,8 @@ y.v = g(y.v) - y.v/y.v + lc/l[0] - 1 return y.v res = self.meta_interp(f, [20], listops=True) - self.check_loops(getfield_gc=1, getarrayitem_gc=0) - self.check_loops(getfield_gc=2, getarrayitem_gc=0, everywhere=True) + self.check_loops(getfield_gc=0, getarrayitem_gc=0) + self.check_loops(getfield_gc=1, getarrayitem_gc=0, everywhere=True) def test_guard_isnull_nonnull(self): myjitdriver = JitDriver(greens = [], reds = ['x', 'res']) From noreply at buildbot.pypy.org Sun Jul 3 08:45:00 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sun, 3 Jul 2011 08:45:00 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: dissbale for now Message-ID: <20110703064500.1509982940@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45302:6ee1ab03fb23 Date: 2011-07-03 08:44 +0200 http://bitbucket.org/pypy/pypy/changeset/6ee1ab03fb23/ Log: dissbale for now diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -127,6 +127,8 @@ if op.getopnum() == rop.SETFIELD_GC: result = op.getarg(1) if result in potential_ops: + # XXX dissable for now + continue newresult = result.clonebox() optimizer.make_equal_to(newresult, optimizer.getvalue(result)) newresult = result From noreply at buildbot.pypy.org Sun Jul 3 08:45:01 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sun, 3 Jul 2011 08:45:01 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: hg merge default Message-ID: <20110703064501.6523582940@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45303:3091ae4843f5 Date: 2011-07-03 08:48 +0200 http://bitbucket.org/pypy/pypy/changeset/3091ae4843f5/ Log: hg merge default diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -382,6 +382,18 @@ v1.intbound.make_gt(IntBound(0, 0)) self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -439,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1710,8 +1710,8 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) - self.check_loops(getarrayitem_gc=8, everywhere=True) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) py.test.skip("for the following, we need setarrayitem(varindex)") def test_multiple_specialied_versions_bridge(self): diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py --- a/pypy/module/pyexpat/__init__.py +++ b/pypy/module/pyexpat/__init__.py @@ -2,6 +2,22 @@ from pypy.interpreter.mixedmodule import MixedModule +class ErrorsModule(MixedModule): + "Definition of pyexpat.errors module." + + appleveldefs = { + } + + interpleveldefs = { + } + + def setup_after_space_initialization(self): + from pypy.module.pyexpat import interp_pyexpat + for name in interp_pyexpat.xml_error_list: + self.space.setattr(self, self.space.wrap(name), + interp_pyexpat.ErrorString(self.space, + getattr(interp_pyexpat, name))) + class Module(MixedModule): "Python wrapper for Expat parser." @@ -21,6 +37,10 @@ 'version_info': 'interp_pyexpat.get_expat_version_info(space)', } + submodules = { + 'errors': ErrorsModule, + } + for name in ['XML_PARAM_ENTITY_PARSING_NEVER', 'XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE', 'XML_PARAM_ENTITY_PARSING_ALWAYS']: diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -31,6 +31,48 @@ XML_Content_Ptr = lltype.Ptr(lltype.ForwardReference()) XML_Parser = rffi.COpaquePtr(typedef='XML_Parser') +xml_error_list = [ + "XML_ERROR_NO_MEMORY", + "XML_ERROR_SYNTAX", + "XML_ERROR_NO_ELEMENTS", + "XML_ERROR_INVALID_TOKEN", + "XML_ERROR_UNCLOSED_TOKEN", + "XML_ERROR_PARTIAL_CHAR", + "XML_ERROR_TAG_MISMATCH", + "XML_ERROR_DUPLICATE_ATTRIBUTE", + "XML_ERROR_JUNK_AFTER_DOC_ELEMENT", + "XML_ERROR_PARAM_ENTITY_REF", + "XML_ERROR_UNDEFINED_ENTITY", + "XML_ERROR_RECURSIVE_ENTITY_REF", + "XML_ERROR_ASYNC_ENTITY", + "XML_ERROR_BAD_CHAR_REF", + "XML_ERROR_BINARY_ENTITY_REF", + "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", + "XML_ERROR_MISPLACED_XML_PI", + "XML_ERROR_UNKNOWN_ENCODING", + "XML_ERROR_INCORRECT_ENCODING", + "XML_ERROR_UNCLOSED_CDATA_SECTION", + "XML_ERROR_EXTERNAL_ENTITY_HANDLING", + "XML_ERROR_NOT_STANDALONE", + "XML_ERROR_UNEXPECTED_STATE", + "XML_ERROR_ENTITY_DECLARED_IN_PE", + "XML_ERROR_FEATURE_REQUIRES_XML_DTD", + "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING", + # Added in Expat 1.95.7. + "XML_ERROR_UNBOUND_PREFIX", + # Added in Expat 1.95.8. + "XML_ERROR_UNDECLARING_PREFIX", + "XML_ERROR_INCOMPLETE_PE", + "XML_ERROR_XML_DECL", + "XML_ERROR_TEXT_DECL", + "XML_ERROR_PUBLICID", + "XML_ERROR_SUSPENDED", + "XML_ERROR_NOT_SUSPENDED", + "XML_ERROR_ABORTED", + "XML_ERROR_FINISHED", + "XML_ERROR_SUSPEND_PE", + ] + class CConfigure: _compilation_info_ = eci XML_Content = rffi_platform.Struct('XML_Content', [ @@ -56,6 +98,9 @@ XML_FALSE = rffi_platform.ConstantInteger('XML_FALSE') XML_TRUE = rffi_platform.ConstantInteger('XML_TRUE') + for name in xml_error_list: + locals()[name] = rffi_platform.ConstantInteger(name) + for k, v in rffi_platform.configure(CConfigure).items(): globals()[k] = v @@ -298,7 +343,8 @@ XML_GetErrorCode = expat_external( 'XML_GetErrorCode', [XML_Parser], rffi.INT) XML_ErrorString = expat_external( - 'XML_ErrorString', [rffi.INT], rffi.CCHARP) + 'XML_ErrorString', [rffi.INT], + rffi.CCHARP) XML_GetCurrentLineNumber = expat_external( 'XML_GetCurrentLineNumber', [XML_Parser], rffi.INT) XML_GetErrorLineNumber = XML_GetCurrentLineNumber diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py --- a/pypy/module/pyexpat/test/test_parser.py +++ b/pypy/module/pyexpat/test/test_parser.py @@ -38,7 +38,7 @@ parser = pyexpat.ParserCreate() raises(pyexpat.ExpatError, "parser.Parse(xml, True)") - def test_encoding(self): + def test_encoding_argument(self): import pyexpat for encoding_arg in (None, 'utf-8', 'iso-8859-1'): for namespace_arg in (None, '{'): @@ -68,7 +68,7 @@ assert p.buffer_size == 150 raises(TypeError, setattr, p, 'buffer_size', sys.maxint + 1) - def test_encoding(self): + def test_encoding_xml(self): # use one of the few encodings built-in in expat xml = "caf\xe9" import pyexpat @@ -120,3 +120,14 @@ return True p.ExternalEntityRefHandler = handler p.Parse(xml) + + def test_errors(self): + import types + import pyexpat + assert isinstance(pyexpat.errors, types.ModuleType) + # check a few random errors + assert pyexpat.errors.XML_ERROR_SYNTAX == 'syntax error' + assert (pyexpat.errors.XML_ERROR_INCORRECT_ENCODING == + 'encoding specified in XML declaration is incorrect') + assert (pyexpat.errors.XML_ERROR_XML_DECL == + 'XML declaration not well-formed') diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -139,12 +139,24 @@ for k, cell in iterator(): cell.invalidate() + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): + if cell.w_value is not None: + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError + def switch_to_object_strategy(self, w_dict): d = self.unerase(w_dict.dstorage) strategy = self.space.fromcache(ObjectDictStrategy) d_new = strategy.unerase(strategy.get_empty_storage()) for key, cell in d.iteritems(): - d_new[self.space.wrap(key)] = cell.w_value + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new) diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -38,3 +38,33 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,7 +964,7 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not From noreply at buildbot.pypy.org Sun Jul 3 08:49:27 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 08:49:27 +0200 (CEST) Subject: [pypy-commit] buildbot default: Don't display "None" in the columns "own tests" and "applevel tests" Message-ID: <20110703064927.1A8AD82940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r521:3aa4da94bc4c Date: 2011-07-03 08:57 +0200 http://bitbucket.org/pypy/buildbot/changeset/3aa4da94bc4c/ Log: Don't display "None" in the columns "own tests" and "applevel tests" for lines that don't even have a revision number, like the pypy-c-*-latest-*. diff --git a/bot2/pypybuildbot/pypylist.py b/bot2/pypybuildbot/pypylist.py --- a/bot2/pypybuildbot/pypylist.py +++ b/bot2/pypybuildbot/pypylist.py @@ -213,15 +213,19 @@ self._add_result_for_builder(element, app_builder, 'app_', t.rev, rowClass) def _add_result_for_builder(self, element, builder_name, prefix, rev, rowClass): - branch = self._get_branch() - summary, category = self._get_summary_and_category(builder_name, branch, rev) - if branch == 'trunk': - branch = '%3Ctrunk%3E' # - if category: - href = cgi.escape('/summary?category=%s&branch=%s&recentrev=%s' % (category, branch, rev)) - str_summary = '%s' % (href, summary) + if rev == -1: + summary = None + str_summary = '' else: - str_summary = str(summary) + branch = self._get_branch() + summary, category = self._get_summary_and_category(builder_name, branch, rev) + if branch == 'trunk': + branch = '%3Ctrunk%3E' # + if category: + href = cgi.escape('/summary?category=%s&branch=%s&recentrev=%s' % (category, branch, rev)) + str_summary = '%s' % (href, summary) + else: + str_summary = str(summary) element[prefix + 'summary'] = str_summary element[prefix + 'summary_class'] = self._get_summary_class(summary, rowClass) From noreply at buildbot.pypy.org Sun Jul 3 08:53:31 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 08:53:31 +0200 (CEST) Subject: [pypy-commit] buildbot default: Display the 'latest' symlinks in italic. Message-ID: <20110703065331.01F9982940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r522:0298afc92f57 Date: 2011-07-03 09:01 +0200 http://bitbucket.org/pypy/buildbot/changeset/0298afc92f57/ Log: Display the 'latest' symlinks in italic. diff --git a/bot2/pypybuildbot/pypylist.py b/bot2/pypybuildbot/pypylist.py --- a/bot2/pypybuildbot/pypylist.py +++ b/bot2/pypybuildbot/pypylist.py @@ -94,6 +94,9 @@ app_builder = '%s-%s-%s-%s' % (self.exe, self.backend, description, platform) return own_builder, app_builder + def display_in_italic(self): + return self.vcs == 'latest' + class PyPyList(File): @@ -198,7 +201,7 @@ rowClasses = itertools.cycle(['odd', 'even']) for element, rowClass in zip(elements, rowClasses): element["class"] = rowClass - result = self._add_test_results(element, rowClass) + self._add_test_results(element, rowClass) tableContent.append(self.linePattern % element) return tableContent @@ -208,6 +211,8 @@ date = datetime.date.fromtimestamp(f.mtime()) element['date'] = date.isoformat() t = PyPyTarball(filename) + if t.display_in_italic(): + element['text'] = '%s' % (element['text'],) own_builder, app_builder = t.get_builder_names() self._add_result_for_builder(element, own_builder, 'own_', t.rev, rowClass) self._add_result_for_builder(element, app_builder, 'app_', t.rev, rowClass) From noreply at buildbot.pypy.org Sun Jul 3 09:40:38 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 09:40:38 +0200 (CEST) Subject: [pypy-commit] pypy default: (rguillebert, arigo) Message-ID: <20110703074038.6BC2282940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45304:bac656e1a363 Date: 2011-07-02 19:18 +0200 http://bitbucket.org/pypy/pypy/changeset/bac656e1a363/ Log: (rguillebert, arigo) Add the options "pypy --jit=off" and "pypy --jit=default", turning off the JIT or setting the default values. (The latter is only useful if you use pypyjit.set_param("default"), actually.) diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -176,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,21 +9,42 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + def test_interface_residual_call(): space = gettestobjspace(usemodules=['pypyjit']) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -294,6 +294,7 @@ 'enable_opts': None, # patched later by optimizeopt/__init__.py } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -348,6 +349,7 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) @@ -359,11 +361,29 @@ return raise ValueError("no such parameter") + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + for name1, _ in unroll_parameters: + if name1 == name: + self._set_param(name1, DEFAULT) + return + raise ValueError("no such parameter") + def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -586,15 +606,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -603,7 +625,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), From noreply at buildbot.pypy.org Sun Jul 3 09:40:39 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 09:40:39 +0200 (CEST) Subject: [pypy-commit] pypy default: (rguillebert, arigo) Add "--jit off" to the help. Message-ID: <20110703074039.AB27382940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45305:1711d58f10f4 Date: 2011-07-02 19:46 +0200 http://bitbucket.org/pypy/pypy/changeset/1711d58f10f4/ Log: (rguillebert, arigo) Add "--jit off" to the help. diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version From noreply at buildbot.pypy.org Sun Jul 3 09:40:40 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 09:40:40 +0200 (CEST) Subject: [pypy-commit] pypy default: For '--jit enable_opts', use a default value of 'all' instead of Message-ID: <20110703074040.F15DF82940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45306:f0dc295dc82d Date: 2011-07-03 08:14 +0200 http://bitbucket.org/pypy/pypy/changeset/f0dc295dc82d/ Log: For '--jit enable_opts', use a default value of 'all' instead of the complete string from optimizeopt. diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,14 +21,17 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] + if enable_opts == 'all': + enable_opts = ALL_OPTS_LIST + else: + enable_opts = enable_opts.split(':') unroll = 'unroll' in enable_opts for name, opt in unroll_all_opts: if name in enable_opts: diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4123,7 +4123,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5373,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/vstring.py rename from pypy/jit/metainterp/optimizeopt/string.py rename to pypy/jit/metainterp/optimizeopt/vstring.py diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -291,7 +291,7 @@ 'inlining': 0, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) DEFAULT = object() @@ -355,20 +355,12 @@ @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) @specialize.arg(0, 1) def set_param_to_default(self, name): """Reset one of the tunable JIT parameters to its default value.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, DEFAULT) - return - raise ValueError("no such parameter") + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string From noreply at buildbot.pypy.org Sun Jul 3 09:40:42 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 09:40:42 +0200 (CEST) Subject: [pypy-commit] pypy default: Add a test for --jit enable_opts=all. Message-ID: <20110703074042.4194682940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45307:8e1a5908e9bc Date: 2011-07-03 08:39 +0200 http://bitbucket.org/pypy/pypy/changeset/8e1a5908e9bc/ Log: Add a test for --jit enable_opts=all. diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -32,6 +32,10 @@ chain, _ = build_opt_chain(metainterp_sd, "") check(chain, ["OptInlineShortPreamble", "OptSimplify"]) # + chain, _ = build_opt_chain(metainterp_sd, "all") + check(chain, ["OptInlineShortPreamble", "OptIntBounds", "OptRewrite", + "OptVirtualize", "OptString", "OptHeap", "OptFfiCall"]) + # chain, _ = build_opt_chain(metainterp_sd, "heap:intbounds") check(chain, ["OptInlineShortPreamble", "OptIntBounds", "OptHeap", "OptSimplify"]) # From noreply at buildbot.pypy.org Sun Jul 3 09:40:43 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 09:40:43 +0200 (CEST) Subject: [pypy-commit] pypy default: Bah. Fix Message-ID: <20110703074043.8272582940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45308:7bf584b32555 Date: 2011-07-03 09:05 +0200 http://bitbucket.org/pypy/pypy/changeset/7bf584b32555/ Log: Bah. Fix diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -28,11 +28,7 @@ inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - if enable_opts == 'all': - enable_opts = ALL_OPTS_LIST - else: - enable_opts = enable_opts.split(':') - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -32,10 +32,6 @@ chain, _ = build_opt_chain(metainterp_sd, "") check(chain, ["OptInlineShortPreamble", "OptSimplify"]) # - chain, _ = build_opt_chain(metainterp_sd, "all") - check(chain, ["OptInlineShortPreamble", "OptIntBounds", "OptRewrite", - "OptVirtualize", "OptString", "OptHeap", "OptFfiCall"]) - # chain, _ = build_opt_chain(metainterp_sd, "heap:intbounds") check(chain, ["OptInlineShortPreamble", "OptIntBounds", "OptHeap", "OptSimplify"]) # diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -237,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: From noreply at buildbot.pypy.org Sun Jul 3 09:40:44 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 09:40:44 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix the tests. Message-ID: <20110703074044.C07B082940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45309:f09af652dc8e Date: 2011-07-03 09:47 +0200 http://bitbucket.org/pypy/pypy/changeset/f09af652dc8e/ Log: Fix the tests. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4400,7 +4400,10 @@ self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) + if hasattr(l.__add__, '__objclass__'): # CPython + self.assertTrue(l.__add__.__objclass__ is list) + else: # PyPy + self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -210,10 +210,20 @@ def m(self): "aaa" m.x = 3 + class B(A): + pass - bm = A().m + bm = B().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self + assert bm.im_class is B assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class From noreply at buildbot.pypy.org Sun Jul 3 09:40:46 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 09:40:46 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110703074046.2059B82940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45310:e90e238c3ac2 Date: 2011-07-03 09:48 +0200 http://bitbucket.org/pypy/pypy/changeset/e90e238c3ac2/ Log: merge heads diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4140,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5373,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/vstring.py rename from pypy/jit/metainterp/optimizeopt/string.py rename to pypy/jit/metainterp/optimizeopt/vstring.py diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -237,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -176,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,21 +9,42 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + def test_interface_residual_call(): space = gettestobjspace(usemodules=['pypyjit']) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -295,9 +295,10 @@ 'inlining': 0, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -352,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -590,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -607,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version From noreply at buildbot.pypy.org Sun Jul 3 09:44:15 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 3 Jul 2011 09:44:15 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix an issue with setting __dict__ on user instances multiple times. Message-ID: <20110703074415.913E482940@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45311:07de70a20b0f Date: 2011-07-03 00:51 -0700 http://bitbucket.org/pypy/pypy/changeset/07de70a20b0f/ Log: Fix an issue with setting __dict__ on user instances multiple times. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -163,10 +163,7 @@ elif self.space.is_w(self.space.type(w_key), self.space.w_int): self.switch_to_int_strategy(w_dict) else: - strategy = self.space.fromcache(ObjectDictStrategy) - storage = strategy.get_empty_storage() - w_dict.strategy = strategy - w_dict.dstorage = storage + self.switch_to_object_strategy(w_dict) def switch_to_string_strategy(self, w_dict): strategy = self.space.fromcache(StringDictStrategy) @@ -180,6 +177,12 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def getitem(self, w_dict, w_key): #return w_value or None # in case the key is unhashable, try to hash it diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -622,6 +622,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): From noreply at buildbot.pypy.org Sun Jul 3 09:44:16 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 3 Jul 2011 09:44:16 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20110703074416.E07A482940@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45312:34463d139c3b Date: 2011-07-03 00:51 -0700 http://bitbucket.org/pypy/pypy/changeset/34463d139c3b/ Log: merged upstream diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4400,7 +4400,10 @@ self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) + if hasattr(l.__add__, '__objclass__'): # CPython + self.assertTrue(l.__add__.__objclass__ is list) + else: # PyPy + self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -210,10 +210,20 @@ def m(self): "aaa" m.x = 3 + class B(A): + pass - bm = A().m + bm = B().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self + assert bm.im_class is B assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4140,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5373,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/vstring.py rename from pypy/jit/metainterp/optimizeopt/string.py rename to pypy/jit/metainterp/optimizeopt/vstring.py diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -237,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -176,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,21 +9,42 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + def test_interface_residual_call(): space = gettestobjspace(usemodules=['pypyjit']) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -295,9 +295,10 @@ 'inlining': 0, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -352,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -590,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -607,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version From noreply at buildbot.pypy.org Sun Jul 3 09:59:59 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 09:59:59 +0200 (CEST) Subject: [pypy-commit] pypy jit-option-refactor: Make a branch to refactor the --jit option processing. Message-ID: <20110703075959.5BE7582940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-option-refactor Changeset: r45313:dabb5d3306f2 Date: 2011-07-03 10:07 +0200 http://bitbucket.org/pypy/pypy/changeset/dabb5d3306f2/ Log: Make a branch to refactor the --jit option processing. diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -288,7 +288,7 @@ 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, 'enable_opts': 'all', From noreply at buildbot.pypy.org Sun Jul 3 11:35:54 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 11:35:54 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge jit-option-refactor Message-ID: <20110703093554.037F982940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45314:b06b6fe4b89f Date: 2011-07-03 11:43 +0200 http://bitbucket.org/pypy/pypy/changeset/b06b6fe4b89f/ Log: hg merge jit-option-refactor changing the default to reflect the real default diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -292,7 +292,7 @@ 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, 'enable_opts': 'all', From noreply at buildbot.pypy.org Sun Jul 3 11:35:55 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 11:35:55 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110703093555.44D4382941@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45315:afeebea4b340 Date: 2011-07-03 11:43 +0200 http://bitbucket.org/pypy/pypy/changeset/afeebea4b340/ Log: merge heads diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -163,10 +163,7 @@ elif self.space.is_w(self.space.type(w_key), self.space.w_int): self.switch_to_int_strategy(w_dict) else: - strategy = self.space.fromcache(ObjectDictStrategy) - storage = strategy.get_empty_storage() - w_dict.strategy = strategy - w_dict.dstorage = storage + self.switch_to_object_strategy(w_dict) def switch_to_string_strategy(self, w_dict): strategy = self.space.fromcache(StringDictStrategy) @@ -180,6 +177,12 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def getitem(self, w_dict, w_key): #return w_value or None # in case the key is unhashable, try to hash it diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -622,6 +622,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): From noreply at buildbot.pypy.org Sun Jul 3 11:47:29 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 3 Jul 2011 11:47:29 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and fix. Message-ID: <20110703094729.9151382940@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45316:f1a93c5db828 Date: 2011-07-03 11:55 +0200 http://bitbucket.org/pypy/pypy/changeset/f1a93c5db828/ Log: Test and fix. diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -670,6 +670,8 @@ def popitem(self, w_dict): curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError key = curr.selector[0] w_value = self.getitem_str(w_dict, key) w_key = self.space.wrap(key) diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -479,6 +479,7 @@ it2 = a.__dict__.popitem() assert it2 == ("x", 5) assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) From notifications-noreply at bitbucket.org Sun Jul 3 14:16:34 2011 From: notifications-noreply at bitbucket.org (Bitbucket) Date: Sun, 03 Jul 2011 12:16:34 -0000 Subject: [pypy-commit] Notification: pypy Message-ID: <20110703121634.20477.78993@bitbucket03.managed.contegix.com> You have received a notification from jerith. Hi, I forked pypy. My fork is at https://bitbucket.org/jerith/pypy. -- Change your notification settings at https://bitbucket.org/account/notifications/ From noreply at buildbot.pypy.org Sun Jul 3 18:22:56 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 3 Jul 2011 18:22:56 +0200 (CEST) Subject: [pypy-commit] pypy default: Whitespace changes, plus a switch to from using try/except/else to raises. Message-ID: <20110703162256.ED23F82940@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45320:b2326a53cb65 Date: 2011-07-03 09:30 -0700 http://bitbucket.org/pypy/pypy/changeset/b2326a53cb65/ Log: Whitespace changes, plus a switch to from using try/except/else to raises. diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -138,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -177,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -196,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -236,16 +236,16 @@ def test_popitem3(self): #object - d = {"a": 1, 2:2, "c":3} + d = {"a": 1, 2: 2, "c": 3} l = [] while True: try: l.append(d.popitem()) except KeyError: break; - assert ("a",1) in l - assert (2,2) in l - assert ("c",3) in l + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l #string d = {"a": 1, "b":2, "c":3} @@ -255,12 +255,12 @@ l.append(d.popitem()) except KeyError: break; - assert ("a",1) in l - assert ("b",2) in l - assert ("c",3) in l + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -293,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -323,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -342,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -392,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} From noreply at buildbot.pypy.org Sun Jul 3 18:22:58 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 3 Jul 2011 18:22:58 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20110703162258.54D6082940@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45321:b1e342bb119b Date: 2011-07-03 09:30 -0700 http://bitbucket.org/pypy/pypy/changeset/b1e342bb119b/ Log: merged upstream diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -186,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -207,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -240,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -1484,7 +1484,7 @@ raise OperationError( moduledict.w_NotSupportedError, space.wrap("Variable_TypeByValue(): unhandled data type %s" % - (space.type(w_value).getname(space, '?'),))) + (space.type(w_value).getname(space),))) def newByInputTypeHandler(space, cursor, w_inputTypeHandler, w_value, numElements): w_var = space.call(w_inputTypeHandler, diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -737,7 +737,7 @@ elif space.is_true(space.isinstance(w_encoding, space.w_str)): encoding = space.str_w(w_encoding) else: - type_name = space.type(w_encoding).getname(space, '?') + type_name = space.type(w_encoding).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 1 must be string or None,' @@ -757,7 +757,7 @@ space.wrap('namespace_separator must be at most one character,' ' omitted, or None')) else: - type_name = space.type(w_namespace_separator).getname(space, '?') + type_name = space.type(w_namespace_separator).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 2 must be string or None,' diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -820,7 +820,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -83,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: From noreply at buildbot.pypy.org Sun Jul 3 19:06:45 2011 From: noreply at buildbot.pypy.org (amauryfa) Date: Sun, 3 Jul 2011 19:06:45 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix CPython issue12412 (!) Message-ID: <20110703170645.30B8D82940@wyvern.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r45322:dded6e510044 Date: 2011-07-03 19:12 +0200 http://bitbucket.org/pypy/pypy/changeset/dded6e510044/ Log: Fix CPython issue12412 (!) Make pwd.struct_passwd as StructSequence, it has a better repr(). diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") From noreply at buildbot.pypy.org Sun Jul 3 19:13:12 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 19:13:12 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: remove unnecessary import Message-ID: <20110703171312.D953A82940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45323:5d2d8af879c4 Date: 2011-07-03 19:18 +0200 http://bitbucket.org/pypy/pypy/changeset/5d2d8af879c4/ Log: remove unnecessary import diff --git a/pypy/jit/codewriter/jitcode.py b/pypy/jit/codewriter/jitcode.py --- a/pypy/jit/codewriter/jitcode.py +++ b/pypy/jit/codewriter/jitcode.py @@ -1,7 +1,6 @@ from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.codewriter import heaptracker from pypy.rlib.objectmodel import we_are_translated -from pypy.rpython.lltypesystem import llmemory class JitCode(AbstractDescr): From noreply at buildbot.pypy.org Sun Jul 3 19:13:14 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 19:13:14 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: disable this test for now Message-ID: <20110703171314.23B3182940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45324:e66ff3b3fb4a Date: 2011-07-03 19:19 +0200 http://bitbucket.org/pypy/pypy/changeset/e66ff3b3fb4a/ Log: disable this test for now diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -1,3 +1,4 @@ +import py from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rlib.jit import JitDriver from pypy.rlib import objectmodel @@ -5,6 +6,7 @@ class DictTests: def test_dict_set_none(self): + py.test.skip("annoying") def fn(n): d = {} d[0] = None From noreply at buildbot.pypy.org Sun Jul 3 19:13:15 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 19:13:15 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: remove unnecessary verbosity of pyjitpl (set debug flag if necessary or use Message-ID: <20110703171315.695BE82940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45325:38bb54970de2 Date: 2011-07-03 19:19 +0200 http://bitbucket.org/pypy/pypy/changeset/38bb54970de2/ Log: remove unnecessary verbosity of pyjitpl (set debug flag if necessary or use the logger) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -35,6 +35,7 @@ class MIFrame(object): + debug = False def __init__(self, metainterp): self.metainterp = metainterp @@ -2503,17 +2504,21 @@ self.pc = position # if not we_are_translated(): - print '\tpyjitpl: %s(%s)' % (name, ', '.join(map(repr, args))), + if self.debug: + print '\tpyjitpl: %s(%s)' % (name, ', '.join(map(repr, args))), try: resultbox = unboundmethod(self, *args) except Exception, e: - print '-> %s!' % e.__class__.__name__ + if self.debug: + print '-> %s!' % e.__class__.__name__ raise if num_return_args == 0: - print + if self.debug: + print assert resultbox is None else: - print '-> %r' % (resultbox,) + if self.debug: + print '-> %r' % (resultbox,) assert argcodes[next_argcode] == '>' result_argcode = argcodes[next_argcode + 1] assert resultbox.type == {'i': history.INT, diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -193,7 +193,7 @@ self.make_enter_functions() self.rewrite_jit_merge_points(policy) - verbose = not self.cpu.translate_support_code + verbose = False # not self.cpu.translate_support_code self.codewriter.make_jitcodes(verbose=verbose) self.rewrite_can_enter_jits() self.rewrite_set_param() From noreply at buildbot.pypy.org Sun Jul 3 19:13:16 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 19:13:16 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: some unneeded imports Message-ID: <20110703171316.AF08982940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45326:9d1805e7587b Date: 2011-07-03 19:19 +0200 http://bitbucket.org/pypy/pypy/changeset/9d1805e7587b/ Log: some unneeded imports diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -15,12 +15,11 @@ load_library_kwargs = {} import os -from pypy import conftest from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.extfunc import ExtRegistryEntry from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic from pypy.tool.uid import fixid -from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longfloat, intmask +from pypy.rlib.rarithmetic import r_singlefloat, r_longfloat, intmask from pypy.annotation import model as annmodel from pypy.rpython.llinterp import LLInterpreter, LLException from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE From noreply at buildbot.pypy.org Sun Jul 3 19:13:17 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 19:13:17 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: Add the posibility to specify which categories you're interested in. Use Message-ID: <20110703171317.ED99782940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45327:143b5e129bca Date: 2011-07-03 19:20 +0200 http://bitbucket.org/pypy/pypy/changeset/143b5e129bca/ Log: Add the posibility to specify which categories you're interested in. Use PYPYDEFAULTLOG as an env var diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -1,6 +1,26 @@ -import sys, time +import sys, time, os from pypy.rpython.extregistry import ExtRegistryEntry +class DebugState(object): + def __init__(self): + self.prefixes = os.environ.get('PYPYDEFAULTLOG', 'all').split(':') + if self.prefixes == ['']: + self.prefixes = [] + self.categories = [] + + def should_print(self, category=None): + if category is None: + category = self.categories[-1] + if self.prefixes != ['all']: + for prefix in self.prefixes: + if category.startswith(prefix): + break + else: + return False + return True + +debug_state = DebugState() # a global state object + def ll_assert(x, msg): """After translation to C, this becomes an RPyAssert.""" assert x, msg @@ -55,6 +75,8 @@ # or compatible def debug_print(*args): + if not debug_state.should_print(): + return for arg in args: print >> sys.stderr, arg, print >> sys.stderr @@ -85,18 +107,25 @@ _stop_colors = "" def debug_start(category): + debug_state.categories.append(category) + if _log is not None: + _log.debug_start(category) + if not debug_state.should_print(category): + return c = int(time.clock() * 100) print >> sys.stderr, '%s[%x] {%s%s' % (_start_colors_1, c, category, _stop_colors) + +def debug_stop(category): if _log is not None: - _log.debug_start(category) - -def debug_stop(category): + _log.debug_stop(category) + last = debug_state.categories.pop() + assert category == last + if not debug_state.should_print(category): + return c = int(time.clock() * 100) print >> sys.stderr, '%s[%x] %s}%s' % (_start_colors_2, c, category, _stop_colors) - if _log is not None: - _log.debug_stop(category) class Entry(ExtRegistryEntry): _about_ = debug_start, debug_stop From noreply at buildbot.pypy.org Sun Jul 3 20:26:02 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 20:26:02 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: one more missing case for parentstructure Message-ID: <20110703182602.1FCE482940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45328:e575516493ff Date: 2011-07-03 20:33 +0200 http://bitbucket.org/pypy/pypy/changeset/e575516493ff/ Log: one more missing case for parentstructure diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -525,7 +525,10 @@ return 0, sys.maxint def getitem(self, index, uninitialized_ok=False): - return self._storage.contents._getitem(index, boundscheck=False) + res = self._storage.contents._getitem(index, boundscheck=False) + if isinstance(self._TYPE.OF, lltype.ContainerType): + res._obj._setparentstructure(self, index) + return res def setitem(self, index, value): self._storage.contents._setitem(index, value, boundscheck=False) diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -1327,6 +1327,11 @@ round = ctypes2lltype(llmemory.GCREF, lltype2ctypes(opaque.hide())) assert Opaque.show(round) is opaque + def test_array_of_structs(self): + A = lltype.GcArray(lltype.Struct('x', ('v', lltype.Signed))) + a = lltype.malloc(A, 5) + a2 = ctypes2lltype(lltype.Ptr(A), lltype2ctypes(a)) + assert a2._obj.getitem(0)._obj._parentstructure() is a2._obj class TestPlatform(object): def test_lib_on_libpaths(self): From noreply at buildbot.pypy.org Sun Jul 3 21:05:41 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 3 Jul 2011 21:05:41 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: an obscure untested change about keeping alive ctypes structures by subarrays Message-ID: <20110703190541.2990582940@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45329:607f00164b89 Date: 2011-07-03 21:13 +0200 http://bitbucket.org/pypy/pypy/changeset/607f00164b89/ Log: an obscure untested change about keeping alive ctypes structures by subarrays diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -1710,7 +1710,8 @@ # Keep the parent array alive, we share the same allocation. # Don't do it if we are inside a GC object, though -- it's someone # else's job to keep the GC object alive - if typeOf(top_container(parent))._gckind == 'raw': + if (typeOf(top_container(parent))._gckind == 'raw' or + hasattr(top_container(parent)._storage, 'contents')): self._keepparent = parent def __str__(self): From noreply at buildbot.pypy.org Mon Jul 4 09:32:44 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 4 Jul 2011 09:32:44 +0200 (CEST) Subject: [pypy-commit] pypy default: Support different precision float formatting. Accompanying test isn't very good, but there was none before. Message-ID: <20110704073244.A946C82941@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45330:53da334735e9 Date: 2011-07-04 00:39 -0700 http://bitbucket.org/pypy/pypy/changeset/53da334735e9/ Log: Support different precision float formatting. Accompanying test isn't very good, but there was none before. diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -969,7 +969,10 @@ // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" From noreply at buildbot.pypy.org Mon Jul 4 09:32:46 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 4 Jul 2011 09:32:46 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge heads Message-ID: <20110704073246.2BB2C82941@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45331:710e095018ab Date: 2011-07-04 00:40 -0700 http://bitbucket.org/pypy/pypy/changeset/710e095018ab/ Log: Merge heads diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4400,7 +4400,10 @@ self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) + if hasattr(l.__add__, '__objclass__'): # CPython + self.assertTrue(l.__add__.__objclass__ is list) + else: # PyPy + self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -210,10 +210,20 @@ def m(self): "aaa" m.x = 3 + class B(A): + pass - bm = A().m + bm = B().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self + assert bm.im_class is B assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4140,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5373,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/vstring.py rename from pypy/jit/metainterp/optimizeopt/string.py rename to pypy/jit/metainterp/optimizeopt/vstring.py diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -237,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -186,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -207,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -240,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -1484,7 +1484,7 @@ raise OperationError( moduledict.w_NotSupportedError, space.wrap("Variable_TypeByValue(): unhandled data type %s" % - (space.type(w_value).getname(space, '?'),))) + (space.type(w_value).getname(space),))) def newByInputTypeHandler(space, cursor, w_inputTypeHandler, w_value, numElements): w_var = space.call(w_inputTypeHandler, diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -737,7 +737,7 @@ elif space.is_true(space.isinstance(w_encoding, space.w_str)): encoding = space.str_w(w_encoding) else: - type_name = space.type(w_encoding).getname(space, '?') + type_name = space.type(w_encoding).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 1 must be string or None,' @@ -757,7 +757,7 @@ space.wrap('namespace_separator must be at most one character,' ' omitted, or None')) else: - type_name = space.type(w_namespace_separator).getname(space, '?') + type_name = space.type(w_namespace_separator).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 2 must be string or None,' diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -176,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,21 +9,42 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + def test_interface_residual_call(): space = gettestobjspace(usemodules=['pypyjit']) diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -163,10 +163,7 @@ elif self.space.is_w(self.space.type(w_key), self.space.w_int): self.switch_to_int_strategy(w_dict) else: - strategy = self.space.fromcache(ObjectDictStrategy) - storage = strategy.get_empty_storage() - w_dict.strategy = strategy - w_dict.dstorage = storage + self.switch_to_object_strategy(w_dict) def switch_to_string_strategy(self, w_dict): strategy = self.space.fromcache(StringDictStrategy) @@ -180,6 +177,12 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def getitem(self, w_dict, w_key): #return w_value or None # in case the key is unhashable, try to hash it @@ -817,7 +820,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -670,6 +670,8 @@ def popitem(self, w_dict): curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError key = curr.selector[0] w_value = self.getitem_str(w_dict, key) w_key = self.space.wrap(key) diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -43,6 +43,8 @@ OPTIONS = {"objspace.std.withcelldict": True} def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") strategy = ModuleDictStrategy(cls.space) storage = strategy.get_empty_storage() cls.w_d = W_DictMultiObject(cls.space, strategy, storage) diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -138,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -177,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -196,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -236,16 +236,16 @@ def test_popitem3(self): #object - d = {"a": 1, 2:2, "c":3} + d = {"a": 1, 2: 2, "c": 3} l = [] while True: try: l.append(d.popitem()) except KeyError: break; - assert ("a",1) in l - assert (2,2) in l - assert ("c",3) in l + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l #string d = {"a": 1, "b":2, "c":3} @@ -255,12 +255,12 @@ l.append(d.popitem()) except KeyError: break; - assert ("a",1) in l - assert ("b",2) in l - assert ("c",3) in l + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -293,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -323,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -342,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -392,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -479,6 +479,7 @@ it2 = a.__dict__.popitem() assert it2 == ("x", 5) assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) @@ -622,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -292,12 +292,13 @@ 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -352,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -590,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -607,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -83,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version From noreply at buildbot.pypy.org Mon Jul 4 11:31:57 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 11:31:57 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: have this debug print somewhere inside jit-backend cat Message-ID: <20110704093157.3204982941@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45332:c23b30f90eca Date: 2011-07-04 11:37 +0200 http://bitbucket.org/pypy/pypy/changeset/c23b30f90eca/ Log: have this debug print somewhere inside jit-backend cat diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -415,10 +415,12 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) + debug_start("jit-backend") debug_print("Loop #%d (%s) has address %x to %x" % ( looptoken.number, loopname, rawstart + self.looppos, rawstart + directbootstrappos)) + debug_stop("jit-backend") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) From noreply at buildbot.pypy.org Mon Jul 4 11:31:58 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 11:31:58 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: more tests Message-ID: <20110704093158.6C27582942@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45333:a884008e2d95 Date: 2011-07-04 11:39 +0200 http://bitbucket.org/pypy/pypy/changeset/a884008e2d95/ Log: more tests diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -883,15 +883,21 @@ self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), BoxFloat(1.5)], 'void', descr=kdescr) + #f = self.cpu.bh_getinteriorfield_gc_f(a_box.getref_base(), 3, kdescr) + #assert f == 1.5 + #self.cpu.bh_setinteriorfield_gc_f(a_box.getref_base(), 3, kdescr, 2.5) r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)], 'float', descr=kdescr) assert r.getfloat() == 1.5 self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), BoxInt(15)], 'void', descr=vdescr) + i = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 3, kdescr) + assert i == 15 + self.cpu.bh_setinteriorfield_gc_i(a_box.getref_base(), 3, kdescr, 25) r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)], 'int', descr=vdescr) - assert r.getint() == 15 + assert r.getint() == 25 self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), s_box], 'void', descr=pdescr) From noreply at buildbot.pypy.org Mon Jul 4 12:51:26 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 4 Jul 2011 12:51:26 +0200 (CEST) Subject: [pypy-commit] pypy default: generate all the dispatching loops that are around in the optimizers. Message-ID: <20110704105126.2BFD982941@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45334:e26fa26172cc Date: 2011-07-04 12:54 +0200 http://bitbucket.org/pypy/pypy/changeset/e26fa26172cc/ Log: generate all the dispatching loops that are around in the optimizers. This allows it to strategically place an "assert isinstance(op, cls)" just before calling the specific optimization method. This means the annotation of "op" in all these methods is precisely the right class, which leads to much faster access to all the arguments of operations. diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -203,13 +203,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -220,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -431,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt @@ -34,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -57,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -440,5 +433,6 @@ propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile @@ -434,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -569,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -477,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -20,9 +20,25 @@ if op_prefix and not name.startswith(op_prefix): continue if hasattr(Class, name_prefix + name): - result.append((value, getattr(Class, name_prefix + name))) + opclass = resoperation.opclasses[getattr(rop, name)] + print value, name, opclass + result.append((value, opclass, getattr(Class, name_prefix + name))) return unrolling_iterable(result) +def make_dispatcher_method(Class, name_prefix, op_prefix=None, default=None): + ops = _findall(Class, name_prefix, op_prefix) + def dispatch(self, op, *args): + opnum = op.getopnum() + for value, cls, func in ops: + if opnum == value: + assert isinstance(op, cls) + return func(self, op, *args) + if default: + return default(self, op, *args) + dispatch.func_name = "dispatch_" + name_prefix + return dispatch + + def partition(array, left, right): last_item = array[right] pivot = last_item.sort_key() diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.history import Const, ConstInt, BoxInt from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs -from pypy.jit.metainterp.optimizeopt.util import descrlist_dict +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, sort_descrs from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.optimizeopt import optimizer from pypy.jit.metainterp.executor import execute @@ -456,13 +456,8 @@ ###self.heap_op_optimizer.optimize_SETARRAYITEM_GC(op, value, fieldvalue) self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptVirtualize, 'optimize_') +dispatch_opt = make_dispatcher_method(OptVirtualize, 'optimize_', + default=OptVirtualize.emit_operation) + +OptVirtualize.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -8,7 +8,7 @@ from pypy.jit.metainterp.optimizeopt import optimizer, virtualize from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1 from pypy.jit.metainterp.optimizeopt.optimizer import llhelper -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter import heaptracker from pypy.rlib.unroll import unrolling_iterable @@ -649,16 +649,11 @@ self.emit_operation(op) return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) -optimize_ops = _findall(OptString, 'optimize_') +dispatch_opt = make_dispatcher_method(OptString, 'optimize_', + default=OptString.emit_operation) def _findall_call_oopspec(): prefix = 'opt_call_stroruni_' From noreply at buildbot.pypy.org Mon Jul 4 16:43:40 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 4 Jul 2011 16:43:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Add an explicit __copy__ method to arrays (rather than using the __reduce__ method), which uses memcpy. This is significantly faster than the previous implementation. Message-ID: <20110704144340.CAF1482941@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45335:734b488bb971 Date: 2011-07-04 07:51 -0700 http://bitbucket.org/pypy/pypy/changeset/734b488bb971/ Log: Add an explicit __copy__ method to arrays (rather than using the __reduce__ method), which uses memcpy. This is significantly faster than the previous implementation. diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,21 @@ from __future__ import with_statement +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -73,6 +76,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +100,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +163,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -615,6 +617,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) + return w_a + def array_byteswap__Array(space, self): if mytype.bytes not in [1, 2, 4, 8]: msg = "byteswap not supported for this array" From noreply at buildbot.pypy.org Mon Jul 4 16:43:42 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 4 Jul 2011 16:43:42 +0200 (CEST) Subject: [pypy-commit] pypy default: Merged upstream. Message-ID: <20110704144342.17BAE82941@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45336:6d1937f2d0a9 Date: 2011-07-04 07:51 -0700 http://bitbucket.org/pypy/pypy/changeset/6d1937f2d0a9/ Log: Merged upstream. diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -203,13 +203,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -220,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -431,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt @@ -34,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -57,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -440,5 +433,6 @@ propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile @@ -434,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -569,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -477,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -20,9 +20,25 @@ if op_prefix and not name.startswith(op_prefix): continue if hasattr(Class, name_prefix + name): - result.append((value, getattr(Class, name_prefix + name))) + opclass = resoperation.opclasses[getattr(rop, name)] + print value, name, opclass + result.append((value, opclass, getattr(Class, name_prefix + name))) return unrolling_iterable(result) +def make_dispatcher_method(Class, name_prefix, op_prefix=None, default=None): + ops = _findall(Class, name_prefix, op_prefix) + def dispatch(self, op, *args): + opnum = op.getopnum() + for value, cls, func in ops: + if opnum == value: + assert isinstance(op, cls) + return func(self, op, *args) + if default: + return default(self, op, *args) + dispatch.func_name = "dispatch_" + name_prefix + return dispatch + + def partition(array, left, right): last_item = array[right] pivot = last_item.sort_key() diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.history import Const, ConstInt, BoxInt from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs -from pypy.jit.metainterp.optimizeopt.util import descrlist_dict +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, sort_descrs from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.optimizeopt import optimizer from pypy.jit.metainterp.executor import execute @@ -456,13 +456,8 @@ ###self.heap_op_optimizer.optimize_SETARRAYITEM_GC(op, value, fieldvalue) self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptVirtualize, 'optimize_') +dispatch_opt = make_dispatcher_method(OptVirtualize, 'optimize_', + default=OptVirtualize.emit_operation) + +OptVirtualize.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -8,7 +8,7 @@ from pypy.jit.metainterp.optimizeopt import optimizer, virtualize from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1 from pypy.jit.metainterp.optimizeopt.optimizer import llhelper -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter import heaptracker from pypy.rlib.unroll import unrolling_iterable @@ -649,16 +649,11 @@ self.emit_operation(op) return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) -optimize_ops = _findall(OptString, 'optimize_') +dispatch_opt = make_dispatcher_method(OptString, 'optimize_', + default=OptString.emit_operation) def _findall_call_oopspec(): prefix = 'opt_call_stroruni_' diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -969,7 +969,10 @@ // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" From noreply at buildbot.pypy.org Mon Jul 4 16:52:31 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 4 Jul 2011 16:52:31 +0200 (CEST) Subject: [pypy-commit] pypy celldict-versions: some more precision Message-ID: <20110704145231.7F76C82941@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: celldict-versions Changeset: r45337:acd7e7a7d15b Date: 2011-07-01 23:59 +0200 http://bitbucket.org/pypy/pypy/changeset/acd7e7a7d15b/ Log: some more precision diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -21,21 +21,25 @@ v2 = strategy.version assert v1 is not v2 assert d.getitem("a") == 1 + assert d.strategy.getdictvalue_no_unwrapping(d, "a") == 1 d.setitem("a", 2) v3 = strategy.version assert v2 is not v3 assert d.getitem("a") == 2 + assert d.strategy.getdictvalue_no_unwrapping(d, "a").w_value == 2 d.setitem("a", 3) v4 = strategy.version assert v3 is v4 assert d.getitem("a") == 3 + assert d.strategy.getdictvalue_no_unwrapping(d, "a").w_value == 3 d.delitem("a") v5 = strategy.version assert v5 is not v4 assert d.getitem("a") is None + assert d.strategy.getdictvalue_no_unwrapping(d, "a") is None class AppTestModuleDict(object): def setup_class(cls): From noreply at buildbot.pypy.org Mon Jul 4 16:52:32 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 4 Jul 2011 16:52:32 +0200 (CEST) Subject: [pypy-commit] pypy celldict-versions: a test that a global read of a non-written global takes only a guard_not_invalidated Message-ID: <20110704145232.B769682941@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: celldict-versions Changeset: r45338:6b534032e588 Date: 2011-07-04 15:59 +0200 http://bitbucket.org/pypy/pypy/changeset/6b534032e588/ Log: a test that a global read of a non-written global takes only a guard_not_invalidated diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -232,3 +232,19 @@ return total # self.run_and_check(main, []) + + + def test_global(self): + log = self.run(""" + i = 0 + globalinc = 1 + def main(n): + global i + while i < n: + l = globalinc # ID: globalread + i += l + """, [1000]) + + loop, = log.loops_by_id("globalread", is_entry_bridge=True) + op, = loop.ops_by_id("globalread") + assert op.name == "guard_not_invalidated" From noreply at buildbot.pypy.org Mon Jul 4 16:52:34 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 4 Jul 2011 16:52:34 +0200 (CEST) Subject: [pypy-commit] pypy celldict-versions: merge default Message-ID: <20110704145234.5624C82941@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: celldict-versions Changeset: r45339:5d58831ea9ce Date: 2011-07-04 16:12 +0200 http://bitbucket.org/pypy/pypy/changeset/5d58831ea9ce/ Log: merge default diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4400,7 +4400,10 @@ self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) + if hasattr(l.__add__, '__objclass__'): # CPython + self.assertTrue(l.__add__.__objclass__ is list) + else: # PyPy + self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -210,10 +210,20 @@ def m(self): "aaa" m.x = 3 + class B(A): + pass - bm = A().m + bm = B().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self + assert bm.im_class is B assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -203,13 +203,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -220,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -431,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt @@ -34,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -57,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -382,6 +375,18 @@ v1.intbound.make_gt(IntBound(0, 0)) self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -428,5 +433,6 @@ propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile @@ -434,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -569,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -477,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -439,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] @@ -4123,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5373,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -1484,7 +1484,7 @@ raise OperationError( moduledict.w_NotSupportedError, space.wrap("Variable_TypeByValue(): unhandled data type %s" % - (space.type(w_value).getname(space, '?'),))) + (space.type(w_value).getname(space),))) def newByInputTypeHandler(space, cursor, w_inputTypeHandler, w_value, numElements): w_var = space.call(w_inputTypeHandler, diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py --- a/pypy/module/pyexpat/__init__.py +++ b/pypy/module/pyexpat/__init__.py @@ -2,6 +2,22 @@ from pypy.interpreter.mixedmodule import MixedModule +class ErrorsModule(MixedModule): + "Definition of pyexpat.errors module." + + appleveldefs = { + } + + interpleveldefs = { + } + + def setup_after_space_initialization(self): + from pypy.module.pyexpat import interp_pyexpat + for name in interp_pyexpat.xml_error_list: + self.space.setattr(self, self.space.wrap(name), + interp_pyexpat.ErrorString(self.space, + getattr(interp_pyexpat, name))) + class Module(MixedModule): "Python wrapper for Expat parser." @@ -21,6 +37,10 @@ 'version_info': 'interp_pyexpat.get_expat_version_info(space)', } + submodules = { + 'errors': ErrorsModule, + } + for name in ['XML_PARAM_ENTITY_PARSING_NEVER', 'XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE', 'XML_PARAM_ENTITY_PARSING_ALWAYS']: diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -31,6 +31,48 @@ XML_Content_Ptr = lltype.Ptr(lltype.ForwardReference()) XML_Parser = rffi.COpaquePtr(typedef='XML_Parser') +xml_error_list = [ + "XML_ERROR_NO_MEMORY", + "XML_ERROR_SYNTAX", + "XML_ERROR_NO_ELEMENTS", + "XML_ERROR_INVALID_TOKEN", + "XML_ERROR_UNCLOSED_TOKEN", + "XML_ERROR_PARTIAL_CHAR", + "XML_ERROR_TAG_MISMATCH", + "XML_ERROR_DUPLICATE_ATTRIBUTE", + "XML_ERROR_JUNK_AFTER_DOC_ELEMENT", + "XML_ERROR_PARAM_ENTITY_REF", + "XML_ERROR_UNDEFINED_ENTITY", + "XML_ERROR_RECURSIVE_ENTITY_REF", + "XML_ERROR_ASYNC_ENTITY", + "XML_ERROR_BAD_CHAR_REF", + "XML_ERROR_BINARY_ENTITY_REF", + "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", + "XML_ERROR_MISPLACED_XML_PI", + "XML_ERROR_UNKNOWN_ENCODING", + "XML_ERROR_INCORRECT_ENCODING", + "XML_ERROR_UNCLOSED_CDATA_SECTION", + "XML_ERROR_EXTERNAL_ENTITY_HANDLING", + "XML_ERROR_NOT_STANDALONE", + "XML_ERROR_UNEXPECTED_STATE", + "XML_ERROR_ENTITY_DECLARED_IN_PE", + "XML_ERROR_FEATURE_REQUIRES_XML_DTD", + "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING", + # Added in Expat 1.95.7. + "XML_ERROR_UNBOUND_PREFIX", + # Added in Expat 1.95.8. + "XML_ERROR_UNDECLARING_PREFIX", + "XML_ERROR_INCOMPLETE_PE", + "XML_ERROR_XML_DECL", + "XML_ERROR_TEXT_DECL", + "XML_ERROR_PUBLICID", + "XML_ERROR_SUSPENDED", + "XML_ERROR_NOT_SUSPENDED", + "XML_ERROR_ABORTED", + "XML_ERROR_FINISHED", + "XML_ERROR_SUSPEND_PE", + ] + class CConfigure: _compilation_info_ = eci XML_Content = rffi_platform.Struct('XML_Content', [ @@ -56,6 +98,9 @@ XML_FALSE = rffi_platform.ConstantInteger('XML_FALSE') XML_TRUE = rffi_platform.ConstantInteger('XML_TRUE') + for name in xml_error_list: + locals()[name] = rffi_platform.ConstantInteger(name) + for k, v in rffi_platform.configure(CConfigure).items(): globals()[k] = v @@ -298,7 +343,8 @@ XML_GetErrorCode = expat_external( 'XML_GetErrorCode', [XML_Parser], rffi.INT) XML_ErrorString = expat_external( - 'XML_ErrorString', [rffi.INT], rffi.CCHARP) + 'XML_ErrorString', [rffi.INT], + rffi.CCHARP) XML_GetCurrentLineNumber = expat_external( 'XML_GetCurrentLineNumber', [XML_Parser], rffi.INT) XML_GetErrorLineNumber = XML_GetCurrentLineNumber @@ -691,7 +737,7 @@ elif space.is_true(space.isinstance(w_encoding, space.w_str)): encoding = space.str_w(w_encoding) else: - type_name = space.type(w_encoding).getname(space, '?') + type_name = space.type(w_encoding).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 1 must be string or None,' @@ -711,7 +757,7 @@ space.wrap('namespace_separator must be at most one character,' ' omitted, or None')) else: - type_name = space.type(w_namespace_separator).getname(space, '?') + type_name = space.type(w_namespace_separator).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 2 must be string or None,' diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py --- a/pypy/module/pyexpat/test/test_parser.py +++ b/pypy/module/pyexpat/test/test_parser.py @@ -38,7 +38,7 @@ parser = pyexpat.ParserCreate() raises(pyexpat.ExpatError, "parser.Parse(xml, True)") - def test_encoding(self): + def test_encoding_argument(self): import pyexpat for encoding_arg in (None, 'utf-8', 'iso-8859-1'): for namespace_arg in (None, '{'): @@ -68,7 +68,7 @@ assert p.buffer_size == 150 raises(TypeError, setattr, p, 'buffer_size', sys.maxint + 1) - def test_encoding(self): + def test_encoding_xml(self): # use one of the few encodings built-in in expat xml = "caf\xe9" import pyexpat @@ -120,3 +120,14 @@ return True p.ExternalEntityRefHandler = handler p.Parse(xml) + + def test_errors(self): + import types + import pyexpat + assert isinstance(pyexpat.errors, types.ModuleType) + # check a few random errors + assert pyexpat.errors.XML_ERROR_SYNTAX == 'syntax error' + assert (pyexpat.errors.XML_ERROR_INCORRECT_ENCODING == + 'encoding specified in XML declaration is incorrect') + assert (pyexpat.errors.XML_ERROR_XML_DECL == + 'XML declaration not well-formed') diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -176,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,21 +9,42 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + def test_interface_residual_call(): space = gettestobjspace(usemodules=['pypyjit']) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -139,6 +139,12 @@ iterator = self.unerase(w_dict.dstorage).clear() self.mutated() + def popitem(self, w_dict): + d = self.unerase(w_dict.dstorage) + key, w_value = d.popitem() + self.mutated() + return self.space.wrap(key), unwrap_cell(w_value) + def switch_to_object_strategy(self, w_dict): d = self.unerase(w_dict.dstorage) strategy = self.space.fromcache(ObjectDictStrategy) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -6,7 +6,7 @@ from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.rlib.objectmodel import r_dict, we_are_translated +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize from pypy.rlib.debug import mark_dict_non_null from pypy.rlib import rerased @@ -155,9 +155,6 @@ erase = staticmethod(erase) unerase = staticmethod(unerase) - def __init__(self, space): - self.space = space - def get_empty_storage(self): return self.erase(None) @@ -165,15 +162,25 @@ #XXX implement other strategies later if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) - return + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + self.switch_to_object_strategy(w_dict) - strategy = self.space.fromcache(ObjectDictStrategy) + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) storage = strategy.get_empty_storage() w_dict.strategy = strategy w_dict.dstorage = storage - def switch_to_string_strategy(self, w_dict): - strategy = self.space.fromcache(StringDictStrategy) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) storage = strategy.get_empty_storage() w_dict.strategy = strategy w_dict.dstorage = storage @@ -268,7 +275,7 @@ # concrete subclasses of the above -class AbtractTypedStrategy(object): +class AbstractTypedStrategy(object): _mixin_ = True @staticmethod @@ -291,6 +298,9 @@ def get_empty_storage(self): raise NotImplementedError("abstract base class") + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + def setitem(self, w_dict, w_key, w_value): space = self.space if self.is_correct_type(w_key): @@ -333,6 +343,8 @@ if self.is_correct_type(w_key): return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None else: self.switch_to_object_strategy(w_dict) return w_dict.getitem(w_key) @@ -365,8 +377,7 @@ w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new) - -class ObjectDictStrategy(AbtractTypedStrategy, DictStrategy): +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) @@ -386,21 +397,21 @@ force_non_null=True) return self.erase(new_dict) + def _never_equal_to(self, w_lookup_type): + return False + def iter(self, w_dict): - return RDictIteratorImplementation(self.space, self, w_dict) + return ObjectIteratorImplementation(self.space, self, w_dict) def keys(self, w_dict): return self.unerase(w_dict.dstorage).keys() -class StringDictStrategy(AbtractTypedStrategy, DictStrategy): +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) unerase = staticmethod(unerase) - def __init__(self, space): - self.space = space - def wrap(self, unwrapped): return self.space.wrap(unwrapped) @@ -416,6 +427,9 @@ mark_dict_non_null(res) return self.erase(res) + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + def setitem_str(self, w_dict, key, w_value): assert key is not None self.unerase(w_dict.dstorage)[key] = w_value @@ -426,14 +440,7 @@ if type(w_key) is space.StringObjectCls: return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - - if self.is_correct_type(w_key): - return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) - elif _never_equal_to_string(space, space.type(w_key)): - return None - else: - self.switch_to_object_strategy(w_dict) - return w_dict.getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) def getitem_str(self, w_dict, key): assert key is not None @@ -446,27 +453,67 @@ class StrIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - dict_w = strategy.unerase(dictimplementation.dstorage) - self.iterator = dict_w.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class RDictIteratorImplementation(IteratorImplementation): +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_int) + + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) + +class IntIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - d = strategy.unerase(dictimplementation.dstorage) - self.iterator = d.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value + else: + return None, None + + +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: return None, None @@ -775,7 +822,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -670,6 +670,8 @@ def popitem(self, w_dict): curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError key = curr.selector[0] w_value = self.getitem_str(w_dict, key) w_key = self.space.wrap(key) diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -105,3 +105,33 @@ string = "int" string2 = "isinstance" + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -137,31 +137,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -176,18 +176,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -195,33 +195,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -235,16 +235,16 @@ def test_popitem3(self): #object - d = {"a": 1, 2:2, "c":3} + d = {"a": 1, 2: 2, "c": 3} l = [] while True: try: l.append(d.popitem()) except KeyError: break; - assert ("a",1) in l - assert (2,2) in l - assert ("c",3) in l + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l #string d = {"a": 1, "b":2, "c":3} @@ -254,12 +254,12 @@ l.append(d.popitem()) except KeyError: break; - assert ("a",1) in l - assert ("b",2) in l - assert ("c",3) in l + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -292,12 +292,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -322,15 +322,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -341,10 +341,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -391,21 +391,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} @@ -734,9 +730,6 @@ set([('a', 1), ('b', 2), ('d', 4), ('e', 5)])) - if option.runappdirect: - py.test.skip("__repr__ doesn't work on appdirect") - class AppTestStrategies(object): def setup_class(cls): if option.runappdirect: @@ -761,7 +754,12 @@ o.a = 1 assert "StringDictStrategy" in self.get_strategy(d) - + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -802,6 +800,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -479,6 +479,7 @@ it2 = a.__dict__.popitem() assert it2 == ("x", 5) assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) @@ -622,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -292,12 +292,13 @@ 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -352,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -590,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -607,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -83,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,12 +964,15 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" From noreply at buildbot.pypy.org Mon Jul 4 16:52:35 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 4 Jul 2011 16:52:35 +0200 (CEST) Subject: [pypy-commit] pypy celldict-versions: make quasi-immutable fields actually useful here Message-ID: <20110704145235.8CBFF82941@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: celldict-versions Changeset: r45340:25523b8429ab Date: 2011-07-04 16:47 +0200 http://bitbucket.org/pypy/pypy/changeset/25523b8429ab/ Log: make quasi-immutable fields actually useful here diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -43,6 +43,9 @@ self.version = VersionTag() def getdictvalue_no_unwrapping(self, w_dict, key): + # NB: it's important to promote self here, so that self.version is a + # no-op due to the quasi-immutable field + self = jit.promote(self) return self._getdictvalue_no_unwrapping_pure(self.version, w_dict, key) @jit.elidable_promote('0,1,2') From noreply at buildbot.pypy.org Mon Jul 4 16:52:36 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 4 Jul 2011 16:52:36 +0200 (CEST) Subject: [pypy-commit] pypy celldict-versions: fix pypy-c tests that changed due to the new way globals work Message-ID: <20110704145236.C625482941@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: celldict-versions Changeset: r45341:d937d40615df Date: 2011-07-04 17:00 +0200 http://bitbucket.org/pypy/pypy/changeset/d937d40615df/ Log: fix pypy-c tests that changed due to the new way globals work diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -39,11 +39,12 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated(descr=) i13 = int_lt(i7, i9) - guard_true(i13, descr=) + guard_true(i13, descr=) i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=) i18 = int_add(i7, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) @@ -69,15 +70,16 @@ assert loop.match(""" i13 = int_lt(i8, 307200) guard_true(i13, descr=) + guard_not_invalidated(descr=) # the bound check guard on img has been killed (thanks to the asserts) i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) + guard_no_overflow(descr=) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=) # on 64bit, there is a guard checking that i19 actually fits into 32bit ... setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -66,33 +66,23 @@ ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value", - "getfield_gc", "guard_value", - "getfield_gc", "guard_nonnull_class"] - # LOAD_GLOBAL of OFFSET but in different function partially folded - # away - # XXX could be improved + "getfield_gc", "guard_value"] ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value"] + assert log.opnames(ops) == ["guard_not_invalidated"] # - # two LOAD_GLOBAL of f, the second is folded away ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["getfield_gc", "guard_nonnull_class"] + assert log.opnames(ops) == ["guard_not_invalidated"] # assert entry_bridge.match_by_id('call', """ - p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) - p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) - p35 = getfield_gc(p29, descr=) - p36 = getfield_gc(p29, descr=) + guard_not_invalidated(descr=) p38 = call(ConstClass(getexecutioncontext), descr=) p39 = getfield_gc(p38, descr=) i40 = force_token() p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) + guard_isnull(p41, descr=) i42 = getfield_gc(p38, descr=) i43 = int_is_zero(i42) - guard_true(i43, descr=) + guard_true(i43, descr=) i50 = force_token() """) # @@ -100,19 +90,16 @@ # ----------------------------- loop, = log.loops_by_id('call') assert loop.match(""" - i12 = int_lt(i5, i6) - guard_true(i12, descr=) + guard_not_invalidated(descr=) + i9 = int_lt(i5, i6) + guard_true(i9, descr=) + i10 = force_token() + i12 = int_add(i5, 1) i13 = force_token() - i15 = int_add(i5, 1) - i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) - i18 = force_token() - i20 = int_add_ovf(i16, 1) + i15 = int_add_ovf(i12, 1) guard_no_overflow(descr=) - i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) + jump(p0, p1, p2, p3, p4, i15, i6, p7, p8, descr=) """) def test_method_call(self): @@ -281,32 +268,30 @@ loop0, = log.loops_by_id('g1') assert loop0.match_by_id('g1', """ i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) assert loop0.match_by_id('h1', """ i20 = force_token() i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) assert loop0.match_by_id('g2', """ i27 = force_token() i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) # loop1, = log.loops_by_id('g3') assert loop1.match_by_id('g3', """ i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) def test_stararg(self): @@ -405,8 +390,8 @@ assert loop.match(""" i10 = int_lt(i5, i6) guard_true(i10, descr=) + guard_not_invalidated(descr=) i120 = int_add(i5, 1) - guard_not_invalidated(descr=) --TICK-- jump(..., descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py --- a/pypy/module/pypyjit/test_pypy_c/test_import.py +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -15,13 +15,9 @@ assert log.result == 500 loop, = log.loops_by_id('import') assert loop.match_by_id('import', """ - p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) - p14 = getfield_gc(ConstPtr(ptr13), descr=) - p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) + guard_not_invalidated(descr=) + p10 = getfield_gc(ConstPtr(ptr9), descr=) + guard_value(p10, ConstPtr(ptr11), descr=) """) def test_import_fast_path(self, tmpdir): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -52,7 +52,7 @@ i10 = int_add_ovf(i5, i7) guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) + jump(p0, p1, p2, p3, p4, i10, i6, i7, p8, descr=) """) def test_getattr_with_dynamic_attribute(self): @@ -118,7 +118,7 @@ i9 = int_lt(i7, i8) guard_true(i9, descr=.*) guard_not_invalidated(descr=.*) - i11 = int_add(i8, 1) + i11 = int_add(i7, 1) i12 = force_token() --TICK-- p20 = new_with_vtable(ConstClass(W_IntObject)) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -17,6 +17,7 @@ assert loop.match(""" i7 = int_lt(i4, 300) guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 3000) guard_no_overflow(descr=...) i11 = int_add(i4, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -16,27 +16,27 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = int_mod(i6, i10) i17 = int_rshift(i15, 63) i18 = int_and(i10, i17) i19 = int_add(i15, i18) i21 = int_lt(i19, 0) - guard_false(i21, descr=) + guard_false(i21, descr=...) i22 = int_ge(i19, i10) - guard_false(i22, descr=) + guard_false(i22, descr=...) i23 = strgetitem(p11, i19) i24 = int_ge(i19, i12) - guard_false(i24, descr=) + guard_false(i24, descr=...) i25 = unicodegetitem(p13, i19) - guard_not_invalidated(descr=) p27 = newstr(1) strsetitem(p27, 0, i23) - p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) - guard_no_exception(descr=) - i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) - guard_true(i32, descr=) + p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...) + guard_no_exception(descr=...) + i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...) + guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) - """) \ No newline at end of file + """) From noreply at buildbot.pypy.org Mon Jul 4 17:17:44 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 4 Jul 2011 17:17:44 +0200 (CEST) Subject: [pypy-commit] pypy default: Simplify the array code, also probably improve its performance. Message-ID: <20110704151744.8B96F82941@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45342:de2e42a93f5e Date: 2011-07-04 08:25 -0700 http://bitbucket.org/pypy/pypy/changeset/de2e42a93f5e/ Log: Simplify the array code, also probably improve its performance. diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -313,6 +313,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -321,12 +329,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -389,7 +392,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -397,7 +400,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -415,7 +418,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -517,7 +520,7 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): From noreply at buildbot.pypy.org Mon Jul 4 18:15:36 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 4 Jul 2011 18:15:36 +0200 (CEST) Subject: [pypy-commit] pypy default: Make the distinction between internal and public API array methods a bit more sane. Message-ID: <20110704161536.A791482941@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45343:94c4be3793c3 Date: 2011-07-04 09:23 -0700 http://bitbucket.org/pypy/pypy/changeset/94c4be3793c3/ Log: Make the distinction between internal and public API array methods a bit more sane. diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -40,7 +40,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -270,12 +270,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -527,7 +525,7 @@ self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() From noreply at buildbot.pypy.org Mon Jul 4 20:37:26 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 20:37:26 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: remove this slide, too confusing Message-ID: <20110704183726.19D5B82934@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3819:efdf40cf1518 Date: 2011-07-02 13:47 +0200 http://bitbucket.org/pypy/extradoc/changeset/efdf40cf1518/ Log: remove this slide, too confusing diff --git a/talk/ctpug2011/talk.rst b/talk/ctpug2011/talk.rst --- a/talk/ctpug2011/talk.rst +++ b/talk/ctpug2011/talk.rst @@ -148,23 +148,6 @@ * if guard fails often enough, start tracing from the failure -Meta-Tracing in PyPy --------------------- - -* The explanation above assumes a tracing JIT for the full Python - language - -* Would need to be maintained whenever we change the Python version we - support - -* Instead, we have a "meta-tracing JIT" - -* A very important point for us since we don't have a huge team - to implement all Python semantics for the JIT - -* We trace the python interpreter's main loop (running N times) interpreting - a python loop (running once) - PYPYLOG -------- From noreply at buildbot.pypy.org Mon Jul 4 20:37:27 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 20:37:27 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: add talk as it went Message-ID: <20110704183727.5A0CD82934@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3820:59c21b5d6b75 Date: 2011-07-04 20:43 +0200 http://bitbucket.org/pypy/extradoc/changeset/59c21b5d6b75/ Log: add talk as it went diff --git a/talk/ctpug2011/talk.pdf b/talk/ctpug2011/talk.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d3beca9e041cdca571282d7773f78f839c519d3d GIT binary patch [cut] From noreply at buildbot.pypy.org Mon Jul 4 20:37:28 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 20:37:28 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: merge Message-ID: <20110704183728.C04FB82934@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3821:828f6cf048c4 Date: 2011-07-04 20:45 +0200 http://bitbucket.org/pypy/extradoc/changeset/828f6cf048c4/ Log: merge diff --git a/sprintinfo/genova-pegli-2011/sprintplanning.txt b/sprintinfo/genova-pegli-2011/sprintplanning.txt --- a/sprintinfo/genova-pegli-2011/sprintplanning.txt +++ b/sprintinfo/genova-pegli-2011/sprintplanning.txt @@ -3,13 +3,12 @@ 1. cython backend (anto hardshooter) (not done) 2. crowdsourcing as a way to get funded (kickstarter like website? Haskell Industry approach? we need a "we are bloody fast" website (lac, all) (half done) -3. discuss GIL removal plan (arigo, all) (not done) +3. discuss GIL removal plan (arigo, all) DONE 4. embedding pypy as a .so (not done) 5. ootype progress, play with jpype (berdario, anto) (not done) -6. pypy logging improvements (berdario + others) (not done) -7. look in the list of reported bugs and fix them (everybody) (did some) +7. look in the list of reported bugs and fix them (everybody) (did some more) 8. improving the performance of shadowstack (arigo + somebody) (not done) -9. CCP games issues / windows on 64 bit machines (tismer + others) +9. windows on 64 bit machines (tismer + others) (in-progress) 10. status of tealet and enhance it (tismer + arigo) proof of concept works, but only with Boehm 11. work on "success stories" part of pypy.org @@ -21,3 +20,6 @@ try to do more of it. Anto has brought an access point. Maybe this will be better. +12. make a quick demo from the sobel algorithm (anto) +13. investigate the fannkuch benchmark (anto, romain) +14. visiting Genova (done) diff --git a/talk/ctpug2011/src/count.py b/talk/ctpug2011/src/count.py new file mode 100644 --- /dev/null +++ b/talk/ctpug2011/src/count.py @@ -0,0 +1,23 @@ +import sys +import time + +def count_mult_of_5(N): + mult = 0 + not_mult = 0 + for i in range(N): + if i % 5 == 0: + mult += 1 + else: + not_mult += 1 + return mult, not_mult + +def main(): + N = int(sys.argv[1]) + start = time.clock() + count = count_mult_of_5(N) + end = time.clock() + print 'count: ', count + print 'time:', end-start, 'secs' + +if __name__ == '__main__': + main() diff --git a/talk/iwtc11/benchmarks/image/magnify.py b/talk/iwtc11/benchmarks/image/magnify.py --- a/talk/iwtc11/benchmarks/image/magnify.py +++ b/talk/iwtc11/benchmarks/image/magnify.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python + +import errno from plain import Image from math import atan2, sqrt, sin, cos, ceil, floor @@ -65,7 +68,13 @@ start = start0 = time() for fcnt, img in enumerate(mplayer(MyImage, fn)): - view(magnify(img)) + try: + view(magnify(img)) + except IOError, e: + if e.errno != errno.EPIPE: + raise + print 'Exiting' + break print 1.0 / (time() - start), 'fps, ', (fcnt-2) / (time() - start0), 'average fps' start = time() if fcnt==2: diff --git a/talk/iwtc11/benchmarks/image/sobel.py b/talk/iwtc11/benchmarks/image/sobel.py --- a/talk/iwtc11/benchmarks/image/sobel.py +++ b/talk/iwtc11/benchmarks/image/sobel.py @@ -1,3 +1,4 @@ +import errno from noborder import NoBorderImagePadded from math import sqrt @@ -78,8 +79,15 @@ #view(img) #sobeldx(img) #view(uint8(sobel_magnitude(img))) - view(sobel_magnitude_uint8(img)) #sobel_magnitude_uint8(img) + try: + view(sobel_magnitude_uint8(img)) + except IOError, e: + if e.errno != errno.EPIPE: + raise + print 'Exiting' + break + print 1.0 / (time() - start), 'fps, ', (fcnt-2) / (time() - start0), 'average fps' start = time() if fcnt==2: diff --git a/talk/iwtc11/paper.tex b/talk/iwtc11/paper.tex --- a/talk/iwtc11/paper.tex +++ b/talk/iwtc11/paper.tex @@ -122,7 +122,7 @@ \begin{abstract} One of the nice properties of a tracing JIT is that many of its optimization -are simple requiring one forward pass. This is not true for loop-invariant code +are simple requiring one forward pass only. This is not true for loop-invariant code motion which is a very important optimization for code with tight kernels. In this paper we present a scheme for making simple optimizations loop-aware by using a simple pre-processing step on the trace and not changing the @@ -246,7 +246,7 @@ \end{lstlisting} The iteration of the loop that was peeled off (lines 1-4) is called the -\emph{preamble}, the loop afterwards the \emph{peeled loop}. +\emph{preamble}, the loop afterwards (lines 6-9) the \emph{peeled loop}. Now the optimizer optimizes both of these two iterations of the loop together, disregarding the \lstinline{jump} and the label in lines 4-6. Doing this, common @@ -438,7 +438,7 @@ \section{Making Trace Optimizations Loop Aware} -Before the trace is passed to a backend compiling it into machine code +Before a trace is passed to the backend compiling it into machine code it is optimized to achieve better performance. One goal of that is to move operations out of the loop making them executed only once @@ -446,8 +446,8 @@ leaves the loop body intact, but prefixes it with one iteration of the loop. This operation by itself will not achieve anything. But if it is combined with other optimizations it can increase the effectiveness of -those optimizations. For many optimization of interest some care has -to be taken when they are combined with loop peeling. This is +those optimizations. For many optimization of interest only a few +additional details has to be considered when they are combined with loop peeling. These are described below by explaining the loop peeling optimization followed by a set of other optimizations and how they interact with loop peeling. From noreply at buildbot.pypy.org Mon Jul 4 20:56:53 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 20:56:53 +0200 (CEST) Subject: [pypy-commit] pypy default: kill 2 codespeak references Message-ID: <20110704185653.493DC82934@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45344:f75946f8b127 Date: 2011-07-04 21:04 +0200 http://bitbucket.org/pypy/pypy/changeset/f75946f8b127/ Log: kill 2 codespeak references diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -237,7 +237,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -186,7 +186,7 @@ print "\n\nTarget specific help:\n\n" targetspec_dic['print_help'](config) print "\n\nFor detailed descriptions of the command line options see" - print "http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html" + print "http://pypy.readthedocs.org/en/latest/config/commandline.html" sys.exit(0) return targetspec_dic, translateconfig, config, args From noreply at buildbot.pypy.org Mon Jul 4 21:03:07 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 21:03:07 +0200 (CEST) Subject: [pypy-commit] pypy default: (justinpeel) Micronumpy pow and mod Message-ID: <20110704190307.77C5A82934@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45345:bff49201da90 Date: 2011-07-04 21:10 +0200 http://bitbucket.org/pypy/pypy/changeset/bff49201da90/ Log: (justinpeel) Micronumpy pow and mod diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -40,6 +40,9 @@ elif b == '/': right = stack.pop() stack.append(stack.pop().descr_div(space, right)) + elif b == '%': + right = stack.pop() + stack.append(stack.pop().descr_mod(space, right)) else: print "Unknown opcode: %s" % b raise BogusBytecode() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -5,6 +5,7 @@ from pypy.rlib import jit from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name +import math def dummy1(v): @@ -38,6 +39,10 @@ return v1 * v2 def div(v1, v2): return v1 / v2 +def pow(v1, v2): + return math.pow(v1, v2) +def mod(v1, v2): + return math.fmod(v1, v2) class BaseArray(Wrappable): def __init__(self): @@ -80,6 +85,8 @@ descr_sub = _binop_impl(sub) descr_mul = _binop_impl(mul) descr_div = _binop_impl(div) + descr_pow = _binop_impl(pow) + descr_mod = _binop_impl(mod) def get_concrete(self): raise NotImplementedError @@ -355,6 +362,8 @@ __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), __div__ = interp2app(BaseArray.descr_div), + __pow__ = interp2app(BaseArray.descr_pow), + __mod__ = interp2app(BaseArray.descr_mod), mean = interp2app(BaseArray.descr_mean), ) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -154,6 +154,51 @@ for i in range(5): assert b[i] == i / 5.0 + def test_pow(self): + from numpy import array + a = array(range(5)) + b = a ** a + for i in range(5): + print b[i], i**i + assert b[i] == i**i + + def test_pow_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a ** b + for i in range(5): + assert c[i] == i ** 2 + + def test_pow_constant(self): + from numpy import array + a = array(range(5)) + b = a ** 2 + for i in range(5): + assert b[i] == i ** 2 + + def test_mod(self): + from numpy import array + a = array(range(1,6)) + b = a % a + for i in range(5): + assert b[i] == 0 + + def test_mod_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a % b + for i in range(5): + assert c[i] == i % 2 + + def test_mod_constant(self): + from numpy import array + a = array(range(5)) + b = a % 2 + for i in range(5): + assert b[i] == i % 2 + def test_auto_force(self): from numpy import array a = array(range(5)) @@ -213,4 +258,4 @@ from numpy import array, mean a = array(range(5)) assert a.mean() == 2.0 - assert a[:4].mean() == 1.5 \ No newline at end of file + assert a[:4].mean() == 1.5 From noreply at buildbot.pypy.org Mon Jul 4 22:03:41 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 22:03:41 +0200 (CEST) Subject: [pypy-commit] pypy default: kill unused parameters Message-ID: <20110704200341.8545A82934@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45346:ffd7e955f3d4 Date: 2011-07-04 21:24 +0200 http://bitbucket.org/pypy/pypy/changeset/ffd7e955f3d4/ Log: kill unused parameters diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call1, Call2, SingleDimSlice, add, mul) + FloatWrapper, Call2, SingleDimSlice, add, mul) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile @@ -13,8 +13,6 @@ cls.space = FakeSpace() def test_add(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, ar, Signature()) @@ -27,8 +25,6 @@ assert result == f(5) def test_floatadd(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, FloatWrapper(4.5), Signature()) @@ -41,8 +37,6 @@ assert result == f(5) def test_already_forecd(self): - space = self.space - def f(i): ar = SingleDimArray(i) v1 = Call2(add, ar, FloatWrapper(4.5), Signature()) @@ -95,8 +89,6 @@ self.check_loop_count(3) def test_slice(self): - space = self.space - def f(i): step = 3 ar = SingleDimArray(step*i) @@ -111,8 +103,6 @@ assert result == f(5) def test_slice2(self): - space = self.space - def f(i): step1 = 2 step2 = 3 From noreply at buildbot.pypy.org Mon Jul 4 22:03:42 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 22:03:42 +0200 (CEST) Subject: [pypy-commit] pypy default: (justinpeel) unary pos, neg, abs Message-ID: <20110704200342.BAFD782935@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45347:f5220ca4563e Date: 2011-07-04 22:11 +0200 http://bitbucket.org/pypy/pypy/changeset/f5220ca4563e/ Log: (justinpeel) unary pos, neg, abs diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -43,6 +43,8 @@ elif b == '%': right = stack.pop() stack.append(stack.pop().descr_mod(space, right)) + elif b == '|': + stack.append(stack.pop().descr_abs(space)) else: print "Unknown opcode: %s" % b raise BogusBytecode() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -31,6 +31,12 @@ self.transitions[target] = new = Signature() return new +def pos(v): + return v +def neg(v): + return -v +def absolute(v): + return abs(v) def add(v1, v2): return v1 + v2 def sub(v1, v2): @@ -57,6 +63,22 @@ arr.force_if_needed() del self.invalidates[:] + def _unop_impl(function): + signature = Signature() + def impl(self, space): + new_sig = self.signature.transition(signature) + res = Call1( + function, + self, + self.signature.transition(signature)) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + + descr_pos = _unop_impl(pos) + descr_neg = _unop_impl(neg) + descr_abs = _unop_impl(absolute) + def _binop_impl(function): signature = Signature() def impl(self, space, w_other): @@ -358,6 +380,9 @@ __getitem__ = interp2app(BaseArray.descr_getitem), __setitem__ = interp2app(BaseArray.descr_setitem), + __pos__ = interp2app(BaseArray.descr_pos), + __neg__ = interp2app(BaseArray.descr_neg), + __abs__ = interp2app(BaseArray.descr_abs), __add__ = interp2app(BaseArray.descr_add), __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -199,6 +199,27 @@ for i in range(5): assert b[i] == i % 2 + def test_pos(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = +a + for i in range(5): + assert b[i] == a[i] + + def test_neg(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = -a + for i in range(5): + assert b[i] == -a[i] + + def test_abs(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = abs(a) + for i in range(5): + assert b[i] == abs(a[i]) + def test_auto_force(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call2, SingleDimSlice, add, mul) + FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile @@ -36,6 +36,21 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) + def test_neg(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + v = Call1(neg, ar, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, + "setarrayitem_raw": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + + assert result == f(5) + def test_already_forecd(self): def f(i): ar = SingleDimArray(i) From noreply at buildbot.pypy.org Mon Jul 4 22:05:23 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 4 Jul 2011 22:05:23 +0200 (CEST) Subject: [pypy-commit] pypy default: simplify Message-ID: <20110704200523.7E6EE82934@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45348:bcff0dbb6a0e Date: 2011-07-04 22:13 +0200 http://bitbucket.org/pypy/pypy/changeset/bcff0dbb6a0e/ Log: simplify diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -70,7 +70,7 @@ res = Call1( function, self, - self.signature.transition(signature)) + new_sig) self.invalidates.append(res) return space.wrap(res) return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) From noreply at buildbot.pypy.org Mon Jul 4 22:19:58 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 4 Jul 2011 22:19:58 +0200 (CEST) Subject: [pypy-commit] pypy default: Ignore Vim's temporary files. Message-ID: <20110704201958.0556382934@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45349:85149c5b8a3d Date: 2011-07-04 13:28 -0700 http://bitbucket.org/pypy/pypy/changeset/85149c5b8a3d/ Log: Ignore Vim's temporary files. diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,6 +1,7 @@ syntax: glob *.py[co] *~ +.*.swp syntax: regexp ^testresult$ From noreply at buildbot.pypy.org Mon Jul 4 22:24:17 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 4 Jul 2011 22:24:17 +0200 (CEST) Subject: [pypy-commit] pypy default: For that matter, ignore translated JVM PyPy. Message-ID: <20110704202417.E5CEC82934@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45350:9371ae6112c7 Date: 2011-07-04 13:32 -0700 http://bitbucket.org/pypy/pypy/changeset/9371ae6112c7/ Log: For that matter, ignore translated JVM PyPy. diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -39,6 +39,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ From noreply at buildbot.pypy.org Tue Jul 5 02:52:51 2011 From: noreply at buildbot.pypy.org (ademan) Date: Tue, 5 Jul 2011 02:52:51 +0200 (CEST) Subject: [pypy-commit] pypy default: Added test for name mangling of quasi immutable fields on pbc on ootype. Message-ID: <20110705005251.7D8DB82934@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45351:2630c86662b4 Date: 2011-07-04 18:00 -0700 http://bitbucket.org/pypy/pypy/changeset/2630c86662b4/ Log: Added test for name mangling of quasi immutable fields on pbc on ootype. diff --git a/pypy/rpython/ootypesystem/test/test_oopbc.py b/pypy/rpython/ootypesystem/test/test_oopbc.py --- a/pypy/rpython/ootypesystem/test/test_oopbc.py +++ b/pypy/rpython/ootypesystem/test/test_oopbc.py @@ -81,3 +81,18 @@ res = interpret(f, [1], type_system='ootype') assert res == 2 +def test_quasi_immutable(): + class A(object): + _immutable_fields_ = ['x?'] + def __init__(self): + self.x = 3 + def foo(self): + return self.x + + a = A() + + def f(): + return a.foo() + + res = interpret(f, [], type_system='ootype') + assert res == 3 From noreply at buildbot.pypy.org Tue Jul 5 10:59:30 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 5 Jul 2011 10:59:30 +0200 (CEST) Subject: [pypy-commit] buildbot default: actually update the *-latest symlinks Message-ID: <20110705085930.2705A82934@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r523:03cc273d734b Date: 2011-07-05 11:02 +0200 http://bitbucket.org/pypy/buildbot/changeset/03cc273d734b/ Log: actually update the *-latest symlinks diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -2,6 +2,7 @@ from buildbot.steps import source, shell, transfer, master from buildbot.status.builder import SUCCESS from buildbot.process.properties import WithProperties +from pypybuildbot.util import symlink_force import os class ShellCmd(shell.ShellCommand): @@ -46,7 +47,7 @@ except OSError: pass try: - os.symlink(os.path.basename(self.masterdest), self.symlinkname) + symlink_force(os.path.basename(self.masterdest), self.symlinkname) except OSError: pass diff --git a/bot2/pypybuildbot/test/test_util.py b/bot2/pypybuildbot/test/test_util.py new file mode 100644 --- /dev/null +++ b/bot2/pypybuildbot/test/test_util.py @@ -0,0 +1,10 @@ +from pypybuildbot import util + +def test_symlink_force(tmpdir): + one = tmpdir.join('one').ensure(file=True) + two = tmpdir.join('two').ensure(file=True) + latest = tmpdir.join('latest') + util.symlink_force(str(one), str(latest)) + assert latest.readlink() == str(one) + util.symlink_force(str(two), str(latest)) + assert latest.readlink() == str(two) diff --git a/bot2/pypybuildbot/util.py b/bot2/pypybuildbot/util.py --- a/bot2/pypybuildbot/util.py +++ b/bot2/pypybuildbot/util.py @@ -1,3 +1,4 @@ +import os import socket def we_are_debugging(): @@ -7,3 +8,12 @@ mod = __import__(name, {}, {}, ['__all__']) reload(mod) return mod + +def symlink_force(src, dst): + """ + More or less equivalent to "ln -fs": it overwrites the destination, if it + exists + """ + if os.path.lexists(dst): + os.remove(dst) + os.symlink(src, dst) From noreply at buildbot.pypy.org Tue Jul 5 11:18:17 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 5 Jul 2011 11:18:17 +0200 (CEST) Subject: [pypy-commit] pypy default: fix this test, we do not care about the exact guard number Message-ID: <20110705091817.E861B82934@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45352:1085869752d2 Date: 2011-07-05 11:23 +0200 http://bitbucket.org/pypy/pypy/changeset/1085869752d2/ Log: fix this test, we do not care about the exact guard number diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -301,12 +301,12 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) def test_stararg(self): From noreply at buildbot.pypy.org Tue Jul 5 11:18:19 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 5 Jul 2011 11:18:19 +0200 (CEST) Subject: [pypy-commit] pypy default: partially revert cd3882d509f3, it made this test failing Message-ID: <20110705091819.2EA6082934@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45353:9d1c34936183 Date: 2011-07-05 11:26 +0200 http://bitbucket.org/pypy/pypy/changeset/9d1c34936183/ Log: partially revert cd3882d509f3, it made this test failing diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -115,7 +115,7 @@ # ---------------------- loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i9 = int_lt(i7, i8) + i9 = int_lt(i8, i7) guard_true(i9, descr=.*) guard_not_invalidated(descr=.*) i11 = int_add(i8, 1) @@ -124,7 +124,7 @@ p20 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p20, i11, descr=) setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i11, i8, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) """) def test_oldstyle_newstyle_mix(self): From noreply at buildbot.pypy.org Tue Jul 5 11:41:58 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 5 Jul 2011 11:41:58 +0200 (CEST) Subject: [pypy-commit] pypy default: (theller) Message-ID: <20110705094158.79C3482934@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45354:634a87b2adbf Date: 2011-07-05 11:50 +0200 http://bitbucket.org/pypy/pypy/changeset/634a87b2adbf/ Log: (theller) fix issue743, by Thomas Heller: https://bugs.pypy.org/issue743 I changed test_commethods.py from unittest to py.test. However, I don't have a windows box around where to try it, so I cross the fingers and I commit it blindly. Please review :-) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -139,7 +139,10 @@ return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -218,5 +221,7 @@ 'z' : _ffi.types.void_p, 'O' : _ffi.types.void_p, 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, } diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -322,20 +322,18 @@ RuntimeWarning, stacklevel=2) if self._com_index: - assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None - - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -343,6 +341,11 @@ if not outargs: return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + if len(outargs) == 1: return outargs[0] return tuple(outargs) @@ -398,10 +401,10 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) cdll = self.dll._handle try: @@ -468,11 +471,7 @@ newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -587,13 +586,7 @@ retval = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, argsandobjs[0]) - else: - retval = int(resbuffer[0]) - elif restype is not None: + if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) @@ -601,7 +594,13 @@ # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value - retval = checker(val) + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) else: diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -216,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py @@ -0,0 +1,82 @@ +# unittest for SOME ctypes com function calls. +# Can't resist from implementing some kind of mini-comtypes +# theller ;-) + +import py +import sys +if sys.platform != "win32": + py.test.skip('windows only test') + +import ctypes, new, unittest +from ctypes.wintypes import HRESULT +from _ctypes import COMError + +oleaut32 = ctypes.OleDLL("oleaut32") + +class UnboundMethod(object): + def __init__(self, func, index, name): + self.func = func + self.index = index + self.name = name + self.__doc__ = func.__doc__ + + def __repr__(self): + return "" % (self.index, self.name, id(self)) + + def __get__(self, instance, owner): + if instance is None: + return self + return new.instancemethod(self.func, instance, owner) + +def commethod(index, restype, *argtypes): + """A decorator that generates COM methods. The decorated function + itself is not used except for it's name.""" + def make_commethod(func): + comfunc = ctypes.WINFUNCTYPE(restype, *argtypes)(index, func.__name__) + comfunc.__name__ = func.__name__ + comfunc.__doc__ = func.__doc__ + return UnboundMethod(comfunc, index, func.__name__) + return make_commethod + +class ICreateTypeLib2(ctypes.c_void_p): + + @commethod(1, ctypes.c_long) + def AddRef(self): + pass + + @commethod(2, ctypes.c_long) + def Release(self): + pass + + @commethod(4, HRESULT, ctypes.c_wchar_p) + def SetName(self): + """Set the name of the library.""" + + @commethod(12, HRESULT) + def SaveAllChanges(self): + pass + + +CreateTypeLib2 = oleaut32.CreateTypeLib2 +CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, ctypes.POINTER(ICreateTypeLib2)) + +################################################################ + +def test_basic_comtypes(): + punk = ICreateTypeLib2() + hr = CreateTypeLib2(0, "foobar.tlb", punk) + assert hr == 0 + + assert 2 == punk.AddRef() + assert 3 == punk.AddRef() + assert 4 == punk.AddRef() + + punk.SetName("TypeLib_ByPYPY") + py.test.raises(COMError, lambda: punk.SetName(None)) + + # This would save the typelib to disk. + ## punk.SaveAllChanges() + + assert 3 == punk.Release() + assert 2 == punk.Release() + assert 1 == punk.Release() From notifications-noreply at bitbucket.org Tue Jul 5 13:00:03 2011 From: notifications-noreply at bitbucket.org (Bitbucket) Date: Tue, 05 Jul 2011 11:00:03 -0000 Subject: [pypy-commit] Notification: pypy Message-ID: <20110705110003.9407.13521@bitbucket03.managed.contegix.com> You have received a notification from Samuel Ytterbrink. Hi, I forked pypy. My fork is at https://bitbucket.org/neppord/pypy. -- Change your notification settings at https://bitbucket.org/account/notifications/ From noreply at buildbot.pypy.org Tue Jul 5 18:53:24 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Tue, 5 Jul 2011 18:53:24 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: Making much progress with win64 and test_ll2ctypes. Message-ID: <20110705165324.5764982934@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45358:f412af2f88c1 Date: 2011-07-05 18:53 +0200 http://bitbucket.org/pypy/pypy/changeset/f412af2f88c1/ Log: Making much progress with win64 and test_ll2ctypes. Compiler configuration works with Visual Studio 8. Checking in since there might be a problem in PyPy that is dependant of the test selection both on 32 and 64 bit. test_arrayofstruct seems to fail at assert a1[2].x == 102 result is always array[0] which is 100. I will check the trunk first before reporting an error. diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -33,24 +33,53 @@ """ -import sys +import sys, struct from pypy.rpython import extregistry from pypy.rlib import objectmodel -# set up of machine internals, using sys.maxint only. -# if sys.maxsize exists and is greater, it is used instead. -_maxnumber = sys.maxint -if hasattr(sys, "maxsize"): - _maxnumber = max(sys.maxint, sys.maxsize) -_bits = 1 -_test = _maxnumber -while _test: - _bits += 1 - _test >>= 1 +""" +Long-term target: +We want to make pypy very flexible concerning its data type layout. +This is a larger task for later. + +Short-term target: +We want to run PyPy on windows 64 bit. + +Problem: +On windows 64 bit, integers are only 32 bit. This is a problem for PyPy +right now, since it assumes that a c long can hold a pointer. +We therefore set up the target machine constants to obey this rule. +Right now this affects 64 bit Python only on windows. + +Note: We use the struct module, because the array module doesn's support +all typecodes. +""" + +def _get_bitsize(typecode): + return len(struct.pack(typecode, 1)) * 8 + +_long_typecode = 'l' +if _get_bitsize('P') > _get_bitsize('l'): + _long_typecode = 'P' + +def _get_long_bit(): + # whatever size a long has, make it big enough for a pointer. + return _get_bitsize(_long_typecode) + +# exported for now for testing array values. +# might go into its own module. +def get_long_pattern(x): + """get the bit pattern for a long, adjusted to pointer size""" + return struct.pack(_long_typecode, x) + +# used in tests for ctypes: +is_emulated_long = _long_typecode <> 'l' -LONG_BIT = _bits +LONG_BIT = _get_long_bit() LONG_MASK = (2**LONG_BIT)-1 LONG_TEST = 2**(LONG_BIT-1) + +# XXX this is a good guess, but what if a long long is 128 bit? LONGLONG_BIT = 64 LONGLONG_MASK = (2**LONGLONG_BIT)-1 LONGLONG_TEST = 2**(LONGLONG_BIT-1) @@ -107,8 +136,6 @@ r_class.BITS == LONG_BIT and r_class.SIGNED) _should_widen_type._annspecialcase_ = 'specialize:memo' -del _bits, _test, _maxnumber - def is_valid_int(r): return -sys.maxint - 1 <= r <= sys.maxint diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -17,6 +17,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.rstring import StringBuilder, UnicodeBuilder from pypy.rpython.lltypesystem import llmemory +from pypy.rlib.rarithmetic import LONG_BIT import os, sys class CConstant(Symbolic): @@ -884,7 +885,7 @@ return 4 assert isinstance(tp, lltype.Number) if tp is lltype.Signed: - return ULONG._type.BITS/8 + return LONG_BIT/8 return tp._type.BITS/8 sizeof._annspecialcase_ = 'specialize:memo' diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -15,7 +15,7 @@ from pypy.rpython.test.test_llinterp import interpret from pypy.annotation.annrpython import RPythonAnnotator from pypy.rpython.rtyper import RPythonTyper -from pypy.rlib.rarithmetic import r_uint +from pypy.rlib.rarithmetic import r_uint, get_long_pattern, is_emulated_long if False: # for now, please keep it False by default from pypy.rpython.lltypesystem import ll2ctypes @@ -154,11 +154,6 @@ assert not ALLOCATED def test_array_nolength(self): - # XXX cannot fix this test when lltype.Signed is faked for win64. - # Replacement with rffi.LONG does not work because then I cannot - # index an array. So I have to use lltype.Signed . But the rffi.sizeof - # at the end has a hard-coded mapping to LONG and ignores the faked - # maxint. So what should I do? A = lltype.Array(lltype.Signed, hints={'nolength': True}) a = lltype.malloc(A, 10, flavor='raw') a[0] = 100 @@ -399,10 +394,9 @@ b = rffi.cast(lltype.Ptr(B), a) - checker = array.array('l') + expected = '' for i in range(10): - checker.append(i*i) - expected = checker.tostring() + expected += get_long_pattern(i*i) for i in range(len(expected)): assert b[i] == expected[i] @@ -442,10 +436,15 @@ def dummy(n): return n+1 - FUNCTYPE = lltype.FuncType([rffi.LONG], rffi.LONG) + FUNCTYPE = lltype.FuncType([lltype.Signed], lltype.Signed) cdummy = lltype2ctypes(llhelper(lltype.Ptr(FUNCTYPE), dummy)) - assert isinstance(cdummy, - ctypes.CFUNCTYPE(ctypes.c_long, ctypes.c_long)) + if not is_emulated_long: + assert isinstance(cdummy, + ctypes.CFUNCTYPE(ctypes.c_long, ctypes.c_long)) + else: + # XXX maybe we skip this if it breaks on some platforms + assert isinstance(cdummy, + ctypes.CFUNCTYPE(ctypes.c_longlong, ctypes.c_longlong)) res = cdummy(41) assert res == 42 lldummy = ctypes2lltype(lltype.Ptr(FUNCTYPE), cdummy) @@ -479,13 +478,13 @@ export_symbols=['get_mul']) get_mul = rffi.llexternal( 'get_mul', [], - lltype.Ptr(lltype.FuncType([rffi.LONG], rffi.LONG)), + lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)), compilation_info=eci) # This call returns a pointer to a function taking one argument funcptr = get_mul() # cast it to the "real" function type - FUNCTYPE2 = lltype.FuncType([rffi.LONG, rffi.LONG], - rffi.LONG) + FUNCTYPE2 = lltype.FuncType([lltype.Signed, lltype.Signed], + lltype.Signed) cmul = rffi.cast(lltype.Ptr(FUNCTYPE2), funcptr) # and it can be called with the expected number of arguments res = cmul(41, 42) @@ -502,12 +501,12 @@ lltype.Void) lst = [23, 43, 24, 324, 242, 34, 78, 5, 3, 10] - A = lltype.Array(rffi.LONG, hints={'nolength': True}) + A = lltype.Array(lltype.Signed, hints={'nolength': True}) a = lltype.malloc(A, 10, flavor='raw') for i in range(10): a[i] = lst[i] - SIGNEDPTR = lltype.Ptr(lltype.FixedSizeArray(rffi.LONG, 1)) + SIGNEDPTR = lltype.Ptr(lltype.FixedSizeArray(lltype.Signed, 1)) def my_compar(p1, p2): p1 = rffi.cast(SIGNEDPTR, p1) @@ -517,7 +516,7 @@ qsort(rffi.cast(rffi.VOIDP, a), rffi.cast(rffi.SIZE_T, 10), - rffi.cast(rffi.SIZE_T, llmemory.sizeof(rffi.LONG)), + rffi.cast(rffi.SIZE_T, llmemory.sizeof(lltype.Signed)), llhelper(lltype.Ptr(CMPFUNC), my_compar)) for i in range(10): @@ -545,8 +544,9 @@ checkval(uninitialized2ctypes(rffi.CHAR), 'B') checkval(uninitialized2ctypes(rffi.SHORT), 'h') - checkval(uninitialized2ctypes(rffi.INT), 'i') - checkval(uninitialized2ctypes(rffi.UINT), 'I') + if not is_emulated_long: + checkval(uninitialized2ctypes(rffi.INT), 'i') + checkval(uninitialized2ctypes(rffi.UINT), 'I') checkval(uninitialized2ctypes(rffi.LONGLONG), 'q') checkval(uninitialized2ctypes(rffi.DOUBLE), 'd') checkobj(uninitialized2ctypes(rffi.INTP), @@ -563,7 +563,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_substructures(self): - S1 = lltype.Struct('S1', ('x', rffi.LONG)) + S1 = lltype.Struct('S1', ('x', lltype.Signed)) BIG = lltype.Struct('BIG', ('s1a', S1), ('s1b', S1)) s = lltype.malloc(BIG, flavor='raw') s.s1a.x = 123 @@ -613,7 +613,7 @@ def test_recursive_struct(self): SX = lltype.ForwardReference() - S1 = lltype.Struct('S1', ('p', lltype.Ptr(SX)), ('x', rffi.LONG)) + S1 = lltype.Struct('S1', ('p', lltype.Ptr(SX)), ('x', lltype.Signed)) SX.become(S1) # a chained list s1 = lltype.malloc(S1, flavor='raw') @@ -691,7 +691,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_arrayofstruct(self): - S1 = lltype.Struct('S1', ('x', rffi.LONG)) + S1 = lltype.Struct('S1', ('x', lltype.Signed)) A = lltype.Array(S1, hints={'nolength': True}) a = lltype.malloc(A, 5, flavor='raw') a[0].x = 100 diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py --- a/pypy/translator/platform/__init__.py +++ b/pypy/translator/platform/__init__.py @@ -253,8 +253,12 @@ else: host_factory = Freebsd_64 elif os.name == 'nt': - from pypy.translator.platform.windows import Windows - host_factory = Windows + from pypy.translator.platform.windows import Windows, Windows_x64 + import platform + if platform.architecture()[0] == '32bit': + host_factory = Windows + else: + host_factory = Windows_x64 else: # pray from pypy.translator.platform.distutils_platform import DistutilsPlatform diff --git a/pypy/translator/platform/windows.py b/pypy/translator/platform/windows.py --- a/pypy/translator/platform/windows.py +++ b/pypy/translator/platform/windows.py @@ -12,14 +12,23 @@ return MingwPlatform(cc) else: return MsvcPlatform(cc) + +def Windows_x64(cc=None): + return MsvcPlatform(cc, True) -def _get_msvc_env(vsver): +def _get_msvc_env(vsver, x64flag): try: toolsdir = os.environ['VS%sCOMNTOOLS' % vsver] except KeyError: return None - vcvars = os.path.join(toolsdir, 'vsvars32.bat') + if x64flag: + vsinstalldir = os.path.abspath(os.path.join(toolsdir, '..', '..')) + vcinstalldir = os.path.join(vsinstalldir, 'VC') + vcbindir = os.path.join(vcinstalldir, 'BIN') + vcvars = os.path.join(vcbindir, 'amd64', 'vcvarsamd64.bat') + else: + vcvars = os.path.join(toolsdir, 'vsvars32.bat') import subprocess popen = subprocess.Popen('"%s" & set' % (vcvars,), @@ -42,21 +51,21 @@ ## log.msg("Updated environment with %s" % (vcvars,)) return env -def find_msvc_env(): +def find_msvc_env(x64flag=False): # First, try to get the compiler which served to compile python msc_pos = sys.version.find('MSC v.') if msc_pos != -1: msc_ver = int(sys.version[msc_pos+6:msc_pos+10]) # 1300 -> 70, 1310 -> 71, 1400 -> 80, 1500 -> 90 vsver = (msc_ver / 10) - 60 - env = _get_msvc_env(vsver) + env = _get_msvc_env(vsver, x64flag) if env is not None: return env # Then, try any other version for vsver in (100, 90, 80, 71, 70): # All the versions I know - env = _get_msvc_env(vsver) + env = _get_msvc_env(vsver, x64flag) if env is not None: return env @@ -64,7 +73,8 @@ log.error("Could not find a Microsoft Compiler") # Assume that the compiler is already part of the environment -msvc_compiler_environ = find_msvc_env() +msvc_compiler_environ32 = find_msvc_env(False) +msvc_compiler_environ64 = find_msvc_env(True) class MsvcPlatform(Platform): name = "msvc" @@ -80,7 +90,11 @@ shared_only = () environ = None - def __init__(self, cc=None): + def __init__(self, cc=None, x64=False): + if x64: + msvc_compiler_environ = msvc_compiler_environ64 + else: + msvc_compiler_environ = msvc_compiler_environ32 Platform.__init__(self, 'cl.exe') if msvc_compiler_environ: self.c_environ = os.environ.copy() From noreply at buildbot.pypy.org Tue Jul 5 20:16:48 2011 From: noreply at buildbot.pypy.org (snus_mumrik) Date: Tue, 5 Jul 2011 20:16:48 +0200 (CEST) Subject: [pypy-commit] pypy numpy-impicit-convert: merge default Message-ID: <20110705181648.DFEA982934@wyvern.cs.uni-duesseldorf.de> Author: Ilya Osadchiy Branch: numpy-impicit-convert Changeset: r45359:418e5dfaa542 Date: 2011-07-05 21:23 +0300 http://bitbucket.org/pypy/pypy/changeset/418e5dfaa542/ Log: merge default diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,6 +1,7 @@ syntax: glob *.py[co] *~ +.*.swp syntax: regexp ^testresult$ @@ -38,6 +39,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,13 +4399,10 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__self__ is l) + if hasattr(l.__add__, '__objclass__'): # CPython self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) + else: # PyPy self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -139,7 +139,10 @@ return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -218,5 +221,7 @@ 'z' : _ffi.types.void_p, 'O' : _ffi.types.void_p, 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, } diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -322,20 +322,18 @@ RuntimeWarning, stacklevel=2) if self._com_index: - assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None - - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -343,6 +341,11 @@ if not outargs: return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + if len(outargs) == 1: return outargs[0] return tuple(outargs) @@ -398,10 +401,10 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) cdll = self.dll._handle try: @@ -468,11 +471,7 @@ newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -587,13 +586,7 @@ retval = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, argsandobjs[0]) - else: - retval = int(resbuffer[0]) - elif restype is not None: + if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) @@ -601,7 +594,13 @@ # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value - retval = checker(val) + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) else: diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -216,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -299,12 +299,13 @@ listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) @@ -351,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -379,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -129,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -266,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -355,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -248,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -134,7 +133,7 @@ def accept_comp_iteration(self, codegen, index): self.elt.walkabout(codegen) - codegen.emit_op_arg(ops.SET_ADD, index) + codegen.emit_op_arg(ops.SET_ADD, index + 1) class __extend__(ast.DictComp): @@ -148,7 +147,7 @@ def accept_comp_iteration(self, codegen, index): self.value.walkabout(codegen) self.key.walkabout(codegen) - codegen.emit_op_arg(ops.MAP_ADD, index) + codegen.emit_op_arg(ops.MAP_ADD, index + 1) # These are frame blocks. @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -237,7 +237,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -100,12 +100,12 @@ @jit.dont_look_inside def fast2locals(self): - # Copy values from self.fastlocals_w to self.w_locals + # Copy values from the fastlocals to self.w_locals if self.w_locals is None: self.w_locals = self.space.newdict() varnames = self.getcode().getvarnames() fastscope_w = self.getfastscope() - for i in range(min(len(varnames), len(fastscope_w))): + for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] if w_value is not None: @@ -114,7 +114,7 @@ @jit.dont_look_inside def locals2fast(self): - # Copy values from self.w_locals to self.fastlocals_w + # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None varnames = self.getcode().getvarnames() numlocals = self.getfastscopelength() diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack @@ -98,7 +98,7 @@ self.closure) for i in funccallunrolling: if i < nargs: - new_frame.fastlocals_w[i] = args_w[i] + new_frame.locals_stack_w[i] = args_w[i] return new_frame.run() elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1: assert isinstance(code, gateway.BuiltinCodePassThroughArguments1) @@ -158,7 +158,7 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg return new_frame.run() @@ -169,13 +169,13 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = self.defs_w[j] + new_frame.locals_stack_w[i] = self.defs_w[j] i += 1 return new_frame.run() @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -170,7 +170,7 @@ for i in range(len(args_to_copy)): argnum = args_to_copy[i] if argnum >= 0: - self.cells[i].set(self.fastlocals_w[argnum]) + self.cells[i].set(self.locals_stack_w[argnum]) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -63,6 +63,7 @@ the pypy compiler""" self.space = space eval.Code.__init__(self, name) + assert nlocals >= 0 self.co_argcount = argcount self.co_nlocals = nlocals self.co_stacksize = stacksize @@ -202,7 +203,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -215,7 +216,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -9,7 +9,7 @@ from pypy.interpreter import pytraceback from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib.jit import hint -from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.debug import make_sure_not_resized, check_nonneg from pypy.rlib.rarithmetic import intmask from pypy.rlib import jit from pypy.tool import stdlib_opcode @@ -56,16 +56,18 @@ assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals) - self.valuestack_w = [None] * code.co_stacksize - self.valuestackdepth = 0 + self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize) + self.nlocals = code.co_nlocals + self.valuestackdepth = code.co_nlocals self.lastblock = None + make_sure_not_resized(self.locals_stack_w) + check_nonneg(self.nlocals) + # if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure, code) - self.fastlocals_w = [None] * code.co_nlocals - make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno def mark_as_escaped(self): @@ -184,14 +186,14 @@ # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth - self.valuestack_w[depth] = w_object + self.locals_stack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 - assert depth >= 0, "pop from empty value stack" - w_object = self.valuestack_w[depth] - self.valuestack_w[depth] = None + assert depth >= self.nlocals, "pop from empty value stack" + w_object = self.locals_stack_w[depth] + self.locals_stack_w[depth] = None self.valuestackdepth = depth return w_object @@ -217,24 +219,24 @@ def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n - assert base >= 0 + assert base >= self.nlocals while True: n -= 1 if n < 0: break - values_w[n] = self.valuestack_w[base+n] + values_w[n] = self.locals_stack_w[base+n] return values_w @jit.unroll_safe def dropvalues(self, n): n = hint(n, promote=True) finaldepth = self.valuestackdepth - n - assert finaldepth >= 0, "stack underflow in dropvalues()" + assert finaldepth >= self.nlocals, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break - self.valuestack_w[finaldepth+n] = None + self.locals_stack_w[finaldepth+n] = None self.valuestackdepth = finaldepth @jit.unroll_safe @@ -261,30 +263,30 @@ # Contrast this with CPython where it's PEEK(-1). index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "peek past the bottom of the stack" - return self.valuestack_w[index] + assert index >= self.nlocals, "peek past the bottom of the stack" + return self.locals_stack_w[index] def settopvalue(self, w_object, index_from_top=0): index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "settop past the bottom of the stack" - self.valuestack_w[index] = w_object + assert index >= self.nlocals, "settop past the bottom of the stack" + self.locals_stack_w[index] = w_object @jit.unroll_safe def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 finaldepth = hint(finaldepth, promote=True) while depth >= finaldepth: - self.valuestack_w[depth] = None + self.locals_stack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth - def savevaluestack(self): - return self.valuestack_w[:self.valuestackdepth] + def save_locals_stack(self): + return self.locals_stack_w[:self.valuestackdepth] - def restorevaluestack(self, items_w): - assert None not in items_w - self.valuestack_w[:len(items_w)] = items_w + def restore_locals_stack(self, items_w): + self.locals_stack_w[:len(items_w)] = items_w + self.init_cells() self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): @@ -314,11 +316,12 @@ else: f_lineno = self.f_lineno - values_w = self.valuestack_w[0:self.valuestackdepth] + values_w = self.locals_stack_w[self.nlocals:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) - w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) + w_fastlocals = maker.slp_into_tuple_with_nulls( + space, self.locals_stack_w[:self.nlocals]) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None @@ -399,7 +402,8 @@ new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) - new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None @@ -423,28 +427,28 @@ @jit.dont_look_inside def getfastscope(self): "Get the fast locals as a list." - return self.fastlocals_w + return self.locals_stack_w @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) - if scope_len > len(self.fastlocals_w): + if scope_len > self.nlocals: raise ValueError, "new fastscope is longer than the allocated area" - # don't assign directly to 'fastlocals_w[:scope_len]' to be + # don't assign directly to 'locals_stack_w[:scope_len]' to be # virtualizable-friendly for i in range(scope_len): - self.fastlocals_w[i] = scope_w[i] + self.locals_stack_w[i] = scope_w[i] self.init_cells() def init_cells(self): - """Initialize cellvars from self.fastlocals_w + """Initialize cellvars from self.locals_stack_w. This is overridden in nestedscope.py""" pass def getfastscopelength(self): - return self.pycode.co_nlocals + return self.nlocals def getclosure(self): return None diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -324,7 +324,7 @@ def LOAD_FAST(self, varindex, next_instr): # access a local variable directly - w_value = self.fastlocals_w[varindex] + w_value = self.locals_stack_w[varindex] if w_value is None: self._load_fast_failed(varindex) self.pushvalue(w_value) @@ -343,7 +343,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self.fastlocals_w[varindex] = w_newvalue + self.locals_stack_w[varindex] = w_newvalue def POP_TOP(self, oparg, next_instr): self.popvalue() @@ -696,12 +696,12 @@ LOAD_GLOBAL._always_inline_ = True def DELETE_FAST(self, varindex, next_instr): - if self.fastlocals_w[varindex] is None: + if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise operationerrfmt(self.space.w_UnboundLocalError, message, varname) - self.fastlocals_w[varindex] = None + self.locals_stack_w[varindex] = None def BUILD_TUPLE(self, itemcount, next_instr): items = self.popvalues(itemcount) @@ -1048,30 +1048,18 @@ def SET_ADD(self, oparg, next_instr): w_value = self.popvalue() - w_set = self.peekvalue(oparg) + w_set = self.peekvalue(oparg - 1) self.space.call_method(w_set, 'add', w_value) def MAP_ADD(self, oparg, next_instr): w_key = self.popvalue() w_value = self.popvalue() - w_dict = self.peekvalue(oparg) + w_dict = self.peekvalue(oparg - 1) self.space.setitem(w_dict, w_key, w_value) def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION @@ -1091,12 +1079,10 @@ @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): - w_set = self.space.call_function(self.space.w_set) - if itemcount: - w_add = self.space.getattr(w_set, self.space.wrap("add")) - for i in range(itemcount): - w_item = self.popvalue() - self.space.call_function(w_add, w_item) + w_set = self.space.newset() + for i in range(itemcount): + w_item = self.popvalue() + self.space.call_method(w_set, 'add', w_item) self.pushvalue(w_set) def STORE_MAP(self, oparg, next_instr): diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py --- a/pypy/interpreter/test/test_eval.py +++ b/pypy/interpreter/test/test_eval.py @@ -15,16 +15,16 @@ self.code = code Frame.__init__(self, space) self.numlocals = numlocals - self.fastlocals_w = [None] * self.numlocals + self._fastlocals_w = [None] * self.numlocals def getcode(self): return self.code def setfastscope(self, scope_w): - self.fastlocals_w = scope_w + self._fastlocals_w = scope_w def getfastscope(self): - return self.fastlocals_w + return self._fastlocals_w def getfastscopelength(self): return self.numlocals @@ -38,11 +38,11 @@ self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({})) - self.f.fastlocals_w[0] = w(5) + self.f._fastlocals_w[0] = w(5) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5})) - self.f.fastlocals_w[2] = w(7) + self.f._fastlocals_w[2] = w(7) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5, 'args': 7})) @@ -57,13 +57,13 @@ w = self.space.wrap self.f.w_locals = self.space.wrap({}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [None]*5) + self.sameList(self.f._fastlocals_w, [None]*5) self.f.w_locals = self.space.wrap({'x': 5}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) + self.sameList(self.f._fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.wrap({'x':5, 'args':7}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), None, w(7), - None, None]) + self.sameList(self.f._fastlocals_w, [w(5), None, w(7), + None, None]) diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -203,3 +203,27 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + import sys + class A(object): + def m(self): + "aaa" + m.x = 3 + class B(A): + pass + + bm = B().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.im_class is B + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -761,12 +761,15 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -703,22 +703,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: @@ -889,7 +895,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -901,7 +907,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -467,13 +469,13 @@ # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,6 +185,13 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -75,12 +75,13 @@ # OS_MATH_SQRT = 100 - def __new__(cls, readonly_descrs_fields, + def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, can_invalidate=False): key = (frozenset(readonly_descrs_fields), + frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, @@ -89,8 +90,9 @@ return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields + result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: @@ -119,7 +121,7 @@ if effects is top_set: return None readonly_descrs_fields = [] - # readonly_descrs_arrays = [] --- not enabled for now + readonly_descrs_arrays = [] write_descrs_fields = [] write_descrs_arrays = [] @@ -145,10 +147,13 @@ elif tup[0] == "array": add_array(write_descrs_arrays, tup) elif tup[0] == "readarray": - pass + tupw = ("array",) + tup[1:] + if tupw not in effects: + add_array(readonly_descrs_arrays, tup) else: assert 0 return EffectInfo(readonly_descrs_fields, + readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect, diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -847,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -34,6 +34,15 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays +def test_include_read_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo.write_descrs_fields + assert not effectinfo.write_descrs_arrays + def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) @@ -51,6 +60,16 @@ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.write_descrs_arrays +def test_dont_include_read_and_write_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A)), + ("array", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert not effectinfo.readonly_descrs_arrays + assert not effectinfo.write_descrs_fields + assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLException diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -15,7 +15,7 @@ from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.jit.metainterp.optimize import InvalidLoop -from pypy.jit.metainterp.resume import NUMBERING +from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong def giveup(): @@ -119,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -302,7 +303,7 @@ rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) CNT_INT = -0x20000000 CNT_REF = -0x40000000 @@ -633,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled @@ -791,6 +792,7 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -203,13 +203,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -220,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -8,8 +8,8 @@ class CachedField(object): def __init__(self): - # Cache information for a field descr. It can be in one - # of two states: + # Cache information for a field descr, or for an (array descr, index) + # pair. It can be in one of two states: # # 1. 'cached_fields' is a dict mapping OptValues of structs # to OptValues of fields. All fields on-heap are @@ -27,19 +27,19 @@ self._lazy_setfield_registered = False def do_setfield(self, optheap, op): - # Update the state with the SETFIELD_GC operation 'op'. + # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) if self.possible_aliasing(optheap, structvalue): self.force_lazy_setfield(optheap) assert not self.possible_aliasing(optheap, structvalue) cached_fieldvalue = self._cached_fields.get(structvalue, None) if cached_fieldvalue is not fieldvalue: # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields list + # myself in the optheap's _lazy_setfields_and_arrayitems list self._lazy_setfield = op if not self._lazy_setfield_registered: - optheap._lazy_setfields.append(self) + optheap._lazy_setfields_and_arrayitems.append(self) self._lazy_setfield_registered = True else: # this is the case where the pending setfield ends up @@ -65,7 +65,7 @@ if self._lazy_setfield is not None: op = self._lazy_setfield assert optheap.getvalue(op.getarg(0)) is structvalue - return optheap.getvalue(op.getarg(1)) + return optheap.getvalue(op.getarglist()[-1]) else: return self._cached_fields.get(structvalue, None) @@ -87,7 +87,7 @@ # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) def get_reconstructed(self, optimizer, valuemap): @@ -100,12 +100,6 @@ return cf -class CachedArrayItems(object): - def __init__(self): - self.fixed_index_items = {} - self.var_index_item = None - self.var_index_indexvalue = None - class BogusPureField(JitException): pass @@ -116,9 +110,10 @@ def __init__(self): # cached fields: {descr: CachedField} self.cached_fields = {} - self._lazy_setfields = [] - # cached array items: {descr: CachedArrayItems} + # cached array items: {array descr: {index: CachedField}} self.cached_arrayitems = {} + # + self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -126,34 +121,23 @@ new = OptHeap() if True: - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() else: assert 0 # was: new.lazy_setfields = self.lazy_setfields for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) - new.cached_arrayitems = {} - for descr, d in self.cached_arrayitems.items(): - newd = {} - new.cached_arrayitems[descr] = newd - for value, cache in d.items(): - newcache = CachedArrayItems() - newd[value.get_reconstructed(optimizer, valuemap)] = newcache - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_reconstructed(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) - for index, fieldvalue in cache.fixed_index_items.items(): - newcache.fixed_index_items[index] = \ - fieldvalue.get_reconstructed(optimizer, valuemap) + for descr, submap in self.cached_arrayitems.items(): + newdict = {} + for index, d in submap.items(): + newdict[index] = d.get_reconstructed(optimizer, valuemap) + new.cached_arrayitems[descr] = newdict return new def clean_caches(self): - del self._lazy_setfields[:] + del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() self.cached_arrayitems.clear() @@ -164,50 +148,16 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): - d = self.cached_arrayitems.get(descr, None) - if d is None: - d = self.cached_arrayitems[descr] = {} - cache = d.get(value, None) - if cache is None: - cache = d[value] = CachedArrayItems() - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - index = indexbox.getint() - if write: - for value, othercache in d.iteritems(): - # fixed index, clean the variable index cache, in case the - # index is the same - othercache.var_index_indexvalue = None - othercache.var_index_item = None - try: - del othercache.fixed_index_items[index] - except KeyError: - pass - cache.fixed_index_items[index] = fieldvalue - else: - if write: - for value, othercache in d.iteritems(): - # variable index, clear all caches for this descr - othercache.var_index_indexvalue = None - othercache.var_index_item = None - othercache.fixed_index_items.clear() - cache.var_index_indexvalue = indexvalue - cache.var_index_item = fieldvalue - - def read_cached_arrayitem(self, descr, value, indexvalue): - d = self.cached_arrayitems.get(descr, None) - if d is None: - return None - cache = d.get(value, None) - if cache is None: - return None - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - return cache.fixed_index_items.get(indexbox.getint(), None) - elif cache.var_index_indexvalue is indexvalue: - return cache.var_index_item - return None + def arrayitem_cache(self, descr, index): + try: + submap = self.cached_arrayitems[descr] + except KeyError: + submap = self.cached_arrayitems[descr] = {} + try: + cf = submap[index] + except KeyError: + cf = submap[index] = CachedField() + return cf def emit_operation(self, op): self.emitting_operation(op) @@ -219,7 +169,8 @@ if op.is_ovf(): return if op.is_guard(): - self.optimizer.pendingfields = self.force_lazy_setfields_for_guard() + self.optimizer.pendingfields = ( + self.force_lazy_setfields_and_arrayitems_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -248,6 +199,8 @@ # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: self.force_lazy_setfield(fielddescr) + for arraydescr in effectinfo.readonly_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: self.force_lazy_setfield(fielddescr) try: @@ -256,8 +209,11 @@ except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) try: - del self.cached_arrayitems[arraydescr] + submap = self.cached_arrayitems[arraydescr] + for cf in submap.itervalues(): + cf._cached_fields.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -266,7 +222,7 @@ # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. return - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() self.clean_caches() @@ -277,6 +233,10 @@ for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] + for submap in self.cached_arrayitems.itervalues(): + for cf in submap.itervalues(): + if value in cf._cached_fields: + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -285,6 +245,14 @@ return cf.force_lazy_setfield(self) + def force_lazy_setarrayitem(self, arraydescr): + try: + submap = self.cached_arrayitems[arraydescr] + except KeyError: + return + for cf in submap.values(): + cf.force_lazy_setfield(self) + def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes # sense to avoid a situation like "int_eq/setfield_gc/guard_true", @@ -309,30 +277,49 @@ newoperations[-2] = lastop newoperations[-1] = prevop - def force_all_lazy_setfields(self): - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + def _assert_valid_cf(self, cf): + # check that 'cf' is in cached_fields or cached_arrayitems + if not we_are_translated(): + if cf not in self.cached_fields.values(): + for submap in self.cached_arrayitems.values(): + if cf in submap.values(): + break + else: + assert 0, "'cf' not in cached_fields/cached_arrayitems" + + def force_all_lazy_setfields_and_arrayitems(self): + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) cf.force_lazy_setfield(self) - def force_lazy_setfields_for_guard(self): + def force_lazy_setfields_and_arrayitems_for_guard(self): pendingfields = [] - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) op = cf._lazy_setfield if op is None: continue # the only really interesting case that we need to handle in the # guards' resume data is that of a virtual object that is stored - # into a field of a non-virtual object. + # into a field of a non-virtual object. Here, 'op' in either + # SETFIELD_GC or SETARRAYITEM_GC. value = self.getvalue(op.getarg(0)) assert not value.is_virtual() # it must be a non-virtual - fieldvalue = self.getvalue(op.getarg(1)) + fieldvalue = self.getvalue(op.getarglist()[-1]) if fieldvalue.is_virtual(): # this is the case that we leave to resume.py + opnum = op.getopnum() + if opnum == rop.SETFIELD_GC: + itemindex = -1 + elif opnum == rop.SETARRAYITEM_GC: + indexvalue = self.getvalue(op.getarg(1)) + assert indexvalue.is_constant() + itemindex = indexvalue.box.getint() + assert itemindex >= 0 + else: + assert 0 pendingfields.append((op.getdescr(), value.box, - fieldvalue.get_key_box())) + fieldvalue.get_key_box(), itemindex)) else: cf.force_lazy_setfield(self) self.fixup_guard_situation() @@ -364,24 +351,45 @@ cf.do_setfield(self, op) def optimize_GETARRAYITEM_GC(self, op): - value = self.getvalue(op.getarg(0)) + arrayvalue = self.getvalue(op.getarg(0)) indexvalue = self.getvalue(op.getarg(1)) - fieldvalue = self.read_cached_arrayitem(op.getdescr(), value, indexvalue) - if fieldvalue is not None: - self.make_equal_to(op.result, fieldvalue) - return - ###self.optimizer.optimize_default(op) + cf = None + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + fieldvalue = cf.getfield_from_cache(self, arrayvalue) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # default case: produce the operation + arrayvalue.ensure_nonnull() self.emit_operation(op) - fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) + # the remember the result of reading the array item + if cf is not None: + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(arrayvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): - self.emit_operation(op) - value = self.getvalue(op.getarg(0)) - fieldvalue = self.getvalue(op.getarg(2)) + if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), + op.getarg(1)], + op.getdescr()): + os.write(2, '[bogus immutable array declaration: %s]\n' % + (op.getdescr().repr_of_descr())) + raise BogusPureField + # indexvalue = self.getvalue(op.getarg(1)) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - write=True) + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + cf.do_setfield(self, op) + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # and then emit the operation + self.emit_operation(op) def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) @@ -423,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeopt.util import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -34,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -57,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -373,6 +366,27 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -418,5 +432,7 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') + +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile @@ -434,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -569,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -477,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -121,6 +121,41 @@ print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + class BaseTestOptimizeBasic(BaseTestBasic): @@ -404,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] @@ -1070,8 +1122,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1436,9 +1488,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) jump(p1, i1, i2, p3) """ @@ -1612,6 +1664,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -1874,7 +1927,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1892,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -1910,7 +1961,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2203,23 +2253,6 @@ # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2328,7 +2361,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2349,7 +2381,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2369,7 +2400,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2395,7 +2425,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2420,7 +2450,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2444,7 +2473,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2465,7 +2493,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2486,7 +2513,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2508,7 +2534,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2550,7 +2575,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2576,7 +2600,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2600,9 +2623,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2894,7 +2914,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2940,7 +2959,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -2979,7 +2997,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3006,7 +3023,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -4124,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -4498,6 +4513,29 @@ """ self.optimize_loop(ops, expected) + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py @@ -51,7 +51,7 @@ restype=types.sint) # def calldescr(cpu, FUNC, oopspecindex, extraeffect=None): - einfo = EffectInfo([], [], [], oopspecindex=oopspecindex, + einfo = EffectInfo([], [], [], [], oopspecindex=oopspecindex, extraeffect=extraeffect) return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo) # diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1381,8 +1381,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1806,9 +1806,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -1818,9 +1818,9 @@ # i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -2055,6 +2055,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2741,8 +2742,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -5374,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -5876,4 +5874,28 @@ escape(p0) jump(p0) """ - self.optimize_loop(ops, expected) \ No newline at end of file + self.optimize_loop(ops, expected) + + def test_setarrayitem_lazy(self): + ops = """ + [i0, i1] + p0 = escape() + i2 = escape() + p1 = new_with_vtable(ConstClass(node_vtable)) + setarrayitem_gc(p0, 2, p1, descr=arraydescr) + guard_true(i2) [] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + expected = """ + [i0, i1] + p0 = escape() + i2 = escape() + guard_true(i2) [p0] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/optimizeopt/test/test_util.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -166,19 +166,19 @@ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [])) + EffectInfo([], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [])) + EffectInfo([], [], [adescr], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [arraydescr])) + EffectInfo([], [], [adescr], [arraydescr])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([adescr], [], [])) + EffectInfo([adescr], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([nextdescr], [], [], + EffectInfo([nextdescr], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), @@ -195,15 +195,15 @@ _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jdindex, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -914,8 +914,10 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jd_index, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation + loc = jitdriver_sd.warmstate.get_location_str(greenkey) + debug_print(loc) args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @@ -1231,7 +1233,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -2,10 +2,12 @@ from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr +from pypy.rpython import annlowlevel from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert @@ -82,6 +84,13 @@ ('nums', lltype.Array(rffi.SHORT))) NUMBERINGP.TO.become(NUMBERING) +PENDINGFIELDSTRUCT = lltype.Struct('PendingField', + ('lldescr', annlowlevel.base_ptr_lltype()), + ('num', rffi.SHORT), + ('fieldnum', rffi.SHORT), + ('itemindex', rffi.INT)) +PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) + TAGMASK = 3 def tag(value, tagbits): @@ -329,7 +338,7 @@ value = values[box] value.get_args_for_fail(self) - for _, box, fieldbox in pending_setfields: + for _, box, fieldbox, _ in pending_setfields: self.register_box(box) self.register_box(fieldbox) value = values[fieldbox] @@ -405,13 +414,25 @@ return False def _add_pending_fields(self, pending_setfields): - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) if pending_setfields: - rd_pendingfields = [] - for descr, box, fieldbox in pending_setfields: + n = len(pending_setfields) + rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) + for i in range(n): + descr, box, fieldbox, itemindex = pending_setfields[i] + lldescr = annlowlevel.cast_instance_to_base_ptr(descr) num = self._gettagged(box) fieldnum = self._gettagged(fieldbox) - rd_pendingfields.append((descr, num, fieldnum)) + # the index is limited to 2147483647 (64-bit machines only) + if itemindex > 2147483647: + from pypy.jit.metainterp import compile + compile.giveup() + itemindex = rffi.cast(rffi.INT, itemindex) + # + rd_pendingfields[i].lldescr = lldescr + rd_pendingfields[i].num = num + rd_pendingfields[i].fieldnum = fieldnum + rd_pendingfields[i].itemindex= itemindex self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): @@ -727,10 +748,28 @@ self.virtuals_cache = [self.virtual_default] * len(virtuals) def _prepare_pendingfields(self, pendingfields): - if pendingfields is not None: - for descr, num, fieldnum in pendingfields: + if pendingfields: + for i in range(len(pendingfields)): + lldescr = pendingfields[i].lldescr + num = pendingfields[i].num + fieldnum = pendingfields[i].fieldnum + itemindex= pendingfields[i].itemindex + descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, + lldescr) struct = self.decode_ref(num) - self.setfield(descr, struct, fieldnum) + itemindex = rffi.cast(lltype.Signed, itemindex) + if itemindex < 0: + self.setfield(descr, struct, fieldnum) + else: + self.setarrayitem(descr, struct, itemindex, fieldnum) + + def setarrayitem(self, arraydescr, array, index, fieldnum): + if arraydescr.is_array_of_pointers(): + self.setarrayitem_ref(arraydescr, array, index, fieldnum) + elif arraydescr.is_array_of_floats(): + self.setarrayitem_float(arraydescr, array, index, fieldnum) + else: + self.setarrayitem_int(arraydescr, array, index, fieldnum) def _prepare_next_section(self, info): # Use info.enumerate_vars(), normally dispatching to @@ -903,15 +942,15 @@ structbox, fieldbox) def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, INT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT) def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, REF) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF) def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) - def setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): + def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): itembox = self.decode_box(fieldnum, kind) self.metainterp.execute_and_record(rop.SETARRAYITEM_GC, arraydescr, arraybox, diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -1252,7 +1252,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1312,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1343,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1496,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1531,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1595,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1676,7 +1676,9 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) + py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) def test_multiple_specialied_versions_bridge(self): @@ -1815,7 +1817,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2000,7 +2002,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2045,7 +2047,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2080,7 +2082,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2137,7 +2139,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2206,7 +2208,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2296,6 +2299,82 @@ res = self.meta_interp(f, [1]) assert res == f(1) + def test_remove_array_operations(self): + myjitdriver = JitDriver(greens = [], reds = ['a']) + class W_Int: + def __init__(self, intvalue): + self.intvalue = intvalue + def f(x): + a = [W_Int(x)] + while a[0].intvalue > 0: + myjitdriver.jit_merge_point(a=a) + a[0] = W_Int(a[0].intvalue - 3) + return a[0].intvalue + res = self.meta_interp(f, [100]) + assert res == -2 + #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + + def test_retrace_ending_up_retrazing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -49,7 +49,7 @@ x = l[n] l = [3] * 100 l[3] = x - l[3] = x + 1 + l[4] = x + 1 n -= 1 return l[0] diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py --- a/pypy/jit/metainterp/test/test_resume.py +++ b/pypy/jit/metainterp/test/test_resume.py @@ -1238,7 +1238,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, values, 0) assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)]) + modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s, -1)]) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume @@ -1259,6 +1259,106 @@ assert len(expected) == len(trace) assert demo55.next == demo66 +def test_virtual_adder_pending_fields_and_arrayitems(): + class Storage(object): + pass + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier._add_pending_fields([]) + assert not storage.rd_pendingfields + # + class FieldDescr(object): + pass + field_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061)} + modifier._add_pending_fields([(field_a, 42, 61, -1)]) + pf = storage.rd_pendingfields + assert len(pf) == 1 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is field_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + # + array_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061), + 62: rffi.cast(rffi.SHORT, 1062), + 63: rffi.cast(rffi.SHORT, 1063)} + modifier._add_pending_fields([(array_a, 42, 61, 0), + (array_a, 42, 62, 2147483647)]) + pf = storage.rd_pendingfields + assert len(pf) == 2 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[1].num) == 1042 + assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 + assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + # + from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole + py.test.raises(SwitchToBlackhole, modifier._add_pending_fields, + [(array_a, 42, 63, 2147483648)]) + +def test_resume_reader_fields_and_arrayitems(): + class ResumeReader(AbstractResumeDataReader): + def __init__(self, got=None, got_array=None): + self.got = got + self.got_array = got_array + def setfield(self, descr, struct, fieldnum): + assert lltype.typeOf(struct) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got.append((descr, struct, fieldnum)) + def setarrayitem(self, arraydescr, array, index, fieldnum): + assert lltype.typeOf(array) is lltype.Signed + assert lltype.typeOf(index) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got_array.append((arraydescr, array, index, fieldnum)) + def decode_ref(self, num): + return rffi.cast(lltype.Signed, num) * 100 + got = [] + pf = lltype.nullptr(PENDINGFIELDSP.TO) + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [] + # + class FieldDescr(AbstractDescr): + pass + field_a = FieldDescr() + field_b = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 2) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) + pf[0].itemindex = rffi.cast(rffi.INT, -1) + pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) + pf[1].num = rffi.cast(rffi.SHORT, 2042) + pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) + pf[1].itemindex = rffi.cast(rffi.INT, -1) + got = [] + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] + # + array_a = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 1) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) + pf[0].itemindex = rffi.cast(rffi.INT, 123) + got_array = [] + ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + assert got_array == [(array_a, 104200, 123, 1063)] + def test_invalidation_needed(): class options: diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -237,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -32,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -294,7 +294,7 @@ break new_frame = space.createframe(code, w_func.w_func_globals, w_func.closure) - new_frame.fastlocals_w[0] = w_item + new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) return result_w diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -631,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -186,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -207,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -240,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -900,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,21 @@ from __future__ import with_statement +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -37,7 +40,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -73,6 +76,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +100,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +163,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -268,12 +270,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -311,6 +311,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -319,12 +327,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -387,7 +390,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -395,7 +398,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -413,7 +416,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -515,14 +518,14 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() @@ -615,6 +618,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) + return w_a + def array_byteswap__Array(space, self): if mytype.bytes not in [1, 2, 4, 8]: msg = "byteswap not supported for this array" diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -39,6 +39,7 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject +import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject import pypy.module.cpyext.longobject @@ -64,6 +65,7 @@ import pypy.module.cpyext.memoryobject import pypy.module.cpyext.codecs import pypy.module.cpyext.pyfile +import pypy.module.cpyext.pystrtod # now that all rffi_platform.Struct types are registered, configure them api.configure_types() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -562,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/pystrtod.py @@ -0,0 +1,68 @@ +import errno +from pypy.interpreter.error import OperationError +from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.pyobject import PyObject +from pypy.rlib import rdtoa +from pypy.rlib import rfloat +from pypy.rlib import rposix +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi + + + at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +def PyOS_string_to_double(space, s, endptr, w_overflow_exception): + """Convert a string s to a double, raising a Python + exception on failure. The set of accepted strings corresponds to + the set of strings accepted by Python's float() constructor, + except that s must not have leading or trailing whitespace. + The conversion is independent of the current locale. + + If endptr is NULL, convert the whole string. Raise + ValueError and return -1.0 if the string is not a valid + representation of a floating-point number. + + If endptr is not NULL, convert as much of the string as + possible and set *endptr to point to the first unconverted + character. If no initial segment of the string is the valid + representation of a floating-point number, set *endptr to point + to the beginning of the string, raise ValueError, and return + -1.0. + + If s represents a value that is too large to store in a float + (for example, "1e500" is such a string on many platforms) then + if overflow_exception is NULL return Py_HUGE_VAL (with + an appropriate sign) and don't set any exception. Otherwise, + overflow_exception must point to a Python exception object; + raise that exception and return -1.0. In both cases, set + *endptr to point to the first character after the converted value. + + If any other error occurs during the conversion (for example an + out-of-memory error), set the appropriate Python exception and + return -1.0. + """ + user_endptr = True + try: + if not endptr: + endptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + user_endptr = False + result = rdtoa.dg_strtod(s, endptr) + endpos = (rffi.cast(rffi.LONG, endptr[0]) - + rffi.cast(rffi.LONG, s)) + if endpos == 0 or (not user_endptr and not endptr[0][0] == '\0'): + raise OperationError( + space.w_ValueError, + space.wrap('invalid input at position %s' % endpos)) + if rposix.get_errno() == errno.ERANGE: + rposix.set_errno(0) + if w_overflow_exception is None: + if result > 0: + return rfloat.INFINITY + else: + return -rfloat.INFINITY + else: + raise OperationError(w_overflow_exception, + space.wrap('value too large')) + return result + finally: + if not user_endptr: + lltype.free(endptr, flavor='raw') diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/setobject.py @@ -0,0 +1,46 @@ +from pypy.interpreter.error import OperationError +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, + build_type_checkers) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, + borrow_from, make_ref, from_ref) +from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall +from pypy.objspace.std.setobject import W_SetObject, newset +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject + + +PySet_Check, PySet_CheckExact = build_type_checkers("Set") + + + at cpython_api([PyObject], PyObject) +def PySet_New(space, w_iterable): + if w_iterable is None: + return space.call_function(space.w_set) + else: + return space.call_function(space.w_set, w_iterable) + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Add(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'add', w_obj) + return 0 + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Discard(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'discard', w_obj) + return 0 + + + at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +def PySet_GET_SIZE(space, w_s): + return space.int_w(space.len(w_s)) + + at cpython_api([PyObject], Py_ssize_t, error=-1) +def PySet_Size(space, ref): + if not PySet_Check(space, ref): + raise OperationError(space.w_TypeError, + space.wrap("expected set object")) + return PySet_GET_SIZE(space, ref) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -480,39 +480,6 @@ """Create a new Python complex number object from a C Py_complex value.""" raise NotImplementedError - at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) -def PyOS_string_to_double(space, s, endptr, overflow_exception): - """Convert a string s to a double, raising a Python - exception on failure. The set of accepted strings corresponds to - the set of strings accepted by Python's float() constructor, - except that s must not have leading or trailing whitespace. - The conversion is independent of the current locale. - - If endptr is NULL, convert the whole string. Raise - ValueError and return -1.0 if the string is not a valid - representation of a floating-point number. - - If endptr is not NULL, convert as much of the string as - possible and set *endptr to point to the first unconverted - character. If no initial segment of the string is the valid - representation of a floating-point number, set *endptr to point - to the beginning of the string, raise ValueError, and return - -1.0. - - If s represents a value that is too large to store in a float - (for example, "1e500" is such a string on many platforms) then - if overflow_exception is NULL return Py_HUGE_VAL (with - an appropriate sign) and don't set any exception. Otherwise, - overflow_exception must point to a Python exception object; - raise that exception and return -1.0. In both cases, set - *endptr to point to the first character after the converted value. - - If any other error occurs during the conversion (for example an - out-of-memory error), set the appropriate Python exception and - return -1.0. - """ - raise NotImplementedError - @cpython_api([rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_strtod(space, nptr, endptr): """Convert a string to a double. This function behaves like the Standard C diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -0,0 +1,93 @@ +import math + +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype + + +class TestPyOS_string_to_double(BaseApiTest): + + def test_simple_float(self, api): + s = rffi.str2charp('0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == 0.4 + rffi.free_charp(s) + + def test_empty_string(self, api): + s = rffi.str2charp('') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_bad_string(self, api): + s = rffi.str2charp(' 0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_overflow_pos(self, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r > 0 + rffi.free_charp(s) + + def test_overflow_neg(self, api): + s = rffi.str2charp('-1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r < 0 + rffi.free_charp(s) + + def test_overflow_exc(self, space, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, space.w_ValueError) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_endptr_number(self, api): + s = rffi.str2charp('0.4') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_tail(self, api): + s = rffi.str2charp('0.4 foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_no_conversion(self, api): + s = rffi.str2charp('foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == -1.0 + raises(ValueError) + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + api.PyErr_Clear() + rffi.free_charp(s) + lltype.free(endp, flavor='raw') diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_setobject.py @@ -0,0 +1,29 @@ +import py + +from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace + + +class TestTupleObject(BaseApiTest): + def test_setobj(self, space, api): + assert not api.PySet_Check(space.w_None) + assert api.PySet_Add(space.w_None, space.w_None) == -1 + api.PyErr_Clear() + w_set = space.call_function(space.w_set) + space.call_method(w_set, 'update', space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + assert api.PySet_GET_SIZE(w_set) == 4 + raises(TypeError, api.PySet_Size(space.newlist([]))) + api.PyErr_Clear() + + def test_set_add_discard(self, space, api): + w_set = api.PySet_New(None) + assert api.PySet_Size(w_set) == 0 + w_set = api.PySet_New(space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + api.PySet_Add(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 5 + api.PySet_Discard(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 4 diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -367,3 +367,14 @@ data, len(u), lltype.nullptr(rffi.CCHARP.TO)) rffi.free_wcharp(data) + def test_format(self, space, api): + w_format = space.wrap(u'hi %s') + w_args = space.wrap((u'test',)) + w_formated = api.PyUnicode_Format(w_format, w_args) + assert space.unwrap(w_formated) == space.unwrap(space.mod(w_format, w_args)) + + def test_join(self, space, api): + w_sep = space.wrap(u'') + w_seq = space.wrap([u'a', u'b']) + w_joined = api.PyUnicode_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == u'ab' diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,6 +7,7 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) + assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -523,3 +523,11 @@ copies sizeof(Py_UNICODE) * length bytes from source to target""" for i in range(0, length): target[i] = source[i] + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Format(space, w_format, w_args): + return space.mod(w_format, w_args) + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -21,6 +21,10 @@ """Return the referenced object from a weak reference. If the referent is no longer live, returns None. This function returns a borrowed reference. """ + return PyWeakref_GET_OBJECT(space, w_ref) + + at cpython_api([PyObject], PyObject) +def PyWeakref_GET_OBJECT(space, w_ref): return borrow_from(w_ref, space.call_function(w_ref)) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -799,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -829,8 +828,6 @@ return struct.unpack('= 0") + res = 1 + for i in range(1, x + 1): + res *= i + return res diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -373,22 +373,6 @@ hi = v return space.wrap(hi) -def factorial(space, w_x): - """Find x!.""" - if space.isinstance_w(w_x, space.w_float): - fl = space.float_w(w_x) - if math.floor(fl) != fl: - raise OperationError(space.w_ValueError, - space.wrap("float arguments must be integral")) - w_x = space.long(w_x) - x = space.int_w(w_x) - if x < 0: - raise OperationError(space.w_ValueError, space.wrap("x must be >= 0")) - w_res = space.wrap(1) - for i in range(1, x + 1): - w_res = space.mul(w_res, space.wrap(i)) - return w_res - def log1p(space, w_x): """Find log(x + 1).""" return math1(space, rfloat.log1p, w_x) diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -40,6 +40,11 @@ elif b == '/': right = stack.pop() stack.append(stack.pop().descr_div(space, right)) + elif b == '%': + right = stack.pop() + stack.append(stack.pop().descr_mod(space, right)) + elif b == '|': + stack.append(stack.pop().descr_abs(space)) else: print "Unknown opcode: %s" % b raise BogusBytecode() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -5,6 +5,7 @@ from pypy.rlib import jit from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name +import math def dummy1(v): @@ -30,6 +31,12 @@ self.transitions[target] = new = Signature() return new +def pos(v): + return v +def neg(v): + return -v +def absolute(v): + return abs(v) def add(v1, v2): return v1 + v2 def sub(v1, v2): @@ -38,6 +45,10 @@ return v1 * v2 def div(v1, v2): return v1 / v2 +def pow(v1, v2): + return math.pow(v1, v2) +def mod(v1, v2): + return math.fmod(v1, v2) class BaseArray(Wrappable): def __init__(self): @@ -52,6 +63,22 @@ arr.force_if_needed() del self.invalidates[:] + def _unop_impl(function): + signature = Signature() + def impl(self, space): + new_sig = self.signature.transition(signature) + res = Call1( + function, + self, + new_sig) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + + descr_pos = _unop_impl(pos) + descr_neg = _unop_impl(neg) + descr_abs = _unop_impl(absolute) + def _binop_impl(function): signature = Signature() def impl(self, space, w_other): @@ -80,6 +107,8 @@ descr_sub = _binop_impl(sub) descr_mul = _binop_impl(mul) descr_div = _binop_impl(div) + descr_pow = _binop_impl(pow) + descr_mod = _binop_impl(mod) def get_concrete(self): raise NotImplementedError @@ -362,10 +391,15 @@ __getitem__ = interp2app(BaseArray.descr_getitem), __setitem__ = interp2app(BaseArray.descr_setitem), + __pos__ = interp2app(BaseArray.descr_pos), + __neg__ = interp2app(BaseArray.descr_neg), + __abs__ = interp2app(BaseArray.descr_abs), __add__ = interp2app(BaseArray.descr_add), __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), __div__ = interp2app(BaseArray.descr_div), + __pow__ = interp2app(BaseArray.descr_pow), + __mod__ = interp2app(BaseArray.descr_mod), mean = interp2app(BaseArray.descr_mean), ) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -163,6 +163,72 @@ for i in range(5): assert b[i] == i / 5.0 + def test_pow(self): + from numpy import array + a = array(range(5)) + b = a ** a + for i in range(5): + print b[i], i**i + assert b[i] == i**i + + def test_pow_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a ** b + for i in range(5): + assert c[i] == i ** 2 + + def test_pow_constant(self): + from numpy import array + a = array(range(5)) + b = a ** 2 + for i in range(5): + assert b[i] == i ** 2 + + def test_mod(self): + from numpy import array + a = array(range(1,6)) + b = a % a + for i in range(5): + assert b[i] == 0 + + def test_mod_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a % b + for i in range(5): + assert c[i] == i % 2 + + def test_mod_constant(self): + from numpy import array + a = array(range(5)) + b = a % 2 + for i in range(5): + assert b[i] == i % 2 + + def test_pos(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = +a + for i in range(5): + assert b[i] == a[i] + + def test_neg(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = -a + for i in range(5): + assert b[i] == -a[i] + + def test_abs(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = abs(a) + for i in range(5): + assert b[i] == abs(a[i]) + def test_auto_force(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call1, Call2, SingleDimSlice, add, mul) + FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile @@ -13,8 +13,6 @@ cls.space = FakeSpace() def test_add(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, ar, Signature()) @@ -27,8 +25,6 @@ assert result == f(5) def test_floatadd(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, FloatWrapper(4.5), Signature()) @@ -40,11 +36,24 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_already_forecd(self): + def test_neg(self): space = self.space def f(i): ar = SingleDimArray(i) + v = Call1(neg, ar, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, + "setarrayitem_raw": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + + assert result == f(5) + + def test_already_forecd(self): + def f(i): + ar = SingleDimArray(i) v1 = Call2(add, ar, FloatWrapper(4.5), Signature()) v2 = Call2(mul, v1, FloatWrapper(4.5), Signature()) v1.force_if_needed() @@ -95,8 +104,6 @@ self.check_loop_count(3) def test_slice(self): - space = self.space - def f(i): step = 3 ar = SingleDimArray(step*i) @@ -111,8 +118,6 @@ assert result == f(5) def test_slice2(self): - space = self.space - def f(i): step1 = 2 step2 = 3 diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -1484,7 +1484,7 @@ raise OperationError( moduledict.w_NotSupportedError, space.wrap("Variable_TypeByValue(): unhandled data type %s" % - (space.type(w_value).getname(space, '?'),))) + (space.type(w_value).getname(space),))) def newByInputTypeHandler(space, cursor, w_inputTypeHandler, w_value, numElements): w_var = space.call(w_inputTypeHandler, diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py --- a/pypy/module/pyexpat/__init__.py +++ b/pypy/module/pyexpat/__init__.py @@ -2,6 +2,22 @@ from pypy.interpreter.mixedmodule import MixedModule +class ErrorsModule(MixedModule): + "Definition of pyexpat.errors module." + + appleveldefs = { + } + + interpleveldefs = { + } + + def setup_after_space_initialization(self): + from pypy.module.pyexpat import interp_pyexpat + for name in interp_pyexpat.xml_error_list: + self.space.setattr(self, self.space.wrap(name), + interp_pyexpat.ErrorString(self.space, + getattr(interp_pyexpat, name))) + class Module(MixedModule): "Python wrapper for Expat parser." @@ -21,6 +37,10 @@ 'version_info': 'interp_pyexpat.get_expat_version_info(space)', } + submodules = { + 'errors': ErrorsModule, + } + for name in ['XML_PARAM_ENTITY_PARSING_NEVER', 'XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE', 'XML_PARAM_ENTITY_PARSING_ALWAYS']: diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -31,6 +31,48 @@ XML_Content_Ptr = lltype.Ptr(lltype.ForwardReference()) XML_Parser = rffi.COpaquePtr(typedef='XML_Parser') +xml_error_list = [ + "XML_ERROR_NO_MEMORY", + "XML_ERROR_SYNTAX", + "XML_ERROR_NO_ELEMENTS", + "XML_ERROR_INVALID_TOKEN", + "XML_ERROR_UNCLOSED_TOKEN", + "XML_ERROR_PARTIAL_CHAR", + "XML_ERROR_TAG_MISMATCH", + "XML_ERROR_DUPLICATE_ATTRIBUTE", + "XML_ERROR_JUNK_AFTER_DOC_ELEMENT", + "XML_ERROR_PARAM_ENTITY_REF", + "XML_ERROR_UNDEFINED_ENTITY", + "XML_ERROR_RECURSIVE_ENTITY_REF", + "XML_ERROR_ASYNC_ENTITY", + "XML_ERROR_BAD_CHAR_REF", + "XML_ERROR_BINARY_ENTITY_REF", + "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", + "XML_ERROR_MISPLACED_XML_PI", + "XML_ERROR_UNKNOWN_ENCODING", + "XML_ERROR_INCORRECT_ENCODING", + "XML_ERROR_UNCLOSED_CDATA_SECTION", + "XML_ERROR_EXTERNAL_ENTITY_HANDLING", + "XML_ERROR_NOT_STANDALONE", + "XML_ERROR_UNEXPECTED_STATE", + "XML_ERROR_ENTITY_DECLARED_IN_PE", + "XML_ERROR_FEATURE_REQUIRES_XML_DTD", + "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING", + # Added in Expat 1.95.7. + "XML_ERROR_UNBOUND_PREFIX", + # Added in Expat 1.95.8. + "XML_ERROR_UNDECLARING_PREFIX", + "XML_ERROR_INCOMPLETE_PE", + "XML_ERROR_XML_DECL", + "XML_ERROR_TEXT_DECL", + "XML_ERROR_PUBLICID", + "XML_ERROR_SUSPENDED", + "XML_ERROR_NOT_SUSPENDED", + "XML_ERROR_ABORTED", + "XML_ERROR_FINISHED", + "XML_ERROR_SUSPEND_PE", + ] + class CConfigure: _compilation_info_ = eci XML_Content = rffi_platform.Struct('XML_Content', [ @@ -56,6 +98,9 @@ XML_FALSE = rffi_platform.ConstantInteger('XML_FALSE') XML_TRUE = rffi_platform.ConstantInteger('XML_TRUE') + for name in xml_error_list: + locals()[name] = rffi_platform.ConstantInteger(name) + for k, v in rffi_platform.configure(CConfigure).items(): globals()[k] = v @@ -298,7 +343,8 @@ XML_GetErrorCode = expat_external( 'XML_GetErrorCode', [XML_Parser], rffi.INT) XML_ErrorString = expat_external( - 'XML_ErrorString', [rffi.INT], rffi.CCHARP) + 'XML_ErrorString', [rffi.INT], + rffi.CCHARP) XML_GetCurrentLineNumber = expat_external( 'XML_GetCurrentLineNumber', [XML_Parser], rffi.INT) XML_GetErrorLineNumber = XML_GetCurrentLineNumber @@ -691,7 +737,7 @@ elif space.is_true(space.isinstance(w_encoding, space.w_str)): encoding = space.str_w(w_encoding) else: - type_name = space.type(w_encoding).getname(space, '?') + type_name = space.type(w_encoding).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 1 must be string or None,' @@ -711,7 +757,7 @@ space.wrap('namespace_separator must be at most one character,' ' omitted, or None')) else: - type_name = space.type(w_namespace_separator).getname(space, '?') + type_name = space.type(w_namespace_separator).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 2 must be string or None,' diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py --- a/pypy/module/pyexpat/test/test_parser.py +++ b/pypy/module/pyexpat/test/test_parser.py @@ -38,7 +38,7 @@ parser = pyexpat.ParserCreate() raises(pyexpat.ExpatError, "parser.Parse(xml, True)") - def test_encoding(self): + def test_encoding_argument(self): import pyexpat for encoding_arg in (None, 'utf-8', 'iso-8859-1'): for namespace_arg in (None, '{'): @@ -68,7 +68,7 @@ assert p.buffer_size == 150 raises(TypeError, setattr, p, 'buffer_size', sys.maxint + 1) - def test_encoding(self): + def test_encoding_xml(self): # use one of the few encodings built-in in expat xml = "caf\xe9" import pyexpat @@ -120,3 +120,14 @@ return True p.ExternalEntityRefHandler = handler p.Parse(xml) + + def test_errors(self): + import types + import pyexpat + assert isinstance(pyexpat.errors, types.ModuleType) + # check a few random errors + assert pyexpat.errors.XML_ERROR_SYNTAX == 'syntax error' + assert (pyexpat.errors.XML_ERROR_INCORRECT_ENCODING == + 'encoding specified in XML declaration is incorrect') + assert (pyexpat.errors.XML_ERROR_XML_DECL == + 'XML declaration not well-formed') diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -21,8 +21,7 @@ from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes PyFrame._virtualizable2_ = ['last_instr', 'pycode', - 'valuestackdepth', 'valuestack_w[*]', - 'fastlocals_w[*]', + 'valuestackdepth', 'locals_stack_w[*]', 'last_exception', 'lastblock', 'is_being_profiled', @@ -177,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -15,7 +15,7 @@ if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', 'posix', '_socket', '_sre', '_lsprof', '_weakref', - '__pypy__']: + '__pypy__', 'cStringIO']: return True return False diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,21 +9,42 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + def test_interface_residual_call(): space = gettestobjspace(usemodules=['pypyjit']) diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -58,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -46,7 +46,7 @@ guard_no_overflow(descr=) i18 = int_add(i7, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) """) def test_array_intimg(self): @@ -83,7 +83,7 @@ setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) i28 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -66,13 +66,13 @@ ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value", - "getfield_gc", "guard_isnull", + "getfield_gc", "guard_value", "getfield_gc", "guard_nonnull_class"] # LOAD_GLOBAL of OFFSET but in different function partially folded # away # XXX could be improved ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_isnull"] + assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value"] # # two LOAD_GLOBAL of f, the second is folded away ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') @@ -187,7 +187,7 @@ guard_no_overflow(descr=) i18 = force_token() --TICK-- - jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) """) def test_default_and_kw(self): @@ -209,6 +209,26 @@ i16 = force_token() """) + def test_kwargs_empty(self): + def main(x): + def g(**args): + return len(args) + 1 + # + s = 0 + d = {} + i = 0 + while i < x: + s += g(**d) # ID: call + i += 1 + return s + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('call') + ops = log.opnames(loop.ops_by_id('call')) + guards = [ops for ops in ops if ops.startswith('guard')] + assert guards == ["guard_no_overflow"] + def test_kwargs(self): # this is not a very precise test, could be improved def main(x): @@ -216,20 +236,24 @@ return len(args) # s = 0 - d = {} - for i in range(x): + d = {"a": 1} + i = 0 + while i < x: s += g(**d) # ID: call d[str(i)] = i if i % 100 == 99: - d = {} + d = {"a": 1} + i += 1 return s # log = self.run(main, [1000]) - assert log.result == 49500 + assert log.result == 50500 loop, = log.loops_by_id('call') + print loop.ops_by_id('call') ops = log.opnames(loop.ops_by_id('call')) guards = [ops for ops in ops if ops.startswith('guard')] - assert len(guards) <= 5 + print guards + assert len(guards) <= 20 def test_stararg_virtual(self): def main(x): @@ -277,12 +301,12 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) def test_stararg(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py --- a/pypy/module/pypyjit/test_pypy_c/test_intbound.py +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -97,7 +97,7 @@ guard_no_overflow(descr=...) i17 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) """) def test_intbound_sub_lt(self): @@ -149,7 +149,7 @@ guard_no_overflow(descr=...) i19 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) """) def test_intbound_addmul_ge(self): @@ -177,7 +177,7 @@ guard_no_overflow(descr=...) i21 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) """) def test_intbound_eq(self): @@ -209,7 +209,7 @@ guard_no_overflow(descr=...) i16 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) """) def test_intbound_mul(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -167,7 +167,7 @@ guard_false(i16, descr=) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) + setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, 146982464, descr=) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) @@ -179,7 +179,7 @@ i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py @@ -0,0 +1,82 @@ +# unittest for SOME ctypes com function calls. +# Can't resist from implementing some kind of mini-comtypes +# theller ;-) + +import py +import sys +if sys.platform != "win32": + py.test.skip('windows only test') + +import ctypes, new, unittest +from ctypes.wintypes import HRESULT +from _ctypes import COMError + +oleaut32 = ctypes.OleDLL("oleaut32") + +class UnboundMethod(object): + def __init__(self, func, index, name): + self.func = func + self.index = index + self.name = name + self.__doc__ = func.__doc__ + + def __repr__(self): + return "" % (self.index, self.name, id(self)) + + def __get__(self, instance, owner): + if instance is None: + return self + return new.instancemethod(self.func, instance, owner) + +def commethod(index, restype, *argtypes): + """A decorator that generates COM methods. The decorated function + itself is not used except for it's name.""" + def make_commethod(func): + comfunc = ctypes.WINFUNCTYPE(restype, *argtypes)(index, func.__name__) + comfunc.__name__ = func.__name__ + comfunc.__doc__ = func.__doc__ + return UnboundMethod(comfunc, index, func.__name__) + return make_commethod + +class ICreateTypeLib2(ctypes.c_void_p): + + @commethod(1, ctypes.c_long) + def AddRef(self): + pass + + @commethod(2, ctypes.c_long) + def Release(self): + pass + + @commethod(4, HRESULT, ctypes.c_wchar_p) + def SetName(self): + """Set the name of the library.""" + + @commethod(12, HRESULT) + def SaveAllChanges(self): + pass + + +CreateTypeLib2 = oleaut32.CreateTypeLib2 +CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, ctypes.POINTER(ICreateTypeLib2)) + +################################################################ + +def test_basic_comtypes(): + punk = ICreateTypeLib2() + hr = CreateTypeLib2(0, "foobar.tlb", punk) + assert hr == 0 + + assert 2 == punk.AddRef() + assert 3 == punk.AddRef() + assert 4 == punk.AddRef() + + punk.SetName("TypeLib_ByPYPY") + py.test.raises(COMError, lambda: punk.SetName(None)) + + # This would save the typelib to disk. + ## punk.SaveAllChanges() + + assert 3 == punk.Release() + assert 2 == punk.Release() + assert 1 == punk.Release() diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -384,8 +384,9 @@ # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) - stack_items_w = self.crnt_frame.valuestack_w - for i in range(self.crnt_frame.valuestackdepth-1, -1, -1): + f = self.crnt_frame + stack_items_w = f.locals_stack_w + for i in range(f.valuestackdepth-1, f.nlocals-1, -1): w_v = stack_items_w[i] if isinstance(w_v, Constant): if w_v.value is oldvalue: diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py --- a/pypy/objspace/flow/framestate.py +++ b/pypy/objspace/flow/framestate.py @@ -10,7 +10,7 @@ def __init__(self, state): if isinstance(state, PyFrame): # getfastscope() can return real None, for undefined locals - data = state.getfastscope() + state.savevaluestack() + data = state.save_locals_stack() if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -36,11 +36,9 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): - fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) # Nones == undefined locals - frame.restorevaluestack(data[fastlocals:-2]) + frame.restore_locals_stack(data[:-2]) # Nones == undefined locals if data[-2] == Constant(None): assert data[-1] == Constant(None) frame.last_exception = None diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py --- a/pypy/objspace/flow/test/test_framestate.py +++ b/pypy/objspace/flow/test/test_framestate.py @@ -25,7 +25,7 @@ dummy = Constant(None) #dummy.dummy = True arg_list = ([Variable() for i in range(formalargcount)] + - [dummy] * (len(frame.fastlocals_w) - formalargcount)) + [dummy] * (frame.nlocals - formalargcount)) frame.setfastscope(arg_list) return frame @@ -42,7 +42,7 @@ def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1 != fs2 @@ -55,7 +55,7 @@ def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general @@ -63,7 +63,7 @@ def test_restore_frame(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs1.restoreframe(frame) assert fs1 == FrameState(frame) @@ -82,25 +82,26 @@ def test_getoutputargs(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable - # fastlocals_w[-1] -> fastlocals_w[-1] is Constant(None) - assert outputargs == [frame.fastlocals_w[0], Constant(None)] + # locals_w[n-1] -> locals_w[n-1] is Constant(None) + assert outputargs == [frame.locals_stack_w[0], Constant(None)] def test_union_different_constants(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(42) + frame.locals_stack_w[frame.nlocals-1] = Constant(42) fs2 = FrameState(frame) fs3 = fs1.union(fs2) fs3.restoreframe(frame) - assert isinstance(frame.fastlocals_w[-1], Variable) # generalized + assert isinstance(frame.locals_stack_w[frame.nlocals-1], Variable) + # ^^^ generalized def test_union_spectag(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(SpecTag()) + frame.locals_stack_w[frame.nlocals-1] = Constant(SpecTag()) fs2 = FrameState(frame) assert fs1.union(fs2) is None # UnionError diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + w_dict = jit.promote(w_dict) + self = jit.promote(self) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + @jit.elidable + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,91 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,18 +1,20 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS -from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize +from pypy.rlib.debug import mark_dict_non_null + +from pypy.rlib import rerased def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -28,48 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -88,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -140,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -149,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -159,106 +140,90 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + self.switch_to_object_strategy(w_dict) - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_length(self): - return len(self.r_dict_content) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError + def length(self, w_dict): + return 0 -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) + def clear(self, w_dict): + return -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -300,319 +265,255 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = {} +class AbstractTypedStrategy(object): + _mixin_ = True - def impl_setitem(self, w_key, w_value): + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, key, w_value): - self.content[key] = w_value + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] return - elif _is_sane_hash(space, w_key_type): - raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) - def impl_length(self): - return len(self.content) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) - def impl_getitem_str(self, key): - return self.content.get(key, None) + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return ObjectIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + + def setitem_str(self, w_dict, key, w_value): + assert key is not None + self.unerase(w_dict.dstorage)[key] = w_value + + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().impl_fallback_getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) - def impl_delitem(self, w_key): + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) + return space.is_w(space.type(w_obj), space.w_int) - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) -class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): +class IntIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - + return None, None init_signature = Signature(['seq_or_map'], None, 'kwargs') @@ -919,7 +820,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,121 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): @@ -311,6 +311,10 @@ classofinstance=classofinstance, strdict=strdict) + def newset(self): + from pypy.objspace.std.setobject import newset + return W_SetObject(self, newset(self)) + def newslice(self, w_start, w_end, w_step): return W_SliceObject(w_start, w_end, w_step) @@ -318,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) @@ -29,3 +38,33 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -137,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -176,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -195,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -233,8 +234,33 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2: 2, "c": 3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l + def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -267,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -297,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -316,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -366,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} @@ -527,6 +549,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +734,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +749,64 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -759,6 +847,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj @@ -790,6 +882,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +895,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +927,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1012,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1027,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1071,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1083,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1104,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,20 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) + + def test_slot_name_conflict(self): class A(object): @@ -604,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -50,6 +50,10 @@ u = self.space.wrap(set('simsalabim')) assert self.space.eq_w(s,u) + def test_space_newset(self): + s = self.space.newset() + assert self.space.str_w(self.space.repr(s)) == 'set([])' + class AppTestAppSetTest: def test_subtype(self): class subset(set):pass diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: @@ -447,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec @@ -277,12 +292,13 @@ 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -337,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -575,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -592,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -74,7 +74,7 @@ raise KeyError @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) @@ -253,7 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -272,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -151,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) @@ -833,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -845,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,8 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - # it's pure but it does not look like it - @purefunction + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -342,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -352,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -370,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -387,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -428,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -451,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -471,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -487,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -504,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -516,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -527,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -595,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -718,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -816,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -831,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -842,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,23 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + class Cls(self.AddressStack): + def append(self2, addr): + assert addr not in self2.tolist() + self.AddressStack.append(self2, addr) + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +637,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +655,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +698,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +789,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +882,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +922,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,11 +933,11 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded self.remember_young_pointer_from_array2(addr_array, index) else: @@ -943,20 +955,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -980,16 +995,18 @@ # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,9 +1019,7 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return @@ -1016,7 +1031,7 @@ addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True @@ -1026,9 +1041,6 @@ # xxx trying it out for the JIT: a 3-arguments version of the above def remember_young_pointer_from_array3(addr_array, index, newvalue): - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") objhdr = self.header(addr_array) # # a single check for the common case of neither GCFLAG_HAS_CARDS @@ -1044,8 +1056,8 @@ else: # case with cards. # - # If the newly written address does not actually point to the - # nursery, leave now. + # If the newly written address does not actually point to a + # young object, leave now. if not self.appears_to_be_young(newvalue): return # @@ -1056,46 +1068,53 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + \ - (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True assert self.card_page_indices > 0 self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1103,15 +1122,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1119,6 +1159,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1135,20 +1191,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1181,7 +1245,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1189,7 +1253,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1205,11 +1269,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1245,19 +1309,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1296,7 +1371,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1343,11 +1430,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,78 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag + # + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert not res # there might be young ptrs, let ll_arraycopy to find them + + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -884,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/ootypesystem/test/test_oopbc.py b/pypy/rpython/ootypesystem/test/test_oopbc.py --- a/pypy/rpython/ootypesystem/test/test_oopbc.py +++ b/pypy/rpython/ootypesystem/test/test_oopbc.py @@ -81,3 +81,18 @@ res = interpret(f, [1], type_system='ootype') assert res == 2 +def test_quasi_immutable(): + class A(object): + _immutable_fields_ = ['x?'] + def __init__(self): + self.x = 3 + def foo(self): + return self.x + + a = A() + + def f(): + return a.foo() + + res = interpret(f, [], type_system='ootype') + assert res == 3 diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,29 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): @@ -860,6 +883,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -121,6 +121,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -220,6 +223,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -168,7 +168,7 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -83,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -186,7 +186,7 @@ print "\n\nTarget specific help:\n\n" targetspec_dic['print_help'](config) print "\n\nFor detailed descriptions of the command line options see" - print "http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html" + print "http://pypy.readthedocs.org/en/latest/config/commandline.html" sys.exit(0) return targetspec_dic, translateconfig, config, args diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,12 +964,15 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" From noreply at buildbot.pypy.org Tue Jul 5 23:49:02 2011 From: noreply at buildbot.pypy.org (amauryfa) Date: Tue, 5 Jul 2011 23:49:02 +0200 (CEST) Subject: [pypy-commit] pypy default: Extension modules could not be compiled with the mingw32 compiler, Message-ID: <20110705214902.7BDF782934@wyvern.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r45360:867e8ffff7a8 Date: 2011-07-05 10:14 +0200 http://bitbucket.org/pypy/pypy/changeset/867e8ffff7a8/ Log: Extension modules could not be compiled with the mingw32 compiler, because pypy 1.5.0 binary was built with VS2010. diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) From noreply at buildbot.pypy.org Wed Jul 6 11:15:00 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 6 Jul 2011 11:15:00 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: fix the test Message-ID: <20110706091500.F376282934@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45361:ee575cebb8e7 Date: 2011-07-06 11:23 +0200 http://bitbucket.org/pypy/pypy/changeset/ee575cebb8e7/ Log: fix the test diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -305,14 +305,14 @@ ofs, size, _ = self.unpack_arraydescr_size(arraydescr) ofs += descr.fielddescr.offset fieldsize = descr.fielddescr.get_field_size(self.translate_support_code) - ofs = itemindex * size + ofs + fullofs = itemindex * size + ofs # --- start of GC unsafe code (no GC operation!) --- - items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs) + items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), fullofs) for STYPE, UTYPE, itemsize in unroll_basic_sizes: if fieldsize == itemsize: # XXX signedness - items = rffi.cast(rffi.CArrayPtr(STYPE), items) - val = items[0] + item = rffi.cast(rffi.CArrayPtr(STYPE), items) + val = item[0] val = rffi.cast(lltype.Signed, val) # --- end of GC unsafe code --- return val diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -892,9 +892,9 @@ self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), BoxInt(15)], 'void', descr=vdescr) - i = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 3, kdescr) + i = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 3, vdescr) assert i == 15 - self.cpu.bh_setinteriorfield_gc_i(a_box.getref_base(), 3, kdescr, 25) + self.cpu.bh_setinteriorfield_gc_i(a_box.getref_base(), 3, vdescr, 25) r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)], 'int', descr=vdescr) assert r.getint() == 25 From noreply at buildbot.pypy.org Wed Jul 6 14:07:32 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 6 Jul 2011 14:07:32 +0200 (CEST) Subject: [pypy-commit] pypy default: put getting started and FAQ in a more evident position Message-ID: <20110706120732.899C382934@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45362:8146c72e14c8 Date: 2011-07-06 14:15 +0200 http://bitbucket.org/pypy/pypy/changeset/8146c72e14c8/ Log: put getting started and FAQ in a more evident position diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -26,13 +30,6 @@ Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: From noreply at buildbot.pypy.org Wed Jul 6 14:28:41 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 6 Jul 2011 14:28:41 +0200 (CEST) Subject: [pypy-commit] pypy default: kill docs for the no longer available CALL_LIKELY_BUILTIN Message-ID: <20110706122841.37B1382934@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45363:b1ad852a205d Date: 2011-07-06 14:37 +0200 http://bitbucket.org/pypy/pypy/changeset/b1ad852a205d/ Log: kill docs for the no longer available CALL_LIKELY_BUILTIN diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ From noreply at buildbot.pypy.org Wed Jul 6 18:02:12 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 6 Jul 2011 18:02:12 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: add shebang and chmod +x Message-ID: <20110706160212.C2F06820AE@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: extradoc Changeset: r3822:6ae6144e3075 Date: 2011-07-06 17:19 +0200 http://bitbucket.org/pypy/extradoc/changeset/6ae6144e3075/ Log: add shebang and chmod +x diff --git a/talk/iwtc11/benchmarks/image/magnify.py b/talk/iwtc11/benchmarks/image/magnify.py old mode 100644 new mode 100755 diff --git a/talk/iwtc11/benchmarks/image/sobel.py b/talk/iwtc11/benchmarks/image/sobel.py old mode 100644 new mode 100755 --- a/talk/iwtc11/benchmarks/image/sobel.py +++ b/talk/iwtc11/benchmarks/image/sobel.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import errno from noborder import NoBorderImagePadded from math import sqrt From noreply at buildbot.pypy.org Wed Jul 6 18:02:14 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 6 Jul 2011 18:02:14 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: blog post draft about the realtime video processing Message-ID: <20110706160214.1B7F4820AE@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: extradoc Changeset: r3823:bcd81510c9f9 Date: 2011-07-06 18:10 +0200 http://bitbucket.org/pypy/extradoc/changeset/bcd81510c9f9/ Log: blog post draft about the realtime video processing diff --git a/blog/draft/realtime_image_processing.rst b/blog/draft/realtime_image_processing.rst new file mode 100644 --- /dev/null +++ b/blog/draft/realtime_image_processing.rst @@ -0,0 +1,51 @@ +Realtime image processing in Python +=================================== + +Image processing is notoriusly a CPU intensive task. To do it in realtime, +you need to implement your algorithm in a fast language, hence trying to do it +in Python is foolish: Python is clearly not fast enough for this task. Is it? +:-) + +.. image:: sobel.png + +Actually, it turns out that the PyPy JIT compiler produces code which is fast +enough to do realtime video processing using two simple algorithms implemented +by Håkan Ardö. + +XXX: add a very brief description of the algorithms + +You can try by yourself by downloading the appropriate demo: + + - `pypy-image-demo.tar.bz2`_: this archive contains only the source code, + use this is you have PyPy already installed + + - `pypy-image-demo-full.tar.bz2`_: this archive contains both the source + code and prebuilt PyPy binaries for linux 32 and 64 bits + +.. `pypy-image-demo.tar.bz2`: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo.tar.bz2 +.. `pypy-image-demo-full.tar.bz2`: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo-full.tar.bz2 + +To run the demo, you need to have ``mplayer`` installed on your system. The +demo has been tested only on linux, it might (or not) work also on other +systems:: + + $ pypy pypy-image-demo/sobel.py + + $ pypy pypy-image-demo/magnify.py + +By default, the two demos uses an example AVI file. To have more fun, you can +use your webcam by passing the appropriate mplayer parameters to the scripts, +e.g:: + + $ pypy demo/sobel.py tv:// + +To have a feeling on how much PyPy is faster than CPython, try to run the demo +with the latter. On my machine, PyPy runs ``sobel.py`` at ~47.23 fps on +average, while CPython runs it at ~0.08 fps, meaning that PyPy is **590 times +faster**. On ``magnify.py`` the difference is much less evident, ~26.92 fps +vs ~1.78 fps, and the speedup is "only" 15x. + +It must be noted that this is an extreme example of what PyPy can do. In +particular, you cannot expect (yet :-)) PyPy to be fast enough to run an +arbitrary video processing algorithm in real time, but the demo still proves +that PyPy has the potential to get there. diff --git a/talk/ep2011/talk/demo.png b/blog/draft/sobel.png copy from talk/ep2011/talk/demo.png copy to blog/draft/sobel.png From noreply at buildbot.pypy.org Wed Jul 6 18:29:00 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 6 Jul 2011 18:29:00 +0200 (CEST) Subject: [pypy-commit] pypy default: start implementing slicing assembler into ops Message-ID: <20110706162900.1E2E9820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45364:6e65afd1e3a4 Date: 2011-07-06 18:37 +0200 http://bitbucket.org/pypy/pypy/changeset/6e65afd1e3a4/ Log: start implementing slicing assembler into ops diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -337,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -5,6 +5,8 @@ class Op(object): bridge = None + offset = None + asm = None def __init__(self, name, args, res, descr): self.name = name @@ -54,10 +56,53 @@ Op = Op use_mock_model = True + def postprocess(self, loop, backend_dump=None, backend_tp=None, + loop_start=0, dump_start=0): + if backend_dump is not None: + raw_asm = self._asm_disassemble(backend_dump.decode('hex'), + backend_tp, dump_start) + asm = [] + start = 0 + for elem in raw_asm: + if len(elem.split("\t")) != 3: + continue + adr, _, v = elem.split("\t") + if not start: + start = int(adr.strip(":"), 16) + ofs = int(adr.strip(":"), 16) - start + if ofs >= 0: + asm.append((ofs, v.strip("\n"))) + asm_index = 0 + for i, op in enumerate(loop.operations): + end = 0 + j = i + 1 + while end == 0: + if j == len(loop.operations): + end = loop.last_offset + break + if loop.operations[j].offset is None: + j += 1 + else: + end = loop.operations[j].offset + if op.offset is not None: + while asm[asm_index][0] < op.offset: + asm_index += 1 + end_index = asm_index + while asm[end_index][0] < end: + end_index += 1 + op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) + return loop + + def _asm_disassemble(self, d, origin_addr, tp): + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + return list(machine_code_dump(d, tp, origin_addr)) + @classmethod - def parse_from_input(cls, input): - return cls(input, None, {}, 'lltype', None, - nonstrict=True).parse() + def parse_from_input(cls, input, **kwds): + parser = cls(input, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + return parser.postprocess(loop, **kwds) def parse_args(self, opname, argspec): if not argspec.strip(): diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -5,8 +5,8 @@ from pypy.tool.jitlogparser.storage import LoopStorage import py -def parse(input): - return SimpleParser.parse_from_input(input) +def parse(input, **kwds): + return SimpleParser.parse_from_input(input, **kwds) def test_parse(): @@ -179,3 +179,31 @@ ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] assert chunk.bytecode_name == 'StrLiteralSearch' + +def test_parsing_assembler(): + backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" + dump_start = 0x7f3b0b2e63d5 + loop = parse(""" + # Loop 0 : loop with 19 ops + [p0, p1, p2, p3, i4] + debug_merge_point(0, ' #15 COMPARE_OP') + +166: i6 = int_lt(i4, 10000) + guard_true(i6, descr=) [p1, p0, p2, p3, i4] + debug_merge_point(0, ' #27 INPLACE_ADD') + +179: i8 = int_add(i4, 1) + debug_merge_point(0, ' #31 JUMP_ABSOLUTE') + +183: i10 = getfield_raw(40564608, descr=) + +191: i12 = int_sub(i10, 1) + +195: setfield_raw(40564608, i12, descr=) + +203: i14 = int_lt(i12, 0) + guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] + debug_merge_point(0, ' #9 LOAD_FAST') + +213: jump(p0, p1, p2, p3, i8, descr=) + +218: --end of the loop--""", backend_dump=backend_dump, + dump_start=dump_start, + backend_tp='x86_64', + loop_start=0x7f3b0b2e645d) + cmp = loop.operations[1] + assert 'jge' in cmp.asm + assert '0x2710' in cmp.asm + assert 'jmp' in loop.operations[-1].asm From noreply at buildbot.pypy.org Wed Jul 6 18:34:34 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 6 Jul 2011 18:34:34 +0200 (CEST) Subject: [pypy-commit] pypy default: include information that will grossly simplify parsing of logs Message-ID: <20110706163434.A3F60820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45365:71493644c4ef Date: 2011-07-06 18:42 +0200 http://bitbucket.org/pypy/pypy/changeset/71493644c4ef/ Log: include information that will grossly simplify parsing of logs diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -416,10 +416,11 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( + debug_print("Loop #%d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) From noreply at buildbot.pypy.org Wed Jul 6 18:57:20 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 6 Jul 2011 18:57:20 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: (cfbolz, bivab) remove redundant and probably wrong method that is already overwritten a few lines below Message-ID: <20110706165720.7A18B820AE@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45366:18b7a3b0b7df Date: 2011-07-06 19:04 +0200 http://bitbucket.org/pypy/pypy/changeset/18b7a3b0b7df/ Log: (cfbolz, bivab) remove redundant and probably wrong method that is already overwritten a few lines below diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -275,9 +275,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 From noreply at buildbot.pypy.org Wed Jul 6 18:57:21 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 6 Jul 2011 18:57:21 +0200 (CEST) Subject: [pypy-commit] pypy default: (cfbolz, bivab) remove redundant and probably wrong method that is already overwritten a few lines below Message-ID: <20110706165721.B07C6820AE@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r45367:bf5d4d62459c Date: 2011-07-06 19:04 +0200 http://bitbucket.org/pypy/pypy/changeset/bf5d4d62459c/ Log: (cfbolz, bivab) remove redundant and probably wrong method that is already overwritten a few lines below diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -281,9 +281,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 From noreply at buildbot.pypy.org Wed Jul 6 19:25:46 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 6 Jul 2011 19:25:46 +0200 (CEST) Subject: [pypy-commit] pypy default: Make an editable copy of test_sets and change it to not assume that immutable object identity is guarnteed. Message-ID: <20110706172546.AC943820AE@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45368:1fc3e8202f32 Date: 2011-07-06 10:34 -0700 http://bitbucket.org/pypy/pypy/changeset/1fc3e8202f32/ Log: Make an editable copy of test_sets and change it to not assume that immutable object identity is guarnteed. diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) From noreply at buildbot.pypy.org Wed Jul 6 19:34:12 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 6 Jul 2011 19:34:12 +0200 (CEST) Subject: [pypy-commit] pypy default: kill leftover code for debugging Message-ID: <20110706173412.95B76820AE@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45369:eb32d6c7a487 Date: 2011-07-06 19:42 +0200 http://bitbucket.org/pypy/pypy/changeset/eb32d6c7a487/ Log: kill leftover code for debugging diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -256,10 +256,6 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - class Cls(self.AddressStack): - def append(self2, addr): - assert addr not in self2.tolist() - self.AddressStack.append(self2, addr) self.objects_pointing_to_young = self.AddressStack() # # Similar to 'objects_pointing_to_young', but lists objects From noreply at buildbot.pypy.org Wed Jul 6 20:12:37 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 6 Jul 2011 20:12:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Have a proper category for addresses Message-ID: <20110706181237.AC4E6820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45370:d9138743c5d6 Date: 2011-07-06 20:18 +0200 http://bitbucket.org/pypy/pypy/changeset/d9138743c5d6/ Log: Have a proper category for addresses diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -416,11 +416,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) + debug_start("jit-backend-addr") debug_print("Loop #%d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, rawstart + directbootstrappos, rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) From noreply at buildbot.pypy.org Wed Jul 6 20:12:38 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 6 Jul 2011 20:12:38 +0200 (CEST) Subject: [pypy-commit] pypy default: more of correct categories Message-ID: <20110706181238.EDE95820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45371:3f646054700c Date: 2011-07-06 20:19 +0200 http://bitbucket.org/pypy/pypy/changeset/3f646054700c/ Log: more of correct categories diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -481,9 +481,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - + debug_start("jit-backend-addr") debug_print("Bridge out of guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) From noreply at buildbot.pypy.org Wed Jul 6 20:12:40 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 6 Jul 2011 20:12:40 +0200 (CEST) Subject: [pypy-commit] pypy default: add a test log (shelve doesn't support adding :-/) Message-ID: <20110706181240.2D174820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45372:a38f246a47b3 Date: 2011-07-06 20:20 +0200 http://bitbucket.org/pypy/pypy/changeset/a38f246a47b3/ Log: add a test log (shelve doesn't support adding :-/) diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -0,0 +1,36 @@ +[11f210b47027] {jit-backend +[11f210b900f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 +[11f210b949b3] jit-backend-dump} +Loop #0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab189] jit-backend} +[11f210bacbb7] {jit-log-opt-loop +# Loop 0 : loop with 19 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 INPLACE_ADD') ++179: i8 = int_add(i4, 1) +debug_merge_point(0, ' #28 STORE_FAST') +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++183: i10 = getfield_raw(40564608, descr=) ++191: i12 = int_sub(i10, 1) ++195: setfield_raw(40564608, i12, descr=) ++203: i14 = int_lt(i12, 0) +guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++213: jump(p0, p1, p2, p3, i8, descr=) ++218: --end of the loop-- +[11f210c17981] jit-log-opt-loop} +[11f210fb1d21] {jit-backend-counts +0:8965 +1:2 +[11f210fb381b] jit-backend-counts} From noreply at buildbot.pypy.org Wed Jul 6 20:12:41 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 6 Jul 2011 20:12:41 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110706181241.68BD6820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45373:582113929b62 Date: 2011-07-06 20:20 +0200 http://bitbucket.org/pypy/pypy/changeset/582113929b62/ Log: merge diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -256,10 +256,6 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - class Cls(self.AddressStack): - def append(self2, addr): - assert addr not in self2.tolist() - self.AddressStack.append(self2, addr) self.objects_pointing_to_young = self.AddressStack() # # Similar to 'objects_pointing_to_young', but lists objects From noreply at buildbot.pypy.org Wed Jul 6 20:28:34 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:34 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Tentative: remove the clears at the start of every function. Message-ID: <20110706182834.8C115820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45374:31d4b032dd61 Date: 2011-07-04 11:15 +0200 http://bitbucket.org/pypy/pypy/changeset/31d4b032dd61/ Log: Tentative: remove the clears at the start of every function. Needs careful tweaks to ensure that old, invalid pointers are not left behind after a collection. diff --git a/pypy/rpython/lltypesystem/llmemory.py b/pypy/rpython/lltypesystem/llmemory.py --- a/pypy/rpython/lltypesystem/llmemory.py +++ b/pypy/rpython/lltypesystem/llmemory.py @@ -435,8 +435,17 @@ if isinstance(other, fakeaddress): if self == other: return 0 - else: - raise TypeError("cannot subtract fakeaddresses in general") + # <*_subarray at n> - <*_subarray at m> == ItemOffset(n-m) + obj1 = self.ptr._obj + obj2 = other.ptr._obj + if (isinstance(obj1, lltype._subarray) and + isinstance(obj2, lltype._subarray) and + obj1._TYPE == obj2._TYPE and + obj1._parentstructure() == obj2._parentstructure()): + n = obj1._parent_index + m = obj2._parent_index + return ItemOffset(obj1._TYPE.OF, n - m) + raise TypeError("cannot subtract fakeaddresses in general") if other == 0: return self return NotImplemented diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -55,11 +55,25 @@ return top.address[0] def allocate_stack(self): - return llmemory.raw_malloc(self.rootstacksize) + stackbase = llmemory.raw_malloc(self.rootstacksize) + if not stackbase: + raise MemoryError + self.clear_stack(stackbase, stackbase) + return stackbase + + def clear_stack(self, stackbase, stacktop): + """When a function is called, the current stack top is + incremented by as much as needed by this function, but the old + content is left in the stack. This is a speed optimization that + may lead to occasional leaks, because the stack may end up + containing dead pointers. Another drawback is that we need to + clear the stack manually after every minor collection, to + prevent these leftover pointers from pointing to garbage.""" + size = stackbase + self.rootstacksize - stacktop + llmemory.raw_memclear(stacktop, size) def setup_root_walker(self): stackbase = self.allocate_stack() - ll_assert(bool(stackbase), "could not allocate root stack") self.gcdata.root_stack_top = stackbase self.gcdata.root_stack_base = stackbase BaseRootWalker.setup_root_walker(self) @@ -67,9 +81,10 @@ def walk_stack_roots(self, collect_stack_root): gcdata = self.gcdata gc = self.gc - rootstackhook = self.rootstackhook addr = gcdata.root_stack_base end = gcdata.root_stack_top + self.clear_stack(addr, end) + rootstackhook = self.rootstackhook while addr != end: addr += rootstackhook(collect_stack_root, gc, addr) if self.collect_stacks_from_other_threads is not None: @@ -107,8 +122,6 @@ """ if not gcdata._fresh_rootstack: gcdata._fresh_rootstack = self.allocate_stack() - if not gcdata._fresh_rootstack: - raise MemoryError def thread_run(): """Called whenever the current thread (re-)acquired the GIL. @@ -132,6 +145,7 @@ gcdata.thread_stacks.setitem(aid, llmemory.NULL) old = gcdata.root_stack_base if gcdata._fresh_rootstack == llmemory.NULL: + self.clear_stack(old, old) gcdata._fresh_rootstack = old else: llmemory.raw_free(old) @@ -178,9 +192,10 @@ # collect all valid stacks from the dict (the entry # corresponding to the current thread is not valid) gc = self.gc - rootstackhook = self.rootstackhook end = stacktop - sizeofaddr addr = end.address[0] + self.clear_stack(addr, stacktop) + rootstackhook = self.rootstackhook while addr != end: addr += rootstackhook(callback, gc, addr) @@ -294,13 +309,6 @@ c_numcolors = rmodel.inputconst(lltype.Signed, numcolors) llops.genop("direct_call", [gct.incr_stack_ptr, c_numcolors], resulttype=llmemory.Address) - top_addr = llops.genop("direct_call", - [gct.get_stack_top_ptr], - resulttype=llmemory.Address) - c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL) - for k in range(numcolors): - c_k = rmodel.inputconst(lltype.Signed, ~k) - llops.genop("raw_store", [top_addr, c_type, c_k, c_null]) graph.startblock.operations[:0] = llops # # Put at the end of the graph: "decr_stack()" From noreply at buildbot.pypy.org Wed Jul 6 20:28:35 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:35 +0200 (CEST) Subject: [pypy-commit] pypy tealet: A branch in which to integrate tealets with pypy's GC transformer. Message-ID: <20110706182835.D1959820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45375:d329df9bdcef Date: 2011-06-10 10:27 +0200 http://bitbucket.org/pypy/pypy/changeset/d329df9bdcef/ Log: A branch in which to integrate tealets with pypy's GC transformer. From noreply at buildbot.pypy.org Wed Jul 6 20:28:37 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:37 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Add an operation to get the address of the shadowstack base pointer, Message-ID: <20110706182837.20F55820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45376:cf207cd3f785 Date: 2011-06-11 12:33 +0200 http://bitbucket.org/pypy/pypy/changeset/cf207cd3f785/ Log: Add an operation to get the address of the shadowstack base pointer, in addition to the top. diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -489,6 +489,7 @@ # ^^^ returns an address of nursery free pointer, for later modifications 'gc_adr_of_nursery_top' : LLOp(), # ^^^ returns an address of pointer, since it can change at runtime + 'gc_adr_of_root_stack_base': LLOp(), 'gc_adr_of_root_stack_top': LLOp(), # ^^^ returns the address of gcdata.root_stack_top (for shadowstack only) diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -795,10 +795,15 @@ resulttype=llmemory.Address) hop.genop('adr_add', [v_gc_adr, c_ofs], resultvar=op.result) + def gct_gc_adr_of_root_stack_base(self, hop): + self._gc_adr_of_root_stack(hop, 'inst_root_stack_base') + def gct_gc_adr_of_root_stack_top(self, hop): + self._gc_adr_of_root_stack(hop, 'inst_root_stack_top') + + def _gc_adr_of_root_stack(self, hop, llattr): op = hop.spaceop - ofs = llmemory.offsetof(self.c_const_gcdata.concretetype.TO, - 'inst_root_stack_top') + ofs = llmemory.offsetof(self.c_const_gcdata.concretetype.TO, llattr) c_ofs = rmodel.inputconst(lltype.Signed, ofs) v_gcdata_adr = hop.genop('cast_ptr_to_adr', [self.c_const_gcdata], resulttype=llmemory.Address) From noreply at buildbot.pypy.org Wed Jul 6 20:28:38 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:38 +0200 (CEST) Subject: [pypy-commit] pypy tealet: General support for tealet. Message-ID: <20110706182838.5E2B8820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45377:4a707bc5ac9a Date: 2011-06-11 16:15 +0200 http://bitbucket.org/pypy/pypy/changeset/4a707bc5ac9a/ Log: General support for tealet. diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -28,6 +28,11 @@ default=False, cmdline="--stackless", requires=[("translation.type_system", "lltype"), ("translation.gcremovetypeptr", False)]), # XXX? + BoolOption("tealet", "enable stackless features via tealets", + default=False, cmdline="--tealet", + requires=[("translation.type_system", "lltype"), + ("translation.gctransformer", "framework"), + ("translation.thread", False)]), # XXX temporary ChoiceOption("type_system", "Type system to use when RTyping", ["lltype", "ootype"], cmdline=None, default="lltype", requires={ diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -483,6 +483,9 @@ 'gc_dump_rpy_heap' : LLOp(), 'gc_typeids_z' : LLOp(), + 'gc_walk_stack_roots' : LLOp(), # for tealet support + 'gc_set_stack_roots_count': LLOp(), # " + # ------- JIT & GC interaction, only for some GCs ---------- 'gc_adr_of_nursery_free' : LLOp(), diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -491,9 +491,11 @@ annmodel.s_None, minimal_transform = False) - # thread support + # thread & tealet support if translator.config.translation.thread: root_walker.need_thread_support(self, getfn) + if translator.config.translation.tealet: + root_walker.need_tealet_support(self, getfn) self.layoutbuilder.encode_type_shapes_now() @@ -1004,6 +1006,19 @@ hop.genop("direct_call", [self.root_walker.thread_after_fork_ptr] + hop.spaceop.args) + def gct_gc_walk_stack_roots(self, hop): + # only available if tealet support is enabled + assert self.translator.config.translation.tealet + hop.genop("direct_call", [self.root_walker.ll_walk_stack_roots_ptr] + + hop.spaceop.args) + + def gct_gc_set_stack_roots_count(self, hop): + assert self.translator.config.translation.tealet + if hasattr(self.root_walker, 'set_stack_roots_count_ptr'): + hop.genop("direct_call", + [self.root_walker.set_stack_roots_count_ptr] + + hop.spaceop.args) + def gct_gc_get_type_info_group(self, hop): return hop.cast_result(self.c_type_info_group) @@ -1327,6 +1342,22 @@ raise Exception("%s does not support threads" % ( self.__class__.__name__,)) + def need_tealet_support(self, gctransformer, getfn): + # + def ll_walk_stack_roots(fnptr_stack_root): + gcdata = self.gcdata + gcdata._fnptr_stack_root = fnptr_stack_root + self.walk_stack_roots(_ll_collect) + # + def _ll_collect(gc, root): + gcdata = self.gcdata + gcdata._fnptr_stack_root(root) + # + FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.Address], lltype.Void)) + s_FuncPtr = annmodel.SomePtr(FUNCPTR) + self.ll_walk_stack_roots_ptr = getfn(ll_walk_stack_roots, + [s_FuncPtr], annmodel.s_None) + class ShadowStackRootWalker(BaseRootWalker): need_root_stack = True @@ -1387,6 +1418,17 @@ if self.collect_stacks_from_other_threads is not None: self.collect_stacks_from_other_threads(collect_stack_root) + def need_tealet_support(self, gctransformer, getfn): + super(ShadowStackRootWalker, self).need_tealet_support(gctransformer, + getfn) + gcdata = self.gcdata + def set_stack_roots_count(count): + bytes = count * llmemory.sizeof(llmemory.Address) + gcdata.root_stack_top = gcdata.root_stack_base + bytes + self.set_stack_roots_count_ptr = getfn(set_stack_roots_count, + [annmodel.SomeInteger()], + annmodel.s_None) + def need_thread_support(self, gctransformer, getfn): from pypy.module.thread import ll_thread # xxx fish from pypy.rpython.memory.support import AddressDict From noreply at buildbot.pypy.org Wed Jul 6 20:28:39 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:39 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Add asserts. Message-ID: <20110706182839.96C9A820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45378:c1f87a237e06 Date: 2011-06-11 18:15 +0200 http://bitbucket.org/pypy/pypy/changeset/c1f87a237e06/ Log: Add asserts. diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1009,11 +1009,15 @@ def gct_gc_walk_stack_roots(self, hop): # only available if tealet support is enabled assert self.translator.config.translation.tealet + # no gc root in the stack around such an llop! + assert not self.push_roots(hop) hop.genop("direct_call", [self.root_walker.ll_walk_stack_roots_ptr] + hop.spaceop.args) def gct_gc_set_stack_roots_count(self, hop): assert self.translator.config.translation.tealet + # no gc root in the stack around such an llop! + assert not self.push_roots(hop) if hasattr(self.root_walker, 'set_stack_roots_count_ptr'): hop.genop("direct_call", [self.root_walker.set_stack_roots_count_ptr] From noreply at buildbot.pypy.org Wed Jul 6 20:28:40 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:40 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Integrate, and use demo1 as the test. Message-ID: <20110706182840.E4AD0820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45379:bac623c0bd2f Date: 2011-06-12 10:53 +0200 http://bitbucket.org/pypy/pypy/changeset/bac623c0bd2f/ Log: Integrate, and use demo1 as the test. diff --git a/pypy/rlib/_tealet_rffi.py b/pypy/rlib/_tealet_rffi.py new file mode 100644 --- /dev/null +++ b/pypy/rlib/_tealet_rffi.py @@ -0,0 +1,27 @@ +import os +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.translator.tool.cbuild import ExternalCompilationInfo + +eci = ExternalCompilationInfo( + includes=['src/tealet/tealet.h'], + separate_module_sources=['#include "src/tealet/tealet.c"\n'], + pre_include_bits=['#define TEALET_NO_SHARING'], + ) + +def llexternal(funcname, args, restype): + return rffi.llexternal(funcname, args, restype, + compilation_info=eci, + sandboxsafe=True, threadsafe=False, + _nowrapper=True) + +TEALET_P = rffi.COpaquePtr('tealet_t', compilation_info=eci) +TEALET_RUN_P = lltype.Ptr(lltype.FuncType([TEALET_P, rffi.VOIDP], TEALET_P)) +NULL = lltype.nullptr(rffi.VOIDP.TO) +NULL_TEALET = lltype.nullptr(TEALET_P.TO) + +tealet_initialize = llexternal("tealet_initialize", [rffi.VOIDP], TEALET_P) +tealet_finalize = llexternal("tealet_finalize", [TEALET_P], lltype.Void) +tealet_new = llexternal("tealet_new", [TEALET_P, TEALET_RUN_P, + rffi.VOIDP], rffi.INT) +tealet_switch = llexternal("tealet_switch", [TEALET_P], rffi.INT) +tealet_current = llexternal("tealet_current", [TEALET_P], TEALET_P) diff --git a/pypy/rlib/rtealet.py b/pypy/rlib/rtealet.py new file mode 100644 --- /dev/null +++ b/pypy/rlib/rtealet.py @@ -0,0 +1,186 @@ +""" +Interface to 'tealets' for RPython. + +Note that you must translate with the --tealet option if you include +this file in your RPython program. +""" +from pypy.rpython.lltypesystem import lltype, llmemory, rffi +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.annlowlevel import llhelper +from pypy.rlib.debug import ll_assert +from pypy.rlib.objectmodel import we_are_translated + +from pypy.rlib import _tealet_rffi + + +class TealetError(Exception): + pass + + +class Tealet(object): + _ll_saved_stack = None + + def __init__(self, main): + assert isinstance(main, MainTealet) + self.main = main + _new(main, self) + + def switch(self): + _switch(self) + + def run(self): + raise NotImplementedError + + +class MainTealet(Tealet): + def __init__(self): + assert we_are_translated(), "no support for untranslated runs yet" + self.main = self + self.current = self + self.lltealet = _tealet_rffi.tealet_initialize(_tealet_rffi.NULL) + + def __del__(self): + _tealet_rffi.tealet_finalize(self.lltealet) + + +## ------------------------------------------------------------ +## The code below is implementation details. + +## XXX No support for multithreading so far! + +class Switcher(object): + current = None + target = None + count_roots = 0 + lst = None + exception = None +switcher = Switcher() + +def _new(main, starting_tealet): + #if main.ll_stack_base != _getstackbase(): + # raise TealetError("starting a new tealet in the wrong thread") + switcher.current = main.current + switcher.target = starting_tealet + llmain = main.lltealet + llrun = llhelper(_tealet_rffi.TEALET_RUN_P, _run) + llarg = _tealet_rffi.NULL + r = _new_critical(llmain, llrun, llarg) + _check_exception(r) + +def _new_critical(llmain, llrun, llarg): + # critical function: no gc operation, and no gc variable alive! + _save_shadow_stack() + r = _tealet_rffi.tealet_new(llmain, llrun, llarg) + _restore_shadow_stack() + return r +_new_critical._dont_inline_ = True + +def _run(lltealet, llarg): + llop.gc_stack_bottom(lltype.Void) + # end of critical code: no gc operation before here! + tealet = switcher.target + switcher.current = None + switcher.target = None + tealet.lltealet = lltealet + main = tealet.main + main.current = tealet + # + try: + other = tealet.run() + if other is None: + other = main + if not other.lltealet: + raise TealetError("returning to a dead tealet") + if other.main is not main: + raise TealetError("returning to a tealet in a different group") + except Exception, e: + other = main + switcher.exception = e + tealet.lltealet = _tealet_rffi.NULL_TEALET + main.current = other + switcher.target = other + llresult = other.lltealet + return llresult + +def _switch(target): + #if target.main.ll_stack_base != _getstackbase(): + # raise TealetError("cannot switch to a tealet in a different thread") + main = target.main + switcher.current = main.current + switcher.target = target + main.current = target + r = _switch_critical(target.lltealet) + switcher.current = None + switcher.target = None + _check_exception(r) + +def _switch_critical(lltarget): + # critical code: no gc operation! + _save_shadow_stack() + r = _tealet_rffi.tealet_switch(lltarget) + _restore_shadow_stack() + return r +_switch_critical._dont_inline_ = True + +def _check_exception(r): + if rffi.cast(lltype.Signed, r) != 0: + # rare case: tealet.c complains, e.g. out of memory. I think that + # in this case it's not really possible to have 'exception != None'. + # Clean it anyway to avoid it showing up at a random time later. + switcher.exception = None + raise TealetError + e = switcher.exception + if e is not None: + switcher.exception = None + raise e + +# ____________________________________________________________ + +ROOT_WALKER = lltype.Ptr(lltype.FuncType([llmemory.Address], lltype.Void)) + +def _count_roots_walker(root): + switcher.count_roots += 1 + +def _save_root_walker(root): + i = switcher.count_roots + switcher.count_roots = i + 1 + gcobj = llmemory.cast_adr_to_ptr(root.address[0], llmemory.GCREF) + switcher.lst[i] = gcobj + +def _save_shadow_stack(): + switcher.count_roots = 0 + fn = llhelper(ROOT_WALKER, _count_roots_walker) + llop.gc_walk_stack_roots(lltype.Void, fn) + n = switcher.count_roots + # + tealet = switcher.current + ll_assert(tealet._ll_saved_stack is None, "tealet stack mismatch (save)") + tealet._ll_saved_stack = [lltype.nullptr(llmemory.GCREF.TO)] * n + switcher.count_roots = 0 + switcher.lst = tealet._ll_saved_stack + fn = llhelper(ROOT_WALKER, _save_root_walker) + llop.gc_walk_stack_roots(lltype.Void, fn) + ll_assert(n == switcher.count_roots, "tealet stack mismatch (count1)") + switcher.lst = None +_save_shadow_stack._dont_inline_ = True + +def _restore_root_walker(root): + i = switcher.count_roots + switcher.count_roots = i + 1 + gcobj = switcher.lst[i] + root.address[0] = llmemory.cast_ptr_to_adr(gcobj) + +def _restore_shadow_stack(): + tealet = switcher.target + lst = tealet._ll_saved_stack + ll_assert(lst is not None, "tealet stack mismatch (restore)") + tealet._ll_saved_stack = None + switcher.count_roots = 0 + switcher.lst = lst + n = len(lst) + fn = llhelper(ROOT_WALKER, _restore_root_walker) + llop.gc_set_stack_roots_count(lltype.Void, n) + llop.gc_walk_stack_roots(lltype.Void, fn) + ll_assert(n == switcher.count_roots, "tealet stack mismatch (count2)") + switcher.lst = None +_restore_shadow_stack._dont_inline_ = True diff --git a/pypy/rlib/test/demotealet.py b/pypy/rlib/test/demotealet.py new file mode 100644 --- /dev/null +++ b/pypy/rlib/test/demotealet.py @@ -0,0 +1,144 @@ +import sys +from pypy.rlib.rtealet import * +from pypy.rlib.rrandom import Random +from pypy.rlib.nonconst import NonConstant +from pypy.rlib.objectmodel import compute_unique_id +from pypy.rlib.debug import debug_print + +def plan_to_do(rand, steps=10000): + ops = [] + live_tealets = {0: None} + total = 0 + current = 0 + i = 0 + while i < steps or len(live_tealets) > 1: + r = rand.random() + if r < 0.06 and i < steps: + total += 1 + ops.append(("new", total)) + live_tealets[total] = None + current = total + else: + keys = live_tealets.keys() + target = keys[int(rand.random() * len(keys))] + if r < 0.1 and current > 0 and current != target: + ops.append(("finish", target)) + del live_tealets[current] + else: + ops.append(("switch", target)) + current = target + #print i, len(live_tealets), r + i += 1 + assert current == 0 + assert live_tealets.keys() == [0] + ops.append(("done", 0)) + return ops + +# ____________________________________________________________ + +class Replay(object): + def setup(self, lst, tealets): + self.lst = lst + self.index = 0 + self.tealets = tealets + self.mapping = {} + + def next(self): + result = self.lst[self.index] + self.index += 1 + return result + +replay = Replay() + +class X(object): + fixed_pattern = 0 + def __init__(self, value): + if NonConstant(True): + self.fixed_pattern = 0x6789ABCD + self.value = value + +class MyTealet(Tealet): + def run(self): + index = len(replay.tealets) + self.index = index + replay.tealets.append(self) + return_to_index = do(index, X(index)) + replay.tealets[index] = None + assert 0 <= return_to_index < len(replay.tealets) + tt = replay.tealets[return_to_index] + assert tt + return tt + +def do_switch(tt): + replay.stuff = X(1) + tt.switch() +do_switch._dont_inline_ = True + +def do_new(main): + MyTealet(main) +do_new._dont_inline_ = True + +def do(current_tealet_index, x): + main = replay.tealets[0] + assert main + if compute_unique_id(x) in replay.mapping.values(): + for index1, x1 in replay.mapping.items(): + debug_print("mapping[", index1, "] =", x1) + debug_print("current_tealet_index =", current_tealet_index) + debug_print("new object x =", x, "(", compute_unique_id(x), ")") + assert 0 + replay.mapping[current_tealet_index] = compute_unique_id(x) + while True: + #debug_print("in", current_tealet_index, ": x =", x, "(", + # compute_unique_id(x), ")") + assert main.current == replay.tealets[current_tealet_index] + assert replay.mapping[current_tealet_index] == compute_unique_id(x) + assert x.fixed_pattern == 0x6789ABCD + assert x.value == current_tealet_index + operation, target = replay.next() + #debug_print("(", operation, target, ")") + if operation == "switch": + assert 0 <= target < len(replay.tealets) + tt = replay.tealets[target] + assert tt + do_switch(tt) + elif operation == "new": + assert target == len(replay.tealets) + do_new(main) + elif operation == "finish": + assert 0 <= target < len(replay.tealets) + assert target != current_tealet_index + del replay.mapping[current_tealet_index] + return target + elif operation == "done": + assert target == current_tealet_index == 0 + return -42 + else: + assert 0 +do._dont_inline_ = True + +def run_demo(lst): + main = MainTealet() + replay.setup(lst, [main]) + res = do(0, X(0)) + assert res == -42 + for tt in replay.tealets[1:]: + assert not tt + assert replay.index == len(replay.lst) + +# ____________________________________________________________ + +def entry_point(argv): + if len(argv) > 1: + seed = int(argv[1]) + else: + seed = 0 + print 'Building plan with seed=%d...' % seed + lst = plan_to_do(Random(seed)) + print 'Running...' + run_demo(lst) + print 'OK' + return 0 + +def target(*args): + return entry_point, None diff --git a/pypy/rlib/test/test_rtealet.py b/pypy/rlib/test/test_rtealet.py new file mode 100644 --- /dev/null +++ b/pypy/rlib/test/test_rtealet.py @@ -0,0 +1,30 @@ +from pypy.translator.c.test.test_standalone import StandaloneTests + + +class BaseTestTealet(StandaloneTests): + + def setup_class(cls): + from pypy.config.pypyoption import get_pypy_config + config = get_pypy_config(translating=True) + config.translation.gc = "minimark" + config.translation.gcrootfinder = cls.gcrootfinder + config.translation.tealet = True + cls.config = config + + def test_demo1(self): + from pypy.rlib.test.demotealet import entry_point + t, cbuilder = self.compile(entry_point) + + expected_data = "Running...\nOK\n" + for i in range(20): + data = cbuilder.cmdexec('%d' % i, env={}) + assert data.endswith(expected_data) + data = cbuilder.cmdexec('%d' % i, env={'PYPY_GC_NURSERY': '10k'}) + assert data.endswith(expected_data) + + +class TestTealetShadowstack(BaseTestTealet): + gcrootfinder = "shadowstack" + +class TestTealetAsmgcc(BaseTestTealet): + gcrootfinder = "asmgcc" diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1428,7 +1428,12 @@ gcdata = self.gcdata def set_stack_roots_count(count): bytes = count * llmemory.sizeof(llmemory.Address) - gcdata.root_stack_top = gcdata.root_stack_base + bytes + p = gcdata.root_stack_base + end = gcdata.root_stack_top = p + bytes + INVALID_NONNULL_ADDRESS = llmemory.cast_int_to_adr(8) + while p != end: + p.address[0] = INVALID_NONNULL_ADDRESS + p += llmemory.sizeof(llmemory.Address) self.set_stack_roots_count_ptr = getfn(set_stack_roots_count, [annmodel.SomeInteger()], annmodel.s_None) diff --git a/pypy/translator/c/src/tealet/README b/pypy/translator/c/src/tealet/README new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/README @@ -0,0 +1,9 @@ +The C sources for tealets are a direct copy of (one of) the following +places. In case they need updating, please consider changing them there +instead. + + From Armin Rigo's user repository: + http://bitbucket.org/arigo/arigo (directory hack/pypy-hack/tealet) + + From Kristj�n Valur J�nsson's repository: + http://bitbucket.org/krisvale/public diff --git a/pypy/translator/c/src/tealet/slp_platformselect.h b/pypy/translator/c/src/tealet/slp_platformselect.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/slp_platformselect.h @@ -0,0 +1,12 @@ + +#if defined(_M_IX86) +#include "src/tealet/switch_x86_msvc.h" /* MS Visual Studio on X86 */ +#elif defined(_M_X64) +#include "src/tealet/switch_x64_msvc.h" /* MS Visual Studio on X64 */ +#elif defined(__GNUC__) && defined(__amd64__) +#include "src/tealet/switch_x86_64_gcc.h" /* gcc on amd64 */ +#elif defined(__GNUC__) && defined(__i386__) +#include "src/tealet/switch_x86_gcc.h" /* gcc on X86 */ +#else +#error "Unsupported platform!" +#endif diff --git a/pypy/translator/c/src/tealet/switch_x64_msvc.asm b/pypy/translator/c/src/tealet/switch_x64_msvc.asm new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/switch_x64_msvc.asm @@ -0,0 +1,103 @@ +; +; stack switching code for MASM on x64 +; Kristjan Valur Jonsson, apr 2011 +; + +include macamd64.inc + +pop_reg MACRO reg + pop reg +ENDM + +load_xmm128 macro Reg, Offset + movdqa Reg, Offset[rsp] +endm + +.code + +;arguments save_state, restore_state, extra are passed in rcx, rdx, r8 respectively +;slp_switch PROC FRAME +NESTED_ENTRY slp_switch, _TEXT$00 + ; save all registers that the x64 ABI specifies as non-volatile. + ; This includes some mmx registers. May not always be necessary, + ; unless our application is doing 3D, but better safe than sorry. + alloc_stack 168; 10 * 16 bytes, plus 8 bytes to make stack 16 byte aligned + save_xmm128 xmm15, 144 + save_xmm128 xmm14, 128 + save_xmm128 xmm13, 112 + save_xmm128 xmm12, 96 + save_xmm128 xmm11, 80 + save_xmm128 xmm10, 64 + save_xmm128 xmm9, 48 + save_xmm128 xmm8, 32 + save_xmm128 xmm7, 16 + save_xmm128 xmm6, 0 + + push_reg r15 + push_reg r14 + push_reg r13 + push_reg r12 + + push_reg rbp + push_reg rbx + push_reg rdi + push_reg rsi + + sub rsp, 20h ;allocate shadow stack space for the arguments (must be multiple of 16) + .allocstack 20h +.endprolog + + ;save argments in nonvolatile registers + mov r12, rcx ;save_state + mov r13, rdx + mov r14, r8 + + ; load stack base that we are saving minus the callee argument + ; shadow stack. We don't want that clobbered + lea rcx, [rsp+20h] + mov rdx, r14 + call r12 ;pass stackpointer, return new stack pointer in eax + + ; an odd value means that we don't restore, could be + ; an error (e.g. -1) or indication that we only want + ; to save state (1). return that value to the caller. + test rax, 1 + jnz exit + + ;actual stack switch (and re-allocating the shadow stack): + lea rsp, [rax-20h] + + mov rcx, rax ;pass new stack pointer + mov rdx, r14 + call r13 + ;return the rax +EXIT: + + add rsp, 20h + pop_reg rsi + pop_reg rdi + pop_reg rbx + pop_reg rbp + + pop_reg r12 + pop_reg r13 + pop_reg r14 + pop_reg r15 + + load_xmm128 xmm15, 144 + load_xmm128 xmm14, 128 + load_xmm128 xmm13, 112 + load_xmm128 xmm12, 96 + load_xmm128 xmm11, 80 + load_xmm128 xmm10, 64 + load_xmm128 xmm9, 48 + load_xmm128 xmm8, 32 + load_xmm128 xmm7, 16 + load_xmm128 xmm6, 0 + add rsp, 168 + ret + +NESTED_END slp_switch, _TEXT$00 +;slp_switch ENDP + +END \ No newline at end of file diff --git a/pypy/translator/c/src/tealet/switch_x64_msvc.h b/pypy/translator/c/src/tealet/switch_x64_msvc.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/switch_x64_msvc.h @@ -0,0 +1,7 @@ +/* The actual stack saving function, which just stores the stack, + * this declared in an .asm file + */ +extern void *slp_switch(void *(*save_state)(void*, void*), + void *(*restore_state)(void*, void*), + void *extra); + diff --git a/pypy/translator/c/src/tealet/switch_x86_64_gcc.h b/pypy/translator/c/src/tealet/switch_x86_64_gcc.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/switch_x86_64_gcc.h @@ -0,0 +1,55 @@ + +static void *slp_switch(void *(*save_state)(void*, void*), + void *(*restore_state)(void*, void*), + void *extra) +{ + void *result, *garbage1, *garbage2; + __asm__ volatile ( + "pushq %%rbp\n" + "pushq %%rbx\n" /* push the registers specified as caller-save */ + "pushq %%r12\n" + "pushq %%r13\n" + "pushq %%r14\n" + "pushq %%r15\n" + + "movq %%rax, %%r12\n" /* save 'restore_state' for later */ + "movq %%rsi, %%r13\n" /* save 'extra' for later */ + + /* arg 2: extra (already in rsi) */ + "movq %%rsp, %%rdi\n" /* arg 1: current (old) stack pointer */ + "call *%%rcx\n" /* call save_state() */ + + "testb $1, %%al\n" /* skip the rest if the return value is odd */ + "jnz 0f\n" + + "movq %%rax, %%rsp\n" /* change the stack pointer */ + + /* From now on, the stack pointer is modified, but the content of the + stack is not restored yet. It contains only garbage here. */ + + "movq %%r13, %%rsi\n" /* arg 2: extra */ + "movq %%rax, %%rdi\n" /* arg 1: current (new) stack pointer */ + "call *%%r12\n" /* call restore_state() */ + + /* The stack's content is now restored. */ + + "0:\n" + "popq %%r15\n" + "popq %%r14\n" + "popq %%r13\n" + "popq %%r12\n" + "popq %%rbx\n" + "popq %%rbp\n" + + : "=a"(result), /* output variables */ + "=c"(garbage1), + "=S"(garbage2) + : "a"(restore_state), /* input variables */ + "c"(save_state), + "S"(extra) + : "memory", "rdx", "rdi", "r8", "r9", "r10", "r11", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10","xmm11","xmm12","xmm13","xmm14","xmm15" + ); + return result; +} diff --git a/pypy/translator/c/src/tealet/switch_x86_gcc.h b/pypy/translator/c/src/tealet/switch_x86_gcc.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/switch_x86_gcc.h @@ -0,0 +1,56 @@ + +static void *slp_switch(void *(*save_state)(void*, void*), + void *(*restore_state)(void*, void*), + void *extra) +{ + void *result, *garbage1, *garbage2; + __asm__ volatile ( + "pushl %%ebp\n" + "pushl %%ebx\n" /* push some registers that may contain */ + "pushl %%esi\n" /* some value that is meant to be saved */ + "pushl %%edi\n" + + "movl %%eax, %%esi\n" /* save 'restore_state' for later */ + "movl %%edx, %%edi\n" /* save 'extra' for later */ + + "movl %%esp, %%eax\n" + + "pushl %%edx\n" /* arg 2: extra */ + "pushl %%eax\n" /* arg 1: current (old) stack pointer */ + "call *%%ecx\n" /* call save_state() */ + + "testl $1, %%eax\n" /* skip the rest if the return value is odd */ + "jnz 0f\n" + + "movl %%eax, %%esp\n" /* change the stack pointer */ + + /* From now on, the stack pointer is modified, but the content of the + stack is not restored yet. It contains only garbage here. */ + + "pushl %%edi\n" /* arg 2: extra */ + "pushl %%eax\n" /* arg 1: current (new) stack pointer */ + "call *%%esi\n" /* call restore_state() */ + + /* The stack's content is now restored. */ + + "0:\n" + "addl $8, %%esp\n" + "popl %%edi\n" + "popl %%esi\n" + "popl %%ebx\n" + "popl %%ebp\n" + + : "=a"(result), /* output variables */ + "=c"(garbage1), + "=d"(garbage2) + : "a"(restore_state), /* input variables */ + "c"(save_state), + "d"(extra) + : "memory" + ); + /* Note: we should also list all fp/xmm registers, but is there a way + to list only the ones used by the current compilation target? + For now we will just ignore the issue and hope (reasonably) that + this function is never inlined all the way into 3rd-party user code. */ + return result; +} diff --git a/pypy/translator/c/src/tealet/switch_x86_msvc.asm b/pypy/translator/c/src/tealet/switch_x86_msvc.asm new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/switch_x86_msvc.asm @@ -0,0 +1,44 @@ + +.386 +.model flat, c + +.code + +slp_switch_raw PROC save_state:DWORD, restore_state:DWORD, extra:DWORD + + ;save registers. EAX ECX and EDX are available for function use and thus + ;do not have to be stored. + push ebx + push esi + push edi + push ebp + + mov esi, restore_state ; /* save 'restore_state' for later */ + mov edi, extra ; /* save 'extra' for later */ + + mov eax, esp + + push edi ; /* arg 2: extra */ + push eax ; /* arg 1: current (old) stack pointer */ + mov ecx, save_state + call ecx ; /* call save_state() */ + + test eax, 1; /* skip the restore if the return value is odd */ + jnz exit + + mov esp, eax; /* change the stack pointer */ + + push edi ; /* arg 2: extra */ + push eax ; /* arg 1: current (new) stack pointer */ + call esi ; /* call restore_state() */ + +exit: + add esp, 8 + pop ebp + pop edi + pop esi + pop ebx + ret +slp_switch_raw ENDP + +end \ No newline at end of file diff --git a/pypy/translator/c/src/tealet/switch_x86_msvc.h b/pypy/translator/c/src/tealet/switch_x86_msvc.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/switch_x86_msvc.h @@ -0,0 +1,26 @@ +/* The actual stack saving function, which just stores the stack, + * this declared in an .asm file + */ +extern void *slp_switch_raw(void *(*save_state)(void*, void*), + void *(*restore_state)(void*, void*), + void *extra); + +#define WIN32_LEAN_AND_MEAN +#include + +/* Store any other runtime information on the local stack */ +#pragma optimize("", off) /* so that autos are stored on the stack */ +#pragma warning(disable:4733) /* disable warning about modifying FS[0] */ + +static void *slp_switch(void *(*save_state)(void*, void*), + void *(*restore_state)(void*, void*), + void *extra) +{ + /* store the structured exception state for this stack */ + DWORD seh_state = __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + void * result = slp_switch_raw(save_state, restore_state, extra); + __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), seh_state); + return result; +} +#pragma warning(default:4733) /* disable warning about modifying FS[0] */ +#pragma optimize("", on) diff --git a/pypy/translator/c/src/tealet/tealet.c b/pypy/translator/c/src/tealet/tealet.c new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/tealet.c @@ -0,0 +1,600 @@ +/********** A minimal coroutine package for C ********** + * By Armin Rigo + * Documentation: see the source code of the greenlet package from + * + * http://codespeak.net/svn/greenlet/trunk/c/_greenlet.c + */ + +#include "src/tealet/tealet.h" + +#include +#include +#include + +/************************************************************ + * platform specific code + */ + +/* The default stack direction is downwards, 0, but platforms + * can redefine it to upwards growing, 1. + */ +#define STACK_DIRECTION 0 + +#include "src/tealet/slp_platformselect.h" + +#if STACK_DIRECTION == 0 +#define STACK_STOP_MAIN ((char*) -1) /* for stack_stop */ +#define STACK_LE(a, b) ((a) <= (b)) /* to compare stack position */ +#define STACK_SUB(a, b) ((a) - (b)) /* to subtract stack pointers */ +#else +#define STACK_STOP_MAIN ((char*) 1) /* for stack_stop */ +#define STACK_LE(a, b) ((b) <= (a)) /* to compare stack position */ +#define STACK_SUB(a, b) ((b) - (a)) /* to subtract stack pointers */ +#endif + +/************************************************************/ + +/* #define DEBUG_DUMP */ + +#ifdef DEBUG_DUMP +#include +static int counter = 0; +#endif + + +/* the actual tealet structure as used internally */ +typedef struct tealet_sub_s { + tealet_t base; + + /* The stack claimed by this tealet. Since we allow for architectures + * where stack can be allocated downwards in memory (most common) or + * upwards (less common), we use the terms near or far to discern this. + * The main tealet will have stack_stop set to the end of memory. + * stack_start is zero for a running tealet, otherwise it contains + * the address where the stack_copy should go. + * In addition, stack_stop is set to NULL value to indicate + * that a tealet is exiting. + */ + char *stack_start; /* the "near" end of the stack */ + char *stack_stop; /* the "far" end of the stack. */ + + /* if the tealet is inactive, the following contain its saved + * stack, otherwise, both are zero. + * stack_saved can also be -1, meaning that saving the stack + * failed and the tealet is invalid. + */ + char *stack_copy; /* saved data */ + size_t stack_saved; /* the amount saved */ + + /* A linked list of partially or completely unsaved tealets linked + * from the currently executing tealet. Each one is has it's + * stack_stop higher to the previous one. This is used + * to enable just-in-time saving of stacks. + */ + struct tealet_sub_s *stack_prev; +#ifdef DEBUG_DUMP + int counter; +#endif +} tealet_sub_t; + +/* The main tealet has additional fields for housekeeping */ +typedef struct { + tealet_sub_t base; + tealet_sub_t *g_current; + tealet_sub_t *g_target; /* Temporary store when switching */ + tealet_run_t g_run; /* run function and arguments */ + void *g_run_arg; + tealet_alloc_t g_alloc; /* the allocation context used */ +} tealet_main_t; + +#define TEALET_IS_MAIN(t) (((tealet_sub_t *)(t))->stack_stop == STACK_STOP_MAIN) +#define TEALET_MAIN(t) ((tealet_main_t *)((t)->base.main)) + +/************************************************************/ + +int (*_tealet_switchstack)(tealet_main_t*); +int (*_tealet_initialstub)(tealet_main_t*, long*); + +/************************************************************ + * helpers to call the malloc functions provided by the user + */ +static void *g_malloc(tealet_main_t *g_main, size_t size) +{ + return g_main->g_alloc.malloc_p(size, g_main->g_alloc.context); +} +static void *g_realloc(tealet_main_t *g_main, void *ptr, size_t size) +{ + return g_main->g_alloc.realloc_p(ptr, size, g_main->g_alloc.context); +} +static void g_free(tealet_main_t *g_main, void *ptr) +{ + g_main->g_alloc.free_p(ptr, g_main->g_alloc.context); +} + +/************************************************************* + * Helpers to allocate, grow and duplicate stacks, using reference + * counts. This allows us to duplicate tealets (stubs primarily) + * cheaply and without all sorts of special casing. + */ +static void* stack_grow(tealet_main_t *main, void *old, size_t oldsize, size_t newsize) +{ +#ifndef TEALET_NO_SHARING + char *result; + newsize += sizeof(size_t); + assert(oldsize < newsize); + if (old == NULL) { + result = (char*)g_malloc(main, newsize); + } else { + char *realp = (char*)old - sizeof(size_t); + size_t cnt = *(size_t*)realp; + if (cnt == 1) { + result = (char*)g_realloc(main, (void*)realp, newsize); + } else { + /* we can't grow a shared stack, un-share it */ + result = (char*)g_malloc(main, newsize); + if (result != NULL) { + --(*(size_t*)realp); + memcpy((void*)result, (void*)realp, oldsize + sizeof(size_t)); + } + } + } + if (result == NULL) + return NULL; + *(size_t*)result = 1; + return (void*)(result + sizeof(size_t)); +#else + return g_realloc(main, old, newsize); +#endif +} + +static void stack_free(tealet_main_t *main, void *ptr) +{ +#ifndef TEALET_NO_SHARING + if (ptr != NULL) { + char *realp = (char*)ptr - sizeof(size_t); + if (--(*(size_t*)realp) == 0) + g_free(main, (void*)realp); + } +#else + g_free(main, ptr); +#endif +} + +#ifndef TEALET_NO_SHARING +static void* stack_dup(void *ptr) +{ + if (ptr != NULL) { + /* just increment the reference count */ + char *realp = (char*)ptr - sizeof(size_t); + ++(*(size_t*)realp); + } + return ptr; +} +#endif + +/***************************************************************/ + +static int g_save(tealet_sub_t* g, char* stop, int fail_ok) +{ + /* Save more of g's stack into the heap -- at least up to 'stop' + + In the picture below, the C stack is on the left, growing down, + and the C heap on the right. The area marked with xxx is the logical + stack of the tealet 'g'. It can be half in the C stack (its older + part), and half in the heap (its newer part). + + g->stack_stop |________| + |xxxxxxxx| + |xxx __ stop ......... + |xxxxxxxx| ==> : : + |________| :_______: + | | |xxxxxxx| + | | |xxxxxxx| + g->stack_start | | |_______| g->stack_copy + + */ + ptrdiff_t sz1 = g->stack_saved; + ptrdiff_t sz2 = STACK_SUB(stop, g->stack_start); + assert(g->stack_stop != NULL); /* it is not exiting */ + assert(STACK_LE(stop, g->stack_stop)); + + if (sz2 > sz1) { + tealet_main_t *g_main = (tealet_main_t *)g->base.main; + char* c = stack_grow(g_main, g->stack_copy, sz1, sz2); + if (c == NULL) { + if (fail_ok) + return -1; + /* we cannot signal a failure, either because this is an exit + * switch, or the user is doing an emergency switch, ignoring + * failures. + * We must therefore mark this tealet's saved state as + * invalid, so that we can't switch to it again. + */ + g->stack_saved = (size_t)-1; /* invalid saved stack */ + return 0; + } +#if STACK_DIRECTION == 0 + memcpy(c+sz1, g->stack_start+sz1, sz2-sz1); +#else + memmove(c+sz2-sz1, c, sz1); + memcpy(c, stop, sz2-sz1); +#endif + g->stack_copy = c; + g->stack_saved = sz2; + } + return 0; +} + +/* main->g_target contains the tealet we are switching to: + * target->stack_stop is the limit to which we must save the old stack + * target->stack_start can be NULL, indicating that the target stack + * needs not be restored. + */ +static void *g_save_state(void *old_stack_pointer, void *main) +{ + /* must free all the C stack up to target->stack_stop */ + tealet_main_t *g_main = (tealet_main_t *)main; + tealet_sub_t *g_target = g_main->g_target; + tealet_sub_t *g_current = g_main->g_current; + char* target_stop = g_target->stack_stop; + int exiting; + assert(target_stop != NULL); + assert(g_current != g_target); + assert(g_current->stack_saved == 0); + assert(g_current->stack_start == NULL); + + exiting = g_current->stack_stop == NULL; + if (exiting) { + /* tealet is exiting. We don't save its stack, and delete it, but + * may need to save other stacks on demand + */ + tealet_sub_t *g; + assert(!TEALET_IS_MAIN(g_current)); + g = g_current; + g_current = g_current->stack_prev; + g_free(g_main, g); + } else + g_current->stack_start = old_stack_pointer; + + /* save and unlink tealets that are completely within + * the area to clear. + */ + while (g_current != NULL && STACK_LE(g_current->stack_stop, target_stop)) { + tealet_sub_t *prev = g_current->stack_prev; + if (g_current != g_target) { /* but don't save the target */ + assert(!TEALET_IS_MAIN(g_current)); /* never completely save main */ + if (g_save(g_current, g_current->stack_stop, exiting) == -1) { + /* make sure that stack chain is intact if we have error */ + if (g_current != g_main->g_current) + g_main->g_current->stack_prev = g_current; + return (void *)-1; /* error */ + } + } + g_current->stack_prev = NULL; + g_current = prev; + } + + /* save a partial stack */ + if (g_current != NULL && g_save(g_current, target_stop, exiting) == -1) + return (void *) -1; /* error */ + + assert(g_target->stack_prev == NULL); + g_target->stack_prev = g_current; + + if (g_target->stack_start == NULL) + return (void *)1; /* don't restore */ + + return g_target->stack_start; +} + +static void *g_restore_state(void *new_stack_pointer, void *main) +{ + tealet_main_t *g_main = (tealet_main_t *)main; + tealet_sub_t *g = g_main->g_target; + + /* Restore the heap copy back into the C stack */ + assert(g->stack_start != NULL); + if (g->stack_saved != 0) { + size_t stack_saved = g->stack_saved; +#if STACK_DIRECTION == 0 + memcpy(g->stack_start, g->stack_copy, stack_saved); +#else + memcpy(g->stack_start - stack_saved, g->stack_copy, stack_saved); +#endif + stack_free(g_main, g->stack_copy); + g->stack_copy = NULL; + g->stack_saved = 0; + } + g->stack_start = NULL; /* mark as running */ + return NULL; +} + +static int g_switchstack(tealet_main_t *g_main) +{ + /* note: we can't pass g_target simply as an argument here, because + of the mix between different call stacks: after slp_switch() it + might end up with a different value. But g_main is safe, because + it should have always the same value before and after the switch. */ + void *res; + assert(g_main->g_target); + assert(g_main->g_target != g_main->g_current); + /* if the target saved stack is invalid (due to a failure to save it + * during the exit of another tealet), we detect this here and + * report an error + * return value is: + * 0 = successful switch + * 1 = successful save only + * -1 = error, couldn't save state + * -2 = error, target tealet corrupt + */ + if (g_main->g_target->stack_saved == (size_t)-1) + return -2; + res = slp_switch(g_save_state, g_restore_state, g_main); + if ((ptrdiff_t)res >= 0) + g_main->g_current = g_main->g_target; + g_main->g_target = NULL; + return (ptrdiff_t)res; +} + +/* This function gets called for two cases: In the first, + * case, we are initializing and switching to a new stub, + * in order to immediately start a new tealet's execution. + * In this case, g_main->run will be non-zero. + * The other case is when we are just saving the current + * execution state in the stub, in order to reawaken it + * later. In this case, g_main->run is zero. + */ +static int g_initialstub(tealet_main_t *g_main, long *dummymarker) +{ + int result; + tealet_sub_t *g_current = g_main->g_current; + tealet_sub_t *g_target = g_main->g_target; + assert(g_target->stack_start == NULL); + g_target->stack_stop = (char *)dummymarker; + + if (g_main->g_run == NULL) { + /* if are saving the execution state in the stub, we set + * things up so that the stub is running, and then switch back + * from it to our caller. + */ + g_target->stack_prev = g_main->g_current; + g_main->g_target = g_current; + g_main->g_current = g_target; + } + /* The following call can return multiple times. The first + * time it returns with 1, when the stub is saved. + * Then it can return with 0 when there is a switch into the + * stub. + */ + result = _tealet_switchstack(g_main); + if (result < 0) { + /* couldn't allocate stack */ + g_main->g_current = g_current; + return result; + } + + if (g_main->g_run) { + /* this is the invocation of a new tealet */ + tealet_sub_t *g, *g_target; + tealet_run_t run = g_main->g_run; + void *run_arg = g_main->g_run_arg; + g_main->g_run = NULL; + g_main->g_run_arg = NULL; + g = g_main->g_current; + assert(g->stack_start == NULL); /* running */ +#ifdef DEBUG_DUMP + printf("starting %p\n", g); +#endif + + g_target = (tealet_sub_t *)(run((tealet_t *)g, run_arg)); + if (!g_target) + g_target = &g_main->base; + assert(g_target != g); + assert(TEALET_MAIN(g_target) == g_main); + assert(g_main->g_current == g); +#ifdef DEBUG_DUMP + printf("ending %p -> %p\n", g, g_target); +#endif + assert(g->stack_copy == NULL); + g->stack_stop = NULL; /* dying */ + g_main->g_target = g_target; + _tealet_switchstack(g_main); + assert(!"This point should not be reached"); + } + return 0; +} + +static tealet_sub_t *tealet_alloc(tealet_main_t *g_main, tealet_alloc_t *alloc) +{ + size_t size; + tealet_sub_t *g; + size = g_main == NULL ? sizeof(tealet_main_t) : sizeof(tealet_sub_t); + g = alloc->malloc_p(size, alloc->context); + if (g == NULL) + return NULL; + if (g_main == NULL) + g_main = (tealet_main_t *)g; + g->base.main = (tealet_t *)g_main; + g->base.data = NULL; + g->stack_start = NULL; + g->stack_stop = NULL; + g->stack_copy = NULL; + g->stack_saved = 0; + g->stack_prev = NULL; +#ifdef DEBUG_DUMP + g->counter = counter++; +#endif + return g; +} + +static int tealet_new_int(tealet_t *main, tealet_run_t run, void *run_arg, tealet_sub_t **res) +{ + long dummymarker; + int result; + tealet_main_t *g_main = (tealet_main_t *)main->main; + assert(TEALET_IS_MAIN(g_main)); + assert(!g_main->g_target); + assert(!g_main->g_run); + assert(!g_main->g_run_arg); + g_main->g_target = tealet_alloc(g_main, &g_main->g_alloc); + if (g_main->g_target == NULL) + return -1; /* Could not allocate */ + if (res != NULL) + *res = g_main->g_target; + g_main->g_run = run; + g_main->g_run_arg = run_arg; + result = _tealet_initialstub(g_main, &dummymarker); + if (result < 0) { + /* could not save stack */ + g_free(g_main, g_main->g_target); + g_main->g_target = NULL; + g_main->g_run = NULL; + g_main->g_run_arg = NULL; + return result; + } + return 0; +} + +/************************************************************/ + +static tealet_alloc_t stdalloc = TEALET_MALLOC; + +tealet_t *tealet_initialize(tealet_alloc_t *alloc) +{ + /* NB. there are a lot of local variables with names starting with 'g_'. + In the original stackless and greenlet code these were typically + globals. There are no global variables left in tealets. */ + tealet_sub_t *g; + tealet_main_t *g_main; + if (alloc == NULL) + alloc = &stdalloc; + g = tealet_alloc(NULL, alloc); + if (g == NULL) + return NULL; + g_main = (tealet_main_t *)g; + g->stack_start = NULL; + g->stack_stop = STACK_STOP_MAIN; + g_main->g_current = g; + g_main->g_target = NULL; + g_main->g_run = NULL; + g_main->g_run_arg = NULL; + g_main->g_alloc = *alloc; + assert(TEALET_IS_MAIN(g_main)); + /* set up the following field with an indirection, which is needed + to prevent any inlining */ + _tealet_initialstub = g_initialstub; + _tealet_switchstack = g_switchstack; + return (tealet_t *)g_main; +} + +void tealet_finalize(tealet_t *main) +{ + tealet_main_t *g_main = (tealet_main_t *)main; + assert(TEALET_IS_MAIN(g_main)); + assert(g_main->g_current == (tealet_sub_t *)g_main); + g_free(g_main, g_main); +} + +int tealet_new(tealet_t *main, tealet_run_t run, void *run_arg) +{ + return tealet_new_int(main, run, run_arg, NULL); +} + +tealet_t *tealet_current(tealet_t *main) +{ + tealet_main_t *g_main = (tealet_main_t *)main; + assert(TEALET_IS_MAIN(g_main)); + return (tealet_t *)g_main->g_current; +} + +int tealet_switch(tealet_t *target) +{ + tealet_sub_t *g_target = (tealet_sub_t *)target; + tealet_main_t *g_main = TEALET_MAIN(g_target); + int result = 0; + if (g_target != g_main->g_current) { + #ifdef DEBUG_DUMP + printf("switch %p -> %p\n", g_main->g_current, g_target); + #endif + g_main->g_target = g_target; + result = _tealet_switchstack(g_main); + #ifdef DEBUG_DUMP + printf("done switching, res=%d, now in %p\n", result, g_main->g_current); + #endif + } + return result; +} + +int tealet_exit(tealet_t *target) +{ + tealet_sub_t *g_target = (tealet_sub_t *)target; + tealet_main_t *g_main = TEALET_MAIN(g_target); + char *stack_stop = g_target->stack_stop; + int result; + if (TEALET_IS_MAIN(g_target) || g_target == g_main->g_current) + return -2; /* invalid tealet */ + + g_target->stack_stop = NULL; /* signal exit */ + g_main->g_target = g_target; + result = _tealet_switchstack(g_main); + assert(result < 0); /* only return here if there was failure */ + g_target->stack_stop = stack_stop; + return result; +} + +tealet_t *tealet_stub_new(tealet_t *main) +{ + tealet_sub_t *g_result; + if (tealet_new_int(main, NULL, NULL, &g_result) < 0) + return NULL; + assert(g_result->stack_copy); + assert(STACK_SUB(g_result->stack_stop, g_result->stack_start) == g_result->stack_saved); + return (tealet_t*)g_result; +} + +int tealet_stub_run(tealet_t *stub, tealet_run_t run, void *run_arg) +{ + tealet_sub_t *g_target = (tealet_sub_t *)stub; + tealet_main_t *g_main = TEALET_MAIN(g_target); + int result = 0; + assert(g_target != g_main->g_current && g_target != (tealet_sub_t*)g_main); + assert(g_main->g_run == 0); + assert(g_main->g_run_arg == 0); + g_main->g_run = run; + g_main->g_run_arg = run_arg; +#ifdef DEBUG_DUMP + printf("stub run %p -> %p\n", g_main->g_current, g_target); +#endif + g_main->g_target = g_target; + result = _tealet_switchstack(g_main); +#ifdef DEBUG_DUMP + printf("done stub_run, res=%d, now in %p\n", result, g_main->g_current); +#endif + return result; +} + +#ifndef TEALET_NO_SHARING +tealet_t *tealet_duplicate(tealet_t *tealet) +{ + tealet_sub_t *g_tealet = (tealet_sub_t *)tealet; + tealet_main_t *g_main = TEALET_MAIN(g_tealet); + tealet_sub_t *g_copy; + assert(g_tealet != g_main->g_current && g_tealet != (tealet_sub_t*)g_main); + g_copy = tealet_alloc(g_main, &g_main->g_alloc); + if (g_copy == NULL) + return NULL; + *g_copy = *g_tealet; + g_copy->stack_copy = stack_dup(g_copy->stack_copy); + return (tealet_t*)g_copy; +} +#endif + +void tealet_delete(tealet_t *target) +{ + tealet_sub_t *g_target = (tealet_sub_t *)target; + tealet_main_t *g_main = TEALET_MAIN(g_target); + /* XXX this is wrong. Deleting a random tealet is delicate, + because it can be part of the stack_prev chained list */ + stack_free(g_main, g_target->stack_copy); + g_free(g_main, g_target); +} diff --git a/pypy/translator/c/src/tealet/tealet.h b/pypy/translator/c/src/tealet/tealet.h new file mode 100644 --- /dev/null +++ b/pypy/translator/c/src/tealet/tealet.h @@ -0,0 +1,147 @@ +/********** A minimal coroutine package for C **********/ +#ifndef _TEALET_H_ +#define _TEALET_H_ + +#include + + +#ifdef WIN32 +#if defined TEALET_EXPORTS +#define TEALET_API __declspec(dllexport) +#elif defined TEALET_IMPORTS +#define TEALET_API __declspec(dllimport) +#else +#define TEALET_API +#endif +#else /* win32 */ +#define TEALET_API +#endif + + +/* A structure to define the memory allocation api used. + * the functions have C89 semantics and take an additional "context" + * pointer that they can use as they please + */ +typedef struct tealet_alloc_s { + void *(*malloc_p)(size_t size, void *context); + void *(*realloc_p)(void *ptr, size_t size, void *context); + void (*free_p)(void *ptr, void *context); + void *context; +} tealet_alloc_t; + +/* use the following macro to initialize a tealet_alloc_t + * structure with stdlib malloc functions, for convenience, e.g.: + * tealet_alloc_t stdalloc = TEALET_MALLOC; + */ +#define TEALET_MALLOC {\ + (void *(*)(size_t, void*))malloc, \ + (void *(*)(void*, size_t, void*))realloc, \ + (void (*)(void*, void*))free, \ + 0 \ +} + + +/* The user-visible tealet structure */ +typedef struct tealet_s { + struct tealet_s *main; /* pointer to the main tealet */ + void *data; /* general-purpose, store whatever you want here */ + /* private fields follow */ +} tealet_t; + +/* The "run" function of a tealet. It is called with the + * current tealet and the argument provided to its start function + */ +typedef tealet_t *(*tealet_run_t)(tealet_t *current, void *arg); + + +/* error codes. API functions that return int return a negative value + * to signal an error. + * Those that return tealet_t pointers return NULL to signal a memory + * error. + */ +#define TEALET_ERR_MEM -1 /* memory allocation failed */ +#define TEALET_ERR_INVALID -2 /* the target tealet is corrupt */ + + +/* Initialize and return the main tealet. The main tealet contains the whole + * "normal" execution of the program; it starts when the program starts and + * ends when the program ends. This function and tealet_finalize() should + * be called together from the same (main) function which calls the rest of + * the program. It is fine to nest several uses of initialize/finalize, + * or to call them in multiple threads in case of multithreaded programs, + * as long as you don't try to switch to tealets created with a + * different main tealet. + */ +TEALET_API +tealet_t *tealet_initialize(tealet_alloc_t *alloc); + +/* Tear down the main tealet. Call e.g. after a thread finishes (including + * all its tealets). + */ +TEALET_API +void tealet_finalize(tealet_t *main); + +/* Allocate a new tealet 'g', and call 'run(g, arg)' in it. + * The return value of run() must be the next tealet in which to continue + * execution, which must be a different one, like for example the main tealet. + * When 'run(g)' returns, the tealet 'g' is freed. + */ +TEALET_API +int tealet_new(tealet_t *main, tealet_run_t run, void *arg); + +/* Return the current tealet, i.e. the one in which the caller of this + * function currently is. "main" can be any tealet derived from the + * main tealet. + */ +TEALET_API +tealet_t *tealet_current(tealet_t *main); + +/* Switch to another tealet. Execution continues there. The tealet + * passed in must not have been freed yet and must descend from + * the same main tealet as the current one. In multithreaded applications, + * it must also belong to the current thread (otherwise, segfaults). + */ +TEALET_API +int tealet_switch(tealet_t *target); + +/* Exit the current tealet. Same as tealet_switch except that + * it the current tealet is deleted. Use this only in emergency, + * if tealet_switch() fails due to inability to save the stack. + * This call fails only if the target has invalid state, otherwise + * it never returns. + */ +TEALET_API +int tealet_exit(tealet_t *target); + +/* Duplicate a tealet. This is intended for the duplication of stubs so + * that new stubs can be recretaed with a predetermined stack. + */ +#ifndef TEALET_NO_SHARING +TEALET_API +tealet_t *tealet_duplicate(tealet_t *tealet); +#endif + +/* Deallocate a tealet. Use this to delete a stub that + * is no longer being used for tealet_stub_dup(), or to deallocate + * a tealet that has become invalid due to memory errors. + * It can also delete a suspended tealet, which effectively kills it. + * + * XXX probably buggy + */ +TEALET_API +void tealet_delete(tealet_t *target); + +/* Allocate a new tealet stub at this position. This can later + * be run with tealet_stub_new(), duplicated with tealet_duplicate() + * and deleted with tealet_stub_del(). + */ +TEALET_API +tealet_t *tealet_stub_new(tealet_t *main); + +/* Run a stub. The combination of tealet_stub_new() and tealet_stub_run() + * is exactly the same as tealet_new() + */ +TEALET_API +int tealet_stub_run(tealet_t *stub, tealet_run_t run, void *run_arg); + +#endif /* _TEALET_H_ */ From noreply at buildbot.pypy.org Wed Jul 6 20:28:42 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:42 +0200 (CEST) Subject: [pypy-commit] pypy tealet: App-level interface. Untested; unsure how to test it... Message-ID: <20110706182842.3582C820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45380:1035732daa98 Date: 2011-06-12 11:42 +0200 http://bitbucket.org/pypy/pypy/changeset/1035732daa98/ Log: App-level interface. Untested; unsure how to test it... diff --git a/pypy/module/tealet/__init__.py b/pypy/module/tealet/__init__.py new file mode 100644 --- /dev/null +++ b/pypy/module/tealet/__init__.py @@ -0,0 +1,13 @@ +from pypy.interpreter.mixedmodule import MixedModule + +class Module(MixedModule): + """Tealets. XXX document me""" + + appleveldefs = { + } + + interpleveldefs = { + 'Tealet' : 'interp_tealet.W_Tealet', + 'MainTealet': 'interp_tealet.W_MainTealet', + 'error' : 'space.fromcache(interp_tealet.Cache).w_error', + } diff --git a/pypy/module/tealet/interp_tealet.py b/pypy/module/tealet/interp_tealet.py new file mode 100644 --- /dev/null +++ b/pypy/module/tealet/interp_tealet.py @@ -0,0 +1,74 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import interp2app + +from pypy.rlib.rtealet import _make_classes, TealetError + +# ____________________________________________________________ + +W_Tealet, W_MainTealet = _make_classes(Wrappable) +W_Tealet.__name__ = 'W_Tealet' +W_MainTealet.__name__ = 'W_MainTealet' + +class Cache: + def __init__(self, space): + self.w_error = space.new_exception_class("tealet.error") + +def wrap_error(space, error): + w_exception_class = space.fromcache(Cache).w_error + w_exception = space.call_function(w_exception_class, space.wrap(error.msg)) + return OperationError(w_exception_class, w_exception) + +# ____________________________________________________________ + +def W_Tealet_run(self): + space = self.space + w_other = space.call_method(space.wrap(self), 'run') + return space.interp_w(W_Tealet, w_other, can_be_None=True) + +def W_Tealet___new__(space, w_subtype, __args__): + r = space.allocate_instance(W_Tealet, w_subtype) + r.space = space + return space.wrap(r) + +def W_Tealet_switch(w_self): + self = space.interp_w(W_Tealet, w_self) + try: + self.switch() + except TealetError, e: + raise wrap_error(space, e) + +W_Tealet.run = W_Tealet_run +W_Tealet.typedef = TypeDef( + 'Tealet', + __module__ = 'tealet', + __new__ = interp2app(W_Tealet___new__), + switch = interp2app(W_Tealet_switch), + ) + +# ____________________________________________________________ + +def W_MainTealet___new__(space, w_subtype, __args__): + r = space.allocate_instance(W_MainTealet, w_subtype) + r.__init__() + r.space = space + return space.wrap(r) + +def W_MainTealet_start(w_self, w_tealet): + space = self.space + self = space.interp_w(W_MainTealet, w_self) + tealet = space.interp_w(W_Tealet, w_tealet) + try: + self.start(tealet) + except TealetError, e: + raise wrap_error(space, e) + +W_MainTealet.typedef = TypeDef( + 'MainTealet', + __module__ = 'tealet', + __new__ = interp2app(W_MainTealet___new__), + start = interp2app(W_MainTealet_start), + ) + +# ____________________________________________________________ diff --git a/pypy/rlib/rtealet.py b/pypy/rlib/rtealet.py --- a/pypy/rlib/rtealet.py +++ b/pypy/rlib/rtealet.py @@ -14,34 +14,41 @@ class TealetError(Exception): - pass + def __init__(self, msg): + self.msg = msg -class Tealet(object): - _ll_saved_stack = None +def _make_classes(base_class): - def __init__(self, main): - assert isinstance(main, MainTealet) - self.main = main - _new(main, self) + class Tealet(base_class): + lltealet = _tealet_rffi.NULL_TEALET + _ll_saved_stack = None - def switch(self): - _switch(self) + def switch(self): + _switch(self) - def run(self): - raise NotImplementedError + def run(self): + raise NotImplementedError + class MainTealet(Tealet): + def __init__(self): + assert we_are_translated(), "no support for untranslated runs yet" + self.main = self + self.current = self + self.lltealet = _tealet_rffi.tealet_initialize(_tealet_rffi.NULL) -class MainTealet(Tealet): - def __init__(self): - assert we_are_translated(), "no support for untranslated runs yet" - self.main = self - self.current = self - self.lltealet = _tealet_rffi.tealet_initialize(_tealet_rffi.NULL) + def __del__(self): + _tealet_rffi.tealet_finalize(self.lltealet) - def __del__(self): - _tealet_rffi.tealet_finalize(self.lltealet) + def start(self, tealet): + if tealet.lltealet: + raise TealetError("tealet already running") + tealet.main = self + _new(self, tealet) + return Tealet, MainTealet + +Tealet, MainTealet = _make_classes(object) ## ------------------------------------------------------------ ## The code below is implementation details. @@ -123,12 +130,13 @@ _switch_critical._dont_inline_ = True def _check_exception(r): - if rffi.cast(lltype.Signed, r) != 0: + r = rffi.cast(lltype.Signed, r) + if r != 0: # rare case: tealet.c complains, e.g. out of memory. I think that # in this case it's not really possible to have 'exception != None'. # Clean it anyway to avoid it showing up at a random time later. switcher.exception = None - raise TealetError + raise TealetError("internal error %d" % r) e = switcher.exception if e is not None: switcher.exception = None diff --git a/pypy/rlib/test/demotealet.py b/pypy/rlib/test/demotealet.py --- a/pypy/rlib/test/demotealet.py +++ b/pypy/rlib/test/demotealet.py @@ -75,7 +75,7 @@ do_switch._dont_inline_ = True def do_new(main): - MyTealet(main) + main.start(MyTealet()) do_new._dont_inline_ = True def do(current_tealet_index, x): From noreply at buildbot.pypy.org Wed Jul 6 20:28:43 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:43 +0200 (CEST) Subject: [pypy-commit] pypy tealet: A proper fix, hopefully. Message-ID: <20110706182843.729A7820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45381:95c873fad361 Date: 2011-06-12 12:41 +0200 http://bitbucket.org/pypy/pypy/changeset/95c873fad361/ Log: A proper fix, hopefully. diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1423,17 +1423,32 @@ self.collect_stacks_from_other_threads(collect_stack_root) def need_tealet_support(self, gctransformer, getfn): - super(ShadowStackRootWalker, self).need_tealet_support(gctransformer, - getfn) + assert not gctransformer.translator.config.translation.jit, ( + "not supported yet: jit + shadowstack + tealet") + assert not gctransformer.translator.config.translation.thread, ( + "not supported yet: thread + shadowstack + tealet") + # + # We need a custom version of ll_walk_stack_roots because the issue + # is that when we try to restore the shadowstack, it initially + # contains garbage; and the default ll_walk_stack_roots would skip + # the NULL pointers in it. gcdata = self.gcdata + # + def ll_walk_stack_roots(fnptr_stack_root): + addr = gcdata.root_stack_base + end = gcdata.root_stack_top + while addr != end: + fnptr_stack_root(addr) + addr += sizeofaddr + # + FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.Address], lltype.Void)) + s_FuncPtr = annmodel.SomePtr(FUNCPTR) + self.ll_walk_stack_roots_ptr = getfn(ll_walk_stack_roots, + [s_FuncPtr], annmodel.s_None) + # def set_stack_roots_count(count): bytes = count * llmemory.sizeof(llmemory.Address) - p = gcdata.root_stack_base - end = gcdata.root_stack_top = p + bytes - INVALID_NONNULL_ADDRESS = llmemory.cast_int_to_adr(8) - while p != end: - p.address[0] = INVALID_NONNULL_ADDRESS - p += llmemory.sizeof(llmemory.Address) + gcdata.root_stack_top = gcdata.root_stack_base + bytes self.set_stack_roots_count_ptr = getfn(set_stack_roots_count, [annmodel.SomeInteger()], annmodel.s_None) From noreply at buildbot.pypy.org Wed Jul 6 20:28:44 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:44 +0200 (CEST) Subject: [pypy-commit] pypy tealet: fixes. Message-ID: <20110706182844.AA2B6820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45382:0cbc95f97c9d Date: 2011-06-12 10:43 +0000 http://bitbucket.org/pypy/pypy/changeset/0cbc95f97c9d/ Log: fixes. diff --git a/pypy/module/tealet/interp_tealet.py b/pypy/module/tealet/interp_tealet.py --- a/pypy/module/tealet/interp_tealet.py +++ b/pypy/module/tealet/interp_tealet.py @@ -32,7 +32,7 @@ r.space = space return space.wrap(r) -def W_Tealet_switch(w_self): +def W_Tealet_switch(space, w_self): self = space.interp_w(W_Tealet, w_self) try: self.switch() @@ -55,8 +55,7 @@ r.space = space return space.wrap(r) -def W_MainTealet_start(w_self, w_tealet): - space = self.space +def W_MainTealet_start(space, w_self, w_tealet): self = space.interp_w(W_MainTealet, w_self) tealet = space.interp_w(W_Tealet, w_tealet) try: @@ -65,7 +64,7 @@ raise wrap_error(space, e) W_MainTealet.typedef = TypeDef( - 'MainTealet', + 'MainTealet', W_Tealet.typedef, __module__ = 'tealet', __new__ = interp2app(W_MainTealet___new__), start = interp2app(W_MainTealet_start), From noreply at buildbot.pypy.org Wed Jul 6 20:28:45 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:45 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Tweak delegation between rtealet.py and the GC. It seems that the Message-ID: <20110706182845.F2345820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45383:01a6ac124f45 Date: 2011-06-12 15:53 +0200 http://bitbucket.org/pypy/pypy/changeset/01a6ac124f45/ Log: Tweak delegation between rtealet.py and the GC. It seems that the GC needs to do a bit more, but it's not really more code in total. diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -32,6 +32,7 @@ default=False, cmdline="--tealet", requires=[("translation.type_system", "lltype"), ("translation.gctransformer", "framework"), + ("translation.gcrootfinder", "shadowstack"), ("translation.thread", False)]), # XXX temporary ChoiceOption("type_system", "Type system to use when RTyping", ["lltype", "ootype"], cmdline=None, default="lltype", diff --git a/pypy/rlib/_tealet_rffi.py b/pypy/rlib/_tealet_rffi.py --- a/pypy/rlib/_tealet_rffi.py +++ b/pypy/rlib/_tealet_rffi.py @@ -11,8 +11,7 @@ def llexternal(funcname, args, restype): return rffi.llexternal(funcname, args, restype, compilation_info=eci, - sandboxsafe=True, threadsafe=False, - _nowrapper=True) + sandboxsafe=True, _nowrapper=True) TEALET_P = rffi.COpaquePtr('tealet_t', compilation_info=eci) TEALET_RUN_P = lltype.Ptr(lltype.FuncType([TEALET_P, rffi.VOIDP], TEALET_P)) diff --git a/pypy/rlib/rtealet.py b/pypy/rlib/rtealet.py --- a/pypy/rlib/rtealet.py +++ b/pypy/rlib/rtealet.py @@ -22,7 +22,6 @@ class Tealet(base_class): lltealet = _tealet_rffi.NULL_TEALET - _ll_saved_stack = None def switch(self): _switch(self) @@ -58,8 +57,6 @@ class Switcher(object): current = None target = None - count_roots = 0 - lst = None exception = None switcher = Switcher() @@ -143,52 +140,37 @@ raise e # ____________________________________________________________ +# +# Shadow stack saving/restoring. -ROOT_WALKER = lltype.Ptr(lltype.FuncType([llmemory.Address], lltype.Void)) +GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF)) +SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed)) +WALKER_PTR = lltype.Ptr(lltype.Struct('walker', + ('gcptr_array', GCPTR_ARRAY), + ('signed_array', SIGNED_ARRAY))) +walker = lltype.malloc(WALKER_PTR.TO, immortal=True) -def _count_roots_walker(root): - switcher.count_roots += 1 - -def _save_root_walker(root): - i = switcher.count_roots - switcher.count_roots = i + 1 - gcobj = llmemory.cast_adr_to_ptr(root.address[0], llmemory.GCREF) - switcher.lst[i] = gcobj +Tealet._gc_gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) +Tealet._gc_signed_array = lltype.nullptr(SIGNED_ARRAY.TO) def _save_shadow_stack(): - switcher.count_roots = 0 - fn = llhelper(ROOT_WALKER, _count_roots_walker) - llop.gc_walk_stack_roots(lltype.Void, fn) - n = switcher.count_roots - # + llop.gc_save_stack_roots(lltype.Void, walker) tealet = switcher.current - ll_assert(tealet._ll_saved_stack is None, "tealet stack mismatch (save)") - tealet._ll_saved_stack = [lltype.nullptr(llmemory.GCREF.TO)] * n - switcher.count_roots = 0 - switcher.lst = tealet._ll_saved_stack - fn = llhelper(ROOT_WALKER, _save_root_walker) - llop.gc_walk_stack_roots(lltype.Void, fn) - ll_assert(n == switcher.count_roots, "tealet stack mismatch (count1)") - switcher.lst = None + ll_assert(not tealet._gc_gcptr_array, "tealet stack mismatch (save)") + tealet._gc_gcptr_array = walker.gcptr_array + tealet._gc_signed_array = walker.signed_array + walker.gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) + walker.signed_array = lltype.nullptr(SIGNED_ARRAY.TO) _save_shadow_stack._dont_inline_ = True -def _restore_root_walker(root): - i = switcher.count_roots - switcher.count_roots = i + 1 - gcobj = switcher.lst[i] - root.address[0] = llmemory.cast_ptr_to_adr(gcobj) - def _restore_shadow_stack(): tealet = switcher.target - lst = tealet._ll_saved_stack - ll_assert(lst is not None, "tealet stack mismatch (restore)") - tealet._ll_saved_stack = None - switcher.count_roots = 0 - switcher.lst = lst - n = len(lst) - fn = llhelper(ROOT_WALKER, _restore_root_walker) - llop.gc_set_stack_roots_count(lltype.Void, n) - llop.gc_walk_stack_roots(lltype.Void, fn) - ll_assert(n == switcher.count_roots, "tealet stack mismatch (count2)") - switcher.lst = None + ll_assert(bool(tealet._gc_gcptr_array), "tealet stack mismatch (restore)") + walker.gcptr_array = tealet._gc_gcptr_array + walker.signed_array = tealet._gc_signed_array + tealet._gc_gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) + tealet._gc_signed_array = lltype.nullptr(SIGNED_ARRAY.TO) + llop.gc_restore_stack_roots(lltype.Void, walker) + walker.gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) + walker.signed_array = lltype.nullptr(SIGNED_ARRAY.TO) _restore_shadow_stack._dont_inline_ = True diff --git a/pypy/rlib/test/test_rtealet.py b/pypy/rlib/test/test_rtealet.py --- a/pypy/rlib/test/test_rtealet.py +++ b/pypy/rlib/test/test_rtealet.py @@ -1,3 +1,4 @@ +import py from pypy.translator.c.test.test_standalone import StandaloneTests @@ -28,3 +29,5 @@ class TestTealetAsmgcc(BaseTestTealet): gcrootfinder = "asmgcc" + def setup_class(cls): + py.test.skip("XXX in-progress") diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -483,8 +483,8 @@ 'gc_dump_rpy_heap' : LLOp(), 'gc_typeids_z' : LLOp(), - 'gc_walk_stack_roots' : LLOp(), # for tealet support - 'gc_set_stack_roots_count': LLOp(), # " + 'gc_save_stack_roots' : LLOp(), # for tealet support + 'gc_restore_stack_roots': LLOp(), # for tealet support # ------- JIT & GC interaction, only for some GCs ---------- diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1006,22 +1006,21 @@ hop.genop("direct_call", [self.root_walker.thread_after_fork_ptr] + hop.spaceop.args) - def gct_gc_walk_stack_roots(self, hop): + def gct_gc_save_stack_roots(self, hop): # only available if tealet support is enabled assert self.translator.config.translation.tealet # no gc root in the stack around such an llop! assert not self.push_roots(hop) - hop.genop("direct_call", [self.root_walker.ll_walk_stack_roots_ptr] + hop.genop("direct_call", [self.root_walker.ll_save_stack_roots_ptr] + hop.spaceop.args) - def gct_gc_set_stack_roots_count(self, hop): + def gct_gc_restore_stack_roots(self, hop): + # only available if tealet support is enabled assert self.translator.config.translation.tealet # no gc root in the stack around such an llop! assert not self.push_roots(hop) - if hasattr(self.root_walker, 'set_stack_roots_count_ptr'): - hop.genop("direct_call", - [self.root_walker.set_stack_roots_count_ptr] - + hop.spaceop.args) + hop.genop("direct_call", [self.root_walker.ll_restore_stack_roots_ptr] + + hop.spaceop.args) def gct_gc_get_type_info_group(self, hop): return hop.cast_result(self.c_type_info_group) @@ -1347,20 +1346,8 @@ self.__class__.__name__,)) def need_tealet_support(self, gctransformer, getfn): - # - def ll_walk_stack_roots(fnptr_stack_root): - gcdata = self.gcdata - gcdata._fnptr_stack_root = fnptr_stack_root - self.walk_stack_roots(_ll_collect) - # - def _ll_collect(gc, root): - gcdata = self.gcdata - gcdata._fnptr_stack_root(root) - # - FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.Address], lltype.Void)) - s_FuncPtr = annmodel.SomePtr(FUNCPTR) - self.ll_walk_stack_roots_ptr = getfn(ll_walk_stack_roots, - [s_FuncPtr], annmodel.s_None) + raise Exception("%s does not support tealets" % ( + self.__class__.__name__,)) class ShadowStackRootWalker(BaseRootWalker): @@ -1424,34 +1411,45 @@ def need_tealet_support(self, gctransformer, getfn): assert not gctransformer.translator.config.translation.jit, ( - "not supported yet: jit + shadowstack + tealet") + "XXX in-progress: tealet + jit + shadowstack") assert not gctransformer.translator.config.translation.thread, ( - "not supported yet: thread + shadowstack + tealet") + "XXX check me: tealet + thread + shadowstack") # - # We need a custom version of ll_walk_stack_roots because the issue - # is that when we try to restore the shadowstack, it initially - # contains garbage; and the default ll_walk_stack_roots would skip - # the NULL pointers in it. + GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF)) + SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed)) + WALKER_PTR = lltype.Ptr(lltype.Struct('walker', + ('gcptr_array', GCPTR_ARRAY), + ('signed_array', SIGNED_ARRAY))) gcdata = self.gcdata # - def ll_walk_stack_roots(fnptr_stack_root): + def ll_save_stack_roots(walker): addr = gcdata.root_stack_base end = gcdata.root_stack_top - while addr != end: - fnptr_stack_root(addr) - addr += sizeofaddr + count = (end - addr) // sizeofaddr + walker.gcptr_array = array = lltype.malloc(GCPTR_ARRAY.TO, count) + n = 0 + while n < len(array): + array[n] = llmemory.cast_adr_to_ptr(addr.address[n], + llmemory.GCREF) + n += 1 # - FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.Address], lltype.Void)) - s_FuncPtr = annmodel.SomePtr(FUNCPTR) - self.ll_walk_stack_roots_ptr = getfn(ll_walk_stack_roots, - [s_FuncPtr], annmodel.s_None) + def ll_restore_stack_roots(walker): + array = walker.gcptr_array + addr = gcdata.root_stack_base + gcdata.root_stack_top = addr + len(array) * sizeofaddr + n = 0 + while n < len(array): + addr.address[n] = llmemory.cast_ptr_to_adr(array[n]) + n += 1 # - def set_stack_roots_count(count): - bytes = count * llmemory.sizeof(llmemory.Address) - gcdata.root_stack_top = gcdata.root_stack_base + bytes - self.set_stack_roots_count_ptr = getfn(set_stack_roots_count, - [annmodel.SomeInteger()], - annmodel.s_None) + self.ll_save_stack_roots_ptr = getfn(ll_save_stack_roots, + [annmodel.SomePtr(WALKER_PTR)], + annmodel.s_None, + minimal_transform=False) + self.ll_restore_stack_roots_ptr = getfn(ll_restore_stack_roots, + [annmodel.SomePtr(WALKER_PTR)], + annmodel.s_None, + minimal_transform=False) def need_thread_support(self, gctransformer, getfn): from pypy.module.thread import ll_thread # xxx fish From noreply at buildbot.pypy.org Wed Jul 6 20:28:47 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:47 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Move initialization to the class declaration. Needed anyway Message-ID: <20110706182847.3565C820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45384:4ededdcb373f Date: 2011-06-12 16:01 +0200 http://bitbucket.org/pypy/pypy/changeset/4ededdcb373f/ Log: Move initialization to the class declaration. Needed anyway because otherwise W_Tealet is missing these attributes. diff --git a/pypy/rlib/rtealet.py b/pypy/rlib/rtealet.py --- a/pypy/rlib/rtealet.py +++ b/pypy/rlib/rtealet.py @@ -22,6 +22,8 @@ class Tealet(base_class): lltealet = _tealet_rffi.NULL_TEALET + _gc_gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) + _gc_signed_array = lltype.nullptr(SIGNED_ARRAY.TO) def switch(self): _switch(self) @@ -47,8 +49,6 @@ return Tealet, MainTealet -Tealet, MainTealet = _make_classes(object) - ## ------------------------------------------------------------ ## The code below is implementation details. @@ -150,9 +150,6 @@ ('signed_array', SIGNED_ARRAY))) walker = lltype.malloc(WALKER_PTR.TO, immortal=True) -Tealet._gc_gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) -Tealet._gc_signed_array = lltype.nullptr(SIGNED_ARRAY.TO) - def _save_shadow_stack(): llop.gc_save_stack_roots(lltype.Void, walker) tealet = switcher.current @@ -174,3 +171,7 @@ walker.gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) walker.signed_array = lltype.nullptr(SIGNED_ARRAY.TO) _restore_shadow_stack._dont_inline_ = True + +# ____________________________________________________________ + +Tealet, MainTealet = _make_classes(object) From noreply at buildbot.pypy.org Wed Jul 6 20:28:48 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:48 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Saving and restoring the shadowstack in the JIT. Message-ID: <20110706182848.6FEAD820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45385:841c213583c6 Date: 2011-06-13 10:51 +0200 http://bitbucket.org/pypy/pypy/changeset/841c213583c6/ Log: Saving and restoring the shadowstack in the JIT. diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -1,7 +1,7 @@ import os from pypy.rlib import rgc from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import fatalerror +from pypy.rlib.debug import fatalerror, ll_assert from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr from pypy.rpython.lltypesystem import llgroup @@ -365,12 +365,24 @@ self.force_index_ofs = gcdescr.force_index_ofs def add_jit2gc_hooks(self, jit2gc): + INTARRAYPTR = self.INTARRAYPTR + def read(addr): + return rffi.cast(INTARRAYPTR, addr)[0] + def write(addr, newvalue): + rffi.cast(INTARRAYPTR, addr)[0] = newvalue + # for tests: + read = jit2gc.get('test_read', read) + write = jit2gc.get('test_write', write) + cast_int_to_adr = jit2gc.get('test_i2a', llmemory.cast_int_to_adr) + cast_int_to_ptr = jit2gc.get('test_i2p', lltype.cast_int_to_ptr) + cast_ptr_to_int = jit2gc.get('test_p2i', lltype.cast_ptr_to_int) # - def collect_jit_stack_root(callback, gc, addr): - if addr.signed[0] != GcRootMap_shadowstack.MARKER: + def collect_jit_stack_root(callback, gc, realaddr): + addr = rffi.cast(lltype.Signed, realaddr) + if read(addr) != GcRootMap_shadowstack.MARKER: # common case - if gc.points_to_valid_gc_object(addr): - callback(gc, addr) + if gc.points_to_valid_gc_object(realaddr): + callback(gc, realaddr) return WORD else: # case of a MARKER followed by an assembler stack frame @@ -378,9 +390,8 @@ return 2 * WORD # def follow_stack_frame_of_assembler(callback, gc, addr): - frame_addr = addr.signed[1] - addr = llmemory.cast_int_to_adr(frame_addr + self.force_index_ofs) - force_index = addr.signed[0] + frame_addr = read(addr + WORD) + force_index = read(frame_addr + self.force_index_ofs) if force_index < 0: force_index = ~force_index callshape = self._callshapes[force_index] @@ -389,13 +400,145 @@ offset = rffi.cast(lltype.Signed, callshape[n]) if offset == 0: break - addr = llmemory.cast_int_to_adr(frame_addr + offset) + addr = cast_int_to_adr(frame_addr + offset) if gc.points_to_valid_gc_object(addr): callback(gc, addr) n += 1 # + # ---------- tealet support ---------- + GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF)) + SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed)) + # + def save_roots(walker, gcdata): + gcptr_count = 0 + signed_count = 0 + gcptr_array = walker.gcptr_array + # + rsbase = gcdata.root_stack_base + rsend = gcdata.root_stack_top + rsaddr = rsbase + while rsaddr != rsend: + if read(rsaddr) != GcRootMap_shadowstack.MARKER: + # common case + if gcptr_array: + gcobj = cast_int_to_ptr(llmemory.GCREF, read(rsaddr)) + gcptr_array[gcptr_count] = gcobj + gcptr_count += 1 + rsaddr += WORD + else: + # case of a MARKER followed by an assembler stack frame + frame_addr = read(rsaddr + WORD) + force_index = read(frame_addr + self.force_index_ofs) + if force_index < 0: + force_index = ~force_index + if walker.signed_array: + walker.signed_array[signed_count] = rsaddr - rsbase + walker.signed_array[signed_count+1] = frame_addr + walker.signed_array[signed_count+2] = force_index + # NB. saving force_index is not necessary, but + # we do it anyway because it costs little and would + # find bugs + signed_count += 3 + callshape = self._callshapes[force_index] + n = 0 + while True: + offset = rffi.cast(lltype.Signed, callshape[n]) + if offset == 0: + break + if gcptr_array: + addr = cast_int_to_adr(frame_addr + offset) + gcobj = cast_int_to_ptr(llmemory.GCREF, read(addr)) + gcptr_array[gcptr_count] = gcobj + gcptr_count += 1 + n += 1 + rsaddr += 2 * WORD + # + if walker.signed_array: + walker.signed_array[signed_count] = rsend - rsbase + signed_count += 1 + # + if not walker.gcptr_array: + walker.gcptr_array = lltype.malloc(GCPTR_ARRAY.TO, gcptr_count) + if not walker.signed_array: + walker.signed_array = lltype.malloc(SIGNED_ARRAY.TO, + signed_count) + ll_assert(signed_count == len(walker.signed_array), + "varying stack signed count") + ll_assert(gcptr_count == len(walker.gcptr_array), + "varying stack gcptr count") + # + def jit_save_stack_roots(walker, gcdata): + """Save the stack roots from the shadowstack piece of memory, + including the stack roots that are in assembler-generated code + with a MARKER followed by the address of the assembler frame. + Puts all this information in two arrays: walker.gcptr_array and + walker.signed_array. + """ + walker.gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) + walker.signed_array = lltype.nullptr(SIGNED_ARRAY.TO) + save_roots(walker, gcdata) # at first, just to count + save_roots(walker, gcdata) # this time, really save + # + def jit_restore_stack_roots(walker, gcdata): + """Restore the stack roots into the shadowstack piece of memory + and into the assembler frames. + """ + gcptr_count = 0 + signed_count = 0 + gcptr_array = walker.gcptr_array + # + rsbase = gcdata.root_stack_base + rsaddr = rsbase + rsmarker = rsbase + walker.signed_array[signed_count] + signed_count += 1 + while True: + if rsaddr != rsmarker: + # common case + gcobj = gcptr_array[gcptr_count] + write(rsaddr, cast_ptr_to_int(gcobj)) + gcptr_count += 1 + rsaddr += WORD + elif signed_count == len(walker.signed_array): + # done + break + else: + # case of a MARKER followed by an assembler stack frame + frame_addr = walker.signed_array[signed_count] + write(rsaddr, GcRootMap_shadowstack.MARKER) + write(rsaddr + WORD, frame_addr) + rsaddr += 2 * WORD + # + force_index = read(frame_addr + self.force_index_ofs) + if force_index < 0: + force_index = ~force_index + ll_assert(force_index == + walker.signed_array[signed_count+1], + "restoring bogus stack force_index") + callshape = self._callshapes[force_index] + n = 0 + while True: + offset = rffi.cast(lltype.Signed, callshape[n]) + if offset == 0: + break + addr = cast_int_to_adr(frame_addr + offset) + gcobj = gcptr_array[gcptr_count] + write(addr, cast_ptr_to_int(gcobj)) + gcptr_count += 1 + n += 1 + # + rsmarker = rsbase + walker.signed_array[signed_count+2] + signed_count += 3 + # + gcdata.root_stack_top = rsmarker + ll_assert(signed_count == len(walker.signed_array), + "restoring bogus stack signed count") + ll_assert(gcptr_count == len(walker.gcptr_array), + "restoring bogus stack gcptr count") + # jit2gc.update({ 'rootstackhook': collect_jit_stack_root, + 'savestackhook': jit_save_stack_roots, + 'restorestackhook': jit_restore_stack_roots, }) def initialize(self): diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py --- a/pypy/jit/backend/llsupport/test/test_gc.py +++ b/pypy/jit/backend/llsupport/test/test_gc.py @@ -1,4 +1,4 @@ -import random +import sys, random from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.annlowlevel import llhelper @@ -241,6 +241,162 @@ assert rffi.cast(lltype.Signed, p[1]) == -24 assert rffi.cast(lltype.Signed, p[2]) == 0 + def build_fake_stack(self): + self.gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr()) + self.gcrootmap.force_index_ofs = 16 + self.writes = {} + # + def read_for_tests(addr): + assert addr % WORD == 0 + if 3000 <= addr < 3000+8*WORD: + return self.shadowstack[(addr - 3000) // WORD] + if 20000 <= addr < 29000: + base = (addr // 1000) * 1000 + return frames[base][addr-base] + raise AssertionError(addr) + def write_for_tests(addr, newvalue): + self.writes[addr] = newvalue + def cast_int_to_adr_for_tests(value): + return value + def cast_int_to_ptr_for_tests(TARGET, value): + assert TARGET == llmemory.GCREF + return lltype.opaqueptr(TARGET.TO, 'foo', x=value) + def cast_ptr_to_int_for_tests(value): + assert isinstance(value, int) + assert 10000 <= value < 11000 or value == 0 + return value + # + self.jit2gc = {'test_read': read_for_tests, + 'test_write': write_for_tests, + 'test_i2a': cast_int_to_adr_for_tests, + 'test_i2p': cast_int_to_ptr_for_tests, + 'test_p2i': cast_ptr_to_int_for_tests} + self.gcrootmap.add_jit2gc_hooks(self.jit2gc) + # + def someobj(x): + return 10000 + x + # + frames = {} + # + def someframe(data, force_index): + num = 20000 + len(frames) * 1000 + data[self.gcrootmap.force_index_ofs] = force_index + frames[num] = data + return num + # + MARKER = GcRootMap_shadowstack.MARKER + self.gcrootmap._callshapes = {61: (32, 64, 80, 0), + 62: (32, 48, 0)} + self.shadowstack = [ + someobj(42), + someobj(43), + 0, + MARKER, + someframe({32:someobj(132), 64:someobj(164), 80:someobj(180)}, 61), + someobj(44), + MARKER, + someframe({32: someobj(232), 48: someobj(248)}, ~62), + ] + # + class FakeGC: + def points_to_valid_gc_object(self, addr): + to = read_for_tests(addr) + if to == 0: + return False + if 10000 <= to < 11000: + return True + raise AssertionError(to) + class FakeGCData: + pass + self.gc = FakeGC() + self.gcdata = FakeGCData() + self.gcdata.root_stack_base = 3000 + self.gcdata.root_stack_top = 3000 + 8*WORD + + def test_jit_stack_root(self): + self.build_fake_stack() + collect_jit_stack_root = self.jit2gc['rootstackhook'] + seen = [] + def callback(gc, addr): + assert gc == self.gc + seen.append(addr) + def f(n): + return self.gcdata.root_stack_base + n * WORD + res = collect_jit_stack_root(callback, self.gc, f(0)) # someobj + assert res == WORD + assert seen == [3000] + res = collect_jit_stack_root(callback, self.gc, f(1)) # someobj + assert res == WORD + assert seen == [3000, 3000+WORD] + res = collect_jit_stack_root(callback, self.gc, f(2)) # 0 + assert res == WORD + assert seen == [3000, 3000+WORD] + res = collect_jit_stack_root(callback, self.gc, f(3)) # MARKER + assert res == 2 * WORD + assert seen == [3000, 3000+WORD, 20032, 20064, 20080] + res = collect_jit_stack_root(callback, self.gc, f(5)) # someobj + assert res == WORD + assert seen == [3000, 3000+WORD, 20032, 20064, 20080, 3000+5*WORD] + res = collect_jit_stack_root(callback, self.gc, f(6)) # MARKER + assert res == 2 * WORD + assert seen == [3000, 3000+WORD, 20032, 20064, 20080, 3000+5*WORD, + 21032, 21048] + + def test_jit_save_stack_roots(self): + class Walker: + pass + self.build_fake_stack() + jit_save_stack_roots = self.jit2gc['savestackhook'] + walker = Walker() + jit_save_stack_roots(walker, self.gcdata) + assert list(walker.signed_array) == [ + 3 * WORD, 20000, 61, + 6 * WORD, 21000, 62, + 8 * WORD] + assert [gcref._obj.x for gcref in walker.gcptr_array] == [ + 10042, + 10043, + 0, + 10132, 10164, 10180, + 10044, + 10232, 10248] + + def test_jit_restore_stack_roots(self): + class Walker: + pass + self.build_fake_stack() + jit_restore_stack_roots = self.jit2gc['restorestackhook'] + walker = Walker() + walker.signed_array = [ + 3 * WORD, 20000, 61, + 6 * WORD, 21000, 62, + 8 * WORD] + walker.gcptr_array = [ + 10042, + 10043, + 0, + 10132, 10164, 10180, + 10044, + 10232, 10248] + self.gcdata.root_stack_top = 4444 + jit_restore_stack_roots(walker, self.gcdata) + assert self.gcdata.root_stack_top == 3000 + 8*WORD + assert self.writes == { + 3000 + 0*WORD: 10042, + 3000 + 1*WORD: 10043, + 3000 + 2*WORD: 0, + 3000 + 3*WORD: GcRootMap_shadowstack.MARKER, + 3000 + 4*WORD: 20000, + 3000 + 5*WORD: 10044, + 3000 + 6*WORD: GcRootMap_shadowstack.MARKER, + 3000 + 7*WORD: 21000, + 20032: 10132, + 20064: 10164, + 20080: 10180, + 21032: 10232, + 21048: 10248, + } + class FakeLLOp(object): def __init__(self): From noreply at buildbot.pypy.org Wed Jul 6 20:28:49 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:49 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Untested JIT support. Message-ID: <20110706182849.ABA5E820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45386:7a765de75f51 Date: 2011-06-13 10:51 +0200 http://bitbucket.org/pypy/pypy/changeset/7a765de75f51/ Log: Untested JIT support. diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -32,8 +32,7 @@ default=False, cmdline="--tealet", requires=[("translation.type_system", "lltype"), ("translation.gctransformer", "framework"), - ("translation.gcrootfinder", "shadowstack"), - ("translation.thread", False)]), # XXX temporary + ("translation.gcrootfinder", "shadowstack")]), ChoiceOption("type_system", "Type system to use when RTyping", ["lltype", "ootype"], cmdline=None, default="lltype", requires={ diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -152,13 +152,8 @@ # for regular translation: pick the GC from the config GCClass, GC_PARAMS = choose_gc_from_config(translator.config) - self.root_stack_jit_hook = None if hasattr(translator, '_jit2gc'): self.layoutbuilder = translator._jit2gc['layoutbuilder'] - try: - self.root_stack_jit_hook = translator._jit2gc['rootstackhook'] - except KeyError: - pass else: self.layoutbuilder = TransformerLayoutBuilder(translator, GCClass) self.layoutbuilder.transformer = self @@ -1372,8 +1367,10 @@ return top self.decr_stack = decr_stack - self.rootstackhook = gctransformer.root_stack_jit_hook - if self.rootstackhook is None: + self.jit2gc = getattr(gctransformer.translator, '_jit2gc', {}) + try: + self.rootstackhook = self.jit2gc['rootstackhook'] + except KeyError: def collect_stack_root(callback, gc, addr): if gc.points_to_valid_gc_object(addr): callback(gc, addr) @@ -1410,19 +1407,19 @@ self.collect_stacks_from_other_threads(collect_stack_root) def need_tealet_support(self, gctransformer, getfn): - assert not gctransformer.translator.config.translation.jit, ( - "XXX in-progress: tealet + jit + shadowstack") - assert not gctransformer.translator.config.translation.thread, ( - "XXX check me: tealet + thread + shadowstack") - # GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF)) SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed)) WALKER_PTR = lltype.Ptr(lltype.Struct('walker', ('gcptr_array', GCPTR_ARRAY), ('signed_array', SIGNED_ARRAY))) gcdata = self.gcdata + jit_save_stack_roots = self.jit2gc.get('savestackhook') + jit_restore_stack_roots = self.jit2gc.get('restorestackhook') # def ll_save_stack_roots(walker): + if jit_save_stack_roots is not None: + jit_save_stack_roots(walker, gcdata) + return addr = gcdata.root_stack_base end = gcdata.root_stack_top count = (end - addr) // sizeofaddr @@ -1434,6 +1431,9 @@ n += 1 # def ll_restore_stack_roots(walker): + if jit_restore_stack_roots is not None: + jit_restore_stack_roots(walker, gcdata) + return array = walker.gcptr_array addr = gcdata.root_stack_base gcdata.root_stack_top = addr + len(array) * sizeofaddr From noreply at buildbot.pypy.org Wed Jul 6 20:28:50 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:50 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Translation fixes. Message-ID: <20110706182850.E4254820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45387:a60fa90a4868 Date: 2011-06-13 10:02 +0000 http://bitbucket.org/pypy/pypy/changeset/a60fa90a4868/ Log: Translation fixes. diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -414,8 +414,8 @@ signed_count = 0 gcptr_array = walker.gcptr_array # - rsbase = gcdata.root_stack_base - rsend = gcdata.root_stack_top + rsbase = rffi.cast(lltype.Signed, gcdata.root_stack_base) + rsend = rffi.cast(lltype.Signed, gcdata.root_stack_top) rsaddr = rsbase while rsaddr != rsend: if read(rsaddr) != GcRootMap_shadowstack.MARKER: @@ -446,8 +446,8 @@ if offset == 0: break if gcptr_array: - addr = cast_int_to_adr(frame_addr + offset) - gcobj = cast_int_to_ptr(llmemory.GCREF, read(addr)) + obj = read(frame_addr + offset) + gcobj = cast_int_to_ptr(llmemory.GCREF, obj) gcptr_array[gcptr_count] = gcobj gcptr_count += 1 n += 1 @@ -487,7 +487,7 @@ signed_count = 0 gcptr_array = walker.gcptr_array # - rsbase = gcdata.root_stack_base + rsbase = rffi.cast(lltype.Signed, gcdata.root_stack_base) rsaddr = rsbase rsmarker = rsbase + walker.signed_array[signed_count] signed_count += 1 @@ -520,16 +520,15 @@ offset = rffi.cast(lltype.Signed, callshape[n]) if offset == 0: break - addr = cast_int_to_adr(frame_addr + offset) gcobj = gcptr_array[gcptr_count] - write(addr, cast_ptr_to_int(gcobj)) + write(frame_addr + offset, cast_ptr_to_int(gcobj)) gcptr_count += 1 n += 1 # rsmarker = rsbase + walker.signed_array[signed_count+2] signed_count += 3 # - gcdata.root_stack_top = rsmarker + gcdata.root_stack_top = cast_int_to_adr(rsmarker) ll_assert(signed_count == len(walker.signed_array), "restoring bogus stack signed count") ll_assert(gcptr_count == len(walker.gcptr_array), From noreply at buildbot.pypy.org Wed Jul 6 20:28:52 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:52 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Fix: need to make the shadowstack empty here. Message-ID: <20110706182852.2B8B4820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45388:039300a3c9b2 Date: 2011-06-13 12:34 +0200 http://bitbucket.org/pypy/pypy/changeset/039300a3c9b2/ Log: Fix: need to make the shadowstack empty here. diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1419,16 +1419,17 @@ def ll_save_stack_roots(walker): if jit_save_stack_roots is not None: jit_save_stack_roots(walker, gcdata) - return - addr = gcdata.root_stack_base - end = gcdata.root_stack_top - count = (end - addr) // sizeofaddr - walker.gcptr_array = array = lltype.malloc(GCPTR_ARRAY.TO, count) - n = 0 - while n < len(array): - array[n] = llmemory.cast_adr_to_ptr(addr.address[n], - llmemory.GCREF) - n += 1 + else: + addr = gcdata.root_stack_base + end = gcdata.root_stack_top + count = (end - addr) // sizeofaddr + walker.gcptr_array = array = lltype.malloc(GCPTR_ARRAY.TO,count) + n = 0 + while n < len(array): + array[n] = llmemory.cast_adr_to_ptr(addr.address[n], + llmemory.GCREF) + n += 1 + gcdata.root_stack_top = gcdata.root_stack_base # make it empty # def ll_restore_stack_roots(walker): if jit_restore_stack_roots is not None: From noreply at buildbot.pypy.org Wed Jul 6 20:28:54 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:54 +0200 (CEST) Subject: [pypy-commit] pypy tealet: hg merge default Message-ID: <20110706182854.3BEC5820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45389:11a6f13ccc0c Date: 2011-06-13 20:42 +0200 http://bitbucket.org/pypy/pypy/changeset/11a6f13ccc0c/ Log: hg merge default diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py --- a/lib_pypy/datetime.py +++ b/lib_pypy/datetime.py @@ -1422,12 +1422,17 @@ converter = _time.localtime else: converter = _time.gmtime - if 1 - (t % 1.0) < 0.000001: - t = float(int(t)) + 1 - if t < 0: - t -= 1 + if t < 0.0: + us = int(round(((-t) % 1.0) * 1000000)) + if us > 0: + us = 1000000 - us + t -= 1.0 + else: + us = int(round((t % 1.0) * 1000000)) + if us == 1000000: + us = 0 + t += 1.0 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) - us = int((t % 1.0) * 1000000) ss = min(ss, 59) # clamp out leap seconds if the platform has them result = cls(y, m, d, hh, mm, ss, us, tz) if tz is not None: diff --git a/lib_pypy/msvcrt.py b/lib_pypy/msvcrt.py --- a/lib_pypy/msvcrt.py +++ b/lib_pypy/msvcrt.py @@ -46,4 +46,42 @@ e = get_errno() raise IOError(e, errno.errorcode[e]) +# Console I/O routines + +kbhit = _c._kbhit +kbhit.argtypes = [] +kbhit.restype = ctypes.c_int + +getch = _c._getch +getch.argtypes = [] +getch.restype = ctypes.c_char + +getwch = _c._getwch +getwch.argtypes = [] +getwch.restype = ctypes.c_wchar + +getche = _c._getche +getche.argtypes = [] +getche.restype = ctypes.c_char + +getwche = _c._getwche +getwche.argtypes = [] +getwche.restype = ctypes.c_wchar + +putch = _c._putch +putch.argtypes = [ctypes.c_char] +putch.restype = None + +putwch = _c._putwch +putwch.argtypes = [ctypes.c_wchar] +putwch.restype = None + +ungetch = _c._ungetch +ungetch.argtypes = [ctypes.c_char] +ungetch.restype = None + +ungetwch = _c._ungetwch +ungetwch.argtypes = [ctypes.c_wchar] +ungetwch.restype = None + del ctypes diff --git a/lib_pypy/pypy_test/test_datetime.py b/lib_pypy/pypy_test/test_datetime.py --- a/lib_pypy/pypy_test/test_datetime.py +++ b/lib_pypy/pypy_test/test_datetime.py @@ -32,4 +32,28 @@ assert datetime.datetime.utcfromtimestamp(a).microsecond == 0 assert datetime.datetime.utcfromtimestamp(a).second == 1 - +def test_more_datetime_rounding(): + # this test verified on top of CPython 2.7 (using a plain + # "import datetime" above) + expected_results = { + -1000.0: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.9999996: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.4: 'datetime.datetime(1970, 1, 1, 0, 43, 20, 600000)', + -999.0000004: 'datetime.datetime(1970, 1, 1, 0, 43, 21)', + -1.0: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.9999996: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.4: 'datetime.datetime(1970, 1, 1, 0, 59, 59, 600000)', + -0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.4: 'datetime.datetime(1970, 1, 1, 1, 0, 0, 400000)', + 0.9999996: 'datetime.datetime(1970, 1, 1, 1, 0, 1)', + 1000.0: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.0000004: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.4: 'datetime.datetime(1970, 1, 1, 1, 16, 40, 400000)', + 1000.9999996: 'datetime.datetime(1970, 1, 1, 1, 16, 41)', + 1293843661.191: 'datetime.datetime(2011, 1, 1, 2, 1, 1, 191000)', + } + for t in sorted(expected_results): + dt = datetime.datetime.fromtimestamp(t) + assert repr(dt) == expected_results[t] diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -84,6 +84,7 @@ "_rawffi": [("objspace.usemodules.struct", True)], "cpyext": [("translation.secondaryentrypoints", "cpyext"), ("translation.shared", sys.platform == "win32")], + "_ffi": [("translation.jit_ffi", True)], } module_import_dependencies = { diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py --- a/pypy/config/test/test_pypyoption.py +++ b/pypy/config/test/test_pypyoption.py @@ -73,3 +73,7 @@ fn = prefix + "." + path + ".txt" yield check_file_exists, fn +def test__ffi_opt(): + config = get_pypy_config(translating=True) + config.objspace.usemodules._ffi = True + assert config.translation.jit_ffi diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -122,6 +122,8 @@ ChoiceOption("jit_profiler", "integrate profiler support into the JIT", ["off", "oprofile"], default="off"), + # jit_ffi is automatically turned on by withmod-_ffi (which is enabled by default) + BoolOption("jit_ffi", "optimize libffi calls", default=False, cmdline=None), # misc BoolOption("verbose", "Print extra information", default=False), diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -1,5 +1,6 @@ import py from pypy.rpython.lltypesystem import lltype, rffi, llmemory, rclass +from pypy.rpython.lltypesystem.lloperation import llop from pypy.jit.backend.llsupport import symbolic, support from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr from pypy.jit.metainterp.history import BasicFailDescr, LoopToken, BoxFloat @@ -45,6 +46,8 @@ size = 0 # help translation is_immutable = False + tid = llop.combine_ushort(lltype.Signed, 0, 0) + def __init__(self, size, count_fields_if_immut=-1): self.size = size self.count_fields_if_immut = count_fields_if_immut @@ -149,6 +152,7 @@ class BaseArrayDescr(AbstractDescr): _clsname = '' + tid = llop.combine_ushort(lltype.Signed, 0, 0) def get_base_size(self, translate_support_code): basesize, _, _ = symbolic.get_array_token(_A, translate_support_code) diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -694,7 +694,7 @@ self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType( [llmemory.Address, llmemory.Address], lltype.Void)) self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType( - [llmemory.Address, lltype.Signed], lltype.Void)) + [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void)) self.write_barrier_descr = WriteBarrierDescr(self) # def malloc_array(itemsize, tid, num_elem): @@ -905,10 +905,8 @@ newops.append(op) return newops - def _gen_write_barrier(self, newops, v_base, v_value_or_index): - # NB. the 2nd argument of COND_CALL_GC_WB is either a pointer - # (regular case), or an index (case of write_barrier_from_array) - args = [v_base, v_value_or_index] + def _gen_write_barrier(self, newops, v_base, v_value): + args = [v_base, v_value] newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None, descr=self.write_barrier_descr)) @@ -922,7 +920,10 @@ length = known_lengths.get(v_base, LARGE) if length >= LARGE: # unknown or too big: produce a write_barrier_from_array - self._gen_write_barrier(newops, v_base, v_index) + args = [v_base, v_value, v_index] + newops.append(ResOperation(rop.COND_CALL_GC_WB_ARRAY, args, + None, + descr=self.write_barrier_descr)) return # fall-back case: produce a write_barrier self._gen_write_barrier(newops, v_base, v_value) diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py --- a/pypy/jit/backend/llsupport/test/test_gc.py +++ b/pypy/jit/backend/llsupport/test/test_gc.py @@ -709,12 +709,15 @@ del operations[:2] assert len(operations) == 2 # - assert operations[0].getopnum() == rop.COND_CALL_GC_WB - assert operations[0].getarg(0) == v_base if isinstance(v_new_length, ConstInt) and v_new_length.value < 130: + assert operations[0].getopnum() == rop.COND_CALL_GC_WB + assert operations[0].getarg(0) == v_base assert operations[0].getarg(1) == v_value else: - assert operations[0].getarg(1) == v_index + assert operations[0].getopnum() == rop.COND_CALL_GC_WB_ARRAY + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_value + assert operations[0].getarg(2) == v_index assert operations[0].result is None # assert operations[1].getopnum() == rop.SETARRAYITEM_RAW diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -2223,15 +2223,26 @@ def genop_discard_cond_call_gc_wb(self, op, arglocs): # Write code equivalent to write_barrier() in the GC: it checks # a flag in the object at arglocs[0], and if set, it calls the - # function remember_young_pointer() from the GC. The two arguments - # to the call are in arglocs[:2]. The rest, arglocs[2:], contains + # function remember_young_pointer() from the GC. The arguments + # to the call are in arglocs[:N]. The rest, arglocs[N:], contains # registers that need to be saved and restored across the call. - # If op.getarg(1) is a int, it is an array index and we must call - # instead remember_young_pointer_from_array(). + # N is either 2 (regular write barrier) or 3 (array write barrier). descr = op.getdescr() if we_are_translated(): cls = self.cpu.gc_ll_descr.has_write_barrier_class() assert cls is not None and isinstance(descr, cls) + # + opnum = op.getopnum() + if opnum == rop.COND_CALL_GC_WB: + N = 2 + func = descr.get_write_barrier_fn(self.cpu) + elif opnum == rop.COND_CALL_GC_WB_ARRAY: + N = 3 + func = descr.get_write_barrier_from_array_fn(self.cpu) + assert func != 0 + else: + raise AssertionError(opnum) + # loc_base = arglocs[0] self.mc.TEST8(addr_add_const(loc_base, descr.jit_wb_if_flag_byteofs), imm(descr.jit_wb_if_flag_singlebyte)) @@ -2242,29 +2253,27 @@ if IS_X86_32: limit = -1 # push all arglocs on the stack elif IS_X86_64: - limit = 1 # push only arglocs[2:] on the stack + limit = N - 1 # push only arglocs[N:] on the stack for i in range(len(arglocs)-1, limit, -1): loc = arglocs[i] if isinstance(loc, RegLoc): self.mc.PUSH_r(loc.value) else: - assert not IS_X86_64 # there should only be regs in arglocs[2:] + assert not IS_X86_64 # there should only be regs in arglocs[N:] self.mc.PUSH_i32(loc.getint()) if IS_X86_64: # We clobber these registers to pass the arguments, but that's # okay, because consider_cond_call_gc_wb makes sure that any # caller-save registers with values in them are present in - # arglocs[2:] too, so they are saved on the stack above and + # arglocs[N:] too, so they are saved on the stack above and # restored below. - remap_frame_layout(self, arglocs[:2], [edi, esi], + if N == 2: + callargs = [edi, esi] + else: + callargs = [edi, esi, edx] + remap_frame_layout(self, arglocs[:N], callargs, X86_64_SCRATCH_REG) - - if op.getarg(1).type == INT: - func = descr.get_write_barrier_from_array_fn(self.cpu) - assert func != 0 - else: - func = descr.get_write_barrier_fn(self.cpu) - + # # misaligned stack in the call, but it's ok because the write barrier # is not going to call anything more. Also, this assumes that the # write barrier does not touch the xmm registers. (Slightly delicate @@ -2273,8 +2282,8 @@ # be done properly) self.mc.CALL(imm(func)) if IS_X86_32: - self.mc.ADD_ri(esp.value, 2*WORD) - for i in range(2, len(arglocs)): + self.mc.ADD_ri(esp.value, N*WORD) + for i in range(N, len(arglocs)): loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) @@ -2283,6 +2292,8 @@ assert 0 < offset <= 127 self.mc.overwrite(jz_location-1, chr(offset)) + genop_discard_cond_call_gc_wb_array = genop_discard_cond_call_gc_wb + def genop_force_token(self, op, arglocs, resloc): # RegAlloc.consider_force_token ensures this: assert isinstance(resloc, RegLoc) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -884,12 +884,18 @@ def consider_cond_call_gc_wb(self, op): assert op.result is None args = op.getarglist() - loc_newvalue_or_index= self.rm.make_sure_var_in_reg(op.getarg(1), args) - # ^^^ we force loc_newvalue_or_index in a reg (unless it's a Const), + loc_newvalue = self.rm.make_sure_var_in_reg(op.getarg(1), args) + # ^^^ we force loc_newvalue in a reg (unless it's a Const), # because it will be needed anyway by the following setfield_gc. # It avoids loading it twice from the memory. loc_base = self.rm.make_sure_var_in_reg(op.getarg(0), args) - arglocs = [loc_base, loc_newvalue_or_index] + # + if len(args) == 2: + arglocs = [loc_base, loc_newvalue] # cond_call_gc_wb + else: + # cond_call_gc_wb_array + loc_arrayindex = self.rm.make_sure_var_in_reg(op.getarg(2), args) + arglocs = [loc_base, loc_newvalue, loc_arrayindex] # add eax, ecx and edx as extra "arguments" to ensure they are # saved and restored. Fish in self.rm to know which of these # registers really need to be saved (a bit of a hack). Moreover, @@ -903,6 +909,8 @@ self.PerformDiscard(op, arglocs) self.rm.possibly_free_vars_for_op(op) + consider_cond_call_gc_wb_array = consider_cond_call_gc_wb + def fastpath_malloc_fixedsize(self, op, descr): assert isinstance(descr, BaseSizeDescr) self._do_fastpath_malloc(op, descr.size, descr.tid) diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -316,6 +316,7 @@ if value in (rop.FORCE_TOKEN, rop.CALL_ASSEMBLER, rop.COND_CALL_GC_WB, + rop.COND_CALL_GC_WB_ARRAY, rop.DEBUG_MERGE_POINT, rop.JIT_DEBUG, rop.SETARRAYITEM_RAW, diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -1063,8 +1063,6 @@ Explodes if the annotator only thinks it is an instance of AbstractValue. """ if x is not None: - if not we_are_translated() and getattr(x, 'I_am_a_descr', False): - return # needed for the mock case in oparser_model assert isinstance(x, AbstractDescr) class Entry(ExtRegistryEntry): diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -15,7 +15,7 @@ ('virtualize', OptVirtualize), ('string', OptString), ('heap', OptHeap), - ('ffi', OptFfiCall), + ('ffi', None), ('unroll', None)] # no direct instantiation of unroll unroll_all_opts = unrolling_iterable(ALL_OPTS) @@ -25,10 +25,9 @@ ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) PARAMETERS['enable_opts'] = ALL_OPTS_NAMES -def optimize_loop_1(metainterp_sd, loop, enable_opts, +def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): - """Optimize loop.operations to remove internal overheadish operations. - """ + config = metainterp_sd.config optimizations = [] unroll = 'unroll' in enable_opts for name, opt in unroll_all_opts: @@ -40,6 +39,11 @@ # FIXME: Workaround to disable string optimisation # during preamble but to keep it during the loop optimizations.append(o) + elif name == 'ffi' and config.translation.jit_ffi: + # we cannot put the class directly in the unrolling_iterable, + # because we do not want it to be seen at all (to avoid to + # introduce a dependency on libffi in case we do not need it) + optimizations.append(OptFfiCall()) if ('rewrite' not in enable_opts or 'virtualize' not in enable_opts or 'heap' not in enable_opts): @@ -48,6 +52,17 @@ if inline_short_preamble: optimizations = [OptInlineShortPreamble(retraced)] + optimizations + return optimizations, unroll + + +def optimize_loop_1(metainterp_sd, loop, enable_opts, + inline_short_preamble=True, retraced=False): + """Optimize loop.operations to remove internal overheadish operations. + """ + + optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, + inline_short_preamble, retraced) + if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1262,8 +1262,7 @@ logger_ops = None def __init__(self, cpu, options, - ProfilerClass=EmptyProfiler, warmrunnerdesc=None, - jit_ffi=True): + ProfilerClass=EmptyProfiler, warmrunnerdesc=None): self.cpu = cpu self.stats = self.cpu.stats self.options = options @@ -1273,7 +1272,11 @@ self.profiler = ProfilerClass() self.profiler.cpu = cpu self.warmrunnerdesc = warmrunnerdesc - self.jit_ffi = jit_ffi + if warmrunnerdesc: + self.config = warmrunnerdesc.translator.config + else: + from pypy.config.pypyoption import get_pypy_config + self.config = get_pypy_config(translating=True) backendmodule = self.cpu.__module__ backendmodule = backendmodule.split('.')[-2] diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -191,9 +191,15 @@ # of the operation. It must inherit from AbstractDescr. The # backend provides it with cpu.fielddescrof(), cpu.arraydescrof(), # cpu.calldescrof(), and cpu.typedescrof(). + self._check_descr(descr) + self._descr = descr + + def _check_descr(self, descr): + if not we_are_translated() and getattr(descr, 'I_am_a_descr', False): + return # needed for the mock case in oparser_model from pypy.jit.metainterp.history import check_descr check_descr(descr) - self._descr = descr + class GuardResOp(ResOpWithDescr): @@ -471,8 +477,8 @@ 'STRSETITEM/3', 'UNICODESETITEM/3', #'RUNTIMENEW/1', # ootype operation - 'COND_CALL_GC_WB/2d', # [objptr, newvalue] or [arrayptr, index] - # (for the write barrier, latter is in an array) + 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier) + 'COND_CALL_GC_WB_ARRAY/3d', # [objptr, newvalue, arrayindex] (write barr.) 'DEBUG_MERGE_POINT/*', # debugging only 'JIT_DEBUG/*', # debugging only 'VIRTUAL_REF_FINISH/2', # removed before it's passed to the backend diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py --- a/pypy/jit/metainterp/test/test_compile.py +++ b/pypy/jit/metainterp/test/test_compile.py @@ -61,7 +61,6 @@ stats = Stats() profiler = jitprof.EmptyProfiler() warmrunnerdesc = None - jit_ffi = False def log(self, msg, event_kind=None): pass diff --git a/pypy/jit/metainterp/test/test_optimizebasic.py b/pypy/jit/metainterp/test/test_optimizebasic.py --- a/pypy/jit/metainterp/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/test/test_optimizebasic.py @@ -232,7 +232,7 @@ class BaseTestBasic(BaseTest): - def invent_fail_descr(self, fail_args): + def invent_fail_descr(self, model, fail_args): if fail_args is None: return None descr = Storage() diff --git a/pypy/jit/metainterp/test/test_optimizefficall.py b/pypy/jit/metainterp/test/test_optimizefficall.py --- a/pypy/jit/metainterp/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/test/test_optimizefficall.py @@ -32,7 +32,6 @@ class TestFfiCall(BaseTestBasic, LLtypeMixin): - jit_ffi = True class namespace: cpu = LLtypeMixin.cpu diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py --- a/pypy/jit/metainterp/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/test/test_optimizeopt.py @@ -5,7 +5,7 @@ BaseTest) import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT +from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT, build_opt_chain from pypy.jit.metainterp.optimizeutil import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp.history import TreeLoop, LoopToken @@ -15,6 +15,7 @@ from pypy.jit.tool.oparser import pure_parse from pypy.jit.metainterp.test.test_optimizebasic import equaloplists from pypy.jit.metainterp.optimizeutil import args_dict +from pypy.config.pypyoption import get_pypy_config class Fake(object): failargs_limit = 1000 @@ -22,12 +23,48 @@ class FakeMetaInterpStaticData(object): - def __init__(self, cpu, jit_ffi=False): + def __init__(self, cpu): self.cpu = cpu self.profiler = EmptyProfiler() self.options = Fake() self.globaldata = Fake() - self.jit_ffi = jit_ffi + self.config = get_pypy_config(translating=True) + self.config.translation.jit_ffi = True + + +def test_build_opt_chain(): + def check(chain, expected_names): + names = [opt.__class__.__name__ for opt in chain] + assert names == expected_names + # + metainterp_sd = FakeMetaInterpStaticData(None) + chain, _ = build_opt_chain(metainterp_sd, "", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "heap:intbounds") + check(chain, ["OptInlineShortPreamble", "OptIntBounds", "OptHeap", "OptSimplify"]) + # + chain, unroll = build_opt_chain(metainterp_sd, "unroll") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + assert unroll + # + chain, _ = build_opt_chain(metainterp_sd, "aaa:bbb", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptFfiCall", "OptSimplify"]) + # + metainterp_sd.config = get_pypy_config(translating=True) + assert not metainterp_sd.config.translation.jit_ffi + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + def test_store_final_boxes_in_guard(): from pypy.jit.metainterp.compile import ResumeGuardDescr @@ -143,9 +180,8 @@ return sorted(boxes, key=lambda box: _kind2count[box.type]) class BaseTestOptimizeOpt(BaseTest): - jit_ffi = False - - def invent_fail_descr(self, fail_args): + + def invent_fail_descr(self, model, fail_args): if fail_args is None: return None descr = Storage() @@ -180,7 +216,7 @@ loop.preamble = TreeLoop('preamble') loop.preamble.inputargs = loop.inputargs loop.preamble.token = LoopToken() - metainterp_sd = FakeMetaInterpStaticData(self.cpu, self.jit_ffi) + metainterp_sd = FakeMetaInterpStaticData(self.cpu) if hasattr(self, 'vrefinfo'): metainterp_sd.virtualref_info = self.vrefinfo if hasattr(self, 'callinfocollection'): diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -46,9 +46,8 @@ return FORCE_SPILL(self.OPNUM, self.getarglist()[:]) -def default_fail_descr(fail_args=None): - from pypy.jit.metainterp.history import BasicFailDescr - return BasicFailDescr() +def default_fail_descr(model, fail_args=None): + return model.BasicFailDescr() class OpParser(object): @@ -237,14 +236,14 @@ "Unknown var in fail_args: %s" % arg) fail_args.append(fail_arg) if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr(fail_args) + descr = self.invent_fail_descr(self.model, fail_args) if hasattr(descr, '_oparser_uses_descr_of_guard'): descr._oparser_uses_descr_of_guard(self, fail_args) else: fail_args = None if opnum == rop.FINISH: if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr() + descr = self.invent_fail_descr(self.model) elif opnum == rop.JUMP: if descr is None and self.invent_fail_descr: descr = self.looptoken diff --git a/pypy/jit/tool/oparser_model.py b/pypy/jit/tool/oparser_model.py --- a/pypy/jit/tool/oparser_model.py +++ b/pypy/jit/tool/oparser_model.py @@ -6,6 +6,7 @@ from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.jit.metainterp.history import Box, BoxInt, BoxFloat from pypy.jit.metainterp.history import ConstInt, ConstObj, ConstPtr, ConstFloat + from pypy.jit.metainterp.history import BasicFailDescr from pypy.jit.metainterp.typesystem import llhelper from pypy.jit.metainterp.history import get_const_ptr_for_string @@ -41,6 +42,9 @@ class LoopToken(object): I_am_a_descr = True + class BasicFailDescr(object): + I_am_a_descr = True + class Box(object): _counter = 0 type = 'b' diff --git a/pypy/jit/tool/test/test_oparser.py b/pypy/jit/tool/test/test_oparser.py --- a/pypy/jit/tool/test/test_oparser.py +++ b/pypy/jit/tool/test/test_oparser.py @@ -1,4 +1,5 @@ import py +import sys from pypy.rpython.lltypesystem import lltype, llmemory from pypy.jit.tool.oparser import parse, OpParser @@ -42,7 +43,7 @@ def test_descr(self): class Xyz(AbstractDescr): - pass + I_am_a_descr = True # for the mock case x = """ [p0] @@ -63,7 +64,7 @@ def test_descr_setfield(self): class Xyz(AbstractDescr): - pass + I_am_a_descr = True # for the mock case x = """ [p0] @@ -122,6 +123,7 @@ def test_jump_target_other(self): looptoken = LoopToken() + looptoken.I_am_a_descr = True # for the mock case x = ''' [] jump(descr=looptoken) @@ -242,8 +244,31 @@ assert isinstance(b.sum0, BoxInt) +class ForbiddenModule(object): + def __init__(self, name, old_mod): + self.name = name + self.old_mod = old_mod + + def __getattr__(self, attr): + assert False, "You should not import module %s" % self.name + class TestOpParserWithMock(BaseTestOparser): class OpParser(OpParser): use_mock_model = True + + def setup_class(cls): + forbidden_mods = [ + 'pypy.jit.metainterp.history', + 'pypy.rpython.lltypesystem.lltype', + ] + for modname in forbidden_mods: + if modname in sys.modules: + newmod = ForbiddenModule(modname, sys.modules[modname]) + sys.modules[modname] = newmod + + def teardown_class(cls): + for modname, mod in sys.modules.iteritems(): + if isinstance(mod, ForbiddenModule): + sys.modules[modname] = mod.old_mod diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -526,15 +526,7 @@ def array_tostring__Array(space, self): cbuf = self.charbuf() - s = ''.join([cbuf[i] for i in xrange(self.len * mytype.bytes)]) - return self.space.wrap(s) -## -## s = '' -## i = 0 -## while i < self.len * mytype.bytes: -## s += cbuf[i] -## i += 1 -## return self.space.wrap(s) + return self.space.wrap(rffi.charpsize2str(cbuf, self.len * mytype.bytes)) def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): if not isinstance(w_f, W_File): diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -8,6 +8,7 @@ interpleveldefs = { 'array': 'interp_numarray.SingleDimArray', 'zeros': 'interp_numarray.zeros', + 'empty': 'interp_numarray.zeros', # ufuncs 'absolute': 'interp_ufuncs.absolute', diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/compile.py @@ -0,0 +1,49 @@ + +""" This is a set of tools for standalone compiling of numpy expressions. +It should not be imported by the module itself +""" + +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray + +class BogusBytecode(Exception): + pass + +def create_array(size): + a = SingleDimArray(size) + for i in range(size): + a.storage[i] = float(i % 10) + return a + +class TrivialSpace(object): + def wrap(self, x): + return x + +def numpy_compile(bytecode, array_size): + space = TrivialSpace() + stack = [] + i = 0 + for b in bytecode: + if b == 'a': + stack.append(create_array(array_size)) + i += 1 + elif b == 'f': + stack.append(FloatWrapper(1.2)) + elif b == '+': + right = stack.pop() + stack.append(stack.pop().descr_add(space, right)) + elif b == '-': + right = stack.pop() + stack.append(stack.pop().descr_sub(space, right)) + elif b == '*': + right = stack.pop() + stack.append(stack.pop().descr_mul(space, right)) + elif b == '/': + right = stack.pop() + stack.append(stack.pop().descr_div(space, right)) + else: + print "Unknown opcode: %s" % b + raise BogusBytecode() + if len(stack) != 1: + print "Bogus bytecode, uneven stack length" + raise BogusBytecode() + return stack[0] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -46,7 +46,7 @@ def invalidated(self): for arr in self.invalidates: arr.force_if_needed() - self.invalidates = [] + del self.invalidates[:] def _binop_impl(function): signature = Signature() @@ -83,16 +83,22 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - return self.get_concrete().descr_getitem(space, item) + def descr_getitem(self, space, w_idx): + # TODO: indexing by tuples + start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) + if step == 0: + # Single index + return space.wrap(self.get_concrete().getitem(start)) + else: + # Slice + res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) + return space.wrap(res) @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): self.invalidated() return self.get_concrete().descr_setitem(space, item, value) - class FloatWrapper(BaseArray): """ Intermediate class representing a float literal. @@ -119,6 +125,10 @@ self.forced_result = None self.signature = signature + def _del_sources(self): + # Function for deleting references to source arrays, to allow garbage-collecting them + raise NotImplementedError + def compute(self): i = 0 signature = self.signature @@ -135,6 +145,7 @@ def force_if_needed(self): if self.forced_result is None: self.forced_result = self.compute() + self._del_sources() def get_concrete(self): self.force_if_needed() @@ -145,6 +156,13 @@ return self.forced_result.eval(i) return self._eval(i) + def find_size(self): + if self.forced_result is not None: + # The result has been computed and sources may be unavailable + return self.forced_result.find_size() + return self._find_size() + + class Call1(VirtualArray): _immutable_fields_ = ["function", "values"] @@ -153,7 +171,10 @@ self.function = function self.values = values - def find_size(self): + def _del_sources(self): + self.values = None + + def _find_size(self): return self.values.find_size() def _eval(self, i): @@ -170,7 +191,11 @@ self.left = left self.right = right - def find_size(self): + def _del_sources(self): + self.left = None + self.right = None + + def _find_size(self): try: return self.left.find_size() except ValueError: @@ -181,6 +206,53 @@ lhs, rhs = self.left.eval(i), self.right.eval(i) return self.function(lhs, rhs) +class ViewArray(BaseArray): + """ + Class for representing views of arrays, they will reflect changes of parrent arrays. Example: slices + """ + _immutable_fields_ = ["parent"] + def __init__(self, parent, signature): + BaseArray.__init__(self) + self.signature = signature + self.parent = parent + self.invalidates = parent.invalidates + + def get_concrete(self): + return self # in fact, ViewArray never gets "concrete" as it never stores data. This implementation is needed for BaseArray getitem/setitem to work, can be refactored. + + def eval(self, i): + return self.parent.eval(self.calc_index(i)) + + def getitem(self, item): + return self.parent.getitem(self.calc_index(item)) + + @unwrap_spec(item=int, value=float) + def descr_setitem(self, space, item, value): + return self.parent.descr_setitem(space, self.calc_index(item), value) + + def descr_len(self, space): + return space.wrap(self.find_size()) + + def calc_index(self, item): + raise NotImplementedError + +class SingleDimSlice(ViewArray): + _immutable_fields_ = ["start", "stop", "step", "size"] + static_signature = Signature() + + def __init__(self, start, stop, step, slice_length, parent, signature): + ViewArray.__init__(self, parent, signature) + self.start = start + self.stop = stop + self.step = step + self.size = slice_length + + def find_size(self): + return self.size + + def calc_index(self, item): + return (self.start + item * self.step) + class SingleDimArray(BaseArray): signature = Signature() @@ -215,10 +287,8 @@ def descr_len(self, space): return space.wrap(self.size) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - item = self.getindex(space, item) - return space.wrap(self.storage[item]) + def getitem(self, item): + return self.storage[item] @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): @@ -254,4 +324,4 @@ __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), __div__ = interp2app(BaseArray.descr_div), -) \ No newline at end of file +) diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -16,4 +16,14 @@ v3 = ar.descr_add(space, FloatWrapper(1.0)) assert v2.signature is v3.signature v4 = ar.descr_add(space, ar) - assert v1.signature is v4.signature \ No newline at end of file + assert v1.signature is v4.signature + + def test_slice_signature(self, space): + ar = SingleDimArray(10) + v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1))) + v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1))) + assert v1.signature is v2.signature + + v3 = ar.descr_add(space, v1) + v4 = ar.descr_add(space, v2) + assert v3.signature is v4.signature \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,6 +18,16 @@ a[13] = 5.3 assert a[13] == 5.3 + def test_empty(self): + """ + Test that empty() works. + """ + + from numpy import empty + a = empty(2) + a[1] = 1.0 + assert a[1] == 1.0 + def test_iterator_init(self): from numpy import array a = array(range(5)) @@ -138,4 +148,46 @@ b = a + a c = b + b b[1] = 5 - assert c[1] == 4 \ No newline at end of file + assert c[1] == 4 + + def test_getslice(self): + from numpy import array + a = array(range(5)) + s = a[1:5] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[i+1] + + def test_getslice_step(self): + from numpy import array + a = array(range(10)) + s = a[1:9:2] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[2*i+1] + + def test_slice_update(self): + from numpy import array + a = array(range(5)) + s = a[0:3] + s[1] = 10 + assert a[1] == 10 + a[2] = 20 + assert s[2] == 20 + + + def test_slice_invaidate(self): + # check that slice shares invalidation list with + from numpy import array + a = array(range(5)) + s = a[0:2] + b = array([10,11]) + c = s + b + a[0]=100 + assert c[0] == 10 + assert c[1] == 12 + d = s + b + a[1]=101 + assert d[0] == 110 + assert d[1] == 12 + diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,8 +1,9 @@ from pypy.jit.metainterp.test.support import LLJitMixin +from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call1, Call2, add, mul) + FloatWrapper, Call1, Call2, SingleDimSlice, add, mul) from pypy.module.micronumpy.interp_ufuncs import negative - +from pypy.module.micronumpy.compile import numpy_compile class FakeSpace(object): pass @@ -91,4 +92,54 @@ self.meta_interp(f, [5], listops=True, backendopt=True) # This is 3, not 2 because there is a bridge for the exit. - self.check_loop_count(3) \ No newline at end of file + self.check_loop_count(3) + + def test_slice(self): + space = self.space + + def f(i): + step = 3 + ar = SingleDimArray(step*i) + s = SingleDimSlice(0, step*i, step, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s, s, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 1, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + + def test_slice2(self): + space = self.space + + def f(i): + step1 = 2 + step2 = 3 + ar = SingleDimArray(step2*i) + s1 = SingleDimSlice(0, step1*i, step1, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + s2 = SingleDimSlice(0, step2*i, step2, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s1, s2, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 2, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + +class TestTranslation(object): + def test_compile(self): + x = numpy_compile('aa+f*f/a-', 10) + x = x.compute() + assert isinstance(x, SingleDimArray) + assert x.size == 10 + assert x.storage[0] == 0 + assert x.storage[1] == ((1 + 1) * 1.2) / 1.2 - 1 + + def test_translation(self): + # we import main to check if the target compiles + from pypy.translator.goal.targetnumpystandalone import main + from pypy.rpython.annlowlevel import llstr + + interpret(main, [llstr('af+'), 100]) diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py --- a/pypy/rlib/clibffi.py +++ b/pypy/rlib/clibffi.py @@ -18,6 +18,10 @@ import sys import ctypes.util +from pypy.tool.ansi_print import ansi_log +log = py.log.Producer("libffi") +py.log.setconsumer("libffi", ansi_log) + # maaaybe isinstance here would be better. Think _MSVC = platform.name == "msvc" _MINGW = platform.name == "mingw32" @@ -67,12 +71,17 @@ result = os.path.join(dir, 'libffi.a') if os.path.exists(result): return result - raise ImportError("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("trying to use the dynamic library instead...") + return None + path_libffi_a = None if hasattr(platform, 'library_dirs_for_libffi_a'): + path_libffi_a = find_libffi_a() + if path_libffi_a is not None: # platforms on which we want static linking libraries = [] - link_files = [find_libffi_a()] + link_files = [path_libffi_a] else: # platforms on which we want dynamic linking libraries = ['ffi'] diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -134,7 +134,8 @@ def external(name, argtypes, restype, **kw): kw['compilation_info'] = eci - eci.export_symbols += (name,) + if not kw.get('macro', False): + eci.export_symbols += (name,) return rffi.llexternal( name, argtypes, restype, **kw) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -139,10 +139,10 @@ source = py.code.Source(""" def call_external_function(%(argnames)s): before = aroundstate.before - after = aroundstate.after if before: before() # NB. it is essential that no exception checking occurs here! res = funcptr(%(argnames)s) + after = aroundstate.after if after: after() return res """ % locals()) @@ -262,13 +262,9 @@ def wrapper(%s): # no *args - no GIL for mallocing the tuple llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py if aroundstate is not None: - before = aroundstate.before after = aroundstate.after - else: - before = None - after = None - if after: - after() + if after: + after() # from now on we hold the GIL stackcounter.stacks_counter += 1 try: @@ -282,8 +278,10 @@ traceback.print_exc() result = errorcode stackcounter.stacks_counter -= 1 - if before: - before() + if aroundstate is not None: + before = aroundstate.before + if before: + before() # here we don't hold the GIL any more. As in the wrapper() produced # by llexternal, it is essential that no exception checking occurs # after the call to before(). diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -927,7 +927,7 @@ def write_barrier_from_array(self, newvalue, addr_array, index): if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded - self.remember_young_pointer_from_array(addr_array, index) + self.remember_young_pointer_from_array2(addr_array, index) else: self.remember_young_pointer(addr_array, newvalue) @@ -976,7 +976,7 @@ def _init_writebarrier_with_card_marker(self): DEBUG = self.DEBUG - def remember_young_pointer_from_array(addr_array, index): + def remember_young_pointer_from_array2(addr_array, index): # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. @@ -1011,7 +1011,7 @@ # # We set the flag (even if the newly written address does not # actually point to the nursery, which seems to be ok -- actually - # it seems more important that remember_young_pointer_from_array() + # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) # @@ -1019,10 +1019,67 @@ self.old_objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET - remember_young_pointer_from_array._dont_inline_ = True + remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 - self.remember_young_pointer_from_array = ( - remember_young_pointer_from_array) + self.remember_young_pointer_from_array2 = ( + remember_young_pointer_from_array2) + + # xxx trying it out for the JIT: a 3-arguments version of the above + def remember_young_pointer_from_array3(addr_array, index, newvalue): + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with GCFLAG_NO_YOUNG_PTRS") + objhdr = self.header(addr_array) + # + # a single check for the common case of neither GCFLAG_HAS_CARDS + # nor GCFLAG_NO_HEAP_PTRS + if objhdr.tid & (GCFLAG_HAS_CARDS | GCFLAG_NO_HEAP_PTRS) == 0: + # common case: fast path, jump to the end of the function + pass + elif objhdr.tid & GCFLAG_HAS_CARDS == 0: + # no cards, but GCFLAG_NO_HEAP_PTRS is set. + objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS + self.prebuilt_root_objects.append(addr_array) + # jump to the end of the function + else: + # case with cards. + # + # If the newly written address does not actually point to the + # nursery, leave now. + if not self.appears_to_be_young(newvalue): + return + # + # 'addr_array' is a raw_malloc'ed array with card markers + # in front. Compute the index of the bit to set: + bitindex = index >> self.card_page_shift + byteindex = bitindex >> 3 + bitmask = 1 << (bitindex & 7) + # + # If the bit is already set, leave now. + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = addr_array - size_gc_header + addr_byte = llarena.getfakearenaaddress(addr_byte) + \ + (~byteindex) + byte = ord(addr_byte.char[0]) + if byte & bitmask: + return + addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.old_objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET + return + # + # Logic for the no-cards case, put here to minimize the number + # of checks done at the start of the function + if self.appears_to_be_young(newvalue): + self.old_objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + + remember_young_pointer_from_array3._dont_inline_ = True + assert self.card_page_indices > 0 + self.remember_young_pointer_from_array3 = ( + remember_young_pointer_from_array3) def assume_young_pointers(self, addr_struct): diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -458,7 +458,7 @@ annmodel.SomeInteger()], annmodel.s_None, inline=True) - func = getattr(gcdata.gc, 'remember_young_pointer_from_array', + func = getattr(gcdata.gc, 'remember_young_pointer_from_array3', None) if func is not None: # func should not be a bound method, but a real function @@ -466,7 +466,8 @@ self.write_barrier_from_array_failing_case_ptr = \ getfn(func, [annmodel.SomeAddress(), - annmodel.SomeInteger()], + annmodel.SomeInteger(), + annmodel.SomeAddress()], annmodel.s_None) self.statistics_ptr = getfn(GCClass.statistics.im_func, [s_gc, annmodel.SomeInteger()], diff --git a/pypy/tool/gcc_cache.py b/pypy/tool/gcc_cache.py --- a/pypy/tool/gcc_cache.py +++ b/pypy/tool/gcc_cache.py @@ -44,7 +44,11 @@ platform.log_errors = False platform.compile(c_files, eci) finally: - platform.log_errors = _previous + del platform.log_errors + # ^^^remove from the instance --- needed so that it can + # compare equal to another instance without it + if platform.log_errors != _previous: + platform.log_errors = _previous data = 'True' path.write(data) except CompilationError, e: diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -3,9 +3,9 @@ It uses 'pypy/translator/goal/pypy-c' and parts of the rest of the working copy. Usage: - package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] + package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] [destination-for-tarball] [pypy-c-path] -Usually you would do: package.py ../../.. pypy-VER-PLATFORM. +Usually you would do: package.py ../../.. pypy-VER-PLATFORM The output is found in the directory /tmp/usession-YOURNAME/build/. """ @@ -122,7 +122,10 @@ zf.close() else: archive = str(builddir.join(name + '.tar.bz2')) - e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) + if sys.platform == 'darwin': + e = os.system('tar --numeric-owner -cvjf ' + archive + " " + name) + else: + e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) if e: raise OSError('"tar" returned exit status %r' % e) finally: diff --git a/pypy/translator/c/gcc/test/msvc/track_and_esp.s b/pypy/translator/c/gcc/test/msvc/track_and_esp.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/msvc/track_and_esp.s @@ -0,0 +1,466 @@ +PUBLIC ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ ; `string' +PUBLIC _pypy_g_ll_math_ll_math_frexp +; COMDAT ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ +CONST SEGMENT +??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ DB 'pypy_g_ll_math_l' + DB 'l_math_frexp', 00H ; `string' +; Function compile flags: /Ogtpy +CONST ENDS +; COMDAT _pypy_g_ll_math_ll_math_frexp +_TEXT SEGMENT +_l_mantissa_0$ = -8 ; size = 8 +_l_v21638$ = -8 ; size = 8 +_l_x_14$ = 8 ; size = 8 +_pypy_g_ll_math_ll_math_frexp PROC ; COMDAT + +; 58245: struct pypy_tuple2_0 *pypy_g_ll_math_ll_math_frexp(double l_x_14) { + + push ebp + mov ebp, esp + and esp, -64 ; ffffffc0H + +; 58246: long *l_exp_p_0; double l_mantissa_0; bool_t l_v21641; +; 58247: bool_t l_v21643; bool_t l_v21644; bool_t l_v21646; bool_t l_v21647; +; 58248: bool_t l_v21652; bool_t l_v21653; bool_t l_v21660; bool_t l_v21666; +; 58249: bool_t l_v21670; bool_t l_v21674; bool_t l_v21676; double l_v21638; +; 58250: long l_v21637; long l_v21649; long l_v21651; long l_v21677; +; 58251: long l_v21678; struct pypy_exceptions_Exception0 *l_v21687; +; 58252: struct pypy_header0 *l_v21654; struct pypy_object0 *l_v21682; +; 58253: struct pypy_object0 *l_v21691; struct pypy_object_vtable0 *l_v21665; +; 58254: struct pypy_object_vtable0 *l_v21669; +; 58255: struct pypy_object_vtable0 *l_v21675; +; 58256: struct pypy_object_vtable0 *l_v21683; struct pypy_tuple2_0 *l_v21640; +; 58257: struct pypy_tuple2_0 *l_v21695; void* l_v21639; void* l_v21648; +; 58258: void* l_v21650; void* l_v21656; void* l_v21658; void* l_v21659; +; 58259: void* l_v21668; void* l_v21672; void* l_v21679; void* l_v21688; +; 58260: void* l_v21696; +; 58261: goto block0; +; 58262: +; 58263: block0: +; 58264: l_v21641 = pypy_g_ll_math_ll_math_isnan(l_x_14); + + fld QWORD PTR _l_x_14$[ebp] + sub esp, 52 ; 00000034H + push ebx + push esi + push edi + sub esp, 8 + fstp QWORD PTR [esp] +$block0$88239: + call _pypy_g_ll_math_ll_math_isnan + +; 58265: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isnan); +; 58266: l_v21643 = l_v21641; +; 58267: if (l_v21643) { +; 58268: l_v21637 = 0L; +; 58269: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] + add esp, 8 + test al, al + +; 58270: goto block3; + + jne SHORT $LN10 at pypy_g_ll_@159 + +; 58271: } +; 58272: goto block1; +; 58273: +; 58274: block1: +; 58275: l_v21644 = pypy_g_ll_math_ll_math_isinf(l_x_14); + + sub esp, 8 + fstp QWORD PTR [esp] +$block1$88243: + call _pypy_g_ll_math_ll_math_isinf + add esp, 8 + +; 58276: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isinf); +; 58277: l_v21646 = l_v21644; +; 58278: if (l_v21646) { + + test al, al + je SHORT $block2$88245 + +; 58279: l_v21637 = 0L; +; 58280: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] +$LN10 at pypy_g_ll_@159: + +; 58288: goto block14; +; 58289: } +; 58290: l_v21637 = 0L; + + xor edi, edi +$LN30 at pypy_g_ll_@159: + +; 58291: l_v21638 = l_x_14; +; 58292: goto block3; +; 58293: +; 58294: block3: +; 58295: l_v21648 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free; + + mov esi, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4 + fstp QWORD PTR _l_v21638$[esp+64] + +; 58296: OP_RAW_MALLOC_USAGE((0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21649); +; 58297: l_v21650 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_top_of_space; +; 58298: OP_ADR_DELTA(l_v21650, l_v21648, l_v21651); + + mov eax, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+12 + sub eax, esi + +; 58299: OP_INT_GT(l_v21649, l_v21651, l_v21652); + + cmp eax, 24 ; 00000018H +$block3$88242: + +; 58300: if (l_v21652) { + + jge $block4$88260 + +; 58334: l_v21695 = l_v21640; +; 58335: goto block8; +; 58336: +; 58337: block8: +; 58338: RPY_DEBUG_RETURN(); +; 58339: return l_v21695; +; 58340: +; 58341: block9: +; 58342: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58343: l_v21695 = ((struct pypy_tuple2_0 *) NULL); +; 58344: goto block8; +; 58345: +; 58346: block10: +; 58347: abort(); /* debug_llinterpcall should be unreachable */ +; 58348: l_v21665 = (&pypy_g_ExcData)->ed_exc_type; +; 58349: l_v21666 = (l_v21665 == NULL); +; 58350: if (!l_v21666) { +; 58351: goto block11; +; 58352: } +; 58353: goto block5; +; 58354: +; 58355: block11: +; 58356: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58357: l_v21696 = NULL; +; 58358: goto block6; +; 58359: +; 58360: block12: +; 58361: l_v21668 = pypy_g_SemiSpaceGC_obtain_free_space((&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC), (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0)))); + + push 24 ; 00000018H + push OFFSET _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC +$block12$88259: + call _pypy_g_SemiSpaceGC_obtain_free_space + +; 58362: l_v21669 = (&pypy_g_ExcData)->ed_exc_type; +; 58363: l_v21670 = (l_v21669 == NULL); + + xor ecx, ecx + add esp, 8 + cmp DWORD PTR _pypy_g_ExcData, ecx + +; 58364: if (!l_v21670) { + + je $LN5 at pypy_g_ll_@159 + +; 58368: goto block4; +; 58369: +; 58370: block13: +; 58371: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?N@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?8??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block13$88313: +$block9$88285: + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block2$88245: + +; 58281: goto block3; +; 58282: } +; 58283: goto block2; +; 58284: +; 58285: block2: +; 58286: OP_FLOAT_IS_TRUE(l_x_14, l_v21647); + + fldz + fld QWORD PTR _l_x_14$[ebp] + fucom ST(1) + fnstsw ax + fstp ST(1) + test ah, 68 ; 00000044H + +; 58287: if (l_v21647) { + + jnp $LN10 at pypy_g_ll_@159 + +; 58372: l_v21696 = NULL; +; 58373: goto block6; +; 58374: +; 58375: block14: +; 58376: l_v21672 = pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign(1L, (0 + 0), sizeof(long)); + + push 4 + fstp ST(0) + push 0 + push 1 +$block14$88247: + call _pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign + mov esi, eax + +; 58377: OP_TRACK_ALLOC_START(l_v21672, /* nothing */); + + push OFFSET ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ + push esi + call _pypy_debug_alloc_start + add esp, 20 ; 00000014H + +; 58378: l_exp_p_0 = (long *)l_v21672; +; 58379: l_v21674 = (l_exp_p_0 != NULL); + + test esi, esi + +; 58380: if (!l_v21674) { + + jne SHORT $block15$88324 + +; 58418: goto block8; +; 58419: +; 58420: block18: +; 58421: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BB@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], esi + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block18$88323: + +; 58422: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block15$88324: + +; 58381: goto block18; +; 58382: } +; 58383: goto block15; +; 58384: +; 58385: block15: +; 58386: l_mantissa_0 = pypy_g_frexp__Float_arrayPtr_star_2(l_x_14, l_exp_p_0); + + fld QWORD PTR _l_x_14$[ebp] + push esi + sub esp, 8 + fstp QWORD PTR [esp] + call _pypy_g_frexp__Float_arrayPtr_star_2 + +; 58387: l_v21675 = (&pypy_g_ExcData)->ed_exc_type; +; 58388: l_v21676 = (l_v21675 == NULL); + + mov edi, DWORD PTR _pypy_g_ExcData + fstp QWORD PTR _l_mantissa_0$[esp+76] + add esp, 12 ; 0000000cH + test edi, edi + +; 58389: if (!l_v21676) { + + je SHORT $block16$88328 + +; 58403: +; 58404: block17: +; 58405: l_v21682 = (&pypy_g_ExcData)->ed_exc_value; +; 58406: l_v21683 = (&pypy_g_ExcData)->ed_exc_type; +; 58407: PYPY_DEBUG_CATCH_EXCEPTION("ll_math_ll_math_frexp", l_v21683, l_v21683 == (&pypy_g_py__code_assertion_AssertionError_vtable.ae_super.ae_super.se_super.e_super) || l_v21683 == (&pypy_g_exceptions_NotImplementedError_vtable.nie_super.re_super.se_super.e_super)); + + mov eax, DWORD PTR _pypydtcount + mov ebx, DWORD PTR _pypy_g_ExcData+4 + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BA@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], edi + inc eax + and eax, 8191 ; 00001fffH +$block17$88327: + mov DWORD PTR _pypydtcount, eax + cmp edi, OFFSET _pypy_g_py__code_assertion_AssertionError_vtable + je SHORT $LN1 at pypy_g_ll_@159 + cmp edi, OFFSET _pypy_g_exceptions_NotImplementedError_vtable + jne SHORT $LN2 at pypy_g_ll_@159 +$LN1 at pypy_g_ll_@159: + call _pypy_debug_catch_fatal_exception +$LN2 at pypy_g_ll_@159: + +; 58408: (&pypy_g_ExcData)->ed_exc_value = ((struct pypy_object0 *) NULL); + + xor eax, eax + +; 58409: (&pypy_g_ExcData)->ed_exc_type = ((struct pypy_object_vtable0 *) NULL); +; 58410: l_v21687 = (struct pypy_exceptions_Exception0 *)l_v21682; +; 58411: l_v21688 = (void*)l_exp_p_0; +; 58412: OP_TRACK_ALLOC_STOP(l_v21688, /* nothing */); + + push esi + mov DWORD PTR _pypy_g_ExcData+4, eax + mov DWORD PTR _pypy_g_ExcData, eax + call _pypy_debug_alloc_stop + +; 58413: OP_RAW_FREE(l_v21688, /* nothing */); + + push esi + call _PyObject_Free + +; 58414: l_v21691 = (struct pypy_object0 *)l_v21687; +; 58415: pypy_g_RPyReRaiseException(l_v21683, l_v21691); + + push ebx + push edi + call _pypy_g_RPyReRaiseException + add esp, 16 ; 00000010H + +; 58416: pypy_asm_gc_nocollect(pypy_g_RPyReRaiseException); +; 58417: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block16$88328: + +; 58390: goto block17; +; 58391: } +; 58392: goto block16; +; 58393: +; 58394: block16: +; 58395: l_v21677 = RPyBareItem(l_exp_p_0, 0L); +; 58396: l_v21678 = (long)(l_v21677); + + mov edi, DWORD PTR [esi] + +; 58397: l_v21679 = (void*)l_exp_p_0; +; 58398: OP_TRACK_ALLOC_STOP(l_v21679, /* nothing */); + + push esi + call _pypy_debug_alloc_stop + +; 58399: OP_RAW_FREE(l_v21679, /* nothing */); + + push esi + call _PyObject_Free + +; 58400: l_v21637 = l_v21678; +; 58401: l_v21638 = l_mantissa_0; + + fld QWORD PTR _l_mantissa_0$[esp+72] + add esp, 8 + +; 58402: goto block3; + + jmp $LN30 at pypy_g_ll_@159 +$LN5 at pypy_g_ll_@159: + +; 58365: goto block13; +; 58366: } +; 58367: l_v21639 = l_v21668; + + mov esi, eax +$block4$88260: +$block5$88263: + +; 58301: goto block12; +; 58302: } +; 58303: l_v21639 = l_v21648; +; 58304: goto block4; +; 58305: +; 58306: block4: +; 58307: OP_INT_IS_TRUE(RUNNING_ON_LLINTERP, l_v21653); +; 58308: if (l_v21653) { +; 58309: goto block10; +; 58310: } +; 58311: goto block5; +; 58312: +; 58313: block5: +; 58314: l_v21654 = (struct pypy_header0 *)l_v21639; +; 58315: RPyField(l_v21654, h_tid) = (GROUP_MEMBER_OFFSET(struct group_pypy_g_typeinfo_s, member20)+0L); + + test esi, esi + jne SHORT $LN18 at pypy_g_ll_@159 + call _RPyAbort +$LN18 at pypy_g_ll_@159: + +; 58316: OP_ADR_ADD(l_v21639, (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21656); +; 58317: (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free = l_v21656; +; 58318: OP_ADR_ADD(l_v21639, 0, l_v21658); +; 58319: l_v21659 = (void*)l_v21658; +; 58320: l_v21696 = l_v21659; +; 58321: goto block6; +; 58322: +; 58323: block6: +; 58324: l_v21640 = (struct pypy_tuple2_0 *)l_v21696; +; 58325: l_v21660 = (l_v21640 != NULL); +; 58326: if (!l_v21660) { +; 58327: goto block9; +; 58328: } +; 58329: goto block7; +; 58330: +; 58331: block7: +; 58332: RPyField(l_v21640, t_item0) = l_v21638; + + fld QWORD PTR _l_v21638$[esp+64] + mov DWORD PTR [esi], 81 ; 00000051H + lea ecx, DWORD PTR [esi+24] + mov DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4, ecx + fstp QWORD PTR [esi+8] + +; 58333: RPyField(l_v21640, t_item1) = l_v21637; + + mov DWORD PTR [esi+16], edi + +; 58423: goto block8; +; 58424: } + + pop edi + mov eax, esi + pop esi +$block6$88281: +$block8$88289: + pop ebx + mov esp, ebp + pop ebp + ret 0 +_pypy_g_ll_math_ll_math_frexp ENDP +_TEXT ENDS diff --git a/pypy/translator/goal/targetnumpystandalone.py b/pypy/translator/goal/targetnumpystandalone.py --- a/pypy/translator/goal/targetnumpystandalone.py +++ b/pypy/translator/goal/targetnumpystandalone.py @@ -10,46 +10,32 @@ """ import time -from pypy.module.micronumpy.numarray import SingleDimArray, Code, compute +from pypy.module.micronumpy.compile import numpy_compile from pypy.jit.codewriter.policy import JitPolicy - -def create_array(size): - a = SingleDimArray(size) - for i in range(size): - a.storage[i] = float(i % 10) - return a +from pypy.rpython.annlowlevel import hlstr def entry_point(argv): if len(argv) != 3: print __doc__ return 1 - bytecode = argv[1] - for b in bytecode: - if b not in 'alf': - print "WRONG BYTECODE" - print __doc__ - return 2 try: size = int(argv[2]) except ValueError: print "INVALID LITERAL FOR INT:", argv[2] print __doc__ return 3 - no_arrays = bytecode.count('l') - no_floats = bytecode.count('f') - arrays = [] - floats = [] - for i in range(no_arrays): - arrays.append(create_array(size)) - for i in range(no_floats): - floats.append(float(i + 1)) - code = Code(bytecode, arrays, floats) t0 = time.time() - compute(code) - print "bytecode:", bytecode, "size:", size + main(argv[0], size) + print "bytecode:", argv[0], "size:", size print "took:", time.time() - t0 return 0 +def main(bc, size): + if not isinstance(bc, str): + bc = hlstr(bc) # for tests + a = numpy_compile(bc, size) + a = a.compute() + def target(*args): return entry_point, None From noreply at buildbot.pypy.org Wed Jul 6 20:28:58 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:58 +0200 (CEST) Subject: [pypy-commit] pypy tealet: hg merge default Message-ID: <20110706182858.1F933820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45390:6404b8a8b2ff Date: 2011-07-06 16:00 +0200 http://bitbucket.org/pypy/pypy/changeset/6404b8a8b2ff/ Log: hg merge default diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,6 +1,7 @@ syntax: glob *.py[co] *~ +.*.swp syntax: regexp ^testresult$ @@ -38,6 +39,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ diff --git a/_pytest/__init__.py b/_pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.0.3' +__version__ = '2.1.0.dev4' diff --git a/_pytest/assertion.py b/_pytest/assertion.py deleted file mode 100644 --- a/_pytest/assertion.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -support for presented detailed information in failing assertions. -""" -import py -import sys -from _pytest.monkeypatch import monkeypatch - -def pytest_addoption(parser): - group = parser.getgroup("debugconfig") - group._addoption('--no-assert', action="store_true", default=False, - dest="noassert", - help="disable python assert expression reinterpretation."), - -def pytest_configure(config): - # The _reprcompare attribute on the py.code module is used by - # py._code._assertionnew to detect this plugin was loaded and in - # turn call the hooks defined here as part of the - # DebugInterpreter. - m = monkeypatch() - config._cleanup.append(m.undo) - warn_about_missing_assertion() - if not config.getvalue("noassert") and not config.getvalue("nomagic"): - def callbinrepr(op, left, right): - hook_result = config.hook.pytest_assertrepr_compare( - config=config, op=op, left=left, right=right) - for new_expl in hook_result: - if new_expl: - return '\n~'.join(new_expl) - m.setattr(py.builtin.builtins, - 'AssertionError', py.code._AssertionError) - m.setattr(py.code, '_reprcompare', callbinrepr) - -def warn_about_missing_assertion(): - try: - assert False - except AssertionError: - pass - else: - sys.stderr.write("WARNING: failing tests may report as passing because " - "assertions are turned off! (are you using python -O?)\n") - -# Provide basestring in python3 -try: - basestring = basestring -except NameError: - basestring = str - - -def pytest_assertrepr_compare(op, left, right): - """return specialised explanations for some operators/operands""" - width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op - left_repr = py.io.saferepr(left, maxsize=int(width/2)) - right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) - summary = '%s %s %s' % (left_repr, op, right_repr) - - issequence = lambda x: isinstance(x, (list, tuple)) - istext = lambda x: isinstance(x, basestring) - isdict = lambda x: isinstance(x, dict) - isset = lambda x: isinstance(x, set) - - explanation = None - try: - if op == '==': - if istext(left) and istext(right): - explanation = _diff_text(left, right) - elif issequence(left) and issequence(right): - explanation = _compare_eq_sequence(left, right) - elif isset(left) and isset(right): - explanation = _compare_eq_set(left, right) - elif isdict(left) and isdict(right): - explanation = _diff_text(py.std.pprint.pformat(left), - py.std.pprint.pformat(right)) - elif op == 'not in': - if istext(left) and istext(right): - explanation = _notin_text(left, right) - except py.builtin._sysex: - raise - except: - excinfo = py.code.ExceptionInfo() - explanation = ['(pytest_assertion plugin: representation of ' - 'details failed. Probably an object has a faulty __repr__.)', - str(excinfo) - ] - - - if not explanation: - return None - - # Don't include pageloads of data, should be configurable - if len(''.join(explanation)) > 80*8: - explanation = ['Detailed information too verbose, truncated'] - - return [summary] + explanation - - -def _diff_text(left, right): - """Return the explanation for the diff between text - - This will skip leading and trailing characters which are - identical to keep the diff minimal. - """ - explanation = [] - i = 0 # just in case left or right has zero length - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - break - if i > 42: - i -= 10 # Provide some context - explanation = ['Skipping %s identical ' - 'leading characters in diff' % i] - left = left[i:] - right = right[i:] - if len(left) == len(right): - for i in range(len(left)): - if left[-i] != right[-i]: - break - if i > 42: - i -= 10 # Provide some context - explanation += ['Skipping %s identical ' - 'trailing characters in diff' % i] - left = left[:-i] - right = right[:-i] - explanation += [line.strip('\n') - for line in py.std.difflib.ndiff(left.splitlines(), - right.splitlines())] - return explanation - - -def _compare_eq_sequence(left, right): - explanation = [] - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - explanation += ['At index %s diff: %r != %r' % - (i, left[i], right[i])] - break - if len(left) > len(right): - explanation += ['Left contains more items, ' - 'first extra item: %s' % py.io.saferepr(left[len(right)],)] - elif len(left) < len(right): - explanation += ['Right contains more items, ' - 'first extra item: %s' % py.io.saferepr(right[len(left)],)] - return explanation # + _diff_text(py.std.pprint.pformat(left), - # py.std.pprint.pformat(right)) - - -def _compare_eq_set(left, right): - explanation = [] - diff_left = left - right - diff_right = right - left - if diff_left: - explanation.append('Extra items in the left set:') - for item in diff_left: - explanation.append(py.io.saferepr(item)) - if diff_right: - explanation.append('Extra items in the right set:') - for item in diff_right: - explanation.append(py.io.saferepr(item)) - return explanation - - -def _notin_text(term, text): - index = text.find(term) - head = text[:index] - tail = text[index+len(term):] - correct_text = head + tail - diff = _diff_text(correct_text, text) - newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] - for line in diff: - if line.startswith('Skipping'): - continue - if line.startswith('- '): - continue - if line.startswith('+ '): - newdiff.append(' ' + line[2:]) - else: - newdiff.append(line) - return newdiff diff --git a/_pytest/assertion/__init__.py b/_pytest/assertion/__init__.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/__init__.py @@ -0,0 +1,128 @@ +""" +support for presenting detailed information in failing assertions. +""" +import py +import imp +import marshal +import struct +import sys +import pytest +from _pytest.monkeypatch import monkeypatch +from _pytest.assertion import reinterpret, util + +try: + from _pytest.assertion.rewrite import rewrite_asserts +except ImportError: + rewrite_asserts = None +else: + import ast + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption('--assertmode', action="store", dest="assertmode", + choices=("on", "old", "off", "default"), default="default", + metavar="on|old|off", + help="""control assertion debugging tools. +'off' performs no assertion debugging. +'old' reinterprets the expressions in asserts to glean information. +'on' (the default) rewrites the assert statements in test modules to provide +sub-expression results.""") + group.addoption('--no-assert', action="store_true", default=False, + dest="noassert", help="DEPRECATED equivalent to --assertmode=off") + group.addoption('--nomagic', action="store_true", default=False, + dest="nomagic", help="DEPRECATED equivalent to --assertmode=off") + +class AssertionState: + """State for the assertion plugin.""" + + def __init__(self, config, mode): + self.mode = mode + self.trace = config.trace.root.get("assertion") + +def pytest_configure(config): + warn_about_missing_assertion() + mode = config.getvalue("assertmode") + if config.getvalue("noassert") or config.getvalue("nomagic"): + if mode not in ("off", "default"): + raise pytest.UsageError("assertion options conflict") + mode = "off" + elif mode == "default": + mode = "on" + if mode != "off": + def callbinrepr(op, left, right): + hook_result = config.hook.pytest_assertrepr_compare( + config=config, op=op, left=left, right=right) + for new_expl in hook_result: + if new_expl: + return '\n~'.join(new_expl) + m = monkeypatch() + config._cleanup.append(m.undo) + m.setattr(py.builtin.builtins, 'AssertionError', + reinterpret.AssertionError) + m.setattr(util, '_reprcompare', callbinrepr) + if mode == "on" and rewrite_asserts is None: + mode = "old" + config._assertstate = AssertionState(config, mode) + config._assertstate.trace("configured with mode set to %r" % (mode,)) + +def _write_pyc(co, source_path): + if hasattr(imp, "cache_from_source"): + # Handle PEP 3147 pycs. + pyc = py.path.local(imp.cache_from_source(str(source_path))) + pyc.ensure() + else: + pyc = source_path + "c" + mtime = int(source_path.mtime()) + fp = pyc.open("wb") + try: + fp.write(imp.get_magic()) + fp.write(struct.pack(">", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + + +class DebugInterpreter(ast.NodeVisitor): + """Interpret AST nodes to gleam useful debugging information. """ + + def __init__(self, frame): + self.frame = frame + + def generic_visit(self, node): + # Fallback when we don't have a special implementation. + if _is_ast_expr(node): + mod = ast.Expression(node) + co = self._compile(mod) + try: + result = self.frame.eval(co) + except Exception: + raise Failure() + explanation = self.frame.repr(result) + return explanation, result + elif _is_ast_stmt(node): + mod = ast.Module([node]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co) + except Exception: + raise Failure() + return None, None + else: + raise AssertionError("can't handle %s" %(node,)) + + def _compile(self, source, mode="eval"): + return compile(source, "", mode) + + def visit_Expr(self, expr): + return self.visit(expr.value) + + def visit_Module(self, mod): + for stmt in mod.body: + self.visit(stmt) + + def visit_Name(self, name): + explanation, result = self.generic_visit(name) + # See if the name is local. + source = "%r in locals() is not globals()" % (name.id,) + co = self._compile(source) + try: + local = self.frame.eval(co) + except Exception: + # have to assume it isn't + local = None + if local is None or not self.frame.is_true(local): + return name.id, result + return explanation, result + + def visit_Compare(self, comp): + left = comp.left + left_explanation, left_result = self.visit(left) + for op, next_op in zip(comp.ops, comp.comparators): + next_explanation, next_result = self.visit(next_op) + op_symbol = operator_map[op.__class__] + explanation = "%s %s %s" % (left_explanation, op_symbol, + next_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=next_result) + except Exception: + raise Failure(explanation) + try: + if not self.frame.is_true(result): + break + except KeyboardInterrupt: + raise + except: + break + left_explanation, left_result = next_explanation, next_result + + if util._reprcompare is not None: + res = util._reprcompare(op_symbol, left_result, next_result) + if res: + explanation = res + return explanation, result + + def visit_BoolOp(self, boolop): + is_or = isinstance(boolop.op, ast.Or) + explanations = [] + for operand in boolop.values: + explanation, result = self.visit(operand) + explanations.append(explanation) + if result == is_or: + break + name = is_or and " or " or " and " + explanation = "(" + name.join(explanations) + ")" + return explanation, result + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_explanation, operand_result = self.visit(unary.operand) + explanation = pattern % (operand_explanation,) + co = self._compile(pattern % ("__exprinfo_expr",)) + try: + result = self.frame.eval(co, __exprinfo_expr=operand_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_BinOp(self, binop): + left_explanation, left_result = self.visit(binop.left) + right_explanation, right_result = self.visit(binop.right) + symbol = operator_map[binop.op.__class__] + explanation = "(%s %s %s)" % (left_explanation, symbol, + right_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=right_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_Call(self, call): + func_explanation, func = self.visit(call.func) + arg_explanations = [] + ns = {"__exprinfo_func" : func} + arguments = [] + for arg in call.args: + arg_explanation, arg_result = self.visit(arg) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + arguments.append(arg_name) + arg_explanations.append(arg_explanation) + for keyword in call.keywords: + arg_explanation, arg_result = self.visit(keyword.value) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + keyword_source = "%s=%%s" % (keyword.arg) + arguments.append(keyword_source % (arg_name,)) + arg_explanations.append(keyword_source % (arg_explanation,)) + if call.starargs: + arg_explanation, arg_result = self.visit(call.starargs) + arg_name = "__exprinfo_star" + ns[arg_name] = arg_result + arguments.append("*%s" % (arg_name,)) + arg_explanations.append("*%s" % (arg_explanation,)) + if call.kwargs: + arg_explanation, arg_result = self.visit(call.kwargs) + arg_name = "__exprinfo_kwds" + ns[arg_name] = arg_result + arguments.append("**%s" % (arg_name,)) + arg_explanations.append("**%s" % (arg_explanation,)) + args_explained = ", ".join(arg_explanations) + explanation = "%s(%s)" % (func_explanation, args_explained) + args = ", ".join(arguments) + source = "__exprinfo_func(%s)" % (args,) + co = self._compile(source) + try: + result = self.frame.eval(co, **ns) + except Exception: + raise Failure(explanation) + pattern = "%s\n{%s = %s\n}" + rep = self.frame.repr(result) + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def _is_builtin_name(self, name): + pattern = "%r not in globals() and %r not in locals()" + source = pattern % (name.id, name.id) + co = self._compile(source) + try: + return self.frame.eval(co) + except Exception: + return False + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + source_explanation, source_result = self.visit(attr.value) + explanation = "%s.%s" % (source_explanation, attr.attr) + source = "__exprinfo_expr.%s" % (attr.attr,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + raise Failure(explanation) + explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), + self.frame.repr(result), + source_explanation, attr.attr) + # Check if the attr is from an instance. + source = "%r in getattr(__exprinfo_expr, '__dict__', {})" + source = source % (attr.attr,) + co = self._compile(source) + try: + from_instance = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + from_instance = None + if from_instance is None or self.frame.is_true(from_instance): + rep = self.frame.repr(result) + pattern = "%s\n{%s = %s\n}" + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def visit_Assert(self, assrt): + test_explanation, test_result = self.visit(assrt.test) + explanation = "assert %s" % (test_explanation,) + if not self.frame.is_true(test_result): + try: + raise BuiltinAssertionError + except Exception: + raise Failure(explanation) + return explanation, test_result + + def visit_Assign(self, assign): + value_explanation, value_result = self.visit(assign.value) + explanation = "... = %s" % (value_explanation,) + name = ast.Name("__exprinfo_expr", ast.Load(), + lineno=assign.value.lineno, + col_offset=assign.value.col_offset) + new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, + col_offset=assign.col_offset) + mod = ast.Module([new_assign]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co, __exprinfo_expr=value_result) + except Exception: + raise Failure(explanation) + return explanation, value_result diff --git a/_pytest/assertion/oldinterpret.py b/_pytest/assertion/oldinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/oldinterpret.py @@ -0,0 +1,552 @@ +import py +import sys, inspect +from compiler import parse, ast, pycodegen +from _pytest.assertion.util import format_explanation +from _pytest.assertion.reinterpret import BuiltinAssertionError + +passthroughex = py.builtin._sysex + +class Failure: + def __init__(self, node): + self.exc, self.value, self.tb = sys.exc_info() + self.node = node + +class View(object): + """View base class. + + If C is a subclass of View, then C(x) creates a proxy object around + the object x. The actual class of the proxy is not C in general, + but a *subclass* of C determined by the rules below. To avoid confusion + we call view class the class of the proxy (a subclass of C, so of View) + and object class the class of x. + + Attributes and methods not found in the proxy are automatically read on x. + Other operations like setting attributes are performed on the proxy, as + determined by its view class. The object x is available from the proxy + as its __obj__ attribute. + + The view class selection is determined by the __view__ tuples and the + optional __viewkey__ method. By default, the selected view class is the + most specific subclass of C whose __view__ mentions the class of x. + If no such subclass is found, the search proceeds with the parent + object classes. For example, C(True) will first look for a subclass + of C with __view__ = (..., bool, ...) and only if it doesn't find any + look for one with __view__ = (..., int, ...), and then ..., object,... + If everything fails the class C itself is considered to be the default. + + Alternatively, the view class selection can be driven by another aspect + of the object x, instead of the class of x, by overriding __viewkey__. + See last example at the end of this module. + """ + + _viewcache = {} + __view__ = () + + def __new__(rootclass, obj, *args, **kwds): + self = object.__new__(rootclass) + self.__obj__ = obj + self.__rootclass__ = rootclass + key = self.__viewkey__() + try: + self.__class__ = self._viewcache[key] + except KeyError: + self.__class__ = self._selectsubclass(key) + return self + + def __getattr__(self, attr): + # attributes not found in the normal hierarchy rooted on View + # are looked up in the object's real class + return getattr(self.__obj__, attr) + + def __viewkey__(self): + return self.__obj__.__class__ + + def __matchkey__(self, key, subclasses): + if inspect.isclass(key): + keys = inspect.getmro(key) + else: + keys = [key] + for key in keys: + result = [C for C in subclasses if key in C.__view__] + if result: + return result + return [] + + def _selectsubclass(self, key): + subclasses = list(enumsubclasses(self.__rootclass__)) + for C in subclasses: + if not isinstance(C.__view__, tuple): + C.__view__ = (C.__view__,) + choices = self.__matchkey__(key, subclasses) + if not choices: + return self.__rootclass__ + elif len(choices) == 1: + return choices[0] + else: + # combine the multiple choices + return type('?', tuple(choices), {}) + + def __repr__(self): + return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) + + +def enumsubclasses(cls): + for subcls in cls.__subclasses__(): + for subsubclass in enumsubclasses(subcls): + yield subsubclass + yield cls + + +class Interpretable(View): + """A parse tree node with a few extra methods.""" + explanation = None + + def is_builtin(self, frame): + return False + + def eval(self, frame): + # fall-back for unknown expression nodes + try: + expr = ast.Expression(self.__obj__) + expr.filename = '' + self.__obj__.filename = '' + co = pycodegen.ExpressionCodeGenerator(expr).getCode() + result = frame.eval(co) + except passthroughex: + raise + except: + raise Failure(self) + self.result = result + self.explanation = self.explanation or frame.repr(self.result) + + def run(self, frame): + # fall-back for unknown statement nodes + try: + expr = ast.Module(None, ast.Stmt([self.__obj__])) + expr.filename = '' + co = pycodegen.ModuleCodeGenerator(expr).getCode() + frame.exec_(co) + except passthroughex: + raise + except: + raise Failure(self) + + def nice_explanation(self): + return format_explanation(self.explanation) + + +class Name(Interpretable): + __view__ = ast.Name + + def is_local(self, frame): + source = '%r in locals() is not globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_global(self, frame): + source = '%r in globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_builtin(self, frame): + source = '%r not in locals() and %r not in globals()' % ( + self.name, self.name) + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + super(Name, self).eval(frame) + if not self.is_local(frame): + self.explanation = self.name + +class Compare(Interpretable): + __view__ = ast.Compare + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + for operation, expr2 in self.ops: + if hasattr(self, 'result'): + # shortcutting in chained expressions + if not frame.is_true(self.result): + break + expr2 = Interpretable(expr2) + expr2.eval(frame) + self.explanation = "%s %s %s" % ( + expr.explanation, operation, expr2.explanation) + source = "__exprinfo_left %s __exprinfo_right" % operation + try: + self.result = frame.eval(source, + __exprinfo_left=expr.result, + __exprinfo_right=expr2.result) + except passthroughex: + raise + except: + raise Failure(self) + expr = expr2 + +class And(Interpretable): + __view__ = ast.And + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if not frame.is_true(expr.result): + break + self.explanation = '(' + ' and '.join(explanations) + ')' + +class Or(Interpretable): + __view__ = ast.Or + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if frame.is_true(expr.result): + break + self.explanation = '(' + ' or '.join(explanations) + ')' + + +# == Unary operations == +keepalive = [] +for astclass, astpattern in { + ast.Not : 'not __exprinfo_expr', + ast.Invert : '(~__exprinfo_expr)', + }.items(): + + class UnaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + expr = Interpretable(self.expr) + expr.eval(frame) + self.explanation = astpattern.replace('__exprinfo_expr', + expr.explanation) + try: + self.result = frame.eval(astpattern, + __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(UnaryArith) + +# == Binary operations == +for astclass, astpattern in { + ast.Add : '(__exprinfo_left + __exprinfo_right)', + ast.Sub : '(__exprinfo_left - __exprinfo_right)', + ast.Mul : '(__exprinfo_left * __exprinfo_right)', + ast.Div : '(__exprinfo_left / __exprinfo_right)', + ast.Mod : '(__exprinfo_left % __exprinfo_right)', + ast.Power : '(__exprinfo_left ** __exprinfo_right)', + }.items(): + + class BinaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + left = Interpretable(self.left) + left.eval(frame) + right = Interpretable(self.right) + right.eval(frame) + self.explanation = (astpattern + .replace('__exprinfo_left', left .explanation) + .replace('__exprinfo_right', right.explanation)) + try: + self.result = frame.eval(astpattern, + __exprinfo_left=left.result, + __exprinfo_right=right.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(BinaryArith) + + +class CallFunc(Interpretable): + __view__ = ast.CallFunc + + def is_bool(self, frame): + source = 'isinstance(__exprinfo_value, bool)' + try: + return frame.is_true(frame.eval(source, + __exprinfo_value=self.result)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + node = Interpretable(self.node) + node.eval(frame) + explanations = [] + vars = {'__exprinfo_fn': node.result} + source = '__exprinfo_fn(' + for a in self.args: + if isinstance(a, ast.Keyword): + keyword = a.name + a = a.expr + else: + keyword = None + a = Interpretable(a) + a.eval(frame) + argname = '__exprinfo_%d' % len(vars) + vars[argname] = a.result + if keyword is None: + source += argname + ',' + explanations.append(a.explanation) + else: + source += '%s=%s,' % (keyword, argname) + explanations.append('%s=%s' % (keyword, a.explanation)) + if self.star_args: + star_args = Interpretable(self.star_args) + star_args.eval(frame) + argname = '__exprinfo_star' + vars[argname] = star_args.result + source += '*' + argname + ',' + explanations.append('*' + star_args.explanation) + if self.dstar_args: + dstar_args = Interpretable(self.dstar_args) + dstar_args.eval(frame) + argname = '__exprinfo_kwds' + vars[argname] = dstar_args.result + source += '**' + argname + ',' + explanations.append('**' + dstar_args.explanation) + self.explanation = "%s(%s)" % ( + node.explanation, ', '.join(explanations)) + if source.endswith(','): + source = source[:-1] + source += ')' + try: + self.result = frame.eval(source, **vars) + except passthroughex: + raise + except: + raise Failure(self) + if not node.is_builtin(frame) or not self.is_bool(frame): + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +class Getattr(Interpretable): + __view__ = ast.Getattr + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + source = '__exprinfo_expr.%s' % self.attrname + try: + self.result = frame.eval(source, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + self.explanation = '%s.%s' % (expr.explanation, self.attrname) + # if the attribute comes from the instance, its value is interesting + source = ('hasattr(__exprinfo_expr, "__dict__") and ' + '%r in __exprinfo_expr.__dict__' % self.attrname) + try: + from_instance = frame.is_true( + frame.eval(source, __exprinfo_expr=expr.result)) + except passthroughex: + raise + except: + from_instance = True + if from_instance: + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +# == Re-interpretation of full statements == + +class Assert(Interpretable): + __view__ = ast.Assert + + def run(self, frame): + test = Interpretable(self.test) + test.eval(frame) + # print the result as 'assert ' + self.result = test.result + self.explanation = 'assert ' + test.explanation + if not frame.is_true(test.result): + try: + raise BuiltinAssertionError + except passthroughex: + raise + except: + raise Failure(self) + +class Assign(Interpretable): + __view__ = ast.Assign + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = '... = ' + expr.explanation + # fall-back-run the rest of the assignment + ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) + mod = ast.Module(None, ast.Stmt([ass])) + mod.filename = '' + co = pycodegen.ModuleCodeGenerator(mod).getCode() + try: + frame.exec_(co, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + +class Discard(Interpretable): + __view__ = ast.Discard + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = expr.explanation + +class Stmt(Interpretable): + __view__ = ast.Stmt + + def run(self, frame): + for stmt in self.nodes: + stmt = Interpretable(stmt) + stmt.run(frame) + + +def report_failure(e): + explanation = e.node.nice_explanation() + if explanation: + explanation = ", in: " + explanation + else: + explanation = "" + sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) + +def check(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + expr = parse(s, 'eval') + assert isinstance(expr, ast.Expression) + node = Interpretable(expr.node) + try: + node.eval(frame) + except passthroughex: + raise + except Failure: + e = sys.exc_info()[1] + report_failure(e) + else: + if not frame.is_true(node.result): + sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) + + +########################################################### +# API / Entry points +# ######################################################### + +def interpret(source, frame, should_fail=False): + module = Interpretable(parse(source, 'exec').node) + #print "got module", module + if isinstance(frame, py.std.types.FrameType): + frame = py.code.Frame(frame) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + return getfailure(e) + except passthroughex: + raise + except: + import traceback + traceback.print_exc() + if should_fail: + return ("(assertion failed, but when it was re-run for " + "printing intermediate values, it did not fail. Suggestions: " + "compute assert expression before the assert or use --nomagic)") + else: + return None + +def getmsg(excinfo): + if isinstance(excinfo, tuple): + excinfo = py.code.ExceptionInfo(excinfo) + #frame, line = gettbline(tb) + #frame = py.code.Frame(frame) + #return interpret(line, frame) + + tb = excinfo.traceback[-1] + source = str(tb.statement).strip() + x = interpret(source, tb.frame, should_fail=True) + if not isinstance(x, str): + raise TypeError("interpret returned non-string %r" % (x,)) + return x + +def getfailure(e): + explanation = e.node.nice_explanation() + if str(e.value): + lines = explanation.split('\n') + lines[0] += " << %s" % (e.value,) + explanation = '\n'.join(lines) + text = "%s: %s" % (e.exc.__name__, explanation) + if text.startswith('AssertionError: assert '): + text = text[16:] + return text + +def run(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + module = Interpretable(parse(s, 'exec').node) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + report_failure(e) + + +if __name__ == '__main__': + # example: + def f(): + return 5 + def g(): + return 3 + def h(x): + return 'never' + check("f() * g() == 5") + check("not f()") + check("not (f() and g() or 0)") + check("f() == g()") + i = 4 + check("i == f()") + check("len(f()) == 0") + check("isinstance(2+3+4, float)") + + run("x = i") + check("x == 5") + + run("assert not f(), 'oops'") + run("a, b, c = 1, 2") + run("a, b, c = f()") + + check("max([f(),g()]) == 4") + check("'hello'[g()] == 'h'") + run("'guk%d' % h(f())") diff --git a/_pytest/assertion/reinterpret.py b/_pytest/assertion/reinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/reinterpret.py @@ -0,0 +1,48 @@ +import sys +import py + +BuiltinAssertionError = py.builtin.builtins.AssertionError + +class AssertionError(BuiltinAssertionError): + def __init__(self, *args): + BuiltinAssertionError.__init__(self, *args) + if args: + try: + self.msg = str(args[0]) + except py.builtin._sysex: + raise + except: + self.msg = "<[broken __repr__] %s at %0xd>" %( + args[0].__class__, id(args[0])) + else: + f = py.code.Frame(sys._getframe(1)) + try: + source = f.code.fullsource + if source is not None: + try: + source = source.getstatement(f.lineno, assertion=True) + except IndexError: + source = None + else: + source = str(source.deindent()).strip() + except py.error.ENOENT: + source = None + # this can also occur during reinterpretation, when the + # co_filename is set to "". + if source: + self.msg = reinterpret(source, f, should_fail=True) + else: + self.msg = "" + if not self.args: + self.args = (self.msg,) + +if sys.version_info > (3, 0): + AssertionError.__module__ = "builtins" + reinterpret_old = "old reinterpretation not available for py3" +else: + from _pytest.assertion.oldinterpret import interpret as reinterpret_old +if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): + from _pytest.assertion.newinterpret import interpret as reinterpret +else: + reinterpret = reinterpret_old + diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/rewrite.py @@ -0,0 +1,340 @@ +"""Rewrite assertion AST to produce nice error messages""" + +import ast +import collections +import itertools +import sys + +import py +from _pytest.assertion import util + + +def rewrite_asserts(mod): + """Rewrite the assert statements in mod.""" + AssertionRewriter().run(mod) + + +_saferepr = py.io.saferepr +from _pytest.assertion.util import format_explanation as _format_explanation + +def _format_boolop(operands, explanations, is_or): + show_explanations = [] + for operand, expl in zip(operands, explanations): + show_explanations.append(expl) + if operand == is_or: + break + return "(" + (is_or and " or " or " and ").join(show_explanations) + ")" + +def _call_reprcompare(ops, results, expls, each_obj): + for i, res, expl in zip(range(len(ops)), results, expls): + try: + done = not res + except Exception: + done = True + if done: + break + if util._reprcompare is not None: + custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1]) + if custom is not None: + return custom + return expl + + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + +binop_map = { + ast.BitOr : "|", + ast.BitXor : "^", + ast.BitAnd : "&", + ast.LShift : "<<", + ast.RShift : ">>", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + + +def set_location(node, lineno, col_offset): + """Set node location information recursively.""" + def _fix(node, lineno, col_offset): + if "lineno" in node._attributes: + node.lineno = lineno + if "col_offset" in node._attributes: + node.col_offset = col_offset + for child in ast.iter_child_nodes(node): + _fix(child, lineno, col_offset) + _fix(node, lineno, col_offset) + return node + + +class AssertionRewriter(ast.NodeVisitor): + + def run(self, mod): + """Find all assert statements in *mod* and rewrite them.""" + if not mod.body: + # Nothing to do. + return + # Insert some special imports at the top of the module but after any + # docstrings and __future__ imports. + aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"), + ast.alias("_pytest.assertion.rewrite", "@pytest_ar")] + expect_docstring = True + pos = 0 + lineno = 0 + for item in mod.body: + if (expect_docstring and isinstance(item, ast.Expr) and + isinstance(item.value, ast.Str)): + doc = item.value.s + if "PYTEST_DONT_REWRITE" in doc: + # The module has disabled assertion rewriting. + return + lineno += len(doc) - 1 + expect_docstring = False + elif (not isinstance(item, ast.ImportFrom) or item.level > 0 and + item.identifier != "__future__"): + lineno = item.lineno + break + pos += 1 + imports = [ast.Import([alias], lineno=lineno, col_offset=0) + for alias in aliases] + mod.body[pos:pos] = imports + # Collect asserts. + nodes = collections.deque([mod]) + while nodes: + node = nodes.popleft() + for name, field in ast.iter_fields(node): + if isinstance(field, list): + new = [] + for i, child in enumerate(field): + if isinstance(child, ast.Assert): + # Transform assert. + new.extend(self.visit(child)) + else: + new.append(child) + if isinstance(child, ast.AST): + nodes.append(child) + setattr(node, name, new) + elif (isinstance(field, ast.AST) and + # Don't recurse into expressions as they can't contain + # asserts. + not isinstance(field, ast.expr)): + nodes.append(field) + + def variable(self): + """Get a new variable.""" + # Use a character invalid in python identifiers to avoid clashing. + name = "@py_assert" + str(next(self.variable_counter)) + self.variables.add(name) + return name + + def assign(self, expr): + """Give *expr* a name.""" + name = self.variable() + self.statements.append(ast.Assign([ast.Name(name, ast.Store())], expr)) + return ast.Name(name, ast.Load()) + + def display(self, expr): + """Call py.io.saferepr on the expression.""" + return self.helper("saferepr", expr) + + def helper(self, name, *args): + """Call a helper in this module.""" + py_name = ast.Name("@pytest_ar", ast.Load()) + attr = ast.Attribute(py_name, "_" + name, ast.Load()) + return ast.Call(attr, list(args), [], None, None) + + def builtin(self, name): + """Return the builtin called *name*.""" + builtin_name = ast.Name("@py_builtins", ast.Load()) + return ast.Attribute(builtin_name, name, ast.Load()) + + def explanation_param(self, expr): + specifier = "py" + str(next(self.variable_counter)) + self.explanation_specifiers[specifier] = expr + return "%(" + specifier + ")s" + + def push_format_context(self): + self.explanation_specifiers = {} + self.stack.append(self.explanation_specifiers) + + def pop_format_context(self, expl_expr): + current = self.stack.pop() + if self.stack: + self.explanation_specifiers = self.stack[-1] + keys = [ast.Str(key) for key in current.keys()] + format_dict = ast.Dict(keys, list(current.values())) + form = ast.BinOp(expl_expr, ast.Mod(), format_dict) + name = "@py_format" + str(next(self.variable_counter)) + self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form)) + return ast.Name(name, ast.Load()) + + def generic_visit(self, node): + """Handle expressions we don't have custom code for.""" + assert isinstance(node, ast.expr) + res = self.assign(node) + return res, self.explanation_param(self.display(res)) + + def visit_Assert(self, assert_): + if assert_.msg: + # There's already a message. Don't mess with it. + return [assert_] + self.statements = [] + self.variables = set() + self.variable_counter = itertools.count() + self.stack = [] + self.on_failure = [] + self.push_format_context() + # Rewrite assert into a bunch of statements. + top_condition, explanation = self.visit(assert_.test) + # Create failure message. + body = self.on_failure + negation = ast.UnaryOp(ast.Not(), top_condition) + self.statements.append(ast.If(negation, body, [])) + explanation = "assert " + explanation + template = ast.Str(explanation) + msg = self.pop_format_context(template) + fmt = self.helper("format_explanation", msg) + err_name = ast.Name("AssertionError", ast.Load()) + exc = ast.Call(err_name, [fmt], [], None, None) + if sys.version_info[0] >= 3: + raise_ = ast.Raise(exc, None) + else: + raise_ = ast.Raise(exc, None, None) + body.append(raise_) + # Delete temporary variables. + names = [ast.Name(name, ast.Del()) for name in self.variables] + if names: + delete = ast.Delete(names) + self.statements.append(delete) + # Fix line numbers. + for stmt in self.statements: + set_location(stmt, assert_.lineno, assert_.col_offset) + return self.statements + + def visit_Name(self, name): + # Check if the name is local or not. + locs = ast.Call(self.builtin("locals"), [], [], None, None) + globs = ast.Call(self.builtin("globals"), [], [], None, None) + ops = [ast.In(), ast.IsNot()] + test = ast.Compare(ast.Str(name.id), ops, [locs, globs]) + expr = ast.IfExp(test, self.display(name), ast.Str(name.id)) + return name, self.explanation_param(expr) + + def visit_BoolOp(self, boolop): + operands = [] + explanations = [] + self.push_format_context() + for operand in boolop.values: + res, explanation = self.visit(operand) + operands.append(res) + explanations.append(explanation) + expls = ast.Tuple([ast.Str(expl) for expl in explanations], ast.Load()) + is_or = ast.Num(isinstance(boolop.op, ast.Or)) + expl_template = self.helper("format_boolop", + ast.Tuple(operands, ast.Load()), expls, + is_or) + expl = self.pop_format_context(expl_template) + res = self.assign(ast.BoolOp(boolop.op, operands)) + return res, self.explanation_param(expl) + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_res, operand_expl = self.visit(unary.operand) + res = self.assign(ast.UnaryOp(unary.op, operand_res)) + return res, pattern % (operand_expl,) + + def visit_BinOp(self, binop): + symbol = binop_map[binop.op.__class__] + left_expr, left_expl = self.visit(binop.left) + right_expr, right_expl = self.visit(binop.right) + explanation = "(%s %s %s)" % (left_expl, symbol, right_expl) + res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) + return res, explanation + + def visit_Call(self, call): + new_func, func_expl = self.visit(call.func) + arg_expls = [] + new_args = [] + new_kwargs = [] + new_star = new_kwarg = None + for arg in call.args: + res, expl = self.visit(arg) + new_args.append(res) + arg_expls.append(expl) + for keyword in call.keywords: + res, expl = self.visit(keyword.value) + new_kwargs.append(ast.keyword(keyword.arg, res)) + arg_expls.append(keyword.arg + "=" + expl) + if call.starargs: + new_star, expl = self.visit(call.starargs) + arg_expls.append("*" + expl) + if call.kwargs: + new_kwarg, expl = self.visit(call.kwarg) + arg_expls.append("**" + expl) + expl = "%s(%s)" % (func_expl, ', '.join(arg_expls)) + new_call = ast.Call(new_func, new_args, new_kwargs, new_star, new_kwarg) + res = self.assign(new_call) + res_expl = self.explanation_param(self.display(res)) + outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl) + return res, outer_expl + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + value, value_expl = self.visit(attr.value) + res = self.assign(ast.Attribute(value, attr.attr, ast.Load())) + res_expl = self.explanation_param(self.display(res)) + pat = "%s\n{%s = %s.%s\n}" + expl = pat % (res_expl, res_expl, value_expl, attr.attr) + return res, expl + + def visit_Compare(self, comp): + self.push_format_context() + left_res, left_expl = self.visit(comp.left) + res_variables = [self.variable() for i in range(len(comp.ops))] + load_names = [ast.Name(v, ast.Load()) for v in res_variables] + store_names = [ast.Name(v, ast.Store()) for v in res_variables] + it = zip(range(len(comp.ops)), comp.ops, comp.comparators) + expls = [] + syms = [] + results = [left_res] + for i, op, next_operand in it: + next_res, next_expl = self.visit(next_operand) + results.append(next_res) + sym = binop_map[op.__class__] + syms.append(ast.Str(sym)) + expl = "%s %s %s" % (left_expl, sym, next_expl) + expls.append(ast.Str(expl)) + res_expr = ast.Compare(left_res, [op], [next_res]) + self.statements.append(ast.Assign([store_names[i]], res_expr)) + left_res, left_expl = next_res, next_expl + # Use py.code._reprcompare if that's available. + expl_call = self.helper("call_reprcompare", + ast.Tuple(syms, ast.Load()), + ast.Tuple(load_names, ast.Load()), + ast.Tuple(expls, ast.Load()), + ast.Tuple(results, ast.Load())) + if len(comp.ops) > 1: + res = ast.BoolOp(ast.And(), load_names) + else: + res = load_names[0] + return res, self.explanation_param(self.pop_format_context(expl_call)) diff --git a/_pytest/assertion/util.py b/_pytest/assertion/util.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/util.py @@ -0,0 +1,213 @@ +"""Utilities for assertion debugging""" + +import py + + +# The _reprcompare attribute on the util module is used by the new assertion +# interpretation code and assertion rewriter to detect this plugin was +# loaded and in turn call the hooks defined here as part of the +# DebugInterpreter. +_reprcompare = None + +def format_explanation(explanation): + """This formats an explanation + + Normally all embedded newlines are escaped, however there are + three exceptions: \n{, \n} and \n~. The first two are intended + cover nested explanations, see function and attribute explanations + for examples (.visit_Call(), visit_Attribute()). The last one is + for when one explanation needs to span multiple lines, e.g. when + displaying diffs. + """ + # simplify 'assert False where False = ...' + where = 0 + while True: + start = where = explanation.find("False\n{False = ", where) + if where == -1: + break + level = 0 + for i, c in enumerate(explanation[start:]): + if c == "{": + level += 1 + elif c == "}": + level -= 1 + if not level: + break + else: + raise AssertionError("unbalanced braces: %r" % (explanation,)) + end = start + i + where = end + if explanation[end - 1] == '\n': + explanation = (explanation[:start] + explanation[start+15:end-1] + + explanation[end+1:]) + where -= 17 + raw_lines = (explanation or '').split('\n') + # escape newlines not followed by {, } and ~ + lines = [raw_lines[0]] + for l in raw_lines[1:]: + if l.startswith('{') or l.startswith('}') or l.startswith('~'): + lines.append(l) + else: + lines[-1] += '\\n' + l + + result = lines[:1] + stack = [0] + stackcnt = [0] + for line in lines[1:]: + if line.startswith('{'): + if stackcnt[-1]: + s = 'and ' + else: + s = 'where ' + stack.append(len(result)) + stackcnt[-1] += 1 + stackcnt.append(0) + result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) + elif line.startswith('}'): + assert line.startswith('}') + stack.pop() + stackcnt.pop() + result[stack[-1]] += line[1:] + else: + assert line.startswith('~') + result.append(' '*len(stack) + line[1:]) + assert len(stack) == 1 + return '\n'.join(result) + + +# Provide basestring in python3 +try: + basestring = basestring +except NameError: + basestring = str + + +def assertrepr_compare(op, left, right): + """return specialised explanations for some operators/operands""" + width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op + left_repr = py.io.saferepr(left, maxsize=int(width/2)) + right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) + summary = '%s %s %s' % (left_repr, op, right_repr) + + issequence = lambda x: isinstance(x, (list, tuple)) + istext = lambda x: isinstance(x, basestring) + isdict = lambda x: isinstance(x, dict) + isset = lambda x: isinstance(x, set) + + explanation = None + try: + if op == '==': + if istext(left) and istext(right): + explanation = _diff_text(left, right) + elif issequence(left) and issequence(right): + explanation = _compare_eq_sequence(left, right) + elif isset(left) and isset(right): + explanation = _compare_eq_set(left, right) + elif isdict(left) and isdict(right): + explanation = _diff_text(py.std.pprint.pformat(left), + py.std.pprint.pformat(right)) + elif op == 'not in': + if istext(left) and istext(right): + explanation = _notin_text(left, right) + except py.builtin._sysex: + raise + except: + excinfo = py.code.ExceptionInfo() + explanation = ['(pytest_assertion plugin: representation of ' + 'details failed. Probably an object has a faulty __repr__.)', + str(excinfo) + ] + + + if not explanation: + return None + + # Don't include pageloads of data, should be configurable + if len(''.join(explanation)) > 80*8: + explanation = ['Detailed information too verbose, truncated'] + + return [summary] + explanation + + +def _diff_text(left, right): + """Return the explanation for the diff between text + + This will skip leading and trailing characters which are + identical to keep the diff minimal. + """ + explanation = [] + i = 0 # just in case left or right has zero length + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + break + if i > 42: + i -= 10 # Provide some context + explanation = ['Skipping %s identical ' + 'leading characters in diff' % i] + left = left[i:] + right = right[i:] + if len(left) == len(right): + for i in range(len(left)): + if left[-i] != right[-i]: + break + if i > 42: + i -= 10 # Provide some context + explanation += ['Skipping %s identical ' + 'trailing characters in diff' % i] + left = left[:-i] + right = right[:-i] + explanation += [line.strip('\n') + for line in py.std.difflib.ndiff(left.splitlines(), + right.splitlines())] + return explanation + + +def _compare_eq_sequence(left, right): + explanation = [] + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + explanation += ['At index %s diff: %r != %r' % + (i, left[i], right[i])] + break + if len(left) > len(right): + explanation += ['Left contains more items, ' + 'first extra item: %s' % py.io.saferepr(left[len(right)],)] + elif len(left) < len(right): + explanation += ['Right contains more items, ' + 'first extra item: %s' % py.io.saferepr(right[len(left)],)] + return explanation # + _diff_text(py.std.pprint.pformat(left), + # py.std.pprint.pformat(right)) + + +def _compare_eq_set(left, right): + explanation = [] + diff_left = left - right + diff_right = right - left + if diff_left: + explanation.append('Extra items in the left set:') + for item in diff_left: + explanation.append(py.io.saferepr(item)) + if diff_right: + explanation.append('Extra items in the right set:') + for item in diff_right: + explanation.append(py.io.saferepr(item)) + return explanation + + +def _notin_text(term, text): + index = text.find(term) + head = text[:index] + tail = text[index+len(term):] + correct_text = head + tail + diff = _diff_text(correct_text, text) + newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] + for line in diff: + if line.startswith('Skipping'): + continue + if line.startswith('- '): + continue + if line.startswith('+ '): + newdiff.append(' ' + line[2:]) + else: + newdiff.append(line) + return newdiff diff --git a/_pytest/doctest.py b/_pytest/doctest.py --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -59,7 +59,7 @@ inner_excinfo = py.code.ExceptionInfo(excinfo.value.exc_info) lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)] - + lines += py.std.traceback.format_exception(*excinfo.value.exc_info) return ReprFailDoctest(reprlocation, lines) else: return super(DoctestItem, self).repr_failure(excinfo) diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -16,9 +16,6 @@ group.addoption('--traceconfig', action="store_true", dest="traceconfig", default=False, help="trace considerations of conftest.py files."), - group._addoption('--nomagic', - action="store_true", dest="nomagic", default=False, - help="don't reinterpret asserts, no traceback cutting. ") group.addoption('--debug', action="store_true", dest="debug", default=False, help="generate and show internal debugging information.") diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -65,7 +65,8 @@ class LogXML(object): def __init__(self, logfile, prefix): - self.logfile = logfile + logfile = os.path.expanduser(os.path.expandvars(logfile)) + self.logfile = os.path.normpath(logfile) self.prefix = prefix self.test_logs = [] self.passed = self.skipped = 0 @@ -76,7 +77,7 @@ names = report.nodeid.split("::") names[0] = names[0].replace("/", '.') names = tuple(names) - d = {'time': self._durations.pop(names, "0")} + d = {'time': self._durations.pop(report.nodeid, "0")} names = [x.replace(".py", "") for x in names if x != "()"] classnames = names[:-1] if self.prefix: @@ -170,12 +171,11 @@ self.append_skipped(report) def pytest_runtest_call(self, item, __multicall__): - names = tuple(item.listnames()) start = time.time() try: return __multicall__.execute() finally: - self._durations[names] = time.time() - start + self._durations[item.nodeid] = time.time() - start def pytest_collectreport(self, report): if not report.passed: diff --git a/_pytest/main.py b/_pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -46,23 +46,25 @@ def pytest_namespace(): - return dict(collect=dict(Item=Item, Collector=Collector, File=File)) + collect = dict(Item=Item, Collector=Collector, File=File, Session=Session) + return dict(collect=collect) def pytest_configure(config): py.test.config = config # compatibiltiy if config.option.exitfirst: config.option.maxfail = 1 -def pytest_cmdline_main(config): - """ default command line protocol for initialization, session, - running tests and reporting. """ +def wrap_session(config, doit): + """Skeleton command line program""" session = Session(config) session.exitstatus = EXIT_OK + initstate = 0 try: config.pluginmanager.do_configure(config) + initstate = 1 config.hook.pytest_sessionstart(session=session) - config.hook.pytest_collection(session=session) - config.hook.pytest_runtestloop(session=session) + initstate = 2 + doit(config, session) except pytest.UsageError: raise except KeyboardInterrupt: @@ -77,18 +79,24 @@ sys.stderr.write("mainloop: caught Spurious SystemExit!\n") if not session.exitstatus and session._testsfailed: session.exitstatus = EXIT_TESTSFAILED - config.hook.pytest_sessionfinish(session=session, - exitstatus=session.exitstatus) - config.pluginmanager.do_unconfigure(config) + if initstate >= 2: + config.hook.pytest_sessionfinish(session=session, + exitstatus=session.exitstatus) + if initstate >= 1: + config.pluginmanager.do_unconfigure(config) return session.exitstatus +def pytest_cmdline_main(config): + return wrap_session(config, _main) + +def _main(config, session): + """ default command line protocol for initialization, session, + running tests and reporting. """ + config.hook.pytest_collection(session=session) + config.hook.pytest_runtestloop(session=session) + def pytest_collection(session): - session.perform_collect() - hook = session.config.hook - hook.pytest_collection_modifyitems(session=session, - config=session.config, items=session.items) - hook.pytest_collection_finish(session=session) - return True + return session.perform_collect() def pytest_runtestloop(session): if session.config.option.collectonly: @@ -374,6 +382,16 @@ return HookProxy(fspath, self.config) def perform_collect(self, args=None, genitems=True): + hook = self.config.hook + try: + items = self._perform_collect(args, genitems) + hook.pytest_collection_modifyitems(session=self, + config=self.config, items=items) + finally: + hook.pytest_collection_finish(session=self) + return items + + def _perform_collect(self, args, genitems): if args is None: args = self.config.args self.trace("perform_collect", self, args) diff --git a/_pytest/mark.py b/_pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -153,7 +153,7 @@ def __repr__(self): return "" % ( - self._name, self.args, self.kwargs) + self.name, self.args, self.kwargs) def pytest_itemcollected(item): if not isinstance(item, pytest.Function): diff --git a/_pytest/pytester.py b/_pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -6,7 +6,7 @@ import inspect import time from fnmatch import fnmatch -from _pytest.main import Session +from _pytest.main import Session, EXIT_OK from py.builtin import print_ from _pytest.core import HookRelay @@ -292,13 +292,19 @@ assert '::' not in str(arg) p = py.path.local(arg) x = session.fspath.bestrelpath(p) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def getpathnode(self, path): - config = self.parseconfig(path) + config = self.parseconfigure(path) session = Session(config) x = session.fspath.bestrelpath(path) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def genitems(self, colitems): session = colitems[0].session @@ -312,7 +318,9 @@ config = self.parseconfigure(*args) rec = self.getreportrecorder(config) session = Session(config) + config.hook.pytest_sessionstart(session=session) session.perform_collect() + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) return session.items, rec def runitem(self, source): @@ -382,6 +390,8 @@ c.basetemp = py.path.local.make_numbered_dir(prefix="reparse", keep=0, rootdir=self.tmpdir, lock_timeout=None) c.parse(args) + c.pluginmanager.do_configure(c) + self.request.addfinalizer(lambda: c.pluginmanager.do_unconfigure(c)) return c finally: py.test.config = oldconfig diff --git a/_pytest/python.py b/_pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -226,8 +226,13 @@ def _importtestmodule(self): # we assume we are only called once per module + from _pytest import assertion + assertion.before_module_import(self) try: - mod = self.fspath.pyimport(ensuresyspath=True) + try: + mod = self.fspath.pyimport(ensuresyspath=True) + finally: + assertion.after_module_import(self) except SyntaxError: excinfo = py.code.ExceptionInfo() raise self.CollectError(excinfo.getrepr(style="short")) @@ -374,7 +379,7 @@ # test generators are seen as collectors but they also # invoke setup/teardown on popular request # (induced by the common "test_*" naming shared with normal tests) - self.config._setupstate.prepare(self) + self.session._setupstate.prepare(self) # see FunctionMixin.setup and test_setupstate_is_preserved_134 self._preservedparent = self.parent.obj l = [] @@ -721,7 +726,7 @@ def _addfinalizer(self, finalizer, scope): colitem = self._getscopeitem(scope) - self.config._setupstate.addfinalizer( + self._pyfuncitem.session._setupstate.addfinalizer( finalizer=finalizer, colitem=colitem) def __repr__(self): @@ -742,8 +747,10 @@ raise self.LookupError(msg) def showfuncargs(config): - from _pytest.main import Session - session = Session(config) + from _pytest.main import wrap_session + return wrap_session(config, _showfuncargs_main) + +def _showfuncargs_main(config, session): session.perform_collect() if session.items: plugins = session.items[0].getplugins() diff --git a/_pytest/runner.py b/_pytest/runner.py --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -14,17 +14,15 @@ # # pytest plugin hooks -# XXX move to pytest_sessionstart and fix py.test owns tests -def pytest_configure(config): - config._setupstate = SetupState() +def pytest_sessionstart(session): + session._setupstate = SetupState() def pytest_sessionfinish(session, exitstatus): - if hasattr(session.config, '_setupstate'): - hook = session.config.hook - rep = hook.pytest__teardown_final(session=session) - if rep: - hook.pytest__teardown_final_logerror(session=session, report=rep) - session.exitstatus = 1 + hook = session.config.hook + rep = hook.pytest__teardown_final(session=session) + if rep: + hook.pytest__teardown_final_logerror(session=session, report=rep) + session.exitstatus = 1 class NodeInfo: def __init__(self, location): @@ -46,16 +44,16 @@ return reports def pytest_runtest_setup(item): - item.config._setupstate.prepare(item) + item.session._setupstate.prepare(item) def pytest_runtest_call(item): item.runtest() def pytest_runtest_teardown(item): - item.config._setupstate.teardown_exact(item) + item.session._setupstate.teardown_exact(item) def pytest__teardown_final(session): - call = CallInfo(session.config._setupstate.teardown_all, when="teardown") + call = CallInfo(session._setupstate.teardown_all, when="teardown") if call.excinfo: ntraceback = call.excinfo.traceback .cut(excludepath=py._pydir) call.excinfo.traceback = ntraceback.filter() diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,13 +4399,10 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__self__ is l) + if hasattr(l.__add__, '__objclass__'): # CPython self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) + else: # PyPy self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_extcall.py b/lib-python/modified-2.7/test/test_extcall.py --- a/lib-python/modified-2.7/test/test_extcall.py +++ b/lib-python/modified-2.7/test/test_extcall.py @@ -299,7 +299,7 @@ def f(a): return a self.assertEqual(f(**{u'a': 4}), 4) - self.assertRaises(TypeError, lambda: f(**{u'stören': 4})) + self.assertRaises(TypeError, f, **{u'stören': 4}) self.assertRaises(TypeError, f, **{u'someLongString':2}) try: f(a=4, **{u'a': 4}) diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -139,7 +139,10 @@ return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -218,5 +221,7 @@ 'z' : _ffi.types.void_p, 'O' : _ffi.types.void_p, 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, } diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -322,20 +322,18 @@ RuntimeWarning, stacklevel=2) if self._com_index: - assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None - - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -343,6 +341,11 @@ if not outargs: return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + if len(outargs) == 1: return outargs[0] return tuple(outargs) @@ -398,10 +401,10 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) cdll = self.dll._handle try: @@ -468,11 +471,7 @@ newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -587,13 +586,7 @@ retval = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, argsandobjs[0]) - else: - retval = int(resbuffer[0]) - elif restype is not None: + if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) @@ -601,7 +594,13 @@ # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value - retval = checker(val) + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) else: diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -216,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -275,7 +275,8 @@ return unicode(x, 'utf-8') class Connection(object): - def __init__(self, database, isolation_level="", detect_types=0, timeout=None, cached_statements=None, factory=None): + def __init__(self, database, timeout=5.0, detect_types=0, isolation_level="", + check_same_thread=True, factory=None, cached_statements=100): self.db = c_void_p() if sqlite.sqlite3_open(database, byref(self.db)) != SQLITE_OK: raise OperationalError("Could not open database") @@ -308,7 +309,8 @@ self._aggregates = {} self.aggregate_instances = {} self._collations = {} - self.thread_ident = thread_get_ident() + if check_same_thread: + self.thread_ident = thread_get_ident() def _get_exception(self, error_code = None): if error_code is None: diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/lib_pypy/resource.py b/lib_pypy/resource.py --- a/lib_pypy/resource.py +++ b/lib_pypy/resource.py @@ -7,7 +7,7 @@ from ctypes_support import standard_c_lib as libc from ctypes_support import get_errno -from ctypes import Structure, c_int, c_long, byref, sizeof +from ctypes import Structure, c_int, c_long, byref, sizeof, POINTER from errno import EINVAL, EPERM import _structseq @@ -25,6 +25,8 @@ _setrlimit = libc.setrlimit try: _getpagesize = libc.getpagesize + _getpagesize.argtypes = () + _getpagesize.restype = c_int except AttributeError: from os import sysconf _getpagesize = None @@ -61,6 +63,10 @@ ("ru_nivcsw", c_long), ) +_getrusage.argtypes = (c_int, POINTER(_struct_rusage)) +_getrusage.restype = c_int + + class struct_rusage: __metaclass__ = _structseq.structseqtype @@ -94,6 +100,12 @@ ("rlim_max", rlim_t), ) +_getrlimit.argtypes = (c_int, POINTER(rlimit)) +_getrlimit.restype = c_int +_setrlimit.argtypes = (c_int, POINTER(rlimit)) +_setrlimit.restype = c_int + + @builtinify def getrusage(who): ru = _struct_rusage() diff --git a/py/__init__.py b/py/__init__.py --- a/py/__init__.py +++ b/py/__init__.py @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2010 """ -__version__ = '1.4.3' +__version__ = '1.4.4.dev1' from py import _apipkg @@ -70,10 +70,6 @@ 'getrawcode' : '._code.code:getrawcode', 'patch_builtins' : '._code.code:patch_builtins', 'unpatch_builtins' : '._code.code:unpatch_builtins', - '_AssertionError' : '._code.assertion:AssertionError', - '_reinterpret_old' : '._code.assertion:reinterpret_old', - '_reinterpret' : '._code.assertion:reinterpret', - '_reprcompare' : '._code.assertion:_reprcompare', }, # backports and additions of builtins diff --git a/py/_code/_assertionnew.py b/py/_code/_assertionnew.py deleted file mode 100644 --- a/py/_code/_assertionnew.py +++ /dev/null @@ -1,339 +0,0 @@ -""" -Find intermediate evalutation results in assert statements through builtin AST. -This should replace _assertionold.py eventually. -""" - -import sys -import ast - -import py -from py._code.assertion import _format_explanation, BuiltinAssertionError - - -if sys.platform.startswith("java") and sys.version_info < (2, 5, 2): - # See http://bugs.jython.org/issue1497 - _exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict", - "ListComp", "GeneratorExp", "Yield", "Compare", "Call", - "Repr", "Num", "Str", "Attribute", "Subscript", "Name", - "List", "Tuple") - _stmts = ("FunctionDef", "ClassDef", "Return", "Delete", "Assign", - "AugAssign", "Print", "For", "While", "If", "With", "Raise", - "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom", - "Exec", "Global", "Expr", "Pass", "Break", "Continue") - _expr_nodes = set(getattr(ast, name) for name in _exprs) - _stmt_nodes = set(getattr(ast, name) for name in _stmts) - def _is_ast_expr(node): - return node.__class__ in _expr_nodes - def _is_ast_stmt(node): - return node.__class__ in _stmt_nodes -else: - def _is_ast_expr(node): - return isinstance(node, ast.expr) - def _is_ast_stmt(node): - return isinstance(node, ast.stmt) - - -class Failure(Exception): - """Error found while interpreting AST.""" - - def __init__(self, explanation=""): - self.cause = sys.exc_info() - self.explanation = explanation - - -def interpret(source, frame, should_fail=False): - mod = ast.parse(source) - visitor = DebugInterpreter(frame) - try: - visitor.visit(mod) - except Failure: - failure = sys.exc_info()[1] - return getfailure(failure) - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --no-assert)") - -def run(offending_line, frame=None): - if frame is None: - frame = py.code.Frame(sys._getframe(1)) - return interpret(offending_line, frame) - -def getfailure(failure): - explanation = _format_explanation(failure.explanation) - value = failure.cause[1] - if str(value): - lines = explanation.splitlines() - if not lines: - lines.append("") - lines[0] += " << %s" % (value,) - explanation = "\n".join(lines) - text = "%s: %s" % (failure.cause[0].__name__, explanation) - if text.startswith("AssertionError: assert "): - text = text[16:] - return text - - -operator_map = { - ast.BitOr : "|", - ast.BitXor : "^", - ast.BitAnd : "&", - ast.LShift : "<<", - ast.RShift : ">>", - ast.Add : "+", - ast.Sub : "-", - ast.Mult : "*", - ast.Div : "/", - ast.FloorDiv : "//", - ast.Mod : "%", - ast.Eq : "==", - ast.NotEq : "!=", - ast.Lt : "<", - ast.LtE : "<=", - ast.Gt : ">", - ast.GtE : ">=", - ast.Pow : "**", - ast.Is : "is", - ast.IsNot : "is not", - ast.In : "in", - ast.NotIn : "not in" -} - -unary_map = { - ast.Not : "not %s", - ast.Invert : "~%s", - ast.USub : "-%s", - ast.UAdd : "+%s" -} - - -class DebugInterpreter(ast.NodeVisitor): - """Interpret AST nodes to gleam useful debugging information. """ - - def __init__(self, frame): - self.frame = frame - - def generic_visit(self, node): - # Fallback when we don't have a special implementation. - if _is_ast_expr(node): - mod = ast.Expression(node) - co = self._compile(mod) - try: - result = self.frame.eval(co) - except Exception: - raise Failure() - explanation = self.frame.repr(result) - return explanation, result - elif _is_ast_stmt(node): - mod = ast.Module([node]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co) - except Exception: - raise Failure() - return None, None - else: - raise AssertionError("can't handle %s" %(node,)) - - def _compile(self, source, mode="eval"): - return compile(source, "", mode) - - def visit_Expr(self, expr): - return self.visit(expr.value) - - def visit_Module(self, mod): - for stmt in mod.body: - self.visit(stmt) - - def visit_Name(self, name): - explanation, result = self.generic_visit(name) - # See if the name is local. - source = "%r in locals() is not globals()" % (name.id,) - co = self._compile(source) - try: - local = self.frame.eval(co) - except Exception: - # have to assume it isn't - local = False - if not local: - return name.id, result - return explanation, result - - def visit_Compare(self, comp): - left = comp.left - left_explanation, left_result = self.visit(left) - for op, next_op in zip(comp.ops, comp.comparators): - next_explanation, next_result = self.visit(next_op) - op_symbol = operator_map[op.__class__] - explanation = "%s %s %s" % (left_explanation, op_symbol, - next_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=next_result) - except Exception: - raise Failure(explanation) - try: - if not result: - break - except KeyboardInterrupt: - raise - except: - break - left_explanation, left_result = next_explanation, next_result - - rcomp = py.code._reprcompare - if rcomp: - res = rcomp(op_symbol, left_result, next_result) - if res: - explanation = res - return explanation, result - - def visit_BoolOp(self, boolop): - is_or = isinstance(boolop.op, ast.Or) - explanations = [] - for operand in boolop.values: - explanation, result = self.visit(operand) - explanations.append(explanation) - if result == is_or: - break - name = is_or and " or " or " and " - explanation = "(" + name.join(explanations) + ")" - return explanation, result - - def visit_UnaryOp(self, unary): - pattern = unary_map[unary.op.__class__] - operand_explanation, operand_result = self.visit(unary.operand) - explanation = pattern % (operand_explanation,) - co = self._compile(pattern % ("__exprinfo_expr",)) - try: - result = self.frame.eval(co, __exprinfo_expr=operand_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_BinOp(self, binop): - left_explanation, left_result = self.visit(binop.left) - right_explanation, right_result = self.visit(binop.right) - symbol = operator_map[binop.op.__class__] - explanation = "(%s %s %s)" % (left_explanation, symbol, - right_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=right_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_Call(self, call): - func_explanation, func = self.visit(call.func) - arg_explanations = [] - ns = {"__exprinfo_func" : func} - arguments = [] - for arg in call.args: - arg_explanation, arg_result = self.visit(arg) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - arguments.append(arg_name) - arg_explanations.append(arg_explanation) - for keyword in call.keywords: - arg_explanation, arg_result = self.visit(keyword.value) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - keyword_source = "%s=%%s" % (keyword.arg) - arguments.append(keyword_source % (arg_name,)) - arg_explanations.append(keyword_source % (arg_explanation,)) - if call.starargs: - arg_explanation, arg_result = self.visit(call.starargs) - arg_name = "__exprinfo_star" - ns[arg_name] = arg_result - arguments.append("*%s" % (arg_name,)) - arg_explanations.append("*%s" % (arg_explanation,)) - if call.kwargs: - arg_explanation, arg_result = self.visit(call.kwargs) - arg_name = "__exprinfo_kwds" - ns[arg_name] = arg_result - arguments.append("**%s" % (arg_name,)) - arg_explanations.append("**%s" % (arg_explanation,)) - args_explained = ", ".join(arg_explanations) - explanation = "%s(%s)" % (func_explanation, args_explained) - args = ", ".join(arguments) - source = "__exprinfo_func(%s)" % (args,) - co = self._compile(source) - try: - result = self.frame.eval(co, **ns) - except Exception: - raise Failure(explanation) - pattern = "%s\n{%s = %s\n}" - rep = self.frame.repr(result) - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def _is_builtin_name(self, name): - pattern = "%r not in globals() and %r not in locals()" - source = pattern % (name.id, name.id) - co = self._compile(source) - try: - return self.frame.eval(co) - except Exception: - return False - - def visit_Attribute(self, attr): - if not isinstance(attr.ctx, ast.Load): - return self.generic_visit(attr) - source_explanation, source_result = self.visit(attr.value) - explanation = "%s.%s" % (source_explanation, attr.attr) - source = "__exprinfo_expr.%s" % (attr.attr,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - raise Failure(explanation) - explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), - self.frame.repr(result), - source_explanation, attr.attr) - # Check if the attr is from an instance. - source = "%r in getattr(__exprinfo_expr, '__dict__', {})" - source = source % (attr.attr,) - co = self._compile(source) - try: - from_instance = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - from_instance = True - if from_instance: - rep = self.frame.repr(result) - pattern = "%s\n{%s = %s\n}" - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def visit_Assert(self, assrt): - test_explanation, test_result = self.visit(assrt.test) - if test_explanation.startswith("False\n{False =") and \ - test_explanation.endswith("\n"): - test_explanation = test_explanation[15:-2] - explanation = "assert %s" % (test_explanation,) - if not test_result: - try: - raise BuiltinAssertionError - except Exception: - raise Failure(explanation) - return explanation, test_result - - def visit_Assign(self, assign): - value_explanation, value_result = self.visit(assign.value) - explanation = "... = %s" % (value_explanation,) - name = ast.Name("__exprinfo_expr", ast.Load(), - lineno=assign.value.lineno, - col_offset=assign.value.col_offset) - new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, - col_offset=assign.col_offset) - mod = ast.Module([new_assign]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co, __exprinfo_expr=value_result) - except Exception: - raise Failure(explanation) - return explanation, value_result diff --git a/py/_code/_assertionold.py b/py/_code/_assertionold.py deleted file mode 100644 --- a/py/_code/_assertionold.py +++ /dev/null @@ -1,555 +0,0 @@ -import py -import sys, inspect -from compiler import parse, ast, pycodegen -from py._code.assertion import BuiltinAssertionError, _format_explanation - -passthroughex = py.builtin._sysex - -class Failure: - def __init__(self, node): - self.exc, self.value, self.tb = sys.exc_info() - self.node = node - -class View(object): - """View base class. - - If C is a subclass of View, then C(x) creates a proxy object around - the object x. The actual class of the proxy is not C in general, - but a *subclass* of C determined by the rules below. To avoid confusion - we call view class the class of the proxy (a subclass of C, so of View) - and object class the class of x. - - Attributes and methods not found in the proxy are automatically read on x. - Other operations like setting attributes are performed on the proxy, as - determined by its view class. The object x is available from the proxy - as its __obj__ attribute. - - The view class selection is determined by the __view__ tuples and the - optional __viewkey__ method. By default, the selected view class is the - most specific subclass of C whose __view__ mentions the class of x. - If no such subclass is found, the search proceeds with the parent - object classes. For example, C(True) will first look for a subclass - of C with __view__ = (..., bool, ...) and only if it doesn't find any - look for one with __view__ = (..., int, ...), and then ..., object,... - If everything fails the class C itself is considered to be the default. - - Alternatively, the view class selection can be driven by another aspect - of the object x, instead of the class of x, by overriding __viewkey__. - See last example at the end of this module. - """ - - _viewcache = {} - __view__ = () - - def __new__(rootclass, obj, *args, **kwds): - self = object.__new__(rootclass) - self.__obj__ = obj - self.__rootclass__ = rootclass - key = self.__viewkey__() - try: - self.__class__ = self._viewcache[key] - except KeyError: - self.__class__ = self._selectsubclass(key) - return self - - def __getattr__(self, attr): - # attributes not found in the normal hierarchy rooted on View - # are looked up in the object's real class - return getattr(self.__obj__, attr) - - def __viewkey__(self): - return self.__obj__.__class__ - - def __matchkey__(self, key, subclasses): - if inspect.isclass(key): - keys = inspect.getmro(key) - else: - keys = [key] - for key in keys: - result = [C for C in subclasses if key in C.__view__] - if result: - return result - return [] - - def _selectsubclass(self, key): - subclasses = list(enumsubclasses(self.__rootclass__)) - for C in subclasses: - if not isinstance(C.__view__, tuple): - C.__view__ = (C.__view__,) - choices = self.__matchkey__(key, subclasses) - if not choices: - return self.__rootclass__ - elif len(choices) == 1: - return choices[0] - else: - # combine the multiple choices - return type('?', tuple(choices), {}) - - def __repr__(self): - return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) - - -def enumsubclasses(cls): - for subcls in cls.__subclasses__(): - for subsubclass in enumsubclasses(subcls): - yield subsubclass - yield cls - - -class Interpretable(View): - """A parse tree node with a few extra methods.""" - explanation = None - - def is_builtin(self, frame): - return False - - def eval(self, frame): - # fall-back for unknown expression nodes - try: - expr = ast.Expression(self.__obj__) - expr.filename = '' - self.__obj__.filename = '' - co = pycodegen.ExpressionCodeGenerator(expr).getCode() - result = frame.eval(co) - except passthroughex: - raise - except: - raise Failure(self) - self.result = result - self.explanation = self.explanation or frame.repr(self.result) - - def run(self, frame): - # fall-back for unknown statement nodes - try: - expr = ast.Module(None, ast.Stmt([self.__obj__])) - expr.filename = '' - co = pycodegen.ModuleCodeGenerator(expr).getCode() - frame.exec_(co) - except passthroughex: - raise - except: - raise Failure(self) - - def nice_explanation(self): - return _format_explanation(self.explanation) - - -class Name(Interpretable): - __view__ = ast.Name - - def is_local(self, frame): - source = '%r in locals() is not globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_global(self, frame): - source = '%r in globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_builtin(self, frame): - source = '%r not in locals() and %r not in globals()' % ( - self.name, self.name) - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - super(Name, self).eval(frame) - if not self.is_local(frame): - self.explanation = self.name - -class Compare(Interpretable): - __view__ = ast.Compare - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - for operation, expr2 in self.ops: - if hasattr(self, 'result'): - # shortcutting in chained expressions - if not frame.is_true(self.result): - break - expr2 = Interpretable(expr2) - expr2.eval(frame) - self.explanation = "%s %s %s" % ( - expr.explanation, operation, expr2.explanation) - source = "__exprinfo_left %s __exprinfo_right" % operation - try: - self.result = frame.eval(source, - __exprinfo_left=expr.result, - __exprinfo_right=expr2.result) - except passthroughex: - raise - except: - raise Failure(self) - expr = expr2 - -class And(Interpretable): - __view__ = ast.And - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if not frame.is_true(expr.result): - break - self.explanation = '(' + ' and '.join(explanations) + ')' - -class Or(Interpretable): - __view__ = ast.Or - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if frame.is_true(expr.result): - break - self.explanation = '(' + ' or '.join(explanations) + ')' - - -# == Unary operations == -keepalive = [] -for astclass, astpattern in { - ast.Not : 'not __exprinfo_expr', - ast.Invert : '(~__exprinfo_expr)', - }.items(): - - class UnaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - expr = Interpretable(self.expr) - expr.eval(frame) - self.explanation = astpattern.replace('__exprinfo_expr', - expr.explanation) - try: - self.result = frame.eval(astpattern, - __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(UnaryArith) - -# == Binary operations == -for astclass, astpattern in { - ast.Add : '(__exprinfo_left + __exprinfo_right)', - ast.Sub : '(__exprinfo_left - __exprinfo_right)', - ast.Mul : '(__exprinfo_left * __exprinfo_right)', - ast.Div : '(__exprinfo_left / __exprinfo_right)', - ast.Mod : '(__exprinfo_left % __exprinfo_right)', - ast.Power : '(__exprinfo_left ** __exprinfo_right)', - }.items(): - - class BinaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - left = Interpretable(self.left) - left.eval(frame) - right = Interpretable(self.right) - right.eval(frame) - self.explanation = (astpattern - .replace('__exprinfo_left', left .explanation) - .replace('__exprinfo_right', right.explanation)) - try: - self.result = frame.eval(astpattern, - __exprinfo_left=left.result, - __exprinfo_right=right.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(BinaryArith) - - -class CallFunc(Interpretable): - __view__ = ast.CallFunc - - def is_bool(self, frame): - source = 'isinstance(__exprinfo_value, bool)' - try: - return frame.is_true(frame.eval(source, - __exprinfo_value=self.result)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - node = Interpretable(self.node) - node.eval(frame) - explanations = [] - vars = {'__exprinfo_fn': node.result} - source = '__exprinfo_fn(' - for a in self.args: - if isinstance(a, ast.Keyword): - keyword = a.name - a = a.expr - else: - keyword = None - a = Interpretable(a) - a.eval(frame) - argname = '__exprinfo_%d' % len(vars) - vars[argname] = a.result - if keyword is None: - source += argname + ',' - explanations.append(a.explanation) - else: - source += '%s=%s,' % (keyword, argname) - explanations.append('%s=%s' % (keyword, a.explanation)) - if self.star_args: - star_args = Interpretable(self.star_args) - star_args.eval(frame) - argname = '__exprinfo_star' - vars[argname] = star_args.result - source += '*' + argname + ',' - explanations.append('*' + star_args.explanation) - if self.dstar_args: - dstar_args = Interpretable(self.dstar_args) - dstar_args.eval(frame) - argname = '__exprinfo_kwds' - vars[argname] = dstar_args.result - source += '**' + argname + ',' - explanations.append('**' + dstar_args.explanation) - self.explanation = "%s(%s)" % ( - node.explanation, ', '.join(explanations)) - if source.endswith(','): - source = source[:-1] - source += ')' - try: - self.result = frame.eval(source, **vars) - except passthroughex: - raise - except: - raise Failure(self) - if not node.is_builtin(frame) or not self.is_bool(frame): - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -class Getattr(Interpretable): - __view__ = ast.Getattr - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - source = '__exprinfo_expr.%s' % self.attrname - try: - self.result = frame.eval(source, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - self.explanation = '%s.%s' % (expr.explanation, self.attrname) - # if the attribute comes from the instance, its value is interesting - source = ('hasattr(__exprinfo_expr, "__dict__") and ' - '%r in __exprinfo_expr.__dict__' % self.attrname) - try: - from_instance = frame.is_true( - frame.eval(source, __exprinfo_expr=expr.result)) - except passthroughex: - raise - except: - from_instance = True - if from_instance: - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -# == Re-interpretation of full statements == - -class Assert(Interpretable): - __view__ = ast.Assert - - def run(self, frame): - test = Interpretable(self.test) - test.eval(frame) - # simplify 'assert False where False = ...' - if (test.explanation.startswith('False\n{False = ') and - test.explanation.endswith('\n}')): - test.explanation = test.explanation[15:-2] - # print the result as 'assert ' - self.result = test.result - self.explanation = 'assert ' + test.explanation - if not frame.is_true(test.result): - try: - raise BuiltinAssertionError - except passthroughex: - raise - except: - raise Failure(self) - -class Assign(Interpretable): - __view__ = ast.Assign - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = '... = ' + expr.explanation - # fall-back-run the rest of the assignment - ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) - mod = ast.Module(None, ast.Stmt([ass])) - mod.filename = '' - co = pycodegen.ModuleCodeGenerator(mod).getCode() - try: - frame.exec_(co, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - -class Discard(Interpretable): - __view__ = ast.Discard - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = expr.explanation - -class Stmt(Interpretable): - __view__ = ast.Stmt - - def run(self, frame): - for stmt in self.nodes: - stmt = Interpretable(stmt) - stmt.run(frame) - - -def report_failure(e): - explanation = e.node.nice_explanation() - if explanation: - explanation = ", in: " + explanation - else: - explanation = "" - sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) - -def check(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - expr = parse(s, 'eval') - assert isinstance(expr, ast.Expression) - node = Interpretable(expr.node) - try: - node.eval(frame) - except passthroughex: - raise - except Failure: - e = sys.exc_info()[1] - report_failure(e) - else: - if not frame.is_true(node.result): - sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) - - -########################################################### -# API / Entry points -# ######################################################### - -def interpret(source, frame, should_fail=False): - module = Interpretable(parse(source, 'exec').node) - #print "got module", module - if isinstance(frame, py.std.types.FrameType): - frame = py.code.Frame(frame) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - return getfailure(e) - except passthroughex: - raise - except: - import traceback - traceback.print_exc() - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --nomagic)") - else: - return None - -def getmsg(excinfo): - if isinstance(excinfo, tuple): - excinfo = py.code.ExceptionInfo(excinfo) - #frame, line = gettbline(tb) - #frame = py.code.Frame(frame) - #return interpret(line, frame) - - tb = excinfo.traceback[-1] - source = str(tb.statement).strip() - x = interpret(source, tb.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - return x - -def getfailure(e): - explanation = e.node.nice_explanation() - if str(e.value): - lines = explanation.split('\n') - lines[0] += " << %s" % (e.value,) - explanation = '\n'.join(lines) - text = "%s: %s" % (e.exc.__name__, explanation) - if text.startswith('AssertionError: assert '): - text = text[16:] - return text - -def run(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - module = Interpretable(parse(s, 'exec').node) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - report_failure(e) - - -if __name__ == '__main__': - # example: - def f(): - return 5 - def g(): - return 3 - def h(x): - return 'never' - check("f() * g() == 5") - check("not f()") - check("not (f() and g() or 0)") - check("f() == g()") - i = 4 - check("i == f()") - check("len(f()) == 0") - check("isinstance(2+3+4, float)") - - run("x = i") - check("x == 5") - - run("assert not f(), 'oops'") - run("a, b, c = 1, 2") - run("a, b, c = f()") - - check("max([f(),g()]) == 4") - check("'hello'[g()] == 'h'") - run("'guk%d' % h(f())") diff --git a/py/_code/assertion.py b/py/_code/assertion.py deleted file mode 100644 --- a/py/_code/assertion.py +++ /dev/null @@ -1,94 +0,0 @@ -import sys -import py - -BuiltinAssertionError = py.builtin.builtins.AssertionError - -_reprcompare = None # if set, will be called by assert reinterp for comparison ops - -def _format_explanation(explanation): - """This formats an explanation - - Normally all embedded newlines are escaped, however there are - three exceptions: \n{, \n} and \n~. The first two are intended - cover nested explanations, see function and attribute explanations - for examples (.visit_Call(), visit_Attribute()). The last one is - for when one explanation needs to span multiple lines, e.g. when - displaying diffs. - """ - raw_lines = (explanation or '').split('\n') - # escape newlines not followed by {, } and ~ - lines = [raw_lines[0]] - for l in raw_lines[1:]: - if l.startswith('{') or l.startswith('}') or l.startswith('~'): - lines.append(l) - else: - lines[-1] += '\\n' + l - - result = lines[:1] - stack = [0] - stackcnt = [0] - for line in lines[1:]: - if line.startswith('{'): - if stackcnt[-1]: - s = 'and ' - else: - s = 'where ' - stack.append(len(result)) - stackcnt[-1] += 1 - stackcnt.append(0) - result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) - elif line.startswith('}'): - assert line.startswith('}') - stack.pop() - stackcnt.pop() - result[stack[-1]] += line[1:] - else: - assert line.startswith('~') - result.append(' '*len(stack) + line[1:]) - assert len(stack) == 1 - return '\n'.join(result) - - -class AssertionError(BuiltinAssertionError): - def __init__(self, *args): - BuiltinAssertionError.__init__(self, *args) - if args: - try: - self.msg = str(args[0]) - except py.builtin._sysex: - raise - except: - self.msg = "<[broken __repr__] %s at %0xd>" %( - args[0].__class__, id(args[0])) - else: - f = py.code.Frame(sys._getframe(1)) - try: - source = f.code.fullsource - if source is not None: - try: - source = source.getstatement(f.lineno, assertion=True) - except IndexError: - source = None - else: - source = str(source.deindent()).strip() - except py.error.ENOENT: - source = None - # this can also occur during reinterpretation, when the - # co_filename is set to "". - if source: - self.msg = reinterpret(source, f, should_fail=True) - else: - self.msg = "" - if not self.args: - self.args = (self.msg,) - -if sys.version_info > (3, 0): - AssertionError.__module__ = "builtins" - reinterpret_old = "old reinterpretation not available for py3" -else: - from py._code._assertionold import interpret as reinterpret_old -if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): - from py._code._assertionnew import interpret as reinterpret -else: - reinterpret = reinterpret_old - diff --git a/py/_code/code.py b/py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -145,17 +145,6 @@ return self.frame.f_locals locals = property(getlocals, None, None, "locals of underlaying frame") - def reinterpret(self): - """Reinterpret the failing statement and returns a detailed information - about what operations are performed.""" - if self.exprinfo is None: - source = str(self.statement).strip() - x = py.code._reinterpret(source, self.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - self.exprinfo = x - return self.exprinfo - def getfirstlinesource(self): # on Jython this firstlineno can be -1 apparently return max(self.frame.code.firstlineno, 0) @@ -310,7 +299,7 @@ # ExceptionInfo-like classes may have different attributes. if tup is None: tup = sys.exc_info() - if exprinfo is None and isinstance(tup[1], py.code._AssertionError): + if exprinfo is None and isinstance(tup[1], AssertionError): exprinfo = getattr(tup[1], 'msg', None) if exprinfo is None: exprinfo = str(tup[1]) @@ -690,22 +679,15 @@ oldbuiltins = {} -def patch_builtins(assertion=True, compile=True): - """ put compile and AssertionError builtins to Python's builtins. """ - if assertion: - from py._code import assertion - l = oldbuiltins.setdefault('AssertionError', []) - l.append(py.builtin.builtins.AssertionError) - py.builtin.builtins.AssertionError = assertion.AssertionError +def patch_builtins(compile=True): + """ put compile builtins to Python's builtins. """ if compile: l = oldbuiltins.setdefault('compile', []) l.append(py.builtin.builtins.compile) py.builtin.builtins.compile = py.code.compile -def unpatch_builtins(assertion=True, compile=True): +def unpatch_builtins(compile=True): """ remove compile and AssertionError builtins from Python builtins. """ - if assertion: - py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop() if compile: py.builtin.builtins.compile = oldbuiltins['compile'].pop() diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -299,12 +299,13 @@ listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) @@ -351,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -379,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -129,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -266,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -355,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -248,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/doc/garbage_collection.rst b/pypy/doc/garbage_collection.rst --- a/pypy/doc/garbage_collection.rst +++ b/pypy/doc/garbage_collection.rst @@ -212,90 +212,4 @@ becomes free garbage, to be collected at the next major collection. -Minimark GC ------------ - -This is a simplification and rewrite of the ideas from the Hybrid GC. -It uses a nursery for the young objects, and mark-and-sweep for the old -objects. This is a moving GC, but objects may only move once (from -the nursery to the old stage). - -The main difference with the Hybrid GC is that the mark-and-sweep -objects (the "old stage") are directly handled by the GC's custom -allocator, instead of being handled by malloc() calls. The gain is that -it is then possible, during a major collection, to walk through all old -generation objects without needing to store a list of pointers to them. -So as a first approximation, when compared to the Hybrid GC, the -Minimark GC saves one word of memory per old object. - -There are a number of environment variables that can be tweaked to -influence the GC. (Their default value should be ok for most usages.) -You can read more about them at the start of -`pypy/rpython/memory/gc/minimark.py`_. - -In more details: - -- The small newly malloced objects are allocated in the nursery (case 1). - All objects living in the nursery are "young". - -- The big objects are always handled directly by the system malloc(). - But the big newly malloced objects are still "young" when they are - allocated (case 2), even though they don't live in the nursery. - -- When the nursery is full, we do a minor collection, i.e. we find - which "young" objects are still alive (from cases 1 and 2). The - "young" flag is then removed. The surviving case 1 objects are moved - to the old stage. The dying case 2 objects are immediately freed. - -- The old stage is an area of memory containing old (small) objects. It - is handled by `pypy/rpython/memory/gc/minimarkpage.py`_. It is organized - as "arenas" of 256KB or 512KB, subdivided into "pages" of 4KB or 8KB. - Each page can either be free, or contain small objects of all the same - size. Furthermore at any point in time each object location can be - either allocated or freed. The basic design comes from ``obmalloc.c`` - from CPython (which itself comes from the same source as the Linux - system malloc()). - -- New objects are added to the old stage at every minor collection. - Immediately after a minor collection, when we reach some threshold, we - trigger a major collection. This is the mark-and-sweep step. It walks - over *all* objects (mark), and then frees some fraction of them (sweep). - This means that the only time when we want to free objects is while - walking over all of them; we never ask to free an object given just its - address. This allows some simplifications and memory savings when - compared to ``obmalloc.c``. - -- As with all generational collectors, this GC needs a write barrier to - record which old objects have a reference to young objects. - -- Additionally, we found out that it is useful to handle the case of - big arrays specially: when we allocate a big array (with the system - malloc()), we reserve a small number of bytes before. When the array - grows old, we use the extra bytes as a set of bits. Each bit - represents 128 entries in the array. Whenever the write barrier is - called to record a reference from the Nth entry of the array to some - young object, we set the bit number ``(N/128)`` to 1. This can - considerably speed up minor collections, because we then only have to - scan 128 entries of the array instead of all of them. - -- As usual, we need special care about weak references, and objects with - finalizers. Weak references are allocated in the nursery, and if they - survive they move to the old stage, as usual for all objects; the - difference is that the reference they contain must either follow the - object, or be set to NULL if the object dies. And the objects with - finalizers, considered rare enough, are immediately allocated old to - simplify the design. In particular their ``__del__`` method can only - be called just after a major collection. - -- The objects move once only, so we can use a trick to implement id() - and hash(). If the object is not in the nursery, it won't move any - more, so its id() and hash() are the object's address, cast to an - integer. If the object is in the nursery, and we ask for its id() - or its hash(), then we pre-reserve a location in the old stage, and - return the address of that location. If the object survives the - next minor collection, we move it there, and so its id() and hash() - are preserved. If the object dies then the pre-reserved location - becomes free garbage, to be collected at the next major collection. - - .. include:: _ref.txt diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -26,13 +30,6 @@ Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -124,6 +124,25 @@ for our needs. It's possible that this has changed, reviving the LLVM backend (or writing new from scratch) for static compilation would be a good project. +(On the other hand, just generating C code and using clang might be enough. +The issue with that is the so-called "asmgcc GC root finder", which has tons +of issues of this own. In my opinion (arigo), it would be definitely a +better project to try to optimize the alternative, the "shadowstack" GC root +finder, which is nicely portable. So far it gives a pypy that is around +7% slower.) + +Embedding PyPy +---------------------------------------- + +Being able to embed PyPy, say with its own limited C API, would be +useful. But here is the most interesting variant, straight from +EuroPython live discussion :-) We can have a generic "libpypy.so" that +can be used as a placeholder dynamic library, and when it gets loaded, +it runs a .py module that installs (via ctypes) the interface it wants +exported. This would give us a one-size-fits-all generic .so file to be +imported by any application that wants to load .so files :-) + + .. _`issue tracker`: http://bugs.pypy.org .. _`mailing list`: http://mail.python.org/mailman/listinfo/pypy-dev .. _`jitviewer`: http://bitbucket.org/pypy/jitviewer diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) @@ -90,15 +90,18 @@ ### Construction ### def __init__(self, space, args_w, keywords=None, keywords_w=None, - w_stararg=None, w_starstararg=None): + w_stararg=None, w_starstararg=None, keyword_names_w=None): self.space = space assert isinstance(args_w, list) self.arguments_w = args_w self.keywords = keywords self.keywords_w = keywords_w + self.keyword_names_w = keyword_names_w # matches the tail of .keywords if keywords is not None: assert keywords_w is not None assert len(keywords_w) == len(keywords) + assert (keyword_names_w is None or + len(keyword_names_w) <= len(keywords)) make_sure_not_resized(self.keywords) make_sure_not_resized(self.keywords_w) @@ -132,7 +135,8 @@ def replace_arguments(self, args_w): "Return a new Arguments with a args_w as positional arguments." - return Arguments(self.space, args_w, self.keywords, self.keywords_w) + return Arguments(self.space, args_w, self.keywords, self.keywords_w, + keyword_names_w = self.keyword_names_w) def prepend(self, w_firstarg): "Return a new Arguments with a new argument inserted first." @@ -201,15 +205,16 @@ space.w_TypeError, space.wrap("keywords must be strings")) if e.match(space, space.w_UnicodeEncodeError): - raise OperationError( - space.w_TypeError, - space.wrap("keyword cannot be encoded to ascii")) - raise - if self.keywords and key in self.keywords: - raise operationerrfmt(self.space.w_TypeError, - "got multiple values " - "for keyword argument " - "'%s'", key) + # Allow this to pass through + key = None + else: + raise + else: + if self.keywords and key in self.keywords: + raise operationerrfmt(self.space.w_TypeError, + "got multiple values " + "for keyword argument " + "'%s'", key) keywords[i] = key keywords_w[i] = space.getitem(w_starstararg, w_key) i += 1 @@ -219,6 +224,7 @@ else: self.keywords = self.keywords + keywords self.keywords_w = self.keywords_w + keywords_w + self.keyword_names_w = keys_w def fixedunpack(self, argcount): """The simplest argument parsing: get the 'argcount' arguments, @@ -339,6 +345,10 @@ used_keywords = [False] * num_kwds for i in range(num_kwds): name = keywords[i] + # If name was not encoded as a string, it could be None. In that + # case, it's definitely not going to be in the signature. + if name is None: + continue j = signature.find_argname(name) if j < 0: continue @@ -374,17 +384,26 @@ if has_kwarg: w_kwds = self.space.newdict() if num_remainingkwds: + # + limit = len(keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(keywords)): if not used_keywords[i]: - key = keywords[i] - self.space.setitem(w_kwds, self.space.wrap(key), keywords_w[i]) + if i < limit: + w_key = self.space.wrap(keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + self.space.setitem(w_kwds, w_key, keywords_w[i]) + # scope_w[co_argcount + has_vararg] = w_kwds elif num_remainingkwds: if co_argcount == 0: raise ArgErrCount(avail, num_kwds, co_argcount, has_vararg, has_kwarg, defaults_w, missing) - raise ArgErrUnknownKwds(num_remainingkwds, keywords, used_keywords) + raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords, + used_keywords, self.keyword_names_w) if missing: raise ArgErrCount(avail, num_kwds, @@ -443,9 +462,15 @@ w_args = space.newtuple(self.arguments_w) w_kwds = space.newdict() if self.keywords is not None: + limit = len(self.keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(self.keywords)): - space.setitem(w_kwds, space.wrap(self.keywords[i]), - self.keywords_w[i]) + if i < limit: + w_key = space.wrap(self.keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + space.setitem(w_kwds, w_key, self.keywords_w[i]) return w_args, w_kwds class ArgumentsForTranslation(Arguments): @@ -666,14 +691,33 @@ class ArgErrUnknownKwds(ArgErr): - def __init__(self, num_remainingkwds, keywords, used_keywords): - self.kwd_name = '' + def __init__(self, space, num_remainingkwds, keywords, used_keywords, + keyword_names_w): + name = '' self.num_kwds = num_remainingkwds if num_remainingkwds == 1: for i in range(len(keywords)): if not used_keywords[i]: - self.kwd_name = keywords[i] + name = keywords[i] + if name is None: + # We'll assume it's unicode. Encode it. + # Careful, I *think* it should not be possible to + # get an IndexError here but you never know. + try: + if keyword_names_w is None: + raise IndexError + # note: negative-based indexing from the end + w_name = keyword_names_w[i - len(keywords)] + except IndexError: + name = '?' + else: + w_enc = space.wrap(space.sys.defaultencoding) + w_err = space.wrap("replace") + w_name = space.call_method(w_name, "encode", w_enc, + w_err) + name = space.str_w(w_name) break + self.kwd_name = name def getmsg(self, fnname): if self.num_kwds == 1: diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -134,7 +133,7 @@ def accept_comp_iteration(self, codegen, index): self.elt.walkabout(codegen) - codegen.emit_op_arg(ops.SET_ADD, index) + codegen.emit_op_arg(ops.SET_ADD, index + 1) class __extend__(ast.DictComp): @@ -148,7 +147,7 @@ def accept_comp_iteration(self, codegen, index): self.value.walkabout(codegen) self.key.walkabout(codegen) - codegen.emit_op_arg(ops.MAP_ADD, index) + codegen.emit_op_arg(ops.MAP_ADD, index + 1) # These are frame blocks. @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -92,7 +92,10 @@ return name if len(name) + 2 >= MANGLE_LEN: return name - if name.endswith('__'): + # Don't mangle __id__ or names with dots. The only time a name with a dot + # can occur is when we are compiling an import statement that has a package + # name. + if name.endswith('__') or '.' in name: return name try: i = 0 diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -55,7 +55,7 @@ co_expr = compile(evalexpr, '', 'eval') space = self.space pyco_expr = PyCode._from_code(space, co_expr) - w_res = pyco_expr.exec_host_bytecode(space, w_dict, w_dict) + w_res = pyco_expr.exec_host_bytecode(w_dict, w_dict) res = space.str_w(space.repr(w_res)) if not isinstance(expected, float): assert res == repr(expected) @@ -308,6 +308,15 @@ "p.__name__", os.path.__name__) yield (self.st, 'from os import *', "path.__name__, sep", (os.path.__name__, os.sep)) + yield (self.st, ''' + class A(object): + def m(self): + from __foo__.bar import x + try: + A().m() + except ImportError, e: + msg = str(e) + ''', "msg", "No module named __foo__") def test_if_stmts(self): yield self.st, "a = 42\nif a > 10: a += 2", "a", 44 diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -237,7 +237,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: @@ -989,10 +986,7 @@ compiler = self.createcompiler() expression = compiler.compile(expression, '?', 'eval', 0, hidden_applevel=hidden_applevel) - if isinstance(expression, types.CodeType): - # XXX only used by appsupport - expression = PyCode._from_code(self, expression) - if not isinstance(expression, PyCode): + else: raise TypeError, 'space.eval(): expected a string, code or PyCode object' return expression.exec_code(self, w_globals, w_locals) @@ -1007,9 +1001,6 @@ compiler = self.createcompiler() statement = compiler.compile(statement, filename, 'exec', 0, hidden_applevel=hidden_applevel) - if isinstance(statement, types.CodeType): - # XXX only used by appsupport - statement = PyCode._from_code(self, statement) if not isinstance(statement, PyCode): raise TypeError, 'space.exec_(): expected a string, code or PyCode object' w_key = self.wrap('__builtins__') diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -100,12 +100,12 @@ @jit.dont_look_inside def fast2locals(self): - # Copy values from self.fastlocals_w to self.w_locals + # Copy values from the fastlocals to self.w_locals if self.w_locals is None: self.w_locals = self.space.newdict() varnames = self.getcode().getvarnames() fastscope_w = self.getfastscope() - for i in range(min(len(varnames), len(fastscope_w))): + for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] if w_value is not None: @@ -114,7 +114,7 @@ @jit.dont_look_inside def locals2fast(self): - # Copy values from self.w_locals to self.fastlocals_w + # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None varnames = self.getcode().getvarnames() numlocals = self.getfastscopelength() diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack @@ -98,7 +98,7 @@ self.closure) for i in funccallunrolling: if i < nargs: - new_frame.fastlocals_w[i] = args_w[i] + new_frame.locals_stack_w[i] = args_w[i] return new_frame.run() elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1: assert isinstance(code, gateway.BuiltinCodePassThroughArguments1) @@ -158,7 +158,7 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg return new_frame.run() @@ -169,13 +169,13 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = self.defs_w[j] + new_frame.locals_stack_w[i] = self.defs_w[j] i += 1 return new_frame.run() @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -170,7 +170,7 @@ for i in range(len(args_to_copy)): argnum = args_to_copy[i] if argnum >= 0: - self.cells[i].set(self.fastlocals_w[argnum]) + self.cells[i].set(self.locals_stack_w[argnum]) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -63,6 +63,7 @@ the pypy compiler""" self.space = space eval.Code.__init__(self, name) + assert nlocals >= 0 self.co_argcount = argcount self.co_nlocals = nlocals self.co_stacksize = stacksize @@ -95,7 +96,7 @@ if self.co_flags & CO_VARKEYWORDS: argcount += 1 # Cell vars could shadow already-set arguments. - # astcompiler.pyassem used to be clever about the order of + # The compiler used to be clever about the order of # the variables in both co_varnames and co_cellvars, but # it no longer is for the sake of simplicity. Moreover # code objects loaded from CPython don't necessarily follow @@ -202,7 +203,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -215,7 +216,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -256,7 +257,7 @@ tuple(self.co_freevars), tuple(self.co_cellvars) ) - def exec_host_bytecode(self, w_dict, w_globals, w_locals): + def exec_host_bytecode(self, w_globals, w_locals): from pypy.interpreter.pyframe import CPythonFrame frame = CPythonFrame(self.space, self, w_globals, None) frame.setdictscope(w_locals) diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -9,7 +9,7 @@ from pypy.interpreter import pytraceback from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib.jit import hint -from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.debug import make_sure_not_resized, check_nonneg from pypy.rlib.rarithmetic import intmask from pypy.rlib import jit from pypy.tool import stdlib_opcode @@ -56,16 +56,18 @@ assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals) - self.valuestack_w = [None] * code.co_stacksize - self.valuestackdepth = 0 + self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize) + self.nlocals = code.co_nlocals + self.valuestackdepth = code.co_nlocals self.lastblock = None + make_sure_not_resized(self.locals_stack_w) + check_nonneg(self.nlocals) + # if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure, code) - self.fastlocals_w = [None] * code.co_nlocals - make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno def mark_as_escaped(self): @@ -184,14 +186,14 @@ # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth - self.valuestack_w[depth] = w_object + self.locals_stack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 - assert depth >= 0, "pop from empty value stack" - w_object = self.valuestack_w[depth] - self.valuestack_w[depth] = None + assert depth >= self.nlocals, "pop from empty value stack" + w_object = self.locals_stack_w[depth] + self.locals_stack_w[depth] = None self.valuestackdepth = depth return w_object @@ -217,24 +219,24 @@ def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n - assert base >= 0 + assert base >= self.nlocals while True: n -= 1 if n < 0: break - values_w[n] = self.valuestack_w[base+n] + values_w[n] = self.locals_stack_w[base+n] return values_w @jit.unroll_safe def dropvalues(self, n): n = hint(n, promote=True) finaldepth = self.valuestackdepth - n - assert finaldepth >= 0, "stack underflow in dropvalues()" + assert finaldepth >= self.nlocals, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break - self.valuestack_w[finaldepth+n] = None + self.locals_stack_w[finaldepth+n] = None self.valuestackdepth = finaldepth @jit.unroll_safe @@ -261,30 +263,30 @@ # Contrast this with CPython where it's PEEK(-1). index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "peek past the bottom of the stack" - return self.valuestack_w[index] + assert index >= self.nlocals, "peek past the bottom of the stack" + return self.locals_stack_w[index] def settopvalue(self, w_object, index_from_top=0): index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "settop past the bottom of the stack" - self.valuestack_w[index] = w_object + assert index >= self.nlocals, "settop past the bottom of the stack" + self.locals_stack_w[index] = w_object @jit.unroll_safe def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 finaldepth = hint(finaldepth, promote=True) while depth >= finaldepth: - self.valuestack_w[depth] = None + self.locals_stack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth - def savevaluestack(self): - return self.valuestack_w[:self.valuestackdepth] + def save_locals_stack(self): + return self.locals_stack_w[:self.valuestackdepth] - def restorevaluestack(self, items_w): - assert None not in items_w - self.valuestack_w[:len(items_w)] = items_w + def restore_locals_stack(self, items_w): + self.locals_stack_w[:len(items_w)] = items_w + self.init_cells() self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): @@ -314,11 +316,12 @@ else: f_lineno = self.f_lineno - values_w = self.valuestack_w[0:self.valuestackdepth] + values_w = self.locals_stack_w[self.nlocals:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) - w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) + w_fastlocals = maker.slp_into_tuple_with_nulls( + space, self.locals_stack_w[:self.nlocals]) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None @@ -399,7 +402,8 @@ new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) - new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None @@ -423,28 +427,28 @@ @jit.dont_look_inside def getfastscope(self): "Get the fast locals as a list." - return self.fastlocals_w + return self.locals_stack_w @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) - if scope_len > len(self.fastlocals_w): + if scope_len > self.nlocals: raise ValueError, "new fastscope is longer than the allocated area" - # don't assign directly to 'fastlocals_w[:scope_len]' to be + # don't assign directly to 'locals_stack_w[:scope_len]' to be # virtualizable-friendly for i in range(scope_len): - self.fastlocals_w[i] = scope_w[i] + self.locals_stack_w[i] = scope_w[i] self.init_cells() def init_cells(self): - """Initialize cellvars from self.fastlocals_w + """Initialize cellvars from self.locals_stack_w. This is overridden in nestedscope.py""" pass def getfastscopelength(self): - return self.pycode.co_nlocals + return self.nlocals def getclosure(self): return None diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -324,7 +324,7 @@ def LOAD_FAST(self, varindex, next_instr): # access a local variable directly - w_value = self.fastlocals_w[varindex] + w_value = self.locals_stack_w[varindex] if w_value is None: self._load_fast_failed(varindex) self.pushvalue(w_value) @@ -343,7 +343,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self.fastlocals_w[varindex] = w_newvalue + self.locals_stack_w[varindex] = w_newvalue def POP_TOP(self, oparg, next_instr): self.popvalue() @@ -696,12 +696,12 @@ LOAD_GLOBAL._always_inline_ = True def DELETE_FAST(self, varindex, next_instr): - if self.fastlocals_w[varindex] is None: + if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise operationerrfmt(self.space.w_UnboundLocalError, message, varname) - self.fastlocals_w[varindex] = None + self.locals_stack_w[varindex] = None def BUILD_TUPLE(self, itemcount, next_instr): items = self.popvalues(itemcount) @@ -1048,30 +1048,18 @@ def SET_ADD(self, oparg, next_instr): w_value = self.popvalue() - w_set = self.peekvalue(oparg) + w_set = self.peekvalue(oparg - 1) self.space.call_method(w_set, 'add', w_value) def MAP_ADD(self, oparg, next_instr): w_key = self.popvalue() w_value = self.popvalue() - w_dict = self.peekvalue(oparg) + w_dict = self.peekvalue(oparg - 1) self.space.setitem(w_dict, w_key, w_value) def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION @@ -1091,12 +1079,10 @@ @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): - w_set = self.space.call_function(self.space.w_set) - if itemcount: - w_add = self.space.getattr(w_set, self.space.wrap("add")) - for i in range(itemcount): - w_item = self.popvalue() - self.space.call_function(w_add, w_item) + w_set = self.space.newset() + for i in range(itemcount): + w_item = self.popvalue() + self.space.call_method(w_set, 'add', w_item) self.pushvalue(w_set) def STORE_MAP(self, oparg, next_instr): diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import py from pypy.interpreter.argument import (Arguments, ArgumentsForTranslation, ArgErr, ArgErrUnknownKwds, ArgErrMultipleValues, ArgErrCount, rawshape, @@ -126,6 +127,7 @@ w_AttributeError = AttributeError w_UnicodeEncodeError = UnicodeEncodeError w_dict = dict + w_str = str class TestArgumentsNormal(object): @@ -485,26 +487,6 @@ args._match_signature(None, l, Signature(['abc'])) assert len(l) == 1 assert l[0] == space.wrap(5) - # - def str_w(w): - try: - return str(w) - except UnicodeEncodeError: - raise OperationError(space.w_UnicodeEncodeError, - space.wrap("oups")) - space.str_w = str_w - w_starstar = space.wrap({u'\u1234': 5}) - err = py.test.raises(OperationError, Arguments, - space, [], w_starstararg=w_starstar) - # Check that we get a TypeError. On CPython it is because of - # "no argument called '?'". On PyPy we get a TypeError too, but - # earlier: "keyword cannot be encoded to ascii". The - # difference, besides the error message, is only apparent if the - # receiver also takes a **arg. Then CPython passes the - # non-ascii unicode unmodified, whereas PyPy complains. We will - # not care until someone has a use case for that. - assert not err.value.match(space, space.w_UnicodeEncodeError) - assert err.value.match(space, space.w_TypeError) class TestErrorHandling(object): def test_missing_args(self): @@ -559,13 +541,26 @@ assert 0, "did not raise" def test_unknown_keywords(self): - err = ArgErrUnknownKwds(1, ['a', 'b'], [True, False]) + space = DummySpace() + err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [True, False], None) s = err.getmsg('foo') assert s == "foo() got an unexpected keyword argument 'b'" - err = ArgErrUnknownKwds(2, ['a', 'b', 'c'], [True, False, False]) + err = ArgErrUnknownKwds(space, 2, ['a', 'b', 'c'], + [True, False, False], None) s = err.getmsg('foo') assert s == "foo() got 2 unexpected keyword arguments" + def test_unknown_unicode_keyword(self): + class DummySpaceUnicode(DummySpace): + class sys: + defaultencoding = 'utf-8' + space = DummySpaceUnicode() + err = ArgErrUnknownKwds(space, 1, ['a', None, 'b', 'c'], + [True, False, True, True], + [unichr(0x1234), u'b', u'c']) + s = err.getmsg('foo') + assert s == "foo() got an unexpected keyword argument '\xe1\x88\xb4'" + def test_multiple_values(self): err = ArgErrMultipleValues('bla') s = err.getmsg('foo') @@ -592,6 +587,14 @@ exc = raises(TypeError, (lambda a, b, **kw: 0), a=1) assert exc.value.message == "() takes exactly 2 non-keyword arguments (0 given)" + def test_unicode_keywords(self): + def f(**kwargs): + assert kwargs[u"美"] == 42 + f(**{u"美" : 42}) + def f(x): pass + e = raises(TypeError, "f(**{u'ü' : 19})") + assert "?" in str(e.value) + def make_arguments_for_translation(space, args_w, keywords_w={}, w_stararg=None, w_starstararg=None): return ArgumentsForTranslation(space, args_w, keywords_w.keys(), diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py --- a/pypy/interpreter/test/test_eval.py +++ b/pypy/interpreter/test/test_eval.py @@ -15,16 +15,16 @@ self.code = code Frame.__init__(self, space) self.numlocals = numlocals - self.fastlocals_w = [None] * self.numlocals + self._fastlocals_w = [None] * self.numlocals def getcode(self): return self.code def setfastscope(self, scope_w): - self.fastlocals_w = scope_w + self._fastlocals_w = scope_w def getfastscope(self): - return self.fastlocals_w + return self._fastlocals_w def getfastscopelength(self): return self.numlocals @@ -38,11 +38,11 @@ self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({})) - self.f.fastlocals_w[0] = w(5) + self.f._fastlocals_w[0] = w(5) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5})) - self.f.fastlocals_w[2] = w(7) + self.f._fastlocals_w[2] = w(7) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5, 'args': 7})) @@ -57,13 +57,13 @@ w = self.space.wrap self.f.w_locals = self.space.wrap({}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [None]*5) + self.sameList(self.f._fastlocals_w, [None]*5) self.f.w_locals = self.space.wrap({'x': 5}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) + self.sameList(self.f._fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.wrap({'x':5, 'args':7}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), None, w(7), - None, None]) + self.sameList(self.f._fastlocals_w, [w(5), None, w(7), + None, None]) diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -203,3 +203,27 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + import sys + class A(object): + def m(self): + "aaa" + m.x = 3 + class B(A): + pass + + bm = B().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.im_class is B + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -761,12 +761,15 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -136,6 +136,7 @@ 'call' : (('ref', 'varargs'), 'intorptr'), 'call_assembler' : (('varargs',), 'intorptr'), 'cond_call_gc_wb' : (('ptr', 'ptr'), None), + 'cond_call_gc_wb_array': (('ptr', 'int', 'ptr'), None), 'oosend' : (('varargs',), 'intorptr'), 'oosend_pure' : (('varargs',), 'intorptr'), 'guard_true' : (('bool',), None), @@ -857,6 +858,9 @@ def op_cond_call_gc_wb(self, descr, a, b): py.test.skip("cond_call_gc_wb not supported") + def op_cond_call_gc_wb_array(self, descr, a, b, c): + py.test.skip("cond_call_gc_wb_array not supported") + def op_oosend(self, descr, obj, *args): raise NotImplementedError("oosend for lltype backend??") diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -267,6 +267,9 @@ def __repr__(self): res = '%s(%s)' % (self.__class__.__name__, self.arg_classes) + extraeffect = getattr(self.extrainfo, 'extraeffect', None) + if extraeffect is not None: + res += ' EF=%r' % extraeffect oopspecindex = getattr(self.extrainfo, 'oopspecindex', 0) if oopspecindex: from pypy.jit.codewriter.effectinfo import EffectInfo diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -618,6 +618,7 @@ return cpu.cast_adr_to_int(funcaddr) def get_write_barrier_from_array_fn(self, cpu): + # returns a function with arguments [array, index, newvalue] llop1 = self.llop1 funcptr = llop1.get_write_barrier_from_array_failing_case( self.WB_ARRAY_FUNCPTR) @@ -920,7 +921,7 @@ length = known_lengths.get(v_base, LARGE) if length >= LARGE: # unknown or too big: produce a write_barrier_from_array - args = [v_base, v_value, v_index] + args = [v_base, v_index, v_value] newops.append(ResOperation(rop.COND_CALL_GC_WB_ARRAY, args, None, descr=self.write_barrier_descr)) diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py --- a/pypy/jit/backend/llsupport/test/test_gc.py +++ b/pypy/jit/backend/llsupport/test/test_gc.py @@ -9,7 +9,7 @@ from pypy.jit.metainterp.resoperation import get_deep_immutable_oplist from pypy.jit.tool.oparser import parse from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists def test_boehm(): gc_ll_descr = GcLLDescr_boehm(None, None, None) @@ -716,8 +716,8 @@ else: assert operations[0].getopnum() == rop.COND_CALL_GC_WB_ARRAY assert operations[0].getarg(0) == v_base - assert operations[0].getarg(1) == v_value - assert operations[0].getarg(2) == v_index + assert operations[0].getarg(1) == v_index + assert operations[0].getarg(2) == v_value assert operations[0].result is None # assert operations[1].getopnum() == rop.SETARRAYITEM_RAW diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -1694,12 +1694,13 @@ assert record == [] def test_cond_call_gc_wb_array(self): - def func_void(a, b): - record.append((a, b)) + def func_void(a, b, c): + record.append((a, b, c)) record = [] # S = lltype.GcStruct('S', ('tid', lltype.Signed)) - FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed], lltype.Void) + FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)], + lltype.Void) func_ptr = llhelper(lltype.Ptr(FUNC), func_void) funcbox = self.get_funcbox(self.cpu, func_ptr) class WriteBarrierDescr(AbstractDescr): @@ -1719,11 +1720,11 @@ s.tid = value sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s) del record[:] - self.execute_operation(rop.COND_CALL_GC_WB, - [BoxPtr(sgcref), ConstInt(123)], - 'void', descr=WriteBarrierDescr()) + self.execute_operation(rop.COND_CALL_GC_WB_ARRAY, + [BoxPtr(sgcref), ConstInt(123), BoxPtr(sgcref)], + 'void', descr=WriteBarrierDescr()) if cond: - assert record == [(s, 123)] + assert record == [(s, 123, s)] else: assert record == [] diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -703,22 +703,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: @@ -889,7 +895,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -901,7 +907,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -884,18 +884,12 @@ def consider_cond_call_gc_wb(self, op): assert op.result is None args = op.getarglist() - loc_newvalue = self.rm.make_sure_var_in_reg(op.getarg(1), args) - # ^^^ we force loc_newvalue in a reg (unless it's a Const), - # because it will be needed anyway by the following setfield_gc. - # It avoids loading it twice from the memory. - loc_base = self.rm.make_sure_var_in_reg(op.getarg(0), args) - # - if len(args) == 2: - arglocs = [loc_base, loc_newvalue] # cond_call_gc_wb - else: - # cond_call_gc_wb_array - loc_arrayindex = self.rm.make_sure_var_in_reg(op.getarg(2), args) - arglocs = [loc_base, loc_newvalue, loc_arrayindex] + N = len(args) + # we force all arguments in a reg (unless they are Consts), + # because it will be needed anyway by the following setfield_gc + # or setarrayitem_gc. It avoids loading it twice from the memory. + arglocs = [self.rm.make_sure_var_in_reg(op.getarg(i), args) + for i in range(N)] # add eax, ecx and edx as extra "arguments" to ensure they are # saved and restored. Fish in self.rm to know which of these # registers really need to be saved (a bit of a hack). Moreover, diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -467,13 +469,13 @@ # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,6 +185,13 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -75,12 +75,13 @@ # OS_MATH_SQRT = 100 - def __new__(cls, readonly_descrs_fields, + def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, can_invalidate=False): key = (frozenset(readonly_descrs_fields), + frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, @@ -89,8 +90,9 @@ return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields + result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: @@ -119,7 +121,7 @@ if effects is top_set: return None readonly_descrs_fields = [] - # readonly_descrs_arrays = [] --- not enabled for now + readonly_descrs_arrays = [] write_descrs_fields = [] write_descrs_arrays = [] @@ -145,10 +147,13 @@ elif tup[0] == "array": add_array(write_descrs_arrays, tup) elif tup[0] == "readarray": - pass + tupw = ("array",) + tup[1:] + if tupw not in effects: + add_array(readonly_descrs_arrays, tup) else: assert 0 return EffectInfo(readonly_descrs_fields, + readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect, diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -847,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' @@ -44,10 +44,6 @@ return True if mod.startswith('pypy.translator.'): # XXX wtf? return True - # string builder interface - if mod == 'pypy.rpython.lltypesystem.rbuilder': - return True - return False def look_inside_graph(self, graph): diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -34,6 +34,15 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays +def test_include_read_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo.write_descrs_fields + assert not effectinfo.write_descrs_arrays + def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) @@ -51,6 +60,16 @@ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.write_descrs_arrays +def test_dont_include_read_and_write_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A)), + ("array", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert not effectinfo.readonly_descrs_arrays + assert not effectinfo.write_descrs_fields + assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLException diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -14,8 +14,8 @@ from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper -from pypy.jit.metainterp.optimizeutil import InvalidLoop -from pypy.jit.metainterp.resume import NUMBERING +from pypy.jit.metainterp.optimize import InvalidLoop +from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong def giveup(): @@ -119,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -302,7 +303,7 @@ rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) CNT_INT = -0x20000000 CNT_REF = -0x40000000 @@ -633,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -4,7 +4,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rlib.objectmodel import we_are_translated, r_dict, Symbolic from pypy.rlib.objectmodel import compute_unique_id -from pypy.rlib.rarithmetic import intmask, r_int64 +from pypy.rlib.rarithmetic import r_int64 from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled @@ -791,6 +792,7 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py --- a/pypy/jit/metainterp/logger.py +++ b/pypy/jit/metainterp/logger.py @@ -103,6 +103,7 @@ if op.getopnum() == rop.DEBUG_MERGE_POINT: jd_sd = self.metainterp_sd.jitdrivers_sd[op.getarg(0).getint()] s = jd_sd.warmstate.get_location_str(op.getarglist()[2:]) + s = s.replace(',', '.') # we use comma for argument splitting return "debug_merge_point(%d, '%s')" % (op.getarg(1).getint(), s) if ops_offset is None: offset = -1 diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py --- a/pypy/jit/metainterp/optimize.py +++ b/pypy/jit/metainterp/optimize.py @@ -1,9 +1,20 @@ from pypy.rlib.debug import debug_start, debug_stop +from pypy.jit.metainterp.jitexc import JitException + +class InvalidLoop(JitException): + """Raised when the optimize*.py detect that the loop that + we are trying to build cannot possibly make sense as a + long-running loop (e.g. it cannot run 2 complete iterations).""" + +class RetraceLoop(JitException): + """ Raised when inlining a short preamble resulted in an + InvalidLoop. This means the optimized loop is too specialized + to be useful here, so we trace it again and produced a second + copy specialized in some different way. + """ # ____________________________________________________________ -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, optimize_bridge_1 - def optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): debug_start("jit-optimize") try: @@ -13,7 +24,7 @@ debug_stop("jit-optimize") def _optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): - cpu = metainterp_sd.cpu + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 loop.logops = metainterp_sd.logger_noopt.log_loop(loop.inputargs, loop.operations) # XXX do we really still need a list? @@ -36,7 +47,7 @@ def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts, inline_short_preamble, retraced=False): - cpu = metainterp_sd.cpu + from pypy.jit.metainterp.optimizeopt import optimize_bridge_1 bridge.logops = metainterp_sd.logger_noopt.log_loop(bridge.inputargs, bridge.operations) if old_loop_tokens: diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -203,13 +203,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -220,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -8,8 +8,8 @@ class CachedField(object): def __init__(self): - # Cache information for a field descr. It can be in one - # of two states: + # Cache information for a field descr, or for an (array descr, index) + # pair. It can be in one of two states: # # 1. 'cached_fields' is a dict mapping OptValues of structs # to OptValues of fields. All fields on-heap are @@ -27,19 +27,19 @@ self._lazy_setfield_registered = False def do_setfield(self, optheap, op): - # Update the state with the SETFIELD_GC operation 'op'. + # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) if self.possible_aliasing(optheap, structvalue): self.force_lazy_setfield(optheap) assert not self.possible_aliasing(optheap, structvalue) cached_fieldvalue = self._cached_fields.get(structvalue, None) if cached_fieldvalue is not fieldvalue: # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields list + # myself in the optheap's _lazy_setfields_and_arrayitems list self._lazy_setfield = op if not self._lazy_setfield_registered: - optheap._lazy_setfields.append(self) + optheap._lazy_setfields_and_arrayitems.append(self) self._lazy_setfield_registered = True else: # this is the case where the pending setfield ends up @@ -65,7 +65,7 @@ if self._lazy_setfield is not None: op = self._lazy_setfield assert optheap.getvalue(op.getarg(0)) is structvalue - return optheap.getvalue(op.getarg(1)) + return optheap.getvalue(op.getarglist()[-1]) else: return self._cached_fields.get(structvalue, None) @@ -87,7 +87,7 @@ # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) def get_reconstructed(self, optimizer, valuemap): @@ -100,25 +100,20 @@ return cf -class CachedArrayItems(object): - def __init__(self): - self.fixed_index_items = {} - self.var_index_item = None - self.var_index_indexvalue = None - class BogusPureField(JitException): pass class OptHeap(Optimization): """Cache repeated heap accesses""" - + def __init__(self): # cached fields: {descr: CachedField} self.cached_fields = {} - self._lazy_setfields = [] - # cached array items: {descr: CachedArrayItems} + # cached array items: {array descr: {index: CachedField}} self.cached_arrayitems = {} + # + self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -126,34 +121,23 @@ new = OptHeap() if True: - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() else: assert 0 # was: new.lazy_setfields = self.lazy_setfields - + for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) - new.cached_arrayitems = {} - for descr, d in self.cached_arrayitems.items(): - newd = {} - new.cached_arrayitems[descr] = newd - for value, cache in d.items(): - newcache = CachedArrayItems() - newd[value.get_reconstructed(optimizer, valuemap)] = newcache - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_reconstructed(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) - for index, fieldvalue in cache.fixed_index_items.items(): - newcache.fixed_index_items[index] = \ - fieldvalue.get_reconstructed(optimizer, valuemap) + for descr, submap in self.cached_arrayitems.items(): + newdict = {} + for index, d in submap.items(): + newdict[index] = d.get_reconstructed(optimizer, valuemap) + new.cached_arrayitems[descr] = newdict return new def clean_caches(self): - del self._lazy_setfields[:] + del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() self.cached_arrayitems.clear() @@ -164,50 +148,16 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): - d = self.cached_arrayitems.get(descr, None) - if d is None: - d = self.cached_arrayitems[descr] = {} - cache = d.get(value, None) - if cache is None: - cache = d[value] = CachedArrayItems() - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - index = indexbox.getint() - if write: - for value, othercache in d.iteritems(): - # fixed index, clean the variable index cache, in case the - # index is the same - othercache.var_index_indexvalue = None - othercache.var_index_item = None - try: - del othercache.fixed_index_items[index] - except KeyError: - pass - cache.fixed_index_items[index] = fieldvalue - else: - if write: - for value, othercache in d.iteritems(): - # variable index, clear all caches for this descr - othercache.var_index_indexvalue = None - othercache.var_index_item = None - othercache.fixed_index_items.clear() - cache.var_index_indexvalue = indexvalue - cache.var_index_item = fieldvalue - - def read_cached_arrayitem(self, descr, value, indexvalue): - d = self.cached_arrayitems.get(descr, None) - if d is None: - return None - cache = d.get(value, None) - if cache is None: - return None - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - return cache.fixed_index_items.get(indexbox.getint(), None) - elif cache.var_index_indexvalue is indexvalue: - return cache.var_index_item - return None + def arrayitem_cache(self, descr, index): + try: + submap = self.cached_arrayitems[descr] + except KeyError: + submap = self.cached_arrayitems[descr] = {} + try: + cf = submap[index] + except KeyError: + cf = submap[index] = CachedField() + return cf def emit_operation(self, op): self.emitting_operation(op) @@ -219,7 +169,8 @@ if op.is_ovf(): return if op.is_guard(): - self.optimizer.pendingfields = self.force_lazy_setfields_for_guard() + self.optimizer.pendingfields = ( + self.force_lazy_setfields_and_arrayitems_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -248,6 +199,8 @@ # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: self.force_lazy_setfield(fielddescr) + for arraydescr in effectinfo.readonly_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: self.force_lazy_setfield(fielddescr) try: @@ -256,8 +209,11 @@ except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) try: - del self.cached_arrayitems[arraydescr] + submap = self.cached_arrayitems[arraydescr] + for cf in submap.itervalues(): + cf._cached_fields.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -266,7 +222,7 @@ # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. return - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() self.clean_caches() @@ -277,6 +233,10 @@ for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] + for submap in self.cached_arrayitems.itervalues(): + for cf in submap.itervalues(): + if value in cf._cached_fields: + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -285,6 +245,14 @@ return cf.force_lazy_setfield(self) + def force_lazy_setarrayitem(self, arraydescr): + try: + submap = self.cached_arrayitems[arraydescr] + except KeyError: + return + for cf in submap.values(): + cf.force_lazy_setfield(self) + def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes # sense to avoid a situation like "int_eq/setfield_gc/guard_true", @@ -309,30 +277,49 @@ newoperations[-2] = lastop newoperations[-1] = prevop - def force_all_lazy_setfields(self): - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + def _assert_valid_cf(self, cf): + # check that 'cf' is in cached_fields or cached_arrayitems + if not we_are_translated(): + if cf not in self.cached_fields.values(): + for submap in self.cached_arrayitems.values(): + if cf in submap.values(): + break + else: + assert 0, "'cf' not in cached_fields/cached_arrayitems" + + def force_all_lazy_setfields_and_arrayitems(self): + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) cf.force_lazy_setfield(self) - def force_lazy_setfields_for_guard(self): + def force_lazy_setfields_and_arrayitems_for_guard(self): pendingfields = [] - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) op = cf._lazy_setfield if op is None: continue # the only really interesting case that we need to handle in the # guards' resume data is that of a virtual object that is stored - # into a field of a non-virtual object. + # into a field of a non-virtual object. Here, 'op' in either + # SETFIELD_GC or SETARRAYITEM_GC. value = self.getvalue(op.getarg(0)) assert not value.is_virtual() # it must be a non-virtual - fieldvalue = self.getvalue(op.getarg(1)) + fieldvalue = self.getvalue(op.getarglist()[-1]) if fieldvalue.is_virtual(): # this is the case that we leave to resume.py + opnum = op.getopnum() + if opnum == rop.SETFIELD_GC: + itemindex = -1 + elif opnum == rop.SETARRAYITEM_GC: + indexvalue = self.getvalue(op.getarg(1)) + assert indexvalue.is_constant() + itemindex = indexvalue.box.getint() + assert itemindex >= 0 + else: + assert 0 pendingfields.append((op.getdescr(), value.box, - fieldvalue.get_key_box())) + fieldvalue.get_key_box(), itemindex)) else: cf.force_lazy_setfield(self) self.fixup_guard_situation() @@ -364,24 +351,45 @@ cf.do_setfield(self, op) def optimize_GETARRAYITEM_GC(self, op): - value = self.getvalue(op.getarg(0)) + arrayvalue = self.getvalue(op.getarg(0)) indexvalue = self.getvalue(op.getarg(1)) - fieldvalue = self.read_cached_arrayitem(op.getdescr(), value, indexvalue) - if fieldvalue is not None: - self.make_equal_to(op.result, fieldvalue) - return - ###self.optimizer.optimize_default(op) + cf = None + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + fieldvalue = cf.getfield_from_cache(self, arrayvalue) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # default case: produce the operation + arrayvalue.ensure_nonnull() self.emit_operation(op) - fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) + # the remember the result of reading the array item + if cf is not None: + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(arrayvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): - self.emit_operation(op) - value = self.getvalue(op.getarg(0)) - fieldvalue = self.getvalue(op.getarg(2)) + if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), + op.getarg(1)], + op.getdescr()): + os.write(2, '[bogus immutable array declaration: %s]\n' % + (op.getdescr().repr_of_descr())) + raise BogusPureField + # indexvalue = self.getvalue(op.getarg(1)) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - write=True) + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + cf.do_setfield(self, op) + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # and then emit the operation + self.emit_operation(op) def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) @@ -423,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeutil import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -23,7 +23,7 @@ def reconstruct_for_next_iteration(self, optimizer, valuemap): assert self.posponedop is None - return self + return self def propagate_forward(self, op): if op.is_ovf(): @@ -34,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -57,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -194,7 +187,7 @@ # Synthesize the reverse ops for optimize_default to reuse self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0)) self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1)) - + def optimize_INT_MUL_OVF(self, op): v1 = self.getvalue(op.getarg(0)) @@ -292,6 +285,11 @@ v1.intbound.make_ge(IntLowerBound(0)) v1.intbound.make_lt(IntUpperBound(256)) + def optimize_UNICODEGETITEM(self, op): + self.emit_operation(op) + v1 = self.getvalue(op.result) + v1.intbound.make_ge(IntLowerBound(0)) + def make_int_lt(self, box1, box2): v1 = self.getvalue(box1) v2 = self.getvalue(box2) @@ -368,6 +366,27 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -413,5 +432,7 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') + +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,9 +4,9 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs -from pypy.jit.metainterp.optimizeutil import descrlist_dict -from pypy.jit.metainterp.optimizeutil import InvalidLoop, args_dict +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.rpython.lltypesystem import lltype @@ -141,6 +141,9 @@ # meaning it has been forced. return self.box is None + def is_forced_virtual(self): + return False + def getfield(self, ofs, default): raise NotImplementedError @@ -431,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -566,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -184,6 +179,32 @@ else: self.emit_operation(op) + def optimize_FLOAT_MUL(self, op): + arg1 = op.getarg(0) + arg2 = op.getarg(1) + + # Constant fold f0 * 1.0 and turn f0 * -1.0 into a FLOAT_NEG, these + # work in all cases, including NaN and inf + for lhs, rhs in [(arg1, arg2), (arg2, arg1)]: + v1 = self.getvalue(lhs) + v2 = self.getvalue(rhs) + + if v1.is_constant(): + if v1.box.getfloat() == 1.0: + self.make_equal_to(op.result, v2) + return + elif v1.box.getfloat() == -1.0: + self.emit_operation(ResOperation( + rop.FLOAT_NEG, [rhs], op.result + )) + return + self.emit_operation(op) + + def optimize_FLOAT_NEG(self, op): + v1 = op.getarg(0) + self.emit_operation(op) + self.pure(rop.FLOAT_NEG, [op.result], v1) + def optimize_CALL_PURE(self, op): arg_consts = [] for i in range(op.numargs()): @@ -193,7 +214,7 @@ break arg_consts.append(const) else: - # all constant arguments: check if we already know the reslut + # all constant arguments: check if we already know the result try: result = self.optimizer.call_pure_results[arg_consts] except KeyError: @@ -451,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/__init__.py b/pypy/jit/metainterp/optimizeopt/test/__init__.py new file mode 100644 diff --git a/pypy/jit/metainterp/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py rename from pypy/jit/metainterp/test/test_optimizebasic.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1,40 +1,15 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, FakeMetaInterpStaticData) from pypy.jit.metainterp.test.test_compile import FakeLogger import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt -from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation -from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.optimizeutil import args_dict - -##class FakeFrame(object): -## parent_resumedata_snapshot = None -## parent_resumedata_frame_info_list = None - -## def __init__(self, code="", pc=0): -## self.jitcode = code -## self.pc = pc - -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() - self.logger_ops = FakeLogger() - self.logger_noopt = FakeLogger() + def test_store_final_boxes_in_guard(): from pypy.jit.metainterp.compile import ResumeGuardDescr @@ -104,7 +79,7 @@ assert vinfo3 is vinfo4 def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil + from pypy.jit.metainterp.optimizeopt import util as optimizeutil h1 = optimizeutil.descrlist_hash([]) h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) h3 = optimizeutil.descrlist_hash( @@ -133,159 +108,55 @@ # ____________________________________________________________ -def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}, - text_right=None): - # try to use the full width of the terminal to display the list - # unfortunately, does not work with the default capture method of py.test - # (which is fd), you you need to use either -s or --capture=sys, else you - # get the standard 80 columns width - totwidth = py.io.get_terminal_width() - width = totwidth / 2 - 1 - print ' Comparing lists '.center(totwidth, '-') - text_right = text_right or 'expected' - print '%s| %s' % ('optimized'.center(width), text_right.center(width)) - for op1, op2 in zip(oplist1, oplist2): - txt1 = str(op1) - txt2 = str(op2) - while txt1 or txt2: - print '%s| %s' % (txt1[:width].ljust(width), txt2[:width]) - txt1 = txt1[width:] - txt2 = txt2[width:] - assert op1.getopnum() == op2.getopnum() - assert op1.numargs() == op2.numargs() - for i in range(op1.numargs()): - x = op1.getarg(i) - y = op2.getarg(i) - assert x == remap.get(y, y) - if op2.result in remap: - assert op1.result == remap[op2.result] - else: - remap[op2.result] = op1.result - if op1.getopnum() != rop.JUMP: # xxx obscure - assert op1.getdescr() == op2.getdescr() - if op1.getfailargs() or op2.getfailargs(): - assert len(op1.getfailargs()) == len(op2.getfailargs()) - if strict_fail_args: - for x, y in zip(op1.getfailargs(), op2.getfailargs()): - assert x == remap.get(y, y) - else: - fail_args1 = set(op1.getfailargs()) - fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()]) - assert fail_args1 == fail_args2 - assert len(oplist1) == len(oplist2) - print '-'*totwidth - return True - -def test_equaloplists(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops, namespace=namespace) - loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), - namespace=namespace) - assert equaloplists(loop1.operations, loop2.operations) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -def test_equaloplists_fail_args(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2, i1] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop2.operations)") - assert equaloplists(loop1.operations, loop2.operations, - strict_fail_args=False) - loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -# ____________________________________________________________ - -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) class BaseTestBasic(BaseTest): - def invent_fail_descr(self, model, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap) + enable_opts = "intbounds:rewrite:virtualize:string:heap" def optimize_loop(self, ops, optops, call_pure_results=None): + loop = self.parse(ops) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v - metainterp_sd = FakeMetaInterpStaticData(self.cpu) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - # - # XXX list the exact optimizations that are needed for each test - from pypy.jit.metainterp.optimizeopt import (OptIntBounds, - OptRewrite, - OptVirtualize, - OptString, - OptHeap, - Optimizer) - from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall - - optimizations = [OptIntBounds(), - OptRewrite(), - OptVirtualize(), - OptString(), - OptHeap(), - OptFfiCall(), - ] - optimizer = Optimizer(metainterp_sd, loop, optimizations) - optimizer.propagate_all_forward() - # expected = self.parse(optops) + self._do_optimize_loop(loop, call_pure_results) print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + + class BaseTestOptimizeBasic(BaseTestBasic): @@ -568,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] @@ -1234,8 +1122,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1600,9 +1488,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) jump(p1, i1, i2, p3) """ @@ -1776,6 +1664,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2038,7 +1927,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2056,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2074,7 +1961,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2290,25 +2176,83 @@ """ self.optimize_loop(ops, expected) + def test_fold_constant_partial_ops_float(self): + ops = """ + [f0] + f1 = float_mul(f0, 1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + + ops = """ + [f0] + f1 = float_mul(f0, -1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(-1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + def test_fold_repeated_float_neg(self): + ops = """ + [f0] + f1 = float_neg(f0) + f2 = float_neg(f1) + f3 = float_neg(f2) + f4 = float_neg(f3) + escape(f4) + jump(f4) + """ + expected = """ + [f0] + # The backend removes this dead op. + f1 = float_neg(f0) + escape(f0) + jump(f0) + """ + self.optimize_loop(ops, expected) + # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2417,7 +2361,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2438,7 +2381,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2458,7 +2400,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2484,7 +2425,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2509,7 +2450,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2533,7 +2473,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2554,7 +2493,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2575,7 +2513,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2597,7 +2534,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2639,7 +2575,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2665,7 +2600,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2689,9 +2623,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2983,7 +2914,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3029,7 +2959,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3068,7 +2997,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3095,7 +3023,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -4213,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -4569,6 +4495,47 @@ # not obvious, because of the exception UnicodeDecodeError that # can be raised by ll_str2unicode() + def test_strgetitem_repeated(self): + ops = """ + [p0, i0] + i1 = strgetitem(p0, i0) + i2 = strgetitem(p0, i0) + i3 = int_eq(i1, i2) + guard_true(i3) [] + escape(i2) + jump(p0, i0) + """ + expected = """ + [p0, i0] + i1 = strgetitem(p0, i0) + escape(i1) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py rename from pypy/jit/metainterp/test/test_optimizefficall.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py --- a/pypy/jit/metainterp/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py @@ -2,8 +2,8 @@ from pypy.rlib.libffi import Func, types from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.metainterp.test.test_optimizebasic import BaseTestBasic -from pypy.jit.metainterp.test.test_optimizebasic import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import BaseTestBasic +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import LLtypeMixin class MyCallDescr(AbstractDescr): """ @@ -33,6 +33,8 @@ class TestFfiCall(BaseTestBasic, LLtypeMixin): + enable_opts = "intbounds:rewrite:virtualize:string:heap:ffi" + class namespace: cpu = LLtypeMixin.cpu FUNC = LLtypeMixin.FUNC @@ -49,7 +51,7 @@ restype=types.sint) # def calldescr(cpu, FUNC, oopspecindex, extraeffect=None): - einfo = EffectInfo([], [], [], oopspecindex=oopspecindex, + einfo = EffectInfo([], [], [], [], oopspecindex=oopspecindex, extraeffect=extraeffect) return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo) # diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py rename from pypy/jit/metainterp/test/test_optimizeopt.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1,36 +1,21 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, Storage, _sortboxes) import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT, build_opt_chain -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.test.test_optimizebasic import equaloplists -from pypy.jit.metainterp.optimizeutil import args_dict +from pypy.jit.metainterp.optimizeopt.util import args_dict +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import FakeMetaInterpStaticData from pypy.config.pypyoption import get_pypy_config -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() - self.config = get_pypy_config(translating=True) - self.config.translation.jit_ffi = True - def test_build_opt_chain(): def check(chain, expected_names): @@ -66,173 +51,38 @@ check(chain, ["OptSimplify"]) -def test_store_final_boxes_in_guard(): - from pypy.jit.metainterp.compile import ResumeGuardDescr - from pypy.jit.metainterp.resume import tag, TAGBOX - b0 = BoxInt() - b1 = BoxInt() - opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu), - None) - fdescr = ResumeGuardDescr() - op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr) - # setup rd data - fi0 = resume.FrameInfo(None, "code0", 11) - fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33) - snapshot0 = resume.Snapshot(None, [b0]) - fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1]) - # - opt.store_final_boxes_in_guard(op) - if op.getfailargs() == [b0, b1]: - assert list(fdescr.rd_numb.nums) == [tag(1, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)] - else: - assert op.getfailargs() == [b1, b0] - assert list(fdescr.rd_numb.nums) == [tag(0, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(1, TAGBOX)] - assert fdescr.rd_virtuals is None - assert fdescr.rd_consts == [] - -def test_sharing_field_lists_of_virtual(): - class FakeOptimizer(object): - class cpu(object): - pass - opt = FakeOptimizer() - virt1 = virtualize.AbstractVirtualStructValue(opt, None) - lst1 = virt1._get_field_descr_list() - assert lst1 == [] - lst2 = virt1._get_field_descr_list() - assert lst1 is lst2 - virt1.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst3 = virt1._get_field_descr_list() - assert lst3 == [LLtypeMixin.valuedescr] - lst4 = virt1._get_field_descr_list() - assert lst3 is lst4 - - virt2 = virtualize.AbstractVirtualStructValue(opt, None) - lst5 = virt2._get_field_descr_list() - assert lst5 is lst1 - virt2.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst6 = virt1._get_field_descr_list() - assert lst6 is lst3 - -def test_reuse_vinfo(): - class FakeVInfo(object): - def set_content(self, fieldnums): - self.fieldnums = fieldnums - def equals(self, fieldnums): - return self.fieldnums == fieldnums - class FakeVirtualValue(virtualize.AbstractVirtualValue): - def _make_virtual(self, *args): - return FakeVInfo() - v1 = FakeVirtualValue(None, None, None) - vinfo1 = v1.make_virtual_info(None, [1, 2, 4]) - vinfo2 = v1.make_virtual_info(None, [1, 2, 4]) - assert vinfo1 is vinfo2 - vinfo3 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is not vinfo2 - vinfo4 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is vinfo4 - -def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil - h1 = optimizeutil.descrlist_hash([]) - h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) - h3 = optimizeutil.descrlist_hash( - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert h1 != h2 - assert h2 != h3 - assert optimizeutil.descrlist_eq([], []) - assert not optimizeutil.descrlist_eq([], [LLtypeMixin.valuedescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.nextdescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr, LLtypeMixin.nextdescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.nextdescr, LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - - # descrlist_eq should compare by identity of the descrs, not by the result - # of sort_key - class FakeDescr(object): - def sort_key(self): - return 1 - - assert not optimizeutil.descrlist_eq([FakeDescr()], [FakeDescr()]) - # ____________________________________________________________ -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure + + +class FakeDescr(compile.ResumeGuardDescr): + class rd_snapshot: + class prev: + prev = None + boxes = [] + boxes = [] def clone_if_mutable(self): - res = Storage(self.metainterp_sd, self.original_greenkey) - self.copy_all_attributes_into(res) - return res - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) - -class BaseTestOptimizeOpt(BaseTest): - - def invent_fail_descr(self, model, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected, text_right=None): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap, text_right) - - def optimize_loop(self, ops, optops, expected_preamble=None, + return self + + +class BaseTestWithUnroll(BaseTest): + + enable_opts = "intbounds:rewrite:virtualize:string:heap:unroll" + + def optimize_loop(self, ops, expected, expected_preamble=None, call_pure_results=None): loop = self.parse(ops) - if optops != "crash!": - expected = self.parse(optops) - else: - expected = "crash!" + if expected != "crash!": + expected = self.parse(expected) if expected_preamble: expected_preamble = self.parse(expected_preamble) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v + loop.preamble = TreeLoop('preamble') loop.preamble.inputargs = loop.inputargs loop.preamble.token = LoopToken() - metainterp_sd = FakeMetaInterpStaticData(self.cpu) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - class FakeDescr(compile.ResumeGuardDescr): - class rd_snapshot: - class prev: - prev = None - boxes = [] - boxes = [] - def clone_if_mutable(self): - return self loop.preamble.start_resumedescr = FakeDescr() - optimize_loop_1(metainterp_sd, loop, ALL_OPTS_DICT) # - + self._do_optimize_loop(loop, call_pure_results) + # print print loop.preamble.inputargs print '\n'.join([str(o) for o in loop.preamble.operations]) @@ -240,16 +90,14 @@ print loop.inputargs print '\n'.join([str(o) for o in loop.operations]) print - assert expected != "crash!", "should have raised an exception" self.assert_equal(loop, expected) if expected_preamble: self.assert_equal(loop.preamble, expected_preamble, text_right='expected preamble') - return loop -class OptimizeOptTest(BaseTestOptimizeOpt): +class OptimizeOptTest(BaseTestWithUnroll): def setup_method(self, meth=None): class FailDescr(compile.ResumeGuardDescr): @@ -1533,8 +1381,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1958,9 +1806,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -1970,9 +1818,9 @@ # i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -2207,6 +2055,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2893,8 +2742,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -5463,7 +5310,7 @@ """ self.optimize_strunicode_loop(ops, expected) - def test_strgetitem_small(self): + def test_strgetitem_bounds(self): ops = """ [p0, i0] i1 = strgetitem(p0, i0) @@ -5475,7 +5322,20 @@ """ expected = """ [p0, i0] - i1 = strgetitem(p0, i0) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_unicodegetitem_bounds(self): + ops = """ + [p0, i0] + i1 = unicodegetitem(p0, i0) + i2 = int_lt(i1, 0) + guard_false(i2) [] + jump(p0, i0) + """ + expected = """ + [p0, i0] jump(p0, i0) """ self.optimize_loop(ops, expected) @@ -5513,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -5989,3 +5848,54 @@ jump(i3, i4) """ self.optimize_loop(ops, expected) + + def test_forced_virtual_pure_getfield(self): + ops = """ + [p0] + p1 = getfield_gc_pure(p0, descr=valuedescr) + jump(p1) + """ + self.optimize_loop(ops, ops) + + ops = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + p2 = getfield_gc_pure(p1, descr=valuedescr) + escape(p2) + jump(p0) + """ + expected = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + escape(p0) + jump(p0) + """ + self.optimize_loop(ops, expected) + + def test_setarrayitem_lazy(self): + ops = """ + [i0, i1] + p0 = escape() + i2 = escape() + p1 = new_with_vtable(ConstClass(node_vtable)) + setarrayitem_gc(p0, 2, p1, descr=arraydescr) + guard_true(i2) [] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + expected = """ + [i0, i1] + p0 = escape() + i2 = escape() + guard_true(i2) [p0] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py rename from pypy/jit/metainterp/test/test_optimizeutil.py rename to pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/test/test_optimizeutil.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -9,11 +9,15 @@ from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, Const, TreeLoop, BoxObj, ConstObj, AbstractDescr) -from pypy.jit.metainterp.optimizeutil import sort_descrs, InvalidLoop +from pypy.jit.metainterp.optimizeopt.util import sort_descrs, equaloplists +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter.heaptracker import register_known_gctype, adr2int -from pypy.jit.tool.oparser import parse +from pypy.jit.tool.oparser import parse, pure_parse from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr +from pypy.jit.metainterp import compile, resume, history +from pypy.jit.metainterp.jitprof import EmptyProfiler +from pypy.config.pypyoption import get_pypy_config def test_sort_descrs(): class PseudoDescr(AbstractDescr): @@ -28,6 +32,44 @@ sort_descrs(lst2) assert lst2 == lst +def test_equaloplists(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops, namespace=namespace) + loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), + namespace=namespace) + assert equaloplists(loop1.operations, loop2.operations) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + +def test_equaloplists_fail_args(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2, i1] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop2.operations)") + assert equaloplists(loop1.operations, loop2.operations, + strict_fail_args=False) + loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + # ____________________________________________________________ class LLtypeMixin(object): @@ -124,19 +166,19 @@ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [])) + EffectInfo([], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [])) + EffectInfo([], [], [adescr], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [arraydescr])) + EffectInfo([], [], [adescr], [arraydescr])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([adescr], [], [])) + EffectInfo([adescr], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([nextdescr], [], [], + EffectInfo([nextdescr], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), @@ -153,15 +195,15 @@ _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): @@ -256,8 +298,45 @@ ## u_vtable_adr: cpu.typedescrof(U)} ## namespace = locals() +# ____________________________________________________________ + + + +class Fake(object): + failargs_limit = 1000 + storedebug = None + + +class FakeMetaInterpStaticData(object): + + def __init__(self, cpu): + self.cpu = cpu + self.profiler = EmptyProfiler() + self.options = Fake() + self.globaldata = Fake() + self.config = get_pypy_config(translating=True) + self.config.translation.jit_ffi = True + + +class Storage(compile.ResumeGuardDescr): + "for tests." + def __init__(self, metainterp_sd=None, original_greenkey=None): + self.metainterp_sd = metainterp_sd + self.original_greenkey = original_greenkey + def store_final_boxes(self, op, boxes): + op.setfailargs(boxes) + def __eq__(self, other): + return type(self) is type(other) # xxx obscure + def clone_if_mutable(self): + res = Storage(self.metainterp_sd, self.original_greenkey) + self.copy_all_attributes_into(res) + return res + +def _sortboxes(boxes): + _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} + return sorted(boxes, key=lambda box: _kind2count[box.type]) + class BaseTest(object): - invent_fail_descr = None def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, @@ -265,5 +344,40 @@ boxkinds=boxkinds, invent_fail_descr=self.invent_fail_descr) + def invent_fail_descr(self, model, fail_args): + if fail_args is None: + return None + descr = Storage() + descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) + descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) + return descr + + def assert_equal(self, optimized, expected, text_right=None): + from pypy.jit.metainterp.optimizeopt.util import equaloplists + assert len(optimized.inputargs) == len(expected.inputargs) + remap = {} + for box1, box2 in zip(optimized.inputargs, expected.inputargs): + assert box1.__class__ == box2.__class__ + remap[box2] = box1 + assert equaloplists(optimized.operations, + expected.operations, False, remap, text_right) + + def _do_optimize_loop(self, loop, call_pure_results): + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 + from pypy.jit.metainterp.optimizeopt.util import args_dict + + self.loop = loop + loop.call_pure_results = args_dict() + if call_pure_results is not None: + for k, v in call_pure_results.items(): + loop.call_pure_results[list(k)] = v + metainterp_sd = FakeMetaInterpStaticData(self.cpu) + if hasattr(self, 'vrefinfo'): + metainterp_sd.virtualref_info = self.vrefinfo + if hasattr(self, 'callinfocollection'): + metainterp_sd.callinfocollection = self.callinfocollection + # + optimize_loop_1(metainterp_sd, loop, self.enable_opts) + # ____________________________________________________________ diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -5,7 +5,7 @@ from pypy.jit.metainterp.resume import Snapshot from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop, RetraceLoop +from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.history import make_hashable_int from pypy.jit.codewriter.effectinfo import EffectInfo @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jdindex, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -914,8 +914,10 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jd_index, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation + loc = jitdriver_sd.warmstate.get_location_str(greenkey) + debug_print(loc) args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @@ -1231,7 +1233,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: @@ -1927,7 +1929,6 @@ self.history.inputargs = original_inputargs self.history.operations.pop() # remove the JUMP - # FIXME: Why is self.history.inputargs not restored? def compile_bridge(self, live_arg_boxes): num_green_args = self.jitdriver_sd.num_green_args @@ -1963,6 +1964,8 @@ start_resumedescr, False) self.history.operations.pop() # remove the JUMP if loop_token is None: + self.history.inputargs = original_inputargs + self.history.operations = original_operations return if loop_token.short_preamble: @@ -2117,7 +2120,6 @@ def vrefs_after_residual_call(self): vrefinfo = self.staticdata.virtualref_info for i in range(0, len(self.virtualref_boxes), 2): - virtualbox = self.virtualref_boxes[i] vrefbox = self.virtualref_boxes[i+1] vref = vrefbox.getref_base() if vrefinfo.tracing_after_residual_call(vref): diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -478,7 +478,7 @@ 'UNICODESETITEM/3', #'RUNTIMENEW/1', # ootype operation 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier) - 'COND_CALL_GC_WB_ARRAY/3d', # [objptr, newvalue, arrayindex] (write barr.) + 'COND_CALL_GC_WB_ARRAY/3d', # [objptr, arrayindex, newvalue] (write barr.) 'DEBUG_MERGE_POINT/*', # debugging only 'JIT_DEBUG/*', # debugging only 'VIRTUAL_REF_FINISH/2', # removed before it's passed to the backend diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -2,15 +2,17 @@ from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr +from pypy.rpython import annlowlevel from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop # Logic to encode the chain of frames and the state of the boxes at a # guard operation, and to decode it again. This is a bit advanced, @@ -82,6 +84,13 @@ ('nums', lltype.Array(rffi.SHORT))) NUMBERINGP.TO.become(NUMBERING) +PENDINGFIELDSTRUCT = lltype.Struct('PendingField', + ('lldescr', annlowlevel.base_ptr_lltype()), + ('num', rffi.SHORT), + ('fieldnum', rffi.SHORT), + ('itemindex', rffi.INT)) +PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) + TAGMASK = 3 def tag(value, tagbits): @@ -329,7 +338,7 @@ value = values[box] value.get_args_for_fail(self) - for _, box, fieldbox in pending_setfields: + for _, box, fieldbox, _ in pending_setfields: self.register_box(box) self.register_box(fieldbox) value = values[fieldbox] @@ -405,13 +414,25 @@ return False def _add_pending_fields(self, pending_setfields): - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) if pending_setfields: - rd_pendingfields = [] - for descr, box, fieldbox in pending_setfields: + n = len(pending_setfields) + rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) + for i in range(n): + descr, box, fieldbox, itemindex = pending_setfields[i] + lldescr = annlowlevel.cast_instance_to_base_ptr(descr) num = self._gettagged(box) fieldnum = self._gettagged(fieldbox) - rd_pendingfields.append((descr, num, fieldnum)) + # the index is limited to 2147483647 (64-bit machines only) + if itemindex > 2147483647: + from pypy.jit.metainterp import compile + compile.giveup() + itemindex = rffi.cast(rffi.INT, itemindex) + # + rd_pendingfields[i].lldescr = lldescr + rd_pendingfields[i].num = num + rd_pendingfields[i].fieldnum = fieldnum + rd_pendingfields[i].itemindex= itemindex self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): @@ -727,10 +748,28 @@ self.virtuals_cache = [self.virtual_default] * len(virtuals) def _prepare_pendingfields(self, pendingfields): - if pendingfields is not None: - for descr, num, fieldnum in pendingfields: + if pendingfields: + for i in range(len(pendingfields)): + lldescr = pendingfields[i].lldescr + num = pendingfields[i].num + fieldnum = pendingfields[i].fieldnum + itemindex= pendingfields[i].itemindex + descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, + lldescr) struct = self.decode_ref(num) - self.setfield(descr, struct, fieldnum) + itemindex = rffi.cast(lltype.Signed, itemindex) + if itemindex < 0: + self.setfield(descr, struct, fieldnum) + else: + self.setarrayitem(descr, struct, itemindex, fieldnum) + + def setarrayitem(self, arraydescr, array, index, fieldnum): + if arraydescr.is_array_of_pointers(): + self.setarrayitem_ref(arraydescr, array, index, fieldnum) + elif arraydescr.is_array_of_floats(): + self.setarrayitem_float(arraydescr, array, index, fieldnum) + else: + self.setarrayitem_int(arraydescr, array, index, fieldnum) def _prepare_next_section(self, info): # Use info.enumerate_vars(), normally dispatching to @@ -903,15 +942,15 @@ structbox, fieldbox) def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, INT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT) def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, REF) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF) def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) - def setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): + def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): itembox = self.decode_box(fieldnum, kind) self.metainterp.execute_and_record(rop.SETARRAYITEM_GC, arraydescr, arraybox, diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -500,7 +500,7 @@ y -= x return y # - res = self.meta_interp(f, [3, 6], repeat=7) + res = self.meta_interp(f, [3, 6], repeat=7, function_threshold=0) assert res == 6 - 4 - 5 self.check_history(call=0) # because the trace starts in the middle # @@ -1252,7 +1252,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1312,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1343,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1496,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1531,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1595,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1676,7 +1676,9 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) + py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) def test_multiple_specialied_versions_bridge(self): @@ -1815,7 +1817,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2000,7 +2002,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2045,7 +2047,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2080,7 +2082,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2137,7 +2139,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2206,7 +2208,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2230,6 +2233,148 @@ self.check_loops(getfield_gc_pure=0) self.check_loops(getfield_gc_pure=2, everywhere=True) + def test_frame_finished_during_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 1 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 1000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'a']) + def f(): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 2) + a = A(0) + sa = 0 + while a.val < 8: + myjitdriver.jit_merge_point(a=a, sa=sa) + a = a.inc() + if a.val > 4: + a = B(a.val) + sa += a.num + return sa + res = self.meta_interp(f, []) + assert res == f() + + def test_frame_finished_during_continued_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 100 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 10000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'b', 'a']) + def f(b): + myjitdriver.set_param('threshold', 6) + myjitdriver.set_param('trace_eagerness', 4) + a = A(0) + sa = 0 + while a.val < 15: + myjitdriver.jit_merge_point(a=a, b=b, sa=sa) + a = a.inc() + if a.val > 8: + a = B(a.val) + if b == 1: + b = 2 + else: + b = 1 + sa += a.num + b + return sa + res = self.meta_interp(f, [1]) + assert res == f(1) + + def test_remove_array_operations(self): + myjitdriver = JitDriver(greens = [], reds = ['a']) + class W_Int: + def __init__(self, intvalue): + self.intvalue = intvalue + def f(x): + a = [W_Int(x)] + while a[0].intvalue > 0: + myjitdriver.jit_merge_point(a=a) + a[0] = W_Int(a[0].intvalue - 3) + return a[0].intvalue + res = self.meta_interp(f, [100]) + assert res == -2 + #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + + def test_retrace_ending_up_retrazing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py --- a/pypy/jit/metainterp/test/test_compile.py +++ b/pypy/jit/metainterp/test/test_compile.py @@ -1,3 +1,4 @@ +from pypy.config.pypyoption import get_pypy_config from pypy.jit.metainterp.history import LoopToken, ConstInt, History, Stats from pypy.jit.metainterp.history import BoxInt, INT from pypy.jit.metainterp.compile import insert_loop_token, compile_new_loop @@ -5,7 +6,7 @@ from pypy.jit.metainterp.compile import ResumeGuardCountersInt from pypy.jit.metainterp.compile import compile_tmp_callback from pypy.jit.metainterp import jitprof, typesystem, compile -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.tool.oparser import parse from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT @@ -57,6 +58,7 @@ logger_noopt = FakeLogger() logger_ops = FakeLogger() + config = get_pypy_config(translating=True) stats = Stats() profiler = jitprof.EmptyProfiler() diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -130,6 +130,38 @@ assert res == 50 self.check_loops(int_mod=1) + def test_repeated_lookup(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'd']) + class Wrapper(object): + _immutable_fields_ = ["value"] + def __init__(self, value): + self.value = value + def eq_func(a, b): + return a.value == b.value + def hash_func(x): + return objectmodel.compute_hash(x.value) + + def f(n): + d = None + while n > 0: + myjitdriver.jit_merge_point(n=n, d=d) + d = objectmodel.r_dict(eq_func, hash_func) + y = Wrapper(str(n)) + d[y] = n - 1 + n = d[y] + return d[Wrapper(str(n + 1))] + + res = self.meta_interp(f, [100], listops=True) + assert res == f(50) + # XXX: ideally there would be 7 calls here, but repeated CALL_PURE with + # the same arguments are not folded, because we have conflicting + # definitions of pure, once strhash can be appropriately folded + # this should be decreased to seven. + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + "guard_true": 1, "int_and": 1, "int_gt": 1, + "int_is_true": 1, "int_sub": 1, "jump": 1, + "new_with_vtable": 1, "setfield_gc": 1}) + class TestOOtype(DictTests, OOJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py --- a/pypy/jit/metainterp/test/test_jitdriver.py +++ b/pypy/jit/metainterp/test/test_jitdriver.py @@ -113,6 +113,7 @@ return n # def loop2(g, r): + myjitdriver1.set_param('function_threshold', 0) while r > 0: myjitdriver2.can_enter_jit(g=g, r=r) myjitdriver2.jit_merge_point(g=g, r=r) diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -49,7 +49,7 @@ x = l[n] l = [3] * 100 l[3] = x - l[3] = x + 1 + l[4] = x + 1 n -= 1 return l[0] diff --git a/pypy/jit/metainterp/test/test_logger.py b/pypy/jit/metainterp/test/test_logger.py --- a/pypy/jit/metainterp/test/test_logger.py +++ b/pypy/jit/metainterp/test/test_logger.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp import logger from pypy.jit.metainterp.typesystem import llhelper from StringIO import StringIO -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.metainterp.history import AbstractDescr, LoopToken, BasicFailDescr from pypy.jit.backend.model import AbstractCPU diff --git a/pypy/jit/metainterp/test/test_pyjitpl.py b/pypy/jit/metainterp/test/test_pyjitpl.py --- a/pypy/jit/metainterp/test/test_pyjitpl.py +++ b/pypy/jit/metainterp/test/test_pyjitpl.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.history import BoxInt, ConstInt from pypy.jit.metainterp.history import History from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.codewriter.jitcode import JitCode diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -483,6 +483,7 @@ def main(inline): myjitdriver.set_param("threshold", 10) + myjitdriver.set_param('function_threshold', 60) if inline: myjitdriver.set_param('inlining', True) else: @@ -925,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 @@ -1193,6 +1194,51 @@ i -= 1 self.meta_interp(portal, [0, 10], inline=True) + def test_trace_from_start_always(self): + from pypy.rlib.nonconst import NonConstant + + driver = JitDriver(greens = ['c'], reds = ['i', 'v']) + + def portal(c, i, v): + while i > 0: + driver.jit_merge_point(c=c, i=i, v=v) + portal(c, i - 1, v) + if v: + driver.can_enter_jit(c=c, i=i, v=v) + break + + def main(c, i, set_param, v): + if set_param: + driver.set_param('function_threshold', 0) + portal(c, i, v) + + self.meta_interp(main, [10, 10, False, False], inline=True) + self.check_tree_loop_count(1) + self.check_loop_count(0) + self.meta_interp(main, [3, 10, True, False], inline=True) + self.check_tree_loop_count(0) + self.check_loop_count(0) + + def test_trace_from_start_does_not_prevent_inlining(self): + driver = JitDriver(greens = ['c', 'bc'], reds = ['i']) + + def portal(bc, c, i): + while True: + driver.jit_merge_point(c=c, bc=bc, i=i) + if bc == 0: + portal(1, 8, 0) + c += 1 + else: + return + if c == 10: # bc == 0 + c = 0 + if i >= 100: + return + driver.can_enter_jit(c=c, bc=bc, i=i) + i += 1 + + self.meta_interp(portal, [0, 0, 0], inline=True) + self.check_loops(call=0, call_may_force=0) class TestLLtype(RecursiveTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py --- a/pypy/jit/metainterp/test/test_resume.py +++ b/pypy/jit/metainterp/test/test_resume.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.resume import * from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt from pypy.jit.metainterp.history import ConstPtr, ConstFloat -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.metainterp import executor from pypy.jit.codewriter import heaptracker, longlong @@ -1238,7 +1238,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, values, 0) assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)]) + modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s, -1)]) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume @@ -1259,6 +1259,106 @@ assert len(expected) == len(trace) assert demo55.next == demo66 +def test_virtual_adder_pending_fields_and_arrayitems(): + class Storage(object): + pass + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier._add_pending_fields([]) + assert not storage.rd_pendingfields + # + class FieldDescr(object): + pass + field_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061)} + modifier._add_pending_fields([(field_a, 42, 61, -1)]) + pf = storage.rd_pendingfields + assert len(pf) == 1 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is field_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + # + array_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061), + 62: rffi.cast(rffi.SHORT, 1062), + 63: rffi.cast(rffi.SHORT, 1063)} + modifier._add_pending_fields([(array_a, 42, 61, 0), + (array_a, 42, 62, 2147483647)]) + pf = storage.rd_pendingfields + assert len(pf) == 2 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[1].num) == 1042 + assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 + assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + # + from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole + py.test.raises(SwitchToBlackhole, modifier._add_pending_fields, + [(array_a, 42, 63, 2147483648)]) + +def test_resume_reader_fields_and_arrayitems(): + class ResumeReader(AbstractResumeDataReader): + def __init__(self, got=None, got_array=None): + self.got = got + self.got_array = got_array + def setfield(self, descr, struct, fieldnum): + assert lltype.typeOf(struct) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got.append((descr, struct, fieldnum)) + def setarrayitem(self, arraydescr, array, index, fieldnum): + assert lltype.typeOf(array) is lltype.Signed + assert lltype.typeOf(index) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got_array.append((arraydescr, array, index, fieldnum)) + def decode_ref(self, num): + return rffi.cast(lltype.Signed, num) * 100 + got = [] + pf = lltype.nullptr(PENDINGFIELDSP.TO) + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [] + # + class FieldDescr(AbstractDescr): + pass + field_a = FieldDescr() + field_b = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 2) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) + pf[0].itemindex = rffi.cast(rffi.INT, -1) + pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) + pf[1].num = rffi.cast(rffi.SHORT, 2042) + pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) + pf[1].itemindex = rffi.cast(rffi.INT, -1) + got = [] + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] + # + array_a = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 1) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) + pf[0].itemindex = rffi.cast(rffi.INT, 123) + got_array = [] + ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + assert got_array == [(array_a, 104200, 123, 1063)] + def test_invalidation_needed(): class options: diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,13 +5,13 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor from pypy.jit.metainterp.warmspot import get_stats, get_translator from pypy.jit.metainterp import history -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin def promote_virtualizable(*args): pass @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py --- a/pypy/jit/metainterp/virtualref.py +++ b/pypy/jit/metainterp/virtualref.py @@ -1,5 +1,5 @@ from pypy.rpython.rmodel import inputconst, log -from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass +from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.jit.metainterp import history from pypy.jit.codewriter import heaptracker from pypy.rlib.jit import InvalidVirtualRef diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -1,6 +1,5 @@ import sys, py -from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr -from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.annlowlevel import llhelper, MixLevelHelperAnnotator,\ cast_base_ptr_to_instance, hlstr from pypy.annotation import model as annmodel @@ -10,16 +9,12 @@ from pypy.objspace.flow.model import checkgraph, Link, copygraph from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import r_uint, intmask -from pypy.rlib.debug import debug_print, fatalerror -from pypy.rlib.debug import debug_start, debug_stop -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.translator.simplify import get_funcobj, get_functype +from pypy.rlib.debug import fatalerror +from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function from pypy.jit.metainterp import history, pyjitpl, gc, memmgr -from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp -from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper +from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.jitdriver import JitDriverStaticData @@ -66,6 +61,7 @@ def jittify_and_run(interp, graph, args, repeat=1, backendopt=False, trace_limit=sys.maxint, inline=False, loop_longevity=0, retrace_limit=5, + function_threshold=4, enable_opts=ALL_OPTS_NAMES, **kwds): from pypy.config.config import ConfigError translator = interp.typer.annotator.translator @@ -77,9 +73,14 @@ translator.config.translation.list_comprehension_operations = True except ConfigError: pass + try: + translator.config.translation.jit_ffi = True + except ConfigError: + pass warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds) for jd in warmrunnerdesc.jitdrivers_sd: jd.warmstate.set_param_threshold(3) # for tests + jd.warmstate.set_param_function_threshold(function_threshold) jd.warmstate.set_param_trace_eagerness(2) # for tests jd.warmstate.set_param_trace_limit(trace_limit) jd.warmstate.set_param_inlining(inline) @@ -291,9 +292,6 @@ self.stats = stats if translate_support_code: self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper) - annhelper = self.annhelper - else: - annhelper = None cpu = CPUClass(self.translator.rtyper, self.stats, self.opt, translate_support_code, gcdescr=self.gcdescr) self.cpu = cpu @@ -422,7 +420,7 @@ if self.translator.rtyper.type_system.name == 'lltypesystem': def maybe_enter_jit(*args): try: - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) except JitException: raise # go through except Exception, e: @@ -430,15 +428,12 @@ maybe_enter_jit._always_inline_ = True else: def maybe_enter_jit(*args): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) maybe_enter_jit._always_inline_ = True jd._maybe_enter_jit_fn = maybe_enter_jit - can_inline = state.can_inline_greenargs - num_green_args = jd.num_green_args def maybe_enter_from_start(*args): - if not can_inline(*args[:num_green_args]): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_function_threshold, *args) maybe_enter_from_start._always_inline_ = True jd._maybe_enter_from_start_fn = maybe_enter_from_start @@ -549,7 +544,6 @@ self.rewrite_can_enter_jit(jd, sublist) def rewrite_can_enter_jit(self, jd, can_enter_jits): - FUNC = jd._JIT_ENTER_FUNCTYPE FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -1,7 +1,7 @@ import sys, weakref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi from pypy.rpython.ootypesystem import ootype -from pypy.rpython.annlowlevel import hlstr, llstr, cast_base_ptr_to_instance +from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance from pypy.rpython.annlowlevel import cast_object_to_ptr from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict from pypy.rlib.rarithmetic import intmask @@ -208,15 +208,20 @@ meth = getattr(self, 'set_param_' + name) meth(default_value) - def set_param_threshold(self, threshold): + def _compute_threshold(self, threshold): if threshold <= 0: - self.increment_threshold = 0 # never reach the THRESHOLD_LIMIT - return + return 0 # never reach the THRESHOLD_LIMIT if threshold < 2: threshold = 2 - self.increment_threshold = (self.THRESHOLD_LIMIT // threshold) + 1 + return (self.THRESHOLD_LIMIT // threshold) + 1 # the number is at least 1, and at most about half THRESHOLD_LIMIT + def set_param_threshold(self, threshold): + self.increment_threshold = self._compute_threshold(threshold) + + def set_param_function_threshold(self, threshold): + self.increment_function_threshold = self._compute_threshold(threshold) + def set_param_trace_eagerness(self, value): self.trace_eagerness = value @@ -232,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: @@ -291,7 +296,7 @@ self.make_jitdriver_callbacks() confirm_enter_jit = self.confirm_enter_jit - def maybe_compile_and_run(*args): + def maybe_compile_and_run(threshold, *args): """Entry point to the JIT. Called at the point with the can_enter_jit() hint. """ @@ -307,7 +312,7 @@ if cell.counter >= 0: # update the profiling counter - n = cell.counter + self.increment_threshold + n = cell.counter + threshold if n <= self.THRESHOLD_LIMIT: # bound not reached cell.counter = n return @@ -497,7 +502,6 @@ if hasattr(self, 'set_future_values'): return self.set_future_values - warmrunnerdesc = self.warmrunnerdesc jitdriver_sd = self.jitdriver_sd cpu = self.cpu vinfo = jitdriver_sd.virtualizable_info @@ -513,7 +517,6 @@ # if vinfo is not None: i0 = len(jitdriver_sd._red_args_types) - num_green_args = jitdriver_sd.num_green_args index_of_virtualizable = jitdriver_sd.index_of_virtualizable vable_static_fields = unrolling_iterable( zip(vinfo.static_extra_types, vinfo.static_fields)) diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -181,11 +181,8 @@ args = [] descr = None if argspec.strip(): - if opname == 'debug_merge_point': - allargs = argspec.split(',', 1) - else: - allargs = [arg for arg in argspec.split(",") - if arg != ''] + allargs = [arg for arg in argspec.split(",") + if arg != ''] poss_descr = allargs[-1].strip() if poss_descr.startswith('descr='): diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -32,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/jit/tool/test/test_oparser.py b/pypy/jit/tool/test/test_oparser.py --- a/pypy/jit/tool/test/test_oparser.py +++ b/pypy/jit/tool/test/test_oparser.py @@ -147,13 +147,13 @@ [] debug_merge_point(0, "info") debug_merge_point(0, 'info') - debug_merge_point(1, ' info') + debug_merge_point(1, ' info') debug_merge_point(0, '(stuff) #1') ''' loop = self.parse(x) assert loop.operations[0].getarg(1)._get_str() == 'info' assert loop.operations[1].getarg(1)._get_str() == 'info' - assert loop.operations[2].getarg(1)._get_str() == " info" + assert loop.operations[2].getarg(1)._get_str() == " info" assert loop.operations[3].getarg(1)._get_str() == "(stuff) #1" diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -294,7 +294,7 @@ break new_frame = space.createframe(code, w_func.w_func_globals, w_func.closure) - new_frame.fastlocals_w[0] = w_item + new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) return result_w diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -1,5 +1,6 @@ import autopath import sys +from pypy import conftest class AppTestBuiltinApp: def setup_class(cls): @@ -15,6 +16,15 @@ cls.w_sane_lookup = cls.space.wrap(True) except KeyError: cls.w_sane_lookup = cls.space.wrap(False) + # starting with CPython 2.6, when the stack is almost out, we + # can get a random error, instead of just a RuntimeError. + # For example if an object x has a __getattr__, we can get + # AttributeError if attempting to call x.__getattr__ runs out + # of stack. That's annoying, so we just work around it. + if conftest.option.runappdirect: + cls.w_safe_runtimerror = cls.space.wrap(True) + else: + cls.w_safe_runtimerror = cls.space.wrap(sys.version_info < (2, 6)) def test_bytes_alias(self): assert bytes is str @@ -399,6 +409,8 @@ def test_cmp_cyclic(self): if not self.sane_lookup: skip("underlying Python implementation has insane dict lookup") + if not self.safe_runtimerror: + skip("underlying Python may raise random exceptions on stack ovf") a = []; a.append(a) b = []; b.append(b) from UserList import UserList @@ -619,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -3,6 +3,14 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.imp.importing import get_pyc_magic + +class BuildersModule(MixedModule): + appleveldefs = {} + + interpleveldefs = { + "UnicodeBuilder": "interp_builders.W_UnicodeBuilder", + } + class Module(MixedModule): appleveldefs = { } @@ -19,6 +27,10 @@ 'lookup_special' : 'interp_magic.lookup_special', } + submodules = { + "builders": BuildersModule, + } + def setup_after_space_initialization(self): """NOT_RPYTHON""" if not self.space.config.translating: diff --git a/pypy/module/__pypy__/interp_builders.py b/pypy/module/__pypy__/interp_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_builders.py @@ -0,0 +1,50 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef +from pypy.rlib.rstring import UnicodeBuilder + + +class W_UnicodeBuilder(Wrappable): + def __init__(self, space, size): + if size == -1: + self.builder = UnicodeBuilder() + else: + self.builder = UnicodeBuilder(size) + self.done = False + + def _check_done(self, space): + if self.done: + raise OperationError(space.w_ValueError, space.wrap("Can't operate on a done builder")) + + @unwrap_spec(size=int) + def descr__new__(space, w_subtype, size=-1): + return W_UnicodeBuilder(space, size) + + @unwrap_spec(s=unicode) + def descr_append(self, space, s): + self._check_done(space) + self.builder.append(s) + + @unwrap_spec(s=unicode, start=int, end=int) + def descr_append_slice(self, space, s, start, end): + self._check_done(space) + if not 0 <= start <= end <= len(s): + raise OperationError(space.w_ValueError, space.wrap("bad start/stop")) + self.builder.append_slice(s, start, end) + + def descr_build(self, space): + self._check_done(space) + w_s = space.wrap(self.builder.build()) + self.done = True + return w_s + + +W_UnicodeBuilder.typedef = TypeDef("UnicodeBuilder", + __new__ = interp2app(W_UnicodeBuilder.descr__new__.im_func), + + append = interp2app(W_UnicodeBuilder.descr_append), + append_slice = interp2app(W_UnicodeBuilder.descr_append_slice), + build = interp2app(W_UnicodeBuilder.descr_build), +) +W_UnicodeBuilder.typedef.acceptable_as_base_class = False \ No newline at end of file diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,15 +1,19 @@ from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.error import OperationError -from pypy.rlib import debug +from pypy.rlib import debug, jit + + at jit.dont_look_inside @unwrap_spec(category=str) def debug_start(space, category): debug.debug_start(category) + at jit.dont_look_inside def debug_print(space, args_w): parts = [space.str_w(space.str(w_item)) for w_item in args_w] debug.debug_print(' '.join(parts)) + at jit.dont_look_inside @unwrap_spec(category=str) def debug_stop(space, category): debug.debug_stop(category) diff --git a/pypy/module/__pypy__/test/test_builders.py b/pypy/module/__pypy__/test/test_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_builders.py @@ -0,0 +1,34 @@ +from pypy.conftest import gettestobjspace + + +class AppTestBuilders(object): + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['__pypy__']) + + def test_simple(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append(u"abc") + b.append(u"123") + b.append(u"1") + s = b.build() + assert s == u"abc1231" + raises(ValueError, b.build) + raises(ValueError, b.append, u"123") + + def test_preallocate(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder(10) + b.append(u"abc") + b.append(u"123") + s = b.build() + assert s == u"abc123" + + def test_append_slice(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append_slice(u"abcdefgh", 2, 5) + raises(ValueError, b.append_slice, u"1", 2, 1) + s = b.build() + assert s == "cde" + raises(ValueError, b.append_slice, u"abc", 1, 2) \ No newline at end of file diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -186,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -207,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -240,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -176,7 +176,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + elif (_MS_WINDOWS and space.is_true(space.isinstance(w_name, space.w_int))): ordinal = space.int_w(w_name) @@ -261,7 +261,7 @@ def descr_size_alignment(self, space, n=1): return space.newtuple([space.wrap(self.size * n), space.wrap(self.alignment)]) - + class W_DataInstance(Wrappable): def __init__(self, space, size, address=r_uint(0)): @@ -427,7 +427,7 @@ if not (argletter in TYPEMAP_PTR_LETTERS and letter in TYPEMAP_PTR_LETTERS): msg = "Argument %d should be typecode %s, got %s" - raise operationerrfmt(space.w_TypeError, msg, + raise operationerrfmt(space.w_TypeError, msg, i+1, argletter, letter) args_ll.append(arg.ll_buffer) # XXX we could avoid the intermediate list args_ll @@ -480,17 +480,25 @@ alignment = _create_new_accessor('alignment', 'c_alignment') @unwrap_spec(address=r_uint, maxlength=int) -def charp2string(space, address, maxlength=sys.maxint): +def charp2string(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.charp2strn(rffi.cast(rffi.CCHARP, address), maxlength) + charp_addr = rffi.cast(rffi.CCHARP, address) + if maxlength == -1: + s = rffi.charp2str(charp_addr) + else: + s = rffi.charp2strn(charp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) -def wcharp2unicode(space, address, maxlength=sys.maxint): +def wcharp2unicode(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.wcharp2unicoden(rffi.cast(rffi.CWCHARP, address), maxlength) + wcharp_addr = rffi.cast(rffi.CWCHARP, address) + if maxlength == -1: + s = rffi.wcharp2unicode(wcharp_addr) + else: + s = rffi.wcharp2unicoden(wcharp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,3 +1,4 @@ +from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable @@ -899,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_stackless/test/test_greenlet.py b/pypy/module/_stackless/test/test_greenlet.py --- a/pypy/module/_stackless/test/test_greenlet.py +++ b/pypy/module/_stackless/test/test_greenlet.py @@ -72,6 +72,23 @@ g1 = greenlet(f) raises(ValueError, g2.switch) + + def test_exc_info_save_restore(self): + from _stackless import greenlet + import sys + def f(): + try: + raise ValueError('fun') + except: + exc_info = sys.exc_info() + greenlet(h).switch() + assert exc_info == sys.exc_info() + + def h(): + assert sys.exc_info() == (None, None, None) + + greenlet(f).switch() + def test_exception(self): from _stackless import greenlet import sys diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,21 @@ from __future__ import with_statement +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -37,7 +40,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -73,6 +76,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +100,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +163,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -268,12 +270,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -311,6 +311,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -319,12 +327,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -387,7 +390,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -395,7 +398,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -413,7 +416,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -515,14 +518,14 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() @@ -615,6 +618,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) + return w_a + def array_byteswap__Array(space, self): if mytype.bytes not in [1, 2, 4, 8]: msg = "byteswap not supported for this array" diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -39,6 +39,7 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject +import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject import pypy.module.cpyext.longobject @@ -64,6 +65,7 @@ import pypy.module.cpyext.memoryobject import pypy.module.cpyext.codecs import pypy.module.cpyext.pyfile +import pypy.module.cpyext.pystrtod # now that all rffi_platform.Struct types are registered, configure them api.configure_types() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -562,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/pystrtod.py @@ -0,0 +1,68 @@ +import errno +from pypy.interpreter.error import OperationError +from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.pyobject import PyObject +from pypy.rlib import rdtoa +from pypy.rlib import rfloat +from pypy.rlib import rposix +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi + + + at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +def PyOS_string_to_double(space, s, endptr, w_overflow_exception): + """Convert a string s to a double, raising a Python + exception on failure. The set of accepted strings corresponds to + the set of strings accepted by Python's float() constructor, + except that s must not have leading or trailing whitespace. + The conversion is independent of the current locale. + + If endptr is NULL, convert the whole string. Raise + ValueError and return -1.0 if the string is not a valid + representation of a floating-point number. + + If endptr is not NULL, convert as much of the string as + possible and set *endptr to point to the first unconverted + character. If no initial segment of the string is the valid + representation of a floating-point number, set *endptr to point + to the beginning of the string, raise ValueError, and return + -1.0. + + If s represents a value that is too large to store in a float + (for example, "1e500" is such a string on many platforms) then + if overflow_exception is NULL return Py_HUGE_VAL (with + an appropriate sign) and don't set any exception. Otherwise, + overflow_exception must point to a Python exception object; + raise that exception and return -1.0. In both cases, set + *endptr to point to the first character after the converted value. + + If any other error occurs during the conversion (for example an + out-of-memory error), set the appropriate Python exception and + return -1.0. + """ + user_endptr = True + try: + if not endptr: + endptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + user_endptr = False + result = rdtoa.dg_strtod(s, endptr) + endpos = (rffi.cast(rffi.LONG, endptr[0]) - + rffi.cast(rffi.LONG, s)) + if endpos == 0 or (not user_endptr and not endptr[0][0] == '\0'): + raise OperationError( + space.w_ValueError, + space.wrap('invalid input at position %s' % endpos)) + if rposix.get_errno() == errno.ERANGE: + rposix.set_errno(0) + if w_overflow_exception is None: + if result > 0: + return rfloat.INFINITY + else: + return -rfloat.INFINITY + else: + raise OperationError(w_overflow_exception, + space.wrap('value too large')) + return result + finally: + if not user_endptr: + lltype.free(endptr, flavor='raw') diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/setobject.py @@ -0,0 +1,46 @@ +from pypy.interpreter.error import OperationError +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, + build_type_checkers) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, + borrow_from, make_ref, from_ref) +from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall +from pypy.objspace.std.setobject import W_SetObject, newset +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject + + +PySet_Check, PySet_CheckExact = build_type_checkers("Set") + + + at cpython_api([PyObject], PyObject) +def PySet_New(space, w_iterable): + if w_iterable is None: + return space.call_function(space.w_set) + else: + return space.call_function(space.w_set, w_iterable) + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Add(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'add', w_obj) + return 0 + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Discard(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'discard', w_obj) + return 0 + + + at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +def PySet_GET_SIZE(space, w_s): + return space.int_w(space.len(w_s)) + + at cpython_api([PyObject], Py_ssize_t, error=-1) +def PySet_Size(space, ref): + if not PySet_Check(space, ref): + raise OperationError(space.w_TypeError, + space.wrap("expected set object")) + return PySet_GET_SIZE(space, ref) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -480,39 +480,6 @@ """Create a new Python complex number object from a C Py_complex value.""" raise NotImplementedError - at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) -def PyOS_string_to_double(space, s, endptr, overflow_exception): - """Convert a string s to a double, raising a Python - exception on failure. The set of accepted strings corresponds to - the set of strings accepted by Python's float() constructor, - except that s must not have leading or trailing whitespace. - The conversion is independent of the current locale. - - If endptr is NULL, convert the whole string. Raise - ValueError and return -1.0 if the string is not a valid - representation of a floating-point number. - - If endptr is not NULL, convert as much of the string as - possible and set *endptr to point to the first unconverted - character. If no initial segment of the string is the valid - representation of a floating-point number, set *endptr to point - to the beginning of the string, raise ValueError, and return - -1.0. - - If s represents a value that is too large to store in a float - (for example, "1e500" is such a string on many platforms) then - if overflow_exception is NULL return Py_HUGE_VAL (with - an appropriate sign) and don't set any exception. Otherwise, - overflow_exception must point to a Python exception object; - raise that exception and return -1.0. In both cases, set - *endptr to point to the first character after the converted value. - - If any other error occurs during the conversion (for example an - out-of-memory error), set the appropriate Python exception and - return -1.0. - """ - raise NotImplementedError - @cpython_api([rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_strtod(space, nptr, endptr): """Convert a string to a double. This function behaves like the Standard C diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -0,0 +1,93 @@ +import math + +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype + + +class TestPyOS_string_to_double(BaseApiTest): + + def test_simple_float(self, api): + s = rffi.str2charp('0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == 0.4 + rffi.free_charp(s) + + def test_empty_string(self, api): + s = rffi.str2charp('') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_bad_string(self, api): + s = rffi.str2charp(' 0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_overflow_pos(self, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r > 0 + rffi.free_charp(s) + + def test_overflow_neg(self, api): + s = rffi.str2charp('-1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r < 0 + rffi.free_charp(s) + + def test_overflow_exc(self, space, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, space.w_ValueError) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_endptr_number(self, api): + s = rffi.str2charp('0.4') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_tail(self, api): + s = rffi.str2charp('0.4 foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_no_conversion(self, api): + s = rffi.str2charp('foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == -1.0 + raises(ValueError) + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + api.PyErr_Clear() + rffi.free_charp(s) + lltype.free(endp, flavor='raw') diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_setobject.py @@ -0,0 +1,29 @@ +import py + +from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace + + +class TestTupleObject(BaseApiTest): + def test_setobj(self, space, api): + assert not api.PySet_Check(space.w_None) + assert api.PySet_Add(space.w_None, space.w_None) == -1 + api.PyErr_Clear() + w_set = space.call_function(space.w_set) + space.call_method(w_set, 'update', space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + assert api.PySet_GET_SIZE(w_set) == 4 + raises(TypeError, api.PySet_Size(space.newlist([]))) + api.PyErr_Clear() + + def test_set_add_discard(self, space, api): + w_set = api.PySet_New(None) + assert api.PySet_Size(w_set) == 0 + w_set = api.PySet_New(space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + api.PySet_Add(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 5 + api.PySet_Discard(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 4 diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -367,3 +367,14 @@ data, len(u), lltype.nullptr(rffi.CCHARP.TO)) rffi.free_wcharp(data) + def test_format(self, space, api): + w_format = space.wrap(u'hi %s') + w_args = space.wrap((u'test',)) + w_formated = api.PyUnicode_Format(w_format, w_args) + assert space.unwrap(w_formated) == space.unwrap(space.mod(w_format, w_args)) + + def test_join(self, space, api): + w_sep = space.wrap(u'') + w_seq = space.wrap([u'a', u'b']) + w_joined = api.PyUnicode_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == u'ab' diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,6 +7,7 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) + assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -523,3 +523,11 @@ copies sizeof(Py_UNICODE) * length bytes from source to target""" for i in range(0, length): target[i] = source[i] + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Format(space, w_format, w_args): + return space.mod(w_format, w_args) + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -21,6 +21,10 @@ """Return the referenced object from a weak reference. If the referent is no longer live, returns None. This function returns a borrowed reference. """ + return PyWeakref_GET_OBJECT(space, w_ref) + + at cpython_api([PyObject], PyObject) +def PyWeakref_GET_OBJECT(space, w_ref): return borrow_from(w_ref, space.call_function(w_ref)) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -622,7 +622,13 @@ try: if find_info: w_mod = load_module(space, w_modulename, find_info) - w_mod = space.getitem(space.sys.get("modules"), w_modulename) + try: + w_mod = space.getitem(space.sys.get("modules"), + w_modulename) + except OperationError, oe: + if not oe.match(space, space.w_KeyError): + raise + raise OperationError(space.w_ImportError, w_modulename) if w_parent is not None: space.setattr(w_parent, space.wrap(partname), w_mod) return w_mod @@ -793,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -823,8 +828,6 @@ return struct.unpack('= 0") + res = 1 + for i in range(1, x + 1): + res *= i + return res diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -373,22 +373,6 @@ hi = v return space.wrap(hi) -def factorial(space, w_x): - """Find x!.""" - if space.isinstance_w(w_x, space.w_float): - fl = space.float_w(w_x) - if math.floor(fl) != fl: - raise OperationError(space.w_ValueError, - space.wrap("float arguments must be integral")) - w_x = space.long(w_x) - x = space.int_w(w_x) - if x < 0: - raise OperationError(space.w_ValueError, space.wrap("x must be >= 0")) - w_res = space.wrap(1) - for i in range(1, x + 1): - w_res = space.mul(w_res, space.wrap(i)) - return w_res - def log1p(space, w_x): """Find log(x + 1).""" return math1(space, rfloat.log1p, w_x) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -9,11 +9,14 @@ 'array': 'interp_numarray.SingleDimArray', 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', + 'ones': 'interp_numarray.ones', # ufuncs + 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', 'copysign': 'interp_ufuncs.copysign', 'exp': 'interp_ufuncs.exp', + 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', 'negative': 'interp_ufuncs.negative', @@ -21,4 +24,7 @@ 'sign': 'interp_ufuncs.sign', } - appleveldefs = {} + appleveldefs = { + 'average': 'app_numpy.average', + 'mean': 'app_numpy.mean', + } diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/app_numpy.py @@ -0,0 +1,11 @@ +import numpy + +def average(a): + # This implements a weighted average, for now we don't implement the + # weighting, just the average part! + return mean(a) + +def mean(a): + if not hasattr(a, "mean"): + a = numpy.array(a) + return a.mean() \ No newline at end of file diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -40,6 +40,11 @@ elif b == '/': right = stack.pop() stack.append(stack.pop().descr_div(space, right)) + elif b == '%': + right = stack.pop() + stack.append(stack.pop().descr_mod(space, right)) + elif b == '|': + stack.append(stack.pop().descr_abs(space)) else: print "Unknown opcode: %s" % b raise BogusBytecode() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,10 +1,11 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable from pypy.interpreter.error import operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name +import math def dummy1(v): @@ -30,6 +31,12 @@ self.transitions[target] = new = Signature() return new +def pos(v): + return v +def neg(v): + return -v +def absolute(v): + return abs(v) def add(v1, v2): return v1 + v2 def sub(v1, v2): @@ -38,16 +45,40 @@ return v1 * v2 def div(v1, v2): return v1 / v2 +def pow(v1, v2): + return math.pow(v1, v2) +def mod(v1, v2): + return math.fmod(v1, v2) class BaseArray(Wrappable): def __init__(self): self.invalidates = [] def invalidated(self): + if self.invalidates: + self._invalidated() + + def _invalidated(self): for arr in self.invalidates: arr.force_if_needed() del self.invalidates[:] + def _unop_impl(function): + signature = Signature() + def impl(self, space): + new_sig = self.signature.transition(signature) + res = Call1( + function, + self, + new_sig) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + + descr_pos = _unop_impl(pos) + descr_neg = _unop_impl(neg) + descr_abs = _unop_impl(absolute) + def _binop_impl(function): signature = Signature() def impl(self, space, w_other): @@ -76,10 +107,15 @@ descr_sub = _binop_impl(sub) descr_mul = _binop_impl(mul) descr_div = _binop_impl(div) + descr_pow = _binop_impl(pow) + descr_mod = _binop_impl(mod) def get_concrete(self): raise NotImplementedError + def descr_get_shape(self, space): + return space.newtuple([self.descr_len(space)]) + def descr_len(self, space): return self.get_concrete().descr_len(space) @@ -99,6 +135,15 @@ self.invalidated() return self.get_concrete().descr_setitem(space, item, value) + def descr_mean(self, space): + s = 0 + concrete = self.get_concrete() + size = concrete.find_size() + for i in xrange(size): + s += concrete.getitem(i) + return space.wrap(s / size) + + class FloatWrapper(BaseArray): """ Intermediate class representing a float literal. @@ -185,6 +230,7 @@ Intermediate class for performing binary operations. """ _immutable_fields_ = ["function", "left", "right"] + def __init__(self, function, left, right, signature): VirtualArray.__init__(self, signature) self.function = function @@ -208,9 +254,11 @@ class ViewArray(BaseArray): """ - Class for representing views of arrays, they will reflect changes of parrent arrays. Example: slices + Class for representing views of arrays, they will reflect changes of parent + arrays. Example: slices """ _immutable_fields_ = ["parent"] + def __init__(self, parent, signature): BaseArray.__init__(self) self.signature = signature @@ -218,7 +266,10 @@ self.invalidates = parent.invalidates def get_concrete(self): - return self # in fact, ViewArray never gets "concrete" as it never stores data. This implementation is needed for BaseArray getitem/setitem to work, can be refactored. + # in fact, ViewArray never gets "concrete" as it never stores data. + # This implementation is needed for BaseArray getitem/setitem to work, + # can be refactored. + return self def eval(self, i): return self.parent.eval(self.calc_index(i)) @@ -308,20 +359,36 @@ i += 1 return space.wrap(arr) - at unwrap_spec(ObjSpace, int) + at unwrap_spec(size=int) def zeros(space, size): return space.wrap(SingleDimArray(size)) + at unwrap_spec(size=int) +def ones(space, size): + arr = SingleDimArray(size) + for i in xrange(size): + arr.storage[i] = 1.0 + return space.wrap(arr) BaseArray.typedef = TypeDef( 'numarray', __new__ = interp2app(descr_new_numarray), + + shape = GetSetProperty(BaseArray.descr_get_shape), + __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), __setitem__ = interp2app(BaseArray.descr_setitem), + __pos__ = interp2app(BaseArray.descr_pos), + __neg__ = interp2app(BaseArray.descr_neg), + __abs__ = interp2app(BaseArray.descr_abs), __add__ = interp2app(BaseArray.descr_add), __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), __div__ = interp2app(BaseArray.descr_div), + __pow__ = interp2app(BaseArray.descr_pow), + __mod__ = interp2app(BaseArray.descr_mod), + + mean = interp2app(BaseArray.descr_mean), ) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -8,22 +8,24 @@ def ufunc(func): signature = Signature() - @unwrap_spec(array=BaseArray) - def impl(space, array): - w_res = Call1(func, array, array.signature.transition(signature)) - array.invalidates.append(w_res) - return w_res + def impl(space, w_obj): + if isinstance(w_obj, BaseArray): + w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) + w_obj.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() - @unwrap_spec(larray=BaseArray, rarray=BaseArray) - def impl(space, larray, rarray): - new_sig = larray.signature.transition(signature).transition(rarray.signature) - w_res = Call2(func, larray, rarray, new_sig) - larray.invalidates.append(w_res) - rarray.invalidates.append(w_res) - return w_res + def impl(space, w_lhs, w_rhs): + if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): + new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) + w_res = Call2(func, w_lhs, w_rhs, new_sig) + w_lhs.invalidates.append(w_res) + w_rhs.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @ufunc @@ -60,6 +62,10 @@ return 1.0 / value @ufunc +def floor(value): + return math.floor(value) + + at ufunc def sign(value): if value == 0.0: return 0.0 diff --git a/pypy/module/micronumpy/test/test_module.py b/pypy/module/micronumpy/test/test_module.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_module.py @@ -0,0 +1,13 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + + +class AppTestNumPyModule(BaseNumpyAppTest): + def test_mean(self): + from numpy import array, mean + assert mean(array(range(5))) == 2.0 + assert mean(range(5)) == 2.0 + + def test_average(self): + from numpy import array, average + assert average(range(10)) == 4.5 + assert average(array(range(10))) == 4.5 \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -28,6 +28,15 @@ a[1] = 1.0 assert a[1] == 1.0 + def test_ones(self): + from numpy import ones + a = ones(3) + assert len(a) == 3 + assert a[0] == 1 + raises(IndexError, "a[3]") + a[2] = 4 + assert a[2] == 4 + def test_iterator_init(self): from numpy import array a = array(range(5)) @@ -56,6 +65,15 @@ assert len(a) == 5 assert len(a + a) == 5 + def test_shape(self): + from numpy import array + a = array(range(5)) + assert a.shape == (5,) + b = a + a + assert b.shape == (5,) + c = a[:3] + assert c.shape == (3,) + def test_add(self): from numpy import array a = array(range(5)) @@ -136,6 +154,72 @@ for i in range(5): assert b[i] == i / 5.0 + def test_pow(self): + from numpy import array + a = array(range(5)) + b = a ** a + for i in range(5): + print b[i], i**i + assert b[i] == i**i + + def test_pow_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a ** b + for i in range(5): + assert c[i] == i ** 2 + + def test_pow_constant(self): + from numpy import array + a = array(range(5)) + b = a ** 2 + for i in range(5): + assert b[i] == i ** 2 + + def test_mod(self): + from numpy import array + a = array(range(1,6)) + b = a % a + for i in range(5): + assert b[i] == 0 + + def test_mod_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a % b + for i in range(5): + assert c[i] == i % 2 + + def test_mod_constant(self): + from numpy import array + a = array(range(5)) + b = a % 2 + for i in range(5): + assert b[i] == i % 2 + + def test_pos(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = +a + for i in range(5): + assert b[i] == a[i] + + def test_neg(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = -a + for i in range(5): + assert b[i] == -a[i] + + def test_abs(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = abs(a) + for i in range(5): + assert b[i] == abs(a[i]) + def test_auto_force(self): from numpy import array a = array(range(5)) @@ -165,7 +249,7 @@ assert len(s) == 4 for i in range(4): assert s[i] == a[2*i+1] - + def test_slice_update(self): from numpy import array a = array(range(5)) @@ -177,17 +261,22 @@ def test_slice_invaidate(self): - # check that slice shares invalidation list with + # check that slice shares invalidation list with from numpy import array a = array(range(5)) s = a[0:2] b = array([10,11]) c = s + b - a[0]=100 + a[0] = 100 assert c[0] == 10 assert c[1] == 12 d = s + b - a[1]=101 + a[1] = 101 assert d[0] == 110 assert d[1] == 12 + def test_mean(self): + from numpy import array, mean + a = array(range(5)) + assert a.mean() == 2.0 + assert a[:4].mean() == 1.5 diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -3,6 +3,13 @@ class AppTestUfuncs(BaseNumpyAppTest): + def test_single_item(self): + from numpy import negative, sign, minimum + + assert negative(5.0) == -5.0 + assert sign(-0.0) == 0.0 + assert minimum(2.0, 3.0) == 2.0 + def test_negative(self): from numpy import array, negative @@ -60,6 +67,15 @@ for i in range(4): assert b[i] == reference[i] + def test_floor(self): + from numpy import array, floor + + reference = [-2.0, -1.0, 0.0, 1.0, 1.0] + a = array([-1.4, -1.0, 0.0, 1.0, 1.4]) + b = floor(a) + for i in range(5): + assert b[i] == reference[i] + def test_copysign(self): from numpy import array, copysign diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call1, Call2, SingleDimSlice, add, mul) + FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile @@ -13,8 +13,6 @@ cls.space = FakeSpace() def test_add(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, ar, Signature()) @@ -27,8 +25,6 @@ assert result == f(5) def test_floatadd(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, FloatWrapper(4.5), Signature()) @@ -40,11 +36,24 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_already_forecd(self): + def test_neg(self): space = self.space def f(i): ar = SingleDimArray(i) + v = Call1(neg, ar, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, + "setarrayitem_raw": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + + assert result == f(5) + + def test_already_forecd(self): + def f(i): + ar = SingleDimArray(i) v1 = Call2(add, ar, FloatWrapper(4.5), Signature()) v2 = Call2(mul, v1, FloatWrapper(4.5), Signature()) v1.force_if_needed() @@ -95,8 +104,6 @@ self.check_loop_count(3) def test_slice(self): - space = self.space - def f(i): step = 3 ar = SingleDimArray(step*i) @@ -111,8 +118,6 @@ assert result == f(5) def test_slice2(self): - space = self.space - def f(i): step1 = 2 step2 = 3 diff --git a/pypy/module/operator/app_operator.py b/pypy/module/operator/app_operator.py --- a/pypy/module/operator/app_operator.py +++ b/pypy/module/operator/app_operator.py @@ -4,6 +4,7 @@ This module exports a set of operators as functions. E.g. operator.add(x,y) is equivalent to x+y. ''' +from __pypy__ import builtinify def countOf(a,b): 'countOf(a, b) -- Return the number of times b occurs in a.' @@ -66,50 +67,56 @@ a[b:c] = d __setslice__ = setslice -class attrgetter(object): - def __init__(self, attr, *attrs): - self.attrs = (attr,) + attrs +def attrgetter(attr, *attrs): + if attrs: + getters = [single_attr_getter(a) for a in (attr,) + attrs] + def getter(obj): + return tuple([getter(obj) for getter in getters]) + else: + getter = single_attr_getter(attr) + return builtinify(getter) - def _resolve_attr(self, obj, attr): - last = 0 - while True: - try: - dot = attr.find(".", last) - except AttributeError: - raise TypeError - if dot > 0: - obj = getattr(obj, attr[last:dot]) - last = dot + 1 - else: - return getattr(obj, attr[last:]) +def single_attr_getter(attr): + if not isinstance(attr, str): + if not isinstance(attr, unicode): + def _raise_typeerror(obj): + raise TypeError("argument must be a string, not %r" % + (type(attr).__name__,)) + return _raise_typeerror + attr = attr.encode('ascii') + # + def make_getter(name, prevfn=None): + if prevfn is None: + def getter(obj): + return getattr(obj, name) + else: + def getter(obj): + return getattr(prevfn(obj), name) + return getter + # + last = 0 + getter = None + while True: + dot = attr.find(".", last) + if dot < 0: break + getter = make_getter(attr[last:dot], getter) + last = dot + 1 + return make_getter(attr[last:], getter) - def __call__(self, obj): - if len(self.attrs) == 1: - return self._resolve_attr(obj, self.attrs[0]) - return tuple(self._resolve_attr(obj, attr) for attr in self.attrs) -class itemgetter(object): +def itemgetter(item, *items): + if items: + list_of_indices = [item] + list(items) + def getter(obj): + return tuple([obj[i] for i in list_of_indices]) + else: + def getter(obj): + return obj[item] + return builtinify(getter) - def __init__(self, item, *args): - self.items = args - self.item = item - def __call__(self, obj): - result = obj[self.item] - - if self.items: - list = [result] + [obj[item] for item in self.items] - return tuple(list) - - return result - -class methodcaller(object): - - def __init__(self, method_name, *args, **kwargs): - self.method_name = method_name - self.args = args - self.kwargs = kwargs - - def __call__(self, obj): - return getattr(obj, self.method_name)(*self.args, **self.kwargs) +def methodcaller(method_name, *args, **kwargs): + def call(obj): + return getattr(obj, method_name)(*args, **kwargs) + return builtinify(call) diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -1484,7 +1484,7 @@ raise OperationError( moduledict.w_NotSupportedError, space.wrap("Variable_TypeByValue(): unhandled data type %s" % - (space.type(w_value).getname(space, '?'),))) + (space.type(w_value).getname(space),))) def newByInputTypeHandler(space, cursor, w_inputTypeHandler, w_value, numElements): w_var = space.call(w_inputTypeHandler, diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py --- a/pypy/module/pyexpat/__init__.py +++ b/pypy/module/pyexpat/__init__.py @@ -2,6 +2,22 @@ from pypy.interpreter.mixedmodule import MixedModule +class ErrorsModule(MixedModule): + "Definition of pyexpat.errors module." + + appleveldefs = { + } + + interpleveldefs = { + } + + def setup_after_space_initialization(self): + from pypy.module.pyexpat import interp_pyexpat + for name in interp_pyexpat.xml_error_list: + self.space.setattr(self, self.space.wrap(name), + interp_pyexpat.ErrorString(self.space, + getattr(interp_pyexpat, name))) + class Module(MixedModule): "Python wrapper for Expat parser." @@ -21,6 +37,10 @@ 'version_info': 'interp_pyexpat.get_expat_version_info(space)', } + submodules = { + 'errors': ErrorsModule, + } + for name in ['XML_PARAM_ENTITY_PARSING_NEVER', 'XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE', 'XML_PARAM_ENTITY_PARSING_ALWAYS']: diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -31,6 +31,48 @@ XML_Content_Ptr = lltype.Ptr(lltype.ForwardReference()) XML_Parser = rffi.COpaquePtr(typedef='XML_Parser') +xml_error_list = [ + "XML_ERROR_NO_MEMORY", + "XML_ERROR_SYNTAX", + "XML_ERROR_NO_ELEMENTS", + "XML_ERROR_INVALID_TOKEN", + "XML_ERROR_UNCLOSED_TOKEN", + "XML_ERROR_PARTIAL_CHAR", + "XML_ERROR_TAG_MISMATCH", + "XML_ERROR_DUPLICATE_ATTRIBUTE", + "XML_ERROR_JUNK_AFTER_DOC_ELEMENT", + "XML_ERROR_PARAM_ENTITY_REF", + "XML_ERROR_UNDEFINED_ENTITY", + "XML_ERROR_RECURSIVE_ENTITY_REF", + "XML_ERROR_ASYNC_ENTITY", + "XML_ERROR_BAD_CHAR_REF", + "XML_ERROR_BINARY_ENTITY_REF", + "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", + "XML_ERROR_MISPLACED_XML_PI", + "XML_ERROR_UNKNOWN_ENCODING", + "XML_ERROR_INCORRECT_ENCODING", + "XML_ERROR_UNCLOSED_CDATA_SECTION", + "XML_ERROR_EXTERNAL_ENTITY_HANDLING", + "XML_ERROR_NOT_STANDALONE", + "XML_ERROR_UNEXPECTED_STATE", + "XML_ERROR_ENTITY_DECLARED_IN_PE", + "XML_ERROR_FEATURE_REQUIRES_XML_DTD", + "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING", + # Added in Expat 1.95.7. + "XML_ERROR_UNBOUND_PREFIX", + # Added in Expat 1.95.8. + "XML_ERROR_UNDECLARING_PREFIX", + "XML_ERROR_INCOMPLETE_PE", + "XML_ERROR_XML_DECL", + "XML_ERROR_TEXT_DECL", + "XML_ERROR_PUBLICID", + "XML_ERROR_SUSPENDED", + "XML_ERROR_NOT_SUSPENDED", + "XML_ERROR_ABORTED", + "XML_ERROR_FINISHED", + "XML_ERROR_SUSPEND_PE", + ] + class CConfigure: _compilation_info_ = eci XML_Content = rffi_platform.Struct('XML_Content', [ @@ -56,6 +98,9 @@ XML_FALSE = rffi_platform.ConstantInteger('XML_FALSE') XML_TRUE = rffi_platform.ConstantInteger('XML_TRUE') + for name in xml_error_list: + locals()[name] = rffi_platform.ConstantInteger(name) + for k, v in rffi_platform.configure(CConfigure).items(): globals()[k] = v @@ -298,7 +343,8 @@ XML_GetErrorCode = expat_external( 'XML_GetErrorCode', [XML_Parser], rffi.INT) XML_ErrorString = expat_external( - 'XML_ErrorString', [rffi.INT], rffi.CCHARP) + 'XML_ErrorString', [rffi.INT], + rffi.CCHARP) XML_GetCurrentLineNumber = expat_external( 'XML_GetCurrentLineNumber', [XML_Parser], rffi.INT) XML_GetErrorLineNumber = XML_GetCurrentLineNumber @@ -691,7 +737,7 @@ elif space.is_true(space.isinstance(w_encoding, space.w_str)): encoding = space.str_w(w_encoding) else: - type_name = space.type(w_encoding).getname(space, '?') + type_name = space.type(w_encoding).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 1 must be string or None,' @@ -711,7 +757,7 @@ space.wrap('namespace_separator must be at most one character,' ' omitted, or None')) else: - type_name = space.type(w_namespace_separator).getname(space, '?') + type_name = space.type(w_namespace_separator).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 2 must be string or None,' diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py --- a/pypy/module/pyexpat/test/test_parser.py +++ b/pypy/module/pyexpat/test/test_parser.py @@ -38,7 +38,7 @@ parser = pyexpat.ParserCreate() raises(pyexpat.ExpatError, "parser.Parse(xml, True)") - def test_encoding(self): + def test_encoding_argument(self): import pyexpat for encoding_arg in (None, 'utf-8', 'iso-8859-1'): for namespace_arg in (None, '{'): @@ -68,7 +68,7 @@ assert p.buffer_size == 150 raises(TypeError, setattr, p, 'buffer_size', sys.maxint + 1) - def test_encoding(self): + def test_encoding_xml(self): # use one of the few encodings built-in in expat xml = "caf\xe9" import pyexpat @@ -120,3 +120,14 @@ return True p.ExternalEntityRefHandler = handler p.Parse(xml) + + def test_errors(self): + import types + import pyexpat + assert isinstance(pyexpat.errors, types.ModuleType) + # check a few random errors + assert pyexpat.errors.XML_ERROR_SYNTAX == 'syntax error' + assert (pyexpat.errors.XML_ERROR_INCORRECT_ENCODING == + 'encoding specified in XML declaration is incorrect') + assert (pyexpat.errors.XML_ERROR_XML_DECL == + 'XML declaration not well-formed') diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,6 +8,7 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'set_compile_hook': 'interp_jit.set_compile_hook', + 'DebugMergePoint': 'interp_resop.W_DebugMergePoint', } def setup_after_space_initialization(self): diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -17,10 +17,11 @@ from opcode import opmap from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant +from pypy.jit.metainterp.resoperation import rop +from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes PyFrame._virtualizable2_ = ['last_instr', 'pycode', - 'valuestackdepth', 'valuestack_w[*]', - 'fastlocals_w[*]', + 'valuestackdepth', 'locals_stack_w[*]', 'last_exception', 'lastblock', 'is_being_profiled', @@ -47,6 +48,16 @@ return (bytecode.co_flags & CO_GENERATOR) != 0 +def wrap_oplist(space, logops, operations): + list_w = [] + for op in operations: + if op.getopnum() == rop.DEBUG_MERGE_POINT: + list_w.append(space.wrap(debug_merge_point_from_boxes( + op.getarglist()))) + else: + list_w.append(space.wrap(logops.repr_of_resop(op))) + return list_w + class PyPyJitDriver(JitDriver): reds = ['frame', 'ec'] greens = ['next_instr', 'is_being_profiled', 'pycode'] @@ -62,8 +73,7 @@ return if space.is_true(cache.w_compile_hook): logops = logger._make_log_operations() - list_w = [space.wrap(logops.repr_of_resop(op)) - for op in operations] + list_w = wrap_oplist(space, logops, operations) pycode = cast_base_ptr_to_instance(PyCode, ll_pycode) cache.in_recursion = True try: @@ -85,8 +95,7 @@ return if space.is_true(cache.w_compile_hook): logops = logger._make_log_operations() - list_w = [space.wrap(logops.repr_of_resop(op)) - for op in operations] + list_w = wrap_oplist(space, logops, operations) cache.in_recursion = True try: space.call_function(cache.w_compile_hook, @@ -167,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/interp_resop.py @@ -0,0 +1,41 @@ + +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.gateway import unwrap_spec, interp2app +from pypy.interpreter.pycode import PyCode +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.annlowlevel import cast_base_ptr_to_instance +from pypy.rpython.lltypesystem.rclass import OBJECT + +class W_DebugMergePoint(Wrappable): + """ A class representing debug_merge_point JIT operation + """ + + def __init__(self, mp_no, offset, pycode): + self.mp_no = mp_no + self.offset = offset + self.pycode = pycode + + def descr_repr(self, space): + return space.wrap('DebugMergePoint()') + + at unwrap_spec(mp_no=int, offset=int, pycode=PyCode) +def new_debug_merge_point(space, w_tp, mp_no, offset, pycode): + return W_DebugMergePoint(mp_no, offset, pycode) + +def debug_merge_point_from_boxes(boxes): + mp_no = boxes[0].getint() + offset = boxes[2].getint() + llcode = lltype.cast_opaque_ptr(lltype.Ptr(OBJECT), + boxes[4].getref_base()) + pycode = cast_base_ptr_to_instance(PyCode, llcode) + assert pycode is not None + return W_DebugMergePoint(mp_no, offset, pycode) + +W_DebugMergePoint.typedef = TypeDef( + 'DebugMergePoint', + __new__ = interp2app(new_debug_merge_point), + __doc__ = W_DebugMergePoint.__doc__, + __repr__ = interp2app(W_DebugMergePoint.descr_repr), + code = interp_attrproperty('pycode', W_DebugMergePoint), +) diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,8 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof', '_weakref']: + 'posix', '_socket', '_sre', '_lsprof', '_weakref', + '__pypy__', 'cStringIO']: return True return False diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -8,12 +8,13 @@ from pypy.jit.metainterp.logger import Logger from pypy.rpython.annlowlevel import (cast_instance_to_base_ptr, cast_base_ptr_to_instance) +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.module.pypyjit.interp_jit import pypyjitdriver from pypy.jit.tool.oparser import parse from pypy.jit.metainterp.typesystem import llhelper class MockSD(object): - class cpu: + class cpu(object): ts = llhelper class AppTestJitHook(object): @@ -27,14 +28,17 @@ pass return f """) + cls.w_f = w_f ll_code = cast_instance_to_base_ptr(w_f.code) + code_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, ll_code) logger = Logger(MockSD()) oplist = parse(""" [i1, i2] i3 = int_add(i1, i2) + debug_merge_point(0, 0, 0, 0, ConstPtr(ptr0)) guard_true(i3) [] - """).operations + """, namespace={'ptr0': code_gcref}).operations def interp_on_compile(): pypyjitdriver.on_compile(logger, LoopToken(), oplist, 'loop', @@ -63,7 +67,7 @@ assert all[0][0][0].co_name == 'f' assert all[0][0][1] == 0 assert all[0][0][2] == False - assert len(all[0][1]) == 2 + assert len(all[0][1]) == 3 assert 'int_add' in all[0][1][0] self.on_compile_bridge() assert len(all) == 2 @@ -103,3 +107,20 @@ self.on_compile_bridge() assert len(l) == 2 # and did not crash + def test_on_compile_types(self): + import pypyjit + l = [] + + def hook(*args): + l.append(args) + + pypyjit.set_compile_hook(hook) + self.on_compile() + dmp = l[0][3][1] + assert isinstance(dmp, pypyjit.DebugMergePoint) + assert dmp.code is self.f.func_code + + def test_creation(self): + import pypyjit + dmp = pypyjit.DebugMergePoint(0, 0, self.f.func_code) + assert dmp.code is self.f.func_code diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,21 +9,42 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + def test_interface_residual_call(): space = gettestobjspace(usemodules=['pypyjit']) diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -2,6 +2,7 @@ import sys import re import os.path +from _pytest.assertion import newinterpret from pypy.tool.jitlogparser.parser import SimpleParser, Function, TraceForOpcode from pypy.tool.jitlogparser.storage import LoopStorage @@ -194,7 +195,7 @@ # transform self._assert(x, 'foo') into assert x, 'foo' source = source.replace('self._assert(', 'assert ') source = source[:-1] # remove the trailing ')' - self.msg = py.code._reinterpret(source, f, should_fail=True) + self.msg = newinterpret.interpret(source, f, should_fail=True) else: self.msg = "" diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -58,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -46,7 +46,7 @@ guard_no_overflow(descr=) i18 = int_add(i7, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) """) def test_array_intimg(self): @@ -83,7 +83,7 @@ setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) i28 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -11,21 +11,14 @@ return 1 + rec(n-1) # # this loop is traced and then aborted, because the trace is too - # long. But then "rec" is marked as "don't inline" - i = 0 - j = 0 - while i < 20: - i += 1 - j += rec(100) - # - # next time we try to trace "rec", instead of inlining we compile - # it separately and generate a call_assembler + # long. But then "rec" is marked as "don't inline". Since we + # already traced function from the start (because of number), + # now we can inline it as call assembler i = 0 j = 0 while i < 20: i += 1 j += rec(100) # ID: call_rec - a = 0 return j # log = self.run(fn, [], threshold=18) @@ -38,6 +31,20 @@ ... """) + def test_fib(self): + def fib(n): + if n == 0 or n == 1: + return 1 + return fib(n - 1) + fib(n - 2) # ID: call_rec + + log = self.run(fib, [7], function_threshold=15) + loop, = log.loops_by_filename(self.filepath, is_entry_bridge='*') + #assert loop.match_by_id('call_rec', ''' + #... + #p1 = call_assembler(..., descr=...) + #... + #''') + def test_simple_call(self): src = """ OFFSET = 0 @@ -59,13 +66,13 @@ ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value", - "getfield_gc", "guard_isnull", + "getfield_gc", "guard_value", "getfield_gc", "guard_nonnull_class"] # LOAD_GLOBAL of OFFSET but in different function partially folded # away # XXX could be improved ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_isnull"] + assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value"] # # two LOAD_GLOBAL of f, the second is folded away ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') @@ -180,7 +187,7 @@ guard_no_overflow(descr=) i18 = force_token() --TICK-- - jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) """) def test_default_and_kw(self): @@ -202,6 +209,26 @@ i16 = force_token() """) + def test_kwargs_empty(self): + def main(x): + def g(**args): + return len(args) + 1 + # + s = 0 + d = {} + i = 0 + while i < x: + s += g(**d) # ID: call + i += 1 + return s + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('call') + ops = log.opnames(loop.ops_by_id('call')) + guards = [ops for ops in ops if ops.startswith('guard')] + assert guards == ["guard_no_overflow"] + def test_kwargs(self): # this is not a very precise test, could be improved def main(x): @@ -209,20 +236,24 @@ return len(args) # s = 0 - d = {} - for i in range(x): + d = {"a": 1} + i = 0 + while i < x: s += g(**d) # ID: call d[str(i)] = i if i % 100 == 99: - d = {} + d = {"a": 1} + i += 1 return s # log = self.run(main, [1000]) - assert log.result == 49500 + assert log.result == 50500 loop, = log.loops_by_id('call') + print loop.ops_by_id('call') ops = log.opnames(loop.ops_by_id('call')) guards = [ops for ops in ops if ops.startswith('guard')] - assert len(guards) <= 5 + print guards + assert len(guards) <= 20 def test_stararg_virtual(self): def main(x): @@ -270,12 +301,12 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) def test_stararg(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -115,7 +115,6 @@ # ---------------------- loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i8 = getfield_gc_pure(p5, descr=) i9 = int_lt(i8, i7) guard_true(i9, descr=.*) guard_not_invalidated(descr=.*) @@ -125,7 +124,7 @@ p20 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p20, i11, descr=) setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i7, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py --- a/pypy/module/pypyjit/test_pypy_c/test_intbound.py +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -97,7 +97,7 @@ guard_no_overflow(descr=...) i17 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) """) def test_intbound_sub_lt(self): @@ -149,7 +149,7 @@ guard_no_overflow(descr=...) i19 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) """) def test_intbound_addmul_ge(self): @@ -177,7 +177,7 @@ guard_no_overflow(descr=...) i21 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) """) def test_intbound_eq(self): @@ -209,7 +209,7 @@ guard_no_overflow(descr=...) i16 = int_add(i8, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) """) def test_intbound_mul(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -167,7 +167,7 @@ guard_false(i16, descr=) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) + setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, 146982464, descr=) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) @@ -179,7 +179,7 @@ i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -0,0 +1,42 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestString(BaseTestPyPyC): + def test_lookup_default_encoding(self): + def main(n): + import string + i = 0 + letters = string.letters + uletters = unicode(string.letters) + while i < n: + i += letters[i % len(letters)] == uletters[i % len(letters)] + return i + + log = self.run(main, [300]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i14 = int_lt(i6, i9) + guard_true(i14, descr=) + i15 = int_mod(i6, i10) + i17 = int_rshift(i15, 63) + i18 = int_and(i10, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=) + i22 = int_ge(i19, i10) + guard_false(i22, descr=) + i23 = strgetitem(p11, i19) + i24 = int_ge(i19, i12) + guard_false(i24, descr=) + i25 = unicodegetitem(p13, i19) + guard_not_invalidated(descr=) + p27 = newstr(1) + strsetitem(p27, 0, i23) + p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) + guard_no_exception(descr=) + i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) + guard_true(i32, descr=) + i34 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) \ No newline at end of file diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -7,6 +7,8 @@ class Module(MixedModule): """Sys Builtin Module. """ + _immutable_fields_ = ["defaultencoding?"] + def __init__(self, space, w_name): """NOT_RPYTHON""" # because parent __init__ isn't if space.config.translating: diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py @@ -0,0 +1,82 @@ +# unittest for SOME ctypes com function calls. +# Can't resist from implementing some kind of mini-comtypes +# theller ;-) + +import py +import sys +if sys.platform != "win32": + py.test.skip('windows only test') + +import ctypes, new, unittest +from ctypes.wintypes import HRESULT +from _ctypes import COMError + +oleaut32 = ctypes.OleDLL("oleaut32") + +class UnboundMethod(object): + def __init__(self, func, index, name): + self.func = func + self.index = index + self.name = name + self.__doc__ = func.__doc__ + + def __repr__(self): + return "" % (self.index, self.name, id(self)) + + def __get__(self, instance, owner): + if instance is None: + return self + return new.instancemethod(self.func, instance, owner) + +def commethod(index, restype, *argtypes): + """A decorator that generates COM methods. The decorated function + itself is not used except for it's name.""" + def make_commethod(func): + comfunc = ctypes.WINFUNCTYPE(restype, *argtypes)(index, func.__name__) + comfunc.__name__ = func.__name__ + comfunc.__doc__ = func.__doc__ + return UnboundMethod(comfunc, index, func.__name__) + return make_commethod + +class ICreateTypeLib2(ctypes.c_void_p): + + @commethod(1, ctypes.c_long) + def AddRef(self): + pass + + @commethod(2, ctypes.c_long) + def Release(self): + pass + + @commethod(4, HRESULT, ctypes.c_wchar_p) + def SetName(self): + """Set the name of the library.""" + + @commethod(12, HRESULT) + def SaveAllChanges(self): + pass + + +CreateTypeLib2 = oleaut32.CreateTypeLib2 +CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, ctypes.POINTER(ICreateTypeLib2)) + +################################################################ + +def test_basic_comtypes(): + punk = ICreateTypeLib2() + hr = CreateTypeLib2(0, "foobar.tlb", punk) + assert hr == 0 + + assert 2 == punk.AddRef() + assert 3 == punk.AddRef() + assert 4 == punk.AddRef() + + punk.SetName("TypeLib_ByPYPY") + py.test.raises(COMError, lambda: punk.SetName(None)) + + # This would save the typelib to disk. + ## punk.SaveAllChanges() + + assert 3 == punk.Release() + assert 2 == punk.Release() + assert 1 == punk.Release() diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -384,8 +384,9 @@ # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) - stack_items_w = self.crnt_frame.valuestack_w - for i in range(self.crnt_frame.valuestackdepth-1, -1, -1): + f = self.crnt_frame + stack_items_w = f.locals_stack_w + for i in range(f.valuestackdepth-1, f.nlocals-1, -1): w_v = stack_items_w[i] if isinstance(w_v, Constant): if w_v.value is oldvalue: diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py --- a/pypy/objspace/flow/framestate.py +++ b/pypy/objspace/flow/framestate.py @@ -10,7 +10,7 @@ def __init__(self, state): if isinstance(state, PyFrame): # getfastscope() can return real None, for undefined locals - data = state.getfastscope() + state.savevaluestack() + data = state.save_locals_stack() if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -36,11 +36,9 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): - fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) # Nones == undefined locals - frame.restorevaluestack(data[fastlocals:-2]) + frame.restore_locals_stack(data[:-2]) # Nones == undefined locals if data[-2] == Constant(None): assert data[-1] == Constant(None) frame.last_exception = None diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py --- a/pypy/objspace/flow/test/test_framestate.py +++ b/pypy/objspace/flow/test/test_framestate.py @@ -25,7 +25,7 @@ dummy = Constant(None) #dummy.dummy = True arg_list = ([Variable() for i in range(formalargcount)] + - [dummy] * (len(frame.fastlocals_w) - formalargcount)) + [dummy] * (frame.nlocals - formalargcount)) frame.setfastscope(arg_list) return frame @@ -42,7 +42,7 @@ def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1 != fs2 @@ -55,7 +55,7 @@ def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general @@ -63,7 +63,7 @@ def test_restore_frame(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs1.restoreframe(frame) assert fs1 == FrameState(frame) @@ -82,25 +82,26 @@ def test_getoutputargs(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable - # fastlocals_w[-1] -> fastlocals_w[-1] is Constant(None) - assert outputargs == [frame.fastlocals_w[0], Constant(None)] + # locals_w[n-1] -> locals_w[n-1] is Constant(None) + assert outputargs == [frame.locals_stack_w[0], Constant(None)] def test_union_different_constants(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(42) + frame.locals_stack_w[frame.nlocals-1] = Constant(42) fs2 = FrameState(frame) fs3 = fs1.union(fs2) fs3.restoreframe(frame) - assert isinstance(frame.fastlocals_w[-1], Variable) # generalized + assert isinstance(frame.locals_stack_w[frame.nlocals-1], Variable) + # ^^^ generalized def test_union_spectag(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(SpecTag()) + frame.locals_stack_w[frame.nlocals-1] = Constant(SpecTag()) fs2 = FrameState(frame) assert fs1.union(fs2) is None # UnionError diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + w_dict = jit.promote(w_dict) + self = jit.promote(self) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + @jit.elidable + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,91 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,18 +1,20 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS -from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize +from pypy.rlib.debug import mark_dict_non_null + +from pypy.rlib import rerased def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -28,48 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -88,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -140,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -149,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -159,106 +140,90 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + self.switch_to_object_strategy(w_dict) - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_length(self): - return len(self.r_dict_content) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError + def length(self, w_dict): + return 0 -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) + def clear(self, w_dict): + return -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -300,319 +265,255 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = {} +class AbstractTypedStrategy(object): + _mixin_ = True - def impl_setitem(self, w_key, w_value): + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, key, w_value): - self.content[key] = w_value + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] return - elif _is_sane_hash(space, w_key_type): - raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) - def impl_length(self): - return len(self.content) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) - def impl_getitem_str(self, key): - return self.content.get(key, None) + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return ObjectIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + + def setitem_str(self, w_dict, key, w_value): + assert key is not None + self.unerase(w_dict.dstorage)[key] = w_value + + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().impl_fallback_getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) - def impl_delitem(self, w_key): + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) + return space.is_w(space.type(w_obj), space.w_int) - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) -class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): +class IntIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - + return None, None init_signature = Signature(['seq_or_map'], None, 'kwargs') @@ -919,7 +820,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,121 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): @@ -311,6 +311,10 @@ classofinstance=classofinstance, strdict=strdict) + def newset(self): + from pypy.objspace.std.setobject import newset + return W_SetObject(self, newset(self)) + def newslice(self, w_start, w_end, w_step): return W_SliceObject(w_start, w_end, w_step) @@ -318,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) @@ -29,3 +38,33 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -137,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -176,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -195,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -233,8 +234,33 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2: 2, "c": 3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l + def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -267,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -297,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -316,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -366,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} @@ -527,6 +549,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +734,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +749,64 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -759,6 +847,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj @@ -790,6 +882,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +895,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +927,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1012,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1027,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1071,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1083,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1104,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,20 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) + + def test_slot_name_conflict(self): class A(object): @@ -604,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -50,6 +50,10 @@ u = self.space.wrap(set('simsalabim')) assert self.space.eq_w(s,u) + def test_space_newset(self): + s = self.space.newset() + assert self.space.str_w(self.space.repr(s)) == 'set([])' + class AppTestAppSetTest: def test_subtype(self): class subset(set):pass diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: @@ -447,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/pytest.ini b/pypy/pytest.ini new file mode 100644 --- /dev/null +++ b/pypy/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --assertmode=old \ No newline at end of file diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py --- a/pypy/rlib/clibffi.py +++ b/pypy/rlib/clibffi.py @@ -10,6 +10,7 @@ from pypy.rlib.rmmap import alloc from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal from pypy.rlib.rdynload import DLOpenError, DLLHANDLE +from pypy.rlib import jit from pypy.tool.autopath import pypydir from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform @@ -270,6 +271,7 @@ elif _MSVC: get_libc_handle = external('pypy_get_libc_handle', [], DLLHANDLE) + @jit.dont_look_inside def get_libc_name(): return rwin32.GetModuleFileName(get_libc_handle()) diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec @@ -273,15 +288,17 @@ class JitHintError(Exception): """Inconsistency in the JIT hints.""" -PARAMETERS = {'threshold': 1000, +PARAMETERS = {'threshold': 1032, # just above 1024 + 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -336,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -574,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -591,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -74,7 +74,7 @@ raise KeyError @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) @@ -253,7 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -272,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -151,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -206,7 +215,7 @@ if dictobj is None: return lltype.nullptr(self.DICT) if not isinstance(dictobj, (dict, objectmodel.r_dict)): - raise TyperError("expected a dict: %r" % (dictobj,)) + raise TypeError("expected a dict: %r" % (dictobj,)) try: key = Constant(dictobj) return self.dict_cache[key] @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) @@ -833,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -845,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py --- a/pypy/rpython/lltypesystem/rlist.py +++ b/pypy/rpython/lltypesystem/rlist.py @@ -250,12 +250,11 @@ length = l.length l.length = length + 1 l.ll_setitem_fast(length, newitem) -ll_append_noresize.oopspec = 'list.append(l, newitem)' def ll_both_none(lst1, lst2): return not lst1 and not lst2 - + # ____________________________________________________________ # diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -57,6 +57,8 @@ llmemory.itemoffsetof(TP.chars, 0) + llmemory.sizeof(CHAR_TP) * item) + # It'd be nice to be able to look inside this function. + @dont_look_inside @enforceargs(None, None, int, int, int) def copy_string_contents(src, dst, srcstart, dststart, length): assert srcstart >= 0 @@ -142,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -157,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -256,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -278,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -323,6 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -334,12 +337,11 @@ x = 29872897 s.hash = x return x - ll_strhash._pure_function_ = True # it's pure but it does not look like it def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -349,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -367,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -384,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -425,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -448,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -468,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -484,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -501,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -513,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -524,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -592,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -715,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -813,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -828,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -839,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,23 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + class Cls(self.AddressStack): + def append(self2, addr): + assert addr not in self2.tolist() + self.AddressStack.append(self2, addr) + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +637,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +655,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +698,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +789,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +882,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +922,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,11 +933,11 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded self.remember_young_pointer_from_array2(addr_array, index) else: @@ -943,20 +955,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -980,16 +995,18 @@ # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,9 +1019,7 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return @@ -1016,7 +1031,7 @@ addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True @@ -1026,9 +1041,6 @@ # xxx trying it out for the JIT: a 3-arguments version of the above def remember_young_pointer_from_array3(addr_array, index, newvalue): - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") objhdr = self.header(addr_array) # # a single check for the common case of neither GCFLAG_HAS_CARDS @@ -1044,8 +1056,8 @@ else: # case with cards. # - # If the newly written address does not actually point to the - # nursery, leave now. + # If the newly written address does not actually point to a + # young object, leave now. if not self.appears_to_be_young(newvalue): return # @@ -1056,46 +1068,53 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + \ - (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True assert self.card_page_indices > 0 self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1103,15 +1122,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1119,6 +1159,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1135,20 +1191,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1181,7 +1245,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1189,7 +1253,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1205,11 +1269,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1245,19 +1309,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1296,7 +1371,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1343,11 +1430,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,78 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag + # + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert not res # there might be young ptrs, let ll_arraycopy to find them + + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -317,7 +317,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -886,7 +887,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/ootypesystem/test/test_oopbc.py b/pypy/rpython/ootypesystem/test/test_oopbc.py --- a/pypy/rpython/ootypesystem/test/test_oopbc.py +++ b/pypy/rpython/ootypesystem/test/test_oopbc.py @@ -81,3 +81,18 @@ res = interpret(f, [1], type_system='ootype') assert res == 2 +def test_quasi_immutable(): + class A(object): + _immutable_fields_ = ['x?'] + def __init__(self): + self.x = 3 + def foo(self): + return self.x + + a = A() + + def f(): + return a.foo() + + res = interpret(f, [], type_system='ootype') + assert res == 3 diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,29 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): @@ -860,6 +883,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -98,7 +98,7 @@ def __init__(self, operations, storage): if operations[0].name == 'debug_merge_point': self.inline_level = int(operations[0].args[0]) - m = re.search('\w]+), file \'(.+?)\', line (\d+)> #(\d+) (\w+)', + m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', operations[0].getarg(1)) if m is None: # a non-code loop, like StrLiteralSearch or something @@ -121,6 +121,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -220,6 +223,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -38,10 +38,10 @@ def test_split(): ops = parse(''' [i0] - debug_merge_point(0, " #10 ADD") - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -54,12 +54,12 @@ def test_inlined_call(): ops = parse(""" [] - debug_merge_point(0, ' #28 CALL_FUNCTION') + debug_merge_point(0, ' #28 CALL_FUNCTION') i18 = getfield_gc(p0, descr=) - debug_merge_point(1, ' #0 LOAD_FAST') - debug_merge_point(1, ' #3 LOAD_CONST') - debug_merge_point(1, ' #7 RETURN_VALUE') - debug_merge_point(0, ' #31 STORE_FAST') + debug_merge_point(1, ' #0 LOAD_FAST') + debug_merge_point(1, ' #3 LOAD_CONST') + debug_merge_point(1, ' #7 RETURN_VALUE') + debug_merge_point(0, ' #31 STORE_FAST') """) res = Function.from_operations(ops.operations, LoopStorage()) assert len(res.chunks) == 3 # two chunks + inlined call @@ -72,10 +72,10 @@ def test_name(): ops = parse(''' [i0] - debug_merge_point(0, " #10 ADD") - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -89,10 +89,10 @@ ops = parse(''' [i0] i3 = int_add(i0, 1) - debug_merge_point(0, " #10 ADD") - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(0, " #11 SUB") + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -102,10 +102,10 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(0, " #0 LOAD_FAST") - debug_merge_point(0, " #3 LOAD_FAST") - debug_merge_point(0, " #6 BINARY_ADD") - debug_merge_point(0, " #7 RETURN_VALUE") + debug_merge_point(0, " #0 LOAD_FAST") + debug_merge_point(0, " #3 LOAD_FAST") + debug_merge_point(0, " #6 BINARY_ADD") + debug_merge_point(0, " #7 RETURN_VALUE") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.chunks[1].lineno == 3 @@ -114,11 +114,11 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(0, " #9 LOAD_FAST") - debug_merge_point(0, " #12 LOAD_CONST") - debug_merge_point(0, " #22 LOAD_CONST") - debug_merge_point(0, " #28 LOAD_CONST") - debug_merge_point(0, " #6 SETUP_LOOP") + debug_merge_point(0, " #9 LOAD_FAST") + debug_merge_point(0, " #12 LOAD_CONST") + debug_merge_point(0, " #22 LOAD_CONST") + debug_merge_point(0, " #28 LOAD_CONST") + debug_merge_point(0, " #6 SETUP_LOOP") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.linerange == (7, 9) @@ -128,7 +128,7 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] - debug_merge_point(0, ' #17 FOR_ITER') + debug_merge_point(0, ' #17 FOR_ITER') guard_class(p6, 144264192, descr=) p12 = getfield_gc(p6, descr=) """ % locals()) @@ -168,7 +168,7 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -1,8 +1,13 @@ import autopath import py -from pypy.interpreter import gateway +from pypy.interpreter import gateway, pycode from pypy.interpreter.error import OperationError +try: + from _pytest.assertion.newinterpret import interpret +except ImportError: + from _pytest.assertion.oldinterpret import interpret + # ____________________________________________________________ class AppCode(object): @@ -51,13 +56,11 @@ space = self.space for key, w_value in vars.items(): space.setitem(self.w_locals, space.wrap(key), w_value) - return space.eval(code, self.w_globals, self.w_locals) - - def exec_(self, code, **vars): - space = self.space - for key, w_value in vars.items(): - space.setitem(self.w_locals, space.wrap(key), w_value) - space.exec_(code, self.w_globals, self.w_locals) + if isinstance(code, str): + return space.eval(code, self.w_globals, self.w_locals) + pyc = pycode.PyCode._from_code(space, code) + return pyc.exec_host_bytecode(self.w_globals, self.w_locals) + exec_ = eval def repr(self, w_value): return self.space.unwrap(self.space.repr(w_value)) @@ -80,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: @@ -163,8 +166,8 @@ except py.error.ENOENT: source = None from pypy import conftest - if source and not py.test.config.option.nomagic: - msg = py.code._reinterpret_old(source, runner, should_fail=True) + if source and py.test.config._assertstate.mode != "off": + msg = interpret(source, runner, should_fail=True) space.setattr(w_self, space.wrap('args'), space.newtuple([space.wrap(msg)])) w_msg = space.wrap(msg) diff --git a/pypy/tool/pytest/test/test_pytestsupport.py b/pypy/tool/pytest/test/test_pytestsupport.py --- a/pypy/tool/pytest/test/test_pytestsupport.py +++ b/pypy/tool/pytest/test/test_pytestsupport.py @@ -4,7 +4,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.pyframe import PyFrame from pypy.tool.pytest.appsupport import (AppFrame, build_pytest_assertion, - AppExceptionInfo) + AppExceptionInfo, interpret) import py from pypy.tool.udir import udir import os @@ -22,8 +22,8 @@ co = PyCode._from_code(space, somefunc.func_code) pyframe = PyFrame(space, co, space.newdict(), None) runner = AppFrame(space, pyframe) - py.code._reinterpret_old("f = lambda x: x+1", runner, should_fail=False) - msg = py.code._reinterpret_old("assert isinstance(f(2), float)", runner) + interpret("f = lambda x: x+1", runner, should_fail=False) + msg = interpret("assert isinstance(f(2), float)", runner) assert msg.startswith("assert isinstance(3, float)\n" " + where 3 = ") @@ -58,6 +58,12 @@ except AssertionError, e: assert e.msg == "Failed" +def app_test_comparison(): + try: + assert 3 > 4 + except AssertionError, e: + assert "3 > 4" in e.msg + def test_appexecinfo(space): try: diff --git a/pypy/translator/c/gcc/test/msvc/track_and_esp.s b/pypy/translator/c/gcc/test/msvc/track_and_esp.s --- a/pypy/translator/c/gcc/test/msvc/track_and_esp.s +++ b/pypy/translator/c/gcc/test/msvc/track_and_esp.s @@ -153,6 +153,7 @@ push OFFSET _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC $block12$88259: call _pypy_g_SemiSpaceGC_obtain_free_space + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } ; 58362: l_v21669 = (&pypy_g_ExcData)->ed_exc_type; ; 58363: l_v21670 = (l_v21669 == NULL); @@ -225,6 +226,7 @@ push 1 $block14$88247: call _pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } mov esi, eax ; 58377: OP_TRACK_ALLOC_START(l_v21672, /* nothing */); @@ -232,6 +234,7 @@ push OFFSET ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ push esi call _pypy_debug_alloc_start + ;; expected {4(%ebp) | 28(%esp), 24(%esp), 20(%esp), (%ebp) | } add esp, 20 ; 00000014H ; 58378: l_exp_p_0 = (long *)l_v21672; @@ -283,6 +286,7 @@ sub esp, 8 fstp QWORD PTR [esp] call _pypy_g_frexp__Float_arrayPtr_star_2 + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } ; 58387: l_v21675 = (&pypy_g_ExcData)->ed_exc_type; ; 58388: l_v21676 = (l_v21675 == NULL); @@ -331,11 +335,13 @@ mov DWORD PTR _pypy_g_ExcData+4, eax mov DWORD PTR _pypy_g_ExcData, eax call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } ; 58413: OP_RAW_FREE(l_v21688, /* nothing */); push esi call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } ; 58414: l_v21691 = (struct pypy_object0 *)l_v21687; ; 58415: pypy_g_RPyReRaiseException(l_v21683, l_v21691); @@ -376,11 +382,13 @@ push esi call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } ; 58399: OP_RAW_FREE(l_v21679, /* nothing */); push esi call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } ; 58400: l_v21637 = l_v21678; ; 58401: l_v21638 = l_mantissa_0; diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -527,8 +527,9 @@ target = match.group("target") if target == self.ESP: # only for andl $-16, %esp used to align the stack in main(). - # main() should not be seen at all. - raise AssertionError("instruction unexpected outside of main()") + # main() should not be seen at all. But on e.g. MSVC we see + # the instruction somewhere else too... + return InsnCannotFollowEsp() else: return self.binary_insn(line) @@ -1176,7 +1177,7 @@ r_gcroot_marker = re.compile(r"$1") # never matches r_gcroot_marker_var = re.compile(r"DWORD PTR .+_constant_always_one_.+pypy_asm_gcroot") r_gcnocollect_marker = re.compile(r"\spypy_asm_gc_nocollect\(("+OPERAND+")\);") - r_bottom_marker = re.compile(r"; .+\tpypy_asm_stack_bottom\(\);") + r_bottom_marker = re.compile(r"; .+\spypy_asm_stack_bottom\(\);") FUNCTIONS_NOT_RETURNING = { '__exit': None, diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -570,7 +570,10 @@ mk.definition('ASMFILES', sfiles) mk.definition('ASMLBLFILES', lblsfiles) mk.definition('GCMAPFILES', gcmapfiles) - mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') if self.config.translation.shared: mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup") @@ -623,7 +626,10 @@ mk.rule('.PRECIOUS', '%.s', "# don't remove .s files if Ctrl-C'ed") else: - mk.definition('DEBUGFLAGS', '-O1 -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O1 -g') mk.write() #self.translator.platform, # , diff --git a/pypy/translator/c/node.py b/pypy/translator/c/node.py --- a/pypy/translator/c/node.py +++ b/pypy/translator/c/node.py @@ -1031,7 +1031,7 @@ if (issubclass(value, BaseException) and value.__module__ == 'exceptions'): return 'PyExc_' + value.__name__ - if value is py.code._AssertionError: + if issubclass(value, AssertionError): return 'PyExc_AssertionError' if value is _StackOverflow: return 'PyExc_RuntimeError' diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h --- a/pypy/translator/c/src/main.h +++ b/pypy/translator/c/src/main.h @@ -79,6 +79,7 @@ fprintf(stderr, "Fatal error during initialization: %s\n", errmsg); #endif abort(); + return 1; } int PYPY_MAIN_FUNCTION(int argc, char *argv[]) diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -1117,6 +1117,7 @@ S = lltype.GcStruct('S', ('u', lltype.Ptr(U))) A = lltype.GcArray(lltype.Ptr(S)) filename = self.filename_dump_typeids_z + open_flags = os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0) def fn(): s = lltype.malloc(S) @@ -1128,7 +1129,7 @@ # p = rgc.get_typeids_z() s = ''.join([p[i] for i in range(len(p))]) - fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0666) + fd = os.open(filename, open_flags, 0666) os.write(fd, s) os.close(fd) return 0 @@ -1137,7 +1138,7 @@ def test_write_typeids_z(self): self.run("write_typeids_z") - f = open(self.filename_dump_typeids_z) + f = open(self.filename_dump_typeids_z, 'rb') data_z = f.read() f.close() import zlib diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -103,6 +103,8 @@ specname = os.path.splitext(os.path.basename(targetspec))[0] sys.path.insert(0, os.path.dirname(targetspec)) mod = __import__(specname) + if 'target' not in mod.__dict__: + raise Exception("file %r is not a valid targetxxx.py." % (targetspec,)) return mod.__dict__ def parse_options_and_load_target(): @@ -184,7 +186,7 @@ print "\n\nTarget specific help:\n\n" targetspec_dic['print_help'](config) print "\n\nFor detailed descriptions of the command line options see" - print "http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html" + print "http://pypy.readthedocs.org/en/latest/config/commandline.html" sys.exit(0) return targetspec_dic, translateconfig, config, args diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,12 +964,15 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" diff --git a/pypy/translator/platform/darwin.py b/pypy/translator/platform/darwin.py --- a/pypy/translator/platform/darwin.py +++ b/pypy/translator/platform/darwin.py @@ -68,12 +68,10 @@ class Darwin_i386(Darwin): name = "darwin_i386" - link_flags = ('-arch', 'i386', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'i386') + cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer') class Darwin_x86_64(Darwin): name = "darwin_x86_64" - link_flags = ('-arch', 'x86_64', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'x86_64') + cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer') diff --git a/pytest.py b/pytest.py old mode 100644 new mode 100755 --- a/pytest.py +++ b/pytest.py @@ -1,7 +1,6 @@ +#!/usr/bin/env python """ unit and functional testing with Python. -(pypy version of startup script) -see http://pytest.org for details. """ __all__ = ['main'] @@ -9,23 +8,6 @@ from _pytest import core as cmdline from _pytest import __version__ -# This pytest.py script is located in the pypy source tree -# which has a copy of pytest and py within its source tree. -# If the environment also has an installed version of pytest/py -# we are bound to get warnings so we disable them. -# XXX eventually pytest and py should not be inlined shipped -# with the pypy source code but become a requirement for installation. - -import warnings -warnings.filterwarnings("ignore", - "Module py was already imported", category=UserWarning) -warnings.filterwarnings("ignore", - "Module _pytest was already imported", - category=UserWarning) -warnings.filterwarnings("ignore", - "Module pytest was already imported", - category=UserWarning) - if __name__ == '__main__': # if run as a script or by 'python -m pytest' raise SystemExit(main()) else: From noreply at buildbot.pypy.org Wed Jul 6 20:28:59 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:28:59 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Multithread safety. Message-ID: <20110706182859.61013820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45391:062824c571a9 Date: 2011-07-06 16:31 +0200 http://bitbucket.org/pypy/pypy/changeset/062824c571a9/ Log: Multithread safety. diff --git a/pypy/module/tealet/interp_tealet.py b/pypy/module/tealet/interp_tealet.py --- a/pypy/module/tealet/interp_tealet.py +++ b/pypy/module/tealet/interp_tealet.py @@ -20,6 +20,13 @@ w_exception = space.call_function(w_exception_class, space.wrap(error.msg)) return OperationError(w_exception_class, w_exception) +def check(space, main, funcname): + if main is None: + raise TealetError("%s to a non-started-yet tealet" % funcname) + assert isinstance(main, W_MainTealet) + if main.execution_context is not space.get_execution_context(): + raise TealetError("%s in a different thread" % funcname) + # ____________________________________________________________ def W_Tealet_run(self): @@ -35,10 +42,12 @@ def W_Tealet_switch(space, w_self): self = space.interp_w(W_Tealet, w_self) try: + check(space, self.main, "switch()") self.switch() except TealetError, e: raise wrap_error(space, e) +W_Tealet.main = None W_Tealet.run = W_Tealet_run W_Tealet.typedef = TypeDef( 'Tealet', @@ -53,12 +62,14 @@ r = space.allocate_instance(W_MainTealet, w_subtype) r.__init__() r.space = space + r.execution_context = space.get_execution_context() return space.wrap(r) def W_MainTealet_start(space, w_self, w_tealet): self = space.interp_w(W_MainTealet, w_self) tealet = space.interp_w(W_Tealet, w_tealet) try: + check(space, self, "start()") self.start(tealet) except TealetError, e: raise wrap_error(space, e) diff --git a/pypy/rlib/rtealet.py b/pypy/rlib/rtealet.py --- a/pypy/rlib/rtealet.py +++ b/pypy/rlib/rtealet.py @@ -61,8 +61,6 @@ switcher = Switcher() def _new(main, starting_tealet): - #if main.ll_stack_base != _getstackbase(): - # raise TealetError("starting a new tealet in the wrong thread") switcher.current = main.current switcher.target = starting_tealet llmain = main.lltealet @@ -107,8 +105,6 @@ return llresult def _switch(target): - #if target.main.ll_stack_base != _getstackbase(): - # raise TealetError("cannot switch to a tealet in a different thread") main = target.main switcher.current = main.current switcher.target = target From noreply at buildbot.pypy.org Wed Jul 6 20:29:00 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:29:00 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Make the --tealet and the --withmod-tealet options equivalent. Message-ID: <20110706182900.CB169820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45392:aacfe8d3f7af Date: 2011-07-06 16:31 +0200 http://bitbucket.org/pypy/pypy/changeset/aacfe8d3f7af/ Log: Make the --tealet and the --withmod-tealet options equivalent. diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py --- a/pypy/translator/goal/targetpypystandalone.py +++ b/pypy/translator/goal/targetpypystandalone.py @@ -182,6 +182,10 @@ raise ConflictConfigError("please use the --stackless option " "to translate.py instead of " "--withmod-_stackless directly") + if config.translation.tealet: + config.objspace.usemodules.tealet = True + elif config.objspace.usemodules.tealet: + config.translation.tealet = True if not config.translation.rweakref: config.objspace.usemodules._weakref = False From noreply at buildbot.pypy.org Wed Jul 6 20:29:02 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:29:02 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Fixes. Message-ID: <20110706182902.094FD820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45393:eca11e837d77 Date: 2011-07-06 19:14 +0200 http://bitbucket.org/pypy/pypy/changeset/eca11e837d77/ Log: Fixes. diff --git a/pypy/module/tealet/interp_tealet.py b/pypy/module/tealet/interp_tealet.py --- a/pypy/module/tealet/interp_tealet.py +++ b/pypy/module/tealet/interp_tealet.py @@ -24,7 +24,7 @@ if main is None: raise TealetError("%s to a non-started-yet tealet" % funcname) assert isinstance(main, W_MainTealet) - if main.execution_context is not space.get_execution_context(): + if main.executioncontext is not space.getexecutioncontext(): raise TealetError("%s in a different thread" % funcname) # ____________________________________________________________ @@ -62,7 +62,7 @@ r = space.allocate_instance(W_MainTealet, w_subtype) r.__init__() r.space = space - r.execution_context = space.get_execution_context() + r.executioncontext = space.getexecutioncontext() return space.wrap(r) def W_MainTealet_start(space, w_self, w_tealet): diff --git a/pypy/rlib/rtealet.py b/pypy/rlib/rtealet.py --- a/pypy/rlib/rtealet.py +++ b/pypy/rlib/rtealet.py @@ -52,7 +52,8 @@ ## ------------------------------------------------------------ ## The code below is implementation details. -## XXX No support for multithreading so far! +## No support for multithreading! The caller is responsible for not +## mixing threads. class Switcher(object): current = None From noreply at buildbot.pypy.org Wed Jul 6 20:29:03 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:29:03 +0200 (CEST) Subject: [pypy-commit] pypy tealet: A full implementation of greenlets on top of tealets. Message-ID: <20110706182903.41C9E820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45394:c60a5d4e0d19 Date: 2011-07-06 19:14 +0200 http://bitbucket.org/pypy/pypy/changeset/c60a5d4e0d19/ Log: A full implementation of greenlets on top of tealets. diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -1,1 +1,171 @@ -from _stackless import greenlet +import tealet, sys + +# ____________________________________________________________ +# Exceptions + +class GreenletExit(Exception): + """This special exception does not propagate to the parent greenlet; it +can be used to kill a single greenlet.""" + +error = tealet.error + +# ____________________________________________________________ +# Helper function + +def getcurrent(): + "Returns the current greenlet (i.e. the one which called this function)." + try: + return _tls.current + except AttributeError: + # first call in this thread: current == main + _green_create_main() + return _tls.current + +# ____________________________________________________________ +# The 'greenlet' class + +class greenlet(object): + getcurrent = staticmethod(getcurrent) + error = error + GreenletExit = GreenletExit + + def __new__(cls, *args, **kwds): + self = super(greenlet, cls).__new__(cls, *args, **kwds) + self.__parent = getcurrent() + return self + + def __init__(self, run=None, parent=None): + if run is not None: + self.run = run + if parent is not None: + self.parent = parent + + def switch(self, *args): + "switch execution to greenlet optionally passing a value, " + "return value passed when switching back" + _tls.passaround = args + oldcurrent = _tls.current + target = self + while True: + if target.__state_active(): + target.__tealet.switch() + break + if not target.__state_started(): + g = _GreenTealet() + g.greenlet = target + _tls.maintealet.start(g) + break + target = target.__parent + # + _tls.current = oldcurrent + res = _tls.passaround + _tls.passaround = None + if _tls.passaround_exception is not None: + typ, val, tb = _tls.passaround_exception + _tls.passaround_exception = None + raise typ, val, tb + if len(res) == 1: + res = res[0] + return res + + def throw(self, typ=GreenletExit, val=None, tb=None): + "raise exception in greenlet, return value passed when switching back" + if self.__is_dead(): + # dead greenlet: turn GreenletExit into a regular return + if (isinstance(typ, type(GreenletExit)) and + issubclass(typ, GreenletExit)): + if val is None: + return self.switch(typ()) + if isinstance(val, GreenletExit): + return self.switch(val) + if isinstance(typ, GreenletExit): + return self.switch(typ) + # + _tls.passaround_exception = (typ, val, tb) + return self.switch() + + def __state_started(self): + return hasattr(self, '_greenlet__tealet') + + def __state_active(self): + return getattr(self, '_greenlet__tealet', None) is not None + + def __nonzero__(self): + return self.__state_active() + + def __get_parent(self): + return self.__parent + + def __set_parent(self, nparent): + if not isinstance(nparent, greenlet): + raise TypeError("parent must be a greenlet") + p = nparent + while p is not None: + if p is self: + raise ValueError("cyclic parent chain") + p = p.__parent + self.__parent = nparent + + def __get_gr_frame(self): + raise NotImplementedError("attribute 'gr_frame' of greenlet objects") + + def __is_dead(self): + return self.__state_started() and not self.__state_active() + + parent = property(__get_parent, __set_parent) + gr_frame = property(__get_gr_frame) + dead = property(__is_dead) + +# ____________________________________________________________ +# Internal stuff + +try: + from thread import _local +except ImportError: + class _local(object): # assume no threads + pass + +_tls = _local() + +def _green_create_main(): + # create the main greenlet for this thread + _tls.maintealet = tealet.MainTealet() + _tls.current = None + _tls.passaround_exception = None + gmain = greenlet() + gmain._greenlet__tealet = _tls.maintealet + _tls.current = gmain + +class _GreenTealet(tealet.Tealet): + def run(self): + while True: + g = self.greenlet + g._greenlet__tealet = self + try: + try: + _tls.current = g + args = _tls.passaround + _tls.passaround = None + if _tls.passaround_exception is not None: + typ, val, tb = _tls.passaround_exception + _tls.passaround_exception = None + raise typ, val, tb + res = self.greenlet.run(*args) + except GreenletExit, res: + pass + except: + _tls.passaround_exception = sys.exc_info() + res = None + finally: + g._greenlet__tealet = None + _tls.passaround = (res,) + parent = g._greenlet__parent + while True: + if parent._greenlet__state_active(): + return parent._greenlet__tealet + if parent._greenlet__state_started(): + parent = parent._greenlet__parent # dead, try the parent + else: + # not started yet. Start it now. + self.greenlet = parent + break From noreply at buildbot.pypy.org Wed Jul 6 20:29:04 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 6 Jul 2011 20:29:04 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Fix on 64-bit. Message-ID: <20110706182904.77789820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45395:d2e14ca5f78b Date: 2011-07-06 19:55 +0200 http://bitbucket.org/pypy/pypy/changeset/d2e14ca5f78b/ Log: Fix on 64-bit. diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -356,6 +356,7 @@ # frame is initially set to a non-negative value x, but it is # occasionally turned into (~x) in case of forcing. + SIGNEDARRAYPTR = rffi.CArrayPtr(lltype.Signed) INTARRAYPTR = rffi.CArrayPtr(rffi.INT) CALLSHAPES_ARRAY = rffi.CArray(INTARRAYPTR) @@ -365,11 +366,11 @@ self.force_index_ofs = gcdescr.force_index_ofs def add_jit2gc_hooks(self, jit2gc): - INTARRAYPTR = self.INTARRAYPTR + SIGNEDARRAYPTR = self.SIGNEDARRAYPTR def read(addr): - return rffi.cast(INTARRAYPTR, addr)[0] + return rffi.cast(SIGNEDARRAYPTR, addr)[0] def write(addr, newvalue): - rffi.cast(INTARRAYPTR, addr)[0] = newvalue + rffi.cast(SIGNEDARRAYPTR, addr)[0] = newvalue # for tests: read = jit2gc.get('test_read', read) write = jit2gc.get('test_write', write) From noreply at buildbot.pypy.org Wed Jul 6 20:37:38 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 6 Jul 2011 20:37:38 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: explain the algorithms, the -b options and the nice abstraction it implements Message-ID: <20110706183738.0C697820AE@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: extradoc Changeset: r3824:34bd12cea418 Date: 2011-07-06 20:46 +0200 http://bitbucket.org/pypy/extradoc/changeset/34bd12cea418/ Log: explain the algorithms, the -b options and the nice abstraction it implements diff --git a/blog/draft/realtime_image_processing.rst b/blog/draft/realtime_image_processing.rst --- a/blog/draft/realtime_image_processing.rst +++ b/blog/draft/realtime_image_processing.rst @@ -12,7 +12,18 @@ enough to do realtime video processing using two simple algorithms implemented by Håkan Ardö. -XXX: add a very brief description of the algorithms +sobel.py implements a classical way of locating edges in images, +`the Sobel operator`:http://en.wikipedia.org/wiki/Sobel_operator. It +is an approximation of the magnitude of the +`image gradient`:http://en.wikipedia.org/wiki/Image_gradient. The +processing time is spend on two +`convolutions`:http://en.wikipedia.org/wiki/Convolution between the +image and 3x3-kernels. + +magnify.py implements a pixel coordinate transformation that rearranges +the pixels in the image to form a magnifying effect in the center. +It consists of a single loop over the pixels in the output image copying +pixels from the input image. You can try by yourself by downloading the appropriate demo: @@ -39,6 +50,22 @@ $ pypy demo/sobel.py tv:// +By default magnify.py uses +`nearest-neighbor +interpolation.`:http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation +By adding the option -b, +`bilinear interpolation`:http://en.wikipedia.org/wiki/Bilinear_interpolation +will be used instead, which gives smoother result. + + $ pypy demo/magnify.py -b + +There is only a single implementation of the algorithm in +magnify.py. The two different interpolation methods are implemented by +subclassing the class used to represent images and embed the +interpolation within the pixel access method. PyPy is able to achieve good +performance with this kind of abstractions because it can inline +virtual methods and specialize functions. + To have a feeling on how much PyPy is faster than CPython, try to run the demo with the latter. On my machine, PyPy runs ``sobel.py`` at ~47.23 fps on average, while CPython runs it at ~0.08 fps, meaning that PyPy is **590 times From noreply at buildbot.pypy.org Wed Jul 6 21:19:49 2011 From: noreply at buildbot.pypy.org (hodgestar) Date: Wed, 6 Jul 2011 21:19:49 +0200 (CEST) Subject: [pypy-commit] jitviewer default: Get jitviewer to install correctly -- move static and template folders into a package so that they really are package data, add qwebview.py to list of scripts to install, mark jitviewer package as zip unsafe in setup.py (since it relies on its package being at a real filesystem path). Message-ID: <20110706191949.30C81820AE@wyvern.cs.uni-duesseldorf.de> Author: Simon Cross Branch: Changeset: r136:97161ab5adfd Date: 2011-07-06 21:28 +0200 http://bitbucket.org/pypy/jitviewer/changeset/97161ab5adfd/ Log: Get jitviewer to install correctly -- move static and template folders into a package so that they really are package data, add qwebview.py to list of scripts to install, mark jitviewer package as zip unsafe in setup.py (since it relies on its package being at a real filesystem path). diff --git a/static/DroidSansMono.ttf b/_jitviewer/static/DroidSansMono.ttf rename from static/DroidSansMono.ttf rename to _jitviewer/static/DroidSansMono.ttf diff --git a/static/jquery-1.2.6.min.js b/_jitviewer/static/jquery-1.2.6.min.js rename from static/jquery-1.2.6.min.js rename to _jitviewer/static/jquery-1.2.6.min.js diff --git a/static/jquery.min.js b/_jitviewer/static/jquery.min.js rename from static/jquery.min.js rename to _jitviewer/static/jquery.min.js diff --git a/static/jquery.scrollTo-1.4.1.js b/_jitviewer/static/jquery.scrollTo-1.4.1.js rename from static/jquery.scrollTo-1.4.1.js rename to _jitviewer/static/jquery.scrollTo-1.4.1.js diff --git a/static/jquery.scrollTo-1.4.2-min.js b/_jitviewer/static/jquery.scrollTo-1.4.2-min.js rename from static/jquery.scrollTo-1.4.2-min.js rename to _jitviewer/static/jquery.scrollTo-1.4.2-min.js diff --git a/static/loop.js b/_jitviewer/static/loop.js rename from static/loop.js rename to _jitviewer/static/loop.js diff --git a/static/pygments.css b/_jitviewer/static/pygments.css rename from static/pygments.css rename to _jitviewer/static/pygments.css diff --git a/static/qt_workaround.css b/_jitviewer/static/qt_workaround.css rename from static/qt_workaround.css rename to _jitviewer/static/qt_workaround.css diff --git a/static/script.js b/_jitviewer/static/script.js rename from static/script.js rename to _jitviewer/static/script.js diff --git a/static/style.css b/_jitviewer/static/style.css rename from static/style.css rename to _jitviewer/static/style.css diff --git a/templates/index.html b/_jitviewer/templates/index.html rename from templates/index.html rename to _jitviewer/templates/index.html diff --git a/templates/loop.html b/_jitviewer/templates/loop.html rename from templates/loop.html rename to _jitviewer/templates/loop.html diff --git a/bin/jitviewer.py b/bin/jitviewer.py --- a/bin/jitviewer.py +++ b/bin/jitviewer.py @@ -1,4 +1,4 @@ -#!/usr/bin/env pypy-c +#!/usr/bin/env pypy """ A web-based browser of your log files. Run by jitviewer.py [port] [--server] @@ -175,8 +175,7 @@ def main(): - PATH = os.path.join(os.path.dirname( - os.path.dirname(_jitviewer.__file__))) + PATH = os.path.join(os.path.dirname((_jitviewer.__file__))) print PATH if not '__pypy__' in sys.builtin_module_names: print "Please run it using pypy-c" diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -9,7 +9,8 @@ author_email='fijall at gmail.com', url='http://pypy.org', packages=['_jitviewer'], - scripts=['bin/jitviewer.py'], + scripts=['bin/jitviewer.py', 'bin/qwebview.py'], install_requires=['flask', 'pygments', 'simplejson'], include_package_data=True, - package_data={'': ['templates/*.html', 'static/*']}) + package_data={'': ['templates/*.html', 'static/*']}, + zip_safe=False) From noreply at buildbot.pypy.org Wed Jul 6 21:22:57 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 6 Jul 2011 21:22:57 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: clairify Message-ID: <20110706192257.7A0A1820AE@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: extradoc Changeset: r3825:1ed18ccca681 Date: 2011-07-06 21:31 +0200 http://bitbucket.org/pypy/extradoc/changeset/1ed18ccca681/ Log: clairify diff --git a/blog/draft/realtime_image_processing.rst b/blog/draft/realtime_image_processing.rst --- a/blog/draft/realtime_image_processing.rst +++ b/blog/draft/realtime_image_processing.rst @@ -64,7 +64,9 @@ subclassing the class used to represent images and embed the interpolation within the pixel access method. PyPy is able to achieve good performance with this kind of abstractions because it can inline -virtual methods and specialize functions. +the pixel access method and specialize the implementation of the algorithm. +In C++ that kind of pixel access method would be virtual and you'll need to use +templates to get the same effect. XXX: Is that correct? To have a feeling on how much PyPy is faster than CPython, try to run the demo with the latter. On my machine, PyPy runs ``sobel.py`` at ~47.23 fps on From noreply at buildbot.pypy.org Thu Jul 7 01:45:53 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 7 Jul 2011 01:45:53 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge default Message-ID: <20110706234553.3B9EB82178@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45397:359fb9a9f8ee Date: 2011-07-06 10:14 -0700 http://bitbucket.org/pypy/pypy/changeset/359fb9a9f8ee/ Log: merge default diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -26,13 +30,6 @@ Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -416,10 +416,11 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( + debug_print("Loop #%d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -281,9 +281,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -337,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -5,6 +5,8 @@ class Op(object): bridge = None + offset = None + asm = None def __init__(self, name, args, res, descr): self.name = name @@ -54,10 +56,53 @@ Op = Op use_mock_model = True + def postprocess(self, loop, backend_dump=None, backend_tp=None, + loop_start=0, dump_start=0): + if backend_dump is not None: + raw_asm = self._asm_disassemble(backend_dump.decode('hex'), + backend_tp, dump_start) + asm = [] + start = 0 + for elem in raw_asm: + if len(elem.split("\t")) != 3: + continue + adr, _, v = elem.split("\t") + if not start: + start = int(adr.strip(":"), 16) + ofs = int(adr.strip(":"), 16) - start + if ofs >= 0: + asm.append((ofs, v.strip("\n"))) + asm_index = 0 + for i, op in enumerate(loop.operations): + end = 0 + j = i + 1 + while end == 0: + if j == len(loop.operations): + end = loop.last_offset + break + if loop.operations[j].offset is None: + j += 1 + else: + end = loop.operations[j].offset + if op.offset is not None: + while asm[asm_index][0] < op.offset: + asm_index += 1 + end_index = asm_index + while asm[end_index][0] < end: + end_index += 1 + op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) + return loop + + def _asm_disassemble(self, d, origin_addr, tp): + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + return list(machine_code_dump(d, tp, origin_addr)) + @classmethod - def parse_from_input(cls, input): - return cls(input, None, {}, 'lltype', None, - nonstrict=True).parse() + def parse_from_input(cls, input, **kwds): + parser = cls(input, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + return parser.postprocess(loop, **kwds) def parse_args(self, opname, argspec): if not argspec.strip(): diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -5,8 +5,8 @@ from pypy.tool.jitlogparser.storage import LoopStorage import py -def parse(input): - return SimpleParser.parse_from_input(input) +def parse(input, **kwds): + return SimpleParser.parse_from_input(input, **kwds) def test_parse(): @@ -179,3 +179,31 @@ ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] assert chunk.bytecode_name == 'StrLiteralSearch' + +def test_parsing_assembler(): + backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" + dump_start = 0x7f3b0b2e63d5 + loop = parse(""" + # Loop 0 : loop with 19 ops + [p0, p1, p2, p3, i4] + debug_merge_point(0, ' #15 COMPARE_OP') + +166: i6 = int_lt(i4, 10000) + guard_true(i6, descr=) [p1, p0, p2, p3, i4] + debug_merge_point(0, ' #27 INPLACE_ADD') + +179: i8 = int_add(i4, 1) + debug_merge_point(0, ' #31 JUMP_ABSOLUTE') + +183: i10 = getfield_raw(40564608, descr=) + +191: i12 = int_sub(i10, 1) + +195: setfield_raw(40564608, i12, descr=) + +203: i14 = int_lt(i12, 0) + guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] + debug_merge_point(0, ' #9 LOAD_FAST') + +213: jump(p0, p1, p2, p3, i8, descr=) + +218: --end of the loop--""", backend_dump=backend_dump, + dump_start=dump_start, + backend_tp='x86_64', + loop_start=0x7f3b0b2e645d) + cmp = loop.operations[1] + assert 'jge' in cmp.asm + assert '0x2710' in cmp.asm + assert 'jmp' in loop.operations[-1].asm From noreply at buildbot.pypy.org Thu Jul 7 01:45:51 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 7 Jul 2011 01:45:51 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge default and minimize changes with default Message-ID: <20110706234551.EA7CC820AE@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45396:167587fc58bb Date: 2011-07-05 18:18 -0700 http://bitbucket.org/pypy/pypy/changeset/167587fc58bb/ Log: merge default and minimize changes with default diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,6 +1,7 @@ syntax: glob *.py[co] *~ +.*.swp syntax: regexp ^testresult$ @@ -43,6 +44,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4400,7 +4400,10 @@ self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) + if hasattr(l.__add__, '__objclass__'): # CPython + self.assertTrue(l.__add__.__objclass__ is list) + else: # PyPy + self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -139,7 +139,10 @@ return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -218,5 +221,7 @@ 'z' : _ffi.types.void_p, 'O' : _ffi.types.void_p, 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, } diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -322,20 +322,18 @@ RuntimeWarning, stacklevel=2) if self._com_index: - assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None - - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -343,6 +341,11 @@ if not outargs: return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + if len(outargs) == 1: return outargs[0] return tuple(outargs) @@ -398,10 +401,10 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) cdll = self.dll._handle try: @@ -468,11 +471,7 @@ newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -587,13 +586,7 @@ retval = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, argsandobjs[0]) - else: - retval = int(resbuffer[0]) - elif restype is not None: + if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) @@ -601,7 +594,13 @@ # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value - retval = checker(val) + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) else: diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -216,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -357,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -385,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -129,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -266,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -355,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -248,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -237,7 +237,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1060,18 +1060,6 @@ def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -210,19 +210,20 @@ def m(self): "aaa" m.x = 3 + class B(A): + pass - bm = A().m + bm = B().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self - assert bm.im_class is A - if '__pypy__' in sys.builtin_module_names: - assert bm.__objclass__ is A + assert bm.im_class is B assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) l = [] assert l.append.__self__ is l - if '__pypy__' in sys.builtin_module_names: - assert l.append.__objclass__ is list assert l.__add__.__self__ is l - assert l.__add__.__objclass__ is list + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -771,7 +771,6 @@ im_self = interp_attrproperty_w('w_instance', cls=Method), __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), - __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, diff --git a/pypy/jit/backend/llgraph/test/test_llgraph.py b/pypy/jit/backend/llgraph/test/test_llgraph.py --- a/pypy/jit/backend/llgraph/test/test_llgraph.py +++ b/pypy/jit/backend/llgraph/test/test_llgraph.py @@ -32,21 +32,6 @@ assert heaptracker.adr2int(llmemory.NULL) == 0 assert heaptracker.int2adr(0) == llmemory.NULL -def test_force_cast_ptr_to_other_ptr(): - from pypy.jit.backend.llgraph import llimpl - from pypy.rpython.lltypesystem import rffi, llmemory - x = lltype.malloc(rffi.DOUBLEP.TO, 1, flavor='raw') - x[0] = 0.1 - args = lltype.malloc(rffi.CArray(rffi.VOIDP), 1, flavor='raw', zero=True) - assert not args[0] - arrayasint = llmemory.cast_adr_to_int(llmemory.cast_ptr_to_adr(args), mode="symbolic") - ptrasint = llmemory.cast_adr_to_int(llmemory.cast_ptr_to_adr(x), mode="symbolic") - llimpl.do_setarrayitem_raw_int(arrayasint, 0, ptrasint) - assert args[0] - lltype.free(x, flavor='raw') - lltype.free(args, flavor='raw') - - ## these tests never worked ## class TestOOTypeLLGraph(LLGraphTest): ## from pypy.jit.backend.llgraph.runner import OOtypeCPU as cpu_type diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -92,7 +92,7 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: @@ -113,18 +113,13 @@ def has_random_effects(self): return self.oopspecindex == self.OS_LIBFFI_CALL - -def _frozenset_or_none(x): - if x is None: return None - return frozenset(x) - def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, can_invalidate=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: - return EffectInfo(None, None, None, extraeffect) + return None readonly_descrs_fields = [] readonly_descrs_arrays = [] write_descrs_fields = [] diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -847,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -3,7 +3,6 @@ from pypy.rpython.ootypesystem import ootype from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze,\ EffectInfo -from pypy.translator.backendopt.writeanalyze import top_set class FakeCPU: def fielddescrof(self, T, fieldname): @@ -106,19 +105,3 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_fields assert not effectinfo.write_descrs_arrays - -def test_no_effectinfo(): - effectinfo = effectinfo_from_writeanalyze(top_set, None, - EffectInfo.EF_CANNOT_RAISE) - assert effectinfo.readonly_descrs_fields is None - assert effectinfo.write_descrs_fields is None - assert effectinfo.write_descrs_arrays is None - assert effectinfo.extraeffect == EffectInfo.EF_CANNOT_RAISE - # - effectinfo2 = effectinfo_from_writeanalyze(top_set, None, - EffectInfo.EF_CANNOT_RAISE) - assert effectinfo2 is effectinfo - # - effectinfo3 = effectinfo_from_writeanalyze(top_set, None, - EffectInfo.EF_PURE) - assert effectinfo3.extraeffect == EffectInfo.EF_PURE diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -203,13 +203,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -220,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -431,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt @@ -34,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -57,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -382,6 +375,18 @@ v1.intbound.make_gt(IntBound(0, 0)) self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -428,5 +433,6 @@ propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile @@ -434,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -569,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -477,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -439,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] @@ -4123,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5373,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -1252,7 +1252,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1312,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1343,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1496,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1531,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1595,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1676,8 +1676,8 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) - self.check_loops(getarrayitem_gc=8, everywhere=True) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) @@ -1817,7 +1817,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2002,7 +2002,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2047,7 +2047,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2082,7 +2082,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2139,7 +2139,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2208,7 +2208,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2313,6 +2314,67 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + def test_retrace_ending_up_retrazing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -237,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: diff --git a/pypy/jit/tl/pypyjit_child.py b/pypy/jit/tl/pypyjit_child.py --- a/pypy/jit/tl/pypyjit_child.py +++ b/pypy/jit/tl/pypyjit_child.py @@ -34,5 +34,4 @@ warmspot.jittify_and_run(interp, graph, [], policy=policy, listops=True, CPUClass=CPUClass, backendopt=True, inline=True) - write_jitcodes_directory=True, diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -1,14 +1,11 @@ -import cppyy -import time -import cppyy -lib = cppyy.load_lib("../../module/cppyy/test/example01Dict.so") -cls = cppyy._type_byname('example01') -inst = cls.construct(-17) +try: + import numpy + a = numpy.array(range(10)) + b = a + a + a + print b[3] -t1 = time.time() -res = 0 -for i in range(10): - res += inst.invoke("addDataToInt", i) -t2 = time.time() -print t2 - t1 +except Exception, e: + print "Exception: ", type(e) + print e + diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -631,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -186,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -207,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -240,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,21 @@ from __future__ import with_statement +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -37,7 +40,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -73,6 +76,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +100,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +163,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -268,12 +270,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -311,6 +311,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -319,12 +327,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -387,7 +390,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -395,7 +398,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -413,7 +416,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -515,14 +518,14 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() @@ -615,6 +618,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) + return w_a + def array_byteswap__Array(space, self): if mytype.bytes not in [1, 2, 4, 8]: msg = "byteswap not supported for this array" diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -4,7 +4,7 @@ from pypy.interpreter.buffer import Buffer from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import r_singlefloat -from pypy.rlib import jit, libffi +from pypy.rlib import jit, libffi, clibffi from pypy.module._rawffi.interp_rawffi import unpack_simple_shape from pypy.module._rawffi.array import W_Array @@ -12,7 +12,7 @@ from pypy.module.cppyy import helper, capi -_converters = {} +NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO) def get_rawobject(space, w_obj): if not space.eq_w(w_obj, space.w_None): @@ -26,7 +26,7 @@ class TypeConverter(object): _immutable = True - libffitype = libffi.types.NULL + libffitype = NULL def __init__(self, space, array_size): pass @@ -383,6 +383,7 @@ pass +_converters = {} def get_converter(space, name): from pypy.module.cppyy import interp_cppyy # The matching of the name to a converter should follow: diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -2,7 +2,7 @@ from pypy.interpreter.error import OperationError from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib import libffi +from pypy.rlib import libffi, clibffi from pypy.module._rawffi.interp_rawffi import unpack_simple_shape from pypy.module._rawffi.array import W_Array @@ -10,11 +10,11 @@ from pypy.module.cppyy import helper, capi -_executors = {} +NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO) class FunctionExecutor(object): _immutable_ = True - libffitype = libffi.types.NULL + libffitype = NULL def __init__(self, space, name, cpptype): self.name = name @@ -162,6 +162,7 @@ return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result) +_executors = {} def get_executor(space, name): # Matching of 'name' to an executor factory goes through up to four levels: # 1) full, qualified match diff --git a/pypy/module/cppyy/test/example01.xml b/pypy/module/cppyy/test/example01.xml new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/example01.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -799,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -829,8 +828,6 @@ return struct.unpack(') i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) def test_stararg(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py @@ -0,0 +1,82 @@ +# unittest for SOME ctypes com function calls. +# Can't resist from implementing some kind of mini-comtypes +# theller ;-) + +import py +import sys +if sys.platform != "win32": + py.test.skip('windows only test') + +import ctypes, new, unittest +from ctypes.wintypes import HRESULT +from _ctypes import COMError + +oleaut32 = ctypes.OleDLL("oleaut32") + +class UnboundMethod(object): + def __init__(self, func, index, name): + self.func = func + self.index = index + self.name = name + self.__doc__ = func.__doc__ + + def __repr__(self): + return "" % (self.index, self.name, id(self)) + + def __get__(self, instance, owner): + if instance is None: + return self + return new.instancemethod(self.func, instance, owner) + +def commethod(index, restype, *argtypes): + """A decorator that generates COM methods. The decorated function + itself is not used except for it's name.""" + def make_commethod(func): + comfunc = ctypes.WINFUNCTYPE(restype, *argtypes)(index, func.__name__) + comfunc.__name__ = func.__name__ + comfunc.__doc__ = func.__doc__ + return UnboundMethod(comfunc, index, func.__name__) + return make_commethod + +class ICreateTypeLib2(ctypes.c_void_p): + + @commethod(1, ctypes.c_long) + def AddRef(self): + pass + + @commethod(2, ctypes.c_long) + def Release(self): + pass + + @commethod(4, HRESULT, ctypes.c_wchar_p) + def SetName(self): + """Set the name of the library.""" + + @commethod(12, HRESULT) + def SaveAllChanges(self): + pass + + +CreateTypeLib2 = oleaut32.CreateTypeLib2 +CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, ctypes.POINTER(ICreateTypeLib2)) + +################################################################ + +def test_basic_comtypes(): + punk = ICreateTypeLib2() + hr = CreateTypeLib2(0, "foobar.tlb", punk) + assert hr == 0 + + assert 2 == punk.AddRef() + assert 3 == punk.AddRef() + assert 4 == punk.AddRef() + + punk.SetName("TypeLib_ByPYPY") + py.test.raises(COMError, lambda: punk.SetName(None)) + + # This would save the typelib to disk. + ## punk.SaveAllChanges() + + assert 3 == punk.Release() + assert 2 == punk.Release() + assert 1 == punk.Release() diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + w_dict = jit.promote(w_dict) + self = jit.promote(self) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + @jit.elidable + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,91 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -5,15 +5,16 @@ from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS -from pypy.rlib.objectmodel import r_dict, we_are_translated +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize from pypy.rlib.debug import mark_dict_non_null +from pypy.rlib import rerased + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -29,49 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w, - force_non_null=True) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -90,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -142,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -151,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -161,106 +140,90 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + self.switch_to_object_strategy(w_dict) - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_length(self): - return len(self.r_dict_content) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError + def length(self, w_dict): + return 0 -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) + def clear(self, w_dict): + return -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -302,322 +265,255 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = {} - mark_dict_non_null(self.content) +class AbstractTypedStrategy(object): + _mixin_ = True - def impl_setitem(self, w_key, w_value): + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, key, w_value): - assert key is not None - self.content[key] = w_value + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] return - elif _is_sane_hash(space, w_key_type): - raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) - def impl_length(self): - return len(self.content) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) - def impl_getitem_str(self, key): + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) + + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return ObjectIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + + def setitem_str(self, w_dict, key, w_value): assert key is not None - return self.content.get(key, None) + self.unerase(w_dict.dstorage)[key] = w_value - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().impl_fallback_getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) - def impl_delitem(self, w_key): + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) + return space.is_w(space.type(w_obj), space.w_int) - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) -class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): +class IntIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - + return None, None init_signature = Signature(['seq_or_map'], None, 'kwargs') @@ -924,7 +820,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,121 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): @@ -322,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) @@ -29,3 +38,33 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -137,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -176,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -195,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -233,8 +234,33 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2: 2, "c": 3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l + def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -267,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -297,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -316,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -366,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} @@ -527,6 +549,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +734,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +749,64 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -759,6 +847,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj @@ -790,6 +882,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +895,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +927,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1012,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1027,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1071,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1083,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1104,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,20 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) + + def test_slot_name_conflict(self): class A(object): @@ -604,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: @@ -447,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec @@ -277,12 +292,13 @@ 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -337,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -575,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -592,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -73,10 +73,8 @@ elif types.is_struct(ffi_type): return 'S' raise KeyError - NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO) - @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) @@ -226,7 +224,7 @@ _immutable_fields_ = ['funcsym'] argtypes = [] - restype = types.NULL + restype = lltype.nullptr(clibffi.FFI_TYPE_P.TO) funcsym = lltype.nullptr(rffi.VOIDP.TO) def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL, @@ -255,11 +253,10 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) - self = jit.hint(self, promote=True) ll_args = self._prepare() i = 0 arg = argchain.first diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -845,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -857,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,8 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - # it's pure but it does not look like it - @purefunction + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -342,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -352,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -370,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -387,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -428,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -451,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -471,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -487,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -504,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -516,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -527,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -595,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -718,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -816,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -831,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -842,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/rpython/ootypesystem/test/test_oopbc.py b/pypy/rpython/ootypesystem/test/test_oopbc.py --- a/pypy/rpython/ootypesystem/test/test_oopbc.py +++ b/pypy/rpython/ootypesystem/test/test_oopbc.py @@ -81,3 +81,18 @@ res = interpret(f, [1], type_system='ootype') assert res == 2 +def test_quasi_immutable(): + class A(object): + _immutable_fields_ = ['x?'] + def __init__(self): + self.x = 3 + def foo(self): + return self.x + + a = A() + + def f(): + return a.foo() + + res = interpret(f, [], type_system='ootype') + assert res == 3 diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,30 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] + class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): def func(i): diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -83,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -559,15 +559,16 @@ mk.rule(*rule) if self.config.translation.gcrootfinder == 'asmgcc': - trackgcfiles = [cfile[:-2] for cfile in mk.cfiles - if cfile.endswith('.c')] - if 1: # XXX do that more cleanly + trackgcfiles = [cfile[:-2] for cfile in mk.cfiles] + if self.translator.platform.name == 'msvc': trackgcfiles = [f for f in trackgcfiles if f.startswith(('implement', 'testing', '../module_cache/module'))] sfiles = ['%s.s' % (c,) for c in trackgcfiles] + lblsfiles = ['%s.lbl.s' % (c,) for c in trackgcfiles] gcmapfiles = ['%s.gcmap' % (c,) for c in trackgcfiles] mk.definition('ASMFILES', sfiles) + mk.definition('ASMLBLFILES', lblsfiles) mk.definition('GCMAPFILES', gcmapfiles) if sys.platform == 'win32': mk.definition('DEBUGFLAGS', '/Zi') @@ -585,32 +586,17 @@ python = sys.executable + ' ' if self.translator.platform.name == 'msvc': - o_ext = '.obj' - lbl_ext = '.lbl.obj' - else: - o_ext = '.o' - lbl_ext = '.lbl.s' + lblofiles = [] + for cfile in mk.cfiles: + f = cfile[:-2] + if f in trackgcfiles: + ofile = '%s.lbl.obj' % (f,) + else: + ofile = '%s.obj' % (f,) - objectfiles = [] - nontrackgcexts = set() - for cfile in mk.cfiles: - f = cfile[:-2] - if f in trackgcfiles: - ofile = f + lbl_ext - else: - f, ext = os.path.splitext(cfile) - nontrackgcexts.add(ext) - ofile = f + o_ext - objectfiles.append(ofile) - if self.translator.platform.name == 'msvc': - objectfiles.append('gcmaptable.obj') - else: - objectfiles.append('gcmaptable.s') - mk.definition('OBJECTS', objectfiles) - nontrackgcexts = list(nontrackgcexts) - nontrackgcexts.sort() - - if self.translator.platform.name == 'msvc': + lblofiles.append(ofile) + mk.definition('ASMLBLOBJFILES', lblofiles) + mk.definition('OBJECTS', 'gcmaptable.obj $(ASMLBLOBJFILES)') # /Oi (enable intrinsics) and /Ob1 (some inlining) are mandatory # even in debug builds mk.definition('ASM_CFLAGS', '$(CFLAGS) $(CFLAGSEXTRA) /Oi /Ob1') @@ -623,13 +609,9 @@ ) mk.rule('gcmaptable.c', '$(GCMAPFILES)', 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@') - mk.rule('gcmaptable.c', '$(GCMAPFILES)', - 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@') - for ext in nontrackgcexts: - mk.rule(ext + '.obj', '', - '$(CC) /nologo $(CFLAGS) $(CFLAGSEXTRA) /Fo$@ /c $< $(INCLUDEDIRS)') else: + mk.definition('OBJECTS', '$(ASMLBLFILES) gcmaptable.s') mk.rule('%.s', '%.c', '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -frandom-seed=$< -o $@ -S $< $(INCLUDEDIRS)') mk.rule('%.lbl.s %.gcmap', '%.s', [python + @@ -642,9 +624,6 @@ '$(GCMAPFILES) > $@.tmp', 'mv $@.tmp $@']) mk.rule('.PRECIOUS', '%.s', "# don't remove .s files if Ctrl-C'ed") - for ext in nontrackgcexts: - mk.rule('%.o', '%' + ext, - '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)') else: if sys.platform == 'win32': diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -186,7 +186,7 @@ print "\n\nTarget specific help:\n\n" targetspec_dic['print_help'](config) print "\n\nFor detailed descriptions of the command line options see" - print "http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html" + print "http://pypy.readthedocs.org/en/latest/config/commandline.html" sys.exit(0) return targetspec_dic, translateconfig, config, args diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,12 +964,15 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" diff --git a/pypy/translator/tool/cbuild.py b/pypy/translator/tool/cbuild.py --- a/pypy/translator/tool/cbuild.py +++ b/pypy/translator/tool/cbuild.py @@ -279,6 +279,7 @@ #basepath = py.path.local(self.separate_module_files[0]).dirpath() basepath = udir.join('shared_cache') if outputfilename is None: + # find more or less unique name there pth = basepath.join('externmod').new(ext=host.so_ext) num = 0 while pth.check(): From noreply at buildbot.pypy.org Thu Jul 7 01:45:54 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 7 Jul 2011 01:45:54 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: fix translation error Message-ID: <20110706234554.7625382934@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45398:6c9c330bf4dd Date: 2011-07-06 15:28 -0700 http://bitbucket.org/pypy/pypy/changeset/6c9c330bf4dd/ Log: fix translation error diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -475,7 +475,7 @@ def construct(self, args_w): try: overload = self.get_overload(self.name) - except Exception, e: + except OperationError, e: if e.match(self.space, self.space.w_AttributeError): raise OperationError(self.space.w_TypeError, self.space.wrap("%s is abstract" % self.name)) From noreply at buildbot.pypy.org Thu Jul 7 01:45:55 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 7 Jul 2011 01:45:55 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: fix translation problem in JIT generation Message-ID: <20110706234555.AFE5182935@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45399:012bea4f7b9b Date: 2011-07-06 16:53 -0700 http://bitbucket.org/pypy/pypy/changeset/012bea4f7b9b/ Log: fix translation problem in JIT generation diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -350,6 +350,9 @@ def __init__(self, space, cpptype): self.cpptype = cpptype + # TODO: factor out the direct_ptradd into a smaller function (so that the + # JIT can look into the rest of the code) + @jit.dont_look_inside def convert_argument(self, space, w_obj): from pypy.module.cppyy.interp_cppyy import W_CPPInstance w_cppinstance = space.findattr(w_obj, space.wrap("_cppinstance")) From alex.gaynor at gmail.com Thu Jul 7 01:56:05 2011 From: alex.gaynor at gmail.com (Alex Gaynor) Date: Wed, 6 Jul 2011 16:56:05 -0700 Subject: [pypy-commit] pypy reflex-support: fix translation problem in JIT generation In-Reply-To: <20110706234555.AFE5182935@wyvern.cs.uni-duesseldorf.de> References: <20110706234555.AFE5182935@wyvern.cs.uni-duesseldorf.de> Message-ID: Rather than factor that out, maybe we should add ptradd support to the JIT, I know I've done this same thing several times at this point. Alex On Wed, Jul 6, 2011 at 4:45 PM, wlav wrote: > Author: Wim Lavrijsen > Branch: reflex-support > Changeset: r45399:012bea4f7b9b > Date: 2011-07-06 16:53 -0700 > http://bitbucket.org/pypy/pypy/changeset/012bea4f7b9b/ > > Log: fix translation problem in JIT generation > > diff --git a/pypy/module/cppyy/converter.py > b/pypy/module/cppyy/converter.py > --- a/pypy/module/cppyy/converter.py > +++ b/pypy/module/cppyy/converter.py > @@ -350,6 +350,9 @@ > def __init__(self, space, cpptype): > self.cpptype = cpptype > > + # TODO: factor out the direct_ptradd into a smaller function (so that > the > + # JIT can look into the rest of the code) > + @jit.dont_look_inside > def convert_argument(self, space, w_obj): > from pypy.module.cppyy.interp_cppyy import W_CPPInstance > w_cppinstance = space.findattr(w_obj, space.wrap("_cppinstance")) > _______________________________________________ > pypy-commit mailing list > pypy-commit at python.org > http://mail.python.org/mailman/listinfo/pypy-commit > -- "I disapprove of what you say, but I will defend to the death your right to say it." -- Evelyn Beatrice Hall (summarizing Voltaire) "The people's good is the highest law." -- Cicero -------------- next part -------------- An HTML attachment was scrubbed... URL: From noreply at buildbot.pypy.org Thu Jul 7 09:08:07 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 7 Jul 2011 09:08:07 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: specify better how I got those results Message-ID: <20110707070807.EB457820AE@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: extradoc Changeset: r3826:8c2e968974b1 Date: 2011-07-07 09:16 +0200 http://bitbucket.org/pypy/extradoc/changeset/8c2e968974b1/ Log: specify better how I got those results diff --git a/blog/draft/realtime_image_processing.rst b/blog/draft/realtime_image_processing.rst --- a/blog/draft/realtime_image_processing.rst +++ b/blog/draft/realtime_image_processing.rst @@ -69,10 +69,24 @@ templates to get the same effect. XXX: Is that correct? To have a feeling on how much PyPy is faster than CPython, try to run the demo -with the latter. On my machine, PyPy runs ``sobel.py`` at ~47.23 fps on -average, while CPython runs it at ~0.08 fps, meaning that PyPy is **590 times -faster**. On ``magnify.py`` the difference is much less evident, ~26.92 fps -vs ~1.78 fps, and the speedup is "only" 15x. +with the latter. These are the the average fps (frames per second) that I get +on my machine (Ubuntu 64 bit, Intel i7 920, 4GB RAM) when processing the +default ``test.avi`` video and using the prebuilt PyPy binary found in the +full_ tarball alinked above. For ``sobel.py``: + + - PyPy: ~47.23 fps + - CPython: ~0.08 fps + +For ``magnify.py``: + + - PyPy: ~26.92 fps + - CPython: ~1.78 fps + +This means that on ``sobel.py``, PyPy is **590 times faster**. On +``magnify.py`` the difference is much less evident and the speedup is "only" +15x. + +.. _full: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo-full.tar.bz2 It must be noted that this is an extreme example of what PyPy can do. In particular, you cannot expect (yet :-)) PyPy to be fast enough to run an From noreply at buildbot.pypy.org Thu Jul 7 10:47:28 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 7 Jul 2011 10:47:28 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: Comment about a potentially much better solution. Message-ID: <20110707084728.DB877820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: reflex-support Changeset: r45400:8c156dc9d400 Date: 2011-07-07 10:55 +0200 http://bitbucket.org/pypy/pypy/changeset/8c156dc9d400/ Log: Comment about a potentially much better solution. diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -351,7 +351,9 @@ self.cpptype = cpptype # TODO: factor out the direct_ptradd into a smaller function (so that the - # JIT can look into the rest of the code) + # JIT can look into the rest of the code), or better, let the JIT + # see it (either by teaching it direct_ptradd, or by using a + # different style like casts between addresses and integers) @jit.dont_look_inside def convert_argument(self, space, w_obj): from pypy.module.cppyy.interp_cppyy import W_CPPInstance From noreply at buildbot.pypy.org Thu Jul 7 11:15:04 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 7 Jul 2011 11:15:04 +0200 (CEST) Subject: [pypy-commit] pypy default: (fijal, djarecka) numpy.fromstring Message-ID: <20110707091504.DB1C4820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45401:65b3eb117eb5 Date: 2011-07-07 11:23 +0200 http://bitbucket.org/pypy/pypy/changeset/65b3eb117eb5/ Log: (fijal, djarecka) numpy.fromstring diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -10,6 +10,7 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + 'fromstring': 'interp_support.fromstring', # ufuncs 'abs': 'interp_ufuncs.absolute', diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_support.py @@ -0,0 +1,32 @@ + +from pypy.rlib.rstruct.runpack import runpack +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.error import OperationError +from pypy.module.micronumpy.interp_numarray import SingleDimArray + +FLOAT_SIZE = rffi.sizeof(lltype.Float) + + at unwrap_spec(s=str) +def fromstring(space, s): + length = len(s) + + if length % FLOAT_SIZE == 0: + number = length/FLOAT_SIZE + else: + raise OperationError(space.w_ValueError, space.wrap( + "string length %d not divisable by %d" % (length, FLOAT_SIZE))) + + a = SingleDimArray(number) + + start = 0 + end = FLOAT_SIZE + i = 0 + while i < number: + part = s[start:end] + a.storage[i] = runpack('d', part) + i += 1 + start += FLOAT_SIZE + end += FLOAT_SIZE + + return space.wrap(a) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1,6 +1,7 @@ import py from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest +from pypy.conftest import gettestobjspace class AppTestNumArray(BaseNumpyAppTest): @@ -276,7 +277,21 @@ assert d[1] == 12 def test_mean(self): - from numpy import array, mean + from numpy import array a = array(range(5)) assert a.mean() == 2.0 assert a[:4].mean() == 1.5 + +class AppTestSupport(object): + def setup_class(cls): + import struct + cls.space = gettestobjspace(usemodules=('micronumpy',)) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + + def test_fromstring(self): + from numpy import fromstring + a = fromstring(self.data) + for i in range(4): + assert a[i] == i + 1 + raises(ValueError, fromstring, "abc") + From noreply at buildbot.pypy.org Thu Jul 7 12:21:11 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 7 Jul 2011 12:21:11 +0200 (CEST) Subject: [pypy-commit] pypy celldict-versions: skip correctly on apptests Message-ID: <20110707102111.B47EC820AE@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: celldict-versions Changeset: r45402:34826add86e7 Date: 2011-07-07 12:29 +0200 http://bitbucket.org/pypy/pypy/changeset/34826add86e7/ Log: skip correctly on apptests diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -6,7 +6,7 @@ BaseTestRDictImplementation, BaseTestDevolvedDictImplementation from pypy.interpreter import gateway -from pypy.conftest import gettestobjspace +from pypy.conftest import gettestobjspace, option space = FakeSpace() @@ -46,6 +46,8 @@ cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) def w_impl_used(self, obj): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") import __pypy__ assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) @@ -134,4 +136,4 @@ d["a"] = 3 del d["a"] d[object()] = 5 - assert d.values() == [5] \ No newline at end of file + assert d.values() == [5] From noreply at buildbot.pypy.org Thu Jul 7 12:21:13 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 7 Jul 2011 12:21:13 +0200 (CEST) Subject: [pypy-commit] pypy celldict-versions: make globals a virtualizable field Message-ID: <20110707102113.013F6820AE@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: celldict-versions Changeset: r45403:485f752ebe10 Date: 2011-07-07 12:29 +0200 http://bitbucket.org/pypy/pypy/changeset/485f752ebe10/ Log: make globals a virtualizable field diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -25,6 +25,7 @@ 'last_exception', 'lastblock', 'is_being_profiled', + 'w_globals', ] JUMP_ABSOLUTE = opmap['JUMP_ABSOLUTE'] From noreply at buildbot.pypy.org Thu Jul 7 12:24:38 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 7 Jul 2011 12:24:38 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Backed out changeset 31d4b032dd61, for now. Message-ID: <20110707102438.1EB86820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45404:11deeacd3210 Date: 2011-07-07 11:23 +0200 http://bitbucket.org/pypy/pypy/changeset/11deeacd3210/ Log: Backed out changeset 31d4b032dd61, for now. It's subtly incorrect, at least because the JIT backend uses two consecutive entries to mean something special and doesn't clear them at function exit (see _call_footer_shadowstack). diff --git a/pypy/rpython/lltypesystem/llmemory.py b/pypy/rpython/lltypesystem/llmemory.py --- a/pypy/rpython/lltypesystem/llmemory.py +++ b/pypy/rpython/lltypesystem/llmemory.py @@ -435,17 +435,8 @@ if isinstance(other, fakeaddress): if self == other: return 0 - # <*_subarray at n> - <*_subarray at m> == ItemOffset(n-m) - obj1 = self.ptr._obj - obj2 = other.ptr._obj - if (isinstance(obj1, lltype._subarray) and - isinstance(obj2, lltype._subarray) and - obj1._TYPE == obj2._TYPE and - obj1._parentstructure() == obj2._parentstructure()): - n = obj1._parent_index - m = obj2._parent_index - return ItemOffset(obj1._TYPE.OF, n - m) - raise TypeError("cannot subtract fakeaddresses in general") + else: + raise TypeError("cannot subtract fakeaddresses in general") if other == 0: return self return NotImplemented diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -55,25 +55,11 @@ return top.address[0] def allocate_stack(self): - stackbase = llmemory.raw_malloc(self.rootstacksize) - if not stackbase: - raise MemoryError - self.clear_stack(stackbase, stackbase) - return stackbase - - def clear_stack(self, stackbase, stacktop): - """When a function is called, the current stack top is - incremented by as much as needed by this function, but the old - content is left in the stack. This is a speed optimization that - may lead to occasional leaks, because the stack may end up - containing dead pointers. Another drawback is that we need to - clear the stack manually after every minor collection, to - prevent these leftover pointers from pointing to garbage.""" - size = stackbase + self.rootstacksize - stacktop - llmemory.raw_memclear(stacktop, size) + return llmemory.raw_malloc(self.rootstacksize) def setup_root_walker(self): stackbase = self.allocate_stack() + ll_assert(bool(stackbase), "could not allocate root stack") self.gcdata.root_stack_top = stackbase self.gcdata.root_stack_base = stackbase BaseRootWalker.setup_root_walker(self) @@ -81,10 +67,9 @@ def walk_stack_roots(self, collect_stack_root): gcdata = self.gcdata gc = self.gc + rootstackhook = self.rootstackhook addr = gcdata.root_stack_base end = gcdata.root_stack_top - self.clear_stack(addr, end) - rootstackhook = self.rootstackhook while addr != end: addr += rootstackhook(collect_stack_root, gc, addr) if self.collect_stacks_from_other_threads is not None: @@ -122,6 +107,8 @@ """ if not gcdata._fresh_rootstack: gcdata._fresh_rootstack = self.allocate_stack() + if not gcdata._fresh_rootstack: + raise MemoryError def thread_run(): """Called whenever the current thread (re-)acquired the GIL. @@ -145,7 +132,6 @@ gcdata.thread_stacks.setitem(aid, llmemory.NULL) old = gcdata.root_stack_base if gcdata._fresh_rootstack == llmemory.NULL: - self.clear_stack(old, old) gcdata._fresh_rootstack = old else: llmemory.raw_free(old) @@ -192,10 +178,9 @@ # collect all valid stacks from the dict (the entry # corresponding to the current thread is not valid) gc = self.gc + rootstackhook = self.rootstackhook end = stacktop - sizeofaddr addr = end.address[0] - self.clear_stack(addr, stacktop) - rootstackhook = self.rootstackhook while addr != end: addr += rootstackhook(callback, gc, addr) @@ -309,6 +294,13 @@ c_numcolors = rmodel.inputconst(lltype.Signed, numcolors) llops.genop("direct_call", [gct.incr_stack_ptr, c_numcolors], resulttype=llmemory.Address) + top_addr = llops.genop("direct_call", + [gct.get_stack_top_ptr], + resulttype=llmemory.Address) + c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL) + for k in range(numcolors): + c_k = rmodel.inputconst(lltype.Signed, ~k) + llops.genop("raw_store", [top_addr, c_type, c_k, c_null]) graph.startblock.operations[:0] = llops # # Put at the end of the graph: "decr_stack()" From noreply at buildbot.pypy.org Thu Jul 7 12:24:39 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 7 Jul 2011 12:24:39 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Mostly comments for now, describing the goal. Message-ID: <20110707102439.58BA2820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45405:c292d7b6630f Date: 2011-07-07 12:33 +0200 http://bitbucket.org/pypy/pypy/changeset/c292d7b6630f/ Log: Mostly comments for now, describing the goal. diff --git a/pypy/translator/register.py b/pypy/translator/register.py new file mode 100644 --- /dev/null +++ b/pypy/translator/register.py @@ -0,0 +1,35 @@ +from pypy.translator.tool.cbuild import ExternalCompilationInfo +from pypy.rpython.tool import rffi_platform + +# On platforms with enough hardware registers and with gcc, we can +# (ab)use gcc to globally assign a register to a single global void* +# variable. We use it with a double meaning: +# +# - when it is NULL upon return from a function, it means that an +# exception occurred. It allows the caller to quickly check for +# exceptions. +# +# - in other cases, with --gcrootfinder=shadowstack, it points to +# the top of the shadow stack. + + +# For now, only for x86-64. Tries to use the register r15. +eci = ExternalCompilationInfo( + post_include_bits=['register void* pypy_reg asm("r15");'], + ) + +_test_eci = eci.merge(ExternalCompilationInfo( + post_include_bits=[""" + void f(void) { + pypy_reg = &f; + } + """])) + +try: + rffi_platform.verify_eci(_test_eci) + var_name_in_c = 'pypy_reg' + register_number = 15 # r15 +except rffi_platform.CompilationError: + eci = None + var_name_in_c = None + register_number = None diff --git a/pypy/translator/test/test_register.py b/pypy/translator/test/test_register.py new file mode 100644 --- /dev/null +++ b/pypy/translator/test/test_register.py @@ -0,0 +1,13 @@ + +def test_register(): + from pypy.translator import register + # + from pypy.jit.backend.detect_cpu import autodetect + if autodetect() == 'x86_64': + assert register.eci is not None + assert register.var_name_in_c is not None + assert register.register_number == 15 # r15 + else: + assert register.eci is None + assert register.var_name_in_c is None + assert register.register_number is None From noreply at buildbot.pypy.org Thu Jul 7 15:08:56 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 7 Jul 2011 15:08:56 +0200 (CEST) Subject: [pypy-commit] pypy default: (cfbolz, arigo around): dont record guard_class operations on the same box Message-ID: <20110707130856.43674820AE@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45406:4303dff32d79 Date: 2011-07-07 15:17 +0200 http://bitbucket.org/pypy/pypy/changeset/4303dff32d79/ Log: (cfbolz, arigo around): dont record guard_class operations on the same box repeatedly. saves a luarge percentage of guards. diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -845,7 +845,9 @@ @arguments("orgpc", "box") def opimpl_guard_class(self, orgpc, box): clsbox = self.cls_of_box(box) - self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + self.metainterp.known_class_boxes[box] = None return clsbox @arguments("int", "orgpc") @@ -1449,6 +1451,8 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1789,6 +1793,8 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1021,6 +1021,24 @@ res = self.meta_interp(main, []) assert res == 55 + + def test_dont_record_guard_class(self): + class A: + pass + class B(A): + pass + def fn(n): + if n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res + self.check_operations_history(guard_class=1) + res = self.interp_operations(fn, [1]) + assert not res + def test_assert_isinstance(self): class A: pass From noreply at buildbot.pypy.org Thu Jul 7 15:39:01 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 7 Jul 2011 15:39:01 +0200 (CEST) Subject: [pypy-commit] pypy default: don't put guard_nonnull for things that have a known class Message-ID: <20110707133901.E98E6820AE@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45407:8061dbe5a513 Date: 2011-07-07 15:35 +0200 http://bitbucket.org/pypy/pypy/changeset/8061dbe5a513/ Log: don't put guard_nonnull for things that have a known class diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -310,26 +310,24 @@ self.opimpl_goto_if_not(condbox, target) ''' % (_opimpl, _opimpl.upper())).compile() + + def _establish_nullity(self, box, orgpc): + value = box.nonnull() + if value: + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc) + else: + self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + return value + @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_nonzero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if not value: + if not self._establish_nullity(box, orgpc): self.pc = target @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_iszero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if value: + if self._establish_nullity(box, orgpc): self.pc = target @arguments("box", "box", "box") diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1021,21 +1021,22 @@ res = self.meta_interp(main, []) assert res == 55 - - def test_dont_record_guard_class(self): + def test_dont_record_repeated_guard_class(self): class A: pass class B(A): pass def fn(n): - if n: + if n == -7: + obj = None + elif n: obj = A() else: obj = B() return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) res = self.interp_operations(fn, [0]) - assert res - self.check_operations_history(guard_class=1) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) res = self.interp_operations(fn, [1]) assert not res From noreply at buildbot.pypy.org Thu Jul 7 15:39:03 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 7 Jul 2011 15:39:03 +0200 (CEST) Subject: [pypy-commit] pypy default: don't repeat guard_isnull Message-ID: <20110707133903.32EED820AE@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45408:2ce2e3e205d8 Date: 2011-07-07 15:35 +0200 http://bitbucket.org/pypy/pypy/changeset/2ce2e3e205d8/ Log: don't repeat guard_isnull diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -317,7 +317,10 @@ if box not in self.metainterp.known_class_boxes: self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc) else: - self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + if not isinstance(box, Const): + self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + promoted_box = box.constbox() + self.metainterp.replace_box(box, promoted_box) return value @arguments("orgpc", "box", "label") diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1040,6 +1040,29 @@ res = self.interp_operations(fn, [1]) assert not res + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass From noreply at buildbot.pypy.org Thu Jul 7 15:39:04 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 7 Jul 2011 15:39:04 +0200 (CEST) Subject: [pypy-commit] pypy default: new objects have a known class Message-ID: <20110707133904.7754A820AE@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45409:01e4f337b79a Date: 2011-07-07 15:47 +0200 http://bitbucket.org/pypy/pypy/changeset/01e4f337b79a/ Log: new objects have a known class diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -365,7 +365,9 @@ def opimpl_new_with_vtable(self, sizedescr): cpu = self.metainterp.cpu cls = heaptracker.descr2vtable(cpu, sizedescr) - return self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + resbox = self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + self.metainterp.known_class_boxes[resbox] = None + return resbox ## @FixME #arguments("box") ## def opimpl_runtimenew(self, classbox): diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1026,6 +1026,27 @@ pass class B(A): pass + a = A() + b = B() + def fn(n): + if n == -7: + obj = None + elif n: + obj = a + else: + obj = b + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass def fn(n): if n == -7: obj = None @@ -1036,7 +1057,7 @@ return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res == 4 - self.check_operations_history(guard_class=1, guard_nonnull=1) + self.check_operations_history(guard_class=0, guard_nonnull=0) res = self.interp_operations(fn, [1]) assert not res From noreply at buildbot.pypy.org Thu Jul 7 16:54:45 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 7 Jul 2011 16:54:45 +0200 (CEST) Subject: [pypy-commit] pypy default: unindented a line that shouldn't be indented in crc32 of the binascii module Message-ID: <20110707145445.8D639820AE@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45410:2d192eaab45f Date: 2011-07-06 13:49 -0600 http://bitbucket.org/pypy/pypy/changeset/2d192eaab45f/ Log: unindented a line that shouldn't be indented in crc32 of the binascii module diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 From noreply at buildbot.pypy.org Thu Jul 7 17:03:03 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 7 Jul 2011 17:03:03 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: small tweaks, and mention the video Message-ID: <20110707150303.21C61820AE@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: extradoc Changeset: r3827:158b8e73b74b Date: 2011-07-07 17:11 +0200 http://bitbucket.org/pypy/extradoc/changeset/158b8e73b74b/ Log: small tweaks, and mention the video diff --git a/blog/draft/realtime_image_processing.rst b/blog/draft/realtime_image_processing.rst --- a/blog/draft/realtime_image_processing.rst +++ b/blog/draft/realtime_image_processing.rst @@ -6,13 +6,11 @@ in Python is foolish: Python is clearly not fast enough for this task. Is it? :-) -.. image:: sobel.png - Actually, it turns out that the PyPy JIT compiler produces code which is fast enough to do realtime video processing using two simple algorithms implemented by Håkan Ardö. -sobel.py implements a classical way of locating edges in images, +``sobel.py`` implements a classical way of locating edges in images, `the Sobel operator`:http://en.wikipedia.org/wiki/Sobel_operator. It is an approximation of the magnitude of the `image gradient`:http://en.wikipedia.org/wiki/Image_gradient. The @@ -20,7 +18,7 @@ `convolutions`:http://en.wikipedia.org/wiki/Convolution between the image and 3x3-kernels. -magnify.py implements a pixel coordinate transformation that rearranges +``magnify.py`` implements a pixel coordinate transformation that rearranges the pixels in the image to form a magnifying effect in the center. It consists of a single loop over the pixels in the output image copying pixels from the input image. @@ -33,8 +31,8 @@ - `pypy-image-demo-full.tar.bz2`_: this archive contains both the source code and prebuilt PyPy binaries for linux 32 and 64 bits -.. `pypy-image-demo.tar.bz2`: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo.tar.bz2 -.. `pypy-image-demo-full.tar.bz2`: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo-full.tar.bz2 +.. _`pypy-image-demo.tar.bz2`: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo.tar.bz2 +.. _`pypy-image-demo-full.tar.bz2`: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo-full.tar.bz2 To run the demo, you need to have ``mplayer`` installed on your system. The demo has been tested only on linux, it might (or not) work also on other @@ -55,24 +53,26 @@ interpolation.`:http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation By adding the option -b, `bilinear interpolation`:http://en.wikipedia.org/wiki/Bilinear_interpolation -will be used instead, which gives smoother result. +will be used instead, which gives smoother result:: $ pypy demo/magnify.py -b There is only a single implementation of the algorithm in -magnify.py. The two different interpolation methods are implemented by +``magnify.py``. The two different interpolation methods are implemented by subclassing the class used to represent images and embed the interpolation within the pixel access method. PyPy is able to achieve good performance with this kind of abstractions because it can inline the pixel access method and specialize the implementation of the algorithm. In C++ that kind of pixel access method would be virtual and you'll need to use -templates to get the same effect. XXX: Is that correct? +templates to get the same effect without incurring in runtime overhead. -To have a feeling on how much PyPy is faster than CPython, try to run the demo -with the latter. These are the the average fps (frames per second) that I get -on my machine (Ubuntu 64 bit, Intel i7 920, 4GB RAM) when processing the -default ``test.avi`` video and using the prebuilt PyPy binary found in the -full_ tarball alinked above. For ``sobel.py``: +The video_ on the right shows PyPy and CPython running ``sobel.py`` side by +side (PyPy taking input from the webcam, CPython from the test +file). Alternatively, to have a feeling on how much PyPy is faster than +CPython, try to run the demo with the latter. These are the the average fps +(frames per second) that I get on my machine (Ubuntu 64 bit, Intel i7 920, 4GB +RAM) when processing the default ``test.avi`` video and using the prebuilt +PyPy binary found in the full_ tarball alinked above. For ``sobel.py``: - PyPy: ~47.23 fps - CPython: ~0.08 fps @@ -86,6 +86,7 @@ ``magnify.py`` the difference is much less evident and the speedup is "only" 15x. +.. _video: http://www.youtube.com/watch?v=5DtlBC_Zbq4 .. _full: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo-full.tar.bz2 It must be noted that this is an extreme example of what PyPy can do. In From noreply at buildbot.pypy.org Thu Jul 7 17:13:03 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 7 Jul 2011 17:13:03 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: rst-ify, and mention that you need at least pypy 1.5 Message-ID: <20110707151303.79CED820AE@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: extradoc Changeset: r3828:d30e46f175be Date: 2011-07-07 17:21 +0200 http://bitbucket.org/pypy/extradoc/changeset/d30e46f175be/ Log: rst-ify, and mention that you need at least pypy 1.5 diff --git a/blog/draft/realtime_image_processing.rst b/blog/draft/realtime_image_processing.rst --- a/blog/draft/realtime_image_processing.rst +++ b/blog/draft/realtime_image_processing.rst @@ -10,12 +10,9 @@ enough to do realtime video processing using two simple algorithms implemented by Håkan Ardö. -``sobel.py`` implements a classical way of locating edges in images, -`the Sobel operator`:http://en.wikipedia.org/wiki/Sobel_operator. It -is an approximation of the magnitude of the -`image gradient`:http://en.wikipedia.org/wiki/Image_gradient. The -processing time is spend on two -`convolutions`:http://en.wikipedia.org/wiki/Convolution between the +``sobel.py`` implements a classical way of locating edges in images, the +`Sobel operator`_. It is an approximation of the magnitude of the `image +gradient`_. The processing time is spend on two convolutions_ between the image and 3x3-kernels. ``magnify.py`` implements a pixel coordinate transformation that rearranges @@ -26,11 +23,14 @@ You can try by yourself by downloading the appropriate demo: - `pypy-image-demo.tar.bz2`_: this archive contains only the source code, - use this is you have PyPy already installed + use this is you have a recent version of PyPy (at least 1.5) already installed - `pypy-image-demo-full.tar.bz2`_: this archive contains both the source code and prebuilt PyPy binaries for linux 32 and 64 bits +.. _`Sobel operator`: http://en.wikipedia.org/wiki/Sobel_operator +.. _`image gradient`: http://en.wikipedia.org/wiki/Image_gradient +.. _convolutions: http://en.wikipedia.org/wiki/Convolution .. _`pypy-image-demo.tar.bz2`: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo.tar.bz2 .. _`pypy-image-demo-full.tar.bz2`: http://wyvern.cs.uni-duesseldorf.de/~antocuni/pypy-image-demo-full.tar.bz2 @@ -48,12 +48,9 @@ $ pypy demo/sobel.py tv:// -By default magnify.py uses -`nearest-neighbor -interpolation.`:http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation -By adding the option -b, -`bilinear interpolation`:http://en.wikipedia.org/wiki/Bilinear_interpolation -will be used instead, which gives smoother result:: +By default magnify.py uses `nearest-neighbor interpolation`_. By adding the +option -b, `bilinear interpolation`_ will be used instead, which gives +smoother result:: $ pypy demo/magnify.py -b @@ -66,6 +63,9 @@ In C++ that kind of pixel access method would be virtual and you'll need to use templates to get the same effect without incurring in runtime overhead. +.. _`nearest-neighbor interpolation`: http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation +.. _`bilinear interpolation`: http://en.wikipedia.org/wiki/Bilinear_interpolation + The video_ on the right shows PyPy and CPython running ``sobel.py`` side by side (PyPy taking input from the webcam, CPython from the test file). Alternatively, to have a feeling on how much PyPy is faster than From noreply at buildbot.pypy.org Thu Jul 7 23:19:22 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 7 Jul 2011 23:19:22 +0200 (CEST) Subject: [pypy-commit] pypy default: switch from using rffi to call memcpy form C to using rgc.ll_arraycopy (which works for non-gc arrays apparently) Message-ID: <20110707211922.D8D99820AE@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45411:5d2970523f79 Date: 2011-07-07 14:28 -0700 http://bitbucket.org/pypy/pypy/changeset/5d2970523f79/ Log: switch from using rffi to call memcpy form C to using rgc.ll_arraycopy (which works for non-gc arrays apparently) diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -11,12 +11,11 @@ from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.rgc import ll_arraycopy from pypy.rlib.unroll import unrolling_iterable from pypy.rpython.lltypesystem import lltype, rffi -memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) - @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): if len(__args__.arguments_w) > 1: @@ -621,10 +620,12 @@ def array_copy__Array(space, self): w_a = mytype.w_class(self.space) w_a.setlen(self.len) - memcpy( - rffi.cast(rffi.VOIDP, w_a.buffer), - rffi.cast(rffi.VOIDP, self.buffer), - self.len * mytype.bytes + ll_arraycopy( + self.buffer, + w_a.buffer, + 0, + 0, + self.len, ) return w_a From noreply at buildbot.pypy.org Fri Jul 8 03:23:11 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 8 Jul 2011 03:23:11 +0200 (CEST) Subject: [pypy-commit] pypy default: Backed out changeset 5d2970523f79, this breaks translation. Message-ID: <20110708012311.3D375820AE@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45412:3476b9be3cec Date: 2011-07-07 18:31 -0700 http://bitbucket.org/pypy/pypy/changeset/3476b9be3cec/ Log: Backed out changeset 5d2970523f79, this breaks translation. diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -11,11 +11,12 @@ from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all from pypy.rlib.rarithmetic import ovfcheck -from pypy.rlib.rgc import ll_arraycopy from pypy.rlib.unroll import unrolling_iterable from pypy.rpython.lltypesystem import lltype, rffi +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) + @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): if len(__args__.arguments_w) > 1: @@ -620,12 +621,10 @@ def array_copy__Array(space, self): w_a = mytype.w_class(self.space) w_a.setlen(self.len) - ll_arraycopy( - self.buffer, - w_a.buffer, - 0, - 0, - self.len, + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes ) return w_a From noreply at buildbot.pypy.org Fri Jul 8 10:56:39 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 8 Jul 2011 10:56:39 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove refernce to call likely builtin. Message-ID: <20110708085639.E12D3820AE@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45413:a48d1097f4d6 Date: 2011-07-08 02:05 -0700 http://bitbucket.org/pypy/pypy/changeset/a48d1097f4d6/ Log: Remove refernce to call likely builtin. diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -263,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects From noreply at buildbot.pypy.org Fri Jul 8 11:46:44 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 8 Jul 2011 11:46:44 +0200 (CEST) Subject: [pypy-commit] pypy default: Skip tests on 2.7 Message-ID: <20110708094644.9002E820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45414:133ea4067736 Date: 2011-07-08 11:54 +0200 http://bitbucket.org/pypy/pypy/changeset/133ea4067736/ Log: Skip tests on 2.7 diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,9 +1,8 @@ -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, Const -from pypy.tool.jitlogparser.parser import SimpleParser, TraceForOpcode, Function,\ - adjust_bridges +from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, + Function, adjust_bridges, + import_log) from pypy.tool.jitlogparser.storage import LoopStorage -import py +import py, sys def parse(input, **kwds): return SimpleParser.parse_from_input(input, **kwds) @@ -111,6 +110,8 @@ assert res.chunks[1].lineno == 3 def test_linerange(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] @@ -125,6 +126,8 @@ assert res.lineset == set([7, 8, 9]) def test_linerange_notstarts(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] From noreply at buildbot.pypy.org Fri Jul 8 11:46:45 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 8 Jul 2011 11:46:45 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110708094645.EE3CC82178@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45415:70d9564fe923 Date: 2011-07-08 11:55 +0200 http://bitbucket.org/pypy/pypy/changeset/70d9564fe923/ Log: merge diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -263,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -310,26 +310,27 @@ self.opimpl_goto_if_not(condbox, target) ''' % (_opimpl, _opimpl.upper())).compile() + + def _establish_nullity(self, box, orgpc): + value = box.nonnull() + if value: + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc) + else: + if not isinstance(box, Const): + self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + promoted_box = box.constbox() + self.metainterp.replace_box(box, promoted_box) + return value + @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_nonzero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if not value: + if not self._establish_nullity(box, orgpc): self.pc = target @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_iszero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if value: + if self._establish_nullity(box, orgpc): self.pc = target @arguments("box", "box", "box") @@ -364,7 +365,9 @@ def opimpl_new_with_vtable(self, sizedescr): cpu = self.metainterp.cpu cls = heaptracker.descr2vtable(cpu, sizedescr) - return self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + resbox = self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + self.metainterp.known_class_boxes[resbox] = None + return resbox ## @FixME #arguments("box") ## def opimpl_runtimenew(self, classbox): @@ -845,7 +848,9 @@ @arguments("orgpc", "box") def opimpl_guard_class(self, orgpc, box): clsbox = self.cls_of_box(box) - self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + self.metainterp.known_class_boxes[box] = None return clsbox @arguments("int", "orgpc") @@ -1449,6 +1454,8 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1789,6 +1796,8 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1021,6 +1021,69 @@ res = self.meta_interp(main, []) assert res == 55 + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + a = A() + b = B() + def fn(n): + if n == -7: + obj = None + elif n: + obj = a + else: + obj = b + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass From noreply at buildbot.pypy.org Fri Jul 8 13:25:48 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 8 Jul 2011 13:25:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Improve logging messages to match exactly the format used in logger Message-ID: <20110708112548.33E39820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45416:330224c355a1 Date: 2011-07-08 13:34 +0200 http://bitbucket.org/pypy/pypy/changeset/330224c355a1/ Log: Improve logging messages to match exactly the format used in logger diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -417,7 +417,7 @@ # rawstart = self.materialize_loop(looptoken) debug_start("jit-backend-addr") - debug_print("Loop #%d (%s) has address %x to %x (bootstrap %x)" % ( + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, rawstart + directbootstrappos, @@ -482,7 +482,7 @@ # rawstart = self.materialize_loop(original_loop_token) debug_start("jit-backend-addr") - debug_print("Bridge out of guard %d has address %x to %x" % + debug_print("Bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, From noreply at buildbot.pypy.org Fri Jul 8 13:40:46 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 8 Jul 2011 13:40:46 +0200 (CEST) Subject: [pypy-commit] pypy default: Write a simple parser of logs that returns loops Message-ID: <20110708114046.EE5DB820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45417:f88554cbc218 Date: 2011-07-08 13:49 +0200 http://bitbucket.org/pypy/pypy/changeset/f88554cbc218/ Log: Write a simple parser of logs that returns loops diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,7 +1,8 @@ import re, sys -from pypy.jit.metainterp.resoperation import rop, opname +from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser +from pypy.tool.logparser import parse_log_file, extract_category class Op(object): bridge = None @@ -57,7 +58,7 @@ use_mock_model = True def postprocess(self, loop, backend_dump=None, backend_tp=None, - loop_start=0, dump_start=0): + dump_start=0): if backend_dump is not None: raw_asm = self._asm_disassemble(backend_dump.decode('hex'), backend_tp, dump_start) @@ -329,3 +330,33 @@ res.append(op) i += 1 return res + + +def import_log(logname, ParserCls=SimpleParser): + log = parse_log_file(logname) + addrs = {} + for entry in extract_category(log, 'jit-backend-addr'): + m = re.search('bootstrap ([\da-f]+)', entry) + name = entry[:entry.find('(') - 1] + addrs[int(m.group(1), 16)] = name + dumps = {} + for entry in extract_category(log, 'jit-backend-dump'): + backend, _, dump, _ = entry.split("\n") + _, addr, _, data = re.split(" +", dump) + backend_name = backend.split(" ")[1] + addr = int(addr[1:], 16) + if addr in addrs: + dumps[addrs[addr]] = (backend_name, addr, data) + loops = [] + for entry in extract_category(log, 'jit-log-opt'): + parser = ParserCls(entry, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + comm = loop.comment + name = comm[2:comm.find(':')-1] + if name in dumps: + bname, start_ofs, dump = dumps[name] + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) + loops.append(loop) + return loops diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log --- a/pypy/tool/jitlogparser/test/logtest.log +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -4,7 +4,9 @@ SYS_EXECUTABLE python CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 [11f210b949b3] jit-backend-dump} -Loop #0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210b949b4] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab188] jit-backend-addr} [11f210bab189] jit-backend} [11f210bacbb7] {jit-log-opt-loop # Loop 0 : loop with 19 ops diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -204,9 +204,12 @@ +213: jump(p0, p1, p2, p3, i8, descr=) +218: --end of the loop--""", backend_dump=backend_dump, dump_start=dump_start, - backend_tp='x86_64', - loop_start=0x7f3b0b2e645d) + backend_tp='x86_64') cmp = loop.operations[1] assert 'jge' in cmp.asm assert '0x2710' in cmp.asm assert 'jmp' in loop.operations[-1].asm + +def test_import_log(): + loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) + assert 'jge' in loops[0].operations[3].asm From noreply at buildbot.pypy.org Fri Jul 8 13:45:40 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 8 Jul 2011 13:45:40 +0200 (CEST) Subject: [pypy-commit] jitviewer default: some cleanups Message-ID: <20110708114540.03089820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r137:5af601922365 Date: 2011-07-08 13:54 +0200 http://bitbucket.org/pypy/jitviewer/changeset/5af601922365/ Log: some cleanups diff --git a/bin/jitviewer.py b/bin/jitviewer.py --- a/bin/jitviewer.py +++ b/bin/jitviewer.py @@ -37,7 +37,6 @@ raise ImportError('Could not import pypy module, make sure to ' 'add the pypy module to PYTHONPATH') -import cgi import flask import inspect import threading @@ -50,15 +49,6 @@ from _jitviewer.display import CodeRepr, CodeReprNoFile import _jitviewer -from pygments import highlight -from pygments.lexers import PythonLexer -from pygments.formatters import HtmlFormatter - -from jinja2 import Environment, FileSystemLoader - -from werkzeug import Response -from flask.helpers import send_from_directory - CUTOFF = 30 class CannotFindFile(Exception): @@ -223,7 +213,7 @@ # # start the webkit browser in the main thread (actually, it's a subprocess) time.sleep(0.5) # give the server some time to start - ret = start_browser(url, filename) + start_browser(url, filename) finally: # shutdown the HTPP server and wait until it completes app.servers[0].shutdown() @@ -238,7 +228,10 @@ except Exception, e: print 'Cannot start the builtin browser: %s' % e print "Please point your browser to: %s" % url - raw_input("Press enter to quit and kill the server") + try: + raw_input("Press enter to quit and kill the server") + except KeyboardInterrupt: + pass if __name__ == '__main__': main() From noreply at buildbot.pypy.org Fri Jul 8 13:47:35 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 8 Jul 2011 13:47:35 +0200 (CEST) Subject: [pypy-commit] pypy default: also return log Message-ID: <20110708114735.78CCC820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45418:1c550f41f9d5 Date: 2011-07-08 13:56 +0200 http://bitbucket.org/pypy/pypy/changeset/1c550f41f9d5/ Log: also return log diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -359,4 +359,4 @@ parser.postprocess(loop, backend_tp=bname, backend_dump=dump, dump_start=start_ofs) loops.append(loop) - return loops + return log, loops diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -211,5 +211,6 @@ assert 'jmp' in loop.operations[-1].asm def test_import_log(): - loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest.log'))) assert 'jge' in loops[0].operations[3].asm From noreply at buildbot.pypy.org Fri Jul 8 15:22:23 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 8 Jul 2011 15:22:23 +0200 (CEST) Subject: [pypy-commit] jitviewer default: use new features to be able to display assembler, disabled by default Message-ID: <20110708132223.1F906820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r138:9156677f07b3 Date: 2011-07-08 15:31 +0200 http://bitbucket.org/pypy/jitviewer/changeset/9156677f07b3/ Log: use new features to be able to display assembler, disabled by default diff --git a/_jitviewer/static/script.js b/_jitviewer/static/script.js --- a/_jitviewer/static/script.js +++ b/_jitviewer/static/script.js @@ -18,6 +18,7 @@ var elem = arg.callstack[index]; $('#callstack').append('"); } + $(".asm").hide(); }); } @@ -57,9 +58,17 @@ }); } -function toggle() +function toggle(name, clsname, v) { - $('.operations').toggle(); + var e = $("#" + name); + var e2 = $("." + clsname); + if (e.html().search("Show") != -1) { + e.html("Hide " + v); + e2.show(); + } else { + e.html("Show " + v); + e2.hide(); + } } function highlight_var(elem) diff --git a/_jitviewer/static/style.css b/_jitviewer/static/style.css --- a/_jitviewer/static/style.css +++ b/_jitviewer/static/style.css @@ -141,6 +141,12 @@ margin-left: 3em; } +.asm { + white-space: pre; + margin-left: 4em; + color: #bbb; +} + .inlined_call { font-size: 12px; font-weight: bold; diff --git a/_jitviewer/templates/index.html b/_jitviewer/templates/index.html --- a/_jitviewer/templates/index.html +++ b/_jitviewer/templates/index.html @@ -17,7 +17,8 @@
Menu
- Toggle operations + Hide operations
+ Show assembler
diff --git a/_jitviewer/templates/loop.html b/_jitviewer/templates/loop.html --- a/_jitviewer/templates/loop.html +++ b/_jitviewer/templates/loop.html @@ -15,6 +15,9 @@ {{op.html_repr()}} >>show bridge (taken {{op.percentage}}%)
{% else %} {{op.html_repr()}}
+ {% if op.asm %} +

{{op.asm}}

+ {% endif %} {% endif %} {% endfor %} {% else %} diff --git a/bin/jitviewer.py b/bin/jitviewer.py --- a/bin/jitviewer.py +++ b/bin/jitviewer.py @@ -43,7 +43,7 @@ import time from pypy.tool.logparser import parse_log_file, extract_category from pypy.tool.jitlogparser.storage import LoopStorage -from pypy.tool.jitlogparser.parser import adjust_bridges +from pypy.tool.jitlogparser.parser import adjust_bridges, import_log # from _jitviewer.parser import ParserWithHtmlRepr, FunctionHtml, parse_log_counts from _jitviewer.display import CodeRepr, CodeReprNoFile @@ -180,15 +180,13 @@ print __doc__ sys.exit(1) filename = sys.argv[1] - log = parse_log_file(filename) extra_path = os.path.dirname(filename) if len(sys.argv) != 3: port = 5000 else: port = int(sys.argv[2]) storage = CheckingLoopStorage(extra_path) - loops = [ParserWithHtmlRepr.parse_from_input(l) - for l in extract_category(log, "jit-log-opt-")] + log, loops = import_log(filename, ParserWithHtmlRepr) parse_log_counts(extract_category(log, 'jit-backend-count'), loops) storage.reconnect_loops(loops) app = OverrideFlask('__name__', root_path=PATH) From noreply at buildbot.pypy.org Fri Jul 8 15:31:07 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 8 Jul 2011 15:31:07 +0200 (CEST) Subject: [pypy-commit] jitviewer default: minor fixes Message-ID: <20110708133107.BDD11820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r139:1f2e5273f980 Date: 2011-07-08 15:39 +0200 http://bitbucket.org/pypy/jitviewer/changeset/1f2e5273f980/ Log: minor fixes diff --git a/_jitviewer/static/script.js b/_jitviewer/static/script.js --- a/_jitviewer/static/script.js +++ b/_jitviewer/static/script.js @@ -19,6 +19,8 @@ $('#callstack').append('"); } $(".asm").hide(); + $('#asmtoggler').html("Show assembler"); + $('#optoggler').html("Hide operations"); }); } diff --git a/_jitviewer/static/style.css b/_jitviewer/static/style.css --- a/_jitviewer/static/style.css +++ b/_jitviewer/static/style.css @@ -144,7 +144,7 @@ .asm { white-space: pre; margin-left: 4em; - color: #bbb; + color: #666; } .inlined_call { From noreply at buildbot.pypy.org Fri Jul 8 15:36:39 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 8 Jul 2011 15:36:39 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: merge default Message-ID: <20110708133639.5EE56820AE@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45419:f152b2c48f65 Date: 2011-07-08 15:45 +0200 http://bitbucket.org/pypy/pypy/changeset/f152b2c48f65/ Log: merge default diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,6 +1,7 @@ syntax: glob *.py[co] *~ +.*.swp syntax: regexp ^testresult$ @@ -38,6 +39,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4400,7 +4400,10 @@ self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) + if hasattr(l.__add__, '__objclass__'): # CPython + self.assertTrue(l.__add__.__objclass__ is list) + else: # PyPy + self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -139,7 +139,10 @@ return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -218,5 +221,7 @@ 'z' : _ffi.types.void_p, 'O' : _ffi.types.void_p, 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, } diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -322,20 +322,18 @@ RuntimeWarning, stacklevel=2) if self._com_index: - assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None - - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -343,6 +341,11 @@ if not outargs: return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + if len(outargs) == 1: return outargs[0] return tuple(outargs) @@ -398,10 +401,10 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) cdll = self.dll._handle try: @@ -468,11 +471,7 @@ newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -587,13 +586,7 @@ retval = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, argsandobjs[0]) - else: - retval = int(resbuffer[0]) - elif restype is not None: + if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) @@ -601,7 +594,13 @@ # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value - retval = checker(val) + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) else: diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -216,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -357,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -385,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -129,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -266,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -355,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -248,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -26,13 +30,6 @@ Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ @@ -289,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -237,7 +237,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1060,18 +1060,6 @@ def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -210,19 +210,20 @@ def m(self): "aaa" m.x = 3 + class B(A): + pass - bm = A().m + bm = B().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self - assert bm.im_class is A - if '__pypy__' in sys.builtin_module_names: - assert bm.__objclass__ is A + assert bm.im_class is B assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) l = [] assert l.append.__self__ is l - if '__pypy__' in sys.builtin_module_names: - assert l.append.__objclass__ is list assert l.__add__.__self__ is l - assert l.__add__.__objclass__ is list + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -771,7 +771,6 @@ im_self = interp_attrproperty_w('w_instance', cls=Method), __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), - __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -415,12 +415,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_start("jit-backend") - debug_print("Loop #%d (%s) has address %x to %x" % ( + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) - debug_stop("jit-backend") + rawstart + directbootstrappos, + rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -479,9 +480,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d has address %x to %x" % + debug_start("jit-backend-addr") + debug_print("Bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -92,7 +92,7 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -870,7 +870,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1351,13 +1351,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1403,7 +1403,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -123,7 +123,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -203,13 +203,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -220,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -431,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt @@ -34,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -57,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -382,6 +375,18 @@ v1.intbound.make_gt(IntBound(0, 0)) self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -428,5 +433,6 @@ propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile @@ -434,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -569,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -477,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -439,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] @@ -4123,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5373,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -1021,6 +1021,69 @@ res = self.meta_interp(main, []) assert res == 55 + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + a = A() + b = B() + def fn(n): + if n == -7: + obj = None + elif n: + obj = a + else: + obj = b + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass @@ -1252,7 +1315,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1375,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1406,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1440,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1559,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1594,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1658,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1676,8 +1739,8 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) - self.check_loops(getarrayitem_gc=8, everywhere=True) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) @@ -1817,7 +1880,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2002,7 +2065,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2047,7 +2110,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2082,7 +2145,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2139,7 +2202,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2208,7 +2271,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2313,6 +2377,67 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + def test_retrace_ending_up_retrazing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -237,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -337,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -631,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -186,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -207,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -240,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,21 @@ from __future__ import with_statement +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -37,7 +40,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -73,6 +76,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +100,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +163,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -268,12 +270,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -311,6 +311,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -319,12 +327,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -387,7 +390,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -395,7 +398,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -413,7 +416,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -515,14 +518,14 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() @@ -615,6 +618,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) + return w_a + def array_byteswap__Array(space, self): if mytype.bytes not in [1, 2, 4, 8]: msg = "byteswap not supported for this array" diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -799,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -829,8 +828,6 @@ return struct.unpack(') i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) def test_stararg(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py @@ -0,0 +1,82 @@ +# unittest for SOME ctypes com function calls. +# Can't resist from implementing some kind of mini-comtypes +# theller ;-) + +import py +import sys +if sys.platform != "win32": + py.test.skip('windows only test') + +import ctypes, new, unittest +from ctypes.wintypes import HRESULT +from _ctypes import COMError + +oleaut32 = ctypes.OleDLL("oleaut32") + +class UnboundMethod(object): + def __init__(self, func, index, name): + self.func = func + self.index = index + self.name = name + self.__doc__ = func.__doc__ + + def __repr__(self): + return "" % (self.index, self.name, id(self)) + + def __get__(self, instance, owner): + if instance is None: + return self + return new.instancemethod(self.func, instance, owner) + +def commethod(index, restype, *argtypes): + """A decorator that generates COM methods. The decorated function + itself is not used except for it's name.""" + def make_commethod(func): + comfunc = ctypes.WINFUNCTYPE(restype, *argtypes)(index, func.__name__) + comfunc.__name__ = func.__name__ + comfunc.__doc__ = func.__doc__ + return UnboundMethod(comfunc, index, func.__name__) + return make_commethod + +class ICreateTypeLib2(ctypes.c_void_p): + + @commethod(1, ctypes.c_long) + def AddRef(self): + pass + + @commethod(2, ctypes.c_long) + def Release(self): + pass + + @commethod(4, HRESULT, ctypes.c_wchar_p) + def SetName(self): + """Set the name of the library.""" + + @commethod(12, HRESULT) + def SaveAllChanges(self): + pass + + +CreateTypeLib2 = oleaut32.CreateTypeLib2 +CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, ctypes.POINTER(ICreateTypeLib2)) + +################################################################ + +def test_basic_comtypes(): + punk = ICreateTypeLib2() + hr = CreateTypeLib2(0, "foobar.tlb", punk) + assert hr == 0 + + assert 2 == punk.AddRef() + assert 3 == punk.AddRef() + assert 4 == punk.AddRef() + + punk.SetName("TypeLib_ByPYPY") + py.test.raises(COMError, lambda: punk.SetName(None)) + + # This would save the typelib to disk. + ## punk.SaveAllChanges() + + assert 3 == punk.Release() + assert 2 == punk.Release() + assert 1 == punk.Release() diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + w_dict = jit.promote(w_dict) + self = jit.promote(self) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + @jit.elidable + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,91 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -5,15 +5,16 @@ from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS -from pypy.rlib.objectmodel import r_dict, we_are_translated +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize from pypy.rlib.debug import mark_dict_non_null +from pypy.rlib import rerased + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -29,49 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w, - force_non_null=True) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -90,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -142,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -151,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -161,106 +140,90 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + self.switch_to_object_strategy(w_dict) - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_length(self): - return len(self.r_dict_content) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError + def length(self, w_dict): + return 0 -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) + def clear(self, w_dict): + return -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -302,322 +265,255 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = {} - mark_dict_non_null(self.content) +class AbstractTypedStrategy(object): + _mixin_ = True - def impl_setitem(self, w_key, w_value): + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, key, w_value): - assert key is not None - self.content[key] = w_value + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] return - elif _is_sane_hash(space, w_key_type): - raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) - def impl_length(self): - return len(self.content) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) - def impl_getitem_str(self, key): + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) + + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return ObjectIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + + def setitem_str(self, w_dict, key, w_value): assert key is not None - return self.content.get(key, None) + self.unerase(w_dict.dstorage)[key] = w_value - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().impl_fallback_getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) - def impl_delitem(self, w_key): + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) + return space.is_w(space.type(w_obj), space.w_int) - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) -class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): +class IntIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - + return None, None init_signature = Signature(['seq_or_map'], None, 'kwargs') @@ -924,7 +820,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,121 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): @@ -322,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) @@ -29,3 +38,33 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -137,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -176,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -195,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -233,8 +234,33 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2: 2, "c": 3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l + def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -267,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -297,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -316,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -366,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} @@ -527,6 +549,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +734,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +749,64 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -759,6 +847,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj @@ -790,6 +882,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +895,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +927,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1012,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1027,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1071,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1083,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1104,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,20 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) + + def test_slot_name_conflict(self): class A(object): @@ -604,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: @@ -447,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec @@ -277,12 +292,13 @@ 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -337,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -575,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -592,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -74,7 +74,7 @@ raise KeyError @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) @@ -253,7 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -850,10 +850,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -862,8 +868,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,8 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - # it's pure but it does not look like it - @purefunction + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -342,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -352,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -370,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -387,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -428,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -451,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -471,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -487,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -504,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -516,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -527,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -595,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -718,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -816,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -831,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -842,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -256,10 +256,6 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - class Cls(self.AddressStack): - def append(self2, addr): - assert addr not in self2.tolist() - self.AddressStack.append(self2, addr) self.objects_pointing_to_young = self.AddressStack() # # Similar to 'objects_pointing_to_young', but lists objects diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/rpython/ootypesystem/test/test_oopbc.py b/pypy/rpython/ootypesystem/test/test_oopbc.py --- a/pypy/rpython/ootypesystem/test/test_oopbc.py +++ b/pypy/rpython/ootypesystem/test/test_oopbc.py @@ -81,3 +81,18 @@ res = interpret(f, [1], type_system='ootype') assert res == 2 +def test_quasi_immutable(): + class A(object): + _immutable_fields_ = ['x?'] + def __init__(self): + self.x = 3 + def foo(self): + return self.x + + a = A() + + def f(): + return a.foo() + + res = interpret(f, [], type_system='ootype') + assert res == 3 diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,30 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] + class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): def func(i): diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,10 +1,13 @@ import re, sys -from pypy.jit.metainterp.resoperation import rop, opname +from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser +from pypy.tool.logparser import parse_log_file, extract_category class Op(object): bridge = None + offset = None + asm = None def __init__(self, name, args, res, descr): self.name = name @@ -54,10 +57,53 @@ Op = Op use_mock_model = True + def postprocess(self, loop, backend_dump=None, backend_tp=None, + dump_start=0): + if backend_dump is not None: + raw_asm = self._asm_disassemble(backend_dump.decode('hex'), + backend_tp, dump_start) + asm = [] + start = 0 + for elem in raw_asm: + if len(elem.split("\t")) != 3: + continue + adr, _, v = elem.split("\t") + if not start: + start = int(adr.strip(":"), 16) + ofs = int(adr.strip(":"), 16) - start + if ofs >= 0: + asm.append((ofs, v.strip("\n"))) + asm_index = 0 + for i, op in enumerate(loop.operations): + end = 0 + j = i + 1 + while end == 0: + if j == len(loop.operations): + end = loop.last_offset + break + if loop.operations[j].offset is None: + j += 1 + else: + end = loop.operations[j].offset + if op.offset is not None: + while asm[asm_index][0] < op.offset: + asm_index += 1 + end_index = asm_index + while asm[end_index][0] < end: + end_index += 1 + op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) + return loop + + def _asm_disassemble(self, d, origin_addr, tp): + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + return list(machine_code_dump(d, tp, origin_addr)) + @classmethod - def parse_from_input(cls, input): - return cls(input, None, {}, 'lltype', None, - nonstrict=True).parse() + def parse_from_input(cls, input, **kwds): + parser = cls(input, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + return parser.postprocess(loop, **kwds) def parse_args(self, opname, argspec): if not argspec.strip(): @@ -284,3 +330,33 @@ res.append(op) i += 1 return res + + +def import_log(logname, ParserCls=SimpleParser): + log = parse_log_file(logname) + addrs = {} + for entry in extract_category(log, 'jit-backend-addr'): + m = re.search('bootstrap ([\da-f]+)', entry) + name = entry[:entry.find('(') - 1] + addrs[int(m.group(1), 16)] = name + dumps = {} + for entry in extract_category(log, 'jit-backend-dump'): + backend, _, dump, _ = entry.split("\n") + _, addr, _, data = re.split(" +", dump) + backend_name = backend.split(" ")[1] + addr = int(addr[1:], 16) + if addr in addrs: + dumps[addrs[addr]] = (backend_name, addr, data) + loops = [] + for entry in extract_category(log, 'jit-log-opt'): + parser = ParserCls(entry, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + comm = loop.comment + name = comm[2:comm.find(':')-1] + if name in dumps: + bname, start_ofs, dump = dumps[name] + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) + loops.append(loop) + return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -0,0 +1,38 @@ +[11f210b47027] {jit-backend +[11f210b900f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 +[11f210b949b3] jit-backend-dump} +[11f210b949b4] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab188] jit-backend-addr} +[11f210bab189] jit-backend} +[11f210bacbb7] {jit-log-opt-loop +# Loop 0 : loop with 19 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 INPLACE_ADD') ++179: i8 = int_add(i4, 1) +debug_merge_point(0, ' #28 STORE_FAST') +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++183: i10 = getfield_raw(40564608, descr=) ++191: i12 = int_sub(i10, 1) ++195: setfield_raw(40564608, i12, descr=) ++203: i14 = int_lt(i12, 0) +guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++213: jump(p0, p1, p2, p3, i8, descr=) ++218: --end of the loop-- +[11f210c17981] jit-log-opt-loop} +[11f210fb1d21] {jit-backend-counts +0:8965 +1:2 +[11f210fb381b] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,12 +1,11 @@ -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, Const -from pypy.tool.jitlogparser.parser import SimpleParser, TraceForOpcode, Function,\ - adjust_bridges +from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, + Function, adjust_bridges, + import_log) from pypy.tool.jitlogparser.storage import LoopStorage -import py +import py, sys -def parse(input): - return SimpleParser.parse_from_input(input) +def parse(input, **kwds): + return SimpleParser.parse_from_input(input, **kwds) def test_parse(): @@ -111,6 +110,8 @@ assert res.chunks[1].lineno == 3 def test_linerange(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] @@ -125,6 +126,8 @@ assert res.lineset == set([7, 8, 9]) def test_linerange_notstarts(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] @@ -179,3 +182,35 @@ ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] assert chunk.bytecode_name == 'StrLiteralSearch' + +def test_parsing_assembler(): + backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" + dump_start = 0x7f3b0b2e63d5 + loop = parse(""" + # Loop 0 : loop with 19 ops + [p0, p1, p2, p3, i4] + debug_merge_point(0, ' #15 COMPARE_OP') + +166: i6 = int_lt(i4, 10000) + guard_true(i6, descr=) [p1, p0, p2, p3, i4] + debug_merge_point(0, ' #27 INPLACE_ADD') + +179: i8 = int_add(i4, 1) + debug_merge_point(0, ' #31 JUMP_ABSOLUTE') + +183: i10 = getfield_raw(40564608, descr=) + +191: i12 = int_sub(i10, 1) + +195: setfield_raw(40564608, i12, descr=) + +203: i14 = int_lt(i12, 0) + guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] + debug_merge_point(0, ' #9 LOAD_FAST') + +213: jump(p0, p1, p2, p3, i8, descr=) + +218: --end of the loop--""", backend_dump=backend_dump, + dump_start=dump_start, + backend_tp='x86_64') + cmp = loop.operations[1] + assert 'jge' in cmp.asm + assert '0x2710' in cmp.asm + assert 'jmp' in loop.operations[-1].asm + +def test_import_log(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest.log'))) + assert 'jge' in loops[0].operations[3].asm diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -83,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -186,7 +186,7 @@ print "\n\nTarget specific help:\n\n" targetspec_dic['print_help'](config) print "\n\nFor detailed descriptions of the command line options see" - print "http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html" + print "http://pypy.readthedocs.org/en/latest/config/commandline.html" sys.exit(0) return targetspec_dic, translateconfig, config, args diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,12 +964,15 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" From noreply at buildbot.pypy.org Fri Jul 8 18:56:45 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Fri, 8 Jul 2011 18:56:45 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: Merge with default Message-ID: <20110708165645.18002820AE@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45420:d5660c58c30e Date: 2011-07-05 19:17 +0200 http://bitbucket.org/pypy/pypy/changeset/d5660c58c30e/ Log: Merge with default diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,6 +1,7 @@ syntax: glob *.py[co] *~ +.*.swp syntax: regexp ^testresult$ @@ -38,6 +39,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,13 +4399,10 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__self__ is l) + if hasattr(l.__add__, '__objclass__'): # CPython self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) + else: # PyPy self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -139,7 +139,10 @@ return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -218,5 +221,7 @@ 'z' : _ffi.types.void_p, 'O' : _ffi.types.void_p, 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, } diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -322,20 +322,18 @@ RuntimeWarning, stacklevel=2) if self._com_index: - assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None - - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -343,6 +341,11 @@ if not outargs: return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + if len(outargs) == 1: return outargs[0] return tuple(outargs) @@ -398,10 +401,10 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) cdll = self.dll._handle try: @@ -468,11 +471,7 @@ newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -587,13 +586,7 @@ retval = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, argsandobjs[0]) - else: - retval = int(resbuffer[0]) - elif restype is not None: + if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) @@ -601,7 +594,13 @@ # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value - retval = checker(val) + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) else: diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -216,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -299,12 +299,13 @@ listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) @@ -351,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -379,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -129,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -266,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -355,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -248,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -237,7 +237,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1060,18 +1060,6 @@ def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -205,16 +205,25 @@ raises(OSError, os.lseek, fd, 7, 0) def test_method_attrs(self): + import sys class A(object): def m(self): "aaa" m.x = 3 + class B(A): + pass - bm = A().m + bm = B().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self - assert bm.__objclass__ is bm.im_class is A + assert bm.im_class is B assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) - assert [].append.__objclass__ is list \ No newline at end of file + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -771,7 +771,6 @@ im_self = interp_attrproperty_w('w_instance', cls=Method), __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), - __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -895,7 +895,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -907,7 +907,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -561,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -239,7 +239,7 @@ # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -92,7 +92,7 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -847,7 +847,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1328,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1380,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -119,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -633,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -203,13 +203,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -220,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -431,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt @@ -34,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -57,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -382,6 +375,18 @@ v1.intbound.make_gt(IntBound(0, 0)) self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -428,5 +433,6 @@ propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile @@ -434,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -569,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -477,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -439,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] @@ -4123,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5373,7 +5373,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jdindex, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -914,8 +914,10 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jd_index, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation + loc = jitdriver_sd.warmstate.get_location_str(greenkey) + debug_print(loc) args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @@ -1231,7 +1233,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -1252,7 +1252,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1312,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1343,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1377,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1496,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1531,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1595,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1676,8 +1676,8 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) - self.check_loops(getarrayitem_gc=8, everywhere=True) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) @@ -1817,7 +1817,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2002,7 +2002,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2047,7 +2047,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2082,7 +2082,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2139,7 +2139,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2208,7 +2208,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2313,6 +2314,67 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + def test_retrace_ending_up_retrazing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -237,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -631,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -186,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -207,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -240,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -235,7 +235,7 @@ argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,21 @@ from __future__ import with_statement +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -37,7 +40,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -73,6 +76,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +100,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +163,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -268,12 +270,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -311,6 +311,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -319,12 +327,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -387,7 +390,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -395,7 +398,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -413,7 +416,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -515,14 +518,14 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() @@ -615,6 +618,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) + return w_a + def array_byteswap__Array(space, self): if mytype.bytes not in [1, 2, 4, 8]: msg = "byteswap not supported for this array" diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -562,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -799,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -829,8 +828,6 @@ return struct.unpack(') i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) def test_stararg(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py @@ -0,0 +1,82 @@ +# unittest for SOME ctypes com function calls. +# Can't resist from implementing some kind of mini-comtypes +# theller ;-) + +import py +import sys +if sys.platform != "win32": + py.test.skip('windows only test') + +import ctypes, new, unittest +from ctypes.wintypes import HRESULT +from _ctypes import COMError + +oleaut32 = ctypes.OleDLL("oleaut32") + +class UnboundMethod(object): + def __init__(self, func, index, name): + self.func = func + self.index = index + self.name = name + self.__doc__ = func.__doc__ + + def __repr__(self): + return "" % (self.index, self.name, id(self)) + + def __get__(self, instance, owner): + if instance is None: + return self + return new.instancemethod(self.func, instance, owner) + +def commethod(index, restype, *argtypes): + """A decorator that generates COM methods. The decorated function + itself is not used except for it's name.""" + def make_commethod(func): + comfunc = ctypes.WINFUNCTYPE(restype, *argtypes)(index, func.__name__) + comfunc.__name__ = func.__name__ + comfunc.__doc__ = func.__doc__ + return UnboundMethod(comfunc, index, func.__name__) + return make_commethod + +class ICreateTypeLib2(ctypes.c_void_p): + + @commethod(1, ctypes.c_long) + def AddRef(self): + pass + + @commethod(2, ctypes.c_long) + def Release(self): + pass + + @commethod(4, HRESULT, ctypes.c_wchar_p) + def SetName(self): + """Set the name of the library.""" + + @commethod(12, HRESULT) + def SaveAllChanges(self): + pass + + +CreateTypeLib2 = oleaut32.CreateTypeLib2 +CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, ctypes.POINTER(ICreateTypeLib2)) + +################################################################ + +def test_basic_comtypes(): + punk = ICreateTypeLib2() + hr = CreateTypeLib2(0, "foobar.tlb", punk) + assert hr == 0 + + assert 2 == punk.AddRef() + assert 3 == punk.AddRef() + assert 4 == punk.AddRef() + + punk.SetName("TypeLib_ByPYPY") + py.test.raises(COMError, lambda: punk.SetName(None)) + + # This would save the typelib to disk. + ## punk.SaveAllChanges() + + assert 3 == punk.Release() + assert 2 == punk.Release() + assert 1 == punk.Release() diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + w_dict = jit.promote(w_dict) + self = jit.promote(self) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + @jit.elidable + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,91 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,18 +1,20 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS -from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize +from pypy.rlib.debug import mark_dict_non_null + +from pypy.rlib import rerased def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -28,48 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -88,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -140,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -149,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -159,106 +140,90 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + self.switch_to_object_strategy(w_dict) - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_length(self): - return len(self.r_dict_content) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError + def length(self, w_dict): + return 0 -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) + def clear(self, w_dict): + return -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -300,319 +265,255 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = {} +class AbstractTypedStrategy(object): + _mixin_ = True - def impl_setitem(self, w_key, w_value): + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, key, w_value): - self.content[key] = w_value + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] return - elif _is_sane_hash(space, w_key_type): - raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) - def impl_length(self): - return len(self.content) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) - def impl_getitem_str(self, key): - return self.content.get(key, None) + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return ObjectIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + + def setitem_str(self, w_dict, key, w_value): + assert key is not None + self.unerase(w_dict.dstorage)[key] = w_value + + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().impl_fallback_getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) - def impl_delitem(self, w_key): + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) + return space.is_w(space.type(w_obj), space.w_int) - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) -class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): +class IntIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - + return None, None init_signature = Signature(['seq_or_map'], None, 'kwargs') @@ -919,7 +820,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,121 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen, is_valid_int from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): @@ -322,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) @@ -29,3 +38,33 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -137,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -176,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -195,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -233,8 +234,33 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2: 2, "c": 3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l + def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -267,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -297,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -316,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -366,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} @@ -527,6 +549,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +734,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +749,64 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -759,6 +847,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj @@ -790,6 +882,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +895,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +927,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1012,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1027,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1071,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1083,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1104,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,20 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) + + def test_slot_name_conflict(self): class A(object): @@ -604,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: @@ -447,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec @@ -277,12 +292,13 @@ 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -337,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -575,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -592,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -40,7 +40,7 @@ del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. @@ -74,7 +74,7 @@ raise KeyError @staticmethod - @jit.purefunction + @jit.elidable def is_struct(ffi_type): return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) @@ -253,7 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. - self = jit.hint(self, promote=True) + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -49,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -272,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -478,12 +478,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) @@ -833,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -845,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -56,7 +56,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -88,8 +88,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted, dont_look_inside +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,8 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - # it's pure but it does not look like it - @purefunction + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -342,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -352,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -370,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -387,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -428,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -451,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -471,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -487,7 +486,7 @@ return True - @purefunction + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -504,7 +503,7 @@ return True - @purefunction + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -516,7 +515,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -527,7 +526,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -595,7 +594,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -718,7 +717,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -816,7 +815,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -831,7 +830,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -842,7 +841,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,23 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + class Cls(self.AddressStack): + def append(self2, addr): + assert addr not in self2.tolist() + self.AddressStack.append(self2, addr) + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +637,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +655,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +698,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +789,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +882,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +922,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,11 +933,11 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded self.remember_young_pointer_from_array2(addr_array, index) else: @@ -943,20 +955,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -980,16 +995,18 @@ # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,9 +1019,7 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return @@ -1016,7 +1031,7 @@ addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True @@ -1026,9 +1041,6 @@ # xxx trying it out for the JIT: a 3-arguments version of the above def remember_young_pointer_from_array3(addr_array, index, newvalue): - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") objhdr = self.header(addr_array) # # a single check for the common case of neither GCFLAG_HAS_CARDS @@ -1044,8 +1056,8 @@ else: # case with cards. # - # If the newly written address does not actually point to the - # nursery, leave now. + # If the newly written address does not actually point to a + # young object, leave now. if not self.appears_to_be_young(newvalue): return # @@ -1056,46 +1068,53 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + \ - (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True assert self.card_page_indices > 0 self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1103,18 +1122,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if source_hdr.tid & GCFLAG_CARDS_SET != 0: - # there might be young objects, let ll_arraycopy find them - return False + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True # - if source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1122,6 +1159,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1138,20 +1191,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1184,7 +1245,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1192,7 +1253,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1208,11 +1269,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1248,19 +1309,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1299,7 +1371,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1346,11 +1430,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -539,27 +539,61 @@ hdr_src = self.gc.header(addr_src) hdr_dst = self.gc.header(addr_dst) # - assert hdr_src.tid & minimark.GCFLAG_NO_YOUNG_PTRS - assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS # - res = self.gc.writebarrier_before_copy(addr_src, addr_dst) + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) assert res - assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS # - hdr_src.tid &= ~minimark.GCFLAG_NO_YOUNG_PTRS # pretend we have young ptrs - res = self.gc.writebarrier_before_copy(addr_src, addr_dst) + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) assert res # we optimized it - assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS == 0 # and we copied the flag + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag # - # in this case, we have cards, so GCFLAG_NO_YOUNG_PTRS is set (because - # cards takes precedence over it) - hdr_src.tid |= minimark.GCFLAG_NO_YOUNG_PTRS - hdr_dst.tid |= minimark.GCFLAG_NO_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS hdr_src.tid |= minimark.GCFLAG_CARDS_SET - res = self.gc.writebarrier_before_copy(addr_src, addr_dst) + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) assert not res # there might be young ptrs, let ll_arraycopy to find them - assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS - + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -884,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/ootypesystem/test/test_oopbc.py b/pypy/rpython/ootypesystem/test/test_oopbc.py --- a/pypy/rpython/ootypesystem/test/test_oopbc.py +++ b/pypy/rpython/ootypesystem/test/test_oopbc.py @@ -81,3 +81,18 @@ res = interpret(f, [1], type_system='ootype') assert res == 2 +def test_quasi_immutable(): + class A(object): + _immutable_fields_ = ['x?'] + def __init__(self): + self.x = 3 + def foo(self): + return self.x + + a = A() + + def f(): + return a.foo() + + res = interpret(f, [], type_system='ootype') + assert res == 3 diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,29 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): @@ -860,6 +883,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -121,6 +121,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -220,6 +223,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -168,7 +168,7 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -83,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -186,7 +186,7 @@ print "\n\nTarget specific help:\n\n" targetspec_dic['print_help'](config) print "\n\nFor detailed descriptions of the command line options see" - print "http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html" + print "http://pypy.readthedocs.org/en/latest/config/commandline.html" sys.exit(0) return targetspec_dic, translateconfig, config, args diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,12 +964,15 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" From noreply at buildbot.pypy.org Fri Jul 8 18:56:46 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Fri, 8 Jul 2011 18:56:46 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: test_ll2ctypes.py works, only test_errno not yet. Message-ID: <20110708165646.5587E820AE@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45421:2acf01fa3075 Date: 2011-07-08 18:58 +0200 http://bitbucket.org/pypy/pypy/changeset/2acf01fa3075/ Log: test_ll2ctypes.py works, only test_errno not yet. temporarily disabled for win64. diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -717,6 +717,8 @@ assert not ALLOCATED # detects memory leaks in the test def test_get_errno(self): + if is_emulated_long: + py.test.skip("skipped temporarily, no idea yet what the error is!") eci = ExternalCompilationInfo(includes=['string.h']) if sys.platform.startswith('win'): underscore_on_windows = '_' @@ -927,7 +929,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_varsized_struct(self): - S = lltype.Struct('S', ('x', rffi.LONG), + S = lltype.Struct('S', ('x', lltype.Signed), ('a', lltype.Array(lltype.Char))) s1 = lltype.malloc(S, 6, flavor='raw') s1.x = 5 @@ -950,7 +952,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_with_explicit_length(self): - A = lltype.Array(rffi.LONG) + A = lltype.Array(lltype.Signed) a1 = lltype.malloc(A, 5, flavor='raw') a1[0] = 42 c1 = lltype2ctypes(a1, normalize=False) @@ -1053,7 +1055,7 @@ NODE = lltype.GcStruct('NODE') node = lltype.malloc(NODE) ref = lltype.cast_opaque_ptr(llmemory.GCREF, node) - back = rffi.cast(llmemory.GCREF, rffi.cast(rffi.LONG, ref)) + back = rffi.cast(llmemory.GCREF, rffi.cast(lltype.Signed, ref)) assert lltype.cast_opaque_ptr(lltype.Ptr(NODE), back) == node def test_gcref_forth_and_back(self): @@ -1080,12 +1082,12 @@ def test_cast_null_gcref(self): ref = lltype.nullptr(llmemory.GCREF.TO) - value = rffi.cast(rffi.LONG, ref) + value = rffi.cast(lltype.Signed, ref) assert value == 0 def test_cast_null_fakeaddr(self): ref = llmemory.NULL - value = rffi.cast(rffi.LONG, ref) + value = rffi.cast(lltype.Signed, ref) assert value == 0 def test_gcref_truth(self): @@ -1110,8 +1112,8 @@ node = lltype.malloc(NODE) ref1 = lltype.cast_opaque_ptr(llmemory.GCREF, node) - intval = rffi.cast(rffi.LONG, node) - intval1 = rffi.cast(rffi.LONG, ref1) + intval = rffi.cast(lltype.Signed, node) + intval1 = rffi.cast(lltype.Signed, ref1) assert intval == intval1 @@ -1143,7 +1145,7 @@ assert node._obj._storage is True # forced! - rffi.cast(rffi.LONG, ref1) + rffi.cast(lltype.Signed, ref1) assert node._obj._storage not in (True, None) assert ref1 != ref2 @@ -1156,7 +1158,7 @@ NODE = lltype.GcStruct('NODE') node = lltype.malloc(NODE) ref1 = lltype.cast_opaque_ptr(llmemory.GCREF, node) - numb = rffi.cast(rffi.LONG, ref1) + numb = rffi.cast(lltype.Signed, ref1) ref2 = rffi.cast(llmemory.GCREF, numb) assert ref1 == ref2 assert ref2 == ref1 @@ -1164,16 +1166,16 @@ assert not (ref2 != ref1) def test_convert_subarray(self): - A = lltype.GcArray(rffi.LONG) + A = lltype.GcArray(lltype.Signed) a = lltype.malloc(A, 20) inside = lltype.direct_ptradd(lltype.direct_arrayitems(a), 3) lltype2ctypes(inside) - start = rffi.cast(rffi.LONG, lltype.direct_arrayitems(a)) - inside_int = rffi.cast(rffi.LONG, inside) + start = rffi.cast(lltype.Signed, lltype.direct_arrayitems(a)) + inside_int = rffi.cast(lltype.Signed, inside) - assert inside_int == start+rffi.sizeof(rffi.LONG)*3 + assert inside_int == start+rffi.sizeof(lltype.Signed)*3 def test_gcref_comparisons_through_addresses(self): NODE = lltype.GcStruct('NODE') @@ -1181,7 +1183,7 @@ adr0 = llmemory.cast_ptr_to_adr(n0) n1 = lltype.malloc(NODE) - i1 = rffi.cast(rffi.LONG, n1) + i1 = rffi.cast(lltype.Signed, n1) ref1 = rffi.cast(llmemory.GCREF, i1) adr1 = llmemory.cast_ptr_to_adr(ref1) @@ -1204,7 +1206,7 @@ s = S() s.x = n ls = cast_instance_to_base_ptr(s) - as_num = rffi.cast(rffi.LONG, ls) + as_num = rffi.cast(lltype.Signed, ls) # --- around this point, only 'as_num' is passed t = rffi.cast(rclass.OBJECTPTR, as_num) u = cast_base_ptr_to_instance(S, t) @@ -1216,7 +1218,7 @@ from pypy.rpython.lltypesystem import rclass SCLASS = lltype.GcStruct('SCLASS', ('parent', rclass.OBJECT), - ('n', rffi.LONG)) + ('n', lltype.Signed)) sclass_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True, immortal=True) sclass_vtable.name = rclass.alloc_array_name('SClass') @@ -1225,7 +1227,7 @@ s = lltype.malloc(SCLASS) s.parent.typeptr = sclass_vtable s.n = n - as_num = rffi.cast(rffi.LONG, s) + as_num = rffi.cast(lltype.Signed, s) # --- around this point, only 'as_num' is passed t = rffi.cast(lltype.Ptr(SCLASS), as_num) return t.n @@ -1242,7 +1244,7 @@ s = S() s.x = n ls = cast_instance_to_base_ptr(s) - as_num = rffi.cast(rffi.LONG, ls) + as_num = rffi.cast(lltype.Signed, ls) # --- around this point, only 'as_num' is passed r = rffi.cast(llmemory.GCREF, as_num) t = lltype.cast_opaque_ptr(rclass.OBJECTPTR, r) @@ -1255,7 +1257,7 @@ from pypy.rpython.lltypesystem import rclass SCLASS = lltype.GcStruct('SCLASS', ('parent', rclass.OBJECT), - ('n', rffi.LONG)) + ('n', lltype.Signed)) sclass_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True, immortal=True) sclass_vtable.name = rclass.alloc_array_name('SClass') @@ -1264,7 +1266,7 @@ s = lltype.malloc(SCLASS) s.parent.typeptr = sclass_vtable s.n = n - as_num = rffi.cast(rffi.LONG, s) + as_num = rffi.cast(lltype.Signed, s) # --- around this point, only 'as_num' is passed r = rffi.cast(llmemory.GCREF, as_num) t = lltype.cast_opaque_ptr(lltype.Ptr(SCLASS), r) @@ -1283,7 +1285,7 @@ def f(): s = T() ls = cast_instance_to_base_ptr(s) - as_num = rffi.cast(rffi.LONG, ls) + as_num = rffi.cast(lltype.Signed, ls) # --- around this point, only 'as_num' is passed t = rffi.cast(rclass.OBJECTPTR, as_num) u = cast_base_ptr_to_instance(S, t) @@ -1296,12 +1298,12 @@ p = lltype.malloc(S, flavor='raw') a = llmemory.cast_ptr_to_adr(p) i = llmemory.cast_adr_to_int(a, "forced") - assert type(i) is int + assert isinstance(i, (int, long)) assert i == llmemory.cast_adr_to_int(a, "forced") lltype.free(p, flavor='raw') def test_freelist(self): - S = lltype.Struct('S', ('x', rffi.LONG), ('y', rffi.LONG)) + S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed)) SP = lltype.Ptr(S) chunk = lltype.malloc(rffi.CArrayPtr(S).TO, 10, flavor='raw') assert lltype.typeOf(chunk) == rffi.CArrayPtr(S) From noreply at buildbot.pypy.org Fri Jul 8 18:56:47 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Fri, 8 Jul 2011 18:56:47 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: merge default into 'win64 test' branch Message-ID: <20110708165647.A99F2820AE@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45422:3a644729b2d9 Date: 2011-07-08 19:02 +0200 http://bitbucket.org/pypy/pypy/changeset/3a644729b2d9/ Log: merge default into 'win64 test' branch diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -26,13 +30,6 @@ Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ @@ -289,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -416,10 +416,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -478,9 +481,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d has address %x to %x" % + debug_start("jit-backend-addr") + debug_print("Bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -310,26 +310,27 @@ self.opimpl_goto_if_not(condbox, target) ''' % (_opimpl, _opimpl.upper())).compile() + + def _establish_nullity(self, box, orgpc): + value = box.nonnull() + if value: + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc) + else: + if not isinstance(box, Const): + self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + promoted_box = box.constbox() + self.metainterp.replace_box(box, promoted_box) + return value + @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_nonzero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if not value: + if not self._establish_nullity(box, orgpc): self.pc = target @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_iszero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if value: + if self._establish_nullity(box, orgpc): self.pc = target @arguments("box", "box", "box") @@ -364,7 +365,9 @@ def opimpl_new_with_vtable(self, sizedescr): cpu = self.metainterp.cpu cls = heaptracker.descr2vtable(cpu, sizedescr) - return self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + resbox = self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + self.metainterp.known_class_boxes[resbox] = None + return resbox ## @FixME #arguments("box") ## def opimpl_runtimenew(self, classbox): @@ -845,7 +848,9 @@ @arguments("orgpc", "box") def opimpl_guard_class(self, orgpc, box): clsbox = self.cls_of_box(box) - self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + self.metainterp.known_class_boxes[box] = None return clsbox @arguments("int", "orgpc") @@ -1449,6 +1454,8 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1789,6 +1796,8 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -281,9 +281,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1021,6 +1021,69 @@ res = self.meta_interp(main, []) assert res == 55 + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + a = A() + b = B() + def fn(n): + if n == -7: + obj = None + elif n: + obj = a + else: + obj = b + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -337,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -10,6 +10,7 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + 'fromstring': 'interp_support.fromstring', # ufuncs 'abs': 'interp_ufuncs.absolute', diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_support.py @@ -0,0 +1,32 @@ + +from pypy.rlib.rstruct.runpack import runpack +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.error import OperationError +from pypy.module.micronumpy.interp_numarray import SingleDimArray + +FLOAT_SIZE = rffi.sizeof(lltype.Float) + + at unwrap_spec(s=str) +def fromstring(space, s): + length = len(s) + + if length % FLOAT_SIZE == 0: + number = length/FLOAT_SIZE + else: + raise OperationError(space.w_ValueError, space.wrap( + "string length %d not divisable by %d" % (length, FLOAT_SIZE))) + + a = SingleDimArray(number) + + start = 0 + end = FLOAT_SIZE + i = 0 + while i < number: + part = s[start:end] + a.storage[i] = runpack('d', part) + i += 1 + start += FLOAT_SIZE + end += FLOAT_SIZE + + return space.wrap(a) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1,6 +1,7 @@ import py from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest +from pypy.conftest import gettestobjspace class AppTestNumArray(BaseNumpyAppTest): @@ -276,7 +277,21 @@ assert d[1] == 12 def test_mean(self): - from numpy import array, mean + from numpy import array a = array(range(5)) assert a.mean() == 2.0 assert a[:4].mean() == 1.5 + +class AppTestSupport(object): + def setup_class(cls): + import struct + cls.space = gettestobjspace(usemodules=('micronumpy',)) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + + def test_fromstring(self): + from numpy import fromstring + a = fromstring(self.data) + for i in range(4): + assert a[i] == i + 1 + raises(ValueError, fromstring, "abc") + diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -256,10 +256,6 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - class Cls(self.AddressStack): - def append(self2, addr): - assert addr not in self2.tolist() - self.AddressStack.append(self2, addr) self.objects_pointing_to_young = self.AddressStack() # # Similar to 'objects_pointing_to_young', but lists objects diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,10 +1,13 @@ import re, sys -from pypy.jit.metainterp.resoperation import rop, opname +from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser +from pypy.tool.logparser import parse_log_file, extract_category class Op(object): bridge = None + offset = None + asm = None def __init__(self, name, args, res, descr): self.name = name @@ -54,10 +57,53 @@ Op = Op use_mock_model = True + def postprocess(self, loop, backend_dump=None, backend_tp=None, + dump_start=0): + if backend_dump is not None: + raw_asm = self._asm_disassemble(backend_dump.decode('hex'), + backend_tp, dump_start) + asm = [] + start = 0 + for elem in raw_asm: + if len(elem.split("\t")) != 3: + continue + adr, _, v = elem.split("\t") + if not start: + start = int(adr.strip(":"), 16) + ofs = int(adr.strip(":"), 16) - start + if ofs >= 0: + asm.append((ofs, v.strip("\n"))) + asm_index = 0 + for i, op in enumerate(loop.operations): + end = 0 + j = i + 1 + while end == 0: + if j == len(loop.operations): + end = loop.last_offset + break + if loop.operations[j].offset is None: + j += 1 + else: + end = loop.operations[j].offset + if op.offset is not None: + while asm[asm_index][0] < op.offset: + asm_index += 1 + end_index = asm_index + while asm[end_index][0] < end: + end_index += 1 + op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) + return loop + + def _asm_disassemble(self, d, origin_addr, tp): + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + return list(machine_code_dump(d, tp, origin_addr)) + @classmethod - def parse_from_input(cls, input): - return cls(input, None, {}, 'lltype', None, - nonstrict=True).parse() + def parse_from_input(cls, input, **kwds): + parser = cls(input, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + return parser.postprocess(loop, **kwds) def parse_args(self, opname, argspec): if not argspec.strip(): @@ -284,3 +330,33 @@ res.append(op) i += 1 return res + + +def import_log(logname, ParserCls=SimpleParser): + log = parse_log_file(logname) + addrs = {} + for entry in extract_category(log, 'jit-backend-addr'): + m = re.search('bootstrap ([\da-f]+)', entry) + name = entry[:entry.find('(') - 1] + addrs[int(m.group(1), 16)] = name + dumps = {} + for entry in extract_category(log, 'jit-backend-dump'): + backend, _, dump, _ = entry.split("\n") + _, addr, _, data = re.split(" +", dump) + backend_name = backend.split(" ")[1] + addr = int(addr[1:], 16) + if addr in addrs: + dumps[addrs[addr]] = (backend_name, addr, data) + loops = [] + for entry in extract_category(log, 'jit-log-opt'): + parser = ParserCls(entry, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + comm = loop.comment + name = comm[2:comm.find(':')-1] + if name in dumps: + bname, start_ofs, dump = dumps[name] + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) + loops.append(loop) + return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -0,0 +1,38 @@ +[11f210b47027] {jit-backend +[11f210b900f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 +[11f210b949b3] jit-backend-dump} +[11f210b949b4] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab188] jit-backend-addr} +[11f210bab189] jit-backend} +[11f210bacbb7] {jit-log-opt-loop +# Loop 0 : loop with 19 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 INPLACE_ADD') ++179: i8 = int_add(i4, 1) +debug_merge_point(0, ' #28 STORE_FAST') +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++183: i10 = getfield_raw(40564608, descr=) ++191: i12 = int_sub(i10, 1) ++195: setfield_raw(40564608, i12, descr=) ++203: i14 = int_lt(i12, 0) +guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++213: jump(p0, p1, p2, p3, i8, descr=) ++218: --end of the loop-- +[11f210c17981] jit-log-opt-loop} +[11f210fb1d21] {jit-backend-counts +0:8965 +1:2 +[11f210fb381b] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,12 +1,11 @@ -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, Const -from pypy.tool.jitlogparser.parser import SimpleParser, TraceForOpcode, Function,\ - adjust_bridges +from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, + Function, adjust_bridges, + import_log) from pypy.tool.jitlogparser.storage import LoopStorage -import py +import py, sys -def parse(input): - return SimpleParser.parse_from_input(input) +def parse(input, **kwds): + return SimpleParser.parse_from_input(input, **kwds) def test_parse(): @@ -111,6 +110,8 @@ assert res.chunks[1].lineno == 3 def test_linerange(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] @@ -125,6 +126,8 @@ assert res.lineset == set([7, 8, 9]) def test_linerange_notstarts(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] @@ -179,3 +182,35 @@ ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] assert chunk.bytecode_name == 'StrLiteralSearch' + +def test_parsing_assembler(): + backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" + dump_start = 0x7f3b0b2e63d5 + loop = parse(""" + # Loop 0 : loop with 19 ops + [p0, p1, p2, p3, i4] + debug_merge_point(0, ' #15 COMPARE_OP') + +166: i6 = int_lt(i4, 10000) + guard_true(i6, descr=) [p1, p0, p2, p3, i4] + debug_merge_point(0, ' #27 INPLACE_ADD') + +179: i8 = int_add(i4, 1) + debug_merge_point(0, ' #31 JUMP_ABSOLUTE') + +183: i10 = getfield_raw(40564608, descr=) + +191: i12 = int_sub(i10, 1) + +195: setfield_raw(40564608, i12, descr=) + +203: i14 = int_lt(i12, 0) + guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] + debug_merge_point(0, ' #9 LOAD_FAST') + +213: jump(p0, p1, p2, p3, i8, descr=) + +218: --end of the loop--""", backend_dump=backend_dump, + dump_start=dump_start, + backend_tp='x86_64') + cmp = loop.operations[1] + assert 'jge' in cmp.asm + assert '0x2710' in cmp.asm + assert 'jmp' in loop.operations[-1].asm + +def test_import_log(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest.log'))) + assert 'jge' in loops[0].operations[3].asm From noreply at buildbot.pypy.org Fri Jul 8 21:27:03 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 8 Jul 2011 21:27:03 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Complete pypy.rlib.register. Message-ID: <20110708192703.6135C820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45423:3ab1f1a91c1c Date: 2011-07-08 19:48 +0200 http://bitbucket.org/pypy/pypy/changeset/3ab1f1a91c1c/ Log: Complete pypy.rlib.register. diff --git a/pypy/translator/register.py b/pypy/rlib/register.py rename from pypy/translator/register.py rename to pypy/rlib/register.py --- a/pypy/translator/register.py +++ b/pypy/rlib/register.py @@ -15,21 +15,50 @@ # For now, only for x86-64. Tries to use the register r15. eci = ExternalCompilationInfo( - post_include_bits=['register void* pypy_reg asm("r15");'], + post_include_bits=['register void* pypy_r15 asm("r15");\n' + '#define PYPY_GET_R15() pypy_r15\n' + '#define PYPY_SET_R15(x) (pypy_r15 = x)\n' + ], ) _test_eci = eci.merge(ExternalCompilationInfo( post_include_bits=[""" void f(void) { - pypy_reg = &f; + pypy_r15 = &f; } """])) try: rffi_platform.verify_eci(_test_eci) - var_name_in_c = 'pypy_reg' register_number = 15 # r15 except rffi_platform.CompilationError: eci = None - var_name_in_c = None register_number = None +else: + + from pypy.rpython.lltypesystem import lltype, llmemory, rffi + + # use load_from_reg(TYPE) and store_into_reg(llvalue) to load and store + # a value out of the special register. When running on top of Python. + # the behavior is emulated. + + _value_reg = None + + def _pypy_get_r15(): + assert _value_reg is not None + return _value_reg + + def _pypy_set_r15(addr): + global _value_reg + _value_reg = addr + + load_from_reg = rffi.llexternal('PYPY_GET_R15', [], llmemory.Address, + _callable=_pypy_get_r15, + compilation_info=eci, + _nowrapper=True) + + store_into_reg = rffi.llexternal('PYPY_SET_R15', [llmemory.Address], + lltype.Void, + _callable=_pypy_set_r15, + compilation_info=eci, + _nowrapper=True) diff --git a/pypy/translator/test/test_register.py b/pypy/rlib/test/test_register.py rename from pypy/translator/test/test_register.py rename to pypy/rlib/test/test_register.py --- a/pypy/translator/test/test_register.py +++ b/pypy/rlib/test/test_register.py @@ -1,13 +1,48 @@ +import py +from pypy.rlib import register +from pypy.rpython.lltypesystem import lltype, llmemory, rffi + def test_register(): - from pypy.translator import register # from pypy.jit.backend.detect_cpu import autodetect if autodetect() == 'x86_64': assert register.eci is not None - assert register.var_name_in_c is not None assert register.register_number == 15 # r15 else: assert register.eci is None - assert register.var_name_in_c is None assert register.register_number is None + + +class TestLoadStore(object): + def setup_class(cls): + if register.register_number is None: + py.test.skip("rlib/register not supported on this platform") + + def test_direct(self): + a = rffi.cast(llmemory.Address, 27) + register.store_into_reg(a) + b = register.load_from_reg() + assert lltype.typeOf(b) == llmemory.Address + assert rffi.cast(lltype.Signed, b) == 27 + + def test_llinterp(self): + from pypy.rpython.test.test_llinterp import interpret + def f(n): + a = rffi.cast(llmemory.Address, n) + register.store_into_reg(a) + b = register.load_from_reg() + return rffi.cast(lltype.Signed, b) + res = interpret(f, [41]) + assert res == 41 + + def test_compiled(self): + from pypy.translator.c.test.test_genc import compile + def f(n): + a = rffi.cast(llmemory.Address, n) + register.store_into_reg(a) + b = register.load_from_reg() + return rffi.cast(lltype.Signed, b) + cfn = compile(f, [int]) + res = cfn(43) + assert res == 43 From noreply at buildbot.pypy.org Fri Jul 8 21:27:04 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 8 Jul 2011 21:27:04 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: In-progress: try to use r15 for signalling exceptions. Message-ID: <20110708192704.9A33F820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45424:65ec9d93dc63 Date: 2011-07-08 20:38 +0200 http://bitbucket.org/pypy/pypy/changeset/65ec9d93dc63/ Log: In-progress: try to use r15 for signalling exceptions. diff --git a/pypy/rlib/register.py b/pypy/rlib/register.py --- a/pypy/rlib/register.py +++ b/pypy/rlib/register.py @@ -15,10 +15,12 @@ # For now, only for x86-64. Tries to use the register r15. eci = ExternalCompilationInfo( - post_include_bits=['register void* pypy_r15 asm("r15");\n' - '#define PYPY_GET_R15() pypy_r15\n' - '#define PYPY_SET_R15(x) (pypy_r15 = x)\n' - ], + post_include_bits=[ + 'register void *pypy_r15 asm("r15");\n' + '#define PYPY_GET_SPECIAL_REG() pypy_r15\n' + '#define PYPY_SPECIAL_REG_NONNULL() (pypy_r15 != NULL)\n' + '#define PYPY_SET_SPECIAL_REG(x) (pypy_r15 = x)\n' + ], ) _test_eci = eci.merge(ExternalCompilationInfo( @@ -38,27 +40,42 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi - # use load_from_reg(TYPE) and store_into_reg(llvalue) to load and store - # a value out of the special register. When running on top of Python. + # use addr=load_from_reg() and store_into_reg(addr) to load and store + # an Address out of the special register. When running on top of Python, # the behavior is emulated. _value_reg = None - def _pypy_get_r15(): + def _pypy_get_special_reg(): assert _value_reg is not None return _value_reg - def _pypy_set_r15(addr): + def _pypy_special_reg_nonnull(): + assert _value_reg is not None + return bool(_value_reg) + + def _pypy_set_special_reg(addr): global _value_reg _value_reg = addr - load_from_reg = rffi.llexternal('PYPY_GET_R15', [], llmemory.Address, - _callable=_pypy_get_r15, + load_from_reg = rffi.llexternal('PYPY_GET_SPECIAL_REG', [], + llmemory.Address, + _callable=_pypy_get_special_reg, compilation_info=eci, _nowrapper=True) - store_into_reg = rffi.llexternal('PYPY_SET_R15', [llmemory.Address], - lltype.Void, - _callable=_pypy_set_r15, + reg_is_nonnull = rffi.llexternal('PYPY_SPECIAL_REG_NONNULL', [], + lltype.Bool, + _callable=_pypy_special_reg_nonnull, compilation_info=eci, _nowrapper=True) + + store_into_reg = rffi.llexternal('PYPY_SET_SPECIAL_REG', + [llmemory.Address], + lltype.Void, + _callable=_pypy_set_special_reg, + compilation_info=eci, + _nowrapper=True) + + # xxx temporary + nonnull = llmemory.cast_int_to_adr(-1) diff --git a/pypy/rlib/test/test_register.py b/pypy/rlib/test/test_register.py --- a/pypy/rlib/test/test_register.py +++ b/pypy/rlib/test/test_register.py @@ -1,6 +1,7 @@ import py from pypy.rlib import register from pypy.rpython.lltypesystem import lltype, llmemory, rffi +from pypy.translator.c.test.test_standalone import StandaloneTests def test_register(): @@ -36,13 +37,19 @@ res = interpret(f, [41]) assert res == 41 + +class TestLoadStoreCompiled(StandaloneTests): + def setup_class(cls): + if register.register_number is None: + py.test.skip("rlib/register not supported on this platform") + def test_compiled(self): - from pypy.translator.c.test.test_genc import compile - def f(n): - a = rffi.cast(llmemory.Address, n) + def f(argv): + a = rffi.cast(llmemory.Address, 43) register.store_into_reg(a) b = register.load_from_reg() - return rffi.cast(lltype.Signed, b) - cfn = compile(f, [int]) - res = cfn(43) - assert res == 43 + print rffi.cast(lltype.Signed, b) + return 0 + t, cbuilder = self.compile(f) + data = cbuilder.cmdexec('') + assert data.startswith('43\n') diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h --- a/pypy/translator/c/src/main.h +++ b/pypy/translator/c/src/main.h @@ -34,6 +34,10 @@ char *errmsg; int i, exitcode; RPyListOfString *list; +#ifdef PYPY_GET_SPECIAL_REG + void *pypy_reg_oldvalue = PYPY_GET_SPECIAL_REG(); + PYPY_SET_SPECIAL_REG((void*)-1); +#endif pypy_asm_stack_bottom(); instrument_setup(); @@ -70,6 +74,10 @@ pypy_debug_catch_fatal_exception(); } +#ifdef PYPY_GET_SPECIAL_REG + PYPY_SET_SPECIAL_REG(pypy_reg_oldvalue); +#endif + return exitcode; memory_out: @@ -79,7 +87,7 @@ fprintf(stderr, "Fatal error during initialization: %s\n", errmsg); #endif abort(); - return 1; + return 1; /* not actually reachable */ } int PYPY_MAIN_FUNCTION(int argc, char *argv[]) diff --git a/pypy/translator/exceptiontransform.py b/pypy/translator/exceptiontransform.py --- a/pypy/translator/exceptiontransform.py +++ b/pypy/translator/exceptiontransform.py @@ -14,6 +14,7 @@ from pypy.rlib.rarithmetic import r_singlefloat from pypy.rlib.debug import ll_assert from pypy.rlib.rstackovf import _StackOverflow +from pypy.rlib import register from pypy.annotation import model as annmodel from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.tool.sourcetools import func_with_new_name @@ -72,9 +73,19 @@ assertion_error_ll_exc_type) self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type) + if register.register_number is not None: + self.c_nonnull_specialregister = constant_value(register.nonnull) + self.c_load_from_reg = constant_value(register.load_from_reg) + self.c_reg_is_nonnull = constant_value(register.reg_is_nonnull) + self.c_store_into_reg = constant_value(register.store_into_reg) + def rpyexc_occured(): - exc_type = exc_data.exc_type - return bool(exc_type) + if register.register_number is None: + exc_type = exc_data.exc_type + return bool(exc_type) + else: + # an exception occurred iff the special register is 0 + return register.load_from_reg() == llmemory.NULL def rpyexc_fetch_type(): return exc_data.exc_type @@ -83,6 +94,8 @@ return exc_data.exc_value def rpyexc_clear(): + if register.register_number is not None: + register.store_into_reg(register.nonnull) exc_data.exc_type = null_type exc_data.exc_value = null_value @@ -99,11 +112,15 @@ exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_start_traceback(lltype.Void, etype) + if register.register_number is not None: + register.store_into_reg(llmemory.NULL) def rpyexc_reraise(etype, evalue): exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_reraise_traceback(lltype.Void, etype) + if register.register_number is not None: + register.store_into_reg(llmemory.NULL) def rpyexc_fetch_exception(): evalue = rpyexc_fetch_value() @@ -114,6 +131,8 @@ if evalue: exc_data.exc_type = rclass.ll_inst_type(evalue) exc_data.exc_value = evalue + if register.register_number is not None: + register.store_into_reg(llmemory.NULL) def rpyexc_raise_stack_overflow(): rpyexc_raise(stackovf_ll_exc_type, stackovf_ll_exc) @@ -409,6 +428,8 @@ # self.gen_setfield('exc_value', self.c_null_evalue, llops) self.gen_setfield('exc_type', self.c_null_etype, llops) + if register.register_number is not None: + self.gen_setspecialregister(self.c_nonnull_specialregister, llops) excblock.operations[:] = llops newgraph.exceptblock.inputargs[0].concretetype = self.lltype_of_exception_type newgraph.exceptblock.inputargs[1].concretetype = self.lltype_of_exception_value @@ -432,9 +453,11 @@ if alloc_shortcut: T = spaceop.result.concretetype var_no_exc = self.gen_nonnull(spaceop.result, llops) - else: + elif register.register_number is None: v_exc_type = self.gen_getfield('exc_type', llops) var_no_exc = self.gen_isnull(v_exc_type, llops) + else: + var_no_exc = self.gen_specialreg_no_exc(llops) block.operations.extend(llops) @@ -527,6 +550,17 @@ def gen_nonnull(self, v, llops): return llops.genop('ptr_nonzero', [v], lltype.Bool) + def gen_getspecialregister(self, llops): + return llops.genop('direct_call', [self.c_load_from_reg], + resulttype = llmemory.Address) + + def gen_specialreg_no_exc(self, llops): + return llops.genop('direct_call', [self.c_reg_is_nonnull], + resulttype = lltype.Bool) + + def gen_setspecialregister(self, v, llops): + llops.genop('direct_call', [self.c_store_into_reg, v]) + def same_obj(self, ptr1, ptr2): return ptr1._same_obj(ptr2) From noreply at buildbot.pypy.org Fri Jul 8 21:52:26 2011 From: noreply at buildbot.pypy.org (snus_mumrik) Date: Fri, 8 Jul 2011 21:52:26 +0200 (CEST) Subject: [pypy-commit] pypy numpy-impicit-convert: Simplifying and moving issequence to objspace Message-ID: <20110708195226.18C21820AE@wyvern.cs.uni-duesseldorf.de> Author: Ilya Osadchiy Branch: numpy-impicit-convert Changeset: r45425:6ee97b808423 Date: 2011-07-08 21:13 +0300 http://bitbucket.org/pypy/pypy/changeset/6ee97b808423/ Log: Simplifying and moving issequence to objspace diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -925,6 +925,9 @@ return self.w_True return self.w_False + def issequence_w(self, w_obj): + return (self.findattr(w_obj, self.wrap("__getitem__")) is not None) + def isinstance_w(self, w_obj, w_type): return self.is_true(self.isinstance(w_obj, w_type)) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -7,7 +7,6 @@ from pypy.tool.sourcetools import func_with_new_name import math - def dummy1(v): assert isinstance(v, float) return v @@ -82,23 +81,15 @@ def _binop_impl(function): signature = Signature() def impl(self, space, w_other): + w_other = convert_to_array(space, w_other) new_sig = self.signature.transition(signature) - if isinstance(w_other, BaseArray): - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - else: - w_other = access_as_array(space, w_other) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) + res = Call2( + function, + self, + w_other, + new_sig.transition(w_other.signature) + ) + w_other.invalidates.append(res) self.invalidates.append(res) return space.wrap(res) return func_with_new_name(impl, "binop_%s_impl" % function.__name__) @@ -143,14 +134,15 @@ s += concrete.getitem(i) return space.wrap(s / size) -def access_as_array (space, w_obj): - try: +def convert_to_array (space, w_obj): + if isinstance(w_obj, BaseArray): + return w_obj + elif space.issequence_w(w_obj): + # Convert to array. + return new_numarray(space, w_obj) + else: # If it's a scalar return FloatWrapper(space.float_w(w_obj)) - except OperationError: - # Convert to array. - # Could we somehow use COW in some cases? - return new_numarray(space, w_obj) class FloatWrapper(BaseArray): """ diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,26 +1,17 @@ import math from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, access_as_array +from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name -def _issequence(space, w_obj): - # Copied from cpyext's PySequence_Check - """Return True if the object provides sequence protocol, and False otherwise. - This function always succeeds.""" - return (space.findattr(w_obj, space.wrap("__getitem__")) is not None) - def ufunc(func): signature = Signature() def impl(space, w_obj): - if isinstance(w_obj, BaseArray): - w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) - w_obj.invalidates.append(w_res) - return w_res - elif _issequence(space, w_obj): - w_obj_arr = access_as_array(space, w_obj) + if space.issequence_w(w_obj): + w_obj_arr = convert_to_array(space, w_obj) w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) + w_obj_arr.invalidates.append(w_res) return w_res else: return space.wrap(func(space.float_w(w_obj))) @@ -29,31 +20,13 @@ def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): - lhs_is_array = isinstance(w_lhs, BaseArray) - rhs_is_array = isinstance(w_rhs, BaseArray) - if lhs_is_array and rhs_is_array: - # This is the (most likely) fall-through case in conversion checks - # Not sure if making it a special case makes it much faster - new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) - w_res = Call2(func, w_lhs, w_rhs, new_sig) - w_lhs.invalidates.append(w_res) - w_rhs.invalidates.append(w_res) - return w_res - elif _issequence(space, w_lhs) or _issequence(space, w_rhs): - if lhs_is_array: - w_lhs_arr = w_lhs - else: - w_lhs_arr = access_as_array(space, w_lhs) - if rhs_is_array: - w_rhs_arr = w_rhs - else: - w_rhs_arr = access_as_array(space, w_rhs) + if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): + w_lhs_arr = convert_to_array(space, w_lhs) + w_rhs_arr = convert_to_array(space, w_rhs) new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature) w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig) - if lhs_is_array: - w_lhs_arr.invalidates.append(w_res) - if rhs_is_array: - w_rhs_arr.invalidates.append(w_res) + w_lhs_arr.invalidates.append(w_res) + w_rhs_arr.invalidates.append(w_res) return w_res else: return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -1,12 +1,10 @@ from pypy.conftest import gettestobjspace from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper - class BaseNumpyAppTest(object): def setup_class(cls): cls.space = gettestobjspace(usemodules=('micronumpy',)) - class TestSignature(object): def test_binop_signature(self, space): ar = SingleDimArray(10) @@ -26,4 +24,4 @@ v3 = ar.descr_add(space, v1) v4 = ar.descr_add(space, v2) - assert v3.signature is v4.signature \ No newline at end of file + assert v3.signature is v4.signature diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -6,7 +6,16 @@ from pypy.module.micronumpy.compile import numpy_compile class FakeSpace(object): - pass + def issequence_w(self, w_obj): + # XXX: get_concrete() fails in some tests + # when using `return hasattr(w_obj, "__getitem__")` + return True + + def wrap(self, w_obj): + return w_obj + + def float_w(self, w_obj): + return float(w_obj) class TestNumpyJIt(LLJitMixin): def setup_class(cls): From noreply at buildbot.pypy.org Fri Jul 8 21:52:27 2011 From: noreply at buildbot.pypy.org (snus_mumrik) Date: Fri, 8 Jul 2011 21:52:27 +0200 (CEST) Subject: [pypy-commit] pypy numpy-impicit-convert: merge default Message-ID: <20110708195227.6F9CE820AE@wyvern.cs.uni-duesseldorf.de> Author: Ilya Osadchiy Branch: numpy-impicit-convert Changeset: r45426:be38f623af1b Date: 2011-07-08 22:48 +0300 http://bitbucket.org/pypy/pypy/changeset/be38f623af1b/ Log: merge default diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -26,13 +30,6 @@ Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ @@ -289,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -416,10 +416,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -478,9 +481,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d has address %x to %x" % + debug_start("jit-backend-addr") + debug_print("Bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -310,26 +310,27 @@ self.opimpl_goto_if_not(condbox, target) ''' % (_opimpl, _opimpl.upper())).compile() + + def _establish_nullity(self, box, orgpc): + value = box.nonnull() + if value: + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc) + else: + if not isinstance(box, Const): + self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + promoted_box = box.constbox() + self.metainterp.replace_box(box, promoted_box) + return value + @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_nonzero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if not value: + if not self._establish_nullity(box, orgpc): self.pc = target @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_iszero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if value: + if self._establish_nullity(box, orgpc): self.pc = target @arguments("box", "box", "box") @@ -364,7 +365,9 @@ def opimpl_new_with_vtable(self, sizedescr): cpu = self.metainterp.cpu cls = heaptracker.descr2vtable(cpu, sizedescr) - return self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + resbox = self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + self.metainterp.known_class_boxes[resbox] = None + return resbox ## @FixME #arguments("box") ## def opimpl_runtimenew(self, classbox): @@ -845,7 +848,9 @@ @arguments("orgpc", "box") def opimpl_guard_class(self, orgpc, box): clsbox = self.cls_of_box(box) - self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + self.metainterp.known_class_boxes[box] = None return clsbox @arguments("int", "orgpc") @@ -1449,6 +1454,8 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1789,6 +1796,8 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -281,9 +281,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1021,6 +1021,69 @@ res = self.meta_interp(main, []) assert res == 55 + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + a = A() + b = B() + def fn(n): + if n == -7: + obj = None + elif n: + obj = a + else: + obj = b + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -337,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -10,6 +10,7 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + 'fromstring': 'interp_support.fromstring', # ufuncs 'abs': 'interp_ufuncs.absolute', diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_support.py @@ -0,0 +1,32 @@ + +from pypy.rlib.rstruct.runpack import runpack +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.error import OperationError +from pypy.module.micronumpy.interp_numarray import SingleDimArray + +FLOAT_SIZE = rffi.sizeof(lltype.Float) + + at unwrap_spec(s=str) +def fromstring(space, s): + length = len(s) + + if length % FLOAT_SIZE == 0: + number = length/FLOAT_SIZE + else: + raise OperationError(space.w_ValueError, space.wrap( + "string length %d not divisable by %d" % (length, FLOAT_SIZE))) + + a = SingleDimArray(number) + + start = 0 + end = FLOAT_SIZE + i = 0 + while i < number: + part = s[start:end] + a.storage[i] = runpack('d', part) + i += 1 + start += FLOAT_SIZE + end += FLOAT_SIZE + + return space.wrap(a) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1,6 +1,7 @@ import py from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest +from pypy.conftest import gettestobjspace class AppTestNumArray(BaseNumpyAppTest): @@ -285,7 +286,21 @@ assert d[1] == 12 def test_mean(self): - from numpy import array, mean + from numpy import array a = array(range(5)) assert a.mean() == 2.0 assert a[:4].mean() == 1.5 + +class AppTestSupport(object): + def setup_class(cls): + import struct + cls.space = gettestobjspace(usemodules=('micronumpy',)) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + + def test_fromstring(self): + from numpy import fromstring + a = fromstring(self.data) + for i in range(4): + assert a[i] == i + 1 + raises(ValueError, fromstring, "abc") + diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -256,10 +256,6 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - class Cls(self.AddressStack): - def append(self2, addr): - assert addr not in self2.tolist() - self.AddressStack.append(self2, addr) self.objects_pointing_to_young = self.AddressStack() # # Similar to 'objects_pointing_to_young', but lists objects diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,10 +1,13 @@ import re, sys -from pypy.jit.metainterp.resoperation import rop, opname +from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser +from pypy.tool.logparser import parse_log_file, extract_category class Op(object): bridge = None + offset = None + asm = None def __init__(self, name, args, res, descr): self.name = name @@ -54,10 +57,53 @@ Op = Op use_mock_model = True + def postprocess(self, loop, backend_dump=None, backend_tp=None, + dump_start=0): + if backend_dump is not None: + raw_asm = self._asm_disassemble(backend_dump.decode('hex'), + backend_tp, dump_start) + asm = [] + start = 0 + for elem in raw_asm: + if len(elem.split("\t")) != 3: + continue + adr, _, v = elem.split("\t") + if not start: + start = int(adr.strip(":"), 16) + ofs = int(adr.strip(":"), 16) - start + if ofs >= 0: + asm.append((ofs, v.strip("\n"))) + asm_index = 0 + for i, op in enumerate(loop.operations): + end = 0 + j = i + 1 + while end == 0: + if j == len(loop.operations): + end = loop.last_offset + break + if loop.operations[j].offset is None: + j += 1 + else: + end = loop.operations[j].offset + if op.offset is not None: + while asm[asm_index][0] < op.offset: + asm_index += 1 + end_index = asm_index + while asm[end_index][0] < end: + end_index += 1 + op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) + return loop + + def _asm_disassemble(self, d, origin_addr, tp): + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + return list(machine_code_dump(d, tp, origin_addr)) + @classmethod - def parse_from_input(cls, input): - return cls(input, None, {}, 'lltype', None, - nonstrict=True).parse() + def parse_from_input(cls, input, **kwds): + parser = cls(input, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + return parser.postprocess(loop, **kwds) def parse_args(self, opname, argspec): if not argspec.strip(): @@ -284,3 +330,33 @@ res.append(op) i += 1 return res + + +def import_log(logname, ParserCls=SimpleParser): + log = parse_log_file(logname) + addrs = {} + for entry in extract_category(log, 'jit-backend-addr'): + m = re.search('bootstrap ([\da-f]+)', entry) + name = entry[:entry.find('(') - 1] + addrs[int(m.group(1), 16)] = name + dumps = {} + for entry in extract_category(log, 'jit-backend-dump'): + backend, _, dump, _ = entry.split("\n") + _, addr, _, data = re.split(" +", dump) + backend_name = backend.split(" ")[1] + addr = int(addr[1:], 16) + if addr in addrs: + dumps[addrs[addr]] = (backend_name, addr, data) + loops = [] + for entry in extract_category(log, 'jit-log-opt'): + parser = ParserCls(entry, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + comm = loop.comment + name = comm[2:comm.find(':')-1] + if name in dumps: + bname, start_ofs, dump = dumps[name] + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) + loops.append(loop) + return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -0,0 +1,38 @@ +[11f210b47027] {jit-backend +[11f210b900f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 +[11f210b949b3] jit-backend-dump} +[11f210b949b4] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab188] jit-backend-addr} +[11f210bab189] jit-backend} +[11f210bacbb7] {jit-log-opt-loop +# Loop 0 : loop with 19 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 INPLACE_ADD') ++179: i8 = int_add(i4, 1) +debug_merge_point(0, ' #28 STORE_FAST') +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++183: i10 = getfield_raw(40564608, descr=) ++191: i12 = int_sub(i10, 1) ++195: setfield_raw(40564608, i12, descr=) ++203: i14 = int_lt(i12, 0) +guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++213: jump(p0, p1, p2, p3, i8, descr=) ++218: --end of the loop-- +[11f210c17981] jit-log-opt-loop} +[11f210fb1d21] {jit-backend-counts +0:8965 +1:2 +[11f210fb381b] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,12 +1,11 @@ -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, Const -from pypy.tool.jitlogparser.parser import SimpleParser, TraceForOpcode, Function,\ - adjust_bridges +from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, + Function, adjust_bridges, + import_log) from pypy.tool.jitlogparser.storage import LoopStorage -import py +import py, sys -def parse(input): - return SimpleParser.parse_from_input(input) +def parse(input, **kwds): + return SimpleParser.parse_from_input(input, **kwds) def test_parse(): @@ -111,6 +110,8 @@ assert res.chunks[1].lineno == 3 def test_linerange(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] @@ -125,6 +126,8 @@ assert res.lineset == set([7, 8, 9]) def test_linerange_notstarts(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] @@ -179,3 +182,35 @@ ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] assert chunk.bytecode_name == 'StrLiteralSearch' + +def test_parsing_assembler(): + backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" + dump_start = 0x7f3b0b2e63d5 + loop = parse(""" + # Loop 0 : loop with 19 ops + [p0, p1, p2, p3, i4] + debug_merge_point(0, ' #15 COMPARE_OP') + +166: i6 = int_lt(i4, 10000) + guard_true(i6, descr=) [p1, p0, p2, p3, i4] + debug_merge_point(0, ' #27 INPLACE_ADD') + +179: i8 = int_add(i4, 1) + debug_merge_point(0, ' #31 JUMP_ABSOLUTE') + +183: i10 = getfield_raw(40564608, descr=) + +191: i12 = int_sub(i10, 1) + +195: setfield_raw(40564608, i12, descr=) + +203: i14 = int_lt(i12, 0) + guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] + debug_merge_point(0, ' #9 LOAD_FAST') + +213: jump(p0, p1, p2, p3, i8, descr=) + +218: --end of the loop--""", backend_dump=backend_dump, + dump_start=dump_start, + backend_tp='x86_64') + cmp = loop.operations[1] + assert 'jge' in cmp.asm + assert '0x2710' in cmp.asm + assert 'jmp' in loop.operations[-1].asm + +def test_import_log(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest.log'))) + assert 'jge' in loops[0].operations[3].asm From noreply at buildbot.pypy.org Sat Jul 9 00:13:26 2011 From: noreply at buildbot.pypy.org (wlav) Date: Sat, 9 Jul 2011 00:13:26 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: first attempt at CINT back-end Message-ID: <20110708221326.15900820AE@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45427:b191cd469f0b Date: 2011-07-08 15:13 -0700 http://bitbucket.org/pypy/pypy/changeset/b191cd469f0b/ Log: first attempt at CINT back-end diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/capi/__init__.py @@ -0,0 +1,2 @@ +from reflex_capi import * +#from cint_capi import * diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/capi/cint_capi.py @@ -0,0 +1,194 @@ +import py, os + +from pypy.translator.tool.cbuild import ExternalCompilationInfo +from pypy.rpython.lltypesystem import rffi, lltype + +pkgpath = py.path.local(__file__).dirpath().join(os.pardir) +srcpath = pkgpath.join("src") +incpath = pkgpath.join("include") + +if os.environ.get("ROOTSYS"): + rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")] + rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib")] +else: + rootincpath = [] + rootlibpath = [] + +eci = ExternalCompilationInfo( + separate_module_files=[srcpath.join("cintcwrapper.cxx")], + include_dirs=[incpath] + rootincpath, + includes=["cintcwrapper.h"], + library_dirs=rootlibpath, +# libraries=["Core", "Cint"], + link_extra=["-lCore", "-lCint"], + use_cpp_linker=True, +) + +C_TYPEHANDLE = rffi.VOIDP +C_OBJECT = rffi.VOIDP + +C_METHPTRGETTER = lltype.FuncType([C_OBJECT], rffi.VOIDP) +C_METHPTRGETTER_PTR = lltype.Ptr(C_METHPTRGETTER) + +c_get_typehandle = rffi.llexternal( + "cppyy_get_typehandle", + [rffi.CCHARP], C_TYPEHANDLE, + compilation_info=eci) + +c_get_templatehandle = rffi.llexternal( + "cppyy_get_templatehandle", + [rffi.CCHARP], C_TYPEHANDLE, + compilation_info=eci) + +c_allocate = rffi.llexternal( + "cppyy_allocate", + [C_TYPEHANDLE], rffi.VOIDP, + compilation_info=eci) +c_deallocate = rffi.llexternal( + "cppyy_deallocate", + [C_TYPEHANDLE, C_OBJECT], lltype.Void, + compilation_info=eci) + +c_destruct = rffi.llexternal( + "cppyy_destruct", + [C_TYPEHANDLE, C_OBJECT], lltype.Void, + compilation_info=eci) + + +c_is_namespace = rffi.llexternal( + "cppyy_is_namespace", + [C_TYPEHANDLE], rffi.INT, + compilation_info=eci) + + +c_final_name = rffi.llexternal( + "cppyy_final_name", + [C_TYPEHANDLE], rffi.CCHARP, + compilation_info=eci) + +c_num_bases = rffi.llexternal( + "cppyy_num_bases", + [C_TYPEHANDLE], rffi.INT, + compilation_info=eci) + +c_base_name = rffi.llexternal( + "cppyy_base_name", + [C_TYPEHANDLE, rffi.INT], rffi.CCHARP, + compilation_info=eci) + +c_is_subtype = rffi.llexternal( + "cppyy_is_subtype", + [C_TYPEHANDLE, C_TYPEHANDLE], rffi.INT, + compilation_info=eci) +c_base_offset = rffi.llexternal( + "cppyy_base_offset", + [C_TYPEHANDLE, C_TYPEHANDLE], rffi.SIZE_T, + compilation_info=eci) + + +c_call_v = rffi.llexternal( + "cppyy_call_v", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], lltype.Void, + compilation_info=eci) +c_call_o = rffi.llexternal( + "cppyy_call_o", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP, C_TYPEHANDLE], rffi.LONG, + compilation_info=eci) +c_call_b = rffi.llexternal( + "cppyy_call_b", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, + compilation_info=eci) +c_call_c = rffi.llexternal( + "cppyy_call_c", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.CHAR, + compilation_info=eci) +c_call_h = rffi.llexternal( + "cppyy_call_h", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, + compilation_info=eci) +c_call_l = rffi.llexternal( + "cppyy_call_l", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.LONG, + compilation_info=eci) +c_call_f = rffi.llexternal( + "cppyy_call_f", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.DOUBLE, + compilation_info=eci) +c_call_d = rffi.llexternal( + "cppyy_call_d", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.DOUBLE, + compilation_info=eci) + + +c_get_methptr_getter = rffi.llexternal( + "cppyy_get_methptr_getter", + [C_TYPEHANDLE, rffi.INT], C_METHPTRGETTER_PTR, + compilation_info=eci) + + +c_num_methods = rffi.llexternal( + "cppyy_num_methods", + [C_TYPEHANDLE], rffi.INT, + compilation_info=eci) +c_method_name = rffi.llexternal( + "cppyy_method_name", + [C_TYPEHANDLE, rffi.INT], rffi.CCHARP, + compilation_info=eci) +c_method_result_type = rffi.llexternal( + "cppyy_method_result_type", + [C_TYPEHANDLE, rffi.INT], rffi.CCHARP, + compilation_info=eci) +c_method_num_args = rffi.llexternal( + "cppyy_method_num_args", + [C_TYPEHANDLE, rffi.INT], rffi.INT, + compilation_info=eci) +c_method_req_args = rffi.llexternal( + "cppyy_method_req_args", + [C_TYPEHANDLE, rffi.INT], rffi.INT, + compilation_info=eci) +c_method_arg_type = rffi.llexternal( + "cppyy_method_arg_type", + [C_TYPEHANDLE, rffi.INT, rffi.INT], rffi.CCHARP, + compilation_info=eci) + +c_is_constructor = rffi.llexternal( + "cppyy_is_constructor", + [C_TYPEHANDLE, rffi.INT], rffi.INT, + compilation_info=eci) +c_is_staticmethod = rffi.llexternal( + "cppyy_is_staticmethod", + [C_TYPEHANDLE, rffi.INT], rffi.INT, + compilation_info=eci) + +c_num_data_members = rffi.llexternal( + "cppyy_num_data_members", + [C_TYPEHANDLE], rffi.INT, + compilation_info=eci) +c_data_member_name = rffi.llexternal( + "cppyy_data_member_name", + [C_TYPEHANDLE, rffi.INT], rffi.CCHARP, + compilation_info=eci) +c_data_member_type = rffi.llexternal( + "cppyy_data_member_type", + [C_TYPEHANDLE, rffi.INT], rffi.CCHARP, + compilation_info=eci) +c_data_member_offset = rffi.llexternal( + "cppyy_data_member_offset", + [C_TYPEHANDLE, rffi.INT], rffi.SIZE_T, + compilation_info=eci) + +c_is_staticdata = rffi.llexternal( + "cppyy_is_staticdata", + [C_TYPEHANDLE, rffi.INT], rffi.INT, + compilation_info=eci) + +c_free = rffi.llexternal( + "cppyy_free", + [rffi.VOIDP], lltype.Void, + compilation_info=eci) + +def charp2str_free(charp): + string = rffi.charp2str(charp) + voidp = rffi.cast(rffi.VOIDP, charp) + c_free(voidp) + return string diff --git a/pypy/module/cppyy/capi.py b/pypy/module/cppyy/capi/reflex_capi.py rename from pypy/module/cppyy/capi.py rename to pypy/module/cppyy/capi/reflex_capi.py --- a/pypy/module/cppyy/capi.py +++ b/pypy/module/cppyy/capi/reflex_capi.py @@ -3,8 +3,9 @@ from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.rpython.lltypesystem import rffi, lltype -srcpath = py.path.local(__file__).dirpath().join("src") -incpath = py.path.local(__file__).dirpath().join("include") +pkgpath = py.path.local(__file__).dirpath().join(os.pardir) +srcpath = pkgpath.join("src") +incpath = pkgpath.join("include") if os.environ.get("ROOTSYS"): rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")] diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/capi.h copy from pypy/module/cppyy/include/reflexcwrapper.h copy to pypy/module/cppyy/include/capi.h --- a/pypy/module/cppyy/include/reflexcwrapper.h +++ b/pypy/module/cppyy/include/capi.h @@ -1,5 +1,7 @@ -#ifndef CPPYY_REFLEXCWRAPPER -#define CPPYY_REFLEXCWRAPPER +#ifndef CPPYY_CAPI +#define CPPYY_CAPI + +#include #ifdef __cplusplus extern "C" { @@ -67,4 +69,4 @@ } #endif // ifdef __cplusplus -#endif // ifndef CPPYY_REFLEXCWRAPPER +#endif // ifndef CPPYY_CAPI diff --git a/pypy/module/cppyy/include/cintcwrapper.h b/pypy/module/cppyy/include/cintcwrapper.h new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/include/cintcwrapper.h @@ -0,0 +1,6 @@ +#ifndef CPPYY_CINTCWRAPPER +#define CPPYY_CINTCWRAPPER + +#include "capi.h" + +#endif // ifndef CPPYY_CINTCWRAPPER diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h --- a/pypy/module/cppyy/include/cppyy.h +++ b/pypy/module/cppyy/include/cppyy.h @@ -1,12 +1,6 @@ #ifndef CPPYY_CPPYY #define CPPYY_CPPYY -#include "Reflex/Type.h" -#include "Reflex/Base.h" -#include "Reflex/Member.h" -#include "Reflex/Object.h" -#include "Reflex/Builder/TypeBuilder.h" -#include "Reflex/PropertyList.h" -#include "Reflex/TypeTemplate.h" +// for now, just a conventional placeholder #endif // CPPYY_CPPYY diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/reflexcwrapper.h --- a/pypy/module/cppyy/include/reflexcwrapper.h +++ b/pypy/module/cppyy/include/reflexcwrapper.h @@ -1,70 +1,6 @@ #ifndef CPPYY_REFLEXCWRAPPER #define CPPYY_REFLEXCWRAPPER -#ifdef __cplusplus -extern "C" { -#endif // ifdef __cplusplus - typedef void* cppyy_typehandle_t; - typedef void* cppyy_object_t; - typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t); - - /* name to handle */ - cppyy_typehandle_t cppyy_get_typehandle(const char* class_name); - cppyy_typehandle_t cppyy_get_templatehandle(const char* template_name); - - /* memory management */ - void* cppyy_allocate(cppyy_typehandle_t handle); - void cppyy_deallocate(cppyy_typehandle_t handle, cppyy_object_t instance); - void cppyy_destruct(cppyy_typehandle_t handle, cppyy_object_t self); - - /* method/function dispatching */ - void cppyy_call_v(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - long cppyy_call_o(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[], cppyy_typehandle_t rettype); - int cppyy_call_b(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - char cppyy_call_c(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - short cppyy_call_h(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - long cppyy_call_l(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - double cppyy_call_f(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - double cppyy_call_d(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - - cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_typehandle_t handle, int method_index); - - /* scope reflection information ------------------------------------------- */ - int cppyy_is_namespace(cppyy_typehandle_t handle); - - /* type/class reflection information -------------------------------------- */ - char* cppyy_final_name(cppyy_typehandle_t handle); - int cppyy_num_bases(cppyy_typehandle_t handle); - char* cppyy_base_name(cppyy_typehandle_t handle, int base_index); - int cppyy_is_subtype(cppyy_typehandle_t dh, cppyy_typehandle_t bh); - size_t cppyy_base_offset(cppyy_typehandle_t dh, cppyy_typehandle_t bh); - - /* method/function reflection information */ - int cppyy_num_methods(cppyy_typehandle_t handle); - char* cppyy_method_name(cppyy_typehandle_t handle, int method_index); - char* cppyy_method_result_type(cppyy_typehandle_t handle, int method_index); - int cppyy_method_num_args(cppyy_typehandle_t handle, int method_index); - int cppyy_method_req_args(cppyy_typehandle_t handle, int method_index); - char* cppyy_method_arg_type(cppyy_typehandle_t handle, int method_index, int index); - - /* method properties */ - int cppyy_is_constructor(cppyy_typehandle_t handle, int method_index); - int cppyy_is_staticmethod(cppyy_typehandle_t handle, int method_index); - - /* data member reflection information */ - int cppyy_num_data_members(cppyy_typehandle_t handle); - char* cppyy_data_member_name(cppyy_typehandle_t handle, int data_member_index); - char* cppyy_data_member_type(cppyy_typehandle_t handle, int data_member_index); - size_t cppyy_data_member_offset(cppyy_typehandle_t handle, int data_member_index); - - /* data member properties */ - int cppyy_is_staticdata(cppyy_typehandle_t handle, int data_member_index); - - /* misc helper */ - void cppyy_free(void* ptr); - -#ifdef __cplusplus -} -#endif // ifdef __cplusplus +#include "capi.h" #endif // ifndef CPPYY_REFLEXCWRAPPER diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -18,7 +18,8 @@ NULL_VOIDP = lltype.nullptr(rffi.VOIDP.TO) def load_lib(space, name): - cdll = libffi.CDLL(name) + # TODO: allow open in RTLD_GLOBAL mode + cdll = libffi.CDLL(name) #, 0x100 | 0x02) return W_CPPLibrary(space, cdll) load_lib.unwrap_spec = [ObjSpace, str] diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/src/cintcwrapper.cxx @@ -0,0 +1,295 @@ +#include "cppyy.h" +#include "cintcwrapper.h" + +#include "Api.h" + +#include "TList.h" + +#include "TBaseClass.h" +#include "TClass.h" +#include "TClassEdit.h" +#include "TClassRef.h" +#include "TDataMember.h" +#include "TMethod.h" +#include "TMethodArg.h" + +#include +#include +#include +#include +#include + + +/* data for life time management ------------------------------------------ */ +typedef std::vector ClassRefs_t; +static ClassRefs_t g_classrefs(1); + +typedef std::map ClassRefIndices_t; +static ClassRefIndices_t g_classref_indices; + + +/* local helpers ---------------------------------------------------------- */ +static inline char* cppstring_to_cstring(const std::string& name) { + char* name_char = (char*)malloc(name.size() + 1); + strcpy(name_char, name.c_str()); + return name_char; +} + +static inline char* type_cppstring_to_cstring(const std::string& tname) { + G__TypeInfo ti(tname.c_str()); + std::string name = ti.IsValid() ? ti.TrueName() : tname; + return cppstring_to_cstring(name); +} + +static inline TClassRef type_from_handle(cppyy_typehandle_t handle) { + return g_classrefs[(ClassRefs_t::size_type)handle]; +} + + +/* name to handle --------------------------------------------------------- */ +cppyy_typehandle_t cppyy_get_typehandle(const char* class_name) { + ClassRefIndices_t::iterator icr = g_classref_indices.find(class_name); + if (icr != g_classref_indices.end()) + return (cppyy_typehandle_t)icr->second; + + ClassRefs_t::size_type sz = g_classrefs.size(); + g_classref_indices[class_name] = sz; + g_classrefs.push_back(TClassRef(class_name)); + return (cppyy_typehandle_t)sz; +} + +cppyy_typehandle_t cppyy_get_templatehandle(const char* template_name) { + return cppyy_get_typehandle(template_name); +} + + +/* memory management ------------------------------------------------------ */ +void* cppyy_allocate(cppyy_typehandle_t handle) { + TClassRef cr = type_from_handle(handle); + return malloc(cr->Size()); +} + +void cppyy_deallocate(cppyy_typehandle_t /*handle*/, cppyy_object_t instance) { + free((void*)instance); +} + +void cppyy_destruct(cppyy_typehandle_t handle, cppyy_object_t self) { + TClassRef cr = type_from_handle(handle); + cr->Destructor((void*)self, true); +} + + +/* method/function dispatching -------------------------------------------- */ +long cppyy_call_o(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[], + cppyy_typehandle_t rettype) { + void* result = cppyy_allocate(rettype); + /* TODO: perform call ... */ + return (long)result; +} + +static inline G__value cppyy_call_T(cppyy_typehandle_t handle, + int method_index, cppyy_object_t self, int numargs, void* args[]) { + TClassRef cr = type_from_handle(handle); + TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); + + G__InterfaceMethod meth = (G__InterfaceMethod)m->InterfaceMethod(); + G__param libp; + for (int i = 0; i < numargs; ++i ) { + G__letint(&libp.para[i], 'u', *(long*)args[i]); // TODO: use actual type code + } + + G__value result; + meth(&result, 0, &libp, 0); + + return result; +} + +void cppyy_call_v(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + cppyy_call_T(handle, method_index, self, numargs, args); +} + +int cppyy_call_b(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + G__value result = cppyy_call_T(handle, method_index, self, numargs, args); + return (bool)G__int(result); +} + +char cppyy_call_c(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + G__value result = cppyy_call_T(handle, method_index, self, numargs, args); + return (char)G__int(result); +} + +short cppyy_call_h(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + G__value result = cppyy_call_T(handle, method_index, self, numargs, args); + return (short)G__int(result); +} + +long cppyy_call_l(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + G__value result = cppyy_call_T(handle, method_index, self, numargs, args); + return G__int(result); +} + +double cppyy_call_f(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + G__value result = cppyy_call_T(handle, method_index, self, numargs, args); + return G__double(result); +} + +double cppyy_call_d(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + G__value result = cppyy_call_T(handle, method_index, self, numargs, args); + return G__double(result); +} + + +cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_typehandle_t /*handle*/, int /*method_index*/) { + return (cppyy_methptrgetter_t)NULL; +} + + +/* scope reflection information ------------------------------------------- */ +int cppyy_is_namespace(cppyy_typehandle_t handle) { + TClassRef cr = type_from_handle(handle); + if (cr.GetClass() && cr->Property()) + return cr->Property() & G__BIT_ISNAMESPACE; + if (strcmp(cr.GetClassName(), "") == 0) + return true; + return false; +} + + +/* type/class reflection information -------------------------------------- */ +char* cppyy_final_name(cppyy_typehandle_t handle) { + TClassRef cr = type_from_handle(handle); + if (cr.GetClass() && cr->Property()) + return type_cppstring_to_cstring(cr->GetName()); + return cppstring_to_cstring(cr.GetClassName()); +} + +int cppyy_num_bases(cppyy_typehandle_t handle) { + TClassRef cr = type_from_handle(handle); + if (cr.GetClass() && cr->GetListOfBases() != 0) + return cr->GetListOfBases()->GetSize(); + return 0; +} + +char* cppyy_base_name(cppyy_typehandle_t handle, int base_index) { + TClassRef cr = type_from_handle(handle); + TBaseClass* b = (TBaseClass*)cr->GetListOfBases()->At(base_index); + return type_cppstring_to_cstring(b->GetName()); +} + +int cppyy_is_subtype(cppyy_typehandle_t dh, cppyy_typehandle_t bh) { + if (dh == bh) + return 1; + TClassRef crd = type_from_handle(dh); + TClassRef crb = type_from_handle(bh); + return (int)crd->GetBaseClass(crb); +} + +size_t cppyy_base_offset(cppyy_typehandle_t dh, cppyy_typehandle_t bh) { + if (dh == bh) + return 0; + TClassRef crd = type_from_handle(dh); + TClassRef crb = type_from_handle(bh); + return (size_t)crd->GetBaseClassOffset(crb); +} + + +/* method/function reflection information --------------------------------- */ +int cppyy_num_methods(cppyy_typehandle_t handle) { + TClassRef cr = type_from_handle(handle); + if (cr.GetClass() && cr->GetListOfMethods()) + return cr->GetListOfMethods()->GetSize(); + return 0; +} + +char* cppyy_method_name(cppyy_typehandle_t handle, int method_index) { + TClassRef cr = type_from_handle(handle); + TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); + return cppstring_to_cstring(m->GetName()); +} + +char* cppyy_method_result_type(cppyy_typehandle_t handle, int method_index) { + TClassRef cr = type_from_handle(handle); + TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); + std::string name = TClassEdit::CleanType(m->GetReturnTypeName(), 1); + return type_cppstring_to_cstring(name); +} + +int cppyy_method_num_args(cppyy_typehandle_t handle, int method_index) { + TClassRef cr = type_from_handle(handle); + TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); + return m->GetNargs(); +} + +int cppyy_method_req_args(cppyy_typehandle_t handle, int method_index) { + TClassRef cr = type_from_handle(handle); + TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); + return m->GetNargs() - m->GetNargsOpt(); +} + +char* cppyy_method_arg_type(cppyy_typehandle_t handle, int method_index, int arg_index) { + TClassRef cr = type_from_handle(handle); + TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); + TMethodArg* arg = (TMethodArg*)m->GetListOfMethodArgs()->At(arg_index); + return type_cppstring_to_cstring(arg->GetFullTypeName()); +} + + +int cppyy_is_constructor(cppyy_typehandle_t handle, int method_index) { + TClassRef cr = type_from_handle(handle); + TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); + return strcmp(m->GetName(), cr->GetName()) == 0; +} + +int cppyy_is_staticmethod(cppyy_typehandle_t handle, int method_index) { + TClassRef cr = type_from_handle(handle); + TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); + return m->Property() & G__BIT_ISSTATIC; +} + + +/* data member reflection information ------------------------------------- */ +int cppyy_num_data_members(cppyy_typehandle_t handle) { + TClassRef cr = type_from_handle(handle); + if (cr.GetClass() && cr->GetListOfDataMembers()) + return cr->GetListOfDataMembers()->GetSize(); + return 0; +} + +char* cppyy_data_member_name(cppyy_typehandle_t handle, int data_member_index) { + TClassRef cr = type_from_handle(handle); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(data_member_index); + return cppstring_to_cstring(m->GetName()); +} + +char* cppyy_data_member_type(cppyy_typehandle_t handle, int data_member_index) { + TClassRef cr = type_from_handle(handle); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(data_member_index); + return cppstring_to_cstring(m->GetFullTypeName()); +} + +size_t cppyy_data_member_offset(cppyy_typehandle_t handle, int data_member_index) { + TClassRef cr = type_from_handle(handle); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(data_member_index); + return m->GetOffset(); +} + + +int cppyy_is_staticdata(cppyy_typehandle_t handle, int data_member_index) { + TClassRef cr = type_from_handle(handle); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(data_member_index); + return m->Property() & G__BIT_ISSTATIC; +} + + +/* misc helper ------------------------------------------------------------ */ +void cppyy_free(void* ptr) { + free(ptr); +} diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx --- a/pypy/module/cppyy/src/reflexcwrapper.cxx +++ b/pypy/module/cppyy/src/reflexcwrapper.cxx @@ -1,5 +1,14 @@ #include "cppyy.h" #include "reflexcwrapper.h" + +#include "Reflex/Type.h" +#include "Reflex/Base.h" +#include "Reflex/Member.h" +#include "Reflex/Object.h" +#include "Reflex/Builder/TypeBuilder.h" +#include "Reflex/PropertyList.h" +#include "Reflex/TypeTemplate.h" + #include #include #include @@ -77,7 +86,7 @@ void cppyy_destruct(cppyy_typehandle_t handle, cppyy_object_t self) { Reflex::Type t = type_from_handle(handle); - t.Destruct(self, true); + t.Destruct((void*)self, true); } @@ -98,8 +107,7 @@ long cppyy_call_o(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[], cppyy_typehandle_t rettype) { - Reflex::Type rt = type_from_handle(rettype); - void* result = rt.Allocate(); + void* result = cppyy_allocate(rettype); std::vector arguments(args, args+numargs); Reflex::Scope s = scope_from_handle(handle); Reflex::Member m = s.FunctionMemberAt(method_index); @@ -214,7 +222,7 @@ return 0; Reflex::Type td = type_from_handle(dh); Reflex::Type tb = type_from_handle(bh); - return base_offset(td, tb); + return (size_t)base_offset(td, tb); } diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile --- a/pypy/module/cppyy/test/Makefile +++ b/pypy/module/cppyy/test/Makefile @@ -22,6 +22,9 @@ $(genreflex) example01.h $(genreflexflags) --selection=example01.xml g++ -o $@ example01_rflx.cpp example01.cxx -shared -lReflex $(cppflags) $(cppflags2) +# rootcint -f example01_cint.cxx -c example01.h +# g++ -I$ROOTSYS/include example01_cint.cxx example01.cxx -shared -o example01Dict.so -L$ROOTSYS/lib -lCore -lCint + datatypesDict.so: datatypes.cxx datatypes.h $(genreflex) datatypes.h $(genreflexflags) g++ -o $@ datatypes_rflx.cpp datatypes.cxx -shared -lReflex $(cppflags) $(cppflags2) diff --git a/pypy/module/cppyy/test/bench1.py b/pypy/module/cppyy/test/bench1.py --- a/pypy/module/cppyy/test/bench1.py +++ b/pypy/module/cppyy/test/bench1.py @@ -30,9 +30,10 @@ self.cls = PyCintex.gbl.example01 self.inst = self.cls(0) - self.scale = 10 def __call__(self): + # note that PyCintex calls don't actually scale linearly, but worse + # than linear (leak or wrong filling of a cache??) instance = self.inst niter = NNN/self.scale for i in range(niter): From noreply at buildbot.pypy.org Sat Jul 9 00:13:27 2011 From: noreply at buildbot.pypy.org (wlav) Date: Sat, 9 Jul 2011 00:13:27 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge heads Message-ID: <20110708221327.5678D820AE@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45428:9ef9fe98b7a3 Date: 2011-07-08 15:18 -0700 http://bitbucket.org/pypy/pypy/changeset/9ef9fe98b7a3/ Log: merge heads diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -351,7 +351,9 @@ self.cpptype = cpptype # TODO: factor out the direct_ptradd into a smaller function (so that the - # JIT can look into the rest of the code) + # JIT can look into the rest of the code), or better, let the JIT + # see it (either by teaching it direct_ptradd, or by using a + # different style like casts between addresses and integers) @jit.dont_look_inside def convert_argument(self, space, w_obj): from pypy.module.cppyy.interp_cppyy import W_CPPInstance From noreply at buildbot.pypy.org Sat Jul 9 10:33:48 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 9 Jul 2011 10:33:48 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Disable usage of the register for non-standalone translations. Message-ID: <20110709083348.12987820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r45429:622cdee7ad2d Date: 2011-07-08 21:48 +0200 http://bitbucket.org/pypy/pypy/changeset/622cdee7ad2d/ Log: Disable usage of the register for non-standalone translations. diff --git a/pypy/translator/c/database.py b/pypy/translator/c/database.py --- a/pypy/translator/c/database.py +++ b/pypy/translator/c/database.py @@ -60,7 +60,8 @@ if translator is None or translator.rtyper is None: self.exctransformer = None else: - self.exctransformer = translator.getexceptiontransformer() + self.exctransformer = translator.getexceptiontransformer( + standalone=standalone) if translator is not None: self.gctransformer = self.gcpolicy.transformerclass(translator) self.completed = False diff --git a/pypy/translator/exceptiontransform.py b/pypy/translator/exceptiontransform.py --- a/pypy/translator/exceptiontransform.py +++ b/pypy/translator/exceptiontransform.py @@ -52,8 +52,9 @@ class BaseExceptionTransformer(object): - def __init__(self, translator): + def __init__(self, translator, standalone): self.translator = translator + self.standalone = standalone self.raise_analyzer = canraise.RaiseAnalyzer(translator) edata = translator.rtyper.getexceptiondata() self.lltype_of_exception_value = edata.lltype_of_exception_value @@ -73,19 +74,21 @@ assertion_error_ll_exc_type) self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type) - if register.register_number is not None: + use_special_reg = standalone and register.register_number is not None + self.use_special_reg = use_special_reg + if use_special_reg: self.c_nonnull_specialregister = constant_value(register.nonnull) self.c_load_from_reg = constant_value(register.load_from_reg) self.c_reg_is_nonnull = constant_value(register.reg_is_nonnull) self.c_store_into_reg = constant_value(register.store_into_reg) def rpyexc_occured(): - if register.register_number is None: + if use_special_reg: + # an exception occurred iff the special register is 0 + return register.load_from_reg() == llmemory.NULL + else: exc_type = exc_data.exc_type return bool(exc_type) - else: - # an exception occurred iff the special register is 0 - return register.load_from_reg() == llmemory.NULL def rpyexc_fetch_type(): return exc_data.exc_type @@ -94,7 +97,7 @@ return exc_data.exc_value def rpyexc_clear(): - if register.register_number is not None: + if use_special_reg: register.store_into_reg(register.nonnull) exc_data.exc_type = null_type exc_data.exc_value = null_value @@ -112,14 +115,14 @@ exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_start_traceback(lltype.Void, etype) - if register.register_number is not None: + if use_special_reg: register.store_into_reg(llmemory.NULL) def rpyexc_reraise(etype, evalue): exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_reraise_traceback(lltype.Void, etype) - if register.register_number is not None: + if use_special_reg: register.store_into_reg(llmemory.NULL) def rpyexc_fetch_exception(): @@ -131,7 +134,7 @@ if evalue: exc_data.exc_type = rclass.ll_inst_type(evalue) exc_data.exc_value = evalue - if register.register_number is not None: + if use_special_reg: register.store_into_reg(llmemory.NULL) def rpyexc_raise_stack_overflow(): @@ -428,7 +431,7 @@ # self.gen_setfield('exc_value', self.c_null_evalue, llops) self.gen_setfield('exc_type', self.c_null_etype, llops) - if register.register_number is not None: + if self.use_special_reg: self.gen_setspecialregister(self.c_nonnull_specialregister, llops) excblock.operations[:] = llops newgraph.exceptblock.inputargs[0].concretetype = self.lltype_of_exception_type @@ -453,11 +456,11 @@ if alloc_shortcut: T = spaceop.result.concretetype var_no_exc = self.gen_nonnull(spaceop.result, llops) - elif register.register_number is None: + elif self.use_special_reg: + var_no_exc = self.gen_specialreg_no_exc(llops) + else: v_exc_type = self.gen_getfield('exc_type', llops) var_no_exc = self.gen_isnull(v_exc_type, llops) - else: - var_no_exc = self.gen_specialreg_no_exc(llops) block.operations.extend(llops) @@ -647,10 +650,10 @@ def build_extra_funcs(self): pass -def ExceptionTransformer(translator): +def ExceptionTransformer(translator, standalone): type_system = translator.rtyper.type_system.name if type_system == 'lltypesystem': - return LLTypeExceptionTransformer(translator) + return LLTypeExceptionTransformer(translator, standalone) else: assert type_system == 'ootypesystem' - return OOTypeExceptionTransformer(translator) + return OOTypeExceptionTransformer(translator, standalone) diff --git a/pypy/translator/translator.py b/pypy/translator/translator.py --- a/pypy/translator/translator.py +++ b/pypy/translator/translator.py @@ -108,13 +108,14 @@ type_system = type_system) return self.rtyper - def getexceptiontransformer(self): + def getexceptiontransformer(self, standalone): if self.rtyper is None: raise ValueError("no rtyper") if self.exceptiontransformer is not None: + assert self.exceptiontransformer.standalone == standalone return self.exceptiontransformer from pypy.translator.exceptiontransform import ExceptionTransformer - self.exceptiontransformer = ExceptionTransformer(self) + self.exceptiontransformer = ExceptionTransformer(self, standalone) return self.exceptiontransformer def checkgraphs(self): From noreply at buildbot.pypy.org Sat Jul 9 11:17:25 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 9 Jul 2011 11:17:25 +0200 (CEST) Subject: [pypy-commit] pypy r15-for-exception: Mostly comments for now, describing the goal. Message-ID: <20110709091725.321BA820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: r15-for-exception Changeset: r45430:d1c160a1df55 Date: 2011-07-07 12:33 +0200 http://bitbucket.org/pypy/pypy/changeset/d1c160a1df55/ Log: Mostly comments for now, describing the goal. diff --git a/pypy/translator/register.py b/pypy/translator/register.py new file mode 100644 --- /dev/null +++ b/pypy/translator/register.py @@ -0,0 +1,35 @@ +from pypy.translator.tool.cbuild import ExternalCompilationInfo +from pypy.rpython.tool import rffi_platform + +# On platforms with enough hardware registers and with gcc, we can +# (ab)use gcc to globally assign a register to a single global void* +# variable. We use it with a double meaning: +# +# - when it is NULL upon return from a function, it means that an +# exception occurred. It allows the caller to quickly check for +# exceptions. +# +# - in other cases, with --gcrootfinder=shadowstack, it points to +# the top of the shadow stack. + + +# For now, only for x86-64. Tries to use the register r15. +eci = ExternalCompilationInfo( + post_include_bits=['register void* pypy_reg asm("r15");'], + ) + +_test_eci = eci.merge(ExternalCompilationInfo( + post_include_bits=[""" + void f(void) { + pypy_reg = &f; + } + """])) + +try: + rffi_platform.verify_eci(_test_eci) + var_name_in_c = 'pypy_reg' + register_number = 15 # r15 +except rffi_platform.CompilationError: + eci = None + var_name_in_c = None + register_number = None diff --git a/pypy/translator/test/test_register.py b/pypy/translator/test/test_register.py new file mode 100644 --- /dev/null +++ b/pypy/translator/test/test_register.py @@ -0,0 +1,13 @@ + +def test_register(): + from pypy.translator import register + # + from pypy.jit.backend.detect_cpu import autodetect + if autodetect() == 'x86_64': + assert register.eci is not None + assert register.var_name_in_c is not None + assert register.register_number == 15 # r15 + else: + assert register.eci is None + assert register.var_name_in_c is None + assert register.register_number is None From noreply at buildbot.pypy.org Sat Jul 9 11:17:26 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 9 Jul 2011 11:17:26 +0200 (CEST) Subject: [pypy-commit] pypy r15-for-exception: Complete pypy.rlib.register. Message-ID: <20110709091726.7158F820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: r15-for-exception Changeset: r45431:871dc1fecff3 Date: 2011-07-08 19:48 +0200 http://bitbucket.org/pypy/pypy/changeset/871dc1fecff3/ Log: Complete pypy.rlib.register. diff --git a/pypy/translator/register.py b/pypy/rlib/register.py rename from pypy/translator/register.py rename to pypy/rlib/register.py --- a/pypy/translator/register.py +++ b/pypy/rlib/register.py @@ -15,21 +15,50 @@ # For now, only for x86-64. Tries to use the register r15. eci = ExternalCompilationInfo( - post_include_bits=['register void* pypy_reg asm("r15");'], + post_include_bits=['register void* pypy_r15 asm("r15");\n' + '#define PYPY_GET_R15() pypy_r15\n' + '#define PYPY_SET_R15(x) (pypy_r15 = x)\n' + ], ) _test_eci = eci.merge(ExternalCompilationInfo( post_include_bits=[""" void f(void) { - pypy_reg = &f; + pypy_r15 = &f; } """])) try: rffi_platform.verify_eci(_test_eci) - var_name_in_c = 'pypy_reg' register_number = 15 # r15 except rffi_platform.CompilationError: eci = None - var_name_in_c = None register_number = None +else: + + from pypy.rpython.lltypesystem import lltype, llmemory, rffi + + # use load_from_reg(TYPE) and store_into_reg(llvalue) to load and store + # a value out of the special register. When running on top of Python. + # the behavior is emulated. + + _value_reg = None + + def _pypy_get_r15(): + assert _value_reg is not None + return _value_reg + + def _pypy_set_r15(addr): + global _value_reg + _value_reg = addr + + load_from_reg = rffi.llexternal('PYPY_GET_R15', [], llmemory.Address, + _callable=_pypy_get_r15, + compilation_info=eci, + _nowrapper=True) + + store_into_reg = rffi.llexternal('PYPY_SET_R15', [llmemory.Address], + lltype.Void, + _callable=_pypy_set_r15, + compilation_info=eci, + _nowrapper=True) diff --git a/pypy/translator/test/test_register.py b/pypy/rlib/test/test_register.py rename from pypy/translator/test/test_register.py rename to pypy/rlib/test/test_register.py --- a/pypy/translator/test/test_register.py +++ b/pypy/rlib/test/test_register.py @@ -1,13 +1,48 @@ +import py +from pypy.rlib import register +from pypy.rpython.lltypesystem import lltype, llmemory, rffi + def test_register(): - from pypy.translator import register # from pypy.jit.backend.detect_cpu import autodetect if autodetect() == 'x86_64': assert register.eci is not None - assert register.var_name_in_c is not None assert register.register_number == 15 # r15 else: assert register.eci is None - assert register.var_name_in_c is None assert register.register_number is None + + +class TestLoadStore(object): + def setup_class(cls): + if register.register_number is None: + py.test.skip("rlib/register not supported on this platform") + + def test_direct(self): + a = rffi.cast(llmemory.Address, 27) + register.store_into_reg(a) + b = register.load_from_reg() + assert lltype.typeOf(b) == llmemory.Address + assert rffi.cast(lltype.Signed, b) == 27 + + def test_llinterp(self): + from pypy.rpython.test.test_llinterp import interpret + def f(n): + a = rffi.cast(llmemory.Address, n) + register.store_into_reg(a) + b = register.load_from_reg() + return rffi.cast(lltype.Signed, b) + res = interpret(f, [41]) + assert res == 41 + + def test_compiled(self): + from pypy.translator.c.test.test_genc import compile + def f(n): + a = rffi.cast(llmemory.Address, n) + register.store_into_reg(a) + b = register.load_from_reg() + return rffi.cast(lltype.Signed, b) + cfn = compile(f, [int]) + res = cfn(43) + assert res == 43 From noreply at buildbot.pypy.org Sat Jul 9 11:17:27 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 9 Jul 2011 11:17:27 +0200 (CEST) Subject: [pypy-commit] pypy r15-for-exception: In-progress: try to use r15 for signalling exceptions. Message-ID: <20110709091727.AB788820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: r15-for-exception Changeset: r45432:d0281a8b1360 Date: 2011-07-08 20:38 +0200 http://bitbucket.org/pypy/pypy/changeset/d0281a8b1360/ Log: In-progress: try to use r15 for signalling exceptions. diff --git a/pypy/rlib/register.py b/pypy/rlib/register.py --- a/pypy/rlib/register.py +++ b/pypy/rlib/register.py @@ -15,10 +15,12 @@ # For now, only for x86-64. Tries to use the register r15. eci = ExternalCompilationInfo( - post_include_bits=['register void* pypy_r15 asm("r15");\n' - '#define PYPY_GET_R15() pypy_r15\n' - '#define PYPY_SET_R15(x) (pypy_r15 = x)\n' - ], + post_include_bits=[ + 'register void *pypy_r15 asm("r15");\n' + '#define PYPY_GET_SPECIAL_REG() pypy_r15\n' + '#define PYPY_SPECIAL_REG_NONNULL() (pypy_r15 != NULL)\n' + '#define PYPY_SET_SPECIAL_REG(x) (pypy_r15 = x)\n' + ], ) _test_eci = eci.merge(ExternalCompilationInfo( @@ -38,27 +40,42 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi - # use load_from_reg(TYPE) and store_into_reg(llvalue) to load and store - # a value out of the special register. When running on top of Python. + # use addr=load_from_reg() and store_into_reg(addr) to load and store + # an Address out of the special register. When running on top of Python, # the behavior is emulated. _value_reg = None - def _pypy_get_r15(): + def _pypy_get_special_reg(): assert _value_reg is not None return _value_reg - def _pypy_set_r15(addr): + def _pypy_special_reg_nonnull(): + assert _value_reg is not None + return bool(_value_reg) + + def _pypy_set_special_reg(addr): global _value_reg _value_reg = addr - load_from_reg = rffi.llexternal('PYPY_GET_R15', [], llmemory.Address, - _callable=_pypy_get_r15, + load_from_reg = rffi.llexternal('PYPY_GET_SPECIAL_REG', [], + llmemory.Address, + _callable=_pypy_get_special_reg, compilation_info=eci, _nowrapper=True) - store_into_reg = rffi.llexternal('PYPY_SET_R15', [llmemory.Address], - lltype.Void, - _callable=_pypy_set_r15, + reg_is_nonnull = rffi.llexternal('PYPY_SPECIAL_REG_NONNULL', [], + lltype.Bool, + _callable=_pypy_special_reg_nonnull, compilation_info=eci, _nowrapper=True) + + store_into_reg = rffi.llexternal('PYPY_SET_SPECIAL_REG', + [llmemory.Address], + lltype.Void, + _callable=_pypy_set_special_reg, + compilation_info=eci, + _nowrapper=True) + + # xxx temporary + nonnull = llmemory.cast_int_to_adr(-1) diff --git a/pypy/rlib/test/test_register.py b/pypy/rlib/test/test_register.py --- a/pypy/rlib/test/test_register.py +++ b/pypy/rlib/test/test_register.py @@ -1,6 +1,7 @@ import py from pypy.rlib import register from pypy.rpython.lltypesystem import lltype, llmemory, rffi +from pypy.translator.c.test.test_standalone import StandaloneTests def test_register(): @@ -36,13 +37,19 @@ res = interpret(f, [41]) assert res == 41 + +class TestLoadStoreCompiled(StandaloneTests): + def setup_class(cls): + if register.register_number is None: + py.test.skip("rlib/register not supported on this platform") + def test_compiled(self): - from pypy.translator.c.test.test_genc import compile - def f(n): - a = rffi.cast(llmemory.Address, n) + def f(argv): + a = rffi.cast(llmemory.Address, 43) register.store_into_reg(a) b = register.load_from_reg() - return rffi.cast(lltype.Signed, b) - cfn = compile(f, [int]) - res = cfn(43) - assert res == 43 + print rffi.cast(lltype.Signed, b) + return 0 + t, cbuilder = self.compile(f) + data = cbuilder.cmdexec('') + assert data.startswith('43\n') diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h --- a/pypy/translator/c/src/main.h +++ b/pypy/translator/c/src/main.h @@ -34,6 +34,10 @@ char *errmsg; int i, exitcode; RPyListOfString *list; +#ifdef PYPY_GET_SPECIAL_REG + void *pypy_reg_oldvalue = PYPY_GET_SPECIAL_REG(); + PYPY_SET_SPECIAL_REG((void*)-1); +#endif pypy_asm_stack_bottom(); instrument_setup(); @@ -70,6 +74,10 @@ pypy_debug_catch_fatal_exception(); } +#ifdef PYPY_GET_SPECIAL_REG + PYPY_SET_SPECIAL_REG(pypy_reg_oldvalue); +#endif + return exitcode; memory_out: @@ -79,7 +87,7 @@ fprintf(stderr, "Fatal error during initialization: %s\n", errmsg); #endif abort(); - return 1; + return 1; /* not actually reachable */ } int PYPY_MAIN_FUNCTION(int argc, char *argv[]) diff --git a/pypy/translator/exceptiontransform.py b/pypy/translator/exceptiontransform.py --- a/pypy/translator/exceptiontransform.py +++ b/pypy/translator/exceptiontransform.py @@ -14,6 +14,7 @@ from pypy.rlib.rarithmetic import r_singlefloat from pypy.rlib.debug import ll_assert from pypy.rlib.rstackovf import _StackOverflow +from pypy.rlib import register from pypy.annotation import model as annmodel from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.tool.sourcetools import func_with_new_name @@ -72,9 +73,19 @@ assertion_error_ll_exc_type) self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type) + if register.register_number is not None: + self.c_nonnull_specialregister = constant_value(register.nonnull) + self.c_load_from_reg = constant_value(register.load_from_reg) + self.c_reg_is_nonnull = constant_value(register.reg_is_nonnull) + self.c_store_into_reg = constant_value(register.store_into_reg) + def rpyexc_occured(): - exc_type = exc_data.exc_type - return bool(exc_type) + if register.register_number is None: + exc_type = exc_data.exc_type + return bool(exc_type) + else: + # an exception occurred iff the special register is 0 + return register.load_from_reg() == llmemory.NULL def rpyexc_fetch_type(): return exc_data.exc_type @@ -83,6 +94,8 @@ return exc_data.exc_value def rpyexc_clear(): + if register.register_number is not None: + register.store_into_reg(register.nonnull) exc_data.exc_type = null_type exc_data.exc_value = null_value @@ -99,11 +112,15 @@ exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_start_traceback(lltype.Void, etype) + if register.register_number is not None: + register.store_into_reg(llmemory.NULL) def rpyexc_reraise(etype, evalue): exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_reraise_traceback(lltype.Void, etype) + if register.register_number is not None: + register.store_into_reg(llmemory.NULL) def rpyexc_fetch_exception(): evalue = rpyexc_fetch_value() @@ -114,6 +131,8 @@ if evalue: exc_data.exc_type = rclass.ll_inst_type(evalue) exc_data.exc_value = evalue + if register.register_number is not None: + register.store_into_reg(llmemory.NULL) def rpyexc_raise_stack_overflow(): rpyexc_raise(stackovf_ll_exc_type, stackovf_ll_exc) @@ -409,6 +428,8 @@ # self.gen_setfield('exc_value', self.c_null_evalue, llops) self.gen_setfield('exc_type', self.c_null_etype, llops) + if register.register_number is not None: + self.gen_setspecialregister(self.c_nonnull_specialregister, llops) excblock.operations[:] = llops newgraph.exceptblock.inputargs[0].concretetype = self.lltype_of_exception_type newgraph.exceptblock.inputargs[1].concretetype = self.lltype_of_exception_value @@ -432,9 +453,11 @@ if alloc_shortcut: T = spaceop.result.concretetype var_no_exc = self.gen_nonnull(spaceop.result, llops) - else: + elif register.register_number is None: v_exc_type = self.gen_getfield('exc_type', llops) var_no_exc = self.gen_isnull(v_exc_type, llops) + else: + var_no_exc = self.gen_specialreg_no_exc(llops) block.operations.extend(llops) @@ -527,6 +550,17 @@ def gen_nonnull(self, v, llops): return llops.genop('ptr_nonzero', [v], lltype.Bool) + def gen_getspecialregister(self, llops): + return llops.genop('direct_call', [self.c_load_from_reg], + resulttype = llmemory.Address) + + def gen_specialreg_no_exc(self, llops): + return llops.genop('direct_call', [self.c_reg_is_nonnull], + resulttype = lltype.Bool) + + def gen_setspecialregister(self, v, llops): + llops.genop('direct_call', [self.c_store_into_reg, v]) + def same_obj(self, ptr1, ptr2): return ptr1._same_obj(ptr2) From noreply at buildbot.pypy.org Sat Jul 9 11:17:28 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 9 Jul 2011 11:17:28 +0200 (CEST) Subject: [pypy-commit] pypy r15-for-exception: Disable usage of the register for non-standalone translations. Message-ID: <20110709091728.E459C820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: r15-for-exception Changeset: r45433:672eead01a28 Date: 2011-07-08 21:48 +0200 http://bitbucket.org/pypy/pypy/changeset/672eead01a28/ Log: Disable usage of the register for non-standalone translations. diff --git a/pypy/translator/c/database.py b/pypy/translator/c/database.py --- a/pypy/translator/c/database.py +++ b/pypy/translator/c/database.py @@ -60,7 +60,8 @@ if translator is None or translator.rtyper is None: self.exctransformer = None else: - self.exctransformer = translator.getexceptiontransformer() + self.exctransformer = translator.getexceptiontransformer( + standalone=standalone) if translator is not None: self.gctransformer = self.gcpolicy.transformerclass(translator) self.completed = False diff --git a/pypy/translator/exceptiontransform.py b/pypy/translator/exceptiontransform.py --- a/pypy/translator/exceptiontransform.py +++ b/pypy/translator/exceptiontransform.py @@ -52,8 +52,9 @@ class BaseExceptionTransformer(object): - def __init__(self, translator): + def __init__(self, translator, standalone): self.translator = translator + self.standalone = standalone self.raise_analyzer = canraise.RaiseAnalyzer(translator) edata = translator.rtyper.getexceptiondata() self.lltype_of_exception_value = edata.lltype_of_exception_value @@ -73,19 +74,21 @@ assertion_error_ll_exc_type) self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type) - if register.register_number is not None: + use_special_reg = standalone and register.register_number is not None + self.use_special_reg = use_special_reg + if use_special_reg: self.c_nonnull_specialregister = constant_value(register.nonnull) self.c_load_from_reg = constant_value(register.load_from_reg) self.c_reg_is_nonnull = constant_value(register.reg_is_nonnull) self.c_store_into_reg = constant_value(register.store_into_reg) def rpyexc_occured(): - if register.register_number is None: + if use_special_reg: + # an exception occurred iff the special register is 0 + return register.load_from_reg() == llmemory.NULL + else: exc_type = exc_data.exc_type return bool(exc_type) - else: - # an exception occurred iff the special register is 0 - return register.load_from_reg() == llmemory.NULL def rpyexc_fetch_type(): return exc_data.exc_type @@ -94,7 +97,7 @@ return exc_data.exc_value def rpyexc_clear(): - if register.register_number is not None: + if use_special_reg: register.store_into_reg(register.nonnull) exc_data.exc_type = null_type exc_data.exc_value = null_value @@ -112,14 +115,14 @@ exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_start_traceback(lltype.Void, etype) - if register.register_number is not None: + if use_special_reg: register.store_into_reg(llmemory.NULL) def rpyexc_reraise(etype, evalue): exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_reraise_traceback(lltype.Void, etype) - if register.register_number is not None: + if use_special_reg: register.store_into_reg(llmemory.NULL) def rpyexc_fetch_exception(): @@ -131,7 +134,7 @@ if evalue: exc_data.exc_type = rclass.ll_inst_type(evalue) exc_data.exc_value = evalue - if register.register_number is not None: + if use_special_reg: register.store_into_reg(llmemory.NULL) def rpyexc_raise_stack_overflow(): @@ -428,7 +431,7 @@ # self.gen_setfield('exc_value', self.c_null_evalue, llops) self.gen_setfield('exc_type', self.c_null_etype, llops) - if register.register_number is not None: + if self.use_special_reg: self.gen_setspecialregister(self.c_nonnull_specialregister, llops) excblock.operations[:] = llops newgraph.exceptblock.inputargs[0].concretetype = self.lltype_of_exception_type @@ -453,11 +456,11 @@ if alloc_shortcut: T = spaceop.result.concretetype var_no_exc = self.gen_nonnull(spaceop.result, llops) - elif register.register_number is None: + elif self.use_special_reg: + var_no_exc = self.gen_specialreg_no_exc(llops) + else: v_exc_type = self.gen_getfield('exc_type', llops) var_no_exc = self.gen_isnull(v_exc_type, llops) - else: - var_no_exc = self.gen_specialreg_no_exc(llops) block.operations.extend(llops) @@ -647,10 +650,10 @@ def build_extra_funcs(self): pass -def ExceptionTransformer(translator): +def ExceptionTransformer(translator, standalone): type_system = translator.rtyper.type_system.name if type_system == 'lltypesystem': - return LLTypeExceptionTransformer(translator) + return LLTypeExceptionTransformer(translator, standalone) else: assert type_system == 'ootypesystem' - return OOTypeExceptionTransformer(translator) + return OOTypeExceptionTransformer(translator, standalone) diff --git a/pypy/translator/translator.py b/pypy/translator/translator.py --- a/pypy/translator/translator.py +++ b/pypy/translator/translator.py @@ -108,13 +108,14 @@ type_system = type_system) return self.rtyper - def getexceptiontransformer(self): + def getexceptiontransformer(self, standalone): if self.rtyper is None: raise ValueError("no rtyper") if self.exceptiontransformer is not None: + assert self.exceptiontransformer.standalone == standalone return self.exceptiontransformer from pypy.translator.exceptiontransform import ExceptionTransformer - self.exceptiontransformer = ExceptionTransformer(self) + self.exceptiontransformer = ExceptionTransformer(self, standalone) return self.exceptiontransformer def checkgraphs(self): From noreply at buildbot.pypy.org Sat Jul 9 12:07:27 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 9 Jul 2011 12:07:27 +0200 (CEST) Subject: [pypy-commit] pypy r15-for-exception: Fix the x86 backend to not touch r15 for normal usage, but handle Message-ID: <20110709100727.9461D820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: r15-for-exception Changeset: r45434:83b783be61f3 Date: 2011-07-09 12:16 +0200 http://bitbucket.org/pypy/pypy/changeset/83b783be61f3/ Log: Fix the x86 backend to not touch r15 for normal usage, but handle it as the exception marker. diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -116,9 +116,12 @@ self.pos_exc_value = pos_exc_value self.save_exception = save_exception self.insert_stack_check = lambda: (0, 0, 0) + self.special_register = None def _setup_exception_handling_translated(self): + from pypy.rlib import register + from pypy.rlib.register import register_number def pos_exception(): addr = llop.get_exception_addr(llmemory.Address) @@ -129,6 +132,8 @@ return heaptracker.adr2int(addr) def save_exception(): + if register_number is not None: + register.store_into_reg(register.nonnull) addr = llop.get_exception_addr(llmemory.Address) addr.address[0] = llmemory.NULL addr = llop.get_exc_value_addr(llmemory.Address) @@ -153,6 +158,9 @@ self.pos_exc_value = pos_exc_value self.save_exception = save_exception self.insert_stack_check = insert_stack_check + self.special_register = register_number + self.special_register_nonnull = llmemory.cast_adr_to_int( + register.nonnull) def _setup_on_leave_jitted_untranslated(self): # assume we don't need a backend leave in this case diff --git a/pypy/jit/backend/x86/arch.py b/pypy/jit/backend/x86/arch.py --- a/pypy/jit/backend/x86/arch.py +++ b/pypy/jit/backend/x86/arch.py @@ -6,6 +6,8 @@ # during a malloc that needs to go via its slow path. import sys +from pypy.rlib.register import register_number as special_register + if sys.maxint == (2**31 - 1): WORD = 4 # ebp + ebx + esi + edi + 4 extra words + force_index = 9 words @@ -14,16 +16,23 @@ MY_COPY_OF_REGS = -7*WORD IS_X86_32 = True IS_X86_64 = False + assert special_register is None else: WORD = 8 - # rbp + rbx + r12 + r13 + r14 + r15 + 11 extra words + force_index = 18 + # rbp + rbx + r12 + r13 + r14 + r15? + 11 extra words + force_index = 18 FRAME_FIXED_SIZE = 18 FORCE_INDEX_OFS = -17*WORD MY_COPY_OF_REGS = -16*WORD IS_X86_32 = False IS_X86_64 = True + if special_register is not None: + assert special_register == 15 + # remove r15 from the saved registers and from the extra words + FRAME_FIXED_SIZE = 16 + FORCE_INDEX_OFS = -15*WORD + MY_COPY_OF_REGS = -14*WORD # The extra space has room for almost all registers, apart from eax and edx # which are used in the malloc itself. They are: # ecx, ebx, esi, edi [32 and 64 bits] -# r8, r9, r10, r12, r13, r14, r15 [64 bits only] +# r8, r9, r10, r12, r13, r14, r15? [64 bits only] diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -263,9 +263,14 @@ # esp is now aligned to a multiple of 16 again mc.CALL(imm(slowpathaddr)) # - mc.MOV(eax, heap(self.cpu.pos_exception())) - mc.TEST_rr(eax.value, eax.value) - mc.J_il8(rx86.Conditions['NZ'], 0) + if self.cpu.special_register is None: + mc.MOV(eax, heap(self.cpu.pos_exception())) + mc.TEST_rr(eax.value, eax.value) + mc.J_il8(rx86.Conditions['NZ'], 0) + else: + rnum = self.cpu.special_register + mc.TEST_rr(rnum, rnum) + mc.J_il8(rx86.Conditions['Z'], 0) jnz_location = mc.get_relative_pos() # if IS_X86_32: @@ -286,8 +291,7 @@ mc.overwrite(jnz_location-1, chr(offset)) # clear the exception from the global position mc.MOV(eax, heap(self.cpu.pos_exc_value())) - mc.MOV(heap(self.cpu.pos_exception()), imm0) - mc.MOV(heap(self.cpu.pos_exc_value()), imm0) + self.clear_current_exception(mc) # save the current exception instance into fail_boxes_ptr[0] adr = self.fail_boxes_ptr.get_addr_for_num(0) mc.MOV(heap(adr), eax) @@ -308,6 +312,13 @@ rawstart = mc.materialize(self.cpu.asmmemmgr, []) self.stack_check_slowpath = rawstart + def clear_current_exception(self, mc): + if self.cpu.special_register is not None: + mc.MOV_ri(self.cpu.special_register, + self.cpu.special_register_nonnull) + mc.MOV(heap(self.cpu.pos_exception()), imm0) + mc.MOV(heap(self.cpu.pos_exc_value()), imm0) + @staticmethod def _release_gil_asmgcc(css): # similar to trackgcroot.py:pypy_asm_stackwalk, first part @@ -1563,8 +1574,13 @@ def genop_guard_guard_no_exception(self, ign_1, guard_op, guard_token, locs, ign_2): - self.mc.CMP(heap(self.cpu.pos_exception()), imm0) - self.implement_guard(guard_token, 'NZ') + if self.cpu.special_register is None: + self.mc.CMP(heap(self.cpu.pos_exception()), imm0) + self.implement_guard(guard_token, 'NZ') + else: + rnum = self.cpu.special_register + self.mc.TEST_rr(rnum, rnum) + self.implement_guard(guard_token, 'Z') def genop_guard_guard_not_invalidated(self, ign_1, guard_op, guard_token, locs, ign_2): @@ -1575,14 +1591,11 @@ def genop_guard_guard_exception(self, ign_1, guard_op, guard_token, locs, resloc): loc = locs[0] - loc1 = locs[1] - self.mc.MOV(loc1, heap(self.cpu.pos_exception())) - self.mc.CMP(loc1, loc) + self.mc.CMP(heap(self.cpu.pos_exception()), loc) self.implement_guard(guard_token, 'NE') if resloc is not None: self.mc.MOV(resloc, heap(self.cpu.pos_exc_value())) - self.mc.MOV(heap(self.cpu.pos_exception()), imm0) - self.mc.MOV(heap(self.cpu.pos_exc_value()), imm0) + self.clear_current_exception(self.mc) def _gen_guard_overflow(self, guard_op, guard_token): guard_opnum = guard_op.getopnum() diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -19,7 +19,7 @@ from pypy.jit.backend.llsupport.descr import BaseCallDescr, BaseSizeDescr from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\ TempBox -from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE +from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE, special_register from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64, MY_COPY_OF_REGS from pypy.rlib.rarithmetic import r_longlong, r_uint @@ -56,8 +56,11 @@ not_implemented("convert_to_imm: got a %s" % c) class X86_64_RegisterManager(X86RegisterManager): - # r11 omitted because it's used as scratch - all_regs = [eax, ecx, edx, ebx, esi, edi, r8, r9, r10, r12, r13, r14, r15] + # r11 omitted because it's used as scratch; r15 is omitted if used + # as a special register + all_regs = [eax, ecx, edx, ebx, esi, edi, r8, r9, r10, r12, r13, r14] + if special_register is None: + all_regs.append(r15) no_lower_byte_regs = [] save_around_call_regs = [eax, ecx, edx, esi, edi, r8, r9, r10] @@ -79,8 +82,9 @@ r12: MY_COPY_OF_REGS + 7 * WORD, r13: MY_COPY_OF_REGS + 8 * WORD, r14: MY_COPY_OF_REGS + 9 * WORD, - r15: MY_COPY_OF_REGS + 10 * WORD, } + if special_register is None: + REGLOC_TO_COPY_AREA_OFS[r15] = MY_COPY_OF_REGS + 10 * WORD class X86XMMRegisterManager(RegisterManager): @@ -518,17 +522,13 @@ def consider_guard_exception(self, op): loc = self.rm.make_sure_var_in_reg(op.getarg(0)) - box = TempBox() - args = op.getarglist() - loc1 = self.rm.force_allocate_reg(box, args) if op.result in self.longevity: # this means, is it ever used - resloc = self.rm.force_allocate_reg(op.result, args + [box]) + resloc = self.rm.force_allocate_reg(op.result) else: resloc = None - self.perform_guard(op, [loc, loc1], resloc) + self.perform_guard(op, [loc], resloc) self.rm.possibly_free_vars_for_op(op) - self.rm.possibly_free_var(box) consider_guard_no_overflow = consider_guard_no_exception consider_guard_overflow = consider_guard_no_exception diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py --- a/pypy/jit/backend/x86/runner.py +++ b/pypy/jit/backend/x86/runner.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp import history, compile from pypy.jit.backend.x86.assembler import Assembler386 -from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS +from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS, special_register from pypy.jit.backend.x86.profagent import ProfileAgent from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU from pypy.jit.backend.x86 import regloc @@ -205,7 +205,9 @@ backend_name = 'x86_64' WORD = 8 NUM_REGS = 16 - CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.r12, regloc.r13, regloc.r14, regloc.r15] + CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.r12, regloc.r13, regloc.r14] + if special_register is None: + CALLEE_SAVE_REGISTERS.append(regloc.r15) def __init__(self, *args, **kwargs): assert sys.maxint == (2**63 - 1) From noreply at buildbot.pypy.org Sat Jul 9 12:13:59 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 9 Jul 2011 12:13:59 +0200 (CEST) Subject: [pypy-commit] pypy r15-for-exception: No-op: make the code more regular. Message-ID: <20110709101359.0ACA8820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: r15-for-exception Changeset: r45435:4c3883bc1f51 Date: 2011-07-09 12:21 +0200 http://bitbucket.org/pypy/pypy/changeset/4c3883bc1f51/ Log: No-op: make the code more regular. diff --git a/pypy/jit/backend/x86/arch.py b/pypy/jit/backend/x86/arch.py --- a/pypy/jit/backend/x86/arch.py +++ b/pypy/jit/backend/x86/arch.py @@ -19,18 +19,19 @@ assert special_register is None else: WORD = 8 - # rbp + rbx + r12 + r13 + r14 + r15? + 11 extra words + force_index = 18 - FRAME_FIXED_SIZE = 18 - FORCE_INDEX_OFS = -17*WORD - MY_COPY_OF_REGS = -16*WORD - IS_X86_32 = False - IS_X86_64 = True if special_register is not None: assert special_register == 15 - # remove r15 from the saved registers and from the extra words + # rbp + rbx + r12 + r13 + r14 + 10 extra words + force_index = 16 FRAME_FIXED_SIZE = 16 FORCE_INDEX_OFS = -15*WORD MY_COPY_OF_REGS = -14*WORD + else: + # rbp + rbx + r12 + r13 + r14 + r15 + 11 extra words + force_index = 18 + FRAME_FIXED_SIZE = 18 + FORCE_INDEX_OFS = -17*WORD + MY_COPY_OF_REGS = -16*WORD + IS_X86_32 = False + IS_X86_64 = True # The extra space has room for almost all registers, apart from eax and edx # which are used in the malloc itself. They are: From noreply at buildbot.pypy.org Sat Jul 9 16:03:26 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 9 Jul 2011 16:03:26 +0200 (CEST) Subject: [pypy-commit] pypy r15-for-exception: Hopefully fix all remaining places that are involved in C callbacks Message-ID: <20110709140326.01E5C820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: r15-for-exception Changeset: r45436:5c84150482d2 Date: 2011-07-09 16:12 +0200 http://bitbucket.org/pypy/pypy/changeset/5c84150482d2/ Log: Hopefully fix all remaining places that are involved in C callbacks (including multi-threading). Simplify a bit the approach, with an explicit 'saved' value to carry around the callback's code. diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -498,12 +498,13 @@ @specialize.ll() def wrapper(*args): + from pypy.rpython.lltypesystem import llmemory from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference # we hope that malloc removal removes the newtuple() that is # inserted exactly here by the varargs specializer - llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py rffi.stackcounter.stacks_counter += 1 + saved = llop.gc_stack_bottom(llmemory.Address) # for trackgcroot.py retval = fatal_value boxed_args = () try: @@ -572,6 +573,7 @@ else: print str(e) pypy_debug_catch_fatal_exception() + llop.gc_stack_bottom_stop(lltype.Void, saved) rffi.stackcounter.stacks_counter -= 1 return retval callable._always_inline_ = True diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -891,9 +891,6 @@ def op_gc_asmgcroot_static(self, index): raise NotImplementedError("gc_asmgcroot_static") - def op_gc_stack_bottom(self): - pass # marker for trackgcroot.py - def op_gc_get_type_info_group(self): raise NotImplementedError("gc_get_type_info_group") diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -503,6 +503,7 @@ # see translator/c/src/mem.h for the valid indices 'gc_asmgcroot_static': LLOp(sideeffects=False), 'gc_stack_bottom': LLOp(canrun=True), + 'gc_stack_bottom_stop': LLOp(canrun=True), # NOTE NOTE NOTE! don't forget *** canunwindgc=True *** for anything that # can go through a stack unwind, in particular anything that mallocs! diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -527,7 +527,10 @@ return debug.have_debug_prints() def op_gc_stack_bottom(): - pass # marker for trackgcroot.py + return llmemory.NULL # marker for trackgcroot.py + +def op_gc_stack_bottom_stop(saved): + pass # for rlib/register.py def op_jit_force_virtualizable(*args): pass diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -248,7 +248,7 @@ """ Function creating wrappers for callbacks. Note that this is cheating as we assume constant callbacks and we just memoize wrappers """ - from pypy.rpython.lltypesystem import lltype + from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem.lloperation import llop if hasattr(callable, '_errorcode_'): errorcode = callable._errorcode_ @@ -260,13 +260,15 @@ args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))]) source = py.code.Source(r""" def wrapper(%s): # no *args - no GIL for mallocing the tuple - llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py if aroundstate is not None: after = aroundstate.after if after: after() # from now on we hold the GIL stackcounter.stacks_counter += 1 + # marker for trackgcroot.py and for rlib/register.py: + # initialize the value of the special register + saved = llop.gc_stack_bottom(llmemory.Address) try: result = callable(%s) except Exception, e: @@ -277,6 +279,7 @@ import traceback traceback.print_exc() result = errorcode + llop.gc_stack_bottom_stop(lltype.Void, saved) stackcounter.stacks_counter -= 1 if aroundstate is not None: before = aroundstate.before diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -104,9 +104,6 @@ def OP_GC_ASSUME_YOUNG_POINTERS(self, funcgen, op): return '' - def OP_GC_STACK_BOTTOM(self, funcgen, op): - return '' - class RefcountingInfo: static_deallocator = None @@ -397,9 +394,6 @@ def GC_KEEPALIVE(self, funcgen, v): return 'pypy_asm_keepalive(%s);' % funcgen.expr(v) - def OP_GC_STACK_BOTTOM(self, funcgen, op): - return 'pypy_asm_stack_bottom();' - name_to_gcpolicy = { 'boehm': BoehmGcPolicy, diff --git a/pypy/translator/c/gcc/test/test_asmgcroot.py b/pypy/translator/c/gcc/test/test_asmgcroot.py --- a/pypy/translator/c/gcc/test/test_asmgcroot.py +++ b/pypy/translator/c/gcc/test/test_asmgcroot.py @@ -6,7 +6,7 @@ from pypy.annotation.listdef import s_list_of_strings from pypy import conftest from pypy.translator.tool.cbuild import ExternalCompilationInfo -from pypy.rpython.lltypesystem import lltype, rffi +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.entrypoint import entrypoint, secondary_entrypoints from pypy.rpython.lltypesystem.lloperation import llop @@ -180,9 +180,10 @@ @entrypoint("x42", [lltype.Signed, lltype.Signed], c_name='callback') def mycallback(a, b): - llop.gc_stack_bottom(lltype.Void) rffi.stackcounter.stacks_counter += 1 + saved = llop.gc_stack_bottom(llmemory.Address) gc.collect() + llop.gc_stack_bottom_stop(lltype.Void, saved) rffi.stackcounter.stacks_counter -= 1 return a + b diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h --- a/pypy/translator/c/src/main.h +++ b/pypy/translator/c/src/main.h @@ -34,12 +34,9 @@ char *errmsg; int i, exitcode; RPyListOfString *list; -#ifdef PYPY_GET_SPECIAL_REG - void *pypy_reg_oldvalue = PYPY_GET_SPECIAL_REG(); - PYPY_SET_SPECIAL_REG((void*)-1); -#endif + void *saved; - pypy_asm_stack_bottom(); + OP_GC_STACK_BOTTOM(saved); instrument_setup(); if (sizeof(void*) != SIZEOF_LONG) { @@ -74,10 +71,7 @@ pypy_debug_catch_fatal_exception(); } -#ifdef PYPY_GET_SPECIAL_REG - PYPY_SET_SPECIAL_REG(pypy_reg_oldvalue); -#endif - + OP_GC_STACK_BOTTOM_STOP(saved, /*nothing*/); return exitcode; memory_out: diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h --- a/pypy/translator/c/src/mem.h +++ b/pypy/translator/c/src/mem.h @@ -84,6 +84,17 @@ #endif +#ifdef PYPY_GET_SPECIAL_REG /* pypy/rlib/register.py */ +# define OP_GC_STACK_BOTTOM(r) pypy_asm_stack_bottom(); \ + r = PYPY_GET_SPECIAL_REG(); \ + PYPY_SET_SPECIAL_REG((void*)-1) +# define OP_GC_STACK_BOTTOM_STOP(v,r) PYPY_SET_SPECIAL_REG(v) +#else +# define OP_GC_STACK_BOTTOM(r) pypy_asm_stack_bottom() +# define OP_GC_STACK_BOTTOM_STOP(v,r) /* nothing */ +#endif + + /* used by pypy.rlib.rstack, but also by asmgcc */ #define OP_STACK_CURRENT(r) r = (long)&r From noreply at buildbot.pypy.org Sat Jul 9 16:24:52 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 9 Jul 2011 16:24:52 +0200 (CEST) Subject: [pypy-commit] pypy r15-for-exception: Fix trackgcroot for ignoring r15 in case it is used by rlib/register.py. Message-ID: <20110709142452.BE64D820AE@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: r15-for-exception Changeset: r45437:523c9a2ca35f Date: 2011-07-09 16:33 +0200 http://bitbucket.org/pypy/pypy/changeset/523c9a2ca35f/ Log: Fix trackgcroot for ignoring r15 in case it is used by rlib/register.py. diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -103,7 +103,15 @@ else: regindex = self.CALLEE_SAVE_REGISTERS.index(tag) shape[1 + regindex] = loc - if LOC_NOWHERE in shape and not self.is_stack_bottom: + # + if self.special_register is None: + shape_wo_specialreg = shape + else: + tag = self.special_register + regindex = self.CALLEE_SAVE_REGISTERS.index(tag) + shape_wo_specialreg = shape[:] + del shape_wo_specialreg[1 + regindex] + if LOC_NOWHERE in shape_wo_specialreg and not self.is_stack_bottom: reg = self.CALLEE_SAVE_REGISTERS[shape.index(LOC_NOWHERE) - 1] raise AssertionError("cannot track where register %s is saved" % (reg,)) @@ -1346,6 +1354,7 @@ def process_function(self, lines, filename): tracker = self.FunctionGcRootTracker( lines, filetag=getidentifier(filename)) + tracker.special_register = special_register if self.verbose == 1: sys.stderr.write('.') elif self.verbose > 1: @@ -1548,10 +1557,12 @@ class GcRootTracker(object): - def __init__(self, verbose=0, shuffle=False, format='elf'): + def __init__(self, verbose=0, shuffle=False, format='elf', + special_register=None): self.verbose = verbose self.shuffle = shuffle # to debug the sorting logic in asmgcroot.py self.format = format + self.special_register = special_register self.gcmaptable = [] def dump_raw_table(self, output): @@ -1892,6 +1903,7 @@ verbose = 0 shuffle = False output_raw_table = False + special_register = None if sys.platform == 'darwin': if sys.maxint > 2147483647: format = 'darwin64' @@ -1917,12 +1929,16 @@ elif sys.argv[1].startswith('-f'): format = sys.argv[1][2:] del sys.argv[1] + elif sys.argv[1].startswith('-%'): + special_register = sys.argv[1][1:] + del sys.argv[1] elif sys.argv[1].startswith('-'): print >> sys.stderr, "unrecognized option:", sys.argv[1] sys.exit(1) else: break - tracker = GcRootTracker(verbose=verbose, shuffle=shuffle, format=format) + tracker = GcRootTracker(verbose=verbose, shuffle=shuffle, format=format, + special_register=special_register) for fn in sys.argv[1:]: f = open(fn, 'r') firstline = f.readline() diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -558,6 +558,12 @@ for rule in rules: mk.rule(*rule) + from pypy.rlib.register import register_number + if register_number is None: + extra_trackgcroot_arg = '' + else: + extra_trackgcroot_arg = '-%%r%d' % register_number + if self.config.translation.gcrootfinder == 'asmgcc': trackgcfiles = [cfile[:-2] for cfile in mk.cfiles] if self.translator.platform.name == 'msvc': @@ -605,7 +611,7 @@ 'cmd /c $(MASM) /nologo /Cx /Cp /Zm /coff /Fo$@ /c $< $(INCLUDEDIRS)') mk.rule('.c.gcmap', '', ['$(CC) /nologo $(ASM_CFLAGS) /c /FAs /Fa$*.s $< $(INCLUDEDIRS)', - 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -t $*.s > $@'] + 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -t %s $*.s > $@' % extra_trackgcroot_arg] ) mk.rule('gcmaptable.c', '$(GCMAPFILES)', 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@') @@ -616,7 +622,7 @@ mk.rule('%.lbl.s %.gcmap', '%.s', [python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py ' - '-t $< > $*.gctmp', + '-t %s $< > $*.gctmp' % extra_trackgcroot_arg, 'mv $*.gctmp $*.gcmap']) mk.rule('gcmaptable.s', '$(GCMAPFILES)', [python + From noreply at buildbot.pypy.org Sun Jul 10 00:11:45 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 10 Jul 2011 00:11:45 +0200 (CEST) Subject: [pypy-commit] pypy default: Improve the encoding of "MOV reg, immed". Follows gcc's lead and Message-ID: <20110709221146.3AA8211B2DB3@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45441:b0d8f9d434b6 Date: 2011-07-09 23:56 +0200 http://bitbucket.org/pypy/pypy/changeset/b0d8f9d434b6/ Log: Improve the encoding of "MOV reg, immed". Follows gcc's lead and use three different encodings instead of two... diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -464,7 +464,7 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ @@ -632,16 +632,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -198,9 +198,19 @@ def test_mov_ri_64(): s = CodeBuilder64() s.MOV_ri(ecx, -2) + s.MOV_ri(r15, -3) + s.MOV_ri(ebx, -0x80000003) + s.MOV_ri(r13, -0x80000002) + s.MOV_ri(ecx, 42) s.MOV_ri(r12, 0x80000042) + s.MOV_ri(r12, 0x100000007) assert s.getvalue() == ('\x48\xC7\xC1\xFE\xFF\xFF\xFF' + - '\x49\xBC\x42\x00\x00\x80\x00\x00\x00\x00') + '\x49\xC7\xC7\xFD\xFF\xFF\xFF' + + '\x48\xBB\xFD\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\x49\xBD\xFE\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\xB9\x2A\x00\x00\x00' + + '\x41\xBC\x42\x00\x00\x80' + + '\x49\xBC\x07\x00\x00\x00\x01\x00\x00\x00') def test_mov_rm_64(): s = CodeBuilder64() diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py --- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py +++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py @@ -212,6 +212,17 @@ for mode, v in zip(argmodes, args): ops.append(assembler_operand[mode](v)) ops.reverse() + # + if (instrname.lower() == 'mov' and suffix == 'q' and + ops[0].startswith('$') and 0 <= int(ops[0][1:]) <= 4294967295 + and ops[1].startswith('%r')): + # movq $xxx, %rax => movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) From noreply at buildbot.pypy.org Sun Jul 10 00:11:49 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 10 Jul 2011 00:11:49 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110709221149.5767E11B2DB3@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45442:fef0408e477f Date: 2011-07-10 00:04 +0200 http://bitbucket.org/pypy/pypy/changeset/fef0408e477f/ Log: merge heads diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -48,7 +48,8 @@ return self.from_param(as_parameter) def get_ffi_param(self, value): - return self.from_param(value)._to_ffi_param() + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() def get_ffi_argtype(self): if self._ffiargtype: diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -328,12 +328,14 @@ "native COM method call without 'this' parameter" ) thisarg = cast(args[0], POINTER(POINTER(c_void_p))) - newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) newargs.insert(0, args[0].value) argtypes.insert(0, c_void_p) else: thisarg = None - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -437,16 +439,15 @@ @classmethod def _conv_param(cls, argtype, arg): if isinstance(argtype, _CDataMeta): - #arg = argtype.from_param(arg) - arg = argtype.get_ffi_param(arg) - return arg, argtype + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - return arg._to_ffi_param(), type(arg) + return arg, arg._to_ffi_param(), type(arg) # # non-usual case: we do the import here to save a lot of code in the # jit trace of the normal case @@ -463,11 +464,12 @@ else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj._to_ffi_param(), type(cobj) + return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] + keepalives = [] newargtypes = [] total = len(args) paramflags = self._paramflags @@ -495,7 +497,8 @@ val = defval if val is marker: val = 0 - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): @@ -511,28 +514,32 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - newarg, newargtype = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) + keepalive = None newarg = ctypes.byref(val) newargtype = type(newarg) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - newarg, newargtype = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) inargs_idx += 1 @@ -541,12 +548,13 @@ extra = args[len(newargs):] for i, arg in enumerate(extra): try: - newarg, newargtype = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) - return newargs, newargtypes, outargs + return keepalives, newargs, newargtypes, outargs def _wrap_result(self, restype, result): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -411,6 +411,23 @@ result = f("abcd", ord("b")) assert result == "bcd" + def test_keepalive_buffers(self, monkeypatch): + import gc + f = dll.my_strchr + f.argtypes = [c_char_p] + f.restype = c_char_p + # + orig__call_funcptr = f._call_funcptr + def _call_funcptr(funcptr, *newargs): + gc.collect() + gc.collect() + gc.collect() + return orig__call_funcptr(funcptr, *newargs) + monkeypatch.setattr(f, '_call_funcptr', _call_funcptr) + # + result = f("abcd", ord("b")) + assert result == "bcd" + def test_caching_bug_1(self): # the same test as test_call_some_args, with two extra lines # in the middle that trigger caching in f._ptr, which then diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py @@ -12,7 +12,7 @@ from _ctypes.function import CFuncPtr def guess(value): - cobj, ctype = CFuncPtr._conv_param(None, value) + _, cobj, ctype = CFuncPtr._conv_param(None, value) return ctype ## cobj = CFuncPtr._conv_param(None, value) ## return type(cobj) From noreply at buildbot.pypy.org Sun Jul 10 01:43:54 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 10 Jul 2011 01:43:54 +0200 (CEST) Subject: [pypy-commit] pypy default: Make Pickler a new-style class. Message-ID: <20110709234354.AF74C11B2DB3@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45443:1b3500a287b9 Date: 2011-07-09 16:37 -0700 http://bitbucket.org/pypy/pypy/changeset/1b3500a287b9/ Log: Make Pickler a new-style class. diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. From noreply at buildbot.pypy.org Sun Jul 10 01:43:55 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 10 Jul 2011 01:43:55 +0200 (CEST) Subject: [pypy-commit] pypy default: When inserting an item in the memodict (so it starts counting at 1) insert the id of None, rather than None itself, this way it stays an int-specialized dict. Message-ID: <20110709234355.DDA3F11B2DB4@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45444:4127e61bd4bc Date: 2011-07-09 16:38 -0700 http://bitbucket.org/pypy/pypy/changeset/4127e61bd4bc/ Log: When inserting an item in the memodict (so it starts counting at 1) insert the id of None, rather than None itself, this way it stays an int-specialized dict. diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -27,9 +27,9 @@ PythonPickler.__init__(self, self.__f, args[0], **kw) else: PythonPickler.__init__(self, *args, **kw) - + def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): From noreply at buildbot.pypy.org Sun Jul 10 03:42:48 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 10 Jul 2011 03:42:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove more operations (particularly strlen and int_add) when concatinating strings. Message-ID: <20110710014248.C569711B2DB3@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45445:fdd9f6e01b33 Date: 2011-07-09 18:42 -0700 http://bitbucket.org/pypy/pypy/changeset/fdd9f6e01b33/ Log: Remove more operations (particularly strlen and int_add) when concatinating strings. Basically this more consistantly passes around the optimizer, rather than optimization, and uses optimize_default rather than emit_operation for optimizations that we want to be removed if they duplicate existing pure ops. diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -3916,11 +3916,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3941,9 +3938,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3962,10 +3957,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -3987,14 +3981,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -4010,10 +3999,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4131,9 +4118,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -4178,11 +4163,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4374,11 +4356,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5082,11 +5082,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5107,9 +5104,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5128,10 +5123,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5153,14 +5147,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -5176,10 +5165,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5303,9 +5290,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -5411,11 +5396,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5609,11 +5591,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -61,7 +61,7 @@ self.ensure_nonnull() box = self.force_box() lengthbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) + optimization.optimize_default(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -72,13 +72,13 @@ else: return None - def string_copy_parts(self, optimization, targetbox, offsetbox, mode): + def string_copy_parts(self, optimizer, targetbox, offsetbox, mode): # Copies the pointer-to-string 'self' into the target string # given by 'targetbox', at the specified offset. Returns the offset # at the end of the copy. - lengthbox = self.getstrlen(optimization, mode) + lengthbox = self.getstrlen(optimizer, mode) srcbox = self.force_box() - return copy_str_content(optimization, srcbox, targetbox, + return copy_str_content(optimizer, srcbox, targetbox, CONST_0, offsetbox, lengthbox, mode) @@ -335,7 +335,7 @@ if optimizer is None: return None resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_ADD, [box1, box2], resbox)) return resbox def _int_sub(optimizer, box1, box2): @@ -450,7 +450,7 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode) + lengthbox = value.getstrlen(self.optimizer, mode) self.make_equal_to(op.result, self.getvalue(lengthbox)) def optimize_CALL(self, op): From noreply at buildbot.pypy.org Sun Jul 10 04:52:04 2011 From: noreply at buildbot.pypy.org (gutworth) Date: Sun, 10 Jul 2011 04:52:04 +0200 (CEST) Subject: [pypy-commit] jitviewer default: technically argument errors should return 2 Message-ID: <20110710025204.29A3A11B2DB3@wyvern.cs.uni-duesseldorf.de> Author: Benjamin Peterson Branch: Changeset: r140:0a3e55eefb3f Date: 2011-07-09 21:56 -0500 http://bitbucket.org/pypy/jitviewer/changeset/0a3e55eefb3f/ Log: technically argument errors should return 2 diff --git a/bin/qwebview.py b/bin/qwebview.py --- a/bin/qwebview.py +++ b/bin/qwebview.py @@ -14,7 +14,7 @@ title = sys.argv[2] else: print >> sys.stderr, "Usage: qwebview.py URL [title]" - return 1 + return 2 app = QApplication(sys.argv) web = QWebView() From noreply at buildbot.pypy.org Sun Jul 10 06:10:08 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 10 Jul 2011 06:10:08 +0200 (CEST) Subject: [pypy-commit] pypy default: Make Module.w_dict as quasi-immut. Message-ID: <20110710041008.1C9CD11B2DB3@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45446:25a92fba83d0 Date: 2011-07-09 21:09 -0700 http://bitbucket.org/pypy/pypy/changeset/25a92fba83d0/ Log: Make Module.w_dict as quasi-immut. diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -0,0 +1,30 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGlobals(BaseTestPyPyC): + def test_load_builtin(self): + def main(n): + import pypyjit + + i = 0 + while i < n: + l = len # ID: loadglobal + i += pypyjit.residual_call(l, "a") + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("loadglobal", """ + p10 = getfield_gc(p0, descr=) + guard_value(p10, ConstPtr(ptr11), descr=...) + p12 = getfield_gc(p10, descr=) + guard_value(p12, ConstPtr(ptr13), descr=...) + p15 = getfield_gc(ConstPtr(ptr14), descr=) + guard_isnull(p15, descr=...) + guard_not_invalidated(descr=...) + p19 = getfield_gc(ConstPtr(p17), descr=) + guard_value(p19, ConstPtr(ptr20), descr=...) + p22 = getfield_gc(ConstPtr(ptr21), descr=) + guard_nonnull(p22, descr=...) + """) \ No newline at end of file From noreply at buildbot.pypy.org Sun Jul 10 06:13:37 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 10 Jul 2011 06:13:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Replace this O(n^2) loop with a simple O(n) library function. Message-ID: <20110710041337.70AF411B2DB3@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45447:40a63caa7c26 Date: 2011-07-09 21:13 -0700 http://bitbucket.org/pypy/pypy/changeset/40a63caa7c26/ Log: Replace this O(n^2) loop with a simple O(n) library function. diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -572,10 +572,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): From noreply at buildbot.pypy.org Sun Jul 10 09:43:52 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 10 Jul 2011 09:43:52 +0200 (CEST) Subject: [pypy-commit] pypy default: Mark a few fields as immutable on dict multi iterator objects. Message-ID: <20110710074352.67A95820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45448:8457c1f2cc6c Date: 2011-07-10 00:43 -0700 http://bitbucket.org/pypy/pypy/changeset/8457c1f2cc6c/ Log: Mark a few fields as immutable on dict multi iterator objects. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -736,6 +736,8 @@ class W_DictMultiIterObject(W_Object): from pypy.objspace.std.dicttype import dictiter_typedef as typedef + _immutable_fields_ = ["iteratorimplementation", "itertype"] + def __init__(w_self, space, iteratorimplementation, itertype): w_self.space = space w_self.iteratorimplementation = iteratorimplementation From notifications-noreply at bitbucket.org Sun Jul 10 12:08:17 2011 From: notifications-noreply at bitbucket.org (Bitbucket) Date: Sun, 10 Jul 2011 10:08:17 -0000 Subject: [pypy-commit] Notification: Your access to pypy has been revoked. Message-ID: <20110710100817.8980.74085@bitbucket01.managed.contegix.com> You have received a notification from Tohru Ike. You no longer have access to the source of pypy. -- Change your notification settings at https://bitbucket.org/account/notifications/ From noreply at buildbot.pypy.org Sun Jul 10 21:11:09 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 10 Jul 2011 21:11:09 +0200 (CEST) Subject: [pypy-commit] jitviewer default: Added in what you need for asm integration. Message-ID: <20110710191109.D8C48820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r141:67de959672a3 Date: 2011-07-10 12:10 -0700 http://bitbucket.org/pypy/jitviewer/changeset/67de959672a3/ Log: Added in what you need for asm integration. diff --git a/README b/README --- a/README +++ b/README @@ -20,5 +20,5 @@ jitviewer.py log where log is a logfile generated by -PYPYLOG=jit-log-opt,jit-backend-counts:log pypy-c . +PYPYLOG=jit-log-opt,jit-backend-counts,jit-backend-dump:log pypy-c . An example log file comes with a checkout. From noreply at buildbot.pypy.org Sun Jul 10 21:28:35 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 10 Jul 2011 21:28:35 +0200 (CEST) Subject: [pypy-commit] pypy default: More consistantly pass around optimizer vs. optimization in the virtual string optimization. Message-ID: <20110710192835.6747D820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45449:b33d4747218e Date: 2011-07-10 12:28 -0700 http://bitbucket.org/pypy/pypy/changeset/b33d4747218e/ Log: More consistantly pass around optimizer vs. optimization in the virtual string optimization. diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -345,10 +345,10 @@ if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimization, strbox, indexbox, mode): +def _strgetitem(optimizer, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimizer.optimize_default(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,7 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) + resbox = _strgetitem(self.optimizer, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): From noreply at buildbot.pypy.org Mon Jul 11 02:21:06 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 11 Jul 2011 02:21:06 +0200 (CEST) Subject: [pypy-commit] pypy default: A test that ought to have gone with the previous commit. Message-ID: <20110711002106.A0504820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45450:716cdaedd431 Date: 2011-07-10 17:20 -0700 http://bitbucket.org/pypy/pypy/changeset/716cdaedd431/ Log: A test that ought to have gone with the previous commit. diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4511,6 +4511,25 @@ """ self.optimize_loop(ops, expected) + def test_strslice_with_other_stuff(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass From noreply at buildbot.pypy.org Mon Jul 11 02:49:06 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Mon, 11 Jul 2011 02:49:06 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: Merge with default Message-ID: <20110711004906.EE1A0820D2@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45451:a44cc5113548 Date: 2011-07-09 18:04 +0200 http://bitbucket.org/pypy/pypy/changeset/a44cc5113548/ Log: Merge with default diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -984,11 +984,14 @@ pass class B(A): pass + @dont_look_inside + def extern(n): + if n: + return A() + else: + return B() def fn(n): - if n: - obj = A() - else: - obj = B() + obj = extern(n) return isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res @@ -1026,15 +1029,16 @@ pass class B(A): pass - a = A() - b = B() + @dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() def fn(n): - if n == -7: - obj = None - elif n: - obj = a - else: - obj = b + obj = extern(n) return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res == 4 From noreply at buildbot.pypy.org Mon Jul 11 02:49:08 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Mon, 11 Jul 2011 02:49:08 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: Annoying bug, presumably in ctypes on win64. Message-ID: <20110711004908.223E9820D2@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45452:25e6867dbd85 Date: 2011-07-11 02:47 +0200 http://bitbucket.org/pypy/pypy/changeset/25e6867dbd85/ Log: Annoying bug, presumably in ctypes on win64. test_ll2ctypes.py test_get_errno 32bit always ok 64bit py 2.6.7 ok 64bit py 2.7.2 breaks contimuing with 2.6.7 for now. (grumble) diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -717,8 +717,8 @@ assert not ALLOCATED # detects memory leaks in the test def test_get_errno(self): - if is_emulated_long: - py.test.skip("skipped temporarily, no idea yet what the error is!") + # win64: works with python 2.7.6, but not with 2.7.2 + # XXX check what is different with ctypes! eci = ExternalCompilationInfo(includes=['string.h']) if sys.platform.startswith('win'): underscore_on_windows = '_' From noreply at buildbot.pypy.org Mon Jul 11 02:59:16 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Mon, 11 Jul 2011 02:59:16 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: korr. of message. Message-ID: <20110711005916.68BF8820D2@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45453:8598a191765f Date: 2011-07-11 02:54 +0200 http://bitbucket.org/pypy/pypy/changeset/8598a191765f/ Log: korr. of message. win64 works with py 2.6.7 diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -717,7 +717,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_get_errno(self): - # win64: works with python 2.7.6, but not with 2.7.2 + # win64: works with python 2.6.7, but not with 2.7.2 # XXX check what is different with ctypes! eci = ExternalCompilationInfo(includes=['string.h']) if sys.platform.startswith('win'): From noreply at buildbot.pypy.org Mon Jul 11 02:59:17 2011 From: noreply at buildbot.pypy.org (ctismer) Date: Mon, 11 Jul 2011 02:59:17 +0200 (CEST) Subject: [pypy-commit] pypy win64 test: Merge with default Message-ID: <20110711005917.D770B820D2@wyvern.cs.uni-duesseldorf.de> Author: Christian Tismer Branch: win64 test Changeset: r45454:9726c7b218e5 Date: 2011-07-11 02:58 +0200 http://bitbucket.org/pypy/pypy/changeset/9726c7b218e5/ Log: Merge with default diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -48,7 +48,8 @@ return self.from_param(as_parameter) def get_ffi_param(self, value): - return self.from_param(value)._to_ffi_param() + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() def get_ffi_argtype(self): if self._ffiargtype: diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -328,12 +328,14 @@ "native COM method call without 'this' parameter" ) thisarg = cast(args[0], POINTER(POINTER(c_void_p))) - newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) newargs.insert(0, args[0].value) argtypes.insert(0, c_void_p) else: thisarg = None - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -437,16 +439,15 @@ @classmethod def _conv_param(cls, argtype, arg): if isinstance(argtype, _CDataMeta): - #arg = argtype.from_param(arg) - arg = argtype.get_ffi_param(arg) - return arg, argtype + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - return arg._to_ffi_param(), type(arg) + return arg, arg._to_ffi_param(), type(arg) # # non-usual case: we do the import here to save a lot of code in the # jit trace of the normal case @@ -463,11 +464,12 @@ else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj._to_ffi_param(), type(cobj) + return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] + keepalives = [] newargtypes = [] total = len(args) paramflags = self._paramflags @@ -495,7 +497,8 @@ val = defval if val is marker: val = 0 - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): @@ -511,28 +514,32 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - newarg, newargtype = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) + keepalive = None newarg = ctypes.byref(val) newargtype = type(newarg) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - newarg, newargtype = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) inargs_idx += 1 @@ -541,12 +548,13 @@ extra = args[len(newargs):] for i, arg in enumerate(extra): try: - newarg, newargtype = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) - return newargs, newargtypes, outargs + return keepalives, newargs, newargtypes, outargs def _wrap_result(self, restype, result): diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -27,9 +27,9 @@ PythonPickler.__init__(self, self.__f, args[0], **kw) else: PythonPickler.__init__(self, *args, **kw) - + def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -464,7 +464,7 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ @@ -632,16 +632,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -198,9 +198,19 @@ def test_mov_ri_64(): s = CodeBuilder64() s.MOV_ri(ecx, -2) + s.MOV_ri(r15, -3) + s.MOV_ri(ebx, -0x80000003) + s.MOV_ri(r13, -0x80000002) + s.MOV_ri(ecx, 42) s.MOV_ri(r12, 0x80000042) + s.MOV_ri(r12, 0x100000007) assert s.getvalue() == ('\x48\xC7\xC1\xFE\xFF\xFF\xFF' + - '\x49\xBC\x42\x00\x00\x80\x00\x00\x00\x00') + '\x49\xC7\xC7\xFD\xFF\xFF\xFF' + + '\x48\xBB\xFD\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\x49\xBD\xFE\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\xB9\x2A\x00\x00\x00' + + '\x41\xBC\x42\x00\x00\x80' + + '\x49\xBC\x07\x00\x00\x00\x01\x00\x00\x00') def test_mov_rm_64(): s = CodeBuilder64() diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py --- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py +++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py @@ -212,6 +212,17 @@ for mode, v in zip(argmodes, args): ops.append(assembler_operand[mode](v)) ops.reverse() + # + if (instrname.lower() == 'mov' and suffix == 'q' and + ops[0].startswith('$') and 0 <= int(ops[0][1:]) <= 4294967295 + and ops[1].startswith('%r')): + # movq $xxx, %rax => movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -3916,11 +3916,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3941,9 +3938,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3962,10 +3957,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -3987,14 +3981,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -4010,10 +3999,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4131,9 +4118,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -4178,11 +4163,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4374,11 +4356,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -4532,6 +4511,25 @@ """ self.optimize_loop(ops, expected) + def test_strslice_with_other_stuff(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5082,11 +5082,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5107,9 +5104,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5128,10 +5123,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5153,14 +5147,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -5176,10 +5165,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5303,9 +5290,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -5411,11 +5396,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5609,11 +5591,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -61,7 +61,7 @@ self.ensure_nonnull() box = self.force_box() lengthbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) + optimization.optimize_default(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -72,13 +72,13 @@ else: return None - def string_copy_parts(self, optimization, targetbox, offsetbox, mode): + def string_copy_parts(self, optimizer, targetbox, offsetbox, mode): # Copies the pointer-to-string 'self' into the target string # given by 'targetbox', at the specified offset. Returns the offset # at the end of the copy. - lengthbox = self.getstrlen(optimization, mode) + lengthbox = self.getstrlen(optimizer, mode) srcbox = self.force_box() - return copy_str_content(optimization, srcbox, targetbox, + return copy_str_content(optimizer, srcbox, targetbox, CONST_0, offsetbox, lengthbox, mode) @@ -335,7 +335,7 @@ if optimizer is None: return None resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_ADD, [box1, box2], resbox)) return resbox def _int_sub(optimizer, box1, box2): @@ -345,10 +345,10 @@ if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimization, strbox, indexbox, mode): +def _strgetitem(optimizer, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimizer.optimize_default(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,7 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) + resbox = _strgetitem(self.optimizer, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): @@ -450,7 +450,7 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode) + lengthbox = value.getstrlen(self.optimizer, mode) self.make_equal_to(op.result, self.getvalue(lengthbox)) def optimize_CALL(self, op): diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -572,10 +572,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -0,0 +1,30 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGlobals(BaseTestPyPyC): + def test_load_builtin(self): + def main(n): + import pypyjit + + i = 0 + while i < n: + l = len # ID: loadglobal + i += pypyjit.residual_call(l, "a") + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("loadglobal", """ + p10 = getfield_gc(p0, descr=) + guard_value(p10, ConstPtr(ptr11), descr=...) + p12 = getfield_gc(p10, descr=) + guard_value(p12, ConstPtr(ptr13), descr=...) + p15 = getfield_gc(ConstPtr(ptr14), descr=) + guard_isnull(p15, descr=...) + guard_not_invalidated(descr=...) + p19 = getfield_gc(ConstPtr(p17), descr=) + guard_value(p19, ConstPtr(ptr20), descr=...) + p22 = getfield_gc(ConstPtr(ptr21), descr=) + guard_nonnull(p22, descr=...) + """) \ No newline at end of file diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -411,6 +411,23 @@ result = f("abcd", ord("b")) assert result == "bcd" + def test_keepalive_buffers(self, monkeypatch): + import gc + f = dll.my_strchr + f.argtypes = [c_char_p] + f.restype = c_char_p + # + orig__call_funcptr = f._call_funcptr + def _call_funcptr(funcptr, *newargs): + gc.collect() + gc.collect() + gc.collect() + return orig__call_funcptr(funcptr, *newargs) + monkeypatch.setattr(f, '_call_funcptr', _call_funcptr) + # + result = f("abcd", ord("b")) + assert result == "bcd" + def test_caching_bug_1(self): # the same test as test_call_some_args, with two extra lines # in the middle that trigger caching in f._ptr, which then diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py @@ -12,7 +12,7 @@ from _ctypes.function import CFuncPtr def guess(value): - cobj, ctype = CFuncPtr._conv_param(None, value) + _, cobj, ctype = CFuncPtr._conv_param(None, value) return ctype ## cobj = CFuncPtr._conv_param(None, value) ## return type(cobj) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -736,6 +736,8 @@ class W_DictMultiIterObject(W_Object): from pypy.objspace.std.dicttype import dictiter_typedef as typedef + _immutable_fields_ = ["iteratorimplementation", "itertype"] + def __init__(w_self, space, iteratorimplementation, itertype): w_self.space = space w_self.iteratorimplementation = iteratorimplementation From noreply at buildbot.pypy.org Mon Jul 11 04:18:32 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 11 Jul 2011 04:18:32 +0200 (CEST) Subject: [pypy-commit] pypy default: There's no reason not to inline list.pop Message-ID: <20110711021832.24ABB820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45455:6438187093b6 Date: 2011-07-10 19:18 -0700 http://bitbucket.org/pypy/pypy/changeset/6438187093b6/ Log: There's no reason not to inline list.pop diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -667,7 +667,6 @@ res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res -ll_pop.oopspec = 'list.pop(l, index)' def ll_reverse(l): length = l.ll_length() From noreply at buildbot.pypy.org Mon Jul 11 11:54:00 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 11 Jul 2011 11:54:00 +0200 (CEST) Subject: [pypy-commit] jitviewer default: actually, this is the best way to invoke it Message-ID: <20110711095400.75AE5820D2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r142:a884b72c1ff9 Date: 2011-07-11 11:53 +0200 http://bitbucket.org/pypy/jitviewer/changeset/a884b72c1ff9/ Log: actually, this is the best way to invoke it diff --git a/README b/README --- a/README +++ b/README @@ -20,5 +20,5 @@ jitviewer.py log where log is a logfile generated by -PYPYLOG=jit-log-opt,jit-backend-counts,jit-backend-dump:log pypy-c . +PYPYLOG=jit-log-opt,jit-backend:log pypy-c . An example log file comes with a checkout. From noreply at buildbot.pypy.org Mon Jul 11 12:57:23 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 11 Jul 2011 12:57:23 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: dissabled "trace some more on bad loop"-feature for now Message-ID: <20110711105723.64A21820D2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45456:d9ef2acf9e1d Date: 2011-07-11 12:54 +0200 http://bitbucket.org/pypy/pypy/changeset/d9ef2acf9e1d/ Log: dissabled "trace some more on bad loop"-feature for now diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -15,7 +15,7 @@ from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE, \ - ABORT_FORCE_QUASIIMMUT + ABORT_FORCE_QUASIIMMUT, ABORT_BAD_LOOP from pypy.jit.metainterp.jitexc import JitException, get_llexception from pypy.rlib.objectmodel import specialize from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr @@ -1847,9 +1847,9 @@ else: self.compile(original_boxes, live_arg_boxes, start, resumedescr) # creation of the loop was cancelled! - self.staticdata.log('cancelled, tracing more...') - #self.staticdata.log('cancelled, stopping tracing') - #raise SwitchToBlackhole(ABORT_BAD_LOOP) + #self.staticdata.log('cancelled, tracing more...') + self.staticdata.log('cancelled, stopping tracing') + raise SwitchToBlackhole(ABORT_BAD_LOOP) # Otherwise, no loop found so far, so continue tracing. start = len(self.history.operations) diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -1,9 +1,47 @@ +def fannkuch(n): + count = range(1, n+1) + max_flips = 0 + m = n-1 + r = n + check = 0 + perm1 = range(n) + perm = range(n) + perm1_ins = perm1.insert + perm1_pop = perm1.pop + + while 1: + if check < 30: + #print "".join(str(i+1) for i in perm1) + check += 1 + + while r != 1: + count[r-1] = r + r -= 1 + + if perm1[0] != 0 and perm1[m] != m: + perm = perm1[:] + flips_count = 0 + k = perm[0] + while k: + perm[:k+1] = perm[k::-1] + flips_count += 1 + k = perm[0] + + if flips_count > max_flips: + max_flips = flips_count + + while r != n: + perm1_ins(r, perm1_pop(0)) + count[r] -= 1 + if count[r] > 0: + break + r += 1 + else: + return max_flips + try: - import numpy - a = numpy.array(range(10)) - b = a + a + a - print b[3] + fannkuch(9) except Exception, e: print "Exception: ", type(e) From noreply at buildbot.pypy.org Mon Jul 11 12:57:25 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 11 Jul 2011 12:57:25 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: hg merge default Message-ID: <20110711105725.91375820D2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45457:4170cb013928 Date: 2011-07-11 12:55 +0200 http://bitbucket.org/pypy/pypy/changeset/4170cb013928/ Log: hg merge default diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4400,7 +4400,10 @@ self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) + if hasattr(l.__add__, '__objclass__'): # CPython + self.assertTrue(l.__add__.__objclass__ is list) + else: # PyPy + self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -210,10 +210,20 @@ def m(self): "aaa" m.x = 3 + class B(A): + pass - bm = A().m + bm = B().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self + assert bm.im_class is B assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4140,7 +4140,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5659,7 +5659,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/vstring.py rename from pypy/jit/metainterp/optimizeopt/string.py rename to pypy/jit/metainterp/optimizeopt/vstring.py diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -237,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -186,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -207,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -240,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -1484,7 +1484,7 @@ raise OperationError( moduledict.w_NotSupportedError, space.wrap("Variable_TypeByValue(): unhandled data type %s" % - (space.type(w_value).getname(space, '?'),))) + (space.type(w_value).getname(space),))) def newByInputTypeHandler(space, cursor, w_inputTypeHandler, w_value, numElements): w_var = space.call(w_inputTypeHandler, diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -737,7 +737,7 @@ elif space.is_true(space.isinstance(w_encoding, space.w_str)): encoding = space.str_w(w_encoding) else: - type_name = space.type(w_encoding).getname(space, '?') + type_name = space.type(w_encoding).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 1 must be string or None,' @@ -757,7 +757,7 @@ space.wrap('namespace_separator must be at most one character,' ' omitted, or None')) else: - type_name = space.type(w_namespace_separator).getname(space, '?') + type_name = space.type(w_namespace_separator).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 2 must be string or None,' diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -176,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,21 +9,42 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + def test_interface_residual_call(): space = gettestobjspace(usemodules=['pypyjit']) diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -163,10 +163,7 @@ elif self.space.is_w(self.space.type(w_key), self.space.w_int): self.switch_to_int_strategy(w_dict) else: - strategy = self.space.fromcache(ObjectDictStrategy) - storage = strategy.get_empty_storage() - w_dict.strategy = strategy - w_dict.dstorage = storage + self.switch_to_object_strategy(w_dict) def switch_to_string_strategy(self, w_dict): strategy = self.space.fromcache(StringDictStrategy) @@ -180,6 +177,12 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def getitem(self, w_dict, w_key): #return w_value or None # in case the key is unhashable, try to hash it @@ -817,7 +820,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -670,6 +670,8 @@ def popitem(self, w_dict): curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError key = curr.selector[0] w_value = self.getitem_str(w_dict, key) w_key = self.space.wrap(key) diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -138,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -177,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -196,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -236,16 +236,16 @@ def test_popitem3(self): #object - d = {"a": 1, 2:2, "c":3} + d = {"a": 1, 2: 2, "c": 3} l = [] while True: try: l.append(d.popitem()) except KeyError: break; - assert ("a",1) in l - assert (2,2) in l - assert ("c",3) in l + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l #string d = {"a": 1, "b":2, "c":3} @@ -255,12 +255,12 @@ l.append(d.popitem()) except KeyError: break; - assert ("a",1) in l - assert ("b",2) in l - assert ("c",3) in l + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -293,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -323,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -342,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -392,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -479,6 +479,7 @@ it2 = a.__dict__.popitem() assert it2 == ("x", 5) assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) @@ -622,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -294,12 +294,13 @@ 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -354,22 +355,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -592,15 +604,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -609,7 +623,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -83,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version From noreply at buildbot.pypy.org Mon Jul 11 15:36:28 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 15:36:28 +0200 (CEST) Subject: [pypy-commit] jitviewer default: Display in bold the residual calls too. Message-ID: <20110711133628.11871820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r143:24bc81b7de27 Date: 2011-06-26 14:02 +0200 http://bitbucket.org/pypy/jitviewer/changeset/24bc81b7de27/ Log: Display in bold the residual calls too. diff --git a/_jitviewer/parser.py b/_jitviewer/parser.py --- a/_jitviewer/parser.py +++ b/_jitviewer/parser.py @@ -40,6 +40,8 @@ s = getattr(self, 'repr_' + self.name, self.repr)() if self.is_guard(): s = 'guard(' + s + ')' + elif 'call' in self.name: + s = '' + s + '' return Html(s) def _getvar(self, v): diff --git a/static/style.css b/static/style.css --- a/static/style.css +++ b/static/style.css @@ -163,8 +163,13 @@ .guard { color: red; } +.call { + font-size: 12px; + font-weight: bold; +} span.dmp, span.guard, +span.call, span.single-operation, .inlined_call { display: inline-block; From noreply at buildbot.pypy.org Mon Jul 11 15:36:29 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 15:36:29 +0200 (CEST) Subject: [pypy-commit] jitviewer default: hg merge Message-ID: <20110711133629.672F8820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r144:d33260e435e0 Date: 2011-07-11 15:35 +0200 http://bitbucket.org/pypy/jitviewer/changeset/d33260e435e0/ Log: hg merge diff --git a/README b/README --- a/README +++ b/README @@ -20,5 +20,5 @@ jitviewer.py log where log is a logfile generated by -PYPYLOG=jit-log-opt,jit-backend-counts:log pypy-c . +PYPYLOG=jit-log-opt,jit-backend:log pypy-c . An example log file comes with a checkout. diff --git a/_jitviewer/parser.py b/_jitviewer/parser.py --- a/_jitviewer/parser.py +++ b/_jitviewer/parser.py @@ -120,6 +120,8 @@ def html_repr(self): if self.filename is not None: code = self.getcode() + if code is None: + return self.bytecode_name opcode = self.code.map[self.bytecode_no] return '%s %s' % (self.bytecode_name, opcode.argstr) else: diff --git a/static/DroidSansMono.ttf b/_jitviewer/static/DroidSansMono.ttf rename from static/DroidSansMono.ttf rename to _jitviewer/static/DroidSansMono.ttf diff --git a/static/jquery-1.2.6.min.js b/_jitviewer/static/jquery-1.2.6.min.js rename from static/jquery-1.2.6.min.js rename to _jitviewer/static/jquery-1.2.6.min.js diff --git a/static/jquery.min.js b/_jitviewer/static/jquery.min.js rename from static/jquery.min.js rename to _jitviewer/static/jquery.min.js diff --git a/static/jquery.scrollTo-1.4.1.js b/_jitviewer/static/jquery.scrollTo-1.4.1.js rename from static/jquery.scrollTo-1.4.1.js rename to _jitviewer/static/jquery.scrollTo-1.4.1.js diff --git a/static/jquery.scrollTo-1.4.2-min.js b/_jitviewer/static/jquery.scrollTo-1.4.2-min.js rename from static/jquery.scrollTo-1.4.2-min.js rename to _jitviewer/static/jquery.scrollTo-1.4.2-min.js diff --git a/static/loop.js b/_jitviewer/static/loop.js rename from static/loop.js rename to _jitviewer/static/loop.js diff --git a/static/pygments.css b/_jitviewer/static/pygments.css rename from static/pygments.css rename to _jitviewer/static/pygments.css diff --git a/static/qt_workaround.css b/_jitviewer/static/qt_workaround.css rename from static/qt_workaround.css rename to _jitviewer/static/qt_workaround.css diff --git a/static/script.js b/_jitviewer/static/script.js rename from static/script.js rename to _jitviewer/static/script.js --- a/static/script.js +++ b/_jitviewer/static/script.js @@ -18,6 +18,9 @@ var elem = arg.callstack[index]; $('#callstack').append('"); } + $(".asm").hide(); + $('#asmtoggler').html("Show assembler"); + $('#optoggler').html("Hide operations"); }); } @@ -57,9 +60,17 @@ }); } -function toggle() +function toggle(name, clsname, v) { - $('.operations').toggle(); + var e = $("#" + name); + var e2 = $("." + clsname); + if (e.html().search("Show") != -1) { + e.html("Hide " + v); + e2.show(); + } else { + e.html("Show " + v); + e2.hide(); + } } function highlight_var(elem) diff --git a/static/style.css b/_jitviewer/static/style.css rename from static/style.css rename to _jitviewer/static/style.css --- a/static/style.css +++ b/_jitviewer/static/style.css @@ -141,6 +141,12 @@ margin-left: 3em; } +.asm { + white-space: pre; + margin-left: 4em; + color: #666; +} + .inlined_call { font-size: 12px; font-weight: bold; diff --git a/templates/index.html b/_jitviewer/templates/index.html rename from templates/index.html rename to _jitviewer/templates/index.html --- a/templates/index.html +++ b/_jitviewer/templates/index.html @@ -17,7 +17,8 @@
Menu
- Toggle operations + Hide operations
+ Show assembler
diff --git a/templates/loop.html b/_jitviewer/templates/loop.html rename from templates/loop.html rename to _jitviewer/templates/loop.html --- a/templates/loop.html +++ b/_jitviewer/templates/loop.html @@ -15,6 +15,9 @@ {{op.html_repr()}} >>show bridge (taken {{op.percentage}}%)
{% else %} {{op.html_repr()}}
+ {% if op.asm %} +

{{op.asm}}

+ {% endif %} {% endif %} {% endfor %} {% else %} diff --git a/bin/jitviewer.py b/bin/jitviewer.py --- a/bin/jitviewer.py +++ b/bin/jitviewer.py @@ -1,4 +1,4 @@ -#!/usr/bin/env pypy-c +#!/usr/bin/env pypy """ A web-based browser of your log files. Run by jitviewer.py [port] [--server] @@ -37,28 +37,18 @@ raise ImportError('Could not import pypy module, make sure to ' 'add the pypy module to PYTHONPATH') -import cgi import flask import inspect import threading import time from pypy.tool.logparser import parse_log_file, extract_category from pypy.tool.jitlogparser.storage import LoopStorage -from pypy.tool.jitlogparser.parser import adjust_bridges +from pypy.tool.jitlogparser.parser import adjust_bridges, import_log # from _jitviewer.parser import ParserWithHtmlRepr, FunctionHtml, parse_log_counts from _jitviewer.display import CodeRepr, CodeReprNoFile import _jitviewer -from pygments import highlight -from pygments.lexers import PythonLexer -from pygments.formatters import HtmlFormatter - -from jinja2 import Environment, FileSystemLoader - -from werkzeug import Response -from flask.helpers import send_from_directory - CUTOFF = 30 class CannotFindFile(Exception): @@ -127,13 +117,14 @@ callstack.append((','.join(path_so_far), '%s in %s at %d' % (loop.name, loop.filename, loop.startlineno))) - startline, endline = loop.linerange - if loop.filename is not None: + if not loop.has_valid_code() or loop.filename is None: + startline = 0 + source = CodeReprNoFile(loop) + else: + startline, endline = loop.linerange code = self.storage.load_code(loop.filename)[(loop.startlineno, loop.name)] source = CodeRepr(inspect.getsource(code), code, loop) - else: - source = CodeReprNoFile(loop) d = {'html': flask.render_template('loop.html', source=source, current_loop=no, @@ -168,14 +159,13 @@ class CheckingLoopStorage(LoopStorage): def disassemble_code(self, fname, startlineno, name): result = super(CheckingLoopStorage, self).disassemble_code(fname, startlineno, name) - if result is None and fname is not None: - raise CannotFindFile(fname) + #if result is None and fname is not None: + # raise CannotFindFile(fname) return result def main(): - PATH = os.path.join(os.path.dirname( - os.path.dirname(_jitviewer.__file__))) + PATH = os.path.join(os.path.dirname((_jitviewer.__file__))) print PATH if not '__pypy__' in sys.builtin_module_names: print "Please run it using pypy-c" @@ -190,15 +180,13 @@ print __doc__ sys.exit(1) filename = sys.argv[1] - log = parse_log_file(filename) extra_path = os.path.dirname(filename) if len(sys.argv) != 3: port = 5000 else: port = int(sys.argv[2]) storage = CheckingLoopStorage(extra_path) - loops = [ParserWithHtmlRepr.parse_from_input(l) - for l in extract_category(log, "jit-log-opt-")] + log, loops = import_log(filename, ParserWithHtmlRepr) parse_log_counts(extract_category(log, 'jit-backend-count'), loops) storage.reconnect_loops(loops) app = OverrideFlask('__name__', root_path=PATH) @@ -223,7 +211,7 @@ # # start the webkit browser in the main thread (actually, it's a subprocess) time.sleep(0.5) # give the server some time to start - ret = start_browser(url, filename) + start_browser(url, filename) finally: # shutdown the HTPP server and wait until it completes app.servers[0].shutdown() @@ -238,7 +226,10 @@ except Exception, e: print 'Cannot start the builtin browser: %s' % e print "Please point your browser to: %s" % url - raw_input("Press enter to quit and kill the server") + try: + raw_input("Press enter to quit and kill the server") + except KeyboardInterrupt: + pass if __name__ == '__main__': main() diff --git a/bin/qwebview.py b/bin/qwebview.py --- a/bin/qwebview.py +++ b/bin/qwebview.py @@ -14,7 +14,7 @@ title = sys.argv[2] else: print >> sys.stderr, "Usage: qwebview.py URL [title]" - return 1 + return 2 app = QApplication(sys.argv) web = QWebView() diff --git a/log b/log --- a/log +++ b/log @@ -1,873 +1,747 @@ -[18cc55464e9ec] {jit-log-opt-loop -# Loop 0 : loop with 20 ops -[p0, p1, p2, p3, i4, p5, p6, i7] -debug_merge_point(' #9 LOAD_FAST', 0) -debug_merge_point(' #12 LOAD_CONST', 0) -debug_merge_point(' #15 COMPARE_OP', 0) -i9 = int_lt(i7, 1003) -guard_true(i9, descr=) [p1, p0, p2, p3, i7] -debug_merge_point(' #18 JUMP_IF_FALSE', 0) -debug_merge_point(' #21 POP_TOP', 0) -debug_merge_point(' #22 LOAD_FAST', 0) -debug_merge_point(' #25 LOAD_CONST', 0) -debug_merge_point(' #28 INPLACE_ADD', 0) -i11 = int_add(i7, 1) -debug_merge_point(' #29 STORE_FAST', 0) -debug_merge_point(' #32 JUMP_ABSOLUTE', 0) -i13 = getfield_raw(32192224, descr=) -i15 = int_sub(i13, 1) -setfield_raw(32192224, i15, descr=) -i17 = int_lt(i15, 0) -guard_false(i17, descr=) [p1, p0, p2, p3, i11, None] -debug_merge_point(' #9 LOAD_FAST', 0) -jump(p0, p1, p2, p3, 9, ConstPtr(ptr20), ConstPtr(ptr21), i11, descr=) -[18cc55471a9cc] jit-log-opt-loop} -[18cc554766c6c] {jit-backend-counts -[18cc5547687cc] jit-backend-counts} -[18cc554cbc55e] {jit-log-opt-loop -# Loop 1 : loop with 59 ops -[p0, p1, p2, p3, i4, p5, p6, p7] -debug_merge_point(' #9 LOAD_FAST', 0) -guard_nonnull_class(p7, ConstClass(W_IntObject), descr=) [p1, p0, p7, p2, p3, p5, p6] -debug_merge_point(' #12 LOAD_CONST', 0) -debug_merge_point(' #15 COMPARE_OP', 0) -i9 = getfield_gc_pure(p7, descr=) -i11 = int_lt(i9, 1003) -guard_true(i11, descr=) [p1, p0, p7, p2, p3] -debug_merge_point(' #18 JUMP_IF_FALSE', 0) -debug_merge_point(' #21 POP_TOP', 0) -debug_merge_point(' #22 LOAD_GLOBAL', 0) -p12 = getfield_gc(p0, descr=) -guard_value(p12, ConstPtr(ptr13), descr=) [p1, p0, p12, p2, p3, p7] -p14 = getfield_gc(p12, descr=) -guard_isnull(p14, descr=) [p1, p0, p14, p12, p2, p3, p7] -p16 = getfield_gc(ConstPtr(ptr15), descr=) -guard_nonnull_class(p16, ConstClass(Function), descr=) [p1, p0, p16, p2, p3, p7] -debug_merge_point(' #25 LOAD_FAST', 0) -debug_merge_point(' #28 CALL_FUNCTION', 0) -i18 = getfield_gc(p0, descr=) -guard_false(i18, descr=) [p1, p0, p16, p2, p3, p7] -p19 = getfield_gc(p16, descr=) -guard_value(p19, ConstPtr(ptr20), descr=) [p1, p0, p19, p16, p2, p3, p7] -p21 = getfield_gc(p16, descr=) -p22 = getfield_gc(p16, descr=) -p24 = call(ConstClass(getexecutioncontext), descr=) -guard_no_exception(, descr=) [p1, p0, p24, p2, p3, p16, p7, p21] -i25 = getfield_gc(p24, descr=) -i27 = getfield_gc(ConstPtr(ptr26), descr=) -i28 = int_gt(i25, i27) -guard_false(i28, descr=) [p1, p0, p24, p2, p3, p16, p7, p21] -i30 = int_add(i25, 1) -p31 = getfield_gc(p24, descr=) -i32 = force_token() -p33 = getfield_gc(p24, descr=) -setfield_gc(p24, i30, descr=) -guard_isnull(p33, descr=) [p1, p0, p24, p33, p2, p3, p16, p7, p31, i32, p21] -i34 = getfield_gc(p24, descr=) -i35 = int_is_zero(i34) -guard_true(i35, descr=) [p1, p0, p24, p2, p3, p16, p7, p31, i32, p21] -debug_merge_point(' #0 LOAD_FAST', 1) -debug_merge_point(' #3 LOAD_CONST', 1) -debug_merge_point(' #6 BINARY_ADD', 1) -i37 = int_add(i9, 1) -debug_merge_point(' #7 RETURN_VALUE', 1) -i38 = int_is_true(i34) -guard_false(i38, descr=) [p1, p0, p24, p2, p3, p16, p7, i37, p31, i32, p21] -debug_merge_point(' #31 STORE_FAST', 0) -debug_merge_point(' #34 JUMP_ABSOLUTE', 0) -i40 = getfield_raw(32192224, descr=) -i42 = int_sub(i40, 9) -setfield_raw(32192224, i42, descr=) -setfield_gc(p24, i25, descr=) -setfield_gc(p24, p31, descr=) -i44 = int_lt(i42, 0) -guard_false(i44, descr=) [p1, p0, p2, p3, i37, None, None, None] -debug_merge_point(' #9 LOAD_FAST', 0) -p47 = new_with_vtable(ConstClass(W_IntObject)) -setfield_gc(p47, i37, descr=) -jump(p0, p1, p2, p3, 9, ConstPtr(ptr49), ConstPtr(ptr50), p47, descr=) -[18cc554d0e81d] jit-log-opt-loop} -[18cc554eeb15e] {jit-log-opt-loop -# Loop 2 : loop with 42 ops -[p0, p1, p2, p3, i4, p5, p6, i7, i8] -debug_merge_point(' #15 LOAD_FAST', 0) -debug_merge_point(' #18 LOAD_CONST', 0) -debug_merge_point(' #21 COMPARE_OP', 0) -i10 = int_lt(i8, 10000) -guard_true(i10, descr=) [p1, p0, p2, p3, i7, i8] -debug_merge_point(' #24 JUMP_IF_FALSE', 0) -debug_merge_point(' #27 POP_TOP', 0) -debug_merge_point(' #28 LOAD_FAST', 0) -debug_merge_point(' #31 LOAD_CONST', 0) -debug_merge_point(' #34 BINARY_MODULO', 0) -i12 = int_add(i8, 9223372036854775807) -i14 = int_and(i12, 2) -i15 = int_mod(i8, 2) -i16 = int_xor(i8, 2) -i18 = int_le(i16, 0) -i19 = int_is_true(i15) -i20 = int_and(i18, i19) -i21 = int_mul(i20, 2) -i22 = int_add(i15, i21) -debug_merge_point(' #35 JUMP_IF_FALSE', 0) -i23 = int_is_true(i22) -guard_false(i23, descr=) [p1, p0, p2, p3, i22, i7, i8] -debug_merge_point(' #52 POP_TOP', 0) -debug_merge_point(' #53 LOAD_FAST', 0) -debug_merge_point(' #56 LOAD_CONST', 0) -debug_merge_point(' #59 INPLACE_ADD', 0) -i25 = int_add_ovf(i7, 2) -guard_no_overflow(, descr=) [p1, p0, i25, p2, p3, None, i7, i8] -debug_merge_point(' #60 STORE_FAST', 0) -debug_merge_point(' #63 LOAD_FAST', 0) -debug_merge_point(' #66 LOAD_CONST', 0) -debug_merge_point(' #69 INPLACE_ADD', 0) -i28 = int_add(i8, 1) -debug_merge_point(' #70 STORE_FAST', 0) -debug_merge_point(' #73 JUMP_ABSOLUTE', 0) -i30 = getfield_raw(32192224, descr=) -i32 = int_sub(i30, 2) -setfield_raw(32192224, i32, descr=) -i34 = int_lt(i32, 0) -guard_false(i34, descr=) [p1, p0, p2, p3, i28, i25, None, None, None] -debug_merge_point(' #15 LOAD_FAST', 0) -jump(p0, p1, p2, p3, 15, ConstPtr(ptr36), ConstPtr(ptr37), i25, i28, descr=) -[18cc554f0c5f0] jit-log-opt-loop} -[18cc55509878b] {jit-log-opt-loop -# Loop 3 : entry bridge with 49 ops -[p0, p1, p2, p3, p4, i5, i6, p7, p8, p9, p10] -debug_merge_point(' #15 LOAD_FAST', 0) -guard_value(i5, 0, descr=) [i5, p1, p0, p2, p3, p4, i6, p7, p8, p9, p10] -guard_nonnull_class(p10, ConstClass(W_IntObject), descr=) [p1, p0, p10, p2, p3, p4, p7, p8, p9] -debug_merge_point(' #18 LOAD_CONST', 0) -guard_value(p3, ConstPtr(ptr13), descr=) [p1, p0, p3, p2, p4, p10, p8, p9] -debug_merge_point(' #21 COMPARE_OP', 0) -i14 = getfield_gc_pure(p10, descr=) -i16 = int_lt(i14, 10000) -guard_true(i16, descr=) [p1, p0, p10, p2, p4, p9] -debug_merge_point(' #24 JUMP_IF_FALSE', 0) -debug_merge_point(' #27 POP_TOP', 0) -debug_merge_point(' #28 LOAD_FAST', 0) -debug_merge_point(' #31 LOAD_CONST', 0) -debug_merge_point(' #34 BINARY_MODULO', 0) -i18 = int_add(i14, 9223372036854775807) -i20 = int_and(i18, 2) -i21 = int_mod(i14, 2) -i22 = int_xor(i14, 2) -i24 = int_le(i22, 0) -i25 = int_is_true(i21) -i26 = int_and(i24, i25) -i27 = int_mul(i26, 2) -i28 = int_add(i21, i27) -debug_merge_point(' #35 JUMP_IF_FALSE', 0) -i29 = int_is_true(i28) -guard_true(i29, descr=) [p1, p0, p2, p4, p9, p10, i28] -debug_merge_point(' #38 POP_TOP', 0) -debug_merge_point(' #39 LOAD_FAST', 0) -guard_nonnull_class(p9, ConstClass(W_IntObject), descr=) [p1, p0, p9, p2, p4, p10, None] -debug_merge_point(' #42 LOAD_CONST', 0) -debug_merge_point(' #45 INPLACE_ADD', 0) -i32 = getfield_gc_pure(p9, descr=) -i34 = int_add_ovf(i32, 1) -guard_no_overflow(, descr=) [p1, p0, p9, i34, p2, p4, p10, None] -debug_merge_point(' #46 STORE_FAST', 0) -debug_merge_point(' #49 JUMP_FORWARD', 0) -debug_merge_point(' #63 LOAD_FAST', 0) -debug_merge_point(' #66 LOAD_CONST', 0) -debug_merge_point(' #69 INPLACE_ADD', 0) -i36 = int_add(i14, 1) -debug_merge_point(' #70 STORE_FAST', 0) -debug_merge_point(' #73 JUMP_ABSOLUTE', 0) -i38 = getfield_raw(32192224, descr=) -i40 = int_sub(i38, 2) -setfield_raw(32192224, i40, descr=) -i42 = int_lt(i40, 0) -guard_false(i42, descr=) [p1, p0, p2, p4, i36, i34, None] -debug_merge_point(' #15 LOAD_FAST', 0) -jump(p0, p1, p2, p4, 15, ConstPtr(ptr44), ConstPtr(ptr45), i34, i36, descr=) -[18cc5550c284f] jit-log-opt-loop} -[18cc55556f919] {jit-log-opt-bridge -# bridge out of Guard 18 with 22 ops +[1af179b69b26d] {jit-backend-counts +[1af179b6aaa20] jit-backend-counts} +[1af179bd270bb] {jit-log-opt-loop +# Loop 0 : loop with 35 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #15 LOAD_FAST') +debug_merge_point(0, ' #18 LOAD_CONST') +debug_merge_point(0, ' #21 COMPARE_OP') ++174: i7 = int_lt(i5, 10000) +guard_true(i7, descr=) [p1, p0, p2, p3, i4, i5] +debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #27 LOAD_FAST') +debug_merge_point(0, ' #30 LOAD_CONST') +debug_merge_point(0, ' #33 BINARY_MODULO') ++187: i9 = int_mod(i5, 2) ++209: i11 = int_rshift(i9, 63) ++216: i12 = int_and(2, i11) ++226: i13 = int_add(i9, i12) +debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') ++229: i14 = int_is_true(i13) +guard_false(i14, descr=) [p1, p0, p2, p3, i13, i4, i5] +debug_merge_point(0, ' #50 LOAD_FAST') +debug_merge_point(0, ' #53 LOAD_CONST') +debug_merge_point(0, ' #56 INPLACE_ADD') ++239: i16 = int_add_ovf(i4, 2) +guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i4, i5] +debug_merge_point(0, ' #57 STORE_FAST') +debug_merge_point(0, ' #60 LOAD_FAST') +debug_merge_point(0, ' #63 LOAD_CONST') +debug_merge_point(0, ' #66 INPLACE_ADD') ++252: i19 = int_add(i5, 1) +debug_merge_point(0, ' #67 STORE_FAST') +debug_merge_point(0, ' #70 JUMP_ABSOLUTE') ++263: i21 = getfield_raw(40681184, descr=) ++271: i23 = int_sub(i21, 1) ++275: setfield_raw(40681184, i23, descr=) ++283: i25 = int_lt(i23, 0) +guard_false(i25, descr=) [p1, p0, p2, p3, i16, i19, None, None, None] +debug_merge_point(0, ' #15 LOAD_FAST') ++293: jump(p0, p1, p2, p3, i16, i19, descr=) ++312: --end of the loop-- +[1af179bdc2aa7] jit-log-opt-loop} +[1af179be14e5b] {jit-log-opt-loop +# Loop 1 : entry bridge with 44 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11] +debug_merge_point(0, ' #15 LOAD_FAST') ++254: guard_value(i6, 0, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11] ++264: guard_nonnull_class(p11, ConstClass(W_IntObject), descr=) [p1, p0, p11, p2, p3, i4, p5, p8, p9, p10] ++282: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p11, p9, p10] +debug_merge_point(0, ' #18 LOAD_CONST') ++292: guard_value(p3, ConstPtr(ptr15), descr=) [p1, p0, p3, p2, p5, p11, p9, p10] +debug_merge_point(0, ' #21 COMPARE_OP') ++311: i16 = getfield_gc_pure(p11, descr=) ++315: i18 = int_lt(i16, 10000) +guard_true(i18, descr=) [p1, p0, p11, p2, p5, p10] +debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #27 LOAD_FAST') +debug_merge_point(0, ' #30 LOAD_CONST') +debug_merge_point(0, ' #33 BINARY_MODULO') ++328: i20 = int_eq(i16, -9223372036854775808) +guard_false(i20, descr=) [p1, p0, p11, i16, p2, p5, p10] ++347: i22 = int_mod(i16, 2) ++383: i24 = int_rshift(i22, 63) ++390: i25 = int_and(2, i24) ++400: i26 = int_add(i22, i25) +debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') ++403: i27 = int_is_true(i26) +guard_false(i27, descr=) [p1, p0, p2, p5, p10, p11, i26] +debug_merge_point(0, ' #50 LOAD_FAST') ++413: guard_nonnull_class(p10, ConstClass(W_IntObject), descr=) [p1, p0, p10, p2, p5, p11, None] +debug_merge_point(0, ' #53 LOAD_CONST') +debug_merge_point(0, ' #56 INPLACE_ADD') ++438: i30 = getfield_gc_pure(p10, descr=) ++442: i32 = int_add_ovf(i30, 2) +guard_no_overflow(, descr=) [p1, p0, p10, i32, p2, p5, p11, None] +debug_merge_point(0, ' #57 STORE_FAST') +debug_merge_point(0, ' #60 LOAD_FAST') +debug_merge_point(0, ' #63 LOAD_CONST') +debug_merge_point(0, ' #66 INPLACE_ADD') ++452: i34 = int_add(i16, 1) +debug_merge_point(0, ' #67 STORE_FAST') +debug_merge_point(0, ' #70 JUMP_ABSOLUTE') ++463: i36 = getfield_raw(40681184, descr=) ++471: i38 = int_sub(i36, 1) ++475: setfield_raw(40681184, i38, descr=) ++483: i40 = int_lt(i38, 0) +guard_false(i40, descr=) [p1, p0, p2, p5, i34, i32, None] +debug_merge_point(0, ' #15 LOAD_FAST') ++493: jump(p0, p1, p2, p5, i32, i34, descr=) ++551: --end of the loop-- +[1af179be57387] jit-log-opt-loop} +[1af179c15cdcd] {jit-log-opt-loop +# Loop 2 : loop with 34 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #18 LOAD_CONST') +debug_merge_point(0, ' #21 COMPARE_OP') ++174: i7 = int_lt(i5, 10000) +guard_true(i7, descr=) [p1, p0, p2, p3, i5, i4] +debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #27 LOAD_FAST') +debug_merge_point(0, ' #30 LOAD_CONST') +debug_merge_point(0, ' #33 BINARY_MODULO') ++187: i9 = int_mod(i5, 2) ++209: i11 = int_rshift(i9, 63) ++216: i12 = int_and(2, i11) ++226: i13 = int_add(i9, i12) +debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') ++229: i14 = int_is_true(i13) +guard_false(i14, descr=) [p1, p0, p2, p3, i13, i5, i4] +debug_merge_point(0, ' #50 LOAD_FAST') +debug_merge_point(0, ' #53 LOAD_CONST') +debug_merge_point(0, ' #56 INPLACE_ADD') ++239: i16 = int_add_ovf(i4, 2) +guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i5, i4] +debug_merge_point(0, ' #57 STORE_FAST') +debug_merge_point(0, ' #60 LOAD_FAST') +debug_merge_point(0, ' #63 LOAD_CONST') +debug_merge_point(0, ' #66 INPLACE_ADD') ++252: i19 = int_add(i5, 1) +debug_merge_point(0, ' #67 STORE_FAST') +debug_merge_point(0, ' #70 JUMP_ABSOLUTE') ++263: i21 = getfield_raw(40681184, descr=) ++271: i23 = int_sub(i21, 3) ++275: setfield_raw(40681184, i23, descr=) ++283: i25 = int_lt(i23, 0) +guard_false(i25, descr=) [p1, p0, p2, p3, i19, i16, None, None, None] +debug_merge_point(0, ' #15 LOAD_FAST') ++293: jump(p0, p1, p2, p3, i16, i19, descr=) ++312: --end of the loop-- +[1af179c182ffd] jit-log-opt-loop} +[1af179c1f947d] {jit-log-opt-bridge +# bridge out of Guard 4 with 25 ops [p0, p1, p2, p3, i4, i5, i6] -debug_merge_point(' #38 POP_TOP', 0) -debug_merge_point(' #39 LOAD_FAST', 0) -debug_merge_point(' #42 LOAD_CONST', 0) -debug_merge_point(' #45 INPLACE_ADD', 0) -i8 = int_add_ovf(i5, 1) -guard_no_overflow(, descr=) [p0, p1, i8, p2, p3, i6, i5] -debug_merge_point(' #46 STORE_FAST', 0) -debug_merge_point(' #49 JUMP_FORWARD', 0) -debug_merge_point(' #63 LOAD_FAST', 0) -debug_merge_point(' #66 LOAD_CONST', 0) -debug_merge_point(' #69 INPLACE_ADD', 0) -i10 = int_add_ovf(i6, 1) -guard_no_overflow(, descr=) [p0, p1, i10, p2, p3, i8, i6, None] -debug_merge_point(' #70 STORE_FAST', 0) -debug_merge_point(' #73 JUMP_ABSOLUTE', 0) -i13 = getfield_raw(32192224, descr=) -i15 = int_sub(i13, 1) -setfield_raw(32192224, i15, descr=) -i17 = int_lt(i15, 0) -guard_false(i17, descr=) [p0, p1, p2, p3, i10, i8, None, None] -debug_merge_point(' #15 LOAD_FAST', 0) -jump(p1, p0, p2, p3, 15, ConstPtr(ptr19), ConstPtr(ptr20), i8, i10, descr=) -[18cc555580391] jit-log-opt-bridge} -[18cc55582206a] {jit-log-opt-loop -# Loop 4 : loop with 53 ops -[p0, p1, p2, p3, i4, p5, p6, p7, p8, p9, p10, p11, p12, i13, p14, p15] -debug_merge_point(' #17 FOR_ITER', 0) -guard_class(p6, 17399936, descr=) [p1, p0, p6, p2, p3, p5, p7, p8, p9, p10, p11, p12, p14, p15, i13] -p17 = getfield_gc(p6, descr=) -guard_nonnull(p17, descr=) [p1, p0, p6, p17, p2, p3, p5, p7, p8, p9, p10, p11, p12, p14, p15, i13] -i18 = getfield_gc(p6, descr=) -p19 = getfield_gc(p17, descr=) -guard_isnull(p19, descr=) [p1, p0, p6, i18, p17, p19, p2, p3, p5, p7, p8, p9, p10, p11, p12, p14, p15, i13] -i20 = getfield_gc(p17, descr=) -i21 = int_ge(i18, i20) -guard_false(i21, descr=) [p1, p0, p6, i18, p17, p2, p3, p5, p7, p8, p9, p10, p11, p12, p14, p15, i13] -i22 = getfield_gc(p17, descr=) -i23 = getfield_gc(p17, descr=) -i24 = int_mul(i18, i23) -i25 = int_add(i22, i24) -i27 = int_add(i18, 1) -debug_merge_point(' #20 STORE_FAST', 0) -debug_merge_point(' #23 LOAD_FAST', 0) -setfield_gc(p6, i27, descr=) -guard_nonnull_class(p12, ConstClass(W_ListObject), descr=) [p1, p0, p12, p2, p3, p5, p6, p8, p9, p10, p11, p14, p15, i25, None] -debug_merge_point(' #26 LOAD_GLOBAL', 0) -p30 = getfield_gc(p0, descr=) -guard_value(p30, ConstPtr(ptr31), descr=) [p1, p0, p30, p2, p3, p5, p6, p12, p8, p9, p10, p11, p14, p15, i25, None] -p32 = getfield_gc(p30, descr=) -guard_isnull(p32, descr=) [p1, p0, p32, p30, p2, p3, p5, p6, p12, p8, p9, p10, p11, p14, p15, i25, None] -p34 = getfield_gc(ConstPtr(ptr33), descr=) -guard_isnull(p34, descr=) [p1, p0, p34, p2, p3, p5, p6, p12, p8, p9, p10, p11, p14, p15, i25, None] -p36 = getfield_gc(ConstPtr(ptr35), descr=) -guard_value(p36, ConstPtr(ptr37), descr=) [p1, p0, p36, p2, p3, p5, p6, p12, p8, p9, p10, p11, p14, p15, i25, None] -p38 = getfield_gc(p36, descr=) -guard_isnull(p38, descr=) [p1, p0, p38, p36, p2, p3, p5, p6, p12, p8, p9, p10, p11, p14, p15, i25, None] -p40 = getfield_gc(ConstPtr(ptr39), descr=) -guard_value(p40, ConstPtr(ptr41), descr=) [p1, p0, p40, p2, p3, p5, p6, p12, p8, p9, p10, p11, p14, p15, i25, None] -debug_merge_point(' #29 LOAD_FAST', 0) -debug_merge_point(' #32 CALL_FUNCTION', 0) -i42 = getfield_gc(p0, descr=) -guard_false(i42, descr=) [p1, p0, p40, p2, p3, p5, p6, p12, p10, p11, p14, p15, i25, None] -p44 = getfield_gc(ConstPtr(ptr43), descr=) -p45 = getfield_gc(ConstPtr(ptr43), descr=) -p47 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i25, descr=) -debug_merge_point(' #35 LIST_APPEND', 0) -p48 = getfield_gc(p12, descr=) -p50 = new_with_vtable(ConstClass(W_StringObject)) -setfield_gc(p50, p47, descr=) -call(ConstClass(ll_append__listPtr_objectPtr), p48, p50, descr=) -guard_no_exception(, descr=) [p1, p0, p2, p3, p5, p6, p10, p11, p12, p14, p15, i25] -debug_merge_point(' #36 JUMP_ABSOLUTE', 0) -i53 = getfield_raw(32192224, descr=) -i55 = int_sub(i53, 3) -setfield_raw(32192224, i55, descr=) -i57 = int_lt(i55, 0) -guard_false(i57, descr=) [p1, p0, p2, p3, p5, p6, p10, p11, p12, p14, p15, i25] -debug_merge_point(' #17 FOR_ITER', 0) -jump(p0, p1, p2, p3, 17, p5, p6, ConstPtr(ptr59), ConstPtr(ptr60), ConstPtr(ptr61), p10, p11, p12, i25, p14, p15, descr=) -[18cc5558655e4] jit-log-opt-loop} -[18cc55604d201] {jit-log-opt-loop +debug_merge_point(0, ' #37 LOAD_FAST') +debug_merge_point(0, ' #40 LOAD_CONST') +debug_merge_point(0, ' #43 INPLACE_ADD') ++37: i8 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i8, p2, p3, i5, i6] +debug_merge_point(0, ' #44 STORE_FAST') +debug_merge_point(0, ' #47 JUMP_FORWARD') +debug_merge_point(0, ' #60 LOAD_FAST') +debug_merge_point(0, ' #63 LOAD_CONST') +debug_merge_point(0, ' #66 INPLACE_ADD') ++50: i10 = int_add_ovf(i6, 1) +guard_no_overflow(, descr=) [p0, p1, i10, p2, p3, i8, None, i6] +debug_merge_point(0, ' #67 STORE_FAST') +debug_merge_point(0, ' #70 JUMP_ABSOLUTE') ++67: i13 = getfield_raw(40681184, descr=) ++75: i15 = int_sub(i13, 1) ++79: setfield_raw(40681184, i15, descr=) ++87: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p0, p1, p2, p3, i10, i8, None, None] +debug_merge_point(0, ' #15 LOAD_FAST') ++97: p19 = new_with_vtable(ConstClass(W_IntObject)) ++167: setfield_gc(p19, i8, descr=) ++171: p21 = new_with_vtable(ConstClass(W_IntObject)) ++241: setfield_gc(p21, i10, descr=) ++252: jump(p1, p0, p2, ConstPtr(ptr22), 0, p3, 0, 15, ConstPtr(ptr26), ConstPtr(ptr27), p19, p21, descr=) ++362: --end of the loop-- +[1af179c2137b0] jit-log-opt-bridge} +[1af179c97806b] {jit-log-opt-loop +# Loop 3 : loop with 30 ops +[p0, p1, p2, p3, p4, p5, p6, i7, p8, p9, i10, i11, p12, i13, i14, p15, p16] +debug_merge_point(0, ' #13 FOR_ITER') ++435: i17 = int_ge(i10, i11) +guard_false(i17, descr=) [p1, p0, p5, i10, p12, p2, p3, p4, p6, p8, p9, i7] ++448: i18 = int_mul(i10, i13) ++459: i19 = int_add(i14, i18) ++469: i21 = int_add(i10, 1) +debug_merge_point(0, ' #16 STORE_FAST') +debug_merge_point(0, ' #19 LOAD_GLOBAL') +debug_merge_point(0, ' #22 LOAD_FAST') +debug_merge_point(0, ' #25 CALL_FUNCTION') ++473: setfield_gc(p5, i21, descr=) ++484: guard_not_invalidated(, descr=) [p1, p0, p15, p2, p3, p4, p5, p6, p8, p9, i19, None] ++484: p24 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i19, descr=) +debug_merge_point(0, ' #28 LIST_APPEND') ++497: i25 = getfield_gc(p16, descr=) ++509: i27 = int_add(i25, 1) ++516: call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p16, i27, descr=) ++546: guard_no_exception(, descr=) [p1, p0, i25, p16, p2, p3, p4, p5, p6, p8, p9, p24, i19, None] ++561: p29 = getfield_gc(p16, descr=) ++566: p31 = new_with_vtable(ConstClass(W_StringObject)) ++636: setfield_gc(p31, p24, descr=) +setarrayitem_gc(p29, i25, p31, descr=) +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++702: i33 = getfield_raw(40681184, descr=) ++710: i35 = int_sub(i33, 4) ++714: setfield_raw(40681184, i35, descr=) ++722: i37 = int_lt(i35, 0) +guard_false(i37, descr=) [p1, p0, p2, p3, p4, p5, p6, p8, p9, i19] +debug_merge_point(0, ' #13 FOR_ITER') ++732: jump(p0, p1, p2, p3, p4, p5, p6, i19, p8, p9, i21, i11, p12, i13, i14, p15, p16, descr=) ++757: --end of the loop-- +[1af179c9ab950] jit-log-opt-loop} +[1af179cc419a7] {jit-log-opt-loop +# Loop 4 : entry bridge with 56 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11, p12, p13, p14, p15] +debug_merge_point(0, ' #13 FOR_ITER') ++362: guard_value(i6, 2, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] ++372: guard_class(p9, 21012688, descr=) [p1, p0, p9, p2, p3, i4, p5, p8, p10, p11, p12, p13, p14, p15] ++384: p18 = getfield_gc(p9, descr=) ++388: guard_nonnull(p18, descr=) [p1, p0, p9, p18, p2, p3, i4, p5, p8, p10, p11, p12, p13, p14, p15] ++397: i19 = getfield_gc(p9, descr=) ++401: p20 = getfield_gc(p18, descr=) ++405: guard_isnull(p20, descr=) [p1, p0, p9, i19, p18, p20, p2, p3, i4, p5, p8, p10, p11, p12, p13, p14, p15] ++414: i21 = getfield_gc(p18, descr=) ++418: i22 = int_ge(i19, i21) +guard_false(i22, descr=) [p1, p0, p9, i19, p18, p2, p3, i4, p5, p8, p10, p11, p12, p13, p14, p15] ++427: i23 = getfield_gc(p18, descr=) ++431: i24 = getfield_gc(p18, descr=) ++442: i25 = int_mul(i19, i24) ++453: i26 = int_add(i23, i25) ++463: i28 = int_add(i19, 1) ++474: setfield_gc(p9, i28, descr=) ++478: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p11, p12, p13, p14, p15, i26] +debug_merge_point(0, ' #16 STORE_FAST') +debug_merge_point(0, ' #19 LOAD_GLOBAL') ++488: guard_value(p3, ConstPtr(ptr30), descr=) [p1, p0, p3, p2, p5, p8, p9, p11, p12, p14, p15, i26] ++507: p31 = getfield_gc(p0, descr=) ++519: guard_value(p31, ConstPtr(ptr32), descr=) [p1, p0, p31, p2, p5, p8, p9, p11, p12, p14, p15, i26] ++538: p33 = getfield_gc(p31, descr=) ++549: guard_isnull(p33, descr=) [p1, p0, p33, p31, p2, p5, p8, p9, p11, p12, p14, p15, i26] ++558: p35 = getfield_gc(ConstPtr(ptr34), descr=) ++571: guard_isnull(p35, descr=) [p1, p0, p35, p2, p5, p8, p9, p11, p12, p14, p15, i26] ++580: p37 = getfield_gc(ConstPtr(ptr36), descr=) ++588: guard_value(p37, ConstPtr(ptr38), descr=) [p1, p0, p37, p2, p5, p8, p9, p11, p12, p14, p15, i26] ++601: p39 = getfield_gc(p37, descr=) ++605: guard_isnull(p39, descr=) [p1, p0, p39, p37, p2, p5, p8, p9, p11, p12, p14, p15, i26] ++614: p41 = getfield_gc(ConstPtr(ptr40), descr=) ++622: guard_value(p41, ConstPtr(ptr42), descr=) [p1, p0, p41, p2, p5, p8, p9, p11, p12, p14, p15, i26] +debug_merge_point(0, ' #22 LOAD_FAST') +debug_merge_point(0, ' #25 CALL_FUNCTION') ++635: p44 = getfield_gc(ConstPtr(ptr43), descr=) ++643: guard_not_invalidated(, descr=) [p1, p0, p44, p2, p5, p8, p9, p12, p14, p15, i26] ++643: p46 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i26, descr=) +debug_merge_point(0, ' #28 LIST_APPEND') ++705: p47 = getfield_gc(p8, descr=) ++716: i48 = getfield_gc(p47, descr=) ++720: i50 = int_add(i48, 1) ++727: call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p47, i50, descr=) ++764: guard_no_exception(, descr=) [p1, p0, i48, p47, p2, p5, p8, p9, p12, p14, p15, p46, i26] ++779: p52 = getfield_gc(p47, descr=) ++790: p54 = new_with_vtable(ConstClass(W_StringObject)) ++860: setfield_gc(p54, p46, descr=) +setarrayitem_gc(p52, i48, p54, descr=) +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++926: i56 = getfield_raw(40681184, descr=) ++934: i58 = int_sub(i56, 4) ++938: setfield_raw(40681184, i58, descr=) ++946: i60 = int_lt(i58, 0) +guard_false(i60, descr=) [p1, p0, p2, p5, p8, p9, p12, p14, p15, i26] +debug_merge_point(0, ' #13 FOR_ITER') ++956: jump(p0, p1, p2, p5, p8, p9, p12, i26, p14, p15, i28, i21, p18, i24, i23, p44, p47, descr=) ++1149: --end of the loop-- +[1af179cc8cec7] jit-log-opt-loop} +[1af179d0cacd1] {jit-log-opt-loop # Loop 5 : entry bridge with 10 ops [i0, p1] -debug_merge_point('StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]', 0) -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 51) -guard_false(i5, descr=) [i0, p1] -i7 = int_add(i0, 1) -i8 = getfield_gc_pure(p1, descr=) -i9 = int_lt(i7, i8) -guard_false(i9, descr=) [i7, p1] -finish(0, descr=) -[18cc55605d17e] jit-log-opt-loop} -[18cc55621cb87] {jit-log-opt-bridge -# bridge out of Guard 47 with 10 ops +debug_merge_point(0, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') ++78: p2 = getfield_gc(p1, descr=) ++82: i3 = strgetitem(p2, i0) ++88: i5 = int_eq(i3, 51) +guard_true(i5, descr=) [i0, p1] ++98: i7 = int_add(i0, 1) ++105: setfield_gc(p1, i7, descr=) ++109: setfield_gc(p1, ConstPtr(ptr8), descr=) ++117: setfield_gc(p1, i0, descr=) ++121: finish(1, descr=) ++168: --end of the loop-- +[1af179d0da7b8] jit-log-opt-loop} +[1af179d281c59] {jit-log-opt-bridge +# bridge out of Guard 44 with 6 ops [i0, p1] -debug_merge_point('StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]', 0) -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 51) -guard_false(i5, descr=) [i0, p1] -i7 = int_add(i0, 1) -i8 = getfield_gc_pure(p1, descr=) -i9 = int_lt(i7, i8) -guard_false(i9, descr=) [i7, p1] -finish(0, descr=) -[18cc556232f98] jit-log-opt-bridge} -[18cc556509b41] {jit-log-opt-bridge -# bridge out of Guard 49 with 10 ops ++37: i3 = int_add(i0, 1) ++41: i4 = getfield_gc_pure(p1, descr=) ++45: i5 = int_lt(i3, i4) +guard_true(i5, descr=) [i3, p1] +debug_merge_point(0, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') ++54: jump(i3, p1, descr=) ++67: --end of the loop-- +[1af179d28ad65] jit-log-opt-bridge} +[1af179d501794] {jit-log-opt-bridge +# bridge out of Guard 45 with 1 ops [i0, p1] -debug_merge_point('StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]', 0) -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 51) -guard_false(i5, descr=) [i0, p1] -i7 = int_add(i0, 1) -i8 = getfield_gc_pure(p1, descr=) -i9 = int_lt(i7, i8) -guard_false(i9, descr=) [i7, p1] -finish(0, descr=) -[18cc556513988] jit-log-opt-bridge} -[18cc5572ba926] {jit-log-opt-loop -# Loop 6 : loop with 251 ops -[p0, p1, p2, p3, i4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15] -debug_merge_point(' #52 FOR_ITER', 0) -guard_class(p5, 17400800, descr=) [p1, p0, p5, p2, p3, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15] -p17 = getfield_gc(p5, descr=) -guard_nonnull(p17, descr=) [p1, p0, p5, p17, p2, p3, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15] -i18 = getfield_gc(p5, descr=) -p20 = call(ConstClass(ll_getitem_nonneg__dum_checkidxConst_listPtr_Signed), p17, i18, descr=) -guard_no_exception(, descr=) [p1, p0, p5, i18, p20, p2, p3, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15] -i22 = int_add(i18, 1) -debug_merge_point(' #55 STORE_FAST', 0) -debug_merge_point(' #58 LOAD_GLOBAL', 0) -p23 = getfield_gc(p0, descr=) -setfield_gc(p5, i22, descr=) -guard_value(p23, ConstPtr(ptr24), descr=) [p1, p0, p23, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p20] -p25 = getfield_gc(p23, descr=) -guard_isnull(p25, descr=) [p1, p0, p25, p23, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p20] -p27 = getfield_gc(ConstPtr(ptr26), descr=) -guard_nonnull_class(p27, 17396272, descr=) [p1, p0, p27, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p20] -debug_merge_point(' #61 LOOKUP_METHOD', 0) -p29 = getfield_gc(p27, descr=) -guard_value(p29, ConstPtr(ptr30), descr=) [p1, p0, p27, p29, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p20] -p31 = getfield_gc(p29, descr=) -guard_isnull(p31, descr=) [p1, p0, p27, p31, p29, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p20] -p33 = getfield_gc(ConstPtr(ptr32), descr=) -guard_nonnull_class(p33, ConstClass(Function), descr=) [p1, p0, p33, p27, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p20] -debug_merge_point(' #64 LOAD_CONST', 0) -debug_merge_point(' #67 LOAD_FAST', 0) -guard_nonnull(p20, descr=) [p1, p0, p20, p2, p3, p5, p33, p9, p10, p11, p12, p13, p14] -debug_merge_point(' #70 CALL_METHOD', 0) -i35 = getfield_gc(p0, descr=) -guard_false(i35, descr=) [p1, p0, p33, p2, p3, p5, p20, p10, p11, p12, p13, p14] -p36 = getfield_gc(p33, descr=) -guard_value(p36, ConstPtr(ptr37), descr=) [p1, p0, p36, p33, p2, p3, p5, p20, p10, p11, p12, p13, p14] -p38 = getfield_gc(p33, descr=) -i39 = arraylen_gc(p38, descr=) -i41 = int_sub(3, i39) -i43 = int_ge(2, i41) -guard_true(i43, descr=) [p1, p0, p33, p2, p3, p5, p20, p10, p11, p12, p13, p14] -p44 = getfield_gc(p33, descr=) -p45 = getfield_gc(p33, descr=) -i47 = int_sub(i39, 1) -i48 = int_ge(i47, i39) -guard_false(i48, descr=) [p1, p0, i39, i47, p38, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p44] -p49 = getarrayitem_gc(p38, i47, descr=) -i50 = int_ge(i39, i39) -guard_true(i50, descr=) [p1, p0, i39, p38, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, p44] -p52 = call(ConstClass(getexecutioncontext), descr=) -guard_no_exception(, descr=) [p1, p0, p52, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, p44] -i53 = getfield_gc(p52, descr=) -i55 = getfield_gc(ConstPtr(ptr54), descr=) -i56 = int_gt(i53, i55) -guard_false(i56, descr=) [p1, p0, p52, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, p44] -i58 = int_add(i53, 1) -p59 = getfield_gc(p52, descr=) -i60 = force_token() -p61 = getfield_gc(p52, descr=) -setfield_gc(p52, i58, descr=) -guard_isnull(p61, descr=) [p1, p0, p52, p61, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p59, i60, p49, p44] -i62 = getfield_gc(p52, descr=) -i63 = int_is_zero(i62) -guard_true(i63, descr=) [p1, p0, p52, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p59, i60, p49, p44] -debug_merge_point(' #0 LOAD_GLOBAL', 1) -guard_value(p44, ConstPtr(ptr64), descr=) [p1, p0, p52, p44, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p59, i60, p49, None] -p66 = getfield_gc(p44, descr=) -guard_isnull(p66, descr=) [p1, p0, p52, p66, p44, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p59, i60, p49, None] -p68 = getfield_gc(ConstPtr(ptr67), descr=) -guard_nonnull_class(p68, ConstClass(Function), descr=) [p1, p0, p52, p68, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p59, i60, p49, None] -debug_merge_point(' #3 LOAD_FAST', 1) -debug_merge_point(' #6 LOAD_FAST', 1) -guard_nonnull(p49, descr=) [p1, p0, p52, p49, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p68, p59, i60, None, None] -debug_merge_point(' #9 CALL_FUNCTION', 1) -p70 = getfield_gc(p68, descr=) -guard_value(p70, ConstPtr(ptr71), descr=) [p1, p0, p52, p70, p68, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, None, p59, i60, p49, None] -p72 = getfield_gc(p68, descr=) -p73 = getfield_gc(p68, descr=) -p74 = getfield_gc(p68, descr=) -p75 = getfield_gc(p68, descr=) -i76 = int_gt(i58, i55) -guard_false(i76, descr=) [p1, p0, p52, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p72, p68, p59, i60, p49, None] -i78 = int_add(i58, 1) -i79 = force_token() -debug_merge_point(' #0 LOAD_GLOBAL', 2) -setfield_gc(p52, i78, descr=) -guard_value(p72, ConstPtr(ptr80), descr=) [p1, p0, p52, p72, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, i79, None, p68, p59, i60, p49, None] -p81 = getfield_gc(p72, descr=) -guard_isnull(p81, descr=) [p1, p0, p52, p81, p72, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, i79, None, p68, p59, i60, p49, None] -p83 = getfield_gc(ConstPtr(ptr82), descr=) -guard_isnull(p83, descr=) [p1, p0, p52, p83, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, i79, None, p68, p59, i60, p49, None] -p85 = getfield_gc(ConstPtr(ptr84), descr=) -guard_value(p85, ConstPtr(ptr86), descr=) [p1, p0, p52, p85, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, i79, None, p68, p59, i60, p49, None] -p87 = getfield_gc(p85, descr=) -guard_isnull(p87, descr=) [p1, p0, p52, p87, p85, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, i79, None, p68, p59, i60, p49, None] -p89 = getfield_gc(ConstPtr(ptr88), descr=) -guard_value(p89, ConstPtr(ptr90), descr=) [p1, p0, p52, p89, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, i79, None, p68, p59, i60, p49, None] -debug_merge_point(' #3 LOAD_FAST', 2) -debug_merge_point(' #6 LOAD_CONST', 2) -debug_merge_point(' #9 BINARY_SUBSCR', 2) -p92 = new_array(2, descr=) -setarrayitem_gc(p92, 0, ConstPtr(ptr94), descr=) -setarrayitem_gc(p92, 1, p49, descr=) -p98 = call(ConstClass(ll_getitem__dum_checkidxConst_arrayPtr_Signed), p92, 0, descr=) -guard_no_exception(, descr=) [p1, p0, p52, p98, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, i60, i79, p68, p92, p89, p59] -debug_merge_point(' #10 CALL_FUNCTION', 2) -guard_class(p98, ConstClass(W_StringObject), descr=) [p1, p0, p52, p98, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, i60, i79, p68, p92, None, p59] -debug_merge_point(' #13 BUILD_TUPLE', 2) -debug_merge_point(' #16 LOAD_FAST', 2) -debug_merge_point(' #19 BINARY_ADD', 2) -i100 = arraylen_gc(p92, descr=) -i102 = int_add_ovf(1, i100) -guard_no_overflow(, descr=) [p1, p0, p52, i102, i100, p92, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, i60, i79, p68, None, None, p59] -p103 = new_array(i102, descr=) -p105 = new_array(1, descr=) -setarrayitem_gc(p105, 0, ConstPtr(ptr107), descr=) -call(ConstClass(ll_arraycopy__arrayPtr_arrayPtr_Signed_Signed_Signed), p105, p103, 0, 0, 1, descr=) -guard_no_exception(, descr=) [p1, p0, p52, i100, p103, p92, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p68, p49, i60, i79, p105, p59] -call(ConstClass(ll_arraycopy__arrayPtr_arrayPtr_Signed_Signed_Signed), p92, p103, 0, 1, i100, descr=) -guard_no_exception(, descr=) [p1, p0, p52, p103, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p92, p68, p49, i60, i79, p105, p59] -debug_merge_point(' #20 STORE_FAST', 2) -debug_merge_point(' #23 LOAD_GLOBAL', 2) -p112 = getfield_gc(ConstPtr(ptr111), descr=) -guard_nonnull_class(p112, 17393704, descr=) [p1, p0, p52, p112, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p103, p92, p68, p49, i60, i79, None, p59] -debug_merge_point(' #26 LOOKUP_METHOD', 2) -debug_merge_point(' #29 LOAD_FAST', 2) -debug_merge_point(' #32 CALL_METHOD', 2) -p115 = getfield_gc(ConstPtr(ptr114), descr=) -p116 = getfield_gc(ConstPtr(ptr114), descr=) -i117 = arraylen_gc(p116, descr=) -i119 = int_sub(3, i117) -i121 = int_ge(2, i119) -guard_true(i121, descr=) [p1, p0, p52, p115, i119, p116, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p112, p103, p92, p68, p49, i60, i79, None, p59] -i122 = int_sub(2, i119) -p123 = getarrayitem_gc(p116, i122, descr=) -guard_class(p123, ConstClass(W_NoneObject), descr=) [p1, p0, p52, p123, p112, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, None, p103, p92, p68, p49, i60, i79, None, p59] -p125 = getfield_gc(p112, descr=) -guard_nonnull(p125, descr=) [p1, p0, p52, p123, p112, p125, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, None, p103, p92, p68, p49, i60, i79, None, p59] -i126 = force_token() -p128 = new_with_vtable(17394712) -setfield_gc(p128, i79, descr=) -setfield_gc(p128, 1, descr=) -setfield_gc(p52, p128, descr=) -setfield_gc(p0, i126, descr=) -p131 = new_with_vtable(17388288) -setfield_gc(p131, p103, descr=) -p134 = call_may_force(ConstClass(ll_get__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_pypy_interpreter_baseobjspace_W_RootPtr), p125, p131, ConstPtr(ptr133), descr=) -guard_not_forced(, descr=) [p1, p0, p52, p123, p131, p112, p134, p128, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p68, p49, p92, p59, i60] -guard_no_exception(, descr=) [p1, p0, p52, p123, p131, p112, p134, p128, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p68, p49, p92, p59, i60] -guard_nonnull_class(p134, 17542064, descr=) [p1, p0, p52, p123, p131, p112, p134, p128, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p68, p49, p92, p59, i60] -debug_merge_point(' #35 STORE_FAST', 2) -debug_merge_point(' #38 LOAD_FAST', 2) -debug_merge_point(' #41 LOAD_CONST', 2) -debug_merge_point(' #44 COMPARE_OP', 2) -i137 = ptr_eq(p134, ConstPtr(ptr136)) -guard_false(i137, descr=) [p1, p0, p52, p128, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p131, p134, p68, p49, p92, p59, i60] -debug_merge_point(' #47 JUMP_IF_FALSE', 2) -debug_merge_point(' #50 POP_TOP', 2) -debug_merge_point(' #51 LOAD_FAST', 2) -debug_merge_point(' #54 RETURN_VALUE', 2) -p138 = getfield_gc(p52, descr=) -guard_isnull(p138, descr=) [p1, p0, p52, p134, p138, p128, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p131, None, p68, p49, p92, p59, i60] -i139 = getfield_gc(p52, descr=) -i140 = int_is_true(i139) -guard_false(i140, descr=) [p1, p0, p52, p134, p128, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p131, None, p68, p49, p92, p59, i60] -i141 = getfield_gc(p52, descr=) -i143 = int_sub(i141, 1) -debug_merge_point(' #12 LOOKUP_METHOD', 1) -debug_merge_point(' #15 LOAD_FAST', 1) -debug_merge_point(' #18 CALL_METHOD', 1) -p145 = getfield_gc(ConstPtr(ptr144), descr=) -p146 = getfield_gc(ConstPtr(ptr144), descr=) -i147 = arraylen_gc(p146, descr=) -i149 = int_sub(4, i147) -setfield_gc(p52, i143, descr=) -setfield_gc(p128, -3, descr=) -i152 = int_ge(2, i149) -guard_true(i152, descr=) [p1, p0, p52, p145, i149, p146, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p128, p131, p134, None, p49, p92, p59, i60] -i153 = int_sub(2, i149) -p154 = getarrayitem_gc(p146, i153, descr=) -i156 = int_sub(3, i149) -p157 = getarrayitem_gc(p146, i156, descr=) -guard_class(p154, ConstClass(W_IntObject), descr=) [p1, p0, p52, p154, p20, p134, p2, p3, p5, p33, p10, p11, p12, p13, p14, p157, p128, p131, None, None, p49, p92, p59, i60] -i159 = getfield_gc_pure(p154, descr=) -guard_class(p157, ConstClass(W_IntObject), descr=) [p1, p0, p52, i159, p20, p157, p134, p2, p3, p5, p33, p10, p11, p12, p13, p14, p154, None, p128, p131, None, None, p49, p92, p59, i60] -i161 = getfield_gc_pure(p157, descr=) -i162 = force_token() -p163 = new_with_vtable(17394712) -setfield_gc(p163, i60, descr=) -setfield_gc(p52, p163, descr=) -p165 = new_with_vtable(17444768) -setfield_gc(p165, p163, descr=) -setfield_gc(p165, ConstPtr(ptr71), descr=) -p167 = new_array(9, descr=) -setfield_gc(p165, p167, descr=) -setfield_gc(p165, -1, descr=) -setfield_gc(p165, -1, descr=) -setfield_gc(p165, ConstPtr(ptr80), descr=) -setfield_gc(p165, 54, descr=) -setfield_gc(p165, ConstPtr(ptr171), descr=) -setfield_gc(p165, 6, descr=) -p173 = new_array(6, descr=) -p175 = new_with_vtable(17388288) -setfield_gc(p175, p92, descr=) -setarrayitem_gc(p173, 0, p175, descr=) -setarrayitem_gc(p173, 1, p131, descr=) -setarrayitem_gc(p173, 2, p134, descr=) -setfield_gc(p165, p173, descr=) -setfield_gc(p165, 227, descr=) -setfield_gc(p165, 1, descr=) -setfield_gc(p128, p165, descr=) -setfield_gc(p0, i162, descr=) -p182 = call_may_force(ConstClass(W_SRE_Pattern.search_w), p134, p20, i159, i161, descr=) -guard_not_forced(, descr=) [p1, p0, p52, p182, p163, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, p134, p154, p157, p59] -guard_no_exception(, descr=) [p1, p0, p52, p182, p163, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, p134, p154, p157, p59] -guard_nonnull(p182, descr=) [p1, p0, p52, p182, p163, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, p134, None, None, p59] -debug_merge_point(' #21 RETURN_VALUE', 1) -p183 = getfield_gc(p52, descr=) -guard_isnull(p183, descr=) [p1, p0, p52, p182, p183, p163, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, None, None, None, p59] -i184 = getfield_gc(p52, descr=) -i185 = int_is_true(i184) -guard_false(i185, descr=) [p1, p0, p182, p52, p163, p2, p3, p5, p33, p20, p10, p11, p12, p13, p14, p49, None, None, None, p59] -i186 = getfield_gc(p52, descr=) -i188 = int_sub(i186, 1) -debug_merge_point(' #73 POP_TOP', 0) -debug_merge_point(' #74 JUMP_ABSOLUTE', 0) -i190 = getfield_raw(32192224, descr=) -i192 = int_sub(i190, 54) -setfield_raw(32192224, i192, descr=) -setfield_gc(p52, p59, descr=) -setfield_gc(p52, i188, descr=) -setfield_gc(p163, -3, descr=) -i195 = int_lt(i192, 0) -guard_false(i195, descr=) [p1, p0, p2, p3, p5, p10, p11, p12, p13, p14, p20, p163, p49, None, None, None, p59] -debug_merge_point(' #52 FOR_ITER', 0) -p197 = new_with_vtable(17444768) -setfield_gc(p197, p59, descr=) -setfield_gc(p197, ConstPtr(ptr37), descr=) -p199 = new_array(3, descr=) -setfield_gc(p197, p199, descr=) -setfield_gc(p197, -1, descr=) -setfield_gc(p197, -1, descr=) -setfield_gc(p197, ConstPtr(ptr64), descr=) -setfield_gc(p197, 21, descr=) -setfield_gc(p197, ConstPtr(ptr171), descr=) -setfield_gc(p197, 3, descr=) -p204 = new_array(3, descr=) -setarrayitem_gc(p204, 0, ConstPtr(ptr94), descr=) -setarrayitem_gc(p204, 1, p20, descr=) -setarrayitem_gc(p204, 2, p49, descr=) -setfield_gc(p197, p204, descr=) -setfield_gc(p197, 139, descr=) -setfield_gc(p197, 1, descr=) -setfield_gc(p163, p197, descr=) -jump(p0, p1, p2, p3, 52, p5, ConstPtr(ptr211), ConstPtr(ptr212), ConstPtr(ptr213), ConstPtr(ptr214), p10, p11, p12, p13, p14, p20, descr=) -[18cc5573d87df] jit-log-opt-loop} -[18cc557a940c2] {jit-log-opt-bridge -# bridge out of Guard 51 with 10 ops -[i0, p1] -debug_merge_point('StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]', 0) -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 51) -guard_false(i5, descr=) [i0, p1] -i7 = int_add(i0, 1) -i8 = getfield_gc_pure(p1, descr=) -i9 = int_lt(i7, i8) -guard_false(i9, descr=) [i7, p1] -finish(0, descr=) -[18cc557aa0241] jit-log-opt-bridge} -[18cc558d00c3c] {jit-log-opt-loop -# Loop 7 : entry bridge with 253 ops -[p0, p1, p2, p3, p4, i5, i6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17] -debug_merge_point(' #52 FOR_ITER', 0) -guard_value(i5, 1, descr=) [i5, p1, p0, p2, p3, p4, i6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17] -guard_class(p7, 17400800, descr=) [p1, p0, p7, p2, p3, p4, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17] -p20 = getfield_gc(p7, descr=) -guard_nonnull(p20, descr=) [p1, p0, p7, p20, p2, p3, p4, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17] -i21 = getfield_gc(p7, descr=) -p23 = call(ConstClass(ll_getitem_nonneg__dum_checkidxConst_listPtr_Signed), p20, i21, descr=) -guard_no_exception(, descr=) [p1, p0, p7, i21, p23, p2, p3, p4, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17] -i25 = int_add(i21, 1) -debug_merge_point(' #55 STORE_FAST', 0) -debug_merge_point(' #58 LOAD_GLOBAL', 0) -setfield_gc(p7, i25, descr=) -guard_value(p3, ConstPtr(ptr26), descr=) [p1, p0, p3, p2, p4, p7, p9, p10, p11, p12, p13, p14, p15, p16, p23] -p27 = getfield_gc(p0, descr=) -guard_value(p27, ConstPtr(ptr28), descr=) [p1, p0, p27, p2, p4, p7, p9, p10, p11, p12, p13, p14, p15, p16, p23] -p29 = getfield_gc(p27, descr=) -guard_isnull(p29, descr=) [p1, p0, p29, p27, p2, p4, p7, p9, p10, p11, p12, p13, p14, p15, p16, p23] -p31 = getfield_gc(ConstPtr(ptr30), descr=) -guard_nonnull_class(p31, 17396272, descr=) [p1, p0, p31, p2, p4, p7, p9, p10, p11, p12, p13, p14, p15, p16, p23] -debug_merge_point(' #61 LOOKUP_METHOD', 0) -p33 = getfield_gc(p31, descr=) -guard_value(p33, ConstPtr(ptr34), descr=) [p1, p0, p31, p33, p2, p4, p7, p9, p10, p11, p12, p13, p14, p15, p16, p23] -p35 = getfield_gc(p33, descr=) -guard_isnull(p35, descr=) [p1, p0, p31, p35, p33, p2, p4, p7, p9, p10, p11, p12, p13, p14, p15, p16, p23] -p37 = getfield_gc(ConstPtr(ptr36), descr=) -guard_nonnull_class(p37, ConstClass(Function), descr=) [p1, p0, p37, p31, p2, p4, p7, p9, p10, p11, p12, p13, p14, p15, p16, p23] -debug_merge_point(' #64 LOAD_CONST', 0) -debug_merge_point(' #67 LOAD_FAST', 0) -guard_nonnull(p23, descr=) [p1, p0, p23, p2, p4, p7, p37, p11, p12, p13, p14, p15, p16] -debug_merge_point(' #70 CALL_METHOD', 0) -i39 = getfield_gc(p0, descr=) -guard_false(i39, descr=) [p1, p0, p37, p2, p4, p7, p23, p12, p13, p14, p15, p16] -p40 = getfield_gc(p37, descr=) -guard_value(p40, ConstPtr(ptr41), descr=) [p1, p0, p40, p37, p2, p4, p7, p23, p12, p13, p14, p15, p16] -p42 = getfield_gc(p37, descr=) -i43 = arraylen_gc(p42, descr=) -i45 = int_sub(3, i43) -i47 = int_ge(2, i45) -guard_true(i47, descr=) [p1, p0, p37, p2, p4, p7, p23, p12, p13, p14, p15, p16] -p48 = getfield_gc(p37, descr=) -p49 = getfield_gc(p37, descr=) -i51 = int_sub(i43, 1) -i52 = int_ge(i51, i43) -guard_false(i52, descr=) [p1, p0, i43, i51, p42, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p48] -p53 = getarrayitem_gc(p42, i51, descr=) -i54 = int_ge(i43, i43) -guard_true(i54, descr=) [p1, p0, i43, p42, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p53, p48] -p56 = call(ConstClass(getexecutioncontext), descr=) -guard_no_exception(, descr=) [p1, p0, p56, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p53, p48] -i57 = getfield_gc(p56, descr=) -i59 = getfield_gc(ConstPtr(ptr58), descr=) -i60 = int_gt(i57, i59) -guard_false(i60, descr=) [p1, p0, p56, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p53, p48] -i62 = int_add(i57, 1) -p63 = getfield_gc(p56, descr=) -i64 = force_token() -p65 = getfield_gc(p56, descr=) -setfield_gc(p56, i62, descr=) -guard_isnull(p65, descr=) [p1, p0, p56, p65, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i64, p63, p53, p48] -i66 = getfield_gc(p56, descr=) -i67 = int_is_zero(i66) -guard_true(i67, descr=) [p1, p0, p56, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i64, p63, p53, p48] -debug_merge_point(' #0 LOAD_GLOBAL', 1) -guard_value(p48, ConstPtr(ptr68), descr=) [p1, p0, p56, p48, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i64, p63, p53, None] -p70 = getfield_gc(p48, descr=) -guard_isnull(p70, descr=) [p1, p0, p56, p70, p48, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i64, p63, p53, None] -p72 = getfield_gc(ConstPtr(ptr71), descr=) -guard_nonnull_class(p72, ConstClass(Function), descr=) [p1, p0, p56, p72, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i64, p63, p53, None] -debug_merge_point(' #3 LOAD_FAST', 1) -debug_merge_point(' #6 LOAD_FAST', 1) -guard_nonnull(p53, descr=) [p1, p0, p56, p53, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p72, i64, p63, None, None] -debug_merge_point(' #9 CALL_FUNCTION', 1) -p74 = getfield_gc(p72, descr=) -guard_value(p74, ConstPtr(ptr75), descr=) [p1, p0, p56, p74, p72, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, None, i64, p63, p53, None] -p76 = getfield_gc(p72, descr=) -p77 = getfield_gc(p72, descr=) -p78 = getfield_gc(p72, descr=) -p79 = getfield_gc(p72, descr=) -i80 = int_gt(i62, i59) -guard_false(i80, descr=) [p1, p0, p56, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p76, p72, i64, p63, p53, None] -i82 = int_add(i62, 1) -i83 = force_token() -debug_merge_point(' #0 LOAD_GLOBAL', 2) -setfield_gc(p56, i82, descr=) -guard_value(p76, ConstPtr(ptr84), descr=) [p1, p0, p56, p76, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i83, None, p72, i64, p63, p53, None] -p85 = getfield_gc(p76, descr=) -guard_isnull(p85, descr=) [p1, p0, p56, p85, p76, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i83, None, p72, i64, p63, p53, None] -p87 = getfield_gc(ConstPtr(ptr86), descr=) -guard_isnull(p87, descr=) [p1, p0, p56, p87, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i83, None, p72, i64, p63, p53, None] -p89 = getfield_gc(ConstPtr(ptr88), descr=) -guard_value(p89, ConstPtr(ptr90), descr=) [p1, p0, p56, p89, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i83, None, p72, i64, p63, p53, None] -p91 = getfield_gc(p89, descr=) -guard_isnull(p91, descr=) [p1, p0, p56, p91, p89, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i83, None, p72, i64, p63, p53, None] -p93 = getfield_gc(ConstPtr(ptr92), descr=) -guard_value(p93, ConstPtr(ptr94), descr=) [p1, p0, p56, p93, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, i83, None, p72, i64, p63, p53, None] -debug_merge_point(' #3 LOAD_FAST', 2) -debug_merge_point(' #6 LOAD_CONST', 2) -debug_merge_point(' #9 BINARY_SUBSCR', 2) -p96 = new_array(2, descr=) -setarrayitem_gc(p96, 0, ConstPtr(ptr98), descr=) -setarrayitem_gc(p96, 1, p53, descr=) -p102 = call(ConstClass(ll_getitem__dum_checkidxConst_arrayPtr_Signed), p96, 0, descr=) -guard_no_exception(, descr=) [p1, p0, p56, p102, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p93, p96, i64, i83, p72, p53, p63] -debug_merge_point(' #10 CALL_FUNCTION', 2) -guard_class(p102, ConstClass(W_StringObject), descr=) [p1, p0, p56, p102, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, None, p96, i64, i83, p72, p53, p63] -debug_merge_point(' #13 BUILD_TUPLE', 2) -debug_merge_point(' #16 LOAD_FAST', 2) -debug_merge_point(' #19 BINARY_ADD', 2) -i104 = arraylen_gc(p96, descr=) -i106 = int_add_ovf(1, i104) -guard_no_overflow(, descr=) [p1, p0, p56, i106, i104, p96, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, None, None, i64, i83, p72, p53, p63] -p107 = new_array(i106, descr=) -p109 = new_array(1, descr=) -setarrayitem_gc(p109, 0, ConstPtr(ptr111), descr=) -call(ConstClass(ll_arraycopy__arrayPtr_arrayPtr_Signed_Signed_Signed), p109, p107, 0, 0, 1, descr=) -guard_no_exception(, descr=) [p1, p0, p56, i104, p107, p96, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p109, i64, i83, p72, p53, p63] -call(ConstClass(ll_arraycopy__arrayPtr_arrayPtr_Signed_Signed_Signed), p96, p107, 0, 1, i104, descr=) -guard_no_exception(, descr=) [p1, p0, p56, p107, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p96, p109, i64, i83, p72, p53, p63] -debug_merge_point(' #20 STORE_FAST', 2) -debug_merge_point(' #23 LOAD_GLOBAL', 2) -p116 = getfield_gc(ConstPtr(ptr115), descr=) -guard_nonnull_class(p116, 17393704, descr=) [p1, p0, p56, p116, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p107, p96, None, i64, i83, p72, p53, p63] -debug_merge_point(' #26 LOOKUP_METHOD', 2) -debug_merge_point(' #29 LOAD_FAST', 2) -debug_merge_point(' #32 CALL_METHOD', 2) -p119 = getfield_gc(ConstPtr(ptr118), descr=) -p120 = getfield_gc(ConstPtr(ptr118), descr=) -i121 = arraylen_gc(p120, descr=) -i123 = int_sub(3, i121) -i125 = int_ge(2, i123) -guard_true(i125, descr=) [p1, p0, p56, p119, i123, p120, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p116, p107, p96, None, i64, i83, p72, p53, p63] -i126 = int_sub(2, i123) -p127 = getarrayitem_gc(p120, i126, descr=) -guard_class(p127, ConstClass(W_NoneObject), descr=) [p1, p0, p56, p127, p116, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, None, p107, p96, None, i64, i83, p72, p53, p63] -p129 = getfield_gc(p116, descr=) -guard_nonnull(p129, descr=) [p1, p0, p56, p127, p116, p129, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, None, p107, p96, None, i64, i83, p72, p53, p63] -i130 = force_token() -p132 = new_with_vtable(17394712) -setfield_gc(p132, i83, descr=) -setfield_gc(p132, 1, descr=) -setfield_gc(p56, p132, descr=) -setfield_gc(p0, i130, descr=) -p135 = new_with_vtable(17388288) -setfield_gc(p135, p107, descr=) -p138 = call_may_force(ConstClass(ll_get__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_pypy_interpreter_baseobjspace_W_RootPtr), p129, p135, ConstPtr(ptr137), descr=) -guard_not_forced(, descr=) [p1, p0, p56, p127, p135, p116, p138, p132, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p96, i64, p72, p53, p63] -guard_no_exception(, descr=) [p1, p0, p56, p127, p135, p116, p138, p132, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p96, i64, p72, p53, p63] -guard_nonnull_class(p138, 17542064, descr=) [p1, p0, p56, p127, p135, p116, p138, p132, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p96, i64, p72, p53, p63] -debug_merge_point(' #35 STORE_FAST', 2) -debug_merge_point(' #38 LOAD_FAST', 2) -debug_merge_point(' #41 LOAD_CONST', 2) -debug_merge_point(' #44 COMPARE_OP', 2) -i141 = ptr_eq(p138, ConstPtr(ptr140)) -guard_false(i141, descr=) [p1, p0, p56, p132, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p138, p135, p96, i64, p72, p53, p63] -debug_merge_point(' #47 JUMP_IF_FALSE', 2) -debug_merge_point(' #50 POP_TOP', 2) -debug_merge_point(' #51 LOAD_FAST', 2) -debug_merge_point(' #54 RETURN_VALUE', 2) -p142 = getfield_gc(p56, descr=) -guard_isnull(p142, descr=) [p1, p0, p56, p138, p142, p132, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, None, p135, p96, i64, p72, p53, p63] -i143 = getfield_gc(p56, descr=) -i144 = int_is_true(i143) -guard_false(i144, descr=) [p1, p0, p56, p138, p132, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, None, p135, p96, i64, p72, p53, p63] -i145 = getfield_gc(p56, descr=) -i147 = int_sub(i145, 1) -debug_merge_point(' #12 LOOKUP_METHOD', 1) -debug_merge_point(' #15 LOAD_FAST', 1) -debug_merge_point(' #18 CALL_METHOD', 1) -p149 = getfield_gc(ConstPtr(ptr148), descr=) -p150 = getfield_gc(ConstPtr(ptr148), descr=) -i151 = arraylen_gc(p150, descr=) -i153 = int_sub(4, i151) -setfield_gc(p56, i147, descr=) -setfield_gc(p132, -3, descr=) -i156 = int_ge(2, i153) -guard_true(i156, descr=) [p1, p0, p56, p149, i153, p150, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p132, p138, p135, p96, i64, None, p53, p63] -i157 = int_sub(2, i153) -p158 = getarrayitem_gc(p150, i157, descr=) -i160 = int_sub(3, i153) -p161 = getarrayitem_gc(p150, i160, descr=) -guard_class(p158, ConstClass(W_IntObject), descr=) [p1, p0, p56, p158, p23, p138, p2, p4, p7, p37, p12, p13, p14, p15, p16, p161, p132, None, p135, p96, i64, None, p53, p63] -i163 = getfield_gc_pure(p158, descr=) -guard_class(p161, ConstClass(W_IntObject), descr=) [p1, p0, p56, i163, p23, p161, p138, p2, p4, p7, p37, p12, p13, p14, p15, p16, p158, None, p132, None, p135, p96, i64, None, p53, p63] -i165 = getfield_gc_pure(p161, descr=) -i166 = force_token() -p167 = new_with_vtable(17394712) -setfield_gc(p167, i64, descr=) -setfield_gc(p56, p167, descr=) -p169 = new_with_vtable(17444768) -setfield_gc(p169, p167, descr=) -setfield_gc(p169, ConstPtr(ptr75), descr=) -p171 = new_array(9, descr=) -setfield_gc(p169, p171, descr=) -setfield_gc(p169, -1, descr=) -setfield_gc(p169, -1, descr=) -setfield_gc(p169, ConstPtr(ptr84), descr=) -setfield_gc(p169, 54, descr=) -setfield_gc(p169, ConstPtr(ptr175), descr=) -setfield_gc(p169, 6, descr=) -p177 = new_array(6, descr=) -p179 = new_with_vtable(17388288) -setfield_gc(p179, p96, descr=) -setarrayitem_gc(p177, 0, p179, descr=) -setarrayitem_gc(p177, 1, p135, descr=) -setarrayitem_gc(p177, 2, p138, descr=) -setfield_gc(p169, p177, descr=) -setfield_gc(p169, 227, descr=) -setfield_gc(p169, 1, descr=) -setfield_gc(p132, p169, descr=) -setfield_gc(p0, i166, descr=) -p186 = call_may_force(ConstClass(W_SRE_Pattern.search_w), p138, p23, i163, i165, descr=) -guard_not_forced(, descr=) [p1, p0, p56, p186, p167, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p138, p161, p158, p53, p63] -guard_no_exception(, descr=) [p1, p0, p56, p186, p167, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p138, p161, p158, p53, p63] -guard_nonnull(p186, descr=) [p1, p0, p56, p186, p167, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, p138, None, None, p53, p63] -debug_merge_point(' #21 RETURN_VALUE', 1) -p187 = getfield_gc(p56, descr=) -guard_isnull(p187, descr=) [p1, p0, p56, p186, p187, p167, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, None, None, None, p53, p63] -i188 = getfield_gc(p56, descr=) -i189 = int_is_true(i188) -guard_false(i189, descr=) [p1, p0, p186, p56, p167, p2, p4, p7, p37, p23, p12, p13, p14, p15, p16, None, None, None, p53, p63] -i190 = getfield_gc(p56, descr=) -i192 = int_sub(i190, 1) -debug_merge_point(' #73 POP_TOP', 0) -debug_merge_point(' #74 JUMP_ABSOLUTE', 0) -i194 = getfield_raw(32192224, descr=) -i196 = int_sub(i194, 54) -setfield_raw(32192224, i196, descr=) -setfield_gc(p56, p63, descr=) -setfield_gc(p56, i192, descr=) -setfield_gc(p167, -3, descr=) -i199 = int_lt(i196, 0) -guard_false(i199, descr=) [p1, p0, p2, p4, p7, p12, p13, p14, p15, p16, p23, p167, None, None, None, p53, p63] -debug_merge_point(' #52 FOR_ITER', 0) -p201 = new_with_vtable(17444768) -setfield_gc(p201, p63, descr=) -setfield_gc(p201, ConstPtr(ptr41), descr=) -p203 = new_array(3, descr=) -setfield_gc(p201, p203, descr=) -setfield_gc(p201, -1, descr=) -setfield_gc(p201, -1, descr=) -setfield_gc(p201, ConstPtr(ptr68), descr=) -setfield_gc(p201, 21, descr=) -setfield_gc(p201, ConstPtr(ptr175), descr=) -setfield_gc(p201, 3, descr=) -p208 = new_array(3, descr=) -setarrayitem_gc(p208, 0, ConstPtr(ptr98), descr=) -setarrayitem_gc(p208, 1, p23, descr=) -setarrayitem_gc(p208, 2, p53, descr=) -setfield_gc(p201, p208, descr=) -setfield_gc(p201, 139, descr=) -setfield_gc(p201, 1, descr=) -setfield_gc(p167, p201, descr=) -jump(p0, p1, p2, p4, 52, p7, ConstPtr(ptr215), ConstPtr(ptr216), ConstPtr(ptr217), ConstPtr(ptr218), p12, p13, p14, p15, p16, p23, descr=) -[18cc5590f3a87] jit-log-opt-loop} -[18cc5593ceb08] {jit-log-opt-bridge -# bridge out of Guard 48 with 5 ops -[i0, p1] -i3 = int_add(i0, 1) -setfield_gc(p1, i3, descr=) -setfield_gc(p1, ConstPtr(ptr4), descr=) -setfield_gc(p1, i0, descr=) -finish(1, descr=) -[18cc5593d6e13] jit-log-opt-bridge} -[18cc559577fad] {jit-log-opt-bridge -# bridge out of Guard 50 with 5 ops -[i0, p1] -i3 = int_add(i0, 1) -setfield_gc(p1, i3, descr=) -setfield_gc(p1, ConstPtr(ptr4), descr=) -setfield_gc(p1, i0, descr=) -finish(1, descr=) -[18cc55957ed2d] jit-log-opt-bridge} -[18cc5595ebde3] {jit-backend-counts -0:3 -1:3 -2:7599 -3:399 -4:3599 -5:1100 -6:3147 -7:2445 -8:2005 -9:983 -10:1420 -11:8 -12:40 -13:0 -[18cc5595f7be9] jit-backend-counts} ++37: finish(0, descr=) ++84: --end of the loop-- +[1af179d5051db] jit-log-opt-bridge} +[1af179fc93628] {jit-log-opt-loop +# Loop 6 : loop with 201 ops +[p0, p1, p2, p3, p4, p5, p6, p7, i8, p9, p10] +debug_merge_point(0, ' #44 FOR_ITER') ++321: p11 = getfield_gc(p4, descr=) ++332: guard_nonnull(p11, descr=) [p1, p0, p4, p11, p2, p3, p5, p6, p7] ++341: i12 = getfield_gc(p4, descr=) ++345: i13 = getfield_gc(p11, descr=) ++350: i14 = int_ge(i12, i13) +guard_false(i14, descr=) [p1, p0, p4, i12, p11, p2, p3, p5, p6, p7] ++359: p15 = getfield_gc(p11, descr=) ++364: p16 = getarrayitem_gc(p15, i12, descr=) ++369: i18 = int_add(i12, 1) +debug_merge_point(0, ' #47 STORE_FAST') +debug_merge_point(0, ' #50 LOAD_GLOBAL') ++373: p19 = getfield_gc(p0, descr=) ++384: setfield_gc(p4, i18, descr=) ++388: guard_value(p19, ConstPtr(ptr20), descr=) [p1, p0, p19, p2, p3, p4, p5, p6, p16] ++407: p21 = getfield_gc(p19, descr=) ++411: guard_isnull(p21, descr=) [p1, p0, p21, p19, p2, p3, p4, p5, p6, p16] ++420: p23 = getfield_gc(ConstPtr(ptr22), descr=) ++433: guard_nonnull_class(p23, 21015776, descr=) [p1, p0, p23, p2, p3, p4, p5, p6, p16] +debug_merge_point(0, ' #53 LOOKUP_METHOD') ++452: p25 = getfield_gc(p23, descr=) ++456: guard_value(p25, ConstPtr(ptr26), descr=) [p1, p0, p23, p25, p2, p3, p4, p5, p6, p16] ++475: p27 = getfield_gc(p25, descr=) ++479: guard_isnull(p27, descr=) [p1, p0, p23, p27, p25, p2, p3, p4, p5, p6, p16] ++488: p29 = getfield_gc(ConstPtr(ptr28), descr=) ++501: guard_nonnull_class(p29, ConstClass(Function), descr=) [p1, p0, p29, p23, p2, p3, p4, p5, p6, p16] +debug_merge_point(0, ' #56 LOAD_CONST') +debug_merge_point(0, ' #59 LOAD_FAST') ++520: guard_nonnull_class(p16, ConstClass(W_StringObject), descr=) [p1, p0, p16, p2, p3, p4, p29, p5, p6] +debug_merge_point(0, ' #62 CALL_METHOD') ++540: p32 = getfield_gc(p29, descr=) ++544: guard_value(p32, ConstPtr(ptr33), descr=) [p1, p0, p32, p29, p2, p3, p4, p16, p5, p6] ++563: p34 = getfield_gc(p29, descr=) ++567: i35 = arraylen_gc(p34, descr=) ++571: i37 = int_sub(3, i35) ++581: i39 = int_ge(2, i37) +guard_true(i39, descr=) [p1, p0, p29, p2, p3, p4, p16, p5, p6] ++591: p40 = getfield_gc(p29, descr=) ++595: p41 = getfield_gc(p29, descr=) ++595: i43 = int_sub(i35, 1) ++602: i44 = int_ge(i43, i35) +guard_false(i44, descr=) [p1, p0, i35, i43, p29, p2, p3, p4, p16, p5, p6, p40] ++611: p45 = getarrayitem_gc_pure(p34, i43, descr=) ++616: i46 = force_token() ++623: i47 = int_is_zero(i8) +guard_true(i47, descr=) [p1, p0, p9, p2, p3, p4, p29, p16, p5, p6, p45, p10, i46, p40] +debug_merge_point(1, ' #0 LOAD_GLOBAL') ++633: guard_value(p40, ConstPtr(ptr48), descr=) [p1, p0, p9, p40, p2, p3, p4, p29, p16, p5, p6, p45, p10, i46, None] ++652: p50 = getfield_gc(p40, descr=) ++656: guard_isnull(p50, descr=) [p1, p0, p9, p50, p40, p2, p3, p4, p29, p16, p5, p6, p45, p10, i46, None] ++665: p52 = getfield_gc(ConstPtr(ptr51), descr=) ++678: guard_nonnull_class(p52, ConstClass(Function), descr=) [p1, p0, p9, p52, p2, p3, p4, p29, p16, p5, p6, p45, p10, i46, None] +debug_merge_point(1, ' #3 LOAD_FAST') +debug_merge_point(1, ' #6 LOAD_FAST') ++696: guard_nonnull(p45, descr=) [p1, p0, p9, p45, p2, p3, p4, p29, p16, p5, p6, p52, None, p10, i46, None] +debug_merge_point(1, ' #9 CALL_FUNCTION') ++705: p54 = getfield_gc(p52, descr=) ++709: guard_value(p54, ConstPtr(ptr55), descr=) [p1, p0, p9, p54, p52, p2, p3, p4, p29, p16, p5, p6, None, p45, p10, i46, None] ++728: p56 = getfield_gc(p52, descr=) ++732: p57 = getfield_gc(p52, descr=) ++732: p58 = getfield_gc(p52, descr=) ++732: p59 = getfield_gc(p52, descr=) ++732: i60 = force_token() +debug_merge_point(2, ' #0 LOAD_GLOBAL') ++739: guard_value(p56, ConstPtr(ptr61), descr=) [p1, p0, p9, p56, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] ++758: p62 = getfield_gc(p56, descr=) ++762: guard_isnull(p62, descr=) [p1, p0, p9, p62, p56, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] ++771: p64 = getfield_gc(ConstPtr(ptr63), descr=) ++784: guard_isnull(p64, descr=) [p1, p0, p9, p64, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] ++793: p66 = getfield_gc(ConstPtr(ptr65), descr=) ++801: guard_value(p66, ConstPtr(ptr67), descr=) [p1, p0, p9, p66, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] ++814: p68 = getfield_gc(p66, descr=) ++818: guard_isnull(p68, descr=) [p1, p0, p9, p68, p66, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] ++827: p70 = getfield_gc(ConstPtr(ptr69), descr=) ++835: guard_value(p70, ConstPtr(ptr71), descr=) [p1, p0, p9, p70, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] +debug_merge_point(2, ' #3 LOAD_FAST') +debug_merge_point(2, ' #6 LOAD_CONST') +debug_merge_point(2, ' #9 BINARY_SUBSCR') +debug_merge_point(2, ' #10 CALL_FUNCTION') +debug_merge_point(2, ' #13 BUILD_TUPLE') +debug_merge_point(2, ' #16 LOAD_FAST') +debug_merge_point(2, ' #19 BINARY_ADD') +debug_merge_point(2, ' #20 STORE_FAST') +debug_merge_point(2, ' #23 LOAD_GLOBAL') ++848: p73 = getfield_gc(ConstPtr(ptr72), descr=) ++861: guard_nonnull_class(p73, 21003520, descr=) [p1, p0, p9, p73, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] +debug_merge_point(2, ' #26 LOOKUP_METHOD') +debug_merge_point(2, ' #29 LOAD_FAST') +debug_merge_point(2, ' #32 CALL_METHOD') ++880: p76 = getfield_gc(ConstPtr(ptr75), descr=) ++888: guard_not_invalidated(, descr=) [p1, p0, p9, p76, p2, p3, p4, p29, p16, p5, p6, p73, i60, p52, p45, p10, i46, None] ++888: p77 = getfield_gc(p73, descr=) ++892: guard_nonnull(p77, descr=) [p1, p0, p9, p73, p77, p2, p3, p4, p29, p16, p5, p6, None, i60, p52, p45, p10, i46, None] ++901: i78 = force_token() ++908: p80 = new_with_vtable(21002328) ++1013: setfield_gc(p80, i60, descr=) +setfield_gc(p9, p80, descr=) ++1064: setfield_gc(p0, i78, descr=) ++1075: p82 = new_array(3, descr=) ++1153: setarrayitem_gc(p82, 0, ConstPtr(ptr84), descr=) ++1161: setarrayitem_gc(p82, 1, ConstPtr(ptr86), descr=) ++1175: setarrayitem_gc(p82, 2, p45, descr=) ++1186: i89 = call_may_force(ConstClass(hash_tuple), p82, descr=) +guard_not_forced(, descr=) [p1, p0, p9, p73, p77, i89, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p82, p10] ++1252: guard_no_exception(, descr=) [p1, p0, p9, p73, p77, i89, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p82, p10] ++1267: i90 = force_token() ++1274: setfield_gc(p0, i90, descr=) ++1285: p92 = new_with_vtable(21002400) ++1355: setfield_gc(p92, p82, descr=) ++1366: i94 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p77, p92, i89, descr=) +guard_not_forced(, descr=) [p1, p0, p9, p92, p73, i94, p77, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] ++1425: guard_no_exception(, descr=) [p1, p0, p9, p92, p73, i94, p77, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] ++1440: i96 = int_and(i94, -9223372036854775808) ++1456: i97 = int_is_true(i96) +guard_false(i97, descr=) [p1, p0, p9, p92, p73, i94, p77, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] ++1466: p99 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p77, i94, descr=) ++1486: guard_no_exception(, descr=) [p1, p0, p9, p92, p73, p99, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] ++1501: guard_nonnull_class(p99, 21206408, descr=) [p1, p0, p9, p92, p73, p99, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] +debug_merge_point(2, ' #35 STORE_FAST') +debug_merge_point(2, ' #38 LOAD_FAST') +debug_merge_point(2, ' #41 LOAD_CONST') +debug_merge_point(2, ' #44 COMPARE_OP') ++1519: i102 = ptr_eq(p99, ConstPtr(ptr101)) +guard_false(i102, descr=) [p1, p0, p9, p80, p2, p3, p4, p29, p16, p5, p6, p92, p99, p52, i46, p45, p10] +debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') +debug_merge_point(2, ' #50 LOAD_FAST') +debug_merge_point(2, ' #53 RETURN_VALUE') ++1532: p103 = getfield_gc(p9, descr=) ++1543: guard_isnull(p103, descr=) [p1, p0, p9, p99, p103, p80, p2, p3, p4, p29, p16, p5, p6, p92, None, p52, i46, p45, p10] ++1552: i104 = getfield_gc(p9, descr=) ++1556: i105 = int_is_true(i104) +guard_false(i105, descr=) [p1, p0, p9, p99, p80, p2, p3, p4, p29, p16, p5, p6, p92, None, p52, i46, p45, p10] ++1566: p106 = getfield_gc(p9, descr=) +debug_merge_point(1, ' #12 LOOKUP_METHOD') +debug_merge_point(1, ' #15 LOAD_FAST') +debug_merge_point(1, ' #18 CALL_METHOD') ++1566: p108 = getfield_gc(ConstPtr(ptr107), descr=) ++1574: setfield_gc(p80, -3, descr=) ++1589: guard_not_invalidated(, descr=) [p1, p0, p9, p108, p2, p3, p4, p29, p16, p5, p6, None, p99, None, i46, p45, p10] ++1589: p110 = getfield_gc_pure(p16, descr=) ++1600: i111 = strlen(p110) ++1604: i113 = int_gt(9223372036854775807, i111) +guard_true(i113, descr=) [p1, p0, p9, p99, p110, p2, p3, p4, p29, p16, p5, p6, None, None, None, i46, p45, p10] ++1623: p114 = getfield_gc(p99, descr=) ++1627: i115 = getfield_gc(p99, descr=) ++1631: i117 = getarrayitem_gc_pure(p114, 0, descr=) ++1635: i119 = int_eq(i117, 17) +guard_true(i119, descr=) [p1, p0, p9, p99, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] ++1645: i121 = getarrayitem_gc_pure(p114, 2, descr=) ++1649: i123 = int_and(i121, 1) ++1656: i124 = int_is_true(i123) +guard_true(i124, descr=) [p1, p0, p9, p99, i121, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] ++1666: i126 = getarrayitem_gc_pure(p114, 5, descr=) ++1670: i128 = int_gt(i126, 1) +guard_false(i128, descr=) [p1, p0, p9, p99, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] ++1680: i130 = getarrayitem_gc_pure(p114, 1, descr=) ++1684: i132 = int_add(i130, 1) ++1688: i133 = getarrayitem_gc_pure(p114, i132, descr=) ++1693: i135 = int_eq(i133, 19) +guard_true(i135, descr=) [p1, p0, p9, p99, i132, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] ++1703: i137 = int_add(i132, 1) ++1710: i138 = getarrayitem_gc_pure(p114, i137, descr=) ++1715: i140 = int_add(i132, 2) ++1719: i142 = int_lt(0, i111) +guard_true(i142, descr=) [p1, p0, p9, p99, i138, i140, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] ++1729: guard_value(i140, 11, descr=) [p1, p0, p9, p99, i138, i140, p114, p2, p3, p4, p29, p16, p5, p6, None, i111, p110, i115, None, None, None, i46, p45, p10] ++1739: guard_value(i138, 51, descr=) [p1, p0, p9, p99, i138, p114, p2, p3, p4, p29, p16, p5, p6, None, i111, p110, i115, None, None, None, i46, p45, p10] ++1749: guard_value(p114, ConstPtr(ptr145), descr=) [p1, p0, p9, p99, p114, p2, p3, p4, p29, p16, p5, p6, None, i111, p110, i115, None, None, None, i46, p45, p10] +debug_merge_point(2, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') ++1768: i146 = force_token() ++1775: p147 = new_with_vtable(21002328) ++1873: setfield_gc(p147, i46, descr=) +setfield_gc(p9, p147, descr=) ++1913: setfield_gc(p0, i146, descr=) ++1931: p149 = new_with_vtable(21022112) ++2001: setfield_gc(p149, ConstPtr(ptr145), descr=) ++2015: setfield_gc(p149, i115, descr=) ++2026: setfield_gc(p149, p110, descr=) ++2037: setfield_gc(p149, i111, descr=) ++2048: i150 = call_assembler(0, p149, descr=) +guard_not_forced(, descr=) [p1, p0, p9, p99, p149, i150, p147, p2, p3, p4, p29, p16, p5, p6, p45, p10] ++2139: guard_no_exception(, descr=) [p1, p0, p9, p99, p149, i150, p147, p2, p3, p4, p29, p16, p5, p6, p45, p10] ++2154: guard_true(i150, descr=) [p1, p0, p9, p99, p149, p147, p2, p3, p4, p29, p16, p5, p6, p45, p10] +debug_merge_point(1, ' #21 RETURN_VALUE') ++2163: p151 = getfield_gc(p9, descr=) ++2174: guard_isnull(p151, descr=) [p1, p0, p9, p151, p147, p2, p3, p4, p29, p16, p5, p6, p99, p149, p45, p10] ++2183: i152 = getfield_gc(p9, descr=) ++2187: i153 = int_is_true(i152) +guard_false(i153, descr=) [p1, p0, p9, p147, p2, p3, p4, p29, p16, p5, p6, p99, p149, p45, p10] ++2197: p154 = getfield_gc(p9, descr=) +debug_merge_point(0, ' #65 POP_TOP') +debug_merge_point(0, ' #66 JUMP_ABSOLUTE') ++2197: i156 = getfield_raw(40681184, descr=) ++2205: i158 = int_sub(i156, 62) ++2209: setfield_raw(40681184, i158, descr=) +setfield_gc(p9, p10, descr=) ++2260: setfield_gc(p147, -3, descr=) ++2275: i161 = int_lt(i158, 0) +guard_false(i161, descr=) [p1, p0, p2, p3, p4, p5, p6, p16, None, None, None, None] +debug_merge_point(0, ' #44 FOR_ITER') ++2285: jump(p0, p1, p2, p3, p4, p5, p6, p16, i152, p9, p10, descr=) ++2304: --end of the loop-- +[1af179fd9d3c7] jit-log-opt-loop} +[1af17a03f77a7] {jit-log-opt-loop +# Loop 7 : entry bridge with 211 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11, p12, p13, p14, p15] +debug_merge_point(0, ' #44 FOR_ITER') ++362: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] ++372: guard_class(p8, 21011168, descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10, p11, p12, p13, p14, p15] ++384: p18 = getfield_gc(p8, descr=) ++388: guard_nonnull(p18, descr=) [p1, p0, p8, p18, p2, p3, i4, p5, p9, p10, p11, p12, p13, p14, p15] ++397: i19 = getfield_gc(p8, descr=) ++401: i20 = getfield_gc(p18, descr=) ++405: i21 = int_ge(i19, i20) +guard_false(i21, descr=) [p1, p0, p8, i19, p18, p2, p3, i4, p5, p9, p10, p11, p12, p13, p14, p15] ++414: p22 = getfield_gc(p18, descr=) ++418: p23 = getarrayitem_gc(p22, i19, descr=) ++423: i25 = int_add(i19, 1) ++427: setfield_gc(p8, i25, descr=) ++431: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p23, p10, p11, p12, p13, p14, p15] +debug_merge_point(0, ' #47 STORE_FAST') +debug_merge_point(0, ' #50 LOAD_GLOBAL') ++441: guard_value(p3, ConstPtr(ptr27), descr=) [p1, p0, p3, p2, p5, p8, p10, p11, p12, p13, p14, p23] ++460: p28 = getfield_gc(p0, descr=) ++464: guard_value(p28, ConstPtr(ptr29), descr=) [p1, p0, p28, p2, p5, p8, p10, p11, p12, p13, p14, p23] ++483: p30 = getfield_gc(p28, descr=) ++488: guard_isnull(p30, descr=) [p1, p0, p30, p28, p2, p5, p8, p10, p11, p12, p13, p14, p23] ++497: p32 = getfield_gc(ConstPtr(ptr31), descr=) ++510: guard_nonnull_class(p32, 21015776, descr=) [p1, p0, p32, p2, p5, p8, p10, p11, p12, p13, p14, p23] +debug_merge_point(0, ' #53 LOOKUP_METHOD') ++530: p34 = getfield_gc(p32, descr=) ++535: guard_value(p34, ConstPtr(ptr35), descr=) [p1, p0, p32, p34, p2, p5, p8, p10, p11, p12, p13, p14, p23] ++554: p36 = getfield_gc(p34, descr=) ++558: guard_isnull(p36, descr=) [p1, p0, p32, p36, p34, p2, p5, p8, p10, p11, p12, p13, p14, p23] ++567: p38 = getfield_gc(ConstPtr(ptr37), descr=) ++580: guard_nonnull_class(p38, ConstClass(Function), descr=) [p1, p0, p38, p32, p2, p5, p8, p10, p11, p12, p13, p14, p23] +debug_merge_point(0, ' #56 LOAD_CONST') +debug_merge_point(0, ' #59 LOAD_FAST') ++599: guard_nonnull_class(p23, ConstClass(W_StringObject), descr=) [p1, p0, p23, p2, p5, p8, p38, p12, p13, p14] +debug_merge_point(0, ' #62 CALL_METHOD') ++617: p41 = getfield_gc(p38, descr=) ++621: guard_value(p41, ConstPtr(ptr42), descr=) [p1, p0, p41, p38, p2, p5, p8, p23, p13, p14] ++640: p43 = getfield_gc(p38, descr=) ++644: i44 = arraylen_gc(p43, descr=) ++648: i46 = int_sub(3, i44) ++658: i48 = int_ge(2, i46) +guard_true(i48, descr=) [p1, p0, p38, p2, p5, p8, p23, p13, p14] ++668: p49 = getfield_gc(p38, descr=) ++672: p50 = getfield_gc(p38, descr=) ++672: i52 = int_sub(i44, 1) ++679: i53 = int_ge(i52, i44) +guard_false(i53, descr=) [p1, p0, i44, i52, p38, p2, p5, p8, p23, p13, p14, p49] ++688: p54 = getarrayitem_gc_pure(p43, i52, descr=) ++693: p56 = call(ConstClass(getexecutioncontext), descr=) ++738: p57 = getfield_gc(p56, descr=) ++742: i58 = force_token() ++749: p59 = getfield_gc(p56, descr=) ++753: guard_isnull(p59, descr=) [p1, p0, p56, p59, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, p49] ++762: i60 = getfield_gc(p56, descr=) ++766: i61 = int_is_zero(i60) +guard_true(i61, descr=) [p1, p0, p56, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, p49] +debug_merge_point(1, ' #0 LOAD_GLOBAL') ++776: guard_value(p49, ConstPtr(ptr62), descr=) [p1, p0, p56, p49, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, None] ++795: p64 = getfield_gc(p49, descr=) ++800: guard_isnull(p64, descr=) [p1, p0, p56, p64, p49, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, None] ++809: p66 = getfield_gc(ConstPtr(ptr65), descr=) ++822: guard_nonnull_class(p66, ConstClass(Function), descr=) [p1, p0, p56, p66, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, None] +debug_merge_point(1, ' #3 LOAD_FAST') +debug_merge_point(1, ' #6 LOAD_FAST') ++842: guard_nonnull(p54, descr=) [p1, p0, p56, p54, p2, p5, p8, p38, p23, p13, p14, p66, None, i58, p57, None] +debug_merge_point(1, ' #9 CALL_FUNCTION') ++858: p68 = getfield_gc(p66, descr=) ++863: guard_value(p68, ConstPtr(ptr69), descr=) [p1, p0, p56, p68, p66, p2, p5, p8, p38, p23, p13, p14, None, p54, i58, p57, None] ++882: p70 = getfield_gc(p66, descr=) ++887: p71 = getfield_gc(p66, descr=) ++887: p72 = getfield_gc(p66, descr=) ++892: p73 = getfield_gc(p66, descr=) ++897: guard_no_exception(, descr=) [p1, p0, p56, p72, p73, p2, p5, p8, p38, p23, p13, p14, p70, p66, p54, i58, p57, None] ++912: i74 = force_token() +debug_merge_point(2, ' #0 LOAD_GLOBAL') ++919: guard_value(p70, ConstPtr(ptr75), descr=) [p1, p0, p56, p70, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] ++938: p76 = getfield_gc(p70, descr=) ++942: guard_isnull(p76, descr=) [p1, p0, p56, p76, p70, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] ++951: p78 = getfield_gc(ConstPtr(ptr77), descr=) ++964: guard_isnull(p78, descr=) [p1, p0, p56, p78, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] ++973: p80 = getfield_gc(ConstPtr(ptr79), descr=) ++981: guard_value(p80, ConstPtr(ptr81), descr=) [p1, p0, p56, p80, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] ++994: p82 = getfield_gc(p80, descr=) ++998: guard_isnull(p82, descr=) [p1, p0, p56, p82, p80, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] ++1007: p84 = getfield_gc(ConstPtr(ptr83), descr=) ++1015: guard_value(p84, ConstPtr(ptr85), descr=) [p1, p0, p56, p84, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] +debug_merge_point(2, ' #3 LOAD_FAST') +debug_merge_point(2, ' #6 LOAD_CONST') +debug_merge_point(2, ' #9 BINARY_SUBSCR') +debug_merge_point(2, ' #10 CALL_FUNCTION') +debug_merge_point(2, ' #13 BUILD_TUPLE') +debug_merge_point(2, ' #16 LOAD_FAST') +debug_merge_point(2, ' #19 BINARY_ADD') +debug_merge_point(2, ' #20 STORE_FAST') +debug_merge_point(2, ' #23 LOAD_GLOBAL') ++1028: p87 = getfield_gc(ConstPtr(ptr86), descr=) ++1041: guard_nonnull_class(p87, 21003520, descr=) [p1, p0, p56, p87, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] +debug_merge_point(2, ' #26 LOOKUP_METHOD') +debug_merge_point(2, ' #29 LOAD_FAST') +debug_merge_point(2, ' #32 CALL_METHOD') ++1059: p90 = getfield_gc(ConstPtr(ptr89), descr=) ++1067: guard_not_invalidated(, descr=) [p1, p0, p56, p90, p2, p5, p8, p38, p23, p13, p14, p87, i74, None, p66, p54, i58, p57, None] ++1067: p91 = getfield_gc(p87, descr=) ++1071: guard_nonnull(p91, descr=) [p1, p0, p56, p87, p91, p2, p5, p8, p38, p23, p13, p14, None, i74, None, p66, p54, i58, p57, None] ++1080: i92 = force_token() ++1087: p94 = new_with_vtable(21002328) ++1199: setfield_gc(p94, i74, descr=) +setfield_gc(p56, p94, descr=) ++1250: setfield_gc(p0, i92, descr=) ++1261: p96 = new_array(3, descr=) ++1339: setarrayitem_gc(p96, 0, ConstPtr(ptr98), descr=) ++1347: setarrayitem_gc(p96, 1, ConstPtr(ptr100), descr=) ++1361: setarrayitem_gc(p96, 2, p54, descr=) ++1372: i103 = call_may_force(ConstClass(hash_tuple), p96, descr=) +guard_not_forced(, descr=) [p1, p0, p56, p87, p91, i103, p94, p2, p5, p8, p38, p23, p13, p14, p96, p54, i58, p66, p57] ++1445: guard_no_exception(, descr=) [p1, p0, p56, p87, p91, i103, p94, p2, p5, p8, p38, p23, p13, p14, p96, p54, i58, p66, p57] ++1460: i104 = force_token() ++1467: setfield_gc(p0, i104, descr=) ++1479: p106 = new_with_vtable(21002400) ++1549: setfield_gc(p106, p96, descr=) ++1560: i108 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p91, p106, i103, descr=) +guard_not_forced(, descr=) [p1, p0, p56, p106, p87, i108, p91, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] ++1619: guard_no_exception(, descr=) [p1, p0, p56, p106, p87, i108, p91, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] ++1634: i110 = int_and(i108, -9223372036854775808) ++1650: i111 = int_is_true(i110) +guard_false(i111, descr=) [p1, p0, p56, p106, p87, i108, p91, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] ++1660: p113 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p91, i108, descr=) ++1680: guard_no_exception(, descr=) [p1, p0, p56, p106, p87, p113, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] ++1695: guard_nonnull_class(p113, 21206408, descr=) [p1, p0, p56, p106, p87, p113, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] +debug_merge_point(2, ' #35 STORE_FAST') +debug_merge_point(2, ' #38 LOAD_FAST') +debug_merge_point(2, ' #41 LOAD_CONST') +debug_merge_point(2, ' #44 COMPARE_OP') ++1713: i116 = ptr_eq(p113, ConstPtr(ptr115)) +guard_false(i116, descr=) [p1, p0, p56, p94, p2, p5, p8, p38, p23, p13, p14, p113, p106, p54, i58, p66, p57] +debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') +debug_merge_point(2, ' #50 LOAD_FAST') +debug_merge_point(2, ' #53 RETURN_VALUE') ++1726: p117 = getfield_gc(p56, descr=) ++1738: guard_isnull(p117, descr=) [p1, p0, p56, p113, p117, p94, p2, p5, p8, p38, p23, p13, p14, None, p106, p54, i58, p66, p57] ++1747: i118 = getfield_gc(p56, descr=) ++1752: i119 = int_is_true(i118) +guard_false(i119, descr=) [p1, p0, p56, p113, p94, p2, p5, p8, p38, p23, p13, p14, None, p106, p54, i58, p66, p57] ++1762: p120 = getfield_gc(p56, descr=) +debug_merge_point(1, ' #12 LOOKUP_METHOD') +debug_merge_point(1, ' #15 LOAD_FAST') +debug_merge_point(1, ' #18 CALL_METHOD') ++1762: p122 = getfield_gc(ConstPtr(ptr121), descr=) ++1770: setfield_gc(p94, -3, descr=) ++1785: guard_not_invalidated(, descr=) [p1, p0, p56, p122, p2, p5, p8, p38, p23, p13, p14, p113, None, p54, i58, None, p57] ++1785: p124 = getfield_gc_pure(p23, descr=) ++1796: i125 = strlen(p124) ++1800: i127 = int_gt(9223372036854775807, i125) +guard_true(i127, descr=) [p1, p0, p56, p113, p124, p2, p5, p8, p38, p23, p13, p14, None, None, p54, i58, None, p57] ++1819: p128 = getfield_gc(p113, descr=) ++1823: i129 = getfield_gc(p113, descr=) ++1827: i131 = getarrayitem_gc_pure(p128, 0, descr=) ++1831: i133 = int_eq(i131, 17) +guard_true(i133, descr=) [p1, p0, p56, p113, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] ++1841: i135 = getarrayitem_gc_pure(p128, 2, descr=) ++1845: i137 = int_and(i135, 1) ++1852: i138 = int_is_true(i137) +guard_true(i138, descr=) [p1, p0, p56, p113, i135, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] ++1862: i140 = getarrayitem_gc_pure(p128, 5, descr=) ++1866: i142 = int_gt(i140, 1) +guard_false(i142, descr=) [p1, p0, p56, p113, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] ++1876: i144 = getarrayitem_gc_pure(p128, 1, descr=) ++1880: i146 = int_add(i144, 1) ++1884: i147 = getarrayitem_gc_pure(p128, i146, descr=) ++1889: i149 = int_eq(i147, 19) +guard_true(i149, descr=) [p1, p0, p56, p113, i146, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] ++1899: i151 = int_add(i146, 1) ++1906: i152 = getarrayitem_gc_pure(p128, i151, descr=) ++1911: i154 = int_add(i146, 2) ++1915: i156 = int_lt(0, i125) +guard_true(i156, descr=) [p1, p0, p56, p113, i152, i154, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] ++1925: guard_value(i154, 11, descr=) [p1, p0, p56, p113, i152, i154, p128, p2, p5, p8, p38, p23, p13, p14, i129, p124, None, i125, None, None, p54, i58, None, p57] ++1935: guard_value(i152, 51, descr=) [p1, p0, p56, p113, i152, p128, p2, p5, p8, p38, p23, p13, p14, i129, p124, None, i125, None, None, p54, i58, None, p57] ++1945: guard_value(p128, ConstPtr(ptr159), descr=) [p1, p0, p56, p113, p128, p2, p5, p8, p38, p23, p13, p14, i129, p124, None, i125, None, None, p54, i58, None, p57] +debug_merge_point(2, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') ++1964: i160 = force_token() ++1971: p161 = new_with_vtable(21002328) ++2069: setfield_gc(p161, i58, descr=) +setfield_gc(p56, p161, descr=) ++2111: setfield_gc(p0, i160, descr=) ++2129: p163 = new_with_vtable(21022112) ++2199: setfield_gc(p163, ConstPtr(ptr159), descr=) ++2213: setfield_gc(p163, i129, descr=) ++2224: setfield_gc(p163, p124, descr=) ++2235: setfield_gc(p163, i125, descr=) ++2246: i164 = call_assembler(0, p163, descr=) +guard_not_forced(, descr=) [p1, p0, p56, p113, p163, i164, p161, p2, p5, p8, p38, p23, p13, p14, p57, p54] ++2337: guard_no_exception(, descr=) [p1, p0, p56, p113, p163, i164, p161, p2, p5, p8, p38, p23, p13, p14, p57, p54] ++2352: guard_true(i164, descr=) [p1, p0, p56, p113, p163, p161, p2, p5, p8, p38, p23, p13, p14, p57, p54] +debug_merge_point(1, ' #21 RETURN_VALUE') ++2361: p165 = getfield_gc(p56, descr=) ++2372: guard_isnull(p165, descr=) [p1, p0, p56, p165, p161, p2, p5, p8, p38, p23, p13, p14, p113, p163, p57, p54] ++2381: i166 = getfield_gc(p56, descr=) ++2385: i167 = int_is_true(i166) +guard_false(i167, descr=) [p1, p0, p56, p161, p2, p5, p8, p38, p23, p13, p14, p113, p163, p57, p54] ++2395: p168 = getfield_gc(p56, descr=) +debug_merge_point(0, ' #65 POP_TOP') +debug_merge_point(0, ' #66 JUMP_ABSOLUTE') ++2395: i170 = getfield_raw(40681184, descr=) ++2403: i172 = int_sub(i170, 62) ++2407: setfield_raw(40681184, i172, descr=) +setfield_gc(p56, p57, descr=) ++2458: setfield_gc(p161, -3, descr=) ++2473: i175 = int_lt(i172, 0) +guard_false(i175, descr=) [p1, p0, p2, p5, p8, p13, p14, p23, None, None, None, None] +debug_merge_point(0, ' #44 FOR_ITER') ++2483: jump(p0, p1, p2, p5, p8, p13, p14, p23, i166, p56, p57, descr=) ++2625: --end of the loop-- +[1af17a04f8f24] jit-log-opt-loop} +[1af17a0a31f25] {jit-log-opt-bridge +# bridge out of Guard 154 with 18 ops +[p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] +debug_merge_point(1, ' #21 RETURN_VALUE') ++37: p15 = getfield_gc(p2, descr=) ++48: guard_isnull(p15, descr=) [p0, p1, p2, p15, p5, p6, p7, p8, p9, p10, p11, p12, p14, p13] ++57: i16 = getfield_gc(p2, descr=) ++61: i17 = int_is_true(i16) +guard_false(i17, descr=) [p0, p1, p2, p5, p6, p7, p8, p9, p10, p11, p12, p14, p13] ++71: p18 = getfield_gc(p2, descr=) +debug_merge_point(0, ' #65 POP_TOP') +debug_merge_point(0, ' #66 JUMP_ABSOLUTE') ++71: i20 = getfield_raw(40681184, descr=) ++79: i22 = int_sub(i20, 5) ++83: setfield_raw(40681184, i22, descr=) +setfield_gc(p2, p13, descr=) ++125: setfield_gc(p5, -3, descr=) ++140: i25 = int_lt(i22, 0) +guard_false(i25, descr=) [p0, p1, p6, p7, p8, p11, p12, p10, None, None] +debug_merge_point(0, ' #44 FOR_ITER') ++150: jump(p1, p0, p6, ConstPtr(ptr27), 0, p7, 1, 44, p8, ConstPtr(ptr31), ConstPtr(ptr32), ConstPtr(ptr33), ConstPtr(ptr34), p11, p12, p10, descr=) ++278: --end of the loop-- +[1af17a0a4ca6a] jit-log-opt-bridge} +[1af17a0db52b7] {jit-backend-counts +0:4481 +1:4485 +2:0 +3:4281 +4:1965 +5:2 +6:9210 +7:8304 +8:1686 +9:532 +10:1433 +11:1052 +[1af17a0db9523] jit-backend-counts} diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -9,7 +9,8 @@ author_email='fijall at gmail.com', url='http://pypy.org', packages=['_jitviewer'], - scripts=['bin/jitviewer.py'], + scripts=['bin/jitviewer.py', 'bin/qwebview.py'], install_requires=['flask', 'pygments', 'simplejson'], include_package_data=True, - package_data={'': ['templates/*.html', 'static/*']}) + package_data={'': ['templates/*.html', 'static/*']}, + zip_safe=False) From noreply at buildbot.pypy.org Mon Jul 11 17:54:21 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 11 Jul 2011 17:54:21 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: go back to a cppyy demo Message-ID: <20110711155421.C48CB820D2@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45458:309c775aacde Date: 2011-07-11 15:58 +0200 http://bitbucket.org/pypy/pypy/changeset/309c775aacde/ Log: go back to a cppyy demo diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -1,11 +1,14 @@ +import cppyy -try: - import numpy - a = numpy.array(range(10)) - b = a + a + a - print b[3] +import time +import cppyy +lib = cppyy.load_lib("../../module/cppyy/test/example01Dict.so") +cls = cppyy._type_byname('example01') +inst = cls.construct(-17) -except Exception, e: - print "Exception: ", type(e) - print e - +t1 = time.time() +res = 0 +for i in range(10): + res += inst.invoke("addDataToInt", i) +t2 = time.time() +print t2 - t1 From noreply at buildbot.pypy.org Mon Jul 11 17:54:22 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 11 Jul 2011 17:54:22 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: the interface changed Message-ID: <20110711155422.EC897820D2@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45459:7615354fff54 Date: 2011-07-11 17:54 +0200 http://bitbucket.org/pypy/pypy/changeset/7615354fff54/ Log: the interface changed diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -5,10 +5,11 @@ lib = cppyy.load_lib("../../module/cppyy/test/example01Dict.so") cls = cppyy._type_byname('example01') inst = cls.construct(-17) +cppol = cls.get_overload("addDataToInt") t1 = time.time() res = 0 -for i in range(10): - res += inst.invoke("addDataToInt", i) +for i in range(1000000): + res += inst.invoke(cppol, i) t2 = time.time() print t2 - t1 From noreply at buildbot.pypy.org Mon Jul 11 19:01:50 2011 From: noreply at buildbot.pypy.org (wlav) Date: Mon, 11 Jul 2011 19:01:50 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, wlav) make offsets elidable functions for caching Message-ID: <20110711170150.A8238820D2@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45460:09c4ea6784a6 Date: 2011-07-11 08:44 -0700 http://bitbucket.org/pypy/pypy/changeset/09c4ea6784a6/ Log: (arigo, wlav) make offsets elidable functions for caching diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py --- a/pypy/module/cppyy/capi/cint_capi.py +++ b/pypy/module/cppyy/capi/cint_capi.py @@ -19,7 +19,6 @@ include_dirs=[incpath] + rootincpath, includes=["cintcwrapper.h"], library_dirs=rootlibpath, -# libraries=["Core", "Cint"], link_extra=["-lCore", "-lCint"], use_cpp_linker=True, ) @@ -79,11 +78,13 @@ c_is_subtype = rffi.llexternal( "cppyy_is_subtype", [C_TYPEHANDLE, C_TYPEHANDLE], rffi.INT, - compilation_info=eci) + compilation_info=eci, + elidable_function=True) c_base_offset = rffi.llexternal( "cppyy_base_offset", [C_TYPEHANDLE, C_TYPEHANDLE], rffi.SIZE_T, - compilation_info=eci) + compilation_info=eci, + elidable_function=True) c_call_v = rffi.llexternal( diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py --- a/pypy/module/cppyy/capi/reflex_capi.py +++ b/pypy/module/cppyy/capi/reflex_capi.py @@ -78,11 +78,13 @@ c_is_subtype = rffi.llexternal( "cppyy_is_subtype", [C_TYPEHANDLE, C_TYPEHANDLE], rffi.INT, - compilation_info=eci) + compilation_info=eci, + elidable_function=True) c_base_offset = rffi.llexternal( "cppyy_base_offset", [C_TYPEHANDLE, C_TYPEHANDLE], rffi.SIZE_T, - compilation_info=eci) + compilation_info=eci, + elidable_function=True) c_call_v = rffi.llexternal( From noreply at buildbot.pypy.org Mon Jul 11 19:01:51 2011 From: noreply at buildbot.pypy.org (wlav) Date: Mon, 11 Jul 2011 19:01:51 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, wlav) cleanup of array converters Message-ID: <20110711170151.DECA1820D2@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45461:85a563569b81 Date: 2011-07-11 08:45 -0700 http://bitbucket.org/pypy/pypy/changeset/85a563569b81/ Log: (arigo, wlav) cleanup of array converters diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -62,11 +62,20 @@ lltype.free(arg, flavor='raw') -class ArrayTypeConverter(TypeConverter): +class ArrayCache(object): + def __init__(self, space): + self.space = space + def __getattr__(self, name): + if name.startswith('array_'): + typecode = name[len('array_'):] + arr = self.space.interp_w(W_Array, unpack_simple_shape(self.space, self.space.wrap(typecode))) + setattr(self, name, arr) + return arr + raise AttributeError(name) + +class ArrayTypeConverterMixin(object): + _mixin_ = True _immutable = True - _immutable_fields_ = ["size"] - typecode = '' - typesize = 0 # TODO: get sizeof(type) from system def __init__(self, space, array_size): if array_size <= 0: @@ -78,18 +87,20 @@ # read access, so no copy needed address_value = self._get_raw_address(space, w_obj, offset) address = rffi.cast(rffi.UINT, address_value) - arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode))) + cache = space.fromcache(ArrayCache) + arr = getattr(cache, 'array_' + self.typecode) return arr.fromaddress(space, address, self.size) def to_memory(self, space, w_obj, w_value, offset): # copy the full array (uses byte copy for now) address = self._get_raw_address(space, w_obj, offset) - buf = space.interp_w(Buffer, w_value.getslotvalue(2)) + buf = space.buffer_w(w_value) + # TODO: report if too many items given? for i in range(min(self.size*self.typesize, buf.getlength())): address[i] = buf.getitem(i) -class PtrTypeConverter(ArrayTypeConverter): +class PtrTypeConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_ = True def _get_raw_address(self, space, w_obj, offset): @@ -294,22 +305,22 @@ return rffi.cast(rffi.VOIDP, x) -class ShortArrayConverter(ArrayTypeConverter): +class ShortArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'h' typesize = 2 -class LongArrayConverter(ArrayTypeConverter): +class LongArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'l' typesize = 4 -class FloatArrayConverter(ArrayTypeConverter): +class FloatArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'f' typesize = 4 -class DoubleArrayConverter(ArrayTypeConverter): +class DoubleArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'd' typesize = 8 From noreply at buildbot.pypy.org Mon Jul 11 19:01:53 2011 From: noreply at buildbot.pypy.org (wlav) Date: Mon, 11 Jul 2011 19:01:53 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, wlav) allow pointer assignment on data members Message-ID: <20110711170153.15748820D2@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45462:8f72ce65c803 Date: 2011-07-11 09:58 -0700 http://bitbucket.org/pypy/pypy/changeset/8f72ce65c803/ Log: (arigo, wlav) allow pointer assignment on data members diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py --- a/pypy/interpreter/buffer.py +++ b/pypy/interpreter/buffer.py @@ -43,6 +43,9 @@ # May be overridden. No bounds checks. return ''.join([self.getitem(i) for i in range(start, stop, step)]) + def get_raw_address(self): + raise ValueError("no raw buffer") + # __________ app-level support __________ def descr_len(self, space): diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -162,6 +162,9 @@ def setitem(self, index, char): self.data[index] = char + def get_raw_address(self): + return self.data + def make_array(mytype): class W_Array(W_ArrayBase): diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -86,7 +86,7 @@ def from_memory(self, space, w_obj, offset): # read access, so no copy needed address_value = self._get_raw_address(space, w_obj, offset) - address = rffi.cast(rffi.UINT, address_value) + address = rffi.cast(rffi.ULONG, address_value) cache = space.fromcache(ArrayCache) arr = getattr(cache, 'array_' + self.typecode) return arr.fromaddress(space, address, self.size) @@ -100,13 +100,32 @@ address[i] = buf.getitem(i) -class PtrTypeConverter(ArrayTypeConverterMixin, TypeConverter): +class PtrTypeConverter(TypeConverter): _immutable_ = True - def _get_raw_address(self, space, w_obj, offset): - address = TypeConverter._get_raw_address(self, space, w_obj, offset) - ptr2ptr = rffi.cast(rffi.LONGP, address) - return rffi.cast(rffi.CCHARP, ptr2ptr[0]) + def __init__(self, space, array_size): + self.size = sys.maxint + + def from_memory(self, space, w_obj, offset): + # read access, so no copy needed + address_value = self._get_raw_address(space, w_obj, offset) + address = rffi.cast(rffi.ULONGP, address_value) + cache = space.fromcache(ArrayCache) + arr = getattr(cache, 'array_' + self.typecode) + return arr.fromaddress(space, address[0], self.size) + + @jit.dont_look_inside + def to_memory(self, space, w_obj, w_value, offset): + # copy only the pointer value + rawobject = get_rawobject(space, w_obj) + field_address = lltype.direct_ptradd(rawobject, offset) + byteptr = rffi.cast(rffi.CCHARPP, field_address) + buf = space.buffer_w(w_value) + try: + byteptr[0] = buf.get_raw_address() + except ValueError: + raise OperationError(space.w_TypeError, + space.wrap("raw buffer interface not supported")) class VoidConverter(TypeConverter): @@ -331,13 +350,6 @@ typecode = 'h' typesize = 2 - def to_memory(self, space, w_obj, w_value, offset): - # copy only the pointer value - rawobject = get_rawobject(space, w_obj) - byteptr = rffi.cast(rffi.LONGP, rawobject[offset]) - # TODO: now what ... ?? AFAICS, w_value is a pure python list, not an array? -# byteptr[0] = space.unwrap(space.id(w_value.getslotvalue(2))) - class LongPtrConverter(PtrTypeConverter): _immutable_=True typecode = 'l' diff --git a/pypy/module/cppyy/test/test_datatypes.py b/pypy/module/cppyy/test/test_datatypes.py --- a/pypy/module/cppyy/test/test_datatypes.py +++ b/pypy/module/cppyy/test/test_datatypes.py @@ -5,7 +5,7 @@ currpath = py.path.local(__file__).dirpath() shared_lib = str(currpath.join("datatypesDict.so")) -space = gettestobjspace(usemodules=['cppyy']) +space = gettestobjspace(usemodules=['cppyy', 'array']) def setup_module(mod): if sys.platform == 'win32': @@ -178,11 +178,10 @@ for i in range(self.N): assert eval('c.m_%s_array[i]' % names[j]) == b[i] -# TODO: be able to dissect array.array for its pointers -# exec 'c.m_%s_array2 = b' % names[j] # pointer copies -# b[i] = 28 -# for i in range(self.N): -# assert eval('c.m_%s_array2[i]' % names[j]) == b[i] + exec 'c.m_%s_array2 = b' % names[j] # pointer copies + b[i] = 28 + for i in range(self.N): + assert eval('c.m_%s_array2[i]' % names[j]) == b[i] c.destruct() From noreply at buildbot.pypy.org Mon Jul 11 19:01:54 2011 From: noreply at buildbot.pypy.org (wlav) Date: Mon, 11 Jul 2011 19:01:54 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge heads Message-ID: <20110711170154.3C82E820D2@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45463:cc09cf376a35 Date: 2011-07-11 10:01 -0700 http://bitbucket.org/pypy/pypy/changeset/cc09cf376a35/ Log: merge heads diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -1,11 +1,15 @@ +import cppyy -try: - import numpy - a = numpy.array(range(10)) - b = a + a + a - print b[3] +import time +import cppyy +lib = cppyy.load_lib("../../module/cppyy/test/example01Dict.so") +cls = cppyy._type_byname('example01') +inst = cls.construct(-17) +cppol = cls.get_overload("addDataToInt") -except Exception, e: - print "Exception: ", type(e) - print e - +t1 = time.time() +res = 0 +for i in range(1000000): + res += inst.invoke(cppol, i) +t2 = time.time() +print t2 - t1 From noreply at buildbot.pypy.org Mon Jul 11 19:08:35 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 11 Jul 2011 19:08:35 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (hager, cfbolz): this should fix the fast path ffi call again Message-ID: <20110711170835.9A8F6820D2@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45464:156e6910a76d Date: 2011-07-11 19:08 +0200 http://bitbucket.org/pypy/pypy/changeset/156e6910a76d/ Log: (hager, cfbolz): this should fix the fast path ffi call again diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -78,7 +78,7 @@ 'CPPLibrary', ) - at jit.purefunction + at jit.elidable_promote() def get_methptr_getter(handle, method_index): return capi.c_get_methptr_getter(handle, method_index) @@ -125,8 +125,8 @@ raise OperationError(space.w_TypeError, space.wrap("wrong number of args")) if self.arg_converters is None: self._build_converters() - funcptr = jit.hint(self.methgetter, promote=True)(cppthis) - libffi_func = self._get_libffi_func(jit.hint(funcptr, promote=True)) + funcptr = jit.promote(self.methgetter)(cppthis) + libffi_func = self._get_libffi_func(funcptr) if not libffi_func: raise FastCallNotPossible @@ -138,7 +138,7 @@ conv.convert_argument_libffi(space, w_arg, argchain) return self.executor.execute_libffi(space, libffi_func, argchain) - @jit.purefunction + @jit.elidable_promote() def _get_libffi_func(self, funcptr): key = rffi.cast(rffi.LONG, funcptr) if key in self._libffifunc_cache: @@ -353,7 +353,7 @@ def get_method_names(self): return self.space.newlist([self.space.wrap(name) for name in self.methods]) - @jit.purefunction + @jit.elidable_promote() def get_overload(self, name): try: return self.methods[name] @@ -365,7 +365,7 @@ def get_data_member_names(self): return self.space.newlist([self.space.wrap(name) for name in self.data_members]) - @jit.purefunction + @jit.elidable_promote() def get_data_member(self, name): try: return self.data_members[name] From noreply at buildbot.pypy.org Mon Jul 11 19:16:58 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 19:16:58 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: A branch in which to refactor the methods __del__ of W_Roots, Message-ID: <20110711171658.2F71C820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45465:b9ca6b440514 Date: 2011-07-11 19:15 +0200 http://bitbucket.org/pypy/pypy/changeset/b9ca6b440514/ Log: A branch in which to refactor the methods __del__ of W_Roots, making sure that they cannot directly invoke arbitrary Python code. From noreply at buildbot.pypy.org Mon Jul 11 19:16:59 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 19:16:59 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Detect cases were an rpython __del__ method calls "too much". Message-ID: <20110711171659.60496820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45466:b484c65880dc Date: 2011-07-11 11:20 +0200 http://bitbucket.org/pypy/pypy/changeset/b484c65880dc/ Log: Detect cases were an rpython __del__ method calls "too much". "Too much" is undefined so far; it will be "something with a jit_merge_point". diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -482,6 +482,13 @@ key[2:]) cache[key] = s_value + # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass) + try: + graph = self.bookkeeper.position_key[0] + graph.func._dont_reach_me_in_del_ = True + except (TypeError, AttributeError): + pass + return annmodel.s_None def annotate_hooks(self, **kwds_s): diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py --- a/pypy/rpython/lltypesystem/rclass.py +++ b/pypy/rpython/lltypesystem/rclass.py @@ -400,6 +400,7 @@ assert len(s_func.descriptions) == 1 funcdesc, = s_func.descriptions graph = funcdesc.getuniquegraph() + self.check_graph_of_del_does_not_call_too_much(graph) FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void) destrptr = functionptr(FUNCTYPE, graph.name, graph=graph, diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -374,6 +374,35 @@ def can_ll_be_null(self, s_value): return s_value.can_be_none() + def check_graph_of_del_does_not_call_too_much(self, graph): + # RPython-level __del__() methods should not do "too much". + # In the PyPy Python interpreter, they usually do simple things + # like file.__del__() closing the file descriptor; or if they + # want to do more like call an app-level __del__() method, they + # enqueue the object instead, and the actual call is done later. + # + # Here, as a quick way to check "not doing too much", we check + # that from no RPython-level __del__() method we can reach a + # JitDriver. + # + # XXX wrong complexity, but good enough because the set of + # reachable graphs should be small + callgraph = self.rtyper.annotator.translator.callgraph.values() + seen = set([graph]) + while True: + oldlength = len(seen) + for caller, callee in callgraph: + if caller in seen: + seen.add(callee) + if len(seen) == oldlength: + break + for reachable_graph in seen: + if (hasattr(reachable_graph, 'func') and + getattr(reachable_graph.func, '_dont_reach_me_in_del_',False)): + raise TyperError("the RPython-level __del__() method in %r " + "ends up indirectly calling %r" % ( + graph, reachable_graph)) + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops, classcallhop=None): diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -7,6 +7,7 @@ from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.rpython.error import TyperError from pypy.objspace.flow.model import summary class EmptyBase(object): @@ -1021,7 +1022,24 @@ assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] assert destrptra is not None assert destrptrb is not None - + + def test_del_forbidden(self): + class A(object): + def __del__(self): + self.foo() + def foo(self): + self.bar() + def bar(self): + pass + bar._dont_reach_me_in_del_ = True + def f(): + a = A() + a.foo() + a.bar() + t = TranslationContext() + t.buildannotator().build_types(f, []) + py.test.raises(TyperError, t.buildrtyper().specialize) + def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int class FooBar(object): From noreply at buildbot.pypy.org Mon Jul 11 19:17:00 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 19:17:00 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: A test for this part too. Message-ID: <20110711171700.89417820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45467:15f692da1705 Date: 2011-07-11 11:22 +0200 http://bitbucket.org/pypy/pypy/changeset/15f692da1705/ Log: A test for this part too. diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -83,6 +83,9 @@ t, rtyper, fngraph = self.gengraph(fn, [int]) + # added by compute_result_annotation() + assert fn._dont_reach_me_in_del_ == True + def getargs(func): for graph in t.graphs: if getattr(graph, 'func', None) is func: From noreply at buildbot.pypy.org Mon Jul 11 19:17:01 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 19:17:01 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Improve error reporting. Message-ID: <20110711171701.B92E2820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45468:cdd54b72b4d4 Date: 2011-07-11 12:27 +0200 http://bitbucket.org/pypy/pypy/changeset/cdd54b72b4d4/ Log: Improve error reporting. diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -388,20 +388,25 @@ # XXX wrong complexity, but good enough because the set of # reachable graphs should be small callgraph = self.rtyper.annotator.translator.callgraph.values() - seen = set([graph]) + seen = {graph: None} while True: oldlength = len(seen) for caller, callee in callgraph: - if caller in seen: - seen.add(callee) + if caller in seen and callee not in seen: + if (hasattr(callee, 'func') and + getattr(callee.func, '_dont_reach_me_in_del_',False)): + lst = [str(callee)] + g = caller + while g: + lst.append(str(g)) + g = seen.get(g) + lst.append('') + raise TyperError("the RPython-level __del__() method " + "in %r calls:%s" % ( + graph, '\n\t'.join(lst[::-1]))) + seen[callee] = caller if len(seen) == oldlength: break - for reachable_graph in seen: - if (hasattr(reachable_graph, 'func') and - getattr(reachable_graph.func, '_dont_reach_me_in_del_',False)): - raise TyperError("the RPython-level __del__() method in %r " - "ends up indirectly calling %r" % ( - graph, reachable_graph)) # ____________________________________________________________ diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -1038,7 +1038,8 @@ a.bar() t = TranslationContext() t.buildannotator().build_types(f, []) - py.test.raises(TyperError, t.buildrtyper().specialize) + e = py.test.raises(TyperError, t.buildrtyper().specialize) + print e.value def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int From noreply at buildbot.pypy.org Mon Jul 11 19:17:02 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 19:17:02 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Refactor the creation of interp-level __del__ methods, Message-ID: <20110711171702.EC79B820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45469:1605b4011b4d Date: 2011-07-11 14:02 +0200 http://bitbucket.org/pypy/pypy/changeset/1605b4011b4d/ Log: Refactor the creation of interp-level __del__ methods, with a nice interface now. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -165,7 +165,7 @@ space.user_del_action.register_dying_object(self) def _call_builtin_destructor(self): - pass # method overridden in typedef.py + pass # method overridden by builtin_destructor() in typedef.py # hooks that the mapdict implementations needs: def _get_mapdict_map(self): diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,80 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + space = self.space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(W_Level1): + typedef.builtin_destructor(locals(), 'destructormeth', W_Level1) + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1() + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[1]" + # + w_seen = space.newlist([]) + W_Level2() + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.str_w(space.repr(w_seen)) == "[2, 1]" + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[1]" + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[4, 1]" + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[2, 1]" + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[6, 2, 1]" + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -232,17 +232,7 @@ if "del" in features: class Proto(object): - def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) - if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + builtin_destructor(locals(), None, supercls) add(Proto) if "slots" in features: @@ -294,6 +284,47 @@ return w_dict check_new_dictionary._dont_inline_ = True + +def builtin_destructor(loc, methodname, baseclass): + # Destructor logic: + # * if we have none, then the class has no __del__. + # * if we have a "simple" interp-level one, it is just written as a + # __del__. ("simple" destructors may not do too much, e.g. they must + # never call further Python code; this is checked at translation-time) + # * if we have a "complex" interp-level destructor, then we define it in + # a method foo(), followed by + # ``builtin_destructor(locals(), "foo", W_Base)''. + # * if we have an app-level destructor, then typedef.py will also + # call builtin_destructor(). + # In the last two cases, the __del__ just calls _enqueue_for_destruction() + # and executioncontext.UserDelAction does the real job. + + assert '_builtin_destructor_already_called_' not in loc + assert '__del__' not in loc + assert '_call_builtin_destructor' not in loc + + if hasattr(baseclass, '_builtin_destructor_already_called_'): + # builtin_destructor() was already called on the parent + # class, so we don't need to install the __del__ method nor + # call the __del__ method from _call_builtin_destructor() + # (because the parent _call_builtin_destructor() will do it) + parent_del = None + else: + def __del__(self): + self._enqueue_for_destruction(self.space) + loc['__del__'] = __del__ + loc['_builtin_destructor_already_called_'] = True + parent_del = getattr(baseclass, '__del__', None) + + if methodname is not None or parent_del is not None: + def _call_builtin_destructor(self): + if methodname is not None: + getattr(self, methodname)() + if parent_del is not None: + parent_del(self) + baseclass._call_builtin_destructor(self) + loc['_call_builtin_destructor'] = _call_builtin_destructor + # ____________________________________________________________ @specialize.arg(0) From noreply at buildbot.pypy.org Mon Jul 11 19:17:04 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 19:17:04 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Use the nice interface here. Message-ID: <20110711171704.22B73820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45470:717909759edc Date: 2011-07-11 14:02 +0200 http://bitbucket.org/pypy/pypy/changeset/717909759edc/ Log: Use the nice interface here. diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -838,9 +838,9 @@ self.w_writer = None raise - def __del__(self): - self.clear_all_weakrefs() - # Don't call the base __del__: do not close the files! + def destructor(self): + # method overriden to not close the files + pass # forward to reader for method in ['read', 'peek', 'read1', 'readinto', 'readable']: diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -1,7 +1,7 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import ( TypeDef, GetSetProperty, generic_new_descr, descr_get_dict, descr_set_dict, - make_weakref_descr) + make_weakref_descr, builtin_destructor) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError, operationerrfmt from pypy.rlib.rstring import StringBuilder @@ -55,8 +55,7 @@ return True return False - def __del__(self): - self.clear_all_weakrefs() + def destructor(self): space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: @@ -69,6 +68,7 @@ # equally as bad, and potentially more frequent (because of # shutdown issues). pass + builtin_destructor(locals(), 'destructor', Wrappable) def _CLOSED(self): # Use this macro whenever you want to check the internal `closed` From noreply at buildbot.pypy.org Mon Jul 11 19:17:05 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 19:17:05 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Add a method delweakref() in addition to setweakref(), to call Message-ID: <20110711171705.5E522820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45471:6b50cfc3ea43 Date: 2011-07-11 14:22 +0200 http://bitbucket.org/pypy/pypy/changeset/6b50cfc3ea43/ Log: Add a method delweakref() in addition to setweakref(), to call from the destructor. This method should not call arbitrary Python code. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,7 +146,7 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() __already_enqueued_for_destruction = False diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -228,6 +228,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: @@ -661,9 +663,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -10,7 +10,7 @@ class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -434,10 +434,12 @@ def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline - assert (isinstance(weakreflifeline, WeakrefLifeline) or - weakreflifeline is None) + assert isinstance(weakreflifeline, WeakrefLifeline) self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + def delweakref(self): + self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + class ObjectMixin(object): _mixin_ = True def _init_empty(self, map): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -36,6 +36,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None class W_SetObject(W_BaseSetObject): from pypy.objspace.std.settype import set_typedef as typedef diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -171,7 +171,7 @@ obj = c.instantiate() assert obj.getweakref() is None obj.setweakref(space, lifeline1) - obj.setweakref(space, None) + obj.delweakref() diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -532,6 +532,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None # ____________________________________________________________ # Initialization of type objects From noreply at buildbot.pypy.org Mon Jul 11 19:17:06 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 11 Jul 2011 19:17:06 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Pfffff. Message-ID: <20110711171706.8D5F3820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45472:a528c8f27198 Date: 2011-07-11 14:36 +0200 http://bitbucket.org/pypy/pypy/changeset/a528c8f27198/ Log: Pfffff. diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -431,14 +431,17 @@ return None assert isinstance(lifeline, WeakrefLifeline) return lifeline + getweakref._cannot_really_call_random_things_ = True def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline assert isinstance(weakreflifeline, WeakrefLifeline) self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + setweakref._cannot_really_call_random_things_ = True def delweakref(self): self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + delweakref._cannot_really_call_random_things_ = True class ObjectMixin(object): _mixin_ = True diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -393,8 +393,8 @@ oldlength = len(seen) for caller, callee in callgraph: if caller in seen and callee not in seen: - if (hasattr(callee, 'func') and - getattr(callee.func, '_dont_reach_me_in_del_',False)): + func = getattr(callee, 'func', None) + if getattr(func, '_dont_reach_me_in_del_', False): lst = [str(callee)] g = caller while g: @@ -404,6 +404,9 @@ raise TyperError("the RPython-level __del__() method " "in %r calls:%s" % ( graph, '\n\t'.join(lst[::-1]))) + if getattr(func, '_cannot_really_call_random_things_', + False): + continue seen[callee] = caller if len(seen) == oldlength: break From noreply at buildbot.pypy.org Mon Jul 11 23:58:33 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 11 Jul 2011 23:58:33 +0200 (CEST) Subject: [pypy-commit] pypy default: Specialize str.{start, end}swith for char values at the RPython level, this makes long(), and inevitably other stuff generate considerably saner code. Message-ID: <20110711215833.24B08820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45473:740fc1da78ad Date: 2011-07-11 14:58 -0700 http://bitbucket.org/pypy/pypy/changeset/740fc1da78ad/ Log: Specialize str.{start,end}swith for char values at the RPython level, this makes long(), and inevitably other stuff generate considerably saner code. diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -16,27 +16,92 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = int_mod(i6, i10) i17 = int_rshift(i15, 63) i18 = int_and(i10, i17) i19 = int_add(i15, i18) i21 = int_lt(i19, 0) - guard_false(i21, descr=) + guard_false(i21, descr=...) i22 = int_ge(i19, i10) - guard_false(i22, descr=) + guard_false(i22, descr=...) i23 = strgetitem(p11, i19) i24 = int_ge(i19, i12) - guard_false(i24, descr=) + guard_false(i24, descr=...) i25 = unicodegetitem(p13, i19) - guard_not_invalidated(descr=) p27 = newstr(1) strsetitem(p27, 0, i23) p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) - guard_true(i32, descr=) + guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) + + def test_long(self): + def main(n): + import string + i = 1 + while i < n: + i += int(long(string.digits[i % len(string.digits)], 16)) + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i13 = int_eq(i6, -9223372036854775808) + guard_false(i13, descr=...) + i15 = int_mod(i6, i8) + i17 = int_rshift(i15, 63) + i18 = int_and(i8, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i8) + guard_false(i22, descr=...) + i23 = strgetitem(p10, i19) + p25 = newstr(1) + strsetitem(p25, 0, i23) + p28 = call(ConstClass(strip_spaces), p25, descr=) + guard_no_exception(descr=...) + i29 = strlen(p28) + i30 = int_is_true(i29) + guard_true(i30, descr=...) + i32 = int_sub(i29, 1) + i33 = strgetitem(p28, i32) + i35 = int_eq(i33, 108) + guard_false(i35, descr=...) + i37 = int_eq(i33, 76) + guard_false(i37, descr=...) + i39 = strgetitem(p28, 0) + i41 = int_eq(i39, 45) + guard_false(i41, descr=...) + i43 = int_eq(i39, 43) + guard_false(i43, descr=...) + i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=) + guard_false(i43, descr=...) + i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=) + guard_false(i46, descr=...) + p51 = new_with_vtable(21136408) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, 1, descr=) + setfield_gc(p51, 16, descr=) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, i29, descr=) + p55 = call(ConstClass(parse_digit_string), p51, descr=) + guard_no_exception(descr=...) + i57 = call(ConstClass(rbigint.toint), p55, descr=) + guard_no_exception(descr=...) + i58 = int_add_ovf(i6, i57) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) """) \ No newline at end of file diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -486,6 +486,11 @@ return True + def ll_startswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[0] == ch + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) @@ -503,6 +508,11 @@ return True + def ll_endswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[len(s.chars) - 1] == ch + @elidable def ll_find_char(s, ch, start, end): i = start diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -433,7 +433,9 @@ "ll_streq": Meth([self.SELFTYPE_T], Bool), "ll_strcmp": Meth([self.SELFTYPE_T], Signed), "ll_startswith": Meth([self.SELFTYPE_T], Bool), + "ll_startswith_char": Meth([self.CHAR], Bool), "ll_endswith": Meth([self.SELFTYPE_T], Bool), + "ll_endswith_char": Meth([self.CHAR], Bool), "ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed), @@ -1429,10 +1431,18 @@ # NOT_RPYTHON return self._str.startswith(s._str) + def ll_startswith_char(self, s): + # NOT_RPYTHON + return self._str.startswith(s) + def ll_endswith(self, s): # NOT_RPYTHON return self._str.endswith(s._str) + def ll_endswith_char(self, s): + # NOT_RPYTHON + return self._str.endswith(s) + def ll_find(self, s, start, end): # NOT_RPYTHON if start > len(self._str): # workaround to cope with corner case diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py --- a/pypy/rpython/rstr.py +++ b/pypy/rpython/rstr.py @@ -81,16 +81,30 @@ return super(AbstractStringRepr, self).rtype_is_true(hop) def rtype_method_startswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_startswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_startswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_endswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_endswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_endswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_find(self, hop, reverse=False): # XXX binaryop diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -227,6 +227,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_startswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].startswith('o') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_endswith(self): const = self.const def fn(i, j): @@ -238,6 +247,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_endswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].endswith('e') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_find(self): const = self.const def fn(i, j): From noreply at buildbot.pypy.org Tue Jul 12 00:17:00 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 12 Jul 2011 00:17:00 +0200 (CEST) Subject: [pypy-commit] pypy default: (dmalcolm) Make the generated C files' names reflect the Python file they came from. Patch from Dave Malcolm, fijal did most of the review. Message-ID: <20110711221700.4473D820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45474:658bf014477b Date: 2011-07-11 15:16 -0700 http://bitbucket.org/pypy/pypy/changeset/658bf014477b/ Log: (dmalcolm) Make the generated C files' names reflect the Python file they came from. Patch from Dave Malcolm, fijal did most of the review. diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -688,28 +688,54 @@ def getothernodes(self): return self.othernodes[:] + def getbasecfilefornode(self, node, basecname): + # For FuncNode instances, use the python source filename (relative to + # the top directory): + if hasattr(node.obj, 'graph'): + g = node.obj.graph + # Lookup the filename from the function. + # However, not all FunctionGraph objs actually have a "func": + if hasattr(g, 'func'): + if g.filename.endswith('.py'): + localpath = py.path.local(g.filename) + pypkgpath = localpath.pypkgpath() + if pypkgpath: + relpypath = localpath.relto(pypkgpath) + return relpypath.replace('.py', '.c') + return basecname + def splitnodesimpl(self, basecname, nodes, nextra, nbetween, split_criteria=SPLIT_CRITERIA): + # Gather nodes by some criteria: + nodes_by_base_cfile = {} + for node in nodes: + c_filename = self.getbasecfilefornode(node, basecname) + if c_filename in nodes_by_base_cfile: + nodes_by_base_cfile[c_filename].append(node) + else: + nodes_by_base_cfile[c_filename] = [node] + # produce a sequence of nodes, grouped into files # which have no more than SPLIT_CRITERIA lines - iternodes = iter(nodes) - done = [False] - def subiter(): - used = nextra - for node in iternodes: - impl = '\n'.join(list(node.implementation())).split('\n') - if not impl: - continue - cost = len(impl) + nbetween - yield node, impl - del impl - if used + cost > split_criteria: - # split if criteria met, unless we would produce nothing. - raise StopIteration - used += cost - done[0] = True - while not done[0]: - yield self.uniquecname(basecname), subiter() + for basecname in nodes_by_base_cfile: + iternodes = iter(nodes_by_base_cfile[basecname]) + done = [False] + def subiter(): + used = nextra + for node in iternodes: + impl = '\n'.join(list(node.implementation())).split('\n') + if not impl: + continue + cost = len(impl) + nbetween + yield node, impl + del impl + if used + cost > split_criteria: + # split if criteria met, unless we would produce nothing. + raise StopIteration + used += cost + done[0] = True + while not done[0]: + yield self.uniquecname(basecname), subiter() def gen_readable_parts_of_source(self, f): split_criteria_big = SPLIT_CRITERIA diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -55,6 +55,13 @@ data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + # Verify that the generated C files have sane names: + gen_c_files = [str(f) for f in cbuilder.extrafiles] + for expfile in ('rlib_rposix.c', + 'rpython_lltypesystem_rstr.c', + 'translator_c_test_test_standalone.c'): + assert cbuilder.targetdir.join(expfile) in gen_c_files + def test_print(self): def entry_point(argv): print "hello simpler world" From noreply at buildbot.pypy.org Tue Jul 12 00:32:40 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 12 Jul 2011 00:32:40 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: look into this function Message-ID: <20110711223240.C637A820D2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45475:f9f66c11aa58 Date: 2011-07-10 16:08 +0200 http://bitbucket.org/pypy/pypy/changeset/f9f66c11aa58/ Log: look into this function diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -874,7 +874,6 @@ global_popitem_index.nextindex = base + counter return i - at jit.dont_look_inside def ll_popitem(ELEM, dic): i = _ll_getnextitem(dic) entry = dic.entries[i] From noreply at buildbot.pypy.org Tue Jul 12 00:32:41 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 12 Jul 2011 00:32:41 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: remove debug print Message-ID: <20110711223241.ECA44820D2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45476:82f517037060 Date: 2011-07-10 16:08 +0200 http://bitbucket.org/pypy/pypy/changeset/82f517037060/ Log: remove debug print diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -21,7 +21,6 @@ continue if hasattr(Class, name_prefix + name): opclass = resoperation.opclasses[getattr(rop, name)] - print value, name, opclass result.append((value, opclass, getattr(Class, name_prefix + name))) return unrolling_iterable(result) From noreply at buildbot.pypy.org Tue Jul 12 00:32:43 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 12 Jul 2011 00:32:43 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: oops Message-ID: <20110711223243.20571820D2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45477:f65004e89b4d Date: 2011-07-10 16:09 +0200 http://bitbucket.org/pypy/pypy/changeset/f65004e89b4d/ Log: oops diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -3,7 +3,7 @@ class DebugState(object): def __init__(self): - self.prefixes = os.environ.get('PYPYDEFAULTLOG', 'all').split(':') + self.prefixes = os.environ.get('PYPYDEFAULTLOG', 'all').split(',') if self.prefixes == ['']: self.prefixes = [] self.categories = [] From noreply at buildbot.pypy.org Tue Jul 12 00:32:44 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 12 Jul 2011 00:32:44 +0200 (CEST) Subject: [pypy-commit] pypy default: (justinpeel, fijal) Reduce-like functions for micronumpy Message-ID: <20110711223244.50534820D2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45478:516f5a4af65d Date: 2011-07-12 00:31 +0200 http://bitbucket.org/pypy/pypy/changeset/516f5a4af65d/ Log: (justinpeel, fijal) Reduce-like functions for micronumpy diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.error import operationerrfmt, OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit @@ -49,6 +49,14 @@ return math.pow(v1, v2) def mod(v1, v2): return math.fmod(v1, v2) +def maximum(v1, v2): + return max(v1, v2) +def minimum(v1, v2): + return min(v1, v2) +def and_bool(v1, v2): + return v1 and bool(v2) +def or_bool(v1, v2): + return v1 or bool(v2) class BaseArray(Wrappable): def __init__(self): @@ -110,6 +118,129 @@ descr_pow = _binop_impl(pow) descr_mod = _binop_impl(mod) + def _reduce_sum_prod_impl(function, init): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + return space.wrap(loop(self, init, self.find_size())) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_max_min_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, result, size): + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, self.eval(0), size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_argmax_argmin_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self']) + def loop(self, size): + result = 0 + cur_best = self.eval(0) + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + new_best = function(cur_best, self.eval(i)) + if new_best != cur_best: + result = i + cur_best = new_best + i += 1 + return result + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, size)) + return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) + + def _reduce_all_impl(): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self']) + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = and_bool(result, self.eval(i)) + if not result: + break + i += 1 + return result + + def impl(self, space): + size = self.find_size() + return space.wrap(loop(self, True, size)) + return func_with_new_name(impl, "reduce_all_impl") + + def _reduce_any_impl(): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = or_bool(result, self.eval(i)) + if result: + break + i += 1 + return result + def impl(self, space): + size = self.find_size() + return space.wrap(loop(self, False, size)) + return func_with_new_name(impl, "reduce_any_impl") + + descr_sum = _reduce_sum_prod_impl(add, 0.0) + descr_prod = _reduce_sum_prod_impl(mul, 1.0) + descr_max = _reduce_max_min_impl(maximum) + descr_min = _reduce_max_min_impl(minimum) + descr_argmax = _reduce_argmax_argmin_impl(maximum) + descr_argmin = _reduce_argmax_argmin_impl(minimum) + descr_all = _reduce_all_impl() + descr_any = _reduce_any_impl() + + def descr_dot(self, space, w_other): + if isinstance(w_other, BaseArray): + w_res = self.descr_mul(space, w_other) + assert isinstance(w_res, BaseArray) + return w_res.descr_sum(space) + else: + return self.descr_mul(space, w_other) + def get_concrete(self): raise NotImplementedError @@ -136,13 +267,7 @@ return self.get_concrete().descr_setitem(space, item, value) def descr_mean(self, space): - s = 0 - concrete = self.get_concrete() - size = concrete.find_size() - for i in xrange(size): - s += concrete.getitem(i) - return space.wrap(s / size) - + return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) class FloatWrapper(BaseArray): """ @@ -391,4 +516,13 @@ __mod__ = interp2app(BaseArray.descr_mod), mean = interp2app(BaseArray.descr_mean), + sum = interp2app(BaseArray.descr_sum), + prod = interp2app(BaseArray.descr_prod), + max = interp2app(BaseArray.descr_max), + min = interp2app(BaseArray.descr_min), + argmax = interp2app(BaseArray.descr_argmax), + argmin = interp2app(BaseArray.descr_argmin), + all = interp2app(BaseArray.descr_all), + any = interp2app(BaseArray.descr_any), + dot = interp2app(BaseArray.descr_dot), ) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -282,12 +282,88 @@ assert a.mean() == 2.0 assert a[:4].mean() == 1.5 + def test_sum(self): + from numpy import array + a = array(range(5)) + assert a.sum() == 10.0 + assert a[:4].sum() == 6.0 + + def test_prod(self): + from numpy import array + a = array(range(1,6)) + assert a.prod() == 120.0 + assert a[:4].prod() == 24.0 + + def test_max(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.max() == 5.7 + b = array([]) + raises(ValueError, "b.max()") + + def test_max_add(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert (a+a).max() == 11.4 + + def test_min(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.min() == -3.0 + b = array([]) + raises(ValueError, "b.min()") + + def test_argmax(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmax() == 2 + b = array([]) + raises(ValueError, "b.argmax()") + + def test_argmin(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmin() == 3 + b = array([]) + raises(ValueError, "b.argmin()") + + def test_all(self): + from numpy import array + a = array(range(5)) + assert a.all() == False + a[0] = 3.0 + assert a.all() == True + b = array([]) + assert b.all() == True + + def test_any(self): + from numpy import array, zeros + a = array(range(5)) + assert a.any() == True + b = zeros(5) + assert b.any() == False + c = array([]) + assert c.any() == False + + def test_dot(self): + from numpy import array + a = array(range(5)) + assert a.dot(a) == 30.0 + + def test_dot_constant(self): + from numpy import array + a = array(range(5)) + b = a.dot(2.5) + for i in xrange(5): + assert b[i] == 2.5*a[i] + + class AppTestSupport(object): def setup_class(cls): import struct cls.space = gettestobjspace(usemodules=('micronumpy',)) cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) - + def test_fromstring(self): from numpy import fromstring a = fromstring(self.data) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -4,9 +4,13 @@ FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile +from pypy.rlib.objectmodel import specialize class FakeSpace(object): - pass + w_ValueError = None + @specialize.argtype(1) + def wrap(self, v): + return v class TestNumpyJIt(LLJitMixin): def setup_class(cls): @@ -51,6 +55,93 @@ assert result == f(5) + def test_sum(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_sum(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 2, + "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_prod(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_prod(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_max(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_max(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_gt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, + "guard_false": 1, "jump": 1}) + + def test_min(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_min(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_all(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = 1.0 + j += 1 + return ar.descr_add(space, ar).descr_all(space) + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, + "int_lt": 1, "guard_true": 2, "jump": 1}) + + def test_any(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_any(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, "guard_false": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + def test_already_forecd(self): def f(i): ar = SingleDimArray(i) From noreply at buildbot.pypy.org Tue Jul 12 00:32:45 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 12 Jul 2011 00:32:45 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110711223245.87052820D2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45479:ac574f367d2e Date: 2011-07-12 00:32 +0200 http://bitbucket.org/pypy/pypy/changeset/ac574f367d2e/ Log: merge diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -16,27 +16,92 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = int_mod(i6, i10) i17 = int_rshift(i15, 63) i18 = int_and(i10, i17) i19 = int_add(i15, i18) i21 = int_lt(i19, 0) - guard_false(i21, descr=) + guard_false(i21, descr=...) i22 = int_ge(i19, i10) - guard_false(i22, descr=) + guard_false(i22, descr=...) i23 = strgetitem(p11, i19) i24 = int_ge(i19, i12) - guard_false(i24, descr=) + guard_false(i24, descr=...) i25 = unicodegetitem(p13, i19) - guard_not_invalidated(descr=) p27 = newstr(1) strsetitem(p27, 0, i23) p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) - guard_true(i32, descr=) + guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) + + def test_long(self): + def main(n): + import string + i = 1 + while i < n: + i += int(long(string.digits[i % len(string.digits)], 16)) + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i13 = int_eq(i6, -9223372036854775808) + guard_false(i13, descr=...) + i15 = int_mod(i6, i8) + i17 = int_rshift(i15, 63) + i18 = int_and(i8, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i8) + guard_false(i22, descr=...) + i23 = strgetitem(p10, i19) + p25 = newstr(1) + strsetitem(p25, 0, i23) + p28 = call(ConstClass(strip_spaces), p25, descr=) + guard_no_exception(descr=...) + i29 = strlen(p28) + i30 = int_is_true(i29) + guard_true(i30, descr=...) + i32 = int_sub(i29, 1) + i33 = strgetitem(p28, i32) + i35 = int_eq(i33, 108) + guard_false(i35, descr=...) + i37 = int_eq(i33, 76) + guard_false(i37, descr=...) + i39 = strgetitem(p28, 0) + i41 = int_eq(i39, 45) + guard_false(i41, descr=...) + i43 = int_eq(i39, 43) + guard_false(i43, descr=...) + i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=) + guard_false(i43, descr=...) + i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=) + guard_false(i46, descr=...) + p51 = new_with_vtable(21136408) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, 1, descr=) + setfield_gc(p51, 16, descr=) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, i29, descr=) + p55 = call(ConstClass(parse_digit_string), p51, descr=) + guard_no_exception(descr=...) + i57 = call(ConstClass(rbigint.toint), p55, descr=) + guard_no_exception(descr=...) + i58 = int_add_ovf(i6, i57) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) """) \ No newline at end of file diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -486,6 +486,11 @@ return True + def ll_startswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[0] == ch + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) @@ -503,6 +508,11 @@ return True + def ll_endswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[len(s.chars) - 1] == ch + @elidable def ll_find_char(s, ch, start, end): i = start diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -433,7 +433,9 @@ "ll_streq": Meth([self.SELFTYPE_T], Bool), "ll_strcmp": Meth([self.SELFTYPE_T], Signed), "ll_startswith": Meth([self.SELFTYPE_T], Bool), + "ll_startswith_char": Meth([self.CHAR], Bool), "ll_endswith": Meth([self.SELFTYPE_T], Bool), + "ll_endswith_char": Meth([self.CHAR], Bool), "ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed), @@ -1429,10 +1431,18 @@ # NOT_RPYTHON return self._str.startswith(s._str) + def ll_startswith_char(self, s): + # NOT_RPYTHON + return self._str.startswith(s) + def ll_endswith(self, s): # NOT_RPYTHON return self._str.endswith(s._str) + def ll_endswith_char(self, s): + # NOT_RPYTHON + return self._str.endswith(s) + def ll_find(self, s, start, end): # NOT_RPYTHON if start > len(self._str): # workaround to cope with corner case diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py --- a/pypy/rpython/rstr.py +++ b/pypy/rpython/rstr.py @@ -81,16 +81,30 @@ return super(AbstractStringRepr, self).rtype_is_true(hop) def rtype_method_startswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_startswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_startswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_endswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_endswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_endswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_find(self, hop, reverse=False): # XXX binaryop diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -227,6 +227,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_startswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].startswith('o') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_endswith(self): const = self.const def fn(i, j): @@ -238,6 +247,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_endswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].endswith('e') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_find(self): const = self.const def fn(i, j): diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -688,28 +688,54 @@ def getothernodes(self): return self.othernodes[:] + def getbasecfilefornode(self, node, basecname): + # For FuncNode instances, use the python source filename (relative to + # the top directory): + if hasattr(node.obj, 'graph'): + g = node.obj.graph + # Lookup the filename from the function. + # However, not all FunctionGraph objs actually have a "func": + if hasattr(g, 'func'): + if g.filename.endswith('.py'): + localpath = py.path.local(g.filename) + pypkgpath = localpath.pypkgpath() + if pypkgpath: + relpypath = localpath.relto(pypkgpath) + return relpypath.replace('.py', '.c') + return basecname + def splitnodesimpl(self, basecname, nodes, nextra, nbetween, split_criteria=SPLIT_CRITERIA): + # Gather nodes by some criteria: + nodes_by_base_cfile = {} + for node in nodes: + c_filename = self.getbasecfilefornode(node, basecname) + if c_filename in nodes_by_base_cfile: + nodes_by_base_cfile[c_filename].append(node) + else: + nodes_by_base_cfile[c_filename] = [node] + # produce a sequence of nodes, grouped into files # which have no more than SPLIT_CRITERIA lines - iternodes = iter(nodes) - done = [False] - def subiter(): - used = nextra - for node in iternodes: - impl = '\n'.join(list(node.implementation())).split('\n') - if not impl: - continue - cost = len(impl) + nbetween - yield node, impl - del impl - if used + cost > split_criteria: - # split if criteria met, unless we would produce nothing. - raise StopIteration - used += cost - done[0] = True - while not done[0]: - yield self.uniquecname(basecname), subiter() + for basecname in nodes_by_base_cfile: + iternodes = iter(nodes_by_base_cfile[basecname]) + done = [False] + def subiter(): + used = nextra + for node in iternodes: + impl = '\n'.join(list(node.implementation())).split('\n') + if not impl: + continue + cost = len(impl) + nbetween + yield node, impl + del impl + if used + cost > split_criteria: + # split if criteria met, unless we would produce nothing. + raise StopIteration + used += cost + done[0] = True + while not done[0]: + yield self.uniquecname(basecname), subiter() def gen_readable_parts_of_source(self, f): split_criteria_big = SPLIT_CRITERIA diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -55,6 +55,13 @@ data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + # Verify that the generated C files have sane names: + gen_c_files = [str(f) for f in cbuilder.extrafiles] + for expfile in ('rlib_rposix.c', + 'rpython_lltypesystem_rstr.c', + 'translator_c_test_test_standalone.c'): + assert cbuilder.targetdir.join(expfile) in gen_c_files + def test_print(self): def entry_point(argv): print "hello simpler world" From noreply at buildbot.pypy.org Tue Jul 12 00:47:06 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:47:06 +0200 (CEST) Subject: [pypy-commit] pypy default: Added sum, prod, max, mul, all, any, and dot to micronumpy Message-ID: <20110711224706.D7EBB820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45480:f3254e205395 Date: 2011-07-10 16:31 -0600 http://bitbucket.org/pypy/pypy/changeset/f3254e205395/ Log: Added sum, prod, max, mul, all, any, and dot to micronumpy diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.error import operationerrfmt, OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit @@ -49,6 +49,14 @@ return math.pow(v1, v2) def mod(v1, v2): return math.fmod(v1, v2) +def maximum(v1, v2): + return max(v1, v2) +def minimum(v1, v2): + return min(v1, v2) +def and_bool(v1, v2): + return v1 and bool(v2) +def or_bool(v1, v2): + return v1 or bool(v2) class BaseArray(Wrappable): def __init__(self): @@ -110,6 +118,90 @@ descr_pow = _binop_impl(pow) descr_mod = _binop_impl(mod) + def _reduce_sum_prod_impl(function, init): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + return space.wrap(loop(self, init, self.find_size())) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_max_min_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, result, size): + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, self.eval(0), size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_any_all_impl(function, init, cond): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self']) + def loop(self, result, size): + i = 0 + if cond: + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + if result: + break + i += 1 + else: + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + if not result: + break + i += 1 + return result + + def impl(self, space): + size = self.find_size() + return space.wrap(loop(self, init, size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + descr_sum = _reduce_sum_prod_impl(add, 0.0) + descr_prod = _reduce_sum_prod_impl(mul, 1.0) + descr_max = _reduce_max_min_impl(maximum) + descr_min = _reduce_max_min_impl(minimum) + descr_all = _reduce_any_all_impl(and_bool, True, False) + descr_any = _reduce_any_all_impl(or_bool, False, True) + + def descr_dot(self, space, w_other): + if isinstance(w_other, BaseArray): + return self.descr_mul(space, w_other).descr_sum(space) + else: + w_other = FloatWrapper(space.float_w(w_other)) + return self.descr_mul(space, w_other) + def get_concrete(self): raise NotImplementedError @@ -391,4 +483,11 @@ __mod__ = interp2app(BaseArray.descr_mod), mean = interp2app(BaseArray.descr_mean), + sum = interp2app(BaseArray.descr_sum), + prod = interp2app(BaseArray.descr_prod), + max = interp2app(BaseArray.descr_max), + min = interp2app(BaseArray.descr_min), + all = interp2app(BaseArray.descr_all), + any = interp2app(BaseArray.descr_any), + dot = interp2app(BaseArray.descr_dot), ) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -282,12 +282,74 @@ assert a.mean() == 2.0 assert a[:4].mean() == 1.5 + def test_sum(self): + from numpy import array + a = array(range(5)) + assert a.sum() == 10.0 + assert a[:4].sum() == 6.0 + + def test_prod(self): + from numpy import array + a = array(range(1,6)) + assert a.prod() == 120.0 + assert a[:4].prod() == 24.0 + + def test_max(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.max() == 5.7 + b = array([]) + raises(ValueError, "b.max()") + + def test_max_add(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert (a+a).max() == 11.4 + + def test_min(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.min() == -3.0 + b = array([]) + raises(ValueError, "b.min()") + + def test_all(self): + from numpy import array + a = array(range(5)) + assert a.all() == False + a[0] = 3.0 + assert a.all() == True + b = array([]) + assert b.all() == True + + def test_any(self): + from numpy import array, zeros + a = array(range(5)) + assert a.any() == True + b = zeros(5) + assert b.any() == False + c = array([]) + assert c.any() == False + + def test_dot(self): + from numpy import array + a = array(range(5)) + assert a.dot(a) == 30.0 + + def test_dot_constant(self): + from numpy import array + a = array(range(5)) + b = a.dot(2.5) + for i in xrange(5): + assert b[i] == 2.5*a[i] + + class AppTestSupport(object): def setup_class(cls): import struct cls.space = gettestobjspace(usemodules=('micronumpy',)) cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) - + def test_fromstring(self): from numpy import fromstring a = fromstring(self.data) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -4,9 +4,13 @@ FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile +from pypy.rlib.objectmodel import specialize class FakeSpace(object): - pass + w_ValueError = None + @specialize.argtype(1) + def wrap(self, v): + return v class TestNumpyJIt(LLJitMixin): def setup_class(cls): @@ -51,6 +55,93 @@ assert result == f(5) + def test_sum(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_sum(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 2, + "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_prod(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_prod(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_max(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_max(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_gt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, + "guard_false": 1, "jump": 1}) + + def test_min(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_min(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_all(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = 1.0 + j += 1 + return ar.descr_add(space, ar).descr_all(space) + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, + "int_lt": 1, "guard_true": 2, "jump": 1}) + + def test_any(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_any(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, "guard_false": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + def test_already_forecd(self): def f(i): ar = SingleDimArray(i) From noreply at buildbot.pypy.org Tue Jul 12 00:47:08 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:47:08 +0200 (CEST) Subject: [pypy-commit] pypy default: Fixed a line in numpy array's dot method Message-ID: <20110711224708.0BAB3820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45481:d16e590f593a Date: 2011-07-10 23:26 -0600 http://bitbucket.org/pypy/pypy/changeset/d16e590f593a/ Log: Fixed a line in numpy array's dot method diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -199,7 +199,6 @@ if isinstance(w_other, BaseArray): return self.descr_mul(space, w_other).descr_sum(space) else: - w_other = FloatWrapper(space.float_w(w_other)) return self.descr_mul(space, w_other) def get_concrete(self): From noreply at buildbot.pypy.org Tue Jul 12 00:47:09 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:47:09 +0200 (CEST) Subject: [pypy-commit] pypy default: Added radd, rsub, rmul, rdiv, rpow, rmod to numpy arrays Message-ID: <20110711224709.357EF820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45482:6eb35289ed58 Date: 2011-07-10 23:32 -0600 http://bitbucket.org/pypy/pypy/changeset/6eb35289ed58/ Log: Added radd, rsub, rmul, rdiv, rpow, rmod to numpy arrays diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -45,7 +45,7 @@ return v1 * v2 def div(v1, v2): return v1 / v2 -def pow(v1, v2): +def power(v1, v2): return math.pow(v1, v2) def mod(v1, v2): return math.fmod(v1, v2) @@ -115,9 +115,32 @@ descr_sub = _binop_impl(sub) descr_mul = _binop_impl(mul) descr_div = _binop_impl(div) - descr_pow = _binop_impl(pow) + descr_pow = _binop_impl(power) descr_mod = _binop_impl(mod) + def _binop_right_impl(function): + signature = Signature() + def impl(self, space, w_other): + new_sig = self.signature.transition(signature) + w_other = FloatWrapper(space.float_w(w_other)) + res = Call2( + function, + w_other, + self, + new_sig.transition(w_other.signature) + ) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, + "binop_right_%s_impl" % function.__name__) + + descr_radd = _binop_right_impl(add) + descr_rsub = _binop_right_impl(sub) + descr_rmul = _binop_right_impl(mul) + descr_rdiv = _binop_right_impl(div) + descr_rpow = _binop_right_impl(power) + descr_rmod = _binop_right_impl(mod) + def _reduce_sum_prod_impl(function, init): reduce_driver = jit.JitDriver(greens=['signature'], reds = ['i', 'size', 'self', 'result']) @@ -480,6 +503,12 @@ __div__ = interp2app(BaseArray.descr_div), __pow__ = interp2app(BaseArray.descr_pow), __mod__ = interp2app(BaseArray.descr_mod), + __radd__ = interp2app(BaseArray.descr_radd), + __rsub__ = interp2app(BaseArray.descr_rsub), + __rmul__ = interp2app(BaseArray.descr_rmul), + __rdiv__ = interp2app(BaseArray.descr_rdiv), + __rpow__ = interp2app(BaseArray.descr_rpow), + __rmod__ = interp2app(BaseArray.descr_rmod), mean = interp2app(BaseArray.descr_mean), sum = interp2app(BaseArray.descr_sum), From noreply at buildbot.pypy.org Tue Jul 12 00:47:10 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:47:10 +0200 (CEST) Subject: [pypy-commit] pypy default: Separated the any/all reduce functions for numpy arrays Message-ID: <20110711224710.5C1FF820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45483:b81b9f3ab263 Date: 2011-07-11 08:12 -0600 http://bitbucket.org/pypy/pypy/changeset/b81b9f3ab263/ Log: Separated the any/all reduce functions for numpy arrays diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -181,42 +181,52 @@ return space.wrap(loop(self, self.eval(0), size)) return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) - def _reduce_any_all_impl(function, init, cond): + def _reduce_all_impl(function, init, cond): reduce_driver = jit.JitDriver(greens=['signature'], reds = ['i', 'size', 'result', 'self']) def loop(self, result, size): i = 0 - if cond: - while i < size: - reduce_driver.jit_merge_point(signature=self.signature, - self=self, size=size, i=i, - result=result) - result = function(result, self.eval(i)) - if result: - break - i += 1 - else: - while i < size: - reduce_driver.jit_merge_point(signature=self.signature, - self=self, size=size, i=i, - result=result) - result = function(result, self.eval(i)) - if not result: - break - i += 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + if not result: + break + i += 1 return result def impl(self, space): size = self.find_size() return space.wrap(loop(self, init, size)) - return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + return func_with_new_name(impl, "reduce_all_impl") + + def _reduce_any_impl(function, init, cond): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + if result: + break + i += 1 + return result + def impl(self, space): + size = self.find_size() + return space.wrap(loop(self, init, size)) + return func_with_new_name(impl, "reduce_any_impl") descr_sum = _reduce_sum_prod_impl(add, 0.0) descr_prod = _reduce_sum_prod_impl(mul, 1.0) descr_max = _reduce_max_min_impl(maximum) descr_min = _reduce_max_min_impl(minimum) - descr_all = _reduce_any_all_impl(and_bool, True, False) - descr_any = _reduce_any_all_impl(or_bool, False, True) + descr_all = _reduce_all_impl(and_bool, True, False) + descr_any = _reduce_any_impl(or_bool, False, True) def descr_dot(self, space, w_other): if isinstance(w_other, BaseArray): From noreply at buildbot.pypy.org Tue Jul 12 00:47:11 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:47:11 +0200 (CEST) Subject: [pypy-commit] pypy default: Merged Message-ID: <20110711224711.8C18E820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45484:5bb6fa8dff1c Date: 2011-07-11 08:33 -0600 http://bitbucket.org/pypy/pypy/changeset/5bb6fa8dff1c/ Log: Merged diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4511,6 +4511,25 @@ """ self.optimize_loop(ops, expected) + def test_strslice_with_other_stuff(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -667,7 +667,6 @@ res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res -ll_pop.oopspec = 'list.pop(l, index)' def ll_reverse(l): length = l.ll_length() From noreply at buildbot.pypy.org Tue Jul 12 00:47:12 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:47:12 +0200 (CEST) Subject: [pypy-commit] pypy default: Simplified the any and all implementations Message-ID: <20110711224712.B1A04820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45485:81ace3ddd0b1 Date: 2011-07-11 09:16 -0600 http://bitbucket.org/pypy/pypy/changeset/81ace3ddd0b1/ Log: Simplified the any and all implementations diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -181,7 +181,7 @@ return space.wrap(loop(self, self.eval(0), size)) return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) - def _reduce_all_impl(function, init, cond): + def _reduce_all_impl(): reduce_driver = jit.JitDriver(greens=['signature'], reds = ['i', 'size', 'result', 'self']) def loop(self, result, size): @@ -190,7 +190,7 @@ reduce_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i, result=result) - result = function(result, self.eval(i)) + result = and_bool(result, self.eval(i)) if not result: break i += 1 @@ -198,10 +198,10 @@ def impl(self, space): size = self.find_size() - return space.wrap(loop(self, init, size)) + return space.wrap(loop(self, True, size)) return func_with_new_name(impl, "reduce_all_impl") - def _reduce_any_impl(function, init, cond): + def _reduce_any_impl(): reduce_driver = jit.JitDriver(greens=['signature'], reds = ['i', 'size', 'result', 'self']) @@ -211,22 +211,22 @@ reduce_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i, result=result) - result = function(result, self.eval(i)) + result = or_bool(result, self.eval(i)) if result: break i += 1 return result def impl(self, space): size = self.find_size() - return space.wrap(loop(self, init, size)) + return space.wrap(loop(self, False, size)) return func_with_new_name(impl, "reduce_any_impl") descr_sum = _reduce_sum_prod_impl(add, 0.0) descr_prod = _reduce_sum_prod_impl(mul, 1.0) descr_max = _reduce_max_min_impl(maximum) descr_min = _reduce_max_min_impl(minimum) - descr_all = _reduce_all_impl(and_bool, True, False) - descr_any = _reduce_any_impl(or_bool, False, True) + descr_all = _reduce_all_impl() + descr_any = _reduce_any_impl() def descr_dot(self, space, w_other): if isinstance(w_other, BaseArray): From noreply at buildbot.pypy.org Tue Jul 12 00:47:13 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:47:13 +0200 (CEST) Subject: [pypy-commit] pypy default: Changed numpy array's mean method to use the sum method Message-ID: <20110711224713.D9266820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45486:61077eb4052f Date: 2011-07-11 09:26 -0600 http://bitbucket.org/pypy/pypy/changeset/61077eb4052f/ Log: Changed numpy array's mean method to use the sum method diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -260,13 +260,7 @@ return self.get_concrete().descr_setitem(space, item, value) def descr_mean(self, space): - s = 0 - concrete = self.get_concrete() - size = concrete.find_size() - for i in xrange(size): - s += concrete.getitem(i) - return space.wrap(s / size) - + return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) class FloatWrapper(BaseArray): """ From noreply at buildbot.pypy.org Tue Jul 12 00:47:15 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:47:15 +0200 (CEST) Subject: [pypy-commit] pypy default: Added argmin and argmax to numpy arrays Message-ID: <20110711224715.0E5CD820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45487:dee586a9d707 Date: 2011-07-11 09:47 -0600 http://bitbucket.org/pypy/pypy/changeset/dee586a9d707/ Log: Added argmin and argmax to numpy arrays diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -181,6 +181,32 @@ return space.wrap(loop(self, self.eval(0), size)) return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + def _reduce_argmax_argmin_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, size): + result = 0 + cur_best = self.eval(0) + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + new_best = function(cur_best, self.eval(i)) + if new_best != cur_best: + result = i + cur_best = new_best + i += 1 + return result + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, size)) + return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) + def _reduce_all_impl(): reduce_driver = jit.JitDriver(greens=['signature'], reds = ['i', 'size', 'result', 'self']) @@ -225,6 +251,8 @@ descr_prod = _reduce_sum_prod_impl(mul, 1.0) descr_max = _reduce_max_min_impl(maximum) descr_min = _reduce_max_min_impl(minimum) + descr_argmax = _reduce_argmax_argmin_impl(maximum) + descr_argmin = _reduce_argmax_argmin_impl(minimum) descr_all = _reduce_all_impl() descr_any = _reduce_any_impl() @@ -519,6 +547,8 @@ prod = interp2app(BaseArray.descr_prod), max = interp2app(BaseArray.descr_max), min = interp2app(BaseArray.descr_min), + argmax = interp2app(BaseArray.descr_argmax), + argmin = interp2app(BaseArray.descr_argmin), all = interp2app(BaseArray.descr_all), any = interp2app(BaseArray.descr_any), dot = interp2app(BaseArray.descr_dot), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -313,6 +313,20 @@ b = array([]) raises(ValueError, "b.min()") + def test_argmax(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmax() == 2 + b = array([]) + raises(ValueError, "b.argmax()") + + def test_argmin(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmin() == 3 + b = array([]) + raises(ValueError, "b.argmin()") + def test_all(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Tue Jul 12 00:47:16 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:47:16 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110711224716.4607D820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45488:daa5541d43ee Date: 2011-07-11 16:46 -0600 http://bitbucket.org/pypy/pypy/changeset/daa5541d43ee/ Log: merge diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -16,27 +16,92 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = int_mod(i6, i10) i17 = int_rshift(i15, 63) i18 = int_and(i10, i17) i19 = int_add(i15, i18) i21 = int_lt(i19, 0) - guard_false(i21, descr=) + guard_false(i21, descr=...) i22 = int_ge(i19, i10) - guard_false(i22, descr=) + guard_false(i22, descr=...) i23 = strgetitem(p11, i19) i24 = int_ge(i19, i12) - guard_false(i24, descr=) + guard_false(i24, descr=...) i25 = unicodegetitem(p13, i19) - guard_not_invalidated(descr=) p27 = newstr(1) strsetitem(p27, 0, i23) p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) - guard_true(i32, descr=) + guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) + + def test_long(self): + def main(n): + import string + i = 1 + while i < n: + i += int(long(string.digits[i % len(string.digits)], 16)) + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i13 = int_eq(i6, -9223372036854775808) + guard_false(i13, descr=...) + i15 = int_mod(i6, i8) + i17 = int_rshift(i15, 63) + i18 = int_and(i8, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i8) + guard_false(i22, descr=...) + i23 = strgetitem(p10, i19) + p25 = newstr(1) + strsetitem(p25, 0, i23) + p28 = call(ConstClass(strip_spaces), p25, descr=) + guard_no_exception(descr=...) + i29 = strlen(p28) + i30 = int_is_true(i29) + guard_true(i30, descr=...) + i32 = int_sub(i29, 1) + i33 = strgetitem(p28, i32) + i35 = int_eq(i33, 108) + guard_false(i35, descr=...) + i37 = int_eq(i33, 76) + guard_false(i37, descr=...) + i39 = strgetitem(p28, 0) + i41 = int_eq(i39, 45) + guard_false(i41, descr=...) + i43 = int_eq(i39, 43) + guard_false(i43, descr=...) + i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=) + guard_false(i43, descr=...) + i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=) + guard_false(i46, descr=...) + p51 = new_with_vtable(21136408) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, 1, descr=) + setfield_gc(p51, 16, descr=) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, i29, descr=) + p55 = call(ConstClass(parse_digit_string), p51, descr=) + guard_no_exception(descr=...) + i57 = call(ConstClass(rbigint.toint), p55, descr=) + guard_no_exception(descr=...) + i58 = int_add_ovf(i6, i57) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) """) \ No newline at end of file diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -486,6 +486,11 @@ return True + def ll_startswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[0] == ch + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) @@ -503,6 +508,11 @@ return True + def ll_endswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[len(s.chars) - 1] == ch + @elidable def ll_find_char(s, ch, start, end): i = start diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -433,7 +433,9 @@ "ll_streq": Meth([self.SELFTYPE_T], Bool), "ll_strcmp": Meth([self.SELFTYPE_T], Signed), "ll_startswith": Meth([self.SELFTYPE_T], Bool), + "ll_startswith_char": Meth([self.CHAR], Bool), "ll_endswith": Meth([self.SELFTYPE_T], Bool), + "ll_endswith_char": Meth([self.CHAR], Bool), "ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed), @@ -1429,10 +1431,18 @@ # NOT_RPYTHON return self._str.startswith(s._str) + def ll_startswith_char(self, s): + # NOT_RPYTHON + return self._str.startswith(s) + def ll_endswith(self, s): # NOT_RPYTHON return self._str.endswith(s._str) + def ll_endswith_char(self, s): + # NOT_RPYTHON + return self._str.endswith(s) + def ll_find(self, s, start, end): # NOT_RPYTHON if start > len(self._str): # workaround to cope with corner case diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py --- a/pypy/rpython/rstr.py +++ b/pypy/rpython/rstr.py @@ -81,16 +81,30 @@ return super(AbstractStringRepr, self).rtype_is_true(hop) def rtype_method_startswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_startswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_startswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_endswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_endswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_endswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_find(self, hop, reverse=False): # XXX binaryop diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -227,6 +227,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_startswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].startswith('o') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_endswith(self): const = self.const def fn(i, j): @@ -238,6 +247,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_endswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].endswith('e') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_find(self): const = self.const def fn(i, j): diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -688,28 +688,54 @@ def getothernodes(self): return self.othernodes[:] + def getbasecfilefornode(self, node, basecname): + # For FuncNode instances, use the python source filename (relative to + # the top directory): + if hasattr(node.obj, 'graph'): + g = node.obj.graph + # Lookup the filename from the function. + # However, not all FunctionGraph objs actually have a "func": + if hasattr(g, 'func'): + if g.filename.endswith('.py'): + localpath = py.path.local(g.filename) + pypkgpath = localpath.pypkgpath() + if pypkgpath: + relpypath = localpath.relto(pypkgpath) + return relpypath.replace('.py', '.c') + return basecname + def splitnodesimpl(self, basecname, nodes, nextra, nbetween, split_criteria=SPLIT_CRITERIA): + # Gather nodes by some criteria: + nodes_by_base_cfile = {} + for node in nodes: + c_filename = self.getbasecfilefornode(node, basecname) + if c_filename in nodes_by_base_cfile: + nodes_by_base_cfile[c_filename].append(node) + else: + nodes_by_base_cfile[c_filename] = [node] + # produce a sequence of nodes, grouped into files # which have no more than SPLIT_CRITERIA lines - iternodes = iter(nodes) - done = [False] - def subiter(): - used = nextra - for node in iternodes: - impl = '\n'.join(list(node.implementation())).split('\n') - if not impl: - continue - cost = len(impl) + nbetween - yield node, impl - del impl - if used + cost > split_criteria: - # split if criteria met, unless we would produce nothing. - raise StopIteration - used += cost - done[0] = True - while not done[0]: - yield self.uniquecname(basecname), subiter() + for basecname in nodes_by_base_cfile: + iternodes = iter(nodes_by_base_cfile[basecname]) + done = [False] + def subiter(): + used = nextra + for node in iternodes: + impl = '\n'.join(list(node.implementation())).split('\n') + if not impl: + continue + cost = len(impl) + nbetween + yield node, impl + del impl + if used + cost > split_criteria: + # split if criteria met, unless we would produce nothing. + raise StopIteration + used += cost + done[0] = True + while not done[0]: + yield self.uniquecname(basecname), subiter() def gen_readable_parts_of_source(self, f): split_criteria_big = SPLIT_CRITERIA diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -55,6 +55,13 @@ data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + # Verify that the generated C files have sane names: + gen_c_files = [str(f) for f in cbuilder.extrafiles] + for expfile in ('rlib_rposix.c', + 'rpython_lltypesystem_rstr.c', + 'translator_c_test_test_standalone.c'): + assert cbuilder.targetdir.join(expfile) in gen_c_files + def test_print(self): def entry_point(argv): print "hello simpler world" From noreply at buildbot.pypy.org Tue Jul 12 00:59:44 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 00:59:44 +0200 (CEST) Subject: [pypy-commit] pypy default: fixed dot and argmax/min jit Message-ID: <20110711225944.07A6B820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45489:b8b3d24c83ab Date: 2011-07-11 16:59 -0600 http://bitbucket.org/pypy/pypy/changeset/b8b3d24c83ab/ Log: fixed dot and argmax/min jit diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -183,7 +183,7 @@ def _reduce_argmax_argmin_impl(function): reduce_driver = jit.JitDriver(greens=['signature'], - reds = ['i', 'size', 'self', 'result']) + reds = ['i', 'size', 'result', 'self']) def loop(self, size): result = 0 cur_best = self.eval(0) @@ -258,7 +258,9 @@ def descr_dot(self, space, w_other): if isinstance(w_other, BaseArray): - return self.descr_mul(space, w_other).descr_sum(space) + w_res = self.descr_mul(space, w_other) + assert isinstance(w_res, BaseArray) + return w_res.descr_sum(space) else: return self.descr_mul(space, w_other) From noreply at buildbot.pypy.org Tue Jul 12 01:03:22 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 12 Jul 2011 01:03:22 +0200 (CEST) Subject: [pypy-commit] pypy default: Simplify these loops. Message-ID: <20110711230322.8920D820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45490:b7293d2ced2b Date: 2011-07-11 16:03 -0700 http://bitbucket.org/pypy/pypy/changeset/b7293d2ced2b/ Log: Simplify these loops. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -53,10 +53,6 @@ return max(v1, v2) def minimum(v1, v2): return min(v1, v2) -def and_bool(v1, v2): - return v1 and bool(v2) -def or_bool(v1, v2): - return v1 or bool(v2) class BaseArray(Wrappable): def __init__(self): @@ -131,7 +127,7 @@ ) self.invalidates.append(res) return space.wrap(res) - return func_with_new_name(impl, + return func_with_new_name(impl, "binop_right_%s_impl" % function.__name__) descr_radd = _binop_right_impl(add) @@ -161,7 +157,7 @@ def _reduce_max_min_impl(function): reduce_driver = jit.JitDriver(greens=['signature'], - reds = ['i', 'size', 'self', 'result']) + reds = ['i', 'size', 'self', 'result']) def loop(self, result, size): i = 1 while i < size: @@ -171,7 +167,7 @@ result = function(result, self.eval(i)) i += 1 return result - + def impl(self, space): size = self.find_size() if size == 0: @@ -207,45 +203,37 @@ return space.wrap(loop(self, size)) return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) - def _reduce_all_impl(): - reduce_driver = jit.JitDriver(greens=['signature'], - reds = ['i', 'size', 'result', 'self']) - def loop(self, result, size): - i = 0 - while i < size: - reduce_driver.jit_merge_point(signature=self.signature, - self=self, size=size, i=i, - result=result) - result = and_bool(result, self.eval(i)) - if not result: - break - i += 1 - return result + all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'result', 'self']) + def _all(self): + size = self.find_size() + signature = self.signature + i = 0 + result = True + while i < size: + BaseArray.all_driver.jit_merge_point(signature=signature, self=self, size=size, i=i, result=result) + result = result and bool(self.eval(i)) + if not result: + break + i += 1 + return result + def descr_all(self, space): + return space.wrap(self._all()) - def impl(self, space): - size = self.find_size() - return space.wrap(loop(self, True, size)) - return func_with_new_name(impl, "reduce_all_impl") - - def _reduce_any_impl(): - reduce_driver = jit.JitDriver(greens=['signature'], - reds = ['i', 'size', 'result', 'self']) - - def loop(self, result, size): - i = 0 - while i < size: - reduce_driver.jit_merge_point(signature=self.signature, - self=self, size=size, i=i, - result=result) - result = or_bool(result, self.eval(i)) - if result: - break - i += 1 - return result - def impl(self, space): - size = self.find_size() - return space.wrap(loop(self, False, size)) - return func_with_new_name(impl, "reduce_any_impl") + any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'result', 'self']) + def _any(self): + size = self.find_size() + signature = self.signature + i = 0 + result = False + while i < size: + BaseArray.any_driver.jit_merge_point(signature=signature, self=self, size=size, i=i, result=result) + result = result or bool(self.eval(i)) + if result: + break + i += 1 + return result + def descr_any(self, space): + return space.wrap(self._any()) descr_sum = _reduce_sum_prod_impl(add, 0.0) descr_prod = _reduce_sum_prod_impl(mul, 1.0) @@ -253,8 +241,6 @@ descr_min = _reduce_max_min_impl(minimum) descr_argmax = _reduce_argmax_argmin_impl(maximum) descr_argmin = _reduce_argmax_argmin_impl(minimum) - descr_all = _reduce_all_impl() - descr_any = _reduce_any_impl() def descr_dot(self, space, w_other): if isinstance(w_other, BaseArray): From noreply at buildbot.pypy.org Tue Jul 12 01:21:23 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 12 Jul 2011 01:21:23 +0200 (CEST) Subject: [pypy-commit] pypy default: fixed translation (hopefully) Message-ID: <20110711232123.39207820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45491:1851161c1535 Date: 2011-07-11 16:21 -0700 http://bitbucket.org/pypy/pypy/changeset/1851161c1535/ Log: fixed translation (hopefully) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -179,7 +179,7 @@ def _reduce_argmax_argmin_impl(function): reduce_driver = jit.JitDriver(greens=['signature'], - reds = ['i', 'size', 'result', 'self']) + reds = ['i', 'size', 'result', 'cur_best', 'self']) def loop(self, size): result = 0 cur_best = self.eval(0) @@ -187,7 +187,7 @@ while i < size: reduce_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i, - result=result) + result=result, cur_best=cur_best) new_best = function(cur_best, self.eval(i)) if new_best != cur_best: result = i From noreply at buildbot.pypy.org Tue Jul 12 01:32:36 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 12 Jul 2011 01:32:36 +0200 (CEST) Subject: [pypy-commit] pypy default: Fixed argmin/max and added a jit test for argmin Message-ID: <20110711233236.75829820D2@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45492:1da5d7bbf8c3 Date: 2011-07-11 17:32 -0600 http://bitbucket.org/pypy/pypy/changeset/1da5d7bbf8c3/ Log: Fixed argmin/max and added a jit test for argmin diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -179,7 +179,7 @@ def _reduce_argmax_argmin_impl(function): reduce_driver = jit.JitDriver(greens=['signature'], - reds = ['i', 'size', 'result', 'cur_best', 'self']) + reds = ['i', 'size', 'result', 'self', 'cur_best']) def loop(self, size): result = 0 cur_best = self.eval(0) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -115,6 +115,23 @@ "int_lt": 1, "guard_true": 2, "jump": 1}) + def test_argmin(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_argmin(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + def test_all(self): space = self.space From noreply at buildbot.pypy.org Tue Jul 12 02:41:07 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 12 Jul 2011 02:41:07 +0200 (CEST) Subject: [pypy-commit] pypy default: Simplify code and fix translation. Message-ID: <20110712004107.5B91C820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45493:b21405daef53 Date: 2011-07-11 17:40 -0700 http://bitbucket.org/pypy/pypy/changeset/b21405daef53/ Log: Simplify code and fix translation. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -20,6 +20,8 @@ numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) +all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) class Signature(object): def __init__(self): @@ -203,35 +205,27 @@ return space.wrap(loop(self, size)) return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) - all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'result', 'self']) def _all(self): size = self.find_size() - signature = self.signature i = 0 - result = True while i < size: - BaseArray.all_driver.jit_merge_point(signature=signature, self=self, size=size, i=i, result=result) - result = result and bool(self.eval(i)) - if not result: - break + all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if not self.eval(i): + return False i += 1 - return result + return True def descr_all(self, space): return space.wrap(self._all()) - any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'result', 'self']) def _any(self): size = self.find_size() - signature = self.signature i = 0 - result = False while i < size: - BaseArray.any_driver.jit_merge_point(signature=signature, self=self, size=size, i=i, result=result) - result = result or bool(self.eval(i)) - if result: - break + any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if self.eval(i): + return True i += 1 - return result + return False def descr_any(self, space): return space.wrap(self._any()) From noreply at buildbot.pypy.org Tue Jul 12 04:50:55 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 12 Jul 2011 04:50:55 +0200 (CEST) Subject: [pypy-commit] pypy default: Made a bunch of guard numbers into "..." in the JIT tests so they pass consistantly. Also sprinked guard_not_invalidated in a few places, and removed a few instructions. Message-ID: <20110712025055.3D590820D2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45494:3b4ad4eaddf7 Date: 2011-07-11 19:50 -0700 http://bitbucket.org/pypy/pypy/changeset/3b4ad4eaddf7/ Log: Made a bunch of guard numbers into "..." in the JIT tests so they pass consistantly. Also sprinked guard_not_invalidated in a few places, and removed a few instructions. diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -19,7 +19,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) + guard_true(i7, descr=...) i9 = int_add(i5, 1) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) @@ -39,11 +39,12 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated(descr=...) i13 = int_lt(i7, i9) - guard_true(i13, descr=) + guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = int_add(i7, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) @@ -68,16 +69,17 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i13 = int_lt(i8, 307200) - guard_true(i13, descr=) + guard_true(i13, descr=...) + guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) # on 64bit, there is a guard checking that i19 actually fits into 32bit ... setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -80,19 +80,19 @@ # assert entry_bridge.match_by_id('call', """ p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) + guard_nonnull_class(p29, ConstClass(Function), descr=...) p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) + guard_value(p33, ConstPtr(ptr34), descr=...) p35 = getfield_gc(p29, descr=) p36 = getfield_gc(p29, descr=) p38 = call(ConstClass(getexecutioncontext), descr=) p39 = getfield_gc(p38, descr=) i40 = force_token() p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) + guard_isnull(p41, descr=...) i42 = getfield_gc(p38, descr=) i43 = int_is_zero(i42) - guard_true(i43, descr=) + guard_true(i43, descr=...) i50 = force_token() """) # @@ -101,16 +101,16 @@ loop, = log.loops_by_id('call') assert loop.match(""" i12 = int_lt(i5, i6) - guard_true(i12, descr=) + guard_true(i12, descr=...) i13 = force_token() i15 = int_add(i5, 1) i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) """) @@ -146,14 +146,14 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i15 = int_lt(i6, i9) - guard_true(i15, descr=) - guard_not_invalidated(descr=) + guard_true(i15, descr=...) + guard_not_invalidated(descr=...) i16 = force_token() i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) """) @@ -180,11 +180,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) - guard_not_invalidated(descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = force_token() i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() --TICK-- jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) @@ -281,25 +281,23 @@ loop0, = log.loops_by_id('g1') assert loop0.match_by_id('g1', """ i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('h1', """ i20 = force_token() i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('g2', """ i27 = force_token() i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) # loop1, = log.loops_by_id('g3') assert loop1.match_by_id('g3', """ i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) guard_no_overflow(descr=...) """) @@ -352,7 +350,7 @@ i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) p17 = getfield_gc(p8, descr=) p19 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p19, i12, descr=) @@ -404,9 +402,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i10 = int_lt(i5, i6) - guard_true(i10, descr=) + guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i120 = int_add(i5, 1) - guard_not_invalidated(descr=) --TICK-- jump(..., descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py --- a/pypy/module/pypyjit/test_pypy_c/test_exception.py +++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py @@ -36,11 +36,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i5 = int_is_true(i3) - guard_true(i5, descr=) - guard_not_invalidated(descr=) + guard_true(i5, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -84,8 +84,8 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i4, i5) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i14 = int_add(i4, 1) --TICK-- diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py --- a/pypy/module/pypyjit/test_pypy_c/test_import.py +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -15,13 +15,13 @@ assert log.result == 500 loop, = log.loops_by_id('import') assert loop.match_by_id('import', """ + guard_not_invalidated(descr=...) p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) + guard_value(p11, ConstPtr(ptr12), descr=...) p14 = getfield_gc(ConstPtr(ptr13), descr=) p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) + guard_value(p14, ConstPtr(ptr17), descr=...) + guard_isnull(p16, descr=...) """) def test_import_fast_path(self, tmpdir): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -22,10 +22,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) """) @@ -47,10 +47,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = int_lt(i5, i6) - guard_true(i9, descr=) - guard_not_invalidated(descr=) + guard_true(i9, descr=...) + guard_not_invalidated(descr=...) i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -17,6 +17,7 @@ assert loop.match(""" i7 = int_lt(i4, 300) guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 3000) guard_no_overflow(descr=...) i11 = int_add(i4, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -84,7 +84,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = float_lt(f5, f7) - guard_true(i9, descr=) + guard_true(i9, descr=...) f10 = float_add(f8, f5) --TICK-- jump(p0, p1, p2, p3, p4, f10, p6, f7, f8, descr=) @@ -107,19 +107,19 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i11, i12) - guard_false(i16, descr=) + guard_false(i16, descr=...) i17 = int_mul(i11, i14) i18 = int_add(i15, i17) i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=) + guard_not_invalidated(descr=...) i23 = int_lt(i18, 0) - guard_false(i23, descr=) + guard_false(i23, descr=...) i25 = int_ge(i18, i9) - guard_false(i25, descr=) + guard_false(i25, descr=...) i27 = int_add_ovf(i7, i18) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -164,20 +164,20 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i12, i13) - guard_false(i16, descr=) + guard_false(i16, descr=...) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) - guard_nonnull_class(p17, 146982464, descr=) + guard_nonnull_class(p17, 146982464, descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) - guard_true(i23, descr=) + guard_true(i23, descr=...) i24 = getfield_gc(p17, descr=) i25 = getarrayitem_raw(i24, 0, descr=<.*>) i27 = int_lt(1, i21) - guard_false(i27, descr=) + guard_false(i27, descr=...) i28 = int_add_ovf(i10, i25) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) @@ -201,9 +201,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i11 = int_lt(i7, 300) - guard_true(i11, descr=) + guard_true(i11, descr=...) i12 = int_add_ovf(i8, i9) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i14 = int_add(i7, 1) --TICK-- jump(..., descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -92,10 +92,10 @@ p51 = new_with_vtable(21136408) setfield_gc(p51, p28, descr=) setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, i29, descr=) setfield_gc(p51, 1, descr=) setfield_gc(p51, 16, descr=) setfield_gc(p51, p28, descr=) - setfield_gc(p51, i29, descr=) p55 = call(ConstClass(parse_digit_string), p51, descr=) guard_no_exception(descr=...) i57 = call(ConstClass(rbigint.toint), p55, descr=) From noreply at buildbot.pypy.org Tue Jul 12 09:40:05 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 12 Jul 2011 09:40:05 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Fix and simplify handling of destructors, both interp-level and Message-ID: <20110712074005.8E323820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45495:3a6efd180057 Date: 2011-07-11 22:55 +0200 http://bitbucket.org/pypy/pypy/changeset/3a6efd180057/ Log: Fix and simplify handling of destructors, both interp-level and app- level. No more magic meta-programming. Instead, we can (but don't have to) call self.enqueue_for_destruction(), passing it an explicit callback, and we can enqueue several callbacks for the same object. Calling the app-level destructor is just one such callback, added by typedef.py. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -149,26 +149,22 @@ self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden by builtin_destructor() in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -141,22 +141,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -184,11 +184,12 @@ def test_destructor(self): space = self.space class W_Level1(Wrappable): - space = self.space def __del__(self): space.call_method(w_seen, 'append', space.wrap(1)) - class W_Level2(W_Level1): - typedef.builtin_destructor(locals(), 'destructormeth', W_Level1) + class W_Level2(Wrappable): + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') def destructormeth(self): space.call_method(w_seen, 'append', space.wrap(2)) W_Level1.typedef = typedef.TypeDef( @@ -201,7 +202,7 @@ w_seen = space.newlist([]) W_Level1() gc.collect(); gc.collect() - assert space.str_w(space.repr(w_seen)) == "[1]" + assert space.unwrap(w_seen) == [1] # w_seen = space.newlist([]) W_Level2() @@ -209,7 +210,7 @@ assert space.str_w(space.repr(w_seen)) == "[]" # not called yet ec = space.getexecutioncontext() self.space.user_del_action.perform(ec, None) - assert space.str_w(space.repr(w_seen)) == "[2, 1]" + assert space.unwrap(w_seen) == [2] # w_seen = space.newlist([]) self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], @@ -219,7 +220,7 @@ A3() """) gc.collect(); gc.collect() - assert space.str_w(space.repr(w_seen)) == "[1]" + assert space.unwrap(w_seen) == [1] # w_seen = space.newlist([]) self.space.appexec([self.space.gettypeobject(W_Level1.typedef), @@ -231,7 +232,7 @@ A4() """) gc.collect(); gc.collect() - assert space.str_w(space.repr(w_seen)) == "[4, 1]" + assert space.unwrap(w_seen) == [4, 1] # w_seen = space.newlist([]) self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], @@ -241,7 +242,7 @@ A5() """) gc.collect(); gc.collect() - assert space.str_w(space.repr(w_seen)) == "[2, 1]" + assert space.unwrap(w_seen) == [2] # w_seen = space.newlist([]) self.space.appexec([self.space.gettypeobject(W_Level2.typedef), @@ -253,7 +254,7 @@ A6() """) gc.collect(); gc.collect() - assert space.str_w(space.repr(w_seen)) == "[6, 2, 1]" + assert space.unwrap(w_seen) == [6, 2] class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -233,8 +233,15 @@ add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) class Proto(object): - builtin_destructor(locals(), None, supercls) + def __del__(self): + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') + if parent_destructor is not None: + self.enqueue_for_destruction(self.space, parent_destructor, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -286,46 +293,8 @@ return w_dict check_new_dictionary._dont_inline_ = True - -def builtin_destructor(loc, methodname, baseclass): - # Destructor logic: - # * if we have none, then the class has no __del__. - # * if we have a "simple" interp-level one, it is just written as a - # __del__. ("simple" destructors may not do too much, e.g. they must - # never call further Python code; this is checked at translation-time) - # * if we have a "complex" interp-level destructor, then we define it in - # a method foo(), followed by - # ``builtin_destructor(locals(), "foo", W_Base)''. - # * if we have an app-level destructor, then typedef.py will also - # call builtin_destructor(). - # In the last two cases, the __del__ just calls _enqueue_for_destruction() - # and executioncontext.UserDelAction does the real job. - - assert '_builtin_destructor_already_called_' not in loc - assert '__del__' not in loc - assert '_call_builtin_destructor' not in loc - - if hasattr(baseclass, '_builtin_destructor_already_called_'): - # builtin_destructor() was already called on the parent - # class, so we don't need to install the __del__ method nor - # call the __del__ method from _call_builtin_destructor() - # (because the parent _call_builtin_destructor() will do it) - parent_del = None - else: - def __del__(self): - self._enqueue_for_destruction(self.space) - loc['__del__'] = __del__ - loc['_builtin_destructor_already_called_'] = True - parent_del = getattr(baseclass, '__del__', None) - - if methodname is not None or parent_del is not None: - def _call_builtin_destructor(self): - if methodname is not None: - getattr(self, methodname)() - if parent_del is not None: - parent_del(self) - baseclass._call_builtin_destructor(self) - loc['_call_builtin_destructor'] = _call_builtin_destructor +def call_applevel_del(self): + self.space.userdel(self) # ____________________________________________________________ @@ -894,8 +863,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -23,8 +23,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,11 +120,7 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: - w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) + w_self.space.call_function(w_self.w_callable, w_self) def descr__repr__(self, space): w_obj = self.dereference() From noreply at buildbot.pypy.org Tue Jul 12 09:40:06 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 12 Jul 2011 09:40:06 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Use enqueue_for_destruction() in case close()ing the file fails. Message-ID: <20110712074006.BFCF9820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45496:a91ad10bc67e Date: 2011-07-11 23:03 +0200 http://bitbucket.org/pypy/pypy/changeset/a91ad10bc67e/ Log: Use enqueue_for_destruction() in case close()ing the file fails. We cannot nicely report the error immediately, because we are in an RPython-level __del__. diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -33,6 +33,7 @@ encoding = None errors = None fd = -1 + streamerror_upon_closing = None newlines = 0 # Updated when the stream is closed @@ -46,8 +47,14 @@ try: self.direct_close() except StreamErrors, e: - operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + self.streamerror_upon_closing = e + self.enqueue_for_destruction(self.space, W_File.report_streamerror, + 'close() method of ') + + def report_streamerror(self): + operr = wrap_streamerror(self.space, self.streamerror_upon_closing, + self.w_name) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd From noreply at buildbot.pypy.org Tue Jul 12 09:40:07 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 12 Jul 2011 09:40:07 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Mostly revert the changes here. The __del__ method just needs Message-ID: <20110712074007.EE67E820D2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45497:4b0f56f41c5d Date: 2011-07-11 23:09 +0200 http://bitbucket.org/pypy/pypy/changeset/4b0f56f41c5d/ Log: Mostly revert the changes here. The __del__ method just needs to use enqueue_for_destruction() in order to call the space.xxx() methods. diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -838,9 +838,9 @@ self.w_writer = None raise - def destructor(self): - # method overriden to not close the files - pass + def __del__(self): + self.clear_all_weakrefs() + # Don't call the base __del__: do not close the files! # forward to reader for method in ['read', 'peek', 'read1', 'readinto', 'readable']: diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -1,7 +1,7 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import ( TypeDef, GetSetProperty, generic_new_descr, descr_get_dict, descr_set_dict, - make_weakref_descr, builtin_destructor) + make_weakref_descr) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError, operationerrfmt from pypy.rlib.rstring import StringBuilder @@ -55,6 +55,11 @@ return True return False + def __del__(self): + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + def destructor(self): space = self.space w_closed = space.findattr(self, space.wrap('closed')) @@ -68,7 +73,6 @@ # equally as bad, and potentially more frequent (because of # shutdown issues). pass - builtin_destructor(locals(), 'destructor', Wrappable) def _CLOSED(self): # Use this macro whenever you want to check the internal `closed` From noreply at buildbot.pypy.org Tue Jul 12 11:06:52 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 12 Jul 2011 11:06:52 +0200 (CEST) Subject: [pypy-commit] pypy default: a failing test Message-ID: <20110712090652.AF892820D2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45498:759f5b308eb6 Date: 2011-07-12 10:38 +0200 http://bitbucket.org/pypy/pypy/changeset/759f5b308eb6/ Log: a failing test diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -132,6 +132,17 @@ # You cannot assing character format codes as restype any longer raises(TypeError, setattr, f, "restype", "i") + + def test_truncate_python_longs(self): + py.test.skip("fixme") + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_int + x = sys.maxint * 2 + result = f(0, 0, x, 0, 0, 0) + assert result == 2 + + def test_floatresult(self): f = dll._testfunc_f_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] From noreply at buildbot.pypy.org Tue Jul 12 11:06:53 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 12 Jul 2011 11:06:53 +0200 (CEST) Subject: [pypy-commit] pypy default: truncate python longs when converting to C types Message-ID: <20110712090653.EB81D82100@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45499:194dbf1456fc Date: 2011-07-12 10:51 +0200 http://bitbucket.org/pypy/pypy/changeset/194dbf1456fc/ Log: truncate python longs when converting to C types diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -149,6 +149,11 @@ raise OperationError(space.w_TypeError, space.wrap(msg)) return res +def unwrap_truncate_int(space, w_arg): + if space.is_true(space.isinstance(w_arg, space.w_int)): + return space.int_w(w_arg) + else: + return rffi.cast(rffi.LONG, space.bigint_w(w_arg).ulonglongmask()) # ======================================================================== @@ -184,7 +189,7 @@ kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind self.arg_longlong(space, argchain, kind, w_arg) elif w_argtype.is_signed(): - argchain.arg(space.int_w(w_arg)) + argchain.arg(unwrap_truncate_int(space, w_arg)) elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -119,10 +119,12 @@ return x+y; } """ + import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint) assert sum_xy(30, 12) == 42 + assert sum_xy(sys.maxint*2, 0) == -2 def test_void_result(self): """ From noreply at buildbot.pypy.org Tue Jul 12 11:06:55 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 12 Jul 2011 11:06:55 +0200 (CEST) Subject: [pypy-commit] pypy default: truncate python longs also when converting to unsigned types Message-ID: <20110712090655.21CFB820D2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45500:0022eb161caa Date: 2011-07-12 11:02 +0200 http://bitbucket.org/pypy/pypy/changeset/0022eb161caa/ Log: truncate python longs also when converting to unsigned types diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -149,11 +149,12 @@ raise OperationError(space.w_TypeError, space.wrap(msg)) return res -def unwrap_truncate_int(space, w_arg): +def unwrap_truncate_int(TP, space, w_arg): if space.is_true(space.isinstance(w_arg, space.w_int)): - return space.int_w(w_arg) + return rffi.cast(TP, space.int_w(w_arg)) else: - return rffi.cast(rffi.LONG, space.bigint_w(w_arg).ulonglongmask()) + return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask()) +unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)' # ======================================================================== @@ -189,12 +190,12 @@ kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind self.arg_longlong(space, argchain, kind, w_arg) elif w_argtype.is_signed(): - argchain.arg(unwrap_truncate_int(space, w_arg)) + argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) elif w_argtype.is_unsigned(): - argchain.arg(intmask(space.uint_w(w_arg))) + argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg)) elif w_argtype.is_char(): w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -111,7 +111,6 @@ types.double) assert pow(2, 3) == 8 - def test_int_args(self): """ DLLEXPORT int sum_xy(int x, int y) @@ -249,6 +248,9 @@ types.ulong) assert sum_xy(sys.maxint, 12) == sys.maxint+12 assert sum_xy(sys.maxint+1, 12) == sys.maxint+13 + # + res = sum_xy(sys.maxint*2+3, 0) + assert res == 1 def test_unsigned_short_args(self): """ From noreply at buildbot.pypy.org Tue Jul 12 11:06:56 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 12 Jul 2011 11:06:56 +0200 (CEST) Subject: [pypy-commit] pypy default: truncate also when converting to {s, u}longlongs. This has the nice effect to simplify a bit the code Message-ID: <20110712090656.49A63820D2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45501:c88c99177447 Date: 2011-07-12 11:06 +0200 http://bitbucket.org/pypy/pypy/changeset/c88c99177447/ Log: truncate also when converting to {s,u}longlongs. This has the nice effect to simplify a bit the code diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -187,8 +187,7 @@ # note that we must check for longlong first, because either # is_signed or is_unsigned returns true anyway assert libffi.IS_32_BIT - kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind - self.arg_longlong(space, argchain, kind, w_arg) + self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) elif w_argtype.is_pointer(): @@ -226,15 +225,10 @@ return w_arg @jit.dont_look_inside - def arg_longlong(self, space, argchain, kind, w_arg): + def arg_longlong(self, space, argchain, w_arg): bigarg = space.bigint_w(w_arg) - if kind == 'I': - llval = bigarg.tolonglong() - elif kind == 'U': - ullval = bigarg.toulonglong() - llval = rffi.cast(rffi.LONGLONG, ullval) - else: - assert False + ullval = bigarg.ulonglongmask() + llval = rffi.cast(rffi.LONGLONG, ullval) # this is a hack: we store the 64 bits of the long long into the # 64 bits of a float (i.e., a C double) floatval = libffi.longlong2float(llval) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -379,6 +379,9 @@ res = sum_xy(x, y) expected = maxint64 + 3 assert res == expected + # + res = sum_xy(maxint64*2+3, 0) + assert res == 1 def test_byval_argument(self): """ From noreply at buildbot.pypy.org Tue Jul 12 11:42:38 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 12 Jul 2011 11:42:38 +0200 (CEST) Subject: [pypy-commit] buildbot default: try using pypy to translate, should be globally installed on all buildslaves Message-ID: <20110712094238.E163382108@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r524:49c32806cd40 Date: 2011-07-12 11:42 +0200 http://bitbucket.org/pypy/buildbot/changeset/49c32806cd40/ Log: try using pypy to translate, should be globally installed on all buildslaves diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -56,7 +56,7 @@ description = ["translating"] descriptionDone = ["translation"] - command = ["python", "translate.py", "--batch"] + command = ["pypy", "translate.py", "--batch"] translationTarget = "targetpypystandalone" haltOnFailure = True From noreply at buildbot.pypy.org Tue Jul 12 11:46:55 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 12 Jul 2011 11:46:55 +0200 (CEST) Subject: [pypy-commit] pypy default: fix the gateway if something has no module Message-ID: <20110712094655.C641282108@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45502:5cfaf26307cf Date: 2011-07-12 11:46 +0200 http://bitbucket.org/pypy/pypy/changeset/5cfaf26307cf/ Log: fix the gateway if something has no module diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -396,11 +396,14 @@ fastfunc = func else: # try to avoid excessive bloat - if func.__module__ == 'pypy.interpreter.astcompiler.ast': + mod = func.__module__ + if mod is None: + mod = "" + if mod == 'pypy.interpreter.astcompiler.ast': raise FastFuncNotSupported - if (not func.__module__.startswith('pypy.module.__builtin__') and - not func.__module__.startswith('pypy.module.sys') and - not func.__module__.startswith('pypy.module.math')): + if (not mod.startswith('pypy.module.__builtin__') and + not mod.startswith('pypy.module.sys') and + not mod.startswith('pypy.module.math')): if not func.__name__.startswith('descr'): raise FastFuncNotSupported d = {} From noreply at buildbot.pypy.org Tue Jul 12 11:48:22 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 12 Jul 2011 11:48:22 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (hager, cfbolz): two careful promotes Message-ID: <20110712094822.7109582108@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45503:0fda37f1f11c Date: 2011-07-12 11:47 +0200 http://bitbucket.org/pypy/pypy/changeset/0fda37f1f11c/ Log: (hager, cfbolz): two careful promotes diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -125,7 +125,8 @@ raise OperationError(space.w_TypeError, space.wrap("wrong number of args")) if self.arg_converters is None: self._build_converters() - funcptr = jit.promote(self.methgetter)(cppthis) + jit.promote(self) + funcptr = self.methgetter(cppthis) libffi_func = self._get_libffi_func(funcptr) if not libffi_func: raise FastCallNotPossible @@ -162,6 +163,7 @@ @jit.unroll_safe def prepare_arguments(self, args_w): + jit.promote(self) space = self.space if len(self.arg_types) < len(args_w) or len(args_w) < self.args_required: raise OperationError(space.w_TypeError, space.wrap("wrong number of args")) From noreply at buildbot.pypy.org Tue Jul 12 11:48:24 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 12 Jul 2011 11:48:24 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge Message-ID: <20110712094824.C946E82108@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45504:1728f9c9d201 Date: 2011-07-12 11:48 +0200 http://bitbucket.org/pypy/pypy/changeset/1728f9c9d201/ Log: merge diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -48,7 +48,8 @@ return self.from_param(as_parameter) def get_ffi_param(self, value): - return self.from_param(value)._to_ffi_param() + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() def get_ffi_argtype(self): if self._ffiargtype: diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -328,12 +328,14 @@ "native COM method call without 'this' parameter" ) thisarg = cast(args[0], POINTER(POINTER(c_void_p))) - newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) newargs.insert(0, args[0].value) argtypes.insert(0, c_void_p) else: thisarg = None - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -437,16 +439,15 @@ @classmethod def _conv_param(cls, argtype, arg): if isinstance(argtype, _CDataMeta): - #arg = argtype.from_param(arg) - arg = argtype.get_ffi_param(arg) - return arg, argtype + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - return arg._to_ffi_param(), type(arg) + return arg, arg._to_ffi_param(), type(arg) # # non-usual case: we do the import here to save a lot of code in the # jit trace of the normal case @@ -463,11 +464,12 @@ else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj._to_ffi_param(), type(cobj) + return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] + keepalives = [] newargtypes = [] total = len(args) paramflags = self._paramflags @@ -495,7 +497,8 @@ val = defval if val is marker: val = 0 - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): @@ -511,28 +514,32 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - newarg, newargtype = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) + keepalive = None newarg = ctypes.byref(val) newargtype = type(newarg) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - newarg, newargtype = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) inargs_idx += 1 @@ -541,12 +548,13 @@ extra = args[len(newargs):] for i, arg in enumerate(extra): try: - newarg, newargtype = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) - return newargs, newargtypes, outargs + return keepalives, newargs, newargtypes, outargs def _wrap_result(self, restype, result): diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -27,9 +27,9 @@ PythonPickler.__init__(self, self.__f, args[0], **kw) else: PythonPickler.__init__(self, *args, **kw) - + def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -263,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -396,11 +396,14 @@ fastfunc = func else: # try to avoid excessive bloat - if func.__module__ == 'pypy.interpreter.astcompiler.ast': + mod = func.__module__ + if mod is None: + mod = "" + if mod == 'pypy.interpreter.astcompiler.ast': raise FastFuncNotSupported - if (not func.__module__.startswith('pypy.module.__builtin__') and - not func.__module__.startswith('pypy.module.sys') and - not func.__module__.startswith('pypy.module.math')): + if (not mod.startswith('pypy.module.__builtin__') and + not mod.startswith('pypy.module.sys') and + not mod.startswith('pypy.module.math')): if not func.__name__.startswith('descr'): raise FastFuncNotSupported d = {} diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -416,11 +416,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x (bootstrap %x)" % ( + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, rawstart + directbootstrappos, rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -479,9 +481,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d has address %x to %x" % + debug_start("jit-backend-addr") + debug_print("Bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -464,7 +464,7 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ @@ -632,16 +632,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -198,9 +198,19 @@ def test_mov_ri_64(): s = CodeBuilder64() s.MOV_ri(ecx, -2) + s.MOV_ri(r15, -3) + s.MOV_ri(ebx, -0x80000003) + s.MOV_ri(r13, -0x80000002) + s.MOV_ri(ecx, 42) s.MOV_ri(r12, 0x80000042) + s.MOV_ri(r12, 0x100000007) assert s.getvalue() == ('\x48\xC7\xC1\xFE\xFF\xFF\xFF' + - '\x49\xBC\x42\x00\x00\x80\x00\x00\x00\x00') + '\x49\xC7\xC7\xFD\xFF\xFF\xFF' + + '\x48\xBB\xFD\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\x49\xBD\xFE\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\xB9\x2A\x00\x00\x00' + + '\x41\xBC\x42\x00\x00\x80' + + '\x49\xBC\x07\x00\x00\x00\x01\x00\x00\x00') def test_mov_rm_64(): s = CodeBuilder64() diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py --- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py +++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py @@ -212,6 +212,17 @@ for mode, v in zip(argmodes, args): ops.append(assembler_operand[mode](v)) ops.reverse() + # + if (instrname.lower() == 'mov' and suffix == 'q' and + ops[0].startswith('$') and 0 <= int(ops[0][1:]) <= 4294967295 + and ops[1].startswith('%r')): + # movq $xxx, %rax => movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -3916,11 +3916,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3941,9 +3938,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3962,10 +3957,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -3987,14 +3981,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -4010,10 +3999,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4131,9 +4118,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -4178,11 +4163,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4374,11 +4356,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -4532,6 +4511,25 @@ """ self.optimize_loop(ops, expected) + def test_strslice_with_other_stuff(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5082,11 +5082,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5107,9 +5104,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5128,10 +5123,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5153,14 +5147,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -5176,10 +5165,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5303,9 +5290,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -5411,11 +5396,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5609,11 +5591,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -61,7 +61,7 @@ self.ensure_nonnull() box = self.force_box() lengthbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) + optimization.optimize_default(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -72,13 +72,13 @@ else: return None - def string_copy_parts(self, optimization, targetbox, offsetbox, mode): + def string_copy_parts(self, optimizer, targetbox, offsetbox, mode): # Copies the pointer-to-string 'self' into the target string # given by 'targetbox', at the specified offset. Returns the offset # at the end of the copy. - lengthbox = self.getstrlen(optimization, mode) + lengthbox = self.getstrlen(optimizer, mode) srcbox = self.force_box() - return copy_str_content(optimization, srcbox, targetbox, + return copy_str_content(optimizer, srcbox, targetbox, CONST_0, offsetbox, lengthbox, mode) @@ -335,7 +335,7 @@ if optimizer is None: return None resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_ADD, [box1, box2], resbox)) return resbox def _int_sub(optimizer, box1, box2): @@ -345,10 +345,10 @@ if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimization, strbox, indexbox, mode): +def _strgetitem(optimizer, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimizer.optimize_default(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,7 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) + resbox = _strgetitem(self.optimizer, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): @@ -450,7 +450,7 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode) + lengthbox = value.getstrlen(self.optimizer, mode) self.make_equal_to(op.result, self.getvalue(lengthbox)) def optimize_CALL(self, op): diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -310,26 +310,27 @@ self.opimpl_goto_if_not(condbox, target) ''' % (_opimpl, _opimpl.upper())).compile() + + def _establish_nullity(self, box, orgpc): + value = box.nonnull() + if value: + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc) + else: + if not isinstance(box, Const): + self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + promoted_box = box.constbox() + self.metainterp.replace_box(box, promoted_box) + return value + @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_nonzero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if not value: + if not self._establish_nullity(box, orgpc): self.pc = target @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_iszero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if value: + if self._establish_nullity(box, orgpc): self.pc = target @arguments("box", "box", "box") @@ -364,7 +365,9 @@ def opimpl_new_with_vtable(self, sizedescr): cpu = self.metainterp.cpu cls = heaptracker.descr2vtable(cpu, sizedescr) - return self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + resbox = self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + self.metainterp.known_class_boxes[resbox] = None + return resbox ## @FixME #arguments("box") ## def opimpl_runtimenew(self, classbox): @@ -845,7 +848,9 @@ @arguments("orgpc", "box") def opimpl_guard_class(self, orgpc, box): clsbox = self.cls_of_box(box) - self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + self.metainterp.known_class_boxes[box] = None return clsbox @arguments("int", "orgpc") @@ -1449,6 +1454,8 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1789,6 +1796,8 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -984,11 +984,14 @@ pass class B(A): pass + @dont_look_inside + def extern(n): + if n: + return A() + else: + return B() def fn(n): - if n: - obj = A() - else: - obj = B() + obj = extern(n) return isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res @@ -1021,6 +1024,70 @@ res = self.meta_interp(main, []) assert res == 55 + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -149,6 +149,12 @@ raise OperationError(space.w_TypeError, space.wrap(msg)) return res +def unwrap_truncate_int(TP, space, w_arg): + if space.is_true(space.isinstance(w_arg, space.w_int)): + return rffi.cast(TP, space.int_w(w_arg)) + else: + return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask()) +unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)' # ======================================================================== @@ -181,15 +187,14 @@ # note that we must check for longlong first, because either # is_signed or is_unsigned returns true anyway assert libffi.IS_32_BIT - kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind - self.arg_longlong(space, argchain, kind, w_arg) + self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): - argchain.arg(space.int_w(w_arg)) + argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) elif w_argtype.is_unsigned(): - argchain.arg(intmask(space.uint_w(w_arg))) + argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg)) elif w_argtype.is_char(): w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) @@ -220,15 +225,10 @@ return w_arg @jit.dont_look_inside - def arg_longlong(self, space, argchain, kind, w_arg): + def arg_longlong(self, space, argchain, w_arg): bigarg = space.bigint_w(w_arg) - if kind == 'I': - llval = bigarg.tolonglong() - elif kind == 'U': - ullval = bigarg.toulonglong() - llval = rffi.cast(rffi.LONGLONG, ullval) - else: - assert False + ullval = bigarg.ulonglongmask() + llval = rffi.cast(rffi.LONGLONG, ullval) # this is a hack: we store the 64 bits of the long long into the # 64 bits of a float (i.e., a C double) floatval = libffi.longlong2float(llval) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -111,7 +111,6 @@ types.double) assert pow(2, 3) == 8 - def test_int_args(self): """ DLLEXPORT int sum_xy(int x, int y) @@ -119,10 +118,12 @@ return x+y; } """ + import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint) assert sum_xy(30, 12) == 42 + assert sum_xy(sys.maxint*2, 0) == -2 def test_void_result(self): """ @@ -247,6 +248,9 @@ types.ulong) assert sum_xy(sys.maxint, 12) == sys.maxint+12 assert sum_xy(sys.maxint+1, 12) == sys.maxint+13 + # + res = sum_xy(sys.maxint*2+3, 0) + assert res == 1 def test_unsigned_short_args(self): """ @@ -375,6 +379,9 @@ res = sum_xy(x, y) expected = maxint64 + 3 assert res == expected + # + res = sum_xy(maxint64*2+3, 0) + assert res == 1 def test_byval_argument(self): """ diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -575,10 +575,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -10,6 +10,7 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + 'fromstring': 'interp_support.fromstring', # ufuncs 'abs': 'interp_ufuncs.absolute', diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.error import operationerrfmt, OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit @@ -20,6 +20,8 @@ numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) +all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) class Signature(object): def __init__(self): @@ -45,10 +47,14 @@ return v1 * v2 def div(v1, v2): return v1 / v2 -def pow(v1, v2): +def power(v1, v2): return math.pow(v1, v2) def mod(v1, v2): return math.fmod(v1, v2) +def maximum(v1, v2): + return max(v1, v2) +def minimum(v1, v2): + return min(v1, v2) class BaseArray(Wrappable): def __init__(self): @@ -107,9 +113,137 @@ descr_sub = _binop_impl(sub) descr_mul = _binop_impl(mul) descr_div = _binop_impl(div) - descr_pow = _binop_impl(pow) + descr_pow = _binop_impl(power) descr_mod = _binop_impl(mod) + def _binop_right_impl(function): + signature = Signature() + def impl(self, space, w_other): + new_sig = self.signature.transition(signature) + w_other = FloatWrapper(space.float_w(w_other)) + res = Call2( + function, + w_other, + self, + new_sig.transition(w_other.signature) + ) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, + "binop_right_%s_impl" % function.__name__) + + descr_radd = _binop_right_impl(add) + descr_rsub = _binop_right_impl(sub) + descr_rmul = _binop_right_impl(mul) + descr_rdiv = _binop_right_impl(div) + descr_rpow = _binop_right_impl(power) + descr_rmod = _binop_right_impl(mod) + + def _reduce_sum_prod_impl(function, init): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + return space.wrap(loop(self, init, self.find_size())) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_max_min_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, result, size): + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, self.eval(0), size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_argmax_argmin_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self', 'cur_best']) + def loop(self, size): + result = 0 + cur_best = self.eval(0) + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result, cur_best=cur_best) + new_best = function(cur_best, self.eval(i)) + if new_best != cur_best: + result = i + cur_best = new_best + i += 1 + return result + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, size)) + return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) + + def _all(self): + size = self.find_size() + i = 0 + while i < size: + all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if not self.eval(i): + return False + i += 1 + return True + def descr_all(self, space): + return space.wrap(self._all()) + + def _any(self): + size = self.find_size() + i = 0 + while i < size: + any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if self.eval(i): + return True + i += 1 + return False + def descr_any(self, space): + return space.wrap(self._any()) + + descr_sum = _reduce_sum_prod_impl(add, 0.0) + descr_prod = _reduce_sum_prod_impl(mul, 1.0) + descr_max = _reduce_max_min_impl(maximum) + descr_min = _reduce_max_min_impl(minimum) + descr_argmax = _reduce_argmax_argmin_impl(maximum) + descr_argmin = _reduce_argmax_argmin_impl(minimum) + + def descr_dot(self, space, w_other): + if isinstance(w_other, BaseArray): + w_res = self.descr_mul(space, w_other) + assert isinstance(w_res, BaseArray) + return w_res.descr_sum(space) + else: + return self.descr_mul(space, w_other) + def get_concrete(self): raise NotImplementedError @@ -136,13 +270,7 @@ return self.get_concrete().descr_setitem(space, item, value) def descr_mean(self, space): - s = 0 - concrete = self.get_concrete() - size = concrete.find_size() - for i in xrange(size): - s += concrete.getitem(i) - return space.wrap(s / size) - + return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) class FloatWrapper(BaseArray): """ @@ -389,6 +517,21 @@ __div__ = interp2app(BaseArray.descr_div), __pow__ = interp2app(BaseArray.descr_pow), __mod__ = interp2app(BaseArray.descr_mod), + __radd__ = interp2app(BaseArray.descr_radd), + __rsub__ = interp2app(BaseArray.descr_rsub), + __rmul__ = interp2app(BaseArray.descr_rmul), + __rdiv__ = interp2app(BaseArray.descr_rdiv), + __rpow__ = interp2app(BaseArray.descr_rpow), + __rmod__ = interp2app(BaseArray.descr_rmod), mean = interp2app(BaseArray.descr_mean), + sum = interp2app(BaseArray.descr_sum), + prod = interp2app(BaseArray.descr_prod), + max = interp2app(BaseArray.descr_max), + min = interp2app(BaseArray.descr_min), + argmax = interp2app(BaseArray.descr_argmax), + argmin = interp2app(BaseArray.descr_argmin), + all = interp2app(BaseArray.descr_all), + any = interp2app(BaseArray.descr_any), + dot = interp2app(BaseArray.descr_dot), ) diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_support.py @@ -0,0 +1,32 @@ + +from pypy.rlib.rstruct.runpack import runpack +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.error import OperationError +from pypy.module.micronumpy.interp_numarray import SingleDimArray + +FLOAT_SIZE = rffi.sizeof(lltype.Float) + + at unwrap_spec(s=str) +def fromstring(space, s): + length = len(s) + + if length % FLOAT_SIZE == 0: + number = length/FLOAT_SIZE + else: + raise OperationError(space.w_ValueError, space.wrap( + "string length %d not divisable by %d" % (length, FLOAT_SIZE))) + + a = SingleDimArray(number) + + start = 0 + end = FLOAT_SIZE + i = 0 + while i < number: + part = s[start:end] + a.storage[i] = runpack('d', part) + i += 1 + start += FLOAT_SIZE + end += FLOAT_SIZE + + return space.wrap(a) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1,6 +1,7 @@ import py from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest +from pypy.conftest import gettestobjspace class AppTestNumArray(BaseNumpyAppTest): @@ -276,7 +277,97 @@ assert d[1] == 12 def test_mean(self): - from numpy import array, mean + from numpy import array a = array(range(5)) assert a.mean() == 2.0 assert a[:4].mean() == 1.5 + + def test_sum(self): + from numpy import array + a = array(range(5)) + assert a.sum() == 10.0 + assert a[:4].sum() == 6.0 + + def test_prod(self): + from numpy import array + a = array(range(1,6)) + assert a.prod() == 120.0 + assert a[:4].prod() == 24.0 + + def test_max(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.max() == 5.7 + b = array([]) + raises(ValueError, "b.max()") + + def test_max_add(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert (a+a).max() == 11.4 + + def test_min(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.min() == -3.0 + b = array([]) + raises(ValueError, "b.min()") + + def test_argmax(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmax() == 2 + b = array([]) + raises(ValueError, "b.argmax()") + + def test_argmin(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmin() == 3 + b = array([]) + raises(ValueError, "b.argmin()") + + def test_all(self): + from numpy import array + a = array(range(5)) + assert a.all() == False + a[0] = 3.0 + assert a.all() == True + b = array([]) + assert b.all() == True + + def test_any(self): + from numpy import array, zeros + a = array(range(5)) + assert a.any() == True + b = zeros(5) + assert b.any() == False + c = array([]) + assert c.any() == False + + def test_dot(self): + from numpy import array + a = array(range(5)) + assert a.dot(a) == 30.0 + + def test_dot_constant(self): + from numpy import array + a = array(range(5)) + b = a.dot(2.5) + for i in xrange(5): + assert b[i] == 2.5*a[i] + + +class AppTestSupport(object): + def setup_class(cls): + import struct + cls.space = gettestobjspace(usemodules=('micronumpy',)) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + + def test_fromstring(self): + from numpy import fromstring + a = fromstring(self.data) + for i in range(4): + assert a[i] == i + 1 + raises(ValueError, fromstring, "abc") + diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -4,9 +4,13 @@ FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile +from pypy.rlib.objectmodel import specialize class FakeSpace(object): - pass + w_ValueError = None + @specialize.argtype(1) + def wrap(self, v): + return v class TestNumpyJIt(LLJitMixin): def setup_class(cls): @@ -51,6 +55,110 @@ assert result == f(5) + def test_sum(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_sum(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 2, + "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_prod(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_prod(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_max(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_max(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_gt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, + "guard_false": 1, "jump": 1}) + + def test_min(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_min(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_argmin(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_argmin(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_all(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = 1.0 + j += 1 + return ar.descr_add(space, ar).descr_all(space) + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, + "int_lt": 1, "guard_true": 2, "jump": 1}) + + def test_any(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_any(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, "guard_false": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + def test_already_forecd(self): def f(i): ar = SingleDimArray(i) diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -19,7 +19,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) + guard_true(i7, descr=...) i9 = int_add(i5, 1) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) @@ -39,11 +39,12 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated(descr=...) i13 = int_lt(i7, i9) - guard_true(i13, descr=) + guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = int_add(i7, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) @@ -68,16 +69,17 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i13 = int_lt(i8, 307200) - guard_true(i13, descr=) + guard_true(i13, descr=...) + guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) # on 64bit, there is a guard checking that i19 actually fits into 32bit ... setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -80,19 +80,19 @@ # assert entry_bridge.match_by_id('call', """ p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) + guard_nonnull_class(p29, ConstClass(Function), descr=...) p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) + guard_value(p33, ConstPtr(ptr34), descr=...) p35 = getfield_gc(p29, descr=) p36 = getfield_gc(p29, descr=) p38 = call(ConstClass(getexecutioncontext), descr=) p39 = getfield_gc(p38, descr=) i40 = force_token() p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) + guard_isnull(p41, descr=...) i42 = getfield_gc(p38, descr=) i43 = int_is_zero(i42) - guard_true(i43, descr=) + guard_true(i43, descr=...) i50 = force_token() """) # @@ -101,16 +101,16 @@ loop, = log.loops_by_id('call') assert loop.match(""" i12 = int_lt(i5, i6) - guard_true(i12, descr=) + guard_true(i12, descr=...) i13 = force_token() i15 = int_add(i5, 1) i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) """) @@ -146,14 +146,14 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i15 = int_lt(i6, i9) - guard_true(i15, descr=) - guard_not_invalidated(descr=) + guard_true(i15, descr=...) + guard_not_invalidated(descr=...) i16 = force_token() i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) """) @@ -180,11 +180,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) - guard_not_invalidated(descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = force_token() i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() --TICK-- jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) @@ -281,25 +281,23 @@ loop0, = log.loops_by_id('g1') assert loop0.match_by_id('g1', """ i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('h1', """ i20 = force_token() i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('g2', """ i27 = force_token() i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) # loop1, = log.loops_by_id('g3') assert loop1.match_by_id('g3', """ i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) guard_no_overflow(descr=...) """) @@ -352,7 +350,7 @@ i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) p17 = getfield_gc(p8, descr=) p19 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p19, i12, descr=) @@ -404,9 +402,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i10 = int_lt(i5, i6) - guard_true(i10, descr=) + guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i120 = int_add(i5, 1) - guard_not_invalidated(descr=) --TICK-- jump(..., descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py --- a/pypy/module/pypyjit/test_pypy_c/test_exception.py +++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py @@ -36,11 +36,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i5 = int_is_true(i3) - guard_true(i5, descr=) - guard_not_invalidated(descr=) + guard_true(i5, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -84,8 +84,8 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i4, i5) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i14 = int_add(i4, 1) --TICK-- diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -0,0 +1,30 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGlobals(BaseTestPyPyC): + def test_load_builtin(self): + def main(n): + import pypyjit + + i = 0 + while i < n: + l = len # ID: loadglobal + i += pypyjit.residual_call(l, "a") + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("loadglobal", """ + p10 = getfield_gc(p0, descr=) + guard_value(p10, ConstPtr(ptr11), descr=...) + p12 = getfield_gc(p10, descr=) + guard_value(p12, ConstPtr(ptr13), descr=...) + p15 = getfield_gc(ConstPtr(ptr14), descr=) + guard_isnull(p15, descr=...) + guard_not_invalidated(descr=...) + p19 = getfield_gc(ConstPtr(p17), descr=) + guard_value(p19, ConstPtr(ptr20), descr=...) + p22 = getfield_gc(ConstPtr(ptr21), descr=) + guard_nonnull(p22, descr=...) + """) \ No newline at end of file diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py --- a/pypy/module/pypyjit/test_pypy_c/test_import.py +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -15,13 +15,13 @@ assert log.result == 500 loop, = log.loops_by_id('import') assert loop.match_by_id('import', """ + guard_not_invalidated(descr=...) p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) + guard_value(p11, ConstPtr(ptr12), descr=...) p14 = getfield_gc(ConstPtr(ptr13), descr=) p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) + guard_value(p14, ConstPtr(ptr17), descr=...) + guard_isnull(p16, descr=...) """) def test_import_fast_path(self, tmpdir): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -22,10 +22,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) """) @@ -47,10 +47,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = int_lt(i5, i6) - guard_true(i9, descr=) - guard_not_invalidated(descr=) + guard_true(i9, descr=...) + guard_not_invalidated(descr=...) i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -17,6 +17,7 @@ assert loop.match(""" i7 = int_lt(i4, 300) guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 3000) guard_no_overflow(descr=...) i11 = int_add(i4, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -84,7 +84,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = float_lt(f5, f7) - guard_true(i9, descr=) + guard_true(i9, descr=...) f10 = float_add(f8, f5) --TICK-- jump(p0, p1, p2, p3, p4, f10, p6, f7, f8, descr=) @@ -107,19 +107,19 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i11, i12) - guard_false(i16, descr=) + guard_false(i16, descr=...) i17 = int_mul(i11, i14) i18 = int_add(i15, i17) i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=) + guard_not_invalidated(descr=...) i23 = int_lt(i18, 0) - guard_false(i23, descr=) + guard_false(i23, descr=...) i25 = int_ge(i18, i9) - guard_false(i25, descr=) + guard_false(i25, descr=...) i27 = int_add_ovf(i7, i18) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -164,20 +164,20 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i12, i13) - guard_false(i16, descr=) + guard_false(i16, descr=...) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) - guard_nonnull_class(p17, 146982464, descr=) + guard_nonnull_class(p17, 146982464, descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) - guard_true(i23, descr=) + guard_true(i23, descr=...) i24 = getfield_gc(p17, descr=) i25 = getarrayitem_raw(i24, 0, descr=<.*>) i27 = int_lt(1, i21) - guard_false(i27, descr=) + guard_false(i27, descr=...) i28 = int_add_ovf(i10, i25) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) @@ -201,9 +201,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i11 = int_lt(i7, 300) - guard_true(i11, descr=) + guard_true(i11, descr=...) i12 = int_add_ovf(i8, i9) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i14 = int_add(i7, 1) --TICK-- jump(..., descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -16,27 +16,92 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = int_mod(i6, i10) i17 = int_rshift(i15, 63) i18 = int_and(i10, i17) i19 = int_add(i15, i18) i21 = int_lt(i19, 0) - guard_false(i21, descr=) + guard_false(i21, descr=...) i22 = int_ge(i19, i10) - guard_false(i22, descr=) + guard_false(i22, descr=...) i23 = strgetitem(p11, i19) i24 = int_ge(i19, i12) - guard_false(i24, descr=) + guard_false(i24, descr=...) i25 = unicodegetitem(p13, i19) - guard_not_invalidated(descr=) p27 = newstr(1) strsetitem(p27, 0, i23) p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) - guard_true(i32, descr=) + guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) + + def test_long(self): + def main(n): + import string + i = 1 + while i < n: + i += int(long(string.digits[i % len(string.digits)], 16)) + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i13 = int_eq(i6, -9223372036854775808) + guard_false(i13, descr=...) + i15 = int_mod(i6, i8) + i17 = int_rshift(i15, 63) + i18 = int_and(i8, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i8) + guard_false(i22, descr=...) + i23 = strgetitem(p10, i19) + p25 = newstr(1) + strsetitem(p25, 0, i23) + p28 = call(ConstClass(strip_spaces), p25, descr=) + guard_no_exception(descr=...) + i29 = strlen(p28) + i30 = int_is_true(i29) + guard_true(i30, descr=...) + i32 = int_sub(i29, 1) + i33 = strgetitem(p28, i32) + i35 = int_eq(i33, 108) + guard_false(i35, descr=...) + i37 = int_eq(i33, 76) + guard_false(i37, descr=...) + i39 = strgetitem(p28, 0) + i41 = int_eq(i39, 45) + guard_false(i41, descr=...) + i43 = int_eq(i39, 43) + guard_false(i43, descr=...) + i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=) + guard_false(i43, descr=...) + i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=) + guard_false(i46, descr=...) + p51 = new_with_vtable(21136408) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, i29, descr=) + setfield_gc(p51, 1, descr=) + setfield_gc(p51, 16, descr=) + setfield_gc(p51, p28, descr=) + p55 = call(ConstClass(parse_digit_string), p51, descr=) + guard_no_exception(descr=...) + i57 = call(ConstClass(rbigint.toint), p55, descr=) + guard_no_exception(descr=...) + i58 = int_add_ovf(i6, i57) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) """) \ No newline at end of file diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -132,6 +132,17 @@ # You cannot assing character format codes as restype any longer raises(TypeError, setattr, f, "restype", "i") + + def test_truncate_python_longs(self): + py.test.skip("fixme") + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_int + x = sys.maxint * 2 + result = f(0, 0, x, 0, 0, 0) + assert result == 2 + + def test_floatresult(self): f = dll._testfunc_f_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] @@ -411,6 +422,23 @@ result = f("abcd", ord("b")) assert result == "bcd" + def test_keepalive_buffers(self, monkeypatch): + import gc + f = dll.my_strchr + f.argtypes = [c_char_p] + f.restype = c_char_p + # + orig__call_funcptr = f._call_funcptr + def _call_funcptr(funcptr, *newargs): + gc.collect() + gc.collect() + gc.collect() + return orig__call_funcptr(funcptr, *newargs) + monkeypatch.setattr(f, '_call_funcptr', _call_funcptr) + # + result = f("abcd", ord("b")) + assert result == "bcd" + def test_caching_bug_1(self): # the same test as test_call_some_args, with two extra lines # in the middle that trigger caching in f._ptr, which then diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py @@ -12,7 +12,7 @@ from _ctypes.function import CFuncPtr def guess(value): - cobj, ctype = CFuncPtr._conv_param(None, value) + _, cobj, ctype = CFuncPtr._conv_param(None, value) return ctype ## cobj = CFuncPtr._conv_param(None, value) ## return type(cobj) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -736,6 +736,8 @@ class W_DictMultiIterObject(W_Object): from pypy.objspace.std.dicttype import dictiter_typedef as typedef + _immutable_fields_ = ["iteratorimplementation", "itertype"] + def __init__(w_self, space, iteratorimplementation, itertype): w_self.space = space w_self.iteratorimplementation = iteratorimplementation diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -486,6 +486,11 @@ return True + def ll_startswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[0] == ch + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) @@ -503,6 +508,11 @@ return True + def ll_endswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[len(s.chars) - 1] == ch + @elidable def ll_find_char(s, ch, start, end): i = start diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -256,10 +256,6 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - class Cls(self.AddressStack): - def append(self2, addr): - assert addr not in self2.tolist() - self.AddressStack.append(self2, addr) self.objects_pointing_to_young = self.AddressStack() # # Similar to 'objects_pointing_to_young', but lists objects diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -433,7 +433,9 @@ "ll_streq": Meth([self.SELFTYPE_T], Bool), "ll_strcmp": Meth([self.SELFTYPE_T], Signed), "ll_startswith": Meth([self.SELFTYPE_T], Bool), + "ll_startswith_char": Meth([self.CHAR], Bool), "ll_endswith": Meth([self.SELFTYPE_T], Bool), + "ll_endswith_char": Meth([self.CHAR], Bool), "ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed), @@ -1429,10 +1431,18 @@ # NOT_RPYTHON return self._str.startswith(s._str) + def ll_startswith_char(self, s): + # NOT_RPYTHON + return self._str.startswith(s) + def ll_endswith(self, s): # NOT_RPYTHON return self._str.endswith(s._str) + def ll_endswith_char(self, s): + # NOT_RPYTHON + return self._str.endswith(s) + def ll_find(self, s, start, end): # NOT_RPYTHON if start > len(self._str): # workaround to cope with corner case diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -667,7 +667,6 @@ res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res -ll_pop.oopspec = 'list.pop(l, index)' def ll_reverse(l): length = l.ll_length() diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py --- a/pypy/rpython/rstr.py +++ b/pypy/rpython/rstr.py @@ -81,16 +81,30 @@ return super(AbstractStringRepr, self).rtype_is_true(hop) def rtype_method_startswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_startswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_startswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_endswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_endswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_endswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_find(self, hop, reverse=False): # XXX binaryop diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -227,6 +227,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_startswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].startswith('o') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_endswith(self): const = self.const def fn(i, j): @@ -238,6 +247,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_endswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].endswith('e') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_find(self): const = self.const def fn(i, j): diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,7 +1,8 @@ import re, sys -from pypy.jit.metainterp.resoperation import rop, opname +from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser +from pypy.tool.logparser import parse_log_file, extract_category class Op(object): bridge = None @@ -57,7 +58,7 @@ use_mock_model = True def postprocess(self, loop, backend_dump=None, backend_tp=None, - loop_start=0, dump_start=0): + dump_start=0): if backend_dump is not None: raw_asm = self._asm_disassemble(backend_dump.decode('hex'), backend_tp, dump_start) @@ -329,3 +330,33 @@ res.append(op) i += 1 return res + + +def import_log(logname, ParserCls=SimpleParser): + log = parse_log_file(logname) + addrs = {} + for entry in extract_category(log, 'jit-backend-addr'): + m = re.search('bootstrap ([\da-f]+)', entry) + name = entry[:entry.find('(') - 1] + addrs[int(m.group(1), 16)] = name + dumps = {} + for entry in extract_category(log, 'jit-backend-dump'): + backend, _, dump, _ = entry.split("\n") + _, addr, _, data = re.split(" +", dump) + backend_name = backend.split(" ")[1] + addr = int(addr[1:], 16) + if addr in addrs: + dumps[addrs[addr]] = (backend_name, addr, data) + loops = [] + for entry in extract_category(log, 'jit-log-opt'): + parser = ParserCls(entry, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + comm = loop.comment + name = comm[2:comm.find(':')-1] + if name in dumps: + bname, start_ofs, dump = dumps[name] + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) + loops.append(loop) + return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -0,0 +1,38 @@ +[11f210b47027] {jit-backend +[11f210b900f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 +[11f210b949b3] jit-backend-dump} +[11f210b949b4] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab188] jit-backend-addr} +[11f210bab189] jit-backend} +[11f210bacbb7] {jit-log-opt-loop +# Loop 0 : loop with 19 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 INPLACE_ADD') ++179: i8 = int_add(i4, 1) +debug_merge_point(0, ' #28 STORE_FAST') +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++183: i10 = getfield_raw(40564608, descr=) ++191: i12 = int_sub(i10, 1) ++195: setfield_raw(40564608, i12, descr=) ++203: i14 = int_lt(i12, 0) +guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++213: jump(p0, p1, p2, p3, i8, descr=) ++218: --end of the loop-- +[11f210c17981] jit-log-opt-loop} +[11f210fb1d21] {jit-backend-counts +0:8965 +1:2 +[11f210fb381b] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,9 +1,8 @@ -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, Const -from pypy.tool.jitlogparser.parser import SimpleParser, TraceForOpcode, Function,\ - adjust_bridges +from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, + Function, adjust_bridges, + import_log) from pypy.tool.jitlogparser.storage import LoopStorage -import py +import py, sys def parse(input, **kwds): return SimpleParser.parse_from_input(input, **kwds) @@ -111,6 +110,8 @@ assert res.chunks[1].lineno == 3 def test_linerange(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] @@ -125,6 +126,8 @@ assert res.lineset == set([7, 8, 9]) def test_linerange_notstarts(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] @@ -201,9 +204,13 @@ +213: jump(p0, p1, p2, p3, i8, descr=) +218: --end of the loop--""", backend_dump=backend_dump, dump_start=dump_start, - backend_tp='x86_64', - loop_start=0x7f3b0b2e645d) + backend_tp='x86_64') cmp = loop.operations[1] assert 'jge' in cmp.asm assert '0x2710' in cmp.asm assert 'jmp' in loop.operations[-1].asm + +def test_import_log(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest.log'))) + assert 'jge' in loops[0].operations[3].asm diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -688,28 +688,54 @@ def getothernodes(self): return self.othernodes[:] + def getbasecfilefornode(self, node, basecname): + # For FuncNode instances, use the python source filename (relative to + # the top directory): + if hasattr(node.obj, 'graph'): + g = node.obj.graph + # Lookup the filename from the function. + # However, not all FunctionGraph objs actually have a "func": + if hasattr(g, 'func'): + if g.filename.endswith('.py'): + localpath = py.path.local(g.filename) + pypkgpath = localpath.pypkgpath() + if pypkgpath: + relpypath = localpath.relto(pypkgpath) + return relpypath.replace('.py', '.c') + return basecname + def splitnodesimpl(self, basecname, nodes, nextra, nbetween, split_criteria=SPLIT_CRITERIA): + # Gather nodes by some criteria: + nodes_by_base_cfile = {} + for node in nodes: + c_filename = self.getbasecfilefornode(node, basecname) + if c_filename in nodes_by_base_cfile: + nodes_by_base_cfile[c_filename].append(node) + else: + nodes_by_base_cfile[c_filename] = [node] + # produce a sequence of nodes, grouped into files # which have no more than SPLIT_CRITERIA lines - iternodes = iter(nodes) - done = [False] - def subiter(): - used = nextra - for node in iternodes: - impl = '\n'.join(list(node.implementation())).split('\n') - if not impl: - continue - cost = len(impl) + nbetween - yield node, impl - del impl - if used + cost > split_criteria: - # split if criteria met, unless we would produce nothing. - raise StopIteration - used += cost - done[0] = True - while not done[0]: - yield self.uniquecname(basecname), subiter() + for basecname in nodes_by_base_cfile: + iternodes = iter(nodes_by_base_cfile[basecname]) + done = [False] + def subiter(): + used = nextra + for node in iternodes: + impl = '\n'.join(list(node.implementation())).split('\n') + if not impl: + continue + cost = len(impl) + nbetween + yield node, impl + del impl + if used + cost > split_criteria: + # split if criteria met, unless we would produce nothing. + raise StopIteration + used += cost + done[0] = True + while not done[0]: + yield self.uniquecname(basecname), subiter() def gen_readable_parts_of_source(self, f): split_criteria_big = SPLIT_CRITERIA diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -55,6 +55,13 @@ data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + # Verify that the generated C files have sane names: + gen_c_files = [str(f) for f in cbuilder.extrafiles] + for expfile in ('rlib_rposix.c', + 'rpython_lltypesystem_rstr.c', + 'translator_c_test_test_standalone.c'): + assert cbuilder.targetdir.join(expfile) in gen_c_files + def test_print(self): def entry_point(argv): print "hello simpler world" From noreply at buildbot.pypy.org Tue Jul 12 13:01:25 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 12 Jul 2011 13:01:25 +0200 (CEST) Subject: [pypy-commit] pypy default: unskip and improve the test Message-ID: <20110712110125.D81C282108@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45505:3bf39b9f938f Date: 2011-07-12 13:00 +0200 http://bitbucket.org/pypy/pypy/changeset/3bf39b9f938f/ Log: unskip and improve the test diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -134,13 +134,12 @@ def test_truncate_python_longs(self): - py.test.skip("fixme") f = dll._testfunc_i_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] f.restype = c_int x = sys.maxint * 2 - result = f(0, 0, x, 0, 0, 0) - assert result == 2 + result = f(x, x, x, x, 0, 0) + assert result == -8 def test_floatresult(self): From noreply at buildbot.pypy.org Tue Jul 12 13:39:51 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 12 Jul 2011 13:39:51 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Need to typecheck all callbacks from enqueue_for_destruction(). Message-ID: <20110712113951.0D0B682108@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45506:0605e5c98e8a Date: 2011-07-12 13:23 +0200 http://bitbucket.org/pypy/pypy/changeset/0605e5c98e8a/ Log: Need to typecheck all callbacks from enqueue_for_destruction(). diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -156,6 +156,9 @@ At a later, safe point in time, UserDelAction will call callback(self). If that raises OperationError, prints it to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -144,11 +145,11 @@ def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): + self.clear_all_weakrefs() self.enqueue_for_destruction(self.space, GeneratorIterator.descr_close, "interrupting generator of ") diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -234,13 +234,19 @@ if "del" in features: parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): self.clear_all_weakrefs() self.enqueue_for_destruction(self.space, call_applevel_del, 'method __del__ of ') if parent_destructor is not None: - self.enqueue_for_destruction(self.space, parent_destructor, + self.enqueue_for_destruction(self.space, call_parent_del, 'internal destructor of ') add(Proto) @@ -293,9 +299,6 @@ return w_dict check_new_dictionary._dont_inline_ = True -def call_applevel_del(self): - self.space.userdel(self) - # ____________________________________________________________ @specialize.arg(0) diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -52,6 +52,7 @@ 'close() method of ') def report_streamerror(self): + assert isinstance(self, W_File) operr = wrap_streamerror(self.space, self.streamerror_upon_closing, self.w_name) raise operr diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -61,6 +61,7 @@ 'internal __del__ of ') def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -120,6 +120,7 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): + assert isinstance(w_self, W_WeakrefBase) w_self.space.call_function(w_self.w_callable, w_self) def descr__repr__(self, space): From noreply at buildbot.pypy.org Tue Jul 12 13:39:52 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 12 Jul 2011 13:39:52 +0200 (CEST) Subject: [pypy-commit] pypy default: (wlav, arigo) Support the simple case of direct_ptradd(). Message-ID: <20110712113952.45A2D82108@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45507:fcfaef748c13 Date: 2011-07-12 13:38 +0200 http://bitbucket.org/pypy/pypy/changeset/fcfaef748c13/ Log: (wlav, arigo) Support the simple case of direct_ptradd(). diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -800,6 +800,13 @@ result[-1].result = op.result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -813,6 +813,15 @@ int_return %i0 """, transform=True) + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" From noreply at buildbot.pypy.org Tue Jul 12 13:39:53 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 12 Jul 2011 13:39:53 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (wlav, arigo) Support the simple case of direct_ptradd(). Message-ID: <20110712113953.7264282108@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: reflex-support Changeset: r45508:ce9c837a3361 Date: 2011-07-12 13:38 +0200 http://bitbucket.org/pypy/pypy/changeset/ce9c837a3361/ Log: (wlav, arigo) Support the simple case of direct_ptradd(). diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -800,6 +800,13 @@ result[-1].result = op.result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -813,6 +813,15 @@ int_return %i0 """, transform=True) + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" From noreply at buildbot.pypy.org Tue Jul 12 13:39:54 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 12 Jul 2011 13:39:54 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110712113954.99B7C82108@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45509:4480dd03bc6a Date: 2011-07-12 13:39 +0200 http://bitbucket.org/pypy/pypy/changeset/4480dd03bc6a/ Log: merge heads diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -134,13 +134,12 @@ def test_truncate_python_longs(self): - py.test.skip("fixme") f = dll._testfunc_i_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] f.restype = c_int x = sys.maxint * 2 - result = f(0, 0, x, 0, 0, 0) - assert result == 2 + result = f(x, x, x, x, 0, 0) + assert result == -8 def test_floatresult(self): From noreply at buildbot.pypy.org Tue Jul 12 14:40:54 2011 From: noreply at buildbot.pypy.org (RonnyPfannschmidt) Date: Tue, 12 Jul 2011 14:40:54 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: merge Message-ID: <20110712124054.E004382108@wyvern.cs.uni-duesseldorf.de> Author: Ronny Pfannschmidt Branch: extradoc Changeset: r206:906ee8c1b535 Date: 2011-07-12 14:39 +0200 http://bitbucket.org/pypy/pypy.org/changeset/906ee8c1b535/ Log: merge diff --git a/source/README b/source/README --- a/source/README +++ b/source/README @@ -1,17 +1,11 @@ You can get necessary software by doing: -git clone https://github.com/tav/ampify.git + pip install yatiblog -and then recreate the website in this directory by running +(tested with version 1.0) you can do: -ampify/environ/yatiblog -o .. + yatiblog -o .. you'll get html output in the parent directory. you need an account -on ep.io for updating. - -Other required dependencies: - * "docutils" from "easy_install docutils" - * "simplejson" from "easy_install simplejson" - * "genshi" from "easy_install genshi" - * "pygments" from "easy_install pygments" - * "yaml" from "apt-get install libyaml-dev", "easy_install pyyaml" +Then you can check it in, login to pypy at pypy.org +and go to pypy.org/htdocs/ and type "hg pull -u". From noreply at buildbot.pypy.org Tue Jul 12 14:50:34 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 12 Jul 2011 14:50:34 +0200 (CEST) Subject: [pypy-commit] pypy default: merge implicit type conversion branch Message-ID: <20110712125034.0E53B82108@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45510:80b39541afcd Date: 2011-07-12 14:48 +0200 http://bitbucket.org/pypy/pypy/changeset/80b39541afcd/ Log: merge implicit type conversion branch diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -925,6 +925,9 @@ return self.w_True return self.w_False + def issequence_w(self, w_obj): + return (self.findattr(w_obj, self.wrap("__getitem__")) is not None) + def isinstance_w(self, w_obj, w_type): return self.is_true(self.isinstance(w_obj, w_type)) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt, OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit @@ -7,7 +7,6 @@ from pypy.tool.sourcetools import func_with_new_name import math - def dummy1(v): assert isinstance(v, float) return v @@ -88,23 +87,15 @@ def _binop_impl(function): signature = Signature() def impl(self, space, w_other): + w_other = convert_to_array(space, w_other) new_sig = self.signature.transition(signature) - if isinstance(w_other, BaseArray): - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - else: - w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) + res = Call2( + function, + self, + w_other, + new_sig.transition(w_other.signature) + ) + w_other.invalidates.append(res) self.invalidates.append(res) return space.wrap(res) return func_with_new_name(impl, "binop_%s_impl" % function.__name__) @@ -272,6 +263,16 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) +def convert_to_array (space, w_obj): + if isinstance(w_obj, BaseArray): + return w_obj + elif space.issequence_w(w_obj): + # Convert to array. + return new_numarray(space, w_obj) + else: + # If it's a scalar + return FloatWrapper(space.float_w(w_obj)) + class FloatWrapper(BaseArray): """ Intermediate class representing a float literal. @@ -478,14 +479,17 @@ def __del__(self): lltype.free(self.storage, flavor='raw') -def descr_new_numarray(space, w_type, w_size_or_iterable): +def new_numarray(space, w_size_or_iterable): l = space.listview(w_size_or_iterable) arr = SingleDimArray(len(l)) i = 0 for w_elem in l: arr.storage[i] = space.float_w(space.float(w_elem)) i += 1 - return space.wrap(arr) + return arr + +def descr_new_numarray(space, w_type, w_size_or_iterable): + return space.wrap(new_numarray(space, w_size_or_iterable)) @unwrap_spec(size=int) def zeros(space, size): diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,31 +1,35 @@ import math from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature +from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name - def ufunc(func): signature = Signature() def impl(space, w_obj): - if isinstance(w_obj, BaseArray): - w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) - w_obj.invalidates.append(w_res) + if space.issequence_w(w_obj): + w_obj_arr = convert_to_array(space, w_obj) + w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) + w_obj_arr.invalidates.append(w_res) return w_res - return space.wrap(func(space.float_w(w_obj))) + else: + return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): - if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): - new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) - w_res = Call2(func, w_lhs, w_rhs, new_sig) - w_lhs.invalidates.append(w_res) - w_rhs.invalidates.append(w_res) + if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): + w_lhs_arr = convert_to_array(space, w_lhs) + w_rhs_arr = convert_to_array(space, w_rhs) + new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature) + w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig) + w_lhs_arr.invalidates.append(w_res) + w_rhs_arr.invalidates.append(w_res) return w_res - return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) + else: + return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @ufunc diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -1,12 +1,10 @@ from pypy.conftest import gettestobjspace from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper - class BaseNumpyAppTest(object): def setup_class(cls): cls.space = gettestobjspace(usemodules=('micronumpy',)) - class TestSignature(object): def test_binop_signature(self, space): ar = SingleDimArray(10) @@ -26,4 +24,4 @@ v3 = ar.descr_add(space, v1) v4 = ar.descr_add(space, v2) - assert v3.signature is v4.signature \ No newline at end of file + assert v3.signature is v4.signature diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -97,6 +97,15 @@ for i in range(5): assert b[i] == i + 5 + def test_add_list(self): + from numpy import array + a = array(range(5)) + b = list(reversed(range(5))) + c = a + b + assert isinstance(c, array) + for i in range(5): + assert c[i] == 4 + def test_subtract(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -10,6 +10,40 @@ assert sign(-0.0) == 0.0 assert minimum(2.0, 3.0) == 2.0 + def test_sequence(self): + from numpy import array, negative, minimum + a = array(range(3)) + b = [2.0, 1.0, 0.0] + c = 1.0 + b_neg = negative(b) + assert isinstance(b_neg, array) + for i in range(3): + assert b_neg[i] == -b[i] + min_a_b = minimum(a, b) + assert isinstance(min_a_b, array) + for i in range(3): + assert min_a_b[i] == min(a[i], b[i]) + min_b_a = minimum(b, a) + assert isinstance(min_b_a, array) + for i in range(3): + assert min_b_a[i] == min(a[i], b[i]) + min_a_c = minimum(a, c) + assert isinstance(min_a_c, array) + for i in range(3): + assert min_a_c[i] == min(a[i], c) + min_c_a = minimum(c, a) + assert isinstance(min_c_a, array) + for i in range(3): + assert min_c_a[i] == min(a[i], c) + min_b_c = minimum(b, c) + assert isinstance(min_b_c, array) + for i in range(3): + assert min_b_c[i] == min(b[i], c) + min_c_b = minimum(c, b) + assert isinstance(min_c_b, array) + for i in range(3): + assert min_c_b[i] == min(b[i], c) + def test_negative(self): from numpy import array, negative diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -8,9 +8,16 @@ class FakeSpace(object): w_ValueError = None + + def issequence_w(self, w_obj): + return True + @specialize.argtype(1) - def wrap(self, v): - return v + def wrap(self, w_obj): + return w_obj + + def float_w(self, w_obj): + return float(w_obj) class TestNumpyJIt(LLJitMixin): def setup_class(cls): From noreply at buildbot.pypy.org Tue Jul 12 14:50:35 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 12 Jul 2011 14:50:35 +0200 (CEST) Subject: [pypy-commit] pypy numpy-impicit-convert: close merged branch Message-ID: <20110712125035.364BE82108@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: numpy-impicit-convert Changeset: r45511:b7e01d83d985 Date: 2011-07-12 14:48 +0200 http://bitbucket.org/pypy/pypy/changeset/b7e01d83d985/ Log: close merged branch From noreply at buildbot.pypy.org Tue Jul 12 14:50:36 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 12 Jul 2011 14:50:36 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110712125036.6619782108@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45512:11343a789981 Date: 2011-07-12 14:50 +0200 http://bitbucket.org/pypy/pypy/changeset/11343a789981/ Log: merge diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -800,6 +800,13 @@ result[-1].result = op.result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -813,6 +813,15 @@ int_return %i0 """, transform=True) + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" From noreply at buildbot.pypy.org Tue Jul 12 15:29:20 2011 From: noreply at buildbot.pypy.org (wlav) Date: Tue, 12 Jul 2011 15:29:20 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (cfbolz, wlav) 64bit support Message-ID: <20110712132920.D5BE182108@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45513:dfa7b7d296fa Date: 2011-07-12 06:24 -0700 http://bitbucket.org/pypy/pypy/changeset/dfa7b7d296fa/ Log: (cfbolz, wlav) 64bit support diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py --- a/pypy/module/cppyy/capi/reflex_capi.py +++ b/pypy/module/cppyy/capi/reflex_capi.py @@ -107,6 +107,10 @@ "cppyy_call_h", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, compilation_info=eci) +c_call_i = rffi.llexternal( + "cppyy_call_l", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, + compilation_info=eci) c_call_l = rffi.llexternal( "cppyy_call_l", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.LONG, diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -100,7 +100,8 @@ address[i] = buf.getitem(i) -class PtrTypeConverter(TypeConverter): +class PtrTypeConverterMixin(object): + _mixin_ = True _immutable_ = True def __init__(self, space, array_size): @@ -204,12 +205,61 @@ address = self._get_raw_address(space, w_obj, offset) address[0] = self._from_space(space, w_value) +class IntConverter(TypeConverter): + _immutable = True + libffitype = libffi.types.sint + + def _unwrap_object(self, space, w_obj): + return rffi.cast(rffi.INT, space.c_int_w(w_obj)) + + def convert_argument(self, space, w_obj): + arg = self._unwrap_object(space, w_obj) + x = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') + x[0] = arg + return rffi.cast(rffi.VOIDP, x) + + def convert_argument_libffi(self, space, w_obj, argchain): + argchain.arg(self._unwrap_object(space, w_obj)) + + def from_memory(self, space, w_obj, offset): + address = self._get_raw_address(space, w_obj, offset) + intptr = rffi.cast(rffi.INTP, address) + return space.wrap(intptr[0]) + + def to_memory(self, space, w_obj, w_value, offset): + address = self._get_raw_address(space, w_obj, offset) + intptr = rffi.cast(rffi.INTP, address) + intptr[0] = self._unwrap_object(space, w_value) + +class UnsignedIntConverter(TypeConverter): + _immutable = True + libffitype = libffi.types.uint + + def _unwrap_object(self, space, w_obj): + return rffi.cast(rffi.UINT, space.uint_w(w_obj)) + + def convert_argument(self, space, w_obj): + arg = self._unwrap_object(space, w_obj) + x = lltype.malloc(rffi.UINTP.TO, 1, flavor='raw') + x[0] = arg + return rffi.cast(rffi.VOIDP, x) + + def from_memory(self, space, w_obj, offset): + address = self._get_raw_address(space, w_obj, offset) + ulongptr = rffi.cast(rffi.UINTP, address) + return space.wrap(ulongptr[0]) + + def to_memory(self, space, w_obj, w_value, offset): + address = self._get_raw_address(space, w_obj, offset) + ulongptr = rffi.cast(rffi.UINTP, address) + ulongptr[0] = self._unwrap_object(space, w_value) + class LongConverter(TypeConverter): _immutable = True libffitype = libffi.types.slong def _unwrap_object(self, space, w_obj): - return space.c_int_w(w_obj) + return space.int_w(w_obj) def convert_argument(self, space, w_obj): arg = self._unwrap_object(space, w_obj) @@ -228,7 +278,7 @@ def to_memory(self, space, w_obj, w_value, offset): address = self._get_raw_address(space, w_obj, offset) longptr = rffi.cast(rffi.LONGP, address) - longptr[0] = space.c_int_w(w_value) + longptr[0] = self._unwrap_object(space, w_value) class UnsignedLongConverter(TypeConverter): _immutable = True @@ -251,7 +301,7 @@ def to_memory(self, space, w_obj, w_value, offset): address = self._get_raw_address(space, w_obj, offset) ulongptr = rffi.cast(rffi.ULONGP, address) - ulongptr[0] = space.c_uint_w(w_value) + ulongptr[0] = self._unwrap_object(space, w_value) class ShortConverter(LongConverter): _immutable = True @@ -287,7 +337,7 @@ def to_memory(self, space, w_obj, w_value, offset): address = self._get_raw_address(space, w_obj, offset) floatptr = rffi.cast(rffi.FLOATP, address) - floatptr[0] = r_singlefloat(space.float_w(w_value)) + floatptr[0] = self._unwrap_object(space, w_value) class DoubleConverter(TypeConverter): _immutable = True @@ -312,7 +362,7 @@ def to_memory(self, space, w_obj, w_value, offset): address = self._get_raw_address(space, w_obj, offset) doubleptr = rffi.cast(rffi.DOUBLEP, address) - doubleptr[0] = space.float_w(w_value) + doubleptr[0] = self._unwrap_object(space, w_value) class CStringConverter(TypeConverter): @@ -327,43 +377,63 @@ class ShortArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'h' - typesize = 2 + typesize = rffi.sizeof(rffi.SHORT) + +class IntArrayConverter(ArrayTypeConverterMixin, TypeConverter): + _immutable_=True + typecode = 'i' + typesize = rffi.sizeof(rffi.INT) + +class UnsignedIntArrayConverter(ArrayTypeConverterMixin, TypeConverter): + _immutable_=True + typecode = 'I' + typesize = rffi.sizeof(rffi.UINT) class LongArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'l' - typesize = 4 + typesize = rffi.sizeof(rffi.LONG) class FloatArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'f' - typesize = 4 + typesize = rffi.sizeof(rffi.FLOAT) class DoubleArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'd' - typesize = 8 + typesize = rffi.sizeof(rffi.DOUBLE) -class ShortPtrConverter(PtrTypeConverter): +class ShortPtrConverter(PtrTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'h' - typesize = 2 + typesize = rffi.sizeof(rffi.SHORT) -class LongPtrConverter(PtrTypeConverter): +class IntPtrConverter(PtrTypeConverterMixin, TypeConverter): + _immutable_=True + typecode = 'i' + typesize = rffi.sizeof(rffi.INT) + +class UnsignedIntPtrConverter(PtrTypeConverterMixin, TypeConverter): + _immutable_=True + typecode = 'I' + typesize = rffi.sizeof(rffi.UINT) + +class LongPtrConverter(PtrTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'l' - typesize = 4 + typesize = rffi.sizeof(rffi.LONG) -class FloatPtrConverter(PtrTypeConverter): +class FloatPtrConverter(PtrTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'f' - typesize = 4 + typesize = rffi.sizeof(rffi.FLOAT) -class DoublePtrConverter(PtrTypeConverter): +class DoublePtrConverter(PtrTypeConverterMixin, TypeConverter): _immutable_=True typecode = 'd' - typesize = 8 + typesize = rffi.sizeof(rffi.DOUBLE) class InstancePtrConverter(TypeConverter): @@ -474,12 +544,12 @@ _converters["unsigned short int"] = ShortConverter _converters["unsigned short int*"] = ShortPtrConverter _converters["unsigned short int[]"] = ShortArrayConverter -_converters["int"] = LongConverter -_converters["int*"] = LongPtrConverter -_converters["int[]"] = LongArrayConverter -_converters["unsigned int"] = UnsignedLongConverter -_converters["unsigned int*"] = LongPtrConverter -_converters["unsigned int[]"] = LongArrayConverter +_converters["int"] = IntConverter +_converters["int*"] = IntPtrConverter +_converters["int[]"] = IntArrayConverter +_converters["unsigned int"] = UnsignedIntConverter +_converters["unsigned int*"] = UnsignedIntPtrConverter +_converters["unsigned int[]"] = UnsignedIntArrayConverter _converters["long int"] = LongConverter _converters["long int*"] = LongPtrConverter _converters["long int[]"] = LongArrayConverter diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -33,7 +33,7 @@ def execute(self, space, func, cppthis, num_args, args): lresult = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) - address = rffi.cast(rffi.UINT, lresult) + address = rffi.cast(rffi.ULONG, lresult) arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode))) return arr.fromaddress(space, address, sys.maxint) @@ -72,6 +72,32 @@ result = capi.c_call_h(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) +class IntExecutor(FunctionExecutor): + _immutable_ = True + libffitype = libffi.types.sint + + def _wrap_result(self, space, result): + return space.wrap(result) + + def execute(self, space, func, cppthis, num_args, args): + result = capi.c_call_i(func.cpptype.handle, func.method_index, cppthis, num_args, args) + return self._wrap_result(space, result) + +# TODO: check whether the following is correct (return type cast): +# def execute_libffi(self, space, libffifunc, argchain): +# return space.wrap(libffifunc.call(argchain, rffi.INT)) + +class UnsignedIntExecutor(FunctionExecutor): + _immutable_ = True + libffitype = libffi.types.uint + + def _wrap_result(self, space, result): + return space.wrap(result) + + def execute(self, space, func, cppthis, num_args, args): + result = capi.c_call_i(func.cpptype.handle, func.method_index, cppthis, num_args, args) + return self._wrap_result(space, result) + class LongExecutor(FunctionExecutor): _immutable_ = True libffitype = libffi.types.slong @@ -86,6 +112,13 @@ def execute_libffi(self, space, libffifunc, argchain): return space.wrap(libffifunc.call(argchain, lltype.Signed)) +class ConstIntRefExecutor(LongExecutor): + _immutable_ = True + + def _wrap_result(self, space, result): + intptr = rffi.cast(rffi.INTP, result) + return space.wrap(intptr[0]) + class ConstLongRefExecutor(LongExecutor): _immutable_ = True @@ -125,6 +158,14 @@ _immutable_ = True typecode = 'h' +class IntPtrExecutor(PtrTypeExecutor): + _immutable_ = True + typecode = 'i' + +class UnsignedIntPtrExecutor(PtrTypeExecutor): + _immutable_ = True + typecode = 'I' + class LongPtrExecutor(PtrTypeExecutor): _immutable_ = True typecode = 'l' @@ -226,12 +267,12 @@ _executors["short int*"] = ShortPtrExecutor _executors["unsigned short int"] = ShortExecutor _executors["unsigned short int*"] = ShortPtrExecutor -_executors["int"] = LongExecutor -_executors["int*"] = LongPtrExecutor -_executors["const int&"] = ConstLongRefExecutor -_executors["int&"] = ConstLongRefExecutor -_executors["unsigned int"] = LongExecutor -_executors["unsigned int*"] = LongPtrExecutor +_executors["int"] = IntExecutor +_executors["int*"] = IntPtrExecutor +_executors["const int&"] = ConstIntRefExecutor +_executors["int&"] = ConstIntRefExecutor +_executors["unsigned int"] = UnsignedIntExecutor +_executors["unsigned int*"] = UnsignedIntPtrExecutor _executors["long int"] = LongExecutor _executors["long int*"] = LongPtrExecutor _executors["unsigned long int"] = LongExecutor diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h --- a/pypy/module/cppyy/include/capi.h +++ b/pypy/module/cppyy/include/capi.h @@ -25,6 +25,7 @@ int cppyy_call_b(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); char cppyy_call_c(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); short cppyy_call_h(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); + int cppyy_call_i(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); long cppyy_call_l(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); double cppyy_call_f(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); double cppyy_call_d(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx --- a/pypy/module/cppyy/src/reflexcwrapper.cxx +++ b/pypy/module/cppyy/src/reflexcwrapper.cxx @@ -151,6 +151,11 @@ return cppyy_call_T(handle, method_index, self, numargs, args); } +int cppyy_call_i(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + return cppyy_call_T(handle, method_index, self, numargs, args); +} + long cppyy_call_l(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]) { return cppyy_call_T(handle, method_index, self, numargs, args); diff --git a/pypy/module/cppyy/test/advancedcpp.cxx b/pypy/module/cppyy/test/advancedcpp.cxx --- a/pypy/module/cppyy/test/advancedcpp.cxx +++ b/pypy/module/cppyy/test/advancedcpp.cxx @@ -25,6 +25,15 @@ int a_ns::d_ns::e_class::f_class::s_f = 66; +// for template testing +template class T1; +template class T2 >; +template class T3; +template class T3, T2 > >; +template class a_ns::T4; +template class a_ns::T4 > >; + + // helpers for checking pass-by-ref void set_int_through_ref(int& i, int val) { i = val; } int pass_int_through_const_ref(const int& i) { return i; } diff --git a/pypy/module/cppyy/test/advancedcpp.h b/pypy/module/cppyy/test/advancedcpp.h --- a/pypy/module/cppyy/test/advancedcpp.h +++ b/pypy/module/cppyy/test/advancedcpp.h @@ -176,12 +176,12 @@ } // namespace a_ns -template class T1; -template class T2 >; -template class T3; -template class T3, T2 > >; -template class a_ns::T4; -template class a_ns::T4 > >; +extern template class T1; +extern template class T2 >; +extern template class T3; +extern template class T3, T2 > >; +extern template class a_ns::T4; +extern template class a_ns::T4 > >; //=========================================================================== diff --git a/pypy/module/cppyy/test/stltypes.cxx b/pypy/module/cppyy/test/stltypes.cxx --- a/pypy/module/cppyy/test/stltypes.cxx +++ b/pypy/module/cppyy/test/stltypes.cxx @@ -1,1 +1,16 @@ #include "stltypes.h" + +#define STLTYPES_EXPLICIT_INSTANTIATION(STLTYPE, TTYPE) \ +template class std::STLTYPE< TTYPE >; \ +template class __gnu_cxx::__normal_iterator >; \ +template class __gnu_cxx::__normal_iterator >;\ +namespace __gnu_cxx { \ +template bool operator==(const std::STLTYPE< TTYPE >::iterator&, \ + const std::STLTYPE< TTYPE >::iterator&); \ +template bool operator!=(const std::STLTYPE< TTYPE >::iterator&, \ + const std::STLTYPE< TTYPE >::iterator&); \ +} + +//- explicit instantiations of used types +STLTYPES_EXPLICIT_INSTANTIATION(vector, int) +STLTYPES_EXPLICIT_INSTANTIATION(vector, just_a_class) diff --git a/pypy/module/cppyy/test/stltypes.h b/pypy/module/cppyy/test/stltypes.h --- a/pypy/module/cppyy/test/stltypes.h +++ b/pypy/module/cppyy/test/stltypes.h @@ -3,14 +3,14 @@ #include #include -#define STLTYPES_EXPLICIT_INSTANTIATION(STLTYPE, TTYPE) \ -template class std::STLTYPE< TTYPE >; \ -template class __gnu_cxx::__normal_iterator >; \ -template class __gnu_cxx::__normal_iterator >;\ +#define STLTYPES_EXPLICIT_INSTANTIATION_DECL(STLTYPE, TTYPE) \ +extern template class std::STLTYPE< TTYPE >; \ +extern template class __gnu_cxx::__normal_iterator >;\ +extern template class __gnu_cxx::__normal_iterator >;\ namespace __gnu_cxx { \ -template bool operator==(const std::STLTYPE< TTYPE >::iterator&, \ +extern template bool operator==(const std::STLTYPE< TTYPE >::iterator&, \ const std::STLTYPE< TTYPE >::iterator&); \ -template bool operator!=(const std::STLTYPE< TTYPE >::iterator&, \ +extern template bool operator!=(const std::STLTYPE< TTYPE >::iterator&, \ const std::STLTYPE< TTYPE >::iterator&); \ } @@ -23,5 +23,5 @@ //- explicit instantiations of used types -STLTYPES_EXPLICIT_INSTANTIATION(vector, int) -STLTYPES_EXPLICIT_INSTANTIATION(vector, just_a_class) +STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, int) +STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, just_a_class) diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -40,7 +40,7 @@ """Test passing of an int, returning of an int, and overloading on a differening number of arguments.""" - import sys + import sys, math t = self.example01 res = t.invoke(t.get_overload("staticAddOneToInt"), 1) @@ -51,14 +51,15 @@ assert res == 4 res = t.invoke(t.get_overload("staticAddOneToInt"), -1) assert res == 0 - res = t.invoke(t.get_overload("staticAddOneToInt"), sys.maxint-1) - assert res == sys.maxint - res = t.invoke(t.get_overload("staticAddOneToInt"), sys.maxint) - assert res == -sys.maxint-1 + maxint32 = int(math.pow(2,31)-1) + res = t.invoke(t.get_overload("staticAddOneToInt"), maxint32-1) + assert res == maxint32 + res = t.invoke(t.get_overload("staticAddOneToInt"), maxint32) + assert res == -maxint32-1 raises(TypeError, 't.invoke(t.get_overload("staticAddOneToInt"), 1, [])') raises(TypeError, 't.invoke(t.get_overload("staticAddOneToInt"), 1.)') - raises(OverflowError, 't.invoke(t.get_overload("staticAddOneToInt"), sys.maxint+1)') + raises(OverflowError, 't.invoke(t.get_overload("staticAddOneToInt"), maxint32+1)') def test_example01static_double(self): diff --git a/pypy/module/cppyy/test/test_datatypes.py b/pypy/module/cppyy/test/test_datatypes.py --- a/pypy/module/cppyy/test/test_datatypes.py +++ b/pypy/module/cppyy/test/test_datatypes.py @@ -30,7 +30,7 @@ lib2 = cppyy.load_lib(self.shared_lib) assert self.datatypes is lib2 - def test1_instance_data_read_access( self ): + def test1_instance_data_read_access(self): """Test read access to instance public data and verify values""" import cppyy, sys diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py --- a/pypy/module/cppyy/test/test_pythonify.py +++ b/pypy/module/cppyy/test/test_pythonify.py @@ -41,7 +41,7 @@ def test03_calling_static_functions(self): """Test calling of static methods.""" - import cppyy, sys + import cppyy, sys, math example01_class = cppyy.gbl.example01 res = example01_class.staticAddOneToInt(1) assert res == 2 @@ -52,14 +52,15 @@ assert res == 4 res = example01_class.staticAddOneToInt(-1) assert res == 0 - res = example01_class.staticAddOneToInt(sys.maxint-1) - assert res == sys.maxint - res = example01_class.staticAddOneToInt(sys.maxint) - assert res == -sys.maxint-1 + maxint32 = int(math.pow(2,31)-1) + res = example01_class.staticAddOneToInt(maxint32-1) + assert res == maxint32 + res = example01_class.staticAddOneToInt(maxint32) + assert res == -maxint32-1 raises(TypeError, 'example01_class.staticAddOneToInt(1, [])') raises(TypeError, 'example01_class.staticAddOneToInt(1.)') - raises(OverflowError, 'example01_class.staticAddOneToInt(sys.maxint+1)') + raises(OverflowError, 'example01_class.staticAddOneToInt(maxint32+1)') res = example01_class.staticAddToDouble(0.09) assert res == 0.09 + 0.01 From noreply at buildbot.pypy.org Tue Jul 12 15:53:08 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 12 Jul 2011 15:53:08 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: (all): planning for yesterday Message-ID: <20110712135308.6E5C282108@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: extradoc Changeset: r3829:29a18711ac3b Date: 2011-07-12 11:19 +0200 http://bitbucket.org/pypy/extradoc/changeset/29a18711ac3b/ Log: (all): planning for yesterday diff --git a/sprintinfo/ddorf2011-cppyy/planning.txt b/sprintinfo/ddorf2011-cppyy/planning.txt new file mode 100644 --- /dev/null +++ b/sprintinfo/ddorf2011-cppyy/planning.txt @@ -0,0 +1,16 @@ +people: + + - Sven + - Armin + - Carl Friedrich + - Wim + +tasks: + +cppyy + - memory management + - split between rpython/python (Carl Friedrich, Sven) + - fast path improvements + - global data members + - code duplication (Armin, Wim) + - array (Armin, Wim) From noreply at buildbot.pypy.org Tue Jul 12 15:53:09 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 12 Jul 2011 15:53:09 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: (all): planning for today Message-ID: <20110712135309.88A5F82108@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: extradoc Changeset: r3830:25902a83f246 Date: 2011-07-12 11:29 +0200 http://bitbucket.org/pypy/extradoc/changeset/25902a83f246/ Log: (all): planning for today diff --git a/sprintinfo/ddorf2011-cppyy/planning.txt b/sprintinfo/ddorf2011-cppyy/planning.txt --- a/sprintinfo/ddorf2011-cppyy/planning.txt +++ b/sprintinfo/ddorf2011-cppyy/planning.txt @@ -4,13 +4,22 @@ - Armin - Carl Friedrich - Wim + - Lukas + - David tasks: cppyy - memory management - - split between rpython/python (Carl Friedrich, Sven) - - fast path improvements + - split between rpython/python (Carl Friedrich) + - fast path improvements DONE + - test fast path (Carl Friedrich) - global data members - - code duplication (Armin, Wim) - - array (Armin, Wim) + - code duplication: IN PROGRESS + - array problems: IN PROGRESS (Armin, Wim) + + +auxilliary tasks + + - look more into PPC (Sven, David) + - list/set improvements (Lukas) From noreply at buildbot.pypy.org Tue Jul 12 15:53:10 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 12 Jul 2011 15:53:10 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: (all): planning Message-ID: <20110712135310.A55F982108@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: extradoc Changeset: r3831:a3afd78a5f9e Date: 2011-07-12 15:40 +0200 http://bitbucket.org/pypy/extradoc/changeset/a3afd78a5f9e/ Log: (all): planning diff --git a/sprintinfo/ddorf2011-cppyy/planning.txt b/sprintinfo/ddorf2011-cppyy/planning.txt new file mode 100644 --- /dev/null +++ b/sprintinfo/ddorf2011-cppyy/planning.txt @@ -0,0 +1,24 @@ +people present: + + - Armin + - Carl Friedrich + - Wim + - Lukas + - David + +tasks: + +cppyy + - memory management + - split between rpython/python (Carl Friedrich) + - fast path improvements DONE + - test fast path (Carl Friedrich) + - global data members + - code duplication: IN PROGRESS + - array problems: IN PROGRESS (Armin, Wim) + + +auxilliary tasks + + - look more into PPC (Sven, David) + - list/set improvements (Lukas) From noreply at buildbot.pypy.org Tue Jul 12 15:53:11 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 12 Jul 2011 15:53:11 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: huh??? merge Message-ID: <20110712135311.CB8F982108@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: extradoc Changeset: r3832:a5dd230dcb1f Date: 2011-07-12 15:43 +0200 http://bitbucket.org/pypy/extradoc/changeset/a5dd230dcb1f/ Log: huh??? merge diff --git a/sprintinfo/ddorf2011-cppyy/planning.txt b/sprintinfo/ddorf2011-cppyy/planning.txt --- a/sprintinfo/ddorf2011-cppyy/planning.txt +++ b/sprintinfo/ddorf2011-cppyy/planning.txt @@ -1,5 +1,6 @@ -people present: +people: + - Sven - Armin - Carl Friedrich - Wim From noreply at buildbot.pypy.org Tue Jul 12 17:53:10 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 12 Jul 2011 17:53:10 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: fix translation Message-ID: <20110712155310.F20B082108@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45514:12420105cecb Date: 2011-07-12 17:52 +0200 http://bitbucket.org/pypy/pypy/changeset/12420105cecb/ Log: fix translation diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -73,6 +73,9 @@ return arr raise AttributeError(name) + def _freeze_(self): + return True + class ArrayTypeConverterMixin(object): _mixin_ = True _immutable = True From noreply at buildbot.pypy.org Tue Jul 12 18:02:13 2011 From: noreply at buildbot.pypy.org (wlav) Date: Tue, 12 Jul 2011 18:02:13 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: call_i implementation for cint back-end Message-ID: <20110712160213.93B9882108@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45515:17d70e8f88b7 Date: 2011-07-12 06:43 -0700 http://bitbucket.org/pypy/pypy/changeset/17d70e8f88b7/ Log: call_i implementation for cint back-end diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py --- a/pypy/module/cppyy/capi/cint_capi.py +++ b/pypy/module/cppyy/capi/cint_capi.py @@ -107,6 +107,10 @@ "cppyy_call_h", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, compilation_info=eci) +c_call_i = rffi.llexternal( + "cppyy_call_i", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, + compilation_info=eci) c_call_l = rffi.llexternal( "cppyy_call_l", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.LONG, diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py --- a/pypy/module/cppyy/capi/reflex_capi.py +++ b/pypy/module/cppyy/capi/reflex_capi.py @@ -108,7 +108,7 @@ [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, compilation_info=eci) c_call_i = rffi.llexternal( - "cppyy_call_l", + "cppyy_call_i", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, compilation_info=eci) c_call_l = rffi.llexternal( diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx --- a/pypy/module/cppyy/src/cintcwrapper.cxx +++ b/pypy/module/cppyy/src/cintcwrapper.cxx @@ -128,6 +128,12 @@ return (short)G__int(result); } +int cppyy_call_i(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + G__value result = cppyy_call_T(handle, method_index, self, numargs, args); + return (int)G__int(result); +} + long cppyy_call_l(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); From noreply at buildbot.pypy.org Tue Jul 12 18:02:15 2011 From: noreply at buildbot.pypy.org (wlav) Date: Tue, 12 Jul 2011 18:02:15 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: basic memory ownership rules Message-ID: <20110712160215.D493082108@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45516:2a9e452cb674 Date: 2011-07-12 09:00 -0700 http://bitbucket.org/pypy/pypy/changeset/2a9e452cb674/ Log: basic memory ownership rules diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -189,7 +189,7 @@ from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) ptr_result = rffi.cast(rffi.VOIDP, long_result) - return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result) + return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) class InstanceExecutor(InstancePtrExecutor): _immutable_ = True @@ -199,8 +199,7 @@ long_result = capi.c_call_o( func.cpptype.handle, func.method_index, cppthis, num_args, args, self.cpptype.handle) ptr_result = rffi.cast(rffi.VOIDP, long_result) - # TODO: take ownership of result ... - return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result) + return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, True) _executors = {} diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -227,7 +227,7 @@ except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) raise - return W_CPPInstance(self.space, self.cpptype, newthis) + return W_CPPInstance(self.space, self.cpptype, newthis, True) class W_CPPOverload(Wrappable): @@ -521,10 +521,11 @@ class W_CPPInstance(Wrappable): _immutable_fields_ = ["cppclass"] - def __init__(self, space, cppclass, rawobject): + def __init__(self, space, cppclass, rawobject, python_owns): self.space = space self.cppclass = cppclass self.rawobject = rawobject + self.python_owns = python_owns def _nullcheck(self): if not self.rawobject: @@ -535,8 +536,13 @@ return overload.call(self.rawobject, args_w) def destruct(self): - capi.c_destruct(self.cppclass.handle, self.rawobject) - self.rawobject = NULL_VOIDP + if self.rawobject: + capi.c_destruct(self.cppclass.handle, self.rawobject) + self.rawobject = NULL_VOIDP + + def __del__(self): + if self.python_owns: + self.destruct() W_CPPInstance.typedef = TypeDef( 'CPPInstance', diff --git a/pypy/module/cppyy/test/example01.cxx b/pypy/module/cppyy/test/example01.cxx --- a/pypy/module/cppyy/test/example01.cxx +++ b/pypy/module/cppyy/test/example01.cxx @@ -7,12 +7,28 @@ #include "example01.h" //=========================================================================== -payload::payload(double d) : m_data(d) {} -payload::payload(const payload& p) : m_data(p.m_data) {} +payload::payload(double d) : m_data(d) { + count++; +} +payload::payload(const payload& p) : m_data(p.m_data) { + count++; +} +payload& payload::operator=(const payload& p) { + if (this != &p) { + m_data = p.m_data; + } + return *this; +} +payload::~payload() { + count--; +} double payload::getData() { return m_data; } void payload::setData(double d) { m_data = d; } +// class-level data +int payload::count = 0; + //=========================================================================== example01::example01() : m_somedata(-99) { diff --git a/pypy/module/cppyy/test/example01.h b/pypy/module/cppyy/test/example01.h --- a/pypy/module/cppyy/test/example01.h +++ b/pypy/module/cppyy/test/example01.h @@ -2,10 +2,15 @@ public: payload(double d); payload(const payload& p); + payload& operator=(const payload& e); + ~payload(); double getData(); void setData(double d); +public: // class-level data + static int count; + private: double m_data; }; diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -111,6 +111,40 @@ e2.destruct() assert t.invoke(t.get_overload("getCount")) == 0 + e2.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 + + def test_example01memory(self): + """Test memory destruction and integrity.""" + + import gc + + t = self.example01 + + assert t.invoke(t.get_overload("getCount")) == 0 + + e1 = t.construct(7) + assert t.invoke(t.get_overload("getCount")) == 1 + res = e1.invoke(t.get_overload("addDataToInt"), 4) + assert res == 11 + res = e1.invoke(t.get_overload("addDataToInt"), -4) + assert res == 3 + e1 = None + gc.collect() + assert t.invoke(t.get_overload("getCount")) == 0 + + e1 = t.construct(7) + e2 = t.construct(8) + assert t.invoke(t.get_overload("getCount")) == 2 + e1 = None + gc.collect() + assert t.invoke(t.get_overload("getCount")) == 1 + e2.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 + e2 = None + gc.collect() + assert t.invoke(t.get_overload("getCount")) == 0 + def test_example01method_double(self): """Test passing of a double and returning of double on a method""" diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py --- a/pypy/module/cppyy/test/test_pythonify.py +++ b/pypy/module/cppyy/test/test_pythonify.py @@ -199,3 +199,44 @@ assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5 assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5 + + def test09_memory(self): + import cppyy, gc + example01_class = cppyy.gbl.example01 + payload_class = cppyy.gbl.payload + + pl = payload_class(3.14) + assert payload_class.count == 1 + assert round(pl.getData()-3.14, 8) == 0 + + pl2 = example01_class.staticCopyCyclePayload(pl, 38.) + assert payload_class.count == 2 + assert pl2.getData() == 38. + pl2 = None + gc.collect() + assert payload_class.count == 1 + + e = example01_class(14) + + pl2 = e.copyCyclePayload(pl) + assert payload_class.count == 2 + assert round(pl2.getData()-14., 8) == 0 + pl2 = None + gc.collect() + assert payload_class.count == 1 + + pl = None + e = None + gc.collect() + assert payload_class.count == 0 + assert example01_class.getCount() == 0 + + pl = payload_class(3.14) + pl_a = example01_class.staticCyclePayload(pl, 66.) + pl_a.getData() == 66. + assert payload_class.count == 1 + pl = None + gc.collect() + assert payload_class.count == 0 + + # TODO: need ReferenceError on touching pl_a From noreply at buildbot.pypy.org Tue Jul 12 18:02:17 2011 From: noreply at buildbot.pypy.org (wlav) Date: Tue, 12 Jul 2011 18:02:17 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge heads Message-ID: <20110712160217.07B7382108@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45517:b656c9b2cc2b Date: 2011-07-12 09:02 -0700 http://bitbucket.org/pypy/pypy/changeset/b656c9b2cc2b/ Log: merge heads diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -73,6 +73,9 @@ return arr raise AttributeError(name) + def _freeze_(self): + return True + class ArrayTypeConverterMixin(object): _mixin_ = True _immutable = True From noreply at buildbot.pypy.org Tue Jul 12 23:42:46 2011 From: noreply at buildbot.pypy.org (amauryfa) Date: Tue, 12 Jul 2011 23:42:46 +0200 (CEST) Subject: [pypy-commit] pypy default: Yes, changing the struct name causes the test to fail Message-ID: <20110712214246.D5FC382108@wyvern.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r45518:24bb4e1afc2a Date: 2011-07-08 19:39 +0200 http://bitbucket.org/pypy/pypy/changeset/24bb4e1afc2a/ Log: Yes, changing the struct name causes the test to fail diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -671,7 +671,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_arrayofstruct(self): - S1 = lltype.Struct('S1', ('x', lltype.Signed)) + S1 = lltype.Struct('S2', ('x', lltype.Signed)) A = lltype.Array(S1, hints={'nolength': True}) a = lltype.malloc(A, 5, flavor='raw') a[0].x = 100 From noreply at buildbot.pypy.org Tue Jul 12 23:42:48 2011 From: noreply at buildbot.pypy.org (amauryfa) Date: Tue, 12 Jul 2011 23:42:48 +0200 (CEST) Subject: [pypy-commit] pypy default: ll2ctypes bug: delay the creation of the ptrtype, Message-ID: <20110712214248.0DC3D82108@wyvern.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r45519:cb7edff773d0 Date: 2011-07-12 23:40 +0200 http://bitbucket.org/pypy/pypy/changeset/cb7edff773d0/ Log: ll2ctypes bug: delay the creation of the ptrtype, so that it does not point to an incomplete type (a Structure without _fields_, for example) diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -172,17 +172,6 @@ assert max_n >= 0 ITEM = A.OF ctypes_item = get_ctypes_type(ITEM, delayed_builders) - # Python 2.5 ctypes can raise OverflowError on 64-bit builds - for n in [sys.maxint, 2**31]: - MAX_SIZE = n/64 - try: - PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item) - except OverflowError, e: - pass - else: - break - else: - raise e class CArray(ctypes.Structure): if not A._hints.get('nolength'): @@ -191,6 +180,7 @@ else: _fields_ = [('items', max_n * ctypes_item)] + @classmethod def _malloc(cls, n=None): if not isinstance(n, int): raise TypeError, "array length must be an int" @@ -199,10 +189,29 @@ if hasattr(bigarray, 'length'): bigarray.length = n return bigarray - _malloc = classmethod(_malloc) + + _ptrtype = None + + @classmethod + def _get_ptrtype(cls): + if cls._ptrtype: + return cls._ptrtype + # ctypes can raise OverflowError on 64-bit builds + for n in [sys.maxint, 2**31]: + cls.MAX_SIZE = n/64 + try: + cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item) + except OverflowError, e: + pass + else: + break + else: + raise e + return cls._ptrtype def _indexable(self, index): - assert index + 1 < MAX_SIZE + PtrType = self._get_ptrtype() + assert index + 1 < self.MAX_SIZE p = ctypes.cast(ctypes.pointer(self.items), PtrType) return p.contents From noreply at buildbot.pypy.org Wed Jul 13 00:18:33 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 13 Jul 2011 00:18:33 +0200 (CEST) Subject: [pypy-commit] benchmarks default: Added an ignore. Message-ID: <20110712221833.BB35D8291A@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r120:a1939ef01100 Date: 2011-07-12 15:17 -0700 http://bitbucket.org/pypy/benchmarks/changeset/a1939ef01100/ Log: Added an ignore. diff --git a/.hgignore b/.hgignore new file mode 100644 --- /dev/null +++ b/.hgignore @@ -0,0 +1,1 @@ +.*\.py[co] From noreply at buildbot.pypy.org Wed Jul 13 10:16:45 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 13 Jul 2011 10:16:45 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: clone the snapshot in start_resumedescr before inlining it and reenable the "trace some more"-feature Message-ID: <20110713081645.E147C8291A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45520:ec6703579cf2 Date: 2011-07-12 18:26 +0200 http://bitbucket.org/pypy/pypy/changeset/ec6703579cf2/ Log: clone the snapshot in start_resumedescr before inlining it and reenable the "trace some more"-feature diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -139,6 +139,22 @@ for op in self.optimizer.loop.operations: newop = op.clone() self.cloned_operations.append(newop) + + def fix_snapshot(self, loop, jump_args, snapshot): + if snapshot is None: + return None + snapshot_args = snapshot.boxes + new_snapshot_args = [] + for a in snapshot_args: + if not isinstance(a, Const): + a = loop.preamble.inputargs[jump_args.index(a)] + a = self.inliner.inline_arg(a) + a = self.getvalue(a).get_key_box() + new_snapshot_args.append(a) + prev = self.fix_snapshot(loop, jump_args, snapshot.prev) + return Snapshot(prev, new_snapshot_args) + #snapshot.boxes = new_snapshot_args + #return snapshot def propagate_all_forward(self): loop = self.optimizer.loop @@ -185,18 +201,8 @@ start_resumedescr = loop.preamble.start_resumedescr.clone_if_mutable() self.start_resumedescr = start_resumedescr assert isinstance(start_resumedescr, ResumeGuardDescr) - snapshot = start_resumedescr.rd_snapshot - while snapshot is not None: - snapshot_args = snapshot.boxes - new_snapshot_args = [] - for a in snapshot_args: - if not isinstance(a, Const): - a = loop.preamble.inputargs[jump_args.index(a)] - a = self.inliner.inline_arg(a) - a = self.getvalue(a).get_key_box() - new_snapshot_args.append(a) - snapshot.boxes = new_snapshot_args - snapshot = snapshot.prev + start_resumedescr.rd_snapshot = self.fix_snapshot(loop, jump_args, + start_resumedescr.rd_snapshot) inputargs, short_inputargs, short = self.inline(self.cloned_operations, loop.inputargs, jump_args, diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1847,9 +1847,9 @@ else: self.compile(original_boxes, live_arg_boxes, start, resumedescr) # creation of the loop was cancelled! - #self.staticdata.log('cancelled, tracing more...') - self.staticdata.log('cancelled, stopping tracing') - raise SwitchToBlackhole(ABORT_BAD_LOOP) + self.staticdata.log('cancelled, tracing more...') + #self.staticdata.log('cancelled, stopping tracing') + #raise SwitchToBlackhole(ABORT_BAD_LOOP) # Otherwise, no loop found so far, so continue tracing. start = len(self.history.operations) From noreply at buildbot.pypy.org Wed Jul 13 10:16:47 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 13 Jul 2011 10:16:47 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: test that snapshot within start_resumedescr is properly cloned before modified Message-ID: <20110713081647.2C6058291A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45521:6020d95d4fa7 Date: 2011-07-12 20:27 +0200 http://bitbucket.org/pypy/pypy/changeset/6020d95d4fa7/ Log: test that snapshot within start_resumedescr is properly cloned before modified diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -153,8 +153,6 @@ new_snapshot_args.append(a) prev = self.fix_snapshot(loop, jump_args, snapshot.prev) return Snapshot(prev, new_snapshot_args) - #snapshot.boxes = new_snapshot_args - #return snapshot def propagate_all_forward(self): loop = self.optimizer.loop diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2758,6 +2758,32 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + def test_continue_tracing_with_boxes_in_start_snapshot_replaced_by_optimizer(self): + myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'a', 'b']) + def f(n): + sa = a = 0 + b = 10 + while n: + myjitdriver.jit_merge_point(sa=sa, n=n, a=a, b=b) + sa += b + b += 1 + if b > 7: + pass + if a == 0: + a = 1 + elif a == 1: + a = 2 + elif a == 2: + a = 0 + sa += a + sa += 0 + n -= 1 + return sa + res = self.meta_interp(f, [16]) + assert res == f(16) + + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): From noreply at buildbot.pypy.org Wed Jul 13 10:16:48 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 13 Jul 2011 10:16:48 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: reenable caching of setfields across loop boundaries and give it priority Message-ID: <20110713081648.600928291A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45522:405bb0cf3cac Date: 2011-07-13 09:48 +0200 http://bitbucket.org/pypy/pypy/changeset/405bb0cf3cac/ Log: reenable caching of setfields across loop boundaries and give it priority diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -126,12 +126,10 @@ if op and structvalue in self._cached_fields: if op.getopnum() == rop.SETFIELD_GC: result = op.getarg(1) - if result in potential_ops: - # XXX dissable for now - continue + if result in potential_ops and potential_ops[result] is None: newresult = result.clonebox() optimizer.make_equal_to(newresult, optimizer.getvalue(result)) - newresult = result + result = newresult # XXX this will not allow for chains of operations getop = ResOperation(rop.GETFIELD_GC, [op.getarg(0)], result, op.getdescr()) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -850,18 +850,23 @@ p2sub = new_with_vtable(ConstClass(node_vtable2)) setfield_gc(p2sub, i1, descr=valuedescr) setfield_gc(p2, p2sub, descr=nextdescr) - jump(i1, p2) - """ - expected = """ - [i1, p2] - p2sub = getfield_gc(p2, descr=nextdescr) + jump(i1, p2, p2sub) + """ + expected = """ + [i1, p2, p2sub] i3 = getfield_gc(p2sub, descr=valuedescr) escape(i3) p1 = new_with_vtable(ConstClass(node_vtable)) p3sub = new_with_vtable(ConstClass(node_vtable2)) setfield_gc(p3sub, i1, descr=valuedescr) setfield_gc(p1, p3sub, descr=nextdescr) - jump(i1, p1) + # XXX: We get two extra operations here because the setfield + # above is the result of forcing p1 and thus not + # registered with the heap optimizer. I've makred tests + # below with VIRTUALHEAP if they suffer from this issue + p3sub2 = getfield_gc(p1, descr=nextdescr) + guard_nonnull_class(p3sub2, ConstClass(node_vtable2)) [] + jump(i1, p1, p3sub2) """ self.optimize_loop(ops, expected, preamble) @@ -883,17 +888,20 @@ i2b = int_is_true(i2) guard_true(i2b) [] setfield_gc(p2, i2, descr=nextdescr) - jump(p2) - """ - expected = """ - [p2] - i1 = getfield_gc(p2, descr=nextdescr) + jump(p2, i2) + """ + expected = """ + [p2, i1] i2 = int_sub(i1, 1) i2b = int_is_true(i2) guard_true(i2b) [] p3 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p3, i2, descr=nextdescr) - jump(p3) + # XXX: VIRTUALHEAP (see above) + i3 = getfield_gc(p3, descr=nextdescr) + i7 = int_is_true(i3) + guard_true(i7) [] + jump(p3, i3) """ self.optimize_loop(ops, expected, preamble) From noreply at buildbot.pypy.org Wed Jul 13 10:16:49 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 13 Jul 2011 10:16:49 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: In this test, the loop is actually specialized to the condition "the first Message-ID: <20110713081649.940BE8291A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45523:3bff25816dd1 Date: 2011-07-13 10:16 +0200 http://bitbucket.org/pypy/pypy/changeset/3bff25816dd1/ Log: In this test, the loop is actually specialized to the condition "the first input argument is equal to the valuedescr field of myptr". A bridge jumping directly to it would need to check that this condition is true, and if it is not jump to the preamble or retrace instead. Do we relay want that? The intention of the test was most likely not to check this so I'll adjust the test to a situation were this kind of specialisation does not occure. diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -110,7 +110,7 @@ assert self._lazy_setfield is None cf = CachedField() for structvalue, fieldvalue in self._cached_fields.iteritems(): - op = self._cached_fields_getfield_op.get(structvalue, None) + op = self._cached_fields_getfield_op.get(structvalue, None) if op and op.result in short_boxes and short_boxes[op.result] is op: structvalue2 = structvalue.get_cloned(optimizer, valuemap) fieldvalue2 = fieldvalue .get_cloned(optimizer, valuemap) @@ -140,6 +140,7 @@ potential_ops[op.result] = op + class BogusPureField(JitException): pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1363,12 +1363,19 @@ ops = """ [i] i1 = getfield_gc(ConstPtr(myptr), descr=valuedescr) - jump(i1) - """ - preamble = ops - expected = """ + call(i1, descr=nonwritedescr) + jump(i) + """ + preamble = """ [i] - jump(i) + i1 = getfield_gc(ConstPtr(myptr), descr=valuedescr) + call(i1, descr=nonwritedescr) + jump(i, i1) + """ + expected = """ + [i, i1] + call(i1, descr=nonwritedescr) + jump(i, i1) """ self.optimize_loop(ops, expected, preamble) From noreply at buildbot.pypy.org Wed Jul 13 11:01:44 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 11:01:44 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: load 32-bit constants in two instructions Message-ID: <20110713090144.C7DEB8291A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45524:69b3c1536bfc Date: 2011-07-09 17:01 +0200 http://bitbucket.org/pypy/pypy/changeset/69b3c1536bfc/ Log: load 32-bit constants in two instructions diff --git a/pypy/jit/backend/arm/codebuilder.py b/pypy/jit/backend/arm/codebuilder.py --- a/pypy/jit/backend/arm/codebuilder.py +++ b/pypy/jit/backend/arm/codebuilder.py @@ -178,9 +178,28 @@ self.write32(target) else: self.gen_load_int(reg.ip.value, target, cond=c) - self.ADD_ri(reg.lr.value, reg.pc.value, arch.PC_OFFSET/2) + self.MOV_rr(reg.lr.value, reg.pc.value, cond=c) self.MOV_rr(reg.pc.value, reg.ip.value, cond=c) + def MOVT_ri(self, rd, imm16, c=cond.AL): + """Move Top writes an immediate value to the top halfword of the + destination register. It does not affect the contents of the bottom + halfword.""" + self.write32(c << 28 + | 0x3 << 24 + | (1 << 22) + | ((imm16 >> 12) & 0xF) << 16 + | (rd & 0xF) << 12 + | imm16 & 0xFFF) + + def MOVW_ri(self, rd, imm16, c=cond.AL): + """Encoding A2 of MOV, that allow to load a 16 bit constant""" + self.write32(c << 28 + | 0x3 << 24 + | ((imm16 >> 12) & 0xF) << 16 + | (rd & 0xF) << 12 + | imm16 & 0xFFF) + DIV = binary_helper_call('int_div') MOD = binary_helper_call('int_mod') UDIV = binary_helper_call('uint_div') @@ -209,30 +228,15 @@ def currpos(self): raise NotImplementedError - size_of_gen_load_int = 3 * WORD + size_of_gen_load_int = 2 * WORD def gen_load_int(self, r, value, cond=cond.AL): """r is the register number, value is the value to be loaded to the register""" - from pypy.jit.backend.arm.conditions import AL - if cond != AL or 0 <= value <= 0xFFFF: - self._load_by_shifting(r, value, cond) - else: - self.LDR_ri(r, reg.pc.value) - self.MOV_rr(reg.pc.value, reg.pc.value) - self.write32(value) - - #size_of_gen_load_int = 4 * WORD - ofs_shift = zip(range(8, 25, 8), range(12, 0, -4)) - def _load_by_shifting(self, r, value, c=cond.AL): - # to be sure it is only called for the correct cases - assert c != cond.AL or 0 <= value <= 0xFFFF - self.MOV_ri(r, (value & 0xFF), cond=c) - for offset, shift in self.ofs_shift: - b = (value >> offset) & 0xFF - if b == 0: - continue - t = b | (shift << 8) - self.ORR_ri(r, r, imm=t, cond=c) + bottom = value & 0xFFFF + top = value >> 16 + self.MOVW_ri(r, bottom, cond) + if top: + self.MOVT_ri(r, top, cond) class OverwritingBuilder(AbstractARMv7Builder): def __init__(self, cb, start, size): diff --git a/pypy/jit/backend/arm/test/test_instr_codebuilder.py b/pypy/jit/backend/arm/test/test_instr_codebuilder.py --- a/pypy/jit/backend/arm/test/test_instr_codebuilder.py +++ b/pypy/jit/backend/arm/test/test_instr_codebuilder.py @@ -156,6 +156,14 @@ self.cb.VMRS(conditions.AL) self.assert_equal("vmrs APSR_nzcv, fpscr") + def test_movw(self): + self.cb.MOVW_ri(r.r3.value, 0xFFFF, conditions.NE) + self.assert_equal("MOVWNE r3, #65535") + + def test_movt(self): + self.cb.MOVT_ri(r.r3.value, 0xFFFF, conditions.NE) + self.assert_equal("MOVTNE r3, #65535") + class TestInstrCodeBuilderForGeneratedInstr(ASMTest): def setup_method(self, ffuu_method): self.cb = CodeBuilder() From noreply at buildbot.pypy.org Wed Jul 13 11:01:46 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 11:01:46 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: try to make sure the stack stays aligned when using saved_registers Message-ID: <20110713090146.3DA058291A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45525:c959cad72952 Date: 2011-07-12 13:41 +0200 http://bitbucket.org/pypy/pypy/changeset/c959cad72952/ Log: try to make sure the stack stays aligned when using saved_registers diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -344,6 +344,7 @@ encode32(mem, j+1, loc.getint()) j += 5 else: + assert loc.is_stack() mem[j] = self.STACK_LOC encode32(mem, j+1, loc.position) j += 5 @@ -364,13 +365,14 @@ return memaddr def gen_exit_code(self, mc, memaddr, fcond=c.AL, save_exc=False): - mc.LDR_ri(r.ip.value, r.pc.value, imm=WORD) + self.mc.gen_load_int(r.ip.value, memaddr) + #mc.LDR_ri(r.ip.value, r.pc.value, imm=WORD) if save_exc: path = self._leave_jitted_hook_save_exc else: path = self._leave_jitted_hook mc.B(path) - mc.write32(memaddr) + #mc.write32(memaddr) def align(self): while(self.mc.currpos() % FUNC_ALIGN != 0): @@ -680,7 +682,7 @@ size = (self.mc.size_of_gen_load_int+WORD) l = self.mc.currpos() for _ in range(size//WORD): - self.mc.MOV_rr(r.r0.value, r.r0.value) + self.mc.NOP() return l def _patch_sp_offset(self, pos, frame_depth): @@ -981,13 +983,12 @@ # convention of slowpath_addr{1,2} are tweaked a lot to allow # the code here to be just two CALLs: slowpath_addr1 gets the # size of the object to allocate from (EDX-EAX) and returns the - # result in EAX; slowpath_addr2 additionally returns in EDX a + # result in EAX; self.malloc_slowpath additionally returns in EDX a # copy of heap(nursery_free_adr), so that the final MOV below is # a no-op. self.mark_gc_roots(self.write_new_force_index(), use_copy_area=True) - slowpath_addr2 = self.malloc_slowpath - self.mc.BL(slowpath_addr2) + self.mc.BL(self.malloc_slowpath) offset = self.mc.currpos() - fast_jmp_pos pmc = OverwritingBuilder(self.mc, fast_jmp_pos, WORD) diff --git a/pypy/jit/backend/arm/helper/assembler.py b/pypy/jit/backend/arm/helper/assembler.py --- a/pypy/jit/backend/arm/helper/assembler.py +++ b/pypy/jit/backend/arm/helper/assembler.py @@ -33,10 +33,10 @@ def f(self, op, arglocs, regalloc, fcond): assert fcond is not None if op.result: - regs = r.caller_resp[1:] + regs = r.caller_resp[1:] + [r.ip] else: regs = r.caller_resp - with saved_registers(self.mc, regs, r.caller_vfp_resp, regalloc=regalloc): + with saved_registers(self.mc, regs, r.caller_vfp_resp): helper(self.mc, fcond) return fcond return f @@ -83,8 +83,9 @@ class saved_registers(object): def __init__(self, assembler, regs_to_save, vfp_regs_to_save=None, regalloc=None): + assert regalloc is None self.assembler = assembler - self.regalloc = regalloc + self.regalloc = None if vfp_regs_to_save is None: vfp_regs_to_save = [] if self.regalloc: diff --git a/pypy/jit/backend/arm/opassembler.py b/pypy/jit/backend/arm/opassembler.py --- a/pypy/jit/backend/arm/opassembler.py +++ b/pypy/jit/backend/arm/opassembler.py @@ -463,7 +463,7 @@ # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. - with saved_registers(self.mc, r.caller_resp, regalloc=regalloc): + with saved_registers(self.mc, r.caller_resp): remap_frame_layout(self, arglocs, [r.r0, r.r1], r.ip) self.mc.BL(descr.get_write_barrier_fn(self.cpu)) @@ -845,7 +845,8 @@ jd = descr.outermost_jitdriver_sd assert jd is not None asm_helper_adr = self.cpu.cast_adr_to_int(jd.assembler_helper_adr) - with saved_registers(self.mc, r.caller_resp[1:], r.caller_vfp_resp, regalloc=regalloc): + with saved_registers(self.mc, r.caller_resp[1:]+[r.ip], + r.caller_vfp_resp): # resbox is allready in r0 self.mov_loc_loc(arglocs[1], r.r1) self.mc.BL(asm_helper_adr) From noreply at buildbot.pypy.org Wed Jul 13 11:01:54 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 11:01:54 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: unskip this test Message-ID: <20110713090154.B2A1D8291B@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45527:cf96111049eb Date: 2011-07-13 10:16 +0200 http://bitbucket.org/pypy/pypy/changeset/cf96111049eb/ Log: unskip this test diff --git a/pypy/jit/backend/arm/test/test_runner.py b/pypy/jit/backend/arm/test/test_runner.py --- a/pypy/jit/backend/arm/test/test_runner.py +++ b/pypy/jit/backend/arm/test/test_runner.py @@ -58,9 +58,6 @@ expected = [3, 7, 11, 15, 19, 23, 27, 3, 7, 11, 15, 19, 23, 27] assert output == expected - def test_cond_call_gc_wb(self, *args): - py.test.skip('needs gc support') - def test_redirect_call_assember(self): called = [] def assembler_helper(failindex, virtualizable): From noreply at buildbot.pypy.org Wed Jul 13 11:01:53 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 11:01:53 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: merge default Message-ID: <20110713090153.738428291A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45526:11ab6fab5723 Date: 2011-07-12 13:46 +0200 http://bitbucket.org/pypy/pypy/changeset/11ab6fab5723/ Log: merge default diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -2,6 +2,7 @@ *.py[co] *.sw[po] *~ +.*.swp syntax: regexp ^testresult$ @@ -39,6 +40,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ @@ -65,6 +68,7 @@ ^pypy/doc/image/lattice3\.png$ ^pypy/doc/image/stackless_informal\.png$ ^pypy/doc/image/parsing_example.+\.png$ +^pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test\.o$ ^compiled ^.git/ ^release/ diff --git a/_pytest/__init__.py b/_pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.0.3' +__version__ = '2.1.0.dev4' diff --git a/_pytest/assertion.py b/_pytest/assertion.py deleted file mode 100644 --- a/_pytest/assertion.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -support for presented detailed information in failing assertions. -""" -import py -import sys -from _pytest.monkeypatch import monkeypatch - -def pytest_addoption(parser): - group = parser.getgroup("debugconfig") - group._addoption('--no-assert', action="store_true", default=False, - dest="noassert", - help="disable python assert expression reinterpretation."), - -def pytest_configure(config): - # The _reprcompare attribute on the py.code module is used by - # py._code._assertionnew to detect this plugin was loaded and in - # turn call the hooks defined here as part of the - # DebugInterpreter. - m = monkeypatch() - config._cleanup.append(m.undo) - warn_about_missing_assertion() - if not config.getvalue("noassert") and not config.getvalue("nomagic"): - def callbinrepr(op, left, right): - hook_result = config.hook.pytest_assertrepr_compare( - config=config, op=op, left=left, right=right) - for new_expl in hook_result: - if new_expl: - return '\n~'.join(new_expl) - m.setattr(py.builtin.builtins, - 'AssertionError', py.code._AssertionError) - m.setattr(py.code, '_reprcompare', callbinrepr) - -def warn_about_missing_assertion(): - try: - assert False - except AssertionError: - pass - else: - sys.stderr.write("WARNING: failing tests may report as passing because " - "assertions are turned off! (are you using python -O?)\n") - -# Provide basestring in python3 -try: - basestring = basestring -except NameError: - basestring = str - - -def pytest_assertrepr_compare(op, left, right): - """return specialised explanations for some operators/operands""" - width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op - left_repr = py.io.saferepr(left, maxsize=int(width/2)) - right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) - summary = '%s %s %s' % (left_repr, op, right_repr) - - issequence = lambda x: isinstance(x, (list, tuple)) - istext = lambda x: isinstance(x, basestring) - isdict = lambda x: isinstance(x, dict) - isset = lambda x: isinstance(x, set) - - explanation = None - try: - if op == '==': - if istext(left) and istext(right): - explanation = _diff_text(left, right) - elif issequence(left) and issequence(right): - explanation = _compare_eq_sequence(left, right) - elif isset(left) and isset(right): - explanation = _compare_eq_set(left, right) - elif isdict(left) and isdict(right): - explanation = _diff_text(py.std.pprint.pformat(left), - py.std.pprint.pformat(right)) - elif op == 'not in': - if istext(left) and istext(right): - explanation = _notin_text(left, right) - except py.builtin._sysex: - raise - except: - excinfo = py.code.ExceptionInfo() - explanation = ['(pytest_assertion plugin: representation of ' - 'details failed. Probably an object has a faulty __repr__.)', - str(excinfo) - ] - - - if not explanation: - return None - - # Don't include pageloads of data, should be configurable - if len(''.join(explanation)) > 80*8: - explanation = ['Detailed information too verbose, truncated'] - - return [summary] + explanation - - -def _diff_text(left, right): - """Return the explanation for the diff between text - - This will skip leading and trailing characters which are - identical to keep the diff minimal. - """ - explanation = [] - i = 0 # just in case left or right has zero length - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - break - if i > 42: - i -= 10 # Provide some context - explanation = ['Skipping %s identical ' - 'leading characters in diff' % i] - left = left[i:] - right = right[i:] - if len(left) == len(right): - for i in range(len(left)): - if left[-i] != right[-i]: - break - if i > 42: - i -= 10 # Provide some context - explanation += ['Skipping %s identical ' - 'trailing characters in diff' % i] - left = left[:-i] - right = right[:-i] - explanation += [line.strip('\n') - for line in py.std.difflib.ndiff(left.splitlines(), - right.splitlines())] - return explanation - - -def _compare_eq_sequence(left, right): - explanation = [] - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - explanation += ['At index %s diff: %r != %r' % - (i, left[i], right[i])] - break - if len(left) > len(right): - explanation += ['Left contains more items, ' - 'first extra item: %s' % py.io.saferepr(left[len(right)],)] - elif len(left) < len(right): - explanation += ['Right contains more items, ' - 'first extra item: %s' % py.io.saferepr(right[len(left)],)] - return explanation # + _diff_text(py.std.pprint.pformat(left), - # py.std.pprint.pformat(right)) - - -def _compare_eq_set(left, right): - explanation = [] - diff_left = left - right - diff_right = right - left - if diff_left: - explanation.append('Extra items in the left set:') - for item in diff_left: - explanation.append(py.io.saferepr(item)) - if diff_right: - explanation.append('Extra items in the right set:') - for item in diff_right: - explanation.append(py.io.saferepr(item)) - return explanation - - -def _notin_text(term, text): - index = text.find(term) - head = text[:index] - tail = text[index+len(term):] - correct_text = head + tail - diff = _diff_text(correct_text, text) - newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] - for line in diff: - if line.startswith('Skipping'): - continue - if line.startswith('- '): - continue - if line.startswith('+ '): - newdiff.append(' ' + line[2:]) - else: - newdiff.append(line) - return newdiff diff --git a/_pytest/assertion/__init__.py b/_pytest/assertion/__init__.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/__init__.py @@ -0,0 +1,128 @@ +""" +support for presenting detailed information in failing assertions. +""" +import py +import imp +import marshal +import struct +import sys +import pytest +from _pytest.monkeypatch import monkeypatch +from _pytest.assertion import reinterpret, util + +try: + from _pytest.assertion.rewrite import rewrite_asserts +except ImportError: + rewrite_asserts = None +else: + import ast + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption('--assertmode', action="store", dest="assertmode", + choices=("on", "old", "off", "default"), default="default", + metavar="on|old|off", + help="""control assertion debugging tools. +'off' performs no assertion debugging. +'old' reinterprets the expressions in asserts to glean information. +'on' (the default) rewrites the assert statements in test modules to provide +sub-expression results.""") + group.addoption('--no-assert', action="store_true", default=False, + dest="noassert", help="DEPRECATED equivalent to --assertmode=off") + group.addoption('--nomagic', action="store_true", default=False, + dest="nomagic", help="DEPRECATED equivalent to --assertmode=off") + +class AssertionState: + """State for the assertion plugin.""" + + def __init__(self, config, mode): + self.mode = mode + self.trace = config.trace.root.get("assertion") + +def pytest_configure(config): + warn_about_missing_assertion() + mode = config.getvalue("assertmode") + if config.getvalue("noassert") or config.getvalue("nomagic"): + if mode not in ("off", "default"): + raise pytest.UsageError("assertion options conflict") + mode = "off" + elif mode == "default": + mode = "on" + if mode != "off": + def callbinrepr(op, left, right): + hook_result = config.hook.pytest_assertrepr_compare( + config=config, op=op, left=left, right=right) + for new_expl in hook_result: + if new_expl: + return '\n~'.join(new_expl) + m = monkeypatch() + config._cleanup.append(m.undo) + m.setattr(py.builtin.builtins, 'AssertionError', + reinterpret.AssertionError) + m.setattr(util, '_reprcompare', callbinrepr) + if mode == "on" and rewrite_asserts is None: + mode = "old" + config._assertstate = AssertionState(config, mode) + config._assertstate.trace("configured with mode set to %r" % (mode,)) + +def _write_pyc(co, source_path): + if hasattr(imp, "cache_from_source"): + # Handle PEP 3147 pycs. + pyc = py.path.local(imp.cache_from_source(str(source_path))) + pyc.ensure() + else: + pyc = source_path + "c" + mtime = int(source_path.mtime()) + fp = pyc.open("wb") + try: + fp.write(imp.get_magic()) + fp.write(struct.pack(">", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + + +class DebugInterpreter(ast.NodeVisitor): + """Interpret AST nodes to gleam useful debugging information. """ + + def __init__(self, frame): + self.frame = frame + + def generic_visit(self, node): + # Fallback when we don't have a special implementation. + if _is_ast_expr(node): + mod = ast.Expression(node) + co = self._compile(mod) + try: + result = self.frame.eval(co) + except Exception: + raise Failure() + explanation = self.frame.repr(result) + return explanation, result + elif _is_ast_stmt(node): + mod = ast.Module([node]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co) + except Exception: + raise Failure() + return None, None + else: + raise AssertionError("can't handle %s" %(node,)) + + def _compile(self, source, mode="eval"): + return compile(source, "", mode) + + def visit_Expr(self, expr): + return self.visit(expr.value) + + def visit_Module(self, mod): + for stmt in mod.body: + self.visit(stmt) + + def visit_Name(self, name): + explanation, result = self.generic_visit(name) + # See if the name is local. + source = "%r in locals() is not globals()" % (name.id,) + co = self._compile(source) + try: + local = self.frame.eval(co) + except Exception: + # have to assume it isn't + local = None + if local is None or not self.frame.is_true(local): + return name.id, result + return explanation, result + + def visit_Compare(self, comp): + left = comp.left + left_explanation, left_result = self.visit(left) + for op, next_op in zip(comp.ops, comp.comparators): + next_explanation, next_result = self.visit(next_op) + op_symbol = operator_map[op.__class__] + explanation = "%s %s %s" % (left_explanation, op_symbol, + next_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=next_result) + except Exception: + raise Failure(explanation) + try: + if not self.frame.is_true(result): + break + except KeyboardInterrupt: + raise + except: + break + left_explanation, left_result = next_explanation, next_result + + if util._reprcompare is not None: + res = util._reprcompare(op_symbol, left_result, next_result) + if res: + explanation = res + return explanation, result + + def visit_BoolOp(self, boolop): + is_or = isinstance(boolop.op, ast.Or) + explanations = [] + for operand in boolop.values: + explanation, result = self.visit(operand) + explanations.append(explanation) + if result == is_or: + break + name = is_or and " or " or " and " + explanation = "(" + name.join(explanations) + ")" + return explanation, result + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_explanation, operand_result = self.visit(unary.operand) + explanation = pattern % (operand_explanation,) + co = self._compile(pattern % ("__exprinfo_expr",)) + try: + result = self.frame.eval(co, __exprinfo_expr=operand_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_BinOp(self, binop): + left_explanation, left_result = self.visit(binop.left) + right_explanation, right_result = self.visit(binop.right) + symbol = operator_map[binop.op.__class__] + explanation = "(%s %s %s)" % (left_explanation, symbol, + right_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=right_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_Call(self, call): + func_explanation, func = self.visit(call.func) + arg_explanations = [] + ns = {"__exprinfo_func" : func} + arguments = [] + for arg in call.args: + arg_explanation, arg_result = self.visit(arg) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + arguments.append(arg_name) + arg_explanations.append(arg_explanation) + for keyword in call.keywords: + arg_explanation, arg_result = self.visit(keyword.value) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + keyword_source = "%s=%%s" % (keyword.arg) + arguments.append(keyword_source % (arg_name,)) + arg_explanations.append(keyword_source % (arg_explanation,)) + if call.starargs: + arg_explanation, arg_result = self.visit(call.starargs) + arg_name = "__exprinfo_star" + ns[arg_name] = arg_result + arguments.append("*%s" % (arg_name,)) + arg_explanations.append("*%s" % (arg_explanation,)) + if call.kwargs: + arg_explanation, arg_result = self.visit(call.kwargs) + arg_name = "__exprinfo_kwds" + ns[arg_name] = arg_result + arguments.append("**%s" % (arg_name,)) + arg_explanations.append("**%s" % (arg_explanation,)) + args_explained = ", ".join(arg_explanations) + explanation = "%s(%s)" % (func_explanation, args_explained) + args = ", ".join(arguments) + source = "__exprinfo_func(%s)" % (args,) + co = self._compile(source) + try: + result = self.frame.eval(co, **ns) + except Exception: + raise Failure(explanation) + pattern = "%s\n{%s = %s\n}" + rep = self.frame.repr(result) + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def _is_builtin_name(self, name): + pattern = "%r not in globals() and %r not in locals()" + source = pattern % (name.id, name.id) + co = self._compile(source) + try: + return self.frame.eval(co) + except Exception: + return False + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + source_explanation, source_result = self.visit(attr.value) + explanation = "%s.%s" % (source_explanation, attr.attr) + source = "__exprinfo_expr.%s" % (attr.attr,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + raise Failure(explanation) + explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), + self.frame.repr(result), + source_explanation, attr.attr) + # Check if the attr is from an instance. + source = "%r in getattr(__exprinfo_expr, '__dict__', {})" + source = source % (attr.attr,) + co = self._compile(source) + try: + from_instance = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + from_instance = None + if from_instance is None or self.frame.is_true(from_instance): + rep = self.frame.repr(result) + pattern = "%s\n{%s = %s\n}" + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def visit_Assert(self, assrt): + test_explanation, test_result = self.visit(assrt.test) + explanation = "assert %s" % (test_explanation,) + if not self.frame.is_true(test_result): + try: + raise BuiltinAssertionError + except Exception: + raise Failure(explanation) + return explanation, test_result + + def visit_Assign(self, assign): + value_explanation, value_result = self.visit(assign.value) + explanation = "... = %s" % (value_explanation,) + name = ast.Name("__exprinfo_expr", ast.Load(), + lineno=assign.value.lineno, + col_offset=assign.value.col_offset) + new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, + col_offset=assign.col_offset) + mod = ast.Module([new_assign]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co, __exprinfo_expr=value_result) + except Exception: + raise Failure(explanation) + return explanation, value_result diff --git a/_pytest/assertion/oldinterpret.py b/_pytest/assertion/oldinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/oldinterpret.py @@ -0,0 +1,552 @@ +import py +import sys, inspect +from compiler import parse, ast, pycodegen +from _pytest.assertion.util import format_explanation +from _pytest.assertion.reinterpret import BuiltinAssertionError + +passthroughex = py.builtin._sysex + +class Failure: + def __init__(self, node): + self.exc, self.value, self.tb = sys.exc_info() + self.node = node + +class View(object): + """View base class. + + If C is a subclass of View, then C(x) creates a proxy object around + the object x. The actual class of the proxy is not C in general, + but a *subclass* of C determined by the rules below. To avoid confusion + we call view class the class of the proxy (a subclass of C, so of View) + and object class the class of x. + + Attributes and methods not found in the proxy are automatically read on x. + Other operations like setting attributes are performed on the proxy, as + determined by its view class. The object x is available from the proxy + as its __obj__ attribute. + + The view class selection is determined by the __view__ tuples and the + optional __viewkey__ method. By default, the selected view class is the + most specific subclass of C whose __view__ mentions the class of x. + If no such subclass is found, the search proceeds with the parent + object classes. For example, C(True) will first look for a subclass + of C with __view__ = (..., bool, ...) and only if it doesn't find any + look for one with __view__ = (..., int, ...), and then ..., object,... + If everything fails the class C itself is considered to be the default. + + Alternatively, the view class selection can be driven by another aspect + of the object x, instead of the class of x, by overriding __viewkey__. + See last example at the end of this module. + """ + + _viewcache = {} + __view__ = () + + def __new__(rootclass, obj, *args, **kwds): + self = object.__new__(rootclass) + self.__obj__ = obj + self.__rootclass__ = rootclass + key = self.__viewkey__() + try: + self.__class__ = self._viewcache[key] + except KeyError: + self.__class__ = self._selectsubclass(key) + return self + + def __getattr__(self, attr): + # attributes not found in the normal hierarchy rooted on View + # are looked up in the object's real class + return getattr(self.__obj__, attr) + + def __viewkey__(self): + return self.__obj__.__class__ + + def __matchkey__(self, key, subclasses): + if inspect.isclass(key): + keys = inspect.getmro(key) + else: + keys = [key] + for key in keys: + result = [C for C in subclasses if key in C.__view__] + if result: + return result + return [] + + def _selectsubclass(self, key): + subclasses = list(enumsubclasses(self.__rootclass__)) + for C in subclasses: + if not isinstance(C.__view__, tuple): + C.__view__ = (C.__view__,) + choices = self.__matchkey__(key, subclasses) + if not choices: + return self.__rootclass__ + elif len(choices) == 1: + return choices[0] + else: + # combine the multiple choices + return type('?', tuple(choices), {}) + + def __repr__(self): + return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) + + +def enumsubclasses(cls): + for subcls in cls.__subclasses__(): + for subsubclass in enumsubclasses(subcls): + yield subsubclass + yield cls + + +class Interpretable(View): + """A parse tree node with a few extra methods.""" + explanation = None + + def is_builtin(self, frame): + return False + + def eval(self, frame): + # fall-back for unknown expression nodes + try: + expr = ast.Expression(self.__obj__) + expr.filename = '' + self.__obj__.filename = '' + co = pycodegen.ExpressionCodeGenerator(expr).getCode() + result = frame.eval(co) + except passthroughex: + raise + except: + raise Failure(self) + self.result = result + self.explanation = self.explanation or frame.repr(self.result) + + def run(self, frame): + # fall-back for unknown statement nodes + try: + expr = ast.Module(None, ast.Stmt([self.__obj__])) + expr.filename = '' + co = pycodegen.ModuleCodeGenerator(expr).getCode() + frame.exec_(co) + except passthroughex: + raise + except: + raise Failure(self) + + def nice_explanation(self): + return format_explanation(self.explanation) + + +class Name(Interpretable): + __view__ = ast.Name + + def is_local(self, frame): + source = '%r in locals() is not globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_global(self, frame): + source = '%r in globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_builtin(self, frame): + source = '%r not in locals() and %r not in globals()' % ( + self.name, self.name) + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + super(Name, self).eval(frame) + if not self.is_local(frame): + self.explanation = self.name + +class Compare(Interpretable): + __view__ = ast.Compare + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + for operation, expr2 in self.ops: + if hasattr(self, 'result'): + # shortcutting in chained expressions + if not frame.is_true(self.result): + break + expr2 = Interpretable(expr2) + expr2.eval(frame) + self.explanation = "%s %s %s" % ( + expr.explanation, operation, expr2.explanation) + source = "__exprinfo_left %s __exprinfo_right" % operation + try: + self.result = frame.eval(source, + __exprinfo_left=expr.result, + __exprinfo_right=expr2.result) + except passthroughex: + raise + except: + raise Failure(self) + expr = expr2 + +class And(Interpretable): + __view__ = ast.And + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if not frame.is_true(expr.result): + break + self.explanation = '(' + ' and '.join(explanations) + ')' + +class Or(Interpretable): + __view__ = ast.Or + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if frame.is_true(expr.result): + break + self.explanation = '(' + ' or '.join(explanations) + ')' + + +# == Unary operations == +keepalive = [] +for astclass, astpattern in { + ast.Not : 'not __exprinfo_expr', + ast.Invert : '(~__exprinfo_expr)', + }.items(): + + class UnaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + expr = Interpretable(self.expr) + expr.eval(frame) + self.explanation = astpattern.replace('__exprinfo_expr', + expr.explanation) + try: + self.result = frame.eval(astpattern, + __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(UnaryArith) + +# == Binary operations == +for astclass, astpattern in { + ast.Add : '(__exprinfo_left + __exprinfo_right)', + ast.Sub : '(__exprinfo_left - __exprinfo_right)', + ast.Mul : '(__exprinfo_left * __exprinfo_right)', + ast.Div : '(__exprinfo_left / __exprinfo_right)', + ast.Mod : '(__exprinfo_left % __exprinfo_right)', + ast.Power : '(__exprinfo_left ** __exprinfo_right)', + }.items(): + + class BinaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + left = Interpretable(self.left) + left.eval(frame) + right = Interpretable(self.right) + right.eval(frame) + self.explanation = (astpattern + .replace('__exprinfo_left', left .explanation) + .replace('__exprinfo_right', right.explanation)) + try: + self.result = frame.eval(astpattern, + __exprinfo_left=left.result, + __exprinfo_right=right.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(BinaryArith) + + +class CallFunc(Interpretable): + __view__ = ast.CallFunc + + def is_bool(self, frame): + source = 'isinstance(__exprinfo_value, bool)' + try: + return frame.is_true(frame.eval(source, + __exprinfo_value=self.result)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + node = Interpretable(self.node) + node.eval(frame) + explanations = [] + vars = {'__exprinfo_fn': node.result} + source = '__exprinfo_fn(' + for a in self.args: + if isinstance(a, ast.Keyword): + keyword = a.name + a = a.expr + else: + keyword = None + a = Interpretable(a) + a.eval(frame) + argname = '__exprinfo_%d' % len(vars) + vars[argname] = a.result + if keyword is None: + source += argname + ',' + explanations.append(a.explanation) + else: + source += '%s=%s,' % (keyword, argname) + explanations.append('%s=%s' % (keyword, a.explanation)) + if self.star_args: + star_args = Interpretable(self.star_args) + star_args.eval(frame) + argname = '__exprinfo_star' + vars[argname] = star_args.result + source += '*' + argname + ',' + explanations.append('*' + star_args.explanation) + if self.dstar_args: + dstar_args = Interpretable(self.dstar_args) + dstar_args.eval(frame) + argname = '__exprinfo_kwds' + vars[argname] = dstar_args.result + source += '**' + argname + ',' + explanations.append('**' + dstar_args.explanation) + self.explanation = "%s(%s)" % ( + node.explanation, ', '.join(explanations)) + if source.endswith(','): + source = source[:-1] + source += ')' + try: + self.result = frame.eval(source, **vars) + except passthroughex: + raise + except: + raise Failure(self) + if not node.is_builtin(frame) or not self.is_bool(frame): + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +class Getattr(Interpretable): + __view__ = ast.Getattr + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + source = '__exprinfo_expr.%s' % self.attrname + try: + self.result = frame.eval(source, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + self.explanation = '%s.%s' % (expr.explanation, self.attrname) + # if the attribute comes from the instance, its value is interesting + source = ('hasattr(__exprinfo_expr, "__dict__") and ' + '%r in __exprinfo_expr.__dict__' % self.attrname) + try: + from_instance = frame.is_true( + frame.eval(source, __exprinfo_expr=expr.result)) + except passthroughex: + raise + except: + from_instance = True + if from_instance: + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +# == Re-interpretation of full statements == + +class Assert(Interpretable): + __view__ = ast.Assert + + def run(self, frame): + test = Interpretable(self.test) + test.eval(frame) + # print the result as 'assert ' + self.result = test.result + self.explanation = 'assert ' + test.explanation + if not frame.is_true(test.result): + try: + raise BuiltinAssertionError + except passthroughex: + raise + except: + raise Failure(self) + +class Assign(Interpretable): + __view__ = ast.Assign + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = '... = ' + expr.explanation + # fall-back-run the rest of the assignment + ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) + mod = ast.Module(None, ast.Stmt([ass])) + mod.filename = '' + co = pycodegen.ModuleCodeGenerator(mod).getCode() + try: + frame.exec_(co, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + +class Discard(Interpretable): + __view__ = ast.Discard + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = expr.explanation + +class Stmt(Interpretable): + __view__ = ast.Stmt + + def run(self, frame): + for stmt in self.nodes: + stmt = Interpretable(stmt) + stmt.run(frame) + + +def report_failure(e): + explanation = e.node.nice_explanation() + if explanation: + explanation = ", in: " + explanation + else: + explanation = "" + sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) + +def check(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + expr = parse(s, 'eval') + assert isinstance(expr, ast.Expression) + node = Interpretable(expr.node) + try: + node.eval(frame) + except passthroughex: + raise + except Failure: + e = sys.exc_info()[1] + report_failure(e) + else: + if not frame.is_true(node.result): + sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) + + +########################################################### +# API / Entry points +# ######################################################### + +def interpret(source, frame, should_fail=False): + module = Interpretable(parse(source, 'exec').node) + #print "got module", module + if isinstance(frame, py.std.types.FrameType): + frame = py.code.Frame(frame) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + return getfailure(e) + except passthroughex: + raise + except: + import traceback + traceback.print_exc() + if should_fail: + return ("(assertion failed, but when it was re-run for " + "printing intermediate values, it did not fail. Suggestions: " + "compute assert expression before the assert or use --nomagic)") + else: + return None + +def getmsg(excinfo): + if isinstance(excinfo, tuple): + excinfo = py.code.ExceptionInfo(excinfo) + #frame, line = gettbline(tb) + #frame = py.code.Frame(frame) + #return interpret(line, frame) + + tb = excinfo.traceback[-1] + source = str(tb.statement).strip() + x = interpret(source, tb.frame, should_fail=True) + if not isinstance(x, str): + raise TypeError("interpret returned non-string %r" % (x,)) + return x + +def getfailure(e): + explanation = e.node.nice_explanation() + if str(e.value): + lines = explanation.split('\n') + lines[0] += " << %s" % (e.value,) + explanation = '\n'.join(lines) + text = "%s: %s" % (e.exc.__name__, explanation) + if text.startswith('AssertionError: assert '): + text = text[16:] + return text + +def run(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + module = Interpretable(parse(s, 'exec').node) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + report_failure(e) + + +if __name__ == '__main__': + # example: + def f(): + return 5 + def g(): + return 3 + def h(x): + return 'never' + check("f() * g() == 5") + check("not f()") + check("not (f() and g() or 0)") + check("f() == g()") + i = 4 + check("i == f()") + check("len(f()) == 0") + check("isinstance(2+3+4, float)") + + run("x = i") + check("x == 5") + + run("assert not f(), 'oops'") + run("a, b, c = 1, 2") + run("a, b, c = f()") + + check("max([f(),g()]) == 4") + check("'hello'[g()] == 'h'") + run("'guk%d' % h(f())") diff --git a/_pytest/assertion/reinterpret.py b/_pytest/assertion/reinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/reinterpret.py @@ -0,0 +1,48 @@ +import sys +import py + +BuiltinAssertionError = py.builtin.builtins.AssertionError + +class AssertionError(BuiltinAssertionError): + def __init__(self, *args): + BuiltinAssertionError.__init__(self, *args) + if args: + try: + self.msg = str(args[0]) + except py.builtin._sysex: + raise + except: + self.msg = "<[broken __repr__] %s at %0xd>" %( + args[0].__class__, id(args[0])) + else: + f = py.code.Frame(sys._getframe(1)) + try: + source = f.code.fullsource + if source is not None: + try: + source = source.getstatement(f.lineno, assertion=True) + except IndexError: + source = None + else: + source = str(source.deindent()).strip() + except py.error.ENOENT: + source = None + # this can also occur during reinterpretation, when the + # co_filename is set to "". + if source: + self.msg = reinterpret(source, f, should_fail=True) + else: + self.msg = "" + if not self.args: + self.args = (self.msg,) + +if sys.version_info > (3, 0): + AssertionError.__module__ = "builtins" + reinterpret_old = "old reinterpretation not available for py3" +else: + from _pytest.assertion.oldinterpret import interpret as reinterpret_old +if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): + from _pytest.assertion.newinterpret import interpret as reinterpret +else: + reinterpret = reinterpret_old + diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/rewrite.py @@ -0,0 +1,340 @@ +"""Rewrite assertion AST to produce nice error messages""" + +import ast +import collections +import itertools +import sys + +import py +from _pytest.assertion import util + + +def rewrite_asserts(mod): + """Rewrite the assert statements in mod.""" + AssertionRewriter().run(mod) + + +_saferepr = py.io.saferepr +from _pytest.assertion.util import format_explanation as _format_explanation + +def _format_boolop(operands, explanations, is_or): + show_explanations = [] + for operand, expl in zip(operands, explanations): + show_explanations.append(expl) + if operand == is_or: + break + return "(" + (is_or and " or " or " and ").join(show_explanations) + ")" + +def _call_reprcompare(ops, results, expls, each_obj): + for i, res, expl in zip(range(len(ops)), results, expls): + try: + done = not res + except Exception: + done = True + if done: + break + if util._reprcompare is not None: + custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1]) + if custom is not None: + return custom + return expl + + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + +binop_map = { + ast.BitOr : "|", + ast.BitXor : "^", + ast.BitAnd : "&", + ast.LShift : "<<", + ast.RShift : ">>", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + + +def set_location(node, lineno, col_offset): + """Set node location information recursively.""" + def _fix(node, lineno, col_offset): + if "lineno" in node._attributes: + node.lineno = lineno + if "col_offset" in node._attributes: + node.col_offset = col_offset + for child in ast.iter_child_nodes(node): + _fix(child, lineno, col_offset) + _fix(node, lineno, col_offset) + return node + + +class AssertionRewriter(ast.NodeVisitor): + + def run(self, mod): + """Find all assert statements in *mod* and rewrite them.""" + if not mod.body: + # Nothing to do. + return + # Insert some special imports at the top of the module but after any + # docstrings and __future__ imports. + aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"), + ast.alias("_pytest.assertion.rewrite", "@pytest_ar")] + expect_docstring = True + pos = 0 + lineno = 0 + for item in mod.body: + if (expect_docstring and isinstance(item, ast.Expr) and + isinstance(item.value, ast.Str)): + doc = item.value.s + if "PYTEST_DONT_REWRITE" in doc: + # The module has disabled assertion rewriting. + return + lineno += len(doc) - 1 + expect_docstring = False + elif (not isinstance(item, ast.ImportFrom) or item.level > 0 and + item.identifier != "__future__"): + lineno = item.lineno + break + pos += 1 + imports = [ast.Import([alias], lineno=lineno, col_offset=0) + for alias in aliases] + mod.body[pos:pos] = imports + # Collect asserts. + nodes = collections.deque([mod]) + while nodes: + node = nodes.popleft() + for name, field in ast.iter_fields(node): + if isinstance(field, list): + new = [] + for i, child in enumerate(field): + if isinstance(child, ast.Assert): + # Transform assert. + new.extend(self.visit(child)) + else: + new.append(child) + if isinstance(child, ast.AST): + nodes.append(child) + setattr(node, name, new) + elif (isinstance(field, ast.AST) and + # Don't recurse into expressions as they can't contain + # asserts. + not isinstance(field, ast.expr)): + nodes.append(field) + + def variable(self): + """Get a new variable.""" + # Use a character invalid in python identifiers to avoid clashing. + name = "@py_assert" + str(next(self.variable_counter)) + self.variables.add(name) + return name + + def assign(self, expr): + """Give *expr* a name.""" + name = self.variable() + self.statements.append(ast.Assign([ast.Name(name, ast.Store())], expr)) + return ast.Name(name, ast.Load()) + + def display(self, expr): + """Call py.io.saferepr on the expression.""" + return self.helper("saferepr", expr) + + def helper(self, name, *args): + """Call a helper in this module.""" + py_name = ast.Name("@pytest_ar", ast.Load()) + attr = ast.Attribute(py_name, "_" + name, ast.Load()) + return ast.Call(attr, list(args), [], None, None) + + def builtin(self, name): + """Return the builtin called *name*.""" + builtin_name = ast.Name("@py_builtins", ast.Load()) + return ast.Attribute(builtin_name, name, ast.Load()) + + def explanation_param(self, expr): + specifier = "py" + str(next(self.variable_counter)) + self.explanation_specifiers[specifier] = expr + return "%(" + specifier + ")s" + + def push_format_context(self): + self.explanation_specifiers = {} + self.stack.append(self.explanation_specifiers) + + def pop_format_context(self, expl_expr): + current = self.stack.pop() + if self.stack: + self.explanation_specifiers = self.stack[-1] + keys = [ast.Str(key) for key in current.keys()] + format_dict = ast.Dict(keys, list(current.values())) + form = ast.BinOp(expl_expr, ast.Mod(), format_dict) + name = "@py_format" + str(next(self.variable_counter)) + self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form)) + return ast.Name(name, ast.Load()) + + def generic_visit(self, node): + """Handle expressions we don't have custom code for.""" + assert isinstance(node, ast.expr) + res = self.assign(node) + return res, self.explanation_param(self.display(res)) + + def visit_Assert(self, assert_): + if assert_.msg: + # There's already a message. Don't mess with it. + return [assert_] + self.statements = [] + self.variables = set() + self.variable_counter = itertools.count() + self.stack = [] + self.on_failure = [] + self.push_format_context() + # Rewrite assert into a bunch of statements. + top_condition, explanation = self.visit(assert_.test) + # Create failure message. + body = self.on_failure + negation = ast.UnaryOp(ast.Not(), top_condition) + self.statements.append(ast.If(negation, body, [])) + explanation = "assert " + explanation + template = ast.Str(explanation) + msg = self.pop_format_context(template) + fmt = self.helper("format_explanation", msg) + err_name = ast.Name("AssertionError", ast.Load()) + exc = ast.Call(err_name, [fmt], [], None, None) + if sys.version_info[0] >= 3: + raise_ = ast.Raise(exc, None) + else: + raise_ = ast.Raise(exc, None, None) + body.append(raise_) + # Delete temporary variables. + names = [ast.Name(name, ast.Del()) for name in self.variables] + if names: + delete = ast.Delete(names) + self.statements.append(delete) + # Fix line numbers. + for stmt in self.statements: + set_location(stmt, assert_.lineno, assert_.col_offset) + return self.statements + + def visit_Name(self, name): + # Check if the name is local or not. + locs = ast.Call(self.builtin("locals"), [], [], None, None) + globs = ast.Call(self.builtin("globals"), [], [], None, None) + ops = [ast.In(), ast.IsNot()] + test = ast.Compare(ast.Str(name.id), ops, [locs, globs]) + expr = ast.IfExp(test, self.display(name), ast.Str(name.id)) + return name, self.explanation_param(expr) + + def visit_BoolOp(self, boolop): + operands = [] + explanations = [] + self.push_format_context() + for operand in boolop.values: + res, explanation = self.visit(operand) + operands.append(res) + explanations.append(explanation) + expls = ast.Tuple([ast.Str(expl) for expl in explanations], ast.Load()) + is_or = ast.Num(isinstance(boolop.op, ast.Or)) + expl_template = self.helper("format_boolop", + ast.Tuple(operands, ast.Load()), expls, + is_or) + expl = self.pop_format_context(expl_template) + res = self.assign(ast.BoolOp(boolop.op, operands)) + return res, self.explanation_param(expl) + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_res, operand_expl = self.visit(unary.operand) + res = self.assign(ast.UnaryOp(unary.op, operand_res)) + return res, pattern % (operand_expl,) + + def visit_BinOp(self, binop): + symbol = binop_map[binop.op.__class__] + left_expr, left_expl = self.visit(binop.left) + right_expr, right_expl = self.visit(binop.right) + explanation = "(%s %s %s)" % (left_expl, symbol, right_expl) + res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) + return res, explanation + + def visit_Call(self, call): + new_func, func_expl = self.visit(call.func) + arg_expls = [] + new_args = [] + new_kwargs = [] + new_star = new_kwarg = None + for arg in call.args: + res, expl = self.visit(arg) + new_args.append(res) + arg_expls.append(expl) + for keyword in call.keywords: + res, expl = self.visit(keyword.value) + new_kwargs.append(ast.keyword(keyword.arg, res)) + arg_expls.append(keyword.arg + "=" + expl) + if call.starargs: + new_star, expl = self.visit(call.starargs) + arg_expls.append("*" + expl) + if call.kwargs: + new_kwarg, expl = self.visit(call.kwarg) + arg_expls.append("**" + expl) + expl = "%s(%s)" % (func_expl, ', '.join(arg_expls)) + new_call = ast.Call(new_func, new_args, new_kwargs, new_star, new_kwarg) + res = self.assign(new_call) + res_expl = self.explanation_param(self.display(res)) + outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl) + return res, outer_expl + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + value, value_expl = self.visit(attr.value) + res = self.assign(ast.Attribute(value, attr.attr, ast.Load())) + res_expl = self.explanation_param(self.display(res)) + pat = "%s\n{%s = %s.%s\n}" + expl = pat % (res_expl, res_expl, value_expl, attr.attr) + return res, expl + + def visit_Compare(self, comp): + self.push_format_context() + left_res, left_expl = self.visit(comp.left) + res_variables = [self.variable() for i in range(len(comp.ops))] + load_names = [ast.Name(v, ast.Load()) for v in res_variables] + store_names = [ast.Name(v, ast.Store()) for v in res_variables] + it = zip(range(len(comp.ops)), comp.ops, comp.comparators) + expls = [] + syms = [] + results = [left_res] + for i, op, next_operand in it: + next_res, next_expl = self.visit(next_operand) + results.append(next_res) + sym = binop_map[op.__class__] + syms.append(ast.Str(sym)) + expl = "%s %s %s" % (left_expl, sym, next_expl) + expls.append(ast.Str(expl)) + res_expr = ast.Compare(left_res, [op], [next_res]) + self.statements.append(ast.Assign([store_names[i]], res_expr)) + left_res, left_expl = next_res, next_expl + # Use py.code._reprcompare if that's available. + expl_call = self.helper("call_reprcompare", + ast.Tuple(syms, ast.Load()), + ast.Tuple(load_names, ast.Load()), + ast.Tuple(expls, ast.Load()), + ast.Tuple(results, ast.Load())) + if len(comp.ops) > 1: + res = ast.BoolOp(ast.And(), load_names) + else: + res = load_names[0] + return res, self.explanation_param(self.pop_format_context(expl_call)) diff --git a/_pytest/assertion/util.py b/_pytest/assertion/util.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/util.py @@ -0,0 +1,213 @@ +"""Utilities for assertion debugging""" + +import py + + +# The _reprcompare attribute on the util module is used by the new assertion +# interpretation code and assertion rewriter to detect this plugin was +# loaded and in turn call the hooks defined here as part of the +# DebugInterpreter. +_reprcompare = None + +def format_explanation(explanation): + """This formats an explanation + + Normally all embedded newlines are escaped, however there are + three exceptions: \n{, \n} and \n~. The first two are intended + cover nested explanations, see function and attribute explanations + for examples (.visit_Call(), visit_Attribute()). The last one is + for when one explanation needs to span multiple lines, e.g. when + displaying diffs. + """ + # simplify 'assert False where False = ...' + where = 0 + while True: + start = where = explanation.find("False\n{False = ", where) + if where == -1: + break + level = 0 + for i, c in enumerate(explanation[start:]): + if c == "{": + level += 1 + elif c == "}": + level -= 1 + if not level: + break + else: + raise AssertionError("unbalanced braces: %r" % (explanation,)) + end = start + i + where = end + if explanation[end - 1] == '\n': + explanation = (explanation[:start] + explanation[start+15:end-1] + + explanation[end+1:]) + where -= 17 + raw_lines = (explanation or '').split('\n') + # escape newlines not followed by {, } and ~ + lines = [raw_lines[0]] + for l in raw_lines[1:]: + if l.startswith('{') or l.startswith('}') or l.startswith('~'): + lines.append(l) + else: + lines[-1] += '\\n' + l + + result = lines[:1] + stack = [0] + stackcnt = [0] + for line in lines[1:]: + if line.startswith('{'): + if stackcnt[-1]: + s = 'and ' + else: + s = 'where ' + stack.append(len(result)) + stackcnt[-1] += 1 + stackcnt.append(0) + result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) + elif line.startswith('}'): + assert line.startswith('}') + stack.pop() + stackcnt.pop() + result[stack[-1]] += line[1:] + else: + assert line.startswith('~') + result.append(' '*len(stack) + line[1:]) + assert len(stack) == 1 + return '\n'.join(result) + + +# Provide basestring in python3 +try: + basestring = basestring +except NameError: + basestring = str + + +def assertrepr_compare(op, left, right): + """return specialised explanations for some operators/operands""" + width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op + left_repr = py.io.saferepr(left, maxsize=int(width/2)) + right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) + summary = '%s %s %s' % (left_repr, op, right_repr) + + issequence = lambda x: isinstance(x, (list, tuple)) + istext = lambda x: isinstance(x, basestring) + isdict = lambda x: isinstance(x, dict) + isset = lambda x: isinstance(x, set) + + explanation = None + try: + if op == '==': + if istext(left) and istext(right): + explanation = _diff_text(left, right) + elif issequence(left) and issequence(right): + explanation = _compare_eq_sequence(left, right) + elif isset(left) and isset(right): + explanation = _compare_eq_set(left, right) + elif isdict(left) and isdict(right): + explanation = _diff_text(py.std.pprint.pformat(left), + py.std.pprint.pformat(right)) + elif op == 'not in': + if istext(left) and istext(right): + explanation = _notin_text(left, right) + except py.builtin._sysex: + raise + except: + excinfo = py.code.ExceptionInfo() + explanation = ['(pytest_assertion plugin: representation of ' + 'details failed. Probably an object has a faulty __repr__.)', + str(excinfo) + ] + + + if not explanation: + return None + + # Don't include pageloads of data, should be configurable + if len(''.join(explanation)) > 80*8: + explanation = ['Detailed information too verbose, truncated'] + + return [summary] + explanation + + +def _diff_text(left, right): + """Return the explanation for the diff between text + + This will skip leading and trailing characters which are + identical to keep the diff minimal. + """ + explanation = [] + i = 0 # just in case left or right has zero length + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + break + if i > 42: + i -= 10 # Provide some context + explanation = ['Skipping %s identical ' + 'leading characters in diff' % i] + left = left[i:] + right = right[i:] + if len(left) == len(right): + for i in range(len(left)): + if left[-i] != right[-i]: + break + if i > 42: + i -= 10 # Provide some context + explanation += ['Skipping %s identical ' + 'trailing characters in diff' % i] + left = left[:-i] + right = right[:-i] + explanation += [line.strip('\n') + for line in py.std.difflib.ndiff(left.splitlines(), + right.splitlines())] + return explanation + + +def _compare_eq_sequence(left, right): + explanation = [] + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + explanation += ['At index %s diff: %r != %r' % + (i, left[i], right[i])] + break + if len(left) > len(right): + explanation += ['Left contains more items, ' + 'first extra item: %s' % py.io.saferepr(left[len(right)],)] + elif len(left) < len(right): + explanation += ['Right contains more items, ' + 'first extra item: %s' % py.io.saferepr(right[len(left)],)] + return explanation # + _diff_text(py.std.pprint.pformat(left), + # py.std.pprint.pformat(right)) + + +def _compare_eq_set(left, right): + explanation = [] + diff_left = left - right + diff_right = right - left + if diff_left: + explanation.append('Extra items in the left set:') + for item in diff_left: + explanation.append(py.io.saferepr(item)) + if diff_right: + explanation.append('Extra items in the right set:') + for item in diff_right: + explanation.append(py.io.saferepr(item)) + return explanation + + +def _notin_text(term, text): + index = text.find(term) + head = text[:index] + tail = text[index+len(term):] + correct_text = head + tail + diff = _diff_text(correct_text, text) + newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] + for line in diff: + if line.startswith('Skipping'): + continue + if line.startswith('- '): + continue + if line.startswith('+ '): + newdiff.append(' ' + line[2:]) + else: + newdiff.append(line) + return newdiff diff --git a/_pytest/doctest.py b/_pytest/doctest.py --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -59,7 +59,7 @@ inner_excinfo = py.code.ExceptionInfo(excinfo.value.exc_info) lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)] - + lines += py.std.traceback.format_exception(*excinfo.value.exc_info) return ReprFailDoctest(reprlocation, lines) else: return super(DoctestItem, self).repr_failure(excinfo) diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -16,9 +16,6 @@ group.addoption('--traceconfig', action="store_true", dest="traceconfig", default=False, help="trace considerations of conftest.py files."), - group._addoption('--nomagic', - action="store_true", dest="nomagic", default=False, - help="don't reinterpret asserts, no traceback cutting. ") group.addoption('--debug', action="store_true", dest="debug", default=False, help="generate and show internal debugging information.") diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -65,7 +65,8 @@ class LogXML(object): def __init__(self, logfile, prefix): - self.logfile = logfile + logfile = os.path.expanduser(os.path.expandvars(logfile)) + self.logfile = os.path.normpath(logfile) self.prefix = prefix self.test_logs = [] self.passed = self.skipped = 0 @@ -76,7 +77,7 @@ names = report.nodeid.split("::") names[0] = names[0].replace("/", '.') names = tuple(names) - d = {'time': self._durations.pop(names, "0")} + d = {'time': self._durations.pop(report.nodeid, "0")} names = [x.replace(".py", "") for x in names if x != "()"] classnames = names[:-1] if self.prefix: @@ -170,12 +171,11 @@ self.append_skipped(report) def pytest_runtest_call(self, item, __multicall__): - names = tuple(item.listnames()) start = time.time() try: return __multicall__.execute() finally: - self._durations[names] = time.time() - start + self._durations[item.nodeid] = time.time() - start def pytest_collectreport(self, report): if not report.passed: diff --git a/_pytest/main.py b/_pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -46,23 +46,25 @@ def pytest_namespace(): - return dict(collect=dict(Item=Item, Collector=Collector, File=File)) + collect = dict(Item=Item, Collector=Collector, File=File, Session=Session) + return dict(collect=collect) def pytest_configure(config): py.test.config = config # compatibiltiy if config.option.exitfirst: config.option.maxfail = 1 -def pytest_cmdline_main(config): - """ default command line protocol for initialization, session, - running tests and reporting. """ +def wrap_session(config, doit): + """Skeleton command line program""" session = Session(config) session.exitstatus = EXIT_OK + initstate = 0 try: config.pluginmanager.do_configure(config) + initstate = 1 config.hook.pytest_sessionstart(session=session) - config.hook.pytest_collection(session=session) - config.hook.pytest_runtestloop(session=session) + initstate = 2 + doit(config, session) except pytest.UsageError: raise except KeyboardInterrupt: @@ -77,18 +79,24 @@ sys.stderr.write("mainloop: caught Spurious SystemExit!\n") if not session.exitstatus and session._testsfailed: session.exitstatus = EXIT_TESTSFAILED - config.hook.pytest_sessionfinish(session=session, - exitstatus=session.exitstatus) - config.pluginmanager.do_unconfigure(config) + if initstate >= 2: + config.hook.pytest_sessionfinish(session=session, + exitstatus=session.exitstatus) + if initstate >= 1: + config.pluginmanager.do_unconfigure(config) return session.exitstatus +def pytest_cmdline_main(config): + return wrap_session(config, _main) + +def _main(config, session): + """ default command line protocol for initialization, session, + running tests and reporting. """ + config.hook.pytest_collection(session=session) + config.hook.pytest_runtestloop(session=session) + def pytest_collection(session): - session.perform_collect() - hook = session.config.hook - hook.pytest_collection_modifyitems(session=session, - config=session.config, items=session.items) - hook.pytest_collection_finish(session=session) - return True + return session.perform_collect() def pytest_runtestloop(session): if session.config.option.collectonly: @@ -374,6 +382,16 @@ return HookProxy(fspath, self.config) def perform_collect(self, args=None, genitems=True): + hook = self.config.hook + try: + items = self._perform_collect(args, genitems) + hook.pytest_collection_modifyitems(session=self, + config=self.config, items=items) + finally: + hook.pytest_collection_finish(session=self) + return items + + def _perform_collect(self, args, genitems): if args is None: args = self.config.args self.trace("perform_collect", self, args) diff --git a/_pytest/mark.py b/_pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -153,7 +153,7 @@ def __repr__(self): return "" % ( - self._name, self.args, self.kwargs) + self.name, self.args, self.kwargs) def pytest_itemcollected(item): if not isinstance(item, pytest.Function): diff --git a/_pytest/pytester.py b/_pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -6,7 +6,7 @@ import inspect import time from fnmatch import fnmatch -from _pytest.main import Session +from _pytest.main import Session, EXIT_OK from py.builtin import print_ from _pytest.core import HookRelay @@ -292,13 +292,19 @@ assert '::' not in str(arg) p = py.path.local(arg) x = session.fspath.bestrelpath(p) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def getpathnode(self, path): - config = self.parseconfig(path) + config = self.parseconfigure(path) session = Session(config) x = session.fspath.bestrelpath(path) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def genitems(self, colitems): session = colitems[0].session @@ -312,7 +318,9 @@ config = self.parseconfigure(*args) rec = self.getreportrecorder(config) session = Session(config) + config.hook.pytest_sessionstart(session=session) session.perform_collect() + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) return session.items, rec def runitem(self, source): @@ -382,6 +390,8 @@ c.basetemp = py.path.local.make_numbered_dir(prefix="reparse", keep=0, rootdir=self.tmpdir, lock_timeout=None) c.parse(args) + c.pluginmanager.do_configure(c) + self.request.addfinalizer(lambda: c.pluginmanager.do_unconfigure(c)) return c finally: py.test.config = oldconfig diff --git a/_pytest/python.py b/_pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -226,8 +226,13 @@ def _importtestmodule(self): # we assume we are only called once per module + from _pytest import assertion + assertion.before_module_import(self) try: - mod = self.fspath.pyimport(ensuresyspath=True) + try: + mod = self.fspath.pyimport(ensuresyspath=True) + finally: + assertion.after_module_import(self) except SyntaxError: excinfo = py.code.ExceptionInfo() raise self.CollectError(excinfo.getrepr(style="short")) @@ -374,7 +379,7 @@ # test generators are seen as collectors but they also # invoke setup/teardown on popular request # (induced by the common "test_*" naming shared with normal tests) - self.config._setupstate.prepare(self) + self.session._setupstate.prepare(self) # see FunctionMixin.setup and test_setupstate_is_preserved_134 self._preservedparent = self.parent.obj l = [] @@ -721,7 +726,7 @@ def _addfinalizer(self, finalizer, scope): colitem = self._getscopeitem(scope) - self.config._setupstate.addfinalizer( + self._pyfuncitem.session._setupstate.addfinalizer( finalizer=finalizer, colitem=colitem) def __repr__(self): @@ -742,8 +747,10 @@ raise self.LookupError(msg) def showfuncargs(config): - from _pytest.main import Session - session = Session(config) + from _pytest.main import wrap_session + return wrap_session(config, _showfuncargs_main) + +def _showfuncargs_main(config, session): session.perform_collect() if session.items: plugins = session.items[0].getplugins() diff --git a/_pytest/runner.py b/_pytest/runner.py --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -14,17 +14,15 @@ # # pytest plugin hooks -# XXX move to pytest_sessionstart and fix py.test owns tests -def pytest_configure(config): - config._setupstate = SetupState() +def pytest_sessionstart(session): + session._setupstate = SetupState() def pytest_sessionfinish(session, exitstatus): - if hasattr(session.config, '_setupstate'): - hook = session.config.hook - rep = hook.pytest__teardown_final(session=session) - if rep: - hook.pytest__teardown_final_logerror(session=session, report=rep) - session.exitstatus = 1 + hook = session.config.hook + rep = hook.pytest__teardown_final(session=session) + if rep: + hook.pytest__teardown_final_logerror(session=session, report=rep) + session.exitstatus = 1 class NodeInfo: def __init__(self, location): @@ -46,16 +44,16 @@ return reports def pytest_runtest_setup(item): - item.config._setupstate.prepare(item) + item.session._setupstate.prepare(item) def pytest_runtest_call(item): item.runtest() def pytest_runtest_teardown(item): - item.config._setupstate.teardown_exact(item) + item.session._setupstate.teardown_exact(item) def pytest__teardown_final(session): - call = CallInfo(session.config._setupstate.teardown_all, when="teardown") + call = CallInfo(session._setupstate.teardown_all, when="teardown") if call.excinfo: ntraceback = call.excinfo.traceback .cut(excludepath=py._pydir) call.excinfo.traceback = ntraceback.filter() diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -569,7 +569,6 @@ # import os import time -import socket import getpass class ReallyRunFileExternal(py.test.collect.Item): diff --git a/lib-python/modified-2.7/ctypes/__init__.py b/lib-python/modified-2.7/ctypes/__init__.py --- a/lib-python/modified-2.7/ctypes/__init__.py +++ b/lib-python/modified-2.7/ctypes/__init__.py @@ -7,6 +7,7 @@ __version__ = "1.1.0" +import _ffi from _ctypes import Union, Structure, Array from _ctypes import _Pointer from _ctypes import CFuncPtr as _CFuncPtr @@ -350,7 +351,7 @@ self._FuncPtr = _FuncPtr if handle is None: - self._handle = _dlopen(self._name, mode) + self._handle = _ffi.CDLL(name) else: self._handle = handle diff --git a/lib-python/modified-2.7/ctypes/test/test_cfuncs.py b/lib-python/modified-2.7/ctypes/test/test_cfuncs.py --- a/lib-python/modified-2.7/ctypes/test/test_cfuncs.py +++ b/lib-python/modified-2.7/ctypes/test/test_cfuncs.py @@ -3,8 +3,8 @@ import unittest from ctypes import * - import _ctypes_test +from test.test_support import impl_detail class CFunctions(unittest.TestCase): _dll = CDLL(_ctypes_test.__file__) @@ -158,12 +158,14 @@ self.assertEqual(self._dll.tf_bd(0, 42.), 14.) self.assertEqual(self.S(), 42) + @impl_detail('long double not supported by PyPy', pypy=False) def test_longdouble(self): self._dll.tf_D.restype = c_longdouble self._dll.tf_D.argtypes = (c_longdouble,) self.assertEqual(self._dll.tf_D(42.), 14.) self.assertEqual(self.S(), 42) - + + @impl_detail('long double not supported by PyPy', pypy=False) def test_longdouble_plus(self): self._dll.tf_bD.restype = c_longdouble self._dll.tf_bD.argtypes = (c_byte, c_longdouble) diff --git a/lib-python/modified-2.7/ctypes/test/test_functions.py b/lib-python/modified-2.7/ctypes/test/test_functions.py --- a/lib-python/modified-2.7/ctypes/test/test_functions.py +++ b/lib-python/modified-2.7/ctypes/test/test_functions.py @@ -8,6 +8,7 @@ from ctypes import * import sys, unittest from ctypes.test import xfail +from test.test_support import impl_detail try: WINFUNCTYPE @@ -144,6 +145,7 @@ self.assertEqual(result, -21) self.assertEqual(type(result), float) + @impl_detail('long double not supported by PyPy', pypy=False) def test_longdoubleresult(self): f = dll._testfunc_D_bhilfD f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble] diff --git a/lib-python/modified-2.7/ctypes/test/test_libc.py b/lib-python/modified-2.7/ctypes/test/test_libc.py --- a/lib-python/modified-2.7/ctypes/test/test_libc.py +++ b/lib-python/modified-2.7/ctypes/test/test_libc.py @@ -26,6 +26,7 @@ self.assertEqual(chars.raw, " ,,aaaadmmmnpppsss\x00") def test_no_more_xfail(self): + import socket import ctypes.test self.assertTrue(not hasattr(ctypes.test, 'xfail'), "You should incrementally grep for '@xfail' and remove them, they are real failures") diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,13 +4399,10 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__self__ is l) + if hasattr(l.__add__, '__objclass__'): # CPython self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) + else: # PyPy self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_extcall.py b/lib-python/modified-2.7/test/test_extcall.py --- a/lib-python/modified-2.7/test/test_extcall.py +++ b/lib-python/modified-2.7/test/test_extcall.py @@ -299,7 +299,7 @@ def f(a): return a self.assertEqual(f(**{u'a': 4}), 4) - self.assertRaises(TypeError, lambda: f(**{u'stören': 4})) + self.assertRaises(TypeError, f, **{u'stören': 4}) self.assertRaises(TypeError, f, **{u'someLongString':2}) try: f(a=4, **{u'a': 4}) diff --git a/lib-python/2.7/test/test_multibytecodec.py b/lib-python/modified-2.7/test/test_multibytecodec.py copy from lib-python/2.7/test/test_multibytecodec.py copy to lib-python/modified-2.7/test/test_multibytecodec.py --- a/lib-python/2.7/test/test_multibytecodec.py +++ b/lib-python/modified-2.7/test/test_multibytecodec.py @@ -42,7 +42,7 @@ dec = codecs.getdecoder('euc-kr') myreplace = lambda exc: (u'', sys.maxint+1) codecs.register_error('test.cjktest', myreplace) - self.assertRaises(IndexError, dec, + self.assertRaises((IndexError, OverflowError), dec, 'apple\x92ham\x93spam', 'test.cjktest') def test_codingspec(self): diff --git a/lib-python/2.7/test/test_multibytecodec_support.py b/lib-python/modified-2.7/test/test_multibytecodec_support.py copy from lib-python/2.7/test/test_multibytecodec_support.py copy to lib-python/modified-2.7/test/test_multibytecodec_support.py --- a/lib-python/2.7/test/test_multibytecodec_support.py +++ b/lib-python/modified-2.7/test/test_multibytecodec_support.py @@ -107,8 +107,8 @@ def myreplace(exc): return (u'x', sys.maxint + 1) codecs.register_error("test.cjktest", myreplace) - self.assertRaises(IndexError, self.encode, self.unmappedunicode, - 'test.cjktest') + self.assertRaises((IndexError, OverflowError), self.encode, + self.unmappedunicode, 'test.cjktest') def test_callback_None_index(self): def myreplace(exc): diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib-python/modified-2.7/test/test_support.py b/lib-python/modified-2.7/test/test_support.py --- a/lib-python/modified-2.7/test/test_support.py +++ b/lib-python/modified-2.7/test/test_support.py @@ -1066,7 +1066,7 @@ if '--pdb' in sys.argv: import pdb, traceback traceback.print_tb(exc_info[2]) - pdb.post_mortem(exc_info[2], pdb.Pdb) + pdb.post_mortem(exc_info[2]) # ---------------------------------- diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py --- a/lib_pypy/_ctypes/array.py +++ b/lib_pypy/_ctypes/array.py @@ -208,6 +208,9 @@ def _get_buffer_value(self): return self._buffer.buffer + def _to_ffi_param(self): + return self._get_buffer_value() + ARRAY_CACHE = {} def create_array_type(base, length): diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -1,5 +1,6 @@ import _rawffi +import _ffi import sys keepalive_key = str # XXX fix this when provided with test @@ -46,6 +47,15 @@ else: return self.from_param(as_parameter) + def get_ffi_param(self, value): + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() + + def get_ffi_argtype(self): + if self._ffiargtype: + return self._ffiargtype + return _shape_to_ffi_type(self._ffiargshape) + def _CData_output(self, resbuffer, base=None, index=-1): #assert isinstance(resbuffer, _rawffi.ArrayInstance) """Used when data exits ctypes and goes into user code. @@ -99,6 +109,7 @@ """ __metaclass__ = _CDataMeta _objects = None + _ffiargtype = None def __init__(self, *args, **kwds): raise TypeError("%s has no type" % (type(self),)) @@ -119,11 +130,20 @@ def _get_buffer_value(self): return self._buffer[0] + def _to_ffi_param(self): + if self.__class__._is_pointer_like(): + return self._get_buffer_value() + else: + return self.value + def __buffer__(self): return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -150,7 +170,7 @@ return pointer(cdata) def cdata_from_address(self, address): - # fix the address, in case it's unsigned + # fix the address: turn it into as unsigned, in case it's a negative number address = address & (sys.maxint * 2 + 1) instance = self.__new__(self) lgt = getattr(self, '_length_', 1) @@ -159,3 +179,50 @@ def addressof(tp): return tp._buffer.buffer + + +# ---------------------------------------------------------------------- + +def is_struct_shape(shape): + # see the corresponding code to set the shape in + # _ctypes.structure._set_shape + return (isinstance(shape, tuple) and + len(shape) == 2 and + isinstance(shape[0], _rawffi.Structure) and + shape[1] == 1) + +def _shape_to_ffi_type(shape): + try: + return _shape_to_ffi_type.typemap[shape] + except KeyError: + pass + if is_struct_shape(shape): + return shape[0].get_ffi_type() + # + assert False, 'unknown shape %s' % (shape,) + + +_shape_to_ffi_type.typemap = { + 'c' : _ffi.types.char, + 'b' : _ffi.types.sbyte, + 'B' : _ffi.types.ubyte, + 'h' : _ffi.types.sshort, + 'u' : _ffi.types.unichar, + 'H' : _ffi.types.ushort, + 'i' : _ffi.types.sint, + 'I' : _ffi.types.uint, + 'l' : _ffi.types.slong, + 'L' : _ffi.types.ulong, + 'q' : _ffi.types.slonglong, + 'Q' : _ffi.types.ulonglong, + 'f' : _ffi.types.float, + 'd' : _ffi.types.double, + 's' : _ffi.types.void_p, + 'P' : _ffi.types.void_p, + 'z' : _ffi.types.void_p, + 'O' : _ffi.types.void_p, + 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, + } + diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -1,12 +1,15 @@ + +from _ctypes.basics import _CData, _CDataMeta, cdata_from_address +from _ctypes.primitive import SimpleType, _SimpleCData +from _ctypes.basics import ArgumentError, keepalive_key +from _ctypes.basics import is_struct_shape +from _ctypes.builtin import set_errno, set_last_error import _rawffi +import _ffi import sys import traceback import warnings -from _ctypes.basics import ArgumentError, keepalive_key -from _ctypes.basics import _CData, _CDataMeta, cdata_from_address -from _ctypes.builtin import set_errno, set_last_error -from _ctypes.primitive import SimpleType # XXX this file needs huge refactoring I fear @@ -24,6 +27,7 @@ WIN64 = sys.platform == 'win32' and sys.maxint == 2**63 - 1 + def get_com_error(errcode, riid, pIunk): "Win32 specific: build a COM Error exception" # XXX need C support code @@ -36,6 +40,7 @@ funcptr.restype = int return funcptr(*args) + class CFuncPtrType(_CDataMeta): # XXX write down here defaults and such things @@ -50,6 +55,7 @@ from_address = cdata_from_address + class CFuncPtr(_CData): __metaclass__ = CFuncPtrType @@ -65,10 +71,12 @@ callable = None _ptr = None _buffer = None + _address = None # win32 COM properties _paramflags = None _com_index = None _com_iid = None + _is_fastpath = False __restype_set = False @@ -85,8 +93,11 @@ raise TypeError( "item %d in _argtypes_ has no from_param method" % ( i + 1,)) - self._argtypes_ = argtypes - + # + if all([hasattr(argtype, '_ffiargshape') for argtype in argtypes]): + fastpath_cls = make_fastpath_subclass(self.__class__) + fastpath_cls.enable_fastpath_maybe(self) + self._argtypes_ = list(argtypes) argtypes = property(_getargtypes, _setargtypes) def _getparamflags(self): @@ -133,6 +144,7 @@ paramflags = property(_getparamflags, _setparamflags) + def _getrestype(self): return self._restype_ @@ -146,27 +158,24 @@ callable(restype)): raise TypeError("restype must be a type, a callable, or None") self._restype_ = restype - + def _delrestype(self): self._ptr = None del self._restype_ - + restype = property(_getrestype, _setrestype, _delrestype) def _geterrcheck(self): return getattr(self, '_errcheck_', None) - def _seterrcheck(self, errcheck): if not callable(errcheck): raise TypeError("The errcheck attribute must be callable") self._errcheck_ = errcheck - def _delerrcheck(self): try: del self._errcheck_ except AttributeError: pass - errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck) def _ffishapes(self, args, restype): @@ -181,6 +190,14 @@ restype = 'O' # void return argtypes, restype + def _set_address(self, address): + if not self._buffer: + self._buffer = _rawffi.Array('P')(1) + self._buffer[0] = address + + def _get_address(self): + return self._buffer[0] + def __init__(self, *args): self.name = None self._objects = {keepalive_key(0):self} @@ -188,7 +205,7 @@ # Empty function object -- this is needed for casts if not args: - self._buffer = _rawffi.Array('P')(1) + self._set_address(0) return argsl = list(args) @@ -196,20 +213,24 @@ # Direct construction from raw address if isinstance(argument, (int, long)) and not argsl: - ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) - self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires, self._flags_) - self._buffer = self._ptr.byptr() + self._set_address(argument) + restype = self._restype_ + if restype is None: + import ctypes + restype = ctypes.c_int + self._ptr = self._getfuncptr_fromaddress(self._argtypes_, restype) return - # A callback into Python + + # A callback into python if callable(argument) and not argsl: self.callable = argument ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) if self._restype_ is None: ffires = None - self._ptr = _rawffi.CallbackPtr(self._wrap_callable( - argument, self.argtypes - ), ffiargs, ffires, self._flags_) + self._ptr = _rawffi.CallbackPtr(self._wrap_callable(argument, + self.argtypes), + ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() return @@ -218,7 +239,7 @@ import ctypes self.name, dll = argument if isinstance(dll, str): - self.dll = ctypes.CDLL(dll) + self.dll = ctypes.CDLL(self.dll) else: self.dll = dll if argsl: @@ -227,7 +248,7 @@ raise TypeError("Unknown constructor %s" % (args,)) # We need to check dll anyway ptr = self._getfuncptr([], ctypes.c_int) - self._buffer = ptr.byptr() + self._set_address(ptr.getaddr()) return # A COM function call, by index @@ -270,15 +291,15 @@ # than the length of the argtypes tuple. args = args[:len(self._argtypes_)] else: - plural = len(argtypes) > 1 and "s" or "" + plural = len(self._argtypes_) > 1 and "s" or "" raise TypeError( "This function takes %d argument%s (%s given)" - % (len(argtypes), plural, len(args))) + % (len(self._argtypes_), plural, len(args))) # check that arguments are convertible ## XXX Not as long as ctypes.cast is a callback function with ## py_object arguments... - ## self._convert_args(argtypes, args, {}) + ## self._convert_args(self._argtypes_, args, {}) try: res = self.callable(*args) @@ -306,83 +327,75 @@ raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) - args, outargs = self._convert_args(argtypes, args, kwargs) - argtypes = [type(arg) for arg in args] + funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) + result = self._call_funcptr(funcptr, *newargs) + result = self._do_errcheck(result, args) - restype = self._restype_ - funcptr = self._getfuncptr(argtypes, restype, thisarg) + if not outargs: + return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + + if len(outargs) == 1: + return outargs[0] + return tuple(outargs) + + def _call_funcptr(self, funcptr, *newargs): + if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: set_errno(_rawffi.get_errno()) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) try: - resbuffer = funcptr(*[arg._get_buffer_for_param()._buffer - for arg in args]) + result = funcptr(*newargs) finally: if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: set_errno(_rawffi.get_errno()) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) + # + return self._build_result(self._restype_, result, newargs) - result = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, args[0]) - else: - result = int(resbuffer[0]) - elif restype is not None: - checker = getattr(self.restype, '_check_retval_', None) - if checker: - val = restype(resbuffer[0]) - # the original ctypes seems to make the distinction between - # classes defining a new type, and their subclasses - if '_type_' in restype.__dict__: - val = val.value - result = checker(val) - elif not isinstance(restype, _CDataMeta): - result = restype(resbuffer[0]) - else: - result = restype._CData_retval(resbuffer) - + def _do_errcheck(self, result, args): # The 'errcheck' protocol if self._errcheck_: v = self._errcheck_(result, self, args) # If the errcheck funtion failed, let it throw - # If the errcheck function returned callargs unchanged, + # If the errcheck function returned newargs unchanged, # continue normal processing. # If the errcheck function returned something else, # use that as result. if v is not args: - result = v + return v + return result - if not outargs: - return result - - if len(outargs) == 1: - return outargs[0] - - return tuple(outargs) + def _getfuncptr_fromaddress(self, argtypes, restype): + address = self._get_address() + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires) def _getfuncptr(self, argtypes, restype, thisarg=None): - if self._ptr is not None and argtypes is self._argtypes_: + if self._ptr is not None and (argtypes is self._argtypes_ or argtypes == self._argtypes_): return self._ptr if restype is None or not isinstance(restype, _CDataMeta): import ctypes restype = ctypes.c_int - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape if self._buffer is not None: - ptr = _rawffi.FuncPtr(self._buffer[0], argshapes, resshape, - self._flags_) - if argtypes is self._argtypes_: + ptr = self._getfuncptr_fromaddress(argtypes, restype) + if argtypes == self._argtypes_: self._ptr = ptr return ptr @@ -390,15 +403,21 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) - + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) + cdll = self.dll._handle try: - return cdll.ptr(self.name, argshapes, resshape, self._flags_) + ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes] + ffi_restype = restype.get_ffi_argtype() + self._ptr = cdll.getfunc(self.name, ffi_argtypes, ffi_restype) + return self._ptr except AttributeError: if self._flags_ & _rawffi.FUNCFLAG_CDECL: raise + # Win64 has no stdcall calling conv, so it should also not have the # name mangling of it. if WIN64: @@ -409,23 +428,32 @@ for i in range(33): mangled_name = "_%s@%d" % (self.name, i*4) try: - return cdll.ptr(mangled_name, argshapes, resshape, - self._flags_) + return cdll.getfunc(mangled_name, + ffi_argtypes, ffi_restype, + # XXX self._flags_ + ) except AttributeError: pass raise - @staticmethod - def _conv_param(argtype, arg): - from ctypes import c_char_p, c_wchar_p, c_void_p, c_int + @classmethod + def _conv_param(cls, argtype, arg): + if isinstance(argtype, _CDataMeta): + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype + if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - # The usual case when argtype is defined - cobj = arg - elif isinstance(arg, str): + return arg, arg._to_ffi_param(), type(arg) + # + # non-usual case: we do the import here to save a lot of code in the + # jit trace of the normal case + from ctypes import c_char_p, c_wchar_p, c_void_p, c_int + # + if isinstance(arg, str): cobj = c_char_p(arg) elif isinstance(arg, unicode): cobj = c_wchar_p(arg) @@ -435,18 +463,17 @@ cobj = c_int(arg) else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj + + return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): - callargs = [] + newargs = [] outargs = [] + keepalives = [] + newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -470,8 +497,10 @@ val = defval if val is marker: val = 0 - wrapped = self._conv_param(argtype, val) - callargs.append(wrapped) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): if inargs_idx < total: val = args[inargs_idx] @@ -485,38 +514,107 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - wrapped = self._conv_param(argtype, val) - callargs.append(wrapped) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - wrapped = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) - wrapped = ctypes.byref(val) - callargs.append(wrapped) + keepalive = None + newarg = ctypes.byref(val) + newargtype = type(newarg) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - wrapped = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) - callargs.append(wrapped) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) inargs_idx += 1 - if len(callargs) < total: - extra = args[len(callargs):] + if len(newargs) < len(args): + extra = args[len(newargs):] for i, arg in enumerate(extra): try: - wrapped = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) - callargs.append(wrapped) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) + return keepalives, newargs, newargtypes, outargs - return callargs, outargs + + def _wrap_result(self, restype, result): + """ + Convert from low-level repr of the result to the high-level python + one. + """ + # hack for performance: if restype is a "simple" primitive type, don't + # allocate the buffer because it's going to be thrown away immediately + if restype.__bases__[0] is _SimpleCData and not restype._is_pointer_like(): + return result + # + shape = restype._ffishape + if is_struct_shape(shape): + buf = result + else: + buf = _rawffi.Array(shape)(1, autofree=True) + buf[0] = result + retval = restype._CData_retval(buf) + return retval + + def _build_result(self, restype, result, argsandobjs): + """Build the function result: + If there is no OUT parameter, return the actual function result + If there is one OUT parameter, return it + If there are many OUT parameters, return a tuple""" + + # XXX: note for the future: the function used to take a "resbuffer", + # i.e. an array of ints. Now it takes a result, which is already a + # python object. All places that do "resbuffer[0]" should check that + # result is actually an int and just use it. + # + # Also, argsandobjs used to be "args" in __call__, now it's "newargs" + # (i.e., the already unwrapped objects). It's used only when we have a + # PARAMFLAG_FOUT and it's probably wrong, I'll fix it when I find a + # failing test + + retval = None + + if restype is not None: + checker = getattr(self.restype, '_check_retval_', None) + if checker: + val = restype(result) + # the original ctypes seems to make the distinction between + # classes defining a new type, and their subclasses + if '_type_' in restype.__dict__: + val = val.value + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) + elif not isinstance(restype, _CDataMeta): + retval = restype(result) + else: + retval = self._wrap_result(restype, result) + + return retval def __nonzero__(self): return self._com_index is not None or bool(self._buffer[0]) @@ -532,3 +630,61 @@ self._ptr.free() self._ptr = None self._needs_free = False + + +def make_fastpath_subclass(CFuncPtr): + if CFuncPtr._is_fastpath: + return CFuncPtr + # + try: + return make_fastpath_subclass.memo[CFuncPtr] + except KeyError: + pass + + class CFuncPtrFast(CFuncPtr): + + _is_fastpath = True + _slowpath_allowed = True # set to False by tests + + @classmethod + def enable_fastpath_maybe(cls, obj): + if (obj.callable is None and + obj._com_index is None): + obj.__class__ = cls + + def __rollback(self): + assert self._slowpath_allowed + self.__class__ = CFuncPtr + + # disable the fast path if we reset argtypes + def _setargtypes(self, argtypes): + self.__rollback() + self._setargtypes(argtypes) + argtypes = property(CFuncPtr._getargtypes, _setargtypes) + + def _setcallable(self, func): + self.__rollback() + self.callable = func + callable = property(lambda x: None, _setcallable) + + def _setcom_index(self, idx): + self.__rollback() + self._com_index = idx + _com_index = property(lambda x: None, _setcom_index) + + def __call__(self, *args): + thisarg = None + argtypes = self._argtypes_ + restype = self._restype_ + funcptr = self._getfuncptr(argtypes, restype, thisarg) + try: + result = self._call_funcptr(funcptr, *args) + result = self._do_errcheck(result, args) + except (TypeError, ArgumentError): # XXX, should be FFITypeError + assert self._slowpath_allowed + return CFuncPtr.__call__(self, *args) + return result + + make_fastpath_subclass.memo[CFuncPtr] = CFuncPtrFast + return CFuncPtrFast +make_fastpath_subclass.memo = {} diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py --- a/lib_pypy/_ctypes/pointer.py +++ b/lib_pypy/_ctypes/pointer.py @@ -1,6 +1,7 @@ import _rawffi -from _ctypes.basics import _CData, _CDataMeta, cdata_from_address +import _ffi +from _ctypes.basics import _CData, _CDataMeta, cdata_from_address, ArgumentError from _ctypes.basics import keepalive_key, store_reference, ensure_objects from _ctypes.basics import sizeof, byref from _ctypes.array import Array, array_get_slice_params, array_slice_getitem,\ @@ -19,7 +20,7 @@ length = 1, _ffiargshape = 'P', _ffishape = 'P', - _fficompositesize = None + _fficompositesize = None, ) # XXX check if typedict['_type_'] is any sane # XXX remember about paramfunc @@ -66,6 +67,7 @@ self._ffiarray = ffiarray self.__init__ = __init__ self._type_ = TP + self._ffiargtype = _ffi.types.Pointer(TP.get_ffi_argtype()) from_address = cdata_from_address @@ -114,6 +116,17 @@ contents = property(getcontents, setcontents) + def _as_ffi_pointer_(self, ffitype): + return as_ffi_pointer(self, ffitype) + +def as_ffi_pointer(value, ffitype): + my_ffitype = type(value).get_ffi_argtype() + # for now, we always allow types.pointer, else a lot of tests + # break. We need to rethink how pointers are represented, though + if my_ffitype is not ffitype and ffitype is not _ffi.types.void_p: + raise ArgumentError, "expected %s instance, got %s" % (type(value), ffitype) + return value._get_buffer_value() + def _cast_addr(obj, _, tp): if not (isinstance(tp, _CDataMeta) and tp._is_pointer_like()): raise TypeError("cast() argument 2 must be a pointer type, not %s" diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -1,3 +1,4 @@ +import _ffi import _rawffi import weakref import sys @@ -8,7 +9,7 @@ CArgObject from _ctypes.builtin import ConvMode from _ctypes.array import Array -from _ctypes.pointer import _Pointer +from _ctypes.pointer import _Pointer, as_ffi_pointer class NULL(object): pass @@ -140,6 +141,8 @@ value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) + result._ffiargtype = _ffi.types.Pointer(_ffi.types.char) + elif tp == 'Z': # c_wchar_p def _getvalue(self): @@ -162,6 +165,7 @@ value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) + result._ffiargtype = _ffi.types.Pointer(_ffi.types.unichar) elif tp == 'P': # c_void_p @@ -212,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: @@ -248,6 +257,12 @@ self._buffer[0] = 0 # VARIANT_FALSE result.value = property(_getvalue, _setvalue) + # make pointer-types compatible with the _ffi fast path + if result._is_pointer_like(): + def _as_ffi_pointer_(self, ffitype): + return as_ffi_pointer(self, ffitype) + result._as_ffi_pointer_ = _as_ffi_pointer_ + return result from_address = cdata_from_address diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -240,6 +240,9 @@ def _get_buffer_value(self): return self._buffer.buffer + def _to_ffi_param(self): + return self._buffer + class StructureMeta(StructOrUnionMeta): _is_union = False diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -275,7 +275,8 @@ return unicode(x, 'utf-8') class Connection(object): - def __init__(self, database, isolation_level="", detect_types=0, timeout=None, cached_statements=None, factory=None): + def __init__(self, database, timeout=5.0, detect_types=0, isolation_level="", + check_same_thread=True, factory=None, cached_statements=100): self.db = c_void_p() if sqlite.sqlite3_open(database, byref(self.db)) != SQLITE_OK: raise OperationalError("Could not open database") @@ -308,7 +309,8 @@ self._aggregates = {} self.aggregate_instances = {} self._collations = {} - self.thread_ident = thread_get_ident() + if check_same_thread: + self.thread_ident = thread_get_ident() def _get_exception(self, error_code = None): if error_code is None: diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -27,9 +27,9 @@ PythonPickler.__init__(self, self.__f, args[0], **kw) else: PythonPickler.__init__(self, *args, **kw) - + def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): diff --git a/lib_pypy/ctypes_support.py b/lib_pypy/ctypes_support.py --- a/lib_pypy/ctypes_support.py +++ b/lib_pypy/ctypes_support.py @@ -10,8 +10,8 @@ # __________ the standard C library __________ if sys.platform == 'win32': - import _rawffi - standard_c_lib = ctypes.CDLL('msvcrt', handle=_rawffi.get_libc()) + import _ffi + standard_c_lib = ctypes.CDLL('msvcrt', handle=_ffi.get_libc()) else: standard_c_lib = ctypes.CDLL(ctypes.util.find_library('c')) diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py --- a/lib_pypy/datetime.py +++ b/lib_pypy/datetime.py @@ -1422,12 +1422,17 @@ converter = _time.localtime else: converter = _time.gmtime - if 1 - (t % 1.0) < 0.000001: - t = float(int(t)) + 1 - if t < 0: - t -= 1 + if t < 0.0: + us = int(round(((-t) % 1.0) * 1000000)) + if us > 0: + us = 1000000 - us + t -= 1.0 + else: + us = int(round((t % 1.0) * 1000000)) + if us == 1000000: + us = 0 + t += 1.0 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) - us = int((t % 1.0) * 1000000) ss = min(ss, 59) # clamp out leap seconds if the platform has them result = cls(y, m, d, hh, mm, ss, us, tz) if tz is not None: diff --git a/lib_pypy/msvcrt.py b/lib_pypy/msvcrt.py --- a/lib_pypy/msvcrt.py +++ b/lib_pypy/msvcrt.py @@ -46,4 +46,42 @@ e = get_errno() raise IOError(e, errno.errorcode[e]) +# Console I/O routines + +kbhit = _c._kbhit +kbhit.argtypes = [] +kbhit.restype = ctypes.c_int + +getch = _c._getch +getch.argtypes = [] +getch.restype = ctypes.c_char + +getwch = _c._getwch +getwch.argtypes = [] +getwch.restype = ctypes.c_wchar + +getche = _c._getche +getche.argtypes = [] +getche.restype = ctypes.c_char + +getwche = _c._getwche +getwche.argtypes = [] +getwche.restype = ctypes.c_wchar + +putch = _c._putch +putch.argtypes = [ctypes.c_char] +putch.restype = None + +putwch = _c._putwch +putwch.argtypes = [ctypes.c_wchar] +putwch.restype = None + +ungetch = _c._ungetch +ungetch.argtypes = [ctypes.c_char] +ungetch.restype = None + +ungetwch = _c._ungetwch +ungetwch.argtypes = [ctypes.c_wchar] +ungetwch.restype = None + del ctypes diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/lib_pypy/pypy_test/test_datetime.py b/lib_pypy/pypy_test/test_datetime.py --- a/lib_pypy/pypy_test/test_datetime.py +++ b/lib_pypy/pypy_test/test_datetime.py @@ -32,4 +32,28 @@ assert datetime.datetime.utcfromtimestamp(a).microsecond == 0 assert datetime.datetime.utcfromtimestamp(a).second == 1 - +def test_more_datetime_rounding(): + # this test verified on top of CPython 2.7 (using a plain + # "import datetime" above) + expected_results = { + -1000.0: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.9999996: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.4: 'datetime.datetime(1970, 1, 1, 0, 43, 20, 600000)', + -999.0000004: 'datetime.datetime(1970, 1, 1, 0, 43, 21)', + -1.0: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.9999996: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.4: 'datetime.datetime(1970, 1, 1, 0, 59, 59, 600000)', + -0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.4: 'datetime.datetime(1970, 1, 1, 1, 0, 0, 400000)', + 0.9999996: 'datetime.datetime(1970, 1, 1, 1, 0, 1)', + 1000.0: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.0000004: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.4: 'datetime.datetime(1970, 1, 1, 1, 16, 40, 400000)', + 1000.9999996: 'datetime.datetime(1970, 1, 1, 1, 16, 41)', + 1293843661.191: 'datetime.datetime(2011, 1, 1, 2, 1, 1, 191000)', + } + for t in sorted(expected_results): + dt = datetime.datetime.fromtimestamp(t) + assert repr(dt) == expected_results[t] diff --git a/lib_pypy/resource.py b/lib_pypy/resource.py --- a/lib_pypy/resource.py +++ b/lib_pypy/resource.py @@ -7,7 +7,7 @@ from ctypes_support import standard_c_lib as libc from ctypes_support import get_errno -from ctypes import Structure, c_int, c_long, byref, sizeof +from ctypes import Structure, c_int, c_long, byref, sizeof, POINTER from errno import EINVAL, EPERM import _structseq @@ -25,6 +25,8 @@ _setrlimit = libc.setrlimit try: _getpagesize = libc.getpagesize + _getpagesize.argtypes = () + _getpagesize.restype = c_int except AttributeError: from os import sysconf _getpagesize = None @@ -61,6 +63,10 @@ ("ru_nivcsw", c_long), ) +_getrusage.argtypes = (c_int, POINTER(_struct_rusage)) +_getrusage.restype = c_int + + class struct_rusage: __metaclass__ = _structseq.structseqtype @@ -94,6 +100,12 @@ ("rlim_max", rlim_t), ) +_getrlimit.argtypes = (c_int, POINTER(rlimit)) +_getrlimit.restype = c_int +_setrlimit.argtypes = (c_int, POINTER(rlimit)) +_setrlimit.restype = c_int + + @builtinify def getrusage(who): ru = _struct_rusage() diff --git a/py/__init__.py b/py/__init__.py --- a/py/__init__.py +++ b/py/__init__.py @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2010 """ -__version__ = '1.4.3' +__version__ = '1.4.4.dev1' from py import _apipkg @@ -70,10 +70,6 @@ 'getrawcode' : '._code.code:getrawcode', 'patch_builtins' : '._code.code:patch_builtins', 'unpatch_builtins' : '._code.code:unpatch_builtins', - '_AssertionError' : '._code.assertion:AssertionError', - '_reinterpret_old' : '._code.assertion:reinterpret_old', - '_reinterpret' : '._code.assertion:reinterpret', - '_reprcompare' : '._code.assertion:_reprcompare', }, # backports and additions of builtins diff --git a/py/_code/_assertionnew.py b/py/_code/_assertionnew.py deleted file mode 100644 --- a/py/_code/_assertionnew.py +++ /dev/null @@ -1,339 +0,0 @@ -""" -Find intermediate evalutation results in assert statements through builtin AST. -This should replace _assertionold.py eventually. -""" - -import sys -import ast - -import py -from py._code.assertion import _format_explanation, BuiltinAssertionError - - -if sys.platform.startswith("java") and sys.version_info < (2, 5, 2): - # See http://bugs.jython.org/issue1497 - _exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict", - "ListComp", "GeneratorExp", "Yield", "Compare", "Call", - "Repr", "Num", "Str", "Attribute", "Subscript", "Name", - "List", "Tuple") - _stmts = ("FunctionDef", "ClassDef", "Return", "Delete", "Assign", - "AugAssign", "Print", "For", "While", "If", "With", "Raise", - "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom", - "Exec", "Global", "Expr", "Pass", "Break", "Continue") - _expr_nodes = set(getattr(ast, name) for name in _exprs) - _stmt_nodes = set(getattr(ast, name) for name in _stmts) - def _is_ast_expr(node): - return node.__class__ in _expr_nodes - def _is_ast_stmt(node): - return node.__class__ in _stmt_nodes -else: - def _is_ast_expr(node): - return isinstance(node, ast.expr) - def _is_ast_stmt(node): - return isinstance(node, ast.stmt) - - -class Failure(Exception): - """Error found while interpreting AST.""" - - def __init__(self, explanation=""): - self.cause = sys.exc_info() - self.explanation = explanation - - -def interpret(source, frame, should_fail=False): - mod = ast.parse(source) - visitor = DebugInterpreter(frame) - try: - visitor.visit(mod) - except Failure: - failure = sys.exc_info()[1] - return getfailure(failure) - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --no-assert)") - -def run(offending_line, frame=None): - if frame is None: - frame = py.code.Frame(sys._getframe(1)) - return interpret(offending_line, frame) - -def getfailure(failure): - explanation = _format_explanation(failure.explanation) - value = failure.cause[1] - if str(value): - lines = explanation.splitlines() - if not lines: - lines.append("") - lines[0] += " << %s" % (value,) - explanation = "\n".join(lines) - text = "%s: %s" % (failure.cause[0].__name__, explanation) - if text.startswith("AssertionError: assert "): - text = text[16:] - return text - - -operator_map = { - ast.BitOr : "|", - ast.BitXor : "^", - ast.BitAnd : "&", - ast.LShift : "<<", - ast.RShift : ">>", - ast.Add : "+", - ast.Sub : "-", - ast.Mult : "*", - ast.Div : "/", - ast.FloorDiv : "//", - ast.Mod : "%", - ast.Eq : "==", - ast.NotEq : "!=", - ast.Lt : "<", - ast.LtE : "<=", - ast.Gt : ">", - ast.GtE : ">=", - ast.Pow : "**", - ast.Is : "is", - ast.IsNot : "is not", - ast.In : "in", - ast.NotIn : "not in" -} - -unary_map = { - ast.Not : "not %s", - ast.Invert : "~%s", - ast.USub : "-%s", - ast.UAdd : "+%s" -} - - -class DebugInterpreter(ast.NodeVisitor): - """Interpret AST nodes to gleam useful debugging information. """ - - def __init__(self, frame): - self.frame = frame - - def generic_visit(self, node): - # Fallback when we don't have a special implementation. - if _is_ast_expr(node): - mod = ast.Expression(node) - co = self._compile(mod) - try: - result = self.frame.eval(co) - except Exception: - raise Failure() - explanation = self.frame.repr(result) - return explanation, result - elif _is_ast_stmt(node): - mod = ast.Module([node]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co) - except Exception: - raise Failure() - return None, None - else: - raise AssertionError("can't handle %s" %(node,)) - - def _compile(self, source, mode="eval"): - return compile(source, "", mode) - - def visit_Expr(self, expr): - return self.visit(expr.value) - - def visit_Module(self, mod): - for stmt in mod.body: - self.visit(stmt) - - def visit_Name(self, name): - explanation, result = self.generic_visit(name) - # See if the name is local. - source = "%r in locals() is not globals()" % (name.id,) - co = self._compile(source) - try: - local = self.frame.eval(co) - except Exception: - # have to assume it isn't - local = False - if not local: - return name.id, result - return explanation, result - - def visit_Compare(self, comp): - left = comp.left - left_explanation, left_result = self.visit(left) - for op, next_op in zip(comp.ops, comp.comparators): - next_explanation, next_result = self.visit(next_op) - op_symbol = operator_map[op.__class__] - explanation = "%s %s %s" % (left_explanation, op_symbol, - next_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=next_result) - except Exception: - raise Failure(explanation) - try: - if not result: - break - except KeyboardInterrupt: - raise - except: - break - left_explanation, left_result = next_explanation, next_result - - rcomp = py.code._reprcompare - if rcomp: - res = rcomp(op_symbol, left_result, next_result) - if res: - explanation = res - return explanation, result - - def visit_BoolOp(self, boolop): - is_or = isinstance(boolop.op, ast.Or) - explanations = [] - for operand in boolop.values: - explanation, result = self.visit(operand) - explanations.append(explanation) - if result == is_or: - break - name = is_or and " or " or " and " - explanation = "(" + name.join(explanations) + ")" - return explanation, result - - def visit_UnaryOp(self, unary): - pattern = unary_map[unary.op.__class__] - operand_explanation, operand_result = self.visit(unary.operand) - explanation = pattern % (operand_explanation,) - co = self._compile(pattern % ("__exprinfo_expr",)) - try: - result = self.frame.eval(co, __exprinfo_expr=operand_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_BinOp(self, binop): - left_explanation, left_result = self.visit(binop.left) - right_explanation, right_result = self.visit(binop.right) - symbol = operator_map[binop.op.__class__] - explanation = "(%s %s %s)" % (left_explanation, symbol, - right_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=right_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_Call(self, call): - func_explanation, func = self.visit(call.func) - arg_explanations = [] - ns = {"__exprinfo_func" : func} - arguments = [] - for arg in call.args: - arg_explanation, arg_result = self.visit(arg) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - arguments.append(arg_name) - arg_explanations.append(arg_explanation) - for keyword in call.keywords: - arg_explanation, arg_result = self.visit(keyword.value) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - keyword_source = "%s=%%s" % (keyword.arg) - arguments.append(keyword_source % (arg_name,)) - arg_explanations.append(keyword_source % (arg_explanation,)) - if call.starargs: - arg_explanation, arg_result = self.visit(call.starargs) - arg_name = "__exprinfo_star" - ns[arg_name] = arg_result - arguments.append("*%s" % (arg_name,)) - arg_explanations.append("*%s" % (arg_explanation,)) - if call.kwargs: - arg_explanation, arg_result = self.visit(call.kwargs) - arg_name = "__exprinfo_kwds" - ns[arg_name] = arg_result - arguments.append("**%s" % (arg_name,)) - arg_explanations.append("**%s" % (arg_explanation,)) - args_explained = ", ".join(arg_explanations) - explanation = "%s(%s)" % (func_explanation, args_explained) - args = ", ".join(arguments) - source = "__exprinfo_func(%s)" % (args,) - co = self._compile(source) - try: - result = self.frame.eval(co, **ns) - except Exception: - raise Failure(explanation) - pattern = "%s\n{%s = %s\n}" - rep = self.frame.repr(result) - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def _is_builtin_name(self, name): - pattern = "%r not in globals() and %r not in locals()" - source = pattern % (name.id, name.id) - co = self._compile(source) - try: - return self.frame.eval(co) - except Exception: - return False - - def visit_Attribute(self, attr): - if not isinstance(attr.ctx, ast.Load): - return self.generic_visit(attr) - source_explanation, source_result = self.visit(attr.value) - explanation = "%s.%s" % (source_explanation, attr.attr) - source = "__exprinfo_expr.%s" % (attr.attr,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - raise Failure(explanation) - explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), - self.frame.repr(result), - source_explanation, attr.attr) - # Check if the attr is from an instance. - source = "%r in getattr(__exprinfo_expr, '__dict__', {})" - source = source % (attr.attr,) - co = self._compile(source) - try: - from_instance = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - from_instance = True - if from_instance: - rep = self.frame.repr(result) - pattern = "%s\n{%s = %s\n}" - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def visit_Assert(self, assrt): - test_explanation, test_result = self.visit(assrt.test) - if test_explanation.startswith("False\n{False =") and \ - test_explanation.endswith("\n"): - test_explanation = test_explanation[15:-2] - explanation = "assert %s" % (test_explanation,) - if not test_result: - try: - raise BuiltinAssertionError - except Exception: - raise Failure(explanation) - return explanation, test_result - - def visit_Assign(self, assign): - value_explanation, value_result = self.visit(assign.value) - explanation = "... = %s" % (value_explanation,) - name = ast.Name("__exprinfo_expr", ast.Load(), - lineno=assign.value.lineno, - col_offset=assign.value.col_offset) - new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, - col_offset=assign.col_offset) - mod = ast.Module([new_assign]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co, __exprinfo_expr=value_result) - except Exception: - raise Failure(explanation) - return explanation, value_result diff --git a/py/_code/_assertionold.py b/py/_code/_assertionold.py deleted file mode 100644 --- a/py/_code/_assertionold.py +++ /dev/null @@ -1,555 +0,0 @@ -import py -import sys, inspect -from compiler import parse, ast, pycodegen -from py._code.assertion import BuiltinAssertionError, _format_explanation - -passthroughex = py.builtin._sysex - -class Failure: - def __init__(self, node): - self.exc, self.value, self.tb = sys.exc_info() - self.node = node - -class View(object): - """View base class. - - If C is a subclass of View, then C(x) creates a proxy object around - the object x. The actual class of the proxy is not C in general, - but a *subclass* of C determined by the rules below. To avoid confusion - we call view class the class of the proxy (a subclass of C, so of View) - and object class the class of x. - - Attributes and methods not found in the proxy are automatically read on x. - Other operations like setting attributes are performed on the proxy, as - determined by its view class. The object x is available from the proxy - as its __obj__ attribute. - - The view class selection is determined by the __view__ tuples and the - optional __viewkey__ method. By default, the selected view class is the - most specific subclass of C whose __view__ mentions the class of x. - If no such subclass is found, the search proceeds with the parent - object classes. For example, C(True) will first look for a subclass - of C with __view__ = (..., bool, ...) and only if it doesn't find any - look for one with __view__ = (..., int, ...), and then ..., object,... - If everything fails the class C itself is considered to be the default. - - Alternatively, the view class selection can be driven by another aspect - of the object x, instead of the class of x, by overriding __viewkey__. - See last example at the end of this module. - """ - - _viewcache = {} - __view__ = () - - def __new__(rootclass, obj, *args, **kwds): - self = object.__new__(rootclass) - self.__obj__ = obj - self.__rootclass__ = rootclass - key = self.__viewkey__() - try: - self.__class__ = self._viewcache[key] - except KeyError: - self.__class__ = self._selectsubclass(key) - return self - - def __getattr__(self, attr): - # attributes not found in the normal hierarchy rooted on View - # are looked up in the object's real class - return getattr(self.__obj__, attr) - - def __viewkey__(self): - return self.__obj__.__class__ - - def __matchkey__(self, key, subclasses): - if inspect.isclass(key): - keys = inspect.getmro(key) - else: - keys = [key] - for key in keys: - result = [C for C in subclasses if key in C.__view__] - if result: - return result - return [] - - def _selectsubclass(self, key): - subclasses = list(enumsubclasses(self.__rootclass__)) - for C in subclasses: - if not isinstance(C.__view__, tuple): - C.__view__ = (C.__view__,) - choices = self.__matchkey__(key, subclasses) - if not choices: - return self.__rootclass__ - elif len(choices) == 1: - return choices[0] - else: - # combine the multiple choices - return type('?', tuple(choices), {}) - - def __repr__(self): - return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) - - -def enumsubclasses(cls): - for subcls in cls.__subclasses__(): - for subsubclass in enumsubclasses(subcls): - yield subsubclass - yield cls - - -class Interpretable(View): - """A parse tree node with a few extra methods.""" - explanation = None - - def is_builtin(self, frame): - return False - - def eval(self, frame): - # fall-back for unknown expression nodes - try: - expr = ast.Expression(self.__obj__) - expr.filename = '' - self.__obj__.filename = '' - co = pycodegen.ExpressionCodeGenerator(expr).getCode() - result = frame.eval(co) - except passthroughex: - raise - except: - raise Failure(self) - self.result = result - self.explanation = self.explanation or frame.repr(self.result) - - def run(self, frame): - # fall-back for unknown statement nodes - try: - expr = ast.Module(None, ast.Stmt([self.__obj__])) - expr.filename = '' - co = pycodegen.ModuleCodeGenerator(expr).getCode() - frame.exec_(co) - except passthroughex: - raise - except: - raise Failure(self) - - def nice_explanation(self): - return _format_explanation(self.explanation) - - -class Name(Interpretable): - __view__ = ast.Name - - def is_local(self, frame): - source = '%r in locals() is not globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_global(self, frame): - source = '%r in globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_builtin(self, frame): - source = '%r not in locals() and %r not in globals()' % ( - self.name, self.name) - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - super(Name, self).eval(frame) - if not self.is_local(frame): - self.explanation = self.name - -class Compare(Interpretable): - __view__ = ast.Compare - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - for operation, expr2 in self.ops: - if hasattr(self, 'result'): - # shortcutting in chained expressions - if not frame.is_true(self.result): - break - expr2 = Interpretable(expr2) - expr2.eval(frame) - self.explanation = "%s %s %s" % ( - expr.explanation, operation, expr2.explanation) - source = "__exprinfo_left %s __exprinfo_right" % operation - try: - self.result = frame.eval(source, - __exprinfo_left=expr.result, - __exprinfo_right=expr2.result) - except passthroughex: - raise - except: - raise Failure(self) - expr = expr2 - -class And(Interpretable): - __view__ = ast.And - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if not frame.is_true(expr.result): - break - self.explanation = '(' + ' and '.join(explanations) + ')' - -class Or(Interpretable): - __view__ = ast.Or - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if frame.is_true(expr.result): - break - self.explanation = '(' + ' or '.join(explanations) + ')' - - -# == Unary operations == -keepalive = [] -for astclass, astpattern in { - ast.Not : 'not __exprinfo_expr', - ast.Invert : '(~__exprinfo_expr)', - }.items(): - - class UnaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - expr = Interpretable(self.expr) - expr.eval(frame) - self.explanation = astpattern.replace('__exprinfo_expr', - expr.explanation) - try: - self.result = frame.eval(astpattern, - __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(UnaryArith) - -# == Binary operations == -for astclass, astpattern in { - ast.Add : '(__exprinfo_left + __exprinfo_right)', - ast.Sub : '(__exprinfo_left - __exprinfo_right)', - ast.Mul : '(__exprinfo_left * __exprinfo_right)', - ast.Div : '(__exprinfo_left / __exprinfo_right)', - ast.Mod : '(__exprinfo_left % __exprinfo_right)', - ast.Power : '(__exprinfo_left ** __exprinfo_right)', - }.items(): - - class BinaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - left = Interpretable(self.left) - left.eval(frame) - right = Interpretable(self.right) - right.eval(frame) - self.explanation = (astpattern - .replace('__exprinfo_left', left .explanation) - .replace('__exprinfo_right', right.explanation)) - try: - self.result = frame.eval(astpattern, - __exprinfo_left=left.result, - __exprinfo_right=right.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(BinaryArith) - - -class CallFunc(Interpretable): - __view__ = ast.CallFunc - - def is_bool(self, frame): - source = 'isinstance(__exprinfo_value, bool)' - try: - return frame.is_true(frame.eval(source, - __exprinfo_value=self.result)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - node = Interpretable(self.node) - node.eval(frame) - explanations = [] - vars = {'__exprinfo_fn': node.result} - source = '__exprinfo_fn(' - for a in self.args: - if isinstance(a, ast.Keyword): - keyword = a.name - a = a.expr - else: - keyword = None - a = Interpretable(a) - a.eval(frame) - argname = '__exprinfo_%d' % len(vars) - vars[argname] = a.result - if keyword is None: - source += argname + ',' - explanations.append(a.explanation) - else: - source += '%s=%s,' % (keyword, argname) - explanations.append('%s=%s' % (keyword, a.explanation)) - if self.star_args: - star_args = Interpretable(self.star_args) - star_args.eval(frame) - argname = '__exprinfo_star' - vars[argname] = star_args.result - source += '*' + argname + ',' - explanations.append('*' + star_args.explanation) - if self.dstar_args: - dstar_args = Interpretable(self.dstar_args) - dstar_args.eval(frame) - argname = '__exprinfo_kwds' - vars[argname] = dstar_args.result - source += '**' + argname + ',' - explanations.append('**' + dstar_args.explanation) - self.explanation = "%s(%s)" % ( - node.explanation, ', '.join(explanations)) - if source.endswith(','): - source = source[:-1] - source += ')' - try: - self.result = frame.eval(source, **vars) - except passthroughex: - raise - except: - raise Failure(self) - if not node.is_builtin(frame) or not self.is_bool(frame): - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -class Getattr(Interpretable): - __view__ = ast.Getattr - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - source = '__exprinfo_expr.%s' % self.attrname - try: - self.result = frame.eval(source, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - self.explanation = '%s.%s' % (expr.explanation, self.attrname) - # if the attribute comes from the instance, its value is interesting - source = ('hasattr(__exprinfo_expr, "__dict__") and ' - '%r in __exprinfo_expr.__dict__' % self.attrname) - try: - from_instance = frame.is_true( - frame.eval(source, __exprinfo_expr=expr.result)) - except passthroughex: - raise - except: - from_instance = True - if from_instance: - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -# == Re-interpretation of full statements == - -class Assert(Interpretable): - __view__ = ast.Assert - - def run(self, frame): - test = Interpretable(self.test) - test.eval(frame) - # simplify 'assert False where False = ...' - if (test.explanation.startswith('False\n{False = ') and - test.explanation.endswith('\n}')): - test.explanation = test.explanation[15:-2] - # print the result as 'assert ' - self.result = test.result - self.explanation = 'assert ' + test.explanation - if not frame.is_true(test.result): - try: - raise BuiltinAssertionError - except passthroughex: - raise - except: - raise Failure(self) - -class Assign(Interpretable): - __view__ = ast.Assign - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = '... = ' + expr.explanation - # fall-back-run the rest of the assignment - ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) - mod = ast.Module(None, ast.Stmt([ass])) - mod.filename = '' - co = pycodegen.ModuleCodeGenerator(mod).getCode() - try: - frame.exec_(co, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - -class Discard(Interpretable): - __view__ = ast.Discard - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = expr.explanation - -class Stmt(Interpretable): - __view__ = ast.Stmt - - def run(self, frame): - for stmt in self.nodes: - stmt = Interpretable(stmt) - stmt.run(frame) - - -def report_failure(e): - explanation = e.node.nice_explanation() - if explanation: - explanation = ", in: " + explanation - else: - explanation = "" - sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) - -def check(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - expr = parse(s, 'eval') - assert isinstance(expr, ast.Expression) - node = Interpretable(expr.node) - try: - node.eval(frame) - except passthroughex: - raise - except Failure: - e = sys.exc_info()[1] - report_failure(e) - else: - if not frame.is_true(node.result): - sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) - - -########################################################### -# API / Entry points -# ######################################################### - -def interpret(source, frame, should_fail=False): - module = Interpretable(parse(source, 'exec').node) - #print "got module", module - if isinstance(frame, py.std.types.FrameType): - frame = py.code.Frame(frame) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - return getfailure(e) - except passthroughex: - raise - except: - import traceback - traceback.print_exc() - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --nomagic)") - else: - return None - -def getmsg(excinfo): - if isinstance(excinfo, tuple): - excinfo = py.code.ExceptionInfo(excinfo) - #frame, line = gettbline(tb) - #frame = py.code.Frame(frame) - #return interpret(line, frame) - - tb = excinfo.traceback[-1] - source = str(tb.statement).strip() - x = interpret(source, tb.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - return x - -def getfailure(e): - explanation = e.node.nice_explanation() - if str(e.value): - lines = explanation.split('\n') - lines[0] += " << %s" % (e.value,) - explanation = '\n'.join(lines) - text = "%s: %s" % (e.exc.__name__, explanation) - if text.startswith('AssertionError: assert '): - text = text[16:] - return text - -def run(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - module = Interpretable(parse(s, 'exec').node) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - report_failure(e) - - -if __name__ == '__main__': - # example: - def f(): - return 5 - def g(): - return 3 - def h(x): - return 'never' - check("f() * g() == 5") - check("not f()") - check("not (f() and g() or 0)") - check("f() == g()") - i = 4 - check("i == f()") - check("len(f()) == 0") - check("isinstance(2+3+4, float)") - - run("x = i") - check("x == 5") - - run("assert not f(), 'oops'") - run("a, b, c = 1, 2") - run("a, b, c = f()") - - check("max([f(),g()]) == 4") - check("'hello'[g()] == 'h'") - run("'guk%d' % h(f())") diff --git a/py/_code/assertion.py b/py/_code/assertion.py deleted file mode 100644 --- a/py/_code/assertion.py +++ /dev/null @@ -1,94 +0,0 @@ -import sys -import py - -BuiltinAssertionError = py.builtin.builtins.AssertionError - -_reprcompare = None # if set, will be called by assert reinterp for comparison ops - -def _format_explanation(explanation): - """This formats an explanation - - Normally all embedded newlines are escaped, however there are - three exceptions: \n{, \n} and \n~. The first two are intended - cover nested explanations, see function and attribute explanations - for examples (.visit_Call(), visit_Attribute()). The last one is - for when one explanation needs to span multiple lines, e.g. when - displaying diffs. - """ - raw_lines = (explanation or '').split('\n') - # escape newlines not followed by {, } and ~ - lines = [raw_lines[0]] - for l in raw_lines[1:]: - if l.startswith('{') or l.startswith('}') or l.startswith('~'): - lines.append(l) - else: - lines[-1] += '\\n' + l - - result = lines[:1] - stack = [0] - stackcnt = [0] - for line in lines[1:]: - if line.startswith('{'): - if stackcnt[-1]: - s = 'and ' - else: - s = 'where ' - stack.append(len(result)) - stackcnt[-1] += 1 - stackcnt.append(0) - result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) - elif line.startswith('}'): - assert line.startswith('}') - stack.pop() - stackcnt.pop() - result[stack[-1]] += line[1:] - else: - assert line.startswith('~') - result.append(' '*len(stack) + line[1:]) - assert len(stack) == 1 - return '\n'.join(result) - - -class AssertionError(BuiltinAssertionError): - def __init__(self, *args): - BuiltinAssertionError.__init__(self, *args) - if args: - try: - self.msg = str(args[0]) - except py.builtin._sysex: - raise - except: - self.msg = "<[broken __repr__] %s at %0xd>" %( - args[0].__class__, id(args[0])) - else: - f = py.code.Frame(sys._getframe(1)) - try: - source = f.code.fullsource - if source is not None: - try: - source = source.getstatement(f.lineno, assertion=True) - except IndexError: - source = None - else: - source = str(source.deindent()).strip() - except py.error.ENOENT: - source = None - # this can also occur during reinterpretation, when the - # co_filename is set to "". - if source: - self.msg = reinterpret(source, f, should_fail=True) - else: - self.msg = "" - if not self.args: - self.args = (self.msg,) - -if sys.version_info > (3, 0): - AssertionError.__module__ = "builtins" - reinterpret_old = "old reinterpretation not available for py3" -else: - from py._code._assertionold import interpret as reinterpret_old -if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): - from py._code._assertionnew import interpret as reinterpret -else: - reinterpret = reinterpret_old - diff --git a/py/_code/code.py b/py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -145,17 +145,6 @@ return self.frame.f_locals locals = property(getlocals, None, None, "locals of underlaying frame") - def reinterpret(self): - """Reinterpret the failing statement and returns a detailed information - about what operations are performed.""" - if self.exprinfo is None: - source = str(self.statement).strip() - x = py.code._reinterpret(source, self.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - self.exprinfo = x - return self.exprinfo - def getfirstlinesource(self): # on Jython this firstlineno can be -1 apparently return max(self.frame.code.firstlineno, 0) @@ -310,7 +299,7 @@ # ExceptionInfo-like classes may have different attributes. if tup is None: tup = sys.exc_info() - if exprinfo is None and isinstance(tup[1], py.code._AssertionError): + if exprinfo is None and isinstance(tup[1], AssertionError): exprinfo = getattr(tup[1], 'msg', None) if exprinfo is None: exprinfo = str(tup[1]) @@ -690,22 +679,15 @@ oldbuiltins = {} -def patch_builtins(assertion=True, compile=True): - """ put compile and AssertionError builtins to Python's builtins. """ - if assertion: - from py._code import assertion - l = oldbuiltins.setdefault('AssertionError', []) - l.append(py.builtin.builtins.AssertionError) - py.builtin.builtins.AssertionError = assertion.AssertionError +def patch_builtins(compile=True): + """ put compile builtins to Python's builtins. """ if compile: l = oldbuiltins.setdefault('compile', []) l.append(py.builtin.builtins.compile) py.builtin.builtins.compile = py.code.compile -def unpatch_builtins(assertion=True, compile=True): +def unpatch_builtins(compile=True): """ remove compile and AssertionError builtins from Python builtins. """ - if assertion: - py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop() if compile: py.builtin.builtins.compile = oldbuiltins['compile'].pop() diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -279,13 +279,13 @@ desc = self.getdesc(cls) return desc.getuniqueclassdef() - def getlistdef(self, **flags): + def getlistdef(self, **flags_if_new): """Get the ListDef associated with the current position.""" try: listdef = self.listdefs[self.position_key] except KeyError: listdef = self.listdefs[self.position_key] = ListDef(self) - listdef.listitem.__dict__.update(flags) + listdef.listitem.__dict__.update(flags_if_new) return listdef def newlist(self, *s_values, **flags): @@ -294,14 +294,18 @@ listdef = self.getlistdef(**flags) for s_value in s_values: listdef.generalize(s_value) + if flags: + assert flags.keys() == ['range_step'] + listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) @@ -351,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -379,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/annotation/listdef.py b/pypy/annotation/listdef.py --- a/pypy/annotation/listdef.py +++ b/pypy/annotation/listdef.py @@ -184,6 +184,11 @@ def generalize(self, s_value): self.listitem.generalize(s_value) + def generalize_range_step(self, range_step): + newlistitem = ListItem(self.listitem.bookkeeper, s_ImpossibleValue) + newlistitem.range_step = range_step + self.listitem.merge(newlistitem) + def __repr__(self): return '<[%r]%s%s%s%s>' % (self.listitem.s_value, self.listitem.mutated and 'm' or '', diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py --- a/pypy/annotation/test/test_annrpython.py +++ b/pypy/annotation/test/test_annrpython.py @@ -3483,6 +3483,17 @@ a = self.RPythonAnnotator() raises(Exception, a.build_types, f, [int]) + def test_range_variable_step(self): + def g(n): + return range(0, 10, n) + def f(n): + r = g(1) # constant step, at first + s = g(n) # but it becomes a variable step + return r + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.listdef.listitem.range_step == 0 + def g(n): return [0,1,2,n] diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -33,13 +33,17 @@ "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", "_bisect", "binascii", "_multiprocessing", '_warnings', - "_collections", "_multibytecodec", "micronumpy"] + "_collections", "_multibytecodec", "micronumpy", "_ffi"] )) translation_modules = default_modules.copy() translation_modules.update(dict.fromkeys( ["fcntl", "rctime", "select", "signal", "_rawffi", "zlib", - "struct", "_md5", "cStringIO", "array"])) + "struct", "_md5", "cStringIO", "array", "_ffi", + # the following are needed for pyrepl (and hence for the + # interactive prompt/pdb) + "termios", "_minimal_curses", + ])) working_oo_modules = default_modules.copy() working_oo_modules.update(dict.fromkeys( @@ -80,6 +84,7 @@ "_rawffi": [("objspace.usemodules.struct", True)], "cpyext": [("translation.secondaryentrypoints", "cpyext"), ("translation.shared", sys.platform == "win32")], + "_ffi": [("translation.jit_ffi", True)], } module_import_dependencies = { @@ -124,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -261,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -350,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py --- a/pypy/config/test/test_pypyoption.py +++ b/pypy/config/test/test_pypyoption.py @@ -73,3 +73,7 @@ fn = prefix + "." + path + ".txt" yield check_file_exists, fn +def test__ffi_opt(): + config = get_pypy_config(translating=True) + config.objspace.usemodules._ffi = True + assert config.translation.jit_ffi diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -118,6 +118,8 @@ ChoiceOption("jit_profiler", "integrate profiler support into the JIT", ["off", "oprofile"], default="off"), + # jit_ffi is automatically turned on by withmod-_ffi (which is enabled by default) + BoolOption("jit_ffi", "optimize libffi calls", default=False, cmdline=None), # misc BoolOption("verbose", "Print extra information", default=False), diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -173,6 +173,11 @@ >>>> A.__del__ = lambda self: None __main__:1: RuntimeWarning: a __del__ method added to an existing type will not be called +Even more obscure: the same is true, for old-style classes, if you attach +the ``__del__`` to an instance (even in CPython this does not work with +new-style classes). You get a RuntimeWarning in PyPy. To fix these cases +just make sure there is a ``__del__`` method in the class to start with. + Subclasses of built-in types ---------------------------- @@ -243,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/doc/garbage_collection.rst b/pypy/doc/garbage_collection.rst --- a/pypy/doc/garbage_collection.rst +++ b/pypy/doc/garbage_collection.rst @@ -212,90 +212,4 @@ becomes free garbage, to be collected at the next major collection. -Minimark GC ------------ - -This is a simplification and rewrite of the ideas from the Hybrid GC. -It uses a nursery for the young objects, and mark-and-sweep for the old -objects. This is a moving GC, but objects may only move once (from -the nursery to the old stage). - -The main difference with the Hybrid GC is that the mark-and-sweep -objects (the "old stage") are directly handled by the GC's custom -allocator, instead of being handled by malloc() calls. The gain is that -it is then possible, during a major collection, to walk through all old -generation objects without needing to store a list of pointers to them. -So as a first approximation, when compared to the Hybrid GC, the -Minimark GC saves one word of memory per old object. - -There are a number of environment variables that can be tweaked to -influence the GC. (Their default value should be ok for most usages.) -You can read more about them at the start of -`pypy/rpython/memory/gc/minimark.py`_. - -In more details: - -- The small newly malloced objects are allocated in the nursery (case 1). - All objects living in the nursery are "young". - -- The big objects are always handled directly by the system malloc(). - But the big newly malloced objects are still "young" when they are - allocated (case 2), even though they don't live in the nursery. - -- When the nursery is full, we do a minor collection, i.e. we find - which "young" objects are still alive (from cases 1 and 2). The - "young" flag is then removed. The surviving case 1 objects are moved - to the old stage. The dying case 2 objects are immediately freed. - -- The old stage is an area of memory containing old (small) objects. It - is handled by `pypy/rpython/memory/gc/minimarkpage.py`_. It is organized - as "arenas" of 256KB or 512KB, subdivided into "pages" of 4KB or 8KB. - Each page can either be free, or contain small objects of all the same - size. Furthermore at any point in time each object location can be - either allocated or freed. The basic design comes from ``obmalloc.c`` - from CPython (which itself comes from the same source as the Linux - system malloc()). - -- New objects are added to the old stage at every minor collection. - Immediately after a minor collection, when we reach some threshold, we - trigger a major collection. This is the mark-and-sweep step. It walks - over *all* objects (mark), and then frees some fraction of them (sweep). - This means that the only time when we want to free objects is while - walking over all of them; we never ask to free an object given just its - address. This allows some simplifications and memory savings when - compared to ``obmalloc.c``. - -- As with all generational collectors, this GC needs a write barrier to - record which old objects have a reference to young objects. - -- Additionally, we found out that it is useful to handle the case of - big arrays specially: when we allocate a big array (with the system - malloc()), we reserve a small number of bytes before. When the array - grows old, we use the extra bytes as a set of bits. Each bit - represents 128 entries in the array. Whenever the write barrier is - called to record a reference from the Nth entry of the array to some - young object, we set the bit number ``(N/128)`` to 1. This can - considerably speed up minor collections, because we then only have to - scan 128 entries of the array instead of all of them. - -- As usual, we need special care about weak references, and objects with - finalizers. Weak references are allocated in the nursery, and if they - survive they move to the old stage, as usual for all objects; the - difference is that the reference they contain must either follow the - object, or be set to NULL if the object dies. And the objects with - finalizers, considered rare enough, are immediately allocated old to - simplify the design. In particular their ``__del__`` method can only - be called just after a major collection. - -- The objects move once only, so we can use a trick to implement id() - and hash(). If the object is not in the nursery, it won't move any - more, so its id() and hash() are the object's address, cast to an - integer. If the object is in the nursery, and we ask for its id() - or its hash(), then we pre-reserve a location in the old stage, and - return the address of that location. If the object survives the - next minor collection, we move it there, and so its id() and hash() - are preserved. If the object dies then the pre-reserved location - becomes free garbage, to be collected at the next major collection. - - .. include:: _ref.txt diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/image/jitviewer.png b/pypy/doc/image/jitviewer.png new file mode 100644 index 0000000000000000000000000000000000000000..ad2abca5c88125061fa519dcf3f9fada577573ee GIT binary patch [cut] diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -21,16 +25,11 @@ * `speed.pypy.org`_: Daily benchmarks of how fast PyPy is +* `potential project ideas`_: In case you want to get your feet wet... + Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: @@ -59,8 +58,6 @@ (if they are not already developed in the FAQ_). You can find logs of the channel here_. -.. XXX play1? - Meeting PyPy developers ======================= @@ -83,7 +80,7 @@ .. _`Release 1.5`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html - +.. _`potential project ideas`: project-ideas.html Project Documentation ===================================== diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ @@ -289,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -11,6 +11,12 @@ `mailing list`_. This is simply for the reason that small possible projects tend to change very rapidly. +This list is mostly for having on overview on potential projects. This list is +by definition not exhaustive and we're pleased if people come up with their +own improvement ideas. In any case, if you feel like working on some of those +projects, or anything else in PyPy, pop up on IRC or write to us on the +`mailing list`_. + Numpy improvements ------------------ @@ -23,27 +29,121 @@ * interface with fortran/C libraries. -Potential mentors: fijal +Improving the jitviewer +------------------------ -JIT tooling ------------ +Analyzing performance of applications is always tricky. We have various +tools, for example a `jitviewer`_ that help us analyze performance. -xxx +The jitviewer shows the code generated by the PyPy JIT in a hierarchical way, +as shown by the screenshot below: + + - at the bottom level, it shows the Python source code of the compiled loops + + - for each source code line, it shows the corresponding Python bytecode + + - for each opcode, it shows the corresponding jit operations, which are the + ones actually sent to the backend for compiling (such as ``i15 = i10 < + 2000`` in the example) + +.. image:: image/jitviewer.png + +We would like to add one level to this hierarchy, by showing the generated +machine code for each jit operation. The necessary information is already in +the log file produced by the JIT, so it is "only" a matter of teaching the +jitviewer to display it. Ideally, the machine code should be hidden by +default and viewable on request. + +The jitviewer is a web application based on flask and jinja2 (and jQuery on +the client): if you have great web developing skills and want to help PyPy, +this is an ideal task to get started, because it does not require any deep +knowledge of the internals. + +Translation Toolchain +--------------------- + +* Incremental or distributed translation. + +* Allow separate compilation of extension modules. Work on some of other languages ------------------------------- -xxx +There are various languages implemented using the RPython translation toolchain. +One of the most interesting is the `JavaScript implementation`_, but there +are others like scheme or prolog. An interesting project would be to improve +the jittability of those or to experiment with various optimizations. Various GCs ----------- -xxx +PyPy has pluggable garbage collection policy. This means that various garbage +collectors can be written for specialized purposes, or even various +experiments can be done for the general purpose. Examples + +* An incremental garbage collector that has specified maximal pause times, + crucial for games + +* A garbage collector that compact memory better for mobile devices + +* A concurrent garbage collector (a lot of work) Remove the GIL -------------- -xxx +This is a major task that requires lots of thinking. However, few subprojects +can be potentially specified, unless a better plan can be thought out: -.. _`issue tracker`: ... -.. _`mailing list`: ... +* A thread-aware garbage collector + +* Better RPython primitives for dealing with concurrency + +* JIT passes to remove locks on objects + +* (maybe) implement locking in Python interpreter + +* alternatively, look at Software Transactional Memory + +Introduce new benchmarks +------------------------ + +We're usually happy to introduce new benchmarks. Please consult us +before, but in general something that's real-world python code +and is not already represented is welcome. We need at least a standalone +script that can run without parameters. Example ideas (benchmarks need +to be got from them!): + +* `hg` + +* `sympy` + +Experiment (again) with LLVM backend for RPython compilation +------------------------------------------------------------ + +We already tried working with LLVM and at the time, LLVM was not mature enough +for our needs. It's possible that this has changed, reviving the LLVM backend +(or writing new from scratch) for static compilation would be a good project. + +(On the other hand, just generating C code and using clang might be enough. +The issue with that is the so-called "asmgcc GC root finder", which has tons +of issues of this own. In my opinion (arigo), it would be definitely a +better project to try to optimize the alternative, the "shadowstack" GC root +finder, which is nicely portable. So far it gives a pypy that is around +7% slower.) + +Embedding PyPy +---------------------------------------- + +Being able to embed PyPy, say with its own limited C API, would be +useful. But here is the most interesting variant, straight from +EuroPython live discussion :-) We can have a generic "libpypy.so" that +can be used as a placeholder dynamic library, and when it gets loaded, +it runs a .py module that installs (via ctypes) the interface it wants +exported. This would give us a one-size-fits-all generic .so file to be +imported by any application that wants to load .so files :-) + + +.. _`issue tracker`: http://bugs.pypy.org +.. _`mailing list`: http://mail.python.org/mailman/listinfo/pypy-dev +.. _`jitviewer`: http://bitbucket.org/pypy/jitviewer +.. _`JavaScript implementation`: https://bitbucket.org/pypy/lang-js/overview diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) @@ -90,15 +90,18 @@ ### Construction ### def __init__(self, space, args_w, keywords=None, keywords_w=None, - w_stararg=None, w_starstararg=None): + w_stararg=None, w_starstararg=None, keyword_names_w=None): self.space = space assert isinstance(args_w, list) self.arguments_w = args_w self.keywords = keywords self.keywords_w = keywords_w + self.keyword_names_w = keyword_names_w # matches the tail of .keywords if keywords is not None: assert keywords_w is not None assert len(keywords_w) == len(keywords) + assert (keyword_names_w is None or + len(keyword_names_w) <= len(keywords)) make_sure_not_resized(self.keywords) make_sure_not_resized(self.keywords_w) @@ -132,7 +135,8 @@ def replace_arguments(self, args_w): "Return a new Arguments with a args_w as positional arguments." - return Arguments(self.space, args_w, self.keywords, self.keywords_w) + return Arguments(self.space, args_w, self.keywords, self.keywords_w, + keyword_names_w = self.keyword_names_w) def prepend(self, w_firstarg): "Return a new Arguments with a new argument inserted first." @@ -201,15 +205,16 @@ space.w_TypeError, space.wrap("keywords must be strings")) if e.match(space, space.w_UnicodeEncodeError): - raise OperationError( - space.w_TypeError, - space.wrap("keyword cannot be encoded to ascii")) - raise - if self.keywords and key in self.keywords: - raise operationerrfmt(self.space.w_TypeError, - "got multiple values " - "for keyword argument " - "'%s'", key) + # Allow this to pass through + key = None + else: + raise + else: + if self.keywords and key in self.keywords: + raise operationerrfmt(self.space.w_TypeError, + "got multiple values " + "for keyword argument " + "'%s'", key) keywords[i] = key keywords_w[i] = space.getitem(w_starstararg, w_key) i += 1 @@ -219,6 +224,7 @@ else: self.keywords = self.keywords + keywords self.keywords_w = self.keywords_w + keywords_w + self.keyword_names_w = keys_w def fixedunpack(self, argcount): """The simplest argument parsing: get the 'argcount' arguments, @@ -339,6 +345,10 @@ used_keywords = [False] * num_kwds for i in range(num_kwds): name = keywords[i] + # If name was not encoded as a string, it could be None. In that + # case, it's definitely not going to be in the signature. + if name is None: + continue j = signature.find_argname(name) if j < 0: continue @@ -374,17 +384,26 @@ if has_kwarg: w_kwds = self.space.newdict() if num_remainingkwds: + # + limit = len(keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(keywords)): if not used_keywords[i]: - key = keywords[i] - self.space.setitem(w_kwds, self.space.wrap(key), keywords_w[i]) + if i < limit: + w_key = self.space.wrap(keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + self.space.setitem(w_kwds, w_key, keywords_w[i]) + # scope_w[co_argcount + has_vararg] = w_kwds elif num_remainingkwds: if co_argcount == 0: raise ArgErrCount(avail, num_kwds, co_argcount, has_vararg, has_kwarg, defaults_w, missing) - raise ArgErrUnknownKwds(num_remainingkwds, keywords, used_keywords) + raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords, + used_keywords, self.keyword_names_w) if missing: raise ArgErrCount(avail, num_kwds, @@ -443,9 +462,15 @@ w_args = space.newtuple(self.arguments_w) w_kwds = space.newdict() if self.keywords is not None: + limit = len(self.keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(self.keywords)): - space.setitem(w_kwds, space.wrap(self.keywords[i]), - self.keywords_w[i]) + if i < limit: + w_key = space.wrap(self.keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + space.setitem(w_kwds, w_key, self.keywords_w[i]) return w_args, w_kwds class ArgumentsForTranslation(Arguments): @@ -666,14 +691,33 @@ class ArgErrUnknownKwds(ArgErr): - def __init__(self, num_remainingkwds, keywords, used_keywords): - self.kwd_name = '' + def __init__(self, space, num_remainingkwds, keywords, used_keywords, + keyword_names_w): + name = '' self.num_kwds = num_remainingkwds if num_remainingkwds == 1: for i in range(len(keywords)): if not used_keywords[i]: - self.kwd_name = keywords[i] + name = keywords[i] + if name is None: + # We'll assume it's unicode. Encode it. + # Careful, I *think* it should not be possible to + # get an IndexError here but you never know. + try: + if keyword_names_w is None: + raise IndexError + # note: negative-based indexing from the end + w_name = keyword_names_w[i - len(keywords)] + except IndexError: + name = '?' + else: + w_enc = space.wrap(space.sys.defaultencoding) + w_err = space.wrap("replace") + w_name = space.call_method(w_name, "encode", w_enc, + w_err) + name = space.str_w(w_name) break + self.kwd_name = name def getmsg(self, fnname): if self.num_kwds == 1: diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -134,7 +133,7 @@ def accept_comp_iteration(self, codegen, index): self.elt.walkabout(codegen) - codegen.emit_op_arg(ops.SET_ADD, index) + codegen.emit_op_arg(ops.SET_ADD, index + 1) class __extend__(ast.DictComp): @@ -148,7 +147,7 @@ def accept_comp_iteration(self, codegen, index): self.value.walkabout(codegen) self.key.walkabout(codegen) - codegen.emit_op_arg(ops.MAP_ADD, index) + codegen.emit_op_arg(ops.MAP_ADD, index + 1) # These are frame blocks. @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -92,7 +92,10 @@ return name if len(name) + 2 >= MANGLE_LEN: return name - if name.endswith('__'): + # Don't mangle __id__ or names with dots. The only time a name with a dot + # can occur is when we are compiling an import statement that has a package + # name. + if name.endswith('__') or '.' in name: return name try: i = 0 diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -55,7 +55,7 @@ co_expr = compile(evalexpr, '', 'eval') space = self.space pyco_expr = PyCode._from_code(space, co_expr) - w_res = pyco_expr.exec_host_bytecode(space, w_dict, w_dict) + w_res = pyco_expr.exec_host_bytecode(w_dict, w_dict) res = space.str_w(space.repr(w_res)) if not isinstance(expected, float): assert res == repr(expected) @@ -308,6 +308,15 @@ "p.__name__", os.path.__name__) yield (self.st, 'from os import *', "path.__name__, sep", (os.path.__name__, os.sep)) + yield (self.st, ''' + class A(object): + def m(self): + from __foo__.bar import x + try: + A().m() + except ImportError, e: + msg = str(e) + ''', "msg", "No module named __foo__") def test_if_stmts(self): yield self.st, "a = 42\nif a > 10: a += 2", "a", 44 diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -237,7 +237,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: @@ -989,10 +986,7 @@ compiler = self.createcompiler() expression = compiler.compile(expression, '?', 'eval', 0, hidden_applevel=hidden_applevel) - if isinstance(expression, types.CodeType): - # XXX only used by appsupport - expression = PyCode._from_code(self, expression) - if not isinstance(expression, PyCode): + else: raise TypeError, 'space.eval(): expected a string, code or PyCode object' return expression.exec_code(self, w_globals, w_locals) @@ -1007,9 +1001,6 @@ compiler = self.createcompiler() statement = compiler.compile(statement, filename, 'exec', 0, hidden_applevel=hidden_applevel) - if isinstance(statement, types.CodeType): - # XXX only used by appsupport - statement = PyCode._from_code(self, statement) if not isinstance(statement, PyCode): raise TypeError, 'space.exec_(): expected a string, code or PyCode object' w_key = self.wrap('__builtins__') diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -100,12 +100,12 @@ @jit.dont_look_inside def fast2locals(self): - # Copy values from self.fastlocals_w to self.w_locals + # Copy values from the fastlocals to self.w_locals if self.w_locals is None: self.w_locals = self.space.newdict() varnames = self.getcode().getvarnames() fastscope_w = self.getfastscope() - for i in range(min(len(varnames), len(fastscope_w))): + for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] if w_value is not None: @@ -114,7 +114,7 @@ @jit.dont_look_inside def locals2fast(self): - # Copy values from self.w_locals to self.fastlocals_w + # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None varnames = self.getcode().getvarnames() numlocals = self.getfastscopelength() diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack @@ -98,7 +98,7 @@ self.closure) for i in funccallunrolling: if i < nargs: - new_frame.fastlocals_w[i] = args_w[i] + new_frame.locals_stack_w[i] = args_w[i] return new_frame.run() elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1: assert isinstance(code, gateway.BuiltinCodePassThroughArguments1) @@ -158,7 +158,7 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg return new_frame.run() @@ -169,13 +169,13 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = self.defs_w[j] + new_frame.locals_stack_w[i] = self.defs_w[j] i += 1 return new_frame.run() @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -396,11 +396,14 @@ fastfunc = func else: # try to avoid excessive bloat - if func.__module__ == 'pypy.interpreter.astcompiler.ast': + mod = func.__module__ + if mod is None: + mod = "" + if mod == 'pypy.interpreter.astcompiler.ast': raise FastFuncNotSupported - if (not func.__module__.startswith('pypy.module.__builtin__') and - not func.__module__.startswith('pypy.module.sys') and - not func.__module__.startswith('pypy.module.math')): + if (not mod.startswith('pypy.module.__builtin__') and + not mod.startswith('pypy.module.sys') and + not mod.startswith('pypy.module.math')): if not func.__name__.startswith('descr'): raise FastFuncNotSupported d = {} diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -170,7 +170,7 @@ for i in range(len(args_to_copy)): argnum = args_to_copy[i] if argnum >= 0: - self.cells[i].set(self.fastlocals_w[argnum]) + self.cells[i].set(self.locals_stack_w[argnum]) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -63,6 +63,7 @@ the pypy compiler""" self.space = space eval.Code.__init__(self, name) + assert nlocals >= 0 self.co_argcount = argcount self.co_nlocals = nlocals self.co_stacksize = stacksize @@ -95,7 +96,7 @@ if self.co_flags & CO_VARKEYWORDS: argcount += 1 # Cell vars could shadow already-set arguments. - # astcompiler.pyassem used to be clever about the order of + # The compiler used to be clever about the order of # the variables in both co_varnames and co_cellvars, but # it no longer is for the sake of simplicity. Moreover # code objects loaded from CPython don't necessarily follow @@ -202,7 +203,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -215,7 +216,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -256,7 +257,7 @@ tuple(self.co_freevars), tuple(self.co_cellvars) ) - def exec_host_bytecode(self, w_dict, w_globals, w_locals): + def exec_host_bytecode(self, w_globals, w_locals): from pypy.interpreter.pyframe import CPythonFrame frame = CPythonFrame(self.space, self, w_globals, None) frame.setdictscope(w_locals) diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -9,7 +9,7 @@ from pypy.interpreter import pytraceback from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib.jit import hint -from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.debug import make_sure_not_resized, check_nonneg from pypy.rlib.rarithmetic import intmask from pypy.rlib import jit from pypy.tool import stdlib_opcode @@ -56,16 +56,18 @@ assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals) - self.valuestack_w = [None] * code.co_stacksize - self.valuestackdepth = 0 + self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize) + self.nlocals = code.co_nlocals + self.valuestackdepth = code.co_nlocals self.lastblock = None + make_sure_not_resized(self.locals_stack_w) + check_nonneg(self.nlocals) + # if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure, code) - self.fastlocals_w = [None] * code.co_nlocals - make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno def mark_as_escaped(self): @@ -184,14 +186,14 @@ # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth - self.valuestack_w[depth] = w_object + self.locals_stack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 - assert depth >= 0, "pop from empty value stack" - w_object = self.valuestack_w[depth] - self.valuestack_w[depth] = None + assert depth >= self.nlocals, "pop from empty value stack" + w_object = self.locals_stack_w[depth] + self.locals_stack_w[depth] = None self.valuestackdepth = depth return w_object @@ -217,24 +219,24 @@ def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n - assert base >= 0 + assert base >= self.nlocals while True: n -= 1 if n < 0: break - values_w[n] = self.valuestack_w[base+n] + values_w[n] = self.locals_stack_w[base+n] return values_w @jit.unroll_safe def dropvalues(self, n): n = hint(n, promote=True) finaldepth = self.valuestackdepth - n - assert finaldepth >= 0, "stack underflow in dropvalues()" + assert finaldepth >= self.nlocals, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break - self.valuestack_w[finaldepth+n] = None + self.locals_stack_w[finaldepth+n] = None self.valuestackdepth = finaldepth @jit.unroll_safe @@ -261,30 +263,30 @@ # Contrast this with CPython where it's PEEK(-1). index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "peek past the bottom of the stack" - return self.valuestack_w[index] + assert index >= self.nlocals, "peek past the bottom of the stack" + return self.locals_stack_w[index] def settopvalue(self, w_object, index_from_top=0): index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "settop past the bottom of the stack" - self.valuestack_w[index] = w_object + assert index >= self.nlocals, "settop past the bottom of the stack" + self.locals_stack_w[index] = w_object @jit.unroll_safe def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 finaldepth = hint(finaldepth, promote=True) while depth >= finaldepth: - self.valuestack_w[depth] = None + self.locals_stack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth - def savevaluestack(self): - return self.valuestack_w[:self.valuestackdepth] + def save_locals_stack(self): + return self.locals_stack_w[:self.valuestackdepth] - def restorevaluestack(self, items_w): - assert None not in items_w - self.valuestack_w[:len(items_w)] = items_w + def restore_locals_stack(self, items_w): + self.locals_stack_w[:len(items_w)] = items_w + self.init_cells() self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): @@ -314,11 +316,12 @@ else: f_lineno = self.f_lineno - values_w = self.valuestack_w[0:self.valuestackdepth] + values_w = self.locals_stack_w[self.nlocals:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) - w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) + w_fastlocals = maker.slp_into_tuple_with_nulls( + space, self.locals_stack_w[:self.nlocals]) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None @@ -399,7 +402,8 @@ new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) - new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None @@ -423,28 +427,28 @@ @jit.dont_look_inside def getfastscope(self): "Get the fast locals as a list." - return self.fastlocals_w + return self.locals_stack_w @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) - if scope_len > len(self.fastlocals_w): + if scope_len > self.nlocals: raise ValueError, "new fastscope is longer than the allocated area" - # don't assign directly to 'fastlocals_w[:scope_len]' to be + # don't assign directly to 'locals_stack_w[:scope_len]' to be # virtualizable-friendly for i in range(scope_len): - self.fastlocals_w[i] = scope_w[i] + self.locals_stack_w[i] = scope_w[i] self.init_cells() def init_cells(self): - """Initialize cellvars from self.fastlocals_w + """Initialize cellvars from self.locals_stack_w. This is overridden in nestedscope.py""" pass def getfastscopelength(self): - return self.pycode.co_nlocals + return self.nlocals def getclosure(self): return None diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -324,7 +324,7 @@ def LOAD_FAST(self, varindex, next_instr): # access a local variable directly - w_value = self.fastlocals_w[varindex] + w_value = self.locals_stack_w[varindex] if w_value is None: self._load_fast_failed(varindex) self.pushvalue(w_value) @@ -343,7 +343,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self.fastlocals_w[varindex] = w_newvalue + self.locals_stack_w[varindex] = w_newvalue def POP_TOP(self, oparg, next_instr): self.popvalue() @@ -696,12 +696,12 @@ LOAD_GLOBAL._always_inline_ = True def DELETE_FAST(self, varindex, next_instr): - if self.fastlocals_w[varindex] is None: + if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise operationerrfmt(self.space.w_UnboundLocalError, message, varname) - self.fastlocals_w[varindex] = None + self.locals_stack_w[varindex] = None def BUILD_TUPLE(self, itemcount, next_instr): items = self.popvalues(itemcount) @@ -1048,30 +1048,18 @@ def SET_ADD(self, oparg, next_instr): w_value = self.popvalue() - w_set = self.peekvalue(oparg) + w_set = self.peekvalue(oparg - 1) self.space.call_method(w_set, 'add', w_value) def MAP_ADD(self, oparg, next_instr): w_key = self.popvalue() w_value = self.popvalue() - w_dict = self.peekvalue(oparg) + w_dict = self.peekvalue(oparg - 1) self.space.setitem(w_dict, w_key, w_value) def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION @@ -1091,12 +1079,10 @@ @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): - w_set = self.space.call_function(self.space.w_set) - if itemcount: - w_add = self.space.getattr(w_set, self.space.wrap("add")) - for i in range(itemcount): - w_item = self.popvalue() - self.space.call_function(w_add, w_item) + w_set = self.space.newset() + for i in range(itemcount): + w_item = self.popvalue() + self.space.call_method(w_set, 'add', w_item) self.pushvalue(w_set) def STORE_MAP(self, oparg, next_instr): diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import py from pypy.interpreter.argument import (Arguments, ArgumentsForTranslation, ArgErr, ArgErrUnknownKwds, ArgErrMultipleValues, ArgErrCount, rawshape, @@ -126,6 +127,7 @@ w_AttributeError = AttributeError w_UnicodeEncodeError = UnicodeEncodeError w_dict = dict + w_str = str class TestArgumentsNormal(object): @@ -485,26 +487,6 @@ args._match_signature(None, l, Signature(['abc'])) assert len(l) == 1 assert l[0] == space.wrap(5) - # - def str_w(w): - try: - return str(w) - except UnicodeEncodeError: - raise OperationError(space.w_UnicodeEncodeError, - space.wrap("oups")) - space.str_w = str_w - w_starstar = space.wrap({u'\u1234': 5}) - err = py.test.raises(OperationError, Arguments, - space, [], w_starstararg=w_starstar) - # Check that we get a TypeError. On CPython it is because of - # "no argument called '?'". On PyPy we get a TypeError too, but - # earlier: "keyword cannot be encoded to ascii". The - # difference, besides the error message, is only apparent if the - # receiver also takes a **arg. Then CPython passes the - # non-ascii unicode unmodified, whereas PyPy complains. We will - # not care until someone has a use case for that. - assert not err.value.match(space, space.w_UnicodeEncodeError) - assert err.value.match(space, space.w_TypeError) class TestErrorHandling(object): def test_missing_args(self): @@ -559,13 +541,26 @@ assert 0, "did not raise" def test_unknown_keywords(self): - err = ArgErrUnknownKwds(1, ['a', 'b'], [True, False]) + space = DummySpace() + err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [True, False], None) s = err.getmsg('foo') assert s == "foo() got an unexpected keyword argument 'b'" - err = ArgErrUnknownKwds(2, ['a', 'b', 'c'], [True, False, False]) + err = ArgErrUnknownKwds(space, 2, ['a', 'b', 'c'], + [True, False, False], None) s = err.getmsg('foo') assert s == "foo() got 2 unexpected keyword arguments" + def test_unknown_unicode_keyword(self): + class DummySpaceUnicode(DummySpace): + class sys: + defaultencoding = 'utf-8' + space = DummySpaceUnicode() + err = ArgErrUnknownKwds(space, 1, ['a', None, 'b', 'c'], + [True, False, True, True], + [unichr(0x1234), u'b', u'c']) + s = err.getmsg('foo') + assert s == "foo() got an unexpected keyword argument '\xe1\x88\xb4'" + def test_multiple_values(self): err = ArgErrMultipleValues('bla') s = err.getmsg('foo') @@ -592,6 +587,14 @@ exc = raises(TypeError, (lambda a, b, **kw: 0), a=1) assert exc.value.message == "() takes exactly 2 non-keyword arguments (0 given)" + def test_unicode_keywords(self): + def f(**kwargs): + assert kwargs[u"美"] == 42 + f(**{u"美" : 42}) + def f(x): pass + e = raises(TypeError, "f(**{u'ü' : 19})") + assert "?" in str(e.value) + def make_arguments_for_translation(space, args_w, keywords_w={}, w_stararg=None, w_starstararg=None): return ArgumentsForTranslation(space, args_w, keywords_w.keys(), diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py --- a/pypy/interpreter/test/test_eval.py +++ b/pypy/interpreter/test/test_eval.py @@ -15,16 +15,16 @@ self.code = code Frame.__init__(self, space) self.numlocals = numlocals - self.fastlocals_w = [None] * self.numlocals + self._fastlocals_w = [None] * self.numlocals def getcode(self): return self.code def setfastscope(self, scope_w): - self.fastlocals_w = scope_w + self._fastlocals_w = scope_w def getfastscope(self): - return self.fastlocals_w + return self._fastlocals_w def getfastscopelength(self): return self.numlocals @@ -38,11 +38,11 @@ self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({})) - self.f.fastlocals_w[0] = w(5) + self.f._fastlocals_w[0] = w(5) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5})) - self.f.fastlocals_w[2] = w(7) + self.f._fastlocals_w[2] = w(7) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5, 'args': 7})) @@ -57,13 +57,13 @@ w = self.space.wrap self.f.w_locals = self.space.wrap({}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [None]*5) + self.sameList(self.f._fastlocals_w, [None]*5) self.f.w_locals = self.space.wrap({'x': 5}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) + self.sameList(self.f._fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.wrap({'x':5, 'args':7}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), None, w(7), - None, None]) + self.sameList(self.f._fastlocals_w, [w(5), None, w(7), + None, None]) diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -203,3 +203,27 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + import sys + class A(object): + def m(self): + "aaa" + m.x = 3 + class B(A): + pass + + bm = B().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.im_class is B + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -761,12 +761,15 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), diff --git a/pypy/jit/backend/arm/test/test_zrpy_gc.py b/pypy/jit/backend/arm/test/test_zrpy_gc.py --- a/pypy/jit/backend/arm/test/test_zrpy_gc.py +++ b/pypy/jit/backend/arm/test/test_zrpy_gc.py @@ -1,8 +1,7 @@ """ -This is a test that translates a complete JIT to C and runs it. It is -not testing much, expect that it basically works. What it *is* testing, -however, is the correct handling of GC, i.e. if objects are freed as -soon as possible (at least in a simple case). +This is a test that translates a complete JIT together with a GC and runs it. +It is testing that the GC-dependent aspects basically work, mostly the mallocs +and the various cases of write barrier. """ import weakref @@ -10,11 +9,10 @@ from pypy.annotation import policy as annpolicy from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe from pypy.jit.backend.arm.runner import ArmCPU from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -85,7 +83,7 @@ # return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2} -def compile(f, gc, **kwds): +def compile(f, gc, enable_opts='', **kwds): from pypy.annotation.listdef import s_list_of_strings from pypy.translator.translator import TranslationContext from pypy.jit.metainterp.warmspot import apply_jit @@ -109,14 +107,14 @@ old_value[obj, attr] = getattr(obj, attr) setattr(obj, attr, value) # - apply_jit(t, enable_opts='') + apply_jit(t, enable_opts=enable_opts) # finally: for (obj, attr), oldvalue in old_value.items(): setattr(obj, attr, oldvalue) cbuilder = genc.CStandaloneBuilder(t, f, t.config) - cbuilder.generate_source() + cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) cbuilder.compile() return cbuilder @@ -153,8 +151,10 @@ # ______________________________________________________________________ -class CompileFrameworkTests(object): - # Test suite using (so far) the minimark GC. + +class BaseFrameworkTests(object): + compile_kwds = {} + def setup_class(cls): funcs = [] name_to_func = {} @@ -204,7 +204,8 @@ try: GcLLDescr_framework.DEBUG = True cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC, - gcrootfinder=cls.gcrootfinder, jit=True) + gcrootfinder=cls.gcrootfinder, jit=True, + **cls.compile_kwds) finally: GcLLDescr_framework.DEBUG = OLD_DEBUG @@ -223,32 +224,36 @@ def run_orig(self, name, n, x): self.main_allfuncs(name, n, x) - def define_libffi_workaround(cls): - # XXX: this is a workaround for a bug in database.py. It seems that - # the problem is triggered by optimizeopt/fficall.py, and in - # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in - # these tests, that line is the only place where libffi.Func is - # referenced. - # - # The problem occurs because the gctransformer tries to annotate a - # low-level helper to call the __del__ of libffi.Func when it's too - # late. - # - # This workaround works by forcing the annotator (and all the rest of - # the toolchain) to see libffi.Func in a "proper" context, not just as - # the target of cast_base_ptr_to_instance. Note that the function - # below is *never* called by any actual test, it's just annotated. - # - from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain - libc_name = get_libc_name() - def f(n, x, *args): - libc = CDLL(libc_name) - ptr = libc.getpointer('labs', [types.slong], types.slong) - chain = ArgChain() - chain.arg(n) - n = ptr.call(chain, lltype.Signed) - return (n, x) + args - return None, f, None + +class CompileFrameworkTests(BaseFrameworkTests): + # Test suite using (so far) the minimark GC. + +## def define_libffi_workaround(cls): +## # XXX: this is a workaround for a bug in database.py. It seems that +## # the problem is triggered by optimizeopt/fficall.py, and in +## # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in +## # these tests, that line is the only place where libffi.Func is +## # referenced. +## # +## # The problem occurs because the gctransformer tries to annotate a +## # low-level helper to call the __del__ of libffi.Func when it's too +## # late. +## # +## # This workaround works by forcing the annotator (and all the rest of +## # the toolchain) to see libffi.Func in a "proper" context, not just as +## # the target of cast_base_ptr_to_instance. Note that the function +## # below is *never* called by any actual test, it's just annotated. +## # +## from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain +## libc_name = get_libc_name() +## def f(n, x, *args): +## libc = CDLL(libc_name) +## ptr = libc.getpointer('labs', [types.slong], types.slong) +## chain = ArgChain() +## chain.arg(n) +## n = ptr.call(chain, lltype.Signed) +## return (n, x) + args +## return None, f, None def define_compile_framework_1(cls): # a moving GC. Supports malloc_varsize_nonmovable. Simple test, works @@ -455,6 +460,73 @@ def test_compile_framework_7(self): self.run('compile_framework_7') + def define_compile_framework_8(cls): + # Array of pointers, of unknown length (test write_barrier_from_array) + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + l = [None] * (16 + (n & 7)) + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[8] = X(n+70) + l[9] = X(n+80) + l[10] = X(n+90) + l[11] = X(n+100) + l[12] = X(n+110) + l[13] = X(n+120) + l[14] = X(n+130) + l[15] = X(n+140) + if n < 1800: + check(len(l) == 16 + (n & 7)) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[8].x == n+70) + check(l[9].x == n+80) + check(l[10].x == n+90) + check(l[11].x == n+100) + check(l[12].x == n+110) + check(l[13].x == n+120) + check(l[14].x == n+130) + check(l[15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 16) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[8].x == 72) + check(l[9].x == 82) + check(l[10].x == 92) + check(l[11].x == 102) + check(l[12].x == 112) + check(l[13].x == 122) + check(l[14].x == 132) + check(l[15].x == 142) + return before, f, after + + def test_compile_framework_8(self): + self.run('compile_framework_8') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) @@ -492,7 +564,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -136,6 +136,7 @@ 'call' : (('ref', 'varargs'), 'intorptr'), 'call_assembler' : (('varargs',), 'intorptr'), 'cond_call_gc_wb' : (('ptr', 'ptr'), None), + 'cond_call_gc_wb_array': (('ptr', 'int', 'ptr'), None), 'oosend' : (('varargs',), 'intorptr'), 'oosend_pure' : (('varargs',), 'intorptr'), 'guard_true' : (('bool',), None), @@ -600,15 +601,15 @@ # return _op_default_implementation - def op_debug_merge_point(self, _, value, recdepth): + def op_debug_merge_point(self, _, *args): from pypy.jit.metainterp.warmspot import get_stats - loc = ConstPtr(value)._get_str() try: stats = get_stats() except AttributeError: pass else: - stats.add_merge_point_location(loc) + stats.add_merge_point_location(args[1:]) + pass def op_guard_true(self, _, value): if not value: @@ -820,6 +821,12 @@ raise NotImplementedError def op_call(self, calldescr, func, *args): + return self._do_call(calldescr, func, args, call_with_llptr=False) + + def op_call_release_gil(self, calldescr, func, *args): + return self._do_call(calldescr, func, args, call_with_llptr=True) + + def _do_call(self, calldescr, func, args, call_with_llptr): global _last_exception assert _last_exception is None, "exception left behind" assert _call_args_i == _call_args_r == _call_args_f == [] @@ -838,7 +845,8 @@ else: raise TypeError(x) try: - return _do_call_common(func, args_in_order, calldescr) + return _do_call_common(func, args_in_order, calldescr, + call_with_llptr) except LLException, lle: _last_exception = lle d = {'v': None, @@ -850,6 +858,9 @@ def op_cond_call_gc_wb(self, descr, a, b): py.test.skip("cond_call_gc_wb not supported") + def op_cond_call_gc_wb_array(self, descr, a, b, c): + py.test.skip("cond_call_gc_wb_array not supported") + def op_oosend(self, descr, obj, *args): raise NotImplementedError("oosend for lltype backend??") @@ -1480,17 +1491,20 @@ 'v': lltype.Void, } -def _do_call_common(f, args_in_order=None, calldescr=None): +def _do_call_common(f, args_in_order=None, calldescr=None, + call_with_llptr=False): ptr = llmemory.cast_int_to_adr(f).ptr PTR = lltype.typeOf(ptr) if PTR == rffi.VOIDP: # it's a pointer to a C function, so we don't have a precise # signature: create one from the descr + assert call_with_llptr is True ARGS = map(kind2TYPE.get, calldescr.arg_types) RESULT = kind2TYPE[calldescr.typeinfo] FUNC = lltype.FuncType(ARGS, RESULT) func_to_call = rffi.cast(lltype.Ptr(FUNC), ptr) else: + assert call_with_llptr is False FUNC = PTR.TO ARGS = FUNC.ARGS func_to_call = ptr._obj._callable diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -134,7 +134,7 @@ old, oldindex = faildescr._compiled_fail llimpl.compile_redirect_fail(old, oldindex, c) - def compile_loop(self, inputargs, operations, looptoken, log=True): + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): """In a real assembler backend, this should assemble the given list of operations. Here we just generate a similar CompiledLoop instance. The code here is RPython, whereas the code in llimpl diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -1,5 +1,6 @@ import py from pypy.rpython.lltypesystem import lltype, rffi, llmemory, rclass +from pypy.rpython.lltypesystem.lloperation import llop from pypy.jit.backend.llsupport import symbolic, support from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr from pypy.jit.metainterp.history import BasicFailDescr, LoopToken, BoxFloat @@ -45,6 +46,8 @@ size = 0 # help translation is_immutable = False + tid = llop.combine_ushort(lltype.Signed, 0, 0) + def __init__(self, size, count_fields_if_immut=-1): self.size = size self.count_fields_if_immut = count_fields_if_immut @@ -149,6 +152,7 @@ class BaseArrayDescr(AbstractDescr): _clsname = '' + tid = llop.combine_ushort(lltype.Signed, 0, 0) def get_base_size(self, translate_support_code): basesize, _, _ = symbolic.get_array_token(_A, translate_support_code) @@ -263,6 +267,9 @@ def __repr__(self): res = '%s(%s)' % (self.__class__.__name__, self.arg_classes) + extraeffect = getattr(self.extrainfo, 'extraeffect', None) + if extraeffect is not None: + res += ' EF=%r' % extraeffect oopspecindex = getattr(self.extrainfo, 'oopspecindex', 0) if oopspecindex: from pypy.jit.codewriter.effectinfo import EffectInfo diff --git a/pypy/jit/backend/llsupport/ffisupport.py b/pypy/jit/backend/llsupport/ffisupport.py --- a/pypy/jit/backend/llsupport/ffisupport.py +++ b/pypy/jit/backend/llsupport/ffisupport.py @@ -3,13 +3,16 @@ from pypy.jit.backend.llsupport.descr import DynamicIntCallDescr, NonGcPtrCallDescr,\ FloatCallDescr, VoidCallDescr +class UnsupportedKind(Exception): + pass + def get_call_descr_dynamic(ffi_args, ffi_result, extrainfo=None): """Get a call descr: the types of result and args are represented by rlib.libffi.types.*""" try: reskind = get_ffi_type_kind(ffi_result) argkinds = [get_ffi_type_kind(arg) for arg in ffi_args] - except KeyError: + except UnsupportedKind: return None # ?? arg_classes = ''.join(argkinds) if reskind == history.INT: @@ -33,7 +36,7 @@ return history.FLOAT elif kind == 'v': return history.VOID - assert False, "Unsupported kind '%s'" % kind + raise UnsupportedKind("Unsupported kind '%s'" % kind) def is_ffi_type_signed(ffi_type): from pypy.rlib.libffi import types diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -34,7 +34,7 @@ pass def do_write_barrier(self, gcref_struct, gcref_newptr): pass - def rewrite_assembler(self, cpu, operations): + def rewrite_assembler(self, cpu, operations, gcrefs_output_list): return operations def can_inline_malloc(self, descr): return False @@ -146,78 +146,6 @@ # All code below is for the hybrid or minimark GC -class GcRefList: - """Handles all references from the generated assembler to GC objects. - This is implemented as a nonmovable, but GC, list; the assembler contains - code that will (for now) always read from this list.""" - - GCREF_LIST = lltype.GcArray(llmemory.GCREF) # followed by the GC - - HASHTABLE = rffi.CArray(llmemory.Address) # ignored by the GC - HASHTABLE_BITS = 10 - HASHTABLE_SIZE = 1 << HASHTABLE_BITS - - def initialize(self): - if we_are_translated(): n = 2000 - else: n = 10 # tests only - self.list = self.alloc_gcref_list(n) - self.nextindex = 0 - self.oldlists = [] - # A pseudo dictionary: it is fixed size, and it may contain - # random nonsense after a collection moved the objects. It is only - # used to avoid too many duplications in the GCREF_LISTs. - self.hashtable = lltype.malloc(self.HASHTABLE, - self.HASHTABLE_SIZE+1, - flavor='raw', track_allocation=False) - dummy = lltype.direct_ptradd(lltype.direct_arrayitems(self.hashtable), - self.HASHTABLE_SIZE) - dummy = llmemory.cast_ptr_to_adr(dummy) - for i in range(self.HASHTABLE_SIZE+1): - self.hashtable[i] = dummy - - def alloc_gcref_list(self, n): - # Important: the GRREF_LISTs allocated are *non-movable*. This - # requires support in the gc (hybrid GC or minimark GC so far). - if we_are_translated(): - list = rgc.malloc_nonmovable(self.GCREF_LIST, n) - assert list, "malloc_nonmovable failed!" - else: - list = lltype.malloc(self.GCREF_LIST, n) # for tests only - return list - - def get_address_of_gcref(self, gcref): - assert lltype.typeOf(gcref) == llmemory.GCREF - # first look in the hashtable, using an inexact hash (fails after - # the object moves) - addr = llmemory.cast_ptr_to_adr(gcref) - hash = llmemory.cast_adr_to_int(addr, "forced") - hash -= hash >> self.HASHTABLE_BITS - hash &= self.HASHTABLE_SIZE - 1 - addr_ref = self.hashtable[hash] - # the following test is safe anyway, because the addresses found - # in the hashtable are always the addresses of nonmovable stuff - # ('addr_ref' is an address inside self.list, not directly the - # address of a real moving GC object -- that's 'addr_ref.address[0]'.) - if addr_ref.address[0] == addr: - return addr_ref - # if it fails, add an entry to the list - if self.nextindex == len(self.list): - # reallocate first, increasing a bit the size every time - self.oldlists.append(self.list) - self.list = self.alloc_gcref_list(len(self.list) // 4 * 5) - self.nextindex = 0 - # add it - index = self.nextindex - self.list[index] = gcref - addr_ref = lltype.direct_ptradd(lltype.direct_arrayitems(self.list), - index) - addr_ref = llmemory.cast_ptr_to_adr(addr_ref) - self.nextindex = index + 1 - # record it in the hashtable - self.hashtable[hash] = addr_ref - return addr_ref - - class GcRootMap_asmgcc(object): """Handles locating the stack roots in the assembler. This is the class supporting --gcrootfinder=asmgcc. @@ -527,6 +455,7 @@ def __init__(self, gc_ll_descr): self.llop1 = gc_ll_descr.llop1 self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR + self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR self.fielddescr_tid = get_field_descr(gc_ll_descr, gc_ll_descr.GCClass.HDR, 'tid') self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG @@ -546,6 +475,14 @@ funcaddr = llmemory.cast_ptr_to_adr(funcptr) return cpu.cast_adr_to_int(funcaddr) + def get_write_barrier_from_array_fn(self, cpu): + # returns a function with arguments [array, index, newvalue] + llop1 = self.llop1 + funcptr = llop1.get_write_barrier_from_array_failing_case( + self.WB_ARRAY_FUNCPTR) + funcaddr = llmemory.cast_ptr_to_adr(funcptr) + return cpu.cast_adr_to_int(funcaddr) # this may return 0 + class GcLLDescr_framework(GcLLDescription): DEBUG = False # forced to True by x86/test/test_zrpy_gc.py @@ -559,7 +496,7 @@ self.translator = translator self.llop1 = llop1 - # we need the hybrid or minimark GC for GcRefList.alloc_gcref_list() + # we need the hybrid or minimark GC for rgc._make_sure_does_not_move() # to work if gcdescr.config.translation.gc not in ('hybrid', 'minimark'): raise NotImplementedError("--gc=%s not implemented with the JIT" % @@ -574,8 +511,6 @@ " with the JIT" % (name,)) gcrootmap = cls(gcdescr) self.gcrootmap = gcrootmap - self.gcrefs = GcRefList() - self.single_gcref_descr = GcPtrFieldDescr('', 0) # make a TransformerLayoutBuilder and save it on the translator # where it can be fished and reused by the FrameworkGCTransformer @@ -618,6 +553,8 @@ [lltype.Signed, lltype.Signed], llmemory.GCREF)) self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType( [llmemory.Address, llmemory.Address], lltype.Void)) + self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType( + [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void)) self.write_barrier_descr = WriteBarrierDescr(self) # def malloc_array(itemsize, tid, num_elem): @@ -710,7 +647,6 @@ return rffi.cast(lltype.Signed, fptr) def initialize(self): - self.gcrefs.initialize() self.gcrootmap.initialize() def init_size_descr(self, S, descr): @@ -772,54 +708,32 @@ funcptr(llmemory.cast_ptr_to_adr(gcref_struct), llmemory.cast_ptr_to_adr(gcref_newptr)) - def replace_constptrs_with_getfield_raw(self, cpu, newops, op): - # xxx some performance issue here - newargs = [None] * op.numargs() - needs_copy = False + def record_constptrs(self, op, gcrefs_output_list): for i in range(op.numargs()): v = op.getarg(i) - newargs[i] = v if isinstance(v, ConstPtr) and bool(v.value): - addr = self.gcrefs.get_address_of_gcref(v.value) - # ^^^even for non-movable objects, to record their presence - if rgc.can_move(v.value): - box = BoxPtr(v.value) - addr = cpu.cast_adr_to_int(addr) - newops.append(ResOperation(rop.GETFIELD_RAW, - [ConstInt(addr)], box, - self.single_gcref_descr)) - newargs[i] = box - needs_copy = True - # - if needs_copy: - return op.copy_and_change(op.getopnum(), args=newargs) - else: - return op + p = v.value + rgc._make_sure_does_not_move(p) + gcrefs_output_list.append(p) - - def rewrite_assembler(self, cpu, operations): + def rewrite_assembler(self, cpu, operations, gcrefs_output_list): # Perform two kinds of rewrites in parallel: # # - Add COND_CALLs to the write barrier before SETFIELD_GC and # SETARRAYITEM_GC operations. # - # - Remove all uses of ConstPtrs away from the assembler. - # Idea: when running on a moving GC, we can't (easily) encode - # the ConstPtrs in the assembler, because they can move at any - # point in time. Instead, we store them in 'gcrefs.list', a GC - # but nonmovable list; and here, we modify 'operations' to - # replace direct usage of ConstPtr with a BoxPtr loaded by a - # GETFIELD_RAW from the array 'gcrefs.list'. + # - Record the ConstPtrs from the assembler. # newops = [] + known_lengths = {} # we can only remember one malloc since the next malloc can possibly # collect last_malloc = None for op in operations: if op.getopnum() == rop.DEBUG_MERGE_POINT: continue - # ---------- replace ConstPtrs with GETFIELD_RAW ---------- - op = self.replace_constptrs_with_getfield_raw(cpu, newops, op) + # ---------- record the ConstPtrs ---------- + self.record_constptrs(op, gcrefs_output_list) if op.is_malloc(): last_malloc = op.result elif op.can_malloc(): @@ -842,10 +756,14 @@ v = op.getarg(2) if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and bool(v.value)): # store a non-NULL - # XXX detect when we should produce a - # write_barrier_from_array - self._gen_write_barrier(newops, op.getarg(0), v) + self._gen_write_barrier_array(newops, op.getarg(0), + op.getarg(1), v, + cpu, known_lengths) op = op.copy_and_change(rop.SETARRAYITEM_RAW) + elif op.getopnum() == rop.NEW_ARRAY: + v_length = op.getarg(0) + if isinstance(v_length, ConstInt): + known_lengths[op.result] = v_length.getint() # ---------- newops.append(op) return newops @@ -855,6 +773,24 @@ newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None, descr=self.write_barrier_descr)) + def _gen_write_barrier_array(self, newops, v_base, v_index, v_value, + cpu, known_lengths): + if self.write_barrier_descr.get_write_barrier_from_array_fn(cpu) != 0: + # If we know statically the length of 'v', and it is not too + # big, then produce a regular write_barrier. If it's unknown or + # too big, produce instead a write_barrier_from_array. + LARGE = 130 + length = known_lengths.get(v_base, LARGE) + if length >= LARGE: + # unknown or too big: produce a write_barrier_from_array + args = [v_base, v_index, v_value] + newops.append(ResOperation(rop.COND_CALL_GC_WB_ARRAY, args, + None, + descr=self.write_barrier_descr)) + return + # fall-back case: produce a write_barrier + self._gen_write_barrier(newops, v_base, v_value) + def can_inline_malloc(self, descr): assert isinstance(descr, BaseSizeDescr) if descr.size < self.max_size_of_young_obj: diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py --- a/pypy/jit/backend/llsupport/regalloc.py +++ b/pypy/jit/backend/llsupport/regalloc.py @@ -38,6 +38,11 @@ self.frame_depth += size return newloc + def reserve_location_in_frame(self, size): + frame_depth = self.frame_depth + self.frame_depth += size + return frame_depth + # abstract methods that need to be overwritten for specific assemblers @staticmethod def frame_pos(loc, type): diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py --- a/pypy/jit/backend/llsupport/test/test_gc.py +++ b/pypy/jit/backend/llsupport/test/test_gc.py @@ -9,7 +9,7 @@ from pypy.jit.metainterp.resoperation import get_deep_immutable_oplist from pypy.jit.tool.oparser import parse from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists def test_boehm(): gc_ll_descr = GcLLDescr_boehm(None, None, None) @@ -49,19 +49,6 @@ # ____________________________________________________________ -def test_GcRefList(): - S = lltype.GcStruct('S') - order = range(50) * 4 - random.shuffle(order) - allocs = [lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S)) - for i in range(50)] - allocs = [allocs[i] for i in order] - # - gcrefs = GcRefList() - gcrefs.initialize() - addrs = [gcrefs.get_address_of_gcref(ptr) for ptr in allocs] - for i in range(len(allocs)): - assert addrs[i].address[0] == llmemory.cast_ptr_to_adr(allocs[i]) class TestGcRootMapAsmGcc: @@ -288,6 +275,18 @@ def get_write_barrier_failing_case(self, FPTRTYPE): return llhelper(FPTRTYPE, self._write_barrier_failing_case) + _have_wb_from_array = False + + def _write_barrier_from_array_failing_case(self, adr_struct, v_index): + self.record.append(('barrier_from_array', adr_struct, v_index)) + + def get_write_barrier_from_array_failing_case(self, FPTRTYPE): + if self._have_wb_from_array: + return llhelper(FPTRTYPE, + self._write_barrier_from_array_failing_case) + else: + return lltype.nullptr(FPTRTYPE.TO) + class TestFramework(object): gc = 'hybrid' @@ -303,9 +302,20 @@ config = config_ class FakeCPU(object): def cast_adr_to_int(self, adr): - ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR) - assert ptr._obj._callable == llop1._write_barrier_failing_case - return 42 + if not adr: + return 0 + try: + ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR) + assert ptr._obj._callable == \ + llop1._write_barrier_failing_case + return 42 + except lltype.InvalidCast: + ptr = llmemory.cast_adr_to_ptr( + adr, gc_ll_descr.WB_ARRAY_FUNCPTR) + assert ptr._obj._callable == \ + llop1._write_barrier_from_array_failing_case + return 43 + gcdescr = get_description(config_) translator = FakeTranslator() llop1 = FakeLLOp() @@ -414,11 +424,11 @@ ResOperation(rop.DEBUG_MERGE_POINT, ['dummy', 2], None), ] gc_ll_descr = self.gc_ll_descr - operations = gc_ll_descr.rewrite_assembler(None, operations) + operations = gc_ll_descr.rewrite_assembler(None, operations, []) assert len(operations) == 0 def test_rewrite_assembler_1(self): - # check rewriting of ConstPtrs + # check recording of ConstPtrs class MyFakeCPU(object): def cast_adr_to_int(self, adr): assert adr == "some fake address" @@ -438,56 +448,12 @@ ] gc_ll_descr = self.gc_ll_descr gc_ll_descr.gcrefs = MyFakeGCRefList() + gcrefs = [] operations = get_deep_immutable_oplist(operations) - operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) - assert len(operations) == 2 - assert operations[0].getopnum() == rop.GETFIELD_RAW - assert operations[0].getarg(0) == ConstInt(43) - assert operations[0].getdescr() == gc_ll_descr.single_gcref_descr - v_box = operations[0].result - assert isinstance(v_box, BoxPtr) - assert operations[1].getopnum() == rop.PTR_EQ - assert operations[1].getarg(0) == v_random_box - assert operations[1].getarg(1) == v_box - assert operations[1].result == v_result - - def test_rewrite_assembler_1_cannot_move(self): - # check rewriting of ConstPtrs - class MyFakeCPU(object): - def cast_adr_to_int(self, adr): - xxx # should not be called - class MyFakeGCRefList(object): - def get_address_of_gcref(self, s_gcref1): - seen.append(s_gcref1) - assert s_gcref1 == s_gcref - return "some fake address" - seen = [] - S = lltype.GcStruct('S') - s = lltype.malloc(S) - s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s) - v_random_box = BoxPtr() - v_result = BoxInt() - operations = [ - ResOperation(rop.PTR_EQ, [v_random_box, ConstPtr(s_gcref)], - v_result), - ] - gc_ll_descr = self.gc_ll_descr - gc_ll_descr.gcrefs = MyFakeGCRefList() - old_can_move = rgc.can_move - operations = get_deep_immutable_oplist(operations) - try: - rgc.can_move = lambda s: False - operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) - finally: - rgc.can_move = old_can_move - assert len(operations) == 1 - assert operations[0].getopnum() == rop.PTR_EQ - assert operations[0].getarg(0) == v_random_box - assert operations[0].getarg(1) == ConstPtr(s_gcref) - assert operations[0].result == v_result - # check that s_gcref gets added to the list anyway, to make sure - # that the GC sees it - assert seen == [s_gcref] + operations2 = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations, + gcrefs) + assert operations2 == operations + assert gcrefs == [s_gcref] def test_rewrite_assembler_2(self): # check write barriers before SETFIELD_GC @@ -500,7 +466,8 @@ ] gc_ll_descr = self.gc_ll_descr operations = get_deep_immutable_oplist(operations) - operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations, + []) assert len(operations) == 2 # assert operations[0].getopnum() == rop.COND_CALL_GC_WB @@ -515,29 +482,93 @@ def test_rewrite_assembler_3(self): # check write barriers before SETARRAYITEM_GC - v_base = BoxPtr() - v_index = BoxInt() - v_value = BoxPtr() - array_descr = AbstractDescr() - operations = [ - ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value], None, - descr=array_descr), - ] - gc_ll_descr = self.gc_ll_descr - operations = get_deep_immutable_oplist(operations) - operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) - assert len(operations) == 2 - # - assert operations[0].getopnum() == rop.COND_CALL_GC_WB - assert operations[0].getarg(0) == v_base - assert operations[0].getarg(1) == v_value - assert operations[0].result is None - # - assert operations[1].getopnum() == rop.SETARRAYITEM_RAW - assert operations[1].getarg(0) == v_base - assert operations[1].getarg(1) == v_index - assert operations[1].getarg(2) == v_value - assert operations[1].getdescr() == array_descr + for v_new_length in (None, ConstInt(5), ConstInt(5000), BoxInt()): + v_base = BoxPtr() + v_index = BoxInt() + v_value = BoxPtr() + array_descr = AbstractDescr() + operations = [ + ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value], + None, descr=array_descr), + ] + if v_new_length is not None: + operations.insert(0, ResOperation(rop.NEW_ARRAY, + [v_new_length], v_base, + descr=array_descr)) + # we need to insert another, unrelated NEW_ARRAY here + # to prevent the initialization_store optimization + operations.insert(1, ResOperation(rop.NEW_ARRAY, + [ConstInt(12)], BoxPtr(), + descr=array_descr)) + gc_ll_descr = self.gc_ll_descr + operations = get_deep_immutable_oplist(operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) + if v_new_length is not None: + assert operations[0].getopnum() == rop.NEW_ARRAY + assert operations[1].getopnum() == rop.NEW_ARRAY + del operations[:2] + assert len(operations) == 2 + # + assert operations[0].getopnum() == rop.COND_CALL_GC_WB + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_value + assert operations[0].result is None + # + assert operations[1].getopnum() == rop.SETARRAYITEM_RAW + assert operations[1].getarg(0) == v_base + assert operations[1].getarg(1) == v_index + assert operations[1].getarg(2) == v_value + assert operations[1].getdescr() == array_descr + + def test_rewrite_assembler_4(self): + # check write barriers before SETARRAYITEM_GC, + # if we have actually a write_barrier_from_array. + self.llop1._have_wb_from_array = True + for v_new_length in (None, ConstInt(5), ConstInt(5000), BoxInt()): + v_base = BoxPtr() + v_index = BoxInt() + v_value = BoxPtr() + array_descr = AbstractDescr() + operations = [ + ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value], + None, descr=array_descr), + ] + if v_new_length is not None: + operations.insert(0, ResOperation(rop.NEW_ARRAY, + [v_new_length], v_base, + descr=array_descr)) + # we need to insert another, unrelated NEW_ARRAY here + # to prevent the initialization_store optimization + operations.insert(1, ResOperation(rop.NEW_ARRAY, + [ConstInt(12)], BoxPtr(), + descr=array_descr)) + gc_ll_descr = self.gc_ll_descr + operations = get_deep_immutable_oplist(operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) + if v_new_length is not None: + assert operations[0].getopnum() == rop.NEW_ARRAY + assert operations[1].getopnum() == rop.NEW_ARRAY + del operations[:2] + assert len(operations) == 2 + # + if isinstance(v_new_length, ConstInt) and v_new_length.value < 130: + assert operations[0].getopnum() == rop.COND_CALL_GC_WB + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_value + else: + assert operations[0].getopnum() == rop.COND_CALL_GC_WB_ARRAY + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_index + assert operations[0].getarg(2) == v_value + assert operations[0].result is None + # + assert operations[1].getopnum() == rop.SETARRAYITEM_RAW + assert operations[1].getarg(0) == v_base + assert operations[1].getarg(1) == v_index + assert operations[1].getarg(2) == v_value + assert operations[1].getdescr() == array_descr def test_rewrite_assembler_initialization_store(self): S = lltype.GcStruct('S', ('parent', OBJECT), @@ -558,7 +589,8 @@ jump() """, namespace=locals()) operations = get_deep_immutable_oplist(ops.operations) - operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) equaloplists(operations, expected.operations) def test_rewrite_assembler_initialization_store_2(self): @@ -583,7 +615,8 @@ jump() """, namespace=locals()) operations = get_deep_immutable_oplist(ops.operations) - operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) equaloplists(operations, expected.operations) def test_rewrite_assembler_initialization_store_3(self): @@ -602,7 +635,8 @@ jump() """, namespace=locals()) operations = get_deep_immutable_oplist(ops.operations) - operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) equaloplists(operations, expected.operations) class TestFrameworkMiniMark(TestFramework): diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py --- a/pypy/jit/backend/model.py +++ b/pypy/jit/backend/model.py @@ -58,7 +58,7 @@ """Called once by the front-end when the program stops.""" pass - def compile_loop(self, inputargs, operations, looptoken, log=True): + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): """Assemble the given loop. Should create and attach a fresh CompiledLoopToken to looptoken.compiled_loop_token and stick extra attributes diff --git a/pypy/jit/backend/test/calling_convention_test.py b/pypy/jit/backend/test/calling_convention_test.py --- a/pypy/jit/backend/test/calling_convention_test.py +++ b/pypy/jit/backend/test/calling_convention_test.py @@ -57,146 +57,146 @@ return ConstInt(heaptracker.adr2int(addr)) def test_call_aligned_with_spilled_values(self): - from pypy.rlib.libffi import types - cpu = self.cpu - if not cpu.supports_floats: - py.test.skip('requires floats') + from pypy.rlib.libffi import types + cpu = self.cpu + if not cpu.supports_floats: + py.test.skip('requires floats') - def func(*args): - return float(sum(args)) + def func(*args): + return float(sum(args)) - F = lltype.Float - I = lltype.Signed - floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] - ints = [7, 11, 23, 13, -42, 1111, 95, 1] - for case in range(256): - local_floats = list(floats) - local_ints = list(ints) - args = [] - spills = [] - funcargs = [] - float_count = 0 - int_count = 0 - for i in range(8): - if case & (1< 0 + del glob.lst[:] + + cpu = self.cpu + func_adr = llmemory.cast_ptr_to_adr(c_qsort.funcsym) + funcbox = ConstInt(heaptracker.adr2int(func_adr)) + calldescr = cpu.calldescrof_dynamic([types.pointer, types_size_t, + types_size_t, types.pointer], + types.void) + i0 = BoxInt() + i1 = BoxInt() + i2 = BoxInt() + i3 = BoxInt() + tok = BoxInt() + faildescr = BasicFailDescr(1) + ops = [ + ResOperation(rop.CALL_RELEASE_GIL, [funcbox, i0, i1, i2, i3], None, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [], None, descr=BasicFailDescr(0)) + ] + ops[1].setfailargs([]) + looptoken = LoopToken() + self.cpu.compile_loop([i0, i1, i2, i3], ops, looptoken) + self.cpu.set_future_value_int(0, rffi.cast(lltype.Signed, raw)) + self.cpu.set_future_value_int(1, 2) + self.cpu.set_future_value_int(2, 4) + self.cpu.set_future_value_int(3, rffi.cast(lltype.Signed, fn)) + assert glob.lst == [] + fail = self.cpu.execute_token(looptoken) + assert fail.identifier == 0 + assert len(glob.lst) > 0 + lltype.free(raw, flavor='raw') + def test_guard_not_invalidated(self): cpu = self.cpu i0 = BoxInt() diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -128,6 +128,8 @@ if gc_ll_descr.get_malloc_slowpath_addr is not None: self._build_malloc_slowpath() self._build_stack_check_slowpath() + if gc_ll_descr.gcrootmap: + self._build_release_gil(gc_ll_descr.gcrootmap) debug_start('jit-backend-counts') self.set_debug(have_debug_prints()) debug_stop('jit-backend-counts') @@ -306,7 +308,66 @@ rawstart = mc.materialize(self.cpu.asmmemmgr, []) self.stack_check_slowpath = rawstart - def assemble_loop(self, inputargs, operations, looptoken, log): + @staticmethod + def _release_gil_asmgcc(css): + # similar to trackgcroot.py:pypy_asm_stackwalk, first part + from pypy.rpython.memory.gctransform import asmgcroot + new = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css) + next = asmgcroot.gcrootanchor.next + new.next = next + new.prev = asmgcroot.gcrootanchor + asmgcroot.gcrootanchor.next = new + next.prev = new + # and now release the GIL + before = rffi.aroundstate.before + if before: + before() + + @staticmethod + def _reacquire_gil_asmgcc(css): + # first reacquire the GIL + after = rffi.aroundstate.after + if after: + after() + # similar to trackgcroot.py:pypy_asm_stackwalk, second part + from pypy.rpython.memory.gctransform import asmgcroot + old = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css) + prev = old.prev + next = old.next + prev.next = next + next.prev = prev + + @staticmethod + def _release_gil_shadowstack(): + before = rffi.aroundstate.before + if before: + before() + + @staticmethod + def _reacquire_gil_shadowstack(): + after = rffi.aroundstate.after + if after: + after() + + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) + _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP], + lltype.Void)) + + def _build_release_gil(self, gcrootmap): + if gcrootmap.is_shadow_stack: + releasegil_func = llhelper(self._NOARG_FUNC, + self._release_gil_shadowstack) + reacqgil_func = llhelper(self._NOARG_FUNC, + self._reacquire_gil_shadowstack) + else: + releasegil_func = llhelper(self._CLOSESTACK_FUNC, + self._release_gil_asmgcc) + reacqgil_func = llhelper(self._CLOSESTACK_FUNC, + self._reacquire_gil_asmgcc) + self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) + self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + + def assemble_loop(self, loopname, inputargs, operations, looptoken, log): '''adds the following attributes to looptoken: _x86_loop_code (an integer giving an address) _x86_bootstrap_code (an integer giving an address) @@ -322,6 +383,7 @@ # for the duration of compiling one loop or a one bridge. clt = CompiledLoopToken(self.cpu, looptoken.number) + clt.allgcrefs = [] looptoken.compiled_loop_token = clt if not we_are_translated(): # Arguments should be unique @@ -329,13 +391,13 @@ self.setup(looptoken) self.currently_compiling_loop = looptoken - funcname = self._find_debug_merge_point(operations) if log: self._register_counter() operations = self._inject_debugging_code(looptoken, operations) regalloc = RegAlloc(self, self.cpu.translate_support_code) - arglocs, operations = regalloc.prepare_loop(inputargs, operations, looptoken) + arglocs, operations = regalloc.prepare_loop(inputargs, operations, + looptoken, clt.allgcrefs) looptoken._x86_arglocs = arglocs bootstrappos = self.mc.get_relative_pos() @@ -354,10 +416,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( - looptoken.number, funcname, + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( + looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -375,7 +440,7 @@ self.teardown() # oprofile support if self.cpu.profile_agent is not None: - name = "Loop # %s: %s" % (looptoken.number, funcname) + name = "Loop # %s: %s" % (looptoken.number, loopname) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) return ops_offset @@ -395,7 +460,6 @@ return self.setup(original_loop_token) - funcname = self._find_debug_merge_point(operations) if log: self._register_counter() operations = self._inject_debugging_code(faildescr, operations) @@ -407,7 +471,8 @@ regalloc = RegAlloc(self, self.cpu.translate_support_code) fail_depths = faildescr._x86_current_depths operations = regalloc.prepare_bridge(fail_depths, inputargs, arglocs, - operations) + operations, + self.current_clt.allgcrefs) stackadjustpos = self._patchable_stackadjust() frame_depth, param_depth = self._assemble(regalloc, operations) @@ -416,9 +481,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d (%s) has address %x to %x" % - (descr_number, funcname, rawstart, rawstart + codeendpos)) + debug_start("jit-backend-addr") + debug_print("Bridge out of Guard %d has address %x to %x" % + (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -432,7 +498,7 @@ self.teardown() # oprofile support if self.cpu.profile_agent is not None: - name = "Bridge # %s: %s" % (descr_number, funcname) + name = "Bridge # %s" % (descr_number,) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) return ops_offset @@ -492,17 +558,6 @@ return self.mc.materialize(self.cpu.asmmemmgr, allblocks, self.cpu.gc_ll_descr.gcrootmap) - def _find_debug_merge_point(self, operations): - - for op in operations: - if op.getopnum() == rop.DEBUG_MERGE_POINT: - funcname = op.getarg(0)._get_str() - break - else: - funcname = "" % len(self.loop_run_counters) - # invent the counter, so we don't get too confused - return funcname - def _register_counter(self): if self._debug: # YYY very minor leak -- we need the counters to stay alive @@ -652,22 +707,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: @@ -838,7 +899,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -850,7 +911,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) @@ -1987,6 +2048,102 @@ self.mc.CMP_bi(FORCE_INDEX_OFS, 0) self.implement_guard(guard_token, 'L') + def genop_guard_call_release_gil(self, op, guard_op, guard_token, + arglocs, result_loc): + # first, close the stack in the sense of the asmgcc GC root tracker + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + if gcrootmap: + self.call_release_gil(gcrootmap, arglocs) + # do the call + faildescr = guard_op.getdescr() + fail_index = self.cpu.get_fail_descr_number(faildescr) + self.mc.MOV_bi(FORCE_INDEX_OFS, fail_index) + self._genop_call(op, arglocs, result_loc, fail_index) + # then reopen the stack + if gcrootmap: + self.call_reacquire_gil(gcrootmap, result_loc) + # finally, the guard_not_forced + self.mc.CMP_bi(FORCE_INDEX_OFS, 0) + self.implement_guard(guard_token, 'L') + + def call_release_gil(self, gcrootmap, save_registers): + # First, we need to save away the registers listed in + # 'save_registers' that are not callee-save. XXX We assume that + # the XMM registers won't be modified. We store them in + # [ESP+4], [ESP+8], etc., leaving enough room in [ESP] for the + # single argument to closestack_addr below. + p = WORD + for reg in self._regalloc.rm.save_around_call_regs: + if reg in save_registers: + self.mc.MOV_sr(p, reg.value) + p += WORD + self._regalloc.reserve_param(p//WORD) + # + if gcrootmap.is_shadow_stack: + args = [] + else: + # note that regalloc.py used save_all_regs=True to save all + # registers, so we don't have to care about saving them (other + # than ebp) in the close_stack_struct. But if they are registers + # like %eax that would be destroyed by this call, *and* they are + # used by arglocs for the *next* call, then trouble; for now we + # will just push/pop them. + from pypy.rpython.memory.gctransform import asmgcroot + css = self._regalloc.close_stack_struct + if css == 0: + use_words = (2 + max(asmgcroot.INDEX_OF_EBP, + asmgcroot.FRAME_PTR) + 1) + pos = self._regalloc.fm.reserve_location_in_frame(use_words) + css = get_ebp_ofs(pos + use_words - 1) + self._regalloc.close_stack_struct = css + # The location where the future CALL will put its return address + # will be [ESP-WORD], so save that as the next frame's top address + self.mc.LEA_rs(eax.value, -WORD) # LEA EAX, [ESP-4] + frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) + self.mc.MOV_br(frame_ptr, eax.value) # MOV [css.frame], EAX + # Save ebp + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_br(index_of_ebp, ebp.value) # MOV [css.ebp], EBP + # Call the closestack() function (also releasing the GIL) + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rb(reg.value, css) + args = [reg] + # + self._emit_call(-1, imm(self.releasegil_addr), args) + # Finally, restore the registers saved above. + p = WORD + for reg in self._regalloc.rm.save_around_call_regs: + if reg in save_registers: + self.mc.MOV_rs(reg.value, p) + p += WORD + + def call_reacquire_gil(self, gcrootmap, save_loc): + # save the previous result (eax/xmm0) into the stack temporarily. + # XXX like with call_release_gil(), we assume that we don't need + # to save xmm0 in this case. + if isinstance(save_loc, RegLoc) and not save_loc.is_xmm: + self.mc.MOV_sr(WORD, save_loc.value) + self._regalloc.reserve_param(2) + # call the reopenstack() function (also reacquiring the GIL) + if gcrootmap.is_shadow_stack: + args = [] + else: + css = self._regalloc.close_stack_struct + assert css != 0 + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rb(reg.value, css) + args = [reg] + self._emit_call(-1, imm(self.reacqgil_addr), args) + # restore the result from the stack + if isinstance(save_loc, RegLoc) and not save_loc.is_xmm: + self.mc.MOV_rs(save_loc.value, WORD) + def genop_guard_call_assembler(self, op, guard_op, guard_token, arglocs, result_loc): faildescr = guard_op.getdescr() @@ -2076,13 +2233,26 @@ def genop_discard_cond_call_gc_wb(self, op, arglocs): # Write code equivalent to write_barrier() in the GC: it checks # a flag in the object at arglocs[0], and if set, it calls the - # function remember_young_pointer() from the GC. The two arguments - # to the call are in arglocs[:2]. The rest, arglocs[2:], contains + # function remember_young_pointer() from the GC. The arguments + # to the call are in arglocs[:N]. The rest, arglocs[N:], contains # registers that need to be saved and restored across the call. + # N is either 2 (regular write barrier) or 3 (array write barrier). descr = op.getdescr() if we_are_translated(): cls = self.cpu.gc_ll_descr.has_write_barrier_class() assert cls is not None and isinstance(descr, cls) + # + opnum = op.getopnum() + if opnum == rop.COND_CALL_GC_WB: + N = 2 + func = descr.get_write_barrier_fn(self.cpu) + elif opnum == rop.COND_CALL_GC_WB_ARRAY: + N = 3 + func = descr.get_write_barrier_from_array_fn(self.cpu) + assert func != 0 + else: + raise AssertionError(opnum) + # loc_base = arglocs[0] self.mc.TEST8(addr_add_const(loc_base, descr.jit_wb_if_flag_byteofs), imm(descr.jit_wb_if_flag_singlebyte)) @@ -2093,33 +2263,37 @@ if IS_X86_32: limit = -1 # push all arglocs on the stack elif IS_X86_64: - limit = 1 # push only arglocs[2:] on the stack + limit = N - 1 # push only arglocs[N:] on the stack for i in range(len(arglocs)-1, limit, -1): loc = arglocs[i] if isinstance(loc, RegLoc): self.mc.PUSH_r(loc.value) else: - assert not IS_X86_64 # there should only be regs in arglocs[2:] + assert not IS_X86_64 # there should only be regs in arglocs[N:] self.mc.PUSH_i32(loc.getint()) if IS_X86_64: # We clobber these registers to pass the arguments, but that's # okay, because consider_cond_call_gc_wb makes sure that any # caller-save registers with values in them are present in - # arglocs[2:] too, so they are saved on the stack above and + # arglocs[N:] too, so they are saved on the stack above and # restored below. - remap_frame_layout(self, arglocs[:2], [edi, esi], + if N == 2: + callargs = [edi, esi] + else: + callargs = [edi, esi, edx] + remap_frame_layout(self, arglocs[:N], callargs, X86_64_SCRATCH_REG) - + # # misaligned stack in the call, but it's ok because the write barrier # is not going to call anything more. Also, this assumes that the # write barrier does not touch the xmm registers. (Slightly delicate # assumption, given that the write barrier can end up calling the # platform's malloc() from AddressStack.append(). XXX may need to # be done properly) - self.mc.CALL(imm(descr.get_write_barrier_fn(self.cpu))) + self.mc.CALL(imm(func)) if IS_X86_32: - self.mc.ADD_ri(esp.value, 2*WORD) - for i in range(2, len(arglocs)): + self.mc.ADD_ri(esp.value, N*WORD) + for i in range(N, len(arglocs)): loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) @@ -2128,6 +2302,8 @@ assert 0 < offset <= 127 self.mc.overwrite(jz_location-1, chr(offset)) + genop_discard_cond_call_gc_wb_array = genop_discard_cond_call_gc_wb + def genop_force_token(self, op, arglocs, resloc): # RegAlloc.consider_force_token ensures this: assert isinstance(resloc, RegLoc) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -156,12 +156,14 @@ self.translate_support_code = translate_support_code # to be read/used by the assembler too self.jump_target_descr = None + self.close_stack_struct = 0 - def _prepare(self, inputargs, operations): + def _prepare(self, inputargs, operations, allgcrefs): self.fm = X86FrameManager() self.param_depth = 0 cpu = self.assembler.cpu - operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations) + operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations, + allgcrefs) # compute longevity of variables longevity = compute_vars_longevity(inputargs, operations) self.longevity = longevity @@ -172,15 +174,16 @@ assembler = self.assembler) return operations - def prepare_loop(self, inputargs, operations, looptoken): - operations = self._prepare(inputargs, operations) + def prepare_loop(self, inputargs, operations, looptoken, allgcrefs): + operations = self._prepare(inputargs, operations, allgcrefs) jump = operations[-1] loop_consts = compute_loop_consts(inputargs, jump, looptoken) self.loop_consts = loop_consts return self._process_inputargs(inputargs), operations - def prepare_bridge(self, prev_depths, inputargs, arglocs, operations): - operations = self._prepare(inputargs, operations) + def prepare_bridge(self, prev_depths, inputargs, arglocs, operations, + allgcrefs): + operations = self._prepare(inputargs, operations, allgcrefs) self.loop_consts = {} self._update_bindings(arglocs, inputargs) self.fm.frame_depth = prev_depths[0] @@ -378,7 +381,9 @@ self.assembler.regalloc_perform_discard(op, arglocs) def can_merge_with_next_guard(self, op, i, operations): - if op.getopnum() == rop.CALL_MAY_FORCE or op.getopnum() == rop.CALL_ASSEMBLER: + if (op.getopnum() == rop.CALL_MAY_FORCE or + op.getopnum() == rop.CALL_ASSEMBLER or + op.getopnum() == rop.CALL_RELEASE_GIL): assert operations[i + 1].getopnum() == rop.GUARD_NOT_FORCED return True if not op.is_comparison(): @@ -729,6 +734,19 @@ self.xrm.possibly_free_var(op.getarg(1)) def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None): + # we need to save registers on the stack: + # + # - at least the non-callee-saved registers + # + # - for shadowstack, we assume that any call can collect, and we + # save also the callee-saved registers that contain GC pointers, + # so that they can be found by follow_stack_frame_of_assembler() + # + # - for CALL_MAY_FORCE or CALL_ASSEMBLER, we have to save all regs + # anyway, in case we need to do cpu.force(). The issue is that + # grab_frame_values() would not be able to locate values in + # callee-saved registers. + # save_all_regs = guard_not_forced_op is not None self.xrm.before_call(force_store, save_all_regs=save_all_regs) if not save_all_regs: @@ -795,6 +813,8 @@ assert guard_op is not None self._consider_call(op, guard_op) + consider_call_release_gil = consider_call_may_force + def consider_call_assembler(self, op, guard_op): descr = op.getdescr() assert isinstance(descr, LoopToken) @@ -814,12 +834,12 @@ def consider_cond_call_gc_wb(self, op): assert op.result is None args = op.getarglist() - loc_newvalue = self.rm.make_sure_var_in_reg(op.getarg(1), args) - # ^^^ we force loc_newvalue in a reg (unless it's a Const), - # because it will be needed anyway by the following setfield_gc. - # It avoids loading it twice from the memory. - loc_base = self.rm.make_sure_var_in_reg(op.getarg(0), args) - arglocs = [loc_base, loc_newvalue] + N = len(args) + # we force all arguments in a reg (unless they are Consts), + # because it will be needed anyway by the following setfield_gc + # or setarrayitem_gc. It avoids loading it twice from the memory. + arglocs = [self.rm.make_sure_var_in_reg(op.getarg(i), args) + for i in range(N)] # add eax, ecx and edx as extra "arguments" to ensure they are # saved and restored. Fish in self.rm to know which of these # registers really need to be saved (a bit of a hack). Moreover, @@ -833,6 +853,8 @@ self.PerformDiscard(op, arglocs) self.rm.possibly_free_vars_for_op(op) + consider_cond_call_gc_wb_array = consider_cond_call_gc_wb + def fastpath_malloc_fixedsize(self, op, descr): assert isinstance(descr, BaseSizeDescr) self._do_fastpath_malloc(op, descr.size, descr.tid) @@ -1308,7 +1330,9 @@ name = name[len('consider_'):] num = getattr(rop, name.upper()) if (is_comparison_or_ovf_op(num) - or num == rop.CALL_MAY_FORCE or num == rop.CALL_ASSEMBLER): + or num == rop.CALL_MAY_FORCE + or num == rop.CALL_ASSEMBLER + or num == rop.CALL_RELEASE_GIL): oplist_with_guard[num] = value oplist[num] = add_none_argument(value) else: diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py --- a/pypy/jit/backend/x86/runner.py +++ b/pypy/jit/backend/x86/runner.py @@ -22,6 +22,7 @@ BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) dont_keepalive_stuff = False # for tests + with_threads = False def __init__(self, rtyper, stats, opts=None, translate_support_code=False, gcdescr=None): @@ -38,6 +39,7 @@ if not oprofile.OPROFILE_AVAILABLE: log.WARNING('oprofile support was explicitly enabled, but oprofile headers seem not to be available') profile_agent = oprofile.OProfileAgent() + self.with_threads = config.translation.thread self.profile_agent = profile_agent @@ -77,9 +79,9 @@ lines = machine_code_dump(data, addr, self.backend_name, label_list) print ''.join(lines) - def compile_loop(self, inputargs, operations, looptoken, log=True): - return self.assembler.assemble_loop(inputargs, operations, looptoken, - log=log) + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): + return self.assembler.assemble_loop(name, inputargs, operations, + looptoken, log=log) def compile_bridge(self, faildescr, inputargs, operations, original_loop_token, log=True): @@ -122,8 +124,8 @@ addr = executable_token._x86_bootstrap_code #llop.debug_print(lltype.Void, ">>>> Entering", addr) func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr) + fail_index = self._execute_call(func) #llop.debug_print(lltype.Void, "<<<< Back") - fail_index = self._execute_call(func) return self.get_fail_descr_from_number(fail_index) def _execute_call(self, func): @@ -140,10 +142,11 @@ LLInterpreter.current_interpreter = prev_interpreter return res - @staticmethod def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return CPU386.cast_adr_to_int(adr) + cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)' + cast_ptr_to_int = staticmethod(cast_ptr_to_int) all_null_registers = lltype.malloc(rffi.LONGP.TO, 24, flavor='raw', zero=True, diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -462,18 +464,18 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) @@ -530,6 +532,7 @@ POP_b = insn(rex_nw, '\x8F', orbyte(0<<3), stack_bp(1)) LEA_rb = insn(rex_w, '\x8D', register(1,8), stack_bp(2)) + LEA_rs = insn(rex_w, '\x8D', register(1,8), stack_sp(2)) LEA32_rb = insn(rex_w, '\x8D', register(1,8),stack_bp(2,force_32bits=True)) LEA_ra = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_scaled_reg_plus_const(2)) LEA_rm = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_const(2)) @@ -629,16 +632,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_gc_integration.py b/pypy/jit/backend/x86/test/test_gc_integration.py --- a/pypy/jit/backend/x86/test/test_gc_integration.py +++ b/pypy/jit/backend/x86/test/test_gc_integration.py @@ -16,7 +16,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.annlowlevel import llhelper from pypy.rpython.lltypesystem import rclass, rstr -from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList, GcPtrFieldDescr +from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcPtrFieldDescr from pypy.jit.backend.x86.test.test_regalloc import MockAssembler from pypy.jit.backend.x86.test.test_regalloc import BaseTestRegalloc @@ -51,11 +51,9 @@ gcrootmap = MockGcRootMap() def initialize(self): - self.gcrefs = GcRefList() - self.gcrefs.initialize() - self.single_gcref_descr = GcPtrFieldDescr('', 0) + pass - replace_constptrs_with_getfield_raw = GcLLDescr_framework.replace_constptrs_with_getfield_raw.im_func + record_constptrs = GcLLDescr_framework.record_constptrs.im_func rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func class TestRegallocDirectGcIntegration(object): diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] @@ -330,6 +348,7 @@ assert result != expected def test_compile_bridge_check_profile_info(self): + py.test.skip("does not work, reinvestigate") class FakeProfileAgent(object): def __init__(self): self.functions = [] @@ -362,7 +381,7 @@ operations[3].setfailargs([i1]) self.cpu.compile_loop(inputargs, operations, looptoken) name, loopaddress, loopsize = agent.functions[0] - assert name == "Loop # 17: hello" + assert name == "Loop # 17: hello (loop counter 0)" assert loopaddress <= looptoken._x86_loop_code assert loopsize >= 40 # randomish number @@ -378,7 +397,7 @@ self.cpu.compile_bridge(faildescr1, [i1b], bridge, looptoken) name, address, size = agent.functions[1] - assert name == "Bridge # 0: bye" + assert name == "Bridge # 0: bye (loop counter 1)" # Would be exactly ==, but there are some guard failure recovery # stubs in-between assert address >= loopaddress + loopsize diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,15 +185,32 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass def test_mov_ri_64(): s = CodeBuilder64() s.MOV_ri(ecx, -2) + s.MOV_ri(r15, -3) + s.MOV_ri(ebx, -0x80000003) + s.MOV_ri(r13, -0x80000002) + s.MOV_ri(ecx, 42) s.MOV_ri(r12, 0x80000042) + s.MOV_ri(r12, 0x100000007) assert s.getvalue() == ('\x48\xC7\xC1\xFE\xFF\xFF\xFF' + - '\x49\xBC\x42\x00\x00\x80\x00\x00\x00\x00') + '\x49\xC7\xC7\xFD\xFF\xFF\xFF' + + '\x48\xBB\xFD\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\x49\xBD\xFE\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\xB9\x2A\x00\x00\x00' + + '\x41\xBC\x42\x00\x00\x80' + + '\x49\xBC\x07\x00\x00\x00\x01\x00\x00\x00') def test_mov_rm_64(): s = CodeBuilder64() diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py --- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py +++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py @@ -212,6 +212,17 @@ for mode, v in zip(argmodes, args): ops.append(assembler_operand[mode](v)) ops.reverse() + # + if (instrname.lower() == 'mov' and suffix == 'q' and + ops[0].startswith('$') and 0 <= int(ops[0][1:]) <= 4294967295 + and ops[1].startswith('%r')): + # movq $xxx, %rax => movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -1,8 +1,7 @@ """ -This is a test that translates a complete JIT to C and runs it. It is -not testing much, expect that it basically works. What it *is* testing, -however, is the correct handling of GC, i.e. if objects are freed as -soon as possible (at least in a simple case). +This is a test that translates a complete JIT together with a GC and runs it. +It is testing that the GC-dependent aspects basically work, mostly the mallocs +and the various cases of write barrier. """ import weakref @@ -10,16 +9,11 @@ from pypy.annotation import policy as annpolicy from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe -from pypy.jit.backend.x86.runner import CPU386 -from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir -from pypy.jit.backend.x86.arch import IS_X86_64 from pypy.config.translationoption import DEFL_GC -import py.test class X(object): def __init__(self, x=0): @@ -86,7 +80,7 @@ # return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2} -def compile(f, gc, **kwds): +def compile(f, gc, enable_opts='', **kwds): from pypy.annotation.listdef import s_list_of_strings from pypy.translator.translator import TranslationContext from pypy.jit.metainterp.warmspot import apply_jit @@ -110,14 +104,14 @@ old_value[obj, attr] = getattr(obj, attr) setattr(obj, attr, value) # - apply_jit(t, enable_opts='') + apply_jit(t, enable_opts=enable_opts) # finally: for (obj, attr), oldvalue in old_value.items(): setattr(obj, attr, oldvalue) cbuilder = genc.CStandaloneBuilder(t, f, t.config) - cbuilder.generate_source() + cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) cbuilder.compile() return cbuilder @@ -154,8 +148,10 @@ # ______________________________________________________________________ -class CompileFrameworkTests(object): - # Test suite using (so far) the minimark GC. + +class BaseFrameworkTests(object): + compile_kwds = {} + def setup_class(cls): funcs = [] name_to_func = {} @@ -205,7 +201,8 @@ try: GcLLDescr_framework.DEBUG = True cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC, - gcrootfinder=cls.gcrootfinder, jit=True) + gcrootfinder=cls.gcrootfinder, jit=True, + **cls.compile_kwds) finally: GcLLDescr_framework.DEBUG = OLD_DEBUG @@ -224,32 +221,36 @@ def run_orig(self, name, n, x): self.main_allfuncs(name, n, x) - def define_libffi_workaround(cls): - # XXX: this is a workaround for a bug in database.py. It seems that - # the problem is triggered by optimizeopt/fficall.py, and in - # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in - # these tests, that line is the only place where libffi.Func is - # referenced. - # - # The problem occurs because the gctransformer tries to annotate a - # low-level helper to call the __del__ of libffi.Func when it's too - # late. - # - # This workaround works by forcing the annotator (and all the rest of - # the toolchain) to see libffi.Func in a "proper" context, not just as - # the target of cast_base_ptr_to_instance. Note that the function - # below is *never* called by any actual test, it's just annotated. - # - from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain - libc_name = get_libc_name() - def f(n, x, *args): - libc = CDLL(libc_name) - ptr = libc.getpointer('labs', [types.slong], types.slong) - chain = ArgChain() - chain.arg(n) - n = ptr.call(chain, lltype.Signed) - return (n, x) + args - return None, f, None + +class CompileFrameworkTests(BaseFrameworkTests): + # Test suite using (so far) the minimark GC. + +## def define_libffi_workaround(cls): +## # XXX: this is a workaround for a bug in database.py. It seems that +## # the problem is triggered by optimizeopt/fficall.py, and in +## # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in +## # these tests, that line is the only place where libffi.Func is +## # referenced. +## # +## # The problem occurs because the gctransformer tries to annotate a +## # low-level helper to call the __del__ of libffi.Func when it's too +## # late. +## # +## # This workaround works by forcing the annotator (and all the rest of +## # the toolchain) to see libffi.Func in a "proper" context, not just as +## # the target of cast_base_ptr_to_instance. Note that the function +## # below is *never* called by any actual test, it's just annotated. +## # +## from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain +## libc_name = get_libc_name() +## def f(n, x, *args): +## libc = CDLL(libc_name) +## ptr = libc.getpointer('labs', [types.slong], types.slong) +## chain = ArgChain() +## chain.arg(n) +## n = ptr.call(chain, lltype.Signed) +## return (n, x) + args +## return None, f, None def define_compile_framework_1(cls): # a moving GC. Supports malloc_varsize_nonmovable. Simple test, works @@ -456,6 +457,73 @@ def test_compile_framework_7(self): self.run('compile_framework_7') + def define_compile_framework_8(cls): + # Array of pointers, of unknown length (test write_barrier_from_array) + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + l = [None] * (16 + (n & 7)) + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[8] = X(n+70) + l[9] = X(n+80) + l[10] = X(n+90) + l[11] = X(n+100) + l[12] = X(n+110) + l[13] = X(n+120) + l[14] = X(n+130) + l[15] = X(n+140) + if n < 1800: + check(len(l) == 16 + (n & 7)) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[8].x == n+70) + check(l[9].x == n+80) + check(l[10].x == n+90) + check(l[11].x == n+100) + check(l[12].x == n+110) + check(l[13].x == n+120) + check(l[14].x == n+130) + check(l[15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 16) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[8].x == 72) + check(l[9].x == 82) + check(l[10].x == 92) + check(l[11].x == 102) + check(l[12].x == 112) + check(l[13].x == 122) + check(l[14].x == 132) + check(l[15].x == 142) + return before, f, after + + def test_compile_framework_8(self): + self.run('compile_framework_8') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) @@ -493,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_releasegil.py copy from pypy/jit/backend/x86/test/test_zrpy_gc.py copy to pypy/jit/backend/x86/test/test_zrpy_releasegil.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_releasegil.py @@ -1,618 +1,110 @@ -""" -This is a test that translates a complete JIT to C and runs it. It is -not testing much, expect that it basically works. What it *is* testing, -however, is the correct handling of GC, i.e. if objects are freed as -soon as possible (at least in a simple case). -""" +from pypy.rpython.lltypesystem import lltype, llmemory, rffi +from pypy.rlib.jit import dont_look_inside +from pypy.jit.metainterp.optimizeopt import ALL_OPTS_NAMES -import weakref -import py, os -from pypy.annotation import policy as annpolicy -from pypy.rlib import rgc -from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe -from pypy.jit.backend.x86.runner import CPU386 -from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc -from pypy.jit.backend.llsupport.gc import GcLLDescr_framework -from pypy.tool.udir import udir -from pypy.jit.backend.x86.arch import IS_X86_64 -from pypy.config.translationoption import DEFL_GC -import py.test +from pypy.rlib.libffi import CDLL, types, ArgChain, clibffi +from pypy.rpython.lltypesystem.ll2ctypes import libc_name +from pypy.rpython.annlowlevel import llhelper -class X(object): - def __init__(self, x=0): - self.x = x +from pypy.jit.backend.x86.test.test_zrpy_gc import BaseFrameworkTests +from pypy.jit.backend.x86.test.test_zrpy_gc import check - next = None -class CheckError(Exception): - pass +class ReleaseGILTests(BaseFrameworkTests): + compile_kwds = dict(enable_opts=ALL_OPTS_NAMES, thread=True) -def check(flag): - if not flag: - raise CheckError - -def get_g(main): - main._dont_inline_ = True - def g(name, n): - x = X() - x.foo = 2 - main(n, x) - x.foo = 5 - return weakref.ref(x) - g._dont_inline_ = True - return g - - -def get_entry(g): - - def entrypoint(args): - name = '' - n = 2000 - argc = len(args) - if argc > 1: - name = args[1] - if argc > 2: - n = int(args[2]) - r_list = [] - for i in range(20): - r = g(name, n) - r_list.append(r) - rgc.collect() - rgc.collect(); rgc.collect() - freed = 0 - for r in r_list: - if r() is None: - freed += 1 - print freed - return 0 - - return entrypoint - - -def get_functions_to_patch(): - from pypy.jit.backend.llsupport import gc - # - can_inline_malloc1 = gc.GcLLDescr_framework.can_inline_malloc - def can_inline_malloc2(*args): - try: - if os.environ['PYPY_NO_INLINE_MALLOC']: - return False - except KeyError: + def define_simple(self): + class Glob: pass - return can_inline_malloc1(*args) - # - return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2} - -def compile(f, gc, **kwds): - from pypy.annotation.listdef import s_list_of_strings - from pypy.translator.translator import TranslationContext - from pypy.jit.metainterp.warmspot import apply_jit - from pypy.translator.c import genc - # - t = TranslationContext() - t.config.translation.gc = gc - if gc != 'boehm': - t.config.translation.gcremovetypeptr = True - for name, value in kwds.items(): - setattr(t.config.translation, name, value) - ann = t.buildannotator(policy=annpolicy.StrictAnnotatorPolicy()) - ann.build_types(f, [s_list_of_strings], main_entry_point=True) - t.buildrtyper().specialize() - - if kwds['jit']: - patch = get_functions_to_patch() - old_value = {} - try: - for (obj, attr), value in patch.items(): - old_value[obj, attr] = getattr(obj, attr) - setattr(obj, attr, value) - # - apply_jit(t, enable_opts='') - # - finally: - for (obj, attr), oldvalue in old_value.items(): - setattr(obj, attr, oldvalue) - - cbuilder = genc.CStandaloneBuilder(t, f, t.config) - cbuilder.generate_source() - cbuilder.compile() - return cbuilder - -def run(cbuilder, args=''): - # - pypylog = udir.join('test_zrpy_gc.log') - data = cbuilder.cmdexec(args, env={'PYPYLOG': ':%s' % pypylog}) - return data.strip() - -def compile_and_run(f, gc, **kwds): - cbuilder = compile(f, gc, **kwds) - return run(cbuilder) - - - -def test_compile_boehm(): - myjitdriver = JitDriver(greens = [], reds = ['n', 'x']) - @dont_look_inside - def see(lst, n): - assert len(lst) == 3 - assert lst[0] == n+10 - assert lst[1] == n+20 - assert lst[2] == n+30 - def main(n, x): - while n > 0: - myjitdriver.can_enter_jit(n=n, x=x) - myjitdriver.jit_merge_point(n=n, x=x) - y = X() - y.foo = x.foo - n -= y.foo - see([n+10, n+20, n+30], n) - res = compile_and_run(get_entry(get_g(main)), "boehm", jit=True) - assert int(res) >= 16 - -# ______________________________________________________________________ - -class CompileFrameworkTests(object): - # Test suite using (so far) the minimark GC. - def setup_class(cls): - funcs = [] - name_to_func = {} - for fullname in dir(cls): - if not fullname.startswith('define'): - continue - definefunc = getattr(cls, fullname) - _, name = fullname.split('_', 1) - beforefunc, loopfunc, afterfunc = definefunc.im_func(cls) - if beforefunc is None: - def beforefunc(n, x): - return n, x, None, None, None, None, None, None, None, None, None, '' - if afterfunc is None: - def afterfunc(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - pass - beforefunc.func_name = 'before_'+name - loopfunc.func_name = 'loop_'+name - afterfunc.func_name = 'after_'+name - funcs.append((beforefunc, loopfunc, afterfunc)) - assert name not in name_to_func - name_to_func[name] = len(name_to_func) - print name_to_func - def allfuncs(name, n): - x = X() - x.foo = 2 - main_allfuncs(name, n, x) - x.foo = 5 - return weakref.ref(x) - def main_allfuncs(name, n, x): - num = name_to_func[name] - n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s = funcs[num][0](n, x) - while n > 0: - myjitdriver.can_enter_jit(num=num, n=n, x=x, x0=x0, x1=x1, - x2=x2, x3=x3, x4=x4, x5=x5, x6=x6, x7=x7, l=l, s=s) - myjitdriver.jit_merge_point(num=num, n=n, x=x, x0=x0, x1=x1, - x2=x2, x3=x3, x4=x4, x5=x5, x6=x6, x7=x7, l=l, s=s) - - n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s = funcs[num][1]( - n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s) - funcs[num][2](n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s) - myjitdriver = JitDriver(greens = ['num'], - reds = ['n', 'x', 'x0', 'x1', 'x2', 'x3', 'x4', - 'x5', 'x6', 'x7', 'l', 's']) - cls.main_allfuncs = staticmethod(main_allfuncs) - cls.name_to_func = name_to_func - OLD_DEBUG = GcLLDescr_framework.DEBUG - try: - GcLLDescr_framework.DEBUG = True - cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC, - gcrootfinder=cls.gcrootfinder, jit=True) - finally: - GcLLDescr_framework.DEBUG = OLD_DEBUG - - def _run(self, name, n, env): - res = self.cbuilder.cmdexec("%s %d" %(name, n), env=env) - assert int(res) == 20 - - def run(self, name, n=2000): - pypylog = udir.join('TestCompileFramework.log') - env = {'PYPYLOG': ':%s' % pypylog, - 'PYPY_NO_INLINE_MALLOC': '1'} - self._run(name, n, env) - env['PYPY_NO_INLINE_MALLOC'] = '' - self._run(name, n, env) - - def run_orig(self, name, n, x): - self.main_allfuncs(name, n, x) - - def define_libffi_workaround(cls): - # XXX: this is a workaround for a bug in database.py. It seems that - # the problem is triggered by optimizeopt/fficall.py, and in - # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in - # these tests, that line is the only place where libffi.Func is - # referenced. + glob = Glob() # - # The problem occurs because the gctransformer tries to annotate a - # low-level helper to call the __del__ of libffi.Func when it's too - # late. - # - # This workaround works by forcing the annotator (and all the rest of - # the toolchain) to see libffi.Func in a "proper" context, not just as - # the target of cast_base_ptr_to_instance. Note that the function - # below is *never* called by any actual test, it's just annotated. - # - from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain - libc_name = get_libc_name() - def f(n, x, *args): - libc = CDLL(libc_name) - ptr = libc.getpointer('labs', [types.slong], types.slong) - chain = ArgChain() - chain.arg(n) - n = ptr.call(chain, lltype.Signed) - return (n, x) + args - return None, f, None - - def define_compile_framework_1(cls): - # a moving GC. Supports malloc_varsize_nonmovable. Simple test, works - # without write_barriers and root stack enumeration. - def f(n, x, *args): - y = X() - y.foo = x.foo - n -= y.foo - return (n, x) + args - return None, f, None - - def test_compile_framework_1(self): - self.run('compile_framework_1') - - def define_compile_framework_2(cls): - # More complex test, requires root stack enumeration but - # not write_barriers. - def f(n, x, *args): - prev = x - for j in range(101): # f() runs 20'000 times, thus allocates - y = X() # a total of 2'020'000 objects - y.foo = prev.foo - prev = y - n -= prev.foo - return (n, x) + args - return None, f, None - - def test_compile_framework_2(self): - self.run('compile_framework_2') - - def define_compile_framework_3(cls): - # Third version of the test. Really requires write_barriers. - def f(n, x, *args): - x.next = None - for j in range(101): # f() runs 20'000 times, thus allocates - y = X() # a total of 2'020'000 objects - y.foo = j+1 - y.next = x.next - x.next = y - check(x.next.foo == 101) - total = 0 - y = x - for j in range(101): - y = y.next - total += y.foo - check(not y.next) - check(total == 101*102/2) - n -= x.foo - return (n, x) + args - return None, f, None - - - - def test_compile_framework_3(self): - x_test = X() - x_test.foo = 5 - self.run_orig('compile_framework_3', 6, x_test) # check that it does not raise CheckError - self.run('compile_framework_3') - - def define_compile_framework_3_extra(cls): - # Extra version of the test, with tons of live vars around the residual - # call that all contain a GC pointer. - @dont_look_inside - def residual(n=26): - x = X() - x.next = X() - x.next.foo = n - return x + def f42(n): + c_strchr = glob.c_strchr + raw = rffi.str2charp("foobar" + chr((n & 63) + 32)) + argchain = ArgChain() + argchain = argchain.arg(rffi.cast(lltype.Signed, raw)) + argchain = argchain.arg(rffi.cast(rffi.INT, ord('b'))) + res = c_strchr.call(argchain, rffi.CCHARP) + check(rffi.charp2str(res) == "bar" + chr((n & 63) + 32)) + rffi.free_charp(raw) # def before(n, x): - residual(5) - x0 = residual() - x1 = residual() - x2 = residual() - x3 = residual() - x4 = residual() - x5 = residual() - x6 = residual() - x7 = residual() - n *= 19 - return n, None, x0, x1, x2, x3, x4, x5, x6, x7, None, None - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - x8 = residual() - x9 = residual() - check(x0.next.foo == 26) - check(x1.next.foo == 26) - check(x2.next.foo == 26) - check(x3.next.foo == 26) - check(x4.next.foo == 26) - check(x5.next.foo == 26) - check(x6.next.foo == 26) - check(x7.next.foo == 26) - check(x8.next.foo == 26) - check(x9.next.foo == 26) - x0, x1, x2, x3, x4, x5, x6, x7 = x7, x4, x6, x5, x3, x2, x9, x8 + libc = CDLL(libc_name) + c_strchr = libc.getpointer('strchr', [types.pointer, types.sint], + types.pointer) + glob.c_strchr = c_strchr + return (n, None, None, None, None, None, + None, None, None, None, None, None) + # + def f(n, x, *args): + f42(n) n -= 1 - return n, None, x0, x1, x2, x3, x4, x5, x6, x7, None, None - return before, f, None - - def test_compile_framework_3_extra(self): - self.run_orig('compile_framework_3_extra', 6, None) # check that it does not raise CheckError - self.run('compile_framework_3_extra') - - def define_compile_framework_4(cls): - # Fourth version of the test, with __del__. - from pypy.rlib.debug import debug_print - class Counter: - cnt = 0 - counter = Counter() - class Z: - def __del__(self): - counter.cnt -= 1 - def before(n, x): - debug_print('counter.cnt =', counter.cnt) - check(counter.cnt < 5) - counter.cnt = n // x.foo - return n, x, None, None, None, None, None, None, None, None, None, None - def f(n, x, *args): - Z() - n -= x.foo return (n, x) + args return before, f, None - def test_compile_framework_4(self): - self.run('compile_framework_4') + def test_simple(self): + self.run('simple') - def define_compile_framework_5(cls): - # Test string manipulation. - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - n -= x.foo - s += str(n) - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - check(len(s) == 1*5 + 2*45 + 3*450 + 4*500) - return None, f, after - - def test_compile_framework_5(self): - self.run('compile_framework_5') - - def define_compile_framework_7(cls): - # Array of pointers (test the write barrier for setarrayitem_gc) + def define_close_stack(self): + # + class Glob(object): + pass + glob = Glob() + class X(object): + pass + # + def callback(p1, p2): + for i in range(100): + glob.lst.append(X()) + return rffi.cast(rffi.INT, 1) + CALLBACK = lltype.Ptr(lltype.FuncType([lltype.Signed, + lltype.Signed], rffi.INT)) + # + @dont_look_inside + def alloc1(): + return llmemory.raw_malloc(16) + @dont_look_inside + def free1(p): + llmemory.raw_free(p) + # + def f42(): + length = len(glob.lst) + c_qsort = glob.c_qsort + raw = alloc1() + fn = llhelper(CALLBACK, rffi._make_wrapper_for(CALLBACK, callback)) + argchain = ArgChain() + argchain = argchain.arg(rffi.cast(lltype.Signed, raw)) + argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 2)) + argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 8)) + argchain = argchain.arg(rffi.cast(lltype.Signed, fn)) + c_qsort.call(argchain, lltype.Void) + free1(raw) + check(len(glob.lst) > length) + del glob.lst[:] + # def before(n, x): - return n, x, None, None, None, None, None, None, None, None, [X(123)], None - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - if n < 1900: - check(l[0].x == 123) - l = [None] * 16 - l[0] = X(123) - l[1] = X(n) - l[2] = X(n+10) - l[3] = X(n+20) - l[4] = X(n+30) - l[5] = X(n+40) - l[6] = X(n+50) - l[7] = X(n+60) - l[8] = X(n+70) - l[9] = X(n+80) - l[10] = X(n+90) - l[11] = X(n+100) - l[12] = X(n+110) - l[13] = X(n+120) - l[14] = X(n+130) - l[15] = X(n+140) - if n < 1800: - check(len(l) == 16) - check(l[0].x == 123) - check(l[1].x == n) - check(l[2].x == n+10) - check(l[3].x == n+20) - check(l[4].x == n+30) - check(l[5].x == n+40) - check(l[6].x == n+50) - check(l[7].x == n+60) - check(l[8].x == n+70) - check(l[9].x == n+80) - check(l[10].x == n+90) - check(l[11].x == n+100) - check(l[12].x == n+110) - check(l[13].x == n+120) - check(l[14].x == n+130) - check(l[15].x == n+140) - n -= x.foo - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - check(len(l) == 16) - check(l[0].x == 123) - check(l[1].x == 2) - check(l[2].x == 12) - check(l[3].x == 22) - check(l[4].x == 32) - check(l[5].x == 42) - check(l[6].x == 52) - check(l[7].x == 62) - check(l[8].x == 72) - check(l[9].x == 82) - check(l[10].x == 92) - check(l[11].x == 102) - check(l[12].x == 112) - check(l[13].x == 122) - check(l[14].x == 132) - check(l[15].x == 142) - return before, f, after - - def test_compile_framework_7(self): - self.run('compile_framework_7') - - def define_compile_framework_external_exception_handling(cls): - def before(n, x): - x = X(0) - return n, x, None, None, None, None, None, None, None, None, None, None - - @dont_look_inside - def g(x): - if x > 200: - return 2 - raise ValueError - @dont_look_inside - def h(x): - if x > 150: - raise ValueError - return 2 - - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - try: - x.x += g(n) - except ValueError: - x.x += 1 - try: - x.x += h(n) - except ValueError: - x.x -= 1 + libc = CDLL(libc_name) + types_size_t = clibffi.cast_type_to_ffitype(rffi.SIZE_T) + c_qsort = libc.getpointer('qsort', [types.pointer, types_size_t, + types_size_t, types.pointer], + types.void) + glob.c_qsort = c_qsort + glob.lst = [] + return (n, None, None, None, None, None, + None, None, None, None, None, None) + # + def f(n, x, *args): + f42() n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - - def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - check(x.x == 1800 * 2 + 1850 * 2 + 200 - 150) - + return (n, x) + args return before, f, None - def test_compile_framework_external_exception_handling(self): - self.run('compile_framework_external_exception_handling') + def test_close_stack(self): + self.run('close_stack') - def define_compile_framework_bug1(self): - @purefunction - def nonmoving(): - x = X(1) - for i in range(7): - rgc.collect() - return x - @dont_look_inside - def do_more_stuff(): - x = X(5) - for i in range(7): - rgc.collect() - return x - - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - x0 = do_more_stuff() - check(nonmoving().x == 1) - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - - return None, f, None - - def test_compile_framework_bug1(self): - self.run('compile_framework_bug1', 200) - - def define_compile_framework_vref(self): - from pypy.rlib.jit import virtual_ref, virtual_ref_finish - class A: - pass - glob = A() - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - a = A() - glob.v = vref = virtual_ref(a) - virtual_ref_finish(vref, a) - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - return None, f, None - - def test_compile_framework_vref(self): - self.run('compile_framework_vref', 200) - - def define_compile_framework_float(self): - # test for a bug: the fastpath_malloc does not save and restore - # xmm registers around the actual call to the slow path - class A: - x0 = x1 = x2 = x3 = x4 = x5 = x6 = x7 = 0 - @dont_look_inside - def escape1(a): - a.x0 += 0 - a.x1 += 6 - a.x2 += 12 - a.x3 += 18 - a.x4 += 24 - a.x5 += 30 - a.x6 += 36 - a.x7 += 42 - @dont_look_inside - def escape2(n, f0, f1, f2, f3, f4, f5, f6, f7): - check(f0 == n + 0.0) - check(f1 == n + 0.125) - check(f2 == n + 0.25) - check(f3 == n + 0.375) - check(f4 == n + 0.5) - check(f5 == n + 0.625) - check(f6 == n + 0.75) - check(f7 == n + 0.875) - @unroll_safe - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - i = 0 - while i < 42: - m = n + i - f0 = m + 0.0 - f1 = m + 0.125 - f2 = m + 0.25 - f3 = m + 0.375 - f4 = m + 0.5 - f5 = m + 0.625 - f6 = m + 0.75 - f7 = m + 0.875 - a1 = A() - # at this point, all or most f's are still in xmm registers - escape1(a1) - escape2(m, f0, f1, f2, f3, f4, f5, f6, f7) - i += 1 - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - return None, f, None - - def test_compile_framework_float(self): - self.run('compile_framework_float') - - def define_compile_framework_minimal_size_in_nursery(self): - S = lltype.GcStruct('S') # no fields! - T = lltype.GcStruct('T', ('i', lltype.Signed)) - @unroll_safe - def f42(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - lst1 = [] - lst2 = [] - i = 0 - while i < 42: - s1 = lltype.malloc(S) - t1 = lltype.malloc(T) - t1.i = 10000 + i + n - lst1.append(s1) - lst2.append(t1) - i += 1 - i = 0 - while i < 42: - check(lst2[i].i == 10000 + i + n) - i += 1 - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - return None, f42, None - - def test_compile_framework_minimal_size_in_nursery(self): - self.run('compile_framework_minimal_size_in_nursery') - - -class TestShadowStack(CompileFrameworkTests): +class TestShadowStack(ReleaseGILTests): gcrootfinder = "shadowstack" -class TestAsmGcc(CompileFrameworkTests): +class TestAsmGcc(ReleaseGILTests): gcrootfinder = "asmgcc" diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/assembler.py b/pypy/jit/codewriter/assembler.py --- a/pypy/jit/codewriter/assembler.py +++ b/pypy/jit/codewriter/assembler.py @@ -76,7 +76,8 @@ TYPE = llmemory.Address if TYPE == llmemory.Address: value = heaptracker.adr2int(value) - elif not isinstance(value, ComputedIntSymbolic): + if not isinstance(value, (llmemory.AddressAsInt, + ComputedIntSymbolic)): value = lltype.cast_primitive(lltype.Signed, value) if allow_short and -128 <= value <= 127: # emit the constant as a small integer diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -237,7 +237,9 @@ self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, oopspecindex, can_invalidate) # - if pure or loopinvariant: + if oopspecindex != EffectInfo.OS_NONE: + assert effectinfo is not None + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -75,12 +75,13 @@ # OS_MATH_SQRT = 100 - def __new__(cls, readonly_descrs_fields, + def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, can_invalidate=False): key = (frozenset(readonly_descrs_fields), + frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, @@ -89,8 +90,9 @@ return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields + result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: @@ -108,6 +110,9 @@ def check_forces_virtual_or_virtualizable(self): return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE + def has_random_effects(self): + return self.oopspecindex == self.OS_LIBFFI_CALL + def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, @@ -116,7 +121,7 @@ if effects is top_set: return None readonly_descrs_fields = [] - # readonly_descrs_arrays = [] --- not enabled for now + readonly_descrs_arrays = [] write_descrs_fields = [] write_descrs_arrays = [] @@ -142,10 +147,13 @@ elif tup[0] == "array": add_array(write_descrs_arrays, tup) elif tup[0] == "readarray": - pass + tupw = ("array",) + tup[1:] + if tupw not in effects: + add_array(readonly_descrs_arrays, tup) else: assert 0 return EffectInfo(readonly_descrs_fields, + readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect, diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -768,10 +768,10 @@ from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof from pypy.rlib.rarithmetic import intmask assert not self._is_gc(op.args[0]) - size1, unsigned1 = size_and_sign(op.args[0].concretetype) size2, unsigned2 = size_and_sign(op.result.concretetype) if size2 >= sizeof(lltype.Signed): return # the target type is LONG or ULONG + size1, unsigned1 = size_and_sign(op.args[0].concretetype) # def bounds(size, unsigned): if unsigned: @@ -800,6 +800,13 @@ result[-1].result = op.result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from @@ -847,7 +854,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1335,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1387,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' @@ -44,10 +44,6 @@ return True if mod.startswith('pypy.translator.'): # XXX wtf? return True - # string builder interface - if mod == 'pypy.rpython.lltypesystem.rbuilder': - return True - return False def look_inside_graph(self, graph): diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -34,6 +34,15 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays +def test_include_read_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo.write_descrs_fields + assert not effectinfo.write_descrs_arrays + def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) @@ -51,6 +60,16 @@ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.write_descrs_arrays +def test_dont_include_read_and_write_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A)), + ("array", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert not effectinfo.readonly_descrs_arrays + assert not effectinfo.write_descrs_fields + assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -813,6 +813,15 @@ int_return %i0 """, transform=True) + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLException diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,8 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print +from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -13,8 +14,8 @@ from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper -from pypy.jit.metainterp.optimizeutil import InvalidLoop -from pypy.jit.metainterp.resume import NUMBERING +from pypy.jit.metainterp.optimize import InvalidLoop +from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong def giveup(): @@ -118,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -156,6 +158,7 @@ def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type): jitdriver_sd.on_compile(metainterp_sd.logger_ops, loop.token, loop.operations, type, greenkey) + loopname = jitdriver_sd.warmstate.get_location_str(greenkey) globaldata = metainterp_sd.globaldata loop_token = loop.token loop_token.number = n = globaldata.loopnumbering @@ -170,7 +173,7 @@ debug_start("jit-backend") try: ops_offset = metainterp_sd.cpu.compile_loop(loop.inputargs, operations, - loop.token) + loop.token, name=loopname) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() @@ -300,7 +303,7 @@ rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) CNT_INT = -0x20000000 CNT_REF = -0x40000000 @@ -452,9 +455,17 @@ # Called during a residual call from the assembler, if the code # actually needs to force one of the virtualrefs or the virtualizable. # Implemented by forcing *all* virtualrefs and the virtualizable. - faildescr = cpu.force(token) - assert isinstance(faildescr, ResumeGuardForcedDescr) - faildescr.handle_async_forcing(token) + + # don't interrupt me! If the stack runs out in force_from_resumedata() + # then we have seen cpu.force() but not self.save_data(), leaving in + # an inconsistent state + rstack._stack_criticalcode_start() + try: + faildescr = cpu.force(token) + assert isinstance(faildescr, ResumeGuardForcedDescr) + faildescr.handle_async_forcing(token) + finally: + rstack._stack_criticalcode_stop() def handle_async_forcing(self, force_token): from pypy.jit.metainterp.resume import force_from_resumedata @@ -623,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -82,9 +82,6 @@ do_call_loopinvariant = do_call do_call_may_force = do_call -def do_call_c(cpu, metainterp, argboxes, descr): - raise NotImplementedError("Should never be called directly") - def do_getarrayitem_gc(cpu, _, arraybox, indexbox, arraydescr): array = arraybox.getref_base() index = indexbox.getint() @@ -319,9 +316,11 @@ if value in (rop.FORCE_TOKEN, rop.CALL_ASSEMBLER, rop.COND_CALL_GC_WB, + rop.COND_CALL_GC_WB_ARRAY, rop.DEBUG_MERGE_POINT, rop.JIT_DEBUG, rop.SETARRAYITEM_RAW, + rop.CALL_RELEASE_GIL, rop.QUASIIMMUT_FIELD, ): # list of opcodes never executed by pyjitpl continue diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -4,7 +4,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rlib.objectmodel import we_are_translated, r_dict, Symbolic from pypy.rlib.objectmodel import compute_unique_id -from pypy.rlib.rarithmetic import intmask, r_int64 +from pypy.rlib.rarithmetic import r_int64 from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop @@ -712,10 +712,14 @@ return -2 # xxx risk of changing hash... def make_hashable_int(i): + from pypy.rpython.lltypesystem.ll2ctypes import NotCtypesAllocatedStructure if not we_are_translated() and isinstance(i, llmemory.AddressAsInt): # Warning: such a hash changes at the time of translation adr = heaptracker.int2adr(i) - return llmemory.cast_adr_to_int(adr, "emulated") + try: + return llmemory.cast_adr_to_int(adr, "emulated") + except NotCtypesAllocatedStructure: + return 12345 # use an arbitrary number for the hash return i def get_const_ptr_for_string(s): @@ -761,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled @@ -787,11 +792,13 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None token = None call_pure_results = None + logops = None quasi_immutable_deps = None def __init__(self, name): diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py --- a/pypy/jit/metainterp/logger.py +++ b/pypy/jit/metainterp/logger.py @@ -11,47 +11,71 @@ def __init__(self, metainterp_sd, guard_number=False): self.metainterp_sd = metainterp_sd - self.ts = metainterp_sd.cpu.ts self.guard_number = guard_number def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): if type is None: debug_start("jit-log-noopt-loop") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-loop") else: debug_start("jit-log-opt-loop") debug_print("# Loop", number, ":", type, "with", len(operations), "ops") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-opt-loop") + return logops def log_bridge(self, inputargs, operations, number=-1, ops_offset=None): if number == -1: debug_start("jit-log-noopt-bridge") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-bridge") else: debug_start("jit-log-opt-bridge") debug_print("# bridge out of Guard", number, "with", len(operations), "ops") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-opt-bridge") + return logops def log_short_preamble(self, inputargs, operations): debug_start("jit-log-short-preamble") - self._log_operations(inputargs, operations, ops_offset=None) - debug_stop("jit-log-short-preamble") + logops = self._log_operations(inputargs, operations, ops_offset=None) + debug_stop("jit-log-short-preamble") + return logops + + def _log_operations(self, inputargs, operations, ops_offset): + if not have_debug_prints(): + return None + logops = self._make_log_operations() + logops._log_operations(inputargs, operations, ops_offset) + return logops + + def _make_log_operations(self): + return LogOperations(self.metainterp_sd, self.guard_number) + + +class LogOperations(object): + """ + ResOperation logger. Each instance contains a memo giving numbers + to boxes, and is typically used to log a single loop. + """ + def __init__(self, metainterp_sd, guard_number): + self.metainterp_sd = metainterp_sd + self.ts = metainterp_sd.cpu.ts + self.guard_number = guard_number + self.memo = {} def repr_of_descr(self, descr): return descr.repr_of_descr() - def repr_of_arg(self, memo, arg): + def repr_of_arg(self, arg): try: - mv = memo[arg] + mv = self.memo[arg] except KeyError: - mv = len(memo) - memo[arg] = mv + mv = len(self.memo) + self.memo[arg] = mv if isinstance(arg, ConstInt): if int_could_be_an_address(arg.value): addr = arg.getaddr() @@ -75,11 +99,12 @@ else: return '?' - def repr_of_resop(self, memo, op, ops_offset=None): + def repr_of_resop(self, op, ops_offset=None): if op.getopnum() == rop.DEBUG_MERGE_POINT: - loc = op.getarg(0)._get_str() - reclev = op.getarg(1).getint() - return "debug_merge_point('%s', %s)" % (loc, reclev) + jd_sd = self.metainterp_sd.jitdrivers_sd[op.getarg(0).getint()] + s = jd_sd.warmstate.get_location_str(op.getarglist()[2:]) + s = s.replace(',', '.') # we use comma for argument splitting + return "debug_merge_point(%d, '%s')" % (op.getarg(1).getint(), s) if ops_offset is None: offset = -1 else: @@ -88,9 +113,10 @@ s_offset = "" else: s_offset = "+%d: " % offset - args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())]) + args = ", ".join([self.repr_of_arg(op.getarg(i)) for i in range(op.numargs())]) + if op.result is not None: - res = self.repr_of_arg(memo, op.result) + " = " + res = self.repr_of_arg(op.result) + " = " else: res = "" is_guard = op.is_guard() @@ -103,7 +129,7 @@ r = self.repr_of_descr(descr) args += ', descr=' + r if is_guard and op.getfailargs() is not None: - fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg) + fail_args = ' [' + ", ".join([self.repr_of_arg(arg) for arg in op.getfailargs()]) + ']' else: fail_args = '' @@ -114,13 +140,12 @@ return if ops_offset is None: ops_offset = {} - memo = {} if inputargs is not None: - args = ", ".join([self.repr_of_arg(memo, arg) for arg in inputargs]) + args = ", ".join([self.repr_of_arg(arg) for arg in inputargs]) debug_print('[' + args + ']') for i in range(len(operations)): op = operations[i] - debug_print(self.repr_of_resop(memo, operations[i], ops_offset)) + debug_print(self.repr_of_resop(operations[i], ops_offset)) if ops_offset and None in ops_offset: offset = ops_offset[None] debug_print("+%d: --end of the loop--" % offset) diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py --- a/pypy/jit/metainterp/optimize.py +++ b/pypy/jit/metainterp/optimize.py @@ -1,9 +1,20 @@ from pypy.rlib.debug import debug_start, debug_stop +from pypy.jit.metainterp.jitexc import JitException + +class InvalidLoop(JitException): + """Raised when the optimize*.py detect that the loop that + we are trying to build cannot possibly make sense as a + long-running loop (e.g. it cannot run 2 complete iterations).""" + +class RetraceLoop(JitException): + """ Raised when inlining a short preamble resulted in an + InvalidLoop. This means the optimized loop is too specialized + to be useful here, so we trace it again and produced a second + copy specialized in some different way. + """ # ____________________________________________________________ -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, optimize_bridge_1 - def optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): debug_start("jit-optimize") try: @@ -13,8 +24,9 @@ debug_stop("jit-optimize") def _optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): - cpu = metainterp_sd.cpu - metainterp_sd.logger_noopt.log_loop(loop.inputargs, loop.operations) + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 + loop.logops = metainterp_sd.logger_noopt.log_loop(loop.inputargs, + loop.operations) # XXX do we really still need a list? if old_loop_tokens: return old_loop_tokens[0] @@ -35,8 +47,9 @@ def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts, inline_short_preamble, retraced=False): - cpu = metainterp_sd.cpu - metainterp_sd.logger_noopt.log_loop(bridge.inputargs, bridge.operations) + from pypy.jit.metainterp.optimizeopt import optimize_bridge_1 + bridge.logops = metainterp_sd.logger_noopt.log_loop(bridge.inputargs, + bridge.operations) if old_loop_tokens: old_loop_token = old_loop_tokens[0] bridge.operations[-1].setdescr(old_loop_token) # patch jump target diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -15,22 +15,20 @@ ('virtualize', OptVirtualize), ('string', OptString), ('heap', OptHeap), - ('ffi', OptFfiCall), + ('ffi', None), ('unroll', None)] # no direct instantiation of unroll unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] +ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES - -def optimize_loop_1(metainterp_sd, loop, enable_opts, +def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): - """Optimize loop.operations to remove internal overheadish operations. - """ + config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: @@ -40,6 +38,11 @@ # FIXME: Workaround to disable string optimisation # during preamble but to keep it during the loop optimizations.append(o) + elif name == 'ffi' and config.translation.jit_ffi: + # we cannot put the class directly in the unrolling_iterable, + # because we do not want it to be seen at all (to avoid to + # introduce a dependency on libffi in case we do not need it) + optimizations.append(OptFfiCall()) if ('rewrite' not in enable_opts or 'virtualize' not in enable_opts or 'heap' not in enable_opts): @@ -48,6 +51,17 @@ if inline_short_preamble: optimizations = [OptInlineShortPreamble(retraced)] + optimizations + return optimizations, unroll + + +def optimize_loop_1(metainterp_sd, loop, enable_opts, + inline_short_preamble=True, retraced=False): + """Optimize loop.operations to remove internal overheadish operations. + """ + + optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, + inline_short_preamble, retraced) + if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -1,10 +1,13 @@ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.libffi import Func +from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization +from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind + class FuncInfo(object): @@ -12,14 +15,18 @@ restype = None descr = None prepare_op = None - force_token_op = None def __init__(self, funcval, cpu, prepare_op): self.funcval = funcval self.opargs = [] argtypes, restype = self._get_signature(funcval) - self.descr = cpu.calldescrof_dynamic(argtypes, restype) + try: + self.descr = cpu.calldescrof_dynamic(argtypes, restype) + except UnsupportedKind: + # e.g., I or U for long longs + self.descr = None self.prepare_op = prepare_op + self.delayed_ops = [] def _get_signature(self, funcval): """ @@ -64,37 +71,51 @@ class OptFfiCall(Optimization): - def __init__(self): + def setup(self): self.funcinfo = None + if self.optimizer.loop is not None: + self.logops = self.optimizer.loop.logops + else: + self.logops = None + + def propagate_begin_forward(self): + debug_start('jit-log-ffiopt') + Optimization.propagate_begin_forward(self) + + def propagate_end_forward(self): + debug_stop('jit-log-ffiopt') + Optimization.propagate_end_forward(self) def reconstruct_for_next_iteration(self, optimizer, valuemap): return OptFfiCall() # FIXME: Should any status be saved for next iteration? def begin_optimization(self, funcval, op): - self.rollback_maybe() + self.rollback_maybe('begin_optimization', op) self.funcinfo = FuncInfo(funcval, self.optimizer.cpu, op) def commit_optimization(self): self.funcinfo = None - def rollback_maybe(self): + def rollback_maybe(self, msg, op): if self.funcinfo is None: return # nothing to rollback # # we immediately set funcinfo to None to prevent recursion when # calling emit_op + if self.logops is not None: + debug_print('rollback: ' + msg + ': ', self.logops.repr_of_resop(op)) funcinfo = self.funcinfo self.funcinfo = None self.emit_operation(funcinfo.prepare_op) for op in funcinfo.opargs: self.emit_operation(op) - if funcinfo.force_token_op: - self.emit_operation(funcinfo.force_token_op) + for delayed_op in funcinfo.delayed_ops: + self.emit_operation(delayed_op) def emit_operation(self, op): # we cannot emit any operation during the optimization - self.rollback_maybe() + self.rollback_maybe('invalid op', op) Optimization.emit_operation(self, op) def optimize_CALL(self, op): @@ -135,13 +156,18 @@ # call_may_force and the setfield_gc, so the final result we get is # again force_token/setfield_gc/call_may_force. # + # However, note that nowadays we also allow to have any setfield_gc + # between libffi_prepare and libffi_call, so while the comment above + # it's a bit superfluous, it has been left there for future reference. if self.funcinfo is None: self.emit_operation(op) else: - self.funcinfo.force_token_op = op + self.funcinfo.delayed_ops.append(op) + + optimize_SETFIELD_GC = optimize_FORCE_TOKEN def do_prepare_call(self, op): - self.rollback_maybe() + self.rollback_maybe('prepare call', op) funcval = self._get_funcval(op) if not funcval.is_constant(): return [op] # cannot optimize @@ -165,23 +191,19 @@ for push_op in funcinfo.opargs: argval = self.getvalue(push_op.getarg(2)) arglist.append(argval.force_box()) - newop = ResOperation(rop.CALL_MAY_FORCE, arglist, op.result, + newop = ResOperation(rop.CALL_RELEASE_GIL, arglist, op.result, descr=funcinfo.descr) self.commit_optimization() ops = [] - if funcinfo.force_token_op: - ops.append(funcinfo.force_token_op) + for delayed_op in funcinfo.delayed_ops: + ops.append(delayed_op) ops.append(newop) return ops def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + if self.logops is not None: + debug_print(self.logops.repr_of_resop(op)) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -192,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -8,8 +8,8 @@ class CachedField(object): def __init__(self): - # Cache information for a field descr. It can be in one - # of two states: + # Cache information for a field descr, or for an (array descr, index) + # pair. It can be in one of two states: # # 1. 'cached_fields' is a dict mapping OptValues of structs # to OptValues of fields. All fields on-heap are @@ -27,19 +27,19 @@ self._lazy_setfield_registered = False def do_setfield(self, optheap, op): - # Update the state with the SETFIELD_GC operation 'op'. + # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) if self.possible_aliasing(optheap, structvalue): self.force_lazy_setfield(optheap) assert not self.possible_aliasing(optheap, structvalue) cached_fieldvalue = self._cached_fields.get(structvalue, None) if cached_fieldvalue is not fieldvalue: # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields list + # myself in the optheap's _lazy_setfields_and_arrayitems list self._lazy_setfield = op if not self._lazy_setfield_registered: - optheap._lazy_setfields.append(self) + optheap._lazy_setfields_and_arrayitems.append(self) self._lazy_setfield_registered = True else: # this is the case where the pending setfield ends up @@ -65,7 +65,7 @@ if self._lazy_setfield is not None: op = self._lazy_setfield assert optheap.getvalue(op.getarg(0)) is structvalue - return optheap.getvalue(op.getarg(1)) + return optheap.getvalue(op.getarglist()[-1]) else: return self._cached_fields.get(structvalue, None) @@ -87,7 +87,7 @@ # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) def get_reconstructed(self, optimizer, valuemap): @@ -100,25 +100,20 @@ return cf -class CachedArrayItems(object): - def __init__(self): - self.fixed_index_items = {} - self.var_index_item = None - self.var_index_indexvalue = None - class BogusPureField(JitException): pass class OptHeap(Optimization): """Cache repeated heap accesses""" - + def __init__(self): # cached fields: {descr: CachedField} self.cached_fields = {} - self._lazy_setfields = [] - # cached array items: {descr: CachedArrayItems} + # cached array items: {array descr: {index: CachedField}} self.cached_arrayitems = {} + # + self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -126,34 +121,23 @@ new = OptHeap() if True: - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() else: assert 0 # was: new.lazy_setfields = self.lazy_setfields - + for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) - new.cached_arrayitems = {} - for descr, d in self.cached_arrayitems.items(): - newd = {} - new.cached_arrayitems[descr] = newd - for value, cache in d.items(): - newcache = CachedArrayItems() - newd[value.get_reconstructed(optimizer, valuemap)] = newcache - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_reconstructed(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) - for index, fieldvalue in cache.fixed_index_items.items(): - newcache.fixed_index_items[index] = \ - fieldvalue.get_reconstructed(optimizer, valuemap) + for descr, submap in self.cached_arrayitems.items(): + newdict = {} + for index, d in submap.items(): + newdict[index] = d.get_reconstructed(optimizer, valuemap) + new.cached_arrayitems[descr] = newdict return new def clean_caches(self): - del self._lazy_setfields[:] + del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() self.cached_arrayitems.clear() @@ -164,50 +148,16 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): - d = self.cached_arrayitems.get(descr, None) - if d is None: - d = self.cached_arrayitems[descr] = {} - cache = d.get(value, None) - if cache is None: - cache = d[value] = CachedArrayItems() - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - index = indexbox.getint() - if write: - for value, othercache in d.iteritems(): - # fixed index, clean the variable index cache, in case the - # index is the same - othercache.var_index_indexvalue = None - othercache.var_index_item = None - try: - del othercache.fixed_index_items[index] - except KeyError: - pass - cache.fixed_index_items[index] = fieldvalue - else: - if write: - for value, othercache in d.iteritems(): - # variable index, clear all caches for this descr - othercache.var_index_indexvalue = None - othercache.var_index_item = None - othercache.fixed_index_items.clear() - cache.var_index_indexvalue = indexvalue - cache.var_index_item = fieldvalue - - def read_cached_arrayitem(self, descr, value, indexvalue): - d = self.cached_arrayitems.get(descr, None) - if d is None: - return None - cache = d.get(value, None) - if cache is None: - return None - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - return cache.fixed_index_items.get(indexbox.getint(), None) - elif cache.var_index_indexvalue is indexvalue: - return cache.var_index_item - return None + def arrayitem_cache(self, descr, index): + try: + submap = self.cached_arrayitems[descr] + except KeyError: + submap = self.cached_arrayitems[descr] = {} + try: + cf = submap[index] + except KeyError: + cf = submap[index] = CachedField() + return cf def emit_operation(self, op): self.emitting_operation(op) @@ -219,7 +169,8 @@ if op.is_ovf(): return if op.is_guard(): - self.optimizer.pendingfields = self.force_lazy_setfields_for_guard() + self.optimizer.pendingfields = ( + self.force_lazy_setfields_and_arrayitems_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -235,6 +186,7 @@ assert opnum != rop.CALL_PURE if (opnum == rop.CALL or opnum == rop.CALL_MAY_FORCE or + opnum == rop.CALL_RELEASE_GIL or opnum == rop.CALL_ASSEMBLER): if opnum == rop.CALL_ASSEMBLER: effectinfo = None @@ -242,11 +194,13 @@ effectinfo = op.getdescr().get_extra_info() if effectinfo is None or effectinfo.check_can_invalidate(): self._seen_guard_not_invalidated = False - if effectinfo is not None: + if effectinfo is not None and not effectinfo.has_random_effects(): # XXX we can get the wrong complexity here, if the lists # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: self.force_lazy_setfield(fielddescr) + for arraydescr in effectinfo.readonly_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: self.force_lazy_setfield(fielddescr) try: @@ -255,8 +209,11 @@ except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) try: - del self.cached_arrayitems[arraydescr] + submap = self.cached_arrayitems[arraydescr] + for cf in submap.itervalues(): + cf._cached_fields.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -265,7 +222,7 @@ # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. return - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() self.clean_caches() @@ -276,6 +233,10 @@ for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] + for submap in self.cached_arrayitems.itervalues(): + for cf in submap.itervalues(): + if value in cf._cached_fields: + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -284,6 +245,14 @@ return cf.force_lazy_setfield(self) + def force_lazy_setarrayitem(self, arraydescr): + try: + submap = self.cached_arrayitems[arraydescr] + except KeyError: + return + for cf in submap.values(): + cf.force_lazy_setfield(self) + def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes # sense to avoid a situation like "int_eq/setfield_gc/guard_true", @@ -308,30 +277,49 @@ newoperations[-2] = lastop newoperations[-1] = prevop - def force_all_lazy_setfields(self): - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + def _assert_valid_cf(self, cf): + # check that 'cf' is in cached_fields or cached_arrayitems + if not we_are_translated(): + if cf not in self.cached_fields.values(): + for submap in self.cached_arrayitems.values(): + if cf in submap.values(): + break + else: + assert 0, "'cf' not in cached_fields/cached_arrayitems" + + def force_all_lazy_setfields_and_arrayitems(self): + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) cf.force_lazy_setfield(self) - def force_lazy_setfields_for_guard(self): + def force_lazy_setfields_and_arrayitems_for_guard(self): pendingfields = [] - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) op = cf._lazy_setfield if op is None: continue # the only really interesting case that we need to handle in the # guards' resume data is that of a virtual object that is stored - # into a field of a non-virtual object. + # into a field of a non-virtual object. Here, 'op' in either + # SETFIELD_GC or SETARRAYITEM_GC. value = self.getvalue(op.getarg(0)) assert not value.is_virtual() # it must be a non-virtual - fieldvalue = self.getvalue(op.getarg(1)) + fieldvalue = self.getvalue(op.getarglist()[-1]) if fieldvalue.is_virtual(): # this is the case that we leave to resume.py + opnum = op.getopnum() + if opnum == rop.SETFIELD_GC: + itemindex = -1 + elif opnum == rop.SETARRAYITEM_GC: + indexvalue = self.getvalue(op.getarg(1)) + assert indexvalue.is_constant() + itemindex = indexvalue.box.getint() + assert itemindex >= 0 + else: + assert 0 pendingfields.append((op.getdescr(), value.box, - fieldvalue.get_key_box())) + fieldvalue.get_key_box(), itemindex)) else: cf.force_lazy_setfield(self) self.fixup_guard_situation() @@ -363,24 +351,45 @@ cf.do_setfield(self, op) def optimize_GETARRAYITEM_GC(self, op): - value = self.getvalue(op.getarg(0)) + arrayvalue = self.getvalue(op.getarg(0)) indexvalue = self.getvalue(op.getarg(1)) - fieldvalue = self.read_cached_arrayitem(op.getdescr(), value, indexvalue) - if fieldvalue is not None: - self.make_equal_to(op.result, fieldvalue) - return - ###self.optimizer.optimize_default(op) + cf = None + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + fieldvalue = cf.getfield_from_cache(self, arrayvalue) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # default case: produce the operation + arrayvalue.ensure_nonnull() self.emit_operation(op) - fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) + # the remember the result of reading the array item + if cf is not None: + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(arrayvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): - self.emit_operation(op) - value = self.getvalue(op.getarg(0)) - fieldvalue = self.getvalue(op.getarg(2)) + if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), + op.getarg(1)], + op.getdescr()): + os.write(2, '[bogus immutable array declaration: %s]\n' % + (op.getdescr().repr_of_descr())) + raise BogusPureField + # indexvalue = self.getvalue(op.getarg(1)) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - write=True) + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + cf.do_setfield(self, op) + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # and then emit the operation + self.emit_operation(op) def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) @@ -422,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeutil import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -17,6 +17,14 @@ assert self.posponedop is None return self + def setup(self): + self.posponedop = None + self.nextop = None + + def reconstruct_for_next_iteration(self, optimizer, valuemap): + assert self.posponedop is None + return self + def propagate_forward(self, op): if op.is_ovf(): self.posponedop = op @@ -26,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -49,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -186,7 +187,7 @@ # Synthesize the reverse ops for optimize_default to reuse self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0)) self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1)) - + def optimize_INT_MUL_OVF(self, op): v1 = self.getvalue(op.getarg(0)) @@ -284,6 +285,11 @@ v1.intbound.make_ge(IntLowerBound(0)) v1.intbound.make_lt(IntUpperBound(256)) + def optimize_UNICODEGETITEM(self, op): + self.emit_operation(op) + v1 = self.getvalue(op.result) + v1.intbound.make_ge(IntLowerBound(0)) + def make_int_lt(self, box1, box2): v1 = self.getvalue(box1) v2 = self.getvalue(box2) @@ -360,6 +366,27 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -405,5 +432,7 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') + +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,9 +4,9 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs -from pypy.jit.metainterp.optimizeutil import descrlist_dict -from pypy.jit.metainterp.optimizeutil import InvalidLoop, args_dict +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.rpython.lltypesystem import lltype @@ -141,6 +141,9 @@ # meaning it has been forced. return self.box is None + def is_forced_virtual(self): + return False + def getfield(self, ofs, default): raise NotImplementedError @@ -175,6 +178,14 @@ def __init__(self): pass # make rpython happy + def propagate_begin_forward(self): + if self.next_optimization: + self.next_optimization.propagate_begin_forward() + + def propagate_end_forward(self): + if self.next_optimization: + self.next_optimization.propagate_end_forward() + def propagate_forward(self, op): raise NotImplementedError @@ -406,11 +417,13 @@ # ^^^ at least at the start of bridges. For loops, we could set # it to False, but we probably don't care self.newoperations = [] + self.first_optimization.propagate_begin_forward() self.i = 0 while self.i < len(self.loop.operations): op = self.loop.operations[self.i] self.first_optimization.propagate_forward(op) self.i += 1 + self.first_optimization.propagate_end_forward() self.loop.operations = self.newoperations self.loop.quasi_immutable_deps = self.quasi_immutable_deps # accumulate counters @@ -421,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -556,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -184,6 +179,32 @@ else: self.emit_operation(op) + def optimize_FLOAT_MUL(self, op): + arg1 = op.getarg(0) + arg2 = op.getarg(1) + + # Constant fold f0 * 1.0 and turn f0 * -1.0 into a FLOAT_NEG, these + # work in all cases, including NaN and inf + for lhs, rhs in [(arg1, arg2), (arg2, arg1)]: + v1 = self.getvalue(lhs) + v2 = self.getvalue(rhs) + + if v1.is_constant(): + if v1.box.getfloat() == 1.0: + self.make_equal_to(op.result, v2) + return + elif v1.box.getfloat() == -1.0: + self.emit_operation(ResOperation( + rop.FLOAT_NEG, [rhs], op.result + )) + return + self.emit_operation(op) + + def optimize_FLOAT_NEG(self, op): + v1 = op.getarg(0) + self.emit_operation(op) + self.pure(rop.FLOAT_NEG, [op.result], v1) + def optimize_CALL_PURE(self, op): arg_consts = [] for i in range(op.numargs()): @@ -193,7 +214,7 @@ break arg_consts.append(const) else: - # all constant arguments: check if we already know the reslut + # all constant arguments: check if we already know the result try: result = self.optimizer.call_pure_results[arg_consts] except KeyError: @@ -451,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/__init__.py b/pypy/jit/metainterp/optimizeopt/test/__init__.py new file mode 100644 diff --git a/pypy/jit/metainterp/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py rename from pypy/jit/metainterp/test/test_optimizebasic.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1,37 +1,15 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, FakeMetaInterpStaticData) +from pypy.jit.metainterp.test.test_compile import FakeLogger import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt -from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation -from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.optimizeutil import args_dict - -##class FakeFrame(object): -## parent_resumedata_snapshot = None -## parent_resumedata_frame_info_list = None - -## def __init__(self, code="", pc=0): -## self.jitcode = code -## self.pc = pc - -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() + def test_store_final_boxes_in_guard(): from pypy.jit.metainterp.compile import ResumeGuardDescr @@ -101,7 +79,7 @@ assert vinfo3 is vinfo4 def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil + from pypy.jit.metainterp.optimizeopt import util as optimizeutil h1 = optimizeutil.descrlist_hash([]) h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) h3 = optimizeutil.descrlist_hash( @@ -130,159 +108,55 @@ # ____________________________________________________________ -def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}, - text_right=None): - # try to use the full width of the terminal to display the list - # unfortunately, does not work with the default capture method of py.test - # (which is fd), you you need to use either -s or --capture=sys, else you - # get the standard 80 columns width - totwidth = py.io.get_terminal_width() - width = totwidth / 2 - 1 - print ' Comparing lists '.center(totwidth, '-') - text_right = text_right or 'expected' - print '%s| %s' % ('optimized'.center(width), text_right.center(width)) - for op1, op2 in zip(oplist1, oplist2): - txt1 = str(op1) - txt2 = str(op2) - while txt1 or txt2: - print '%s| %s' % (txt1[:width].ljust(width), txt2[:width]) - txt1 = txt1[width:] - txt2 = txt2[width:] - assert op1.getopnum() == op2.getopnum() - assert op1.numargs() == op2.numargs() - for i in range(op1.numargs()): - x = op1.getarg(i) - y = op2.getarg(i) - assert x == remap.get(y, y) - if op2.result in remap: - assert op1.result == remap[op2.result] - else: - remap[op2.result] = op1.result - if op1.getopnum() != rop.JUMP: # xxx obscure - assert op1.getdescr() == op2.getdescr() - if op1.getfailargs() or op2.getfailargs(): - assert len(op1.getfailargs()) == len(op2.getfailargs()) - if strict_fail_args: - for x, y in zip(op1.getfailargs(), op2.getfailargs()): - assert x == remap.get(y, y) - else: - fail_args1 = set(op1.getfailargs()) - fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()]) - assert fail_args1 == fail_args2 - assert len(oplist1) == len(oplist2) - print '-'*totwidth - return True - -def test_equaloplists(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops, namespace=namespace) - loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), - namespace=namespace) - assert equaloplists(loop1.operations, loop2.operations) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -def test_equaloplists_fail_args(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2, i1] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop2.operations)") - assert equaloplists(loop1.operations, loop2.operations, - strict_fail_args=False) - loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -# ____________________________________________________________ - -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) class BaseTestBasic(BaseTest): - def invent_fail_descr(self, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap) + enable_opts = "intbounds:rewrite:virtualize:string:heap" def optimize_loop(self, ops, optops, call_pure_results=None): + loop = self.parse(ops) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v - metainterp_sd = FakeMetaInterpStaticData(self.cpu) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - # - # XXX list the exact optimizations that are needed for each test - from pypy.jit.metainterp.optimizeopt import (OptIntBounds, - OptRewrite, - OptVirtualize, - OptString, - OptHeap, - Optimizer) - from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall - - optimizations = [OptIntBounds(), - OptRewrite(), - OptVirtualize(), - OptString(), - OptHeap(), - OptFfiCall(), - ] - optimizer = Optimizer(metainterp_sd, loop, optimizations) - optimizer.propagate_all_forward() - # expected = self.parse(optops) + self._do_optimize_loop(loop, call_pure_results) print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + + class BaseTestOptimizeBasic(BaseTestBasic): @@ -565,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] @@ -1231,8 +1122,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1597,9 +1488,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) jump(p1, i1, i2, p3) """ @@ -1773,6 +1664,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2035,7 +1927,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2053,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2071,7 +1961,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2287,25 +2176,83 @@ """ self.optimize_loop(ops, expected) + def test_fold_constant_partial_ops_float(self): + ops = """ + [f0] + f1 = float_mul(f0, 1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + + ops = """ + [f0] + f1 = float_mul(f0, -1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(-1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + def test_fold_repeated_float_neg(self): + ops = """ + [f0] + f1 = float_neg(f0) + f2 = float_neg(f1) + f3 = float_neg(f2) + f4 = float_neg(f3) + escape(f4) + jump(f4) + """ + expected = """ + [f0] + # The backend removes this dead op. + f1 = float_neg(f0) + escape(f0) + jump(f0) + """ + self.optimize_loop(ops, expected) + # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2414,7 +2361,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2435,7 +2381,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2455,7 +2400,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2481,7 +2425,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2506,7 +2450,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2530,7 +2473,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2551,7 +2493,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2572,7 +2513,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2594,7 +2534,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2636,7 +2575,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2662,7 +2600,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2686,9 +2623,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2980,7 +2914,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3026,7 +2959,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3065,7 +2997,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3092,7 +3023,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -3986,11 +3916,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4011,9 +3938,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4032,10 +3957,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -4057,14 +3981,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -4080,10 +3999,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4201,16 +4118,13 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -4249,11 +4163,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4445,11 +4356,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -4566,6 +4474,66 @@ # not obvious, because of the exception UnicodeDecodeError that # can be raised by ll_str2unicode() + def test_strgetitem_repeated(self): + ops = """ + [p0, i0] + i1 = strgetitem(p0, i0) + i2 = strgetitem(p0, i0) + i3 = int_eq(i1, i2) + guard_true(i3) [] + escape(i2) + jump(p0, i0) + """ + expected = """ + [p0, i0] + i1 = strgetitem(p0, i0) + escape(i1) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + def test_strslice_with_other_stuff(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py rename from pypy/jit/metainterp/test/test_optimizefficall.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py --- a/pypy/jit/metainterp/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py @@ -2,8 +2,8 @@ from pypy.rlib.libffi import Func, types from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.metainterp.test.test_optimizebasic import BaseTestBasic -from pypy.jit.metainterp.test.test_optimizebasic import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import BaseTestBasic +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import LLtypeMixin class MyCallDescr(AbstractDescr): """ @@ -32,12 +32,15 @@ class TestFfiCall(BaseTestBasic, LLtypeMixin): - jit_ffi = True + + enable_opts = "intbounds:rewrite:virtualize:string:heap:ffi" class namespace: cpu = LLtypeMixin.cpu FUNC = LLtypeMixin.FUNC vable_token_descr = LLtypeMixin.valuedescr + valuedescr = LLtypeMixin.valuedescr + int_float__int = MyCallDescr('if', 'i') funcptr = FakeLLObject() func = FakeLLObject(_fake_class=Func, @@ -48,7 +51,7 @@ restype=types.sint) # def calldescr(cpu, FUNC, oopspecindex, extraeffect=None): - einfo = EffectInfo([], [], [], oopspecindex=oopspecindex, + einfo = EffectInfo([], [], [], [], oopspecindex=oopspecindex, extraeffect=extraeffect) return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo) # @@ -76,7 +79,7 @@ """ expected = """ [i0, f1] - i3 = call_may_force(12345, i0, f1, descr=int_float__int) + i3 = call_release_gil(12345, i0, f1, descr=int_float__int) guard_not_forced() [] guard_no_exception() [] jump(i3, f1) @@ -99,7 +102,7 @@ def test_handle_virtualizables(self): # this test needs an explanation to understand what goes on: see the - # coment in optimize_FORCE_TOKEN + # comment in optimize_FORCE_TOKEN ops = """ [i0, f1, p2] call(0, ConstPtr(func), descr=libffi_prepare) @@ -116,7 +119,7 @@ [i0, f1, p2] i4 = force_token() setfield_gc(p2, i4, descr=vable_token_descr) - i3 = call_may_force(12345, i0, f1, descr=int_float__int) + i3 = call_release_gil(12345, i0, f1, descr=int_float__int) guard_not_forced() [p2] guard_no_exception() [p2] jump(i3, f1, p2) @@ -213,7 +216,7 @@ call(0, ConstPtr(func), descr=libffi_prepare) # # this "nested" call is nicely optimized - i4 = call_may_force(67890, i0, f1, descr=int_float__int) + i4 = call_release_gil(67890, i0, f1, descr=int_float__int) guard_not_forced() [] guard_no_exception() [] # @@ -242,3 +245,25 @@ """ expected = ops loop = self.optimize_loop(ops, expected) + + def test_allow_setfields_in_between(self): + ops = """ + [i0, f1, p2] + call(0, ConstPtr(func), descr=libffi_prepare) + call(0, ConstPtr(func), i0, descr=libffi_push_arg) + call(0, ConstPtr(func), f1, descr=libffi_push_arg) + setfield_gc(p2, i0, descr=valuedescr) + i3 = call_may_force(0, ConstPtr(func), 12345, descr=libffi_call) + guard_not_forced() [] + guard_no_exception() [] + jump(i3, f1, p2) + """ + expected = """ + [i0, f1, p2] + setfield_gc(p2, i0, descr=valuedescr) + i3 = call_release_gil(12345, i0, f1, descr=int_float__int) + guard_not_forced() [] + guard_no_exception() [] + jump(i3, f1, p2) + """ + loop = self.optimize_loop(ops, expected) diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py rename from pypy/jit/metainterp/test/test_optimizeopt.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1,202 +1,88 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, Storage, _sortboxes) import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT, build_opt_chain +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.test.test_optimizebasic import equaloplists -from pypy.jit.metainterp.optimizeutil import args_dict - -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu, jit_ffi=False): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() - self.jit_ffi = jit_ffi - -def test_store_final_boxes_in_guard(): - from pypy.jit.metainterp.compile import ResumeGuardDescr - from pypy.jit.metainterp.resume import tag, TAGBOX - b0 = BoxInt() - b1 = BoxInt() - opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu), - None) - fdescr = ResumeGuardDescr() - op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr) - # setup rd data - fi0 = resume.FrameInfo(None, "code0", 11) - fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33) - snapshot0 = resume.Snapshot(None, [b0]) - fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1]) +from pypy.jit.metainterp.optimizeopt.util import args_dict +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import FakeMetaInterpStaticData +from pypy.config.pypyoption import get_pypy_config + + +def test_build_opt_chain(): + def check(chain, expected_names): + names = [opt.__class__.__name__ for opt in chain] + assert names == expected_names # - opt.store_final_boxes_in_guard(op) - if op.getfailargs() == [b0, b1]: - assert list(fdescr.rd_numb.nums) == [tag(1, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)] - else: - assert op.getfailargs() == [b1, b0] - assert list(fdescr.rd_numb.nums) == [tag(0, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(1, TAGBOX)] - assert fdescr.rd_virtuals is None - assert fdescr.rd_consts == [] - -def test_sharing_field_lists_of_virtual(): - class FakeOptimizer(object): - class cpu(object): - pass - opt = FakeOptimizer() - virt1 = virtualize.AbstractVirtualStructValue(opt, None) - lst1 = virt1._get_field_descr_list() - assert lst1 == [] - lst2 = virt1._get_field_descr_list() - assert lst1 is lst2 - virt1.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst3 = virt1._get_field_descr_list() - assert lst3 == [LLtypeMixin.valuedescr] - lst4 = virt1._get_field_descr_list() - assert lst3 is lst4 - - virt2 = virtualize.AbstractVirtualStructValue(opt, None) - lst5 = virt2._get_field_descr_list() - assert lst5 is lst1 - virt2.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst6 = virt1._get_field_descr_list() - assert lst6 is lst3 - -def test_reuse_vinfo(): - class FakeVInfo(object): - def set_content(self, fieldnums): - self.fieldnums = fieldnums - def equals(self, fieldnums): - return self.fieldnums == fieldnums - class FakeVirtualValue(virtualize.AbstractVirtualValue): - def _make_virtual(self, *args): - return FakeVInfo() - v1 = FakeVirtualValue(None, None, None) - vinfo1 = v1.make_virtual_info(None, [1, 2, 4]) - vinfo2 = v1.make_virtual_info(None, [1, 2, 4]) - assert vinfo1 is vinfo2 - vinfo3 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is not vinfo2 - vinfo4 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is vinfo4 - -def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil - h1 = optimizeutil.descrlist_hash([]) - h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) - h3 = optimizeutil.descrlist_hash( - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert h1 != h2 - assert h2 != h3 - assert optimizeutil.descrlist_eq([], []) - assert not optimizeutil.descrlist_eq([], [LLtypeMixin.valuedescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.nextdescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr, LLtypeMixin.nextdescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.nextdescr, LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - - # descrlist_eq should compare by identity of the descrs, not by the result - # of sort_key - class FakeDescr(object): - def sort_key(self): - return 1 - - assert not optimizeutil.descrlist_eq([FakeDescr()], [FakeDescr()]) + metainterp_sd = FakeMetaInterpStaticData(None) + chain, _ = build_opt_chain(metainterp_sd, "", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "heap:intbounds") + check(chain, ["OptInlineShortPreamble", "OptIntBounds", "OptHeap", "OptSimplify"]) + # + chain, unroll = build_opt_chain(metainterp_sd, "unroll") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + assert unroll + # + chain, _ = build_opt_chain(metainterp_sd, "aaa:bbb", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptFfiCall", "OptSimplify"]) + # + metainterp_sd.config = get_pypy_config(translating=True) + assert not metainterp_sd.config.translation.jit_ffi + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # ____________________________________________________________ -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure + + +class FakeDescr(compile.ResumeGuardDescr): + class rd_snapshot: + class prev: + prev = None + boxes = [] + boxes = [] def clone_if_mutable(self): - res = Storage(self.metainterp_sd, self.original_greenkey) - self.copy_all_attributes_into(res) - return res - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) - -class BaseTestOptimizeOpt(BaseTest): - jit_ffi = False - - def invent_fail_descr(self, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected, text_right=None): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap, text_right) - - def optimize_loop(self, ops, optops, expected_preamble=None, + return self + + +class BaseTestWithUnroll(BaseTest): + + enable_opts = "intbounds:rewrite:virtualize:string:heap:unroll" + + def optimize_loop(self, ops, expected, expected_preamble=None, call_pure_results=None): loop = self.parse(ops) - if optops != "crash!": - expected = self.parse(optops) - else: - expected = "crash!" + if expected != "crash!": + expected = self.parse(expected) if expected_preamble: expected_preamble = self.parse(expected_preamble) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v + loop.preamble = TreeLoop('preamble') loop.preamble.inputargs = loop.inputargs loop.preamble.token = LoopToken() - metainterp_sd = FakeMetaInterpStaticData(self.cpu, self.jit_ffi) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - class FakeDescr(compile.ResumeGuardDescr): - class rd_snapshot: - class prev: - prev = None - boxes = [] - boxes = [] - def clone_if_mutable(self): - return self loop.preamble.start_resumedescr = FakeDescr() - optimize_loop_1(metainterp_sd, loop, ALL_OPTS_DICT) # - + self._do_optimize_loop(loop, call_pure_results) + # print print loop.preamble.inputargs print '\n'.join([str(o) for o in loop.preamble.operations]) @@ -204,16 +90,14 @@ print loop.inputargs print '\n'.join([str(o) for o in loop.operations]) print - assert expected != "crash!", "should have raised an exception" self.assert_equal(loop, expected) if expected_preamble: self.assert_equal(loop.preamble, expected_preamble, text_right='expected preamble') - return loop -class OptimizeOptTest(BaseTestOptimizeOpt): +class OptimizeOptTest(BaseTestWithUnroll): def setup_method(self, meth=None): class FailDescr(compile.ResumeGuardDescr): @@ -1497,8 +1381,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1922,9 +1806,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -1934,9 +1818,9 @@ # i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -2171,6 +2055,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2857,8 +2742,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -5199,11 +5082,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5224,9 +5104,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5245,10 +5123,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5270,14 +5147,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -5293,10 +5165,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5420,14 +5290,12 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) - def test_strgetitem_small(self): + def test_strgetitem_bounds(self): ops = """ [p0, i0] i1 = strgetitem(p0, i0) @@ -5439,7 +5307,20 @@ """ expected = """ [p0, i0] - i1 = strgetitem(p0, i0) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_unicodegetitem_bounds(self): + ops = """ + [p0, i0] + i1 = unicodegetitem(p0, i0) + i2 = int_lt(i1, 0) + guard_false(i2) [] + jump(p0, i0) + """ + expected = """ + [p0, i0] jump(p0, i0) """ self.optimize_loop(ops, expected) @@ -5477,7 +5358,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -5516,11 +5396,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5714,11 +5591,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -5953,3 +5827,54 @@ jump(i3, i4) """ self.optimize_loop(ops, expected) + + def test_forced_virtual_pure_getfield(self): + ops = """ + [p0] + p1 = getfield_gc_pure(p0, descr=valuedescr) + jump(p1) + """ + self.optimize_loop(ops, ops) + + ops = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + p2 = getfield_gc_pure(p1, descr=valuedescr) + escape(p2) + jump(p0) + """ + expected = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + escape(p0) + jump(p0) + """ + self.optimize_loop(ops, expected) + + def test_setarrayitem_lazy(self): + ops = """ + [i0, i1] + p0 = escape() + i2 = escape() + p1 = new_with_vtable(ConstClass(node_vtable)) + setarrayitem_gc(p0, 2, p1, descr=arraydescr) + guard_true(i2) [] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + expected = """ + [i0, i1] + p0 = escape() + i2 = escape() + guard_true(i2) [p0] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py rename from pypy/jit/metainterp/test/test_optimizeutil.py rename to pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/test/test_optimizeutil.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -9,11 +9,15 @@ from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, Const, TreeLoop, BoxObj, ConstObj, AbstractDescr) -from pypy.jit.metainterp.optimizeutil import sort_descrs, InvalidLoop +from pypy.jit.metainterp.optimizeopt.util import sort_descrs, equaloplists +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter.heaptracker import register_known_gctype, adr2int -from pypy.jit.tool.oparser import parse +from pypy.jit.tool.oparser import parse, pure_parse from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr +from pypy.jit.metainterp import compile, resume, history +from pypy.jit.metainterp.jitprof import EmptyProfiler +from pypy.config.pypyoption import get_pypy_config def test_sort_descrs(): class PseudoDescr(AbstractDescr): @@ -28,6 +32,44 @@ sort_descrs(lst2) assert lst2 == lst +def test_equaloplists(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops, namespace=namespace) + loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), + namespace=namespace) + assert equaloplists(loop1.operations, loop2.operations) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + +def test_equaloplists_fail_args(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2, i1] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop2.operations)") + assert equaloplists(loop1.operations, loop2.operations, + strict_fail_args=False) + loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + # ____________________________________________________________ class LLtypeMixin(object): @@ -124,19 +166,19 @@ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [])) + EffectInfo([], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [])) + EffectInfo([], [], [adescr], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [arraydescr])) + EffectInfo([], [], [adescr], [arraydescr])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([adescr], [], [])) + EffectInfo([adescr], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([nextdescr], [], [], + EffectInfo([nextdescr], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), @@ -153,15 +195,15 @@ _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): @@ -256,8 +298,45 @@ ## u_vtable_adr: cpu.typedescrof(U)} ## namespace = locals() +# ____________________________________________________________ + + + +class Fake(object): + failargs_limit = 1000 + storedebug = None + + +class FakeMetaInterpStaticData(object): + + def __init__(self, cpu): + self.cpu = cpu + self.profiler = EmptyProfiler() + self.options = Fake() + self.globaldata = Fake() + self.config = get_pypy_config(translating=True) + self.config.translation.jit_ffi = True + + +class Storage(compile.ResumeGuardDescr): + "for tests." + def __init__(self, metainterp_sd=None, original_greenkey=None): + self.metainterp_sd = metainterp_sd + self.original_greenkey = original_greenkey + def store_final_boxes(self, op, boxes): + op.setfailargs(boxes) + def __eq__(self, other): + return type(self) is type(other) # xxx obscure + def clone_if_mutable(self): + res = Storage(self.metainterp_sd, self.original_greenkey) + self.copy_all_attributes_into(res) + return res + +def _sortboxes(boxes): + _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} + return sorted(boxes, key=lambda box: _kind2count[box.type]) + class BaseTest(object): - invent_fail_descr = None def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, @@ -265,5 +344,40 @@ boxkinds=boxkinds, invent_fail_descr=self.invent_fail_descr) + def invent_fail_descr(self, model, fail_args): + if fail_args is None: + return None + descr = Storage() + descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) + descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) + return descr + + def assert_equal(self, optimized, expected, text_right=None): + from pypy.jit.metainterp.optimizeopt.util import equaloplists + assert len(optimized.inputargs) == len(expected.inputargs) + remap = {} + for box1, box2 in zip(optimized.inputargs, expected.inputargs): + assert box1.__class__ == box2.__class__ + remap[box2] = box1 + assert equaloplists(optimized.operations, + expected.operations, False, remap, text_right) + + def _do_optimize_loop(self, loop, call_pure_results): + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 + from pypy.jit.metainterp.optimizeopt.util import args_dict + + self.loop = loop + loop.call_pure_results = args_dict() + if call_pure_results is not None: + for k, v in call_pure_results.items(): + loop.call_pure_results[list(k)] = v + metainterp_sd = FakeMetaInterpStaticData(self.cpu) + if hasattr(self, 'vrefinfo'): + metainterp_sd.virtualref_info = self.vrefinfo + if hasattr(self, 'callinfocollection'): + metainterp_sd.callinfocollection = self.callinfocollection + # + optimize_loop_1(metainterp_sd, loop, self.enable_opts) + # ____________________________________________________________ diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -5,7 +5,7 @@ from pypy.jit.metainterp.resume import Snapshot from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop, RetraceLoop +from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.history import make_hashable_int from pypy.jit.codewriter.effectinfo import EffectInfo @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jitdriver_sd, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -914,13 +919,12 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jitdriver_sd, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation loc = jitdriver_sd.warmstate.get_location_str(greenkey) debug_print(loc) - constloc = self.metainterp.cpu.ts.conststr(loc) - self.metainterp.history.record(rop.DEBUG_MERGE_POINT, - [constloc, ConstInt(in_recursion)], None) + args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey + self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @arguments("box", "label") def opimpl_goto_if_exception_mismatch(self, vtablebox, next_exc_target): @@ -1234,7 +1238,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: @@ -1265,8 +1269,7 @@ logger_ops = None def __init__(self, cpu, options, - ProfilerClass=EmptyProfiler, warmrunnerdesc=None, - jit_ffi=True): + ProfilerClass=EmptyProfiler, warmrunnerdesc=None): self.cpu = cpu self.stats = self.cpu.stats self.options = options @@ -1276,7 +1279,11 @@ self.profiler = ProfilerClass() self.profiler.cpu = cpu self.warmrunnerdesc = warmrunnerdesc - self.jit_ffi = jit_ffi + if warmrunnerdesc: + self.config = warmrunnerdesc.translator.config + else: + from pypy.config.pypyoption import get_pypy_config + self.config = get_pypy_config(translating=True) backendmodule = self.cpu.__module__ backendmodule = backendmodule.split('.')[-2] @@ -1447,6 +1454,8 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1787,6 +1796,8 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) @@ -1927,7 +1938,6 @@ self.history.inputargs = original_inputargs self.history.operations.pop() # remove the JUMP - # FIXME: Why is self.history.inputargs not restored? def compile_bridge(self, live_arg_boxes): num_green_args = self.jitdriver_sd.num_green_args @@ -1963,6 +1973,8 @@ start_resumedescr, False) self.history.operations.pop() # remove the JUMP if loop_token is None: + self.history.inputargs = original_inputargs + self.history.operations = original_operations return if loop_token.short_preamble: @@ -2117,7 +2129,6 @@ def vrefs_after_residual_call(self): vrefinfo = self.staticdata.virtualref_info for i in range(0, len(self.virtualref_boxes), 2): - virtualbox = self.virtualref_boxes[i] vrefbox = self.virtualref_boxes[i+1] vref = vrefbox.getref_base() if vrefinfo.tracing_after_residual_call(vref): diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -191,9 +191,15 @@ # of the operation. It must inherit from AbstractDescr. The # backend provides it with cpu.fielddescrof(), cpu.arraydescrof(), # cpu.calldescrof(), and cpu.typedescrof(). + self._check_descr(descr) + self._descr = descr + + def _check_descr(self, descr): + if not we_are_translated() and getattr(descr, 'I_am_a_descr', False): + return # needed for the mock case in oparser_model from pypy.jit.metainterp.history import check_descr check_descr(descr) - self._descr = descr + class GuardResOp(ResOpWithDescr): @@ -468,8 +474,9 @@ 'STRSETITEM/3', 'UNICODESETITEM/3', #'RUNTIMENEW/1', # ootype operation - 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier) - 'DEBUG_MERGE_POINT/2', # debugging only + 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier) + 'COND_CALL_GC_WB_ARRAY/3d', # [objptr, arrayindex, newvalue] (write barr.) + 'DEBUG_MERGE_POINT/*', # debugging only 'JIT_DEBUG/*', # debugging only 'VIRTUAL_REF_FINISH/2', # removed before it's passed to the backend 'COPYSTRCONTENT/5', # src, dst, srcstart, dststart, length @@ -482,6 +489,7 @@ 'CALL_ASSEMBLER/*d', # call already compiled assembler 'CALL_MAY_FORCE/*d', 'CALL_LOOPINVARIANT/*d', + 'CALL_RELEASE_GIL/*d', # release the GIL and "close the stack" for asmgcc #'OOSEND', # ootype operation #'OOSEND_PURE', # ootype operation 'CALL_PURE/*d', # removed before it's passed to the backend diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -2,15 +2,17 @@ from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr +from pypy.rpython import annlowlevel from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop # Logic to encode the chain of frames and the state of the boxes at a # guard operation, and to decode it again. This is a bit advanced, @@ -82,6 +84,13 @@ ('nums', lltype.Array(rffi.SHORT))) NUMBERINGP.TO.become(NUMBERING) +PENDINGFIELDSTRUCT = lltype.Struct('PendingField', + ('lldescr', annlowlevel.base_ptr_lltype()), + ('num', rffi.SHORT), + ('fieldnum', rffi.SHORT), + ('itemindex', rffi.INT)) +PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) + TAGMASK = 3 def tag(value, tagbits): @@ -329,7 +338,7 @@ value = values[box] value.get_args_for_fail(self) - for _, box, fieldbox in pending_setfields: + for _, box, fieldbox, _ in pending_setfields: self.register_box(box) self.register_box(fieldbox) value = values[fieldbox] @@ -405,13 +414,25 @@ return False def _add_pending_fields(self, pending_setfields): - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) if pending_setfields: - rd_pendingfields = [] - for descr, box, fieldbox in pending_setfields: + n = len(pending_setfields) + rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) + for i in range(n): + descr, box, fieldbox, itemindex = pending_setfields[i] + lldescr = annlowlevel.cast_instance_to_base_ptr(descr) num = self._gettagged(box) fieldnum = self._gettagged(fieldbox) - rd_pendingfields.append((descr, num, fieldnum)) + # the index is limited to 2147483647 (64-bit machines only) + if itemindex > 2147483647: + from pypy.jit.metainterp import compile + compile.giveup() + itemindex = rffi.cast(rffi.INT, itemindex) + # + rd_pendingfields[i].lldescr = lldescr + rd_pendingfields[i].num = num + rd_pendingfields[i].fieldnum = fieldnum + rd_pendingfields[i].itemindex= itemindex self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): @@ -727,10 +748,28 @@ self.virtuals_cache = [self.virtual_default] * len(virtuals) def _prepare_pendingfields(self, pendingfields): - if pendingfields is not None: - for descr, num, fieldnum in pendingfields: + if pendingfields: + for i in range(len(pendingfields)): + lldescr = pendingfields[i].lldescr + num = pendingfields[i].num + fieldnum = pendingfields[i].fieldnum + itemindex= pendingfields[i].itemindex + descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, + lldescr) struct = self.decode_ref(num) - self.setfield(descr, struct, fieldnum) + itemindex = rffi.cast(lltype.Signed, itemindex) + if itemindex < 0: + self.setfield(descr, struct, fieldnum) + else: + self.setarrayitem(descr, struct, itemindex, fieldnum) + + def setarrayitem(self, arraydescr, array, index, fieldnum): + if arraydescr.is_array_of_pointers(): + self.setarrayitem_ref(arraydescr, array, index, fieldnum) + elif arraydescr.is_array_of_floats(): + self.setarrayitem_float(arraydescr, array, index, fieldnum) + else: + self.setarrayitem_int(arraydescr, array, index, fieldnum) def _prepare_next_section(self, info): # Use info.enumerate_vars(), normally dispatching to @@ -903,15 +942,15 @@ structbox, fieldbox) def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, INT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT) def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, REF) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF) def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) - def setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): + def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): itembox = self.decode_box(fieldnum, kind) self.metainterp.execute_and_record(rop.SETARRAYITEM_GC, arraydescr, arraybox, diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -15,14 +15,14 @@ supports_longlong=False, **kwds): from pypy.jit.codewriter import support - class FakeJitCell: + class FakeJitCell(object): __compiled_merge_points = [] def get_compiled_merge_points(self): return self.__compiled_merge_points[:] def set_compiled_merge_points(self, lst): self.__compiled_merge_points = lst - class FakeWarmRunnerState: + class FakeWarmRunnerState(object): def attach_unoptimized_bridge_from_interp(self, greenkey, newloop): pass @@ -30,6 +30,9 @@ from pypy.rpython.annlowlevel import llhelper return llhelper(FUNCPTR, func) + def get_location_str(self, args): + return 'location' + def jit_cell_at_key(self, greenkey): assert greenkey == [] return self._cell diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -500,7 +500,7 @@ y -= x return y # - res = self.meta_interp(f, [3, 6], repeat=7) + res = self.meta_interp(f, [3, 6], repeat=7, function_threshold=0) assert res == 6 - 4 - 5 self.check_history(call=0) # because the trace starts in the middle # @@ -984,11 +984,14 @@ pass class B(A): pass + @dont_look_inside + def extern(n): + if n: + return A() + else: + return B() def fn(n): - if n: - obj = A() - else: - obj = B() + obj = extern(n) return isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res @@ -1021,6 +1024,70 @@ res = self.meta_interp(main, []) assert res == 55 + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass @@ -1252,7 +1319,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1379,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1410,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1444,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1563,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1598,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1662,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1676,7 +1743,9 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) + py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) def test_multiple_specialied_versions_bridge(self): @@ -1815,7 +1884,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2000,7 +2069,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2045,7 +2114,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2080,7 +2149,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2137,7 +2206,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2206,7 +2275,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2230,6 +2300,148 @@ self.check_loops(getfield_gc_pure=0) self.check_loops(getfield_gc_pure=2, everywhere=True) + def test_frame_finished_during_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 1 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 1000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'a']) + def f(): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 2) + a = A(0) + sa = 0 + while a.val < 8: + myjitdriver.jit_merge_point(a=a, sa=sa) + a = a.inc() + if a.val > 4: + a = B(a.val) + sa += a.num + return sa + res = self.meta_interp(f, []) + assert res == f() + + def test_frame_finished_during_continued_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 100 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 10000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'b', 'a']) + def f(b): + myjitdriver.set_param('threshold', 6) + myjitdriver.set_param('trace_eagerness', 4) + a = A(0) + sa = 0 + while a.val < 15: + myjitdriver.jit_merge_point(a=a, b=b, sa=sa) + a = a.inc() + if a.val > 8: + a = B(a.val) + if b == 1: + b = 2 + else: + b = 1 + sa += a.num + b + return sa + res = self.meta_interp(f, [1]) + assert res == f(1) + + def test_remove_array_operations(self): + myjitdriver = JitDriver(greens = [], reds = ['a']) + class W_Int: + def __init__(self, intvalue): + self.intvalue = intvalue + def f(x): + a = [W_Int(x)] + while a[0].intvalue > 0: + myjitdriver.jit_merge_point(a=a) + a[0] = W_Int(a[0].intvalue - 3) + return a[0].intvalue + res = self.meta_interp(f, [100]) + assert res == -2 + #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + + def test_retrace_ending_up_retrazing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py --- a/pypy/jit/metainterp/test/test_compile.py +++ b/pypy/jit/metainterp/test/test_compile.py @@ -1,3 +1,4 @@ +from pypy.config.pypyoption import get_pypy_config from pypy.jit.metainterp.history import LoopToken, ConstInt, History, Stats from pypy.jit.metainterp.history import BoxInt, INT from pypy.jit.metainterp.compile import insert_loop_token, compile_new_loop @@ -5,7 +6,7 @@ from pypy.jit.metainterp.compile import ResumeGuardCountersInt from pypy.jit.metainterp.compile import compile_tmp_callback from pypy.jit.metainterp import jitprof, typesystem, compile -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.tool.oparser import parse from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT @@ -30,13 +31,16 @@ ts = typesystem.llhelper def __init__(self): self.seen = [] - def compile_loop(self, inputargs, operations, token): + def compile_loop(self, inputargs, operations, token, name=''): self.seen.append((inputargs, operations, token)) class FakeLogger(object): def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): pass + def repr_of_resop(self, op): + return repr(op) + class FakeState(object): enable_opts = ALL_OPTS_DICT.copy() enable_opts.pop('unroll') @@ -44,6 +48,9 @@ def attach_unoptimized_bridge_from_interp(*args): pass + def get_location_str(self, args): + return 'location' + class FakeGlobalData(object): loopnumbering = 0 @@ -51,11 +58,11 @@ logger_noopt = FakeLogger() logger_ops = FakeLogger() + config = get_pypy_config(translating=True) stats = Stats() profiler = jitprof.EmptyProfiler() warmrunnerdesc = None - jit_ffi = False def log(self, msg, event_kind=None): pass @@ -63,6 +70,8 @@ call_pure_results = {} class jitdriver_sd: warmstate = FakeState() + on_compile = staticmethod(lambda *args: None) + on_compile_bridge = staticmethod(lambda *args: None) def test_compile_new_loop(): cpu = FakeCPU() diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -130,6 +130,38 @@ assert res == 50 self.check_loops(int_mod=1) + def test_repeated_lookup(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'd']) + class Wrapper(object): + _immutable_fields_ = ["value"] + def __init__(self, value): + self.value = value + def eq_func(a, b): + return a.value == b.value + def hash_func(x): + return objectmodel.compute_hash(x.value) + + def f(n): + d = None + while n > 0: + myjitdriver.jit_merge_point(n=n, d=d) + d = objectmodel.r_dict(eq_func, hash_func) + y = Wrapper(str(n)) + d[y] = n - 1 + n = d[y] + return d[Wrapper(str(n + 1))] + + res = self.meta_interp(f, [100], listops=True) + assert res == f(50) + # XXX: ideally there would be 7 calls here, but repeated CALL_PURE with + # the same arguments are not folded, because we have conflicting + # definitions of pure, once strhash can be appropriately folded + # this should be decreased to seven. + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + "guard_true": 1, "int_and": 1, "int_gt": 1, + "int_is_true": 1, "int_sub": 1, "jump": 1, + "new_with_vtable": 1, "setfield_gc": 1}) + class TestOOtype(DictTests, OOJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,28 +1,46 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.libffi import ArgChain +from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong +from pypy.rlib.libffi import IS_32_BIT from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall from pypy.rpython.lltypesystem import lltype, rffi +from pypy.rlib.objectmodel import specialize +from pypy.tool.sourcetools import func_with_new_name from pypy.jit.metainterp.test.support import LLJitMixin - class TestFfiCall(LLJitMixin, _TestLibffiCall): # ===> ../../../rlib/test/test_libffi.py - def call(self, funcspec, args, RESULT, init_result=0): + def call(self, funcspec, args, RESULT, init_result=0, is_struct=False): """ Call the function specified by funcspec in a loop, and let the jit to see and optimize it. """ # lib, name, argtypes, restype = funcspec - args = unrolling_iterable(args) + method_and_args = [] + for argval in args: + if type(argval) is r_singlefloat: + method_name = 'arg_singlefloat' + argval = float(argval) + elif IS_32_BIT and type(argval) in [r_longlong, r_ulonglong]: + method_name = 'arg_longlong' + argval = rffi.cast(rffi.LONGLONG, argval) + argval = longlong2float(argval) + elif isinstance(argval, tuple): + method_name, argval = argval + else: + method_name = 'arg' + method_and_args.append((method_name, argval)) + method_and_args = unrolling_iterable(method_and_args) # reds = ['n', 'res', 'func'] - if type(init_result) is float: + if (RESULT in [rffi.FLOAT, rffi.DOUBLE] or + IS_32_BIT and RESULT in [rffi.LONGLONG, rffi.ULONGLONG]): reds = ['n', 'func', 'res'] # floats must be *after* refs driver = JitDriver(reds=reds, greens=[]) # @@ -31,15 +49,19 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() - for argval in args: # this loop is unrolled - argchain.arg(argval) - res = func.call(argchain, RESULT) + # this loop is unrolled + for method_name, argval in method_and_args: + getattr(argchain, method_name)(argval) + res = func.call(argchain, RESULT, is_struct=is_struct) n += 1 return res # - res = self.meta_interp(f, [0]) + res = self.meta_interp(f, [0], backendopt=True) return res + def test_byval_result(self): + _TestLibffiCall.test_byval_result(self) + test_byval_result.__doc__ = _TestLibffiCall.test_byval_result.__doc__ + test_byval_result.dont_track_allocations = True diff --git a/pypy/jit/metainterp/test/test_history.py b/pypy/jit/metainterp/test/test_history.py --- a/pypy/jit/metainterp/test/test_history.py +++ b/pypy/jit/metainterp/test/test_history.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.history import * -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi def test_repr(): @@ -10,6 +10,18 @@ const = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)) assert const._getrepr_() == "*T" +def test_repr_ll2ctypes(): + ptr = lltype.malloc(rffi.VOIDPP.TO, 10, flavor='raw') + # force it to be a ll2ctypes object + ptr = rffi.cast(rffi.VOIDPP, rffi.cast(rffi.LONG, ptr)) + adr = llmemory.cast_ptr_to_adr(ptr) + lltype.free(ptr, flavor='raw') + intval = llmemory.cast_adr_to_int(adr, 'symbolic') + box = BoxInt(intval) + s = box.repr_rpython() + assert s.startswith('12345/') # the arbitrary hash value used by + # make_hashable_int + def test_same_constant(): c1a = ConstInt(0) c1b = ConstInt(0) diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py --- a/pypy/jit/metainterp/test/test_jitdriver.py +++ b/pypy/jit/metainterp/test/test_jitdriver.py @@ -113,6 +113,7 @@ return n # def loop2(g, r): + myjitdriver1.set_param('function_threshold', 0) while r > 0: myjitdriver2.can_enter_jit(g=g, r=r) myjitdriver2.jit_merge_point(g=g, r=r) diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -49,7 +49,7 @@ x = l[n] l = [3] * 100 l[3] = x - l[3] = x + 1 + l[4] = x + 1 n -= 1 return l[0] diff --git a/pypy/jit/metainterp/test/test_logger.py b/pypy/jit/metainterp/test/test_logger.py --- a/pypy/jit/metainterp/test/test_logger.py +++ b/pypy/jit/metainterp/test/test_logger.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp import logger from pypy.jit.metainterp.typesystem import llhelper from StringIO import StringIO -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.metainterp.history import AbstractDescr, LoopToken, BasicFailDescr from pypy.jit.backend.model import AbstractCPU @@ -36,19 +36,29 @@ return capturing(logger.Logger.log_loop, self, loop.inputargs, loop.operations, ops_offset=ops_offset) - def repr_of_descr(self, descr): - for k, v in self.namespace.items(): - if v == descr: - return k - return descr.repr_of_descr() + def _make_log_operations(self1): + class LogOperations(logger.LogOperations): + def repr_of_descr(self, descr): + for k, v in self1.namespace.items(): + if v == descr: + return k + return descr.repr_of_descr() + logops = LogOperations(self1.metainterp_sd, self1.guard_number) + self1.logops = logops + return logops class TestLogger(object): ts = llhelper def make_metainterp_sd(self): + class FakeJitDriver(object): + class warmstate(object): + get_location_str = staticmethod(lambda args: "dupa") + class FakeMetaInterpSd: cpu = AbstractCPU() cpu.ts = self.ts + jitdrivers_sd = [FakeJitDriver()] def get_name_from_address(self, addr): return 'Name' return FakeMetaInterpSd() @@ -66,7 +76,7 @@ if check_equal: equaloplists(loop.operations, oloop.operations) assert oloop.inputargs == loop.inputargs - return loop, oloop + return logger, loop, oloop def test_simple(self): inp = ''' @@ -106,18 +116,18 @@ def test_debug_merge_point(self): inp = ''' [] - debug_merge_point("info", 0) + debug_merge_point(0, 0) ''' - loop, oloop = self.reparse(inp, check_equal=False) - assert loop.operations[0].getarg(0)._get_str() == 'info' - assert oloop.operations[0].getarg(0)._get_str() == 'info' + _, loop, oloop = self.reparse(inp, check_equal=False) + assert loop.operations[0].getarg(1).getint() == 0 + assert oloop.operations[0].getarg(1)._get_str() == "dupa" def test_floats(self): inp = ''' [f0] f1 = float_add(3.5, f0) ''' - loop, oloop = self.reparse(inp) + _, loop, oloop = self.reparse(inp) equaloplists(loop.operations, oloop.operations) def test_jump(self): @@ -179,6 +189,17 @@ assert output.splitlines()[0] == "# bridge out of Guard 3 with 0 ops" pure_parse(output) + def test_repr_single_op(self): + inp = ''' + [i0, i1, i2, p3, p4, p5] + i6 = int_add(i1, i2) + i8 = int_add(i6, 3) + jump(i0, i8, i6, p3, p4, p5) + ''' + logger, loop, _ = self.reparse(inp) + op = loop.operations[1] + assert logger.logops.repr_of_resop(op) == "i8 = int_add(i6, 3)" + def test_ops_offset(self): inp = ''' [i0] diff --git a/pypy/jit/metainterp/test/test_pyjitpl.py b/pypy/jit/metainterp/test/test_pyjitpl.py --- a/pypy/jit/metainterp/test/test_pyjitpl.py +++ b/pypy/jit/metainterp/test/test_pyjitpl.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.history import BoxInt, ConstInt from pypy.jit.metainterp.history import History from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.codewriter.jitcode import JitCode diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -483,6 +483,7 @@ def main(inline): myjitdriver.set_param("threshold", 10) + myjitdriver.set_param('function_threshold', 60) if inline: myjitdriver.set_param('inlining', True) else: @@ -925,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 @@ -1193,6 +1194,51 @@ i -= 1 self.meta_interp(portal, [0, 10], inline=True) + def test_trace_from_start_always(self): + from pypy.rlib.nonconst import NonConstant + + driver = JitDriver(greens = ['c'], reds = ['i', 'v']) + + def portal(c, i, v): + while i > 0: + driver.jit_merge_point(c=c, i=i, v=v) + portal(c, i - 1, v) + if v: + driver.can_enter_jit(c=c, i=i, v=v) + break + + def main(c, i, set_param, v): + if set_param: + driver.set_param('function_threshold', 0) + portal(c, i, v) + + self.meta_interp(main, [10, 10, False, False], inline=True) + self.check_tree_loop_count(1) + self.check_loop_count(0) + self.meta_interp(main, [3, 10, True, False], inline=True) + self.check_tree_loop_count(0) + self.check_loop_count(0) + + def test_trace_from_start_does_not_prevent_inlining(self): + driver = JitDriver(greens = ['c', 'bc'], reds = ['i']) + + def portal(bc, c, i): + while True: + driver.jit_merge_point(c=c, bc=bc, i=i) + if bc == 0: + portal(1, 8, 0) + c += 1 + else: + return + if c == 10: # bc == 0 + c = 0 + if i >= 100: + return + driver.can_enter_jit(c=c, bc=bc, i=i) + i += 1 + + self.meta_interp(portal, [0, 0, 0], inline=True) + self.check_loops(call=0, call_may_force=0) class TestLLtype(RecursiveTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py --- a/pypy/jit/metainterp/test/test_resume.py +++ b/pypy/jit/metainterp/test/test_resume.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.resume import * from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt from pypy.jit.metainterp.history import ConstPtr, ConstFloat -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.metainterp import executor from pypy.jit.codewriter import heaptracker, longlong @@ -1238,7 +1238,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, values, 0) assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)]) + modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s, -1)]) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume @@ -1259,6 +1259,106 @@ assert len(expected) == len(trace) assert demo55.next == demo66 +def test_virtual_adder_pending_fields_and_arrayitems(): + class Storage(object): + pass + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier._add_pending_fields([]) + assert not storage.rd_pendingfields + # + class FieldDescr(object): + pass + field_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061)} + modifier._add_pending_fields([(field_a, 42, 61, -1)]) + pf = storage.rd_pendingfields + assert len(pf) == 1 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is field_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + # + array_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061), + 62: rffi.cast(rffi.SHORT, 1062), + 63: rffi.cast(rffi.SHORT, 1063)} + modifier._add_pending_fields([(array_a, 42, 61, 0), + (array_a, 42, 62, 2147483647)]) + pf = storage.rd_pendingfields + assert len(pf) == 2 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[1].num) == 1042 + assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 + assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + # + from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole + py.test.raises(SwitchToBlackhole, modifier._add_pending_fields, + [(array_a, 42, 63, 2147483648)]) + +def test_resume_reader_fields_and_arrayitems(): + class ResumeReader(AbstractResumeDataReader): + def __init__(self, got=None, got_array=None): + self.got = got + self.got_array = got_array + def setfield(self, descr, struct, fieldnum): + assert lltype.typeOf(struct) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got.append((descr, struct, fieldnum)) + def setarrayitem(self, arraydescr, array, index, fieldnum): + assert lltype.typeOf(array) is lltype.Signed + assert lltype.typeOf(index) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got_array.append((arraydescr, array, index, fieldnum)) + def decode_ref(self, num): + return rffi.cast(lltype.Signed, num) * 100 + got = [] + pf = lltype.nullptr(PENDINGFIELDSP.TO) + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [] + # + class FieldDescr(AbstractDescr): + pass + field_a = FieldDescr() + field_b = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 2) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) + pf[0].itemindex = rffi.cast(rffi.INT, -1) + pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) + pf[1].num = rffi.cast(rffi.SHORT, 2042) + pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) + pf[1].itemindex = rffi.cast(rffi.INT, -1) + got = [] + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] + # + array_a = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 1) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) + pf[0].itemindex = rffi.cast(rffi.INT, 123) + got_array = [] + ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + assert got_array == [(array_a, 104200, 123, 1063)] + def test_invalidation_needed(): class options: diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,13 +5,13 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor from pypy.jit.metainterp.warmspot import get_stats, get_translator from pypy.jit.metainterp import history -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin def promote_virtualizable(*args): pass @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py --- a/pypy/jit/metainterp/test/test_warmspot.py +++ b/pypy/jit/metainterp/test/test_warmspot.py @@ -80,7 +80,7 @@ self.meta_interp(f, [123, 10]) assert len(get_stats().locations) >= 4 for loc in get_stats().locations: - assert loc == 'GREEN IS 123.' + assert loc == (0, 123) def test_set_param_enable_opts(self): from pypy.rpython.annlowlevel import llstr, hlstr diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -181,6 +181,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = None @@ -207,6 +208,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = llhelper(GET_LOCATION, get_location) _confirm_enter_jit_ptr = None @@ -230,6 +232,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = llhelper(ENTER_JIT, confirm_enter_jit) @@ -253,6 +256,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = None diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py --- a/pypy/jit/metainterp/virtualref.py +++ b/pypy/jit/metainterp/virtualref.py @@ -1,5 +1,5 @@ from pypy.rpython.rmodel import inputconst, log -from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass +from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.jit.metainterp import history from pypy.jit.codewriter import heaptracker from pypy.rlib.jit import InvalidVirtualRef diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -1,6 +1,5 @@ import sys, py -from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr -from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.annlowlevel import llhelper, MixLevelHelperAnnotator,\ cast_base_ptr_to_instance, hlstr from pypy.annotation import model as annmodel @@ -10,16 +9,12 @@ from pypy.objspace.flow.model import checkgraph, Link, copygraph from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import r_uint, intmask -from pypy.rlib.debug import debug_print, fatalerror -from pypy.rlib.debug import debug_start, debug_stop -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.translator.simplify import get_funcobj, get_functype +from pypy.rlib.debug import fatalerror +from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function from pypy.jit.metainterp import history, pyjitpl, gc, memmgr -from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp -from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper +from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.jitdriver import JitDriverStaticData @@ -66,6 +61,7 @@ def jittify_and_run(interp, graph, args, repeat=1, backendopt=False, trace_limit=sys.maxint, inline=False, loop_longevity=0, retrace_limit=5, + function_threshold=4, enable_opts=ALL_OPTS_NAMES, **kwds): from pypy.config.config import ConfigError translator = interp.typer.annotator.translator @@ -77,9 +73,14 @@ translator.config.translation.list_comprehension_operations = True except ConfigError: pass + try: + translator.config.translation.jit_ffi = True + except ConfigError: + pass warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds) for jd in warmrunnerdesc.jitdrivers_sd: jd.warmstate.set_param_threshold(3) # for tests + jd.warmstate.set_param_function_threshold(function_threshold) jd.warmstate.set_param_trace_eagerness(2) # for tests jd.warmstate.set_param_trace_limit(trace_limit) jd.warmstate.set_param_inlining(inline) @@ -291,9 +292,6 @@ self.stats = stats if translate_support_code: self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper) - annhelper = self.annhelper - else: - annhelper = None cpu = CPUClass(self.translator.rtyper, self.stats, self.opt, translate_support_code, gcdescr=self.gcdescr) self.cpu = cpu @@ -422,7 +420,7 @@ if self.translator.rtyper.type_system.name == 'lltypesystem': def maybe_enter_jit(*args): try: - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) except JitException: raise # go through except Exception, e: @@ -430,15 +428,12 @@ maybe_enter_jit._always_inline_ = True else: def maybe_enter_jit(*args): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) maybe_enter_jit._always_inline_ = True jd._maybe_enter_jit_fn = maybe_enter_jit - can_inline = state.can_inline_greenargs - num_green_args = jd.num_green_args def maybe_enter_from_start(*args): - if not can_inline(*args[:num_green_args]): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_function_threshold, *args) maybe_enter_from_start._always_inline_ = True jd._maybe_enter_from_start_fn = maybe_enter_from_start @@ -549,7 +544,6 @@ self.rewrite_can_enter_jit(jd, sublist) def rewrite_can_enter_jit(self, jd, can_enter_jits): - FUNC = jd._JIT_ENTER_FUNCTYPE FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -1,7 +1,7 @@ import sys, weakref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi from pypy.rpython.ootypesystem import ootype -from pypy.rpython.annlowlevel import hlstr, llstr, cast_base_ptr_to_instance +from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance from pypy.rpython.annlowlevel import cast_object_to_ptr from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict from pypy.rlib.rarithmetic import intmask @@ -208,15 +208,20 @@ meth = getattr(self, 'set_param_' + name) meth(default_value) - def set_param_threshold(self, threshold): + def _compute_threshold(self, threshold): if threshold <= 0: - self.increment_threshold = 0 # never reach the THRESHOLD_LIMIT - return + return 0 # never reach the THRESHOLD_LIMIT if threshold < 2: threshold = 2 - self.increment_threshold = (self.THRESHOLD_LIMIT // threshold) + 1 + return (self.THRESHOLD_LIMIT // threshold) + 1 # the number is at least 1, and at most about half THRESHOLD_LIMIT + def set_param_threshold(self, threshold): + self.increment_threshold = self._compute_threshold(threshold) + + def set_param_function_threshold(self, threshold): + self.increment_function_threshold = self._compute_threshold(threshold) + def set_param_trace_eagerness(self, value): self.trace_eagerness = value @@ -232,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: @@ -291,7 +296,7 @@ self.make_jitdriver_callbacks() confirm_enter_jit = self.confirm_enter_jit - def maybe_compile_and_run(*args): + def maybe_compile_and_run(threshold, *args): """Entry point to the JIT. Called at the point with the can_enter_jit() hint. """ @@ -307,7 +312,7 @@ if cell.counter >= 0: # update the profiling counter - n = cell.counter + self.increment_threshold + n = cell.counter + threshold if n <= self.THRESHOLD_LIMIT: # bound not reached cell.counter = n return @@ -497,7 +502,6 @@ if hasattr(self, 'set_future_values'): return self.set_future_values - warmrunnerdesc = self.warmrunnerdesc jitdriver_sd = self.jitdriver_sd cpu = self.cpu vinfo = jitdriver_sd.virtualizable_info @@ -513,7 +517,6 @@ # if vinfo is not None: i0 = len(jitdriver_sd._red_args_types) - num_green_args = jitdriver_sd.num_green_args index_of_virtualizable = jitdriver_sd.index_of_virtualizable vable_static_fields = unrolling_iterable( zip(vinfo.static_extra_types, vinfo.static_fields)) @@ -599,12 +602,8 @@ get_location_ptr = self.jitdriver_sd._get_printable_location_ptr if get_location_ptr is None: missing = '(no jitdriver.get_printable_location!)' - missingll = llstr(missing) def get_location_str(greenkey): - if we_are_translated(): - return missingll - else: - return missing + return missing else: rtyper = self.warmrunnerdesc.rtyper unwrap_greenkey = self.make_unwrap_greenkey() @@ -612,10 +611,10 @@ def get_location_str(greenkey): greenargs = unwrap_greenkey(greenkey) fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr) - res = fn(*greenargs) - if not we_are_translated() and not isinstance(res, str): - res = hlstr(res) - return res + llres = fn(*greenargs) + if not we_are_translated() and isinstance(llres, str): + return llres + return hlstr(llres) self.get_location_str = get_location_str # confirm_enter_jit_ptr = self.jitdriver_sd._confirm_enter_jit_ptr diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py --- a/pypy/jit/tl/pypyjit.py +++ b/pypy/jit/tl/pypyjit.py @@ -30,6 +30,7 @@ BACKEND = 'c' config = get_pypy_config(translating=True) +config.translation.backendopt.inline_threshold = 0.1 config.translation.gc = 'boehm' config.objspace.nofaking = True config.translating = True diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -3,24 +3,15 @@ in a nicer fashion """ -from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat,\ - LoopToken, get_const_ptr_for_string, get_const_ptr_for_unicode +from pypy.jit.tool.oparser_model import get_model + from pypy.jit.metainterp.resoperation import rop, ResOperation, \ ResOpWithDescr, N_aryOp, \ UnaryOp, PlainResOp -from pypy.jit.metainterp.typesystem import llhelper -from pypy.jit.codewriter.heaptracker import adr2int -from pypy.jit.codewriter import longlong -from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.rpython.ootypesystem import ootype class ParseError(Exception): pass -class Boxes(object): - pass - class ESCAPE_OP(N_aryOp, ResOpWithDescr): OPNUM = -123 @@ -54,37 +45,15 @@ def clone(self): return FORCE_SPILL(self.OPNUM, self.getarglist()[:]) -class ExtendedTreeLoop(TreeLoop): - def getboxes(self): - def opboxes(operations): - for op in operations: - yield op.result - for box in op.getarglist(): - yield box - def allboxes(): - for box in self.inputargs: - yield box - for box in opboxes(self.operations): - yield box - - boxes = Boxes() - for box in allboxes(): - if isinstance(box, Box): - name = str(box) - setattr(boxes, name, box) - return boxes - - def setvalues(self, **kwds): - boxes = self.getboxes() - for name, value in kwds.iteritems(): - getattr(boxes, name).value = value - -def default_fail_descr(fail_args=None): - return BasicFailDescr() +def default_fail_descr(model, fail_args=None): + return model.BasicFailDescr() class OpParser(object): + + use_mock_model = False + def __init__(self, input, cpu, namespace, type_system, boxkinds, invent_fail_descr=default_fail_descr, nonstrict=False): @@ -100,7 +69,8 @@ self._cache = {} self.invent_fail_descr = invent_fail_descr self.nonstrict = nonstrict - self.looptoken = LoopToken() + self.model = get_model(self.use_mock_model) + self.looptoken = self.model.LoopToken() def get_const(self, name, typ): if self._consts is None: @@ -108,16 +78,16 @@ obj = self._consts[name] if self.type_system == 'lltype': if typ == 'ptr': - return ConstPtr(obj) + return self.model.ConstPtr(obj) else: assert typ == 'class' - return ConstInt(adr2int(llmemory.cast_ptr_to_adr(obj))) + return self.model.ConstInt(self.model.ptr_to_int(obj)) else: if typ == 'ptr': - return ConstObj(obj) + return self.model.ConstObj(obj) else: assert typ == 'class' - return ConstObj(ootype.cast_to_object(obj)) + return self.model.ConstObj(ootype.cast_to_object(obj)) def get_descr(self, poss_descr): if poss_descr.startswith('<'): @@ -132,16 +102,16 @@ pass if elem.startswith('i'): # integer - box = BoxInt() - _box_counter_more_than(elem[1:]) + box = self.model.BoxInt() + _box_counter_more_than(self.model, elem[1:]) elif elem.startswith('f'): - box = BoxFloat() - _box_counter_more_than(elem[1:]) + box = self.model.BoxFloat() + _box_counter_more_than(self.model, elem[1:]) elif elem.startswith('p'): # pointer - ts = getattr(self.cpu, 'ts', llhelper) + ts = getattr(self.cpu, 'ts', self.model.llhelper) box = ts.BoxRef() - _box_counter_more_than(elem[1:]) + _box_counter_more_than(self.model, elem[1:]) else: for prefix, boxclass in self.boxkinds.iteritems(): if elem.startswith(prefix): @@ -175,21 +145,21 @@ def getvar(self, arg): if not arg: - return ConstInt(0) + return self.model.ConstInt(0) try: - return ConstInt(int(arg)) + return self.model.ConstInt(int(arg)) except ValueError: if self.is_float(arg): - return ConstFloat(longlong.getfloatstorage(float(arg))) + return self.model.ConstFloat(self.model.convert_to_floatstorage(arg)) if (arg.startswith('"') or arg.startswith("'") or arg.startswith('s"')): # XXX ootype info = arg[1:].strip("'\"") - return get_const_ptr_for_string(info) + return self.model.get_const_ptr_for_string(info) if arg.startswith('u"'): # XXX ootype info = arg[1:].strip("'\"") - return get_const_ptr_for_unicode(info) + return self.model.get_const_ptr_for_unicode(info) if arg.startswith('ConstClass('): name = arg[len('ConstClass('):-1] return self.get_const(name, 'class') @@ -197,9 +167,9 @@ return None elif arg == 'NULL': if self.type_system == 'lltype': - return ConstPtr(ConstPtr.value) + return self.model.ConstPtr(self.model.ConstPtr.value) else: - return ConstObj(ConstObj.value) + return self.model.ConstObj(self.model.ConstObj.value) elif arg.startswith('ConstPtr('): name = arg[len('ConstPtr('):-1] return self.get_const(name, 'ptr') @@ -211,11 +181,8 @@ args = [] descr = None if argspec.strip(): - if opname == 'debug_merge_point': - allargs = argspec.rsplit(', ', 1) - else: - allargs = [arg for arg in argspec.split(",") - if arg != ''] + allargs = [arg for arg in argspec.split(",") + if arg != ''] poss_descr = allargs[-1].strip() if poss_descr.startswith('descr='): @@ -266,14 +233,14 @@ "Unknown var in fail_args: %s" % arg) fail_args.append(fail_arg) if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr(fail_args) + descr = self.invent_fail_descr(self.model, fail_args) if hasattr(descr, '_oparser_uses_descr_of_guard'): descr._oparser_uses_descr_of_guard(self, fail_args) else: fail_args = None if opnum == rop.FINISH: if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr() + descr = self.invent_fail_descr(self.model) elif opnum == rop.JUMP: if descr is None and self.invent_fail_descr: descr = self.looptoken @@ -338,7 +305,7 @@ num, ops, last_offset = self.parse_ops(base_indent, newlines, 0) if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) - loop = ExtendedTreeLoop("loop") + loop = self.model.ExtendedTreeLoop("loop") loop.comment = first_comment loop.token = self.looptoken loop.operations = ops @@ -370,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" @@ -394,7 +366,7 @@ def parse(input, cpu=None, namespace=None, type_system='lltype', boxkinds=None, invent_fail_descr=default_fail_descr, - no_namespace=False, nonstrict=False): + no_namespace=False, nonstrict=False, OpParser=OpParser): if namespace is None and not no_namespace: namespace = {} return OpParser(input, cpu, namespace, type_system, boxkinds, @@ -405,6 +377,6 @@ return parse(*args, **kwds) -def _box_counter_more_than(s): +def _box_counter_more_than(model, s): if s.isdigit(): - Box._counter = max(Box._counter, int(s)+1) + model.Box._counter = max(model.Box._counter, int(s)+1) diff --git a/pypy/jit/tool/oparser_model.py b/pypy/jit/tool/oparser_model.py new file mode 100644 --- /dev/null +++ b/pypy/jit/tool/oparser_model.py @@ -0,0 +1,148 @@ +class Boxes(object): + pass + +def get_real_model(): + class LoopModel(object): + from pypy.jit.metainterp.history import TreeLoop, LoopToken + from pypy.jit.metainterp.history import Box, BoxInt, BoxFloat + from pypy.jit.metainterp.history import ConstInt, ConstObj, ConstPtr, ConstFloat + from pypy.jit.metainterp.history import BasicFailDescr + from pypy.jit.metainterp.typesystem import llhelper + + from pypy.jit.metainterp.history import get_const_ptr_for_string + from pypy.jit.metainterp.history import get_const_ptr_for_unicode + get_const_ptr_for_string = staticmethod(get_const_ptr_for_string) + get_const_ptr_for_unicode = staticmethod(get_const_ptr_for_unicode) + + @staticmethod + def convert_to_floatstorage(arg): + from pypy.jit.codewriter import longlong + return longlong.getfloatstorage(float(arg)) + + @staticmethod + def ptr_to_int(obj): + from pypy.jit.codewriter.heaptracker import adr2int + from pypy.rpython.lltypesystem import llmemory + return adr2int(llmemory.cast_ptr_to_adr(obj)) + + @staticmethod + def ootype_cast_to_object(obj): + from pypy.rpython.ootypesystem import ootype + return ootype.cast_to_object(obj) + + return LoopModel + +def get_mock_model(): + class LoopModel(object): + + class TreeLoop(object): + def __init__(self, name): + self.name = name + + class LoopToken(object): + I_am_a_descr = True + + class BasicFailDescr(object): + I_am_a_descr = True + + class Box(object): + _counter = 0 + type = 'b' + + def __init__(self, value=0): + self.value = value + + def __repr__(self): + result = str(self) + result += '(%s)' % self.value + return result + + def __str__(self): + if not hasattr(self, '_str'): + self._str = '%s%d' % (self.type, Box._counter) + Box._counter += 1 + return self._str + + class BoxInt(Box): + type = 'i' + + class BoxFloat(Box): + type = 'f' + + class BoxRef(Box): + type = 'p' + + class Const(object): + def __init__(self, value=None): + self.value = value + + def _get_str(self): + return str(self.value) + + class ConstInt(Const): + pass + + class ConstPtr(Const): + pass + + class ConstFloat(Const): + pass + + @classmethod + def get_const_ptr_for_string(cls, s): + return cls.ConstPtr(s) + + @classmethod + def get_const_ptr_for_unicode(cls, s): + return cls.ConstPtr(s) + + @staticmethod + def convert_to_floatstorage(arg): + return float(arg) + + @staticmethod + def ptr_to_int(obj): + return id(obj) + + class llhelper(object): + pass + + LoopModel.llhelper.BoxRef = LoopModel.BoxRef + + return LoopModel + + +def get_model(use_mock): + if use_mock: + model = get_mock_model() + else: + model = get_real_model() + + class ExtendedTreeLoop(model.TreeLoop): + + def getboxes(self): + def opboxes(operations): + for op in operations: + yield op.result + for box in op.getarglist(): + yield box + def allboxes(): + for box in self.inputargs: + yield box + for box in opboxes(self.operations): + yield box + + boxes = Boxes() + for box in allboxes(): + if isinstance(box, model.Box): + name = str(box) + setattr(boxes, name, box) + return boxes + + def setvalues(self, **kwds): + boxes = self.getboxes() + for name, value in kwds.iteritems(): + getattr(boxes, name).value = value + + model.ExtendedTreeLoop = ExtendedTreeLoop + return model diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -8,10 +8,16 @@ (defun set-truncate-lines () (setq truncate-lines t)) +;; to generate the list of keywords: +;; from pypy.jit.metainterp import resoperation +;; print ' '.join(sorted('"%s"' % op.lower() for op in resoperation.opname.values() if not op.startswith('GUARD'))) + + + (define-generic-mode 'pypytrace-mode ;; name of the mode to create nil - '("jump" "finish" "int_add" "int_sub" "int_mul" "int_floordiv" "uint_floordiv" "int_mod" "int_and" "int_or" "int_xor" "int_rshift" "int_lshift" "uint_rshift" "float_add" "float_sub" "float_mul" "float_truediv" "float_neg" "float_abs" "cast_float_to_int" "cast_int_to_float" "int_lt" "int_le" "int_eq" "int_ne" "int_gt" "int_ge" "uint_lt" "uint_le" "uint_gt" "uint_ge" "float_lt" "float_le" "float_eq" "float_ne" "float_gt" "float_ge" "int_is_zero" "int_is_true" "int_neg" "int_invert" "same_as" "ptr_eq" "ptr_ne" "arraylen_gc" "strlen" "strgetitem" "getfield_gc_pure" "getfield_raw_pure" "getarrayitem_gc_pure" "unicodelen" "unicodegetitem" "getarrayitem_gc" "getarrayitem_raw" "getfield_gc" "getfield_raw" "new" "new_with_vtable" "new_array" "force_token" "virtual_ref" "setarrayitem_gc" "setarrayitem_raw" "setfield_gc" "setfield_raw" "arraycopy" "newstr" "strsetitem" "unicodesetitem" "newunicode" "cond_call_gc_wb" "virtual_ref_finish" "call" "call_assembler" "call_may_force" "call_loopinvariant" "call_pure" "int_add_ovf" "int_sub_ovf" "int_mul_ovf") ;; keywords + '("arraylen_gc" "call" "call_assembler" "call_loopinvariant" "call_may_force" "call_pure" "call_release_gil" "cast_float_to_int" "cast_int_to_float" "cond_call_gc_wb" "copystrcontent" "copyunicodecontent" "debug_merge_point" "finish" "float_abs" "float_add" "float_eq" "float_ge" "float_gt" "float_le" "float_lt" "float_mul" "float_ne" "float_neg" "float_sub" "float_truediv" "force_token" "getarrayitem_gc" "getarrayitem_gc_pure" "getarrayitem_raw" "getfield_gc" "getfield_gc_pure" "getfield_raw" "getfield_raw_pure" "int_add" "int_add_ovf" "int_and" "int_eq" "int_floordiv" "int_ge" "int_gt" "int_invert" "int_is_true" "int_is_zero" "int_le" "int_lshift" "int_lt" "int_mod" "int_mul" "int_mul_ovf" "int_ne" "int_neg" "int_or" "int_rshift" "int_sub" "int_sub_ovf" "int_xor" "jit_debug" "jump" "new" "new_array" "new_with_vtable" "newstr" "newunicode" "ptr_eq" "ptr_ne" "quasiimmut_field" "read_timestamp" "same_as" "setarrayitem_gc" "setarrayitem_raw" "setfield_gc" "setfield_raw" "strgetitem" "strlen" "strsetitem" "uint_floordiv" "uint_ge" "uint_gt" "uint_le" "uint_lt" "uint_rshift" "unicodegetitem" "unicodelen" "unicodesetitem" "virtual_ref" "virtual_ref_finish") ;; keywords '( ;; additional regexps ("^# Loop.*" . 'hi-blue) ("\\[.*\\]" . 'font-lock-comment-face) ;; comment out argument lists @@ -26,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/jit/tool/test/test_oparser.py b/pypy/jit/tool/test/test_oparser.py --- a/pypy/jit/tool/test/test_oparser.py +++ b/pypy/jit/tool/test/test_oparser.py @@ -1,227 +1,274 @@ import py +import sys from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.jit.tool.oparser import parse, ParseError +from pypy.jit.tool.oparser import parse, OpParser from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken,\ - BoxFloat +from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken -def test_basic_parse(): - x = """ - [i0, i1] - # a comment - i2 = int_add(i0, i1) - i3 = int_sub(i2, 3) # another comment - finish() # (tricky) - """ - loop = parse(x) - assert len(loop.operations) == 3 - assert [op.getopnum() for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, - rop.FINISH] - assert len(loop.inputargs) == 2 - assert loop.operations[-1].getdescr() +class BaseTestOparser(object): -def test_const_ptr_subops(): - x = """ - [p0] - guard_class(p0, ConstClass(vtable)) [] - """ - S = lltype.Struct('S') - vtable = lltype.nullptr(S) - loop = parse(x, None, locals()) - assert len(loop.operations) == 1 - assert loop.operations[0].getdescr() - assert loop.operations[0].getfailargs() == [] + OpParser = None -def test_descr(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - i1 = getfield_gc(p0, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff + def parse(self, *args, **kwds): + kwds['OpParser'] = self.OpParser + return parse(*args, **kwds) -def test_after_fail(): - x = """ - [i0] - guard_value(i0, 3) [] - i1 = int_add(1, 2) - """ - loop = parse(x, None, {}) - assert len(loop.operations) == 2 + def test_basic_parse(self): + x = """ + [i0, i1] + # a comment + i2 = int_add(i0, i1) + i3 = int_sub(i2, 3) # another comment + finish() # (tricky) + """ + loop = self.parse(x) + assert len(loop.operations) == 3 + assert [op.getopnum() for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, + rop.FINISH] + assert len(loop.inputargs) == 2 + assert loop.operations[-1].getdescr() -def test_descr_setfield(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - setfield_gc(p0, 3, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff + def test_const_ptr_subops(self): + x = """ + [p0] + guard_class(p0, ConstClass(vtable)) [] + """ + S = lltype.Struct('S') + vtable = lltype.nullptr(S) + loop = self.parse(x, None, locals()) + assert len(loop.operations) == 1 + assert loop.operations[0].getdescr() + assert loop.operations[0].getfailargs() == [] -def test_boxname(): - x = """ - [i42] - i50 = int_add(i42, 1) - """ - loop = parse(x, None, {}) - assert str(loop.inputargs[0]) == 'i42' - assert str(loop.operations[0].result) == 'i50' + def test_descr(self): + class Xyz(AbstractDescr): + I_am_a_descr = True # for the mock case -def test_getboxes(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - boxes = loop.getboxes() - assert boxes.i0 is loop.inputargs[0] - assert boxes.i1 is loop.operations[0].result - -def test_setvalues(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - loop.setvalues(i0=32, i1=42) - assert loop.inputargs[0].value == 32 - assert loop.operations[0].result.value == 42 + x = """ + [p0] + i1 = getfield_gc(p0, descr=stuff) + """ + stuff = Xyz() + loop = self.parse(x, None, locals()) + assert loop.operations[0].getdescr() is stuff -def test_boxkind(): - x = """ - [sum0] - """ - loop = parse(x, None, {}, boxkinds={'sum': BoxInt}) - b = loop.getboxes() - assert isinstance(b.sum0, BoxInt) - -def test_getvar_const_ptr(): - x = ''' - [] - call(ConstPtr(func_ptr)) + def test_after_fail(self): + x = """ + [i0] + guard_value(i0, 3) [] + i1 = int_add(1, 2) + """ + loop = self.parse(x, None, {}) + assert len(loop.operations) == 2 + + def test_descr_setfield(self): + class Xyz(AbstractDescr): + I_am_a_descr = True # for the mock case + + x = """ + [p0] + setfield_gc(p0, 3, descr=stuff) + """ + stuff = Xyz() + loop = self.parse(x, None, locals()) + assert loop.operations[0].getdescr() is stuff + + def test_boxname(self): + x = """ + [i42] + i50 = int_add(i42, 1) + """ + loop = self.parse(x, None, {}) + assert str(loop.inputargs[0]) == 'i42' + assert str(loop.operations[0].result) == 'i50' + + def test_getboxes(self): + x = """ + [i0] + i1 = int_add(i0, 10) + """ + loop = self.parse(x, None, {}) + boxes = loop.getboxes() + assert boxes.i0 is loop.inputargs[0] + assert boxes.i1 is loop.operations[0].result + + def test_setvalues(self): + x = """ + [i0] + i1 = int_add(i0, 10) + """ + loop = self.parse(x, None, {}) + loop.setvalues(i0=32, i1=42) + assert loop.inputargs[0].value == 32 + assert loop.operations[0].result.value == 42 + + def test_getvar_const_ptr(self): + x = ''' + [] + call(ConstPtr(func_ptr)) + ''' + TP = lltype.GcArray(lltype.Signed) + NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) + loop = self.parse(x, None, {'func_ptr' : NULL}) + assert loop.operations[0].getarg(0).value == NULL + + def test_jump_target(self): + x = ''' + [] + jump() + ''' + loop = self.parse(x) + assert loop.operations[0].getdescr() is loop.token + + def test_jump_target_other(self): + looptoken = LoopToken() + looptoken.I_am_a_descr = True # for the mock case + x = ''' + [] + jump(descr=looptoken) + ''' + loop = self.parse(x, namespace=locals()) + assert loop.operations[0].getdescr() is looptoken + + def test_floats(self): + x = ''' + [f0] + f1 = float_add(f0, 3.5) + ''' + loop = self.parse(x) + box = loop.operations[0].getarg(0) + # we cannot use isinstance, because in case of mock the class will be + # constructed on the fly + assert box.__class__.__name__ == 'BoxFloat' + + def test_debug_merge_point(self): + x = ''' + [] + debug_merge_point(0, "info") + debug_merge_point(0, 'info') + debug_merge_point(1, ' info') + debug_merge_point(0, '(stuff) #1') + ''' + loop = self.parse(x) + assert loop.operations[0].getarg(1)._get_str() == 'info' + assert loop.operations[1].getarg(1)._get_str() == 'info' + assert loop.operations[2].getarg(1)._get_str() == " info" + assert loop.operations[3].getarg(1)._get_str() == "(stuff) #1" + + + def test_descr_with_obj_print(self): + x = ''' + [p0] + setfield_gc(p0, 1, descr=) + ''' + loop = self.parse(x) + # assert did not explode + + example_loop_log = '''\ + # bridge out of Guard12, 6 ops + [i0, i1, i2] + i4 = int_add(i0, 2) + i6 = int_sub(i1, 1) + i8 = int_gt(i6, 3) + guard_true(i8, descr=) [i4, i6] + debug_merge_point('(no jitdriver.get_printable_location!)', 0) + jump(i6, i4, descr=) ''' - TP = lltype.GcArray(lltype.Signed) - NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) - loop = parse(x, None, {'func_ptr' : NULL}) - assert loop.operations[0].getarg(0).value == NULL -def test_jump_target(): - x = ''' - [] - jump() - ''' - loop = parse(x) - assert loop.operations[0].getdescr() is loop.token + def test_parse_no_namespace(self): + loop = self.parse(self.example_loop_log, no_namespace=True) -def test_jump_target_other(): - looptoken = LoopToken() - x = ''' - [] - jump(descr=looptoken) - ''' - loop = parse(x, namespace=locals()) - assert loop.operations[0].getdescr() is looptoken + def test_attach_comment_to_loop(self): + loop = self.parse(self.example_loop_log, no_namespace=True) + assert loop.comment == ' # bridge out of Guard12, 6 ops' -def test_floats(): - x = ''' - [f0] - f1 = float_add(f0, 3.5) - ''' - loop = parse(x) - assert isinstance(loop.operations[0].getarg(0), BoxFloat) - -def test_debug_merge_point(): - x = ''' - [] - debug_merge_point("info", 0) - debug_merge_point('info', 1) - debug_merge_point(' info', 1) - debug_merge_point('(stuff) #1', 1) - ''' - loop = parse(x) - assert loop.operations[0].getarg(0)._get_str() == 'info' - assert loop.operations[1].getarg(0)._get_str() == 'info' - assert loop.operations[2].getarg(0)._get_str() == " info" - assert loop.operations[3].getarg(0)._get_str() == "(stuff) #1" - + def test_parse_new_with_comma(self): + # this is generated by PYPYJITLOG, check that we can handle it + x = ''' + [] + p0 = new(, descr=) + ''' + loop = self.parse(x) + assert loop.operations[0].getopname() == 'new' -def test_descr_with_obj_print(): - x = ''' - [p0] - setfield_gc(p0, 1, descr=) - ''' - loop = parse(x) - # assert did not explode + def test_no_fail_args(self): + x = ''' + [i0] + guard_true(i0, descr=) + ''' + loop = self.parse(x, nonstrict=True) + assert loop.operations[0].getfailargs() == [] -example_loop_log = '''\ -# bridge out of Guard12, 6 ops -[i0, i1, i2] -i4 = int_add(i0, 2) -i6 = int_sub(i1, 1) -i8 = int_gt(i6, 3) -guard_true(i8, descr=) [i4, i6] -debug_merge_point('(no jitdriver.get_printable_location!)', 0) -jump(i6, i4, descr=) -''' + def test_no_inputargs(self): + x = ''' + i2 = int_add(i0, i1) + ''' + loop = self.parse(x, nonstrict=True) + assert loop.inputargs == [] + assert loop.operations[0].getopname() == 'int_add' -def test_parse_no_namespace(): - loop = parse(example_loop_log, no_namespace=True) + def test_offsets(self): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + """ + # +30: --end of the loop-- + loop = self.parse(x) + assert loop.operations[0].offset == 10 + assert not hasattr(loop.operations[1], 'offset') -def test_attach_comment_to_loop(): - loop = parse(example_loop_log, no_namespace=True) - assert loop.comment == '# bridge out of Guard12, 6 ops' + def test_last_offset(self): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + +30: --end of the loop-- + """ + loop = self.parse(x) + assert len(loop.operations) == 2 + assert loop.last_offset == 30 -def test_parse_new_with_comma(): - # this is generated by PYPYJITLOG, check that we can handle it - x = ''' - [] - p0 = new(, descr=) - ''' - loop = parse(x) - assert loop.operations[0].getopname() == 'new' -def test_no_fail_args(): - x = ''' - [i0] - guard_true(i0, descr=) - ''' - loop = parse(x, nonstrict=True) - assert loop.operations[0].getfailargs() == [] +class TestOpParser(BaseTestOparser): -def test_no_inputargs(): - x = ''' - i2 = int_add(i0, i1) - ''' - loop = parse(x, nonstrict=True) - assert loop.inputargs == [] - assert loop.operations[0].getopname() == 'int_add' + OpParser = OpParser -def test_offsets(): - x = """ - [i0, i1] - +10: i2 = int_add(i0, i1) - i3 = int_add(i2, 3) - """ - # +30: --end of the loop-- - loop = parse(x) - assert loop.operations[0].offset == 10 - assert not hasattr(loop.operations[1], 'offset') + def test_boxkind(self): + x = """ + [sum0] + """ + loop = self.parse(x, None, {}, boxkinds={'sum': BoxInt}) + b = loop.getboxes() + assert isinstance(b.sum0, BoxInt) -def test_last_offset(): - x = """ - [i0, i1] - +10: i2 = int_add(i0, i1) - i3 = int_add(i2, 3) - +30: --end of the loop-- - """ - loop = parse(x) - assert len(loop.operations) == 2 - assert loop.last_offset == 30 + +class ForbiddenModule(object): + def __init__(self, name, old_mod): + self.name = name + self.old_mod = old_mod + + def __getattr__(self, attr): + assert False, "You should not import module %s" % self.name + + +class TestOpParserWithMock(BaseTestOparser): + + class OpParser(OpParser): + use_mock_model = True + + def setup_class(cls): + forbidden_mods = [ + 'pypy.jit.metainterp.history', + 'pypy.rpython.lltypesystem.lltype', + ] + for modname in forbidden_mods: + if modname in sys.modules: + newmod = ForbiddenModule(modname, sys.modules[modname]) + sys.modules[modname] = newmod + + def teardown_class(cls): + for modname, mod in sys.modules.iteritems(): + if isinstance(mod, ForbiddenModule): + sys.modules[modname] = mod.old_mod diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -31,6 +17,8 @@ 'apply' : 'app_functional.apply', 'sorted' : 'app_functional.sorted', + 'any' : 'app_functional.any', + 'all' : 'app_functional.all', 'vars' : 'app_inspect.vars', 'dir' : 'app_inspect.dir', @@ -95,8 +83,6 @@ 'range' : 'functional.range_int', 'xrange' : 'functional.W_XRange', 'enumerate' : 'functional.W_Enumerate', - 'all' : 'functional.all', - 'any' : 'functional.any', 'min' : 'functional.min', 'max' : 'functional.max', 'sum' : 'functional.sum', @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py --- a/pypy/module/__builtin__/app_functional.py +++ b/pypy/module/__builtin__/app_functional.py @@ -16,3 +16,21 @@ sorted_lst = list(lst) sorted_lst.sort(cmp, key, reverse) return sorted_lst + +def any(seq): + """any(iterable) -> bool + +Return True if bool(x) is True for any x in the iterable.""" + for x in seq: + if x: + return True + return False + +def all(seq): + """all(iterable) -> bool + +Return True if bool(x) is True for all values x in the iterable.""" + for x in seq: + if not x: + return False + return True diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -294,7 +294,7 @@ break new_frame = space.createframe(code, w_func.w_func_globals, w_func.closure) - new_frame.fastlocals_w[0] = w_item + new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) return result_w @@ -452,40 +452,6 @@ w_empty = space.call_function(w_str_type) return space.call_method(w_empty, "join", space.newlist(result_w)) -def all(space, w_S): - """all(iterable) -> bool - -Return True if bool(x) is True for all values x in the iterable.""" - w_iter = space.iter(w_S) - while True: - try: - w_next = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise # re-raise other app-level exceptions - break - if not space.is_true(w_next): - return space.w_False - return space.w_True - - -def any(space, w_S): - """any(iterable) -> bool - -Return True if bool(x) is True for any x in the iterable.""" - w_iter = space.iter(w_S) - while True: - try: - w_next = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise # re-raise other app-level exceptions - break - if space.is_true(w_next): - return space.w_True - return space.w_False - - class W_Enumerate(Wrappable): def __init__(self, w_iter, w_start): diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -1,5 +1,6 @@ import autopath import sys +from pypy import conftest class AppTestBuiltinApp: def setup_class(cls): @@ -15,6 +16,15 @@ cls.w_sane_lookup = cls.space.wrap(True) except KeyError: cls.w_sane_lookup = cls.space.wrap(False) + # starting with CPython 2.6, when the stack is almost out, we + # can get a random error, instead of just a RuntimeError. + # For example if an object x has a __getattr__, we can get + # AttributeError if attempting to call x.__getattr__ runs out + # of stack. That's annoying, so we just work around it. + if conftest.option.runappdirect: + cls.w_safe_runtimerror = cls.space.wrap(True) + else: + cls.w_safe_runtimerror = cls.space.wrap(sys.version_info < (2, 6)) def test_bytes_alias(self): assert bytes is str @@ -399,6 +409,8 @@ def test_cmp_cyclic(self): if not self.sane_lookup: skip("underlying Python implementation has insane dict lookup") + if not self.safe_runtimerror: + skip("underlying Python may raise random exceptions on stack ovf") a = []; a.append(a) b = []; b.append(b) from UserList import UserList @@ -619,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -3,6 +3,14 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.imp.importing import get_pyc_magic + +class BuildersModule(MixedModule): + appleveldefs = {} + + interpleveldefs = { + "UnicodeBuilder": "interp_builders.W_UnicodeBuilder", + } + class Module(MixedModule): appleveldefs = { } @@ -19,6 +27,10 @@ 'lookup_special' : 'interp_magic.lookup_special', } + submodules = { + "builders": BuildersModule, + } + def setup_after_space_initialization(self): """NOT_RPYTHON""" if not self.space.config.translating: diff --git a/pypy/module/__pypy__/interp_builders.py b/pypy/module/__pypy__/interp_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_builders.py @@ -0,0 +1,50 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef +from pypy.rlib.rstring import UnicodeBuilder + + +class W_UnicodeBuilder(Wrappable): + def __init__(self, space, size): + if size == -1: + self.builder = UnicodeBuilder() + else: + self.builder = UnicodeBuilder(size) + self.done = False + + def _check_done(self, space): + if self.done: + raise OperationError(space.w_ValueError, space.wrap("Can't operate on a done builder")) + + @unwrap_spec(size=int) + def descr__new__(space, w_subtype, size=-1): + return W_UnicodeBuilder(space, size) + + @unwrap_spec(s=unicode) + def descr_append(self, space, s): + self._check_done(space) + self.builder.append(s) + + @unwrap_spec(s=unicode, start=int, end=int) + def descr_append_slice(self, space, s, start, end): + self._check_done(space) + if not 0 <= start <= end <= len(s): + raise OperationError(space.w_ValueError, space.wrap("bad start/stop")) + self.builder.append_slice(s, start, end) + + def descr_build(self, space): + self._check_done(space) + w_s = space.wrap(self.builder.build()) + self.done = True + return w_s + + +W_UnicodeBuilder.typedef = TypeDef("UnicodeBuilder", + __new__ = interp2app(W_UnicodeBuilder.descr__new__.im_func), + + append = interp2app(W_UnicodeBuilder.descr_append), + append_slice = interp2app(W_UnicodeBuilder.descr_append_slice), + build = interp2app(W_UnicodeBuilder.descr_build), +) +W_UnicodeBuilder.typedef.acceptable_as_base_class = False \ No newline at end of file diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,15 +1,19 @@ from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.error import OperationError -from pypy.rlib import debug +from pypy.rlib import debug, jit + + at jit.dont_look_inside @unwrap_spec(category=str) def debug_start(space, category): debug.debug_start(category) + at jit.dont_look_inside def debug_print(space, args_w): parts = [space.str_w(space.str(w_item)) for w_item in args_w] debug.debug_print(' '.join(parts)) + at jit.dont_look_inside @unwrap_spec(category=str) def debug_stop(space, category): debug.debug_stop(category) diff --git a/pypy/module/__pypy__/test/test_builders.py b/pypy/module/__pypy__/test/test_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_builders.py @@ -0,0 +1,34 @@ +from pypy.conftest import gettestobjspace + + +class AppTestBuilders(object): + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['__pypy__']) + + def test_simple(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append(u"abc") + b.append(u"123") + b.append(u"1") + s = b.build() + assert s == u"abc1231" + raises(ValueError, b.build) + raises(ValueError, b.append, u"123") + + def test_preallocate(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder(10) + b.append(u"abc") + b.append(u"123") + s = b.build() + assert s == u"abc123" + + def test_append_slice(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append_slice(u"abcdefgh", 2, 5) + raises(ValueError, b.append_slice, u"1", 2, 1) + s = b.build() + assert s == "cde" + raises(ValueError, b.append_slice, u"abc", 1, 2) \ No newline at end of file diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -32,15 +32,22 @@ space.wrap(reason)) w_res = space.call_function(w_errorhandler, w_exc) if (not space.is_true(space.isinstance(w_res, space.w_tuple)) - or space.len_w(w_res) != 2): + or space.len_w(w_res) != 2 + or not space.is_true(space.isinstance( + space.getitem(w_res, space.wrap(0)), + space.w_unicode))): + if decode: + msg = ("decoding error handler must return " + "(unicode, int) tuple, not %s") + else: + msg = ("encoding error handler must return " + "(unicode, int) tuple, not %s") raise operationerrfmt( - space.w_TypeError, - "encoding error handler must return " - "(unicode, int) tuple, not %s", + space.w_TypeError, msg, space.str_w(space.repr(w_res))) w_replace, w_newpos = space.fixedview(w_res, 2) newpos = space.int_w(w_newpos) - if (newpos < 0): + if newpos < 0: newpos = len(input) + newpos if newpos < 0 or newpos > len(input): raise operationerrfmt( @@ -50,7 +57,9 @@ replace = space.unicode_w(w_replace) return replace, newpos else: - replace = space.str_w(w_replace) + from pypy.objspace.std.unicodetype import encode_object + w_str = encode_object(space, w_replace, encoding, None) + replace = space.str_w(w_str) return replace, newpos return unicode_call_errorhandler @@ -160,15 +169,7 @@ def ignore_errors(space, w_exc): check_exception(space, w_exc) w_end = space.getattr(w_exc, space.wrap('end')) - if space.isinstance_w(w_exc, space.w_UnicodeEncodeError): - return space.newtuple([space.wrap(''), w_end]) - elif (space.isinstance_w(w_exc, space.w_UnicodeDecodeError) or - space.isinstance_w(w_exc, space.w_UnicodeTranslateError)): - return space.newtuple([space.wrap(u''), w_end]) - else: - typename = space.type(w_exc).getname(space, '?') - raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + return space.newtuple([space.wrap(u''), w_end]) def replace_errors(space, w_exc): check_exception(space, w_exc) @@ -176,7 +177,7 @@ w_end = space.getattr(w_exc, space.wrap('end')) size = space.int_w(w_end) - space.int_w(w_start) if space.isinstance_w(w_exc, space.w_UnicodeEncodeError): - text = '?' * size + text = u'?' * size return space.newtuple([space.wrap(text), w_end]) elif space.isinstance_w(w_exc, space.w_UnicodeDecodeError): text = u'\ufffd' @@ -185,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -206,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -239,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_codecs/test/test_codecs.py b/pypy/module/_codecs/test/test_codecs.py --- a/pypy/module/_codecs/test/test_codecs.py +++ b/pypy/module/_codecs/test/test_codecs.py @@ -540,6 +540,17 @@ else: assert res == u"\x00\x00\x01\x00\x00" # UCS2 build + def test_encode_error_bad_handler(self): + import codecs + codecs.register_error("test.bad_handler", lambda e: (repl, 1)) + assert u"xyz".encode("latin-1", "test.bad_handler") == "xyz" + repl = u"\u1234" + raises(UnicodeEncodeError, u"\u5678".encode, "latin-1", + "test.bad_handler") + repl = u"\u00E9" + s = u"\u5678".encode("latin-1", "test.bad_handler") + assert s == '\xe9' + def test_charmap_encode(self): assert 'xxx'.encode('charmap') == 'xxx' @@ -593,3 +604,11 @@ assert u'caf\xe9'.encode('mbcs') == 'caf\xe9' assert u'\u040a'.encode('mbcs') == '?' # some cyrillic letter assert 'cafx\e9'.decode('mbcs') == u'cafx\e9' + + def test_bad_handler_string_result(self): + import _codecs + def f(exc): + return ('foo', exc.end) + _codecs.register_error("test.test_codecs_not_a_string", f) + raises(TypeError, u'\u1234'.encode, 'ascii', + 'test.test_codecs_not_a_string') diff --git a/pypy/module/_ffi/__init__.py b/pypy/module/_ffi/__init__.py --- a/pypy/module/_ffi/__init__.py +++ b/pypy/module/_ffi/__init__.py @@ -4,8 +4,10 @@ class Module(MixedModule): interpleveldefs = { - 'CDLL' : 'interp_ffi.W_CDLL', - 'types': 'interp_ffi.W_types', + 'CDLL': 'interp_ffi.W_CDLL', + 'types': 'interp_ffi.W_types', + 'FuncPtr': 'interp_ffi.W_FuncPtr', + 'get_libc':'interp_ffi.get_libc', } appleveldefs = {} diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -4,63 +4,176 @@ operationerrfmt from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi # from pypy.rlib import jit from pypy.rlib import libffi from pypy.rlib.rdynload import DLOpenError -from pypy.rlib.rarithmetic import intmask +from pypy.rlib.rarithmetic import intmask, r_uint class W_FFIType(Wrappable): - def __init__(self, name, ffitype): + + _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to'] + + def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None): self.name = name self.ffitype = ffitype + self.w_datashape = w_datashape + self.w_pointer_to = w_pointer_to + if self.is_struct(): + assert w_datashape is not None - def str(self, space): - return space.wrap('' % self.name) + def descr_deref_pointer(self, space): + if self.w_pointer_to is None: + return space.w_None + return self.w_pointer_to + def repr(self, space): + return space.wrap(self.__repr__()) + def __repr__(self): + return "" % self.name + + def is_signed(self): + return (self is app_types.slong or + self is app_types.sint or + self is app_types.sshort or + self is app_types.sbyte or + self is app_types.slonglong) + + def is_unsigned(self): + return (self is app_types.ulong or + self is app_types.uint or + self is app_types.ushort or + self is app_types.ubyte or + self is app_types.ulonglong) + + def is_pointer(self): + return self.ffitype is libffi.types.pointer + + def is_char(self): + return self is app_types.char + + def is_unichar(self): + return self is app_types.unichar + + def is_longlong(self): + return libffi.IS_32_BIT and (self is app_types.slonglong or + self is app_types.ulonglong) + + def is_double(self): + return self is app_types.double + + def is_singlefloat(self): + return self is app_types.float + + def is_void(self): + return self is app_types.void + + def is_struct(self): + return libffi.types.is_struct(self.ffitype) W_FFIType.typedef = TypeDef( 'FFIType', - __str__ = interp2app(W_FFIType.str), + __repr__ = interp2app(W_FFIType.repr), + deref_pointer = interp2app(W_FFIType.descr_deref_pointer), ) +def build_ffi_types(): + from pypy.rlib.clibffi import FFI_TYPE_P + types = [ + # note: most of the type name directly come from the C equivalent, + # with the exception of bytes: in C, ubyte and char are equivalent, + # but for _ffi the first expects a number while the second a 1-length + # string + W_FFIType('slong', libffi.types.slong), + W_FFIType('sint', libffi.types.sint), + W_FFIType('sshort', libffi.types.sshort), + W_FFIType('sbyte', libffi.types.schar), + W_FFIType('slonglong', libffi.types.slonglong), + # + W_FFIType('ulong', libffi.types.ulong), + W_FFIType('uint', libffi.types.uint), + W_FFIType('ushort', libffi.types.ushort), + W_FFIType('ubyte', libffi.types.uchar), + W_FFIType('ulonglong', libffi.types.ulonglong), + # + W_FFIType('char', libffi.types.uchar), + W_FFIType('unichar', libffi.types.wchar_t), + # + W_FFIType('double', libffi.types.double), + W_FFIType('float', libffi.types.float), + W_FFIType('void', libffi.types.void), + W_FFIType('void_p', libffi.types.pointer), + # + # missing types: + + ## 's' : ffi_type_pointer, + ## 'z' : ffi_type_pointer, + ## 'O' : ffi_type_pointer, + ## 'Z' : ffi_type_pointer, + + ] + return dict([(t.name, t) for t in types]) + +class app_types: + pass +app_types.__dict__ = build_ffi_types() + +def descr_new_pointer(space, w_cls, w_pointer_to): + try: + return descr_new_pointer.cache[w_pointer_to] + except KeyError: + w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) + name = '(pointer to %s)' % w_pointer_to.name + w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to) + descr_new_pointer.cache[w_pointer_to] = w_result + return w_result +descr_new_pointer.cache = {} + class W_types(Wrappable): pass - -def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P - tdict = {} - for key, value in libffi.types.__dict__.iteritems(): - if key == 'getkind' or key.startswith('__'): - continue - assert lltype.typeOf(value) == FFI_TYPE_P - tdict[key] = W_FFIType(key, value) - return tdict - W_types.typedef = TypeDef( 'types', - **build_ffi_types()) + Pointer = interp2app(descr_new_pointer, as_classmethod=True), + **app_types.__dict__) + + +def unwrap_ffitype(space, w_argtype, allow_void=False): + res = w_argtype.ffitype + if res is libffi.types.void and not allow_void: + msg = 'void is not a valid argument type' + raise OperationError(space.w_TypeError, space.wrap(msg)) + return res + +def unwrap_truncate_int(TP, space, w_arg): + if space.is_true(space.isinstance(w_arg, space.w_int)): + return rffi.cast(TP, space.int_w(w_arg)) + else: + return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask()) +unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)' # ======================================================================== class W_FuncPtr(Wrappable): - _immutable_fields_ = ['func'] + _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype'] - def __init__(self, func): + def __init__(self, func, argtypes_w, w_restype): self.func = func + self.argtypes_w = argtypes_w + self.w_restype = w_restype @jit.unroll_safe - def build_argchain(self, space, argtypes, args_w): - expected = len(argtypes) + def build_argchain(self, space, args_w): + expected = len(self.argtypes_w) given = len(args_w) if given != expected: arg = 'arguments' - if len(argtypes) == 1: + if len(self.argtypes_w) == 1: arg = 'argument' raise operationerrfmt(space.w_TypeError, '%s() takes exactly %d %s (%d given)', @@ -68,34 +181,97 @@ # argchain = libffi.ArgChain() for i in range(expected): - argtype = argtypes[i] + w_argtype = self.argtypes_w[i] w_arg = args_w[i] - kind = libffi.types.getkind(argtype) - if kind == 'i': + if w_argtype.is_longlong(): + # note that we must check for longlong first, because either + # is_signed or is_unsigned returns true anyway + assert libffi.IS_32_BIT + self.arg_longlong(space, argchain, w_arg) + elif w_argtype.is_signed(): + argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) + elif w_argtype.is_pointer(): + w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) + argchain.arg(intmask(space.uint_w(w_arg))) + elif w_argtype.is_unsigned(): + argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg)) + elif w_argtype.is_char(): + w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) - elif kind == 'u': - argchain.arg(intmask(space.uint_w(w_arg))) - elif kind == 'f': + elif w_argtype.is_unichar(): + w_arg = space.ord(w_arg) + argchain.arg(space.int_w(w_arg)) + elif w_argtype.is_double(): argchain.arg(space.float_w(w_arg)) + elif w_argtype.is_singlefloat(): + argchain.arg_singlefloat(space.float_w(w_arg)) + elif w_argtype.is_struct(): + # arg_raw directly takes value to put inside ll_args + w_arg = space.interp_w(W_StructureInstance, w_arg) + ptrval = w_arg.ll_buffer + argchain.arg_raw(ptrval) else: - assert False, "Argument kind '%s' not supported" % kind + assert False, "Argument shape '%s' not supported" % w_argtype return argchain + def convert_pointer_arg_maybe(self, space, w_arg, w_argtype): + """ + Try to convert the argument by calling _as_ffi_pointer_() + """ + meth = space.lookup(w_arg, '_as_ffi_pointer_') # this also promotes the type + if meth: + return space.call_function(meth, w_arg, w_argtype) + else: + return w_arg + + @jit.dont_look_inside + def arg_longlong(self, space, argchain, w_arg): + bigarg = space.bigint_w(w_arg) + ullval = bigarg.ulonglongmask() + llval = rffi.cast(rffi.LONGLONG, ullval) + # this is a hack: we store the 64 bits of the long long into the + # 64 bits of a float (i.e., a C double) + floatval = libffi.longlong2float(llval) + argchain.arg_longlong(floatval) + def call(self, space, args_w): - self = jit.hint(self, promote=True) - argchain = self.build_argchain(space, self.func.argtypes, args_w) - reskind = libffi.types.getkind(self.func.restype) - if reskind == 'i': + self = jit.promote(self) + argchain = self.build_argchain(space, args_w) + w_restype = self.w_restype + if w_restype.is_longlong(): + # note that we must check for longlong first, because either + # is_signed or is_unsigned returns true anyway + assert libffi.IS_32_BIT + reskind = libffi.types.getkind(self.func.restype) # XXX: remove the kind + return self._call_longlong(space, argchain, reskind) + elif w_restype.is_signed(): return self._call_int(space, argchain) - elif reskind == 'u': + elif w_restype.is_unsigned() or w_restype.is_pointer(): return self._call_uint(space, argchain) - elif reskind == 'f': + elif w_restype.is_char(): + intres = self.func.call(argchain, rffi.UCHAR) + return space.wrap(chr(intres)) + elif w_restype.is_unichar(): + intres = self.func.call(argchain, rffi.WCHAR_T) + return space.wrap(unichr(intres)) + elif w_restype.is_double(): floatres = self.func.call(argchain, rffi.DOUBLE) return space.wrap(floatres) - else: + elif w_restype.is_singlefloat(): + # the result is a float, but widened to be inside a double + floatres = self.func.call(argchain, rffi.FLOAT) + return space.wrap(floatres) + elif w_restype.is_struct(): + w_datashape = w_restype.w_datashape + assert isinstance(w_datashape, W_Structure) + ptrval = self.func.call(argchain, rffi.ULONG, is_struct=True) + return w_datashape.fromaddress(space, ptrval) + elif w_restype.is_void(): voidres = self.func.call(argchain, lltype.Void) assert voidres is None return space.w_None + else: + assert False, "Return value shape '%s' not supported" % w_restype def _call_int(self, space, argchain): # if the declared return type of the function is smaller than LONG, @@ -138,6 +314,10 @@ # special case uintres = call(argchain, rffi.ULONG) return space.wrap(uintres) + elif restype is libffi.types.pointer: + ptrres = call(argchain, rffi.VOIDP) + uintres = rffi.cast(rffi.ULONG, ptrres) + return space.wrap(uintres) elif restype is libffi.types.uint: intres = rffi.cast(rffi.LONG, call(argchain, rffi.UINT)) elif restype is libffi.types.ushort: @@ -149,16 +329,52 @@ space.wrap('Unsupported restype')) return space.wrap(intres) + @jit.dont_look_inside + def _call_longlong(self, space, argchain, reskind): + # this is a hack: we store the 64 bits of the long long into the 64 + # bits of a float (i.e., a C double) + floatres = self.func.call(argchain, rffi.LONGLONG) + llres = libffi.float2longlong(floatres) + if reskind == 'I': + return space.wrap(llres) + elif reskind == 'U': + ullres = rffi.cast(rffi.ULONGLONG, llres) + return space.wrap(ullres) + else: + assert False + def getaddr(self, space): """ Return the physical address in memory of the function """ return space.wrap(rffi.cast(rffi.LONG, self.func.funcsym)) + + +def unpack_argtypes(space, w_argtypes, w_restype): + argtypes_w = [space.interp_w(W_FFIType, w_argtype) + for w_argtype in space.listview(w_argtypes)] + argtypes = [unwrap_ffitype(space, w_argtype) for w_argtype in + argtypes_w] + w_restype = space.interp_w(W_FFIType, w_restype) + restype = unwrap_ffitype(space, w_restype, allow_void=True) + return argtypes_w, argtypes, w_restype, restype + + at unwrap_spec(addr=r_uint, name=str) +def descr_fromaddr(space, w_cls, addr, name, w_argtypes, w_restype): + argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space, + w_argtypes, + w_restype) + addr = rffi.cast(rffi.VOIDP, addr) + func = libffi.Func(name, argtypes, restype, addr) + return W_FuncPtr(func, argtypes_w, w_restype) + + W_FuncPtr.typedef = TypeDef( - 'FuncPtr', + '_ffi.FuncPtr', __call__ = interp2app(W_FuncPtr.call), getaddr = interp2app(W_FuncPtr.getaddr), + fromaddr = interp2app(descr_fromaddr, as_classmethod=True) ) @@ -167,40 +383,57 @@ class W_CDLL(Wrappable): def __init__(self, space, name): + self.space = space + if name is None: + self.name = "" + else: + self.name = name try: self.cdll = libffi.CDLL(name) except DLOpenError, e: - raise operationerrfmt(space.w_OSError, '%s: %s', name, + raise operationerrfmt(space.w_OSError, '%s: %s', self.name, e.msg or 'unspecified error') - self.name = name - self.space = space - - def ffitype(self, w_argtype, allow_void=False): - res = self.space.interp_w(W_FFIType, w_argtype).ffitype - if res is libffi.types.void and not allow_void: - space = self.space - msg = 'void is not a valid argument type' - raise OperationError(space.w_TypeError, space.wrap(msg)) - return res @unwrap_spec(name=str) def getfunc(self, space, name, w_argtypes, w_restype): - argtypes = [self.ffitype(w_argtype) for w_argtype in - space.listview(w_argtypes)] - restype = self.ffitype(w_restype, allow_void=True) - func = self.cdll.getpointer(name, argtypes, restype) - return W_FuncPtr(func) + argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space, + w_argtypes, + w_restype) + try: + func = self.cdll.getpointer(name, argtypes, restype) + except KeyError: + raise operationerrfmt(space.w_AttributeError, + "No symbol %s found in library %s", name, self.name) + + return W_FuncPtr(func, argtypes_w, w_restype) + @unwrap_spec(name=str) + def getaddressindll(self, space, name): + try: + address_as_uint = rffi.cast(lltype.Unsigned, + self.cdll.getaddressindll(name)) + except KeyError: + raise operationerrfmt(space.w_ValueError, + "No symbol %s found in library %s", name, self.name) + return space.wrap(address_as_uint) - at unwrap_spec(name=str) + at unwrap_spec(name='str_or_None') def descr_new_cdll(space, w_type, name): return space.wrap(W_CDLL(space, name)) W_CDLL.typedef = TypeDef( - 'CDLL', + '_ffi.CDLL', __new__ = interp2app(descr_new_cdll), getfunc = interp2app(W_CDLL.getfunc), + getaddressindll = interp2app(W_CDLL.getaddressindll), ) # ======================================================================== + +def get_libc(space): + from pypy.rlib.clibffi import get_libc_name + try: + return space.wrap(W_CDLL(space, get_libc_name())) + except OSError, e: + raise wrap_oserror(space, e) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -17,7 +17,13 @@ c_file = udir.ensure("test__ffi", dir=1).join("foolib.c") # automatically collect the C source from the docstrings of the tests - snippets = [] + snippets = [""" + #ifdef _WIN32 + #define DLLEXPORT __declspec(dllexport) + #else + #define DLLEXPORT + #endif + """] for name in dir(cls): if name.startswith('test_'): meth = getattr(cls, name) @@ -35,8 +41,9 @@ from pypy.rpython.lltypesystem import rffi from pypy.rlib.libffi import get_libc_name, CDLL, types from pypy.rlib.test.test_libffi import get_libm_name - space = gettestobjspace(usemodules=('_ffi',)) + space = gettestobjspace(usemodules=('_ffi', '_rawffi')) cls.space = space + cls.w_iswin32 = space.wrap(sys.platform == 'win32') cls.w_libfoo_name = space.wrap(cls.prepare_c_example()) cls.w_libc_name = space.wrap(get_libc_name()) libm_name = get_libm_name(sys.platform) @@ -45,6 +52,13 @@ pow = libm.getpointer('pow', [], types.void) pow_addr = rffi.cast(rffi.LONG, pow.funcsym) cls.w_pow_addr = space.wrap(pow_addr) + # + # these are needed for test_single_float_args + from ctypes import c_float + f_12_34 = c_float(12.34).value + f_56_78 = c_float(56.78).value + f_result = c_float(f_12_34 + f_56_78).value + cls.w_f_12_34_plus_56_78 = space.wrap(f_result) def test_libload(self): import _ffi @@ -54,10 +68,20 @@ import _ffi raises(OSError, _ffi.CDLL, "xxxxx_this_name_does_not_exist_xxxxx") + def test_libload_None(self): + if self.iswin32: + skip("unix specific") + from _ffi import CDLL, types + # this should return *all* loaded libs, dlopen(NULL) + dll = CDLL(None) + # Assume CPython, or PyPy compiled with cpyext + res = dll.getfunc('Py_IsInitialized', [], types.slong)() + assert res == 1 + def test_simple_types(self): from _ffi import types - assert str(types.sint) == '' - assert str(types.uint) == '' + assert str(types.sint) == "" + assert str(types.uint) == "" def test_callfunc(self): from _ffi import CDLL, types @@ -70,24 +94,42 @@ libm = CDLL(self.libm_name) pow = libm.getfunc('pow', [types.double, types.double], types.double) assert pow.getaddr() == self.pow_addr - + + def test_getaddressindll(self): + import sys + from _ffi import CDLL, types + libm = CDLL(self.libm_name) + pow_addr = libm.getaddressindll('pow') + assert pow_addr == self.pow_addr & (sys.maxint*2-1) + + def test_func_fromaddr(self): + import sys + from _ffi import CDLL, types, FuncPtr + libm = CDLL(self.libm_name) + pow_addr = libm.getaddressindll('pow') + pow = FuncPtr.fromaddr(pow_addr, 'pow', [types.double, types.double], + types.double) + assert pow(2, 3) == 8 + def test_int_args(self): """ - int sum_xy(int x, int y) + DLLEXPORT int sum_xy(int x, int y) { return x+y; } """ + import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint) assert sum_xy(30, 12) == 42 + assert sum_xy(sys.maxint*2, 0) == -2 def test_void_result(self): """ int dummy = 0; - void set_dummy(int val) { dummy = val; } - int get_dummy() { return dummy; } + DLLEXPORT void set_dummy(int val) { dummy = val; } + DLLEXPORT int get_dummy() { return dummy; } """ from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) @@ -96,10 +138,105 @@ assert get_dummy() == 0 assert set_dummy(42) is None assert get_dummy() == 42 + set_dummy(0) + + def test_pointer_args(self): + """ + extern int dummy; // defined in test_void_result + DLLEXPORT int* get_dummy_ptr() { return &dummy; } + DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + get_dummy = libfoo.getfunc('get_dummy', [], types.sint) + get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p) + set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', + [types.void_p, types.sint], + types.void) + assert get_dummy() == 0 + ptr = get_dummy_ptr() + set_val_to_ptr(ptr, 123) + assert get_dummy() == 123 + set_val_to_ptr(ptr, 0) + + def test_convert_pointer_args(self): + """ + extern int dummy; // defined in test_void_result + DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args + DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto + """ + from _ffi import CDLL, types + + class MyPointerWrapper(object): + def __init__(self, value): + self.value = value + def _as_ffi_pointer_(self, ffitype): + assert ffitype is types.void_p + return self.value + + libfoo = CDLL(self.libfoo_name) + get_dummy = libfoo.getfunc('get_dummy', [], types.sint) + get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p) + set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', + [types.void_p, types.sint], + types.void) + assert get_dummy() == 0 + ptr = get_dummy_ptr() + assert type(ptr) in (int, long) + ptr2 = MyPointerWrapper(ptr) + set_val_to_ptr(ptr2, 123) + assert get_dummy() == 123 + set_val_to_ptr(ptr2, 0) + + def test_typed_pointer(self): + from _ffi import types + intptr = types.Pointer(types.sint) # create a typed pointer to sint + assert intptr.deref_pointer() is types.sint + assert str(intptr) == '' + assert types.sint.deref_pointer() is None + raises(TypeError, "types.Pointer(42)") + + def test_pointer_identity(self): + from _ffi import types + x = types.Pointer(types.slong) + y = types.Pointer(types.slong) + z = types.Pointer(types.char) + assert x is y + assert x is not z + + def test_typed_pointer_args(self): + """ + extern int dummy; // defined in test_void_result + DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args + DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto + """ + from _ffi import CDLL, types + + libfoo = CDLL(self.libfoo_name) + intptr = types.Pointer(types.sint) + get_dummy = libfoo.getfunc('get_dummy', [], types.sint) + get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], intptr) + set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', [intptr, types.sint], types.void) + assert get_dummy() == 0 + ptr = get_dummy_ptr() + set_val_to_ptr(ptr, 123) + assert get_dummy() == 123 + set_val_to_ptr(ptr, 0) + + def test_huge_pointer_args(self): + """ + #include + DLLEXPORT long is_null_ptr(void* ptr) { return ptr == NULL; } + """ + import sys + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + is_null_ptr = libfoo.getfunc('is_null_ptr', [types.void_p], types.ulong) + assert not is_null_ptr(sys.maxint+1) def test_unsigned_long_args(self): """ - unsigned long sum_xy_ul(unsigned long x, unsigned long y) + DLLEXPORT unsigned long sum_xy_ul(unsigned long x, unsigned long y) { return x+y; } @@ -111,15 +248,17 @@ types.ulong) assert sum_xy(sys.maxint, 12) == sys.maxint+12 assert sum_xy(sys.maxint+1, 12) == sys.maxint+13 + # + res = sum_xy(sys.maxint*2+3, 0) + assert res == 1 def test_unsigned_short_args(self): """ - unsigned short sum_xy_us(unsigned short x, unsigned short y) + DLLEXPORT unsigned short sum_xy_us(unsigned short x, unsigned short y) { return x+y; } """ - import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy_us', [types.ushort, types.ushort], @@ -127,6 +266,169 @@ assert sum_xy(32000, 8000) == 40000 assert sum_xy(60000, 30000) == 90000 % 65536 + def test_unsigned_byte_args(self): + """ + DLLEXPORT unsigned char sum_xy_ub(unsigned char x, unsigned char y) + { + return x+y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_us', [types.ubyte, types.ubyte], + types.ubyte) + assert sum_xy(100, 40) == 140 + assert sum_xy(200, 60) == 260 % 256 + + def test_signed_byte_args(self): + """ + DLLEXPORT signed char sum_xy_sb(signed char x, signed char y) + { + return x+y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_sb', [types.sbyte, types.sbyte], + types.sbyte) + assert sum_xy(10, 20) == 30 + assert sum_xy(100, 28) == -128 + + def test_char_args(self): + """ + DLLEXPORT char my_toupper(char x) + { + return x - ('a'-'A'); + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + my_toupper = libfoo.getfunc('my_toupper', [types.char], + types.char) + assert my_toupper('c') == 'C' + + def test_unichar_args(self): + """ + #include + DLLEXPORT wchar_t sum_xy_wc(wchar_t x, wchar_t y) + { + return x + y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_wc', [types.unichar, types.unichar], + types.unichar) + res = sum_xy(unichr(1000), unichr(2000)) + assert type(res) is unicode + assert ord(res) == 3000 + + def test_single_float_args(self): + """ + DLLEXPORT float sum_xy_float(float x, float y) + { + return x+y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_float', [types.float, types.float], + types.float) + res = sum_xy(12.34, 56.78) + assert res == self.f_12_34_plus_56_78 + + + def test_slonglong_args(self): + """ + DLLEXPORT long long sum_xy_longlong(long long x, long long y) + { + return x+y; + } + """ + from _ffi import CDLL, types + maxint32 = 2147483647 # we cannot really go above maxint on 64 bits + # (and we would not test anything, as there long + # is the same as long long) + + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_longlong', [types.slonglong, types.slonglong], + types.slonglong) + x = maxint32+1 + y = maxint32+2 + res = sum_xy(x, y) + expected = maxint32*2 + 3 + assert res == expected + + def test_ulonglong_args(self): + """ + DLLEXPORT unsigned long long sum_xy_ulonglong(unsigned long long x, + unsigned long long y) + { + return x+y; + } + """ + from _ffi import CDLL, types + maxint64 = 9223372036854775807 # maxint64+1 does not fit into a + # longlong, but it does into a + # ulonglong + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_ulonglong', [types.ulonglong, types.ulonglong], + types.ulonglong) + x = maxint64+1 + y = 2 + res = sum_xy(x, y) + expected = maxint64 + 3 + assert res == expected + # + res = sum_xy(maxint64*2+3, 0) + assert res == 1 + + def test_byval_argument(self): + """ + struct Point { + long x; + long y; + }; + + DLLEXPORT long sum_point(struct Point p) { + return p.x + p.y; + } + """ + import _rawffi + from _ffi import CDLL, types + POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')]) + ffi_point = POINT.get_ffi_type() + libfoo = CDLL(self.libfoo_name) + sum_point = libfoo.getfunc('sum_point', [ffi_point], types.slong) + # + p = POINT() + p.x = 30 + p.y = 12 + res = sum_point(p) + assert res == 42 + p.free() + + def test_byval_result(self): + """ + DLLEXPORT struct Point make_point(long x, long y) { + struct Point p; + p.x = x; + p.y = y; + return p; + } + """ + import _rawffi + from _ffi import CDLL, types + POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')]) + ffi_point = POINT.get_ffi_type() + libfoo = CDLL(self.libfoo_name) + make_point = libfoo.getfunc('make_point', [types.slong, types.slong], ffi_point) + # + p = make_point(12, 34) + assert p.x == 12 + assert p.y == 34 + p.free() + def test_TypeError_numargs(self): from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) @@ -142,3 +444,10 @@ def test_OSError_loading(self): from _ffi import CDLL, types raises(OSError, "CDLL('I do not exist')") + + def test_AttributeError_missing_function(self): + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + raises(AttributeError, "libfoo.getfunc('I_do_not_exist', [], types.void)") + libnone = CDLL(None) + raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)") diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -3,6 +3,8 @@ from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir +UNICODE_REPLACEMENT_CHARACTER = u'\uFFFD' + class EncodeDecodeError(Exception): def __init__(self, start, end, reason): @@ -103,8 +105,12 @@ [DECODEBUF_P], rffi.SSIZE_T) pypy_cjk_dec_inbuf_consumed = llexternal('pypy_cjk_dec_inbuf_consumed', [DECODEBUF_P], rffi.SSIZE_T) +pypy_cjk_dec_replace_on_error = llexternal('pypy_cjk_dec_replace_on_error', + [DECODEBUF_P, rffi.CWCHARP, + rffi.SSIZE_T, rffi.SSIZE_T], + rffi.SSIZE_T) -def decode(codec, stringdata): +def decode(codec, stringdata, errors="strict", errorcb=None, namecb=None): inleft = len(stringdata) inbuf = rffi.get_nonmovingbuffer(stringdata) try: @@ -112,10 +118,12 @@ if not decodebuf: raise MemoryError try: - r = pypy_cjk_dec_chunk(decodebuf) - if r != 0: - multibytecodec_decerror(decodebuf, r) - assert False + while True: + r = pypy_cjk_dec_chunk(decodebuf) + if r == 0: + break + multibytecodec_decerror(decodebuf, r, errors, + errorcb, namecb, stringdata) src = pypy_cjk_dec_outbuf(decodebuf) length = pypy_cjk_dec_outlen(decodebuf) return rffi.wcharpsize2unicode(src, length) @@ -126,7 +134,8 @@ finally: rffi.free_nonmovingbuffer(stringdata, inbuf) -def multibytecodec_decerror(decodebuf, e): +def multibytecodec_decerror(decodebuf, e, errors, + errorcb, namecb, stringdata): if e > 0: reason = "illegal multibyte sequence" esize = e @@ -138,12 +147,27 @@ else: raise RuntimeError # - # if errors == ERROR_REPLACE:... - # if errors == ERROR_IGNORE or errors == ERROR_REPLACE:... + # compute the unicode to use as a replacement -> 'replace', and + # the current position in the input 'unicodedata' -> 'end' start = pypy_cjk_dec_inbuf_consumed(decodebuf) end = start + esize - if 1: # errors == ERROR_STRICT: + if errors == "strict": raise EncodeDecodeError(start, end, reason) + elif errors == "ignore": + replace = u"" + elif errors == "replace": + replace = UNICODE_REPLACEMENT_CHARACTER + else: + assert errorcb + replace, end = errorcb(errors, namecb, reason, + stringdata, start, end) + inbuf = rffi.get_nonmoving_unicodebuffer(replace) + try: + r = pypy_cjk_dec_replace_on_error(decodebuf, inbuf, len(replace), end) + finally: + rffi.free_nonmoving_unicodebuffer(replace, inbuf) + if r == MBERR_NOMEMORY: + raise MemoryError # ____________________________________________________________ # Encoding @@ -165,8 +189,12 @@ [ENCODEBUF_P], rffi.SSIZE_T) pypy_cjk_enc_inbuf_consumed = llexternal('pypy_cjk_enc_inbuf_consumed', [ENCODEBUF_P], rffi.SSIZE_T) +pypy_cjk_enc_replace_on_error = llexternal('pypy_cjk_enc_replace_on_error', + [ENCODEBUF_P, rffi.CCHARP, + rffi.SSIZE_T, rffi.SSIZE_T], + rffi.SSIZE_T) -def encode(codec, unicodedata): +def encode(codec, unicodedata, errors="strict", errorcb=None, namecb=None): inleft = len(unicodedata) inbuf = rffi.get_nonmoving_unicodebuffer(unicodedata) try: @@ -174,14 +202,18 @@ if not encodebuf: raise MemoryError try: - r = pypy_cjk_enc_chunk(encodebuf) - if r != 0: - multibytecodec_encerror(encodebuf, r) - assert False - r = pypy_cjk_enc_reset(encodebuf) - if r != 0: - multibytecodec_encerror(encodebuf, r) - assert False + while True: + r = pypy_cjk_enc_chunk(encodebuf) + if r == 0: + break + multibytecodec_encerror(encodebuf, r, errors, + codec, errorcb, namecb, unicodedata) + while True: + r = pypy_cjk_enc_reset(encodebuf) + if r == 0: + break + multibytecodec_encerror(encodebuf, r, errors, + codec, errorcb, namecb, unicodedata) src = pypy_cjk_enc_outbuf(encodebuf) length = pypy_cjk_enc_outlen(encodebuf) return rffi.charpsize2str(src, length) @@ -192,7 +224,8 @@ finally: rffi.free_nonmoving_unicodebuffer(unicodedata, inbuf) -def multibytecodec_encerror(encodebuf, e): +def multibytecodec_encerror(encodebuf, e, errors, + codec, errorcb, namecb, unicodedata): if e > 0: reason = "illegal multibyte sequence" esize = e @@ -204,9 +237,27 @@ else: raise RuntimeError # - # if errors == ERROR_REPLACE:... - # if errors == ERROR_IGNORE or errors == ERROR_REPLACE:... + # compute the string to use as a replacement -> 'replace', and + # the current position in the input 'unicodedata' -> 'end' start = pypy_cjk_enc_inbuf_consumed(encodebuf) end = start + esize - if 1: # errors == ERROR_STRICT: + if errors == "strict": raise EncodeDecodeError(start, end, reason) + elif errors == "ignore": + replace = "" + elif errors == "replace": + try: + replace = encode(codec, u"?") + except EncodeDecodeError: + replace = "?" + else: + assert errorcb + replace, end = errorcb(errors, namecb, reason, + unicodedata, start, end) + inbuf = rffi.get_nonmovingbuffer(replace) + try: + r = pypy_cjk_enc_replace_on_error(encodebuf, inbuf, len(replace), end) + finally: + rffi.free_nonmovingbuffer(replace, inbuf) + if r == MBERR_NOMEMORY: + raise MemoryError diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -3,6 +3,7 @@ from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs +from pypy.module._codecs.interp_codecs import CodecState class MultibyteCodec(Wrappable): @@ -13,13 +14,13 @@ @unwrap_spec(input=str, errors="str_or_None") def decode(self, space, input, errors=None): - if errors is not None and errors != 'strict': - raise OperationError(space.w_NotImplementedError, # XXX - space.wrap("errors='%s' in _multibytecodec" - % errors)) + if errors is None: + errors = 'strict' + state = space.fromcache(CodecState) # try: - output = c_codecs.decode(self.codec, input) + output = c_codecs.decode(self.codec, input, errors, + state.decode_error_handler, self.name) except c_codecs.EncodeDecodeError, e: raise OperationError( space.w_UnicodeDecodeError, @@ -37,13 +38,13 @@ @unwrap_spec(input=unicode, errors="str_or_None") def encode(self, space, input, errors=None): - if errors is not None and errors != 'strict': - raise OperationError(space.w_NotImplementedError, # XXX - space.wrap("errors='%s' in _multibytecodec" - % errors)) + if errors is None: + errors = 'strict' + state = space.fromcache(CodecState) # try: - output = c_codecs.encode(self.codec, input) + output = c_codecs.encode(self.codec, input, errors, + state.encode_error_handler, self.name) except c_codecs.EncodeDecodeError, e: raise OperationError( space.w_UnicodeEncodeError, diff --git a/pypy/module/_multibytecodec/test/test_app_codecs.py b/pypy/module/_multibytecodec/test/test_app_codecs.py --- a/pypy/module/_multibytecodec/test/test_app_codecs.py +++ b/pypy/module/_multibytecodec/test/test_app_codecs.py @@ -36,6 +36,37 @@ e = raises(UnicodeDecodeError, codec.decode, "~{xyz}").value assert e.args == ('hz', '~{xyz}', 2, 4, 'illegal multibyte sequence') + def test_decode_hz_ignore(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.decode("def~{}abc", errors='ignore') + assert r == (u'def\u5fcf', 9) + r = codec.decode("def~{}abc", 'ignore') + assert r == (u'def\u5fcf', 9) + + def test_decode_hz_replace(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.decode("def~{}abc", errors='replace') + assert r == (u'def\ufffd\u5fcf', 9) + r = codec.decode("def~{}abc", 'replace') + assert r == (u'def\ufffd\u5fcf', 9) + + def test_decode_custom_error_handler(self): + import codecs + codecs.register_error("test.decode_custom_error_handler", + lambda e: (u'\u1234\u5678', e.end)) + u = "abc\xDD".decode("hz", "test.decode_custom_error_handler") + assert u == u'abc\u1234\u5678' + + def test_decode_custom_error_handler_overflow(self): + import codecs + import sys + codecs.register_error("test.test_decode_custom_error_handler_overflow", + lambda e: (u'', sys.maxint + 1)) + raises((IndexError, OverflowError), "abc\xDD".decode, "hz", + "test.test_decode_custom_error_handler_overflow") + def test_encode_hz(self): import _codecs_cn codec = _codecs_cn.getcodec("hz") @@ -54,3 +85,24 @@ assert e.start == 3 assert e.end == 4 assert e.reason == 'illegal multibyte sequence' + + def test_encode_hz_ignore(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.encode(u'abc\u1234def', 'ignore') + assert r == ('abcdef', 7) + assert type(r[0]) is str + + def test_encode_hz_replace(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.encode(u'abc\u1234def', 'replace') + assert r == ('abc?def', 7) + assert type(r[0]) is str + + def test_encode_custom_error_handler(self): + import codecs + codecs.register_error("test.multi_bad_handler", lambda e: (repl, 1)) + repl = u"\u2014" + s = u"\uDDA1".encode("gbk", "test.multi_bad_handler") + assert s == '\xA1\xAA' diff --git a/pypy/module/_multibytecodec/test/test_c_codecs.py b/pypy/module/_multibytecodec/test/test_c_codecs.py --- a/pypy/module/_multibytecodec/test/test_c_codecs.py +++ b/pypy/module/_multibytecodec/test/test_c_codecs.py @@ -36,6 +36,16 @@ assert e.end == 4 assert e.reason == "illegal multibyte sequence" +def test_decode_hz_ignore(): + c = getcodec("hz") + u = decode(c, 'def~{}abc', 'ignore') + assert u == u'def\u5fcf' + +def test_decode_hz_replace(): + c = getcodec("hz") + u = decode(c, 'def~{}abc', 'replace') + assert u == u'def\ufffd\u5fcf' + def test_encode_hz(): c = getcodec("hz") s = encode(c, u'foobar') @@ -51,6 +61,16 @@ assert e.end == 4 assert e.reason == "illegal multibyte sequence" +def test_encode_hz_ignore(): + c = getcodec("hz") + s = encode(c, u'abc\u1234def', 'ignore') + assert s == 'abcdef' + +def test_encode_hz_replace(): + c = getcodec("hz") + s = encode(c, u'abc\u1234def', 'replace') + assert s == 'abc?def' + def test_encode_jisx0208(): c = getcodec('iso2022_jp') s = encode(c, u'\u83ca\u5730\u6642\u592b') diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_multiprocessing/test/test_memory.py b/pypy/module/_multiprocessing/test/test_memory.py --- a/pypy/module/_multiprocessing/test/test_memory.py +++ b/pypy/module/_multiprocessing/test/test_memory.py @@ -3,7 +3,7 @@ class AppTestMemory: def setup_class(cls): space = gettestobjspace( - usemodules=('_multiprocessing', 'mmap', '_rawffi')) + usemodules=('_multiprocessing', 'mmap', '_rawffi', '_ffi')) cls.space = space def test_address_of(self): diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -176,7 +176,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + elif (_MS_WINDOWS and space.is_true(space.isinstance(w_name, space.w_int))): ordinal = space.int_w(w_name) @@ -250,11 +250,18 @@ def get_basic_ffi_type(self): raise NotImplementedError + def descr_get_ffi_type(self, space): + # XXX: this assumes that you have the _ffi module enabled. In the long + # term, probably we will move the code for build structures and arrays + # from _rawffi to _ffi + from pypy.module._ffi.interp_ffi import W_FFIType + return W_FFIType('', self.get_basic_ffi_type(), self) + @unwrap_spec(n=int) def descr_size_alignment(self, space, n=1): return space.newtuple([space.wrap(self.size * n), space.wrap(self.alignment)]) - + class W_DataInstance(Wrappable): def __init__(self, space, size, address=r_uint(0)): @@ -420,7 +427,7 @@ if not (argletter in TYPEMAP_PTR_LETTERS and letter in TYPEMAP_PTR_LETTERS): msg = "Argument %d should be typecode %s, got %s" - raise operationerrfmt(space.w_TypeError, msg, + raise operationerrfmt(space.w_TypeError, msg, i+1, argletter, letter) args_ll.append(arg.ll_buffer) # XXX we could avoid the intermediate list args_ll @@ -473,17 +480,25 @@ alignment = _create_new_accessor('alignment', 'c_alignment') @unwrap_spec(address=r_uint, maxlength=int) -def charp2string(space, address, maxlength=sys.maxint): +def charp2string(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.charp2strn(rffi.cast(rffi.CCHARP, address), maxlength) + charp_addr = rffi.cast(rffi.CCHARP, address) + if maxlength == -1: + s = rffi.charp2str(charp_addr) + else: + s = rffi.charp2strn(charp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) -def wcharp2unicode(space, address, maxlength=sys.maxint): +def wcharp2unicode(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.wcharp2unicoden(rffi.cast(rffi.CWCHARP, address), maxlength) + wcharp_addr = rffi.cast(rffi.CWCHARP, address) + if maxlength == -1: + s = rffi.wcharp2unicode(wcharp_addr) + else: + s = rffi.wcharp2unicoden(wcharp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) diff --git a/pypy/module/_rawffi/structure.py b/pypy/module/_rawffi/structure.py --- a/pypy/module/_rawffi/structure.py +++ b/pypy/module/_rawffi/structure.py @@ -248,7 +248,8 @@ alignment = interp_attrproperty('alignment', W_Structure), fieldoffset = interp2app(W_Structure.descr_fieldoffset), fieldsize = interp2app(W_Structure.descr_fieldsize), - size_alignment = interp2app(W_Structure.descr_size_alignment) + size_alignment = interp2app(W_Structure.descr_size_alignment), + get_ffi_type = interp2app(W_Structure.descr_get_ffi_type), ) W_Structure.typedef.acceptable_as_base_class = False diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,3 +1,4 @@ +from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable @@ -899,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_stackless/test/test_greenlet.py b/pypy/module/_stackless/test/test_greenlet.py --- a/pypy/module/_stackless/test/test_greenlet.py +++ b/pypy/module/_stackless/test/test_greenlet.py @@ -72,6 +72,23 @@ g1 = greenlet(f) raises(ValueError, g2.switch) + + def test_exc_info_save_restore(self): + from _stackless import greenlet + import sys + def f(): + try: + raise ValueError('fun') + except: + exc_info = sys.exc_info() + greenlet(h).switch() + assert exc_info == sys.exc_info() + + def h(): + assert sys.exc_info() == (None, None, None) + + greenlet(f).switch() + def test_exception(self): from _stackless import greenlet import sys diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,21 @@ from __future__ import with_statement +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -37,7 +40,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -73,6 +76,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +100,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +163,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -268,12 +270,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -311,6 +311,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -319,12 +327,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -387,7 +390,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -395,7 +398,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -413,7 +416,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -515,26 +518,18 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() - s = ''.join([cbuf[i] for i in xrange(self.len * mytype.bytes)]) - return self.space.wrap(s) -## -## s = '' -## i = 0 -## while i < self.len * mytype.bytes: -## s += cbuf[i] -## i += 1 -## return self.space.wrap(s) + return self.space.wrap(rffi.charpsize2str(cbuf, self.len * mytype.bytes)) def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): if not isinstance(w_f, W_File): @@ -577,10 +572,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): @@ -623,6 +615,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) + return w_a + def array_byteswap__Array(space, self): if mytype.bytes not in [1, 2, 4, 8]: msg = "byteswap not supported for this array" diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -39,6 +39,7 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject +import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject import pypy.module.cpyext.longobject @@ -64,6 +65,7 @@ import pypy.module.cpyext.memoryobject import pypy.module.cpyext.codecs import pypy.module.cpyext.pyfile +import pypy.module.cpyext.pystrtod # now that all rffi_platform.Struct types are registered, configure them api.configure_types() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -348,6 +348,7 @@ '_Py_TrueStruct#': ('PyObject*', 'space.w_True'), '_Py_ZeroStruct#': ('PyObject*', 'space.w_False'), '_Py_NotImplementedStruct#': ('PyObject*', 'space.w_NotImplemented'), + '_Py_EllipsisObject#': ('PyObject*', 'space.w_Ellipsis'), 'PyDateTimeAPI': ('PyDateTime_CAPI*', 'None'), } FORWARD_DECLS = [] @@ -561,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/pystrtod.py @@ -0,0 +1,68 @@ +import errno +from pypy.interpreter.error import OperationError +from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.pyobject import PyObject +from pypy.rlib import rdtoa +from pypy.rlib import rfloat +from pypy.rlib import rposix +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi + + + at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +def PyOS_string_to_double(space, s, endptr, w_overflow_exception): + """Convert a string s to a double, raising a Python + exception on failure. The set of accepted strings corresponds to + the set of strings accepted by Python's float() constructor, + except that s must not have leading or trailing whitespace. + The conversion is independent of the current locale. + + If endptr is NULL, convert the whole string. Raise + ValueError and return -1.0 if the string is not a valid + representation of a floating-point number. + + If endptr is not NULL, convert as much of the string as + possible and set *endptr to point to the first unconverted + character. If no initial segment of the string is the valid + representation of a floating-point number, set *endptr to point + to the beginning of the string, raise ValueError, and return + -1.0. + + If s represents a value that is too large to store in a float + (for example, "1e500" is such a string on many platforms) then + if overflow_exception is NULL return Py_HUGE_VAL (with + an appropriate sign) and don't set any exception. Otherwise, + overflow_exception must point to a Python exception object; + raise that exception and return -1.0. In both cases, set + *endptr to point to the first character after the converted value. + + If any other error occurs during the conversion (for example an + out-of-memory error), set the appropriate Python exception and + return -1.0. + """ + user_endptr = True + try: + if not endptr: + endptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + user_endptr = False + result = rdtoa.dg_strtod(s, endptr) + endpos = (rffi.cast(rffi.LONG, endptr[0]) - + rffi.cast(rffi.LONG, s)) + if endpos == 0 or (not user_endptr and not endptr[0][0] == '\0'): + raise OperationError( + space.w_ValueError, + space.wrap('invalid input at position %s' % endpos)) + if rposix.get_errno() == errno.ERANGE: + rposix.set_errno(0) + if w_overflow_exception is None: + if result > 0: + return rfloat.INFINITY + else: + return -rfloat.INFINITY + else: + raise OperationError(w_overflow_exception, + space.wrap('value too large')) + return result + finally: + if not user_endptr: + lltype.free(endptr, flavor='raw') diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/setobject.py @@ -0,0 +1,46 @@ +from pypy.interpreter.error import OperationError +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, + build_type_checkers) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, + borrow_from, make_ref, from_ref) +from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall +from pypy.objspace.std.setobject import W_SetObject, newset +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject + + +PySet_Check, PySet_CheckExact = build_type_checkers("Set") + + + at cpython_api([PyObject], PyObject) +def PySet_New(space, w_iterable): + if w_iterable is None: + return space.call_function(space.w_set) + else: + return space.call_function(space.w_set, w_iterable) + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Add(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'add', w_obj) + return 0 + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Discard(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'discard', w_obj) + return 0 + + + at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +def PySet_GET_SIZE(space, w_s): + return space.int_w(space.len(w_s)) + + at cpython_api([PyObject], Py_ssize_t, error=-1) +def PySet_Size(space, ref): + if not PySet_Check(space, ref): + raise OperationError(space.w_TypeError, + space.wrap("expected set object")) + return PySet_GET_SIZE(space, ref) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -480,39 +480,6 @@ """Create a new Python complex number object from a C Py_complex value.""" raise NotImplementedError - at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) -def PyOS_string_to_double(space, s, endptr, overflow_exception): - """Convert a string s to a double, raising a Python - exception on failure. The set of accepted strings corresponds to - the set of strings accepted by Python's float() constructor, - except that s must not have leading or trailing whitespace. - The conversion is independent of the current locale. - - If endptr is NULL, convert the whole string. Raise - ValueError and return -1.0 if the string is not a valid - representation of a floating-point number. - - If endptr is not NULL, convert as much of the string as - possible and set *endptr to point to the first unconverted - character. If no initial segment of the string is the valid - representation of a floating-point number, set *endptr to point - to the beginning of the string, raise ValueError, and return - -1.0. - - If s represents a value that is too large to store in a float - (for example, "1e500" is such a string on many platforms) then - if overflow_exception is NULL return Py_HUGE_VAL (with - an appropriate sign) and don't set any exception. Otherwise, - overflow_exception must point to a Python exception object; - raise that exception and return -1.0. In both cases, set - *endptr to point to the first character after the converted value. - - If any other error occurs during the conversion (for example an - out-of-memory error), set the appropriate Python exception and - return -1.0. - """ - raise NotImplementedError - @cpython_api([rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_strtod(space, nptr, endptr): """Convert a string to a double. This function behaves like the Standard C diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -0,0 +1,93 @@ +import math + +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype + + +class TestPyOS_string_to_double(BaseApiTest): + + def test_simple_float(self, api): + s = rffi.str2charp('0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == 0.4 + rffi.free_charp(s) + + def test_empty_string(self, api): + s = rffi.str2charp('') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_bad_string(self, api): + s = rffi.str2charp(' 0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_overflow_pos(self, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r > 0 + rffi.free_charp(s) + + def test_overflow_neg(self, api): + s = rffi.str2charp('-1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r < 0 + rffi.free_charp(s) + + def test_overflow_exc(self, space, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, space.w_ValueError) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_endptr_number(self, api): + s = rffi.str2charp('0.4') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_tail(self, api): + s = rffi.str2charp('0.4 foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_no_conversion(self, api): + s = rffi.str2charp('foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == -1.0 + raises(ValueError) + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + api.PyErr_Clear() + rffi.free_charp(s) + lltype.free(endp, flavor='raw') diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_setobject.py @@ -0,0 +1,29 @@ +import py + +from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace + + +class TestTupleObject(BaseApiTest): + def test_setobj(self, space, api): + assert not api.PySet_Check(space.w_None) + assert api.PySet_Add(space.w_None, space.w_None) == -1 + api.PyErr_Clear() + w_set = space.call_function(space.w_set) + space.call_method(w_set, 'update', space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + assert api.PySet_GET_SIZE(w_set) == 4 + raises(TypeError, api.PySet_Size(space.newlist([]))) + api.PyErr_Clear() + + def test_set_add_discard(self, space, api): + w_set = api.PySet_New(None) + assert api.PySet_Size(w_set) == 0 + w_set = api.PySet_New(space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + api.PySet_Add(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 5 + api.PySet_Discard(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 4 diff --git a/pypy/module/cpyext/test/test_sliceobject.py b/pypy/module/cpyext/test/test_sliceobject.py --- a/pypy/module/cpyext/test/test_sliceobject.py +++ b/pypy/module/cpyext/test/test_sliceobject.py @@ -67,3 +67,14 @@ """), ]) assert module.nullslice() == slice(None, None, None) + + def test_ellipsis(self): + module = self.import_extension('foo', [ + ("get_ellipsis", "METH_NOARGS", + """ + PyObject *ret = Py_Ellipsis; + Py_INCREF(ret); + return ret; + """), + ]) + assert module.get_ellipsis() is Ellipsis diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -367,3 +367,14 @@ data, len(u), lltype.nullptr(rffi.CCHARP.TO)) rffi.free_wcharp(data) + def test_format(self, space, api): + w_format = space.wrap(u'hi %s') + w_args = space.wrap((u'test',)) + w_formated = api.PyUnicode_Format(w_format, w_args) + assert space.unwrap(w_formated) == space.unwrap(space.mod(w_format, w_args)) + + def test_join(self, space, api): + w_sep = space.wrap(u'') + w_seq = space.wrap([u'a', u'b']) + w_joined = api.PyUnicode_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == u'ab' diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,6 +7,7 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) + assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -523,3 +523,11 @@ copies sizeof(Py_UNICODE) * length bytes from source to target""" for i in range(0, length): target[i] = source[i] + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Format(space, w_format, w_args): + return space.mod(w_format, w_args) + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -21,6 +21,10 @@ """Return the referenced object from a weak reference. If the referent is no longer live, returns None. This function returns a borrowed reference. """ + return PyWeakref_GET_OBJECT(space, w_ref) + + at cpython_api([PyObject], PyObject) +def PyWeakref_GET_OBJECT(space, w_ref): return borrow_from(w_ref, space.call_function(w_ref)) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -622,7 +622,13 @@ try: if find_info: w_mod = load_module(space, w_modulename, find_info) - w_mod = space.getitem(space.sys.get("modules"), w_modulename) + try: + w_mod = space.getitem(space.sys.get("modules"), + w_modulename) + except OperationError, oe: + if not oe.match(space, space.w_KeyError): + raise + raise OperationError(space.w_ImportError, w_modulename) if w_parent is not None: space.setattr(w_parent, space.wrap(partname), w_mod) return w_mod @@ -793,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -823,8 +828,6 @@ return struct.unpack('= 0") + res = 1 + for i in range(1, x + 1): + res *= i + return res diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -373,22 +373,6 @@ hi = v return space.wrap(hi) -def factorial(space, w_x): - """Find x!.""" - if space.isinstance_w(w_x, space.w_float): - fl = space.float_w(w_x) - if math.floor(fl) != fl: - raise OperationError(space.w_ValueError, - space.wrap("float arguments must be integral")) - w_x = space.long(w_x) - x = space.int_w(w_x) - if x < 0: - raise OperationError(space.w_ValueError, space.wrap("x must be >= 0")) - w_res = space.wrap(1) - for i in range(1, x + 1): - w_res = space.mul(w_res, space.wrap(i)) - return w_res - def log1p(space, w_x): """Find log(x + 1).""" return math1(space, rfloat.log1p, w_x) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -8,11 +8,16 @@ interpleveldefs = { 'array': 'interp_numarray.SingleDimArray', 'zeros': 'interp_numarray.zeros', + 'empty': 'interp_numarray.zeros', + 'ones': 'interp_numarray.ones', + 'fromstring': 'interp_support.fromstring', # ufuncs + 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', 'copysign': 'interp_ufuncs.copysign', 'exp': 'interp_ufuncs.exp', + 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', 'negative': 'interp_ufuncs.negative', @@ -20,4 +25,7 @@ 'sign': 'interp_ufuncs.sign', } - appleveldefs = {} + appleveldefs = { + 'average': 'app_numpy.average', + 'mean': 'app_numpy.mean', + } diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/app_numpy.py @@ -0,0 +1,11 @@ +import numpy + +def average(a): + # This implements a weighted average, for now we don't implement the + # weighting, just the average part! + return mean(a) + +def mean(a): + if not hasattr(a, "mean"): + a = numpy.array(a) + return a.mean() \ No newline at end of file diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/compile.py @@ -0,0 +1,54 @@ + +""" This is a set of tools for standalone compiling of numpy expressions. +It should not be imported by the module itself +""" + +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray + +class BogusBytecode(Exception): + pass + +def create_array(size): + a = SingleDimArray(size) + for i in range(size): + a.storage[i] = float(i % 10) + return a + +class TrivialSpace(object): + def wrap(self, x): + return x + +def numpy_compile(bytecode, array_size): + space = TrivialSpace() + stack = [] + i = 0 + for b in bytecode: + if b == 'a': + stack.append(create_array(array_size)) + i += 1 + elif b == 'f': + stack.append(FloatWrapper(1.2)) + elif b == '+': + right = stack.pop() + stack.append(stack.pop().descr_add(space, right)) + elif b == '-': + right = stack.pop() + stack.append(stack.pop().descr_sub(space, right)) + elif b == '*': + right = stack.pop() + stack.append(stack.pop().descr_mul(space, right)) + elif b == '/': + right = stack.pop() + stack.append(stack.pop().descr_div(space, right)) + elif b == '%': + right = stack.pop() + stack.append(stack.pop().descr_mod(space, right)) + elif b == '|': + stack.append(stack.pop().descr_abs(space)) + else: + print "Unknown opcode: %s" % b + raise BogusBytecode() + if len(stack) != 1: + print "Bogus bytecode, uneven stack length" + raise BogusBytecode() + return stack[0] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,10 +1,11 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.error import operationerrfmt, OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name +import math def dummy1(v): @@ -19,6 +20,8 @@ numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) +all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) class Signature(object): def __init__(self): @@ -30,6 +33,12 @@ self.transitions[target] = new = Signature() return new +def pos(v): + return v +def neg(v): + return -v +def absolute(v): + return abs(v) def add(v1, v2): return v1 + v2 def sub(v1, v2): @@ -38,15 +47,43 @@ return v1 * v2 def div(v1, v2): return v1 / v2 +def power(v1, v2): + return math.pow(v1, v2) +def mod(v1, v2): + return math.fmod(v1, v2) +def maximum(v1, v2): + return max(v1, v2) +def minimum(v1, v2): + return min(v1, v2) class BaseArray(Wrappable): def __init__(self): self.invalidates = [] def invalidated(self): + if self.invalidates: + self._invalidated() + + def _invalidated(self): for arr in self.invalidates: arr.force_if_needed() - self.invalidates = [] + del self.invalidates[:] + + def _unop_impl(function): + signature = Signature() + def impl(self, space): + new_sig = self.signature.transition(signature) + res = Call1( + function, + self, + new_sig) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + + descr_pos = _unop_impl(pos) + descr_neg = _unop_impl(neg) + descr_abs = _unop_impl(absolute) def _binop_impl(function): signature = Signature() @@ -76,22 +113,164 @@ descr_sub = _binop_impl(sub) descr_mul = _binop_impl(mul) descr_div = _binop_impl(div) + descr_pow = _binop_impl(power) + descr_mod = _binop_impl(mod) + + def _binop_right_impl(function): + signature = Signature() + def impl(self, space, w_other): + new_sig = self.signature.transition(signature) + w_other = FloatWrapper(space.float_w(w_other)) + res = Call2( + function, + w_other, + self, + new_sig.transition(w_other.signature) + ) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, + "binop_right_%s_impl" % function.__name__) + + descr_radd = _binop_right_impl(add) + descr_rsub = _binop_right_impl(sub) + descr_rmul = _binop_right_impl(mul) + descr_rdiv = _binop_right_impl(div) + descr_rpow = _binop_right_impl(power) + descr_rmod = _binop_right_impl(mod) + + def _reduce_sum_prod_impl(function, init): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + return space.wrap(loop(self, init, self.find_size())) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_max_min_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, result, size): + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, self.eval(0), size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_argmax_argmin_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self', 'cur_best']) + def loop(self, size): + result = 0 + cur_best = self.eval(0) + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result, cur_best=cur_best) + new_best = function(cur_best, self.eval(i)) + if new_best != cur_best: + result = i + cur_best = new_best + i += 1 + return result + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, size)) + return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) + + def _all(self): + size = self.find_size() + i = 0 + while i < size: + all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if not self.eval(i): + return False + i += 1 + return True + def descr_all(self, space): + return space.wrap(self._all()) + + def _any(self): + size = self.find_size() + i = 0 + while i < size: + any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if self.eval(i): + return True + i += 1 + return False + def descr_any(self, space): + return space.wrap(self._any()) + + descr_sum = _reduce_sum_prod_impl(add, 0.0) + descr_prod = _reduce_sum_prod_impl(mul, 1.0) + descr_max = _reduce_max_min_impl(maximum) + descr_min = _reduce_max_min_impl(minimum) + descr_argmax = _reduce_argmax_argmin_impl(maximum) + descr_argmin = _reduce_argmax_argmin_impl(minimum) + + def descr_dot(self, space, w_other): + if isinstance(w_other, BaseArray): + w_res = self.descr_mul(space, w_other) + assert isinstance(w_res, BaseArray) + return w_res.descr_sum(space) + else: + return self.descr_mul(space, w_other) def get_concrete(self): raise NotImplementedError + def descr_get_shape(self, space): + return space.newtuple([self.descr_len(space)]) + def descr_len(self, space): return self.get_concrete().descr_len(space) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - return self.get_concrete().descr_getitem(space, item) + def descr_getitem(self, space, w_idx): + # TODO: indexing by tuples + start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) + if step == 0: + # Single index + return space.wrap(self.get_concrete().getitem(start)) + else: + # Slice + res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) + return space.wrap(res) @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): self.invalidated() return self.get_concrete().descr_setitem(space, item, value) + def descr_mean(self, space): + return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) class FloatWrapper(BaseArray): """ @@ -119,6 +298,10 @@ self.forced_result = None self.signature = signature + def _del_sources(self): + # Function for deleting references to source arrays, to allow garbage-collecting them + raise NotImplementedError + def compute(self): i = 0 signature = self.signature @@ -135,6 +318,7 @@ def force_if_needed(self): if self.forced_result is None: self.forced_result = self.compute() + self._del_sources() def get_concrete(self): self.force_if_needed() @@ -145,6 +329,13 @@ return self.forced_result.eval(i) return self._eval(i) + def find_size(self): + if self.forced_result is not None: + # The result has been computed and sources may be unavailable + return self.forced_result.find_size() + return self._find_size() + + class Call1(VirtualArray): _immutable_fields_ = ["function", "values"] @@ -153,7 +344,10 @@ self.function = function self.values = values - def find_size(self): + def _del_sources(self): + self.values = None + + def _find_size(self): return self.values.find_size() def _eval(self, i): @@ -164,13 +358,18 @@ Intermediate class for performing binary operations. """ _immutable_fields_ = ["function", "left", "right"] + def __init__(self, function, left, right, signature): VirtualArray.__init__(self, signature) self.function = function self.left = left self.right = right - def find_size(self): + def _del_sources(self): + self.left = None + self.right = None + + def _find_size(self): try: return self.left.find_size() except ValueError: @@ -181,6 +380,58 @@ lhs, rhs = self.left.eval(i), self.right.eval(i) return self.function(lhs, rhs) +class ViewArray(BaseArray): + """ + Class for representing views of arrays, they will reflect changes of parent + arrays. Example: slices + """ + _immutable_fields_ = ["parent"] + + def __init__(self, parent, signature): + BaseArray.__init__(self) + self.signature = signature + self.parent = parent + self.invalidates = parent.invalidates + + def get_concrete(self): + # in fact, ViewArray never gets "concrete" as it never stores data. + # This implementation is needed for BaseArray getitem/setitem to work, + # can be refactored. + return self + + def eval(self, i): + return self.parent.eval(self.calc_index(i)) + + def getitem(self, item): + return self.parent.getitem(self.calc_index(item)) + + @unwrap_spec(item=int, value=float) + def descr_setitem(self, space, item, value): + return self.parent.descr_setitem(space, self.calc_index(item), value) + + def descr_len(self, space): + return space.wrap(self.find_size()) + + def calc_index(self, item): + raise NotImplementedError + +class SingleDimSlice(ViewArray): + _immutable_fields_ = ["start", "stop", "step", "size"] + static_signature = Signature() + + def __init__(self, start, stop, step, slice_length, parent, signature): + ViewArray.__init__(self, parent, signature) + self.start = start + self.stop = stop + self.step = step + self.size = slice_length + + def find_size(self): + return self.size + + def calc_index(self, item): + return (self.start + item * self.step) + class SingleDimArray(BaseArray): signature = Signature() @@ -215,10 +466,8 @@ def descr_len(self, space): return space.wrap(self.size) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - item = self.getindex(space, item) - return space.wrap(self.storage[item]) + def getitem(self, item): + return self.storage[item] @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): @@ -238,20 +487,51 @@ i += 1 return space.wrap(arr) - at unwrap_spec(ObjSpace, int) + at unwrap_spec(size=int) def zeros(space, size): return space.wrap(SingleDimArray(size)) + at unwrap_spec(size=int) +def ones(space, size): + arr = SingleDimArray(size) + for i in xrange(size): + arr.storage[i] = 1.0 + return space.wrap(arr) BaseArray.typedef = TypeDef( 'numarray', __new__ = interp2app(descr_new_numarray), + + shape = GetSetProperty(BaseArray.descr_get_shape), + __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), __setitem__ = interp2app(BaseArray.descr_setitem), + __pos__ = interp2app(BaseArray.descr_pos), + __neg__ = interp2app(BaseArray.descr_neg), + __abs__ = interp2app(BaseArray.descr_abs), __add__ = interp2app(BaseArray.descr_add), __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), __div__ = interp2app(BaseArray.descr_div), -) \ No newline at end of file + __pow__ = interp2app(BaseArray.descr_pow), + __mod__ = interp2app(BaseArray.descr_mod), + __radd__ = interp2app(BaseArray.descr_radd), + __rsub__ = interp2app(BaseArray.descr_rsub), + __rmul__ = interp2app(BaseArray.descr_rmul), + __rdiv__ = interp2app(BaseArray.descr_rdiv), + __rpow__ = interp2app(BaseArray.descr_rpow), + __rmod__ = interp2app(BaseArray.descr_rmod), + + mean = interp2app(BaseArray.descr_mean), + sum = interp2app(BaseArray.descr_sum), + prod = interp2app(BaseArray.descr_prod), + max = interp2app(BaseArray.descr_max), + min = interp2app(BaseArray.descr_min), + argmax = interp2app(BaseArray.descr_argmax), + argmin = interp2app(BaseArray.descr_argmin), + all = interp2app(BaseArray.descr_all), + any = interp2app(BaseArray.descr_any), + dot = interp2app(BaseArray.descr_dot), +) diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_support.py @@ -0,0 +1,32 @@ + +from pypy.rlib.rstruct.runpack import runpack +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.error import OperationError +from pypy.module.micronumpy.interp_numarray import SingleDimArray + +FLOAT_SIZE = rffi.sizeof(lltype.Float) + + at unwrap_spec(s=str) +def fromstring(space, s): + length = len(s) + + if length % FLOAT_SIZE == 0: + number = length/FLOAT_SIZE + else: + raise OperationError(space.w_ValueError, space.wrap( + "string length %d not divisable by %d" % (length, FLOAT_SIZE))) + + a = SingleDimArray(number) + + start = 0 + end = FLOAT_SIZE + i = 0 + while i < number: + part = s[start:end] + a.storage[i] = runpack('d', part) + i += 1 + start += FLOAT_SIZE + end += FLOAT_SIZE + + return space.wrap(a) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -8,22 +8,24 @@ def ufunc(func): signature = Signature() - @unwrap_spec(array=BaseArray) - def impl(space, array): - w_res = Call1(func, array, array.signature.transition(signature)) - array.invalidates.append(w_res) - return w_res + def impl(space, w_obj): + if isinstance(w_obj, BaseArray): + w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) + w_obj.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() - @unwrap_spec(larray=BaseArray, rarray=BaseArray) - def impl(space, larray, rarray): - new_sig = larray.signature.transition(signature).transition(rarray.signature) - w_res = Call2(func, larray, rarray, new_sig) - larray.invalidates.append(w_res) - rarray.invalidates.append(w_res) - return w_res + def impl(space, w_lhs, w_rhs): + if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): + new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) + w_res = Call2(func, w_lhs, w_rhs, new_sig) + w_lhs.invalidates.append(w_res) + w_rhs.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @ufunc @@ -60,6 +62,10 @@ return 1.0 / value @ufunc +def floor(value): + return math.floor(value) + + at ufunc def sign(value): if value == 0.0: return 0.0 diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -16,4 +16,14 @@ v3 = ar.descr_add(space, FloatWrapper(1.0)) assert v2.signature is v3.signature v4 = ar.descr_add(space, ar) - assert v1.signature is v4.signature \ No newline at end of file + assert v1.signature is v4.signature + + def test_slice_signature(self, space): + ar = SingleDimArray(10) + v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1))) + v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1))) + assert v1.signature is v2.signature + + v3 = ar.descr_add(space, v1) + v4 = ar.descr_add(space, v2) + assert v3.signature is v4.signature \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_module.py b/pypy/module/micronumpy/test/test_module.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_module.py @@ -0,0 +1,13 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + + +class AppTestNumPyModule(BaseNumpyAppTest): + def test_mean(self): + from numpy import array, mean + assert mean(array(range(5))) == 2.0 + assert mean(range(5)) == 2.0 + + def test_average(self): + from numpy import array, average + assert average(range(10)) == 4.5 + assert average(array(range(10))) == 4.5 \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1,6 +1,7 @@ import py from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest +from pypy.conftest import gettestobjspace class AppTestNumArray(BaseNumpyAppTest): @@ -18,6 +19,25 @@ a[13] = 5.3 assert a[13] == 5.3 + def test_empty(self): + """ + Test that empty() works. + """ + + from numpy import empty + a = empty(2) + a[1] = 1.0 + assert a[1] == 1.0 + + def test_ones(self): + from numpy import ones + a = ones(3) + assert len(a) == 3 + assert a[0] == 1 + raises(IndexError, "a[3]") + a[2] = 4 + assert a[2] == 4 + def test_iterator_init(self): from numpy import array a = array(range(5)) @@ -46,6 +66,15 @@ assert len(a) == 5 assert len(a + a) == 5 + def test_shape(self): + from numpy import array + a = array(range(5)) + assert a.shape == (5,) + b = a + a + assert b.shape == (5,) + c = a[:3] + assert c.shape == (3,) + def test_add(self): from numpy import array a = array(range(5)) @@ -126,6 +155,72 @@ for i in range(5): assert b[i] == i / 5.0 + def test_pow(self): + from numpy import array + a = array(range(5)) + b = a ** a + for i in range(5): + print b[i], i**i + assert b[i] == i**i + + def test_pow_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a ** b + for i in range(5): + assert c[i] == i ** 2 + + def test_pow_constant(self): + from numpy import array + a = array(range(5)) + b = a ** 2 + for i in range(5): + assert b[i] == i ** 2 + + def test_mod(self): + from numpy import array + a = array(range(1,6)) + b = a % a + for i in range(5): + assert b[i] == 0 + + def test_mod_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a % b + for i in range(5): + assert c[i] == i % 2 + + def test_mod_constant(self): + from numpy import array + a = array(range(5)) + b = a % 2 + for i in range(5): + assert b[i] == i % 2 + + def test_pos(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = +a + for i in range(5): + assert b[i] == a[i] + + def test_neg(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = -a + for i in range(5): + assert b[i] == -a[i] + + def test_abs(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = abs(a) + for i in range(5): + assert b[i] == abs(a[i]) + def test_auto_force(self): from numpy import array a = array(range(5)) @@ -138,4 +233,141 @@ b = a + a c = b + b b[1] = 5 - assert c[1] == 4 \ No newline at end of file + assert c[1] == 4 + + def test_getslice(self): + from numpy import array + a = array(range(5)) + s = a[1:5] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[i+1] + + def test_getslice_step(self): + from numpy import array + a = array(range(10)) + s = a[1:9:2] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[2*i+1] + + def test_slice_update(self): + from numpy import array + a = array(range(5)) + s = a[0:3] + s[1] = 10 + assert a[1] == 10 + a[2] = 20 + assert s[2] == 20 + + + def test_slice_invaidate(self): + # check that slice shares invalidation list with + from numpy import array + a = array(range(5)) + s = a[0:2] + b = array([10,11]) + c = s + b + a[0] = 100 + assert c[0] == 10 + assert c[1] == 12 + d = s + b + a[1] = 101 + assert d[0] == 110 + assert d[1] == 12 + + def test_mean(self): + from numpy import array + a = array(range(5)) + assert a.mean() == 2.0 + assert a[:4].mean() == 1.5 + + def test_sum(self): + from numpy import array + a = array(range(5)) + assert a.sum() == 10.0 + assert a[:4].sum() == 6.0 + + def test_prod(self): + from numpy import array + a = array(range(1,6)) + assert a.prod() == 120.0 + assert a[:4].prod() == 24.0 + + def test_max(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.max() == 5.7 + b = array([]) + raises(ValueError, "b.max()") + + def test_max_add(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert (a+a).max() == 11.4 + + def test_min(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.min() == -3.0 + b = array([]) + raises(ValueError, "b.min()") + + def test_argmax(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmax() == 2 + b = array([]) + raises(ValueError, "b.argmax()") + + def test_argmin(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmin() == 3 + b = array([]) + raises(ValueError, "b.argmin()") + + def test_all(self): + from numpy import array + a = array(range(5)) + assert a.all() == False + a[0] = 3.0 + assert a.all() == True + b = array([]) + assert b.all() == True + + def test_any(self): + from numpy import array, zeros + a = array(range(5)) + assert a.any() == True + b = zeros(5) + assert b.any() == False + c = array([]) + assert c.any() == False + + def test_dot(self): + from numpy import array + a = array(range(5)) + assert a.dot(a) == 30.0 + + def test_dot_constant(self): + from numpy import array + a = array(range(5)) + b = a.dot(2.5) + for i in xrange(5): + assert b[i] == 2.5*a[i] + + +class AppTestSupport(object): + def setup_class(cls): + import struct + cls.space = gettestobjspace(usemodules=('micronumpy',)) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + + def test_fromstring(self): + from numpy import fromstring + a = fromstring(self.data) + for i in range(4): + assert a[i] == i + 1 + raises(ValueError, fromstring, "abc") + diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -3,6 +3,13 @@ class AppTestUfuncs(BaseNumpyAppTest): + def test_single_item(self): + from numpy import negative, sign, minimum + + assert negative(5.0) == -5.0 + assert sign(-0.0) == 0.0 + assert minimum(2.0, 3.0) == 2.0 + def test_negative(self): from numpy import array, negative @@ -60,6 +67,15 @@ for i in range(4): assert b[i] == reference[i] + def test_floor(self): + from numpy import array, floor + + reference = [-2.0, -1.0, 0.0, 1.0, 1.0] + a = array([-1.4, -1.0, 0.0, 1.0, 1.4]) + b = floor(a) + for i in range(5): + assert b[i] == reference[i] + def test_copysign(self): from numpy import array, copysign diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,19 +1,22 @@ from pypy.jit.metainterp.test.support import LLJitMixin +from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call1, Call2, add, mul) + FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative - +from pypy.module.micronumpy.compile import numpy_compile +from pypy.rlib.objectmodel import specialize class FakeSpace(object): - pass + w_ValueError = None + @specialize.argtype(1) + def wrap(self, v): + return v class TestNumpyJIt(LLJitMixin): def setup_class(cls): cls.space = FakeSpace() def test_add(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, ar, Signature()) @@ -26,8 +29,6 @@ assert result == f(5) def test_floatadd(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, FloatWrapper(4.5), Signature()) @@ -39,11 +40,128 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_already_forecd(self): + def test_neg(self): space = self.space def f(i): ar = SingleDimArray(i) + v = Call1(neg, ar, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, + "setarrayitem_raw": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + + assert result == f(5) + + def test_sum(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_sum(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 2, + "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_prod(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_prod(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_max(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_max(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_gt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, + "guard_false": 1, "jump": 1}) + + def test_min(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_min(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_argmin(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_argmin(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_all(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = 1.0 + j += 1 + return ar.descr_add(space, ar).descr_all(space) + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, + "int_lt": 1, "guard_true": 2, "jump": 1}) + + def test_any(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_any(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, "guard_false": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + + def test_already_forecd(self): + def f(i): + ar = SingleDimArray(i) v1 = Call2(add, ar, FloatWrapper(4.5), Signature()) v2 = Call2(mul, v1, FloatWrapper(4.5), Signature()) v1.force_if_needed() @@ -91,4 +209,50 @@ self.meta_interp(f, [5], listops=True, backendopt=True) # This is 3, not 2 because there is a bridge for the exit. - self.check_loop_count(3) \ No newline at end of file + self.check_loop_count(3) + + def test_slice(self): + def f(i): + step = 3 + ar = SingleDimArray(step*i) + s = SingleDimSlice(0, step*i, step, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s, s, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 1, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + + def test_slice2(self): + def f(i): + step1 = 2 + step2 = 3 + ar = SingleDimArray(step2*i) + s1 = SingleDimSlice(0, step1*i, step1, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + s2 = SingleDimSlice(0, step2*i, step2, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s1, s2, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 2, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + +class TestTranslation(object): + def test_compile(self): + x = numpy_compile('aa+f*f/a-', 10) + x = x.compute() + assert isinstance(x, SingleDimArray) + assert x.size == 10 + assert x.storage[0] == 0 + assert x.storage[1] == ((1 + 1) * 1.2) / 1.2 - 1 + + def test_translation(self): + # we import main to check if the target compiles + from pypy.translator.goal.targetnumpystandalone import main + from pypy.rpython.annlowlevel import llstr + + interpret(main, [llstr('af+'), 100]) diff --git a/pypy/module/operator/app_operator.py b/pypy/module/operator/app_operator.py --- a/pypy/module/operator/app_operator.py +++ b/pypy/module/operator/app_operator.py @@ -4,6 +4,7 @@ This module exports a set of operators as functions. E.g. operator.add(x,y) is equivalent to x+y. ''' +from __pypy__ import builtinify def countOf(a,b): 'countOf(a, b) -- Return the number of times b occurs in a.' @@ -66,50 +67,56 @@ a[b:c] = d __setslice__ = setslice -class attrgetter(object): - def __init__(self, attr, *attrs): - self.attrs = (attr,) + attrs +def attrgetter(attr, *attrs): + if attrs: + getters = [single_attr_getter(a) for a in (attr,) + attrs] + def getter(obj): + return tuple([getter(obj) for getter in getters]) + else: + getter = single_attr_getter(attr) + return builtinify(getter) - def _resolve_attr(self, obj, attr): - last = 0 - while True: - try: - dot = attr.find(".", last) - except AttributeError: - raise TypeError - if dot > 0: - obj = getattr(obj, attr[last:dot]) - last = dot + 1 - else: - return getattr(obj, attr[last:]) +def single_attr_getter(attr): + if not isinstance(attr, str): + if not isinstance(attr, unicode): + def _raise_typeerror(obj): + raise TypeError("argument must be a string, not %r" % + (type(attr).__name__,)) + return _raise_typeerror + attr = attr.encode('ascii') + # + def make_getter(name, prevfn=None): + if prevfn is None: + def getter(obj): + return getattr(obj, name) + else: + def getter(obj): + return getattr(prevfn(obj), name) + return getter + # + last = 0 + getter = None + while True: + dot = attr.find(".", last) + if dot < 0: break + getter = make_getter(attr[last:dot], getter) + last = dot + 1 + return make_getter(attr[last:], getter) - def __call__(self, obj): - if len(self.attrs) == 1: - return self._resolve_attr(obj, self.attrs[0]) - return tuple(self._resolve_attr(obj, attr) for attr in self.attrs) -class itemgetter(object): +def itemgetter(item, *items): + if items: + list_of_indices = [item] + list(items) + def getter(obj): + return tuple([obj[i] for i in list_of_indices]) + else: + def getter(obj): + return obj[item] + return builtinify(getter) - def __init__(self, item, *args): - self.items = args - self.item = item - def __call__(self, obj): - result = obj[self.item] - - if self.items: - list = [result] + [obj[item] for item in self.items] - return tuple(list) - - return result - -class methodcaller(object): - - def __init__(self, method_name, *args, **kwargs): - self.method_name = method_name - self.args = args - self.kwargs = kwargs - - def __call__(self, obj): - return getattr(obj, self.method_name)(*self.args, **self.kwargs) +def methodcaller(method_name, *args, **kwargs): + def call(obj): + return getattr(obj, method_name)(*args, **kwargs) + return builtinify(call) diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -1484,7 +1484,7 @@ raise OperationError( moduledict.w_NotSupportedError, space.wrap("Variable_TypeByValue(): unhandled data type %s" % - (space.type(w_value).getname(space, '?'),))) + (space.type(w_value).getname(space),))) def newByInputTypeHandler(space, cursor, w_inputTypeHandler, w_value, numElements): w_var = space.call(w_inputTypeHandler, diff --git a/pypy/module/posix/app_posix.py b/pypy/module/posix/app_posix.py --- a/pypy/module/posix/app_posix.py +++ b/pypy/module/posix/app_posix.py @@ -107,6 +107,9 @@ def tmpnam(): """Return an absolute pathname of a file that did not exist at the time the call is made.""" + from warnings import warn + warn(RuntimeWarning("tmpnam is a potential security risk to your program")) + import tempfile return tempfile.mktemp() @@ -114,6 +117,9 @@ """Return an absolute pathname of a file that did not exist at the time the call is made. The directory and a prefix may be specified as strings; they may be omitted or None if not needed.""" + from warnings import warn + warn(RuntimeWarning("tempnam is a potential security risk to your program")) + import tempfile return tempfile.mktemp('', prefix or 'tmp', dir) diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -847,6 +847,21 @@ assert os.path.basename(s1).startswith(prefix or 'tmp') assert os.path.basename(s2).startswith(prefix or 'tmp') + def test_tmpnam_warning(self): + import warnings, os + # + def f_tmpnam_warning(): os.tmpnam() # a single line + # + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + f_tmpnam_warning() + assert len(w) == 1 + assert issubclass(w[-1].category, RuntimeWarning) + assert "potential security risk" in str(w[-1].message) + # check that the warning points to the call to os.tmpnam(), + # not to some code inside app_posix.py + assert w[-1].lineno == f_tmpnam_warning.func_code.co_firstlineno + class AppTestEnvironment(object): def setup_class(cls): diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py --- a/pypy/module/pyexpat/__init__.py +++ b/pypy/module/pyexpat/__init__.py @@ -2,6 +2,22 @@ from pypy.interpreter.mixedmodule import MixedModule +class ErrorsModule(MixedModule): + "Definition of pyexpat.errors module." + + appleveldefs = { + } + + interpleveldefs = { + } + + def setup_after_space_initialization(self): + from pypy.module.pyexpat import interp_pyexpat + for name in interp_pyexpat.xml_error_list: + self.space.setattr(self, self.space.wrap(name), + interp_pyexpat.ErrorString(self.space, + getattr(interp_pyexpat, name))) + class Module(MixedModule): "Python wrapper for Expat parser." @@ -21,6 +37,10 @@ 'version_info': 'interp_pyexpat.get_expat_version_info(space)', } + submodules = { + 'errors': ErrorsModule, + } + for name in ['XML_PARAM_ENTITY_PARSING_NEVER', 'XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE', 'XML_PARAM_ENTITY_PARSING_ALWAYS']: diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -31,6 +31,48 @@ XML_Content_Ptr = lltype.Ptr(lltype.ForwardReference()) XML_Parser = rffi.COpaquePtr(typedef='XML_Parser') +xml_error_list = [ + "XML_ERROR_NO_MEMORY", + "XML_ERROR_SYNTAX", + "XML_ERROR_NO_ELEMENTS", + "XML_ERROR_INVALID_TOKEN", + "XML_ERROR_UNCLOSED_TOKEN", + "XML_ERROR_PARTIAL_CHAR", + "XML_ERROR_TAG_MISMATCH", + "XML_ERROR_DUPLICATE_ATTRIBUTE", + "XML_ERROR_JUNK_AFTER_DOC_ELEMENT", + "XML_ERROR_PARAM_ENTITY_REF", + "XML_ERROR_UNDEFINED_ENTITY", + "XML_ERROR_RECURSIVE_ENTITY_REF", + "XML_ERROR_ASYNC_ENTITY", + "XML_ERROR_BAD_CHAR_REF", + "XML_ERROR_BINARY_ENTITY_REF", + "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", + "XML_ERROR_MISPLACED_XML_PI", + "XML_ERROR_UNKNOWN_ENCODING", + "XML_ERROR_INCORRECT_ENCODING", + "XML_ERROR_UNCLOSED_CDATA_SECTION", + "XML_ERROR_EXTERNAL_ENTITY_HANDLING", + "XML_ERROR_NOT_STANDALONE", + "XML_ERROR_UNEXPECTED_STATE", + "XML_ERROR_ENTITY_DECLARED_IN_PE", + "XML_ERROR_FEATURE_REQUIRES_XML_DTD", + "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING", + # Added in Expat 1.95.7. + "XML_ERROR_UNBOUND_PREFIX", + # Added in Expat 1.95.8. + "XML_ERROR_UNDECLARING_PREFIX", + "XML_ERROR_INCOMPLETE_PE", + "XML_ERROR_XML_DECL", + "XML_ERROR_TEXT_DECL", + "XML_ERROR_PUBLICID", + "XML_ERROR_SUSPENDED", + "XML_ERROR_NOT_SUSPENDED", + "XML_ERROR_ABORTED", + "XML_ERROR_FINISHED", + "XML_ERROR_SUSPEND_PE", + ] + class CConfigure: _compilation_info_ = eci XML_Content = rffi_platform.Struct('XML_Content', [ @@ -56,6 +98,9 @@ XML_FALSE = rffi_platform.ConstantInteger('XML_FALSE') XML_TRUE = rffi_platform.ConstantInteger('XML_TRUE') + for name in xml_error_list: + locals()[name] = rffi_platform.ConstantInteger(name) + for k, v in rffi_platform.configure(CConfigure).items(): globals()[k] = v @@ -298,7 +343,8 @@ XML_GetErrorCode = expat_external( 'XML_GetErrorCode', [XML_Parser], rffi.INT) XML_ErrorString = expat_external( - 'XML_ErrorString', [rffi.INT], rffi.CCHARP) + 'XML_ErrorString', [rffi.INT], + rffi.CCHARP) XML_GetCurrentLineNumber = expat_external( 'XML_GetCurrentLineNumber', [XML_Parser], rffi.INT) XML_GetErrorLineNumber = XML_GetCurrentLineNumber @@ -691,7 +737,7 @@ elif space.is_true(space.isinstance(w_encoding, space.w_str)): encoding = space.str_w(w_encoding) else: - type_name = space.type(w_encoding).getname(space, '?') + type_name = space.type(w_encoding).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 1 must be string or None,' @@ -711,7 +757,7 @@ space.wrap('namespace_separator must be at most one character,' ' omitted, or None')) else: - type_name = space.type(w_namespace_separator).getname(space, '?') + type_name = space.type(w_namespace_separator).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 2 must be string or None,' diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py --- a/pypy/module/pyexpat/test/test_parser.py +++ b/pypy/module/pyexpat/test/test_parser.py @@ -38,7 +38,7 @@ parser = pyexpat.ParserCreate() raises(pyexpat.ExpatError, "parser.Parse(xml, True)") - def test_encoding(self): + def test_encoding_argument(self): import pyexpat for encoding_arg in (None, 'utf-8', 'iso-8859-1'): for namespace_arg in (None, '{'): @@ -68,7 +68,7 @@ assert p.buffer_size == 150 raises(TypeError, setattr, p, 'buffer_size', sys.maxint + 1) - def test_encoding(self): + def test_encoding_xml(self): # use one of the few encodings built-in in expat xml = "caf\xe9" import pyexpat @@ -120,3 +120,14 @@ return True p.ExternalEntityRefHandler = handler p.Parse(xml) + + def test_errors(self): + import types + import pyexpat + assert isinstance(pyexpat.errors, types.ModuleType) + # check a few random errors + assert pyexpat.errors.XML_ERROR_SYNTAX == 'syntax error' + assert (pyexpat.errors.XML_ERROR_INCORRECT_ENCODING == + 'encoding specified in XML declaration is incorrect') + assert (pyexpat.errors.XML_ERROR_XML_DECL == + 'XML declaration not well-formed') diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,6 +8,7 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'set_compile_hook': 'interp_jit.set_compile_hook', + 'DebugMergePoint': 'interp_resop.W_DebugMergePoint', } def setup_after_space_initialization(self): diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -16,10 +16,12 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap from pypy.rlib.objectmodel import we_are_translated +from pypy.rlib.nonconst import NonConstant +from pypy.jit.metainterp.resoperation import rop +from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes PyFrame._virtualizable2_ = ['last_instr', 'pycode', - 'valuestackdepth', 'valuestack_w[*]', - 'fastlocals_w[*]', + 'valuestackdepth', 'locals_stack_w[*]', 'last_exception', 'lastblock', 'is_being_profiled', @@ -46,6 +48,16 @@ return (bytecode.co_flags & CO_GENERATOR) != 0 +def wrap_oplist(space, logops, operations): + list_w = [] + for op in operations: + if op.getopnum() == rop.DEBUG_MERGE_POINT: + list_w.append(space.wrap(debug_merge_point_from_boxes( + op.getarglist()))) + else: + list_w.append(space.wrap(logops.repr_of_resop(op))) + return list_w + class PyPyJitDriver(JitDriver): reds = ['frame', 'ec'] greens = ['next_instr', 'is_being_profiled', 'pycode'] @@ -57,11 +69,13 @@ space = self.space cache = space.fromcache(Cache) + if cache.in_recursion: + return if space.is_true(cache.w_compile_hook): - memo = {} - list_w = [space.wrap(logger.repr_of_resop(memo, op)) - for op in operations] + logops = logger._make_log_operations() + list_w = wrap_oplist(space, logops, operations) pycode = cast_base_ptr_to_instance(PyCode, ll_pycode) + cache.in_recursion = True try: space.call_function(cache.w_compile_hook, space.wrap('main'), @@ -72,14 +86,17 @@ space.newlist(list_w)) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_compile_hook) + cache.in_recursion = False def on_compile_bridge(self, logger, orig_looptoken, operations, n): space = self.space cache = space.fromcache(Cache) + if cache.in_recursion: + return if space.is_true(cache.w_compile_hook): - memo = {} - list_w = [space.wrap(logger.repr_of_resop(memo, op)) - for op in operations] + logops = logger._make_log_operations() + list_w = wrap_oplist(space, logops, operations) + cache.in_recursion = True try: space.call_function(cache.w_compile_hook, space.wrap('main'), @@ -88,6 +105,7 @@ space.newlist(list_w)) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_compile_hook) + cache.in_recursion = False pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location, get_jitcell_at = get_jitcell_at, @@ -158,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() @@ -191,6 +211,8 @@ return space.call_args(w_callable, __args__) class Cache(object): + in_recursion = False + def __init__(self, space): self.w_compile_hook = space.w_None @@ -209,8 +231,13 @@ for jit merge point. in case it's `main` it'll be a tuple (code, offset, is_being_profiled) + Note that jit hook is not reentrant. It means that if the code + inside the jit hook is itself jitted, it will get compiled, but the + jit hook won't be called for that. + XXX write down what else """ cache = space.fromcache(Cache) cache.w_compile_hook = w_hook + cache.in_recursion = NonConstant(False) return space.w_None diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/interp_resop.py @@ -0,0 +1,41 @@ + +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.gateway import unwrap_spec, interp2app +from pypy.interpreter.pycode import PyCode +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.annlowlevel import cast_base_ptr_to_instance +from pypy.rpython.lltypesystem.rclass import OBJECT + +class W_DebugMergePoint(Wrappable): + """ A class representing debug_merge_point JIT operation + """ + + def __init__(self, mp_no, offset, pycode): + self.mp_no = mp_no + self.offset = offset + self.pycode = pycode + + def descr_repr(self, space): + return space.wrap('DebugMergePoint()') + + at unwrap_spec(mp_no=int, offset=int, pycode=PyCode) +def new_debug_merge_point(space, w_tp, mp_no, offset, pycode): + return W_DebugMergePoint(mp_no, offset, pycode) + +def debug_merge_point_from_boxes(boxes): + mp_no = boxes[0].getint() + offset = boxes[2].getint() + llcode = lltype.cast_opaque_ptr(lltype.Ptr(OBJECT), + boxes[4].getref_base()) + pycode = cast_base_ptr_to_instance(PyCode, llcode) + assert pycode is not None + return W_DebugMergePoint(mp_no, offset, pycode) + +W_DebugMergePoint.typedef = TypeDef( + 'DebugMergePoint', + __new__ = interp2app(new_debug_merge_point), + __doc__ = W_DebugMergePoint.__doc__, + __repr__ = interp2app(W_DebugMergePoint.descr_repr), + code = interp_attrproperty('pycode', W_DebugMergePoint), +) diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,8 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof', '_weakref']: + 'posix', '_socket', '_sre', '_lsprof', '_weakref', + '__pypy__', 'cStringIO']: return True return False diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -8,12 +8,13 @@ from pypy.jit.metainterp.logger import Logger from pypy.rpython.annlowlevel import (cast_instance_to_base_ptr, cast_base_ptr_to_instance) +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.module.pypyjit.interp_jit import pypyjitdriver from pypy.jit.tool.oparser import parse from pypy.jit.metainterp.typesystem import llhelper class MockSD(object): - class cpu: + class cpu(object): ts = llhelper class AppTestJitHook(object): @@ -27,14 +28,17 @@ pass return f """) + cls.w_f = w_f ll_code = cast_instance_to_base_ptr(w_f.code) + code_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, ll_code) logger = Logger(MockSD()) oplist = parse(""" [i1, i2] i3 = int_add(i1, i2) + debug_merge_point(0, 0, 0, 0, ConstPtr(ptr0)) guard_true(i3) [] - """).operations + """, namespace={'ptr0': code_gcref}).operations def interp_on_compile(): pypyjitdriver.on_compile(logger, LoopToken(), oplist, 'loop', @@ -63,7 +67,7 @@ assert all[0][0][0].co_name == 'f' assert all[0][0][1] == 0 assert all[0][0][2] == False - assert len(all[0][1]) == 2 + assert len(all[0][1]) == 3 assert 'int_add' in all[0][1][0] self.on_compile_bridge() assert len(all) == 2 @@ -87,3 +91,36 @@ sys.stderr = prev assert 'jit hook' in s.getvalue() assert 'ZeroDivisionError' in s.getvalue() + + def test_non_reentrant(self): + import pypyjit + l = [] + + def hook(*args): + l.append(None) + self.on_compile() + self.on_compile_bridge() + + pypyjit.set_compile_hook(hook) + self.on_compile() + assert len(l) == 1 # and did not crash + self.on_compile_bridge() + assert len(l) == 2 # and did not crash + + def test_on_compile_types(self): + import pypyjit + l = [] + + def hook(*args): + l.append(args) + + pypyjit.set_compile_hook(hook) + self.on_compile() + dmp = l[0][3][1] + assert isinstance(dmp, pypyjit.DebugMergePoint) + assert dmp.code is self.f.func_code + + def test_creation(self): + import pypyjit + dmp = pypyjit.DebugMergePoint(0, 0, self.f.func_code) + assert dmp.code is self.f.func_code diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,18 +9,49 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + + +def test_interface_residual_call(): + space = gettestobjspace(usemodules=['pypyjit']) + space.appexec([], """(): + import pypyjit + def f(*args, **kwds): + return (args, kwds) + res = pypyjit.residual_call(f, 4, x=6) + assert res == ((4,), {'x': 6}) + """) diff --git a/pypy/module/pypyjit/test/test_pypy_c.py b/pypy/module/pypyjit/test/test_pypy_c.py deleted file mode 100644 --- a/pypy/module/pypyjit/test/test_pypy_c.py +++ /dev/null @@ -1,430 +0,0 @@ -from pypy.conftest import gettestobjspace, option -from pypy.tool.udir import udir -import py -from py.test import skip -import sys, os, re -import subprocess - -class BytecodeTrace(list): - def get_opnames(self, prefix=""): - return [op.getopname() for op in self - if op.getopname().startswith(prefix)] - - def __repr__(self): - return "%s%s" % (self.bytecode, list.__repr__(self)) - -ZERO_OP_BYTECODES = [ - 'POP_TOP', - 'ROT_TWO', - 'ROT_THREE', - 'DUP_TOP', - 'ROT_FOUR', - 'NOP', - 'DUP_TOPX', - 'LOAD_CONST', - 'JUMP_FORWARD', - #'JUMP_ABSOLUTE' in theory, but contains signals stuff - #'LOAD_FAST' should be here, but currently needs a guard for nonzeroness - 'STORE_FAST', - ] - - -r_bridge = re.compile(r"bridge out of Guard (\d+)") - -def from_entry_bridge(text, allparts): - firstline = text.splitlines()[0] - if 'entry bridge' in firstline: - return True - match = r_bridge.search(firstline) - if match: - search = '' - for part in allparts: - if search in part: - break - else: - raise AssertionError, "%s not found??" % (search,) - return from_entry_bridge(part, allparts) - return False - -def test_from_entry_bridge(): - assert from_entry_bridge( - "# Loop 4 : entry bridge with 31 ops\n[p0, etc", []) - assert not from_entry_bridge( - "# Loop 1 : loop with 31 ops\n[p0, p1, etc", []) - assert not from_entry_bridge( - "# bridge out of Guard 5 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : loop with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n"]) - assert from_entry_bridge( - "# bridge out of Guard 5 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : entry bridge with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n"]) - assert not from_entry_bridge( - "# bridge out of Guard 51 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : loop with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n", - "# bridge out of Guard 5 with 13 ops\n" - "[p0, p1]\n" - "guard_other(p1, descr=)\n"]) - assert from_entry_bridge( - "# bridge out of Guard 51 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : entry bridge with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n", - "# bridge out of Guard 5 with 13 ops\n" - "[p0, p1]\n" - "guard_other(p1, descr=)\n"]) - - -class PyPyCJITTests(object): - def run_source(self, source, expected_max_ops, *testcases, **kwds): - assert isinstance(expected_max_ops, int) - threshold = kwds.pop('threshold', 3) - self.count_debug_merge_point = \ - kwds.pop('count_debug_merge_point', True) - if kwds: - raise TypeError, 'Unsupported keyword arguments: %s' % kwds.keys() - source = py.code.Source(source) - filepath = self.tmpdir.join('case%d.py' % self.counter) - logfilepath = filepath.new(ext='.log') - self.__class__.counter += 1 - f = filepath.open('w') - print >> f, source - # some support code... - print >> f, py.code.Source(""" - import sys - # we don't want to see the small bridges created - # by the checkinterval reaching the limit - sys.setcheckinterval(10000000) - try: # make the file runnable by CPython - import pypyjit - pypyjit.set_param(threshold=%d) - except ImportError: - pass - - def check(args, expected): - #print >> sys.stderr, 'trying:', args - result = main(*args) - #print >> sys.stderr, 'got:', repr(result) - assert result == expected - assert type(result) is type(expected) - """ % threshold) - for testcase in testcases * 2: - print >> f, "check(%r, %r)" % testcase - print >> f, "print 'OK :-)'" - f.close() - - print logfilepath - env = os.environ.copy() - env['PYPYLOG'] = ":%s" % (logfilepath,) - p = subprocess.Popen([self.pypy_c, str(filepath)], - env=env, stdout=subprocess.PIPE) - result, _ = p.communicate() - assert result - if result.strip().startswith('SKIP:'): - py.test.skip(result.strip()) - assert result.splitlines()[-1].strip() == 'OK :-)' - self.parse_loops(logfilepath) - self.print_loops() - print logfilepath - if self.total_ops > expected_max_ops: - assert 0, "too many operations: got %d, expected maximum %d" % ( - self.total_ops, expected_max_ops) - return result - - def parse_loops(self, opslogfile): - from pypy.tool import logparser - assert opslogfile.check() - log = logparser.parse_log_file(str(opslogfile)) - parts = logparser.extract_category(log, 'jit-log-opt-') - self.rawloops = [part for part in parts - if not from_entry_bridge(part, parts)] - self.loops, self.sliced_loops, self.total_ops = \ - self.parse_rawloops(self.rawloops) - self.check_0_op_bytecodes() - self.rawentrybridges = [part for part in parts - if from_entry_bridge(part, parts)] - _, self.sliced_entrybridge, _ = \ - self.parse_rawloops(self.rawentrybridges) - - from pypy.jit.tool.jitoutput import parse_prof - summaries = logparser.extract_category(log, 'jit-summary') - if len(summaries) > 0: - self.jit_summary = parse_prof(summaries[-1]) - else: - self.jit_summary = None - - - def parse_rawloops(self, rawloops): - from pypy.jit.tool.oparser import parse - loops = [parse(part, no_namespace=True) for part in rawloops] - sliced_loops = [] # contains all bytecodes of all loops - total_ops = 0 - for loop in loops: - for op in loop.operations: - if op.getopname() == "debug_merge_point": - sliced_loop = BytecodeTrace() - sliced_loop.bytecode = op.getarg(0)._get_str().rsplit(" ", 1)[1] - sliced_loops.append(sliced_loop) - if self.count_debug_merge_point: - total_ops += 1 - else: - sliced_loop.append(op) - total_ops += 1 - return loops, sliced_loops, total_ops - - def check_0_op_bytecodes(self): - for bytecodetrace in self.sliced_loops: - if bytecodetrace.bytecode not in ZERO_OP_BYTECODES: - continue - assert not bytecodetrace - - def get_by_bytecode(self, name, from_entry_bridge=False): - if from_entry_bridge: - sliced_loops = self.sliced_entrybridge - else: - sliced_loops = self.sliced_loops - return [ops for ops in sliced_loops if ops.bytecode == name] - - def print_loops(self): - for rawloop in self.rawloops: - print - print '@' * 79 - print - print rawloop.rstrip() - print - print '@' * 79 - - - def test_richards(self): - self.run_source(''' - import sys; sys.path[:] = %r - from pypy.translator.goal import richards - - def main(): - return richards.main(iterations = 1) - ''' % (sys.path,), 7200, - ([], 42)) - - - def test_overflow_checking(self): - startvalue = sys.maxint - 2147483647 - self.run_source(''' - def main(): - def f(a,b): - if a < 0: return -1 - return a-b - total = %d - for i in range(100000): - total += f(i, 5) - return total - ''' % startvalue, 170, ([], startvalue + 4999450000L)) - - def test_shift(self): - from sys import maxint - maxvals = (-maxint-1, -maxint, maxint-1, maxint) - for a in (-4, -3, -2, -1, 0, 1, 2, 3, 4) + maxvals: - for b in (0, 1, 2, 31, 32, 33, 61, 62, 63): - r = 0 - if (a >> b) >= 0: - r += 2000 - if (a << b) > 2: - r += 20000000 - if abs(a) < 10 and b < 5: - ops = 13 - else: - ops = 29 - - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 2000: - if a > 0: # Specialises the loop - pass - if b < 2 and b > 0: - pass - if (a >> b) >= 0: - sa += 1 - if (a << b) > 2: - sa += 10000 - i += 1 - return sa - ''', ops, ([a, b], r), count_debug_merge_point=False) - - def test_revert_shift(self): - from sys import maxint - tests = [] - for a in (1, 4, 8, 100): - for b in (-10, 10, -201, 201, -maxint/3, maxint/3): - for c in (-10, 10, -maxint/3, maxint/3): - tests.append(([a, b, c], long(4000*(a+b+c)))) - self.run_source(''' - def main(a, b, c): - from sys import maxint - i = sa = 0 - while i < 2000: - if 0 < a < 10: pass - if -100 < b < 100: pass - if -maxint/2 < c < maxint/2: pass - sa += (a<>a - sa += (b<>a - sa += (c<>a - sa += (a<<100)>>100 - sa += (b<<100)>>100 - sa += (c<<100)>>100 - i += 1 - return long(sa) - ''', 93, count_debug_merge_point=False, *tests) - - def test_division_to_rshift(self): - avalues = ('a', 'b', 7, -42, 8) - bvalues = ['b'] + range(-10, 0) + range(1,10) - code = '' - a1, b1, res1 = 10, 20, 0 - a2, b2, res2 = 10, -20, 0 - a3, b3, res3 = -10, -20, 0 - def dd(a, b, aval, bval): - m = {'a': aval, 'b': bval} - if not isinstance(a, int): - a=m[a] - if not isinstance(b, int): - b=m[b] - return a/b - for a in avalues: - for b in bvalues: - code += ' sa += %s / %s\n' % (a, b) - res1 += dd(a, b, a1, b1) - res2 += dd(a, b, a2, b2) - res3 += dd(a, b, a3, b3) - # The purpose of this test is to check that we get - # the correct results, not really to count operations. - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 2000: -%s - i += 1 - return sa - ''' % code, sys.maxint, ([a1, b1], 2000 * res1), - ([a2, b2], 2000 * res2), - ([a3, b3], 2000 * res3)) - - def test_mod(self): - avalues = ('a', 'b', 7, -42, 8) - bvalues = ['b'] + range(-10, 0) + range(1,10) - code = '' - a1, b1, res1 = 10, 20, 0 - a2, b2, res2 = 10, -20, 0 - a3, b3, res3 = -10, -20, 0 - def dd(a, b, aval, bval): - m = {'a': aval, 'b': bval} - if not isinstance(a, int): - a=m[a] - if not isinstance(b, int): - b=m[b] - return a % b - for a in avalues: - for b in bvalues: - code += ' sa += %s %% %s\n' % (a, b) - res1 += dd(a, b, a1, b1) - res2 += dd(a, b, a2, b2) - res3 += dd(a, b, a3, b3) - # The purpose of this test is to check that we get - # the correct results, not really to count operations. - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 2000: - if a > 0: pass - if 1 < b < 2: pass -%s - i += 1 - return sa - ''' % code, sys.maxint, ([a1, b1], 2000 * res1), - ([a2, b2], 2000 * res2), - ([a3, b3], 2000 * res3)) - - def test_dont_trace_every_iteration(self): - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 200: - if a > 0: pass - if 1 < b < 2: pass - sa += a % b - i += 1 - return sa - ''', 22, ([10, 20], 200 * (10 % 20)), - ([-10, -20], 200 * (-10 % -20)), - count_debug_merge_point=False) - assert self.jit_summary.tracing_no == 2 - def test_id_compare_optimization(self): - # XXX: lower the instruction count, 35 is the old value. - self.run_source(""" - class A(object): - pass - def main(): - i = 0 - a = A() - while i < 5: - if A() != a: - pass - i += 1 - """, 35, ([], None)) - _, compare = self.get_by_bytecode("COMPARE_OP") - assert "call" not in compare.get_opnames() - -class AppTestJIT(PyPyCJITTests): - def setup_class(cls): - if not option.runappdirect: - py.test.skip("meant only for pypy-c") - # the next line skips stuff if the pypy-c is not a jit build - cls.space = gettestobjspace(usemodules=['pypyjit']) - cls.tmpdir = udir.join('pypy-jit') - cls.tmpdir.ensure(dir=1) - cls.counter = 0 - cls.pypy_c = sys.executable - -class TestJIT(PyPyCJITTests): - def setup_class(cls): - if option.pypy_c is None: - py.test.skip("pass --pypy!") - if not has_info(option.pypy_c, 'translation.jit'): - py.test.skip("must give a pypy-c with the jit enabled") - cls.tmpdir = udir.join('pypy-jit') - cls.tmpdir.ensure(dir=1) - cls.counter = 0 - cls.pypy_c = option.pypy_c - - -def test_interface_residual_call(): - space = gettestobjspace(usemodules=['pypyjit']) - space.appexec([], """(): - import pypyjit - def f(*args, **kwds): - return (args, kwds) - res = pypyjit.residual_call(f, 4, x=6) - assert res == ((4,), {'x': 6}) - """) - - -def has_info(pypy_c, option): - g = os.popen('"%s" --info' % pypy_c, 'r') - lines = g.readlines() - g.close() - if not lines: - raise ValueError("cannot execute %r" % pypy_c) - for line in lines: - line = line.strip() - if line.startswith(option + ':'): - line = line[len(option)+1:].strip() - if line == 'True': - return True - elif line == 'False': - return False - else: - return line - raise ValueError(option + ' not found in ' + pypy_c) diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -2,6 +2,7 @@ import sys import re import os.path +from _pytest.assertion import newinterpret from pypy.tool.jitlogparser.parser import SimpleParser, Function, TraceForOpcode from pypy.tool.jitlogparser.storage import LoopStorage @@ -194,7 +195,7 @@ # transform self._assert(x, 'foo') into assert x, 'foo' source = source.replace('self._assert(', 'assert ') source = source[:-1] # remove the trailing ')' - self.msg = py.code._reinterpret(source, f, should_fail=True) + self.msg = newinterpret.interpret(source, f, should_fail=True) else: self.msg = "" diff --git a/pypy/module/pypyjit/test_pypy_c/test_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py rename from pypy/module/pypyjit/test_pypy_c/test_model.py rename to pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -5,6 +5,7 @@ from lib_pypy import disassembler from pypy.tool.udir import udir from pypy.tool import logparser +from pypy.jit.tool.jitoutput import parse_prof from pypy.module.pypyjit.test_pypy_c.model import Log, find_ids_range, find_ids, \ LoopWithIds, OpMatcher @@ -21,6 +22,7 @@ self.filepath = self.tmpdir.join(meth.im_func.func_name + '.py') def run(self, func_or_src, args=[], import_site=False, **jitopts): + jitopts.setdefault('threshold', 200) src = py.code.Source(func_or_src) if isinstance(func_or_src, types.FunctionType): funcname = func_or_src.func_name @@ -56,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log @@ -63,6 +67,13 @@ rawtraces = logparser.extract_category(rawlog, 'jit-log-opt-') log = Log(rawtraces) log.result = eval(stdout) + # + summaries = logparser.extract_category(rawlog, 'jit-summary') + if len(summaries) > 0: + log.jit_summary = parse_prof(summaries[-1]) + else: + log.jit_summary = None + # return log def run_and_check(self, src, args=[], **jitopts): diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -0,0 +1,133 @@ +import py +import sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class Test__ffi(BaseTestPyPyC): + + def test__ffi_call(self): + from pypy.rlib.test.test_libffi import get_libm_name + def main(libm_name): + try: + from _ffi import CDLL, types + except ImportError: + sys.stderr.write('SKIP: cannot import _ffi\n') + return 0 + + libm = CDLL(libm_name) + pow = libm.getfunc('pow', [types.double, types.double], + types.double) + i = 0 + res = 0 + while i < 300: + tmp = pow(2, 3) # ID: fficall + res += tmp + i += 1 + return pow.getaddr(), res + # + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + pow_addr, res = log.result + assert res == 8.0 * 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('fficall', """ + p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>) + guard_not_invalidated(descr=...) + i17 = force_token() + setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>) + f21 = call_release_gil(%d, 2.000000, 3.000000, descr=) + guard_not_forced(descr=...) + guard_no_exception(descr=...) + """ % pow_addr) + + + def test__ffi_call_frame_does_not_escape(self): + from pypy.rlib.test.test_libffi import get_libm_name + def main(libm_name): + try: + from _ffi import CDLL, types + except ImportError: + sys.stderr.write('SKIP: cannot import _ffi\n') + return 0 + + libm = CDLL(libm_name) + pow = libm.getfunc('pow', [types.double, types.double], + types.double) + + def mypow(a, b): + return pow(a, b) + + i = 0 + res = 0 + while i < 300: + tmp = mypow(2, 3) + res += tmp + i += 1 + return pow.getaddr(), res + # + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + pow_addr, res = log.result + assert res == 8.0 * 300 + loop, = log.loops_by_filename(self.filepath) + opnames = log.opnames(loop.allops()) + # we only force the virtualref, not its content + assert opnames.count('new_with_vtable') == 1 + + def test__ffi_call_releases_gil(self): + from pypy.rlib.test.test_libffi import get_libc_name + def main(libc_name, n): + import time + from threading import Thread + from _ffi import CDLL, types + # + libc = CDLL(libc_name) + sleep = libc.getfunc('sleep', [types.uint], types.uint) + delays = [0]*n + [1] + # + def loop_of_sleeps(i, delays): + for delay in delays: + sleep(delay) # ID: sleep + # + threads = [Thread(target=loop_of_sleeps, args=[i, delays]) for i in range(5)] + start = time.time() + for i, thread in enumerate(threads): + thread.start() + for thread in threads: + thread.join() + end = time.time() + return end - start + # + log = self.run(main, [get_libc_name(), 200], threshold=150) + assert 1 <= log.result <= 1.5 # at most 0.5 seconds of overhead + loops = log.loops_by_id('sleep') + assert len(loops) == 1 # make sure that we actually JITted the loop + + + def test_ctypes_call(self): + from pypy.rlib.test.test_libffi import get_libm_name + def main(libm_name): + import ctypes + libm = ctypes.CDLL(libm_name) + fabs = libm.fabs + fabs.argtypes = [ctypes.c_double] + fabs.restype = ctypes.c_double + x = -4 + i = 0 + while i < 300: + x = fabs(x) + x = x - 100 + i += 1 + return fabs._ptr.getaddr(), x + + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + fabs_addr, res = log.result + assert res == -4.0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.allops() + opnames = log.opnames(ops) + assert opnames.count('new_with_vtable') == 1 # only the virtualref + assert opnames.count('call_release_gil') == 1 + idx = opnames.index('call_release_gil') + call = ops[idx] + assert int(call.args[0]) == fabs_addr diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -0,0 +1,188 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestArray(BaseTestPyPyC): + + def test_arraycopy_disappears(self): + def main(n): + i = 0 + while i < n: + t = (1, 2, 3, i + 1) + t2 = t[:] + del t + i = t2[3] + del t2 + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i5, i6) + guard_true(i7, descr=...) + i9 = int_add(i5, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i9, i6, descr=) + """) + + def test_array_sum(self): + def main(): + from array import array + img = array("i", range(128) * 5) * 480 + l, i = 0, 0 + while i < len(img): + l += img[i] + i += 1 + return l + # + log = self.run(main, []) + assert log.result == 19507200 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + guard_not_invalidated(descr=...) + i13 = int_lt(i7, i9) + guard_true(i13, descr=...) + i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) + i16 = int_add_ovf(i8, i15) + guard_no_overflow(descr=...) + i18 = int_add(i7, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) + """) + + def test_array_intimg(self): + def main(): + from array import array + img = array('i', range(3)) * (350 * 480) + intimg = array('i', (0,)) * (640 * 480) + l, i = 0, 640 + while i < 640 * 480: + assert len(img) == 3*350*480 + assert len(intimg) == 640*480 + l = l + img[i] + intimg[i] = (intimg[i-640] + l) + i += 1 + return intimg[i - 1] + # + log = self.run(main, []) + assert log.result == 73574560 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i13 = int_lt(i8, 307200) + guard_true(i13, descr=...) + guard_not_invalidated(descr=...) + # the bound check guard on img has been killed (thanks to the asserts) + i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) + i15 = int_add_ovf(i9, i14) + guard_no_overflow(descr=...) + i17 = int_sub(i8, 640) + # the bound check guard on intimg has been killed (thanks to the asserts) + i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) + i19 = int_add_ovf(i18, i15) + guard_no_overflow(descr=...) + # on 64bit, there is a guard checking that i19 actually fits into 32bit + ... + setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) + i28 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) + """) + + + def test_zeropadded(self): + def main(): + from array import array + class ZeroPadded(array): + def __new__(cls, l): + self = array.__new__(cls, 'd', range(l)) + return self + + def __getitem__(self, i): + if i < 0 or i >= len(self): + return 0 + return array.__getitem__(self, i) # ID: get + # + buf = ZeroPadded(2000) + i = 10 + sa = 0 + while i < 2000 - 10: + sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] + i += 1 + return sa + + log = self.run(main, []) + assert log.result == 9895050.0 + loop, = log.loops_by_filename(self.filepath) + # + # check that the overloaded __getitem__ does not introduce double + # array bound checks. + # + # The force_token()s are still there, but will be eliminated by the + # backend regalloc, so they are harmless + assert loop.match(ignore_ops=['force_token'], + expected_src=""" + ... + i20 = int_ge(i18, i8) + guard_false(i20, descr=...) + f21 = getarrayitem_raw(i13, i18, descr=...) + f23 = getarrayitem_raw(i13, i14, descr=...) + f24 = float_add(f21, f23) + f26 = getarrayitem_raw(i13, i6, descr=...) + f27 = float_add(f24, f26) + i29 = int_add(i6, 1) + i31 = int_ge(i29, i8) + guard_false(i31, descr=...) + f33 = getarrayitem_raw(i13, i29, descr=...) + f34 = float_add(f27, f33) + i36 = int_add(i6, 2) + i38 = int_ge(i36, i8) + guard_false(i38, descr=...) + f39 = getarrayitem_raw(i13, i36, descr=...) + ... + """) + + def test_circular(self): + def main(): + from array import array + class Circular(array): + def __new__(cls): + self = array.__new__(cls, 'd', range(256)) + return self + def __getitem__(self, i): + assert len(self) == 256 + return array.__getitem__(self, i & 255) + # + buf = Circular() + i = 10 + sa = 0 + while i < 2000 - 10: + sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] + i += 1 + return sa + # + log = self.run(main, []) + assert log.result == 1239690.0 + loop, = log.loops_by_filename(self.filepath) + # + # check that the array bound checks are removed + # + # The force_token()s are still there, but will be eliminated by the + # backend regalloc, so they are harmless + assert loop.match(ignore_ops=['force_token'], + expected_src=""" + ... + i17 = int_and(i14, 255) + f18 = getarrayitem_raw(i8, i17, descr=...) + f20 = getarrayitem_raw(i8, i9, descr=...) + f21 = float_add(f18, f20) + f23 = getarrayitem_raw(i8, i10, descr=...) + f24 = float_add(f21, f23) + i26 = int_add(i6, 1) + i29 = int_and(i26, 255) + f30 = getarrayitem_raw(i8, i29, descr=...) + f31 = float_add(f24, f30) + i33 = int_add(i6, 2) + i36 = int_and(i33, 255) + f37 = getarrayitem_raw(i8, i36, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_boolrewrite.py b/pypy/module/pypyjit/test_pypy_c/test_boolrewrite.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_boolrewrite.py @@ -0,0 +1,233 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestBoolRewrite(BaseTestPyPyC): + + def test_boolrewrite_inverse(self): + """ + Test for this case:: + guard(i < x) + ... + guard(i >= y) + + where x and y can be either constants or variables. There are cases in + which the second guard is proven to be always true. + """ + + for a, b, res, opt_expected in (('2000', '2000', 20001000, True), + ( '500', '500', 15001500, True), + ( '300', '600', 16001700, False), + ( 'a', 'b', 16001700, False), + ( 'a', 'a', 13001700, True)): + src = """ + def main(): + sa = 0 + a = 300 + b = 600 + for i in range(1000): + if i < %s: # ID: lt + sa += 1 + else: + sa += 2 + # + if i >= %s: # ID: ge + sa += 10000 + else: + sa += 20000 + return sa + """ % (a, b) + # + log = self.run(src, [], threshold=400) + assert log.result == res + loop, = log.loops_by_filename(self.filepath) + le_ops = log.opnames(loop.ops_by_id('lt')) + ge_ops = log.opnames(loop.ops_by_id('ge')) + assert le_ops.count('int_lt') == 1 + # + if opt_expected: + assert ge_ops.count('int_ge') == 0 + else: + # if this assert fails it means that the optimization was + # applied even if we don't expect to. Check whether the + # optimization is valid, and either fix the code or fix the + # test :-) + assert ge_ops.count('int_ge') == 1 + + def test_boolrewrite_reflex(self): + """ + Test for this case:: + guard(i < x) + ... + guard(y > i) + + where x and y can be either constants or variables. There are cases in + which the second guard is proven to be always true. + """ + for a, b, res, opt_expected in (('2000', '2000', 10001000, True), + ( '500', '500', 15001500, True), + ( '300', '600', 14001700, False), + ( 'a', 'b', 14001700, False), + ( 'a', 'a', 17001700, True)): + + src = """ + def main(): + sa = 0 + a = 300 + b = 600 + for i in range(1000): + if i < %s: # ID: lt + sa += 1 + else: + sa += 2 + if %s > i: # ID: gt + sa += 10000 + else: + sa += 20000 + return sa + """ % (a, b) + log = self.run(src, [], threshold=400) + assert log.result == res + loop, = log.loops_by_filename(self.filepath) + le_ops = log.opnames(loop.ops_by_id('lt')) + gt_ops = log.opnames(loop.ops_by_id('gt')) + assert le_ops.count('int_lt') == 1 + # + if opt_expected: + assert gt_ops.count('int_gt') == 0 + else: + # if this assert fails it means that the optimization was + # applied even if we don't expect to. Check whether the + # optimization is valid, and either fix the code or fix the + # test :-) + assert gt_ops.count('int_gt') == 1 + + + def test_boolrewrite_allcases_inverse(self): + """ + Test for this case:: + guard(i < x) + ... + guard(i > y) + + with all possible combination of binary comparison operators. This + test only checks that we get the expected result, not that any + optimization has been applied. + """ + ops = ('<', '>', '<=', '>=', '==', '!=') + for op1 in ops: + for op2 in ops: + for a,b in ((500, 500), (300, 600)): + src = """ + def main(): + sa = 0 + for i in range(300): + if i %s %d: + sa += 1 + else: + sa += 2 + if i %s %d: + sa += 10000 + else: + sa += 20000 + return sa + """ % (op1, a, op2, b) + yield self.run_and_check, src + + src = """ + def main(): + sa = 0 + i = 0.0 + while i < 250.0: + if i %s %f: + sa += 1 + else: + sa += 2 + if i %s %f: + sa += 10000 + else: + sa += 20000 + i += 0.25 + return sa + """ % (op1, float(a)/4.0, op2, float(b)/4.0) + yield self.run_and_check, src + + + def test_boolrewrite_allcases_reflex(self): + """ + Test for this case:: + guard(i < x) + ... + guard(x > i) + + with all possible combination of binary comparison operators. This + test only checks that we get the expected result, not that any + optimization has been applied. + """ + ops = ('<', '>', '<=', '>=', '==', '!=') + for op1 in ops: + for op2 in ops: + for a,b in ((500, 500), (300, 600)): + src = """ + def main(): + sa = 0 + for i in range(300): + if i %s %d: + sa += 1 + else: + sa += 2 + if %d %s i: + sa += 10000 + else: + sa += 20000 + return sa + """ % (op1, a, b, op2) + yield self.run_and_check, src + + src = """ + def main(): + sa = 0 + i = 0.0 + while i < 250.0: + if i %s %f: + sa += 1 + else: + sa += 2 + if %f %s i: + sa += 10000 + else: + sa += 20000 + i += 0.25 + return sa + """ % (op1, float(a)/4.0, float(b)/4.0, op2) + yield self.run_and_check, src + + def test_boolrewrite_ptr(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b') + for e1 in compares: + for e2 in compares: + src = """ + class tst(object): + pass + def main(): + a = tst() + b = tst() + c = tst() + sa = 0 + for i in range(300): + if %s: + sa += 1 + else: + sa += 2 + if %s: + sa += 10000 + else: + sa += 20000 + if i > 750: + a = b + return sa + """ % (e1, e2) + yield self.run_and_check, src diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -0,0 +1,410 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestCall(BaseTestPyPyC): + + def test_recursive_call(self): + def fn(): + def rec(n): + if n == 0: + return 0 + return 1 + rec(n-1) + # + # this loop is traced and then aborted, because the trace is too + # long. But then "rec" is marked as "don't inline". Since we + # already traced function from the start (because of number), + # now we can inline it as call assembler + i = 0 + j = 0 + while i < 20: + i += 1 + j += rec(100) # ID: call_rec + return j + # + log = self.run(fn, [], threshold=18) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('call_rec', """ + ... + p53 = call_assembler(..., descr=...) + guard_not_forced(descr=...) + guard_no_exception(descr=...) + ... + """) + + def test_fib(self): + def fib(n): + if n == 0 or n == 1: + return 1 + return fib(n - 1) + fib(n - 2) # ID: call_rec + + log = self.run(fib, [7], function_threshold=15) + loop, = log.loops_by_filename(self.filepath, is_entry_bridge='*') + #assert loop.match_by_id('call_rec', ''' + #... + #p1 = call_assembler(..., descr=...) + #... + #''') + + def test_simple_call(self): + src = """ + OFFSET = 0 + def f(i): + return i + 1 + OFFSET # ID: add + def main(n): + i = 0 + while i < n+OFFSET: # ID: cond + i = f(f(i)) # ID: call + a = 0 + return i + """ + log = self.run(src, [1000]) + assert log.result == 1000 + # first, we test what is inside the entry bridge + # ----------------------------------------------- + entry_bridge, = log.loops_by_id('call', is_entry_bridge=True) + # LOAD_GLOBAL of OFFSET + ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') + assert log.opnames(ops) == ["guard_value", + "getfield_gc", "guard_value", + "getfield_gc", "guard_value", + "getfield_gc", "guard_nonnull_class"] + # LOAD_GLOBAL of OFFSET but in different function partially folded + # away + # XXX could be improved + ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') + assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value"] + # + # two LOAD_GLOBAL of f, the second is folded away + ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') + assert log.opnames(ops) == ["getfield_gc", "guard_nonnull_class"] + # + assert entry_bridge.match_by_id('call', """ + p29 = getfield_gc(ConstPtr(ptr28), descr=) + guard_nonnull_class(p29, ConstClass(Function), descr=...) + p33 = getfield_gc(p29, descr=) + guard_value(p33, ConstPtr(ptr34), descr=...) + p35 = getfield_gc(p29, descr=) + p36 = getfield_gc(p29, descr=) + p38 = call(ConstClass(getexecutioncontext), descr=) + p39 = getfield_gc(p38, descr=) + i40 = force_token() + p41 = getfield_gc(p38, descr=) + guard_isnull(p41, descr=...) + i42 = getfield_gc(p38, descr=) + i43 = int_is_zero(i42) + guard_true(i43, descr=...) + i50 = force_token() + """) + # + # then, we test the actual loop + # ----------------------------- + loop, = log.loops_by_id('call') + assert loop.match(""" + i12 = int_lt(i5, i6) + guard_true(i12, descr=...) + i13 = force_token() + i15 = int_add(i5, 1) + i16 = int_add_ovf(i15, i7) + guard_no_overflow(descr=...) + i18 = force_token() + i20 = int_add_ovf(i16, 1) + guard_no_overflow(descr=...) + i21 = int_add_ovf(i20, i7) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) + """) + + def test_method_call(self): + def fn(n): + class A(object): + def __init__(self, a): + self.a = a + def f(self, i): + return self.a + i + i = 0 + a = A(1) + while i < n: + x = a.f(i) # ID: meth1 + i = a.f(x) # ID: meth2 + return i + # + log = self.run(fn, [1000]) + assert log.result == 1000 + # + # first, we test the entry bridge + # ------------------------------- + entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) + ops = entry_bridge.ops_by_id('meth1', opcode='LOOKUP_METHOD') + assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', + 'guard_not_invalidated'] + # the second LOOKUP_METHOD is folded away + assert list(entry_bridge.ops_by_id('meth2', opcode='LOOKUP_METHOD')) == [] + # + # then, the actual loop + # ---------------------- + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i15 = int_lt(i6, i9) + guard_true(i15, descr=...) + guard_not_invalidated(descr=...) + i16 = force_token() + i17 = int_add_ovf(i10, i6) + guard_no_overflow(descr=...) + i18 = force_token() + i19 = int_add_ovf(i10, i17) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) + """) + + def test_static_classmethod_call(self): + def fn(n): + class A(object): + @classmethod + def f(cls, i): + return i + (cls is A) + 1 + @staticmethod + def g(i): + return i - 1 + # + i = 0 + a = A() + while i < n: + x = a.f(i) + i = a.g(x) + return i + # + log = self.run(fn, [1000]) + assert log.result == 1000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i14 = int_lt(i6, i9) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) + i15 = force_token() + i17 = int_add_ovf(i8, 1) + guard_no_overflow(descr=...) + i18 = force_token() + --TICK-- + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) + """) + + def test_default_and_kw(self): + def main(n): + def f(i, j=1): + return i + j + # + i = 0 + while i < n: + i = f(f(i), j=1) # ID: call + a = 0 + return i + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('call') + assert loop.match_by_id('call', """ + i14 = force_token() + i16 = force_token() + """) + + def test_kwargs_empty(self): + def main(x): + def g(**args): + return len(args) + 1 + # + s = 0 + d = {} + i = 0 + while i < x: + s += g(**d) # ID: call + i += 1 + return s + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('call') + ops = log.opnames(loop.ops_by_id('call')) + guards = [ops for ops in ops if ops.startswith('guard')] + assert guards == ["guard_no_overflow"] + + def test_kwargs(self): + # this is not a very precise test, could be improved + def main(x): + def g(**args): + return len(args) + # + s = 0 + d = {"a": 1} + i = 0 + while i < x: + s += g(**d) # ID: call + d[str(i)] = i + if i % 100 == 99: + d = {"a": 1} + i += 1 + return s + # + log = self.run(main, [1000]) + assert log.result == 50500 + loop, = log.loops_by_id('call') + print loop.ops_by_id('call') + ops = log.opnames(loop.ops_by_id('call')) + guards = [ops for ops in ops if ops.startswith('guard')] + print guards + assert len(guards) <= 20 + + def test_stararg_virtual(self): + def main(x): + def g(*args): + return len(args) + def h(a, b, c): + return c + # + s = 0 + for i in range(x): + l = [i, x, 2] + s += g(*l) # ID: g1 + s += h(*l) # ID: h1 + s += g(i, x, 2) # ID: g2 + a = 0 + for i in range(x): + l = [x, 2] + s += g(i, *l) # ID: g3 + s += h(i, *l) # ID: h2 + a = 0 + return s + # + log = self.run(main, [1000]) + assert log.result == 13000 + loop0, = log.loops_by_id('g1') + assert loop0.match_by_id('g1', """ + i20 = force_token() + i22 = int_add_ovf(i8, 3) + guard_no_overflow(descr=...) + """) + assert loop0.match_by_id('h1', """ + i20 = force_token() + i22 = int_add_ovf(i8, 2) + guard_no_overflow(descr=...) + """) + assert loop0.match_by_id('g2', """ + i27 = force_token() + i29 = int_add_ovf(i26, 3) + guard_no_overflow(descr=...) + """) + # + loop1, = log.loops_by_id('g3') + assert loop1.match_by_id('g3', """ + i21 = force_token() + i23 = int_add_ovf(i9, 3) + guard_no_overflow(descr=...) + """) + assert loop1.match_by_id('h2', """ + i25 = force_token() + i27 = int_add_ovf(i23, 2) + guard_no_overflow(descr=...) + """) + + def test_stararg(self): + def main(x): + def g(*args): + return args[-1] + def h(*args): + return len(args) + # + s = 0 + l = [] + i = 0 + while i < x: + l.append(1) + s += g(*l) # ID: g + i = h(*l) # ID: h + a = 0 + return s + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('g') + ops_g = log.opnames(loop.ops_by_id('g')) + ops_h = log.opnames(loop.ops_by_id('h')) + ops = ops_g + ops_h + assert 'new_with_vtable' not in ops + assert 'call_may_force' not in ops + + def test_call_builtin_function(self): + def main(n): + i = 2 + l = [] + while i < n: + i += 1 + l.append(i) # ID: append + a = 0 + return i, len(l) + # + log = self.run(main, [1000]) + assert log.result == (1000, 998) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('append', """ + i13 = getfield_gc(p8, descr=) + i15 = int_add(i13, 1) + call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) + guard_no_exception(descr=...) + p17 = getfield_gc(p8, descr=) + p19 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p19, i12, descr=) + setarrayitem_gc(p17, i13, p19, descr=) + """) + + def test_blockstack_virtualizable(self): + def main(n): + from pypyjit import residual_call + i = 0 + while i < n: + try: + residual_call(len, []) # ID: call + except: + pass + i += 1 + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_id('call') + assert loop.match_by_id('call', opcode='CALL_FUNCTION', expected_src=""" + # make sure that the "block" is not allocated + ... + i20 = force_token() + setfield_gc(p0, i20, descr=) + p22 = new_with_vtable(19511408) + p24 = new_array(1, descr=) + p26 = new_with_vtable(ConstClass(W_ListObject)) + p27 = new(descr=) + p29 = new_array(0, descr=) + setfield_gc(p27, p29, descr=) + setfield_gc(p26, p27, descr=<.* .*W_ListObject.inst_wrappeditems .*>) + setarrayitem_gc(p24, 0, p26, descr=) + setfield_gc(p22, p24, descr=) + p32 = call_may_force(11376960, p18, p22, descr=) + ... + """) + + def test_func_defaults(self): + def main(n): + i = 1 + while i < n: + i += len(xrange(i+1)) - i + return i + + log = self.run(main, [10000]) + assert log.result == 10000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i5, i6) + guard_true(i10, descr=...) + guard_not_invalidated(descr=...) + i120 = int_add(i5, 1) + --TICK-- + jump(..., descr=) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py @@ -0,0 +1,93 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestException(BaseTestPyPyC): + + def test_cmp_exc(self): + def f1(n): + # So we don't get a LOAD_GLOBAL op + KE = KeyError + i = 0 + while i < n: + try: + raise KE + except KE: # ID: except + i += 1 + return i + + log = self.run(f1, [10000]) + assert log.result == 10000 + loop, = log.loops_by_id("except") + ops = list(loop.ops_by_id("except", opcode="COMPARE_OP")) + assert ops == [] + + def test_exception_inside_loop_1(self): + def main(n): + while n: + try: + raise ValueError + except ValueError: + pass + n -= 1 + return n + # + log = self.run(main, [1000]) + assert log.result == 0 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i5 = int_is_true(i3) + guard_true(i5, descr=...) + guard_not_invalidated(descr=...) + --EXC-TICK-- + i12 = int_sub_ovf(i3, 1) + guard_no_overflow(descr=...) + --TICK-- + jump(..., descr=) + """) + + def test_exception_inside_loop_2(self): + def main(n): + def g(n): + raise ValueError(n) # ID: raise + def f(n): + g(n) + # + while n: + try: + f(n) + except ValueError: + pass + n -= 1 + return n + # + log = self.run(main, [1000]) + assert log.result == 0 + loop, = log.loops_by_filename(self.filepath) + ops = log.opnames(loop.ops_by_id('raise')) + assert 'new' not in ops + + def test_reraise(self): + def f(n): + i = 0 + while i < n: + try: + try: + raise KeyError + except KeyError: + raise + except KeyError: + i += 1 + return i + + log = self.run(f, [100000]) + assert log.result == 100000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i4, i5) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) + --EXC-TICK-- + i14 = int_add(i4, 1) + --TICK-- + jump(..., descr=) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -0,0 +1,30 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGlobals(BaseTestPyPyC): + def test_load_builtin(self): + def main(n): + import pypyjit + + i = 0 + while i < n: + l = len # ID: loadglobal + i += pypyjit.residual_call(l, "a") + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("loadglobal", """ + p10 = getfield_gc(p0, descr=) + guard_value(p10, ConstPtr(ptr11), descr=...) + p12 = getfield_gc(p10, descr=) + guard_value(p12, ConstPtr(ptr13), descr=...) + p15 = getfield_gc(ConstPtr(ptr14), descr=) + guard_isnull(p15, descr=...) + guard_not_invalidated(descr=...) + p19 = getfield_gc(ConstPtr(p17), descr=) + guard_value(p19, ConstPtr(ptr20), descr=...) + p22 = getfield_gc(ConstPtr(ptr21), descr=) + guard_nonnull(p22, descr=...) + """) \ No newline at end of file diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -0,0 +1,46 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestImport(BaseTestPyPyC): + + def test_import_in_function(self): + def main(n): + i = 0 + while i < n: + from sys import version # ID: import + i += 1 + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_id('import') + assert loop.match_by_id('import', """ + guard_not_invalidated(descr=...) + p11 = getfield_gc(ConstPtr(ptr10), descr=) + guard_value(p11, ConstPtr(ptr12), descr=...) + p14 = getfield_gc(ConstPtr(ptr13), descr=) + p16 = getfield_gc(ConstPtr(ptr15), descr=) + guard_value(p14, ConstPtr(ptr17), descr=...) + guard_isnull(p16, descr=...) + """) + + def test_import_fast_path(self, tmpdir): + pkg = tmpdir.join('mypkg').ensure(dir=True) + pkg.join('__init__.py').write("") + pkg.join('mod.py').write(str(py.code.Source(""" + def do_the_import(): + import sys + """))) + def main(path, n): + import sys + sys.path.append(path) + from mypkg.mod import do_the_import + for i in range(n): + do_the_import() + # + log = self.run(main, [str(tmpdir), 300]) + loop, = log.loops_by_filename(self.filepath) + # this is a check for a slow-down that introduced a + # call_may_force(absolute_import_with_lock). + for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")): + assert 'call' not in opname # no call-like opcode diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -0,0 +1,201 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestInstance(BaseTestPyPyC): + + def test_virtual_instance(self): + def main(n): + class A(object): + pass + # + i = 0 + while i < n: + a = A() + assert isinstance(a, A) + assert not isinstance(a, int) + a.x = 2 + i = i + a.x + return i + # + log = self.run(main, [1000], threshold = 400) + assert log.result == 1000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i5, i6) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) + i9 = int_add_ovf(i5, 2) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, i9, i6, descr=) + """) + + def test_load_attr(self): + src = ''' + class A(object): + pass + a = A() + a.x = 2 + def main(n): + i = 0 + while i < n: + i = i + a.x + return i + ''' + log = self.run(src, [1000]) + assert log.result == 1000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i9 = int_lt(i5, i6) + guard_true(i9, descr=...) + guard_not_invalidated(descr=...) + i10 = int_add_ovf(i5, i7) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) + """) + + def test_getattr_with_dynamic_attribute(self): + src = """ + class A(object): + pass + + l = ["x", "y"] + + def main(): + sum = 0 + a = A() + a.a1 = 0 + a.a2 = 0 + a.a3 = 0 + a.a4 = 0 + a.a5 = 0 # workaround, because the first five attributes need a promotion + a.x = 1 + a.y = 2 + i = 0 + while i < 500: + name = l[i % 2] + sum += getattr(a, name) + i += 1 + return sum + """ + log = self.run(src, []) + assert log.result == 250 + 250*2 + loops = log.loops_by_filename(self.filepath) + assert len(loops) == 1 + + def test_mutate_class(self): + def fn(n): + class A(object): + count = 1 + def __init__(self, a): + self.a = a + def f(self): + return self.count + i = 0 + a = A(1) + while i < n: + A.count += 1 # ID: mutate + i = a.f() # ID: meth1 + return i + # + log = self.run(fn, [1000], threshold=10) + assert log.result == 1000 + # + # first, we test the entry bridge + # ------------------------------- + entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) + ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') + assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', + 'getfield_gc', 'guard_nonnull_class'] + # the STORE_ATTR is folded away + assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] + # + # then, the actual loop + # ---------------------- + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i9 = int_lt(i8, i7) + guard_true(i9, descr=.*) + guard_not_invalidated(descr=.*) + i11 = int_add(i8, 1) + i12 = force_token() + --TICK-- + p20 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p20, i11, descr=) + setfield_gc(ConstPtr(ptr21), p20, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) + """) + + def test_oldstyle_newstyle_mix(self): + def main(): + class A: + pass + + class B(object, A): + def __init__(self, x): + self.x = x + + i = 0 + b = B(1) + while i < 100: + v = b.x # ID: loadattr + i += v + return i + + log = self.run(main, [], threshold=80) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('loadattr', + ''' + guard_not_invalidated(descr=...) + i19 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) + guard_no_exception(descr=...) + i21 = int_and(i19, _) + i22 = int_is_true(i21) + guard_true(i22, descr=...) + i26 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) + guard_no_exception(descr=...) + i28 = int_and(i26, _) + i29 = int_is_true(i28) + guard_true(i29, descr=...) + ''') + + def test_python_contains(self): + def main(): + class A(object): + def __contains__(self, v): + return True + + i = 0 + a = A() + while i < 100: + i += i in a # ID: contains + b = 0 # to make sure that JUMP_ABSOLUTE is not part of the ID + + log = self.run(main, [], threshold=80) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("contains", """ + guard_not_invalidated(descr=...) + i11 = force_token() + i12 = int_add_ovf(i5, i7) + guard_no_overflow(descr=...) + """) + + def test_id_compare_optimization(self): + def main(): + class A(object): + pass + # + i = 0 + a = A() + while i < 300: + new_a = A() + if new_a != a: # ID: compare + pass + i += 1 + return i + # + log = self.run(main, []) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("compare", "") # optimized away + diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -0,0 +1,296 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestIntbound(BaseTestPyPyC): + + def test_intbound_simple(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + ops = ('<', '>', '<=', '>=', '==', '!=') + nbr = (3, 7) + for o1 in ops: + for o2 in ops: + for n1 in nbr: + for n2 in nbr: + src = ''' + def f(i): + a, b = 3, 3 + if i %s %d: + a = 0 + else: + a = 1 + if i %s %d: + b = 0 + else: + b = 1 + return a + b * 2 + + def main(): + res = [0] * 4 + idx = [] + for i in range(15): + idx.extend([i] * 15) + for i in idx: + res[f(i)] += 1 + return res + + ''' % (o1, n1, o2, n2) + yield self.run_and_check, src + + def test_intbound_addsub_mix(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + tests = ('i > 4', 'i > 2', 'i + 1 > 2', '1 + i > 4', + 'i - 1 > 1', '1 - i > 1', '1 - i < -3', + 'i == 1', 'i == 5', 'i != 1', '-2 * i < -4') + for t1 in tests: + for t2 in tests: + src = ''' + def f(i): + a, b = 3, 3 + if %s: + a = 0 + else: + a = 1 + if %s: + b = 0 + else: + b = 1 + return a + b * 2 + + def main(): + res = [0] * 4 + idx = [] + for i in range(15): + idx.extend([i] * 15) + for i in idx: + res[f(i)] += 1 + return res + + ''' % (t1, t2) + yield self.run_and_check, src + + def test_intbound_gt(self): + def main(n): + i, a, b = 0, 0, 0 + while i < n: + if i > -1: + a += 1 + if i > -2: + b += 1 + i += 1 + return (a, b) + # + log = self.run(main, [300]) + assert log.result == (300, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, i9) + guard_true(i10, descr=...) + i12 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i14 = int_add_ovf(i6, 1) + guard_no_overflow(descr=...) + i17 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) + """) + + def test_intbound_sub_lt(self): + def main(): + i, a = 0, 0 + while i < 300: + if i - 10 < 295: + a += 1 + i += 1 + return a + # + log = self.run(main, []) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i5, 300) + guard_true(i7, descr=...) + i9 = int_sub_ovf(i5, 10) + guard_no_overflow(descr=...) + i11 = int_add_ovf(i4, 1) + guard_no_overflow(descr=...) + i13 = int_add(i5, 1) + --TICK-- + jump(p0, p1, p2, p3, i11, i13, descr=) + """) + + def test_intbound_addsub_ge(self): + def main(n): + i, a, b = 0, 0, 0 + while i < n: + if i + 5 >= 5: + a += 1 + if i - 1 >= -1: + b += 1 + i += 1 + return (a, b) + # + log = self.run(main, [300]) + assert log.result == (300, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, i9) + guard_true(i10, descr=...) + i12 = int_add_ovf(i8, 5) + guard_no_overflow(descr=...) + i14 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i16 = int_add_ovf(i6, 1) + guard_no_overflow(descr=...) + i19 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) + """) + + def test_intbound_addmul_ge(self): + def main(n): + i, a, b = 0, 0, 0 + while i < 300: + if i + 5 >= 5: + a += 1 + if 2 * i >= 0: + b += 1 + i += 1 + return (a, b) + # + log = self.run(main, [300]) + assert log.result == (300, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, 300) + guard_true(i10, descr=...) + i12 = int_add(i8, 5) + i14 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i16 = int_lshift(i8, 1) + i18 = int_add_ovf(i6, 1) + guard_no_overflow(descr=...) + i21 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) + """) + + def test_intbound_eq(self): + def main(a, n): + i, s = 0, 0 + while i < 300: + if a == 7: + s += a + 1 + elif i == 10: + s += i + else: + s += 1 + i += 1 + return s + # + log = self.run(main, [7, 300]) + assert log.result == main(7, 300) + log = self.run(main, [10, 300]) + assert log.result == main(10, 300) + log = self.run(main, [42, 300]) + assert log.result == main(42, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, 300) + guard_true(i10, descr=...) + i12 = int_eq(i8, 10) + guard_false(i12, descr=...) + i14 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i16 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) + """) + + def test_intbound_mul(self): + def main(a): + i, s = 0, 0 + while i < 300: + assert i >= 0 + if 2 * i < 30000: + s += 1 + else: + s += a + i += 1 + return s + # + log = self.run(main, [7]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i8 = int_lt(i6, 300) + guard_true(i8, descr=...) + i10 = int_lshift(i6, 1) + i12 = int_add_ovf(i5, 1) + guard_no_overflow(descr=...) + i14 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i12, i14, descr=) + """) + + def test_assert(self): + def main(a): + i, s = 0, 0 + while i < 300: + assert a == 7 + s += a + 1 + i += 1 + return s + log = self.run(main, [7]) + assert log.result == 300*8 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i8 = int_lt(i6, 300) + guard_true(i8, descr=...) + i10 = int_add_ovf(i5, 8) + guard_no_overflow(descr=...) + i12 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i10, i12, descr=) + """) + + def test_xor(self): + def main(b): + a = sa = 0 + while a < 300: + if a > 0: # Specialises the loop + pass + if b > 10: + pass + if a^b >= 0: # ID: guard + sa += 1 + sa += a^a # ID: a_xor_a + a += 1 + return sa + + log = self.run(main, [11]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # if both are >=0, a^b is known to be >=0 + # note that we know that b>10 + assert loop.match_by_id('guard', """ + i10 = int_xor(i5, i7) + """) + # + # x^x is always optimized to 0 + assert loop.match_by_id('a_xor_a', "") + + log = self.run(main, [9]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # we don't know that b>10, hence we cannot optimize it + assert loop.match_by_id('guard', """ + i10 = int_xor(i5, i7) + i12 = int_ge(i10, 0) + guard_true(i12, descr=...) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -0,0 +1,68 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestMinMax(BaseTestPyPyC): + + def test_min_max(self): + def main(): + i=0 + sa=0 + while i < 300: + sa+=min(max(i, 3000), 4000) + i+=1 + return sa + log = self.run(main, []) + assert log.result == 300*3000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i4, 300) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) + i9 = int_add_ovf(i5, 3000) + guard_no_overflow(descr=...) + i11 = int_add(i4, 1) + --TICK-- + jump(p0, p1, p2, p3, i11, i9, descr=) + """) + + def test_silly_max(self): + def main(): + i = 2 + sa = 0 + while i < 300: + lst = range(i) + sa += max(*lst) # ID: max + i += 1 + return sa + log = self.run(main, []) + assert log.result == main() + loop, = log.loops_by_filename(self.filepath) + # We dont want too many guards, but a residual call to min_max_loop + guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] + assert len(guards) < 20 + assert loop.match_by_id('max',""" + ... + p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) + ... + """) + + def test_iter_max(self): + def main(): + i = 2 + sa = 0 + while i < 300: + lst = range(i) + sa += max(lst) # ID: max + i += 1 + return sa + log = self.run(main, []) + assert log.result == main() + loop, = log.loops_by_filename(self.filepath) + # We dont want too many guards, but a residual call to min_max_loop + guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] + assert len(guards) < 20 + assert loop.match_by_id('max',""" + ... + p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py rename from pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py rename to pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -1,13 +1,8 @@ -import py, sys, re -import subprocess -from lib_pypy import disassembler -from pypy.tool.udir import udir -from pypy.tool import logparser -from pypy.module.pypyjit.test_pypy_c.model import Log -from pypy.module.pypyjit.test_pypy_c.test_model import BaseTestPyPyC +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC -class TestPyPyCNew(BaseTestPyPyC): +class TestMisc(BaseTestPyPyC): def test_f1(self): def f1(n): "Arbitrary test function." @@ -76,377 +71,6 @@ """) - def test_recursive_call(self): - def fn(): - def rec(n): - if n == 0: - return 0 - return 1 + rec(n-1) - # - # this loop is traced and then aborted, because the trace is too - # long. But then "rec" is marked as "don't inline" - i = 0 - j = 0 - while i < 20: - i += 1 - j += rec(100) - # - # next time we try to trace "rec", instead of inlining we compile - # it separately and generate a call_assembler - i = 0 - j = 0 - while i < 20: - i += 1 - j += rec(100) # ID: call_rec - a = 0 - return j - # - log = self.run(fn, [], threshold=18) - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('call_rec', """ - ... - p53 = call_assembler(..., descr=...) - guard_not_forced(descr=...) - guard_no_exception(descr=...) - ... - """) - - def test_cmp_exc(self): - def f1(n): - # So we don't get a LOAD_GLOBAL op - KE = KeyError - i = 0 - while i < n: - try: - raise KE - except KE: # ID: except - i += 1 - return i - - log = self.run(f1, [10000]) - assert log.result == 10000 - loop, = log.loops_by_id("except") - ops = list(loop.ops_by_id("except", opcode="COMPARE_OP")) - assert ops == [] - - def test_simple_call(self): - src = """ - OFFSET = 0 - def f(i): - return i + 1 + OFFSET # ID: add - def main(n): - i = 0 - while i < n+OFFSET: # ID: cond - i = f(f(i)) # ID: call - a = 0 - return i - """ - log = self.run(src, [1000], threshold=400) - assert log.result == 1000 - # first, we test what is inside the entry bridge - # ----------------------------------------------- - entry_bridge, = log.loops_by_id('call', is_entry_bridge=True) - # LOAD_GLOBAL of OFFSET - ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", - "getfield_gc", "guard_value", - "getfield_gc", "guard_isnull", - "getfield_gc", "guard_nonnull_class"] - # LOAD_GLOBAL of OFFSET but in different function partially folded - # away - # XXX could be improved - ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_isnull"] - # - # two LOAD_GLOBAL of f, the second is folded away - ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["getfield_gc", "guard_nonnull_class"] - # - assert entry_bridge.match_by_id('call', """ - p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) - p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) - p35 = getfield_gc(p29, descr=) - p36 = getfield_gc(p29, descr=) - p38 = call(ConstClass(getexecutioncontext), descr=) - p39 = getfield_gc(p38, descr=) - i40 = force_token() - p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) - i42 = getfield_gc(p38, descr=) - i43 = int_is_zero(i42) - guard_true(i43, descr=) - i50 = force_token() - """) - # - # then, we test the actual loop - # ----------------------------- - loop, = log.loops_by_id('call') - assert loop.match(""" - i12 = int_lt(i5, i6) - guard_true(i12, descr=) - i13 = force_token() - i15 = int_add(i5, 1) - i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) - i18 = force_token() - i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=) - i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) - """) - - def test_method_call(self): - def fn(n): - class A(object): - def __init__(self, a): - self.a = a - def f(self, i): - return self.a + i - i = 0 - a = A(1) - while i < n: - x = a.f(i) # ID: meth1 - i = a.f(x) # ID: meth2 - return i - # - log = self.run(fn, [1000], threshold=400) - assert log.result == 1000 - # - # first, we test the entry bridge - # ------------------------------- - entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) - ops = entry_bridge.ops_by_id('meth1', opcode='LOOKUP_METHOD') - assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', - 'guard_not_invalidated'] - # the second LOOKUP_METHOD is folded away - assert list(entry_bridge.ops_by_id('meth2', opcode='LOOKUP_METHOD')) == [] - # - # then, the actual loop - # ---------------------- - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i15 = int_lt(i6, i9) - guard_true(i15, descr=) - guard_not_invalidated(descr=) - i16 = force_token() - i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) - i18 = force_token() - i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) - """) - - def test_static_classmethod_call(self): - def fn(n): - class A(object): - @classmethod - def f(cls, i): - return i + (cls is A) + 1 - @staticmethod - def g(i): - return i - 1 - # - i = 0 - a = A() - while i < n: - x = a.f(i) - i = a.g(x) - return i - # - log = self.run(fn, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i14 = int_lt(i6, i9) - guard_true(i14, descr=) - guard_not_invalidated(descr=) - i15 = force_token() - i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) - i18 = force_token() - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) - """) - - def test_default_and_kw(self): - def main(n): - def f(i, j=1): - return i + j - # - i = 0 - while i < n: - i = f(f(i), j=1) # ID: call - a = 0 - return i - # - log = self.run(main, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_id('call') - assert loop.match_by_id('call', """ - i14 = force_token() - i16 = force_token() - """) - - def test_kwargs(self): - # this is not a very precise test, could be improved - def main(x): - def g(**args): - return len(args) - # - s = 0 - d = {} - for i in range(x): - s += g(**d) # ID: call - d[str(i)] = i - if i % 100 == 99: - d = {} - return s - # - log = self.run(main, [1000], threshold=400) - assert log.result == 49500 - loop, = log.loops_by_id('call') - ops = log.opnames(loop.ops_by_id('call')) - guards = [ops for ops in ops if ops.startswith('guard')] - assert len(guards) <= 5 - - def test_stararg_virtual(self): - def main(x): - def g(*args): - return len(args) - def h(a, b, c): - return c - # - s = 0 - for i in range(x): - l = [i, x, 2] - s += g(*l) # ID: g1 - s += h(*l) # ID: h1 - s += g(i, x, 2) # ID: g2 - a = 0 - for i in range(x): - l = [x, 2] - s += g(i, *l) # ID: g3 - s += h(i, *l) # ID: h2 - a = 0 - return s - # - log = self.run(main, [1000], threshold=400) - assert log.result == 13000 - loop0, = log.loops_by_id('g1') - assert loop0.match_by_id('g1', """ - i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) - i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) - """) - assert loop0.match_by_id('h1', """ - i20 = force_token() - i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) - """) - assert loop0.match_by_id('g2', """ - i27 = force_token() - i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) - """) - # - loop1, = log.loops_by_id('g3') - assert loop1.match_by_id('g3', """ - i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) - """) - assert loop1.match_by_id('h2', """ - i25 = force_token() - i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) - """) - - def test_stararg(self): - def main(x): - def g(*args): - return args[-1] - def h(*args): - return len(args) - # - s = 0 - l = [] - i = 0 - while i < x: - l.append(1) - s += g(*l) # ID: g - i = h(*l) # ID: h - a = 0 - return s - # - log = self.run(main, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_id('g') - ops_g = log.opnames(loop.ops_by_id('g')) - ops_h = log.opnames(loop.ops_by_id('h')) - ops = ops_g + ops_h - assert 'new_with_vtable' not in ops - assert 'call_may_force' not in ops - - def test_virtual_instance(self): - def main(n): - class A(object): - pass - # - i = 0 - while i < n: - a = A() - assert isinstance(a, A) - assert not isinstance(a, int) - a.x = 2 - i = i + a.x - return i - # - log = self.run(main, [1000], threshold = 400) - assert log.result == 1000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i5, i6) - guard_true(i7, descr=) - guard_not_invalidated(descr=) - i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, i9, i6, descr=) - """) - - def test_load_attr(self): - src = ''' - class A(object): - pass - a = A() - a.x = 2 - def main(n): - i = 0 - while i < n: - i = i + a.x - return i - ''' - log = self.run(src, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i9 = int_lt(i5, i6) - guard_true(i9, descr=) - guard_not_invalidated(descr=) - i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) - """) - def test_mixed_type_loop(self): def main(n): i = 0.0 @@ -455,40 +79,17 @@ i = j + i return i # - log = self.run(main, [1000], threshold=400) + log = self.run(main, [1000]) assert log.result == 1000.0 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = float_lt(f5, f7) - guard_true(i9, descr=) + guard_true(i9, descr=...) f10 = float_add(f8, f5) --TICK-- jump(p0, p1, p2, p3, p4, f10, p6, f7, f8, descr=) """) - def test_call_builtin_function(self): - def main(n): - i = 2 - l = [] - while i < n: - i += 1 - l.append(i) # ID: append - a = 0 - return i, len(l) - # - log = self.run(main, [1000], threshold=400) - assert log.result == (1000, 998) - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('append', """ - i13 = getfield_gc(p8, descr=) - i15 = int_add(i13, 1) - call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) - guard_no_exception(descr=) - p17 = getfield_gc(p8, descr=) - p19 = new_with_vtable(ConstClass(W_IntObject)) - setfield_gc(p19, i12, descr=) - setarrayitem_gc(p17, i13, p19, descr=) - """) def test_range_iter(self): def main(n): @@ -501,98 +102,28 @@ a = 0 return s # - log = self.run(main, [1000], threshold=400) + log = self.run(main, [1000]) assert log.result == 1000 * 999 / 2 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i11, i12) - guard_false(i16, descr=) + guard_false(i16, descr=...) i17 = int_mul(i11, i14) i18 = int_add(i15, i17) i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=) + guard_not_invalidated(descr=...) i23 = int_lt(i18, 0) - guard_false(i23, descr=) + guard_false(i23, descr=...) i25 = int_ge(i18, i9) - guard_false(i25, descr=) + guard_false(i25, descr=...) i27 = int_add_ovf(i7, i18) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) - def test_exception_inside_loop_1(self): - def main(n): - while n: - try: - raise ValueError - except ValueError: - pass - n -= 1 - return n - # - log = self.run(main, [1000], threshold=400) - assert log.result == 0 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i5 = int_is_true(i3) - guard_true(i5, descr=) - guard_not_invalidated(descr=) - --EXC-TICK-- - i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) - --TICK-- - jump(..., descr=) - """) - - def test_exception_inside_loop_2(self): - def main(n): - def g(n): - raise ValueError(n) # ID: raise - def f(n): - g(n) - # - while n: - try: - f(n) - except ValueError: - pass - n -= 1 - return n - # - log = self.run(main, [1000], threshold=400) - assert log.result == 0 - loop, = log.loops_by_filename(self.filepath) - ops = log.opnames(loop.ops_by_id('raise')) - assert 'new' not in ops - - def test_reraise(self): - def f(n): - i = 0 - while i < n: - try: - try: - raise KeyError - except KeyError: - raise - except KeyError: - i += 1 - return i - - log = self.run(f, [100000]) - assert log.result == 100000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i4, i5) - guard_true(i7, descr=) - guard_not_invalidated(descr=) - --EXC-TICK-- - i14 = int_add(i4, 1) - --TICK-- - jump(..., descr=) - """) def test_chain_of_guards(self): src = """ @@ -612,445 +143,11 @@ i += 1 return sum """ - log = self.run(src, [0], threshold=400) + log = self.run(src, [0]) assert log.result == 500*3 loops = log.loops_by_filename(self.filepath) assert len(loops) == 1 - def test_getattr_with_dynamic_attribute(self): - src = """ - class A(object): - pass - - l = ["x", "y"] - - def main(): - sum = 0 - a = A() - a.a1 = 0 - a.a2 = 0 - a.a3 = 0 - a.a4 = 0 - a.a5 = 0 # workaround, because the first five attributes need a promotion - a.x = 1 - a.y = 2 - i = 0 - while i < 500: - name = l[i % 2] - sum += getattr(a, name) - i += 1 - return sum - """ - log = self.run(src, [], threshold=400) - assert log.result == 250 + 250*2 - loops = log.loops_by_filename(self.filepath) - assert len(loops) == 1 - - def test_blockstack_virtualizable(self): - def main(n): - from pypyjit import residual_call - i = 0 - while i < n: - try: - residual_call(len, []) # ID: call - except: - pass - i += 1 - return i - # - log = self.run(main, [500], threshold=400) - assert log.result == 500 - loop, = log.loops_by_id('call') - assert loop.match_by_id('call', opcode='CALL_FUNCTION', expected_src=""" - # make sure that the "block" is not allocated - ... - i20 = force_token() - setfield_gc(p0, i20, descr=) - p22 = new_with_vtable(19511408) - p24 = new_array(1, descr=) - p26 = new_with_vtable(ConstClass(W_ListObject)) - p27 = new(descr=) - p29 = new_array(0, descr=) - setfield_gc(p27, p29, descr=) - setfield_gc(p26, p27, descr=<.* .*W_ListObject.inst_wrappeditems .*>) - setarrayitem_gc(p24, 0, p26, descr=) - setfield_gc(p22, p24, descr=) - p32 = call_may_force(11376960, p18, p22, descr=) - ... - """) - - def test_import_in_function(self): - def main(n): - i = 0 - while i < n: - from sys import version # ID: import - i += 1 - return i - # - log = self.run(main, [500], threshold=400) - assert log.result == 500 - loop, = log.loops_by_id('import') - assert loop.match_by_id('import', """ - p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) - p14 = getfield_gc(ConstPtr(ptr13), descr=) - p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) - """) - - def test_import_fast_path(self, tmpdir): - pkg = tmpdir.join('mypkg').ensure(dir=True) - pkg.join('__init__.py').write("") - pkg.join('mod.py').write(str(py.code.Source(""" - def do_the_import(): - import sys - """))) - def main(path, n): - import sys - sys.path.append(path) - from mypkg.mod import do_the_import - for i in range(n): - do_the_import() - # - log = self.run(main, [str(tmpdir), 300], threshold=200) - loop, = log.loops_by_filename(self.filepath) - # this is a check for a slow-down that introduced a - # call_may_force(absolute_import_with_lock). - for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")): - assert 'call' not in opname # no call-like opcode - - def test_arraycopy_disappears(self): - def main(n): - i = 0 - while i < n: - t = (1, 2, 3, i + 1) - t2 = t[:] - del t - i = t2[3] - del t2 - return i - # - log = self.run(main, [500], threshold=400) - assert log.result == 500 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i5, i6) - guard_true(i7, descr=) - i9 = int_add(i5, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, i9, i6, descr=) - """) - - def test_boolrewrite_inverse(self): - """ - Test for this case:: - guard(i < x) - ... - guard(i >= y) - - where x and y can be either constants or variables. There are cases in - which the second guard is proven to be always true. - """ - - for a, b, res, opt_expected in (('2000', '2000', 20001000, True), - ( '500', '500', 15001500, True), - ( '300', '600', 16001700, False), - ( 'a', 'b', 16001700, False), - ( 'a', 'a', 13001700, True)): - src = """ - def main(): - sa = 0 - a = 300 - b = 600 - for i in range(1000): - if i < %s: # ID: lt - sa += 1 - else: - sa += 2 - # - if i >= %s: # ID: ge - sa += 10000 - else: - sa += 20000 - return sa - """ % (a, b) - # - log = self.run(src, [], threshold=400) - assert log.result == res - loop, = log.loops_by_filename(self.filepath) - le_ops = log.opnames(loop.ops_by_id('lt')) - ge_ops = log.opnames(loop.ops_by_id('ge')) - assert le_ops.count('int_lt') == 1 - # - if opt_expected: - assert ge_ops.count('int_ge') == 0 - else: - # if this assert fails it means that the optimization was - # applied even if we don't expect to. Check whether the - # optimization is valid, and either fix the code or fix the - # test :-) - assert ge_ops.count('int_ge') == 1 - - def test_boolrewrite_reflex(self): - """ - Test for this case:: - guard(i < x) - ... - guard(y > i) - - where x and y can be either constants or variables. There are cases in - which the second guard is proven to be always true. - """ - for a, b, res, opt_expected in (('2000', '2000', 10001000, True), - ( '500', '500', 15001500, True), - ( '300', '600', 14001700, False), - ( 'a', 'b', 14001700, False), - ( 'a', 'a', 17001700, True)): - - src = """ - def main(): - sa = 0 - a = 300 - b = 600 - for i in range(1000): - if i < %s: # ID: lt - sa += 1 - else: - sa += 2 - if %s > i: # ID: gt - sa += 10000 - else: - sa += 20000 - return sa - """ % (a, b) - log = self.run(src, [], threshold=400) - assert log.result == res - loop, = log.loops_by_filename(self.filepath) - le_ops = log.opnames(loop.ops_by_id('lt')) - gt_ops = log.opnames(loop.ops_by_id('gt')) - assert le_ops.count('int_lt') == 1 - # - if opt_expected: - assert gt_ops.count('int_gt') == 0 - else: - # if this assert fails it means that the optimization was - # applied even if we don't expect to. Check whether the - # optimization is valid, and either fix the code or fix the - # test :-) - assert gt_ops.count('int_gt') == 1 - - - def test_boolrewrite_allcases_inverse(self): - """ - Test for this case:: - guard(i < x) - ... - guard(i > y) - - with all possible combination of binary comparison operators. This - test only checks that we get the expected result, not that any - optimization has been applied. - """ - ops = ('<', '>', '<=', '>=', '==', '!=') - for op1 in ops: - for op2 in ops: - for a,b in ((500, 500), (300, 600)): - src = """ - def main(): - sa = 0 - for i in range(300): - if i %s %d: - sa += 1 - else: - sa += 2 - if i %s %d: - sa += 10000 - else: - sa += 20000 - return sa - """ % (op1, a, op2, b) - self.run_and_check(src, threshold=200) - - src = """ - def main(): - sa = 0 - i = 0.0 - while i < 250.0: - if i %s %f: - sa += 1 - else: - sa += 2 - if i %s %f: - sa += 10000 - else: - sa += 20000 - i += 0.25 - return sa - """ % (op1, float(a)/4.0, op2, float(b)/4.0) - self.run_and_check(src, threshold=300) - - - def test_boolrewrite_allcases_reflex(self): - """ - Test for this case:: - guard(i < x) - ... - guard(x > i) - - with all possible combination of binary comparison operators. This - test only checks that we get the expected result, not that any - optimization has been applied. - """ - ops = ('<', '>', '<=', '>=', '==', '!=') - for op1 in ops: - for op2 in ops: - for a,b in ((500, 500), (300, 600)): - src = """ - def main(): - sa = 0 - for i in range(300): - if i %s %d: - sa += 1 - else: - sa += 2 - if %d %s i: - sa += 10000 - else: - sa += 20000 - return sa - """ % (op1, a, b, op2) - self.run_and_check(src, threshold=200) - - src = """ - def main(): - sa = 0 - i = 0.0 - while i < 250.0: - if i %s %f: - sa += 1 - else: - sa += 2 - if %f %s i: - sa += 10000 - else: - sa += 20000 - i += 0.25 - return sa - """ % (op1, float(a)/4.0, float(b)/4.0, op2) - self.run_and_check(src, threshold=300) - - def test_boolrewrite_ptr(self): - """ - This test only checks that we get the expected result, not that any - optimization has been applied. - """ - compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b') - for e1 in compares: - for e2 in compares: - src = """ - class tst(object): - pass - def main(): - a = tst() - b = tst() - c = tst() - sa = 0 - for i in range(300): - if %s: - sa += 1 - else: - sa += 2 - if %s: - sa += 10000 - else: - sa += 20000 - if i > 750: - a = b - return sa - """ % (e1, e2) - self.run_and_check(src, threshold=200) - - def test_array_sum(self): - def main(): - from array import array - img = array("i", range(128) * 5) * 480 - l, i = 0, 0 - while i < len(img): - l += img[i] - i += 1 - return l - # - log = self.run(main, []) - assert log.result == 19507200 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i13 = int_lt(i7, i9) - guard_true(i13, descr=) - i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) - i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) - i18 = int_add(i7, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) - """) - - def test_array_intimg(self): - def main(): - from array import array - img = array('i', range(3)) * (350 * 480) - intimg = array('i', (0,)) * (640 * 480) - l, i = 0, 640 - while i < 640 * 480: - assert len(img) == 3*350*480 - assert len(intimg) == 640*480 - l = l + img[i] - intimg[i] = (intimg[i-640] + l) - i += 1 - return intimg[i - 1] - # - log = self.run(main, []) - assert log.result == 73574560 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i13 = int_lt(i8, 307200) - guard_true(i13, descr=) - # the bound check guard on img has been killed (thanks to the asserts) - i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) - i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) - i17 = int_sub(i8, 640) - # the bound check guard on intimg has been killed (thanks to the asserts) - i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) - i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) - # on 64bit, there is a guard checking that i19 actually fits into 32bit - ... - setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) - i28 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) - """) - - def test_func_defaults(self): - def main(n): - i = 1 - while i < n: - i += len(xrange(i+1)) - i - return i - - log = self.run(main, [10000]) - assert log.result == 10000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i5, i6) - guard_true(i10, descr=) - i120 = int_add(i5, 1) - guard_not_invalidated(descr=) - --TICK-- - jump(..., descr=) - """) def test_unpack_iterable_non_list_tuple(self): def main(n): @@ -1067,667 +164,71 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i12, i13) - guard_false(i16, descr=) + guard_false(i16, descr=...) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) - guard_nonnull_class(p17, 146982464, descr=) + setfield_gc(p9, i19, descr=) + guard_nonnull_class(p17, 146982464, descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) - guard_true(i23, descr=) + guard_true(i23, descr=...) i24 = getfield_gc(p17, descr=) i25 = getarrayitem_raw(i24, 0, descr=<.*>) i27 = int_lt(1, i21) - guard_false(i27, descr=) + guard_false(i27, descr=...) i28 = int_add_ovf(i10, i25) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) - def test_mutate_class(self): - def fn(n): - class A(object): - count = 1 - def __init__(self, a): - self.a = a - def f(self): - return self.count - i = 0 - a = A(1) - while i < n: - A.count += 1 # ID: mutate - i = a.f() # ID: meth1 - return i + + def test_dont_trace_every_iteration(self): + def main(a, b): + i = sa = 0 + while i < 300: + if a > 0: + pass + if 1 < b < 2: + pass + sa += a % b + i += 1 + return sa # - log = self.run(fn, [1000], threshold=10) - assert log.result == 1000 - # - # first, we test the entry bridge - # ------------------------------- - entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) - ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') - assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc', 'guard_nonnull_class'] - # the STORE_ATTR is folded away - assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] - # - # then, the actual loop - # ---------------------- + log = self.run(main, [10, 20]) + assert log.result == 300 * (10 % 20) + assert log.jit_summary.tracing_no == 1 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i8 = getfield_gc_pure(p5, descr=) - i9 = int_lt(i8, i7) - guard_true(i9, descr=.*) - guard_not_invalidated(descr=.*) - i11 = int_add(i8, 1) - i12 = force_token() + i11 = int_lt(i7, 300) + guard_true(i11, descr=...) + i12 = int_add_ovf(i8, i9) + guard_no_overflow(descr=...) + i14 = int_add(i7, 1) --TICK-- - p20 = new_with_vtable(ConstClass(W_IntObject)) - setfield_gc(p20, i11, descr=) - setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i7, descr=) + jump(..., descr=...) """) + # + log = self.run(main, [-10, -20]) + assert log.result == 300 * (-10 % -20) + assert log.jit_summary.tracing_no == 1 - def test_intbound_simple(self): + def test_overflow_checking(self): """ This test only checks that we get the expected result, not that any optimization has been applied. """ - ops = ('<', '>', '<=', '>=', '==', '!=') - nbr = (3, 7) - for o1 in ops: - for o2 in ops: - for n1 in nbr: - for n2 in nbr: - src = ''' - def f(i): - a, b = 3, 3 - if i %s %d: - a = 0 - else: - a = 1 - if i %s %d: - b = 0 - else: - b = 1 - return a + b * 2 - - def main(): - res = [0] * 4 - idx = [] - for i in range(15): - idx.extend([i] * 15) - for i in idx: - res[f(i)] += 1 - return res - - ''' % (o1, n1, o2, n2) - self.run_and_check(src, threshold=200) - - def test_intbound_addsub_mix(self): - """ - This test only checks that we get the expected result, not that any - optimization has been applied. - """ - tests = ('i > 4', 'i > 2', 'i + 1 > 2', '1 + i > 4', - 'i - 1 > 1', '1 - i > 1', '1 - i < -3', - 'i == 1', 'i == 5', 'i != 1', '-2 * i < -4') - for t1 in tests: - for t2 in tests: - src = ''' - def f(i): - a, b = 3, 3 - if %s: - a = 0 - else: - a = 1 - if %s: - b = 0 - else: - b = 1 - return a + b * 2 - - def main(): - res = [0] * 4 - idx = [] - for i in range(15): - idx.extend([i] * 15) - for i in idx: - res[f(i)] += 1 - return res - - ''' % (t1, t2) - self.run_and_check(src, threshold=200) - - def test_intbound_gt(self): - def main(n): - i, a, b = 0, 0, 0 - while i < n: - if i > -1: - a += 1 - if i > -2: - b += 1 - i += 1 - return (a, b) + def main(): + import sys + def f(a,b): + if a < 0: return -1 + return a-b + # + total = sys.maxint - 2147483647 + for i in range(100000): + total += f(i, 5) + # + return total # - log = self.run(main, [300], threshold=200) - assert log.result == (300, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, i9) - guard_true(i10, descr=...) - i12 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i14 = int_add_ovf(i6, 1) - guard_no_overflow(descr=...) - i17 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) - """) - - def test_intbound_sub_lt(self): - def main(): - i, a = 0, 0 - while i < 300: - if i - 10 < 295: - a += 1 - i += 1 - return a - # - log = self.run(main, [], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i5, 300) - guard_true(i7, descr=...) - i9 = int_sub_ovf(i5, 10) - guard_no_overflow(descr=...) - i11 = int_add_ovf(i4, 1) - guard_no_overflow(descr=...) - i13 = int_add(i5, 1) - --TICK-- - jump(p0, p1, p2, p3, i11, i13, descr=) - """) - - def test_intbound_addsub_ge(self): - def main(n): - i, a, b = 0, 0, 0 - while i < n: - if i + 5 >= 5: - a += 1 - if i - 1 >= -1: - b += 1 - i += 1 - return (a, b) - # - log = self.run(main, [300], threshold=200) - assert log.result == (300, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, i9) - guard_true(i10, descr=...) - i12 = int_add_ovf(i8, 5) - guard_no_overflow(descr=...) - i14 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i16 = int_add_ovf(i6, 1) - guard_no_overflow(descr=...) - i19 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) - """) - - def test_intbound_addmul_ge(self): - def main(n): - i, a, b = 0, 0, 0 - while i < 300: - if i + 5 >= 5: - a += 1 - if 2 * i >= 0: - b += 1 - i += 1 - return (a, b) - # - log = self.run(main, [300], threshold=200) - assert log.result == (300, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, 300) - guard_true(i10, descr=...) - i12 = int_add(i8, 5) - i14 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i16 = int_lshift(i8, 1) - i18 = int_add_ovf(i6, 1) - guard_no_overflow(descr=...) - i21 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) - """) - - def test_intbound_eq(self): - def main(a, n): - i, s = 0, 0 - while i < 300: - if a == 7: - s += a + 1 - elif i == 10: - s += i - else: - s += 1 - i += 1 - return s - # - log = self.run(main, [7, 300], threshold=200) - assert log.result == main(7, 300) - log = self.run(main, [10, 300], threshold=200) - assert log.result == main(10, 300) - log = self.run(main, [42, 300], threshold=200) - assert log.result == main(42, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, 300) - guard_true(i10, descr=...) - i12 = int_eq(i8, 10) - guard_false(i12, descr=...) - i14 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i16 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) - """) - - def test_intbound_mul(self): - def main(a): - i, s = 0, 0 - while i < 300: - assert i >= 0 - if 2 * i < 30000: - s += 1 - else: - s += a - i += 1 - return s - # - log = self.run(main, [7], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i8 = int_lt(i6, 300) - guard_true(i8, descr=...) - i10 = int_lshift(i6, 1) - i12 = int_add_ovf(i5, 1) - guard_no_overflow(descr=...) - i14 = int_add(i6, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, i12, i14, descr=) - """) - - def test_assert(self): - def main(a): - i, s = 0, 0 - while i < 300: - assert a == 7 - s += a + 1 - i += 1 - return s - log = self.run(main, [7], threshold=200) - assert log.result == 300*8 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i8 = int_lt(i6, 300) - guard_true(i8, descr=...) - i10 = int_add_ovf(i5, 8) - guard_no_overflow(descr=...) - i12 = int_add(i6, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, i10, i12, descr=) - """) - - def test_zeropadded(self): - def main(): - from array import array - class ZeroPadded(array): - def __new__(cls, l): - self = array.__new__(cls, 'd', range(l)) - return self - - def __getitem__(self, i): - if i < 0 or i >= len(self): - return 0 - return array.__getitem__(self, i) # ID: get - # - buf = ZeroPadded(2000) - i = 10 - sa = 0 - while i < 2000 - 10: - sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] - i += 1 - return sa - - log = self.run(main, [], threshold=200) - assert log.result == 9895050.0 - loop, = log.loops_by_filename(self.filepath) - # - # check that the overloaded __getitem__ does not introduce double - # array bound checks. - # - # The force_token()s are still there, but will be eliminated by the - # backend regalloc, so they are harmless - assert loop.match(ignore_ops=['force_token'], - expected_src=""" - ... - i20 = int_ge(i18, i8) - guard_false(i20, descr=...) - f21 = getarrayitem_raw(i13, i18, descr=...) - f23 = getarrayitem_raw(i13, i14, descr=...) - f24 = float_add(f21, f23) - f26 = getarrayitem_raw(i13, i6, descr=...) - f27 = float_add(f24, f26) - i29 = int_add(i6, 1) - i31 = int_ge(i29, i8) - guard_false(i31, descr=...) - f33 = getarrayitem_raw(i13, i29, descr=...) - f34 = float_add(f27, f33) - i36 = int_add(i6, 2) - i38 = int_ge(i36, i8) - guard_false(i38, descr=...) - f39 = getarrayitem_raw(i13, i36, descr=...) - ... - """) - - - def test_circular(self): - def main(): - from array import array - class Circular(array): - def __new__(cls): - self = array.__new__(cls, 'd', range(256)) - return self - def __getitem__(self, i): - assert len(self) == 256 - return array.__getitem__(self, i & 255) - # - buf = Circular() - i = 10 - sa = 0 - while i < 2000 - 10: - sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] - i += 1 - return sa - # - log = self.run(main, [], threshold=200) - assert log.result == 1239690.0 - loop, = log.loops_by_filename(self.filepath) - # - # check that the array bound checks are removed - # - # The force_token()s are still there, but will be eliminated by the - # backend regalloc, so they are harmless - assert loop.match(ignore_ops=['force_token'], - expected_src=""" - ... - i17 = int_and(i14, 255) - f18 = getarrayitem_raw(i8, i17, descr=...) - f20 = getarrayitem_raw(i8, i9, descr=...) - f21 = float_add(f18, f20) - f23 = getarrayitem_raw(i8, i10, descr=...) - f24 = float_add(f21, f23) - i26 = int_add(i6, 1) - i29 = int_and(i26, 255) - f30 = getarrayitem_raw(i8, i29, descr=...) - f31 = float_add(f24, f30) - i33 = int_add(i6, 2) - i36 = int_and(i33, 255) - f37 = getarrayitem_raw(i8, i36, descr=...) - ... - """) - - def test_min_max(self): - def main(): - i=0 - sa=0 - while i < 300: - sa+=min(max(i, 3000), 4000) - i+=1 - return sa - log = self.run(main, [], threshold=200) - assert log.result == 300*3000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i4, 300) - guard_true(i7, descr=...) - i9 = int_add_ovf(i5, 3000) - guard_no_overflow(descr=...) - i11 = int_add(i4, 1) - --TICK-- - jump(p0, p1, p2, p3, i11, i9, descr=) - """) - - def test_silly_max(self): - def main(): - i = 2 - sa = 0 - while i < 300: - lst = range(i) - sa += max(*lst) # ID: max - i += 1 - return sa - log = self.run(main, [], threshold=200) - assert log.result == main() - loop, = log.loops_by_filename(self.filepath) - # We dont want too many guards, but a residual call to min_max_loop - guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] - assert len(guards) < 20 - assert loop.match_by_id('max',""" - ... - p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) - ... - """) - - def test_iter_max(self): - def main(): - i = 2 - sa = 0 - while i < 300: - lst = range(i) - sa += max(lst) # ID: max - i += 1 - return sa - log = self.run(main, [], threshold=200) - assert log.result == main() - loop, = log.loops_by_filename(self.filepath) - # We dont want too many guards, but a residual call to min_max_loop - guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] - assert len(guards) < 20 - assert loop.match_by_id('max',""" - ... - p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) - ... - """) - - def test__ffi_call(self): - from pypy.rlib.test.test_libffi import get_libm_name - def main(libm_name): - try: - from _ffi import CDLL, types - except ImportError: - sys.stderr.write('SKIP: cannot import _ffi\n') - return 0 - - libm = CDLL(libm_name) - pow = libm.getfunc('pow', [types.double, types.double], - types.double) - i = 0 - res = 0 - while i < 300: - res += pow(2, 3) - i += 1 - return pow.getaddr(), res - # - libm_name = get_libm_name(sys.platform) - log = self.run(main, [libm_name], threshold=200) - pow_addr, res = log.result - assert res == 8.0 * 300 - loop, = log.loops_by_filename(self.filepath) - # XXX: write the actual test when we merge this to jitypes2 - ## ops = self.get_by_bytecode('CALL_FUNCTION') - ## assert len(ops) == 2 # we get two loops, because of specialization - ## call_function = ops[0] - ## last_ops = [op.getopname() for op in call_function[-5:]] - ## assert last_ops == ['force_token', - ## 'setfield_gc', - ## 'call_may_force', - ## 'guard_not_forced', - ## 'guard_no_exception'] - ## call = call_function[-3] - ## assert call.getarg(0).value == pow_addr - ## assert call.getarg(1).value == 2.0 - ## assert call.getarg(2).value == 3.0 - - def test_xor(self): - def main(b): - a = sa = 0 - while a < 300: - if a > 0: # Specialises the loop - pass - if b > 10: - pass - if a^b >= 0: # ID: guard - sa += 1 - sa += a^a # ID: a_xor_a - a += 1 - return sa - - log = self.run(main, [11], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - # if both are >=0, a^b is known to be >=0 - # note that we know that b>10 - assert loop.match_by_id('guard', """ - i10 = int_xor(i5, i7) - """) - # - # x^x is always optimized to 0 - assert loop.match_by_id('a_xor_a', "") - - log = self.run(main, [9], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - # we don't know that b>10, hence we cannot optimize it - assert loop.match_by_id('guard', """ - i10 = int_xor(i5, i7) - i12 = int_ge(i10, 0) - guard_true(i12, descr=...) - """) - - def test_shift_intbound(self): - def main(b): - res = 0 - a = 0 - while a < 300: - assert a >= 0 - assert 0 <= b <= 10 - val = a >> b - if val >= 0: # ID: rshift - res += 1 - val = a << b - if val >= 0: # ID: lshift - res += 2 - a += 1 - return res - # - log = self.run(main, [2], threshold=200) - assert log.result == 300*3 - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('rshift', "") # guard optimized away - assert loop.match_by_id('lshift', "") # guard optimized away - - def test_lshift_and_then_rshift(self): - py.test.skip('fixme, this optimization is disabled') - def main(b): - res = 0 - a = 0 - while res < 300: - assert a >= 0 - assert 0 <= b <= 10 - res = (a << b) >> b # ID: shift - a += 1 - return res - # - log = self.run(main, [2], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('shift', "") # optimized away - - def test_division_to_rshift(self): - py.test.skip('in-progress') - def main(b): - res = 0 - a = 0 - while a < 300: - assert a >= 0 - assert 0 <= b <= 10 - res = a/b # ID: div - a += 1 - return res - # - log = self.run(main, [3], threshold=200) - #assert log.result == 149 - loop, = log.loops_by_filename(self.filepath) - import pdb;pdb.set_trace() - assert loop.match_by_id('div', "") # optimized away - - def test_oldstyle_newstyle_mix(self): - def main(): - class A: - pass - - class B(object, A): - def __init__(self, x): - self.x = x - - i = 0 - b = B(1) - while i < 100: - v = b.x # ID: loadattr - i += v - return i - - log = self.run(main, [], threshold=80) - loop, = log.loops_by_filename(self.filepath) - loop.match_by_id('loadattr', - ''' - guard_not_invalidated(descr=...) - i19 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) - guard_no_exception(descr=...) - i21 = int_and(i19, _) - i22 = int_is_true(i21) - guard_true(i22, descr=...) - i26 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) - guard_no_exception(descr=...) - i28 = int_and(i26, _) - i29 = int_is_true(i28) - guard_true(i29, descr=...) - ''') - - def test_python_contains(self): - def main(): - class A(object): - def __contains__(self, v): - return True - - i = 0 - a = A() - while i < 100: - i += i in a # ID: contains - - log = self.run(main, [], threshold=80) - loop, = log.loops_by_filename(self.filemath) - # XXX: haven't confirmed his is correct, it's probably missing a - # few instructions - loop.match_by_id("contains", """ - i1 = int_add(i0, 1) - """) + self.run_and_check(main, []) diff --git a/pypy/module/pypyjit/test_pypy_c/test_shift.py b/pypy/module/pypyjit/test_pypy_c/test_shift.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_shift.py @@ -0,0 +1,166 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestShift(BaseTestPyPyC): + + def test_shift_intbound(self): + def main(b): + res = 0 + a = 0 + while a < 300: + assert a >= 0 + assert 0 <= b <= 10 + val = a >> b + if val >= 0: # ID: rshift + res += 1 + val = a << b + if val >= 0: # ID: lshift + res += 2 + a += 1 + return res + # + log = self.run(main, [2]) + assert log.result == 300*3 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('rshift', "") # guard optimized away + assert loop.match_by_id('lshift', "") # guard optimized away + + def test_lshift_and_then_rshift(self): + py.test.skip('fixme, this optimization is disabled') + def main(b): + res = 0 + a = 0 + while res < 300: + assert a >= 0 + assert 0 <= b <= 10 + res = (a << b) >> b # ID: shift + a += 1 + return res + # + log = self.run(main, [2]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('shift', "") # optimized away + + def test_division_to_rshift(self): + def main(b): + res = 0 + a = 0 + while a < 300: + assert a >= 0 + assert 0 <= b <= 10 + res = a/b # ID: div + a += 1 + return res + # + log = self.run(main, [3]) + assert log.result == 99 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('div', """ + i10 = int_floordiv(i6, i7) + i11 = int_mul(i10, i7) + i12 = int_sub(i6, i11) + i14 = int_rshift(i12, 63) + i15 = int_add(i10, i14) + """) + + def test_division_to_rshift_allcases(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + avalues = ('a', 'b', 7, -42, 8) + bvalues = ['b'] + range(-10, 0) + range(1,10) + code = '' + for a in avalues: + for b in bvalues: + code += ' sa += %s / %s\n' % (a, b) + src = """ + def main(a, b): + i = sa = 0 + while i < 300: +%s + i += 1 + return sa + """ % code + self.run_and_check(src, [ 10, 20]) + self.run_and_check(src, [ 10, -20]) + self.run_and_check(src, [-10, -20]) + + def test_mod(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + avalues = ('a', 'b', 7, -42, 8) + bvalues = ['b'] + range(-10, 0) + range(1,10) + code = '' + for a in avalues: + for b in bvalues: + code += ' sa += %s %% %s\n' % (a, b) + src = """ + def main(a, b): + i = sa = 0 + while i < 2000: + if a > 0: pass + if 1 < b < 2: pass +%s + i += 1 + return sa + """ % code + self.run_and_check(src, [ 10, 20]) + self.run_and_check(src, [ 10, -20]) + self.run_and_check(src, [-10, -20]) + + def test_shift_allcases(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + from sys import maxint + def main(a, b): + i = sa = 0 + while i < 300: + if a > 0: # Specialises the loop + pass + if b < 2 and b > 0: + pass + if (a >> b) >= 0: + sa += 1 + if (a << b) > 2: + sa += 10000 + i += 1 + return sa + # + maxvals = (-maxint-1, -maxint, maxint-1, maxint) + for a in (-4, -3, -2, -1, 0, 1, 2, 3, 4) + maxvals: + for b in (0, 1, 2, 31, 32, 33, 61, 62, 63): + yield self.run_and_check, main, [a, b] + + def test_revert_shift_allcases(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + from sys import maxint + + def main(a, b, c): + from sys import maxint + i = sa = 0 + while i < 300: + if 0 < a < 10: pass + if -100 < b < 100: pass + if -maxint/2 < c < maxint/2: pass + sa += (a<>a + sa += (b<>a + sa += (c<>a + sa += (a<<100)>>100 + sa += (b<<100)>>100 + sa += (c<<100)>>100 + i += 1 + return long(sa) + + for a in (1, 4, 8, 100): + for b in (-10, 10, -201, 201, -maxint/3, maxint/3): + for c in (-10, 10, -maxint/3, maxint/3): + yield self.run_and_check, main, [a, b, c] diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -0,0 +1,107 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestString(BaseTestPyPyC): + def test_lookup_default_encoding(self): + def main(n): + import string + i = 0 + letters = string.letters + uletters = unicode(string.letters) + while i < n: + i += letters[i % len(letters)] == uletters[i % len(letters)] + return i + + log = self.run(main, [300]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i14 = int_lt(i6, i9) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) + i15 = int_mod(i6, i10) + i17 = int_rshift(i15, 63) + i18 = int_and(i10, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i10) + guard_false(i22, descr=...) + i23 = strgetitem(p11, i19) + i24 = int_ge(i19, i12) + guard_false(i24, descr=...) + i25 = unicodegetitem(p13, i19) + p27 = newstr(1) + strsetitem(p27, 0, i23) + p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) + guard_no_exception(descr=...) + i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) + guard_true(i32, descr=...) + i34 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) + + def test_long(self): + def main(n): + import string + i = 1 + while i < n: + i += int(long(string.digits[i % len(string.digits)], 16)) + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i13 = int_eq(i6, -9223372036854775808) + guard_false(i13, descr=...) + i15 = int_mod(i6, i8) + i17 = int_rshift(i15, 63) + i18 = int_and(i8, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i8) + guard_false(i22, descr=...) + i23 = strgetitem(p10, i19) + p25 = newstr(1) + strsetitem(p25, 0, i23) + p28 = call(ConstClass(strip_spaces), p25, descr=) + guard_no_exception(descr=...) + i29 = strlen(p28) + i30 = int_is_true(i29) + guard_true(i30, descr=...) + i32 = int_sub(i29, 1) + i33 = strgetitem(p28, i32) + i35 = int_eq(i33, 108) + guard_false(i35, descr=...) + i37 = int_eq(i33, 76) + guard_false(i37, descr=...) + i39 = strgetitem(p28, 0) + i41 = int_eq(i39, 45) + guard_false(i41, descr=...) + i43 = int_eq(i39, 43) + guard_false(i43, descr=...) + i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=) + guard_false(i43, descr=...) + i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=) + guard_false(i46, descr=...) + p51 = new_with_vtable(21136408) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, i29, descr=) + setfield_gc(p51, 1, descr=) + setfield_gc(p51, 16, descr=) + setfield_gc(p51, p28, descr=) + p55 = call(ConstClass(parse_digit_string), p51, descr=) + guard_no_exception(descr=...) + i57 = call(ConstClass(rbigint.toint), p55, descr=) + guard_no_exception(descr=...) + i58 = int_add_ovf(i6, i57) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) + """) \ No newline at end of file diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -7,6 +7,8 @@ class Module(MixedModule): """Sys Builtin Module. """ + _immutable_fields_ = ["defaultencoding?"] + def __init__(self, space, w_name): """NOT_RPYTHON""" # because parent __init__ isn't if space.config.translating: diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c b/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c --- a/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c +++ b/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c @@ -43,6 +43,12 @@ qsort(base, num, width, compare); } +EXPORT(char) deref_LP_c_char_p(char** argv) +{ + char* s = *argv; + return s[0]; +} + EXPORT(int *) _testfunc_ai8(int a[8]) { return a; diff --git a/pypy/module/test_lib_pypy/ctypes_tests/support.py b/pypy/module/test_lib_pypy/ctypes_tests/support.py --- a/pypy/module/test_lib_pypy/ctypes_tests/support.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/support.py @@ -1,4 +1,5 @@ import py +import sys import ctypes py.test.importorskip("ctypes", "1.0.2") @@ -14,6 +15,16 @@ if _rawffi: py.test.skip("white-box tests for pypy _rawffi based ctypes impl") +def del_funcptr_refs_maybe(obj, attrname): + dll = getattr(obj, attrname, None) + if not dll: + return + _FuncPtr = dll._FuncPtr + for name in dir(dll): + obj = getattr(dll, name, None) + if isinstance(obj, _FuncPtr): + delattr(dll, name) + class BaseCTypesTestChecker: def setup_class(cls): if _rawffi: @@ -21,8 +32,21 @@ for _ in range(4): gc.collect() cls.old_num = _rawffi._num_of_allocated_objects() - + + def teardown_class(cls): + if sys.pypy_translation_info['translation.gc'] == 'boehm': + return # it seems that boehm has problems with __del__, so not + # everything is freed + # + mod = sys.modules[cls.__module__] + del_funcptr_refs_maybe(mod, 'dll') + del_funcptr_refs_maybe(mod, 'dll2') + del_funcptr_refs_maybe(mod, 'lib') + del_funcptr_refs_maybe(mod, 'testdll') + del_funcptr_refs_maybe(mod, 'ctdll') + del_funcptr_refs_maybe(cls, '_dll') + # if hasattr(cls, 'old_num'): import gc for _ in range(4): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py @@ -0,0 +1,82 @@ +# unittest for SOME ctypes com function calls. +# Can't resist from implementing some kind of mini-comtypes +# theller ;-) + +import py +import sys +if sys.platform != "win32": + py.test.skip('windows only test') + +import ctypes, new, unittest +from ctypes.wintypes import HRESULT +from _ctypes import COMError + +oleaut32 = ctypes.OleDLL("oleaut32") + +class UnboundMethod(object): + def __init__(self, func, index, name): + self.func = func + self.index = index + self.name = name + self.__doc__ = func.__doc__ + + def __repr__(self): + return "" % (self.index, self.name, id(self)) + + def __get__(self, instance, owner): + if instance is None: + return self + return new.instancemethod(self.func, instance, owner) + +def commethod(index, restype, *argtypes): + """A decorator that generates COM methods. The decorated function + itself is not used except for it's name.""" + def make_commethod(func): + comfunc = ctypes.WINFUNCTYPE(restype, *argtypes)(index, func.__name__) + comfunc.__name__ = func.__name__ + comfunc.__doc__ = func.__doc__ + return UnboundMethod(comfunc, index, func.__name__) + return make_commethod + +class ICreateTypeLib2(ctypes.c_void_p): + + @commethod(1, ctypes.c_long) + def AddRef(self): + pass + + @commethod(2, ctypes.c_long) + def Release(self): + pass + + @commethod(4, HRESULT, ctypes.c_wchar_p) + def SetName(self): + """Set the name of the library.""" + + @commethod(12, HRESULT) + def SaveAllChanges(self): + pass + + +CreateTypeLib2 = oleaut32.CreateTypeLib2 +CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, ctypes.POINTER(ICreateTypeLib2)) + +################################################################ + +def test_basic_comtypes(): + punk = ICreateTypeLib2() + hr = CreateTypeLib2(0, "foobar.tlb", punk) + assert hr == 0 + + assert 2 == punk.AddRef() + assert 3 == punk.AddRef() + assert 4 == punk.AddRef() + + punk.SetName("TypeLib_ByPYPY") + py.test.raises(COMError, lambda: punk.SetName(None)) + + # This would save the typelib to disk. + ## punk.SaveAllChanges() + + assert 3 == punk.Release() + assert 2 == punk.Release() + assert 1 == punk.Release() diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py @@ -0,0 +1,103 @@ +from ctypes import CDLL, POINTER, pointer, c_byte, c_int, c_char_p +import sys +import py +from support import BaseCTypesTestChecker + +class MyCDLL(CDLL): + def __getattr__(self, attr): + fn = self[attr] # this way it's not cached as an attribute + fn._slowpath_allowed = False + return fn + +def setup_module(mod): + import conftest + _ctypes_test = str(conftest.sofile) + mod.dll = MyCDLL(_ctypes_test) # slowpath not allowed + mod.dll2 = CDLL(_ctypes_test) # slowpath allowed + + +class TestFastpath(BaseCTypesTestChecker): + + def test_fastpath_forbidden(self): + def myfunc(): + pass + # + tf_b = dll.tf_b + tf_b.restype = c_byte + # + # so far, it's still using the slowpath + assert not tf_b._is_fastpath + tf_b.callable = myfunc + tf_b.argtypes = (c_byte,) + # errcheck prevented the fastpath to kick in + assert not tf_b._is_fastpath + # + del tf_b.callable + tf_b.argtypes = (c_byte,) # try to re-enable the fastpath + assert tf_b._is_fastpath + # + assert not tf_b._slowpath_allowed + py.test.raises(AssertionError, "tf_b.callable = myfunc") + py.test.raises(AssertionError, "tf_b('aaa')") # force a TypeError + + def test_simple_args(self): + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + assert tf_b(-126) == -42 + + def test_pointer_args(self): + f = dll._testfunc_p_p + f.restype = POINTER(c_int) + f.argtypes = [POINTER(c_int)] + v = c_int(42) + result = f(pointer(v)) + assert type(result) == POINTER(c_int) + assert result.contents.value == 42 + + def test_simple_pointer_args(self): + f = dll.my_strchr + f.argtypes = [c_char_p, c_int] + f.restype = c_char_p + mystr = c_char_p("abcd") + result = f(mystr, ord("b")) + assert result == "bcd" + + @py.test.mark.xfail + def test_strings(self): + f = dll.my_strchr + f.argtypes = [c_char_p, c_int] + f.restype = c_char_p + # python strings need to be converted to c_char_p, but this is + # supported only in the slow path so far + result = f("abcd", ord("b")) + assert result == "bcd" + + def test_errcheck(self): + def errcheck(result, func, args): + return 'hello' + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + tf_b.errcheck = errcheck + assert tf_b(-126) == 'hello' + + +class TestFallbackToSlowpath(BaseCTypesTestChecker): + + def test_argtypes_is_None(self): + tf_b = dll2.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_char_p,) # this is intentionally wrong + tf_b.argtypes = None # kill the fast path + assert not tf_b._is_fastpath + assert tf_b(-126) == -42 + + def test_callable_is_None(self): + tf_b = dll2.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + tf_b.callable = lambda x: x+1 + assert not tf_b._is_fastpath + assert tf_b(-126) == -125 + tf_b.callable = None diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -91,6 +91,13 @@ result = f(0, 0, 0, 0, 0, 0) assert result == u'\x00' + def test_char_result(self): + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_char + result = f(0, 0, 0, 0, 0, 0) + assert result == '\x00' + def test_voidresult(self): f = dll._testfunc_v f.restype = None @@ -125,6 +132,16 @@ # You cannot assing character format codes as restype any longer raises(TypeError, setattr, f, "restype", "i") + + def test_truncate_python_longs(self): + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_int + x = sys.maxint * 2 + result = f(x, x, x, x, 0, 0) + assert result == -8 + + def test_floatresult(self): f = dll._testfunc_f_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] @@ -211,8 +228,19 @@ result = f(byref(c_int(99))) assert not result.contents == 99 + def test_convert_pointers(self): + f = dll.deref_LP_c_char_p + f.restype = c_char + f.argtypes = [POINTER(c_char_p)] + # + s = c_char_p('hello world') + ps = pointer(s) + assert f(ps) == 'h' + assert f(s) == 'h' # automatic conversion from char** to char* + def test_errors_1(self): f = dll._testfunc_p_p + f.argtypes = [POINTER(c_int)] f.restype = c_int class X(Structure): @@ -393,6 +421,23 @@ result = f("abcd", ord("b")) assert result == "bcd" + def test_keepalive_buffers(self, monkeypatch): + import gc + f = dll.my_strchr + f.argtypes = [c_char_p] + f.restype = c_char_p + # + orig__call_funcptr = f._call_funcptr + def _call_funcptr(funcptr, *newargs): + gc.collect() + gc.collect() + gc.collect() + return orig__call_funcptr(funcptr, *newargs) + monkeypatch.setattr(f, '_call_funcptr', _call_funcptr) + # + result = f("abcd", ord("b")) + assert result == "bcd" + def test_caching_bug_1(self): # the same test as test_call_some_args, with two extra lines # in the middle that trigger caching in f._ptr, which then @@ -428,6 +473,16 @@ u = dll.ret_un_func(a[1]) assert u.y == 33*10000 + def test_cache_funcptr(self): + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + assert tf_b(-126) == -42 + ptr = tf_b._ptr + assert ptr is not None + assert tf_b(-126) == -42 + assert tf_b._ptr is ptr + def test_warnings(self): import warnings warnings.simplefilter("always") @@ -439,6 +494,22 @@ assert "C function without declared arguments called" in str(w[0].message) assert "C function without declared return type called" in str(w[1].message) + def test_errcheck(self): + py.test.skip('fixme') + def errcheck(result, func, args): + assert result == -42 + assert type(result) is int + arg, = args + assert arg == -126 + assert type(arg) is int + return result + # + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + tf_b.errcheck = errcheck + assert tf_b(-126) == -42 + del tf_b.errcheck with warnings.catch_warnings(record=True) as w: dll.get_an_integer.argtypes = [] dll.get_an_integer() diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py @@ -12,8 +12,10 @@ from _ctypes.function import CFuncPtr def guess(value): - cobj = CFuncPtr._conv_param(None, value) - return type(cobj) + _, cobj, ctype = CFuncPtr._conv_param(None, value) + return ctype + ## cobj = CFuncPtr._conv_param(None, value) + ## return type(cobj) assert guess(13) == c_int assert guess(0) == c_int diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py @@ -125,6 +125,9 @@ if t is c_longdouble: # no support for 'g' in the struct module continue code = t._type_ # the typecode + if code == 'g': + # typecode not supported by "struct" + continue align = struct.calcsize("c%c" % code) - struct.calcsize(code) # alignment of the type... diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py @@ -12,6 +12,13 @@ mod._ctypes_test = str(conftest.sofile) class TestPointers(BaseCTypesTestChecker): + + def test_get_ffi_argtype(self): + P = POINTER(c_int) + ffitype = P.get_ffi_argtype() + assert P.get_ffi_argtype() is ffitype + assert ffitype.deref_pointer() is c_int.get_ffi_argtype() + def test_pointer_crash(self): class A(POINTER(c_ulong)): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py b/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py @@ -15,6 +15,10 @@ mod.wcslen.argtypes = [ctypes.c_wchar_p] mod.func = dll._testfunc_p_p + def teardown_module(mod): + del mod.func + del mod.wcslen + class TestUnicode(BaseCTypesTestChecker): def setup_method(self, method): self.prev_conv_mode = ctypes.set_conversion_mode("ascii", "strict") diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -384,8 +384,9 @@ # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) - stack_items_w = self.crnt_frame.valuestack_w - for i in range(self.crnt_frame.valuestackdepth-1, -1, -1): + f = self.crnt_frame + stack_items_w = f.locals_stack_w + for i in range(f.valuestackdepth-1, f.nlocals-1, -1): w_v = stack_items_w[i] if isinstance(w_v, Constant): if w_v.value is oldvalue: diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py --- a/pypy/objspace/flow/framestate.py +++ b/pypy/objspace/flow/framestate.py @@ -10,7 +10,7 @@ def __init__(self, state): if isinstance(state, PyFrame): # getfastscope() can return real None, for undefined locals - data = state.getfastscope() + state.savevaluestack() + data = state.save_locals_stack() if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -36,11 +36,9 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): - fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) # Nones == undefined locals - frame.restorevaluestack(data[fastlocals:-2]) + frame.restore_locals_stack(data[:-2]) # Nones == undefined locals if data[-2] == Constant(None): assert data[-1] == Constant(None) frame.last_exception = None diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py --- a/pypy/objspace/flow/test/test_framestate.py +++ b/pypy/objspace/flow/test/test_framestate.py @@ -25,7 +25,7 @@ dummy = Constant(None) #dummy.dummy = True arg_list = ([Variable() for i in range(formalargcount)] + - [dummy] * (len(frame.fastlocals_w) - formalargcount)) + [dummy] * (frame.nlocals - formalargcount)) frame.setfastscope(arg_list) return frame @@ -42,7 +42,7 @@ def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1 != fs2 @@ -55,7 +55,7 @@ def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general @@ -63,7 +63,7 @@ def test_restore_frame(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs1.restoreframe(frame) assert fs1 == FrameState(frame) @@ -82,25 +82,26 @@ def test_getoutputargs(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable - # fastlocals_w[-1] -> fastlocals_w[-1] is Constant(None) - assert outputargs == [frame.fastlocals_w[0], Constant(None)] + # locals_w[n-1] -> locals_w[n-1] is Constant(None) + assert outputargs == [frame.locals_stack_w[0], Constant(None)] def test_union_different_constants(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(42) + frame.locals_stack_w[frame.nlocals-1] = Constant(42) fs2 = FrameState(frame) fs3 = fs1.union(fs2) fs3.restoreframe(frame) - assert isinstance(frame.fastlocals_w[-1], Variable) # generalized + assert isinstance(frame.locals_stack_w[frame.nlocals-1], Variable) + # ^^^ generalized def test_union_spectag(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(SpecTag()) + frame.locals_stack_w[frame.nlocals-1] = Constant(SpecTag()) fs2 = FrameState(frame) assert fs1.union(fs2) is None # UnionError diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + w_dict = jit.promote(w_dict) + self = jit.promote(self) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + @jit.elidable + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,91 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,18 +1,20 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS -from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize +from pypy.rlib.debug import mark_dict_non_null + +from pypy.rlib import rerased def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -28,48 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -88,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -140,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -149,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -159,106 +140,90 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + self.switch_to_object_strategy(w_dict) - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_length(self): - return len(self.r_dict_content) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError + def length(self, w_dict): + return 0 -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) + def clear(self, w_dict): + return -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -300,319 +265,255 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = {} +class AbstractTypedStrategy(object): + _mixin_ = True - def impl_setitem(self, w_key, w_value): + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, key, w_value): - self.content[key] = w_value + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] return - elif _is_sane_hash(space, w_key_type): - raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) - def impl_length(self): - return len(self.content) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) - def impl_getitem_str(self, key): - return self.content.get(key, None) + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return ObjectIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + + def setitem_str(self, w_dict, key, w_value): + assert key is not None + self.unerase(w_dict.dstorage)[key] = w_value + + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().impl_fallback_getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) - def impl_delitem(self, w_key): + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) + return space.is_w(space.type(w_obj), space.w_int) - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) -class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): +class IntIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - + return None, None init_signature = Signature(['seq_or_map'], None, 'kwargs') @@ -835,6 +736,8 @@ class W_DictMultiIterObject(W_Object): from pypy.objspace.std.dicttype import dictiter_typedef as typedef + _immutable_fields_ = ["iteratorimplementation", "itertype"] + def __init__(w_self, space, iteratorimplementation, itertype): w_self.space = space w_self.iteratorimplementation = iteratorimplementation @@ -919,7 +822,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,121 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): @@ -311,6 +311,10 @@ classofinstance=classofinstance, strdict=strdict) + def newset(self): + from pypy.objspace.std.setobject import newset + return W_SetObject(self, newset(self)) + def newslice(self, w_start, w_end, w_step): return W_SliceObject(w_start, w_end, w_step) @@ -318,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) @@ -29,3 +38,33 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -137,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -176,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -195,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -233,8 +234,33 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2: 2, "c": 3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l + def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -267,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -297,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -316,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -366,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} @@ -527,6 +549,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +734,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +749,64 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -759,6 +847,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj @@ -790,6 +882,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +895,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +927,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1012,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1027,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1071,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1083,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1104,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,20 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) + + def test_slot_name_conflict(self): class A(object): @@ -604,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -50,6 +50,10 @@ u = self.space.wrap(set('simsalabim')) assert self.space.eq_w(s,u) + def test_space_newset(self): + s = self.space.newset() + assert self.space.str_w(self.space.repr(s)) == 'set([])' + class AppTestAppSetTest: def test_subtype(self): class subset(set):pass diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: @@ -447,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/pytest.ini b/pypy/pytest.ini new file mode 100644 --- /dev/null +++ b/pypy/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --assertmode=old \ No newline at end of file diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py --- a/pypy/rlib/clibffi.py +++ b/pypy/rlib/clibffi.py @@ -10,6 +10,7 @@ from pypy.rlib.rmmap import alloc from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal from pypy.rlib.rdynload import DLOpenError, DLLHANDLE +from pypy.rlib import jit from pypy.tool.autopath import pypydir from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform @@ -18,6 +19,10 @@ import sys import ctypes.util +from pypy.tool.ansi_print import ansi_log +log = py.log.Producer("libffi") +py.log.setconsumer("libffi", ansi_log) + # maaaybe isinstance here would be better. Think _MSVC = platform.name == "msvc" _MINGW = platform.name == "mingw32" @@ -67,12 +72,17 @@ result = os.path.join(dir, 'libffi.a') if os.path.exists(result): return result - raise ImportError("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("trying to use the dynamic library instead...") + return None + path_libffi_a = None if hasattr(platform, 'library_dirs_for_libffi_a'): + path_libffi_a = find_libffi_a() + if path_libffi_a is not None: # platforms on which we want static linking libraries = [] - link_files = [find_libffi_a()] + link_files = [path_libffi_a] else: # platforms on which we want dynamic linking libraries = ['ffi'] @@ -261,6 +271,7 @@ elif _MSVC: get_libc_handle = external('pypy_get_libc_handle', [], DLLHANDLE) + @jit.dont_look_inside def get_libc_name(): return rwin32.GetModuleFileName(get_libc_handle()) diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec @@ -273,15 +288,17 @@ class JitHintError(Exception): """Inconsistency in the JIT hints.""" -PARAMETERS = {'threshold': 1000, +PARAMETERS = {'threshold': 1032, # just above 1024 + 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -336,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -574,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -591,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -1,12 +1,15 @@ +from __future__ import with_statement + from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.objectmodel import specialize, enforceargs, we_are_translated -from pypy.rlib.rarithmetic import intmask, r_uint +from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat from pypy.rlib import jit from pypy.rlib import clibffi from pypy.rlib.clibffi import get_libc_name, FUNCFLAG_CDECL, AbstractFuncPtr, \ - push_arg_as_ffiptr, c_ffi_call + push_arg_as_ffiptr, c_ffi_call, FFI_TYPE_STRUCT from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal from pypy.rlib.rdynload import DLLHANDLE +from pypy.rlib.longlong2float import longlong2float, float2longlong class types(object): """ @@ -31,17 +34,21 @@ setattr(cls, name, value) cls.slong = clibffi.cast_type_to_ffitype(rffi.LONG) cls.ulong = clibffi.cast_type_to_ffitype(rffi.ULONG) + cls.slonglong = clibffi.cast_type_to_ffitype(rffi.LONGLONG) + cls.ulonglong = clibffi.cast_type_to_ffitype(rffi.ULONGLONG) + cls.wchar_t = clibffi.cast_type_to_ffitype(lltype.UniChar) del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. """ if ffi_type is types.void: return 'v' elif ffi_type is types.double: return 'f' - elif ffi_type is types.pointer: return 'i' + elif ffi_type is types.float: return 's' + elif ffi_type is types.pointer: return 'u' # elif ffi_type is types.schar: return 'i' elif ffi_type is types.uchar: return 'u' @@ -58,13 +65,19 @@ elif ffi_type is types.uint16: return 'u' elif ffi_type is types.sint32: return 'i' elif ffi_type is types.uint32: return 'u' - ## we only support integers that fit in a lltype.Signed (==rffi.LONG) - ## (on 64-bit platforms, types.sint64 is types.slong and the case is - ## caught above) - ## elif ffi_type is types.sint64: return 'i' - ## elif ffi_type is types.uint64: return 'u' + ## (note that on 64-bit platforms, types.sint64 is types.slong and the + ## case is caught above) + elif ffi_type is types.sint64: return 'I' + elif ffi_type is types.uint64: return 'U' + # + elif types.is_struct(ffi_type): return 'S' raise KeyError + @staticmethod + @jit.elidable + def is_struct(ffi_type): + return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) + types._import() @specialize.arg(0) @@ -78,8 +91,11 @@ sz = rffi.sizeof(TYPE) return sz <= rffi.sizeof(rffi.LONG) + # ====================================================================== +IS_32_BIT = (r_uint.BITS == 32) + @specialize.memo() def _check_type(TYPE): if isinstance(TYPE, lltype.Ptr): @@ -105,11 +121,37 @@ val = rffi.cast(rffi.LONG, val) elif TYPE is rffi.DOUBLE: cls = FloatArg + elif TYPE is rffi.LONGLONG or TYPE is rffi.ULONGLONG: + raise TypeError, 'r_(u)longlong not supported by arg(), use arg_(u)longlong()' + elif TYPE is rffi.FLOAT: + raise TypeError, 'r_singlefloat not supported by arg(), use arg_singlefloat()' else: raise TypeError, 'Unsupported argument type: %s' % TYPE self._append(cls(val)) return self + def arg_raw(self, val): + self._append(RawArg(val)) + + def arg_longlong(self, val): + """ + Note: this is a hack. So far, the JIT does not support long longs, so + you must pass it as if it were a python Float (rffi.DOUBLE). You can + use the convenience functions longlong2float and float2longlong to do + the conversions. Note that if you use long longs, the call won't + be jitted at all. + """ + assert IS_32_BIT # use a normal integer on 64-bit platforms + self._append(LongLongArg(val)) + + def arg_singlefloat(self, val): + """ + Note: you must pass a python Float (rffi.DOUBLE), not a r_singlefloat + (else the jit complains). Note that if you use single floats, the + call won't be jitted at all. + """ + self._append(SingleFloatArg(val)) + def _append(self, arg): if self.first is None: self.first = self.last = arg @@ -132,8 +174,9 @@ def push(self, func, ll_args, i): func._push_int(self.intval, ll_args, i) + class FloatArg(AbstractArg): - """ An argument holding a float + """ An argument holding a python float (i.e. a C double) """ def __init__(self, floatval): @@ -142,6 +185,37 @@ def push(self, func, ll_args, i): func._push_float(self.floatval, ll_args, i) +class RawArg(AbstractArg): + """ An argument holding a raw pointer to put inside ll_args + """ + + def __init__(self, ptrval): + self.ptrval = ptrval + + def push(self, func, ll_args, i): + func._push_raw(self.ptrval, ll_args, i) + +class SingleFloatArg(AbstractArg): + """ An argument representing a C float (but holding a C double) + """ + + def __init__(self, floatval): + self.floatval = floatval + + def push(self, func, ll_args, i): + func._push_single_float(self.floatval, ll_args, i) + + +class LongLongArg(AbstractArg): + """ An argument representing a C long long (but holding a C double) + """ + + def __init__(self, floatval): + self.floatval = floatval + + def push(self, func, ll_args, i): + func._push_longlong(self.floatval, ll_args, i) + # ====================================================================== @@ -164,8 +238,8 @@ # ======================================================================== @jit.unroll_safe - @specialize.arg(2) - def call(self, argchain, RESULT): + @specialize.arg(2, 3) + def call(self, argchain, RESULT, is_struct=False): # WARNING! This code is written carefully in a way that the JIT # optimizer will see a sequence of calls like the following: # @@ -179,6 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) @@ -190,10 +265,24 @@ i += 1 arg = arg.next # - if _fits_into_long(RESULT): + if is_struct: + assert types.is_struct(self.restype) + res = self._do_call_raw(self.funcsym, ll_args) + elif _fits_into_long(RESULT): + assert not types.is_struct(self.restype) res = self._do_call_int(self.funcsym, ll_args) elif RESULT is rffi.DOUBLE: return self._do_call_float(self.funcsym, ll_args) + elif RESULT is rffi.FLOAT: + # XXX: even if RESULT is FLOAT, we still return a DOUBLE, else the + # jit complains. Note that the jit is disabled in this case + return self._do_call_single_float(self.funcsym, ll_args) + elif RESULT is rffi.LONGLONG or RESULT is rffi.ULONGLONG: + # XXX: even if RESULT is LONGLONG, we still return a DOUBLE, else the + # jit complains. Note that the jit is disabled in this case + # (it's not a typo, we really return a DOUBLE) + assert IS_32_BIT + return self._do_call_longlong(self.funcsym, ll_args) elif RESULT is lltype.Void: return self._do_call_void(self.funcsym, ll_args) else: @@ -222,11 +311,26 @@ def _push_int(self, value, ll_args, i): self._push_arg(value, ll_args, i) + @jit.dont_look_inside + def _push_raw(self, value, ll_args, i): + ll_args[i] = value + @jit.oopspec('libffi_push_float(self, value, ll_args, i)') @enforceargs( None, float, None, int) # fix the annotation for tests def _push_float(self, value, ll_args, i): self._push_arg(value, ll_args, i) + @jit.dont_look_inside + def _push_single_float(self, value, ll_args, i): + self._push_arg(r_singlefloat(value), ll_args, i) + + @jit.dont_look_inside + def _push_longlong(self, floatval, ll_args, i): + """ + Takes a longlong represented as a python Float. It's a hack for the + jit, else we could not see the whole libffi module at all""" + self._push_arg(float2longlong(floatval), ll_args, i) + @jit.oopspec('libffi_call_int(self, funcsym, ll_args)') def _do_call_int(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, rffi.LONG) @@ -235,6 +339,21 @@ def _do_call_float(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, rffi.DOUBLE) + @jit.dont_look_inside + def _do_call_single_float(self, funcsym, ll_args): + single_res = self._do_call(funcsym, ll_args, rffi.FLOAT) + return float(single_res) + + @jit.dont_look_inside + def _do_call_raw(self, funcsym, ll_args): + # same as _do_call_int, but marked as jit.dont_look_inside + return self._do_call(funcsym, ll_args, rffi.LONG) + + @jit.dont_look_inside + def _do_call_longlong(self, funcsym, ll_args): + llres = self._do_call(funcsym, ll_args, rffi.LONGLONG) + return longlong2float(llres) + @jit.oopspec('libffi_call_void(self, funcsym, ll_args)') def _do_call_void(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, lltype.Void) @@ -265,7 +384,14 @@ rffi.cast(rffi.VOIDPP, ll_args)) if RESULT is not lltype.Void: TP = lltype.Ptr(rffi.CArray(RESULT)) - res = rffi.cast(TP, ll_result)[0] + buf = rffi.cast(TP, ll_result) + if types.is_struct(self.restype): + assert RESULT == rffi.LONG + # for structs, we directly return the buffer and transfer the + # ownership + res = rffi.cast(RESULT, buf) + else: + res = buf[0] else: res = None self._free_buffers(ll_result, ll_args) @@ -274,11 +400,19 @@ def _free_buffers(self, ll_result, ll_args): if ll_result: - lltype.free(ll_result, flavor='raw') + self._free_buffer_maybe(rffi.cast(rffi.VOIDP, ll_result), self.restype) for i in range(len(self.argtypes)): - lltype.free(ll_args[i], flavor='raw') + argtype = self.argtypes[i] + self._free_buffer_maybe(ll_args[i], argtype) lltype.free(ll_args, flavor='raw') + def _free_buffer_maybe(self, buf, ffitype): + # if it's a struct, the buffer is not freed and the ownership is + # already of the caller (in case of ll_args buffers) or transferred to + # it (in case of ll_result buffer) + if not types.is_struct(ffitype): + lltype.free(buf, flavor='raw') + # ====================================================================== @@ -288,11 +422,8 @@ def __init__(self, libname): """Load the library, or raises DLOpenError.""" self.lib = rffi.cast(DLLHANDLE, 0) - ll_libname = rffi.str2charp(libname) - try: + with rffi.scoped_str2charp(libname) as ll_libname: self.lib = dlopen(ll_libname) - finally: - lltype.free(ll_libname, flavor='raw') def __del__(self): if self.lib: @@ -302,3 +433,6 @@ def getpointer(self, name, argtypes, restype, flags=FUNCFLAG_CDECL): return Func(name, argtypes, restype, dlsym(self.lib, name), flags=flags, keepalive=self) + + def getaddressindll(self, name): + return dlsym(self.lib, name) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -30,25 +30,18 @@ return llval from pypy.translator.tool.cbuild import ExternalCompilationInfo -eci = ExternalCompilationInfo(post_include_bits=[""" +eci = ExternalCompilationInfo(includes=['string.h', 'assert.h'], + post_include_bits=[""" static double pypy__longlong2float(long long x) { - int i; double dd; - char *p = (char*)&x; - char *d = (char*)ⅆ - for(i = 0; i < 8; i++) { - d[i] = p[i]; - } + assert(sizeof(double) == 8 && sizeof(long long) == 8); + memcpy(&dd, &x, 8); return dd; } static long long pypy__float2longlong(double x) { - int i; long long ll; - char *p = (char*)&x; - char *l = (char*)≪ - for(i = 0; i < 8; i++) { - l[i] = p[i]; - } + assert(sizeof(double) == 8 && sizeof(long long) == 8); + memcpy(&ll, &x, 8); return ll; } """]) @@ -56,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -191,6 +191,21 @@ hop.exception_cannot_occur() return hop.genop('gc_can_move', hop.args_v, resulttype=hop.r_result) +def _make_sure_does_not_move(p): + """'p' is a non-null GC object. This (tries to) make sure that the + object does not move any more, by forcing collections if needed. + Warning: should ideally only be used with the minimark GC, and only + on objects that are already a bit old, so have a chance to be + already non-movable.""" + if not we_are_translated(): + return + i = 0 + while can_move(p): + if i > 6: + raise NotImplementedError("can't make object non-movable!") + collect(i) + i += 1 + def _heap_stats(): raise NotImplementedError # can't be run directly @@ -257,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -134,7 +134,8 @@ def external(name, argtypes, restype, **kw): kw['compilation_info'] = eci - eci.export_symbols += (name,) + if not kw.get('macro', False): + eci.export_symbols += (name,) return rffi.llexternal( name, argtypes, restype, **kw) @@ -150,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rrandom.py b/pypy/rlib/rrandom.py --- a/pypy/rlib/rrandom.py +++ b/pypy/rlib/rrandom.py @@ -24,8 +24,7 @@ def __init__(self, seed=r_uint(0)): self.state = [r_uint(0)] * N self.index = 0 - if seed: - self.init_genrand(seed) + self.init_genrand(seed) def init_genrand(self, s): mt = self.state diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -141,7 +141,8 @@ def construct_stream_tower(stream, buffering, universal, reading, writing, binary): if buffering == 0: # no buffering - pass + if reading: # force some minimal buffering for readline() + stream = ReadlineInputStream(stream) elif buffering == 1: # line-buffering if writing: stream = LineBufferingOutputStream(stream) @@ -749,6 +750,113 @@ flush_buffers=False) +class ReadlineInputStream(Stream): + + """Minimal buffering input stream. + + Only does buffering for readline(). The other kinds of reads, and + all writes, are not buffered at all. + """ + + bufsize = 2**13 # 8 K + + def __init__(self, base, bufsize=-1): + self.base = base + self.do_read = base.read # function to fill buffer some more + self.do_seek = base.seek # seek to a byte offset + if bufsize == -1: # Get default from the class + bufsize = self.bufsize + self.bufsize = bufsize # buffer size (hint only) + self.buf = None # raw data (may contain "\n") + self.bufstart = 0 + + def flush_buffers(self): + if self.buf is not None: + try: + self.do_seek(self.bufstart-len(self.buf), 1) + except MyNotImplementedError: + pass + else: + self.buf = None + self.bufstart = 0 + + def readline(self): + if self.buf is not None: + i = self.buf.find('\n', self.bufstart) + else: + self.buf = '' + i = -1 + # + if i < 0: + self.buf = self.buf[self.bufstart:] + self.bufstart = 0 + while True: + bufsize = max(self.bufsize, len(self.buf) >> 2) + data = self.do_read(bufsize) + if not data: + result = self.buf # end-of-file reached + self.buf = None + return result + startsearch = len(self.buf) # there is no '\n' in buf so far + self.buf += data + i = self.buf.find('\n', startsearch) + if i >= 0: + break + # + i += 1 + result = self.buf[self.bufstart:i] + self.bufstart = i + return result + + def peek(self): + if self.buf is None: + return '' + if self.bufstart > 0: + self.buf = self.buf[self.bufstart:] + self.bufstart = 0 + return self.buf + + def tell(self): + pos = self.base.tell() + if self.buf is not None: + pos -= (len(self.buf) - self.bufstart) + return pos + + def readall(self): + result = self.base.readall() + if self.buf is not None: + result = self.buf[self.bufstart:] + result + self.buf = None + self.bufstart = 0 + return result + + def read(self, n): + if self.buf is None: + return self.do_read(n) + else: + m = n - (len(self.buf) - self.bufstart) + start = self.bufstart + if m > 0: + result = self.buf[start:] + self.do_read(m) + self.buf = None + self.bufstart = 0 + return result + elif n >= 0: + self.bufstart = start + n + return self.buf[start : self.bufstart] + else: + return '' + + seek = PassThrough("seek", flush_buffers=True) + write = PassThrough("write", flush_buffers=True) + truncate = PassThrough("truncate", flush_buffers=True) + flush = PassThrough("flush", flush_buffers=True) + flushable = PassThrough("flushable", flush_buffers=False) + close = PassThrough("close", flush_buffers=False) + try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", + flush_buffers=False) + + class BufferingOutputStream(Stream): """Standard buffering output stream. diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rlib/test/test_libffi.py b/pypy/rlib/test/test_libffi.py --- a/pypy/rlib/test/test_libffi.py +++ b/pypy/rlib/test/test_libffi.py @@ -2,8 +2,10 @@ import sys from pypy.rpython.lltypesystem import rffi, lltype from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED -from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name +from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong +from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name, make_struct_ffitype_e from pypy.rlib.libffi import CDLL, Func, get_libc_name, ArgChain, types +from pypy.rlib.libffi import longlong2float, float2longlong, IS_32_BIT class TestLibffiMisc(BaseFfiTest): @@ -50,6 +52,18 @@ del lib assert not ALLOCATED + def test_longlong_as_float(self): + from pypy.translator.c.test.test_genc import compile + maxint64 = r_longlong(9223372036854775807) + def fn(x): + d = longlong2float(x) + ll = float2longlong(d) + return ll + assert fn(maxint64) == maxint64 + # + fn2 = compile(fn, [r_longlong]) + res = fn2(maxint64) + assert res == maxint64 class TestLibffiCall(BaseFfiTest): """ @@ -97,7 +111,7 @@ def get_libfoo(self): return self.CDLL(self.libfoo_name) - def call(self, funcspec, args, RESULT, init_result=0): + def call(self, funcspec, args, RESULT, init_result=0, is_struct=False): """ Call the specified function after constructing and ArgChain with the arguments in ``args``. @@ -114,8 +128,20 @@ func = lib.getpointer(name, argtypes, restype) chain = ArgChain() for arg in args: - chain.arg(arg) - return func.call(chain, RESULT) + if isinstance(arg, r_singlefloat): + chain.arg_singlefloat(float(arg)) + elif IS_32_BIT and isinstance(arg, r_longlong): + chain.arg_longlong(longlong2float(arg)) + elif IS_32_BIT and isinstance(arg, r_ulonglong): + arg = rffi.cast(rffi.LONGLONG, arg) + chain.arg_longlong(longlong2float(arg)) + elif isinstance(arg, tuple): + methname, arg = arg + meth = getattr(chain, methname) + meth(arg) + else: + chain.arg(arg) + return func.call(chain, RESULT, is_struct=is_struct) def check_loops(self, *args, **kwds): """ @@ -137,7 +163,7 @@ res = self.call(func, [38, 4.2], rffi.LONG) assert res == 42 self.check_loops({ - 'call_may_force': 1, + 'call_release_gil': 1, 'guard_no_exception': 1, 'guard_not_forced': 1, 'int_add': 1, @@ -150,7 +176,7 @@ func = (libm, 'pow', [types.double, types.double], types.double) res = self.call(func, [2.0, 3.0], rffi.DOUBLE, init_result=0.0) assert res == 8.0 - self.check_loops(call_may_force=1, guard_no_exception=1, guard_not_forced=1) + self.check_loops(call_release_gil=1, guard_no_exception=1, guard_not_forced=1) def test_cast_result(self): """ @@ -163,7 +189,7 @@ func = (libfoo, 'cast_to_uchar_and_ovf', [types.sint], types.uchar) res = self.call(func, [0], rffi.UCHAR) assert res == 200 - self.check_loops(call_may_force=1, guard_no_exception=1, guard_not_forced=1) + self.check_loops(call_release_gil=1, guard_no_exception=1, guard_not_forced=1) def test_cast_argument(self): """ @@ -267,6 +293,76 @@ res = self.call(get_dummy, [], rffi.LONG) assert res == initval+1 + def test_single_float_args(self): + """ + float sum_xy_float(float x, float y) + { + return x+y; + } + """ + from ctypes import c_float # this is used only to compute the expected result + libfoo = self.get_libfoo() + func = (libfoo, 'sum_xy_float', [types.float, types.float], types.float) + x = r_singlefloat(12.34) + y = r_singlefloat(56.78) + res = self.call(func, [x, y], rffi.FLOAT, init_result=0.0) + expected = c_float(c_float(12.34).value + c_float(56.78).value).value + assert res == expected + + def test_slonglong_args(self): + """ + long long sum_xy_longlong(long long x, long long y) + { + return x+y; + } + """ + maxint32 = 2147483647 # we cannot really go above maxint on 64 bits + # (and we would not test anything, as there long + # is the same as long long) + libfoo = self.get_libfoo() + func = (libfoo, 'sum_xy_longlong', [types.slonglong, types.slonglong], + types.slonglong) + if IS_32_BIT: + x = r_longlong(maxint32+1) + y = r_longlong(maxint32+2) + zero = longlong2float(r_longlong(0)) + else: + x = maxint32+1 + y = maxint32+2 + zero = 0 + res = self.call(func, [x, y], rffi.LONGLONG, init_result=zero) + if IS_32_BIT: + # obscure, on 32bit it's really a long long, so it returns a + # DOUBLE because of the JIT hack + res = float2longlong(res) + expected = maxint32*2 + 3 + assert res == expected + + def test_ulonglong_args(self): + """ + unsigned long long sum_xy_ulonglong(unsigned long long x, + unsigned long long y) + { + return x+y; + } + """ + maxint64 = 9223372036854775807 # maxint64+1 does not fit into a + # longlong, but it does into a + # ulonglong + libfoo = self.get_libfoo() + func = (libfoo, 'sum_xy_ulonglong', [types.ulonglong, types.ulonglong], + types.ulonglong) + x = r_ulonglong(maxint64+1) + y = r_ulonglong(2) + res = self.call(func, [x, y], rffi.ULONGLONG, init_result=0) + if IS_32_BIT: + # obscure, on 32bit it's really a long long, so it returns a + # DOUBLE because of the JIT hack + res = float2longlong(res) + res = rffi.cast(rffi.ULONGLONG, res) + expected = maxint64 + 3 + assert res == expected + def test_wrong_number_of_arguments(self): from pypy.rpython.llinterp import LLException libfoo = self.get_libfoo() @@ -287,3 +383,57 @@ my_raises("self.call(func, [38], rffi.LONG)") # one less my_raises("self.call(func, [38, 12.3, 42], rffi.LONG)") # one more + + + def test_byval_argument(self): + """ + struct Point { + long x; + long y; + }; + + long sum_point(struct Point p) { + return p.x + p.y; + } + """ + libfoo = CDLL(self.libfoo_name) + ffi_point_struct = make_struct_ffitype_e(0, 0, [types.slong, types.slong]) + ffi_point = ffi_point_struct.ffistruct + sum_point = (libfoo, 'sum_point', [ffi_point], types.slong) + # + ARRAY = rffi.CArray(rffi.LONG) + buf = lltype.malloc(ARRAY, 2, flavor='raw') + buf[0] = 30 + buf[1] = 12 + adr = rffi.cast(rffi.VOIDP, buf) + res = self.call(sum_point, [('arg_raw', adr)], rffi.LONG, init_result=0) + assert res == 42 + # check that we still have the ownership on the buffer + assert buf[0] == 30 + assert buf[1] == 12 + lltype.free(buf, flavor='raw') + lltype.free(ffi_point_struct, flavor='raw') + + def test_byval_result(self): + """ + struct Point make_point(long x, long y) { + struct Point p; + p.x = x; + p.y = y; + return p; + } + """ + libfoo = CDLL(self.libfoo_name) + ffi_point_struct = make_struct_ffitype_e(0, 0, [types.slong, types.slong]) + ffi_point = ffi_point_struct.ffistruct + + libfoo = CDLL(self.libfoo_name) + make_point = (libfoo, 'make_point', [types.slong, types.slong], ffi_point) + # + PTR = lltype.Ptr(rffi.CArray(rffi.LONG)) + p = self.call(make_point, [12, 34], PTR, init_result=lltype.nullptr(PTR.TO), + is_struct=True) + assert p[0] == 12 + assert p[1] == 34 + lltype.free(p, flavor='raw') + lltype.free(ffi_point_struct, flavor='raw') diff --git a/pypy/rlib/test/test_rrandom.py b/pypy/rlib/test/test_rrandom.py --- a/pypy/rlib/test/test_rrandom.py +++ b/pypy/rlib/test/test_rrandom.py @@ -3,6 +3,12 @@ # the numbers were created by using CPython's _randommodule.c +def test_init_from_zero(): + rnd = Random(0) + assert rnd.state[:14] == [0, 1, 1812433255, 1900727105, 1208447044, + 2481403966, 4042607538, 337614300, 3232553940, + 1018809052, 3202401494, 1775180719, 3192392114, 594215549] + def test_init_from_seed(): rnd = Random(1000) assert rnd.state[:14] == [1000, 4252021385, 1724402292, 571538732, diff --git a/pypy/rlib/test/test_streamio.py b/pypy/rlib/test/test_streamio.py --- a/pypy/rlib/test/test_streamio.py +++ b/pypy/rlib/test/test_streamio.py @@ -1008,6 +1008,75 @@ assert base.buf == data +class TestReadlineInputStream: + + packets = ["a", "b", "\n", "def", "\nxy\npq\nuv", "wx"] + lines = ["ab\n", "def\n", "xy\n", "pq\n", "uvwx"] + + def makeStream(self, seek=False, tell=False, bufsize=-1): + base = TSource(self.packets) + self.source = base + def f(*args): + if seek is False: + raise NotImplementedError # a bug! + if seek is None: + raise streamio.MyNotImplementedError # can be caught + raise ValueError(seek) # uh? + if not tell: + base.tell = f + if not seek: + base.seek = f + return streamio.ReadlineInputStream(base, bufsize) + + def test_readline(self): + for file in [self.makeStream(), self.makeStream(bufsize=2)]: + i = 0 + while 1: + r = file.readline() + if r == "": + break + assert self.lines[i] == r + i += 1 + assert i == len(self.lines) + + def test_readline_and_read_interleaved(self): + for file in [self.makeStream(seek=True), + self.makeStream(seek=True, bufsize=2)]: + i = 0 + while 1: + firstchar = file.read(1) + if firstchar == "": + break + r = file.readline() + assert r != "" + assert self.lines[i] == firstchar + r + i += 1 + assert i == len(self.lines) + + def test_readline_and_read_interleaved_no_seek(self): + for file in [self.makeStream(seek=None), + self.makeStream(seek=None, bufsize=2)]: + i = 0 + while 1: + firstchar = file.read(1) + if firstchar == "": + break + r = file.readline() + assert r != "" + assert self.lines[i] == firstchar + r + i += 1 + assert i == len(self.lines) + + def test_readline_and_readall(self): + file = self.makeStream(seek=True, tell=True, bufsize=2) + r = file.readline() + assert r == 'ab\n' + assert file.tell() == 3 + r = file.readall() + assert r == 'def\nxy\npq\nuvwx' + r = file.readall() + assert r == '' + # Speed test diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: @@ -418,6 +420,9 @@ instance._storage = ctypes_storage assert ctypes_storage # null pointer? +class NotCtypesAllocatedStructure(ValueError): + pass + class _parentable_mixin(object): """Mixin added to _parentable containers when they become ctypes-based. (This is done by changing the __class__ of the instance to reference @@ -436,7 +441,7 @@ def _addressof_storage(self): "Returns the storage address as an int" if self._storage is None or self._storage is True: - raise ValueError("Not a ctypes allocated structure") + raise NotCtypesAllocatedStructure("Not a ctypes allocated structure") return intmask(ctypes.cast(self._storage, ctypes.c_void_p).value) def _free(self): diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -831,7 +831,7 @@ raise TypeError, "unsupported cast" def _cast_whatever(TGT, value): - from pypy.rpython.lltypesystem import llmemory + from pypy.rpython.lltypesystem import llmemory, rffi ORIG = typeOf(value) if ORIG == TGT: return value @@ -847,6 +847,8 @@ return cast_pointer(TGT, value) elif ORIG == llmemory.Address: return llmemory.cast_adr_to_ptr(value, TGT) + elif TGT == rffi.VOIDP and ORIG == Unsigned: + return rffi.cast(TGT, value) elif ORIG == Signed: return cast_int_to_ptr(TGT, value) elif TGT == llmemory.Address and isinstance(ORIG, Ptr): diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -206,7 +215,7 @@ if dictobj is None: return lltype.nullptr(self.DICT) if not isinstance(dictobj, (dict, objectmodel.r_dict)): - raise TyperError("expected a dict: %r" % (dictobj,)) + raise TypeError("expected a dict: %r" % (dictobj,)) try: key = Constant(dictobj) return self.dict_cache[key] @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) @@ -833,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -845,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive @@ -139,10 +139,10 @@ source = py.code.Source(""" def call_external_function(%(argnames)s): before = aroundstate.before - after = aroundstate.after if before: before() # NB. it is essential that no exception checking occurs here! res = funcptr(%(argnames)s) + after = aroundstate.after if after: after() return res """ % locals()) @@ -244,7 +244,7 @@ def __init__(self): self.callbacks = {} -def _make_wrapper_for(TP, callable, callbackholder, aroundstate=None): +def _make_wrapper_for(TP, callable, callbackholder=None, aroundstate=None): """ Function creating wrappers for callbacks. Note that this is cheating as we assume constant callbacks and we just memoize wrappers """ @@ -253,21 +253,18 @@ if hasattr(callable, '_errorcode_'): errorcode = callable._errorcode_ else: - errorcode = TP.TO.RESULT._example() + errorcode = TP.TO.RESULT._defl() callable_name = getattr(callable, '__name__', '?') - callbackholder.callbacks[callable] = True + if callbackholder is not None: + callbackholder.callbacks[callable] = True args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))]) source = py.code.Source(r""" def wrapper(%s): # no *args - no GIL for mallocing the tuple llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py if aroundstate is not None: - before = aroundstate.before after = aroundstate.after - else: - before = None - after = None - if after: - after() + if after: + after() # from now on we hold the GIL stackcounter.stacks_counter += 1 try: @@ -281,8 +278,10 @@ traceback.print_exc() result = errorcode stackcounter.stacks_counter -= 1 - if before: - before() + if aroundstate is not None: + before = aroundstate.before + if before: + before() # here we don't hold the GIL any more. As in the wrapper() produced # by llexternal, it is essential that no exception checking occurs # after the call to before(). diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py --- a/pypy/rpython/lltypesystem/rlist.py +++ b/pypy/rpython/lltypesystem/rlist.py @@ -250,12 +250,11 @@ length = l.length l.length = length + 1 l.ll_setitem_fast(length, newitem) -ll_append_noresize.oopspec = 'list.append(l, newitem)' def ll_both_none(lst1, lst2): return not lst1 and not lst2 - + # ____________________________________________________________ # diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -57,6 +57,8 @@ llmemory.itemoffsetof(TP.chars, 0) + llmemory.sizeof(CHAR_TP) * item) + # It'd be nice to be able to look inside this function. + @dont_look_inside @enforceargs(None, None, int, int, int) def copy_string_contents(src, dst, srcstart, dststart, length): assert srcstart >= 0 @@ -142,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -157,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -256,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -278,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -323,6 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -334,12 +337,11 @@ x = 29872897 s.hash = x return x - ll_strhash._pure_function_ = True # it's pure but it does not look like it def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -349,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -367,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -384,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -425,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -448,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -468,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -484,7 +486,12 @@ return True - @purefunction + def ll_startswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[0] == ch + + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -501,7 +508,12 @@ return True - @purefunction + def ll_endswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[len(s.chars) - 1] == ch + + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -513,7 +525,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -524,7 +536,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -592,7 +604,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -715,7 +727,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -813,7 +825,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -828,7 +840,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -839,7 +851,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,19 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +633,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +651,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +694,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +785,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +878,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +918,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,13 +929,13 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded - self.remember_young_pointer_from_array(addr_array, index) + self.remember_young_pointer_from_array2(addr_array, index) else: self.remember_young_pointer(addr_array, newvalue) @@ -943,20 +951,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -976,20 +987,22 @@ def _init_writebarrier_with_card_marker(self): DEBUG = self.DEBUG - def remember_young_pointer_from_array(addr_array, index): + def remember_young_pointer_from_array2(addr_array, index): # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,26 +1015,85 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return # # We set the flag (even if the newly written address does not # actually point to the nursery, which seems to be ok -- actually - # it seems more important that remember_young_pointer_from_array() + # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET - remember_young_pointer_from_array._dont_inline_ = True - self.remember_young_pointer_from_array = ( - remember_young_pointer_from_array) + remember_young_pointer_from_array2._dont_inline_ = True + assert self.card_page_indices > 0 + self.remember_young_pointer_from_array2 = ( + remember_young_pointer_from_array2) + + # xxx trying it out for the JIT: a 3-arguments version of the above + def remember_young_pointer_from_array3(addr_array, index, newvalue): + objhdr = self.header(addr_array) + # + # a single check for the common case of neither GCFLAG_HAS_CARDS + # nor GCFLAG_NO_HEAP_PTRS + if objhdr.tid & (GCFLAG_HAS_CARDS | GCFLAG_NO_HEAP_PTRS) == 0: + # common case: fast path, jump to the end of the function + pass + elif objhdr.tid & GCFLAG_HAS_CARDS == 0: + # no cards, but GCFLAG_NO_HEAP_PTRS is set. + objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS + self.prebuilt_root_objects.append(addr_array) + # jump to the end of the function + else: + # case with cards. + # + # If the newly written address does not actually point to a + # young object, leave now. + if not self.appears_to_be_young(newvalue): + return + # + # 'addr_array' is a raw_malloc'ed array with card markers + # in front. Compute the index of the bit to set: + bitindex = index >> self.card_page_shift + byteindex = bitindex >> 3 + bitmask = 1 << (bitindex & 7) + # + # If the bit is already set, leave now. + addr_byte = self.get_card(addr_array, byteindex) + byte = ord(addr_byte.char[0]) + if byte & bitmask: + return + addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET + return + # + # Logic for the no-cards case, put here to minimize the number + # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # + if self.appears_to_be_young(newvalue): + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS + + remember_young_pointer_from_array3._dont_inline_ = True + assert self.card_page_indices > 0 + self.remember_young_pointer_from_array3 = ( + remember_young_pointer_from_array3) + + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) def assume_young_pointers(self, addr_struct): @@ -1029,15 +1101,16 @@ may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1045,15 +1118,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1061,6 +1155,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1077,20 +1187,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1123,7 +1241,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1131,7 +1249,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1147,11 +1265,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1187,19 +1305,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1238,7 +1367,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1285,11 +1426,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,78 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag + # + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert not res # there might be young ptrs, let ll_arraycopy to find them + + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -463,7 +464,7 @@ annmodel.SomeInteger()], annmodel.s_None, inline=True) - func = getattr(gcdata.gc, 'remember_young_pointer_from_array', + func = getattr(gcdata.gc, 'remember_young_pointer_from_array3', None) if func is not None: # func should not be a bound method, but a real function @@ -471,7 +472,8 @@ self.write_barrier_from_array_failing_case_ptr = \ getfn(func, [annmodel.SomeAddress(), - annmodel.SomeInteger()], + annmodel.SomeInteger(), + annmodel.SomeAddress()], annmodel.s_None) self.statistics_ptr = getfn(GCClass.statistics.im_func, [s_gc, annmodel.SomeInteger()], @@ -860,9 +862,9 @@ def gct_get_write_barrier_from_array_failing_case(self, hop): op = hop.spaceop - hop.genop("same_as", - [self.write_barrier_from_array_failing_case_ptr], - resultvar=op.result) + v = getattr(self, 'write_barrier_from_array_failing_case_ptr', + lltype.nullptr(op.result.concretetype.TO)) + hop.genop("same_as", [v], resultvar=op.result) def gct_zero_gc_pointers_inside(self, hop): if not self.malloc_zero_filled: @@ -883,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/module/test/test_posix.py b/pypy/rpython/module/test/test_posix.py --- a/pypy/rpython/module/test/test_posix.py +++ b/pypy/rpython/module/test/test_posix.py @@ -43,6 +43,17 @@ for i in range(len(stat)): assert long(getattr(func, 'item%d' % i)) == stat[i] + def test_stat_exception(self): + def fo(): + try: + posix.stat('I/do/not/exist') + except OSError: + return True + else: + return False + res = self.interpret(fo,[]) + assert res + def test_times(self): import py; py.test.skip("llinterp does not like tuple returns") from pypy.rpython.test.test_llinterp import interpret @@ -205,5 +216,8 @@ def test_stat(self): py.test.skip("ootypesystem does not support os.stat") + def test_stat_exception(self): + py.test.skip("ootypesystem does not support os.stat") + def test_chown(self): py.test.skip("ootypesystem does not support os.chown") diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -433,7 +433,9 @@ "ll_streq": Meth([self.SELFTYPE_T], Bool), "ll_strcmp": Meth([self.SELFTYPE_T], Signed), "ll_startswith": Meth([self.SELFTYPE_T], Bool), + "ll_startswith_char": Meth([self.CHAR], Bool), "ll_endswith": Meth([self.SELFTYPE_T], Bool), + "ll_endswith_char": Meth([self.CHAR], Bool), "ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed), @@ -1429,10 +1431,18 @@ # NOT_RPYTHON return self._str.startswith(s._str) + def ll_startswith_char(self, s): + # NOT_RPYTHON + return self._str.startswith(s) + def ll_endswith(self, s): # NOT_RPYTHON return self._str.endswith(s._str) + def ll_endswith_char(self, s): + # NOT_RPYTHON + return self._str.endswith(s) + def ll_find(self, s, start, end): # NOT_RPYTHON if start > len(self._str): # workaround to cope with corner case diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/ootypesystem/test/test_oopbc.py b/pypy/rpython/ootypesystem/test/test_oopbc.py --- a/pypy/rpython/ootypesystem/test/test_oopbc.py +++ b/pypy/rpython/ootypesystem/test/test_oopbc.py @@ -81,3 +81,18 @@ res = interpret(f, [1], type_system='ootype') assert res == 2 +def test_quasi_immutable(): + class A(object): + _immutable_fields_ = ['x?'] + def __init__(self): + self.x = 3 + def foo(self): + return self.x + + a = A() + + def f(): + return a.foo() + + res = interpret(f, [], type_system='ootype') + assert res == 3 diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -667,7 +667,6 @@ res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res -ll_pop.oopspec = 'list.pop(l, index)' def ll_reverse(l): length = l.ll_length() diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py --- a/pypy/rpython/rstr.py +++ b/pypy/rpython/rstr.py @@ -81,16 +81,30 @@ return super(AbstractStringRepr, self).rtype_is_true(hop) def rtype_method_startswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_startswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_startswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_endswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_endswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_endswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_find(self, hop, reverse=False): # XXX binaryop diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,29 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): @@ -860,6 +883,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -227,6 +227,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_startswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].startswith('o') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_endswith(self): const = self.const def fn(i, j): @@ -238,6 +247,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_endswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].endswith('e') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_find(self): const = self.const def fn(i, j): diff --git a/pypy/tool/gcc_cache.py b/pypy/tool/gcc_cache.py --- a/pypy/tool/gcc_cache.py +++ b/pypy/tool/gcc_cache.py @@ -39,7 +39,16 @@ data = '' if not (data.startswith('True') or data.startswith('FAIL\n')): try: - platform.compile(c_files, eci) + _previous = platform.log_errors + try: + platform.log_errors = False + platform.compile(c_files, eci) + finally: + del platform.log_errors + # ^^^remove from the instance --- needed so that it can + # compare equal to another instance without it + if platform.log_errors != _previous: + platform.log_errors = _previous data = 'True' path.write(data) except CompilationError, e: diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,9 +1,13 @@ import re, sys -from pypy.jit.metainterp.resoperation import rop, opname + +from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser +from pypy.tool.logparser import parse_log_file, extract_category class Op(object): bridge = None + offset = None + asm = None def __init__(self, name, args, res, descr): self.name = name @@ -51,17 +55,61 @@ # factory method Op = Op + use_mock_model = True + + def postprocess(self, loop, backend_dump=None, backend_tp=None, + dump_start=0): + if backend_dump is not None: + raw_asm = self._asm_disassemble(backend_dump.decode('hex'), + backend_tp, dump_start) + asm = [] + start = 0 + for elem in raw_asm: + if len(elem.split("\t")) != 3: + continue + adr, _, v = elem.split("\t") + if not start: + start = int(adr.strip(":"), 16) + ofs = int(adr.strip(":"), 16) - start + if ofs >= 0: + asm.append((ofs, v.strip("\n"))) + asm_index = 0 + for i, op in enumerate(loop.operations): + end = 0 + j = i + 1 + while end == 0: + if j == len(loop.operations): + end = loop.last_offset + break + if loop.operations[j].offset is None: + j += 1 + else: + end = loop.operations[j].offset + if op.offset is not None: + while asm[asm_index][0] < op.offset: + asm_index += 1 + end_index = asm_index + while asm[end_index][0] < end: + end_index += 1 + op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) + return loop + + def _asm_disassemble(self, d, origin_addr, tp): + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + return list(machine_code_dump(d, tp, origin_addr)) @classmethod - def parse_from_input(cls, input): - return cls(input, None, {}, 'lltype', None, - nonstrict=True).parse() + def parse_from_input(cls, input, **kwds): + parser = cls(input, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + return parser.postprocess(loop, **kwds) def parse_args(self, opname, argspec): if not argspec.strip(): return [], None if opname == 'debug_merge_point': - return argspec.rsplit(", ", 1), None + return argspec.split(", ", 1), None else: args = argspec.split(', ') descr = None @@ -95,12 +143,12 @@ def __init__(self, operations, storage): if operations[0].name == 'debug_merge_point': - self.inline_level = int(operations[0].args[1]) - m = re.search('\w]+), file \'(.+?)\', line (\d+)> #(\d+) (\w+)', - operations[0].getarg(0)) + self.inline_level = int(operations[0].args[0]) + m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', + operations[0].getarg(1)) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[0].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1].split(" ")[0][1:] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) @@ -119,6 +167,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -218,6 +269,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint @@ -273,3 +330,33 @@ res.append(op) i += 1 return res + + +def import_log(logname, ParserCls=SimpleParser): + log = parse_log_file(logname) + addrs = {} + for entry in extract_category(log, 'jit-backend-addr'): + m = re.search('bootstrap ([\da-f]+)', entry) + name = entry[:entry.find('(') - 1] + addrs[int(m.group(1), 16)] = name + dumps = {} + for entry in extract_category(log, 'jit-backend-dump'): + backend, _, dump, _ = entry.split("\n") + _, addr, _, data = re.split(" +", dump) + backend_name = backend.split(" ")[1] + addr = int(addr[1:], 16) + if addr in addrs: + dumps[addrs[addr]] = (backend_name, addr, data) + loops = [] + for entry in extract_category(log, 'jit-log-opt'): + parser = ParserCls(entry, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + comm = loop.comment + name = comm[2:comm.find(':')-1] + if name in dumps: + bname, start_ofs, dump = dumps[name] + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) + loops.append(loop) + return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -0,0 +1,38 @@ +[11f210b47027] {jit-backend +[11f210b900f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 +[11f210b949b3] jit-backend-dump} +[11f210b949b4] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab188] jit-backend-addr} +[11f210bab189] jit-backend} +[11f210bacbb7] {jit-log-opt-loop +# Loop 0 : loop with 19 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 INPLACE_ADD') ++179: i8 = int_add(i4, 1) +debug_merge_point(0, ' #28 STORE_FAST') +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++183: i10 = getfield_raw(40564608, descr=) ++191: i12 = int_sub(i10, 1) ++195: setfield_raw(40564608, i12, descr=) ++203: i14 = int_lt(i12, 0) +guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++213: jump(p0, p1, p2, p3, i8, descr=) ++218: --end of the loop-- +[11f210c17981] jit-log-opt-loop} +[11f210fb1d21] {jit-backend-counts +0:8965 +1:2 +[11f210fb381b] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,12 +1,11 @@ -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, Const -from pypy.tool.jitlogparser.parser import SimpleParser, TraceForOpcode, Function,\ - adjust_bridges +from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, + Function, adjust_bridges, + import_log) from pypy.tool.jitlogparser.storage import LoopStorage -import py +import py, sys -def parse(input): - return SimpleParser.parse_from_input(input) +def parse(input, **kwds): + return SimpleParser.parse_from_input(input, **kwds) def test_parse(): @@ -29,7 +28,7 @@ def test_parse_non_code(): ops = parse(''' [] - debug_merge_point("SomeRandomStuff", 0) + debug_merge_point(0, "SomeRandomStuff") ''') res = Function.from_operations(ops.operations, LoopStorage()) assert len(res.chunks) == 1 @@ -38,10 +37,10 @@ def test_split(): ops = parse(''' [i0] - debug_merge_point(" #10 ADD", 0) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -54,12 +53,12 @@ def test_inlined_call(): ops = parse(""" [] - debug_merge_point(' #28 CALL_FUNCTION', 0) + debug_merge_point(0, ' #28 CALL_FUNCTION') i18 = getfield_gc(p0, descr=) - debug_merge_point(' #0 LOAD_FAST', 1) - debug_merge_point(' #3 LOAD_CONST', 1) - debug_merge_point(' #7 RETURN_VALUE', 1) - debug_merge_point(' #31 STORE_FAST', 0) + debug_merge_point(1, ' #0 LOAD_FAST') + debug_merge_point(1, ' #3 LOAD_CONST') + debug_merge_point(1, ' #7 RETURN_VALUE') + debug_merge_point(0, ' #31 STORE_FAST') """) res = Function.from_operations(ops.operations, LoopStorage()) assert len(res.chunks) == 3 # two chunks + inlined call @@ -72,10 +71,10 @@ def test_name(): ops = parse(''' [i0] - debug_merge_point(" #10 ADD", 0) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -89,10 +88,10 @@ ops = parse(''' [i0] i3 = int_add(i0, 1) - debug_merge_point(" #10 ADD", 0) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -102,33 +101,37 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(" #0 LOAD_FAST", 0) - debug_merge_point(" #3 LOAD_FAST", 0) - debug_merge_point(" #6 BINARY_ADD", 0) - debug_merge_point(" #7 RETURN_VALUE", 0) + debug_merge_point(0, " #0 LOAD_FAST") + debug_merge_point(0, " #3 LOAD_FAST") + debug_merge_point(0, " #6 BINARY_ADD") + debug_merge_point(0, " #7 RETURN_VALUE") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.chunks[1].lineno == 3 def test_linerange(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(" #9 LOAD_FAST", 0) - debug_merge_point(" #12 LOAD_CONST", 0) - debug_merge_point(" #22 LOAD_CONST", 0) - debug_merge_point(" #28 LOAD_CONST", 0) - debug_merge_point(" #6 SETUP_LOOP", 0) + debug_merge_point(0, " #9 LOAD_FAST") + debug_merge_point(0, " #12 LOAD_CONST") + debug_merge_point(0, " #22 LOAD_CONST") + debug_merge_point(0, " #28 LOAD_CONST") + debug_merge_point(0, " #6 SETUP_LOOP") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.linerange == (7, 9) assert res.lineset == set([7, 8, 9]) def test_linerange_notstarts(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] - debug_merge_point(' #17 FOR_ITER', 0) + debug_merge_point(0, ' #17 FOR_ITER') guard_class(p6, 144264192, descr=) p12 = getfield_gc(p6, descr=) """ % locals()) @@ -168,14 +171,46 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' def test_parsing_strliteral(): loop = parse(""" - debug_merge_point('StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]', 0) + debug_merge_point(0, 'StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]') """) ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] assert chunk.bytecode_name == 'StrLiteralSearch' + +def test_parsing_assembler(): + backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" + dump_start = 0x7f3b0b2e63d5 + loop = parse(""" + # Loop 0 : loop with 19 ops + [p0, p1, p2, p3, i4] + debug_merge_point(0, ' #15 COMPARE_OP') + +166: i6 = int_lt(i4, 10000) + guard_true(i6, descr=) [p1, p0, p2, p3, i4] + debug_merge_point(0, ' #27 INPLACE_ADD') + +179: i8 = int_add(i4, 1) + debug_merge_point(0, ' #31 JUMP_ABSOLUTE') + +183: i10 = getfield_raw(40564608, descr=) + +191: i12 = int_sub(i10, 1) + +195: setfield_raw(40564608, i12, descr=) + +203: i14 = int_lt(i12, 0) + guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] + debug_merge_point(0, ' #9 LOAD_FAST') + +213: jump(p0, p1, p2, p3, i8, descr=) + +218: --end of the loop--""", backend_dump=backend_dump, + dump_start=dump_start, + backend_tp='x86_64') + cmp = loop.operations[1] + assert 'jge' in cmp.asm + assert '0x2710' in cmp.asm + assert 'jmp' in loop.operations[-1].asm + +def test_import_log(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest.log'))) + assert 'jge' in loops[0].operations[3].asm diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -1,8 +1,13 @@ import autopath import py -from pypy.interpreter import gateway +from pypy.interpreter import gateway, pycode from pypy.interpreter.error import OperationError +try: + from _pytest.assertion.newinterpret import interpret +except ImportError: + from _pytest.assertion.oldinterpret import interpret + # ____________________________________________________________ class AppCode(object): @@ -51,13 +56,11 @@ space = self.space for key, w_value in vars.items(): space.setitem(self.w_locals, space.wrap(key), w_value) - return space.eval(code, self.w_globals, self.w_locals) - - def exec_(self, code, **vars): - space = self.space - for key, w_value in vars.items(): - space.setitem(self.w_locals, space.wrap(key), w_value) - space.exec_(code, self.w_globals, self.w_locals) + if isinstance(code, str): + return space.eval(code, self.w_globals, self.w_locals) + pyc = pycode.PyCode._from_code(space, code) + return pyc.exec_host_bytecode(self.w_globals, self.w_locals) + exec_ = eval def repr(self, w_value): return self.space.unwrap(self.space.repr(w_value)) @@ -80,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: @@ -163,8 +166,8 @@ except py.error.ENOENT: source = None from pypy import conftest - if source and not py.test.config.option.nomagic: - msg = py.code._reinterpret_old(source, runner, should_fail=True) + if source and py.test.config._assertstate.mode != "off": + msg = interpret(source, runner, should_fail=True) space.setattr(w_self, space.wrap('args'), space.newtuple([space.wrap(msg)])) w_msg = space.wrap(msg) diff --git a/pypy/tool/pytest/test/test_pytestsupport.py b/pypy/tool/pytest/test/test_pytestsupport.py --- a/pypy/tool/pytest/test/test_pytestsupport.py +++ b/pypy/tool/pytest/test/test_pytestsupport.py @@ -4,7 +4,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.pyframe import PyFrame from pypy.tool.pytest.appsupport import (AppFrame, build_pytest_assertion, - AppExceptionInfo) + AppExceptionInfo, interpret) import py from pypy.tool.udir import udir import os @@ -22,8 +22,8 @@ co = PyCode._from_code(space, somefunc.func_code) pyframe = PyFrame(space, co, space.newdict(), None) runner = AppFrame(space, pyframe) - py.code._reinterpret_old("f = lambda x: x+1", runner, should_fail=False) - msg = py.code._reinterpret_old("assert isinstance(f(2), float)", runner) + interpret("f = lambda x: x+1", runner, should_fail=False) + msg = interpret("assert isinstance(f(2), float)", runner) assert msg.startswith("assert isinstance(3, float)\n" " + where 3 = ") @@ -58,6 +58,12 @@ except AssertionError, e: assert e.msg == "Failed" +def app_test_comparison(): + try: + assert 3 > 4 + except AssertionError, e: + assert "3 > 4" in e.msg + def test_appexecinfo(space): try: diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -3,9 +3,9 @@ It uses 'pypy/translator/goal/pypy-c' and parts of the rest of the working copy. Usage: - package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] + package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] [destination-for-tarball] [pypy-c-path] -Usually you would do: package.py ../../.. pypy-VER-PLATFORM. +Usually you would do: package.py ../../.. pypy-VER-PLATFORM The output is found in the directory /tmp/usession-YOURNAME/build/. """ @@ -122,7 +122,10 @@ zf.close() else: archive = str(builddir.join(name + '.tar.bz2')) - e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) + if sys.platform == 'darwin': + e = os.system('tar --numeric-owner -cvjf ' + archive + " " + name) + else: + e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) if e: raise OSError('"tar" returned exit status %r' % e) finally: diff --git a/pypy/tool/test/test_gcc_cache.py b/pypy/tool/test/test_gcc_cache.py --- a/pypy/tool/test/test_gcc_cache.py +++ b/pypy/tool/test/test_gcc_cache.py @@ -1,11 +1,13 @@ - +import sys from pypy.tool.gcc_cache import * from pypy.tool.udir import udir -import md5 +import md5, cStringIO from pypy.translator.tool.cbuild import ExternalCompilationInfo +localudir = udir.join('test_gcc_cache').ensure(dir=1) + def test_gcc_exec(): - f = udir.join("x.c") + f = localudir.join("x.c") f.write(""" #include #include @@ -15,8 +17,8 @@ return 0; } """) - dir1 = udir.join('test_gcc_exec_dir1').ensure(dir=1) - dir2 = udir.join('test_gcc_exec_dir2').ensure(dir=1) + dir1 = localudir.join('test_gcc_exec_dir1').ensure(dir=1) + dir2 = localudir.join('test_gcc_exec_dir2').ensure(dir=1) dir1.join('test_gcc_exec.h').write('#define ANSWER 3\n') dir2.join('test_gcc_exec.h').write('#define ANSWER 42\n') eci = ExternalCompilationInfo(include_dirs=[str(dir1)]) @@ -36,7 +38,7 @@ print '>>>' def test_gcc_ask(): - f = udir.join("y.c") + f = localudir.join("y.c") f.write(""" #include #include @@ -46,8 +48,8 @@ return 0; } """) - dir1 = udir.join('test_gcc_ask_dir1').ensure(dir=1) - dir2 = udir.join('test_gcc_ask_dir2').ensure(dir=1) + dir1 = localudir.join('test_gcc_ask_dir1').ensure(dir=1) + dir2 = localudir.join('test_gcc_ask_dir2').ensure(dir=1) dir1.join('test_gcc_ask.h').write('/* hello world */\n') dir2.join('test_gcc_ask.h').write('#error boom\n') eci = ExternalCompilationInfo(include_dirs=[str(dir1)]) @@ -63,3 +65,15 @@ print '<<<' print err print '>>>' + +def test_gcc_ask_doesnt_log_errors(): + f = localudir.join('z.c') + f.write("""this file is not valid C code\n""") + eci = ExternalCompilationInfo() + oldstderr = sys.stderr + try: + sys.stderr = capture = cStringIO.StringIO() + py.test.raises(CompilationError, try_compile_cache, [f], eci) + finally: + sys.stderr = oldstderr + assert 'ERROR' not in capture.getvalue().upper() diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -297,6 +297,13 @@ gc_startup_code = RefcountingGcPolicy.gc_startup_code.im_func + def compilation_info(self): + eci = BasicGcPolicy.compilation_info(self) + eci = eci.merge(ExternalCompilationInfo( + post_include_bits=['#define USING_NO_GC_AT_ALL'], + )) + return eci + class FrameworkGcPolicy(BasicGcPolicy): transformerclass = framework.FrameworkGCTransformer diff --git a/pypy/translator/c/gcc/instruction.py b/pypy/translator/c/gcc/instruction.py --- a/pypy/translator/c/gcc/instruction.py +++ b/pypy/translator/c/gcc/instruction.py @@ -187,8 +187,8 @@ def requestgcroots(self, tracker): # no need to track the value of these registers in the caller - # function if we are the main(), or if we are flagged as a - # "bottom" function (a callback from C code) + # function if we are flagged as a "bottom" function (a callback + # from C code, or pypy_main_function()) if tracker.is_stack_bottom: return {} else: diff --git a/pypy/translator/c/gcc/test/elf/track10.s b/pypy/translator/c/gcc/test/elf/track10.s --- a/pypy/translator/c/gcc/test/elf/track10.s +++ b/pypy/translator/c/gcc/test/elf/track10.s @@ -1,5 +1,5 @@ - .type main, @function -main: + .type main1, @function +main1: pushl %ebx call pypy_f ;; expected {4(%esp) | (%esp), %esi, %edi, %ebp | %ebx} @@ -11,4 +11,4 @@ /* GCROOT %ebx */ popl %ebx ret - .size main, .-main + .size main1, .-main1 diff --git a/pypy/translator/c/gcc/test/elf/track12.s b/pypy/translator/c/gcc/test/elf/track12.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf/track12.s @@ -0,0 +1,9 @@ + .type pypy_f, @function +pypy_f: + pushl 4(%esp) + call pypy_other + ;; expected {4(%esp) | %ebx, %esi, %edi, %ebp | (%esp)} + popl %eax + /* GCROOT %eax */ + ret + .size pypy_f, .-pypy_f diff --git a/pypy/translator/c/gcc/test/elf/track13.s b/pypy/translator/c/gcc/test/elf/track13.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf/track13.s @@ -0,0 +1,9 @@ + .type pypy_f, @function +pypy_f: + call pypy_other + ;; expected {(%esp) | %ebx, %esi, %edi, %ebp | 8(%esp)} + pushl 8(%esp) + popl %eax + /* GCROOT %eax */ + ret + .size pypy_f, .-pypy_f diff --git a/pypy/translator/c/gcc/test/elf/track4.s b/pypy/translator/c/gcc/test/elf/track4.s deleted file mode 100644 --- a/pypy/translator/c/gcc/test/elf/track4.s +++ /dev/null @@ -1,52 +0,0 @@ - .type main, @function -main: - ;; this is an artificial example showing what kind of code gcc - ;; can produce for main() - pushl %ebp - movl %eax, $globalptr1 - movl %esp, %ebp - pushl %edi - subl $8, %esp - andl $-16, %esp - movl %ebx, -8(%ebp) - movl 8(%ebp), %edi - call foobar - ;; expected {4(%ebp) | -8(%ebp), %esi, -4(%ebp), (%ebp) | %edi} -.L1: - cmpl $0, %eax - je .L3 -.L2: - ;; inlined function here with -fomit-frame-pointer - movl %eax, -12(%ebp) - movl %edi, %edx - subl $16, %esp - movl %eax, (%esp) - movl $42, %edi - movl %edx, 4(%esp) - movl %esi, %ebx - movl $nonsense, %esi - call foobar - ;; expected {4(%ebp) | -8(%ebp), %ebx, -4(%ebp), (%ebp) | 4(%esp), -12(%ebp)} - addl %edi, %eax - movl 4(%esp), %eax - movl %ebx, %esi - addl $16, %esp - movl %eax, %edi - movl -12(%ebp), %eax -#APP - /* GCROOT %eax */ -#NO_APP - ;; end of inlined function -.L3: - call foobar - ;; expected {4(%ebp) | -8(%ebp), %esi, -4(%ebp), (%ebp) | %edi} -#APP - /* GCROOT %edi */ -#NO_APP - movl -8(%ebp), %ebx - movl -4(%ebp), %edi - movl %ebp, %esp - popl %ebp - ret - - .size main, .-main diff --git a/pypy/translator/c/gcc/test/elf/track6.s b/pypy/translator/c/gcc/test/elf/track6.s deleted file mode 100644 --- a/pypy/translator/c/gcc/test/elf/track6.s +++ /dev/null @@ -1,26 +0,0 @@ - .type main, @function -main: - ;; a minimal example showing what kind of code gcc - ;; can produce for main(): some local variable accesses - ;; are relative to %ebp, while others are relative to - ;; %esp, and the difference %ebp-%esp is not constant - ;; because of the 'andl' to align the stack - pushl %ebp - movl %esp, %ebp - subl $8, %esp - andl $-16, %esp - movl $globalptr1, -4(%ebp) - movl $globalptr2, (%esp) - pushl $0 - call foobar - ;; expected {4(%ebp) | %ebx, %esi, %edi, (%ebp) | 4(%esp), -4(%ebp)} - popl %eax -#APP - /* GCROOT -4(%ebp) */ - /* GCROOT (%esp) */ -#NO_APP - movl %ebp, %esp - popl %ebp - ret - - .size main, .-main diff --git a/pypy/translator/c/gcc/test/elf/track7.s b/pypy/translator/c/gcc/test/elf/track7.s --- a/pypy/translator/c/gcc/test/elf/track7.s +++ b/pypy/translator/c/gcc/test/elf/track7.s @@ -1,5 +1,5 @@ - .type main, @function -main: + .type main1, @function +main1: ;; cmovCOND tests. pushl %ebx movl 12(%esp), %ebx @@ -16,4 +16,4 @@ popl %ebx ret - .size main, .-main + .size main1, .-main1 diff --git a/pypy/translator/c/gcc/test/msvc/track6.s b/pypy/translator/c/gcc/test/msvc/track6.s deleted file mode 100644 --- a/pypy/translator/c/gcc/test/msvc/track6.s +++ /dev/null @@ -1,15 +0,0 @@ -_TEXT SEGMENT -_pypy_g_foo PROC ; COMDAT - - push ebp - mov ebp, esp - and esp, -64 - sub esp, 12 - push esi - call _pypy_g_something_else - ;; expected {4(%ebp) | %ebx, (%esp), %edi, (%ebp) | } - pop esi - mov esp, ebp - pop ebp - ret 0 -_pypy_g_foo ENDP diff --git a/pypy/translator/c/gcc/test/msvc/track_and_esp.s b/pypy/translator/c/gcc/test/msvc/track_and_esp.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/msvc/track_and_esp.s @@ -0,0 +1,474 @@ +PUBLIC ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ ; `string' +PUBLIC _pypy_g_ll_math_ll_math_frexp +; COMDAT ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ +CONST SEGMENT +??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ DB 'pypy_g_ll_math_l' + DB 'l_math_frexp', 00H ; `string' +; Function compile flags: /Ogtpy +CONST ENDS +; COMDAT _pypy_g_ll_math_ll_math_frexp +_TEXT SEGMENT +_l_mantissa_0$ = -8 ; size = 8 +_l_v21638$ = -8 ; size = 8 +_l_x_14$ = 8 ; size = 8 +_pypy_g_ll_math_ll_math_frexp PROC ; COMDAT + +; 58245: struct pypy_tuple2_0 *pypy_g_ll_math_ll_math_frexp(double l_x_14) { + + push ebp + mov ebp, esp + and esp, -64 ; ffffffc0H + +; 58246: long *l_exp_p_0; double l_mantissa_0; bool_t l_v21641; +; 58247: bool_t l_v21643; bool_t l_v21644; bool_t l_v21646; bool_t l_v21647; +; 58248: bool_t l_v21652; bool_t l_v21653; bool_t l_v21660; bool_t l_v21666; +; 58249: bool_t l_v21670; bool_t l_v21674; bool_t l_v21676; double l_v21638; +; 58250: long l_v21637; long l_v21649; long l_v21651; long l_v21677; +; 58251: long l_v21678; struct pypy_exceptions_Exception0 *l_v21687; +; 58252: struct pypy_header0 *l_v21654; struct pypy_object0 *l_v21682; +; 58253: struct pypy_object0 *l_v21691; struct pypy_object_vtable0 *l_v21665; +; 58254: struct pypy_object_vtable0 *l_v21669; +; 58255: struct pypy_object_vtable0 *l_v21675; +; 58256: struct pypy_object_vtable0 *l_v21683; struct pypy_tuple2_0 *l_v21640; +; 58257: struct pypy_tuple2_0 *l_v21695; void* l_v21639; void* l_v21648; +; 58258: void* l_v21650; void* l_v21656; void* l_v21658; void* l_v21659; +; 58259: void* l_v21668; void* l_v21672; void* l_v21679; void* l_v21688; +; 58260: void* l_v21696; +; 58261: goto block0; +; 58262: +; 58263: block0: +; 58264: l_v21641 = pypy_g_ll_math_ll_math_isnan(l_x_14); + + fld QWORD PTR _l_x_14$[ebp] + sub esp, 52 ; 00000034H + push ebx + push esi + push edi + sub esp, 8 + fstp QWORD PTR [esp] +$block0$88239: + call _pypy_g_ll_math_ll_math_isnan + +; 58265: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isnan); +; 58266: l_v21643 = l_v21641; +; 58267: if (l_v21643) { +; 58268: l_v21637 = 0L; +; 58269: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] + add esp, 8 + test al, al + +; 58270: goto block3; + + jne SHORT $LN10 at pypy_g_ll_@159 + +; 58271: } +; 58272: goto block1; +; 58273: +; 58274: block1: +; 58275: l_v21644 = pypy_g_ll_math_ll_math_isinf(l_x_14); + + sub esp, 8 + fstp QWORD PTR [esp] +$block1$88243: + call _pypy_g_ll_math_ll_math_isinf + add esp, 8 + +; 58276: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isinf); +; 58277: l_v21646 = l_v21644; +; 58278: if (l_v21646) { + + test al, al + je SHORT $block2$88245 + +; 58279: l_v21637 = 0L; +; 58280: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] +$LN10 at pypy_g_ll_@159: + +; 58288: goto block14; +; 58289: } +; 58290: l_v21637 = 0L; + + xor edi, edi +$LN30 at pypy_g_ll_@159: + +; 58291: l_v21638 = l_x_14; +; 58292: goto block3; +; 58293: +; 58294: block3: +; 58295: l_v21648 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free; + + mov esi, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4 + fstp QWORD PTR _l_v21638$[esp+64] + +; 58296: OP_RAW_MALLOC_USAGE((0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21649); +; 58297: l_v21650 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_top_of_space; +; 58298: OP_ADR_DELTA(l_v21650, l_v21648, l_v21651); + + mov eax, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+12 + sub eax, esi + +; 58299: OP_INT_GT(l_v21649, l_v21651, l_v21652); + + cmp eax, 24 ; 00000018H +$block3$88242: + +; 58300: if (l_v21652) { + + jge $block4$88260 + +; 58334: l_v21695 = l_v21640; +; 58335: goto block8; +; 58336: +; 58337: block8: +; 58338: RPY_DEBUG_RETURN(); +; 58339: return l_v21695; +; 58340: +; 58341: block9: +; 58342: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58343: l_v21695 = ((struct pypy_tuple2_0 *) NULL); +; 58344: goto block8; +; 58345: +; 58346: block10: +; 58347: abort(); /* debug_llinterpcall should be unreachable */ +; 58348: l_v21665 = (&pypy_g_ExcData)->ed_exc_type; +; 58349: l_v21666 = (l_v21665 == NULL); +; 58350: if (!l_v21666) { +; 58351: goto block11; +; 58352: } +; 58353: goto block5; +; 58354: +; 58355: block11: +; 58356: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58357: l_v21696 = NULL; +; 58358: goto block6; +; 58359: +; 58360: block12: +; 58361: l_v21668 = pypy_g_SemiSpaceGC_obtain_free_space((&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC), (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0)))); + + push 24 ; 00000018H + push OFFSET _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC +$block12$88259: + call _pypy_g_SemiSpaceGC_obtain_free_space + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58362: l_v21669 = (&pypy_g_ExcData)->ed_exc_type; +; 58363: l_v21670 = (l_v21669 == NULL); + + xor ecx, ecx + add esp, 8 + cmp DWORD PTR _pypy_g_ExcData, ecx + +; 58364: if (!l_v21670) { + + je $LN5 at pypy_g_ll_@159 + +; 58368: goto block4; +; 58369: +; 58370: block13: +; 58371: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?N@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?8??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block13$88313: +$block9$88285: + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block2$88245: + +; 58281: goto block3; +; 58282: } +; 58283: goto block2; +; 58284: +; 58285: block2: +; 58286: OP_FLOAT_IS_TRUE(l_x_14, l_v21647); + + fldz + fld QWORD PTR _l_x_14$[ebp] + fucom ST(1) + fnstsw ax + fstp ST(1) + test ah, 68 ; 00000044H + +; 58287: if (l_v21647) { + + jnp $LN10 at pypy_g_ll_@159 + +; 58372: l_v21696 = NULL; +; 58373: goto block6; +; 58374: +; 58375: block14: +; 58376: l_v21672 = pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign(1L, (0 + 0), sizeof(long)); + + push 4 + fstp ST(0) + push 0 + push 1 +$block14$88247: + call _pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } + mov esi, eax + +; 58377: OP_TRACK_ALLOC_START(l_v21672, /* nothing */); + + push OFFSET ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ + push esi + call _pypy_debug_alloc_start + ;; expected {4(%ebp) | 28(%esp), 24(%esp), 20(%esp), (%ebp) | } + add esp, 20 ; 00000014H + +; 58378: l_exp_p_0 = (long *)l_v21672; +; 58379: l_v21674 = (l_exp_p_0 != NULL); + + test esi, esi + +; 58380: if (!l_v21674) { + + jne SHORT $block15$88324 + +; 58418: goto block8; +; 58419: +; 58420: block18: +; 58421: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BB@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], esi + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block18$88323: + +; 58422: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block15$88324: + +; 58381: goto block18; +; 58382: } +; 58383: goto block15; +; 58384: +; 58385: block15: +; 58386: l_mantissa_0 = pypy_g_frexp__Float_arrayPtr_star_2(l_x_14, l_exp_p_0); + + fld QWORD PTR _l_x_14$[ebp] + push esi + sub esp, 8 + fstp QWORD PTR [esp] + call _pypy_g_frexp__Float_arrayPtr_star_2 + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } + +; 58387: l_v21675 = (&pypy_g_ExcData)->ed_exc_type; +; 58388: l_v21676 = (l_v21675 == NULL); + + mov edi, DWORD PTR _pypy_g_ExcData + fstp QWORD PTR _l_mantissa_0$[esp+76] + add esp, 12 ; 0000000cH + test edi, edi + +; 58389: if (!l_v21676) { + + je SHORT $block16$88328 + +; 58403: +; 58404: block17: +; 58405: l_v21682 = (&pypy_g_ExcData)->ed_exc_value; +; 58406: l_v21683 = (&pypy_g_ExcData)->ed_exc_type; +; 58407: PYPY_DEBUG_CATCH_EXCEPTION("ll_math_ll_math_frexp", l_v21683, l_v21683 == (&pypy_g_py__code_assertion_AssertionError_vtable.ae_super.ae_super.se_super.e_super) || l_v21683 == (&pypy_g_exceptions_NotImplementedError_vtable.nie_super.re_super.se_super.e_super)); + + mov eax, DWORD PTR _pypydtcount + mov ebx, DWORD PTR _pypy_g_ExcData+4 + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BA@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], edi + inc eax + and eax, 8191 ; 00001fffH +$block17$88327: + mov DWORD PTR _pypydtcount, eax + cmp edi, OFFSET _pypy_g_py__code_assertion_AssertionError_vtable + je SHORT $LN1 at pypy_g_ll_@159 + cmp edi, OFFSET _pypy_g_exceptions_NotImplementedError_vtable + jne SHORT $LN2 at pypy_g_ll_@159 +$LN1 at pypy_g_ll_@159: + call _pypy_debug_catch_fatal_exception +$LN2 at pypy_g_ll_@159: + +; 58408: (&pypy_g_ExcData)->ed_exc_value = ((struct pypy_object0 *) NULL); + + xor eax, eax + +; 58409: (&pypy_g_ExcData)->ed_exc_type = ((struct pypy_object_vtable0 *) NULL); +; 58410: l_v21687 = (struct pypy_exceptions_Exception0 *)l_v21682; +; 58411: l_v21688 = (void*)l_exp_p_0; +; 58412: OP_TRACK_ALLOC_STOP(l_v21688, /* nothing */); + + push esi + mov DWORD PTR _pypy_g_ExcData+4, eax + mov DWORD PTR _pypy_g_ExcData, eax + call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } + +; 58413: OP_RAW_FREE(l_v21688, /* nothing */); + + push esi + call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58414: l_v21691 = (struct pypy_object0 *)l_v21687; +; 58415: pypy_g_RPyReRaiseException(l_v21683, l_v21691); + + push ebx + push edi + call _pypy_g_RPyReRaiseException + add esp, 16 ; 00000010H + +; 58416: pypy_asm_gc_nocollect(pypy_g_RPyReRaiseException); +; 58417: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block16$88328: + +; 58390: goto block17; +; 58391: } +; 58392: goto block16; +; 58393: +; 58394: block16: +; 58395: l_v21677 = RPyBareItem(l_exp_p_0, 0L); +; 58396: l_v21678 = (long)(l_v21677); + + mov edi, DWORD PTR [esi] + +; 58397: l_v21679 = (void*)l_exp_p_0; +; 58398: OP_TRACK_ALLOC_STOP(l_v21679, /* nothing */); + + push esi + call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } + +; 58399: OP_RAW_FREE(l_v21679, /* nothing */); + + push esi + call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58400: l_v21637 = l_v21678; +; 58401: l_v21638 = l_mantissa_0; + + fld QWORD PTR _l_mantissa_0$[esp+72] + add esp, 8 + +; 58402: goto block3; + + jmp $LN30 at pypy_g_ll_@159 +$LN5 at pypy_g_ll_@159: + +; 58365: goto block13; +; 58366: } +; 58367: l_v21639 = l_v21668; + + mov esi, eax +$block4$88260: +$block5$88263: + +; 58301: goto block12; +; 58302: } +; 58303: l_v21639 = l_v21648; +; 58304: goto block4; +; 58305: +; 58306: block4: +; 58307: OP_INT_IS_TRUE(RUNNING_ON_LLINTERP, l_v21653); +; 58308: if (l_v21653) { +; 58309: goto block10; +; 58310: } +; 58311: goto block5; +; 58312: +; 58313: block5: +; 58314: l_v21654 = (struct pypy_header0 *)l_v21639; +; 58315: RPyField(l_v21654, h_tid) = (GROUP_MEMBER_OFFSET(struct group_pypy_g_typeinfo_s, member20)+0L); + + test esi, esi + jne SHORT $LN18 at pypy_g_ll_@159 + call _RPyAbort +$LN18 at pypy_g_ll_@159: + +; 58316: OP_ADR_ADD(l_v21639, (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21656); +; 58317: (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free = l_v21656; +; 58318: OP_ADR_ADD(l_v21639, 0, l_v21658); +; 58319: l_v21659 = (void*)l_v21658; +; 58320: l_v21696 = l_v21659; +; 58321: goto block6; +; 58322: +; 58323: block6: +; 58324: l_v21640 = (struct pypy_tuple2_0 *)l_v21696; +; 58325: l_v21660 = (l_v21640 != NULL); +; 58326: if (!l_v21660) { +; 58327: goto block9; +; 58328: } +; 58329: goto block7; +; 58330: +; 58331: block7: +; 58332: RPyField(l_v21640, t_item0) = l_v21638; + + fld QWORD PTR _l_v21638$[esp+64] + mov DWORD PTR [esi], 81 ; 00000051H + lea ecx, DWORD PTR [esi+24] + mov DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4, ecx + fstp QWORD PTR [esi+8] + +; 58333: RPyField(l_v21640, t_item1) = l_v21637; + + mov DWORD PTR [esi+16], edi + +; 58423: goto block8; +; 58424: } + + pop edi + mov eax, esi + pop esi +$block6$88281: +$block8$88289: + pop ebx + mov esp, ebp + pop ebp + ret 0 +_pypy_g_ll_math_ll_math_frexp ENDP +_TEXT ENDS diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -39,10 +39,15 @@ self.uses_frame_pointer = False self.r_localvar = self.r_localvarnofp self.filetag = filetag - # a "stack bottom" function is either main() or a callback from C code + # a "stack bottom" function is either pypy_main_function() or a + # callback from C code. In both cases they are identified by + # the presence of pypy_asm_stack_bottom(). self.is_stack_bottom = False def computegcmaptable(self, verbose=0): + if self.funcname in ['main', '_main']: + return [] # don't analyze main(), its prologue may contain + # strange instructions self.findlabels() self.parse_instructions() try: @@ -226,7 +231,7 @@ # in the frame at this point. This doesn't count the return address # which is the word immediately following the frame in memory. # The 'framesize' is set to an odd value if it is only an estimate - # (see visit_andl()). + # (see InsnCannotFollowEsp). def walker(insn, size_delta): check = deltas.setdefault(insn, size_delta) @@ -266,7 +271,8 @@ match = self.r_localvar_esp.match(localvar) if match: - if localvar == self.TOP_OF_STACK: # for pushl and popl, by + if localvar == self.TOP_OF_STACK_MINUS_WORD: + # for pushl and popl, by hint = None # default ebp addressing is else: # a bit nicer hint = 'esp' @@ -521,9 +527,8 @@ target = match.group("target") if target == self.ESP: # only for andl $-16, %esp used to align the stack in main(). - # The exact amount of adjutment is not known yet, so we use - # an odd-valued estimate to make sure the real value is not used - # elsewhere by the FunctionGcRootTracker. + # main() should not be seen at all. But on e.g. MSVC we see + # the instruction somewhere else too... return InsnCannotFollowEsp() else: return self.binary_insn(line) @@ -588,10 +593,12 @@ def _visit_push(self, line): match = self.r_unaryinsn.match(line) source = match.group(1) - return [InsnStackAdjust(-self.WORD)] + self.insns_for_copy(source, self.TOP_OF_STACK) + return self.insns_for_copy(source, self.TOP_OF_STACK_MINUS_WORD) + \ + [InsnStackAdjust(-self.WORD)] def _visit_pop(self, target): - return self.insns_for_copy(self.TOP_OF_STACK, target) + [InsnStackAdjust(+self.WORD)] + return [InsnStackAdjust(+self.WORD)] + \ + self.insns_for_copy(self.TOP_OF_STACK_MINUS_WORD, target) def _visit_prologue(self): # for the prologue of functions that use %ebp as frame pointer @@ -983,15 +990,15 @@ OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' LABEL = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)' OFFSET_LABELS = 2**30 - TOP_OF_STACK = '0(%esp)' + TOP_OF_STACK_MINUS_WORD = '-4(%esp)' r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$") r_functionend = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$") - LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|\d*[(]%esp[)]" + LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|-?\d*[(]%esp[)]" LOCALVARFP = LOCALVAR + r"|-?\d*[(]%ebp[)]" r_localvarnofp = re.compile(LOCALVAR) r_localvarfp = re.compile(LOCALVARFP) - r_localvar_esp = re.compile(r"(\d*)[(]%esp[)]") + r_localvar_esp = re.compile(r"(-?\d*)[(]%esp[)]") r_localvar_ebp = re.compile(r"(-?\d*)[(]%ebp[)]") r_rel_label = re.compile(r"(\d+):\s*$") @@ -1044,7 +1051,7 @@ OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' LABEL = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)' OFFSET_LABELS = 2**30 - TOP_OF_STACK = '0(%rsp)' + TOP_OF_STACK_MINUS_WORD = '-8(%rsp)' r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$") r_functionend = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$") @@ -1140,7 +1147,7 @@ CALLEE_SAVE_REGISTERS = ['ebx', 'esi', 'edi', 'ebp'] REG2LOC = dict((_reg, LOC_REG | ((_i+1)<<2)) for _i, _reg in enumerate(CALLEE_SAVE_REGISTERS)) - TOP_OF_STACK = 'DWORD PTR [esp]' + TOP_OF_STACK_MINUS_WORD = 'DWORD PTR [esp-4]' OPERAND = r'(?:(:?WORD|DWORD|BYTE) PTR |OFFSET )?[_\w?:@$]*(?:[-+0-9]+)?(:?\[[-+*\w0-9]+\])?' LABEL = r'([a-zA-Z_$@.][a-zA-Z0-9_$@.]*)' @@ -1170,7 +1177,7 @@ r_gcroot_marker = re.compile(r"$1") # never matches r_gcroot_marker_var = re.compile(r"DWORD PTR .+_constant_always_one_.+pypy_asm_gcroot") r_gcnocollect_marker = re.compile(r"\spypy_asm_gc_nocollect\(("+OPERAND+")\);") - r_bottom_marker = re.compile(r"; .+\tpypy_asm_stack_bottom\(\);") + r_bottom_marker = re.compile(r"; .+\spypy_asm_stack_bottom\(\);") FUNCTIONS_NOT_RETURNING = { '__exit': None, @@ -1323,12 +1330,11 @@ self.verbose = verbose self.shuffle = shuffle self.gcmaptable = [] - self.seen_main = False - def process(self, iterlines, newfile, entrypoint='main', filename='?'): + def process(self, iterlines, newfile, filename='?'): for in_function, lines in self.find_functions(iterlines): if in_function: - tracker = self.process_function(lines, entrypoint, filename) + tracker = self.process_function(lines, filename) lines = tracker.lines self.write_newfile(newfile, lines, filename.split('.')[0]) if self.verbose == 1: @@ -1337,11 +1343,9 @@ def write_newfile(self, newfile, lines, grist): newfile.writelines(lines) - def process_function(self, lines, entrypoint, filename): + def process_function(self, lines, filename): tracker = self.FunctionGcRootTracker( lines, filetag=getidentifier(filename)) - is_main = tracker.funcname == entrypoint - tracker.is_stack_bottom = is_main if self.verbose == 1: sys.stderr.write('.') elif self.verbose > 1: @@ -1356,7 +1360,6 @@ self.gcmaptable[:0] = table else: self.gcmaptable.extend(table) - self.seen_main |= is_main return tracker class ElfAssemblerParser(AssemblerParser): @@ -1432,11 +1435,6 @@ if functionlines: yield in_function, functionlines - def process_function(self, lines, entrypoint, filename): - entrypoint = '_' + entrypoint - return super(DarwinAssemblerParser, self).process_function( - lines, entrypoint, filename) - class DarwinAssemblerParser64(DarwinAssemblerParser): format = "darwin64" FunctionGcRootTracker = DarwinFunctionGcRootTracker64 @@ -1494,11 +1492,6 @@ "missed the end of the previous function") yield False, functionlines - def process_function(self, lines, entrypoint, filename): - entrypoint = '_' + entrypoint - return super(MsvcAssemblerParser, self).process_function( - lines, entrypoint, filename) - def write_newfile(self, newfile, lines, grist): newlines = [] for line in lines: @@ -1560,24 +1553,21 @@ self.shuffle = shuffle # to debug the sorting logic in asmgcroot.py self.format = format self.gcmaptable = [] - self.seen_main = False def dump_raw_table(self, output): - print >> output, "seen_main = %d" % (self.seen_main,) + print 'raw table' for entry in self.gcmaptable: print >> output, entry def reload_raw_table(self, input): firstline = input.readline() - assert firstline.startswith("seen_main = ") - self.seen_main |= bool(int(firstline[len("seen_main = "):].strip())) + assert firstline == 'raw table\n' for line in input: entry = eval(line) assert type(entry) is tuple self.gcmaptable.append(entry) def dump(self, output): - assert self.seen_main def _globalname(name, disp=""): return tracker_cls.function_names_prefix + name @@ -1649,8 +1639,8 @@ s = """\ /* See description in asmgcroot.py */ .cfi_startproc - movq\t%rdi, %rdx\t/* 1st argument, which is the callback */ - movq\t%rsi, %rcx\t/* 2nd argument, which is gcrootanchor */ + /* %rdi is the 1st argument, which is the callback */ + /* %rsi is the 2nd argument, which is gcrootanchor */ movq\t%rsp, %rax\t/* my frame top address */ pushq\t%rax\t\t/* ASM_FRAMEDATA[8] */ pushq\t%rbp\t\t/* ASM_FRAMEDATA[7] */ @@ -1663,15 +1653,15 @@ /* Add this ASM_FRAMEDATA to the front of the circular linked */ /* list. Let's call it 'self'. */ - movq\t8(%rcx), %rax\t/* next = gcrootanchor->next */ + movq\t8(%rsi), %rax\t/* next = gcrootanchor->next */ pushq\t%rax\t\t\t\t/* self->next = next */ - pushq\t%rcx\t\t\t/* self->prev = gcrootanchor */ - movq\t%rsp, 8(%rcx)\t/* gcrootanchor->next = self */ + pushq\t%rsi\t\t\t/* self->prev = gcrootanchor */ + movq\t%rsp, 8(%rsi)\t/* gcrootanchor->next = self */ movq\t%rsp, 0(%rax)\t\t\t/* next->prev = self */ .cfi_def_cfa_offset 80\t/* 9 pushes + the retaddr = 80 bytes */ /* note: the Mac OS X 16 bytes aligment must be respected. */ - call\t*%rdx\t\t/* invoke the callback */ + call\t*%rdi\t\t/* invoke the callback */ /* Detach this ASM_FRAMEDATA from the circular linked list */ popq\t%rsi\t\t/* prev = self->prev */ @@ -1688,7 +1678,7 @@ popq\t%rcx\t\t/* ignored ASM_FRAMEDATA[8] */ /* the return value is the one of the 'call' above, */ - /* because %rax (and possibly %rdx) are unmodified */ + /* because %rax is unmodified */ ret .cfi_endproc """ @@ -1835,11 +1825,11 @@ """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) - def process(self, iterlines, newfile, entrypoint='main', filename='?'): + def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) for in_function, lines in parser.find_functions(iterlines): if in_function: - tracker = parser.process_function(lines, entrypoint, filename) + tracker = parser.process_function(lines, filename) lines = tracker.lines parser.write_newfile(newfile, lines, filename.split('.')[0]) if self.verbose == 1: @@ -1848,7 +1838,6 @@ self.gcmaptable[:0] = parser.gcmaptable else: self.gcmaptable.extend(parser.gcmaptable) - self.seen_main |= parser.seen_main class UnrecognizedOperation(Exception): @@ -1915,7 +1904,6 @@ format = 'elf64' else: format = 'elf' - entrypoint = 'main' while len(sys.argv) > 1: if sys.argv[1] == '-v': del sys.argv[1] @@ -1929,9 +1917,9 @@ elif sys.argv[1].startswith('-f'): format = sys.argv[1][2:] del sys.argv[1] - elif sys.argv[1].startswith('-m'): - entrypoint = sys.argv[1][2:] - del sys.argv[1] + elif sys.argv[1].startswith('-'): + print >> sys.stderr, "unrecognized option:", sys.argv[1] + sys.exit(1) else: break tracker = GcRootTracker(verbose=verbose, shuffle=shuffle, format=format) @@ -1940,7 +1928,7 @@ firstline = f.readline() f.seek(0) assert firstline, "file %r is empty!" % (fn,) - if firstline.startswith('seen_main = '): + if firstline == 'raw table\n': tracker.reload_raw_table(f) f.close() else: @@ -1948,7 +1936,7 @@ lblfn = fn[:-2] + '.lbl.s' g = open(lblfn, 'w') try: - tracker.process(f, g, entrypoint=entrypoint, filename=fn) + tracker.process(f, g, filename=fn) except: g.close() os.unlink(lblfn) diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -570,7 +570,10 @@ mk.definition('ASMFILES', sfiles) mk.definition('ASMLBLFILES', lblsfiles) mk.definition('GCMAPFILES', gcmapfiles) - mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') if self.config.translation.shared: mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup") @@ -602,7 +605,7 @@ 'cmd /c $(MASM) /nologo /Cx /Cp /Zm /coff /Fo$@ /c $< $(INCLUDEDIRS)') mk.rule('.c.gcmap', '', ['$(CC) /nologo $(ASM_CFLAGS) /c /FAs /Fa$*.s $< $(INCLUDEDIRS)', - 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -m$(PYPY_MAIN_FUNCTION) -t $*.s > $@'] + 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -t $*.s > $@'] ) mk.rule('gcmaptable.c', '$(GCMAPFILES)', 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@') @@ -613,7 +616,7 @@ mk.rule('%.lbl.s %.gcmap', '%.s', [python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py ' - '-m$(PYPY_MAIN_FUNCTION) -t $< > $*.gctmp', + '-t $< > $*.gctmp', 'mv $*.gctmp $*.gcmap']) mk.rule('gcmaptable.s', '$(GCMAPFILES)', [python + @@ -623,7 +626,10 @@ mk.rule('.PRECIOUS', '%.s', "# don't remove .s files if Ctrl-C'ed") else: - mk.definition('DEBUGFLAGS', '-O1 -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O1 -g') mk.write() #self.translator.platform, # , @@ -682,28 +688,54 @@ def getothernodes(self): return self.othernodes[:] + def getbasecfilefornode(self, node, basecname): + # For FuncNode instances, use the python source filename (relative to + # the top directory): + if hasattr(node.obj, 'graph'): + g = node.obj.graph + # Lookup the filename from the function. + # However, not all FunctionGraph objs actually have a "func": + if hasattr(g, 'func'): + if g.filename.endswith('.py'): + localpath = py.path.local(g.filename) + pypkgpath = localpath.pypkgpath() + if pypkgpath: + relpypath = localpath.relto(pypkgpath) + return relpypath.replace('.py', '.c') + return basecname + def splitnodesimpl(self, basecname, nodes, nextra, nbetween, split_criteria=SPLIT_CRITERIA): + # Gather nodes by some criteria: + nodes_by_base_cfile = {} + for node in nodes: + c_filename = self.getbasecfilefornode(node, basecname) + if c_filename in nodes_by_base_cfile: + nodes_by_base_cfile[c_filename].append(node) + else: + nodes_by_base_cfile[c_filename] = [node] + # produce a sequence of nodes, grouped into files # which have no more than SPLIT_CRITERIA lines - iternodes = iter(nodes) - done = [False] - def subiter(): - used = nextra - for node in iternodes: - impl = '\n'.join(list(node.implementation())).split('\n') - if not impl: - continue - cost = len(impl) + nbetween - yield node, impl - del impl - if used + cost > split_criteria: - # split if criteria met, unless we would produce nothing. - raise StopIteration - used += cost - done[0] = True - while not done[0]: - yield self.uniquecname(basecname), subiter() + for basecname in nodes_by_base_cfile: + iternodes = iter(nodes_by_base_cfile[basecname]) + done = [False] + def subiter(): + used = nextra + for node in iternodes: + impl = '\n'.join(list(node.implementation())).split('\n') + if not impl: + continue + cost = len(impl) + nbetween + yield node, impl + del impl + if used + cost > split_criteria: + # split if criteria met, unless we would produce nothing. + raise StopIteration + used += cost + done[0] = True + while not done[0]: + yield self.uniquecname(basecname), subiter() def gen_readable_parts_of_source(self, f): split_criteria_big = SPLIT_CRITERIA @@ -900,8 +932,9 @@ print >> f, '}' def commondefs(defines): - from pypy.rlib.rarithmetic import LONG_BIT + from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT defines['PYPY_LONG_BIT'] = LONG_BIT + defines['PYPY_LONGLONG_BIT'] = LONGLONG_BIT def add_extra_files(eci): srcdir = py.path.local(autopath.pypydir).join('translator', 'c', 'src') diff --git a/pypy/translator/c/node.py b/pypy/translator/c/node.py --- a/pypy/translator/c/node.py +++ b/pypy/translator/c/node.py @@ -1031,7 +1031,7 @@ if (issubclass(value, BaseException) and value.__module__ == 'exceptions'): return 'PyExc_' + value.__name__ - if value is py.code._AssertionError: + if issubclass(value, AssertionError): return 'PyExc_AssertionError' if value is _StackOverflow: return 'PyExc_RuntimeError' diff --git a/pypy/translator/c/src/cjkcodecs/multibytecodec.c b/pypy/translator/c/src/cjkcodecs/multibytecodec.c --- a/pypy/translator/c/src/cjkcodecs/multibytecodec.c +++ b/pypy/translator/c/src/cjkcodecs/multibytecodec.c @@ -1,4 +1,5 @@ #include +#include #include "src/cjkcodecs/multibytecodec.h" @@ -93,6 +94,22 @@ return d->inbuf - d->inbuf_start; } +Py_ssize_t pypy_cjk_dec_replace_on_error(struct pypy_cjk_dec_s* d, + Py_UNICODE *newbuf, Py_ssize_t newlen, + Py_ssize_t in_offset) +{ + if (newlen > 0) + { + if (d->outbuf + newlen > d->outbuf_end) + if (expand_decodebuffer(d, newlen) == -1) + return MBERR_NOMEMORY; + memcpy(d->outbuf, newbuf, newlen * sizeof(Py_UNICODE)); + d->outbuf += newlen; + } + d->inbuf = d->inbuf_start + in_offset; + return 0; +} + /************************************************************/ struct pypy_cjk_enc_s *pypy_cjk_enc_init(const MultibyteCodec *codec, @@ -209,3 +226,19 @@ { return d->inbuf - d->inbuf_start; } + +Py_ssize_t pypy_cjk_enc_replace_on_error(struct pypy_cjk_enc_s* d, + char *newbuf, Py_ssize_t newlen, + Py_ssize_t in_offset) +{ + if (newlen > 0) + { + if (d->outbuf + newlen > d->outbuf_end) + if (expand_encodebuffer(d, newlen) == -1) + return MBERR_NOMEMORY; + memcpy(d->outbuf, newbuf, newlen); + d->outbuf += newlen; + } + d->inbuf = d->inbuf_start + in_offset; + return 0; +} diff --git a/pypy/translator/c/src/cjkcodecs/multibytecodec.h b/pypy/translator/c/src/cjkcodecs/multibytecodec.h --- a/pypy/translator/c/src/cjkcodecs/multibytecodec.h +++ b/pypy/translator/c/src/cjkcodecs/multibytecodec.h @@ -102,6 +102,8 @@ Py_ssize_t pypy_cjk_dec_outlen(struct pypy_cjk_dec_s *); Py_ssize_t pypy_cjk_dec_inbuf_remaining(struct pypy_cjk_dec_s *d); Py_ssize_t pypy_cjk_dec_inbuf_consumed(struct pypy_cjk_dec_s* d); +Py_ssize_t pypy_cjk_dec_replace_on_error(struct pypy_cjk_dec_s* d, + Py_UNICODE *, Py_ssize_t, Py_ssize_t); struct pypy_cjk_enc_s { const MultibyteCodec *codec; @@ -119,6 +121,8 @@ Py_ssize_t pypy_cjk_enc_outlen(struct pypy_cjk_enc_s *); Py_ssize_t pypy_cjk_enc_inbuf_remaining(struct pypy_cjk_enc_s *d); Py_ssize_t pypy_cjk_enc_inbuf_consumed(struct pypy_cjk_enc_s* d); +Py_ssize_t pypy_cjk_enc_replace_on_error(struct pypy_cjk_enc_s* d, + char *, Py_ssize_t, Py_ssize_t); /* list of codecs defined in the .c files */ diff --git a/pypy/translator/c/src/int.h b/pypy/translator/c/src/int.h --- a/pypy/translator/c/src/int.h +++ b/pypy/translator/c/src/int.h @@ -73,15 +73,28 @@ /* NB. shifting has same limitations as C: the shift count must be >= 0 and < LONG_BITS. */ -#define OP_INT_RSHIFT(x,y,r) r = Py_ARITHMETIC_RIGHT_SHIFT(long, x, y) -#define OP_UINT_RSHIFT(x,y,r) r = (x) >> (y) -#define OP_LLONG_RSHIFT(x,y,r) r = Py_ARITHMETIC_RIGHT_SHIFT(PY_LONG_LONG,x,y) -#define OP_ULLONG_RSHIFT(x,y,r) r = (x) >> (y) +#define CHECK_SHIFT_RANGE(y, bits) RPyAssert(y >= 0 && y < bits, \ + "The shift count is outside of the supported range") -#define OP_INT_LSHIFT(x,y,r) r = (x) << (y) -#define OP_UINT_LSHIFT(x,y,r) r = (x) << (y) -#define OP_LLONG_LSHIFT(x,y,r) r = (x) << (y) -#define OP_ULLONG_LSHIFT(x,y,r) r = (x) << (y) + +#define OP_INT_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = Py_ARITHMETIC_RIGHT_SHIFT(long, x, (y)) +#define OP_UINT_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = (x) >> (y) +#define OP_LLONG_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = Py_ARITHMETIC_RIGHT_SHIFT(PY_LONG_LONG,x, (y)) +#define OP_ULLONG_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = (x) >> (y) + + +#define OP_INT_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = (x) << (y) +#define OP_UINT_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = (x) << (y) +#define OP_LLONG_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = (x) << (y) +#define OP_ULLONG_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = (x) << (y) #define OP_INT_LSHIFT_OVF(x,y,r) \ OP_INT_LSHIFT(x,y,r); \ diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h --- a/pypy/translator/c/src/main.h +++ b/pypy/translator/c/src/main.h @@ -23,12 +23,19 @@ #include "src/winstuff.c" #endif -int PYPY_MAIN_FUNCTION(int argc, char *argv[]) +#ifdef __GNUC__ +/* Hack to prevent this function from being inlined. Helps asmgcc + because the main() function has often a different prologue/epilogue. */ +int pypy_main_function(int argc, char *argv[]) __attribute__((__noinline__)); +#endif + +int pypy_main_function(int argc, char *argv[]) { char *errmsg; int i, exitcode; RPyListOfString *list; + pypy_asm_stack_bottom(); instrument_setup(); if (sizeof(void*) != SIZEOF_LONG) { @@ -72,6 +79,12 @@ fprintf(stderr, "Fatal error during initialization: %s\n", errmsg); #endif abort(); + return 1; +} + +int PYPY_MAIN_FUNCTION(int argc, char *argv[]) +{ + return pypy_main_function(argc, argv); } #endif /* PYPY_NOT_MAIN_FILE */ diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h --- a/pypy/translator/c/src/mem.h +++ b/pypy/translator/c/src/mem.h @@ -222,6 +222,15 @@ #endif /* USING_BOEHM_GC */ + +#ifdef USING_NO_GC_AT_ALL +#define OP_BOEHM_ZERO_MALLOC(size, r, restype, is_atomic, is_varsize) \ + r = (restype) calloc(1, size); +#define OP_BOEHM_DISAPPEARING_LINK(link, obj, r) /* nothing */ +#define OP_GC__DISABLE_FINALIZERS(r) /* nothing */ +#define OP_GC__ENABLE_FINALIZERS(r) /* nothing */ +#endif + /************************************************************/ /* weakref support */ diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -1117,6 +1117,7 @@ S = lltype.GcStruct('S', ('u', lltype.Ptr(U))) A = lltype.GcArray(lltype.Ptr(S)) filename = self.filename_dump_typeids_z + open_flags = os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0) def fn(): s = lltype.malloc(S) @@ -1128,7 +1129,7 @@ # p = rgc.get_typeids_z() s = ''.join([p[i] for i in range(len(p))]) - fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0666) + fd = os.open(filename, open_flags, 0666) os.write(fd, s) os.close(fd) return 0 @@ -1137,7 +1138,7 @@ def test_write_typeids_z(self): self.run("write_typeids_z") - f = open(self.filename_dump_typeids_z) + f = open(self.filename_dump_typeids_z, 'rb') data_z = f.read() f.close() import zlib diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -55,6 +55,13 @@ data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + # Verify that the generated C files have sane names: + gen_c_files = [str(f) for f in cbuilder.extrafiles] + for expfile in ('rlib_rposix.c', + 'rpython_lltypesystem_rstr.c', + 'translator_c_test_test_standalone.c'): + assert cbuilder.targetdir.join(expfile) in gen_c_files + def test_print(self): def entry_point(argv): print "hello simpler world" @@ -596,6 +603,42 @@ # The traceback stops at f() because it's the first function that # captures the AssertionError, which makes the program abort. + def test_int_lshift_too_large(self): + from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT + def entry_point(argv): + a = int(argv[1]) + b = int(argv[2]) + print a << b + return 0 + + t, cbuilder = self.compile(entry_point, debug=True) + out = cbuilder.cmdexec("10 2", expect_crash=False) + assert out.strip() == str(10 << 2) + cases = [-4, LONG_BIT, LONGLONG_BIT] + for x in cases: + out, err = cbuilder.cmdexec("%s %s" % (1, x), expect_crash=True) + lines = err.strip() + assert 'The shift count is outside of the supported range' in lines + + def test_llong_rshift_too_large(self): + from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT + def entry_point(argv): + a = r_longlong(int(argv[1])) + b = r_longlong(int(argv[2])) + print a >> b + return 0 + + t, cbuilder = self.compile(entry_point, debug=True) + out = cbuilder.cmdexec("10 2", expect_crash=False) + assert out.strip() == str(10 >> 2) + out = cbuilder.cmdexec("%s %s" % (-42, LONGLONG_BIT - 1), expect_crash=False) + assert out.strip() == '-1' + cases = [-4, LONGLONG_BIT] + for x in cases: + out, err = cbuilder.cmdexec("%s %s" % (1, x), expect_crash=True) + lines = err.strip() + assert 'The shift count is outside of the supported range' in lines + def test_ll_assert_error_debug(self): def entry_point(argv): ll_assert(len(argv) != 1, "foobar") diff --git a/pypy/translator/driver.py b/pypy/translator/driver.py --- a/pypy/translator/driver.py +++ b/pypy/translator/driver.py @@ -559,6 +559,7 @@ shutil.copy(str(soname), str(newsoname)) self.log.info("copied: %s" % (newsoname,)) self.c_entryp = newexename + self.log.info('usession directory: %s' % (udir,)) self.log.info("created: %s" % (self.c_entryp,)) def task_compile_c(self): diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version diff --git a/pypy/translator/goal/targetnumpystandalone.py b/pypy/translator/goal/targetnumpystandalone.py --- a/pypy/translator/goal/targetnumpystandalone.py +++ b/pypy/translator/goal/targetnumpystandalone.py @@ -10,46 +10,32 @@ """ import time -from pypy.module.micronumpy.numarray import SingleDimArray, Code, compute +from pypy.module.micronumpy.compile import numpy_compile from pypy.jit.codewriter.policy import JitPolicy - -def create_array(size): - a = SingleDimArray(size) - for i in range(size): - a.storage[i] = float(i % 10) - return a +from pypy.rpython.annlowlevel import hlstr def entry_point(argv): if len(argv) != 3: print __doc__ return 1 - bytecode = argv[1] - for b in bytecode: - if b not in 'alf': - print "WRONG BYTECODE" - print __doc__ - return 2 try: size = int(argv[2]) except ValueError: print "INVALID LITERAL FOR INT:", argv[2] print __doc__ return 3 - no_arrays = bytecode.count('l') - no_floats = bytecode.count('f') - arrays = [] - floats = [] - for i in range(no_arrays): - arrays.append(create_array(size)) - for i in range(no_floats): - floats.append(float(i + 1)) - code = Code(bytecode, arrays, floats) t0 = time.time() - compute(code) - print "bytecode:", bytecode, "size:", size + main(argv[0], size) + print "bytecode:", argv[0], "size:", size print "took:", time.time() - t0 return 0 +def main(bc, size): + if not isinstance(bc, str): + bc = hlstr(bc) # for tests + a = numpy_compile(bc, size) + a = a.compute() + def target(*args): return entry_point, None diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -103,6 +103,8 @@ specname = os.path.splitext(os.path.basename(targetspec))[0] sys.path.insert(0, os.path.dirname(targetspec)) mod = __import__(specname) + if 'target' not in mod.__dict__: + raise Exception("file %r is not a valid targetxxx.py." % (targetspec,)) return mod.__dict__ def parse_options_and_load_target(): @@ -149,6 +151,9 @@ log.ERROR("Could not find target %r" % (arg, )) sys.exit(1) + # apply the platform settings + set_platform(config) + targetspec = translateconfig.targetspec targetspec_dic = load_target(targetspec) @@ -164,9 +169,6 @@ existing_config=config, translating=True) - # apply the platform settings - set_platform(config) - # apply the optimization level settings set_opt_level(config, translateconfig.opt) @@ -184,7 +186,7 @@ print "\n\nTarget specific help:\n\n" targetspec_dic['print_help'](config) print "\n\nFor detailed descriptions of the command line options see" - print "http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html" + print "http://pypy.readthedocs.org/en/latest/config/commandline.html" sys.exit(0) return targetspec_dic, translateconfig, config, args diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,12 +964,15 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py --- a/pypy/translator/platform/__init__.py +++ b/pypy/translator/platform/__init__.py @@ -38,6 +38,7 @@ c_environ = None relevant_environ = () + log_errors = True so_prefixes = ('',) @@ -120,11 +121,12 @@ if returncode != 0: errorfile = outname.new(ext='errors') errorfile.write(stderr, 'wb') - stderrlines = stderr.splitlines() - for line in stderrlines: - log.Error(line) - # ^^^ don't use ERROR, because it might actually be fine. - # Also, ERROR confuses lib-python/conftest.py. + if self.log_errors: + stderrlines = stderr.splitlines() + for line in stderrlines: + log.Error(line) + # ^^^ don't use ERROR, because it might actually be fine. + # Also, ERROR confuses lib-python/conftest.py. raise CompilationError(stdout, stderr) else: for line in stderr.splitlines(): diff --git a/pypy/translator/platform/darwin.py b/pypy/translator/platform/darwin.py --- a/pypy/translator/platform/darwin.py +++ b/pypy/translator/platform/darwin.py @@ -68,12 +68,10 @@ class Darwin_i386(Darwin): name = "darwin_i386" - link_flags = ('-arch', 'i386', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'i386') + cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer') class Darwin_x86_64(Darwin): name = "darwin_x86_64" - link_flags = ('-arch', 'x86_64', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'x86_64') + cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer') diff --git a/pytest.py b/pytest.py old mode 100644 new mode 100755 --- a/pytest.py +++ b/pytest.py @@ -1,7 +1,6 @@ +#!/usr/bin/env python """ unit and functional testing with Python. -(pypy version of startup script) -see http://pytest.org for details. """ __all__ = ['main'] @@ -9,23 +8,6 @@ from _pytest import core as cmdline from _pytest import __version__ -# This pytest.py script is located in the pypy source tree -# which has a copy of pytest and py within its source tree. -# If the environment also has an installed version of pytest/py -# we are bound to get warnings so we disable them. -# XXX eventually pytest and py should not be inlined shipped -# with the pypy source code but become a requirement for installation. - -import warnings -warnings.filterwarnings("ignore", - "Module py was already imported", category=UserWarning) -warnings.filterwarnings("ignore", - "Module _pytest was already imported", - category=UserWarning) -warnings.filterwarnings("ignore", - "Module pytest was already imported", - category=UserWarning) - if __name__ == '__main__': # if run as a script or by 'python -m pytest' raise SystemExit(main()) else: From noreply at buildbot.pypy.org Wed Jul 13 11:01:55 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 11:01:55 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: make the backend work with the merged changes so that the tests can run Message-ID: <20110713090155.E7F4C8291A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45528:7a98d4859cd7 Date: 2011-07-13 10:54 +0200 http://bitbucket.org/pypy/pypy/changeset/7a98d4859cd7/ Log: make the backend work with the merged changes so that the tests can run diff --git a/pypy/jit/backend/arm/arch.py b/pypy/jit/backend/arm/arch.py --- a/pypy/jit/backend/arm/arch.py +++ b/pypy/jit/backend/arm/arch.py @@ -34,7 +34,7 @@ "pypy__arm_int_div", [lltype.Signed, lltype.Signed], lltype.Signed, _callable=arm_int_div_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) arm_uint_div_sign = lltype.Ptr(lltype.FuncType([lltype.Unsigned, lltype.Unsigned], lltype.Unsigned)) def arm_uint_div_emulator(a, b): @@ -43,7 +43,7 @@ "pypy__arm_uint_div", [lltype.Unsigned, lltype.Unsigned], lltype.Unsigned, _callable=arm_uint_div_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) arm_int_mod_sign = arm_int_div_sign @@ -60,5 +60,5 @@ "pypy__arm_int_mod", [lltype.Signed, lltype.Signed], lltype.Signed, _callable=arm_int_mod_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -84,9 +84,10 @@ self.datablockwrapper = None def setup(self, looptoken, operations): - self.cpu.gc_ll_descr.rewrite_assembler(self.cpu, operations) + self.current_clt = looptoken.compiled_loop_token + self.cpu.gc_ll_descr.rewrite_assembler(self.cpu, + operations, self.current_clt.allgcrefs) assert self.memcpy_addr != 0, 'setup_once() not called?' - self.current_clt = looptoken.compiled_loop_token self.mc = ARMv7Builder() self.pending_guards = [] assert self.datablockwrapper is None @@ -556,6 +557,7 @@ def assemble_loop(self, inputargs, operations, looptoken, log): clt = CompiledLoopToken(self.cpu, looptoken.number) + clt.allgcrefs = [] looptoken.compiled_loop_token = clt self.setup(looptoken, operations) From noreply at buildbot.pypy.org Wed Jul 13 11:01:57 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 11:01:57 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: implement cond_call_gc_wb_array Message-ID: <20110713090157.237C28291A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45529:46e12d14ce56 Date: 2011-07-13 10:54 +0200 http://bitbucket.org/pypy/pypy/changeset/46e12d14ce56/ Log: implement cond_call_gc_wb_array diff --git a/pypy/jit/backend/arm/opassembler.py b/pypy/jit/backend/arm/opassembler.py --- a/pypy/jit/backend/arm/opassembler.py +++ b/pypy/jit/backend/arm/opassembler.py @@ -446,6 +446,17 @@ if we_are_translated(): cls = self.cpu.gc_ll_descr.has_write_barrier_class() assert cls is not None and isinstance(descr, cls) + + opnum = op.getopnum() + if opnum == rop.COND_CALL_GC_WB: + N = 2 + addr = descr.get_write_barrier_fn(self.cpu) + elif opnum == rop.COND_CALL_GC_WB_ARRAY: + N = 3 + addr = descr.get_write_barrier_from_array_fn(self.cpu) + assert addr != 0 + else: + raise AssertionError(opnum) loc_base = arglocs[0] self.mc.LDR_ri(r.ip.value, loc_base.value) # calculate the shift value to rotate the ofs according to the ARM @@ -464,8 +475,16 @@ # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. with saved_registers(self.mc, r.caller_resp, regalloc=regalloc): - remap_frame_layout(self, arglocs, [r.r0, r.r1], r.ip) - self.mc.BL(descr.get_write_barrier_fn(self.cpu)) + if N == 2: + callargs = [r.r0, r.r1] + else: + callargs = [r.r0, r.r1, r.r2] + remap_frame_layout(self, arglocs, callargs, r.ip) + func = self.cpu.cast_adr_to_int(addr) + # + # misaligned stack in the call, but it's ok because the write barrier + # is not going to call anything more. + self.mc.BL(func) # patch the JZ above offset = self.mc.currpos() - jz_location @@ -473,6 +492,7 @@ pmc.ADD_ri(r.pc.value, r.pc.value, offset - PC_OFFSET, cond=c.EQ) return fcond + emit_op_cond_call_gc_wb_array = emit_op_cond_call_gc_wb class FieldOpAssembler(object): diff --git a/pypy/jit/backend/arm/regalloc.py b/pypy/jit/backend/arm/regalloc.py --- a/pypy/jit/backend/arm/regalloc.py +++ b/pypy/jit/backend/arm/regalloc.py @@ -965,16 +965,20 @@ def prepare_op_cond_call_gc_wb(self, op, fcond): assert op.result is None - args = op.getarglist() - loc_newvalue, box_newvalue = self._ensure_value_is_boxed(op.getarg(1), args) - # ^^^ we force loc_newvalue in a reg (unless it's a Const), - # because it will be needed anyway by the following setfield_gc. - # It avoids loading it twice from the memory. - loc_base, box_base = self._ensure_value_is_boxed(op.getarg(0), args) - arglocs = [loc_base, loc_newvalue] - self.rm.possibly_free_vars([box_newvalue, box_base]) + N = op.numargs() + # we force all arguments in a reg (unless they are Consts), + # because it will be needed anyway by the following setfield_gc + # or setarrayitem_gc. It avoids loading it twice from the memory. + arglocs = [] + argboxes = [] + for i in range(N): + loc, box = self._ensure_value_is_boxed(op.getarg(i), arglocs) + arglocs.append(loc) + argboxes.append(box) + self.rm.possibly_free_vars(argboxes) return arglocs + prepare_op_cond_call_gc_wb_array = prepare_op_cond_call_gc_wb def prepare_op_force_token(self, op, fcond): res_loc = self.force_allocate_reg(op.result) From noreply at buildbot.pypy.org Wed Jul 13 11:02:01 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 11:02:01 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: merge heads Message-ID: <20110713090201.176AD8291A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45530:a825381eba0b Date: 2011-07-13 11:01 +0200 http://bitbucket.org/pypy/pypy/changeset/a825381eba0b/ Log: merge heads diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -2,6 +2,7 @@ *.py[co] *.sw[po] *~ +.*.swp syntax: regexp ^testresult$ @@ -39,6 +40,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ @@ -65,6 +68,7 @@ ^pypy/doc/image/lattice3\.png$ ^pypy/doc/image/stackless_informal\.png$ ^pypy/doc/image/parsing_example.+\.png$ +^pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test\.o$ ^compiled ^.git/ ^release/ diff --git a/_pytest/__init__.py b/_pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.0.3' +__version__ = '2.1.0.dev4' diff --git a/_pytest/assertion.py b/_pytest/assertion.py deleted file mode 100644 --- a/_pytest/assertion.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -support for presented detailed information in failing assertions. -""" -import py -import sys -from _pytest.monkeypatch import monkeypatch - -def pytest_addoption(parser): - group = parser.getgroup("debugconfig") - group._addoption('--no-assert', action="store_true", default=False, - dest="noassert", - help="disable python assert expression reinterpretation."), - -def pytest_configure(config): - # The _reprcompare attribute on the py.code module is used by - # py._code._assertionnew to detect this plugin was loaded and in - # turn call the hooks defined here as part of the - # DebugInterpreter. - m = monkeypatch() - config._cleanup.append(m.undo) - warn_about_missing_assertion() - if not config.getvalue("noassert") and not config.getvalue("nomagic"): - def callbinrepr(op, left, right): - hook_result = config.hook.pytest_assertrepr_compare( - config=config, op=op, left=left, right=right) - for new_expl in hook_result: - if new_expl: - return '\n~'.join(new_expl) - m.setattr(py.builtin.builtins, - 'AssertionError', py.code._AssertionError) - m.setattr(py.code, '_reprcompare', callbinrepr) - -def warn_about_missing_assertion(): - try: - assert False - except AssertionError: - pass - else: - sys.stderr.write("WARNING: failing tests may report as passing because " - "assertions are turned off! (are you using python -O?)\n") - -# Provide basestring in python3 -try: - basestring = basestring -except NameError: - basestring = str - - -def pytest_assertrepr_compare(op, left, right): - """return specialised explanations for some operators/operands""" - width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op - left_repr = py.io.saferepr(left, maxsize=int(width/2)) - right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) - summary = '%s %s %s' % (left_repr, op, right_repr) - - issequence = lambda x: isinstance(x, (list, tuple)) - istext = lambda x: isinstance(x, basestring) - isdict = lambda x: isinstance(x, dict) - isset = lambda x: isinstance(x, set) - - explanation = None - try: - if op == '==': - if istext(left) and istext(right): - explanation = _diff_text(left, right) - elif issequence(left) and issequence(right): - explanation = _compare_eq_sequence(left, right) - elif isset(left) and isset(right): - explanation = _compare_eq_set(left, right) - elif isdict(left) and isdict(right): - explanation = _diff_text(py.std.pprint.pformat(left), - py.std.pprint.pformat(right)) - elif op == 'not in': - if istext(left) and istext(right): - explanation = _notin_text(left, right) - except py.builtin._sysex: - raise - except: - excinfo = py.code.ExceptionInfo() - explanation = ['(pytest_assertion plugin: representation of ' - 'details failed. Probably an object has a faulty __repr__.)', - str(excinfo) - ] - - - if not explanation: - return None - - # Don't include pageloads of data, should be configurable - if len(''.join(explanation)) > 80*8: - explanation = ['Detailed information too verbose, truncated'] - - return [summary] + explanation - - -def _diff_text(left, right): - """Return the explanation for the diff between text - - This will skip leading and trailing characters which are - identical to keep the diff minimal. - """ - explanation = [] - i = 0 # just in case left or right has zero length - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - break - if i > 42: - i -= 10 # Provide some context - explanation = ['Skipping %s identical ' - 'leading characters in diff' % i] - left = left[i:] - right = right[i:] - if len(left) == len(right): - for i in range(len(left)): - if left[-i] != right[-i]: - break - if i > 42: - i -= 10 # Provide some context - explanation += ['Skipping %s identical ' - 'trailing characters in diff' % i] - left = left[:-i] - right = right[:-i] - explanation += [line.strip('\n') - for line in py.std.difflib.ndiff(left.splitlines(), - right.splitlines())] - return explanation - - -def _compare_eq_sequence(left, right): - explanation = [] - for i in range(min(len(left), len(right))): - if left[i] != right[i]: - explanation += ['At index %s diff: %r != %r' % - (i, left[i], right[i])] - break - if len(left) > len(right): - explanation += ['Left contains more items, ' - 'first extra item: %s' % py.io.saferepr(left[len(right)],)] - elif len(left) < len(right): - explanation += ['Right contains more items, ' - 'first extra item: %s' % py.io.saferepr(right[len(left)],)] - return explanation # + _diff_text(py.std.pprint.pformat(left), - # py.std.pprint.pformat(right)) - - -def _compare_eq_set(left, right): - explanation = [] - diff_left = left - right - diff_right = right - left - if diff_left: - explanation.append('Extra items in the left set:') - for item in diff_left: - explanation.append(py.io.saferepr(item)) - if diff_right: - explanation.append('Extra items in the right set:') - for item in diff_right: - explanation.append(py.io.saferepr(item)) - return explanation - - -def _notin_text(term, text): - index = text.find(term) - head = text[:index] - tail = text[index+len(term):] - correct_text = head + tail - diff = _diff_text(correct_text, text) - newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] - for line in diff: - if line.startswith('Skipping'): - continue - if line.startswith('- '): - continue - if line.startswith('+ '): - newdiff.append(' ' + line[2:]) - else: - newdiff.append(line) - return newdiff diff --git a/_pytest/assertion/__init__.py b/_pytest/assertion/__init__.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/__init__.py @@ -0,0 +1,128 @@ +""" +support for presenting detailed information in failing assertions. +""" +import py +import imp +import marshal +import struct +import sys +import pytest +from _pytest.monkeypatch import monkeypatch +from _pytest.assertion import reinterpret, util + +try: + from _pytest.assertion.rewrite import rewrite_asserts +except ImportError: + rewrite_asserts = None +else: + import ast + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption('--assertmode', action="store", dest="assertmode", + choices=("on", "old", "off", "default"), default="default", + metavar="on|old|off", + help="""control assertion debugging tools. +'off' performs no assertion debugging. +'old' reinterprets the expressions in asserts to glean information. +'on' (the default) rewrites the assert statements in test modules to provide +sub-expression results.""") + group.addoption('--no-assert', action="store_true", default=False, + dest="noassert", help="DEPRECATED equivalent to --assertmode=off") + group.addoption('--nomagic', action="store_true", default=False, + dest="nomagic", help="DEPRECATED equivalent to --assertmode=off") + +class AssertionState: + """State for the assertion plugin.""" + + def __init__(self, config, mode): + self.mode = mode + self.trace = config.trace.root.get("assertion") + +def pytest_configure(config): + warn_about_missing_assertion() + mode = config.getvalue("assertmode") + if config.getvalue("noassert") or config.getvalue("nomagic"): + if mode not in ("off", "default"): + raise pytest.UsageError("assertion options conflict") + mode = "off" + elif mode == "default": + mode = "on" + if mode != "off": + def callbinrepr(op, left, right): + hook_result = config.hook.pytest_assertrepr_compare( + config=config, op=op, left=left, right=right) + for new_expl in hook_result: + if new_expl: + return '\n~'.join(new_expl) + m = monkeypatch() + config._cleanup.append(m.undo) + m.setattr(py.builtin.builtins, 'AssertionError', + reinterpret.AssertionError) + m.setattr(util, '_reprcompare', callbinrepr) + if mode == "on" and rewrite_asserts is None: + mode = "old" + config._assertstate = AssertionState(config, mode) + config._assertstate.trace("configured with mode set to %r" % (mode,)) + +def _write_pyc(co, source_path): + if hasattr(imp, "cache_from_source"): + # Handle PEP 3147 pycs. + pyc = py.path.local(imp.cache_from_source(str(source_path))) + pyc.ensure() + else: + pyc = source_path + "c" + mtime = int(source_path.mtime()) + fp = pyc.open("wb") + try: + fp.write(imp.get_magic()) + fp.write(struct.pack(">", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + + +class DebugInterpreter(ast.NodeVisitor): + """Interpret AST nodes to gleam useful debugging information. """ + + def __init__(self, frame): + self.frame = frame + + def generic_visit(self, node): + # Fallback when we don't have a special implementation. + if _is_ast_expr(node): + mod = ast.Expression(node) + co = self._compile(mod) + try: + result = self.frame.eval(co) + except Exception: + raise Failure() + explanation = self.frame.repr(result) + return explanation, result + elif _is_ast_stmt(node): + mod = ast.Module([node]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co) + except Exception: + raise Failure() + return None, None + else: + raise AssertionError("can't handle %s" %(node,)) + + def _compile(self, source, mode="eval"): + return compile(source, "", mode) + + def visit_Expr(self, expr): + return self.visit(expr.value) + + def visit_Module(self, mod): + for stmt in mod.body: + self.visit(stmt) + + def visit_Name(self, name): + explanation, result = self.generic_visit(name) + # See if the name is local. + source = "%r in locals() is not globals()" % (name.id,) + co = self._compile(source) + try: + local = self.frame.eval(co) + except Exception: + # have to assume it isn't + local = None + if local is None or not self.frame.is_true(local): + return name.id, result + return explanation, result + + def visit_Compare(self, comp): + left = comp.left + left_explanation, left_result = self.visit(left) + for op, next_op in zip(comp.ops, comp.comparators): + next_explanation, next_result = self.visit(next_op) + op_symbol = operator_map[op.__class__] + explanation = "%s %s %s" % (left_explanation, op_symbol, + next_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=next_result) + except Exception: + raise Failure(explanation) + try: + if not self.frame.is_true(result): + break + except KeyboardInterrupt: + raise + except: + break + left_explanation, left_result = next_explanation, next_result + + if util._reprcompare is not None: + res = util._reprcompare(op_symbol, left_result, next_result) + if res: + explanation = res + return explanation, result + + def visit_BoolOp(self, boolop): + is_or = isinstance(boolop.op, ast.Or) + explanations = [] + for operand in boolop.values: + explanation, result = self.visit(operand) + explanations.append(explanation) + if result == is_or: + break + name = is_or and " or " or " and " + explanation = "(" + name.join(explanations) + ")" + return explanation, result + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_explanation, operand_result = self.visit(unary.operand) + explanation = pattern % (operand_explanation,) + co = self._compile(pattern % ("__exprinfo_expr",)) + try: + result = self.frame.eval(co, __exprinfo_expr=operand_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_BinOp(self, binop): + left_explanation, left_result = self.visit(binop.left) + right_explanation, right_result = self.visit(binop.right) + symbol = operator_map[binop.op.__class__] + explanation = "(%s %s %s)" % (left_explanation, symbol, + right_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=right_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_Call(self, call): + func_explanation, func = self.visit(call.func) + arg_explanations = [] + ns = {"__exprinfo_func" : func} + arguments = [] + for arg in call.args: + arg_explanation, arg_result = self.visit(arg) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + arguments.append(arg_name) + arg_explanations.append(arg_explanation) + for keyword in call.keywords: + arg_explanation, arg_result = self.visit(keyword.value) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + keyword_source = "%s=%%s" % (keyword.arg) + arguments.append(keyword_source % (arg_name,)) + arg_explanations.append(keyword_source % (arg_explanation,)) + if call.starargs: + arg_explanation, arg_result = self.visit(call.starargs) + arg_name = "__exprinfo_star" + ns[arg_name] = arg_result + arguments.append("*%s" % (arg_name,)) + arg_explanations.append("*%s" % (arg_explanation,)) + if call.kwargs: + arg_explanation, arg_result = self.visit(call.kwargs) + arg_name = "__exprinfo_kwds" + ns[arg_name] = arg_result + arguments.append("**%s" % (arg_name,)) + arg_explanations.append("**%s" % (arg_explanation,)) + args_explained = ", ".join(arg_explanations) + explanation = "%s(%s)" % (func_explanation, args_explained) + args = ", ".join(arguments) + source = "__exprinfo_func(%s)" % (args,) + co = self._compile(source) + try: + result = self.frame.eval(co, **ns) + except Exception: + raise Failure(explanation) + pattern = "%s\n{%s = %s\n}" + rep = self.frame.repr(result) + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def _is_builtin_name(self, name): + pattern = "%r not in globals() and %r not in locals()" + source = pattern % (name.id, name.id) + co = self._compile(source) + try: + return self.frame.eval(co) + except Exception: + return False + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + source_explanation, source_result = self.visit(attr.value) + explanation = "%s.%s" % (source_explanation, attr.attr) + source = "__exprinfo_expr.%s" % (attr.attr,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + raise Failure(explanation) + explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), + self.frame.repr(result), + source_explanation, attr.attr) + # Check if the attr is from an instance. + source = "%r in getattr(__exprinfo_expr, '__dict__', {})" + source = source % (attr.attr,) + co = self._compile(source) + try: + from_instance = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + from_instance = None + if from_instance is None or self.frame.is_true(from_instance): + rep = self.frame.repr(result) + pattern = "%s\n{%s = %s\n}" + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def visit_Assert(self, assrt): + test_explanation, test_result = self.visit(assrt.test) + explanation = "assert %s" % (test_explanation,) + if not self.frame.is_true(test_result): + try: + raise BuiltinAssertionError + except Exception: + raise Failure(explanation) + return explanation, test_result + + def visit_Assign(self, assign): + value_explanation, value_result = self.visit(assign.value) + explanation = "... = %s" % (value_explanation,) + name = ast.Name("__exprinfo_expr", ast.Load(), + lineno=assign.value.lineno, + col_offset=assign.value.col_offset) + new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, + col_offset=assign.col_offset) + mod = ast.Module([new_assign]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co, __exprinfo_expr=value_result) + except Exception: + raise Failure(explanation) + return explanation, value_result diff --git a/_pytest/assertion/oldinterpret.py b/_pytest/assertion/oldinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/oldinterpret.py @@ -0,0 +1,552 @@ +import py +import sys, inspect +from compiler import parse, ast, pycodegen +from _pytest.assertion.util import format_explanation +from _pytest.assertion.reinterpret import BuiltinAssertionError + +passthroughex = py.builtin._sysex + +class Failure: + def __init__(self, node): + self.exc, self.value, self.tb = sys.exc_info() + self.node = node + +class View(object): + """View base class. + + If C is a subclass of View, then C(x) creates a proxy object around + the object x. The actual class of the proxy is not C in general, + but a *subclass* of C determined by the rules below. To avoid confusion + we call view class the class of the proxy (a subclass of C, so of View) + and object class the class of x. + + Attributes and methods not found in the proxy are automatically read on x. + Other operations like setting attributes are performed on the proxy, as + determined by its view class. The object x is available from the proxy + as its __obj__ attribute. + + The view class selection is determined by the __view__ tuples and the + optional __viewkey__ method. By default, the selected view class is the + most specific subclass of C whose __view__ mentions the class of x. + If no such subclass is found, the search proceeds with the parent + object classes. For example, C(True) will first look for a subclass + of C with __view__ = (..., bool, ...) and only if it doesn't find any + look for one with __view__ = (..., int, ...), and then ..., object,... + If everything fails the class C itself is considered to be the default. + + Alternatively, the view class selection can be driven by another aspect + of the object x, instead of the class of x, by overriding __viewkey__. + See last example at the end of this module. + """ + + _viewcache = {} + __view__ = () + + def __new__(rootclass, obj, *args, **kwds): + self = object.__new__(rootclass) + self.__obj__ = obj + self.__rootclass__ = rootclass + key = self.__viewkey__() + try: + self.__class__ = self._viewcache[key] + except KeyError: + self.__class__ = self._selectsubclass(key) + return self + + def __getattr__(self, attr): + # attributes not found in the normal hierarchy rooted on View + # are looked up in the object's real class + return getattr(self.__obj__, attr) + + def __viewkey__(self): + return self.__obj__.__class__ + + def __matchkey__(self, key, subclasses): + if inspect.isclass(key): + keys = inspect.getmro(key) + else: + keys = [key] + for key in keys: + result = [C for C in subclasses if key in C.__view__] + if result: + return result + return [] + + def _selectsubclass(self, key): + subclasses = list(enumsubclasses(self.__rootclass__)) + for C in subclasses: + if not isinstance(C.__view__, tuple): + C.__view__ = (C.__view__,) + choices = self.__matchkey__(key, subclasses) + if not choices: + return self.__rootclass__ + elif len(choices) == 1: + return choices[0] + else: + # combine the multiple choices + return type('?', tuple(choices), {}) + + def __repr__(self): + return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) + + +def enumsubclasses(cls): + for subcls in cls.__subclasses__(): + for subsubclass in enumsubclasses(subcls): + yield subsubclass + yield cls + + +class Interpretable(View): + """A parse tree node with a few extra methods.""" + explanation = None + + def is_builtin(self, frame): + return False + + def eval(self, frame): + # fall-back for unknown expression nodes + try: + expr = ast.Expression(self.__obj__) + expr.filename = '' + self.__obj__.filename = '' + co = pycodegen.ExpressionCodeGenerator(expr).getCode() + result = frame.eval(co) + except passthroughex: + raise + except: + raise Failure(self) + self.result = result + self.explanation = self.explanation or frame.repr(self.result) + + def run(self, frame): + # fall-back for unknown statement nodes + try: + expr = ast.Module(None, ast.Stmt([self.__obj__])) + expr.filename = '' + co = pycodegen.ModuleCodeGenerator(expr).getCode() + frame.exec_(co) + except passthroughex: + raise + except: + raise Failure(self) + + def nice_explanation(self): + return format_explanation(self.explanation) + + +class Name(Interpretable): + __view__ = ast.Name + + def is_local(self, frame): + source = '%r in locals() is not globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_global(self, frame): + source = '%r in globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_builtin(self, frame): + source = '%r not in locals() and %r not in globals()' % ( + self.name, self.name) + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + super(Name, self).eval(frame) + if not self.is_local(frame): + self.explanation = self.name + +class Compare(Interpretable): + __view__ = ast.Compare + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + for operation, expr2 in self.ops: + if hasattr(self, 'result'): + # shortcutting in chained expressions + if not frame.is_true(self.result): + break + expr2 = Interpretable(expr2) + expr2.eval(frame) + self.explanation = "%s %s %s" % ( + expr.explanation, operation, expr2.explanation) + source = "__exprinfo_left %s __exprinfo_right" % operation + try: + self.result = frame.eval(source, + __exprinfo_left=expr.result, + __exprinfo_right=expr2.result) + except passthroughex: + raise + except: + raise Failure(self) + expr = expr2 + +class And(Interpretable): + __view__ = ast.And + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if not frame.is_true(expr.result): + break + self.explanation = '(' + ' and '.join(explanations) + ')' + +class Or(Interpretable): + __view__ = ast.Or + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if frame.is_true(expr.result): + break + self.explanation = '(' + ' or '.join(explanations) + ')' + + +# == Unary operations == +keepalive = [] +for astclass, astpattern in { + ast.Not : 'not __exprinfo_expr', + ast.Invert : '(~__exprinfo_expr)', + }.items(): + + class UnaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + expr = Interpretable(self.expr) + expr.eval(frame) + self.explanation = astpattern.replace('__exprinfo_expr', + expr.explanation) + try: + self.result = frame.eval(astpattern, + __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(UnaryArith) + +# == Binary operations == +for astclass, astpattern in { + ast.Add : '(__exprinfo_left + __exprinfo_right)', + ast.Sub : '(__exprinfo_left - __exprinfo_right)', + ast.Mul : '(__exprinfo_left * __exprinfo_right)', + ast.Div : '(__exprinfo_left / __exprinfo_right)', + ast.Mod : '(__exprinfo_left % __exprinfo_right)', + ast.Power : '(__exprinfo_left ** __exprinfo_right)', + }.items(): + + class BinaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + left = Interpretable(self.left) + left.eval(frame) + right = Interpretable(self.right) + right.eval(frame) + self.explanation = (astpattern + .replace('__exprinfo_left', left .explanation) + .replace('__exprinfo_right', right.explanation)) + try: + self.result = frame.eval(astpattern, + __exprinfo_left=left.result, + __exprinfo_right=right.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(BinaryArith) + + +class CallFunc(Interpretable): + __view__ = ast.CallFunc + + def is_bool(self, frame): + source = 'isinstance(__exprinfo_value, bool)' + try: + return frame.is_true(frame.eval(source, + __exprinfo_value=self.result)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + node = Interpretable(self.node) + node.eval(frame) + explanations = [] + vars = {'__exprinfo_fn': node.result} + source = '__exprinfo_fn(' + for a in self.args: + if isinstance(a, ast.Keyword): + keyword = a.name + a = a.expr + else: + keyword = None + a = Interpretable(a) + a.eval(frame) + argname = '__exprinfo_%d' % len(vars) + vars[argname] = a.result + if keyword is None: + source += argname + ',' + explanations.append(a.explanation) + else: + source += '%s=%s,' % (keyword, argname) + explanations.append('%s=%s' % (keyword, a.explanation)) + if self.star_args: + star_args = Interpretable(self.star_args) + star_args.eval(frame) + argname = '__exprinfo_star' + vars[argname] = star_args.result + source += '*' + argname + ',' + explanations.append('*' + star_args.explanation) + if self.dstar_args: + dstar_args = Interpretable(self.dstar_args) + dstar_args.eval(frame) + argname = '__exprinfo_kwds' + vars[argname] = dstar_args.result + source += '**' + argname + ',' + explanations.append('**' + dstar_args.explanation) + self.explanation = "%s(%s)" % ( + node.explanation, ', '.join(explanations)) + if source.endswith(','): + source = source[:-1] + source += ')' + try: + self.result = frame.eval(source, **vars) + except passthroughex: + raise + except: + raise Failure(self) + if not node.is_builtin(frame) or not self.is_bool(frame): + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +class Getattr(Interpretable): + __view__ = ast.Getattr + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + source = '__exprinfo_expr.%s' % self.attrname + try: + self.result = frame.eval(source, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + self.explanation = '%s.%s' % (expr.explanation, self.attrname) + # if the attribute comes from the instance, its value is interesting + source = ('hasattr(__exprinfo_expr, "__dict__") and ' + '%r in __exprinfo_expr.__dict__' % self.attrname) + try: + from_instance = frame.is_true( + frame.eval(source, __exprinfo_expr=expr.result)) + except passthroughex: + raise + except: + from_instance = True + if from_instance: + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +# == Re-interpretation of full statements == + +class Assert(Interpretable): + __view__ = ast.Assert + + def run(self, frame): + test = Interpretable(self.test) + test.eval(frame) + # print the result as 'assert ' + self.result = test.result + self.explanation = 'assert ' + test.explanation + if not frame.is_true(test.result): + try: + raise BuiltinAssertionError + except passthroughex: + raise + except: + raise Failure(self) + +class Assign(Interpretable): + __view__ = ast.Assign + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = '... = ' + expr.explanation + # fall-back-run the rest of the assignment + ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) + mod = ast.Module(None, ast.Stmt([ass])) + mod.filename = '' + co = pycodegen.ModuleCodeGenerator(mod).getCode() + try: + frame.exec_(co, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + +class Discard(Interpretable): + __view__ = ast.Discard + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = expr.explanation + +class Stmt(Interpretable): + __view__ = ast.Stmt + + def run(self, frame): + for stmt in self.nodes: + stmt = Interpretable(stmt) + stmt.run(frame) + + +def report_failure(e): + explanation = e.node.nice_explanation() + if explanation: + explanation = ", in: " + explanation + else: + explanation = "" + sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) + +def check(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + expr = parse(s, 'eval') + assert isinstance(expr, ast.Expression) + node = Interpretable(expr.node) + try: + node.eval(frame) + except passthroughex: + raise + except Failure: + e = sys.exc_info()[1] + report_failure(e) + else: + if not frame.is_true(node.result): + sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) + + +########################################################### +# API / Entry points +# ######################################################### + +def interpret(source, frame, should_fail=False): + module = Interpretable(parse(source, 'exec').node) + #print "got module", module + if isinstance(frame, py.std.types.FrameType): + frame = py.code.Frame(frame) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + return getfailure(e) + except passthroughex: + raise + except: + import traceback + traceback.print_exc() + if should_fail: + return ("(assertion failed, but when it was re-run for " + "printing intermediate values, it did not fail. Suggestions: " + "compute assert expression before the assert or use --nomagic)") + else: + return None + +def getmsg(excinfo): + if isinstance(excinfo, tuple): + excinfo = py.code.ExceptionInfo(excinfo) + #frame, line = gettbline(tb) + #frame = py.code.Frame(frame) + #return interpret(line, frame) + + tb = excinfo.traceback[-1] + source = str(tb.statement).strip() + x = interpret(source, tb.frame, should_fail=True) + if not isinstance(x, str): + raise TypeError("interpret returned non-string %r" % (x,)) + return x + +def getfailure(e): + explanation = e.node.nice_explanation() + if str(e.value): + lines = explanation.split('\n') + lines[0] += " << %s" % (e.value,) + explanation = '\n'.join(lines) + text = "%s: %s" % (e.exc.__name__, explanation) + if text.startswith('AssertionError: assert '): + text = text[16:] + return text + +def run(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + module = Interpretable(parse(s, 'exec').node) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + report_failure(e) + + +if __name__ == '__main__': + # example: + def f(): + return 5 + def g(): + return 3 + def h(x): + return 'never' + check("f() * g() == 5") + check("not f()") + check("not (f() and g() or 0)") + check("f() == g()") + i = 4 + check("i == f()") + check("len(f()) == 0") + check("isinstance(2+3+4, float)") + + run("x = i") + check("x == 5") + + run("assert not f(), 'oops'") + run("a, b, c = 1, 2") + run("a, b, c = f()") + + check("max([f(),g()]) == 4") + check("'hello'[g()] == 'h'") + run("'guk%d' % h(f())") diff --git a/_pytest/assertion/reinterpret.py b/_pytest/assertion/reinterpret.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/reinterpret.py @@ -0,0 +1,48 @@ +import sys +import py + +BuiltinAssertionError = py.builtin.builtins.AssertionError + +class AssertionError(BuiltinAssertionError): + def __init__(self, *args): + BuiltinAssertionError.__init__(self, *args) + if args: + try: + self.msg = str(args[0]) + except py.builtin._sysex: + raise + except: + self.msg = "<[broken __repr__] %s at %0xd>" %( + args[0].__class__, id(args[0])) + else: + f = py.code.Frame(sys._getframe(1)) + try: + source = f.code.fullsource + if source is not None: + try: + source = source.getstatement(f.lineno, assertion=True) + except IndexError: + source = None + else: + source = str(source.deindent()).strip() + except py.error.ENOENT: + source = None + # this can also occur during reinterpretation, when the + # co_filename is set to "". + if source: + self.msg = reinterpret(source, f, should_fail=True) + else: + self.msg = "" + if not self.args: + self.args = (self.msg,) + +if sys.version_info > (3, 0): + AssertionError.__module__ = "builtins" + reinterpret_old = "old reinterpretation not available for py3" +else: + from _pytest.assertion.oldinterpret import interpret as reinterpret_old +if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): + from _pytest.assertion.newinterpret import interpret as reinterpret +else: + reinterpret = reinterpret_old + diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/rewrite.py @@ -0,0 +1,340 @@ +"""Rewrite assertion AST to produce nice error messages""" + +import ast +import collections +import itertools +import sys + +import py +from _pytest.assertion import util + + +def rewrite_asserts(mod): + """Rewrite the assert statements in mod.""" + AssertionRewriter().run(mod) + + +_saferepr = py.io.saferepr +from _pytest.assertion.util import format_explanation as _format_explanation + +def _format_boolop(operands, explanations, is_or): + show_explanations = [] + for operand, expl in zip(operands, explanations): + show_explanations.append(expl) + if operand == is_or: + break + return "(" + (is_or and " or " or " and ").join(show_explanations) + ")" + +def _call_reprcompare(ops, results, expls, each_obj): + for i, res, expl in zip(range(len(ops)), results, expls): + try: + done = not res + except Exception: + done = True + if done: + break + if util._reprcompare is not None: + custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1]) + if custom is not None: + return custom + return expl + + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + +binop_map = { + ast.BitOr : "|", + ast.BitXor : "^", + ast.BitAnd : "&", + ast.LShift : "<<", + ast.RShift : ">>", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + + +def set_location(node, lineno, col_offset): + """Set node location information recursively.""" + def _fix(node, lineno, col_offset): + if "lineno" in node._attributes: + node.lineno = lineno + if "col_offset" in node._attributes: + node.col_offset = col_offset + for child in ast.iter_child_nodes(node): + _fix(child, lineno, col_offset) + _fix(node, lineno, col_offset) + return node + + +class AssertionRewriter(ast.NodeVisitor): + + def run(self, mod): + """Find all assert statements in *mod* and rewrite them.""" + if not mod.body: + # Nothing to do. + return + # Insert some special imports at the top of the module but after any + # docstrings and __future__ imports. + aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"), + ast.alias("_pytest.assertion.rewrite", "@pytest_ar")] + expect_docstring = True + pos = 0 + lineno = 0 + for item in mod.body: + if (expect_docstring and isinstance(item, ast.Expr) and + isinstance(item.value, ast.Str)): + doc = item.value.s + if "PYTEST_DONT_REWRITE" in doc: + # The module has disabled assertion rewriting. + return + lineno += len(doc) - 1 + expect_docstring = False + elif (not isinstance(item, ast.ImportFrom) or item.level > 0 and + item.identifier != "__future__"): + lineno = item.lineno + break + pos += 1 + imports = [ast.Import([alias], lineno=lineno, col_offset=0) + for alias in aliases] + mod.body[pos:pos] = imports + # Collect asserts. + nodes = collections.deque([mod]) + while nodes: + node = nodes.popleft() + for name, field in ast.iter_fields(node): + if isinstance(field, list): + new = [] + for i, child in enumerate(field): + if isinstance(child, ast.Assert): + # Transform assert. + new.extend(self.visit(child)) + else: + new.append(child) + if isinstance(child, ast.AST): + nodes.append(child) + setattr(node, name, new) + elif (isinstance(field, ast.AST) and + # Don't recurse into expressions as they can't contain + # asserts. + not isinstance(field, ast.expr)): + nodes.append(field) + + def variable(self): + """Get a new variable.""" + # Use a character invalid in python identifiers to avoid clashing. + name = "@py_assert" + str(next(self.variable_counter)) + self.variables.add(name) + return name + + def assign(self, expr): + """Give *expr* a name.""" + name = self.variable() + self.statements.append(ast.Assign([ast.Name(name, ast.Store())], expr)) + return ast.Name(name, ast.Load()) + + def display(self, expr): + """Call py.io.saferepr on the expression.""" + return self.helper("saferepr", expr) + + def helper(self, name, *args): + """Call a helper in this module.""" + py_name = ast.Name("@pytest_ar", ast.Load()) + attr = ast.Attribute(py_name, "_" + name, ast.Load()) + return ast.Call(attr, list(args), [], None, None) + + def builtin(self, name): + """Return the builtin called *name*.""" + builtin_name = ast.Name("@py_builtins", ast.Load()) + return ast.Attribute(builtin_name, name, ast.Load()) + + def explanation_param(self, expr): + specifier = "py" + str(next(self.variable_counter)) + self.explanation_specifiers[specifier] = expr + return "%(" + specifier + ")s" + + def push_format_context(self): + self.explanation_specifiers = {} + self.stack.append(self.explanation_specifiers) + + def pop_format_context(self, expl_expr): + current = self.stack.pop() + if self.stack: + self.explanation_specifiers = self.stack[-1] + keys = [ast.Str(key) for key in current.keys()] + format_dict = ast.Dict(keys, list(current.values())) + form = ast.BinOp(expl_expr, ast.Mod(), format_dict) + name = "@py_format" + str(next(self.variable_counter)) + self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form)) + return ast.Name(name, ast.Load()) + + def generic_visit(self, node): + """Handle expressions we don't have custom code for.""" + assert isinstance(node, ast.expr) + res = self.assign(node) + return res, self.explanation_param(self.display(res)) + + def visit_Assert(self, assert_): + if assert_.msg: + # There's already a message. Don't mess with it. + return [assert_] + self.statements = [] + self.variables = set() + self.variable_counter = itertools.count() + self.stack = [] + self.on_failure = [] + self.push_format_context() + # Rewrite assert into a bunch of statements. + top_condition, explanation = self.visit(assert_.test) + # Create failure message. + body = self.on_failure + negation = ast.UnaryOp(ast.Not(), top_condition) + self.statements.append(ast.If(negation, body, [])) + explanation = "assert " + explanation + template = ast.Str(explanation) + msg = self.pop_format_context(template) + fmt = self.helper("format_explanation", msg) + err_name = ast.Name("AssertionError", ast.Load()) + exc = ast.Call(err_name, [fmt], [], None, None) + if sys.version_info[0] >= 3: + raise_ = ast.Raise(exc, None) + else: + raise_ = ast.Raise(exc, None, None) + body.append(raise_) + # Delete temporary variables. + names = [ast.Name(name, ast.Del()) for name in self.variables] + if names: + delete = ast.Delete(names) + self.statements.append(delete) + # Fix line numbers. + for stmt in self.statements: + set_location(stmt, assert_.lineno, assert_.col_offset) + return self.statements + + def visit_Name(self, name): + # Check if the name is local or not. + locs = ast.Call(self.builtin("locals"), [], [], None, None) + globs = ast.Call(self.builtin("globals"), [], [], None, None) + ops = [ast.In(), ast.IsNot()] + test = ast.Compare(ast.Str(name.id), ops, [locs, globs]) + expr = ast.IfExp(test, self.display(name), ast.Str(name.id)) + return name, self.explanation_param(expr) + + def visit_BoolOp(self, boolop): + operands = [] + explanations = [] + self.push_format_context() + for operand in boolop.values: + res, explanation = self.visit(operand) + operands.append(res) + explanations.append(explanation) + expls = ast.Tuple([ast.Str(expl) for expl in explanations], ast.Load()) + is_or = ast.Num(isinstance(boolop.op, ast.Or)) + expl_template = self.helper("format_boolop", + ast.Tuple(operands, ast.Load()), expls, + is_or) + expl = self.pop_format_context(expl_template) + res = self.assign(ast.BoolOp(boolop.op, operands)) + return res, self.explanation_param(expl) + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_res, operand_expl = self.visit(unary.operand) + res = self.assign(ast.UnaryOp(unary.op, operand_res)) + return res, pattern % (operand_expl,) + + def visit_BinOp(self, binop): + symbol = binop_map[binop.op.__class__] + left_expr, left_expl = self.visit(binop.left) + right_expr, right_expl = self.visit(binop.right) + explanation = "(%s %s %s)" % (left_expl, symbol, right_expl) + res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) + return res, explanation + + def visit_Call(self, call): + new_func, func_expl = self.visit(call.func) + arg_expls = [] + new_args = [] + new_kwargs = [] + new_star = new_kwarg = None + for arg in call.args: + res, expl = self.visit(arg) + new_args.append(res) + arg_expls.append(expl) + for keyword in call.keywords: + res, expl = self.visit(keyword.value) + new_kwargs.append(ast.keyword(keyword.arg, res)) + arg_expls.append(keyword.arg + "=" + expl) + if call.starargs: + new_star, expl = self.visit(call.starargs) + arg_expls.append("*" + expl) + if call.kwargs: + new_kwarg, expl = self.visit(call.kwarg) + arg_expls.append("**" + expl) + expl = "%s(%s)" % (func_expl, ', '.join(arg_expls)) + new_call = ast.Call(new_func, new_args, new_kwargs, new_star, new_kwarg) + res = self.assign(new_call) + res_expl = self.explanation_param(self.display(res)) + outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl) + return res, outer_expl + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + value, value_expl = self.visit(attr.value) + res = self.assign(ast.Attribute(value, attr.attr, ast.Load())) + res_expl = self.explanation_param(self.display(res)) + pat = "%s\n{%s = %s.%s\n}" + expl = pat % (res_expl, res_expl, value_expl, attr.attr) + return res, expl + + def visit_Compare(self, comp): + self.push_format_context() + left_res, left_expl = self.visit(comp.left) + res_variables = [self.variable() for i in range(len(comp.ops))] + load_names = [ast.Name(v, ast.Load()) for v in res_variables] + store_names = [ast.Name(v, ast.Store()) for v in res_variables] + it = zip(range(len(comp.ops)), comp.ops, comp.comparators) + expls = [] + syms = [] + results = [left_res] + for i, op, next_operand in it: + next_res, next_expl = self.visit(next_operand) + results.append(next_res) + sym = binop_map[op.__class__] + syms.append(ast.Str(sym)) + expl = "%s %s %s" % (left_expl, sym, next_expl) + expls.append(ast.Str(expl)) + res_expr = ast.Compare(left_res, [op], [next_res]) + self.statements.append(ast.Assign([store_names[i]], res_expr)) + left_res, left_expl = next_res, next_expl + # Use py.code._reprcompare if that's available. + expl_call = self.helper("call_reprcompare", + ast.Tuple(syms, ast.Load()), + ast.Tuple(load_names, ast.Load()), + ast.Tuple(expls, ast.Load()), + ast.Tuple(results, ast.Load())) + if len(comp.ops) > 1: + res = ast.BoolOp(ast.And(), load_names) + else: + res = load_names[0] + return res, self.explanation_param(self.pop_format_context(expl_call)) diff --git a/_pytest/assertion/util.py b/_pytest/assertion/util.py new file mode 100644 --- /dev/null +++ b/_pytest/assertion/util.py @@ -0,0 +1,213 @@ +"""Utilities for assertion debugging""" + +import py + + +# The _reprcompare attribute on the util module is used by the new assertion +# interpretation code and assertion rewriter to detect this plugin was +# loaded and in turn call the hooks defined here as part of the +# DebugInterpreter. +_reprcompare = None + +def format_explanation(explanation): + """This formats an explanation + + Normally all embedded newlines are escaped, however there are + three exceptions: \n{, \n} and \n~. The first two are intended + cover nested explanations, see function and attribute explanations + for examples (.visit_Call(), visit_Attribute()). The last one is + for when one explanation needs to span multiple lines, e.g. when + displaying diffs. + """ + # simplify 'assert False where False = ...' + where = 0 + while True: + start = where = explanation.find("False\n{False = ", where) + if where == -1: + break + level = 0 + for i, c in enumerate(explanation[start:]): + if c == "{": + level += 1 + elif c == "}": + level -= 1 + if not level: + break + else: + raise AssertionError("unbalanced braces: %r" % (explanation,)) + end = start + i + where = end + if explanation[end - 1] == '\n': + explanation = (explanation[:start] + explanation[start+15:end-1] + + explanation[end+1:]) + where -= 17 + raw_lines = (explanation or '').split('\n') + # escape newlines not followed by {, } and ~ + lines = [raw_lines[0]] + for l in raw_lines[1:]: + if l.startswith('{') or l.startswith('}') or l.startswith('~'): + lines.append(l) + else: + lines[-1] += '\\n' + l + + result = lines[:1] + stack = [0] + stackcnt = [0] + for line in lines[1:]: + if line.startswith('{'): + if stackcnt[-1]: + s = 'and ' + else: + s = 'where ' + stack.append(len(result)) + stackcnt[-1] += 1 + stackcnt.append(0) + result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) + elif line.startswith('}'): + assert line.startswith('}') + stack.pop() + stackcnt.pop() + result[stack[-1]] += line[1:] + else: + assert line.startswith('~') + result.append(' '*len(stack) + line[1:]) + assert len(stack) == 1 + return '\n'.join(result) + + +# Provide basestring in python3 +try: + basestring = basestring +except NameError: + basestring = str + + +def assertrepr_compare(op, left, right): + """return specialised explanations for some operators/operands""" + width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op + left_repr = py.io.saferepr(left, maxsize=int(width/2)) + right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) + summary = '%s %s %s' % (left_repr, op, right_repr) + + issequence = lambda x: isinstance(x, (list, tuple)) + istext = lambda x: isinstance(x, basestring) + isdict = lambda x: isinstance(x, dict) + isset = lambda x: isinstance(x, set) + + explanation = None + try: + if op == '==': + if istext(left) and istext(right): + explanation = _diff_text(left, right) + elif issequence(left) and issequence(right): + explanation = _compare_eq_sequence(left, right) + elif isset(left) and isset(right): + explanation = _compare_eq_set(left, right) + elif isdict(left) and isdict(right): + explanation = _diff_text(py.std.pprint.pformat(left), + py.std.pprint.pformat(right)) + elif op == 'not in': + if istext(left) and istext(right): + explanation = _notin_text(left, right) + except py.builtin._sysex: + raise + except: + excinfo = py.code.ExceptionInfo() + explanation = ['(pytest_assertion plugin: representation of ' + 'details failed. Probably an object has a faulty __repr__.)', + str(excinfo) + ] + + + if not explanation: + return None + + # Don't include pageloads of data, should be configurable + if len(''.join(explanation)) > 80*8: + explanation = ['Detailed information too verbose, truncated'] + + return [summary] + explanation + + +def _diff_text(left, right): + """Return the explanation for the diff between text + + This will skip leading and trailing characters which are + identical to keep the diff minimal. + """ + explanation = [] + i = 0 # just in case left or right has zero length + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + break + if i > 42: + i -= 10 # Provide some context + explanation = ['Skipping %s identical ' + 'leading characters in diff' % i] + left = left[i:] + right = right[i:] + if len(left) == len(right): + for i in range(len(left)): + if left[-i] != right[-i]: + break + if i > 42: + i -= 10 # Provide some context + explanation += ['Skipping %s identical ' + 'trailing characters in diff' % i] + left = left[:-i] + right = right[:-i] + explanation += [line.strip('\n') + for line in py.std.difflib.ndiff(left.splitlines(), + right.splitlines())] + return explanation + + +def _compare_eq_sequence(left, right): + explanation = [] + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + explanation += ['At index %s diff: %r != %r' % + (i, left[i], right[i])] + break + if len(left) > len(right): + explanation += ['Left contains more items, ' + 'first extra item: %s' % py.io.saferepr(left[len(right)],)] + elif len(left) < len(right): + explanation += ['Right contains more items, ' + 'first extra item: %s' % py.io.saferepr(right[len(left)],)] + return explanation # + _diff_text(py.std.pprint.pformat(left), + # py.std.pprint.pformat(right)) + + +def _compare_eq_set(left, right): + explanation = [] + diff_left = left - right + diff_right = right - left + if diff_left: + explanation.append('Extra items in the left set:') + for item in diff_left: + explanation.append(py.io.saferepr(item)) + if diff_right: + explanation.append('Extra items in the right set:') + for item in diff_right: + explanation.append(py.io.saferepr(item)) + return explanation + + +def _notin_text(term, text): + index = text.find(term) + head = text[:index] + tail = text[index+len(term):] + correct_text = head + tail + diff = _diff_text(correct_text, text) + newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] + for line in diff: + if line.startswith('Skipping'): + continue + if line.startswith('- '): + continue + if line.startswith('+ '): + newdiff.append(' ' + line[2:]) + else: + newdiff.append(line) + return newdiff diff --git a/_pytest/doctest.py b/_pytest/doctest.py --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -59,7 +59,7 @@ inner_excinfo = py.code.ExceptionInfo(excinfo.value.exc_info) lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)] - + lines += py.std.traceback.format_exception(*excinfo.value.exc_info) return ReprFailDoctest(reprlocation, lines) else: return super(DoctestItem, self).repr_failure(excinfo) diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -16,9 +16,6 @@ group.addoption('--traceconfig', action="store_true", dest="traceconfig", default=False, help="trace considerations of conftest.py files."), - group._addoption('--nomagic', - action="store_true", dest="nomagic", default=False, - help="don't reinterpret asserts, no traceback cutting. ") group.addoption('--debug', action="store_true", dest="debug", default=False, help="generate and show internal debugging information.") diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -65,7 +65,8 @@ class LogXML(object): def __init__(self, logfile, prefix): - self.logfile = logfile + logfile = os.path.expanduser(os.path.expandvars(logfile)) + self.logfile = os.path.normpath(logfile) self.prefix = prefix self.test_logs = [] self.passed = self.skipped = 0 @@ -76,7 +77,7 @@ names = report.nodeid.split("::") names[0] = names[0].replace("/", '.') names = tuple(names) - d = {'time': self._durations.pop(names, "0")} + d = {'time': self._durations.pop(report.nodeid, "0")} names = [x.replace(".py", "") for x in names if x != "()"] classnames = names[:-1] if self.prefix: @@ -170,12 +171,11 @@ self.append_skipped(report) def pytest_runtest_call(self, item, __multicall__): - names = tuple(item.listnames()) start = time.time() try: return __multicall__.execute() finally: - self._durations[names] = time.time() - start + self._durations[item.nodeid] = time.time() - start def pytest_collectreport(self, report): if not report.passed: diff --git a/_pytest/main.py b/_pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -46,23 +46,25 @@ def pytest_namespace(): - return dict(collect=dict(Item=Item, Collector=Collector, File=File)) + collect = dict(Item=Item, Collector=Collector, File=File, Session=Session) + return dict(collect=collect) def pytest_configure(config): py.test.config = config # compatibiltiy if config.option.exitfirst: config.option.maxfail = 1 -def pytest_cmdline_main(config): - """ default command line protocol for initialization, session, - running tests and reporting. """ +def wrap_session(config, doit): + """Skeleton command line program""" session = Session(config) session.exitstatus = EXIT_OK + initstate = 0 try: config.pluginmanager.do_configure(config) + initstate = 1 config.hook.pytest_sessionstart(session=session) - config.hook.pytest_collection(session=session) - config.hook.pytest_runtestloop(session=session) + initstate = 2 + doit(config, session) except pytest.UsageError: raise except KeyboardInterrupt: @@ -77,18 +79,24 @@ sys.stderr.write("mainloop: caught Spurious SystemExit!\n") if not session.exitstatus and session._testsfailed: session.exitstatus = EXIT_TESTSFAILED - config.hook.pytest_sessionfinish(session=session, - exitstatus=session.exitstatus) - config.pluginmanager.do_unconfigure(config) + if initstate >= 2: + config.hook.pytest_sessionfinish(session=session, + exitstatus=session.exitstatus) + if initstate >= 1: + config.pluginmanager.do_unconfigure(config) return session.exitstatus +def pytest_cmdline_main(config): + return wrap_session(config, _main) + +def _main(config, session): + """ default command line protocol for initialization, session, + running tests and reporting. """ + config.hook.pytest_collection(session=session) + config.hook.pytest_runtestloop(session=session) + def pytest_collection(session): - session.perform_collect() - hook = session.config.hook - hook.pytest_collection_modifyitems(session=session, - config=session.config, items=session.items) - hook.pytest_collection_finish(session=session) - return True + return session.perform_collect() def pytest_runtestloop(session): if session.config.option.collectonly: @@ -374,6 +382,16 @@ return HookProxy(fspath, self.config) def perform_collect(self, args=None, genitems=True): + hook = self.config.hook + try: + items = self._perform_collect(args, genitems) + hook.pytest_collection_modifyitems(session=self, + config=self.config, items=items) + finally: + hook.pytest_collection_finish(session=self) + return items + + def _perform_collect(self, args, genitems): if args is None: args = self.config.args self.trace("perform_collect", self, args) diff --git a/_pytest/mark.py b/_pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -153,7 +153,7 @@ def __repr__(self): return "" % ( - self._name, self.args, self.kwargs) + self.name, self.args, self.kwargs) def pytest_itemcollected(item): if not isinstance(item, pytest.Function): diff --git a/_pytest/pytester.py b/_pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -6,7 +6,7 @@ import inspect import time from fnmatch import fnmatch -from _pytest.main import Session +from _pytest.main import Session, EXIT_OK from py.builtin import print_ from _pytest.core import HookRelay @@ -292,13 +292,19 @@ assert '::' not in str(arg) p = py.path.local(arg) x = session.fspath.bestrelpath(p) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def getpathnode(self, path): - config = self.parseconfig(path) + config = self.parseconfigure(path) session = Session(config) x = session.fspath.bestrelpath(path) - return session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res def genitems(self, colitems): session = colitems[0].session @@ -312,7 +318,9 @@ config = self.parseconfigure(*args) rec = self.getreportrecorder(config) session = Session(config) + config.hook.pytest_sessionstart(session=session) session.perform_collect() + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) return session.items, rec def runitem(self, source): @@ -382,6 +390,8 @@ c.basetemp = py.path.local.make_numbered_dir(prefix="reparse", keep=0, rootdir=self.tmpdir, lock_timeout=None) c.parse(args) + c.pluginmanager.do_configure(c) + self.request.addfinalizer(lambda: c.pluginmanager.do_unconfigure(c)) return c finally: py.test.config = oldconfig diff --git a/_pytest/python.py b/_pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -226,8 +226,13 @@ def _importtestmodule(self): # we assume we are only called once per module + from _pytest import assertion + assertion.before_module_import(self) try: - mod = self.fspath.pyimport(ensuresyspath=True) + try: + mod = self.fspath.pyimport(ensuresyspath=True) + finally: + assertion.after_module_import(self) except SyntaxError: excinfo = py.code.ExceptionInfo() raise self.CollectError(excinfo.getrepr(style="short")) @@ -374,7 +379,7 @@ # test generators are seen as collectors but they also # invoke setup/teardown on popular request # (induced by the common "test_*" naming shared with normal tests) - self.config._setupstate.prepare(self) + self.session._setupstate.prepare(self) # see FunctionMixin.setup and test_setupstate_is_preserved_134 self._preservedparent = self.parent.obj l = [] @@ -721,7 +726,7 @@ def _addfinalizer(self, finalizer, scope): colitem = self._getscopeitem(scope) - self.config._setupstate.addfinalizer( + self._pyfuncitem.session._setupstate.addfinalizer( finalizer=finalizer, colitem=colitem) def __repr__(self): @@ -742,8 +747,10 @@ raise self.LookupError(msg) def showfuncargs(config): - from _pytest.main import Session - session = Session(config) + from _pytest.main import wrap_session + return wrap_session(config, _showfuncargs_main) + +def _showfuncargs_main(config, session): session.perform_collect() if session.items: plugins = session.items[0].getplugins() diff --git a/_pytest/runner.py b/_pytest/runner.py --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -14,17 +14,15 @@ # # pytest plugin hooks -# XXX move to pytest_sessionstart and fix py.test owns tests -def pytest_configure(config): - config._setupstate = SetupState() +def pytest_sessionstart(session): + session._setupstate = SetupState() def pytest_sessionfinish(session, exitstatus): - if hasattr(session.config, '_setupstate'): - hook = session.config.hook - rep = hook.pytest__teardown_final(session=session) - if rep: - hook.pytest__teardown_final_logerror(session=session, report=rep) - session.exitstatus = 1 + hook = session.config.hook + rep = hook.pytest__teardown_final(session=session) + if rep: + hook.pytest__teardown_final_logerror(session=session, report=rep) + session.exitstatus = 1 class NodeInfo: def __init__(self, location): @@ -46,16 +44,16 @@ return reports def pytest_runtest_setup(item): - item.config._setupstate.prepare(item) + item.session._setupstate.prepare(item) def pytest_runtest_call(item): item.runtest() def pytest_runtest_teardown(item): - item.config._setupstate.teardown_exact(item) + item.session._setupstate.teardown_exact(item) def pytest__teardown_final(session): - call = CallInfo(session.config._setupstate.teardown_all, when="teardown") + call = CallInfo(session._setupstate.teardown_all, when="teardown") if call.excinfo: ntraceback = call.excinfo.traceback .cut(excludepath=py._pydir) call.excinfo.traceback = ntraceback.filter() diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -569,7 +569,6 @@ # import os import time -import socket import getpass class ReallyRunFileExternal(py.test.collect.Item): diff --git a/lib-python/modified-2.7/ctypes/__init__.py b/lib-python/modified-2.7/ctypes/__init__.py --- a/lib-python/modified-2.7/ctypes/__init__.py +++ b/lib-python/modified-2.7/ctypes/__init__.py @@ -7,6 +7,7 @@ __version__ = "1.1.0" +import _ffi from _ctypes import Union, Structure, Array from _ctypes import _Pointer from _ctypes import CFuncPtr as _CFuncPtr @@ -350,7 +351,7 @@ self._FuncPtr = _FuncPtr if handle is None: - self._handle = _dlopen(self._name, mode) + self._handle = _ffi.CDLL(name) else: self._handle = handle diff --git a/lib-python/modified-2.7/ctypes/test/test_cfuncs.py b/lib-python/modified-2.7/ctypes/test/test_cfuncs.py --- a/lib-python/modified-2.7/ctypes/test/test_cfuncs.py +++ b/lib-python/modified-2.7/ctypes/test/test_cfuncs.py @@ -3,8 +3,8 @@ import unittest from ctypes import * - import _ctypes_test +from test.test_support import impl_detail class CFunctions(unittest.TestCase): _dll = CDLL(_ctypes_test.__file__) @@ -158,12 +158,14 @@ self.assertEqual(self._dll.tf_bd(0, 42.), 14.) self.assertEqual(self.S(), 42) + @impl_detail('long double not supported by PyPy', pypy=False) def test_longdouble(self): self._dll.tf_D.restype = c_longdouble self._dll.tf_D.argtypes = (c_longdouble,) self.assertEqual(self._dll.tf_D(42.), 14.) self.assertEqual(self.S(), 42) - + + @impl_detail('long double not supported by PyPy', pypy=False) def test_longdouble_plus(self): self._dll.tf_bD.restype = c_longdouble self._dll.tf_bD.argtypes = (c_byte, c_longdouble) diff --git a/lib-python/modified-2.7/ctypes/test/test_functions.py b/lib-python/modified-2.7/ctypes/test/test_functions.py --- a/lib-python/modified-2.7/ctypes/test/test_functions.py +++ b/lib-python/modified-2.7/ctypes/test/test_functions.py @@ -8,6 +8,7 @@ from ctypes import * import sys, unittest from ctypes.test import xfail +from test.test_support import impl_detail try: WINFUNCTYPE @@ -144,6 +145,7 @@ self.assertEqual(result, -21) self.assertEqual(type(result), float) + @impl_detail('long double not supported by PyPy', pypy=False) def test_longdoubleresult(self): f = dll._testfunc_D_bhilfD f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble] diff --git a/lib-python/modified-2.7/ctypes/test/test_libc.py b/lib-python/modified-2.7/ctypes/test/test_libc.py --- a/lib-python/modified-2.7/ctypes/test/test_libc.py +++ b/lib-python/modified-2.7/ctypes/test/test_libc.py @@ -26,6 +26,7 @@ self.assertEqual(chars.raw, " ,,aaaadmmmnpppsss\x00") def test_no_more_xfail(self): + import socket import ctypes.test self.assertTrue(not hasattr(ctypes.test, 'xfail'), "You should incrementally grep for '@xfail' and remove them, they are real failures") diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. @@ -873,7 +873,7 @@ # Unpickling machinery -class Unpickler: +class Unpickler(object): def __init__(self, file): """This takes a file-like object for reading a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4399,13 +4399,10 @@ self.assertTrue(l.__add__ != [5].__add__) self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') - if hasattr(l.__add__, '__self__'): - # CPython - self.assertTrue(l.__add__.__self__ is l) + self.assertTrue(l.__add__.__self__ is l) + if hasattr(l.__add__, '__objclass__'): # CPython self.assertTrue(l.__add__.__objclass__ is list) - else: - # Python implementations where [].__add__ is a normal bound method - self.assertTrue(l.__add__.im_self is l) + else: # PyPy self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/modified-2.7/test/test_extcall.py b/lib-python/modified-2.7/test/test_extcall.py --- a/lib-python/modified-2.7/test/test_extcall.py +++ b/lib-python/modified-2.7/test/test_extcall.py @@ -299,7 +299,7 @@ def f(a): return a self.assertEqual(f(**{u'a': 4}), 4) - self.assertRaises(TypeError, lambda: f(**{u'stören': 4})) + self.assertRaises(TypeError, f, **{u'stören': 4}) self.assertRaises(TypeError, f, **{u'someLongString':2}) try: f(a=4, **{u'a': 4}) diff --git a/lib-python/2.7/test/test_multibytecodec.py b/lib-python/modified-2.7/test/test_multibytecodec.py copy from lib-python/2.7/test/test_multibytecodec.py copy to lib-python/modified-2.7/test/test_multibytecodec.py --- a/lib-python/2.7/test/test_multibytecodec.py +++ b/lib-python/modified-2.7/test/test_multibytecodec.py @@ -42,7 +42,7 @@ dec = codecs.getdecoder('euc-kr') myreplace = lambda exc: (u'', sys.maxint+1) codecs.register_error('test.cjktest', myreplace) - self.assertRaises(IndexError, dec, + self.assertRaises((IndexError, OverflowError), dec, 'apple\x92ham\x93spam', 'test.cjktest') def test_codingspec(self): diff --git a/lib-python/2.7/test/test_multibytecodec_support.py b/lib-python/modified-2.7/test/test_multibytecodec_support.py copy from lib-python/2.7/test/test_multibytecodec_support.py copy to lib-python/modified-2.7/test/test_multibytecodec_support.py --- a/lib-python/2.7/test/test_multibytecodec_support.py +++ b/lib-python/modified-2.7/test/test_multibytecodec_support.py @@ -107,8 +107,8 @@ def myreplace(exc): return (u'x', sys.maxint + 1) codecs.register_error("test.cjktest", myreplace) - self.assertRaises(IndexError, self.encode, self.unmappedunicode, - 'test.cjktest') + self.assertRaises((IndexError, OverflowError), self.encode, + self.unmappedunicode, 'test.cjktest') def test_callback_None_index(self): def myreplace(exc): diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib-python/modified-2.7/test/test_support.py b/lib-python/modified-2.7/test/test_support.py --- a/lib-python/modified-2.7/test/test_support.py +++ b/lib-python/modified-2.7/test/test_support.py @@ -1066,7 +1066,7 @@ if '--pdb' in sys.argv: import pdb, traceback traceback.print_tb(exc_info[2]) - pdb.post_mortem(exc_info[2], pdb.Pdb) + pdb.post_mortem(exc_info[2]) # ---------------------------------- diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py --- a/lib_pypy/_ctypes/array.py +++ b/lib_pypy/_ctypes/array.py @@ -208,6 +208,9 @@ def _get_buffer_value(self): return self._buffer.buffer + def _to_ffi_param(self): + return self._get_buffer_value() + ARRAY_CACHE = {} def create_array_type(base, length): diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -1,5 +1,6 @@ import _rawffi +import _ffi import sys keepalive_key = str # XXX fix this when provided with test @@ -46,6 +47,15 @@ else: return self.from_param(as_parameter) + def get_ffi_param(self, value): + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() + + def get_ffi_argtype(self): + if self._ffiargtype: + return self._ffiargtype + return _shape_to_ffi_type(self._ffiargshape) + def _CData_output(self, resbuffer, base=None, index=-1): #assert isinstance(resbuffer, _rawffi.ArrayInstance) """Used when data exits ctypes and goes into user code. @@ -99,6 +109,7 @@ """ __metaclass__ = _CDataMeta _objects = None + _ffiargtype = None def __init__(self, *args, **kwds): raise TypeError("%s has no type" % (type(self),)) @@ -119,11 +130,20 @@ def _get_buffer_value(self): return self._buffer[0] + def _to_ffi_param(self): + if self.__class__._is_pointer_like(): + return self._get_buffer_value() + else: + return self.value + def __buffer__(self): return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -150,7 +170,7 @@ return pointer(cdata) def cdata_from_address(self, address): - # fix the address, in case it's unsigned + # fix the address: turn it into as unsigned, in case it's a negative number address = address & (sys.maxint * 2 + 1) instance = self.__new__(self) lgt = getattr(self, '_length_', 1) @@ -159,3 +179,50 @@ def addressof(tp): return tp._buffer.buffer + + +# ---------------------------------------------------------------------- + +def is_struct_shape(shape): + # see the corresponding code to set the shape in + # _ctypes.structure._set_shape + return (isinstance(shape, tuple) and + len(shape) == 2 and + isinstance(shape[0], _rawffi.Structure) and + shape[1] == 1) + +def _shape_to_ffi_type(shape): + try: + return _shape_to_ffi_type.typemap[shape] + except KeyError: + pass + if is_struct_shape(shape): + return shape[0].get_ffi_type() + # + assert False, 'unknown shape %s' % (shape,) + + +_shape_to_ffi_type.typemap = { + 'c' : _ffi.types.char, + 'b' : _ffi.types.sbyte, + 'B' : _ffi.types.ubyte, + 'h' : _ffi.types.sshort, + 'u' : _ffi.types.unichar, + 'H' : _ffi.types.ushort, + 'i' : _ffi.types.sint, + 'I' : _ffi.types.uint, + 'l' : _ffi.types.slong, + 'L' : _ffi.types.ulong, + 'q' : _ffi.types.slonglong, + 'Q' : _ffi.types.ulonglong, + 'f' : _ffi.types.float, + 'd' : _ffi.types.double, + 's' : _ffi.types.void_p, + 'P' : _ffi.types.void_p, + 'z' : _ffi.types.void_p, + 'O' : _ffi.types.void_p, + 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, + } + diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -1,12 +1,15 @@ + +from _ctypes.basics import _CData, _CDataMeta, cdata_from_address +from _ctypes.primitive import SimpleType, _SimpleCData +from _ctypes.basics import ArgumentError, keepalive_key +from _ctypes.basics import is_struct_shape +from _ctypes.builtin import set_errno, set_last_error import _rawffi +import _ffi import sys import traceback import warnings -from _ctypes.basics import ArgumentError, keepalive_key -from _ctypes.basics import _CData, _CDataMeta, cdata_from_address -from _ctypes.builtin import set_errno, set_last_error -from _ctypes.primitive import SimpleType # XXX this file needs huge refactoring I fear @@ -24,6 +27,7 @@ WIN64 = sys.platform == 'win32' and sys.maxint == 2**63 - 1 + def get_com_error(errcode, riid, pIunk): "Win32 specific: build a COM Error exception" # XXX need C support code @@ -36,6 +40,7 @@ funcptr.restype = int return funcptr(*args) + class CFuncPtrType(_CDataMeta): # XXX write down here defaults and such things @@ -50,6 +55,7 @@ from_address = cdata_from_address + class CFuncPtr(_CData): __metaclass__ = CFuncPtrType @@ -65,10 +71,12 @@ callable = None _ptr = None _buffer = None + _address = None # win32 COM properties _paramflags = None _com_index = None _com_iid = None + _is_fastpath = False __restype_set = False @@ -85,8 +93,11 @@ raise TypeError( "item %d in _argtypes_ has no from_param method" % ( i + 1,)) - self._argtypes_ = argtypes - + # + if all([hasattr(argtype, '_ffiargshape') for argtype in argtypes]): + fastpath_cls = make_fastpath_subclass(self.__class__) + fastpath_cls.enable_fastpath_maybe(self) + self._argtypes_ = list(argtypes) argtypes = property(_getargtypes, _setargtypes) def _getparamflags(self): @@ -133,6 +144,7 @@ paramflags = property(_getparamflags, _setparamflags) + def _getrestype(self): return self._restype_ @@ -146,27 +158,24 @@ callable(restype)): raise TypeError("restype must be a type, a callable, or None") self._restype_ = restype - + def _delrestype(self): self._ptr = None del self._restype_ - + restype = property(_getrestype, _setrestype, _delrestype) def _geterrcheck(self): return getattr(self, '_errcheck_', None) - def _seterrcheck(self, errcheck): if not callable(errcheck): raise TypeError("The errcheck attribute must be callable") self._errcheck_ = errcheck - def _delerrcheck(self): try: del self._errcheck_ except AttributeError: pass - errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck) def _ffishapes(self, args, restype): @@ -181,6 +190,14 @@ restype = 'O' # void return argtypes, restype + def _set_address(self, address): + if not self._buffer: + self._buffer = _rawffi.Array('P')(1) + self._buffer[0] = address + + def _get_address(self): + return self._buffer[0] + def __init__(self, *args): self.name = None self._objects = {keepalive_key(0):self} @@ -188,7 +205,7 @@ # Empty function object -- this is needed for casts if not args: - self._buffer = _rawffi.Array('P')(1) + self._set_address(0) return argsl = list(args) @@ -196,20 +213,24 @@ # Direct construction from raw address if isinstance(argument, (int, long)) and not argsl: - ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) - self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires, self._flags_) - self._buffer = self._ptr.byptr() + self._set_address(argument) + restype = self._restype_ + if restype is None: + import ctypes + restype = ctypes.c_int + self._ptr = self._getfuncptr_fromaddress(self._argtypes_, restype) return - # A callback into Python + + # A callback into python if callable(argument) and not argsl: self.callable = argument ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) if self._restype_ is None: ffires = None - self._ptr = _rawffi.CallbackPtr(self._wrap_callable( - argument, self.argtypes - ), ffiargs, ffires, self._flags_) + self._ptr = _rawffi.CallbackPtr(self._wrap_callable(argument, + self.argtypes), + ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() return @@ -218,7 +239,7 @@ import ctypes self.name, dll = argument if isinstance(dll, str): - self.dll = ctypes.CDLL(dll) + self.dll = ctypes.CDLL(self.dll) else: self.dll = dll if argsl: @@ -227,7 +248,7 @@ raise TypeError("Unknown constructor %s" % (args,)) # We need to check dll anyway ptr = self._getfuncptr([], ctypes.c_int) - self._buffer = ptr.byptr() + self._set_address(ptr.getaddr()) return # A COM function call, by index @@ -270,15 +291,15 @@ # than the length of the argtypes tuple. args = args[:len(self._argtypes_)] else: - plural = len(argtypes) > 1 and "s" or "" + plural = len(self._argtypes_) > 1 and "s" or "" raise TypeError( "This function takes %d argument%s (%s given)" - % (len(argtypes), plural, len(args))) + % (len(self._argtypes_), plural, len(args))) # check that arguments are convertible ## XXX Not as long as ctypes.cast is a callback function with ## py_object arguments... - ## self._convert_args(argtypes, args, {}) + ## self._convert_args(self._argtypes_, args, {}) try: res = self.callable(*args) @@ -306,83 +327,75 @@ raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) - args, outargs = self._convert_args(argtypes, args, kwargs) - argtypes = [type(arg) for arg in args] + funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) + result = self._call_funcptr(funcptr, *newargs) + result = self._do_errcheck(result, args) - restype = self._restype_ - funcptr = self._getfuncptr(argtypes, restype, thisarg) + if not outargs: + return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + + if len(outargs) == 1: + return outargs[0] + return tuple(outargs) + + def _call_funcptr(self, funcptr, *newargs): + if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: set_errno(_rawffi.get_errno()) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) try: - resbuffer = funcptr(*[arg._get_buffer_for_param()._buffer - for arg in args]) + result = funcptr(*newargs) finally: if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: set_errno(_rawffi.get_errno()) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) + # + return self._build_result(self._restype_, result, newargs) - result = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, args[0]) - else: - result = int(resbuffer[0]) - elif restype is not None: - checker = getattr(self.restype, '_check_retval_', None) - if checker: - val = restype(resbuffer[0]) - # the original ctypes seems to make the distinction between - # classes defining a new type, and their subclasses - if '_type_' in restype.__dict__: - val = val.value - result = checker(val) - elif not isinstance(restype, _CDataMeta): - result = restype(resbuffer[0]) - else: - result = restype._CData_retval(resbuffer) - + def _do_errcheck(self, result, args): # The 'errcheck' protocol if self._errcheck_: v = self._errcheck_(result, self, args) # If the errcheck funtion failed, let it throw - # If the errcheck function returned callargs unchanged, + # If the errcheck function returned newargs unchanged, # continue normal processing. # If the errcheck function returned something else, # use that as result. if v is not args: - result = v + return v + return result - if not outargs: - return result - - if len(outargs) == 1: - return outargs[0] - - return tuple(outargs) + def _getfuncptr_fromaddress(self, argtypes, restype): + address = self._get_address() + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires) def _getfuncptr(self, argtypes, restype, thisarg=None): - if self._ptr is not None and argtypes is self._argtypes_: + if self._ptr is not None and (argtypes is self._argtypes_ or argtypes == self._argtypes_): return self._ptr if restype is None or not isinstance(restype, _CDataMeta): import ctypes restype = ctypes.c_int - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape if self._buffer is not None: - ptr = _rawffi.FuncPtr(self._buffer[0], argshapes, resshape, - self._flags_) - if argtypes is self._argtypes_: + ptr = self._getfuncptr_fromaddress(argtypes, restype) + if argtypes == self._argtypes_: self._ptr = ptr return ptr @@ -390,15 +403,21 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) - + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) + cdll = self.dll._handle try: - return cdll.ptr(self.name, argshapes, resshape, self._flags_) + ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes] + ffi_restype = restype.get_ffi_argtype() + self._ptr = cdll.getfunc(self.name, ffi_argtypes, ffi_restype) + return self._ptr except AttributeError: if self._flags_ & _rawffi.FUNCFLAG_CDECL: raise + # Win64 has no stdcall calling conv, so it should also not have the # name mangling of it. if WIN64: @@ -409,23 +428,32 @@ for i in range(33): mangled_name = "_%s@%d" % (self.name, i*4) try: - return cdll.ptr(mangled_name, argshapes, resshape, - self._flags_) + return cdll.getfunc(mangled_name, + ffi_argtypes, ffi_restype, + # XXX self._flags_ + ) except AttributeError: pass raise - @staticmethod - def _conv_param(argtype, arg): - from ctypes import c_char_p, c_wchar_p, c_void_p, c_int + @classmethod + def _conv_param(cls, argtype, arg): + if isinstance(argtype, _CDataMeta): + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype + if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - # The usual case when argtype is defined - cobj = arg - elif isinstance(arg, str): + return arg, arg._to_ffi_param(), type(arg) + # + # non-usual case: we do the import here to save a lot of code in the + # jit trace of the normal case + from ctypes import c_char_p, c_wchar_p, c_void_p, c_int + # + if isinstance(arg, str): cobj = c_char_p(arg) elif isinstance(arg, unicode): cobj = c_wchar_p(arg) @@ -435,18 +463,17 @@ cobj = c_int(arg) else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj + + return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): - callargs = [] + newargs = [] outargs = [] + keepalives = [] + newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -470,8 +497,10 @@ val = defval if val is marker: val = 0 - wrapped = self._conv_param(argtype, val) - callargs.append(wrapped) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): if inargs_idx < total: val = args[inargs_idx] @@ -485,38 +514,107 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - wrapped = self._conv_param(argtype, val) - callargs.append(wrapped) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - wrapped = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) - wrapped = ctypes.byref(val) - callargs.append(wrapped) + keepalive = None + newarg = ctypes.byref(val) + newargtype = type(newarg) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - wrapped = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) - callargs.append(wrapped) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) inargs_idx += 1 - if len(callargs) < total: - extra = args[len(callargs):] + if len(newargs) < len(args): + extra = args[len(newargs):] for i, arg in enumerate(extra): try: - wrapped = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) - callargs.append(wrapped) + keepalives.append(keepalive) + newargs.append(newarg) + newargtypes.append(newargtype) + return keepalives, newargs, newargtypes, outargs - return callargs, outargs + + def _wrap_result(self, restype, result): + """ + Convert from low-level repr of the result to the high-level python + one. + """ + # hack for performance: if restype is a "simple" primitive type, don't + # allocate the buffer because it's going to be thrown away immediately + if restype.__bases__[0] is _SimpleCData and not restype._is_pointer_like(): + return result + # + shape = restype._ffishape + if is_struct_shape(shape): + buf = result + else: + buf = _rawffi.Array(shape)(1, autofree=True) + buf[0] = result + retval = restype._CData_retval(buf) + return retval + + def _build_result(self, restype, result, argsandobjs): + """Build the function result: + If there is no OUT parameter, return the actual function result + If there is one OUT parameter, return it + If there are many OUT parameters, return a tuple""" + + # XXX: note for the future: the function used to take a "resbuffer", + # i.e. an array of ints. Now it takes a result, which is already a + # python object. All places that do "resbuffer[0]" should check that + # result is actually an int and just use it. + # + # Also, argsandobjs used to be "args" in __call__, now it's "newargs" + # (i.e., the already unwrapped objects). It's used only when we have a + # PARAMFLAG_FOUT and it's probably wrong, I'll fix it when I find a + # failing test + + retval = None + + if restype is not None: + checker = getattr(self.restype, '_check_retval_', None) + if checker: + val = restype(result) + # the original ctypes seems to make the distinction between + # classes defining a new type, and their subclasses + if '_type_' in restype.__dict__: + val = val.value + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) + elif not isinstance(restype, _CDataMeta): + retval = restype(result) + else: + retval = self._wrap_result(restype, result) + + return retval def __nonzero__(self): return self._com_index is not None or bool(self._buffer[0]) @@ -532,3 +630,61 @@ self._ptr.free() self._ptr = None self._needs_free = False + + +def make_fastpath_subclass(CFuncPtr): + if CFuncPtr._is_fastpath: + return CFuncPtr + # + try: + return make_fastpath_subclass.memo[CFuncPtr] + except KeyError: + pass + + class CFuncPtrFast(CFuncPtr): + + _is_fastpath = True + _slowpath_allowed = True # set to False by tests + + @classmethod + def enable_fastpath_maybe(cls, obj): + if (obj.callable is None and + obj._com_index is None): + obj.__class__ = cls + + def __rollback(self): + assert self._slowpath_allowed + self.__class__ = CFuncPtr + + # disable the fast path if we reset argtypes + def _setargtypes(self, argtypes): + self.__rollback() + self._setargtypes(argtypes) + argtypes = property(CFuncPtr._getargtypes, _setargtypes) + + def _setcallable(self, func): + self.__rollback() + self.callable = func + callable = property(lambda x: None, _setcallable) + + def _setcom_index(self, idx): + self.__rollback() + self._com_index = idx + _com_index = property(lambda x: None, _setcom_index) + + def __call__(self, *args): + thisarg = None + argtypes = self._argtypes_ + restype = self._restype_ + funcptr = self._getfuncptr(argtypes, restype, thisarg) + try: + result = self._call_funcptr(funcptr, *args) + result = self._do_errcheck(result, args) + except (TypeError, ArgumentError): # XXX, should be FFITypeError + assert self._slowpath_allowed + return CFuncPtr.__call__(self, *args) + return result + + make_fastpath_subclass.memo[CFuncPtr] = CFuncPtrFast + return CFuncPtrFast +make_fastpath_subclass.memo = {} diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py --- a/lib_pypy/_ctypes/pointer.py +++ b/lib_pypy/_ctypes/pointer.py @@ -1,6 +1,7 @@ import _rawffi -from _ctypes.basics import _CData, _CDataMeta, cdata_from_address +import _ffi +from _ctypes.basics import _CData, _CDataMeta, cdata_from_address, ArgumentError from _ctypes.basics import keepalive_key, store_reference, ensure_objects from _ctypes.basics import sizeof, byref from _ctypes.array import Array, array_get_slice_params, array_slice_getitem,\ @@ -19,7 +20,7 @@ length = 1, _ffiargshape = 'P', _ffishape = 'P', - _fficompositesize = None + _fficompositesize = None, ) # XXX check if typedict['_type_'] is any sane # XXX remember about paramfunc @@ -66,6 +67,7 @@ self._ffiarray = ffiarray self.__init__ = __init__ self._type_ = TP + self._ffiargtype = _ffi.types.Pointer(TP.get_ffi_argtype()) from_address = cdata_from_address @@ -114,6 +116,17 @@ contents = property(getcontents, setcontents) + def _as_ffi_pointer_(self, ffitype): + return as_ffi_pointer(self, ffitype) + +def as_ffi_pointer(value, ffitype): + my_ffitype = type(value).get_ffi_argtype() + # for now, we always allow types.pointer, else a lot of tests + # break. We need to rethink how pointers are represented, though + if my_ffitype is not ffitype and ffitype is not _ffi.types.void_p: + raise ArgumentError, "expected %s instance, got %s" % (type(value), ffitype) + return value._get_buffer_value() + def _cast_addr(obj, _, tp): if not (isinstance(tp, _CDataMeta) and tp._is_pointer_like()): raise TypeError("cast() argument 2 must be a pointer type, not %s" diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -1,3 +1,4 @@ +import _ffi import _rawffi import weakref import sys @@ -8,7 +9,7 @@ CArgObject from _ctypes.builtin import ConvMode from _ctypes.array import Array -from _ctypes.pointer import _Pointer +from _ctypes.pointer import _Pointer, as_ffi_pointer class NULL(object): pass @@ -140,6 +141,8 @@ value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) + result._ffiargtype = _ffi.types.Pointer(_ffi.types.char) + elif tp == 'Z': # c_wchar_p def _getvalue(self): @@ -162,6 +165,7 @@ value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) + result._ffiargtype = _ffi.types.Pointer(_ffi.types.unichar) elif tp == 'P': # c_void_p @@ -212,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: @@ -248,6 +257,12 @@ self._buffer[0] = 0 # VARIANT_FALSE result.value = property(_getvalue, _setvalue) + # make pointer-types compatible with the _ffi fast path + if result._is_pointer_like(): + def _as_ffi_pointer_(self, ffitype): + return as_ffi_pointer(self, ffitype) + result._as_ffi_pointer_ = _as_ffi_pointer_ + return result from_address = cdata_from_address diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -240,6 +240,9 @@ def _get_buffer_value(self): return self._buffer.buffer + def _to_ffi_param(self): + return self._buffer + class StructureMeta(StructOrUnionMeta): _is_union = False diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -275,7 +275,8 @@ return unicode(x, 'utf-8') class Connection(object): - def __init__(self, database, isolation_level="", detect_types=0, timeout=None, cached_statements=None, factory=None): + def __init__(self, database, timeout=5.0, detect_types=0, isolation_level="", + check_same_thread=True, factory=None, cached_statements=100): self.db = c_void_p() if sqlite.sqlite3_open(database, byref(self.db)) != SQLITE_OK: raise OperationalError("Could not open database") @@ -308,7 +309,8 @@ self._aggregates = {} self.aggregate_instances = {} self._collations = {} - self.thread_ident = thread_get_ident() + if check_same_thread: + self.thread_ident = thread_get_ident() def _get_exception(self, error_code = None): if error_code is None: diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -27,9 +27,9 @@ PythonPickler.__init__(self, self.__f, args[0], **kw) else: PythonPickler.__init__(self, *args, **kw) - + def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): diff --git a/lib_pypy/ctypes_support.py b/lib_pypy/ctypes_support.py --- a/lib_pypy/ctypes_support.py +++ b/lib_pypy/ctypes_support.py @@ -10,8 +10,8 @@ # __________ the standard C library __________ if sys.platform == 'win32': - import _rawffi - standard_c_lib = ctypes.CDLL('msvcrt', handle=_rawffi.get_libc()) + import _ffi + standard_c_lib = ctypes.CDLL('msvcrt', handle=_ffi.get_libc()) else: standard_c_lib = ctypes.CDLL(ctypes.util.find_library('c')) diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py --- a/lib_pypy/datetime.py +++ b/lib_pypy/datetime.py @@ -1422,12 +1422,17 @@ converter = _time.localtime else: converter = _time.gmtime - if 1 - (t % 1.0) < 0.000001: - t = float(int(t)) + 1 - if t < 0: - t -= 1 + if t < 0.0: + us = int(round(((-t) % 1.0) * 1000000)) + if us > 0: + us = 1000000 - us + t -= 1.0 + else: + us = int(round((t % 1.0) * 1000000)) + if us == 1000000: + us = 0 + t += 1.0 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) - us = int((t % 1.0) * 1000000) ss = min(ss, 59) # clamp out leap seconds if the platform has them result = cls(y, m, d, hh, mm, ss, us, tz) if tz is not None: diff --git a/lib_pypy/msvcrt.py b/lib_pypy/msvcrt.py --- a/lib_pypy/msvcrt.py +++ b/lib_pypy/msvcrt.py @@ -46,4 +46,42 @@ e = get_errno() raise IOError(e, errno.errorcode[e]) +# Console I/O routines + +kbhit = _c._kbhit +kbhit.argtypes = [] +kbhit.restype = ctypes.c_int + +getch = _c._getch +getch.argtypes = [] +getch.restype = ctypes.c_char + +getwch = _c._getwch +getwch.argtypes = [] +getwch.restype = ctypes.c_wchar + +getche = _c._getche +getche.argtypes = [] +getche.restype = ctypes.c_char + +getwche = _c._getwche +getwche.argtypes = [] +getwche.restype = ctypes.c_wchar + +putch = _c._putch +putch.argtypes = [ctypes.c_char] +putch.restype = None + +putwch = _c._putwch +putwch.argtypes = [ctypes.c_wchar] +putwch.restype = None + +ungetch = _c._ungetch +ungetch.argtypes = [ctypes.c_char] +ungetch.restype = None + +ungetwch = _c._ungetwch +ungetwch.argtypes = [ctypes.c_wchar] +ungetwch.restype = None + del ctypes diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/lib_pypy/pypy_test/test_datetime.py b/lib_pypy/pypy_test/test_datetime.py --- a/lib_pypy/pypy_test/test_datetime.py +++ b/lib_pypy/pypy_test/test_datetime.py @@ -32,4 +32,28 @@ assert datetime.datetime.utcfromtimestamp(a).microsecond == 0 assert datetime.datetime.utcfromtimestamp(a).second == 1 - +def test_more_datetime_rounding(): + # this test verified on top of CPython 2.7 (using a plain + # "import datetime" above) + expected_results = { + -1000.0: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.9999996: 'datetime.datetime(1970, 1, 1, 0, 43, 20)', + -999.4: 'datetime.datetime(1970, 1, 1, 0, 43, 20, 600000)', + -999.0000004: 'datetime.datetime(1970, 1, 1, 0, 43, 21)', + -1.0: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.9999996: 'datetime.datetime(1970, 1, 1, 0, 59, 59)', + -0.4: 'datetime.datetime(1970, 1, 1, 0, 59, 59, 600000)', + -0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.0000004: 'datetime.datetime(1970, 1, 1, 1, 0)', + 0.4: 'datetime.datetime(1970, 1, 1, 1, 0, 0, 400000)', + 0.9999996: 'datetime.datetime(1970, 1, 1, 1, 0, 1)', + 1000.0: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.0000004: 'datetime.datetime(1970, 1, 1, 1, 16, 40)', + 1000.4: 'datetime.datetime(1970, 1, 1, 1, 16, 40, 400000)', + 1000.9999996: 'datetime.datetime(1970, 1, 1, 1, 16, 41)', + 1293843661.191: 'datetime.datetime(2011, 1, 1, 2, 1, 1, 191000)', + } + for t in sorted(expected_results): + dt = datetime.datetime.fromtimestamp(t) + assert repr(dt) == expected_results[t] diff --git a/lib_pypy/resource.py b/lib_pypy/resource.py --- a/lib_pypy/resource.py +++ b/lib_pypy/resource.py @@ -7,7 +7,7 @@ from ctypes_support import standard_c_lib as libc from ctypes_support import get_errno -from ctypes import Structure, c_int, c_long, byref, sizeof +from ctypes import Structure, c_int, c_long, byref, sizeof, POINTER from errno import EINVAL, EPERM import _structseq @@ -25,6 +25,8 @@ _setrlimit = libc.setrlimit try: _getpagesize = libc.getpagesize + _getpagesize.argtypes = () + _getpagesize.restype = c_int except AttributeError: from os import sysconf _getpagesize = None @@ -61,6 +63,10 @@ ("ru_nivcsw", c_long), ) +_getrusage.argtypes = (c_int, POINTER(_struct_rusage)) +_getrusage.restype = c_int + + class struct_rusage: __metaclass__ = _structseq.structseqtype @@ -94,6 +100,12 @@ ("rlim_max", rlim_t), ) +_getrlimit.argtypes = (c_int, POINTER(rlimit)) +_getrlimit.restype = c_int +_setrlimit.argtypes = (c_int, POINTER(rlimit)) +_setrlimit.restype = c_int + + @builtinify def getrusage(who): ru = _struct_rusage() diff --git a/py/__init__.py b/py/__init__.py --- a/py/__init__.py +++ b/py/__init__.py @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2010 """ -__version__ = '1.4.3' +__version__ = '1.4.4.dev1' from py import _apipkg @@ -70,10 +70,6 @@ 'getrawcode' : '._code.code:getrawcode', 'patch_builtins' : '._code.code:patch_builtins', 'unpatch_builtins' : '._code.code:unpatch_builtins', - '_AssertionError' : '._code.assertion:AssertionError', - '_reinterpret_old' : '._code.assertion:reinterpret_old', - '_reinterpret' : '._code.assertion:reinterpret', - '_reprcompare' : '._code.assertion:_reprcompare', }, # backports and additions of builtins diff --git a/py/_code/_assertionnew.py b/py/_code/_assertionnew.py deleted file mode 100644 --- a/py/_code/_assertionnew.py +++ /dev/null @@ -1,339 +0,0 @@ -""" -Find intermediate evalutation results in assert statements through builtin AST. -This should replace _assertionold.py eventually. -""" - -import sys -import ast - -import py -from py._code.assertion import _format_explanation, BuiltinAssertionError - - -if sys.platform.startswith("java") and sys.version_info < (2, 5, 2): - # See http://bugs.jython.org/issue1497 - _exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict", - "ListComp", "GeneratorExp", "Yield", "Compare", "Call", - "Repr", "Num", "Str", "Attribute", "Subscript", "Name", - "List", "Tuple") - _stmts = ("FunctionDef", "ClassDef", "Return", "Delete", "Assign", - "AugAssign", "Print", "For", "While", "If", "With", "Raise", - "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom", - "Exec", "Global", "Expr", "Pass", "Break", "Continue") - _expr_nodes = set(getattr(ast, name) for name in _exprs) - _stmt_nodes = set(getattr(ast, name) for name in _stmts) - def _is_ast_expr(node): - return node.__class__ in _expr_nodes - def _is_ast_stmt(node): - return node.__class__ in _stmt_nodes -else: - def _is_ast_expr(node): - return isinstance(node, ast.expr) - def _is_ast_stmt(node): - return isinstance(node, ast.stmt) - - -class Failure(Exception): - """Error found while interpreting AST.""" - - def __init__(self, explanation=""): - self.cause = sys.exc_info() - self.explanation = explanation - - -def interpret(source, frame, should_fail=False): - mod = ast.parse(source) - visitor = DebugInterpreter(frame) - try: - visitor.visit(mod) - except Failure: - failure = sys.exc_info()[1] - return getfailure(failure) - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --no-assert)") - -def run(offending_line, frame=None): - if frame is None: - frame = py.code.Frame(sys._getframe(1)) - return interpret(offending_line, frame) - -def getfailure(failure): - explanation = _format_explanation(failure.explanation) - value = failure.cause[1] - if str(value): - lines = explanation.splitlines() - if not lines: - lines.append("") - lines[0] += " << %s" % (value,) - explanation = "\n".join(lines) - text = "%s: %s" % (failure.cause[0].__name__, explanation) - if text.startswith("AssertionError: assert "): - text = text[16:] - return text - - -operator_map = { - ast.BitOr : "|", - ast.BitXor : "^", - ast.BitAnd : "&", - ast.LShift : "<<", - ast.RShift : ">>", - ast.Add : "+", - ast.Sub : "-", - ast.Mult : "*", - ast.Div : "/", - ast.FloorDiv : "//", - ast.Mod : "%", - ast.Eq : "==", - ast.NotEq : "!=", - ast.Lt : "<", - ast.LtE : "<=", - ast.Gt : ">", - ast.GtE : ">=", - ast.Pow : "**", - ast.Is : "is", - ast.IsNot : "is not", - ast.In : "in", - ast.NotIn : "not in" -} - -unary_map = { - ast.Not : "not %s", - ast.Invert : "~%s", - ast.USub : "-%s", - ast.UAdd : "+%s" -} - - -class DebugInterpreter(ast.NodeVisitor): - """Interpret AST nodes to gleam useful debugging information. """ - - def __init__(self, frame): - self.frame = frame - - def generic_visit(self, node): - # Fallback when we don't have a special implementation. - if _is_ast_expr(node): - mod = ast.Expression(node) - co = self._compile(mod) - try: - result = self.frame.eval(co) - except Exception: - raise Failure() - explanation = self.frame.repr(result) - return explanation, result - elif _is_ast_stmt(node): - mod = ast.Module([node]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co) - except Exception: - raise Failure() - return None, None - else: - raise AssertionError("can't handle %s" %(node,)) - - def _compile(self, source, mode="eval"): - return compile(source, "", mode) - - def visit_Expr(self, expr): - return self.visit(expr.value) - - def visit_Module(self, mod): - for stmt in mod.body: - self.visit(stmt) - - def visit_Name(self, name): - explanation, result = self.generic_visit(name) - # See if the name is local. - source = "%r in locals() is not globals()" % (name.id,) - co = self._compile(source) - try: - local = self.frame.eval(co) - except Exception: - # have to assume it isn't - local = False - if not local: - return name.id, result - return explanation, result - - def visit_Compare(self, comp): - left = comp.left - left_explanation, left_result = self.visit(left) - for op, next_op in zip(comp.ops, comp.comparators): - next_explanation, next_result = self.visit(next_op) - op_symbol = operator_map[op.__class__] - explanation = "%s %s %s" % (left_explanation, op_symbol, - next_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=next_result) - except Exception: - raise Failure(explanation) - try: - if not result: - break - except KeyboardInterrupt: - raise - except: - break - left_explanation, left_result = next_explanation, next_result - - rcomp = py.code._reprcompare - if rcomp: - res = rcomp(op_symbol, left_result, next_result) - if res: - explanation = res - return explanation, result - - def visit_BoolOp(self, boolop): - is_or = isinstance(boolop.op, ast.Or) - explanations = [] - for operand in boolop.values: - explanation, result = self.visit(operand) - explanations.append(explanation) - if result == is_or: - break - name = is_or and " or " or " and " - explanation = "(" + name.join(explanations) + ")" - return explanation, result - - def visit_UnaryOp(self, unary): - pattern = unary_map[unary.op.__class__] - operand_explanation, operand_result = self.visit(unary.operand) - explanation = pattern % (operand_explanation,) - co = self._compile(pattern % ("__exprinfo_expr",)) - try: - result = self.frame.eval(co, __exprinfo_expr=operand_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_BinOp(self, binop): - left_explanation, left_result = self.visit(binop.left) - right_explanation, right_result = self.visit(binop.right) - symbol = operator_map[binop.op.__class__] - explanation = "(%s %s %s)" % (left_explanation, symbol, - right_explanation) - source = "__exprinfo_left %s __exprinfo_right" % (symbol,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_left=left_result, - __exprinfo_right=right_result) - except Exception: - raise Failure(explanation) - return explanation, result - - def visit_Call(self, call): - func_explanation, func = self.visit(call.func) - arg_explanations = [] - ns = {"__exprinfo_func" : func} - arguments = [] - for arg in call.args: - arg_explanation, arg_result = self.visit(arg) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - arguments.append(arg_name) - arg_explanations.append(arg_explanation) - for keyword in call.keywords: - arg_explanation, arg_result = self.visit(keyword.value) - arg_name = "__exprinfo_%s" % (len(ns),) - ns[arg_name] = arg_result - keyword_source = "%s=%%s" % (keyword.arg) - arguments.append(keyword_source % (arg_name,)) - arg_explanations.append(keyword_source % (arg_explanation,)) - if call.starargs: - arg_explanation, arg_result = self.visit(call.starargs) - arg_name = "__exprinfo_star" - ns[arg_name] = arg_result - arguments.append("*%s" % (arg_name,)) - arg_explanations.append("*%s" % (arg_explanation,)) - if call.kwargs: - arg_explanation, arg_result = self.visit(call.kwargs) - arg_name = "__exprinfo_kwds" - ns[arg_name] = arg_result - arguments.append("**%s" % (arg_name,)) - arg_explanations.append("**%s" % (arg_explanation,)) - args_explained = ", ".join(arg_explanations) - explanation = "%s(%s)" % (func_explanation, args_explained) - args = ", ".join(arguments) - source = "__exprinfo_func(%s)" % (args,) - co = self._compile(source) - try: - result = self.frame.eval(co, **ns) - except Exception: - raise Failure(explanation) - pattern = "%s\n{%s = %s\n}" - rep = self.frame.repr(result) - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def _is_builtin_name(self, name): - pattern = "%r not in globals() and %r not in locals()" - source = pattern % (name.id, name.id) - co = self._compile(source) - try: - return self.frame.eval(co) - except Exception: - return False - - def visit_Attribute(self, attr): - if not isinstance(attr.ctx, ast.Load): - return self.generic_visit(attr) - source_explanation, source_result = self.visit(attr.value) - explanation = "%s.%s" % (source_explanation, attr.attr) - source = "__exprinfo_expr.%s" % (attr.attr,) - co = self._compile(source) - try: - result = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - raise Failure(explanation) - explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), - self.frame.repr(result), - source_explanation, attr.attr) - # Check if the attr is from an instance. - source = "%r in getattr(__exprinfo_expr, '__dict__', {})" - source = source % (attr.attr,) - co = self._compile(source) - try: - from_instance = self.frame.eval(co, __exprinfo_expr=source_result) - except Exception: - from_instance = True - if from_instance: - rep = self.frame.repr(result) - pattern = "%s\n{%s = %s\n}" - explanation = pattern % (rep, rep, explanation) - return explanation, result - - def visit_Assert(self, assrt): - test_explanation, test_result = self.visit(assrt.test) - if test_explanation.startswith("False\n{False =") and \ - test_explanation.endswith("\n"): - test_explanation = test_explanation[15:-2] - explanation = "assert %s" % (test_explanation,) - if not test_result: - try: - raise BuiltinAssertionError - except Exception: - raise Failure(explanation) - return explanation, test_result - - def visit_Assign(self, assign): - value_explanation, value_result = self.visit(assign.value) - explanation = "... = %s" % (value_explanation,) - name = ast.Name("__exprinfo_expr", ast.Load(), - lineno=assign.value.lineno, - col_offset=assign.value.col_offset) - new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, - col_offset=assign.col_offset) - mod = ast.Module([new_assign]) - co = self._compile(mod, "exec") - try: - self.frame.exec_(co, __exprinfo_expr=value_result) - except Exception: - raise Failure(explanation) - return explanation, value_result diff --git a/py/_code/_assertionold.py b/py/_code/_assertionold.py deleted file mode 100644 --- a/py/_code/_assertionold.py +++ /dev/null @@ -1,555 +0,0 @@ -import py -import sys, inspect -from compiler import parse, ast, pycodegen -from py._code.assertion import BuiltinAssertionError, _format_explanation - -passthroughex = py.builtin._sysex - -class Failure: - def __init__(self, node): - self.exc, self.value, self.tb = sys.exc_info() - self.node = node - -class View(object): - """View base class. - - If C is a subclass of View, then C(x) creates a proxy object around - the object x. The actual class of the proxy is not C in general, - but a *subclass* of C determined by the rules below. To avoid confusion - we call view class the class of the proxy (a subclass of C, so of View) - and object class the class of x. - - Attributes and methods not found in the proxy are automatically read on x. - Other operations like setting attributes are performed on the proxy, as - determined by its view class. The object x is available from the proxy - as its __obj__ attribute. - - The view class selection is determined by the __view__ tuples and the - optional __viewkey__ method. By default, the selected view class is the - most specific subclass of C whose __view__ mentions the class of x. - If no such subclass is found, the search proceeds with the parent - object classes. For example, C(True) will first look for a subclass - of C with __view__ = (..., bool, ...) and only if it doesn't find any - look for one with __view__ = (..., int, ...), and then ..., object,... - If everything fails the class C itself is considered to be the default. - - Alternatively, the view class selection can be driven by another aspect - of the object x, instead of the class of x, by overriding __viewkey__. - See last example at the end of this module. - """ - - _viewcache = {} - __view__ = () - - def __new__(rootclass, obj, *args, **kwds): - self = object.__new__(rootclass) - self.__obj__ = obj - self.__rootclass__ = rootclass - key = self.__viewkey__() - try: - self.__class__ = self._viewcache[key] - except KeyError: - self.__class__ = self._selectsubclass(key) - return self - - def __getattr__(self, attr): - # attributes not found in the normal hierarchy rooted on View - # are looked up in the object's real class - return getattr(self.__obj__, attr) - - def __viewkey__(self): - return self.__obj__.__class__ - - def __matchkey__(self, key, subclasses): - if inspect.isclass(key): - keys = inspect.getmro(key) - else: - keys = [key] - for key in keys: - result = [C for C in subclasses if key in C.__view__] - if result: - return result - return [] - - def _selectsubclass(self, key): - subclasses = list(enumsubclasses(self.__rootclass__)) - for C in subclasses: - if not isinstance(C.__view__, tuple): - C.__view__ = (C.__view__,) - choices = self.__matchkey__(key, subclasses) - if not choices: - return self.__rootclass__ - elif len(choices) == 1: - return choices[0] - else: - # combine the multiple choices - return type('?', tuple(choices), {}) - - def __repr__(self): - return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) - - -def enumsubclasses(cls): - for subcls in cls.__subclasses__(): - for subsubclass in enumsubclasses(subcls): - yield subsubclass - yield cls - - -class Interpretable(View): - """A parse tree node with a few extra methods.""" - explanation = None - - def is_builtin(self, frame): - return False - - def eval(self, frame): - # fall-back for unknown expression nodes - try: - expr = ast.Expression(self.__obj__) - expr.filename = '' - self.__obj__.filename = '' - co = pycodegen.ExpressionCodeGenerator(expr).getCode() - result = frame.eval(co) - except passthroughex: - raise - except: - raise Failure(self) - self.result = result - self.explanation = self.explanation or frame.repr(self.result) - - def run(self, frame): - # fall-back for unknown statement nodes - try: - expr = ast.Module(None, ast.Stmt([self.__obj__])) - expr.filename = '' - co = pycodegen.ModuleCodeGenerator(expr).getCode() - frame.exec_(co) - except passthroughex: - raise - except: - raise Failure(self) - - def nice_explanation(self): - return _format_explanation(self.explanation) - - -class Name(Interpretable): - __view__ = ast.Name - - def is_local(self, frame): - source = '%r in locals() is not globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_global(self, frame): - source = '%r in globals()' % self.name - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def is_builtin(self, frame): - source = '%r not in locals() and %r not in globals()' % ( - self.name, self.name) - try: - return frame.is_true(frame.eval(source)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - super(Name, self).eval(frame) - if not self.is_local(frame): - self.explanation = self.name - -class Compare(Interpretable): - __view__ = ast.Compare - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - for operation, expr2 in self.ops: - if hasattr(self, 'result'): - # shortcutting in chained expressions - if not frame.is_true(self.result): - break - expr2 = Interpretable(expr2) - expr2.eval(frame) - self.explanation = "%s %s %s" % ( - expr.explanation, operation, expr2.explanation) - source = "__exprinfo_left %s __exprinfo_right" % operation - try: - self.result = frame.eval(source, - __exprinfo_left=expr.result, - __exprinfo_right=expr2.result) - except passthroughex: - raise - except: - raise Failure(self) - expr = expr2 - -class And(Interpretable): - __view__ = ast.And - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if not frame.is_true(expr.result): - break - self.explanation = '(' + ' and '.join(explanations) + ')' - -class Or(Interpretable): - __view__ = ast.Or - - def eval(self, frame): - explanations = [] - for expr in self.nodes: - expr = Interpretable(expr) - expr.eval(frame) - explanations.append(expr.explanation) - self.result = expr.result - if frame.is_true(expr.result): - break - self.explanation = '(' + ' or '.join(explanations) + ')' - - -# == Unary operations == -keepalive = [] -for astclass, astpattern in { - ast.Not : 'not __exprinfo_expr', - ast.Invert : '(~__exprinfo_expr)', - }.items(): - - class UnaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - expr = Interpretable(self.expr) - expr.eval(frame) - self.explanation = astpattern.replace('__exprinfo_expr', - expr.explanation) - try: - self.result = frame.eval(astpattern, - __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(UnaryArith) - -# == Binary operations == -for astclass, astpattern in { - ast.Add : '(__exprinfo_left + __exprinfo_right)', - ast.Sub : '(__exprinfo_left - __exprinfo_right)', - ast.Mul : '(__exprinfo_left * __exprinfo_right)', - ast.Div : '(__exprinfo_left / __exprinfo_right)', - ast.Mod : '(__exprinfo_left % __exprinfo_right)', - ast.Power : '(__exprinfo_left ** __exprinfo_right)', - }.items(): - - class BinaryArith(Interpretable): - __view__ = astclass - - def eval(self, frame, astpattern=astpattern): - left = Interpretable(self.left) - left.eval(frame) - right = Interpretable(self.right) - right.eval(frame) - self.explanation = (astpattern - .replace('__exprinfo_left', left .explanation) - .replace('__exprinfo_right', right.explanation)) - try: - self.result = frame.eval(astpattern, - __exprinfo_left=left.result, - __exprinfo_right=right.result) - except passthroughex: - raise - except: - raise Failure(self) - - keepalive.append(BinaryArith) - - -class CallFunc(Interpretable): - __view__ = ast.CallFunc - - def is_bool(self, frame): - source = 'isinstance(__exprinfo_value, bool)' - try: - return frame.is_true(frame.eval(source, - __exprinfo_value=self.result)) - except passthroughex: - raise - except: - return False - - def eval(self, frame): - node = Interpretable(self.node) - node.eval(frame) - explanations = [] - vars = {'__exprinfo_fn': node.result} - source = '__exprinfo_fn(' - for a in self.args: - if isinstance(a, ast.Keyword): - keyword = a.name - a = a.expr - else: - keyword = None - a = Interpretable(a) - a.eval(frame) - argname = '__exprinfo_%d' % len(vars) - vars[argname] = a.result - if keyword is None: - source += argname + ',' - explanations.append(a.explanation) - else: - source += '%s=%s,' % (keyword, argname) - explanations.append('%s=%s' % (keyword, a.explanation)) - if self.star_args: - star_args = Interpretable(self.star_args) - star_args.eval(frame) - argname = '__exprinfo_star' - vars[argname] = star_args.result - source += '*' + argname + ',' - explanations.append('*' + star_args.explanation) - if self.dstar_args: - dstar_args = Interpretable(self.dstar_args) - dstar_args.eval(frame) - argname = '__exprinfo_kwds' - vars[argname] = dstar_args.result - source += '**' + argname + ',' - explanations.append('**' + dstar_args.explanation) - self.explanation = "%s(%s)" % ( - node.explanation, ', '.join(explanations)) - if source.endswith(','): - source = source[:-1] - source += ')' - try: - self.result = frame.eval(source, **vars) - except passthroughex: - raise - except: - raise Failure(self) - if not node.is_builtin(frame) or not self.is_bool(frame): - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -class Getattr(Interpretable): - __view__ = ast.Getattr - - def eval(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - source = '__exprinfo_expr.%s' % self.attrname - try: - self.result = frame.eval(source, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - self.explanation = '%s.%s' % (expr.explanation, self.attrname) - # if the attribute comes from the instance, its value is interesting - source = ('hasattr(__exprinfo_expr, "__dict__") and ' - '%r in __exprinfo_expr.__dict__' % self.attrname) - try: - from_instance = frame.is_true( - frame.eval(source, __exprinfo_expr=expr.result)) - except passthroughex: - raise - except: - from_instance = True - if from_instance: - r = frame.repr(self.result) - self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) - -# == Re-interpretation of full statements == - -class Assert(Interpretable): - __view__ = ast.Assert - - def run(self, frame): - test = Interpretable(self.test) - test.eval(frame) - # simplify 'assert False where False = ...' - if (test.explanation.startswith('False\n{False = ') and - test.explanation.endswith('\n}')): - test.explanation = test.explanation[15:-2] - # print the result as 'assert ' - self.result = test.result - self.explanation = 'assert ' + test.explanation - if not frame.is_true(test.result): - try: - raise BuiltinAssertionError - except passthroughex: - raise - except: - raise Failure(self) - -class Assign(Interpretable): - __view__ = ast.Assign - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = '... = ' + expr.explanation - # fall-back-run the rest of the assignment - ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) - mod = ast.Module(None, ast.Stmt([ass])) - mod.filename = '' - co = pycodegen.ModuleCodeGenerator(mod).getCode() - try: - frame.exec_(co, __exprinfo_expr=expr.result) - except passthroughex: - raise - except: - raise Failure(self) - -class Discard(Interpretable): - __view__ = ast.Discard - - def run(self, frame): - expr = Interpretable(self.expr) - expr.eval(frame) - self.result = expr.result - self.explanation = expr.explanation - -class Stmt(Interpretable): - __view__ = ast.Stmt - - def run(self, frame): - for stmt in self.nodes: - stmt = Interpretable(stmt) - stmt.run(frame) - - -def report_failure(e): - explanation = e.node.nice_explanation() - if explanation: - explanation = ", in: " + explanation - else: - explanation = "" - sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) - -def check(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - expr = parse(s, 'eval') - assert isinstance(expr, ast.Expression) - node = Interpretable(expr.node) - try: - node.eval(frame) - except passthroughex: - raise - except Failure: - e = sys.exc_info()[1] - report_failure(e) - else: - if not frame.is_true(node.result): - sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) - - -########################################################### -# API / Entry points -# ######################################################### - -def interpret(source, frame, should_fail=False): - module = Interpretable(parse(source, 'exec').node) - #print "got module", module - if isinstance(frame, py.std.types.FrameType): - frame = py.code.Frame(frame) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - return getfailure(e) - except passthroughex: - raise - except: - import traceback - traceback.print_exc() - if should_fail: - return ("(assertion failed, but when it was re-run for " - "printing intermediate values, it did not fail. Suggestions: " - "compute assert expression before the assert or use --nomagic)") - else: - return None - -def getmsg(excinfo): - if isinstance(excinfo, tuple): - excinfo = py.code.ExceptionInfo(excinfo) - #frame, line = gettbline(tb) - #frame = py.code.Frame(frame) - #return interpret(line, frame) - - tb = excinfo.traceback[-1] - source = str(tb.statement).strip() - x = interpret(source, tb.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - return x - -def getfailure(e): - explanation = e.node.nice_explanation() - if str(e.value): - lines = explanation.split('\n') - lines[0] += " << %s" % (e.value,) - explanation = '\n'.join(lines) - text = "%s: %s" % (e.exc.__name__, explanation) - if text.startswith('AssertionError: assert '): - text = text[16:] - return text - -def run(s, frame=None): - if frame is None: - frame = sys._getframe(1) - frame = py.code.Frame(frame) - module = Interpretable(parse(s, 'exec').node) - try: - module.run(frame) - except Failure: - e = sys.exc_info()[1] - report_failure(e) - - -if __name__ == '__main__': - # example: - def f(): - return 5 - def g(): - return 3 - def h(x): - return 'never' - check("f() * g() == 5") - check("not f()") - check("not (f() and g() or 0)") - check("f() == g()") - i = 4 - check("i == f()") - check("len(f()) == 0") - check("isinstance(2+3+4, float)") - - run("x = i") - check("x == 5") - - run("assert not f(), 'oops'") - run("a, b, c = 1, 2") - run("a, b, c = f()") - - check("max([f(),g()]) == 4") - check("'hello'[g()] == 'h'") - run("'guk%d' % h(f())") diff --git a/py/_code/assertion.py b/py/_code/assertion.py deleted file mode 100644 --- a/py/_code/assertion.py +++ /dev/null @@ -1,94 +0,0 @@ -import sys -import py - -BuiltinAssertionError = py.builtin.builtins.AssertionError - -_reprcompare = None # if set, will be called by assert reinterp for comparison ops - -def _format_explanation(explanation): - """This formats an explanation - - Normally all embedded newlines are escaped, however there are - three exceptions: \n{, \n} and \n~. The first two are intended - cover nested explanations, see function and attribute explanations - for examples (.visit_Call(), visit_Attribute()). The last one is - for when one explanation needs to span multiple lines, e.g. when - displaying diffs. - """ - raw_lines = (explanation or '').split('\n') - # escape newlines not followed by {, } and ~ - lines = [raw_lines[0]] - for l in raw_lines[1:]: - if l.startswith('{') or l.startswith('}') or l.startswith('~'): - lines.append(l) - else: - lines[-1] += '\\n' + l - - result = lines[:1] - stack = [0] - stackcnt = [0] - for line in lines[1:]: - if line.startswith('{'): - if stackcnt[-1]: - s = 'and ' - else: - s = 'where ' - stack.append(len(result)) - stackcnt[-1] += 1 - stackcnt.append(0) - result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) - elif line.startswith('}'): - assert line.startswith('}') - stack.pop() - stackcnt.pop() - result[stack[-1]] += line[1:] - else: - assert line.startswith('~') - result.append(' '*len(stack) + line[1:]) - assert len(stack) == 1 - return '\n'.join(result) - - -class AssertionError(BuiltinAssertionError): - def __init__(self, *args): - BuiltinAssertionError.__init__(self, *args) - if args: - try: - self.msg = str(args[0]) - except py.builtin._sysex: - raise - except: - self.msg = "<[broken __repr__] %s at %0xd>" %( - args[0].__class__, id(args[0])) - else: - f = py.code.Frame(sys._getframe(1)) - try: - source = f.code.fullsource - if source is not None: - try: - source = source.getstatement(f.lineno, assertion=True) - except IndexError: - source = None - else: - source = str(source.deindent()).strip() - except py.error.ENOENT: - source = None - # this can also occur during reinterpretation, when the - # co_filename is set to "". - if source: - self.msg = reinterpret(source, f, should_fail=True) - else: - self.msg = "" - if not self.args: - self.args = (self.msg,) - -if sys.version_info > (3, 0): - AssertionError.__module__ = "builtins" - reinterpret_old = "old reinterpretation not available for py3" -else: - from py._code._assertionold import interpret as reinterpret_old -if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): - from py._code._assertionnew import interpret as reinterpret -else: - reinterpret = reinterpret_old - diff --git a/py/_code/code.py b/py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -145,17 +145,6 @@ return self.frame.f_locals locals = property(getlocals, None, None, "locals of underlaying frame") - def reinterpret(self): - """Reinterpret the failing statement and returns a detailed information - about what operations are performed.""" - if self.exprinfo is None: - source = str(self.statement).strip() - x = py.code._reinterpret(source, self.frame, should_fail=True) - if not isinstance(x, str): - raise TypeError("interpret returned non-string %r" % (x,)) - self.exprinfo = x - return self.exprinfo - def getfirstlinesource(self): # on Jython this firstlineno can be -1 apparently return max(self.frame.code.firstlineno, 0) @@ -310,7 +299,7 @@ # ExceptionInfo-like classes may have different attributes. if tup is None: tup = sys.exc_info() - if exprinfo is None and isinstance(tup[1], py.code._AssertionError): + if exprinfo is None and isinstance(tup[1], AssertionError): exprinfo = getattr(tup[1], 'msg', None) if exprinfo is None: exprinfo = str(tup[1]) @@ -690,22 +679,15 @@ oldbuiltins = {} -def patch_builtins(assertion=True, compile=True): - """ put compile and AssertionError builtins to Python's builtins. """ - if assertion: - from py._code import assertion - l = oldbuiltins.setdefault('AssertionError', []) - l.append(py.builtin.builtins.AssertionError) - py.builtin.builtins.AssertionError = assertion.AssertionError +def patch_builtins(compile=True): + """ put compile builtins to Python's builtins. """ if compile: l = oldbuiltins.setdefault('compile', []) l.append(py.builtin.builtins.compile) py.builtin.builtins.compile = py.code.compile -def unpatch_builtins(assertion=True, compile=True): +def unpatch_builtins(compile=True): """ remove compile and AssertionError builtins from Python builtins. """ - if assertion: - py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop() if compile: py.builtin.builtins.compile = oldbuiltins['compile'].pop() diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -279,13 +279,13 @@ desc = self.getdesc(cls) return desc.getuniqueclassdef() - def getlistdef(self, **flags): + def getlistdef(self, **flags_if_new): """Get the ListDef associated with the current position.""" try: listdef = self.listdefs[self.position_key] except KeyError: listdef = self.listdefs[self.position_key] = ListDef(self) - listdef.listitem.__dict__.update(flags) + listdef.listitem.__dict__.update(flags_if_new) return listdef def newlist(self, *s_values, **flags): @@ -294,14 +294,18 @@ listdef = self.getlistdef(**flags) for s_value in s_values: listdef.generalize(s_value) + if flags: + assert flags.keys() == ['range_step'] + listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) @@ -351,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -379,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/annotation/listdef.py b/pypy/annotation/listdef.py --- a/pypy/annotation/listdef.py +++ b/pypy/annotation/listdef.py @@ -184,6 +184,11 @@ def generalize(self, s_value): self.listitem.generalize(s_value) + def generalize_range_step(self, range_step): + newlistitem = ListItem(self.listitem.bookkeeper, s_ImpossibleValue) + newlistitem.range_step = range_step + self.listitem.merge(newlistitem) + def __repr__(self): return '<[%r]%s%s%s%s>' % (self.listitem.s_value, self.listitem.mutated and 'm' or '', diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py --- a/pypy/annotation/test/test_annrpython.py +++ b/pypy/annotation/test/test_annrpython.py @@ -3483,6 +3483,17 @@ a = self.RPythonAnnotator() raises(Exception, a.build_types, f, [int]) + def test_range_variable_step(self): + def g(n): + return range(0, 10, n) + def f(n): + r = g(1) # constant step, at first + s = g(n) # but it becomes a variable step + return r + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.listdef.listitem.range_step == 0 + def g(n): return [0,1,2,n] diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -33,13 +33,17 @@ "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", "_bisect", "binascii", "_multiprocessing", '_warnings', - "_collections", "_multibytecodec", "micronumpy"] + "_collections", "_multibytecodec", "micronumpy", "_ffi"] )) translation_modules = default_modules.copy() translation_modules.update(dict.fromkeys( ["fcntl", "rctime", "select", "signal", "_rawffi", "zlib", - "struct", "_md5", "cStringIO", "array"])) + "struct", "_md5", "cStringIO", "array", "_ffi", + # the following are needed for pyrepl (and hence for the + # interactive prompt/pdb) + "termios", "_minimal_curses", + ])) working_oo_modules = default_modules.copy() working_oo_modules.update(dict.fromkeys( @@ -80,6 +84,7 @@ "_rawffi": [("objspace.usemodules.struct", True)], "cpyext": [("translation.secondaryentrypoints", "cpyext"), ("translation.shared", sys.platform == "win32")], + "_ffi": [("translation.jit_ffi", True)], } module_import_dependencies = { @@ -124,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -261,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -350,8 +346,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py --- a/pypy/config/test/test_pypyoption.py +++ b/pypy/config/test/test_pypyoption.py @@ -73,3 +73,7 @@ fn = prefix + "." + path + ".txt" yield check_file_exists, fn +def test__ffi_opt(): + config = get_pypy_config(translating=True) + config.objspace.usemodules._ffi = True + assert config.translation.jit_ffi diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -118,6 +118,8 @@ ChoiceOption("jit_profiler", "integrate profiler support into the JIT", ["off", "oprofile"], default="off"), + # jit_ffi is automatically turned on by withmod-_ffi (which is enabled by default) + BoolOption("jit_ffi", "optimize libffi calls", default=False, cmdline=None), # misc BoolOption("verbose", "Print extra information", default=False), diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -173,6 +173,11 @@ >>>> A.__del__ = lambda self: None __main__:1: RuntimeWarning: a __del__ method added to an existing type will not be called +Even more obscure: the same is true, for old-style classes, if you attach +the ``__del__`` to an instance (even in CPython this does not work with +new-style classes). You get a RuntimeWarning in PyPy. To fix these cases +just make sure there is a ``__del__`` method in the class to start with. + Subclasses of built-in types ---------------------------- @@ -243,5 +248,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/doc/garbage_collection.rst b/pypy/doc/garbage_collection.rst --- a/pypy/doc/garbage_collection.rst +++ b/pypy/doc/garbage_collection.rst @@ -212,90 +212,4 @@ becomes free garbage, to be collected at the next major collection. -Minimark GC ------------ - -This is a simplification and rewrite of the ideas from the Hybrid GC. -It uses a nursery for the young objects, and mark-and-sweep for the old -objects. This is a moving GC, but objects may only move once (from -the nursery to the old stage). - -The main difference with the Hybrid GC is that the mark-and-sweep -objects (the "old stage") are directly handled by the GC's custom -allocator, instead of being handled by malloc() calls. The gain is that -it is then possible, during a major collection, to walk through all old -generation objects without needing to store a list of pointers to them. -So as a first approximation, when compared to the Hybrid GC, the -Minimark GC saves one word of memory per old object. - -There are a number of environment variables that can be tweaked to -influence the GC. (Their default value should be ok for most usages.) -You can read more about them at the start of -`pypy/rpython/memory/gc/minimark.py`_. - -In more details: - -- The small newly malloced objects are allocated in the nursery (case 1). - All objects living in the nursery are "young". - -- The big objects are always handled directly by the system malloc(). - But the big newly malloced objects are still "young" when they are - allocated (case 2), even though they don't live in the nursery. - -- When the nursery is full, we do a minor collection, i.e. we find - which "young" objects are still alive (from cases 1 and 2). The - "young" flag is then removed. The surviving case 1 objects are moved - to the old stage. The dying case 2 objects are immediately freed. - -- The old stage is an area of memory containing old (small) objects. It - is handled by `pypy/rpython/memory/gc/minimarkpage.py`_. It is organized - as "arenas" of 256KB or 512KB, subdivided into "pages" of 4KB or 8KB. - Each page can either be free, or contain small objects of all the same - size. Furthermore at any point in time each object location can be - either allocated or freed. The basic design comes from ``obmalloc.c`` - from CPython (which itself comes from the same source as the Linux - system malloc()). - -- New objects are added to the old stage at every minor collection. - Immediately after a minor collection, when we reach some threshold, we - trigger a major collection. This is the mark-and-sweep step. It walks - over *all* objects (mark), and then frees some fraction of them (sweep). - This means that the only time when we want to free objects is while - walking over all of them; we never ask to free an object given just its - address. This allows some simplifications and memory savings when - compared to ``obmalloc.c``. - -- As with all generational collectors, this GC needs a write barrier to - record which old objects have a reference to young objects. - -- Additionally, we found out that it is useful to handle the case of - big arrays specially: when we allocate a big array (with the system - malloc()), we reserve a small number of bytes before. When the array - grows old, we use the extra bytes as a set of bits. Each bit - represents 128 entries in the array. Whenever the write barrier is - called to record a reference from the Nth entry of the array to some - young object, we set the bit number ``(N/128)`` to 1. This can - considerably speed up minor collections, because we then only have to - scan 128 entries of the array instead of all of them. - -- As usual, we need special care about weak references, and objects with - finalizers. Weak references are allocated in the nursery, and if they - survive they move to the old stage, as usual for all objects; the - difference is that the reference they contain must either follow the - object, or be set to NULL if the object dies. And the objects with - finalizers, considered rare enough, are immediately allocated old to - simplify the design. In particular their ``__del__`` method can only - be called just after a major collection. - -- The objects move once only, so we can use a trick to implement id() - and hash(). If the object is not in the nursery, it won't move any - more, so its id() and hash() are the object's address, cast to an - integer. If the object is in the nursery, and we ask for its id() - or its hash(), then we pre-reserve a location in the old stage, and - return the address of that location. If the object survives the - next minor collection, we move it there, and so its id() and hash() - are preserved. If the object dies then the pre-reserved location - becomes free garbage, to be collected at the next major collection. - - .. include:: _ref.txt diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/image/jitviewer.png b/pypy/doc/image/jitviewer.png new file mode 100644 index 0000000000000000000000000000000000000000..ad2abca5c88125061fa519dcf3f9fada577573ee GIT binary patch [cut] diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -21,16 +25,11 @@ * `speed.pypy.org`_: Daily benchmarks of how fast PyPy is +* `potential project ideas`_: In case you want to get your feet wet... + Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: @@ -59,8 +58,6 @@ (if they are not already developed in the FAQ_). You can find logs of the channel here_. -.. XXX play1? - Meeting PyPy developers ======================= @@ -83,7 +80,7 @@ .. _`Release 1.5`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html - +.. _`potential project ideas`: project-ideas.html Project Documentation ===================================== diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ @@ -289,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -11,6 +11,12 @@ `mailing list`_. This is simply for the reason that small possible projects tend to change very rapidly. +This list is mostly for having on overview on potential projects. This list is +by definition not exhaustive and we're pleased if people come up with their +own improvement ideas. In any case, if you feel like working on some of those +projects, or anything else in PyPy, pop up on IRC or write to us on the +`mailing list`_. + Numpy improvements ------------------ @@ -23,27 +29,121 @@ * interface with fortran/C libraries. -Potential mentors: fijal +Improving the jitviewer +------------------------ -JIT tooling ------------ +Analyzing performance of applications is always tricky. We have various +tools, for example a `jitviewer`_ that help us analyze performance. -xxx +The jitviewer shows the code generated by the PyPy JIT in a hierarchical way, +as shown by the screenshot below: + + - at the bottom level, it shows the Python source code of the compiled loops + + - for each source code line, it shows the corresponding Python bytecode + + - for each opcode, it shows the corresponding jit operations, which are the + ones actually sent to the backend for compiling (such as ``i15 = i10 < + 2000`` in the example) + +.. image:: image/jitviewer.png + +We would like to add one level to this hierarchy, by showing the generated +machine code for each jit operation. The necessary information is already in +the log file produced by the JIT, so it is "only" a matter of teaching the +jitviewer to display it. Ideally, the machine code should be hidden by +default and viewable on request. + +The jitviewer is a web application based on flask and jinja2 (and jQuery on +the client): if you have great web developing skills and want to help PyPy, +this is an ideal task to get started, because it does not require any deep +knowledge of the internals. + +Translation Toolchain +--------------------- + +* Incremental or distributed translation. + +* Allow separate compilation of extension modules. Work on some of other languages ------------------------------- -xxx +There are various languages implemented using the RPython translation toolchain. +One of the most interesting is the `JavaScript implementation`_, but there +are others like scheme or prolog. An interesting project would be to improve +the jittability of those or to experiment with various optimizations. Various GCs ----------- -xxx +PyPy has pluggable garbage collection policy. This means that various garbage +collectors can be written for specialized purposes, or even various +experiments can be done for the general purpose. Examples + +* An incremental garbage collector that has specified maximal pause times, + crucial for games + +* A garbage collector that compact memory better for mobile devices + +* A concurrent garbage collector (a lot of work) Remove the GIL -------------- -xxx +This is a major task that requires lots of thinking. However, few subprojects +can be potentially specified, unless a better plan can be thought out: -.. _`issue tracker`: ... -.. _`mailing list`: ... +* A thread-aware garbage collector + +* Better RPython primitives for dealing with concurrency + +* JIT passes to remove locks on objects + +* (maybe) implement locking in Python interpreter + +* alternatively, look at Software Transactional Memory + +Introduce new benchmarks +------------------------ + +We're usually happy to introduce new benchmarks. Please consult us +before, but in general something that's real-world python code +and is not already represented is welcome. We need at least a standalone +script that can run without parameters. Example ideas (benchmarks need +to be got from them!): + +* `hg` + +* `sympy` + +Experiment (again) with LLVM backend for RPython compilation +------------------------------------------------------------ + +We already tried working with LLVM and at the time, LLVM was not mature enough +for our needs. It's possible that this has changed, reviving the LLVM backend +(or writing new from scratch) for static compilation would be a good project. + +(On the other hand, just generating C code and using clang might be enough. +The issue with that is the so-called "asmgcc GC root finder", which has tons +of issues of this own. In my opinion (arigo), it would be definitely a +better project to try to optimize the alternative, the "shadowstack" GC root +finder, which is nicely portable. So far it gives a pypy that is around +7% slower.) + +Embedding PyPy +---------------------------------------- + +Being able to embed PyPy, say with its own limited C API, would be +useful. But here is the most interesting variant, straight from +EuroPython live discussion :-) We can have a generic "libpypy.so" that +can be used as a placeholder dynamic library, and when it gets loaded, +it runs a .py module that installs (via ctypes) the interface it wants +exported. This would give us a one-size-fits-all generic .so file to be +imported by any application that wants to load .so files :-) + + +.. _`issue tracker`: http://bugs.pypy.org +.. _`mailing list`: http://mail.python.org/mailman/listinfo/pypy-dev +.. _`jitviewer`: http://bitbucket.org/pypy/jitviewer +.. _`JavaScript implementation`: https://bitbucket.org/pypy/lang-js/overview diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) @@ -90,15 +90,18 @@ ### Construction ### def __init__(self, space, args_w, keywords=None, keywords_w=None, - w_stararg=None, w_starstararg=None): + w_stararg=None, w_starstararg=None, keyword_names_w=None): self.space = space assert isinstance(args_w, list) self.arguments_w = args_w self.keywords = keywords self.keywords_w = keywords_w + self.keyword_names_w = keyword_names_w # matches the tail of .keywords if keywords is not None: assert keywords_w is not None assert len(keywords_w) == len(keywords) + assert (keyword_names_w is None or + len(keyword_names_w) <= len(keywords)) make_sure_not_resized(self.keywords) make_sure_not_resized(self.keywords_w) @@ -132,7 +135,8 @@ def replace_arguments(self, args_w): "Return a new Arguments with a args_w as positional arguments." - return Arguments(self.space, args_w, self.keywords, self.keywords_w) + return Arguments(self.space, args_w, self.keywords, self.keywords_w, + keyword_names_w = self.keyword_names_w) def prepend(self, w_firstarg): "Return a new Arguments with a new argument inserted first." @@ -201,15 +205,16 @@ space.w_TypeError, space.wrap("keywords must be strings")) if e.match(space, space.w_UnicodeEncodeError): - raise OperationError( - space.w_TypeError, - space.wrap("keyword cannot be encoded to ascii")) - raise - if self.keywords and key in self.keywords: - raise operationerrfmt(self.space.w_TypeError, - "got multiple values " - "for keyword argument " - "'%s'", key) + # Allow this to pass through + key = None + else: + raise + else: + if self.keywords and key in self.keywords: + raise operationerrfmt(self.space.w_TypeError, + "got multiple values " + "for keyword argument " + "'%s'", key) keywords[i] = key keywords_w[i] = space.getitem(w_starstararg, w_key) i += 1 @@ -219,6 +224,7 @@ else: self.keywords = self.keywords + keywords self.keywords_w = self.keywords_w + keywords_w + self.keyword_names_w = keys_w def fixedunpack(self, argcount): """The simplest argument parsing: get the 'argcount' arguments, @@ -339,6 +345,10 @@ used_keywords = [False] * num_kwds for i in range(num_kwds): name = keywords[i] + # If name was not encoded as a string, it could be None. In that + # case, it's definitely not going to be in the signature. + if name is None: + continue j = signature.find_argname(name) if j < 0: continue @@ -374,17 +384,26 @@ if has_kwarg: w_kwds = self.space.newdict() if num_remainingkwds: + # + limit = len(keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(keywords)): if not used_keywords[i]: - key = keywords[i] - self.space.setitem(w_kwds, self.space.wrap(key), keywords_w[i]) + if i < limit: + w_key = self.space.wrap(keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + self.space.setitem(w_kwds, w_key, keywords_w[i]) + # scope_w[co_argcount + has_vararg] = w_kwds elif num_remainingkwds: if co_argcount == 0: raise ArgErrCount(avail, num_kwds, co_argcount, has_vararg, has_kwarg, defaults_w, missing) - raise ArgErrUnknownKwds(num_remainingkwds, keywords, used_keywords) + raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords, + used_keywords, self.keyword_names_w) if missing: raise ArgErrCount(avail, num_kwds, @@ -443,9 +462,15 @@ w_args = space.newtuple(self.arguments_w) w_kwds = space.newdict() if self.keywords is not None: + limit = len(self.keywords) + if self.keyword_names_w is not None: + limit -= len(self.keyword_names_w) for i in range(len(self.keywords)): - space.setitem(w_kwds, space.wrap(self.keywords[i]), - self.keywords_w[i]) + if i < limit: + w_key = space.wrap(self.keywords[i]) + else: + w_key = self.keyword_names_w[i - limit] + space.setitem(w_kwds, w_key, self.keywords_w[i]) return w_args, w_kwds class ArgumentsForTranslation(Arguments): @@ -666,14 +691,33 @@ class ArgErrUnknownKwds(ArgErr): - def __init__(self, num_remainingkwds, keywords, used_keywords): - self.kwd_name = '' + def __init__(self, space, num_remainingkwds, keywords, used_keywords, + keyword_names_w): + name = '' self.num_kwds = num_remainingkwds if num_remainingkwds == 1: for i in range(len(keywords)): if not used_keywords[i]: - self.kwd_name = keywords[i] + name = keywords[i] + if name is None: + # We'll assume it's unicode. Encode it. + # Careful, I *think* it should not be possible to + # get an IndexError here but you never know. + try: + if keyword_names_w is None: + raise IndexError + # note: negative-based indexing from the end + w_name = keyword_names_w[i - len(keywords)] + except IndexError: + name = '?' + else: + w_enc = space.wrap(space.sys.defaultencoding) + w_err = space.wrap("replace") + w_name = space.call_method(w_name, "encode", w_enc, + w_err) + name = space.str_w(w_name) break + self.kwd_name = name def getmsg(self, fnname): if self.num_kwds == 1: diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -134,7 +133,7 @@ def accept_comp_iteration(self, codegen, index): self.elt.walkabout(codegen) - codegen.emit_op_arg(ops.SET_ADD, index) + codegen.emit_op_arg(ops.SET_ADD, index + 1) class __extend__(ast.DictComp): @@ -148,7 +147,7 @@ def accept_comp_iteration(self, codegen, index): self.value.walkabout(codegen) self.key.walkabout(codegen) - codegen.emit_op_arg(ops.MAP_ADD, index) + codegen.emit_op_arg(ops.MAP_ADD, index + 1) # These are frame blocks. @@ -942,8 +941,7 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) arg = 0 @@ -977,28 +975,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -92,7 +92,10 @@ return name if len(name) + 2 >= MANGLE_LEN: return name - if name.endswith('__'): + # Don't mangle __id__ or names with dots. The only time a name with a dot + # can occur is when we are compiling an import statement that has a package + # name. + if name.endswith('__') or '.' in name: return name try: i = 0 diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -55,7 +55,7 @@ co_expr = compile(evalexpr, '', 'eval') space = self.space pyco_expr = PyCode._from_code(space, co_expr) - w_res = pyco_expr.exec_host_bytecode(space, w_dict, w_dict) + w_res = pyco_expr.exec_host_bytecode(w_dict, w_dict) res = space.str_w(space.repr(w_res)) if not isinstance(expected, float): assert res == repr(expected) @@ -308,6 +308,15 @@ "p.__name__", os.path.__name__) yield (self.st, 'from os import *', "path.__name__, sep", (os.path.__name__, os.sep)) + yield (self.st, ''' + class A(object): + def m(self): + from __foo__.bar import x + try: + A().m() + except ImportError, e: + msg = str(e) + ''', "msg", "No module named __foo__") def test_if_stmts(self): yield self.st, "a = 42\nif a > 10: a += 2", "a", 44 diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -237,7 +237,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) @@ -311,9 +311,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: @@ -989,10 +986,7 @@ compiler = self.createcompiler() expression = compiler.compile(expression, '?', 'eval', 0, hidden_applevel=hidden_applevel) - if isinstance(expression, types.CodeType): - # XXX only used by appsupport - expression = PyCode._from_code(self, expression) - if not isinstance(expression, PyCode): + else: raise TypeError, 'space.eval(): expected a string, code or PyCode object' return expression.exec_code(self, w_globals, w_locals) @@ -1007,9 +1001,6 @@ compiler = self.createcompiler() statement = compiler.compile(statement, filename, 'exec', 0, hidden_applevel=hidden_applevel) - if isinstance(statement, types.CodeType): - # XXX only used by appsupport - statement = PyCode._from_code(self, statement) if not isinstance(statement, PyCode): raise TypeError, 'space.exec_(): expected a string, code or PyCode object' w_key = self.wrap('__builtins__') diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -100,12 +100,12 @@ @jit.dont_look_inside def fast2locals(self): - # Copy values from self.fastlocals_w to self.w_locals + # Copy values from the fastlocals to self.w_locals if self.w_locals is None: self.w_locals = self.space.newdict() varnames = self.getcode().getvarnames() fastscope_w = self.getfastscope() - for i in range(min(len(varnames), len(fastscope_w))): + for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] if w_value is not None: @@ -114,7 +114,7 @@ @jit.dont_look_inside def locals2fast(self): - # Copy values from self.w_locals to self.fastlocals_w + # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None varnames = self.getcode().getvarnames() numlocals = self.getfastscopelength() diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -63,7 +63,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack @@ -98,7 +98,7 @@ self.closure) for i in funccallunrolling: if i < nargs: - new_frame.fastlocals_w[i] = args_w[i] + new_frame.locals_stack_w[i] = args_w[i] return new_frame.run() elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1: assert isinstance(code, gateway.BuiltinCodePassThroughArguments1) @@ -158,7 +158,7 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg return new_frame.run() @@ -169,13 +169,13 @@ self.closure) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) - new_frame.fastlocals_w[i] = w_arg + new_frame.locals_stack_w[i] = w_arg ndefs = len(self.defs_w) start = ndefs - defs_to_load i = nargs for j in xrange(start, ndefs): - new_frame.fastlocals_w[i] = self.defs_w[j] + new_frame.locals_stack_w[i] = self.defs_w[j] i += 1 return new_frame.run() @@ -465,19 +465,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -396,11 +396,14 @@ fastfunc = func else: # try to avoid excessive bloat - if func.__module__ == 'pypy.interpreter.astcompiler.ast': + mod = func.__module__ + if mod is None: + mod = "" + if mod == 'pypy.interpreter.astcompiler.ast': raise FastFuncNotSupported - if (not func.__module__.startswith('pypy.module.__builtin__') and - not func.__module__.startswith('pypy.module.sys') and - not func.__module__.startswith('pypy.module.math')): + if (not mod.startswith('pypy.module.__builtin__') and + not mod.startswith('pypy.module.sys') and + not mod.startswith('pypy.module.math')): if not func.__name__.startswith('descr'): raise FastFuncNotSupported d = {} diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -170,7 +170,7 @@ for i in range(len(args_to_copy)): argnum = args_to_copy[i] if argnum >= 0: - self.cells[i].set(self.fastlocals_w[argnum]) + self.cells[i].set(self.locals_stack_w[argnum]) def getfreevarname(self, index): freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -63,6 +63,7 @@ the pypy compiler""" self.space = space eval.Code.__init__(self, name) + assert nlocals >= 0 self.co_argcount = argcount self.co_nlocals = nlocals self.co_stacksize = stacksize @@ -95,7 +96,7 @@ if self.co_flags & CO_VARKEYWORDS: argcount += 1 # Cell vars could shadow already-set arguments. - # astcompiler.pyassem used to be clever about the order of + # The compiler used to be clever about the order of # the variables in both co_varnames and co_cellvars, but # it no longer is for the sake of simplicity. Moreover # code objects loaded from CPython don't necessarily follow @@ -202,7 +203,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -215,7 +216,7 @@ # speed hack fresh_frame = jit.hint(frame, access_directly=True, fresh_virtualizable=True) - args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, + args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name, sig, func.defs_w) fresh_frame.init_cells() @@ -256,7 +257,7 @@ tuple(self.co_freevars), tuple(self.co_cellvars) ) - def exec_host_bytecode(self, w_dict, w_globals, w_locals): + def exec_host_bytecode(self, w_globals, w_locals): from pypy.interpreter.pyframe import CPythonFrame frame = CPythonFrame(self.space, self, w_globals, None) frame.setdictscope(w_locals) diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -9,7 +9,7 @@ from pypy.interpreter import pytraceback from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib.jit import hint -from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.debug import make_sure_not_resized, check_nonneg from pypy.rlib.rarithmetic import intmask from pypy.rlib import jit from pypy.tool import stdlib_opcode @@ -56,16 +56,18 @@ assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals) - self.valuestack_w = [None] * code.co_stacksize - self.valuestackdepth = 0 + self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize) + self.nlocals = code.co_nlocals + self.valuestackdepth = code.co_nlocals self.lastblock = None + make_sure_not_resized(self.locals_stack_w) + check_nonneg(self.nlocals) + # if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure, code) - self.fastlocals_w = [None] * code.co_nlocals - make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno def mark_as_escaped(self): @@ -184,14 +186,14 @@ # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth - self.valuestack_w[depth] = w_object + self.locals_stack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 - assert depth >= 0, "pop from empty value stack" - w_object = self.valuestack_w[depth] - self.valuestack_w[depth] = None + assert depth >= self.nlocals, "pop from empty value stack" + w_object = self.locals_stack_w[depth] + self.locals_stack_w[depth] = None self.valuestackdepth = depth return w_object @@ -217,24 +219,24 @@ def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n - assert base >= 0 + assert base >= self.nlocals while True: n -= 1 if n < 0: break - values_w[n] = self.valuestack_w[base+n] + values_w[n] = self.locals_stack_w[base+n] return values_w @jit.unroll_safe def dropvalues(self, n): n = hint(n, promote=True) finaldepth = self.valuestackdepth - n - assert finaldepth >= 0, "stack underflow in dropvalues()" + assert finaldepth >= self.nlocals, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break - self.valuestack_w[finaldepth+n] = None + self.locals_stack_w[finaldepth+n] = None self.valuestackdepth = finaldepth @jit.unroll_safe @@ -261,30 +263,30 @@ # Contrast this with CPython where it's PEEK(-1). index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "peek past the bottom of the stack" - return self.valuestack_w[index] + assert index >= self.nlocals, "peek past the bottom of the stack" + return self.locals_stack_w[index] def settopvalue(self, w_object, index_from_top=0): index_from_top = hint(index_from_top, promote=True) index = self.valuestackdepth + ~index_from_top - assert index >= 0, "settop past the bottom of the stack" - self.valuestack_w[index] = w_object + assert index >= self.nlocals, "settop past the bottom of the stack" + self.locals_stack_w[index] = w_object @jit.unroll_safe def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 finaldepth = hint(finaldepth, promote=True) while depth >= finaldepth: - self.valuestack_w[depth] = None + self.locals_stack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth - def savevaluestack(self): - return self.valuestack_w[:self.valuestackdepth] + def save_locals_stack(self): + return self.locals_stack_w[:self.valuestackdepth] - def restorevaluestack(self, items_w): - assert None not in items_w - self.valuestack_w[:len(items_w)] = items_w + def restore_locals_stack(self, items_w): + self.locals_stack_w[:len(items_w)] = items_w + self.init_cells() self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): @@ -314,11 +316,12 @@ else: f_lineno = self.f_lineno - values_w = self.valuestack_w[0:self.valuestackdepth] + values_w = self.locals_stack_w[self.nlocals:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) - w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) + w_fastlocals = maker.slp_into_tuple_with_nulls( + space, self.locals_stack_w[:self.nlocals]) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None @@ -399,7 +402,8 @@ new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) - new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals) + new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None @@ -423,28 +427,28 @@ @jit.dont_look_inside def getfastscope(self): "Get the fast locals as a list." - return self.fastlocals_w + return self.locals_stack_w @jit.dont_look_inside def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) - if scope_len > len(self.fastlocals_w): + if scope_len > self.nlocals: raise ValueError, "new fastscope is longer than the allocated area" - # don't assign directly to 'fastlocals_w[:scope_len]' to be + # don't assign directly to 'locals_stack_w[:scope_len]' to be # virtualizable-friendly for i in range(scope_len): - self.fastlocals_w[i] = scope_w[i] + self.locals_stack_w[i] = scope_w[i] self.init_cells() def init_cells(self): - """Initialize cellvars from self.fastlocals_w + """Initialize cellvars from self.locals_stack_w. This is overridden in nestedscope.py""" pass def getfastscopelength(self): - return self.pycode.co_nlocals + return self.nlocals def getclosure(self): return None diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -324,7 +324,7 @@ def LOAD_FAST(self, varindex, next_instr): # access a local variable directly - w_value = self.fastlocals_w[varindex] + w_value = self.locals_stack_w[varindex] if w_value is None: self._load_fast_failed(varindex) self.pushvalue(w_value) @@ -343,7 +343,7 @@ def STORE_FAST(self, varindex, next_instr): w_newvalue = self.popvalue() assert w_newvalue is not None - self.fastlocals_w[varindex] = w_newvalue + self.locals_stack_w[varindex] = w_newvalue def POP_TOP(self, oparg, next_instr): self.popvalue() @@ -696,12 +696,12 @@ LOAD_GLOBAL._always_inline_ = True def DELETE_FAST(self, varindex, next_instr): - if self.fastlocals_w[varindex] is None: + if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise operationerrfmt(self.space.w_UnboundLocalError, message, varname) - self.fastlocals_w[varindex] = None + self.locals_stack_w[varindex] = None def BUILD_TUPLE(self, itemcount, next_instr): items = self.popvalues(itemcount) @@ -1048,30 +1048,18 @@ def SET_ADD(self, oparg, next_instr): w_value = self.popvalue() - w_set = self.peekvalue(oparg) + w_set = self.peekvalue(oparg - 1) self.space.call_method(w_set, 'add', w_value) def MAP_ADD(self, oparg, next_instr): w_key = self.popvalue() w_value = self.popvalue() - w_dict = self.peekvalue(oparg) + w_dict = self.peekvalue(oparg - 1) self.space.setitem(w_dict, w_key, w_value) def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION @@ -1091,12 +1079,10 @@ @jit.unroll_safe def BUILD_SET(self, itemcount, next_instr): - w_set = self.space.call_function(self.space.w_set) - if itemcount: - w_add = self.space.getattr(w_set, self.space.wrap("add")) - for i in range(itemcount): - w_item = self.popvalue() - self.space.call_function(w_add, w_item) + w_set = self.space.newset() + for i in range(itemcount): + w_item = self.popvalue() + self.space.call_method(w_set, 'add', w_item) self.pushvalue(w_set) def STORE_MAP(self, oparg, next_instr): diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import py from pypy.interpreter.argument import (Arguments, ArgumentsForTranslation, ArgErr, ArgErrUnknownKwds, ArgErrMultipleValues, ArgErrCount, rawshape, @@ -126,6 +127,7 @@ w_AttributeError = AttributeError w_UnicodeEncodeError = UnicodeEncodeError w_dict = dict + w_str = str class TestArgumentsNormal(object): @@ -485,26 +487,6 @@ args._match_signature(None, l, Signature(['abc'])) assert len(l) == 1 assert l[0] == space.wrap(5) - # - def str_w(w): - try: - return str(w) - except UnicodeEncodeError: - raise OperationError(space.w_UnicodeEncodeError, - space.wrap("oups")) - space.str_w = str_w - w_starstar = space.wrap({u'\u1234': 5}) - err = py.test.raises(OperationError, Arguments, - space, [], w_starstararg=w_starstar) - # Check that we get a TypeError. On CPython it is because of - # "no argument called '?'". On PyPy we get a TypeError too, but - # earlier: "keyword cannot be encoded to ascii". The - # difference, besides the error message, is only apparent if the - # receiver also takes a **arg. Then CPython passes the - # non-ascii unicode unmodified, whereas PyPy complains. We will - # not care until someone has a use case for that. - assert not err.value.match(space, space.w_UnicodeEncodeError) - assert err.value.match(space, space.w_TypeError) class TestErrorHandling(object): def test_missing_args(self): @@ -559,13 +541,26 @@ assert 0, "did not raise" def test_unknown_keywords(self): - err = ArgErrUnknownKwds(1, ['a', 'b'], [True, False]) + space = DummySpace() + err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [True, False], None) s = err.getmsg('foo') assert s == "foo() got an unexpected keyword argument 'b'" - err = ArgErrUnknownKwds(2, ['a', 'b', 'c'], [True, False, False]) + err = ArgErrUnknownKwds(space, 2, ['a', 'b', 'c'], + [True, False, False], None) s = err.getmsg('foo') assert s == "foo() got 2 unexpected keyword arguments" + def test_unknown_unicode_keyword(self): + class DummySpaceUnicode(DummySpace): + class sys: + defaultencoding = 'utf-8' + space = DummySpaceUnicode() + err = ArgErrUnknownKwds(space, 1, ['a', None, 'b', 'c'], + [True, False, True, True], + [unichr(0x1234), u'b', u'c']) + s = err.getmsg('foo') + assert s == "foo() got an unexpected keyword argument '\xe1\x88\xb4'" + def test_multiple_values(self): err = ArgErrMultipleValues('bla') s = err.getmsg('foo') @@ -592,6 +587,14 @@ exc = raises(TypeError, (lambda a, b, **kw: 0), a=1) assert exc.value.message == "() takes exactly 2 non-keyword arguments (0 given)" + def test_unicode_keywords(self): + def f(**kwargs): + assert kwargs[u"美"] == 42 + f(**{u"美" : 42}) + def f(x): pass + e = raises(TypeError, "f(**{u'ü' : 19})") + assert "?" in str(e.value) + def make_arguments_for_translation(space, args_w, keywords_w={}, w_stararg=None, w_starstararg=None): return ArgumentsForTranslation(space, args_w, keywords_w.keys(), diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py --- a/pypy/interpreter/test/test_eval.py +++ b/pypy/interpreter/test/test_eval.py @@ -15,16 +15,16 @@ self.code = code Frame.__init__(self, space) self.numlocals = numlocals - self.fastlocals_w = [None] * self.numlocals + self._fastlocals_w = [None] * self.numlocals def getcode(self): return self.code def setfastscope(self, scope_w): - self.fastlocals_w = scope_w + self._fastlocals_w = scope_w def getfastscope(self): - return self.fastlocals_w + return self._fastlocals_w def getfastscopelength(self): return self.numlocals @@ -38,11 +38,11 @@ self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({})) - self.f.fastlocals_w[0] = w(5) + self.f._fastlocals_w[0] = w(5) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5})) - self.f.fastlocals_w[2] = w(7) + self.f._fastlocals_w[2] = w(7) self.f.fast2locals() assert space.eq_w(self.f.w_locals, self.space.wrap({'x': 5, 'args': 7})) @@ -57,13 +57,13 @@ w = self.space.wrap self.f.w_locals = self.space.wrap({}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [None]*5) + self.sameList(self.f._fastlocals_w, [None]*5) self.f.w_locals = self.space.wrap({'x': 5}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) + self.sameList(self.f._fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.wrap({'x':5, 'args':7}) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), None, w(7), - None, None]) + self.sameList(self.f._fastlocals_w, [w(5), None, w(7), + None, None]) diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -16,7 +16,7 @@ def g(): f() - + try: g() except: @@ -203,3 +203,27 @@ lst = seen[:] assert lst == [5, 10, 2] raises(OSError, os.lseek, fd, 7, 0) + + def test_method_attrs(self): + import sys + class A(object): + def m(self): + "aaa" + m.x = 3 + class B(A): + pass + + bm = B().m + assert bm.__func__ is bm.im_func + assert bm.__self__ is bm.im_self + assert bm.im_class is B + assert bm.__doc__ == "aaa" + assert bm.x == 3 + raises(AttributeError, setattr, bm, 'x', 15) + l = [] + assert l.append.__self__ is l + assert l.__add__.__self__ is l + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -761,12 +761,15 @@ ) Function.typedef.acceptable_as_base_class = False -Method.typedef = TypeDef("method", +Method.typedef = TypeDef( + "method", __new__ = interp2app(Method.descr_method__new__.im_func), __call__ = interp2app(Method.descr_method_call), __get__ = interp2app(Method.descr_method_get), im_func = interp_attrproperty_w('w_function', cls=Method), + __func__ = interp_attrproperty_w('w_function', cls=Method), im_self = interp_attrproperty_w('w_instance', cls=Method), + __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), diff --git a/pypy/jit/backend/arm/arch.py b/pypy/jit/backend/arm/arch.py --- a/pypy/jit/backend/arm/arch.py +++ b/pypy/jit/backend/arm/arch.py @@ -34,7 +34,7 @@ "pypy__arm_int_div", [lltype.Signed, lltype.Signed], lltype.Signed, _callable=arm_int_div_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) arm_uint_div_sign = lltype.Ptr(lltype.FuncType([lltype.Unsigned, lltype.Unsigned], lltype.Unsigned)) def arm_uint_div_emulator(a, b): @@ -43,7 +43,7 @@ "pypy__arm_uint_div", [lltype.Unsigned, lltype.Unsigned], lltype.Unsigned, _callable=arm_uint_div_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) arm_int_mod_sign = arm_int_div_sign @@ -60,5 +60,5 @@ "pypy__arm_int_mod", [lltype.Signed, lltype.Signed], lltype.Signed, _callable=arm_int_mod_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -84,9 +84,10 @@ self.datablockwrapper = None def setup(self, looptoken, operations): - self.cpu.gc_ll_descr.rewrite_assembler(self.cpu, operations) + self.current_clt = looptoken.compiled_loop_token + self.cpu.gc_ll_descr.rewrite_assembler(self.cpu, + operations, self.current_clt.allgcrefs) assert self.memcpy_addr != 0, 'setup_once() not called?' - self.current_clt = looptoken.compiled_loop_token self.mc = ARMv7Builder() self.pending_guards = [] assert self.datablockwrapper is None @@ -558,6 +559,7 @@ def assemble_loop(self, inputargs, operations, looptoken, log): clt = CompiledLoopToken(self.cpu, looptoken.number) + clt.allgcrefs = [] looptoken.compiled_loop_token = clt self.setup(looptoken, operations) diff --git a/pypy/jit/backend/arm/opassembler.py b/pypy/jit/backend/arm/opassembler.py --- a/pypy/jit/backend/arm/opassembler.py +++ b/pypy/jit/backend/arm/opassembler.py @@ -446,6 +446,17 @@ if we_are_translated(): cls = self.cpu.gc_ll_descr.has_write_barrier_class() assert cls is not None and isinstance(descr, cls) + + opnum = op.getopnum() + if opnum == rop.COND_CALL_GC_WB: + N = 2 + addr = descr.get_write_barrier_fn(self.cpu) + elif opnum == rop.COND_CALL_GC_WB_ARRAY: + N = 3 + addr = descr.get_write_barrier_from_array_fn(self.cpu) + assert addr != 0 + else: + raise AssertionError(opnum) loc_base = arglocs[0] self.mc.LDR_ri(r.ip.value, loc_base.value) # calculate the shift value to rotate the ofs according to the ARM @@ -463,9 +474,17 @@ # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. - with saved_registers(self.mc, r.caller_resp): - remap_frame_layout(self, arglocs, [r.r0, r.r1], r.ip) - self.mc.BL(descr.get_write_barrier_fn(self.cpu)) + with saved_registers(self.mc, r.caller_resp, regalloc=regalloc): + if N == 2: + callargs = [r.r0, r.r1] + else: + callargs = [r.r0, r.r1, r.r2] + remap_frame_layout(self, arglocs, callargs, r.ip) + func = self.cpu.cast_adr_to_int(addr) + # + # misaligned stack in the call, but it's ok because the write barrier + # is not going to call anything more. + self.mc.BL(func) # patch the JZ above offset = self.mc.currpos() - jz_location @@ -473,6 +492,7 @@ pmc.ADD_ri(r.pc.value, r.pc.value, offset - PC_OFFSET, cond=c.EQ) return fcond + emit_op_cond_call_gc_wb_array = emit_op_cond_call_gc_wb class FieldOpAssembler(object): diff --git a/pypy/jit/backend/arm/regalloc.py b/pypy/jit/backend/arm/regalloc.py --- a/pypy/jit/backend/arm/regalloc.py +++ b/pypy/jit/backend/arm/regalloc.py @@ -965,16 +965,20 @@ def prepare_op_cond_call_gc_wb(self, op, fcond): assert op.result is None - args = op.getarglist() - loc_newvalue, box_newvalue = self._ensure_value_is_boxed(op.getarg(1), args) - # ^^^ we force loc_newvalue in a reg (unless it's a Const), - # because it will be needed anyway by the following setfield_gc. - # It avoids loading it twice from the memory. - loc_base, box_base = self._ensure_value_is_boxed(op.getarg(0), args) - arglocs = [loc_base, loc_newvalue] - self.rm.possibly_free_vars([box_newvalue, box_base]) + N = op.numargs() + # we force all arguments in a reg (unless they are Consts), + # because it will be needed anyway by the following setfield_gc + # or setarrayitem_gc. It avoids loading it twice from the memory. + arglocs = [] + argboxes = [] + for i in range(N): + loc, box = self._ensure_value_is_boxed(op.getarg(i), arglocs) + arglocs.append(loc) + argboxes.append(box) + self.rm.possibly_free_vars(argboxes) return arglocs + prepare_op_cond_call_gc_wb_array = prepare_op_cond_call_gc_wb def prepare_op_force_token(self, op, fcond): res_loc = self.force_allocate_reg(op.result) diff --git a/pypy/jit/backend/arm/test/test_runner.py b/pypy/jit/backend/arm/test/test_runner.py --- a/pypy/jit/backend/arm/test/test_runner.py +++ b/pypy/jit/backend/arm/test/test_runner.py @@ -58,9 +58,6 @@ expected = [3, 7, 11, 15, 19, 23, 27, 3, 7, 11, 15, 19, 23, 27] assert output == expected - def test_cond_call_gc_wb(self, *args): - py.test.skip('needs gc support') - def test_redirect_call_assember(self): called = [] def assembler_helper(failindex, virtualizable): diff --git a/pypy/jit/backend/arm/test/test_zrpy_gc.py b/pypy/jit/backend/arm/test/test_zrpy_gc.py --- a/pypy/jit/backend/arm/test/test_zrpy_gc.py +++ b/pypy/jit/backend/arm/test/test_zrpy_gc.py @@ -1,8 +1,7 @@ """ -This is a test that translates a complete JIT to C and runs it. It is -not testing much, expect that it basically works. What it *is* testing, -however, is the correct handling of GC, i.e. if objects are freed as -soon as possible (at least in a simple case). +This is a test that translates a complete JIT together with a GC and runs it. +It is testing that the GC-dependent aspects basically work, mostly the mallocs +and the various cases of write barrier. """ import weakref @@ -10,11 +9,10 @@ from pypy.annotation import policy as annpolicy from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe from pypy.jit.backend.arm.runner import ArmCPU from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -85,7 +83,7 @@ # return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2} -def compile(f, gc, **kwds): +def compile(f, gc, enable_opts='', **kwds): from pypy.annotation.listdef import s_list_of_strings from pypy.translator.translator import TranslationContext from pypy.jit.metainterp.warmspot import apply_jit @@ -109,14 +107,14 @@ old_value[obj, attr] = getattr(obj, attr) setattr(obj, attr, value) # - apply_jit(t, enable_opts='') + apply_jit(t, enable_opts=enable_opts) # finally: for (obj, attr), oldvalue in old_value.items(): setattr(obj, attr, oldvalue) cbuilder = genc.CStandaloneBuilder(t, f, t.config) - cbuilder.generate_source() + cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) cbuilder.compile() return cbuilder @@ -153,8 +151,10 @@ # ______________________________________________________________________ -class CompileFrameworkTests(object): - # Test suite using (so far) the minimark GC. + +class BaseFrameworkTests(object): + compile_kwds = {} + def setup_class(cls): funcs = [] name_to_func = {} @@ -204,7 +204,8 @@ try: GcLLDescr_framework.DEBUG = True cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC, - gcrootfinder=cls.gcrootfinder, jit=True) + gcrootfinder=cls.gcrootfinder, jit=True, + **cls.compile_kwds) finally: GcLLDescr_framework.DEBUG = OLD_DEBUG @@ -223,32 +224,36 @@ def run_orig(self, name, n, x): self.main_allfuncs(name, n, x) - def define_libffi_workaround(cls): - # XXX: this is a workaround for a bug in database.py. It seems that - # the problem is triggered by optimizeopt/fficall.py, and in - # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in - # these tests, that line is the only place where libffi.Func is - # referenced. - # - # The problem occurs because the gctransformer tries to annotate a - # low-level helper to call the __del__ of libffi.Func when it's too - # late. - # - # This workaround works by forcing the annotator (and all the rest of - # the toolchain) to see libffi.Func in a "proper" context, not just as - # the target of cast_base_ptr_to_instance. Note that the function - # below is *never* called by any actual test, it's just annotated. - # - from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain - libc_name = get_libc_name() - def f(n, x, *args): - libc = CDLL(libc_name) - ptr = libc.getpointer('labs', [types.slong], types.slong) - chain = ArgChain() - chain.arg(n) - n = ptr.call(chain, lltype.Signed) - return (n, x) + args - return None, f, None + +class CompileFrameworkTests(BaseFrameworkTests): + # Test suite using (so far) the minimark GC. + +## def define_libffi_workaround(cls): +## # XXX: this is a workaround for a bug in database.py. It seems that +## # the problem is triggered by optimizeopt/fficall.py, and in +## # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in +## # these tests, that line is the only place where libffi.Func is +## # referenced. +## # +## # The problem occurs because the gctransformer tries to annotate a +## # low-level helper to call the __del__ of libffi.Func when it's too +## # late. +## # +## # This workaround works by forcing the annotator (and all the rest of +## # the toolchain) to see libffi.Func in a "proper" context, not just as +## # the target of cast_base_ptr_to_instance. Note that the function +## # below is *never* called by any actual test, it's just annotated. +## # +## from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain +## libc_name = get_libc_name() +## def f(n, x, *args): +## libc = CDLL(libc_name) +## ptr = libc.getpointer('labs', [types.slong], types.slong) +## chain = ArgChain() +## chain.arg(n) +## n = ptr.call(chain, lltype.Signed) +## return (n, x) + args +## return None, f, None def define_compile_framework_1(cls): # a moving GC. Supports malloc_varsize_nonmovable. Simple test, works @@ -455,6 +460,73 @@ def test_compile_framework_7(self): self.run('compile_framework_7') + def define_compile_framework_8(cls): + # Array of pointers, of unknown length (test write_barrier_from_array) + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + l = [None] * (16 + (n & 7)) + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[8] = X(n+70) + l[9] = X(n+80) + l[10] = X(n+90) + l[11] = X(n+100) + l[12] = X(n+110) + l[13] = X(n+120) + l[14] = X(n+130) + l[15] = X(n+140) + if n < 1800: + check(len(l) == 16 + (n & 7)) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[8].x == n+70) + check(l[9].x == n+80) + check(l[10].x == n+90) + check(l[11].x == n+100) + check(l[12].x == n+110) + check(l[13].x == n+120) + check(l[14].x == n+130) + check(l[15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 16) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[8].x == 72) + check(l[9].x == 82) + check(l[10].x == 92) + check(l[11].x == 102) + check(l[12].x == 112) + check(l[13].x == 122) + check(l[14].x == 132) + check(l[15].x == 142) + return before, f, after + + def test_compile_framework_8(self): + self.run('compile_framework_8') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) @@ -492,7 +564,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -136,6 +136,7 @@ 'call' : (('ref', 'varargs'), 'intorptr'), 'call_assembler' : (('varargs',), 'intorptr'), 'cond_call_gc_wb' : (('ptr', 'ptr'), None), + 'cond_call_gc_wb_array': (('ptr', 'int', 'ptr'), None), 'oosend' : (('varargs',), 'intorptr'), 'oosend_pure' : (('varargs',), 'intorptr'), 'guard_true' : (('bool',), None), @@ -600,15 +601,15 @@ # return _op_default_implementation - def op_debug_merge_point(self, _, value, recdepth): + def op_debug_merge_point(self, _, *args): from pypy.jit.metainterp.warmspot import get_stats - loc = ConstPtr(value)._get_str() try: stats = get_stats() except AttributeError: pass else: - stats.add_merge_point_location(loc) + stats.add_merge_point_location(args[1:]) + pass def op_guard_true(self, _, value): if not value: @@ -820,6 +821,12 @@ raise NotImplementedError def op_call(self, calldescr, func, *args): + return self._do_call(calldescr, func, args, call_with_llptr=False) + + def op_call_release_gil(self, calldescr, func, *args): + return self._do_call(calldescr, func, args, call_with_llptr=True) + + def _do_call(self, calldescr, func, args, call_with_llptr): global _last_exception assert _last_exception is None, "exception left behind" assert _call_args_i == _call_args_r == _call_args_f == [] @@ -838,7 +845,8 @@ else: raise TypeError(x) try: - return _do_call_common(func, args_in_order, calldescr) + return _do_call_common(func, args_in_order, calldescr, + call_with_llptr) except LLException, lle: _last_exception = lle d = {'v': None, @@ -850,6 +858,9 @@ def op_cond_call_gc_wb(self, descr, a, b): py.test.skip("cond_call_gc_wb not supported") + def op_cond_call_gc_wb_array(self, descr, a, b, c): + py.test.skip("cond_call_gc_wb_array not supported") + def op_oosend(self, descr, obj, *args): raise NotImplementedError("oosend for lltype backend??") @@ -1480,17 +1491,20 @@ 'v': lltype.Void, } -def _do_call_common(f, args_in_order=None, calldescr=None): +def _do_call_common(f, args_in_order=None, calldescr=None, + call_with_llptr=False): ptr = llmemory.cast_int_to_adr(f).ptr PTR = lltype.typeOf(ptr) if PTR == rffi.VOIDP: # it's a pointer to a C function, so we don't have a precise # signature: create one from the descr + assert call_with_llptr is True ARGS = map(kind2TYPE.get, calldescr.arg_types) RESULT = kind2TYPE[calldescr.typeinfo] FUNC = lltype.FuncType(ARGS, RESULT) func_to_call = rffi.cast(lltype.Ptr(FUNC), ptr) else: + assert call_with_llptr is False FUNC = PTR.TO ARGS = FUNC.ARGS func_to_call = ptr._obj._callable diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -134,7 +134,7 @@ old, oldindex = faildescr._compiled_fail llimpl.compile_redirect_fail(old, oldindex, c) - def compile_loop(self, inputargs, operations, looptoken, log=True): + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): """In a real assembler backend, this should assemble the given list of operations. Here we just generate a similar CompiledLoop instance. The code here is RPython, whereas the code in llimpl diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -1,5 +1,6 @@ import py from pypy.rpython.lltypesystem import lltype, rffi, llmemory, rclass +from pypy.rpython.lltypesystem.lloperation import llop from pypy.jit.backend.llsupport import symbolic, support from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr from pypy.jit.metainterp.history import BasicFailDescr, LoopToken, BoxFloat @@ -45,6 +46,8 @@ size = 0 # help translation is_immutable = False + tid = llop.combine_ushort(lltype.Signed, 0, 0) + def __init__(self, size, count_fields_if_immut=-1): self.size = size self.count_fields_if_immut = count_fields_if_immut @@ -149,6 +152,7 @@ class BaseArrayDescr(AbstractDescr): _clsname = '' + tid = llop.combine_ushort(lltype.Signed, 0, 0) def get_base_size(self, translate_support_code): basesize, _, _ = symbolic.get_array_token(_A, translate_support_code) @@ -263,6 +267,9 @@ def __repr__(self): res = '%s(%s)' % (self.__class__.__name__, self.arg_classes) + extraeffect = getattr(self.extrainfo, 'extraeffect', None) + if extraeffect is not None: + res += ' EF=%r' % extraeffect oopspecindex = getattr(self.extrainfo, 'oopspecindex', 0) if oopspecindex: from pypy.jit.codewriter.effectinfo import EffectInfo diff --git a/pypy/jit/backend/llsupport/ffisupport.py b/pypy/jit/backend/llsupport/ffisupport.py --- a/pypy/jit/backend/llsupport/ffisupport.py +++ b/pypy/jit/backend/llsupport/ffisupport.py @@ -3,13 +3,16 @@ from pypy.jit.backend.llsupport.descr import DynamicIntCallDescr, NonGcPtrCallDescr,\ FloatCallDescr, VoidCallDescr +class UnsupportedKind(Exception): + pass + def get_call_descr_dynamic(ffi_args, ffi_result, extrainfo=None): """Get a call descr: the types of result and args are represented by rlib.libffi.types.*""" try: reskind = get_ffi_type_kind(ffi_result) argkinds = [get_ffi_type_kind(arg) for arg in ffi_args] - except KeyError: + except UnsupportedKind: return None # ?? arg_classes = ''.join(argkinds) if reskind == history.INT: @@ -33,7 +36,7 @@ return history.FLOAT elif kind == 'v': return history.VOID - assert False, "Unsupported kind '%s'" % kind + raise UnsupportedKind("Unsupported kind '%s'" % kind) def is_ffi_type_signed(ffi_type): from pypy.rlib.libffi import types diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -34,7 +34,7 @@ pass def do_write_barrier(self, gcref_struct, gcref_newptr): pass - def rewrite_assembler(self, cpu, operations): + def rewrite_assembler(self, cpu, operations, gcrefs_output_list): return operations def can_inline_malloc(self, descr): return False @@ -146,78 +146,6 @@ # All code below is for the hybrid or minimark GC -class GcRefList: - """Handles all references from the generated assembler to GC objects. - This is implemented as a nonmovable, but GC, list; the assembler contains - code that will (for now) always read from this list.""" - - GCREF_LIST = lltype.GcArray(llmemory.GCREF) # followed by the GC - - HASHTABLE = rffi.CArray(llmemory.Address) # ignored by the GC - HASHTABLE_BITS = 10 - HASHTABLE_SIZE = 1 << HASHTABLE_BITS - - def initialize(self): - if we_are_translated(): n = 2000 - else: n = 10 # tests only - self.list = self.alloc_gcref_list(n) - self.nextindex = 0 - self.oldlists = [] - # A pseudo dictionary: it is fixed size, and it may contain - # random nonsense after a collection moved the objects. It is only - # used to avoid too many duplications in the GCREF_LISTs. - self.hashtable = lltype.malloc(self.HASHTABLE, - self.HASHTABLE_SIZE+1, - flavor='raw', track_allocation=False) - dummy = lltype.direct_ptradd(lltype.direct_arrayitems(self.hashtable), - self.HASHTABLE_SIZE) - dummy = llmemory.cast_ptr_to_adr(dummy) - for i in range(self.HASHTABLE_SIZE+1): - self.hashtable[i] = dummy - - def alloc_gcref_list(self, n): - # Important: the GRREF_LISTs allocated are *non-movable*. This - # requires support in the gc (hybrid GC or minimark GC so far). - if we_are_translated(): - list = rgc.malloc_nonmovable(self.GCREF_LIST, n) - assert list, "malloc_nonmovable failed!" - else: - list = lltype.malloc(self.GCREF_LIST, n) # for tests only - return list - - def get_address_of_gcref(self, gcref): - assert lltype.typeOf(gcref) == llmemory.GCREF - # first look in the hashtable, using an inexact hash (fails after - # the object moves) - addr = llmemory.cast_ptr_to_adr(gcref) - hash = llmemory.cast_adr_to_int(addr, "forced") - hash -= hash >> self.HASHTABLE_BITS - hash &= self.HASHTABLE_SIZE - 1 - addr_ref = self.hashtable[hash] - # the following test is safe anyway, because the addresses found - # in the hashtable are always the addresses of nonmovable stuff - # ('addr_ref' is an address inside self.list, not directly the - # address of a real moving GC object -- that's 'addr_ref.address[0]'.) - if addr_ref.address[0] == addr: - return addr_ref - # if it fails, add an entry to the list - if self.nextindex == len(self.list): - # reallocate first, increasing a bit the size every time - self.oldlists.append(self.list) - self.list = self.alloc_gcref_list(len(self.list) // 4 * 5) - self.nextindex = 0 - # add it - index = self.nextindex - self.list[index] = gcref - addr_ref = lltype.direct_ptradd(lltype.direct_arrayitems(self.list), - index) - addr_ref = llmemory.cast_ptr_to_adr(addr_ref) - self.nextindex = index + 1 - # record it in the hashtable - self.hashtable[hash] = addr_ref - return addr_ref - - class GcRootMap_asmgcc(object): """Handles locating the stack roots in the assembler. This is the class supporting --gcrootfinder=asmgcc. @@ -527,6 +455,7 @@ def __init__(self, gc_ll_descr): self.llop1 = gc_ll_descr.llop1 self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR + self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR self.fielddescr_tid = get_field_descr(gc_ll_descr, gc_ll_descr.GCClass.HDR, 'tid') self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG @@ -546,6 +475,14 @@ funcaddr = llmemory.cast_ptr_to_adr(funcptr) return cpu.cast_adr_to_int(funcaddr) + def get_write_barrier_from_array_fn(self, cpu): + # returns a function with arguments [array, index, newvalue] + llop1 = self.llop1 + funcptr = llop1.get_write_barrier_from_array_failing_case( + self.WB_ARRAY_FUNCPTR) + funcaddr = llmemory.cast_ptr_to_adr(funcptr) + return cpu.cast_adr_to_int(funcaddr) # this may return 0 + class GcLLDescr_framework(GcLLDescription): DEBUG = False # forced to True by x86/test/test_zrpy_gc.py @@ -559,7 +496,7 @@ self.translator = translator self.llop1 = llop1 - # we need the hybrid or minimark GC for GcRefList.alloc_gcref_list() + # we need the hybrid or minimark GC for rgc._make_sure_does_not_move() # to work if gcdescr.config.translation.gc not in ('hybrid', 'minimark'): raise NotImplementedError("--gc=%s not implemented with the JIT" % @@ -574,8 +511,6 @@ " with the JIT" % (name,)) gcrootmap = cls(gcdescr) self.gcrootmap = gcrootmap - self.gcrefs = GcRefList() - self.single_gcref_descr = GcPtrFieldDescr('', 0) # make a TransformerLayoutBuilder and save it on the translator # where it can be fished and reused by the FrameworkGCTransformer @@ -618,6 +553,8 @@ [lltype.Signed, lltype.Signed], llmemory.GCREF)) self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType( [llmemory.Address, llmemory.Address], lltype.Void)) + self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType( + [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void)) self.write_barrier_descr = WriteBarrierDescr(self) # def malloc_array(itemsize, tid, num_elem): @@ -710,7 +647,6 @@ return rffi.cast(lltype.Signed, fptr) def initialize(self): - self.gcrefs.initialize() self.gcrootmap.initialize() def init_size_descr(self, S, descr): @@ -772,54 +708,32 @@ funcptr(llmemory.cast_ptr_to_adr(gcref_struct), llmemory.cast_ptr_to_adr(gcref_newptr)) - def replace_constptrs_with_getfield_raw(self, cpu, newops, op): - # xxx some performance issue here - newargs = [None] * op.numargs() - needs_copy = False + def record_constptrs(self, op, gcrefs_output_list): for i in range(op.numargs()): v = op.getarg(i) - newargs[i] = v if isinstance(v, ConstPtr) and bool(v.value): - addr = self.gcrefs.get_address_of_gcref(v.value) - # ^^^even for non-movable objects, to record their presence - if rgc.can_move(v.value): - box = BoxPtr(v.value) - addr = cpu.cast_adr_to_int(addr) - newops.append(ResOperation(rop.GETFIELD_RAW, - [ConstInt(addr)], box, - self.single_gcref_descr)) - newargs[i] = box - needs_copy = True - # - if needs_copy: - return op.copy_and_change(op.getopnum(), args=newargs) - else: - return op + p = v.value + rgc._make_sure_does_not_move(p) + gcrefs_output_list.append(p) - - def rewrite_assembler(self, cpu, operations): + def rewrite_assembler(self, cpu, operations, gcrefs_output_list): # Perform two kinds of rewrites in parallel: # # - Add COND_CALLs to the write barrier before SETFIELD_GC and # SETARRAYITEM_GC operations. # - # - Remove all uses of ConstPtrs away from the assembler. - # Idea: when running on a moving GC, we can't (easily) encode - # the ConstPtrs in the assembler, because they can move at any - # point in time. Instead, we store them in 'gcrefs.list', a GC - # but nonmovable list; and here, we modify 'operations' to - # replace direct usage of ConstPtr with a BoxPtr loaded by a - # GETFIELD_RAW from the array 'gcrefs.list'. + # - Record the ConstPtrs from the assembler. # newops = [] + known_lengths = {} # we can only remember one malloc since the next malloc can possibly # collect last_malloc = None for op in operations: if op.getopnum() == rop.DEBUG_MERGE_POINT: continue - # ---------- replace ConstPtrs with GETFIELD_RAW ---------- - op = self.replace_constptrs_with_getfield_raw(cpu, newops, op) + # ---------- record the ConstPtrs ---------- + self.record_constptrs(op, gcrefs_output_list) if op.is_malloc(): last_malloc = op.result elif op.can_malloc(): @@ -842,10 +756,14 @@ v = op.getarg(2) if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and bool(v.value)): # store a non-NULL - # XXX detect when we should produce a - # write_barrier_from_array - self._gen_write_barrier(newops, op.getarg(0), v) + self._gen_write_barrier_array(newops, op.getarg(0), + op.getarg(1), v, + cpu, known_lengths) op = op.copy_and_change(rop.SETARRAYITEM_RAW) + elif op.getopnum() == rop.NEW_ARRAY: + v_length = op.getarg(0) + if isinstance(v_length, ConstInt): + known_lengths[op.result] = v_length.getint() # ---------- newops.append(op) return newops @@ -855,6 +773,24 @@ newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None, descr=self.write_barrier_descr)) + def _gen_write_barrier_array(self, newops, v_base, v_index, v_value, + cpu, known_lengths): + if self.write_barrier_descr.get_write_barrier_from_array_fn(cpu) != 0: + # If we know statically the length of 'v', and it is not too + # big, then produce a regular write_barrier. If it's unknown or + # too big, produce instead a write_barrier_from_array. + LARGE = 130 + length = known_lengths.get(v_base, LARGE) + if length >= LARGE: + # unknown or too big: produce a write_barrier_from_array + args = [v_base, v_index, v_value] + newops.append(ResOperation(rop.COND_CALL_GC_WB_ARRAY, args, + None, + descr=self.write_barrier_descr)) + return + # fall-back case: produce a write_barrier + self._gen_write_barrier(newops, v_base, v_value) + def can_inline_malloc(self, descr): assert isinstance(descr, BaseSizeDescr) if descr.size < self.max_size_of_young_obj: diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py --- a/pypy/jit/backend/llsupport/regalloc.py +++ b/pypy/jit/backend/llsupport/regalloc.py @@ -38,6 +38,11 @@ self.frame_depth += size return newloc + def reserve_location_in_frame(self, size): + frame_depth = self.frame_depth + self.frame_depth += size + return frame_depth + # abstract methods that need to be overwritten for specific assemblers @staticmethod def frame_pos(loc, type): diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py --- a/pypy/jit/backend/llsupport/test/test_gc.py +++ b/pypy/jit/backend/llsupport/test/test_gc.py @@ -9,7 +9,7 @@ from pypy.jit.metainterp.resoperation import get_deep_immutable_oplist from pypy.jit.tool.oparser import parse from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists def test_boehm(): gc_ll_descr = GcLLDescr_boehm(None, None, None) @@ -49,19 +49,6 @@ # ____________________________________________________________ -def test_GcRefList(): - S = lltype.GcStruct('S') - order = range(50) * 4 - random.shuffle(order) - allocs = [lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S)) - for i in range(50)] - allocs = [allocs[i] for i in order] - # - gcrefs = GcRefList() - gcrefs.initialize() - addrs = [gcrefs.get_address_of_gcref(ptr) for ptr in allocs] - for i in range(len(allocs)): - assert addrs[i].address[0] == llmemory.cast_ptr_to_adr(allocs[i]) class TestGcRootMapAsmGcc: @@ -288,6 +275,18 @@ def get_write_barrier_failing_case(self, FPTRTYPE): return llhelper(FPTRTYPE, self._write_barrier_failing_case) + _have_wb_from_array = False + + def _write_barrier_from_array_failing_case(self, adr_struct, v_index): + self.record.append(('barrier_from_array', adr_struct, v_index)) + + def get_write_barrier_from_array_failing_case(self, FPTRTYPE): + if self._have_wb_from_array: + return llhelper(FPTRTYPE, + self._write_barrier_from_array_failing_case) + else: + return lltype.nullptr(FPTRTYPE.TO) + class TestFramework(object): gc = 'hybrid' @@ -303,9 +302,20 @@ config = config_ class FakeCPU(object): def cast_adr_to_int(self, adr): - ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR) - assert ptr._obj._callable == llop1._write_barrier_failing_case - return 42 + if not adr: + return 0 + try: + ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR) + assert ptr._obj._callable == \ + llop1._write_barrier_failing_case + return 42 + except lltype.InvalidCast: + ptr = llmemory.cast_adr_to_ptr( + adr, gc_ll_descr.WB_ARRAY_FUNCPTR) + assert ptr._obj._callable == \ + llop1._write_barrier_from_array_failing_case + return 43 + gcdescr = get_description(config_) translator = FakeTranslator() llop1 = FakeLLOp() @@ -414,11 +424,11 @@ ResOperation(rop.DEBUG_MERGE_POINT, ['dummy', 2], None), ] gc_ll_descr = self.gc_ll_descr - operations = gc_ll_descr.rewrite_assembler(None, operations) + operations = gc_ll_descr.rewrite_assembler(None, operations, []) assert len(operations) == 0 def test_rewrite_assembler_1(self): - # check rewriting of ConstPtrs + # check recording of ConstPtrs class MyFakeCPU(object): def cast_adr_to_int(self, adr): assert adr == "some fake address" @@ -438,56 +448,12 @@ ] gc_ll_descr = self.gc_ll_descr gc_ll_descr.gcrefs = MyFakeGCRefList() + gcrefs = [] operations = get_deep_immutable_oplist(operations) - operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) - assert len(operations) == 2 - assert operations[0].getopnum() == rop.GETFIELD_RAW - assert operations[0].getarg(0) == ConstInt(43) - assert operations[0].getdescr() == gc_ll_descr.single_gcref_descr - v_box = operations[0].result - assert isinstance(v_box, BoxPtr) - assert operations[1].getopnum() == rop.PTR_EQ - assert operations[1].getarg(0) == v_random_box - assert operations[1].getarg(1) == v_box - assert operations[1].result == v_result - - def test_rewrite_assembler_1_cannot_move(self): - # check rewriting of ConstPtrs - class MyFakeCPU(object): - def cast_adr_to_int(self, adr): - xxx # should not be called - class MyFakeGCRefList(object): - def get_address_of_gcref(self, s_gcref1): - seen.append(s_gcref1) - assert s_gcref1 == s_gcref - return "some fake address" - seen = [] - S = lltype.GcStruct('S') - s = lltype.malloc(S) - s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s) - v_random_box = BoxPtr() - v_result = BoxInt() - operations = [ - ResOperation(rop.PTR_EQ, [v_random_box, ConstPtr(s_gcref)], - v_result), - ] - gc_ll_descr = self.gc_ll_descr - gc_ll_descr.gcrefs = MyFakeGCRefList() - old_can_move = rgc.can_move - operations = get_deep_immutable_oplist(operations) - try: - rgc.can_move = lambda s: False - operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations) - finally: - rgc.can_move = old_can_move - assert len(operations) == 1 - assert operations[0].getopnum() == rop.PTR_EQ - assert operations[0].getarg(0) == v_random_box - assert operations[0].getarg(1) == ConstPtr(s_gcref) - assert operations[0].result == v_result - # check that s_gcref gets added to the list anyway, to make sure - # that the GC sees it - assert seen == [s_gcref] + operations2 = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations, + gcrefs) + assert operations2 == operations + assert gcrefs == [s_gcref] def test_rewrite_assembler_2(self): # check write barriers before SETFIELD_GC @@ -500,7 +466,8 @@ ] gc_ll_descr = self.gc_ll_descr operations = get_deep_immutable_oplist(operations) - operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations, + []) assert len(operations) == 2 # assert operations[0].getopnum() == rop.COND_CALL_GC_WB @@ -515,29 +482,93 @@ def test_rewrite_assembler_3(self): # check write barriers before SETARRAYITEM_GC - v_base = BoxPtr() - v_index = BoxInt() - v_value = BoxPtr() - array_descr = AbstractDescr() - operations = [ - ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value], None, - descr=array_descr), - ] - gc_ll_descr = self.gc_ll_descr - operations = get_deep_immutable_oplist(operations) - operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) - assert len(operations) == 2 - # - assert operations[0].getopnum() == rop.COND_CALL_GC_WB - assert operations[0].getarg(0) == v_base - assert operations[0].getarg(1) == v_value - assert operations[0].result is None - # - assert operations[1].getopnum() == rop.SETARRAYITEM_RAW - assert operations[1].getarg(0) == v_base - assert operations[1].getarg(1) == v_index - assert operations[1].getarg(2) == v_value - assert operations[1].getdescr() == array_descr + for v_new_length in (None, ConstInt(5), ConstInt(5000), BoxInt()): + v_base = BoxPtr() + v_index = BoxInt() + v_value = BoxPtr() + array_descr = AbstractDescr() + operations = [ + ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value], + None, descr=array_descr), + ] + if v_new_length is not None: + operations.insert(0, ResOperation(rop.NEW_ARRAY, + [v_new_length], v_base, + descr=array_descr)) + # we need to insert another, unrelated NEW_ARRAY here + # to prevent the initialization_store optimization + operations.insert(1, ResOperation(rop.NEW_ARRAY, + [ConstInt(12)], BoxPtr(), + descr=array_descr)) + gc_ll_descr = self.gc_ll_descr + operations = get_deep_immutable_oplist(operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) + if v_new_length is not None: + assert operations[0].getopnum() == rop.NEW_ARRAY + assert operations[1].getopnum() == rop.NEW_ARRAY + del operations[:2] + assert len(operations) == 2 + # + assert operations[0].getopnum() == rop.COND_CALL_GC_WB + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_value + assert operations[0].result is None + # + assert operations[1].getopnum() == rop.SETARRAYITEM_RAW + assert operations[1].getarg(0) == v_base + assert operations[1].getarg(1) == v_index + assert operations[1].getarg(2) == v_value + assert operations[1].getdescr() == array_descr + + def test_rewrite_assembler_4(self): + # check write barriers before SETARRAYITEM_GC, + # if we have actually a write_barrier_from_array. + self.llop1._have_wb_from_array = True + for v_new_length in (None, ConstInt(5), ConstInt(5000), BoxInt()): + v_base = BoxPtr() + v_index = BoxInt() + v_value = BoxPtr() + array_descr = AbstractDescr() + operations = [ + ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value], + None, descr=array_descr), + ] + if v_new_length is not None: + operations.insert(0, ResOperation(rop.NEW_ARRAY, + [v_new_length], v_base, + descr=array_descr)) + # we need to insert another, unrelated NEW_ARRAY here + # to prevent the initialization_store optimization + operations.insert(1, ResOperation(rop.NEW_ARRAY, + [ConstInt(12)], BoxPtr(), + descr=array_descr)) + gc_ll_descr = self.gc_ll_descr + operations = get_deep_immutable_oplist(operations) + operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) + if v_new_length is not None: + assert operations[0].getopnum() == rop.NEW_ARRAY + assert operations[1].getopnum() == rop.NEW_ARRAY + del operations[:2] + assert len(operations) == 2 + # + if isinstance(v_new_length, ConstInt) and v_new_length.value < 130: + assert operations[0].getopnum() == rop.COND_CALL_GC_WB + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_value + else: + assert operations[0].getopnum() == rop.COND_CALL_GC_WB_ARRAY + assert operations[0].getarg(0) == v_base + assert operations[0].getarg(1) == v_index + assert operations[0].getarg(2) == v_value + assert operations[0].result is None + # + assert operations[1].getopnum() == rop.SETARRAYITEM_RAW + assert operations[1].getarg(0) == v_base + assert operations[1].getarg(1) == v_index + assert operations[1].getarg(2) == v_value + assert operations[1].getdescr() == array_descr def test_rewrite_assembler_initialization_store(self): S = lltype.GcStruct('S', ('parent', OBJECT), @@ -558,7 +589,8 @@ jump() """, namespace=locals()) operations = get_deep_immutable_oplist(ops.operations) - operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) equaloplists(operations, expected.operations) def test_rewrite_assembler_initialization_store_2(self): @@ -583,7 +615,8 @@ jump() """, namespace=locals()) operations = get_deep_immutable_oplist(ops.operations) - operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) equaloplists(operations, expected.operations) def test_rewrite_assembler_initialization_store_3(self): @@ -602,7 +635,8 @@ jump() """, namespace=locals()) operations = get_deep_immutable_oplist(ops.operations) - operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, operations) + operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, + operations, []) equaloplists(operations, expected.operations) class TestFrameworkMiniMark(TestFramework): diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py --- a/pypy/jit/backend/model.py +++ b/pypy/jit/backend/model.py @@ -58,7 +58,7 @@ """Called once by the front-end when the program stops.""" pass - def compile_loop(self, inputargs, operations, looptoken, log=True): + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): """Assemble the given loop. Should create and attach a fresh CompiledLoopToken to looptoken.compiled_loop_token and stick extra attributes diff --git a/pypy/jit/backend/test/calling_convention_test.py b/pypy/jit/backend/test/calling_convention_test.py --- a/pypy/jit/backend/test/calling_convention_test.py +++ b/pypy/jit/backend/test/calling_convention_test.py @@ -57,146 +57,146 @@ return ConstInt(heaptracker.adr2int(addr)) def test_call_aligned_with_spilled_values(self): - from pypy.rlib.libffi import types - cpu = self.cpu - if not cpu.supports_floats: - py.test.skip('requires floats') + from pypy.rlib.libffi import types + cpu = self.cpu + if not cpu.supports_floats: + py.test.skip('requires floats') - def func(*args): - return float(sum(args)) + def func(*args): + return float(sum(args)) - F = lltype.Float - I = lltype.Signed - floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] - ints = [7, 11, 23, 13, -42, 1111, 95, 1] - for case in range(256): - local_floats = list(floats) - local_ints = list(ints) - args = [] - spills = [] - funcargs = [] - float_count = 0 - int_count = 0 - for i in range(8): - if case & (1< 0 + del glob.lst[:] + + cpu = self.cpu + func_adr = llmemory.cast_ptr_to_adr(c_qsort.funcsym) + funcbox = ConstInt(heaptracker.adr2int(func_adr)) + calldescr = cpu.calldescrof_dynamic([types.pointer, types_size_t, + types_size_t, types.pointer], + types.void) + i0 = BoxInt() + i1 = BoxInt() + i2 = BoxInt() + i3 = BoxInt() + tok = BoxInt() + faildescr = BasicFailDescr(1) + ops = [ + ResOperation(rop.CALL_RELEASE_GIL, [funcbox, i0, i1, i2, i3], None, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [], None, descr=BasicFailDescr(0)) + ] + ops[1].setfailargs([]) + looptoken = LoopToken() + self.cpu.compile_loop([i0, i1, i2, i3], ops, looptoken) + self.cpu.set_future_value_int(0, rffi.cast(lltype.Signed, raw)) + self.cpu.set_future_value_int(1, 2) + self.cpu.set_future_value_int(2, 4) + self.cpu.set_future_value_int(3, rffi.cast(lltype.Signed, fn)) + assert glob.lst == [] + fail = self.cpu.execute_token(looptoken) + assert fail.identifier == 0 + assert len(glob.lst) > 0 + lltype.free(raw, flavor='raw') + def test_guard_not_invalidated(self): cpu = self.cpu i0 = BoxInt() diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -128,6 +128,8 @@ if gc_ll_descr.get_malloc_slowpath_addr is not None: self._build_malloc_slowpath() self._build_stack_check_slowpath() + if gc_ll_descr.gcrootmap: + self._build_release_gil(gc_ll_descr.gcrootmap) debug_start('jit-backend-counts') self.set_debug(have_debug_prints()) debug_stop('jit-backend-counts') @@ -306,7 +308,66 @@ rawstart = mc.materialize(self.cpu.asmmemmgr, []) self.stack_check_slowpath = rawstart - def assemble_loop(self, inputargs, operations, looptoken, log): + @staticmethod + def _release_gil_asmgcc(css): + # similar to trackgcroot.py:pypy_asm_stackwalk, first part + from pypy.rpython.memory.gctransform import asmgcroot + new = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css) + next = asmgcroot.gcrootanchor.next + new.next = next + new.prev = asmgcroot.gcrootanchor + asmgcroot.gcrootanchor.next = new + next.prev = new + # and now release the GIL + before = rffi.aroundstate.before + if before: + before() + + @staticmethod + def _reacquire_gil_asmgcc(css): + # first reacquire the GIL + after = rffi.aroundstate.after + if after: + after() + # similar to trackgcroot.py:pypy_asm_stackwalk, second part + from pypy.rpython.memory.gctransform import asmgcroot + old = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css) + prev = old.prev + next = old.next + prev.next = next + next.prev = prev + + @staticmethod + def _release_gil_shadowstack(): + before = rffi.aroundstate.before + if before: + before() + + @staticmethod + def _reacquire_gil_shadowstack(): + after = rffi.aroundstate.after + if after: + after() + + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) + _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP], + lltype.Void)) + + def _build_release_gil(self, gcrootmap): + if gcrootmap.is_shadow_stack: + releasegil_func = llhelper(self._NOARG_FUNC, + self._release_gil_shadowstack) + reacqgil_func = llhelper(self._NOARG_FUNC, + self._reacquire_gil_shadowstack) + else: + releasegil_func = llhelper(self._CLOSESTACK_FUNC, + self._release_gil_asmgcc) + reacqgil_func = llhelper(self._CLOSESTACK_FUNC, + self._reacquire_gil_asmgcc) + self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) + self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + + def assemble_loop(self, loopname, inputargs, operations, looptoken, log): '''adds the following attributes to looptoken: _x86_loop_code (an integer giving an address) _x86_bootstrap_code (an integer giving an address) @@ -322,6 +383,7 @@ # for the duration of compiling one loop or a one bridge. clt = CompiledLoopToken(self.cpu, looptoken.number) + clt.allgcrefs = [] looptoken.compiled_loop_token = clt if not we_are_translated(): # Arguments should be unique @@ -329,13 +391,13 @@ self.setup(looptoken) self.currently_compiling_loop = looptoken - funcname = self._find_debug_merge_point(operations) if log: self._register_counter() operations = self._inject_debugging_code(looptoken, operations) regalloc = RegAlloc(self, self.cpu.translate_support_code) - arglocs, operations = regalloc.prepare_loop(inputargs, operations, looptoken) + arglocs, operations = regalloc.prepare_loop(inputargs, operations, + looptoken, clt.allgcrefs) looptoken._x86_arglocs = arglocs bootstrappos = self.mc.get_relative_pos() @@ -354,10 +416,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( - looptoken.number, funcname, + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( + looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -375,7 +440,7 @@ self.teardown() # oprofile support if self.cpu.profile_agent is not None: - name = "Loop # %s: %s" % (looptoken.number, funcname) + name = "Loop # %s: %s" % (looptoken.number, loopname) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) return ops_offset @@ -395,7 +460,6 @@ return self.setup(original_loop_token) - funcname = self._find_debug_merge_point(operations) if log: self._register_counter() operations = self._inject_debugging_code(faildescr, operations) @@ -407,7 +471,8 @@ regalloc = RegAlloc(self, self.cpu.translate_support_code) fail_depths = faildescr._x86_current_depths operations = regalloc.prepare_bridge(fail_depths, inputargs, arglocs, - operations) + operations, + self.current_clt.allgcrefs) stackadjustpos = self._patchable_stackadjust() frame_depth, param_depth = self._assemble(regalloc, operations) @@ -416,9 +481,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d (%s) has address %x to %x" % - (descr_number, funcname, rawstart, rawstart + codeendpos)) + debug_start("jit-backend-addr") + debug_print("Bridge out of Guard %d has address %x to %x" % + (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -432,7 +498,7 @@ self.teardown() # oprofile support if self.cpu.profile_agent is not None: - name = "Bridge # %s: %s" % (descr_number, funcname) + name = "Bridge # %s" % (descr_number,) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) return ops_offset @@ -492,17 +558,6 @@ return self.mc.materialize(self.cpu.asmmemmgr, allblocks, self.cpu.gc_ll_descr.gcrootmap) - def _find_debug_merge_point(self, operations): - - for op in operations: - if op.getopnum() == rop.DEBUG_MERGE_POINT: - funcname = op.getarg(0)._get_str() - break - else: - funcname = "" % len(self.loop_run_counters) - # invent the counter, so we don't get too confused - return funcname - def _register_counter(self): if self._debug: # YYY very minor leak -- we need the counters to stay alive @@ -652,22 +707,28 @@ # we need to put two words into the shadowstack: the MARKER # and the address of the frame (ebp, actually) rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - if IS_X86_64: - # cannot use rdx here, it's used to pass arguments! - tmp = X86_64_SCRATCH_REG + if rx86.fits_in_32bits(rst): + self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] else: - tmp = edx - self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop] - self.mc.LEA_rm(tmp.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD] + self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop + self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13] + # + self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD] self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp - self.mc.MOV_jr(rst, tmp.value) # MOV [rootstacktop], edx + # + if rx86.fits_in_32bits(rst): + self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx + else: + self.mc.MOV_mr((r13.value, 0), ebx.value) # MOV [r13], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() - assert rx86.fits_in_32bits(rst) - self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + if rx86.fits_in_32bits(rst): + self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD + else: + self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop + self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth): if IS_X86_64: @@ -838,7 +899,7 @@ def regalloc_push(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: - self.mc.SUB_ri(esp.value, 2*WORD) + self.mc.SUB_ri(esp.value, 8) # = size of doubles self.mc.MOVSD_sx(0, loc.value) elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick @@ -850,7 +911,7 @@ def regalloc_pop(self, loc): if isinstance(loc, RegLoc) and loc.is_xmm: self.mc.MOVSD_xs(loc.value, 0) - self.mc.ADD_ri(esp.value, 2*WORD) + self.mc.ADD_ri(esp.value, 8) # = size of doubles elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8: # XXX evil trick self.mc.POP_b(get_ebp_ofs(loc.position + 1)) @@ -1987,6 +2048,102 @@ self.mc.CMP_bi(FORCE_INDEX_OFS, 0) self.implement_guard(guard_token, 'L') + def genop_guard_call_release_gil(self, op, guard_op, guard_token, + arglocs, result_loc): + # first, close the stack in the sense of the asmgcc GC root tracker + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + if gcrootmap: + self.call_release_gil(gcrootmap, arglocs) + # do the call + faildescr = guard_op.getdescr() + fail_index = self.cpu.get_fail_descr_number(faildescr) + self.mc.MOV_bi(FORCE_INDEX_OFS, fail_index) + self._genop_call(op, arglocs, result_loc, fail_index) + # then reopen the stack + if gcrootmap: + self.call_reacquire_gil(gcrootmap, result_loc) + # finally, the guard_not_forced + self.mc.CMP_bi(FORCE_INDEX_OFS, 0) + self.implement_guard(guard_token, 'L') + + def call_release_gil(self, gcrootmap, save_registers): + # First, we need to save away the registers listed in + # 'save_registers' that are not callee-save. XXX We assume that + # the XMM registers won't be modified. We store them in + # [ESP+4], [ESP+8], etc., leaving enough room in [ESP] for the + # single argument to closestack_addr below. + p = WORD + for reg in self._regalloc.rm.save_around_call_regs: + if reg in save_registers: + self.mc.MOV_sr(p, reg.value) + p += WORD + self._regalloc.reserve_param(p//WORD) + # + if gcrootmap.is_shadow_stack: + args = [] + else: + # note that regalloc.py used save_all_regs=True to save all + # registers, so we don't have to care about saving them (other + # than ebp) in the close_stack_struct. But if they are registers + # like %eax that would be destroyed by this call, *and* they are + # used by arglocs for the *next* call, then trouble; for now we + # will just push/pop them. + from pypy.rpython.memory.gctransform import asmgcroot + css = self._regalloc.close_stack_struct + if css == 0: + use_words = (2 + max(asmgcroot.INDEX_OF_EBP, + asmgcroot.FRAME_PTR) + 1) + pos = self._regalloc.fm.reserve_location_in_frame(use_words) + css = get_ebp_ofs(pos + use_words - 1) + self._regalloc.close_stack_struct = css + # The location where the future CALL will put its return address + # will be [ESP-WORD], so save that as the next frame's top address + self.mc.LEA_rs(eax.value, -WORD) # LEA EAX, [ESP-4] + frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) + self.mc.MOV_br(frame_ptr, eax.value) # MOV [css.frame], EAX + # Save ebp + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_br(index_of_ebp, ebp.value) # MOV [css.ebp], EBP + # Call the closestack() function (also releasing the GIL) + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rb(reg.value, css) + args = [reg] + # + self._emit_call(-1, imm(self.releasegil_addr), args) + # Finally, restore the registers saved above. + p = WORD + for reg in self._regalloc.rm.save_around_call_regs: + if reg in save_registers: + self.mc.MOV_rs(reg.value, p) + p += WORD + + def call_reacquire_gil(self, gcrootmap, save_loc): + # save the previous result (eax/xmm0) into the stack temporarily. + # XXX like with call_release_gil(), we assume that we don't need + # to save xmm0 in this case. + if isinstance(save_loc, RegLoc) and not save_loc.is_xmm: + self.mc.MOV_sr(WORD, save_loc.value) + self._regalloc.reserve_param(2) + # call the reopenstack() function (also reacquiring the GIL) + if gcrootmap.is_shadow_stack: + args = [] + else: + css = self._regalloc.close_stack_struct + assert css != 0 + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rb(reg.value, css) + args = [reg] + self._emit_call(-1, imm(self.reacqgil_addr), args) + # restore the result from the stack + if isinstance(save_loc, RegLoc) and not save_loc.is_xmm: + self.mc.MOV_rs(save_loc.value, WORD) + def genop_guard_call_assembler(self, op, guard_op, guard_token, arglocs, result_loc): faildescr = guard_op.getdescr() @@ -2076,13 +2233,26 @@ def genop_discard_cond_call_gc_wb(self, op, arglocs): # Write code equivalent to write_barrier() in the GC: it checks # a flag in the object at arglocs[0], and if set, it calls the - # function remember_young_pointer() from the GC. The two arguments - # to the call are in arglocs[:2]. The rest, arglocs[2:], contains + # function remember_young_pointer() from the GC. The arguments + # to the call are in arglocs[:N]. The rest, arglocs[N:], contains # registers that need to be saved and restored across the call. + # N is either 2 (regular write barrier) or 3 (array write barrier). descr = op.getdescr() if we_are_translated(): cls = self.cpu.gc_ll_descr.has_write_barrier_class() assert cls is not None and isinstance(descr, cls) + # + opnum = op.getopnum() + if opnum == rop.COND_CALL_GC_WB: + N = 2 + func = descr.get_write_barrier_fn(self.cpu) + elif opnum == rop.COND_CALL_GC_WB_ARRAY: + N = 3 + func = descr.get_write_barrier_from_array_fn(self.cpu) + assert func != 0 + else: + raise AssertionError(opnum) + # loc_base = arglocs[0] self.mc.TEST8(addr_add_const(loc_base, descr.jit_wb_if_flag_byteofs), imm(descr.jit_wb_if_flag_singlebyte)) @@ -2093,33 +2263,37 @@ if IS_X86_32: limit = -1 # push all arglocs on the stack elif IS_X86_64: - limit = 1 # push only arglocs[2:] on the stack + limit = N - 1 # push only arglocs[N:] on the stack for i in range(len(arglocs)-1, limit, -1): loc = arglocs[i] if isinstance(loc, RegLoc): self.mc.PUSH_r(loc.value) else: - assert not IS_X86_64 # there should only be regs in arglocs[2:] + assert not IS_X86_64 # there should only be regs in arglocs[N:] self.mc.PUSH_i32(loc.getint()) if IS_X86_64: # We clobber these registers to pass the arguments, but that's # okay, because consider_cond_call_gc_wb makes sure that any # caller-save registers with values in them are present in - # arglocs[2:] too, so they are saved on the stack above and + # arglocs[N:] too, so they are saved on the stack above and # restored below. - remap_frame_layout(self, arglocs[:2], [edi, esi], + if N == 2: + callargs = [edi, esi] + else: + callargs = [edi, esi, edx] + remap_frame_layout(self, arglocs[:N], callargs, X86_64_SCRATCH_REG) - + # # misaligned stack in the call, but it's ok because the write barrier # is not going to call anything more. Also, this assumes that the # write barrier does not touch the xmm registers. (Slightly delicate # assumption, given that the write barrier can end up calling the # platform's malloc() from AddressStack.append(). XXX may need to # be done properly) - self.mc.CALL(imm(descr.get_write_barrier_fn(self.cpu))) + self.mc.CALL(imm(func)) if IS_X86_32: - self.mc.ADD_ri(esp.value, 2*WORD) - for i in range(2, len(arglocs)): + self.mc.ADD_ri(esp.value, N*WORD) + for i in range(N, len(arglocs)): loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) @@ -2128,6 +2302,8 @@ assert 0 < offset <= 127 self.mc.overwrite(jz_location-1, chr(offset)) + genop_discard_cond_call_gc_wb_array = genop_discard_cond_call_gc_wb + def genop_force_token(self, op, arglocs, resloc): # RegAlloc.consider_force_token ensures this: assert isinstance(resloc, RegLoc) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -156,12 +156,14 @@ self.translate_support_code = translate_support_code # to be read/used by the assembler too self.jump_target_descr = None + self.close_stack_struct = 0 - def _prepare(self, inputargs, operations): + def _prepare(self, inputargs, operations, allgcrefs): self.fm = X86FrameManager() self.param_depth = 0 cpu = self.assembler.cpu - operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations) + operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations, + allgcrefs) # compute longevity of variables longevity = compute_vars_longevity(inputargs, operations) self.longevity = longevity @@ -172,15 +174,16 @@ assembler = self.assembler) return operations - def prepare_loop(self, inputargs, operations, looptoken): - operations = self._prepare(inputargs, operations) + def prepare_loop(self, inputargs, operations, looptoken, allgcrefs): + operations = self._prepare(inputargs, operations, allgcrefs) jump = operations[-1] loop_consts = compute_loop_consts(inputargs, jump, looptoken) self.loop_consts = loop_consts return self._process_inputargs(inputargs), operations - def prepare_bridge(self, prev_depths, inputargs, arglocs, operations): - operations = self._prepare(inputargs, operations) + def prepare_bridge(self, prev_depths, inputargs, arglocs, operations, + allgcrefs): + operations = self._prepare(inputargs, operations, allgcrefs) self.loop_consts = {} self._update_bindings(arglocs, inputargs) self.fm.frame_depth = prev_depths[0] @@ -378,7 +381,9 @@ self.assembler.regalloc_perform_discard(op, arglocs) def can_merge_with_next_guard(self, op, i, operations): - if op.getopnum() == rop.CALL_MAY_FORCE or op.getopnum() == rop.CALL_ASSEMBLER: + if (op.getopnum() == rop.CALL_MAY_FORCE or + op.getopnum() == rop.CALL_ASSEMBLER or + op.getopnum() == rop.CALL_RELEASE_GIL): assert operations[i + 1].getopnum() == rop.GUARD_NOT_FORCED return True if not op.is_comparison(): @@ -729,6 +734,19 @@ self.xrm.possibly_free_var(op.getarg(1)) def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None): + # we need to save registers on the stack: + # + # - at least the non-callee-saved registers + # + # - for shadowstack, we assume that any call can collect, and we + # save also the callee-saved registers that contain GC pointers, + # so that they can be found by follow_stack_frame_of_assembler() + # + # - for CALL_MAY_FORCE or CALL_ASSEMBLER, we have to save all regs + # anyway, in case we need to do cpu.force(). The issue is that + # grab_frame_values() would not be able to locate values in + # callee-saved registers. + # save_all_regs = guard_not_forced_op is not None self.xrm.before_call(force_store, save_all_regs=save_all_regs) if not save_all_regs: @@ -795,6 +813,8 @@ assert guard_op is not None self._consider_call(op, guard_op) + consider_call_release_gil = consider_call_may_force + def consider_call_assembler(self, op, guard_op): descr = op.getdescr() assert isinstance(descr, LoopToken) @@ -814,12 +834,12 @@ def consider_cond_call_gc_wb(self, op): assert op.result is None args = op.getarglist() - loc_newvalue = self.rm.make_sure_var_in_reg(op.getarg(1), args) - # ^^^ we force loc_newvalue in a reg (unless it's a Const), - # because it will be needed anyway by the following setfield_gc. - # It avoids loading it twice from the memory. - loc_base = self.rm.make_sure_var_in_reg(op.getarg(0), args) - arglocs = [loc_base, loc_newvalue] + N = len(args) + # we force all arguments in a reg (unless they are Consts), + # because it will be needed anyway by the following setfield_gc + # or setarrayitem_gc. It avoids loading it twice from the memory. + arglocs = [self.rm.make_sure_var_in_reg(op.getarg(i), args) + for i in range(N)] # add eax, ecx and edx as extra "arguments" to ensure they are # saved and restored. Fish in self.rm to know which of these # registers really need to be saved (a bit of a hack). Moreover, @@ -833,6 +853,8 @@ self.PerformDiscard(op, arglocs) self.rm.possibly_free_vars_for_op(op) + consider_cond_call_gc_wb_array = consider_cond_call_gc_wb + def fastpath_malloc_fixedsize(self, op, descr): assert isinstance(descr, BaseSizeDescr) self._do_fastpath_malloc(op, descr.size, descr.tid) @@ -1308,7 +1330,9 @@ name = name[len('consider_'):] num = getattr(rop, name.upper()) if (is_comparison_or_ovf_op(num) - or num == rop.CALL_MAY_FORCE or num == rop.CALL_ASSEMBLER): + or num == rop.CALL_MAY_FORCE + or num == rop.CALL_ASSEMBLER + or num == rop.CALL_RELEASE_GIL): oplist_with_guard[num] = value oplist[num] = add_none_argument(value) else: diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -318,7 +318,9 @@ # must be careful not to combine it with location types that # might need to use the scratch register themselves. if loc2 is X86_64_SCRATCH_REG: - assert code1 != 'j' + if code1 == 'j': + assert (name.startswith("MOV") and + rx86.fits_in_32bits(loc1.value_j())) if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"): assert code2 not in ('j', 'i') diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py --- a/pypy/jit/backend/x86/runner.py +++ b/pypy/jit/backend/x86/runner.py @@ -22,6 +22,7 @@ BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) dont_keepalive_stuff = False # for tests + with_threads = False def __init__(self, rtyper, stats, opts=None, translate_support_code=False, gcdescr=None): @@ -38,6 +39,7 @@ if not oprofile.OPROFILE_AVAILABLE: log.WARNING('oprofile support was explicitly enabled, but oprofile headers seem not to be available') profile_agent = oprofile.OProfileAgent() + self.with_threads = config.translation.thread self.profile_agent = profile_agent @@ -77,9 +79,9 @@ lines = machine_code_dump(data, addr, self.backend_name, label_list) print ''.join(lines) - def compile_loop(self, inputargs, operations, looptoken, log=True): - return self.assembler.assemble_loop(inputargs, operations, looptoken, - log=log) + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): + return self.assembler.assemble_loop(name, inputargs, operations, + looptoken, log=log) def compile_bridge(self, faildescr, inputargs, operations, original_loop_token, log=True): @@ -122,8 +124,8 @@ addr = executable_token._x86_bootstrap_code #llop.debug_print(lltype.Void, ">>>> Entering", addr) func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr) + fail_index = self._execute_call(func) #llop.debug_print(lltype.Void, "<<<< Back") - fail_index = self._execute_call(func) return self.get_fail_descr_from_number(fail_index) def _execute_call(self, func): @@ -140,10 +142,11 @@ LLInterpreter.current_interpreter = prev_interpreter return res - @staticmethod def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return CPU386.cast_adr_to_int(adr) + cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)' + cast_ptr_to_int = staticmethod(cast_ptr_to_int) all_null_registers = lltype.malloc(rffi.LONGP.TO, 24, flavor='raw', zero=True, diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -283,7 +283,7 @@ # with immediate(argnum)). def encode_abs(mc, _1, _2, orbyte): - # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit + # expands to either '\x05' on 32-bit, or '\x04\x25' on 64-bit if mc.WORD == 8: mc.writechar(chr(0x04 | orbyte)) mc.writechar(chr(0x25)) @@ -370,6 +370,8 @@ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2)) INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1), immediate(2,'b')) + INSN_mi8 = insn(rex_w, '\x83', orbyte(base), mem_reg_plus_const(1), + immediate(2,'b')) INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b')) INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2)) @@ -388,7 +390,7 @@ INSN_bi._always_inline_ = True # try to constant-fold single_byte() return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj, - INSN_ji8) + INSN_ji8, INSN_mi8) def select_8_or_32_bit_immed(insn_8, insn_32): def INSN(*args): @@ -462,18 +464,18 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ - ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0) - OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1) - AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4) - SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5) - SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3) - XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6) - CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7) + ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0) + OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1) + AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4) + SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5) + SBB_ri,SBB_rr,SBB_rb,_,_,SBB_rm,SBB_rj,_,_ = common_modes(3) + XOR_ri,XOR_rr,XOR_rb,_,_,XOR_rm,XOR_rj,_,_ = common_modes(6) + CMP_ri,CMP_rr,CMP_rb,CMP_bi,CMP_br,CMP_rm,CMP_rj,_,_ = common_modes(7) CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b')) CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2)) @@ -530,6 +532,7 @@ POP_b = insn(rex_nw, '\x8F', orbyte(0<<3), stack_bp(1)) LEA_rb = insn(rex_w, '\x8D', register(1,8), stack_bp(2)) + LEA_rs = insn(rex_w, '\x8D', register(1,8), stack_sp(2)) LEA32_rb = insn(rex_w, '\x8D', register(1,8),stack_bp(2,force_32bits=True)) LEA_ra = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_scaled_reg_plus_const(2)) LEA_rm = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_const(2)) @@ -629,16 +632,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py --- a/pypy/jit/backend/x86/test/test_assembler.py +++ b/pypy/jit/backend/x86/test/test_assembler.py @@ -1,13 +1,15 @@ from pypy.jit.backend.x86.regloc import * from pypy.jit.backend.x86.assembler import Assembler386 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, ConstFloat +from pypy.jit.metainterp.history import INT, REF, FLOAT from pypy.rlib.rarithmetic import intmask from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64 from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager from pypy.jit.codewriter import longlong +import ctypes ACTUAL_CPU = getcpuclass() @@ -238,3 +240,103 @@ assert assembler.fail_boxes_int.getitem(i) == expected_ints[i] assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i] assert assembler.fail_boxes_float.getitem(i) == expected_floats[i] + +# ____________________________________________________________ + +class TestRegallocPushPop(object): + + def do_test(self, callback): + from pypy.jit.backend.x86.regalloc import X86FrameManager + from pypy.jit.backend.x86.regalloc import X86XMMRegisterManager + class FakeToken: + class compiled_loop_token: + asmmemmgr_blocks = None + cpu = ACTUAL_CPU(None, None) + cpu.setup() + looptoken = FakeToken() + asm = cpu.assembler + asm.setup_once() + asm.setup(looptoken) + self.fm = X86FrameManager() + self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm, + assembler=asm) + callback(asm) + asm.mc.RET() + rawstart = asm.materialize_loop(looptoken) + # + F = ctypes.CFUNCTYPE(ctypes.c_long) + fn = ctypes.cast(rawstart, F) + res = fn() + return res + + def test_simple(self): + def callback(asm): + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(eax) + res = self.do_test(callback) + assert res == 42 + + def test_push_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), loc) + asm.regalloc_push(loc) + asm.regalloc_pop(eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_pop_stack(self): + def callback(asm): + loc = self.fm.frame_pos(5, INT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(imm(42), edx) + asm.regalloc_push(edx) + asm.regalloc_pop(loc) + asm.mov(loc, eax) + asm.mc.ADD_ri(esp.value, 64) + res = self.do_test(callback) + assert res == 42 + + def test_simple_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(xmm0) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_push_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.mov(xmm5, loc2) + asm.regalloc_push(loc2) + asm.regalloc_pop(xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 + + def test_pop_stack_xmm(self): + def callback(asm): + c = ConstFloat(longlong.getfloatstorage(-42.5)) + loc = self.xrm.convert_to_imm(c) + loc2 = self.fm.frame_pos(4, FLOAT) + asm.mc.SUB_ri(esp.value, 64) + asm.mov(loc, xmm5) + asm.regalloc_push(xmm5) + asm.regalloc_pop(loc2) + asm.mov(loc2, xmm0) + asm.mc.ADD_ri(esp.value, 64) + asm.mc.CVTTSD2SI(eax, xmm0) + res = self.do_test(callback) + assert res == -42 diff --git a/pypy/jit/backend/x86/test/test_gc_integration.py b/pypy/jit/backend/x86/test/test_gc_integration.py --- a/pypy/jit/backend/x86/test/test_gc_integration.py +++ b/pypy/jit/backend/x86/test/test_gc_integration.py @@ -16,7 +16,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.annlowlevel import llhelper from pypy.rpython.lltypesystem import rclass, rstr -from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList, GcPtrFieldDescr +from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcPtrFieldDescr from pypy.jit.backend.x86.test.test_regalloc import MockAssembler from pypy.jit.backend.x86.test.test_regalloc import BaseTestRegalloc @@ -51,11 +51,9 @@ gcrootmap = MockGcRootMap() def initialize(self): - self.gcrefs = GcRefList() - self.gcrefs.initialize() - self.single_gcref_descr = GcPtrFieldDescr('', 0) + pass - replace_constptrs_with_getfield_raw = GcLLDescr_framework.replace_constptrs_with_getfield_raw.im_func + record_constptrs = GcLLDescr_framework.record_constptrs.im_func rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func class TestRegallocDirectGcIntegration(object): diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -6,6 +6,7 @@ ConstPtr, Box, BoxFloat, BasicFailDescr) from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.x86.arch import WORD +from pypy.jit.backend.x86.rx86 import fits_in_32bits from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute @@ -241,6 +242,23 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 + def test_bug_setfield_64bit(self): + if WORD == 4: + py.test.skip("only for 64 bits") + TP = lltype.GcStruct('S', ('i', lltype.Signed)) + ofsi = self.cpu.fielddescrof(TP, 'i') + for i in range(500): + p = lltype.malloc(TP) + addr = rffi.cast(lltype.Signed, p) + if fits_in_32bits(addr): + break # fitting in 32 bits, good + else: + py.test.skip("cannot get a 32-bit pointer") + res = ConstPtr(rffi.cast(llmemory.GCREF, addr)) + self.execute_operation(rop.SETFIELD_RAW, [res, ConstInt(3**33)], + 'void', ofsi) + assert p.i == 3**33 + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] @@ -330,6 +348,7 @@ assert result != expected def test_compile_bridge_check_profile_info(self): + py.test.skip("does not work, reinvestigate") class FakeProfileAgent(object): def __init__(self): self.functions = [] @@ -362,7 +381,7 @@ operations[3].setfailargs([i1]) self.cpu.compile_loop(inputargs, operations, looptoken) name, loopaddress, loopsize = agent.functions[0] - assert name == "Loop # 17: hello" + assert name == "Loop # 17: hello (loop counter 0)" assert loopaddress <= looptoken._x86_loop_code assert loopsize >= 40 # randomish number @@ -378,7 +397,7 @@ self.cpu.compile_bridge(faildescr1, [i1b], bridge, looptoken) name, address, size = agent.functions[1] - assert name == "Bridge # 0: bye" + assert name == "Bridge # 0: bye (loop counter 1)" # Would be exactly ==, but there are some guard failure recovery # stubs in-between assert address >= loopaddress + loopsize diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py --- a/pypy/jit/backend/x86/test/test_rx86.py +++ b/pypy/jit/backend/x86/test/test_rx86.py @@ -185,15 +185,32 @@ cb = CodeBuilder32 assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00') +def test_sub_ji8(): + cb = CodeBuilder32 + assert_encodes_as(cb, 'SUB_ji8', (11223344, 55), + '\x83\x2D\x30\x41\xAB\x00\x37') + assert_encodes_as(cb, 'SUB_mi8', ((edx, 16), 55), + '\x83\x6A\x10\x37') + class CodeBuilder64(CodeBuilderMixin, X86_64_CodeBuilder): pass def test_mov_ri_64(): s = CodeBuilder64() s.MOV_ri(ecx, -2) + s.MOV_ri(r15, -3) + s.MOV_ri(ebx, -0x80000003) + s.MOV_ri(r13, -0x80000002) + s.MOV_ri(ecx, 42) s.MOV_ri(r12, 0x80000042) + s.MOV_ri(r12, 0x100000007) assert s.getvalue() == ('\x48\xC7\xC1\xFE\xFF\xFF\xFF' + - '\x49\xBC\x42\x00\x00\x80\x00\x00\x00\x00') + '\x49\xC7\xC7\xFD\xFF\xFF\xFF' + + '\x48\xBB\xFD\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\x49\xBD\xFE\xFF\xFF\x7F\xFF\xFF\xFF\xFF' + + '\xB9\x2A\x00\x00\x00' + + '\x41\xBC\x42\x00\x00\x80' + + '\x49\xBC\x07\x00\x00\x00\x01\x00\x00\x00') def test_mov_rm_64(): s = CodeBuilder64() diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py --- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py +++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py @@ -212,6 +212,17 @@ for mode, v in zip(argmodes, args): ops.append(assembler_operand[mode](v)) ops.reverse() + # + if (instrname.lower() == 'mov' and suffix == 'q' and + ops[0].startswith('$') and 0 <= int(ops[0][1:]) <= 4294967295 + and ops[1].startswith('%r')): + # movq $xxx, %rax => movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -1,8 +1,7 @@ """ -This is a test that translates a complete JIT to C and runs it. It is -not testing much, expect that it basically works. What it *is* testing, -however, is the correct handling of GC, i.e. if objects are freed as -soon as possible (at least in a simple case). +This is a test that translates a complete JIT together with a GC and runs it. +It is testing that the GC-dependent aspects basically work, mostly the mallocs +and the various cases of write barrier. """ import weakref @@ -10,16 +9,11 @@ from pypy.annotation import policy as annpolicy from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe -from pypy.jit.backend.x86.runner import CPU386 -from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir -from pypy.jit.backend.x86.arch import IS_X86_64 from pypy.config.translationoption import DEFL_GC -import py.test class X(object): def __init__(self, x=0): @@ -86,7 +80,7 @@ # return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2} -def compile(f, gc, **kwds): +def compile(f, gc, enable_opts='', **kwds): from pypy.annotation.listdef import s_list_of_strings from pypy.translator.translator import TranslationContext from pypy.jit.metainterp.warmspot import apply_jit @@ -110,14 +104,14 @@ old_value[obj, attr] = getattr(obj, attr) setattr(obj, attr, value) # - apply_jit(t, enable_opts='') + apply_jit(t, enable_opts=enable_opts) # finally: for (obj, attr), oldvalue in old_value.items(): setattr(obj, attr, oldvalue) cbuilder = genc.CStandaloneBuilder(t, f, t.config) - cbuilder.generate_source() + cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) cbuilder.compile() return cbuilder @@ -154,8 +148,10 @@ # ______________________________________________________________________ -class CompileFrameworkTests(object): - # Test suite using (so far) the minimark GC. + +class BaseFrameworkTests(object): + compile_kwds = {} + def setup_class(cls): funcs = [] name_to_func = {} @@ -205,7 +201,8 @@ try: GcLLDescr_framework.DEBUG = True cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC, - gcrootfinder=cls.gcrootfinder, jit=True) + gcrootfinder=cls.gcrootfinder, jit=True, + **cls.compile_kwds) finally: GcLLDescr_framework.DEBUG = OLD_DEBUG @@ -224,32 +221,36 @@ def run_orig(self, name, n, x): self.main_allfuncs(name, n, x) - def define_libffi_workaround(cls): - # XXX: this is a workaround for a bug in database.py. It seems that - # the problem is triggered by optimizeopt/fficall.py, and in - # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in - # these tests, that line is the only place where libffi.Func is - # referenced. - # - # The problem occurs because the gctransformer tries to annotate a - # low-level helper to call the __del__ of libffi.Func when it's too - # late. - # - # This workaround works by forcing the annotator (and all the rest of - # the toolchain) to see libffi.Func in a "proper" context, not just as - # the target of cast_base_ptr_to_instance. Note that the function - # below is *never* called by any actual test, it's just annotated. - # - from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain - libc_name = get_libc_name() - def f(n, x, *args): - libc = CDLL(libc_name) - ptr = libc.getpointer('labs', [types.slong], types.slong) - chain = ArgChain() - chain.arg(n) - n = ptr.call(chain, lltype.Signed) - return (n, x) + args - return None, f, None + +class CompileFrameworkTests(BaseFrameworkTests): + # Test suite using (so far) the minimark GC. + +## def define_libffi_workaround(cls): +## # XXX: this is a workaround for a bug in database.py. It seems that +## # the problem is triggered by optimizeopt/fficall.py, and in +## # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in +## # these tests, that line is the only place where libffi.Func is +## # referenced. +## # +## # The problem occurs because the gctransformer tries to annotate a +## # low-level helper to call the __del__ of libffi.Func when it's too +## # late. +## # +## # This workaround works by forcing the annotator (and all the rest of +## # the toolchain) to see libffi.Func in a "proper" context, not just as +## # the target of cast_base_ptr_to_instance. Note that the function +## # below is *never* called by any actual test, it's just annotated. +## # +## from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain +## libc_name = get_libc_name() +## def f(n, x, *args): +## libc = CDLL(libc_name) +## ptr = libc.getpointer('labs', [types.slong], types.slong) +## chain = ArgChain() +## chain.arg(n) +## n = ptr.call(chain, lltype.Signed) +## return (n, x) + args +## return None, f, None def define_compile_framework_1(cls): # a moving GC. Supports malloc_varsize_nonmovable. Simple test, works @@ -456,6 +457,73 @@ def test_compile_framework_7(self): self.run('compile_framework_7') + def define_compile_framework_8(cls): + # Array of pointers, of unknown length (test write_barrier_from_array) + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + l = [None] * (16 + (n & 7)) + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[8] = X(n+70) + l[9] = X(n+80) + l[10] = X(n+90) + l[11] = X(n+100) + l[12] = X(n+110) + l[13] = X(n+120) + l[14] = X(n+130) + l[15] = X(n+140) + if n < 1800: + check(len(l) == 16 + (n & 7)) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[8].x == n+70) + check(l[9].x == n+80) + check(l[10].x == n+90) + check(l[11].x == n+100) + check(l[12].x == n+110) + check(l[13].x == n+120) + check(l[14].x == n+130) + check(l[15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 16) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[8].x == 72) + check(l[9].x == 82) + check(l[10].x == 92) + check(l[11].x == 102) + check(l[12].x == 112) + check(l[13].x == 122) + check(l[14].x == 132) + check(l[15].x == 142) + return before, f, after + + def test_compile_framework_8(self): + self.run('compile_framework_8') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) @@ -493,7 +561,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_releasegil.py copy from pypy/jit/backend/x86/test/test_zrpy_gc.py copy to pypy/jit/backend/x86/test/test_zrpy_releasegil.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_releasegil.py @@ -1,618 +1,110 @@ -""" -This is a test that translates a complete JIT to C and runs it. It is -not testing much, expect that it basically works. What it *is* testing, -however, is the correct handling of GC, i.e. if objects are freed as -soon as possible (at least in a simple case). -""" +from pypy.rpython.lltypesystem import lltype, llmemory, rffi +from pypy.rlib.jit import dont_look_inside +from pypy.jit.metainterp.optimizeopt import ALL_OPTS_NAMES -import weakref -import py, os -from pypy.annotation import policy as annpolicy -from pypy.rlib import rgc -from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe -from pypy.jit.backend.x86.runner import CPU386 -from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc -from pypy.jit.backend.llsupport.gc import GcLLDescr_framework -from pypy.tool.udir import udir -from pypy.jit.backend.x86.arch import IS_X86_64 -from pypy.config.translationoption import DEFL_GC -import py.test +from pypy.rlib.libffi import CDLL, types, ArgChain, clibffi +from pypy.rpython.lltypesystem.ll2ctypes import libc_name +from pypy.rpython.annlowlevel import llhelper -class X(object): - def __init__(self, x=0): - self.x = x +from pypy.jit.backend.x86.test.test_zrpy_gc import BaseFrameworkTests +from pypy.jit.backend.x86.test.test_zrpy_gc import check - next = None -class CheckError(Exception): - pass +class ReleaseGILTests(BaseFrameworkTests): + compile_kwds = dict(enable_opts=ALL_OPTS_NAMES, thread=True) -def check(flag): - if not flag: - raise CheckError - -def get_g(main): - main._dont_inline_ = True - def g(name, n): - x = X() - x.foo = 2 - main(n, x) - x.foo = 5 - return weakref.ref(x) - g._dont_inline_ = True - return g - - -def get_entry(g): - - def entrypoint(args): - name = '' - n = 2000 - argc = len(args) - if argc > 1: - name = args[1] - if argc > 2: - n = int(args[2]) - r_list = [] - for i in range(20): - r = g(name, n) - r_list.append(r) - rgc.collect() - rgc.collect(); rgc.collect() - freed = 0 - for r in r_list: - if r() is None: - freed += 1 - print freed - return 0 - - return entrypoint - - -def get_functions_to_patch(): - from pypy.jit.backend.llsupport import gc - # - can_inline_malloc1 = gc.GcLLDescr_framework.can_inline_malloc - def can_inline_malloc2(*args): - try: - if os.environ['PYPY_NO_INLINE_MALLOC']: - return False - except KeyError: + def define_simple(self): + class Glob: pass - return can_inline_malloc1(*args) - # - return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2} - -def compile(f, gc, **kwds): - from pypy.annotation.listdef import s_list_of_strings - from pypy.translator.translator import TranslationContext - from pypy.jit.metainterp.warmspot import apply_jit - from pypy.translator.c import genc - # - t = TranslationContext() - t.config.translation.gc = gc - if gc != 'boehm': - t.config.translation.gcremovetypeptr = True - for name, value in kwds.items(): - setattr(t.config.translation, name, value) - ann = t.buildannotator(policy=annpolicy.StrictAnnotatorPolicy()) - ann.build_types(f, [s_list_of_strings], main_entry_point=True) - t.buildrtyper().specialize() - - if kwds['jit']: - patch = get_functions_to_patch() - old_value = {} - try: - for (obj, attr), value in patch.items(): - old_value[obj, attr] = getattr(obj, attr) - setattr(obj, attr, value) - # - apply_jit(t, enable_opts='') - # - finally: - for (obj, attr), oldvalue in old_value.items(): - setattr(obj, attr, oldvalue) - - cbuilder = genc.CStandaloneBuilder(t, f, t.config) - cbuilder.generate_source() - cbuilder.compile() - return cbuilder - -def run(cbuilder, args=''): - # - pypylog = udir.join('test_zrpy_gc.log') - data = cbuilder.cmdexec(args, env={'PYPYLOG': ':%s' % pypylog}) - return data.strip() - -def compile_and_run(f, gc, **kwds): - cbuilder = compile(f, gc, **kwds) - return run(cbuilder) - - - -def test_compile_boehm(): - myjitdriver = JitDriver(greens = [], reds = ['n', 'x']) - @dont_look_inside - def see(lst, n): - assert len(lst) == 3 - assert lst[0] == n+10 - assert lst[1] == n+20 - assert lst[2] == n+30 - def main(n, x): - while n > 0: - myjitdriver.can_enter_jit(n=n, x=x) - myjitdriver.jit_merge_point(n=n, x=x) - y = X() - y.foo = x.foo - n -= y.foo - see([n+10, n+20, n+30], n) - res = compile_and_run(get_entry(get_g(main)), "boehm", jit=True) - assert int(res) >= 16 - -# ______________________________________________________________________ - -class CompileFrameworkTests(object): - # Test suite using (so far) the minimark GC. - def setup_class(cls): - funcs = [] - name_to_func = {} - for fullname in dir(cls): - if not fullname.startswith('define'): - continue - definefunc = getattr(cls, fullname) - _, name = fullname.split('_', 1) - beforefunc, loopfunc, afterfunc = definefunc.im_func(cls) - if beforefunc is None: - def beforefunc(n, x): - return n, x, None, None, None, None, None, None, None, None, None, '' - if afterfunc is None: - def afterfunc(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - pass - beforefunc.func_name = 'before_'+name - loopfunc.func_name = 'loop_'+name - afterfunc.func_name = 'after_'+name - funcs.append((beforefunc, loopfunc, afterfunc)) - assert name not in name_to_func - name_to_func[name] = len(name_to_func) - print name_to_func - def allfuncs(name, n): - x = X() - x.foo = 2 - main_allfuncs(name, n, x) - x.foo = 5 - return weakref.ref(x) - def main_allfuncs(name, n, x): - num = name_to_func[name] - n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s = funcs[num][0](n, x) - while n > 0: - myjitdriver.can_enter_jit(num=num, n=n, x=x, x0=x0, x1=x1, - x2=x2, x3=x3, x4=x4, x5=x5, x6=x6, x7=x7, l=l, s=s) - myjitdriver.jit_merge_point(num=num, n=n, x=x, x0=x0, x1=x1, - x2=x2, x3=x3, x4=x4, x5=x5, x6=x6, x7=x7, l=l, s=s) - - n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s = funcs[num][1]( - n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s) - funcs[num][2](n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s) - myjitdriver = JitDriver(greens = ['num'], - reds = ['n', 'x', 'x0', 'x1', 'x2', 'x3', 'x4', - 'x5', 'x6', 'x7', 'l', 's']) - cls.main_allfuncs = staticmethod(main_allfuncs) - cls.name_to_func = name_to_func - OLD_DEBUG = GcLLDescr_framework.DEBUG - try: - GcLLDescr_framework.DEBUG = True - cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC, - gcrootfinder=cls.gcrootfinder, jit=True) - finally: - GcLLDescr_framework.DEBUG = OLD_DEBUG - - def _run(self, name, n, env): - res = self.cbuilder.cmdexec("%s %d" %(name, n), env=env) - assert int(res) == 20 - - def run(self, name, n=2000): - pypylog = udir.join('TestCompileFramework.log') - env = {'PYPYLOG': ':%s' % pypylog, - 'PYPY_NO_INLINE_MALLOC': '1'} - self._run(name, n, env) - env['PYPY_NO_INLINE_MALLOC'] = '' - self._run(name, n, env) - - def run_orig(self, name, n, x): - self.main_allfuncs(name, n, x) - - def define_libffi_workaround(cls): - # XXX: this is a workaround for a bug in database.py. It seems that - # the problem is triggered by optimizeopt/fficall.py, and in - # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in - # these tests, that line is the only place where libffi.Func is - # referenced. + glob = Glob() # - # The problem occurs because the gctransformer tries to annotate a - # low-level helper to call the __del__ of libffi.Func when it's too - # late. - # - # This workaround works by forcing the annotator (and all the rest of - # the toolchain) to see libffi.Func in a "proper" context, not just as - # the target of cast_base_ptr_to_instance. Note that the function - # below is *never* called by any actual test, it's just annotated. - # - from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain - libc_name = get_libc_name() - def f(n, x, *args): - libc = CDLL(libc_name) - ptr = libc.getpointer('labs', [types.slong], types.slong) - chain = ArgChain() - chain.arg(n) - n = ptr.call(chain, lltype.Signed) - return (n, x) + args - return None, f, None - - def define_compile_framework_1(cls): - # a moving GC. Supports malloc_varsize_nonmovable. Simple test, works - # without write_barriers and root stack enumeration. - def f(n, x, *args): - y = X() - y.foo = x.foo - n -= y.foo - return (n, x) + args - return None, f, None - - def test_compile_framework_1(self): - self.run('compile_framework_1') - - def define_compile_framework_2(cls): - # More complex test, requires root stack enumeration but - # not write_barriers. - def f(n, x, *args): - prev = x - for j in range(101): # f() runs 20'000 times, thus allocates - y = X() # a total of 2'020'000 objects - y.foo = prev.foo - prev = y - n -= prev.foo - return (n, x) + args - return None, f, None - - def test_compile_framework_2(self): - self.run('compile_framework_2') - - def define_compile_framework_3(cls): - # Third version of the test. Really requires write_barriers. - def f(n, x, *args): - x.next = None - for j in range(101): # f() runs 20'000 times, thus allocates - y = X() # a total of 2'020'000 objects - y.foo = j+1 - y.next = x.next - x.next = y - check(x.next.foo == 101) - total = 0 - y = x - for j in range(101): - y = y.next - total += y.foo - check(not y.next) - check(total == 101*102/2) - n -= x.foo - return (n, x) + args - return None, f, None - - - - def test_compile_framework_3(self): - x_test = X() - x_test.foo = 5 - self.run_orig('compile_framework_3', 6, x_test) # check that it does not raise CheckError - self.run('compile_framework_3') - - def define_compile_framework_3_extra(cls): - # Extra version of the test, with tons of live vars around the residual - # call that all contain a GC pointer. - @dont_look_inside - def residual(n=26): - x = X() - x.next = X() - x.next.foo = n - return x + def f42(n): + c_strchr = glob.c_strchr + raw = rffi.str2charp("foobar" + chr((n & 63) + 32)) + argchain = ArgChain() + argchain = argchain.arg(rffi.cast(lltype.Signed, raw)) + argchain = argchain.arg(rffi.cast(rffi.INT, ord('b'))) + res = c_strchr.call(argchain, rffi.CCHARP) + check(rffi.charp2str(res) == "bar" + chr((n & 63) + 32)) + rffi.free_charp(raw) # def before(n, x): - residual(5) - x0 = residual() - x1 = residual() - x2 = residual() - x3 = residual() - x4 = residual() - x5 = residual() - x6 = residual() - x7 = residual() - n *= 19 - return n, None, x0, x1, x2, x3, x4, x5, x6, x7, None, None - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - x8 = residual() - x9 = residual() - check(x0.next.foo == 26) - check(x1.next.foo == 26) - check(x2.next.foo == 26) - check(x3.next.foo == 26) - check(x4.next.foo == 26) - check(x5.next.foo == 26) - check(x6.next.foo == 26) - check(x7.next.foo == 26) - check(x8.next.foo == 26) - check(x9.next.foo == 26) - x0, x1, x2, x3, x4, x5, x6, x7 = x7, x4, x6, x5, x3, x2, x9, x8 + libc = CDLL(libc_name) + c_strchr = libc.getpointer('strchr', [types.pointer, types.sint], + types.pointer) + glob.c_strchr = c_strchr + return (n, None, None, None, None, None, + None, None, None, None, None, None) + # + def f(n, x, *args): + f42(n) n -= 1 - return n, None, x0, x1, x2, x3, x4, x5, x6, x7, None, None - return before, f, None - - def test_compile_framework_3_extra(self): - self.run_orig('compile_framework_3_extra', 6, None) # check that it does not raise CheckError - self.run('compile_framework_3_extra') - - def define_compile_framework_4(cls): - # Fourth version of the test, with __del__. - from pypy.rlib.debug import debug_print - class Counter: - cnt = 0 - counter = Counter() - class Z: - def __del__(self): - counter.cnt -= 1 - def before(n, x): - debug_print('counter.cnt =', counter.cnt) - check(counter.cnt < 5) - counter.cnt = n // x.foo - return n, x, None, None, None, None, None, None, None, None, None, None - def f(n, x, *args): - Z() - n -= x.foo return (n, x) + args return before, f, None - def test_compile_framework_4(self): - self.run('compile_framework_4') + def test_simple(self): + self.run('simple') - def define_compile_framework_5(cls): - # Test string manipulation. - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - n -= x.foo - s += str(n) - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - check(len(s) == 1*5 + 2*45 + 3*450 + 4*500) - return None, f, after - - def test_compile_framework_5(self): - self.run('compile_framework_5') - - def define_compile_framework_7(cls): - # Array of pointers (test the write barrier for setarrayitem_gc) + def define_close_stack(self): + # + class Glob(object): + pass + glob = Glob() + class X(object): + pass + # + def callback(p1, p2): + for i in range(100): + glob.lst.append(X()) + return rffi.cast(rffi.INT, 1) + CALLBACK = lltype.Ptr(lltype.FuncType([lltype.Signed, + lltype.Signed], rffi.INT)) + # + @dont_look_inside + def alloc1(): + return llmemory.raw_malloc(16) + @dont_look_inside + def free1(p): + llmemory.raw_free(p) + # + def f42(): + length = len(glob.lst) + c_qsort = glob.c_qsort + raw = alloc1() + fn = llhelper(CALLBACK, rffi._make_wrapper_for(CALLBACK, callback)) + argchain = ArgChain() + argchain = argchain.arg(rffi.cast(lltype.Signed, raw)) + argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 2)) + argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 8)) + argchain = argchain.arg(rffi.cast(lltype.Signed, fn)) + c_qsort.call(argchain, lltype.Void) + free1(raw) + check(len(glob.lst) > length) + del glob.lst[:] + # def before(n, x): - return n, x, None, None, None, None, None, None, None, None, [X(123)], None - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - if n < 1900: - check(l[0].x == 123) - l = [None] * 16 - l[0] = X(123) - l[1] = X(n) - l[2] = X(n+10) - l[3] = X(n+20) - l[4] = X(n+30) - l[5] = X(n+40) - l[6] = X(n+50) - l[7] = X(n+60) - l[8] = X(n+70) - l[9] = X(n+80) - l[10] = X(n+90) - l[11] = X(n+100) - l[12] = X(n+110) - l[13] = X(n+120) - l[14] = X(n+130) - l[15] = X(n+140) - if n < 1800: - check(len(l) == 16) - check(l[0].x == 123) - check(l[1].x == n) - check(l[2].x == n+10) - check(l[3].x == n+20) - check(l[4].x == n+30) - check(l[5].x == n+40) - check(l[6].x == n+50) - check(l[7].x == n+60) - check(l[8].x == n+70) - check(l[9].x == n+80) - check(l[10].x == n+90) - check(l[11].x == n+100) - check(l[12].x == n+110) - check(l[13].x == n+120) - check(l[14].x == n+130) - check(l[15].x == n+140) - n -= x.foo - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - check(len(l) == 16) - check(l[0].x == 123) - check(l[1].x == 2) - check(l[2].x == 12) - check(l[3].x == 22) - check(l[4].x == 32) - check(l[5].x == 42) - check(l[6].x == 52) - check(l[7].x == 62) - check(l[8].x == 72) - check(l[9].x == 82) - check(l[10].x == 92) - check(l[11].x == 102) - check(l[12].x == 112) - check(l[13].x == 122) - check(l[14].x == 132) - check(l[15].x == 142) - return before, f, after - - def test_compile_framework_7(self): - self.run('compile_framework_7') - - def define_compile_framework_external_exception_handling(cls): - def before(n, x): - x = X(0) - return n, x, None, None, None, None, None, None, None, None, None, None - - @dont_look_inside - def g(x): - if x > 200: - return 2 - raise ValueError - @dont_look_inside - def h(x): - if x > 150: - raise ValueError - return 2 - - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - try: - x.x += g(n) - except ValueError: - x.x += 1 - try: - x.x += h(n) - except ValueError: - x.x -= 1 + libc = CDLL(libc_name) + types_size_t = clibffi.cast_type_to_ffitype(rffi.SIZE_T) + c_qsort = libc.getpointer('qsort', [types.pointer, types_size_t, + types_size_t, types.pointer], + types.void) + glob.c_qsort = c_qsort + glob.lst = [] + return (n, None, None, None, None, None, + None, None, None, None, None, None) + # + def f(n, x, *args): + f42() n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - - def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - check(x.x == 1800 * 2 + 1850 * 2 + 200 - 150) - + return (n, x) + args return before, f, None - def test_compile_framework_external_exception_handling(self): - self.run('compile_framework_external_exception_handling') + def test_close_stack(self): + self.run('close_stack') - def define_compile_framework_bug1(self): - @purefunction - def nonmoving(): - x = X(1) - for i in range(7): - rgc.collect() - return x - @dont_look_inside - def do_more_stuff(): - x = X(5) - for i in range(7): - rgc.collect() - return x - - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - x0 = do_more_stuff() - check(nonmoving().x == 1) - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - - return None, f, None - - def test_compile_framework_bug1(self): - self.run('compile_framework_bug1', 200) - - def define_compile_framework_vref(self): - from pypy.rlib.jit import virtual_ref, virtual_ref_finish - class A: - pass - glob = A() - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - a = A() - glob.v = vref = virtual_ref(a) - virtual_ref_finish(vref, a) - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - return None, f, None - - def test_compile_framework_vref(self): - self.run('compile_framework_vref', 200) - - def define_compile_framework_float(self): - # test for a bug: the fastpath_malloc does not save and restore - # xmm registers around the actual call to the slow path - class A: - x0 = x1 = x2 = x3 = x4 = x5 = x6 = x7 = 0 - @dont_look_inside - def escape1(a): - a.x0 += 0 - a.x1 += 6 - a.x2 += 12 - a.x3 += 18 - a.x4 += 24 - a.x5 += 30 - a.x6 += 36 - a.x7 += 42 - @dont_look_inside - def escape2(n, f0, f1, f2, f3, f4, f5, f6, f7): - check(f0 == n + 0.0) - check(f1 == n + 0.125) - check(f2 == n + 0.25) - check(f3 == n + 0.375) - check(f4 == n + 0.5) - check(f5 == n + 0.625) - check(f6 == n + 0.75) - check(f7 == n + 0.875) - @unroll_safe - def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - i = 0 - while i < 42: - m = n + i - f0 = m + 0.0 - f1 = m + 0.125 - f2 = m + 0.25 - f3 = m + 0.375 - f4 = m + 0.5 - f5 = m + 0.625 - f6 = m + 0.75 - f7 = m + 0.875 - a1 = A() - # at this point, all or most f's are still in xmm registers - escape1(a1) - escape2(m, f0, f1, f2, f3, f4, f5, f6, f7) - i += 1 - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - return None, f, None - - def test_compile_framework_float(self): - self.run('compile_framework_float') - - def define_compile_framework_minimal_size_in_nursery(self): - S = lltype.GcStruct('S') # no fields! - T = lltype.GcStruct('T', ('i', lltype.Signed)) - @unroll_safe - def f42(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): - lst1 = [] - lst2 = [] - i = 0 - while i < 42: - s1 = lltype.malloc(S) - t1 = lltype.malloc(T) - t1.i = 10000 + i + n - lst1.append(s1) - lst2.append(t1) - i += 1 - i = 0 - while i < 42: - check(lst2[i].i == 10000 + i + n) - i += 1 - n -= 1 - return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s - return None, f42, None - - def test_compile_framework_minimal_size_in_nursery(self): - self.run('compile_framework_minimal_size_in_nursery') - - -class TestShadowStack(CompileFrameworkTests): +class TestShadowStack(ReleaseGILTests): gcrootfinder = "shadowstack" -class TestAsmGcc(CompileFrameworkTests): +class TestAsmGcc(ReleaseGILTests): gcrootfinder = "asmgcc" diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/assembler.py b/pypy/jit/codewriter/assembler.py --- a/pypy/jit/codewriter/assembler.py +++ b/pypy/jit/codewriter/assembler.py @@ -76,7 +76,8 @@ TYPE = llmemory.Address if TYPE == llmemory.Address: value = heaptracker.adr2int(value) - elif not isinstance(value, ComputedIntSymbolic): + if not isinstance(value, (llmemory.AddressAsInt, + ComputedIntSymbolic)): value = lltype.cast_primitive(lltype.Signed, value) if allow_short and -128 <= value <= 127: # emit the constant as a small integer diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -208,12 +208,12 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " @@ -225,9 +225,9 @@ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -237,7 +237,9 @@ self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, oopspecindex, can_invalidate) # - if pure or loopinvariant: + if oopspecindex != EffectInfo.OS_NONE: + assert effectinfo is not None + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -75,12 +75,13 @@ # OS_MATH_SQRT = 100 - def __new__(cls, readonly_descrs_fields, + def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, can_invalidate=False): key = (frozenset(readonly_descrs_fields), + frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, @@ -89,8 +90,9 @@ return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields + result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: @@ -108,6 +110,9 @@ def check_forces_virtual_or_virtualizable(self): return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE + def has_random_effects(self): + return self.oopspecindex == self.OS_LIBFFI_CALL + def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, @@ -116,7 +121,7 @@ if effects is top_set: return None readonly_descrs_fields = [] - # readonly_descrs_arrays = [] --- not enabled for now + readonly_descrs_arrays = [] write_descrs_fields = [] write_descrs_arrays = [] @@ -142,10 +147,13 @@ elif tup[0] == "array": add_array(write_descrs_arrays, tup) elif tup[0] == "readarray": - pass + tupw = ("array",) + tup[1:] + if tupw not in effects: + add_array(readonly_descrs_arrays, tup) else: assert 0 return EffectInfo(readonly_descrs_fields, + readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, extraeffect, diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -768,10 +768,10 @@ from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof from pypy.rlib.rarithmetic import intmask assert not self._is_gc(op.args[0]) - size1, unsigned1 = size_and_sign(op.args[0].concretetype) size2, unsigned2 = size_and_sign(op.result.concretetype) if size2 >= sizeof(lltype.Signed): return # the target type is LONG or ULONG + size1, unsigned1 = size_and_sign(op.args[0].concretetype) # def bounds(size, unsigned): if unsigned: @@ -800,6 +800,13 @@ result[-1].result = op.result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from @@ -847,7 +854,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1328,13 +1335,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1380,7 +1387,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -35,8 +35,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' @@ -44,10 +44,6 @@ return True if mod.startswith('pypy.translator.'): # XXX wtf? return True - # string builder interface - if mod == 'pypy.rpython.lltypesystem.rbuilder': - return True - return False def look_inside_graph(self, graph): diff --git a/pypy/jit/codewriter/test/test_effectinfo.py b/pypy/jit/codewriter/test/test_effectinfo.py --- a/pypy/jit/codewriter/test/test_effectinfo.py +++ b/pypy/jit/codewriter/test/test_effectinfo.py @@ -34,6 +34,15 @@ assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays +def test_include_read_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert list(effectinfo.readonly_descrs_arrays) == [('arraydescr', A)] + assert not effectinfo.write_descrs_fields + assert not effectinfo.write_descrs_arrays + def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) @@ -51,6 +60,16 @@ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.write_descrs_arrays +def test_dont_include_read_and_write_array(): + A = lltype.GcArray(lltype.Signed) + effects = frozenset([("readarray", lltype.Ptr(A)), + ("array", lltype.Ptr(A))]) + effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) + assert not effectinfo.readonly_descrs_fields + assert not effectinfo.readonly_descrs_arrays + assert not effectinfo.write_descrs_fields + assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)] + def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -813,6 +813,15 @@ int_return %i0 """, transform=True) + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop -from pypy.rlib.debug import make_sure_not_resized, fatalerror +from pypy.rlib.debug import make_sure_not_resized from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLException diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -3,7 +3,8 @@ from pypy.rpython.ootypesystem import ootype from pypy.objspace.flow.model import Constant, Variable from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.debug import debug_start, debug_stop +from pypy.rlib.debug import debug_start, debug_stop, debug_print +from pypy.rlib import rstack from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name @@ -13,8 +14,8 @@ from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper -from pypy.jit.metainterp.optimizeutil import InvalidLoop -from pypy.jit.metainterp.resume import NUMBERING +from pypy.jit.metainterp.optimize import InvalidLoop +from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong def giveup(): @@ -118,6 +119,7 @@ old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: + debug_print("compile_new_loop: got an InvalidLoop") return None if old_loop_token is not None: metainterp.staticdata.log("reusing old loop") @@ -156,6 +158,7 @@ def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type): jitdriver_sd.on_compile(metainterp_sd.logger_ops, loop.token, loop.operations, type, greenkey) + loopname = jitdriver_sd.warmstate.get_location_str(greenkey) globaldata = metainterp_sd.globaldata loop_token = loop.token loop_token.number = n = globaldata.loopnumbering @@ -170,7 +173,7 @@ debug_start("jit-backend") try: ops_offset = metainterp_sd.cpu.compile_loop(loop.inputargs, operations, - loop.token) + loop.token, name=loopname) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() @@ -300,7 +303,7 @@ rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) CNT_INT = -0x20000000 CNT_REF = -0x40000000 @@ -452,9 +455,17 @@ # Called during a residual call from the assembler, if the code # actually needs to force one of the virtualrefs or the virtualizable. # Implemented by forcing *all* virtualrefs and the virtualizable. - faildescr = cpu.force(token) - assert isinstance(faildescr, ResumeGuardForcedDescr) - faildescr.handle_async_forcing(token) + + # don't interrupt me! If the stack runs out in force_from_resumedata() + # then we have seen cpu.force() but not self.save_data(), leaving in + # an inconsistent state + rstack._stack_criticalcode_start() + try: + faildescr = cpu.force(token) + assert isinstance(faildescr, ResumeGuardForcedDescr) + faildescr.handle_async_forcing(token) + finally: + rstack._stack_criticalcode_stop() def handle_async_forcing(self, force_token): from pypy.jit.metainterp.resume import force_from_resumedata @@ -623,6 +634,7 @@ new_loop, state.enable_opts, inline_short_preamble, retraced) except InvalidLoop: + debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop return None diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -82,9 +82,6 @@ do_call_loopinvariant = do_call do_call_may_force = do_call -def do_call_c(cpu, metainterp, argboxes, descr): - raise NotImplementedError("Should never be called directly") - def do_getarrayitem_gc(cpu, _, arraybox, indexbox, arraydescr): array = arraybox.getref_base() index = indexbox.getint() @@ -319,9 +316,11 @@ if value in (rop.FORCE_TOKEN, rop.CALL_ASSEMBLER, rop.COND_CALL_GC_WB, + rop.COND_CALL_GC_WB_ARRAY, rop.DEBUG_MERGE_POINT, rop.JIT_DEBUG, rop.SETARRAYITEM_RAW, + rop.CALL_RELEASE_GIL, rop.QUASIIMMUT_FIELD, ): # list of opcodes never executed by pyjitpl continue diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -4,7 +4,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rlib.objectmodel import we_are_translated, r_dict, Symbolic from pypy.rlib.objectmodel import compute_unique_id -from pypy.rlib.rarithmetic import intmask, r_int64 +from pypy.rlib.rarithmetic import r_int64 from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop @@ -712,10 +712,14 @@ return -2 # xxx risk of changing hash... def make_hashable_int(i): + from pypy.rpython.lltypesystem.ll2ctypes import NotCtypesAllocatedStructure if not we_are_translated() and isinstance(i, llmemory.AddressAsInt): # Warning: such a hash changes at the time of translation adr = heaptracker.int2adr(i) - return llmemory.cast_adr_to_int(adr, "emulated") + try: + return llmemory.cast_adr_to_int(adr, "emulated") + except NotCtypesAllocatedStructure: + return 12345 # use an arbitrary number for the hash return i def get_const_ptr_for_string(s): @@ -761,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled @@ -787,11 +792,13 @@ def dump(self): self.compiled_loop_token.cpu.dump_loop_token(self) + class TreeLoop(object): inputargs = None operations = None token = None call_pure_results = None + logops = None quasi_immutable_deps = None def __init__(self, name): diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py --- a/pypy/jit/metainterp/logger.py +++ b/pypy/jit/metainterp/logger.py @@ -11,47 +11,71 @@ def __init__(self, metainterp_sd, guard_number=False): self.metainterp_sd = metainterp_sd - self.ts = metainterp_sd.cpu.ts self.guard_number = guard_number def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): if type is None: debug_start("jit-log-noopt-loop") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-loop") else: debug_start("jit-log-opt-loop") debug_print("# Loop", number, ":", type, "with", len(operations), "ops") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-opt-loop") + return logops def log_bridge(self, inputargs, operations, number=-1, ops_offset=None): if number == -1: debug_start("jit-log-noopt-bridge") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-bridge") else: debug_start("jit-log-opt-bridge") debug_print("# bridge out of Guard", number, "with", len(operations), "ops") - self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-opt-bridge") + return logops def log_short_preamble(self, inputargs, operations): debug_start("jit-log-short-preamble") - self._log_operations(inputargs, operations, ops_offset=None) - debug_stop("jit-log-short-preamble") + logops = self._log_operations(inputargs, operations, ops_offset=None) + debug_stop("jit-log-short-preamble") + return logops + + def _log_operations(self, inputargs, operations, ops_offset): + if not have_debug_prints(): + return None + logops = self._make_log_operations() + logops._log_operations(inputargs, operations, ops_offset) + return logops + + def _make_log_operations(self): + return LogOperations(self.metainterp_sd, self.guard_number) + + +class LogOperations(object): + """ + ResOperation logger. Each instance contains a memo giving numbers + to boxes, and is typically used to log a single loop. + """ + def __init__(self, metainterp_sd, guard_number): + self.metainterp_sd = metainterp_sd + self.ts = metainterp_sd.cpu.ts + self.guard_number = guard_number + self.memo = {} def repr_of_descr(self, descr): return descr.repr_of_descr() - def repr_of_arg(self, memo, arg): + def repr_of_arg(self, arg): try: - mv = memo[arg] + mv = self.memo[arg] except KeyError: - mv = len(memo) - memo[arg] = mv + mv = len(self.memo) + self.memo[arg] = mv if isinstance(arg, ConstInt): if int_could_be_an_address(arg.value): addr = arg.getaddr() @@ -75,11 +99,12 @@ else: return '?' - def repr_of_resop(self, memo, op, ops_offset=None): + def repr_of_resop(self, op, ops_offset=None): if op.getopnum() == rop.DEBUG_MERGE_POINT: - loc = op.getarg(0)._get_str() - reclev = op.getarg(1).getint() - return "debug_merge_point('%s', %s)" % (loc, reclev) + jd_sd = self.metainterp_sd.jitdrivers_sd[op.getarg(0).getint()] + s = jd_sd.warmstate.get_location_str(op.getarglist()[2:]) + s = s.replace(',', '.') # we use comma for argument splitting + return "debug_merge_point(%d, '%s')" % (op.getarg(1).getint(), s) if ops_offset is None: offset = -1 else: @@ -88,9 +113,10 @@ s_offset = "" else: s_offset = "+%d: " % offset - args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())]) + args = ", ".join([self.repr_of_arg(op.getarg(i)) for i in range(op.numargs())]) + if op.result is not None: - res = self.repr_of_arg(memo, op.result) + " = " + res = self.repr_of_arg(op.result) + " = " else: res = "" is_guard = op.is_guard() @@ -103,7 +129,7 @@ r = self.repr_of_descr(descr) args += ', descr=' + r if is_guard and op.getfailargs() is not None: - fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg) + fail_args = ' [' + ", ".join([self.repr_of_arg(arg) for arg in op.getfailargs()]) + ']' else: fail_args = '' @@ -114,13 +140,12 @@ return if ops_offset is None: ops_offset = {} - memo = {} if inputargs is not None: - args = ", ".join([self.repr_of_arg(memo, arg) for arg in inputargs]) + args = ", ".join([self.repr_of_arg(arg) for arg in inputargs]) debug_print('[' + args + ']') for i in range(len(operations)): op = operations[i] - debug_print(self.repr_of_resop(memo, operations[i], ops_offset)) + debug_print(self.repr_of_resop(operations[i], ops_offset)) if ops_offset and None in ops_offset: offset = ops_offset[None] debug_print("+%d: --end of the loop--" % offset) diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py --- a/pypy/jit/metainterp/optimize.py +++ b/pypy/jit/metainterp/optimize.py @@ -1,9 +1,20 @@ from pypy.rlib.debug import debug_start, debug_stop +from pypy.jit.metainterp.jitexc import JitException + +class InvalidLoop(JitException): + """Raised when the optimize*.py detect that the loop that + we are trying to build cannot possibly make sense as a + long-running loop (e.g. it cannot run 2 complete iterations).""" + +class RetraceLoop(JitException): + """ Raised when inlining a short preamble resulted in an + InvalidLoop. This means the optimized loop is too specialized + to be useful here, so we trace it again and produced a second + copy specialized in some different way. + """ # ____________________________________________________________ -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, optimize_bridge_1 - def optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): debug_start("jit-optimize") try: @@ -13,8 +24,9 @@ debug_stop("jit-optimize") def _optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts): - cpu = metainterp_sd.cpu - metainterp_sd.logger_noopt.log_loop(loop.inputargs, loop.operations) + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 + loop.logops = metainterp_sd.logger_noopt.log_loop(loop.inputargs, + loop.operations) # XXX do we really still need a list? if old_loop_tokens: return old_loop_tokens[0] @@ -35,8 +47,9 @@ def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts, inline_short_preamble, retraced=False): - cpu = metainterp_sd.cpu - metainterp_sd.logger_noopt.log_loop(bridge.inputargs, bridge.operations) + from pypy.jit.metainterp.optimizeopt import optimize_bridge_1 + bridge.logops = metainterp_sd.logger_noopt.log_loop(bridge.inputargs, + bridge.operations) if old_loop_tokens: old_loop_token = old_loop_tokens[0] bridge.operations[-1].setdescr(old_loop_token) # patch jump target diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -15,22 +15,20 @@ ('virtualize', OptVirtualize), ('string', OptString), ('heap', OptHeap), - ('ffi', OptFfiCall), + ('ffi', None), ('unroll', None)] # no direct instantiation of unroll unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] +ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES - -def optimize_loop_1(metainterp_sd, loop, enable_opts, +def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): - """Optimize loop.operations to remove internal overheadish operations. - """ + config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: @@ -40,6 +38,11 @@ # FIXME: Workaround to disable string optimisation # during preamble but to keep it during the loop optimizations.append(o) + elif name == 'ffi' and config.translation.jit_ffi: + # we cannot put the class directly in the unrolling_iterable, + # because we do not want it to be seen at all (to avoid to + # introduce a dependency on libffi in case we do not need it) + optimizations.append(OptFfiCall()) if ('rewrite' not in enable_opts or 'virtualize' not in enable_opts or 'heap' not in enable_opts): @@ -48,6 +51,17 @@ if inline_short_preamble: optimizations = [OptInlineShortPreamble(retraced)] + optimizations + return optimizations, unroll + + +def optimize_loop_1(metainterp_sd, loop, enable_opts, + inline_short_preamble=True, retraced=False): + """Optimize loop.operations to remove internal overheadish operations. + """ + + optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, + inline_short_preamble, retraced) + if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -1,10 +1,13 @@ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.libffi import Func +from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization +from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind + class FuncInfo(object): @@ -12,14 +15,18 @@ restype = None descr = None prepare_op = None - force_token_op = None def __init__(self, funcval, cpu, prepare_op): self.funcval = funcval self.opargs = [] argtypes, restype = self._get_signature(funcval) - self.descr = cpu.calldescrof_dynamic(argtypes, restype) + try: + self.descr = cpu.calldescrof_dynamic(argtypes, restype) + except UnsupportedKind: + # e.g., I or U for long longs + self.descr = None self.prepare_op = prepare_op + self.delayed_ops = [] def _get_signature(self, funcval): """ @@ -64,37 +71,51 @@ class OptFfiCall(Optimization): - def __init__(self): + def setup(self): self.funcinfo = None + if self.optimizer.loop is not None: + self.logops = self.optimizer.loop.logops + else: + self.logops = None + + def propagate_begin_forward(self): + debug_start('jit-log-ffiopt') + Optimization.propagate_begin_forward(self) + + def propagate_end_forward(self): + debug_stop('jit-log-ffiopt') + Optimization.propagate_end_forward(self) def reconstruct_for_next_iteration(self, optimizer, valuemap): return OptFfiCall() # FIXME: Should any status be saved for next iteration? def begin_optimization(self, funcval, op): - self.rollback_maybe() + self.rollback_maybe('begin_optimization', op) self.funcinfo = FuncInfo(funcval, self.optimizer.cpu, op) def commit_optimization(self): self.funcinfo = None - def rollback_maybe(self): + def rollback_maybe(self, msg, op): if self.funcinfo is None: return # nothing to rollback # # we immediately set funcinfo to None to prevent recursion when # calling emit_op + if self.logops is not None: + debug_print('rollback: ' + msg + ': ', self.logops.repr_of_resop(op)) funcinfo = self.funcinfo self.funcinfo = None self.emit_operation(funcinfo.prepare_op) for op in funcinfo.opargs: self.emit_operation(op) - if funcinfo.force_token_op: - self.emit_operation(funcinfo.force_token_op) + for delayed_op in funcinfo.delayed_ops: + self.emit_operation(delayed_op) def emit_operation(self, op): # we cannot emit any operation during the optimization - self.rollback_maybe() + self.rollback_maybe('invalid op', op) Optimization.emit_operation(self, op) def optimize_CALL(self, op): @@ -135,13 +156,18 @@ # call_may_force and the setfield_gc, so the final result we get is # again force_token/setfield_gc/call_may_force. # + # However, note that nowadays we also allow to have any setfield_gc + # between libffi_prepare and libffi_call, so while the comment above + # it's a bit superfluous, it has been left there for future reference. if self.funcinfo is None: self.emit_operation(op) else: - self.funcinfo.force_token_op = op + self.funcinfo.delayed_ops.append(op) + + optimize_SETFIELD_GC = optimize_FORCE_TOKEN def do_prepare_call(self, op): - self.rollback_maybe() + self.rollback_maybe('prepare call', op) funcval = self._get_funcval(op) if not funcval.is_constant(): return [op] # cannot optimize @@ -165,23 +191,19 @@ for push_op in funcinfo.opargs: argval = self.getvalue(push_op.getarg(2)) arglist.append(argval.force_box()) - newop = ResOperation(rop.CALL_MAY_FORCE, arglist, op.result, + newop = ResOperation(rop.CALL_RELEASE_GIL, arglist, op.result, descr=funcinfo.descr) self.commit_optimization() ops = [] - if funcinfo.force_token_op: - ops.append(funcinfo.force_token_op) + for delayed_op in funcinfo.delayed_ops: + ops.append(delayed_op) ops.append(newop) return ops def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + if self.logops is not None: + debug_print(self.logops.repr_of_resop(op)) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -192,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -8,8 +8,8 @@ class CachedField(object): def __init__(self): - # Cache information for a field descr. It can be in one - # of two states: + # Cache information for a field descr, or for an (array descr, index) + # pair. It can be in one of two states: # # 1. 'cached_fields' is a dict mapping OptValues of structs # to OptValues of fields. All fields on-heap are @@ -27,19 +27,19 @@ self._lazy_setfield_registered = False def do_setfield(self, optheap, op): - # Update the state with the SETFIELD_GC operation 'op'. + # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) if self.possible_aliasing(optheap, structvalue): self.force_lazy_setfield(optheap) assert not self.possible_aliasing(optheap, structvalue) cached_fieldvalue = self._cached_fields.get(structvalue, None) if cached_fieldvalue is not fieldvalue: # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields list + # myself in the optheap's _lazy_setfields_and_arrayitems list self._lazy_setfield = op if not self._lazy_setfield_registered: - optheap._lazy_setfields.append(self) + optheap._lazy_setfields_and_arrayitems.append(self) self._lazy_setfield_registered = True else: # this is the case where the pending setfield ends up @@ -65,7 +65,7 @@ if self._lazy_setfield is not None: op = self._lazy_setfield assert optheap.getvalue(op.getarg(0)) is structvalue - return optheap.getvalue(op.getarg(1)) + return optheap.getvalue(op.getarglist()[-1]) else: return self._cached_fields.get(structvalue, None) @@ -87,7 +87,7 @@ # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) - fieldvalue = optheap.getvalue(op.getarg(1)) + fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) def get_reconstructed(self, optimizer, valuemap): @@ -100,25 +100,20 @@ return cf -class CachedArrayItems(object): - def __init__(self): - self.fixed_index_items = {} - self.var_index_item = None - self.var_index_indexvalue = None - class BogusPureField(JitException): pass class OptHeap(Optimization): """Cache repeated heap accesses""" - + def __init__(self): # cached fields: {descr: CachedField} self.cached_fields = {} - self._lazy_setfields = [] - # cached array items: {descr: CachedArrayItems} + # cached array items: {array descr: {index: CachedField}} self.cached_arrayitems = {} + # + self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -126,34 +121,23 @@ new = OptHeap() if True: - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() else: assert 0 # was: new.lazy_setfields = self.lazy_setfields - + for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap) - new.cached_arrayitems = {} - for descr, d in self.cached_arrayitems.items(): - newd = {} - new.cached_arrayitems[descr] = newd - for value, cache in d.items(): - newcache = CachedArrayItems() - newd[value.get_reconstructed(optimizer, valuemap)] = newcache - if cache.var_index_item: - newcache.var_index_item = \ - cache.var_index_item.get_reconstructed(optimizer, valuemap) - if cache.var_index_indexvalue: - newcache.var_index_indexvalue = \ - cache.var_index_indexvalue.get_reconstructed(optimizer, valuemap) - for index, fieldvalue in cache.fixed_index_items.items(): - newcache.fixed_index_items[index] = \ - fieldvalue.get_reconstructed(optimizer, valuemap) + for descr, submap in self.cached_arrayitems.items(): + newdict = {} + for index, d in submap.items(): + newdict[index] = d.get_reconstructed(optimizer, valuemap) + new.cached_arrayitems[descr] = newdict return new def clean_caches(self): - del self._lazy_setfields[:] + del self._lazy_setfields_and_arrayitems[:] self.cached_fields.clear() self.cached_arrayitems.clear() @@ -164,50 +148,16 @@ cf = self.cached_fields[descr] = CachedField() return cf - def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): - d = self.cached_arrayitems.get(descr, None) - if d is None: - d = self.cached_arrayitems[descr] = {} - cache = d.get(value, None) - if cache is None: - cache = d[value] = CachedArrayItems() - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - index = indexbox.getint() - if write: - for value, othercache in d.iteritems(): - # fixed index, clean the variable index cache, in case the - # index is the same - othercache.var_index_indexvalue = None - othercache.var_index_item = None - try: - del othercache.fixed_index_items[index] - except KeyError: - pass - cache.fixed_index_items[index] = fieldvalue - else: - if write: - for value, othercache in d.iteritems(): - # variable index, clear all caches for this descr - othercache.var_index_indexvalue = None - othercache.var_index_item = None - othercache.fixed_index_items.clear() - cache.var_index_indexvalue = indexvalue - cache.var_index_item = fieldvalue - - def read_cached_arrayitem(self, descr, value, indexvalue): - d = self.cached_arrayitems.get(descr, None) - if d is None: - return None - cache = d.get(value, None) - if cache is None: - return None - indexbox = self.get_constant_box(indexvalue.box) - if indexbox is not None: - return cache.fixed_index_items.get(indexbox.getint(), None) - elif cache.var_index_indexvalue is indexvalue: - return cache.var_index_item - return None + def arrayitem_cache(self, descr, index): + try: + submap = self.cached_arrayitems[descr] + except KeyError: + submap = self.cached_arrayitems[descr] = {} + try: + cf = submap[index] + except KeyError: + cf = submap[index] = CachedField() + return cf def emit_operation(self, op): self.emitting_operation(op) @@ -219,7 +169,8 @@ if op.is_ovf(): return if op.is_guard(): - self.optimizer.pendingfields = self.force_lazy_setfields_for_guard() + self.optimizer.pendingfields = ( + self.force_lazy_setfields_and_arrayitems_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -235,6 +186,7 @@ assert opnum != rop.CALL_PURE if (opnum == rop.CALL or opnum == rop.CALL_MAY_FORCE or + opnum == rop.CALL_RELEASE_GIL or opnum == rop.CALL_ASSEMBLER): if opnum == rop.CALL_ASSEMBLER: effectinfo = None @@ -242,11 +194,13 @@ effectinfo = op.getdescr().get_extra_info() if effectinfo is None or effectinfo.check_can_invalidate(): self._seen_guard_not_invalidated = False - if effectinfo is not None: + if effectinfo is not None and not effectinfo.has_random_effects(): # XXX we can get the wrong complexity here, if the lists # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: self.force_lazy_setfield(fielddescr) + for arraydescr in effectinfo.readonly_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: self.force_lazy_setfield(fielddescr) try: @@ -255,8 +209,11 @@ except KeyError: pass for arraydescr in effectinfo.write_descrs_arrays: + self.force_lazy_setarrayitem(arraydescr) try: - del self.cached_arrayitems[arraydescr] + submap = self.cached_arrayitems[arraydescr] + for cf in submap.itervalues(): + cf._cached_fields.clear() except KeyError: pass if effectinfo.check_forces_virtual_or_virtualizable(): @@ -265,7 +222,7 @@ # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. return - self.force_all_lazy_setfields() + self.force_all_lazy_setfields_and_arrayitems() self.clean_caches() @@ -276,6 +233,10 @@ for cf in self.cached_fields.itervalues(): if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] + for submap in self.cached_arrayitems.itervalues(): + for cf in submap.itervalues(): + if value in cf._cached_fields: + cf._cached_fields[newvalue] = cf._cached_fields[value] def force_lazy_setfield(self, descr): try: @@ -284,6 +245,14 @@ return cf.force_lazy_setfield(self) + def force_lazy_setarrayitem(self, arraydescr): + try: + submap = self.cached_arrayitems[arraydescr] + except KeyError: + return + for cf in submap.values(): + cf.force_lazy_setfield(self) + def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes # sense to avoid a situation like "int_eq/setfield_gc/guard_true", @@ -308,30 +277,49 @@ newoperations[-2] = lastop newoperations[-1] = prevop - def force_all_lazy_setfields(self): - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + def _assert_valid_cf(self, cf): + # check that 'cf' is in cached_fields or cached_arrayitems + if not we_are_translated(): + if cf not in self.cached_fields.values(): + for submap in self.cached_arrayitems.values(): + if cf in submap.values(): + break + else: + assert 0, "'cf' not in cached_fields/cached_arrayitems" + + def force_all_lazy_setfields_and_arrayitems(self): + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) cf.force_lazy_setfield(self) - def force_lazy_setfields_for_guard(self): + def force_lazy_setfields_and_arrayitems_for_guard(self): pendingfields = [] - for cf in self._lazy_setfields: - if not we_are_translated(): - assert cf in self.cached_fields.values() + for cf in self._lazy_setfields_and_arrayitems: + self._assert_valid_cf(cf) op = cf._lazy_setfield if op is None: continue # the only really interesting case that we need to handle in the # guards' resume data is that of a virtual object that is stored - # into a field of a non-virtual object. + # into a field of a non-virtual object. Here, 'op' in either + # SETFIELD_GC or SETARRAYITEM_GC. value = self.getvalue(op.getarg(0)) assert not value.is_virtual() # it must be a non-virtual - fieldvalue = self.getvalue(op.getarg(1)) + fieldvalue = self.getvalue(op.getarglist()[-1]) if fieldvalue.is_virtual(): # this is the case that we leave to resume.py + opnum = op.getopnum() + if opnum == rop.SETFIELD_GC: + itemindex = -1 + elif opnum == rop.SETARRAYITEM_GC: + indexvalue = self.getvalue(op.getarg(1)) + assert indexvalue.is_constant() + itemindex = indexvalue.box.getint() + assert itemindex >= 0 + else: + assert 0 pendingfields.append((op.getdescr(), value.box, - fieldvalue.get_key_box())) + fieldvalue.get_key_box(), itemindex)) else: cf.force_lazy_setfield(self) self.fixup_guard_situation() @@ -363,24 +351,45 @@ cf.do_setfield(self, op) def optimize_GETARRAYITEM_GC(self, op): - value = self.getvalue(op.getarg(0)) + arrayvalue = self.getvalue(op.getarg(0)) indexvalue = self.getvalue(op.getarg(1)) - fieldvalue = self.read_cached_arrayitem(op.getdescr(), value, indexvalue) - if fieldvalue is not None: - self.make_equal_to(op.result, fieldvalue) - return - ###self.optimizer.optimize_default(op) + cf = None + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + fieldvalue = cf.getfield_from_cache(self, arrayvalue) + if fieldvalue is not None: + self.make_equal_to(op.result, fieldvalue) + return + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # default case: produce the operation + arrayvalue.ensure_nonnull() self.emit_operation(op) - fieldvalue = self.getvalue(op.result) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue) + # the remember the result of reading the array item + if cf is not None: + fieldvalue = self.getvalue(op.result) + cf.remember_field_value(arrayvalue, fieldvalue) def optimize_SETARRAYITEM_GC(self, op): - self.emit_operation(op) - value = self.getvalue(op.getarg(0)) - fieldvalue = self.getvalue(op.getarg(2)) + if self.has_pure_result(rop.GETARRAYITEM_GC_PURE, [op.getarg(0), + op.getarg(1)], + op.getdescr()): + os.write(2, '[bogus immutable array declaration: %s]\n' % + (op.getdescr().repr_of_descr())) + raise BogusPureField + # indexvalue = self.getvalue(op.getarg(1)) - self.cache_arrayitem_value(op.getdescr(), value, indexvalue, fieldvalue, - write=True) + if indexvalue.is_constant(): + # use the cache on (arraydescr, index), which is a constant + cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) + cf.do_setfield(self, op) + else: + # variable index, so make sure the lazy setarrayitems are done + self.force_lazy_setarrayitem(op.getdescr()) + # and then emit the operation + self.emit_operation(op) def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) @@ -422,13 +431,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeutil import _findall -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - IntLowerBound, IntUpperBound +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, + IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -17,6 +17,14 @@ assert self.posponedop is None return self + def setup(self): + self.posponedop = None + self.nextop = None + + def reconstruct_for_next_iteration(self, optimizer, valuemap): + assert self.posponedop is None + return self + def propagate_forward(self, op): if op.is_ovf(): self.posponedop = op @@ -26,14 +34,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -49,11 +54,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -186,7 +187,7 @@ # Synthesize the reverse ops for optimize_default to reuse self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0)) self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1)) - + def optimize_INT_MUL_OVF(self, op): v1 = self.getvalue(op.getarg(0)) @@ -284,6 +285,11 @@ v1.intbound.make_ge(IntLowerBound(0)) v1.intbound.make_lt(IntUpperBound(256)) + def optimize_UNICODEGETITEM(self, op): + self.emit_operation(op) + v1 = self.getvalue(op.result) + v1.intbound.make_ge(IntLowerBound(0)) + def make_int_lt(self, box1, box2): v1 = self.getvalue(box1) v2 = self.getvalue(box2) @@ -360,6 +366,27 @@ if v2.intbound.intersect(v1.intbound): self.propagate_bounds_backward(op.getarg(1)) + def propagate_bounds_INT_IS_TRUE(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + if v1.intbound.known_ge(IntBound(0, 0)): + v1.intbound.make_gt(IntBound(0, 0)) + self.propagate_bounds_backward(op.getarg(0)) + + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -405,5 +432,7 @@ propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') + +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,9 +4,9 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs -from pypy.jit.metainterp.optimizeutil import descrlist_dict -from pypy.jit.metainterp.optimizeutil import InvalidLoop, args_dict +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.rpython.lltypesystem import lltype @@ -141,6 +141,9 @@ # meaning it has been forced. return self.box is None + def is_forced_virtual(self): + return False + def getfield(self, ofs, default): raise NotImplementedError @@ -175,6 +178,14 @@ def __init__(self): pass # make rpython happy + def propagate_begin_forward(self): + if self.next_optimization: + self.next_optimization.propagate_begin_forward() + + def propagate_end_forward(self): + if self.next_optimization: + self.next_optimization.propagate_end_forward() + def propagate_forward(self, op): raise NotImplementedError @@ -406,11 +417,13 @@ # ^^^ at least at the start of bridges. For loops, we could set # it to False, but we probably don't care self.newoperations = [] + self.first_optimization.propagate_begin_forward() self.i = 0 while self.i < len(self.loop.operations): op = self.loop.operations[self.i] self.first_optimization.propagate_forward(op) self.i += 1 + self.first_optimization.propagate_end_forward() self.loop.operations = self.newoperations self.loop.quasi_immutable_deps = self.quasi_immutable_deps # accumulate counters @@ -421,14 +434,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -556,7 +562,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -21,18 +21,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -184,6 +179,32 @@ else: self.emit_operation(op) + def optimize_FLOAT_MUL(self, op): + arg1 = op.getarg(0) + arg2 = op.getarg(1) + + # Constant fold f0 * 1.0 and turn f0 * -1.0 into a FLOAT_NEG, these + # work in all cases, including NaN and inf + for lhs, rhs in [(arg1, arg2), (arg2, arg1)]: + v1 = self.getvalue(lhs) + v2 = self.getvalue(rhs) + + if v1.is_constant(): + if v1.box.getfloat() == 1.0: + self.make_equal_to(op.result, v2) + return + elif v1.box.getfloat() == -1.0: + self.emit_operation(ResOperation( + rop.FLOAT_NEG, [rhs], op.result + )) + return + self.emit_operation(op) + + def optimize_FLOAT_NEG(self, op): + v1 = op.getarg(0) + self.emit_operation(op) + self.pure(rop.FLOAT_NEG, [op.result], v1) + def optimize_CALL_PURE(self, op): arg_consts = [] for i in range(op.numargs()): @@ -193,7 +214,7 @@ break arg_consts.append(const) else: - # all constant arguments: check if we already know the reslut + # all constant arguments: check if we already know the result try: result = self.optimizer.call_pure_results[arg_consts] except KeyError: @@ -451,5 +472,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeutil import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/__init__.py b/pypy/jit/metainterp/optimizeopt/test/__init__.py new file mode 100644 diff --git a/pypy/jit/metainterp/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py rename from pypy/jit/metainterp/test/test_optimizebasic.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1,37 +1,15 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, FakeMetaInterpStaticData) +from pypy.jit.metainterp.test.test_compile import FakeLogger import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt -from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation -from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.optimizeutil import args_dict - -##class FakeFrame(object): -## parent_resumedata_snapshot = None -## parent_resumedata_frame_info_list = None - -## def __init__(self, code="", pc=0): -## self.jitcode = code -## self.pc = pc - -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() + def test_store_final_boxes_in_guard(): from pypy.jit.metainterp.compile import ResumeGuardDescr @@ -101,7 +79,7 @@ assert vinfo3 is vinfo4 def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil + from pypy.jit.metainterp.optimizeopt import util as optimizeutil h1 = optimizeutil.descrlist_hash([]) h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) h3 = optimizeutil.descrlist_hash( @@ -130,159 +108,55 @@ # ____________________________________________________________ -def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}, - text_right=None): - # try to use the full width of the terminal to display the list - # unfortunately, does not work with the default capture method of py.test - # (which is fd), you you need to use either -s or --capture=sys, else you - # get the standard 80 columns width - totwidth = py.io.get_terminal_width() - width = totwidth / 2 - 1 - print ' Comparing lists '.center(totwidth, '-') - text_right = text_right or 'expected' - print '%s| %s' % ('optimized'.center(width), text_right.center(width)) - for op1, op2 in zip(oplist1, oplist2): - txt1 = str(op1) - txt2 = str(op2) - while txt1 or txt2: - print '%s| %s' % (txt1[:width].ljust(width), txt2[:width]) - txt1 = txt1[width:] - txt2 = txt2[width:] - assert op1.getopnum() == op2.getopnum() - assert op1.numargs() == op2.numargs() - for i in range(op1.numargs()): - x = op1.getarg(i) - y = op2.getarg(i) - assert x == remap.get(y, y) - if op2.result in remap: - assert op1.result == remap[op2.result] - else: - remap[op2.result] = op1.result - if op1.getopnum() != rop.JUMP: # xxx obscure - assert op1.getdescr() == op2.getdescr() - if op1.getfailargs() or op2.getfailargs(): - assert len(op1.getfailargs()) == len(op2.getfailargs()) - if strict_fail_args: - for x, y in zip(op1.getfailargs(), op2.getfailargs()): - assert x == remap.get(y, y) - else: - fail_args1 = set(op1.getfailargs()) - fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()]) - assert fail_args1 == fail_args2 - assert len(oplist1) == len(oplist2) - print '-'*totwidth - return True - -def test_equaloplists(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops, namespace=namespace) - loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), - namespace=namespace) - assert equaloplists(loop1.operations, loop2.operations) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -def test_equaloplists_fail_args(): - ops = """ - [i0] - i1 = int_add(i0, 1) - i2 = int_add(i1, 1) - guard_true(i1) [i2, i1] - jump(i1) - """ - namespace = {} - loop1 = pure_parse(ops, namespace=namespace) - loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop2.operations)") - assert equaloplists(loop1.operations, loop2.operations, - strict_fail_args=False) - loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), - namespace=namespace) - py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") - -# ____________________________________________________________ - -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) class BaseTestBasic(BaseTest): - def invent_fail_descr(self, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap) + enable_opts = "intbounds:rewrite:virtualize:string:heap" def optimize_loop(self, ops, optops, call_pure_results=None): + loop = self.parse(ops) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v - metainterp_sd = FakeMetaInterpStaticData(self.cpu) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - # - # XXX list the exact optimizations that are needed for each test - from pypy.jit.metainterp.optimizeopt import (OptIntBounds, - OptRewrite, - OptVirtualize, - OptString, - OptHeap, - Optimizer) - from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall - - optimizations = [OptIntBounds(), - OptRewrite(), - OptVirtualize(), - OptString(), - OptHeap(), - OptFfiCall(), - ] - optimizer = Optimizer(metainterp_sd, loop, optimizations) - optimizer.propagate_all_forward() - # expected = self.parse(optops) + self._do_optimize_loop(loop, call_pure_results) print '\n'.join([str(o) for o in loop.operations]) self.assert_equal(loop, expected) + def setup_method(self, meth=None): + class FailDescr(compile.ResumeGuardDescr): + oparse = None + def _oparser_uses_descr_of_guard(self, oparse, fail_args): + # typically called 3 times: once when parsing 'ops', + # once when parsing 'preamble', once when parsing 'expected'. + self.oparse = oparse + self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args) + def _clone_if_mutable(self): + assert self is fdescr + return fdescr2 + def __repr__(self): + if self is fdescr: + return 'fdescr' + if self is fdescr2: + return 'fdescr2' + return compile.ResumeGuardDescr.__repr__(self) + # + def snapshot(fail_args, got=[]): + if not got: # only the first time, i.e. when parsing 'ops' + rd_frame_info_list = resume.FrameInfo(None, "code", 11) + rd_snapshot = resume.Snapshot(None, fail_args) + got.append(rd_frame_info_list) + got.append(rd_snapshot) + return got + # + fdescr = instantiate(FailDescr) + self.namespace['fdescr'] = fdescr + fdescr2 = instantiate(FailDescr) + self.namespace['fdescr2'] = fdescr2 + + def teardown_method(self, meth): + self.namespace.pop('fdescr', None) + self.namespace.pop('fdescr2', None) + + class BaseTestOptimizeBasic(BaseTestBasic): @@ -565,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] @@ -1231,8 +1122,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1597,9 +1488,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) jump(p1, i1, i2, p3) """ @@ -1773,6 +1664,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2035,7 +1927,6 @@ self.optimize_loop(ops, expected) def test_merge_guard_nonnull_guard_class(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2053,7 +1944,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2071,7 +1961,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - self.make_fail_descr() ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1, descr=fdescr) [i0] @@ -2287,25 +2176,83 @@ """ self.optimize_loop(ops, expected) + def test_fold_constant_partial_ops_float(self): + ops = """ + [f0] + f1 = float_mul(f0, 1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f2 = escape(f0) + jump(f2) + """ + self.optimize_loop(ops, expected) + + + ops = """ + [f0] + f1 = float_mul(f0, -1.0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + ops = """ + [f0] + f1 = float_mul(-1.0, f0) + f2 = escape(f1) + jump(f2) + """ + expected = """ + [f0] + f1 = float_neg(f0) + f2 = escape(f1) + jump(f2) + """ + self.optimize_loop(ops, expected) + + def test_fold_repeated_float_neg(self): + ops = """ + [f0] + f1 = float_neg(f0) + f2 = float_neg(f1) + f3 = float_neg(f2) + f4 = float_neg(f3) + escape(f4) + jump(f4) + """ + expected = """ + [f0] + # The backend removes this dead op. + f1 = float_neg(f0) + escape(f0) + jump(f0) + """ + self.optimize_loop(ops, expected) + # ---------- - def make_fail_descr(self): - class FailDescr(compile.ResumeGuardDescr): - oparse = None - def _oparser_uses_descr_of_guard(self, oparse, fail_args): - # typically called twice, before and after optimization - if self.oparse is None: - fdescr.rd_frame_info_list = resume.FrameInfo(None, - "code", 11) - fdescr.rd_snapshot = resume.Snapshot(None, fail_args) - self.oparse = oparse - # - fdescr = instantiate(FailDescr) - self.namespace['fdescr'] = fdescr - - def teardown_method(self, meth): - self.namespace.pop('fdescr', None) - def _verify_fail_args(self, boxes, oparse, text): import re r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)") @@ -2414,7 +2361,6 @@ self._verify_fail_args(boxes, fdescr.oparse, expectedtext) def test_expand_fail_1(self): - self.make_fail_descr() ops = """ [i1, i3] # first rename i3 into i4 @@ -2435,7 +2381,6 @@ self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE) def test_expand_fail_2(self): - self.make_fail_descr() ops = """ [i1, i2] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2455,7 +2400,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_3(self): - self.make_fail_descr() ops = """ [i1, i2, i3, p3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2481,7 +2425,7 @@ def test_expand_fail_4(self): for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1', 'i2,p1,p2', 'i2,p2,p1']: - self.make_fail_descr() + self.setup_method() # humpf ops = """ [i1, i2, i3] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2506,7 +2450,6 @@ rop.GUARD_TRUE) def test_expand_fail_5(self): - self.make_fail_descr() ops = """ [i1, i2, i3, i4] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -2530,7 +2473,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_6(self): - self.make_fail_descr() ops = """ [p0, i0, i1] guard_true(i0, descr=fdescr) [p0] @@ -2551,7 +2493,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_varray(self): - self.make_fail_descr() ops = """ [i1] p1 = new_array(3, descr=arraydescr) @@ -2572,7 +2513,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_vstruct(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = new(descr=ssize) @@ -2594,7 +2534,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_v_all_1(self): - self.make_fail_descr() ops = """ [i1, p1a, i2] p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) @@ -2636,7 +2575,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_1(self): - self.make_fail_descr() ops = """ [p1, i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2662,7 +2600,6 @@ ''', rop.GUARD_TRUE) def test_expand_fail_lazy_setfield_2(self): - self.make_fail_descr() ops = """ [i2, i3] p2 = new_with_vtable(ConstClass(node_vtable)) @@ -2686,9 +2623,6 @@ where p2 is a node_vtable, valuedescr=i2 ''', rop.GUARD_TRUE) - -class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -2980,7 +2914,6 @@ self.optimize_loop(ops, expected) def test_vref_virtual_2(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3026,7 +2959,6 @@ ''', rop.GUARD_NOT_FORCED) def test_vref_virtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [p0, i1] # @@ -3065,7 +2997,6 @@ ''', rop.GUARD_NO_EXCEPTION) def test_vref_virtual_after_finish(self): - self.make_fail_descr() ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) @@ -3092,7 +3023,6 @@ self.optimize_loop(ops, expected) def test_vref_nonvirtual_and_lazy_setfield(self): - self.make_fail_descr() ops = """ [i1, p1] p2 = virtual_ref(p1, 23) @@ -3986,11 +3916,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4011,9 +3938,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4032,10 +3957,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -4057,14 +3981,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -4080,10 +3999,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4201,16 +4118,13 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -4249,11 +4163,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4445,11 +4356,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -4566,6 +4474,66 @@ # not obvious, because of the exception UnicodeDecodeError that # can be raised by ll_str2unicode() + def test_strgetitem_repeated(self): + ops = """ + [p0, i0] + i1 = strgetitem(p0, i0) + i2 = strgetitem(p0, i0) + i3 = int_eq(i1, i2) + guard_true(i3) [] + escape(i2) + jump(p0, i0) + """ + expected = """ + [p0, i0] + i1 = strgetitem(p0, i0) + escape(i1) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_int_is_true_bounds(self): + ops = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_ge(0, i0) + guard_false(i2) [] + jump(p0) + """ + expected = """ + [p0] + i0 = strlen(p0) + i1 = int_is_true(i0) + guard_true(i1) [] + jump(p0) + """ + self.optimize_loop(ops, expected) + + def test_strslice_with_other_stuff(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + + +class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): + pass + ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin): diff --git a/pypy/jit/metainterp/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py rename from pypy/jit/metainterp/test/test_optimizefficall.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py --- a/pypy/jit/metainterp/test/test_optimizefficall.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py @@ -2,8 +2,8 @@ from pypy.rlib.libffi import Func, types from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.metainterp.test.test_optimizebasic import BaseTestBasic -from pypy.jit.metainterp.test.test_optimizebasic import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import BaseTestBasic +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import LLtypeMixin class MyCallDescr(AbstractDescr): """ @@ -32,12 +32,15 @@ class TestFfiCall(BaseTestBasic, LLtypeMixin): - jit_ffi = True + + enable_opts = "intbounds:rewrite:virtualize:string:heap:ffi" class namespace: cpu = LLtypeMixin.cpu FUNC = LLtypeMixin.FUNC vable_token_descr = LLtypeMixin.valuedescr + valuedescr = LLtypeMixin.valuedescr + int_float__int = MyCallDescr('if', 'i') funcptr = FakeLLObject() func = FakeLLObject(_fake_class=Func, @@ -48,7 +51,7 @@ restype=types.sint) # def calldescr(cpu, FUNC, oopspecindex, extraeffect=None): - einfo = EffectInfo([], [], [], oopspecindex=oopspecindex, + einfo = EffectInfo([], [], [], [], oopspecindex=oopspecindex, extraeffect=extraeffect) return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo) # @@ -76,7 +79,7 @@ """ expected = """ [i0, f1] - i3 = call_may_force(12345, i0, f1, descr=int_float__int) + i3 = call_release_gil(12345, i0, f1, descr=int_float__int) guard_not_forced() [] guard_no_exception() [] jump(i3, f1) @@ -99,7 +102,7 @@ def test_handle_virtualizables(self): # this test needs an explanation to understand what goes on: see the - # coment in optimize_FORCE_TOKEN + # comment in optimize_FORCE_TOKEN ops = """ [i0, f1, p2] call(0, ConstPtr(func), descr=libffi_prepare) @@ -116,7 +119,7 @@ [i0, f1, p2] i4 = force_token() setfield_gc(p2, i4, descr=vable_token_descr) - i3 = call_may_force(12345, i0, f1, descr=int_float__int) + i3 = call_release_gil(12345, i0, f1, descr=int_float__int) guard_not_forced() [p2] guard_no_exception() [p2] jump(i3, f1, p2) @@ -213,7 +216,7 @@ call(0, ConstPtr(func), descr=libffi_prepare) # # this "nested" call is nicely optimized - i4 = call_may_force(67890, i0, f1, descr=int_float__int) + i4 = call_release_gil(67890, i0, f1, descr=int_float__int) guard_not_forced() [] guard_no_exception() [] # @@ -242,3 +245,25 @@ """ expected = ops loop = self.optimize_loop(ops, expected) + + def test_allow_setfields_in_between(self): + ops = """ + [i0, f1, p2] + call(0, ConstPtr(func), descr=libffi_prepare) + call(0, ConstPtr(func), i0, descr=libffi_push_arg) + call(0, ConstPtr(func), f1, descr=libffi_push_arg) + setfield_gc(p2, i0, descr=valuedescr) + i3 = call_may_force(0, ConstPtr(func), 12345, descr=libffi_call) + guard_not_forced() [] + guard_no_exception() [] + jump(i3, f1, p2) + """ + expected = """ + [i0, f1, p2] + setfield_gc(p2, i0, descr=valuedescr) + i3 = call_release_gil(12345, i0, f1, descr=int_float__int) + guard_not_forced() [] + guard_no_exception() [] + jump(i3, f1, p2) + """ + loop = self.optimize_loop(ops, expected) diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py rename from pypy/jit/metainterp/test/test_optimizeopt.py rename to pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1,202 +1,88 @@ import py from pypy.rlib.objectmodel import instantiate -from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin, - #OOtypeMixin, - BaseTest) +from pypy.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, Storage, _sortboxes) import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt import pypy.jit.metainterp.optimizeopt.virtualize as virtualize -from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT, build_opt_chain +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.jit.metainterp.jitprof import EmptyProfiler from pypy.jit.metainterp import executor, compile, resume, history from pypy.jit.metainterp.resoperation import rop, opname, ResOperation from pypy.jit.tool.oparser import pure_parse -from pypy.jit.metainterp.test.test_optimizebasic import equaloplists -from pypy.jit.metainterp.optimizeutil import args_dict - -class Fake(object): - failargs_limit = 1000 - storedebug = None - -class FakeMetaInterpStaticData(object): - - def __init__(self, cpu, jit_ffi=False): - self.cpu = cpu - self.profiler = EmptyProfiler() - self.options = Fake() - self.globaldata = Fake() - self.jit_ffi = jit_ffi - -def test_store_final_boxes_in_guard(): - from pypy.jit.metainterp.compile import ResumeGuardDescr - from pypy.jit.metainterp.resume import tag, TAGBOX - b0 = BoxInt() - b1 = BoxInt() - opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu), - None) - fdescr = ResumeGuardDescr() - op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr) - # setup rd data - fi0 = resume.FrameInfo(None, "code0", 11) - fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33) - snapshot0 = resume.Snapshot(None, [b0]) - fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1]) +from pypy.jit.metainterp.optimizeopt.util import args_dict +from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import FakeMetaInterpStaticData +from pypy.config.pypyoption import get_pypy_config + + +def test_build_opt_chain(): + def check(chain, expected_names): + names = [opt.__class__.__name__ for opt in chain] + assert names == expected_names # - opt.store_final_boxes_in_guard(op) - if op.getfailargs() == [b0, b1]: - assert list(fdescr.rd_numb.nums) == [tag(1, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)] - else: - assert op.getfailargs() == [b1, b0] - assert list(fdescr.rd_numb.nums) == [tag(0, TAGBOX)] - assert list(fdescr.rd_numb.prev.nums) == [tag(1, TAGBOX)] - assert fdescr.rd_virtuals is None - assert fdescr.rd_consts == [] - -def test_sharing_field_lists_of_virtual(): - class FakeOptimizer(object): - class cpu(object): - pass - opt = FakeOptimizer() - virt1 = virtualize.AbstractVirtualStructValue(opt, None) - lst1 = virt1._get_field_descr_list() - assert lst1 == [] - lst2 = virt1._get_field_descr_list() - assert lst1 is lst2 - virt1.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst3 = virt1._get_field_descr_list() - assert lst3 == [LLtypeMixin.valuedescr] - lst4 = virt1._get_field_descr_list() - assert lst3 is lst4 - - virt2 = virtualize.AbstractVirtualStructValue(opt, None) - lst5 = virt2._get_field_descr_list() - assert lst5 is lst1 - virt2.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None)) - lst6 = virt1._get_field_descr_list() - assert lst6 is lst3 - -def test_reuse_vinfo(): - class FakeVInfo(object): - def set_content(self, fieldnums): - self.fieldnums = fieldnums - def equals(self, fieldnums): - return self.fieldnums == fieldnums - class FakeVirtualValue(virtualize.AbstractVirtualValue): - def _make_virtual(self, *args): - return FakeVInfo() - v1 = FakeVirtualValue(None, None, None) - vinfo1 = v1.make_virtual_info(None, [1, 2, 4]) - vinfo2 = v1.make_virtual_info(None, [1, 2, 4]) - assert vinfo1 is vinfo2 - vinfo3 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is not vinfo2 - vinfo4 = v1.make_virtual_info(None, [1, 2, 6]) - assert vinfo3 is vinfo4 - -def test_descrlist_dict(): - from pypy.jit.metainterp import optimizeutil - h1 = optimizeutil.descrlist_hash([]) - h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr]) - h3 = optimizeutil.descrlist_hash( - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert h1 != h2 - assert h2 != h3 - assert optimizeutil.descrlist_eq([], []) - assert not optimizeutil.descrlist_eq([], [LLtypeMixin.valuedescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.valuedescr], - [LLtypeMixin.nextdescr]) - assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr, LLtypeMixin.nextdescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - assert not optimizeutil.descrlist_eq([LLtypeMixin.nextdescr, LLtypeMixin.valuedescr], - [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr]) - - # descrlist_eq should compare by identity of the descrs, not by the result - # of sort_key - class FakeDescr(object): - def sort_key(self): - return 1 - - assert not optimizeutil.descrlist_eq([FakeDescr()], [FakeDescr()]) + metainterp_sd = FakeMetaInterpStaticData(None) + chain, _ = build_opt_chain(metainterp_sd, "", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "heap:intbounds") + check(chain, ["OptInlineShortPreamble", "OptIntBounds", "OptHeap", "OptSimplify"]) + # + chain, unroll = build_opt_chain(metainterp_sd, "unroll") + check(chain, ["OptInlineShortPreamble", "OptSimplify"]) + assert unroll + # + chain, _ = build_opt_chain(metainterp_sd, "aaa:bbb", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptFfiCall", "OptSimplify"]) + # + metainterp_sd.config = get_pypy_config(translating=True) + assert not metainterp_sd.config.translation.jit_ffi + chain, _ = build_opt_chain(metainterp_sd, "ffi", inline_short_preamble=False) + check(chain, ["OptSimplify"]) + # ____________________________________________________________ -class Storage(compile.ResumeGuardDescr): - "for tests." - def __init__(self, metainterp_sd=None, original_greenkey=None): - self.metainterp_sd = metainterp_sd - self.original_greenkey = original_greenkey - def store_final_boxes(self, op, boxes): - op.setfailargs(boxes) - def __eq__(self, other): - return type(self) is type(other) # xxx obscure + + +class FakeDescr(compile.ResumeGuardDescr): + class rd_snapshot: + class prev: + prev = None + boxes = [] + boxes = [] def clone_if_mutable(self): - res = Storage(self.metainterp_sd, self.original_greenkey) - self.copy_all_attributes_into(res) - return res - -def _sortboxes(boxes): - _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} - return sorted(boxes, key=lambda box: _kind2count[box.type]) - -class BaseTestOptimizeOpt(BaseTest): - jit_ffi = False - - def invent_fail_descr(self, fail_args): - if fail_args is None: - return None - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) - descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) - return descr - - def assert_equal(self, optimized, expected, text_right=None): - assert len(optimized.inputargs) == len(expected.inputargs) - remap = {} - for box1, box2 in zip(optimized.inputargs, expected.inputargs): - assert box1.__class__ == box2.__class__ - remap[box2] = box1 - assert equaloplists(optimized.operations, - expected.operations, False, remap, text_right) - - def optimize_loop(self, ops, optops, expected_preamble=None, + return self + + +class BaseTestWithUnroll(BaseTest): + + enable_opts = "intbounds:rewrite:virtualize:string:heap:unroll" + + def optimize_loop(self, ops, expected, expected_preamble=None, call_pure_results=None): loop = self.parse(ops) - if optops != "crash!": - expected = self.parse(optops) - else: - expected = "crash!" + if expected != "crash!": + expected = self.parse(expected) if expected_preamble: expected_preamble = self.parse(expected_preamble) - # - self.loop = loop - loop.call_pure_results = args_dict() - if call_pure_results is not None: - for k, v in call_pure_results.items(): - loop.call_pure_results[list(k)] = v + loop.preamble = TreeLoop('preamble') loop.preamble.inputargs = loop.inputargs loop.preamble.token = LoopToken() - metainterp_sd = FakeMetaInterpStaticData(self.cpu, self.jit_ffi) - if hasattr(self, 'vrefinfo'): - metainterp_sd.virtualref_info = self.vrefinfo - if hasattr(self, 'callinfocollection'): - metainterp_sd.callinfocollection = self.callinfocollection - class FakeDescr(compile.ResumeGuardDescr): - class rd_snapshot: - class prev: - prev = None - boxes = [] - boxes = [] - def clone_if_mutable(self): - return self loop.preamble.start_resumedescr = FakeDescr() - optimize_loop_1(metainterp_sd, loop, ALL_OPTS_DICT) # - + self._do_optimize_loop(loop, call_pure_results) + # print print loop.preamble.inputargs print '\n'.join([str(o) for o in loop.preamble.operations]) @@ -204,16 +90,14 @@ print loop.inputargs print '\n'.join([str(o) for o in loop.operations]) print - assert expected != "crash!", "should have raised an exception" self.assert_equal(loop, expected) if expected_preamble: self.assert_equal(loop.preamble, expected_preamble, text_right='expected preamble') - return loop -class OptimizeOptTest(BaseTestOptimizeOpt): +class OptimizeOptTest(BaseTestWithUnroll): def setup_method(self, meth=None): class FailDescr(compile.ResumeGuardDescr): @@ -1497,8 +1381,8 @@ """ expected = """ [i1, p0] + p1 = new_array(i1, descr=arraydescr) setarrayitem_gc(p0, 0, i1, descr=arraydescr) - p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ self.optimize_loop(ops, expected) @@ -1922,9 +1806,9 @@ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr) i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -1934,9 +1818,9 @@ # i4 = getarrayitem_gc(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) - setarrayitem_gc(p3, 0, i5, descr=arraydescr) # setfield_gc(p1, i2, descr=valuedescr) + setarrayitem_gc(p3, 0, i5, descr=arraydescr) setfield_gc(p1, i4, descr=nextdescr) escape() jump(p1, i1, i2, p3, i3) @@ -2171,6 +2055,7 @@ self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_after_setarrayitem_2(self): + py.test.skip("setarrayitem with variable index") ops = """ [p1, p2, p3, i1] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) @@ -2857,8 +2742,6 @@ # ---------- -class TestLLtype(OptimizeOptTest, LLtypeMixin): - def test_residual_call_does_not_invalidate_caches(self): ops = """ [p1, p2] @@ -5199,11 +5082,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5224,9 +5104,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5245,10 +5123,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5270,14 +5147,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -5293,10 +5165,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5420,14 +5290,12 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) - def test_strgetitem_small(self): + def test_strgetitem_bounds(self): ops = """ [p0, i0] i1 = strgetitem(p0, i0) @@ -5439,7 +5307,20 @@ """ expected = """ [p0, i0] - i1 = strgetitem(p0, i0) + jump(p0, i0) + """ + self.optimize_loop(ops, expected) + + def test_unicodegetitem_bounds(self): + ops = """ + [p0, i0] + i1 = unicodegetitem(p0, i0) + i2 = int_lt(i1, 0) + guard_false(i2) [] + jump(p0, i0) + """ + expected = """ + [p0, i0] jump(p0, i0) """ self.optimize_loop(ops, expected) @@ -5477,7 +5358,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -5516,11 +5396,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5714,11 +5591,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -5953,3 +5827,54 @@ jump(i3, i4) """ self.optimize_loop(ops, expected) + + def test_forced_virtual_pure_getfield(self): + ops = """ + [p0] + p1 = getfield_gc_pure(p0, descr=valuedescr) + jump(p1) + """ + self.optimize_loop(ops, ops) + + ops = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + p2 = getfield_gc_pure(p1, descr=valuedescr) + escape(p2) + jump(p0) + """ + expected = """ + [p0] + p1 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p0, descr=valuedescr) + escape(p1) + escape(p0) + jump(p0) + """ + self.optimize_loop(ops, expected) + + def test_setarrayitem_lazy(self): + ops = """ + [i0, i1] + p0 = escape() + i2 = escape() + p1 = new_with_vtable(ConstClass(node_vtable)) + setarrayitem_gc(p0, 2, p1, descr=arraydescr) + guard_true(i2) [] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + expected = """ + [i0, i1] + p0 = escape() + i2 = escape() + guard_true(i2) [p0] + setarrayitem_gc(p0, 2, p0, descr=arraydescr) + jump(i0, i1) + """ + self.optimize_loop(ops, expected) + +class TestLLtype(OptimizeOptTest, LLtypeMixin): + pass diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py rename from pypy/jit/metainterp/test/test_optimizeutil.py rename to pypy/jit/metainterp/optimizeopt/test/test_util.py --- a/pypy/jit/metainterp/test/test_optimizeutil.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py @@ -9,11 +9,15 @@ from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, Const, TreeLoop, BoxObj, ConstObj, AbstractDescr) -from pypy.jit.metainterp.optimizeutil import sort_descrs, InvalidLoop +from pypy.jit.metainterp.optimizeopt.util import sort_descrs, equaloplists +from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter.heaptracker import register_known_gctype, adr2int -from pypy.jit.tool.oparser import parse +from pypy.jit.tool.oparser import parse, pure_parse from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr +from pypy.jit.metainterp import compile, resume, history +from pypy.jit.metainterp.jitprof import EmptyProfiler +from pypy.config.pypyoption import get_pypy_config def test_sort_descrs(): class PseudoDescr(AbstractDescr): @@ -28,6 +32,44 @@ sort_descrs(lst2) assert lst2 == lst +def test_equaloplists(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops, namespace=namespace) + loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), + namespace=namespace) + assert equaloplists(loop1.operations, loop2.operations) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + +def test_equaloplists_fail_args(): + ops = """ + [i0] + i1 = int_add(i0, 1) + i2 = int_add(i1, 1) + guard_true(i1) [i2, i1] + jump(i1) + """ + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop2.operations)") + assert equaloplists(loop1.operations, loop2.operations, + strict_fail_args=False) + loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), + namespace=namespace) + py.test.raises(AssertionError, + "equaloplists(loop1.operations, loop3.operations)") + # ____________________________________________________________ class LLtypeMixin(object): @@ -124,19 +166,19 @@ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [])) + EffectInfo([], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [])) + EffectInfo([], [], [adescr], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [adescr], [arraydescr])) + EffectInfo([], [], [adescr], [arraydescr])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([adescr], [], [])) + EffectInfo([adescr], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([nextdescr], [], [], + EffectInfo([nextdescr], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY)) for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), @@ -153,15 +195,15 @@ _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=_oopspecindex)) + EffectInfo([], [], [], [], oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, - EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) + EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): @@ -256,8 +298,45 @@ ## u_vtable_adr: cpu.typedescrof(U)} ## namespace = locals() +# ____________________________________________________________ + + + +class Fake(object): + failargs_limit = 1000 + storedebug = None + + +class FakeMetaInterpStaticData(object): + + def __init__(self, cpu): + self.cpu = cpu + self.profiler = EmptyProfiler() + self.options = Fake() + self.globaldata = Fake() + self.config = get_pypy_config(translating=True) + self.config.translation.jit_ffi = True + + +class Storage(compile.ResumeGuardDescr): + "for tests." + def __init__(self, metainterp_sd=None, original_greenkey=None): + self.metainterp_sd = metainterp_sd + self.original_greenkey = original_greenkey + def store_final_boxes(self, op, boxes): + op.setfailargs(boxes) + def __eq__(self, other): + return type(self) is type(other) # xxx obscure + def clone_if_mutable(self): + res = Storage(self.metainterp_sd, self.original_greenkey) + self.copy_all_attributes_into(res) + return res + +def _sortboxes(boxes): + _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3} + return sorted(boxes, key=lambda box: _kind2count[box.type]) + class BaseTest(object): - invent_fail_descr = None def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, @@ -265,5 +344,40 @@ boxkinds=boxkinds, invent_fail_descr=self.invent_fail_descr) + def invent_fail_descr(self, model, fail_args): + if fail_args is None: + return None + descr = Storage() + descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11) + descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args)) + return descr + + def assert_equal(self, optimized, expected, text_right=None): + from pypy.jit.metainterp.optimizeopt.util import equaloplists + assert len(optimized.inputargs) == len(expected.inputargs) + remap = {} + for box1, box2 in zip(optimized.inputargs, expected.inputargs): + assert box1.__class__ == box2.__class__ + remap[box2] = box1 + assert equaloplists(optimized.operations, + expected.operations, False, remap, text_right) + + def _do_optimize_loop(self, loop, call_pure_results): + from pypy.jit.metainterp.optimizeopt import optimize_loop_1 + from pypy.jit.metainterp.optimizeopt.util import args_dict + + self.loop = loop + loop.call_pure_results = args_dict() + if call_pure_results is not None: + for k, v in call_pure_results.items(): + loop.call_pure_results[list(k)] = v + metainterp_sd = FakeMetaInterpStaticData(self.cpu) + if hasattr(self, 'vrefinfo'): + metainterp_sd.virtualref_info = self.vrefinfo + if hasattr(self, 'callinfocollection'): + metainterp_sd.callinfocollection = self.callinfocollection + # + optimize_loop_1(metainterp_sd, loop, self.enable_opts) + # ____________________________________________________________ diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -5,7 +5,7 @@ from pypy.jit.metainterp.resume import Snapshot from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop, RetraceLoop +from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.history import make_hashable_int from pypy.jit.codewriter.effectinfo import EffectInfo @@ -546,7 +546,7 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False @@ -676,24 +676,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - self.debug_merge_point(jitdriver_sd, self.metainterp.in_recursion, + self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) if self.metainterp.seen_loop_header_for_jdindex < 0: @@ -914,13 +919,12 @@ assembler_call=True) raise ChangeFrame - def debug_merge_point(self, jitdriver_sd, in_recursion, greenkey): + def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey): # debugging: produce a DEBUG_MERGE_POINT operation loc = jitdriver_sd.warmstate.get_location_str(greenkey) debug_print(loc) - constloc = self.metainterp.cpu.ts.conststr(loc) - self.metainterp.history.record(rop.DEBUG_MERGE_POINT, - [constloc, ConstInt(in_recursion)], None) + args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey + self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None) @arguments("box", "label") def opimpl_goto_if_exception_mismatch(self, vtablebox, next_exc_target): @@ -1234,7 +1238,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: @@ -1265,8 +1269,7 @@ logger_ops = None def __init__(self, cpu, options, - ProfilerClass=EmptyProfiler, warmrunnerdesc=None, - jit_ffi=True): + ProfilerClass=EmptyProfiler, warmrunnerdesc=None): self.cpu = cpu self.stats = self.cpu.stats self.options = options @@ -1276,7 +1279,11 @@ self.profiler = ProfilerClass() self.profiler.cpu = cpu self.warmrunnerdesc = warmrunnerdesc - self.jit_ffi = jit_ffi + if warmrunnerdesc: + self.config = warmrunnerdesc.translator.config + else: + from pypy.config.pypyoption import get_pypy_config + self.config = get_pypy_config(translating=True) backendmodule = self.cpu.__module__ backendmodule = backendmodule.split('.')[-2] @@ -1447,6 +1454,8 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1787,6 +1796,8 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) @@ -1927,7 +1938,6 @@ self.history.inputargs = original_inputargs self.history.operations.pop() # remove the JUMP - # FIXME: Why is self.history.inputargs not restored? def compile_bridge(self, live_arg_boxes): num_green_args = self.jitdriver_sd.num_green_args @@ -1963,6 +1973,8 @@ start_resumedescr, False) self.history.operations.pop() # remove the JUMP if loop_token is None: + self.history.inputargs = original_inputargs + self.history.operations = original_operations return if loop_token.short_preamble: @@ -2117,7 +2129,6 @@ def vrefs_after_residual_call(self): vrefinfo = self.staticdata.virtualref_info for i in range(0, len(self.virtualref_boxes), 2): - virtualbox = self.virtualref_boxes[i] vrefbox = self.virtualref_boxes[i+1] vref = vrefbox.getref_base() if vrefinfo.tracing_after_residual_call(vref): diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -191,9 +191,15 @@ # of the operation. It must inherit from AbstractDescr. The # backend provides it with cpu.fielddescrof(), cpu.arraydescrof(), # cpu.calldescrof(), and cpu.typedescrof(). + self._check_descr(descr) + self._descr = descr + + def _check_descr(self, descr): + if not we_are_translated() and getattr(descr, 'I_am_a_descr', False): + return # needed for the mock case in oparser_model from pypy.jit.metainterp.history import check_descr check_descr(descr) - self._descr = descr + class GuardResOp(ResOpWithDescr): @@ -275,9 +281,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 @@ -471,8 +474,9 @@ 'STRSETITEM/3', 'UNICODESETITEM/3', #'RUNTIMENEW/1', # ootype operation - 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier) - 'DEBUG_MERGE_POINT/2', # debugging only + 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier) + 'COND_CALL_GC_WB_ARRAY/3d', # [objptr, arrayindex, newvalue] (write barr.) + 'DEBUG_MERGE_POINT/*', # debugging only 'JIT_DEBUG/*', # debugging only 'VIRTUAL_REF_FINISH/2', # removed before it's passed to the backend 'COPYSTRCONTENT/5', # src, dst, srcstart, dststart, length @@ -485,6 +489,7 @@ 'CALL_ASSEMBLER/*d', # call already compiled assembler 'CALL_MAY_FORCE/*d', 'CALL_LOOPINVARIANT/*d', + 'CALL_RELEASE_GIL/*d', # release the GIL and "close the stack" for asmgcc #'OOSEND', # ootype operation #'OOSEND_PURE', # ootype operation 'CALL_PURE/*d', # removed before it's passed to the backend diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -2,15 +2,17 @@ from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr +from pypy.rpython import annlowlevel from pypy.rlib import rarithmetic, rstack from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib.debug import have_debug_prints, ll_assert from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimizeutil import InvalidLoop +from pypy.jit.metainterp.optimize import InvalidLoop # Logic to encode the chain of frames and the state of the boxes at a # guard operation, and to decode it again. This is a bit advanced, @@ -82,6 +84,13 @@ ('nums', lltype.Array(rffi.SHORT))) NUMBERINGP.TO.become(NUMBERING) +PENDINGFIELDSTRUCT = lltype.Struct('PendingField', + ('lldescr', annlowlevel.base_ptr_lltype()), + ('num', rffi.SHORT), + ('fieldnum', rffi.SHORT), + ('itemindex', rffi.INT)) +PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) + TAGMASK = 3 def tag(value, tagbits): @@ -329,7 +338,7 @@ value = values[box] value.get_args_for_fail(self) - for _, box, fieldbox in pending_setfields: + for _, box, fieldbox, _ in pending_setfields: self.register_box(box) self.register_box(fieldbox) value = values[fieldbox] @@ -405,13 +414,25 @@ return False def _add_pending_fields(self, pending_setfields): - rd_pendingfields = None + rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) if pending_setfields: - rd_pendingfields = [] - for descr, box, fieldbox in pending_setfields: + n = len(pending_setfields) + rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) + for i in range(n): + descr, box, fieldbox, itemindex = pending_setfields[i] + lldescr = annlowlevel.cast_instance_to_base_ptr(descr) num = self._gettagged(box) fieldnum = self._gettagged(fieldbox) - rd_pendingfields.append((descr, num, fieldnum)) + # the index is limited to 2147483647 (64-bit machines only) + if itemindex > 2147483647: + from pypy.jit.metainterp import compile + compile.giveup() + itemindex = rffi.cast(rffi.INT, itemindex) + # + rd_pendingfields[i].lldescr = lldescr + rd_pendingfields[i].num = num + rd_pendingfields[i].fieldnum = fieldnum + rd_pendingfields[i].itemindex= itemindex self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): @@ -727,10 +748,28 @@ self.virtuals_cache = [self.virtual_default] * len(virtuals) def _prepare_pendingfields(self, pendingfields): - if pendingfields is not None: - for descr, num, fieldnum in pendingfields: + if pendingfields: + for i in range(len(pendingfields)): + lldescr = pendingfields[i].lldescr + num = pendingfields[i].num + fieldnum = pendingfields[i].fieldnum + itemindex= pendingfields[i].itemindex + descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, + lldescr) struct = self.decode_ref(num) - self.setfield(descr, struct, fieldnum) + itemindex = rffi.cast(lltype.Signed, itemindex) + if itemindex < 0: + self.setfield(descr, struct, fieldnum) + else: + self.setarrayitem(descr, struct, itemindex, fieldnum) + + def setarrayitem(self, arraydescr, array, index, fieldnum): + if arraydescr.is_array_of_pointers(): + self.setarrayitem_ref(arraydescr, array, index, fieldnum) + elif arraydescr.is_array_of_floats(): + self.setarrayitem_float(arraydescr, array, index, fieldnum) + else: + self.setarrayitem_int(arraydescr, array, index, fieldnum) def _prepare_next_section(self, info): # Use info.enumerate_vars(), normally dispatching to @@ -903,15 +942,15 @@ structbox, fieldbox) def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, INT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT) def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, REF) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF) def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum): - self.setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) + self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT) - def setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): + def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind): itembox = self.decode_box(fieldnum, kind) self.metainterp.execute_and_record(rop.SETARRAYITEM_GC, arraydescr, arraybox, diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -15,14 +15,14 @@ supports_longlong=False, **kwds): from pypy.jit.codewriter import support - class FakeJitCell: + class FakeJitCell(object): __compiled_merge_points = [] def get_compiled_merge_points(self): return self.__compiled_merge_points[:] def set_compiled_merge_points(self, lst): self.__compiled_merge_points = lst - class FakeWarmRunnerState: + class FakeWarmRunnerState(object): def attach_unoptimized_bridge_from_interp(self, greenkey, newloop): pass @@ -30,6 +30,9 @@ from pypy.rpython.annlowlevel import llhelper return llhelper(FUNCPTR, func) + def get_location_str(self, args): + return 'location' + def jit_cell_at_key(self, greenkey): assert greenkey == [] return self._cell diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -500,7 +500,7 @@ y -= x return y # - res = self.meta_interp(f, [3, 6], repeat=7) + res = self.meta_interp(f, [3, 6], repeat=7, function_threshold=0) assert res == 6 - 4 - 5 self.check_history(call=0) # because the trace starts in the middle # @@ -984,11 +984,14 @@ pass class B(A): pass + @dont_look_inside + def extern(n): + if n: + return A() + else: + return B() def fn(n): - if n: - obj = A() - else: - obj = B() + obj = extern(n) return isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res @@ -1021,6 +1024,70 @@ res = self.meta_interp(main, []) assert res == 55 + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass @@ -1252,7 +1319,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1379,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1410,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1444,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1563,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1598,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1595,9 +1662,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1676,7 +1743,9 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) + py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) def test_multiple_specialied_versions_bridge(self): @@ -1815,7 +1884,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -2000,7 +2069,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2045,7 +2114,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 @@ -2080,7 +2149,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2137,7 +2206,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2206,7 +2275,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2230,6 +2300,148 @@ self.check_loops(getfield_gc_pure=0) self.check_loops(getfield_gc_pure=2, everywhere=True) + def test_frame_finished_during_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 1 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 1000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'a']) + def f(): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 2) + a = A(0) + sa = 0 + while a.val < 8: + myjitdriver.jit_merge_point(a=a, sa=sa) + a = a.inc() + if a.val > 4: + a = B(a.val) + sa += a.num + return sa + res = self.meta_interp(f, []) + assert res == f() + + def test_frame_finished_during_continued_retrace(self): + class Base(object): + pass + class A(Base): + def __init__(self, a): + self.val = a + self.num = 100 + def inc(self): + return A(self.val + 1) + class B(Base): + def __init__(self, a): + self.val = a + self.num = 10000 + def inc(self): + return B(self.val + 1) + myjitdriver = JitDriver(greens = [], reds = ['sa', 'b', 'a']) + def f(b): + myjitdriver.set_param('threshold', 6) + myjitdriver.set_param('trace_eagerness', 4) + a = A(0) + sa = 0 + while a.val < 15: + myjitdriver.jit_merge_point(a=a, b=b, sa=sa) + a = a.inc() + if a.val > 8: + a = B(a.val) + if b == 1: + b = 2 + else: + b = 1 + sa += a.num + b + return sa + res = self.meta_interp(f, [1]) + assert res == f(1) + + def test_remove_array_operations(self): + myjitdriver = JitDriver(greens = [], reds = ['a']) + class W_Int: + def __init__(self, intvalue): + self.intvalue = intvalue + def f(x): + a = [W_Int(x)] + while a[0].intvalue > 0: + myjitdriver.jit_merge_point(a=a) + a[0] = W_Int(a[0].intvalue - 3) + return a[0].intvalue + res = self.meta_interp(f, [100]) + assert res == -2 + #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + + def test_retrace_ending_up_retrazing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py --- a/pypy/jit/metainterp/test/test_compile.py +++ b/pypy/jit/metainterp/test/test_compile.py @@ -1,3 +1,4 @@ +from pypy.config.pypyoption import get_pypy_config from pypy.jit.metainterp.history import LoopToken, ConstInt, History, Stats from pypy.jit.metainterp.history import BoxInt, INT from pypy.jit.metainterp.compile import insert_loop_token, compile_new_loop @@ -5,7 +6,7 @@ from pypy.jit.metainterp.compile import ResumeGuardCountersInt from pypy.jit.metainterp.compile import compile_tmp_callback from pypy.jit.metainterp import jitprof, typesystem, compile -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.tool.oparser import parse from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT @@ -30,13 +31,16 @@ ts = typesystem.llhelper def __init__(self): self.seen = [] - def compile_loop(self, inputargs, operations, token): + def compile_loop(self, inputargs, operations, token, name=''): self.seen.append((inputargs, operations, token)) class FakeLogger(object): def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): pass + def repr_of_resop(self, op): + return repr(op) + class FakeState(object): enable_opts = ALL_OPTS_DICT.copy() enable_opts.pop('unroll') @@ -44,6 +48,9 @@ def attach_unoptimized_bridge_from_interp(*args): pass + def get_location_str(self, args): + return 'location' + class FakeGlobalData(object): loopnumbering = 0 @@ -51,11 +58,11 @@ logger_noopt = FakeLogger() logger_ops = FakeLogger() + config = get_pypy_config(translating=True) stats = Stats() profiler = jitprof.EmptyProfiler() warmrunnerdesc = None - jit_ffi = False def log(self, msg, event_kind=None): pass @@ -63,6 +70,8 @@ call_pure_results = {} class jitdriver_sd: warmstate = FakeState() + on_compile = staticmethod(lambda *args: None) + on_compile_bridge = staticmethod(lambda *args: None) def test_compile_new_loop(): cpu = FakeCPU() diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -130,6 +130,38 @@ assert res == 50 self.check_loops(int_mod=1) + def test_repeated_lookup(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'd']) + class Wrapper(object): + _immutable_fields_ = ["value"] + def __init__(self, value): + self.value = value + def eq_func(a, b): + return a.value == b.value + def hash_func(x): + return objectmodel.compute_hash(x.value) + + def f(n): + d = None + while n > 0: + myjitdriver.jit_merge_point(n=n, d=d) + d = objectmodel.r_dict(eq_func, hash_func) + y = Wrapper(str(n)) + d[y] = n - 1 + n = d[y] + return d[Wrapper(str(n + 1))] + + res = self.meta_interp(f, [100], listops=True) + assert res == f(50) + # XXX: ideally there would be 7 calls here, but repeated CALL_PURE with + # the same arguments are not folded, because we have conflicting + # definitions of pure, once strhash can be appropriately folded + # this should be decreased to seven. + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + "guard_true": 1, "int_and": 1, "int_gt": 1, + "int_is_true": 1, "int_sub": 1, "jump": 1, + "new_with_vtable": 1, "setfield_gc": 1}) + class TestOOtype(DictTests, OOJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,28 +1,46 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.libffi import ArgChain +from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong +from pypy.rlib.libffi import IS_32_BIT from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall from pypy.rpython.lltypesystem import lltype, rffi +from pypy.rlib.objectmodel import specialize +from pypy.tool.sourcetools import func_with_new_name from pypy.jit.metainterp.test.support import LLJitMixin - class TestFfiCall(LLJitMixin, _TestLibffiCall): # ===> ../../../rlib/test/test_libffi.py - def call(self, funcspec, args, RESULT, init_result=0): + def call(self, funcspec, args, RESULT, init_result=0, is_struct=False): """ Call the function specified by funcspec in a loop, and let the jit to see and optimize it. """ # lib, name, argtypes, restype = funcspec - args = unrolling_iterable(args) + method_and_args = [] + for argval in args: + if type(argval) is r_singlefloat: + method_name = 'arg_singlefloat' + argval = float(argval) + elif IS_32_BIT and type(argval) in [r_longlong, r_ulonglong]: + method_name = 'arg_longlong' + argval = rffi.cast(rffi.LONGLONG, argval) + argval = longlong2float(argval) + elif isinstance(argval, tuple): + method_name, argval = argval + else: + method_name = 'arg' + method_and_args.append((method_name, argval)) + method_and_args = unrolling_iterable(method_and_args) # reds = ['n', 'res', 'func'] - if type(init_result) is float: + if (RESULT in [rffi.FLOAT, rffi.DOUBLE] or + IS_32_BIT and RESULT in [rffi.LONGLONG, rffi.ULONGLONG]): reds = ['n', 'func', 'res'] # floats must be *after* refs driver = JitDriver(reds=reds, greens=[]) # @@ -31,15 +49,19 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() - for argval in args: # this loop is unrolled - argchain.arg(argval) - res = func.call(argchain, RESULT) + # this loop is unrolled + for method_name, argval in method_and_args: + getattr(argchain, method_name)(argval) + res = func.call(argchain, RESULT, is_struct=is_struct) n += 1 return res # - res = self.meta_interp(f, [0]) + res = self.meta_interp(f, [0], backendopt=True) return res + def test_byval_result(self): + _TestLibffiCall.test_byval_result(self) + test_byval_result.__doc__ = _TestLibffiCall.test_byval_result.__doc__ + test_byval_result.dont_track_allocations = True diff --git a/pypy/jit/metainterp/test/test_history.py b/pypy/jit/metainterp/test/test_history.py --- a/pypy/jit/metainterp/test/test_history.py +++ b/pypy/jit/metainterp/test/test_history.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.history import * -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi def test_repr(): @@ -10,6 +10,18 @@ const = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)) assert const._getrepr_() == "*T" +def test_repr_ll2ctypes(): + ptr = lltype.malloc(rffi.VOIDPP.TO, 10, flavor='raw') + # force it to be a ll2ctypes object + ptr = rffi.cast(rffi.VOIDPP, rffi.cast(rffi.LONG, ptr)) + adr = llmemory.cast_ptr_to_adr(ptr) + lltype.free(ptr, flavor='raw') + intval = llmemory.cast_adr_to_int(adr, 'symbolic') + box = BoxInt(intval) + s = box.repr_rpython() + assert s.startswith('12345/') # the arbitrary hash value used by + # make_hashable_int + def test_same_constant(): c1a = ConstInt(0) c1b = ConstInt(0) diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py --- a/pypy/jit/metainterp/test/test_jitdriver.py +++ b/pypy/jit/metainterp/test/test_jitdriver.py @@ -113,6 +113,7 @@ return n # def loop2(g, r): + myjitdriver1.set_param('function_threshold', 0) while r > 0: myjitdriver2.can_enter_jit(g=g, r=r) myjitdriver2.jit_merge_point(g=g, r=r) diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py --- a/pypy/jit/metainterp/test/test_list.py +++ b/pypy/jit/metainterp/test/test_list.py @@ -49,7 +49,7 @@ x = l[n] l = [3] * 100 l[3] = x - l[3] = x + 1 + l[4] = x + 1 n -= 1 return l[0] diff --git a/pypy/jit/metainterp/test/test_logger.py b/pypy/jit/metainterp/test/test_logger.py --- a/pypy/jit/metainterp/test/test_logger.py +++ b/pypy/jit/metainterp/test/test_logger.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp import logger from pypy.jit.metainterp.typesystem import llhelper from StringIO import StringIO -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.metainterp.history import AbstractDescr, LoopToken, BasicFailDescr from pypy.jit.backend.model import AbstractCPU @@ -36,19 +36,29 @@ return capturing(logger.Logger.log_loop, self, loop.inputargs, loop.operations, ops_offset=ops_offset) - def repr_of_descr(self, descr): - for k, v in self.namespace.items(): - if v == descr: - return k - return descr.repr_of_descr() + def _make_log_operations(self1): + class LogOperations(logger.LogOperations): + def repr_of_descr(self, descr): + for k, v in self1.namespace.items(): + if v == descr: + return k + return descr.repr_of_descr() + logops = LogOperations(self1.metainterp_sd, self1.guard_number) + self1.logops = logops + return logops class TestLogger(object): ts = llhelper def make_metainterp_sd(self): + class FakeJitDriver(object): + class warmstate(object): + get_location_str = staticmethod(lambda args: "dupa") + class FakeMetaInterpSd: cpu = AbstractCPU() cpu.ts = self.ts + jitdrivers_sd = [FakeJitDriver()] def get_name_from_address(self, addr): return 'Name' return FakeMetaInterpSd() @@ -66,7 +76,7 @@ if check_equal: equaloplists(loop.operations, oloop.operations) assert oloop.inputargs == loop.inputargs - return loop, oloop + return logger, loop, oloop def test_simple(self): inp = ''' @@ -106,18 +116,18 @@ def test_debug_merge_point(self): inp = ''' [] - debug_merge_point("info", 0) + debug_merge_point(0, 0) ''' - loop, oloop = self.reparse(inp, check_equal=False) - assert loop.operations[0].getarg(0)._get_str() == 'info' - assert oloop.operations[0].getarg(0)._get_str() == 'info' + _, loop, oloop = self.reparse(inp, check_equal=False) + assert loop.operations[0].getarg(1).getint() == 0 + assert oloop.operations[0].getarg(1)._get_str() == "dupa" def test_floats(self): inp = ''' [f0] f1 = float_add(3.5, f0) ''' - loop, oloop = self.reparse(inp) + _, loop, oloop = self.reparse(inp) equaloplists(loop.operations, oloop.operations) def test_jump(self): @@ -179,6 +189,17 @@ assert output.splitlines()[0] == "# bridge out of Guard 3 with 0 ops" pure_parse(output) + def test_repr_single_op(self): + inp = ''' + [i0, i1, i2, p3, p4, p5] + i6 = int_add(i1, i2) + i8 = int_add(i6, 3) + jump(i0, i8, i6, p3, p4, p5) + ''' + logger, loop, _ = self.reparse(inp) + op = loop.operations[1] + assert logger.logops.repr_of_resop(op) == "i8 = int_add(i6, 3)" + def test_ops_offset(self): inp = ''' [i0] diff --git a/pypy/jit/metainterp/test/test_pyjitpl.py b/pypy/jit/metainterp/test/test_pyjitpl.py --- a/pypy/jit/metainterp/test/test_pyjitpl.py +++ b/pypy/jit/metainterp/test/test_pyjitpl.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.history import BoxInt, ConstInt from pypy.jit.metainterp.history import History from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.optimizeopt.util import equaloplists from pypy.jit.codewriter.jitcode import JitCode diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -483,6 +483,7 @@ def main(inline): myjitdriver.set_param("threshold", 10) + myjitdriver.set_param('function_threshold', 60) if inline: myjitdriver.set_param('inlining', True) else: @@ -925,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 @@ -1193,6 +1194,51 @@ i -= 1 self.meta_interp(portal, [0, 10], inline=True) + def test_trace_from_start_always(self): + from pypy.rlib.nonconst import NonConstant + + driver = JitDriver(greens = ['c'], reds = ['i', 'v']) + + def portal(c, i, v): + while i > 0: + driver.jit_merge_point(c=c, i=i, v=v) + portal(c, i - 1, v) + if v: + driver.can_enter_jit(c=c, i=i, v=v) + break + + def main(c, i, set_param, v): + if set_param: + driver.set_param('function_threshold', 0) + portal(c, i, v) + + self.meta_interp(main, [10, 10, False, False], inline=True) + self.check_tree_loop_count(1) + self.check_loop_count(0) + self.meta_interp(main, [3, 10, True, False], inline=True) + self.check_tree_loop_count(0) + self.check_loop_count(0) + + def test_trace_from_start_does_not_prevent_inlining(self): + driver = JitDriver(greens = ['c', 'bc'], reds = ['i']) + + def portal(bc, c, i): + while True: + driver.jit_merge_point(c=c, bc=bc, i=i) + if bc == 0: + portal(1, 8, 0) + c += 1 + else: + return + if c == 10: # bc == 0 + c = 0 + if i >= 100: + return + driver.can_enter_jit(c=c, bc=bc, i=i) + i += 1 + + self.meta_interp(portal, [0, 0, 0], inline=True) + self.check_loops(call=0, call_may_force=0) class TestLLtype(RecursiveTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py --- a/pypy/jit/metainterp/test/test_resume.py +++ b/pypy/jit/metainterp/test/test_resume.py @@ -6,7 +6,7 @@ from pypy.jit.metainterp.resume import * from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt from pypy.jit.metainterp.history import ConstPtr, ConstFloat -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from pypy.jit.metainterp import executor from pypy.jit.codewriter import heaptracker, longlong @@ -1238,7 +1238,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, values, 0) assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)]) + modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s, -1)]) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume @@ -1259,6 +1259,106 @@ assert len(expected) == len(trace) assert demo55.next == demo66 +def test_virtual_adder_pending_fields_and_arrayitems(): + class Storage(object): + pass + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier._add_pending_fields([]) + assert not storage.rd_pendingfields + # + class FieldDescr(object): + pass + field_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061)} + modifier._add_pending_fields([(field_a, 42, 61, -1)]) + pf = storage.rd_pendingfields + assert len(pf) == 1 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is field_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + # + array_a = FieldDescr() + storage = Storage() + modifier = ResumeDataVirtualAdder(storage, None) + modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042), + 61: rffi.cast(rffi.SHORT, 1061), + 62: rffi.cast(rffi.SHORT, 1062), + 63: rffi.cast(rffi.SHORT, 1063)} + modifier._add_pending_fields([(array_a, 42, 61, 0), + (array_a, 42, 62, 2147483647)]) + pf = storage.rd_pendingfields + assert len(pf) == 2 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[0].num) == 1042 + assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 + assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 + assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) + is array_a) + assert rffi.cast(lltype.Signed, pf[1].num) == 1042 + assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 + assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + # + from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole + py.test.raises(SwitchToBlackhole, modifier._add_pending_fields, + [(array_a, 42, 63, 2147483648)]) + +def test_resume_reader_fields_and_arrayitems(): + class ResumeReader(AbstractResumeDataReader): + def __init__(self, got=None, got_array=None): + self.got = got + self.got_array = got_array + def setfield(self, descr, struct, fieldnum): + assert lltype.typeOf(struct) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got.append((descr, struct, fieldnum)) + def setarrayitem(self, arraydescr, array, index, fieldnum): + assert lltype.typeOf(array) is lltype.Signed + assert lltype.typeOf(index) is lltype.Signed + assert lltype.typeOf(fieldnum) is rffi.SHORT + fieldnum = rffi.cast(lltype.Signed, fieldnum) + self.got_array.append((arraydescr, array, index, fieldnum)) + def decode_ref(self, num): + return rffi.cast(lltype.Signed, num) * 100 + got = [] + pf = lltype.nullptr(PENDINGFIELDSP.TO) + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [] + # + class FieldDescr(AbstractDescr): + pass + field_a = FieldDescr() + field_b = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 2) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) + pf[0].itemindex = rffi.cast(rffi.INT, -1) + pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) + pf[1].num = rffi.cast(rffi.SHORT, 2042) + pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) + pf[1].itemindex = rffi.cast(rffi.INT, -1) + got = [] + ResumeReader(got)._prepare_pendingfields(pf) + assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] + # + array_a = FieldDescr() + pf = lltype.malloc(PENDINGFIELDSP.TO, 1) + pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) + pf[0].num = rffi.cast(rffi.SHORT, 1042) + pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) + pf[0].itemindex = rffi.cast(rffi.INT, 123) + got_array = [] + ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + assert got_array == [(array_a, 104200, 123, 1063)] + def test_invalidation_needed(): class options: diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,13 +5,13 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor from pypy.jit.metainterp.warmspot import get_stats, get_translator from pypy.jit.metainterp import history -from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin +from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin def promote_virtualizable(*args): pass @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py --- a/pypy/jit/metainterp/test/test_warmspot.py +++ b/pypy/jit/metainterp/test/test_warmspot.py @@ -80,7 +80,7 @@ self.meta_interp(f, [123, 10]) assert len(get_stats().locations) >= 4 for loc in get_stats().locations: - assert loc == 'GREEN IS 123.' + assert loc == (0, 123) def test_set_param_enable_opts(self): from pypy.rpython.annlowlevel import llstr, hlstr diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -181,6 +181,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = None @@ -207,6 +208,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = llhelper(GET_LOCATION, get_location) _confirm_enter_jit_ptr = None @@ -230,6 +232,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = llhelper(ENTER_JIT, confirm_enter_jit) @@ -253,6 +256,7 @@ cpu = None memory_manager = None class FakeJitDriverSD: + jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = None diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py --- a/pypy/jit/metainterp/virtualref.py +++ b/pypy/jit/metainterp/virtualref.py @@ -1,5 +1,5 @@ from pypy.rpython.rmodel import inputconst, log -from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass +from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.jit.metainterp import history from pypy.jit.codewriter import heaptracker from pypy.rlib.jit import InvalidVirtualRef diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -1,6 +1,5 @@ import sys, py -from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr -from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.annlowlevel import llhelper, MixLevelHelperAnnotator,\ cast_base_ptr_to_instance, hlstr from pypy.annotation import model as annmodel @@ -10,16 +9,12 @@ from pypy.objspace.flow.model import checkgraph, Link, copygraph from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import r_uint, intmask -from pypy.rlib.debug import debug_print, fatalerror -from pypy.rlib.debug import debug_start, debug_stop -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.translator.simplify import get_funcobj, get_functype +from pypy.rlib.debug import fatalerror +from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function from pypy.jit.metainterp import history, pyjitpl, gc, memmgr -from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp -from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper +from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.jitdriver import JitDriverStaticData @@ -66,6 +61,7 @@ def jittify_and_run(interp, graph, args, repeat=1, backendopt=False, trace_limit=sys.maxint, inline=False, loop_longevity=0, retrace_limit=5, + function_threshold=4, enable_opts=ALL_OPTS_NAMES, **kwds): from pypy.config.config import ConfigError translator = interp.typer.annotator.translator @@ -77,9 +73,14 @@ translator.config.translation.list_comprehension_operations = True except ConfigError: pass + try: + translator.config.translation.jit_ffi = True + except ConfigError: + pass warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds) for jd in warmrunnerdesc.jitdrivers_sd: jd.warmstate.set_param_threshold(3) # for tests + jd.warmstate.set_param_function_threshold(function_threshold) jd.warmstate.set_param_trace_eagerness(2) # for tests jd.warmstate.set_param_trace_limit(trace_limit) jd.warmstate.set_param_inlining(inline) @@ -291,9 +292,6 @@ self.stats = stats if translate_support_code: self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper) - annhelper = self.annhelper - else: - annhelper = None cpu = CPUClass(self.translator.rtyper, self.stats, self.opt, translate_support_code, gcdescr=self.gcdescr) self.cpu = cpu @@ -422,7 +420,7 @@ if self.translator.rtyper.type_system.name == 'lltypesystem': def maybe_enter_jit(*args): try: - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) except JitException: raise # go through except Exception, e: @@ -430,15 +428,12 @@ maybe_enter_jit._always_inline_ = True else: def maybe_enter_jit(*args): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_threshold, *args) maybe_enter_jit._always_inline_ = True jd._maybe_enter_jit_fn = maybe_enter_jit - can_inline = state.can_inline_greenargs - num_green_args = jd.num_green_args def maybe_enter_from_start(*args): - if not can_inline(*args[:num_green_args]): - maybe_compile_and_run(*args) + maybe_compile_and_run(state.increment_function_threshold, *args) maybe_enter_from_start._always_inline_ = True jd._maybe_enter_from_start_fn = maybe_enter_from_start @@ -549,7 +544,6 @@ self.rewrite_can_enter_jit(jd, sublist) def rewrite_can_enter_jit(self, jd, can_enter_jits): - FUNC = jd._JIT_ENTER_FUNCTYPE FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -1,7 +1,7 @@ import sys, weakref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi from pypy.rpython.ootypesystem import ootype -from pypy.rpython.annlowlevel import hlstr, llstr, cast_base_ptr_to_instance +from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance from pypy.rpython.annlowlevel import cast_object_to_ptr from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict from pypy.rlib.rarithmetic import intmask @@ -208,15 +208,20 @@ meth = getattr(self, 'set_param_' + name) meth(default_value) - def set_param_threshold(self, threshold): + def _compute_threshold(self, threshold): if threshold <= 0: - self.increment_threshold = 0 # never reach the THRESHOLD_LIMIT - return + return 0 # never reach the THRESHOLD_LIMIT if threshold < 2: threshold = 2 - self.increment_threshold = (self.THRESHOLD_LIMIT // threshold) + 1 + return (self.THRESHOLD_LIMIT // threshold) + 1 # the number is at least 1, and at most about half THRESHOLD_LIMIT + def set_param_threshold(self, threshold): + self.increment_threshold = self._compute_threshold(threshold) + + def set_param_function_threshold(self, threshold): + self.increment_function_threshold = self._compute_threshold(threshold) + def set_param_trace_eagerness(self, value): self.trace_eagerness = value @@ -232,7 +237,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: @@ -291,7 +296,7 @@ self.make_jitdriver_callbacks() confirm_enter_jit = self.confirm_enter_jit - def maybe_compile_and_run(*args): + def maybe_compile_and_run(threshold, *args): """Entry point to the JIT. Called at the point with the can_enter_jit() hint. """ @@ -307,7 +312,7 @@ if cell.counter >= 0: # update the profiling counter - n = cell.counter + self.increment_threshold + n = cell.counter + threshold if n <= self.THRESHOLD_LIMIT: # bound not reached cell.counter = n return @@ -497,7 +502,6 @@ if hasattr(self, 'set_future_values'): return self.set_future_values - warmrunnerdesc = self.warmrunnerdesc jitdriver_sd = self.jitdriver_sd cpu = self.cpu vinfo = jitdriver_sd.virtualizable_info @@ -513,7 +517,6 @@ # if vinfo is not None: i0 = len(jitdriver_sd._red_args_types) - num_green_args = jitdriver_sd.num_green_args index_of_virtualizable = jitdriver_sd.index_of_virtualizable vable_static_fields = unrolling_iterable( zip(vinfo.static_extra_types, vinfo.static_fields)) @@ -599,12 +602,8 @@ get_location_ptr = self.jitdriver_sd._get_printable_location_ptr if get_location_ptr is None: missing = '(no jitdriver.get_printable_location!)' - missingll = llstr(missing) def get_location_str(greenkey): - if we_are_translated(): - return missingll - else: - return missing + return missing else: rtyper = self.warmrunnerdesc.rtyper unwrap_greenkey = self.make_unwrap_greenkey() @@ -612,10 +611,10 @@ def get_location_str(greenkey): greenargs = unwrap_greenkey(greenkey) fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr) - res = fn(*greenargs) - if not we_are_translated() and not isinstance(res, str): - res = hlstr(res) - return res + llres = fn(*greenargs) + if not we_are_translated() and isinstance(llres, str): + return llres + return hlstr(llres) self.get_location_str = get_location_str # confirm_enter_jit_ptr = self.jitdriver_sd._confirm_enter_jit_ptr diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py --- a/pypy/jit/tl/pypyjit.py +++ b/pypy/jit/tl/pypyjit.py @@ -30,6 +30,7 @@ BACKEND = 'c' config = get_pypy_config(translating=True) +config.translation.backendopt.inline_threshold = 0.1 config.translation.gc = 'boehm' config.objspace.nofaking = True config.translating = True diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -3,24 +3,15 @@ in a nicer fashion """ -from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat,\ - LoopToken, get_const_ptr_for_string, get_const_ptr_for_unicode +from pypy.jit.tool.oparser_model import get_model + from pypy.jit.metainterp.resoperation import rop, ResOperation, \ ResOpWithDescr, N_aryOp, \ UnaryOp, PlainResOp -from pypy.jit.metainterp.typesystem import llhelper -from pypy.jit.codewriter.heaptracker import adr2int -from pypy.jit.codewriter import longlong -from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.rpython.ootypesystem import ootype class ParseError(Exception): pass -class Boxes(object): - pass - class ESCAPE_OP(N_aryOp, ResOpWithDescr): OPNUM = -123 @@ -54,37 +45,15 @@ def clone(self): return FORCE_SPILL(self.OPNUM, self.getarglist()[:]) -class ExtendedTreeLoop(TreeLoop): - def getboxes(self): - def opboxes(operations): - for op in operations: - yield op.result - for box in op.getarglist(): - yield box - def allboxes(): - for box in self.inputargs: - yield box - for box in opboxes(self.operations): - yield box - - boxes = Boxes() - for box in allboxes(): - if isinstance(box, Box): - name = str(box) - setattr(boxes, name, box) - return boxes - - def setvalues(self, **kwds): - boxes = self.getboxes() - for name, value in kwds.iteritems(): - getattr(boxes, name).value = value - -def default_fail_descr(fail_args=None): - return BasicFailDescr() +def default_fail_descr(model, fail_args=None): + return model.BasicFailDescr() class OpParser(object): + + use_mock_model = False + def __init__(self, input, cpu, namespace, type_system, boxkinds, invent_fail_descr=default_fail_descr, nonstrict=False): @@ -100,7 +69,8 @@ self._cache = {} self.invent_fail_descr = invent_fail_descr self.nonstrict = nonstrict - self.looptoken = LoopToken() + self.model = get_model(self.use_mock_model) + self.looptoken = self.model.LoopToken() def get_const(self, name, typ): if self._consts is None: @@ -108,16 +78,16 @@ obj = self._consts[name] if self.type_system == 'lltype': if typ == 'ptr': - return ConstPtr(obj) + return self.model.ConstPtr(obj) else: assert typ == 'class' - return ConstInt(adr2int(llmemory.cast_ptr_to_adr(obj))) + return self.model.ConstInt(self.model.ptr_to_int(obj)) else: if typ == 'ptr': - return ConstObj(obj) + return self.model.ConstObj(obj) else: assert typ == 'class' - return ConstObj(ootype.cast_to_object(obj)) + return self.model.ConstObj(ootype.cast_to_object(obj)) def get_descr(self, poss_descr): if poss_descr.startswith('<'): @@ -132,16 +102,16 @@ pass if elem.startswith('i'): # integer - box = BoxInt() - _box_counter_more_than(elem[1:]) + box = self.model.BoxInt() + _box_counter_more_than(self.model, elem[1:]) elif elem.startswith('f'): - box = BoxFloat() - _box_counter_more_than(elem[1:]) + box = self.model.BoxFloat() + _box_counter_more_than(self.model, elem[1:]) elif elem.startswith('p'): # pointer - ts = getattr(self.cpu, 'ts', llhelper) + ts = getattr(self.cpu, 'ts', self.model.llhelper) box = ts.BoxRef() - _box_counter_more_than(elem[1:]) + _box_counter_more_than(self.model, elem[1:]) else: for prefix, boxclass in self.boxkinds.iteritems(): if elem.startswith(prefix): @@ -175,21 +145,21 @@ def getvar(self, arg): if not arg: - return ConstInt(0) + return self.model.ConstInt(0) try: - return ConstInt(int(arg)) + return self.model.ConstInt(int(arg)) except ValueError: if self.is_float(arg): - return ConstFloat(longlong.getfloatstorage(float(arg))) + return self.model.ConstFloat(self.model.convert_to_floatstorage(arg)) if (arg.startswith('"') or arg.startswith("'") or arg.startswith('s"')): # XXX ootype info = arg[1:].strip("'\"") - return get_const_ptr_for_string(info) + return self.model.get_const_ptr_for_string(info) if arg.startswith('u"'): # XXX ootype info = arg[1:].strip("'\"") - return get_const_ptr_for_unicode(info) + return self.model.get_const_ptr_for_unicode(info) if arg.startswith('ConstClass('): name = arg[len('ConstClass('):-1] return self.get_const(name, 'class') @@ -197,9 +167,9 @@ return None elif arg == 'NULL': if self.type_system == 'lltype': - return ConstPtr(ConstPtr.value) + return self.model.ConstPtr(self.model.ConstPtr.value) else: - return ConstObj(ConstObj.value) + return self.model.ConstObj(self.model.ConstObj.value) elif arg.startswith('ConstPtr('): name = arg[len('ConstPtr('):-1] return self.get_const(name, 'ptr') @@ -211,11 +181,8 @@ args = [] descr = None if argspec.strip(): - if opname == 'debug_merge_point': - allargs = argspec.rsplit(', ', 1) - else: - allargs = [arg for arg in argspec.split(",") - if arg != ''] + allargs = [arg for arg in argspec.split(",") + if arg != ''] poss_descr = allargs[-1].strip() if poss_descr.startswith('descr='): @@ -266,14 +233,14 @@ "Unknown var in fail_args: %s" % arg) fail_args.append(fail_arg) if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr(fail_args) + descr = self.invent_fail_descr(self.model, fail_args) if hasattr(descr, '_oparser_uses_descr_of_guard'): descr._oparser_uses_descr_of_guard(self, fail_args) else: fail_args = None if opnum == rop.FINISH: if descr is None and self.invent_fail_descr: - descr = self.invent_fail_descr() + descr = self.invent_fail_descr(self.model) elif opnum == rop.JUMP: if descr is None and self.invent_fail_descr: descr = self.looptoken @@ -338,7 +305,7 @@ num, ops, last_offset = self.parse_ops(base_indent, newlines, 0) if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) - loop = ExtendedTreeLoop("loop") + loop = self.model.ExtendedTreeLoop("loop") loop.comment = first_comment loop.token = self.looptoken loop.operations = ops @@ -370,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" @@ -394,7 +366,7 @@ def parse(input, cpu=None, namespace=None, type_system='lltype', boxkinds=None, invent_fail_descr=default_fail_descr, - no_namespace=False, nonstrict=False): + no_namespace=False, nonstrict=False, OpParser=OpParser): if namespace is None and not no_namespace: namespace = {} return OpParser(input, cpu, namespace, type_system, boxkinds, @@ -405,6 +377,6 @@ return parse(*args, **kwds) -def _box_counter_more_than(s): +def _box_counter_more_than(model, s): if s.isdigit(): - Box._counter = max(Box._counter, int(s)+1) + model.Box._counter = max(model.Box._counter, int(s)+1) diff --git a/pypy/jit/tool/oparser_model.py b/pypy/jit/tool/oparser_model.py new file mode 100644 --- /dev/null +++ b/pypy/jit/tool/oparser_model.py @@ -0,0 +1,148 @@ +class Boxes(object): + pass + +def get_real_model(): + class LoopModel(object): + from pypy.jit.metainterp.history import TreeLoop, LoopToken + from pypy.jit.metainterp.history import Box, BoxInt, BoxFloat + from pypy.jit.metainterp.history import ConstInt, ConstObj, ConstPtr, ConstFloat + from pypy.jit.metainterp.history import BasicFailDescr + from pypy.jit.metainterp.typesystem import llhelper + + from pypy.jit.metainterp.history import get_const_ptr_for_string + from pypy.jit.metainterp.history import get_const_ptr_for_unicode + get_const_ptr_for_string = staticmethod(get_const_ptr_for_string) + get_const_ptr_for_unicode = staticmethod(get_const_ptr_for_unicode) + + @staticmethod + def convert_to_floatstorage(arg): + from pypy.jit.codewriter import longlong + return longlong.getfloatstorage(float(arg)) + + @staticmethod + def ptr_to_int(obj): + from pypy.jit.codewriter.heaptracker import adr2int + from pypy.rpython.lltypesystem import llmemory + return adr2int(llmemory.cast_ptr_to_adr(obj)) + + @staticmethod + def ootype_cast_to_object(obj): + from pypy.rpython.ootypesystem import ootype + return ootype.cast_to_object(obj) + + return LoopModel + +def get_mock_model(): + class LoopModel(object): + + class TreeLoop(object): + def __init__(self, name): + self.name = name + + class LoopToken(object): + I_am_a_descr = True + + class BasicFailDescr(object): + I_am_a_descr = True + + class Box(object): + _counter = 0 + type = 'b' + + def __init__(self, value=0): + self.value = value + + def __repr__(self): + result = str(self) + result += '(%s)' % self.value + return result + + def __str__(self): + if not hasattr(self, '_str'): + self._str = '%s%d' % (self.type, Box._counter) + Box._counter += 1 + return self._str + + class BoxInt(Box): + type = 'i' + + class BoxFloat(Box): + type = 'f' + + class BoxRef(Box): + type = 'p' + + class Const(object): + def __init__(self, value=None): + self.value = value + + def _get_str(self): + return str(self.value) + + class ConstInt(Const): + pass + + class ConstPtr(Const): + pass + + class ConstFloat(Const): + pass + + @classmethod + def get_const_ptr_for_string(cls, s): + return cls.ConstPtr(s) + + @classmethod + def get_const_ptr_for_unicode(cls, s): + return cls.ConstPtr(s) + + @staticmethod + def convert_to_floatstorage(arg): + return float(arg) + + @staticmethod + def ptr_to_int(obj): + return id(obj) + + class llhelper(object): + pass + + LoopModel.llhelper.BoxRef = LoopModel.BoxRef + + return LoopModel + + +def get_model(use_mock): + if use_mock: + model = get_mock_model() + else: + model = get_real_model() + + class ExtendedTreeLoop(model.TreeLoop): + + def getboxes(self): + def opboxes(operations): + for op in operations: + yield op.result + for box in op.getarglist(): + yield box + def allboxes(): + for box in self.inputargs: + yield box + for box in opboxes(self.operations): + yield box + + boxes = Boxes() + for box in allboxes(): + if isinstance(box, model.Box): + name = str(box) + setattr(boxes, name, box) + return boxes + + def setvalues(self, **kwds): + boxes = self.getboxes() + for name, value in kwds.iteritems(): + getattr(boxes, name).value = value + + model.ExtendedTreeLoop = ExtendedTreeLoop + return model diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el --- a/pypy/jit/tool/pypytrace-mode.el +++ b/pypy/jit/tool/pypytrace-mode.el @@ -8,10 +8,16 @@ (defun set-truncate-lines () (setq truncate-lines t)) +;; to generate the list of keywords: +;; from pypy.jit.metainterp import resoperation +;; print ' '.join(sorted('"%s"' % op.lower() for op in resoperation.opname.values() if not op.startswith('GUARD'))) + + + (define-generic-mode 'pypytrace-mode ;; name of the mode to create nil - '("jump" "finish" "int_add" "int_sub" "int_mul" "int_floordiv" "uint_floordiv" "int_mod" "int_and" "int_or" "int_xor" "int_rshift" "int_lshift" "uint_rshift" "float_add" "float_sub" "float_mul" "float_truediv" "float_neg" "float_abs" "cast_float_to_int" "cast_int_to_float" "int_lt" "int_le" "int_eq" "int_ne" "int_gt" "int_ge" "uint_lt" "uint_le" "uint_gt" "uint_ge" "float_lt" "float_le" "float_eq" "float_ne" "float_gt" "float_ge" "int_is_zero" "int_is_true" "int_neg" "int_invert" "same_as" "ptr_eq" "ptr_ne" "arraylen_gc" "strlen" "strgetitem" "getfield_gc_pure" "getfield_raw_pure" "getarrayitem_gc_pure" "unicodelen" "unicodegetitem" "getarrayitem_gc" "getarrayitem_raw" "getfield_gc" "getfield_raw" "new" "new_with_vtable" "new_array" "force_token" "virtual_ref" "setarrayitem_gc" "setarrayitem_raw" "setfield_gc" "setfield_raw" "arraycopy" "newstr" "strsetitem" "unicodesetitem" "newunicode" "cond_call_gc_wb" "virtual_ref_finish" "call" "call_assembler" "call_may_force" "call_loopinvariant" "call_pure" "int_add_ovf" "int_sub_ovf" "int_mul_ovf") ;; keywords + '("arraylen_gc" "call" "call_assembler" "call_loopinvariant" "call_may_force" "call_pure" "call_release_gil" "cast_float_to_int" "cast_int_to_float" "cond_call_gc_wb" "copystrcontent" "copyunicodecontent" "debug_merge_point" "finish" "float_abs" "float_add" "float_eq" "float_ge" "float_gt" "float_le" "float_lt" "float_mul" "float_ne" "float_neg" "float_sub" "float_truediv" "force_token" "getarrayitem_gc" "getarrayitem_gc_pure" "getarrayitem_raw" "getfield_gc" "getfield_gc_pure" "getfield_raw" "getfield_raw_pure" "int_add" "int_add_ovf" "int_and" "int_eq" "int_floordiv" "int_ge" "int_gt" "int_invert" "int_is_true" "int_is_zero" "int_le" "int_lshift" "int_lt" "int_mod" "int_mul" "int_mul_ovf" "int_ne" "int_neg" "int_or" "int_rshift" "int_sub" "int_sub_ovf" "int_xor" "jit_debug" "jump" "new" "new_array" "new_with_vtable" "newstr" "newunicode" "ptr_eq" "ptr_ne" "quasiimmut_field" "read_timestamp" "same_as" "setarrayitem_gc" "setarrayitem_raw" "setfield_gc" "setfield_raw" "strgetitem" "strlen" "strsetitem" "uint_floordiv" "uint_ge" "uint_gt" "uint_le" "uint_lt" "uint_rshift" "unicodegetitem" "unicodelen" "unicodesetitem" "virtual_ref" "virtual_ref_finish") ;; keywords '( ;; additional regexps ("^# Loop.*" . 'hi-blue) ("\\[.*\\]" . 'font-lock-comment-face) ;; comment out argument lists @@ -26,7 +32,7 @@ ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face)) ;; comment out debug_merge_point, but then highlight specific part of it ("^debug_merge_point.*" . font-lock-comment-face) - ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)" + ("^\\(debug_merge_point\\).*code object\\(.*\\). file \\('.*'\\). \\(line .*\\)> \\(.*\\)" (1 'compilation-warning t) (2 'escape-glyph t) (3 'font-lock-string-face t) diff --git a/pypy/jit/tool/test/test_oparser.py b/pypy/jit/tool/test/test_oparser.py --- a/pypy/jit/tool/test/test_oparser.py +++ b/pypy/jit/tool/test/test_oparser.py @@ -1,227 +1,274 @@ import py +import sys from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.jit.tool.oparser import parse, ParseError +from pypy.jit.tool.oparser import parse, OpParser from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken,\ - BoxFloat +from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken -def test_basic_parse(): - x = """ - [i0, i1] - # a comment - i2 = int_add(i0, i1) - i3 = int_sub(i2, 3) # another comment - finish() # (tricky) - """ - loop = parse(x) - assert len(loop.operations) == 3 - assert [op.getopnum() for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, - rop.FINISH] - assert len(loop.inputargs) == 2 - assert loop.operations[-1].getdescr() +class BaseTestOparser(object): -def test_const_ptr_subops(): - x = """ - [p0] - guard_class(p0, ConstClass(vtable)) [] - """ - S = lltype.Struct('S') - vtable = lltype.nullptr(S) - loop = parse(x, None, locals()) - assert len(loop.operations) == 1 - assert loop.operations[0].getdescr() - assert loop.operations[0].getfailargs() == [] + OpParser = None -def test_descr(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - i1 = getfield_gc(p0, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff + def parse(self, *args, **kwds): + kwds['OpParser'] = self.OpParser + return parse(*args, **kwds) -def test_after_fail(): - x = """ - [i0] - guard_value(i0, 3) [] - i1 = int_add(1, 2) - """ - loop = parse(x, None, {}) - assert len(loop.operations) == 2 + def test_basic_parse(self): + x = """ + [i0, i1] + # a comment + i2 = int_add(i0, i1) + i3 = int_sub(i2, 3) # another comment + finish() # (tricky) + """ + loop = self.parse(x) + assert len(loop.operations) == 3 + assert [op.getopnum() for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, + rop.FINISH] + assert len(loop.inputargs) == 2 + assert loop.operations[-1].getdescr() -def test_descr_setfield(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - setfield_gc(p0, 3, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff + def test_const_ptr_subops(self): + x = """ + [p0] + guard_class(p0, ConstClass(vtable)) [] + """ + S = lltype.Struct('S') + vtable = lltype.nullptr(S) + loop = self.parse(x, None, locals()) + assert len(loop.operations) == 1 + assert loop.operations[0].getdescr() + assert loop.operations[0].getfailargs() == [] -def test_boxname(): - x = """ - [i42] - i50 = int_add(i42, 1) - """ - loop = parse(x, None, {}) - assert str(loop.inputargs[0]) == 'i42' - assert str(loop.operations[0].result) == 'i50' + def test_descr(self): + class Xyz(AbstractDescr): + I_am_a_descr = True # for the mock case -def test_getboxes(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - boxes = loop.getboxes() - assert boxes.i0 is loop.inputargs[0] - assert boxes.i1 is loop.operations[0].result - -def test_setvalues(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - loop.setvalues(i0=32, i1=42) - assert loop.inputargs[0].value == 32 - assert loop.operations[0].result.value == 42 + x = """ + [p0] + i1 = getfield_gc(p0, descr=stuff) + """ + stuff = Xyz() + loop = self.parse(x, None, locals()) + assert loop.operations[0].getdescr() is stuff -def test_boxkind(): - x = """ - [sum0] - """ - loop = parse(x, None, {}, boxkinds={'sum': BoxInt}) - b = loop.getboxes() - assert isinstance(b.sum0, BoxInt) - -def test_getvar_const_ptr(): - x = ''' - [] - call(ConstPtr(func_ptr)) + def test_after_fail(self): + x = """ + [i0] + guard_value(i0, 3) [] + i1 = int_add(1, 2) + """ + loop = self.parse(x, None, {}) + assert len(loop.operations) == 2 + + def test_descr_setfield(self): + class Xyz(AbstractDescr): + I_am_a_descr = True # for the mock case + + x = """ + [p0] + setfield_gc(p0, 3, descr=stuff) + """ + stuff = Xyz() + loop = self.parse(x, None, locals()) + assert loop.operations[0].getdescr() is stuff + + def test_boxname(self): + x = """ + [i42] + i50 = int_add(i42, 1) + """ + loop = self.parse(x, None, {}) + assert str(loop.inputargs[0]) == 'i42' + assert str(loop.operations[0].result) == 'i50' + + def test_getboxes(self): + x = """ + [i0] + i1 = int_add(i0, 10) + """ + loop = self.parse(x, None, {}) + boxes = loop.getboxes() + assert boxes.i0 is loop.inputargs[0] + assert boxes.i1 is loop.operations[0].result + + def test_setvalues(self): + x = """ + [i0] + i1 = int_add(i0, 10) + """ + loop = self.parse(x, None, {}) + loop.setvalues(i0=32, i1=42) + assert loop.inputargs[0].value == 32 + assert loop.operations[0].result.value == 42 + + def test_getvar_const_ptr(self): + x = ''' + [] + call(ConstPtr(func_ptr)) + ''' + TP = lltype.GcArray(lltype.Signed) + NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) + loop = self.parse(x, None, {'func_ptr' : NULL}) + assert loop.operations[0].getarg(0).value == NULL + + def test_jump_target(self): + x = ''' + [] + jump() + ''' + loop = self.parse(x) + assert loop.operations[0].getdescr() is loop.token + + def test_jump_target_other(self): + looptoken = LoopToken() + looptoken.I_am_a_descr = True # for the mock case + x = ''' + [] + jump(descr=looptoken) + ''' + loop = self.parse(x, namespace=locals()) + assert loop.operations[0].getdescr() is looptoken + + def test_floats(self): + x = ''' + [f0] + f1 = float_add(f0, 3.5) + ''' + loop = self.parse(x) + box = loop.operations[0].getarg(0) + # we cannot use isinstance, because in case of mock the class will be + # constructed on the fly + assert box.__class__.__name__ == 'BoxFloat' + + def test_debug_merge_point(self): + x = ''' + [] + debug_merge_point(0, "info") + debug_merge_point(0, 'info') + debug_merge_point(1, ' info') + debug_merge_point(0, '(stuff) #1') + ''' + loop = self.parse(x) + assert loop.operations[0].getarg(1)._get_str() == 'info' + assert loop.operations[1].getarg(1)._get_str() == 'info' + assert loop.operations[2].getarg(1)._get_str() == " info" + assert loop.operations[3].getarg(1)._get_str() == "(stuff) #1" + + + def test_descr_with_obj_print(self): + x = ''' + [p0] + setfield_gc(p0, 1, descr=) + ''' + loop = self.parse(x) + # assert did not explode + + example_loop_log = '''\ + # bridge out of Guard12, 6 ops + [i0, i1, i2] + i4 = int_add(i0, 2) + i6 = int_sub(i1, 1) + i8 = int_gt(i6, 3) + guard_true(i8, descr=) [i4, i6] + debug_merge_point('(no jitdriver.get_printable_location!)', 0) + jump(i6, i4, descr=) ''' - TP = lltype.GcArray(lltype.Signed) - NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) - loop = parse(x, None, {'func_ptr' : NULL}) - assert loop.operations[0].getarg(0).value == NULL -def test_jump_target(): - x = ''' - [] - jump() - ''' - loop = parse(x) - assert loop.operations[0].getdescr() is loop.token + def test_parse_no_namespace(self): + loop = self.parse(self.example_loop_log, no_namespace=True) -def test_jump_target_other(): - looptoken = LoopToken() - x = ''' - [] - jump(descr=looptoken) - ''' - loop = parse(x, namespace=locals()) - assert loop.operations[0].getdescr() is looptoken + def test_attach_comment_to_loop(self): + loop = self.parse(self.example_loop_log, no_namespace=True) + assert loop.comment == ' # bridge out of Guard12, 6 ops' -def test_floats(): - x = ''' - [f0] - f1 = float_add(f0, 3.5) - ''' - loop = parse(x) - assert isinstance(loop.operations[0].getarg(0), BoxFloat) - -def test_debug_merge_point(): - x = ''' - [] - debug_merge_point("info", 0) - debug_merge_point('info', 1) - debug_merge_point(' info', 1) - debug_merge_point('(stuff) #1', 1) - ''' - loop = parse(x) - assert loop.operations[0].getarg(0)._get_str() == 'info' - assert loop.operations[1].getarg(0)._get_str() == 'info' - assert loop.operations[2].getarg(0)._get_str() == " info" - assert loop.operations[3].getarg(0)._get_str() == "(stuff) #1" - + def test_parse_new_with_comma(self): + # this is generated by PYPYJITLOG, check that we can handle it + x = ''' + [] + p0 = new(, descr=) + ''' + loop = self.parse(x) + assert loop.operations[0].getopname() == 'new' -def test_descr_with_obj_print(): - x = ''' - [p0] - setfield_gc(p0, 1, descr=) - ''' - loop = parse(x) - # assert did not explode + def test_no_fail_args(self): + x = ''' + [i0] + guard_true(i0, descr=) + ''' + loop = self.parse(x, nonstrict=True) + assert loop.operations[0].getfailargs() == [] -example_loop_log = '''\ -# bridge out of Guard12, 6 ops -[i0, i1, i2] -i4 = int_add(i0, 2) -i6 = int_sub(i1, 1) -i8 = int_gt(i6, 3) -guard_true(i8, descr=) [i4, i6] -debug_merge_point('(no jitdriver.get_printable_location!)', 0) -jump(i6, i4, descr=) -''' + def test_no_inputargs(self): + x = ''' + i2 = int_add(i0, i1) + ''' + loop = self.parse(x, nonstrict=True) + assert loop.inputargs == [] + assert loop.operations[0].getopname() == 'int_add' -def test_parse_no_namespace(): - loop = parse(example_loop_log, no_namespace=True) + def test_offsets(self): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + """ + # +30: --end of the loop-- + loop = self.parse(x) + assert loop.operations[0].offset == 10 + assert not hasattr(loop.operations[1], 'offset') -def test_attach_comment_to_loop(): - loop = parse(example_loop_log, no_namespace=True) - assert loop.comment == '# bridge out of Guard12, 6 ops' + def test_last_offset(self): + x = """ + [i0, i1] + +10: i2 = int_add(i0, i1) + i3 = int_add(i2, 3) + +30: --end of the loop-- + """ + loop = self.parse(x) + assert len(loop.operations) == 2 + assert loop.last_offset == 30 -def test_parse_new_with_comma(): - # this is generated by PYPYJITLOG, check that we can handle it - x = ''' - [] - p0 = new(, descr=) - ''' - loop = parse(x) - assert loop.operations[0].getopname() == 'new' -def test_no_fail_args(): - x = ''' - [i0] - guard_true(i0, descr=) - ''' - loop = parse(x, nonstrict=True) - assert loop.operations[0].getfailargs() == [] +class TestOpParser(BaseTestOparser): -def test_no_inputargs(): - x = ''' - i2 = int_add(i0, i1) - ''' - loop = parse(x, nonstrict=True) - assert loop.inputargs == [] - assert loop.operations[0].getopname() == 'int_add' + OpParser = OpParser -def test_offsets(): - x = """ - [i0, i1] - +10: i2 = int_add(i0, i1) - i3 = int_add(i2, 3) - """ - # +30: --end of the loop-- - loop = parse(x) - assert loop.operations[0].offset == 10 - assert not hasattr(loop.operations[1], 'offset') + def test_boxkind(self): + x = """ + [sum0] + """ + loop = self.parse(x, None, {}, boxkinds={'sum': BoxInt}) + b = loop.getboxes() + assert isinstance(b.sum0, BoxInt) -def test_last_offset(): - x = """ - [i0, i1] - +10: i2 = int_add(i0, i1) - i3 = int_add(i2, 3) - +30: --end of the loop-- - """ - loop = parse(x) - assert len(loop.operations) == 2 - assert loop.last_offset == 30 + +class ForbiddenModule(object): + def __init__(self, name, old_mod): + self.name = name + self.old_mod = old_mod + + def __getattr__(self, attr): + assert False, "You should not import module %s" % self.name + + +class TestOpParserWithMock(BaseTestOparser): + + class OpParser(OpParser): + use_mock_model = True + + def setup_class(cls): + forbidden_mods = [ + 'pypy.jit.metainterp.history', + 'pypy.rpython.lltypesystem.lltype', + ] + for modname in forbidden_mods: + if modname in sys.modules: + newmod = ForbiddenModule(modname, sys.modules[modname]) + sys.modules[modname] = newmod + + def teardown_class(cls): + for modname, mod in sys.modules.iteritems(): + if isinstance(mod, ForbiddenModule): + sys.modules[modname] = mod.old_mod diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -31,6 +17,8 @@ 'apply' : 'app_functional.apply', 'sorted' : 'app_functional.sorted', + 'any' : 'app_functional.any', + 'all' : 'app_functional.all', 'vars' : 'app_inspect.vars', 'dir' : 'app_inspect.dir', @@ -95,8 +83,6 @@ 'range' : 'functional.range_int', 'xrange' : 'functional.W_XRange', 'enumerate' : 'functional.W_Enumerate', - 'all' : 'functional.all', - 'any' : 'functional.any', 'min' : 'functional.min', 'max' : 'functional.max', 'sum' : 'functional.sum', @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py --- a/pypy/module/__builtin__/app_functional.py +++ b/pypy/module/__builtin__/app_functional.py @@ -16,3 +16,21 @@ sorted_lst = list(lst) sorted_lst.sort(cmp, key, reverse) return sorted_lst + +def any(seq): + """any(iterable) -> bool + +Return True if bool(x) is True for any x in the iterable.""" + for x in seq: + if x: + return True + return False + +def all(seq): + """all(iterable) -> bool + +Return True if bool(x) is True for all values x in the iterable.""" + for x in seq: + if not x: + return False + return True diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -294,7 +294,7 @@ break new_frame = space.createframe(code, w_func.w_func_globals, w_func.closure) - new_frame.fastlocals_w[0] = w_item + new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) return result_w @@ -452,40 +452,6 @@ w_empty = space.call_function(w_str_type) return space.call_method(w_empty, "join", space.newlist(result_w)) -def all(space, w_S): - """all(iterable) -> bool - -Return True if bool(x) is True for all values x in the iterable.""" - w_iter = space.iter(w_S) - while True: - try: - w_next = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise # re-raise other app-level exceptions - break - if not space.is_true(w_next): - return space.w_False - return space.w_True - - -def any(space, w_S): - """any(iterable) -> bool - -Return True if bool(x) is True for any x in the iterable.""" - w_iter = space.iter(w_S) - while True: - try: - w_next = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise # re-raise other app-level exceptions - break - if space.is_true(w_next): - return space.w_True - return space.w_False - - class W_Enumerate(Wrappable): def __init__(self, w_iter, w_start): diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -12,7 +12,7 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -1,5 +1,6 @@ import autopath import sys +from pypy import conftest class AppTestBuiltinApp: def setup_class(cls): @@ -15,6 +16,15 @@ cls.w_sane_lookup = cls.space.wrap(True) except KeyError: cls.w_sane_lookup = cls.space.wrap(False) + # starting with CPython 2.6, when the stack is almost out, we + # can get a random error, instead of just a RuntimeError. + # For example if an object x has a __getattr__, we can get + # AttributeError if attempting to call x.__getattr__ runs out + # of stack. That's annoying, so we just work around it. + if conftest.option.runappdirect: + cls.w_safe_runtimerror = cls.space.wrap(True) + else: + cls.w_safe_runtimerror = cls.space.wrap(sys.version_info < (2, 6)) def test_bytes_alias(self): assert bytes is str @@ -399,6 +409,8 @@ def test_cmp_cyclic(self): if not self.sane_lookup: skip("underlying Python implementation has insane dict lookup") + if not self.safe_runtimerror: + skip("underlying Python may raise random exceptions on stack ovf") a = []; a.append(a) b = []; b.append(b) from UserList import UserList @@ -619,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -3,6 +3,14 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.imp.importing import get_pyc_magic + +class BuildersModule(MixedModule): + appleveldefs = {} + + interpleveldefs = { + "UnicodeBuilder": "interp_builders.W_UnicodeBuilder", + } + class Module(MixedModule): appleveldefs = { } @@ -19,6 +27,10 @@ 'lookup_special' : 'interp_magic.lookup_special', } + submodules = { + "builders": BuildersModule, + } + def setup_after_space_initialization(self): """NOT_RPYTHON""" if not self.space.config.translating: diff --git a/pypy/module/__pypy__/interp_builders.py b/pypy/module/__pypy__/interp_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_builders.py @@ -0,0 +1,50 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef +from pypy.rlib.rstring import UnicodeBuilder + + +class W_UnicodeBuilder(Wrappable): + def __init__(self, space, size): + if size == -1: + self.builder = UnicodeBuilder() + else: + self.builder = UnicodeBuilder(size) + self.done = False + + def _check_done(self, space): + if self.done: + raise OperationError(space.w_ValueError, space.wrap("Can't operate on a done builder")) + + @unwrap_spec(size=int) + def descr__new__(space, w_subtype, size=-1): + return W_UnicodeBuilder(space, size) + + @unwrap_spec(s=unicode) + def descr_append(self, space, s): + self._check_done(space) + self.builder.append(s) + + @unwrap_spec(s=unicode, start=int, end=int) + def descr_append_slice(self, space, s, start, end): + self._check_done(space) + if not 0 <= start <= end <= len(s): + raise OperationError(space.w_ValueError, space.wrap("bad start/stop")) + self.builder.append_slice(s, start, end) + + def descr_build(self, space): + self._check_done(space) + w_s = space.wrap(self.builder.build()) + self.done = True + return w_s + + +W_UnicodeBuilder.typedef = TypeDef("UnicodeBuilder", + __new__ = interp2app(W_UnicodeBuilder.descr__new__.im_func), + + append = interp2app(W_UnicodeBuilder.descr_append), + append_slice = interp2app(W_UnicodeBuilder.descr_append_slice), + build = interp2app(W_UnicodeBuilder.descr_build), +) +W_UnicodeBuilder.typedef.acceptable_as_base_class = False \ No newline at end of file diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,15 +1,19 @@ from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.error import OperationError -from pypy.rlib import debug +from pypy.rlib import debug, jit + + at jit.dont_look_inside @unwrap_spec(category=str) def debug_start(space, category): debug.debug_start(category) + at jit.dont_look_inside def debug_print(space, args_w): parts = [space.str_w(space.str(w_item)) for w_item in args_w] debug.debug_print(' '.join(parts)) + at jit.dont_look_inside @unwrap_spec(category=str) def debug_stop(space, category): debug.debug_stop(category) diff --git a/pypy/module/__pypy__/test/test_builders.py b/pypy/module/__pypy__/test/test_builders.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_builders.py @@ -0,0 +1,34 @@ +from pypy.conftest import gettestobjspace + + +class AppTestBuilders(object): + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['__pypy__']) + + def test_simple(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append(u"abc") + b.append(u"123") + b.append(u"1") + s = b.build() + assert s == u"abc1231" + raises(ValueError, b.build) + raises(ValueError, b.append, u"123") + + def test_preallocate(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder(10) + b.append(u"abc") + b.append(u"123") + s = b.build() + assert s == u"abc123" + + def test_append_slice(self): + from __pypy__.builders import UnicodeBuilder + b = UnicodeBuilder() + b.append_slice(u"abcdefgh", 2, 5) + raises(ValueError, b.append_slice, u"1", 2, 1) + s = b.build() + assert s == "cde" + raises(ValueError, b.append_slice, u"abc", 1, 2) \ No newline at end of file diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -32,15 +32,22 @@ space.wrap(reason)) w_res = space.call_function(w_errorhandler, w_exc) if (not space.is_true(space.isinstance(w_res, space.w_tuple)) - or space.len_w(w_res) != 2): + or space.len_w(w_res) != 2 + or not space.is_true(space.isinstance( + space.getitem(w_res, space.wrap(0)), + space.w_unicode))): + if decode: + msg = ("decoding error handler must return " + "(unicode, int) tuple, not %s") + else: + msg = ("encoding error handler must return " + "(unicode, int) tuple, not %s") raise operationerrfmt( - space.w_TypeError, - "encoding error handler must return " - "(unicode, int) tuple, not %s", + space.w_TypeError, msg, space.str_w(space.repr(w_res))) w_replace, w_newpos = space.fixedview(w_res, 2) newpos = space.int_w(w_newpos) - if (newpos < 0): + if newpos < 0: newpos = len(input) + newpos if newpos < 0 or newpos > len(input): raise operationerrfmt( @@ -50,7 +57,9 @@ replace = space.unicode_w(w_replace) return replace, newpos else: - replace = space.str_w(w_replace) + from pypy.objspace.std.unicodetype import encode_object + w_str = encode_object(space, w_replace, encoding, None) + replace = space.str_w(w_str) return replace, newpos return unicode_call_errorhandler @@ -160,15 +169,7 @@ def ignore_errors(space, w_exc): check_exception(space, w_exc) w_end = space.getattr(w_exc, space.wrap('end')) - if space.isinstance_w(w_exc, space.w_UnicodeEncodeError): - return space.newtuple([space.wrap(''), w_end]) - elif (space.isinstance_w(w_exc, space.w_UnicodeDecodeError) or - space.isinstance_w(w_exc, space.w_UnicodeTranslateError)): - return space.newtuple([space.wrap(u''), w_end]) - else: - typename = space.type(w_exc).getname(space, '?') - raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + return space.newtuple([space.wrap(u''), w_end]) def replace_errors(space, w_exc): check_exception(space, w_exc) @@ -176,7 +177,7 @@ w_end = space.getattr(w_exc, space.wrap('end')) size = space.int_w(w_end) - space.int_w(w_start) if space.isinstance_w(w_exc, space.w_UnicodeEncodeError): - text = '?' * size + text = u'?' * size return space.newtuple([space.wrap(text), w_end]) elif space.isinstance_w(w_exc, space.w_UnicodeDecodeError): text = u'\ufffd' @@ -185,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -206,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -239,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_codecs/test/test_codecs.py b/pypy/module/_codecs/test/test_codecs.py --- a/pypy/module/_codecs/test/test_codecs.py +++ b/pypy/module/_codecs/test/test_codecs.py @@ -540,6 +540,17 @@ else: assert res == u"\x00\x00\x01\x00\x00" # UCS2 build + def test_encode_error_bad_handler(self): + import codecs + codecs.register_error("test.bad_handler", lambda e: (repl, 1)) + assert u"xyz".encode("latin-1", "test.bad_handler") == "xyz" + repl = u"\u1234" + raises(UnicodeEncodeError, u"\u5678".encode, "latin-1", + "test.bad_handler") + repl = u"\u00E9" + s = u"\u5678".encode("latin-1", "test.bad_handler") + assert s == '\xe9' + def test_charmap_encode(self): assert 'xxx'.encode('charmap') == 'xxx' @@ -593,3 +604,11 @@ assert u'caf\xe9'.encode('mbcs') == 'caf\xe9' assert u'\u040a'.encode('mbcs') == '?' # some cyrillic letter assert 'cafx\e9'.decode('mbcs') == u'cafx\e9' + + def test_bad_handler_string_result(self): + import _codecs + def f(exc): + return ('foo', exc.end) + _codecs.register_error("test.test_codecs_not_a_string", f) + raises(TypeError, u'\u1234'.encode, 'ascii', + 'test.test_codecs_not_a_string') diff --git a/pypy/module/_ffi/__init__.py b/pypy/module/_ffi/__init__.py --- a/pypy/module/_ffi/__init__.py +++ b/pypy/module/_ffi/__init__.py @@ -4,8 +4,10 @@ class Module(MixedModule): interpleveldefs = { - 'CDLL' : 'interp_ffi.W_CDLL', - 'types': 'interp_ffi.W_types', + 'CDLL': 'interp_ffi.W_CDLL', + 'types': 'interp_ffi.W_types', + 'FuncPtr': 'interp_ffi.W_FuncPtr', + 'get_libc':'interp_ffi.get_libc', } appleveldefs = {} diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -4,63 +4,176 @@ operationerrfmt from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi # from pypy.rlib import jit from pypy.rlib import libffi from pypy.rlib.rdynload import DLOpenError -from pypy.rlib.rarithmetic import intmask +from pypy.rlib.rarithmetic import intmask, r_uint class W_FFIType(Wrappable): - def __init__(self, name, ffitype): + + _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to'] + + def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None): self.name = name self.ffitype = ffitype + self.w_datashape = w_datashape + self.w_pointer_to = w_pointer_to + if self.is_struct(): + assert w_datashape is not None - def str(self, space): - return space.wrap('' % self.name) + def descr_deref_pointer(self, space): + if self.w_pointer_to is None: + return space.w_None + return self.w_pointer_to + def repr(self, space): + return space.wrap(self.__repr__()) + def __repr__(self): + return "" % self.name + + def is_signed(self): + return (self is app_types.slong or + self is app_types.sint or + self is app_types.sshort or + self is app_types.sbyte or + self is app_types.slonglong) + + def is_unsigned(self): + return (self is app_types.ulong or + self is app_types.uint or + self is app_types.ushort or + self is app_types.ubyte or + self is app_types.ulonglong) + + def is_pointer(self): + return self.ffitype is libffi.types.pointer + + def is_char(self): + return self is app_types.char + + def is_unichar(self): + return self is app_types.unichar + + def is_longlong(self): + return libffi.IS_32_BIT and (self is app_types.slonglong or + self is app_types.ulonglong) + + def is_double(self): + return self is app_types.double + + def is_singlefloat(self): + return self is app_types.float + + def is_void(self): + return self is app_types.void + + def is_struct(self): + return libffi.types.is_struct(self.ffitype) W_FFIType.typedef = TypeDef( 'FFIType', - __str__ = interp2app(W_FFIType.str), + __repr__ = interp2app(W_FFIType.repr), + deref_pointer = interp2app(W_FFIType.descr_deref_pointer), ) +def build_ffi_types(): + from pypy.rlib.clibffi import FFI_TYPE_P + types = [ + # note: most of the type name directly come from the C equivalent, + # with the exception of bytes: in C, ubyte and char are equivalent, + # but for _ffi the first expects a number while the second a 1-length + # string + W_FFIType('slong', libffi.types.slong), + W_FFIType('sint', libffi.types.sint), + W_FFIType('sshort', libffi.types.sshort), + W_FFIType('sbyte', libffi.types.schar), + W_FFIType('slonglong', libffi.types.slonglong), + # + W_FFIType('ulong', libffi.types.ulong), + W_FFIType('uint', libffi.types.uint), + W_FFIType('ushort', libffi.types.ushort), + W_FFIType('ubyte', libffi.types.uchar), + W_FFIType('ulonglong', libffi.types.ulonglong), + # + W_FFIType('char', libffi.types.uchar), + W_FFIType('unichar', libffi.types.wchar_t), + # + W_FFIType('double', libffi.types.double), + W_FFIType('float', libffi.types.float), + W_FFIType('void', libffi.types.void), + W_FFIType('void_p', libffi.types.pointer), + # + # missing types: + + ## 's' : ffi_type_pointer, + ## 'z' : ffi_type_pointer, + ## 'O' : ffi_type_pointer, + ## 'Z' : ffi_type_pointer, + + ] + return dict([(t.name, t) for t in types]) + +class app_types: + pass +app_types.__dict__ = build_ffi_types() + +def descr_new_pointer(space, w_cls, w_pointer_to): + try: + return descr_new_pointer.cache[w_pointer_to] + except KeyError: + w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) + name = '(pointer to %s)' % w_pointer_to.name + w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to) + descr_new_pointer.cache[w_pointer_to] = w_result + return w_result +descr_new_pointer.cache = {} + class W_types(Wrappable): pass - -def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P - tdict = {} - for key, value in libffi.types.__dict__.iteritems(): - if key == 'getkind' or key.startswith('__'): - continue - assert lltype.typeOf(value) == FFI_TYPE_P - tdict[key] = W_FFIType(key, value) - return tdict - W_types.typedef = TypeDef( 'types', - **build_ffi_types()) + Pointer = interp2app(descr_new_pointer, as_classmethod=True), + **app_types.__dict__) + + +def unwrap_ffitype(space, w_argtype, allow_void=False): + res = w_argtype.ffitype + if res is libffi.types.void and not allow_void: + msg = 'void is not a valid argument type' + raise OperationError(space.w_TypeError, space.wrap(msg)) + return res + +def unwrap_truncate_int(TP, space, w_arg): + if space.is_true(space.isinstance(w_arg, space.w_int)): + return rffi.cast(TP, space.int_w(w_arg)) + else: + return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask()) +unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)' # ======================================================================== class W_FuncPtr(Wrappable): - _immutable_fields_ = ['func'] + _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype'] - def __init__(self, func): + def __init__(self, func, argtypes_w, w_restype): self.func = func + self.argtypes_w = argtypes_w + self.w_restype = w_restype @jit.unroll_safe - def build_argchain(self, space, argtypes, args_w): - expected = len(argtypes) + def build_argchain(self, space, args_w): + expected = len(self.argtypes_w) given = len(args_w) if given != expected: arg = 'arguments' - if len(argtypes) == 1: + if len(self.argtypes_w) == 1: arg = 'argument' raise operationerrfmt(space.w_TypeError, '%s() takes exactly %d %s (%d given)', @@ -68,34 +181,97 @@ # argchain = libffi.ArgChain() for i in range(expected): - argtype = argtypes[i] + w_argtype = self.argtypes_w[i] w_arg = args_w[i] - kind = libffi.types.getkind(argtype) - if kind == 'i': + if w_argtype.is_longlong(): + # note that we must check for longlong first, because either + # is_signed or is_unsigned returns true anyway + assert libffi.IS_32_BIT + self.arg_longlong(space, argchain, w_arg) + elif w_argtype.is_signed(): + argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) + elif w_argtype.is_pointer(): + w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) + argchain.arg(intmask(space.uint_w(w_arg))) + elif w_argtype.is_unsigned(): + argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg)) + elif w_argtype.is_char(): + w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) - elif kind == 'u': - argchain.arg(intmask(space.uint_w(w_arg))) - elif kind == 'f': + elif w_argtype.is_unichar(): + w_arg = space.ord(w_arg) + argchain.arg(space.int_w(w_arg)) + elif w_argtype.is_double(): argchain.arg(space.float_w(w_arg)) + elif w_argtype.is_singlefloat(): + argchain.arg_singlefloat(space.float_w(w_arg)) + elif w_argtype.is_struct(): + # arg_raw directly takes value to put inside ll_args + w_arg = space.interp_w(W_StructureInstance, w_arg) + ptrval = w_arg.ll_buffer + argchain.arg_raw(ptrval) else: - assert False, "Argument kind '%s' not supported" % kind + assert False, "Argument shape '%s' not supported" % w_argtype return argchain + def convert_pointer_arg_maybe(self, space, w_arg, w_argtype): + """ + Try to convert the argument by calling _as_ffi_pointer_() + """ + meth = space.lookup(w_arg, '_as_ffi_pointer_') # this also promotes the type + if meth: + return space.call_function(meth, w_arg, w_argtype) + else: + return w_arg + + @jit.dont_look_inside + def arg_longlong(self, space, argchain, w_arg): + bigarg = space.bigint_w(w_arg) + ullval = bigarg.ulonglongmask() + llval = rffi.cast(rffi.LONGLONG, ullval) + # this is a hack: we store the 64 bits of the long long into the + # 64 bits of a float (i.e., a C double) + floatval = libffi.longlong2float(llval) + argchain.arg_longlong(floatval) + def call(self, space, args_w): - self = jit.hint(self, promote=True) - argchain = self.build_argchain(space, self.func.argtypes, args_w) - reskind = libffi.types.getkind(self.func.restype) - if reskind == 'i': + self = jit.promote(self) + argchain = self.build_argchain(space, args_w) + w_restype = self.w_restype + if w_restype.is_longlong(): + # note that we must check for longlong first, because either + # is_signed or is_unsigned returns true anyway + assert libffi.IS_32_BIT + reskind = libffi.types.getkind(self.func.restype) # XXX: remove the kind + return self._call_longlong(space, argchain, reskind) + elif w_restype.is_signed(): return self._call_int(space, argchain) - elif reskind == 'u': + elif w_restype.is_unsigned() or w_restype.is_pointer(): return self._call_uint(space, argchain) - elif reskind == 'f': + elif w_restype.is_char(): + intres = self.func.call(argchain, rffi.UCHAR) + return space.wrap(chr(intres)) + elif w_restype.is_unichar(): + intres = self.func.call(argchain, rffi.WCHAR_T) + return space.wrap(unichr(intres)) + elif w_restype.is_double(): floatres = self.func.call(argchain, rffi.DOUBLE) return space.wrap(floatres) - else: + elif w_restype.is_singlefloat(): + # the result is a float, but widened to be inside a double + floatres = self.func.call(argchain, rffi.FLOAT) + return space.wrap(floatres) + elif w_restype.is_struct(): + w_datashape = w_restype.w_datashape + assert isinstance(w_datashape, W_Structure) + ptrval = self.func.call(argchain, rffi.ULONG, is_struct=True) + return w_datashape.fromaddress(space, ptrval) + elif w_restype.is_void(): voidres = self.func.call(argchain, lltype.Void) assert voidres is None return space.w_None + else: + assert False, "Return value shape '%s' not supported" % w_restype def _call_int(self, space, argchain): # if the declared return type of the function is smaller than LONG, @@ -138,6 +314,10 @@ # special case uintres = call(argchain, rffi.ULONG) return space.wrap(uintres) + elif restype is libffi.types.pointer: + ptrres = call(argchain, rffi.VOIDP) + uintres = rffi.cast(rffi.ULONG, ptrres) + return space.wrap(uintres) elif restype is libffi.types.uint: intres = rffi.cast(rffi.LONG, call(argchain, rffi.UINT)) elif restype is libffi.types.ushort: @@ -149,16 +329,52 @@ space.wrap('Unsupported restype')) return space.wrap(intres) + @jit.dont_look_inside + def _call_longlong(self, space, argchain, reskind): + # this is a hack: we store the 64 bits of the long long into the 64 + # bits of a float (i.e., a C double) + floatres = self.func.call(argchain, rffi.LONGLONG) + llres = libffi.float2longlong(floatres) + if reskind == 'I': + return space.wrap(llres) + elif reskind == 'U': + ullres = rffi.cast(rffi.ULONGLONG, llres) + return space.wrap(ullres) + else: + assert False + def getaddr(self, space): """ Return the physical address in memory of the function """ return space.wrap(rffi.cast(rffi.LONG, self.func.funcsym)) + + +def unpack_argtypes(space, w_argtypes, w_restype): + argtypes_w = [space.interp_w(W_FFIType, w_argtype) + for w_argtype in space.listview(w_argtypes)] + argtypes = [unwrap_ffitype(space, w_argtype) for w_argtype in + argtypes_w] + w_restype = space.interp_w(W_FFIType, w_restype) + restype = unwrap_ffitype(space, w_restype, allow_void=True) + return argtypes_w, argtypes, w_restype, restype + + at unwrap_spec(addr=r_uint, name=str) +def descr_fromaddr(space, w_cls, addr, name, w_argtypes, w_restype): + argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space, + w_argtypes, + w_restype) + addr = rffi.cast(rffi.VOIDP, addr) + func = libffi.Func(name, argtypes, restype, addr) + return W_FuncPtr(func, argtypes_w, w_restype) + + W_FuncPtr.typedef = TypeDef( - 'FuncPtr', + '_ffi.FuncPtr', __call__ = interp2app(W_FuncPtr.call), getaddr = interp2app(W_FuncPtr.getaddr), + fromaddr = interp2app(descr_fromaddr, as_classmethod=True) ) @@ -167,40 +383,57 @@ class W_CDLL(Wrappable): def __init__(self, space, name): + self.space = space + if name is None: + self.name = "" + else: + self.name = name try: self.cdll = libffi.CDLL(name) except DLOpenError, e: - raise operationerrfmt(space.w_OSError, '%s: %s', name, + raise operationerrfmt(space.w_OSError, '%s: %s', self.name, e.msg or 'unspecified error') - self.name = name - self.space = space - - def ffitype(self, w_argtype, allow_void=False): - res = self.space.interp_w(W_FFIType, w_argtype).ffitype - if res is libffi.types.void and not allow_void: - space = self.space - msg = 'void is not a valid argument type' - raise OperationError(space.w_TypeError, space.wrap(msg)) - return res @unwrap_spec(name=str) def getfunc(self, space, name, w_argtypes, w_restype): - argtypes = [self.ffitype(w_argtype) for w_argtype in - space.listview(w_argtypes)] - restype = self.ffitype(w_restype, allow_void=True) - func = self.cdll.getpointer(name, argtypes, restype) - return W_FuncPtr(func) + argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space, + w_argtypes, + w_restype) + try: + func = self.cdll.getpointer(name, argtypes, restype) + except KeyError: + raise operationerrfmt(space.w_AttributeError, + "No symbol %s found in library %s", name, self.name) + + return W_FuncPtr(func, argtypes_w, w_restype) + @unwrap_spec(name=str) + def getaddressindll(self, space, name): + try: + address_as_uint = rffi.cast(lltype.Unsigned, + self.cdll.getaddressindll(name)) + except KeyError: + raise operationerrfmt(space.w_ValueError, + "No symbol %s found in library %s", name, self.name) + return space.wrap(address_as_uint) - at unwrap_spec(name=str) + at unwrap_spec(name='str_or_None') def descr_new_cdll(space, w_type, name): return space.wrap(W_CDLL(space, name)) W_CDLL.typedef = TypeDef( - 'CDLL', + '_ffi.CDLL', __new__ = interp2app(descr_new_cdll), getfunc = interp2app(W_CDLL.getfunc), + getaddressindll = interp2app(W_CDLL.getaddressindll), ) # ======================================================================== + +def get_libc(space): + from pypy.rlib.clibffi import get_libc_name + try: + return space.wrap(W_CDLL(space, get_libc_name())) + except OSError, e: + raise wrap_oserror(space, e) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -17,7 +17,13 @@ c_file = udir.ensure("test__ffi", dir=1).join("foolib.c") # automatically collect the C source from the docstrings of the tests - snippets = [] + snippets = [""" + #ifdef _WIN32 + #define DLLEXPORT __declspec(dllexport) + #else + #define DLLEXPORT + #endif + """] for name in dir(cls): if name.startswith('test_'): meth = getattr(cls, name) @@ -35,8 +41,9 @@ from pypy.rpython.lltypesystem import rffi from pypy.rlib.libffi import get_libc_name, CDLL, types from pypy.rlib.test.test_libffi import get_libm_name - space = gettestobjspace(usemodules=('_ffi',)) + space = gettestobjspace(usemodules=('_ffi', '_rawffi')) cls.space = space + cls.w_iswin32 = space.wrap(sys.platform == 'win32') cls.w_libfoo_name = space.wrap(cls.prepare_c_example()) cls.w_libc_name = space.wrap(get_libc_name()) libm_name = get_libm_name(sys.platform) @@ -45,6 +52,13 @@ pow = libm.getpointer('pow', [], types.void) pow_addr = rffi.cast(rffi.LONG, pow.funcsym) cls.w_pow_addr = space.wrap(pow_addr) + # + # these are needed for test_single_float_args + from ctypes import c_float + f_12_34 = c_float(12.34).value + f_56_78 = c_float(56.78).value + f_result = c_float(f_12_34 + f_56_78).value + cls.w_f_12_34_plus_56_78 = space.wrap(f_result) def test_libload(self): import _ffi @@ -54,10 +68,20 @@ import _ffi raises(OSError, _ffi.CDLL, "xxxxx_this_name_does_not_exist_xxxxx") + def test_libload_None(self): + if self.iswin32: + skip("unix specific") + from _ffi import CDLL, types + # this should return *all* loaded libs, dlopen(NULL) + dll = CDLL(None) + # Assume CPython, or PyPy compiled with cpyext + res = dll.getfunc('Py_IsInitialized', [], types.slong)() + assert res == 1 + def test_simple_types(self): from _ffi import types - assert str(types.sint) == '' - assert str(types.uint) == '' + assert str(types.sint) == "" + assert str(types.uint) == "" def test_callfunc(self): from _ffi import CDLL, types @@ -70,24 +94,42 @@ libm = CDLL(self.libm_name) pow = libm.getfunc('pow', [types.double, types.double], types.double) assert pow.getaddr() == self.pow_addr - + + def test_getaddressindll(self): + import sys + from _ffi import CDLL, types + libm = CDLL(self.libm_name) + pow_addr = libm.getaddressindll('pow') + assert pow_addr == self.pow_addr & (sys.maxint*2-1) + + def test_func_fromaddr(self): + import sys + from _ffi import CDLL, types, FuncPtr + libm = CDLL(self.libm_name) + pow_addr = libm.getaddressindll('pow') + pow = FuncPtr.fromaddr(pow_addr, 'pow', [types.double, types.double], + types.double) + assert pow(2, 3) == 8 + def test_int_args(self): """ - int sum_xy(int x, int y) + DLLEXPORT int sum_xy(int x, int y) { return x+y; } """ + import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint) assert sum_xy(30, 12) == 42 + assert sum_xy(sys.maxint*2, 0) == -2 def test_void_result(self): """ int dummy = 0; - void set_dummy(int val) { dummy = val; } - int get_dummy() { return dummy; } + DLLEXPORT void set_dummy(int val) { dummy = val; } + DLLEXPORT int get_dummy() { return dummy; } """ from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) @@ -96,10 +138,105 @@ assert get_dummy() == 0 assert set_dummy(42) is None assert get_dummy() == 42 + set_dummy(0) + + def test_pointer_args(self): + """ + extern int dummy; // defined in test_void_result + DLLEXPORT int* get_dummy_ptr() { return &dummy; } + DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + get_dummy = libfoo.getfunc('get_dummy', [], types.sint) + get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p) + set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', + [types.void_p, types.sint], + types.void) + assert get_dummy() == 0 + ptr = get_dummy_ptr() + set_val_to_ptr(ptr, 123) + assert get_dummy() == 123 + set_val_to_ptr(ptr, 0) + + def test_convert_pointer_args(self): + """ + extern int dummy; // defined in test_void_result + DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args + DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto + """ + from _ffi import CDLL, types + + class MyPointerWrapper(object): + def __init__(self, value): + self.value = value + def _as_ffi_pointer_(self, ffitype): + assert ffitype is types.void_p + return self.value + + libfoo = CDLL(self.libfoo_name) + get_dummy = libfoo.getfunc('get_dummy', [], types.sint) + get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p) + set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', + [types.void_p, types.sint], + types.void) + assert get_dummy() == 0 + ptr = get_dummy_ptr() + assert type(ptr) in (int, long) + ptr2 = MyPointerWrapper(ptr) + set_val_to_ptr(ptr2, 123) + assert get_dummy() == 123 + set_val_to_ptr(ptr2, 0) + + def test_typed_pointer(self): + from _ffi import types + intptr = types.Pointer(types.sint) # create a typed pointer to sint + assert intptr.deref_pointer() is types.sint + assert str(intptr) == '' + assert types.sint.deref_pointer() is None + raises(TypeError, "types.Pointer(42)") + + def test_pointer_identity(self): + from _ffi import types + x = types.Pointer(types.slong) + y = types.Pointer(types.slong) + z = types.Pointer(types.char) + assert x is y + assert x is not z + + def test_typed_pointer_args(self): + """ + extern int dummy; // defined in test_void_result + DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args + DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto + """ + from _ffi import CDLL, types + + libfoo = CDLL(self.libfoo_name) + intptr = types.Pointer(types.sint) + get_dummy = libfoo.getfunc('get_dummy', [], types.sint) + get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], intptr) + set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', [intptr, types.sint], types.void) + assert get_dummy() == 0 + ptr = get_dummy_ptr() + set_val_to_ptr(ptr, 123) + assert get_dummy() == 123 + set_val_to_ptr(ptr, 0) + + def test_huge_pointer_args(self): + """ + #include + DLLEXPORT long is_null_ptr(void* ptr) { return ptr == NULL; } + """ + import sys + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + is_null_ptr = libfoo.getfunc('is_null_ptr', [types.void_p], types.ulong) + assert not is_null_ptr(sys.maxint+1) def test_unsigned_long_args(self): """ - unsigned long sum_xy_ul(unsigned long x, unsigned long y) + DLLEXPORT unsigned long sum_xy_ul(unsigned long x, unsigned long y) { return x+y; } @@ -111,15 +248,17 @@ types.ulong) assert sum_xy(sys.maxint, 12) == sys.maxint+12 assert sum_xy(sys.maxint+1, 12) == sys.maxint+13 + # + res = sum_xy(sys.maxint*2+3, 0) + assert res == 1 def test_unsigned_short_args(self): """ - unsigned short sum_xy_us(unsigned short x, unsigned short y) + DLLEXPORT unsigned short sum_xy_us(unsigned short x, unsigned short y) { return x+y; } """ - import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy_us', [types.ushort, types.ushort], @@ -127,6 +266,169 @@ assert sum_xy(32000, 8000) == 40000 assert sum_xy(60000, 30000) == 90000 % 65536 + def test_unsigned_byte_args(self): + """ + DLLEXPORT unsigned char sum_xy_ub(unsigned char x, unsigned char y) + { + return x+y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_us', [types.ubyte, types.ubyte], + types.ubyte) + assert sum_xy(100, 40) == 140 + assert sum_xy(200, 60) == 260 % 256 + + def test_signed_byte_args(self): + """ + DLLEXPORT signed char sum_xy_sb(signed char x, signed char y) + { + return x+y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_sb', [types.sbyte, types.sbyte], + types.sbyte) + assert sum_xy(10, 20) == 30 + assert sum_xy(100, 28) == -128 + + def test_char_args(self): + """ + DLLEXPORT char my_toupper(char x) + { + return x - ('a'-'A'); + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + my_toupper = libfoo.getfunc('my_toupper', [types.char], + types.char) + assert my_toupper('c') == 'C' + + def test_unichar_args(self): + """ + #include + DLLEXPORT wchar_t sum_xy_wc(wchar_t x, wchar_t y) + { + return x + y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_wc', [types.unichar, types.unichar], + types.unichar) + res = sum_xy(unichr(1000), unichr(2000)) + assert type(res) is unicode + assert ord(res) == 3000 + + def test_single_float_args(self): + """ + DLLEXPORT float sum_xy_float(float x, float y) + { + return x+y; + } + """ + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_float', [types.float, types.float], + types.float) + res = sum_xy(12.34, 56.78) + assert res == self.f_12_34_plus_56_78 + + + def test_slonglong_args(self): + """ + DLLEXPORT long long sum_xy_longlong(long long x, long long y) + { + return x+y; + } + """ + from _ffi import CDLL, types + maxint32 = 2147483647 # we cannot really go above maxint on 64 bits + # (and we would not test anything, as there long + # is the same as long long) + + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_longlong', [types.slonglong, types.slonglong], + types.slonglong) + x = maxint32+1 + y = maxint32+2 + res = sum_xy(x, y) + expected = maxint32*2 + 3 + assert res == expected + + def test_ulonglong_args(self): + """ + DLLEXPORT unsigned long long sum_xy_ulonglong(unsigned long long x, + unsigned long long y) + { + return x+y; + } + """ + from _ffi import CDLL, types + maxint64 = 9223372036854775807 # maxint64+1 does not fit into a + # longlong, but it does into a + # ulonglong + libfoo = CDLL(self.libfoo_name) + sum_xy = libfoo.getfunc('sum_xy_ulonglong', [types.ulonglong, types.ulonglong], + types.ulonglong) + x = maxint64+1 + y = 2 + res = sum_xy(x, y) + expected = maxint64 + 3 + assert res == expected + # + res = sum_xy(maxint64*2+3, 0) + assert res == 1 + + def test_byval_argument(self): + """ + struct Point { + long x; + long y; + }; + + DLLEXPORT long sum_point(struct Point p) { + return p.x + p.y; + } + """ + import _rawffi + from _ffi import CDLL, types + POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')]) + ffi_point = POINT.get_ffi_type() + libfoo = CDLL(self.libfoo_name) + sum_point = libfoo.getfunc('sum_point', [ffi_point], types.slong) + # + p = POINT() + p.x = 30 + p.y = 12 + res = sum_point(p) + assert res == 42 + p.free() + + def test_byval_result(self): + """ + DLLEXPORT struct Point make_point(long x, long y) { + struct Point p; + p.x = x; + p.y = y; + return p; + } + """ + import _rawffi + from _ffi import CDLL, types + POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')]) + ffi_point = POINT.get_ffi_type() + libfoo = CDLL(self.libfoo_name) + make_point = libfoo.getfunc('make_point', [types.slong, types.slong], ffi_point) + # + p = make_point(12, 34) + assert p.x == 12 + assert p.y == 34 + p.free() + def test_TypeError_numargs(self): from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) @@ -142,3 +444,10 @@ def test_OSError_loading(self): from _ffi import CDLL, types raises(OSError, "CDLL('I do not exist')") + + def test_AttributeError_missing_function(self): + from _ffi import CDLL, types + libfoo = CDLL(self.libfoo_name) + raises(AttributeError, "libfoo.getfunc('I_do_not_exist', [], types.void)") + libnone = CDLL(None) + raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)") diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -175,7 +175,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -119,7 +119,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -155,7 +155,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +181,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -3,6 +3,8 @@ from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir +UNICODE_REPLACEMENT_CHARACTER = u'\uFFFD' + class EncodeDecodeError(Exception): def __init__(self, start, end, reason): @@ -103,8 +105,12 @@ [DECODEBUF_P], rffi.SSIZE_T) pypy_cjk_dec_inbuf_consumed = llexternal('pypy_cjk_dec_inbuf_consumed', [DECODEBUF_P], rffi.SSIZE_T) +pypy_cjk_dec_replace_on_error = llexternal('pypy_cjk_dec_replace_on_error', + [DECODEBUF_P, rffi.CWCHARP, + rffi.SSIZE_T, rffi.SSIZE_T], + rffi.SSIZE_T) -def decode(codec, stringdata): +def decode(codec, stringdata, errors="strict", errorcb=None, namecb=None): inleft = len(stringdata) inbuf = rffi.get_nonmovingbuffer(stringdata) try: @@ -112,10 +118,12 @@ if not decodebuf: raise MemoryError try: - r = pypy_cjk_dec_chunk(decodebuf) - if r != 0: - multibytecodec_decerror(decodebuf, r) - assert False + while True: + r = pypy_cjk_dec_chunk(decodebuf) + if r == 0: + break + multibytecodec_decerror(decodebuf, r, errors, + errorcb, namecb, stringdata) src = pypy_cjk_dec_outbuf(decodebuf) length = pypy_cjk_dec_outlen(decodebuf) return rffi.wcharpsize2unicode(src, length) @@ -126,7 +134,8 @@ finally: rffi.free_nonmovingbuffer(stringdata, inbuf) -def multibytecodec_decerror(decodebuf, e): +def multibytecodec_decerror(decodebuf, e, errors, + errorcb, namecb, stringdata): if e > 0: reason = "illegal multibyte sequence" esize = e @@ -138,12 +147,27 @@ else: raise RuntimeError # - # if errors == ERROR_REPLACE:... - # if errors == ERROR_IGNORE or errors == ERROR_REPLACE:... + # compute the unicode to use as a replacement -> 'replace', and + # the current position in the input 'unicodedata' -> 'end' start = pypy_cjk_dec_inbuf_consumed(decodebuf) end = start + esize - if 1: # errors == ERROR_STRICT: + if errors == "strict": raise EncodeDecodeError(start, end, reason) + elif errors == "ignore": + replace = u"" + elif errors == "replace": + replace = UNICODE_REPLACEMENT_CHARACTER + else: + assert errorcb + replace, end = errorcb(errors, namecb, reason, + stringdata, start, end) + inbuf = rffi.get_nonmoving_unicodebuffer(replace) + try: + r = pypy_cjk_dec_replace_on_error(decodebuf, inbuf, len(replace), end) + finally: + rffi.free_nonmoving_unicodebuffer(replace, inbuf) + if r == MBERR_NOMEMORY: + raise MemoryError # ____________________________________________________________ # Encoding @@ -165,8 +189,12 @@ [ENCODEBUF_P], rffi.SSIZE_T) pypy_cjk_enc_inbuf_consumed = llexternal('pypy_cjk_enc_inbuf_consumed', [ENCODEBUF_P], rffi.SSIZE_T) +pypy_cjk_enc_replace_on_error = llexternal('pypy_cjk_enc_replace_on_error', + [ENCODEBUF_P, rffi.CCHARP, + rffi.SSIZE_T, rffi.SSIZE_T], + rffi.SSIZE_T) -def encode(codec, unicodedata): +def encode(codec, unicodedata, errors="strict", errorcb=None, namecb=None): inleft = len(unicodedata) inbuf = rffi.get_nonmoving_unicodebuffer(unicodedata) try: @@ -174,14 +202,18 @@ if not encodebuf: raise MemoryError try: - r = pypy_cjk_enc_chunk(encodebuf) - if r != 0: - multibytecodec_encerror(encodebuf, r) - assert False - r = pypy_cjk_enc_reset(encodebuf) - if r != 0: - multibytecodec_encerror(encodebuf, r) - assert False + while True: + r = pypy_cjk_enc_chunk(encodebuf) + if r == 0: + break + multibytecodec_encerror(encodebuf, r, errors, + codec, errorcb, namecb, unicodedata) + while True: + r = pypy_cjk_enc_reset(encodebuf) + if r == 0: + break + multibytecodec_encerror(encodebuf, r, errors, + codec, errorcb, namecb, unicodedata) src = pypy_cjk_enc_outbuf(encodebuf) length = pypy_cjk_enc_outlen(encodebuf) return rffi.charpsize2str(src, length) @@ -192,7 +224,8 @@ finally: rffi.free_nonmoving_unicodebuffer(unicodedata, inbuf) -def multibytecodec_encerror(encodebuf, e): +def multibytecodec_encerror(encodebuf, e, errors, + codec, errorcb, namecb, unicodedata): if e > 0: reason = "illegal multibyte sequence" esize = e @@ -204,9 +237,27 @@ else: raise RuntimeError # - # if errors == ERROR_REPLACE:... - # if errors == ERROR_IGNORE or errors == ERROR_REPLACE:... + # compute the string to use as a replacement -> 'replace', and + # the current position in the input 'unicodedata' -> 'end' start = pypy_cjk_enc_inbuf_consumed(encodebuf) end = start + esize - if 1: # errors == ERROR_STRICT: + if errors == "strict": raise EncodeDecodeError(start, end, reason) + elif errors == "ignore": + replace = "" + elif errors == "replace": + try: + replace = encode(codec, u"?") + except EncodeDecodeError: + replace = "?" + else: + assert errorcb + replace, end = errorcb(errors, namecb, reason, + unicodedata, start, end) + inbuf = rffi.get_nonmovingbuffer(replace) + try: + r = pypy_cjk_enc_replace_on_error(encodebuf, inbuf, len(replace), end) + finally: + rffi.free_nonmovingbuffer(replace, inbuf) + if r == MBERR_NOMEMORY: + raise MemoryError diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -3,6 +3,7 @@ from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs +from pypy.module._codecs.interp_codecs import CodecState class MultibyteCodec(Wrappable): @@ -13,13 +14,13 @@ @unwrap_spec(input=str, errors="str_or_None") def decode(self, space, input, errors=None): - if errors is not None and errors != 'strict': - raise OperationError(space.w_NotImplementedError, # XXX - space.wrap("errors='%s' in _multibytecodec" - % errors)) + if errors is None: + errors = 'strict' + state = space.fromcache(CodecState) # try: - output = c_codecs.decode(self.codec, input) + output = c_codecs.decode(self.codec, input, errors, + state.decode_error_handler, self.name) except c_codecs.EncodeDecodeError, e: raise OperationError( space.w_UnicodeDecodeError, @@ -37,13 +38,13 @@ @unwrap_spec(input=unicode, errors="str_or_None") def encode(self, space, input, errors=None): - if errors is not None and errors != 'strict': - raise OperationError(space.w_NotImplementedError, # XXX - space.wrap("errors='%s' in _multibytecodec" - % errors)) + if errors is None: + errors = 'strict' + state = space.fromcache(CodecState) # try: - output = c_codecs.encode(self.codec, input) + output = c_codecs.encode(self.codec, input, errors, + state.encode_error_handler, self.name) except c_codecs.EncodeDecodeError, e: raise OperationError( space.w_UnicodeEncodeError, diff --git a/pypy/module/_multibytecodec/test/test_app_codecs.py b/pypy/module/_multibytecodec/test/test_app_codecs.py --- a/pypy/module/_multibytecodec/test/test_app_codecs.py +++ b/pypy/module/_multibytecodec/test/test_app_codecs.py @@ -36,6 +36,37 @@ e = raises(UnicodeDecodeError, codec.decode, "~{xyz}").value assert e.args == ('hz', '~{xyz}', 2, 4, 'illegal multibyte sequence') + def test_decode_hz_ignore(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.decode("def~{}abc", errors='ignore') + assert r == (u'def\u5fcf', 9) + r = codec.decode("def~{}abc", 'ignore') + assert r == (u'def\u5fcf', 9) + + def test_decode_hz_replace(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.decode("def~{}abc", errors='replace') + assert r == (u'def\ufffd\u5fcf', 9) + r = codec.decode("def~{}abc", 'replace') + assert r == (u'def\ufffd\u5fcf', 9) + + def test_decode_custom_error_handler(self): + import codecs + codecs.register_error("test.decode_custom_error_handler", + lambda e: (u'\u1234\u5678', e.end)) + u = "abc\xDD".decode("hz", "test.decode_custom_error_handler") + assert u == u'abc\u1234\u5678' + + def test_decode_custom_error_handler_overflow(self): + import codecs + import sys + codecs.register_error("test.test_decode_custom_error_handler_overflow", + lambda e: (u'', sys.maxint + 1)) + raises((IndexError, OverflowError), "abc\xDD".decode, "hz", + "test.test_decode_custom_error_handler_overflow") + def test_encode_hz(self): import _codecs_cn codec = _codecs_cn.getcodec("hz") @@ -54,3 +85,24 @@ assert e.start == 3 assert e.end == 4 assert e.reason == 'illegal multibyte sequence' + + def test_encode_hz_ignore(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.encode(u'abc\u1234def', 'ignore') + assert r == ('abcdef', 7) + assert type(r[0]) is str + + def test_encode_hz_replace(self): + import _codecs_cn + codec = _codecs_cn.getcodec("hz") + r = codec.encode(u'abc\u1234def', 'replace') + assert r == ('abc?def', 7) + assert type(r[0]) is str + + def test_encode_custom_error_handler(self): + import codecs + codecs.register_error("test.multi_bad_handler", lambda e: (repl, 1)) + repl = u"\u2014" + s = u"\uDDA1".encode("gbk", "test.multi_bad_handler") + assert s == '\xA1\xAA' diff --git a/pypy/module/_multibytecodec/test/test_c_codecs.py b/pypy/module/_multibytecodec/test/test_c_codecs.py --- a/pypy/module/_multibytecodec/test/test_c_codecs.py +++ b/pypy/module/_multibytecodec/test/test_c_codecs.py @@ -36,6 +36,16 @@ assert e.end == 4 assert e.reason == "illegal multibyte sequence" +def test_decode_hz_ignore(): + c = getcodec("hz") + u = decode(c, 'def~{}abc', 'ignore') + assert u == u'def\u5fcf' + +def test_decode_hz_replace(): + c = getcodec("hz") + u = decode(c, 'def~{}abc', 'replace') + assert u == u'def\ufffd\u5fcf' + def test_encode_hz(): c = getcodec("hz") s = encode(c, u'foobar') @@ -51,6 +61,16 @@ assert e.end == 4 assert e.reason == "illegal multibyte sequence" +def test_encode_hz_ignore(): + c = getcodec("hz") + s = encode(c, u'abc\u1234def', 'ignore') + assert s == 'abcdef' + +def test_encode_hz_replace(): + c = getcodec("hz") + s = encode(c, u'abc\u1234def', 'replace') + assert s == 'abc?def' + def test_encode_jisx0208(): c = getcodec('iso2022_jp') s = encode(c, u'\u83ca\u5730\u6642\u592b') diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_multiprocessing/test/test_memory.py b/pypy/module/_multiprocessing/test/test_memory.py --- a/pypy/module/_multiprocessing/test/test_memory.py +++ b/pypy/module/_multiprocessing/test/test_memory.py @@ -3,7 +3,7 @@ class AppTestMemory: def setup_class(cls): space = gettestobjspace( - usemodules=('_multiprocessing', 'mmap', '_rawffi')) + usemodules=('_multiprocessing', 'mmap', '_rawffi', '_ffi')) cls.space = space def test_address_of(self): diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -176,7 +176,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + elif (_MS_WINDOWS and space.is_true(space.isinstance(w_name, space.w_int))): ordinal = space.int_w(w_name) @@ -250,11 +250,18 @@ def get_basic_ffi_type(self): raise NotImplementedError + def descr_get_ffi_type(self, space): + # XXX: this assumes that you have the _ffi module enabled. In the long + # term, probably we will move the code for build structures and arrays + # from _rawffi to _ffi + from pypy.module._ffi.interp_ffi import W_FFIType + return W_FFIType('', self.get_basic_ffi_type(), self) + @unwrap_spec(n=int) def descr_size_alignment(self, space, n=1): return space.newtuple([space.wrap(self.size * n), space.wrap(self.alignment)]) - + class W_DataInstance(Wrappable): def __init__(self, space, size, address=r_uint(0)): @@ -420,7 +427,7 @@ if not (argletter in TYPEMAP_PTR_LETTERS and letter in TYPEMAP_PTR_LETTERS): msg = "Argument %d should be typecode %s, got %s" - raise operationerrfmt(space.w_TypeError, msg, + raise operationerrfmt(space.w_TypeError, msg, i+1, argletter, letter) args_ll.append(arg.ll_buffer) # XXX we could avoid the intermediate list args_ll @@ -473,17 +480,25 @@ alignment = _create_new_accessor('alignment', 'c_alignment') @unwrap_spec(address=r_uint, maxlength=int) -def charp2string(space, address, maxlength=sys.maxint): +def charp2string(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.charp2strn(rffi.cast(rffi.CCHARP, address), maxlength) + charp_addr = rffi.cast(rffi.CCHARP, address) + if maxlength == -1: + s = rffi.charp2str(charp_addr) + else: + s = rffi.charp2strn(charp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) -def wcharp2unicode(space, address, maxlength=sys.maxint): +def wcharp2unicode(space, address, maxlength=-1): if address == 0: return space.w_None - s = rffi.wcharp2unicoden(rffi.cast(rffi.CWCHARP, address), maxlength) + wcharp_addr = rffi.cast(rffi.CWCHARP, address) + if maxlength == -1: + s = rffi.wcharp2unicode(wcharp_addr) + else: + s = rffi.wcharp2unicoden(wcharp_addr, maxlength) return space.wrap(s) @unwrap_spec(address=r_uint, maxlength=int) diff --git a/pypy/module/_rawffi/structure.py b/pypy/module/_rawffi/structure.py --- a/pypy/module/_rawffi/structure.py +++ b/pypy/module/_rawffi/structure.py @@ -248,7 +248,8 @@ alignment = interp_attrproperty('alignment', W_Structure), fieldoffset = interp2app(W_Structure.descr_fieldoffset), fieldsize = interp2app(W_Structure.descr_fieldsize), - size_alignment = interp2app(W_Structure.descr_size_alignment) + size_alignment = interp2app(W_Structure.descr_size_alignment), + get_ffi_type = interp2app(W_Structure.descr_get_ffi_type), ) W_Structure.typedef.acceptable_as_base_class = False diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,3 +1,4 @@ +from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable @@ -899,7 +900,7 @@ def _ssl_thread_id_function(): from pypy.module.thread import ll_thread - return rffi.cast(rffi.INT, ll_thread.get_ident()) + return rffi.cast(rffi.LONG, ll_thread.get_ident()) def setup_ssl_threads(): from pypy.module.thread import ll_thread diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -40,7 +40,7 @@ raise operationerrfmt( space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args diff --git a/pypy/module/_stackless/test/test_greenlet.py b/pypy/module/_stackless/test/test_greenlet.py --- a/pypy/module/_stackless/test/test_greenlet.py +++ b/pypy/module/_stackless/test/test_greenlet.py @@ -72,6 +72,23 @@ g1 = greenlet(f) raises(ValueError, g2.switch) + + def test_exc_info_save_restore(self): + from _stackless import greenlet + import sys + def f(): + try: + raise ValueError('fun') + except: + exc_info = sys.exc_info() + greenlet(h).switch() + assert exc_info == sys.exc_info() + + def h(): + assert sys.exc_info() == (None, None, None) + + greenlet(f).switch() + def test_exception(self): from _stackless import greenlet import sys diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -129,7 +129,7 @@ if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,21 @@ from __future__ import with_statement +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -37,7 +40,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -73,6 +76,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +100,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +163,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -268,12 +270,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -311,6 +311,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -319,12 +327,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -387,7 +390,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -395,7 +398,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -413,7 +416,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -515,26 +518,18 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() - s = ''.join([cbuf[i] for i in xrange(self.len * mytype.bytes)]) - return self.space.wrap(s) -## -## s = '' -## i = 0 -## while i < self.len * mytype.bytes: -## s += cbuf[i] -## i += 1 -## return self.space.wrap(s) + return self.space.wrap(rffi.charpsize2str(cbuf, self.len * mytype.bytes)) def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): if not isinstance(w_f, W_File): @@ -577,10 +572,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): @@ -623,6 +615,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) + return w_a + def array_byteswap__Array(space, self): if mytype.bytes not in [1, 2, 4, 8]: msg = "byteswap not supported for this array" diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -39,6 +39,7 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject +import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject import pypy.module.cpyext.longobject @@ -64,6 +65,7 @@ import pypy.module.cpyext.memoryobject import pypy.module.cpyext.codecs import pypy.module.cpyext.pyfile +import pypy.module.cpyext.pystrtod # now that all rffi_platform.Struct types are registered, configure them api.configure_types() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -348,6 +348,7 @@ '_Py_TrueStruct#': ('PyObject*', 'space.w_True'), '_Py_ZeroStruct#': ('PyObject*', 'space.w_False'), '_Py_NotImplementedStruct#': ('PyObject*', 'space.w_NotImplemented'), + '_Py_EllipsisObject#': ('PyObject*', 'space.w_Ellipsis'), 'PyDateTimeAPI': ('PyDateTime_CAPI*', 'None'), } FORWARD_DECLS = [] @@ -561,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -122,7 +122,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space, '?'))) + return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) @@ -151,7 +151,7 @@ def descr_method_repr(self): return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space, '?'))) + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/pystrtod.py @@ -0,0 +1,68 @@ +import errno +from pypy.interpreter.error import OperationError +from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.pyobject import PyObject +from pypy.rlib import rdtoa +from pypy.rlib import rfloat +from pypy.rlib import rposix +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi + + + at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +def PyOS_string_to_double(space, s, endptr, w_overflow_exception): + """Convert a string s to a double, raising a Python + exception on failure. The set of accepted strings corresponds to + the set of strings accepted by Python's float() constructor, + except that s must not have leading or trailing whitespace. + The conversion is independent of the current locale. + + If endptr is NULL, convert the whole string. Raise + ValueError and return -1.0 if the string is not a valid + representation of a floating-point number. + + If endptr is not NULL, convert as much of the string as + possible and set *endptr to point to the first unconverted + character. If no initial segment of the string is the valid + representation of a floating-point number, set *endptr to point + to the beginning of the string, raise ValueError, and return + -1.0. + + If s represents a value that is too large to store in a float + (for example, "1e500" is such a string on many platforms) then + if overflow_exception is NULL return Py_HUGE_VAL (with + an appropriate sign) and don't set any exception. Otherwise, + overflow_exception must point to a Python exception object; + raise that exception and return -1.0. In both cases, set + *endptr to point to the first character after the converted value. + + If any other error occurs during the conversion (for example an + out-of-memory error), set the appropriate Python exception and + return -1.0. + """ + user_endptr = True + try: + if not endptr: + endptr = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + user_endptr = False + result = rdtoa.dg_strtod(s, endptr) + endpos = (rffi.cast(rffi.LONG, endptr[0]) - + rffi.cast(rffi.LONG, s)) + if endpos == 0 or (not user_endptr and not endptr[0][0] == '\0'): + raise OperationError( + space.w_ValueError, + space.wrap('invalid input at position %s' % endpos)) + if rposix.get_errno() == errno.ERANGE: + rposix.set_errno(0) + if w_overflow_exception is None: + if result > 0: + return rfloat.INFINITY + else: + return -rfloat.INFINITY + else: + raise OperationError(w_overflow_exception, + space.wrap('value too large')) + return result + finally: + if not user_endptr: + lltype.free(endptr, flavor='raw') diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/setobject.py @@ -0,0 +1,46 @@ +from pypy.interpreter.error import OperationError +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, + build_type_checkers) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, + borrow_from, make_ref, from_ref) +from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall +from pypy.objspace.std.setobject import W_SetObject, newset +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject + + +PySet_Check, PySet_CheckExact = build_type_checkers("Set") + + + at cpython_api([PyObject], PyObject) +def PySet_New(space, w_iterable): + if w_iterable is None: + return space.call_function(space.w_set) + else: + return space.call_function(space.w_set, w_iterable) + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Add(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'add', w_obj) + return 0 + + at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) +def PySet_Discard(space, w_s, w_obj): + if not PySet_Check(space, w_s): + PyErr_BadInternalCall(space) + space.call_method(w_s, 'discard', w_obj) + return 0 + + + at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +def PySet_GET_SIZE(space, w_s): + return space.int_w(space.len(w_s)) + + at cpython_api([PyObject], Py_ssize_t, error=-1) +def PySet_Size(space, ref): + if not PySet_Check(space, ref): + raise OperationError(space.w_TypeError, + space.wrap("expected set object")) + return PySet_GET_SIZE(space, ref) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -480,39 +480,6 @@ """Create a new Python complex number object from a C Py_complex value.""" raise NotImplementedError - at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) -def PyOS_string_to_double(space, s, endptr, overflow_exception): - """Convert a string s to a double, raising a Python - exception on failure. The set of accepted strings corresponds to - the set of strings accepted by Python's float() constructor, - except that s must not have leading or trailing whitespace. - The conversion is independent of the current locale. - - If endptr is NULL, convert the whole string. Raise - ValueError and return -1.0 if the string is not a valid - representation of a floating-point number. - - If endptr is not NULL, convert as much of the string as - possible and set *endptr to point to the first unconverted - character. If no initial segment of the string is the valid - representation of a floating-point number, set *endptr to point - to the beginning of the string, raise ValueError, and return - -1.0. - - If s represents a value that is too large to store in a float - (for example, "1e500" is such a string on many platforms) then - if overflow_exception is NULL return Py_HUGE_VAL (with - an appropriate sign) and don't set any exception. Otherwise, - overflow_exception must point to a Python exception object; - raise that exception and return -1.0. In both cases, set - *endptr to point to the first character after the converted value. - - If any other error occurs during the conversion (for example an - out-of-memory error), set the appropriate Python exception and - return -1.0. - """ - raise NotImplementedError - @cpython_api([rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, error=CANNOT_FAIL) def PyOS_ascii_strtod(space, nptr, endptr): """Convert a string to a double. This function behaves like the Standard C diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -0,0 +1,93 @@ +import math + +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype + + +class TestPyOS_string_to_double(BaseApiTest): + + def test_simple_float(self, api): + s = rffi.str2charp('0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == 0.4 + rffi.free_charp(s) + + def test_empty_string(self, api): + s = rffi.str2charp('') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_bad_string(self, api): + s = rffi.str2charp(' 0.4') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_overflow_pos(self, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r > 0 + rffi.free_charp(s) + + def test_overflow_neg(self, api): + s = rffi.str2charp('-1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, None) + assert math.isinf(r) + assert r < 0 + rffi.free_charp(s) + + def test_overflow_exc(self, space, api): + s = rffi.str2charp('1e500') + null = lltype.nullptr(rffi.CCHARPP.TO) + r = api.PyOS_string_to_double(s, null, space.w_ValueError) + assert r == -1.0 + raises(ValueError) + api.PyErr_Clear() + rffi.free_charp(s) + + def test_endptr_number(self, api): + s = rffi.str2charp('0.4') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_tail(self, api): + s = rffi.str2charp('0.4 foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == 0.4 + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + 3 + rffi.free_charp(s) + lltype.free(endp, flavor='raw') + + def test_endptr_no_conversion(self, api): + s = rffi.str2charp('foo') + endp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + r = api.PyOS_string_to_double(s, endp, None) + assert r == -1.0 + raises(ValueError) + endp_addr = rffi.cast(rffi.LONG, endp[0]) + s_addr = rffi.cast(rffi.LONG, s) + assert endp_addr == s_addr + api.PyErr_Clear() + rffi.free_charp(s) + lltype.free(endp, flavor='raw') diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_setobject.py @@ -0,0 +1,29 @@ +import py + +from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.conftest import gettestobjspace + + +class TestTupleObject(BaseApiTest): + def test_setobj(self, space, api): + assert not api.PySet_Check(space.w_None) + assert api.PySet_Add(space.w_None, space.w_None) == -1 + api.PyErr_Clear() + w_set = space.call_function(space.w_set) + space.call_method(w_set, 'update', space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + assert api.PySet_GET_SIZE(w_set) == 4 + raises(TypeError, api.PySet_Size(space.newlist([]))) + api.PyErr_Clear() + + def test_set_add_discard(self, space, api): + w_set = api.PySet_New(None) + assert api.PySet_Size(w_set) == 0 + w_set = api.PySet_New(space.wrap([1,2,3,4])) + assert api.PySet_Size(w_set) == 4 + api.PySet_Add(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 5 + api.PySet_Discard(w_set, space.wrap(6)) + assert api.PySet_Size(w_set) == 4 diff --git a/pypy/module/cpyext/test/test_sliceobject.py b/pypy/module/cpyext/test/test_sliceobject.py --- a/pypy/module/cpyext/test/test_sliceobject.py +++ b/pypy/module/cpyext/test/test_sliceobject.py @@ -67,3 +67,14 @@ """), ]) assert module.nullslice() == slice(None, None, None) + + def test_ellipsis(self): + module = self.import_extension('foo', [ + ("get_ellipsis", "METH_NOARGS", + """ + PyObject *ret = Py_Ellipsis; + Py_INCREF(ret); + return ret; + """), + ]) + assert module.get_ellipsis() is Ellipsis diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -367,3 +367,14 @@ data, len(u), lltype.nullptr(rffi.CCHARP.TO)) rffi.free_wcharp(data) + def test_format(self, space, api): + w_format = space.wrap(u'hi %s') + w_args = space.wrap((u'test',)) + w_formated = api.PyUnicode_Format(w_format, w_args) + assert space.unwrap(w_formated) == space.unwrap(space.mod(w_format, w_args)) + + def test_join(self, space, api): + w_sep = space.wrap(u'') + w_seq = space.wrap([u'a', u'b']) + w_joined = api.PyUnicode_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == u'ab' diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,6 +7,7 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) + assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -450,7 +450,7 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?")) + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -523,3 +523,11 @@ copies sizeof(Py_UNICODE) * length bytes from source to target""" for i in range(0, length): target[i] = source[i] + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Format(space, w_format, w_args): + return space.mod(w_format, w_args) + + at cpython_api([PyObject, PyObject], PyObject) +def PyUnicode_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -21,6 +21,10 @@ """Return the referenced object from a weak reference. If the referent is no longer live, returns None. This function returns a borrowed reference. """ + return PyWeakref_GET_OBJECT(space, w_ref) + + at cpython_api([PyObject], PyObject) +def PyWeakref_GET_OBJECT(space, w_ref): return borrow_from(w_ref, space.call_function(w_ref)) @cpython_api([PyObject], PyObject) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -136,7 +136,7 @@ args_repr = space.str_w(space.repr(space.newtuple(self.args_w))) else: args_repr = "()" - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) def descr_getargs(self, space): @@ -546,7 +546,7 @@ w_tuple = space.newtuple(values_w + [self.w_lastlineno]) args_w = [self.args_w[0], w_tuple] args_repr = space.str_w(space.repr(space.newtuple(args_w))) - clsname = self.getclass(space).getname(space, '?') + clsname = self.getclass(space).getname(space) return space.wrap(clsname + args_repr) else: return W_StandardError.descr_repr(self, space) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -120,7 +120,7 @@ def check_sys_modules_w(space, modulename): return space.finditem_str(space.sys.get('modules'), modulename) - at jit.purefunction + at jit.elidable def _get_dot_position(str, n): # return the index in str of the '.' such that there are n '.'-separated # strings after it @@ -133,8 +133,8 @@ def _get_relative_name(space, modulename, level, w_globals): w = space.wrap ctxt_w_package = space.finditem_str(w_globals, '__package__') - ctxt_w_package = jit.hint(ctxt_w_package, promote=True) - level = jit.hint(level, promote=True) + ctxt_w_package = jit.promote(ctxt_w_package) + level = jit.promote(level) ctxt_package = None if ctxt_w_package is not None and ctxt_w_package is not space.w_None: @@ -184,7 +184,7 @@ ctxt_w_name = space.finditem_str(w_globals, '__name__') ctxt_w_path = space.finditem_str(w_globals, '__path__') - ctxt_w_name = jit.hint(ctxt_w_name, promote=True) + ctxt_w_name = jit.promote(ctxt_w_name) ctxt_name = None if ctxt_w_name is not None: try: @@ -622,7 +622,13 @@ try: if find_info: w_mod = load_module(space, w_modulename, find_info) - w_mod = space.getitem(space.sys.get("modules"), w_modulename) + try: + w_mod = space.getitem(space.sys.get("modules"), + w_modulename) + except OperationError, oe: + if not oe.match(space, space.w_KeyError): + raise + raise OperationError(space.w_ImportError, w_modulename) if w_parent is not None: space.setattr(w_parent, space.wrap(partname), w_mod) return w_mod @@ -793,14 +799,13 @@ """ -# XXX picking a magic number is a mess. So far it works because we -# have only two extra opcodes, which bump the magic number by +1 and -# +2 respectively, and CPython leaves a gap of 10 when it increases +# picking a magic number is a mess. So far it works because we +# have only one extra opcode, which bumps the magic number by +2, and CPython +# leaves a gap of 10 when it increases # its own magic number. To avoid assigning exactly the same numbers # as CPython we always add a +2. We'll have to think again when we -# get at the fourth new opcode :-( +# get three more new opcodes # -# * CALL_LIKELY_BUILTIN +1 # * CALL_METHOD +2 # # In other words: @@ -823,8 +828,6 @@ return struct.unpack('= 0") + res = 1 + for i in range(1, x + 1): + res *= i + return res diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -373,22 +373,6 @@ hi = v return space.wrap(hi) -def factorial(space, w_x): - """Find x!.""" - if space.isinstance_w(w_x, space.w_float): - fl = space.float_w(w_x) - if math.floor(fl) != fl: - raise OperationError(space.w_ValueError, - space.wrap("float arguments must be integral")) - w_x = space.long(w_x) - x = space.int_w(w_x) - if x < 0: - raise OperationError(space.w_ValueError, space.wrap("x must be >= 0")) - w_res = space.wrap(1) - for i in range(1, x + 1): - w_res = space.mul(w_res, space.wrap(i)) - return w_res - def log1p(space, w_x): """Find log(x + 1).""" return math1(space, rfloat.log1p, w_x) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -8,11 +8,16 @@ interpleveldefs = { 'array': 'interp_numarray.SingleDimArray', 'zeros': 'interp_numarray.zeros', + 'empty': 'interp_numarray.zeros', + 'ones': 'interp_numarray.ones', + 'fromstring': 'interp_support.fromstring', # ufuncs + 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', 'copysign': 'interp_ufuncs.copysign', 'exp': 'interp_ufuncs.exp', + 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', 'negative': 'interp_ufuncs.negative', @@ -20,4 +25,7 @@ 'sign': 'interp_ufuncs.sign', } - appleveldefs = {} + appleveldefs = { + 'average': 'app_numpy.average', + 'mean': 'app_numpy.mean', + } diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/app_numpy.py @@ -0,0 +1,11 @@ +import numpy + +def average(a): + # This implements a weighted average, for now we don't implement the + # weighting, just the average part! + return mean(a) + +def mean(a): + if not hasattr(a, "mean"): + a = numpy.array(a) + return a.mean() \ No newline at end of file diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/compile.py @@ -0,0 +1,54 @@ + +""" This is a set of tools for standalone compiling of numpy expressions. +It should not be imported by the module itself +""" + +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray + +class BogusBytecode(Exception): + pass + +def create_array(size): + a = SingleDimArray(size) + for i in range(size): + a.storage[i] = float(i % 10) + return a + +class TrivialSpace(object): + def wrap(self, x): + return x + +def numpy_compile(bytecode, array_size): + space = TrivialSpace() + stack = [] + i = 0 + for b in bytecode: + if b == 'a': + stack.append(create_array(array_size)) + i += 1 + elif b == 'f': + stack.append(FloatWrapper(1.2)) + elif b == '+': + right = stack.pop() + stack.append(stack.pop().descr_add(space, right)) + elif b == '-': + right = stack.pop() + stack.append(stack.pop().descr_sub(space, right)) + elif b == '*': + right = stack.pop() + stack.append(stack.pop().descr_mul(space, right)) + elif b == '/': + right = stack.pop() + stack.append(stack.pop().descr_div(space, right)) + elif b == '%': + right = stack.pop() + stack.append(stack.pop().descr_mod(space, right)) + elif b == '|': + stack.append(stack.pop().descr_abs(space)) + else: + print "Unknown opcode: %s" % b + raise BogusBytecode() + if len(stack) != 1: + print "Bogus bytecode, uneven stack length" + raise BogusBytecode() + return stack[0] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,10 +1,11 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.error import operationerrfmt, OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name +import math def dummy1(v): @@ -19,6 +20,8 @@ numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) +all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) class Signature(object): def __init__(self): @@ -30,6 +33,12 @@ self.transitions[target] = new = Signature() return new +def pos(v): + return v +def neg(v): + return -v +def absolute(v): + return abs(v) def add(v1, v2): return v1 + v2 def sub(v1, v2): @@ -38,15 +47,43 @@ return v1 * v2 def div(v1, v2): return v1 / v2 +def power(v1, v2): + return math.pow(v1, v2) +def mod(v1, v2): + return math.fmod(v1, v2) +def maximum(v1, v2): + return max(v1, v2) +def minimum(v1, v2): + return min(v1, v2) class BaseArray(Wrappable): def __init__(self): self.invalidates = [] def invalidated(self): + if self.invalidates: + self._invalidated() + + def _invalidated(self): for arr in self.invalidates: arr.force_if_needed() - self.invalidates = [] + del self.invalidates[:] + + def _unop_impl(function): + signature = Signature() + def impl(self, space): + new_sig = self.signature.transition(signature) + res = Call1( + function, + self, + new_sig) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + + descr_pos = _unop_impl(pos) + descr_neg = _unop_impl(neg) + descr_abs = _unop_impl(absolute) def _binop_impl(function): signature = Signature() @@ -76,22 +113,164 @@ descr_sub = _binop_impl(sub) descr_mul = _binop_impl(mul) descr_div = _binop_impl(div) + descr_pow = _binop_impl(power) + descr_mod = _binop_impl(mod) + + def _binop_right_impl(function): + signature = Signature() + def impl(self, space, w_other): + new_sig = self.signature.transition(signature) + w_other = FloatWrapper(space.float_w(w_other)) + res = Call2( + function, + w_other, + self, + new_sig.transition(w_other.signature) + ) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, + "binop_right_%s_impl" % function.__name__) + + descr_radd = _binop_right_impl(add) + descr_rsub = _binop_right_impl(sub) + descr_rmul = _binop_right_impl(mul) + descr_rdiv = _binop_right_impl(div) + descr_rpow = _binop_right_impl(power) + descr_rmod = _binop_right_impl(mod) + + def _reduce_sum_prod_impl(function, init): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + return space.wrap(loop(self, init, self.find_size())) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_max_min_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, result, size): + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, self.eval(0), size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_argmax_argmin_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self', 'cur_best']) + def loop(self, size): + result = 0 + cur_best = self.eval(0) + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result, cur_best=cur_best) + new_best = function(cur_best, self.eval(i)) + if new_best != cur_best: + result = i + cur_best = new_best + i += 1 + return result + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, size)) + return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) + + def _all(self): + size = self.find_size() + i = 0 + while i < size: + all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if not self.eval(i): + return False + i += 1 + return True + def descr_all(self, space): + return space.wrap(self._all()) + + def _any(self): + size = self.find_size() + i = 0 + while i < size: + any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if self.eval(i): + return True + i += 1 + return False + def descr_any(self, space): + return space.wrap(self._any()) + + descr_sum = _reduce_sum_prod_impl(add, 0.0) + descr_prod = _reduce_sum_prod_impl(mul, 1.0) + descr_max = _reduce_max_min_impl(maximum) + descr_min = _reduce_max_min_impl(minimum) + descr_argmax = _reduce_argmax_argmin_impl(maximum) + descr_argmin = _reduce_argmax_argmin_impl(minimum) + + def descr_dot(self, space, w_other): + if isinstance(w_other, BaseArray): + w_res = self.descr_mul(space, w_other) + assert isinstance(w_res, BaseArray) + return w_res.descr_sum(space) + else: + return self.descr_mul(space, w_other) def get_concrete(self): raise NotImplementedError + def descr_get_shape(self, space): + return space.newtuple([self.descr_len(space)]) + def descr_len(self, space): return self.get_concrete().descr_len(space) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - return self.get_concrete().descr_getitem(space, item) + def descr_getitem(self, space, w_idx): + # TODO: indexing by tuples + start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) + if step == 0: + # Single index + return space.wrap(self.get_concrete().getitem(start)) + else: + # Slice + res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) + return space.wrap(res) @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): self.invalidated() return self.get_concrete().descr_setitem(space, item, value) + def descr_mean(self, space): + return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) class FloatWrapper(BaseArray): """ @@ -119,6 +298,10 @@ self.forced_result = None self.signature = signature + def _del_sources(self): + # Function for deleting references to source arrays, to allow garbage-collecting them + raise NotImplementedError + def compute(self): i = 0 signature = self.signature @@ -135,6 +318,7 @@ def force_if_needed(self): if self.forced_result is None: self.forced_result = self.compute() + self._del_sources() def get_concrete(self): self.force_if_needed() @@ -145,6 +329,13 @@ return self.forced_result.eval(i) return self._eval(i) + def find_size(self): + if self.forced_result is not None: + # The result has been computed and sources may be unavailable + return self.forced_result.find_size() + return self._find_size() + + class Call1(VirtualArray): _immutable_fields_ = ["function", "values"] @@ -153,7 +344,10 @@ self.function = function self.values = values - def find_size(self): + def _del_sources(self): + self.values = None + + def _find_size(self): return self.values.find_size() def _eval(self, i): @@ -164,13 +358,18 @@ Intermediate class for performing binary operations. """ _immutable_fields_ = ["function", "left", "right"] + def __init__(self, function, left, right, signature): VirtualArray.__init__(self, signature) self.function = function self.left = left self.right = right - def find_size(self): + def _del_sources(self): + self.left = None + self.right = None + + def _find_size(self): try: return self.left.find_size() except ValueError: @@ -181,6 +380,58 @@ lhs, rhs = self.left.eval(i), self.right.eval(i) return self.function(lhs, rhs) +class ViewArray(BaseArray): + """ + Class for representing views of arrays, they will reflect changes of parent + arrays. Example: slices + """ + _immutable_fields_ = ["parent"] + + def __init__(self, parent, signature): + BaseArray.__init__(self) + self.signature = signature + self.parent = parent + self.invalidates = parent.invalidates + + def get_concrete(self): + # in fact, ViewArray never gets "concrete" as it never stores data. + # This implementation is needed for BaseArray getitem/setitem to work, + # can be refactored. + return self + + def eval(self, i): + return self.parent.eval(self.calc_index(i)) + + def getitem(self, item): + return self.parent.getitem(self.calc_index(item)) + + @unwrap_spec(item=int, value=float) + def descr_setitem(self, space, item, value): + return self.parent.descr_setitem(space, self.calc_index(item), value) + + def descr_len(self, space): + return space.wrap(self.find_size()) + + def calc_index(self, item): + raise NotImplementedError + +class SingleDimSlice(ViewArray): + _immutable_fields_ = ["start", "stop", "step", "size"] + static_signature = Signature() + + def __init__(self, start, stop, step, slice_length, parent, signature): + ViewArray.__init__(self, parent, signature) + self.start = start + self.stop = stop + self.step = step + self.size = slice_length + + def find_size(self): + return self.size + + def calc_index(self, item): + return (self.start + item * self.step) + class SingleDimArray(BaseArray): signature = Signature() @@ -215,10 +466,8 @@ def descr_len(self, space): return space.wrap(self.size) - @unwrap_spec(item=int) - def descr_getitem(self, space, item): - item = self.getindex(space, item) - return space.wrap(self.storage[item]) + def getitem(self, item): + return self.storage[item] @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): @@ -238,20 +487,51 @@ i += 1 return space.wrap(arr) - at unwrap_spec(ObjSpace, int) + at unwrap_spec(size=int) def zeros(space, size): return space.wrap(SingleDimArray(size)) + at unwrap_spec(size=int) +def ones(space, size): + arr = SingleDimArray(size) + for i in xrange(size): + arr.storage[i] = 1.0 + return space.wrap(arr) BaseArray.typedef = TypeDef( 'numarray', __new__ = interp2app(descr_new_numarray), + + shape = GetSetProperty(BaseArray.descr_get_shape), + __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), __setitem__ = interp2app(BaseArray.descr_setitem), + __pos__ = interp2app(BaseArray.descr_pos), + __neg__ = interp2app(BaseArray.descr_neg), + __abs__ = interp2app(BaseArray.descr_abs), __add__ = interp2app(BaseArray.descr_add), __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), __div__ = interp2app(BaseArray.descr_div), -) \ No newline at end of file + __pow__ = interp2app(BaseArray.descr_pow), + __mod__ = interp2app(BaseArray.descr_mod), + __radd__ = interp2app(BaseArray.descr_radd), + __rsub__ = interp2app(BaseArray.descr_rsub), + __rmul__ = interp2app(BaseArray.descr_rmul), + __rdiv__ = interp2app(BaseArray.descr_rdiv), + __rpow__ = interp2app(BaseArray.descr_rpow), + __rmod__ = interp2app(BaseArray.descr_rmod), + + mean = interp2app(BaseArray.descr_mean), + sum = interp2app(BaseArray.descr_sum), + prod = interp2app(BaseArray.descr_prod), + max = interp2app(BaseArray.descr_max), + min = interp2app(BaseArray.descr_min), + argmax = interp2app(BaseArray.descr_argmax), + argmin = interp2app(BaseArray.descr_argmin), + all = interp2app(BaseArray.descr_all), + any = interp2app(BaseArray.descr_any), + dot = interp2app(BaseArray.descr_dot), +) diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_support.py @@ -0,0 +1,32 @@ + +from pypy.rlib.rstruct.runpack import runpack +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.error import OperationError +from pypy.module.micronumpy.interp_numarray import SingleDimArray + +FLOAT_SIZE = rffi.sizeof(lltype.Float) + + at unwrap_spec(s=str) +def fromstring(space, s): + length = len(s) + + if length % FLOAT_SIZE == 0: + number = length/FLOAT_SIZE + else: + raise OperationError(space.w_ValueError, space.wrap( + "string length %d not divisable by %d" % (length, FLOAT_SIZE))) + + a = SingleDimArray(number) + + start = 0 + end = FLOAT_SIZE + i = 0 + while i < number: + part = s[start:end] + a.storage[i] = runpack('d', part) + i += 1 + start += FLOAT_SIZE + end += FLOAT_SIZE + + return space.wrap(a) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -8,22 +8,24 @@ def ufunc(func): signature = Signature() - @unwrap_spec(array=BaseArray) - def impl(space, array): - w_res = Call1(func, array, array.signature.transition(signature)) - array.invalidates.append(w_res) - return w_res + def impl(space, w_obj): + if isinstance(w_obj, BaseArray): + w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) + w_obj.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() - @unwrap_spec(larray=BaseArray, rarray=BaseArray) - def impl(space, larray, rarray): - new_sig = larray.signature.transition(signature).transition(rarray.signature) - w_res = Call2(func, larray, rarray, new_sig) - larray.invalidates.append(w_res) - rarray.invalidates.append(w_res) - return w_res + def impl(space, w_lhs, w_rhs): + if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): + new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) + w_res = Call2(func, w_lhs, w_rhs, new_sig) + w_lhs.invalidates.append(w_res) + w_rhs.invalidates.append(w_res) + return w_res + return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @ufunc @@ -60,6 +62,10 @@ return 1.0 / value @ufunc +def floor(value): + return math.floor(value) + + at ufunc def sign(value): if value == 0.0: return 0.0 diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -16,4 +16,14 @@ v3 = ar.descr_add(space, FloatWrapper(1.0)) assert v2.signature is v3.signature v4 = ar.descr_add(space, ar) - assert v1.signature is v4.signature \ No newline at end of file + assert v1.signature is v4.signature + + def test_slice_signature(self, space): + ar = SingleDimArray(10) + v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1))) + v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1))) + assert v1.signature is v2.signature + + v3 = ar.descr_add(space, v1) + v4 = ar.descr_add(space, v2) + assert v3.signature is v4.signature \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_module.py b/pypy/module/micronumpy/test/test_module.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_module.py @@ -0,0 +1,13 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + + +class AppTestNumPyModule(BaseNumpyAppTest): + def test_mean(self): + from numpy import array, mean + assert mean(array(range(5))) == 2.0 + assert mean(range(5)) == 2.0 + + def test_average(self): + from numpy import array, average + assert average(range(10)) == 4.5 + assert average(array(range(10))) == 4.5 \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1,6 +1,7 @@ import py from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest +from pypy.conftest import gettestobjspace class AppTestNumArray(BaseNumpyAppTest): @@ -18,6 +19,25 @@ a[13] = 5.3 assert a[13] == 5.3 + def test_empty(self): + """ + Test that empty() works. + """ + + from numpy import empty + a = empty(2) + a[1] = 1.0 + assert a[1] == 1.0 + + def test_ones(self): + from numpy import ones + a = ones(3) + assert len(a) == 3 + assert a[0] == 1 + raises(IndexError, "a[3]") + a[2] = 4 + assert a[2] == 4 + def test_iterator_init(self): from numpy import array a = array(range(5)) @@ -46,6 +66,15 @@ assert len(a) == 5 assert len(a + a) == 5 + def test_shape(self): + from numpy import array + a = array(range(5)) + assert a.shape == (5,) + b = a + a + assert b.shape == (5,) + c = a[:3] + assert c.shape == (3,) + def test_add(self): from numpy import array a = array(range(5)) @@ -126,6 +155,72 @@ for i in range(5): assert b[i] == i / 5.0 + def test_pow(self): + from numpy import array + a = array(range(5)) + b = a ** a + for i in range(5): + print b[i], i**i + assert b[i] == i**i + + def test_pow_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a ** b + for i in range(5): + assert c[i] == i ** 2 + + def test_pow_constant(self): + from numpy import array + a = array(range(5)) + b = a ** 2 + for i in range(5): + assert b[i] == i ** 2 + + def test_mod(self): + from numpy import array + a = array(range(1,6)) + b = a % a + for i in range(5): + assert b[i] == 0 + + def test_mod_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a % b + for i in range(5): + assert c[i] == i % 2 + + def test_mod_constant(self): + from numpy import array + a = array(range(5)) + b = a % 2 + for i in range(5): + assert b[i] == i % 2 + + def test_pos(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = +a + for i in range(5): + assert b[i] == a[i] + + def test_neg(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = -a + for i in range(5): + assert b[i] == -a[i] + + def test_abs(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = abs(a) + for i in range(5): + assert b[i] == abs(a[i]) + def test_auto_force(self): from numpy import array a = array(range(5)) @@ -138,4 +233,141 @@ b = a + a c = b + b b[1] = 5 - assert c[1] == 4 \ No newline at end of file + assert c[1] == 4 + + def test_getslice(self): + from numpy import array + a = array(range(5)) + s = a[1:5] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[i+1] + + def test_getslice_step(self): + from numpy import array + a = array(range(10)) + s = a[1:9:2] + assert len(s) == 4 + for i in range(4): + assert s[i] == a[2*i+1] + + def test_slice_update(self): + from numpy import array + a = array(range(5)) + s = a[0:3] + s[1] = 10 + assert a[1] == 10 + a[2] = 20 + assert s[2] == 20 + + + def test_slice_invaidate(self): + # check that slice shares invalidation list with + from numpy import array + a = array(range(5)) + s = a[0:2] + b = array([10,11]) + c = s + b + a[0] = 100 + assert c[0] == 10 + assert c[1] == 12 + d = s + b + a[1] = 101 + assert d[0] == 110 + assert d[1] == 12 + + def test_mean(self): + from numpy import array + a = array(range(5)) + assert a.mean() == 2.0 + assert a[:4].mean() == 1.5 + + def test_sum(self): + from numpy import array + a = array(range(5)) + assert a.sum() == 10.0 + assert a[:4].sum() == 6.0 + + def test_prod(self): + from numpy import array + a = array(range(1,6)) + assert a.prod() == 120.0 + assert a[:4].prod() == 24.0 + + def test_max(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.max() == 5.7 + b = array([]) + raises(ValueError, "b.max()") + + def test_max_add(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert (a+a).max() == 11.4 + + def test_min(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.min() == -3.0 + b = array([]) + raises(ValueError, "b.min()") + + def test_argmax(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmax() == 2 + b = array([]) + raises(ValueError, "b.argmax()") + + def test_argmin(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmin() == 3 + b = array([]) + raises(ValueError, "b.argmin()") + + def test_all(self): + from numpy import array + a = array(range(5)) + assert a.all() == False + a[0] = 3.0 + assert a.all() == True + b = array([]) + assert b.all() == True + + def test_any(self): + from numpy import array, zeros + a = array(range(5)) + assert a.any() == True + b = zeros(5) + assert b.any() == False + c = array([]) + assert c.any() == False + + def test_dot(self): + from numpy import array + a = array(range(5)) + assert a.dot(a) == 30.0 + + def test_dot_constant(self): + from numpy import array + a = array(range(5)) + b = a.dot(2.5) + for i in xrange(5): + assert b[i] == 2.5*a[i] + + +class AppTestSupport(object): + def setup_class(cls): + import struct + cls.space = gettestobjspace(usemodules=('micronumpy',)) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + + def test_fromstring(self): + from numpy import fromstring + a = fromstring(self.data) + for i in range(4): + assert a[i] == i + 1 + raises(ValueError, fromstring, "abc") + diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -3,6 +3,13 @@ class AppTestUfuncs(BaseNumpyAppTest): + def test_single_item(self): + from numpy import negative, sign, minimum + + assert negative(5.0) == -5.0 + assert sign(-0.0) == 0.0 + assert minimum(2.0, 3.0) == 2.0 + def test_negative(self): from numpy import array, negative @@ -60,6 +67,15 @@ for i in range(4): assert b[i] == reference[i] + def test_floor(self): + from numpy import array, floor + + reference = [-2.0, -1.0, 0.0, 1.0, 1.0] + a = array([-1.4, -1.0, 0.0, 1.0, 1.4]) + b = floor(a) + for i in range(5): + assert b[i] == reference[i] + def test_copysign(self): from numpy import array, copysign diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,19 +1,22 @@ from pypy.jit.metainterp.test.support import LLJitMixin +from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call1, Call2, add, mul) + FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative - +from pypy.module.micronumpy.compile import numpy_compile +from pypy.rlib.objectmodel import specialize class FakeSpace(object): - pass + w_ValueError = None + @specialize.argtype(1) + def wrap(self, v): + return v class TestNumpyJIt(LLJitMixin): def setup_class(cls): cls.space = FakeSpace() def test_add(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, ar, Signature()) @@ -26,8 +29,6 @@ assert result == f(5) def test_floatadd(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, FloatWrapper(4.5), Signature()) @@ -39,11 +40,128 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_already_forecd(self): + def test_neg(self): space = self.space def f(i): ar = SingleDimArray(i) + v = Call1(neg, ar, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, + "setarrayitem_raw": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + + assert result == f(5) + + def test_sum(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_sum(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 2, + "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_prod(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_prod(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_max(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_max(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_gt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, + "guard_false": 1, "jump": 1}) + + def test_min(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_min(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_argmin(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_argmin(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_all(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = 1.0 + j += 1 + return ar.descr_add(space, ar).descr_all(space) + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, + "int_lt": 1, "guard_true": 2, "jump": 1}) + + def test_any(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_any(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, "guard_false": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + + def test_already_forecd(self): + def f(i): + ar = SingleDimArray(i) v1 = Call2(add, ar, FloatWrapper(4.5), Signature()) v2 = Call2(mul, v1, FloatWrapper(4.5), Signature()) v1.force_if_needed() @@ -91,4 +209,50 @@ self.meta_interp(f, [5], listops=True, backendopt=True) # This is 3, not 2 because there is a bridge for the exit. - self.check_loop_count(3) \ No newline at end of file + self.check_loop_count(3) + + def test_slice(self): + def f(i): + step = 3 + ar = SingleDimArray(step*i) + s = SingleDimSlice(0, step*i, step, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s, s, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 1, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + + def test_slice2(self): + def f(i): + step1 = 2 + step2 = 3 + ar = SingleDimArray(step2*i) + s1 = SingleDimSlice(0, step1*i, step1, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + s2 = SingleDimSlice(0, step2*i, step2, i, ar, ar.signature.transition(SingleDimSlice.static_signature)) + v = Call2(add, s1, s2, Signature()) + return v.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'int_mul': 2, 'getarrayitem_raw': 2, 'float_add': 1, + 'setarrayitem_raw': 1, 'int_add': 1, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == f(5) + +class TestTranslation(object): + def test_compile(self): + x = numpy_compile('aa+f*f/a-', 10) + x = x.compute() + assert isinstance(x, SingleDimArray) + assert x.size == 10 + assert x.storage[0] == 0 + assert x.storage[1] == ((1 + 1) * 1.2) / 1.2 - 1 + + def test_translation(self): + # we import main to check if the target compiles + from pypy.translator.goal.targetnumpystandalone import main + from pypy.rpython.annlowlevel import llstr + + interpret(main, [llstr('af+'), 100]) diff --git a/pypy/module/operator/app_operator.py b/pypy/module/operator/app_operator.py --- a/pypy/module/operator/app_operator.py +++ b/pypy/module/operator/app_operator.py @@ -4,6 +4,7 @@ This module exports a set of operators as functions. E.g. operator.add(x,y) is equivalent to x+y. ''' +from __pypy__ import builtinify def countOf(a,b): 'countOf(a, b) -- Return the number of times b occurs in a.' @@ -66,50 +67,56 @@ a[b:c] = d __setslice__ = setslice -class attrgetter(object): - def __init__(self, attr, *attrs): - self.attrs = (attr,) + attrs +def attrgetter(attr, *attrs): + if attrs: + getters = [single_attr_getter(a) for a in (attr,) + attrs] + def getter(obj): + return tuple([getter(obj) for getter in getters]) + else: + getter = single_attr_getter(attr) + return builtinify(getter) - def _resolve_attr(self, obj, attr): - last = 0 - while True: - try: - dot = attr.find(".", last) - except AttributeError: - raise TypeError - if dot > 0: - obj = getattr(obj, attr[last:dot]) - last = dot + 1 - else: - return getattr(obj, attr[last:]) +def single_attr_getter(attr): + if not isinstance(attr, str): + if not isinstance(attr, unicode): + def _raise_typeerror(obj): + raise TypeError("argument must be a string, not %r" % + (type(attr).__name__,)) + return _raise_typeerror + attr = attr.encode('ascii') + # + def make_getter(name, prevfn=None): + if prevfn is None: + def getter(obj): + return getattr(obj, name) + else: + def getter(obj): + return getattr(prevfn(obj), name) + return getter + # + last = 0 + getter = None + while True: + dot = attr.find(".", last) + if dot < 0: break + getter = make_getter(attr[last:dot], getter) + last = dot + 1 + return make_getter(attr[last:], getter) - def __call__(self, obj): - if len(self.attrs) == 1: - return self._resolve_attr(obj, self.attrs[0]) - return tuple(self._resolve_attr(obj, attr) for attr in self.attrs) -class itemgetter(object): +def itemgetter(item, *items): + if items: + list_of_indices = [item] + list(items) + def getter(obj): + return tuple([obj[i] for i in list_of_indices]) + else: + def getter(obj): + return obj[item] + return builtinify(getter) - def __init__(self, item, *args): - self.items = args - self.item = item - def __call__(self, obj): - result = obj[self.item] - - if self.items: - list = [result] + [obj[item] for item in self.items] - return tuple(list) - - return result - -class methodcaller(object): - - def __init__(self, method_name, *args, **kwargs): - self.method_name = method_name - self.args = args - self.kwargs = kwargs - - def __call__(self, obj): - return getattr(obj, self.method_name)(*self.args, **self.kwargs) +def methodcaller(method_name, *args, **kwargs): + def call(obj): + return getattr(obj, method_name)(*args, **kwargs) + return builtinify(call) diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -1484,7 +1484,7 @@ raise OperationError( moduledict.w_NotSupportedError, space.wrap("Variable_TypeByValue(): unhandled data type %s" % - (space.type(w_value).getname(space, '?'),))) + (space.type(w_value).getname(space),))) def newByInputTypeHandler(space, cursor, w_inputTypeHandler, w_value, numElements): w_var = space.call(w_inputTypeHandler, diff --git a/pypy/module/posix/app_posix.py b/pypy/module/posix/app_posix.py --- a/pypy/module/posix/app_posix.py +++ b/pypy/module/posix/app_posix.py @@ -107,6 +107,9 @@ def tmpnam(): """Return an absolute pathname of a file that did not exist at the time the call is made.""" + from warnings import warn + warn(RuntimeWarning("tmpnam is a potential security risk to your program")) + import tempfile return tempfile.mktemp() @@ -114,6 +117,9 @@ """Return an absolute pathname of a file that did not exist at the time the call is made. The directory and a prefix may be specified as strings; they may be omitted or None if not needed.""" + from warnings import warn + warn(RuntimeWarning("tempnam is a potential security risk to your program")) + import tempfile return tempfile.mktemp('', prefix or 'tmp', dir) diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -847,6 +847,21 @@ assert os.path.basename(s1).startswith(prefix or 'tmp') assert os.path.basename(s2).startswith(prefix or 'tmp') + def test_tmpnam_warning(self): + import warnings, os + # + def f_tmpnam_warning(): os.tmpnam() # a single line + # + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + f_tmpnam_warning() + assert len(w) == 1 + assert issubclass(w[-1].category, RuntimeWarning) + assert "potential security risk" in str(w[-1].message) + # check that the warning points to the call to os.tmpnam(), + # not to some code inside app_posix.py + assert w[-1].lineno == f_tmpnam_warning.func_code.co_firstlineno + class AppTestEnvironment(object): def setup_class(cls): diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py --- a/pypy/module/pyexpat/__init__.py +++ b/pypy/module/pyexpat/__init__.py @@ -2,6 +2,22 @@ from pypy.interpreter.mixedmodule import MixedModule +class ErrorsModule(MixedModule): + "Definition of pyexpat.errors module." + + appleveldefs = { + } + + interpleveldefs = { + } + + def setup_after_space_initialization(self): + from pypy.module.pyexpat import interp_pyexpat + for name in interp_pyexpat.xml_error_list: + self.space.setattr(self, self.space.wrap(name), + interp_pyexpat.ErrorString(self.space, + getattr(interp_pyexpat, name))) + class Module(MixedModule): "Python wrapper for Expat parser." @@ -21,6 +37,10 @@ 'version_info': 'interp_pyexpat.get_expat_version_info(space)', } + submodules = { + 'errors': ErrorsModule, + } + for name in ['XML_PARAM_ENTITY_PARSING_NEVER', 'XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE', 'XML_PARAM_ENTITY_PARSING_ALWAYS']: diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -31,6 +31,48 @@ XML_Content_Ptr = lltype.Ptr(lltype.ForwardReference()) XML_Parser = rffi.COpaquePtr(typedef='XML_Parser') +xml_error_list = [ + "XML_ERROR_NO_MEMORY", + "XML_ERROR_SYNTAX", + "XML_ERROR_NO_ELEMENTS", + "XML_ERROR_INVALID_TOKEN", + "XML_ERROR_UNCLOSED_TOKEN", + "XML_ERROR_PARTIAL_CHAR", + "XML_ERROR_TAG_MISMATCH", + "XML_ERROR_DUPLICATE_ATTRIBUTE", + "XML_ERROR_JUNK_AFTER_DOC_ELEMENT", + "XML_ERROR_PARAM_ENTITY_REF", + "XML_ERROR_UNDEFINED_ENTITY", + "XML_ERROR_RECURSIVE_ENTITY_REF", + "XML_ERROR_ASYNC_ENTITY", + "XML_ERROR_BAD_CHAR_REF", + "XML_ERROR_BINARY_ENTITY_REF", + "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", + "XML_ERROR_MISPLACED_XML_PI", + "XML_ERROR_UNKNOWN_ENCODING", + "XML_ERROR_INCORRECT_ENCODING", + "XML_ERROR_UNCLOSED_CDATA_SECTION", + "XML_ERROR_EXTERNAL_ENTITY_HANDLING", + "XML_ERROR_NOT_STANDALONE", + "XML_ERROR_UNEXPECTED_STATE", + "XML_ERROR_ENTITY_DECLARED_IN_PE", + "XML_ERROR_FEATURE_REQUIRES_XML_DTD", + "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING", + # Added in Expat 1.95.7. + "XML_ERROR_UNBOUND_PREFIX", + # Added in Expat 1.95.8. + "XML_ERROR_UNDECLARING_PREFIX", + "XML_ERROR_INCOMPLETE_PE", + "XML_ERROR_XML_DECL", + "XML_ERROR_TEXT_DECL", + "XML_ERROR_PUBLICID", + "XML_ERROR_SUSPENDED", + "XML_ERROR_NOT_SUSPENDED", + "XML_ERROR_ABORTED", + "XML_ERROR_FINISHED", + "XML_ERROR_SUSPEND_PE", + ] + class CConfigure: _compilation_info_ = eci XML_Content = rffi_platform.Struct('XML_Content', [ @@ -56,6 +98,9 @@ XML_FALSE = rffi_platform.ConstantInteger('XML_FALSE') XML_TRUE = rffi_platform.ConstantInteger('XML_TRUE') + for name in xml_error_list: + locals()[name] = rffi_platform.ConstantInteger(name) + for k, v in rffi_platform.configure(CConfigure).items(): globals()[k] = v @@ -298,7 +343,8 @@ XML_GetErrorCode = expat_external( 'XML_GetErrorCode', [XML_Parser], rffi.INT) XML_ErrorString = expat_external( - 'XML_ErrorString', [rffi.INT], rffi.CCHARP) + 'XML_ErrorString', [rffi.INT], + rffi.CCHARP) XML_GetCurrentLineNumber = expat_external( 'XML_GetCurrentLineNumber', [XML_Parser], rffi.INT) XML_GetErrorLineNumber = XML_GetCurrentLineNumber @@ -691,7 +737,7 @@ elif space.is_true(space.isinstance(w_encoding, space.w_str)): encoding = space.str_w(w_encoding) else: - type_name = space.type(w_encoding).getname(space, '?') + type_name = space.type(w_encoding).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 1 must be string or None,' @@ -711,7 +757,7 @@ space.wrap('namespace_separator must be at most one character,' ' omitted, or None')) else: - type_name = space.type(w_namespace_separator).getname(space, '?') + type_name = space.type(w_namespace_separator).getname(space) raise OperationError( space.w_TypeError, space.wrap('ParserCreate() argument 2 must be string or None,' diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py --- a/pypy/module/pyexpat/test/test_parser.py +++ b/pypy/module/pyexpat/test/test_parser.py @@ -38,7 +38,7 @@ parser = pyexpat.ParserCreate() raises(pyexpat.ExpatError, "parser.Parse(xml, True)") - def test_encoding(self): + def test_encoding_argument(self): import pyexpat for encoding_arg in (None, 'utf-8', 'iso-8859-1'): for namespace_arg in (None, '{'): @@ -68,7 +68,7 @@ assert p.buffer_size == 150 raises(TypeError, setattr, p, 'buffer_size', sys.maxint + 1) - def test_encoding(self): + def test_encoding_xml(self): # use one of the few encodings built-in in expat xml = "caf\xe9" import pyexpat @@ -120,3 +120,14 @@ return True p.ExternalEntityRefHandler = handler p.Parse(xml) + + def test_errors(self): + import types + import pyexpat + assert isinstance(pyexpat.errors, types.ModuleType) + # check a few random errors + assert pyexpat.errors.XML_ERROR_SYNTAX == 'syntax error' + assert (pyexpat.errors.XML_ERROR_INCORRECT_ENCODING == + 'encoding specified in XML declaration is incorrect') + assert (pyexpat.errors.XML_ERROR_XML_DECL == + 'XML declaration not well-formed') diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,6 +8,7 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'set_compile_hook': 'interp_jit.set_compile_hook', + 'DebugMergePoint': 'interp_resop.W_DebugMergePoint', } def setup_after_space_initialization(self): diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -16,10 +16,12 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap from pypy.rlib.objectmodel import we_are_translated +from pypy.rlib.nonconst import NonConstant +from pypy.jit.metainterp.resoperation import rop +from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes PyFrame._virtualizable2_ = ['last_instr', 'pycode', - 'valuestackdepth', 'valuestack_w[*]', - 'fastlocals_w[*]', + 'valuestackdepth', 'locals_stack_w[*]', 'last_exception', 'lastblock', 'is_being_profiled', @@ -46,6 +48,16 @@ return (bytecode.co_flags & CO_GENERATOR) != 0 +def wrap_oplist(space, logops, operations): + list_w = [] + for op in operations: + if op.getopnum() == rop.DEBUG_MERGE_POINT: + list_w.append(space.wrap(debug_merge_point_from_boxes( + op.getarglist()))) + else: + list_w.append(space.wrap(logops.repr_of_resop(op))) + return list_w + class PyPyJitDriver(JitDriver): reds = ['frame', 'ec'] greens = ['next_instr', 'is_being_profiled', 'pycode'] @@ -57,11 +69,13 @@ space = self.space cache = space.fromcache(Cache) + if cache.in_recursion: + return if space.is_true(cache.w_compile_hook): - memo = {} - list_w = [space.wrap(logger.repr_of_resop(memo, op)) - for op in operations] + logops = logger._make_log_operations() + list_w = wrap_oplist(space, logops, operations) pycode = cast_base_ptr_to_instance(PyCode, ll_pycode) + cache.in_recursion = True try: space.call_function(cache.w_compile_hook, space.wrap('main'), @@ -72,14 +86,17 @@ space.newlist(list_w)) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_compile_hook) + cache.in_recursion = False def on_compile_bridge(self, logger, orig_looptoken, operations, n): space = self.space cache = space.fromcache(Cache) + if cache.in_recursion: + return if space.is_true(cache.w_compile_hook): - memo = {} - list_w = [space.wrap(logger.repr_of_resop(memo, op)) - for op in operations] + logops = logger._make_log_operations() + list_w = wrap_oplist(space, logops, operations) + cache.in_recursion = True try: space.call_function(cache.w_compile_hook, space.wrap('main'), @@ -88,6 +105,7 @@ space.newlist(list_w)) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_compile_hook) + cache.in_recursion = False pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location, get_jitcell_at = get_jitcell_at, @@ -158,6 +176,8 @@ '''Configure the tunable JIT parameters. * set_param(name=value, ...) # as keyword arguments * set_param("name=value,name=value") # as a user-supplied string + * set_param("off") # disable the jit + * set_param("default") # restore all defaults ''' # XXXXXXXXX args_w, kwds_w = __args__.unpack() @@ -191,6 +211,8 @@ return space.call_args(w_callable, __args__) class Cache(object): + in_recursion = False + def __init__(self, space): self.w_compile_hook = space.w_None @@ -209,8 +231,13 @@ for jit merge point. in case it's `main` it'll be a tuple (code, offset, is_being_profiled) + Note that jit hook is not reentrant. It means that if the code + inside the jit hook is itself jitted, it will get compiled, but the + jit hook won't be called for that. + XXX write down what else """ cache = space.fromcache(Cache) cache.w_compile_hook = w_hook + cache.in_recursion = NonConstant(False) return space.w_None diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/interp_resop.py @@ -0,0 +1,41 @@ + +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.gateway import unwrap_spec, interp2app +from pypy.interpreter.pycode import PyCode +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.annlowlevel import cast_base_ptr_to_instance +from pypy.rpython.lltypesystem.rclass import OBJECT + +class W_DebugMergePoint(Wrappable): + """ A class representing debug_merge_point JIT operation + """ + + def __init__(self, mp_no, offset, pycode): + self.mp_no = mp_no + self.offset = offset + self.pycode = pycode + + def descr_repr(self, space): + return space.wrap('DebugMergePoint()') + + at unwrap_spec(mp_no=int, offset=int, pycode=PyCode) +def new_debug_merge_point(space, w_tp, mp_no, offset, pycode): + return W_DebugMergePoint(mp_no, offset, pycode) + +def debug_merge_point_from_boxes(boxes): + mp_no = boxes[0].getint() + offset = boxes[2].getint() + llcode = lltype.cast_opaque_ptr(lltype.Ptr(OBJECT), + boxes[4].getref_base()) + pycode = cast_base_ptr_to_instance(PyCode, llcode) + assert pycode is not None + return W_DebugMergePoint(mp_no, offset, pycode) + +W_DebugMergePoint.typedef = TypeDef( + 'DebugMergePoint', + __new__ = interp2app(new_debug_merge_point), + __doc__ = W_DebugMergePoint.__doc__, + __repr__ = interp2app(W_DebugMergePoint.descr_repr), + code = interp_attrproperty('pycode', W_DebugMergePoint), +) diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,8 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof', '_weakref']: + 'posix', '_socket', '_sre', '_lsprof', '_weakref', + '__pypy__', 'cStringIO']: return True return False diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -8,12 +8,13 @@ from pypy.jit.metainterp.logger import Logger from pypy.rpython.annlowlevel import (cast_instance_to_base_ptr, cast_base_ptr_to_instance) +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.module.pypyjit.interp_jit import pypyjitdriver from pypy.jit.tool.oparser import parse from pypy.jit.metainterp.typesystem import llhelper class MockSD(object): - class cpu: + class cpu(object): ts = llhelper class AppTestJitHook(object): @@ -27,14 +28,17 @@ pass return f """) + cls.w_f = w_f ll_code = cast_instance_to_base_ptr(w_f.code) + code_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, ll_code) logger = Logger(MockSD()) oplist = parse(""" [i1, i2] i3 = int_add(i1, i2) + debug_merge_point(0, 0, 0, 0, ConstPtr(ptr0)) guard_true(i3) [] - """).operations + """, namespace={'ptr0': code_gcref}).operations def interp_on_compile(): pypyjitdriver.on_compile(logger, LoopToken(), oplist, 'loop', @@ -63,7 +67,7 @@ assert all[0][0][0].co_name == 'f' assert all[0][0][1] == 0 assert all[0][0][2] == False - assert len(all[0][1]) == 2 + assert len(all[0][1]) == 3 assert 'int_add' in all[0][1][0] self.on_compile_bridge() assert len(all) == 2 @@ -87,3 +91,36 @@ sys.stderr = prev assert 'jit hook' in s.getvalue() assert 'ZeroDivisionError' in s.getvalue() + + def test_non_reentrant(self): + import pypyjit + l = [] + + def hook(*args): + l.append(None) + self.on_compile() + self.on_compile_bridge() + + pypyjit.set_compile_hook(hook) + self.on_compile() + assert len(l) == 1 # and did not crash + self.on_compile_bridge() + assert len(l) == 2 # and did not crash + + def test_on_compile_types(self): + import pypyjit + l = [] + + def hook(*args): + l.append(args) + + pypyjit.set_compile_hook(hook) + self.on_compile() + dmp = l[0][3][1] + assert isinstance(dmp, pypyjit.DebugMergePoint) + assert dmp.code is self.f.func_code + + def test_creation(self): + import pypyjit + dmp = pypyjit.DebugMergePoint(0, 0, self.f.func_code) + assert dmp.code is self.f.func_code diff --git a/pypy/module/pypyjit/test/test_jit_setup.py b/pypy/module/pypyjit/test/test_jit_setup.py --- a/pypy/module/pypyjit/test/test_jit_setup.py +++ b/pypy/module/pypyjit/test/test_jit_setup.py @@ -9,18 +9,49 @@ # this just checks that the module is setting up things correctly, and # the resulting code makes sense on top of CPython. import pypyjit - pypyjit.set_param(threshold=5, inlining=1) - pypyjit.set_param("trace_eagerness=3,inlining=0") + try: + pypyjit.set_param(threshold=5, inlining=1) + pypyjit.set_param("trace_eagerness=3,inlining=0") - def f(x, y): - return x*y+1 + def f(x, y): + return x*y+1 - assert f(6, 7) == 43 + assert f(6, 7) == 43 - def gen(x): - i = 0 - while i < x: - yield i*i - i += 1 + def gen(x): + i = 0 + while i < x: + yield i*i + i += 1 - assert list(gen(3)) == [0, 1, 4] + assert list(gen(3)) == [0, 1, 4] + finally: + pypyjit.set_param('default') + + def test_no_jit(self): + import pypyjit + was_called = [] + def should_not_be_called(*args, **kwds): + was_called.append((args, kwds)) + try: + pypyjit.set_param('off') + pypyjit.set_compile_hook(should_not_be_called) + def f(): + pass + for i in range(2500): + f() + assert not was_called + finally: + pypyjit.set_compile_hook(None) + pypyjit.set_param('default') + + +def test_interface_residual_call(): + space = gettestobjspace(usemodules=['pypyjit']) + space.appexec([], """(): + import pypyjit + def f(*args, **kwds): + return (args, kwds) + res = pypyjit.residual_call(f, 4, x=6) + assert res == ((4,), {'x': 6}) + """) diff --git a/pypy/module/pypyjit/test/test_pypy_c.py b/pypy/module/pypyjit/test/test_pypy_c.py deleted file mode 100644 --- a/pypy/module/pypyjit/test/test_pypy_c.py +++ /dev/null @@ -1,430 +0,0 @@ -from pypy.conftest import gettestobjspace, option -from pypy.tool.udir import udir -import py -from py.test import skip -import sys, os, re -import subprocess - -class BytecodeTrace(list): - def get_opnames(self, prefix=""): - return [op.getopname() for op in self - if op.getopname().startswith(prefix)] - - def __repr__(self): - return "%s%s" % (self.bytecode, list.__repr__(self)) - -ZERO_OP_BYTECODES = [ - 'POP_TOP', - 'ROT_TWO', - 'ROT_THREE', - 'DUP_TOP', - 'ROT_FOUR', - 'NOP', - 'DUP_TOPX', - 'LOAD_CONST', - 'JUMP_FORWARD', - #'JUMP_ABSOLUTE' in theory, but contains signals stuff - #'LOAD_FAST' should be here, but currently needs a guard for nonzeroness - 'STORE_FAST', - ] - - -r_bridge = re.compile(r"bridge out of Guard (\d+)") - -def from_entry_bridge(text, allparts): - firstline = text.splitlines()[0] - if 'entry bridge' in firstline: - return True - match = r_bridge.search(firstline) - if match: - search = '' - for part in allparts: - if search in part: - break - else: - raise AssertionError, "%s not found??" % (search,) - return from_entry_bridge(part, allparts) - return False - -def test_from_entry_bridge(): - assert from_entry_bridge( - "# Loop 4 : entry bridge with 31 ops\n[p0, etc", []) - assert not from_entry_bridge( - "# Loop 1 : loop with 31 ops\n[p0, p1, etc", []) - assert not from_entry_bridge( - "# bridge out of Guard 5 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : loop with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n"]) - assert from_entry_bridge( - "# bridge out of Guard 5 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : entry bridge with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n"]) - assert not from_entry_bridge( - "# bridge out of Guard 51 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : loop with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n", - "# bridge out of Guard 5 with 13 ops\n" - "[p0, p1]\n" - "guard_other(p1, descr=)\n"]) - assert from_entry_bridge( - "# bridge out of Guard 51 with 24 ops\n[p0, p1, etc", - ["# Loop 1 : entry bridge with 31 ops\n" - "[p0, p1]\n" - "guard_stuff(descr=)\n", - "# bridge out of Guard 5 with 13 ops\n" - "[p0, p1]\n" - "guard_other(p1, descr=)\n"]) - - -class PyPyCJITTests(object): - def run_source(self, source, expected_max_ops, *testcases, **kwds): - assert isinstance(expected_max_ops, int) - threshold = kwds.pop('threshold', 3) - self.count_debug_merge_point = \ - kwds.pop('count_debug_merge_point', True) - if kwds: - raise TypeError, 'Unsupported keyword arguments: %s' % kwds.keys() - source = py.code.Source(source) - filepath = self.tmpdir.join('case%d.py' % self.counter) - logfilepath = filepath.new(ext='.log') - self.__class__.counter += 1 - f = filepath.open('w') - print >> f, source - # some support code... - print >> f, py.code.Source(""" - import sys - # we don't want to see the small bridges created - # by the checkinterval reaching the limit - sys.setcheckinterval(10000000) - try: # make the file runnable by CPython - import pypyjit - pypyjit.set_param(threshold=%d) - except ImportError: - pass - - def check(args, expected): - #print >> sys.stderr, 'trying:', args - result = main(*args) - #print >> sys.stderr, 'got:', repr(result) - assert result == expected - assert type(result) is type(expected) - """ % threshold) - for testcase in testcases * 2: - print >> f, "check(%r, %r)" % testcase - print >> f, "print 'OK :-)'" - f.close() - - print logfilepath - env = os.environ.copy() - env['PYPYLOG'] = ":%s" % (logfilepath,) - p = subprocess.Popen([self.pypy_c, str(filepath)], - env=env, stdout=subprocess.PIPE) - result, _ = p.communicate() - assert result - if result.strip().startswith('SKIP:'): - py.test.skip(result.strip()) - assert result.splitlines()[-1].strip() == 'OK :-)' - self.parse_loops(logfilepath) - self.print_loops() - print logfilepath - if self.total_ops > expected_max_ops: - assert 0, "too many operations: got %d, expected maximum %d" % ( - self.total_ops, expected_max_ops) - return result - - def parse_loops(self, opslogfile): - from pypy.tool import logparser - assert opslogfile.check() - log = logparser.parse_log_file(str(opslogfile)) - parts = logparser.extract_category(log, 'jit-log-opt-') - self.rawloops = [part for part in parts - if not from_entry_bridge(part, parts)] - self.loops, self.sliced_loops, self.total_ops = \ - self.parse_rawloops(self.rawloops) - self.check_0_op_bytecodes() - self.rawentrybridges = [part for part in parts - if from_entry_bridge(part, parts)] - _, self.sliced_entrybridge, _ = \ - self.parse_rawloops(self.rawentrybridges) - - from pypy.jit.tool.jitoutput import parse_prof - summaries = logparser.extract_category(log, 'jit-summary') - if len(summaries) > 0: - self.jit_summary = parse_prof(summaries[-1]) - else: - self.jit_summary = None - - - def parse_rawloops(self, rawloops): - from pypy.jit.tool.oparser import parse - loops = [parse(part, no_namespace=True) for part in rawloops] - sliced_loops = [] # contains all bytecodes of all loops - total_ops = 0 - for loop in loops: - for op in loop.operations: - if op.getopname() == "debug_merge_point": - sliced_loop = BytecodeTrace() - sliced_loop.bytecode = op.getarg(0)._get_str().rsplit(" ", 1)[1] - sliced_loops.append(sliced_loop) - if self.count_debug_merge_point: - total_ops += 1 - else: - sliced_loop.append(op) - total_ops += 1 - return loops, sliced_loops, total_ops - - def check_0_op_bytecodes(self): - for bytecodetrace in self.sliced_loops: - if bytecodetrace.bytecode not in ZERO_OP_BYTECODES: - continue - assert not bytecodetrace - - def get_by_bytecode(self, name, from_entry_bridge=False): - if from_entry_bridge: - sliced_loops = self.sliced_entrybridge - else: - sliced_loops = self.sliced_loops - return [ops for ops in sliced_loops if ops.bytecode == name] - - def print_loops(self): - for rawloop in self.rawloops: - print - print '@' * 79 - print - print rawloop.rstrip() - print - print '@' * 79 - - - def test_richards(self): - self.run_source(''' - import sys; sys.path[:] = %r - from pypy.translator.goal import richards - - def main(): - return richards.main(iterations = 1) - ''' % (sys.path,), 7200, - ([], 42)) - - - def test_overflow_checking(self): - startvalue = sys.maxint - 2147483647 - self.run_source(''' - def main(): - def f(a,b): - if a < 0: return -1 - return a-b - total = %d - for i in range(100000): - total += f(i, 5) - return total - ''' % startvalue, 170, ([], startvalue + 4999450000L)) - - def test_shift(self): - from sys import maxint - maxvals = (-maxint-1, -maxint, maxint-1, maxint) - for a in (-4, -3, -2, -1, 0, 1, 2, 3, 4) + maxvals: - for b in (0, 1, 2, 31, 32, 33, 61, 62, 63): - r = 0 - if (a >> b) >= 0: - r += 2000 - if (a << b) > 2: - r += 20000000 - if abs(a) < 10 and b < 5: - ops = 13 - else: - ops = 29 - - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 2000: - if a > 0: # Specialises the loop - pass - if b < 2 and b > 0: - pass - if (a >> b) >= 0: - sa += 1 - if (a << b) > 2: - sa += 10000 - i += 1 - return sa - ''', ops, ([a, b], r), count_debug_merge_point=False) - - def test_revert_shift(self): - from sys import maxint - tests = [] - for a in (1, 4, 8, 100): - for b in (-10, 10, -201, 201, -maxint/3, maxint/3): - for c in (-10, 10, -maxint/3, maxint/3): - tests.append(([a, b, c], long(4000*(a+b+c)))) - self.run_source(''' - def main(a, b, c): - from sys import maxint - i = sa = 0 - while i < 2000: - if 0 < a < 10: pass - if -100 < b < 100: pass - if -maxint/2 < c < maxint/2: pass - sa += (a<>a - sa += (b<>a - sa += (c<>a - sa += (a<<100)>>100 - sa += (b<<100)>>100 - sa += (c<<100)>>100 - i += 1 - return long(sa) - ''', 93, count_debug_merge_point=False, *tests) - - def test_division_to_rshift(self): - avalues = ('a', 'b', 7, -42, 8) - bvalues = ['b'] + range(-10, 0) + range(1,10) - code = '' - a1, b1, res1 = 10, 20, 0 - a2, b2, res2 = 10, -20, 0 - a3, b3, res3 = -10, -20, 0 - def dd(a, b, aval, bval): - m = {'a': aval, 'b': bval} - if not isinstance(a, int): - a=m[a] - if not isinstance(b, int): - b=m[b] - return a/b - for a in avalues: - for b in bvalues: - code += ' sa += %s / %s\n' % (a, b) - res1 += dd(a, b, a1, b1) - res2 += dd(a, b, a2, b2) - res3 += dd(a, b, a3, b3) - # The purpose of this test is to check that we get - # the correct results, not really to count operations. - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 2000: -%s - i += 1 - return sa - ''' % code, sys.maxint, ([a1, b1], 2000 * res1), - ([a2, b2], 2000 * res2), - ([a3, b3], 2000 * res3)) - - def test_mod(self): - avalues = ('a', 'b', 7, -42, 8) - bvalues = ['b'] + range(-10, 0) + range(1,10) - code = '' - a1, b1, res1 = 10, 20, 0 - a2, b2, res2 = 10, -20, 0 - a3, b3, res3 = -10, -20, 0 - def dd(a, b, aval, bval): - m = {'a': aval, 'b': bval} - if not isinstance(a, int): - a=m[a] - if not isinstance(b, int): - b=m[b] - return a % b - for a in avalues: - for b in bvalues: - code += ' sa += %s %% %s\n' % (a, b) - res1 += dd(a, b, a1, b1) - res2 += dd(a, b, a2, b2) - res3 += dd(a, b, a3, b3) - # The purpose of this test is to check that we get - # the correct results, not really to count operations. - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 2000: - if a > 0: pass - if 1 < b < 2: pass -%s - i += 1 - return sa - ''' % code, sys.maxint, ([a1, b1], 2000 * res1), - ([a2, b2], 2000 * res2), - ([a3, b3], 2000 * res3)) - - def test_dont_trace_every_iteration(self): - self.run_source(''' - def main(a, b): - i = sa = 0 - while i < 200: - if a > 0: pass - if 1 < b < 2: pass - sa += a % b - i += 1 - return sa - ''', 22, ([10, 20], 200 * (10 % 20)), - ([-10, -20], 200 * (-10 % -20)), - count_debug_merge_point=False) - assert self.jit_summary.tracing_no == 2 - def test_id_compare_optimization(self): - # XXX: lower the instruction count, 35 is the old value. - self.run_source(""" - class A(object): - pass - def main(): - i = 0 - a = A() - while i < 5: - if A() != a: - pass - i += 1 - """, 35, ([], None)) - _, compare = self.get_by_bytecode("COMPARE_OP") - assert "call" not in compare.get_opnames() - -class AppTestJIT(PyPyCJITTests): - def setup_class(cls): - if not option.runappdirect: - py.test.skip("meant only for pypy-c") - # the next line skips stuff if the pypy-c is not a jit build - cls.space = gettestobjspace(usemodules=['pypyjit']) - cls.tmpdir = udir.join('pypy-jit') - cls.tmpdir.ensure(dir=1) - cls.counter = 0 - cls.pypy_c = sys.executable - -class TestJIT(PyPyCJITTests): - def setup_class(cls): - if option.pypy_c is None: - py.test.skip("pass --pypy!") - if not has_info(option.pypy_c, 'translation.jit'): - py.test.skip("must give a pypy-c with the jit enabled") - cls.tmpdir = udir.join('pypy-jit') - cls.tmpdir.ensure(dir=1) - cls.counter = 0 - cls.pypy_c = option.pypy_c - - -def test_interface_residual_call(): - space = gettestobjspace(usemodules=['pypyjit']) - space.appexec([], """(): - import pypyjit - def f(*args, **kwds): - return (args, kwds) - res = pypyjit.residual_call(f, 4, x=6) - assert res == ((4,), {'x': 6}) - """) - - -def has_info(pypy_c, option): - g = os.popen('"%s" --info' % pypy_c, 'r') - lines = g.readlines() - g.close() - if not lines: - raise ValueError("cannot execute %r" % pypy_c) - for line in lines: - line = line.strip() - if line.startswith(option + ':'): - line = line[len(option)+1:].strip() - if line == 'True': - return True - elif line == 'False': - return False - else: - return line - raise ValueError(option + ' not found in ' + pypy_c) diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -2,6 +2,7 @@ import sys import re import os.path +from _pytest.assertion import newinterpret from pypy.tool.jitlogparser.parser import SimpleParser, Function, TraceForOpcode from pypy.tool.jitlogparser.storage import LoopStorage @@ -194,7 +195,7 @@ # transform self._assert(x, 'foo') into assert x, 'foo' source = source.replace('self._assert(', 'assert ') source = source[:-1] # remove the trailing ')' - self.msg = py.code._reinterpret(source, f, should_fail=True) + self.msg = newinterpret.interpret(source, f, should_fail=True) else: self.msg = "" diff --git a/pypy/module/pypyjit/test_pypy_c/test_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py rename from pypy/module/pypyjit/test_pypy_c/test_model.py rename to pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -5,6 +5,7 @@ from lib_pypy import disassembler from pypy.tool.udir import udir from pypy.tool import logparser +from pypy.jit.tool.jitoutput import parse_prof from pypy.module.pypyjit.test_pypy_c.model import Log, find_ids_range, find_ids, \ LoopWithIds, OpMatcher @@ -21,6 +22,7 @@ self.filepath = self.tmpdir.join(meth.im_func.func_name + '.py') def run(self, func_or_src, args=[], import_site=False, **jitopts): + jitopts.setdefault('threshold', 200) src = py.code.Source(func_or_src) if isinstance(func_or_src, types.FunctionType): funcname = func_or_src.func_name @@ -56,6 +58,8 @@ stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) + if stderr.startswith('debug_alloc.h:'): # lldebug builds + stderr = '' assert not stderr # # parse the JIT log @@ -63,6 +67,13 @@ rawtraces = logparser.extract_category(rawlog, 'jit-log-opt-') log = Log(rawtraces) log.result = eval(stdout) + # + summaries = logparser.extract_category(rawlog, 'jit-summary') + if len(summaries) > 0: + log.jit_summary = parse_prof(summaries[-1]) + else: + log.jit_summary = None + # return log def run_and_check(self, src, args=[], **jitopts): diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -0,0 +1,133 @@ +import py +import sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class Test__ffi(BaseTestPyPyC): + + def test__ffi_call(self): + from pypy.rlib.test.test_libffi import get_libm_name + def main(libm_name): + try: + from _ffi import CDLL, types + except ImportError: + sys.stderr.write('SKIP: cannot import _ffi\n') + return 0 + + libm = CDLL(libm_name) + pow = libm.getfunc('pow', [types.double, types.double], + types.double) + i = 0 + res = 0 + while i < 300: + tmp = pow(2, 3) # ID: fficall + res += tmp + i += 1 + return pow.getaddr(), res + # + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + pow_addr, res = log.result + assert res == 8.0 * 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('fficall', """ + p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>) + guard_not_invalidated(descr=...) + i17 = force_token() + setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>) + f21 = call_release_gil(%d, 2.000000, 3.000000, descr=) + guard_not_forced(descr=...) + guard_no_exception(descr=...) + """ % pow_addr) + + + def test__ffi_call_frame_does_not_escape(self): + from pypy.rlib.test.test_libffi import get_libm_name + def main(libm_name): + try: + from _ffi import CDLL, types + except ImportError: + sys.stderr.write('SKIP: cannot import _ffi\n') + return 0 + + libm = CDLL(libm_name) + pow = libm.getfunc('pow', [types.double, types.double], + types.double) + + def mypow(a, b): + return pow(a, b) + + i = 0 + res = 0 + while i < 300: + tmp = mypow(2, 3) + res += tmp + i += 1 + return pow.getaddr(), res + # + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + pow_addr, res = log.result + assert res == 8.0 * 300 + loop, = log.loops_by_filename(self.filepath) + opnames = log.opnames(loop.allops()) + # we only force the virtualref, not its content + assert opnames.count('new_with_vtable') == 1 + + def test__ffi_call_releases_gil(self): + from pypy.rlib.test.test_libffi import get_libc_name + def main(libc_name, n): + import time + from threading import Thread + from _ffi import CDLL, types + # + libc = CDLL(libc_name) + sleep = libc.getfunc('sleep', [types.uint], types.uint) + delays = [0]*n + [1] + # + def loop_of_sleeps(i, delays): + for delay in delays: + sleep(delay) # ID: sleep + # + threads = [Thread(target=loop_of_sleeps, args=[i, delays]) for i in range(5)] + start = time.time() + for i, thread in enumerate(threads): + thread.start() + for thread in threads: + thread.join() + end = time.time() + return end - start + # + log = self.run(main, [get_libc_name(), 200], threshold=150) + assert 1 <= log.result <= 1.5 # at most 0.5 seconds of overhead + loops = log.loops_by_id('sleep') + assert len(loops) == 1 # make sure that we actually JITted the loop + + + def test_ctypes_call(self): + from pypy.rlib.test.test_libffi import get_libm_name + def main(libm_name): + import ctypes + libm = ctypes.CDLL(libm_name) + fabs = libm.fabs + fabs.argtypes = [ctypes.c_double] + fabs.restype = ctypes.c_double + x = -4 + i = 0 + while i < 300: + x = fabs(x) + x = x - 100 + i += 1 + return fabs._ptr.getaddr(), x + + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + fabs_addr, res = log.result + assert res == -4.0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.allops() + opnames = log.opnames(ops) + assert opnames.count('new_with_vtable') == 1 # only the virtualref + assert opnames.count('call_release_gil') == 1 + idx = opnames.index('call_release_gil') + call = ops[idx] + assert int(call.args[0]) == fabs_addr diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -0,0 +1,188 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestArray(BaseTestPyPyC): + + def test_arraycopy_disappears(self): + def main(n): + i = 0 + while i < n: + t = (1, 2, 3, i + 1) + t2 = t[:] + del t + i = t2[3] + del t2 + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i5, i6) + guard_true(i7, descr=...) + i9 = int_add(i5, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i9, i6, descr=) + """) + + def test_array_sum(self): + def main(): + from array import array + img = array("i", range(128) * 5) * 480 + l, i = 0, 0 + while i < len(img): + l += img[i] + i += 1 + return l + # + log = self.run(main, []) + assert log.result == 19507200 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + guard_not_invalidated(descr=...) + i13 = int_lt(i7, i9) + guard_true(i13, descr=...) + i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) + i16 = int_add_ovf(i8, i15) + guard_no_overflow(descr=...) + i18 = int_add(i7, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) + """) + + def test_array_intimg(self): + def main(): + from array import array + img = array('i', range(3)) * (350 * 480) + intimg = array('i', (0,)) * (640 * 480) + l, i = 0, 640 + while i < 640 * 480: + assert len(img) == 3*350*480 + assert len(intimg) == 640*480 + l = l + img[i] + intimg[i] = (intimg[i-640] + l) + i += 1 + return intimg[i - 1] + # + log = self.run(main, []) + assert log.result == 73574560 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i13 = int_lt(i8, 307200) + guard_true(i13, descr=...) + guard_not_invalidated(descr=...) + # the bound check guard on img has been killed (thanks to the asserts) + i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) + i15 = int_add_ovf(i9, i14) + guard_no_overflow(descr=...) + i17 = int_sub(i8, 640) + # the bound check guard on intimg has been killed (thanks to the asserts) + i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) + i19 = int_add_ovf(i18, i15) + guard_no_overflow(descr=...) + # on 64bit, there is a guard checking that i19 actually fits into 32bit + ... + setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) + i28 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) + """) + + + def test_zeropadded(self): + def main(): + from array import array + class ZeroPadded(array): + def __new__(cls, l): + self = array.__new__(cls, 'd', range(l)) + return self + + def __getitem__(self, i): + if i < 0 or i >= len(self): + return 0 + return array.__getitem__(self, i) # ID: get + # + buf = ZeroPadded(2000) + i = 10 + sa = 0 + while i < 2000 - 10: + sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] + i += 1 + return sa + + log = self.run(main, []) + assert log.result == 9895050.0 + loop, = log.loops_by_filename(self.filepath) + # + # check that the overloaded __getitem__ does not introduce double + # array bound checks. + # + # The force_token()s are still there, but will be eliminated by the + # backend regalloc, so they are harmless + assert loop.match(ignore_ops=['force_token'], + expected_src=""" + ... + i20 = int_ge(i18, i8) + guard_false(i20, descr=...) + f21 = getarrayitem_raw(i13, i18, descr=...) + f23 = getarrayitem_raw(i13, i14, descr=...) + f24 = float_add(f21, f23) + f26 = getarrayitem_raw(i13, i6, descr=...) + f27 = float_add(f24, f26) + i29 = int_add(i6, 1) + i31 = int_ge(i29, i8) + guard_false(i31, descr=...) + f33 = getarrayitem_raw(i13, i29, descr=...) + f34 = float_add(f27, f33) + i36 = int_add(i6, 2) + i38 = int_ge(i36, i8) + guard_false(i38, descr=...) + f39 = getarrayitem_raw(i13, i36, descr=...) + ... + """) + + def test_circular(self): + def main(): + from array import array + class Circular(array): + def __new__(cls): + self = array.__new__(cls, 'd', range(256)) + return self + def __getitem__(self, i): + assert len(self) == 256 + return array.__getitem__(self, i & 255) + # + buf = Circular() + i = 10 + sa = 0 + while i < 2000 - 10: + sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] + i += 1 + return sa + # + log = self.run(main, []) + assert log.result == 1239690.0 + loop, = log.loops_by_filename(self.filepath) + # + # check that the array bound checks are removed + # + # The force_token()s are still there, but will be eliminated by the + # backend regalloc, so they are harmless + assert loop.match(ignore_ops=['force_token'], + expected_src=""" + ... + i17 = int_and(i14, 255) + f18 = getarrayitem_raw(i8, i17, descr=...) + f20 = getarrayitem_raw(i8, i9, descr=...) + f21 = float_add(f18, f20) + f23 = getarrayitem_raw(i8, i10, descr=...) + f24 = float_add(f21, f23) + i26 = int_add(i6, 1) + i29 = int_and(i26, 255) + f30 = getarrayitem_raw(i8, i29, descr=...) + f31 = float_add(f24, f30) + i33 = int_add(i6, 2) + i36 = int_and(i33, 255) + f37 = getarrayitem_raw(i8, i36, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_boolrewrite.py b/pypy/module/pypyjit/test_pypy_c/test_boolrewrite.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_boolrewrite.py @@ -0,0 +1,233 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestBoolRewrite(BaseTestPyPyC): + + def test_boolrewrite_inverse(self): + """ + Test for this case:: + guard(i < x) + ... + guard(i >= y) + + where x and y can be either constants or variables. There are cases in + which the second guard is proven to be always true. + """ + + for a, b, res, opt_expected in (('2000', '2000', 20001000, True), + ( '500', '500', 15001500, True), + ( '300', '600', 16001700, False), + ( 'a', 'b', 16001700, False), + ( 'a', 'a', 13001700, True)): + src = """ + def main(): + sa = 0 + a = 300 + b = 600 + for i in range(1000): + if i < %s: # ID: lt + sa += 1 + else: + sa += 2 + # + if i >= %s: # ID: ge + sa += 10000 + else: + sa += 20000 + return sa + """ % (a, b) + # + log = self.run(src, [], threshold=400) + assert log.result == res + loop, = log.loops_by_filename(self.filepath) + le_ops = log.opnames(loop.ops_by_id('lt')) + ge_ops = log.opnames(loop.ops_by_id('ge')) + assert le_ops.count('int_lt') == 1 + # + if opt_expected: + assert ge_ops.count('int_ge') == 0 + else: + # if this assert fails it means that the optimization was + # applied even if we don't expect to. Check whether the + # optimization is valid, and either fix the code or fix the + # test :-) + assert ge_ops.count('int_ge') == 1 + + def test_boolrewrite_reflex(self): + """ + Test for this case:: + guard(i < x) + ... + guard(y > i) + + where x and y can be either constants or variables. There are cases in + which the second guard is proven to be always true. + """ + for a, b, res, opt_expected in (('2000', '2000', 10001000, True), + ( '500', '500', 15001500, True), + ( '300', '600', 14001700, False), + ( 'a', 'b', 14001700, False), + ( 'a', 'a', 17001700, True)): + + src = """ + def main(): + sa = 0 + a = 300 + b = 600 + for i in range(1000): + if i < %s: # ID: lt + sa += 1 + else: + sa += 2 + if %s > i: # ID: gt + sa += 10000 + else: + sa += 20000 + return sa + """ % (a, b) + log = self.run(src, [], threshold=400) + assert log.result == res + loop, = log.loops_by_filename(self.filepath) + le_ops = log.opnames(loop.ops_by_id('lt')) + gt_ops = log.opnames(loop.ops_by_id('gt')) + assert le_ops.count('int_lt') == 1 + # + if opt_expected: + assert gt_ops.count('int_gt') == 0 + else: + # if this assert fails it means that the optimization was + # applied even if we don't expect to. Check whether the + # optimization is valid, and either fix the code or fix the + # test :-) + assert gt_ops.count('int_gt') == 1 + + + def test_boolrewrite_allcases_inverse(self): + """ + Test for this case:: + guard(i < x) + ... + guard(i > y) + + with all possible combination of binary comparison operators. This + test only checks that we get the expected result, not that any + optimization has been applied. + """ + ops = ('<', '>', '<=', '>=', '==', '!=') + for op1 in ops: + for op2 in ops: + for a,b in ((500, 500), (300, 600)): + src = """ + def main(): + sa = 0 + for i in range(300): + if i %s %d: + sa += 1 + else: + sa += 2 + if i %s %d: + sa += 10000 + else: + sa += 20000 + return sa + """ % (op1, a, op2, b) + yield self.run_and_check, src + + src = """ + def main(): + sa = 0 + i = 0.0 + while i < 250.0: + if i %s %f: + sa += 1 + else: + sa += 2 + if i %s %f: + sa += 10000 + else: + sa += 20000 + i += 0.25 + return sa + """ % (op1, float(a)/4.0, op2, float(b)/4.0) + yield self.run_and_check, src + + + def test_boolrewrite_allcases_reflex(self): + """ + Test for this case:: + guard(i < x) + ... + guard(x > i) + + with all possible combination of binary comparison operators. This + test only checks that we get the expected result, not that any + optimization has been applied. + """ + ops = ('<', '>', '<=', '>=', '==', '!=') + for op1 in ops: + for op2 in ops: + for a,b in ((500, 500), (300, 600)): + src = """ + def main(): + sa = 0 + for i in range(300): + if i %s %d: + sa += 1 + else: + sa += 2 + if %d %s i: + sa += 10000 + else: + sa += 20000 + return sa + """ % (op1, a, b, op2) + yield self.run_and_check, src + + src = """ + def main(): + sa = 0 + i = 0.0 + while i < 250.0: + if i %s %f: + sa += 1 + else: + sa += 2 + if %f %s i: + sa += 10000 + else: + sa += 20000 + i += 0.25 + return sa + """ % (op1, float(a)/4.0, float(b)/4.0, op2) + yield self.run_and_check, src + + def test_boolrewrite_ptr(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b') + for e1 in compares: + for e2 in compares: + src = """ + class tst(object): + pass + def main(): + a = tst() + b = tst() + c = tst() + sa = 0 + for i in range(300): + if %s: + sa += 1 + else: + sa += 2 + if %s: + sa += 10000 + else: + sa += 20000 + if i > 750: + a = b + return sa + """ % (e1, e2) + yield self.run_and_check, src diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -0,0 +1,410 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestCall(BaseTestPyPyC): + + def test_recursive_call(self): + def fn(): + def rec(n): + if n == 0: + return 0 + return 1 + rec(n-1) + # + # this loop is traced and then aborted, because the trace is too + # long. But then "rec" is marked as "don't inline". Since we + # already traced function from the start (because of number), + # now we can inline it as call assembler + i = 0 + j = 0 + while i < 20: + i += 1 + j += rec(100) # ID: call_rec + return j + # + log = self.run(fn, [], threshold=18) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('call_rec', """ + ... + p53 = call_assembler(..., descr=...) + guard_not_forced(descr=...) + guard_no_exception(descr=...) + ... + """) + + def test_fib(self): + def fib(n): + if n == 0 or n == 1: + return 1 + return fib(n - 1) + fib(n - 2) # ID: call_rec + + log = self.run(fib, [7], function_threshold=15) + loop, = log.loops_by_filename(self.filepath, is_entry_bridge='*') + #assert loop.match_by_id('call_rec', ''' + #... + #p1 = call_assembler(..., descr=...) + #... + #''') + + def test_simple_call(self): + src = """ + OFFSET = 0 + def f(i): + return i + 1 + OFFSET # ID: add + def main(n): + i = 0 + while i < n+OFFSET: # ID: cond + i = f(f(i)) # ID: call + a = 0 + return i + """ + log = self.run(src, [1000]) + assert log.result == 1000 + # first, we test what is inside the entry bridge + # ----------------------------------------------- + entry_bridge, = log.loops_by_id('call', is_entry_bridge=True) + # LOAD_GLOBAL of OFFSET + ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') + assert log.opnames(ops) == ["guard_value", + "getfield_gc", "guard_value", + "getfield_gc", "guard_value", + "getfield_gc", "guard_nonnull_class"] + # LOAD_GLOBAL of OFFSET but in different function partially folded + # away + # XXX could be improved + ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') + assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value"] + # + # two LOAD_GLOBAL of f, the second is folded away + ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') + assert log.opnames(ops) == ["getfield_gc", "guard_nonnull_class"] + # + assert entry_bridge.match_by_id('call', """ + p29 = getfield_gc(ConstPtr(ptr28), descr=) + guard_nonnull_class(p29, ConstClass(Function), descr=...) + p33 = getfield_gc(p29, descr=) + guard_value(p33, ConstPtr(ptr34), descr=...) + p35 = getfield_gc(p29, descr=) + p36 = getfield_gc(p29, descr=) + p38 = call(ConstClass(getexecutioncontext), descr=) + p39 = getfield_gc(p38, descr=) + i40 = force_token() + p41 = getfield_gc(p38, descr=) + guard_isnull(p41, descr=...) + i42 = getfield_gc(p38, descr=) + i43 = int_is_zero(i42) + guard_true(i43, descr=...) + i50 = force_token() + """) + # + # then, we test the actual loop + # ----------------------------- + loop, = log.loops_by_id('call') + assert loop.match(""" + i12 = int_lt(i5, i6) + guard_true(i12, descr=...) + i13 = force_token() + i15 = int_add(i5, 1) + i16 = int_add_ovf(i15, i7) + guard_no_overflow(descr=...) + i18 = force_token() + i20 = int_add_ovf(i16, 1) + guard_no_overflow(descr=...) + i21 = int_add_ovf(i20, i7) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) + """) + + def test_method_call(self): + def fn(n): + class A(object): + def __init__(self, a): + self.a = a + def f(self, i): + return self.a + i + i = 0 + a = A(1) + while i < n: + x = a.f(i) # ID: meth1 + i = a.f(x) # ID: meth2 + return i + # + log = self.run(fn, [1000]) + assert log.result == 1000 + # + # first, we test the entry bridge + # ------------------------------- + entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) + ops = entry_bridge.ops_by_id('meth1', opcode='LOOKUP_METHOD') + assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', + 'guard_not_invalidated'] + # the second LOOKUP_METHOD is folded away + assert list(entry_bridge.ops_by_id('meth2', opcode='LOOKUP_METHOD')) == [] + # + # then, the actual loop + # ---------------------- + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i15 = int_lt(i6, i9) + guard_true(i15, descr=...) + guard_not_invalidated(descr=...) + i16 = force_token() + i17 = int_add_ovf(i10, i6) + guard_no_overflow(descr=...) + i18 = force_token() + i19 = int_add_ovf(i10, i17) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) + """) + + def test_static_classmethod_call(self): + def fn(n): + class A(object): + @classmethod + def f(cls, i): + return i + (cls is A) + 1 + @staticmethod + def g(i): + return i - 1 + # + i = 0 + a = A() + while i < n: + x = a.f(i) + i = a.g(x) + return i + # + log = self.run(fn, [1000]) + assert log.result == 1000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i14 = int_lt(i6, i9) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) + i15 = force_token() + i17 = int_add_ovf(i8, 1) + guard_no_overflow(descr=...) + i18 = force_token() + --TICK-- + jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) + """) + + def test_default_and_kw(self): + def main(n): + def f(i, j=1): + return i + j + # + i = 0 + while i < n: + i = f(f(i), j=1) # ID: call + a = 0 + return i + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('call') + assert loop.match_by_id('call', """ + i14 = force_token() + i16 = force_token() + """) + + def test_kwargs_empty(self): + def main(x): + def g(**args): + return len(args) + 1 + # + s = 0 + d = {} + i = 0 + while i < x: + s += g(**d) # ID: call + i += 1 + return s + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('call') + ops = log.opnames(loop.ops_by_id('call')) + guards = [ops for ops in ops if ops.startswith('guard')] + assert guards == ["guard_no_overflow"] + + def test_kwargs(self): + # this is not a very precise test, could be improved + def main(x): + def g(**args): + return len(args) + # + s = 0 + d = {"a": 1} + i = 0 + while i < x: + s += g(**d) # ID: call + d[str(i)] = i + if i % 100 == 99: + d = {"a": 1} + i += 1 + return s + # + log = self.run(main, [1000]) + assert log.result == 50500 + loop, = log.loops_by_id('call') + print loop.ops_by_id('call') + ops = log.opnames(loop.ops_by_id('call')) + guards = [ops for ops in ops if ops.startswith('guard')] + print guards + assert len(guards) <= 20 + + def test_stararg_virtual(self): + def main(x): + def g(*args): + return len(args) + def h(a, b, c): + return c + # + s = 0 + for i in range(x): + l = [i, x, 2] + s += g(*l) # ID: g1 + s += h(*l) # ID: h1 + s += g(i, x, 2) # ID: g2 + a = 0 + for i in range(x): + l = [x, 2] + s += g(i, *l) # ID: g3 + s += h(i, *l) # ID: h2 + a = 0 + return s + # + log = self.run(main, [1000]) + assert log.result == 13000 + loop0, = log.loops_by_id('g1') + assert loop0.match_by_id('g1', """ + i20 = force_token() + i22 = int_add_ovf(i8, 3) + guard_no_overflow(descr=...) + """) + assert loop0.match_by_id('h1', """ + i20 = force_token() + i22 = int_add_ovf(i8, 2) + guard_no_overflow(descr=...) + """) + assert loop0.match_by_id('g2', """ + i27 = force_token() + i29 = int_add_ovf(i26, 3) + guard_no_overflow(descr=...) + """) + # + loop1, = log.loops_by_id('g3') + assert loop1.match_by_id('g3', """ + i21 = force_token() + i23 = int_add_ovf(i9, 3) + guard_no_overflow(descr=...) + """) + assert loop1.match_by_id('h2', """ + i25 = force_token() + i27 = int_add_ovf(i23, 2) + guard_no_overflow(descr=...) + """) + + def test_stararg(self): + def main(x): + def g(*args): + return args[-1] + def h(*args): + return len(args) + # + s = 0 + l = [] + i = 0 + while i < x: + l.append(1) + s += g(*l) # ID: g + i = h(*l) # ID: h + a = 0 + return s + # + log = self.run(main, [1000]) + assert log.result == 1000 + loop, = log.loops_by_id('g') + ops_g = log.opnames(loop.ops_by_id('g')) + ops_h = log.opnames(loop.ops_by_id('h')) + ops = ops_g + ops_h + assert 'new_with_vtable' not in ops + assert 'call_may_force' not in ops + + def test_call_builtin_function(self): + def main(n): + i = 2 + l = [] + while i < n: + i += 1 + l.append(i) # ID: append + a = 0 + return i, len(l) + # + log = self.run(main, [1000]) + assert log.result == (1000, 998) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('append', """ + i13 = getfield_gc(p8, descr=) + i15 = int_add(i13, 1) + call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) + guard_no_exception(descr=...) + p17 = getfield_gc(p8, descr=) + p19 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p19, i12, descr=) + setarrayitem_gc(p17, i13, p19, descr=) + """) + + def test_blockstack_virtualizable(self): + def main(n): + from pypyjit import residual_call + i = 0 + while i < n: + try: + residual_call(len, []) # ID: call + except: + pass + i += 1 + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_id('call') + assert loop.match_by_id('call', opcode='CALL_FUNCTION', expected_src=""" + # make sure that the "block" is not allocated + ... + i20 = force_token() + setfield_gc(p0, i20, descr=) + p22 = new_with_vtable(19511408) + p24 = new_array(1, descr=) + p26 = new_with_vtable(ConstClass(W_ListObject)) + p27 = new(descr=) + p29 = new_array(0, descr=) + setfield_gc(p27, p29, descr=) + setfield_gc(p26, p27, descr=<.* .*W_ListObject.inst_wrappeditems .*>) + setarrayitem_gc(p24, 0, p26, descr=) + setfield_gc(p22, p24, descr=) + p32 = call_may_force(11376960, p18, p22, descr=) + ... + """) + + def test_func_defaults(self): + def main(n): + i = 1 + while i < n: + i += len(xrange(i+1)) - i + return i + + log = self.run(main, [10000]) + assert log.result == 10000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i5, i6) + guard_true(i10, descr=...) + guard_not_invalidated(descr=...) + i120 = int_add(i5, 1) + --TICK-- + jump(..., descr=) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -0,0 +1,25 @@ + +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestDicts(BaseTestPyPyC): + def test_strdict(self): + def fn(n): + import sys + d = {} + class A(object): + pass + a = A() + a.x = 1 + for s in sys.modules.keys() * 1000: + inc = a.x # ID: look + d[s] = d.get(s, 0) + inc + return sum(d.values()) + # + log = self.run(fn, [1000]) + assert log.result % 1000 == 0 + loop, = log.loops_by_filename(self.filepath) + ops = loop.ops_by_id('look') + assert log.opnames(ops) == ['setfield_gc', + 'guard_not_invalidated'] diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py @@ -0,0 +1,93 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestException(BaseTestPyPyC): + + def test_cmp_exc(self): + def f1(n): + # So we don't get a LOAD_GLOBAL op + KE = KeyError + i = 0 + while i < n: + try: + raise KE + except KE: # ID: except + i += 1 + return i + + log = self.run(f1, [10000]) + assert log.result == 10000 + loop, = log.loops_by_id("except") + ops = list(loop.ops_by_id("except", opcode="COMPARE_OP")) + assert ops == [] + + def test_exception_inside_loop_1(self): + def main(n): + while n: + try: + raise ValueError + except ValueError: + pass + n -= 1 + return n + # + log = self.run(main, [1000]) + assert log.result == 0 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i5 = int_is_true(i3) + guard_true(i5, descr=...) + guard_not_invalidated(descr=...) + --EXC-TICK-- + i12 = int_sub_ovf(i3, 1) + guard_no_overflow(descr=...) + --TICK-- + jump(..., descr=) + """) + + def test_exception_inside_loop_2(self): + def main(n): + def g(n): + raise ValueError(n) # ID: raise + def f(n): + g(n) + # + while n: + try: + f(n) + except ValueError: + pass + n -= 1 + return n + # + log = self.run(main, [1000]) + assert log.result == 0 + loop, = log.loops_by_filename(self.filepath) + ops = log.opnames(loop.ops_by_id('raise')) + assert 'new' not in ops + + def test_reraise(self): + def f(n): + i = 0 + while i < n: + try: + try: + raise KeyError + except KeyError: + raise + except KeyError: + i += 1 + return i + + log = self.run(f, [100000]) + assert log.result == 100000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i4, i5) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) + --EXC-TICK-- + i14 = int_add(i4, 1) + --TICK-- + jump(..., descr=) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -0,0 +1,30 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGlobals(BaseTestPyPyC): + def test_load_builtin(self): + def main(n): + import pypyjit + + i = 0 + while i < n: + l = len # ID: loadglobal + i += pypyjit.residual_call(l, "a") + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("loadglobal", """ + p10 = getfield_gc(p0, descr=) + guard_value(p10, ConstPtr(ptr11), descr=...) + p12 = getfield_gc(p10, descr=) + guard_value(p12, ConstPtr(ptr13), descr=...) + p15 = getfield_gc(ConstPtr(ptr14), descr=) + guard_isnull(p15, descr=...) + guard_not_invalidated(descr=...) + p19 = getfield_gc(ConstPtr(p17), descr=) + guard_value(p19, ConstPtr(ptr20), descr=...) + p22 = getfield_gc(ConstPtr(ptr21), descr=) + guard_nonnull(p22, descr=...) + """) \ No newline at end of file diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -0,0 +1,46 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestImport(BaseTestPyPyC): + + def test_import_in_function(self): + def main(n): + i = 0 + while i < n: + from sys import version # ID: import + i += 1 + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_id('import') + assert loop.match_by_id('import', """ + guard_not_invalidated(descr=...) + p11 = getfield_gc(ConstPtr(ptr10), descr=) + guard_value(p11, ConstPtr(ptr12), descr=...) + p14 = getfield_gc(ConstPtr(ptr13), descr=) + p16 = getfield_gc(ConstPtr(ptr15), descr=) + guard_value(p14, ConstPtr(ptr17), descr=...) + guard_isnull(p16, descr=...) + """) + + def test_import_fast_path(self, tmpdir): + pkg = tmpdir.join('mypkg').ensure(dir=True) + pkg.join('__init__.py').write("") + pkg.join('mod.py').write(str(py.code.Source(""" + def do_the_import(): + import sys + """))) + def main(path, n): + import sys + sys.path.append(path) + from mypkg.mod import do_the_import + for i in range(n): + do_the_import() + # + log = self.run(main, [str(tmpdir), 300]) + loop, = log.loops_by_filename(self.filepath) + # this is a check for a slow-down that introduced a + # call_may_force(absolute_import_with_lock). + for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")): + assert 'call' not in opname # no call-like opcode diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -0,0 +1,201 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestInstance(BaseTestPyPyC): + + def test_virtual_instance(self): + def main(n): + class A(object): + pass + # + i = 0 + while i < n: + a = A() + assert isinstance(a, A) + assert not isinstance(a, int) + a.x = 2 + i = i + a.x + return i + # + log = self.run(main, [1000], threshold = 400) + assert log.result == 1000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i5, i6) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) + i9 = int_add_ovf(i5, 2) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, i9, i6, descr=) + """) + + def test_load_attr(self): + src = ''' + class A(object): + pass + a = A() + a.x = 2 + def main(n): + i = 0 + while i < n: + i = i + a.x + return i + ''' + log = self.run(src, [1000]) + assert log.result == 1000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i9 = int_lt(i5, i6) + guard_true(i9, descr=...) + guard_not_invalidated(descr=...) + i10 = int_add_ovf(i5, i7) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) + """) + + def test_getattr_with_dynamic_attribute(self): + src = """ + class A(object): + pass + + l = ["x", "y"] + + def main(): + sum = 0 + a = A() + a.a1 = 0 + a.a2 = 0 + a.a3 = 0 + a.a4 = 0 + a.a5 = 0 # workaround, because the first five attributes need a promotion + a.x = 1 + a.y = 2 + i = 0 + while i < 500: + name = l[i % 2] + sum += getattr(a, name) + i += 1 + return sum + """ + log = self.run(src, []) + assert log.result == 250 + 250*2 + loops = log.loops_by_filename(self.filepath) + assert len(loops) == 1 + + def test_mutate_class(self): + def fn(n): + class A(object): + count = 1 + def __init__(self, a): + self.a = a + def f(self): + return self.count + i = 0 + a = A(1) + while i < n: + A.count += 1 # ID: mutate + i = a.f() # ID: meth1 + return i + # + log = self.run(fn, [1000], threshold=10) + assert log.result == 1000 + # + # first, we test the entry bridge + # ------------------------------- + entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) + ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') + assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', + 'getfield_gc', 'guard_nonnull_class'] + # the STORE_ATTR is folded away + assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] + # + # then, the actual loop + # ---------------------- + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i9 = int_lt(i8, i7) + guard_true(i9, descr=.*) + guard_not_invalidated(descr=.*) + i11 = int_add(i8, 1) + i12 = force_token() + --TICK-- + p20 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p20, i11, descr=) + setfield_gc(ConstPtr(ptr21), p20, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) + """) + + def test_oldstyle_newstyle_mix(self): + def main(): + class A: + pass + + class B(object, A): + def __init__(self, x): + self.x = x + + i = 0 + b = B(1) + while i < 100: + v = b.x # ID: loadattr + i += v + return i + + log = self.run(main, [], threshold=80) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('loadattr', + ''' + guard_not_invalidated(descr=...) + i19 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) + guard_no_exception(descr=...) + i21 = int_and(i19, _) + i22 = int_is_true(i21) + guard_true(i22, descr=...) + i26 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) + guard_no_exception(descr=...) + i28 = int_and(i26, _) + i29 = int_is_true(i28) + guard_true(i29, descr=...) + ''') + + def test_python_contains(self): + def main(): + class A(object): + def __contains__(self, v): + return True + + i = 0 + a = A() + while i < 100: + i += i in a # ID: contains + b = 0 # to make sure that JUMP_ABSOLUTE is not part of the ID + + log = self.run(main, [], threshold=80) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("contains", """ + guard_not_invalidated(descr=...) + i11 = force_token() + i12 = int_add_ovf(i5, i7) + guard_no_overflow(descr=...) + """) + + def test_id_compare_optimization(self): + def main(): + class A(object): + pass + # + i = 0 + a = A() + while i < 300: + new_a = A() + if new_a != a: # ID: compare + pass + i += 1 + return i + # + log = self.run(main, []) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("compare", "") # optimized away + diff --git a/pypy/module/pypyjit/test_pypy_c/test_intbound.py b/pypy/module/pypyjit/test_pypy_c/test_intbound.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_intbound.py @@ -0,0 +1,296 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestIntbound(BaseTestPyPyC): + + def test_intbound_simple(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + ops = ('<', '>', '<=', '>=', '==', '!=') + nbr = (3, 7) + for o1 in ops: + for o2 in ops: + for n1 in nbr: + for n2 in nbr: + src = ''' + def f(i): + a, b = 3, 3 + if i %s %d: + a = 0 + else: + a = 1 + if i %s %d: + b = 0 + else: + b = 1 + return a + b * 2 + + def main(): + res = [0] * 4 + idx = [] + for i in range(15): + idx.extend([i] * 15) + for i in idx: + res[f(i)] += 1 + return res + + ''' % (o1, n1, o2, n2) + yield self.run_and_check, src + + def test_intbound_addsub_mix(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + tests = ('i > 4', 'i > 2', 'i + 1 > 2', '1 + i > 4', + 'i - 1 > 1', '1 - i > 1', '1 - i < -3', + 'i == 1', 'i == 5', 'i != 1', '-2 * i < -4') + for t1 in tests: + for t2 in tests: + src = ''' + def f(i): + a, b = 3, 3 + if %s: + a = 0 + else: + a = 1 + if %s: + b = 0 + else: + b = 1 + return a + b * 2 + + def main(): + res = [0] * 4 + idx = [] + for i in range(15): + idx.extend([i] * 15) + for i in idx: + res[f(i)] += 1 + return res + + ''' % (t1, t2) + yield self.run_and_check, src + + def test_intbound_gt(self): + def main(n): + i, a, b = 0, 0, 0 + while i < n: + if i > -1: + a += 1 + if i > -2: + b += 1 + i += 1 + return (a, b) + # + log = self.run(main, [300]) + assert log.result == (300, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, i9) + guard_true(i10, descr=...) + i12 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i14 = int_add_ovf(i6, 1) + guard_no_overflow(descr=...) + i17 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i14, i12, i17, p8, i9, descr=) + """) + + def test_intbound_sub_lt(self): + def main(): + i, a = 0, 0 + while i < 300: + if i - 10 < 295: + a += 1 + i += 1 + return a + # + log = self.run(main, []) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i5, 300) + guard_true(i7, descr=...) + i9 = int_sub_ovf(i5, 10) + guard_no_overflow(descr=...) + i11 = int_add_ovf(i4, 1) + guard_no_overflow(descr=...) + i13 = int_add(i5, 1) + --TICK-- + jump(p0, p1, p2, p3, i11, i13, descr=) + """) + + def test_intbound_addsub_ge(self): + def main(n): + i, a, b = 0, 0, 0 + while i < n: + if i + 5 >= 5: + a += 1 + if i - 1 >= -1: + b += 1 + i += 1 + return (a, b) + # + log = self.run(main, [300]) + assert log.result == (300, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, i9) + guard_true(i10, descr=...) + i12 = int_add_ovf(i8, 5) + guard_no_overflow(descr=...) + i14 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i16 = int_add_ovf(i6, 1) + guard_no_overflow(descr=...) + i19 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i16, i14, i19, p8, i9, descr=) + """) + + def test_intbound_addmul_ge(self): + def main(n): + i, a, b = 0, 0, 0 + while i < 300: + if i + 5 >= 5: + a += 1 + if 2 * i >= 0: + b += 1 + i += 1 + return (a, b) + # + log = self.run(main, [300]) + assert log.result == (300, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, 300) + guard_true(i10, descr=...) + i12 = int_add(i8, 5) + i14 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i16 = int_lshift(i8, 1) + i18 = int_add_ovf(i6, 1) + guard_no_overflow(descr=...) + i21 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i18, i14, i21, p8, descr=) + """) + + def test_intbound_eq(self): + def main(a, n): + i, s = 0, 0 + while i < 300: + if a == 7: + s += a + 1 + elif i == 10: + s += i + else: + s += 1 + i += 1 + return s + # + log = self.run(main, [7, 300]) + assert log.result == main(7, 300) + log = self.run(main, [10, 300]) + assert log.result == main(10, 300) + log = self.run(main, [42, 300]) + assert log.result == main(42, 300) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i8, 300) + guard_true(i10, descr=...) + i12 = int_eq(i8, 10) + guard_false(i12, descr=...) + i14 = int_add_ovf(i7, 1) + guard_no_overflow(descr=...) + i16 = int_add(i8, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p6, i14, i16, p8, descr=) + """) + + def test_intbound_mul(self): + def main(a): + i, s = 0, 0 + while i < 300: + assert i >= 0 + if 2 * i < 30000: + s += 1 + else: + s += a + i += 1 + return s + # + log = self.run(main, [7]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i8 = int_lt(i6, 300) + guard_true(i8, descr=...) + i10 = int_lshift(i6, 1) + i12 = int_add_ovf(i5, 1) + guard_no_overflow(descr=...) + i14 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i12, i14, descr=) + """) + + def test_assert(self): + def main(a): + i, s = 0, 0 + while i < 300: + assert a == 7 + s += a + 1 + i += 1 + return s + log = self.run(main, [7]) + assert log.result == 300*8 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i8 = int_lt(i6, 300) + guard_true(i8, descr=...) + i10 = int_add_ovf(i5, 8) + guard_no_overflow(descr=...) + i12 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, i10, i12, descr=) + """) + + def test_xor(self): + def main(b): + a = sa = 0 + while a < 300: + if a > 0: # Specialises the loop + pass + if b > 10: + pass + if a^b >= 0: # ID: guard + sa += 1 + sa += a^a # ID: a_xor_a + a += 1 + return sa + + log = self.run(main, [11]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # if both are >=0, a^b is known to be >=0 + # note that we know that b>10 + assert loop.match_by_id('guard', """ + i10 = int_xor(i5, i7) + """) + # + # x^x is always optimized to 0 + assert loop.match_by_id('a_xor_a', "") + + log = self.run(main, [9]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # we don't know that b>10, hence we cannot optimize it + assert loop.match_by_id('guard', """ + i10 = int_xor(i5, i7) + i12 = int_ge(i10, 0) + guard_true(i12, descr=...) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -0,0 +1,68 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestMinMax(BaseTestPyPyC): + + def test_min_max(self): + def main(): + i=0 + sa=0 + while i < 300: + sa+=min(max(i, 3000), 4000) + i+=1 + return sa + log = self.run(main, []) + assert log.result == 300*3000 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i7 = int_lt(i4, 300) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) + i9 = int_add_ovf(i5, 3000) + guard_no_overflow(descr=...) + i11 = int_add(i4, 1) + --TICK-- + jump(p0, p1, p2, p3, i11, i9, descr=) + """) + + def test_silly_max(self): + def main(): + i = 2 + sa = 0 + while i < 300: + lst = range(i) + sa += max(*lst) # ID: max + i += 1 + return sa + log = self.run(main, []) + assert log.result == main() + loop, = log.loops_by_filename(self.filepath) + # We dont want too many guards, but a residual call to min_max_loop + guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] + assert len(guards) < 20 + assert loop.match_by_id('max',""" + ... + p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) + ... + """) + + def test_iter_max(self): + def main(): + i = 2 + sa = 0 + while i < 300: + lst = range(i) + sa += max(lst) # ID: max + i += 1 + return sa + log = self.run(main, []) + assert log.result == main() + loop, = log.loops_by_filename(self.filepath) + # We dont want too many guards, but a residual call to min_max_loop + guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] + assert len(guards) < 20 + assert loop.match_by_id('max',""" + ... + p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py rename from pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py rename to pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -1,13 +1,8 @@ -import py, sys, re -import subprocess -from lib_pypy import disassembler -from pypy.tool.udir import udir -from pypy.tool import logparser -from pypy.module.pypyjit.test_pypy_c.model import Log -from pypy.module.pypyjit.test_pypy_c.test_model import BaseTestPyPyC +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC -class TestPyPyCNew(BaseTestPyPyC): +class TestMisc(BaseTestPyPyC): def test_f1(self): def f1(n): "Arbitrary test function." @@ -76,377 +71,6 @@ """) - def test_recursive_call(self): - def fn(): - def rec(n): - if n == 0: - return 0 - return 1 + rec(n-1) - # - # this loop is traced and then aborted, because the trace is too - # long. But then "rec" is marked as "don't inline" - i = 0 - j = 0 - while i < 20: - i += 1 - j += rec(100) - # - # next time we try to trace "rec", instead of inlining we compile - # it separately and generate a call_assembler - i = 0 - j = 0 - while i < 20: - i += 1 - j += rec(100) # ID: call_rec - a = 0 - return j - # - log = self.run(fn, [], threshold=18) - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('call_rec', """ - ... - p53 = call_assembler(..., descr=...) - guard_not_forced(descr=...) - guard_no_exception(descr=...) - ... - """) - - def test_cmp_exc(self): - def f1(n): - # So we don't get a LOAD_GLOBAL op - KE = KeyError - i = 0 - while i < n: - try: - raise KE - except KE: # ID: except - i += 1 - return i - - log = self.run(f1, [10000]) - assert log.result == 10000 - loop, = log.loops_by_id("except") - ops = list(loop.ops_by_id("except", opcode="COMPARE_OP")) - assert ops == [] - - def test_simple_call(self): - src = """ - OFFSET = 0 - def f(i): - return i + 1 + OFFSET # ID: add - def main(n): - i = 0 - while i < n+OFFSET: # ID: cond - i = f(f(i)) # ID: call - a = 0 - return i - """ - log = self.run(src, [1000], threshold=400) - assert log.result == 1000 - # first, we test what is inside the entry bridge - # ----------------------------------------------- - entry_bridge, = log.loops_by_id('call', is_entry_bridge=True) - # LOAD_GLOBAL of OFFSET - ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", - "getfield_gc", "guard_value", - "getfield_gc", "guard_isnull", - "getfield_gc", "guard_nonnull_class"] - # LOAD_GLOBAL of OFFSET but in different function partially folded - # away - # XXX could be improved - ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_isnull"] - # - # two LOAD_GLOBAL of f, the second is folded away - ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["getfield_gc", "guard_nonnull_class"] - # - assert entry_bridge.match_by_id('call', """ - p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) - p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) - p35 = getfield_gc(p29, descr=) - p36 = getfield_gc(p29, descr=) - p38 = call(ConstClass(getexecutioncontext), descr=) - p39 = getfield_gc(p38, descr=) - i40 = force_token() - p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) - i42 = getfield_gc(p38, descr=) - i43 = int_is_zero(i42) - guard_true(i43, descr=) - i50 = force_token() - """) - # - # then, we test the actual loop - # ----------------------------- - loop, = log.loops_by_id('call') - assert loop.match(""" - i12 = int_lt(i5, i6) - guard_true(i12, descr=) - i13 = force_token() - i15 = int_add(i5, 1) - i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) - i18 = force_token() - i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=) - i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) - """) - - def test_method_call(self): - def fn(n): - class A(object): - def __init__(self, a): - self.a = a - def f(self, i): - return self.a + i - i = 0 - a = A(1) - while i < n: - x = a.f(i) # ID: meth1 - i = a.f(x) # ID: meth2 - return i - # - log = self.run(fn, [1000], threshold=400) - assert log.result == 1000 - # - # first, we test the entry bridge - # ------------------------------- - entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) - ops = entry_bridge.ops_by_id('meth1', opcode='LOOKUP_METHOD') - assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', - 'guard_not_invalidated'] - # the second LOOKUP_METHOD is folded away - assert list(entry_bridge.ops_by_id('meth2', opcode='LOOKUP_METHOD')) == [] - # - # then, the actual loop - # ---------------------- - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i15 = int_lt(i6, i9) - guard_true(i15, descr=) - guard_not_invalidated(descr=) - i16 = force_token() - i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) - i18 = force_token() - i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) - """) - - def test_static_classmethod_call(self): - def fn(n): - class A(object): - @classmethod - def f(cls, i): - return i + (cls is A) + 1 - @staticmethod - def g(i): - return i - 1 - # - i = 0 - a = A() - while i < n: - x = a.f(i) - i = a.g(x) - return i - # - log = self.run(fn, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i14 = int_lt(i6, i9) - guard_true(i14, descr=) - guard_not_invalidated(descr=) - i15 = force_token() - i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) - i18 = force_token() - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=) - """) - - def test_default_and_kw(self): - def main(n): - def f(i, j=1): - return i + j - # - i = 0 - while i < n: - i = f(f(i), j=1) # ID: call - a = 0 - return i - # - log = self.run(main, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_id('call') - assert loop.match_by_id('call', """ - i14 = force_token() - i16 = force_token() - """) - - def test_kwargs(self): - # this is not a very precise test, could be improved - def main(x): - def g(**args): - return len(args) - # - s = 0 - d = {} - for i in range(x): - s += g(**d) # ID: call - d[str(i)] = i - if i % 100 == 99: - d = {} - return s - # - log = self.run(main, [1000], threshold=400) - assert log.result == 49500 - loop, = log.loops_by_id('call') - ops = log.opnames(loop.ops_by_id('call')) - guards = [ops for ops in ops if ops.startswith('guard')] - assert len(guards) <= 5 - - def test_stararg_virtual(self): - def main(x): - def g(*args): - return len(args) - def h(a, b, c): - return c - # - s = 0 - for i in range(x): - l = [i, x, 2] - s += g(*l) # ID: g1 - s += h(*l) # ID: h1 - s += g(i, x, 2) # ID: g2 - a = 0 - for i in range(x): - l = [x, 2] - s += g(i, *l) # ID: g3 - s += h(i, *l) # ID: h2 - a = 0 - return s - # - log = self.run(main, [1000], threshold=400) - assert log.result == 13000 - loop0, = log.loops_by_id('g1') - assert loop0.match_by_id('g1', """ - i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) - i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) - """) - assert loop0.match_by_id('h1', """ - i20 = force_token() - i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) - """) - assert loop0.match_by_id('g2', """ - i27 = force_token() - i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) - """) - # - loop1, = log.loops_by_id('g3') - assert loop1.match_by_id('g3', """ - i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) - """) - assert loop1.match_by_id('h2', """ - i25 = force_token() - i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) - """) - - def test_stararg(self): - def main(x): - def g(*args): - return args[-1] - def h(*args): - return len(args) - # - s = 0 - l = [] - i = 0 - while i < x: - l.append(1) - s += g(*l) # ID: g - i = h(*l) # ID: h - a = 0 - return s - # - log = self.run(main, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_id('g') - ops_g = log.opnames(loop.ops_by_id('g')) - ops_h = log.opnames(loop.ops_by_id('h')) - ops = ops_g + ops_h - assert 'new_with_vtable' not in ops - assert 'call_may_force' not in ops - - def test_virtual_instance(self): - def main(n): - class A(object): - pass - # - i = 0 - while i < n: - a = A() - assert isinstance(a, A) - assert not isinstance(a, int) - a.x = 2 - i = i + a.x - return i - # - log = self.run(main, [1000], threshold = 400) - assert log.result == 1000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i5, i6) - guard_true(i7, descr=) - guard_not_invalidated(descr=) - i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, i9, i6, descr=) - """) - - def test_load_attr(self): - src = ''' - class A(object): - pass - a = A() - a.x = 2 - def main(n): - i = 0 - while i < n: - i = i + a.x - return i - ''' - log = self.run(src, [1000], threshold=400) - assert log.result == 1000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i9 = int_lt(i5, i6) - guard_true(i9, descr=) - guard_not_invalidated(descr=) - i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) - --TICK-- - jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) - """) - def test_mixed_type_loop(self): def main(n): i = 0.0 @@ -455,40 +79,17 @@ i = j + i return i # - log = self.run(main, [1000], threshold=400) + log = self.run(main, [1000]) assert log.result == 1000.0 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = float_lt(f5, f7) - guard_true(i9, descr=) + guard_true(i9, descr=...) f10 = float_add(f8, f5) --TICK-- jump(p0, p1, p2, p3, p4, f10, p6, f7, f8, descr=) """) - def test_call_builtin_function(self): - def main(n): - i = 2 - l = [] - while i < n: - i += 1 - l.append(i) # ID: append - a = 0 - return i, len(l) - # - log = self.run(main, [1000], threshold=400) - assert log.result == (1000, 998) - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('append', """ - i13 = getfield_gc(p8, descr=) - i15 = int_add(i13, 1) - call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) - guard_no_exception(descr=) - p17 = getfield_gc(p8, descr=) - p19 = new_with_vtable(ConstClass(W_IntObject)) - setfield_gc(p19, i12, descr=) - setarrayitem_gc(p17, i13, p19, descr=) - """) def test_range_iter(self): def main(n): @@ -501,98 +102,28 @@ a = 0 return s # - log = self.run(main, [1000], threshold=400) + log = self.run(main, [1000]) assert log.result == 1000 * 999 / 2 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i11, i12) - guard_false(i16, descr=) + guard_false(i16, descr=...) i17 = int_mul(i11, i14) i18 = int_add(i15, i17) i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=) + guard_not_invalidated(descr=...) i23 = int_lt(i18, 0) - guard_false(i23, descr=) + guard_false(i23, descr=...) i25 = int_ge(i18, i9) - guard_false(i25, descr=) + guard_false(i25, descr=...) i27 = int_add_ovf(i7, i18) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) - def test_exception_inside_loop_1(self): - def main(n): - while n: - try: - raise ValueError - except ValueError: - pass - n -= 1 - return n - # - log = self.run(main, [1000], threshold=400) - assert log.result == 0 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i5 = int_is_true(i3) - guard_true(i5, descr=) - guard_not_invalidated(descr=) - --EXC-TICK-- - i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) - --TICK-- - jump(..., descr=) - """) - - def test_exception_inside_loop_2(self): - def main(n): - def g(n): - raise ValueError(n) # ID: raise - def f(n): - g(n) - # - while n: - try: - f(n) - except ValueError: - pass - n -= 1 - return n - # - log = self.run(main, [1000], threshold=400) - assert log.result == 0 - loop, = log.loops_by_filename(self.filepath) - ops = log.opnames(loop.ops_by_id('raise')) - assert 'new' not in ops - - def test_reraise(self): - def f(n): - i = 0 - while i < n: - try: - try: - raise KeyError - except KeyError: - raise - except KeyError: - i += 1 - return i - - log = self.run(f, [100000]) - assert log.result == 100000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i4, i5) - guard_true(i7, descr=) - guard_not_invalidated(descr=) - --EXC-TICK-- - i14 = int_add(i4, 1) - --TICK-- - jump(..., descr=) - """) def test_chain_of_guards(self): src = """ @@ -612,445 +143,11 @@ i += 1 return sum """ - log = self.run(src, [0], threshold=400) + log = self.run(src, [0]) assert log.result == 500*3 loops = log.loops_by_filename(self.filepath) assert len(loops) == 1 - def test_getattr_with_dynamic_attribute(self): - src = """ - class A(object): - pass - - l = ["x", "y"] - - def main(): - sum = 0 - a = A() - a.a1 = 0 - a.a2 = 0 - a.a3 = 0 - a.a4 = 0 - a.a5 = 0 # workaround, because the first five attributes need a promotion - a.x = 1 - a.y = 2 - i = 0 - while i < 500: - name = l[i % 2] - sum += getattr(a, name) - i += 1 - return sum - """ - log = self.run(src, [], threshold=400) - assert log.result == 250 + 250*2 - loops = log.loops_by_filename(self.filepath) - assert len(loops) == 1 - - def test_blockstack_virtualizable(self): - def main(n): - from pypyjit import residual_call - i = 0 - while i < n: - try: - residual_call(len, []) # ID: call - except: - pass - i += 1 - return i - # - log = self.run(main, [500], threshold=400) - assert log.result == 500 - loop, = log.loops_by_id('call') - assert loop.match_by_id('call', opcode='CALL_FUNCTION', expected_src=""" - # make sure that the "block" is not allocated - ... - i20 = force_token() - setfield_gc(p0, i20, descr=) - p22 = new_with_vtable(19511408) - p24 = new_array(1, descr=) - p26 = new_with_vtable(ConstClass(W_ListObject)) - p27 = new(descr=) - p29 = new_array(0, descr=) - setfield_gc(p27, p29, descr=) - setfield_gc(p26, p27, descr=<.* .*W_ListObject.inst_wrappeditems .*>) - setarrayitem_gc(p24, 0, p26, descr=) - setfield_gc(p22, p24, descr=) - p32 = call_may_force(11376960, p18, p22, descr=) - ... - """) - - def test_import_in_function(self): - def main(n): - i = 0 - while i < n: - from sys import version # ID: import - i += 1 - return i - # - log = self.run(main, [500], threshold=400) - assert log.result == 500 - loop, = log.loops_by_id('import') - assert loop.match_by_id('import', """ - p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) - p14 = getfield_gc(ConstPtr(ptr13), descr=) - p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) - """) - - def test_import_fast_path(self, tmpdir): - pkg = tmpdir.join('mypkg').ensure(dir=True) - pkg.join('__init__.py').write("") - pkg.join('mod.py').write(str(py.code.Source(""" - def do_the_import(): - import sys - """))) - def main(path, n): - import sys - sys.path.append(path) - from mypkg.mod import do_the_import - for i in range(n): - do_the_import() - # - log = self.run(main, [str(tmpdir), 300], threshold=200) - loop, = log.loops_by_filename(self.filepath) - # this is a check for a slow-down that introduced a - # call_may_force(absolute_import_with_lock). - for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")): - assert 'call' not in opname # no call-like opcode - - def test_arraycopy_disappears(self): - def main(n): - i = 0 - while i < n: - t = (1, 2, 3, i + 1) - t2 = t[:] - del t - i = t2[3] - del t2 - return i - # - log = self.run(main, [500], threshold=400) - assert log.result == 500 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i5, i6) - guard_true(i7, descr=) - i9 = int_add(i5, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, i9, i6, descr=) - """) - - def test_boolrewrite_inverse(self): - """ - Test for this case:: - guard(i < x) - ... - guard(i >= y) - - where x and y can be either constants or variables. There are cases in - which the second guard is proven to be always true. - """ - - for a, b, res, opt_expected in (('2000', '2000', 20001000, True), - ( '500', '500', 15001500, True), - ( '300', '600', 16001700, False), - ( 'a', 'b', 16001700, False), - ( 'a', 'a', 13001700, True)): - src = """ - def main(): - sa = 0 - a = 300 - b = 600 - for i in range(1000): - if i < %s: # ID: lt - sa += 1 - else: - sa += 2 - # - if i >= %s: # ID: ge - sa += 10000 - else: - sa += 20000 - return sa - """ % (a, b) - # - log = self.run(src, [], threshold=400) - assert log.result == res - loop, = log.loops_by_filename(self.filepath) - le_ops = log.opnames(loop.ops_by_id('lt')) - ge_ops = log.opnames(loop.ops_by_id('ge')) - assert le_ops.count('int_lt') == 1 - # - if opt_expected: - assert ge_ops.count('int_ge') == 0 - else: - # if this assert fails it means that the optimization was - # applied even if we don't expect to. Check whether the - # optimization is valid, and either fix the code or fix the - # test :-) - assert ge_ops.count('int_ge') == 1 - - def test_boolrewrite_reflex(self): - """ - Test for this case:: - guard(i < x) - ... - guard(y > i) - - where x and y can be either constants or variables. There are cases in - which the second guard is proven to be always true. - """ - for a, b, res, opt_expected in (('2000', '2000', 10001000, True), - ( '500', '500', 15001500, True), - ( '300', '600', 14001700, False), - ( 'a', 'b', 14001700, False), - ( 'a', 'a', 17001700, True)): - - src = """ - def main(): - sa = 0 - a = 300 - b = 600 - for i in range(1000): - if i < %s: # ID: lt - sa += 1 - else: - sa += 2 - if %s > i: # ID: gt - sa += 10000 - else: - sa += 20000 - return sa - """ % (a, b) - log = self.run(src, [], threshold=400) - assert log.result == res - loop, = log.loops_by_filename(self.filepath) - le_ops = log.opnames(loop.ops_by_id('lt')) - gt_ops = log.opnames(loop.ops_by_id('gt')) - assert le_ops.count('int_lt') == 1 - # - if opt_expected: - assert gt_ops.count('int_gt') == 0 - else: - # if this assert fails it means that the optimization was - # applied even if we don't expect to. Check whether the - # optimization is valid, and either fix the code or fix the - # test :-) - assert gt_ops.count('int_gt') == 1 - - - def test_boolrewrite_allcases_inverse(self): - """ - Test for this case:: - guard(i < x) - ... - guard(i > y) - - with all possible combination of binary comparison operators. This - test only checks that we get the expected result, not that any - optimization has been applied. - """ - ops = ('<', '>', '<=', '>=', '==', '!=') - for op1 in ops: - for op2 in ops: - for a,b in ((500, 500), (300, 600)): - src = """ - def main(): - sa = 0 - for i in range(300): - if i %s %d: - sa += 1 - else: - sa += 2 - if i %s %d: - sa += 10000 - else: - sa += 20000 - return sa - """ % (op1, a, op2, b) - self.run_and_check(src, threshold=200) - - src = """ - def main(): - sa = 0 - i = 0.0 - while i < 250.0: - if i %s %f: - sa += 1 - else: - sa += 2 - if i %s %f: - sa += 10000 - else: - sa += 20000 - i += 0.25 - return sa - """ % (op1, float(a)/4.0, op2, float(b)/4.0) - self.run_and_check(src, threshold=300) - - - def test_boolrewrite_allcases_reflex(self): - """ - Test for this case:: - guard(i < x) - ... - guard(x > i) - - with all possible combination of binary comparison operators. This - test only checks that we get the expected result, not that any - optimization has been applied. - """ - ops = ('<', '>', '<=', '>=', '==', '!=') - for op1 in ops: - for op2 in ops: - for a,b in ((500, 500), (300, 600)): - src = """ - def main(): - sa = 0 - for i in range(300): - if i %s %d: - sa += 1 - else: - sa += 2 - if %d %s i: - sa += 10000 - else: - sa += 20000 - return sa - """ % (op1, a, b, op2) - self.run_and_check(src, threshold=200) - - src = """ - def main(): - sa = 0 - i = 0.0 - while i < 250.0: - if i %s %f: - sa += 1 - else: - sa += 2 - if %f %s i: - sa += 10000 - else: - sa += 20000 - i += 0.25 - return sa - """ % (op1, float(a)/4.0, float(b)/4.0, op2) - self.run_and_check(src, threshold=300) - - def test_boolrewrite_ptr(self): - """ - This test only checks that we get the expected result, not that any - optimization has been applied. - """ - compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b') - for e1 in compares: - for e2 in compares: - src = """ - class tst(object): - pass - def main(): - a = tst() - b = tst() - c = tst() - sa = 0 - for i in range(300): - if %s: - sa += 1 - else: - sa += 2 - if %s: - sa += 10000 - else: - sa += 20000 - if i > 750: - a = b - return sa - """ % (e1, e2) - self.run_and_check(src, threshold=200) - - def test_array_sum(self): - def main(): - from array import array - img = array("i", range(128) * 5) * 480 - l, i = 0, 0 - while i < len(img): - l += img[i] - i += 1 - return l - # - log = self.run(main, []) - assert log.result == 19507200 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i13 = int_lt(i7, i9) - guard_true(i13, descr=) - i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) - i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) - i18 = int_add(i7, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i18, i16, i9, i10, descr=) - """) - - def test_array_intimg(self): - def main(): - from array import array - img = array('i', range(3)) * (350 * 480) - intimg = array('i', (0,)) * (640 * 480) - l, i = 0, 640 - while i < 640 * 480: - assert len(img) == 3*350*480 - assert len(intimg) == 640*480 - l = l + img[i] - intimg[i] = (intimg[i-640] + l) - i += 1 - return intimg[i - 1] - # - log = self.run(main, []) - assert log.result == 73574560 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i13 = int_lt(i8, 307200) - guard_true(i13, descr=) - # the bound check guard on img has been killed (thanks to the asserts) - i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) - i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) - i17 = int_sub(i8, 640) - # the bound check guard on intimg has been killed (thanks to the asserts) - i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) - i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) - # on 64bit, there is a guard checking that i19 actually fits into 32bit - ... - setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) - i28 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=) - """) - - def test_func_defaults(self): - def main(n): - i = 1 - while i < n: - i += len(xrange(i+1)) - i - return i - - log = self.run(main, [10000]) - assert log.result == 10000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i5, i6) - guard_true(i10, descr=) - i120 = int_add(i5, 1) - guard_not_invalidated(descr=) - --TICK-- - jump(..., descr=) - """) def test_unpack_iterable_non_list_tuple(self): def main(n): @@ -1067,667 +164,71 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i12, i13) - guard_false(i16, descr=) + guard_false(i16, descr=...) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) - setfield_gc(p4, i19, descr=) - guard_nonnull_class(p17, 146982464, descr=) + setfield_gc(p9, i19, descr=) + guard_nonnull_class(p17, 146982464, descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) - guard_true(i23, descr=) + guard_true(i23, descr=...) i24 = getfield_gc(p17, descr=) i25 = getarrayitem_raw(i24, 0, descr=<.*>) i27 = int_lt(1, i21) - guard_false(i27, descr=) + guard_false(i27, descr=...) i28 = int_add_ovf(i10, i25) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=) + jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) - def test_mutate_class(self): - def fn(n): - class A(object): - count = 1 - def __init__(self, a): - self.a = a - def f(self): - return self.count - i = 0 - a = A(1) - while i < n: - A.count += 1 # ID: mutate - i = a.f() # ID: meth1 - return i + + def test_dont_trace_every_iteration(self): + def main(a, b): + i = sa = 0 + while i < 300: + if a > 0: + pass + if 1 < b < 2: + pass + sa += a % b + i += 1 + return sa # - log = self.run(fn, [1000], threshold=10) - assert log.result == 1000 - # - # first, we test the entry bridge - # ------------------------------- - entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) - ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') - assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc', 'guard_nonnull_class'] - # the STORE_ATTR is folded away - assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] - # - # then, the actual loop - # ---------------------- + log = self.run(main, [10, 20]) + assert log.result == 300 * (10 % 20) + assert log.jit_summary.tracing_no == 1 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i8 = getfield_gc_pure(p5, descr=) - i9 = int_lt(i8, i7) - guard_true(i9, descr=.*) - guard_not_invalidated(descr=.*) - i11 = int_add(i8, 1) - i12 = force_token() + i11 = int_lt(i7, 300) + guard_true(i11, descr=...) + i12 = int_add_ovf(i8, i9) + guard_no_overflow(descr=...) + i14 = int_add(i7, 1) --TICK-- - p20 = new_with_vtable(ConstClass(W_IntObject)) - setfield_gc(p20, i11, descr=) - setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i7, descr=) + jump(..., descr=...) """) + # + log = self.run(main, [-10, -20]) + assert log.result == 300 * (-10 % -20) + assert log.jit_summary.tracing_no == 1 - def test_intbound_simple(self): + def test_overflow_checking(self): """ This test only checks that we get the expected result, not that any optimization has been applied. """ - ops = ('<', '>', '<=', '>=', '==', '!=') - nbr = (3, 7) - for o1 in ops: - for o2 in ops: - for n1 in nbr: - for n2 in nbr: - src = ''' - def f(i): - a, b = 3, 3 - if i %s %d: - a = 0 - else: - a = 1 - if i %s %d: - b = 0 - else: - b = 1 - return a + b * 2 - - def main(): - res = [0] * 4 - idx = [] - for i in range(15): - idx.extend([i] * 15) - for i in idx: - res[f(i)] += 1 - return res - - ''' % (o1, n1, o2, n2) - self.run_and_check(src, threshold=200) - - def test_intbound_addsub_mix(self): - """ - This test only checks that we get the expected result, not that any - optimization has been applied. - """ - tests = ('i > 4', 'i > 2', 'i + 1 > 2', '1 + i > 4', - 'i - 1 > 1', '1 - i > 1', '1 - i < -3', - 'i == 1', 'i == 5', 'i != 1', '-2 * i < -4') - for t1 in tests: - for t2 in tests: - src = ''' - def f(i): - a, b = 3, 3 - if %s: - a = 0 - else: - a = 1 - if %s: - b = 0 - else: - b = 1 - return a + b * 2 - - def main(): - res = [0] * 4 - idx = [] - for i in range(15): - idx.extend([i] * 15) - for i in idx: - res[f(i)] += 1 - return res - - ''' % (t1, t2) - self.run_and_check(src, threshold=200) - - def test_intbound_gt(self): - def main(n): - i, a, b = 0, 0, 0 - while i < n: - if i > -1: - a += 1 - if i > -2: - b += 1 - i += 1 - return (a, b) + def main(): + import sys + def f(a,b): + if a < 0: return -1 + return a-b + # + total = sys.maxint - 2147483647 + for i in range(100000): + total += f(i, 5) + # + return total # - log = self.run(main, [300], threshold=200) - assert log.result == (300, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, i9) - guard_true(i10, descr=...) - i12 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i14 = int_add_ovf(i6, 1) - guard_no_overflow(descr=...) - i17 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=) - """) - - def test_intbound_sub_lt(self): - def main(): - i, a = 0, 0 - while i < 300: - if i - 10 < 295: - a += 1 - i += 1 - return a - # - log = self.run(main, [], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i5, 300) - guard_true(i7, descr=...) - i9 = int_sub_ovf(i5, 10) - guard_no_overflow(descr=...) - i11 = int_add_ovf(i4, 1) - guard_no_overflow(descr=...) - i13 = int_add(i5, 1) - --TICK-- - jump(p0, p1, p2, p3, i11, i13, descr=) - """) - - def test_intbound_addsub_ge(self): - def main(n): - i, a, b = 0, 0, 0 - while i < n: - if i + 5 >= 5: - a += 1 - if i - 1 >= -1: - b += 1 - i += 1 - return (a, b) - # - log = self.run(main, [300], threshold=200) - assert log.result == (300, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, i9) - guard_true(i10, descr=...) - i12 = int_add_ovf(i8, 5) - guard_no_overflow(descr=...) - i14 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i16 = int_add_ovf(i6, 1) - guard_no_overflow(descr=...) - i19 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=) - """) - - def test_intbound_addmul_ge(self): - def main(n): - i, a, b = 0, 0, 0 - while i < 300: - if i + 5 >= 5: - a += 1 - if 2 * i >= 0: - b += 1 - i += 1 - return (a, b) - # - log = self.run(main, [300], threshold=200) - assert log.result == (300, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, 300) - guard_true(i10, descr=...) - i12 = int_add(i8, 5) - i14 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i16 = int_lshift(i8, 1) - i18 = int_add_ovf(i6, 1) - guard_no_overflow(descr=...) - i21 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=) - """) - - def test_intbound_eq(self): - def main(a, n): - i, s = 0, 0 - while i < 300: - if a == 7: - s += a + 1 - elif i == 10: - s += i - else: - s += 1 - i += 1 - return s - # - log = self.run(main, [7, 300], threshold=200) - assert log.result == main(7, 300) - log = self.run(main, [10, 300], threshold=200) - assert log.result == main(10, 300) - log = self.run(main, [42, 300], threshold=200) - assert log.result == main(42, 300) - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i10 = int_lt(i8, 300) - guard_true(i10, descr=...) - i12 = int_eq(i8, 10) - guard_false(i12, descr=...) - i14 = int_add_ovf(i7, 1) - guard_no_overflow(descr=...) - i16 = int_add(i8, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=) - """) - - def test_intbound_mul(self): - def main(a): - i, s = 0, 0 - while i < 300: - assert i >= 0 - if 2 * i < 30000: - s += 1 - else: - s += a - i += 1 - return s - # - log = self.run(main, [7], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i8 = int_lt(i6, 300) - guard_true(i8, descr=...) - i10 = int_lshift(i6, 1) - i12 = int_add_ovf(i5, 1) - guard_no_overflow(descr=...) - i14 = int_add(i6, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, i12, i14, descr=) - """) - - def test_assert(self): - def main(a): - i, s = 0, 0 - while i < 300: - assert a == 7 - s += a + 1 - i += 1 - return s - log = self.run(main, [7], threshold=200) - assert log.result == 300*8 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i8 = int_lt(i6, 300) - guard_true(i8, descr=...) - i10 = int_add_ovf(i5, 8) - guard_no_overflow(descr=...) - i12 = int_add(i6, 1) - --TICK-- - jump(p0, p1, p2, p3, p4, i10, i12, descr=) - """) - - def test_zeropadded(self): - def main(): - from array import array - class ZeroPadded(array): - def __new__(cls, l): - self = array.__new__(cls, 'd', range(l)) - return self - - def __getitem__(self, i): - if i < 0 or i >= len(self): - return 0 - return array.__getitem__(self, i) # ID: get - # - buf = ZeroPadded(2000) - i = 10 - sa = 0 - while i < 2000 - 10: - sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] - i += 1 - return sa - - log = self.run(main, [], threshold=200) - assert log.result == 9895050.0 - loop, = log.loops_by_filename(self.filepath) - # - # check that the overloaded __getitem__ does not introduce double - # array bound checks. - # - # The force_token()s are still there, but will be eliminated by the - # backend regalloc, so they are harmless - assert loop.match(ignore_ops=['force_token'], - expected_src=""" - ... - i20 = int_ge(i18, i8) - guard_false(i20, descr=...) - f21 = getarrayitem_raw(i13, i18, descr=...) - f23 = getarrayitem_raw(i13, i14, descr=...) - f24 = float_add(f21, f23) - f26 = getarrayitem_raw(i13, i6, descr=...) - f27 = float_add(f24, f26) - i29 = int_add(i6, 1) - i31 = int_ge(i29, i8) - guard_false(i31, descr=...) - f33 = getarrayitem_raw(i13, i29, descr=...) - f34 = float_add(f27, f33) - i36 = int_add(i6, 2) - i38 = int_ge(i36, i8) - guard_false(i38, descr=...) - f39 = getarrayitem_raw(i13, i36, descr=...) - ... - """) - - - def test_circular(self): - def main(): - from array import array - class Circular(array): - def __new__(cls): - self = array.__new__(cls, 'd', range(256)) - return self - def __getitem__(self, i): - assert len(self) == 256 - return array.__getitem__(self, i & 255) - # - buf = Circular() - i = 10 - sa = 0 - while i < 2000 - 10: - sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2] - i += 1 - return sa - # - log = self.run(main, [], threshold=200) - assert log.result == 1239690.0 - loop, = log.loops_by_filename(self.filepath) - # - # check that the array bound checks are removed - # - # The force_token()s are still there, but will be eliminated by the - # backend regalloc, so they are harmless - assert loop.match(ignore_ops=['force_token'], - expected_src=""" - ... - i17 = int_and(i14, 255) - f18 = getarrayitem_raw(i8, i17, descr=...) - f20 = getarrayitem_raw(i8, i9, descr=...) - f21 = float_add(f18, f20) - f23 = getarrayitem_raw(i8, i10, descr=...) - f24 = float_add(f21, f23) - i26 = int_add(i6, 1) - i29 = int_and(i26, 255) - f30 = getarrayitem_raw(i8, i29, descr=...) - f31 = float_add(f24, f30) - i33 = int_add(i6, 2) - i36 = int_and(i33, 255) - f37 = getarrayitem_raw(i8, i36, descr=...) - ... - """) - - def test_min_max(self): - def main(): - i=0 - sa=0 - while i < 300: - sa+=min(max(i, 3000), 4000) - i+=1 - return sa - log = self.run(main, [], threshold=200) - assert log.result == 300*3000 - loop, = log.loops_by_filename(self.filepath) - assert loop.match(""" - i7 = int_lt(i4, 300) - guard_true(i7, descr=...) - i9 = int_add_ovf(i5, 3000) - guard_no_overflow(descr=...) - i11 = int_add(i4, 1) - --TICK-- - jump(p0, p1, p2, p3, i11, i9, descr=) - """) - - def test_silly_max(self): - def main(): - i = 2 - sa = 0 - while i < 300: - lst = range(i) - sa += max(*lst) # ID: max - i += 1 - return sa - log = self.run(main, [], threshold=200) - assert log.result == main() - loop, = log.loops_by_filename(self.filepath) - # We dont want too many guards, but a residual call to min_max_loop - guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] - assert len(guards) < 20 - assert loop.match_by_id('max',""" - ... - p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) - ... - """) - - def test_iter_max(self): - def main(): - i = 2 - sa = 0 - while i < 300: - lst = range(i) - sa += max(lst) # ID: max - i += 1 - return sa - log = self.run(main, [], threshold=200) - assert log.result == main() - loop, = log.loops_by_filename(self.filepath) - # We dont want too many guards, but a residual call to min_max_loop - guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')] - assert len(guards) < 20 - assert loop.match_by_id('max',""" - ... - p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...) - ... - """) - - def test__ffi_call(self): - from pypy.rlib.test.test_libffi import get_libm_name - def main(libm_name): - try: - from _ffi import CDLL, types - except ImportError: - sys.stderr.write('SKIP: cannot import _ffi\n') - return 0 - - libm = CDLL(libm_name) - pow = libm.getfunc('pow', [types.double, types.double], - types.double) - i = 0 - res = 0 - while i < 300: - res += pow(2, 3) - i += 1 - return pow.getaddr(), res - # - libm_name = get_libm_name(sys.platform) - log = self.run(main, [libm_name], threshold=200) - pow_addr, res = log.result - assert res == 8.0 * 300 - loop, = log.loops_by_filename(self.filepath) - # XXX: write the actual test when we merge this to jitypes2 - ## ops = self.get_by_bytecode('CALL_FUNCTION') - ## assert len(ops) == 2 # we get two loops, because of specialization - ## call_function = ops[0] - ## last_ops = [op.getopname() for op in call_function[-5:]] - ## assert last_ops == ['force_token', - ## 'setfield_gc', - ## 'call_may_force', - ## 'guard_not_forced', - ## 'guard_no_exception'] - ## call = call_function[-3] - ## assert call.getarg(0).value == pow_addr - ## assert call.getarg(1).value == 2.0 - ## assert call.getarg(2).value == 3.0 - - def test_xor(self): - def main(b): - a = sa = 0 - while a < 300: - if a > 0: # Specialises the loop - pass - if b > 10: - pass - if a^b >= 0: # ID: guard - sa += 1 - sa += a^a # ID: a_xor_a - a += 1 - return sa - - log = self.run(main, [11], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - # if both are >=0, a^b is known to be >=0 - # note that we know that b>10 - assert loop.match_by_id('guard', """ - i10 = int_xor(i5, i7) - """) - # - # x^x is always optimized to 0 - assert loop.match_by_id('a_xor_a', "") - - log = self.run(main, [9], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - # we don't know that b>10, hence we cannot optimize it - assert loop.match_by_id('guard', """ - i10 = int_xor(i5, i7) - i12 = int_ge(i10, 0) - guard_true(i12, descr=...) - """) - - def test_shift_intbound(self): - def main(b): - res = 0 - a = 0 - while a < 300: - assert a >= 0 - assert 0 <= b <= 10 - val = a >> b - if val >= 0: # ID: rshift - res += 1 - val = a << b - if val >= 0: # ID: lshift - res += 2 - a += 1 - return res - # - log = self.run(main, [2], threshold=200) - assert log.result == 300*3 - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('rshift', "") # guard optimized away - assert loop.match_by_id('lshift', "") # guard optimized away - - def test_lshift_and_then_rshift(self): - py.test.skip('fixme, this optimization is disabled') - def main(b): - res = 0 - a = 0 - while res < 300: - assert a >= 0 - assert 0 <= b <= 10 - res = (a << b) >> b # ID: shift - a += 1 - return res - # - log = self.run(main, [2], threshold=200) - assert log.result == 300 - loop, = log.loops_by_filename(self.filepath) - assert loop.match_by_id('shift', "") # optimized away - - def test_division_to_rshift(self): - py.test.skip('in-progress') - def main(b): - res = 0 - a = 0 - while a < 300: - assert a >= 0 - assert 0 <= b <= 10 - res = a/b # ID: div - a += 1 - return res - # - log = self.run(main, [3], threshold=200) - #assert log.result == 149 - loop, = log.loops_by_filename(self.filepath) - import pdb;pdb.set_trace() - assert loop.match_by_id('div', "") # optimized away - - def test_oldstyle_newstyle_mix(self): - def main(): - class A: - pass - - class B(object, A): - def __init__(self, x): - self.x = x - - i = 0 - b = B(1) - while i < 100: - v = b.x # ID: loadattr - i += v - return i - - log = self.run(main, [], threshold=80) - loop, = log.loops_by_filename(self.filepath) - loop.match_by_id('loadattr', - ''' - guard_not_invalidated(descr=...) - i19 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) - guard_no_exception(descr=...) - i21 = int_and(i19, _) - i22 = int_is_true(i21) - guard_true(i22, descr=...) - i26 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) - guard_no_exception(descr=...) - i28 = int_and(i26, _) - i29 = int_is_true(i28) - guard_true(i29, descr=...) - ''') - - def test_python_contains(self): - def main(): - class A(object): - def __contains__(self, v): - return True - - i = 0 - a = A() - while i < 100: - i += i in a # ID: contains - - log = self.run(main, [], threshold=80) - loop, = log.loops_by_filename(self.filemath) - # XXX: haven't confirmed his is correct, it's probably missing a - # few instructions - loop.match_by_id("contains", """ - i1 = int_add(i0, 1) - """) + self.run_and_check(main, []) diff --git a/pypy/module/pypyjit/test_pypy_c/test_shift.py b/pypy/module/pypyjit/test_pypy_c/test_shift.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_shift.py @@ -0,0 +1,166 @@ +import py +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestShift(BaseTestPyPyC): + + def test_shift_intbound(self): + def main(b): + res = 0 + a = 0 + while a < 300: + assert a >= 0 + assert 0 <= b <= 10 + val = a >> b + if val >= 0: # ID: rshift + res += 1 + val = a << b + if val >= 0: # ID: lshift + res += 2 + a += 1 + return res + # + log = self.run(main, [2]) + assert log.result == 300*3 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('rshift', "") # guard optimized away + assert loop.match_by_id('lshift', "") # guard optimized away + + def test_lshift_and_then_rshift(self): + py.test.skip('fixme, this optimization is disabled') + def main(b): + res = 0 + a = 0 + while res < 300: + assert a >= 0 + assert 0 <= b <= 10 + res = (a << b) >> b # ID: shift + a += 1 + return res + # + log = self.run(main, [2]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('shift', "") # optimized away + + def test_division_to_rshift(self): + def main(b): + res = 0 + a = 0 + while a < 300: + assert a >= 0 + assert 0 <= b <= 10 + res = a/b # ID: div + a += 1 + return res + # + log = self.run(main, [3]) + assert log.result == 99 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id('div', """ + i10 = int_floordiv(i6, i7) + i11 = int_mul(i10, i7) + i12 = int_sub(i6, i11) + i14 = int_rshift(i12, 63) + i15 = int_add(i10, i14) + """) + + def test_division_to_rshift_allcases(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + avalues = ('a', 'b', 7, -42, 8) + bvalues = ['b'] + range(-10, 0) + range(1,10) + code = '' + for a in avalues: + for b in bvalues: + code += ' sa += %s / %s\n' % (a, b) + src = """ + def main(a, b): + i = sa = 0 + while i < 300: +%s + i += 1 + return sa + """ % code + self.run_and_check(src, [ 10, 20]) + self.run_and_check(src, [ 10, -20]) + self.run_and_check(src, [-10, -20]) + + def test_mod(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + avalues = ('a', 'b', 7, -42, 8) + bvalues = ['b'] + range(-10, 0) + range(1,10) + code = '' + for a in avalues: + for b in bvalues: + code += ' sa += %s %% %s\n' % (a, b) + src = """ + def main(a, b): + i = sa = 0 + while i < 2000: + if a > 0: pass + if 1 < b < 2: pass +%s + i += 1 + return sa + """ % code + self.run_and_check(src, [ 10, 20]) + self.run_and_check(src, [ 10, -20]) + self.run_and_check(src, [-10, -20]) + + def test_shift_allcases(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + from sys import maxint + def main(a, b): + i = sa = 0 + while i < 300: + if a > 0: # Specialises the loop + pass + if b < 2 and b > 0: + pass + if (a >> b) >= 0: + sa += 1 + if (a << b) > 2: + sa += 10000 + i += 1 + return sa + # + maxvals = (-maxint-1, -maxint, maxint-1, maxint) + for a in (-4, -3, -2, -1, 0, 1, 2, 3, 4) + maxvals: + for b in (0, 1, 2, 31, 32, 33, 61, 62, 63): + yield self.run_and_check, main, [a, b] + + def test_revert_shift_allcases(self): + """ + This test only checks that we get the expected result, not that any + optimization has been applied. + """ + from sys import maxint + + def main(a, b, c): + from sys import maxint + i = sa = 0 + while i < 300: + if 0 < a < 10: pass + if -100 < b < 100: pass + if -maxint/2 < c < maxint/2: pass + sa += (a<>a + sa += (b<>a + sa += (c<>a + sa += (a<<100)>>100 + sa += (b<<100)>>100 + sa += (c<<100)>>100 + i += 1 + return long(sa) + + for a in (1, 4, 8, 100): + for b in (-10, 10, -201, 201, -maxint/3, maxint/3): + for c in (-10, 10, -maxint/3, maxint/3): + yield self.run_and_check, main, [a, b, c] diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -0,0 +1,107 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestString(BaseTestPyPyC): + def test_lookup_default_encoding(self): + def main(n): + import string + i = 0 + letters = string.letters + uletters = unicode(string.letters) + while i < n: + i += letters[i % len(letters)] == uletters[i % len(letters)] + return i + + log = self.run(main, [300]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i14 = int_lt(i6, i9) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) + i15 = int_mod(i6, i10) + i17 = int_rshift(i15, 63) + i18 = int_and(i10, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i10) + guard_false(i22, descr=...) + i23 = strgetitem(p11, i19) + i24 = int_ge(i19, i12) + guard_false(i24, descr=...) + i25 = unicodegetitem(p13, i19) + p27 = newstr(1) + strsetitem(p27, 0, i23) + p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) + guard_no_exception(descr=...) + i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) + guard_true(i32, descr=...) + i34 = int_add(i6, 1) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) + + def test_long(self): + def main(n): + import string + i = 1 + while i < n: + i += int(long(string.digits[i % len(string.digits)], 16)) + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i13 = int_eq(i6, -9223372036854775808) + guard_false(i13, descr=...) + i15 = int_mod(i6, i8) + i17 = int_rshift(i15, 63) + i18 = int_and(i8, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i8) + guard_false(i22, descr=...) + i23 = strgetitem(p10, i19) + p25 = newstr(1) + strsetitem(p25, 0, i23) + p28 = call(ConstClass(strip_spaces), p25, descr=) + guard_no_exception(descr=...) + i29 = strlen(p28) + i30 = int_is_true(i29) + guard_true(i30, descr=...) + i32 = int_sub(i29, 1) + i33 = strgetitem(p28, i32) + i35 = int_eq(i33, 108) + guard_false(i35, descr=...) + i37 = int_eq(i33, 76) + guard_false(i37, descr=...) + i39 = strgetitem(p28, 0) + i41 = int_eq(i39, 45) + guard_false(i41, descr=...) + i43 = int_eq(i39, 43) + guard_false(i43, descr=...) + i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=) + guard_false(i43, descr=...) + i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=) + guard_false(i46, descr=...) + p51 = new_with_vtable(21136408) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, i29, descr=) + setfield_gc(p51, 1, descr=) + setfield_gc(p51, 16, descr=) + setfield_gc(p51, p28, descr=) + p55 = call(ConstClass(parse_digit_string), p51, descr=) + guard_no_exception(descr=...) + i57 = call(ConstClass(rbigint.toint), p55, descr=) + guard_no_exception(descr=...) + i58 = int_add_ovf(i6, i57) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) + """) \ No newline at end of file diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -80,7 +80,7 @@ pypysig_getaddr_occurred = external('pypysig_getaddr_occurred', [], lltype.Ptr(LONG_STRUCT), _nowrapper=True, - pure_function=True) + elidable_function=True) c_alarm = external('alarm', [rffi.INT], rffi.INT) c_pause = external('pause', [], rffi.INT) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT) diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -7,6 +7,8 @@ class Module(MixedModule): """Sys Builtin Module. """ + _immutable_fields_ = ["defaultencoding?"] + def __init__(self, space, w_name): """NOT_RPYTHON""" # because parent __init__ isn't if space.config.translating: diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -57,7 +57,8 @@ raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) space.sys.recursionlimit = new_limit - _stack_set_length_fraction(new_limit * 0.001) + if space.config.translation.type_system == 'lltype': + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c b/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c --- a/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c +++ b/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c @@ -43,6 +43,12 @@ qsort(base, num, width, compare); } +EXPORT(char) deref_LP_c_char_p(char** argv) +{ + char* s = *argv; + return s[0]; +} + EXPORT(int *) _testfunc_ai8(int a[8]) { return a; diff --git a/pypy/module/test_lib_pypy/ctypes_tests/support.py b/pypy/module/test_lib_pypy/ctypes_tests/support.py --- a/pypy/module/test_lib_pypy/ctypes_tests/support.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/support.py @@ -1,4 +1,5 @@ import py +import sys import ctypes py.test.importorskip("ctypes", "1.0.2") @@ -14,6 +15,16 @@ if _rawffi: py.test.skip("white-box tests for pypy _rawffi based ctypes impl") +def del_funcptr_refs_maybe(obj, attrname): + dll = getattr(obj, attrname, None) + if not dll: + return + _FuncPtr = dll._FuncPtr + for name in dir(dll): + obj = getattr(dll, name, None) + if isinstance(obj, _FuncPtr): + delattr(dll, name) + class BaseCTypesTestChecker: def setup_class(cls): if _rawffi: @@ -21,8 +32,21 @@ for _ in range(4): gc.collect() cls.old_num = _rawffi._num_of_allocated_objects() - + + def teardown_class(cls): + if sys.pypy_translation_info['translation.gc'] == 'boehm': + return # it seems that boehm has problems with __del__, so not + # everything is freed + # + mod = sys.modules[cls.__module__] + del_funcptr_refs_maybe(mod, 'dll') + del_funcptr_refs_maybe(mod, 'dll2') + del_funcptr_refs_maybe(mod, 'lib') + del_funcptr_refs_maybe(mod, 'testdll') + del_funcptr_refs_maybe(mod, 'ctdll') + del_funcptr_refs_maybe(cls, '_dll') + # if hasattr(cls, 'old_num'): import gc for _ in range(4): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py @@ -0,0 +1,82 @@ +# unittest for SOME ctypes com function calls. +# Can't resist from implementing some kind of mini-comtypes +# theller ;-) + +import py +import sys +if sys.platform != "win32": + py.test.skip('windows only test') + +import ctypes, new, unittest +from ctypes.wintypes import HRESULT +from _ctypes import COMError + +oleaut32 = ctypes.OleDLL("oleaut32") + +class UnboundMethod(object): + def __init__(self, func, index, name): + self.func = func + self.index = index + self.name = name + self.__doc__ = func.__doc__ + + def __repr__(self): + return "" % (self.index, self.name, id(self)) + + def __get__(self, instance, owner): + if instance is None: + return self + return new.instancemethod(self.func, instance, owner) + +def commethod(index, restype, *argtypes): + """A decorator that generates COM methods. The decorated function + itself is not used except for it's name.""" + def make_commethod(func): + comfunc = ctypes.WINFUNCTYPE(restype, *argtypes)(index, func.__name__) + comfunc.__name__ = func.__name__ + comfunc.__doc__ = func.__doc__ + return UnboundMethod(comfunc, index, func.__name__) + return make_commethod + +class ICreateTypeLib2(ctypes.c_void_p): + + @commethod(1, ctypes.c_long) + def AddRef(self): + pass + + @commethod(2, ctypes.c_long) + def Release(self): + pass + + @commethod(4, HRESULT, ctypes.c_wchar_p) + def SetName(self): + """Set the name of the library.""" + + @commethod(12, HRESULT) + def SaveAllChanges(self): + pass + + +CreateTypeLib2 = oleaut32.CreateTypeLib2 +CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, ctypes.POINTER(ICreateTypeLib2)) + +################################################################ + +def test_basic_comtypes(): + punk = ICreateTypeLib2() + hr = CreateTypeLib2(0, "foobar.tlb", punk) + assert hr == 0 + + assert 2 == punk.AddRef() + assert 3 == punk.AddRef() + assert 4 == punk.AddRef() + + punk.SetName("TypeLib_ByPYPY") + py.test.raises(COMError, lambda: punk.SetName(None)) + + # This would save the typelib to disk. + ## punk.SaveAllChanges() + + assert 3 == punk.Release() + assert 2 == punk.Release() + assert 1 == punk.Release() diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py @@ -0,0 +1,103 @@ +from ctypes import CDLL, POINTER, pointer, c_byte, c_int, c_char_p +import sys +import py +from support import BaseCTypesTestChecker + +class MyCDLL(CDLL): + def __getattr__(self, attr): + fn = self[attr] # this way it's not cached as an attribute + fn._slowpath_allowed = False + return fn + +def setup_module(mod): + import conftest + _ctypes_test = str(conftest.sofile) + mod.dll = MyCDLL(_ctypes_test) # slowpath not allowed + mod.dll2 = CDLL(_ctypes_test) # slowpath allowed + + +class TestFastpath(BaseCTypesTestChecker): + + def test_fastpath_forbidden(self): + def myfunc(): + pass + # + tf_b = dll.tf_b + tf_b.restype = c_byte + # + # so far, it's still using the slowpath + assert not tf_b._is_fastpath + tf_b.callable = myfunc + tf_b.argtypes = (c_byte,) + # errcheck prevented the fastpath to kick in + assert not tf_b._is_fastpath + # + del tf_b.callable + tf_b.argtypes = (c_byte,) # try to re-enable the fastpath + assert tf_b._is_fastpath + # + assert not tf_b._slowpath_allowed + py.test.raises(AssertionError, "tf_b.callable = myfunc") + py.test.raises(AssertionError, "tf_b('aaa')") # force a TypeError + + def test_simple_args(self): + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + assert tf_b(-126) == -42 + + def test_pointer_args(self): + f = dll._testfunc_p_p + f.restype = POINTER(c_int) + f.argtypes = [POINTER(c_int)] + v = c_int(42) + result = f(pointer(v)) + assert type(result) == POINTER(c_int) + assert result.contents.value == 42 + + def test_simple_pointer_args(self): + f = dll.my_strchr + f.argtypes = [c_char_p, c_int] + f.restype = c_char_p + mystr = c_char_p("abcd") + result = f(mystr, ord("b")) + assert result == "bcd" + + @py.test.mark.xfail + def test_strings(self): + f = dll.my_strchr + f.argtypes = [c_char_p, c_int] + f.restype = c_char_p + # python strings need to be converted to c_char_p, but this is + # supported only in the slow path so far + result = f("abcd", ord("b")) + assert result == "bcd" + + def test_errcheck(self): + def errcheck(result, func, args): + return 'hello' + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + tf_b.errcheck = errcheck + assert tf_b(-126) == 'hello' + + +class TestFallbackToSlowpath(BaseCTypesTestChecker): + + def test_argtypes_is_None(self): + tf_b = dll2.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_char_p,) # this is intentionally wrong + tf_b.argtypes = None # kill the fast path + assert not tf_b._is_fastpath + assert tf_b(-126) == -42 + + def test_callable_is_None(self): + tf_b = dll2.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + tf_b.callable = lambda x: x+1 + assert not tf_b._is_fastpath + assert tf_b(-126) == -125 + tf_b.callable = None diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -91,6 +91,13 @@ result = f(0, 0, 0, 0, 0, 0) assert result == u'\x00' + def test_char_result(self): + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_char + result = f(0, 0, 0, 0, 0, 0) + assert result == '\x00' + def test_voidresult(self): f = dll._testfunc_v f.restype = None @@ -125,6 +132,16 @@ # You cannot assing character format codes as restype any longer raises(TypeError, setattr, f, "restype", "i") + + def test_truncate_python_longs(self): + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_int + x = sys.maxint * 2 + result = f(x, x, x, x, 0, 0) + assert result == -8 + + def test_floatresult(self): f = dll._testfunc_f_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] @@ -211,8 +228,19 @@ result = f(byref(c_int(99))) assert not result.contents == 99 + def test_convert_pointers(self): + f = dll.deref_LP_c_char_p + f.restype = c_char + f.argtypes = [POINTER(c_char_p)] + # + s = c_char_p('hello world') + ps = pointer(s) + assert f(ps) == 'h' + assert f(s) == 'h' # automatic conversion from char** to char* + def test_errors_1(self): f = dll._testfunc_p_p + f.argtypes = [POINTER(c_int)] f.restype = c_int class X(Structure): @@ -393,6 +421,23 @@ result = f("abcd", ord("b")) assert result == "bcd" + def test_keepalive_buffers(self, monkeypatch): + import gc + f = dll.my_strchr + f.argtypes = [c_char_p] + f.restype = c_char_p + # + orig__call_funcptr = f._call_funcptr + def _call_funcptr(funcptr, *newargs): + gc.collect() + gc.collect() + gc.collect() + return orig__call_funcptr(funcptr, *newargs) + monkeypatch.setattr(f, '_call_funcptr', _call_funcptr) + # + result = f("abcd", ord("b")) + assert result == "bcd" + def test_caching_bug_1(self): # the same test as test_call_some_args, with two extra lines # in the middle that trigger caching in f._ptr, which then @@ -428,6 +473,16 @@ u = dll.ret_un_func(a[1]) assert u.y == 33*10000 + def test_cache_funcptr(self): + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + assert tf_b(-126) == -42 + ptr = tf_b._ptr + assert ptr is not None + assert tf_b(-126) == -42 + assert tf_b._ptr is ptr + def test_warnings(self): import warnings warnings.simplefilter("always") @@ -439,6 +494,22 @@ assert "C function without declared arguments called" in str(w[0].message) assert "C function without declared return type called" in str(w[1].message) + def test_errcheck(self): + py.test.skip('fixme') + def errcheck(result, func, args): + assert result == -42 + assert type(result) is int + arg, = args + assert arg == -126 + assert type(arg) is int + return result + # + tf_b = dll.tf_b + tf_b.restype = c_byte + tf_b.argtypes = (c_byte,) + tf_b.errcheck = errcheck + assert tf_b(-126) == -42 + del tf_b.errcheck with warnings.catch_warnings(record=True) as w: dll.get_an_integer.argtypes = [] dll.get_an_integer() diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py @@ -12,8 +12,10 @@ from _ctypes.function import CFuncPtr def guess(value): - cobj = CFuncPtr._conv_param(None, value) - return type(cobj) + _, cobj, ctype = CFuncPtr._conv_param(None, value) + return ctype + ## cobj = CFuncPtr._conv_param(None, value) + ## return type(cobj) assert guess(13) == c_int assert guess(0) == c_int diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py @@ -125,6 +125,9 @@ if t is c_longdouble: # no support for 'g' in the struct module continue code = t._type_ # the typecode + if code == 'g': + # typecode not supported by "struct" + continue align = struct.calcsize("c%c" % code) - struct.calcsize(code) # alignment of the type... diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py @@ -12,6 +12,13 @@ mod._ctypes_test = str(conftest.sofile) class TestPointers(BaseCTypesTestChecker): + + def test_get_ffi_argtype(self): + P = POINTER(c_int) + ffitype = P.get_ffi_argtype() + assert P.get_ffi_argtype() is ffitype + assert ffitype.deref_pointer() is c_int.get_ffi_argtype() + def test_pointer_crash(self): class A(POINTER(c_ulong)): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py b/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_unicode.py @@ -15,6 +15,10 @@ mod.wcslen.argtypes = [ctypes.c_wchar_p] mod.func = dll._testfunc_p_p + def teardown_module(mod): + del mod.func + del mod.wcslen + class TestUnicode(BaseCTypesTestChecker): def setup_method(self, method): self.prev_conv_mode = ctypes.set_conversion_mode("ascii", "strict") diff --git a/pypy/module/test_lib_pypy/test_pwd.py b/pypy/module/test_lib_pypy/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/test_pwd.py @@ -0,0 +1,12 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=('_ffi', '_rawffi')) + cls.space.appexec((), "(): import pwd") + + def test_getpwuid(self): + import os, pwd + passwd_info = pwd.getpwuid(os.getuid()) + assert type(passwd_info).__name__ == 'struct_passwd' + assert repr(passwd_info).startswith("pwd.struct_passwd(pw_name=") diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -416,7 +416,7 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "'%s' objects are unhashable", typename) w_result = space.get_and_call_function(w_hash, w_obj) diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -384,8 +384,9 @@ # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) - stack_items_w = self.crnt_frame.valuestack_w - for i in range(self.crnt_frame.valuestackdepth-1, -1, -1): + f = self.crnt_frame + stack_items_w = f.locals_stack_w + for i in range(f.valuestackdepth-1, f.nlocals-1, -1): w_v = stack_items_w[i] if isinstance(w_v, Constant): if w_v.value is oldvalue: diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py --- a/pypy/objspace/flow/framestate.py +++ b/pypy/objspace/flow/framestate.py @@ -10,7 +10,7 @@ def __init__(self, state): if isinstance(state, PyFrame): # getfastscope() can return real None, for undefined locals - data = state.getfastscope() + state.savevaluestack() + data = state.save_locals_stack() if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -36,11 +36,9 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): - fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) # Nones == undefined locals - frame.restorevaluestack(data[fastlocals:-2]) + frame.restore_locals_stack(data[:-2]) # Nones == undefined locals if data[-2] == Constant(None): assert data[-1] == Constant(None) frame.last_exception = None diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -143,9 +143,6 @@ def mod_ovf(x, y): return ovfcheck(x % y) -##def pow_ovf(*two_or_three_args): -## return ovfcheck(pow(*two_or_three_args)) - def lshift_ovf(x, y): return ovfcheck_lshift(x, y) diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py --- a/pypy/objspace/flow/test/test_framestate.py +++ b/pypy/objspace/flow/test/test_framestate.py @@ -25,7 +25,7 @@ dummy = Constant(None) #dummy.dummy = True arg_list = ([Variable() for i in range(formalargcount)] + - [dummy] * (len(frame.fastlocals_w) - formalargcount)) + [dummy] * (frame.nlocals - formalargcount)) frame.setfastscope(arg_list) return frame @@ -42,7 +42,7 @@ def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1 != fs2 @@ -55,7 +55,7 @@ def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general @@ -63,7 +63,7 @@ def test_restore_frame(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs1.restoreframe(frame) assert fs1 == FrameState(frame) @@ -82,25 +82,26 @@ def test_getoutputargs(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Variable() + frame.locals_stack_w[frame.nlocals-1] = Variable() fs2 = FrameState(frame) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable - # fastlocals_w[-1] -> fastlocals_w[-1] is Constant(None) - assert outputargs == [frame.fastlocals_w[0], Constant(None)] + # locals_w[n-1] -> locals_w[n-1] is Constant(None) + assert outputargs == [frame.locals_stack_w[0], Constant(None)] def test_union_different_constants(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(42) + frame.locals_stack_w[frame.nlocals-1] = Constant(42) fs2 = FrameState(frame) fs3 = fs1.union(fs2) fs3.restoreframe(frame) - assert isinstance(frame.fastlocals_w[-1], Variable) # generalized + assert isinstance(frame.locals_stack_w[frame.nlocals-1], Variable) + # ^^^ generalized def test_union_spectag(self): frame = self.getframe(self.func_simple) fs1 = FrameState(frame) - frame.fastlocals_w[-1] = Constant(SpecTag()) + frame.locals_stack_w[frame.nlocals-1] = Constant(SpecTag()) fs2 = FrameState(frame) assert fs1.union(fs2) is None # UnionError diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -374,7 +374,7 @@ raise operationerrfmt( space.w_TypeError, "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space, '?')) + "found", i, space.type(w_s).getname(space)) if data and i != 0: newdata.extend(data) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -4,8 +4,9 @@ speed up global lookups a lot.""" from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash -from pypy.rlib import jit +from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string +from pypy.objspace.std.dictmultiobject import ObjectDictStrategy +from pypy.rlib import jit, rerased class ModuleCell(object): def __init__(self, w_value=None): @@ -19,49 +20,59 @@ def __repr__(self): return "" % (self.w_value, ) -class ModuleDictImplementation(W_DictMultiObject): +class ModuleDictStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("modulecell") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + def __init__(self, space): self.space = space - self.content = {} - def getcell(self, key, makenew): + def get_empty_storage(self): + return self.erase({}) + + def getcell(self, w_dict, key, makenew): if makenew or jit.we_are_jitted(): # when we are jitting, we always go through the pure function # below, to ensure that we have no residual dict lookup - self = jit.hint(self, promote=True) - return self._getcell_makenew(key) - return self.content.get(key, None) + w_dict = jit.promote(w_dict) + self = jit.promote(self) + return self._getcell_makenew(w_dict, key) + return self.unerase(w_dict.dstorage).get(key, None) - @jit.purefunction - def _getcell_makenew(self, key): - return self.content.setdefault(key, ModuleCell()) + @jit.elidable + def _getcell_makenew(self, w_dict, key): + return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, name, w_value): - self.getcell(name, True).w_value = w_value + def setitem_str(self, w_dict, key, w_value): + self.getcell(w_dict, key, True).w_value = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(space.str_w(w_key), True) + cell = self.getcell(w_dict, space.str_w(w_key), True) if cell.w_value is None: cell.w_value = w_default return cell.w_value else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(key, False) + cell = self.getcell(w_dict, key, False) if cell is None or cell.w_value is None: raise KeyError # note that we don't remove the cell from self.content, to make @@ -69,75 +80,91 @@ # maps to the same cell later (even if this cell no longer # represents a key) cell.invalidate() - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) - - def impl_length(self): + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) + + def length(self, w_dict): # inefficient, but do we care? res = 0 - for cell in self.content.itervalues(): + for cell in self.unerase(w_dict.dstorage).itervalues(): if cell.w_value is not None: res += 1 return res - def impl_getitem(self, w_lookup): + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, lookup): - res = self.getcell(lookup, False) + def getitem_str(self, w_dict, key): + res = self.getcell(w_dict, key, False) if res is None: return None # note that even if the res.w_value is None, the next line is fine return res.w_value - def impl_iter(self): - return ModuleDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return ModuleDictIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key, cell in self.content.iteritems() + iterator = self.unerase(w_dict.dstorage).iteritems + return [space.wrap(key) for key, cell in iterator() if cell.w_value is not None] - def impl_values(self): - return [cell.w_value for cell in self.content.itervalues() + def values(self, w_dict): + iterator = self.unerase(w_dict.dstorage).itervalues + return [cell.w_value for cell in iterator() if cell.w_value is not None] - def impl_items(self): + def items(self, w_dict): space = self.space + iterator = self.unerase(w_dict.dstorage).iteritems return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in self.content.iteritems() + for (key, cell) in iterator() if cell.w_value is not None] - def impl_clear(self): - for k, cell in self.content.iteritems(): + def clear(self, w_dict): + iterator = self.unerase(w_dict.dstorage).iteritems + for k, cell in iterator(): cell.invalidate() - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, cell in self.content.iteritems(): + def popitem(self, w_dict): + # This is O(n) if called repeatadly, you probably shouldn't be on a + # Module's dict though + for k, cell in self.unerase(w_dict.dstorage).iteritems(): if cell.w_value is not None: - r_dict_content[self.space.wrap(k)] = cell.w_value - cell.invalidate() - self._clear_fields() - return self + w_value = cell.w_value + cell.invalidate() + return self.space.wrap(k), w_value + else: + raise KeyError - def _clear_fields(self): - self.content = None + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, cell in d.iteritems(): + if cell.w_value is not None: + d_new[self.space.wrap(key)] = cell.w_value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) class ModuleDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + dict_w = strategy.unerase(dictimplementation.dstorage) + self.iterator = dict_w.iteritems() def next_entry(self): for key, cell in self.iterator: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,18 +1,20 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS -from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize +from pypy.rlib.debug import mark_dict_non_null + +from pypy.rlib import rerased def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) -def _is_sane_hash(space, w_lookup_type): +def _never_equal_to_string(space, w_lookup_type): """ Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. @@ -28,48 +30,38 @@ class W_DictMultiObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef - r_dict_content = None - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, classofinstance=None, strdict=False): + if space.config.objspace.std.withcelldict and module: - from pypy.objspace.std.celldict import ModuleDictImplementation + from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - return ModuleDictImplementation(space) - elif space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and module: - assert w_type is None - return WaryDictImplementation(space) - elif space.config.objspace.std.withdictmeasurement: - assert w_type is None - return MeasuringDictImplementation(space) + strategy = space.fromcache(ModuleDictStrategy) + elif instance or strdict or module: assert w_type is None - return StrDictImplementation(space) + strategy = space.fromcache(StringDictStrategy) + else: - if w_type is None: - w_type = space.w_dict - w_self = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_self, space) - return w_self + strategy = space.fromcache(EmptyDictStrategy) - def __init__(self, space): + if w_type is None: + w_type = space.w_dict + storage = strategy.get_empty_storage() + w_self = space.allocate_instance(W_DictMultiObject, w_type) + W_DictMultiObject.__init__(w_self, space, strategy, storage) + return w_self + + def __init__(self, space, strategy, storage): self.space = space - - def initialize_as_rdict(self): - assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) - return self.r_dict_content - - - def initialize_content(w_self, list_pairs_w): - for w_k, w_v in list_pairs_w: - w_self.setitem(w_k, w_v) + self.strategy = strategy + self.dstorage = storage def __repr__(w_self): """ representation for debugging purposes """ - return "%s()" % (w_self.__class__.__name__, ) + return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): result = {} @@ -88,51 +80,38 @@ else: return None - # _________________________________________________________________ - # implementation methods - def impl_getitem(self, w_key): - #return w_value or None - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - # return None anyway - return None + def initialize_content(w_self, list_pairs_w): + for w_k, w_v in list_pairs_w: + w_self.setitem(w_k, w_v) - def impl_getitem_str(self, key): - #return w_value or None - return None +def _add_indirections(): + dict_methods = "setitem setitem_str getitem \ + getitem_str delitem length \ + clear keys values \ + items iter setdefault \ + popitem".split() - def impl_setdefault(self, w_key, w_default): - # here the dict is always empty - self._as_rdict().impl_fallback_setitem(w_key, w_default) - return w_default + def make_method(method): + def f(self, *args): + return getattr(self.strategy, method)(self, *args) + f.func_name = method + return f - def impl_setitem(self, w_key, w_value): - self._as_rdict().impl_fallback_setitem(w_key, w_value) + for method in dict_methods: + setattr(W_DictMultiObject, method, make_method(method)) - def impl_setitem_str(self, key, w_value): - self._as_rdict().impl_fallback_setitem_str(key, w_value) +_add_indirections() - def impl_delitem(self, w_key): - # in case the key is unhashable, try to hash it - self.space.hash(w_key) - raise KeyError +class DictStrategy(object): - def impl_length(self): - return 0 + def __init__(self, space): + self.space = space - def impl_iter(self): - # XXX I guess it's not important to be fast in this case? - return self._as_rdict().impl_fallback_iter() + def get_empty_storage(self): + raise NotImplementedError - def impl_clear(self): - self.r_dict_content = None - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - return self - - def impl_keys(self): - iterator = self.impl_iter() + def keys(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -140,8 +119,9 @@ result.append(w_key) else: return result - def impl_values(self): - iterator = self.impl_iter() + + def values(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -149,8 +129,9 @@ result.append(w_value) else: return result - def impl_items(self): - iterator = self.impl_iter() + + def items(self, w_dict): + iterator = self.iter(w_dict) result = [] while 1: w_key, w_value = iterator.next() @@ -159,106 +140,90 @@ else: return result - # the following method only makes sense when the option to use the - # CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen - # by the annotator - def impl_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_getitem_str(key) + def clear(self, w_dict): + strategy = self.space.fromcache(EmptyDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_popitem(self): - # default implementation - space = self.space - iterator = self.impl_iter() - w_key, w_value = iterator.next() - if w_key is None: - raise KeyError - self.impl_delitem(w_key) - return w_key, w_value - # _________________________________________________________________ - # fallback implementation methods +class EmptyDictStrategy(DictStrategy): - def impl_fallback_setdefault(self, w_key, w_default): - return self.r_dict_content.setdefault(w_key, w_default) + erase, unerase = rerased.new_erasing_pair("empty") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_fallback_setitem(self, w_key, w_value): - self.r_dict_content[w_key] = w_value + def get_empty_storage(self): + return self.erase(None) - def impl_fallback_setitem_str(self, key, w_value): - return self.impl_fallback_setitem(self.space.wrap(key), w_value) + def switch_to_correct_strategy(self, w_dict, w_key): + #XXX implement other strategies later + if type(w_key) is self.space.StringObjectCls: + self.switch_to_string_strategy(w_dict) + elif self.space.is_w(self.space.type(w_key), self.space.w_int): + self.switch_to_int_strategy(w_dict) + else: + self.switch_to_object_strategy(w_dict) - def impl_fallback_delitem(self, w_key): - del self.r_dict_content[w_key] + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_length(self): - return len(self.r_dict_content) + def switch_to_int_strategy(self, w_dict): + strategy = self.space.fromcache(IntDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem(self, w_key): - return self.r_dict_content.get(w_key, None) + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage - def impl_fallback_getitem_str(self, key): - return self.r_dict_content.get(self.space.wrap(key), None) + def getitem(self, w_dict, w_key): + #return w_value or None + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + # return None anyway + return None - def impl_fallback_iter(self): - return RDictIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + #return w_value or None + return None - def impl_fallback_keys(self): - return self.r_dict_content.keys() - def impl_fallback_values(self): - return self.r_dict_content.values() - def impl_fallback_items(self): - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.r_dict_content.iteritems()] + def setdefault(self, w_dict, w_key, w_default): + # here the dict is always empty + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_default) + return w_default - def impl_fallback_clear(self): - self.r_dict_content.clear() + def setitem(self, w_dict, w_key, w_value): + self.switch_to_correct_strategy(w_dict, w_key) + w_dict.setitem(w_key, w_value) - def impl_fallback_get_builtin_indexed(self, i): - key = OPTIMIZED_BUILTINS[i] - return self.impl_fallback_getitem_str(key) + def setitem_str(self, w_dict, key, w_value): + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) - def impl_fallback_popitem(self): - return self.r_dict_content.popitem() + def delitem(self, w_dict, w_key): + # in case the key is unhashable, try to hash it + self.space.hash(w_key) + raise KeyError + def length(self, w_dict): + return 0 -implementation_methods = [ - ("getitem", 1), - ("getitem_str", 1), - ("length", 0), - ("setitem_str", 2), - ("setitem", 2), - ("setdefault", 2), - ("delitem", 1), - ("iter", 0), - ("items", 0), - ("values", 0), - ("keys", 0), - ("clear", 0), - ("get_builtin_indexed", 1), - ("popitem", 0), -] + def iter(self, w_dict): + return EmptyIteratorImplementation(self.space, w_dict) + def clear(self, w_dict): + return -def _make_method(name, implname, fallback, numargs): - args = ", ".join(["a" + str(i) for i in range(numargs)]) - code = """def %s(self, %s): - if self.r_dict_content is not None: - return self.%s(%s) - return self.%s(%s)""" % (name, args, fallback, args, implname, args) - d = {} - exec py.code.Source(code).compile() in d - implementation_method = d[name] - implementation_method.func_defaults = getattr(W_DictMultiObject, implname).func_defaults - return implementation_method - -def _install_methods(): - for name, numargs in implementation_methods: - implname = "impl_" + name - fallbackname = "impl_fallback_" + name - func = _make_method(name, implname, fallbackname, numargs) - setattr(W_DictMultiObject, name, func) -_install_methods() + def popitem(self, w_dict): + raise KeyError registerimplementation(W_DictMultiObject) @@ -300,319 +265,255 @@ return self.len - self.pos return 0 +class EmptyIteratorImplementation(IteratorImplementation): + def next(self): + return (None, None) + # concrete subclasses of the above -class StrDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = {} +class AbstractTypedStrategy(object): + _mixin_ = True - def impl_setitem(self, w_key, w_value): + @staticmethod + def erase(storage): + raise NotImplementedError("abstract base class") + + @staticmethod + def unerase(obj): + raise NotImplementedError("abstract base class") + + def wrap(self, unwrapped): + raise NotImplementedError + + def unwrap(self, wrapped): + raise NotImplementedError + + def is_correct_type(self, w_obj): + raise NotImplementedError("abstract base class") + + def get_empty_storage(self): + raise NotImplementedError("abstract base class") + + def _never_equal_to(self, w_lookup_type): + raise NotImplementedError("abstract base class") + + def setitem(self, w_dict, w_key, w_value): space = self.space - if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + if self.is_correct_type(w_key): + self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value + return else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setitem_str(self, key, w_value): - self.content[key] = w_value + def setitem_str(self, w_dict, key, w_value): + self.switch_to_object_strategy(w_dict) + w_dict.setitem(self.space.wrap(key), w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.content.setdefault(space.str_w(w_key), w_default) + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - del self.content[space.str_w(w_key)] + if self.is_correct_type(w_key): + del self.unerase(w_dict.dstorage)[self.unwrap(w_key)] return - elif _is_sane_hash(space, w_key_type): - raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) - def impl_length(self): - return len(self.content) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)) - def impl_getitem_str(self, key): - return self.content.get(key, None) + def getitem_str(self, w_dict, key): + return self.getitem(w_dict, self.space.wrap(key)) - def impl_getitem(self, w_key): + def getitem(self, w_dict, w_key): + space = self.space + + if self.is_correct_type(w_key): + return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def keys(self, w_dict): + return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()] + + def values(self, w_dict): + return self.unerase(w_dict.dstorage).values() + + def items(self, w_dict): + space = self.space + dict_w = self.unerase(w_dict.dstorage) + return [space.newtuple([self.wrap(key), w_value]) + for (key, w_value) in dict_w.iteritems()] + + def popitem(self, w_dict): + key, value = self.unerase(w_dict.dstorage).popitem() + return (self.wrap(key), value) + + def clear(self, w_dict): + self.unerase(w_dict.dstorage).clear() + + def switch_to_object_strategy(self, w_dict): + d = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + d_new = strategy.unerase(strategy.get_empty_storage()) + for key, value in d.iteritems(): + d_new[self.wrap(key)] = value + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + +class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("object") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def is_correct_type(self, w_obj): + return True + + def get_empty_storage(self): + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return ObjectIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + +class StringDictStrategy(AbstractTypedStrategy, DictStrategy): + + erase, unerase = rerased.new_erasing_pair("string") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def get_empty_storage(self): + res = {} + mark_dict_non_null(res) + return self.erase(res) + + def _never_equal_to(self, w_lookup_type): + return _never_equal_to_string(self.space, w_lookup_type) + + def setitem_str(self, w_dict, key, w_value): + assert key is not None + self.unerase(w_dict.dstorage)[key] = w_value + + def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: - return self.impl_getitem_str(w_key.unwrap(space)) + return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- - w_lookup_type = space.type(w_key) - if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_key)) - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().impl_fallback_getitem(w_key) + return AbstractTypedStrategy.getitem(self, w_dict, w_key) - def impl_iter(self): - return StrIteratorImplementation(self.space, self) + def getitem_str(self, w_dict, key): + assert key is not None + return self.unerase(w_dict.dstorage).get(key, None) - def impl_keys(self): - space = self.space - return [space.wrap(key) for key in self.content.iterkeys()] + def iter(self, w_dict): + return StrIteratorImplementation(self.space, self, w_dict) - def impl_values(self): - return self.content.values() - - def impl_items(self): - space = self.space - return [space.newtuple([space.wrap(key), w_value]) - for (key, w_value) in self.content.iteritems()] - - def impl_clear(self): - self.content.clear() - - - def _as_rdict(self): - r_dict_content = self.initialize_as_rdict() - for k, w_v in self.content.items(): - r_dict_content[self.space.wrap(k)] = w_v - self._clear_fields() - return self - - def _clear_fields(self): - self.content = None class StrIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for str, w_value in self.iterator: - return self.space.wrap(str), w_value + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None -class WaryDictImplementation(StrDictImplementation): - def __init__(self, space): - StrDictImplementation.__init__(self, space) - self.shadowed = [None] * len(BUILTIN_TO_INDEX) +class IntDictStrategy(AbstractTypedStrategy, DictStrategy): + erase, unerase = rerased.new_erasing_pair("int") + erase = staticmethod(erase) + unerase = staticmethod(unerase) - def impl_setitem_str(self, key, w_value): - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = w_value - self.content[key] = w_value + def wrap(self, unwrapped): + return self.space.wrap(unwrapped) - def impl_delitem(self, w_key): + def unwrap(self, wrapped): + return self.space.int_w(wrapped) + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - del self.content[key] - i = BUILTIN_TO_INDEX.get(key, -1) - if i != -1: - self.shadowed[i] = None - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - self._as_rdict().impl_fallback_delitem(w_key) + return space.is_w(space.type(w_obj), space.w_int) - def impl_get_builtin_indexed(self, i): - return self.shadowed[i] + def _never_equal_to(self, w_lookup_type): + space = self.space + # XXX there are many more types + return (space.is_w(w_lookup_type, space.w_NoneType) or + space.is_w(w_lookup_type, space.w_str) or + space.is_w(w_lookup_type, space.w_unicode) + ) + def iter(self, w_dict): + return IntIteratorImplementation(self.space, self, w_dict) -class RDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): +class IntIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.r_dict_content.iteritems() + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() def next_entry(self): # note that this 'for' loop only runs once, at most - for item in self.iterator: - return item + for key, w_value in self.iterator: + return self.space.wrap(key), w_value else: return None, None +class ObjectIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() -# XXX fix this thing -import time - -class DictInfo(object): - _dict_infos = [] - def __init__(self): - self.id = len(self._dict_infos) - - self.setitem_strs = 0; self.setitems = 0; self.delitems = 0 - self.lengths = 0; self.gets = 0 - self.iteritems = 0; self.iterkeys = 0; self.itervalues = 0 - self.keys = 0; self.values = 0; self.items = 0 - - self.maxcontents = 0 - - self.reads = 0 - self.hits = self.misses = 0 - self.writes = 0 - self.iterations = 0 - self.listings = 0 - - self.seen_non_string_in_write = 0 - self.seen_non_string_in_read_first = 0 - self.size_on_non_string_seen_in_read = -1 - self.size_on_non_string_seen_in_write = -1 - - self.createtime = time.time() - self.lifetime = -1.0 - - if not we_are_translated(): - # very probable stack from here: - # 0 - us - # 1 - MeasuringDictImplementation.__init__ - # 2 - W_DictMultiObject.__init__ - # 3 - space.newdict - # 4 - newdict's caller. let's look at that - try: - frame = sys._getframe(4) - except ValueError: - pass # might be at import time - else: - self.sig = '(%s:%s)%s'%(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name) - - self._dict_infos.append(self) - def __repr__(self): - args = [] - for k in sorted(self.__dict__): - v = self.__dict__[k] - if v != 0: - args.append('%s=%r'%(k, v)) - return ''%(', '.join(args),) - -class OnTheWayOut: - def __init__(self, info): - self.info = info - def __del__(self): - self.info.lifetime = time.time() - self.info.createtime - -class MeasuringDictImplementation(W_DictMultiObject): - def __init__(self, space): - self.space = space - self.content = r_dict(space.eq_w, space.hash_w) - self.info = DictInfo() - self.thing_with_del = OnTheWayOut(self.info) - - def __repr__(self): - return "%s<%s>" % (self.__class__.__name__, self.content) - - def _is_str(self, w_key): - space = self.space - return space.is_true(space.isinstance(w_key, space.w_str)) - def _read(self, w_key): - self.info.reads += 1 - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - hit = w_key in self.content - if hit: - self.info.hits += 1 + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value else: - self.info.misses += 1 - - def impl_setitem(self, w_key, w_value): - if not self.info.seen_non_string_in_write and not self._is_str(w_key): - self.info.seen_non_string_in_write = True - self.info.size_on_non_string_seen_in_write = len(self.content) - self.info.setitems += 1 - self.info.writes += 1 - self.content[w_key] = w_value - self.info.maxcontents = max(self.info.maxcontents, len(self.content)) - def impl_setitem_str(self, key, w_value): - self.info.setitem_strs += 1 - self.impl_setitem(self.space.wrap(key), w_value) - def impl_delitem(self, w_key): - if not self.info.seen_non_string_in_write \ - and not self.info.seen_non_string_in_read_first \ - and not self._is_str(w_key): - self.info.seen_non_string_in_read_first = True - self.info.size_on_non_string_seen_in_read = len(self.content) - self.info.delitems += 1 - self.info.writes += 1 - del self.content[w_key] - - def impl_length(self): - self.info.lengths += 1 - return len(self.content) - def impl_getitem_str(self, key): - return self.impl_getitem(self.space.wrap(key)) - def impl_getitem(self, w_key): - self.info.gets += 1 - self._read(w_key) - return self.content.get(w_key, None) - - def impl_iteritems(self): - self.info.iteritems += 1 - self.info.iterations += 1 - return RDictItemIteratorImplementation(self.space, self) - def impl_iterkeys(self): - self.info.iterkeys += 1 - self.info.iterations += 1 - return RDictKeyIteratorImplementation(self.space, self) - def impl_itervalues(self): - self.info.itervalues += 1 - self.info.iterations += 1 - return RDictValueIteratorImplementation(self.space, self) - - def impl_keys(self): - self.info.keys += 1 - self.info.listings += 1 - return self.content.keys() - def impl_values(self): - self.info.values += 1 - self.info.listings += 1 - return self.content.values() - def impl_items(self): - self.info.items += 1 - self.info.listings += 1 - return [self.space.newtuple([w_key, w_val]) - for w_key, w_val in self.content.iteritems()] - - -_example = DictInfo() -del DictInfo._dict_infos[-1] -tmpl = 'os.write(fd, "%(attr)s" + ": " + str(info.%(attr)s) + "\\n")' -bodySrc = [] -for attr in sorted(_example.__dict__): - if attr == 'sig': - continue - bodySrc.append(tmpl%locals()) -exec py.code.Source(''' -from pypy.rlib.objectmodel import current_object_addr_as_int -def _report_one(fd, info): - os.write(fd, "_address" + ": " + str(current_object_addr_as_int(info)) - + "\\n") - %s -'''%'\n '.join(bodySrc)).compile() - -def report(): - if not DictInfo._dict_infos: - return - os.write(2, "Starting multidict report.\n") - fd = os.open('dictinfo.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644) - for info in DictInfo._dict_infos: - os.write(fd, '------------------\n') - _report_one(fd, info) - os.close(fd) - os.write(2, "Reporting done.\n") - + return None, None init_signature = Signature(['seq_or_map'], None, 'kwargs') @@ -835,6 +736,8 @@ class W_DictMultiIterObject(W_Object): from pypy.objspace.std.dicttype import dictiter_typedef as typedef + _immutable_fields_ = ["iteratorimplementation", "itertype"] + def __init__(w_self, space, iteratorimplementation, itertype): w_self.space = space w_self.iteratorimplementation = iteratorimplementation @@ -919,7 +822,7 @@ def repr__DictViewKeys(space, w_dictview): w_seq = space.call_function(space.w_list, w_dictview) w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space, "?"), + return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), space.str_w(w_repr))) repr__DictViewItems = repr__DictViewKeys repr__DictViewValues = repr__DictViewKeys diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,96 +1,98 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation +from pypy.objspace.std.dictmultiobject import DictStrategy from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError +from pypy.rlib import rerased -class W_DictProxyObject(W_DictMultiObject): - def __init__(w_self, space, w_type): - W_DictMultiObject.__init__(w_self, space) - w_self.w_type = w_type - def impl_getitem(self, w_lookup): +class DictProxyStrategy(DictStrategy): + + erase, unerase = rerased.new_erasing_pair("dictproxy") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(w_self, space): + DictStrategy.__init__(w_self, space) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) + return self.getitem_str(w_dict, space.str_w(w_key)) else: return None - def impl_getitem_str(self, lookup): - return self.w_type.getdictvalue(self.space, lookup) + def getitem_str(self, w_dict, key): + return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) - def impl_setitem_str(self, name, w_value): + def setitem_str(self, w_dict, key, w_value): + w_type = self.unerase(w_dict.dstorage) try: - self.w_type.setdictvalue(self.space, name, w_value) + w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise - w_type = self.w_type if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. - w_type.dict_w[name] = w_value + w_type.dict_w[key] = w_value - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space - w_result = self.impl_getitem(w_key) + w_result = self.getitem(w_dict, w_key) if w_result is not None: return w_result - self.impl_setitem(w_key, w_default) + self.setitem(w_dict, w_key, w_default) return w_default - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.w_type.deldictvalue(space, w_key): + if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): raise KeyError else: raise KeyError - def impl_length(self): - return len(self.w_type.dict_w) + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage).dict_w) - def impl_iter(self): - return DictProxyIteratorImplementation(self.space, self) + def iter(self, w_dict): + return DictProxyIteratorImplementation(self.space, self, w_dict) - def impl_keys(self): + def keys(self, w_dict): space = self.space - return [space.wrap(key) for key in self.w_type.dict_w.iterkeys()] + return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()] - def impl_values(self): - return [unwrap_cell(self.space, w_value) for w_value in self.w_type.dict_w.itervalues()] + def values(self, w_dict): + return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()] - def impl_items(self): + def items(self, w_dict): space = self.space return [space.newtuple([space.wrap(key), unwrap_cell(self.space, w_value)]) - for (key, w_value) in self.w_type.dict_w.iteritems()] + for (key, w_value) in self.unerase(w_dict.dstorage).dict_w.iteritems()] - def impl_clear(self): - self.w_type.dict_w.clear() - self.w_type.mutated() - - def _as_rdict(self): - assert 0, "should be unreachable" - - def _clear_fields(self): - assert 0, "should be unreachable" + def clear(self, w_dict): + self.unerase(w_dict.dstorage).dict_w.clear() + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.w_type.dict_w.iteritems() + w_type = strategy.unerase(dictimplementation.dstorage) + self.iterator = w_type.dict_w.iteritems() def next_entry(self): for key, w_value in self.iterator: diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py --- a/pypy/objspace/std/frame.py +++ b/pypy/objspace/std/frame.py @@ -6,7 +6,7 @@ from pypy.interpreter import pyopcode, function from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module +from pypy.module.__builtin__ import Module from pypy.objspace.std import intobject, smallintobject from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.dictmultiobject import W_DictMultiObject @@ -66,41 +66,6 @@ w_result = f.space.getitem(w_1, w_2) f.pushvalue(w_result) -def CALL_LIKELY_BUILTIN(f, oparg, next_instr): - w_globals = f.w_globals - num = oparg >> 8 - assert isinstance(w_globals, W_DictMultiObject) - w_value = w_globals.get_builtin_indexed(num) - if w_value is None: - builtins = f.get_builtin() - assert isinstance(builtins, Module) - w_builtin_dict = builtins.getdict(f.space) - assert isinstance(w_builtin_dict, W_DictMultiObject) - w_value = w_builtin_dict.get_builtin_indexed(num) - if w_value is None: - varname = OPTIMIZED_BUILTINS[num] - message = "global name '%s' is not defined" - raise operationerrfmt(f.space.w_NameError, - message, varname) - nargs = oparg & 0xff - w_function = w_value - try: - w_result = call_likely_builtin(f, w_function, nargs) - finally: - f.dropvalues(nargs) - f.pushvalue(w_result) - -def call_likely_builtin(f, w_function, nargs): - if isinstance(w_function, function.Function): - executioncontext = f.space.getexecutioncontext() - executioncontext.c_call_trace(f, w_function) - res = w_function.funccall_valuestack(nargs, f) - executioncontext.c_return_trace(f, w_function) - return res - args = f.make_arguments(nargs) - return f.space.call_args(w_function, args) - - compare_table = [ "lt", # "<" "le", # "<=" @@ -145,8 +110,6 @@ StdObjSpaceFrame.BINARY_ADD = int_BINARY_ADD if space.config.objspace.std.optimized_list_getitem: StdObjSpaceFrame.BINARY_SUBSCR = list_BINARY_SUBSCR - if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN: - StdObjSpaceFrame.CALL_LIKELY_BUILTIN = CALL_LIKELY_BUILTIN if space.config.objspace.opcodes.CALL_METHOD: from pypy.objspace.std.callmethod import LOOKUP_METHOD, CALL_METHOD StdObjSpaceFrame.LOOKUP_METHOD = LOOKUP_METHOD diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -4,9 +4,9 @@ from pypy.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy from pypy.objspace.std.dictmultiobject import IteratorImplementation -from pypy.objspace.std.dictmultiobject import _is_sane_hash +from pypy.objspace.std.dictmultiobject import _never_equal_to_string from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.typeobject import TypeCell @@ -53,7 +53,7 @@ else: return self._index_indirection(selector) - @jit.purefunction + @jit.elidable def _index_jit_pure(self, name, index): return self._index_indirection((name, index)) @@ -113,14 +113,14 @@ def set_terminator(self, obj, terminator): raise NotImplementedError("abstract base class") - @jit.purefunction + @jit.elidable def size_estimate(self): return self._size_estimate >> NUM_DIGITS def search(self, attrtype): return None - @jit.purefunction + @jit.elidable def _get_new_attr(self, name, index): selector = name, index cache = self.cache_attrs @@ -154,7 +154,7 @@ obj._set_mapdict_map(attr) obj._mapdict_write_storage(attr.position, w_value) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") def remove_dict_entries(self, obj): @@ -205,7 +205,7 @@ Terminator.__init__(self, space, w_cls) self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls) - def materialize_r_dict(self, space, obj, w_d): + def materialize_r_dict(self, space, obj, dict_w): result = Object() result.space = space result._init_empty(self.devolved_dict_terminator) @@ -297,11 +297,11 @@ return self return self.back.search(attrtype) - def materialize_r_dict(self, space, obj, w_d): - new_obj = self.back.materialize_r_dict(space, obj, w_d) + def materialize_r_dict(self, space, obj, dict_w): + new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - w_d.r_dict_content[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.position) else: self._copy_attr(obj, new_obj) return new_obj @@ -357,7 +357,7 @@ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) def _get_mapdict_map(self): - return jit.hint(self.map, promote=True) + return jit.promote(self.map) def _set_mapdict_map(self, map): self.map = map # _____________________________________________ @@ -382,7 +382,10 @@ if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict - w_dict = MapDictImplementation(space, self) + + strategy = space.fromcache(MapDictStrategy) + storage = strategy.erase(self) + w_dict = W_DictMultiObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -392,8 +395,8 @@ w_dict = check_new_dictionary(space, w_dict) w_olddict = self.getdict(space) assert isinstance(w_dict, W_DictMultiObject) - if w_olddict.r_dict_content is None: - w_olddict._as_rdict() + if type(w_olddict.strategy) is not ObjectDictStrategy: + w_olddict.strategy.switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -575,105 +578,121 @@ # ____________________________________________________________ # dict implementation +class MapDictStrategy(DictStrategy): -class MapDictImplementation(W_DictMultiObject): - def __init__(self, space, w_obj): + erase, unerase = rerased.new_erasing_pair("map") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def __init__(self, space): self.space = space - self.w_obj = w_obj - def impl_getitem(self, w_lookup): + def switch_to_object_strategy(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) + strategy = self.space.fromcache(ObjectDictStrategy) + dict_w = strategy.unerase(strategy.get_empty_storage()) + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(dict_w) + assert w_obj.getdict(self.space) is w_dict + materialize_r_dict(self.space, w_obj, dict_w) + + def getitem(self, w_dict, w_key): space = self.space - w_lookup_type = space.type(w_lookup) + w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): - return self.impl_getitem_str(space.str_w(w_lookup)) - elif _is_sane_hash(space, w_lookup_type): + return self.getitem_str(w_dict, space.str_w(w_key)) + elif _never_equal_to_string(space, w_lookup_type): return None else: - return self._as_rdict().impl_fallback_getitem(w_lookup) + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) - def impl_getitem_str(self, key): - return self.w_obj.getdictvalue(self.space, key) + def getitem_str(self, w_dict, key): + w_obj = self.unerase(w_dict.dstorage) + return w_obj.getdictvalue(self.space, key) - def impl_setitem_str(self, key, w_value): - flag = self.w_obj.setdictvalue(self.space, key, w_value) + def setitem_str(self, w_dict, key, w_value): + w_obj = self.unerase(w_dict.dstorage) + flag = w_obj.setdictvalue(self.space, key, w_value) assert flag - def impl_setitem(self, w_key, w_value): + def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): - self.impl_setitem_str(self.space.str_w(w_key), w_value) + self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: - self._as_rdict().impl_fallback_setitem(w_key, w_value) + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) - def impl_setdefault(self, w_key, w_default): + def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) - w_result = self.impl_getitem_str(key) + w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result - self.impl_setitem_str(key, w_default) + self.setitem_str(w_dict, key, w_default) return w_default else: - return self._as_rdict().impl_fallback_setdefault(w_key, w_default) + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) - def impl_delitem(self, w_key): + def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) + w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = self.w_obj.deldictvalue(space, w_key) + flag = w_obj.deldictvalue(space, w_key) if not flag: raise KeyError - elif _is_sane_hash(space, w_key_type): + elif _never_equal_to_string(space, w_key_type): raise KeyError else: - self._as_rdict().impl_fallback_delitem(w_key) + self.switch_to_object_strategy(w_dict) + w_dict.delitem(w_key) - def impl_length(self): + def length(self, w_dict): res = 0 - curr = self.w_obj._get_mapdict_map().search(DICT) + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res - def impl_iter(self): - return MapDictIteratorImplementation(self.space, self) + def iter(self, w_dict): + return MapDictIteratorImplementation(self.space, self, w_dict) - def impl_clear(self): - w_obj = self.w_obj + def clear(self, w_dict): + w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) - def _clear_fields(self): - self.w_obj = None + def popitem(self, w_dict): + curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) + if curr is None: + raise KeyError + key = curr.selector[0] + w_value = self.getitem_str(w_dict, key) + w_key = self.space.wrap(key) + self.delitem(w_dict, w_key) + return (w_key, w_value) - def _as_rdict(self): - self.initialize_as_rdict() - space = self.space - w_obj = self.w_obj - materialize_r_dict(space, w_obj, self) - self._clear_fields() - return self - - -def materialize_r_dict(space, obj, w_d): +def materialize_r_dict(space, obj, dict_w): map = obj._get_mapdict_map() - assert obj.getdict(space) is w_d - new_obj = map.materialize_r_dict(space, obj, w_d) + new_obj = map.materialize_r_dict(space, obj, dict_w) _become(obj, new_obj) class MapDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) - w_obj = dictimplementation.w_obj + w_obj = strategy.unerase(dictimplementation.dstorage) self.w_obj = w_obj self.orig_map = self.curr_map = w_obj._get_mapdict_map() def next_entry(self): implementation = self.dictimplementation - assert isinstance(implementation, MapDictImplementation) + assert isinstance(implementation.strategy, MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -11,7 +11,7 @@ from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.rarithmetic import base_int, widen from pypy.rlib.objectmodel import we_are_translated -from pypy.rlib.jit import hint +from pypy.rlib import jit from pypy.rlib.rbigint import rbigint from pypy.tool.sourcetools import func_with_new_name @@ -255,7 +255,7 @@ w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result - from fake import fake_object + from pypy.objspace.std.fake import fake_object return fake_object(self, x) def wrap_exception_cls(self, x): @@ -311,6 +311,10 @@ classofinstance=classofinstance, strdict=strdict) + def newset(self): + from pypy.objspace.std.setobject import newset + return W_SetObject(self, newset(self)) + def newslice(self, w_start, w_end, w_step): return W_SliceObject(w_start, w_end, w_step) @@ -318,7 +322,7 @@ return W_SeqIterObject(w_obj) def type(self, w_obj): - hint(w_obj.__class__, promote=True) + jit.promote(w_obj.__class__) return w_obj.getclass(self) def lookup(self, w_obj, name): diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py --- a/pypy/objspace/std/ropeunicodeobject.py +++ b/pypy/objspace/std/ropeunicodeobject.py @@ -986,7 +986,7 @@ ## return space.wrap(0) ## return space.wrap(result) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -997,7 +997,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_RopeUnicodeObject = W_RopeUnicodeObject from pypy.objspace.std.ropeobject import W_RopeObject def str_strip__Rope_RopeUnicode(space, w_self, w_chars): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" @@ -466,12 +466,11 @@ return space.wrap(hash) def set_pop__Set(space, w_left): - for w_key in w_left.setdata: - break - else: + try: + w_key, _ = w_left.setdata.popitem() + except KeyError: raise OperationError(space.w_KeyError, space.wrap('pop from an empty set')) - del w_left.setdata[w_key] return w_key def and__Set_Set(space, w_left, w_other): diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,6 +1,7 @@ import py from pypy.conftest import gettestobjspace, option -from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy from pypy.objspace.std.test.test_dictmultiobject import FakeSpace from pypy.interpreter import gateway @@ -8,7 +9,15 @@ class TestCellDict(object): def test_basic_property(self): - d = ModuleDictImplementation(space) + strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + + # replace getcell with getcell from strategy + def f(key, makenew): + return strategy.getcell(d, key, makenew) + d.getcell = f + d.setitem("a", 1) assert d.getcell("a", False) is d.getcell("a", False) acell = d.getcell("a", False) @@ -29,3 +38,33 @@ assert d.getitem("a") is None assert d.getcell("a", False) is acell assert d.length() == 0 + +class AppTestCellDict(object): + OPTIONS = {"objspace.std.withcelldict": True} + + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + strategy = ModuleDictStrategy(cls.space) + storage = strategy.get_empty_storage() + cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + + def test_popitem(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + raises(KeyError, d.popitem) + d["a"] = 3 + x = d.popitem() + assert x == ("a", 3) + + def test_degenerate(self): + import __pypy__ + + d = self.d + assert "ModuleDict" in __pypy__.internal_repr(d) + d["a"] = 3 + del d["a"] + d[object()] = 5 + assert d.values() == [5] \ No newline at end of file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1,12 +1,13 @@ +import py import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.dictmultiobject import \ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ - StrDictImplementation + StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictImplementation +from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace - +from pypy.conftest import option class TestW_DictObject: @@ -17,7 +18,7 @@ space = self.space d = self.space.newdict() assert not self.space.is_true(d) - assert d.r_dict_content is None + assert type(d.strategy) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -137,31 +138,31 @@ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names) def test_equality(self): - d = {1:2} - f = {1:2} + d = {1: 2} + f = {1: 2} assert d == f - assert d != {1:3} + assert d != {1: 3} def test_clear(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} d.clear() assert len(d) == 0 def test_copy(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() assert d == dd assert not d is dd def test_get(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.get(1) == 2 - assert d.get(1,44) == 2 + assert d.get(1, 44) == 2 assert d.get(33) == None - assert d.get(33,44) == 44 + assert d.get(33, 44) == 44 def test_pop(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() result = dd.pop(1) assert result == 2 @@ -176,18 +177,18 @@ raises(KeyError, dd.pop, 33) def test_has_key(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} assert d.has_key(1) assert not d.has_key(33) def test_items(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} its = d.items() its.sort() - assert its == [(1,2),(3,4)] + assert its == [(1, 2), (3, 4)] def test_iteritems(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k, v in d.iteritems(): assert v == dd[k] @@ -195,33 +196,33 @@ assert not dd def test_iterkeys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() for k in d.iterkeys(): del dd[k] assert not dd def test_itervalues(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} values = [] for k in d.itervalues(): values.append(k) assert values == d.values() def test_keys(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} kys = d.keys() kys.sort() - assert kys == [1,3] + assert kys == [1, 3] def test_popitem(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} it = d.popitem() assert len(d) == 1 - assert it==(1,2) or it==(3,4) + assert it == (1, 2) or it == (3, 4) it1 = d.popitem() assert len(d) == 0 - assert (it!=it1) and (it1==(1,2) or it1==(3,4)) + assert (it != it1) and (it1 == (1, 2) or it1 == (3, 4)) raises(KeyError, d.popitem) def test_popitem_2(self): @@ -233,8 +234,33 @@ assert it1 == ('x', 5) raises(KeyError, d.popitem) + def test_popitem3(self): + #object + d = {"a": 1, 2: 2, "c": 3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert (2, 2) in l + assert ("c", 3) in l + + #string + d = {"a": 1, "b":2, "c":3} + l = [] + while True: + try: + l.append(d.popitem()) + except KeyError: + break; + assert ("a", 1) in l + assert ("b", 2) in l + assert ("c", 3) in l + def test_setdefault(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() x = dd.setdefault(1, 99) assert d == dd @@ -267,12 +293,12 @@ assert k.calls == 1 def test_update(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} dd = d.copy() d.update({}) assert d == dd - d.update({3:5, 6:7}) - assert d == {1:2, 3:5, 6:7} + d.update({3: 5, 6: 7}) + assert d == {1: 2, 3: 5, 6: 7} def test_update_iterable(self): d = {} @@ -297,15 +323,15 @@ assert d == {'foo': 'bar', 'baz': 1} def test_values(self): - d = {1:2, 3:4} + d = {1: 2, 3: 4} vals = d.values() vals.sort() assert vals == [2,4] def test_eq(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2} bool = d1 == d2 assert bool == True bool = d1 == d3 @@ -316,10 +342,10 @@ assert bool == True def test_lt(self): - d1 = {1:2, 3:4} - d2 = {1:2, 3:4} - d3 = {1:2, 3:5} - d4 = {1:2} + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} bool = d1 < d2 assert bool == False bool = d1 < d3 @@ -366,21 +392,17 @@ def test_new(self): d = dict() assert d == {} - args = [['a',2], [23,45]] + args = [['a', 2], [23, 45]] d = dict(args) - assert d == {'a':2, 23:45} + assert d == {'a': 2, 23: 45} d = dict(args, a=33, b=44) - assert d == {'a':33, 'b':44, 23:45} + assert d == {'a': 33, 'b': 44, 23: 45} d = dict(a=33, b=44) - assert d == {'a':33, 'b':44} - d = dict({'a':33, 'b':44}) - assert d == {'a':33, 'b':44} - try: d = dict(23) - except (TypeError, ValueError): pass - else: self.fail("dict(23) should raise!") - try: d = dict([[1,2,3]]) - except (TypeError, ValueError): pass - else: self.fail("dict([[1,2,3]]) should raise!") + assert d == {'a': 33, 'b': 44} + d = dict({'a': 33, 'b': 44}) + assert d == {'a': 33, 'b': 44} + raises((TypeError, ValueError), dict, 23) + raises((TypeError, ValueError), dict, [[1, 2, 3]]) def test_fromkeys(self): assert {}.fromkeys([1, 2], 1) == {1: 1, 2: 1} @@ -527,6 +549,12 @@ __missing__ = SpecialDescr(missing) assert X()['hi'] == 42 + def test_empty_dict(self): + d = {} + raises(KeyError, d.popitem) + assert d.items() == [] + assert d.values() == [] + assert d.keys() == [] class AppTest_DictMultiObject(AppTest_DictObject): @@ -706,10 +734,12 @@ class AppTestModuleDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") def w_impl_used(self, obj): import __pypy__ - assert "ModuleDictImplementation" in __pypy__.internal_repr(obj) + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) def test_check_module_uses_module_dict(self): m = type(__builtins__)("abc") @@ -719,6 +749,64 @@ d = type(__builtins__)("abc").__dict__ raises(KeyError, "d['def']") + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + +class AppTestStrategies(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_empty_to_string(self): + d = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + d["a"] = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + class O(object): + pass + o = O() + d = o.__dict__ = {} + assert "EmptyDictStrategy" in self.get_strategy(d) + o.a = 1 + assert "StringDictStrategy" in self.get_strategy(d) + + def test_empty_to_int(self): + import sys + d = {} + d[1] = "hi" + assert "IntDictStrategy" in self.get_strategy(d) + assert d[1L] == "hi" class FakeString(str): @@ -759,6 +847,10 @@ assert isinstance(string, str) return string + def int_w(self, integer): + assert isinstance(integer, int) + return integer + def wrap(self, obj): return obj @@ -790,6 +882,10 @@ w_StopIteration = StopIteration w_None = None + w_NoneType = type(None, None) + w_int = int + w_bool = bool + w_float = float StringObjectCls = FakeString w_dict = W_DictMultiObject iter = iter @@ -799,12 +895,9 @@ class Config: class objspace: class std: - withdictmeasurement = False withsmalldicts = False withcelldict = False withmethodcache = False - class opcodes: - CALL_LIKELY_BUILTIN = False FakeSpace.config = Config() @@ -834,14 +927,20 @@ self.impl = self.get_impl() def get_impl(self): - return self.ImplementionClass(self.fakespace) + strategy = self.StrategyClass(self.fakespace) + storage = strategy.get_empty_storage() + w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) + W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + return w_dict def fill_impl(self): self.impl.setitem(self.string, 1000) self.impl.setitem(self.string2, 2000) def check_not_devolved(self): - assert self.impl.r_dict_content is None + #XXX check if strategy changed!? + assert type(self.impl.strategy) is self.StrategyClass + #assert self.impl.r_dict_content is None def test_setitem(self): self.impl.setitem(self.string, 1000) @@ -913,7 +1012,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert impl.r_dict_content is not None + assert type(impl.strategy) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -928,8 +1027,38 @@ if on_pypy: assert key.hash_count == 2 + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + + d = self.get_impl() + d.setitem("s", 12) + assert d.getitem("s") == 12 + assert d.getitem(F()) == d.getitem("s") + + d = self.get_impl() + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + x = d.setdefault(F(), 12) + assert x == 12 + + d = self.get_impl() + d.setitem("s", 12) + d.delitem(F()) + + assert "s" not in d.keys() + assert F() not in d.keys() + class TestStrDictImplementation(BaseTestRDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy + #ImplementionClass = StrDictImplementation def test_str_shortcut(self): self.fill_impl() @@ -942,10 +1071,10 @@ ## DevolvedClass = MeasuringDictImplementation class TestModuleDictImplementation(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -954,19 +1083,19 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl._as_rdict() + self.impl.strategy.switch_to_object_strategy(self.impl) def check_not_devolved(self): pass class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = StrDictImplementation + StrategyClass = StringDictStrategy class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - ImplementionClass = ModuleDictImplementation + StrategyClass = ModuleDictStrategy string = "int" string2 = "isinstance" @@ -975,5 +1104,4 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert isinstance(d, StrDictImplementation) - + assert type(d.strategy) is StringDictStrategy diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -250,13 +250,18 @@ class FakeDict(W_DictMultiObject): def __init__(self, d): - self.r_dict_content = d + self.dstorage = d + + class strategy: + def unerase(self, x): + return d + strategy = strategy() d = {} w_d = FakeDict(d) flag = obj.map.write(obj, ("dict", SPECIAL), w_d) assert flag - materialize_r_dict(space, obj, w_d) + materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} assert obj.storage == [50, 60, 70, w_d] @@ -291,18 +296,18 @@ w_obj = cls.instantiate(self.fakespace) return w_obj.getdict(self.fakespace) class TestMapDictImplementation(BaseTestRDictImplementation): - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy get_impl = get_impl class TestDevolvedMapDictImplementation(BaseTestDevolvedDictImplementation): get_impl = get_impl - ImplementionClass = MapDictImplementation + StrategyClass = MapDictStrategy # ___________________________________________________________ # tests that check the obj interface after the dict has devolved def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d._as_rdict() + w_d.strategy.switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -463,6 +468,20 @@ d['dd'] = 43 assert a.dd == 41 + def test_popitem(self): + class A(object): + pass + a = A() + a.x = 5 + a.y = 6 + it1 = a.__dict__.popitem() + assert it1 == ("y", 6) + it2 = a.__dict__.popitem() + assert it2 == ("x", 5) + assert a.__dict__ == {} + raises(KeyError, a.__dict__.popitem) + + def test_slot_name_conflict(self): class A(object): @@ -604,6 +623,14 @@ assert a.__dict__ is d assert isinstance(a, B) + def test_setdict(self): + class A(object): + pass + + a = A() + a.__dict__ = {} + a.__dict__ = {} + class AppTestWithMapDictAndCounters(object): def setup_class(cls): diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -50,6 +50,10 @@ u = self.space.wrap(set('simsalabim')) assert self.space.eq_w(s,u) + def test_space_newset(self): + s = self.space.newset() + assert self.space.str_w(self.space.repr(s)) == 'set([])' + class AppTestAppSetTest: def test_subtype(self): class subset(set):pass diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -9,8 +9,8 @@ from pypy.objspace.std.objecttype import object_typedef from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash -from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted -from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe +from pypy.rlib.jit import promote, elidable_promote, we_are_jitted +from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe from pypy.rlib.rarithmetic import intmask, r_uint class TypeCell(W_Root): @@ -177,7 +177,7 @@ # prebuilt objects cannot get their version_tag changed return w_self._pure_version_tag() - @purefunction_promote() + @elidable_promote() def _pure_version_tag(w_self): return w_self._version_tag @@ -247,7 +247,7 @@ return w_value return w_value - @purefunction + @elidable def _pure_getdictvalue_no_unwrapping(w_self, space, version_tag, attr): return w_self._getdictvalue_no_unwrapping(space, attr) @@ -351,16 +351,16 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space - w_self = hint(w_self, promote=True) + promote(w_self) assert space.config.objspace.std.withmethodcache - version_tag = hint(w_self.version_tag(), promote=True) + version_tag = promote(w_self.version_tag()) if version_tag is None: tup = w_self._lookup_where(name) return tup w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag) return w_class, unwrap_cell(space, w_value) - @purefunction + @elidable def _pure_lookup_where_with_method_cache(w_self, name, version_tag): space = w_self.space cache = space.fromcache(MethodCache) @@ -423,10 +423,13 @@ return False def getdict(w_self, space): # returning a dict-proxy! - from pypy.objspace.std.dictproxyobject import W_DictProxyObject + from pypy.objspace.std.dictproxyobject import DictProxyStrategy + from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_self.lazyloaders: w_self._freeze_() # force un-lazification - return W_DictProxyObject(space, w_self) + strategy = space.fromcache(DictProxyStrategy) + storage = strategy.erase(w_self) + return W_DictMultiObject(space, strategy, storage) def unwrap(w_self, space): if w_self.instancetypedef.fakedcpytype is not None: @@ -447,8 +450,8 @@ w_self.flag_abstract = bool(abstract) def issubtype(w_self, w_type): - w_self = hint(w_self, promote=True) - w_type = hint(w_type, promote=True) + promote(w_self) + promote(w_type) if w_self.space.config.objspace.std.withtypeversion and we_are_jitted(): version_tag1 = w_self.version_tag() version_tag2 = w_type.version_tag() @@ -774,7 +777,7 @@ # ____________________________________________________________ def call__Type(space, w_type, __args__): - w_type = hint(w_type, promote=True) + promote(w_type) # special case for type(x) if space.is_w(w_type, space.w_type): try: @@ -820,7 +823,7 @@ def _issubtype(w_sub, w_type): return w_type in w_sub.mro_w - at purefunction_promote() + at elidable_promote() def _pure_issubtype(w_sub, w_type, version_tag1, version_tag2): return _issubtype(w_sub, w_type) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -937,7 +937,7 @@ return formatter.format_string(space.unicode_w(w_unicode)) -import unicodetype +from pypy.objspace.std import unicodetype register_all(vars(), unicodetype) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we @@ -948,7 +948,7 @@ # methods? class str_methods: - import stringtype + from pypy.objspace.std import stringtype W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.ropeobject import W_RopeObject diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py --- a/pypy/objspace/taint.py +++ b/pypy/objspace/taint.py @@ -92,8 +92,8 @@ w_realtype = space.type(w_obj) if not space.is_w(w_realtype, w_expectedtype): #msg = "expected an object of type '%s'" % ( - # w_expectedtype.getname(space, '?'),) - # #w_realtype.getname(space, '?')) + # w_expectedtype.getname(space),) + # #w_realtype.getname(space)) raise OperationError(space.w_TaintError, space.w_None) return w_obj app_untaint = gateway.interp2app(untaint) diff --git a/pypy/pytest.ini b/pypy/pytest.ini new file mode 100644 --- /dev/null +++ b/pypy/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --assertmode=old \ No newline at end of file diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py --- a/pypy/rlib/clibffi.py +++ b/pypy/rlib/clibffi.py @@ -10,6 +10,7 @@ from pypy.rlib.rmmap import alloc from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal from pypy.rlib.rdynload import DLOpenError, DLLHANDLE +from pypy.rlib import jit from pypy.tool.autopath import pypydir from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform @@ -18,6 +19,10 @@ import sys import ctypes.util +from pypy.tool.ansi_print import ansi_log +log = py.log.Producer("libffi") +py.log.setconsumer("libffi", ansi_log) + # maaaybe isinstance here would be better. Think _MSVC = platform.name == "msvc" _MINGW = platform.name == "mingw32" @@ -67,12 +72,17 @@ result = os.path.join(dir, 'libffi.a') if os.path.exists(result): return result - raise ImportError("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("'libffi.a' not found in %s" % (dirlist,)) + log.WARNING("trying to use the dynamic library instead...") + return None + path_libffi_a = None if hasattr(platform, 'library_dirs_for_libffi_a'): + path_libffi_a = find_libffi_a() + if path_libffi_a is not None: # platforms on which we want static linking libraries = [] - link_files = [find_libffi_a()] + link_files = [path_libffi_a] else: # platforms on which we want dynamic linking libraries = ['ffi'] @@ -261,6 +271,7 @@ elif _MSVC: get_libc_handle = external('pypy_get_libc_handle', [], DLLHANDLE) + @jit.dont_look_inside def get_libc_name(): return rwin32.GetModuleFileName(get_libc_handle()) diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -6,21 +6,26 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -def purefunction(func): - """ Decorate a function as pure. Pure means precisely that: +def elidable(func): + """ Decorate a function as "trace-elidable". This means precisely that: (1) the result of the call should not change if the arguments are the same (same numbers or same pointers) (2) it's fine to remove the call completely if we can guess the result according to rule 1 - Most importantly it doesn't mean that pure function has no observable - side effect, but those side effects can be ommited (ie caching). + Most importantly it doesn't mean that an elidable function has no observable + side effect, but those side effects are idempotent (ie caching). For now, such a function should never raise an exception. """ - func._pure_function_ = True + func._elidable_function_ = True return func +def purefunction(*args, **kwargs): + import warnings + warnings.warn("purefunction is deprecated, use elidable instead", DeprecationWarning) + return elidable(*args, **kwargs) + def hint(x, **kwds): """ Hint for the JIT @@ -36,6 +41,10 @@ """ return x + at specialize.argtype(0) +def promote(x): + return hint(x, promote=True) + def dont_look_inside(func): """ Make sure the JIT does not trace inside decorated function (it becomes a call instead) @@ -60,13 +69,13 @@ func._jit_loop_invariant_ = True return func -def purefunction_promote(promote_args='all'): +def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): import inspect - purefunction(func) + elidable(func) args, varargs, varkw, defaults = inspect.getargspec(func) args = ["v%s" % (i, ) for i in range(len(args))] assert varargs is None and varkw is None @@ -85,6 +94,12 @@ return result return decorator +def purefunction_promote(*args, **kwargs): + import warnings + warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) + return elidable_promote(*args, **kwargs) + + def oopspec(spec): def decorator(func): func.oopspec = spec @@ -273,15 +288,17 @@ class JitHintError(Exception): """Inconsistency in the JIT hints.""" -PARAMETERS = {'threshold': 1000, +PARAMETERS = {'threshold': 1032, # just above 1024 + 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, - 'inlining': 0, + 'inlining': 1, 'loop_longevity': 1000, 'retrace_limit': 5, - 'enable_opts': None, # patched later by optimizeopt/__init__.py + 'enable_opts': 'all', } unroll_parameters = unrolling_iterable(PARAMETERS.items()) +DEFAULT = object() # ____________________________________________________________ @@ -336,22 +353,33 @@ def _set_param(self, name, value): # special-cased by ExtRegistryEntry # (internal, must receive a constant 'name') + # if value is DEFAULT, sets the default value. assert name in PARAMETERS @specialize.arg(0, 1) def set_param(self, name, value): """Set one of the tunable JIT parameter.""" - for name1, _ in unroll_parameters: - if name1 == name: - self._set_param(name1, value) - return - raise ValueError("no such parameter") + self._set_param(name, value) + + @specialize.arg(0, 1) + def set_param_to_default(self, name): + """Reset one of the tunable JIT parameters to its default value.""" + self._set_param(name, DEFAULT) def set_user_param(self, text): """Set the tunable JIT parameters from a user-supplied string - following the format 'param=value,param=value'. For programmatic - setting of parameters, use directly JitDriver.set_param(). + following the format 'param=value,param=value', or 'off' to + disable the JIT. For programmatic setting of parameters, use + directly JitDriver.set_param(). """ + if text == 'off': + self.set_param('threshold', -1) + self.set_param('function_threshold', -1) + return + if text == 'default': + for name1, _ in unroll_parameters: + self.set_param_to_default(name1) + return for s in text.split(','): s = s.strip(' ') parts = s.split('=') @@ -574,15 +602,17 @@ def compute_result_annotation(self, s_name, s_value): from pypy.annotation import model as annmodel assert s_name.is_constant() - if s_name.const == 'enable_opts': - assert annmodel.SomeString(can_be_None=True).contains(s_value) - else: - assert annmodel.SomeInteger().contains(s_value) + if not self.bookkeeper.immutablevalue(DEFAULT).contains(s_value): + if s_name.const == 'enable_opts': + assert annmodel.SomeString(can_be_None=True).contains(s_value) + else: + assert annmodel.SomeInteger().contains(s_value) return annmodel.s_None def specialize_call(self, hop): from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.rstr import string_repr + from pypy.objspace.flow.model import Constant hop.exception_cannot_occur() driver = self.instance.im_self @@ -591,7 +621,12 @@ repr = string_repr else: repr = lltype.Signed - v_value = hop.inputarg(repr, arg=1) + if (isinstance(hop.args_v[1], Constant) and + hop.args_v[1].value is DEFAULT): + value = PARAMETERS[name] + v_value = hop.inputconst(repr, value) + else: + v_value = hop.inputarg(repr, arg=1) vlist = [hop.inputconst(lltype.Void, "set_param"), hop.inputconst(lltype.Void, driver), hop.inputconst(lltype.Void, name), diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -1,12 +1,15 @@ +from __future__ import with_statement + from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.objectmodel import specialize, enforceargs, we_are_translated -from pypy.rlib.rarithmetic import intmask, r_uint +from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat from pypy.rlib import jit from pypy.rlib import clibffi from pypy.rlib.clibffi import get_libc_name, FUNCFLAG_CDECL, AbstractFuncPtr, \ - push_arg_as_ffiptr, c_ffi_call + push_arg_as_ffiptr, c_ffi_call, FFI_TYPE_STRUCT from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal from pypy.rlib.rdynload import DLLHANDLE +from pypy.rlib.longlong2float import longlong2float, float2longlong class types(object): """ @@ -31,17 +34,21 @@ setattr(cls, name, value) cls.slong = clibffi.cast_type_to_ffitype(rffi.LONG) cls.ulong = clibffi.cast_type_to_ffitype(rffi.ULONG) + cls.slonglong = clibffi.cast_type_to_ffitype(rffi.LONGLONG) + cls.ulonglong = clibffi.cast_type_to_ffitype(rffi.ULONGLONG) + cls.wchar_t = clibffi.cast_type_to_ffitype(lltype.UniChar) del cls._import @staticmethod - @jit.purefunction + @jit.elidable def getkind(ffi_type): """Returns 'v' for void, 'f' for float, 'i' for signed integer, and 'u' for unsigned integer. """ if ffi_type is types.void: return 'v' elif ffi_type is types.double: return 'f' - elif ffi_type is types.pointer: return 'i' + elif ffi_type is types.float: return 's' + elif ffi_type is types.pointer: return 'u' # elif ffi_type is types.schar: return 'i' elif ffi_type is types.uchar: return 'u' @@ -58,13 +65,19 @@ elif ffi_type is types.uint16: return 'u' elif ffi_type is types.sint32: return 'i' elif ffi_type is types.uint32: return 'u' - ## we only support integers that fit in a lltype.Signed (==rffi.LONG) - ## (on 64-bit platforms, types.sint64 is types.slong and the case is - ## caught above) - ## elif ffi_type is types.sint64: return 'i' - ## elif ffi_type is types.uint64: return 'u' + ## (note that on 64-bit platforms, types.sint64 is types.slong and the + ## case is caught above) + elif ffi_type is types.sint64: return 'I' + elif ffi_type is types.uint64: return 'U' + # + elif types.is_struct(ffi_type): return 'S' raise KeyError + @staticmethod + @jit.elidable + def is_struct(ffi_type): + return intmask(ffi_type.c_type) == intmask(FFI_TYPE_STRUCT) + types._import() @specialize.arg(0) @@ -78,8 +91,11 @@ sz = rffi.sizeof(TYPE) return sz <= rffi.sizeof(rffi.LONG) + # ====================================================================== +IS_32_BIT = (r_uint.BITS == 32) + @specialize.memo() def _check_type(TYPE): if isinstance(TYPE, lltype.Ptr): @@ -105,11 +121,37 @@ val = rffi.cast(rffi.LONG, val) elif TYPE is rffi.DOUBLE: cls = FloatArg + elif TYPE is rffi.LONGLONG or TYPE is rffi.ULONGLONG: + raise TypeError, 'r_(u)longlong not supported by arg(), use arg_(u)longlong()' + elif TYPE is rffi.FLOAT: + raise TypeError, 'r_singlefloat not supported by arg(), use arg_singlefloat()' else: raise TypeError, 'Unsupported argument type: %s' % TYPE self._append(cls(val)) return self + def arg_raw(self, val): + self._append(RawArg(val)) + + def arg_longlong(self, val): + """ + Note: this is a hack. So far, the JIT does not support long longs, so + you must pass it as if it were a python Float (rffi.DOUBLE). You can + use the convenience functions longlong2float and float2longlong to do + the conversions. Note that if you use long longs, the call won't + be jitted at all. + """ + assert IS_32_BIT # use a normal integer on 64-bit platforms + self._append(LongLongArg(val)) + + def arg_singlefloat(self, val): + """ + Note: you must pass a python Float (rffi.DOUBLE), not a r_singlefloat + (else the jit complains). Note that if you use single floats, the + call won't be jitted at all. + """ + self._append(SingleFloatArg(val)) + def _append(self, arg): if self.first is None: self.first = self.last = arg @@ -132,8 +174,9 @@ def push(self, func, ll_args, i): func._push_int(self.intval, ll_args, i) + class FloatArg(AbstractArg): - """ An argument holding a float + """ An argument holding a python float (i.e. a C double) """ def __init__(self, floatval): @@ -142,6 +185,37 @@ def push(self, func, ll_args, i): func._push_float(self.floatval, ll_args, i) +class RawArg(AbstractArg): + """ An argument holding a raw pointer to put inside ll_args + """ + + def __init__(self, ptrval): + self.ptrval = ptrval + + def push(self, func, ll_args, i): + func._push_raw(self.ptrval, ll_args, i) + +class SingleFloatArg(AbstractArg): + """ An argument representing a C float (but holding a C double) + """ + + def __init__(self, floatval): + self.floatval = floatval + + def push(self, func, ll_args, i): + func._push_single_float(self.floatval, ll_args, i) + + +class LongLongArg(AbstractArg): + """ An argument representing a C long long (but holding a C double) + """ + + def __init__(self, floatval): + self.floatval = floatval + + def push(self, func, ll_args, i): + func._push_longlong(self.floatval, ll_args, i) + # ====================================================================== @@ -164,8 +238,8 @@ # ======================================================================== @jit.unroll_safe - @specialize.arg(2) - def call(self, argchain, RESULT): + @specialize.arg(2, 3) + def call(self, argchain, RESULT, is_struct=False): # WARNING! This code is written carefully in a way that the JIT # optimizer will see a sequence of calls like the following: # @@ -179,6 +253,7 @@ # the optimizer will fail to recognize the pattern and won't turn it # into a fast CALL. Note that "arg = arg.next" is optimized away, # assuming that archain is completely virtual. + self = jit.promote(self) if argchain.numargs != len(self.argtypes): raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ (argchain.numargs, len(self.argtypes)) @@ -190,10 +265,24 @@ i += 1 arg = arg.next # - if _fits_into_long(RESULT): + if is_struct: + assert types.is_struct(self.restype) + res = self._do_call_raw(self.funcsym, ll_args) + elif _fits_into_long(RESULT): + assert not types.is_struct(self.restype) res = self._do_call_int(self.funcsym, ll_args) elif RESULT is rffi.DOUBLE: return self._do_call_float(self.funcsym, ll_args) + elif RESULT is rffi.FLOAT: + # XXX: even if RESULT is FLOAT, we still return a DOUBLE, else the + # jit complains. Note that the jit is disabled in this case + return self._do_call_single_float(self.funcsym, ll_args) + elif RESULT is rffi.LONGLONG or RESULT is rffi.ULONGLONG: + # XXX: even if RESULT is LONGLONG, we still return a DOUBLE, else the + # jit complains. Note that the jit is disabled in this case + # (it's not a typo, we really return a DOUBLE) + assert IS_32_BIT + return self._do_call_longlong(self.funcsym, ll_args) elif RESULT is lltype.Void: return self._do_call_void(self.funcsym, ll_args) else: @@ -222,11 +311,26 @@ def _push_int(self, value, ll_args, i): self._push_arg(value, ll_args, i) + @jit.dont_look_inside + def _push_raw(self, value, ll_args, i): + ll_args[i] = value + @jit.oopspec('libffi_push_float(self, value, ll_args, i)') @enforceargs( None, float, None, int) # fix the annotation for tests def _push_float(self, value, ll_args, i): self._push_arg(value, ll_args, i) + @jit.dont_look_inside + def _push_single_float(self, value, ll_args, i): + self._push_arg(r_singlefloat(value), ll_args, i) + + @jit.dont_look_inside + def _push_longlong(self, floatval, ll_args, i): + """ + Takes a longlong represented as a python Float. It's a hack for the + jit, else we could not see the whole libffi module at all""" + self._push_arg(float2longlong(floatval), ll_args, i) + @jit.oopspec('libffi_call_int(self, funcsym, ll_args)') def _do_call_int(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, rffi.LONG) @@ -235,6 +339,21 @@ def _do_call_float(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, rffi.DOUBLE) + @jit.dont_look_inside + def _do_call_single_float(self, funcsym, ll_args): + single_res = self._do_call(funcsym, ll_args, rffi.FLOAT) + return float(single_res) + + @jit.dont_look_inside + def _do_call_raw(self, funcsym, ll_args): + # same as _do_call_int, but marked as jit.dont_look_inside + return self._do_call(funcsym, ll_args, rffi.LONG) + + @jit.dont_look_inside + def _do_call_longlong(self, funcsym, ll_args): + llres = self._do_call(funcsym, ll_args, rffi.LONGLONG) + return longlong2float(llres) + @jit.oopspec('libffi_call_void(self, funcsym, ll_args)') def _do_call_void(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, lltype.Void) @@ -265,7 +384,14 @@ rffi.cast(rffi.VOIDPP, ll_args)) if RESULT is not lltype.Void: TP = lltype.Ptr(rffi.CArray(RESULT)) - res = rffi.cast(TP, ll_result)[0] + buf = rffi.cast(TP, ll_result) + if types.is_struct(self.restype): + assert RESULT == rffi.LONG + # for structs, we directly return the buffer and transfer the + # ownership + res = rffi.cast(RESULT, buf) + else: + res = buf[0] else: res = None self._free_buffers(ll_result, ll_args) @@ -274,11 +400,19 @@ def _free_buffers(self, ll_result, ll_args): if ll_result: - lltype.free(ll_result, flavor='raw') + self._free_buffer_maybe(rffi.cast(rffi.VOIDP, ll_result), self.restype) for i in range(len(self.argtypes)): - lltype.free(ll_args[i], flavor='raw') + argtype = self.argtypes[i] + self._free_buffer_maybe(ll_args[i], argtype) lltype.free(ll_args, flavor='raw') + def _free_buffer_maybe(self, buf, ffitype): + # if it's a struct, the buffer is not freed and the ownership is + # already of the caller (in case of ll_args buffers) or transferred to + # it (in case of ll_result buffer) + if not types.is_struct(ffitype): + lltype.free(buf, flavor='raw') + # ====================================================================== @@ -288,11 +422,8 @@ def __init__(self, libname): """Load the library, or raises DLOpenError.""" self.lib = rffi.cast(DLLHANDLE, 0) - ll_libname = rffi.str2charp(libname) - try: + with rffi.scoped_str2charp(libname) as ll_libname: self.lib = dlopen(ll_libname) - finally: - lltype.free(ll_libname, flavor='raw') def __del__(self): if self.lib: @@ -302,3 +433,6 @@ def getpointer(self, name, argtypes, restype, flags=FUNCFLAG_CDECL): return Func(name, argtypes, restype, dlsym(self.lib, name), flags=flags, keepalive=self) + + def getaddressindll(self, name): + return dlsym(self.lib, name) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -30,25 +30,18 @@ return llval from pypy.translator.tool.cbuild import ExternalCompilationInfo -eci = ExternalCompilationInfo(post_include_bits=[""" +eci = ExternalCompilationInfo(includes=['string.h', 'assert.h'], + post_include_bits=[""" static double pypy__longlong2float(long long x) { - int i; double dd; - char *p = (char*)&x; - char *d = (char*)ⅆ - for(i = 0; i < 8; i++) { - d[i] = p[i]; - } + assert(sizeof(double) == 8 && sizeof(long long) == 8); + memcpy(&dd, &x, 8); return dd; } static long long pypy__float2longlong(double x) { - int i; long long ll; - char *p = (char*)&x; - char *l = (char*)≪ - for(i = 0; i < 8; i++) { - l[i] = p[i]; - } + assert(sizeof(double) == 8 && sizeof(long long) == 8); + memcpy(&ll, &x, 8); return ll; } """]) @@ -56,9 +49,9 @@ longlong2float = rffi.llexternal( "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE, _callable=longlong2float_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) float2longlong = rffi.llexternal( "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -124,7 +124,7 @@ return len(self._digits) @staticmethod - @jit.purefunction + @jit.elidable def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. @@ -156,7 +156,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -179,7 +179,7 @@ raise OverflowError @staticmethod - @jit.purefunction + @jit.elidable def _fromfloat_finite(dval): sign = 1 if dval < 0.0: @@ -201,7 +201,7 @@ return v @staticmethod - @jit.purefunction + @jit.elidable @specialize.argtype(0) def fromrarith_int(i): # This function is marked as pure, so you must not call it and @@ -209,7 +209,7 @@ return rbigint(*args_from_rarith_int(i)) @staticmethod - @jit.purefunction + @jit.elidable def fromdecimalstr(s): # This function is marked as pure, so you must not call it and # then modify the result. diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py --- a/pypy/rlib/rgc.py +++ b/pypy/rlib/rgc.py @@ -191,6 +191,21 @@ hop.exception_cannot_occur() return hop.genop('gc_can_move', hop.args_v, resulttype=hop.r_result) +def _make_sure_does_not_move(p): + """'p' is a non-null GC object. This (tries to) make sure that the + object does not move any more, by forcing collections if needed. + Warning: should ideally only be used with the minimark GC, and only + on objects that are already a bit old, so have a chance to be + already non-movable.""" + if not we_are_translated(): + return + i = 0 + while can_move(p): + if i > 6: + raise NotImplementedError("can't make object non-movable!") + collect(i) + i += 1 + def _heap_stats(): raise NotImplementedError # can't be run directly @@ -257,7 +272,9 @@ if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest - if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): + if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, + source_start, dest_start, + length): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] diff --git a/pypy/rlib/rmd5.py b/pypy/rlib/rmd5.py --- a/pypy/rlib/rmd5.py +++ b/pypy/rlib/rmd5.py @@ -51,7 +51,7 @@ _rotateLeft = rffi.llexternal( "pypy__rotateLeft", [lltype.Unsigned, lltype.Signed], lltype.Unsigned, _callable=_rotateLeft_emulator, compilation_info=eci, - _nowrapper=True, pure_function=True) + _nowrapper=True, elidable_function=True) # we expect the function _rotateLeft to be actually inlined diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -134,7 +134,8 @@ def external(name, argtypes, restype, **kw): kw['compilation_info'] = eci - eci.export_symbols += (name,) + if not kw.get('macro', False): + eci.export_symbols += (name,) return rffi.llexternal( name, argtypes, restype, **kw) @@ -150,7 +151,7 @@ [rffi.INT, rffi.INT, rffi.CCHARP, rffi.INT], lltype.Void))], lltype.Void) ssl_external('CRYPTO_set_id_callback', - [lltype.Ptr(lltype.FuncType([], rffi.INT))], + [lltype.Ptr(lltype.FuncType([], rffi.LONG))], lltype.Void) if HAVE_OPENSSL_RAND: diff --git a/pypy/rlib/rrandom.py b/pypy/rlib/rrandom.py --- a/pypy/rlib/rrandom.py +++ b/pypy/rlib/rrandom.py @@ -24,8 +24,7 @@ def __init__(self, seed=r_uint(0)): self.state = [r_uint(0)] * N self.index = 0 - if seed: - self.init_genrand(seed) + self.init_genrand(seed) def init_genrand(self, s): mt = self.state diff --git a/pypy/rlib/rsdl/RMix.py b/pypy/rlib/rsdl/RMix.py --- a/pypy/rlib/rsdl/RMix.py +++ b/pypy/rlib/rsdl/RMix.py @@ -52,7 +52,8 @@ ChunkPtr) def LoadWAV(filename_ccharp): - return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, rffi.str2charp('rb')), 1) + with rffi.scoped_str2charp('rb') as mode: + return LoadWAV_RW(RSDL.RWFromFile(filename_ccharp, mode), 1) PlayChannelTimed = external('Mix_PlayChannelTimed', @@ -64,4 +65,4 @@ """Returns zero if the channel is not playing. Otherwise if you passed in -1, the number of channels playing is returned""" -ChannelPlaying = external('Mix_Playing', [ rffi.INT]) \ No newline at end of file +ChannelPlaying = external('Mix_Playing', [rffi.INT], rffi.INT) diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -141,7 +141,8 @@ def construct_stream_tower(stream, buffering, universal, reading, writing, binary): if buffering == 0: # no buffering - pass + if reading: # force some minimal buffering for readline() + stream = ReadlineInputStream(stream) elif buffering == 1: # line-buffering if writing: stream = LineBufferingOutputStream(stream) @@ -749,6 +750,113 @@ flush_buffers=False) +class ReadlineInputStream(Stream): + + """Minimal buffering input stream. + + Only does buffering for readline(). The other kinds of reads, and + all writes, are not buffered at all. + """ + + bufsize = 2**13 # 8 K + + def __init__(self, base, bufsize=-1): + self.base = base + self.do_read = base.read # function to fill buffer some more + self.do_seek = base.seek # seek to a byte offset + if bufsize == -1: # Get default from the class + bufsize = self.bufsize + self.bufsize = bufsize # buffer size (hint only) + self.buf = None # raw data (may contain "\n") + self.bufstart = 0 + + def flush_buffers(self): + if self.buf is not None: + try: + self.do_seek(self.bufstart-len(self.buf), 1) + except MyNotImplementedError: + pass + else: + self.buf = None + self.bufstart = 0 + + def readline(self): + if self.buf is not None: + i = self.buf.find('\n', self.bufstart) + else: + self.buf = '' + i = -1 + # + if i < 0: + self.buf = self.buf[self.bufstart:] + self.bufstart = 0 + while True: + bufsize = max(self.bufsize, len(self.buf) >> 2) + data = self.do_read(bufsize) + if not data: + result = self.buf # end-of-file reached + self.buf = None + return result + startsearch = len(self.buf) # there is no '\n' in buf so far + self.buf += data + i = self.buf.find('\n', startsearch) + if i >= 0: + break + # + i += 1 + result = self.buf[self.bufstart:i] + self.bufstart = i + return result + + def peek(self): + if self.buf is None: + return '' + if self.bufstart > 0: + self.buf = self.buf[self.bufstart:] + self.bufstart = 0 + return self.buf + + def tell(self): + pos = self.base.tell() + if self.buf is not None: + pos -= (len(self.buf) - self.bufstart) + return pos + + def readall(self): + result = self.base.readall() + if self.buf is not None: + result = self.buf[self.bufstart:] + result + self.buf = None + self.bufstart = 0 + return result + + def read(self, n): + if self.buf is None: + return self.do_read(n) + else: + m = n - (len(self.buf) - self.bufstart) + start = self.bufstart + if m > 0: + result = self.buf[start:] + self.do_read(m) + self.buf = None + self.bufstart = 0 + return result + elif n >= 0: + self.bufstart = start + n + return self.buf[start : self.bufstart] + else: + return '' + + seek = PassThrough("seek", flush_buffers=True) + write = PassThrough("write", flush_buffers=True) + truncate = PassThrough("truncate", flush_buffers=True) + flush = PassThrough("flush", flush_buffers=True) + flushable = PassThrough("flushable", flush_buffers=False) + close = PassThrough("close", flush_buffers=False) + try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", + flush_buffers=False) + + class BufferingOutputStream(Stream): """Standard buffering output stream. diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -1,6 +1,6 @@ import py from pypy.conftest import option -from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote +from pypy.rlib.jit import hint, we_are_jitted, JitDriver, elidable_promote from pypy.rlib.jit import JitHintError, oopspec from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin @@ -31,8 +31,8 @@ res = self.interpret(f, [4]) assert res == 5 - def test_purefunction_promote(self): - @purefunction_promote() + def test_elidable_promote(self): + @elidable_promote() def g(func): return func + 1 def f(x): @@ -40,8 +40,8 @@ res = self.interpret(f, [2]) assert res == 5 - def test_purefunction_promote_args(self): - @purefunction_promote(promote_args='0') + def test_elidable_promote_args(self): + @elidable_promote(promote_args='0') def g(func, x): return func + 1 def f(x): diff --git a/pypy/rlib/test/test_libffi.py b/pypy/rlib/test/test_libffi.py --- a/pypy/rlib/test/test_libffi.py +++ b/pypy/rlib/test/test_libffi.py @@ -2,8 +2,10 @@ import sys from pypy.rpython.lltypesystem import rffi, lltype from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED -from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name +from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong +from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name, make_struct_ffitype_e from pypy.rlib.libffi import CDLL, Func, get_libc_name, ArgChain, types +from pypy.rlib.libffi import longlong2float, float2longlong, IS_32_BIT class TestLibffiMisc(BaseFfiTest): @@ -50,6 +52,18 @@ del lib assert not ALLOCATED + def test_longlong_as_float(self): + from pypy.translator.c.test.test_genc import compile + maxint64 = r_longlong(9223372036854775807) + def fn(x): + d = longlong2float(x) + ll = float2longlong(d) + return ll + assert fn(maxint64) == maxint64 + # + fn2 = compile(fn, [r_longlong]) + res = fn2(maxint64) + assert res == maxint64 class TestLibffiCall(BaseFfiTest): """ @@ -97,7 +111,7 @@ def get_libfoo(self): return self.CDLL(self.libfoo_name) - def call(self, funcspec, args, RESULT, init_result=0): + def call(self, funcspec, args, RESULT, init_result=0, is_struct=False): """ Call the specified function after constructing and ArgChain with the arguments in ``args``. @@ -114,8 +128,20 @@ func = lib.getpointer(name, argtypes, restype) chain = ArgChain() for arg in args: - chain.arg(arg) - return func.call(chain, RESULT) + if isinstance(arg, r_singlefloat): + chain.arg_singlefloat(float(arg)) + elif IS_32_BIT and isinstance(arg, r_longlong): + chain.arg_longlong(longlong2float(arg)) + elif IS_32_BIT and isinstance(arg, r_ulonglong): + arg = rffi.cast(rffi.LONGLONG, arg) + chain.arg_longlong(longlong2float(arg)) + elif isinstance(arg, tuple): + methname, arg = arg + meth = getattr(chain, methname) + meth(arg) + else: + chain.arg(arg) + return func.call(chain, RESULT, is_struct=is_struct) def check_loops(self, *args, **kwds): """ @@ -137,7 +163,7 @@ res = self.call(func, [38, 4.2], rffi.LONG) assert res == 42 self.check_loops({ - 'call_may_force': 1, + 'call_release_gil': 1, 'guard_no_exception': 1, 'guard_not_forced': 1, 'int_add': 1, @@ -150,7 +176,7 @@ func = (libm, 'pow', [types.double, types.double], types.double) res = self.call(func, [2.0, 3.0], rffi.DOUBLE, init_result=0.0) assert res == 8.0 - self.check_loops(call_may_force=1, guard_no_exception=1, guard_not_forced=1) + self.check_loops(call_release_gil=1, guard_no_exception=1, guard_not_forced=1) def test_cast_result(self): """ @@ -163,7 +189,7 @@ func = (libfoo, 'cast_to_uchar_and_ovf', [types.sint], types.uchar) res = self.call(func, [0], rffi.UCHAR) assert res == 200 - self.check_loops(call_may_force=1, guard_no_exception=1, guard_not_forced=1) + self.check_loops(call_release_gil=1, guard_no_exception=1, guard_not_forced=1) def test_cast_argument(self): """ @@ -267,6 +293,76 @@ res = self.call(get_dummy, [], rffi.LONG) assert res == initval+1 + def test_single_float_args(self): + """ + float sum_xy_float(float x, float y) + { + return x+y; + } + """ + from ctypes import c_float # this is used only to compute the expected result + libfoo = self.get_libfoo() + func = (libfoo, 'sum_xy_float', [types.float, types.float], types.float) + x = r_singlefloat(12.34) + y = r_singlefloat(56.78) + res = self.call(func, [x, y], rffi.FLOAT, init_result=0.0) + expected = c_float(c_float(12.34).value + c_float(56.78).value).value + assert res == expected + + def test_slonglong_args(self): + """ + long long sum_xy_longlong(long long x, long long y) + { + return x+y; + } + """ + maxint32 = 2147483647 # we cannot really go above maxint on 64 bits + # (and we would not test anything, as there long + # is the same as long long) + libfoo = self.get_libfoo() + func = (libfoo, 'sum_xy_longlong', [types.slonglong, types.slonglong], + types.slonglong) + if IS_32_BIT: + x = r_longlong(maxint32+1) + y = r_longlong(maxint32+2) + zero = longlong2float(r_longlong(0)) + else: + x = maxint32+1 + y = maxint32+2 + zero = 0 + res = self.call(func, [x, y], rffi.LONGLONG, init_result=zero) + if IS_32_BIT: + # obscure, on 32bit it's really a long long, so it returns a + # DOUBLE because of the JIT hack + res = float2longlong(res) + expected = maxint32*2 + 3 + assert res == expected + + def test_ulonglong_args(self): + """ + unsigned long long sum_xy_ulonglong(unsigned long long x, + unsigned long long y) + { + return x+y; + } + """ + maxint64 = 9223372036854775807 # maxint64+1 does not fit into a + # longlong, but it does into a + # ulonglong + libfoo = self.get_libfoo() + func = (libfoo, 'sum_xy_ulonglong', [types.ulonglong, types.ulonglong], + types.ulonglong) + x = r_ulonglong(maxint64+1) + y = r_ulonglong(2) + res = self.call(func, [x, y], rffi.ULONGLONG, init_result=0) + if IS_32_BIT: + # obscure, on 32bit it's really a long long, so it returns a + # DOUBLE because of the JIT hack + res = float2longlong(res) + res = rffi.cast(rffi.ULONGLONG, res) + expected = maxint64 + 3 + assert res == expected + def test_wrong_number_of_arguments(self): from pypy.rpython.llinterp import LLException libfoo = self.get_libfoo() @@ -287,3 +383,57 @@ my_raises("self.call(func, [38], rffi.LONG)") # one less my_raises("self.call(func, [38, 12.3, 42], rffi.LONG)") # one more + + + def test_byval_argument(self): + """ + struct Point { + long x; + long y; + }; + + long sum_point(struct Point p) { + return p.x + p.y; + } + """ + libfoo = CDLL(self.libfoo_name) + ffi_point_struct = make_struct_ffitype_e(0, 0, [types.slong, types.slong]) + ffi_point = ffi_point_struct.ffistruct + sum_point = (libfoo, 'sum_point', [ffi_point], types.slong) + # + ARRAY = rffi.CArray(rffi.LONG) + buf = lltype.malloc(ARRAY, 2, flavor='raw') + buf[0] = 30 + buf[1] = 12 + adr = rffi.cast(rffi.VOIDP, buf) + res = self.call(sum_point, [('arg_raw', adr)], rffi.LONG, init_result=0) + assert res == 42 + # check that we still have the ownership on the buffer + assert buf[0] == 30 + assert buf[1] == 12 + lltype.free(buf, flavor='raw') + lltype.free(ffi_point_struct, flavor='raw') + + def test_byval_result(self): + """ + struct Point make_point(long x, long y) { + struct Point p; + p.x = x; + p.y = y; + return p; + } + """ + libfoo = CDLL(self.libfoo_name) + ffi_point_struct = make_struct_ffitype_e(0, 0, [types.slong, types.slong]) + ffi_point = ffi_point_struct.ffistruct + + libfoo = CDLL(self.libfoo_name) + make_point = (libfoo, 'make_point', [types.slong, types.slong], ffi_point) + # + PTR = lltype.Ptr(rffi.CArray(rffi.LONG)) + p = self.call(make_point, [12, 34], PTR, init_result=lltype.nullptr(PTR.TO), + is_struct=True) + assert p[0] == 12 + assert p[1] == 34 + lltype.free(p, flavor='raw') + lltype.free(ffi_point_struct, flavor='raw') diff --git a/pypy/rlib/test/test_rrandom.py b/pypy/rlib/test/test_rrandom.py --- a/pypy/rlib/test/test_rrandom.py +++ b/pypy/rlib/test/test_rrandom.py @@ -3,6 +3,12 @@ # the numbers were created by using CPython's _randommodule.c +def test_init_from_zero(): + rnd = Random(0) + assert rnd.state[:14] == [0, 1, 1812433255, 1900727105, 1208447044, + 2481403966, 4042607538, 337614300, 3232553940, + 1018809052, 3202401494, 1775180719, 3192392114, 594215549] + def test_init_from_seed(): rnd = Random(1000) assert rnd.state[:14] == [1000, 4252021385, 1724402292, 571538732, diff --git a/pypy/rlib/test/test_streamio.py b/pypy/rlib/test/test_streamio.py --- a/pypy/rlib/test/test_streamio.py +++ b/pypy/rlib/test/test_streamio.py @@ -1008,6 +1008,75 @@ assert base.buf == data +class TestReadlineInputStream: + + packets = ["a", "b", "\n", "def", "\nxy\npq\nuv", "wx"] + lines = ["ab\n", "def\n", "xy\n", "pq\n", "uvwx"] + + def makeStream(self, seek=False, tell=False, bufsize=-1): + base = TSource(self.packets) + self.source = base + def f(*args): + if seek is False: + raise NotImplementedError # a bug! + if seek is None: + raise streamio.MyNotImplementedError # can be caught + raise ValueError(seek) # uh? + if not tell: + base.tell = f + if not seek: + base.seek = f + return streamio.ReadlineInputStream(base, bufsize) + + def test_readline(self): + for file in [self.makeStream(), self.makeStream(bufsize=2)]: + i = 0 + while 1: + r = file.readline() + if r == "": + break + assert self.lines[i] == r + i += 1 + assert i == len(self.lines) + + def test_readline_and_read_interleaved(self): + for file in [self.makeStream(seek=True), + self.makeStream(seek=True, bufsize=2)]: + i = 0 + while 1: + firstchar = file.read(1) + if firstchar == "": + break + r = file.readline() + assert r != "" + assert self.lines[i] == firstchar + r + i += 1 + assert i == len(self.lines) + + def test_readline_and_read_interleaved_no_seek(self): + for file in [self.makeStream(seek=None), + self.makeStream(seek=None, bufsize=2)]: + i = 0 + while 1: + firstchar = file.read(1) + if firstchar == "": + break + r = file.readline() + assert r != "" + assert self.lines[i] == firstchar + r + i += 1 + assert i == len(self.lines) + + def test_readline_and_readall(self): + file = self.makeStream(seek=True, tell=True, bufsize=2) + r = file.readline() + assert r == 'ab\n' + assert file.tell() == 3 + r = file.readall() + assert r == 'def\nxy\npq\nuvwx' + r = file.readall() + assert r == '' + # Speed test diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -737,9 +737,12 @@ def op_zero_gc_pointers_inside(self, obj): raise NotImplementedError("zero_gc_pointers_inside") - def op_gc_writebarrier_before_copy(self, source, dest): + def op_gc_writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if hasattr(self.heap, 'writebarrier_before_copy'): - return self.heap.writebarrier_before_copy(source, dest) + return self.heap.writebarrier_before_copy(source, dest, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -37,7 +37,9 @@ if far_regions: import random pieces = far_regions._ll2ctypes_pieces - num = random.randrange(len(pieces)) + num = random.randrange(len(pieces)+1) + if num == len(pieces): + return ctype() i1, stop = pieces[num] i2 = i1 + ((ctypes.sizeof(ctype) or 1) + 7) & ~7 if i2 > stop: @@ -418,6 +420,9 @@ instance._storage = ctypes_storage assert ctypes_storage # null pointer? +class NotCtypesAllocatedStructure(ValueError): + pass + class _parentable_mixin(object): """Mixin added to _parentable containers when they become ctypes-based. (This is done by changing the __class__ of the instance to reference @@ -436,7 +441,7 @@ def _addressof_storage(self): "Returns the storage address as an int" if self._storage is None or self._storage is True: - raise ValueError("Not a ctypes allocated structure") + raise NotCtypesAllocatedStructure("Not a ctypes allocated structure") return intmask(ctypes.cast(self._storage, ctypes.c_void_p).value) def _free(self): diff --git a/pypy/rpython/lltypesystem/ll_str.py b/pypy/rpython/lltypesystem/ll_str.py --- a/pypy/rpython/lltypesystem/ll_str.py +++ b/pypy/rpython/lltypesystem/ll_str.py @@ -1,12 +1,13 @@ from pypy.rpython.lltypesystem.lltype import GcArray, Array, Char, malloc from pypy.rpython.annlowlevel import llstr from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.rlib import jit CHAR_ARRAY = GcArray(Char) + at jit.elidable def ll_int_str(repr, i): return ll_int2dec(i) -ll_int_str._pure_function_ = True def ll_unsigned(i): if isinstance(i, r_longlong) or isinstance(i, r_ulonglong): @@ -14,6 +15,7 @@ else: return r_uint(i) + at jit.elidable def ll_int2dec(i): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -44,13 +46,13 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2dec._pure_function_ = True hex_chars = malloc(Array(Char), 16, immortal=True) for i in range(16): hex_chars[i] = "%x"%i + at jit.elidable def ll_int2hex(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr temp = malloc(CHAR_ARRAY, 20) @@ -86,8 +88,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2hex._pure_function_ = True + at jit.elidable def ll_int2oct(i, addPrefix): from pypy.rpython.lltypesystem.rstr import mallocstr if i == 0: @@ -123,9 +125,8 @@ result.chars[j] = temp[len-j-1] j += 1 return result -ll_int2oct._pure_function_ = True + at jit.elidable def ll_float_str(repr, f): from pypy.rlib.rfloat import formatd return llstr(formatd(f, 'f', 6)) -ll_float_str._pure_function_ = True diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -831,7 +831,7 @@ raise TypeError, "unsupported cast" def _cast_whatever(TGT, value): - from pypy.rpython.lltypesystem import llmemory + from pypy.rpython.lltypesystem import llmemory, rffi ORIG = typeOf(value) if ORIG == TGT: return value @@ -847,6 +847,8 @@ return cast_pointer(TGT, value) elif ORIG == llmemory.Address: return llmemory.cast_adr_to_ptr(value, TGT) + elif TGT == rffi.VOIDP and ORIG == Unsigned: + return rffi.cast(TGT, value) elif ORIG == Signed: return cast_int_to_ptr(TGT, value) elif TGT == llmemory.Address and isinstance(ORIG, Ptr): diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -58,7 +58,7 @@ math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) math_copysign = llexternal(underscore + 'copysign', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, - pure_function=True) + elidable_function=True) math_atan2 = llexternal('atan2', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_frexp = llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE) math_modf = llexternal('modf', [rffi.DOUBLE, rffi.DOUBLEP], rffi.DOUBLE) @@ -67,11 +67,11 @@ math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) -math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, pure_function=True) +math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) - at jit.purefunction + at jit.elidable def sqrt_nonneg(x): return math_sqrt(x) sqrt_nonneg.oopspec = "math.sqrt_nonneg(x)" diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -473,12 +473,16 @@ checkadr(addr2) return addr1 - addr2 -def op_gc_writebarrier_before_copy(source, dest): +def op_gc_writebarrier_before_copy(source, dest, + source_start, dest_start, length): A = lltype.typeOf(source) assert A == lltype.typeOf(dest) assert isinstance(A.TO, lltype.GcArray) assert isinstance(A.TO.OF, lltype.Ptr) assert A.TO.OF.TO._gckind == 'gc' + assert type(source_start) is int + assert type(dest_start) is int + assert type(length) is int return True def op_getfield(p, name): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -206,7 +215,7 @@ if dictobj is None: return lltype.nullptr(self.DICT) if not isinstance(dictobj, (dict, objectmodel.r_dict)): - raise TyperError("expected a dict: %r" % (dictobj,)) + raise TypeError("expected a dict: %r" % (dictobj,)) try: key = Constant(dictobj) return self.dict_cache[key] @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) @@ -833,10 +845,16 @@ POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) -def ll_popitem(ELEM, dic): +def _ll_getnextitem(dic): entries = dic.entries + ENTRY = lltype.typeOf(entries).TO.OF dmask = len(entries) - 1 - base = global_popitem_index.nextindex + if hasattr(ENTRY, 'f_hash'): + if entries.valid(0): + return 0 + base = entries[0].f_hash + else: + base = global_popitem_index.nextindex counter = 0 while counter <= dmask: i = (base + counter) & dmask @@ -845,8 +863,16 @@ break else: raise KeyError - global_popitem_index.nextindex += counter - entry = entries[i] + if hasattr(ENTRY, 'f_hash'): + entries[0].f_hash = base + counter + else: + global_popitem_index.nextindex = base + counter + return i + + at jit.dont_look_inside +def ll_popitem(ELEM, dic): + i = _ll_getnextitem(dic) + entry = dic.entries[i] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -55,7 +55,7 @@ compilation_info=ExternalCompilationInfo(), sandboxsafe=False, threadsafe='auto', _nowrapper=False, calling_conv='c', - oo_primitive=None, pure_function=False, + oo_primitive=None, elidable_function=False, macro=None): """Build an external function that will invoke the C function 'name' with the given 'args' types and 'result' type. @@ -87,8 +87,8 @@ name, macro, ext_type, compilation_info) else: _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) - if pure_function: - _callable._pure_function_ = True + if elidable_function: + _callable._elidable_function_ = True kwds = {} if oo_primitive: kwds['oo_primitive'] = oo_primitive @@ -139,10 +139,10 @@ source = py.code.Source(""" def call_external_function(%(argnames)s): before = aroundstate.before - after = aroundstate.after if before: before() # NB. it is essential that no exception checking occurs here! res = funcptr(%(argnames)s) + after = aroundstate.after if after: after() return res """ % locals()) @@ -244,7 +244,7 @@ def __init__(self): self.callbacks = {} -def _make_wrapper_for(TP, callable, callbackholder, aroundstate=None): +def _make_wrapper_for(TP, callable, callbackholder=None, aroundstate=None): """ Function creating wrappers for callbacks. Note that this is cheating as we assume constant callbacks and we just memoize wrappers """ @@ -253,21 +253,18 @@ if hasattr(callable, '_errorcode_'): errorcode = callable._errorcode_ else: - errorcode = TP.TO.RESULT._example() + errorcode = TP.TO.RESULT._defl() callable_name = getattr(callable, '__name__', '?') - callbackholder.callbacks[callable] = True + if callbackholder is not None: + callbackholder.callbacks[callable] = True args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))]) source = py.code.Source(r""" def wrapper(%s): # no *args - no GIL for mallocing the tuple llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py if aroundstate is not None: - before = aroundstate.before after = aroundstate.after - else: - before = None - after = None - if after: - after() + if after: + after() # from now on we hold the GIL stackcounter.stacks_counter += 1 try: @@ -281,8 +278,10 @@ traceback.print_exc() result = errorcode stackcounter.stacks_counter -= 1 - if before: - before() + if aroundstate is not None: + before = aroundstate.before + if before: + before() # here we don't hold the GIL any more. As in the wrapper() produced # by llexternal, it is essential that no exception checking occurs # after the call to before(). diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py --- a/pypy/rpython/lltypesystem/rlist.py +++ b/pypy/rpython/lltypesystem/rlist.py @@ -250,12 +250,11 @@ length = l.length l.length = length + 1 l.ll_setitem_fast(length, newitem) -ll_append_noresize.oopspec = 'list.append(l, newitem)' def ll_both_none(lst1, lst2): return not lst1 and not lst2 - + # ____________________________________________________________ # diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import purefunction, we_are_jitted +from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -57,6 +57,8 @@ llmemory.itemoffsetof(TP.chars, 0) + llmemory.sizeof(CHAR_TP) * item) + # It'd be nice to be able to look inside this function. + @dont_look_inside @enforceargs(None, None, int, int, int) def copy_string_contents(src, dst, srcstart, dststart, length): assert srcstart >= 0 @@ -142,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @purefunction + @elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -157,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @purefunction + @elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -256,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @purefunction + @elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -278,7 +280,7 @@ i += j return newstr - @purefunction + @elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -323,6 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' + @elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -334,12 +337,11 @@ x = 29872897 s.hash = x return x - ll_strhash._pure_function_ = True # it's pure but it does not look like it def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @purefunction + @elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -349,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @purefunction + @elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -367,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @purefunction + @elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -384,7 +386,7 @@ i += 1 return result - @purefunction + @elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -425,7 +427,7 @@ i += 1 return result - @purefunction + @elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -448,7 +450,7 @@ i += 1 return len1 - len2 - @purefunction + @elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -468,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @purefunction + @elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -484,7 +486,12 @@ return True - @purefunction + def ll_startswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[0] == ch + + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -501,7 +508,12 @@ return True - @purefunction + def ll_endswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[len(s.chars) - 1] == ch + + @elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -513,7 +525,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @purefunction + @elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -524,7 +536,7 @@ return i return -1 - @purefunction + @elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -592,7 +604,7 @@ res = 0 return res - @purefunction + @elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -715,7 +727,7 @@ i += 1 return result - @purefunction + @elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -813,7 +825,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @purefunction + @elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -828,7 +840,7 @@ j += 1 return newstr - @purefunction + @elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -839,7 +851,7 @@ i += 1 return False - @purefunction + @elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py --- a/pypy/rpython/memory/gc/generation.py +++ b/pypy/rpython/memory/gc/generation.py @@ -517,7 +517,8 @@ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.last_generation_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -75,10 +75,16 @@ first_gcflag = 1 << (LONG_BIT//2) -# The following flag is never set on young objects. It is initially set -# on all prebuilt and old objects, and gets cleared by the write_barrier() -# when we write in them a pointer to a young object. -GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0 +# The following flag is set on objects if we need to do something to +# track the young pointers that it might contain. The flag is not set +# on young objects (unless they are large arrays, see below), and we +# simply assume that any young object can point to any other young object. +# For old and prebuilt objects, the flag is usually set, and is cleared +# when we write a young pointer to it. For large arrays with +# GCFLAG_HAS_CARDS, we rely on card marking to track where the +# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this +# case too, to speed up the write barrier. +GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0 # The following flag is set on some prebuilt objects. The flag is set # unless the object is already listed in 'prebuilt_root_objects'. @@ -246,17 +252,19 @@ self.ac = ArenaCollectionClass(arena_size, page_size, small_request_threshold) # - # Used by minor collection: a list of non-young objects that + # Used by minor collection: a list of (mostly non-young) objects that # (may) contain a pointer to a young object. Populated by - # the write barrier. - self.old_objects_pointing_to_young = self.AddressStack() + # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we + # add it to this list. + self.objects_pointing_to_young = self.AddressStack() # - # Similar to 'old_objects_pointing_to_young', but lists objects + # Similar to 'objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'old_objects_pointing_to_young', in which case we + # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - self.old_objects_with_cards_set = self.AddressStack() + # Note also that young array objects may be added to this list. + self.objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -625,7 +633,7 @@ # if 'can_make_young'. The interesting case of 'can_make_young' # is for large objects, bigger than the 'large_objects' threshold, # which are raw-malloced but still young. - extra_flags = GCFLAG_NO_YOUNG_PTRS + extra_flags = GCFLAG_TRACK_YOUNG_PTRS # else: # No, so proceed to allocate it externally with raw_malloc(). @@ -643,7 +651,7 @@ # Reserve N extra words containing card bits before the object. extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words - extra_flags = GCFLAG_HAS_CARDS + extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only # be used later, after (and if) the object becomes old # @@ -686,7 +694,7 @@ self.young_rawmalloced_objects.add(result + size_gc_header) else: self.old_rawmalloced_objects.append(result + size_gc_header) - extra_flags |= GCFLAG_NO_YOUNG_PTRS + extra_flags |= GCFLAG_TRACK_YOUNG_PTRS # # Common code to fill the header and length of the object. self.init_gc_object(result, typeid, extra_flags) @@ -777,7 +785,7 @@ def init_gc_object_immortal(self, addr, typeid16, flags=0): # For prebuilt GC objects, the flags must contain # GCFLAG_NO_xxx_PTRS, at least initially. - flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS + flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS self.init_gc_object(addr, typeid16, flags) def is_in_nursery(self, addr): @@ -870,8 +878,8 @@ ll_assert(not self.is_in_nursery(obj), "object in nursery after collection") # similarily, all objects should have this flag: - ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS, - "missing GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS, + "missing GCFLAG_TRACK_YOUNG_PTRS") # the GCFLAG_VISITED should not be set between collections ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0, "unexpected GCFLAG_VISITED") @@ -910,7 +918,7 @@ # for the JIT: a minimal description of the write_barrier() method # (the JIT assumes it is of the shape # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") - JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS + JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS @classmethod def JIT_max_size_of_young_obj(cls): @@ -921,13 +929,13 @@ return cls.minimal_size_in_nursery def write_barrier(self, newvalue, addr_struct): - if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS: self.remember_young_pointer(addr_struct, newvalue) def write_barrier_from_array(self, newvalue, addr_array, index): - if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS: + if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS: if self.card_page_indices > 0: # <- constant-folded - self.remember_young_pointer_from_array(addr_array, index) + self.remember_young_pointer_from_array2(addr_array, index) else: self.remember_young_pointer(addr_array, newvalue) @@ -943,20 +951,23 @@ def remember_young_pointer(addr_struct, newvalue): # 'addr_struct' is the address of the object in which we write. # 'newvalue' is the address that we are going to write in there. + # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far. + # if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_struct), - "young object with GCFLAG_NO_YOUNG_PTRS") + ll_assert(self.debug_is_old_object(addr_struct) or + self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0, + "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards") # - # If it seems that what we are writing is a pointer to the nursery + # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need - # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object - # to the list 'old_objects_pointing_to_young'. We know that + # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object + # to the list 'objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects - # never have the flag GCFLAG_NO_YOUNG_PTRS to start with. + # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC # object and it's the first time we see a write to it, we @@ -976,20 +987,22 @@ def _init_writebarrier_with_card_marker(self): DEBUG = self.DEBUG - def remember_young_pointer_from_array(addr_array, index): + def remember_young_pointer_from_array2(addr_array, index): # 'addr_array' is the address of the object in which we write, # which must have an array part; 'index' is the index of the # item that is (or contains) the pointer that we write. - if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this - ll_assert(self.debug_is_old_object(addr_array), - "young array with GCFLAG_NO_YOUNG_PTRS") + # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far. + # objhdr = self.header(addr_array) if objhdr.tid & GCFLAG_HAS_CARDS == 0: # + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # # no cards, use default logic. Mostly copied from above. - self.old_objects_pointing_to_young.append(addr_array) - objhdr = self.header(addr_array) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) @@ -1002,26 +1015,85 @@ bitmask = 1 << (bitindex & 7) # # If the bit is already set, leave now. - size_gc_header = self.gcheaderbuilder.size_gc_header - addr_byte = addr_array - size_gc_header - addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex) + addr_byte = self.get_card(addr_array, byteindex) byte = ord(addr_byte.char[0]) if byte & bitmask: return # # We set the flag (even if the newly written address does not # actually point to the nursery, which seems to be ok -- actually - # it seems more important that remember_young_pointer_from_array() + # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.old_objects_with_cards_set.append(addr_array) + self.objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET - remember_young_pointer_from_array._dont_inline_ = True - self.remember_young_pointer_from_array = ( - remember_young_pointer_from_array) + remember_young_pointer_from_array2._dont_inline_ = True + assert self.card_page_indices > 0 + self.remember_young_pointer_from_array2 = ( + remember_young_pointer_from_array2) + + # xxx trying it out for the JIT: a 3-arguments version of the above + def remember_young_pointer_from_array3(addr_array, index, newvalue): + objhdr = self.header(addr_array) + # + # a single check for the common case of neither GCFLAG_HAS_CARDS + # nor GCFLAG_NO_HEAP_PTRS + if objhdr.tid & (GCFLAG_HAS_CARDS | GCFLAG_NO_HEAP_PTRS) == 0: + # common case: fast path, jump to the end of the function + pass + elif objhdr.tid & GCFLAG_HAS_CARDS == 0: + # no cards, but GCFLAG_NO_HEAP_PTRS is set. + objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS + self.prebuilt_root_objects.append(addr_array) + # jump to the end of the function + else: + # case with cards. + # + # If the newly written address does not actually point to a + # young object, leave now. + if not self.appears_to_be_young(newvalue): + return + # + # 'addr_array' is a raw_malloc'ed array with card markers + # in front. Compute the index of the bit to set: + bitindex = index >> self.card_page_shift + byteindex = bitindex >> 3 + bitmask = 1 << (bitindex & 7) + # + # If the bit is already set, leave now. + addr_byte = self.get_card(addr_array, byteindex) + byte = ord(addr_byte.char[0]) + if byte & bitmask: + return + addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET + return + # + # Logic for the no-cards case, put here to minimize the number + # of checks done at the start of the function + if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this + ll_assert(self.debug_is_old_object(addr_array), + "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") + # + if self.appears_to_be_young(newvalue): + self.objects_pointing_to_young.append(addr_array) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS + + remember_young_pointer_from_array3._dont_inline_ = True + assert self.card_page_indices > 0 + self.remember_young_pointer_from_array3 = ( + remember_young_pointer_from_array3) + + def get_card(self, obj, byteindex): + size_gc_header = self.gcheaderbuilder.size_gc_header + addr_byte = obj - size_gc_header + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) def assume_young_pointers(self, addr_struct): @@ -1029,15 +1101,16 @@ may now contain young pointers.'' """ objhdr = self.header(addr_struct) - if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: - self.old_objects_pointing_to_young.append(addr_struct) - objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: + self.objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_struct) - def writebarrier_before_copy(self, source_addr, dest_addr): + def writebarrier_before_copy(self, source_addr, dest_addr, + source_start, dest_start, length): """ This has the same effect as calling writebarrier over each element in dest copied from source, except it might reset one of the following flags a bit too eagerly, which means we'll have @@ -1045,15 +1118,36 @@ """ source_hdr = self.header(source_addr) dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0: + if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: return True # ^^^ a fast path of write-barrier # - if (source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0 or - source_hdr.tid & GCFLAG_CARDS_SET != 0): + if source_hdr.tid & GCFLAG_HAS_CARDS != 0: + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # The source object may have random young pointers. + # Return False to mean "do it manually in ll_arraycopy". + return False + # + if source_hdr.tid & GCFLAG_CARDS_SET == 0: + # The source object has no young pointers at all. Done. + return True + # + if dest_hdr.tid & GCFLAG_HAS_CARDS == 0: + # The dest object doesn't have cards. Do it manually. + return False + # + if source_start != 0 or dest_start != 0: + # Misaligned. Do it manually. + return False + # + self.manually_copy_card_bits(source_addr, dest_addr, length) + return True + # + if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.old_objects_pointing_to_young.append(dest_addr) - dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + self.objects_pointing_to_young.append(dest_addr) + dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0: @@ -1061,6 +1155,22 @@ self.prebuilt_root_objects.append(dest_addr) return True + def manually_copy_card_bits(self, source_addr, dest_addr, length): + # manually copy the individual card marks from source to dest + bytes = self.card_marking_bytes_for_length(length) + # + i = 0 + while i < bytes: + addr_srcbyte = self.get_card(source_addr, i) + addr_dstbyte = self.get_card(dest_addr, i) + byte = ord(addr_srcbyte.char[0]) + addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) + i += 1 + # + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1077,20 +1187,28 @@ # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'old_objects_pointing_to_young'. + # 'objects_pointing_to_young'. self.collect_roots_in_nursery() # - # If we are using card marking, do a partial trace of the arrays - # that are flagged with GCFLAG_CARDS_SET. - if self.card_page_indices > 0: - self.collect_cardrefs_to_nursery() - # - # Now trace objects from 'old_objects_pointing_to_young'. - # All nursery objects they reference are copied out of the - # nursery, and again added to 'old_objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'old_objects_pointing_to_young' is empty. - self.collect_oldrefs_to_nursery() + while True: + # If we are using card marking, do a partial trace of the arrays + # that are flagged with GCFLAG_CARDS_SET. + if self.card_page_indices > 0: + self.collect_cardrefs_to_nursery() + # + # Now trace objects from 'objects_pointing_to_young'. + # All nursery objects they reference are copied out of the + # nursery, and again added to 'objects_pointing_to_young'. + # All young raw-malloced object found is flagged GCFLAG_VISITED. + # We proceed until 'objects_pointing_to_young' is empty. + self.collect_oldrefs_to_nursery() + # + # We have to loop back if collect_oldrefs_to_nursery caused + # new objects to show up in objects_with_cards_set + if self.card_page_indices > 0: + if self.objects_with_cards_set.non_empty(): + continue + break # # Now all live nursery objects should be out. Update the young # weakrefs' targets. @@ -1123,7 +1241,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.old_objects_pointing_to_young. + # GcStruct is in the list self.objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1131,7 +1249,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.old_objects_with_cards_set + oldlist = self.objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1147,11 +1265,11 @@ bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) # - # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it - # means that it is in 'old_objects_pointing_to_young' and + # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it + # means that it is in 'objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. - if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # # In that case, we just have to reset all card bits. while bytes > 0: @@ -1187,19 +1305,30 @@ def collect_oldrefs_to_nursery(self): - # Follow the old_objects_pointing_to_young list and move the + # Follow the objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.old_objects_pointing_to_young + oldlist = self.objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have - # this flag set after a nursery collection. - self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS + # Check (somehow) that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's + # possible that the same obj is appended twice to the list + # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out + # here. + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: + ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, + "objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") + continue + # + # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should + # have this flag set after a nursery collection. + self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'old_objects_pointing_to_young' as well. + # and adding them to 'objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1238,7 +1367,19 @@ # 'obj' points to a young, raw-malloced object if (self.header(obj).tid & GCFLAG_VISITED) == 0: self.header(obj).tid |= GCFLAG_VISITED - self.old_objects_pointing_to_young.append(obj) + # + # we just made 'obj' old, so we may need to add it + # in the correct list: + if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + else: + # large array case: the object contains card marks + # that tell us where young pointers are, and it + # is already in objects_with_cards_set. + ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, + "neither YOUNG_PTRS nor HAS_CARDS??") return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1285,11 +1426,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'old_objects_pointing_to_young', + # Add the newobj to the list 'objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'old_objects_pointing_to_young'. - self.old_objects_pointing_to_young.append(newobj) + # objects when we walk 'objects_pointing_to_young'. + self.objects_pointing_to_young.append(newobj) def _malloc_out_of_nursery(self, totalsize): diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -522,5 +522,78 @@ self.stackroots.pop() test_card_marker.GC_PARAMS = {"card_page_indices": 4} + def test_writebarrier_before_copy(self): + from pypy.rpython.memory.gc import minimark + largeobj_size = self.gc.nonlarge_max + 1 + p_src = self.malloc(VAR, largeobj_size) + p_dst = self.malloc(VAR, largeobj_size) + # make them old + self.stackroots.append(p_src) + self.stackroots.append(p_dst) + self.gc.collect() + p_dst = self.stackroots.pop() + p_src = self.stackroots.pop() + # + addr_src = llmemory.cast_ptr_to_adr(p_src) + addr_dst = llmemory.cast_ptr_to_adr(p_dst) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS + # + hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have young ptrs + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert res # we optimized it + assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we copied the flag + # + hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS + hdr_src.tid |= minimark.GCFLAG_HAS_CARDS + hdr_src.tid |= minimark.GCFLAG_CARDS_SET + # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10) + assert not res # there might be young ptrs, let ll_arraycopy to find them + + def test_writebarrier_before_copy_preserving_cards(self): + from pypy.rpython.lltypesystem import llarena + from pypy.rpython.memory.gc import minimark + tid = self.get_type_id(VAR) + largeobj_size = self.gc.nonlarge_max + 1 + addr_src = self.gc.external_malloc(tid, largeobj_size) + addr_dst = self.gc.external_malloc(tid, largeobj_size) + hdr_src = self.gc.header(addr_src) + hdr_dst = self.gc.header(addr_dst) + # + assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS + assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS + # + young_p = self.malloc(S) + self.gc.write_barrier_from_array(young_p, addr_src, 0) + index_in_third_page = int(2.5 * self.gc.card_page_indices) + assert index_in_third_page < largeobj_size + self.gc.write_barrier_from_array(young_p, addr_src, + index_in_third_page) + # + assert hdr_src.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_src, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + # + res = self.gc.writebarrier_before_copy(addr_src, addr_dst, + 0, 0, 2*self.gc.card_page_indices) + assert res + # + assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET + addr_byte = self.gc.get_card(addr_dst, 0) + assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2 + + test_writebarrier_before_copy_preserving_cards.GC_PARAMS = { + "card_page_indices": 4} + + class TestMiniMarkGCFull(DirectGCTest): from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -322,7 +322,8 @@ if hasattr(GCClass, 'writebarrier_before_copy'): self.wb_before_copy_ptr = \ getfn(GCClass.writebarrier_before_copy.im_func, - [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool()) + [s_gc] + [annmodel.SomeAddress()] * 2 + + [annmodel.SomeInteger()] * 3, annmodel.SomeBool()) elif GCClass.needs_write_barrier: raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality") @@ -463,7 +464,7 @@ annmodel.SomeInteger()], annmodel.s_None, inline=True) - func = getattr(gcdata.gc, 'remember_young_pointer_from_array', + func = getattr(gcdata.gc, 'remember_young_pointer_from_array3', None) if func is not None: # func should not be a bound method, but a real function @@ -471,7 +472,8 @@ self.write_barrier_from_array_failing_case_ptr = \ getfn(func, [annmodel.SomeAddress(), - annmodel.SomeInteger()], + annmodel.SomeInteger(), + annmodel.SomeAddress()], annmodel.s_None) self.statistics_ptr = getfn(GCClass.statistics.im_func, [s_gc, annmodel.SomeInteger()], @@ -860,9 +862,9 @@ def gct_get_write_barrier_from_array_failing_case(self, hop): op = hop.spaceop - hop.genop("same_as", - [self.write_barrier_from_array_failing_case_ptr], - resultvar=op.result) + v = getattr(self, 'write_barrier_from_array_failing_case_ptr', + lltype.nullptr(op.result.concretetype.TO)) + hop.genop("same_as", [v], resultvar=op.result) def gct_zero_gc_pointers_inside(self, hop): if not self.malloc_zero_filled: @@ -883,7 +885,7 @@ dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]], resulttype=llmemory.Address) hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc, - source_addr, dest_addr], + source_addr, dest_addr] + op.args[2:], resultvar=op.result) def gct_weakref_create(self, hop): diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py b/pypy/rpython/memory/gctransform/test/test_framework.py --- a/pypy/rpython/memory/gctransform/test/test_framework.py +++ b/pypy/rpython/memory/gctransform/test/test_framework.py @@ -163,7 +163,8 @@ GC_PARAMS = {} class GCClass(MarkSweepGC): needs_write_barrier = True - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): return True def write_barrier_check(spaceop, needs_write_barrier=True): diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -136,11 +136,14 @@ ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr) return self.gc.id(ptr) - def writebarrier_before_copy(self, source, dest): + def writebarrier_before_copy(self, source, dest, + source_start, dest_start, length): if self.gc.needs_write_barrier: source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) - return self.gc.writebarrier_before_copy(source_addr, dest_addr) + return self.gc.writebarrier_before_copy(source_addr, dest_addr, + source_start, dest_start, + length) else: return True diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -140,6 +140,14 @@ self.foreach(_add_in_dict, result) return result + def tolist(self): + """NOT_RPYTHON. Returns the content as a list.""" + lst = [] + def _add(obj, lst): + lst.append(obj) + self.foreach(_add, lst) + return lst + def remove(self, addr): """Remove 'addr' from the stack. The addr *must* be in the list, and preferrably near the top. diff --git a/pypy/rpython/module/test/test_posix.py b/pypy/rpython/module/test/test_posix.py --- a/pypy/rpython/module/test/test_posix.py +++ b/pypy/rpython/module/test/test_posix.py @@ -43,6 +43,17 @@ for i in range(len(stat)): assert long(getattr(func, 'item%d' % i)) == stat[i] + def test_stat_exception(self): + def fo(): + try: + posix.stat('I/do/not/exist') + except OSError: + return True + else: + return False + res = self.interpret(fo,[]) + assert res + def test_times(self): import py; py.test.skip("llinterp does not like tuple returns") from pypy.rpython.test.test_llinterp import interpret @@ -205,5 +216,8 @@ def test_stat(self): py.test.skip("ootypesystem does not support os.stat") + def test_stat_exception(self): + py.test.skip("ootypesystem does not support os.stat") + def test_chown(self): py.test.skip("ootypesystem does not support os.chown") diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -433,7 +433,9 @@ "ll_streq": Meth([self.SELFTYPE_T], Bool), "ll_strcmp": Meth([self.SELFTYPE_T], Signed), "ll_startswith": Meth([self.SELFTYPE_T], Bool), + "ll_startswith_char": Meth([self.CHAR], Bool), "ll_endswith": Meth([self.SELFTYPE_T], Bool), + "ll_endswith_char": Meth([self.CHAR], Bool), "ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed), @@ -1429,10 +1431,18 @@ # NOT_RPYTHON return self._str.startswith(s._str) + def ll_startswith_char(self, s): + # NOT_RPYTHON + return self._str.startswith(s) + def ll_endswith(self, s): # NOT_RPYTHON return self._str.endswith(s._str) + def ll_endswith_char(self, s): + # NOT_RPYTHON + return self._str.endswith(s) + def ll_find(self, s, start, end): # NOT_RPYTHON if start > len(self._str): # workaround to cope with corner case diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py --- a/pypy/rpython/ootypesystem/rclass.py +++ b/pypy/rpython/ootypesystem/rclass.py @@ -264,7 +264,8 @@ for name, attrdef in selfattrs.iteritems(): if not attrdef.readonly and self.is_quasi_immutable(name): - ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT}) + name = mangle('mutable_' + name, self.rtyper.getconfig()) + ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/ootypesystem/test/test_oopbc.py b/pypy/rpython/ootypesystem/test/test_oopbc.py --- a/pypy/rpython/ootypesystem/test/test_oopbc.py +++ b/pypy/rpython/ootypesystem/test/test_oopbc.py @@ -81,3 +81,18 @@ res = interpret(f, [1], type_system='ootype') assert res == 2 +def test_quasi_immutable(): + class A(object): + _immutable_fields_ = ['x?'] + def __init__(self): + self.x = 3 + def foo(self): + return self.x + + a = A() + + def f(): + return a.foo() + + res = interpret(f, [], type_system='ootype') + assert res == 3 diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -667,7 +667,6 @@ res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res -ll_pop.oopspec = 'list.pop(l, index)' def ll_reverse(l): length = l.ll_length() diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py --- a/pypy/rpython/rstr.py +++ b/pypy/rpython/rstr.py @@ -81,16 +81,30 @@ return super(AbstractStringRepr, self).rtype_is_true(hop) def rtype_method_startswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_startswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_startswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_endswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_endswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_endswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_find(self, hop, reverse=False): # XXX binaryop diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,6 +598,29 @@ res = self.interpret(func, []) assert res in [5263, 6352] + def test_dict_popitem_hash(self): + def deq(n, m): + return n == m + def dhash(n): + return ~n + def func(): + d = r_dict(deq, dhash) + d[5] = 2 + d[6] = 3 + k1, v1 = d.popitem() + assert len(d) == 1 + k2, v2 = d.popitem() + try: + d.popitem() + except KeyError: + pass + else: + assert 0, "should have raised KeyError" + assert len(d) == 0 + return k1*1000 + v1*100 + k2*10 + v2 + + res = self.interpret(func, []) + assert res in [5263, 6352] class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): @@ -860,6 +883,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -227,6 +227,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_startswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].startswith('o') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_endswith(self): const = self.const def fn(i, j): @@ -238,6 +247,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_endswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].endswith('e') + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_find(self): const = self.const def fn(i, j): diff --git a/pypy/tool/gcc_cache.py b/pypy/tool/gcc_cache.py --- a/pypy/tool/gcc_cache.py +++ b/pypy/tool/gcc_cache.py @@ -39,7 +39,16 @@ data = '' if not (data.startswith('True') or data.startswith('FAIL\n')): try: - platform.compile(c_files, eci) + _previous = platform.log_errors + try: + platform.log_errors = False + platform.compile(c_files, eci) + finally: + del platform.log_errors + # ^^^remove from the instance --- needed so that it can + # compare equal to another instance without it + if platform.log_errors != _previous: + platform.log_errors = _previous data = 'True' path.write(data) except CompilationError, e: diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,9 +1,13 @@ import re, sys -from pypy.jit.metainterp.resoperation import rop, opname + +from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser +from pypy.tool.logparser import parse_log_file, extract_category class Op(object): bridge = None + offset = None + asm = None def __init__(self, name, args, res, descr): self.name = name @@ -51,17 +55,61 @@ # factory method Op = Op + use_mock_model = True + + def postprocess(self, loop, backend_dump=None, backend_tp=None, + dump_start=0): + if backend_dump is not None: + raw_asm = self._asm_disassemble(backend_dump.decode('hex'), + backend_tp, dump_start) + asm = [] + start = 0 + for elem in raw_asm: + if len(elem.split("\t")) != 3: + continue + adr, _, v = elem.split("\t") + if not start: + start = int(adr.strip(":"), 16) + ofs = int(adr.strip(":"), 16) - start + if ofs >= 0: + asm.append((ofs, v.strip("\n"))) + asm_index = 0 + for i, op in enumerate(loop.operations): + end = 0 + j = i + 1 + while end == 0: + if j == len(loop.operations): + end = loop.last_offset + break + if loop.operations[j].offset is None: + j += 1 + else: + end = loop.operations[j].offset + if op.offset is not None: + while asm[asm_index][0] < op.offset: + asm_index += 1 + end_index = asm_index + while asm[end_index][0] < end: + end_index += 1 + op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) + return loop + + def _asm_disassemble(self, d, origin_addr, tp): + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + return list(machine_code_dump(d, tp, origin_addr)) @classmethod - def parse_from_input(cls, input): - return cls(input, None, {}, 'lltype', None, - nonstrict=True).parse() + def parse_from_input(cls, input, **kwds): + parser = cls(input, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + return parser.postprocess(loop, **kwds) def parse_args(self, opname, argspec): if not argspec.strip(): return [], None if opname == 'debug_merge_point': - return argspec.rsplit(", ", 1), None + return argspec.split(", ", 1), None else: args = argspec.split(', ') descr = None @@ -95,12 +143,12 @@ def __init__(self, operations, storage): if operations[0].name == 'debug_merge_point': - self.inline_level = int(operations[0].args[1]) - m = re.search('\w]+), file \'(.+?)\', line (\d+)> #(\d+) (\w+)', - operations[0].getarg(0)) + self.inline_level = int(operations[0].args[0]) + m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', + operations[0].getarg(1)) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[0].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1].split(" ")[0][1:] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) @@ -119,6 +167,9 @@ def getcode(self): return self.code + def has_valid_code(self): + return self.code is not None + def getopcode(self): return self.code.map[self.bytecode_no] @@ -218,6 +269,12 @@ return self._lineset lineset = property(getlineset) + def has_valid_code(self): + for chunk in self.chunks: + if not chunk.has_valid_code(): + return False + return True + def _compute_linerange(self): self._lineset = set() minline = sys.maxint @@ -273,3 +330,33 @@ res.append(op) i += 1 return res + + +def import_log(logname, ParserCls=SimpleParser): + log = parse_log_file(logname) + addrs = {} + for entry in extract_category(log, 'jit-backend-addr'): + m = re.search('bootstrap ([\da-f]+)', entry) + name = entry[:entry.find('(') - 1] + addrs[int(m.group(1), 16)] = name + dumps = {} + for entry in extract_category(log, 'jit-backend-dump'): + backend, _, dump, _ = entry.split("\n") + _, addr, _, data = re.split(" +", dump) + backend_name = backend.split(" ")[1] + addr = int(addr[1:], 16) + if addr in addrs: + dumps[addrs[addr]] = (backend_name, addr, data) + loops = [] + for entry in extract_category(log, 'jit-log-opt'): + parser = ParserCls(entry, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + comm = loop.comment + name = comm[2:comm.find(':')-1] + if name in dumps: + bname, start_ofs, dump = dumps[name] + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) + loops.append(loop) + return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -0,0 +1,38 @@ +[11f210b47027] {jit-backend +[11f210b900f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 +[11f210b949b3] jit-backend-dump} +[11f210b949b4] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab188] jit-backend-addr} +[11f210bab189] jit-backend} +[11f210bacbb7] {jit-log-opt-loop +# Loop 0 : loop with 19 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 INPLACE_ADD') ++179: i8 = int_add(i4, 1) +debug_merge_point(0, ' #28 STORE_FAST') +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++183: i10 = getfield_raw(40564608, descr=) ++191: i12 = int_sub(i10, 1) ++195: setfield_raw(40564608, i12, descr=) ++203: i14 = int_lt(i12, 0) +guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++213: jump(p0, p1, p2, p3, i8, descr=) ++218: --end of the loop-- +[11f210c17981] jit-log-opt-loop} +[11f210fb1d21] {jit-backend-counts +0:8965 +1:2 +[11f210fb381b] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,12 +1,11 @@ -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, Const -from pypy.tool.jitlogparser.parser import SimpleParser, TraceForOpcode, Function,\ - adjust_bridges +from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, + Function, adjust_bridges, + import_log) from pypy.tool.jitlogparser.storage import LoopStorage -import py +import py, sys -def parse(input): - return SimpleParser.parse_from_input(input) +def parse(input, **kwds): + return SimpleParser.parse_from_input(input, **kwds) def test_parse(): @@ -29,7 +28,7 @@ def test_parse_non_code(): ops = parse(''' [] - debug_merge_point("SomeRandomStuff", 0) + debug_merge_point(0, "SomeRandomStuff") ''') res = Function.from_operations(ops.operations, LoopStorage()) assert len(res.chunks) == 1 @@ -38,10 +37,10 @@ def test_split(): ops = parse(''' [i0] - debug_merge_point(" #10 ADD", 0) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -54,12 +53,12 @@ def test_inlined_call(): ops = parse(""" [] - debug_merge_point(' #28 CALL_FUNCTION', 0) + debug_merge_point(0, ' #28 CALL_FUNCTION') i18 = getfield_gc(p0, descr=) - debug_merge_point(' #0 LOAD_FAST', 1) - debug_merge_point(' #3 LOAD_CONST', 1) - debug_merge_point(' #7 RETURN_VALUE', 1) - debug_merge_point(' #31 STORE_FAST', 0) + debug_merge_point(1, ' #0 LOAD_FAST') + debug_merge_point(1, ' #3 LOAD_CONST') + debug_merge_point(1, ' #7 RETURN_VALUE') + debug_merge_point(0, ' #31 STORE_FAST') """) res = Function.from_operations(ops.operations, LoopStorage()) assert len(res.chunks) == 3 # two chunks + inlined call @@ -72,10 +71,10 @@ def test_name(): ops = parse(''' [i0] - debug_merge_point(" #10 ADD", 0) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -89,10 +88,10 @@ ops = parse(''' [i0] i3 = int_add(i0, 1) - debug_merge_point(" #10 ADD", 0) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #10 ADD") + debug_merge_point(0, " #11 SUB") i1 = int_add(i0, 1) - debug_merge_point(" #11 SUB", 0) + debug_merge_point(0, " #11 SUB") i2 = int_add(i1, 1) ''') res = Function.from_operations(ops.operations, LoopStorage()) @@ -102,33 +101,37 @@ fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(" #0 LOAD_FAST", 0) - debug_merge_point(" #3 LOAD_FAST", 0) - debug_merge_point(" #6 BINARY_ADD", 0) - debug_merge_point(" #7 RETURN_VALUE", 0) + debug_merge_point(0, " #0 LOAD_FAST") + debug_merge_point(0, " #3 LOAD_FAST") + debug_merge_point(0, " #6 BINARY_ADD") + debug_merge_point(0, " #7 RETURN_VALUE") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.chunks[1].lineno == 3 def test_linerange(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] - debug_merge_point(" #9 LOAD_FAST", 0) - debug_merge_point(" #12 LOAD_CONST", 0) - debug_merge_point(" #22 LOAD_CONST", 0) - debug_merge_point(" #28 LOAD_CONST", 0) - debug_merge_point(" #6 SETUP_LOOP", 0) + debug_merge_point(0, " #9 LOAD_FAST") + debug_merge_point(0, " #12 LOAD_CONST") + debug_merge_point(0, " #22 LOAD_CONST") + debug_merge_point(0, " #28 LOAD_CONST") + debug_merge_point(0, " #6 SETUP_LOOP") ''' % locals()) res = Function.from_operations(ops.operations, LoopStorage()) assert res.linerange == (7, 9) assert res.lineset == set([7, 8, 9]) def test_linerange_notstarts(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] - debug_merge_point(' #17 FOR_ITER', 0) + debug_merge_point(0, ' #17 FOR_ITER') guard_class(p6, 144264192, descr=) p12 = getfield_gc(p6, descr=) """ % locals()) @@ -168,14 +171,46 @@ [] int_add(0, 1) ''') - loops = LoopStorage().reconnect_loops([main, bridge]) + LoopStorage().reconnect_loops([main, bridge]) assert adjust_bridges(main, {})[1].name == 'guard_true' assert adjust_bridges(main, {'loop-13': True})[1].name == 'int_add' def test_parsing_strliteral(): loop = parse(""" - debug_merge_point('StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]', 0) + debug_merge_point(0, 'StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]') """) ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] assert chunk.bytecode_name == 'StrLiteralSearch' + +def test_parsing_assembler(): + backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" + dump_start = 0x7f3b0b2e63d5 + loop = parse(""" + # Loop 0 : loop with 19 ops + [p0, p1, p2, p3, i4] + debug_merge_point(0, ' #15 COMPARE_OP') + +166: i6 = int_lt(i4, 10000) + guard_true(i6, descr=) [p1, p0, p2, p3, i4] + debug_merge_point(0, ' #27 INPLACE_ADD') + +179: i8 = int_add(i4, 1) + debug_merge_point(0, ' #31 JUMP_ABSOLUTE') + +183: i10 = getfield_raw(40564608, descr=) + +191: i12 = int_sub(i10, 1) + +195: setfield_raw(40564608, i12, descr=) + +203: i14 = int_lt(i12, 0) + guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] + debug_merge_point(0, ' #9 LOAD_FAST') + +213: jump(p0, p1, p2, p3, i8, descr=) + +218: --end of the loop--""", backend_dump=backend_dump, + dump_start=dump_start, + backend_tp='x86_64') + cmp = loop.operations[1] + assert 'jge' in cmp.asm + assert '0x2710' in cmp.asm + assert 'jmp' in loop.operations[-1].asm + +def test_import_log(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest.log'))) + assert 'jge' in loops[0].operations[3].asm diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -1,8 +1,13 @@ import autopath import py -from pypy.interpreter import gateway +from pypy.interpreter import gateway, pycode from pypy.interpreter.error import OperationError +try: + from _pytest.assertion.newinterpret import interpret +except ImportError: + from _pytest.assertion.oldinterpret import interpret + # ____________________________________________________________ class AppCode(object): @@ -51,13 +56,11 @@ space = self.space for key, w_value in vars.items(): space.setitem(self.w_locals, space.wrap(key), w_value) - return space.eval(code, self.w_globals, self.w_locals) - - def exec_(self, code, **vars): - space = self.space - for key, w_value in vars.items(): - space.setitem(self.w_locals, space.wrap(key), w_value) - space.exec_(code, self.w_globals, self.w_locals) + if isinstance(code, str): + return space.eval(code, self.w_globals, self.w_locals) + pyc = pycode.PyCode._from_code(space, code) + return pyc.exec_host_bytecode(self.w_globals, self.w_locals) + exec_ = eval def repr(self, w_value): return self.space.unwrap(self.space.repr(w_value)) @@ -80,7 +83,7 @@ def __init__(self, space, operr): self.space = space self.operr = operr - self.typename = operr.w_type.getname(space, "?") + self.typename = operr.w_type.getname(space) self.traceback = AppTraceback(space, self.operr.get_traceback()) debug_excs = getattr(operr, 'debug_excs', []) if debug_excs: @@ -163,8 +166,8 @@ except py.error.ENOENT: source = None from pypy import conftest - if source and not py.test.config.option.nomagic: - msg = py.code._reinterpret_old(source, runner, should_fail=True) + if source and py.test.config._assertstate.mode != "off": + msg = interpret(source, runner, should_fail=True) space.setattr(w_self, space.wrap('args'), space.newtuple([space.wrap(msg)])) w_msg = space.wrap(msg) diff --git a/pypy/tool/pytest/test/test_pytestsupport.py b/pypy/tool/pytest/test/test_pytestsupport.py --- a/pypy/tool/pytest/test/test_pytestsupport.py +++ b/pypy/tool/pytest/test/test_pytestsupport.py @@ -4,7 +4,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.pyframe import PyFrame from pypy.tool.pytest.appsupport import (AppFrame, build_pytest_assertion, - AppExceptionInfo) + AppExceptionInfo, interpret) import py from pypy.tool.udir import udir import os @@ -22,8 +22,8 @@ co = PyCode._from_code(space, somefunc.func_code) pyframe = PyFrame(space, co, space.newdict(), None) runner = AppFrame(space, pyframe) - py.code._reinterpret_old("f = lambda x: x+1", runner, should_fail=False) - msg = py.code._reinterpret_old("assert isinstance(f(2), float)", runner) + interpret("f = lambda x: x+1", runner, should_fail=False) + msg = interpret("assert isinstance(f(2), float)", runner) assert msg.startswith("assert isinstance(3, float)\n" " + where 3 = ") @@ -58,6 +58,12 @@ except AssertionError, e: assert e.msg == "Failed" +def app_test_comparison(): + try: + assert 3 > 4 + except AssertionError, e: + assert "3 > 4" in e.msg + def test_appexecinfo(space): try: diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -3,9 +3,9 @@ It uses 'pypy/translator/goal/pypy-c' and parts of the rest of the working copy. Usage: - package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] + package.py root-pypy-dir [name-of-archive] [name-of-pypy-c] [destination-for-tarball] [pypy-c-path] -Usually you would do: package.py ../../.. pypy-VER-PLATFORM. +Usually you would do: package.py ../../.. pypy-VER-PLATFORM The output is found in the directory /tmp/usession-YOURNAME/build/. """ @@ -122,7 +122,10 @@ zf.close() else: archive = str(builddir.join(name + '.tar.bz2')) - e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) + if sys.platform == 'darwin': + e = os.system('tar --numeric-owner -cvjf ' + archive + " " + name) + else: + e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name) if e: raise OSError('"tar" returned exit status %r' % e) finally: diff --git a/pypy/tool/test/test_gcc_cache.py b/pypy/tool/test/test_gcc_cache.py --- a/pypy/tool/test/test_gcc_cache.py +++ b/pypy/tool/test/test_gcc_cache.py @@ -1,11 +1,13 @@ - +import sys from pypy.tool.gcc_cache import * from pypy.tool.udir import udir -import md5 +import md5, cStringIO from pypy.translator.tool.cbuild import ExternalCompilationInfo +localudir = udir.join('test_gcc_cache').ensure(dir=1) + def test_gcc_exec(): - f = udir.join("x.c") + f = localudir.join("x.c") f.write(""" #include #include @@ -15,8 +17,8 @@ return 0; } """) - dir1 = udir.join('test_gcc_exec_dir1').ensure(dir=1) - dir2 = udir.join('test_gcc_exec_dir2').ensure(dir=1) + dir1 = localudir.join('test_gcc_exec_dir1').ensure(dir=1) + dir2 = localudir.join('test_gcc_exec_dir2').ensure(dir=1) dir1.join('test_gcc_exec.h').write('#define ANSWER 3\n') dir2.join('test_gcc_exec.h').write('#define ANSWER 42\n') eci = ExternalCompilationInfo(include_dirs=[str(dir1)]) @@ -36,7 +38,7 @@ print '>>>' def test_gcc_ask(): - f = udir.join("y.c") + f = localudir.join("y.c") f.write(""" #include #include @@ -46,8 +48,8 @@ return 0; } """) - dir1 = udir.join('test_gcc_ask_dir1').ensure(dir=1) - dir2 = udir.join('test_gcc_ask_dir2').ensure(dir=1) + dir1 = localudir.join('test_gcc_ask_dir1').ensure(dir=1) + dir2 = localudir.join('test_gcc_ask_dir2').ensure(dir=1) dir1.join('test_gcc_ask.h').write('/* hello world */\n') dir2.join('test_gcc_ask.h').write('#error boom\n') eci = ExternalCompilationInfo(include_dirs=[str(dir1)]) @@ -63,3 +65,15 @@ print '<<<' print err print '>>>' + +def test_gcc_ask_doesnt_log_errors(): + f = localudir.join('z.c') + f.write("""this file is not valid C code\n""") + eci = ExternalCompilationInfo() + oldstderr = sys.stderr + try: + sys.stderr = capture = cStringIO.StringIO() + py.test.raises(CompilationError, try_compile_cache, [f], eci) + finally: + sys.stderr = oldstderr + assert 'ERROR' not in capture.getvalue().upper() diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -297,6 +297,13 @@ gc_startup_code = RefcountingGcPolicy.gc_startup_code.im_func + def compilation_info(self): + eci = BasicGcPolicy.compilation_info(self) + eci = eci.merge(ExternalCompilationInfo( + post_include_bits=['#define USING_NO_GC_AT_ALL'], + )) + return eci + class FrameworkGcPolicy(BasicGcPolicy): transformerclass = framework.FrameworkGCTransformer diff --git a/pypy/translator/c/gcc/instruction.py b/pypy/translator/c/gcc/instruction.py --- a/pypy/translator/c/gcc/instruction.py +++ b/pypy/translator/c/gcc/instruction.py @@ -187,8 +187,8 @@ def requestgcroots(self, tracker): # no need to track the value of these registers in the caller - # function if we are the main(), or if we are flagged as a - # "bottom" function (a callback from C code) + # function if we are flagged as a "bottom" function (a callback + # from C code, or pypy_main_function()) if tracker.is_stack_bottom: return {} else: diff --git a/pypy/translator/c/gcc/test/elf/track10.s b/pypy/translator/c/gcc/test/elf/track10.s --- a/pypy/translator/c/gcc/test/elf/track10.s +++ b/pypy/translator/c/gcc/test/elf/track10.s @@ -1,5 +1,5 @@ - .type main, @function -main: + .type main1, @function +main1: pushl %ebx call pypy_f ;; expected {4(%esp) | (%esp), %esi, %edi, %ebp | %ebx} @@ -11,4 +11,4 @@ /* GCROOT %ebx */ popl %ebx ret - .size main, .-main + .size main1, .-main1 diff --git a/pypy/translator/c/gcc/test/elf/track12.s b/pypy/translator/c/gcc/test/elf/track12.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf/track12.s @@ -0,0 +1,9 @@ + .type pypy_f, @function +pypy_f: + pushl 4(%esp) + call pypy_other + ;; expected {4(%esp) | %ebx, %esi, %edi, %ebp | (%esp)} + popl %eax + /* GCROOT %eax */ + ret + .size pypy_f, .-pypy_f diff --git a/pypy/translator/c/gcc/test/elf/track13.s b/pypy/translator/c/gcc/test/elf/track13.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf/track13.s @@ -0,0 +1,9 @@ + .type pypy_f, @function +pypy_f: + call pypy_other + ;; expected {(%esp) | %ebx, %esi, %edi, %ebp | 8(%esp)} + pushl 8(%esp) + popl %eax + /* GCROOT %eax */ + ret + .size pypy_f, .-pypy_f diff --git a/pypy/translator/c/gcc/test/elf/track4.s b/pypy/translator/c/gcc/test/elf/track4.s deleted file mode 100644 --- a/pypy/translator/c/gcc/test/elf/track4.s +++ /dev/null @@ -1,52 +0,0 @@ - .type main, @function -main: - ;; this is an artificial example showing what kind of code gcc - ;; can produce for main() - pushl %ebp - movl %eax, $globalptr1 - movl %esp, %ebp - pushl %edi - subl $8, %esp - andl $-16, %esp - movl %ebx, -8(%ebp) - movl 8(%ebp), %edi - call foobar - ;; expected {4(%ebp) | -8(%ebp), %esi, -4(%ebp), (%ebp) | %edi} -.L1: - cmpl $0, %eax - je .L3 -.L2: - ;; inlined function here with -fomit-frame-pointer - movl %eax, -12(%ebp) - movl %edi, %edx - subl $16, %esp - movl %eax, (%esp) - movl $42, %edi - movl %edx, 4(%esp) - movl %esi, %ebx - movl $nonsense, %esi - call foobar - ;; expected {4(%ebp) | -8(%ebp), %ebx, -4(%ebp), (%ebp) | 4(%esp), -12(%ebp)} - addl %edi, %eax - movl 4(%esp), %eax - movl %ebx, %esi - addl $16, %esp - movl %eax, %edi - movl -12(%ebp), %eax -#APP - /* GCROOT %eax */ -#NO_APP - ;; end of inlined function -.L3: - call foobar - ;; expected {4(%ebp) | -8(%ebp), %esi, -4(%ebp), (%ebp) | %edi} -#APP - /* GCROOT %edi */ -#NO_APP - movl -8(%ebp), %ebx - movl -4(%ebp), %edi - movl %ebp, %esp - popl %ebp - ret - - .size main, .-main diff --git a/pypy/translator/c/gcc/test/elf/track6.s b/pypy/translator/c/gcc/test/elf/track6.s deleted file mode 100644 --- a/pypy/translator/c/gcc/test/elf/track6.s +++ /dev/null @@ -1,26 +0,0 @@ - .type main, @function -main: - ;; a minimal example showing what kind of code gcc - ;; can produce for main(): some local variable accesses - ;; are relative to %ebp, while others are relative to - ;; %esp, and the difference %ebp-%esp is not constant - ;; because of the 'andl' to align the stack - pushl %ebp - movl %esp, %ebp - subl $8, %esp - andl $-16, %esp - movl $globalptr1, -4(%ebp) - movl $globalptr2, (%esp) - pushl $0 - call foobar - ;; expected {4(%ebp) | %ebx, %esi, %edi, (%ebp) | 4(%esp), -4(%ebp)} - popl %eax -#APP - /* GCROOT -4(%ebp) */ - /* GCROOT (%esp) */ -#NO_APP - movl %ebp, %esp - popl %ebp - ret - - .size main, .-main diff --git a/pypy/translator/c/gcc/test/elf/track7.s b/pypy/translator/c/gcc/test/elf/track7.s --- a/pypy/translator/c/gcc/test/elf/track7.s +++ b/pypy/translator/c/gcc/test/elf/track7.s @@ -1,5 +1,5 @@ - .type main, @function -main: + .type main1, @function +main1: ;; cmovCOND tests. pushl %ebx movl 12(%esp), %ebx @@ -16,4 +16,4 @@ popl %ebx ret - .size main, .-main + .size main1, .-main1 diff --git a/pypy/translator/c/gcc/test/msvc/track6.s b/pypy/translator/c/gcc/test/msvc/track6.s deleted file mode 100644 --- a/pypy/translator/c/gcc/test/msvc/track6.s +++ /dev/null @@ -1,15 +0,0 @@ -_TEXT SEGMENT -_pypy_g_foo PROC ; COMDAT - - push ebp - mov ebp, esp - and esp, -64 - sub esp, 12 - push esi - call _pypy_g_something_else - ;; expected {4(%ebp) | %ebx, (%esp), %edi, (%ebp) | } - pop esi - mov esp, ebp - pop ebp - ret 0 -_pypy_g_foo ENDP diff --git a/pypy/translator/c/gcc/test/msvc/track_and_esp.s b/pypy/translator/c/gcc/test/msvc/track_and_esp.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/msvc/track_and_esp.s @@ -0,0 +1,474 @@ +PUBLIC ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ ; `string' +PUBLIC _pypy_g_ll_math_ll_math_frexp +; COMDAT ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ +CONST SEGMENT +??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ DB 'pypy_g_ll_math_l' + DB 'l_math_frexp', 00H ; `string' +; Function compile flags: /Ogtpy +CONST ENDS +; COMDAT _pypy_g_ll_math_ll_math_frexp +_TEXT SEGMENT +_l_mantissa_0$ = -8 ; size = 8 +_l_v21638$ = -8 ; size = 8 +_l_x_14$ = 8 ; size = 8 +_pypy_g_ll_math_ll_math_frexp PROC ; COMDAT + +; 58245: struct pypy_tuple2_0 *pypy_g_ll_math_ll_math_frexp(double l_x_14) { + + push ebp + mov ebp, esp + and esp, -64 ; ffffffc0H + +; 58246: long *l_exp_p_0; double l_mantissa_0; bool_t l_v21641; +; 58247: bool_t l_v21643; bool_t l_v21644; bool_t l_v21646; bool_t l_v21647; +; 58248: bool_t l_v21652; bool_t l_v21653; bool_t l_v21660; bool_t l_v21666; +; 58249: bool_t l_v21670; bool_t l_v21674; bool_t l_v21676; double l_v21638; +; 58250: long l_v21637; long l_v21649; long l_v21651; long l_v21677; +; 58251: long l_v21678; struct pypy_exceptions_Exception0 *l_v21687; +; 58252: struct pypy_header0 *l_v21654; struct pypy_object0 *l_v21682; +; 58253: struct pypy_object0 *l_v21691; struct pypy_object_vtable0 *l_v21665; +; 58254: struct pypy_object_vtable0 *l_v21669; +; 58255: struct pypy_object_vtable0 *l_v21675; +; 58256: struct pypy_object_vtable0 *l_v21683; struct pypy_tuple2_0 *l_v21640; +; 58257: struct pypy_tuple2_0 *l_v21695; void* l_v21639; void* l_v21648; +; 58258: void* l_v21650; void* l_v21656; void* l_v21658; void* l_v21659; +; 58259: void* l_v21668; void* l_v21672; void* l_v21679; void* l_v21688; +; 58260: void* l_v21696; +; 58261: goto block0; +; 58262: +; 58263: block0: +; 58264: l_v21641 = pypy_g_ll_math_ll_math_isnan(l_x_14); + + fld QWORD PTR _l_x_14$[ebp] + sub esp, 52 ; 00000034H + push ebx + push esi + push edi + sub esp, 8 + fstp QWORD PTR [esp] +$block0$88239: + call _pypy_g_ll_math_ll_math_isnan + +; 58265: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isnan); +; 58266: l_v21643 = l_v21641; +; 58267: if (l_v21643) { +; 58268: l_v21637 = 0L; +; 58269: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] + add esp, 8 + test al, al + +; 58270: goto block3; + + jne SHORT $LN10 at pypy_g_ll_@159 + +; 58271: } +; 58272: goto block1; +; 58273: +; 58274: block1: +; 58275: l_v21644 = pypy_g_ll_math_ll_math_isinf(l_x_14); + + sub esp, 8 + fstp QWORD PTR [esp] +$block1$88243: + call _pypy_g_ll_math_ll_math_isinf + add esp, 8 + +; 58276: pypy_asm_gc_nocollect(pypy_g_ll_math_ll_math_isinf); +; 58277: l_v21646 = l_v21644; +; 58278: if (l_v21646) { + + test al, al + je SHORT $block2$88245 + +; 58279: l_v21637 = 0L; +; 58280: l_v21638 = l_x_14; + + fld QWORD PTR _l_x_14$[ebp] +$LN10 at pypy_g_ll_@159: + +; 58288: goto block14; +; 58289: } +; 58290: l_v21637 = 0L; + + xor edi, edi +$LN30 at pypy_g_ll_@159: + +; 58291: l_v21638 = l_x_14; +; 58292: goto block3; +; 58293: +; 58294: block3: +; 58295: l_v21648 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free; + + mov esi, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4 + fstp QWORD PTR _l_v21638$[esp+64] + +; 58296: OP_RAW_MALLOC_USAGE((0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21649); +; 58297: l_v21650 = (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_top_of_space; +; 58298: OP_ADR_DELTA(l_v21650, l_v21648, l_v21651); + + mov eax, DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+12 + sub eax, esi + +; 58299: OP_INT_GT(l_v21649, l_v21651, l_v21652); + + cmp eax, 24 ; 00000018H +$block3$88242: + +; 58300: if (l_v21652) { + + jge $block4$88260 + +; 58334: l_v21695 = l_v21640; +; 58335: goto block8; +; 58336: +; 58337: block8: +; 58338: RPY_DEBUG_RETURN(); +; 58339: return l_v21695; +; 58340: +; 58341: block9: +; 58342: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58343: l_v21695 = ((struct pypy_tuple2_0 *) NULL); +; 58344: goto block8; +; 58345: +; 58346: block10: +; 58347: abort(); /* debug_llinterpcall should be unreachable */ +; 58348: l_v21665 = (&pypy_g_ExcData)->ed_exc_type; +; 58349: l_v21666 = (l_v21665 == NULL); +; 58350: if (!l_v21666) { +; 58351: goto block11; +; 58352: } +; 58353: goto block5; +; 58354: +; 58355: block11: +; 58356: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); +; 58357: l_v21696 = NULL; +; 58358: goto block6; +; 58359: +; 58360: block12: +; 58361: l_v21668 = pypy_g_SemiSpaceGC_obtain_free_space((&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC), (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0)))); + + push 24 ; 00000018H + push OFFSET _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC +$block12$88259: + call _pypy_g_SemiSpaceGC_obtain_free_space + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58362: l_v21669 = (&pypy_g_ExcData)->ed_exc_type; +; 58363: l_v21670 = (l_v21669 == NULL); + + xor ecx, ecx + add esp, 8 + cmp DWORD PTR _pypy_g_ExcData, ecx + +; 58364: if (!l_v21670) { + + je $LN5 at pypy_g_ll_@159 + +; 58368: goto block4; +; 58369: +; 58370: block13: +; 58371: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?N@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?8??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], ecx + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block13$88313: +$block9$88285: + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block2$88245: + +; 58281: goto block3; +; 58282: } +; 58283: goto block2; +; 58284: +; 58285: block2: +; 58286: OP_FLOAT_IS_TRUE(l_x_14, l_v21647); + + fldz + fld QWORD PTR _l_x_14$[ebp] + fucom ST(1) + fnstsw ax + fstp ST(1) + test ah, 68 ; 00000044H + +; 58287: if (l_v21647) { + + jnp $LN10 at pypy_g_ll_@159 + +; 58372: l_v21696 = NULL; +; 58373: goto block6; +; 58374: +; 58375: block14: +; 58376: l_v21672 = pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign(1L, (0 + 0), sizeof(long)); + + push 4 + fstp ST(0) + push 0 + push 1 +$block14$88247: + call _pypy_g__ll_malloc_varsize_no_length__Signed_Signed_Sign + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } + mov esi, eax + +; 58377: OP_TRACK_ALLOC_START(l_v21672, /* nothing */); + + push OFFSET ??_C at _0BN@BIPHFGBC at pypy_g_ll_math_ll_math_frexp?$AA@ + push esi + call _pypy_debug_alloc_start + ;; expected {4(%ebp) | 28(%esp), 24(%esp), 20(%esp), (%ebp) | } + add esp, 20 ; 00000014H + +; 58378: l_exp_p_0 = (long *)l_v21672; +; 58379: l_v21674 = (l_exp_p_0 != NULL); + + test esi, esi + +; 58380: if (!l_v21674) { + + jne SHORT $block15$88324 + +; 58418: goto block8; +; 58419: +; 58420: block18: +; 58421: PYPY_DEBUG_RECORD_TRACEBACK("ll_math_ll_math_frexp"); + + mov eax, DWORD PTR _pypydtcount + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BB@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], esi + inc eax + and eax, 8191 ; 00001fffH + mov DWORD PTR _pypydtcount, eax +$block18$88323: + +; 58422: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block15$88324: + +; 58381: goto block18; +; 58382: } +; 58383: goto block15; +; 58384: +; 58385: block15: +; 58386: l_mantissa_0 = pypy_g_frexp__Float_arrayPtr_star_2(l_x_14, l_exp_p_0); + + fld QWORD PTR _l_x_14$[ebp] + push esi + sub esp, 8 + fstp QWORD PTR [esp] + call _pypy_g_frexp__Float_arrayPtr_star_2 + ;; expected {4(%ebp) | 20(%esp), 16(%esp), 12(%esp), (%ebp) | } + +; 58387: l_v21675 = (&pypy_g_ExcData)->ed_exc_type; +; 58388: l_v21676 = (l_v21675 == NULL); + + mov edi, DWORD PTR _pypy_g_ExcData + fstp QWORD PTR _l_mantissa_0$[esp+76] + add esp, 12 ; 0000000cH + test edi, edi + +; 58389: if (!l_v21676) { + + je SHORT $block16$88328 + +; 58403: +; 58404: block17: +; 58405: l_v21682 = (&pypy_g_ExcData)->ed_exc_value; +; 58406: l_v21683 = (&pypy_g_ExcData)->ed_exc_type; +; 58407: PYPY_DEBUG_CATCH_EXCEPTION("ll_math_ll_math_frexp", l_v21683, l_v21683 == (&pypy_g_py__code_assertion_AssertionError_vtable.ae_super.ae_super.se_super.e_super) || l_v21683 == (&pypy_g_exceptions_NotImplementedError_vtable.nie_super.re_super.se_super.e_super)); + + mov eax, DWORD PTR _pypydtcount + mov ebx, DWORD PTR _pypy_g_ExcData+4 + mov DWORD PTR _pypy_debug_tracebacks[eax*8], OFFSET ?loc@?BA@??pypy_g_ll_math_ll_math_frexp@@9 at 9 + mov DWORD PTR _pypy_debug_tracebacks[eax*8+4], edi + inc eax + and eax, 8191 ; 00001fffH +$block17$88327: + mov DWORD PTR _pypydtcount, eax + cmp edi, OFFSET _pypy_g_py__code_assertion_AssertionError_vtable + je SHORT $LN1 at pypy_g_ll_@159 + cmp edi, OFFSET _pypy_g_exceptions_NotImplementedError_vtable + jne SHORT $LN2 at pypy_g_ll_@159 +$LN1 at pypy_g_ll_@159: + call _pypy_debug_catch_fatal_exception +$LN2 at pypy_g_ll_@159: + +; 58408: (&pypy_g_ExcData)->ed_exc_value = ((struct pypy_object0 *) NULL); + + xor eax, eax + +; 58409: (&pypy_g_ExcData)->ed_exc_type = ((struct pypy_object_vtable0 *) NULL); +; 58410: l_v21687 = (struct pypy_exceptions_Exception0 *)l_v21682; +; 58411: l_v21688 = (void*)l_exp_p_0; +; 58412: OP_TRACK_ALLOC_STOP(l_v21688, /* nothing */); + + push esi + mov DWORD PTR _pypy_g_ExcData+4, eax + mov DWORD PTR _pypy_g_ExcData, eax + call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } + +; 58413: OP_RAW_FREE(l_v21688, /* nothing */); + + push esi + call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58414: l_v21691 = (struct pypy_object0 *)l_v21687; +; 58415: pypy_g_RPyReRaiseException(l_v21683, l_v21691); + + push ebx + push edi + call _pypy_g_RPyReRaiseException + add esp, 16 ; 00000010H + +; 58416: pypy_asm_gc_nocollect(pypy_g_RPyReRaiseException); +; 58417: l_v21695 = ((struct pypy_tuple2_0 *) NULL); + + xor eax, eax + +; 58423: goto block8; +; 58424: } + + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret 0 +$block16$88328: + +; 58390: goto block17; +; 58391: } +; 58392: goto block16; +; 58393: +; 58394: block16: +; 58395: l_v21677 = RPyBareItem(l_exp_p_0, 0L); +; 58396: l_v21678 = (long)(l_v21677); + + mov edi, DWORD PTR [esi] + +; 58397: l_v21679 = (void*)l_exp_p_0; +; 58398: OP_TRACK_ALLOC_STOP(l_v21679, /* nothing */); + + push esi + call _pypy_debug_alloc_stop + ;; expected {4(%ebp) | 12(%esp), 8(%esp), 4(%esp), (%ebp) | } + +; 58399: OP_RAW_FREE(l_v21679, /* nothing */); + + push esi + call _PyObject_Free + ;; expected {4(%ebp) | 16(%esp), 12(%esp), 8(%esp), (%ebp) | } + +; 58400: l_v21637 = l_v21678; +; 58401: l_v21638 = l_mantissa_0; + + fld QWORD PTR _l_mantissa_0$[esp+72] + add esp, 8 + +; 58402: goto block3; + + jmp $LN30 at pypy_g_ll_@159 +$LN5 at pypy_g_ll_@159: + +; 58365: goto block13; +; 58366: } +; 58367: l_v21639 = l_v21668; + + mov esi, eax +$block4$88260: +$block5$88263: + +; 58301: goto block12; +; 58302: } +; 58303: l_v21639 = l_v21648; +; 58304: goto block4; +; 58305: +; 58306: block4: +; 58307: OP_INT_IS_TRUE(RUNNING_ON_LLINTERP, l_v21653); +; 58308: if (l_v21653) { +; 58309: goto block10; +; 58310: } +; 58311: goto block5; +; 58312: +; 58313: block5: +; 58314: l_v21654 = (struct pypy_header0 *)l_v21639; +; 58315: RPyField(l_v21654, h_tid) = (GROUP_MEMBER_OFFSET(struct group_pypy_g_typeinfo_s, member20)+0L); + + test esi, esi + jne SHORT $LN18 at pypy_g_ll_@159 + call _RPyAbort +$LN18 at pypy_g_ll_@159: + +; 58316: OP_ADR_ADD(l_v21639, (0 + ROUND_UP_FOR_ALLOCATION(sizeof(struct pypy_tuple2_0), sizeof(struct pypy_forwarding_stub0))), l_v21656); +; 58317: (&pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC)->ssgc_inst_free = l_v21656; +; 58318: OP_ADR_ADD(l_v21639, 0, l_v21658); +; 58319: l_v21659 = (void*)l_v21658; +; 58320: l_v21696 = l_v21659; +; 58321: goto block6; +; 58322: +; 58323: block6: +; 58324: l_v21640 = (struct pypy_tuple2_0 *)l_v21696; +; 58325: l_v21660 = (l_v21640 != NULL); +; 58326: if (!l_v21660) { +; 58327: goto block9; +; 58328: } +; 58329: goto block7; +; 58330: +; 58331: block7: +; 58332: RPyField(l_v21640, t_item0) = l_v21638; + + fld QWORD PTR _l_v21638$[esp+64] + mov DWORD PTR [esi], 81 ; 00000051H + lea ecx, DWORD PTR [esi+24] + mov DWORD PTR _pypy_g_pypy_rpython_memory_gc_semispace_SemiSpaceGC+4, ecx + fstp QWORD PTR [esi+8] + +; 58333: RPyField(l_v21640, t_item1) = l_v21637; + + mov DWORD PTR [esi+16], edi + +; 58423: goto block8; +; 58424: } + + pop edi + mov eax, esi + pop esi +$block6$88281: +$block8$88289: + pop ebx + mov esp, ebp + pop ebp + ret 0 +_pypy_g_ll_math_ll_math_frexp ENDP +_TEXT ENDS diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -39,10 +39,15 @@ self.uses_frame_pointer = False self.r_localvar = self.r_localvarnofp self.filetag = filetag - # a "stack bottom" function is either main() or a callback from C code + # a "stack bottom" function is either pypy_main_function() or a + # callback from C code. In both cases they are identified by + # the presence of pypy_asm_stack_bottom(). self.is_stack_bottom = False def computegcmaptable(self, verbose=0): + if self.funcname in ['main', '_main']: + return [] # don't analyze main(), its prologue may contain + # strange instructions self.findlabels() self.parse_instructions() try: @@ -226,7 +231,7 @@ # in the frame at this point. This doesn't count the return address # which is the word immediately following the frame in memory. # The 'framesize' is set to an odd value if it is only an estimate - # (see visit_andl()). + # (see InsnCannotFollowEsp). def walker(insn, size_delta): check = deltas.setdefault(insn, size_delta) @@ -266,7 +271,8 @@ match = self.r_localvar_esp.match(localvar) if match: - if localvar == self.TOP_OF_STACK: # for pushl and popl, by + if localvar == self.TOP_OF_STACK_MINUS_WORD: + # for pushl and popl, by hint = None # default ebp addressing is else: # a bit nicer hint = 'esp' @@ -521,9 +527,8 @@ target = match.group("target") if target == self.ESP: # only for andl $-16, %esp used to align the stack in main(). - # The exact amount of adjutment is not known yet, so we use - # an odd-valued estimate to make sure the real value is not used - # elsewhere by the FunctionGcRootTracker. + # main() should not be seen at all. But on e.g. MSVC we see + # the instruction somewhere else too... return InsnCannotFollowEsp() else: return self.binary_insn(line) @@ -588,10 +593,12 @@ def _visit_push(self, line): match = self.r_unaryinsn.match(line) source = match.group(1) - return [InsnStackAdjust(-self.WORD)] + self.insns_for_copy(source, self.TOP_OF_STACK) + return self.insns_for_copy(source, self.TOP_OF_STACK_MINUS_WORD) + \ + [InsnStackAdjust(-self.WORD)] def _visit_pop(self, target): - return self.insns_for_copy(self.TOP_OF_STACK, target) + [InsnStackAdjust(+self.WORD)] + return [InsnStackAdjust(+self.WORD)] + \ + self.insns_for_copy(self.TOP_OF_STACK_MINUS_WORD, target) def _visit_prologue(self): # for the prologue of functions that use %ebp as frame pointer @@ -983,15 +990,15 @@ OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' LABEL = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)' OFFSET_LABELS = 2**30 - TOP_OF_STACK = '0(%esp)' + TOP_OF_STACK_MINUS_WORD = '-4(%esp)' r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$") r_functionend = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$") - LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|\d*[(]%esp[)]" + LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|-?\d*[(]%esp[)]" LOCALVARFP = LOCALVAR + r"|-?\d*[(]%ebp[)]" r_localvarnofp = re.compile(LOCALVAR) r_localvarfp = re.compile(LOCALVARFP) - r_localvar_esp = re.compile(r"(\d*)[(]%esp[)]") + r_localvar_esp = re.compile(r"(-?\d*)[(]%esp[)]") r_localvar_ebp = re.compile(r"(-?\d*)[(]%ebp[)]") r_rel_label = re.compile(r"(\d+):\s*$") @@ -1044,7 +1051,7 @@ OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' LABEL = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)' OFFSET_LABELS = 2**30 - TOP_OF_STACK = '0(%rsp)' + TOP_OF_STACK_MINUS_WORD = '-8(%rsp)' r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$") r_functionend = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$") @@ -1140,7 +1147,7 @@ CALLEE_SAVE_REGISTERS = ['ebx', 'esi', 'edi', 'ebp'] REG2LOC = dict((_reg, LOC_REG | ((_i+1)<<2)) for _i, _reg in enumerate(CALLEE_SAVE_REGISTERS)) - TOP_OF_STACK = 'DWORD PTR [esp]' + TOP_OF_STACK_MINUS_WORD = 'DWORD PTR [esp-4]' OPERAND = r'(?:(:?WORD|DWORD|BYTE) PTR |OFFSET )?[_\w?:@$]*(?:[-+0-9]+)?(:?\[[-+*\w0-9]+\])?' LABEL = r'([a-zA-Z_$@.][a-zA-Z0-9_$@.]*)' @@ -1170,7 +1177,7 @@ r_gcroot_marker = re.compile(r"$1") # never matches r_gcroot_marker_var = re.compile(r"DWORD PTR .+_constant_always_one_.+pypy_asm_gcroot") r_gcnocollect_marker = re.compile(r"\spypy_asm_gc_nocollect\(("+OPERAND+")\);") - r_bottom_marker = re.compile(r"; .+\tpypy_asm_stack_bottom\(\);") + r_bottom_marker = re.compile(r"; .+\spypy_asm_stack_bottom\(\);") FUNCTIONS_NOT_RETURNING = { '__exit': None, @@ -1323,12 +1330,11 @@ self.verbose = verbose self.shuffle = shuffle self.gcmaptable = [] - self.seen_main = False - def process(self, iterlines, newfile, entrypoint='main', filename='?'): + def process(self, iterlines, newfile, filename='?'): for in_function, lines in self.find_functions(iterlines): if in_function: - tracker = self.process_function(lines, entrypoint, filename) + tracker = self.process_function(lines, filename) lines = tracker.lines self.write_newfile(newfile, lines, filename.split('.')[0]) if self.verbose == 1: @@ -1337,11 +1343,9 @@ def write_newfile(self, newfile, lines, grist): newfile.writelines(lines) - def process_function(self, lines, entrypoint, filename): + def process_function(self, lines, filename): tracker = self.FunctionGcRootTracker( lines, filetag=getidentifier(filename)) - is_main = tracker.funcname == entrypoint - tracker.is_stack_bottom = is_main if self.verbose == 1: sys.stderr.write('.') elif self.verbose > 1: @@ -1356,7 +1360,6 @@ self.gcmaptable[:0] = table else: self.gcmaptable.extend(table) - self.seen_main |= is_main return tracker class ElfAssemblerParser(AssemblerParser): @@ -1432,11 +1435,6 @@ if functionlines: yield in_function, functionlines - def process_function(self, lines, entrypoint, filename): - entrypoint = '_' + entrypoint - return super(DarwinAssemblerParser, self).process_function( - lines, entrypoint, filename) - class DarwinAssemblerParser64(DarwinAssemblerParser): format = "darwin64" FunctionGcRootTracker = DarwinFunctionGcRootTracker64 @@ -1494,11 +1492,6 @@ "missed the end of the previous function") yield False, functionlines - def process_function(self, lines, entrypoint, filename): - entrypoint = '_' + entrypoint - return super(MsvcAssemblerParser, self).process_function( - lines, entrypoint, filename) - def write_newfile(self, newfile, lines, grist): newlines = [] for line in lines: @@ -1560,24 +1553,21 @@ self.shuffle = shuffle # to debug the sorting logic in asmgcroot.py self.format = format self.gcmaptable = [] - self.seen_main = False def dump_raw_table(self, output): - print >> output, "seen_main = %d" % (self.seen_main,) + print 'raw table' for entry in self.gcmaptable: print >> output, entry def reload_raw_table(self, input): firstline = input.readline() - assert firstline.startswith("seen_main = ") - self.seen_main |= bool(int(firstline[len("seen_main = "):].strip())) + assert firstline == 'raw table\n' for line in input: entry = eval(line) assert type(entry) is tuple self.gcmaptable.append(entry) def dump(self, output): - assert self.seen_main def _globalname(name, disp=""): return tracker_cls.function_names_prefix + name @@ -1649,8 +1639,8 @@ s = """\ /* See description in asmgcroot.py */ .cfi_startproc - movq\t%rdi, %rdx\t/* 1st argument, which is the callback */ - movq\t%rsi, %rcx\t/* 2nd argument, which is gcrootanchor */ + /* %rdi is the 1st argument, which is the callback */ + /* %rsi is the 2nd argument, which is gcrootanchor */ movq\t%rsp, %rax\t/* my frame top address */ pushq\t%rax\t\t/* ASM_FRAMEDATA[8] */ pushq\t%rbp\t\t/* ASM_FRAMEDATA[7] */ @@ -1663,15 +1653,15 @@ /* Add this ASM_FRAMEDATA to the front of the circular linked */ /* list. Let's call it 'self'. */ - movq\t8(%rcx), %rax\t/* next = gcrootanchor->next */ + movq\t8(%rsi), %rax\t/* next = gcrootanchor->next */ pushq\t%rax\t\t\t\t/* self->next = next */ - pushq\t%rcx\t\t\t/* self->prev = gcrootanchor */ - movq\t%rsp, 8(%rcx)\t/* gcrootanchor->next = self */ + pushq\t%rsi\t\t\t/* self->prev = gcrootanchor */ + movq\t%rsp, 8(%rsi)\t/* gcrootanchor->next = self */ movq\t%rsp, 0(%rax)\t\t\t/* next->prev = self */ .cfi_def_cfa_offset 80\t/* 9 pushes + the retaddr = 80 bytes */ /* note: the Mac OS X 16 bytes aligment must be respected. */ - call\t*%rdx\t\t/* invoke the callback */ + call\t*%rdi\t\t/* invoke the callback */ /* Detach this ASM_FRAMEDATA from the circular linked list */ popq\t%rsi\t\t/* prev = self->prev */ @@ -1688,7 +1678,7 @@ popq\t%rcx\t\t/* ignored ASM_FRAMEDATA[8] */ /* the return value is the one of the 'call' above, */ - /* because %rax (and possibly %rdx) are unmodified */ + /* because %rax is unmodified */ ret .cfi_endproc """ @@ -1835,11 +1825,11 @@ """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) - def process(self, iterlines, newfile, entrypoint='main', filename='?'): + def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) for in_function, lines in parser.find_functions(iterlines): if in_function: - tracker = parser.process_function(lines, entrypoint, filename) + tracker = parser.process_function(lines, filename) lines = tracker.lines parser.write_newfile(newfile, lines, filename.split('.')[0]) if self.verbose == 1: @@ -1848,7 +1838,6 @@ self.gcmaptable[:0] = parser.gcmaptable else: self.gcmaptable.extend(parser.gcmaptable) - self.seen_main |= parser.seen_main class UnrecognizedOperation(Exception): @@ -1915,7 +1904,6 @@ format = 'elf64' else: format = 'elf' - entrypoint = 'main' while len(sys.argv) > 1: if sys.argv[1] == '-v': del sys.argv[1] @@ -1929,9 +1917,9 @@ elif sys.argv[1].startswith('-f'): format = sys.argv[1][2:] del sys.argv[1] - elif sys.argv[1].startswith('-m'): - entrypoint = sys.argv[1][2:] - del sys.argv[1] + elif sys.argv[1].startswith('-'): + print >> sys.stderr, "unrecognized option:", sys.argv[1] + sys.exit(1) else: break tracker = GcRootTracker(verbose=verbose, shuffle=shuffle, format=format) @@ -1940,7 +1928,7 @@ firstline = f.readline() f.seek(0) assert firstline, "file %r is empty!" % (fn,) - if firstline.startswith('seen_main = '): + if firstline == 'raw table\n': tracker.reload_raw_table(f) f.close() else: @@ -1948,7 +1936,7 @@ lblfn = fn[:-2] + '.lbl.s' g = open(lblfn, 'w') try: - tracker.process(f, g, entrypoint=entrypoint, filename=fn) + tracker.process(f, g, filename=fn) except: g.close() os.unlink(lblfn) diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -570,7 +570,10 @@ mk.definition('ASMFILES', sfiles) mk.definition('ASMLBLFILES', lblsfiles) mk.definition('GCMAPFILES', gcmapfiles) - mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') if self.config.translation.shared: mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup") @@ -602,7 +605,7 @@ 'cmd /c $(MASM) /nologo /Cx /Cp /Zm /coff /Fo$@ /c $< $(INCLUDEDIRS)') mk.rule('.c.gcmap', '', ['$(CC) /nologo $(ASM_CFLAGS) /c /FAs /Fa$*.s $< $(INCLUDEDIRS)', - 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -m$(PYPY_MAIN_FUNCTION) -t $*.s > $@'] + 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -t $*.s > $@'] ) mk.rule('gcmaptable.c', '$(GCMAPFILES)', 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@') @@ -613,7 +616,7 @@ mk.rule('%.lbl.s %.gcmap', '%.s', [python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py ' - '-m$(PYPY_MAIN_FUNCTION) -t $< > $*.gctmp', + '-t $< > $*.gctmp', 'mv $*.gctmp $*.gcmap']) mk.rule('gcmaptable.s', '$(GCMAPFILES)', [python + @@ -623,7 +626,10 @@ mk.rule('.PRECIOUS', '%.s', "# don't remove .s files if Ctrl-C'ed") else: - mk.definition('DEBUGFLAGS', '-O1 -g') + if sys.platform == 'win32': + mk.definition('DEBUGFLAGS', '/Zi') + else: + mk.definition('DEBUGFLAGS', '-O1 -g') mk.write() #self.translator.platform, # , @@ -682,28 +688,54 @@ def getothernodes(self): return self.othernodes[:] + def getbasecfilefornode(self, node, basecname): + # For FuncNode instances, use the python source filename (relative to + # the top directory): + if hasattr(node.obj, 'graph'): + g = node.obj.graph + # Lookup the filename from the function. + # However, not all FunctionGraph objs actually have a "func": + if hasattr(g, 'func'): + if g.filename.endswith('.py'): + localpath = py.path.local(g.filename) + pypkgpath = localpath.pypkgpath() + if pypkgpath: + relpypath = localpath.relto(pypkgpath) + return relpypath.replace('.py', '.c') + return basecname + def splitnodesimpl(self, basecname, nodes, nextra, nbetween, split_criteria=SPLIT_CRITERIA): + # Gather nodes by some criteria: + nodes_by_base_cfile = {} + for node in nodes: + c_filename = self.getbasecfilefornode(node, basecname) + if c_filename in nodes_by_base_cfile: + nodes_by_base_cfile[c_filename].append(node) + else: + nodes_by_base_cfile[c_filename] = [node] + # produce a sequence of nodes, grouped into files # which have no more than SPLIT_CRITERIA lines - iternodes = iter(nodes) - done = [False] - def subiter(): - used = nextra - for node in iternodes: - impl = '\n'.join(list(node.implementation())).split('\n') - if not impl: - continue - cost = len(impl) + nbetween - yield node, impl - del impl - if used + cost > split_criteria: - # split if criteria met, unless we would produce nothing. - raise StopIteration - used += cost - done[0] = True - while not done[0]: - yield self.uniquecname(basecname), subiter() + for basecname in nodes_by_base_cfile: + iternodes = iter(nodes_by_base_cfile[basecname]) + done = [False] + def subiter(): + used = nextra + for node in iternodes: + impl = '\n'.join(list(node.implementation())).split('\n') + if not impl: + continue + cost = len(impl) + nbetween + yield node, impl + del impl + if used + cost > split_criteria: + # split if criteria met, unless we would produce nothing. + raise StopIteration + used += cost + done[0] = True + while not done[0]: + yield self.uniquecname(basecname), subiter() def gen_readable_parts_of_source(self, f): split_criteria_big = SPLIT_CRITERIA @@ -900,8 +932,9 @@ print >> f, '}' def commondefs(defines): - from pypy.rlib.rarithmetic import LONG_BIT + from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT defines['PYPY_LONG_BIT'] = LONG_BIT + defines['PYPY_LONGLONG_BIT'] = LONGLONG_BIT def add_extra_files(eci): srcdir = py.path.local(autopath.pypydir).join('translator', 'c', 'src') diff --git a/pypy/translator/c/node.py b/pypy/translator/c/node.py --- a/pypy/translator/c/node.py +++ b/pypy/translator/c/node.py @@ -1031,7 +1031,7 @@ if (issubclass(value, BaseException) and value.__module__ == 'exceptions'): return 'PyExc_' + value.__name__ - if value is py.code._AssertionError: + if issubclass(value, AssertionError): return 'PyExc_AssertionError' if value is _StackOverflow: return 'PyExc_RuntimeError' diff --git a/pypy/translator/c/src/cjkcodecs/multibytecodec.c b/pypy/translator/c/src/cjkcodecs/multibytecodec.c --- a/pypy/translator/c/src/cjkcodecs/multibytecodec.c +++ b/pypy/translator/c/src/cjkcodecs/multibytecodec.c @@ -1,4 +1,5 @@ #include +#include #include "src/cjkcodecs/multibytecodec.h" @@ -93,6 +94,22 @@ return d->inbuf - d->inbuf_start; } +Py_ssize_t pypy_cjk_dec_replace_on_error(struct pypy_cjk_dec_s* d, + Py_UNICODE *newbuf, Py_ssize_t newlen, + Py_ssize_t in_offset) +{ + if (newlen > 0) + { + if (d->outbuf + newlen > d->outbuf_end) + if (expand_decodebuffer(d, newlen) == -1) + return MBERR_NOMEMORY; + memcpy(d->outbuf, newbuf, newlen * sizeof(Py_UNICODE)); + d->outbuf += newlen; + } + d->inbuf = d->inbuf_start + in_offset; + return 0; +} + /************************************************************/ struct pypy_cjk_enc_s *pypy_cjk_enc_init(const MultibyteCodec *codec, @@ -209,3 +226,19 @@ { return d->inbuf - d->inbuf_start; } + +Py_ssize_t pypy_cjk_enc_replace_on_error(struct pypy_cjk_enc_s* d, + char *newbuf, Py_ssize_t newlen, + Py_ssize_t in_offset) +{ + if (newlen > 0) + { + if (d->outbuf + newlen > d->outbuf_end) + if (expand_encodebuffer(d, newlen) == -1) + return MBERR_NOMEMORY; + memcpy(d->outbuf, newbuf, newlen); + d->outbuf += newlen; + } + d->inbuf = d->inbuf_start + in_offset; + return 0; +} diff --git a/pypy/translator/c/src/cjkcodecs/multibytecodec.h b/pypy/translator/c/src/cjkcodecs/multibytecodec.h --- a/pypy/translator/c/src/cjkcodecs/multibytecodec.h +++ b/pypy/translator/c/src/cjkcodecs/multibytecodec.h @@ -102,6 +102,8 @@ Py_ssize_t pypy_cjk_dec_outlen(struct pypy_cjk_dec_s *); Py_ssize_t pypy_cjk_dec_inbuf_remaining(struct pypy_cjk_dec_s *d); Py_ssize_t pypy_cjk_dec_inbuf_consumed(struct pypy_cjk_dec_s* d); +Py_ssize_t pypy_cjk_dec_replace_on_error(struct pypy_cjk_dec_s* d, + Py_UNICODE *, Py_ssize_t, Py_ssize_t); struct pypy_cjk_enc_s { const MultibyteCodec *codec; @@ -119,6 +121,8 @@ Py_ssize_t pypy_cjk_enc_outlen(struct pypy_cjk_enc_s *); Py_ssize_t pypy_cjk_enc_inbuf_remaining(struct pypy_cjk_enc_s *d); Py_ssize_t pypy_cjk_enc_inbuf_consumed(struct pypy_cjk_enc_s* d); +Py_ssize_t pypy_cjk_enc_replace_on_error(struct pypy_cjk_enc_s* d, + char *, Py_ssize_t, Py_ssize_t); /* list of codecs defined in the .c files */ diff --git a/pypy/translator/c/src/int.h b/pypy/translator/c/src/int.h --- a/pypy/translator/c/src/int.h +++ b/pypy/translator/c/src/int.h @@ -73,15 +73,28 @@ /* NB. shifting has same limitations as C: the shift count must be >= 0 and < LONG_BITS. */ -#define OP_INT_RSHIFT(x,y,r) r = Py_ARITHMETIC_RIGHT_SHIFT(long, x, y) -#define OP_UINT_RSHIFT(x,y,r) r = (x) >> (y) -#define OP_LLONG_RSHIFT(x,y,r) r = Py_ARITHMETIC_RIGHT_SHIFT(PY_LONG_LONG,x,y) -#define OP_ULLONG_RSHIFT(x,y,r) r = (x) >> (y) +#define CHECK_SHIFT_RANGE(y, bits) RPyAssert(y >= 0 && y < bits, \ + "The shift count is outside of the supported range") -#define OP_INT_LSHIFT(x,y,r) r = (x) << (y) -#define OP_UINT_LSHIFT(x,y,r) r = (x) << (y) -#define OP_LLONG_LSHIFT(x,y,r) r = (x) << (y) -#define OP_ULLONG_LSHIFT(x,y,r) r = (x) << (y) + +#define OP_INT_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = Py_ARITHMETIC_RIGHT_SHIFT(long, x, (y)) +#define OP_UINT_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = (x) >> (y) +#define OP_LLONG_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = Py_ARITHMETIC_RIGHT_SHIFT(PY_LONG_LONG,x, (y)) +#define OP_ULLONG_RSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = (x) >> (y) + + +#define OP_INT_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = (x) << (y) +#define OP_UINT_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONG_BIT); \ + r = (x) << (y) +#define OP_LLONG_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = (x) << (y) +#define OP_ULLONG_LSHIFT(x,y,r) CHECK_SHIFT_RANGE(y, PYPY_LONGLONG_BIT); \ + r = (x) << (y) #define OP_INT_LSHIFT_OVF(x,y,r) \ OP_INT_LSHIFT(x,y,r); \ diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h --- a/pypy/translator/c/src/main.h +++ b/pypy/translator/c/src/main.h @@ -23,12 +23,19 @@ #include "src/winstuff.c" #endif -int PYPY_MAIN_FUNCTION(int argc, char *argv[]) +#ifdef __GNUC__ +/* Hack to prevent this function from being inlined. Helps asmgcc + because the main() function has often a different prologue/epilogue. */ +int pypy_main_function(int argc, char *argv[]) __attribute__((__noinline__)); +#endif + +int pypy_main_function(int argc, char *argv[]) { char *errmsg; int i, exitcode; RPyListOfString *list; + pypy_asm_stack_bottom(); instrument_setup(); if (sizeof(void*) != SIZEOF_LONG) { @@ -72,6 +79,12 @@ fprintf(stderr, "Fatal error during initialization: %s\n", errmsg); #endif abort(); + return 1; +} + +int PYPY_MAIN_FUNCTION(int argc, char *argv[]) +{ + return pypy_main_function(argc, argv); } #endif /* PYPY_NOT_MAIN_FILE */ diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h --- a/pypy/translator/c/src/mem.h +++ b/pypy/translator/c/src/mem.h @@ -222,6 +222,15 @@ #endif /* USING_BOEHM_GC */ + +#ifdef USING_NO_GC_AT_ALL +#define OP_BOEHM_ZERO_MALLOC(size, r, restype, is_atomic, is_varsize) \ + r = (restype) calloc(1, size); +#define OP_BOEHM_DISAPPEARING_LINK(link, obj, r) /* nothing */ +#define OP_GC__DISABLE_FINALIZERS(r) /* nothing */ +#define OP_GC__ENABLE_FINALIZERS(r) /* nothing */ +#endif + /************************************************************/ /* weakref support */ diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -1117,6 +1117,7 @@ S = lltype.GcStruct('S', ('u', lltype.Ptr(U))) A = lltype.GcArray(lltype.Ptr(S)) filename = self.filename_dump_typeids_z + open_flags = os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0) def fn(): s = lltype.malloc(S) @@ -1128,7 +1129,7 @@ # p = rgc.get_typeids_z() s = ''.join([p[i] for i in range(len(p))]) - fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0666) + fd = os.open(filename, open_flags, 0666) os.write(fd, s) os.close(fd) return 0 @@ -1137,7 +1138,7 @@ def test_write_typeids_z(self): self.run("write_typeids_z") - f = open(self.filename_dump_typeids_z) + f = open(self.filename_dump_typeids_z, 'rb') data_z = f.read() f.close() import zlib diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -55,6 +55,13 @@ data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + # Verify that the generated C files have sane names: + gen_c_files = [str(f) for f in cbuilder.extrafiles] + for expfile in ('rlib_rposix.c', + 'rpython_lltypesystem_rstr.c', + 'translator_c_test_test_standalone.c'): + assert cbuilder.targetdir.join(expfile) in gen_c_files + def test_print(self): def entry_point(argv): print "hello simpler world" @@ -596,6 +603,42 @@ # The traceback stops at f() because it's the first function that # captures the AssertionError, which makes the program abort. + def test_int_lshift_too_large(self): + from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT + def entry_point(argv): + a = int(argv[1]) + b = int(argv[2]) + print a << b + return 0 + + t, cbuilder = self.compile(entry_point, debug=True) + out = cbuilder.cmdexec("10 2", expect_crash=False) + assert out.strip() == str(10 << 2) + cases = [-4, LONG_BIT, LONGLONG_BIT] + for x in cases: + out, err = cbuilder.cmdexec("%s %s" % (1, x), expect_crash=True) + lines = err.strip() + assert 'The shift count is outside of the supported range' in lines + + def test_llong_rshift_too_large(self): + from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT + def entry_point(argv): + a = r_longlong(int(argv[1])) + b = r_longlong(int(argv[2])) + print a >> b + return 0 + + t, cbuilder = self.compile(entry_point, debug=True) + out = cbuilder.cmdexec("10 2", expect_crash=False) + assert out.strip() == str(10 >> 2) + out = cbuilder.cmdexec("%s %s" % (-42, LONGLONG_BIT - 1), expect_crash=False) + assert out.strip() == '-1' + cases = [-4, LONGLONG_BIT] + for x in cases: + out, err = cbuilder.cmdexec("%s %s" % (1, x), expect_crash=True) + lines = err.strip() + assert 'The shift count is outside of the supported range' in lines + def test_ll_assert_error_debug(self): def entry_point(argv): ll_assert(len(argv) != 1, "foobar") diff --git a/pypy/translator/driver.py b/pypy/translator/driver.py --- a/pypy/translator/driver.py +++ b/pypy/translator/driver.py @@ -559,6 +559,7 @@ shutil.copy(str(soname), str(newsoname)) self.log.info("copied: %s" % (newsoname,)) self.c_entryp = newexename + self.log.info('usession directory: %s' % (udir,)) self.log.info("created: %s" % (self.c_entryp,)) def task_compile_c(self): diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py --- a/pypy/translator/goal/app_main.py +++ b/pypy/translator/goal/app_main.py @@ -143,6 +143,7 @@ for key, value in items: print ' --jit %s=N %slow-level JIT parameter (default %s)' % ( key, ' '*(18-len(key)), value) + print ' --jit off turn off the JIT' def print_version(*args): print "Python", sys.version diff --git a/pypy/translator/goal/targetnumpystandalone.py b/pypy/translator/goal/targetnumpystandalone.py --- a/pypy/translator/goal/targetnumpystandalone.py +++ b/pypy/translator/goal/targetnumpystandalone.py @@ -10,46 +10,32 @@ """ import time -from pypy.module.micronumpy.numarray import SingleDimArray, Code, compute +from pypy.module.micronumpy.compile import numpy_compile from pypy.jit.codewriter.policy import JitPolicy - -def create_array(size): - a = SingleDimArray(size) - for i in range(size): - a.storage[i] = float(i % 10) - return a +from pypy.rpython.annlowlevel import hlstr def entry_point(argv): if len(argv) != 3: print __doc__ return 1 - bytecode = argv[1] - for b in bytecode: - if b not in 'alf': - print "WRONG BYTECODE" - print __doc__ - return 2 try: size = int(argv[2]) except ValueError: print "INVALID LITERAL FOR INT:", argv[2] print __doc__ return 3 - no_arrays = bytecode.count('l') - no_floats = bytecode.count('f') - arrays = [] - floats = [] - for i in range(no_arrays): - arrays.append(create_array(size)) - for i in range(no_floats): - floats.append(float(i + 1)) - code = Code(bytecode, arrays, floats) t0 = time.time() - compute(code) - print "bytecode:", bytecode, "size:", size + main(argv[0], size) + print "bytecode:", argv[0], "size:", size print "took:", time.time() - t0 return 0 +def main(bc, size): + if not isinstance(bc, str): + bc = hlstr(bc) # for tests + a = numpy_compile(bc, size) + a = a.compute() + def target(*args): return entry_point, None diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py --- a/pypy/translator/goal/translate.py +++ b/pypy/translator/goal/translate.py @@ -103,6 +103,8 @@ specname = os.path.splitext(os.path.basename(targetspec))[0] sys.path.insert(0, os.path.dirname(targetspec)) mod = __import__(specname) + if 'target' not in mod.__dict__: + raise Exception("file %r is not a valid targetxxx.py." % (targetspec,)) return mod.__dict__ def parse_options_and_load_target(): @@ -149,6 +151,9 @@ log.ERROR("Could not find target %r" % (arg, )) sys.exit(1) + # apply the platform settings + set_platform(config) + targetspec = translateconfig.targetspec targetspec_dic = load_target(targetspec) @@ -164,9 +169,6 @@ existing_config=config, translating=True) - # apply the platform settings - set_platform(config) - # apply the optimization level settings set_opt_level(config, translateconfig.opt) @@ -184,7 +186,7 @@ print "\n\nTarget specific help:\n\n" targetspec_dic['print_help'](config) print "\n\nFor detailed descriptions of the command line options see" - print "http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html" + print "http://pypy.readthedocs.org/en/latest/config/commandline.html" sys.exit(0) return targetspec_dic, translateconfig, config, args diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -98,6 +98,7 @@ 'jit_marker': Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, + 'jit_force_quasi_immutable': Ignore, 'debug_assert': [], # TODO: implement? 'debug_start_traceback': Ignore, diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -964,12 +964,15 @@ return a + File.separator + b; } - public String ll_strtod_formatd(String format, double d) + public String ll_strtod_formatd(double d, char code, int precision, int flags) { // XXX: this is really a quick hack to make things work. // it should disappear, because this function is not // supported by ootypesystem. - return Double.toString(d); // XXX: we are ignoring "format" + DecimalFormat format = new DecimalFormat("0.###"); + format.setMinimumFractionDigits(precision); + format.setMaximumFractionDigits(precision); + return format.format(d); } // ---------------------------------------------------------------------- diff --git a/pypy/translator/jvm/test/test_float.py b/pypy/translator/jvm/test/test_float.py --- a/pypy/translator/jvm/test/test_float.py +++ b/pypy/translator/jvm/test/test_float.py @@ -22,3 +22,14 @@ def test_r_singlefloat(self): py.test.skip("not implemented: single-precision floats") + + def test_format_float(self): + from pypy.rlib.rfloat import _formatd + def fn(precision): + return _formatd(10.01, 'd', precision, 0) + + res = self.interpret(fn, [2]) + assert res == "10.01" + + res = self.interpret(fn, [1]) + assert res == "10.0" diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py --- a/pypy/translator/platform/__init__.py +++ b/pypy/translator/platform/__init__.py @@ -38,6 +38,7 @@ c_environ = None relevant_environ = () + log_errors = True so_prefixes = ('',) @@ -120,11 +121,12 @@ if returncode != 0: errorfile = outname.new(ext='errors') errorfile.write(stderr, 'wb') - stderrlines = stderr.splitlines() - for line in stderrlines: - log.Error(line) - # ^^^ don't use ERROR, because it might actually be fine. - # Also, ERROR confuses lib-python/conftest.py. + if self.log_errors: + stderrlines = stderr.splitlines() + for line in stderrlines: + log.Error(line) + # ^^^ don't use ERROR, because it might actually be fine. + # Also, ERROR confuses lib-python/conftest.py. raise CompilationError(stdout, stderr) else: for line in stderr.splitlines(): diff --git a/pypy/translator/platform/darwin.py b/pypy/translator/platform/darwin.py --- a/pypy/translator/platform/darwin.py +++ b/pypy/translator/platform/darwin.py @@ -68,12 +68,10 @@ class Darwin_i386(Darwin): name = "darwin_i386" - link_flags = ('-arch', 'i386', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'i386') + cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer') class Darwin_x86_64(Darwin): name = "darwin_x86_64" - link_flags = ('-arch', 'x86_64', '-mmacosx-version-min=10.4') - cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer', - '-mmacosx-version-min=10.4') + link_flags = ('-arch', 'x86_64') + cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer') diff --git a/pytest.py b/pytest.py old mode 100644 new mode 100755 --- a/pytest.py +++ b/pytest.py @@ -1,7 +1,6 @@ +#!/usr/bin/env python """ unit and functional testing with Python. -(pypy version of startup script) -see http://pytest.org for details. """ __all__ = ['main'] @@ -9,23 +8,6 @@ from _pytest import core as cmdline from _pytest import __version__ -# This pytest.py script is located in the pypy source tree -# which has a copy of pytest and py within its source tree. -# If the environment also has an installed version of pytest/py -# we are bound to get warnings so we disable them. -# XXX eventually pytest and py should not be inlined shipped -# with the pypy source code but become a requirement for installation. - -import warnings -warnings.filterwarnings("ignore", - "Module py was already imported", category=UserWarning) -warnings.filterwarnings("ignore", - "Module _pytest was already imported", - category=UserWarning) -warnings.filterwarnings("ignore", - "Module pytest was already imported", - category=UserWarning) - if __name__ == '__main__': # if run as a script or by 'python -m pytest' raise SystemExit(main()) else: From noreply at buildbot.pypy.org Wed Jul 13 11:49:55 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 13 Jul 2011 11:49:55 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: tests of and support for operator overloading Message-ID: <20110713094955.4EEAE8291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45531:25d752656651 Date: 2011-07-13 02:48 -0700 http://bitbucket.org/pypy/pypy/changeset/25d752656651/ Log: tests of and support for operator overloading diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -288,7 +288,7 @@ libffitype = libffi.types.ulong def _unwrap_object(self, space, w_obj): - return space.c_uint_w(w_obj) + return space.uint_w(w_obj) def convert_argument(self, space, w_obj): arg = self._unwrap_object(space, w_obj) @@ -376,6 +376,11 @@ x = rffi.str2charp(arg) return rffi.cast(rffi.VOIDP, x) + def from_memory(self, space, w_obj, offset): + address = self._get_raw_address(space, w_obj, offset) + charpptr = rffi.cast(rffi.CCHARPP, address) + return space.wrap(rffi.charp2str(charpptr[0])) + class ShortArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True @@ -566,3 +571,4 @@ _converters["double*"] = DoublePtrConverter _converters["double[]"] = DoubleArrayConverter _converters["const char*"] = CStringConverter +_converters["char*"] = CStringConverter diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -92,10 +92,10 @@ libffitype = libffi.types.uint def _wrap_result(self, space, result): - return space.wrap(result) + return space.wrap(rffi.cast(rffi.UINT, result)) def execute(self, space, func, cppthis, num_args, args): - result = capi.c_call_i(func.cpptype.handle, func.method_index, cppthis, num_args, args) + result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) return self._wrap_result(space, result) class LongExecutor(FunctionExecutor): @@ -112,6 +112,13 @@ def execute_libffi(self, space, libffifunc, argchain): return space.wrap(libffifunc.call(argchain, lltype.Signed)) +class UnsignedLongExecutor(LongExecutor): + _immutable_ = True + libffitype = libffi.types.ulong + + def _wrap_result(self, space, result): + return space.wrap(rffi.cast(rffi.ULONG, result)) + class ConstIntRefExecutor(LongExecutor): _immutable_ = True @@ -170,6 +177,10 @@ _immutable_ = True typecode = 'l' +class UnsignedLongPtrExecutor(PtrTypeExecutor): + _immutable_ = True + typecode = 'L' + class FloatPtrExecutor(PtrTypeExecutor): _immutable_ = True typecode = 'f' @@ -274,8 +285,8 @@ _executors["unsigned int*"] = UnsignedIntPtrExecutor _executors["long int"] = LongExecutor _executors["long int*"] = LongPtrExecutor -_executors["unsigned long int"] = LongExecutor -_executors["unsigned long int*"] = LongPtrExecutor +_executors["unsigned long int"] = UnsignedLongExecutor +_executors["unsigned long int*"] = UnsignedLongPtrExecutor _executors["float"] = FloatExecutor _executors["float*"] = FloatPtrExecutor _executors["double"] = DoubleExecutor diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -246,13 +246,22 @@ return self.space.wrap(self.functions[0].executor.name) @jit.unroll_safe - def call(self, cppthis, args_w): + def call(self, cppinstance, args_w): + if cppinstance: + cppthis = cppinstance.rawobject + else: + cppthis = NULL_VOIDP + space = self.space errmsg = 'None of the overloads matched:' for i in range(len(self.functions)): cppyyfunc = self.functions[i] try: - return cppyyfunc.call(cppthis, args_w) + cppresult = cppyyfunc.call(cppthis, args_w) + if cppinstance and isinstance(cppresult, W_CPPInstance): + if cppresult.rawobject == cppinstance.rawobject: + return cppinstance # recycle object to preserve identity + return cppresult except OperationError, e: if not e.match(space, space.w_TypeError): raise @@ -377,7 +386,7 @@ self.space.wrap(str("class %s has no attribute %s" % (self.name, name)))) def invoke(self, overload, args_w): - return overload.call(NULL_VOIDP, args_w) + return overload.call(None, args_w) W_CPPScope.typedef = TypeDef( 'CPPScope', @@ -484,7 +493,7 @@ self.space.wrap("%s is abstract" % self.name)) raise - return overload.call(NULL_VOIDP, args_w) + return overload.call(None, args_w) W_CPPType.typedef = TypeDef( 'CPPType', @@ -533,7 +542,7 @@ def invoke(self, overload, args_w): self._nullcheck() - return overload.call(self.rawobject, args_w) + return overload.call(self, args_w) def destruct(self): if self.rawobject: diff --git a/pypy/module/cppyy/test/operators.cxx b/pypy/module/cppyy/test/operators.cxx new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/operators.cxx @@ -0,0 +1,1 @@ +#include "operators.h" diff --git a/pypy/module/cppyy/test/operators.h b/pypy/module/cppyy/test/operators.h new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/operators.h @@ -0,0 +1,97 @@ +class number { +public: + number() { m_int = 0; } + number(int i) { m_int = i; } + + int AsInt() { return m_int; } + + number operator+(const number& n) const { return number(m_int + n.m_int); } + number operator+(int n) const { return number(m_int + n); } + number operator-(const number& n) const { return number(m_int - n.m_int); } + number operator-(int n) const { return number(m_int - n); } + number operator*(const number& n) const { return number(m_int * n.m_int); } + number operator*(int n) const { return number(m_int * n); } + number operator/(const number& n) const { return number(m_int / n.m_int); } + number operator/(int n) const { return number(m_int / n); } + number operator%(const number& n) const { return number(m_int % n.m_int); } + number operator%(int n) const { return number(m_int % n); } + + number& operator+=(const number& n) { m_int += n.m_int; return *this; } + number& operator-=(const number& n) { m_int -= n.m_int; return *this; } + number& operator*=(const number& n) { m_int *= n.m_int; return *this; } + number& operator/=(const number& n) { m_int /= n.m_int; return *this; } + number& operator%=(const number& n) { m_int %= n.m_int; return *this; } + + number operator-() { return number( -m_int ); } + + bool operator<(const number& n) const { return m_int < n.m_int; } + bool operator>(const number& n) const { return m_int > n.m_int; } + bool operator<=(const number& n) const { return m_int <= n.m_int; } + bool operator>=(const number& n) const { return m_int >= n.m_int; } + bool operator!=(const number& n) const { return m_int != n.m_int; } + bool operator==(const number& n) const { return m_int == n.m_int; } + + operator bool() { return m_int != 0; } + + number operator&(const number& n) const { return number(m_int & n.m_int); } + number operator|(const number& n) const { return number(m_int | n.m_int); } + number operator^(const number& n) const { return number(m_int ^ n.m_int); } + + number& operator&=(const number& n) { m_int &= n.m_int; return *this; } + number& operator|=(const number& n) { m_int |= n.m_int; return *this; } + number& operator^=(const number& n) { m_int ^= n.m_int; return *this; } + + number operator<<(int i) const { return number(m_int << i); } + number operator>>(int i) const { return number(m_int >> i); } + +private: + int m_int; +}; + +//---------------------------------------------------------------------------- +struct operator_char_star { // for testing user-defined implicit casts + operator_char_star() : m_str((char*)"operator_char_star") {} + operator char*() { return m_str; } + char* m_str; +}; + +struct operator_const_char_star { + operator_const_char_star() : m_str("operator_const_char_star" ) {} + operator const char*() { return m_str; } + const char* m_str; +}; + +struct operator_int { + operator int() { return m_int; } + int m_int; +}; + +struct operator_long { + operator long() { return m_long; } + long m_long; +}; + +struct operator_double { + operator double() { return m_double; } + double m_double; +}; + +struct operator_short { + operator short() { return m_short; } + unsigned short m_short; +}; + +struct operator_unsigned_int { + operator unsigned int() { return m_uint; } + unsigned int m_uint; +}; + +struct operator_unsigned_long { + operator unsigned long() { return m_ulong; } + unsigned long m_ulong; +}; + +struct operator_float { + operator float() { return m_float; } + float m_float; +}; diff --git a/pypy/module/cppyy/test/test_operators.py b/pypy/module/cppyy/test/test_operators.py new file mode 100755 --- /dev/null +++ b/pypy/module/cppyy/test/test_operators.py @@ -0,0 +1,141 @@ +import py, os, sys +from pypy.conftest import gettestobjspace + + +currpath = py.path.local(__file__).dirpath() +shared_lib = str(currpath.join("operatorsDict.so")) + +space = gettestobjspace(usemodules=['cppyy']) + +def setup_module(mod): + if sys.platform == 'win32': + py.test.skip("win32 not supported so far") + err = os.system("cd '%s' && make operatorsDict.so" % currpath) + if err: + raise OSError("'make' failed (see stderr)") + +class AppTestOPERATORS: + def setup_class(cls): + cls.space = space + env = os.environ + cls.w_N = space.wrap(5) # should be imported from the dictionary + cls.w_shared_lib = space.wrap(shared_lib) + cls.w_datatypes = cls.space.appexec([], """(): + import cppyy + return cppyy.load_lib(%r)""" % (shared_lib, )) + + def teardown_method(self, meth): + import gc + gc.collect() + + def test01_math_operators(self): + """Test overloading of math operators""" + + import cppyy + number = cppyy.gbl.number + + assert (number(20) + number(10)) == number(30) + assert (number(20) + 10 ) == number(30) + assert (number(20) - number(10)) == number(10) + assert (number(20) - 10 ) == number(10) + assert (number(20) / number(10)) == number(2) + assert (number(20) / 10 ) == number(2) + assert (number(20) * number(10)) == number(200) + assert (number(20) * 10 ) == number(200) + assert (number(20) % 10 ) == number(0) + assert (number(20) % number(10)) == number(0) + assert (number(5) & number(14)) == number(4) + assert (number(5) | number(14)) == number(15) + assert (number(5) ^ number(14)) == number(11) + assert (number(5) << 2) == number(20) + assert (number(20) >> 2) == number(5) + + def test02_unary_math_operators(self): + """Test overloading of unary math operators""" + + import cppyy + number = cppyy.gbl.number + + n = number(20) + n += number(10) + n -= number(10) + n *= number(10) + n /= number(2) + assert n == number(100) + + nn = -n; + assert nn == number(-100) + + def test03_comparison_operators(self): + """Test overloading of comparison operators""" + + import cppyy + number = cppyy.gbl.number + + assert (number(20) > number(10)) == True + assert (number(20) < number(10)) == False + assert (number(20) >= number(20)) == True + assert (number(20) <= number(10)) == False + assert (number(20) != number(10)) == True + assert (number(20) == number(10)) == False + + def test04_boolean_operator(self): + """Test implementation of operator bool""" + + import cppyy + number = cppyy.gbl.number + + n = number(20) + assert n + + n = number(0) + assert not n + + def test05_exact_types(self): + """Test converter operators of exact types""" + + import cppyy + gbl = cppyy.gbl + + o = gbl.operator_char_star() + assert o.m_str == 'operator_char_star' + assert str(o) == 'operator_char_star' + + o = gbl.operator_const_char_star() + assert o.m_str == 'operator_const_char_star' + assert str(o) == 'operator_const_char_star' + + o = gbl.operator_int(); o.m_int = -13 + assert o.m_int == -13 + assert int(o) == -13 + + o = gbl.operator_long(); o.m_long = 42 + assert o.m_long == 42 + assert long(o) == 42 + + o = gbl.operator_double(); o.m_double = 3.1415 + assert o.m_double == 3.1415 + assert float(o) == 3.1415 + + def test06_approximate_types(self): + """Test converter operators of approximate types""" + + import cppyy, sys + gbl = cppyy.gbl + + o = gbl.operator_short(); o.m_short = 256 + assert o.m_short == 256 + assert int(o) == 256 + + o = gbl.operator_unsigned_int(); o.m_uint = 2147483647 + 32 + assert o.m_uint == 2147483647 + 32 + assert long(o) == 2147483647 + 32 + + o = gbl.operator_unsigned_long(); + o.m_ulong = sys.maxint + 128 + assert o.m_ulong == sys.maxint + 128 + assert long(o) == sys.maxint + 128 + + o = gbl.operator_float(); o.m_float = 3.14 + assert round(o.m_float - 3.14, 5) == 0. + assert round(float(o) - 3.14, 5) == 0. From noreply at buildbot.pypy.org Wed Jul 13 14:12:50 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Wed, 13 Jul 2011 14:12:50 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: can't promote strings Message-ID: <20110713121250.E0CAF8291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45537:f7ff4915180f Date: 2011-07-12 18:04 +0200 http://bitbucket.org/pypy/pypy/changeset/f7ff4915180f/ Log: can't promote strings diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -355,7 +355,7 @@ def get_method_names(self): return self.space.newlist([self.space.wrap(name) for name in self.methods]) - @jit.elidable_promote() + @jit.elidable_promote('0') def get_overload(self, name): try: return self.methods[name] @@ -367,7 +367,7 @@ def get_data_member_names(self): return self.space.newlist([self.space.wrap(name) for name in self.data_members]) - @jit.elidable_promote() + @jit.elidable_promote('0') def get_data_member(self, name): try: return self.data_members[name] From noreply at buildbot.pypy.org Wed Jul 13 14:12:52 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Wed, 13 Jul 2011 14:12:52 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge heads Message-ID: <20110713121252.2BEF28291B@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45538:6ff6f4beb1bf Date: 2011-07-13 14:07 +0200 http://bitbucket.org/pypy/pypy/changeset/6ff6f4beb1bf/ Log: merge heads diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py --- a/pypy/module/cppyy/capi/cint_capi.py +++ b/pypy/module/cppyy/capi/cint_capi.py @@ -107,6 +107,10 @@ "cppyy_call_h", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, compilation_info=eci) +c_call_i = rffi.llexternal( + "cppyy_call_i", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, + compilation_info=eci) c_call_l = rffi.llexternal( "cppyy_call_l", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.LONG, diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py --- a/pypy/module/cppyy/capi/reflex_capi.py +++ b/pypy/module/cppyy/capi/reflex_capi.py @@ -108,7 +108,7 @@ [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, compilation_info=eci) c_call_i = rffi.llexternal( - "cppyy_call_l", + "cppyy_call_i", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, compilation_info=eci) c_call_l = rffi.llexternal( diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -288,7 +288,7 @@ libffitype = libffi.types.ulong def _unwrap_object(self, space, w_obj): - return space.c_uint_w(w_obj) + return space.uint_w(w_obj) def convert_argument(self, space, w_obj): arg = self._unwrap_object(space, w_obj) @@ -376,6 +376,11 @@ x = rffi.str2charp(arg) return rffi.cast(rffi.VOIDP, x) + def from_memory(self, space, w_obj, offset): + address = self._get_raw_address(space, w_obj, offset) + charpptr = rffi.cast(rffi.CCHARPP, address) + return space.wrap(rffi.charp2str(charpptr[0])) + class ShortArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True @@ -566,3 +571,4 @@ _converters["double*"] = DoublePtrConverter _converters["double[]"] = DoubleArrayConverter _converters["const char*"] = CStringConverter +_converters["char*"] = CStringConverter diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -92,10 +92,10 @@ libffitype = libffi.types.uint def _wrap_result(self, space, result): - return space.wrap(result) + return space.wrap(rffi.cast(rffi.UINT, result)) def execute(self, space, func, cppthis, num_args, args): - result = capi.c_call_i(func.cpptype.handle, func.method_index, cppthis, num_args, args) + result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) return self._wrap_result(space, result) class LongExecutor(FunctionExecutor): @@ -112,6 +112,13 @@ def execute_libffi(self, space, libffifunc, argchain): return space.wrap(libffifunc.call(argchain, lltype.Signed)) +class UnsignedLongExecutor(LongExecutor): + _immutable_ = True + libffitype = libffi.types.ulong + + def _wrap_result(self, space, result): + return space.wrap(rffi.cast(rffi.ULONG, result)) + class ConstIntRefExecutor(LongExecutor): _immutable_ = True @@ -170,6 +177,10 @@ _immutable_ = True typecode = 'l' +class UnsignedLongPtrExecutor(PtrTypeExecutor): + _immutable_ = True + typecode = 'L' + class FloatPtrExecutor(PtrTypeExecutor): _immutable_ = True typecode = 'f' @@ -189,7 +200,7 @@ from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) ptr_result = rffi.cast(rffi.VOIDP, long_result) - return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result) + return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) class InstanceExecutor(InstancePtrExecutor): _immutable_ = True @@ -199,8 +210,7 @@ long_result = capi.c_call_o( func.cpptype.handle, func.method_index, cppthis, num_args, args, self.cpptype.handle) ptr_result = rffi.cast(rffi.VOIDP, long_result) - # TODO: take ownership of result ... - return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result) + return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, True) _executors = {} @@ -275,8 +285,8 @@ _executors["unsigned int*"] = UnsignedIntPtrExecutor _executors["long int"] = LongExecutor _executors["long int*"] = LongPtrExecutor -_executors["unsigned long int"] = LongExecutor -_executors["unsigned long int*"] = LongPtrExecutor +_executors["unsigned long int"] = UnsignedLongExecutor +_executors["unsigned long int*"] = UnsignedLongPtrExecutor _executors["float"] = FloatExecutor _executors["float*"] = FloatPtrExecutor _executors["double"] = DoubleExecutor diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -227,7 +227,7 @@ except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) raise - return W_CPPInstance(self.space, self.cpptype, newthis) + return W_CPPInstance(self.space, self.cpptype, newthis, True) class W_CPPOverload(Wrappable): @@ -246,13 +246,22 @@ return self.space.wrap(self.functions[0].executor.name) @jit.unroll_safe - def call(self, cppthis, args_w): + def call(self, cppinstance, args_w): + if cppinstance: + cppthis = cppinstance.rawobject + else: + cppthis = NULL_VOIDP + space = self.space errmsg = 'None of the overloads matched:' for i in range(len(self.functions)): cppyyfunc = self.functions[i] try: - return cppyyfunc.call(cppthis, args_w) + cppresult = cppyyfunc.call(cppthis, args_w) + if cppinstance and isinstance(cppresult, W_CPPInstance): + if cppresult.rawobject == cppinstance.rawobject: + return cppinstance # recycle object to preserve identity + return cppresult except OperationError, e: if not e.match(space, space.w_TypeError): raise @@ -377,7 +386,7 @@ self.space.wrap(str("class %s has no attribute %s" % (self.name, name)))) def invoke(self, overload, args_w): - return overload.call(NULL_VOIDP, args_w) + return overload.call(None, args_w) W_CPPScope.typedef = TypeDef( 'CPPScope', @@ -484,7 +493,7 @@ self.space.wrap("%s is abstract" % self.name)) raise - return overload.call(NULL_VOIDP, args_w) + return overload.call(None, args_w) W_CPPType.typedef = TypeDef( 'CPPType', @@ -521,10 +530,11 @@ class W_CPPInstance(Wrappable): _immutable_fields_ = ["cppclass"] - def __init__(self, space, cppclass, rawobject): + def __init__(self, space, cppclass, rawobject, python_owns): self.space = space self.cppclass = cppclass self.rawobject = rawobject + self.python_owns = python_owns def _nullcheck(self): if not self.rawobject: @@ -532,11 +542,16 @@ def invoke(self, overload, args_w): self._nullcheck() - return overload.call(self.rawobject, args_w) + return overload.call(self, args_w) def destruct(self): - capi.c_destruct(self.cppclass.handle, self.rawobject) - self.rawobject = NULL_VOIDP + if self.rawobject: + capi.c_destruct(self.cppclass.handle, self.rawobject) + self.rawobject = NULL_VOIDP + + def __del__(self): + if self.python_owns: + self.destruct() W_CPPInstance.typedef = TypeDef( 'CPPInstance', diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx --- a/pypy/module/cppyy/src/cintcwrapper.cxx +++ b/pypy/module/cppyy/src/cintcwrapper.cxx @@ -128,6 +128,12 @@ return (short)G__int(result); } +int cppyy_call_i(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + G__value result = cppyy_call_T(handle, method_index, self, numargs, args); + return (int)G__int(result); +} + long cppyy_call_l(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); diff --git a/pypy/module/cppyy/test/example01.cxx b/pypy/module/cppyy/test/example01.cxx --- a/pypy/module/cppyy/test/example01.cxx +++ b/pypy/module/cppyy/test/example01.cxx @@ -7,12 +7,28 @@ #include "example01.h" //=========================================================================== -payload::payload(double d) : m_data(d) {} -payload::payload(const payload& p) : m_data(p.m_data) {} +payload::payload(double d) : m_data(d) { + count++; +} +payload::payload(const payload& p) : m_data(p.m_data) { + count++; +} +payload& payload::operator=(const payload& p) { + if (this != &p) { + m_data = p.m_data; + } + return *this; +} +payload::~payload() { + count--; +} double payload::getData() { return m_data; } void payload::setData(double d) { m_data = d; } +// class-level data +int payload::count = 0; + //=========================================================================== example01::example01() : m_somedata(-99) { diff --git a/pypy/module/cppyy/test/example01.h b/pypy/module/cppyy/test/example01.h --- a/pypy/module/cppyy/test/example01.h +++ b/pypy/module/cppyy/test/example01.h @@ -2,10 +2,15 @@ public: payload(double d); payload(const payload& p); + payload& operator=(const payload& e); + ~payload(); double getData(); void setData(double d); +public: // class-level data + static int count; + private: double m_data; }; diff --git a/pypy/module/cppyy/test/operators.cxx b/pypy/module/cppyy/test/operators.cxx new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/operators.cxx @@ -0,0 +1,1 @@ +#include "operators.h" diff --git a/pypy/module/cppyy/test/operators.h b/pypy/module/cppyy/test/operators.h new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/operators.h @@ -0,0 +1,97 @@ +class number { +public: + number() { m_int = 0; } + number(int i) { m_int = i; } + + int AsInt() { return m_int; } + + number operator+(const number& n) const { return number(m_int + n.m_int); } + number operator+(int n) const { return number(m_int + n); } + number operator-(const number& n) const { return number(m_int - n.m_int); } + number operator-(int n) const { return number(m_int - n); } + number operator*(const number& n) const { return number(m_int * n.m_int); } + number operator*(int n) const { return number(m_int * n); } + number operator/(const number& n) const { return number(m_int / n.m_int); } + number operator/(int n) const { return number(m_int / n); } + number operator%(const number& n) const { return number(m_int % n.m_int); } + number operator%(int n) const { return number(m_int % n); } + + number& operator+=(const number& n) { m_int += n.m_int; return *this; } + number& operator-=(const number& n) { m_int -= n.m_int; return *this; } + number& operator*=(const number& n) { m_int *= n.m_int; return *this; } + number& operator/=(const number& n) { m_int /= n.m_int; return *this; } + number& operator%=(const number& n) { m_int %= n.m_int; return *this; } + + number operator-() { return number( -m_int ); } + + bool operator<(const number& n) const { return m_int < n.m_int; } + bool operator>(const number& n) const { return m_int > n.m_int; } + bool operator<=(const number& n) const { return m_int <= n.m_int; } + bool operator>=(const number& n) const { return m_int >= n.m_int; } + bool operator!=(const number& n) const { return m_int != n.m_int; } + bool operator==(const number& n) const { return m_int == n.m_int; } + + operator bool() { return m_int != 0; } + + number operator&(const number& n) const { return number(m_int & n.m_int); } + number operator|(const number& n) const { return number(m_int | n.m_int); } + number operator^(const number& n) const { return number(m_int ^ n.m_int); } + + number& operator&=(const number& n) { m_int &= n.m_int; return *this; } + number& operator|=(const number& n) { m_int |= n.m_int; return *this; } + number& operator^=(const number& n) { m_int ^= n.m_int; return *this; } + + number operator<<(int i) const { return number(m_int << i); } + number operator>>(int i) const { return number(m_int >> i); } + +private: + int m_int; +}; + +//---------------------------------------------------------------------------- +struct operator_char_star { // for testing user-defined implicit casts + operator_char_star() : m_str((char*)"operator_char_star") {} + operator char*() { return m_str; } + char* m_str; +}; + +struct operator_const_char_star { + operator_const_char_star() : m_str("operator_const_char_star" ) {} + operator const char*() { return m_str; } + const char* m_str; +}; + +struct operator_int { + operator int() { return m_int; } + int m_int; +}; + +struct operator_long { + operator long() { return m_long; } + long m_long; +}; + +struct operator_double { + operator double() { return m_double; } + double m_double; +}; + +struct operator_short { + operator short() { return m_short; } + unsigned short m_short; +}; + +struct operator_unsigned_int { + operator unsigned int() { return m_uint; } + unsigned int m_uint; +}; + +struct operator_unsigned_long { + operator unsigned long() { return m_ulong; } + unsigned long m_ulong; +}; + +struct operator_float { + operator float() { return m_float; } + float m_float; +}; diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -111,6 +111,40 @@ e2.destruct() assert t.invoke(t.get_overload("getCount")) == 0 + e2.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 + + def test_example01memory(self): + """Test memory destruction and integrity.""" + + import gc + + t = self.example01 + + assert t.invoke(t.get_overload("getCount")) == 0 + + e1 = t.construct(7) + assert t.invoke(t.get_overload("getCount")) == 1 + res = e1.invoke(t.get_overload("addDataToInt"), 4) + assert res == 11 + res = e1.invoke(t.get_overload("addDataToInt"), -4) + assert res == 3 + e1 = None + gc.collect() + assert t.invoke(t.get_overload("getCount")) == 0 + + e1 = t.construct(7) + e2 = t.construct(8) + assert t.invoke(t.get_overload("getCount")) == 2 + e1 = None + gc.collect() + assert t.invoke(t.get_overload("getCount")) == 1 + e2.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 + e2 = None + gc.collect() + assert t.invoke(t.get_overload("getCount")) == 0 + def test_example01method_double(self): """Test passing of a double and returning of double on a method""" diff --git a/pypy/module/cppyy/test/test_operators.py b/pypy/module/cppyy/test/test_operators.py new file mode 100755 --- /dev/null +++ b/pypy/module/cppyy/test/test_operators.py @@ -0,0 +1,141 @@ +import py, os, sys +from pypy.conftest import gettestobjspace + + +currpath = py.path.local(__file__).dirpath() +shared_lib = str(currpath.join("operatorsDict.so")) + +space = gettestobjspace(usemodules=['cppyy']) + +def setup_module(mod): + if sys.platform == 'win32': + py.test.skip("win32 not supported so far") + err = os.system("cd '%s' && make operatorsDict.so" % currpath) + if err: + raise OSError("'make' failed (see stderr)") + +class AppTestOPERATORS: + def setup_class(cls): + cls.space = space + env = os.environ + cls.w_N = space.wrap(5) # should be imported from the dictionary + cls.w_shared_lib = space.wrap(shared_lib) + cls.w_datatypes = cls.space.appexec([], """(): + import cppyy + return cppyy.load_lib(%r)""" % (shared_lib, )) + + def teardown_method(self, meth): + import gc + gc.collect() + + def test01_math_operators(self): + """Test overloading of math operators""" + + import cppyy + number = cppyy.gbl.number + + assert (number(20) + number(10)) == number(30) + assert (number(20) + 10 ) == number(30) + assert (number(20) - number(10)) == number(10) + assert (number(20) - 10 ) == number(10) + assert (number(20) / number(10)) == number(2) + assert (number(20) / 10 ) == number(2) + assert (number(20) * number(10)) == number(200) + assert (number(20) * 10 ) == number(200) + assert (number(20) % 10 ) == number(0) + assert (number(20) % number(10)) == number(0) + assert (number(5) & number(14)) == number(4) + assert (number(5) | number(14)) == number(15) + assert (number(5) ^ number(14)) == number(11) + assert (number(5) << 2) == number(20) + assert (number(20) >> 2) == number(5) + + def test02_unary_math_operators(self): + """Test overloading of unary math operators""" + + import cppyy + number = cppyy.gbl.number + + n = number(20) + n += number(10) + n -= number(10) + n *= number(10) + n /= number(2) + assert n == number(100) + + nn = -n; + assert nn == number(-100) + + def test03_comparison_operators(self): + """Test overloading of comparison operators""" + + import cppyy + number = cppyy.gbl.number + + assert (number(20) > number(10)) == True + assert (number(20) < number(10)) == False + assert (number(20) >= number(20)) == True + assert (number(20) <= number(10)) == False + assert (number(20) != number(10)) == True + assert (number(20) == number(10)) == False + + def test04_boolean_operator(self): + """Test implementation of operator bool""" + + import cppyy + number = cppyy.gbl.number + + n = number(20) + assert n + + n = number(0) + assert not n + + def test05_exact_types(self): + """Test converter operators of exact types""" + + import cppyy + gbl = cppyy.gbl + + o = gbl.operator_char_star() + assert o.m_str == 'operator_char_star' + assert str(o) == 'operator_char_star' + + o = gbl.operator_const_char_star() + assert o.m_str == 'operator_const_char_star' + assert str(o) == 'operator_const_char_star' + + o = gbl.operator_int(); o.m_int = -13 + assert o.m_int == -13 + assert int(o) == -13 + + o = gbl.operator_long(); o.m_long = 42 + assert o.m_long == 42 + assert long(o) == 42 + + o = gbl.operator_double(); o.m_double = 3.1415 + assert o.m_double == 3.1415 + assert float(o) == 3.1415 + + def test06_approximate_types(self): + """Test converter operators of approximate types""" + + import cppyy, sys + gbl = cppyy.gbl + + o = gbl.operator_short(); o.m_short = 256 + assert o.m_short == 256 + assert int(o) == 256 + + o = gbl.operator_unsigned_int(); o.m_uint = 2147483647 + 32 + assert o.m_uint == 2147483647 + 32 + assert long(o) == 2147483647 + 32 + + o = gbl.operator_unsigned_long(); + o.m_ulong = sys.maxint + 128 + assert o.m_ulong == sys.maxint + 128 + assert long(o) == sys.maxint + 128 + + o = gbl.operator_float(); o.m_float = 3.14 + assert round(o.m_float - 3.14, 5) == 0. + assert round(float(o) - 3.14, 5) == 0. diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py --- a/pypy/module/cppyy/test/test_pythonify.py +++ b/pypy/module/cppyy/test/test_pythonify.py @@ -199,3 +199,44 @@ assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5 assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5 + + def test09_memory(self): + import cppyy, gc + example01_class = cppyy.gbl.example01 + payload_class = cppyy.gbl.payload + + pl = payload_class(3.14) + assert payload_class.count == 1 + assert round(pl.getData()-3.14, 8) == 0 + + pl2 = example01_class.staticCopyCyclePayload(pl, 38.) + assert payload_class.count == 2 + assert pl2.getData() == 38. + pl2 = None + gc.collect() + assert payload_class.count == 1 + + e = example01_class(14) + + pl2 = e.copyCyclePayload(pl) + assert payload_class.count == 2 + assert round(pl2.getData()-14., 8) == 0 + pl2 = None + gc.collect() + assert payload_class.count == 1 + + pl = None + e = None + gc.collect() + assert payload_class.count == 0 + assert example01_class.getCount() == 0 + + pl = payload_class(3.14) + pl_a = example01_class.staticCyclePayload(pl, 66.) + pl_a.getData() == 66. + assert payload_class.count == 1 + pl = None + gc.collect() + assert payload_class.count == 0 + + # TODO: need ReferenceError on touching pl_a From noreply at buildbot.pypy.org Wed Jul 13 14:12:53 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Wed, 13 Jul 2011 14:12:53 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: hg merge default Message-ID: <20110713121253.77A078291C@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45539:f37b832e2ed3 Date: 2011-07-13 14:08 +0200 http://bitbucket.org/pypy/pypy/changeset/f37b832e2ed3/ Log: hg merge default diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -925,6 +925,9 @@ return self.w_True return self.w_False + def issequence_w(self, w_obj): + return (self.findattr(w_obj, self.wrap("__getitem__")) is not None) + def isinstance_w(self, w_obj, w_type): return self.is_true(self.isinstance(w_obj, w_type)) diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -765,13 +765,58 @@ raise NotImplementedError("cast_ptr_to_int") def rewrite_op_force_cast(self, op): + assert not self._is_gc(op.args[0]) + fromll = longlong.is_longlong(op.args[0].concretetype) + toll = longlong.is_longlong(op.result.concretetype) + if fromll and toll: + return + if fromll: + args = op.args + opname = 'truncate_longlong_to_int' + RESULT = lltype.Signed + v = varoftype(RESULT) + op1 = SpaceOperation(opname, args, v) + op2 = self.rewrite_operation(op1) + oplist = self.force_cast_without_longlong(op2.result, op.result) + if oplist: + return [op2] + oplist + # + # force a renaming to put the correct result in place, even though + # it might be slightly mistyped (e.g. Signed versus Unsigned) + assert op2.result is v + op2.result = op.result + return op2 + elif toll: + from pypy.rpython.lltypesystem import rffi + size, unsigned = rffi.size_and_sign(op.args[0].concretetype) + if unsigned: + INTERMEDIATE = lltype.Unsigned + else: + INTERMEDIATE = lltype.Signed + v = varoftype(INTERMEDIATE) + oplist = self.force_cast_without_longlong(op.args[0], v) + if not oplist: + v = op.args[0] + oplist = [] + if unsigned: + opname = 'cast_uint_to_longlong' + else: + opname = 'cast_int_to_longlong' + op1 = SpaceOperation(opname, [v], op.result) + op2 = self.rewrite_operation(op1) + return oplist + [op2] + else: + return self.force_cast_without_longlong(op.args[0], op.result) + + def force_cast_without_longlong(self, v_arg, v_result): from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof from pypy.rlib.rarithmetic import intmask - assert not self._is_gc(op.args[0]) - size2, unsigned2 = size_and_sign(op.result.concretetype) - if size2 >= sizeof(lltype.Signed): + size2, unsigned2 = size_and_sign(v_result.concretetype) + assert size2 <= sizeof(lltype.Signed) + if size2 == sizeof(lltype.Signed): return # the target type is LONG or ULONG - size1, unsigned1 = size_and_sign(op.args[0].concretetype) + size1, unsigned1 = size_and_sign(v_arg.concretetype) + assert size1 <= sizeof(lltype.Signed) # def bounds(size, unsigned): if unsigned: @@ -784,20 +829,19 @@ return # the target type includes the source range # result = [] - v1 = op.args[0] if min2: c_min2 = Constant(min2, lltype.Signed) - v2 = Variable(); v2.concretetype = lltype.Signed - result.append(SpaceOperation('int_sub', [v1, c_min2], v2)) + v2 = varoftype(lltype.Signed) + result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2)) else: - v2 = v1 + v2 = v_arg c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed) - v3 = Variable(); v3.concretetype = lltype.Signed + v3 = varoftype(lltype.Signed) result.append(SpaceOperation('int_and', [v2, c_mask], v3)) if min2: - result.append(SpaceOperation('int_add', [v3, c_min2], op.result)) + result.append(SpaceOperation('int_add', [v3, c_min2], v_result)) else: - result[-1].result = op.result + result[-1].result = v_result return result def rewrite_op_direct_ptradd(self, op): @@ -890,30 +934,7 @@ rewrite_op_ullong_is_true = rewrite_op_llong_is_true def rewrite_op_cast_primitive(self, op): - fromll = longlong.is_longlong(op.args[0].concretetype) - toll = longlong.is_longlong(op.result.concretetype) - if fromll != toll: - args = op.args - if fromll: - opname = 'truncate_longlong_to_int' - RESULT = lltype.Signed - else: - from pypy.rpython.lltypesystem import rffi - if rffi.cast(op.args[0].concretetype, -1) < 0: - opname = 'cast_int_to_longlong' - else: - opname = 'cast_uint_to_longlong' - RESULT = lltype.SignedLongLong - v = varoftype(RESULT) - op1 = SpaceOperation(opname, args, v) - op2 = self.rewrite_operation(op1) - # - # force a renaming to put the correct result in place, even though - # it might be slightly mistyped (e.g. Signed versus Unsigned) - assert op2.result is v - op2.result = op.result - # - return op2 + return self.rewrite_op_force_cast(op) # ---------- # Renames, from the _old opname to the _new one. @@ -1247,7 +1268,7 @@ calldescr = self.callcontrol.getcalldescr(op, oopspecindex, extraeffect) if extraeffect is not None: - assert (type(calldescr) is str # for tests + assert (is_test_calldescr(calldescr) # for tests or calldescr.get_extra_info().extraeffect == extraeffect) if isinstance(op.args[0].value, str): pass # for tests only @@ -1408,6 +1429,9 @@ return "using virtualizable array in illegal way in %r" % ( self.args[0],) +def is_test_calldescr(calldescr): + return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False) + def _with_prefix(prefix): result = {} for name in dir(Transformer): diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -3,6 +3,7 @@ from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register from pypy.jit.codewriter.format import assert_format +from pypy.jit.codewriter import longlong from pypy.jit.metainterp.history import AbstractDescr from pypy.rpython.lltypesystem import lltype, rclass, rstr from pypy.objspace.flow.model import SpaceOperation, Variable, Constant @@ -30,6 +31,9 @@ 'float': FakeRegAlloc()} class FakeDescr(AbstractDescr): + _for_tests_only = True + def __init__(self, oopspecindex=None): + self.oopspecindex = oopspecindex def __repr__(self): return '' def as_vtable_size_descr(self): @@ -55,19 +59,24 @@ def arraydescrof(self, ARRAY): return FakeDescr() +class FakeCallInfoCollection: + def add(self, *args): + pass + class FakeCallControl: _descr_cannot_raise = FakeDescr() + callinfocollection = FakeCallInfoCollection() def guess_call_kind(self, op): return 'residual' - def getcalldescr(self, op): + def getcalldescr(self, op, oopspecindex=None, extraeffect=None): try: if 'cannot_raise' in op.args[0].value._obj.graph.name: return self._descr_cannot_raise except AttributeError: pass - return FakeDescr() + return FakeDescr(oopspecindex) def calldescr_canraise(self, calldescr): - return calldescr is not self._descr_cannot_raise + return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None def get_vinfo(self, VTYPEPTR): return None @@ -734,7 +743,9 @@ def test_force_cast(self): from pypy.rpython.lltypesystem import rffi - + # NB: we don't need to test for INT here, the logic in jtransform is + # general enough so that if we have the below cases it should + # generalize also to INT for FROM, TO, expected in [ (rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""), (rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"), @@ -797,14 +808,44 @@ expected = [s.strip() for s in expected.splitlines()] check_force_cast(FROM, TO, expected, 42) check_force_cast(FROM, TO, expected, -42) - expected.append('int_return %i' + str(len(expected))) - expected = '\n'.join(expected) + returnvar = "%i" + str(len(expected)) + expected.append('int_return ' + returnvar) + expectedstr = '\n'.join(expected) # def f(n): return rffi.cast(TO, n) - self.encoding_test(f, [rffi.cast(FROM, 42)], expected, + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, transform=True) + if not longlong.is_64_bit: + if FROM in (rffi.LONG, rffi.ULONG): + if FROM == rffi.LONG: + FROM = rffi.LONGLONG + else: + FROM = rffi.ULONGLONG + expected.insert(0, + "residual_call_irf_i $<* fn llong_to_int>, , I[], R[], F[%f0] -> %i0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + elif TO in (rffi.LONG, rffi.ULONG): + if TO == rffi.LONG: + TO = rffi.LONGLONG + else: + TO = rffi.ULONGLONG + if rffi.cast(FROM, -1) < 0: + fnname = "llong_from_int" + else: + fnname = "llong_from_uint" + expected.pop() # remove int_return + expected.append( + "residual_call_irf_f $<* fn %s>, , I[%s], R[], F[] -> %%f0" + % (fnname, returnvar)) + expected.append("float_return %f0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + def test_force_cast_pointer(self): from pypy.rpython.lltypesystem import rffi def h(p): @@ -822,6 +863,15 @@ int_return %i2 """, transform=True) + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py --- a/pypy/jit/codewriter/test/test_longlong.py +++ b/pypy/jit/codewriter/test/test_longlong.py @@ -37,7 +37,7 @@ class TestLongLong: def setup_class(cls): - if sys.maxint > 2147483647: + if longlong.is_64_bit: py.test.skip("only for 32-bit platforms") def do_check(self, opname, oopspecindex, ARGS, RESULT): @@ -46,6 +46,8 @@ op = SpaceOperation(opname, vlist, v_result) tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) op1 = tr.rewrite_operation(op) + if isinstance(op1, list): + [op1] = op1 # def is_llf(TYPE): return (TYPE == lltype.SignedLongLong or @@ -196,6 +198,23 @@ for T2 in [lltype.Signed, lltype.Unsigned]: self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT, [T1], T2) + self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT, + [T1], T2) + if T2 == lltype.Signed: + expected = EffectInfo.OS_LLONG_FROM_INT + else: + expected = EffectInfo.OS_LLONG_FROM_UINT + self.do_check('cast_primitive', expected, [T2], T1) + self.do_check('force_cast', expected, [T2], T1) + # + for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + vlist = [varoftype(T1)] + v_result = varoftype(T2) + op = SpaceOperation('force_cast', vlist, v_result) + tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) + op1 = tr.rewrite_operation(op) + assert op1 is None def test_constants(self): for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]: diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt, OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit @@ -7,7 +7,6 @@ from pypy.tool.sourcetools import func_with_new_name import math - def dummy1(v): assert isinstance(v, float) return v @@ -88,23 +87,15 @@ def _binop_impl(function): signature = Signature() def impl(self, space, w_other): + w_other = convert_to_array(space, w_other) new_sig = self.signature.transition(signature) - if isinstance(w_other, BaseArray): - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - else: - w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) + res = Call2( + function, + self, + w_other, + new_sig.transition(w_other.signature) + ) + w_other.invalidates.append(res) self.invalidates.append(res) return space.wrap(res) return func_with_new_name(impl, "binop_%s_impl" % function.__name__) @@ -272,6 +263,16 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) +def convert_to_array (space, w_obj): + if isinstance(w_obj, BaseArray): + return w_obj + elif space.issequence_w(w_obj): + # Convert to array. + return new_numarray(space, w_obj) + else: + # If it's a scalar + return FloatWrapper(space.float_w(w_obj)) + class FloatWrapper(BaseArray): """ Intermediate class representing a float literal. @@ -478,14 +479,17 @@ def __del__(self): lltype.free(self.storage, flavor='raw') -def descr_new_numarray(space, w_type, w_size_or_iterable): +def new_numarray(space, w_size_or_iterable): l = space.listview(w_size_or_iterable) arr = SingleDimArray(len(l)) i = 0 for w_elem in l: arr.storage[i] = space.float_w(space.float(w_elem)) i += 1 - return space.wrap(arr) + return arr + +def descr_new_numarray(space, w_type, w_size_or_iterable): + return space.wrap(new_numarray(space, w_size_or_iterable)) @unwrap_spec(size=int) def zeros(space, size): diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,31 +1,35 @@ import math from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature +from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name - def ufunc(func): signature = Signature() def impl(space, w_obj): - if isinstance(w_obj, BaseArray): - w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) - w_obj.invalidates.append(w_res) + if space.issequence_w(w_obj): + w_obj_arr = convert_to_array(space, w_obj) + w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) + w_obj_arr.invalidates.append(w_res) return w_res - return space.wrap(func(space.float_w(w_obj))) + else: + return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): - if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): - new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) - w_res = Call2(func, w_lhs, w_rhs, new_sig) - w_lhs.invalidates.append(w_res) - w_rhs.invalidates.append(w_res) + if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): + w_lhs_arr = convert_to_array(space, w_lhs) + w_rhs_arr = convert_to_array(space, w_rhs) + new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature) + w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig) + w_lhs_arr.invalidates.append(w_res) + w_rhs_arr.invalidates.append(w_res) return w_res - return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) + else: + return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @ufunc diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -1,12 +1,10 @@ from pypy.conftest import gettestobjspace from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper - class BaseNumpyAppTest(object): def setup_class(cls): cls.space = gettestobjspace(usemodules=('micronumpy',)) - class TestSignature(object): def test_binop_signature(self, space): ar = SingleDimArray(10) @@ -26,4 +24,4 @@ v3 = ar.descr_add(space, v1) v4 = ar.descr_add(space, v2) - assert v3.signature is v4.signature \ No newline at end of file + assert v3.signature is v4.signature diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -97,6 +97,15 @@ for i in range(5): assert b[i] == i + 5 + def test_add_list(self): + from numpy import array + a = array(range(5)) + b = list(reversed(range(5))) + c = a + b + assert isinstance(c, array) + for i in range(5): + assert c[i] == 4 + def test_subtract(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -10,6 +10,40 @@ assert sign(-0.0) == 0.0 assert minimum(2.0, 3.0) == 2.0 + def test_sequence(self): + from numpy import array, negative, minimum + a = array(range(3)) + b = [2.0, 1.0, 0.0] + c = 1.0 + b_neg = negative(b) + assert isinstance(b_neg, array) + for i in range(3): + assert b_neg[i] == -b[i] + min_a_b = minimum(a, b) + assert isinstance(min_a_b, array) + for i in range(3): + assert min_a_b[i] == min(a[i], b[i]) + min_b_a = minimum(b, a) + assert isinstance(min_b_a, array) + for i in range(3): + assert min_b_a[i] == min(a[i], b[i]) + min_a_c = minimum(a, c) + assert isinstance(min_a_c, array) + for i in range(3): + assert min_a_c[i] == min(a[i], c) + min_c_a = minimum(c, a) + assert isinstance(min_c_a, array) + for i in range(3): + assert min_c_a[i] == min(a[i], c) + min_b_c = minimum(b, c) + assert isinstance(min_b_c, array) + for i in range(3): + assert min_b_c[i] == min(b[i], c) + min_c_b = minimum(c, b) + assert isinstance(min_c_b, array) + for i in range(3): + assert min_c_b[i] == min(b[i], c) + def test_negative(self): from numpy import array, negative diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -8,9 +8,16 @@ class FakeSpace(object): w_ValueError = None + + def issequence_w(self, w_obj): + return True + @specialize.argtype(1) - def wrap(self, v): - return v + def wrap(self, w_obj): + return w_obj + + def float_w(self, w_obj): + return float(w_obj) class TestNumpyJIt(LLJitMixin): def setup_class(cls): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -134,13 +134,12 @@ def test_truncate_python_longs(self): - py.test.skip("fixme") f = dll._testfunc_i_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] f.restype = c_int x = sys.maxint * 2 - result = f(0, 0, x, 0, 0, 0) - assert result == 2 + result = f(x, x, x, x, 0, 0) + assert result == -8 def test_floatresult(self): diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -172,17 +172,6 @@ assert max_n >= 0 ITEM = A.OF ctypes_item = get_ctypes_type(ITEM, delayed_builders) - # Python 2.5 ctypes can raise OverflowError on 64-bit builds - for n in [sys.maxint, 2**31]: - MAX_SIZE = n/64 - try: - PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item) - except OverflowError, e: - pass - else: - break - else: - raise e class CArray(ctypes.Structure): if not A._hints.get('nolength'): @@ -191,6 +180,7 @@ else: _fields_ = [('items', max_n * ctypes_item)] + @classmethod def _malloc(cls, n=None): if not isinstance(n, int): raise TypeError, "array length must be an int" @@ -199,10 +189,29 @@ if hasattr(bigarray, 'length'): bigarray.length = n return bigarray - _malloc = classmethod(_malloc) + + _ptrtype = None + + @classmethod + def _get_ptrtype(cls): + if cls._ptrtype: + return cls._ptrtype + # ctypes can raise OverflowError on 64-bit builds + for n in [sys.maxint, 2**31]: + cls.MAX_SIZE = n/64 + try: + cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item) + except OverflowError, e: + pass + else: + break + else: + raise e + return cls._ptrtype def _indexable(self, index): - assert index + 1 < MAX_SIZE + PtrType = self._get_ptrtype() + assert index + 1 < self.MAX_SIZE p = ctypes.cast(ctypes.pointer(self.items), PtrType) return p.contents diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -671,7 +671,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_arrayofstruct(self): - S1 = lltype.Struct('S1', ('x', lltype.Signed)) + S1 = lltype.Struct('S2', ('x', lltype.Signed)) A = lltype.Array(S1, hints={'nolength': True}) a = lltype.malloc(A, 5, flavor='raw') a[0].x = 100 From noreply at buildbot.pypy.org Wed Jul 13 14:16:54 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 14:16:54 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Kill that approach too, and just call enqueue_for_destruction() Message-ID: <20110713121654.356068291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45540:3c9c2a6e7599 Date: 2011-07-12 17:46 +0200 http://bitbucket.org/pypy/pypy/changeset/3c9c2a6e7599/ Log: Kill that approach too, and just call enqueue_for_destruction() in all cases, at least if self.stream is not None. Works even if direct_close() calls random Python code, like in the bz2 module. diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -33,7 +33,6 @@ encoding = None errors = None fd = -1 - streamerror_upon_closing = None newlines = 0 # Updated when the stream is closed @@ -44,18 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: - self.streamerror_upon_closing = e - self.enqueue_for_destruction(self.space, W_File.report_streamerror, - 'close() method of ') - - def report_streamerror(self): - assert isinstance(self, W_File) - operr = wrap_streamerror(self.space, self.streamerror_upon_closing, - self.w_name) - raise operr + operr = wrap_streamerror(self.space, e, self.w_name) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd From noreply at buildbot.pypy.org Wed Jul 13 14:16:55 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 14:16:55 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Fix on top of CPython 2.6 (it worked on top of CPython 2.5) Message-ID: <20110713121655.632978291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45541:69a6931f84e2 Date: 2011-07-12 18:11 +0200 http://bitbucket.org/pypy/pypy/changeset/69a6931f84e2/ Log: Fix on top of CPython 2.6 (it worked on top of CPython 2.5) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -184,9 +184,13 @@ def test_destructor(self): space = self.space class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space def __del__(self): space.call_method(w_seen, 'append', space.wrap(1)) class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space def __del__(self): self.enqueue_for_destruction(space, W_Level2.destructormeth, 'FOO ') @@ -200,12 +204,12 @@ __new__ = typedef.generic_new_descr(W_Level2)) # w_seen = space.newlist([]) - W_Level1() + W_Level1(space) gc.collect(); gc.collect() assert space.unwrap(w_seen) == [1] # w_seen = space.newlist([]) - W_Level2() + W_Level2(space) gc.collect(); gc.collect() assert space.str_w(space.repr(w_seen)) == "[]" # not called yet ec = space.getexecutioncontext() From noreply at buildbot.pypy.org Wed Jul 13 14:16:56 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 14:16:56 +0200 (CEST) Subject: [pypy-commit] pypy refactor-wrapped-del: Close branch to merge. Message-ID: <20110713121656.88F578291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: refactor-wrapped-del Changeset: r45542:4bdfafab9f2b Date: 2011-07-13 14:14 +0200 http://bitbucket.org/pypy/pypy/changeset/4bdfafab9f2b/ Log: Close branch to merge. From noreply at buildbot.pypy.org Wed Jul 13 14:16:57 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 14:16:57 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge refactor-wrapped-del: clean up and generalize the Message-ID: <20110713121657.DD5678291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45543:f9a24c80bd03 Date: 2011-07-13 14:16 +0200 http://bitbucket.org/pypy/pypy/changeset/f9a24c80bd03/ Log: Merge refactor-wrapped-del: clean up and generalize the way our W_Root's __del__ works. They should not do too much, which is now checked during translation, but they can call self.enqueue_for_destruction() by passing them a callback, possibly several times. The callbacks are invoked at a later safe point. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) - if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') + if parent_destructor is not None: + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -858,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -43,11 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -57,6 +57,11 @@ def __del__(self): self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + + def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -10,7 +10,7 @@ class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 @@ -23,8 +23,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,11 +120,8 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: - w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) + assert isinstance(w_self, W_WeakrefBase) + w_self.space.call_function(w_self.w_callable, w_self) def descr__repr__(self, space): w_obj = self.dereference() diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -431,12 +431,17 @@ return None assert isinstance(lifeline, WeakrefLifeline) return lifeline + getweakref._cannot_really_call_random_things_ = True def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline - assert (isinstance(weakreflifeline, WeakrefLifeline) or - weakreflifeline is None) + assert isinstance(weakreflifeline, WeakrefLifeline) self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + setweakref._cannot_really_call_random_things_ = True + + def delweakref(self): + self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + delweakref._cannot_really_call_random_things_ = True class ObjectMixin(object): _mixin_ = True diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -36,6 +36,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None class W_SetObject(W_BaseSetObject): from pypy.objspace.std.settype import set_typedef as typedef diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -171,7 +171,7 @@ obj = c.instantiate() assert obj.getweakref() is None obj.setweakref(space, lifeline1) - obj.setweakref(space, None) + obj.delweakref() diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -532,6 +532,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None # ____________________________________________________________ # Initialization of type objects diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -482,6 +482,13 @@ key[2:]) cache[key] = s_value + # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass) + try: + graph = self.bookkeeper.position_key[0] + graph.func._dont_reach_me_in_del_ = True + except (TypeError, AttributeError): + pass + return annmodel.s_None def annotate_hooks(self, **kwds_s): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -83,6 +83,9 @@ t, rtyper, fngraph = self.gengraph(fn, [int]) + # added by compute_result_annotation() + assert fn._dont_reach_me_in_del_ == True + def getargs(func): for graph in t.graphs: if getattr(graph, 'func', None) is func: diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py --- a/pypy/rpython/lltypesystem/rclass.py +++ b/pypy/rpython/lltypesystem/rclass.py @@ -400,6 +400,7 @@ assert len(s_func.descriptions) == 1 funcdesc, = s_func.descriptions graph = funcdesc.getuniquegraph() + self.check_graph_of_del_does_not_call_too_much(graph) FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void) destrptr = functionptr(FUNCTYPE, graph.name, graph=graph, diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -374,6 +374,43 @@ def can_ll_be_null(self, s_value): return s_value.can_be_none() + def check_graph_of_del_does_not_call_too_much(self, graph): + # RPython-level __del__() methods should not do "too much". + # In the PyPy Python interpreter, they usually do simple things + # like file.__del__() closing the file descriptor; or if they + # want to do more like call an app-level __del__() method, they + # enqueue the object instead, and the actual call is done later. + # + # Here, as a quick way to check "not doing too much", we check + # that from no RPython-level __del__() method we can reach a + # JitDriver. + # + # XXX wrong complexity, but good enough because the set of + # reachable graphs should be small + callgraph = self.rtyper.annotator.translator.callgraph.values() + seen = {graph: None} + while True: + oldlength = len(seen) + for caller, callee in callgraph: + if caller in seen and callee not in seen: + func = getattr(callee, 'func', None) + if getattr(func, '_dont_reach_me_in_del_', False): + lst = [str(callee)] + g = caller + while g: + lst.append(str(g)) + g = seen.get(g) + lst.append('') + raise TyperError("the RPython-level __del__() method " + "in %r calls:%s" % ( + graph, '\n\t'.join(lst[::-1]))) + if getattr(func, '_cannot_really_call_random_things_', + False): + continue + seen[callee] = caller + if len(seen) == oldlength: + break + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops, classcallhop=None): diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -7,6 +7,7 @@ from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.rpython.error import TyperError from pypy.objspace.flow.model import summary class EmptyBase(object): @@ -1021,7 +1022,25 @@ assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] assert destrptra is not None assert destrptrb is not None - + + def test_del_forbidden(self): + class A(object): + def __del__(self): + self.foo() + def foo(self): + self.bar() + def bar(self): + pass + bar._dont_reach_me_in_del_ = True + def f(): + a = A() + a.foo() + a.bar() + t = TranslationContext() + t.buildannotator().build_types(f, []) + e = py.test.raises(TyperError, t.buildrtyper().specialize) + print e.value + def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int class FooBar(object): From noreply at buildbot.pypy.org Wed Jul 13 14:22:18 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 13 Jul 2011 14:22:18 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (cfbolz, wlav) fast path implementations and removal of jit.dont_look_inside Message-ID: <20110713122218.31B308291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45544:9a2e5320fd1e Date: 2011-07-13 05:15 -0700 http://bitbucket.org/pypy/pypy/changeset/9a2e5320fd1e/ Log: (cfbolz, wlav) fast path implementations and removal of jit.dont_look_inside diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -118,7 +118,6 @@ arr = getattr(cache, 'array_' + self.typecode) return arr.fromaddress(space, address[0], self.size) - @jit.dont_look_inside def to_memory(self, space, w_obj, w_value, offset): # copy only the pointer value rawobject = get_rawobject(space, w_obj) @@ -146,29 +145,33 @@ class BoolConverter(TypeConverter): _immutable = True - libffitype = libffi.types.sint # TODO: probably incorrect + libffitype = libffi.types.schar - def convert_argument(self, space, w_obj): + def _unwrap_object(self, space, w_obj): arg = space.c_int_w(w_obj) if arg != False and arg != True: raise OperationError(space.w_TypeError, space.wrap("boolean value should be bool, or integer 1 or 0")) + return arg + + def convert_argument(self, space, w_obj): + arg = self._unwrap_object(space, w_obj) x = lltype.malloc(rffi.LONGP.TO, 1, flavor='raw') x[0] = arg return rffi.cast(rffi.VOIDP, x) + def convert_argument_libffi(self, space, w_obj, argchain): + argchain.arg(self._unwrap_object(space, w_obj)) + def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) if address[0] == '\x01': - return space.wrap(True) - return space.wrap(False) + return space.w_True + return space.w_False def to_memory(self, space, w_obj, w_value, offset): address = self._get_raw_address(space, w_obj, offset) - arg = space.c_int_w(w_value) - if arg != False and arg != True: - raise OperationError(space.w_TypeError, - space.wrap("boolean value should be bool, or integer 1 or 0")) + arg = self._unwrap_object(space, w_value) if arg: address[0] = '\x01' else: @@ -178,7 +181,7 @@ _immutable = True libffitype = libffi.types.schar - def _from_space(self, space, w_value): + def _unwrap_object(self, space, w_value): # allow int to pass to char and make sure that str is of length 1 if space.isinstance_w(w_value, space.w_int): ival = space.c_int_w(w_value) @@ -196,17 +199,20 @@ return value[0] # turn it into a "char" to the annotator def convert_argument(self, space, w_obj): - arg = self._from_space(space, w_obj) + arg = self._unwrap_object(space, w_obj) x = rffi.str2charp(arg) return rffi.cast(rffi.VOIDP, x) + def convert_argument_libffi(self, space, w_obj, argchain): + argchain.arg(self._unwrap_object(space, w_obj)) + def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) return space.wrap(address[0]) def to_memory(self, space, w_obj, w_value, offset): address = self._get_raw_address(space, w_obj, offset) - address[0] = self._from_space(space, w_value) + address[0] = self._unwrap_object(space, w_value) class IntConverter(TypeConverter): _immutable = True @@ -247,6 +253,9 @@ x[0] = arg return rffi.cast(rffi.VOIDP, x) + def convert_argument_libffi(self, space, w_obj, argchain): + argchain.arg(self._unwrap_object(space, w_obj)) + def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) ulongptr = rffi.cast(rffi.UINTP, address) @@ -296,6 +305,9 @@ x[0] = arg return rffi.cast(rffi.VOIDP, x) + def convert_argument_libffi(self, space, w_obj, argchain): + argchain.arg(self._unwrap_object(space, w_obj)) + def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) ulongptr = rffi.cast(rffi.ULONGP, address) @@ -306,10 +318,22 @@ ulongptr = rffi.cast(rffi.ULONGP, address) ulongptr[0] = self._unwrap_object(space, w_value) -class ShortConverter(LongConverter): +class ShortConverter(TypeConverter): _immutable = True libffitype = libffi.types.sshort + def _unwrap_object(self, space, w_obj): + return rffi.cast(rffi.SHORT, space.int_w(w_obj)) + + def convert_argument(self, space, w_obj): + arg = self._unwrap_object(space, w_obj) + x = lltype.malloc(rffi.SHORTP.TO, 1, flavor='raw') + x[0] = arg + return rffi.cast(rffi.VOIDP, x) + + def convert_argument_libffi(self, space, w_obj, argchain): + argchain.arg(self._unwrap_object(space, w_obj)) + def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) shortptr = rffi.cast(rffi.SHORTP, address) @@ -318,7 +342,7 @@ def to_memory(self, space, w_obj, w_value, offset): address = self._get_raw_address(space, w_obj, offset) shortptr = rffi.cast(rffi.SHORTP, address) - shortptr[0] = rffi.cast(rffi.SHORT, self._unwrap_object(space, w_value)) + shortptr[0] = self._unwrap_object(space, w_value) class FloatConverter(TypeConverter): _immutable = True @@ -332,6 +356,9 @@ x[0] = self._unwrap_object(space, w_obj) return rffi.cast(rffi.VOIDP, x) + def convert_argument_libffi(self, space, w_obj, argchain): + argchain.arg_singlefloat(self._unwrap_object(space, w_obj)) + def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) floatptr = rffi.cast(rffi.FLOATP, address) @@ -451,12 +478,7 @@ def __init__(self, space, cpptype): self.cpptype = cpptype - # TODO: factor out the direct_ptradd into a smaller function (so that the - # JIT can look into the rest of the code), or better, let the JIT - # see it (either by teaching it direct_ptradd, or by using a - # different style like casts between addresses and integers) - @jit.dont_look_inside - def convert_argument(self, space, w_obj): + def _unwrap_object(self, space, w_obj): from pypy.module.cppyy.interp_cppyy import W_CPPInstance w_cppinstance = space.findattr(w_obj, space.wrap("_cppinstance")) if w_cppinstance: @@ -473,6 +495,12 @@ space.type(w_obj).getname(space, "?"), self.cpptype.name))) + def convert_argument(self, space, w_obj): + return self._unwrap_object(space, w_obj) + + def convert_argument_libffi(self, space, w_obj, argchain): + argchain.arg(self._unwrap_object(space, w_obj)) + def free_argument(self, arg): pass diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -40,6 +40,7 @@ class VoidExecutor(FunctionExecutor): _immutable_ = True + libffitype = libffi.types.void def execute(self, space, func, cppthis, num_args, args): capi.c_call_v(func.cpptype.handle, func.method_index, cppthis, num_args, args) @@ -52,18 +53,28 @@ class BoolExecutor(FunctionExecutor): _immutable_ = True + libffitype = libffi.types.schar def execute(self, space, func, cppthis, num_args, args): result = capi.c_call_b(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.CHAR) + return space.wrap(result) + class CharExecutor(FunctionExecutor): _immutable_ = True + libffitype = libffi.types.schar def execute(self, space, func, cppthis, num_args, args): result = capi.c_call_c(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.CHAR) + return space.wrap(result) + class ShortExecutor(FunctionExecutor): _immutable_ = True libffitype = libffi.types.sshort @@ -72,6 +83,10 @@ result = capi.c_call_h(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.SHORT) + return space.wrap(result) + class IntExecutor(FunctionExecutor): _immutable_ = True libffitype = libffi.types.sint @@ -83,9 +98,9 @@ result = capi.c_call_i(func.cpptype.handle, func.method_index, cppthis, num_args, args) return self._wrap_result(space, result) -# TODO: check whether the following is correct (return type cast): -# def execute_libffi(self, space, libffifunc, argchain): -# return space.wrap(libffifunc.call(argchain, rffi.INT)) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.INT) + return space.wrap(result) class UnsignedIntExecutor(FunctionExecutor): _immutable_ = True @@ -98,6 +113,10 @@ result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) return self._wrap_result(space, result) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.UINT) + return space.wrap(result) + class LongExecutor(FunctionExecutor): _immutable_ = True libffitype = libffi.types.slong @@ -110,7 +129,8 @@ return self._wrap_result(space, result) def execute_libffi(self, space, libffifunc, argchain): - return space.wrap(libffifunc.call(argchain, lltype.Signed)) + result = libffifunc.call(argchain, rffi.LONG) + return space.wrap(result) class UnsignedLongExecutor(LongExecutor): _immutable_ = True @@ -119,27 +139,46 @@ def _wrap_result(self, space, result): return space.wrap(rffi.cast(rffi.ULONG, result)) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.ULONG) + return space.wrap(result) + class ConstIntRefExecutor(LongExecutor): _immutable_ = True + libffitype = libffi.types.pointer def _wrap_result(self, space, result): intptr = rffi.cast(rffi.INTP, result) return space.wrap(intptr[0]) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.INTP) + return space.wrap(result[0]) + class ConstLongRefExecutor(LongExecutor): _immutable_ = True + libffitype = libffi.types.pointer def _wrap_result(self, space, result): longptr = rffi.cast(rffi.LONGP, result) return space.wrap(longptr[0]) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.LONGP) + return space.wrap(result[0]) + class FloatExecutor(FunctionExecutor): _immutable_ = True + libffitype = libffi.types.float def execute(self, space, func, cppthis, num_args, args): result = capi.c_call_f(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.FLOAT) + return space.wrap(result) + class DoubleExecutor(FunctionExecutor): _immutable_ = True libffitype = libffi.types.double @@ -149,11 +188,13 @@ return space.wrap(result) def execute_libffi(self, space, libffifunc, argchain): - return space.wrap(libffifunc.call(argchain, rffi.DOUBLE)) + result = libffifunc.call(argchain, rffi.DOUBLE) + return space.wrap(result) class CStringExecutor(FunctionExecutor): _immutable_ = True + def execute(self, space, func, cppthis, num_args, args): lresult = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) ccpresult = rffi.cast(rffi.CCHARP, lresult) @@ -192,6 +233,8 @@ class InstancePtrExecutor(FunctionExecutor): _immutable_ = True + libffitype = libffi.types.pointer + def __init__(self, space, name, cpptype): FunctionExecutor.__init__(self, space, name, cpptype) self.cpptype = cpptype @@ -202,6 +245,11 @@ ptr_result = rffi.cast(rffi.VOIDP, long_result) return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) + def execute_libffi(self, space, libffifunc, argchain): + result = libffifunc.call(argchain, rffi.VOIDP) + return interp_cppyy.W_CPPInstance(space, self.cpptype, result, False) + + class InstanceExecutor(InstancePtrExecutor): _immutable_ = True From noreply at buildbot.pypy.org Wed Jul 13 14:22:19 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 13 Jul 2011 14:22:19 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: add operatorsDict.so to makefile Message-ID: <20110713122219.59ED28291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45545:e60e23c56a31 Date: 2011-07-13 05:17 -0700 http://bitbucket.org/pypy/pypy/changeset/e60e23c56a31/ Log: add operatorsDict.so to makefile diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile --- a/pypy/module/cppyy/test/Makefile +++ b/pypy/module/cppyy/test/Makefile @@ -1,4 +1,4 @@ -all: example01Dict.so datatypesDict.so advancedcppDict.so stltypesDict.so +all: example01Dict.so datatypesDict.so advancedcppDict.so stltypesDict.so operatorsDict.so ROOTSYS := ${ROOTSYS} @@ -36,3 +36,8 @@ stltypesDict.so: stltypes.cxx stltypes.h stltypes.xml $(genreflex) stltypes.h --selection=stltypes.xml g++ -o $@ stltypes_rflx.cpp stltypes.cxx -shared -lReflex $(cppflags) $(cppflags2) + +operatorsDict.so: operators.cxx operators.h + $(genreflex) operators.h + g++ -o $@ operators_rflx.cpp operators.cxx -shared -lReflex $(cppflags) $(cppflags2) + From noreply at buildbot.pypy.org Wed Jul 13 14:22:20 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 13 Jul 2011 14:22:20 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (cfbolz, wlav) do not free returned char ptrs Message-ID: <20110713122220.8AA6A8291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45546:1d7bc21fae62 Date: 2011-07-13 05:22 -0700 http://bitbucket.org/pypy/pypy/changeset/1d7bc21fae62/ Log: (cfbolz, wlav) do not free returned char ptrs diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -198,7 +198,7 @@ def execute(self, space, func, cppthis, num_args, args): lresult = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) ccpresult = rffi.cast(rffi.CCHARP, lresult) - result = capi.charp2str_free(ccpresult) + result = rffi.charp2str(ccpresult) # TODO: make it a choice to free return space.wrap(result) diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -78,12 +78,12 @@ res = t.invoke(t.get_overload("staticAtoi"), "1") assert res == 1 - res = t.invoke(t.get_overload("staticStrcpy"), "aap") + res = t.invoke(t.get_overload("staticStrcpy"), "aap") # TODO: this leaks assert res == "aap" - res = t.invoke(t.get_overload("staticStrcpy"), u"aap") + res = t.invoke(t.get_overload("staticStrcpy"), u"aap") # TODO: this leaks assert res == "aap" - raises(TypeError, 't.invoke(t.get_overload("staticStrcpy"), 1.)') + raises(TypeError, 't.invoke(t.get_overload("staticStrcpy"), 1.)') # TODO: this leaks def test_example01method_int(self): """Test passing of a int, returning of a int, and memory cleanup, on @@ -170,9 +170,9 @@ e = t.construct(42) res = e.invoke(t.get_overload("addDataToAtoi"), "13") assert res == 55 - res = e.invoke(t.get_overload("addToStringValue"), "12") + res = e.invoke(t.get_overload("addToStringValue"), "12") # TODO: this leaks assert res == "54" - res = e.invoke(t.get_overload("addToStringValue"), "-12") + res = e.invoke(t.get_overload("addToStringValue"), "-12") # TODO: this leaks assert res == "30" e.destruct() assert t.invoke(t.get_overload("getCount")) == 0 diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py --- a/pypy/module/cppyy/test/test_pythonify.py +++ b/pypy/module/cppyy/test/test_pythonify.py @@ -67,13 +67,13 @@ res = example01_class.staticAtoi("1") assert res == 1 - res = example01_class.staticStrcpy("aap") + res = example01_class.staticStrcpy("aap") # TODO: this leaks assert res == "aap" - res = example01_class.staticStrcpy(u"aap") + res = example01_class.staticStrcpy(u"aap") # TODO: this leaks assert res == "aap" - raises(TypeError, 'example01_class.staticStrcpy(1.)') + raises(TypeError, 'example01_class.staticStrcpy(1.)') # TODO: this leaks def test04_constructing_and_calling(self): """Test object and method calls.""" @@ -115,9 +115,9 @@ res = instance.addDataToAtoi("13") assert res == 55 - res = instance.addToStringValue("12") + res = instance.addToStringValue("12") # TODO: this leaks assert res == "54" - res = instance.addToStringValue("-12") + res = instance.addToStringValue("-12") # TODO: this leaks assert res == "30" res = instance.staticAddOneToInt(1L) From noreply at buildbot.pypy.org Wed Jul 13 14:35:48 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 14:35:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix the test on 32-bit. Message-ID: <20110713123548.236CC8291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45547:85d2142b7446 Date: 2011-07-13 14:29 +0200 http://bitbucket.org/pypy/pypy/changeset/85d2142b7446/ Log: Fix the test on 32-bit. diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): From noreply at buildbot.pypy.org Wed Jul 13 14:35:49 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 14:35:49 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix this other test on 64-bit. Message-ID: <20110713123549.4F5688291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45548:6ffb5166d42c Date: 2011-07-13 14:35 +0200 http://bitbucket.org/pypy/pypy/changeset/6ffb5166d42c/ Log: Fix this other test on 64-bit. diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -49,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -63,10 +63,15 @@ expected = "\xE8" + struct.pack(' Author: David Schneider Branch: arm-backend-2 Changeset: r45549:37b0e249c32f Date: 2011-07-13 14:53 +0200 http://bitbucket.org/pypy/pypy/changeset/37b0e249c32f/ Log: implement call_release_gil diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -121,11 +121,34 @@ ll_new_unicode) if gc_ll_descr.get_malloc_slowpath_addr is not None: self._build_malloc_slowpath() + if gc_ll_descr.gcrootmap: + self._build_release_gil(gc_ll_descr.gcrootmap) self.memcpy_addr = self.cpu.cast_ptr_to_int(memcpy_fn) self._exit_code_addr = self._gen_exit_path() self._leave_jitted_hook_save_exc = self._gen_leave_jitted_hook_code(True) self._leave_jitted_hook = self._gen_leave_jitted_hook_code(False) + @staticmethod + def _release_gil_shadowstack(): + before = rffi.aroundstate.before + if before: + before() + + @staticmethod + def _reacquire_gil_shadowstack(): + after = rffi.aroundstate.after + if after: + after() + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) + def _build_release_gil(self, gcrootmap): + assert gcrootmap.is_shadow_stack + releasegil_func = llhelper(self._NOARG_FUNC, + self._release_gil_shadowstack) + reacqgil_func = llhelper(self._NOARG_FUNC, + self._reacquire_gil_shadowstack) + self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) + self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + def setup_failure_recovery(self): @rgc.no_collect @@ -758,6 +781,8 @@ opnum = operations[i + 1].getopnum() assert opnum == rop.GUARD_OVERFLOW or opnum == rop.GUARD_NO_OVERFLOW return True + if num == rop.CALL_RELEASE_GIL: + return True return False diff --git a/pypy/jit/backend/arm/opassembler.py b/pypy/jit/backend/arm/opassembler.py --- a/pypy/jit/backend/arm/opassembler.py +++ b/pypy/jit/backend/arm/opassembler.py @@ -474,7 +474,7 @@ # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. - with saved_registers(self.mc, r.caller_resp, regalloc=regalloc): + with saved_registers(self.mc, r.caller_resp): if N == 2: callargs = [r.r0, r.r1] else: @@ -950,6 +950,35 @@ self._emit_guard(guard_op, arglocs, c.GE) return fcond + emit_guard_call_release_gil = emit_guard_call_may_force + + def call_release_gil(self, gcrootmap, save_registers): + # First, we need to save away the registers listed in + # 'save_registers' that are not callee-save. XXX We assume that + # the floating point registers won't be modified. + import pdb; pdb.set_trace() + regs_to_save = [] + for reg in self._regalloc.rm.save_around_call_regs: + if reg in save_registers: + regs_to_save.append(reg) + assert gcrootmap.is_shadow_stack + with saved_registers(self.mc, regs_to_save): + self._emit_call(-1, self.releasegil_addr, [], regalloc, fcond) + + def call_reacquire_gil(self, gcrootmap, save_loc): + # save the previous result into the stack temporarily. + # XXX like with call_release_gil(), we assume that we don't need + # to save vfp regs in this case. + regs_to_save = [] + if isinstance(save_loc, RegLoc) and not save_loc.is_vfp_reg(): + regs_to_save.append(save_loc) + # call the reopenstack() function (also reacquiring the GIL) + if len(regs_to_save) == 1: + regs_to_save.append(r.ip) # for alingment + assert gcrootmap.is_shadow_stack + with saved_registers(self.mc, regs_to_save): + self._emit_call(-1, self.reacqgil_addr, [], regalloc, fcond) + def write_new_force_index(self): # for shadowstack only: get a new, unused force_index number and # write it to FORCE_INDEX_OFS. Used to record the call shape diff --git a/pypy/jit/backend/arm/regalloc.py b/pypy/jit/backend/arm/regalloc.py --- a/pypy/jit/backend/arm/regalloc.py +++ b/pypy/jit/backend/arm/regalloc.py @@ -998,6 +998,23 @@ self.possibly_free_vars(guard_op.getfailargs()) return locs + def prepare_guard_call_release_gil(self, op, guard_op, fcond): + # first, close the stack in the sense of the asmgcc GC root tracker + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + if gcrootmap: + self.assembler.call_release_gil(gcrootmap, arglocs) + # do the call + faildescr = guard_op.getdescr() + fail_index = self.cpu.get_fail_descr_number(faildescr) + args = [imm(rffi.cast(lltype.Signed, op.getarg(0).getint()))] + self.assembler.emit_op_call(op, args, self, fcond, fail_index) + # then reopen the stack + if gcrootmap: + self.call_reacquire_gil(gcrootmap, r.r0) + locs = self._prepare_guard(guard_op) + self.possibly_free_vars(guard_op.getfailargs()) + return locs + def prepare_guard_call_assembler(self, op, guard_op, fcond): descr = op.getdescr() assert isinstance(descr, LoopToken) From noreply at buildbot.pypy.org Wed Jul 13 15:18:00 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 13 Jul 2011 15:18:00 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: fix rtyper error and proper bindings of instance data members Message-ID: <20110713131800.F28138291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45550:95fe0aabf5d4 Date: 2011-07-13 06:17 -0700 http://bitbucket.org/pypy/pypy/changeset/95fe0aabf5d4/ Log: fix rtyper error and proper bindings of instance data members diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py --- a/pypy/module/cppyy/__init__.py +++ b/pypy/module/cppyy/__init__.py @@ -7,6 +7,7 @@ '_load_lib' : 'interp_cppyy.load_lib', '_type_byname' : 'interp_cppyy.type_byname', '_template_byname' : 'interp_cppyy.template_byname', + 'CPPInstance' : 'interp_cppyy.W_CPPInstance', } appleveldefs = { diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -511,7 +511,7 @@ address = self._get_raw_address(space, w_obj, offset) obj_address = rffi.cast(rffi.VOIDP, address) from pypy.module.cppyy import interp_cppyy - return interp_cppyy.W_CPPInstance(space, self.cpptype, obj_address) + return interp_cppyy.W_CPPInstance(space, self.cpptype, obj_address, False) def free_argument(self, arg): pass diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -2,7 +2,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import ObjSpace, interp2app -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import TypeDef, interp_attrproperty from pypy.interpreter.baseobjspace import Wrappable from pypy.rpython.lltypesystem import rffi, lltype @@ -497,6 +497,7 @@ W_CPPType.typedef = TypeDef( 'CPPType', + type_name = interp_attrproperty('name', W_CPPType), get_base_names = interp2app(W_CPPType.get_base_names, unwrap_spec=['self']), get_method_names = interp2app(W_CPPType.get_method_names, unwrap_spec=['self']), get_overload = interp2app(W_CPPType.get_overload, unwrap_spec=['self', str]), @@ -555,6 +556,7 @@ W_CPPInstance.typedef = TypeDef( 'CPPInstance', + cppclass = interp_attrproperty('cppclass', W_CPPInstance), invoke = interp2app(W_CPPInstance.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']), destruct = interp2app(W_CPPInstance.destruct, unwrap_spec=['self']), ) diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py --- a/pypy/module/cppyy/pythonify.py +++ b/pypy/module/cppyy/pythonify.py @@ -82,6 +82,16 @@ return method +def make_datamember(cppdm): + import cppyy + def binder(obj, owner=None): + value = cppdm.__get__(obj, owner) + if isinstance(value, cppyy.CPPInstance): + cppclass = get_cppclass(value.cppclass.type_name) + return bind_object(value, cppclass) + return value + return property(binder, cppdm.__set__) + def make_cppnamespace(namespace_name, cppns): d = {"_cpp_proxy" : cppns} @@ -97,8 +107,9 @@ # static ones also to the meta class (needed for property setters) for dm in cppns.get_data_member_names(): cppdm = cppns.get_data_member(dm) - d[dm] = cppdm - setattr(metans, dm, cppdm) + pydm = make_datamember(cppdm) + d[dm] = pydm + setattr(metans, dm, pydm) # create the python-side C++ namespace representation pycppns = metans(namespace_name, (object,), d) @@ -147,10 +158,11 @@ # static ones also to the meta class (needed for property setters) for dm_name in cpptype.get_data_member_names(): cppdm = cpptype.get_data_member(dm_name) + pydm = make_datamember(cppdm) - setattr(pycpptype, dm_name, cppdm) + setattr(pycpptype, dm_name, pydm) if cppdm.is_static(): - setattr(metacpp, dm_name, cppdm) + setattr(metacpp, dm_name, pydm) _pythonize(pycpptype) return pycpptype diff --git a/pypy/module/cppyy/test/test_advancedcpp.py b/pypy/module/cppyy/test/test_advancedcpp.py --- a/pypy/module/cppyy/test/test_advancedcpp.py +++ b/pypy/module/cppyy/test/test_advancedcpp.py @@ -175,9 +175,9 @@ #----- t2 = gbl.T2(gbl.T1(int))(gbl.T1(int)(32)) -# t2.m_t2.m_t1 = 32 -# assert t2.m_t2.value() == 32 -# assert t2.m_t2.m_t1 == 32 + t2.m_t2.m_t1 = 32 + assert t2.m_t2.value() == 32 + assert t2.m_t2.m_t1 == 32 t2.destruct() def test05_abstract_classes(self): From noreply at buildbot.pypy.org Wed Jul 13 15:25:31 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 15:25:31 +0200 (CEST) Subject: [pypy-commit] pypy default: Support the no-op force_cast(Float) -> Float. Complain when Message-ID: <20110713132531.0AF6E8291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45551:c7482c194d60 Date: 2011-07-13 15:23 +0200 http://bitbucket.org/pypy/pypy/changeset/c7482c194d60/ Log: Support the no-op force_cast(Float) -> Float. Complain when seeing any other usage of Float in force_cast. diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -809,8 +809,15 @@ return self.force_cast_without_longlong(op.args[0], op.result) def force_cast_without_longlong(self, v_arg, v_result): - from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof + from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT from pypy.rlib.rarithmetic import intmask + # + if (v_result.concretetype in (FLOAT, lltype.Float) or + v_arg.concretetype in (FLOAT, lltype.Float)): + assert (v_result.concretetype == lltype.Float and + v_arg.concretetype == lltype.Float), "xxx unsupported cast" + return + # size2, unsigned2 = size_and_sign(v_result.concretetype) assert size2 <= sizeof(lltype.Signed) if size2 == sizeof(lltype.Signed): diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -854,6 +854,14 @@ int_return %i0 """, transform=True) + def test_force_cast_float(self): + from pypy.rpython.lltypesystem import rffi + def f(n): + return rffi.cast(lltype.Float, n) + self.encoding_test(f, [12.456], """ + float_return %f0 + """, transform=True) + def test_direct_ptradd(self): from pypy.rpython.lltypesystem import rffi def f(p, n): From noreply at buildbot.pypy.org Wed Jul 13 15:25:32 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 15:25:32 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: hg merge default Message-ID: <20110713132532.5CC198291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: reflex-support Changeset: r45552:545bfae84d30 Date: 2011-07-13 15:24 +0200 http://bitbucket.org/pypy/pypy/changeset/545bfae84d30/ Log: hg merge default diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) - if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') + if parent_destructor is not None: + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -858,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): @@ -44,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -58,10 +63,15 @@ expected = "\xE8" + struct.pack(' Author: Armin Rigo Branch: reflex-support Changeset: r45553:5bfaefc7a682 Date: 2011-07-13 15:25 +0200 http://bitbucket.org/pypy/pypy/changeset/5bfaefc7a682/ Log: merge heads diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py --- a/pypy/module/cppyy/__init__.py +++ b/pypy/module/cppyy/__init__.py @@ -7,6 +7,7 @@ '_load_lib' : 'interp_cppyy.load_lib', '_type_byname' : 'interp_cppyy.type_byname', '_template_byname' : 'interp_cppyy.template_byname', + 'CPPInstance' : 'interp_cppyy.W_CPPInstance', } appleveldefs = { diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -511,7 +511,7 @@ address = self._get_raw_address(space, w_obj, offset) obj_address = rffi.cast(rffi.VOIDP, address) from pypy.module.cppyy import interp_cppyy - return interp_cppyy.W_CPPInstance(space, self.cpptype, obj_address) + return interp_cppyy.W_CPPInstance(space, self.cpptype, obj_address, False) def free_argument(self, arg): pass diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -2,7 +2,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import ObjSpace, interp2app -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import TypeDef, interp_attrproperty from pypy.interpreter.baseobjspace import Wrappable from pypy.rpython.lltypesystem import rffi, lltype @@ -497,6 +497,7 @@ W_CPPType.typedef = TypeDef( 'CPPType', + type_name = interp_attrproperty('name', W_CPPType), get_base_names = interp2app(W_CPPType.get_base_names, unwrap_spec=['self']), get_method_names = interp2app(W_CPPType.get_method_names, unwrap_spec=['self']), get_overload = interp2app(W_CPPType.get_overload, unwrap_spec=['self', str]), @@ -555,6 +556,7 @@ W_CPPInstance.typedef = TypeDef( 'CPPInstance', + cppclass = interp_attrproperty('cppclass', W_CPPInstance), invoke = interp2app(W_CPPInstance.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']), destruct = interp2app(W_CPPInstance.destruct, unwrap_spec=['self']), ) diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py --- a/pypy/module/cppyy/pythonify.py +++ b/pypy/module/cppyy/pythonify.py @@ -82,6 +82,16 @@ return method +def make_datamember(cppdm): + import cppyy + def binder(obj, owner=None): + value = cppdm.__get__(obj, owner) + if isinstance(value, cppyy.CPPInstance): + cppclass = get_cppclass(value.cppclass.type_name) + return bind_object(value, cppclass) + return value + return property(binder, cppdm.__set__) + def make_cppnamespace(namespace_name, cppns): d = {"_cpp_proxy" : cppns} @@ -97,8 +107,9 @@ # static ones also to the meta class (needed for property setters) for dm in cppns.get_data_member_names(): cppdm = cppns.get_data_member(dm) - d[dm] = cppdm - setattr(metans, dm, cppdm) + pydm = make_datamember(cppdm) + d[dm] = pydm + setattr(metans, dm, pydm) # create the python-side C++ namespace representation pycppns = metans(namespace_name, (object,), d) @@ -147,10 +158,11 @@ # static ones also to the meta class (needed for property setters) for dm_name in cpptype.get_data_member_names(): cppdm = cpptype.get_data_member(dm_name) + pydm = make_datamember(cppdm) - setattr(pycpptype, dm_name, cppdm) + setattr(pycpptype, dm_name, pydm) if cppdm.is_static(): - setattr(metacpp, dm_name, cppdm) + setattr(metacpp, dm_name, pydm) _pythonize(pycpptype) return pycpptype diff --git a/pypy/module/cppyy/test/test_advancedcpp.py b/pypy/module/cppyy/test/test_advancedcpp.py --- a/pypy/module/cppyy/test/test_advancedcpp.py +++ b/pypy/module/cppyy/test/test_advancedcpp.py @@ -175,9 +175,9 @@ #----- t2 = gbl.T2(gbl.T1(int))(gbl.T1(int)(32)) -# t2.m_t2.m_t1 = 32 -# assert t2.m_t2.value() == 32 -# assert t2.m_t2.m_t1 == 32 + t2.m_t2.m_t1 = 32 + assert t2.m_t2.value() == 32 + assert t2.m_t2.m_t1 == 32 t2.destruct() def test05_abstract_classes(self): From noreply at buildbot.pypy.org Wed Jul 13 15:26:22 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 13 Jul 2011 15:26:22 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (cfbolz, wlav) fix bool casting Message-ID: <20110713132622.83E4A8291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45554:acfcd4105fa7 Date: 2011-07-13 06:26 -0700 http://bitbucket.org/pypy/pypy/changeset/acfcd4105fa7/ Log: (cfbolz, wlav) fix bool casting diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -61,7 +61,7 @@ def execute_libffi(self, space, libffifunc, argchain): result = libffifunc.call(argchain, rffi.CHAR) - return space.wrap(result) + return space.wrap(bool(ord(result))) class CharExecutor(FunctionExecutor): _immutable_ = True From noreply at buildbot.pypy.org Wed Jul 13 15:56:08 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 15:56:08 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix for 64-bit: disable automatically collecting on the second external_malloc. Message-ID: <20110713135608.75B358291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45555:663cb9f5a040 Date: 2011-07-13 15:55 +0200 http://bitbucket.org/pypy/pypy/changeset/663cb9f5a040/ Log: Fix for 64-bit: disable automatically collecting on the second external_malloc. diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -525,6 +525,7 @@ def test_writebarrier_before_copy(self): from pypy.rpython.memory.gc import minimark largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 p_src = self.malloc(VAR, largeobj_size) p_dst = self.malloc(VAR, largeobj_size) # make them old @@ -564,6 +565,7 @@ from pypy.rpython.memory.gc import minimark tid = self.get_type_id(VAR) largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 addr_src = self.gc.external_malloc(tid, largeobj_size) addr_dst = self.gc.external_malloc(tid, largeobj_size) hdr_src = self.gc.header(addr_src) From noreply at buildbot.pypy.org Wed Jul 13 16:25:54 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 16:25:54 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix test_runicode for 740fc1da78ad. Message-ID: <20110713142554.32B438291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45556:ac7f45e87955 Date: 2011-07-13 16:25 +0200 http://bitbucket.org/pypy/pypy/changeset/ac7f45e87955/ Log: Fix test_runicode for 740fc1da78ad. diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -231,7 +231,7 @@ const = self.const def fn(i): s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] - return s[i].startswith('o') + return s[i].startswith(const('o')) for i in range(10): res = self.interpret(fn, [i]) assert res == fn(i) @@ -251,7 +251,7 @@ const = self.const def fn(i): s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] - return s[i].endswith('e') + return s[i].endswith(const('e')) for i in range(10): res = self.interpret(fn, [i]) assert res == fn(i) From noreply at buildbot.pypy.org Wed Jul 13 17:00:18 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 13 Jul 2011 17:00:18 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: These loops are no longer specialized to the condition "4th input argument is Message-ID: <20110713150018.3CED58291A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45557:d155e04aa75f Date: 2011-07-13 10:29 +0200 http://bitbucket.org/pypy/pypy/changeset/d155e04aa75f/ Log: These loops are no longer specialized to the condition "4th input argument is int_neg of 3rd input argument" diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2015,8 +2015,9 @@ [p1, i1, i2, i4] setfield_gc(p1, i1, descr=valuedescr) guard_true(i4) [] + i5 = int_neg(i2) setfield_gc(p1, i2, descr=valuedescr) - jump(p1, i1, i2, 1) + jump(p1, i1, i2, i5) """ self.optimize_loop(ops, expected, preamble) @@ -2044,9 +2045,10 @@ expected = """ [p1, i2, i4] guard_true(i4) [p1] + i5 = int_neg(i2) setfield_gc(p1, NULL, descr=nextdescr) escape() - jump(p1, i2, 1) + jump(p1, i2, i5) """ self.optimize_loop(ops, expected, preamble) @@ -2073,9 +2075,10 @@ expected = """ [p1, i2, i4] guard_true(i4) [i2, p1] + i5 = int_neg(i2) setfield_gc(p1, NULL, descr=nextdescr) escape() - jump(p1, i2, 1) + jump(p1, i2, i5) """ self.optimize_loop(ops, expected) @@ -2097,8 +2100,9 @@ setfield_gc(p1, i1, descr=valuedescr) i5 = int_eq(i4, 5) guard_true(i5) [] + i7 = int_neg(i2) setfield_gc(p1, i2, descr=valuedescr) - jump(p1, i1, i2, 5) + jump(p1, i1, i2, i7) """ self.optimize_loop(ops, expected, preamble) From noreply at buildbot.pypy.org Wed Jul 13 17:00:19 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 13 Jul 2011 17:00:19 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: support for array accesses with variable index was killed Message-ID: <20110713150019.702A58291A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45558:5d3d1b3ab4f5 Date: 2011-07-13 10:38 +0200 http://bitbucket.org/pypy/pypy/changeset/5d3d1b3ab4f5/ Log: support for array accesses with variable index was killed diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2195,21 +2195,6 @@ """ self.optimize_loop(ops, expected) - def test_duplicate_getarrayitem_3(self): - ops = """ - [p1, i0, i10] - i2 = getarrayitem_gc(p1, i10, descr=arraydescr2) - i4 = getarrayitem_gc(p1, i10, descr=arraydescr2) - i7 = int_add(i0, i4) - jump(p1, i7, i10) - """ - expected = """ - [p1, i0, i10, i6] - i7 = int_add(i0, i6) - jump(p1, i7, i10, i6) - """ - self.optimize_loop(ops, expected) - def test_duplicate_getarrayitem_after_setarrayitem_1(self): ops = """ [p1, p2] From noreply at buildbot.pypy.org Wed Jul 13 17:00:20 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 13 Jul 2011 17:00:20 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: more overspecialization Message-ID: <20110713150020.A0CFB8291A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45559:1796d791c1b4 Date: 2011-07-13 10:46 +0200 http://bitbucket.org/pypy/pypy/changeset/1796d791c1b4/ Log: more overspecialization diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2325,10 +2325,11 @@ expected = """ [p1, i2, i4, p4] guard_true(i4) [p1, p4] + i5 = int_neg(i2) p2 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p2, p4, descr=nextdescr) setfield_gc(p1, p2, descr=nextdescr) - jump(p1, i2, 1, p4) + jump(p1, i2, i5, p4) """ self.optimize_loop(ops, expected, preamble) From noreply at buildbot.pypy.org Wed Jul 13 17:00:21 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 13 Jul 2011 17:00:21 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: separated the genralization startegy into a class of its own Message-ID: <20110713150021.DCEBF8291A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45560:421d6523ee43 Date: 2011-07-13 16:39 +0200 http://bitbucket.org/pypy/pypy/changeset/421d6523ee43/ Log: separated the genralization startegy into a class of its own diff --git a/pypy/jit/metainterp/optimizeopt/generalize.py b/pypy/jit/metainterp/optimizeopt/generalize.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/optimizeopt/generalize.py @@ -0,0 +1,18 @@ +from pypy.jit.metainterp.optimizeopt.optimizer import MININT, MAXINT + +class GeneralizationStrategy(object): + def __init__(self, optimizer): + self.optimizer = optimizer + + def apply(self): + raise NotImplementedError + +class KillHugeIntBounds(GeneralizationStrategy): + def apply(self): + for v in self.optimizer.values.values(): + if v.intbound.lower < MININT/2: + v.intbound.lower = MININT + if v.intbound.upper > MAXINT/2: + v.intbound.upper = MAXINT + import pdb; pdb.set_trace() + diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -87,10 +87,6 @@ return self.box def force_at_end_of_preamble(self, already_forced): - if self.intbound.lower < MININT/2: - self.intbound.lower = MININT - if self.intbound.upper > MAXINT/2: - self.intbound.upper = MAXINT return self def get_cloned(self, optimizer, valuemap, force_if_needed=True): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2865,8 +2865,7 @@ jump(p8, p11, p26) """ expected = """ - [p8, p11, i24, i19, p16, i21, i34] - i39 = getfield_gc(p8, descr=nextdescr) + [p8, p11, i24, i39, i19, p16, i21, i34] i40 = int_ge(i39, i19) guard_false(i40) [] i41 = getfield_gc(p16, descr=nextdescr) @@ -2876,7 +2875,7 @@ setfield_gc(p8, i44, descr=nextdescr) i45 = int_add_ovf(i34, i43) guard_no_overflow() [] - jump(p8, p11, i43, i19, p16, i21, i34) + jump(p8, p11, i43, i44, i19, p16, i21, i34) """ self.optimize_loop(ops, expected) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -9,6 +9,7 @@ from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.history import make_hashable_int from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.metainterp.optimizeopt.generalize import KillHugeIntBounds # Assumptions # =========== @@ -171,6 +172,8 @@ jumpop.initarglist([]) self.optimizer.flush() + KillHugeIntBounds(self.optimizer).apply() + loop.preamble.operations = self.optimizer.newoperations modifier = VirtualStateAdder(self.optimizer) @@ -192,7 +195,7 @@ self.optimizer.quasi_immutable_deps) self.optimizer = self.optimizer.reconstruct_for_next_iteration(sb, jump_args) loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps - + initial_inputargs_len = len(inputargs) self.inliner = Inliner(loop.inputargs, jump_args) @@ -307,6 +310,7 @@ self.add_op_to_short(op, short, short_seen) self.optimizer.flush() + i = j = 0 while i < len(self.optimizer.newoperations): From noreply at buildbot.pypy.org Wed Jul 13 17:00:23 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 13 Jul 2011 17:00:23 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: produce the value guards for the short preamble prior to inlining the peeled loop as that might strengthen the values of the inputargs and thus make the value guards in the short preamble too strong Message-ID: <20110713150023.1630F8291A@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45561:05ccf7b80667 Date: 2011-07-13 16:59 +0200 http://bitbucket.org/pypy/pypy/changeset/05ccf7b80667/ Log: produce the value guards for the short preamble prior to inlining the peeled loop as that might strengthen the values of the inputargs and thus make the value guards in the short preamble too strong diff --git a/pypy/jit/metainterp/optimizeopt/generalize.py b/pypy/jit/metainterp/optimizeopt/generalize.py --- a/pypy/jit/metainterp/optimizeopt/generalize.py +++ b/pypy/jit/metainterp/optimizeopt/generalize.py @@ -14,5 +14,4 @@ v.intbound.lower = MININT if v.intbound.upper > MAXINT/2: v.intbound.upper = MAXINT - import pdb; pdb.set_trace() diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -275,6 +275,17 @@ short_jumpargs = inputargs[:] short_inputargs = virtual_state.make_inputargs(values, keyboxes=True) + short = [] + short_seen = {} + for box, const in self.constant_inputargs.items(): + short_seen[box] = True + + for result, op in self.short_boxes.items(): + if op is not None: + assert result is op.result + for guard in self.getvalue(result).make_guards(result): + self.add_op_to_short(guard, short, short_seen, False) + # This loop is equivalent to the main optimization loop in # Optimizer.propagate_all_forward jumpop = None @@ -297,18 +308,13 @@ jmp_to_short_args = virtual_state.make_inputargs(values, keyboxes=True) self.short_inliner = Inliner(short_inputargs, jmp_to_short_args) - short = [] - short_seen = {} for box, const in self.constant_inputargs.items(): - short_seen[box] = True self.short_inliner.argmap[box] = const + + for op in short: + newop = self.short_inliner.inline_op(op) + self.optimizer.send_extra_operation(newop) - for result, op in self.short_boxes.items(): - if op is not None: - assert result is op.result - if len(self.getvalue(result).make_guards(result)) > 0: - self.add_op_to_short(op, short, short_seen) - self.optimizer.flush() @@ -356,35 +362,35 @@ return inputargs, short_inputargs, short - def add_op_to_short(self, op, short, short_seen): + def add_op_to_short(self, op, short, short_seen, emit=True): if op is None: - return + return None if op.result is not None and op.result in short_seen: - return self.short_inliner.inline_arg(op.result) + if emit: + return self.short_inliner.inline_arg(op.result) + else: + return None for a in op.getarglist(): if not isinstance(a, Const) and a not in short_seen: - self.add_op_to_short(self.short_boxes[a], short, short_seen) + self.add_op_to_short(self.short_boxes[a], short, short_seen, emit) if op.is_guard(): descr = self.start_resumedescr.clone_if_mutable() op.setdescr(descr) - value_guards = [] - if op.result in self.short_boxes: - value_guards = self.getvalue(op.result).make_guards(op.result) - short.append(op) short_seen[op.result] = True - newop = self.short_inliner.inline_op(op) - self.optimizer.send_extra_operation(newop) + if emit: + newop = self.short_inliner.inline_op(op) + self.optimizer.send_extra_operation(newop) if op.is_ovf(): # FIXME: ensure that GUARD_OVERFLOW:ed ops not end up here guard = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) - self.add_op_to_short(guard, short, short_seen) - for guard in value_guards: - self.add_op_to_short(guard, short, short_seen) + self.add_op_to_short(guard, short, short_seen, emit) - return newop.result + if emit: + return newop.result + return None def import_box(self, box, inputargs, short, short_jumpargs, jumpargs, short_seen): From noreply at buildbot.pypy.org Wed Jul 13 17:06:56 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 17:06:56 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: fix tests Message-ID: <20110713150656.796FC8291A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45562:8c2c5a276c71 Date: 2011-07-13 17:04 +0200 http://bitbucket.org/pypy/pypy/changeset/8c2c5a276c71/ Log: fix tests diff --git a/pypy/jit/backend/arm/test/test_zrpy_gc.py b/pypy/jit/backend/arm/test/test_zrpy_gc.py --- a/pypy/jit/backend/arm/test/test_zrpy_gc.py +++ b/pypy/jit/backend/arm/test/test_zrpy_gc.py @@ -10,13 +10,10 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.jit.backend.arm.runner import ArmCPU -from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC -import py.test class X(object): def __init__(self, x=0): @@ -684,3 +681,4 @@ class TestShadowStack(CompileFrameworkTests): gcrootfinder = "shadowstack" + diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -2737,7 +2737,7 @@ assert False, 'should not be called' from pypy.jit.codewriter.effectinfo import EffectInfo - effectinfo = EffectInfo([], [], [], EffectInfo.EF_CAN_RAISE, EffectInfo.OS_MATH_SQRT) + effectinfo = EffectInfo([], [], [], [], EffectInfo.EF_CAN_RAISE, EffectInfo.OS_MATH_SQRT) FPTR = self.Ptr(self.FuncType([lltype.Float], lltype.Float)) func_ptr = llhelper(FPTR, math_sqrt) FUNC = deref(FPTR) From noreply at buildbot.pypy.org Wed Jul 13 17:06:57 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 17:06:57 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: add propper names to functions generated for the register allocator Message-ID: <20110713150657.A90768291A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45563:90628c54e101 Date: 2011-07-13 17:06 +0200 http://bitbucket.org/pypy/pypy/changeset/90628c54e101/ Log: add propper names to functions generated for the register allocator diff --git a/pypy/jit/backend/arm/helper/regalloc.py b/pypy/jit/backend/arm/helper/regalloc.py --- a/pypy/jit/backend/arm/helper/regalloc.py +++ b/pypy/jit/backend/arm/helper/regalloc.py @@ -14,7 +14,7 @@ return i <= size and lower_bound return False -def prepare_op_unary_cmp(): +def prepare_op_unary_cmp(name=None): def f(self, op, fcond): assert fcond is not None a0 = op.getarg(0) @@ -22,9 +22,11 @@ res = self.force_allocate_reg(op.result, [box]) self.possibly_free_vars([a0, box, op.result]) return [reg, res] + if name: + f.__name__ = name return f -def prepare_op_ri(imm_size=0xFF, commutative=True, allow_zero=True): +def prepare_op_ri(name=None, imm_size=0xFF, commutative=True, allow_zero=True): def f(self, op, fcond): assert fcond is not None a0 = op.getarg(0) @@ -49,6 +51,8 @@ res = self.force_allocate_reg(op.result, boxes) self.possibly_free_var(op.result) return [l0, l1, res] + if name: + f.__name__ = name return f def prepare_float_op(base=True, float_result=True): @@ -70,7 +74,7 @@ return locs return f -def prepare_op_by_helper_call(): +def prepare_op_by_helper_call(name): def f(self, op, fcond): assert fcond is not None a0 = op.getarg(0) @@ -86,9 +90,10 @@ self.possibly_free_var(a1) self.possibly_free_var(op.result) return [] + f.__name__ = name return f -def prepare_cmp_op(inverse=False): +def prepare_cmp_op(name=None, inverse=False): def f(self, op, fcond): assert fcond is not None boxes = list(op.getarglist()) @@ -111,4 +116,6 @@ res = self.force_allocate_reg(op.result) self.possibly_free_var(op.result) return [l0, l1, res] + if name: + f.__name__ = name return f diff --git a/pypy/jit/backend/arm/regalloc.py b/pypy/jit/backend/arm/regalloc.py --- a/pypy/jit/backend/arm/regalloc.py +++ b/pypy/jit/backend/arm/regalloc.py @@ -400,29 +400,29 @@ self.possibly_free_vars(guard.getfailargs()) return locs - prepare_op_int_floordiv = prepare_op_by_helper_call() - prepare_op_int_mod = prepare_op_by_helper_call() - prepare_op_uint_floordiv = prepare_op_by_helper_call() + prepare_op_int_floordiv = prepare_op_by_helper_call('int_floordiv') + prepare_op_int_mod = prepare_op_by_helper_call('int_mod') + prepare_op_uint_floordiv = prepare_op_by_helper_call('unit_floordiv') - prepare_op_int_and = prepare_op_ri() - prepare_op_int_or = prepare_op_ri() - prepare_op_int_xor = prepare_op_ri() - prepare_op_int_lshift = prepare_op_ri(imm_size=0x1F, allow_zero=False, commutative=False) - prepare_op_int_rshift = prepare_op_ri(imm_size=0x1F, allow_zero=False, commutative=False) - prepare_op_uint_rshift = prepare_op_ri(imm_size=0x1F, allow_zero=False, commutative=False) + prepare_op_int_and = prepare_op_ri('int_and') + prepare_op_int_or = prepare_op_ri('int_or') + prepare_op_int_xor = prepare_op_ri('int_xor') + prepare_op_int_lshift = prepare_op_ri('int_lshift', imm_size=0x1F, allow_zero=False, commutative=False) + prepare_op_int_rshift = prepare_op_ri('int_rshift', imm_size=0x1F, allow_zero=False, commutative=False) + prepare_op_uint_rshift = prepare_op_ri('uint_rshift', imm_size=0x1F, allow_zero=False, commutative=False) - prepare_op_int_lt = prepare_cmp_op() - prepare_op_int_le = prepare_cmp_op() - prepare_op_int_eq = prepare_cmp_op() - prepare_op_int_ne = prepare_cmp_op() - prepare_op_int_gt = prepare_cmp_op() - prepare_op_int_ge = prepare_cmp_op() + prepare_op_int_lt = prepare_cmp_op('int_lt') + prepare_op_int_le = prepare_cmp_op('int_le') + prepare_op_int_eq = prepare_cmp_op('int_eq') + prepare_op_int_ne = prepare_cmp_op('int_ne') + prepare_op_int_gt = prepare_cmp_op('int_gt') + prepare_op_int_ge = prepare_cmp_op('int_ge') - prepare_op_uint_le = prepare_cmp_op() - prepare_op_uint_gt = prepare_cmp_op() + prepare_op_uint_le = prepare_cmp_op('uint_le') + prepare_op_uint_gt = prepare_cmp_op('uint_gt') - prepare_op_uint_lt = prepare_cmp_op(inverse=True) - prepare_op_uint_ge = prepare_cmp_op(inverse=True) + prepare_op_uint_lt = prepare_cmp_op('uint_lt', inverse=True) + prepare_op_uint_ge = prepare_cmp_op('uint_ge', inverse=True) prepare_op_int_add_ovf = prepare_op_int_add prepare_op_int_sub_ovf = prepare_op_int_sub @@ -430,8 +430,8 @@ prepare_op_ptr_eq = prepare_op_int_eq prepare_op_ptr_ne = prepare_op_int_ne - prepare_op_int_is_true = prepare_op_unary_cmp() - prepare_op_int_is_zero = prepare_op_unary_cmp() + prepare_op_int_is_true = prepare_op_unary_cmp('int_is_true') + prepare_op_int_is_zero = prepare_op_unary_cmp('int_is_zero') def prepare_op_int_neg(self, op, fcond): l0, box = self._ensure_value_is_boxed(op.getarg(0)) From noreply at buildbot.pypy.org Wed Jul 13 17:06:58 2011 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 13 Jul 2011 17:06:58 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: translation fixes Message-ID: <20110713150658.D81588291A@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45564:e9c9ec773f6a Date: 2011-07-13 17:06 +0200 http://bitbucket.org/pypy/pypy/changeset/e9c9ec773f6a/ Log: translation fixes diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -30,11 +30,7 @@ have_debug_prints) # XXX Move to llsupport -from pypy.jit.backend.x86.support import values_array - -memcpy_fn = rffi.llexternal('memcpy', [llmemory.Address, llmemory.Address, - rffi.SIZE_T], lltype.Void, - sandboxsafe=True, _nowrapper=True) +from pypy.jit.backend.x86.support import values_array, memcpy_fn class AssemblerARM(ResOpAssembler): """ diff --git a/pypy/jit/backend/arm/regalloc.py b/pypy/jit/backend/arm/regalloc.py --- a/pypy/jit/backend/arm/regalloc.py +++ b/pypy/jit/backend/arm/regalloc.py @@ -972,7 +972,7 @@ arglocs = [] argboxes = [] for i in range(N): - loc, box = self._ensure_value_is_boxed(op.getarg(i), arglocs) + loc, box = self._ensure_value_is_boxed(op.getarg(i), argboxes) arglocs.append(loc) argboxes.append(box) self.rm.possibly_free_vars(argboxes) @@ -1002,7 +1002,14 @@ # first, close the stack in the sense of the asmgcc GC root tracker gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap: + arglocs = [] + argboxes = [] + for i in range(op.numargs()): + loc, box = self._ensure_value_is_boxed(op.getarg(i), argboxes) + arglocs.append(loc) + argboxes.append(box) self.assembler.call_release_gil(gcrootmap, arglocs) + self.possibly_free_vars(argboxes) # do the call faildescr = guard_op.getdescr() fail_index = self.cpu.get_fail_descr_number(faildescr) diff --git a/pypy/jit/backend/arm/runner.py b/pypy/jit/backend/arm/runner.py --- a/pypy/jit/backend/arm/runner.py +++ b/pypy/jit/backend/arm/runner.py @@ -31,7 +31,7 @@ def finish_once(self): pass - def compile_loop(self, inputargs, operations, looptoken, log=True): + def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): self.assembler.assemble_loop(inputargs, operations, looptoken, log=log) From noreply at buildbot.pypy.org Wed Jul 13 17:11:53 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 17:11:53 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove a print left behind. Replace it with an assert. Message-ID: <20110713151153.9C6858291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45565:ab3c2b73305b Date: 2011-07-13 17:11 +0200 http://bitbucket.org/pypy/pypy/changeset/ab3c2b73305b/ Log: Remove a print left behind. Replace it with an assert. diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -21,7 +21,7 @@ continue if hasattr(Class, name_prefix + name): opclass = resoperation.opclasses[getattr(rop, name)] - print value, name, opclass + assert name in opclass.__name__ result.append((value, opclass, getattr(Class, name_prefix + name))) return unrolling_iterable(result) From noreply at buildbot.pypy.org Wed Jul 13 17:26:26 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 13 Jul 2011 17:26:26 +0200 (CEST) Subject: [pypy-commit] buildbot default: update the README Message-ID: <20110713152626.7517D8291A@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r525:8307abad2f0b Date: 2011-07-13 17:26 +0200 http://bitbucket.org/pypy/buildbot/changeset/8307abad2f0b/ Log: update the README diff --git a/README b/README --- a/README +++ b/README @@ -24,7 +24,7 @@ If you want to run buildbot in production, you need to make sure that the function ``pypybuildbot.util.we_are_debugging`` returns ``False`` in your environment. At the moment of writing, debugging is enabled everywhere but on -codespeak.net. +wyvern. You still need to fill ``master/slaveinfo.py`` with the passwords of the various slaves you want to use. From noreply at buildbot.pypy.org Wed Jul 13 18:08:14 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 13 Jul 2011 18:08:14 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: fix rtyper error Message-ID: <20110713160814.7F51F8291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45566:b44c747fd5a6 Date: 2011-07-13 09:07 -0700 http://bitbucket.org/pypy/pypy/changeset/b44c747fd5a6/ Log: fix rtyper error diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -357,7 +357,8 @@ return rffi.cast(rffi.VOIDP, x) def convert_argument_libffi(self, space, w_obj, argchain): - argchain.arg_singlefloat(self._unwrap_object(space, w_obj)) + # it's required to sent an rffi.DOUBLE not r_singlefloat + argchain.arg_singlefloat(space.float_w(w_obj)) def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) From noreply at buildbot.pypy.org Wed Jul 13 19:33:24 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 13 Jul 2011 19:33:24 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix test_import_lock. Message-ID: <20110713173324.CE6E18291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45567:9cc125e51cc7 Date: 2011-07-13 19:33 +0200 http://bitbucket.org/pypy/pypy/changeset/9cc125e51cc7/ Log: Fix test_import_lock. diff --git a/pypy/module/thread/test/test_import_lock.py b/pypy/module/thread/test/test_import_lock.py --- a/pypy/module/thread/test/test_import_lock.py +++ b/pypy/module/thread/test/test_import_lock.py @@ -66,6 +66,9 @@ def test_lock(self, space, monkeypatch): from pypy.module.imp.importing import getimportlock, importhook + # Force importing the module _file now + space.builtin.get('file') + # Monkeypatch the import lock and add a counter importlock = getimportlock(space) original_acquire = importlock.acquire_lock From noreply at buildbot.pypy.org Wed Jul 13 19:36:58 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 13 Jul 2011 19:36:58 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: translation fixes (all rawobject now ccharp for benefit of direct_ptradd) Message-ID: <20110713173659.004858291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45568:5ccedc547337 Date: 2011-07-13 10:36 -0700 http://bitbucket.org/pypy/pypy/changeset/5ccedc547337/ Log: translation fixes (all rawobject now ccharp for benefit of direct_ptradd) diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -21,7 +21,7 @@ cpp_instance = space.interp_w(W_CPPInstance, w_cpp_instance, can_be_None=True) if cpp_instance: return cpp_instance.rawobject - return lltype.nullptr(rffi.VOIDP.TO) + return lltype.nullptr(rffi.CCHARP.TO) class TypeConverter(object): @@ -35,6 +35,7 @@ def _get_raw_address(self, space, w_obj, offset): rawobject = get_rawobject(space, w_obj) if rawobject: + assert lltype.typeOf(rawobject) == rffi.CCHARP field_address = lltype.direct_ptradd(rawobject, offset) fieldptr = rffi.cast(rffi.CCHARP, field_address) else: @@ -121,6 +122,7 @@ def to_memory(self, space, w_obj, w_value, offset): # copy only the pointer value rawobject = get_rawobject(space, w_obj) + assert lltype.typeOf(rawobject) == rffi.CCHARP field_address = lltype.direct_ptradd(rawobject, offset) byteptr = rffi.cast(rffi.CCHARPP, field_address) buf = space.buffer_w(w_value) @@ -488,6 +490,7 @@ if isinstance(obj, W_CPPInstance): if capi.c_is_subtype(obj.cppclass.handle, self.cpptype.handle): offset = capi.c_base_offset(obj.cppclass.handle, self.cpptype.handle) + assert lltype.typeOf(obj.rawobject) == rffi.CCHARP obj_address = lltype.direct_ptradd(obj.rawobject, offset) objptr = rffi.cast(rffi.VOIDP, obj_address) return objptr @@ -510,9 +513,8 @@ def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) - obj_address = rffi.cast(rffi.VOIDP, address) from pypy.module.cppyy import interp_cppyy - return interp_cppyy.W_CPPInstance(space, self.cpptype, obj_address, False) + return interp_cppyy.W_CPPInstance(space, self.cpptype, address, False) def free_argument(self, arg): pass diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -242,7 +242,7 @@ def execute(self, space, func, cppthis, num_args, args): from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) - ptr_result = rffi.cast(rffi.VOIDP, long_result) + ptr_result = rffi.cast(rffi.CCHARP, long_result) return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) def execute_libffi(self, space, libffifunc, argchain): @@ -257,7 +257,7 @@ from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_o( func.cpptype.handle, func.method_index, cppthis, num_args, args, self.cpptype.handle) - ptr_result = rffi.cast(rffi.VOIDP, long_result) + ptr_result = rffi.cast(rffi.CCHARP, long_result) return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, True) diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -15,7 +15,8 @@ class FastCallNotPossible(Exception): pass -NULL_VOIDP = lltype.nullptr(rffi.VOIDP.TO) +NULL_CCHARP = lltype.nullptr(rffi.CCHARP.TO) +NULL_VOIDP = lltype.nullptr(rffi.VOIDP.TO) def load_lib(space, name): # TODO: allow open in RTLD_GLOBAL mode @@ -126,7 +127,7 @@ if self.arg_converters is None: self._build_converters() jit.promote(self) - funcptr = self.methgetter(cppthis) + funcptr = self.methgetter(rffi.cast(rffi.VOIDP, cppthis)) libffi_func = self._get_libffi_func(funcptr) if not libffi_func: raise FastCallNotPossible @@ -210,7 +211,7 @@ assert not cppthis args = self.prepare_arguments(args_w) try: - return self.executor.execute(self.space, self, NULL_VOIDP, + return self.executor.execute(self.space, self, NULL_CCHARP, len(args_w), args) finally: self.free_arguments(args, len(args_w)) @@ -222,12 +223,13 @@ def call(self, cppthis, args_w): assert not cppthis newthis = capi.c_allocate(self.cpptype.handle) + ccharp_this = rffi.cast(rffi.CCHARP, newthis) try: - CPPMethod.call(self, newthis, args_w) + CPPMethod.call(self, ccharp_this, args_w) except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) raise - return W_CPPInstance(self.space, self.cpptype, newthis, True) + return W_CPPInstance(self.space, self.cpptype, ccharp_this, True) class W_CPPOverload(Wrappable): @@ -250,7 +252,7 @@ if cppinstance: cppthis = cppinstance.rawobject else: - cppthis = NULL_VOIDP + cppthis = NULL_CCHARP space = self.space errmsg = 'None of the overloads matched:' @@ -534,6 +536,7 @@ def __init__(self, space, cppclass, rawobject, python_owns): self.space = space self.cppclass = cppclass + assert lltype.typeOf(rawobject) == rffi.CCHARP self.rawobject = rawobject self.python_owns = python_owns @@ -548,7 +551,7 @@ def destruct(self): if self.rawobject: capi.c_destruct(self.cppclass.handle, self.rawobject) - self.rawobject = NULL_VOIDP + self.rawobject = NULL_CCHARP def __del__(self): if self.python_owns: From noreply at buildbot.pypy.org Wed Jul 13 20:44:12 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 13 Jul 2011 20:44:12 +0200 (CEST) Subject: [pypy-commit] pypy default: use issequence_w here as well Message-ID: <20110713184412.2FC848291A@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45569:2f59716baa22 Date: 2011-07-13 20:43 +0200 http://bitbucket.org/pypy/pypy/changeset/2f59716baa22/ Log: use issequence_w here as well diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -22,7 +22,7 @@ def PySequence_Check(space, w_obj): """Return 1 if the object provides sequence protocol, and 0 otherwise. This function always succeeds.""" - return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None) + return int(space.issequence_w(w_obj)) @cpython_api([PyObject], Py_ssize_t, error=-1) def PySequence_Size(space, w_obj): From noreply at buildbot.pypy.org Wed Jul 13 22:18:58 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 13 Jul 2011 22:18:58 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix the string startswith and endswith stuff for the JVM and CLR. Message-ID: <20110713201858.9CDBD8291A@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45570:9c3e9ffb771c Date: 2011-07-13 20:18 +0000 http://bitbucket.org/pypy/pypy/changeset/9c3e9ffb771c/ Log: Fix the string startswith and endswith stuff for the JVM and CLR. diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs --- a/pypy/translator/cli/src/pypylib.cs +++ b/pypy/translator/cli/src/pypylib.cs @@ -615,10 +615,28 @@ return s1.StartsWith(s2); } + public static bool ll_startswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[0] == c; + } + public static bool ll_endswith(string s1, string s2) { return s1.EndsWith(s2); } + + public static bool ll_endswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[s.Length - 1] == c; + } public static int ll_find(string s1, string s2, int start, int stop) { diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -791,6 +791,20 @@ return str.substring(start,start+cnt); } + public static boolean ll_startswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(0) == c; + } + + public static boolean ll_endswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(str.length() - 1) == c; + } + // ---------------------------------------------------------------------- // StringBuffer From noreply at buildbot.pypy.org Wed Jul 13 23:32:59 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Wed, 13 Jul 2011 23:32:59 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: New branch for Justin Peel's additions to single dimensional numpy arrays Message-ID: <20110713213259.3B30B8291A@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45571:e262d6770928 Date: 2011-07-13 14:52 -0600 http://bitbucket.org/pypy/pypy/changeset/e262d6770928/ Log: New branch for Justin Peel's additions to single dimensional numpy arrays From noreply at buildbot.pypy.org Wed Jul 13 23:33:00 2011 From: noreply at buildbot.pypy.org (Timo Paulssen) Date: Wed, 13 Jul 2011 23:33:00 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: added size and ndim properties to numpy array. Message-ID: <20110713213300.68DC68291A@wyvern.cs.uni-duesseldorf.de> Author: Timo Paulssen Branch: numpy-singledim Changeset: r45572:35414c5cfac1 Date: 2011-07-13 18:08 +0200 http://bitbucket.org/pypy/pypy/changeset/35414c5cfac1/ Log: added size and ndim properties to numpy array. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -244,6 +244,12 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_get_size(self, space): + return self.get_concrete().descr_len(space) + + def descr_get_ndim(self, space): + return self.get_concrete().descr_get_ndim(space) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -467,6 +473,9 @@ def descr_len(self, space): return space.wrap(self.size) + def descr_get_ndim(self, space): + return space.wrap(1) + def getitem(self, item): return self.storage[item] @@ -507,6 +516,8 @@ __new__ = interp2app(descr_new_numarray), shape = GetSetProperty(BaseArray.descr_get_shape), + size = GetSetProperty(BaseArray.descr_get_size), + ndim = GetSetProperty(BaseArray.descr_get_ndim), __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -66,6 +66,18 @@ assert len(a) == 5 assert len(a + a) == 5 + def test_ndim(self): + from numpy import array + a = array(range(4)) + assert a.ndim == 1 + assert (a + a).ndim == 1 + + def test_size(self): + from numpy import array + a = array(range(4)) + assert a.size == 4 + assert (a + a).size == 4 + def test_shape(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Wed Jul 13 23:33:01 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Wed, 13 Jul 2011 23:33:01 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: micronumpy: Changed descr_get_size to work better with future larger dimensional arrays Message-ID: <20110713213301.9801D8291A@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45573:f704a8f5c76d Date: 2011-07-13 15:30 -0600 http://bitbucket.org/pypy/pypy/changeset/f704a8f5c76d/ Log: micronumpy: Changed descr_get_size to work better with future larger dimensional arrays diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -245,7 +245,7 @@ return self.get_concrete().descr_len(space) def descr_get_size(self, space): - return self.get_concrete().descr_len(space) + return self.get_concrete().descr_get_size(space) def descr_get_ndim(self, space): return self.get_concrete().descr_get_ndim(space) @@ -473,6 +473,8 @@ def descr_len(self, space): return space.wrap(self.size) + descr_get_size = descr_len + def descr_get_ndim(self, space): return space.wrap(1) From noreply at buildbot.pypy.org Wed Jul 13 23:45:11 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Wed, 13 Jul 2011 23:45:11 +0200 (CEST) Subject: [pypy-commit] pypy default: numpy merge for ndim and size Message-ID: <20110713214511.B4BAF8291A@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45574:df41087675e6 Date: 2011-07-13 15:45 -0600 http://bitbucket.org/pypy/pypy/changeset/df41087675e6/ Log: numpy merge for ndim and size diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -244,6 +244,12 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_get_size(self, space): + return self.get_concrete().descr_get_size(space) + + def descr_get_ndim(self, space): + return self.get_concrete().descr_get_ndim(space) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -467,6 +473,11 @@ def descr_len(self, space): return space.wrap(self.size) + descr_get_size = descr_len + + def descr_get_ndim(self, space): + return space.wrap(1) + def getitem(self, item): return self.storage[item] @@ -507,6 +518,8 @@ __new__ = interp2app(descr_new_numarray), shape = GetSetProperty(BaseArray.descr_get_shape), + size = GetSetProperty(BaseArray.descr_get_size), + ndim = GetSetProperty(BaseArray.descr_get_ndim), __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -66,6 +66,18 @@ assert len(a) == 5 assert len(a + a) == 5 + def test_ndim(self): + from numpy import array + a = array(range(4)) + assert a.ndim == 1 + assert (a + a).ndim == 1 + + def test_size(self): + from numpy import array + a = array(range(4)) + assert a.size == 4 + assert (a + a).size == 4 + def test_shape(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Thu Jul 14 03:25:41 2011 From: noreply at buildbot.pypy.org (Timo Paulssen) Date: Thu, 14 Jul 2011 03:25:41 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: implement numpy.array.__repr__ with test. Message-ID: <20110714012541.5AB158291A@wyvern.cs.uni-duesseldorf.de> Author: Timo Paulssen Branch: numpy-singledim Changeset: r45575:05c6eea4919f Date: 2011-07-13 23:17 +0200 http://bitbucket.org/pypy/pypy/changeset/05c6eea4919f/ Log: implement numpy.array.__repr__ with test. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -269,6 +269,12 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) + def descr_repr(self, space): + concrete = self.get_concrete() + return space.wrap("array([" + + " ".join([str(concrete.getitem(index)) for index in range(concrete.find_size())]) + + "])") + def convert_to_array (space, w_obj): if isinstance(w_obj, BaseArray): return w_obj @@ -540,6 +546,7 @@ __rdiv__ = interp2app(BaseArray.descr_rdiv), __rpow__ = interp2app(BaseArray.descr_rpow), __rmod__ = interp2app(BaseArray.descr_rmod), + __repr__ = interp2app(BaseArray.descr_repr), mean = interp2app(BaseArray.descr_mean), sum = interp2app(BaseArray.descr_sum), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -43,6 +43,11 @@ a = array(range(5)) assert a[3] == 3 + def test_repr(self): + from numpy import array + a = array(range(5)) + assert repr(a) == "array([0.0 1.0 2.0 3.0 4.0])" + def test_getitem(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Thu Jul 14 03:25:42 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 14 Jul 2011 03:25:42 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: numpy - fixed repr and added str Message-ID: <20110714012542.8706A8291A@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45576:fe7fb5a882ab Date: 2011-07-13 17:46 -0600 http://bitbucket.org/pypy/pypy/changeset/fe7fb5a882ab/ Log: numpy - fixed repr and added str diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -250,6 +250,12 @@ def descr_get_ndim(self, space): return self.get_concrete().descr_get_ndim(space) + def descr_repr(self, space): + return self.get_concrete().descr_repr(space) + + def descr_str(self, space): + return self.get_concrete().descr_str(space) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -269,11 +275,7 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) - def descr_repr(self, space): - concrete = self.get_concrete() - return space.wrap("array([" + - " ".join([str(concrete.getitem(index)) for index in range(concrete.find_size())]) + - "])") + def convert_to_array (space, w_obj): if isinstance(w_obj, BaseArray): @@ -487,6 +489,24 @@ def getitem(self, item): return self.storage[item] + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def descr_repr(self, space): + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def descr_str(self,space): + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) @@ -547,6 +567,7 @@ __rpow__ = interp2app(BaseArray.descr_rpow), __rmod__ = interp2app(BaseArray.descr_rmod), __repr__ = interp2app(BaseArray.descr_repr), + __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), sum = interp2app(BaseArray.descr_sum), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -44,9 +44,18 @@ assert a[3] == 3 def test_repr(self): - from numpy import array + from numpy import array, zeros a = array(range(5)) - assert repr(a) == "array([0.0 1.0 2.0 3.0 4.0])" + assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" + a = zeros(1001) + assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_str(self): + from numpy import array, zeros + a = array(range(5)) + assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + a = zeros(1001) + assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" def test_getitem(self): from numpy import array From noreply at buildbot.pypy.org Thu Jul 14 03:25:43 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 14 Jul 2011 03:25:43 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: numpy merge Message-ID: <20110714012543.AD0AF8291A@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45577:f8ea9d70d630 Date: 2011-07-13 19:21 -0600 http://bitbucket.org/pypy/pypy/changeset/f8ea9d70d630/ Log: numpy merge From noreply at buildbot.pypy.org Thu Jul 14 03:25:44 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 14 Jul 2011 03:25:44 +0200 (CEST) Subject: [pypy-commit] pypy default: numpy merge Message-ID: <20110714012544.D91AE8291A@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45578:dbaf01243418 Date: 2011-07-13 19:25 -0600 http://bitbucket.org/pypy/pypy/changeset/dbaf01243418/ Log: numpy merge diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -250,6 +250,12 @@ def descr_get_ndim(self, space): return self.get_concrete().descr_get_ndim(space) + def descr_repr(self, space): + return self.get_concrete().descr_repr(space) + + def descr_str(self, space): + return self.get_concrete().descr_str(space) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -269,6 +275,8 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) + + def convert_to_array (space, w_obj): if isinstance(w_obj, BaseArray): return w_obj @@ -481,6 +489,24 @@ def getitem(self, item): return self.storage[item] + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def descr_repr(self, space): + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def descr_str(self,space): + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) @@ -540,6 +566,8 @@ __rdiv__ = interp2app(BaseArray.descr_rdiv), __rpow__ = interp2app(BaseArray.descr_rpow), __rmod__ = interp2app(BaseArray.descr_rmod), + __repr__ = interp2app(BaseArray.descr_repr), + __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), sum = interp2app(BaseArray.descr_sum), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -43,6 +43,20 @@ a = array(range(5)) assert a[3] == 3 + def test_repr(self): + from numpy import array, zeros + a = array(range(5)) + assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" + a = zeros(1001) + assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_str(self): + from numpy import array, zeros + a = array(range(5)) + assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + a = zeros(1001) + assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_getitem(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Thu Jul 14 09:56:38 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 14 Jul 2011 09:56:38 +0200 (CEST) Subject: [pypy-commit] pypy default: Backed out changeset dbaf01243418 Message-ID: <20110714075638.3A6148291A@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45579:aeec0a828b6c Date: 2011-07-14 09:55 +0200 http://bitbucket.org/pypy/pypy/changeset/aeec0a828b6c/ Log: Backed out changeset dbaf01243418 * size and ndim should not force array * repr should be more compatible with original numpy diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -250,12 +250,6 @@ def descr_get_ndim(self, space): return self.get_concrete().descr_get_ndim(space) - def descr_repr(self, space): - return self.get_concrete().descr_repr(space) - - def descr_str(self, space): - return self.get_concrete().descr_str(space) - def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -275,8 +269,6 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) - - def convert_to_array (space, w_obj): if isinstance(w_obj, BaseArray): return w_obj @@ -489,24 +481,6 @@ def getitem(self, item): return self.storage[item] - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def descr_repr(self, space): - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def descr_str(self,space): - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) @@ -566,8 +540,6 @@ __rdiv__ = interp2app(BaseArray.descr_rdiv), __rpow__ = interp2app(BaseArray.descr_rpow), __rmod__ = interp2app(BaseArray.descr_rmod), - __repr__ = interp2app(BaseArray.descr_repr), - __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), sum = interp2app(BaseArray.descr_sum), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -43,20 +43,6 @@ a = array(range(5)) assert a[3] == 3 - def test_repr(self): - from numpy import array, zeros - a = array(range(5)) - assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" - a = zeros(1001) - assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" - - def test_str(self): - from numpy import array, zeros - a = array(range(5)) - assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" - a = zeros(1001) - assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" - def test_getitem(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Thu Jul 14 09:56:39 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 14 Jul 2011 09:56:39 +0200 (CEST) Subject: [pypy-commit] pypy default: more backout Message-ID: <20110714075639.68AB48291A@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45580:614108ceefb7 Date: 2011-07-14 09:56 +0200 http://bitbucket.org/pypy/pypy/changeset/614108ceefb7/ Log: more backout diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -244,12 +244,6 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) - def descr_get_size(self, space): - return self.get_concrete().descr_get_size(space) - - def descr_get_ndim(self, space): - return self.get_concrete().descr_get_ndim(space) - def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -473,11 +467,6 @@ def descr_len(self, space): return space.wrap(self.size) - descr_get_size = descr_len - - def descr_get_ndim(self, space): - return space.wrap(1) - def getitem(self, item): return self.storage[item] @@ -518,8 +507,6 @@ __new__ = interp2app(descr_new_numarray), shape = GetSetProperty(BaseArray.descr_get_shape), - size = GetSetProperty(BaseArray.descr_get_size), - ndim = GetSetProperty(BaseArray.descr_get_ndim), __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -66,18 +66,6 @@ assert len(a) == 5 assert len(a + a) == 5 - def test_ndim(self): - from numpy import array - a = array(range(4)) - assert a.ndim == 1 - assert (a + a).ndim == 1 - - def test_size(self): - from numpy import array - a = array(range(4)) - assert a.size == 4 - assert (a + a).size == 4 - def test_shape(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Thu Jul 14 10:31:40 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 14 Jul 2011 10:31:40 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (cfbolz, arigo): write a test that runs the jit on cppyy directly without translating the full interpreter Message-ID: <20110714083140.4B93E8291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45581:948ee9c5e9ab Date: 2011-07-13 17:58 +0200 http://bitbucket.org/pypy/pypy/changeset/948ee9c5e9ab/ Log: (cfbolz, arigo): write a test that runs the jit on cppyy directly without translating the full interpreter diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -37,9 +37,9 @@ return a.typeannotation(t) def annotate(func, values, inline=None, backendoptimize=True, - type_system="lltype"): + type_system="lltype", listcomp=False): # build the normal ll graphs for ll_function - t = TranslationContext() + t = TranslationContext(list_comprehension_operations=listcomp) annpolicy = AnnotatorPolicy() annpolicy.allow_someobjects = False a = t.buildannotator(policy=annpolicy) diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -42,7 +42,7 @@ enable_opts = ALL_OPTS_DICT func._jit_unroll_safe_ = True - rtyper = support.annotate(func, values, type_system=type_system) + rtyper = support.annotate(func, values, type_system=type_system, listcomp=kwds.get("listcomp", False)) graphs = rtyper.annotator.translator.graphs testself.all_graphs = graphs result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0] diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -92,7 +92,7 @@ def unpack_simple_shape(space, w_shape): # 'w_shape' must be either a letter or a tuple (struct, 1). - if space.is_true(space.isinstance(w_shape, space.w_str)): + if space.isinstance_w(w_shape, space.w_str): letter = space.str_w(w_shape) return letter2tp(space, letter) else: diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -87,6 +87,8 @@ self.size = array_size def from_memory(self, space, w_obj, offset): + if hasattr(space, "fake"): + raise NotImplementedError # read access, so no copy needed address_value = self._get_raw_address(space, w_obj, offset) address = rffi.cast(rffi.ULONG, address_value) diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -32,6 +32,8 @@ typecode = 'P' def execute(self, space, func, cppthis, num_args, args): + if hasattr(space, "fake"): + raise NotImplementedError lresult = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) address = rffi.cast(rffi.ULONG, lresult) arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode))) @@ -246,6 +248,7 @@ return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) def execute_libffi(self, space, libffifunc, argchain): + from pypy.module.cppyy import interp_cppyy result = libffifunc.call(argchain, rffi.VOIDP) return interp_cppyy.W_CPPInstance(space, self.cpptype, result, False) diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -51,7 +51,7 @@ assert res == 4 res = t.invoke(t.get_overload("staticAddOneToInt"), -1) assert res == 0 - maxint32 = int(math.pow(2,31)-1) + maxint32 = int(2 ** 31 - 1) res = t.invoke(t.get_overload("staticAddOneToInt"), maxint32-1) assert res == maxint32 res = t.invoke(t.get_overload("staticAddOneToInt"), maxint32) diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py --- a/pypy/module/cppyy/test/test_pythonify.py +++ b/pypy/module/cppyy/test/test_pythonify.py @@ -52,7 +52,7 @@ assert res == 4 res = example01_class.staticAddOneToInt(-1) assert res == 0 - maxint32 = int(math.pow(2,31)-1) + maxint32 = int(2 ** 31 - 1) res = example01_class.staticAddOneToInt(maxint32-1) assert res == maxint32 res = example01_class.staticAddOneToInt(maxint32) diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/test_zjit.py @@ -0,0 +1,122 @@ +from pypy.jit.metainterp.test.support import LLJitMixin +from pypy.rlib.objectmodel import specialize +from pypy.rlib import rarithmetic +from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root + +from pypy.module.cppyy import interp_cppyy + +class FakeBase(W_Root): + typename = None + +class FakeInt(FakeBase): + typename = "int" + def __init__(self, val): + self.val = val +class FakeFloat(FakeBase): + typename = "float" + def __init__(self, val): + self.val = val +class FakeString(FakeBase): + typename = "str" + def __init__(self, val): + self.val = val +class FakeType(FakeBase): + typename = "type" + def __init__(self, name): + self.name = name + def getname(self, space, name): + return self.name + + + + +class FakeSpace(object): + fake = True + + w_ValueError = FakeType("ValueError") + w_TypeError = FakeType("TypeError") + w_AttributeError = FakeType("AttributeError") + w_ReferenceError = FakeType("ReferenceError") + + w_None = None + w_str = FakeType("str") + w_int = FakeType("int") + w_float = FakeType("float") + + def __init__(self): + self.fromcache = InternalSpaceCache(self).getorbuild + + def issequence_w(self, w_obj): + return True + + @specialize.argtype(1) + def wrap(self, obj): + if isinstance(obj, int): + return FakeInt(obj) + if isinstance(obj, float): + return FakeFloat(obj) + if isinstance(obj, str): + return FakeString(obj) + assert 0 + + def float_w(self, w_obj): + assert isinstance(w_obj, FakeFloat) + return w_obj.val + + def interp_w(self, RequiredClass, w_obj, can_be_None=False): + if can_be_None and w_obj is None: + return None + if not isinstance(w_obj, RequiredClass): + raise TypeError + return w_obj + interp_w._annspecialcase_ = 'specialize:arg(1)' + + def interpclass_w(self, w_obj): + return w_obj + + def exception_match(self, typ, sub): + return typ is sub + + def int_w(self, w_obj): + assert isinstance(w_obj, FakeInt) + return w_obj.val + + def uint_w(self, w_obj): + assert isinstance(w_obj, FakeInt) + return rarithmetic.r_uint(w_obj.val) + + + def str_w(self, w_obj): + assert isinstance(w_obj, FakeString) + return w_obj.val + + c_int_w = int_w + + def isinstance_w(self, w_obj, w_type): + assert isinstance(w_obj, FakeBase) + return w_obj.typename == w_type.name + + def type(self, w_obj): + return FakeType("fake") + + def findattr(self, w_obj, w_name): + return None + + def _freeze_(self): + return True + +class TestFastPathJIT(LLJitMixin): + def test_simple(self): + space = FakeSpace() + def f(): + lib = interp_cppyy.load_lib(space, "./example01Dict.so") + cls = interp_cppyy.type_byname(space, "example01") + inst = cls.construct([FakeInt(0)]) + addDataToInt = cls.get_overload("addDataToInt") + assert isinstance(inst, interp_cppyy.W_CPPInstance) + inst.invoke(addDataToInt, [FakeInt(41)]) + return 7 + f() + space = FakeSpace() + result = self.interp_operations(f, [], listops=True, backendopt=True, listcomp=True) + From noreply at buildbot.pypy.org Thu Jul 14 10:31:41 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 14 Jul 2011 10:31:41 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, cfbolz): use a driver instead Message-ID: <20110714083141.78EE18291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45582:3a97a5046d82 Date: 2011-07-13 18:17 +0200 http://bitbucket.org/pypy/pypy/changeset/3a97a5046d82/ Log: (arigo, cfbolz): use a driver instead diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py --- a/pypy/module/cppyy/test/test_zjit.py +++ b/pypy/module/cppyy/test/test_zjit.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rlib.objectmodel import specialize -from pypy.rlib import rarithmetic +from pypy.rlib import rarithmetic, jit from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root from pypy.module.cppyy import interp_cppyy @@ -108,15 +108,20 @@ class TestFastPathJIT(LLJitMixin): def test_simple(self): space = FakeSpace() + drv = jit.JitDriver(greens=[], reds=["i", "inst", "addDataToInt"]) def f(): lib = interp_cppyy.load_lib(space, "./example01Dict.so") cls = interp_cppyy.type_byname(space, "example01") inst = cls.construct([FakeInt(0)]) addDataToInt = cls.get_overload("addDataToInt") assert isinstance(inst, interp_cppyy.W_CPPInstance) - inst.invoke(addDataToInt, [FakeInt(41)]) + i = 10 + while i > 0: + drv.jit_merge_point(inst=inst, addDataToInt=addDataToInt, i=i) + inst.invoke(addDataToInt, [FakeInt(i)]) + i -= 1 return 7 f() space = FakeSpace() - result = self.interp_operations(f, [], listops=True, backendopt=True, listcomp=True) - + result = self.meta_interp(f, [], listops=True, backendopt=True, listcomp=True) + self.check_loops(call=0, call_release_gil=1) From noreply at buildbot.pypy.org Thu Jul 14 10:31:42 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 14 Jul 2011 10:31:42 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge Message-ID: <20110714083142.A632F8291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45583:5a36ac4cbf9f Date: 2011-07-13 18:17 +0200 http://bitbucket.org/pypy/pypy/changeset/5a36ac4cbf9f/ Log: merge diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -359,7 +359,8 @@ return rffi.cast(rffi.VOIDP, x) def convert_argument_libffi(self, space, w_obj, argchain): - argchain.arg_singlefloat(self._unwrap_object(space, w_obj)) + # it's required to sent an rffi.DOUBLE not r_singlefloat + argchain.arg_singlefloat(space.float_w(w_obj)) def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) From noreply at buildbot.pypy.org Thu Jul 14 10:31:43 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 14 Jul 2011 10:31:43 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge Message-ID: <20110714083143.DA59D8291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45584:14fa95c53e4b Date: 2011-07-14 10:31 +0200 http://bitbucket.org/pypy/pypy/changeset/14fa95c53e4b/ Log: merge diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -21,7 +21,7 @@ cpp_instance = space.interp_w(W_CPPInstance, w_cpp_instance, can_be_None=True) if cpp_instance: return cpp_instance.rawobject - return lltype.nullptr(rffi.VOIDP.TO) + return lltype.nullptr(rffi.CCHARP.TO) class TypeConverter(object): @@ -35,6 +35,7 @@ def _get_raw_address(self, space, w_obj, offset): rawobject = get_rawobject(space, w_obj) if rawobject: + assert lltype.typeOf(rawobject) == rffi.CCHARP field_address = lltype.direct_ptradd(rawobject, offset) fieldptr = rffi.cast(rffi.CCHARP, field_address) else: @@ -123,6 +124,7 @@ def to_memory(self, space, w_obj, w_value, offset): # copy only the pointer value rawobject = get_rawobject(space, w_obj) + assert lltype.typeOf(rawobject) == rffi.CCHARP field_address = lltype.direct_ptradd(rawobject, offset) byteptr = rffi.cast(rffi.CCHARPP, field_address) buf = space.buffer_w(w_value) @@ -490,6 +492,7 @@ if isinstance(obj, W_CPPInstance): if capi.c_is_subtype(obj.cppclass.handle, self.cpptype.handle): offset = capi.c_base_offset(obj.cppclass.handle, self.cpptype.handle) + assert lltype.typeOf(obj.rawobject) == rffi.CCHARP obj_address = lltype.direct_ptradd(obj.rawobject, offset) objptr = rffi.cast(rffi.VOIDP, obj_address) return objptr @@ -512,9 +515,8 @@ def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) - obj_address = rffi.cast(rffi.VOIDP, address) from pypy.module.cppyy import interp_cppyy - return interp_cppyy.W_CPPInstance(space, self.cpptype, obj_address, False) + return interp_cppyy.W_CPPInstance(space, self.cpptype, address, False) def free_argument(self, arg): pass diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -244,7 +244,7 @@ def execute(self, space, func, cppthis, num_args, args): from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) - ptr_result = rffi.cast(rffi.VOIDP, long_result) + ptr_result = rffi.cast(rffi.CCHARP, long_result) return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) def execute_libffi(self, space, libffifunc, argchain): @@ -260,7 +260,7 @@ from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_o( func.cpptype.handle, func.method_index, cppthis, num_args, args, self.cpptype.handle) - ptr_result = rffi.cast(rffi.VOIDP, long_result) + ptr_result = rffi.cast(rffi.CCHARP, long_result) return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, True) diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -15,7 +15,8 @@ class FastCallNotPossible(Exception): pass -NULL_VOIDP = lltype.nullptr(rffi.VOIDP.TO) +NULL_CCHARP = lltype.nullptr(rffi.CCHARP.TO) +NULL_VOIDP = lltype.nullptr(rffi.VOIDP.TO) def load_lib(space, name): # TODO: allow open in RTLD_GLOBAL mode @@ -126,7 +127,7 @@ if self.arg_converters is None: self._build_converters() jit.promote(self) - funcptr = self.methgetter(cppthis) + funcptr = self.methgetter(rffi.cast(rffi.VOIDP, cppthis)) libffi_func = self._get_libffi_func(funcptr) if not libffi_func: raise FastCallNotPossible @@ -210,7 +211,7 @@ assert not cppthis args = self.prepare_arguments(args_w) try: - return self.executor.execute(self.space, self, NULL_VOIDP, + return self.executor.execute(self.space, self, NULL_CCHARP, len(args_w), args) finally: self.free_arguments(args, len(args_w)) @@ -222,12 +223,13 @@ def call(self, cppthis, args_w): assert not cppthis newthis = capi.c_allocate(self.cpptype.handle) + ccharp_this = rffi.cast(rffi.CCHARP, newthis) try: - CPPMethod.call(self, newthis, args_w) + CPPMethod.call(self, ccharp_this, args_w) except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) raise - return W_CPPInstance(self.space, self.cpptype, newthis, True) + return W_CPPInstance(self.space, self.cpptype, ccharp_this, True) class W_CPPOverload(Wrappable): @@ -250,7 +252,7 @@ if cppinstance: cppthis = cppinstance.rawobject else: - cppthis = NULL_VOIDP + cppthis = NULL_CCHARP space = self.space errmsg = 'None of the overloads matched:' @@ -534,6 +536,7 @@ def __init__(self, space, cppclass, rawobject, python_owns): self.space = space self.cppclass = cppclass + assert lltype.typeOf(rawobject) == rffi.CCHARP self.rawobject = rawobject self.python_owns = python_owns @@ -548,7 +551,7 @@ def destruct(self): if self.rawobject: capi.c_destruct(self.cppclass.handle, self.rawobject) - self.rawobject = NULL_VOIDP + self.rawobject = NULL_CCHARP def __del__(self): if self.python_owns: From noreply at buildbot.pypy.org Thu Jul 14 10:54:07 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 14 Jul 2011 10:54:07 +0200 (CEST) Subject: [pypy-commit] pypy default: consistent capitalization Message-ID: <20110714085407.E336F8291A@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45585:ab1c0e7ecfa5 Date: 2011-07-14 10:53 +0200 http://bitbucket.org/pypy/pypy/changeset/ab1c0e7ecfa5/ Log: consistent capitalization diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -482,7 +482,7 @@ # rawstart = self.materialize_loop(original_loop_token) debug_start("jit-backend-addr") - debug_print("Bridge out of Guard %d has address %x to %x" % + debug_print("bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -337,8 +337,13 @@ addrs = {} for entry in extract_category(log, 'jit-backend-addr'): m = re.search('bootstrap ([\da-f]+)', entry) - name = entry[:entry.find('(') - 1] - addrs[int(m.group(1), 16)] = name + if not m: + # a bridge + m = re.search('has address ([\da-f]+)', entry) + addr = int(m.group(1), 16) + else: + name = entry[:entry.find('(') - 1] + addrs[int(m.group(1), 16)] = name dumps = {} for entry in extract_category(log, 'jit-backend-dump'): backend, _, dump, _ = entry.split("\n") @@ -358,5 +363,7 @@ bname, start_ofs, dump = dumps[name] parser.postprocess(loop, backend_tp=bname, backend_dump=dump, dump_start=start_ofs) + else: + xxx loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -214,3 +214,8 @@ _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) assert 'jge' in loops[0].operations[3].asm + +def test_import_log_2(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest2.log'))) + xxx From noreply at buildbot.pypy.org Thu Jul 14 11:04:10 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 14 Jul 2011 11:04:10 +0200 (CEST) Subject: [pypy-commit] pypy default: support bridges Message-ID: <20110714090410.C9E178291A@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45586:e152619384f9 Date: 2011-07-14 11:03 +0200 http://bitbucket.org/pypy/pypy/changeset/e152619384f9/ Log: support bridges diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -341,8 +341,11 @@ # a bridge m = re.search('has address ([\da-f]+)', entry) addr = int(m.group(1), 16) + entry = entry.lower() + m = re.search('guard \d+', entry) + addrs[addr] = m.group(0) else: - name = entry[:entry.find('(') - 1] + name = entry[:entry.find('(') - 1].lower() addrs[int(m.group(1), 16)] = name dumps = {} for entry in extract_category(log, 'jit-backend-dump'): @@ -358,12 +361,15 @@ nonstrict=True) loop = parser.parse() comm = loop.comment - name = comm[2:comm.find(':')-1] + comm = comm.lower() + if comm.startswith('# bridge'): + m = re.search('guard \d+', comm) + name = m.group(0) + else: + name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] parser.postprocess(loop, backend_tp=bname, backend_dump=dump, dump_start=start_ofs) - else: - xxx loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -218,4 +218,6 @@ def test_import_log_2(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest2.log'))) - xxx + assert 'cmp' in loops[1].operations[1].asm + # bridge + assert 'cmp' in loops[3].operations[1].asm From noreply at buildbot.pypy.org Thu Jul 14 11:35:44 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 14 Jul 2011 11:35:44 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: refactoring and another attempt at ccharp vs voidp consistency Message-ID: <20110714093544.97AA48291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45587:281a4df60741 Date: 2011-07-14 02:35 -0700 http://bitbucket.org/pypy/pypy/changeset/281a4df60741/ Log: refactoring and another attempt at ccharp vs voidp consistency diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -12,21 +12,24 @@ from pypy.module.cppyy import helper, capi -NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO) - def get_rawobject(space, w_obj): if not space.eq_w(w_obj, space.w_None): from pypy.module.cppyy.interp_cppyy import W_CPPInstance w_cpp_instance = space.findattr(w_obj, space.wrap("_cppinstance")) cpp_instance = space.interp_w(W_CPPInstance, w_cpp_instance, can_be_None=True) if cpp_instance: + assert lltype.typeOf(cpp_instance.rawobject) == rffi.VOIDP return cpp_instance.rawobject - return lltype.nullptr(rffi.CCHARP.TO) + return lltype.nullptr(rffi.VOIDP.TO) + +def _direct_ptradd(ptr, offset): + address = rffi.cast(rffi.CCHARP, ptr) + return rffi.cast(rffi.CCHARP, lltype.direct_ptradd(address, offset)) class TypeConverter(object): _immutable = True - libffitype = NULL + libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO) def __init__(self, space, array_size): pass @@ -35,9 +38,7 @@ def _get_raw_address(self, space, w_obj, offset): rawobject = get_rawobject(space, w_obj) if rawobject: - assert lltype.typeOf(rawobject) == rffi.CCHARP - field_address = lltype.direct_ptradd(rawobject, offset) - fieldptr = rffi.cast(rffi.CCHARP, field_address) + fieldptr = _direct_ptradd(rawobject, offset) else: fieldptr = rffi.cast(rffi.CCHARP, offset) return fieldptr @@ -124,9 +125,7 @@ def to_memory(self, space, w_obj, w_value, offset): # copy only the pointer value rawobject = get_rawobject(space, w_obj) - assert lltype.typeOf(rawobject) == rffi.CCHARP - field_address = lltype.direct_ptradd(rawobject, offset) - byteptr = rffi.cast(rffi.CCHARPP, field_address) + byteptr = rffi.cast(rffi.CCHARPP, _direct_ptradd(rawobject, offset)) buf = space.buffer_w(w_value) try: byteptr[0] = buf.get_raw_address() @@ -492,10 +491,8 @@ if isinstance(obj, W_CPPInstance): if capi.c_is_subtype(obj.cppclass.handle, self.cpptype.handle): offset = capi.c_base_offset(obj.cppclass.handle, self.cpptype.handle) - assert lltype.typeOf(obj.rawobject) == rffi.CCHARP - obj_address = lltype.direct_ptradd(obj.rawobject, offset) - objptr = rffi.cast(rffi.VOIDP, obj_address) - return objptr + obj_address = _direct_ptradd(obj.rawobject, offset) + return rffi.cast(rffi.VOIDP, obj_address) raise OperationError(space.w_TypeError, space.wrap("cannot pass %s as %s" % ( space.type(w_obj).getname(space, "?"), @@ -514,7 +511,7 @@ _immutable_ = True def from_memory(self, space, w_obj, offset): - address = self._get_raw_address(space, w_obj, offset) + address = rffi.cast(rffi.VOIDP, self._get_raw_address(space, w_obj, offset)) from pypy.module.cppyy import interp_cppyy return interp_cppyy.W_CPPInstance(space, self.cpptype, address, False) diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -243,14 +243,15 @@ def execute(self, space, func, cppthis, num_args, args): from pypy.module.cppyy import interp_cppyy - long_result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) - ptr_result = rffi.cast(rffi.CCHARP, long_result) + long_result = capi.c_call_l( + func.cpptype.handle, func.method_index, cppthis, num_args, args) + ptr_result = rffi.cast(rffi.VOIDP, long_result) return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) def execute_libffi(self, space, libffifunc, argchain): from pypy.module.cppyy import interp_cppyy - result = libffifunc.call(argchain, rffi.VOIDP) - return interp_cppyy.W_CPPInstance(space, self.cpptype, result, False) + ptr_result = rffi.cast(rffi.VOIDP, libffifunc.call(argchain, rffi.VOIDP)) + return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) class InstanceExecutor(InstancePtrExecutor): @@ -260,7 +261,7 @@ from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_o( func.cpptype.handle, func.method_index, cppthis, num_args, args, self.cpptype.handle) - ptr_result = rffi.cast(rffi.CCHARP, long_result) + ptr_result = rffi.cast(rffi.VOIDP, long_result) return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, True) diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -15,7 +15,6 @@ class FastCallNotPossible(Exception): pass -NULL_CCHARP = lltype.nullptr(rffi.CCHARP.TO) NULL_VOIDP = lltype.nullptr(rffi.VOIDP.TO) def load_lib(space, name): @@ -103,8 +102,10 @@ self._libffifunc_cache = {} def call(self, cppthis, args_w): + assert lltype.typeOf(cppthis) == rffi.VOIDP if self.executor is None: - raise OperationError(self.space.w_TypeError, self.space.wrap("return type not handled")) + raise OperationError(self.space.w_TypeError, + self.space.wrap("return type not handled")) if self.methgetter and cppthis: # only for methods try: @@ -205,13 +206,15 @@ _immutable_ = True def call(self, cppthis, args_w): + assert lltype.typeOf(cppthis) == rffi.VOIDP if self.executor is None: - raise OperationError(self.space.w_TypeError, self.space.wrap("return type not handled")) + raise OperationError(self.space.w_TypeError, + self.space.wrap("return type not handled")) assert not cppthis args = self.prepare_arguments(args_w) try: - return self.executor.execute(self.space, self, NULL_CCHARP, + return self.executor.execute(self.space, self, NULL_VOIDP, len(args_w), args) finally: self.free_arguments(args, len(args_w)) @@ -223,13 +226,13 @@ def call(self, cppthis, args_w): assert not cppthis newthis = capi.c_allocate(self.cpptype.handle) - ccharp_this = rffi.cast(rffi.CCHARP, newthis) + assert lltype.typeOf(newthis) == rffi.VOIDP try: - CPPMethod.call(self, ccharp_this, args_w) + CPPMethod.call(self, newthis, args_w) except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) raise - return W_CPPInstance(self.space, self.cpptype, ccharp_this, True) + return W_CPPInstance(self.space, self.cpptype, newthis, True) class W_CPPOverload(Wrappable): @@ -252,7 +255,8 @@ if cppinstance: cppthis = cppinstance.rawobject else: - cppthis = NULL_CCHARP + cppthis = NULL_VOIDP + assert lltype.typeOf(cppthis) == rffi.VOIDP space = self.space errmsg = 'None of the overloads matched:' @@ -536,13 +540,14 @@ def __init__(self, space, cppclass, rawobject, python_owns): self.space = space self.cppclass = cppclass - assert lltype.typeOf(rawobject) == rffi.CCHARP + assert lltype.typeOf(rawobject) == rffi.VOIDP self.rawobject = rawobject self.python_owns = python_owns def _nullcheck(self): if not self.rawobject: - raise OperationError(self.space.w_ReferenceError, self.space.wrap("trying to access a NULL pointer")) + raise OperationError(self.space.w_ReferenceError, + self.space.wrap("trying to access a NULL pointer")) def invoke(self, overload, args_w): self._nullcheck() @@ -551,7 +556,7 @@ def destruct(self): if self.rawobject: capi.c_destruct(self.cppclass.handle, self.rawobject) - self.rawobject = NULL_CCHARP + self.rawobject = NULL_VOIDP def __del__(self): if self.python_owns: From noreply at buildbot.pypy.org Thu Jul 14 13:14:02 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 14 Jul 2011 13:14:02 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, cfbolz, wlav) fix test for 64b mac Message-ID: <20110714111402.D26D18291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45588:f8c113c6e3c5 Date: 2011-07-14 04:13 -0700 http://bitbucket.org/pypy/pypy/changeset/f8c113c6e3c5/ Log: (arigo, cfbolz, wlav) fix test for 64b mac diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py --- a/pypy/module/cppyy/test/test_zjit.py +++ b/pypy/module/cppyy/test/test_zjit.py @@ -1,6 +1,7 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rlib.objectmodel import specialize from pypy.rlib import rarithmetic, jit +from pypy.rpython.lltypesystem import rffi from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root from pypy.module.cppyy import interp_cppyy @@ -57,6 +58,8 @@ return FakeFloat(obj) if isinstance(obj, str): return FakeString(obj) + if isinstance(obj, rffi.r_int): + return FakeInt(int(obj)) assert 0 def float_w(self, w_obj): From noreply at buildbot.pypy.org Thu Jul 14 14:22:01 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 14 Jul 2011 14:22:01 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: make life a little easier testing on Mac Message-ID: <20110714122201.BE85A8291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45589:35d45de496ad Date: 2011-07-14 05:21 -0700 http://bitbucket.org/pypy/pypy/changeset/35d45de496ad/ Log: make life a little easier testing on Mac diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile --- a/pypy/module/cppyy/test/Makefile +++ b/pypy/module/cppyy/test/Makefile @@ -10,6 +10,11 @@ cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib endif +PLATFORM := $(shell uname -s) +ifeq ($(PLATFORM),Darwin) + cppflags+=-dynamiclib -single_module -arch x86_64 +endif + ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),) genreflexflags= cppflags2=-O3 @@ -18,6 +23,7 @@ cppflags2=-Wno-pmf-conversions -O3 endif + example01Dict.so: example01.cxx example01.h example01.xml $(genreflex) example01.h $(genreflexflags) --selection=example01.xml g++ -o $@ example01_rflx.cpp example01.cxx -shared -lReflex $(cppflags) $(cppflags2) @@ -40,4 +46,3 @@ operatorsDict.so: operators.cxx operators.h $(genreflex) operators.h g++ -o $@ operators_rflx.cpp operators.cxx -shared -lReflex $(cppflags) $(cppflags2) - From noreply at buildbot.pypy.org Thu Jul 14 15:06:35 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 14 Jul 2011 15:06:35 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: add a promote and a test for it Message-ID: <20110714130635.E9CCB8291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45590:ce41ead106ca Date: 2011-07-14 15:05 +0200 http://bitbucket.org/pypy/pypy/changeset/ce41ead106ca/ Log: add a promote and a test for it diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -260,6 +260,7 @@ space = self.space errmsg = 'None of the overloads matched:' + jit.promote(self) for i in range(len(self.functions)): cppyyfunc = self.functions[i] try: diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py --- a/pypy/module/cppyy/test/test_zjit.py +++ b/pypy/module/cppyy/test/test_zjit.py @@ -125,3 +125,4 @@ space = FakeSpace() result = self.meta_interp(f, [], listops=True, backendopt=True, listcomp=True) self.check_loops(call=0, call_release_gil=1) + self.check_loops(getarrayitem_gc_pure=0, everywhere=True) From noreply at buildbot.pypy.org Thu Jul 14 15:06:37 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 14 Jul 2011 15:06:37 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge Message-ID: <20110714130637.253378291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45591:169b3d988430 Date: 2011-07-14 15:06 +0200 http://bitbucket.org/pypy/pypy/changeset/169b3d988430/ Log: merge diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile --- a/pypy/module/cppyy/test/Makefile +++ b/pypy/module/cppyy/test/Makefile @@ -10,6 +10,11 @@ cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib endif +PLATFORM := $(shell uname -s) +ifeq ($(PLATFORM),Darwin) + cppflags+=-dynamiclib -single_module -arch x86_64 +endif + ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),) genreflexflags= cppflags2=-O3 @@ -18,6 +23,7 @@ cppflags2=-Wno-pmf-conversions -O3 endif + example01Dict.so: example01.cxx example01.h example01.xml $(genreflex) example01.h $(genreflexflags) --selection=example01.xml g++ -o $@ example01_rflx.cpp example01.cxx -shared -lReflex $(cppflags) $(cppflags2) @@ -40,4 +46,3 @@ operatorsDict.so: operators.cxx operators.h $(genreflex) operators.h g++ -o $@ operators_rflx.cpp operators.cxx -shared -lReflex $(cppflags) $(cppflags2) - diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py --- a/pypy/module/cppyy/test/test_zjit.py +++ b/pypy/module/cppyy/test/test_zjit.py @@ -1,6 +1,7 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rlib.objectmodel import specialize from pypy.rlib import rarithmetic, jit +from pypy.rpython.lltypesystem import rffi from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root from pypy.module.cppyy import interp_cppyy @@ -57,6 +58,8 @@ return FakeFloat(obj) if isinstance(obj, str): return FakeString(obj) + if isinstance(obj, rffi.r_int): + return FakeInt(int(obj)) assert 0 def float_w(self, w_obj): From noreply at buildbot.pypy.org Thu Jul 14 15:12:46 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 14 Jul 2011 15:12:46 +0200 (CEST) Subject: [pypy-commit] pypy default: Add a precise assert that will crash more cleanly than in the following 'if...'. Message-ID: <20110714131246.605BD8291A@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45592:1163bf4021a2 Date: 2011-07-14 15:12 +0200 http://bitbucket.org/pypy/pypy/changeset/1163bf4021a2/ Log: Add a precise assert that will crash more cleanly than in the following 'if...'. diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -96,6 +96,7 @@ def _try_coalesce(self, v, w): if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: + assert getkind(w.concretetype) == self.kind dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) From noreply at buildbot.pypy.org Thu Jul 14 15:34:50 2011 From: noreply at buildbot.pypy.org (gutworth) Date: Thu, 14 Jul 2011 15:34:50 +0200 (CEST) Subject: [pypy-commit] pypy default: actually add future related flags when compiling user ast (closes #795) Message-ID: <20110714133450.A73658291A@wyvern.cs.uni-duesseldorf.de> Author: Benjamin Peterson Branch: Changeset: r45593:ee7992bb45f7 Date: 2011-07-14 08:39 -0500 http://bitbucket.org/pypy/pypy/changeset/ee7992bb45f7/ Log: actually add future related flags when compiling user ast (closes #795) diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -27,9 +27,10 @@ _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset) -def parse_future(tree): +def parse_future(tree, feature_flags): future_lineno = 0 future_column = 0 + flags = 0 have_docstring = False body = None if isinstance(tree, ast.Module): @@ -37,7 +38,7 @@ elif isinstance(tree, ast.Interactive): body = tree.body if body is None: - return 0, 0 + return 0, 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): if have_docstring: @@ -48,11 +49,15 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset + for name in stmt.names: + # If this is an invalid flag, it will be caught later in + # codegen.py. + flags |= feature_flags.get(name.name, 0) else: break else: break - return future_lineno, future_column + return flags, future_lineno, future_column class ForbiddenNameAssignment(Exception): diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,10 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - future_pos = misc.parse_future(node) + fut = misc.parse_future(node, self.future_flags.compiler_features) + f_flags, f_lineno, f_col = fut + future_pos = f_lineno, f_col + flags |= f_flags info = pyparse.CompileInfo(filename, mode, flags, future_pos) return self._compile_ast(node, info) diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -186,6 +186,11 @@ mod = self.get_ast("from __future__ import with_statement; import y; " \ "from __future__ import nested_scopes") raises(SyntaxError, compile, mod, "", "exec") + mod = self.get_ast("from __future__ import division\nx = 1/2") + co = compile(mod, "", "exec") + ns = {} + exec co in ns + assert ns["x"] == .5 def test_field_attr_writable(self): import _ast as ast From noreply at buildbot.pypy.org Thu Jul 14 15:34:51 2011 From: noreply at buildbot.pypy.org (gutworth) Date: Thu, 14 Jul 2011 15:34:51 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110714133451.D2D568291A@wyvern.cs.uni-duesseldorf.de> Author: Benjamin Peterson Branch: Changeset: r45594:ec0511be1922 Date: 2011-07-14 08:39 -0500 http://bitbucket.org/pypy/pypy/changeset/ec0511be1922/ Log: merge heads diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -96,6 +96,7 @@ def _try_coalesce(self, v, w): if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: + assert getkind(w.concretetype) == self.kind dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) From noreply at buildbot.pypy.org Thu Jul 14 15:47:02 2011 From: noreply at buildbot.pypy.org (gutworth) Date: Thu, 14 Jul 2011 15:47:02 +0200 (CEST) Subject: [pypy-commit] pypy default: technically we should always have mandatory __future__ flags Message-ID: <20110714134702.AEDB98291A@wyvern.cs.uni-duesseldorf.de> Author: Benjamin Peterson Branch: Changeset: r45595:311ced346dbb Date: 2011-07-14 08:51 -0500 http://bitbucket.org/pypy/pypy/changeset/311ced346dbb/ Log: technically we should always have mandatory __future__ flags diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,6 +119,7 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) + flags |= self.future_flags.mandatory_flags fut = misc.parse_future(node, self.future_flags.compiler_features) f_flags, f_lineno, f_col = fut future_pos = f_lineno, f_col @@ -137,6 +138,7 @@ return code def compile_to_ast(self, source, filename, mode, flags): + flags |= self.future_flags.mandatory_flags info = pyparse.CompileInfo(filename, mode, flags) return self._compile_to_ast(source, info) @@ -154,6 +156,7 @@ return mod def compile(self, source, filename, mode, flags, hidden_applevel=False): + flags |= self.future_flags.mandatory_flags info = pyparse.CompileInfo(filename, mode, flags, hidden_applevel=hidden_applevel) mod = self._compile_to_ast(source, info) From noreply at buildbot.pypy.org Thu Jul 14 16:27:38 2011 From: noreply at buildbot.pypy.org (gutworth) Date: Thu, 14 Jul 2011 16:27:38 +0200 (CEST) Subject: [pypy-commit] pypy default: grumble, grumble the annotator does't know the annotation of alias list Message-ID: <20110714142738.75D298291A@wyvern.cs.uni-duesseldorf.de> Author: Benjamin Peterson Branch: Changeset: r45596:63342a547bd7 Date: 2011-07-14 09:32 -0500 http://bitbucket.org/pypy/pypy/changeset/63342a547bd7/ Log: grumble, grumble the annotator does't know the annotation of alias list diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -49,10 +49,11 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset - for name in stmt.names: + for alias in stmt.names: + assert isinstance(alias, ast.alias) # If this is an invalid flag, it will be caught later in # codegen.py. - flags |= feature_flags.get(name.name, 0) + flags |= feature_flags.get(alias.name, 0) else: break else: From noreply at buildbot.pypy.org Thu Jul 14 16:38:59 2011 From: noreply at buildbot.pypy.org (hpk42) Date: Thu, 14 Jul 2011 16:38:59 +0200 (CEST) Subject: [pypy-commit] pypy default: bump pypy version to 1.6.0.dev1 to distinguish from the released "1.5.0 Message-ID: <20110714143859.6C6DA8291A@wyvern.cs.uni-duesseldorf.de> Author: holger krekel Branch: Changeset: r45597:e38414a7518d Date: 2011-07-14 16:38 +0200 http://bitbucket.org/pypy/pypy/changeset/e38414a7518d/ Log: bump pypy version to 1.6.0.dev1 to distinguish from the released "1.5.0 (alpha)". Makes it a bit easier to know what pypy version was used when people/CI systems submit bug reports for test runs with pypy. Maybe makes sense to increase the patchlevel (the "1" in dev1) from time to time. diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ CPYTHON_VERSION = (2, 7, 1, "final", 42) #XXX # sync patchlevel.h CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (1, 5, 0, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (1, 6, 0, "dev", 1) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) From noreply at buildbot.pypy.org Thu Jul 14 18:01:07 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 14 Jul 2011 18:01:07 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: restructure reflex calling for integration with cint Message-ID: <20110714160107.CBB0C8291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45598:c0410ece8035 Date: 2011-07-14 08:59 -0700 http://bitbucket.org/pypy/pypy/changeset/c0410ece8035/ Log: restructure reflex calling for integration with cint diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py --- a/pypy/module/cppyy/capi/reflex_capi.py +++ b/pypy/module/cppyy/capi/reflex_capi.py @@ -19,7 +19,7 @@ include_dirs=[incpath] + rootincpath, includes=["reflexcwrapper.h"], library_dirs=rootlibpath, - libraries=["Reflex"], + link_extra=["-lReflex"], use_cpp_linker=True, ) @@ -89,39 +89,39 @@ c_call_v = rffi.llexternal( "cppyy_call_v", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], lltype.Void, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void, compilation_info=eci) c_call_o = rffi.llexternal( "cppyy_call_o", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP, C_TYPEHANDLE], rffi.LONG, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP, C_TYPEHANDLE], rffi.LONG, compilation_info=eci) c_call_b = rffi.llexternal( "cppyy_call_b", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT, compilation_info=eci) c_call_c = rffi.llexternal( "cppyy_call_c", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.CHAR, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CHAR, compilation_info=eci) c_call_h = rffi.llexternal( "cppyy_call_h", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.SHORT, compilation_info=eci) c_call_i = rffi.llexternal( "cppyy_call_i", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT, compilation_info=eci) c_call_l = rffi.llexternal( "cppyy_call_l", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.LONG, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONG, compilation_info=eci) c_call_f = rffi.llexternal( "cppyy_call_f", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.DOUBLE, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE, compilation_info=eci) c_call_d = rffi.llexternal( "cppyy_call_d", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.DOUBLE, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE, compilation_info=eci) @@ -131,6 +131,29 @@ compilation_info=eci) +c_allocate_function_args = rffi.llexternal( + "cppyy_allocate_function_args", + [rffi.SIZE_T], rffi.VOIDP, + compilation_info=eci) + +c_deallocate_function_args = rffi.llexternal( + "cppyy_deallocate_function_args", + [rffi.VOIDP], lltype.Void, + compilation_info=eci) + +c_function_arg_sizeof = rffi.llexternal( + "cppyy_function_arg_sizeof", + [], rffi.SIZE_T, + compilation_info=eci, + elidable_function=True) + +c_function_arg_typeoffset = rffi.llexternal( + "cppyy_function_arg_typeoffset", + [], rffi.SIZE_T, + compilation_info=eci, + elidable_function=True) + + c_num_methods = rffi.llexternal( "cppyy_num_methods", [C_TYPEHANDLE], rffi.INT, diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -47,7 +47,7 @@ raise NotImplementedError( "abstract base class" ) # more detailed part is not rpython: (actual: %s)" % type(self).__name__) - def convert_argument(self, space, w_obj): + def convert_argument(self, space, w_obj, address): self._is_abstract() def convert_argument_libffi(self, space, w_obj, argchain): @@ -61,7 +61,7 @@ self._is_abstract() def free_argument(self, arg): - lltype.free(arg, flavor='raw') + pass class ArrayCache(object): @@ -141,7 +141,7 @@ def __init__(self, space, name): self.name = name - def convert_argument(self, space, w_obj): + def convert_argument(self, space, w_obj, address): raise OperationError(space.w_TypeError, space.wrap('no converter available for type "%s"' % self.name)) @@ -157,11 +157,9 @@ space.wrap("boolean value should be bool, or integer 1 or 0")) return arg - def convert_argument(self, space, w_obj): - arg = self._unwrap_object(space, w_obj) - x = lltype.malloc(rffi.LONGP.TO, 1, flavor='raw') - x[0] = arg - return rffi.cast(rffi.VOIDP, x) + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.LONGP, address) + x[0] = self._unwrap_object(space, w_obj) def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) @@ -201,10 +199,9 @@ space.wrap("char expected, got string of size %d" % len(value))) return value[0] # turn it into a "char" to the annotator - def convert_argument(self, space, w_obj): - arg = self._unwrap_object(space, w_obj) - x = rffi.str2charp(arg) - return rffi.cast(rffi.VOIDP, x) + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.CCHARP, address) + x[0] = self._unwrap_object(space, w_obj) def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) @@ -224,11 +221,9 @@ def _unwrap_object(self, space, w_obj): return rffi.cast(rffi.INT, space.c_int_w(w_obj)) - def convert_argument(self, space, w_obj): - arg = self._unwrap_object(space, w_obj) - x = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') - x[0] = arg - return rffi.cast(rffi.VOIDP, x) + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.INTP, address) + x[0] = self._unwrap_object(space, w_obj) def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) @@ -250,11 +245,9 @@ def _unwrap_object(self, space, w_obj): return rffi.cast(rffi.UINT, space.uint_w(w_obj)) - def convert_argument(self, space, w_obj): - arg = self._unwrap_object(space, w_obj) - x = lltype.malloc(rffi.UINTP.TO, 1, flavor='raw') - x[0] = arg - return rffi.cast(rffi.VOIDP, x) + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.UINTP, address) + x[0] = self._unwrap_object(space, w_obj) def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) @@ -276,11 +269,9 @@ def _unwrap_object(self, space, w_obj): return space.int_w(w_obj) - def convert_argument(self, space, w_obj): - arg = self._unwrap_object(space, w_obj) - x = lltype.malloc(rffi.LONGP.TO, 1, flavor='raw') - x[0] = arg - return rffi.cast(rffi.VOIDP, x) + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.LONGP, address) + x[0] = self._unwrap_object(space, w_obj) def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) @@ -302,11 +293,9 @@ def _unwrap_object(self, space, w_obj): return space.uint_w(w_obj) - def convert_argument(self, space, w_obj): - arg = self._unwrap_object(space, w_obj) - x = lltype.malloc(rffi.ULONGP.TO, 1, flavor='raw') - x[0] = arg - return rffi.cast(rffi.VOIDP, x) + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.ULONGP, address) + x[0] = self._unwrap_object(space, w_obj) def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) @@ -328,11 +317,9 @@ def _unwrap_object(self, space, w_obj): return rffi.cast(rffi.SHORT, space.int_w(w_obj)) - def convert_argument(self, space, w_obj): - arg = self._unwrap_object(space, w_obj) - x = lltype.malloc(rffi.SHORTP.TO, 1, flavor='raw') - x[0] = arg - return rffi.cast(rffi.VOIDP, x) + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.SHORTP, address) + x[0] = self._unwrap_object(space, w_obj) def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) @@ -354,10 +341,9 @@ def _unwrap_object(self, space, w_obj): return r_singlefloat(space.float_w(w_obj)) - def convert_argument(self, space, w_obj): - x = lltype.malloc(rffi.FLOATP.TO, 1, flavor='raw') + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.FLOATP, address) x[0] = self._unwrap_object(space, w_obj) - return rffi.cast(rffi.VOIDP, x) def convert_argument_libffi(self, space, w_obj, argchain): # it's required to sent an rffi.DOUBLE not r_singlefloat @@ -380,10 +366,9 @@ def _unwrap_object(self, space, w_obj): return space.float_w(w_obj) - def convert_argument(self, space, w_obj): - x = lltype.malloc(rffi.DOUBLEP.TO, 1, flavor='raw') + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.DOUBLEP, address) x[0] = self._unwrap_object(space, w_obj) - return rffi.cast(rffi.VOIDP, x) def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) @@ -402,16 +387,21 @@ class CStringConverter(TypeConverter): _immutable = True - def convert_argument(self, space, w_obj): + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.LONGP, address) arg = space.str_w(w_obj) - x = rffi.str2charp(arg) - return rffi.cast(rffi.VOIDP, x) + x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg)) + typecode = _direct_ptradd(address, capi.c_function_arg_typeoffset()) + typecode[0] = 'a' def from_memory(self, space, w_obj, offset): address = self._get_raw_address(space, w_obj, offset) charpptr = rffi.cast(rffi.CCHARPP, address) return space.wrap(rffi.charp2str(charpptr[0])) + def free_argument(self, arg): + lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw') + class ShortArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True @@ -498,14 +488,15 @@ space.type(w_obj).getname(space, "?"), self.cpptype.name))) - def convert_argument(self, space, w_obj): - return self._unwrap_object(space, w_obj) + def convert_argument(self, space, w_obj, address): + x = rffi.cast(rffi.VOIDPP, address) + x[0] = self._unwrap_object(space, w_obj) + typecode = _direct_ptradd(address, capi.c_function_arg_typeoffset()) + typecode[0] = 'a' def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) - def free_argument(self, arg): - pass class InstanceConverter(InstancePtrConverter): _immutable_ = True @@ -515,9 +506,6 @@ from pypy.module.cppyy import interp_cppyy return interp_cppyy.W_CPPInstance(space, self.cpptype, address, False) - def free_argument(self, arg): - pass - _converters = {} def get_converter(space, name): diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h --- a/pypy/module/cppyy/include/capi.h +++ b/pypy/module/cppyy/include/capi.h @@ -20,18 +20,24 @@ void cppyy_destruct(cppyy_typehandle_t handle, cppyy_object_t self); /* method/function dispatching */ - void cppyy_call_v(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - long cppyy_call_o(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[], cppyy_typehandle_t rettype); - int cppyy_call_b(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - char cppyy_call_c(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - short cppyy_call_h(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - int cppyy_call_i(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - long cppyy_call_l(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - double cppyy_call_f(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); - double cppyy_call_d(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]); + void cppyy_call_v(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args); + long cppyy_call_o(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args, cppyy_typehandle_t rettype); + int cppyy_call_b(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args); + char cppyy_call_c(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args); + short cppyy_call_h(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args); + int cppyy_call_i(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args); + long cppyy_call_l(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args); + double cppyy_call_f(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args); + double cppyy_call_d(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args); cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_typehandle_t handle, int method_index); + /* handling of function argument buffer */ + void* cppyy_allocate_function_args(size_t nargs); + void cppyy_deallocate_function_args(void* args); + size_t cppyy_function_arg_sizeof(); + size_t cppyy_function_arg_typeoffset(); + /* scope reflection information ------------------------------------------- */ int cppyy_is_namespace(cppyy_typehandle_t handle); diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h --- a/pypy/module/cppyy/include/cppyy.h +++ b/pypy/module/cppyy/include/cppyy.h @@ -1,6 +1,81 @@ #ifndef CPPYY_CPPYY #define CPPYY_CPPYY -// for now, just a conventional placeholder +#define CPPYY_G__MAXFUNCPARA 40 + +#ifdef __cplusplus +struct CPPYY_G__DUMMY_FOR_CINT7 { +#else +typedef struct +#endif + void* fTypeName; + unsigned int fModifiers; +#ifdef __cplusplus +}; +#else +} CPPYY_G__DUMMY_FOR_CINT7; +#endif + +#ifdef __cplusplus +struct CPPYY_G__p2p { +#else +#typedef struct +#endif + long i; + int reftype; +#ifdef __cplusplus +}; +#else +} CPPYY_G__p2p; +#endif + + +#ifdef __cplusplus +struct CPPYY_G__value { +#else +typedef struct { +#endif + union { + double d; + long i; /* used to be int */ + struct CPPYY_G__p2p reftype; + char ch; + short sh; + int in; + float fl; + unsigned char uch; + unsigned short ush; + unsigned int uin; + unsigned long ulo; + long long ll; + unsigned long long ull; + long double ld; + } obj; + long ref; + int type; + int tagnum; + int typenum; + char isconst; + struct CPPYY_G__DUMMY_FOR_CINT7 dummyForCint7; +#ifdef __cplusplus +}; +#else +} CPPYY_G__value; +#endif + + +#ifdef __cplusplus +struct CPPYY_G__param { +#else +typedef struct +#endif + int paran; + long para; /* place-holder */ + /* dropped parameter as it appears unused in stub functions */ +#ifdef __cplusplus +}; +#else +} CPPYY_G__param; +#endif #endif // CPPYY_CPPYY diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -171,28 +171,32 @@ raise OperationError(space.w_TypeError, space.wrap("wrong number of args")) if self.arg_converters is None: self._build_converters() - args = lltype.malloc(rffi.CArray(rffi.VOIDP), len(args_w), flavor='raw') + args = capi.c_allocate_function_args(len(args_w)) + stride = capi.c_function_arg_sizeof() for i in range(len(args_w)): conv = self.arg_converters[i] w_arg = args_w[i] try: - arg = conv.convert_argument(space, w_arg) + arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride) + conv.convert_argument(space, w_arg, rffi.cast(rffi.VOIDP, arg_i)) except: # fun :-( for j in range(i): conv = self.arg_converters[j] - conv.free_argument(args[j]) - lltype.free(args, flavor='raw') + arg_j = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), j*stride) + conv.free_argument(rffi.cast(rffi.VOIDP, arg_j)) + capi.c_deallocate_function_args(args) raise - args[i] = arg return args @jit.unroll_safe def free_arguments(self, args, nargs): + stride = capi.c_function_arg_sizeof() for i in range(nargs): conv = self.arg_converters[i] - conv.free_argument(args[i]) - lltype.free(args, flavor='raw') + arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride) + conv.free_argument(rffi.cast(rffi.VOIDP, arg_i)) + capi.c_deallocate_function_args(args) def __repr__(self): return "CPPFunction(%s, %s, %r, %s)" % ( diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx --- a/pypy/module/cppyy/src/reflexcwrapper.cxx +++ b/pypy/module/cppyy/src/reflexcwrapper.cxx @@ -30,6 +30,18 @@ return Reflex::Scope((Reflex::ScopeName*)handle); } +static inline std::vector build_args(int numargs, void* args) { + std::vector arguments; + arguments.reserve(numargs); + for (int i=0; i < numargs; ++i) { + if (((CPPYY_G__value*)args)[i].type == 'l') + arguments.push_back(&((CPPYY_G__value*)args)[i]); + else + arguments.push_back((void*)(*(long*)&((CPPYY_G__value*)args)[i])); + } + return arguments; +} + static inline size_t base_offset(const Reflex::Type& td, const Reflex::Type& tb) { // when dealing with virtual inheritance the only (reasonably) well-defined info is // in a Reflex internal base table, that contains all offsets within the hierarchy @@ -92,8 +104,8 @@ /* method/function dispatching -------------------------------------------- */ void cppyy_call_v(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { - std::vector arguments(args, args+numargs); + cppyy_object_t self, int numargs, void* args) { + std::vector arguments = build_args(numargs, args); Reflex::Scope s = scope_from_handle(handle); Reflex::Member m = s.FunctionMemberAt(method_index); if (self) { @@ -105,10 +117,10 @@ } long cppyy_call_o(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[], + cppyy_object_t self, int numargs, void* args, cppyy_typehandle_t rettype) { void* result = cppyy_allocate(rettype); - std::vector arguments(args, args+numargs); + std::vector arguments = build_args(numargs, args); Reflex::Scope s = scope_from_handle(handle); Reflex::Member m = s.FunctionMemberAt(method_index); if (self) { @@ -122,9 +134,9 @@ template static inline T cppyy_call_T(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { T result; - std::vector arguments(args, args+numargs); + std::vector arguments = build_args(numargs, args); Reflex::Scope s = scope_from_handle(handle); Reflex::Member m = s.FunctionMemberAt(method_index); if (self) { @@ -137,37 +149,37 @@ } int cppyy_call_b(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { return (int)cppyy_call_T(handle, method_index, self, numargs, args); } char cppyy_call_c(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { return cppyy_call_T(handle, method_index, self, numargs, args); } short cppyy_call_h(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { return cppyy_call_T(handle, method_index, self, numargs, args); } int cppyy_call_i(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { return cppyy_call_T(handle, method_index, self, numargs, args); } long cppyy_call_l(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { return cppyy_call_T(handle, method_index, self, numargs, args); } double cppyy_call_f(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { return cppyy_call_T(handle, method_index, self, numargs, args); } double cppyy_call_d(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { return cppyy_call_T(handle, method_index, self, numargs, args); } @@ -188,6 +200,29 @@ } +/* handling of function argument buffer */ +void* cppyy_allocate_function_args(size_t nargs) { + CPPYY_G__param* libp = (CPPYY_G__param*)malloc( + sizeof(int/*CPPYY_G__param.paran*/) + nargs*sizeof(CPPYY_G__value)); + libp->paran = (int)nargs; + for (int i = 0; i < nargs; ++i) + ((CPPYY_G__value*)&libp->para)[i].type = 'l'; + return (void*)&libp->para; +} + +void cppyy_deallocate_function_args(void* args) { + free((char*)args - offsetof(CPPYY_G__param, para)); +} + +size_t cppyy_function_arg_sizeof() { + return sizeof(CPPYY_G__value); +} + +size_t cppyy_function_arg_typeoffset() { + return offsetof(CPPYY_G__value, type); +} + + /* scope reflection information ------------------------------------------- */ int cppyy_is_namespace(cppyy_typehandle_t handle) { Reflex::Scope s = scope_from_handle(handle); diff --git a/pypy/module/cppyy/test/example01.cxx b/pypy/module/cppyy/test/example01.cxx --- a/pypy/module/cppyy/test/example01.cxx +++ b/pypy/module/cppyy/test/example01.cxx @@ -83,7 +83,6 @@ } int example01::getCount() { - std::cout << "getcount called" << std::endl; return count; } diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -61,7 +61,6 @@ raises(TypeError, 't.invoke(t.get_overload("staticAddOneToInt"), 1.)') raises(OverflowError, 't.invoke(t.get_overload("staticAddOneToInt"), maxint32+1)') - def test_example01static_double(self): """Test passing of a double and returning of a double on a static function.""" From noreply at buildbot.pypy.org Thu Jul 14 18:01:09 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 14 Jul 2011 18:01:09 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge of branch heads Message-ID: <20110714160109.08EB78291A@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45599:aa6ff948e437 Date: 2011-07-14 09:00 -0700 http://bitbucket.org/pypy/pypy/changeset/aa6ff948e437/ Log: merge of branch heads diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -264,6 +264,7 @@ space = self.space errmsg = 'None of the overloads matched:' + jit.promote(self) for i in range(len(self.functions)): cppyyfunc = self.functions[i] try: diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py --- a/pypy/module/cppyy/test/test_zjit.py +++ b/pypy/module/cppyy/test/test_zjit.py @@ -128,3 +128,4 @@ space = FakeSpace() result = self.meta_interp(f, [], listops=True, backendopt=True, listcomp=True) self.check_loops(call=0, call_release_gil=1) + self.check_loops(getarrayitem_gc_pure=0, everywhere=True) From noreply at buildbot.pypy.org Thu Jul 14 18:48:27 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 14 Jul 2011 18:48:27 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, cfbolz): refactor away the invokes and replace them with Overload.call Message-ID: <20110714164827.C91428291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45600:6413ad84ad2f Date: 2011-07-14 18:24 +0200 http://bitbucket.org/pypy/pypy/changeset/6413ad84ad2f/ Log: (arigo, cfbolz): refactor away the invokes and replace them with Overload.call with a slightly strange set of arguments: - first argument is this or None - second argument is the type of the result or None diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -3,7 +3,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import ObjSpace, interp2app from pypy.interpreter.typedef import TypeDef, interp_attrproperty -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.rpython.lltypesystem import rffi, lltype @@ -101,7 +101,7 @@ self.methgetter = methgetter self._libffifunc_cache = {} - def call(self, cppthis, args_w): + def call(self, cppthis, w_type, args_w): assert lltype.typeOf(cppthis) == rffi.VOIDP if self.executor is None: raise OperationError(self.space.w_TypeError, @@ -209,7 +209,7 @@ class CPPFunction(CPPMethod): _immutable_ = True - def call(self, cppthis, args_w): + def call(self, cppthis, w_type, args_w): assert lltype.typeOf(cppthis) == rffi.VOIDP if self.executor is None: raise OperationError(self.space.w_TypeError, @@ -227,16 +227,18 @@ class CPPConstructor(CPPMethod): _immutable_=True - def call(self, cppthis, args_w): - assert not cppthis + def call(self, cppthis, w_type, args_w): newthis = capi.c_allocate(self.cpptype.handle) assert lltype.typeOf(newthis) == rffi.VOIDP try: - CPPMethod.call(self, newthis, args_w) + CPPMethod.call(self, newthis, None, args_w) except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) raise - return W_CPPInstance(self.space, self.cpptype, newthis, True) + w_instance = self.space.allocate_instance(W_CPPInstance, w_type) + instance = self.space.interp_w(W_CPPInstance, w_instance) + W_CPPInstance.__init__(instance, self.space, self.cpptype, newthis, True) + return w_instance class W_CPPOverload(Wrappable): @@ -255,8 +257,10 @@ return self.space.wrap(self.functions[0].executor.name) @jit.unroll_safe - def call(self, cppinstance, args_w): - if cppinstance: + def call(self, w_cppinstance, w_type, args_w): + cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True) + if cppinstance is not None: + cppinstance._nullcheck() cppthis = cppinstance.rawobject else: cppthis = NULL_VOIDP @@ -268,7 +272,7 @@ for i in range(len(self.functions)): cppyyfunc = self.functions[i] try: - cppresult = cppyyfunc.call(cppthis, args_w) + cppresult = cppyyfunc.call(cppthis, w_type, args_w) if cppinstance and isinstance(cppresult, W_CPPInstance): if cppresult.rawobject == cppinstance.rawobject: return cppinstance # recycle object to preserve identity @@ -289,6 +293,7 @@ 'CPPOverload', is_static = interp2app(W_CPPOverload.is_static, unwrap_spec=['self']), get_returntype = interp2app(W_CPPOverload.get_returntype, unwrap_spec=['self']), + call = interp2app(W_CPPOverload.call, unwrap_spec=['self', W_Root, W_Root, 'args_w']), ) @@ -396,16 +401,12 @@ self.space.w_AttributeError, self.space.wrap(str("class %s has no attribute %s" % (self.name, name)))) - def invoke(self, overload, args_w): - return overload.call(None, args_w) - W_CPPScope.typedef = TypeDef( 'CPPScope', get_method_names = interp2app(W_CPPScope.get_method_names, unwrap_spec=['self']), get_overload = interp2app(W_CPPScope.get_overload, unwrap_spec=['self', str]), get_data_member_names = interp2app(W_CPPScope.get_data_member_names, unwrap_spec=['self']), get_data_member = interp2app(W_CPPScope.get_data_member, unwrap_spec=['self', str]), - invoke = interp2app(W_CPPScope.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']), ) @@ -450,7 +451,6 @@ get_data_member_names = interp2app(W_CPPNamespace.get_data_member_names, unwrap_spec=['self']), get_data_member = interp2app(W_CPPNamespace.get_data_member, unwrap_spec=['self', str]), is_namespace = interp2app(W_CPPNamespace.is_namespace, unwrap_spec=['self']), - invoke = interp2app(W_CPPNamespace.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']), ) @@ -495,7 +495,8 @@ bases.append(self.space.wrap(base_name)) return self.space.newlist(bases) - def construct(self, args_w): + def construct(self, w_type, args_w): + # XXX make pure python try: overload = self.get_overload(self.name) except OperationError, e: @@ -503,8 +504,7 @@ raise OperationError(self.space.w_TypeError, self.space.wrap("%s is abstract" % self.name)) raise - - return overload.call(None, args_w) + return overload.call(self.space.w_None, w_type, args_w) W_CPPType.typedef = TypeDef( 'CPPType', @@ -515,8 +515,7 @@ get_data_member_names = interp2app(W_CPPType.get_data_member_names, unwrap_spec=['self']), get_data_member = interp2app(W_CPPType.get_data_member, unwrap_spec=['self', str]), is_namespace = interp2app(W_CPPType.is_namespace, unwrap_spec=['self']), - invoke = interp2app(W_CPPType.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']), - construct = interp2app(W_CPPType.construct, unwrap_spec=['self', 'args_w']), + construct = interp2app(W_CPPType.construct, unwrap_spec=['self', W_Root, 'args_w']), ) @@ -549,15 +548,12 @@ self.rawobject = rawobject self.python_owns = python_owns + def _nullcheck(self): if not self.rawobject: raise OperationError(self.space.w_ReferenceError, self.space.wrap("trying to access a NULL pointer")) - def invoke(self, overload, args_w): - self._nullcheck() - return overload.call(self, args_w) - def destruct(self): if self.rawobject: capi.c_destruct(self.cppclass.handle, self.rawobject) @@ -567,9 +563,9 @@ if self.python_owns: self.destruct() + W_CPPInstance.typedef = TypeDef( 'CPPInstance', cppclass = interp_attrproperty('cppclass', W_CPPInstance), - invoke = interp2app(W_CPPInstance.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']), destruct = interp2app(W_CPPInstance.destruct, unwrap_spec=['self']), ) diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -43,30 +43,30 @@ import sys, math t = self.example01 - res = t.invoke(t.get_overload("staticAddOneToInt"), 1) + res = t.get_overload("staticAddOneToInt").call(None, None, 1) assert res == 2 - res = t.invoke(t.get_overload("staticAddOneToInt"), 1L) + res = t.get_overload("staticAddOneToInt").call(None, None, 1L) assert res == 2 - res = t.invoke(t.get_overload("staticAddOneToInt"), 1, 2) + res = t.get_overload("staticAddOneToInt").call(None, None, 1, 2) assert res == 4 - res = t.invoke(t.get_overload("staticAddOneToInt"), -1) + res = t.get_overload("staticAddOneToInt").call(None, None, -1) assert res == 0 maxint32 = int(2 ** 31 - 1) - res = t.invoke(t.get_overload("staticAddOneToInt"), maxint32-1) + res = t.get_overload("staticAddOneToInt").call(None, None, maxint32-1) assert res == maxint32 - res = t.invoke(t.get_overload("staticAddOneToInt"), maxint32) + res = t.get_overload("staticAddOneToInt").call(None, None, maxint32) assert res == -maxint32-1 - raises(TypeError, 't.invoke(t.get_overload("staticAddOneToInt"), 1, [])') - raises(TypeError, 't.invoke(t.get_overload("staticAddOneToInt"), 1.)') - raises(OverflowError, 't.invoke(t.get_overload("staticAddOneToInt"), maxint32+1)') + raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, None, 1, [])') + raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, None, 1.)') + raises(OverflowError, 't.get_overload("staticAddOneToInt").call(None, None, maxint32+1)') def test_example01static_double(self): """Test passing of a double and returning of a double on a static function.""" t = self.example01 - res = t.invoke(t.get_overload("staticAddToDouble"), 0.09) + res = t.get_overload("staticAddToDouble").call(None, None, 0.09) assert res == 0.09 + 0.01 def test_example01static_constcharp(self): @@ -75,141 +75,147 @@ t = self.example01 - res = t.invoke(t.get_overload("staticAtoi"), "1") + res = t.get_overload("staticAtoi").call(None, None, "1") assert res == 1 - res = t.invoke(t.get_overload("staticStrcpy"), "aap") # TODO: this leaks + res = t.get_overload("staticStrcpy").call(None, None, "aap") # TODO: this leaks assert res == "aap" - res = t.invoke(t.get_overload("staticStrcpy"), u"aap") # TODO: this leaks + res = t.get_overload("staticStrcpy").call(None, None, u"aap") # TODO: this leaks assert res == "aap" - raises(TypeError, 't.invoke(t.get_overload("staticStrcpy"), 1.)') # TODO: this leaks + raises(TypeError, 't.get_overload("staticStrcpy").call(None, None, 1.)') # TODO: this leaks def test_example01method_int(self): """Test passing of a int, returning of a int, and memory cleanup, on a method.""" + import cppyy t = self.example01 - assert t.invoke(t.get_overload("getCount")) == 0 + assert t.get_overload("getCount").call(None, None) == 0 - e1 = t.construct(7) - assert t.invoke(t.get_overload("getCount")) == 1 - res = e1.invoke(t.get_overload("addDataToInt"), 4) + e1 = t.construct(cppyy.CPPInstance, 7) + assert t.get_overload("getCount").call(None, None) == 1 + res = t.get_overload("addDataToInt").call(e1, None, 4) assert res == 11 - res = e1.invoke(t.get_overload("addDataToInt"), -4) + res = t.get_overload("addDataToInt").call(e1, None, -4) assert res == 3 e1.destruct() - assert t.invoke(t.get_overload("getCount")) == 0 - raises(ReferenceError, 'e1.invoke(t.get_overload("addDataToInt"), 4)') + assert t.get_overload("getCount").call(None, None) == 0 + raises(ReferenceError, 't.get_overload("addDataToInt").call(e1, None, 4)') - e1 = t.construct(7) - e2 = t.construct(8) - assert t.invoke(t.get_overload("getCount")) == 2 + e1 = t.construct(cppyy.CPPInstance, 7) + e2 = t.construct(cppyy.CPPInstance, 8) + assert t.get_overload("getCount").call(None, None) == 2 e1.destruct() - assert t.invoke(t.get_overload("getCount")) == 1 + assert t.get_overload("getCount").call(None, None) == 1 e2.destruct() - assert t.invoke(t.get_overload("getCount")) == 0 + assert t.get_overload("getCount").call(None, None) == 0 e2.destruct() - assert t.invoke(t.get_overload("getCount")) == 0 + assert t.get_overload("getCount").call(None, None) == 0 def test_example01memory(self): """Test memory destruction and integrity.""" import gc + import cppyy t = self.example01 - assert t.invoke(t.get_overload("getCount")) == 0 + assert t.get_overload("getCount").call(None, None) == 0 - e1 = t.construct(7) - assert t.invoke(t.get_overload("getCount")) == 1 - res = e1.invoke(t.get_overload("addDataToInt"), 4) + e1 = t.construct(cppyy.CPPInstance, 7) + assert t.get_overload("getCount").call(None, None) == 1 + res = t.get_overload("addDataToInt").call(e1, None, 4) assert res == 11 - res = e1.invoke(t.get_overload("addDataToInt"), -4) + res = t.get_overload("addDataToInt").call(e1, None, -4) assert res == 3 e1 = None gc.collect() - assert t.invoke(t.get_overload("getCount")) == 0 + assert t.get_overload("getCount").call(None, None) == 0 - e1 = t.construct(7) - e2 = t.construct(8) - assert t.invoke(t.get_overload("getCount")) == 2 + e1 = t.construct(cppyy.CPPInstance, 7) + e2 = t.construct(cppyy.CPPInstance, 8) + assert t.get_overload("getCount").call(None, None) == 2 e1 = None gc.collect() - assert t.invoke(t.get_overload("getCount")) == 1 + assert t.get_overload("getCount").call(None, None) == 1 e2.destruct() - assert t.invoke(t.get_overload("getCount")) == 0 + assert t.get_overload("getCount").call(None, None) == 0 e2 = None gc.collect() - assert t.invoke(t.get_overload("getCount")) == 0 + assert t.get_overload("getCount").call(None, None) == 0 def test_example01method_double(self): """Test passing of a double and returning of double on a method""" + import cppyy t = self.example01 - e = t.construct(13) - res = e.invoke(t.get_overload("addDataToDouble"), 16) + e = t.construct(cppyy.CPPInstance, 13) + res = t.get_overload("addDataToDouble").call(e, None, 16) assert round(res-29, 8) == 0. e.destruct() - e = t.construct(-13) - res = e.invoke(t.get_overload("addDataToDouble"), 16) + e = t.construct(cppyy.CPPInstance, -13) + res = t.get_overload("addDataToDouble").call(e, None, 16) assert round(res-3, 8) == 0. e.destruct() - assert t.invoke(t.get_overload("getCount")) == 0 + assert t.get_overload("getCount").call(None, None) == 0 def test_example01method_constcharp(self): """Test passing of a C string and returning of a C string on a method.""" + import cppyy t = self.example01 - e = t.construct(42) - res = e.invoke(t.get_overload("addDataToAtoi"), "13") + e = t.construct(cppyy.CPPInstance, 42) + res = t.get_overload("addDataToAtoi").call(e, None, "13") assert res == 55 - res = e.invoke(t.get_overload("addToStringValue"), "12") # TODO: this leaks + res = t.get_overload("addToStringValue").call(e, None, "12") # TODO: this leaks assert res == "54" - res = e.invoke(t.get_overload("addToStringValue"), "-12") # TODO: this leaks + res = t.get_overload("addToStringValue").call(e, None, "-12") # TODO: this leaks assert res == "30" e.destruct() - assert t.invoke(t.get_overload("getCount")) == 0 + assert t.get_overload("getCount").call(None, None) == 0 def testPassingOfAnObjectByPointer(self): """Test passing of an instance as an argument.""" + import cppyy t1 = self.example01 t2 = self.payload - pl = t2.construct(3.14) - assert round(pl.invoke(t2.get_overload("getData"))-3.14, 8) == 0 - t1.invoke(t1.get_overload("staticSetPayload"), pl, 41.) # now pl is a CPPInstance - assert pl.invoke(t2.get_overload("getData")) == 41. + pl = t2.construct(cppyy.CPPInstance, 3.14) + assert round(t2.get_overload("getData").call(pl, None)-3.14, 8) == 0 + t1.get_overload("staticSetPayload").call(None, None, pl, 41.) # now pl is a CPPInstance + assert t2.get_overload("getData").call(pl, None) == 41. - e = t1.construct(50) - e.invoke(t1.get_overload("setPayload"), pl); - assert round(pl.invoke(t2.get_overload("getData"))-50., 8) == 0 + e = t1.construct(cppyy.CPPInstance, 50) + t1.get_overload("setPayload").call(e, None, pl); + assert round(t2.get_overload("getData").call(pl, None)-50., 8) == 0 e.destruct() pl.destruct() - assert t1.invoke(t1.get_overload("getCount")) == 0 + assert t1.get_overload("getCount").call(None, None) == 0 def testReturningOfAnObjectByPointer(self): """Test returning of an instance as an argument.""" + import cppyy t1 = self.example01 t2 = self.payload - pl1 = t2.construct(3.14) - assert round(pl1.invoke(t2.get_overload("getData"))-3.14, 8) == 0 - pl2 = t1.invoke(t1.get_overload("staticCyclePayload"), pl1, 38.) - assert pl2.invoke(t2.get_overload("getData")) == 38. + pl1 = t2.construct(cppyy.CPPInstance, 3.14) + assert round(t2.get_overload("getData").call(pl1, None)-3.14, 8) == 0 + pl2 = t1.get_overload("staticCyclePayload").call(None, cppyy.CPPInstance, pl1, 38.) + assert t2.get_overload("getData").call(pl2, None) == 38. - e = t1.construct(50) - pl2 = e.invoke(t1.get_overload("cyclePayload"), pl1); - assert round(pl2.invoke(t2.get_overload("getData"))-50., 8) == 0 + e = t1.construct(cppyy.CPPInstance, 50) + pl2 = t1.get_overload("cyclePayload").call(e, cppyy.CPPInstance, pl1); + assert round(t2.get_overload("getData").call(pl2, None)-50., 8) == 0 e.destruct() pl1.destruct() - assert t1.invoke(t1.get_overload("getCount")) == 0 + assert t1.get_overload("getCount").call(None, None) == 0 From noreply at buildbot.pypy.org Thu Jul 14 18:48:29 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 14 Jul 2011 18:48:29 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, cfbolz) Message-ID: <20110714164829.0310D8291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45601:ea621cd7b2fa Date: 2011-07-14 18:31 +0200 http://bitbucket.org/pypy/pypy/changeset/ea621cd7b2fa/ Log: (arigo, cfbolz) Kill construct(). diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -495,17 +495,6 @@ bases.append(self.space.wrap(base_name)) return self.space.newlist(bases) - def construct(self, w_type, args_w): - # XXX make pure python - try: - overload = self.get_overload(self.name) - except OperationError, e: - if e.match(self.space, self.space.w_AttributeError): - raise OperationError(self.space.w_TypeError, - self.space.wrap("%s is abstract" % self.name)) - raise - return overload.call(self.space.w_None, w_type, args_w) - W_CPPType.typedef = TypeDef( 'CPPType', type_name = interp_attrproperty('name', W_CPPType), @@ -515,7 +504,6 @@ get_data_member_names = interp2app(W_CPPType.get_data_member_names, unwrap_spec=['self']), get_data_member = interp2app(W_CPPType.get_data_member, unwrap_spec=['self', str]), is_namespace = interp2app(W_CPPType.is_namespace, unwrap_spec=['self']), - construct = interp2app(W_CPPType.construct, unwrap_spec=['self', W_Root, 'args_w']), ) diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -93,7 +93,7 @@ assert t.get_overload("getCount").call(None, None) == 0 - e1 = t.construct(cppyy.CPPInstance, 7) + e1 = t.get_overload(t.type_name).call(None, cppyy.CPPInstance, 7) assert t.get_overload("getCount").call(None, None) == 1 res = t.get_overload("addDataToInt").call(e1, None, 4) assert res == 11 @@ -103,8 +103,8 @@ assert t.get_overload("getCount").call(None, None) == 0 raises(ReferenceError, 't.get_overload("addDataToInt").call(e1, None, 4)') - e1 = t.construct(cppyy.CPPInstance, 7) - e2 = t.construct(cppyy.CPPInstance, 8) + e1 = t.get_overload(t.type_name).call(None, cppyy.CPPInstance, 7) + e2 = t.get_overload(t.type_name).call(None, cppyy.CPPInstance, 8) assert t.get_overload("getCount").call(None, None) == 2 e1.destruct() assert t.get_overload("getCount").call(None, None) == 1 @@ -124,7 +124,7 @@ assert t.get_overload("getCount").call(None, None) == 0 - e1 = t.construct(cppyy.CPPInstance, 7) + e1 = t.get_overload(t.type_name).call(None, cppyy.CPPInstance, 7) assert t.get_overload("getCount").call(None, None) == 1 res = t.get_overload("addDataToInt").call(e1, None, 4) assert res == 11 @@ -134,8 +134,8 @@ gc.collect() assert t.get_overload("getCount").call(None, None) == 0 - e1 = t.construct(cppyy.CPPInstance, 7) - e2 = t.construct(cppyy.CPPInstance, 8) + e1 = t.get_overload(t.type_name).call(None, cppyy.CPPInstance, 7) + e2 = t.get_overload(t.type_name).call(None, cppyy.CPPInstance, 8) assert t.get_overload("getCount").call(None, None) == 2 e1 = None gc.collect() @@ -152,12 +152,12 @@ t = self.example01 - e = t.construct(cppyy.CPPInstance, 13) + e = t.get_overload(t.type_name).call(None, cppyy.CPPInstance, 13) res = t.get_overload("addDataToDouble").call(e, None, 16) assert round(res-29, 8) == 0. e.destruct() - e = t.construct(cppyy.CPPInstance, -13) + e = t.get_overload(t.type_name).call(None, cppyy.CPPInstance, -13) res = t.get_overload("addDataToDouble").call(e, None, 16) assert round(res-3, 8) == 0. e.destruct() @@ -170,7 +170,7 @@ t = self.example01 - e = t.construct(cppyy.CPPInstance, 42) + e = t.get_overload(t.type_name).call(None, cppyy.CPPInstance, 42) res = t.get_overload("addDataToAtoi").call(e, None, "13") assert res == 55 res = t.get_overload("addToStringValue").call(e, None, "12") # TODO: this leaks @@ -187,12 +187,12 @@ t1 = self.example01 t2 = self.payload - pl = t2.construct(cppyy.CPPInstance, 3.14) + pl = t2.get_overload(t2.type_name).call(None, cppyy.CPPInstance, 3.14) assert round(t2.get_overload("getData").call(pl, None)-3.14, 8) == 0 t1.get_overload("staticSetPayload").call(None, None, pl, 41.) # now pl is a CPPInstance assert t2.get_overload("getData").call(pl, None) == 41. - e = t1.construct(cppyy.CPPInstance, 50) + e = t1.get_overload(t1.type_name).call(None, cppyy.CPPInstance, 50) t1.get_overload("setPayload").call(e, None, pl); assert round(t2.get_overload("getData").call(pl, None)-50., 8) == 0 @@ -207,12 +207,12 @@ t1 = self.example01 t2 = self.payload - pl1 = t2.construct(cppyy.CPPInstance, 3.14) + pl1 = t2.get_overload(t2.type_name).call(None, cppyy.CPPInstance, 3.14) assert round(t2.get_overload("getData").call(pl1, None)-3.14, 8) == 0 pl2 = t1.get_overload("staticCyclePayload").call(None, cppyy.CPPInstance, pl1, 38.) assert t2.get_overload("getData").call(pl2, None) == 38. - e = t1.construct(cppyy.CPPInstance, 50) + e = t1.get_overload(t1.type_name).call(None, cppyy.CPPInstance, 50) pl2 = t1.get_overload("cyclePayload").call(e, cppyy.CPPInstance, pl1); assert round(t2.get_overload("getData").call(pl2, None)-50., 8) == 0 From noreply at buildbot.pypy.org Thu Jul 14 18:48:30 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 14 Jul 2011 18:48:30 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, cfbolz): fix pythonify and test_zjit to use the new interface Message-ID: <20110714164830.2E2408291A@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45602:35ece280f108 Date: 2011-07-14 18:46 +0200 http://bitbucket.org/pypy/pypy/changeset/35ece280f108/ Log: (arigo, cfbolz): fix pythonify and test_zjit to use the new interface diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py --- a/pypy/module/cppyy/pythonify.py +++ b/pypy/module/cppyy/pythonify.py @@ -44,8 +44,13 @@ __metaclass__ = CppyyClass def __init__(self, *args): - self._cppinstance = self._cpp_proxy.construct(*args) - + try: + cppol = self._cpp_proxy.get_overload(self._cpp_proxy.type_name) + except AttributeError: + raise TypeError("cannot instantiate abstract class '%s'" % + self._cpp_proxy.type_name) + self._cppinstance = cppol.call(None, cppyy.CPPInstance, *args) + def destruct(self): self._cppinstance.destruct() @@ -61,11 +66,11 @@ rettype = cppol.get_returntype() if not rettype: # return builtin type def function(*args): - return cpptype.invoke(cppol, *args) + return cppol.call(None, cppyy.CPPInstance, *args) else: # return instance cppclass = get_cppclass(rettype) def function(*args): - return bind_object(cpptype.invoke(cppol, *args), cppclass) + return bind_object(cppol.call(None, cppyy.CPPInstance, *args), cppclass) function.__name__ = func_name return staticmethod(function) @@ -73,11 +78,11 @@ rettype = cppol.get_returntype() if not rettype: # return builtin type def method(self, *args): - return self._cppinstance.invoke(cppol, *args) + return cppol.call(self._cppinstance, cppyy.CPPInstance, *args) else: # return instance cppclass = get_cppclass(rettype) def method(self, *args): - return bind_object(self._cppinstance.invoke(cppol, *args), cppclass) + return bind_object(cppol.call(self._cppinstance, cppyy.CPPInstance, *args), cppclass) method.__name__ = meth_name return method diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py --- a/pypy/module/cppyy/test/test_zjit.py +++ b/pypy/module/cppyy/test/test_zjit.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.test.support import LLJitMixin -from pypy.rlib.objectmodel import specialize +from pypy.rlib.objectmodel import specialize, instantiate from pypy.rlib import rarithmetic, jit from pypy.rpython.lltypesystem import rffi from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root @@ -105,6 +105,10 @@ def findattr(self, w_obj, w_name): return None + def allocate_instance(self, cls, w_type): + assert w_type == "stuff" + return instantiate(cls) + def _freeze_(self): return True @@ -115,13 +119,13 @@ def f(): lib = interp_cppyy.load_lib(space, "./example01Dict.so") cls = interp_cppyy.type_byname(space, "example01") - inst = cls.construct([FakeInt(0)]) + inst = cls.get_overload("example01").call(None, "stuff", [FakeInt(0)]) addDataToInt = cls.get_overload("addDataToInt") assert isinstance(inst, interp_cppyy.W_CPPInstance) i = 10 while i > 0: drv.jit_merge_point(inst=inst, addDataToInt=addDataToInt, i=i) - inst.invoke(addDataToInt, [FakeInt(i)]) + addDataToInt.call(inst, None, [FakeInt(i)]) i -= 1 return 7 f() From noreply at buildbot.pypy.org Fri Jul 15 02:23:36 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 15 Jul 2011 02:23:36 +0200 (CEST) Subject: [pypy-commit] pypy default: Actually call the appropriate deallocation function on lock objects when we're done with them, not just deallocate the struct that contains them. It is extremely likely that they have some OS resources assosciated with them. Message-ID: <20110715002336.4B4CE8291A@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45603:e62883bb9a0d Date: 2011-07-14 17:23 -0700 http://bitbucket.org/pypy/pypy/changeset/e62883bb9a0d/ Log: Actually call the appropriate deallocation function on lock objects when we're done with them, not just deallocate the struct that contains them. It is extremely likely that they have some OS resources assosciated with them. diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -21,6 +21,7 @@ 'RPyThreadAcquireLock', 'RPyThreadReleaseLock', 'RPyThreadYield', 'RPyThreadGetStackSize', 'RPyThreadSetStackSize', + 'RPyOpaqueDealloc_ThreadLock', 'RPyThreadAfterFork'] ) @@ -52,6 +53,9 @@ c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], rffi.INT, threadsafe=False) # may add in a global list +c_thread_lock_dealloc = llexternal('RPyOpaqueDealloc_ThreadLock', [TLOCKP], + lltype.Void, + threadsafe=True) c_thread_acquirelock = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT], rffi.INT, threadsafe=True) # release the GIL @@ -120,7 +124,7 @@ def __enter__(self): self.acquire(True) - + def __exit__(self, *args): self.release() @@ -156,6 +160,9 @@ return ll_lock def free_ll_lock(ll_lock): + c_thread_acquirelock(ll_lock, 0) + c_thread_releaselock(ll_lock) + c_thread_lock_dealloc(ll_lock) lltype.free(ll_lock, flavor='raw', track_allocation=False) def acquire_NOAUTO(ll_lock, flag): From noreply at buildbot.pypy.org Fri Jul 15 05:16:39 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 15 Jul 2011 05:16:39 +0200 (CEST) Subject: [pypy-commit] pypy default: Backout the change to use mandatory flags everywhere, this breaks relative imports, as absolute import is marked as mandator in 2.7, but it obviously isn't. Further, CPython doesn't seem to do it, and I can't find any actual advantage to it. Message-ID: <20110715031639.C07868291A@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45604:80dc3701fb24 Date: 2011-07-14 20:15 -0700 http://bitbucket.org/pypy/pypy/changeset/80dc3701fb24/ Log: Backout the change to use mandatory flags everywhere, this breaks relative imports, as absolute import is marked as mandator in 2.7, but it obviously isn't. Further, CPython doesn't seem to do it, and I can't find any actual advantage to it. diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,6 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - flags |= self.future_flags.mandatory_flags fut = misc.parse_future(node, self.future_flags.compiler_features) f_flags, f_lineno, f_col = fut future_pos = f_lineno, f_col @@ -138,7 +137,6 @@ return code def compile_to_ast(self, source, filename, mode, flags): - flags |= self.future_flags.mandatory_flags info = pyparse.CompileInfo(filename, mode, flags) return self._compile_to_ast(source, info) @@ -156,7 +154,6 @@ return mod def compile(self, source, filename, mode, flags, hidden_applevel=False): - flags |= self.future_flags.mandatory_flags info = pyparse.CompileInfo(filename, mode, flags, hidden_applevel=hidden_applevel) mod = self._compile_to_ast(source, info) From noreply at buildbot.pypy.org Fri Jul 15 10:06:55 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 15 Jul 2011 10:06:55 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: add default ctor for CINT usage Message-ID: <20110715080655.2212982931@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45605:bcbad6c3dc54 Date: 2011-07-14 15:01 -0700 http://bitbucket.org/pypy/pypy/changeset/bcbad6c3dc54/ Log: add default ctor for CINT usage diff --git a/pypy/module/cppyy/test/example01.h b/pypy/module/cppyy/test/example01.h --- a/pypy/module/cppyy/test/example01.h +++ b/pypy/module/cppyy/test/example01.h @@ -1,6 +1,6 @@ class payload { public: - payload(double d); + payload(double d = 0.); payload(const payload& p); payload& operator=(const payload& e); ~payload(); From noreply at buildbot.pypy.org Fri Jul 15 10:06:56 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 15 Jul 2011 10:06:56 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: further progress on CINT backend and some Reflex backend sync Message-ID: <20110715080656.5587282931@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45606:78c5c11329a0 Date: 2011-07-14 15:08 -0700 http://bitbucket.org/pypy/pypy/changeset/78c5c11329a0/ Log: further progress on CINT backend and some Reflex backend sync diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py --- a/pypy/module/cppyy/capi/cint_capi.py +++ b/pypy/module/cppyy/capi/cint_capi.py @@ -89,39 +89,39 @@ c_call_v = rffi.llexternal( "cppyy_call_v", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], lltype.Void, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void, compilation_info=eci) c_call_o = rffi.llexternal( "cppyy_call_o", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP, C_TYPEHANDLE], rffi.LONG, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP, C_TYPEHANDLE], rffi.LONG, compilation_info=eci) c_call_b = rffi.llexternal( "cppyy_call_b", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT, compilation_info=eci) c_call_c = rffi.llexternal( "cppyy_call_c", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.CHAR, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CHAR, compilation_info=eci) c_call_h = rffi.llexternal( "cppyy_call_h", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.SHORT, compilation_info=eci) c_call_i = rffi.llexternal( "cppyy_call_i", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT, compilation_info=eci) c_call_l = rffi.llexternal( "cppyy_call_l", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.LONG, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONG, compilation_info=eci) c_call_f = rffi.llexternal( "cppyy_call_f", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.DOUBLE, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE, compilation_info=eci) c_call_d = rffi.llexternal( "cppyy_call_d", - [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.DOUBLE, + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE, compilation_info=eci) @@ -131,6 +131,29 @@ compilation_info=eci) +c_allocate_function_args = rffi.llexternal( + "cppyy_allocate_function_args", + [rffi.SIZE_T], rffi.VOIDP, + compilation_info=eci) + +c_deallocate_function_args = rffi.llexternal( + "cppyy_deallocate_function_args", + [rffi.VOIDP], lltype.Void, + compilation_info=eci) + +c_function_arg_sizeof = rffi.llexternal( + "cppyy_function_arg_sizeof", + [], rffi.SIZE_T, + compilation_info=eci, + elidable_function=True) + +c_function_arg_typeoffset = rffi.llexternal( + "cppyy_function_arg_typeoffset", + [], rffi.SIZE_T, + compilation_info=eci, + elidable_function=True) + + c_num_methods = rffi.llexternal( "cppyy_num_methods", [C_TYPEHANDLE], rffi.INT, diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -369,6 +369,8 @@ def convert_argument(self, space, w_obj, address): x = rffi.cast(rffi.DOUBLEP, address) x[0] = self._unwrap_object(space, w_obj) + typecode = _direct_ptradd(address, capi.c_function_arg_typeoffset()) + typecode[0] = 'd' def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -231,6 +231,8 @@ newthis = capi.c_allocate(self.cpptype.handle) assert lltype.typeOf(newthis) == rffi.VOIDP try: + # TODO: this does not work for CINT, as it calls a temp object + # by value returning method, not placement on newthis ... CPPMethod.call(self, newthis, None, args_w) except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx --- a/pypy/module/cppyy/src/cintcwrapper.cxx +++ b/pypy/module/cppyy/src/cintcwrapper.cxx @@ -13,6 +13,7 @@ #include "TMethod.h" #include "TMethodArg.h" +#include #include #include #include @@ -81,73 +82,85 @@ /* method/function dispatching -------------------------------------------- */ long cppyy_call_o(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[], + cppyy_object_t self, int numargs, void* args, cppyy_typehandle_t rettype) { - void* result = cppyy_allocate(rettype); - /* TODO: perform call ... */ - return (long)result; -} - -static inline G__value cppyy_call_T(cppyy_typehandle_t handle, - int method_index, cppyy_object_t self, int numargs, void* args[]) { TClassRef cr = type_from_handle(handle); TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); G__InterfaceMethod meth = (G__InterfaceMethod)m->InterfaceMethod(); - G__param libp; - for (int i = 0; i < numargs; ++i ) { - G__letint(&libp.para[i], 'u', *(long*)args[i]); // TODO: use actual type code - } + G__param* libp = (G__param*)((char*)args - offsetof(G__param, para)); + assert(libp->paran == numargs); + + long obj = (long)cppyy_allocate(rettype); + G__setgvp(obj); G__value result; - meth(&result, 0, &libp, 0); + G__setnull(&result); + meth(&result, 0, libp, 0); + + // G__pop_tempobject_nodel(); # TODO: not sure ... + return obj; +} + +static inline G__value cppyy_call_T(cppyy_typehandle_t handle, + int method_index, cppyy_object_t self, int numargs, void* args) { + TClassRef cr = type_from_handle(handle); + TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); + + G__InterfaceMethod meth = (G__InterfaceMethod)m->InterfaceMethod(); + G__param* libp = (G__param*)((char*)args - offsetof(G__param, para)); + assert(libp->paran == numargs); + + G__value result; + G__setnull(&result); + meth(&result, 0, libp, 0); return result; } void cppyy_call_v(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { cppyy_call_T(handle, method_index, self, numargs, args); } int cppyy_call_b(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); return (bool)G__int(result); } char cppyy_call_c(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); return (char)G__int(result); } short cppyy_call_h(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); return (short)G__int(result); } int cppyy_call_i(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); return (int)G__int(result); } long cppyy_call_l(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); return G__int(result); } double cppyy_call_f(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); return G__double(result); } double cppyy_call_d(cppyy_typehandle_t handle, int method_index, - cppyy_object_t self, int numargs, void* args[]) { + cppyy_object_t self, int numargs, void* args) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); return G__double(result); } @@ -158,6 +171,30 @@ } +/* handling of function argument buffer ----------------------------------- */ +void* cppyy_allocate_function_args(size_t nargs) { + assert(sizeof(CPPYY_G__value) == sizeof(G__value)); + G__param* libp = (G__param*)malloc( + offsetof(G__param, para) + nargs*sizeof(CPPYY_G__value)); + libp->paran = (int)nargs; + for (int i = 0; i < nargs; ++i) + libp->para[i].type = 'l'; + return (void*)libp->para; +} + +void cppyy_deallocate_function_args(void* args) { + free((char*)args - offsetof(G__param, para)); +} + +size_t cppyy_function_arg_sizeof() { + return sizeof(CPPYY_G__value); +} + +size_t cppyy_function_arg_typeoffset() { + return offsetof(CPPYY_G__value, type); +} + + /* scope reflection information ------------------------------------------- */ int cppyy_is_namespace(cppyy_typehandle_t handle) { TClassRef cr = type_from_handle(handle); @@ -195,7 +232,7 @@ return 1; TClassRef crd = type_from_handle(dh); TClassRef crb = type_from_handle(bh); - return (int)crd->GetBaseClass(crb); + return crd->GetBaseClass(crb) != 0; } size_t cppyy_base_offset(cppyy_typehandle_t dh, cppyy_typehandle_t bh) { diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx --- a/pypy/module/cppyy/src/reflexcwrapper.cxx +++ b/pypy/module/cppyy/src/reflexcwrapper.cxx @@ -34,7 +34,7 @@ std::vector arguments; arguments.reserve(numargs); for (int i=0; i < numargs; ++i) { - if (((CPPYY_G__value*)args)[i].type == 'l') + if (((CPPYY_G__value*)args)[i].type != 'a') arguments.push_back(&((CPPYY_G__value*)args)[i]); else arguments.push_back((void*)(*(long*)&((CPPYY_G__value*)args)[i])); @@ -200,7 +200,7 @@ } -/* handling of function argument buffer */ +/* handling of function argument buffer ----------------------------------- */ void* cppyy_allocate_function_args(size_t nargs) { CPPYY_G__param* libp = (CPPYY_G__param*)malloc( sizeof(int/*CPPYY_G__param.paran*/) + nargs*sizeof(CPPYY_G__value)); diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile --- a/pypy/module/cppyy/test/Makefile +++ b/pypy/module/cppyy/test/Makefile @@ -28,7 +28,7 @@ $(genreflex) example01.h $(genreflexflags) --selection=example01.xml g++ -o $@ example01_rflx.cpp example01.cxx -shared -lReflex $(cppflags) $(cppflags2) -# rootcint -f example01_cint.cxx -c example01.h +# rootcint -f example01_cint.cxx -c example01.h example01_LinkDef.h # g++ -I$ROOTSYS/include example01_cint.cxx example01.cxx -shared -o example01Dict.so -L$ROOTSYS/lib -lCore -lCint datatypesDict.so: datatypes.cxx datatypes.h From noreply at buildbot.pypy.org Fri Jul 15 10:34:35 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 15 Jul 2011 10:34:35 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: test fix Message-ID: <20110715083435.8C10982931@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45607:ead8a92a4f9f Date: 2011-07-13 17:15 +0200 http://bitbucket.org/pypy/pypy/changeset/ead8a92a4f9f/ Log: test fix diff --git a/pypy/jit/backend/arm/test/test_assembler.py b/pypy/jit/backend/arm/test/test_assembler.py --- a/pypy/jit/backend/arm/test/test_assembler.py +++ b/pypy/jit/backend/arm/test/test_assembler.py @@ -26,6 +26,7 @@ self.a.setup_once() token = LoopToken() clt = CompiledLoopToken(cpu, 0) + clt.allgcrefs = [] token.compiled_loop_token = clt self.a.setup(token, []) From noreply at buildbot.pypy.org Fri Jul 15 10:34:36 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 15 Jul 2011 10:34:36 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: translation fixes Message-ID: <20110715083436.BF70F82931@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45608:6cf24885c6df Date: 2011-07-14 13:00 +0200 http://bitbucket.org/pypy/pypy/changeset/6cf24885c6df/ Log: translation fixes diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -135,6 +135,7 @@ after = rffi.aroundstate.after if after: after() + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) def _build_release_gil(self, gcrootmap): assert gcrootmap.is_shadow_stack @@ -142,8 +143,8 @@ self._release_gil_shadowstack) reacqgil_func = llhelper(self._NOARG_FUNC, self._reacquire_gil_shadowstack) - self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) - self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + self.releasegil_addr = rffi.cast(lltype.Signed, releasegil_func) + self.reacqgil_addr = rffi.cast(lltype.Signed, reacqgil_func) def setup_failure_recovery(self): diff --git a/pypy/jit/backend/arm/opassembler.py b/pypy/jit/backend/arm/opassembler.py --- a/pypy/jit/backend/arm/opassembler.py +++ b/pypy/jit/backend/arm/opassembler.py @@ -480,7 +480,7 @@ else: callargs = [r.r0, r.r1, r.r2] remap_frame_layout(self, arglocs, callargs, r.ip) - func = self.cpu.cast_adr_to_int(addr) + func = rffi.cast(lltype.Signed, addr) # # misaligned stack in the call, but it's ok because the write barrier # is not going to call anything more. @@ -952,32 +952,31 @@ emit_guard_call_release_gil = emit_guard_call_may_force - def call_release_gil(self, gcrootmap, save_registers): + def call_release_gil(self, gcrootmap, save_registers, fcond): # First, we need to save away the registers listed in # 'save_registers' that are not callee-save. XXX We assume that # the floating point registers won't be modified. - import pdb; pdb.set_trace() regs_to_save = [] for reg in self._regalloc.rm.save_around_call_regs: if reg in save_registers: regs_to_save.append(reg) assert gcrootmap.is_shadow_stack with saved_registers(self.mc, regs_to_save): - self._emit_call(-1, self.releasegil_addr, [], regalloc, fcond) + self._emit_call(-1, self.releasegil_addr, [], self._regalloc, fcond) - def call_reacquire_gil(self, gcrootmap, save_loc): + def call_reacquire_gil(self, gcrootmap, save_loc, fcond): # save the previous result into the stack temporarily. # XXX like with call_release_gil(), we assume that we don't need # to save vfp regs in this case. regs_to_save = [] - if isinstance(save_loc, RegLoc) and not save_loc.is_vfp_reg(): + if save_loc.is_reg(): regs_to_save.append(save_loc) # call the reopenstack() function (also reacquiring the GIL) if len(regs_to_save) == 1: regs_to_save.append(r.ip) # for alingment assert gcrootmap.is_shadow_stack with saved_registers(self.mc, regs_to_save): - self._emit_call(-1, self.reacqgil_addr, [], regalloc, fcond) + self._emit_call(-1, self.reacqgil_addr, [], self._regalloc, fcond) def write_new_force_index(self): # for shadowstack only: get a new, unused force_index number and diff --git a/pypy/jit/backend/arm/regalloc.py b/pypy/jit/backend/arm/regalloc.py --- a/pypy/jit/backend/arm/regalloc.py +++ b/pypy/jit/backend/arm/regalloc.py @@ -1008,7 +1008,7 @@ loc, box = self._ensure_value_is_boxed(op.getarg(i), argboxes) arglocs.append(loc) argboxes.append(box) - self.assembler.call_release_gil(gcrootmap, arglocs) + self.assembler.call_release_gil(gcrootmap, arglocs, fcond) self.possibly_free_vars(argboxes) # do the call faildescr = guard_op.getdescr() @@ -1017,7 +1017,7 @@ self.assembler.emit_op_call(op, args, self, fcond, fail_index) # then reopen the stack if gcrootmap: - self.call_reacquire_gil(gcrootmap, r.r0) + self.assembler.call_reacquire_gil(gcrootmap, r.r0, fcond) locs = self._prepare_guard(guard_op) self.possibly_free_vars(guard_op.getfailargs()) return locs diff --git a/pypy/jit/backend/arm/runner.py b/pypy/jit/backend/arm/runner.py --- a/pypy/jit/backend/arm/runner.py +++ b/pypy/jit/backend/arm/runner.py @@ -100,10 +100,11 @@ LLInterpreter.current_interpreter = prev_interpreter return res - @staticmethod def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return ArmCPU.cast_adr_to_int(adr) + cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)' + cast_ptr_to_int = staticmethod(cast_ptr_to_int) def force(self, addr_of_force_index): TP = rffi.CArrayPtr(lltype.Signed) From noreply at buildbot.pypy.org Fri Jul 15 10:34:38 2011 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 15 Jul 2011 10:34:38 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: fix test_gc_integration Message-ID: <20110715083438.01D9182931@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45609:ed3eaad9f4fe Date: 2011-07-15 10:34 +0200 http://bitbucket.org/pypy/pypy/changeset/ed3eaad9f4fe/ Log: fix test_gc_integration diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -117,7 +117,7 @@ ll_new_unicode) if gc_ll_descr.get_malloc_slowpath_addr is not None: self._build_malloc_slowpath() - if gc_ll_descr.gcrootmap: + if gc_ll_descr.gcrootmap and gc_ll_descr.is_shadow_stack: self._build_release_gil(gc_ll_descr.gcrootmap) self.memcpy_addr = self.cpu.cast_ptr_to_int(memcpy_fn) self._exit_code_addr = self._gen_exit_path() diff --git a/pypy/jit/backend/arm/test/test_gc_integration.py b/pypy/jit/backend/arm/test/test_gc_integration.py --- a/pypy/jit/backend/arm/test/test_gc_integration.py +++ b/pypy/jit/backend/arm/test/test_gc_integration.py @@ -16,7 +16,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.annlowlevel import llhelper from pypy.rpython.lltypesystem import rclass, rstr -from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList, GcPtrFieldDescr +from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcPtrFieldDescr from pypy.jit.backend.arm.test.test_regalloc import MockAssembler from pypy.jit.backend.arm.test.test_regalloc import BaseTestRegalloc @@ -54,6 +54,7 @@ return ['compressed'] + shape[1:] class MockGcDescr(GcCache): + is_shadow_stack = False def get_funcptr_for_new(self): return 123 get_funcptr_for_newarray = get_funcptr_for_new @@ -65,11 +66,9 @@ gcrootmap = MockGcRootMap() def initialize(self): - self.gcrefs = GcRefList() - self.gcrefs.initialize() - self.single_gcref_descr = GcPtrFieldDescr('', 0) - - replace_constptrs_with_getfield_raw = GcLLDescr_framework.replace_constptrs_with_getfield_raw.im_func + pass + + record_constptrs = GcLLDescr_framework.record_constptrs.im_func rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func class TestRegallocDirectGcIntegration(object): From noreply at buildbot.pypy.org Fri Jul 15 11:54:46 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 15 Jul 2011 11:54:46 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: reflex c wrapper cleanup Message-ID: <20110715095446.3B3A382931@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45610:11a4cd3dac31 Date: 2011-07-15 02:54 -0700 http://bitbucket.org/pypy/pypy/changeset/11a4cd3dac31/ Log: reflex c wrapper cleanup diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h --- a/pypy/module/cppyy/include/cppyy.h +++ b/pypy/module/cppyy/include/cppyy.h @@ -1,8 +1,6 @@ #ifndef CPPYY_CPPYY #define CPPYY_CPPYY -#define CPPYY_G__MAXFUNCPARA 40 - #ifdef __cplusplus struct CPPYY_G__DUMMY_FOR_CINT7 { #else @@ -63,19 +61,4 @@ } CPPYY_G__value; #endif - -#ifdef __cplusplus -struct CPPYY_G__param { -#else -typedef struct -#endif - int paran; - long para; /* place-holder */ - /* dropped parameter as it appears unused in stub functions */ -#ifdef __cplusplus -}; -#else -} CPPYY_G__param; -#endif - #endif // CPPYY_CPPYY diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx --- a/pypy/module/cppyy/src/reflexcwrapper.cxx +++ b/pypy/module/cppyy/src/reflexcwrapper.cxx @@ -202,16 +202,14 @@ /* handling of function argument buffer ----------------------------------- */ void* cppyy_allocate_function_args(size_t nargs) { - CPPYY_G__param* libp = (CPPYY_G__param*)malloc( - sizeof(int/*CPPYY_G__param.paran*/) + nargs*sizeof(CPPYY_G__value)); - libp->paran = (int)nargs; + CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value)); for (int i = 0; i < nargs; ++i) - ((CPPYY_G__value*)&libp->para)[i].type = 'l'; - return (void*)&libp->para; + args[i].type = 'l'; + return (void*)args; } void cppyy_deallocate_function_args(void* args) { - free((char*)args - offsetof(CPPYY_G__param, para)); + free(args); } size_t cppyy_function_arg_sizeof() { From noreply at buildbot.pypy.org Fri Jul 15 11:58:17 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 15 Jul 2011 11:58:17 +0200 (CEST) Subject: [pypy-commit] buildbot default: just disable the jit Message-ID: <20110715095817.E9D7A82931@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r526:acf8d8be6447 Date: 2011-07-15 11:57 +0200 http://bitbucket.org/pypy/buildbot/changeset/acf8d8be6447/ Log: just disable the jit diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -308,7 +308,7 @@ '--revision', WithProperties('%(got_revision)s'), '--upload', #'--force-host', 'bigdog', '--branch', WithProperties('%(branch)s'), - '--args', ',--jit threshold=0 --jit function_threshold=0'], + '--args', ',--jit off'], workdir='./benchmarks', haltOnFailure=True)) resfile = os.path.expanduser("~/bench_results_nojit/%(got_revision)s.json") From noreply at buildbot.pypy.org Fri Jul 15 13:08:58 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 13:08:58 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix for e38414a7518d. Message-ID: <20110715110858.ACB7682931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45611:004a414eebdc Date: 2011-07-15 13:05 +0200 http://bitbucket.org/pypy/pypy/changeset/004a414eebdc/ Log: Fix for e38414a7518d. diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py --- a/pypy/module/sys/test/test_sysmodule.py +++ b/pypy/module/sys/test/test_sysmodule.py @@ -476,7 +476,7 @@ assert isinstance(vi[0], int) assert isinstance(vi[1], int) assert isinstance(vi[2], int) - assert vi[3] in ("alpha", "beta", "candidate", "final") + assert vi[3] in ("alpha", "beta", "candidate", "dev", "final") assert isinstance(vi[4], int) def test_allattributes(self): @@ -523,4 +523,4 @@ # If this ever actually becomes a compilation option this test should # be changed. - assert sys.float_repr_style == "short" \ No newline at end of file + assert sys.float_repr_style == "short" From noreply at buildbot.pypy.org Fri Jul 15 13:08:59 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 13:08:59 +0200 (CEST) Subject: [pypy-commit] pypy default: Missing bump of the revision number here. Message-ID: <20110715110859.D8D2782931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45612:6e7de8d8d4e6 Date: 2011-07-15 13:07 +0200 http://bitbucket.org/pypy/pypy/changeset/6e7de8d8d4e6/ Log: Missing bump of the revision number here. diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.1" /* PyPy version as a string */ -#define PYPY_VERSION "1.5.0" +#define PYPY_VERSION "1.6.0" /* Subversion Revision number of this file (not of the repository) */ #define PY_PATCHLEVEL_REVISION "$Revision: 77872 $" From noreply at buildbot.pypy.org Fri Jul 15 13:18:48 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 15 Jul 2011 13:18:48 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, cfbolz): refactoring: pass a bit everywhere the subtype that should be Message-ID: <20110715111848.AAF8282931@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45613:5ac7b89a8285 Date: 2011-07-15 13:18 +0200 http://bitbucket.org/pypy/pypy/changeset/5ac7b89a8285/ Log: (arigo, cfbolz): refactoring: pass a bit everywhere the subtype that should be used for resulting W_CPPInstance instances. This makes it possible to not need a wrapper on the Python side any more. diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -15,11 +15,12 @@ def get_rawobject(space, w_obj): if not space.eq_w(w_obj, space.w_None): from pypy.module.cppyy.interp_cppyy import W_CPPInstance - w_cpp_instance = space.findattr(w_obj, space.wrap("_cppinstance")) - cpp_instance = space.interp_w(W_CPPInstance, w_cpp_instance, can_be_None=True) + cpp_instance = space.interp_w(W_CPPInstance, w_obj) if cpp_instance: assert lltype.typeOf(cpp_instance.rawobject) == rffi.VOIDP return cpp_instance.rawobject + else: + xxx return lltype.nullptr(rffi.VOIDP.TO) def _direct_ptradd(ptr, offset): @@ -31,6 +32,8 @@ _immutable = True libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO) + name = "" + def __init__(self, space, array_size): pass @@ -54,7 +57,7 @@ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible raise FastCallNotPossible - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): self._is_abstract() def to_memory(self, space, w_obj, w_value, offset): @@ -88,7 +91,7 @@ else: self.size = array_size - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): if hasattr(space, "fake"): raise NotImplementedError # read access, so no copy needed @@ -114,7 +117,7 @@ def __init__(self, space, array_size): self.size = sys.maxint - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): # read access, so no copy needed address_value = self._get_raw_address(space, w_obj, offset) address = rffi.cast(rffi.ULONGP, address_value) @@ -164,7 +167,7 @@ def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) if address[0] == '\x01': return space.w_True @@ -206,7 +209,7 @@ def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) return space.wrap(address[0]) @@ -228,7 +231,7 @@ def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) intptr = rffi.cast(rffi.INTP, address) return space.wrap(intptr[0]) @@ -252,7 +255,7 @@ def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) ulongptr = rffi.cast(rffi.UINTP, address) return space.wrap(ulongptr[0]) @@ -276,7 +279,7 @@ def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) longptr = rffi.cast(rffi.LONGP, address) return space.wrap(longptr[0]) @@ -300,7 +303,7 @@ def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) ulongptr = rffi.cast(rffi.ULONGP, address) return space.wrap(ulongptr[0]) @@ -324,7 +327,7 @@ def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) shortptr = rffi.cast(rffi.SHORTP, address) return space.wrap(shortptr[0]) @@ -349,7 +352,7 @@ # it's required to sent an rffi.DOUBLE not r_singlefloat argchain.arg_singlefloat(space.float_w(w_obj)) - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) floatptr = rffi.cast(rffi.FLOATP, address) return space.wrap(float(floatptr[0])) @@ -375,7 +378,7 @@ def convert_argument_libffi(self, space, w_obj, argchain): argchain.arg(self._unwrap_object(space, w_obj)) - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) doubleptr = rffi.cast(rffi.DOUBLEP, address) return space.wrap(doubleptr[0]) @@ -396,7 +399,7 @@ typecode = _direct_ptradd(address, capi.c_function_arg_typeoffset()) typecode[0] = 'a' - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = self._get_raw_address(space, w_obj, offset) charpptr = rffi.cast(rffi.CCHARPP, address) return space.wrap(rffi.charp2str(charpptr[0])) @@ -471,8 +474,9 @@ _immutable_ = True _immutable_fields_ = ["cpptype"] - def __init__(self, space, cpptype): + def __init__(self, space, cpptype, name): self.cpptype = cpptype + self.name = name def _unwrap_object(self, space, w_obj): from pypy.module.cppyy.interp_cppyy import W_CPPInstance @@ -503,10 +507,10 @@ class InstanceConverter(InstancePtrConverter): _immutable_ = True - def from_memory(self, space, w_obj, offset): + def from_memory(self, space, w_obj, w_type, offset): address = rffi.cast(rffi.VOIDP, self._get_raw_address(space, w_obj, offset)) from pypy.module.cppyy import interp_cppyy - return interp_cppyy.W_CPPInstance(space, self.cpptype, address, False) + return interp_cppyy.new_instance(space, w_type, self.cpptype, address, False) _converters = {} @@ -552,9 +556,9 @@ from pypy.module.cppyy.interp_cppyy import W_CPPType cpptype = space.interp_w(W_CPPType, cpptype, can_be_None=False) if compound == "*" or compound == "&": - return InstancePtrConverter(space, cpptype) + return InstancePtrConverter(space, cpptype, clean_name) elif compound == "": - return InstanceConverter(space, cpptype) + return InstanceConverter(space, cpptype, clean_name) # 6) void converter, which fails on use # diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -19,10 +19,10 @@ def __init__(self, space, name, cpptype): self.name = name - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): raise NotImplementedError - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): from pypy.module.cppyy.interp_cppyy import FastCallNotPossible raise FastCallNotPossible @@ -31,7 +31,7 @@ _immutable_ = True typecode = 'P' - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): if hasattr(space, "fake"): raise NotImplementedError lresult = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) @@ -44,11 +44,11 @@ _immutable_ = True libffitype = libffi.types.void - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): capi.c_call_v(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.w_None - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): libffifunc.call(argchain, lltype.Void) return space.w_None @@ -57,11 +57,11 @@ _immutable_ = True libffitype = libffi.types.schar - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): result = capi.c_call_b(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.CHAR) return space.wrap(bool(ord(result))) @@ -69,11 +69,11 @@ _immutable_ = True libffitype = libffi.types.schar - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): result = capi.c_call_c(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.CHAR) return space.wrap(result) @@ -81,11 +81,11 @@ _immutable_ = True libffitype = libffi.types.sshort - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): result = capi.c_call_h(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.SHORT) return space.wrap(result) @@ -96,11 +96,11 @@ def _wrap_result(self, space, result): return space.wrap(result) - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): result = capi.c_call_i(func.cpptype.handle, func.method_index, cppthis, num_args, args) return self._wrap_result(space, result) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.INT) return space.wrap(result) @@ -111,11 +111,11 @@ def _wrap_result(self, space, result): return space.wrap(rffi.cast(rffi.UINT, result)) - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) return self._wrap_result(space, result) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.UINT) return space.wrap(result) @@ -126,11 +126,11 @@ def _wrap_result(self, space, result): return space.wrap(result) - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) return self._wrap_result(space, result) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.LONG) return space.wrap(result) @@ -141,7 +141,7 @@ def _wrap_result(self, space, result): return space.wrap(rffi.cast(rffi.ULONG, result)) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.ULONG) return space.wrap(result) @@ -153,7 +153,7 @@ intptr = rffi.cast(rffi.INTP, result) return space.wrap(intptr[0]) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.INTP) return space.wrap(result[0]) @@ -165,7 +165,7 @@ longptr = rffi.cast(rffi.LONGP, result) return space.wrap(longptr[0]) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.LONGP) return space.wrap(result[0]) @@ -173,11 +173,11 @@ _immutable_ = True libffitype = libffi.types.float - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): result = capi.c_call_f(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.FLOAT) return space.wrap(result) @@ -185,11 +185,11 @@ _immutable_ = True libffitype = libffi.types.double - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): result = capi.c_call_d(func.cpptype.handle, func.method_index, cppthis, num_args, args) return space.wrap(result) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): result = libffifunc.call(argchain, rffi.DOUBLE) return space.wrap(result) @@ -197,7 +197,7 @@ class CStringExecutor(FunctionExecutor): _immutable_ = True - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): lresult = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) ccpresult = rffi.cast(rffi.CCHARP, lresult) result = rffi.charp2str(ccpresult) # TODO: make it a choice to free @@ -241,28 +241,28 @@ FunctionExecutor.__init__(self, space, name, cpptype) self.cpptype = cpptype - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_l( func.cpptype.handle, func.method_index, cppthis, num_args, args) ptr_result = rffi.cast(rffi.VOIDP, long_result) - return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) + return interp_cppyy.new_instance(space, w_returntype, self.cpptype, ptr_result, False) - def execute_libffi(self, space, libffifunc, argchain): + def execute_libffi(self, space, w_returntype, libffifunc, argchain): from pypy.module.cppyy import interp_cppyy ptr_result = rffi.cast(rffi.VOIDP, libffifunc.call(argchain, rffi.VOIDP)) - return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) + return interp_cppyy.new_instance(space, w_returntype, self.cpptype, ptr_result, False) class InstanceExecutor(InstancePtrExecutor): _immutable_ = True - def execute(self, space, func, cppthis, num_args, args): + def execute(self, space, w_returntype, func, cppthis, num_args, args): from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_o( func.cpptype.handle, func.method_index, cppthis, num_args, args, self.cpptype.handle) ptr_result = rffi.cast(rffi.VOIDP, long_result) - return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, True) + return interp_cppyy.new_instance(space, w_returntype, self.cpptype, ptr_result, True) _executors = {} diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -109,18 +109,18 @@ if self.methgetter and cppthis: # only for methods try: - return self.do_fast_call(cppthis, args_w) + return self.do_fast_call(cppthis, w_type, args_w) except FastCallNotPossible: pass args = self.prepare_arguments(args_w) try: - return self.executor.execute(self.space, self, cppthis, len(args_w), args) + return self.executor.execute(self.space, w_type, self, cppthis, len(args_w), args) finally: self.free_arguments(args, len(args_w)) @jit.unroll_safe - def do_fast_call(self, cppthis, args_w): + def do_fast_call(self, cppthis, w_type, args_w): space = self.space # XXX factor out if len(self.arg_types) < len(args_w) or len(args_w) < self.args_required: @@ -139,7 +139,7 @@ conv = self.arg_converters[i] w_arg = args_w[i] conv.convert_argument_libffi(space, w_arg, argchain) - return self.executor.execute_libffi(space, libffi_func, argchain) + return self.executor.execute_libffi(space, w_type, libffi_func, argchain) @jit.elidable_promote() def _get_libffi_func(self, funcptr): @@ -218,7 +218,7 @@ assert not cppthis args = self.prepare_arguments(args_w) try: - return self.executor.execute(self.space, self, NULL_VOIDP, + return self.executor.execute(self.space, w_type, self, NULL_VOIDP, len(args_w), args) finally: self.free_arguments(args, len(args_w)) @@ -237,10 +237,7 @@ except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) raise - w_instance = self.space.allocate_instance(W_CPPInstance, w_type) - instance = self.space.interp_w(W_CPPInstance, w_instance) - W_CPPInstance.__init__(instance, self.space, self.cpptype, newthis, True) - return w_instance + return new_instance(self.space, w_type, self.cpptype, newthis, True) class W_CPPOverload(Wrappable): @@ -303,47 +300,31 @@ _immutable_=True _immutable_fields_ = ["converter", "offset"] - def __init__(self, space, type_name, offset): + def __init__(self, space, type_name, offset, is_static): self.space = space self.converter = converter.get_converter(self.space, type_name) self.offset = offset + self._is_static = is_static + + def get_returntype(self): + return self.space.wrap(self.converter.name) def is_static(self): - return self.space.w_False + return self.space.newbool(self._is_static) - def __get__(self, args_w): - return self.converter.from_memory(self.space, args_w[0], self.offset) + def get(self, w_cppinstance, w_type): + return self.converter.from_memory(self.space, w_cppinstance, w_type, self.offset) - def __set__(self, args_w): - self.converter.to_memory(self.space, args_w[0], args_w[1], self.offset) + def set(self, w_cppinstance, w_value): + self.converter.to_memory(self.space, w_cppinstance, w_value, self.offset) return self.space.w_None W_CPPDataMember.typedef = TypeDef( 'CPPDataMember', is_static = interp2app(W_CPPDataMember.is_static, unwrap_spec=['self']), - __get__ = interp2app(W_CPPDataMember.__get__, unwrap_spec=['self', 'args_w']), - __set__ = interp2app(W_CPPDataMember.__set__, unwrap_spec=['self', 'args_w']), -) - - -class W_CPPStaticDataMember(W_CPPDataMember): - _immutable_=True - - def is_static(self): - return self.space.w_True - - def __get__(self, args_w): - return self.converter.from_memory(self.space, self.space.w_None, self.offset) - - def __set__(self, args_w): - self.converter.to_memory(self.space, self.space.w_None, args_w[1], self.offset) - return self.space.w_None - -W_CPPStaticDataMember.typedef = TypeDef( - 'CPPStaticDataMember', - is_static = interp2app(W_CPPStaticDataMember.is_static, unwrap_spec=['self']), - __get__ = interp2app(W_CPPStaticDataMember.__get__, unwrap_spec=['self', 'args_w']), - __set__ = interp2app(W_CPPStaticDataMember.__set__, unwrap_spec=['self', 'args_w']), + get_returntype = interp2app(W_CPPDataMember.get_returntype, unwrap_spec=['self']), + get = interp2app(W_CPPDataMember.get, unwrap_spec=['self', W_Root, W_Root]), + set = interp2app(W_CPPDataMember.set, unwrap_spec=['self', W_Root, W_Root]), ) @@ -387,9 +368,7 @@ try: return self.methods[name] except KeyError: - raise OperationError( - self.space.w_AttributeError, - self.space.wrap(str("class %s has no attribute %s" % (self.name, name)))) + raise self.missing_attribute_error(name) def get_data_member_names(self): return self.space.newlist([self.space.wrap(name) for name in self.data_members]) @@ -399,9 +378,12 @@ try: return self.data_members[name] except KeyError: - raise OperationError( - self.space.w_AttributeError, - self.space.wrap(str("class %s has no attribute %s" % (self.name, name)))) + raise self.missing_attribute_error(name) + + def missing_attribute_error(self, name): + return OperationError( + self.space.w_AttributeError, + self.space.wrap("%s '%s' has no attribute %s" % (self.kind, self.name, name))) W_CPPScope.typedef = TypeDef( 'CPPScope', @@ -417,6 +399,7 @@ # classes for inheritance. Both are python classes, though, and refactoring # may be in order at some point. class W_CPPNamespace(W_CPPScope): + kind = "namespace" def _make_cppfunction(self, method_index): result_type = capi.charp2str_free(capi.c_method_result_type(self.handle, method_index)) @@ -435,7 +418,7 @@ if not data_member_name in self.data_members: type_name = capi.charp2str_free(capi.c_data_member_type(self.handle, i)) offset = capi.c_data_member_offset(self.handle, i) - data_member = W_CPPStaticDataMember(self.space, type_name, offset) + data_member = W_CPPDataMember(self.space, type_name, offset, True) self.data_members[data_member_name] = data_member def update(self): @@ -445,6 +428,7 @@ def is_namespace(self): return self.space.w_True + W_CPPNamespace.typedef = TypeDef( 'CPPNamespace', update = interp2app(W_CPPNamespace.update, unwrap_spec=['self']), @@ -457,6 +441,7 @@ class W_CPPType(W_CPPScope): + kind = "class" def _make_cppfunction(self, method_index): result_type = capi.charp2str_free(capi.c_method_result_type(self.handle, method_index)) @@ -480,10 +465,8 @@ data_member_name = capi.charp2str_free(capi.c_data_member_name(self.handle, i)) type_name = capi.charp2str_free(capi.c_data_member_type(self.handle, i)) offset = capi.c_data_member_offset(self.handle, i) - if capi.c_is_staticdata(self.handle, i): - data_member = W_CPPStaticDataMember(self.space, type_name, offset) - else: - data_member = W_CPPDataMember(self.space, type_name, offset) + is_static = bool(capi.c_is_staticdata(self.handle, i)) + data_member = W_CPPDataMember(self.space, type_name, offset, is_static) self.data_members[data_member_name] = data_member def is_namespace(self): @@ -559,3 +542,9 @@ cppclass = interp_attrproperty('cppclass', W_CPPInstance), destruct = interp2app(W_CPPInstance.destruct, unwrap_spec=['self']), ) + +def new_instance(space, w_type, cpptype, rawptr, owns): + w_instance = space.allocate_instance(W_CPPInstance, w_type) + instance = space.interp_w(W_CPPInstance, w_instance) + W_CPPInstance.__init__(instance, space, cpptype, rawptr, owns) + return w_instance diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py --- a/pypy/module/cppyy/pythonify.py +++ b/pypy/module/cppyy/pythonify.py @@ -20,6 +20,9 @@ class CppyyClass(CppyyScopeMeta): pass +class CPPObject(cppyy.CPPInstance): + __metaclass__ = CppyyClass + class CppyyTemplateType(object): def __init__(self, scope, name): @@ -40,62 +43,48 @@ fullname += '>' return getattr(self._scope, fullname) -class CppyyObject(object): - __metaclass__ = CppyyClass - def __init__(self, *args): - try: - cppol = self._cpp_proxy.get_overload(self._cpp_proxy.type_name) - except AttributeError: - raise TypeError("cannot instantiate abstract class '%s'" % - self._cpp_proxy.type_name) - self._cppinstance = cppol.call(None, cppyy.CPPInstance, *args) - def destruct(self): - self._cppinstance.destruct() - - -def bind_object(cppobj, cppclass): - if cppobj is None: - return None - bound_obj = object.__new__(cppclass) - bound_obj._cppinstance = cppobj - return bound_obj def make_static_function(cpptype, func_name, cppol): rettype = cppol.get_returntype() if not rettype: # return builtin type - def function(*args): - return cppol.call(None, cppyy.CPPInstance, *args) + cppclass = None else: # return instance cppclass = get_cppclass(rettype) - def function(*args): - return bind_object(cppol.call(None, cppyy.CPPInstance, *args), cppclass) + def function(*args): + return cppol.call(None, cppclass, *args) function.__name__ = func_name return staticmethod(function) def make_method(meth_name, cppol): rettype = cppol.get_returntype() if not rettype: # return builtin type - def method(self, *args): - return cppol.call(self._cppinstance, cppyy.CPPInstance, *args) + cppclass = None else: # return instance cppclass = get_cppclass(rettype) - def method(self, *args): - return bind_object(cppol.call(self._cppinstance, cppyy.CPPInstance, *args), cppclass) + def method(self, *args): + return cppol.call(self, cppclass, *args) method.__name__ = meth_name return method def make_datamember(cppdm): - import cppyy - def binder(obj, owner=None): - value = cppdm.__get__(obj, owner) - if isinstance(value, cppyy.CPPInstance): - cppclass = get_cppclass(value.cppclass.type_name) - return bind_object(value, cppclass) - return value - return property(binder, cppdm.__set__) + rettype = cppdm.get_returntype() + if not rettype: # return builtin type + cppclass = None + else: # return instance + cppclass = get_cppclass(rettype) + if cppdm.is_static(): + def binder(obj): + return cppdm.get(None, cppclass) + def setter(obj, value): + return cppdm.set(None, value) + else: + def binder(obj): + return cppdm.get(obj, cppclass) + setter = cppdm.set + return property(binder, setter) def make_cppnamespace(namespace_name, cppns): d = {"_cpp_proxy" : cppns} @@ -133,19 +122,34 @@ break return tuple(bases) +def make_new(class_name, cpptype): + try: + constructor_overload = cpptype.get_overload(cpptype.type_name) + except AttributeError: + msg = "cannot instantiate abstract class '%s'" % class_name + def __new__(cls, *args): + raise TypeError(msg) + else: + def __new__(cls, *args): + return constructor_overload.call(None, cls, *args) + return __new__ + def make_cppclass(class_name, cpptype): # get a list of base classes for class creation bases = [get_cppclass(base) for base in cpptype.get_base_names()] if not bases: - bases = [CppyyObject,] + bases = [CPPObject,] # create a meta class to allow properties (for static data write access) metabases = [type(base) for base in bases] metacpp = type(CppyyClass)(class_name+'_meta', _drop_cycles(metabases), {}) + # create the python-side C++ class representation - d = {"_cpp_proxy" : cpptype} + d = {"_cpp_proxy" : cpptype, + "__new__" : make_new(class_name, cpptype), + } pycpptype = metacpp(class_name, _drop_cycles(bases), d) # cache result early so that the class methods can find the class itself diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py --- a/pypy/module/cppyy/test/test_pythonify.py +++ b/pypy/module/cppyy/test/test_pythonify.py @@ -135,7 +135,7 @@ pl = payload_class(3.14) assert round(pl.getData()-3.14, 8) == 0 - example01_class.staticSetPayload(pl._cppinstance, 41.) + example01_class.staticSetPayload(pl, 41.) assert pl.getData() == 41. example01_class.staticSetPayload(pl, 43.) assert pl.getData() == 43. From noreply at buildbot.pypy.org Fri Jul 15 13:26:30 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 15 Jul 2011 13:26:30 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, cfbolz): simplify Message-ID: <20110715112630.4BB7782931@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45614:65d04e815adb Date: 2011-07-15 13:25 +0200 http://bitbucket.org/pypy/pypy/changeset/65d04e815adb/ Log: (arigo, cfbolz): simplify diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -13,14 +13,11 @@ def get_rawobject(space, w_obj): - if not space.eq_w(w_obj, space.w_None): - from pypy.module.cppyy.interp_cppyy import W_CPPInstance - cpp_instance = space.interp_w(W_CPPInstance, w_obj) - if cpp_instance: - assert lltype.typeOf(cpp_instance.rawobject) == rffi.VOIDP - return cpp_instance.rawobject - else: - xxx + from pypy.module.cppyy.interp_cppyy import W_CPPInstance + cpp_instance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True) + if cpp_instance: + assert lltype.typeOf(cpp_instance.rawobject) == rffi.VOIDP + return cpp_instance.rawobject return lltype.nullptr(rffi.VOIDP.TO) def _direct_ptradd(ptr, offset): diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -114,6 +114,9 @@ e2.destruct() assert t.get_overload("getCount").call(None, None) == 0 + + raises(TypeError, t.get_overload("addDataToInt").call, 41, None, 4) + def test_example01memory(self): """Test memory destruction and integrity.""" From noreply at buildbot.pypy.org Fri Jul 15 13:29:43 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 13:29:43 +0200 (CEST) Subject: [pypy-commit] pypy default: Tentative: add yet another tweakable gc parameter: PYPY_GC_LOSTCARD. Message-ID: <20110715112943.A44C782931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45615:4543677d758a Date: 2011-07-14 16:31 +0200 http://bitbucket.org/pypy/pypy/changeset/4543677d758a/ Log: Tentative: add yet another tweakable gc parameter: PYPY_GC_LOSTCARD. See comments. diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,6 +34,11 @@ the GC in very small programs. Defaults to 8 times the nursery. + PYPY_GC_LOSTCARD If between two minor collections we see more than + 'PYPY_GC_LOSTCARD * length' writes to the same array, + then give up card marking and use the fast write + barrier instead. Defaults to 0.3333 for now. + PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -198,6 +203,9 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, + # See PYPY_GC_LOSTCARD. + "lost_card": 1.0 / 3.0, + # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -214,6 +222,7 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, + lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -235,6 +244,7 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 + self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -355,6 +365,10 @@ else: self.max_delta = 0.125 * env.get_total_memory() # + lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') + if lost_card > 0.0: + self.lost_card = lost_card + # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -649,7 +663,7 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only @@ -675,11 +689,15 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # (the loop is empty in C). - i = 0 - while i < cardheadersize: - llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) - i += 1 + # followed by a Signed (the loop is empty in C). + if cardheadersize > 0: + i = 0 + while i < cardheadersize - WORD: + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Char)) + i += 1 + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -903,14 +921,11 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # - size_gc_header = self.gcheaderbuilder.size_gc_header - p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: - p -= 1 - ll_assert(p.char[0] == '\x00', + i -= 1 + ll_assert(self.get_card(obj, i).char[0] == '\x00', "the card marker bits are not cleared") - i -= 1 # ---------- # Write barrier @@ -1026,9 +1041,7 @@ # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(addr_array) remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1070,9 +1083,7 @@ return addr_byte.char[0] = chr(byte | bitmask) # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(addr_array) return # # Logic for the no-cards case, put here to minimize the number @@ -1090,11 +1101,36 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card(self, obj, byteindex): + def get_card_counter_addr(self, obj): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + return llarena.getfakearenaaddress(addr_byte) - WORD + def get_card(self, obj, byteindex): + return self.get_card_counter_addr(obj) + (~byteindex) + + def set_cards_flag(self, obj): + hdr = self.header(obj) + if hdr.tid & GCFLAG_CARDS_SET == 0: + # + # first time we set a card bit in this object + self.header(obj).tid |= GCFLAG_CARDS_SET + self.objects_with_cards_set.append(obj) + # + # initialize the counter with the array length and self.lost_card + typeid = self.get_type_id(obj) + offset_to_length = self.varsize_offset_to_length(typeid) + length = (obj + offset_to_length).signed[0] + counter = int(length * self.lost_card) + self.get_card_counter_addr(obj).signed[0] = counter + else: + # decrement the counter and if zero is reached, give up on + # card marking (up to the next collection). + addr = self.get_card_counter_addr(obj) + addr.signed[0] -= 1 + if addr.signed[0] < 0: + self.objects_pointing_to_young.append(obj) + hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1167,10 +1203,7 @@ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(dest_addr) - dest_hdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(dest_addr) # ---------- # Nursery collection @@ -1264,6 +1297,7 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) + p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1602,7 +1636,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 arena -= extra_words * WORD allocsize += extra_words * WORD # From noreply at buildbot.pypy.org Fri Jul 15 13:29:44 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 13:29:44 +0200 (CEST) Subject: [pypy-commit] pypy default: Duh. Message-ID: <20110715112944.D68A282931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45616:abc993e8d795 Date: 2011-07-14 16:36 +0200 http://bitbucket.org/pypy/pypy/changeset/abc993e8d795/ Log: Duh. diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -38,6 +38,8 @@ 'PYPY_GC_LOSTCARD * length' writes to the same array, then give up card marking and use the fast write barrier instead. Defaults to 0.3333 for now. + Avoid values lower than 0.125: it is the growth + factor of list.append(). PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), @@ -1023,6 +1025,8 @@ self.prebuilt_root_objects.append(addr_array) return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1040,8 +1044,6 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) - # - self.set_cards_flag(addr_array) remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1070,6 +1072,8 @@ if not self.appears_to_be_young(newvalue): return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1082,8 +1086,6 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) - # - self.set_cards_flag(addr_array) return # # Logic for the no-cards case, put here to minimize the number From noreply at buildbot.pypy.org Fri Jul 15 13:29:46 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 13:29:46 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110715112946.1327C82931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45617:315507ad0fc2 Date: 2011-07-15 13:28 +0200 http://bitbucket.org/pypy/pypy/changeset/315507ad0fc2/ Log: merge heads diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,6 +34,13 @@ the GC in very small programs. Defaults to 8 times the nursery. + PYPY_GC_LOSTCARD If between two minor collections we see more than + 'PYPY_GC_LOSTCARD * length' writes to the same array, + then give up card marking and use the fast write + barrier instead. Defaults to 0.3333 for now. + Avoid values lower than 0.125: it is the growth + factor of list.append(). + PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -198,6 +205,9 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, + # See PYPY_GC_LOSTCARD. + "lost_card": 1.0 / 3.0, + # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -214,6 +224,7 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, + lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -235,6 +246,7 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 + self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -355,6 +367,10 @@ else: self.max_delta = 0.125 * env.get_total_memory() # + lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') + if lost_card > 0.0: + self.lost_card = lost_card + # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -649,7 +665,7 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only @@ -675,11 +691,15 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # (the loop is empty in C). - i = 0 - while i < cardheadersize: - llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) - i += 1 + # followed by a Signed (the loop is empty in C). + if cardheadersize > 0: + i = 0 + while i < cardheadersize - WORD: + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Char)) + i += 1 + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -903,14 +923,11 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # - size_gc_header = self.gcheaderbuilder.size_gc_header - p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: - p -= 1 - ll_assert(p.char[0] == '\x00', + i -= 1 + ll_assert(self.get_card(obj, i).char[0] == '\x00', "the card marker bits are not cleared") - i -= 1 # ---------- # Write barrier @@ -1008,6 +1025,8 @@ self.prebuilt_root_objects.append(addr_array) return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1025,10 +1044,6 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1057,6 +1072,8 @@ if not self.appears_to_be_young(newvalue): return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1069,10 +1086,6 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1090,11 +1103,36 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card(self, obj, byteindex): + def get_card_counter_addr(self, obj): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + return llarena.getfakearenaaddress(addr_byte) - WORD + def get_card(self, obj, byteindex): + return self.get_card_counter_addr(obj) + (~byteindex) + + def set_cards_flag(self, obj): + hdr = self.header(obj) + if hdr.tid & GCFLAG_CARDS_SET == 0: + # + # first time we set a card bit in this object + self.header(obj).tid |= GCFLAG_CARDS_SET + self.objects_with_cards_set.append(obj) + # + # initialize the counter with the array length and self.lost_card + typeid = self.get_type_id(obj) + offset_to_length = self.varsize_offset_to_length(typeid) + length = (obj + offset_to_length).signed[0] + counter = int(length * self.lost_card) + self.get_card_counter_addr(obj).signed[0] = counter + else: + # decrement the counter and if zero is reached, give up on + # card marking (up to the next collection). + addr = self.get_card_counter_addr(obj) + addr.signed[0] -= 1 + if addr.signed[0] < 0: + self.objects_pointing_to_young.append(obj) + hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1167,10 +1205,7 @@ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(dest_addr) - dest_hdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(dest_addr) # ---------- # Nursery collection @@ -1264,6 +1299,7 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) + p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1602,7 +1638,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 arena -= extra_words * WORD allocsize += extra_words * WORD # From noreply at buildbot.pypy.org Fri Jul 15 13:38:37 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 13:38:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Sorry, fix this test. It comes from f9a24c80bd03. Message-ID: <20110715113837.1D70182931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45618:9aebf8933ec2 Date: 2011-07-15 13:38 +0200 http://bitbucket.org/pypy/pypy/changeset/9aebf8933ec2/ Log: Sorry, fix this test. It comes from f9a24c80bd03. diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -133,6 +133,7 @@ bz2f.seek(0) assert bz2f.tell() == 0 + del bz2f # delete from this frame, which is captured in the traceback def test_open_close_del(self): from bz2 import BZ2File @@ -246,11 +247,18 @@ assert text_read == self.TEXT bz2f.close() + def test_silently_closes(self): + from bz2 import BZ2File + self.create_broken_temp_file() + BZ2File(self.temppath) + # check that no C-level malloc is left behind + def test_read_broken_file(self): from bz2 import BZ2File self.create_broken_temp_file() bz2f = BZ2File(self.temppath) raises(EOFError, bz2f.read) + del bz2f # delete from this frame, which is captured in the traceback def test_subsequent_read_broken_file(self): from bz2 import BZ2File @@ -264,6 +272,7 @@ raise Exception("should generate EOFError earlier") except EOFError: pass + del bz2f # delete from this frame, which is captured in the traceback def test_read_chunk10(self): from bz2 import BZ2File @@ -416,6 +425,7 @@ bz2f.close() bz2f = BZ2File(self.temppath, 'r') assert bz2f.read() == self.random_data + del bz2f # delete from this frame, which is captured in the traceback def test_context_manager(self): from bz2 import BZ2File From noreply at buildbot.pypy.org Fri Jul 15 13:40:00 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 13:40:00 +0200 (CEST) Subject: [pypy-commit] pypy default: Oups. test_weakref shows that this is needed. Message-ID: <20110715114000.07AFF82931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45619:d7287648ee0d Date: 2011-07-15 13:39 +0200 http://bitbucket.org/pypy/pypy/changeset/d7287648ee0d/ Log: Oups. test_weakref shows that this is needed. diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -145,11 +145,11 @@ def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - self.clear_all_weakrefs() self.enqueue_for_destruction(self.space, GeneratorIterator.descr_close, "interrupting generator of ") From noreply at buildbot.pypy.org Fri Jul 15 13:51:28 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 15 Jul 2011 13:51:28 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: (arigo, cfbolz): make some things not subclassable Message-ID: <20110715115128.E31E082931@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45620:6e1daa79ed94 Date: 2011-07-15 13:51 +0200 http://bitbucket.org/pypy/pypy/changeset/6e1daa79ed94/ Log: (arigo, cfbolz): make some things not subclassable diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -326,6 +326,7 @@ get = interp2app(W_CPPDataMember.get, unwrap_spec=['self', W_Root, W_Root]), set = interp2app(W_CPPDataMember.set, unwrap_spec=['self', W_Root, W_Root]), ) +W_CPPDataMember.typedef.acceptable_as_base_class = False class W_CPPScope(Wrappable): @@ -385,13 +386,6 @@ self.space.w_AttributeError, self.space.wrap("%s '%s' has no attribute %s" % (self.kind, self.name, name))) -W_CPPScope.typedef = TypeDef( - 'CPPScope', - get_method_names = interp2app(W_CPPScope.get_method_names, unwrap_spec=['self']), - get_overload = interp2app(W_CPPScope.get_overload, unwrap_spec=['self', str]), - get_data_member_names = interp2app(W_CPPScope.get_data_member_names, unwrap_spec=['self']), - get_data_member = interp2app(W_CPPScope.get_data_member, unwrap_spec=['self', str]), -) # For now, keep namespaces and classes separate as namespaces are extensible @@ -438,6 +432,7 @@ get_data_member = interp2app(W_CPPNamespace.get_data_member, unwrap_spec=['self', str]), is_namespace = interp2app(W_CPPNamespace.is_namespace, unwrap_spec=['self']), ) +W_CPPNamespace.typedef.acceptable_as_base_class = False class W_CPPType(W_CPPScope): @@ -490,6 +485,7 @@ get_data_member = interp2app(W_CPPType.get_data_member, unwrap_spec=['self', str]), is_namespace = interp2app(W_CPPType.is_namespace, unwrap_spec=['self']), ) +W_CPPType.typedef.acceptable_as_base_class = False class W_CPPTemplateType(Wrappable): @@ -509,6 +505,7 @@ 'CPPTemplateType', __call__ = interp2app(W_CPPTemplateType.__call__, unwrap_spec=['self', 'args_w']), ) +W_CPPTemplateType.typedef.acceptable_as_base_class = False class W_CPPInstance(Wrappable): From noreply at buildbot.pypy.org Fri Jul 15 14:20:19 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 15 Jul 2011 14:20:19 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: simplify things, clean up some of the immutable hints Message-ID: <20110715122019.9FD6D82931@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: reflex-support Changeset: r45621:69cab0f20d26 Date: 2011-07-15 14:20 +0200 http://bitbucket.org/pypy/pypy/changeset/69cab0f20d26/ Log: simplify things, clean up some of the immutable hints diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -26,7 +26,7 @@ class TypeConverter(object): - _immutable = True + _immutable_ = True libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO) name = "" @@ -80,7 +80,7 @@ class ArrayTypeConverterMixin(object): _mixin_ = True - _immutable = True + _immutable_ = True def __init__(self, space, array_size): if array_size <= 0: @@ -135,7 +135,7 @@ class VoidConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.void def __init__(self, space, name): @@ -147,7 +147,7 @@ class BoolConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.schar def _unwrap_object(self, space, w_obj): @@ -179,7 +179,7 @@ address[0] = '\x00' class CharConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.schar def _unwrap_object(self, space, w_value): @@ -215,7 +215,7 @@ address[0] = self._unwrap_object(space, w_value) class IntConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.sint def _unwrap_object(self, space, w_obj): @@ -239,7 +239,7 @@ intptr[0] = self._unwrap_object(space, w_value) class UnsignedIntConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.uint def _unwrap_object(self, space, w_obj): @@ -263,7 +263,7 @@ ulongptr[0] = self._unwrap_object(space, w_value) class LongConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.slong def _unwrap_object(self, space, w_obj): @@ -287,7 +287,7 @@ longptr[0] = self._unwrap_object(space, w_value) class UnsignedLongConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.ulong def _unwrap_object(self, space, w_obj): @@ -311,7 +311,7 @@ ulongptr[0] = self._unwrap_object(space, w_value) class ShortConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.sshort def _unwrap_object(self, space, w_obj): @@ -335,7 +335,7 @@ shortptr[0] = self._unwrap_object(space, w_value) class FloatConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.float def _unwrap_object(self, space, w_obj): @@ -360,7 +360,7 @@ floatptr[0] = self._unwrap_object(space, w_value) class DoubleConverter(TypeConverter): - _immutable = True + _immutable_ = True libffitype = libffi.types.double def _unwrap_object(self, space, w_obj): @@ -387,7 +387,7 @@ class CStringConverter(TypeConverter): - _immutable = True + _immutable_ = True def convert_argument(self, space, w_obj, address): x = rffi.cast(rffi.LONGP, address) @@ -406,70 +406,69 @@ class ShortArrayConverter(ArrayTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'h' typesize = rffi.sizeof(rffi.SHORT) class IntArrayConverter(ArrayTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'i' typesize = rffi.sizeof(rffi.INT) class UnsignedIntArrayConverter(ArrayTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'I' typesize = rffi.sizeof(rffi.UINT) class LongArrayConverter(ArrayTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'l' typesize = rffi.sizeof(rffi.LONG) class FloatArrayConverter(ArrayTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'f' typesize = rffi.sizeof(rffi.FLOAT) class DoubleArrayConverter(ArrayTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'd' typesize = rffi.sizeof(rffi.DOUBLE) class ShortPtrConverter(PtrTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'h' typesize = rffi.sizeof(rffi.SHORT) class IntPtrConverter(PtrTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'i' typesize = rffi.sizeof(rffi.INT) class UnsignedIntPtrConverter(PtrTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'I' typesize = rffi.sizeof(rffi.UINT) class LongPtrConverter(PtrTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'l' typesize = rffi.sizeof(rffi.LONG) class FloatPtrConverter(PtrTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'f' typesize = rffi.sizeof(rffi.FLOAT) class DoublePtrConverter(PtrTypeConverterMixin, TypeConverter): - _immutable_=True + _immutable_ = True typecode = 'd' typesize = rffi.sizeof(rffi.DOUBLE) class InstancePtrConverter(TypeConverter): _immutable_ = True - _immutable_fields_ = ["cpptype"] def __init__(self, space, cpptype, name): self.cpptype = cpptype diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -68,7 +68,7 @@ class W_CPPLibrary(Wrappable): - _immutable_ = True + _immutable_fields_ = ["cdll"] def __init__(self, space, cdll): self.cdll = cdll @@ -77,6 +77,7 @@ W_CPPLibrary.typedef = TypeDef( 'CPPLibrary', ) +W_CPPLibrary.typedef.acceptable_as_base_class = True @jit.elidable_promote() def get_methptr_getter(handle, method_index): @@ -106,6 +107,8 @@ if self.executor is None: raise OperationError(self.space.w_TypeError, self.space.wrap("return type not handled")) + if len(self.arg_types) < len(args_w) or len(args_w) < self.args_required: + raise OperationError(self.space.w_TypeError, self.space.wrap("wrong number of args")) if self.methgetter and cppthis: # only for methods try: @@ -122,9 +125,6 @@ @jit.unroll_safe def do_fast_call(self, cppthis, w_type, args_w): space = self.space - # XXX factor out - if len(self.arg_types) < len(args_w) or len(args_w) < self.args_required: - raise OperationError(space.w_TypeError, space.wrap("wrong number of args")) if self.arg_converters is None: self._build_converters() jit.promote(self) @@ -167,8 +167,6 @@ def prepare_arguments(self, args_w): jit.promote(self) space = self.space - if len(self.arg_types) < len(args_w) or len(args_w) < self.args_required: - raise OperationError(space.w_TypeError, space.wrap("wrong number of args")) if self.arg_converters is None: self._build_converters() args = capi.c_allocate_function_args(len(args_w)) @@ -209,23 +207,9 @@ class CPPFunction(CPPMethod): _immutable_ = True - def call(self, cppthis, w_type, args_w): - assert lltype.typeOf(cppthis) == rffi.VOIDP - if self.executor is None: - raise OperationError(self.space.w_TypeError, - self.space.wrap("return type not handled")) - - assert not cppthis - args = self.prepare_arguments(args_w) - try: - return self.executor.execute(self.space, w_type, self, NULL_VOIDP, - len(args_w), args) - finally: - self.free_arguments(args, len(args_w)) - class CPPConstructor(CPPMethod): - _immutable_=True + _immutable_ = True def call(self, cppthis, w_type, args_w): newthis = capi.c_allocate(self.cpptype.handle) @@ -241,7 +225,6 @@ class W_CPPOverload(Wrappable): - _immutable_ = True _immutable_fields_ = ["func_name", "functions[*]"] def __init__(self, space, func_name, functions): @@ -297,8 +280,7 @@ class W_CPPDataMember(Wrappable): - _immutable_=True - _immutable_fields_ = ["converter", "offset"] + _immutable_fields_ = ["converter", "offset", "_is_static"] def __init__(self, space, type_name, offset, is_static): self.space = space From noreply at buildbot.pypy.org Fri Jul 15 15:11:09 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 15 Jul 2011 15:11:09 +0200 (CEST) Subject: [pypy-commit] pypy default: update this page wrt the new ctypes and _ffi performances. It still contains XXXs though Message-ID: <20110715131109.3325482931@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45622:87c5f89a4e78 Date: 2011-07-15 15:11 +0200 http://bitbucket.org/pypy/pypy/changeset/87c5f89a4e78/ Log: update this page wrt the new ctypes and _ffi performances. It still contains XXXs though diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -19,12 +19,12 @@ section * Write them in pure python and use direct libffi low-level bindings, See - \_rawffi_ module description. + \_ffi_ module description. * Write them in RPython as mixedmodule_, using *rffi* as bindings. .. _ctypes: #CTypes -.. _\_rawffi: #LibFFI +.. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules CTypes @@ -42,41 +42,50 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. +ctypes call are optimized by the JIT and the resulting machine code contains a +direct call to the target C function. However, due to the very dynamic nature +of ctypes, some overhead over a bare C call is still present, in particular to +check/convert the types of the parameters. Moreover, even if most calls are +optimized, some cannot and thus need to follow the slow path, not optimized by +the JIT. + .. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure +.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html Pros ---- -Stable, CPython-compatible API +Stable, CPython-compatible API. Most calls are fast, optimized by JIT. Cons ---- -Only pure-python code (slow), problems with platform-dependency (although -we partially solve those). PyPy implementation is now very slow. +Problems with platform-dependency (although we partially solve +those). Although the JIT optimizes ctypes calls, some overhead is still +present. The slow-path is very slow. -_`CPython ctypes`: http://python.net/crew/theller/ctypes/ LibFFI ====== Mostly in order to be able to write a ctypes module, we developed a very -low-level libffi bindings. (libffi is a C-level library for dynamic calling, +low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling, which is used by CPython ctypes). This library provides stable and usable API, although it's API is a very low-level one. It does not contain any -magic. +magic. It is also optimized by the JIT, but has much less overhead than ctypes. Pros ---- -Works. Combines disadvantages of using ctypes with disadvantages of -using mixed modules. Probably more suitable for a delicate code -where ctypes magic goes in a way. +It Works. Probably more suitable for a delicate code where ctypes magic goes +in a way. All calls are optimized by the JIT, there is no slow path as in +ctypes. Cons ---- -Slow. CPython-incompatible API, very rough and low-level +It combines disadvantages of using ctypes with disadvantages of using mixed +modules. CPython-incompatible API, very rough and low-level. Mixed Modules ============= @@ -87,15 +96,15 @@ * a mixed module needs to be written in RPython, which is far more complicated than Python (XXX link) -* due to lack of separate compilation (as of April 2008), each +* due to lack of separate compilation (as of July 2011), each compilation-check requires to recompile whole PyPy python interpreter, which takes 0.5-1h. We plan to solve this at some point in near future. * although rpython is a garbage-collected language, the border between C and RPython needs to be managed by hand (each object that goes into the - C level must be explicitly freed) XXX we try to solve this + C level must be explicitly freed). -Some document is available `here`_ +Some documentation is available `here`_ .. _`here`: rffi.html From noreply at buildbot.pypy.org Fri Jul 15 15:34:31 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 15 Jul 2011 15:34:31 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: fix for const functions and hack around ellipses Message-ID: <20110715133431.D3ED482931@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45623:4ff11a2924b7 Date: 2011-07-15 06:29 -0700 http://bitbucket.org/pypy/pypy/changeset/4ff11a2924b7/ Log: fix for const functions and hack around ellipses diff --git a/pypy/module/cppyy/genreflex-methptrgetter.patch b/pypy/module/cppyy/genreflex-methptrgetter.patch --- a/pypy/module/cppyy/genreflex-methptrgetter.patch +++ b/pypy/module/cppyy/genreflex-methptrgetter.patch @@ -1,6 +1,6 @@ Index: cint/reflex/python/genreflex/gendict.py =================================================================== ---- cint/reflex/python/genreflex/gendict.py (revision 34339) +--- cint/reflex/python/genreflex/gendict.py (revision 40173) +++ cint/reflex/python/genreflex/gendict.py (working copy) @@ -52,6 +52,7 @@ self.typedefs_for_usr = [] @@ -10,7 +10,7 @@ # The next is to avoid a known problem with gccxml that it generates a # references to id equal '_0' which is not defined anywhere self.xref['_0'] = {'elem':'Unknown', 'attrs':{'id':'_0','name':''}, 'subelems':[]} -@@ -1939,8 +1940,15 @@ +@@ -1956,8 +1957,15 @@ else : params = '0' s = ' .AddFunctionMember(%s, Reflex::Literal("%s"), %s%s, 0, %s, %s)' % (self.genTypeID(id), name, type, id, params, mod) s += self.genCommentProperty(attrs) @@ -26,7 +26,7 @@ def genMCODef(self, type, name, attrs, args): id = attrs['id'] cl = self.genTypeName(attrs['context'],colon=True) -@@ -2007,8 +2015,36 @@ +@@ -2024,8 +2032,44 @@ if returns == 'void' : body += ' }\n' else : body += ' }\n' body += '}\n' @@ -48,15 +48,23 @@ + cl = self.genTypeName(attrs['context'],colon=True) + rettype = self.genTypeName(attrs['returns'],enum=True, const=True, colon=True) + arg_type_list = [self.genTypeName(arg['type'], colon=True) for arg in args] ++ constness = attrs.get('const', 0) and 'const' or '' + lines = [] + a = lines.append + a('static void* %s(void* o)' % (funcname,)) + a('{') -+ # declare a variable "meth" which is a member pointer -+ a(' %s (%s::*meth)(%s);' % (rettype, cl, ', '.join(arg_type_list))) -+ a(' meth = &%s::%s;' % (cl, name)) -+ a(' %s* obj = (%s*)o;' % (cl, cl)) -+ a(' return (void*)(obj->*meth);') ++ if name == 'EmitVA': ++ # TODO: this is for ROOT TQObject, the problem being that ellipses is not ++ # exposed in the arguments and that makes the generated code fail if the named ++ # method is overloaded as is with TQObject::EmitVA ++ a(' return (void*)0;') ++ else: ++ # declare a variable "meth" which is a member pointer ++ a(' %s (%s::*meth)(%s)%s;' % (rettype, cl, ', '.join(arg_type_list), constness)) ++ a(' meth = (%s (%s::*)(%s)%s)&%s::%s;' % \ ++ (rettype, cl, ', '.join(arg_type_list), constness, cl, name)) ++ a(' %s* obj = (%s*)o;' % (cl, cl)) ++ a(' return (void*)(obj->*meth);') + a('}') + return '\n'.join(lines) + @@ -66,7 +74,7 @@ for a in args : Index: cint/reflex/python/genreflex/genreflex.py =================================================================== ---- cint/reflex/python/genreflex/genreflex.py (revision 34339) +--- cint/reflex/python/genreflex/genreflex.py (revision 40173) +++ cint/reflex/python/genreflex/genreflex.py (working copy) @@ -108,6 +108,10 @@ Print extra debug information while processing. Keep intermediate files\n From noreply at buildbot.pypy.org Fri Jul 15 15:34:33 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 15 Jul 2011 15:34:33 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: start of new benchmarks Message-ID: <20110715133433.112F082931@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45624:40bfcf443937 Date: 2011-07-15 06:34 -0700 http://bitbucket.org/pypy/pypy/changeset/40bfcf443937/ Log: start of new benchmarks diff --git a/pypy/module/cppyy/bench/Makefile b/pypy/module/cppyy/bench/Makefile new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/bench/Makefile @@ -0,0 +1,29 @@ +all: bench02Dict_reflex.so + +ROOTSYS := ${ROOTSYS} + +ifeq ($(ROOTSYS),) + genreflex=genreflex + cppflags= +else + genreflex=$(ROOTSYS)/bin/genreflex + cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib +endif + +PLATFORM := $(shell uname -s) +ifeq ($(PLATFORM),Darwin) + cppflags+=-dynamiclib -single_module -arch x86_64 +endif + +ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),) + genreflexflags= + cppflags2=-O3 +else + genreflexflags=--with-methptrgetter + cppflags2=-Wno-pmf-conversions -O3 +endif + + +bench02Dict_reflex.so: bench02.h bench02.xml + $(genreflex) bench02.h $(genreflexflags) --selection=bench02.xml -I$(ROOTSYS)/include + g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -lReflex `root-config --libs` $(cppflags) $(cppflags2) diff --git a/pypy/module/cppyy/bench/bench02.cxx b/pypy/module/cppyy/bench/bench02.cxx new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/bench/bench02.cxx @@ -0,0 +1,20 @@ +#include "bench02.h" +#include "TROOT.h" +#include "TApplication.h" +#include "TDirectory.h" + +#include + +CloserHack::CloserHack() { + std::cout << "gROOT is: " << gROOT << std::endl; + std::cout << "gApplication is: " << gApplication << std::endl; +} + +CloserHack::~CloserHack() { + std::cout << "closing file ... " << std::endl; + if (gDirectory && gDirectory != gROOT) { + gDirectory->Write(); + gDirectory->Close(); + } +} + diff --git a/pypy/module/cppyy/bench/bench02.h b/pypy/module/cppyy/bench/bench02.h new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/bench/bench02.h @@ -0,0 +1,23 @@ +#include "TCanvas.h" +#include "TFile.h" +#include "TProfile.h" +#include "TNtuple.h" +#include "TH1F.h" +#include "TH2F.h" + +#include "TROOT.h" +#include "TApplication.h" + + +class CloserHack { +public: + CloserHack(); + ~CloserHack(); +}; + +/* +gROOT = cppyy.gbl.gROOT +gBenchmark = cppyy.gbl.gBenchmark +gRandom = cppyy.gbl.gRandom +gSystem = cppyy.gbl.gSystem +*/ diff --git a/pypy/module/cppyy/bench/bench02.xml b/pypy/module/cppyy/bench/bench02.xml new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/bench/bench02.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + --> + + + + + + + + + + + + + diff --git a/pypy/module/cppyy/bench/hsimple.C b/pypy/module/cppyy/bench/hsimple.C new file mode 100755 --- /dev/null +++ b/pypy/module/cppyy/bench/hsimple.C @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TFile *hsimple(Int_t get=0) +{ +// This program creates : +// - a one dimensional histogram +// - a two dimensional histogram +// - a profile histogram +// - a memory-resident ntuple +// +// These objects are filled with some random numbers and saved on a file. +// If get=1 the macro returns a pointer to the TFile of "hsimple.root" +// if this file exists, otherwise it is created. +// The file "hsimple.root" is created in $ROOTSYS/tutorials if the caller has +// write access to this directory, otherwise the file is created in $PWD + + TString filename = "hsimple.root"; +/* + TString dir = gSystem->UnixPathName(gInterpreter->GetCurrentMacroName()); + dir.ReplaceAll("hsimple.C",""); + dir.ReplaceAll("/./","/"); +*/ + TFile *hfile = 0; +/* + if (get) { + // if the argument get =1 return the file "hsimple.root" + // if the file does not exist, it is created + TString fullPath = dir+"hsimple.root"; + if (!gSystem->AccessPathName(fullPath,kFileExists)) { + hfile = TFile::Open(fullPath); //in $ROOTSYS/tutorials + if (hfile) return hfile; + } + //otherwise try $PWD/hsimple.root + if (!gSystem->AccessPathName("hsimple.root",kFileExists)) { + hfile = TFile::Open("hsimple.root"); //in current dir + if (hfile) return hfile; + } + } + //no hsimple.root file found. Must generate it ! + //generate hsimple.root in $ROOTSYS/tutorials if we have write access + if (!gSystem->AccessPathName(dir,kWritePermission)) { + filename = dir+"hsimple.root"; + } else if (!gSystem->AccessPathName(".",kWritePermission)) { + //otherwise generate hsimple.root in the current directory + } else { + printf("you must run the script in a directory with write access\n"); + return 0; + } + hfile = (TFile*)gROOT->FindObject(filename); if (hfile) hfile->Close(); +*/ + hfile = new TFile(filename,"RECREATE","Demo ROOT file with histograms"); + + // Create some histograms, a profile histogram and an ntuple + TH1F *hpx = new TH1F("hpx","This is the px distribution",100,-4,4); +/* + hpx->SetFillColor(48); + TH2F *hpxpy = new TH2F("hpxpy","py vs px",40,-4,4,40,-4,4); + TProfile *hprof = new TProfile("hprof","Profile of pz versus px",100,-4,4,0,20); + TNtuple *ntuple = new TNtuple("ntuple","Demo ntuple","px:py:pz:random:i"); + + gBenchmark->Start("hsimple"); + + // Create a new canvas. + TCanvas *c1 = new TCanvas("c1","Dynamic Filling Example",200,10,700,500); + c1->SetFillColor(42); + c1->GetFrame()->SetFillColor(21); + c1->GetFrame()->SetBorderSize(6); + c1->GetFrame()->SetBorderMode(-1); + +*/ + // Fill histograms randomly + gRandom->SetSeed(); + Float_t px, py, pz; + const Int_t kUPDATE = 1000; + for (Int_t i = 0; i < 2500000; i++) { + gRandom->Rannor(px,py); + pz = px*px + py*py; + // Float_t random = gRandom->Rndm(1); + hpx->Fill(px); +/* + hpxpy->Fill(px,py); + hprof->Fill(px,pz); + ntuple->Fill(px,py,pz,random,i); + if (i && (i%kUPDATE) == 0) { + if (i == kUPDATE) hpx->Draw(); + c1->Modified(); + c1->Update(); + if (gSystem->ProcessEvents()) + break; + } +*/ + } +/* + gBenchmark->Show("hsimple"); + + // Save all objects in this file + hpx->SetFillColor(0); + hfile->Write(); + hpx->SetFillColor(48); + c1->Modified(); +*/ + return hfile; + +// Note that the file is automatically close when application terminates +// or when the file destructor is called. +} diff --git a/pypy/module/cppyy/bench/hsimple.py b/pypy/module/cppyy/bench/hsimple.py new file mode 100755 --- /dev/null +++ b/pypy/module/cppyy/bench/hsimple.py @@ -0,0 +1,106 @@ +#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* +#*-* +#*-* This program creates : +#*-* - a one dimensional histogram +#*-* - a two dimensional histogram +#*-* - a profile histogram +#*-* - a memory-resident ntuple +#*-* +#*-* These objects are filled with some random numbers and saved on a file. +#*-* +#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* + +try: + import cppyy, random + cppyy.load_lib('bench02Dict_reflex.so') + + TCanvas = cppyy.gbl.TCanvas + TFile = cppyy.gbl.TFile + TProfile = cppyy.gbl.TProfile + TNtuple = cppyy.gbl.TNtuple + TH1F = cppyy.gbl.TH1F + TH2F = cppyy.gbl.TH2F +except ImportError: + from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F + import random + +#gROOT = cppyy.gbl.gROOT +#gBenchmark = cppyy.gbl.gBenchmark +#gRandom = cppyy.gbl.gRandom +#gSystem = cppyy.gbl.gSystem + +#gROOT.Reset() + +# Create a new canvas, and customize it. +#c1 = TCanvas( 'c1', 'Dynamic Filling Example', 200, 10, 700, 500 ) +#c1.SetFillColor( 42 ) +#c1.GetFrame().SetFillColor( 21 ) +#c1.GetFrame().SetBorderSize( 6 ) +#c1.GetFrame().SetBorderMode( -1 ) + +# Create a new ROOT binary machine independent file. +# Note that this file may contain any kind of ROOT objects, histograms, +# pictures, graphics objects, detector geometries, tracks, events, etc.. +# This file is now becoming the current directory. + +#hfile = gROOT.FindObject( 'hsimple.root' ) +#if hfile: +# hfile.Close() +hfile = TFile( 'hsimple.root', 'RECREATE', 'Demo ROOT file with histograms' ) + +# Create some histograms, a profile histogram and an ntuple +hpx = TH1F( 'hpx', 'This is the px distribution', 100, -4, 4 ) +#hpxpy = TH2F( 'hpxpy', 'py vs px', 40, -4, 4, 40, -4, 4 ) +#hprof = TProfile( 'hprof', 'Profile of pz versus px', 100, -4, 4, 0, 20 ) +#ntuple = TNtuple( 'ntuple', 'Demo ntuple', 'px:py:pz:random:i' ) + +# Set canvas/frame attributes. +#hpx.SetFillColor( 48 ) + +#gBenchmark.Start( 'hsimple' ) + +# Initialize random number generator. +#gRandom.SetSeed() +#rannor, rndm = gRandom.Rannor, gRandom.Rndm + +# Fill histograms randomly. +#px, py = Double(), Double() +kUPDATE = 1000 +for i in xrange( 2500000 ): + # Generate random values. + px, py = random.gauss(0, 1), random.gauss(0, 1) +# pt = (px*px + py*py)**0.5 + pt = (px*px + py*py) +# random = rndm(1) + + # Fill histograms. + hpx.Fill( pt ) +# hpxpyFill( px, py ) +# hprofFill( px, pz ) +# ntupleFill( px, py, pz, random, i ) + + # Update display every kUPDATE events. +# if i and i%kUPDATE == 0: +# if i == kUPDATE: +# hpx.Draw() + +# c1.Modified() +# c1.Update() + +# if gSystem.ProcessEvents(): # allow user interrupt +# break + +#gBenchmark.Show( 'hsimple' ) + +# Save all objects in this file. +#hpx.SetFillColor( 0 ) +#hfile.Write() +hfile.Close() +#hpx.SetFillColor( 48 ) +#c1.Modified() +#c1.Update() +#import gc +#gc.collect() + +# Note that the file is automatically closed when application terminates +# or when the file destructor is called. From noreply at buildbot.pypy.org Fri Jul 15 15:52:24 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 15 Jul 2011 15:52:24 +0200 (CEST) Subject: [pypy-commit] benchmarks default: update twisted-trunk to r32338 Message-ID: <20110715135224.2D2E482931@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r121:76cec4fd41d9 Date: 2011-07-15 15:49 +0200 http://bitbucket.org/pypy/benchmarks/changeset/76cec4fd41d9/ Log: update twisted-trunk to r32338 diff --git a/lib/twisted-trunk/LICENSE b/lib/twisted-trunk/LICENSE --- a/lib/twisted-trunk/LICENSE +++ b/lib/twisted-trunk/LICENSE @@ -12,7 +12,7 @@ Donovan Preston Eric Mangold Eyal Lotem -Itamar Shtull-Trauring +Itamar Turner-Trauring James Knight Jason A. Mobarak Jean-Paul Calderone diff --git a/lib/twisted-trunk/bin/conch/cftp b/lib/twisted-trunk/bin/conch/cftp --- a/lib/twisted-trunk/bin/conch/cftp +++ b/lib/twisted-trunk/bin/conch/cftp @@ -1,20 +1,15 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.conch.scripts.cftp import run run() diff --git a/lib/twisted-trunk/bin/conch/ckeygen b/lib/twisted-trunk/bin/conch/ckeygen --- a/lib/twisted-trunk/bin/conch/ckeygen +++ b/lib/twisted-trunk/bin/conch/ckeygen @@ -1,20 +1,15 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.conch.scripts.ckeygen import run run() diff --git a/lib/twisted-trunk/bin/conch/conch b/lib/twisted-trunk/bin/conch/conch --- a/lib/twisted-trunk/bin/conch/conch +++ b/lib/twisted-trunk/bin/conch/conch @@ -1,20 +1,15 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.conch.scripts.conch import run run() diff --git a/lib/twisted-trunk/bin/conch/tkconch b/lib/twisted-trunk/bin/conch/tkconch --- a/lib/twisted-trunk/bin/conch/tkconch +++ b/lib/twisted-trunk/bin/conch/tkconch @@ -1,20 +1,15 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.conch.scripts.tkconch import run run() diff --git a/lib/twisted-trunk/bin/lore/lore b/lib/twisted-trunk/bin/lore/lore --- a/lib/twisted-trunk/bin/lore/lore +++ b/lib/twisted-trunk/bin/lore/lore @@ -1,20 +1,15 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.lore.scripts.lore import run run() diff --git a/lib/twisted-trunk/bin/mail/mailmail b/lib/twisted-trunk/bin/mail/mailmail --- a/lib/twisted-trunk/bin/mail/mailmail +++ b/lib/twisted-trunk/bin/mail/mailmail @@ -1,24 +1,19 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - """ This script attempts to send some email. """ -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.mail.scripts import mailmail mailmail.run() diff --git a/lib/twisted-trunk/bin/manhole b/lib/twisted-trunk/bin/manhole --- a/lib/twisted-trunk/bin/manhole +++ b/lib/twisted-trunk/bin/manhole @@ -1,21 +1,16 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - """ This script runs GtkManhole, a client for Twisted.Manhole """ +import sys -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os -if os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') != -1: - sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))) -### end of preamble - +try: + import _preamble +except ImportError: + sys.exc_clear() from twisted.scripts import manhole manhole.run() diff --git a/lib/twisted-trunk/bin/mktap b/lib/twisted-trunk/bin/mktap --- a/lib/twisted-trunk/bin/mktap +++ b/lib/twisted-trunk/bin/mktap @@ -1,17 +1,12 @@ #!/usr/bin/env python # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +import sys - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os -if os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') != -1: - sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))) -if not hasattr(os, "getuid") or os.getuid() != 0: - sys.path.insert(0, os.getcwd()) -### end of preamble +try: + import _preamble +except ImportError: + sys.exc_clear() from twisted.scripts.mktap import run run() diff --git a/lib/twisted-trunk/bin/pyhtmlizer b/lib/twisted-trunk/bin/pyhtmlizer --- a/lib/twisted-trunk/bin/pyhtmlizer +++ b/lib/twisted-trunk/bin/pyhtmlizer @@ -1,17 +1,12 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +import sys - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os -if os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') != -1: - sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))) -sys.path.insert(0, os.curdir) -### end of preamble +try: + import _preamble +except ImportError: + sys.exc_clear() from twisted.scripts.htmlizer import run run() diff --git a/lib/twisted-trunk/bin/tap2deb b/lib/twisted-trunk/bin/tap2deb --- a/lib/twisted-trunk/bin/tap2deb +++ b/lib/twisted-trunk/bin/tap2deb @@ -1,20 +1,16 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - """ tap2deb """ +import sys -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os -if os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') != -1: - sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))) -### end of preamble +try: + import _preamble +except ImportError: + sys.exc_clear() from twisted.scripts import tap2deb tap2deb.run() diff --git a/lib/twisted-trunk/bin/tap2rpm b/lib/twisted-trunk/bin/tap2rpm --- a/lib/twisted-trunk/bin/tap2rpm +++ b/lib/twisted-trunk/bin/tap2rpm @@ -1,5 +1,4 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. @@ -9,14 +8,12 @@ """ tap2rpm """ +import sys -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os -if os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') != -1: - sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))) -### end of preamble +try: + import _preamble +except ImportError: + sys.exc_clear() from twisted.scripts import tap2rpm tap2rpm.run() diff --git a/lib/twisted-trunk/bin/tapconvert b/lib/twisted-trunk/bin/tapconvert --- a/lib/twisted-trunk/bin/tapconvert +++ b/lib/twisted-trunk/bin/tapconvert @@ -1,18 +1,12 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +import sys - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os -if os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') != -1: - sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))) -if not hasattr(os, "getuid") or os.getuid() != 0: - sys.path.insert(0, os.getcwd()) -### end of preamble +try: + import _preamble +except ImportError: + sys.exc_clear() from twisted.scripts.tapconvert import run run() diff --git a/lib/twisted-trunk/bin/trial b/lib/twisted-trunk/bin/trial --- a/lib/twisted-trunk/bin/trial +++ b/lib/twisted-trunk/bin/trial @@ -1,22 +1,18 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +import os, sys - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os -if os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') != -1: - sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))) -if hasattr(os, "getuid") and os.getuid() != 0: - sys.path.insert(0, os.curdir) -### end of preamble +try: + import _preamble +except ImportError: + sys.exc_clear() # begin chdir armor sys.path[:] = map(os.path.abspath, sys.path) # end chdir armor +sys.path.insert(0, os.path.abspath(os.getcwd())) + from twisted.scripts.trial import run run() diff --git a/lib/twisted-trunk/bin/twistd b/lib/twisted-trunk/bin/twistd --- a/lib/twisted-trunk/bin/twistd +++ b/lib/twisted-trunk/bin/twistd @@ -1,19 +1,14 @@ #!/usr/bin/env python - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +import os, sys +try: + import _preamble +except ImportError: + sys.exc_clear() -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os -if os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') != -1: - sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))) -if hasattr(os, "getuid") and os.getuid() != 0: - sys.path.insert(0, os.path.abspath(os.getcwd())) -### end of preamble - +sys.path.insert(0, os.path.abspath(os.getcwd())) from twisted.scripts.twistd import run run() diff --git a/lib/twisted-trunk/doc/core/development/policy/coding-standard.xhtml b/lib/twisted-trunk/doc/core/development/policy/coding-standard.xhtml --- a/lib/twisted-trunk/doc/core/development/policy/coding-standard.xhtml +++ b/lib/twisted-trunk/doc/core/development/policy/coding-standard.xhtml @@ -47,9 +47,16 @@

Test Suite

The Twisted test suite is spread across many subpackages of the - twisted package. Many tests are in + twisted package. Many older tests are in twisted.test. Others can be found at places such as - twisted.web.test or twisted.internet.test. + twisted.web.test (for twisted.web tests) + or twisted.internet.test (for twisted.internet + tests). The latter arrangement, twisted.somepackage.test, + is preferred for new tests except when a test module already exists in + twisted.test. +

+ +

Parts of the Twisted test suite may serve as good examples of how to write tests for Twisted or for Twisted-based libraries (newer parts of the test suite are generally better examples than older parts - check @@ -106,17 +113,15 @@

Copyright Header

Whenever a new file is added to the repository, add the following - license header at the top of the file, including the year the file was - added. For example:

+ license header at the top of the file:

-# Copyright (c) 2009 Twisted Matrix Laboratories.
+# Copyright (c) Twisted Matrix Laboratories.
 # See LICENSE for details.
 
-

When you update existing files, make sure the year in the copyright - header is up to date as well. You should add a new copyright header when - it's completely missing in the file that is being edited.

+

When you update existing files, if there is no copyright header, add + one.

Whitespace

@@ -272,7 +277,7 @@

Docstrings should be written in epytext format; more documentation is available in the - Epytext Markup Language documentation.

Additionally, to accommodate emacs users:

@@ -359,17 +364,25 @@ distutils will rewrite the shebang line upon installation so this policy only covers the source files in version control.

-
  • Add the Twisted running-from-SVN header: +
  • For core scripts, add this Twisted running-from-SVN header:
    -### Twisted Preamble
    -# This makes sure that users don't have to set up their environment
    -# specially in order to run these programs from bin/.
    +import sys
    +try:
    +    import _preamble
    +except ImportError:
    +    sys.clear_exc()
    +
    + + Or for sub-project scripts, add a modified version which also adjusts sys.path: +
     import sys, os
    -if os.path.abspath(sys.argv[0]).find(os.sep+'Twisted') != -1:
    -    sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir)))
    -if not hasattr(os, "getuid") or os.getuid() != 0:
    -    sys.path.insert(0, os.getcwd())
    -### end of preamble
    +extra = os.path.dirname(os.path.dirname(sys.argv[0]))
    +sys.path.insert(0, extra)
    +try:
    +    import _preamble
    +except ImportError:
    +    sys.clear_exc()
    +sys.path.remove(extra)
     
  • And end with: diff --git a/lib/twisted-trunk/doc/core/development/policy/doc-standard.xhtml b/lib/twisted-trunk/doc/core/development/policy/doc-standard.xhtml --- a/lib/twisted-trunk/doc/core/development/policy/doc-standard.xhtml +++ b/lib/twisted-trunk/doc/core/development/policy/doc-standard.xhtml @@ -125,18 +125,11 @@
             <p>
    -    To add a <code class="API">twisted.web.widgets.Widget</code>
    +    To add a <code class="API">twisted.web.static.File</code>
         instance to a <code class="API"
    -    base="twisted.web.widgets">Gadget</code> instance, do 
    -    <code class="python">myGadget.putWidget("widgetPath",
    -    MyWidget())</code>.  
    -        </p>
    -    
    -        <p> 
    -    (implementation note: the widgets are stored in the <code
    -    class="python">gadgetInstance.widgets</code> attribute,
    -    which is a
    -    list.)
    +    base="twisted.web.resource">Resource</code> instance, do 
    +    <code class="python">myResource.putChild("resourcePath",
    +    File("/tmp"))</code>.  
             </p>
         
     
    @@ -145,17 +138,10 @@

    Rendered result:

    - To add a twisted.web.widgets.Widget - instance to a Gadget + To add a twisted.web.static.File + instance to a Resource instance, do - myGadget.putWidget("widgetPath", MyWidget()). -

    - -

    - (implementation note: the widgets are stored in the gadgetInstance.widgets attribute, - which is a - list.) + myResource.putChild("resourcePath", File("/tmp")).

    diff --git a/lib/twisted-trunk/doc/core/development/policy/test-standard.xhtml b/lib/twisted-trunk/doc/core/development/policy/test-standard.xhtml --- a/lib/twisted-trunk/doc/core/development/policy/test-standard.xhtml +++ b/lib/twisted-trunk/doc/core/development/policy/test-standard.xhtml @@ -106,10 +106,10 @@

    PyUnit provides a large number of assertion methods to be used when writing tests. Many of these are redundant. For consistency, Twisted unit tests should use the assert forms rather than the - fail forms. Also, use assertEquals, - assertNotEquals, and assertAlmostEquals rather - than assertEqual, assertNotEqual, and - assertAlmostEqual. assertTrue is also + fail forms. Also, use assertEqual, + assertNotEqual, and assertAlmostEqual rather + than assertEquals, assertNotEquals, and + assertAlmostEquals. assertTrue is also preferred over assert_. You may notice this convention is not followed everywhere in the Twisted codebase. If you are changing some test code and notice the wrong method being used in nearby code, diff --git a/lib/twisted-trunk/doc/core/howto/basics.xhtml b/lib/twisted-trunk/doc/core/howto/basics.xhtml --- a/lib/twisted-trunk/doc/core/howto/basics.xhtml +++ b/lib/twisted-trunk/doc/core/howto/basics.xhtml @@ -83,7 +83,8 @@ and tap2deb do not package your entire application and dependent code, just the Twisted Application file. You will need to find some other way to package your Python code, such -as distutils' bdist_rpm command. +as distutils' +bdist_rpm command.

  • diff --git a/lib/twisted-trunk/doc/core/howto/choosing-reactor.xhtml b/lib/twisted-trunk/doc/core/howto/choosing-reactor.xhtml --- a/lib/twisted-trunk/doc/core/howto/choosing-reactor.xhtml +++ b/lib/twisted-trunk/doc/core/howto/choosing-reactor.xhtml @@ -68,7 +68,7 @@ select()StableYYYYYYUnix, Win32 pollStableYYYYYYUnix WaitForMultipleObjects (WFMO) for Win32ExperimentalYYYYYYWin32 - Input/Output Completion Port (IOCP) for Win32ExperimentalYYNNNYWin32 + Input/Output Completion Port (IOCP) for Win32ExperimentalYYYYYYWin32 CoreFoundationUnmaintainedYYYYYYMac OS X epollStableYYYYYYLinux 2.6 GTK+StableYYYYYYUnix, Win32 @@ -150,8 +150,7 @@

    Windows provides a fast, scalable event notification system known as IO Completion Ports, or IOCP for short. Twisted includes a reactor based - on IOCP which is nearly complete. The reactor has a handful of known - bugs and lacks SSL support. + on IOCP which is nearly complete.

    @@ -268,7 +267,7 @@
     
         

    Tkinter

    -

    The support for The support for Tkinter doesn't use a specialized reactor. Instead, there is some specialized support code:

    diff --git a/lib/twisted-trunk/doc/core/howto/cred.xhtml b/lib/twisted-trunk/doc/core/howto/cred.xhtml --- a/lib/twisted-trunk/doc/core/howto/cred.xhtml +++ b/lib/twisted-trunk/doc/core/howto/cred.xhtml @@ -34,7 +34,7 @@ such as a Protocol, stores a reference to the portal. Login consists of passing credentials and a request interface (e.g. POP3's IMailbox) to the portal. The portal passes +base="twisted.mail.pop3">IMailbox
    ) to the portal. The portal passes the credentials to the appropriate credential checker, which returns an avatar ID. The ID is passed to the realm, which returns the appropriate avatar. For a Portal that has a realm that creates mailbox objects and a credential checker @@ -379,7 +379,7 @@

    Once you have created this structure within your application, you can create the code for your cred plugin by building a factory class which -implements ICheckerFactory. +implements ICheckerFactory. These factory classes should not consist of a tremendous amount of code. Most of the real application logic should reside in the cred checker itself. (For help on building those, scroll up.) @@ -398,7 +398,7 @@ from zope.interface import implements from twisted import plugin -from twisted.cred import checkers +from twisted.cred.strcred import ICheckerFactory from myapp.cred import SpecialChecker class SpecialCheckerFactory(object): @@ -407,7 +407,7 @@ """ # The class needs to implement both of these interfaces # for the plugin system to find our factory. - implements(checkers.ICheckerFactory, plugin.IPlugin) + implements(ICheckerFactory, plugin.IPlugin) # This tells AuthOptionsMixin how to find this factory. authType = "special" diff --git a/lib/twisted-trunk/doc/core/howto/defer.xhtml b/lib/twisted-trunk/doc/core/howto/defer.xhtml --- a/lib/twisted-trunk/doc/core/howto/defer.xhtml +++ b/lib/twisted-trunk/doc/core/howto/defer.xhtml @@ -382,10 +382,10 @@

    -from twisted.internet import reactor
    +from twisted.internet import reactor, defer
     
    -def asynchronousIsValidUser(d, user):
    -    d = Deferred()
    +def asynchronousIsValidUser(user):
    +    d = defer.Deferred()
         reactor.callLater(2, d.callback, user in ["Alice", "Angus", "Agnes"])
         return d
     
    diff --git a/lib/twisted-trunk/doc/core/howto/endpoints.xhtml b/lib/twisted-trunk/doc/core/howto/endpoints.xhtml --- a/lib/twisted-trunk/doc/core/howto/endpoints.xhtml +++ b/lib/twisted-trunk/doc/core/howto/endpoints.xhtml @@ -31,8 +31,8 @@

    In Twisted 10.1, several new interfaces were introduced to describe each of these roles for stream-oriented connections: IServerStreamEndpoint and IClientStreamEndpoint. + base="twisted.internet.interfaces">IStreamServerEndpoint and IStreamClientEndpoint. The word "stream", in this case, refers to endpoints which treat a connection as a continuous stream of bytes, rather than a sequence of discrete datagrams: TCP is a "stream" protocol whereas UDP is a "datagram" @@ -70,7 +70,7 @@

    Servers and Stopping

    -

    IServerStreamEndpoint.listen +

    IStreamServerEndpoint.listen returns a Deferred that fires with an IListeningPort. Note that this deferred may errback. The most common cause of such an error @@ -99,7 +99,7 @@

    Clients and Cancelling

    -

    IClientStreamEndpoint.connect +

    IStreamClientEndpoint.connect will connect your protocol factory to a new outgoing connection attempt. It returns a Deferred which fires with the IProtocol returned from the factory's buildProtocol method.

    diff --git a/lib/twisted-trunk/doc/core/howto/glossary.xhtml b/lib/twisted-trunk/doc/core/howto/glossary.xhtml --- a/lib/twisted-trunk/doc/core/howto/glossary.xhtml +++ b/lib/twisted-trunk/doc/core/howto/glossary.xhtml @@ -220,7 +220,7 @@
    Nevow
    The successor to Woven; available from Divmod. + href="http://launchpad.net/nevow">Divmod.
    PB
    @@ -335,7 +335,7 @@ system was the main focus of Twisted Matrix Labs; Twisted, the general networking framework, grew out of Reality's need for better network functionality. Twisted Reality has been superseded by the Imaginary project. +href="http://launchpad.net/imaginary">Imaginary project.
    usage
    @@ -351,7 +351,7 @@
    Woven
    Web Object Visualization Environment. A templating system previously, but no longer, included with Twisted. Woven -has largely been superceded by +has largely been superceded by Divmod Nevow.
    diff --git a/lib/twisted-trunk/doc/core/howto/index.xhtml b/lib/twisted-trunk/doc/core/howto/index.xhtml --- a/lib/twisted-trunk/doc/core/howto/index.xhtml +++ b/lib/twisted-trunk/doc/core/howto/index.xhtml @@ -108,7 +108,7 @@
  • Using threads
  • -
  • Efficient High-Volume Streaming
  • +
  • Producers and Consumers: Efficient High-Volume Streaming
  • Choosing a reactor and GUI toolkit integration
  • diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_1.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_1.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_1.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_1.py @@ -5,19 +5,19 @@ def test_add(self): calc = Calculation() result = calc.add(3, 8) - self.assertEquals(result, 11) + self.assertEqual(result, 11) def test_subtract(self): calc = Calculation() result = calc.subtract(7, 3) - self.assertEquals(result, 4) + self.assertEqual(result, 4) def test_multiply(self): calc = Calculation() result = calc.multiply(12, 5) - self.assertEquals(result, 60) + self.assertEqual(result, 60) def test_divide(self): calc = Calculation() result = calc.divide(12, 5) - self.assertEquals(result, 2) + self.assertEqual(result, 2) diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_2.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_2.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_2.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_2.py @@ -8,22 +8,22 @@ def test_add(self): calc = Calculation() result = calc.add(3, 8) - self.assertEquals(result, 11) + self.assertEqual(result, 11) def test_subtract(self): calc = Calculation() result = calc.subtract(7, 3) - self.assertEquals(result, 4) + self.assertEqual(result, 4) def test_multiply(self): calc = Calculation() result = calc.multiply(12, 5) - self.assertEquals(result, 60) + self.assertEqual(result, 60) def test_divide(self): calc = Calculation() result = calc.divide(12, 5) - self.assertEquals(result, 2) + self.assertEqual(result, 2) diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_2b.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_2b.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_2b.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_2b.py @@ -10,7 +10,7 @@ def _test(self, operation, a, b, expected): result = operation(a, b) - self.assertEquals(result, expected) + self.assertEqual(result, expected) def test_add(self): diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_3.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_3.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_3.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_base_3.py @@ -10,7 +10,7 @@ def _test(self, operation, a, b, expected): result = operation(a, b) - self.assertEquals(result, expected) + self.assertEqual(result, expected) def _test_error(self, operation): diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_1.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_1.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_1.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_1.py @@ -13,9 +13,9 @@ def _test(self, operation, a, b, expected): d = getattr(self.proto, operation)(a, b) - self.assertEquals(self.tr.value(), '%s %d %d\r\n' % (operation, a, b)) + self.assertEqual(self.tr.value(), '%s %d %d\r\n' % (operation, a, b)) self.tr.clear() - d.addCallback(self.assertEquals, expected) + d.addCallback(self.assertEqual, expected) self.proto.dataReceived("%d\r\n" % (expected,)) return d diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_2.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_2.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_2.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_2.py @@ -18,9 +18,9 @@ def _test(self, operation, a, b, expected): d = getattr(self.proto, operation)(a, b) - self.assertEquals(self.tr.value(), '%s %d %d\r\n' % (operation, a, b)) + self.assertEqual(self.tr.value(), '%s %d %d\r\n' % (operation, a, b)) self.tr.clear() - d.addCallback(self.assertEquals, expected) + d.addCallback(self.assertEqual, expected) self.proto.dataReceived("%d\r\n" % (expected,)) return d @@ -43,6 +43,6 @@ def test_timeout(self): d = self.proto.add(9, 4) - self.assertEquals(self.tr.value(), 'add 9 4\r\n') + self.assertEqual(self.tr.value(), 'add 9 4\r\n') self.clock.advance(self.proto.timeOut) return self.assertFailure(d, ClientTimeoutError) diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_3.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_3.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_3.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_client_3.py @@ -18,9 +18,9 @@ def _test(self, operation, a, b, expected): d = getattr(self.proto, operation)(a, b) - self.assertEquals(self.tr.value(), '%s %d %d\r\n' % (operation, a, b)) + self.assertEqual(self.tr.value(), '%s %d %d\r\n' % (operation, a, b)) self.tr.clear() - d.addCallback(self.assertEquals, expected) + d.addCallback(self.assertEqual, expected) self.proto.dataReceived("%d\r\n" % (expected,)) return d @@ -43,7 +43,7 @@ def test_timeout(self): d = self.proto.add(9, 4) - self.assertEquals(self.tr.value(), 'add 9 4\r\n') + self.assertEqual(self.tr.value(), 'add 9 4\r\n') self.clock.advance(self.proto.timeOut) return self.assertFailure(d, ClientTimeoutError) @@ -55,9 +55,9 @@ self.proto.connectionLost = lost d = self.proto.add(9, 4) - self.assertEquals(self.tr.value(), 'add 9 4\r\n') + self.assertEqual(self.tr.value(), 'add 9 4\r\n') self.clock.advance(self.proto.timeOut) def check(ignore): - self.assertEquals(called, [True]) + self.assertEqual(called, [True]) return self.assertFailure(d, ClientTimeoutError).addCallback(check) diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_1.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_1.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_1.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_1.py @@ -14,7 +14,7 @@ def _test(self, operation, a, b, expected): self.proto.dataReceived('%s %d %d\r\n' % (operation, a, b)) - self.assertEquals(int(self.tr.value()), expected) + self.assertEqual(int(self.tr.value()), expected) def test_add(self): diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_2.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_2.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_2.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_2.py @@ -25,7 +25,7 @@ def cb(client): self.client = client return getattr(self.client, op)(a, b - ).addCallback(self.assertEquals, expected) + ).addCallback(self.assertEqual, expected) return creator.connectTCP('127.0.0.1', self.port.getHost().port ).addCallback(cb) diff --git a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_3.py b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_3.py --- a/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_3.py +++ b/lib/twisted-trunk/doc/core/howto/listings/trial/calculus/test/test_remote_3.py @@ -14,7 +14,7 @@ def _test(self, operation, a, b, expected): self.proto.dataReceived('%s %d %d\r\n' % (operation, a, b)) - self.assertEquals(int(self.tr.value()), expected) + self.assertEqual(int(self.tr.value()), expected) def test_add(self): @@ -35,6 +35,6 @@ def test_invalidParameters(self): self.proto.dataReceived('add foo bar\r\n') - self.assertEquals(self.tr.value(), "error\r\n") + self.assertEqual(self.tr.value(), "error\r\n") errors = self.flushLoggedErrors(TypeError) - self.assertEquals(len(errors), 1) + self.assertEqual(len(errors), 1) diff --git a/lib/twisted-trunk/doc/core/howto/listings/udp/MulticastClient.py b/lib/twisted-trunk/doc/core/howto/listings/udp/MulticastClient.py --- a/lib/twisted-trunk/doc/core/howto/listings/udp/MulticastClient.py +++ b/lib/twisted-trunk/doc/core/howto/listings/udp/MulticastClient.py @@ -1,6 +1,5 @@ from twisted.internet.protocol import DatagramProtocol from twisted.internet import reactor -from twisted.application.internet import MulticastServer class MulticastClientUDP(DatagramProtocol): @@ -8,6 +7,6 @@ print "Received:" + repr(datagram) # Send multicast on 224.0.0.1:8005, on our dynamically allocated port -reactor.listenUDP(0, MulticastClientUDP()).write('UniqueID', - ('224.0.0.1', 8005)) +port = reactor.listenUDP(0, MulticastClientUDP()) +port.write('UniqueID', ('224.0.0.1', 8005)) reactor.run() diff --git a/lib/twisted-trunk/doc/core/howto/listings/udp/MulticastServer.py b/lib/twisted-trunk/doc/core/howto/listings/udp/MulticastServer.py --- a/lib/twisted-trunk/doc/core/howto/listings/udp/MulticastServer.py +++ b/lib/twisted-trunk/doc/core/howto/listings/udp/MulticastServer.py @@ -1,6 +1,5 @@ from twisted.internet.protocol import DatagramProtocol from twisted.internet import reactor -from twisted.application.internet import MulticastServer class MulticastServerUDP(DatagramProtocol): def startProtocol(self): diff --git a/lib/twisted-trunk/doc/core/howto/logging.xhtml b/lib/twisted-trunk/doc/core/howto/logging.xhtml --- a/lib/twisted-trunk/doc/core/howto/logging.xhtml +++ b/lib/twisted-trunk/doc/core/howto/logging.xhtml @@ -54,7 +54,7 @@
    or:
    -from twisted.python.logging import DailyLogFile
    +from twisted.python.logfile import DailyLogFile
     
     log.startLogging(DailyLogFile.fromFullPath("/var/log/foo.log"))
             
    diff --git a/lib/twisted-trunk/doc/core/howto/process.xhtml b/lib/twisted-trunk/doc/core/howto/process.xhtml --- a/lib/twisted-trunk/doc/core/howto/process.xhtml +++ b/lib/twisted-trunk/doc/core/howto/process.xhtml @@ -97,8 +97,9 @@ env to the child.

    reactor.spawnProcess returns an instance that -implements -IProcessTransport.

    +implements +IProcessTransport. +

    Writing a ProcessProtocol

    diff --git a/lib/twisted-trunk/doc/core/howto/quotes.xhtml b/lib/twisted-trunk/doc/core/howto/quotes.xhtml --- a/lib/twisted-trunk/doc/core/howto/quotes.xhtml +++ b/lib/twisted-trunk/doc/core/howto/quotes.xhtml @@ -31,9 +31,9 @@
  • __init__.py (this file marks it as a package, see this section of the Python tutorial for more on packages);
  • -
  • quoters.py;
  • -
  • quoteproto.py;
  • + >this section of the Python tutorial for more on packages) +
  • quoters.py
  • +
  • quoteproto.py
  • Add the TwistedQuotes directory's parent to your Python diff --git a/lib/twisted-trunk/doc/core/howto/rdbms.xhtml b/lib/twisted-trunk/doc/core/howto/rdbms.xhtml --- a/lib/twisted-trunk/doc/core/howto/rdbms.xhtml +++ b/lib/twisted-trunk/doc/core/howto/rdbms.xhtml @@ -56,7 +56,7 @@ framework such as Twisted. For this reason, twisted provides twisted.enterprise.adbapi, an asynchronous wrapper for any + href="http://www.python.org/dev/peps/pep-0249/"> DB-API 2.0-compliant module.

    enterprise.adbapi will do diff --git a/lib/twisted-trunk/doc/core/howto/testing.xhtml b/lib/twisted-trunk/doc/core/howto/testing.xhtml --- a/lib/twisted-trunk/doc/core/howto/testing.xhtml +++ b/lib/twisted-trunk/doc/core/howto/testing.xhtml @@ -70,9 +70,9 @@

    If your test leaves event sources in the reactor, Trial will fail the test. The tearDown method is a good place to put cleanup code: it is -always run regardless of whether your test passes or fails (like a bare -except clause in a try-except construct). Exceptions in tearDown - are flagged as errors and flunk the test. +always run regardless of whether your test passes or fails (like a finally +clause in a try-except-finally construct). Exceptions in tearDown +are flagged as errors and flunk the test. TestCase.addCleanup is another useful tool for cleaning up. With it, you can register callables to clean up resources as the test allocates them. Generally, code should be @@ -154,8 +154,8 @@

    Warnings emitted in tests which are not flushed will be included by the default reporter in its output after the result of the test. If Python's warnings filter system (see the -W command -line option to Python) is configured to treat a warning as an error, +href="http://docs.python.org/using/cmdline.html#cmdoption-unittest-discover-W">the +-W command option to Python) is configured to treat a warning as an error, then unflushed warnings will causes tests to fail and will be included in the summary section of the default reporter. Note that unlike usual operation, when warnings.warn is called as part of a test @@ -167,4 +167,3 @@ - diff --git a/lib/twisted-trunk/doc/core/howto/trial.xhtml b/lib/twisted-trunk/doc/core/howto/trial.xhtml --- a/lib/twisted-trunk/doc/core/howto/trial.xhtml +++ b/lib/twisted-trunk/doc/core/howto/trial.xhtml @@ -132,7 +132,7 @@ [FAIL] Traceback (most recent call last): File "/tmp/calculus/test/test_base_1.py", line 8, in test_add - self.assertEquals(result, 11) + self.assertEqual(result, 11) twisted.trial.unittest.FailTest: not equal: a = None b = 11 @@ -143,7 +143,7 @@ [FAIL] Traceback (most recent call last): File "/tmp/calculus/test/test_base_1.py", line 23, in test_divide - self.assertEquals(result, 2) + self.assertEqual(result, 2) twisted.trial.unittest.FailTest: not equal: a = None b = 2 @@ -154,7 +154,7 @@ [FAIL] Traceback (most recent call last): File "/tmp/calculus/test/test_base_1.py", line 18, in test_multiply - self.assertEquals(result, 60) + self.assertEqual(result, 60) twisted.trial.unittest.FailTest: not equal: a = None b = 60 @@ -165,7 +165,7 @@ [FAIL] Traceback (most recent call last): File "/tmp/calculus/test/test_base_1.py", line 13, in test_subtract - self.assertEquals(result, 4) + self.assertEqual(result, 4) twisted.trial.unittest.FailTest: not equal: a = None b = 4 @@ -532,7 +532,7 @@ creator = protocol.ClientCreator(reactor, RemoteCalculationClient) def cb(client): self.addCleanup(self.client.transport.loseConnection) - return getattr(client, op)(a, b).addCallback(self.assertEquals, expected) + return getattr(client, op)(a, b).addCallback(self.assertEqual, expected) return creator.connectTCP('127.0.0.1', self.port.getHost().port).addCallback(cb) @@ -551,7 +551,7 @@

     def test_invalidParameters(self):
         self.proto.dataReceived('add foo bar\r\n')
    -    self.assertEquals(self.tr.value(), "error\r\n")
    +    self.assertEqual(self.tr.value(), "error\r\n")
     
    remote_2.py diff --git a/lib/twisted-trunk/doc/core/howto/tutorial/protocol.xhtml b/lib/twisted-trunk/doc/core/howto/tutorial/protocol.xhtml --- a/lib/twisted-trunk/doc/core/howto/tutorial/protocol.xhtml +++ b/lib/twisted-trunk/doc/core/howto/tutorial/protocol.xhtml @@ -46,7 +46,7 @@ base="twisted.application.service.Service">setServiceParent
    method is used to define the two TCPServer services as children of application, which implements IServiceCollection. Both +base="twisted.application.service">IServiceCollection
    . Both services are thus started with the application.

    diff --git a/lib/twisted-trunk/doc/core/howto/upgrading.xhtml b/lib/twisted-trunk/doc/core/howto/upgrading.xhtml --- a/lib/twisted-trunk/doc/core/howto/upgrading.xhtml +++ b/lib/twisted-trunk/doc/core/howto/upgrading.xhtml @@ -12,7 +12,7 @@

    Applications must frequently deal with data that lives longer than the programs that create it. Sometimes the structure of that data changes over -time, but new versions of a program must be able to accomodate data created +time, but new versions of a program must be able to accommodate data created by an older version. These versions may change very quickly, especially during development of new code. Sometimes different versions of the same program are running at the same time, sharing data across a network @@ -145,7 +145,7 @@

    Finally, version 2.0 adds multiple dimensions. Instead of merely recording the length of a line, it records the size of an N-dimensional -rectangular solid. For backwards compatiblity, all 1.X version of the +rectangular solid. For backwards compatibility, all 1.X version of the program are assumed to be dealing with a 1-dimensional line. We change the name of the attribute from .length to .size to reflect the new meaning.

    @@ -227,7 +227,7 @@ can probably be sent across a network connection, and the upgrade process can be made to occur upon receipt. (You'll want to look at the requireUpgrade - function). This might be useful in providing compability with an older + function). This might be useful in providing compatibility with an older peer. Note, however, that Versioned does not let you go backwards in time; there is no downgradeVersionNN method. This means it is probably only useful for compatibility in one direction: @@ -249,9 +249,10 @@

    Rebuild: Loading New Code Without Restarting

    -

    Versioned is good for handling changes between -released versions of your program, where the application state is saved on -disk during the upgrade. But while you are developing that code, you often +

    Versioned is good for handling changes +between released versions of your program, where the application state is saved +on disk during the upgrade. But while you are developing that code, you often want to change the behavior of the running program, without the slowdown of saving everything out to disk, shutting down, and restarting. Sometimes it will be difficult or time-consuming to get back to the previous diff --git a/lib/twisted-trunk/doc/core/man/twistd.1 b/lib/twisted-trunk/doc/core/man/twistd.1 --- a/lib/twisted-trunk/doc/core/man/twistd.1 +++ b/lib/twisted-trunk/doc/core/man/twistd.1 @@ -1,4 +1,4 @@ -.TH TWISTD "1" "Dec 2003" "" "" +.TH TWISTD "1" "Dec 2011" "" "" .SH NAME twistd \- run Twisted applications (TACs, TAPs) .SH SYNOPSIS @@ -88,18 +88,9 @@ Use the variable "application" from the given Python file. This option overrides \fB\-f\fR. This option implies \fB\--no_save\fR. .TP -\fB\-g\fR, \fB\--plugin\fR \fI\fR -Read config.tac from a plugin package, as with \fB\-y\fR. -.TP \fB\--syslog\fR Log to syslog instead of a file. .TP -\fB\-u\fR, \fB\--uid\fR \fI\fR -The uid to run as. -.TP -\fB\-g\fR, \fB\--gid\fR \fI\fR -The gid to run as. -.TP \fB\--version\fR Print version information and exit. .TP @@ -117,7 +108,7 @@ To report a bug, visit \fIhttp://twistedmatrix.com/trac/wiki/TwistedDevelopment#DevelopmentProcess\fR .SH COPYRIGHT -Copyright \(co 2001-2010 Twisted Matrix Laboratories. +Copyright \(co 2001-2011 Twisted Matrix Laboratories. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/lib/twisted-trunk/doc/fun/Twisted.Quotes b/lib/twisted-trunk/doc/fun/Twisted.Quotes --- a/lib/twisted-trunk/doc/fun/Twisted.Quotes +++ b/lib/twisted-trunk/doc/fun/Twisted.Quotes @@ -5784,3 +5784,19 @@ % seriously, I sneeze out a resource pool before breakfast every morning % + It should be AMP I guess. + Or at least protobuffers or some crap like that. + you're trying too hard. + gxti: That's the only way I know how to try. +% + PenguinOfDoom: plz upload that to PyPI + assuming you did it right + and didn't totally screw it up + haha + how would I even be able to tell + you just assert that you didn't + then when it breaks you blame someone else + it's the distutils' hokey pokey + o/` you put your pathname in o/` you take your sys path out o/` you + change your site.py o/` and you shake it all about o/` +% diff --git a/lib/twisted-trunk/doc/web/howto/client.xhtml b/lib/twisted-trunk/doc/web/howto/client.xhtml --- a/lib/twisted-trunk/doc/web/howto/client.xhtml +++ b/lib/twisted-trunk/doc/web/howto/client.xhtml @@ -132,6 +132,25 @@ Issue a request with a body. +

    + If you want to upload a file or you just have some data in a string, you + don't have to copy StringProducer though. Instead, you can + use FileBodyProducer. + This IBodyProducer implementation works with any file-like + object (so use it with a StringIO if your upload data is + already in memory as a string); the idea is the same + as StringProducer from the previous example, but with a + little extra code to only send data as fast as the server will take it. +

    + + + Another way to issue a request with a body. + + +

    + FileBodyProducer closes the file when it no longer needs it. +

    +

    Receiving Responses

    @@ -286,6 +305,67 @@ context objects.

    +

    Using a HTTP proxy

    + +

    + To be able to use HTTP proxies with an agent, you can use the twisted.web.client.ProxyAgent class. It supports the + same interface as Agent, but takes the endpoint of the proxy + as initializer argument. +

    + +

    + Here's an example demonstrating the use of an HTTP proxy running on + localhost:8000. +

    + +
    +from twisted.python.log import err
    +from twisted.web.client import ProxyAgent
    +from twisted.internet import reactor
    +from twisted.internet.endpoints import TCP4ClientEndpoint
    +
    +def display(response):
    +    print "Received response"
    +    print response
    +
    +def main():
    +    endpoint = TCP4ClientEndpoint(reactor, "localhost", 8000)
    +    agent = ProxyAgent(endpoint)
    +    d = agent.request("GET", "https://example.com/")
    +    d.addCallbacks(display, err)
    +    d.addCallback(lambda ignored: reactor.stop())
    +    reactor.run()
    +
    +if __name__ == "__main__":
    +    main()
    +
    + +

    + Please refer to the endpoints documentation for + more information about how they work and the twisted.internet.endpoints API documentation to learn + what other kinds of endpoints exist. +

    + +

    Handling HTTP cookies

    + +

    + An existing agent instance can be wrapped with + twisted.web.client.CookieAgent to automatically + store, send and track HTTP cookies. A CookieJar + instance, from the Python standard library module + cookielib, is + used to store the cookie information. An example of using + CookieAgent to perform a request and display the collected + cookies might look like this: +

    + + + Storing cookies with CookieAgent + +

    Conclusion

    diff --git a/lib/twisted-trunk/doc/web/howto/resource-templates.xhtml b/lib/twisted-trunk/doc/web/howto/resource-templates.xhtml --- a/lib/twisted-trunk/doc/web/howto/resource-templates.xhtml +++ b/lib/twisted-trunk/doc/web/howto/resource-templates.xhtml @@ -13,7 +13,7 @@

    Overview

    While high-level templating systems can be used with Twisted (for -example, Divmod +example, Divmod Nevow, sometimes one needs a less file-heavy system which lets one directly write HTML. While ResourceScript is diff --git a/lib/twisted-trunk/doc/web/howto/using-twistedweb.xhtml b/lib/twisted-trunk/doc/web/howto/using-twistedweb.xhtml --- a/lib/twisted-trunk/doc/web/howto/using-twistedweb.xhtml +++ b/lib/twisted-trunk/doc/web/howto/using-twistedweb.xhtml @@ -206,7 +206,7 @@

    Non-trivial configurations of Twisted Web are achieved with Python configuration files. This is a Python snippet which builds up a variable called application. Usually, -a twisted.application.internet.TCPServer +a twisted.application.internet.TCPServer instance will be used to make the application listen on a TCP port (80, in case direct web serving is desired), with the listener being a twisted.web.server.Site. The resulting file @@ -498,8 +498,8 @@

    Web UIs

    -The Nevow framework, available as -part of the Quotient project, +The Nevow framework, available as +part of the Quotient project, is an advanced system for giving Web UIs to your application. Nevow uses Twisted Web but is not itself part of Twisted.

    @@ -560,7 +560,7 @@

    Serving WSGI Applications

    -

    WSGI is the Web Server Gateway +

    WSGI is the Web Server Gateway Interface. It is a specification for web servers and application servers to communicate with Python web applications. All modern Python web frameworks support the WSGI interface.

    diff --git a/lib/twisted-trunk/doc/web/howto/web-overview.xhtml b/lib/twisted-trunk/doc/web/howto/web-overview.xhtml --- a/lib/twisted-trunk/doc/web/howto/web-overview.xhtml +++ b/lib/twisted-trunk/doc/web/howto/web-overview.xhtml @@ -55,7 +55,7 @@

    Web programmers seeking a higher level abstraction than the Resource system - should look at Nevow. + should look at Nevow. Nevow is based on ideas previously developed in Twisted, but is now maintained outside of Twisted to easy development and release cycle pressures.

    diff --git a/lib/twisted-trunk/doc/web/howto/xmlrpc.xhtml b/lib/twisted-trunk/doc/web/howto/xmlrpc.xhtml --- a/lib/twisted-trunk/doc/web/howto/xmlrpc.xhtml +++ b/lib/twisted-trunk/doc/web/howto/xmlrpc.xhtml @@ -12,9 +12,11 @@

    Introduction

    -

    XML-RPC is a simple request/reply protocol that runs over HTTP. It is simple, -easy to implement and supported by most programming languages. Twisted's XML-RPC -support is implemented using the xmlrpclib library that is included with Python 2.2 and later.

    +

    XML-RPC is a simple request/reply protocol +that runs over HTTP. It is simple, easy to implement and supported by most programming +languages. Twisted's XML-RPC support is implemented using the +xmlrpclib library that is +included with Python 2.2 and later.

    Creating a XML-RPC server

    @@ -26,16 +28,13 @@

    Methods published via XML-RPC can return all the basic XML-RPC types, such as strings, lists and so on (just return a regular python integer, etc). They can also raise exceptions or return Failure instances to indicate an -error has occurred, or Binary, Boolean or DateTime instances (all of these are the same as -the respective classes in xmlrpclib. In addition, XML-RPC published -methods can return Deferred instances whose results are one of the -above. This allows you to return results that can't be calculated -immediately, such as database queries. See the Deferred documentation for more details.

    +error has occurred, or Binary, Boolean or DateTime +instances (all of these are the same as the respective classes in xmlrpclib. In +addition, XML-RPC published methods can return Deferred instances whose results are one of the above. This allows +you to return results that can't be calculated immediately, such as database queries. +See the Deferred documentation for more +details.

    XMLRPC instances are Resource objects, and they can thus be published using a Site. The @@ -46,7 +45,9 @@ from twisted.web import xmlrpc, server class Example(xmlrpc.XMLRPC): - """An example object to be published.""" + """ + An example object to be published. + """ def xmlrpc_echo(self, x): """ @@ -130,21 +131,31 @@ from twisted.web import xmlrpc, server class Example(xmlrpc.XMLRPC): - """An example object to be published.""" + """ + An example object to be published. + """ def xmlrpc_echo(self, x): - """Return all passed args.""" + """ + Return all passed args. + """ return x def xmlrpc_add(self, a, b): - """Return sum of arguments.""" + """ + Return sum of arguments. + """ return a + b class Date(xmlrpc.XMLRPC): - """Serve the XML-RPC 'time' method.""" + """ + Serve the XML-RPC 'time' method. + """ def xmlrpc_time(self): - """Return UNIX time.""" + """ + Return UNIX time. + """ return time.time() if __name__ == '__main__': @@ -176,7 +187,7 @@

    Adding XML-RPC Introspection support

    XML-RPC has an -informal Introspection +informal Introspection API that specifies three methods in a system sub-handler which allow a client to query a server about the server's API. Adding Introspection support to @@ -288,9 +299,9 @@

    twisted.web.xmlrpc.XMLRPC and twisted.web.soap.SOAPPublisher are both Resources. So, to serve both XML-RPC and +base="twisted.web.resource">Resources. So, to serve both XML-RPC and SOAP in the one web server, you can use the putChild method of Resources.

    +base="twisted.web.resource.IResource">putChild
    method of Resource.

    The following example uses an empty resource.Resource as the root resource for diff --git a/lib/twisted-trunk/emacs/banana.el b/lib/twisted-trunk/emacs/banana.el --- a/lib/twisted-trunk/emacs/banana.el +++ b/lib/twisted-trunk/emacs/banana.el @@ -1,6 +1,7 @@ +;;;; Copyright (c) Twisted Matrix Laboratories. +;;;; See LICENSE for details. ;;;; Banana -- allows network abstraction, nearly always. -;;;; by Allen Short -;;;; This file is in the public domain. +;;;; by Allen Short "'Get into a rut early: Do the same processes the same way. Accumulate idioms. Standardize. The only difference(!) between Shakespeare and you was diff --git a/lib/twisted-trunk/emacs/jelly.el b/lib/twisted-trunk/emacs/jelly.el --- a/lib/twisted-trunk/emacs/jelly.el +++ b/lib/twisted-trunk/emacs/jelly.el @@ -1,6 +1,7 @@ +;;;; Copyright (c) Twisted Matrix Laboratories. +;;;; See LICENSE for details. ;;;; Jelly -- portable serialisation for network communication. -;;;; by Allen Short -;;;; This file is in the public domain. +;;;; by Allen Short "'Get into a rut early: Do the same processes the same way. Accumulate idioms. Standardize. The only difference(!) between Shakespeare and you was the size of his idiom list -- not the size of his vocabulary.' -- Alan Perlis, Programming Epigram #10" diff --git a/lib/twisted-trunk/emacs/manhole.el b/lib/twisted-trunk/emacs/manhole.el --- a/lib/twisted-trunk/emacs/manhole.el +++ b/lib/twisted-trunk/emacs/manhole.el @@ -1,3 +1,7 @@ +;;;; Copyright (c) Twisted Matrix Laboratories. +;;;; See LICENSE for details. +;;;; by Allen Short + ;;this is all based on ielm.el -- i was planning to copy ;;inferior-emacs-lisp-mode as verbatim as possible and just swap ;;function names round, and bringing in the python diff --git a/lib/twisted-trunk/emacs/pb.el b/lib/twisted-trunk/emacs/pb.el --- a/lib/twisted-trunk/emacs/pb.el +++ b/lib/twisted-trunk/emacs/pb.el @@ -1,6 +1,7 @@ +;;;; Copyright (c) Twisted Matrix Laboratories. +;;;; See LICENSE for details. ;;;; pb.el - a perspective broker implementation for emacs -;;;; by Allen Short -;;;; this file is in the public domain. +;;;; by Allen Short "'We will never run out of things to program as long as there is a single program around.' -- Alan Perlis, Programming Epigram #100" diff --git a/lib/twisted-trunk/emacs/pbechoclient.el b/lib/twisted-trunk/emacs/pbechoclient.el --- a/lib/twisted-trunk/emacs/pbechoclient.el +++ b/lib/twisted-trunk/emacs/pbechoclient.el @@ -1,3 +1,7 @@ +;;;; Copyright (c) Twisted Matrix Laboratories. +;;;; See LICENSE for details. +;;;; by Allen Short + (require 'pb) (defvar pbecho-buf (get-buffer-create "*pbechoclient*")) diff --git a/lib/twisted-trunk/emacs/pbsimpleclient.el b/lib/twisted-trunk/emacs/pbsimpleclient.el --- a/lib/twisted-trunk/emacs/pbsimpleclient.el +++ b/lib/twisted-trunk/emacs/pbsimpleclient.el @@ -1,3 +1,7 @@ +;;;; Copyright (c) Twisted Matrix Laboratories. +;;;; See LICENSE for details. +;;;; by Allen Short + (require 'pb) (defvar pbsimple-buf (get-buffer-create "*pbsimpleclient*")) diff --git a/lib/twisted-trunk/emacs/twisted-dev.el b/lib/twisted-trunk/emacs/twisted-dev.el --- a/lib/twisted-trunk/emacs/twisted-dev.el +++ b/lib/twisted-trunk/emacs/twisted-dev.el @@ -1,3 +1,7 @@ +;;;; Copyright (c) Twisted Matrix Laboratories. +;;;; See LICENSE for details. +;;;; by Allen Short + ;; Instructions for Use ;; In your ~/.emacs, write: diff --git a/lib/twisted-trunk/setup.py b/lib/twisted-trunk/setup.py --- a/lib/twisted-trunk/setup.py +++ b/lib/twisted-trunk/setup.py @@ -31,7 +31,7 @@ execfile(setup_py, ns, ns) if "extensions" in ns: extensions.extend(ns["extensions"]) - + return extensions @@ -43,42 +43,43 @@ if os.path.exists('twisted'): sys.path.insert(0, '.') from twisted import copyright - from twisted.python.dist import getDataFiles, getScripts, getPackages, setup + from twisted.python.dist import getDataFiles, getScripts, getPackages, \ + setup, twisted_subprojects # "" is included because core scripts are directly in bin/ projects = [''] + [x for x in os.listdir('bin') if os.path.isdir(os.path.join("bin", x)) - and not x.startswith(".")] + and x in twisted_subprojects] + scripts = [] for i in projects: scripts.extend(getScripts(i)) - setup_args = dict( - # metadata - name="Twisted", - version=copyright.version, - description="An asynchronous networking framework written in " - "Python", - author="Twisted Matrix Laboratories", - author_email="twisted-python at twistedmatrix.com", - maintainer="Glyph Lefkowitz", - maintainer_email="glyph at twistedmatrix.com", - url="http://twistedmatrix.com/", - license="MIT", - long_description="""\ + setup_args = dict( + # metadata + name="Twisted", + version=copyright.version, + description="An asynchronous networking framework written in Python", + author="Twisted Matrix Laboratories", + author_email="twisted-python at twistedmatrix.com", + maintainer="Glyph Lefkowitz", + maintainer_email="glyph at twistedmatrix.com", + url="http://twistedmatrix.com/", + license="MIT", + long_description="""\ An extensible framework for Python programming, with special focus on event-based network programming and multiprotocol integration. """, - packages = getPackages('twisted'), - conditionalExtensions = getExtensions(), - scripts = scripts, - data_files=getDataFiles('twisted'), - classifiers=[ - "Programming Language :: Python :: 2.4", - "Programming Language :: Python :: 2.5", - "Programming Language :: Python :: 2.6", - "Programming Language :: Python :: 2.7", - ]) + packages = getPackages('twisted'), + conditionalExtensions = getExtensions(), + scripts = scripts, + data_files=getDataFiles('twisted'), + classifiers=[ + "Programming Language :: Python :: 2.4", + "Programming Language :: Python :: 2.5", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + ]) if 'setuptools' in sys.modules: from pkg_resources import parse_requirements diff --git a/lib/twisted-trunk/twisted/application/service.py b/lib/twisted-trunk/twisted/application/service.py --- a/lib/twisted-trunk/twisted/application/service.py +++ b/lib/twisted-trunk/twisted/application/service.py @@ -39,7 +39,7 @@ "Twisted application plugin.") options = Attribute( - "A C{twisted.python.usage.Options} subclass defining the" + "A C{twisted.python.usage.Options} subclass defining the " "configuration options for this application.") diff --git a/lib/twisted-trunk/twisted/application/test/test_internet.py b/lib/twisted-trunk/twisted/application/test/test_internet.py --- a/lib/twisted-trunk/twisted/application/test/test_internet.py +++ b/lib/twisted-trunk/twisted/application/test/test_internet.py @@ -165,7 +165,7 @@ self.svc.startService() self.fakeServer.result.errback(ZeroDivisionError()) logged = self.flushLoggedErrors(ZeroDivisionError) - self.assertEquals(len(logged), 1) + self.assertEqual(len(logged), 1) def test_synchronousFailReportsError(self): @@ -176,7 +176,7 @@ self.fakeServer.failImmediately = ZeroDivisionError() self.svc.startService() logged = self.flushLoggedErrors(ZeroDivisionError) - self.assertEquals(len(logged), 1) + self.assertEqual(len(logged), 1) def test_startServiceUnstarted(self): @@ -187,7 +187,7 @@ """ self.svc.startService() self.assertIdentical(self.factory, self.fakeServer.factory) - self.assertEquals(self.svc.running, True) + self.assertEqual(self.svc.running, True) def test_startServiceStarted(self): @@ -197,8 +197,8 @@ """ self.test_privilegedStartService() self.svc.startService() - self.assertEquals(self.fakeServer.listenAttempts, 1) - self.assertEquals(self.svc.running, True) + self.assertEqual(self.fakeServer.listenAttempts, 1) + self.assertEqual(self.svc.running, True) def test_stopService(self): @@ -214,9 +214,9 @@ result = self.svc.stopService() l = [] result.addCallback(l.append) - self.assertEquals(len(l), 0) + self.assertEqual(len(l), 0) self.fakeServer.stoppedListening() - self.assertEquals(len(l), 1) + self.assertEqual(len(l), 1) self.assertFalse(self.svc.running) @@ -230,8 +230,8 @@ result = self.svc.stopService() l = [] result.addBoth(l.append) - self.assertEquals(l, [None]) - self.assertEquals(self.flushLoggedErrors(CancelledError), []) + self.assertEqual(l, [None]) + self.assertEqual(self.flushLoggedErrors(CancelledError), []) def test_stopServiceCancelStartError(self): @@ -245,8 +245,8 @@ result = self.svc.stopService() l = [] result.addCallback(l.append) - self.assertEquals(l, [None]) + self.assertEqual(l, [None]) stoppingErrors = self.flushLoggedErrors(ZeroDivisionError) - self.assertEquals(len(stoppingErrors), 1) + self.assertEqual(len(stoppingErrors), 1) diff --git a/lib/twisted-trunk/twisted/conch/insults/window.py b/lib/twisted-trunk/twisted/conch/insults/window.py --- a/lib/twisted-trunk/twisted/conch/insults/window.py +++ b/lib/twisted-trunk/twisted/conch/insults/window.py @@ -729,8 +729,12 @@ class ScrolledArea(Widget): + """ + A L{ScrolledArea} contains another widget wrapped in a viewport and + vertical and horizontal scrollbars for moving the viewport around. + """ def __init__(self, containee): - Widget.__init__(self, containee) + Widget.__init__(self) self._viewport = Viewport(containee) self._horiz = HorizontalScrollbar(self._horizScroll) self._vert = VerticalScrollbar(self._vertScroll) diff --git a/lib/twisted-trunk/twisted/conch/test/test_agent.py b/lib/twisted-trunk/twisted/conch/test/test_agent.py --- a/lib/twisted-trunk/twisted/conch/test/test_agent.py +++ b/lib/twisted-trunk/twisted/conch/test/test_agent.py @@ -309,7 +309,7 @@ def _check(sig): # Cannot do this b/c DSA uses random numbers when signing # expected = self.dsaPrivate.sign("John Hancock") - # self.assertEquals(expected, sig) + # self.assertEqual(expected, sig) self.assertTrue(self.dsaPublic.verify(sig, "John Hancock")) return d.addCallback(_check) @@ -340,7 +340,7 @@ received = {} for k in keyt: received[keys.Key.fromString(k[0], type='blob').blob()] = k[1] - self.assertEquals(expected, received) + self.assertEqual(expected, received) return d.addCallback(_check) @@ -395,5 +395,5 @@ self.pump.flush() def _check(ignored): - self.assertEquals(0, len(self.server.factory.keys)) + self.assertEqual(0, len(self.server.factory.keys)) return d.addCallback(_check) diff --git a/lib/twisted-trunk/twisted/conch/test/test_cftp.py b/lib/twisted-trunk/twisted/conch/test/test_cftp.py --- a/lib/twisted-trunk/twisted/conch/test/test_cftp.py +++ b/lib/twisted-trunk/twisted/conch/test/test_cftp.py @@ -156,10 +156,10 @@ locale.setlocale(locale.LC_ALL, "es_AR.UTF8") self.addCleanup(locale.setlocale, locale.LC_ALL, currentLocale) - self.assertEquals( + self.assertEqual( self._lsInTimezone('America/New_York', stat), '!--------- 0 0 0 0 Aug 28 17:33 foo') - self.assertEquals( + self.assertEqual( self._lsInTimezone('Pacific/Auckland', stat), '!--------- 0 0 0 0 Aug 29 09:33 foo') @@ -229,7 +229,7 @@ sys.executable) d = self.client._dispatchCommand("exec print 1 + 2") - d.addCallback(self.assertEquals, "3\n") + d.addCallback(self.assertEqual, "3\n") return d @@ -242,7 +242,7 @@ getpass.getuser(), 'secret', os.getuid(), 1234, 'foo', 'bar', '') d = self.client._dispatchCommand("exec echo hello") - d.addCallback(self.assertEquals, "hello\n") + d.addCallback(self.assertEqual, "hello\n") return d @@ -255,7 +255,7 @@ '/bin/sh') d = self.client._dispatchCommand("!echo hello") - d.addCallback(self.assertEquals, "hello\n") + d.addCallback(self.assertEqual, "hello\n") return d @@ -297,7 +297,7 @@ clock.advance(2.0) wrapper.total += 4096 self.client._printProgressBar(wrapper, startTime) - self.assertEquals(self.client.transport.value(), + self.assertEqual(self.client.transport.value(), "\rsample 40% 4.0kB 2.0kBps 00:03 ") @@ -314,7 +314,7 @@ wrapper = cftp.FileWrapper(wrapped) startTime = clock.seconds() self.client._printProgressBar(wrapper, startTime) - self.assertEquals(self.client.transport.value(), + self.assertEqual(self.client.transport.value(), "\rsample 0% 0.0B 0.0Bps 00:00 ") @@ -615,7 +615,7 @@ """ f1 = file(name1).read() f2 = file(name2).read() - self.failUnlessEqual(f1, f2, msg) + self.assertEqual(f1, f2, msg) def testGet(self): @@ -786,8 +786,8 @@ appropriate error, and doesn't log an useless error server side. """ def _check(results): - self.assertEquals(results[0], '') - self.assertEquals(results[1], + self.assertEqual(results[0], '') + self.assertEqual(results[1], 'remote error 11: mkdir failed') d = self.runScript('mkdir testMakeDirectory', @@ -875,7 +875,7 @@ res = res.split('\n') log.msg('RES %s' % str(res)) self.failUnless(res[1].find(self.testDir) != -1, repr(res)) - self.failUnlessEqual(res[3:-2], ['testDirectory', 'testRemoveFile', + self.assertEqual(res[3:-2], ['testDirectory', 'testRemoveFile', 'testRenameFile', 'testfile1']) d = self._getBatchOutput(cmds) @@ -954,7 +954,7 @@ '-o', 'Port=%i' % (port,), '-b', fn, 'testuser at 127.0.0.1') d = getProcessOutputAndValue("sftp", cmds) def check(result): - self.assertEquals(result[2], 0) + self.assertEqual(result[2], 0) for i in ['testDirectory', 'testRemoveFile', 'testRenameFile', 'testfile1']: self.assertIn(i, result[0]) diff --git a/lib/twisted-trunk/twisted/conch/test/test_channel.py b/lib/twisted-trunk/twisted/conch/test/test_channel.py --- a/lib/twisted-trunk/twisted/conch/test/test_channel.py +++ b/lib/twisted-trunk/twisted/conch/test/test_channel.py @@ -91,31 +91,31 @@ order. """ c = channel.SSHChannel(conn=self.conn) - self.assertEquals(c.localWindowSize, 131072) - self.assertEquals(c.localWindowLeft, 131072) - self.assertEquals(c.localMaxPacket, 32768) - self.assertEquals(c.remoteWindowLeft, 0) - self.assertEquals(c.remoteMaxPacket, 0) - self.assertEquals(c.conn, self.conn) - self.assertEquals(c.data, None) - self.assertEquals(c.avatar, None) + self.assertEqual(c.localWindowSize, 131072) + self.assertEqual(c.localWindowLeft, 131072) + self.assertEqual(c.localMaxPacket, 32768) + self.assertEqual(c.remoteWindowLeft, 0) + self.assertEqual(c.remoteMaxPacket, 0) + self.assertEqual(c.conn, self.conn) + self.assertEqual(c.data, None) + self.assertEqual(c.avatar, None) c2 = channel.SSHChannel(1, 2, 3, 4, 5, 6, 7) - self.assertEquals(c2.localWindowSize, 1) - self.assertEquals(c2.localWindowLeft, 1) - self.assertEquals(c2.localMaxPacket, 2) - self.assertEquals(c2.remoteWindowLeft, 3) - self.assertEquals(c2.remoteMaxPacket, 4) - self.assertEquals(c2.conn, 5) - self.assertEquals(c2.data, 6) - self.assertEquals(c2.avatar, 7) + self.assertEqual(c2.localWindowSize, 1) + self.assertEqual(c2.localWindowLeft, 1) + self.assertEqual(c2.localMaxPacket, 2) + self.assertEqual(c2.remoteWindowLeft, 3) + self.assertEqual(c2.remoteMaxPacket, 4) + self.assertEqual(c2.conn, 5) + self.assertEqual(c2.data, 6) + self.assertEqual(c2.avatar, 7) def test_str(self): """ Test that str(SSHChannel) works gives the channel name and local and remote windows at a glance.. """ - self.assertEquals(str(self.channel), '') def test_logPrefix(self): @@ -123,7 +123,7 @@ Test that SSHChannel.logPrefix gives the name of the channel, the local channel ID and the underlying connection. """ - self.assertEquals(self.channel.logPrefix(), 'SSHChannel channel ' + self.assertEqual(self.channel.logPrefix(), 'SSHChannel channel ' '(unknown) on MockConnection') def test_addWindowBytes(self): @@ -138,13 +138,13 @@ self.channel.write('test') self.channel.writeExtended(1, 'test') self.channel.addWindowBytes(50) - self.assertEquals(self.channel.remoteWindowLeft, 50 - 4 - 4) + self.assertEqual(self.channel.remoteWindowLeft, 50 - 4 - 4) self.assertTrue(self.channel.areWriting) self.assertTrue(cb[0]) - self.assertEquals(self.channel.buf, '') - self.assertEquals(self.conn.data[self.channel], ['test']) - self.assertEquals(self.channel.extBuf, []) - self.assertEquals(self.conn.extData[self.channel], [(1, 'test')]) + self.assertEqual(self.channel.buf, '') + self.assertEqual(self.conn.data[self.channel], ['test']) + self.assertEqual(self.channel.extBuf, []) + self.assertEqual(self.conn.extData[self.channel], [(1, 'test')]) cb[0] = False self.channel.addWindowBytes(20) @@ -192,20 +192,20 @@ self.channel.addWindowBytes(20) self.channel.write('ta') data = self.conn.data[self.channel] - self.assertEquals(data, ['da', 'ta']) - self.assertEquals(self.channel.remoteWindowLeft, 16) + self.assertEqual(data, ['da', 'ta']) + self.assertEqual(self.channel.remoteWindowLeft, 16) # larger than max packet self.channel.write('12345678901') - self.assertEquals(data, ['da', 'ta', '1234567890', '1']) - self.assertEquals(self.channel.remoteWindowLeft, 5) + self.assertEqual(data, ['da', 'ta', '1234567890', '1']) + self.assertEqual(self.channel.remoteWindowLeft, 5) # running out of window cb[0] = False self.channel.write('123456') self.assertFalse(self.channel.areWriting) self.assertTrue(cb[0]) - self.assertEquals(data, ['da', 'ta', '1234567890', '1', '12345']) - self.assertEquals(self.channel.buf, '6') - self.assertEquals(self.channel.remoteWindowLeft, 0) + self.assertEqual(data, ['da', 'ta', '1234567890', '1', '12345']) + self.assertEqual(self.channel.buf, '6') + self.assertEqual(self.channel.remoteWindowLeft, 0) def test_writeExtended(self): """ @@ -227,22 +227,22 @@ self.channel.addWindowBytes(20) self.channel.writeExtended(2, 'a') data = self.conn.extData[self.channel] - self.assertEquals(data, [(1, 'da'), (2, 't'), (2, 'a')]) - self.assertEquals(self.channel.remoteWindowLeft, 16) + self.assertEqual(data, [(1, 'da'), (2, 't'), (2, 'a')]) + self.assertEqual(self.channel.remoteWindowLeft, 16) # larger than max packet self.channel.writeExtended(3, '12345678901') - self.assertEquals(data, [(1, 'da'), (2, 't'), (2, 'a'), + self.assertEqual(data, [(1, 'da'), (2, 't'), (2, 'a'), (3, '1234567890'), (3, '1')]) - self.assertEquals(self.channel.remoteWindowLeft, 5) + self.assertEqual(self.channel.remoteWindowLeft, 5) # running out of window cb[0] = False self.channel.writeExtended(4, '123456') self.assertFalse(self.channel.areWriting) self.assertTrue(cb[0]) - self.assertEquals(data, [(1, 'da'), (2, 't'), (2, 'a'), + self.assertEqual(data, [(1, 'da'), (2, 't'), (2, 'a'), (3, '1234567890'), (3, '1'), (4, '12345')]) - self.assertEquals(self.channel.extBuf, [[4, '6']]) - self.assertEquals(self.channel.remoteWindowLeft, 0) + self.assertEqual(self.channel.extBuf, [[4, '6']]) + self.assertEqual(self.channel.remoteWindowLeft, 0) def test_writeSequence(self): """ @@ -250,7 +250,7 @@ """ self.channel.addWindowBytes(20) self.channel.writeSequence(map(str, range(10))) - self.assertEquals(self.conn.data[self.channel], ['0123456789']) + self.assertEqual(self.conn.data[self.channel], ['0123456789']) def test_loseConnection(self): """ @@ -260,9 +260,9 @@ self.channel.write('data') self.channel.writeExtended(1, 'datadata') self.channel.loseConnection() - self.assertEquals(self.conn.closes.get(self.channel), None) + self.assertEqual(self.conn.closes.get(self.channel), None) self.channel.addWindowBytes(4) # send regular data - self.assertEquals(self.conn.closes.get(self.channel), None) + self.assertEqual(self.conn.closes.get(self.channel), None) self.channel.addWindowBytes(8) # send extended data self.assertTrue(self.conn.closes.get(self.channel)) @@ -270,10 +270,10 @@ """ Test that getPeer() returns ('SSH', ). """ - self.assertEquals(self.channel.getPeer(), ('SSH', 'MockPeer')) + self.assertEqual(self.channel.getPeer(), ('SSH', 'MockPeer')) def test_getHost(self): """ Test that getHost() returns ('SSH', ). """ - self.assertEquals(self.channel.getHost(), ('SSH', 'MockHost')) + self.assertEqual(self.channel.getHost(), ('SSH', 'MockHost')) diff --git a/lib/twisted-trunk/twisted/conch/test/test_checkers.py b/lib/twisted-trunk/twisted/conch/test/test_checkers.py --- a/lib/twisted-trunk/twisted/conch/test/test_checkers.py +++ b/lib/twisted-trunk/twisted/conch/test/test_checkers.py @@ -81,8 +81,8 @@ authorized_keys file and check the keys against that file. """ self._testCheckKey("authorized_keys") - self.assertEquals(self.mockos.seteuidCalls, []) - self.assertEquals(self.mockos.setegidCalls, []) + self.assertEqual(self.mockos.seteuidCalls, []) + self.assertEqual(self.mockos.setegidCalls, []) def test_checkKey2(self): @@ -91,8 +91,8 @@ authorized_keys2 file and check the keys against that file. """ self._testCheckKey("authorized_keys2") - self.assertEquals(self.mockos.seteuidCalls, []) - self.assertEquals(self.mockos.setegidCalls, []) + self.assertEqual(self.mockos.seteuidCalls, []) + self.assertEqual(self.mockos.setegidCalls, []) def test_checkKeyAsRoot(self): @@ -114,8 +114,8 @@ user = UsernamePassword("user", "password") user.blob = "foobar" self.assertTrue(self.checker.checkKey(user)) - self.assertEquals(self.mockos.seteuidCalls, [0, 1, 0, os.getuid()]) - self.assertEquals(self.mockos.setegidCalls, [2, os.getgid()]) + self.assertEqual(self.mockos.seteuidCalls, [0, 1, 0, os.getuid()]) + self.assertEqual(self.mockos.setegidCalls, [2, os.getgid()]) def test_requestAvatarId(self): @@ -130,7 +130,7 @@ 'foo', keys.Key.fromString(keydata.privateRSA_openssh).sign('foo')) d = self.checker.requestAvatarId(credentials) def _verify(avatarId): - self.assertEquals(avatarId, 'test') + self.assertEqual(avatarId, 'test') return d.addCallback(_verify) @@ -208,9 +208,9 @@ the list of registered checkers. """ checker = SSHProtocolChecker() - self.assertEquals(checker.credentialInterfaces, []) + self.assertEqual(checker.credentialInterfaces, []) checker.registerChecker(SSHPublicKeyDatabase(), ) - self.assertEquals(checker.credentialInterfaces, [ISSHPrivateKey]) + self.assertEqual(checker.credentialInterfaces, [ISSHPrivateKey]) self.assertIsInstance(checker.checkers[ISSHPrivateKey], SSHPublicKeyDatabase) @@ -223,9 +223,9 @@ credentialIntefaces. """ checker = SSHProtocolChecker() - self.assertEquals(checker.credentialInterfaces, []) + self.assertEqual(checker.credentialInterfaces, []) checker.registerChecker(SSHPublicKeyDatabase(), IUsernamePassword) - self.assertEquals(checker.credentialInterfaces, [IUsernamePassword]) + self.assertEqual(checker.credentialInterfaces, [IUsernamePassword]) self.assertIsInstance(checker.checkers[IUsernamePassword], SSHPublicKeyDatabase) @@ -241,7 +241,7 @@ checker.registerChecker(passwordDatabase) d = checker.requestAvatarId(UsernamePassword('test', 'test')) def _callback(avatarId): - self.assertEquals(avatarId, 'test') + self.assertEqual(avatarId, 'test') return d.addCallback(_callback) @@ -277,4 +277,4 @@ """ The default L{SSHProcotolChecker.areDone} should simply return True. """ - self.assertEquals(SSHProtocolChecker().areDone(None), True) + self.assertEqual(SSHProtocolChecker().areDone(None), True) diff --git a/lib/twisted-trunk/twisted/conch/test/test_conch.py b/lib/twisted-trunk/twisted/conch/test/test_conch.py --- a/lib/twisted-trunk/twisted/conch/test/test_conch.py +++ b/lib/twisted-trunk/twisted/conch/test/test_conch.py @@ -349,7 +349,7 @@ server. """ d = self.execute('echo goodbye', ConchTestOpenSSHProcess()) - return d.addCallback(self.assertEquals, 'goodbye\n') + return d.addCallback(self.assertEqual, 'goodbye\n') def test_localToRemoteForwarding(self): @@ -462,7 +462,7 @@ process = ConchTestOpenSSHProcess() d = self.execute("", process, '-o RekeyLimit=2K') def finished(result): - self.assertEquals( + self.assertEqual( result, '\n'.join(['line #%02d' % (i,) for i in range(60)]) + '\n') d.addCallback(finished) diff --git a/lib/twisted-trunk/twisted/conch/test/test_connection.py b/lib/twisted-trunk/twisted/conch/test/test_connection.py --- a/lib/twisted-trunk/twisted/conch/test/test_connection.py +++ b/lib/twisted-trunk/twisted/conch/test/test_connection.py @@ -235,20 +235,20 @@ messages. """ self.conn.ssh_GLOBAL_REQUEST(common.NS('TestGlobal') + '\xff') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_REQUEST_SUCCESS, '')]) self.transport.packets = [] self.conn.ssh_GLOBAL_REQUEST(common.NS('TestData') + '\xff' + 'test data') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_REQUEST_SUCCESS, 'test data')]) self.transport.packets = [] self.conn.ssh_GLOBAL_REQUEST(common.NS('TestBad') + '\xff') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_REQUEST_FAILURE, '')]) self.transport.packets = [] self.conn.ssh_GLOBAL_REQUEST(common.NS('TestGlobal') + '\x00') - self.assertEquals(self.transport.packets, []) + self.assertEqual(self.transport.packets, []) def test_REQUEST_SUCCESS(self): """ @@ -258,7 +258,7 @@ d = self.conn.sendGlobalRequest('request', 'data', True) self.conn.ssh_REQUEST_SUCCESS('data') def check(data): - self.assertEquals(data, 'data') + self.assertEqual(data, 'data') d.addCallback(check) d.addErrback(self.fail) return d @@ -271,7 +271,7 @@ d = self.conn.sendGlobalRequest('request', 'data', True) self.conn.ssh_REQUEST_FAILURE('data') def check(f): - self.assertEquals(f.value.data, 'data') + self.assertEqual(f.value.data, 'data') d.addCallback(self.fail) d.addErrback(check) return d @@ -285,12 +285,12 @@ self.conn.ssh_CHANNEL_OPEN(common.NS('TestChannel') + '\x00\x00\x00\x01' * 4) self.assertTrue(self.conn.channel.gotOpen) - self.assertEquals(self.conn.channel.conn, self.conn) - self.assertEquals(self.conn.channel.data, '\x00\x00\x00\x01') - self.assertEquals(self.conn.channel.specificData, '\x00\x00\x00\x01') - self.assertEquals(self.conn.channel.remoteWindowLeft, 1) - self.assertEquals(self.conn.channel.remoteMaxPacket, 1) - self.assertEquals(self.transport.packets, + self.assertEqual(self.conn.channel.conn, self.conn) + self.assertEqual(self.conn.channel.data, '\x00\x00\x00\x01') + self.assertEqual(self.conn.channel.specificData, '\x00\x00\x00\x01') + self.assertEqual(self.conn.channel.remoteWindowLeft, 1) + self.assertEqual(self.conn.channel.remoteMaxPacket, 1) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_OPEN_CONFIRMATION, '\x00\x00\x00\x01\x00\x00\x00\x00\x00\x02\x00\x00' '\x00\x00\x80\x00')]) @@ -298,7 +298,7 @@ self.conn.ssh_CHANNEL_OPEN(common.NS('BadChannel') + '\x00\x00\x00\x02' * 4) self.flushLoggedErrors() - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_OPEN_FAILURE, '\x00\x00\x00\x02\x00\x00\x00\x03' + common.NS( 'unknown channel') + common.NS(''))]) @@ -306,7 +306,7 @@ self.conn.ssh_CHANNEL_OPEN(common.NS('ErrorChannel') + '\x00\x00\x00\x02' * 4) self.flushLoggedErrors() - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_OPEN_FAILURE, '\x00\x00\x00\x02\x00\x00\x00\x02' + common.NS( 'unknown failure') + common.NS(''))]) @@ -322,10 +322,10 @@ self.conn.ssh_CHANNEL_OPEN( common.NS('conch-error-args') + '\x00\x00\x00\x01' * 4) errors = self.flushLoggedErrors(error.ConchError) - self.assertEquals( + self.assertEqual( len(errors), 1, "Expected one error, got: %r" % (errors,)) - self.assertEquals(errors[0].value.args, (123, "error args in wrong order")) - self.assertEquals( + self.assertEqual(errors[0].value.args, (123, "error args in wrong order")) + self.assertEqual( self.transport.packets, [(connection.MSG_CHANNEL_OPEN_FAILURE, # The response includes some bytes which identifying the @@ -365,12 +365,12 @@ channel = TestChannel() self.conn.openChannel(channel) self.conn.ssh_CHANNEL_OPEN_CONFIRMATION('\x00\x00\x00\x00'*5) - self.assertEquals(channel.remoteWindowLeft, 0) - self.assertEquals(channel.remoteMaxPacket, 0) - self.assertEquals(channel.specificData, '\x00\x00\x00\x00') - self.assertEquals(self.conn.channelsToRemoteChannel[channel], + self.assertEqual(channel.remoteWindowLeft, 0) + self.assertEqual(channel.remoteMaxPacket, 0) + self.assertEqual(channel.specificData, '\x00\x00\x00\x00') + self.assertEqual(self.conn.channelsToRemoteChannel[channel], 0) - self.assertEquals(self.conn.localToRemoteChannel[0], 0) + self.assertEqual(self.conn.localToRemoteChannel[0], 0) def test_CHANNEL_OPEN_FAILURE(self): """ @@ -381,8 +381,8 @@ self.conn.openChannel(channel) self.conn.ssh_CHANNEL_OPEN_FAILURE('\x00\x00\x00\x00\x00\x00\x00' '\x01' + common.NS('failure!')) - self.assertEquals(channel.openFailureReason.args, ('failure!', 1)) - self.assertEquals(self.conn.channels.get(channel), None) + self.assertEqual(channel.openFailureReason.args, ('failure!', 1)) + self.assertEqual(self.conn.channels.get(channel), None) def test_CHANNEL_WINDOW_ADJUST(self): @@ -395,7 +395,7 @@ oldWindowSize = channel.remoteWindowLeft self.conn.ssh_CHANNEL_WINDOW_ADJUST('\x00\x00\x00\x00\x00\x00\x00' '\x01') - self.assertEquals(channel.remoteWindowLeft, oldWindowSize + 1) + self.assertEqual(channel.remoteWindowLeft, oldWindowSize + 1) def test_CHANNEL_DATA(self): """ @@ -405,23 +405,23 @@ channel = TestChannel(localWindow=6, localMaxPacket=5) self._openChannel(channel) self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x00' + common.NS('data')) - self.assertEquals(channel.inBuffer, ['data']) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.inBuffer, ['data']) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' '\x00\x00\x00\x04')]) self.transport.packets = [] longData = 'a' * (channel.localWindowLeft + 1) self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x00' + common.NS(longData)) - self.assertEquals(channel.inBuffer, ['data']) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.inBuffer, ['data']) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) channel = TestChannel() self._openChannel(channel) bigData = 'a' * (channel.localMaxPacket + 1) self.transport.packets = [] self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x01' + common.NS(bigData)) - self.assertEquals(channel.inBuffer, []) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.inBuffer, []) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) def test_CHANNEL_EXTENDED_DATA(self): @@ -433,16 +433,16 @@ self._openChannel(channel) self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x00\x00\x00\x00' '\x00' + common.NS('data')) - self.assertEquals(channel.extBuffer, [(0, 'data')]) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.extBuffer, [(0, 'data')]) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' '\x00\x00\x00\x04')]) self.transport.packets = [] longData = 'a' * (channel.localWindowLeft + 1) self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x00\x00\x00\x00' '\x00' + common.NS(longData)) - self.assertEquals(channel.extBuffer, [(0, 'data')]) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.extBuffer, [(0, 'data')]) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) channel = TestChannel() self._openChannel(channel) @@ -450,8 +450,8 @@ self.transport.packets = [] self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x01\x00\x00\x00' '\x00' + common.NS(bigData)) - self.assertEquals(channel.extBuffer, []) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.extBuffer, []) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) def test_CHANNEL_EOF(self): @@ -484,11 +484,11 @@ self._openChannel(channel) self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS('test') + '\x00') - self.assertEquals(channel.numberRequests, 1) + self.assertEqual(channel.numberRequests, 1) d = self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS( 'test') + '\xff' + 'data') def check(result): - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_SUCCESS, '\x00\x00\x00\xff')]) d.addCallback(check) return d @@ -502,7 +502,7 @@ d = self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS( 'test') + '\xff') def check(result): - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_FAILURE, '\x00\x00\x00\xff' )]) d.addCallback(self.fail) @@ -532,7 +532,7 @@ d = self.conn.sendRequest(channel, 'test', '', True) self.conn.ssh_CHANNEL_FAILURE('\x00\x00\x00\x00') def check(result): - self.assertEquals(result.value.value, 'channel request failed') + self.assertEqual(result.value.value, 'channel request failed') d.addCallback(self.fail) d.addErrback(check) return d @@ -545,12 +545,12 @@ # must be added to prevent errbacking during teardown d.addErrback(lambda failure: None) self.conn.sendGlobalRequest('noReply', '', False) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_GLOBAL_REQUEST, common.NS('wantReply') + '\xffdata'), (connection.MSG_GLOBAL_REQUEST, common.NS('noReply') + '\x00')]) - self.assertEquals(self.conn.deferreds, {'global':[d]}) + self.assertEqual(self.conn.deferreds, {'global':[d]}) def test_openChannel(self): """ @@ -558,11 +558,11 @@ """ channel = TestChannel() self.conn.openChannel(channel, 'aaaa') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_OPEN, common.NS('TestChannel') + '\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x80\x00aaaa')]) - self.assertEquals(channel.id, 0) - self.assertEquals(self.conn.localChannelID, 1) + self.assertEqual(channel.id, 0) + self.assertEqual(self.conn.localChannelID, 1) def test_sendRequest(self): """ @@ -576,12 +576,12 @@ self.conn.sendRequest(channel, 'test2', '', False) channel.localClosed = True # emulate sending a close message self.conn.sendRequest(channel, 'test3', '', True) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_REQUEST, '\x00\x00\x00\xff' + common.NS('test') + '\x01test'), (connection.MSG_CHANNEL_REQUEST, '\x00\x00\x00\xff' + common.NS('test2') + '\x00')]) - self.assertEquals(self.conn.deferreds[0], [d]) + self.assertEqual(self.conn.deferreds[0], [d]) def test_adjustWindow(self): """ @@ -592,11 +592,11 @@ self._openChannel(channel) channel.localWindowLeft = 0 self.conn.adjustWindow(channel, 1) - self.assertEquals(channel.localWindowLeft, 1) + self.assertEqual(channel.localWindowLeft, 1) channel.localClosed = True self.conn.adjustWindow(channel, 2) - self.assertEquals(channel.localWindowLeft, 1) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.localWindowLeft, 1) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' '\x00\x00\x00\x01')]) @@ -609,7 +609,7 @@ self.conn.sendData(channel, 'a') channel.localClosed = True self.conn.sendData(channel, 'b') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_DATA, '\x00\x00\x00\xff' + common.NS('a'))]) @@ -622,7 +622,7 @@ self.conn.sendExtendedData(channel, 1, 'test') channel.localClosed = True self.conn.sendExtendedData(channel, 2, 'test2') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_EXTENDED_DATA, '\x00\x00\x00\xff' + '\x00\x00\x00\x01' + common.NS('test'))]) @@ -633,11 +633,11 @@ channel = TestChannel() self._openChannel(channel) self.conn.sendEOF(channel) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_EOF, '\x00\x00\x00\xff')]) channel.localClosed = True self.conn.sendEOF(channel) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_EOF, '\x00\x00\x00\xff')]) def test_sendClose(self): @@ -648,10 +648,10 @@ self._openChannel(channel) self.conn.sendClose(channel) self.assertTrue(channel.localClosed) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) self.conn.sendClose(channel) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) channel2 = TestChannel() @@ -667,9 +667,9 @@ test_CHANNEL_OPEN. """ channel = self.conn.getChannel('TestChannel', 50, 30, 'data') - self.assertEquals(channel.data, 'data') - self.assertEquals(channel.remoteWindowLeft, 50) - self.assertEquals(channel.remoteMaxPacket, 30) + self.assertEqual(channel.data, 'data') + self.assertEqual(channel.remoteWindowLeft, 50) + self.assertEqual(channel.remoteMaxPacket, 30) self.assertRaises(error.ConchError, self.conn.getChannel, 'BadChannel', 50, 30, 'data') @@ -679,7 +679,7 @@ """ del self.transport.avatar self.assertTrue(self.conn.gotGlobalRequest('TestGlobal', 'data')) - self.assertEquals(self.conn.gotGlobalRequest('Test-Data', 'data'), + self.assertEqual(self.conn.gotGlobalRequest('Test-Data', 'data'), (True, 'data')) self.assertFalse(self.conn.gotGlobalRequest('BadGlobal', 'data')) diff --git a/lib/twisted-trunk/twisted/conch/test/test_default.py b/lib/twisted-trunk/twisted/conch/test/test_default.py --- a/lib/twisted-trunk/twisted/conch/test/test_default.py +++ b/lib/twisted-trunk/twisted/conch/test/test_default.py @@ -52,7 +52,7 @@ client.keyAgent = agent cleartext = "Sign here" client.signData(self.rsaPublic, cleartext) - self.assertEquals( + self.assertEqual( transport.value(), "\x00\x00\x00\x8b\r\x00\x00\x00u" + self.rsaPublic.blob() + "\x00\x00\x00\t" + cleartext + @@ -69,9 +69,9 @@ agent = SSHAgentClient() agent.blobs = [self.rsaPublic.blob()] key = agent.getPublicKey() - self.assertEquals(key.isPublic(), True) - self.assertEquals(key, self.rsaPublic) - self.assertEquals(agent.getPublicKey(), None) + self.assertEqual(key.isPublic(), True) + self.assertEqual(key, self.rsaPublic) + self.assertEqual(agent.getPublicKey(), None) def test_getPublicKeyFromFile(self): @@ -84,8 +84,8 @@ options.identitys = [self.rsaFile.path] client = SSHUserAuthClient("user", options, None) key = client.getPublicKey() - self.assertEquals(key.isPublic(), True) - self.assertEquals(key, self.rsaPublic) + self.assertEqual(key.isPublic(), True) + self.assertEqual(key, self.rsaPublic) def test_getPublicKeyAgentFallback(self): @@ -99,8 +99,8 @@ client = SSHUserAuthClient("user", options, None) client.keyAgent = agent key = client.getPublicKey() - self.assertEquals(key.isPublic(), True) - self.assertEquals(key, self.rsaPublic) + self.assertEqual(key.isPublic(), True) + self.assertEqual(key, self.rsaPublic) def test_getPublicKeyBadKeyError(self): @@ -117,9 +117,9 @@ self.tmpdir.child('id_rsa.pub').setContent('not a key!') client = SSHUserAuthClient("user", options, None) key = client.getPublicKey() - self.assertEquals(key.isPublic(), True) - self.assertEquals(key, Key.fromString(keydata.publicDSA_openssh)) - self.assertEquals(client.usedFiles, [self.rsaFile.path, dsaFile.path]) + self.assertEqual(key.isPublic(), True) + self.assertEqual(key, Key.fromString(keydata.publicDSA_openssh)) + self.assertEqual(client.usedFiles, [self.rsaFile.path, dsaFile.path]) def test_getPrivateKey(self): @@ -136,8 +136,8 @@ client.getPublicKey() def _cbGetPrivateKey(key): - self.assertEquals(key.isPublic(), False) - self.assertEquals(key, rsaPrivate) + self.assertEqual(key.isPublic(), False) + self.assertEqual(key, rsaPrivate) return client.getPrivateKey().addCallback(_cbGetPrivateKey) @@ -158,14 +158,14 @@ client.getPublicKey() def _getPassword(prompt): - self.assertEquals(prompt, + self.assertEqual(prompt, "Enter passphrase for key '%s': " % ( self.rsaFile.path,)) return passphrase def _cbGetPrivateKey(key): - self.assertEquals(key.isPublic(), False) - self.assertEquals(key, rsaPrivate) + self.assertEqual(key.isPublic(), False) + self.assertEqual(key, rsaPrivate) self.patch(client, '_getPassword', _getPassword) return client.getPrivateKey().addCallback(_cbGetPrivateKey) diff --git a/lib/twisted-trunk/twisted/conch/test/test_filetransfer.py b/lib/twisted-trunk/twisted/conch/test/test_filetransfer.py --- a/lib/twisted-trunk/twisted/conch/test/test_filetransfer.py +++ b/lib/twisted-trunk/twisted/conch/test/test_filetransfer.py @@ -147,8 +147,8 @@ def testServerVersion(self): - self.failUnlessEqual(self._serverVersion, 3) - self.failUnlessEqual(self._extData, {'conchTest' : 'ext data'}) + self.assertEqual(self._serverVersion, 3) + self.assertEqual(self._extData, {'conchTest' : 'ext data'}) def test_openedFileClosedWithConnection(self): @@ -173,7 +173,7 @@ self.clientTransport.loseConnection() self.serverTransport.clearBuffer() self.clientTransport.clearBuffer() - self.assertEquals(self.server.openFiles, {}) + self.assertEqual(self.server.openFiles, {}) self.assertIn(fd, closed) d.addCallback(_fileOpened) @@ -193,7 +193,7 @@ self.clientTransport.loseConnection() self.serverTransport.clearBuffer() self.clientTransport.clearBuffer() - self.assertEquals(self.server.openDirs, {}) + self.assertEqual(self.server.openDirs, {}) d.addCallback(_getFiles) return d @@ -205,7 +205,7 @@ self._emptyBuffers() def _fileOpened(openFile): - self.failUnlessEqual(openFile, filetransfer.ISFTPFile(openFile)) + self.assertEqual(openFile, filetransfer.ISFTPFile(openFile)) d = _readChunk(openFile) d.addCallback(_writeChunk, openFile) return d @@ -213,7 +213,7 @@ def _readChunk(openFile): d = openFile.readChunk(0, 20) self._emptyBuffers() - d.addCallback(self.failUnlessEqual, 'a'*10 + 'b'*10) + d.addCallback(self.assertEqual, 'a'*10 + 'b'*10) return d def _writeChunk(_, openFile): @@ -225,7 +225,7 @@ def _readChunk2(_, openFile): d = openFile.readChunk(0, 30) self._emptyBuffers() - d.addCallback(self.failUnlessEqual, 'a'*10 + 'b'*10 + 'c'*10) + d.addCallback(self.assertEqual, 'a'*10 + 'b'*10 + 'c'*10) return d d.addCallback(_fileOpened) @@ -269,7 +269,7 @@ def _getAttrs2(attrs1): d = self.client.getAttrs('testfile1') self._emptyBuffers() - d.addCallback(self.failUnlessEqual, attrs1) + d.addCallback(self.assertEqual, attrs1) return d return d.addCallback(_getAttrs) @@ -293,7 +293,7 @@ d = self.client.setAttrs('testfile1', attrs) self._emptyBuffers() d.addCallback(_getAttrs2) - d.addCallback(self.failUnlessEqual, attrs) + d.addCallback(self.assertEqual, attrs) return d def _getAttrs2(_): @@ -323,7 +323,7 @@ self._emptyBuffers() def check(ign): - self.assertEquals(savedAttributes, {"ext_foo": "bar"}) + self.assertEqual(savedAttributes, {"ext_foo": "bar"}) return d.addCallback(check) @@ -350,7 +350,7 @@ def _testRenamed(_, attrs): d = self.client.getAttrs("testRenamedFile") self._emptyBuffers() - d.addCallback(self.failUnlessEqual, attrs) + d.addCallback(self.assertEqual, attrs) return d.addCallback(_rename) def testDirectoryBad(self): @@ -368,7 +368,7 @@ return d # XXX not until version 4/5 - # self.failUnlessEqual(filetransfer.FILEXFER_TYPE_DIRECTORY&attrs['type'], + # self.assertEqual(filetransfer.FILEXFER_TYPE_DIRECTORY&attrs['type'], # filetransfer.FILEXFER_TYPE_DIRECTORY) def _removeDirectory(_): @@ -400,7 +400,7 @@ def _checkFiles(ignored): fs = list(zip(*files)[0]) fs.sort() - self.failUnlessEqual(fs, + self.assertEqual(fs, ['.testHiddenFile', 'testDirectory', 'testRemoveFile', 'testRenameFile', 'testfile1']) @@ -440,13 +440,13 @@ def _readLink(_): d = self.client.readLink('testLink') self._emptyBuffers() - d.addCallback(self.failUnlessEqual, + d.addCallback(self.assertEqual, os.path.join(os.getcwd(), self.testDir, 'testfile1')) return d def _realPath(_): d = self.client.realPath('testLink') self._emptyBuffers() - d.addCallback(self.failUnlessEqual, + d.addCallback(self.assertEqual, os.path.join(os.getcwd(), self.testDir, 'testfile1')) return d d.addCallback(_readLink) @@ -456,7 +456,7 @@ def testExtendedRequest(self): d = self.client.extendedRequest('testExtendedRequest', 'foo') self._emptyBuffers() - d.addCallback(self.failUnlessEqual, 'bar') + d.addCallback(self.assertEqual, 'bar') d.addCallback(self._cbTestExtendedRequest) return d diff --git a/lib/twisted-trunk/twisted/conch/test/test_helper.py b/lib/twisted-trunk/twisted/conch/test/test_helper.py --- a/lib/twisted-trunk/twisted/conch/test/test_helper.py +++ b/lib/twisted-trunk/twisted/conch/test/test_helper.py @@ -18,11 +18,11 @@ self.term.connectionMade() def testInitialState(self): - self.assertEquals(self.term.width, WIDTH) - self.assertEquals(self.term.height, HEIGHT) - self.assertEquals(str(self.term), + self.assertEqual(self.term.width, WIDTH) + self.assertEqual(self.term.height, HEIGHT) + self.assertEqual(str(self.term), '\n' * (HEIGHT - 1)) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) def test_initialPrivateModes(self): @@ -94,50 +94,50 @@ def testCursorDown(self): self.term.cursorDown(3) - self.assertEquals(self.term.reportCursorPosition(), (0, 3)) + self.assertEqual(self.term.reportCursorPosition(), (0, 3)) self.term.cursorDown() - self.assertEquals(self.term.reportCursorPosition(), (0, 4)) + self.assertEqual(self.term.reportCursorPosition(), (0, 4)) self.term.cursorDown(HEIGHT) - self.assertEquals(self.term.reportCursorPosition(), (0, HEIGHT - 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1)) def testCursorUp(self): self.term.cursorUp(5) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) self.term.cursorDown(20) self.term.cursorUp(1) - self.assertEquals(self.term.reportCursorPosition(), (0, 19)) + self.assertEqual(self.term.reportCursorPosition(), (0, 19)) self.term.cursorUp(19) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) def testCursorForward(self): self.term.cursorForward(2) - self.assertEquals(self.term.reportCursorPosition(), (2, 0)) + self.assertEqual(self.term.reportCursorPosition(), (2, 0)) self.term.cursorForward(2) - self.assertEquals(self.term.reportCursorPosition(), (4, 0)) + self.assertEqual(self.term.reportCursorPosition(), (4, 0)) self.term.cursorForward(WIDTH) - self.assertEquals(self.term.reportCursorPosition(), (WIDTH, 0)) + self.assertEqual(self.term.reportCursorPosition(), (WIDTH, 0)) def testCursorBackward(self): self.term.cursorForward(10) self.term.cursorBackward(2) - self.assertEquals(self.term.reportCursorPosition(), (8, 0)) + self.assertEqual(self.term.reportCursorPosition(), (8, 0)) self.term.cursorBackward(7) - self.assertEquals(self.term.reportCursorPosition(), (1, 0)) + self.assertEqual(self.term.reportCursorPosition(), (1, 0)) self.term.cursorBackward(1) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) self.term.cursorBackward(1) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) def testCursorPositioning(self): self.term.cursorPosition(3, 9) - self.assertEquals(self.term.reportCursorPosition(), (3, 9)) + self.assertEqual(self.term.reportCursorPosition(), (3, 9)) def testSimpleWriting(self): s = "Hello, world." self.term.write(s) - self.assertEquals( + self.assertEqual( str(self.term), s + '\n' + '\n' * (HEIGHT - 2)) @@ -148,7 +148,7 @@ self.term.cursorBackward(len(s)) self.term.resetModes([modes.IRM]) self.term.write("H") - self.assertEquals( + self.assertEqual( str(self.term), ("H" + s[1:]) + '\n' + '\n' * (HEIGHT - 2)) @@ -159,7 +159,7 @@ self.term.cursorBackward(len(s)) self.term.setModes([modes.IRM]) self.term.write("H") - self.assertEquals( + self.assertEqual( str(self.term), ("H" + s) + '\n' + '\n' * (HEIGHT - 2)) @@ -169,7 +169,7 @@ self.term.cursorDown(5) self.term.cursorForward(5) self.term.write(s) - self.assertEquals( + self.assertEqual( str(self.term), '\n' * 5 + (self.term.fill * 5) + s + '\n' + @@ -179,7 +179,7 @@ s = "Hello, world." self.term.cursorForward(WIDTH - 5) self.term.write(s) - self.assertEquals( + self.assertEqual( str(self.term), s[:5].rjust(WIDTH) + '\n' + s[5:] + '\n' + @@ -187,19 +187,19 @@ def testIndex(self): self.term.index() - self.assertEquals(self.term.reportCursorPosition(), (0, 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, 1)) self.term.cursorDown(HEIGHT) - self.assertEquals(self.term.reportCursorPosition(), (0, HEIGHT - 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1)) self.term.index() - self.assertEquals(self.term.reportCursorPosition(), (0, HEIGHT - 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1)) def testReverseIndex(self): self.term.reverseIndex() - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) self.term.cursorDown(2) - self.assertEquals(self.term.reportCursorPosition(), (0, 2)) + self.assertEqual(self.term.reportCursorPosition(), (0, 2)) self.term.reverseIndex() - self.assertEquals(self.term.reportCursorPosition(), (0, 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, 1)) def test_nextLine(self): """ @@ -207,45 +207,45 @@ current row. """ self.term.nextLine() - self.assertEquals(self.term.reportCursorPosition(), (0, 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, 1)) self.term.cursorForward(5) - self.assertEquals(self.term.reportCursorPosition(), (5, 1)) + self.assertEqual(self.term.reportCursorPosition(), (5, 1)) self.term.nextLine() - self.assertEquals(self.term.reportCursorPosition(), (0, 2)) + self.assertEqual(self.term.reportCursorPosition(), (0, 2)) def testSaveCursor(self): self.term.cursorDown(5) self.term.cursorForward(7) - self.assertEquals(self.term.reportCursorPosition(), (7, 5)) + self.assertEqual(self.term.reportCursorPosition(), (7, 5)) self.term.saveCursor() self.term.cursorDown(7) self.term.cursorBackward(3) - self.assertEquals(self.term.reportCursorPosition(), (4, 12)) + self.assertEqual(self.term.reportCursorPosition(), (4, 12)) self.term.restoreCursor() - self.assertEquals(self.term.reportCursorPosition(), (7, 5)) + self.assertEqual(self.term.reportCursorPosition(), (7, 5)) def testSingleShifts(self): self.term.singleShift2() self.term.write('Hi') ch = self.term.getCharacter(0, 0) - self.assertEquals(ch[0], 'H') - self.assertEquals(ch[1].charset, G2) + self.assertEqual(ch[0], 'H') + self.assertEqual(ch[1].charset, G2) ch = self.term.getCharacter(1, 0) - self.assertEquals(ch[0], 'i') - self.assertEquals(ch[1].charset, G0) + self.assertEqual(ch[0], 'i') + self.assertEqual(ch[1].charset, G0) self.term.singleShift3() self.term.write('!!') ch = self.term.getCharacter(2, 0) - self.assertEquals(ch[0], '!') - self.assertEquals(ch[1].charset, G3) + self.assertEqual(ch[0], '!') + self.assertEqual(ch[1].charset, G3) ch = self.term.getCharacter(3, 0) - self.assertEquals(ch[0], '!') - self.assertEquals(ch[1].charset, G0) + self.assertEqual(ch[0], '!') + self.assertEqual(ch[1].charset, G0) def testShifting(self): s1 = "Hello" @@ -262,8 +262,8 @@ for s in (s1, s2, s3): for i in range(len(s)): ch = self.term.getCharacter(i, h) - self.assertEquals(ch[0], s[i]) - self.assertEquals(ch[1].charset, g) + self.assertEqual(ch[0], s[i]) + self.assertEqual(ch[1].charset, g) g = g == G0 and G1 or G0 h += 1 @@ -278,28 +278,28 @@ self.term.write('Z') ch = self.term.getCharacter(0, 0) - self.assertEquals(ch[0], 'W') + self.assertEqual(ch[0], 'W') self.failUnless(ch[1].bold) self.failUnless(ch[1].underline) self.failUnless(ch[1].blink) self.failUnless(ch[1].reverseVideo) ch = self.term.getCharacter(1, 0) - self.assertEquals(ch[0], 'X') + self.assertEqual(ch[0], 'X') self.failIf(ch[1].bold) self.failIf(ch[1].underline) self.failIf(ch[1].blink) self.failIf(ch[1].reverseVideo) ch = self.term.getCharacter(2, 0) - self.assertEquals(ch[0], 'Y') + self.assertEqual(ch[0], 'Y') self.failUnless(ch[1].blink) self.failIf(ch[1].bold) self.failIf(ch[1].underline) self.failIf(ch[1].reverseVideo) ch = self.term.getCharacter(3, 0) - self.assertEquals(ch[0], 'Z') + self.assertEqual(ch[0], 'Z') self.failUnless(ch[1].blink) self.failUnless(ch[1].bold) self.failIf(ch[1].underline) @@ -316,25 +316,25 @@ for i in range(len(s1)): ch = self.term.getCharacter(i, 0) - self.assertEquals(ch[0], s1[i]) - self.assertEquals(ch[1].charset, G0) - self.assertEquals(ch[1].bold, False) - self.assertEquals(ch[1].underline, False) - self.assertEquals(ch[1].blink, False) - self.assertEquals(ch[1].reverseVideo, False) - self.assertEquals(ch[1].foreground, helper.RED) - self.assertEquals(ch[1].background, helper.GREEN) + self.assertEqual(ch[0], s1[i]) + self.assertEqual(ch[1].charset, G0) + self.assertEqual(ch[1].bold, False) + self.assertEqual(ch[1].underline, False) + self.assertEqual(ch[1].blink, False) + self.assertEqual(ch[1].reverseVideo, False) + self.assertEqual(ch[1].foreground, helper.RED) + self.assertEqual(ch[1].background, helper.GREEN) for i in range(len(s2)): ch = self.term.getCharacter(i, 1) - self.assertEquals(ch[0], s2[i]) - self.assertEquals(ch[1].charset, G0) - self.assertEquals(ch[1].bold, False) - self.assertEquals(ch[1].underline, False) - self.assertEquals(ch[1].blink, False) - self.assertEquals(ch[1].reverseVideo, False) - self.assertEquals(ch[1].foreground, helper.WHITE) - self.assertEquals(ch[1].background, helper.BLACK) + self.assertEqual(ch[0], s2[i]) + self.assertEqual(ch[1].charset, G0) + self.assertEqual(ch[1].bold, False) + self.assertEqual(ch[1].underline, False) + self.assertEqual(ch[1].blink, False) + self.assertEqual(ch[1].reverseVideo, False) + self.assertEqual(ch[1].foreground, helper.WHITE) + self.assertEqual(ch[1].background, helper.BLACK) def testEraseLine(self): s1 = 'line 1' @@ -344,7 +344,7 @@ self.term.cursorPosition(1, 1) self.term.eraseLine() - self.assertEquals( + self.assertEqual( str(self.term), s1 + '\n' + '\n' + @@ -356,7 +356,7 @@ self.term.write(s) self.term.cursorBackward(5) self.term.eraseToLineEnd() - self.assertEquals( + self.assertEqual( str(self.term), s[:-5] + '\n' + '\n' * (HEIGHT - 2)) @@ -366,7 +366,7 @@ self.term.write(s) self.term.cursorBackward(5) self.term.eraseToLineBeginning() - self.assertEquals( + self.assertEqual( str(self.term), s[-4:].rjust(len(s)) + '\n' + '\n' * (HEIGHT - 2)) @@ -376,7 +376,7 @@ self.term.write('Goodbye world\n') self.term.eraseDisplay() - self.assertEquals( + self.assertEqual( str(self.term), '\n' * (HEIGHT - 1)) @@ -387,7 +387,7 @@ self.term.cursorPosition(5, 1) self.term.eraseToDisplayEnd() - self.assertEquals( + self.assertEqual( str(self.term), s1 + '\n' + s2[:5] + '\n' + @@ -400,7 +400,7 @@ self.term.cursorPosition(5, 1) self.term.eraseToDisplayBeginning() - self.assertEquals( + self.assertEqual( str(self.term), '\n' + s2[6:].rjust(len(s2)) + '\n' + @@ -413,7 +413,7 @@ self.term.cursorPosition(7, 1) self.term.insertLine() - self.assertEquals( + self.assertEqual( str(self.term), s1 + '\n' + '\n' + @@ -428,7 +428,7 @@ self.term.cursorPosition(9, 1) self.term.deleteLine() - self.assertEquals( + self.assertEqual( str(self.term), s1 + '\n' + s3 + '\n' + @@ -478,8 +478,8 @@ self.failIf(result) self.term.write("hello world\n") self.failUnless(result) - self.assertEquals(result[0].group(), "hello world") - self.assertEquals(len(self.fs.calls), 1) + self.assertEqual(result[0].group(), "hello world") + self.assertEqual(len(self.fs.calls), 1) self.failIf(self.fs.calls[0].active()) def testBrokenUpString(self): @@ -494,7 +494,7 @@ self.failIf(result) self.term.write("d") self.failUnless(result) - self.assertEquals(result[0].group(), "hello world") + self.assertEqual(result[0].group(), "hello world") def testMultiple(self): @@ -508,11 +508,11 @@ self.term.write("hello") self.failIf(result) self.term.write(" ") - self.assertEquals(len(result), 1) + self.assertEqual(len(result), 1) self.term.write("world") - self.assertEquals(len(result), 2) - self.assertEquals(result[0].group(), "hello ") - self.assertEquals(result[1].group(), "world") + self.assertEqual(len(result), 2) + self.assertEqual(result[0].group(), "hello ") + self.assertEqual(result[1].group(), "world") def testSynchronous(self): self.term.write("hello world") @@ -521,7 +521,7 @@ d = self.term.expect("hello world") d.addCallback(result.append) self.failUnless(result) - self.assertEquals(result[0].group(), "hello world") + self.assertEqual(result[0].group(), "hello world") def testMultipleSynchronous(self): self.term.write("goodbye world") @@ -532,9 +532,9 @@ d2 = self.term.expect("world") d2.addCallback(result.append) - self.assertEquals(len(result), 2) - self.assertEquals(result[0].group(), "bye") - self.assertEquals(result[1].group(), "world") + self.assertEqual(len(result), 2) + self.assertEqual(result[0].group(), "bye") + self.assertEqual(result[1].group(), "world") def _cbTestTimeoutFailure(self, res): self.assert_(hasattr(res, 'type')) @@ -556,5 +556,5 @@ self.fs.calls[0].call() - self.assertEquals(len(result), 1) - self.assertEquals(result[0].group(), "zoom") + self.assertEqual(len(result), 1) + self.assertEqual(result[0].group(), "zoom") diff --git a/lib/twisted-trunk/twisted/conch/test/test_insults.py b/lib/twisted-trunk/twisted/conch/test/test_insults.py --- a/lib/twisted-trunk/twisted/conch/test/test_insults.py +++ b/lib/twisted-trunk/twisted/conch/test/test_insults.py @@ -61,12 +61,12 @@ def assertCall(self, occurrence, methodName, expectedPositionalArgs=(), expectedKeywordArgs={}): attr, mock = occurrence - self.assertEquals(attr, methodName) - self.assertEquals(len(occurrences(mock)), 1) + self.assertEqual(attr, methodName) + self.assertEqual(len(occurrences(mock)), 1) [(call, result, args, kw)] = occurrences(mock) - self.assertEquals(call, "__call__") - self.assertEquals(args, expectedPositionalArgs) - self.assertEquals(kw, expectedKeywordArgs) + self.assertEqual(call, "__call__") + self.assertEqual(args, expectedPositionalArgs) + self.assertEqual(kw, expectedKeywordArgs) return result @@ -95,7 +95,7 @@ def verifyResults(self, transport, proto, parser): result = self.assertCall(occurrences(proto).pop(0), "makeConnection", (parser,)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) del _byteGroupingTestTemplate @@ -111,7 +111,7 @@ for arrow in (parser.UP_ARROW, parser.DOWN_ARROW, parser.RIGHT_ARROW, parser.LEFT_ARROW): result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (arrow, None)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) self.failIf(occurrences(proto)) @@ -128,11 +128,11 @@ for char in 'abc123ABC!@#': result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (char, None)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) for char in 'abc123': result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (char, parser.ALT)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) occs = occurrences(proto) self.failIf(occs, "%r should have been []" % (occs,)) @@ -155,7 +155,7 @@ for funcNum in range(1, 13): funcArg = getattr(parser, 'F%d' % (funcNum,)) result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (funcArg, None)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) self.failIf(occurrences(proto)) class ClientCursorMovement(ByteGroupingsMixin, unittest.TestCase): @@ -175,7 +175,7 @@ for (method, count) in [('Down', 2), ('Forward', 4), ('Up', 1), ('Backward', 2), ('Up', 1), ('Backward', 2)]: result = self.assertCall(occurrences(proto).pop(0), "cursor" + method, (count,)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) self.failIf(occurrences(proto)) class ClientControlSequences(unittest.TestCase, MockMixin): @@ -354,13 +354,13 @@ def testCursorPosition(self): methods(self.proto)['reportCursorPosition'] = (6, 7) self.parser.dataReceived("\x1b[6n") - self.assertEquals(self.transport.value(), "\x1b[7;8R") + self.assertEqual(self.transport.value(), "\x1b[7;8R") occs = occurrences(self.proto) result = self.assertCall(occs.pop(0), "reportCursorPosition") # This isn't really an interesting assert, since it only tests that # our mock setup is working right, but I'll include it anyway. - self.assertEquals(result, (6, 7)) + self.assertEqual(result, (6, 7)) def test_applicationDataBytes(self): @@ -472,8 +472,8 @@ """ warnings = self.flushWarnings() self.assertIdentical(warnings[0]['category'], DeprecationWarning) - self.assertEquals(warnings[0]['message'], message) - self.assertEquals(len(warnings), 1) + self.assertEqual(warnings[0]['message'], message) + self.assertEqual(len(warnings), 1) def test_colors(self): diff --git a/lib/twisted-trunk/twisted/conch/test/test_keys.py b/lib/twisted-trunk/twisted/conch/test/test_keys.py --- a/lib/twisted-trunk/twisted/conch/test/test_keys.py +++ b/lib/twisted-trunk/twisted/conch/test/test_keys.py @@ -47,11 +47,11 @@ """ data = 'ABC' messageSize = 6 - self.assertEquals(keys.pkcs1Pad(data, messageSize), + self.assertEqual(keys.pkcs1Pad(data, messageSize), '\x01\xff\x00ABC') hash = sha1().digest() messageSize = 40 - self.assertEquals(keys.pkcs1Digest('', messageSize), + self.assertEqual(keys.pkcs1Digest('', messageSize), '\x01\xff\xff\xff\x00' + keys.ID_SHA1 + hash) def _signRSA(self, data): @@ -72,7 +72,7 @@ key, sig = self._signRSA(data) sigData = keys.pkcs1Digest(data, keys.lenSig(key)) v = key.sign(sigData, '')[0] - self.assertEquals(sig, common.NS('ssh-rsa') + common.MP(v)) + self.assertEqual(sig, common.NS('ssh-rsa') + common.MP(v)) return key, sig def test_signDSA(self): @@ -83,7 +83,7 @@ key, sig = self._signDSA(data) sigData = sha1(data).digest() v = key.sign(sigData, '\x55' * 19) - self.assertEquals(sig, common.NS('ssh-dss') + common.NS( + self.assertEqual(sig, common.NS('ssh-dss') + common.NS( Crypto.Util.number.long_to_bytes(v[0], 20) + Crypto.Util.number.long_to_bytes(v[1], 20))) return key, sig @@ -93,9 +93,9 @@ """ Test that objectType, returns the correct type for objects. """ - self.assertEquals(keys.objectType(keys.Key.fromString( + self.assertEqual(keys.objectType(keys.Key.fromString( keydata.privateRSA_openssh).keyObject), 'ssh-rsa') - self.assertEquals(keys.objectType(keys.Key.fromString( + self.assertEqual(keys.objectType(keys.Key.fromString( keydata.privateDSA_openssh).keyObject), 'ssh-dss') self.assertRaises(keys.BadKeyError, keys.objectType, None) @@ -136,33 +136,33 @@ Test that the _guessStringType method guesses string types correctly. """ - self.assertEquals(keys.Key._guessStringType(keydata.publicRSA_openssh), + self.assertEqual(keys.Key._guessStringType(keydata.publicRSA_openssh), 'public_openssh') - self.assertEquals(keys.Key._guessStringType(keydata.publicDSA_openssh), + self.assertEqual(keys.Key._guessStringType(keydata.publicDSA_openssh), 'public_openssh') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( keydata.privateRSA_openssh), 'private_openssh') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( keydata.privateDSA_openssh), 'private_openssh') - self.assertEquals(keys.Key._guessStringType(keydata.publicRSA_lsh), + self.assertEqual(keys.Key._guessStringType(keydata.publicRSA_lsh), 'public_lsh') - self.assertEquals(keys.Key._guessStringType(keydata.publicDSA_lsh), + self.assertEqual(keys.Key._guessStringType(keydata.publicDSA_lsh), 'public_lsh') - self.assertEquals(keys.Key._guessStringType(keydata.privateRSA_lsh), + self.assertEqual(keys.Key._guessStringType(keydata.privateRSA_lsh), 'private_lsh') - self.assertEquals(keys.Key._guessStringType(keydata.privateDSA_lsh), + self.assertEqual(keys.Key._guessStringType(keydata.privateDSA_lsh), 'private_lsh') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( keydata.privateRSA_agentv3), 'agentv3') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( keydata.privateDSA_agentv3), 'agentv3') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( '\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01\x01'), 'blob') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( '\x00\x00\x00\x07ssh-dss\x00\x00\x00\x01\x01'), 'blob') - self.assertEquals(keys.Key._guessStringType('not a key'), + self.assertEqual(keys.Key._guessStringType('not a key'), None) def _testPublicPrivateFromString(self, public, private, type, data): @@ -172,16 +172,16 @@ def _testPublicFromString(self, public, type, data): publicKey = keys.Key.fromString(public) self.assertTrue(publicKey.isPublic()) - self.assertEquals(publicKey.type(), type) + self.assertEqual(publicKey.type(), type) for k, v in publicKey.data().items(): - self.assertEquals(data[k], v) + self.assertEqual(data[k], v) def _testPrivateFromString(self, private, type, data): privateKey = keys.Key.fromString(private) self.assertFalse(privateKey.isPublic()) - self.assertEquals(privateKey.type(), type) + self.assertEqual(privateKey.type(), type) for k, v in data.items(): - self.assertEquals(privateKey.data()[k], v) + self.assertEqual(privateKey.data()[k], v) def test_fromOpenSSH(self): """ @@ -189,11 +189,11 @@ """ self._testPublicPrivateFromString(keydata.publicRSA_openssh, keydata.privateRSA_openssh, 'RSA', keydata.RSAData) - self.assertEquals(keys.Key.fromString( + self.assertEqual(keys.Key.fromString( keydata.privateRSA_openssh_encrypted, passphrase='encrypted'), keys.Key.fromString(keydata.privateRSA_openssh)) - self.assertEquals(keys.Key.fromString( + self.assertEqual(keys.Key.fromString( keydata.privateRSA_openssh_alternate), keys.Key.fromString(keydata.privateRSA_openssh)) self._testPublicPrivateFromString(keydata.publicDSA_openssh, @@ -217,7 +217,7 @@ /ow0IqSj0VF72VJN9uSoPpFd4lLT0zN8v42RWja0M8ohWNf+YNJluPgCFE0PT4Vm SUrCyZXsNh6VXwjs3gKQ -----END DSA PRIVATE KEY-----""" - self.assertEquals(keys.Key.fromString(privateDSAData), + self.assertEqual(keys.Key.fromString(privateDSAData), keys.Key.fromString(privateDSAData + '\n')) def test_fromLSH(self): @@ -268,7 +268,7 @@ """ Test that fromFile works correctly. """ - self.assertEquals(keys.Key.fromFile(self.keyFile), + self.assertEqual(keys.Key.fromFile(self.keyFile), keys.Key.fromString(keydata.privateRSA_lsh)) self.assertRaises(keys.BadKeyError, keys.Key.fromFile, self.keyFile, 'bad_type') @@ -281,7 +281,7 @@ """ obj = Crypto.PublicKey.RSA.construct((1L, 2L)) key = keys.Key(obj) - self.assertEquals(key.keyObject, obj) + self.assertEqual(key.keyObject, obj) def test_equal(self): """ @@ -315,10 +315,10 @@ """ Test that the type method returns the correct type for an object. """ - self.assertEquals(keys.Key(self.rsaObj).type(), 'RSA') - self.assertEquals(keys.Key(self.rsaObj).sshType(), 'ssh-rsa') - self.assertEquals(keys.Key(self.dsaObj).type(), 'DSA') - self.assertEquals(keys.Key(self.dsaObj).sshType(), 'ssh-dss') + self.assertEqual(keys.Key(self.rsaObj).type(), 'RSA') + self.assertEqual(keys.Key(self.rsaObj).sshType(), 'ssh-rsa') + self.assertEqual(keys.Key(self.dsaObj).type(), 'DSA') + self.assertEqual(keys.Key(self.dsaObj).sshType(), 'ssh-dss') self.assertRaises(RuntimeError, keys.Key(None).type) self.assertRaises(RuntimeError, keys.Key(None).sshType) self.assertRaises(RuntimeError, keys.Key(self).type) @@ -335,9 +335,9 @@ dsaKey = keys.Key.fromString(dsaBlob) badBlob = common.NS('ssh-bad') self.assertTrue(rsaKey.isPublic()) - self.assertEquals(rsaKey.data(), {'e':2L, 'n':3L}) + self.assertEqual(rsaKey.data(), {'e':2L, 'n':3L}) self.assertTrue(dsaKey.isPublic()) - self.assertEquals(dsaKey.data(), {'p':2L, 'q':3L, 'g':4L, 'y':5L}) + self.assertEqual(dsaKey.data(), {'p':2L, 'q':3L, 'g':4L, 'y':5L}) self.assertRaises(keys.BadKeyError, keys.Key.fromString, badBlob) @@ -366,10 +366,10 @@ """ Test that the Key object generates blobs correctly. """ - self.assertEquals(keys.Key(self.rsaObj).blob(), + self.assertEqual(keys.Key(self.rsaObj).blob(), '\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01\x02' '\x00\x00\x00\x01\x01') - self.assertEquals(keys.Key(self.dsaObj).blob(), + self.assertEqual(keys.Key(self.dsaObj).blob(), '\x00\x00\x00\x07ssh-dss\x00\x00\x00\x01\x03' '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x02' '\x00\x00\x00\x01\x01') @@ -383,12 +383,12 @@ L{Key.privateBlob} returns the SSH protocol-level format of the private key and raises L{RuntimeError} if the underlying key object is invalid. """ - self.assertEquals(keys.Key(self.rsaObj).privateBlob(), + self.assertEqual(keys.Key(self.rsaObj).privateBlob(), '\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01\x01' '\x00\x00\x00\x01\x02\x00\x00\x00\x01\x03\x00' '\x00\x00\x01\x04\x00\x00\x00\x01\x04\x00\x00' '\x00\x01\x05') - self.assertEquals(keys.Key(self.dsaObj).privateBlob(), + self.assertEqual(keys.Key(self.dsaObj).privateBlob(), '\x00\x00\x00\x07ssh-dss\x00\x00\x00\x01\x03' '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x02\x00' '\x00\x00\x01\x01\x00\x00\x00\x01\x05') @@ -402,18 +402,18 @@ Test that the Key object generates OpenSSH keys correctly. """ key = keys.Key.fromString(keydata.privateRSA_lsh) - self.assertEquals(key.toString('openssh'), keydata.privateRSA_openssh) - self.assertEquals(key.toString('openssh', 'encrypted'), + self.assertEqual(key.toString('openssh'), keydata.privateRSA_openssh) + self.assertEqual(key.toString('openssh', 'encrypted'), keydata.privateRSA_openssh_encrypted) - self.assertEquals(key.public().toString('openssh'), + self.assertEqual(key.public().toString('openssh'), keydata.publicRSA_openssh[:-8]) # no comment - self.assertEquals(key.public().toString('openssh', 'comment'), + self.assertEqual(key.public().toString('openssh', 'comment'), keydata.publicRSA_openssh) key = keys.Key.fromString(keydata.privateDSA_lsh) - self.assertEquals(key.toString('openssh'), keydata.privateDSA_openssh) - self.assertEquals(key.public().toString('openssh', 'comment'), + self.assertEqual(key.toString('openssh'), keydata.privateDSA_openssh) + self.assertEqual(key.public().toString('openssh', 'comment'), keydata.publicDSA_openssh) - self.assertEquals(key.public().toString('openssh'), + self.assertEqual(key.public().toString('openssh'), keydata.publicDSA_openssh[:-8]) # no comment def test_toLSH(self): @@ -421,12 +421,12 @@ Test that the Key object generates LSH keys correctly. """ key = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(key.toString('lsh'), keydata.privateRSA_lsh) - self.assertEquals(key.public().toString('lsh'), + self.assertEqual(key.toString('lsh'), keydata.privateRSA_lsh) + self.assertEqual(key.public().toString('lsh'), keydata.publicRSA_lsh) key = keys.Key.fromString(keydata.privateDSA_openssh) - self.assertEquals(key.toString('lsh'), keydata.privateDSA_lsh) - self.assertEquals(key.public().toString('lsh'), + self.assertEqual(key.toString('lsh'), keydata.privateDSA_lsh) + self.assertEqual(key.public().toString('lsh'), keydata.publicDSA_lsh) def test_toAgentv3(self): @@ -434,9 +434,9 @@ Test that the Key object generates Agent v3 keys correctly. """ key = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(key.toString('agentv3'), keydata.privateRSA_agentv3) + self.assertEqual(key.toString('agentv3'), keydata.privateRSA_agentv3) key = keys.Key.fromString(keydata.privateDSA_openssh) - self.assertEquals(key.toString('agentv3'), keydata.privateDSA_agentv3) + self.assertEqual(key.toString('agentv3'), keydata.privateDSA_agentv3) def test_toStringErrors(self): """ @@ -450,9 +450,9 @@ Test that the Key object generates correct signatures. """ key = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(key.sign(''), self.rsaSignature) + self.assertEqual(key.sign(''), self.rsaSignature) key = keys.Key.fromString(keydata.privateDSA_openssh) - self.assertEquals(key.sign(''), self.dsaSignature) + self.assertEqual(key.sign(''), self.dsaSignature) def test_verify(self): @@ -472,7 +472,7 @@ """ Test the pretty representation of Key. """ - self.assertEquals(repr(keys.Key(self.rsaObj)), + self.assertEqual(repr(keys.Key(self.rsaObj)), """4L', 1, 2, 3, 4) + common.NS( @@ -969,7 +969,7 @@ packed = session.packRequest_pty_req('xterm', (2, 1, 3, 4), '\x05\x00\x00\x00\x06') - self.assertEquals(packed, + self.assertEqual(packed, common.NS('xterm') + struct.pack('>4L', 1, 2, 3, 4) + common.NS(struct.pack('>BL', 5, 6))) @@ -980,7 +980,7 @@ """ packed = session.packRequest_pty_req('xterm', (2, 1, 3, 4), '\x05\x00\x00\x00\x06') - self.assertEquals(packed, + self.assertEqual(packed, common.NS('xterm') + struct.pack('>4L', 1, 2, 3, 4) + common.NS(struct.pack('>BL', 5, 6))) @@ -996,7 +996,7 @@ parseRequest_window_change() returns (rows, columns, x pixels, y pixels). """ - self.assertEquals(session.parseRequest_window_change( + self.assertEqual(session.parseRequest_window_change( struct.pack('>4L', 1, 2, 3, 4)), (2, 1, 3, 4)) @@ -1004,7 +1004,7 @@ """ See test_parseRequest_window_change for the payload format. """ - self.assertEquals(session.packRequest_window_change((2, 1, 3, 4)), + self.assertEqual(session.packRequest_window_change((2, 1, 3, 4)), struct.pack('>4L', 1, 2, 3, 4)) @@ -1044,7 +1044,7 @@ SSHSessionProcessProtocol should set self.session to the session passed to the __init__ method. """ - self.assertEquals(self.pp.session, self.session) + self.assertEqual(self.pp.session, self.session) def test_getHost(self): @@ -1052,7 +1052,7 @@ SSHSessionProcessProtocol.getHost() just delegates to its session.conn.transport.getHost(). """ - self.assertEquals( + self.assertEqual( self.session.conn.transport.getHost(), self.pp.getHost()) @@ -1061,7 +1061,7 @@ SSHSessionProcessProtocol.getPeer() just delegates to its session.conn.transport.getPeer(). """ - self.assertEquals( + self.assertEqual( self.session.conn.transport.getPeer(), self.pp.getPeer()) @@ -1072,7 +1072,7 @@ """ self.session.buf = 'buffer' self.pp.connectionMade() - self.assertEquals(self.transport.buf, 'buffer') + self.assertEqual(self.transport.buf, 'buffer') def test_getSignalName(self): @@ -1084,7 +1084,7 @@ signalName = 'SIG' + signalName signalValue = getattr(signal, signalName) sshName = self.pp._getSignalName(signalValue) - self.assertEquals(sshName, signalName, + self.assertEqual(sshName, signalName, "%i: %s != %s" % (signalValue, sshName, signalName)) @@ -1097,7 +1097,7 @@ signal.SIGTwistedTest = signal.NSIG + 1 # value can't exist normally # Force reinitialization of signals self.pp._signalValuesToNames = None - self.assertEquals(self.pp._getSignalName(signal.SIGTwistedTest), + self.assertEqual(self.pp._getSignalName(signal.SIGTwistedTest), 'SIGTwistedTest@' + sys.platform) @@ -1112,7 +1112,7 @@ the session's write method. """ self.pp.outReceived('test data') - self.assertEquals(self.session.conn.data[self.session], + self.assertEqual(self.session.conn.data[self.session], ['test data']) @@ -1122,7 +1122,7 @@ session channel's write method. """ self.pp.write('test data') - self.assertEquals(self.session.conn.data[self.session], + self.assertEqual(self.session.conn.data[self.session], ['test data']) def test_writeSequence(self): @@ -1131,7 +1131,7 @@ joined together and sent to the session channel's write method. """ self.pp.writeSequence(['test ', 'data']) - self.assertEquals(self.session.conn.data[self.session], + self.assertEqual(self.session.conn.data[self.session], ['test data']) @@ -1141,7 +1141,7 @@ the session's writeExtended method. """ self.pp.errReceived('test data') - self.assertEquals(self.session.conn.extData[self.session], + self.assertEqual(self.session.conn.extData[self.session], [(1, 'test data')]) @@ -1253,4 +1253,4 @@ client = session.SSHSessionClient() client.transport = StubTransport() client.dataReceived('test data') - self.assertEquals(client.transport.buf, 'test data') + self.assertEqual(client.transport.buf, 'test data') diff --git a/lib/twisted-trunk/twisted/conch/test/test_ssh.py b/lib/twisted-trunk/twisted/conch/test/test_ssh.py --- a/lib/twisted-trunk/twisted/conch/test/test_ssh.py +++ b/lib/twisted-trunk/twisted/conch/test/test_ssh.py @@ -311,10 +311,10 @@ def testCounter(self): c = transport._Counter('\x00\x00', 2) for i in xrange(256 * 256): - self.assertEquals(c(), struct.pack('!H', (i + 1) % (2 ** 16))) + self.assertEqual(c(), struct.pack('!H', (i + 1) % (2 ** 16))) # It should wrap around, too. for i in xrange(256 * 256): - self.assertEquals(c(), struct.pack('!H', (i + 1) % (2 ** 16))) + self.assertEqual(c(), struct.pack('!H', (i + 1) % (2 ** 16))) class ConchTestPublicKeyChecker(checkers.SSHPublicKeyDatabase): @@ -593,7 +593,7 @@ d1 = channel.conn.sendGlobalRequest('foo', 'bar', 1) d2 = channel.conn.sendGlobalRequest('foo-2', 'bar2', 1) - d2.addCallback(self.assertEquals, 'data') + d2.addCallback(self.assertEqual, 'data') d3 = self.assertFailure( channel.conn.sendGlobalRequest('bar', 'foo', 1), @@ -603,7 +603,7 @@ channel.addCallback(cbGlobalRequests) def disconnect(ignored): - self.assertEquals( + self.assertEqual( self.realm.avatar.globalRequests, {"foo": "bar", "foo_2": "bar2"}) channel = self.channel @@ -632,8 +632,8 @@ # The server-side object corresponding to our client side channel. session = self.realm.avatar.conn.channels[0].session self.assertIdentical(session.avatar, self.realm.avatar) - self.assertEquals(session._terminalType, 'conch-test-term') - self.assertEquals(session._windowSize, (24, 80, 0, 0)) + self.assertEqual(session._terminalType, 'conch-test-term') + self.assertEqual(session._windowSize, (24, 80, 0, 0)) self.assertTrue(session.ptyReq) channel = self.channel return channel.conn.sendRequest(channel, 'shell', '', 1) @@ -651,7 +651,7 @@ if self.channel.status != 0: log.msg( 'shell exit status was not 0: %i' % (self.channel.status,)) - self.assertEquals( + self.assertEqual( "".join(self.channel.received), 'testing the shell!\x00\r\n') self.assertTrue(self.channel.eofCalled) @@ -680,7 +680,7 @@ # The server logs this exception when it cannot perform the # requested exec. errors = self.flushLoggedErrors(error.ConchError) - self.assertEquals(errors[0].value.args, ('bad exec', None)) + self.assertEqual(errors[0].value.args, ('bad exec', None)) channel.addCallback(cbFailed) return channel @@ -704,7 +704,7 @@ def cbClosed(ignored): # No data is expected - self.assertEquals(self.channel.received, []) + self.assertEqual(self.channel.received, []) self.assertNotEquals(self.channel.status, 0) channel.addCallback(cbClosed) return channel @@ -730,12 +730,12 @@ channel.addCallback(cbExec) def cbClosed(ignored): - self.assertEquals(self.channel.received, []) - self.assertEquals("".join(self.channel.receivedExt), "hello\r\n") - self.assertEquals(self.channel.status, 0) + self.assertEqual(self.channel.received, []) + self.assertEqual("".join(self.channel.receivedExt), "hello\r\n") + self.assertEqual(self.channel.status, 0) self.assertTrue(self.channel.eofCalled) - self.assertEquals(self.channel.localWindowLeft, 4) - self.assertEquals( + self.assertEqual(self.channel.localWindowLeft, 4) + self.assertEqual( self.channel.localWindowLeft, self.realm.avatar._testSession.remoteWindowLeftAtClose) channel.addCallback(cbClosed) @@ -751,8 +751,8 @@ self._ourServerOurClientTest('crazy-unknown-channel'), Exception) def cbFailed(ignored): errors = self.flushLoggedErrors(error.ConchError) - self.assertEquals(errors[0].value.args, (3, 'unknown channel')) - self.assertEquals(len(errors), 1) + self.assertEqual(errors[0].value.args, (3, 'unknown channel')) + self.assertEqual(len(errors), 1) d.addCallback(cbFailed) return d @@ -778,10 +778,10 @@ channel.addCallback(cbExec) def cbClosed(ignored): - self.assertEquals(self.channel.status, 0) - self.assertEquals("".join(self.channel.received), "hello\r\n") - self.assertEquals("".join(self.channel.receivedExt), "hello\r\n") - self.assertEquals(self.channel.localWindowLeft, 11) + self.assertEqual(self.channel.status, 0) + self.assertEqual("".join(self.channel.received), "hello\r\n") + self.assertEqual("".join(self.channel.receivedExt), "hello\r\n") + self.assertEqual(self.channel.localWindowLeft, 11) self.assertTrue(self.channel.eofCalled) channel.addCallback(cbClosed) return channel @@ -807,11 +807,11 @@ channel.addCallback(cbEcho) def cbClosed(ignored): - self.assertEquals(self.channel.status, 0) - self.assertEquals("".join(self.channel.received), "hello\r\n") - self.assertEquals(self.channel.localWindowLeft, 4) + self.assertEqual(self.channel.status, 0) + self.assertEqual("".join(self.channel.received), "hello\r\n") + self.assertEqual(self.channel.localWindowLeft, 4) self.assertTrue(self.channel.eofCalled) - self.assertEquals( + self.assertEqual( self.channel.localWindowLeft, self.realm.avatar._testSession.remoteWindowLeftAtClose) channel.addCallback(cbClosed) @@ -858,7 +858,7 @@ factory = self.makeSSHFactory() factory.protocol = makeProtocol factory.buildProtocol(None) - self.assertEquals([()], calls) + self.assertEqual([()], calls) def test_multipleFactories(self): @@ -894,7 +894,7 @@ L{common.getMP} should parse the a multiple precision integer from a string: a 4-byte length followed by length bytes of the integer. """ - self.assertEquals( + self.assertEqual( self.getMP('\x00\x00\x00\x04\x00\x00\x00\x01'), (1, '')) @@ -904,7 +904,7 @@ L{common.getMP} should be able to parse a big enough integer (that doesn't fit on one byte). """ - self.assertEquals( + self.assertEqual( self.getMP('\x00\x00\x00\x04\x01\x02\x03\x04'), (16909060, '')) @@ -914,7 +914,7 @@ L{common.getMP} has the ability to parse multiple integer in the same string. """ - self.assertEquals( + self.assertEqual( self.getMP('\x00\x00\x00\x04\x00\x00\x00\x01' '\x00\x00\x00\x04\x00\x00\x00\x02', 2), (1, 2, '')) @@ -925,7 +925,7 @@ When more data than needed is sent to L{common.getMP}, it should return the remaining data. """ - self.assertEquals( + self.assertEqual( self.getMP('\x00\x00\x00\x04\x00\x00\x00\x01foo'), (1, 'foo')) @@ -965,19 +965,19 @@ pow gives the correct result when passed a base of type float with a non-integer value. """ - self.assertEquals(6.25, pow(2.5, 2)) + self.assertEqual(6.25, pow(2.5, 2)) def test_intBase(self): """ pow gives the correct result when passed a base of type int. """ - self.assertEquals(81, pow(3, 4)) + self.assertEqual(81, pow(3, 4)) def test_longBase(self): """ pow gives the correct result when passed a base of type long. """ - self.assertEquals(81, pow(3, 4)) + self.assertEqual(81, pow(3, 4)) def test_mpzBase(self): """ @@ -985,7 +985,7 @@ """ if gmpy is None: raise unittest.SkipTest('gmpy not available') - self.assertEquals(81, pow(gmpy.mpz(3), 4)) + self.assertEqual(81, pow(gmpy.mpz(3), 4)) try: diff --git a/lib/twisted-trunk/twisted/conch/test/test_tap.py b/lib/twisted-trunk/twisted/conch/test/test_tap.py --- a/lib/twisted-trunk/twisted/conch/test/test_tap.py +++ b/lib/twisted-trunk/twisted/conch/test/test_tap.py @@ -57,7 +57,7 @@ config = tap.Options() service = tap.makeService(config) self.assertIsInstance(service, StreamServerEndpointService) - self.assertEquals(service.endpoint._port, 22) + self.assertEqual(service.endpoint._port, 22) self.assertIsInstance(service.factory, OpenSSHFactory) @@ -73,7 +73,7 @@ config = tap.Options() service = tap.makeService(config) portal = service.factory.portal - self.assertEquals( + self.assertEqual( set(portal.checkers.keys()), set([IPluggableAuthenticationModules, ISSHPrivateKey, IUsernamePassword])) @@ -90,6 +90,6 @@ config = tap.Options() service = tap.makeService(config) portal = service.factory.portal - self.assertEquals( + self.assertEqual( set(portal.checkers.keys()), set([ISSHPrivateKey, IUsernamePassword])) diff --git a/lib/twisted-trunk/twisted/conch/test/test_telnet.py b/lib/twisted-trunk/twisted/conch/test/test_telnet.py --- a/lib/twisted-trunk/twisted/conch/test/test_telnet.py +++ b/lib/twisted-trunk/twisted/conch/test/test_telnet.py @@ -93,7 +93,7 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, ''.join(L)) + self.assertEqual(h.bytes, ''.join(L)) def testNewlineHandling(self): # Send various kinds of newlines and make sure they get translated @@ -108,7 +108,7 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, L[0][:-2] + '\n' + + self.assertEqual(h.bytes, L[0][:-2] + '\n' + L[1][:-2] + '\r' + L[2][:-2] + '\n' + L[3][:-2] + '\r') @@ -126,7 +126,7 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, ''.join(L).replace('\xff\xff', '\xff')) + self.assertEqual(h.bytes, ''.join(L).replace('\xff\xff', '\xff')) def _simpleCommandTest(self, cmdName): # Send a single simple telnet command and make sure @@ -141,8 +141,8 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.calls, [cmdName]) - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) + self.assertEqual(h.calls, [cmdName]) + self.assertEqual(h.bytes, ''.join(L).replace(cmd, '')) def testInterrupt(self): self._simpleCommandTest("IP") @@ -183,8 +183,8 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - self.assertEquals(h.subcmd, list("hello world")) + self.assertEqual(h.bytes, ''.join(L).replace(cmd, '')) + self.assertEqual(h.subcmd, list("hello world")) def testSubnegotiationWithEmbeddedSE(self): # Send a subnegotiation command with an embedded SE. Make sure @@ -201,8 +201,8 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - self.assertEquals(h.subcmd, [telnet.SE]) + self.assertEqual(h.bytes, ''.join(L).replace(cmd, '')) + self.assertEqual(h.subcmd, [telnet.SE]) def testBoundarySubnegotiation(self): # Send a subnegotiation command. Split it at every possible byte boundary @@ -223,14 +223,14 @@ for bytes in L: self.p.dataReceived(bytes) - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - self.assertEquals(h.subcmd, [telnet.SE] + list('hello')) + self.assertEqual(h.bytes, ''.join(L).replace(cmd, '')) + self.assertEqual(h.subcmd, [telnet.SE] + list('hello')) def _enabledHelper(self, o, eL=[], eR=[], dL=[], dR=[]): - self.assertEquals(o.enabledLocal, eL) - self.assertEquals(o.enabledRemote, eR) - self.assertEquals(o.disabledLocal, dL) - self.assertEquals(o.disabledRemote, dR) + self.assertEqual(o.enabledLocal, eL) + self.assertEqual(o.enabledRemote, eR) + self.assertEqual(o.disabledLocal, dL) + self.assertEqual(o.disabledRemote, dR) def testRefuseWill(self): # Try to enable an option. The server should refuse to enable it. @@ -239,8 +239,8 @@ bytes = "surrounding bytes" + cmd + "to spice things up" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DONT + '\x12') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), telnet.IAC + telnet.DONT + '\x12') self._enabledHelper(self.p.protocol) def testRefuseDo(self): @@ -250,8 +250,8 @@ bytes = "surrounding bytes" + cmd + "to spice things up" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.WONT + '\x12') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), telnet.IAC + telnet.WONT + '\x12') self._enabledHelper(self.p.protocol) def testAcceptDo(self): @@ -264,7 +264,7 @@ h.localEnableable = ('\x19',) self.p.dataReceived(bytes) - self.assertEquals(self.t.value(), telnet.IAC + telnet.WILL + '\x19') + self.assertEqual(self.t.value(), telnet.IAC + telnet.WILL + '\x19') self._enabledHelper(h, eL=['\x19']) def testAcceptWill(self): @@ -276,7 +276,7 @@ h.remoteEnableable = ('\x91',) self.p.dataReceived(bytes) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DO + '\x91') + self.assertEqual(self.t.value(), telnet.IAC + telnet.DO + '\x91') self._enabledHelper(h, eR=['\x91']) def testAcceptWont(self): @@ -294,9 +294,9 @@ bytes = "fiddle dee" + cmd self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DONT + '\x29') - self.assertEquals(s.him.state, 'no') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), telnet.IAC + telnet.DONT + '\x29') + self.assertEqual(s.him.state, 'no') self._enabledHelper(self.p.protocol, dR=['\x29']) def testAcceptDont(self): @@ -314,9 +314,9 @@ bytes = "fiddle dum " + cmd self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.WONT + '\x29') - self.assertEquals(s.us.state, 'no') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), telnet.IAC + telnet.WONT + '\x29') + self.assertEqual(s.us.state, 'no') self._enabledHelper(self.p.protocol, dL=['\x29']) def testIgnoreWont(self): @@ -327,8 +327,8 @@ bytes = "dum de dum" + cmd + "tra la la" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), '') self._enabledHelper(self.p.protocol) def testIgnoreDont(self): @@ -340,8 +340,8 @@ bytes = "dum de dum" + cmd + "tra la la" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), '') self._enabledHelper(self.p.protocol) def testIgnoreWill(self): @@ -359,8 +359,8 @@ bytes = "tra la la" + cmd + "dum de dum" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), '') self._enabledHelper(self.p.protocol) def testIgnoreDo(self): @@ -378,8 +378,8 @@ bytes = "tra la la" + cmd + "dum de dum" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), '') self._enabledHelper(self.p.protocol) def testAcceptedEnableRequest(self): @@ -392,11 +392,11 @@ h = self.p.protocol h.remoteEnableable = ('\x42',) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DO + '\x42') + self.assertEqual(self.t.value(), telnet.IAC + telnet.DO + '\x42') self.p.dataReceived(telnet.IAC + telnet.WILL + '\x42') - d.addCallback(self.assertEquals, True) + d.addCallback(self.assertEqual, True) d.addCallback(lambda _: self._enabledHelper(h, eR=['\x42'])) return d @@ -414,20 +414,20 @@ self.p.protocol.remoteEnableable = ('\x42',) d = self.p.do('\x42') - self.assertEquals(self.t.value(), telnet.IAC + telnet.DO + '\x42') + self.assertEqual(self.t.value(), telnet.IAC + telnet.DO + '\x42') s = self.p.getOptionState('\x42') - self.assertEquals(s.him.state, 'no') - self.assertEquals(s.us.state, 'no') - self.assertEquals(s.him.negotiating, True) - self.assertEquals(s.us.negotiating, False) + self.assertEqual(s.him.state, 'no') + self.assertEqual(s.us.state, 'no') + self.assertEqual(s.him.negotiating, True) + self.assertEqual(s.us.negotiating, False) self.p.dataReceived(telnet.IAC + telnet.WONT + '\x42') d = self.assertFailure(d, telnet.OptionRefused) d.addCallback(lambda ignored: self._enabledHelper(self.p.protocol)) d.addCallback( - lambda ignored: self.assertEquals(s.him.negotiating, False)) + lambda ignored: self.assertEqual(s.him.negotiating, False)) return d @@ -444,20 +444,20 @@ self.p.protocol.localEnableable = ('\x42',) d = self.p.will('\x42') - self.assertEquals(self.t.value(), telnet.IAC + telnet.WILL + '\x42') + self.assertEqual(self.t.value(), telnet.IAC + telnet.WILL + '\x42') s = self.p.getOptionState('\x42') - self.assertEquals(s.him.state, 'no') - self.assertEquals(s.us.state, 'no') - self.assertEquals(s.him.negotiating, False) - self.assertEquals(s.us.negotiating, True) + self.assertEqual(s.him.state, 'no') + self.assertEqual(s.us.state, 'no') + self.assertEqual(s.him.negotiating, False) + self.assertEqual(s.us.negotiating, True) self.p.dataReceived(telnet.IAC + telnet.DONT + '\x42') d = self.assertFailure(d, telnet.OptionRefused) d.addCallback(lambda ignored: self._enabledHelper(self.p.protocol)) d.addCallback( - lambda ignored: self.assertEquals(s.us.negotiating, False)) + lambda ignored: self.assertEqual(s.us.negotiating, False)) return d @@ -471,11 +471,11 @@ d = self.p.dont('\x42') - self.assertEquals(self.t.value(), telnet.IAC + telnet.DONT + '\x42') + self.assertEqual(self.t.value(), telnet.IAC + telnet.DONT + '\x42') self.p.dataReceived(telnet.IAC + telnet.WONT + '\x42') - d.addCallback(self.assertEquals, True) + d.addCallback(self.assertEqual, True) d.addCallback(lambda _: self._enabledHelper(self.p.protocol, dR=['\x42'])) return d @@ -504,7 +504,7 @@ self.p.protocol.remoteEnableable = ('\x24',) d = self.p.do('\x24') self.p.dataReceived(telnet.IAC + telnet.WILL + '\x24') - d.addCallback(self.assertEquals, True) + d.addCallback(self.assertEqual, True) d.addCallback(lambda _: self._enabledHelper(self.p.protocol, eR=['\x24'], dR=['\x24'])) diff --git a/lib/twisted-trunk/twisted/conch/test/test_text.py b/lib/twisted-trunk/twisted/conch/test/test_text.py --- a/lib/twisted-trunk/twisted/conch/test/test_text.py +++ b/lib/twisted-trunk/twisted/conch/test/test_text.py @@ -13,46 +13,46 @@ self.attrs = helper.CharacterAttribute() def testTrivial(self): - self.assertEquals( + self.assertEqual( text.flatten(A.normal['Hello, world.'], self.attrs), 'Hello, world.') def testBold(self): - self.assertEquals( + self.assertEqual( text.flatten(A.bold['Hello, world.'], self.attrs), '\x1b[1mHello, world.') def testUnderline(self): - self.assertEquals( + self.assertEqual( text.flatten(A.underline['Hello, world.'], self.attrs), '\x1b[4mHello, world.') def testBlink(self): - self.assertEquals( + self.assertEqual( text.flatten(A.blink['Hello, world.'], self.attrs), '\x1b[5mHello, world.') def testReverseVideo(self): - self.assertEquals( + self.assertEqual( text.flatten(A.reverseVideo['Hello, world.'], self.attrs), '\x1b[7mHello, world.') def testMinus(self): - self.assertEquals( + self.assertEqual( text.flatten( A.bold[A.blink['Hello', -A.bold[' world'], '.']], self.attrs), '\x1b[1;5mHello\x1b[0;5m world\x1b[1;5m.') def testForeground(self): - self.assertEquals( + self.assertEqual( text.flatten( A.normal[A.fg.red['Hello, '], A.fg.green['world!']], self.attrs), '\x1b[31mHello, \x1b[32mworld!') def testBackground(self): - self.assertEquals( + self.assertEqual( text.flatten( A.normal[A.bg.red['Hello, '], A.bg.green['world!']], self.attrs), @@ -82,7 +82,7 @@ A.fg.green[ "Foreground Green, Background Cyan, Bold"]]]] - self.assertEquals( + self.assertEqual( text.flatten(output, self.attrs), "\x1b[1;31;46mForeground Red, Background Cyan, Bold" "\x1b[5mBlinking" @@ -90,11 +90,11 @@ "\x1b[1;32;46mForeground Green, Background Cyan, Bold") def testNesting(self): - self.assertEquals( + self.assertEqual( text.flatten(A.bold['Hello, ', A.underline['world.']], self.attrs), '\x1b[1mHello, \x1b[4mworld.') - self.assertEquals( + self.assertEqual( text.flatten( A.bold[A.reverseVideo['Hello, ', A.normal['world'], '.']], self.attrs), diff --git a/lib/twisted-trunk/twisted/conch/test/test_transport.py b/lib/twisted-trunk/twisted/conch/test/test_transport.py --- a/lib/twisted-trunk/twisted/conch/test/test_transport.py +++ b/lib/twisted-trunk/twisted/conch/test/test_transport.py @@ -410,7 +410,7 @@ string. """ # the other setup was done in the setup method - self.assertEquals(self.transport.value().split('\r\n', 1)[0], + self.assertEqual(self.transport.value().split('\r\n', 1)[0], "SSH-2.0-Twisted") @@ -432,7 +432,7 @@ payload = 'BCDEFG' proto.sendPacket(message, payload) value = self.transport.value() - self.assertEquals(value, '\x00\x00\x00\x0c\x04ABCDEFG\x99\x99\x99\x99') + self.assertEqual(value, '\x00\x00\x00\x0c\x04ABCDEFG\x99\x99\x99\x99') def test_sendPacketEncrypted(self): @@ -450,7 +450,7 @@ proto.sendPacket(message, payload) self.assertTrue(testCipher.usedEncrypt) value = self.transport.value() - self.assertEquals( + self.assertEqual( value, # Four byte length prefix '\x00\x00\x00\x08' @@ -476,7 +476,7 @@ self.transport.clear() proto.sendPacket(ord('A'), 'B') value = self.transport.value() - self.assertEquals( + self.assertEqual( value, '\x00\x00\x00\x0c\x08BA\x66\x99\x99\x99\x99\x99\x99\x99\x99') @@ -498,7 +498,7 @@ proto.sendPacket(message, payload) self.assertTrue(testCipher.usedEncrypt) value = self.transport.value() - self.assertEquals( + self.assertEqual( value, # Four byte length prefix '\x00\x00\x00\x0e' @@ -523,8 +523,8 @@ self.transport.clear() proto.sendPacket(ord('A'), 'BC') proto.buf = self.transport.value() + 'extra' - self.assertEquals(proto.getPacket(), 'ABC') - self.assertEquals(proto.buf, 'extra') + self.assertEqual(proto.getPacket(), 'ABC') + self.assertEqual(proto.buf, 'extra') def test_getPacketEncrypted(self): @@ -540,12 +540,12 @@ proto.sendPacket(ord('A'), 'BCD') value = self.transport.value() proto.buf = value[:MockCipher.decBlockSize] - self.assertEquals(proto.getPacket(), None) + self.assertEqual(proto.getPacket(), None) self.assertTrue(testCipher.usedDecrypt) - self.assertEquals(proto.first, '\x00\x00\x00\x0e\x09A') + self.assertEqual(proto.first, '\x00\x00\x00\x0e\x09A') proto.buf += value[MockCipher.decBlockSize:] - self.assertEquals(proto.getPacket(), 'ABCD') - self.assertEquals(proto.buf, '') + self.assertEqual(proto.getPacket(), 'ABCD') + self.assertEqual(proto.buf, '') def test_getPacketCompressed(self): @@ -561,7 +561,7 @@ proto.incomingCompression = proto.outgoingCompression proto.sendPacket(ord('A'), 'BCD') proto.buf = self.transport.value() - self.assertEquals(proto.getPacket(), 'ABCD') + self.assertEqual(proto.getPacket(), 'ABCD') def test_getPacketBoth(self): @@ -578,7 +578,7 @@ proto.incomingCompression = proto.outgoingCompression proto.sendPacket(ord('A'), 'BCDEFG') proto.buf = self.transport.value() - self.assertEquals(proto.getPacket(), 'ABCDEFG') + self.assertEqual(proto.getPacket(), 'ABCDEFG') def test_ciphersAreValid(self): @@ -610,25 +610,25 @@ value = self.transport.value().split('\r\n', 1)[1] self.proto.buf = value packet = self.proto.getPacket() - self.assertEquals(packet[0], chr(transport.MSG_KEXINIT)) - self.assertEquals(packet[1:17], '\x99' * 16) + self.assertEqual(packet[0], chr(transport.MSG_KEXINIT)) + self.assertEqual(packet[1:17], '\x99' * 16) (kex, pubkeys, ciphers1, ciphers2, macs1, macs2, compressions1, compressions2, languages1, languages2, buf) = common.getNS(packet[17:], 10) - self.assertEquals(kex, ','.join(self.proto.supportedKeyExchanges)) - self.assertEquals(pubkeys, ','.join(self.proto.supportedPublicKeys)) - self.assertEquals(ciphers1, ','.join(self.proto.supportedCiphers)) - self.assertEquals(ciphers2, ','.join(self.proto.supportedCiphers)) - self.assertEquals(macs1, ','.join(self.proto.supportedMACs)) - self.assertEquals(macs2, ','.join(self.proto.supportedMACs)) - self.assertEquals(compressions1, + self.assertEqual(kex, ','.join(self.proto.supportedKeyExchanges)) + self.assertEqual(pubkeys, ','.join(self.proto.supportedPublicKeys)) + self.assertEqual(ciphers1, ','.join(self.proto.supportedCiphers)) + self.assertEqual(ciphers2, ','.join(self.proto.supportedCiphers)) + self.assertEqual(macs1, ','.join(self.proto.supportedMACs)) + self.assertEqual(macs2, ','.join(self.proto.supportedMACs)) + self.assertEqual(compressions1, ','.join(self.proto.supportedCompressions)) - self.assertEquals(compressions2, + self.assertEqual(compressions2, ','.join(self.proto.supportedCompressions)) - self.assertEquals(languages1, ','.join(self.proto.supportedLanguages)) - self.assertEquals(languages2, ','.join(self.proto.supportedLanguages)) - self.assertEquals(buf, '\x00' * 5) + self.assertEqual(languages1, ','.join(self.proto.supportedLanguages)) + self.assertEqual(languages2, ','.join(self.proto.supportedLanguages)) + self.assertEqual(buf, '\x00' * 5) def test_receiveKEXINITReply(self): @@ -639,7 +639,7 @@ self.transport.clear() self.proto.dispatchMessage( transport.MSG_KEXINIT, self._A_KEXINIT_MESSAGE) - self.assertEquals(self.packets, []) + self.assertEqual(self.packets, []) def test_sendKEXINITReply(self): @@ -652,8 +652,8 @@ self.proto.dispatchMessage( transport.MSG_KEXINIT, self._A_KEXINIT_MESSAGE) - self.assertEquals(len(self.packets), 1) - self.assertEquals(self.packets[0][0], transport.MSG_KEXINIT) + self.assertEqual(len(self.packets), 1) + self.assertEqual(self.packets[0][0], transport.MSG_KEXINIT) def test_sendKexInitTwiceFails(self): @@ -690,7 +690,7 @@ for messageType in disallowedMessageTypes: self.proto.sendPacket(messageType, 'foo') - self.assertEquals(self.transport.value(), "") + self.assertEqual(self.transport.value(), "") self.finishKeyExchange(self.proto) # Make the bytes written to the transport cleartext so it's easier to @@ -700,7 +700,7 @@ # Pseudo-deliver the peer's NEWKEYS message, which should flush the # messages which were queued above. self.proto._newKeys() - self.assertEquals(self.transport.value().count("foo"), 2) + self.assertEqual(self.transport.value().count("foo"), 2) def test_sendDebug(self): @@ -711,7 +711,7 @@ string language """ self.proto.sendDebug("test", True, 'en') - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_DEBUG, "\x01\x00\x00\x00\x04test\x00\x00\x00\x02en")]) @@ -724,7 +724,7 @@ self.proto.dispatchMessage( transport.MSG_DEBUG, '\x01\x00\x00\x00\x04test\x00\x00\x00\x02en') - self.assertEquals(self.proto.debugs, [(True, 'test', 'en')]) + self.assertEqual(self.proto.debugs, [(True, 'test', 'en')]) def test_sendIgnore(self): @@ -733,7 +733,7 @@ string ignored data """ self.proto.sendIgnore("test") - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_IGNORE, '\x00\x00\x00\x04test')]) @@ -744,7 +744,7 @@ test_sendIgnore. """ self.proto.dispatchMessage(transport.MSG_IGNORE, 'test') - self.assertEquals(self.proto.ignoreds, ['test']) + self.assertEqual(self.proto.ignoreds, ['test']) def test_sendUnimplemented(self): @@ -753,7 +753,7 @@ uint32 sequence number """ self.proto.sendUnimplemented() - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_UNIMPLEMENTED, '\x00\x00\x00\x00')]) @@ -765,7 +765,7 @@ """ self.proto.dispatchMessage(transport.MSG_UNIMPLEMENTED, '\x00\x00\x00\xff') - self.assertEquals(self.proto.unimplementeds, [255]) + self.assertEqual(self.proto.unimplementeds, [255]) def test_sendDisconnect(self): @@ -780,7 +780,7 @@ disconnected[0] = True self.transport.loseConnection = stubLoseConnection self.proto.sendDisconnect(0xff, "test") - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_DISCONNECT, "\x00\x00\x00\xff\x00\x00\x00\x04test\x00\x00\x00\x00")]) @@ -798,7 +798,7 @@ self.transport.loseConnection = stubLoseConnection self.proto.dispatchMessage(transport.MSG_DISCONNECT, '\x00\x00\x00\xff\x00\x00\x00\x04test') - self.assertEquals(self.proto.errors, [(255, 'test')]) + self.assertEqual(self.proto.errors, [(255, 'test')]) self.assertTrue(disconnected[0]) @@ -813,7 +813,7 @@ self.proto.ssh_KEXINIT = stubKEXINIT self.proto.dataReceived(self.transport.value()) self.assertTrue(self.proto.gotVersion) - self.assertEquals(self.proto.ourVersionString, + self.assertEqual(self.proto.ourVersionString, self.proto.otherVersionString) self.assertTrue(kexInit[0]) @@ -825,10 +825,10 @@ """ service = MockService() self.proto.setService(service) - self.assertEquals(self.proto.service, service) + self.assertEqual(self.proto.service, service) self.assertTrue(service.started) self.proto.dispatchMessage(0xff, "test") - self.assertEquals(self.packets, [(0xff, "test")]) + self.assertEqual(self.packets, [(0xff, "test")]) service2 = MockService() self.proto.setService(service2) @@ -903,8 +903,8 @@ disconnected[0] = True self.transport.loseConnection = stubLoseConnection self.proto.loseConnection() - self.assertEquals(self.packets[0][0], transport.MSG_DISCONNECT) - self.assertEquals(self.packets[0][1][3], + self.assertEqual(self.packets[0][0], transport.MSG_DISCONNECT) + self.assertEqual(self.packets[0][1][3], chr(transport.DISCONNECT_CONNECTION_LOST)) @@ -922,8 +922,8 @@ for c in version + '\r\n': self.proto.dataReceived(c) self.assertTrue(disconnected[0]) - self.assertEquals(self.packets[0][0], transport.MSG_DISCONNECT) - self.assertEquals( + self.assertEqual(self.packets[0][0], transport.MSG_DISCONNECT) + self.assertEqual( self.packets[0][1][3], chr(transport.DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED)) testBad('SSH-1.5-OpenSSH') @@ -942,7 +942,7 @@ """ + proto.ourVersionString + "\r\n") [proto.dataReceived(c) for c in data] self.assertTrue(proto.gotVersion) - self.assertEquals(proto.otherVersionString, proto.ourVersionString) + self.assertEqual(proto.otherVersionString, proto.ourVersionString) def test_compatabilityVersion(self): @@ -954,7 +954,7 @@ proto.makeConnection(proto_helpers.StringTransport()) proto.dataReceived("SSH-1.99-OpenSSH\n") self.assertTrue(proto.gotVersion) - self.assertEquals(proto.otherVersionString, "SSH-1.99-OpenSSH") + self.assertEqual(proto.otherVersionString, "SSH-1.99-OpenSSH") def test_supportedVersionsAreAllowed(self): @@ -978,7 +978,7 @@ proto.supportedVersions = ("2.0", ) proto.makeConnection(proto_helpers.StringTransport()) proto.dataReceived("SSH-9.99-OpenSSH\n") - self.assertEquals("9.99", proto.gotUnsupportedVersion) + self.assertEqual("9.99", proto.gotUnsupportedVersion) def test_badPackets(self): @@ -989,10 +989,10 @@ def testBad(packet, error=transport.DISCONNECT_PROTOCOL_ERROR): self.packets = [] self.proto.buf = packet - self.assertEquals(self.proto.getPacket(), None) - self.assertEquals(len(self.packets), 1) - self.assertEquals(self.packets[0][0], transport.MSG_DISCONNECT) - self.assertEquals(self.packets[0][1][3], chr(error)) + self.assertEqual(self.proto.getPacket(), None) + self.assertEqual(len(self.packets), 1) + self.assertEqual(self.packets[0][0], transport.MSG_DISCONNECT) + self.assertEqual(self.packets[0][1][3], chr(error)) testBad('\xff' * 8) # big packet testBad('\x00\x00\x00\x05\x00BCDE') # length not modulo blocksize @@ -1019,9 +1019,9 @@ """ seqnum = self.proto.incomingPacketSequence def checkUnimplemented(seqnum=seqnum): - self.assertEquals(self.packets[0][0], + self.assertEqual(self.packets[0][0], transport.MSG_UNIMPLEMENTED) - self.assertEquals(self.packets[0][1][3], chr(seqnum)) + self.assertEqual(self.packets[0][1][3], chr(seqnum)) self.proto.packets = [] seqnum += 1 @@ -1047,7 +1047,7 @@ k1 = sha1('AB' + 'CD' + 'K' + self.proto.sessionID).digest() k2 = sha1('ABCD' + k1).digest() - self.assertEquals(self.proto._getKey('K', 'AB', 'CD'), k1 + k2) + self.assertEqual(self.proto._getKey('K', 'AB', 'CD'), k1 + k2) def test_multipleClasses(self): @@ -1087,8 +1087,8 @@ """ if kind is None: kind = transport.DISCONNECT_PROTOCOL_ERROR - self.assertEquals(self.packets[-1][0], transport.MSG_DISCONNECT) - self.assertEquals(self.packets[-1][1][3], chr(kind)) + self.assertEqual(self.packets[-1][0], transport.MSG_DISCONNECT) + self.assertEqual(self.packets[-1][1][3], chr(kind)) def connectModifiedProtocol(self, protoModification, @@ -1194,19 +1194,19 @@ '\tnone,zlib\x00\x00\x00\tnone,zlib\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x99\x99\x99\x99\x99\x99\x99\x99' '\x99') - self.assertEquals(self.proto.kexAlg, + self.assertEqual(self.proto.kexAlg, 'diffie-hellman-group1-sha1') - self.assertEquals(self.proto.keyAlg, + self.assertEqual(self.proto.keyAlg, 'ssh-dss') - self.assertEquals(self.proto.outgoingCompressionType, + self.assertEqual(self.proto.outgoingCompressionType, 'none') - self.assertEquals(self.proto.incomingCompressionType, + self.assertEqual(self.proto.incomingCompressionType, 'none') ne = self.proto.nextEncryptions - self.assertEquals(ne.outCipType, 'aes128-ctr') - self.assertEquals(ne.inCipType, 'aes128-ctr') - self.assertEquals(ne.outMACType, 'hmac-md5') - self.assertEquals(ne.inMACType, 'hmac-md5') + self.assertEqual(ne.outCipType, 'aes128-ctr') + self.assertEqual(ne.inCipType, 'aes128-ctr') + self.assertEqual(ne.outMACType, 'hmac-md5') + self.assertEqual(ne.inMACType, 'hmac-md5') def test_ignoreGuessPacketKex(self): @@ -1239,12 +1239,12 @@ self.proto.ssh_KEX_DH_GEX_REQUEST_OLD('\x00\x00\x08\x00') self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) + self.assertEqual(self.packets, []) self.proto.ignoreNextPacket = True self.proto.ssh_KEX_DH_GEX_REQUEST('\x00\x00\x08\x00' * 3) self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) + self.assertEqual(self.packets, []) def test_ignoreGuessPacketKey(self): @@ -1273,12 +1273,12 @@ self.proto.ssh_KEX_DH_GEX_REQUEST_OLD('\x00\x00\x08\x00') self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) + self.assertEqual(self.packets, []) self.proto.ignoreNextPacket = True self.proto.ssh_KEX_DH_GEX_REQUEST('\x00\x00\x08\x00' * 3) self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) + self.assertEqual(self.packets, []) def test_KEXDH_INIT(self): @@ -1309,7 +1309,7 @@ signature = self.proto.factory.privateKeys['ssh-rsa'].sign( exchangeHash) - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_KEXDH_REPLY, common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()) @@ -1328,12 +1328,12 @@ self.proto.supportedPublicKeys = ['ssh-rsa'] self.proto.dataReceived(self.transport.value()) self.proto.ssh_KEX_DH_GEX_REQUEST_OLD('\x00\x00\x04\x00') - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_KEX_DH_GEX_GROUP, common.MP(transport.DH_PRIME) + '\x00\x00\x00\x01\x02')]) - self.assertEquals(self.proto.g, 2) - self.assertEquals(self.proto.p, transport.DH_PRIME) + self.assertEqual(self.proto.g, 2) + self.assertEqual(self.proto.p, transport.DH_PRIME) def test_KEX_DH_GEX_REQUEST_OLD_badKexAlg(self): @@ -1359,12 +1359,12 @@ self.proto.dataReceived(self.transport.value()) self.proto.ssh_KEX_DH_GEX_REQUEST('\x00\x00\x04\x00\x00\x00\x08\x00' + '\x00\x00\x0c\x00') - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_KEX_DH_GEX_GROUP, common.MP(transport.DH_PRIME) + '\x00\x00\x00\x01\x03')]) - self.assertEquals(self.proto.g, 3) - self.assertEquals(self.proto.p, transport.DH_PRIME) + self.assertEqual(self.proto.g, 3) + self.assertEqual(self.proto.p, transport.DH_PRIME) def test_KEX_DH_GEX_INIT_after_REQUEST(self): @@ -1390,7 +1390,7 @@ h.update(sharedSecret) exchangeHash = h.digest() self.proto.ssh_KEX_DH_GEX_INIT(common.MP(e)) - self.assertEquals( + self.assertEqual( self.packets[1], (transport.MSG_KEX_DH_GEX_REPLY, common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()) + @@ -1421,7 +1421,7 @@ h.update(sharedSecret) exchangeHash = h.digest() self.proto.ssh_KEX_DH_GEX_INIT(common.MP(e)) - self.assertEquals( + self.assertEqual( self.packets[1:], [(transport.MSG_KEX_DH_GEX_REPLY, common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()) + @@ -1436,12 +1436,12 @@ """ self.proto.nextEncryptions = MockCipher() self.simulateKeyExchange('AB', 'CD') - self.assertEquals(self.proto.sessionID, 'CD') + self.assertEqual(self.proto.sessionID, 'CD') self.simulateKeyExchange('AB', 'EF') - self.assertEquals(self.proto.sessionID, 'CD') - self.assertEquals(self.packets[-1], (transport.MSG_NEWKEYS, '')) + self.assertEqual(self.proto.sessionID, 'CD') + self.assertEqual(self.packets[-1], (transport.MSG_NEWKEYS, '')) newKeys = [self.proto._getKey(c, 'AB', 'EF') for c in 'ABCDEF'] - self.assertEquals( + self.assertEqual( self.proto.nextEncryptions.keys, (newKeys[1], newKeys[3], newKeys[0], newKeys[2], newKeys[5], newKeys[4])) @@ -1477,9 +1477,9 @@ service. """ self.proto.ssh_SERVICE_REQUEST(common.NS('ssh-userauth')) - self.assertEquals(self.packets, [(transport.MSG_SERVICE_ACCEPT, + self.assertEqual(self.packets, [(transport.MSG_SERVICE_ACCEPT, common.NS('ssh-userauth'))]) - self.assertEquals(self.proto.service.name, 'MockService') + self.assertEqual(self.proto.service.name, 'MockService') def test_disconnectNEWKEYSData(self): @@ -1528,19 +1528,19 @@ '\tzlib,none\x00\x00\x00\tzlib,none\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x99\x99\x99\x99\x99\x99\x99\x99' '\x99') - self.assertEquals(self.proto.kexAlg, + self.assertEqual(self.proto.kexAlg, 'diffie-hellman-group-exchange-sha1') - self.assertEquals(self.proto.keyAlg, + self.assertEqual(self.proto.keyAlg, 'ssh-rsa') - self.assertEquals(self.proto.outgoingCompressionType, + self.assertEqual(self.proto.outgoingCompressionType, 'none') - self.assertEquals(self.proto.incomingCompressionType, + self.assertEqual(self.proto.incomingCompressionType, 'none') ne = self.proto.nextEncryptions - self.assertEquals(ne.outCipType, 'aes256-ctr') - self.assertEquals(ne.inCipType, 'aes256-ctr') - self.assertEquals(ne.outMACType, 'hmac-sha1') - self.assertEquals(ne.inMACType, 'hmac-sha1') + self.assertEqual(ne.outCipType, 'aes256-ctr') + self.assertEqual(ne.inCipType, 'aes256-ctr') + self.assertEqual(ne.outMACType, 'hmac-sha1') + self.assertEqual(ne.inMACType, 'hmac-sha1') def verifyHostKey(self, pubKey, fingerprint): @@ -1548,8 +1548,8 @@ Mock version of SSHClientTransport.verifyHostKey. """ self.calledVerifyHostKey = True - self.assertEquals(pubKey, self.blob) - self.assertEquals(fingerprint.replace(':', ''), + self.assertEqual(pubKey, self.blob) + self.assertEqual(fingerprint.replace(':', ''), md5(pubKey).hexdigest()) return defer.succeed(True) @@ -1583,7 +1583,7 @@ self.proto.supportedKeyExchanges = [ 'diffie-hellman-group-exchange-sha1'] self.proto.dataReceived(self.transport.value()) - self.assertEquals(self.packets, [(transport.MSG_KEX_DH_GEX_REQUEST_OLD, + self.assertEqual(self.packets, [(transport.MSG_KEX_DH_GEX_REQUEST_OLD, '\x00\x00\x08\x00')]) @@ -1593,8 +1593,8 @@ """ self.proto.supportedKeyExchanges = ['diffie-hellman-group1-sha1'] self.proto.dataReceived(self.transport.value()) - self.assertEquals(common.MP(self.proto.x)[5:], '\x99' * 64) - self.assertEquals(self.packets, + self.assertEqual(common.MP(self.proto.x)[5:], '\x99' * 64) + self.assertEqual(self.packets, [(transport.MSG_KEXDH_INIT, self.proto.e)]) @@ -1628,8 +1628,8 @@ def _cbTestKEXDH_REPLY(value): self.assertIdentical(value, None) - self.assertEquals(self.calledVerifyHostKey, True) - self.assertEquals(self.proto.sessionID, exchangeHash) + self.assertEqual(self.calledVerifyHostKey, True) + self.assertEqual(self.proto.sessionID, exchangeHash) signature = self.privObj.sign(exchangeHash) @@ -1649,12 +1649,12 @@ self.test_KEXINIT_groupexchange() self.proto.ssh_KEX_DH_GEX_GROUP( '\x00\x00\x00\x01\x0f\x00\x00\x00\x01\x02') - self.assertEquals(self.proto.p, 15) - self.assertEquals(self.proto.g, 2) - self.assertEquals(common.MP(self.proto.x)[5:], '\x99' * 40) - self.assertEquals(self.proto.e, + self.assertEqual(self.proto.p, 15) + self.assertEqual(self.proto.g, 2) + self.assertEqual(common.MP(self.proto.x)[5:], '\x99' * 40) + self.assertEqual(self.proto.e, common.MP(pow(2, self.proto.x, 15))) - self.assertEquals(self.packets[1:], [(transport.MSG_KEX_DH_GEX_INIT, + self.assertEqual(self.packets[1:], [(transport.MSG_KEX_DH_GEX_INIT, self.proto.e)]) @@ -1678,8 +1678,8 @@ def _cbTestKEX_DH_GEX_REPLY(value): self.assertIdentical(value, None) - self.assertEquals(self.calledVerifyHostKey, True) - self.assertEquals(self.proto.sessionID, exchangeHash) + self.assertEqual(self.calledVerifyHostKey, True) + self.assertEqual(self.proto.sessionID, exchangeHash) signature = self.privObj.sign(exchangeHash) @@ -1697,12 +1697,12 @@ """ self.proto.nextEncryptions = MockCipher() self.simulateKeyExchange('AB', 'CD') - self.assertEquals(self.proto.sessionID, 'CD') + self.assertEqual(self.proto.sessionID, 'CD') self.simulateKeyExchange('AB', 'EF') - self.assertEquals(self.proto.sessionID, 'CD') - self.assertEquals(self.packets[-1], (transport.MSG_NEWKEYS, '')) + self.assertEqual(self.proto.sessionID, 'CD') + self.assertEqual(self.packets[-1], (transport.MSG_NEWKEYS, '')) newKeys = [self.proto._getKey(c, 'AB', 'EF') for c in 'ABCDEF'] - self.assertEquals(self.proto.nextEncryptions.keys, + self.assertEqual(self.proto.nextEncryptions.keys, (newKeys[0], newKeys[2], newKeys[1], newKeys[3], newKeys[4], newKeys[5])) @@ -1755,7 +1755,7 @@ Test that requesting a service sends a SERVICE_REQUEST packet. """ self.proto.requestService(MockService()) - self.assertEquals(self.packets, [(transport.MSG_SERVICE_REQUEST, + self.assertEqual(self.packets, [(transport.MSG_SERVICE_REQUEST, '\x00\x00\x00\x0bMockService')]) @@ -1812,10 +1812,10 @@ Test that the initializer sets up the SSHCiphers object. """ ciphers = transport.SSHCiphers('A', 'B', 'C', 'D') - self.assertEquals(ciphers.outCipType, 'A') - self.assertEquals(ciphers.inCipType, 'B') - self.assertEquals(ciphers.outMACType, 'C') - self.assertEquals(ciphers.inMACType, 'D') + self.assertEqual(ciphers.outCipType, 'A') + self.assertEqual(ciphers.inCipType, 'B') + self.assertEqual(ciphers.outMACType, 'C') + self.assertEqual(ciphers.inMACType, 'D') def test_getCipher(self): @@ -1843,12 +1843,12 @@ if macName == 'none': self.assertIdentical(mac, None) else: - self.assertEquals(mod[0], mac) - self.assertEquals(mod[1], + self.assertEqual(mod[0], mac) + self.assertEqual(mod[1], Crypto.Cipher.XOR.new('\x36').encrypt(key)) - self.assertEquals(mod[2], + self.assertEqual(mod[2], Crypto.Cipher.XOR.new('\x5c').encrypt(key)) - self.assertEquals(mod[3], len(mod[0]().digest())) + self.assertEqual(mod[3], len(mod[0]().digest())) def test_setKeysCiphers(self): @@ -1864,16 +1864,16 @@ bs = cip.block_size encCipher.setKeys(key, key, '', '', '', '') decCipher.setKeys('', '', key, key, '', '') - self.assertEquals(encCipher.encBlockSize, bs) - self.assertEquals(decCipher.decBlockSize, bs) + self.assertEqual(encCipher.encBlockSize, bs) + self.assertEqual(decCipher.decBlockSize, bs) enc = cip.encrypt(key[:bs]) enc2 = cip.encrypt(key[:bs]) if counter: self.failIfEquals(enc, enc2) - self.assertEquals(encCipher.encrypt(key[:bs]), enc) - self.assertEquals(encCipher.encrypt(key[:bs]), enc2) - self.assertEquals(decCipher.decrypt(enc), key[:bs]) - self.assertEquals(decCipher.decrypt(enc2), key[:bs]) + self.assertEqual(encCipher.encrypt(key[:bs]), enc) + self.assertEqual(encCipher.encrypt(key[:bs]), enc2) + self.assertEqual(decCipher.decrypt(enc), key[:bs]) + self.assertEqual(decCipher.decrypt(enc2), key[:bs]) def test_setKeysMACs(self): @@ -1890,7 +1890,7 @@ ds = mod().digest_size else: ds = 0 - self.assertEquals(inMac.verifyDigestSize, ds) + self.assertEqual(inMac.verifyDigestSize, ds) if mod: mod, i, o, ds = outMac._getMAC(macName, key) seqid = 0 @@ -1900,7 +1900,7 @@ mac = mod(o + mod(i + packet).digest()).digest() else: mac = '' - self.assertEquals(outMac.makeMAC(seqid, data), mac) + self.assertEqual(outMac.makeMAC(seqid, data), mac) self.assertTrue(inMac.verify(seqid, data, mac)) @@ -1921,8 +1921,8 @@ Test that the counter is initialized correctly. """ counter = transport._Counter('\x00' * 8 + '\xff' * 8, 8) - self.assertEquals(counter.blockSize, 8) - self.assertEquals(counter.count.tostring(), '\x00' * 8) + self.assertEqual(counter.blockSize, 8) + self.assertEqual(counter.count.tostring(), '\x00' * 8) def test_count(self): @@ -1930,11 +1930,11 @@ Test that the counter counts incrementally and wraps at the top. """ counter = transport._Counter('\x00', 1) - self.assertEquals(counter(), '\x01') - self.assertEquals(counter(), '\x02') + self.assertEqual(counter(), '\x01') + self.assertEqual(counter(), '\x02') [counter() for i in range(252)] - self.assertEquals(counter(), '\xff') - self.assertEquals(counter(), '\x00') + self.assertEqual(counter(), '\xff') + self.assertEqual(counter(), '\x00') @@ -1978,8 +1978,8 @@ server.supportedMACs[0], server.supportedKeyExchanges[0], server.supportedCompressions[0]]) - self.assertEquals(client.errors, []) - self.assertEquals(server.errors, [( + self.assertEqual(client.errors, []) + self.assertEqual(server.errors, [( transport.DISCONNECT_CONNECTION_LOST, "user closed connection")]) if server.supportedCiphers[0] == 'none': @@ -2069,7 +2069,7 @@ # The number of bytes requested will be the value of each byte # we return. return chr(bytes) * bytes - self.assertEquals( + self.assertEqual( transport._getRandomNumber(random, 32), 4 << 24 | 4 << 16 | 4 << 8 | 4) @@ -2093,7 +2093,7 @@ results = [chr(0), chr(1), chr(127)] def random(bytes): return results.pop(0) * bytes - self.assertEquals( + self.assertEqual( transport._generateX(random, 8), 127) @@ -2108,7 +2108,7 @@ results = [chr(255), chr(64)] def random(bytes): return results.pop(0) * bytes - self.assertEquals( + self.assertEqual( transport._generateX(random, 8), 64) @@ -2143,7 +2143,7 @@ "a mapping from strings to Key objects instead." % (qual(MockOldFactoryPublicKeys),), factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.publicKeys, MockFactory().getPublicKeys()) + self.assertEqual(sshFactory.publicKeys, MockFactory().getPublicKeys()) def test_getPrivateKeysWarning(self): @@ -2158,7 +2158,7 @@ " a mapping from strings to Key objects instead." % (qual(MockOldFactoryPrivateKeys),), factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.privateKeys, + self.assertEqual(sshFactory.privateKeys, MockFactory().getPrivateKeys()) @@ -2175,7 +2175,7 @@ "a mapping from strings to Key objects instead." % (qual(MockOldFactoryPublicKeys),), factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.publicKeys, MockFactory().getPublicKeys()) + self.assertEqual(sshFactory.publicKeys, MockFactory().getPublicKeys()) def test_privateKeysWarning(self): @@ -2192,5 +2192,5 @@ " a mapping from strings to Key objects instead." % (qual(MockOldFactoryPrivateKeys),), factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.privateKeys, + self.assertEqual(sshFactory.privateKeys, MockFactory().getPrivateKeys()) diff --git a/lib/twisted-trunk/twisted/conch/test/test_userauth.py b/lib/twisted-trunk/twisted/conch/test/test_userauth.py --- a/lib/twisted-trunk/twisted/conch/test/test_userauth.py +++ b/lib/twisted-trunk/twisted/conch/test/test_userauth.py @@ -306,7 +306,7 @@ """ Check that the authentication has failed. """ - self.assertEquals(self.authServer.transport.packets[-1], + self.assertEqual(self.authServer.transport.packets[-1], (userauth.MSG_USERAUTH_FAILURE, NS('keyboard-interactive,password,publickey') + '\x00')) @@ -353,7 +353,7 @@ packet = NS('foo') + NS('none') + NS('password') + chr(0) + NS('bar') self.authServer.clock = task.Clock() d = self.authServer.ssh_USERAUTH_REQUEST(packet) - self.assertEquals(self.authServer.transport.packets, []) + self.assertEqual(self.authServer.transport.packets, []) self.authServer.clock.advance(2) return d.addCallback(self._checkFailed) @@ -372,7 +372,7 @@ packet += NS(signature) d = self.authServer.ssh_USERAUTH_REQUEST(packet) def check(ignored): - self.assertEquals(self.authServer.transport.packets, + self.assertEqual(self.authServer.transport.packets, [(userauth.MSG_USERAUTH_SUCCESS, '')]) return d.addCallback(check) @@ -413,7 +413,7 @@ + NS('ssh-rsa') + NS(blob)) d = self.authServer.ssh_USERAUTH_REQUEST(packet) def check(ignored): - self.assertEquals(self.authServer.transport.packets, + self.assertEqual(self.authServer.transport.packets, [(userauth.MSG_USERAUTH_PK_OK, NS('ssh-rsa') + NS(blob))]) return d.addCallback(check) @@ -454,7 +454,7 @@ d = self.authServer.ssh_USERAUTH_REQUEST(packet) self.authServer.ssh_USERAUTH_INFO_RESPONSE(response) def check(ignored): - self.assertEquals(self.authServer.transport.packets, + self.assertEqual(self.authServer.transport.packets, [(userauth.MSG_USERAUTH_INFO_REQUEST, (NS('') + NS('') + NS('') + '\x00\x00\x00\x02' + NS('Name: ') + '\x01' + NS('Password: ') + '\x00')), @@ -473,7 +473,7 @@ d = self.authServer.ssh_USERAUTH_REQUEST(packet) self.authServer.ssh_USERAUTH_INFO_RESPONSE(response) def check(ignored): - self.assertEquals(self.authServer.transport.packets[0], + self.assertEqual(self.authServer.transport.packets[0], (userauth.MSG_USERAUTH_INFO_REQUEST, (NS('') + NS('') + NS('') + '\x00\x00\x00\x02' + NS('Name: ') + '\x01' + NS('Password: ') + '\x00'))) @@ -515,9 +515,9 @@ + NS('') + NS('')) self.authServer.ssh_USERAUTH_REQUEST(packet) self.authServer.ssh_USERAUTH_REQUEST(packet) - self.assertEquals(self.authServer.transport.packets[-1][0], + self.assertEqual(self.authServer.transport.packets[-1][0], transport.MSG_DISCONNECT) - self.assertEquals(self.authServer.transport.packets[-1][1][3], + self.assertEqual(self.authServer.transport.packets[-1][1][3], chr(transport.DISCONNECT_PROTOCOL_ERROR)) @@ -536,7 +536,7 @@ server.serviceStarted() server.serviceStopped() server.supportedAuthentications.sort() # give a consistent order - self.assertEquals(server.supportedAuthentications, + self.assertEqual(server.supportedAuthentications, ['keyboard-interactive', 'password', 'publickey']) @@ -603,7 +603,7 @@ clearAuthServer.transport.isEncrypted = lambda x: False clearAuthServer.serviceStarted() clearAuthServer.serviceStopped() - self.assertEquals(clearAuthServer.supportedAuthentications, + self.assertEqual(clearAuthServer.supportedAuthentications, ['publickey']) # only encrypt incoming (the direction the password is sent) @@ -612,7 +612,7 @@ halfAuthServer.transport.isEncrypted = lambda x: x == 'in' halfAuthServer.serviceStarted() halfAuthServer.serviceStopped() - self.assertEquals(clearAuthServer.supportedAuthentications, + self.assertEqual(clearAuthServer.supportedAuthentications, ['publickey']) @@ -626,7 +626,7 @@ timeoutAuthServer.serviceStarted() timeoutAuthServer.clock.advance(11 * 60 * 60) timeoutAuthServer.serviceStopped() - self.assertEquals(timeoutAuthServer.transport.packets, + self.assertEqual(timeoutAuthServer.transport.packets, [(transport.MSG_DISCONNECT, '\x00' * 3 + chr(transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE) + @@ -644,7 +644,7 @@ timeoutAuthServer.serviceStarted() timeoutAuthServer.serviceStopped() timeoutAuthServer.clock.advance(11 * 60 * 60) - self.assertEquals(timeoutAuthServer.transport.packets, []) + self.assertEqual(timeoutAuthServer.transport.packets, []) self.assertFalse(timeoutAuthServer.transport.lostConnection) @@ -659,7 +659,7 @@ d = self.authServer.ssh_USERAUTH_REQUEST(packet) self.authServer.clock.advance(2) def check(ignored): - self.assertEquals(self.authServer.transport.packets[-1], + self.assertEqual(self.authServer.transport.packets[-1], (transport.MSG_DISCONNECT, '\x00' * 3 + chr(transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE) + @@ -743,9 +743,9 @@ """ Test that client is initialized properly. """ - self.assertEquals(self.authClient.user, 'foo') - self.assertEquals(self.authClient.instance.name, 'nancy') - self.assertEquals(self.authClient.transport.packets, + self.assertEqual(self.authClient.user, 'foo') + self.assertEqual(self.authClient.instance.name, 'nancy') + self.assertEqual(self.authClient.transport.packets, [(userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('none'))]) @@ -759,7 +759,7 @@ instance[0] = service self.authClient.transport.setService = stubSetService self.authClient.ssh_USERAUTH_SUCCESS('') - self.assertEquals(instance[0], self.authClient.instance) + self.assertEqual(instance[0], self.authClient.instance) def test_publickey(self): @@ -767,7 +767,7 @@ Test that the client can authenticate with a public key. """ self.authClient.ssh_USERAUTH_FAILURE(NS('publickey') + '\x00') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('publickey') + '\x00' + NS('ssh-dss') + NS(keys.Key.fromString( @@ -775,7 +775,7 @@ # that key isn't good self.authClient.ssh_USERAUTH_FAILURE(NS('publickey') + '\x00') blob = NS(keys.Key.fromString(keydata.publicRSA_openssh).blob()) - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, (NS('foo') + NS('nancy') + NS('publickey') + '\x00'+ NS('ssh-rsa') + blob))) self.authClient.ssh_USERAUTH_PK_OK(NS('ssh-rsa') @@ -785,7 +785,7 @@ + NS('nancy') + NS('publickey') + '\xff' + NS('ssh-rsa') + blob) obj = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('publickey') + '\xff' + NS('ssh-rsa') + blob + NS(obj.sign(sigData)))) @@ -806,7 +806,7 @@ authClient.tryAuth('publickey') authClient.transport.packets = [] self.assertIdentical(authClient.ssh_USERAUTH_PK_OK(''), None) - self.assertEquals(authClient.transport.packets, [ + self.assertEqual(authClient.transport.packets, [ (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('none'))]) @@ -826,7 +826,7 @@ "SSHUserAuthClient.getPublicKey() is deprecated since " "Twisted 9.0. Return a keys.Key() instead.", userauth.__file__, oldAuth.tryAuth, 'publickey') - self.assertEquals(oldAuth.transport.packets, [ + self.assertEqual(oldAuth.transport.packets, [ (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('publickey') + '\x00' + NS('ssh-rsa') + NS(keys.Key.fromString(keydata.publicRSA_openssh).blob()))]) @@ -845,7 +845,7 @@ "Return a keys.Key() instead.", userauth.__file__, oldAuth.signData, None, 'data') def _checkSignedData(sig): - self.assertEquals(sig, + self.assertEqual(sig, keys.Key.fromString(keydata.privateRSA_openssh).sign( 'data')) d.addCallback(_checkSignedData) @@ -869,11 +869,11 @@ includes changing the password. """ self.authClient.ssh_USERAUTH_FAILURE(NS('password') + '\x00') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('password') + '\x00' + NS('foo'))) self.authClient.ssh_USERAUTH_PK_OK(NS('') + NS('')) - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('password') + '\xff' + NS('foo') * 2)) @@ -893,12 +893,12 @@ """ self.authClient.ssh_USERAUTH_FAILURE(NS('keyboard-interactive') + '\x00') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('keyboard-interactive') + NS('')*2)) self.authClient.ssh_USERAUTH_PK_OK(NS('')*3 + '\x00\x00\x00\x02' + NS('Name: ') + '\xff' + NS('Password: ') + '\x00') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_INFO_RESPONSE, '\x00\x00\x00\x02' + NS('foo')*2)) @@ -912,7 +912,7 @@ self.authClient.lastAuth = 'unknown' self.authClient.transport.packets = [] self.authClient.ssh_USERAUTH_PK_OK('') - self.assertEquals(self.authClient.transport.packets, + self.assertEqual(self.authClient.transport.packets, [(userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('none'))]) @@ -936,12 +936,12 @@ self.authClient.ssh_USERAUTH_FAILURE(NS('anothermethod,password') + '\x00') # should send password packet - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('password') + '\x00' + NS('foo'))) self.authClient.ssh_USERAUTH_FAILURE( NS('firstmethod,anothermethod,password') + '\xff') - self.assertEquals(self.authClient.transport.packets[-2:], + self.assertEqual(self.authClient.transport.packets[-2:], [(255, 'here is data'), (254, 'other data')]) @@ -953,7 +953,7 @@ """ self.authClient.ssh_USERAUTH_FAILURE(NS('password') + '\x00') self.authClient.ssh_USERAUTH_FAILURE(NS('password') + '\xff') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (transport.MSG_DISCONNECT, '\x00\x00\x00\x0e' + NS('no more authentication methods available') + '\x00\x00\x00\x00')) @@ -966,7 +966,7 @@ """ self.authClient.transport.packets = [] self.authClient._ebAuth(None) - self.assertEquals(self.authClient.transport.packets, + self.assertEqual(self.authClient.transport.packets, [(userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('none'))]) @@ -1058,5 +1058,5 @@ client.serviceStarted() def check(ignored): - self.assertEquals(server.transport.service.name, 'TestService') + self.assertEqual(server.transport.service.name, 'TestService') return d.addCallback(check) diff --git a/lib/twisted-trunk/twisted/conch/test/test_window.py b/lib/twisted-trunk/twisted/conch/test/test_window.py --- a/lib/twisted-trunk/twisted/conch/test/test_window.py +++ b/lib/twisted-trunk/twisted/conch/test/test_window.py @@ -5,7 +5,7 @@ from twisted.trial.unittest import TestCase -from twisted.conch.insults.window import TopWindow +from twisted.conch.insults.window import TopWindow, ScrolledArea, TextOutput class TopWindowTests(TestCase): @@ -47,3 +47,21 @@ root.repaint() self.assertEqual(len(paints), 1) self.assertEqual(len(scheduled), 1) + + + +class ScrolledAreaTests(TestCase): + """ + Tests for L{ScrolledArea}, a widget which creates a viewport containing + another widget and can reposition that viewport using scrollbars. + """ + def test_parent(self): + """ + The parent of the widget passed to L{ScrolledArea} is set to a new + L{Viewport} created by the L{ScrolledArea} which itself has the + L{ScrolledArea} instance as its parent. + """ + widget = TextOutput() + scrolled = ScrolledArea(widget) + self.assertIdentical(widget.parent, scrolled._viewport) + self.assertIdentical(scrolled._viewport.parent, scrolled) diff --git a/lib/twisted-trunk/twisted/internet/_win32serialport.py b/lib/twisted-trunk/twisted/internet/_win32serialport.py --- a/lib/twisted-trunk/twisted/internet/_win32serialport.py +++ b/lib/twisted-trunk/twisted/internet/_win32serialport.py @@ -1,16 +1,13 @@ # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - """ Serial port support for Windows. -Requires PySerial and win32all, and needs to be used with win32event -reactor. +Requires PySerial and pywin32. """ # system imports -import os import serial from serial import PARITY_NONE, PARITY_EVEN, PARITY_ODD from serial import STOPBITS_ONE, STOPBITS_TWO @@ -18,9 +15,7 @@ import win32file, win32event # twisted imports -from twisted.protocols import basic from twisted.internet import abstract -from twisted.python import log # sibling imports from serialport import BaseSerialPort diff --git a/lib/twisted-trunk/twisted/internet/abstract.py b/lib/twisted-trunk/twisted/internet/abstract.py --- a/lib/twisted-trunk/twisted/internet/abstract.py +++ b/lib/twisted-trunk/twisted/internet/abstract.py @@ -175,7 +175,8 @@ def doRead(self): - """Called when data is avaliable for reading. + """ + Called when data is available for reading. Subclasses must override this method. The result will be interpreted in the same way as a result of doWrite(). diff --git a/lib/twisted-trunk/twisted/internet/base.py b/lib/twisted-trunk/twisted/internet/base.py --- a/lib/twisted-trunk/twisted/internet/base.py +++ b/lib/twisted-trunk/twisted/internet/base.py @@ -452,9 +452,15 @@ an explicit state machine. @ivar running: See L{IReactorCore.running} + + @ivar _registerAsIOThread: A flag controlling whether the reactor will + register the thread it is running in as the I/O thread when it starts. + If C{True}, registration will be done, otherwise it will not be. """ implements(IReactorCore, IReactorTime, IReactorPluggableResolver) + _registerAsIOThread = True + _stopped = True installed = False usingThreads = False @@ -674,7 +680,8 @@ raise error.ReactorNotRestartable() self._started = True self._stopped = False - threadable.registerAsIOThread() + if self._registerAsIOThread: + threadable.registerAsIOThread() self.fireSystemEvent('startup') diff --git a/lib/twisted-trunk/twisted/internet/default.py b/lib/twisted-trunk/twisted/internet/default.py --- a/lib/twisted-trunk/twisted/internet/default.py +++ b/lib/twisted-trunk/twisted/internet/default.py @@ -1,21 +1,50 @@ -# -*- test-case-name: twisted.test.test_internet -*- -# $Id: default.py,v 1.90 2004/01/06 22:35:22 warner Exp $ -# +# -*- test-case-name: twisted.internet.test.test_default -*- # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +""" +The most suitable default reactor for the current platform. -""" -Deprecated module that used to contain SelectReactor and PosixReactorBase - -Maintainer: Itamar Shtull-Trauring +Depending on a specific application's needs, some other reactor may in +fact be better. """ -import warnings -warnings.warn("twisted.internet.default is deprecated. Use posixbase or selectreactor instead.", category=DeprecationWarning) +__all__ = ["install"] -# Backwards compat -from posixbase import PosixReactorBase -from selectreactor import SelectReactor, install +from twisted.python.runtime import platform -__all__ = ["install", "PosixReactorBase", "SelectReactor"] + +def _getInstallFunction(platform): + """ + Return a function to install the reactor most suited for the given platform. + + @param platform: The platform for which to select a reactor. + @type platform: L{twisted.python.runtime.Platform} + + @return: A zero-argument callable which will install the selected + reactor. + """ + # Linux: Once is fixed + # epoll should be the default. + # + # OS X: poll(2) is not exposed by Python because it doesn't + # support all file descriptors (in particular, lack of PTY support + # is a problem) -- see . kqueue + # reactor is being rewritten (see + # ), and also has same + # restriction as poll(2) as far PTY support goes. + # + # Windows: IOCP should eventually be default, but still has a few + # remaining bugs, + # e.g. . + # + # We therefore choose poll(2) on non-OS X POSIX platforms, and + # select(2) everywhere else. + if platform.getType() == 'posix' and not platform.isMacOSX(): + from twisted.internet.pollreactor import install + else: + from twisted.internet.selectreactor import install + return install + + +install = _getInstallFunction(platform) diff --git a/lib/twisted-trunk/twisted/internet/defer.py b/lib/twisted-trunk/twisted/internet/defer.py --- a/lib/twisted-trunk/twisted/internet/defer.py +++ b/lib/twisted-trunk/twisted/internet/defer.py @@ -17,6 +17,7 @@ """ import traceback +import types import warnings from sys import exc_info @@ -132,7 +133,7 @@ try: result = f(*args, **kw) except: - return fail(failure.Failure()) + return fail(failure.Failure(captureVars=Deferred.debug)) if isinstance(result, Deferred): return result @@ -382,7 +383,9 @@ @raise NoCurrentExceptionError: If C{fail} is C{None} but there is no current exception state. """ - if not isinstance(fail, failure.Failure): + if fail is None: + fail = failure.Failure(captureVars=self.debug) + elif not isinstance(fail, failure.Failure): fail = failure.Failure(fail) self._startRunCallbacks(fail) @@ -543,7 +546,9 @@ finally: current._runningCallbacks = False except: - current.result = failure.Failure() + # Including full frame information in the Failure is quite + # expensive, so we avoid it unless self.debug is set. + current.result = failure.Failure(captureVars=self.debug) else: if isinstance(current.result, Deferred): # The result is another Deferred. If it has a result, @@ -1138,7 +1143,17 @@ raise Exception('DESTROY ALL LIFE') """ def unwindGenerator(*args, **kwargs): - return _inlineCallbacks(None, f(*args, **kwargs), Deferred()) + try: + gen = f(*args, **kwargs) + except _DefGen_Return: + raise TypeError( + "inlineCallbacks requires %r to produce a generator; instead" + "caught returnValue being used in a non-generator" % (f,)) + if not isinstance(gen, types.GeneratorType): + raise TypeError( + "inlineCallbacks requires %r to produce a generator; " + "instead got %r" % (f, gen)) + return _inlineCallbacks(None, gen, Deferred()) return mergeFunctionMetadata(f, unwindGenerator) diff --git a/lib/twisted-trunk/twisted/internet/inotify.py b/lib/twisted-trunk/twisted/internet/inotify.py --- a/lib/twisted-trunk/twisted/internet/inotify.py +++ b/lib/twisted-trunk/twisted/internet/inotify.py @@ -376,7 +376,9 @@ @type path: L{FilePath} """ wd = self._isWatched(path) - if wd is not False: + if wd is None: + raise KeyError("%r is not watched" % (path,)) + else: self._rmWatch(wd) diff --git a/lib/twisted-trunk/twisted/internet/interfaces.py b/lib/twisted-trunk/twisted/internet/interfaces.py --- a/lib/twisted-trunk/twisted/internet/interfaces.py +++ b/lib/twisted-trunk/twisted/internet/interfaces.py @@ -1150,16 +1150,25 @@ +deprecatedModuleAttribute(Version("Twisted", 11, 1, 0), + "Please use IConsumer (and IConsumer.unregisterProducer) instead.", + __name__, "IFinishableConsumer") + class IFinishableConsumer(IConsumer): """ - A Consumer for producers that finish. + A Consumer for producers that finish. This interface offers no advantages + over L{IConsumer} and is deprecated. Please use + L{IConsumer.unregisterProducer} instead of L{IFinishableConsumer.finish}. """ def finish(): """ - The producer has finished producing. + The producer has finished producing. This method is deprecated. + Please use L{IConsumer.unregisterProducer} instead. """ + + class IProducer(Interface): """ A producer produces data for a consumer. diff --git a/lib/twisted-trunk/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c b/lib/twisted-trunk/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c --- a/lib/twisted-trunk/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c +++ b/lib/twisted-trunk/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c @@ -1,4 +1,4 @@ -/* Generated by Cython 0.14.1 on Wed Mar 16 15:58:08 2011 */ +/* Generated by Cython 0.14.1 on Sat May 14 18:30:23 2011 */ #define PY_SSIZE_T_CLEAN #include "Python.h" @@ -223,6 +223,7 @@ #include "io.h" #include "errno.h" #include "winsock2.h" +#include "ws2tcpip.h" #include "windows.h" #include "python.h" #include "string.h" @@ -326,7 +327,7 @@ /* Type declarations */ -/* "iocpsupport.pyx":104 +/* "iocpsupport.pyx":114 * # BOOL (*lpTransmitFile)(SOCKET s, HANDLE hFile, DWORD size, DWORD buffer_size, OVERLAPPED *ov, TRANSMIT_FILE_BUFFERS *buff, DWORD flags) * * cdef struct myOVERLAPPED: # <<<<<<<<<<<<<< @@ -339,7 +340,7 @@ struct PyObject *obj; }; -/* "iocpsupport.pyx":128 +/* "iocpsupport.pyx":138 * setattr(self, k, v) * * cdef class CompletionPort: # <<<<<<<<<<<<<< @@ -423,6 +424,80 @@ static CYTHON_INLINE int __Pyx_CheckKeywordStrings(PyObject *kwdict, const char* function_name, int kw_allowed); /*proto*/ + +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (!j) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} + + +#define __Pyx_GetItemInt_List(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \ + __Pyx_GetItemInt_List_Fast(o, i) : \ + __Pyx_GetItemInt_Generic(o, to_py_func(i))) + +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i) { + if (likely(o != Py_None)) { + if (likely((0 <= i) & (i < PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, i); + Py_INCREF(r); + return r; + } + else if ((-PyList_GET_SIZE(o) <= i) & (i < 0)) { + PyObject *r = PyList_GET_ITEM(o, PyList_GET_SIZE(o) + i); + Py_INCREF(r); + return r; + } + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +#define __Pyx_GetItemInt_Tuple(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \ + __Pyx_GetItemInt_Tuple_Fast(o, i) : \ + __Pyx_GetItemInt_Generic(o, to_py_func(i))) + +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i) { + if (likely(o != Py_None)) { + if (likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, i); + Py_INCREF(r); + return r; + } + else if ((-PyTuple_GET_SIZE(o) <= i) & (i < 0)) { + PyObject *r = PyTuple_GET_ITEM(o, PyTuple_GET_SIZE(o) + i); + Py_INCREF(r); + return r; + } + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + + +#define __Pyx_GetItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \ + __Pyx_GetItemInt_Fast(o, i) : \ + __Pyx_GetItemInt_Generic(o, to_py_func(i))) + +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i) { + PyObject *r; + if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) { + r = PyList_GET_ITEM(o, i); + Py_INCREF(r); + } + else if (PyTuple_CheckExact(o) && ((0 <= i) & (i < PyTuple_GET_SIZE(o)))) { + r = PyTuple_GET_ITEM(o, i); + Py_INCREF(r); + } + else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0))) { + r = PySequence_GetItem(o, i); + } + else { + r = __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); + } + return r; +} + static CYTHON_INLINE long __Pyx_div_long(long, long); /* proto */ static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases); /*proto*/ @@ -498,12 +573,15 @@ static PyObject *__pyx_builtin_WindowsError; static char __pyx_k_1[] = "CreateIoCompletionPort"; static char __pyx_k_2[] = "PostQueuedCompletionStatus"; -static char __pyx_k_3[] = "invalid IP address"; -static char __pyx_k_4[] = "ConnectEx is not available on this system"; -static char __pyx_k_5[] = "unsupported address family"; -static char __pyx_k_6[] = "second argument needs to be a list"; -static char __pyx_k_7[] = "length of address length buffer needs to be sizeof(int)"; -static char __pyx_k_8[] = "Failed to initialize Winsock function vectors"; +static char __pyx_k_3[] = ":"; +static char __pyx_k_5[] = "["; +static char __pyx_k_6[] = "]"; +static char __pyx_k_7[] = "invalid IP address"; +static char __pyx_k_8[] = "ConnectEx is not available on this system"; +static char __pyx_k_9[] = "unsupported address family"; +static char __pyx_k_10[] = "second argument needs to be a list"; +static char __pyx_k_11[] = "length of address length buffer needs to be sizeof(int)"; +static char __pyx_k_12[] = "Failed to initialize Winsock function vectors"; static char __pyx_k__s[] = "s"; static char __pyx_k__buf[] = "buf"; static char __pyx_k__key[] = "key"; @@ -522,6 +600,7 @@ static char __pyx_k__owner[] = "owner"; static char __pyx_k__accept[] = "accept"; static char __pyx_k__handle[] = "handle"; +static char __pyx_k__rsplit[] = "rsplit"; static char __pyx_k__s_addr[] = "s_addr"; static char __pyx_k__socket[] = "socket"; static char __pyx_k__connect[] = "connect"; @@ -538,6 +617,7 @@ static char __pyx_k__addr_buff[] = "addr_buff"; static char __pyx_k__listening[] = "listening"; static char __pyx_k__sa_family[] = "sa_family"; +static char __pyx_k__sin6_port[] = "sin6_port"; static char __pyx_k__ValueError[] = "ValueError"; static char __pyx_k__getsockopt[] = "getsockopt"; static char __pyx_k__maxAddrLen[] = "maxAddrLen"; @@ -551,17 +631,22 @@ static char __pyx_k__iAddressFamily[] = "iAddressFamily"; static char __pyx_k__get_accept_addrs[] = "get_accept_addrs"; static char __pyx_k__AllocateReadBuffer[] = "AllocateReadBuffer"; +static char __pyx_k__WSAAddressToString[] = "WSAAddressToString"; static PyObject *__pyx_n_s_1; +static PyObject *__pyx_kp_s_11; +static PyObject *__pyx_kp_s_12; static PyObject *__pyx_n_s_2; static PyObject *__pyx_kp_s_3; -static PyObject *__pyx_kp_s_4; static PyObject *__pyx_kp_s_5; +static PyObject *__pyx_kp_s_6; static PyObject *__pyx_kp_s_7; static PyObject *__pyx_kp_s_8; +static PyObject *__pyx_kp_s_9; static PyObject *__pyx_n_s__AllocateReadBuffer; static PyObject *__pyx_n_s__Event; static PyObject *__pyx_n_s__MemoryError; static PyObject *__pyx_n_s__ValueError; +static PyObject *__pyx_n_s__WSAAddressToString; static PyObject *__pyx_n_s__WindowsError; static PyObject *__pyx_n_s____init__; static PyObject *__pyx_n_s____main__; @@ -596,18 +681,22 @@ static PyObject *__pyx_n_s__port; static PyObject *__pyx_n_s__recv; static PyObject *__pyx_n_s__recvfrom; +static PyObject *__pyx_n_s__rsplit; static PyObject *__pyx_n_s__s; static PyObject *__pyx_n_s__s_addr; static PyObject *__pyx_n_s__sa_data; static PyObject *__pyx_n_s__sa_family; static PyObject *__pyx_n_s__self; static PyObject *__pyx_n_s__send; +static PyObject *__pyx_n_s__sin6_port; static PyObject *__pyx_n_s__sin_addr; static PyObject *__pyx_n_s__sin_port; static PyObject *__pyx_n_s__socket; static PyObject *__pyx_int_0; - -/* "iocpsupport.pyx":108 +static PyObject *__pyx_int_1; +static PyObject *__pyx_k_tuple_4; + +/* "iocpsupport.pyx":118 * PyObject *obj * * cdef myOVERLAPPED *makeOV() except NULL: # <<<<<<<<<<<<<< @@ -622,17 +711,17 @@ int __pyx_t_2; __Pyx_RefNannySetupContext("makeOV"); - /* "iocpsupport.pyx":110 + /* "iocpsupport.pyx":120 * cdef myOVERLAPPED *makeOV() except NULL: * cdef myOVERLAPPED *res * res = PyMem_Malloc(sizeof(myOVERLAPPED)) # <<<<<<<<<<<<<< * if not res: * raise MemoryError */ - __pyx_t_1 = PyMem_Malloc((sizeof(struct __pyx_t_11iocpsupport_myOVERLAPPED))); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyMem_Malloc((sizeof(struct __pyx_t_11iocpsupport_myOVERLAPPED))); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_res = ((struct __pyx_t_11iocpsupport_myOVERLAPPED *)__pyx_t_1); - /* "iocpsupport.pyx":111 + /* "iocpsupport.pyx":121 * cdef myOVERLAPPED *res * res = PyMem_Malloc(sizeof(myOVERLAPPED)) * if not res: # <<<<<<<<<<<<<< @@ -642,19 +731,19 @@ __pyx_t_2 = (!(__pyx_v_res != 0)); if (__pyx_t_2) { - /* "iocpsupport.pyx":112 + /* "iocpsupport.pyx":122 * res = PyMem_Malloc(sizeof(myOVERLAPPED)) * if not res: * raise MemoryError # <<<<<<<<<<<<<< * memset(res, 0, sizeof(myOVERLAPPED)) * return res */ - PyErr_NoMemory(); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + PyErr_NoMemory(); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L3; } __pyx_L3:; - /* "iocpsupport.pyx":113 + /* "iocpsupport.pyx":123 * if not res: * raise MemoryError * memset(res, 0, sizeof(myOVERLAPPED)) # <<<<<<<<<<<<<< @@ -663,7 +752,7 @@ */ memset(__pyx_v_res, 0, (sizeof(struct __pyx_t_11iocpsupport_myOVERLAPPED))); - /* "iocpsupport.pyx":114 + /* "iocpsupport.pyx":124 * raise MemoryError * memset(res, 0, sizeof(myOVERLAPPED)) * return res # <<<<<<<<<<<<<< @@ -683,7 +772,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":116 +/* "iocpsupport.pyx":126 * return res * * cdef void raise_error(int err, object message) except *: # <<<<<<<<<<<<<< @@ -697,7 +786,7 @@ PyObject *__pyx_t_3 = NULL; __Pyx_RefNannySetupContext("raise_error"); - /* "iocpsupport.pyx":117 + /* "iocpsupport.pyx":127 * * cdef void raise_error(int err, object message) except *: * if not err: # <<<<<<<<<<<<<< @@ -707,7 +796,7 @@ __pyx_t_1 = (!__pyx_v_err); if (__pyx_t_1) { - /* "iocpsupport.pyx":118 + /* "iocpsupport.pyx":128 * cdef void raise_error(int err, object message) except *: * if not err: * err = GetLastError() # <<<<<<<<<<<<<< @@ -719,16 +808,16 @@ } __pyx_L3:; - /* "iocpsupport.pyx":119 + /* "iocpsupport.pyx":129 * if not err: * err = GetLastError() * raise WindowsError(message, err) # <<<<<<<<<<<<<< * * class Event: */ - __pyx_t_2 = PyInt_FromLong(__pyx_v_err); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyInt_FromLong(__pyx_v_err); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_3)); __Pyx_INCREF(__pyx_v_message); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_message); @@ -736,12 +825,12 @@ PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = PyObject_Call(__pyx_builtin_WindowsError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyObject_Call(__pyx_builtin_WindowsError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0; __Pyx_Raise(__pyx_t_2, 0, 0); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L0; __pyx_L1_error:; @@ -752,7 +841,7 @@ __Pyx_RefNannyFinishContext(); } -/* "iocpsupport.pyx":122 +/* "iocpsupport.pyx":132 * * class Event: * def __init__(self, callback, owner, **kw): # <<<<<<<<<<<<<< @@ -801,17 +890,17 @@ values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__callback); if (likely(values[1])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } case 2: values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__owner); if (likely(values[2])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_kw, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_kw, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } __pyx_v_self = values[0]; __pyx_v_callback = values[1]; @@ -825,7 +914,7 @@ } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_DECREF(__pyx_v_kw); __Pyx_AddTraceback("iocpsupport.Event.__init__"); @@ -835,25 +924,25 @@ __pyx_v_k = Py_None; __Pyx_INCREF(Py_None); __pyx_v_v = Py_None; __Pyx_INCREF(Py_None); - /* "iocpsupport.pyx":123 + /* "iocpsupport.pyx":133 * class Event: * def __init__(self, callback, owner, **kw): * self.callback = callback # <<<<<<<<<<<<<< * self.owner = owner * for k, v in kw.items(): */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__callback, __pyx_v_callback) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - /* "iocpsupport.pyx":124 + if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__callback, __pyx_v_callback) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + + /* "iocpsupport.pyx":134 * def __init__(self, callback, owner, **kw): * self.callback = callback * self.owner = owner # <<<<<<<<<<<<<< * for k, v in kw.items(): * setattr(self, k, v) */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__owner, __pyx_v_owner) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - /* "iocpsupport.pyx":125 + if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__owner, __pyx_v_owner) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + + /* "iocpsupport.pyx":135 * self.callback = callback * self.owner = owner * for k, v in kw.items(): # <<<<<<<<<<<<<< @@ -861,14 +950,14 @@ * */ if (unlikely(__pyx_v_kw == Py_None)) { - PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'items'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'items'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } - __pyx_t_2 = PyDict_Items(__pyx_v_kw); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyDict_Items(__pyx_v_kw); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) { __pyx_t_1 = 0; __pyx_t_3 = __pyx_t_2; __Pyx_INCREF(__pyx_t_3); } else { - __pyx_t_1 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); } __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; @@ -882,7 +971,7 @@ } else { __pyx_t_2 = PyIter_Next(__pyx_t_3); if (!__pyx_t_2) { - if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} break; } __Pyx_GOTREF(__pyx_t_2); @@ -899,14 +988,14 @@ __pyx_v_v = __pyx_t_5; __pyx_t_5 = 0; } else { - __pyx_t_6 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_6 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_6, 0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_6, 0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = __Pyx_UnpackItem(__pyx_t_6, 1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = __Pyx_UnpackItem(__pyx_t_6, 1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_5); - if (__Pyx_EndUnpack(__pyx_t_6, 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (__Pyx_EndUnpack(__pyx_t_6, 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; __Pyx_DECREF(__pyx_v_k); __pyx_v_k = __pyx_t_4; @@ -916,7 +1005,7 @@ __pyx_t_5 = 0; } - /* "iocpsupport.pyx":126 + /* "iocpsupport.pyx":136 * self.owner = owner * for k, v in kw.items(): * setattr(self, k, v) # <<<<<<<<<<<<<< @@ -925,7 +1014,7 @@ */ __pyx_t_2 = __pyx_v_self; __Pyx_INCREF(__pyx_t_2); - __pyx_t_7 = PyObject_SetAttr(__pyx_t_2, __pyx_v_k, __pyx_v_v); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_7 = PyObject_SetAttr(__pyx_t_2, __pyx_v_k, __pyx_v_v); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; } __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; @@ -949,7 +1038,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":130 +/* "iocpsupport.pyx":140 * cdef class CompletionPort: * cdef HANDLE port * def __init__(self): # <<<<<<<<<<<<<< @@ -969,7 +1058,7 @@ __Pyx_RaiseArgtupleInvalid("__init__", 1, 0, 0, PyTuple_GET_SIZE(__pyx_args)); return -1;} if (unlikely(__pyx_kwds) && unlikely(PyDict_Size(__pyx_kwds) > 0) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__init__", 0))) return -1; - /* "iocpsupport.pyx":132 + /* "iocpsupport.pyx":142 * def __init__(self): * cdef HANDLE res * res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0) # <<<<<<<<<<<<<< @@ -978,7 +1067,7 @@ */ __pyx_v_res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); - /* "iocpsupport.pyx":133 + /* "iocpsupport.pyx":143 * cdef HANDLE res * res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0) * if not res: # <<<<<<<<<<<<<< @@ -988,7 +1077,7 @@ __pyx_t_1 = (!__pyx_v_res); if (__pyx_t_1) { - /* "iocpsupport.pyx":134 + /* "iocpsupport.pyx":144 * res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0) * if not res: * raise_error(0, 'CreateIoCompletionPort') # <<<<<<<<<<<<<< @@ -998,13 +1087,13 @@ __pyx_t_2 = 0; __pyx_t_3 = ((PyObject *)__pyx_n_s_1); __Pyx_INCREF(__pyx_t_3); - __pyx_f_11iocpsupport_raise_error(__pyx_t_2, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(__pyx_t_2, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; goto __pyx_L5; } __pyx_L5:; - /* "iocpsupport.pyx":135 + /* "iocpsupport.pyx":145 * if not res: * raise_error(0, 'CreateIoCompletionPort') * self.port = res # <<<<<<<<<<<<<< @@ -1024,7 +1113,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":137 +/* "iocpsupport.pyx":147 * self.port = res * * def addHandle(self, long handle, long key=0): # <<<<<<<<<<<<<< @@ -1064,33 +1153,33 @@ } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "addHandle") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "addHandle") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } - __pyx_v_handle = __Pyx_PyInt_AsLong(values[0]); if (unlikely((__pyx_v_handle == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_handle = __Pyx_PyInt_AsLong(values[0]); if (unlikely((__pyx_v_handle == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L3_error;} if (values[1]) { - __pyx_v_key = __Pyx_PyInt_AsLong(values[1]); if (unlikely((__pyx_v_key == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_key = __Pyx_PyInt_AsLong(values[1]); if (unlikely((__pyx_v_key == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } else { __pyx_v_key = ((long)0); } } else { __pyx_v_key = ((long)0); switch (PyTuple_GET_SIZE(__pyx_args)) { - case 2: __pyx_v_key = __Pyx_PyInt_AsLong(PyTuple_GET_ITEM(__pyx_args, 1)); if (unlikely((__pyx_v_key == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - case 1: __pyx_v_handle = __Pyx_PyInt_AsLong(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_handle == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + case 2: __pyx_v_key = __Pyx_PyInt_AsLong(PyTuple_GET_ITEM(__pyx_args, 1)); if (unlikely((__pyx_v_key == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + case 1: __pyx_v_handle = __Pyx_PyInt_AsLong(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_handle == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L3_error;} break; default: goto __pyx_L5_argtuple_error; } } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("addHandle", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("addHandle", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("iocpsupport.CompletionPort.addHandle"); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":139 + /* "iocpsupport.pyx":149 * def addHandle(self, long handle, long key=0): * cdef HANDLE res * res = CreateIoCompletionPort(handle, self.port, key, 0) # <<<<<<<<<<<<<< @@ -1099,7 +1188,7 @@ */ __pyx_v_res = CreateIoCompletionPort(__pyx_v_handle, ((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port, __pyx_v_key, 0); - /* "iocpsupport.pyx":140 + /* "iocpsupport.pyx":150 * cdef HANDLE res * res = CreateIoCompletionPort(handle, self.port, key, 0) * if not res: # <<<<<<<<<<<<<< @@ -1109,7 +1198,7 @@ __pyx_t_1 = (!__pyx_v_res); if (__pyx_t_1) { - /* "iocpsupport.pyx":141 + /* "iocpsupport.pyx":151 * res = CreateIoCompletionPort(handle, self.port, key, 0) * if not res: * raise_error(0, 'CreateIoCompletionPort') # <<<<<<<<<<<<<< @@ -1119,7 +1208,7 @@ __pyx_t_2 = 0; __pyx_t_3 = ((PyObject *)__pyx_n_s_1); __Pyx_INCREF(__pyx_t_3); - __pyx_f_11iocpsupport_raise_error(__pyx_t_2, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(__pyx_t_2, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; goto __pyx_L6; } @@ -1137,7 +1226,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":143 +/* "iocpsupport.pyx":153 * raise_error(0, 'CreateIoCompletionPort') * * def getEvent(self, long timeout): # <<<<<<<<<<<<<< @@ -1162,7 +1251,7 @@ PyObject *__pyx_t_5 = NULL; __Pyx_RefNannySetupContext("getEvent"); assert(__pyx_arg_timeout); { - __pyx_v_timeout = __Pyx_PyInt_AsLong(__pyx_arg_timeout); if (unlikely((__pyx_v_timeout == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_timeout = __Pyx_PyInt_AsLong(__pyx_arg_timeout); if (unlikely((__pyx_v_timeout == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -1172,7 +1261,7 @@ __pyx_L4_argument_unpacking_done:; __pyx_v_obj = Py_None; __Pyx_INCREF(Py_None); - /* "iocpsupport.pyx":148 + /* "iocpsupport.pyx":158 * cdef myOVERLAPPED *ov * * _save = PyEval_SaveThread() # <<<<<<<<<<<<<< @@ -1181,7 +1270,7 @@ */ __pyx_v__save = PyEval_SaveThread(); - /* "iocpsupport.pyx":149 + /* "iocpsupport.pyx":159 * * _save = PyEval_SaveThread() * rc = GetQueuedCompletionStatus(self.port, &bytes, &key, &ov, timeout) # <<<<<<<<<<<<<< @@ -1190,7 +1279,7 @@ */ __pyx_v_rc = GetQueuedCompletionStatus(((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port, (&__pyx_v_bytes), (&__pyx_v_key), ((OVERLAPPED **)(&__pyx_v_ov)), __pyx_v_timeout); - /* "iocpsupport.pyx":150 + /* "iocpsupport.pyx":160 * _save = PyEval_SaveThread() * rc = GetQueuedCompletionStatus(self.port, &bytes, &key, &ov, timeout) * PyEval_RestoreThread(_save) # <<<<<<<<<<<<<< @@ -1199,7 +1288,7 @@ */ PyEval_RestoreThread(__pyx_v__save); - /* "iocpsupport.pyx":152 + /* "iocpsupport.pyx":162 * PyEval_RestoreThread(_save) * * if not rc: # <<<<<<<<<<<<<< @@ -1209,7 +1298,7 @@ __pyx_t_1 = (!__pyx_v_rc); if (__pyx_t_1) { - /* "iocpsupport.pyx":153 + /* "iocpsupport.pyx":163 * * if not rc: * rc = GetLastError() # <<<<<<<<<<<<<< @@ -1221,7 +1310,7 @@ } /*else*/ { - /* "iocpsupport.pyx":155 + /* "iocpsupport.pyx":165 * rc = GetLastError() * else: * rc = 0 # <<<<<<<<<<<<<< @@ -1232,7 +1321,7 @@ } __pyx_L5:; - /* "iocpsupport.pyx":157 + /* "iocpsupport.pyx":167 * rc = 0 * * obj = None # <<<<<<<<<<<<<< @@ -1243,7 +1332,7 @@ __Pyx_DECREF(__pyx_v_obj); __pyx_v_obj = Py_None; - /* "iocpsupport.pyx":158 + /* "iocpsupport.pyx":168 * * obj = None * if ov: # <<<<<<<<<<<<<< @@ -1253,7 +1342,7 @@ __pyx_t_1 = (__pyx_v_ov != 0); if (__pyx_t_1) { - /* "iocpsupport.pyx":159 + /* "iocpsupport.pyx":169 * obj = None * if ov: * if ov.obj: # <<<<<<<<<<<<<< @@ -1263,7 +1352,7 @@ __pyx_t_1 = (__pyx_v_ov->obj != 0); if (__pyx_t_1) { - /* "iocpsupport.pyx":160 + /* "iocpsupport.pyx":170 * if ov: * if ov.obj: * obj = ov.obj # <<<<<<<<<<<<<< @@ -1274,7 +1363,7 @@ __Pyx_DECREF(__pyx_v_obj); __pyx_v_obj = ((PyObject *)__pyx_v_ov->obj); - /* "iocpsupport.pyx":161 + /* "iocpsupport.pyx":171 * if ov.obj: * obj = ov.obj * Py_DECREF(obj) # we are stealing a reference here # <<<<<<<<<<<<<< @@ -1286,7 +1375,7 @@ } __pyx_L7:; - /* "iocpsupport.pyx":162 + /* "iocpsupport.pyx":172 * obj = ov.obj * Py_DECREF(obj) # we are stealing a reference here * PyMem_Free(ov) # <<<<<<<<<<<<<< @@ -1298,7 +1387,7 @@ } __pyx_L6:; - /* "iocpsupport.pyx":164 + /* "iocpsupport.pyx":174 * PyMem_Free(ov) * * return (rc, bytes, key, obj) # <<<<<<<<<<<<<< @@ -1306,13 +1395,13 @@ * def postEvent(self, unsigned long bytes, unsigned long key, obj): */ __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = PyLong_FromUnsignedLong(__pyx_v_rc); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyLong_FromUnsignedLong(__pyx_v_rc); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = PyLong_FromUnsignedLong(__pyx_v_key); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyLong_FromUnsignedLong(__pyx_v_key); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_5)); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); @@ -1346,7 +1435,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":166 +/* "iocpsupport.pyx":176 * return (rc, bytes, key, obj) * * def postEvent(self, unsigned long bytes, unsigned long key, obj): # <<<<<<<<<<<<<< @@ -1387,38 +1476,38 @@ values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__key); if (likely(values[1])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } case 2: values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__obj); if (likely(values[2])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "postEvent") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "postEvent") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } - __pyx_v_bytes = __Pyx_PyInt_AsUnsignedLong(values[0]); if (unlikely((__pyx_v_bytes == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_key = __Pyx_PyInt_AsUnsignedLong(values[1]); if (unlikely((__pyx_v_key == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_bytes = __Pyx_PyInt_AsUnsignedLong(values[0]); if (unlikely((__pyx_v_bytes == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_key = __Pyx_PyInt_AsUnsignedLong(values[1]); if (unlikely((__pyx_v_key == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_v_obj = values[2]; } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { goto __pyx_L5_argtuple_error; } else { - __pyx_v_bytes = __Pyx_PyInt_AsUnsignedLong(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_bytes == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_key = __Pyx_PyInt_AsUnsignedLong(PyTuple_GET_ITEM(__pyx_args, 1)); if (unlikely((__pyx_v_key == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_bytes = __Pyx_PyInt_AsUnsignedLong(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_bytes == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_key = __Pyx_PyInt_AsUnsignedLong(PyTuple_GET_ITEM(__pyx_args, 1)); if (unlikely((__pyx_v_key == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_v_obj = PyTuple_GET_ITEM(__pyx_args, 2); } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("iocpsupport.CompletionPort.postEvent"); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":170 + /* "iocpsupport.pyx":180 * cdef unsigned long rc * * if obj is not None: # <<<<<<<<<<<<<< @@ -1428,17 +1517,17 @@ __pyx_t_1 = (__pyx_v_obj != Py_None); if (__pyx_t_1) { - /* "iocpsupport.pyx":171 + /* "iocpsupport.pyx":181 * * if obj is not None: * ov = makeOV() # <<<<<<<<<<<<<< * Py_INCREF(obj) # give ov its own reference to obj * ov.obj = obj */ - __pyx_t_2 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_2 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 171; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_2 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 181; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_ov = __pyx_t_2; - /* "iocpsupport.pyx":172 + /* "iocpsupport.pyx":182 * if obj is not None: * ov = makeOV() * Py_INCREF(obj) # give ov its own reference to obj # <<<<<<<<<<<<<< @@ -1450,7 +1539,7 @@ Py_INCREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - /* "iocpsupport.pyx":173 + /* "iocpsupport.pyx":183 * ov = makeOV() * Py_INCREF(obj) # give ov its own reference to obj * ov.obj = obj # <<<<<<<<<<<<<< @@ -1462,7 +1551,7 @@ } /*else*/ { - /* "iocpsupport.pyx":175 + /* "iocpsupport.pyx":185 * ov.obj = obj * else: * ov = NULL # <<<<<<<<<<<<<< @@ -1473,7 +1562,7 @@ } __pyx_L6:; - /* "iocpsupport.pyx":177 + /* "iocpsupport.pyx":187 * ov = NULL * * rc = PostQueuedCompletionStatus(self.port, bytes, key, ov) # <<<<<<<<<<<<<< @@ -1482,7 +1571,7 @@ */ __pyx_v_rc = PostQueuedCompletionStatus(((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port, __pyx_v_bytes, __pyx_v_key, ((OVERLAPPED *)__pyx_v_ov)); - /* "iocpsupport.pyx":178 + /* "iocpsupport.pyx":188 * * rc = PostQueuedCompletionStatus(self.port, bytes, key, ov) * if not rc: # <<<<<<<<<<<<<< @@ -1492,7 +1581,7 @@ __pyx_t_1 = (!__pyx_v_rc); if (__pyx_t_1) { - /* "iocpsupport.pyx":179 + /* "iocpsupport.pyx":189 * rc = PostQueuedCompletionStatus(self.port, bytes, key, ov) * if not rc: * raise_error(0, 'PostQueuedCompletionStatus') # <<<<<<<<<<<<<< @@ -1502,7 +1591,7 @@ __pyx_t_4 = 0; __pyx_t_3 = ((PyObject *)__pyx_n_s_2); __Pyx_INCREF(__pyx_t_3); - __pyx_f_11iocpsupport_raise_error(__pyx_t_4, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 179; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(__pyx_t_4, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 189; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; goto __pyx_L7; } @@ -1520,7 +1609,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":181 +/* "iocpsupport.pyx":191 * raise_error(0, 'PostQueuedCompletionStatus') * * def __del__(self): # <<<<<<<<<<<<<< @@ -1533,7 +1622,7 @@ PyObject *__pyx_r = NULL; __Pyx_RefNannySetupContext("__del__"); - /* "iocpsupport.pyx":182 + /* "iocpsupport.pyx":192 * * def __del__(self): * CloseHandle(self.port) # <<<<<<<<<<<<<< @@ -1548,7 +1637,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":184 +/* "iocpsupport.pyx":194 * CloseHandle(self.port) * * def makesockaddr(object buff): # <<<<<<<<<<<<<< @@ -1567,7 +1656,7 @@ __Pyx_RefNannySetupContext("makesockaddr"); __pyx_self = __pyx_self; - /* "iocpsupport.pyx":188 + /* "iocpsupport.pyx":198 * cdef int size * * PyObject_AsReadBuffer(buff, &mem_buffer, &size) # <<<<<<<<<<<<<< @@ -1576,10 +1665,10 @@ */ __pyx_t_1 = __pyx_v_buff; __Pyx_INCREF(__pyx_t_1); - __pyx_t_2 = PyObject_AsReadBuffer(__pyx_t_1, (&__pyx_v_mem_buffer), (&__pyx_v_size)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyObject_AsReadBuffer(__pyx_t_1, (&__pyx_v_mem_buffer), (&__pyx_v_size)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 198; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "iocpsupport.pyx":190 + /* "iocpsupport.pyx":200 * PyObject_AsReadBuffer(buff, &mem_buffer, &size) * # XXX: this should really return the address family as well * return _makesockaddr(mem_buffer, size) # <<<<<<<<<<<<<< @@ -1587,7 +1676,7 @@ * cdef object _makesockaddr(sockaddr *addr, int len): */ __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __pyx_f_11iocpsupport__makesockaddr(((struct sockaddr *)__pyx_v_mem_buffer), __pyx_v_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 190; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __pyx_f_11iocpsupport__makesockaddr(((struct sockaddr *)__pyx_v_mem_buffer), __pyx_v_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 200; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; @@ -1605,26 +1694,47 @@ return __pyx_r; } -/* "iocpsupport.pyx":192 +/* "iocpsupport.pyx":202 * return _makesockaddr(mem_buffer, size) * * cdef object _makesockaddr(sockaddr *addr, int len): # <<<<<<<<<<<<<< * cdef sockaddr_in *sin - * if not len: + * cdef sockaddr_in6 *sin6 */ static PyObject *__pyx_f_11iocpsupport__makesockaddr(struct sockaddr *__pyx_v_addr, int __pyx_v_len) { struct sockaddr_in *__pyx_v_sin; + struct sockaddr_in6 *__pyx_v_sin6; + char __pyx_v_buff[256]; + int __pyx_v_rc; + __pyx_t_11iocpsupport_DWORD __pyx_v_buff_size; + PyObject *__pyx_v_host; + unsigned short __pyx_v_sa_port; + PyObject *__pyx_v_port; PyObject *__pyx_r = NULL; int __pyx_t_1; PyObject *__pyx_t_2 = NULL; PyObject *__pyx_t_3 = NULL; PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + unsigned short __pyx_t_6; + PyObject *__pyx_t_7 = NULL; __Pyx_RefNannySetupContext("_makesockaddr"); - - /* "iocpsupport.pyx":194 - * cdef object _makesockaddr(sockaddr *addr, int len): - * cdef sockaddr_in *sin + __pyx_v_host = Py_None; __Pyx_INCREF(Py_None); + __pyx_v_port = Py_None; __Pyx_INCREF(Py_None); + + /* "iocpsupport.pyx":207 + * cdef char buff[256] + * cdef int rc + * cdef DWORD buff_size = sizeof(buff) # <<<<<<<<<<<<<< + * if not len: + * return None + */ + __pyx_v_buff_size = (sizeof(__pyx_v_buff)); + + /* "iocpsupport.pyx":208 + * cdef int rc + * cdef DWORD buff_size = sizeof(buff) * if not len: # <<<<<<<<<<<<<< * return None * if addr.sa_family == AF_INET: @@ -1632,8 +1742,8 @@ __pyx_t_1 = (!__pyx_v_len); if (__pyx_t_1) { - /* "iocpsupport.pyx":195 - * cdef sockaddr_in *sin + /* "iocpsupport.pyx":209 + * cdef DWORD buff_size = sizeof(buff) * if not len: * return None # <<<<<<<<<<<<<< * if addr.sa_family == AF_INET: @@ -1647,38 +1757,46 @@ } __pyx_L3:; - /* "iocpsupport.pyx":196 + /* "iocpsupport.pyx":213 + * sin = addr + * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) + * elif addr.sa_family == AF_INET6: # <<<<<<<<<<<<<< + * sin6 = addr + * rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) + */ + switch (__pyx_v_addr->sa_family) { + + /* "iocpsupport.pyx":210 * if not len: * return None * if addr.sa_family == AF_INET: # <<<<<<<<<<<<<< * sin = addr * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) */ - __pyx_t_1 = (__pyx_v_addr->sa_family == AF_INET); - if (__pyx_t_1) { - - /* "iocpsupport.pyx":197 + case AF_INET: + + /* "iocpsupport.pyx":211 * return None * if addr.sa_family == AF_INET: * sin = addr # <<<<<<<<<<<<<< * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) - * else: + * elif addr.sa_family == AF_INET6: */ __pyx_v_sin = ((struct sockaddr_in *)__pyx_v_addr); - /* "iocpsupport.pyx":198 + /* "iocpsupport.pyx":212 * if addr.sa_family == AF_INET: * sin = addr * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) # <<<<<<<<<<<<<< - * else: - * return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) + * elif addr.sa_family == AF_INET6: + * sin6 = addr */ __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = PyString_FromString(inet_ntoa(__pyx_v_sin->sin_addr)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 198; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyString_FromString(inet_ntoa(__pyx_v_sin->sin_addr)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyInt_FromLong(ntohs(__pyx_v_sin->sin_port)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 198; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyInt_FromLong(ntohs(__pyx_v_sin->sin_port)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 198; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); @@ -1689,25 +1807,238 @@ __pyx_r = ((PyObject *)__pyx_t_4); __pyx_t_4 = 0; goto __pyx_L0; - goto __pyx_L4; - } - /*else*/ { - - /* "iocpsupport.pyx":200 + break; + + /* "iocpsupport.pyx":213 + * sin = addr * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) + * elif addr.sa_family == AF_INET6: # <<<<<<<<<<<<<< + * sin6 = addr + * rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) + */ + case AF_INET6: + + /* "iocpsupport.pyx":214 + * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) + * elif addr.sa_family == AF_INET6: + * sin6 = addr # <<<<<<<<<<<<<< + * rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) + * if rc == SOCKET_ERROR: + */ + __pyx_v_sin6 = ((struct sockaddr_in6 *)__pyx_v_addr); + + /* "iocpsupport.pyx":215 + * elif addr.sa_family == AF_INET6: + * sin6 = addr + * rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) # <<<<<<<<<<<<<< + * if rc == SOCKET_ERROR: + * raise_error(0, 'WSAAddressToString') + */ + __pyx_v_rc = WSAAddressToStringA(__pyx_v_addr, (sizeof(struct sockaddr_in6)), NULL, __pyx_v_buff, (&__pyx_v_buff_size)); + + /* "iocpsupport.pyx":216 + * sin6 = addr + * rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) + * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< + * raise_error(0, 'WSAAddressToString') + * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) + */ + __pyx_t_1 = (__pyx_v_rc == SOCKET_ERROR); + if (__pyx_t_1) { + + /* "iocpsupport.pyx":217 + * rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) + * if rc == SOCKET_ERROR: + * raise_error(0, 'WSAAddressToString') # <<<<<<<<<<<<<< + * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) + * host, port = host.rsplit(':', 1) + */ + __pyx_t_5 = 0; + __pyx_t_4 = ((PyObject *)__pyx_n_s__WSAAddressToString); + __Pyx_INCREF(__pyx_t_4); + __pyx_f_11iocpsupport_raise_error(__pyx_t_5, __pyx_t_4); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 217; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + goto __pyx_L4; + } + __pyx_L4:; + + /* "iocpsupport.pyx":218 + * if rc == SOCKET_ERROR: + * raise_error(0, 'WSAAddressToString') + * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) # <<<<<<<<<<<<<< + * host, port = host.rsplit(':', 1) + * port = int(port) + */ + __pyx_t_4 = PyString_FromString(__pyx_v_buff); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 218; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = ntohs(__pyx_v_sin6->sin6_port); + __Pyx_DECREF(__pyx_v_host); + __pyx_v_host = __pyx_t_4; + __pyx_t_4 = 0; + __pyx_v_sa_port = __pyx_t_6; + + /* "iocpsupport.pyx":219 + * raise_error(0, 'WSAAddressToString') + * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) + * host, port = host.rsplit(':', 1) # <<<<<<<<<<<<<< + * port = int(port) + * assert host[0] == '[' + */ + __pyx_t_4 = PyObject_GetAttr(__pyx_v_host, __pyx_n_s__rsplit); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_k_tuple_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (PyTuple_CheckExact(__pyx_t_3) && likely(PyTuple_GET_SIZE(__pyx_t_3) == 2)) { + PyObject* tuple = __pyx_t_3; + __pyx_t_4 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_4); + __pyx_t_2 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_v_host); + __pyx_v_host = __pyx_t_4; + __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_v_port); + __pyx_v_port = __pyx_t_2; + __pyx_t_2 = 0; + } else { + __pyx_t_7 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_7, 0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = __Pyx_UnpackItem(__pyx_t_7, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_2); + if (__Pyx_EndUnpack(__pyx_t_7, 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_v_host); + __pyx_v_host = __pyx_t_4; + __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_v_port); + __pyx_v_port = __pyx_t_2; + __pyx_t_2 = 0; + } + + /* "iocpsupport.pyx":220 + * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) + * host, port = host.rsplit(':', 1) + * port = int(port) # <<<<<<<<<<<<<< + * assert host[0] == '[' + * assert host[-1] == ']' + */ + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 220; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_3)); + __Pyx_INCREF(__pyx_v_port); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_port); + __Pyx_GIVEREF(__pyx_v_port); + __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)(&PyInt_Type))), ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 220; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_v_port); + __pyx_v_port = __pyx_t_2; + __pyx_t_2 = 0; + + /* "iocpsupport.pyx":221 + * host, port = host.rsplit(':', 1) + * port = int(port) + * assert host[0] == '[' # <<<<<<<<<<<<<< + * assert host[-1] == ']' + * assert port == sa_port + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_host, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, ((PyObject *)__pyx_kp_s_5), Py_EQ); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) { + PyErr_SetNone(PyExc_AssertionError); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + } + #endif + + /* "iocpsupport.pyx":222 + * port = int(port) + * assert host[0] == '[' + * assert host[-1] == ']' # <<<<<<<<<<<<<< + * assert port == sa_port + * return host[1:-1], port + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_host, -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = PyObject_RichCompare(__pyx_t_3, ((PyObject *)__pyx_kp_s_6), Py_EQ); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(!__pyx_t_1)) { + PyErr_SetNone(PyExc_AssertionError); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + } + #endif + + /* "iocpsupport.pyx":223 + * assert host[0] == '[' + * assert host[-1] == ']' + * assert port == sa_port # <<<<<<<<<<<<<< + * return host[1:-1], port + * else: + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + __pyx_t_2 = PyInt_FromLong(__pyx_v_sa_port); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_port, __pyx_t_2, Py_EQ); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) { + PyErr_SetNone(PyExc_AssertionError); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + } + #endif + + /* "iocpsupport.pyx":224 + * assert host[-1] == ']' + * assert port == sa_port + * return host[1:-1], port # <<<<<<<<<<<<<< + * else: + * return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PySequence_GetSlice(__pyx_v_host, 1, -1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_2)); + PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_port); + PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_port); + __Pyx_GIVEREF(__pyx_v_port); + __pyx_t_3 = 0; + __pyx_r = ((PyObject *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + break; + default: + + /* "iocpsupport.pyx":226 + * return host[1:-1], port * else: * return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) # <<<<<<<<<<<<<< * * cdef object fillinetaddr(sockaddr_in *dest, object addr): */ __Pyx_XDECREF(__pyx_r); - __pyx_t_4 = PyString_FromStringAndSize(__pyx_v_addr->sa_data, (sizeof(__pyx_v_addr->sa_data))); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 200; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_r = __pyx_t_4; - __pyx_t_4 = 0; + __pyx_t_2 = PyString_FromStringAndSize(__pyx_v_addr->sa_data, (sizeof(__pyx_v_addr->sa_data))); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; goto __pyx_L0; + break; } - __pyx_L4:; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; @@ -1715,15 +2046,18 @@ __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_7); __Pyx_AddTraceback("iocpsupport._makesockaddr"); __pyx_r = 0; __pyx_L0:; + __Pyx_DECREF(__pyx_v_host); + __Pyx_DECREF(__pyx_v_port); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } -/* "iocpsupport.pyx":202 +/* "iocpsupport.pyx":228 * return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) * * cdef object fillinetaddr(sockaddr_in *dest, object addr): # <<<<<<<<<<<<<< @@ -1746,7 +2080,7 @@ __Pyx_RefNannySetupContext("fillinetaddr"); __pyx_v_host = Py_None; __Pyx_INCREF(Py_None); - /* "iocpsupport.pyx":206 + /* "iocpsupport.pyx":232 * cdef unsigned long res * cdef char *hoststr * host, port = addr # <<<<<<<<<<<<<< @@ -1757,22 +2091,22 @@ PyObject* tuple = __pyx_v_addr; __pyx_t_1 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = __Pyx_PyInt_AsUnsignedShort(__pyx_t_2); if (unlikely((__pyx_t_3 == (unsigned short)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 206; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = __Pyx_PyInt_AsUnsignedShort(__pyx_t_2); if (unlikely((__pyx_t_3 == (unsigned short)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_v_host); __pyx_v_host = __pyx_t_1; __pyx_t_1 = 0; __pyx_v_port = __pyx_t_3; } else { - __pyx_t_4 = PyObject_GetIter(__pyx_v_addr); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 206; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyObject_GetIter(__pyx_v_addr); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); - __pyx_t_1 = __Pyx_UnpackItem(__pyx_t_4, 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 206; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __Pyx_UnpackItem(__pyx_t_4, 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_UnpackItem(__pyx_t_4, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 206; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __Pyx_UnpackItem(__pyx_t_4, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_PyInt_AsUnsignedShort(__pyx_t_2); if (unlikely((__pyx_t_3 == (unsigned short)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 206; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = __Pyx_PyInt_AsUnsignedShort(__pyx_t_2); if (unlikely((__pyx_t_3 == (unsigned short)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (__Pyx_EndUnpack(__pyx_t_4, 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 206; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (__Pyx_EndUnpack(__pyx_t_4, 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_DECREF(__pyx_v_host); __pyx_v_host = __pyx_t_1; @@ -1780,17 +2114,17 @@ __pyx_v_port = __pyx_t_3; } - /* "iocpsupport.pyx":208 + /* "iocpsupport.pyx":234 * host, port = addr * * hoststr = PyString_AsString(host) # <<<<<<<<<<<<<< * res = inet_addr(hoststr) * if res == INADDR_ANY: */ - __pyx_t_5 = PyString_AsString(__pyx_v_host); if (unlikely(__pyx_t_5 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 208; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = PyString_AsString(__pyx_v_host); if (unlikely(__pyx_t_5 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_hoststr = __pyx_t_5; - /* "iocpsupport.pyx":209 + /* "iocpsupport.pyx":235 * * hoststr = PyString_AsString(host) * res = inet_addr(hoststr) # <<<<<<<<<<<<<< @@ -1799,7 +2133,7 @@ */ __pyx_v_res = inet_addr(__pyx_v_hoststr); - /* "iocpsupport.pyx":210 + /* "iocpsupport.pyx":236 * hoststr = PyString_AsString(host) * res = inet_addr(hoststr) * if res == INADDR_ANY: # <<<<<<<<<<<<<< @@ -1809,20 +2143,20 @@ __pyx_t_6 = (__pyx_v_res == INADDR_ANY); if (__pyx_t_6) { - /* "iocpsupport.pyx":211 + /* "iocpsupport.pyx":237 * res = inet_addr(hoststr) * if res == INADDR_ANY: * raise ValueError, 'invalid IP address' # <<<<<<<<<<<<<< * dest.sin_addr.s_addr = res * */ - __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_3), 0); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 211; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_7), 0); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L3; } __pyx_L3:; - /* "iocpsupport.pyx":212 + /* "iocpsupport.pyx":238 * if res == INADDR_ANY: * raise ValueError, 'invalid IP address' * dest.sin_addr.s_addr = res # <<<<<<<<<<<<<< @@ -1831,7 +2165,7 @@ */ __pyx_v_dest->sin_addr.s_addr = __pyx_v_res; - /* "iocpsupport.pyx":214 + /* "iocpsupport.pyx":240 * dest.sin_addr.s_addr = res * * dest.sin_port = htons(port) # <<<<<<<<<<<<<< @@ -1855,7 +2189,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":216 +/* "iocpsupport.pyx":242 * dest.sin_port = htons(port) * * def AllocateReadBuffer(int size): # <<<<<<<<<<<<<< @@ -1872,7 +2206,7 @@ __Pyx_RefNannySetupContext("AllocateReadBuffer"); __pyx_self = __pyx_self; assert(__pyx_arg_size); { - __pyx_v_size = __Pyx_PyInt_AsInt(__pyx_arg_size); if (unlikely((__pyx_v_size == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 216; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_size = __Pyx_PyInt_AsInt(__pyx_arg_size); if (unlikely((__pyx_v_size == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 242; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -1881,7 +2215,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":217 + /* "iocpsupport.pyx":243 * * def AllocateReadBuffer(int size): * return PyBuffer_New(size) # <<<<<<<<<<<<<< @@ -1889,7 +2223,7 @@ * def maxAddrLen(long s): */ __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = PyBuffer_New(__pyx_v_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 217; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyBuffer_New(__pyx_v_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; @@ -1907,7 +2241,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":219 +/* "iocpsupport.pyx":245 * return PyBuffer_New(size) * * def maxAddrLen(long s): # <<<<<<<<<<<<<< @@ -1929,7 +2263,7 @@ __Pyx_RefNannySetupContext("maxAddrLen"); __pyx_self = __pyx_self; assert(__pyx_arg_s); { - __pyx_v_s = __Pyx_PyInt_AsLong(__pyx_arg_s); if (unlikely((__pyx_v_s == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_s = __Pyx_PyInt_AsLong(__pyx_arg_s); if (unlikely((__pyx_v_s == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -1938,7 +2272,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":223 + /* "iocpsupport.pyx":249 * cdef int size, rc * * size = sizeof(wsa_pi) # <<<<<<<<<<<<<< @@ -1947,7 +2281,7 @@ */ __pyx_v_size = (sizeof(__pyx_v_wsa_pi)); - /* "iocpsupport.pyx":224 + /* "iocpsupport.pyx":250 * * size = sizeof(wsa_pi) * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) # <<<<<<<<<<<<<< @@ -1956,7 +2290,7 @@ */ __pyx_v_rc = getsockopt(__pyx_v_s, SOL_SOCKET, SO_PROTOCOL_INFO, ((char *)(&__pyx_v_wsa_pi)), (&__pyx_v_size)); - /* "iocpsupport.pyx":225 + /* "iocpsupport.pyx":251 * size = sizeof(wsa_pi) * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< @@ -1966,7 +2300,7 @@ __pyx_t_1 = (__pyx_v_rc == SOCKET_ERROR); if (__pyx_t_1) { - /* "iocpsupport.pyx":226 + /* "iocpsupport.pyx":252 * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) * if rc == SOCKET_ERROR: * raise_error(WSAGetLastError(), 'getsockopt') # <<<<<<<<<<<<<< @@ -1976,13 +2310,13 @@ __pyx_t_2 = WSAGetLastError(); __pyx_t_3 = ((PyObject *)__pyx_n_s__getsockopt); __Pyx_INCREF(__pyx_t_3); - __pyx_f_11iocpsupport_raise_error(__pyx_t_2, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(__pyx_t_2, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 252; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; goto __pyx_L5; } __pyx_L5:; - /* "iocpsupport.pyx":227 + /* "iocpsupport.pyx":253 * if rc == SOCKET_ERROR: * raise_error(WSAGetLastError(), 'getsockopt') * return wsa_pi.iMaxSockAddr # <<<<<<<<<<<<<< @@ -1990,7 +2324,7 @@ * cdef int getAddrFamily(SOCKET s) except *: */ __Pyx_XDECREF(__pyx_r); - __pyx_t_3 = PyInt_FromLong(__pyx_v_wsa_pi.iMaxSockAddr); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 227; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyInt_FromLong(__pyx_v_wsa_pi.iMaxSockAddr); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 253; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __pyx_r = __pyx_t_3; __pyx_t_3 = 0; @@ -2008,7 +2342,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":229 +/* "iocpsupport.pyx":255 * return wsa_pi.iMaxSockAddr * * cdef int getAddrFamily(SOCKET s) except *: # <<<<<<<<<<<<<< @@ -2026,7 +2360,7 @@ PyObject *__pyx_t_3 = NULL; __Pyx_RefNannySetupContext("getAddrFamily"); - /* "iocpsupport.pyx":233 + /* "iocpsupport.pyx":259 * cdef int size, rc * * size = sizeof(wsa_pi) # <<<<<<<<<<<<<< @@ -2035,7 +2369,7 @@ */ __pyx_v_size = (sizeof(__pyx_v_wsa_pi)); - /* "iocpsupport.pyx":234 + /* "iocpsupport.pyx":260 * * size = sizeof(wsa_pi) * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) # <<<<<<<<<<<<<< @@ -2044,7 +2378,7 @@ */ __pyx_v_rc = getsockopt(__pyx_v_s, SOL_SOCKET, SO_PROTOCOL_INFO, ((char *)(&__pyx_v_wsa_pi)), (&__pyx_v_size)); - /* "iocpsupport.pyx":235 + /* "iocpsupport.pyx":261 * size = sizeof(wsa_pi) * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< @@ -2054,7 +2388,7 @@ __pyx_t_1 = (__pyx_v_rc == SOCKET_ERROR); if (__pyx_t_1) { - /* "iocpsupport.pyx":236 + /* "iocpsupport.pyx":262 * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) * if rc == SOCKET_ERROR: * raise_error(WSAGetLastError(), 'getsockopt') # <<<<<<<<<<<<<< @@ -2064,13 +2398,13 @@ __pyx_t_2 = WSAGetLastError(); __pyx_t_3 = ((PyObject *)__pyx_n_s__getsockopt); __Pyx_INCREF(__pyx_t_3); - __pyx_f_11iocpsupport_raise_error(__pyx_t_2, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(__pyx_t_2, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 262; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; goto __pyx_L3; } __pyx_L3:; - /* "iocpsupport.pyx":237 + /* "iocpsupport.pyx":263 * if rc == SOCKET_ERROR: * raise_error(WSAGetLastError(), 'getsockopt') * return wsa_pi.iAddressFamily # <<<<<<<<<<<<<< @@ -2091,7 +2425,7 @@ return __pyx_r; } -/* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":5 +/* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":5 * * * def accept(long listening, long accepting, object buff, object obj): # <<<<<<<<<<<<<< @@ -2179,7 +2513,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":14 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":14 * cdef myOVERLAPPED *ov * * PyObject_AsWriteBuffer(buff, &mem_buffer, &size) # <<<<<<<<<<<<<< @@ -2191,7 +2525,7 @@ __pyx_t_2 = PyObject_AsWriteBuffer(__pyx_t_1, (&__pyx_v_mem_buffer), (&__pyx_v_size)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":16 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":16 * PyObject_AsWriteBuffer(buff, &mem_buffer, &size) * * ov = makeOV() # <<<<<<<<<<<<<< @@ -2201,7 +2535,7 @@ __pyx_t_3 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_ov = __pyx_t_3; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":17 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":17 * * ov = makeOV() * if obj is not None: # <<<<<<<<<<<<<< @@ -2211,7 +2545,7 @@ __pyx_t_4 = (__pyx_v_obj != Py_None); if (__pyx_t_4) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":18 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":18 * ov = makeOV() * if obj is not None: * ov.obj = obj # <<<<<<<<<<<<<< @@ -2223,7 +2557,7 @@ } __pyx_L6:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":21 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":21 * * rc = lpAcceptEx(listening, accepting, mem_buffer, 0, size / 2, size / 2, * &bytes, ov) # <<<<<<<<<<<<<< @@ -2232,7 +2566,7 @@ */ __pyx_v_rc = lpAcceptEx(__pyx_v_listening, __pyx_v_accepting, __pyx_v_mem_buffer, 0, __Pyx_div_long(__pyx_v_size, 2), __Pyx_div_long(__pyx_v_size, 2), (&__pyx_v_bytes), ((OVERLAPPED *)__pyx_v_ov)); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":22 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":22 * rc = lpAcceptEx(listening, accepting, mem_buffer, 0, size / 2, size / 2, * &bytes, ov) * if not rc: # <<<<<<<<<<<<<< @@ -2242,7 +2576,7 @@ __pyx_t_4 = (!__pyx_v_rc); if (__pyx_t_4) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":23 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":23 * &bytes, ov) * if not rc: * rc = WSAGetLastError() # <<<<<<<<<<<<<< @@ -2251,7 +2585,7 @@ */ __pyx_v_rc = WSAGetLastError(); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":24 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":24 * if not rc: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< @@ -2261,7 +2595,7 @@ __pyx_t_4 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_4) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":25 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":25 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: * return rc # <<<<<<<<<<<<<< @@ -2281,7 +2615,7 @@ } __pyx_L7:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":28 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":28 * * # operation is in progress * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -2293,7 +2627,7 @@ Py_XINCREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":29 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":29 * # operation is in progress * Py_XINCREF(obj) * return 0 # <<<<<<<<<<<<<< @@ -2317,7 +2651,7 @@ return __pyx_r; } -/* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":31 +/* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":31 * return 0 * * def get_accept_addrs(long s, object buff): # <<<<<<<<<<<<<< @@ -2386,7 +2720,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":37 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":37 * cdef sockaddr *localaddr, *remoteaddr * * PyObject_AsReadBuffer(buff, &mem_buffer, &size) # <<<<<<<<<<<<<< @@ -2398,7 +2732,7 @@ __pyx_t_2 = PyObject_AsReadBuffer(__pyx_t_1, (&__pyx_v_mem_buffer), (&__pyx_v_size)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":39 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":39 * PyObject_AsReadBuffer(buff, &mem_buffer, &size) * * lpGetAcceptExSockaddrs(mem_buffer, 0, size / 2, size / 2, &localaddr, &locallen, &remoteaddr, &remotelen) # <<<<<<<<<<<<<< @@ -2407,7 +2741,7 @@ */ lpGetAcceptExSockaddrs(__pyx_v_mem_buffer, 0, __Pyx_div_long(__pyx_v_size, 2), __Pyx_div_long(__pyx_v_size, 2), (&__pyx_v_localaddr), (&__pyx_v_locallen), (&__pyx_v_remoteaddr), (&__pyx_v_remotelen)); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":40 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":40 * * lpGetAcceptExSockaddrs(mem_buffer, 0, size / 2, size / 2, &localaddr, &locallen, &remoteaddr, &remotelen) * return remoteaddr.sa_family, _makesockaddr(localaddr, locallen), _makesockaddr(remoteaddr, remotelen) # <<<<<<<<<<<<<< @@ -2450,7 +2784,7 @@ return __pyx_r; } -/* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":5 +/* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":5 * * * def connect(long s, object addr, object obj): # <<<<<<<<<<<<<< @@ -2530,7 +2864,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":13 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":13 * cdef sockaddr name * * if not have_connectex: # <<<<<<<<<<<<<< @@ -2544,20 +2878,20 @@ __pyx_t_3 = (!__pyx_t_2); if (__pyx_t_3) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":14 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":14 * * if not have_connectex: * raise ValueError, 'ConnectEx is not available on this system' # <<<<<<<<<<<<<< * * family = getAddrFamily(s) */ - __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_4), 0); + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_8), 0); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":16 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":16 * raise ValueError, 'ConnectEx is not available on this system' * * family = getAddrFamily(s) # <<<<<<<<<<<<<< @@ -2567,7 +2901,7 @@ __pyx_t_4 = __pyx_f_11iocpsupport_getAddrFamily(__pyx_v_s); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_family = __pyx_t_4; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":17 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":17 * * family = getAddrFamily(s) * if family == AF_INET: # <<<<<<<<<<<<<< @@ -2577,7 +2911,7 @@ __pyx_t_3 = (__pyx_v_family == AF_INET); if (__pyx_t_3) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":18 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":18 * family = getAddrFamily(s) * if family == AF_INET: * fillinetaddr(&name, addr) # <<<<<<<<<<<<<< @@ -2595,19 +2929,19 @@ } /*else*/ { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":20 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":20 * fillinetaddr(&name, addr) * else: * raise ValueError, 'unsupported address family' # <<<<<<<<<<<<<< * name.sa_family = family * */ - __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_5), 0); + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_9), 0); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } __pyx_L7:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":21 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":21 * else: * raise ValueError, 'unsupported address family' * name.sa_family = family # <<<<<<<<<<<<<< @@ -2616,7 +2950,7 @@ */ __pyx_v_name.sa_family = __pyx_v_family; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":23 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":23 * name.sa_family = family * * ov = makeOV() # <<<<<<<<<<<<<< @@ -2626,7 +2960,7 @@ __pyx_t_7 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_7 == NULL)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_ov = __pyx_t_7; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":24 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":24 * * ov = makeOV() * if obj is not None: # <<<<<<<<<<<<<< @@ -2636,7 +2970,7 @@ __pyx_t_3 = (__pyx_v_obj != Py_None); if (__pyx_t_3) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":25 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":25 * ov = makeOV() * if obj is not None: * ov.obj = obj # <<<<<<<<<<<<<< @@ -2648,7 +2982,7 @@ } __pyx_L8:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":27 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":27 * ov.obj = obj * * rc = lpConnectEx(s, &name, sizeof(name), NULL, 0, NULL, ov) # <<<<<<<<<<<<<< @@ -2657,7 +2991,7 @@ */ __pyx_v_rc = lpConnectEx(__pyx_v_s, (&__pyx_v_name), (sizeof(__pyx_v_name)), NULL, 0, NULL, ((OVERLAPPED *)__pyx_v_ov)); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":29 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":29 * rc = lpConnectEx(s, &name, sizeof(name), NULL, 0, NULL, ov) * * if not rc: # <<<<<<<<<<<<<< @@ -2667,7 +3001,7 @@ __pyx_t_3 = (!__pyx_v_rc); if (__pyx_t_3) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":30 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":30 * * if not rc: * rc = WSAGetLastError() # <<<<<<<<<<<<<< @@ -2676,7 +3010,7 @@ */ __pyx_v_rc = WSAGetLastError(); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":31 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":31 * if not rc: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< @@ -2686,7 +3020,7 @@ __pyx_t_3 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_3) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":32 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":32 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: * return rc # <<<<<<<<<<<<<< @@ -2706,7 +3040,7 @@ } __pyx_L9:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":35 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":35 * * # operation is in progress * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -2718,7 +3052,7 @@ Py_XINCREF(__pyx_t_6); __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":36 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":36 * # operation is in progress * Py_XINCREF(obj) * return 0 # <<<<<<<<<<<<<< @@ -2742,7 +3076,7 @@ return __pyx_r; } -/* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":5 +/* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":5 * * * def recv(long s, object bufflist, object obj, unsigned long flags = 0): # <<<<<<<<<<<<<< @@ -2844,7 +3178,7 @@ __pyx_L4_argument_unpacking_done:; __Pyx_INCREF(__pyx_v_bufflist); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":12 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":12 * cdef PyObject **buffers * * bufflist = PySequence_Fast(bufflist, 'second argument needs to be a list') # <<<<<<<<<<<<<< @@ -2853,14 +3187,14 @@ */ __pyx_t_1 = __pyx_v_bufflist; __Pyx_INCREF(__pyx_t_1); - __pyx_t_2 = PySequence_Fast(__pyx_t_1, __pyx_k_6); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PySequence_Fast(__pyx_t_1, __pyx_k_10); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_v_bufflist); __pyx_v_bufflist = __pyx_t_2; __pyx_t_2 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":13 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":13 * * bufflist = PySequence_Fast(bufflist, 'second argument needs to be a list') * buffcount = PySequence_Fast_GET_SIZE(bufflist) # <<<<<<<<<<<<<< @@ -2872,7 +3206,7 @@ __pyx_v_buffcount = PySequence_Fast_GET_SIZE(__pyx_t_2); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":14 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":14 * bufflist = PySequence_Fast(bufflist, 'second argument needs to be a list') * buffcount = PySequence_Fast_GET_SIZE(bufflist) * buffers = PySequence_Fast_ITEMS(bufflist) # <<<<<<<<<<<<<< @@ -2884,7 +3218,7 @@ __pyx_v_buffers = PySequence_Fast_ITEMS(__pyx_t_2); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":16 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":16 * buffers = PySequence_Fast_ITEMS(bufflist) * * ws_buf = PyMem_Malloc(buffcount*sizeof(WSABUF)) # <<<<<<<<<<<<<< @@ -2894,7 +3228,7 @@ __pyx_t_3 = PyMem_Malloc((__pyx_v_buffcount * (sizeof(WSABUF)))); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_ws_buf = ((WSABUF *)__pyx_t_3); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":18 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":18 * ws_buf = PyMem_Malloc(buffcount*sizeof(WSABUF)) * * try: # <<<<<<<<<<<<<< @@ -2903,7 +3237,7 @@ */ /*try:*/ { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":19 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":19 * * try: * for i from 0 <= i < buffcount: # <<<<<<<<<<<<<< @@ -2913,7 +3247,7 @@ __pyx_t_4 = __pyx_v_buffcount; for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_4; __pyx_v_i++) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":20 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":20 * try: * for i from 0 <= i < buffcount: * PyObject_AsWriteBuffer(buffers[i], &ws_buf[i].buf, &ws_buf[i].len) # <<<<<<<<<<<<<< @@ -2926,7 +3260,7 @@ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; } - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":22 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":22 * PyObject_AsWriteBuffer(buffers[i], &ws_buf[i].buf, &ws_buf[i].len) * * ov = makeOV() # <<<<<<<<<<<<<< @@ -2936,7 +3270,7 @@ __pyx_t_6 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_6 == NULL)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L7;} __pyx_v_ov = __pyx_t_6; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":23 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":23 * * ov = makeOV() * if obj is not None: # <<<<<<<<<<<<<< @@ -2946,7 +3280,7 @@ __pyx_t_7 = (__pyx_v_obj != Py_None); if (__pyx_t_7) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":24 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":24 * ov = makeOV() * if obj is not None: * ov.obj = obj # <<<<<<<<<<<<<< @@ -2958,7 +3292,7 @@ } __pyx_L11:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":26 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":26 * ov.obj = obj * * rc = WSARecv(s, ws_buf, buffcount, &bytes, &flags, ov, NULL) # <<<<<<<<<<<<<< @@ -2967,7 +3301,7 @@ */ __pyx_v_rc = WSARecv(__pyx_v_s, __pyx_v_ws_buf, __pyx_v_buffcount, (&__pyx_v_bytes), (&__pyx_v_flags), ((OVERLAPPED *)__pyx_v_ov), NULL); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":28 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":28 * rc = WSARecv(s, ws_buf, buffcount, &bytes, &flags, ov, NULL) * * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< @@ -2977,7 +3311,7 @@ __pyx_t_7 = (__pyx_v_rc == SOCKET_ERROR); if (__pyx_t_7) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":29 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":29 * * if rc == SOCKET_ERROR: * rc = WSAGetLastError() # <<<<<<<<<<<<<< @@ -2986,7 +3320,7 @@ */ __pyx_v_rc = WSAGetLastError(); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":30 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":30 * if rc == SOCKET_ERROR: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< @@ -2996,7 +3330,7 @@ __pyx_t_7 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_7) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":31 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":31 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: * return rc, 0 # <<<<<<<<<<<<<< @@ -3024,7 +3358,7 @@ } __pyx_L12:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":33 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":33 * return rc, 0 * * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -3036,7 +3370,7 @@ Py_XINCREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":34 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":34 * * Py_XINCREF(obj) * return rc, bytes # <<<<<<<<<<<<<< @@ -3061,7 +3395,7 @@ goto __pyx_L6; } - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":36 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":36 * return rc, bytes * finally: * PyMem_Free(ws_buf) # <<<<<<<<<<<<<< @@ -3115,7 +3449,7 @@ return __pyx_r; } -/* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":38 +/* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":38 * PyMem_Free(ws_buf) * * def recvfrom(long s, object buff, object addr_buff, object addr_len_buff, object obj, unsigned long flags = 0): # <<<<<<<<<<<<<< @@ -3235,7 +3569,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":46 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":46 * cdef int *c_addr_len_buff * * PyObject_AsWriteBuffer(buff, &ws_buf.buf, &ws_buf.len) # <<<<<<<<<<<<<< @@ -3247,7 +3581,7 @@ __pyx_t_2 = PyObject_AsWriteBuffer(__pyx_t_1, ((void **)(&__pyx_v_ws_buf.buf)), ((int *)(&__pyx_v_ws_buf.len))); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":47 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":47 * * PyObject_AsWriteBuffer(buff, &ws_buf.buf, &ws_buf.len) * PyObject_AsWriteBuffer(addr_buff, &c_addr_buff, &c_addr_buff_len) # <<<<<<<<<<<<<< @@ -3259,7 +3593,7 @@ __pyx_t_2 = PyObject_AsWriteBuffer(__pyx_t_1, ((void **)(&__pyx_v_c_addr_buff)), (&__pyx_v_c_addr_buff_len)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":48 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":48 * PyObject_AsWriteBuffer(buff, &ws_buf.buf, &ws_buf.len) * PyObject_AsWriteBuffer(addr_buff, &c_addr_buff, &c_addr_buff_len) * PyObject_AsWriteBuffer(addr_len_buff, &c_addr_len_buff, &c_addr_len_buff_len) # <<<<<<<<<<<<<< @@ -3271,7 +3605,7 @@ __pyx_t_2 = PyObject_AsWriteBuffer(__pyx_t_1, ((void **)(&__pyx_v_c_addr_len_buff)), (&__pyx_v_c_addr_len_buff_len)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":50 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":50 * PyObject_AsWriteBuffer(addr_len_buff, &c_addr_len_buff, &c_addr_len_buff_len) * * if c_addr_len_buff_len != sizeof(int): # <<<<<<<<<<<<<< @@ -3281,20 +3615,20 @@ __pyx_t_3 = (__pyx_v_c_addr_len_buff_len != (sizeof(int))); if (__pyx_t_3) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":51 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":51 * * if c_addr_len_buff_len != sizeof(int): * raise ValueError, 'length of address length buffer needs to be sizeof(int)' # <<<<<<<<<<<<<< * * c_addr_len_buff[0] = c_addr_buff_len */ - __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_7), 0); + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_11), 0); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":53 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":53 * raise ValueError, 'length of address length buffer needs to be sizeof(int)' * * c_addr_len_buff[0] = c_addr_buff_len # <<<<<<<<<<<<<< @@ -3303,7 +3637,7 @@ */ (__pyx_v_c_addr_len_buff[0]) = __pyx_v_c_addr_buff_len; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":55 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":55 * c_addr_len_buff[0] = c_addr_buff_len * * ov = makeOV() # <<<<<<<<<<<<<< @@ -3313,7 +3647,7 @@ __pyx_t_4 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_4 == NULL)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_ov = __pyx_t_4; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":56 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":56 * * ov = makeOV() * if obj is not None: # <<<<<<<<<<<<<< @@ -3323,7 +3657,7 @@ __pyx_t_3 = (__pyx_v_obj != Py_None); if (__pyx_t_3) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":57 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":57 * ov = makeOV() * if obj is not None: * ov.obj = obj # <<<<<<<<<<<<<< @@ -3335,7 +3669,7 @@ } __pyx_L7:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":59 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":59 * ov.obj = obj * * rc = WSARecvFrom(s, &ws_buf, 1, &bytes, &flags, c_addr_buff, c_addr_len_buff, ov, NULL) # <<<<<<<<<<<<<< @@ -3344,7 +3678,7 @@ */ __pyx_v_rc = WSARecvFrom(__pyx_v_s, (&__pyx_v_ws_buf), 1, (&__pyx_v_bytes), (&__pyx_v_flags), __pyx_v_c_addr_buff, __pyx_v_c_addr_len_buff, ((OVERLAPPED *)__pyx_v_ov), NULL); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":61 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":61 * rc = WSARecvFrom(s, &ws_buf, 1, &bytes, &flags, c_addr_buff, c_addr_len_buff, ov, NULL) * * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< @@ -3354,7 +3688,7 @@ __pyx_t_3 = (__pyx_v_rc == SOCKET_ERROR); if (__pyx_t_3) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":62 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":62 * * if rc == SOCKET_ERROR: * rc = WSAGetLastError() # <<<<<<<<<<<<<< @@ -3363,7 +3697,7 @@ */ __pyx_v_rc = WSAGetLastError(); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":63 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":63 * if rc == SOCKET_ERROR: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< @@ -3373,7 +3707,7 @@ __pyx_t_3 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_3) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":64 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":64 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: * return rc, 0 # <<<<<<<<<<<<<< @@ -3401,7 +3735,7 @@ } __pyx_L8:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":66 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":66 * return rc, 0 * * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -3413,7 +3747,7 @@ Py_XINCREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":67 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":67 * * Py_XINCREF(obj) * return rc, bytes # <<<<<<<<<<<<<< @@ -3450,7 +3784,7 @@ return __pyx_r; } -/* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":5 +/* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":5 * * * def send(long s, object buff, object obj, unsigned long flags = 0): # <<<<<<<<<<<<<< @@ -3546,7 +3880,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":11 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":11 * cdef unsigned long bytes * * PyObject_AsReadBuffer(buff, &ws_buf.buf, &ws_buf.len) # <<<<<<<<<<<<<< @@ -3558,7 +3892,7 @@ __pyx_t_2 = PyObject_AsReadBuffer(__pyx_t_1, ((void **)(&__pyx_v_ws_buf.buf)), ((int *)(&__pyx_v_ws_buf.len))); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":13 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":13 * PyObject_AsReadBuffer(buff, &ws_buf.buf, &ws_buf.len) * * ov = makeOV() # <<<<<<<<<<<<<< @@ -3568,7 +3902,7 @@ __pyx_t_3 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_ov = __pyx_t_3; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":14 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":14 * * ov = makeOV() * if obj is not None: # <<<<<<<<<<<<<< @@ -3578,7 +3912,7 @@ __pyx_t_4 = (__pyx_v_obj != Py_None); if (__pyx_t_4) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":15 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":15 * ov = makeOV() * if obj is not None: * ov.obj = obj # <<<<<<<<<<<<<< @@ -3590,7 +3924,7 @@ } __pyx_L6:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":17 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":17 * ov.obj = obj * * rc = WSASend(s, &ws_buf, 1, &bytes, flags, ov, NULL) # <<<<<<<<<<<<<< @@ -3599,7 +3933,7 @@ */ __pyx_v_rc = WSASend(__pyx_v_s, (&__pyx_v_ws_buf), 1, (&__pyx_v_bytes), __pyx_v_flags, ((OVERLAPPED *)__pyx_v_ov), NULL); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":19 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":19 * rc = WSASend(s, &ws_buf, 1, &bytes, flags, ov, NULL) * * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< @@ -3609,7 +3943,7 @@ __pyx_t_4 = (__pyx_v_rc == SOCKET_ERROR); if (__pyx_t_4) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":20 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":20 * * if rc == SOCKET_ERROR: * rc = WSAGetLastError() # <<<<<<<<<<<<<< @@ -3618,7 +3952,7 @@ */ __pyx_v_rc = WSAGetLastError(); - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":21 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":21 * if rc == SOCKET_ERROR: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< @@ -3628,7 +3962,7 @@ __pyx_t_4 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_4) { - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":22 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":22 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: * return rc, bytes # <<<<<<<<<<<<<< @@ -3658,7 +3992,7 @@ } __pyx_L7:; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":24 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":24 * return rc, bytes * * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -3670,7 +4004,7 @@ Py_XINCREF(__pyx_t_6); __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":25 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":25 * * Py_XINCREF(obj) * return rc, bytes # <<<<<<<<<<<<<< @@ -3900,16 +4234,20 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { {&__pyx_n_s_1, __pyx_k_1, sizeof(__pyx_k_1), 0, 0, 1, 1}, + {&__pyx_kp_s_11, __pyx_k_11, sizeof(__pyx_k_11), 0, 0, 1, 0}, + {&__pyx_kp_s_12, __pyx_k_12, sizeof(__pyx_k_12), 0, 0, 1, 0}, {&__pyx_n_s_2, __pyx_k_2, sizeof(__pyx_k_2), 0, 0, 1, 1}, {&__pyx_kp_s_3, __pyx_k_3, sizeof(__pyx_k_3), 0, 0, 1, 0}, - {&__pyx_kp_s_4, __pyx_k_4, sizeof(__pyx_k_4), 0, 0, 1, 0}, {&__pyx_kp_s_5, __pyx_k_5, sizeof(__pyx_k_5), 0, 0, 1, 0}, + {&__pyx_kp_s_6, __pyx_k_6, sizeof(__pyx_k_6), 0, 0, 1, 0}, {&__pyx_kp_s_7, __pyx_k_7, sizeof(__pyx_k_7), 0, 0, 1, 0}, {&__pyx_kp_s_8, __pyx_k_8, sizeof(__pyx_k_8), 0, 0, 1, 0}, + {&__pyx_kp_s_9, __pyx_k_9, sizeof(__pyx_k_9), 0, 0, 1, 0}, {&__pyx_n_s__AllocateReadBuffer, __pyx_k__AllocateReadBuffer, sizeof(__pyx_k__AllocateReadBuffer), 0, 0, 1, 1}, {&__pyx_n_s__Event, __pyx_k__Event, sizeof(__pyx_k__Event), 0, 0, 1, 1}, {&__pyx_n_s__MemoryError, __pyx_k__MemoryError, sizeof(__pyx_k__MemoryError), 0, 0, 1, 1}, {&__pyx_n_s__ValueError, __pyx_k__ValueError, sizeof(__pyx_k__ValueError), 0, 0, 1, 1}, + {&__pyx_n_s__WSAAddressToString, __pyx_k__WSAAddressToString, sizeof(__pyx_k__WSAAddressToString), 0, 0, 1, 1}, {&__pyx_n_s__WindowsError, __pyx_k__WindowsError, sizeof(__pyx_k__WindowsError), 0, 0, 1, 1}, {&__pyx_n_s____init__, __pyx_k____init__, sizeof(__pyx_k____init__), 0, 0, 1, 1}, {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1}, @@ -3944,21 +4282,23 @@ {&__pyx_n_s__port, __pyx_k__port, sizeof(__pyx_k__port), 0, 0, 1, 1}, {&__pyx_n_s__recv, __pyx_k__recv, sizeof(__pyx_k__recv), 0, 0, 1, 1}, {&__pyx_n_s__recvfrom, __pyx_k__recvfrom, sizeof(__pyx_k__recvfrom), 0, 0, 1, 1}, + {&__pyx_n_s__rsplit, __pyx_k__rsplit, sizeof(__pyx_k__rsplit), 0, 0, 1, 1}, {&__pyx_n_s__s, __pyx_k__s, sizeof(__pyx_k__s), 0, 0, 1, 1}, {&__pyx_n_s__s_addr, __pyx_k__s_addr, sizeof(__pyx_k__s_addr), 0, 0, 1, 1}, {&__pyx_n_s__sa_data, __pyx_k__sa_data, sizeof(__pyx_k__sa_data), 0, 0, 1, 1}, {&__pyx_n_s__sa_family, __pyx_k__sa_family, sizeof(__pyx_k__sa_family), 0, 0, 1, 1}, {&__pyx_n_s__self, __pyx_k__self, sizeof(__pyx_k__self), 0, 0, 1, 1}, {&__pyx_n_s__send, __pyx_k__send, sizeof(__pyx_k__send), 0, 0, 1, 1}, + {&__pyx_n_s__sin6_port, __pyx_k__sin6_port, sizeof(__pyx_k__sin6_port), 0, 0, 1, 1}, {&__pyx_n_s__sin_addr, __pyx_k__sin_addr, sizeof(__pyx_k__sin_addr), 0, 0, 1, 1}, {&__pyx_n_s__sin_port, __pyx_k__sin_port, sizeof(__pyx_k__sin_port), 0, 0, 1, 1}, {&__pyx_n_s__socket, __pyx_k__socket, sizeof(__pyx_k__socket), 0, 0, 1, 1}, {0, 0, 0, 0, 0, 0, 0} }; static int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_ValueError = __Pyx_GetName(__pyx_b, __pyx_n_s__ValueError); if (!__pyx_builtin_ValueError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_builtin_MemoryError = __Pyx_GetName(__pyx_b, __pyx_n_s__MemoryError); if (!__pyx_builtin_MemoryError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_builtin_WindowsError = __Pyx_GetName(__pyx_b, __pyx_n_s__WindowsError); if (!__pyx_builtin_WindowsError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_builtin_ValueError = __Pyx_GetName(__pyx_b, __pyx_n_s__ValueError); if (!__pyx_builtin_ValueError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 267; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_builtin_MemoryError = __Pyx_GetName(__pyx_b, __pyx_n_s__MemoryError); if (!__pyx_builtin_MemoryError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_builtin_WindowsError = __Pyx_GetName(__pyx_b, __pyx_n_s__WindowsError); if (!__pyx_builtin_WindowsError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;} return 0; __pyx_L1_error:; return -1; @@ -3966,13 +4306,34 @@ static int __Pyx_InitCachedConstants(void) { __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants"); + + /* "iocpsupport.pyx":219 + * raise_error(0, 'WSAAddressToString') + * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) + * host, port = host.rsplit(':', 1) # <<<<<<<<<<<<<< + * port = int(port) + * assert host[0] == '[' + */ + __pyx_k_tuple_4 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_k_tuple_4)); + __Pyx_INCREF(((PyObject *)__pyx_kp_s_3)); + PyTuple_SET_ITEM(__pyx_k_tuple_4, 0, ((PyObject *)__pyx_kp_s_3)); + __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_3)); + __Pyx_INCREF(__pyx_int_1); + PyTuple_SET_ITEM(__pyx_k_tuple_4, 1, __pyx_int_1); + __Pyx_GIVEREF(__pyx_int_1); + __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_4)); __Pyx_RefNannyFinishContext(); return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; } static int __Pyx_InitGlobals(void) { if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; + __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; return 0; __pyx_L1_error:; return -1; @@ -4037,97 +4398,97 @@ /*--- Global init code ---*/ /*--- Function export code ---*/ /*--- Type init code ---*/ - if (PyType_Ready(&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (__Pyx_SetAttrString(__pyx_m, "CompletionPort", (PyObject *)&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyType_Ready(&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (__Pyx_SetAttrString(__pyx_m, "CompletionPort", (PyObject *)&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_ptype_11iocpsupport_CompletionPort = &__pyx_type_11iocpsupport_CompletionPort; /*--- Type import code ---*/ /*--- Function import code ---*/ /*--- Execution code ---*/ - /* "iocpsupport.pyx":121 + /* "iocpsupport.pyx":131 * raise WindowsError(message, err) * * class Event: # <<<<<<<<<<<<<< * def __init__(self, callback, owner, **kw): * self.callback = callback */ - __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_1)); - /* "iocpsupport.pyx":122 + /* "iocpsupport.pyx":132 * * class Event: * def __init__(self, callback, owner, **kw): # <<<<<<<<<<<<<< * self.callback = callback * self.owner = owner */ - __pyx_t_2 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_11iocpsupport_5Event___init__, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_11iocpsupport_5Event___init__, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - if (PyObject_SetItem(__pyx_t_1, __pyx_n_s____init__, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetItem(__pyx_t_1, __pyx_n_s____init__, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "iocpsupport.pyx":121 + /* "iocpsupport.pyx":131 * raise WindowsError(message, err) * * class Event: # <<<<<<<<<<<<<< * def __init__(self, callback, owner, **kw): * self.callback = callback */ - __pyx_t_2 = __Pyx_CreateClass(((PyObject *)__pyx_empty_tuple), ((PyObject *)__pyx_t_1), __pyx_n_s__Event, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __Pyx_CreateClass(((PyObject *)__pyx_empty_tuple), ((PyObject *)__pyx_t_1), __pyx_n_s__Event, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__Event, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__Event, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; - /* "iocpsupport.pyx":184 + /* "iocpsupport.pyx":194 * CloseHandle(self.port) * * def makesockaddr(object buff): # <<<<<<<<<<<<<< * cdef void *mem_buffer * cdef int size */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_makesockaddr, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 184; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_makesockaddr, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__makesockaddr, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 184; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__makesockaddr, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "iocpsupport.pyx":216 + /* "iocpsupport.pyx":242 * dest.sin_port = htons(port) * * def AllocateReadBuffer(int size): # <<<<<<<<<<<<<< * return PyBuffer_New(size) * */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_1AllocateReadBuffer, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 216; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_1AllocateReadBuffer, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 242; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__AllocateReadBuffer, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 216; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__AllocateReadBuffer, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 242; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "iocpsupport.pyx":219 + /* "iocpsupport.pyx":245 * return PyBuffer_New(size) * * def maxAddrLen(long s): # <<<<<<<<<<<<<< * cdef WSAPROTOCOL_INFO wsa_pi * cdef int size, rc */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_2maxAddrLen, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_2maxAddrLen, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__maxAddrLen, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__maxAddrLen, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "iocpsupport.pyx":239 + /* "iocpsupport.pyx":265 * return wsa_pi.iAddressFamily * * import socket # for WSAStartup # <<<<<<<<<<<<<< * if not initWinsockPointers(): * raise ValueError, 'Failed to initialize Winsock function vectors' */ - __pyx_t_1 = __Pyx_Import(((PyObject *)__pyx_n_s__socket), 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __Pyx_Import(((PyObject *)__pyx_n_s__socket), 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__socket, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__socket, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "iocpsupport.pyx":240 + /* "iocpsupport.pyx":266 * * import socket # for WSAStartup * if not initWinsockPointers(): # <<<<<<<<<<<<<< @@ -4137,32 +4498,32 @@ __pyx_t_3 = (!initWinsockPointers()); if (__pyx_t_3) { - /* "iocpsupport.pyx":241 + /* "iocpsupport.pyx":267 * import socket # for WSAStartup * if not initWinsockPointers(): * raise ValueError, 'Failed to initialize Winsock function vectors' # <<<<<<<<<<<<<< * * have_connectex = (lpConnectEx != NULL) */ - __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_8), 0); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_12), 0); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 267; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L2; } __pyx_L2:; - /* "iocpsupport.pyx":243 + /* "iocpsupport.pyx":269 * raise ValueError, 'Failed to initialize Winsock function vectors' * * have_connectex = (lpConnectEx != NULL) # <<<<<<<<<<<<<< * * include 'acceptex.pxi' */ - __pyx_t_1 = __Pyx_PyBool_FromLong((lpConnectEx != NULL)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __Pyx_PyBool_FromLong((lpConnectEx != NULL)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__have_connectex, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__have_connectex, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":5 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":5 * * * def accept(long listening, long accepting, object buff, object obj): # <<<<<<<<<<<<<< @@ -4174,7 +4535,7 @@ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__accept, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":31 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":31 * return 0 * * def get_accept_addrs(long s, object buff): # <<<<<<<<<<<<<< @@ -4186,7 +4547,7 @@ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__get_accept_addrs, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":5 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":5 * * * def connect(long s, object addr, object obj): # <<<<<<<<<<<<<< @@ -4202,7 +4563,7 @@ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__recv, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":38 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":38 * PyMem_Free(ws_buf) * * def recvfrom(long s, object buff, object addr_buff, object addr_len_buff, object obj, unsigned long flags = 0): # <<<<<<<<<<<<<< @@ -4214,7 +4575,7 @@ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__recvfrom, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "E:\Twisted.3233\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":5 + /* "E:\Twisted.5084\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":5 * * * def send(long s, object buff, object obj, unsigned long flags = 0): # <<<<<<<<<<<<<< @@ -4599,6 +4960,7 @@ return 0; } + static CYTHON_INLINE long __Pyx_div_long(long a, long b) { long q = a / b; long r = a - q*b; diff --git a/lib/twisted-trunk/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx b/lib/twisted-trunk/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx --- a/lib/twisted-trunk/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx +++ b/lib/twisted-trunk/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx @@ -20,6 +20,9 @@ cdef extern from 'winsock2.h': pass +cdef extern from 'ws2tcpip.h': + pass + cdef extern from 'windows.h': ctypedef struct OVERLAPPED: pass @@ -66,6 +69,8 @@ struct sockaddr_in: int sin_port in_addr sin_addr + struct sockaddr_in6: + int sin6_port int getsockopt(SOCKET s, int level, int optname, char *optval, int *optlen) enum: SOL_SOCKET @@ -73,6 +78,7 @@ SOCKET_ERROR ERROR_IO_PENDING AF_INET + AF_INET6 INADDR_ANY ctypedef struct WSAPROTOCOL_INFO: int iMaxSockAddr @@ -90,6 +96,10 @@ int WSARecv(SOCKET s, WSABUF *buffs, DWORD buffcount, DWORD *bytes, DWORD *flags, OVERLAPPED *ov, void *crud) int WSARecvFrom(SOCKET s, WSABUF *buffs, DWORD buffcount, DWORD *bytes, DWORD *flags, sockaddr *fromaddr, int *fromlen, OVERLAPPED *ov, void *crud) int WSASend(SOCKET s, WSABUF *buffs, DWORD buffcount, DWORD *bytes, DWORD flags, OVERLAPPED *ov, void *crud) + int WSAAddressToStringA(sockaddr *lpsaAddress, DWORD dwAddressLength, + WSAPROTOCOL_INFO *lpProtocolInfo, + char *lpszAddressString, + DWORD *lpdwAddressStringLength) cdef extern from 'string.h': void *memset(void *s, int c, size_t n) @@ -191,11 +201,27 @@ cdef object _makesockaddr(sockaddr *addr, int len): cdef sockaddr_in *sin + cdef sockaddr_in6 *sin6 + cdef char buff[256] + cdef int rc + cdef DWORD buff_size = sizeof(buff) if not len: return None if addr.sa_family == AF_INET: sin = addr return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) + elif addr.sa_family == AF_INET6: + sin6 = addr + rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) + if rc == SOCKET_ERROR: + raise_error(0, 'WSAAddressToString') + host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) + host, port = host.rsplit(':', 1) + port = int(port) + assert host[0] == '[' + assert host[-1] == ']' + assert port == sa_port + return host[1:-1], port else: return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) diff --git a/lib/twisted-trunk/twisted/internet/iocpreactor/reactor.py b/lib/twisted-trunk/twisted/internet/iocpreactor/reactor.py --- a/lib/twisted-trunk/twisted/internet/iocpreactor/reactor.py +++ b/lib/twisted-trunk/twisted/internet/iocpreactor/reactor.py @@ -13,6 +13,7 @@ from twisted.internet import base, interfaces, main, error from twisted.python import log, failure from twisted.internet._dumbwin32proc import Process +from twisted.internet.win32eventreactor import _ThreadedWin32EventsMixin from twisted.internet.iocpreactor import iocpsupport as _iocp from twisted.internet.iocpreactor.const import WAIT_TIMEOUT @@ -46,7 +47,8 @@ -class IOCPReactor(base._SignalReactorMixin, base.ReactorBase): +class IOCPReactor(base._SignalReactorMixin, base.ReactorBase, + _ThreadedWin32EventsMixin): implements(interfaces.IReactorTCP, interfaces.IReactorUDP, interfaces.IReactorMulticast, interfaces.IReactorProcess, *_extraInterfaces) diff --git a/lib/twisted-trunk/twisted/internet/iocpreactor/tcp.py b/lib/twisted-trunk/twisted/internet/iocpreactor/tcp.py --- a/lib/twisted-trunk/twisted/internet/iocpreactor/tcp.py +++ b/lib/twisted-trunk/twisted/internet/iocpreactor/tcp.py @@ -152,6 +152,8 @@ @see: L{ITCPTransport.write} """ + if self.disconnected: + return if self.TLS: self.protocol.write(data) else: @@ -166,6 +168,8 @@ @see: L{ITCPTransport.writeSequence} """ + if self.disconnected: + return if self.TLS: self.protocol.writeSequence(iovec) else: diff --git a/lib/twisted-trunk/twisted/internet/protocol.py b/lib/twisted-trunk/twisted/internet/protocol.py --- a/lib/twisted-trunk/twisted/internet/protocol.py +++ b/lib/twisted-trunk/twisted/internet/protocol.py @@ -431,22 +431,15 @@ """ + class BaseProtocol: - """This is the abstract superclass of all protocols. + """ + This is the abstract superclass of all protocols. - If you are going to write a new protocol for Twisted, start here. The - docstrings of this class explain how you can get started. Any protocol - implementation, either client or server, should be a subclass of me. - - My API is quite simple. Implement dataReceived(data) to handle both - event-based and synchronous input; output can be sent through the - 'transport' attribute, which is to be an instance that implements - L{twisted.internet.interfaces.ITransport}. - - Some subclasses exist already to help you write common types of protocols: - see the L{twisted.protocols.basic} module for a few of them. + Some methods have helpful default implementations here so that they can + easily be shared, but otherwise the direct subclasses of this class are more + interesting, L{Protocol} and L{ProcessProtocol}. """ - connected = 0 transport = None @@ -476,7 +469,22 @@ class Protocol(BaseProtocol): + """ + This is the base class for streaming connection-oriented protocols. + If you are going to write a new connection-oriented protocol for Twisted, + start here. Any protocol implementation, either client or server, should + be a subclass of this class. + + The API is quite simple. Implement L{dataReceived} to handle both + event-based and synchronous input; output can be sent through the + 'transport' attribute, which is to be an instance that implements + L{twisted.internet.interfaces.ITransport}. Override C{connectionLost} to be + notified when the connection ends. + + Some subclasses exist already to help you write common types of protocols: + see the L{twisted.protocols.basic} module for a few of them. + """ implements(interfaces.IProtocol) def dataReceived(self, data): diff --git a/lib/twisted-trunk/twisted/internet/reactor.py b/lib/twisted-trunk/twisted/internet/reactor.py --- a/lib/twisted-trunk/twisted/internet/reactor.py +++ b/lib/twisted-trunk/twisted/internet/reactor.py @@ -34,5 +34,5 @@ import sys del sys.modules['twisted.internet.reactor'] -from twisted.internet import selectreactor -selectreactor.install() +from twisted.internet import default +default.install() diff --git a/lib/twisted-trunk/twisted/internet/selectreactor.py b/lib/twisted-trunk/twisted/internet/selectreactor.py --- a/lib/twisted-trunk/twisted/internet/selectreactor.py +++ b/lib/twisted-trunk/twisted/internet/selectreactor.py @@ -5,8 +5,6 @@ """ Select reactor - -Maintainer: Itamar Shtull-Trauring """ from time import sleep @@ -43,7 +41,16 @@ else: _select = select.select -class SelectReactor(posixbase.PosixReactorBase): + +try: + from twisted.internet.win32eventreactor import _ThreadedWin32EventsMixin +except ImportError: + _extraBase = object +else: + _extraBase = _ThreadedWin32EventsMixin + + +class SelectReactor(posixbase.PosixReactorBase, _extraBase): """ A select() based reactor - runs on all POSIX platforms and on Win32. diff --git a/lib/twisted-trunk/twisted/internet/task.py b/lib/twisted-trunk/twisted/internet/task.py --- a/lib/twisted-trunk/twisted/internet/task.py +++ b/lib/twisted-trunk/twisted/internet/task.py @@ -177,6 +177,20 @@ d, self.deferred = self.deferred, None d.callback(self) + def reset(self): + """ + Skip the next iteration and reset the timer. + + @since: 11.1 + """ + assert self.running, ("Tried to reset a LoopingCall that was " + "not running.") + if self.call is not None: + self.call.cancel() + self.call = None + self._expectNextCallAt = self.clock.seconds() + self._reschedule() + def __call__(self): def cb(result): if self.running: @@ -484,7 +498,7 @@ @param terminationPredicateFactory: A no-argument callable which will be invoked at the beginning of each step and should return a - no-argument callable which will return False when the step should be + no-argument callable which will return True when the step should be terminated. The default factory is time-based and allows iterators to run for 1/100th of a second at a time. diff --git a/lib/twisted-trunk/twisted/internet/test/connectionmixins.py b/lib/twisted-trunk/twisted/internet/test/connectionmixins.py --- a/lib/twisted-trunk/twisted/internet/test/connectionmixins.py +++ b/lib/twisted-trunk/twisted/internet/test/connectionmixins.py @@ -120,4 +120,4 @@ portDeferred.addCallback(lambda ignored: reactor.stop()) self.runReactor(reactor) - self.assertEquals(finished, [True, True]) + self.assertEqual(finished, [True, True]) diff --git a/lib/twisted-trunk/twisted/internet/test/inlinecb_tests.py b/lib/twisted-trunk/twisted/internet/test/inlinecb_tests.py --- a/lib/twisted-trunk/twisted/internet/test/inlinecb_tests.py +++ b/lib/twisted-trunk/twisted/internet/test/inlinecb_tests.py @@ -46,8 +46,8 @@ self.assertEqual(resultList, [1]) warnings = self.flushWarnings(offendingFunctions=[self.mistakenMethod]) self.assertEqual(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "returnValue() in 'mistakenMethod' causing 'inline' to exit: " "returnValue should only be invoked by functions decorated with " @@ -85,7 +85,7 @@ effect = inline() results = [] effect.addCallback(results.append) - self.assertEquals(results, []) + self.assertEqual(results, []) cause.callback(1) self.assertMistakenMethodWarning(results) diff --git a/lib/twisted-trunk/twisted/internet/test/test_address.py b/lib/twisted-trunk/twisted/internet/test/test_address.py --- a/lib/twisted-trunk/twisted/internet/test/test_address.py +++ b/lib/twisted-trunk/twisted/internet/test/test_address.py @@ -49,10 +49,10 @@ None, m, "%s does not match the standard __str__ pattern " "ClassName(arg1, arg2, etc)" % (stringValue,)) - self.assertEquals(addr.__class__.__name__, m.group(1)) + self.assertEqual(addr.__class__.__name__, m.group(1)) args = [x.strip() for x in m.group(2).split(",")] - self.assertEquals( + self.assertEqual( args, [argSpec[1] % (getattr(addr, argSpec[0]),) for argSpec in self.addressArgSpec]) @@ -98,9 +98,9 @@ emitted against the given method. """ warnings = self.flushWarnings([testMethod]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals(warnings[0]['message'], message) - self.assertEquals(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(warnings[0]['message'], message) + self.assertEqual(len(warnings), 1) @@ -211,7 +211,7 @@ linkName = self.mktemp() self.fd = open(self._socketAddress, 'w') os.symlink(os.path.abspath(self._socketAddress), linkName) - self.assertEquals( + self.assertEqual( hash(UNIXAddress(self._socketAddress)), hash(UNIXAddress(linkName))) test_hashOfLinkedFiles.skip = symlinkSkip diff --git a/lib/twisted-trunk/twisted/internet/test/test_base.py b/lib/twisted-trunk/twisted/internet/test/test_base.py --- a/lib/twisted-trunk/twisted/internet/test/test_base.py +++ b/lib/twisted-trunk/twisted/internet/test/test_base.py @@ -195,7 +195,7 @@ except (TypeError, KeyError): return id(obj) self.addCleanup(setIDFunction, setIDFunction(fakeID)) - self.assertEquals( + self.assertEqual( str(dc), "") @@ -254,7 +254,7 @@ """ A L{DelayedCall} instance is only equal to itself. """ - # Explicitly use == here, instead of assertEquals, to be more + # Explicitly use == here, instead of assertEqual, to be more # confident __eq__ is being tested. self.assertFalse(self.zero == self.one) self.assertTrue(self.zero == self.zero) @@ -265,7 +265,7 @@ """ A L{DelayedCall} instance is not equal to any other object. """ - # Explicitly use != here, instead of assertEquals, to be more + # Explicitly use != here, instead of assertEqual, to be more # confident __ne__ is being tested. self.assertTrue(self.zero != self.one) self.assertFalse(self.zero != self.zero) diff --git a/lib/twisted-trunk/twisted/internet/test/test_core.py b/lib/twisted-trunk/twisted/internet/test/test_core.py --- a/lib/twisted-trunk/twisted/internet/test/test_core.py +++ b/lib/twisted-trunk/twisted/internet/test/test_core.py @@ -164,7 +164,7 @@ lambda: events.append(("after", "shutdown"))) reactor.callWhenRunning(reactor.stop) self.runReactor(reactor) - self.assertEquals(events, [("before", "shutdown"), + self.assertEqual(events, [("before", "shutdown"), ("during", "shutdown"), ("after", "shutdown")]) diff --git a/lib/twisted-trunk/twisted/internet/test/test_endpoints.py b/lib/twisted-trunk/twisted/internet/test/test_endpoints.py --- a/lib/twisted-trunk/twisted/internet/test/test_endpoints.py +++ b/lib/twisted-trunk/twisted/internet/test/test_endpoints.py @@ -121,7 +121,7 @@ wf.buildProtocol(None) d = self.assertFailure(wf._onConnection, ValueError) - d.addCallback(lambda e: self.assertEquals( + d.addCallback(lambda e: self.assertEqual( e.args, ("My protocol is poorly defined.",))) @@ -138,10 +138,10 @@ p.makeConnection(None) p.dataReceived('foo') - self.assertEquals(p._wrappedProtocol.data, ['foo']) + self.assertEqual(p._wrappedProtocol.data, ['foo']) p.dataReceived('bar') - self.assertEquals(p._wrappedProtocol.data, ['foo', 'bar']) + self.assertEqual(p._wrappedProtocol.data, ['foo', 'bar']) def test_wrappedProtocolTransport(self): @@ -156,9 +156,9 @@ p.makeConnection(dummyTransport) - self.assertEquals(p.transport, dummyTransport) + self.assertEqual(p.transport, dummyTransport) - self.assertEquals(p._wrappedProtocol.transport, dummyTransport) + self.assertEqual(p._wrappedProtocol.transport, dummyTransport) def test_wrappedProtocolConnectionLost(self): @@ -172,7 +172,7 @@ p.connectionLost("fail") - self.assertEquals(p._wrappedProtocol.connectionsLost, ["fail"]) + self.assertEqual(p._wrappedProtocol.connectionsLost, ["fail"]) def test_clientConnectionFailed(self): @@ -193,7 +193,7 @@ wf._onConnection.addErrback(gotError) - self.assertEquals(errors, [expectedFailure]) + self.assertEqual(errors, [expectedFailure]) def test_wrappingProtocolHalfCloseable(self): @@ -204,7 +204,7 @@ cd = object() hcp = TestHalfCloseableProtocol() p = endpoints._WrappingProtocol(cd, hcp) - self.assertEquals( + self.assertEqual( interfaces.IHalfCloseableProtocol.providedBy(p), True) @@ -215,7 +215,7 @@ """ tp = TestProtocol() p = endpoints._WrappingProtocol(None, tp) - self.assertEquals( + self.assertEqual( interfaces.IHalfCloseableProtocol.providedBy(p), False) @@ -227,7 +227,7 @@ hcp = TestHalfCloseableProtocol() p = endpoints._WrappingProtocol(None, hcp) p.readConnectionLost() - self.assertEquals(hcp.readLost, True) + self.assertEqual(hcp.readLost, True) def test_wrappedProtocolWriteConnectionLost(self): @@ -238,7 +238,7 @@ hcp = TestHalfCloseableProtocol() p = endpoints._WrappingProtocol(None, hcp) p.writeConnectionLost() - self.assertEquals(hcp.writeLost, True) + self.assertEqual(hcp.writeLost, True) @@ -282,11 +282,11 @@ factory = self.retrieveConnectedFactory(mreactor) factory._onConnection.callback(proto) - self.assertEquals(receivedProtos, [proto]) + self.assertEqual(receivedProtos, [proto]) expectedClients = self.expectedClients(mreactor) - self.assertEquals(len(expectedClients), 1) + self.assertEqual(len(expectedClients), 1) self.assertConnectArgs(expectedClients[0], expectedArgs) @@ -313,7 +313,7 @@ d.addErrback(checkFailure) - self.assertEquals(receivedExceptions, [expectedError]) + self.assertEqual(receivedExceptions, [expectedError]) def test_endpointConnectingCancelled(self): @@ -340,12 +340,12 @@ d.cancel() - self.assertEquals(len(receivedFailures), 1) + self.assertEqual(len(receivedFailures), 1) failure = receivedFailures[0] self.assertIsInstance(failure.value, error.ConnectingCancelledError) - self.assertEquals(failure.value.address, address) + self.assertEqual(failure.value.address, address) def test_endpointListenSuccess(self): @@ -369,8 +369,8 @@ d.addCallback(checkPortAndServer) - self.assertEquals(receivedHosts, [expectedHost]) - self.assertEquals(self.expectedServers(mreactor), [expectedArgs]) + self.assertEqual(receivedHosts, [expectedHost]) + self.assertEqual(self.expectedServers(mreactor), [expectedArgs]) def test_endpointListenFailure(self): @@ -394,7 +394,7 @@ d.addErrback(checkFailure) - self.assertEquals(receivedExceptions, [exception]) + self.assertEqual(receivedExceptions, [exception]) def test_endpointConnectNonDefaultArgs(self): @@ -414,7 +414,7 @@ expectedClients = self.expectedClients(mreactor) - self.assertEquals(len(expectedClients), 1) + self.assertEqual(len(expectedClients), 1) self.assertConnectArgs(expectedClients[0], expectedArgs) @@ -435,7 +435,7 @@ expectedServers = self.expectedServers(mreactor) - self.assertEquals(expectedServers, [expectedArgs]) + self.assertEqual(expectedServers, [expectedArgs]) @@ -477,10 +477,10 @@ (expectedHost, expectedPort, _ignoredFactory, expectedTimeout, expectedBindAddress) = expectedArgs - self.assertEquals(host, expectedHost) - self.assertEquals(port, expectedPort) - self.assertEquals(timeout, expectedTimeout) - self.assertEquals(bindAddress, expectedBindAddress) + self.assertEqual(host, expectedHost) + self.assertEqual(port, expectedPort) + self.assertEqual(timeout, expectedTimeout) + self.assertEqual(bindAddress, expectedBindAddress) def connectArgs(self): @@ -590,11 +590,11 @@ (expectedHost, expectedPort, _ignoredFactory, expectedContextFactory, expectedTimeout, expectedBindAddress) = expectedArgs - self.assertEquals(host, expectedHost) - self.assertEquals(port, expectedPort) - self.assertEquals(contextFactory, expectedContextFactory) - self.assertEquals(timeout, expectedTimeout) - self.assertEquals(bindAddress, expectedBindAddress) + self.assertEqual(host, expectedHost) + self.assertEqual(port, expectedPort) + self.assertEqual(contextFactory, expectedContextFactory) + self.assertEqual(timeout, expectedTimeout) + self.assertEqual(bindAddress, expectedBindAddress) def connectArgs(self): @@ -727,9 +727,9 @@ (expectedPath, _ignoredFactory, expectedTimeout, expectedCheckPID) = expectedArgs - self.assertEquals(path, expectedPath) - self.assertEquals(timeout, expectedTimeout) - self.assertEquals(checkPID, expectedCheckPID) + self.assertEqual(path, expectedPath) + self.assertEqual(timeout, expectedTimeout) + self.assertEqual(checkPID, expectedCheckPID) def connectArgs(self): @@ -810,7 +810,7 @@ """ Simple strings with a 'tcp:' prefix should be parsed as TCP. """ - self.assertEquals(self.parse('tcp:80', self.f), + self.assertEqual(self.parse('tcp:80', self.f), ('TCP', (80, self.f), {'interface':'', 'backlog':50})) @@ -818,7 +818,7 @@ """ TCP port descriptions parse their 'interface' argument as a string. """ - self.assertEquals( + self.assertEqual( self.parse('tcp:80:interface=127.0.0.1', self.f), ('TCP', (80, self.f), {'interface':'127.0.0.1', 'backlog':50})) @@ -827,7 +827,7 @@ """ TCP port descriptions parse their 'backlog' argument as an integer. """ - self.assertEquals(self.parse('tcp:80:backlog=6', self.f), + self.assertEqual(self.parse('tcp:80:backlog=6', self.f), ('TCP', (80, self.f), {'interface':'', 'backlog':6})) @@ -838,7 +838,7 @@ defaults for C{'mode'}, C{'backlog'}, and C{'wantPID'} when passed a string with the C{'unix:'} prefix and no other parameter values. """ - self.assertEquals( + self.assertEqual( self.parse('unix:/var/run/finger', self.f), ('UNIX', ('/var/run/finger', self.f), {'mode': 0666, 'backlog': 50, 'wantPID': True})) @@ -848,7 +848,7 @@ """ C{mode} can be set by including C{"mode="}. """ - self.assertEquals( + self.assertEqual( self.parse('unix:/var/run/finger:mode=0660', self.f), ('UNIX', ('/var/run/finger', self.f), {'mode': 0660, 'backlog': 50, 'wantPID': True})) @@ -858,7 +858,7 @@ """ C{wantPID} can be set to false by included C{"lockfile=0"}. """ - self.assertEquals( + self.assertEqual( self.parse('unix:/var/run/finger:lockfile=0', self.f), ('UNIX', ('/var/run/finger', self.f), {'mode': 0666, 'backlog': 50, 'wantPID': False})) @@ -869,7 +869,7 @@ Backslash can be used to escape colons and backslashes in port descriptions. """ - self.assertEquals( + self.assertEqual( self.parse(r'unix:foo\:bar\=baz\:qux\\', self.f), ('UNIX', ('foo:bar=baz:qux\\', self.f), {'mode': 0666, 'backlog': 50, 'wantPID': True})) @@ -881,7 +881,7 @@ for interpolation into L{endpoints.serverFromString} and L{endpoints.clientFactory} arguments. """ - self.assertEquals(endpoints.quoteStringArgument("some : stuff \\"), + self.assertEqual(endpoints.quoteStringArgument("some : stuff \\"), "some \\: stuff \\\\") @@ -890,7 +890,7 @@ In strports descriptions, '=' in a parameter value does not need to be quoted; it will simply be parsed as part of the value. """ - self.assertEquals( + self.assertEqual( self.parse(r'unix:address=foo=bar', self.f), ('UNIX', ('foo=bar', self.f), {'mode': 0666, 'backlog': 50, 'wantPID': True})) @@ -902,7 +902,7 @@ the third 'mode' argument may be specified to L{endpoints.parse} to indicate a default other than TCP. """ - self.assertEquals( + self.assertEqual( self.parse('filename', self.f, 'unix'), ('UNIX', ('filename', self.f), {'mode': 0666, 'backlog': 50, 'wantPID': True})) @@ -933,9 +933,9 @@ reactor, "tcp:1234:backlog=12:interface=10.0.0.1") self.assertIsInstance(server, endpoints.TCP4ServerEndpoint) self.assertIdentical(server._reactor, reactor) - self.assertEquals(server._port, 1234) - self.assertEquals(server._backlog, 12) - self.assertEquals(server._interface, "10.0.0.1") + self.assertEqual(server._port, 1234) + self.assertEqual(server._backlog, 12) + self.assertEqual(server._interface, "10.0.0.1") def test_ssl(self): @@ -952,9 +952,9 @@ escapedPEMPathName)) self.assertIsInstance(server, endpoints.SSL4ServerEndpoint) self.assertIdentical(server._reactor, reactor) - self.assertEquals(server._port, 1234) - self.assertEquals(server._backlog, 12) - self.assertEquals(server._interface, "10.0.0.1") + self.assertEqual(server._port, 1234) + self.assertEqual(server._backlog, 12) + self.assertEqual(server._interface, "10.0.0.1") ctx = server._sslContextFactory.getContext() self.assertIsInstance(ctx, ContextType) @@ -974,10 +974,10 @@ "unix:/var/foo/bar:backlog=7:mode=0123:lockfile=1") self.assertIsInstance(endpoint, endpoints.UNIXServerEndpoint) self.assertIdentical(endpoint._reactor, reactor) - self.assertEquals(endpoint._address, "/var/foo/bar") - self.assertEquals(endpoint._backlog, 7) - self.assertEquals(endpoint._mode, 0123) - self.assertEquals(endpoint._wantPID, True) + self.assertEqual(endpoint._address, "/var/foo/bar") + self.assertEqual(endpoint._backlog, 7) + self.assertEqual(endpoint._mode, 0123) + self.assertEqual(endpoint._wantPID, True) def test_implicitDefaultNotAllowed(self): @@ -991,7 +991,7 @@ """ value = self.assertRaises( ValueError, endpoints.serverFromString, None, "4321") - self.assertEquals( + self.assertEqual( str(value), "Unqualified strport description passed to 'service'." "Use qualified endpoint descriptions; for example, 'tcp:4321'.") @@ -1006,7 +1006,7 @@ # faster-than-light communication not supported ValueError, endpoints.serverFromString, None, "ftl:andromeda/carcosa/hali/2387") - self.assertEquals( + self.assertEqual( str(value), "Unknown endpoint type: 'ftl'") @@ -1025,8 +1025,8 @@ notAReactor, "fake:hello:world:yes=no:up=down") from twisted.plugins.fakeendpoint import fake self.assertIdentical(fakeEndpoint.parser, fake) - self.assertEquals(fakeEndpoint.args, (notAReactor, 'hello', 'world')) - self.assertEquals(fakeEndpoint.kwargs, dict(yes='no', up='down')) + self.assertEqual(fakeEndpoint.args, (notAReactor, 'hello', 'world')) + self.assertEqual(fakeEndpoint.kwargs, dict(yes='no', up='down')) @@ -1068,10 +1068,10 @@ "tcp:host=example.com:port=1234:timeout=7:bindAddress=10.0.0.2") self.assertIsInstance(client, endpoints.TCP4ClientEndpoint) self.assertIdentical(client._reactor, reactor) - self.assertEquals(client._host, "example.com") - self.assertEquals(client._port, 1234) - self.assertEquals(client._timeout, 7) - self.assertEquals(client._bindAddress, "10.0.0.2") + self.assertEqual(client._host, "example.com") + self.assertEqual(client._port, 1234) + self.assertEqual(client._timeout, 7) + self.assertEqual(client._bindAddress, "10.0.0.2") def test_tcpDefaults(self): @@ -1083,8 +1083,8 @@ client = endpoints.clientFromString( reactor, "tcp:host=example.com:port=1234") - self.assertEquals(client._timeout, 30) - self.assertEquals(client._bindAddress, None) + self.assertEqual(client._timeout, 30) + self.assertEqual(client._bindAddress, None) def test_unix(self): @@ -1099,9 +1099,9 @@ "unix:path=/var/foo/bar:lockfile=1:timeout=9") self.assertIsInstance(client, endpoints.UNIXClientEndpoint) self.assertIdentical(client._reactor, reactor) - self.assertEquals(client._path, "/var/foo/bar") - self.assertEquals(client._timeout, 9) - self.assertEquals(client._checkPID, True) + self.assertEqual(client._path, "/var/foo/bar") + self.assertEqual(client._timeout, 9) + self.assertEqual(client._checkPID, True) def test_unixDefaults(self): @@ -1110,8 +1110,8 @@ the defaults to be used. """ client = endpoints.clientFromString(object(), "unix:path=/var/foo/bar") - self.assertEquals(client._timeout, 30) - self.assertEquals(client._checkPID, False) + self.assertEqual(client._timeout, 30) + self.assertEqual(client._checkPID, False) def test_typeFromPlugin(self): @@ -1125,8 +1125,8 @@ notAReactor, "cfake:alpha:beta:cee=dee:num=1") from twisted.plugins.fakeendpoint import fakeClient self.assertIdentical(clientEndpoint.parser, fakeClient) - self.assertEquals(clientEndpoint.args, ('alpha', 'beta')) - self.assertEquals(clientEndpoint.kwargs, dict(cee='dee', num='1')) + self.assertEqual(clientEndpoint.args, ('alpha', 'beta')) + self.assertEqual(clientEndpoint.kwargs, dict(cee='dee', num='1')) def test_unknownType(self): @@ -1138,7 +1138,7 @@ # faster-than-light communication not supported ValueError, endpoints.clientFromString, None, "ftl:andromeda/carcosa/hali/2387") - self.assertEquals( + self.assertEqual( str(value), "Unknown endpoint type: 'ftl'") @@ -1168,25 +1168,25 @@ escapedCAsPathName)) self.assertIsInstance(client, endpoints.SSL4ClientEndpoint) self.assertIdentical(client._reactor, reactor) - self.assertEquals(client._host, "example.net") - self.assertEquals(client._port, 4321) - self.assertEquals(client._timeout, 3) - self.assertEquals(client._bindAddress, "10.0.0.3") + self.assertEqual(client._host, "example.net") + self.assertEqual(client._port, 4321) + self.assertEqual(client._timeout, 3) + self.assertEqual(client._bindAddress, "10.0.0.3") certOptions = client._sslContextFactory self.assertIsInstance(certOptions, CertificateOptions) ctx = certOptions.getContext() self.assertIsInstance(ctx, ContextType) - self.assertEquals(Certificate(certOptions.certificate), + self.assertEqual(Certificate(certOptions.certificate), testCertificate) privateCert = PrivateCertificate(certOptions.certificate) privateCert._setPrivateKey(KeyPair(certOptions.privateKey)) - self.assertEquals(privateCert, testPrivateCertificate) + self.assertEqual(privateCert, testPrivateCertificate) expectedCerts = [ Certificate.loadPEM(x.getContent()) for x in [casPath.child("thing1.pem"), casPath.child("thing2.pem")] if x.basename().lower().endswith('.pem') ] - self.assertEquals([Certificate(x) for x in certOptions.caCerts], + self.assertEqual([Certificate(x) for x in certOptions.caCerts], expectedCerts) @@ -1206,7 +1206,7 @@ return data casPathClone = casPath.child("ignored").parent() casPathClone.clonePath = UnreadableFilePath - self.assertEquals( + self.assertEqual( [Certificate(x) for x in endpoints._loadCAsFromDir(casPathClone)], [Certificate.loadPEM(casPath.child("thing1.pem").getContent())]) @@ -1222,6 +1222,6 @@ reactor, "ssl:host=simple.example.org:port=4321") certOptions = client._sslContextFactory self.assertIsInstance(certOptions, CertificateOptions) - self.assertEquals(certOptions.verify, False) + self.assertEqual(certOptions.verify, False) ctx = certOptions.getContext() self.assertIsInstance(ctx, ContextType) diff --git a/lib/twisted-trunk/twisted/internet/test/test_fdset.py b/lib/twisted-trunk/twisted/internet/test/test_fdset.py --- a/lib/twisted-trunk/twisted/internet/test/test_fdset.py +++ b/lib/twisted-trunk/twisted/internet/test/test_fdset.py @@ -234,7 +234,7 @@ descriptor = RemovingDescriptor(reactor) reactor.callWhenRunning(descriptor.start) self.runReactor(reactor) - self.assertEquals(descriptor.calls, []) + self.assertEqual(descriptor.calls, []) def test_negativeOneFileDescriptor(self): @@ -271,7 +271,7 @@ reactor.addReader(descriptor) client.send('x') self.runReactor(reactor) - self.assertEquals(descriptor._received, "x") + self.assertEqual(descriptor._received, "x") def test_lostFileDescriptor(self): diff --git a/lib/twisted-trunk/twisted/internet/test/test_gtkreactor.py b/lib/twisted-trunk/twisted/internet/test/test_gtkreactor.py --- a/lib/twisted-trunk/twisted/internet/test/test_gtkreactor.py +++ b/lib/twisted-trunk/twisted/internet/test/test_gtkreactor.py @@ -47,9 +47,9 @@ def lookForDeprecationWarning(self, testmethod, attributeName): warningsShown = self.flushWarnings([testmethod]) - self.assertEquals(len(warningsShown), 1) + self.assertEqual(len(warningsShown), 1) self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual( warningsShown[0]['message'], "twisted.internet.gtkreactor." + attributeName + " " "was deprecated in Twisted 10.1.0: All new applications should be " diff --git a/lib/twisted-trunk/twisted/internet/test/test_inotify.py b/lib/twisted-trunk/twisted/internet/test/test_inotify.py --- a/lib/twisted-trunk/twisted/internet/test/test_inotify.py +++ b/lib/twisted-trunk/twisted/internet/test/test_inotify.py @@ -72,7 +72,7 @@ expectedPath = self.dirname.child("foo.bar") notified = defer.Deferred() def cbNotified((watch, filename, events)): - self.assertEquals(filename, expectedPath) + self.assertEqual(filename, expectedPath) self.assertTrue(events & mask) notified.addCallback(cbNotified) @@ -316,11 +316,11 @@ masks to a human readable string. """ for mask, value in inotify._FLAG_TO_HUMAN: - self.assertEquals(inotify.humanReadableMask(mask)[0], value) + self.assertEqual(inotify.humanReadableMask(mask)[0], value) checkMask = ( inotify.IN_CLOSE_WRITE | inotify.IN_ACCESS | inotify.IN_OPEN) - self.assertEquals( + self.assertEqual( set(inotify.humanReadableMask(checkMask)), set(['close_write', 'access', 'open'])) @@ -389,7 +389,7 @@ notified = defer.Deferred() def cbNotified((ignored, filename, events)): - self.assertEquals(filename, expectedPath) + self.assertEqual(filename, expectedPath) self.assertTrue(events & inotify.IN_DELETE_SELF) def callIt(*args): @@ -425,7 +425,7 @@ notified = defer.Deferred() def cbNotified((ignored, filename, events)): - self.assertEquals(filename, expectedPath2) + self.assertEqual(filename, expectedPath2) self.assertTrue(events & inotify.IN_DELETE_SELF) def callIt(*args): @@ -477,8 +477,8 @@ self.assertTrue(self.inotify._isWatched(subdir2)) self.assertTrue(self.inotify._isWatched(subdir3)) created = someFiles + [subdir, subdir2, subdir3] - self.assertEquals(len(calls), len(created)) - self.assertEquals(calls, set(created)) + self.assertEqual(len(calls), len(created)) + self.assertEqual(calls, set(created)) except Exception: d.errback() else: diff --git a/lib/twisted-trunk/twisted/internet/test/test_iocp.py b/lib/twisted-trunk/twisted/internet/test/test_iocp.py --- a/lib/twisted-trunk/twisted/internet/test/test_iocp.py +++ b/lib/twisted-trunk/twisted/internet/test/test_iocp.py @@ -1,13 +1,102 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for L{twisted.internet.iocpreactor}. +""" + +import errno +from array import array +from struct import pack +from socket import AF_INET6, AF_INET, SOCK_STREAM, SOL_SOCKET, error, socket + +from zope.interface.verify import verifyClass + from twisted.trial import unittest +from twisted.python.log import msg try: from twisted.internet.iocpreactor import iocpsupport as _iocp, tcp, udp from twisted.internet.iocpreactor.reactor import IOCPReactor, EVENTS_PER_LOOP, KEY_NORMAL from twisted.internet.iocpreactor.interfaces import IReadWriteHandle + from twisted.internet.iocpreactor.const import SO_UPDATE_ACCEPT_CONTEXT except ImportError: skip = 'This test only applies to IOCPReactor' -from zope.interface.verify import verifyClass +try: + socket(AF_INET6, SOCK_STREAM).close() +except error, e: + ipv6Skip = str(e) +else: + ipv6Skip = None + +class SupportTests(unittest.TestCase): + """ + Tests for L{twisted.internet.iocpreactor.iocpsupport}, low-level reactor + implementation helpers. + """ + def _acceptAddressTest(self, family, localhost): + """ + Create a C{SOCK_STREAM} connection to localhost using a socket with an + address family of C{family} and assert that the result of + L{iocpsupport.get_accept_addrs} is consistent with the result of + C{socket.getsockname} and C{socket.getpeername}. + """ + msg("family = %r" % (family,)) + port = socket(family, SOCK_STREAM) + self.addCleanup(port.close) + port.bind(('', 0)) + port.listen(1) + client = socket(family, SOCK_STREAM) + self.addCleanup(client.close) + client.setblocking(False) + try: + client.connect((localhost, port.getsockname()[1])) + except error, (errnum, message): + self.assertIn(errnum, (errno.EINPROGRESS, errno.EWOULDBLOCK)) + + server = socket(family, SOCK_STREAM) + self.addCleanup(server.close) + buff = array('c', '\0' * 256) + self.assertEqual( + 0, _iocp.accept(port.fileno(), server.fileno(), buff, None)) + server.setsockopt( + SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, pack('I', server.fileno())) + self.assertEqual( + (family, client.getpeername()[:2], client.getsockname()[:2]), + _iocp.get_accept_addrs(server.fileno(), buff)) + + + def test_ipv4AcceptAddress(self): + """ + L{iocpsupport.get_accept_addrs} returns a three-tuple of address + information about the socket associated with the file descriptor passed + to it. For a connection using IPv4: + + - the first element is C{AF_INET} + - the second element is a two-tuple of a dotted decimal notation IPv4 + address and a port number giving the peer address of the connection + - the third element is the same type giving the host address of the + connection + """ + self._acceptAddressTest(AF_INET, '127.0.0.1') + + + def test_ipv6AcceptAddress(self): + """ + Like L{test_ipv4AcceptAddress}, but for IPv6 connections. In this case: + + - the first element is C{AF_INET6} + - the second element is a two-tuple of a hexadecimal IPv6 address + literal and a port number giving the peer address of the connection + - the third element is the same type giving the host address of the + connection + """ + self._acceptAddressTest(AF_INET6, '::1') + if ipv6Skip is not None: + test_ipv6AcceptAddress.skip = ipv6Skip + + class IOCPReactorTestCase(unittest.TestCase): def test_noPendingTimerEvents(self): @@ -46,7 +135,7 @@ for _ in range(EVENTS_PER_LOOP + 1): ir.port.postEvent(0, KEY_NORMAL, event) ir.doIteration(None) - self.assertEquals(fd.counter, EVENTS_PER_LOOP) + self.assertEqual(fd.counter, EVENTS_PER_LOOP) ir.doIteration(0) - self.assertEquals(fd.counter, EVENTS_PER_LOOP + 1) + self.assertEqual(fd.counter, EVENTS_PER_LOOP + 1) diff --git a/lib/twisted-trunk/twisted/internet/test/test_posixbase.py b/lib/twisted-trunk/twisted/internet/test/test_posixbase.py --- a/lib/twisted-trunk/twisted/internet/test/test_posixbase.py +++ b/lib/twisted-trunk/twisted/internet/test/test_posixbase.py @@ -108,9 +108,9 @@ warningsShown = self.flushWarnings( [self.test_IReactorArbitraryIsDeprecated]) - self.assertEquals(len(warningsShown), 1) - self.assertEquals(warningsShown[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(len(warningsShown), 1) + self.assertEqual(warningsShown[0]['category'], DeprecationWarning) + self.assertEqual( "twisted.internet.interfaces.IReactorArbitrary was deprecated " "in Twisted 10.1.0: See IReactorFDSet.", warningsShown[0]['message']) @@ -136,9 +136,9 @@ reactor.listenWith(fakePort) warnings = self.flushWarnings([self.test_listenWithIsDeprecated]) - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( "listenWith is deprecated since Twisted 10.1. " "See IReactorFDSet.", warnings[0]['message']) @@ -164,9 +164,9 @@ reactor.connectWith(fakeConnector) warnings = self.flushWarnings([self.test_connectWithIsDeprecated]) - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( "connectWith is deprecated since Twisted 10.1. " "See IReactorFDSet.", warnings[0]['message']) @@ -258,7 +258,7 @@ """ reactor = TimeoutReportReactor() timeout = self._checkIterationTimeout(reactor) - self.assertEquals(timeout, None) + self.assertEqual(timeout, None) def test_delayedCall(self): @@ -270,7 +270,7 @@ reactor = TimeoutReportReactor() reactor.callLater(100, lambda: None) timeout = self._checkIterationTimeout(reactor) - self.assertEquals(timeout, 100) + self.assertEqual(timeout, 100) def test_timePasses(self): @@ -283,7 +283,7 @@ reactor.callLater(100, lambda: None) reactor.now += 25 timeout = self._checkIterationTimeout(reactor) - self.assertEquals(timeout, 75) + self.assertEqual(timeout, 75) def test_multipleDelayedCalls(self): @@ -297,7 +297,7 @@ reactor.callLater(10, lambda: None) reactor.callLater(100, lambda: None) timeout = self._checkIterationTimeout(reactor) - self.assertEquals(timeout, 10) + self.assertEqual(timeout, 10) def test_resetDelayedCall(self): @@ -311,7 +311,7 @@ reactor.now += 25 call.reset(15) timeout = self._checkIterationTimeout(reactor) - self.assertEquals(timeout, 15) + self.assertEqual(timeout, 15) def test_delayDelayedCall(self): @@ -326,7 +326,7 @@ reactor.now += 10 call.delay(20) timeout = self._checkIterationTimeout(reactor) - self.assertEquals(timeout, 60) + self.assertEqual(timeout, 60) def test_cancelDelayedCall(self): @@ -338,7 +338,7 @@ call = reactor.callLater(50, lambda: None) call.cancel() timeout = self._checkIterationTimeout(reactor) - self.assertEquals(timeout, None) + self.assertEqual(timeout, None) @@ -384,4 +384,4 @@ port = unix.ConnectedDatagramPort(None, ClientProto()) port.stopListening = stopListening port.connectionFailed("goodbye") - self.assertEquals(self.called, True) + self.assertEqual(self.called, True) diff --git a/lib/twisted-trunk/twisted/internet/test/test_posixprocess.py b/lib/twisted-trunk/twisted/internet/test/test_posixprocess.py --- a/lib/twisted-trunk/twisted/internet/test/test_posixprocess.py +++ b/lib/twisted-trunk/twisted/internet/test/test_posixprocess.py @@ -35,7 +35,7 @@ try: fcntl.fcntl(fd, fcntl.F_GETFL) except IOError, err: - self.assertEquals( + self.assertEqual( errno.EBADF, err.errno, "fcntl(%d, F_GETFL) failed with unexpected errno %d" % ( fd, err.errno)) diff --git a/lib/twisted-trunk/twisted/internet/test/test_process.py b/lib/twisted-trunk/twisted/internet/test/test_process.py --- a/lib/twisted-trunk/twisted/internet/test/test_process.py +++ b/lib/twisted-trunk/twisted/internet/test/test_process.py @@ -273,7 +273,7 @@ "sys.stdout.flush()") def checkOutput(output): - self.assertEquals('[0, 1, 2, 3]', output) + self.assertEqual('[0, 1, 2, 3]', output) reactor = self.buildReactor() @@ -539,7 +539,7 @@ output = output.split('\0') # Drop the trailing \0. output.pop() - self.assertEquals(args, output) + self.assertEqual(args, output) def shutdown(result): reactor.stop() @@ -589,13 +589,13 @@ error.PotentialZombieWarning warnings = self.flushWarnings([self.test_deprecated]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "twisted.internet.error.PotentialZombieWarning was deprecated in " "Twisted 10.0.0: There is no longer any potential for zombie " "process.") - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) @@ -772,7 +772,7 @@ third = detector._listOpenFDs.func_name self.assertNotEquals(first, second) - self.assertEquals(second, third) + self.assertEqual(second, third) def test_accurateDevFDResults(self): @@ -784,7 +784,7 @@ self.procfs = False self.devfs = True self.accurateDevFDResults = True - self.assertEquals( + self.assertEqual( self.detector._getImplementation().func_name, '_devFDImplementation') @@ -798,7 +798,7 @@ self.procfs = False self.devfs = True self.accurateDevFDResults = False - self.assertEquals( + self.assertEqual( self.detector._getImplementation().func_name, '_fallbackFDImplementation') @@ -810,7 +810,7 @@ """ self.devfs = False self.procfs = True - self.assertEquals( + self.assertEqual( self.detector._getImplementation().func_name, '_procFDImplementation') @@ -824,7 +824,7 @@ self.devfs = False self.procfs = False self.revealResourceModule() - self.assertEquals( + self.assertEqual( self.detector._getImplementation().func_name, '_resourceFDImplementation') @@ -839,7 +839,7 @@ self.devfs = False self.procfs = False self.hideResourceModule() - self.assertEquals( + self.assertEqual( self.detector._getImplementation().func_name, '_fallbackFDImplementation') diff --git a/lib/twisted-trunk/twisted/internet/test/test_protocol.py b/lib/twisted-trunk/twisted/internet/test/test_protocol.py --- a/lib/twisted-trunk/twisted/internet/test/test_protocol.py +++ b/lib/twisted-trunk/twisted/internet/test/test_protocol.py @@ -90,10 +90,10 @@ def check(reactor, cc): cc.connectTCP('example.com', 1234, 4321, ('1.2.3.4', 9876)) host, port, factory, timeout, bindAddress = reactor.tcpClients.pop() - self.assertEquals(host, 'example.com') - self.assertEquals(port, 1234) - self.assertEquals(timeout, 4321) - self.assertEquals(bindAddress, ('1.2.3.4', 9876)) + self.assertEqual(host, 'example.com') + self.assertEqual(port, 1234) + self.assertEqual(timeout, 4321) + self.assertEqual(bindAddress, ('1.2.3.4', 9876)) return factory self._basicConnectTest(check) @@ -107,9 +107,9 @@ def check(reactor, cc): cc.connectUNIX('/foo/bar', 123, True) address, factory, timeout, checkPID = reactor.unixClients.pop() - self.assertEquals(address, '/foo/bar') - self.assertEquals(timeout, 123) - self.assertEquals(checkPID, True) + self.assertEqual(address, '/foo/bar') + self.assertEqual(timeout, 123) + self.assertEqual(checkPID, True) return factory self._basicConnectTest(check) @@ -124,11 +124,11 @@ expectedContextFactory = object() cc.connectSSL('example.com', 1234, expectedContextFactory, 4321, ('4.3.2.1', 5678)) host, port, factory, contextFactory, timeout, bindAddress = reactor.sslClients.pop() - self.assertEquals(host, 'example.com') - self.assertEquals(port, 1234) + self.assertEqual(host, 'example.com') + self.assertEqual(port, 1234) self.assertIdentical(contextFactory, expectedContextFactory) - self.assertEquals(timeout, 4321) - self.assertEquals(bindAddress, ('4.3.2.1', 5678)) + self.assertEqual(timeout, 4321) + self.assertEqual(bindAddress, ('4.3.2.1', 5678)) return factory self._basicConnectTest(check) @@ -198,13 +198,13 @@ connector = reactor.connectors.pop() # Sanity check - there is an outstanding delayed call to fire the # Deferred. - self.assertEquals(len(reactor.getDelayedCalls()), 1) + self.assertEqual(len(reactor.getDelayedCalls()), 1) # Cancel the Deferred, disconnecting the transport just set up and # cancelling the delayed call. d.cancel() - self.assertEquals(reactor.getDelayedCalls(), []) + self.assertEqual(reactor.getDelayedCalls(), []) # A real connector implementation is responsible for disconnecting the # transport as well. For our purposes, just check that someone told the @@ -286,12 +286,12 @@ # Sanity check - there is an outstanding delayed call to fire the # Deferred. - self.assertEquals(len(reactor.getDelayedCalls()), 1) + self.assertEqual(len(reactor.getDelayedCalls()), 1) # Cancel the Deferred, cancelling the delayed call. d.cancel() - self.assertEquals(reactor.getDelayedCalls(), []) + self.assertEqual(reactor.getDelayedCalls(), []) return self.assertFailure(d, CancelledError) diff --git a/lib/twisted-trunk/twisted/internet/test/test_qtreactor.py b/lib/twisted-trunk/twisted/internet/test/test_qtreactor.py --- a/lib/twisted-trunk/twisted/internet/test/test_qtreactor.py +++ b/lib/twisted-trunk/twisted/internet/test/test_qtreactor.py @@ -32,4 +32,4 @@ try: import twisted.internet.qtreactor except ImportError, e: - self.assertEquals(str(e), errorMessage) + self.assertEqual(str(e), errorMessage) diff --git a/lib/twisted-trunk/twisted/internet/test/test_tcp.py b/lib/twisted-trunk/twisted/internet/test/test_tcp.py --- a/lib/twisted-trunk/twisted/internet/test/test_tcp.py +++ b/lib/twisted-trunk/twisted/internet/test/test_tcp.py @@ -7,7 +7,7 @@ __metaclass__ = type -import socket +import socket, errno from zope.interface import implements from zope.interface.verify import verifyObject @@ -36,7 +36,6 @@ except ImportError: ClientContextFactory = None - def findFreePort(interface='127.0.0.1', type=socket.SOCK_STREAM): """ Ask the platform to allocate a free port on the specified interface, @@ -188,12 +187,12 @@ def test_blocking(self): skt = FakeSocket("someData") skt.setblocking(0) - self.assertEquals(skt.blocking, 0) + self.assertEqual(skt.blocking, 0) def test_recv(self): skt = FakeSocket("someData") - self.assertEquals(skt.recv(10), "someData") + self.assertEqual(skt.recv(10), "someData") def test_send(self): @@ -302,13 +301,13 @@ conn = Connection(skt, protocol) conn.doRead() warnings = self.flushWarnings([FakeProtocol.dataReceived]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]["message"], "Returning a value other than None from " "twisted.internet.test.test_tcp.FakeProtocol.dataReceived " "is deprecated since Twisted 11.0.0.") - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) def test_noTLSBeforeStartTLS(self): @@ -557,25 +556,10 @@ -class TCPPortTestsBuilder(ReactorBuilder, ObjectModelIntegrationMixin): +class StreamTransportTestsMixin: """ - Tests for L{IReactorRCP.listenTCP} + Mixin defining tests which apply to any port/connection based transport. """ - - def getListeningPort(self, reactor): - """ - Get a TCP port from a reactor - """ - return reactor.listenTCP(0, ServerFactory()) - - - def getExpectedConnectionLostLogMsg(self, port): - """ - Get the expected connection lost message for a TCP port - """ - return "(TCP Port %s Closed)" % (port.getHost().port,) - - def test_connectionLostLogMsg(self): """ When a connection is lost, an informative message should be logged @@ -617,6 +601,156 @@ +class TCPPortTestsBuilder(ReactorBuilder, ObjectModelIntegrationMixin, + StreamTransportTestsMixin): + """ + Tests for L{IReactorTCP.listenTCP} + """ + def getListeningPort(self, reactor): + """ + Get a TCP port from a reactor. + """ + return reactor.listenTCP(0, ServerFactory()) + + + def getExpectedConnectionLostLogMsg(self, port): + """ + Get the expected connection lost message for a TCP port. + """ + return "(TCP Port %s Closed)" % (port.getHost().port,) + + + def test_portGetHostOnIPv4(self): + """ + When no interface is passed to L{IReactorTCP.listenTCP}, the returned + listening port listens on an IPv4 address. + """ + reactor = self.buildReactor() + port = reactor.listenTCP(0, ServerFactory()) + address = port.getHost() + self.assertIsInstance(address, IPv4Address) + + + def _buildProtocolAddressTest(self, client, interface): + """ + Connect C{client} to a server listening on C{interface} started with + L{IReactorTCP.listenTCP} and return the address passed to the factory's + C{buildProtocol} method. + + @param client: A C{SOCK_STREAM} L{socket.socket} created with an address + family such that it will be able to connect to a server listening on + C{interface}. + + @param interface: A C{str} giving an address for a server to listen on. + This should almost certainly be the loopback address for some + address family supported by L{IReactorTCP.listenTCP}. + + @return: Whatever object, probably an L{IAddress} provider, is passed to + a server factory's C{buildProtocol} method when C{client} + establishes a connection. + """ + class ObserveAddress(ServerFactory): + def buildProtocol(self, address): + reactor.stop() + self.observedAddress = address + return Protocol() + + factory = ObserveAddress() + reactor = self.buildReactor() + port = reactor.listenTCP(0, factory, interface=interface) + client.setblocking(False) + try: + client.connect((port.getHost().host, port.getHost().port)) + except socket.error, (errnum, message): + self.assertIn(errnum, (errno.EINPROGRESS, errno.EWOULDBLOCK)) + + self.runReactor(reactor) + + return factory.observedAddress + + + def test_buildProtocolIPv4Address(self): + """ + When a connection is accepted over IPv4, an L{IPv4Address} is passed + to the factory's C{buildProtocol} method giving the peer's address. + """ + interface = '127.0.0.1' + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.addCleanup(client.close) + observedAddress = self._buildProtocolAddressTest(client, interface) + self.assertEqual( + IPv4Address('TCP', *client.getsockname()), observedAddress) + + + def _serverGetConnectionAddressTest(self, client, interface, which): + """ + Connect C{client} to a server listening on C{interface} started with + L{IReactorTCP.listenTCP} and return the address returned by one of the + server transport's address lookup methods, C{getHost} or C{getPeer}. + + @param client: A C{SOCK_STREAM} L{socket.socket} created with an address + family such that it will be able to connect to a server listening on + C{interface}. + + @param interface: A C{str} giving an address for a server to listen on. + This should almost certainly be the loopback address for some + address family supported by L{IReactorTCP.listenTCP}. + + @param which: A C{str} equal to either C{"getHost"} or C{"getPeer"} + determining which address will be returned. + + @return: Whatever object, probably an L{IAddress} provider, is returned + from the method indicated by C{which}. + """ + class ObserveAddress(Protocol): + def makeConnection(self, transport): + reactor.stop() + self.factory.address = getattr(transport, which)() + + reactor = self.buildReactor() + factory = ServerFactory() + factory.protocol = ObserveAddress + port = reactor.listenTCP(0, factory, interface=interface) + client.setblocking(False) + try: + client.connect((port.getHost().host, port.getHost().port)) + except socket.error, (errnum, message): + self.assertIn(errnum, (errno.EINPROGRESS, errno.EWOULDBLOCK)) + self.runReactor(reactor) + return factory.address + + + def test_serverGetHostOnIPv4(self): + """ + When a connection is accepted over IPv4, the server + L{ITransport.getHost} method returns an L{IPv4Address} giving the + address on which the server accepted the connection. + """ + interface = '127.0.0.1' + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.addCleanup(client.close) + hostAddress = self._serverGetConnectionAddressTest( + client, interface, 'getHost') + self.assertEqual( + IPv4Address('TCP', *client.getpeername()), hostAddress) + + + def test_serverGetPeerOnIPv4(self): + """ + When a connection is accepted over IPv4, the server + L{ITransport.getPeer} method returns an L{IPv4Address} giving the + address of the remote end of the connection. + """ + interface = '127.0.0.1' + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.addCleanup(client.close) + peerAddress = self._serverGetConnectionAddressTest( + client, interface, 'getPeer') + self.assertEqual( + IPv4Address('TCP', *client.getsockname()), peerAddress) + + + class StopStartReadingProtocol(Protocol): """ Protocol that pauses and resumes the transport a few times @@ -687,7 +821,7 @@ Make sure IOCPReactor didn't start several WSARecv operations that clobbered each other's results. """ - self.assertEquals(data, 'x'*(2*4096) + 'y'*(2*4096), + self.assertEqual(data, 'x'*(2*4096) + 'y'*(2*4096), 'did not get the right data') return DeferredList([ maybeDeferred(protos[0].transport.loseConnection), diff --git a/lib/twisted-trunk/twisted/internet/test/test_threads.py b/lib/twisted-trunk/twisted/internet/test/test_threads.py --- a/lib/twisted-trunk/twisted/internet/test/test_threads.py +++ b/lib/twisted-trunk/twisted/internet/test/test_threads.py @@ -10,6 +10,7 @@ from weakref import ref import gc +from twisted.python.threadable import isInIOThread from twisted.internet.test.reactormixins import ReactorBuilder from twisted.python.threadpool import ThreadPool @@ -161,4 +162,36 @@ self.assertIdentical(threadPoolRef(), None) + def test_isInIOThread(self): + """ + The reactor registers itself as the I/O thread when it runs so that + L{twisted.python.threadable.isInIOThread} returns C{True} if it is + called in the thread the reactor is running in. + """ + results = [] + reactor = self.buildReactor() + def check(): + results.append(isInIOThread()) + reactor.stop() + reactor.callWhenRunning(check) + self.runReactor(reactor) + self.assertEqual([True], results) + + + def test_isNotInIOThread(self): + """ + The reactor registers itself as the I/O thread when it runs so that + L{twisted.python.threadable.isInIOThread} returns C{False} if it is + called in a different thread than the reactor is running in. + """ + results = [] + reactor = self.buildReactor() + def check(): + results.append(isInIOThread()) + reactor.callFromThread(reactor.stop) + reactor.callInThread(check) + self.runReactor(reactor) + self.assertEqual([False], results) + + globals().update(ThreadTestsBuilder.makeTestCaseClasses()) diff --git a/lib/twisted-trunk/twisted/internet/test/test_udp.py b/lib/twisted-trunk/twisted/internet/test/test_udp.py --- a/lib/twisted-trunk/twisted/internet/test/test_udp.py +++ b/lib/twisted-trunk/twisted/internet/test/test_udp.py @@ -42,7 +42,7 @@ reactor = self.buildReactor() port = reactor.listenUDP( portNumber, DatagramProtocol(), interface=host) - self.assertEquals( + self.assertEqual( port.getHost(), IPv4Address('UDP', host, portNumber)) diff --git a/lib/twisted-trunk/twisted/internet/test/test_unix.py b/lib/twisted-trunk/twisted/internet/test/test_unix.py --- a/lib/twisted-trunk/twisted/internet/test/test_unix.py +++ b/lib/twisted-trunk/twisted/internet/test/test_unix.py @@ -23,7 +23,8 @@ from twisted.internet.protocol import ( ServerFactory, ClientFactory, DatagramProtocol) from twisted.internet.test.reactormixins import ReactorBuilder -from twisted.internet.test.test_tcp import TCPPortTestsBuilder +from twisted.internet.test.test_core import ObjectModelIntegrationMixin +from twisted.internet.test.test_tcp import StreamTransportTestsMixin @@ -87,7 +88,7 @@ path = _abstractPath(self) reactor = self.buildReactor() port = reactor.listenUNIX('\0' + path, ServerFactory()) - self.assertEquals(port.getHost(), UNIXAddress('\0' + path)) + self.assertEqual(port.getHost(), UNIXAddress('\0' + path)) if platform != 'linux2': test_listenOnLinuxAbstractNamespace.skip = ( 'Abstract namespace UNIX sockets only supported on Linux.') @@ -101,7 +102,7 @@ path = _abstractPath(self) reactor = self.buildReactor() connector = reactor.connectUNIX('\0' + path, ClientFactory()) - self.assertEquals( + self.assertEqual( connector.getDestination(), UNIXAddress('\0' + path)) if platform != 'linux2': test_connectToLinuxAbstractNamespace.skip = ( @@ -133,14 +134,14 @@ path = _abstractPath(self) reactor = self.buildReactor() port = reactor.listenUNIXDatagram('\0' + path, DatagramProtocol()) - self.assertEquals(port.getHost(), UNIXAddress('\0' + path)) + self.assertEqual(port.getHost(), UNIXAddress('\0' + path)) if platform != 'linux2': test_listenOnLinuxAbstractNamespace.skip = ( 'Abstract namespace UNIX sockets only supported on Linux.') -class UNIXPortTestsBuilder(TCPPortTestsBuilder): +class UNIXPortTestsBuilder(ReactorBuilder, ObjectModelIntegrationMixin, StreamTransportTestsMixin): """ Tests for L{IReactorUNIX.listenUnix} """ diff --git a/lib/twisted-trunk/twisted/internet/test/test_win32events.py b/lib/twisted-trunk/twisted/internet/test/test_win32events.py --- a/lib/twisted-trunk/twisted/internet/test/test_win32events.py +++ b/lib/twisted-trunk/twisted/internet/test/test_win32events.py @@ -5,6 +5,8 @@ Tests for implementations of L{IReactorWin32Events}. """ +from thread import get_ident + try: import win32event except ImportError: @@ -12,10 +14,65 @@ from zope.interface.verify import verifyObject +from twisted.python.threadable import isInIOThread from twisted.internet.interfaces import IReactorWin32Events +from twisted.internet.defer import Deferred from twisted.internet.test.reactormixins import ReactorBuilder +class Listener(object): + """ + L{Listener} is an object that can be added to a L{IReactorWin32Events} + reactor to receive callback notification when a Windows event is set. It + records what thread its callback is invoked in and fires a Deferred. + + @ivar success: A flag which is set to C{True} when the event callback is + called. + + @ivar logThreadID: The id of the thread in which the C{logPrefix} method is + called. + + @ivar eventThreadID: The id of the thread in which the event callback is + called. + + @ivar connLostThreadID: The id of the thread in which the C{connectionLost} + method is called. + + @ivar _finished: The L{Deferred} which will be fired when the event callback + is called. + """ + success = False + logThreadID = eventThreadID = connLostThreadID = None + + def __init__(self, finished): + self._finished = finished + + + def logPrefix(self): + self.logThreadID = get_ident() + return 'Listener' + + + def occurred(self): + self.success = True + self.eventThreadID = get_ident() + self._finished.callback(None) + + + def brokenOccurred(self): + raise RuntimeError("Some problem") + + + def returnValueOccurred(self): + return EnvironmentError("Entirely different problem") + + + def connectionLost(self, reason): + self.connLostThreadID = get_ident() + self._finished.errback(reason) + + + class Win32EventsTestsBuilder(ReactorBuilder): """ Builder defining tests relating to L{IReactorWin32Events}. @@ -34,25 +91,93 @@ def test_addEvent(self): """ When an event which has been added to the reactor is set, the action - associated with the event is invoked. + associated with the event is invoked in the reactor thread. """ + reactorThreadID = get_ident() reactor = self.buildReactor() event = win32event.CreateEvent(None, False, False, None) - class Listener(object): - success = False - - def logPrefix(self): - return 'Listener' - - def occurred(self): - self.success = True - reactor.stop() - - listener = Listener() + finished = Deferred() + finished.addCallback(lambda ignored: reactor.stop()) + listener = Listener(finished) reactor.addEvent(event, listener, 'occurred') reactor.callWhenRunning(win32event.SetEvent, event) self.runReactor(reactor) self.assertTrue(listener.success) + self.assertEqual(reactorThreadID, listener.logThreadID) + self.assertEqual(reactorThreadID, listener.eventThreadID) + def test_ioThreadDoesNotChange(self): + """ + Using L{IReactorWin32Events.addEvent} does not change which thread is + reported as the I/O thread. + """ + results = [] + def check(ignored): + results.append(isInIOThread()) + reactor.stop() + reactor = self.buildReactor() + event = win32event.CreateEvent(None, False, False, None) + finished = Deferred() + listener = Listener(finished) + finished.addCallback(check) + reactor.addEvent(event, listener, 'occurred') + reactor.callWhenRunning(win32event.SetEvent, event) + self.runReactor(reactor) + self.assertTrue(listener.success) + self.assertEqual([True], results) + + + def test_disconnectedOnError(self): + """ + If the event handler raises an exception, the event is removed from the + reactor and the handler's C{connectionLost} method is called in the I/O + thread and the exception is logged. + """ + reactorThreadID = get_ident() + reactor = self.buildReactor() + event = win32event.CreateEvent(None, False, False, None) + finished = self.assertFailure(Deferred(), RuntimeError) + finished.addCallback(lambda ignored: reactor.stop()) + listener = Listener(finished) + reactor.addEvent(event, listener, 'brokenOccurred') + reactor.callWhenRunning(win32event.SetEvent, event) + self.runReactor(reactor) + self.assertEqual(reactorThreadID, listener.connLostThreadID) + self.assertEqual(1, len(self.flushLoggedErrors(RuntimeError))) + + + def test_disconnectOnReturnValue(self): + """ + If the event handler returns a value, the event is removed from the + reactor and the handler's C{connectionLost} method is called in the I/O + thread. + """ + reactorThreadID = get_ident() + reactor = self.buildReactor() + event = win32event.CreateEvent(None, False, False, None) + finished = self.assertFailure(Deferred(), EnvironmentError) + finished.addCallback(lambda ignored: reactor.stop()) + listener = Listener(finished) + reactor.addEvent(event, listener, 'returnValueOccurred') + reactor.callWhenRunning(win32event.SetEvent, event) + self.runReactor(reactor) + self.assertEqual(reactorThreadID, listener.connLostThreadID) + + + def test_notDisconnectedOnShutdown(self): + """ + Event handlers added with L{IReactorWin32Events.addEvent} do not have + C{connectionLost} called on them if they are still active when the + reactor shuts down. + """ + reactor = self.buildReactor() + event = win32event.CreateEvent(None, False, False, None) + finished = Deferred() + listener = Listener(finished) + reactor.addEvent(event, listener, 'occurred') + reactor.callWhenRunning(reactor.stop) + self.runReactor(reactor) + self.assertIdentical(None, listener.connLostThreadID) + globals().update(Win32EventsTestsBuilder.makeTestCaseClasses()) diff --git a/lib/twisted-trunk/twisted/internet/tksupport.py b/lib/twisted-trunk/twisted/internet/tksupport.py --- a/lib/twisted-trunk/twisted/internet/tksupport.py +++ b/lib/twisted-trunk/twisted/internet/tksupport.py @@ -20,6 +20,13 @@ | root.protocol('WM_DELETE_WINDOW', reactor.stop) +When using Aqua Tcl/Tk on Mac OS X the standard Quit menu item in +your application might become unresponsive without the additional +fix:: + + | root.createcommand("::tk::mac::Quit", reactor.stop) + + at see: U{Tcl/TkAqua FAQ for more info} """ # system imports diff --git a/lib/twisted-trunk/twisted/internet/unix.py b/lib/twisted-trunk/twisted/internet/unix.py --- a/lib/twisted-trunk/twisted/internet/unix.py +++ b/lib/twisted-trunk/twisted/internet/unix.py @@ -90,7 +90,8 @@ return address.UNIXAddress(name) def startListening(self): - """Create and bind my socket, and begin listening on it. + """ + Create and bind my socket, and begin listening on it. This is called on unserialization, and must be called after creating a server to begin listening on the specified port. @@ -107,7 +108,7 @@ # left-over unix sockets on the filesystem. # If it fails, there's not much else we can # do. The bind() below will fail with an - # exception that actually propegates. + # exception that actually propagates. if stat.S_ISSOCK(os.stat(self.port).st_mode): os.remove(self.port) except: diff --git a/lib/twisted-trunk/twisted/internet/win32eventreactor.py b/lib/twisted-trunk/twisted/internet/win32eventreactor.py --- a/lib/twisted-trunk/twisted/internet/win32eventreactor.py +++ b/lib/twisted-trunk/twisted/internet/win32eventreactor.py @@ -13,9 +13,6 @@ from twisted.internet import win32eventreactor win32eventreactor.install() -Maintainer: Itamar Shtull-Trauring - - LIMITATIONS: 1. WaitForMultipleObjects and thus the event loop can only handle 64 objects. 2. Process running has some problems (see L{Process} docstring). @@ -50,6 +47,7 @@ # System imports import time import sys +from threading import Thread from zope.interface import implements @@ -65,6 +63,7 @@ from twisted.python import log, threadable, failure from twisted.internet.interfaces import IReactorFDSet, IReactorProcess from twisted.internet.interfaces import IReactorWin32Events +from twisted.internet.threads import blockingCallFromThread from twisted.internet._dumbwin32proc import Process @@ -241,6 +240,118 @@ return Process(self, processProtocol, executable, args, env, path) + +class _ThreadFDWrapper(object): + """ + This wraps an event handler and translates notification in the helper + L{Win32Reactor} thread into a notification in the primary reactor thread. + + @ivar _reactor: The primary reactor, the one to which event notification + will be sent. + + @ivar _fd: The L{FileDescriptor} to which the event will be dispatched. + + @ivar _action: A C{str} giving the method of C{_fd} which handles the event. + + @ivar _logPrefix: The pre-fetched log prefix string for C{_fd}, so that + C{_fd.logPrefix} does not need to be called in a non-main thread. + """ + def __init__(self, reactor, fd, action, logPrefix): + self._reactor = reactor + self._fd = fd + self._action = action + self._logPrefix = logPrefix + + + def logPrefix(self): + """ + Return the original handler's log prefix, as it was given to + C{__init__}. + """ + return self._logPrefix + + + def _execute(self): + """ + Callback fired when the associated event is set. Run the C{action} + callback on the wrapped descriptor in the main reactor thread and raise + or return whatever it raises or returns to cause this event handler to + be removed from C{self._reactor} if appropriate. + """ + return blockingCallFromThread( + self._reactor, lambda: getattr(self._fd, self._action)()) + + + def connectionLost(self, reason): + """ + Pass through to the wrapped descriptor, but in the main reactor thread + instead of the helper C{Win32Reactor} thread. + """ + self._reactor.callFromThread(self._fd.connectionLost, reason) + + + +class _ThreadedWin32EventsMixin(object): + """ + This mixin implements L{IReactorWin32Events} for another reactor by running + a L{Win32Reactor} in a separate thread and dispatching work to it. + + @ivar _reactor: The L{Win32Reactor} running in the other thread. This is + C{None} until it is actually needed. + + @ivar _reactorThread: The L{threading.Thread} which is running the + L{Win32Reactor}. This is C{None} until it is actually needed. + """ + implements(IReactorWin32Events) + + _reactor = None + _reactorThread = None + + + def _unmakeHelperReactor(self): + """ + Stop and discard the reactor started by C{_makeHelperReactor}. + """ + self._reactor.callFromThread(self._reactor.stop) + self._reactor = None + + + def _makeHelperReactor(self): + """ + Create and (in a new thread) start a L{Win32Reactor} instance to use for + the implementation of L{IReactorWin32Events}. + """ + self._reactor = Win32Reactor() + # This is a helper reactor, it is not the global reactor and its thread + # is not "the" I/O thread. Prevent it from registering it as such. + self._reactor._registerAsIOThread = False + self._reactorThread = Thread( + target=self._reactor.run, args=(False,)) + self.addSystemEventTrigger( + 'after', 'shutdown', self._unmakeHelperReactor) + self._reactorThread.start() + + + def addEvent(self, event, fd, action): + """ + @see: L{IReactorWin32Events} + """ + if self._reactor is None: + self._makeHelperReactor() + self._reactor.callFromThread( + self._reactor.addEvent, + event, _ThreadFDWrapper(self, fd, action, fd.logPrefix()), + "_execute") + + + def removeEvent(self, event): + """ + @see: L{IReactorWin32Events} + """ + self._reactor.callFromThread(self._reactor.removeEvent, event) + + + def install(): threadable.init(1) r = Win32Reactor() diff --git a/lib/twisted-trunk/twisted/lore/test/test_lint.py b/lib/twisted-trunk/twisted/lore/test/test_lint.py --- a/lib/twisted-trunk/twisted/lore/test/test_lint.py +++ b/lib/twisted-trunk/twisted/lore/test/test_lint.py @@ -75,7 +75,7 @@ '

    foo

    A link.' '') - self.assertEquals(self._lintCheck(True, documentSource), "") + self.assertEqual(self._lintCheck(True, documentSource), "") def test_textMatchesRef(self): @@ -91,7 +91,7 @@ '%s' '' '') - self.assertEquals( + self.assertEqual( self._lintCheck(True, documentSource % ("http://bar/baz",)), "") self.assertIn( "link text does not match href", diff --git a/lib/twisted-trunk/twisted/lore/test/test_lore.py b/lib/twisted-trunk/twisted/lore/test/test_lore.py --- a/lib/twisted-trunk/twisted/lore/test/test_lore.py +++ b/lib/twisted-trunk/twisted/lore/test/test_lore.py @@ -36,7 +36,6 @@ from twisted.trial import unittest from twisted.python.filepath import FilePath -from twisted.python.versions import Version from twisted.lore import tree, process, indexer, numberer, htmlbook, default from twisted.lore.default import factory @@ -318,7 +317,7 @@ actual = process.outputdirGenerator(join("/", 'home', 'joe', "myfile.html"), '.xhtml', inputdir, outputdir) expected = normp(join("/", 'away', 'joseph', 'myfile.xhtml')) - self.assertEquals(expected, actual) + self.assertEqual(expected, actual) def test_outputdirGeneratorBadInput(self): options = {'outputdir': '/away/joseph/', 'inputdir': '/home/joe/' } @@ -393,7 +392,7 @@ } dct = book.__dict__ for k in dct: - self.assertEquals(dct[k], expected[k]) + self.assertEqual(dct[k], expected[k]) def test_runningLore(self): options = lore.Options() @@ -413,7 +412,7 @@ '--index=%s' % indexFilename ]) result = lore.runGivenOptions(options) - self.assertEquals(None, result) + self.assertEqual(None, result) self.assertEqualFiles1("lore_index_file_unnumbered_out.html", indexFilename + ".html") @@ -436,7 +435,7 @@ '--index=%s' % indexFilename ]) result = lore.runGivenOptions(options) - self.assertEquals(None, result) + self.assertEqual(None, result) self.assertEqual( # XXX This doesn't seem like a very good index file. @@ -523,7 +522,7 @@ inputFilename, inputFilename2]) result = lore.runGivenOptions(options) - self.assertEquals(None, result) + self.assertEqual(None, result) #self.assertEqualFiles1("lore_index_file_out_multiple.html", indexFilename + ".tns") # VVV change to new, numbered files self.assertEqualFiles("lore_numbering_test_out.html", "lore_numbering_test.tns") @@ -598,7 +597,7 @@ tree.setIndexLink(templ, indexFilename) - self.assertEquals( + self.assertEqual( [], domhelpers.findElementsWithAttribute(templ, "class", @@ -619,7 +618,7 @@ tree.setIndexLink(templ, indexFilename) - self.assertEquals( + self.assertEqual( [], domhelpers.findElementsWithAttribute(templ, "class", @@ -1197,32 +1196,3 @@ """ processor = lore.getProcessor("lore", "html", options) self.assertNotIdentical(processor, None) - - - -class DeprecationTests(unittest.TestCase): - """ - Tests for deprecated APIs in L{twisted.lore.tree}. - """ - def test_comparePosition(self): - """ - L{tree.comparePosition} is deprecated. - """ - from twisted.web.microdom import parseString - element = parseString('').documentElement - self.assertEqual( - self.callDeprecated( - Version('Twisted', 9, 0, 0), - tree.comparePosition, element, element), - 0) - - - def test_compareMarkPos(self): - """ - L{tree.compareMarkPos} is deprecated. - """ - self.assertEqual( - self.callDeprecated( - Version('Twisted', 9, 0, 0), - tree.compareMarkPos, [0, 1], [1, 2]), - -1) diff --git a/lib/twisted-trunk/twisted/lore/test/test_man2lore.py b/lib/twisted-trunk/twisted/lore/test/test_man2lore.py --- a/lib/twisted-trunk/twisted/lore/test/test_man2lore.py +++ b/lib/twisted-trunk/twisted/lore/test/test_man2lore.py @@ -50,7 +50,7 @@ inputFile.seek(0) outputFile = StringIO() self.converter.convert(inputFile, outputFile) - self.assertEquals( + self.assertEqual( outputFile.getvalue(), _TRANSITIONAL_XHTML_DTD + expectedOutput) diff --git a/lib/twisted-trunk/twisted/lore/tree.py b/lib/twisted-trunk/twisted/lore/tree.py --- a/lib/twisted-trunk/twisted/lore/tree.py +++ b/lib/twisted-trunk/twisted/lore/tree.py @@ -12,8 +12,6 @@ from twisted.python import htmlizer, text from twisted.python.filepath import FilePath -from twisted.python.deprecate import deprecated -from twisted.python.versions import Version from twisted.web import domhelpers import process, latex, indexer, numberer, htmlbook @@ -471,34 +469,6 @@ -def compareMarkPos(a, b): - """ - Perform in every way identically to L{cmp} for valid inputs. - """ - linecmp = cmp(a[0], b[0]) - if linecmp: - return linecmp - return cmp(a[1], b[1]) -compareMarkPos = deprecated(Version('Twisted', 9, 0, 0))(compareMarkPos) - - - -def comparePosition(firstElement, secondElement): - """ - Compare the two elements given by their position in the document or - documents they were parsed from. - - @type firstElement: C{dom.Element} - @type secondElement: C{dom.Element} - - @return: C{-1}, C{0}, or C{1}, with the same meanings as the return value - of L{cmp}. - """ - return cmp(firstElement._markpos, secondElement._markpos) -comparePosition = deprecated(Version('Twisted', 9, 0, 0))(comparePosition) - - - def findNodeJustBefore(target, nodes): """ Find the last Element which is a sibling of C{target} and is in C{nodes}. diff --git a/lib/twisted-trunk/twisted/mail/scripts/mailmail.py b/lib/twisted-trunk/twisted/mail/scripts/mailmail.py --- a/lib/twisted-trunk/twisted/mail/scripts/mailmail.py +++ b/lib/twisted-trunk/twisted/mail/scripts/mailmail.py @@ -17,6 +17,7 @@ except: import StringIO +from twisted.copyright import version from twisted.internet import reactor from twisted.mail import smtp @@ -67,6 +68,11 @@ # Skip -bm -- it is the default + # Add a non-standard option for querying the version of this tool. + if '--version' in argv: + print 'mailmail version:', version + raise SystemExit() + # -bp lists queue information. Screw that. if '-bp' in argv: raise _unsupportedOption diff --git a/lib/twisted-trunk/twisted/mail/test/test_bounce.py b/lib/twisted-trunk/twisted/mail/test/test_bounce.py --- a/lib/twisted-trunk/twisted/mail/test/test_bounce.py +++ b/lib/twisted-trunk/twisted/mail/test/test_bounce.py @@ -21,12 +21,12 @@ Subject: test '''), 'moshez at example.com', 'nonexistant at example.org') - self.assertEquals(from_, '') - self.assertEquals(to, 'moshez at example.com') + self.assertEqual(from_, '') + self.assertEqual(to, 'moshez at example.com') mess = rfc822.Message(cStringIO.StringIO(s)) - self.assertEquals(mess['To'], 'moshez at example.com') - self.assertEquals(mess['From'], 'postmaster at example.org') - self.assertEquals(mess['subject'], 'Returned Mail: see transcript for details') + self.assertEqual(mess['To'], 'moshez at example.com') + self.assertEqual(mess['From'], 'postmaster at example.org') + self.assertEqual(mess['subject'], 'Returned Mail: see transcript for details') def testBounceMIME(self): pass diff --git a/lib/twisted-trunk/twisted/mail/test/test_imap.py b/lib/twisted-trunk/twisted/mail/test/test_imap.py --- a/lib/twisted-trunk/twisted/mail/test/test_imap.py +++ b/lib/twisted-trunk/twisted/mail/test/test_imap.py @@ -95,7 +95,7 @@ reader class. """ reader = codecs.getreader('imap4-utf-7')(StringIO('Hello&AP8-world')) - self.assertEquals(reader.read(), u'Hello\xffworld') + self.assertEqual(reader.read(), u'Hello\xffworld') def test_getwriter(self): @@ -106,7 +106,7 @@ output = StringIO() writer = codecs.getwriter('imap4-utf-7')(output) writer.write(u'Hello\xffworld') - self.assertEquals(output.getvalue(), 'Hello&AP8-world') + self.assertEqual(output.getvalue(), 'Hello&AP8-world') def test_encode(self): @@ -115,7 +115,7 @@ string according to the IMAP4 modified UTF-7 encoding rules. """ for (input, output) in self.tests: - self.assertEquals(input.encode('imap4-utf-7'), output) + self.assertEqual(input.encode('imap4-utf-7'), output) def test_decode(self): @@ -124,7 +124,7 @@ string according to the IMAP4 modified UTF-7 encoding rules. """ for (input, output) in self.tests: - self.assertEquals(input, output.decode('imap4-utf-7')) + self.assertEqual(input, output.decode('imap4-utf-7')) def test_printableSingletons(self): @@ -134,10 +134,10 @@ """ # All printables represent themselves for o in range(0x20, 0x26) + range(0x27, 0x7f): - self.failUnlessEqual(chr(o), chr(o).encode('imap4-utf-7')) - self.failUnlessEqual(chr(o), chr(o).decode('imap4-utf-7')) - self.failUnlessEqual('&'.encode('imap4-utf-7'), '&-') - self.failUnlessEqual('&-'.decode('imap4-utf-7'), '&') + self.assertEqual(chr(o), chr(o).encode('imap4-utf-7')) + self.assertEqual(chr(o), chr(o).decode('imap4-utf-7')) + self.assertEqual('&'.encode('imap4-utf-7'), '&-') + self.assertEqual('&-'.decode('imap4-utf-7'), '&') @@ -174,7 +174,7 @@ def cbProduced(result): self.assertIdentical(result, p) - self.assertEquals( + self.assertEqual( ''.join(c.buffer), '{119}\r\n' @@ -211,7 +211,7 @@ def cbProduced(result): self.failUnlessIdentical(result, p) - self.assertEquals( + self.assertEqual( ''.join(c.buffer), '{239}\r\n' @@ -259,7 +259,7 @@ def cbProduced(result): self.failUnlessIdentical(result, p) - self.assertEquals( + self.assertEqual( ''.join(c.buffer), '{354}\r\n' @@ -298,7 +298,7 @@ def cbProduced(result): self.failUnlessIdentical(result, p) - self.assertEquals( + self.assertEqual( ('{%d}\r\n' % len(b))+ b, ''.join(c.buffer)) return d.addCallback(cbProduced) @@ -354,22 +354,22 @@ ] for (input, output) in cases: - self.assertEquals(imap4._formatHeaders(input), output) + self.assertEqual(imap4._formatHeaders(input), output) def test_messageSet(self): m1 = MessageSet() m2 = MessageSet() - self.assertEquals(m1, m2) + self.assertEqual(m1, m2) m1 = m1 + (1, 3) - self.assertEquals(len(m1), 3) - self.assertEquals(list(m1), [1, 2, 3]) + self.assertEqual(len(m1), 3) + self.assertEqual(list(m1), [1, 2, 3]) m2 = m2 + (1, 3) - self.assertEquals(m1, m2) - self.assertEquals(list(m1 + m2), [1, 2, 3]) + self.assertEqual(m1, m2) + self.assertEqual(list(m1 + m2), [1, 2, 3]) def test_messageSetStringRepresentationWithWildcards(self): @@ -390,7 +390,7 @@ ] for i, o in zip(inputs, outputs): - self.assertEquals(str(i), o) + self.assertEqual(str(i), o) def test_messageSetStringRepresentationWithInversion(self): @@ -410,7 +410,7 @@ ] for i, o in zip(inputs, outputs): - self.assertEquals(str(i), o) + self.assertEqual(str(i), o) def test_quotedSplitter(self): @@ -470,7 +470,7 @@ self.assertRaises(imap4.MismatchedQuoting, imap4.splitQuoted, s) for (case, expected) in zip(cases, answers): - self.assertEquals(imap4.splitQuoted(case), expected) + self.assertEqual(imap4.splitQuoted(case), expected) def test_stringCollapser(self): @@ -495,7 +495,7 @@ ] for (case, expected) in zip(cases, answers): - self.assertEquals(imap4.collapseStrings(case), expected) + self.assertEqual(imap4.collapseStrings(case), expected) def test_parenParser(self): @@ -561,7 +561,7 @@ ] for (case, expected) in zip(cases, answers): - self.assertEquals(imap4.parseNestedParens(case), [expected]) + self.assertEqual(imap4.parseNestedParens(case), [expected]) # XXX This code used to work, but changes occurred within the # imap4.py module which made it no longer necessary for *all* of it @@ -572,7 +572,7 @@ # # for (case, expected) in zip(answers, cases): -# self.assertEquals('(' + imap4.collapseNestedLists(case) + ')', expected) +# self.assertEqual('(' + imap4.collapseNestedLists(case) + ')', expected) def test_fetchParserSimple(self): @@ -591,7 +591,7 @@ for (inp, outp) in cases: p = imap4._FetchParser() p.parseString(inp) - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], getattr(p, outp))) @@ -605,11 +605,11 @@ for (inp, outp) in cases: p = imap4._FetchParser() p.parseString(inp) - self.assertEquals(len(p.result), outp[0]) + self.assertEqual(len(p.result), outp[0]) p = [str(p).lower() for p in p.result] p.sort() outp[1].sort() - self.assertEquals(p, outp[1]) + self.assertEqual(p, outp[1]) def test_fetchParserBody(self): @@ -617,105 +617,105 @@ p = P() p.parseString('BODY') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, False) - self.assertEquals(p.result[0].header, None) - self.assertEquals(str(p.result[0]), 'BODY') + self.assertEqual(p.result[0].peek, False) + self.assertEqual(p.result[0].header, None) + self.assertEqual(str(p.result[0]), 'BODY') p = P() p.parseString('BODY.PEEK') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) - self.assertEquals(str(p.result[0]), 'BODY') + self.assertEqual(p.result[0].peek, True) + self.assertEqual(str(p.result[0]), 'BODY') p = P() p.parseString('BODY[]') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].empty, True) - self.assertEquals(str(p.result[0]), 'BODY[]') + self.assertEqual(p.result[0].empty, True) + self.assertEqual(str(p.result[0]), 'BODY[]') p = P() p.parseString('BODY[HEADER]') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, False) + self.assertEqual(p.result[0].peek, False) self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, True) - self.assertEquals(p.result[0].header.fields, ()) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER]') + self.assertEqual(p.result[0].header.negate, True) + self.assertEqual(p.result[0].header.fields, ()) + self.assertEqual(p.result[0].empty, False) + self.assertEqual(str(p.result[0]), 'BODY[HEADER]') p = P() p.parseString('BODY.PEEK[HEADER]') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) + self.assertEqual(p.result[0].peek, True) self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, True) - self.assertEquals(p.result[0].header.fields, ()) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER]') + self.assertEqual(p.result[0].header.negate, True) + self.assertEqual(p.result[0].header.fields, ()) + self.assertEqual(p.result[0].empty, False) + self.assertEqual(str(p.result[0]), 'BODY[HEADER]') p = P() p.parseString('BODY[HEADER.FIELDS (Subject Cc Message-Id)]') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, False) + self.assertEqual(p.result[0].peek, False) self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, False) - self.assertEquals(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER.FIELDS (Subject Cc Message-Id)]') + self.assertEqual(p.result[0].header.negate, False) + self.assertEqual(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) + self.assertEqual(p.result[0].empty, False) + self.assertEqual(str(p.result[0]), 'BODY[HEADER.FIELDS (Subject Cc Message-Id)]') p = P() p.parseString('BODY.PEEK[HEADER.FIELDS (Subject Cc Message-Id)]') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) + self.assertEqual(p.result[0].peek, True) self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, False) - self.assertEquals(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER.FIELDS (Subject Cc Message-Id)]') + self.assertEqual(p.result[0].header.negate, False) + self.assertEqual(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) + self.assertEqual(p.result[0].empty, False) + self.assertEqual(str(p.result[0]), 'BODY[HEADER.FIELDS (Subject Cc Message-Id)]') p = P() p.parseString('BODY.PEEK[HEADER.FIELDS.NOT (Subject Cc Message-Id)]') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) + self.assertEqual(p.result[0].peek, True) self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, True) - self.assertEquals(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER.FIELDS.NOT (Subject Cc Message-Id)]') + self.assertEqual(p.result[0].header.negate, True) + self.assertEqual(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) + self.assertEqual(p.result[0].empty, False) + self.assertEqual(str(p.result[0]), 'BODY[HEADER.FIELDS.NOT (Subject Cc Message-Id)]') p = P() p.parseString('BODY[1.MIME]<10.50>') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, False) + self.assertEqual(p.result[0].peek, False) self.failUnless(isinstance(p.result[0].mime, p.MIME)) - self.assertEquals(p.result[0].part, (0,)) - self.assertEquals(p.result[0].partialBegin, 10) - self.assertEquals(p.result[0].partialLength, 50) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[1.MIME]<10.50>') + self.assertEqual(p.result[0].part, (0,)) + self.assertEqual(p.result[0].partialBegin, 10) + self.assertEqual(p.result[0].partialLength, 50) + self.assertEqual(p.result[0].empty, False) + self.assertEqual(str(p.result[0]), 'BODY[1.MIME]<10.50>') p = P() p.parseString('BODY.PEEK[1.3.9.11.HEADER.FIELDS.NOT (Message-Id Date)]<103.69>') - self.assertEquals(len(p.result), 1) + self.assertEqual(len(p.result), 1) self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) + self.assertEqual(p.result[0].peek, True) self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].part, (0, 2, 8, 10)) - self.assertEquals(p.result[0].header.fields, ['MESSAGE-ID', 'DATE']) - self.assertEquals(p.result[0].partialBegin, 103) - self.assertEquals(p.result[0].partialLength, 69) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[1.3.9.11.HEADER.FIELDS.NOT (Message-Id Date)]<103.69>') + self.assertEqual(p.result[0].part, (0, 2, 8, 10)) + self.assertEqual(p.result[0].header.fields, ['MESSAGE-ID', 'DATE']) + self.assertEqual(p.result[0].partialBegin, 103) + self.assertEqual(p.result[0].partialLength, 69) + self.assertEqual(p.result[0].empty, False) + self.assertEqual(str(p.result[0]), 'BODY[1.3.9.11.HEADER.FIELDS.NOT (Message-Id Date)]<103.69>') def test_files(self): @@ -725,7 +725,7 @@ output = '"foo" "bar" "baz" {16}\r\nthis is a file\r\n "buz"' - self.assertEquals(imap4.collapseNestedLists(inputStructure), output) + self.assertEqual(imap4.collapseNestedLists(inputStructure), output) def test_quoteAvoider(self): @@ -736,7 +736,7 @@ output = '"foo" bar "baz" {16}\r\nthis is a file\r\n buz ""' - self.assertEquals(imap4.collapseNestedLists(input), output) + self.assertEqual(imap4.collapseNestedLists(input), output) def test_literals(self): @@ -745,7 +745,7 @@ ] for (case, expected) in cases: - self.assertEquals(imap4.parseNestedParens(case), expected) + self.assertEqual(imap4.parseNestedParens(case), expected) def test_queryBuilder(self): @@ -789,7 +789,7 @@ ] for (query, expected) in zip(inputs, outputs): - self.assertEquals(query, expected) + self.assertEqual(query, expected) def test_invalidIdListParser(self): @@ -875,14 +875,14 @@ ] for (input, expected) in zip(inputs, outputs): - self.assertEquals(imap4.parseIdList(input), expected) + self.assertEqual(imap4.parseIdList(input), expected) for (input, expected) in zip(inputs, lengths): if expected is None: self.assertRaises(TypeError, len, imap4.parseIdList(input)) else: L = len(imap4.parseIdList(input)) - self.assertEquals(L, expected, + self.assertEqual(L, expected, "len(%r) = %r != %r" % (input, L, expected)) class SimpleMailbox: @@ -1061,7 +1061,7 @@ d1 = self.connected.addCallback(strip(getCaps)).addErrback(self._ebGeneral) d = defer.gatherResults([self.loopback(), d1]) expected = {'IMAP4rev1': None, 'NAMESPACE': None, 'IDLE': None} - return d.addCallback(lambda _: self.assertEquals(expected, caps)) + return d.addCallback(lambda _: self.assertEqual(expected, caps)) def testCapabilityWithAuth(self): caps = {} @@ -1077,7 +1077,7 @@ expCap = {'IMAP4rev1': None, 'NAMESPACE': None, 'IDLE': None, 'AUTH': ['CRAM-MD5']} - return d.addCallback(lambda _: self.assertEquals(expCap, caps)) + return d.addCallback(lambda _: self.assertEqual(expCap, caps)) def testLogout(self): self.loggedOut = 0 @@ -1087,7 +1087,7 @@ self.client.logout().addCallback(strip(setLoggedOut)) self.connected.addCallback(strip(logout)).addErrback(self._ebGeneral) d = self.loopback() - return d.addCallback(lambda _: self.assertEquals(self.loggedOut, 1)) + return d.addCallback(lambda _: self.assertEqual(self.loggedOut, 1)) def testNoop(self): self.responses = None @@ -1098,7 +1098,7 @@ self.client.noop().addCallback(setResponses) self.connected.addCallback(strip(noop)).addErrback(self._ebGeneral) d = self.loopback() - return d.addCallback(lambda _: self.assertEquals(self.responses, [])) + return d.addCallback(lambda _: self.assertEqual(self.responses, [])) def testLogin(self): def login(): @@ -1109,8 +1109,8 @@ return d.addCallback(self._cbTestLogin) def _cbTestLogin(self, ignored): - self.assertEquals(self.server.account, SimpleServer.theAccount) - self.assertEquals(self.server.state, 'auth') + self.assertEqual(self.server.account, SimpleServer.theAccount) + self.assertEqual(self.server.state, 'auth') def testFailedLogin(self): def login(): @@ -1123,8 +1123,8 @@ return d.addCallback(self._cbTestFailedLogin) def _cbTestFailedLogin(self, ignored): - self.assertEquals(self.server.account, None) - self.assertEquals(self.server.state, 'unauth') + self.assertEqual(self.server.account, None) + self.assertEqual(self.server.state, 'unauth') def testLoginRequiringQuoting(self): @@ -1140,8 +1140,8 @@ return d.addCallback(self._cbTestLoginRequiringQuoting) def _cbTestLoginRequiringQuoting(self, ignored): - self.assertEquals(self.server.account, SimpleServer.theAccount) - self.assertEquals(self.server.state, 'auth') + self.assertEqual(self.server.account, SimpleServer.theAccount) + self.assertEqual(self.server.state, 'auth') def testNamespace(self): @@ -1159,7 +1159,7 @@ d1.addErrback(self._ebGeneral) d2 = self.loopback() d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.assertEquals(self.namespaceArgs, + d.addCallback(lambda _: self.assertEqual(self.namespaceArgs, [[['', '/']], [], []])) return d @@ -1184,8 +1184,8 @@ def _cbTestSelect(self, ignored): mbox = SimpleServer.theAccount.mailboxes['TEST-MAILBOX'] - self.assertEquals(self.server.mbox, mbox) - self.assertEquals(self.selectedArgs, { + self.assertEqual(self.server.mbox, mbox) + self.assertEqual(self.selectedArgs, { 'EXISTS': 9, 'RECENT': 3, 'UIDVALIDITY': 42, 'FLAGS': ('\\Flag1', 'Flag2', '\\AnotherSysFlag', 'LastFlag'), 'READ-WRITE': 1 @@ -1229,8 +1229,8 @@ def _cbTestExamine(self, ignored): mbox = SimpleServer.theAccount.mailboxes['TEST-MAILBOX'] - self.assertEquals(self.server.mbox, mbox) - self.assertEquals(self.examinedArgs, { + self.assertEqual(self.server.mbox, mbox) + self.assertEqual(self.examinedArgs, { 'EXISTS': 9, 'RECENT': 3, 'UIDVALIDITY': 42, 'FLAGS': ('\\Flag1', 'Flag2', '\\AnotherSysFlag', 'LastFlag'), 'READ-WRITE': False}) @@ -1258,12 +1258,12 @@ return d.addCallback(self._cbTestCreate, succeed, fail) def _cbTestCreate(self, ignored, succeed, fail): - self.assertEquals(self.result, [1] * len(succeed) + [0] * len(fail)) + self.assertEqual(self.result, [1] * len(succeed) + [0] * len(fail)) mbox = SimpleServer.theAccount.mailboxes.keys() answers = ['inbox', 'testbox', 'test/box', 'test', 'test/box/box'] mbox.sort() answers.sort() - self.assertEquals(mbox, [a.upper() for a in answers]) + self.assertEqual(mbox, [a.upper() for a in answers]) def testDelete(self): SimpleServer.theAccount.addMailbox('delete/me') @@ -1278,7 +1278,7 @@ d2 = self.loopback() d = defer.gatherResults([d1, d2]) d.addCallback(lambda _: - self.assertEquals(SimpleServer.theAccount.mailboxes.keys(), [])) + self.assertEqual(SimpleServer.theAccount.mailboxes.keys(), [])) return d def testIllegalInboxDelete(self): @@ -1315,7 +1315,7 @@ d1.addCallbacks(self._cbStopClient, self._ebGeneral) d2 = self.loopback() d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.assertEquals(str(self.failure.value), + d.addCallback(lambda _: self.assertEqual(str(self.failure.value), 'No such mailbox')) return d @@ -1341,7 +1341,7 @@ d = defer.gatherResults([d1, d2]) expected = "Hierarchically inferior mailboxes exist and \\Noselect is set" d.addCallback(lambda _: - self.assertEquals(str(self.failure.value), expected)) + self.assertEqual(str(self.failure.value), expected)) return d def testRename(self): @@ -1357,7 +1357,7 @@ d2 = self.loopback() d = defer.gatherResults([d1, d2]) d.addCallback(lambda _: - self.assertEquals(SimpleServer.theAccount.mailboxes.keys(), + self.assertEqual(SimpleServer.theAccount.mailboxes.keys(), ['NEWNAME'])) return d @@ -1399,7 +1399,7 @@ mboxes = SimpleServer.theAccount.mailboxes.keys() expected = ['newname', 'newname/m1', 'newname/m2'] mboxes.sort() - self.assertEquals(mboxes, [s.upper() for s in expected]) + self.assertEqual(mboxes, [s.upper() for s in expected]) def testSubscribe(self): def login(): @@ -1413,7 +1413,7 @@ d2 = self.loopback() d = defer.gatherResults([d1, d2]) d.addCallback(lambda _: - self.assertEquals(SimpleServer.theAccount.subscriptions, + self.assertEqual(SimpleServer.theAccount.subscriptions, ['THIS/MBOX'])) return d @@ -1430,7 +1430,7 @@ d2 = self.loopback() d = defer.gatherResults([d1, d2]) d.addCallback(lambda _: - self.assertEquals(SimpleServer.theAccount.subscriptions, + self.assertEqual(SimpleServer.theAccount.subscriptions, ['THAT/MBOX'])) return d @@ -1456,7 +1456,7 @@ def list(): return self.client.list('root', '%') d = self._listSetup(list) - d.addCallback(lambda listed: self.assertEquals( + d.addCallback(lambda listed: self.assertEqual( sortNest(listed), sortNest([ (SimpleMailbox.flags, "/", "ROOT/SUBTHING"), @@ -1470,7 +1470,7 @@ def lsub(): return self.client.lsub('root', '%') d = self._listSetup(lsub) - d.addCallback(self.assertEquals, + d.addCallback(self.assertEqual, [(SimpleMailbox.flags, "/", "ROOT/SUBTHING")]) return d @@ -1490,7 +1490,7 @@ d1.addCallbacks(self._cbStopClient, self._ebGeneral) d2 = self.loopback() d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.assertEquals( + d.addCallback(lambda _: self.assertEqual( self.statused, {'MESSAGES': 9, 'UIDNEXT': '10', 'UNSEEN': 4} )) @@ -1515,10 +1515,10 @@ return defer.gatherResults([d1, d2]).addCallback(self._cbTestFailedStatus) def _cbTestFailedStatus(self, ignored): - self.assertEquals( + self.assertEqual( self.statused, None ) - self.assertEquals( + self.assertEqual( self.failure.value.args, ('Could not open mailbox',) ) @@ -1546,12 +1546,12 @@ def _cbTestFullAppend(self, ignored, infile): mb = SimpleServer.theAccount.mailboxes['ROOT/SUBTHING'] - self.assertEquals(1, len(mb.messages)) - self.assertEquals( + self.assertEqual(1, len(mb.messages)) + self.assertEqual( (['\\SEEN', '\\DELETED'], 'Tue, 17 Jun 2003 11:22:16 -0600 (MDT)', 0), mb.messages[0][1:] ) - self.assertEquals(open(infile).read(), mb.messages[0][0].getvalue()) + self.assertEqual(open(infile).read(), mb.messages[0][0].getvalue()) def testPartialAppend(self): infile = util.sibpath(__file__, 'rfc822.message') @@ -1577,12 +1577,12 @@ def _cbTestPartialAppend(self, ignored, infile): mb = SimpleServer.theAccount.mailboxes['PARTIAL/SUBTHING'] - self.assertEquals(1, len(mb.messages)) - self.assertEquals( + self.assertEqual(1, len(mb.messages)) + self.assertEqual( (['\\SEEN'], 'Right now', 0), mb.messages[0][1:] ) - self.assertEquals(open(infile).read(), mb.messages[0][0].getvalue()) + self.assertEqual(open(infile).read(), mb.messages[0][0].getvalue()) def testCheck(self): SimpleServer.theAccount.addMailbox('root/subthing') @@ -1624,8 +1624,8 @@ return defer.gatherResults([d, d2]).addCallback(self._cbTestClose, m) def _cbTestClose(self, ignored, m): - self.assertEquals(len(m.messages), 1) - self.assertEquals(m.messages[0], ('Message 2', ('AnotherFlag',), None, 1)) + self.assertEqual(len(m.messages), 1) + self.assertEqual(m.messages[0], ('Message 2', ('AnotherFlag',), None, 1)) self.failUnless(m.closed) def testExpunge(self): @@ -1657,10 +1657,10 @@ return d.addCallback(self._cbTestExpunge, m) def _cbTestExpunge(self, ignored, m): - self.assertEquals(len(m.messages), 1) - self.assertEquals(m.messages[0], ('Message 2', ('AnotherFlag',), None, 1)) - - self.assertEquals(self.results, [0, 2]) + self.assertEqual(len(m.messages), 1) + self.assertEqual(m.messages[0], ('Message 2', ('AnotherFlag',), None, 1)) + + self.assertEqual(self.results, [0, 2]) @@ -1715,7 +1715,7 @@ the same as the query date. """ msgset = imap4.parseIdList('4:2') - self.assertEquals(list(msgset), [2, 3, 4]) + self.assertEqual(list(msgset), [2, 3, 4]) def test_searchSentOn(self): """ @@ -1833,8 +1833,8 @@ return d.addCallback(self._cbTestCramMD5) def _cbTestCramMD5(self, ignored): - self.assertEquals(self.authenticated, 1) - self.assertEquals(self.server.account, self.account) + self.assertEqual(self.authenticated, 1) + self.assertEqual(self.server.account, self.account) def testFailedCramMD5(self): self.server.challengers['CRAM-MD5'] = cred.credentials.CramMD5Credentials @@ -1855,8 +1855,8 @@ return d.addCallback(self._cbTestFailedCramMD5) def _cbTestFailedCramMD5(self, ignored): - self.assertEquals(self.authenticated, -1) - self.assertEquals(self.server.account, None) + self.assertEqual(self.authenticated, -1) + self.assertEqual(self.server.account, None) def testLOGIN(self): self.server.challengers['LOGIN'] = imap4.LOGINCredentials @@ -1875,8 +1875,8 @@ return d.addCallback(self._cbTestLOGIN) def _cbTestLOGIN(self, ignored): - self.assertEquals(self.authenticated, 1) - self.assertEquals(self.server.account, self.account) + self.assertEqual(self.authenticated, 1) + self.assertEqual(self.server.account, self.account) def testFailedLOGIN(self): self.server.challengers['LOGIN'] = imap4.LOGINCredentials @@ -1897,8 +1897,8 @@ return d.addCallback(self._cbTestFailedLOGIN) def _cbTestFailedLOGIN(self, ignored): - self.assertEquals(self.authenticated, -1) - self.assertEquals(self.server.account, None) + self.assertEqual(self.authenticated, -1) + self.assertEqual(self.server.account, None) def testPLAIN(self): self.server.challengers['PLAIN'] = imap4.PLAINCredentials @@ -1917,8 +1917,8 @@ return d.addCallback(self._cbTestPLAIN) def _cbTestPLAIN(self, ignored): - self.assertEquals(self.authenticated, 1) - self.assertEquals(self.server.account, self.account) + self.assertEqual(self.authenticated, 1) + self.assertEqual(self.server.account, self.account) def testFailedPLAIN(self): self.server.challengers['PLAIN'] = imap4.PLAINCredentials @@ -1939,8 +1939,8 @@ return d.addCallback(self._cbTestFailedPLAIN) def _cbTestFailedPLAIN(self, ignored): - self.assertEquals(self.authenticated, -1) - self.assertEquals(self.server.account, None) + self.assertEqual(self.authenticated, -1) + self.assertEqual(self.server.account, None) @@ -1964,7 +1964,7 @@ chal = 'challenge' cAuth = imap4.PLAINAuthenticator(username) response = cAuth.challengeResponse(secret, chal) - self.assertEquals(response, '\0%s\0%s' % (username, secret)) + self.assertEqual(response, '\0%s\0%s' % (username, secret)) def test_credentialsSetResponse(self): @@ -1976,8 +1976,8 @@ """ cred = imap4.PLAINCredentials() cred.setResponse('\0testuser\0secret') - self.assertEquals(cred.username, 'testuser') - self.assertEquals(cred.password, 'secret') + self.assertEqual(cred.username, 'testuser') + self.assertEqual(cred.password, 'secret') def test_credentialsInvalidResponse(self): @@ -2010,7 +2010,7 @@ def _cbTestReadWrite(self, ignored): E = self.client.events - self.assertEquals(E, [['modeChanged', 1]]) + self.assertEqual(E, [['modeChanged', 1]]) def testReadOnly(self): def login(): @@ -2025,7 +2025,7 @@ def _cbTestReadOnly(self, ignored): E = self.client.events - self.assertEquals(E, [['modeChanged', 0]]) + self.assertEqual(E, [['modeChanged', 0]]) def testFlagChange(self): flags = { @@ -2048,7 +2048,7 @@ expect = [['flagsChanged', {x[0]: x[1]}] for x in flags.items()] E.sort() expect.sort() - self.assertEquals(E, expect) + self.assertEqual(E, expect) def testNewMessages(self): def login(): @@ -2063,7 +2063,7 @@ def _cbTestNewMessages(self, ignored): E = self.client.events - self.assertEquals(E, [['newMessages', 10, None]]) + self.assertEqual(E, [['newMessages', 10, None]]) def testNewRecentMessages(self): def login(): @@ -2078,7 +2078,7 @@ def _cbTestNewRecentMessages(self, ignored): E = self.client.events - self.assertEquals(E, [['newMessages', None, 10]]) + self.assertEqual(E, [['newMessages', None, 10]]) def testNewMessagesAndRecent(self): def login(): @@ -2093,7 +2093,7 @@ def _cbTestNewMessagesAndRecent(self, ignored): E = self.client.events - self.assertEquals(E, [['newMessages', 20, None], ['newMessages', None, 10]]) + self.assertEqual(E, [['newMessages', 20, None], ['newMessages', None, 10]]) class ClientCapabilityTests(unittest.TestCase): @@ -2216,16 +2216,16 @@ transport.clear() self.server.dataReceived("01 LOGIN {8}\r\n") - self.assertEquals(transport.value(), "+ Ready for 8 octets of text\r\n") + self.assertEqual(transport.value(), "+ Ready for 8 octets of text\r\n") transport.clear() self.server.dataReceived("testuser {13}\r\n") - self.assertEquals(transport.value(), "+ Ready for 13 octets of text\r\n") + self.assertEqual(transport.value(), "+ Ready for 13 octets of text\r\n") transport.clear() self.server.dataReceived("password-test\r\n") - self.assertEquals(transport.value(), "01 OK LOGIN succeeded\r\n") - self.assertEquals(self.server.state, 'auth') + self.assertEqual(transport.value(), "01 OK LOGIN succeeded\r\n") + self.assertEqual(self.server.state, 'auth') self.server.connectionLost(error.ConnectionDone("Connection done.")) @@ -2267,14 +2267,14 @@ c.dataReceived('0003 OK FETCH completed\r\n') return d def test(res): - self.assertEquals(res, { + self.assertEqual(res, { 1: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], 'Subject: Suprise for your woman...\r\n\r\n']], 2: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], 'Subject: What you been doing. Order your meds here . ,. handcuff madsen\r\n\r\n']] }) - self.assertEquals(c.flags, {1: ['\\Seen']}) + self.assertEqual(c.flags, {1: ['\\Seen']}) return login( ).addCallback(strip(select) @@ -2390,14 +2390,14 @@ return d def test(res): - self.assertEquals(res, { + self.assertEqual(res, { 1: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], 'Subject: subject one\r\n']], 2: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], 'Subject: subject two\r\n']] }) - self.assertEquals(c.flags, {1: ['\\Recent'], 2: ['\\Seen']}) + self.assertEqual(c.flags, {1: ['\\Recent'], 2: ['\\Seen']}) return login( ).addCallback(strip(select) @@ -2437,11 +2437,11 @@ return d def test(res): - self.assertEquals(res, { + self.assertEqual(res, { 1: {'RFC822': 'Subject: first subject\r\n'}, 2: {'RFC822': 'Subject: second subject\r\n'}}) - self.assertEquals( + self.assertEqual( c.flags, {1: ['\\Seen'], 2: ['\\Recent', '\\Seen']}) return login( @@ -2503,7 +2503,7 @@ called. """ d = getattr(self.client, self.method)('foobox') - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 %s foobox\r\n' % (self.command,)) return d @@ -2529,7 +2529,7 @@ """ d = self._examineOrSelect() self._response('* 3 EXISTS') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {'READ-WRITE': False, 'EXISTS': 3}) @@ -2556,7 +2556,7 @@ """ d = self._examineOrSelect() self._response('* 5 RECENT') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {'READ-WRITE': False, 'RECENT': 5}) @@ -2583,7 +2583,7 @@ """ d = self._examineOrSelect() self._response('* OK [UNSEEN 8] Message 8 is first unseen') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {'READ-WRITE': False, 'UNSEEN': 8}) @@ -2610,7 +2610,7 @@ """ d = self._examineOrSelect() self._response('* OK [UIDVALIDITY 12345] UIDs valid') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {'READ-WRITE': False, 'UIDVALIDITY': 12345}) @@ -2637,7 +2637,7 @@ """ d = self._examineOrSelect() self._response('* OK [UIDNEXT 4392] Predicted next UID') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {'READ-WRITE': False, 'UIDNEXT': 4392}) @@ -2665,7 +2665,7 @@ d = self._examineOrSelect() self._response( '* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), { 'READ-WRITE': False, 'FLAGS': ('\\Answered', '\\Flagged', '\\Deleted', '\\Seen', @@ -2683,7 +2683,7 @@ self._response( '* OK [PERMANENTFLAGS (\\Starred)] Just one permanent flag in ' 'that list up there') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), { 'READ-WRITE': False, 'PERMANENTFLAGS': ('\\Starred',)}) @@ -2699,7 +2699,7 @@ '* OK [X-MADE-UP] I just made this response text up.') # The value won't show up in the result. It would be okay if it did # someday, perhaps. This shouldn't ever happen, though. - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {'READ-WRITE': False}) @@ -2710,7 +2710,7 @@ """ d = self._examineOrSelect() self._response('* OK') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {'READ-WRITE': False}) @@ -2772,7 +2772,7 @@ """ def _expunge(self): d = self.client.expunge() - self.assertEquals(self.transport.value(), '0001 EXPUNGE\r\n') + self.assertEqual(self.transport.value(), '0001 EXPUNGE\r\n') self.transport.clear() return d @@ -2791,7 +2791,7 @@ """ d = self._expunge() self._response([3, 3, 5, 8]) - self.assertEquals(self._extractDeferredResult(d), [3, 3, 5, 8]) + self.assertEqual(self._extractDeferredResult(d), [3, 3, 5, 8]) def test_nonIntegerExpunged(self): @@ -2826,7 +2826,7 @@ """ def _search(self): d = self.client.search(imap4.Query(text="ABCDEF")) - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 SEARCH (TEXT "ABCDEF")\r\n') return d @@ -2845,7 +2845,7 @@ """ d = self._search() self._response([2, 5, 10]) - self.assertEquals(self._extractDeferredResult(d), [2, 5, 10]) + self.assertEqual(self._extractDeferredResult(d), [2, 5, 10]) def test_nonIntegerFound(self): @@ -2875,13 +2875,13 @@ response. """ d = self.client.fetchUID('1:7') - self.assertEquals(self.transport.value(), '0001 FETCH 1:7 (UID)\r\n') + self.assertEqual(self.transport.value(), '0001 FETCH 1:7 (UID)\r\n') self.client.lineReceived('* 2 FETCH (UID 22)') self.client.lineReceived('* 3 FETCH (UID 23)') self.client.lineReceived('* 4 FETCH (UID 24)') self.client.lineReceived('* 5 FETCH (UID 25)') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), { 2: {'UID': '22'}, 3: {'UID': '23'}, @@ -2896,7 +2896,7 @@ fails with L{IllegalServerResponse}. """ d = self.client.fetchUID('1') - self.assertEquals(self.transport.value(), '0001 FETCH 1 (UID)\r\n') + self.assertEqual(self.transport.value(), '0001 FETCH 1 (UID)\r\n') self.client.lineReceived('* foo FETCH (UID 22)') self.client.lineReceived('0001 OK FETCH completed') self.assertRaises( @@ -2910,7 +2910,7 @@ L{IllegalServerResponse}. """ d = self.client.fetchUID('1:7') - self.assertEquals(self.transport.value(), '0001 FETCH 1:7 (UID)\r\n') + self.assertEqual(self.transport.value(), '0001 FETCH 1:7 (UID)\r\n') self.client.lineReceived('* 2 FETCH (UID 22)') self.client.lineReceived('* 3 FETCH (UID)') self.client.lineReceived('* 4 FETCH (UID 24)') @@ -2927,11 +2927,11 @@ the server's response. """ d = self.client.fetchBody('3') - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 3 (RFC822.TEXT)\r\n') self.client.lineReceived('* 3 FETCH (RFC822.TEXT "Message text")') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {3: {'RFC822.TEXT': 'Message text'}}) @@ -2945,11 +2945,11 @@ response. """ d = self.client.fetchSpecific('7') - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 7 BODY[]\r\n') self.client.lineReceived('* 7 FETCH (BODY[] "Some body")') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {7: [['BODY', [], "Some body"]]}) @@ -2959,12 +2959,12 @@ C{True} for the C{peek} parameter. """ d = self.client.fetchSpecific('6', peek=True) - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 6 BODY.PEEK[]\r\n') # BODY.PEEK responses are just BODY self.client.lineReceived('* 6 FETCH (BODY[] "Some body")') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {6: [['BODY', [], "Some body"]]}) @@ -2977,11 +2977,11 @@ response. """ d = self.client.fetchSpecific('7', headerNumber=(1, 2, 3)) - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 7 BODY[1.2.3]\r\n') self.client.lineReceived('* 7 FETCH (BODY[1.2.3] "Some body")') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {7: [['BODY', ['1.2.3'], "Some body"]]}) @@ -2994,11 +2994,11 @@ corresponding message data given by the server's response. """ d = self.client.fetchSpecific('8', headerType='TEXT') - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 8 BODY[TEXT]\r\n') self.client.lineReceived('* 8 FETCH (BODY[TEXT] "Some body")') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {8: [['BODY', ['TEXT'], "Some body"]]}) @@ -3012,11 +3012,11 @@ given by the server's response. """ d = self.client.fetchSpecific('4', headerType='TEXT', headerNumber=7) - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 4 BODY[7.TEXT]\r\n') self.client.lineReceived('* 4 FETCH (BODY[7.TEXT] "Some body")') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {4: [['BODY', ['7.TEXT'], "Some body"]]}) @@ -3029,7 +3029,7 @@ L{IllegalServerResponse}. """ d = self.client.fetchSpecific('8', headerType='TEXT') - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 8 BODY[TEXT]\r\n') self.client.lineReceived('* 8 FETCH (BODY[TEXT])') self.client.lineReceived('0001 OK FETCH completed') @@ -3045,11 +3045,11 @@ corresponding message data given by the server's response. """ d = self.client.fetchSpecific('8', headerType='MIME') - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 8 BODY[MIME]\r\n') self.client.lineReceived('* 8 FETCH (BODY[MIME] "Some body")') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {8: [['BODY', ['MIME'], "Some body"]]}) @@ -3064,11 +3064,11 @@ """ d = self.client.fetchSpecific( '9', headerType='TEXT', offset=17, length=3) - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 9 BODY[TEXT]<17.3>\r\n') self.client.lineReceived('* 9 FETCH (BODY[TEXT]<17> "foo")') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {9: [['BODY', ['TEXT'], '<17>', 'foo']]}) @@ -3081,7 +3081,7 @@ L{IllegalServerResponse}. """ d = self.client.fetchSpecific('8', headerType='TEXT') - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 8 BODY[TEXT]\r\n') self.client.lineReceived('* 8 FETCH (BODY[TEXT]<17>)') self.client.lineReceived('0001 OK FETCH completed') @@ -3098,11 +3098,11 @@ body). """ d = self.client.fetchSpecific('7') - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 FETCH 7 BODY[]\r\n') self.client.lineReceived('* 7 FETCH (BODY[] "test")') self.client.lineReceived('0001 OK FETCH completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {7: [['BODY', [], "test"]]}) @@ -3133,12 +3133,12 @@ @param item: The data item which is expected to be specified. """ d = getattr(self.client, method)('3', ('\\Read', '\\Seen'), False) - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 STORE 3 ' + item + ' (\\Read \\Seen)\r\n') self.client.lineReceived('* 3 FETCH (FLAGS (\\Read \\Seen))') self.client.lineReceived('0001 OK STORE completed') - self.assertEquals( + self.assertEqual( self._extractDeferredResult(d), {3: {'FLAGS': ['\\Read', '\\Seen']}}) @@ -3153,11 +3153,11 @@ @param item: The data item which is expected to be specified. """ d = getattr(self.client, method)('3', ('\\Read', '\\Seen'), True) - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 STORE 3 ' + item + ' (\\Read \\Seen)\r\n') self.client.lineReceived('0001 OK STORE completed') - self.assertEquals(self._extractDeferredResult(d), {}) + self.assertEqual(self._extractDeferredResult(d), {}) def _flagsSilentlyWithUnsolicitedDataTest(self, method, item): @@ -3171,13 +3171,13 @@ @param item: The data item which is expected to be specified. """ d = getattr(self.client, method)('3', ('\\Read', '\\Seen'), True) - self.assertEquals( + self.assertEqual( self.transport.value(), '0001 STORE 3 ' + item + ' (\\Read \\Seen)\r\n') self.client.lineReceived('* 2 FETCH (FLAGS (\\Read \\Seen))') self.client.lineReceived('0001 OK STORE completed') - self.assertEquals(self._extractDeferredResult(d), {}) - self.assertEquals(self.client.flags, {2: ['\\Read', '\\Seen']}) + self.assertEqual(self._extractDeferredResult(d), {}) + self.assertEqual(self.client.flags, {2: ['\\Read', '\\Seen']}) def test_setFlags(self): @@ -3342,8 +3342,8 @@ ).addErrback(self._ebGeneral) def check(ignored): - self.assertEquals(self.result, self.expected) - self.assertEquals(self.storeArgs, self.expectedArgs) + self.assertEqual(self.result, self.expected) + self.assertEqual(self.storeArgs, self.expectedArgs) d = loopback.loopbackTCP(self.server, self.client, noisy=False) d.addCallback(check) return d @@ -3407,7 +3407,7 @@ ).addErrback(self._ebGeneral) d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(lambda x : self.assertEquals(self.result, self.expected)) + d.addCallback(lambda x : self.assertEqual(self.result, self.expected)) return d def testFetchUID(self): @@ -3468,21 +3468,23 @@ The month name in the date is locale independent. """ # Fake that we're in a language where December is not Dec - currentLocale = locale.getlocale() + currentLocale = locale.setlocale(locale.LC_ALL, None) locale.setlocale(locale.LC_ALL, "es_AR.UTF8") self.addCleanup(locale.setlocale, locale.LC_ALL, currentLocale) return self.testFetchInternalDate(1) - # if alternate locale is not available, the previous test will be - # skipped, please install this locale for it to run - currentLocale = locale.getlocale() + # if alternate locale is not available, the previous test will be skipped, + # please install this locale for it to run. Avoid using locale.getlocale to + # learn the current locale; its values don't round-trip well on all + # platforms. Fortunately setlocale returns a value which does round-trip + # well. + currentLocale = locale.setlocale(locale.LC_ALL, None) try: - try: - locale.setlocale(locale.LC_ALL, "es_AR.UTF8") - except locale.Error: - test_fetchInternalDateLocaleIndependent.skip = ( - "The es_AR.UTF8 locale is not installed.") - finally: + locale.setlocale(locale.LC_ALL, "es_AR.UTF8") + except locale.Error: + test_fetchInternalDateLocaleIndependent.skip = ( + "The es_AR.UTF8 locale is not installed.") + else: locale.setlocale(locale.LC_ALL, currentLocale) @@ -3672,7 +3674,7 @@ self.connected.addErrback(self._ebGeneral) d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(lambda ign: self.assertEquals(self.result, self.expected)) + d.addCallback(lambda ign: self.assertEqual(self.result, self.expected)) return d @@ -3707,7 +3709,7 @@ self.connected.addErrback(self._ebGeneral) d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(lambda ign: self.assertEquals(self.result, self.expected)) + d.addCallback(lambda ign: self.assertEqual(self.result, self.expected)) return d @@ -3837,7 +3839,7 @@ d = self.connected.addCallback(strip(search)) def searched(results): - self.assertEquals(results, expectedMessages) + self.assertEqual(results, expectedMessages) d.addCallback(searched) d.addCallback(self._cbStopClient) d.addErrback(self._ebGeneral) @@ -3991,9 +3993,9 @@ # Ensure no short-circuiting wierdness is going on self.failIf(self.result is self.expected) - self.assertEquals(self.result, self.expected) - self.assertEquals(self.uid, self.server_received_uid) - self.assertEquals( + self.assertEqual(self.result, self.expected) + self.assertEqual(self.uid, self.server_received_uid) + self.assertEqual( imap4.parseNestedParens(self.query), self.server_received_query ) @@ -4052,10 +4054,10 @@ for (k, v) in self.expected.items(): v['UID'] = str(k) - self.assertEquals(self.result, self.expected) - self.assertEquals(self.uid, self.server_received_uid) - self.assertEquals(self.parts, self.server_received_parts) - self.assertEquals(imap4.parseIdList(self.messages), + self.assertEqual(self.result, self.expected) + self.assertEqual(self.uid, self.server_received_uid) + self.assertEqual(self.parts, self.server_received_parts) + self.assertEqual(imap4.parseIdList(self.messages), imap4.parseIdList(self.server_received_messages)) d = loopback.loopbackTCP(self.server, self.client, noisy=False) @@ -4112,13 +4114,13 @@ def cbCopy(results): for a in m.args: - self.assertEquals(a[0].read(), "open") - self.assertEquals(a[1], "flags") - self.assertEquals(a[2], "internaldate") + self.assertEqual(a[0].read(), "open") + self.assertEqual(a[1], "flags") + self.assertEqual(a[2], "internaldate") for (status, result) in results: self.failUnless(status) - self.assertEquals(result, None) + self.assertEqual(result, None) return d.addCallback(cbCopy) @@ -4137,17 +4139,17 @@ seen = [] for a in m.args: seen.append(a[0].read()) - self.assertEquals(a[1], ()) - self.assertEquals(a[2], "Date") + self.assertEqual(a[1], ()) + self.assertEqual(a[2], "Date") seen.sort() exp = ["Header-Counter: %d\r\n\r\nBody %d" % (i, i) for i in range(1, 11)] exp.sort() - self.assertEquals(seen, exp) + self.assertEqual(seen, exp) for (status, result) in results: self.failUnless(status) - self.assertEquals(result, None) + self.assertEqual(result, None) return d.addCallback(cbCopy) @@ -4162,7 +4164,7 @@ d = f([im for im in zip(range(1, 11), msgs)], 'tag', m) def cbCopy(results): - self.assertEquals(results, zip([1] * 10, range(1, 11))) + self.assertEqual(results, zip([1] * 10, range(1, 11))) for (orig, new) in zip(msgs, m.msgs): self.assertIdentical(orig, new) @@ -4201,9 +4203,9 @@ map(self.connected.addCallback, map(strip, methods)) self.connected.addCallbacks(self._cbStopClient, self._ebGeneral) def check(ignored): - self.assertEquals(self.server.startedTLS, True) - self.assertEquals(self.client.startedTLS, True) - self.assertEquals(len(called), len(methods)) + self.assertEqual(self.server.startedTLS, True) + self.assertEqual(self.client.startedTLS, True) + self.assertEqual(len(called), len(methods)) d = self.loopback() d.addCallback(check) return d @@ -4221,7 +4223,7 @@ ).addErrback(self._ebGeneral) d = self.loopback() - d.addCallback(lambda x : self.assertEquals(len(success), 1)) + d.addCallback(lambda x : self.assertEqual(len(success), 1)) return d @@ -4468,7 +4470,7 @@ # call resumeProducing on its producer). It doesn't matter: just # make sure the surrounding structure is okay, and that no # exceptions occurred. - self.assertEquals( + self.assertEqual( self.transport.value(), '* 1 FETCH (BODY[] )\r\n' '01 OK FETCH completed\r\n' diff --git a/lib/twisted-trunk/twisted/mail/test/test_mail.py b/lib/twisted-trunk/twisted/mail/test/test_mail.py --- a/lib/twisted-trunk/twisted/mail/test/test_mail.py +++ b/lib/twisted-trunk/twisted/mail/test/test_mail.py @@ -56,57 +56,57 @@ d = dict([(x, x + 10) for x in range(10)]) d = mail.mail.DomainWithDefaultDict(d, 'Default') - self.assertEquals(len(d), 10) - self.assertEquals(list(iter(d)), range(10)) - self.assertEquals(list(d.iterkeys()), list(iter(d))) + self.assertEqual(len(d), 10) + self.assertEqual(list(iter(d)), range(10)) + self.assertEqual(list(d.iterkeys()), list(iter(d))) items = list(d.iteritems()) items.sort() - self.assertEquals(items, [(x, x + 10) for x in range(10)]) + self.assertEqual(items, [(x, x + 10) for x in range(10)]) values = list(d.itervalues()) values.sort() - self.assertEquals(values, range(10, 20)) + self.assertEqual(values, range(10, 20)) items = d.items() items.sort() - self.assertEquals(items, [(x, x + 10) for x in range(10)]) + self.assertEqual(items, [(x, x + 10) for x in range(10)]) values = d.values() values.sort() - self.assertEquals(values, range(10, 20)) + self.assertEqual(values, range(10, 20)) for x in range(10): - self.assertEquals(d[x], x + 10) - self.assertEquals(d.get(x), x + 10) + self.assertEqual(d[x], x + 10) + self.assertEqual(d.get(x), x + 10) self.failUnless(x in d) self.failUnless(d.has_key(x)) del d[2], d[4], d[6] - self.assertEquals(len(d), 7) - self.assertEquals(d[2], 'Default') - self.assertEquals(d[4], 'Default') - self.assertEquals(d[6], 'Default') + self.assertEqual(len(d), 7) + self.assertEqual(d[2], 'Default') + self.assertEqual(d[4], 'Default') + self.assertEqual(d[6], 'Default') d.update({'a': None, 'b': (), 'c': '*'}) - self.assertEquals(len(d), 10) - self.assertEquals(d['a'], None) - self.assertEquals(d['b'], ()) - self.assertEquals(d['c'], '*') + self.assertEqual(len(d), 10) + self.assertEqual(d['a'], None) + self.assertEqual(d['b'], ()) + self.assertEqual(d['c'], '*') d.clear() - self.assertEquals(len(d), 0) + self.assertEqual(len(d), 0) - self.assertEquals(d.setdefault('key', 'value'), 'value') - self.assertEquals(d['key'], 'value') + self.assertEqual(d.setdefault('key', 'value'), 'value') + self.assertEqual(d['key'], 'value') - self.assertEquals(d.popitem(), ('key', 'value')) - self.assertEquals(len(d), 0) + self.assertEqual(d.popitem(), ('key', 'value')) + self.assertEqual(len(d), 0) dcopy = d.copy() - self.assertEquals(d.domains, dcopy.domains) - self.assertEquals(d.default, dcopy.default) + self.assertEqual(d.domains, dcopy.domains) + self.assertEqual(d.default, dcopy.default) def _stringificationTest(self, stringifier): @@ -150,7 +150,7 @@ self.assertRaises(smtp.AddressError, self.domain.exists, "any user") def testRelay(self): - self.assertEquals( + self.assertEqual( self.domain.willRelay("random q emailer", "protocol"), False ) @@ -187,7 +187,7 @@ return self.fp.eomReceived().addCallback(self._cbFinalName) def _cbFinalName(self, result): - self.assertEquals(result, self.final) + self.assertEqual(result, self.final) self.failUnless(self.f.closed) self.failIf(os.path.exists(self.name)) @@ -196,7 +196,7 @@ for line in contents.splitlines(): self.fp.lineReceived(line) self.fp.eomReceived() - self.assertEquals(file(self.final).read(), contents) + self.assertEqual(file(self.final).read(), contents) def testInterrupted(self): contents = "first line\nsecond line\n" @@ -411,7 +411,7 @@ mbox.AppendFactory = FailingMaildirMailboxAppendMessageTask d = self._appendMessages(mbox, ["X" * i for i in range(1, 11)]) - d.addCallback(self.assertEquals, [None] * 10) + d.addCallback(self.assertEqual, [None] * 10) d.addCallback(self._cbTestAppend, mbox) return d @@ -422,8 +422,8 @@ and that each has the expected contents, and that they are in the same order as that in which they were appended. """ - self.assertEquals(len(mbox.listMessages()), 10) - self.assertEquals( + self.assertEqual(len(mbox.listMessages()), 10) + self.assertEqual( [len(mbox.getMessage(i).read()) for i in range(10)], range(1, 11)) # test in the right order: last to first error location. @@ -472,8 +472,8 @@ and that each has the expected contents, and that they are in the same order as that in which they were appended. """ - self.assertEquals(len(mbox.listMessages()), 10) - self.assertEquals( + self.assertEqual(len(mbox.listMessages()), 10) + self.assertEqual( [len(mbox.getMessage(i).read()) for i in range(10)], range(1, 11)) @@ -543,12 +543,12 @@ i = i + 1 mb = mail.maildir.MaildirMailbox(self.d) - self.assertEquals(mb.listMessages(), range(1, 11)) - self.assertEquals(mb.listMessages(1), 2) - self.assertEquals(mb.listMessages(5), 6) + self.assertEqual(mb.listMessages(), range(1, 11)) + self.assertEqual(mb.listMessages(1), 2) + self.assertEqual(mb.listMessages(5), 6) - self.assertEquals(mb.getMessage(6).read(), 'x' * 7) - self.assertEquals(mb.getMessage(1).read(), 'x' * 2) + self.assertEqual(mb.getMessage(6).read(), 'x' * 7) + self.assertEqual(mb.getMessage(1).read(), 'x' * 2) d = {} for i in range(10): @@ -559,12 +559,12 @@ p, f = os.path.split(msgs[5]) mb.deleteMessage(5) - self.assertEquals(mb.listMessages(5), 0) + self.assertEqual(mb.listMessages(5), 0) self.failUnless(os.path.exists(j(self.d, '.Trash', 'cur', f))) self.failIf(os.path.exists(j(self.d, msgs[5]))) mb.undeleteMessages() - self.assertEquals(mb.listMessages(5), 6) + self.assertEqual(mb.listMessages(5), 6) self.failIf(os.path.exists(j(self.d, '.Trash', 'cur', f))) self.failUnless(os.path.exists(j(self.d, msgs[5]))) @@ -584,13 +584,13 @@ for (u, p) in toAdd: self.failUnless(u in self.D.dbm) - self.assertEquals(self.D.dbm[u], p) + self.assertEqual(self.D.dbm[u], p) self.failUnless(os.path.exists(os.path.join(self.P, u))) def testCredentials(self): creds = self.D.getCredentialsCheckers() - self.assertEquals(len(creds), 1) + self.assertEqual(len(creds), 1) self.failUnless(cred.checkers.ICredentialsChecker.providedBy(creds[0])) self.failUnless(cred.credentials.IUsernamePassword in creds[0].credentialInterfaces) @@ -605,7 +605,7 @@ ) t = self.D.requestAvatar('user', None, pop3.IMailbox) - self.assertEquals(len(t), 3) + self.assertEqual(len(t), 3) self.failUnless(t[0] is pop3.IMailbox) self.failUnless(pop3.IMailbox.providedBy(t[1])) @@ -622,7 +622,7 @@ ) creds = cred.credentials.UsernamePassword('user', 'password') - self.assertEquals(database.requestAvatarId(creds), 'user') + self.assertEqual(database.requestAvatarId(creds), 'user') class StubAliasableDomain(object): @@ -701,7 +701,7 @@ ) fp = StringIO.StringIO(hdr) m = rfc822.Message(fp) - self.assertEquals(len(m.items()), 1) + self.assertEqual(len(m.items()), 1) self.failUnless(m.has_key('Received')) def testValidateTo(self): @@ -769,8 +769,8 @@ ) def _cbAuthenticateAPOP(self, result): - self.assertEquals(len(result), 3) - self.assertEquals(result[0], pop3.IMailbox) + self.assertEqual(len(result), 3) + self.assertEqual(result[0], pop3.IMailbox) self.failUnless(pop3.IMailbox.providedBy(result[1])) result[2]() @@ -792,8 +792,8 @@ ) def _cbAuthenticatePASS(self, result): - self.assertEquals(len(result), 3) - self.assertEquals(result[0], pop3.IMailbox) + self.assertEqual(len(result), 3) + self.assertEqual(result[0], pop3.IMailbox) self.failUnless(pop3.IMailbox.providedBy(result[1])) result[2]() @@ -870,22 +870,22 @@ def testMailFrom(self): for i in range(10): - self.assertEquals(self.R.getMailFrom(), 'from-%d' % (i,)) + self.assertEqual(self.R.getMailFrom(), 'from-%d' % (i,)) self.R.sentMail(250, None, None, None, None) - self.assertEquals(self.R.getMailFrom(), None) + self.assertEqual(self.R.getMailFrom(), None) def testMailTo(self): for i in range(10): - self.assertEquals(self.R.getMailTo(), ['to-%d' % (i,)]) + self.assertEqual(self.R.getMailTo(), ['to-%d' % (i,)]) self.R.sentMail(250, None, None, None, None) - self.assertEquals(self.R.getMailTo(), None) + self.assertEqual(self.R.getMailTo(), None) def testMailData(self): for i in range(10): name = os.path.join(self.tmpdir, 'body-%d' % (i,)) - self.assertEquals(self.R.getMailData().read(), name) + self.assertEqual(self.R.getMailData().read(), name) self.R.sentMail(250, None, None, None, None) - self.assertEquals(self.R.getMailData(), None) + self.assertEqual(self.R.getMailData(), None) class Manager: def __init__(self): @@ -916,7 +916,7 @@ for i in self.messages: self.relay.sentMail(250, None, None, None, None) - self.assertEquals( + self.assertEqual( self.manager.success, [(self.factory, m) for m in self.messages] ) @@ -925,14 +925,14 @@ for i in self.messages: self.relay.sentMail(550, None, None, None, None) - self.assertEquals( + self.assertEqual( self.manager.failure, [(self.factory, m) for m in self.messages] ) def testConnectionLost(self): self.relay.connectionLost(failure.Failure(Exception())) - self.assertEquals(self.manager.done, [self.factory]) + self.assertEqual(self.manager.done, [self.factory]) class DirectoryQueueTestCase(unittest.TestCase): def setUp(self): @@ -954,19 +954,19 @@ def testWaiting(self): self.failUnless(self.queue.hasWaiting()) - self.assertEquals(len(self.queue.getWaiting()), 25) + self.assertEqual(len(self.queue.getWaiting()), 25) waiting = self.queue.getWaiting() self.queue.setRelaying(waiting[0]) - self.assertEquals(len(self.queue.getWaiting()), 24) + self.assertEqual(len(self.queue.getWaiting()), 24) self.queue.setWaiting(waiting[0]) - self.assertEquals(len(self.queue.getWaiting()), 25) + self.assertEqual(len(self.queue.getWaiting()), 25) def testRelaying(self): for m in self.queue.getWaiting(): self.queue.setRelaying(m) - self.assertEquals( + self.assertEqual( len(self.queue.getRelayed()), 25 - len(self.queue.getWaiting()) ) @@ -975,16 +975,16 @@ relayed = self.queue.getRelayed() self.queue.setWaiting(relayed[0]) - self.assertEquals(len(self.queue.getWaiting()), 1) - self.assertEquals(len(self.queue.getRelayed()), 24) + self.assertEqual(len(self.queue.getWaiting()), 1) + self.assertEqual(len(self.queue.getRelayed()), 24) def testDone(self): msg = self.queue.getWaiting()[0] self.queue.setRelaying(msg) self.queue.done(msg) - self.assertEquals(len(self.queue.getWaiting()), 24) - self.assertEquals(len(self.queue.getRelayed()), 0) + self.assertEqual(len(self.queue.getWaiting()), 24) + self.assertEqual(len(self.queue.getRelayed()), 0) self.failIf(msg in self.queue.getWaiting()) self.failIf(msg in self.queue.getRelayed()) @@ -997,7 +997,7 @@ envelopes.sort() for i in range(25): - self.assertEquals( + self.assertEqual( envelopes.pop(0), ['header', i] ) @@ -1078,8 +1078,8 @@ return self.mx.getMX('test.domain').addCallback(self._cbSimpleSuccess) def _cbSimpleSuccess(self, mx): - self.assertEquals(mx.preference, 0) - self.assertEquals(str(mx.name), 'the.email.test.domain') + self.assertEqual(mx.preference, 0) + self.assertEqual(str(mx.name), 'the.email.test.domain') def testSimpleFailure(self): self.mx.fallbackToDomain = False @@ -1636,35 +1636,35 @@ for l in lines: mail.alias.handle(result, l, 'TestCase', None) - self.assertEquals(result['user'], ['another at host', 'me at again']) - self.assertEquals(result['nextuser'], ['|/bin/program']) - self.assertEquals(result['moreusers'], [':/etc/include/filename']) - self.assertEquals(result['multiuser'], ['first at host', 'second at host', 'last at anotherhost']) + self.assertEqual(result['user'], ['another at host', 'me at again']) + self.assertEqual(result['nextuser'], ['|/bin/program']) + self.assertEqual(result['moreusers'], [':/etc/include/filename']) + self.assertEqual(result['multiuser'], ['first at host', 'second at host', 'last at anotherhost']) def testFileLoader(self): domains = {'': object()} result = mail.alias.loadAliasFile(domains, fp=aliasFile) - self.assertEquals(len(result), 3) + self.assertEqual(len(result), 3) group = result['testuser'] s = str(group) for a in ('address1', 'address2', 'address3', 'continuation at address', '/bin/process/this'): self.failIfEqual(s.find(a), -1) - self.assertEquals(len(group), 5) + self.assertEqual(len(group), 5) group = result['usertwo'] s = str(group) for a in ('thisaddress', 'thataddress', 'lastaddress'): self.failIfEqual(s.find(a), -1) - self.assertEquals(len(group), 3) + self.assertEqual(len(group), 3) group = result['lastuser'] s = str(group) - self.failUnlessEqual(s.find('/includable'), -1) + self.assertEqual(s.find('/includable'), -1) for a in ('/filename', 'program', 'address'): self.failIfEqual(s.find(a), -1, '%s not found' % a) - self.assertEquals(len(group), 3) + self.assertEqual(len(group), 3) def testMultiWrapper(self): msgs = LineBufferMessage(), LineBufferMessage(), LineBufferMessage() @@ -1678,7 +1678,7 @@ for m in msgs: self.failUnless(m.eom) self.failIf(m.lost) - self.assertEquals(self.lines, m.lines) + self.assertEqual(self.lines, m.lines) def testFileAlias(self): tmpfile = self.mktemp() @@ -1691,7 +1691,7 @@ def _cbTestFileAlias(self, ignored, tmpfile): lines = file(tmpfile).readlines() - self.assertEquals([L[:-1] for L in lines], self.lines) + self.assertEqual([L[:-1] for L in lines], self.lines) @@ -1843,7 +1843,7 @@ def _cbProcessAlias(ignored): lines = file('process.alias.out').readlines() - self.assertEquals([L[:-1] for L in lines], self.lines) + self.assertEqual([L[:-1] for L in lines], self.lines) return m.eomReceived().addCallback(_cbProcessAlias) @@ -1951,7 +1951,7 @@ mail.alias.FileWrapper('/file'), ]) expected.sort() - self.assertEquals(r1, expected) + self.assertEqual(r1, expected) res2 = A2.resolve(aliases) r2 = map(str, res2.objs) @@ -1961,7 +1961,7 @@ mail.alias.AddressAlias('user3', None, None) ]) expected.sort() - self.assertEquals(r2, expected) + self.assertEqual(r2, expected) res3 = A3.resolve(aliases) r3 = map(str, res3.objs) @@ -1972,7 +1972,7 @@ mail.alias.FileWrapper('/file'), ]) expected.sort() - self.assertEquals(r3, expected) + self.assertEqual(r3, expected) def test_cyclicAlias(self): @@ -1990,9 +1990,9 @@ 'alias3': A3 }) - self.assertEquals(aliases['alias1'].resolve(aliases), None) - self.assertEquals(aliases['alias2'].resolve(aliases), None) - self.assertEquals(aliases['alias3'].resolve(aliases), None) + self.assertEqual(aliases['alias1'].resolve(aliases), None) + self.assertEqual(aliases['alias2'].resolve(aliases), None) + self.assertEqual(aliases['alias3'].resolve(aliases), None) A4 = MockAliasGroup(['|echo', 'alias1'], domain, 'alias4') aliases['alias4'] = A4 @@ -2004,7 +2004,7 @@ mail.alias.MessageWrapper(DummyProcess(), 'echo') ]) expected.sort() - self.assertEquals(r, expected) + self.assertEqual(r, expected) diff --git a/lib/twisted-trunk/twisted/mail/test/test_options.py b/lib/twisted-trunk/twisted/mail/test/test_options.py --- a/lib/twisted-trunk/twisted/mail/test/test_options.py +++ b/lib/twisted-trunk/twisted/mail/test/test_options.py @@ -56,11 +56,11 @@ options = Options() options.opt_passwordfile(passwd.path) warnings = self.flushWarnings([self.testPasswordfileDeprecation]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 1) msg = deprecate.getDeprecationWarningString(options.opt_passwordfile, versions.Version('twisted.mail', 11, 0, 0)) - self.assertEquals(warnings[0]['message'], msg) + self.assertEqual(warnings[0]['message'], msg) def test_barePort(self): @@ -70,13 +70,13 @@ """ options = Options() options.parseOptions(['--pop3', '8110']) - self.assertEquals(len(options['pop3']), 1) + self.assertEqual(len(options['pop3']), 1) self.assertIsInstance( options['pop3'][0], endpoints.TCP4ServerEndpoint) warnings = self.flushWarnings([options.opt_pop3]) - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "Specifying plain ports and/or a certificate is deprecated since " "Twisted 11.0; use endpoint descriptions instead.") @@ -90,7 +90,7 @@ """ options = Options() options.parseOptions(['--' + service, 'tcp:1234']) - self.assertEquals(len(options[service]), 1) + self.assertEqual(len(options[service]), 1) self.assertIsInstance( options[service][0], endpoints.TCP4ServerEndpoint) @@ -118,11 +118,11 @@ options = Options() options.parseOptions([]) - self.assertEquals(len(options['pop3']), 1) + self.assertEqual(len(options['pop3']), 1) self.assertIsInstance( options['pop3'][0], endpoints.TCP4ServerEndpoint) - self.assertEquals(len(options['smtp']), 1) + self.assertEqual(len(options['smtp']), 1) self.assertIsInstance( options['smtp'][0], endpoints.TCP4ServerEndpoint) @@ -134,13 +134,13 @@ """ options = Options() options.parseOptions(['--no-pop3']) - self.assertEquals(options._getEndpoints(None, 'pop3'), []) + self.assertEqual(options._getEndpoints(None, 'pop3'), []) self.assertNotEquals(options._getEndpoints(None, 'smtp'), []) options = Options() options.parseOptions(['--no-smtp']) self.assertNotEquals(options._getEndpoints(None, 'pop3'), []) - self.assertEquals(options._getEndpoints(None, 'smtp'), []) + self.assertEqual(options._getEndpoints(None, 'smtp'), []) def test_allProtosDisabledError(self): @@ -162,16 +162,16 @@ options = Options() options.parseOptions(['--pop3s', '8995', '--certificate', cert.path]) - self.assertEquals(len(options['pop3']), 2) + self.assertEqual(len(options['pop3']), 2) self.assertIsInstance( options['pop3'][0], endpoints.SSL4ServerEndpoint) self.assertIsInstance( options['pop3'][1], endpoints.TCP4ServerEndpoint) warnings = self.flushWarnings([options.postOptions]) - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "Specifying plain ports and/or a certificate is deprecated since " "Twisted 11.0; use endpoint descriptions instead.") diff --git a/lib/twisted-trunk/twisted/mail/test/test_pop3.py b/lib/twisted-trunk/twisted/mail/test/test_pop3.py --- a/lib/twisted-trunk/twisted/mail/test/test_pop3.py +++ b/lib/twisted-trunk/twisted/mail/test/test_pop3.py @@ -48,16 +48,16 @@ input = iter(itertools.cycle(['012', '345', '6', '7', '8', '9'])) c = pop3._IteratorBuffer(output.extend, input, 6) i = iter(c) - self.assertEquals(output, []) # nothing is buffer + self.assertEqual(output, []) # nothing is buffer i.next() - self.assertEquals(output, []) # '012' is buffered + self.assertEqual(output, []) # '012' is buffered i.next() - self.assertEquals(output, []) # '012345' is buffered + self.assertEqual(output, []) # '012345' is buffered i.next() - self.assertEquals(output, ['012', '345', '6']) # nothing is buffered + self.assertEqual(output, ['012', '345', '6']) # nothing is buffered for n in range(5): i.next() - self.assertEquals(output, ['012', '345', '6', '7', '8', '9', '012', '345']) + self.assertEqual(output, ['012', '345', '6', '7', '8', '9', '012', '345']) def testFinishLineBuffering(self): @@ -70,7 +70,7 @@ c = pop3._IteratorBuffer(output.extend, input, 5) for i in c: pass - self.assertEquals(output, ['a', 'b', 'c']) + self.assertEqual(output, ['a', 'b', 'c']) def testSuccessResponseFormatter(self): @@ -78,7 +78,7 @@ Test that the thing that spits out POP3 'success responses' works right. """ - self.assertEquals( + self.assertEqual( pop3.successResponse('Great.'), '+OK Great.\r\n') @@ -88,10 +88,10 @@ Test that the function which formats stat lines does so appropriately. """ statLine = list(pop3.formatStatResponse([]))[-1] - self.assertEquals(statLine, '+OK 0 0\r\n') + self.assertEqual(statLine, '+OK 0 0\r\n') statLine = list(pop3.formatStatResponse([10, 31, 0, 10101]))[-1] - self.assertEquals(statLine, '+OK 4 10142\r\n') + self.assertEqual(statLine, '+OK 4 10142\r\n') def testListLineFormatter(self): @@ -100,12 +100,12 @@ command does so appropriately. """ listLines = list(pop3.formatListResponse([])) - self.assertEquals( + self.assertEqual( listLines, ['+OK 0\r\n', '.\r\n']) listLines = list(pop3.formatListResponse([1, 2, 3, 100])) - self.assertEquals( + self.assertEqual( listLines, ['+OK 4\r\n', '1 1\r\n', '2 2\r\n', '3 3\r\n', '4 100\r\n', '.\r\n']) @@ -118,17 +118,17 @@ """ UIDs = ['abc', 'def', 'ghi'] listLines = list(pop3.formatUIDListResponse([], UIDs.__getitem__)) - self.assertEquals( + self.assertEqual( listLines, ['+OK \r\n', '.\r\n']) listLines = list(pop3.formatUIDListResponse([123, 431, 591], UIDs.__getitem__)) - self.assertEquals( + self.assertEqual( listLines, ['+OK \r\n', '1 abc\r\n', '2 def\r\n', '3 ghi\r\n', '.\r\n']) listLines = list(pop3.formatUIDListResponse([0, None, 591], UIDs.__getitem__)) - self.assertEquals( + self.assertEqual( listLines, ['+OK \r\n', '1 abc\r\n', '3 ghi\r\n', '.\r\n']) @@ -247,7 +247,7 @@ server.service = self.factory def check(ignored): output = '\r\n'.join(client.response) + '\r\n' - self.assertEquals(output, self.expectedOutput) + self.assertEqual(output, self.expectedOutput) return loopback.loopbackTCP(server, client).addCallback(check) def testLoopback(self): @@ -255,7 +255,7 @@ protocol.service = self.factory clientProtocol = MyPOP3Downloader() def check(ignored): - self.failUnlessEqual(clientProtocol.message, self.message) + self.assertEqual(clientProtocol.message, self.message) protocol.connectionLost( failure.Failure(Exception("Test harness disconnect"))) d = loopback.loopbackAsync(protocol, clientProtocol) @@ -310,7 +310,7 @@ def _cbRunTest(self, ignored, client, dummy, expectedOutput): - self.failUnlessEqual('\r\n'.join(expectedOutput), + self.assertEqual('\r\n'.join(expectedOutput), '\r\n'.join(client.response)) dummy.connectionLost(failure.Failure(Exception("Test harness disconnect"))) return ignored @@ -382,7 +382,7 @@ def _cbTestAuthListing(self, ignored, client): self.failUnless(client.response[1].startswith('+OK')) - self.assertEquals(client.response[2:6], + self.assertEqual(client.response[2:6], ["AUTH1", "SECONDAUTH", "AUTHLAST", "."]) def testIllegalPASS(self): @@ -396,7 +396,7 @@ def _cbTestIllegalPASS(self, ignored, client, dummy): expected_output = '+OK \r\n-ERR USER required before PASS\r\n+OK \r\n' - self.failUnlessEqual(expected_output, '\r\n'.join(client.response) + '\r\n') + self.assertEqual(expected_output, '\r\n'.join(client.response) + '\r\n') dummy.connectionLost(failure.Failure(Exception("Test harness disconnect"))) def testEmptyPASS(self): @@ -410,7 +410,7 @@ def _cbTestEmptyPASS(self, ignored, client, dummy): expected_output = '+OK \r\n-ERR USER required before PASS\r\n+OK \r\n' - self.failUnlessEqual(expected_output, '\r\n'.join(client.response) + '\r\n') + self.assertEqual(expected_output, '\r\n'.join(client.response) + '\r\n') dummy.connectionLost(failure.Failure(Exception("Test harness disconnect"))) @@ -625,12 +625,12 @@ p.lineReceived("LIST 1") self._flush() - self.assertEquals(s.getvalue(), "+OK 1 44\r\n") + self.assertEqual(s.getvalue(), "+OK 1 44\r\n") s.truncate(0) p.lineReceived("LIST") self._flush() - self.assertEquals(s.getvalue(), "+OK 1\r\n1 44\r\n.\r\n") + self.assertEqual(s.getvalue(), "+OK 1\r\n1 44\r\n.\r\n") def testLISTWithBadArgument(self): @@ -642,19 +642,19 @@ s = self.pop3Transport p.lineReceived("LIST a") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Invalid message-number: 'a'\r\n") s.truncate(0) p.lineReceived("LIST 0") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Invalid message-number: 0\r\n") s.truncate(0) p.lineReceived("LIST 2") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Invalid message-number: 2\r\n") s.truncate(0) @@ -669,12 +669,12 @@ s = self.pop3Transport p.lineReceived("UIDL 1") - self.assertEquals(s.getvalue(), "+OK 0\r\n") + self.assertEqual(s.getvalue(), "+OK 0\r\n") s.truncate(0) p.lineReceived("UIDL") self._flush() - self.assertEquals(s.getvalue(), "+OK \r\n1 0\r\n.\r\n") + self.assertEqual(s.getvalue(), "+OK \r\n1 0\r\n.\r\n") def testUIDLWithBadArgument(self): @@ -686,19 +686,19 @@ s = self.pop3Transport p.lineReceived("UIDL a") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad message number argument\r\n") s.truncate(0) p.lineReceived("UIDL 0") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad message number argument\r\n") s.truncate(0) p.lineReceived("UIDL 2") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad message number argument\r\n") s.truncate(0) @@ -714,7 +714,7 @@ p.lineReceived("STAT") self._flush() - self.assertEquals(s.getvalue(), "+OK 1 44\r\n") + self.assertEqual(s.getvalue(), "+OK 1 44\r\n") def testRETR(self): @@ -726,7 +726,7 @@ p.lineReceived("RETR 1") self._flush() - self.assertEquals( + self.assertEqual( s.getvalue(), "+OK 44\r\n" "From: moshe\r\n" @@ -747,19 +747,19 @@ s = self.pop3Transport p.lineReceived("RETR a") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad message number argument\r\n") s.truncate(0) p.lineReceived("RETR 0") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad message number argument\r\n") s.truncate(0) p.lineReceived("RETR 2") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad message number argument\r\n") s.truncate(0) @@ -775,7 +775,7 @@ p.lineReceived("TOP 1 0") self._flush() - self.assertEquals( + self.assertEqual( s.getvalue(), "+OK Top of message follows\r\n" "From: moshe\r\n" @@ -796,31 +796,31 @@ p.mbox.messages.append(self.extraMessage) p.lineReceived("TOP 1 a") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad line count argument\r\n") s.truncate(0) p.lineReceived("TOP 1 -1") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad line count argument\r\n") s.truncate(0) p.lineReceived("TOP a 1") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad message number argument\r\n") s.truncate(0) p.lineReceived("TOP 0 1") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad message number argument\r\n") s.truncate(0) p.lineReceived("TOP 3 1") - self.assertEquals( + self.assertEqual( s.getvalue(), "-ERR Bad message number argument\r\n") s.truncate(0) @@ -836,7 +836,7 @@ p.mbox.messages.append(self.extraMessage) p.lineReceived('LAST') - self.assertEquals( + self.assertEqual( s.getvalue(), "+OK 0\r\n") s.truncate(0) @@ -854,7 +854,7 @@ self._flush() s.truncate(0) p.lineReceived('LAST') - self.assertEquals( + self.assertEqual( s.getvalue(), '+OK 2\r\n') s.truncate(0) @@ -872,7 +872,7 @@ self._flush() s.truncate(0) p.lineReceived('LAST') - self.assertEquals( + self.assertEqual( s.getvalue(), '+OK 2\r\n') @@ -892,7 +892,7 @@ self._flush() s.truncate(0) p.lineReceived('LAST') - self.assertEquals( + self.assertEqual( s.getvalue(), '+OK 2\r\n') @@ -910,7 +910,7 @@ p.lineReceived('RSET') s.truncate(0) p.lineReceived('LAST') - self.assertEquals( + self.assertEqual( s.getvalue(), '+OK 0\r\n') diff --git a/lib/twisted-trunk/twisted/mail/test/test_pop3client.py b/lib/twisted-trunk/twisted/mail/test/test_pop3client.py --- a/lib/twisted-trunk/twisted/mail/test/test_pop3client.py +++ b/lib/twisted-trunk/twisted/mail/test/test_pop3client.py @@ -57,48 +57,48 @@ p.dataReceived('-ERR Offline for maintenance\r\n') return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Offline for maintenance")) + lambda exc: self.assertEqual(exc.args[0], "Offline for maintenance")) def testOkUser(self): p, t = setUp() d = p.user("username") - self.assertEquals(t.value(), "USER username\r\n") + self.assertEqual(t.value(), "USER username\r\n") p.dataReceived("+OK send password\r\n") return d.addCallback(self.assertEqual, "send password") def testBadUser(self): p, t = setUp() d = p.user("username") - self.assertEquals(t.value(), "USER username\r\n") + self.assertEqual(t.value(), "USER username\r\n") p.dataReceived("-ERR account suspended\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "account suspended")) + lambda exc: self.assertEqual(exc.args[0], "account suspended")) def testOkPass(self): p, t = setUp() d = p.password("password") - self.assertEquals(t.value(), "PASS password\r\n") + self.assertEqual(t.value(), "PASS password\r\n") p.dataReceived("+OK you're in!\r\n") return d.addCallback(self.assertEqual, "you're in!") def testBadPass(self): p, t = setUp() d = p.password("password") - self.assertEquals(t.value(), "PASS password\r\n") + self.assertEqual(t.value(), "PASS password\r\n") p.dataReceived("-ERR go away\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "go away")) + lambda exc: self.assertEqual(exc.args[0], "go away")) def testOkLogin(self): p, t = setUp() p.allowInsecureLogin = True d = p.login("username", "password") - self.assertEquals(t.value(), "USER username\r\n") + self.assertEqual(t.value(), "USER username\r\n") p.dataReceived("+OK go ahead\r\n") - self.assertEquals(t.value(), "USER username\r\nPASS password\r\n") + self.assertEqual(t.value(), "USER username\r\nPASS password\r\n") p.dataReceived("+OK password accepted\r\n") return d.addCallback(self.assertEqual, "password accepted") @@ -106,39 +106,39 @@ p, t = setUp() p.allowInsecureLogin = True d = p.login("username", "password") - self.assertEquals(t.value(), "USER username\r\n") + self.assertEqual(t.value(), "USER username\r\n") p.dataReceived("+OK waiting on you\r\n") - self.assertEquals(t.value(), "USER username\r\nPASS password\r\n") + self.assertEqual(t.value(), "USER username\r\nPASS password\r\n") p.dataReceived("-ERR bogus login\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "bogus login")) + lambda exc: self.assertEqual(exc.args[0], "bogus login")) def testBadUsernameLogin(self): p, t = setUp() p.allowInsecureLogin = True d = p.login("username", "password") - self.assertEquals(t.value(), "USER username\r\n") + self.assertEqual(t.value(), "USER username\r\n") p.dataReceived("-ERR bogus login\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "bogus login")) + lambda exc: self.assertEqual(exc.args[0], "bogus login")) def testServerGreeting(self): p, t = setUp(greet=False) p.dataReceived("+OK lalala this has no challenge\r\n") - self.assertEquals(p.serverChallenge, None) + self.assertEqual(p.serverChallenge, None) def testServerGreetingWithChallenge(self): p, t = setUp(greet=False) p.dataReceived("+OK \r\n") - self.assertEquals(p.serverChallenge, "") + self.assertEqual(p.serverChallenge, "") def testAPOP(self): p, t = setUp(greet=False) p.dataReceived("+OK \r\n") d = p.login("username", "password") - self.assertEquals(t.value(), "APOP username f34f1e464d0d7927607753129cabe39a\r\n") + self.assertEqual(t.value(), "APOP username f34f1e464d0d7927607753129cabe39a\r\n") p.dataReceived("+OK Welcome!\r\n") return d.addCallback(self.assertEqual, "Welcome!") @@ -161,10 +161,10 @@ directlyProvides(t, interfaces.ISSLTransport) p.dataReceived("+OK Howdy\r\n") d = p.login("username", "password") - self.assertEquals(t.value(), "USER username\r\n") + self.assertEqual(t.value(), "USER username\r\n") t.clear() p.dataReceived("+OK\r\n") - self.assertEquals(t.value(), "PASS password\r\n") + self.assertEqual(t.value(), "PASS password\r\n") p.dataReceived("+OK\r\n") return d @@ -188,7 +188,7 @@ def testListSize(self): p, t = setUp() d = p.listSize() - self.assertEquals(t.value(), "LIST\r\n") + self.assertEqual(t.value(), "LIST\r\n") p.dataReceived("+OK Here it comes\r\n") p.dataReceived("1 3\r\n2 2\r\n3 1\r\n.\r\n") return d.addCallback(self.assertEqual, [3, 2, 1]) @@ -198,28 +198,28 @@ c = ListConsumer() f = c.consume d = p.listSize(f) - self.assertEquals(t.value(), "LIST\r\n") + self.assertEqual(t.value(), "LIST\r\n") p.dataReceived("+OK Here it comes\r\n") p.dataReceived("1 3\r\n2 2\r\n3 1\r\n") - self.assertEquals(c.data, {0: [3], 1: [2], 2: [1]}) + self.assertEqual(c.data, {0: [3], 1: [2], 2: [1]}) p.dataReceived("5 3\r\n6 2\r\n7 1\r\n") - self.assertEquals(c.data, {0: [3], 1: [2], 2: [1], 4: [3], 5: [2], 6: [1]}) + self.assertEqual(c.data, {0: [3], 1: [2], 2: [1], 4: [3], 5: [2], 6: [1]}) p.dataReceived(".\r\n") return d.addCallback(self.assertIdentical, f) def testFailedListSize(self): p, t = setUp() d = p.listSize() - self.assertEquals(t.value(), "LIST\r\n") + self.assertEqual(t.value(), "LIST\r\n") p.dataReceived("-ERR Fatal doom server exploded\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Fatal doom server exploded")) + lambda exc: self.assertEqual(exc.args[0], "Fatal doom server exploded")) def testListUID(self): p, t = setUp() d = p.listUID() - self.assertEquals(t.value(), "UIDL\r\n") + self.assertEqual(t.value(), "UIDL\r\n") p.dataReceived("+OK Here it comes\r\n") p.dataReceived("1 abc\r\n2 def\r\n3 ghi\r\n.\r\n") return d.addCallback(self.assertEqual, ["abc", "def", "ghi"]) @@ -229,27 +229,27 @@ c = ListConsumer() f = c.consume d = p.listUID(f) - self.assertEquals(t.value(), "UIDL\r\n") + self.assertEqual(t.value(), "UIDL\r\n") p.dataReceived("+OK Here it comes\r\n") p.dataReceived("1 xyz\r\n2 abc\r\n5 mno\r\n") - self.assertEquals(c.data, {0: ["xyz"], 1: ["abc"], 4: ["mno"]}) + self.assertEqual(c.data, {0: ["xyz"], 1: ["abc"], 4: ["mno"]}) p.dataReceived(".\r\n") return d.addCallback(self.assertIdentical, f) def testFailedListUID(self): p, t = setUp() d = p.listUID() - self.assertEquals(t.value(), "UIDL\r\n") + self.assertEqual(t.value(), "UIDL\r\n") p.dataReceived("-ERR Fatal doom server exploded\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Fatal doom server exploded")) + lambda exc: self.assertEqual(exc.args[0], "Fatal doom server exploded")) class POP3ClientMessageTestCase(unittest.TestCase): def testRetrieve(self): p, t = setUp() d = p.retrieve(7) - self.assertEquals(t.value(), "RETR 8\r\n") + self.assertEqual(t.value(), "RETR 8\r\n") p.dataReceived("+OK Message incoming\r\n") p.dataReceived("La la la here is message text\r\n") p.dataReceived("..Further message text tra la la\r\n") @@ -264,7 +264,7 @@ c = MessageConsumer() f = c.consume d = p.retrieve(7, f) - self.assertEquals(t.value(), "RETR 8\r\n") + self.assertEqual(t.value(), "RETR 8\r\n") p.dataReceived("+OK Message incoming\r\n") p.dataReceived("La la la here is message text\r\n") p.dataReceived("..Further message text\r\n.\r\n") @@ -272,13 +272,13 @@ def _cbTestRetrieveWithConsumer(self, result, f, c): self.assertIdentical(result, f) - self.assertEquals(c.data, ["La la la here is message text", + self.assertEqual(c.data, ["La la la here is message text", ".Further message text"]) def testPartialRetrieve(self): p, t = setUp() d = p.retrieve(7, lines=2) - self.assertEquals(t.value(), "TOP 8 2\r\n") + self.assertEqual(t.value(), "TOP 8 2\r\n") p.dataReceived("+OK 2 lines on the way\r\n") p.dataReceived("Line the first! Woop\r\n") p.dataReceived("Line the last! Bye\r\n") @@ -293,7 +293,7 @@ c = MessageConsumer() f = c.consume d = p.retrieve(7, f, lines=2) - self.assertEquals(t.value(), "TOP 8 2\r\n") + self.assertEqual(t.value(), "TOP 8 2\r\n") p.dataReceived("+OK 2 lines on the way\r\n") p.dataReceived("Line the first! Woop\r\n") p.dataReceived("Line the last! Bye\r\n") @@ -302,17 +302,17 @@ def _cbTestPartialRetrieveWithConsumer(self, result, f, c): self.assertIdentical(result, f) - self.assertEquals(c.data, ["Line the first! Woop", + self.assertEqual(c.data, ["Line the first! Woop", "Line the last! Bye"]) def testFailedRetrieve(self): p, t = setUp() d = p.retrieve(0) - self.assertEquals(t.value(), "RETR 1\r\n") + self.assertEqual(t.value(), "RETR 1\r\n") p.dataReceived("-ERR Fatal doom server exploded\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Fatal doom server exploded")) + lambda exc: self.assertEqual(exc.args[0], "Fatal doom server exploded")) def test_concurrentRetrieves(self): @@ -323,19 +323,19 @@ p, t = setUp() messages = [ p.retrieve(i).addCallback( - self.assertEquals, + self.assertEqual, ["First line of %d." % (i + 1,), "Second line of %d." % (i + 1,)]) for i in range(3)] for i in range(1, 4): - self.assertEquals(t.value(), "RETR %d\r\n" % (i,)) + self.assertEqual(t.value(), "RETR %d\r\n" % (i,)) t.clear() p.dataReceived("+OK 2 lines on the way\r\n") p.dataReceived("First line of %d.\r\n" % (i,)) p.dataReceived("Second line of %d.\r\n" % (i,)) - self.assertEquals(t.value(), "") + self.assertEqual(t.value(), "") p.dataReceived(".\r\n") return defer.DeferredList(messages, fireOnOneErrback=True) @@ -346,7 +346,7 @@ def testCapability(self): p, t = setUp() d = p.capabilities(useCache=0) - self.assertEquals(t.value(), "CAPA\r\n") + self.assertEqual(t.value(), "CAPA\r\n") p.dataReceived("+OK Capabilities on the way\r\n") p.dataReceived("X\r\nY\r\nZ\r\nA 1 2 3\r\nB 1 2\r\nC 1\r\n.\r\n") return d.addCallback( @@ -359,73 +359,73 @@ def testCapabilityError(self): p, t = setUp() d = p.capabilities(useCache=0) - self.assertEquals(t.value(), "CAPA\r\n") + self.assertEqual(t.value(), "CAPA\r\n") p.dataReceived("-ERR This server is lame!\r\n") - return d.addCallback(self.assertEquals, {}) + return d.addCallback(self.assertEqual, {}) def testStat(self): p, t = setUp() d = p.stat() - self.assertEquals(t.value(), "STAT\r\n") + self.assertEqual(t.value(), "STAT\r\n") p.dataReceived("+OK 1 1212\r\n") return d.addCallback(self.assertEqual, (1, 1212)) def testStatError(self): p, t = setUp() d = p.stat() - self.assertEquals(t.value(), "STAT\r\n") + self.assertEqual(t.value(), "STAT\r\n") p.dataReceived("-ERR This server is lame!\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "This server is lame!")) + lambda exc: self.assertEqual(exc.args[0], "This server is lame!")) def testNoop(self): p, t = setUp() d = p.noop() - self.assertEquals(t.value(), "NOOP\r\n") + self.assertEqual(t.value(), "NOOP\r\n") p.dataReceived("+OK No-op to you too!\r\n") return d.addCallback(self.assertEqual, "No-op to you too!") def testNoopError(self): p, t = setUp() d = p.noop() - self.assertEquals(t.value(), "NOOP\r\n") + self.assertEqual(t.value(), "NOOP\r\n") p.dataReceived("-ERR This server is lame!\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "This server is lame!")) + lambda exc: self.assertEqual(exc.args[0], "This server is lame!")) def testRset(self): p, t = setUp() d = p.reset() - self.assertEquals(t.value(), "RSET\r\n") + self.assertEqual(t.value(), "RSET\r\n") p.dataReceived("+OK Reset state\r\n") return d.addCallback(self.assertEqual, "Reset state") def testRsetError(self): p, t = setUp() d = p.reset() - self.assertEquals(t.value(), "RSET\r\n") + self.assertEqual(t.value(), "RSET\r\n") p.dataReceived("-ERR This server is lame!\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "This server is lame!")) + lambda exc: self.assertEqual(exc.args[0], "This server is lame!")) def testDelete(self): p, t = setUp() d = p.delete(3) - self.assertEquals(t.value(), "DELE 4\r\n") + self.assertEqual(t.value(), "DELE 4\r\n") p.dataReceived("+OK Hasta la vista\r\n") return d.addCallback(self.assertEqual, "Hasta la vista") def testDeleteError(self): p, t = setUp() d = p.delete(3) - self.assertEquals(t.value(), "DELE 4\r\n") + self.assertEqual(t.value(), "DELE 4\r\n") p.dataReceived("-ERR Winner is not you.\r\n") return self.assertFailure( d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Winner is not you.")) + lambda exc: self.assertEqual(exc.args[0], "Winner is not you.")) class SimpleClient(POP3Client): @@ -480,7 +480,15 @@ class POP3TLSTestCase(unittest.TestCase): - def testStartTLS(self): + """ + Tests for POP3Client's support for TLS connections. + """ + + def test_startTLS(self): + """ + POP3Client.startTLS starts a TLS session over its existing TCP + connection. + """ sf = TLSServerFactory() sf.protocol.output = [ ['+OK'], # Server greeting @@ -491,10 +499,16 @@ ] sf.protocol.context = ServerTLSContext() port = reactor.listenTCP(0, sf, interface='127.0.0.1') + self.addCleanup(port.stopListening) H = port.getHost().host P = port.getHost().port + connLostDeferred = defer.Deferred() cp = SimpleClient(defer.Deferred(), ClientTLSContext()) + def connectionLost(reason): + SimpleClient.connectionLost(cp, reason) + connLostDeferred.callback(None) + cp.connectionLost = connectionLost cf = protocol.ClientFactory() cf.protocol = lambda: cp @@ -510,19 +524,14 @@ def cbDisconnected(ign): log.msg("Disconnected; asserting correct input received") - self.assertEquals( + self.assertEqual( sf.input, ['CAPA', 'STLS', 'CAPA', 'QUIT']) def cleanup(result): log.msg("Asserted correct input; disconnecting client and shutting down server") conn.disconnect() - - def cbShutdown(ignored): - log.msg("Shut down server") - return result - - return defer.maybeDeferred(port.stopListening).addCallback(cbShutdown) + return connLostDeferred cp.deferred.addCallback(cbConnected) cp.deferred.addCallback(cbStartedTLS) diff --git a/lib/twisted-trunk/twisted/mail/test/test_smtp.py b/lib/twisted-trunk/twisted/mail/test/test_smtp.py --- a/lib/twisted-trunk/twisted/mail/test/test_smtp.py +++ b/lib/twisted-trunk/twisted/mail/test/test_smtp.py @@ -308,7 +308,7 @@ server = FakeSMTPServer() d = self.loopback(server, client) d.addCallback(lambda x : - self.assertEquals(server.buffer, self.expected_output)) + self.assertEqual(server.buffer, self.expected_output)) return d @@ -514,7 +514,7 @@ for recip in msgdata[2]: expected = list(msgdata[:]) expected[2] = [recip] - self.assertEquals( + self.assertEqual( a.message[(recip,)], tuple(expected) ) @@ -602,7 +602,7 @@ client.registerAuthenticator(cAuth) d = self.loopback(server, client) - d.addCallback(lambda x : self.assertEquals(server.authenticated, 1)) + d.addCallback(lambda x : self.assertEqual(server.authenticated, 1)) return d @@ -675,11 +675,11 @@ ] for (c, e) in cases: - self.assertEquals(smtp.quoteaddr(c), e) + self.assertEqual(smtp.quoteaddr(c), e) def testUser(self): u = smtp.User('user at host', 'helo.host.name', None, None) - self.assertEquals(str(u), 'user at host') + self.assertEqual(str(u), 'user at host') def testXtextEncoding(self): cases = [ @@ -691,10 +691,10 @@ for (case, expected) in cases: self.assertEqual(smtp.xtext_encode(case), (expected, len(case))) - self.assertEquals(case.encode('xtext'), expected) + self.assertEqual(case.encode('xtext'), expected) self.assertEqual( smtp.xtext_decode(expected), (case, len(expected))) - self.assertEquals(expected.decode('xtext'), case) + self.assertEqual(expected.decode('xtext'), case) def test_encodeWithErrors(self): @@ -742,8 +742,8 @@ server = DummyESMTP(contextFactory=serverCTX) def check(ignored): - self.assertEquals(client.tls, True) - self.assertEquals(server.startedTLS, True) + self.assertEqual(client.tls, True) + self.assertEqual(server.startedTLS, True) return self.loopback(server, client).addCallback(check) @@ -768,9 +768,9 @@ proto.setTimeout(None) out = transport.value().splitlines() - self.assertEquals(len(out), 2) + self.assertEqual(len(out), 2) self.failUnless(out[0].startswith('220')) - self.assertEquals(out[1], "500 Error: bad syntax") + self.assertEqual(out[1], "500 Error: bad syntax") @@ -791,7 +791,7 @@ client.makeConnection(t) t.protocol = client def check(ign): - self.assertEquals(clock.seconds(), 0.5) + self.assertEqual(clock.seconds(), 0.5) d = self.assertFailure(onDone, smtp.SMTPTimeoutError ).addCallback(check) # The first call should not trigger the timeout @@ -978,7 +978,7 @@ Verify that the message was successfully delivered and flush the error which caused the first attempt to fail. """ - self.assertEquals( + self.assertEqual( domain.messages, {recipient: ["\n%s\n" % (message,)]}) # Flush the RuntimeError that BrokenMessage caused to be logged. @@ -1449,11 +1449,11 @@ d, credentials, mind, interfaces = loginArgs.pop() d.errback(RuntimeError("Something wrong with the server")) - self.assertEquals( + self.assertEqual( '451 Requested action aborted: local error in processing\r\n', self.transport.value()) - self.assertEquals(len(self.flushLoggedErrors(RuntimeError)), 1) + self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1) @@ -1467,7 +1467,7 @@ the response code and response string. """ err = smtp.SMTPClientError(123, "some text") - self.assertEquals(str(err), "123 some text") + self.assertEqual(str(err), "123 some text") def test_strWithNegativeCode(self): @@ -1476,7 +1476,7 @@ is excluded from the string representation. """ err = smtp.SMTPClientError(-1, "foo bar") - self.assertEquals(str(err), "foo bar") + self.assertEqual(str(err), "foo bar") def test_strWithLog(self): @@ -1488,7 +1488,7 @@ log.append("testlog") log.append("secondline") err = smtp.SMTPClientError(100, "test error", log=log.str()) - self.assertEquals( + self.assertEqual( str(err), "100 test error\n" "testlog\n" @@ -1507,7 +1507,7 @@ SMTP response codes to the log passed to the factory's errback. """ onDone = self.assertFailure(defer.Deferred(), smtp.SMTPDeliveryError) - onDone.addCallback(lambda e: self.assertEquals( + onDone.addCallback(lambda e: self.assertEqual( e.log, "bob at example.com: 199 Error in sending.\n")) clientFactory = smtp.SMTPSenderFactory( diff --git a/lib/twisted-trunk/twisted/names/dns.py b/lib/twisted-trunk/twisted/names/dns.py --- a/lib/twisted-trunk/twisted/names/dns.py +++ b/lib/twisted-trunk/twisted/names/dns.py @@ -332,7 +332,11 @@ @raise EOFError: Raised when there are not enough bytes available from C{strio}. + + @raise ValueError: Raised when the name cannot be decoded (for example, + because it contains a loop). """ + visited = set() self.name = '' off = 0 while 1: @@ -344,6 +348,9 @@ if (l >> 6) == 3: new_off = ((l&63) << 8 | ord(readPrecisely(strio, 1))) + if new_off in visited: + raise ValueError("Compression loop in encoded name") + visited.add(new_off) if off == 0: off = strio.tell() strio.seek(new_off) diff --git a/lib/twisted-trunk/twisted/names/hosts.py b/lib/twisted-trunk/twisted/names/hosts.py --- a/lib/twisted-trunk/twisted/names/hosts.py +++ b/lib/twisted-trunk/twisted/names/hosts.py @@ -1,3 +1,4 @@ +# -*- test-case-name: twisted.names.test.test_hosts -*- # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. @@ -8,10 +9,46 @@ from twisted.names import dns from twisted.persisted import styles from twisted.python import failure +from twisted.python.filepath import FilePath from twisted.internet import defer +from twisted.internet.abstract import isIPAddress from twisted.names import common +def searchFileForAll(hostsFile, name): + """ + Search the given file, which is in hosts(5) standard format, for an address + entry with a given name. + + @param hostsFile: The name of the hosts(5)-format file to search. + @type hostsFile: L{FilePath} + + @param name: The name to search for. + @type name: C{str} + + @return: C{None} if the name is not found in the file, otherwise a + C{str} giving the address in the file associated with the name. + """ + results = [] + try: + lines = hostsFile.getContent().splitlines() + except: + return results + + name = name.lower() + for line in lines: + idx = line.find('#') + if idx != -1: + line = line[:idx] + if not line: + continue + parts = line.split() + + if name.lower() in [s.lower() for s in parts[1:]]: + results.append(parts[0]) + return results + + def searchFileFor(file, name): """ @@ -26,30 +63,17 @@ @return: C{None} if the name is not found in the file, otherwise a C{str} giving the address in the file associated with the name. """ - try: - fp = open(file) - except: - return None - try: - lines = fp.readlines() - finally: - fp.close() - for line in lines: - idx = line.find('#') - if idx != -1: - line = line[:idx] - if not line: - continue - parts = line.split() - if name.lower() in [s.lower() for s in parts[1:]]: - return parts[0] + addresses = searchFileForAll(FilePath(file), name) + if addresses: + return addresses[0] return None class Resolver(common.ResolverBase, styles.Versioned): - """A resolver that services hosts(5) format files.""" - #TODO: IPv6 support + """ + A resolver that services hosts(5) format files. + """ persistenceVersion = 1 @@ -66,14 +90,68 @@ self.ttl = ttl - def lookupAddress(self, name, timeout = None): - res = searchFileFor(self.file, name) - if res: - return defer.succeed([ - (dns.RRHeader(name, dns.A, dns.IN, self.ttl, dns.Record_A(res, self.ttl)),), (), () - ]) + def _aRecords(self, name): + """ + Return a tuple of L{dns.RRHeader} instances for all of the IPv4 + addresses in the hosts file. + """ + return tuple([ + dns.RRHeader(name, dns.A, dns.IN, self.ttl, + dns.Record_A(addr, self.ttl)) + for addr + in searchFileForAll(FilePath(self.file), name) + if isIPAddress(addr)]) + + + def _aaaaRecords(self, name): + """ + Return a tuple of L{dns.RRHeader} instances for all of the IPv6 + addresses in the hosts file. + """ + return tuple([ + dns.RRHeader(name, dns.AAAA, dns.IN, self.ttl, + dns.Record_AAAA(addr, self.ttl)) + for addr + in searchFileForAll(FilePath(self.file), name) + if not isIPAddress(addr)]) + + + def _respond(self, name, records): + """ + Generate a response for the given name containing the given result + records, or a failure if there are no result records. + + @param name: The DNS name the response is for. + @type name: C{str} + + @param records: A tuple of L{dns.RRHeader} instances giving the results + that will go into the response. + + @return: A L{Deferred} which will fire with a three-tuple of result + records, authority records, and additional records, or which will + fail with L{dns.DomainError} if there are no result records. + """ + if records: + return defer.succeed((records, (), ())) return defer.fail(failure.Failure(dns.DomainError(name))) - # When we put IPv6 support in, this'll need a real impl + def lookupAddress(self, name, timeout=None): + """ + Read any IPv4 addresses from C{self.file} and return them as L{Record_A} + instances. + """ + return self._respond(name, self._aRecords(name)) + + + def lookupIPV6Address(self, name, timeout=None): + """ + Read any IPv4 addresses from C{self.file} and return them as L{Record_A} + instances. + """ + return self._respond(name, self._aaaaRecords(name)) + + # Someday this should include IPv6 addresses too, but that will cause + # problems if users of the API (mainly via getHostByName) aren't updated to + # know about IPv6 first. lookupAllRecords = lookupAddress diff --git a/lib/twisted-trunk/twisted/names/test/test_cache.py b/lib/twisted-trunk/twisted/names/test/test_cache.py --- a/lib/twisted-trunk/twisted/names/test/test_cache.py +++ b/lib/twisted-trunk/twisted/names/test/test_cache.py @@ -11,4 +11,4 @@ def testLookup(self): c = cache.CacheResolver({ dns.Query(name='example.com', type=dns.MX, cls=dns.IN): (time.time(), ([], [], []))}) - return c.lookupMailExchange('example.com').addCallback(self.assertEquals, ([], [], [])) + return c.lookupMailExchange('example.com').addCallback(self.assertEqual, ([], [], [])) diff --git a/lib/twisted-trunk/twisted/names/test/test_client.py b/lib/twisted-trunk/twisted/names/test/test_client.py --- a/lib/twisted-trunk/twisted/names/test/test_client.py +++ b/lib/twisted-trunk/twisted/names/test/test_client.py @@ -438,14 +438,14 @@ Verify that the result is the same query type as what is expected. """ result = results[0] - self.assertEquals(str(result.name), self.hostname) - self.assertEquals(result.type, qtype) + self.assertEqual(str(result.name), self.hostname) + self.assertEqual(result.type, qtype) def checkGetHostByName(self, result): """ Test that the getHostByName query returns the 127.0.0.1 address. """ - self.assertEquals(result, '127.0.0.1') + self.assertEqual(result, '127.0.0.1') def test_getHostByName(self): """ @@ -654,10 +654,10 @@ """ client.ThreadedResolver() warnings = self.flushWarnings(offendingFunctions=[self.test_deprecated]) - self.assertEquals( + self.assertEqual( warnings[0]['message'], "twisted.names.client.ThreadedResolver is deprecated since " "Twisted 9.0, use twisted.internet.base.ThreadedResolver " "instead.") - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 1) diff --git a/lib/twisted-trunk/twisted/names/test/test_dns.py b/lib/twisted-trunk/twisted/names/test/test_dns.py --- a/lib/twisted-trunk/twisted/names/test/test_dns.py +++ b/lib/twisted-trunk/twisted/names/test/test_dns.py @@ -22,6 +22,103 @@ from twisted.test import proto_helpers +class NameTests(unittest.TestCase): + """ + Tests for L{Name}, the representation of a single domain name with support + for encoding into and decoding from DNS message format. + """ + def test_decode(self): + """ + L{Name.decode} populates the L{Name} instance with name information read + from the file-like object passed to it. + """ + n = dns.Name() + n.decode(StringIO("\x07example\x03com\x00")) + self.assertEqual(n.name, "example.com") + + + def test_encode(self): + """ + L{Name.encode} encodes its name information and writes it to the + file-like object passed to it. + """ + name = dns.Name("foo.example.com") + stream = StringIO() + name.encode(stream) + self.assertEqual(stream.getvalue(), "\x03foo\x07example\x03com\x00") + + + def test_encodeWithCompression(self): + """ + If a compression dictionary is passed to it, L{Name.encode} uses offset + information from it to encode its name with references to existing + labels in the stream instead of including another copy of them in the + output. It also updates the compression dictionary with the location of + the name it writes to the stream. + """ + name = dns.Name("foo.example.com") + compression = {"example.com": 0x17} + + # Some bytes already encoded into the stream for this message + previous = "some prefix to change .tell()" + stream = StringIO() + stream.write(previous) + + # The position at which the encoded form of this new name will appear in + # the stream. + expected = len(previous) + dns.Message.headerSize + name.encode(stream, compression) + self.assertEqual( + "\x03foo\xc0\x17", + stream.getvalue()[len(previous):]) + self.assertEqual( + {"example.com": 0x17, "foo.example.com": expected}, + compression) + + + def test_decodeWithCompression(self): + """ + If the leading byte of an encoded label (in bytes read from a stream + passed to L{Name.decode}) has its two high bits set, the next byte is + treated as a pointer to another label in the stream and that label is + included in the name being decoded. + """ + # Slightly modified version of the example from RFC 1035, section 4.1.4. + stream = StringIO( + "x" * 20 + + "\x01f\x03isi\x04arpa\x00" + "\x03foo\xc0\x14" + "\x03bar\xc0\x20") + stream.seek(20) + name = dns.Name() + name.decode(stream) + # Verify we found the first name in the stream and that the stream + # position is left at the first byte after the decoded name. + self.assertEqual("f.isi.arpa", name.name) + self.assertEqual(32, stream.tell()) + + # Get the second name from the stream and make the same assertions. + name.decode(stream) + self.assertEqual(name.name, "foo.f.isi.arpa") + self.assertEqual(38, stream.tell()) + + # Get the third and final name + name.decode(stream) + self.assertEqual(name.name, "bar.foo.f.isi.arpa") + self.assertEqual(44, stream.tell()) + + + def test_rejectCompressionLoop(self): + """ + L{Name.decode} raises L{ValueError} if the stream passed to it includes + a compression pointer which forms a loop, causing the name to be + undecodable. + """ + name = dns.Name() + stream = StringIO("\xc0\x00") + self.assertRaises(ValueError, name.decode, stream) + + class RoundtripDNSTestCase(unittest.TestCase): """Encoding and then decoding various objects.""" @@ -38,7 +135,7 @@ f.seek(0, 0) result = dns.Name() result.decode(f) - self.assertEquals(result.name, n) + self.assertEqual(result.name, n) def testQuery(self): for n in self.names: @@ -52,9 +149,9 @@ f.seek(0, 0) result = dns.Query() result.decode(f) - self.assertEquals(result.name.name, n) - self.assertEquals(result.type, dnstype) - self.assertEquals(result.cls, dnscls) + self.assertEqual(result.name.name, n) + self.assertEqual(result.type, dnstype) + self.assertEqual(result.cls, dnscls) def testRR(self): # encode the RR @@ -65,10 +162,10 @@ f.seek(0, 0) result = dns.RRHeader() result.decode(f) - self.assertEquals(str(result.name), "test.org") - self.assertEquals(result.type, 3) - self.assertEquals(result.cls, 4) - self.assertEquals(result.ttl, 17) + self.assertEqual(str(result.name), "test.org") + self.assertEqual(result.type, 3) + self.assertEqual(result.cls, 4) + self.assertEqual(result.ttl, 17) def testResources(self): @@ -85,7 +182,7 @@ f.seek(0, 0) result = dns.SimpleRecord() result.decode(f) - self.assertEquals(str(result.name), s) + self.assertEqual(str(result.name), s) def test_hashable(self): """ @@ -104,7 +201,7 @@ k1, k2 = k(), k() hk1 = hash(k1) hk2 = hash(k2) - self.assertEquals(hk1, hk2, "%s != %s (for %s)" % (hk1,hk2,k)) + self.assertEqual(hk1, hk2, "%s != %s (for %s)" % (hk1,hk2,k)) def test_Charstr(self): @@ -120,7 +217,7 @@ f.seek(0, 0) result = dns.Charstr() result.decode(f) - self.assertEquals(result.string, n) + self.assertEqual(result.string, n) def test_NAPTR(self): @@ -140,13 +237,13 @@ e.seek(0,0) rout = dns.Record_NAPTR() rout.decode(e) - self.assertEquals(rin.order, rout.order) - self.assertEquals(rin.preference, rout.preference) - self.assertEquals(rin.flags, rout.flags) - self.assertEquals(rin.service, rout.service) - self.assertEquals(rin.regexp, rout.regexp) - self.assertEquals(rin.replacement.name, rout.replacement.name) - self.assertEquals(rin.ttl, rout.ttl) + self.assertEqual(rin.order, rout.order) + self.assertEqual(rin.preference, rout.preference) + self.assertEqual(rin.flags, rout.flags) + self.assertEqual(rin.service, rout.service) + self.assertEqual(rin.regexp, rout.regexp) + self.assertEqual(rin.replacement.name, rout.replacement.name) + self.assertEqual(rin.ttl, rout.ttl) @@ -179,15 +276,15 @@ '\x00\x00' # number of authorities '\x00\x00' # number of additionals ) - self.assertEquals(msg.id, 256) + self.assertEqual(msg.id, 256) self.failIf(msg.answer, "Message was not supposed to be an answer.") - self.assertEquals(msg.opCode, dns.OP_QUERY) + self.assertEqual(msg.opCode, dns.OP_QUERY) self.failIf(msg.auth, "Message was not supposed to be authoritative.") self.failIf(msg.trunc, "Message was not supposed to be truncated.") - self.assertEquals(msg.queries, []) - self.assertEquals(msg.answers, []) - self.assertEquals(msg.authority, []) - self.assertEquals(msg.additional, []) + self.assertEqual(msg.queries, []) + self.assertEqual(msg.answers, []) + self.assertEqual(msg.authority, []) + self.assertEqual(msg.additional, []) def testNULL(self): @@ -203,7 +300,7 @@ msg2.decode(s) self.failUnless(isinstance(msg2.answers[0].payload, dns.Record_NULL)) - self.assertEquals(msg2.answers[0].payload.payload, bytes) + self.assertEqual(msg2.answers[0].payload.payload, bytes) def test_lookupRecordTypeDefault(self): @@ -266,7 +363,7 @@ """ self.proto.datagramReceived('', address.IPv4Address('UDP', '127.0.0.1', 12345)) - self.assertEquals(self.controller.messages, []) + self.assertEqual(self.controller.messages, []) def test_simpleQuery(self): @@ -274,13 +371,13 @@ Test content received after a query. """ d = self.proto.query(('127.0.0.1', 21345), [dns.Query('foo')]) - self.assertEquals(len(self.proto.liveMessages.keys()), 1) + self.assertEqual(len(self.proto.liveMessages.keys()), 1) m = dns.Message() m.id = self.proto.liveMessages.items()[0][0] m.answers = [dns.RRHeader(payload=dns.Record_A(address='1.2.3.4'))] called = False def cb(result): - self.assertEquals(result.answers[0].payload.dottedQuad(), '1.2.3.4') + self.assertEqual(result.answers[0].payload.dottedQuad(), '1.2.3.4') d.addCallback(cb) self.proto.datagramReceived(m.toStr(), ('127.0.0.1', 21345)) return d @@ -291,10 +388,10 @@ Test that query timeouts after some seconds. """ d = self.proto.query(('127.0.0.1', 21345), [dns.Query('foo')]) - self.assertEquals(len(self.proto.liveMessages), 1) + self.assertEqual(len(self.proto.liveMessages), 1) self.clock.advance(10) self.assertFailure(d, dns.DNSQueryTimeoutError) - self.assertEquals(len(self.proto.liveMessages), 0) + self.assertEqual(len(self.proto.liveMessages), 0) return d @@ -384,10 +481,10 @@ Test that query timeouts after some seconds. """ d = self.proto.query([dns.Query('foo')]) - self.assertEquals(len(self.proto.liveMessages), 1) + self.assertEqual(len(self.proto.liveMessages), 1) self.clock.advance(60) self.assertFailure(d, dns.DNSQueryTimeoutError) - self.assertEquals(len(self.proto.liveMessages), 0) + self.assertEqual(len(self.proto.liveMessages), 0) return d @@ -396,13 +493,13 @@ Test content received after a query. """ d = self.proto.query([dns.Query('foo')]) - self.assertEquals(len(self.proto.liveMessages.keys()), 1) + self.assertEqual(len(self.proto.liveMessages.keys()), 1) m = dns.Message() m.id = self.proto.liveMessages.items()[0][0] m.answers = [dns.RRHeader(payload=dns.Record_A(address='1.2.3.4'))] called = False def cb(result): - self.assertEquals(result.answers[0].payload.dottedQuad(), '1.2.3.4') + self.assertEqual(result.answers[0].payload.dottedQuad(), '1.2.3.4') d.addCallback(cb) s = m.toStr() s = struct.pack('!H', len(s)) + s diff --git a/lib/twisted-trunk/twisted/names/test/test_names.py b/lib/twisted-trunk/twisted/names/test/test_names.py --- a/lib/twisted-trunk/twisted/names/test/test_names.py +++ b/lib/twisted-trunk/twisted/names/test/test_names.py @@ -12,7 +12,7 @@ from twisted.internet import reactor, defer, error from twisted.internet.defer import succeed -from twisted.names import client, server, common, authority, hosts, dns +from twisted.names import client, server, common, authority, dns from twisted.python import failure from twisted.names.error import DNSFormatError, DNSServerError, DNSNameError from twisted.names.error import DNSNotImplementedError, DNSQueryRefusedError @@ -551,7 +551,7 @@ m.queries = [dns.Query('fooby.com', dns.AXFR, dns.IN)] m.answers = self.records self.controller.messageReceived(m, None) - self.assertEquals(self.results, self.records) + self.assertEqual(self.results, self.records) def _gotResults(self, result): self.results = result @@ -564,72 +564,7 @@ m.queries = [] # DJB *doesn't* specify any queries.. hmm.. m.answers = [records.pop(0)] self.controller.messageReceived(m, None) - self.assertEquals(self.results, self.records) - -class HostsTestCase(unittest.TestCase): - def setUp(self): - f = open('EtcHosts', 'w') - f.write(''' -1.1.1.1 EXAMPLE EXAMPLE.EXAMPLETHING -1.1.1.2 HOOJY -::1 ip6thingy -''') - f.close() - self.resolver = hosts.Resolver('EtcHosts') - - def testGetHostByName(self): - data = [('EXAMPLE', '1.1.1.1'), - ('EXAMPLE.EXAMPLETHING', '1.1.1.1'), - ('HOOJY', '1.1.1.2'), - ] - ds = [self.resolver.getHostByName(n).addCallback(self.assertEqual, ip) - for n, ip in data] - return defer.gatherResults(ds) - - def testLookupAddress(self): - d = self.resolver.lookupAddress('HOOJY') - d.addCallback(lambda x: self.assertEqual(x[0][0].payload.dottedQuad(), - '1.1.1.2')) - return d - - def testIPv6(self): - d = self.resolver.lookupIPV6Address('ip6thingy') - d.addCallback(self.assertEqual, '::1') - return d - - testIPv6.skip = 'IPv6 support is not in our hosts resolver yet' - - def testNotImplemented(self): - return self.assertFailure(self.resolver.lookupMailExchange('EXAMPLE'), - NotImplementedError) - - def testQuery(self): - d = self.resolver.query(dns.Query('EXAMPLE')) - d.addCallback(lambda x: self.assertEqual(x[0][0].payload.dottedQuad(), - '1.1.1.1')) - return d - - def testNotFound(self): - return self.assertFailure(self.resolver.lookupAddress('foueoa'), - dns.DomainError) - - - def test_searchFileFor(self): - """ - L{searchFileFor} parses hosts(5) files and returns the address for - the given name, or C{None} if the name is not found. - """ - tmp = self.mktemp() - f = open(tmp, 'w') - f.write('127.0.1.1 helmut.example.org helmut\n') - f.write('# a comment\n') - f.write('::1 localhost ip6-localhost ip6-loopback\n') - f.close() - self.assertEquals(hosts.searchFileFor(tmp, 'helmut'), '127.0.1.1') - self.assertEquals(hosts.searchFileFor(tmp, 'ip6-localhost'), '::1') - self.assertIdentical(hosts.searchFileFor(tmp, 'blah'), None) - - + self.assertEqual(self.results, self.records) class FakeDNSDatagramProtocol(object): def __init__(self): @@ -678,8 +613,8 @@ expected.sort() for ((addr, query, timeout, id), expectedAddr) in zip(tries, expected): - self.assertEquals(addr, (expectedAddr, 53)) - self.assertEquals(timeout, t) + self.assertEqual(addr, (expectedAddr, 53)) + self.assertEqual(timeout, t) self.failIf(fakeProto.queries) @@ -687,7 +622,7 @@ def testMissing(self): resolvConf = self.mktemp() r = client.Resolver(resolv=resolvConf) - self.assertEquals(r.dynServers, [('127.0.0.1', 53)]) + self.assertEqual(r.dynServers, [('127.0.0.1', 53)]) r._parseCall.cancel() def testEmpty(self): @@ -695,7 +630,7 @@ fObj = file(resolvConf, 'w') fObj.close() r = client.Resolver(resolv=resolvConf) - self.assertEquals(r.dynServers, [('127.0.0.1', 53)]) + self.assertEqual(r.dynServers, [('127.0.0.1', 53)]) r._parseCall.cancel() @@ -807,14 +742,14 @@ result = [] d.addCallback(result.append) answer, authority, additional = result[0] - self.assertEquals(answer, []) - self.assertEquals( + self.assertEqual(answer, []) + self.assertEqual( authority, [ dns.RRHeader( str(soa_record.mname), soa_record.TYPE, ttl=soa_record.expire, payload=soa_record, auth=True)]) - self.assertEquals(additional, []) + self.assertEqual(additional, []) def _referralTest(self, method): @@ -835,12 +770,12 @@ result = [] d.addCallback(result.append) answer, authority, additional = result[0] - self.assertEquals(answer, []) - self.assertEquals( + self.assertEqual(answer, []) + self.assertEqual( authority, [dns.RRHeader( subdomain, dns.NS, ttl=soa_record.expire, payload=nameserver, auth=False)]) - self.assertEquals(additional, []) + self.assertEqual(additional, []) def test_referral(self): diff --git a/lib/twisted-trunk/twisted/names/test/test_rootresolve.py b/lib/twisted-trunk/twisted/names/test/test_rootresolve.py --- a/lib/twisted-trunk/twisted/names/test/test_rootresolve.py +++ b/lib/twisted-trunk/twisted/names/test/test_rootresolve.py @@ -159,14 +159,14 @@ msg.fromStr(packet) # It should be a query with the parameters used above. - self.assertEquals(msg.queries, [Query('foo.example.com', A, IN)]) - self.assertEquals(msg.answers, []) - self.assertEquals(msg.authority, []) - self.assertEquals(msg.additional, []) + self.assertEqual(msg.queries, [Query('foo.example.com', A, IN)]) + self.assertEqual(msg.answers, []) + self.assertEqual(msg.authority, []) + self.assertEqual(msg.additional, []) response = [] d.addCallback(response.append) - self.assertEquals(response, []) + self.assertEqual(response, []) # Once a reply is received, the Deferred should fire. del msg.queries[:] @@ -184,11 +184,11 @@ result is a three-tuple of lists of records. """ answer, authority, additional = self._queryTest(True) - self.assertEquals( + self.assertEqual( answer, [RRHeader('foo.example.com', payload=Record_A('5.8.13.21', ttl=0))]) - self.assertEquals(authority, []) - self.assertEquals(additional, []) + self.assertEqual(authority, []) + self.assertEqual(additional, []) def test_unfilteredQuery(self): @@ -199,12 +199,12 @@ """ message = self._queryTest(False) self.assertIsInstance(message, Message) - self.assertEquals(message.queries, []) - self.assertEquals( + self.assertEqual(message.queries, []) + self.assertEqual( message.answers, [RRHeader('foo.example.com', payload=Record_A('5.8.13.21', ttl=0))]) - self.assertEquals(message.authority, []) - self.assertEquals(message.additional, []) + self.assertEqual(message.authority, []) + self.assertEqual(message.additional, []) def _respond(self, answers=[], authority=[], additional=[], rCode=OK): @@ -282,7 +282,7 @@ resolver = self._getResolver(servers) d = resolver.lookupAddress('foo.example.com') d.addCallback(lambda (ans, auth, add): ans[0].payload.dottedQuad()) - d.addCallback(self.assertEquals, '10.0.0.1') + d.addCallback(self.assertEqual, '10.0.0.1') return d @@ -311,7 +311,7 @@ resolver = self._getResolver(servers) d = resolver.lookupAddress('foo.example.com') d.addCallback(lambda (ans, auth, add): ans[0].payload) - d.addCallback(self.assertEquals, Record_A('10.0.0.3')) + d.addCallback(self.assertEqual, Record_A('10.0.0.3')) return d @@ -339,7 +339,7 @@ resolver = self._getResolver(servers) d = resolver.lookupAddress('foo.example.com') d.addCallback(lambda (ans, auth, add): ans[0].payload.dottedQuad()) - d.addCallback(self.assertEquals, '10.0.0.2') + d.addCallback(self.assertEqual, '10.0.0.2') return d @@ -436,7 +436,7 @@ resolver = self._getResolver(servers) d = resolver.lookupNameservers('example.com') d.addCallback(lambda (ans, auth, add): str(ans[0].payload.name)) - d.addCallback(self.assertEquals, 'ns1.example.com') + d.addCallback(self.assertEqual, 'ns1.example.com') return d @@ -457,7 +457,7 @@ d = resolver.lookupAddress('example.com') d.addCallback(lambda (ans, auth, add): ans) d.addCallback( - self.assertEquals, + self.assertEqual, [RRHeader('example.com', CNAME, payload=Record_CNAME('example.net')), RRHeader('example.net', A, payload=Record_A('10.0.0.7'))]) return d @@ -483,7 +483,7 @@ d = resolver.lookupAddress('example.com') d.addCallback(lambda (ans, auth, add): ans) d.addCallback( - self.assertEquals, + self.assertEqual, [RRHeader('example.com', CNAME, payload=Record_CNAME('example.net')), RRHeader('example.net', A, payload=Record_A('10.0.0.5'))]) return d @@ -553,7 +553,7 @@ succeeder = self._getResolver(servers, 4) succeedD = succeeder.lookupAddress('example.com') succeedD.addCallback(lambda (ans, auth, add): ans[0].payload) - succeedD.addCallback(self.assertEquals, Record_A('10.0.0.4')) + succeedD.addCallback(self.assertEqual, Record_A('10.0.0.4')) return gatherResults([failD, succeedD]) @@ -567,12 +567,12 @@ warnings = self.flushWarnings([ self.test_discoveredAuthorityDeprecated]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], 'twisted.names.root.Resolver.discoveredAuthority is deprecated since ' 'Twisted 10.0. Use twisted.names.client.Resolver directly, instead.') - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) # This will time out quickly, but we need to wait for it because there # are resources associated with. @@ -614,13 +614,13 @@ warnings = self.flushWarnings([ self.test_lookupNameserversDeprecated]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], 'twisted.names.root.lookupNameservers is deprecated since Twisted ' '10.0. Use twisted.names.root.Resolver.lookupNameservers ' 'instead.') - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) test_lookupNameserversDeprecated.suppress = [_retrySuppression] @@ -634,13 +634,13 @@ warnings = self.flushWarnings([ self.test_lookupAddressDeprecated]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], 'twisted.names.root.lookupAddress is deprecated since Twisted ' '10.0. Use twisted.names.root.Resolver.lookupAddress ' 'instead.') - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) test_lookupAddressDeprecated.suppress = [_retrySuppression] @@ -652,12 +652,12 @@ warnings = self.flushWarnings([ self.test_extractAuthorityDeprecated]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], 'twisted.names.root.extractAuthority is deprecated since Twisted ' '10.0. Please inspect the Message object directly.') - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) def test_discoverAuthorityDeprecated(self): @@ -669,13 +669,13 @@ warnings = self.flushWarnings([ self.test_discoverAuthorityDeprecated]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], 'twisted.names.root.discoverAuthority is deprecated since Twisted ' '10.0. Use twisted.names.root.Resolver.lookupNameservers ' 'instead.') - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) # discoverAuthority is implemented in terms of deprecated functions, # too. Ignore those. @@ -697,9 +697,9 @@ warnings = self.flushWarnings([ self.test_retryDeprecated]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], 'twisted.names.root.retry is deprecated since Twisted ' '10.0. Use a Resolver object for retry logic.') - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) diff --git a/lib/twisted-trunk/twisted/names/test/test_srvconnect.py b/lib/twisted-trunk/twisted/names/test/test_srvconnect.py --- a/lib/twisted-trunk/twisted/names/test/test_srvconnect.py +++ b/lib/twisted-trunk/twisted/names/test/test_srvconnect.py @@ -74,7 +74,7 @@ self.connector.connect() self.assertIdentical(None, self.factory.reason) - self.assertEquals( + self.assertEqual( self.reactor.tcpClients.pop()[:2], ('host.example.org', 6269)) @@ -86,7 +86,7 @@ self.connector.connect() self.assertIdentical(None, self.factory.reason) - self.assertEquals( + self.assertEqual( self.reactor.tcpClients.pop()[:2], ('example.org', 'xmpp-server')) @@ -98,7 +98,7 @@ self.connector.connect() self.assertIdentical(None, self.factory.reason) - self.assertEquals( + self.assertEqual( self.reactor.tcpClients.pop()[:2], ('example.org', 'xmpp-server')) @@ -113,7 +113,7 @@ self.connector.connect() self.assertIdentical(None, self.factory.reason) - self.assertEquals( + self.assertEqual( self.reactor.tcpClients.pop()[:2], ('example.org', 'xmpp-server')) @@ -130,4 +130,4 @@ self.assertNotIdentical(None, self.factory.reason) self.factory.reason.trap(DNSLookupError) - self.assertEquals(self.reactor.tcpClients, []) + self.assertEqual(self.reactor.tcpClients, []) diff --git a/lib/twisted-trunk/twisted/news/test/test_database.py b/lib/twisted-trunk/twisted/news/test/test_database.py --- a/lib/twisted-trunk/twisted/news/test/test_database.py +++ b/lib/twisted-trunk/twisted/news/test/test_database.py @@ -102,7 +102,7 @@ result = storage.postRequest(message) def cbPosted(ignored): - self.assertEquals(self._email, []) + self.assertEqual(self._email, []) exists = storage.articleExistsRequest(articleID) exists.addCallback(self.assertTrue) return exists @@ -126,14 +126,14 @@ result = storage.postRequest(message) def cbModerated(ignored): - self.assertEquals(len(self._email), 1) - self.assertEquals(self._email[0][0], mailhost) - self.assertEquals(self._email[0][1], sender) - self.assertEquals(self._email[0][2], [moderator]) + self.assertEqual(len(self._email), 1) + self.assertEqual(self._email[0][0], mailhost) + self.assertEqual(self._email[0][1], sender) + self.assertEqual(self._email[0][2], [moderator]) self._checkModeratorMessage( self._email[0][3], sender, moderator, group, message) - self.assertEquals(self._email[0][4], None) - self.assertEquals(self._email[0][5], 25) + self.assertEqual(self._email[0][4], None) + self.assertEqual(self._email[0][5], 25) exists = storage.articleExistsRequest(articleID) exists.addCallback(self.assertFalse) return exists @@ -146,7 +146,7 @@ msg = p.parsestr(messageText) headers = dict(msg.items()) del headers['Message-ID'] - self.assertEquals( + self.assertEqual( headers, {'From': sender, 'To': moderator, @@ -157,9 +157,9 @@ attachment = msg.get_payload()[0] for header in ['from', 'to', 'subject', 'message-id', 'newsgroups']: - self.assertEquals(posting[header], attachment[header]) + self.assertEqual(posting[header], attachment[header]) - self.assertEquals(posting.get_payload(), attachment.get_payload()) + self.assertEqual(posting.get_payload(), attachment.get_payload()) @@ -208,7 +208,7 @@ shelf = NewsShelf('example.com', self.mktemp(), 'alice at example.com') shelf.sendmail = self.sendmail shelf.notifyModerator('bob at example.org', Article('Foo: bar', 'Some text')) - self.assertEquals(len(self._email), 1) + self.assertEqual(len(self._email), 1) def test_defaultSender(self): @@ -220,5 +220,5 @@ shelf = NewsShelf('example.com', self.mktemp()) shelf.sendmail = self.sendmail shelf.notifyModerators(['bob at example.org'], Article('Foo: bar', 'Some text')) - self.assertEquals(self._email[0][1], 'twisted-news@' + gethostname()) + self.assertEqual(self._email[0][1], 'twisted-news@' + gethostname()) self.assertIn('From: twisted-news@' + gethostname(), self._email[0][3]) diff --git a/lib/twisted-trunk/twisted/news/test/test_news.py b/lib/twisted-trunk/twisted/news/test/test_news.py --- a/lib/twisted-trunk/twisted/news/test/test_news.py +++ b/lib/twisted-trunk/twisted/news/test/test_news.py @@ -50,10 +50,10 @@ def cbArticle(result): self.failUnless(isinstance(result, tuple), 'callback result is wrong type: ' + str(result)) - self.assertEquals(len(result), 3, + self.assertEqual(len(result), 3, 'callback result list should have three entries: ' + str(result)) - self.assertEquals(result[1], MESSAGE_ID, + self.assertEqual(result[1], MESSAGE_ID, "callback result Message-Id doesn't match: %s vs %s" % (MESSAGE_ID, result[1])) body = result[2].read() @@ -76,11 +76,11 @@ return d def cbHead(result): - self.assertEquals(result[1], MESSAGE_ID, + self.assertEqual(result[1], MESSAGE_ID, "callback result Message-Id doesn't match: %s vs %s" % (MESSAGE_ID, result[1])) - self.assertEquals(result[2][-2:], '\r\n', + self.assertEqual(result[2][-2:], '\r\n', "headers must be \\r\\n terminated.") d.addCallback(cbArticle) @@ -99,7 +99,7 @@ def cbBody(result): body = result[2].read() - self.assertEquals(body[0:4], 'this', + self.assertEqual(body[0:4], 'this', "message body has been altered: " + pformat(body[0:4])) diff --git a/lib/twisted-trunk/twisted/news/test/test_nntp.py b/lib/twisted-trunk/twisted/news/test/test_nntp.py --- a/lib/twisted-trunk/twisted/news/test/test_nntp.py +++ b/lib/twisted-trunk/twisted/news/test/test_nntp.py @@ -36,39 +36,39 @@ def __init__(self): nntp.NNTPClient.__init__(self) - def assertEquals(self, foo, bar): + def assertEqual(self, foo, bar): if foo != bar: raise AssertionError("%r != %r!" % (foo, bar)) - + def connectionMade(self): nntp.NNTPClient.connectionMade(self) self.fetchSubscriptions() def gotSubscriptions(self, subscriptions): - self.assertEquals(len(subscriptions), len(SUBSCRIPTIONS)) + self.assertEqual(len(subscriptions), len(SUBSCRIPTIONS)) for s in subscriptions: assert s in SUBSCRIPTIONS self.fetchGroups() - + def gotAllGroups(self, info): - self.assertEquals(len(info), len(ALL_GROUPS)) - self.assertEquals(info[0], ALL_GROUPS[0]) - + self.assertEqual(len(info), len(ALL_GROUPS)) + self.assertEqual(info[0], ALL_GROUPS[0]) + self.fetchGroup('alt.test.nntp') - - + + def getAllGroupsFailed(self, error): raise AssertionError("fetchGroups() failed: %s" % (error,)) def gotGroup(self, info): - self.assertEquals(len(info), 6) - self.assertEquals(info, GROUP) - + self.assertEqual(len(info), 6) + self.assertEqual(info, GROUP) + self.postArticle(POST_STRING) - - + + def getSubscriptionsFailed(self, error): raise AssertionError("fetchSubscriptions() failed: %s" % (error,)) @@ -84,17 +84,17 @@ def postedOk(self): self.fetchArticle(1) - + def gotArticle(self, info): origBody = POST_STRING.split('\n\n')[1] newBody = info.split('\n\n', 1)[1] - self.assertEquals(origBody, newBody) - + self.assertEqual(origBody, newBody) + # We're done self.transport.loseConnection() - - + + def getArticleFailed(self, error): raise AssertionError("fetchArticle() failed: %s" % (error,)) @@ -105,7 +105,7 @@ self.server.factory = self self.backend = database.NewsShelf(None, 'news.db') self.backend.addGroup('alt.test.nntp', 'y') - + for s in SUBSCRIPTIONS: self.backend.addSubscription(s) diff --git a/lib/twisted-trunk/twisted/plugins/twisted_reactors.py b/lib/twisted-trunk/twisted/plugins/twisted_reactors.py --- a/lib/twisted-trunk/twisted/plugins/twisted_reactors.py +++ b/lib/twisted-trunk/twisted/plugins/twisted_reactors.py @@ -5,7 +5,7 @@ default = Reactor( 'default', 'twisted.internet.default', - 'The best reactor for the current platform.') + 'A reasonable default: poll(2) if available, otherwise select(2).') select = Reactor( 'select', 'twisted.internet.selectreactor', 'select(2)-based reactor.') diff --git a/lib/twisted-trunk/twisted/protocols/test/test_tls.py b/lib/twisted-trunk/twisted/protocols/test/test_tls.py --- a/lib/twisted-trunk/twisted/protocols/test/test_tls.py +++ b/lib/twisted-trunk/twisted/protocols/test/test_tls.py @@ -19,8 +19,9 @@ from twisted.internet.ssl import DefaultOpenSSLContextFactory from twisted.python.filepath import FilePath +from twisted.python.failure import Failure from twisted.internet.interfaces import ISystemHandle, ISSLTransport -from twisted.internet.error import ConnectionDone +from twisted.internet.error import ConnectionDone, ConnectionLost from twisted.internet.defer import Deferred, gatherResults from twisted.internet.protocol import Protocol, ClientFactory, ServerFactory from twisted.protocols.loopback import loopbackAsync, collapsingPumpPolicy @@ -162,10 +163,9 @@ self.assertNotIdentical(clientProtocol.transport, transport) - def test_handshake(self): + def handshakeProtocols(self): """ - The TLS handshake is performed when L{TLSMemoryBIOProtocol} is - connected to a transport. + Start handshake between TLS client and server. """ clientFactory = ClientFactory() clientFactory.protocol = Protocol @@ -185,6 +185,16 @@ sslServerProtocol = wrapperFactory.buildProtocol(None) connectionDeferred = loopbackAsync(sslServerProtocol, sslClientProtocol) + return (sslClientProtocol, sslServerProtocol, handshakeDeferred, + connectionDeferred) + + + def test_handshake(self): + """ + The TLS handshake is performed when L{TLSMemoryBIOProtocol} is + connected to a transport. + """ + tlsClient, tlsServer, handshakeDeferred, _ = self.handshakeProtocols() # Only wait for the handshake to complete. Anything after that isn't # important here. @@ -273,7 +283,7 @@ # Grab the server's certificate and check it out cert = sslClientProtocol.getPeerCertificate() self.assertIsInstance(cert, X509Type) - self.assertEquals( + self.assertEqual( cert.digest('md5'), '9B:A4:AB:43:10:BE:82:AE:94:3E:6B:91:F2:F3:40:E8') handshakeDeferred.addCallback(cbHandshook) @@ -320,26 +330,19 @@ # Once the connection is lost, make sure the server received the # expected bytes. def cbDisconnected(ignored): - self.assertEquals("".join(serverProtocol.received), bytes) + self.assertEqual("".join(serverProtocol.received), bytes) handshakeDeferred.addCallback(cbDisconnected) return handshakeDeferred - def test_writeBeforeHandshake(self): + def writeBeforeHandshakeTest(self, sendingProtocol, bytes): """ - Bytes written to L{TLSMemoryBIOProtocol} before the handshake is - complete are received by the protocol on the other side of the - connection once the handshake succeeds. + Run test where client sends data before handshake, given the sending + protocol and expected bytes. """ - bytes = "some bytes" - - class SimpleSendingProtocol(Protocol): - def connectionMade(self): - self.transport.write(bytes) - clientFactory = ClientFactory() - clientFactory.protocol = SimpleSendingProtocol + clientFactory.protocol = sendingProtocol clientContextFactory, handshakeDeferred = ( HandshakeCallbackContextFactory.factoryAndDeferred()) @@ -361,11 +364,26 @@ # Wait for the connection to end, then make sure the server received # the bytes sent by the client. def cbConnectionDone(ignored): - self.assertEquals("".join(serverProtocol.received), bytes) + self.assertEqual("".join(serverProtocol.received), bytes) connectionDeferred.addCallback(cbConnectionDone) return connectionDeferred + def test_writeBeforeHandshake(self): + """ + Bytes written to L{TLSMemoryBIOProtocol} before the handshake is + complete are received by the protocol on the other side of the + connection once the handshake succeeds. + """ + bytes = "some bytes" + + class SimpleSendingProtocol(Protocol): + def connectionMade(self): + self.transport.write(bytes) + + return self.writeBeforeHandshakeTest(SimpleSendingProtocol, bytes) + + def test_writeSequence(self): """ Bytes written to L{TLSMemoryBIOProtocol} with C{writeSequence} are @@ -376,31 +394,23 @@ def connectionMade(self): self.transport.writeSequence(list(bytes)) - clientFactory = ClientFactory() - clientFactory.protocol = SimpleSendingProtocol + return self.writeBeforeHandshakeTest(SimpleSendingProtocol, bytes) - clientContextFactory = HandshakeCallbackContextFactory() - wrapperFactory = TLSMemoryBIOFactory( - clientContextFactory, True, clientFactory) - sslClientProtocol = wrapperFactory.buildProtocol(None) - serverProtocol = AccumulatingProtocol(len(bytes)) - serverFactory = ServerFactory() - serverFactory.protocol = lambda: serverProtocol - - serverContextFactory = DefaultOpenSSLContextFactory(certPath, certPath) - wrapperFactory = TLSMemoryBIOFactory( - serverContextFactory, False, serverFactory) - sslServerProtocol = wrapperFactory.buildProtocol(None) - - connectionDeferred = loopbackAsync(sslServerProtocol, sslClientProtocol) - - # Wait for the connection to end, then make sure the server received - # the bytes sent by the client. - def cbConnectionDone(ignored): - self.assertEquals("".join(serverProtocol.received), bytes) - connectionDeferred.addCallback(cbConnectionDone) - return connectionDeferred + def test_writeAfterLoseConnection(self): + """ + Bytes written to L{TLSMemoryBIOProtocol} after C{loseConnection} is + called are not transmitted (unless there is a registered producer, + which will be tested elsewhere). + """ + bytes = "some bytes" + class SimpleSendingProtocol(Protocol): + def connectionMade(self): + self.transport.write(bytes) + self.transport.loseConnection() + self.transport.write("hello") + self.transport.writeSequence(["world"]) + return self.writeBeforeHandshakeTest(SimpleSendingProtocol, bytes) def test_multipleWrites(self): @@ -437,7 +447,7 @@ # Wait for the connection to end, then make sure the server received # the bytes sent by the client. def cbConnectionDone(ignored): - self.assertEquals("".join(serverProtocol.received), ''.join(bytes)) + self.assertEqual("".join(serverProtocol.received), ''.join(bytes)) connectionDeferred.addCallback(cbConnectionDone) return connectionDeferred @@ -476,7 +486,7 @@ # Wait for the connection to end, then make sure the server received # the bytes sent by the client. def cbConnectionDone(ignored): - self.assertEquals("".join(serverProtocol.received), bytes * factor) + self.assertEqual("".join(serverProtocol.received), bytes * factor) connectionDeferred.addCallback(cbConnectionDone) return connectionDeferred @@ -515,13 +525,22 @@ def test_loseConnectionAfterHandshake(self): """ L{TLSMemoryBIOProtocol.loseConnection} sends a TLS close alert and - shuts down the underlying connection. + shuts down the underlying connection cleanly on both sides, after + transmitting all buffered data. """ + class NotifyingProtocol(ConnectionLostNotifyingProtocol): + def __init__(self, onConnectionLost): + ConnectionLostNotifyingProtocol.__init__(self, + onConnectionLost) + self.data = [] + + def dataReceived(self, bytes): + self.data.append(bytes) + clientConnectionLost = Deferred() clientFactory = ClientFactory() - clientFactory.protocol = ( - lambda: ConnectionLostNotifyingProtocol( - clientConnectionLost)) + clientProtocol = NotifyingProtocol(clientConnectionLost) + clientFactory.protocol = lambda: clientProtocol clientContextFactory, handshakeDeferred = ( HandshakeCallbackContextFactory.factoryAndDeferred()) @@ -529,7 +548,8 @@ clientContextFactory, True, clientFactory) sslClientProtocol = wrapperFactory.buildProtocol(None) - serverProtocol = Protocol() + serverConnectionLost = Deferred() + serverProtocol = NotifyingProtocol(serverConnectionLost) serverFactory = ServerFactory() serverFactory.protocol = lambda: serverProtocol @@ -539,19 +559,32 @@ sslServerProtocol = wrapperFactory.buildProtocol(None) connectionDeferred = loopbackAsync(sslServerProtocol, sslClientProtocol) + chunkOfBytes = "123456890" * 100000 # Wait for the handshake before dropping the connection. def cbHandshake(ignored): + # Write more than a single bio_read, to ensure client will still + # have some data it needs to write when it receives the TLS close + # alert, and that simply doing a single bio_read won't be + # sufficient. Thus we will verify that any amount of buffered data + # will be written out before the connection is closed, rather than + # just small amounts that can be returned in a single bio_read: + clientProtocol.transport.write(chunkOfBytes) serverProtocol.transport.loseConnection() - # Now wait for the client to notice. - return clientConnectionLost + # Now wait for the client and server to notice. + return gatherResults([clientConnectionLost, serverConnectionLost]) handshakeDeferred.addCallback(cbHandshake) - # Wait for the connection to end, then make sure the client was - # notified of a handshake failure. - def cbConnectionDone(clientProtocol): + # Wait for the connection to end, then make sure the client and server + # weren't notified of a handshake failure that would cause the test to + # fail. + def cbConnectionDone((clientProtocol, serverProtocol)): clientProtocol.lostConnectionReason.trap(ConnectionDone) + serverProtocol.lostConnectionReason.trap(ConnectionDone) + + # The server should have received all bytes sent by the client: + self.assertEqual("".join(serverProtocol.data), chunkOfBytes) # The server should have closed its underlying transport, in # addition to whatever it did to shut down the TLS layer. @@ -564,3 +597,118 @@ handshakeDeferred.addCallback(cbConnectionDone) return handshakeDeferred + + def test_connectionLostOnlyAfterUnderlyingCloses(self): + """ + The user protocol's connectionLost is only called when transport + underlying TLS is disconnected. + """ + class LostProtocol(Protocol): + disconnected = None + def connectionLost(self, reason): + self.disconnected = reason + wrapperFactory = TLSMemoryBIOFactory(ClientContextFactory(), + True, ClientFactory()) + protocol = LostProtocol() + tlsProtocol = TLSMemoryBIOProtocol(wrapperFactory, protocol) + transport = StringTransport() + tlsProtocol.makeConnection(transport) + + # Pretend TLS shutdown finished cleanly; the underlying transport + # should be told to close, but the user protocol should not yet be + # notified: + tlsProtocol._tlsShutdownFinished(None) + self.assertEqual(transport.disconnecting, True) + self.assertEqual(protocol.disconnected, None) + + # Now close the underlying connection; the user protocol should be + # notified with the given reason (since TLS closed cleanly): + tlsProtocol.connectionLost(Failure(ConnectionLost("ono"))) + self.assertTrue(protocol.disconnected.check(ConnectionLost)) + self.assertEqual(protocol.disconnected.value.args, ("ono",)) + + + def test_loseConnectionTwice(self): + """ + If TLSMemoryBIOProtocol.loseConnection is called multiple times, all + but the first call have no effect. + """ + wrapperFactory = TLSMemoryBIOFactory(ClientContextFactory(), + True, ClientFactory()) + tlsProtocol = TLSMemoryBIOProtocol(wrapperFactory, Protocol()) + transport = StringTransport() + tlsProtocol.makeConnection(transport) + self.assertEqual(tlsProtocol.disconnecting, False) + + # Make sure loseConnection calls _shutdownTLS the first time (mostly + # to make sure we've overriding it correctly): + calls = [] + def _shutdownTLS(shutdown=tlsProtocol._shutdownTLS): + calls.append(1) + return shutdown() + tlsProtocol._shutdownTLS = _shutdownTLS + tlsProtocol.loseConnection() + self.assertEqual(tlsProtocol.disconnecting, True) + self.assertEqual(calls, [1]) + + # Make sure _shutdownTLS isn't called a second time: + tlsProtocol.loseConnection() + self.assertEqual(calls, [1]) + + + def test_unexpectedEOF(self): + """ + Unexpected disconnects get converted to ConnectionLost errors. + """ + tlsClient, tlsServer, handshakeDeferred, disconnectDeferred = ( + self.handshakeProtocols()) + serverProtocol = tlsServer.wrappedProtocol + data = [] + reason = [] + serverProtocol.dataReceived = data.append + serverProtocol.connectionLost = reason.append + + # Write data, then disconnect *underlying* transport, resulting in an + # unexpected TLS disconnect: + def handshakeDone(ign): + tlsClient.write("hello") + tlsClient.transport.loseConnection() + handshakeDeferred.addCallback(handshakeDone) + + # Receiver should be disconnected, with ConnectionLost notification + # (masking the Unexpected EOF SSL error): + def disconnected(ign): + self.assertTrue(reason[0].check(ConnectionLost), reason[0]) + disconnectDeferred.addCallback(disconnected) + return disconnectDeferred + + + def test_errorWriting(self): + """ + Errors while writing cause the protocols to be disconnected. + """ + tlsClient, tlsServer, handshakeDeferred, disconnectDeferred = ( + self.handshakeProtocols()) + reason = [] + tlsClient.wrappedProtocol.connectionLost = reason.append + + # Pretend TLS connection is unhappy sending: + class Wrapper(object): + def __init__(self, wrapped): + self._wrapped = wrapped + def __getattr__(self, attr): + return getattr(self._wrapped, attr) + def send(self, *args): + raise Error("ONO!") + tlsClient._tlsConnection = Wrapper(tlsClient._tlsConnection) + + # Write some data: + def handshakeDone(ign): + tlsClient.write("hello") + handshakeDeferred.addCallback(handshakeDone) + + # Failed writer should be disconnected with SSL error: + def disconnected(ign): + self.assertTrue(reason[0].check(Error), reason[0]) + disconnectDeferred.addCallback(disconnected) + return disconnectDeferred diff --git a/lib/twisted-trunk/twisted/protocols/tls.py b/lib/twisted-trunk/twisted/protocols/tls.py --- a/lib/twisted-trunk/twisted/protocols/tls.py +++ b/lib/twisted-trunk/twisted/protocols/tls.py @@ -49,7 +49,7 @@ from twisted.python.failure import Failure from twisted.internet.interfaces import ISystemHandle, ISSLTransport -from twisted.internet.main import CONNECTION_DONE, CONNECTION_LOST +from twisted.internet.main import CONNECTION_LOST from twisted.internet.protocol import Protocol from twisted.protocols.policies import ProtocolWrapper, WrappingFactory @@ -64,8 +64,9 @@ @ivar _tlsConnection: The L{OpenSSL.SSL.Connection} instance which is encrypted and decrypting this connection. - @ivar _lostConnection: A flag indicating whether connection loss has - already been dealt with (C{True}) or not (C{False}). + @ivar _lostTLSConnection: A flag indicating whether connection loss has + already been dealt with (C{True}) or not (C{False}). TLS disconnection + is distinct from the underlying connection being lost. @ivar _writeBlockedOnRead: A flag indicating whether further writing must wait for data to be received (C{True}) or not (C{False}). @@ -100,7 +101,7 @@ _reason = None _handshakeDone = False - _lostConnection = False + _lostTLSConnection = False _writeBlockedOnRead = False def __init__(self, factory, wrappedProtocol, _connectWrapped=True): @@ -183,7 +184,7 @@ # close the connection. Looping is necessary to make sure we # process all of the data which was put into the receive BIO, as # there is no guarantee that a single recv call will do it all. - while not self._lostConnection: + while not self._lostTLSConnection: try: bytes = self._tlsConnection.recv(2 ** 15) except WantReadError: @@ -193,32 +194,25 @@ except ZeroReturnError: # TLS has shut down and no more TLS data will be received over # this connection. - self._lostConnection = True - self.transport.loseConnection() - if not self._handshakeDone and self._reason is not None: - failure = self._reason - else: - failure = Failure(CONNECTION_DONE) - # Failure's are fat. Drop the reference. - self._reason = None - ProtocolWrapper.connectionLost(self, failure) + self._shutdownTLS() + # Passing in None means the user protocol's connnectionLost + # will get called with reason from underlying transport: + self._tlsShutdownFinished(None) except Error, e: # Something went pretty wrong. For example, this might be a # handshake failure (because there were no shared ciphers, because # a certificate failed to verify, etc). TLS can no longer proceed. - self._flushSendBIO() - self._lostConnection = True - # Squash EOF in violation of protocol into ConnectionLost + # Squash EOF in violation of protocol into ConnectionLost; we + # create Failure before calling _flushSendBio so that no new + # exception will get thrown in the interim. if e.args[0] == -1 and e.args[1] == 'Unexpected EOF': failure = Failure(CONNECTION_LOST) else: failure = Failure() - ProtocolWrapper.connectionLost(self, failure) - # This loseConnection call is basically tested by - # test_handshakeFailure. At least one side will need to do it - # or the test never finishes. - self.transport.loseConnection() + + self._flushSendBIO() + self._tlsShutdownFinished(failure) else: # If we got application bytes, the handshake must be done by # now. Keep track of this to control error reporting later. @@ -246,43 +240,94 @@ appSendBuffer = self._appSendBuffer self._appSendBuffer = [] for bytes in appSendBuffer: - self.write(bytes) + self._write(bytes) if not self._writeBlockedOnRead and self.disconnecting: - self.loseConnection() + self._shutdownTLS() self._flushReceiveBIO() + def _shutdownTLS(self): + """ + Initiate, or reply to, the shutdown handshake of the TLS layer. + """ + shutdownSuccess = self._tlsConnection.shutdown() + self._flushSendBIO() + if shutdownSuccess: + # Both sides have shutdown, so we can start closing lower-level + # transport. This will also happen if we haven't started + # negotiation at all yet, in which case shutdown succeeds + # immediately. + self.transport.loseConnection() + + + def _tlsShutdownFinished(self, reason): + """ + Called when TLS connection has gone away; tell underlying transport to + disconnect. + """ + self._reason = reason + self._lostTLSConnection = True + # Using loseConnection causes the application protocol's + # connectionLost method to be invoked non-reentrantly, which is always + # a nice feature. However, for error cases (reason != None) we might + # want to use abortConnection when it becomes available. The + # loseConnection call is basically tested by test_handshakeFailure. + # At least one side will need to do it or the test never finishes. + self.transport.loseConnection() + + def connectionLost(self, reason): """ Handle the possible repetition of calls to this method (due to either the underlying transport going away or due to an error at the TLS layer) and make sure the base implementation only gets invoked once. """ - if not self._lostConnection: + if not self._lostTLSConnection: # Tell the TLS connection that it's not going to get any more data # and give it a chance to finish reading. self._tlsConnection.bio_shutdown() self._flushReceiveBIO() + self._lostTLSConnection = True + reason = self._reason or reason + self._reason = None + ProtocolWrapper.connectionLost(self, reason) def loseConnection(self): """ Send a TLS close alert and close the underlying connection. """ + if self.disconnecting: + return self.disconnecting = True if not self._writeBlockedOnRead: - self._tlsConnection.shutdown() - self._flushSendBIO() - self.transport.loseConnection() + self._shutdownTLS() def write(self, bytes): """ Process the given application bytes and send any resulting TLS traffic which arrives in the send BIO. + + If C{loseConnection} was called, subsequent calls to C{write} will + drop the bytes on the floor. """ - if self._lostConnection: + if self.disconnecting: + return + self._write(bytes) + + + def _write(self, bytes): + """ + Process the given application bytes and send any resulting TLS traffic + which arrives in the send BIO. + + This may be called by C{dataReceived} with bytes that were buffered + before C{loseConnection} was called, which is why this function + doesn't check for disconnection but accepts the bytes regardless. + """ + if self._lostTLSConnection: return leftToSend = bytes @@ -293,16 +338,13 @@ self._writeBlockedOnRead = True self._appSendBuffer.append(leftToSend) break - except Error, e: - # Just drop the connection. This has two useful consequences. - # First, for the application protocol's connectionLost method, - # it will squash any error into connection lost. We *could* - # let the real exception propagate to application code, but the - # other SSL implementation doesn't. Second, it causes the - # protocol's connectionLost method to be invoked - # non-reentrantly, which is always a nice feature. - self._reason = Failure() - self.transport.loseConnection() + except Error: + # Pretend TLS connection disconnected, which will trigger + # disconnect of underlying transport. The error will be passed + # to the application protocol's connectionLost method. The + # other SSL implementation doesn't, but losing helpful + # debugging information is a bad idea. + self._tlsShutdownFinished(Failure()) break else: # If we sent some bytes, the handshake must be done. Keep diff --git a/lib/twisted-trunk/twisted/python/_inotify.py b/lib/twisted-trunk/twisted/python/_inotify.py --- a/lib/twisted-trunk/twisted/python/_inotify.py +++ b/lib/twisted-trunk/twisted/python/_inotify.py @@ -75,13 +75,22 @@ def initializeModule(libc): """ Intialize the module, checking if the expected APIs exist and setting the - argtypes for C{inotify_add_watch}. + argtypes and restype for for C{inotify_init}, C{inotify_add_watch}, and + C{inotify_rm_watch}. """ for function in ("inotify_add_watch", "inotify_init", "inotify_rm_watch"): if getattr(libc, function, None) is None: raise ImportError("libc6 2.4 or higher needed") + libc.inotify_init.argtypes = [] + libc.inotify_init.restype = ctypes.c_int + + libc.inotify_rm_watch.argtypes = [ + ctypes.c_int, ctypes.c_int] + libc.inotify_rm_watch.restype = ctypes.c_int + libc.inotify_add_watch.argtypes = [ - ctypes.c_int, ctypes.c_char_p, ctypes.c_int] + ctypes.c_int, ctypes.c_char_p, ctypes.c_uint32] + libc.inotify_add_watch.restype = ctypes.c_int diff --git a/lib/twisted-trunk/twisted/python/compat.py b/lib/twisted-trunk/twisted/python/compat.py --- a/lib/twisted-trunk/twisted/python/compat.py +++ b/lib/twisted-trunk/twisted/python/compat.py @@ -95,11 +95,15 @@ raise socket.error(97, 'Address family not supported by protocol') try: + socket.AF_INET6 +except AttributeError: + socket.AF_INET6 = 'AF_INET6' + +try: socket.inet_pton(socket.AF_INET6, "::") except (AttributeError, NameError, socket.error): socket.inet_pton = inet_pton socket.inet_ntop = inet_ntop - socket.AF_INET6 = 'AF_INET6' adict = dict diff --git a/lib/twisted-trunk/twisted/python/deprecate.py b/lib/twisted-trunk/twisted/python/deprecate.py --- a/lib/twisted-trunk/twisted/python/deprecate.py +++ b/lib/twisted-trunk/twisted/python/deprecate.py @@ -291,6 +291,29 @@ +class _InternalState(object): + """ + An L{_InternalState} is a helper object for a L{_ModuleProxy}, so that it + can easily access its own attributes, bypassing its logic for delegating to + another object that it's proxying for. + + @ivar proxy: a L{ModuleProxy} + """ + def __init__(self, proxy): + object.__setattr__(self, 'proxy', proxy) + + + def __getattribute__(self, name): + return object.__getattribute__(object.__getattribute__(self, 'proxy'), + name) + + + def __setattr__(self, name, value): + return object.__setattr__(object.__getattribute__(self, 'proxy'), + name, value) + + + class _ModuleProxy(object): """ Python module wrapper to hook module-level attribute access. @@ -300,17 +323,29 @@ there then access falls through to L{_ModuleProxy._module}, the wrapped module object. + @ivar _module: Module on which to hook attribute access. @type _module: C{module} - @ivar _module: Module on which to hook attribute access. + @ivar _deprecatedAttributes: Mapping of attribute names to objects that + retrieve the module attribute's original value. @type _deprecatedAttributes: C{dict} mapping C{str} to L{_DeprecatedAttribute} - @ivar _deprecatedAttributes: Mapping of attribute names to objects that - retrieve the module attribute's original value. + + @ivar _lastWasPath: Heuristic guess as to whether warnings about this + package should be ignored for the next call. If the last attribute + access of this module was a C{getattr} of C{__path__}, we will assume + that it was the import system doing it and we won't emit a warning for + the next access, even if it is to a deprecated attribute. The CPython + import system always tries to access C{__path__}, then the attribute + itself, then the attribute itself again, in both successful and failed + cases. + @type _lastWasPath: C{bool} """ def __init__(self, module): - object.__setattr__(self, '_module', module) - object.__setattr__(self, '_deprecatedAttributes', {}) + state = _InternalState(self) + state._module = module + state._deprecatedAttributes = {} + state._lastWasPath = False def __repr__(self): @@ -318,35 +353,46 @@ Get a string containing the type of the module proxy and a representation of the wrapped module object. """ - _module = object.__getattribute__(self, '_module') - return '<%s module=%r>' % ( - type(self).__name__, - _module) + state = _InternalState(self) + return '<%s module=%r>' % (type(self).__name__, state._module) def __setattr__(self, name, value): """ Set an attribute on the wrapped module object. """ - _module = object.__getattribute__(self, '_module') - setattr(_module, name, value) + state = _InternalState(self) + state._lastWasPath = False + setattr(state._module, name, value) def __getattribute__(self, name): """ - Get an attribute on the wrapped module object. + Get an attribute from the module object, possibly emitting a warning. - If the specified name has been deprecated then a warning is issued. + If the specified name has been deprecated, then a warning is issued. + (Unless certain obscure conditions are met; see + L{_ModuleProxy._lastWasPath} for more information about what might quash + such a warning.) """ - _module = object.__getattribute__(self, '_module') - _deprecatedAttributes = object.__getattribute__( - self, '_deprecatedAttributes') + state = _InternalState(self) + if state._lastWasPath: + deprecatedAttribute = None + else: + deprecatedAttribute = state._deprecatedAttributes.get(name) - getter = _deprecatedAttributes.get(name) - if getter is not None: - value = getter.get() + if deprecatedAttribute is not None: + # If we have a _DeprecatedAttribute object from the earlier lookup, + # allow it to issue the warning. + value = deprecatedAttribute.get() else: - value = getattr(_module, name) + # Otherwise, just retrieve the underlying value directly; it's not + # deprecated, there's no warning to issue. + value = getattr(state._module, name) + if name == '__path__': + state._lastWasPath = True + else: + state._lastWasPath = False return value diff --git a/lib/twisted-trunk/twisted/python/dist.py b/lib/twisted-trunk/twisted/python/dist.py --- a/lib/twisted-trunk/twisted/python/dist.py +++ b/lib/twisted-trunk/twisted/python/dist.py @@ -245,8 +245,9 @@ if not os.path.isdir(scriptdir): return [] thingies = os.listdir(scriptdir) - if '.svn' in thingies: - thingies.remove('.svn') + for specialExclusion in ['.svn', '_preamble.py', '_preamble.pyc']: + if specialExclusion in thingies: + thingies.remove(specialExclusion) return filter(os.path.isfile, [os.path.join(scriptdir, x) for x in thingies]) diff --git a/lib/twisted-trunk/twisted/python/failure.py b/lib/twisted-trunk/twisted/python/failure.py --- a/lib/twisted-trunk/twisted/python/failure.py +++ b/lib/twisted-trunk/twisted/python/failure.py @@ -36,12 +36,18 @@ @type frames: list @param write: this will be called with formatted strings. @type write: callable - @param detail: Three detail levels are available: - default, brief, and verbose. + @param detail: Four detail levels are available: + default, brief, verbose, and verbose-vars-not-captured. + C{Failure.printDetailedTraceback} uses the latter when the caller asks + for verbose, but no vars were captured, so that an explicit warning + about the missing data is shown. @type detail: string """ - if detail not in ('default', 'brief', 'verbose'): - raise ValueError, "Detail must be default, brief, or verbose. (not %r)" % (detail,) + if detail not in ('default', 'brief', 'verbose', + 'verbose-vars-not-captured'): + raise ValueError( + "Detail must be default, brief, verbose, or " + "verbose-vars-not-captured. (not %r)" % (detail,)) w = write if detail == "brief": for method, filename, lineno, localVars, globalVars in frames: @@ -50,6 +56,10 @@ for method, filename, lineno, localVars, globalVars in frames: w( ' File "%s", line %s, in %s\n' % (filename, lineno, method)) w( ' %s\n' % linecache.getline(filename, lineno).strip()) + elif detail == "verbose-vars-not-captured": + for method, filename, lineno, localVars, globalVars in frames: + w("%s:%d: %s(...)\n" % (filename, lineno, method)) + w(' [Capture of Locals and Globals disabled (use captureVars=True)]\n') elif detail == "verbose": for method, filename, lineno, localVars, globalVars in frames: w("%s:%d: %s(...)\n" % (filename, lineno, method)) @@ -137,8 +147,16 @@ This is necessary because Python's built-in error mechanisms are inconvenient for asynchronous communication. + The C{stack} and C{frame} attributes contain frames. Each frame is a tuple + of (funcName, fileName, lineNumber, localsItems, globalsItems), where + localsItems and globalsItems are the contents of + C{locals().items()}/C{globals().items()} for that frame, or an empty tuple + if those details were not captured. + @ivar value: The exception instance responsible for this failure. @ivar type: The exception's class. + @ivar stack: list of frames, innermost last, excluding C{Failure.__init__}. + @ivar frames: list of frames, innermost first. """ pickled = 0 @@ -149,7 +167,8 @@ # throwExceptionIntoGenerator. _yieldOpcode = chr(opcode.opmap["YIELD_VALUE"]) - def __init__(self, exc_value=None, exc_type=None, exc_tb=None): + def __init__(self, exc_value=None, exc_type=None, exc_tb=None, + captureVars=False): """ Initialize me with an explanation of the error. @@ -168,11 +187,16 @@ If C{None} is supplied for C{exc_value}, the value of C{exc_tb} is ignored, otherwise if C{exc_tb} is C{None}, it will be found from execution context (ie, L{sys.exc_info}). + + @param captureVars: if set, capture locals and globals of stack + frames. This is pretty slow, and makes no difference unless you + are going to use L{printDetailedTraceback}. """ global count count = count + 1 self.count = count self.type = self.value = tb = None + self.captureVars = captureVars #strings Exceptions/Failures are bad, mmkay? if isinstance(exc_value, (str, unicode)) and exc_type is None: @@ -244,46 +268,54 @@ # what called upon the PB object. while f: - localz = f.f_locals.copy() - if f.f_locals is f.f_globals: - globalz = {} + if captureVars: + localz = f.f_locals.copy() + if f.f_locals is f.f_globals: + globalz = {} + else: + globalz = f.f_globals.copy() + for d in globalz, localz: + if "__builtins__" in d: + del d["__builtins__"] + localz = localz.items() + globalz = globalz.items() else: - globalz = f.f_globals.copy() - for d in globalz, localz: - if d.has_key("__builtins__"): - del d["__builtins__"] - stack.insert(0, [ + localz = globalz = () + stack.insert(0, ( f.f_code.co_name, f.f_code.co_filename, f.f_lineno, - localz.items(), - globalz.items(), - ]) + localz, + globalz, + )) f = f.f_back while tb is not None: f = tb.tb_frame - localz = f.f_locals.copy() - if f.f_locals is f.f_globals: - globalz = {} + if captureVars: + localz = f.f_locals.copy() + if f.f_locals is f.f_globals: + globalz = {} + else: + globalz = f.f_globals.copy() + for d in globalz, localz: + if "__builtins__" in d: + del d["__builtins__"] + localz = localz.items() + globalz = globalz.items() else: - globalz = f.f_globals.copy() - for d in globalz, localz: - if d.has_key("__builtins__"): - del d["__builtins__"] - - frames.append([ + localz = globalz = () + frames.append(( f.f_code.co_name, f.f_code.co_filename, tb.tb_lineno, - localz.items(), - globalz.items(), - ]) + localz, + globalz, + )) tb = tb.tb_next if inspect.isclass(self.type) and issubclass(self.type, Exception): parentCs = getmro(self.type) self.parents = map(reflect.qual, parentCs) - self.parents.append(reflect.qual(self.type)) else: self.parents = [self.type] @@ -424,8 +456,8 @@ c['frames'] = [ [ v[0], v[1], v[2], - [(j[0], reflect.safe_repr(j[1])) for j in v[3]], - [(j[0], reflect.safe_repr(j[1])) for j in v[4]] + _safeReprVars(v[3]), + _safeReprVars(v[4]), ] for v in self.frames ] @@ -438,8 +470,8 @@ c['stack'] = [ [ v[0], v[1], v[2], - [(j[0], reflect.safe_repr(j[1])) for j in v[3]], - [(j[0], reflect.safe_repr(j[1])) for j in v[4]] + _safeReprVars(v[3]), + _safeReprVars(v[4]), ] for v in self.stack ] @@ -504,6 +536,14 @@ file = log.logerr w = file.write + if detail == 'verbose' and not self.captureVars: + # We don't have any locals or globals, so rather than show them as + # empty make the output explicitly say that we don't have them at + # all. + formatDetail = 'verbose-vars-not-captured' + else: + formatDetail = detail + # Preamble if detail == 'verbose': w( '*--- Failure #%d%s---\n' % @@ -524,9 +564,9 @@ # Frames, formatted in appropriate style if self.frames: if not elideFrameworkCode: - format_frames(self.stack[-traceupLength:], w, detail) + format_frames(self.stack[-traceupLength:], w, formatDetail) w("%s\n" % (EXCEPTION_CAUGHT_HERE,)) - format_frames(self.frames, w, detail) + format_frames(self.frames, w, formatDetail) elif not detail == 'brief': # Yeah, it's not really a traceback, despite looking like one... w("Failure: ") @@ -562,12 +602,28 @@ """ self.printTraceback(file, elideFrameworkCode, detail='verbose') + +def _safeReprVars(varsDictItems): + """ + Convert a list of (name, object) pairs into (name, repr) pairs. + + L{twisted.python.reflect.safe_repr} is used to generate the repr, so no + exceptions will be raised by faulty C{__repr__} methods. + + @param varsDictItems: a sequence of (name, value) pairs as returned by e.g. + C{locals().items()}. + @returns: a sequence of (name, repr) pairs. + """ + return [(name, reflect.safe_repr(obj)) for (name, obj) in varsDictItems] + + # slyphon: make post-morteming exceptions tweakable DO_POST_MORTEM = True def _debuginit(self, exc_value=None, exc_type=None, exc_tb=None, - Failure__init__=Failure.__init__.im_func): + captureVars=False, + Failure__init__=Failure.__init__.im_func): """ Initialize failure object, possibly spawning pdb. """ @@ -581,7 +637,8 @@ print "Jumping into debugger for post-mortem of exception '%s':" % (strrepr,) import pdb pdb.post_mortem(exc[2]) - Failure__init__(self, exc_value, exc_type, exc_tb) + Failure__init__(self, exc_value, exc_type, exc_tb, captureVars) + def startDebugMode(): """Enable debug hooks for Failures.""" diff --git a/lib/twisted-trunk/twisted/python/filepath.py b/lib/twisted-trunk/twisted/python/filepath.py --- a/lib/twisted-trunk/twisted/python/filepath.py +++ b/lib/twisted-trunk/twisted/python/filepath.py @@ -17,7 +17,11 @@ from os import sep as slash from os import listdir, utime, stat -from stat import S_ISREG, S_ISDIR +from stat import S_ISREG, S_ISDIR, S_IMODE, S_ISBLK, S_ISSOCK +from stat import S_IRUSR, S_IWUSR, S_IXUSR +from stat import S_IRGRP, S_IWGRP, S_IXGRP +from stat import S_IROTH, S_IWOTH, S_IXOTH + # Please keep this as light as possible on other Twisted imports; many, many # things import this module, and it would be good if it could easily be @@ -30,6 +34,8 @@ from twisted.python.win32 import ERROR_INVALID_NAME, ERROR_DIRECTORY, O_BINARY from twisted.python.win32 import WindowsError +from twisted.python.util import FancyEqMixin + _CREATE_FLAGS = (os.O_EXCL | os.O_CREAT | os.O_RDWR | @@ -338,6 +344,95 @@ +class RWX(FancyEqMixin, object): + """ + A class representing read/write/execute permissions for a single user + category (i.e. user/owner, group, or other/world). Instantiate with + three boolean values: readable? writable? executable?. + + @type read: C{bool} + @ivar read: Whether permission to read is given + + @type write: C{bool} + @ivar write: Whether permission to write is given + + @type execute: C{bool} + @ivar execute: Whether permission to execute is given + + @since: 11.1 + """ + compareAttributes = ('read', 'write', 'execute') + def __init__(self, readable, writable, executable): + self.read = readable + self.write = writable + self.execute = executable + + + def __repr__(self): + return "RWX(read=%s, write=%s, execute=%s)" % ( + self.read, self.write, self.execute) + + + def shorthand(self): + """ + Returns a short string representing the permission bits. Looks like + part of what is printed by command line utilities such as 'ls -l' + (e.g. 'rwx') + """ + returnval = ['r', 'w', 'x'] + i = 0 + for val in (self.read, self.write, self.execute): + if not val: + returnval[i] = '-' + i += 1 + return ''.join(returnval) + + + +class Permissions(FancyEqMixin, object): + """ + A class representing read/write/execute permissions. Instantiate with any + portion of the file's mode that includes the permission bits. + + @type user: L{RWX} + @ivar user: User/Owner permissions + + @type group: L{RWX} + @ivar group: Group permissions + + @type other: L{RWX} + @ivar other: Other/World permissions + + @since: 11.1 + """ + + compareAttributes = ('user', 'group', 'other') + + def __init__(self, statModeInt): + self.user, self.group, self.other = ( + [RWX(*[statModeInt & bit > 0 for bit in bitGroup]) for bitGroup in + [[S_IRUSR, S_IWUSR, S_IXUSR], + [S_IRGRP, S_IWGRP, S_IXGRP], + [S_IROTH, S_IWOTH, S_IXOTH]]] + ) + + + def __repr__(self): + return "[%s | %s | %s]" % ( + str(self.user), str(self.group), str(self.other)) + + + def shorthand(self): + """ + Returns a short string representing the permission bits. Looks like + what is printed by command line utilities such as 'ls -l' + (e.g. 'rwx-wx--x') + """ + return "".join( + [x.shorthand() for x in (self.user, self.group, self.other)]) + + + class FilePath(_PathHelper): """ I am a path on the filesystem that only permits 'downwards' access. @@ -746,6 +841,22 @@ return int(st.st_gid) + def getPermissions(self): + """ + Returns the permissions of the file. Should also work on Windows, + however, those permissions may not what is expected in Windows. + + @return: the permissions for the file + @rtype: L{Permissions} + @since: 11.1 + """ + st = self.statinfo + if not st: + self.restat() + st = self.statinfo + return Permissions(S_IMODE(st.st_mode)) + + def exists(self): """ Check if this L{FilePath} exists. @@ -792,6 +903,40 @@ return S_ISREG(st.st_mode) + def isBlockDevice(self): + """ + Returns whether the underlying path is a block device. + + @return: C{True} if it is a block device, C{False} otherwise + @rtype: C{bool} + @since: 11.1 + """ + st = self.statinfo + if not st: + self.restat(False) + st = self.statinfo + if not st: + return False + return S_ISBLK(st.st_mode) + + + def isSocket(self): + """ + Returns whether the underlying path is a socket. + + @return: C{True} if it is a socket, C{False} otherwise + @rtype: C{bool} + @since: 11.1 + """ + st = self.statinfo + if not st: + self.restat(False) + st = self.statinfo + if not st: + return False + return S_ISSOCK(st.st_mode) + + def islink(self): """ @return: C{True} if this L{FilePath} points to a symbolic link. diff --git a/lib/twisted-trunk/twisted/python/log.py b/lib/twisted-trunk/twisted/python/log.py --- a/lib/twisted-trunk/twisted/python/log.py +++ b/lib/twisted-trunk/twisted/python/log.py @@ -290,8 +290,14 @@ except: observer = self.observers[i] self.observers[i] = lambda event: None - err(failure.Failure(), - "Log observer %s failed." % (observer,)) + try: + err(failure.Failure(), + "Log observer %s failed." % (observer,)) + except: + # Sometimes err() will throw an exception, + # e.g. RuntimeError due to blowing the stack; if that + # happens, there's not much we can do... + pass self.observers[i] = observer @@ -522,7 +528,13 @@ class StdioOnnaStick: """ - Class that pretends to be stout/err. + Class that pretends to be stdout/err, and turns writes into log messages. + + @ivar isError: boolean indicating whether this is stderr, in which cases + log messages will be logged as errors. + + @ivar encoding: unicode encoding used to encode any unicode strings + written to this object. """ closed = 0 @@ -530,8 +542,11 @@ mode = 'wb' name = '' - def __init__(self, isError=0): + def __init__(self, isError=0, encoding=None): self.isError = isError + if encoding is None: + encoding = sys.getdefaultencoding() + self.encoding = encoding self.buf = '' def close(self): @@ -552,6 +567,8 @@ tell = read def write(self, data): + if isinstance(data, unicode): + data = data.encode(self.encoding) d = (self.buf + data).split('\n') self.buf = d[-1] messages = d[0:-1] @@ -560,6 +577,8 @@ def writelines(self, lines): for line in lines: + if isinstance(line, unicode): + line = line.encode(self.encoding) msg(line, printed=1, isError=self.isError) @@ -623,8 +642,9 @@ try: logfile except NameError: - logfile = StdioOnnaStick(0) - logerr = StdioOnnaStick(1) + logfile = StdioOnnaStick(0, getattr(sys.stdout, "encoding", None)) + logerr = StdioOnnaStick(1, getattr(sys.stderr, "encoding", None)) + class DefaultObserver: diff --git a/lib/twisted-trunk/twisted/python/modules.py b/lib/twisted-trunk/twisted/python/modules.py --- a/lib/twisted-trunk/twisted/python/modules.py +++ b/lib/twisted-trunk/twisted/python/modules.py @@ -158,7 +158,7 @@ modname = self._subModuleName(potentialTopLevel.basename()) for ext in PYTHON_EXTENSIONS: initpy = potentialTopLevel.child("__init__"+ext) - if initpy.exists(): + if initpy.exists() and modname not in yielded: yielded[modname] = True pm = PythonModule(modname, initpy, self._getEntry()) assert pm != self diff --git a/lib/twisted-trunk/twisted/python/runtime.py b/lib/twisted-trunk/twisted/python/runtime.py --- a/lib/twisted-trunk/twisted/python/runtime.py +++ b/lib/twisted-trunk/twisted/python/runtime.py @@ -35,11 +35,15 @@ type = knownPlatforms.get(os.name) seconds = staticmethod(_timeFunctions.get(type, time.time)) + _platform = sys.platform - def __init__(self, name=None): + def __init__(self, name=None, platform=None): if name is not None: self.type = knownPlatforms.get(name) self.seconds = _timeFunctions.get(self.type, time.time) + if platform is not None: + self._platform = platform + def isKnown(self): """Do we know about this platform?""" @@ -50,8 +54,12 @@ return self.type def isMacOSX(self): - """Return if we are runnng on Mac OS X.""" - return sys.platform == "darwin" + """Check if current platform is Mac OS X. + + @return: C{True} if the current platform has been detected as OS X + @rtype: C{bool} + """ + return self._platform == "darwin" def isWinNT(self): """Are we running in Windows NT?""" diff --git a/lib/twisted-trunk/twisted/python/test/test_components.py b/lib/twisted-trunk/twisted/python/test/test_components.py --- a/lib/twisted-trunk/twisted/python/test/test_components.py +++ b/lib/twisted-trunk/twisted/python/test/test_components.py @@ -140,7 +140,7 @@ o = object() a = Adept(o) self.assertRaises(components.CannotAdapt, ITest, a) - self.assertEquals(ITest(a, None), None) + self.assertEqual(ITest(a, None), None) @@ -220,13 +220,13 @@ def testBasic(self): n = MetaNumber(1) - self.assertEquals(IMeta(n).add(1), 2) + self.assertEqual(IMeta(n).add(1), 2) def testComponentizedInteraction(self): c = ComponentNumber() IMeta(c).add(1) IMeta(c).add(1) - self.assertEquals(IMeta(c).add(1), 3) + self.assertEqual(IMeta(c).add(1), 3) def testAdapterWithCmp(self): # Make sure that a __cmp__ on an adapter doesn't break anything @@ -554,8 +554,8 @@ yayable = Yayable() proxy = klass(yayable) proxy.yay() - self.assertEquals(proxy.yay(), 2) - self.assertEquals(yayable.yays, 2) + self.assertEqual(proxy.yay(), 2) + self.assertEqual(yayable.yays, 2) def test_proxyAttribute(self): @@ -601,8 +601,8 @@ """ multi = MultipleMethodImplementor() proxy = proxyForInterface(IMultipleMethods)(multi) - self.assertEquals(proxy.methodOne(), 1) - self.assertEquals(proxy.methodTwo(), 2) + self.assertEqual(proxy.methodOne(), 1) + self.assertEqual(proxy.methodTwo(), 2) def test_subclassing(self): @@ -622,9 +622,9 @@ yayable = Yayable() special = SpecializedProxy(yayable) - self.assertEquals(yayable.yays, 0) + self.assertEqual(yayable.yays, 0) special.boo() - self.assertEquals(yayable.yays, -1) + self.assertEqual(yayable.yays, -1) def test_proxyName(self): @@ -632,7 +632,7 @@ The name of a proxy class indicates which interface it proxies. """ proxy = proxyForInterface(IProxiedInterface) - self.assertEquals( + self.assertEqual( proxy.__name__, "(Proxy for " "twisted.python.test.test_components.IProxiedInterface)") @@ -670,7 +670,7 @@ testObject = Sample() fakeProxy.original = testObject pd = components._ProxyDescriptor("hello", "original") - self.assertEquals(pd.__get__(fakeProxy), testObject.hello) + self.assertEqual(pd.__get__(fakeProxy), testObject.hello) fakeClassMethod = pd.__get__(None) fakeClassMethod(fakeProxy) self.failUnless(testObject.called) @@ -698,8 +698,8 @@ yayable = Yayable() wrapper = EnhancedWrapper(yayable) - self.assertEquals(wrapper.yay(3, 4, x=5, y=6), 8) - self.assertEquals(yayable.yayArgs, + self.assertEqual(wrapper.yay(3, 4, x=5, y=6), 8) + self.assertEqual(yayable.yayArgs, [((3, 4), dict(x=5, y=6))]) @@ -731,7 +731,7 @@ self.assertIdentical(proxy.foo, yayable) # Check the behavior - self.assertEquals(proxy.yay(), 1) + self.assertEqual(proxy.yay(), 1) self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute) thingy = object() proxy.ifaceAttribute = thingy diff --git a/lib/twisted-trunk/twisted/python/test/test_deprecate.py b/lib/twisted-trunk/twisted/python/test/test_deprecate.py --- a/lib/twisted-trunk/twisted/python/test/test_deprecate.py +++ b/lib/twisted-trunk/twisted/python/test/test_deprecate.py @@ -22,6 +22,7 @@ from twisted.python.filepath import FilePath from twisted.python.test import deprecatedattributes +from twisted.python.test.modules_helpers import TwistedModulesTestCase @@ -65,7 +66,7 @@ """ version = Version('Twisted', 8, 0, 0) format = deprecate.DEPRECATION_WARNING_FORMAT + ': This is a message' - self.assertEquals( + self.assertEqual( getDeprecationWarningString(self.test_getDeprecationWarningString, version, format), 'twisted.python.test.test_deprecate.TestDeprecationWarnings.' @@ -182,7 +183,7 @@ """ version = Version('Twisted', 8, 0, 0) dummy = deprecated(version, "something.foobar")(dummyCallable) - self.assertEquals(dummy.__doc__, + self.assertEqual(dummy.__doc__, "\n" " Do nothing.\n\n" " This is used to test the deprecation decorators.\n\n" @@ -202,7 +203,7 @@ version = Version('Twisted', 8, 0, 0) decorator = deprecated(version, replacement=dummyReplacementMethod) dummy = decorator(dummyCallable) - self.assertEquals(dummy.__doc__, + self.assertEqual(dummy.__doc__, "\n" " Do nothing.\n\n" " This is used to test the deprecation decorators.\n\n" @@ -341,7 +342,7 @@ _deprecatedAttributes = object.__getattribute__( proxy, '_deprecatedAttributes') _deprecatedAttributes['foo'] = _MockDeprecatedAttribute(42) - self.assertEquals(proxy.foo, 42) + self.assertEqual(proxy.foo, 42) def test_privateAttributes(self): @@ -363,7 +364,7 @@ proxy = self._makeProxy() proxy._module = 1 self.assertNotEquals(object.__getattribute__(proxy, '_module'), 1) - self.assertEquals(proxy._module, 1) + self.assertEqual(proxy._module, 1) def test_repr(self): @@ -374,7 +375,7 @@ """ proxy = self._makeProxy() realModule = object.__getattribute__(proxy, '_module') - self.assertEquals( + self.assertEqual( repr(proxy), '<%s module=%r>' % (type(proxy).__name__, realModule)) @@ -412,7 +413,7 @@ attr = deprecate._DeprecatedAttribute( deprecatedattributes, name, self.version, self.message) - self.assertEquals(attr.__name__, name) + self.assertEqual(attr.__name__, name) # Since we're accessing the value getter directly, as opposed to via # the module proxy, we need to match the warning's stack level. @@ -424,10 +425,10 @@ warningsShown = self.flushWarnings([ self.test_deprecatedAttributeHelper]) self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual( warningsShown[0]['message'], self._getWarningString(name)) - self.assertEquals(len(warningsShown), 1) + self.assertEqual(len(warningsShown), 1) def test_deprecatedAttribute(self): @@ -440,7 +441,7 @@ # Accessing non-deprecated attributes does not issue a warning. deprecatedattributes.ANOTHER_ATTRIBUTE warningsShown = self.flushWarnings([self.test_deprecatedAttribute]) - self.assertEquals(len(warningsShown), 0) + self.assertEqual(len(warningsShown), 0) name = 'DEPRECATED_ATTRIBUTE' @@ -449,9 +450,9 @@ getattr(deprecatedattributes, name) warningsShown = self.flushWarnings([self.test_deprecatedAttribute]) - self.assertEquals(len(warningsShown), 1) + self.assertEqual(len(warningsShown), 1) self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual( warningsShown[0]['message'], self._getWarningString(name)) @@ -486,6 +487,14 @@ self.assertIdentical(proxy, sys.modules[self._testModuleName]) + + +class ImportedModuleAttributeTests(TwistedModulesTestCase): + """ + Tests for L{deprecatedModuleAttribute} which involve loading a module via + 'import'. + """ + _packageInit = """\ from twisted.python.deprecate import deprecatedModuleAttribute from twisted.python.versions import Version @@ -494,29 +503,97 @@ Version('Package', 1, 2, 3), 'message', __name__, 'module') """ + + def pathEntryTree(self, tree): + """ + Create some files in a hierarchy, based on a dictionary describing those + files. The resulting hierarchy will be placed onto sys.path for the + duration of the test. + + @param tree: A dictionary representing a directory structure. Keys are + strings, representing filenames, dictionary values represent + directories, string values represent file contents. + + @return: another dictionary similar to the input, with file content + strings replaced with L{FilePath} objects pointing at where those + contents are now stored. + """ + def makeSomeFiles(pathobj, dirdict): + pathdict = {} + for (key, value) in dirdict.items(): + child = pathobj.child(key) + if isinstance(value, str): + pathdict[key] = child + child.setContent(value) + elif isinstance(value, dict): + child.createDirectory() + pathdict[key] = makeSomeFiles(child, value) + else: + raise ValueError("only strings and dicts allowed as values") + return pathdict + base = FilePath(self.mktemp()) + base.makedirs() + + result = makeSomeFiles(base, tree) + self.replaceSysPath([base.path] + sys.path) + self.replaceSysModules(sys.modules.copy()) + return result + + + def simpleModuleEntry(self): + """ + Add a sample module and package to the path, returning a L{FilePath} + pointing at the module which will be loadable as C{package.module}. + """ + paths = self.pathEntryTree( + {"package": {"__init__.py": self._packageInit, + "module.py": ""}}) + return paths['package']['module.py'] + + + def checkOneWarning(self, modulePath): + """ + Verification logic for L{test_deprecatedModule}. + """ + # import package.module + from package import module + self.assertEqual(module.__file__, modulePath.path) + emitted = self.flushWarnings([self.checkOneWarning]) + self.assertEqual(len(emitted), 1) + self.assertEqual(emitted[0]['message'], + 'package.module was deprecated in Package 1.2.3: ' + 'message') + self.assertEqual(emitted[0]['category'], DeprecationWarning) + + def test_deprecatedModule(self): """ If L{deprecatedModuleAttribute} is used to deprecate a module attribute of a package, only one deprecation warning is emitted when the deprecated module is imported. """ - base = FilePath(self.mktemp()) - base.makedirs() - package = base.child('package') - package.makedirs() - package.child('__init__.py').setContent(self._packageInit) - module = package.child('module.py').setContent('') + self.checkOneWarning(self.simpleModuleEntry()) - sys.path.insert(0, base.path) - self.addCleanup(sys.path.remove, base.path) - # import package.module - from package import module - # make sure it's the right module. - self.assertEquals(module.__file__.rsplit(".", 1)[0], - package.child('module.py').path.rsplit(".", 1)[0]) - warningsShown = self.flushWarnings([self.test_deprecatedModule]) - self.assertEquals(len(warningsShown), 1) + def test_deprecatedModuleMultipleTimes(self): + """ + If L{deprecatedModuleAttribute} is used to deprecate a module attribute + of a package, only one deprecation warning is emitted when the + deprecated module is subsequently imported. + """ + mp = self.simpleModuleEntry() + # The first time, the code needs to be loaded. + self.checkOneWarning(mp) + # The second time, things are slightly different; the object's already + # in the namespace. + self.checkOneWarning(mp) + # The third and fourth times, things things should all be exactly the + # same, but this is a sanity check to make sure the implementation isn't + # special casing the second time. Also, putting these cases into a loop + # means that the stack will be identical, to make sure that the + # implementation doesn't rely too much on stack-crawling. + for x in range(2): + self.checkOneWarning(mp) @@ -570,7 +647,7 @@ filename = filename[:-1] self.assertSamePath( FilePath(warningsShown[0]["filename"]), FilePath(filename)) - self.assertEquals(warningsShown[0]["message"], "A Warning Message") + self.assertEqual(warningsShown[0]["message"], "A Warning Message") def test_warningLineNumber(self): @@ -586,9 +663,9 @@ self.package.sibling('twisted_private_helper').child('module.py')) # Line number 9 is the last line in the testFunction in the helper # module. - self.assertEquals(warningsShown[0]["lineno"], 9) - self.assertEquals(warningsShown[0]["message"], "A Warning String") - self.assertEquals(len(warningsShown), 1) + self.assertEqual(warningsShown[0]["lineno"], 9) + self.assertEqual(warningsShown[0]["message"], "A Warning String") + self.assertEqual(len(warningsShown), 1) def assertSamePath(self, first, second): @@ -633,9 +710,9 @@ expectedPath = self.package.sibling( 'twisted_renamed_helper').child('module.py') self.assertSamePath(warnedPath, expectedPath) - self.assertEquals(warningsShown[0]["lineno"], 9) - self.assertEquals(warningsShown[0]["message"], "A Warning String") - self.assertEquals(len(warningsShown), 1) + self.assertEqual(warningsShown[0]["lineno"], 9) + self.assertEqual(warningsShown[0]["message"], "A Warning String") + self.assertEqual(len(warningsShown), 1) def test_filteredWarning(self): @@ -656,7 +733,7 @@ module.callTestFunction() warningsShown = self.flushWarnings() - self.assertEquals(len(warningsShown), 0) + self.assertEqual(len(warningsShown), 0) def test_filteredOnceWarning(self): @@ -678,7 +755,7 @@ module.callTestFunction() warningsShown = self.flushWarnings() - self.assertEquals(len(warningsShown), 1) + self.assertEqual(len(warningsShown), 1) message = warningsShown[0]['message'] category = warningsShown[0]['category'] filename = warningsShown[0]['filename'] diff --git a/lib/twisted-trunk/twisted/python/test/test_dist.py b/lib/twisted-trunk/twisted/python/test/test_dist.py --- a/lib/twisted-trunk/twisted/python/test/test_dist.py +++ b/lib/twisted-trunk/twisted/python/test/test_dist.py @@ -25,7 +25,7 @@ """ Passing C{conditionalExtensions} as a list of L{ConditionalExtension} objects to get_setup_args inserts a custom build_ext into the result - which knows how to check whether they should be + which knows how to check whether they should be built. """ good_ext = ConditionalExtension("whatever", ["whatever.c"], condition=lambda b: True) @@ -34,12 +34,12 @@ args = get_setup_args(conditionalExtensions=[good_ext, bad_ext]) # ext_modules should be set even though it's not used. See comment # in get_setup_args - self.assertEquals(args["ext_modules"], [good_ext, bad_ext]) + self.assertEqual(args["ext_modules"], [good_ext, bad_ext]) cmdclass = args["cmdclass"] build_ext = cmdclass["build_ext"] builder = build_ext(Distribution()) builder.prepare_extensions() - self.assertEquals(builder.extensions, [good_ext]) + self.assertEqual(builder.extensions, [good_ext]) def test_win32Definition(self): @@ -52,7 +52,7 @@ builder = args["cmdclass"]["build_ext"](Distribution()) self.patch(os, "name", "nt") builder.prepare_extensions() - self.assertEquals(ext.define_macros, [("whatever", 2), ("WIN32", 1)]) + self.assertEqual(ext.define_macros, [("whatever", 2), ("WIN32", 1)]) @@ -76,7 +76,7 @@ version = versions.Version("twisted", 0, 1, 2) """) f.close() - self.assertEquals(dist.getVersion("core", base=self.dirname), "0.1.2") + self.assertEqual(dist.getVersion("core", base=self.dirname), "0.1.2") def test_getVersionOther(self): """ @@ -90,10 +90,14 @@ version = versions.Version("twisted.blat", 9, 8, 10) """) f.close() - self.assertEquals(dist.getVersion("blat", base=self.dirname), "9.8.10") + self.assertEqual(dist.getVersion("blat", base=self.dirname), "9.8.10") class GetScriptsTest(TestCase): + """ + Tests for L{dist.getScripts} which returns the scripts which should be + included in the distribution of a project. + """ def test_scriptsInSVN(self): """ @@ -108,8 +112,23 @@ f.write('yay') f.close() scripts = dist.getScripts('proj', basedir=basedir) - self.assertEquals(len(scripts), 1) - self.assertEquals(os.path.basename(scripts[0]), 'exy') + self.assertEqual(len(scripts), 1) + self.assertEqual(os.path.basename(scripts[0]), 'exy') + + + def test_excludedPreamble(self): + """ + L{dist.getScripts} includes neither C{"_preamble.py"} nor + C{"_preamble.pyc"}. + """ + basedir = FilePath(self.mktemp()) + bin = basedir.child('bin') + bin.makedirs() + bin.child('_preamble.py').setContent('some preamble code\n') + bin.child('_preamble.pyc').setContent('some preamble byte code\n') + bin.child('program').setContent('good program code\n') + scripts = dist.getScripts("", basedir=basedir.path) + self.assertEqual(scripts, [bin.child('program').path]) def test_scriptsInRelease(self): @@ -124,8 +143,8 @@ f.write('yay') f.close() scripts = dist.getScripts('proj', basedir=basedir) - self.assertEquals(len(scripts), 1) - self.assertEquals(os.path.basename(scripts[0]), 'exy') + self.assertEqual(len(scripts), 1) + self.assertEqual(os.path.basename(scripts[0]), 'exy') def test_noScriptsInSVN(self): @@ -139,7 +158,7 @@ os.mkdir(os.path.join(basedir, 'bin')) os.mkdir(os.path.join(basedir, 'bin', 'otherproj')) scripts = dist.getScripts('noscripts', basedir=basedir) - self.assertEquals(scripts, []) + self.assertEqual(scripts, []) def test_getScriptsTopLevel(self): @@ -158,7 +177,7 @@ subdir.child("not-included").setContent("not included") scripts = dist.getScripts("", basedir=basedir.path) - self.assertEquals(scripts, [included.path]) + self.assertEqual(scripts, [included.path]) def test_noScriptsInSubproject(self): @@ -170,4 +189,4 @@ basedir = self.mktemp() os.mkdir(basedir) scripts = dist.getScripts('noscripts', basedir=basedir) - self.assertEquals(scripts, []) + self.assertEqual(scripts, []) diff --git a/lib/twisted-trunk/twisted/python/test/test_fakepwd.py b/lib/twisted-trunk/twisted/python/test/test_fakepwd.py --- a/lib/twisted-trunk/twisted/python/test/test_fakepwd.py +++ b/lib/twisted-trunk/twisted/python/test/test_fakepwd.py @@ -37,13 +37,13 @@ # Now try to look it up and make sure the result is correct. entry = self.database.getpwuid(uid) - self.assertEquals(entry.pw_name, username) - self.assertEquals(entry.pw_passwd, password) - self.assertEquals(entry.pw_uid, uid) - self.assertEquals(entry.pw_gid, gid) - self.assertEquals(entry.pw_gecos, gecos) - self.assertEquals(entry.pw_dir, dir) - self.assertEquals(entry.pw_shell, shell) + self.assertEqual(entry.pw_name, username) + self.assertEqual(entry.pw_passwd, password) + self.assertEqual(entry.pw_uid, uid) + self.assertEqual(entry.pw_gid, gid) + self.assertEqual(entry.pw_gecos, gecos) + self.assertEqual(entry.pw_dir, dir) + self.assertEqual(entry.pw_shell, shell) def test_noSuchUID(self): @@ -65,13 +65,13 @@ # Now try to look it up and make sure the result is correct. entry = self.database.getpwnam(username) - self.assertEquals(entry.pw_name, username) - self.assertEquals(entry.pw_passwd, password) - self.assertEquals(entry.pw_uid, uid) - self.assertEquals(entry.pw_gid, gid) - self.assertEquals(entry.pw_gecos, gecos) - self.assertEquals(entry.pw_dir, dir) - self.assertEquals(entry.pw_shell, shell) + self.assertEqual(entry.pw_name, username) + self.assertEqual(entry.pw_passwd, password) + self.assertEqual(entry.pw_uid, uid) + self.assertEqual(entry.pw_gid, gid) + self.assertEqual(entry.pw_gecos, gecos) + self.assertEqual(entry.pw_dir, dir) + self.assertEqual(entry.pw_shell, shell) def test_noSuchName(self): @@ -106,15 +106,15 @@ db = self.database username, password, uid, gid, gecos, dir, shell = self.getExistingUserInfo() for entry in [db.getpwuid(uid), db.getpwnam(username), db.getpwall()[0]]: - self.assertEquals(entry[0], username) - self.assertEquals(entry[1], password) - self.assertEquals(entry[2], uid) - self.assertEquals(entry[3], gid) - self.assertEquals(entry[4], gecos) - self.assertEquals(entry[5], dir) - self.assertEquals(entry[6], shell) + self.assertEqual(entry[0], username) + self.assertEqual(entry[1], password) + self.assertEqual(entry[2], uid) + self.assertEqual(entry[3], gid) + self.assertEqual(entry[4], gecos) + self.assertEqual(entry[5], dir) + self.assertEqual(entry[6], shell) - self.assertEquals(len(entry), len(list(entry))) + self.assertEqual(len(entry), len(list(entry))) self.assertRaises(IndexError, getitem, entry, 7) @@ -168,22 +168,22 @@ db.addUser(username, password, uid, gid, gecos, home, shell) for entry in [db.getpwuid(uid), db.getpwnam(username)]: - self.assertEquals(entry.pw_name, username) - self.assertEquals(entry.pw_passwd, password) - self.assertEquals(entry.pw_uid, uid) - self.assertEquals(entry.pw_gid, gid) - self.assertEquals(entry.pw_gecos, gecos) - self.assertEquals(entry.pw_dir, home) - self.assertEquals(entry.pw_shell, shell) + self.assertEqual(entry.pw_name, username) + self.assertEqual(entry.pw_passwd, password) + self.assertEqual(entry.pw_uid, uid) + self.assertEqual(entry.pw_gid, gid) + self.assertEqual(entry.pw_gecos, gecos) + self.assertEqual(entry.pw_dir, home) + self.assertEqual(entry.pw_shell, shell) [entry] = db.getpwall() - self.assertEquals(entry.pw_name, username) - self.assertEquals(entry.pw_passwd, password) - self.assertEquals(entry.pw_uid, uid) - self.assertEquals(entry.pw_gid, gid) - self.assertEquals(entry.pw_gecos, gecos) - self.assertEquals(entry.pw_dir, home) - self.assertEquals(entry.pw_shell, shell) + self.assertEqual(entry.pw_name, username) + self.assertEqual(entry.pw_passwd, password) + self.assertEqual(entry.pw_uid, uid) + self.assertEqual(entry.pw_gid, gid) + self.assertEqual(entry.pw_gecos, gecos) + self.assertEqual(entry.pw_dir, home) + self.assertEqual(entry.pw_shell, shell) diff --git a/lib/twisted-trunk/twisted/python/test/test_inotify.py b/lib/twisted-trunk/twisted/python/test/test_inotify.py --- a/lib/twisted-trunk/twisted/python/test/test_inotify.py +++ b/lib/twisted-trunk/twisted/python/test/test_inotify.py @@ -9,7 +9,7 @@ from twisted.python.runtime import platform if platform.supportsINotify(): - from ctypes import c_int, c_char_p + from ctypes import c_int, c_uint32, c_char_p from twisted.python import _inotify from twisted.python._inotify import ( INotifyError, initializeModule, init, add) @@ -64,25 +64,36 @@ self.assertRaises(ImportError, initializeModule, libc()) - def test_setAddArgtypes(self): + def test_setTypes(self): """ - If the I{libc} object passed to L{initializeModule} has all - of the necessary attributes, it sets the C{argtypes} attribute - of the C{inotify_add_watch} attribute to a list describing the - argument types. + If the I{libc} object passed to L{initializeModule} has all of the + necessary attributes, it sets the C{argtypes} and C{restype} attributes + of the three ctypes methods used from libc. """ class libc: def inotify_init(self): pass + inotify_init = staticmethod(inotify_init) + def inotify_rm_watch(self): pass + inotify_rm_watch = staticmethod(inotify_rm_watch) + def inotify_add_watch(self): pass inotify_add_watch = staticmethod(inotify_add_watch) + c = libc() initializeModule(c) - self.assertEquals( - c.inotify_add_watch.argtypes, [c_int, c_char_p, c_int]) + self.assertEqual(c.inotify_init.argtypes, []) + self.assertEqual(c.inotify_init.restype, c_int) + + self.assertEqual(c.inotify_rm_watch.argtypes, [c_int, c_int]) + self.assertEqual(c.inotify_rm_watch.restype, c_int) + + self.assertEqual( + c.inotify_add_watch.argtypes, [c_int, c_char_p, c_uint32]) + self.assertEqual(c.inotify_add_watch.restype, c_int) def test_failedInit(self): diff --git a/lib/twisted-trunk/twisted/python/test/test_release.py b/lib/twisted-trunk/twisted/python/test/test_release.py --- a/lib/twisted-trunk/twisted/python/test/test_release.py +++ b/lib/twisted-trunk/twisted/python/test/test_release.py @@ -145,7 +145,7 @@ self.assertStructure(child, dirDict[x]) else: a = child.getContent().replace(os.linesep, '\n') - self.assertEquals(a, dirDict[x], child.path) + self.assertEqual(a, dirDict[x], child.path) children.remove(x) if children: self.fail("There were extra children in %s: %s" @@ -203,7 +203,7 @@ now = date.today() major = now.year - VERSION_OFFSET version = Version("twisted", major, 9, 0) - self.assertEquals(getNextVersion(version, now=now), + self.assertEqual(getNextVersion(version, now=now), Version("twisted", major, 10, 0)) @@ -215,7 +215,7 @@ now = date.today() major = now.year - VERSION_OFFSET version = Version("twisted", major - 1, 9, 0) - self.assertEquals(getNextVersion(version, now=now), + self.assertEqual(getNextVersion(version, now=now), Version("twisted", major, 0, 0)) @@ -396,7 +396,7 @@ """ version = Version('foo', 2, 1, 0) project = self.makeProject(version) - self.assertEquals(project.getVersion(), version) + self.assertEqual(project.getVersion(), version) def test_updateVersion(self): @@ -407,8 +407,8 @@ project = self.makeProject(Version("bar", 2, 1, 0)) newVersion = Version("bar", 3, 2, 9) project.updateVersion(newVersion) - self.assertEquals(project.getVersion(), newVersion) - self.assertEquals( + self.assertEqual(project.getVersion(), newVersion) + self.assertEqual( project.directory.child("topfiles").child("README").getContent(), "3.2.9") @@ -479,7 +479,7 @@ 1/0 self.assertRaises(ZeroDivisionError, release.runChdirSafe, chAndBreak) - self.assertEquals(cwd, os.getcwd()) + self.assertEqual(cwd, os.getcwd()) @@ -496,12 +496,12 @@ expected = in_.replace('$VER', '2.0.0') replaceInFile('release.replace', {'$VER': '2.0.0'}) - self.assertEquals(open('release.replace').read(), expected) + self.assertEqual(open('release.replace').read(), expected) expected = expected.replace('2.0.0', '3.0.0') replaceInFile('release.replace', {'2.0.0': '3.0.0'}) - self.assertEquals(open('release.replace').read(), expected) + self.assertEqual(open('release.replace').read(), expected) @@ -520,7 +520,7 @@ Version("twisted.test_project", 0, 82, 7)) ns = {'__name___': 'twisted.test_project'} execfile("test_project", ns) - self.assertEquals(ns["version"].base(), "0.82.7") + self.assertEqual(ns["version"].base(), "0.82.7") def test_replaceProjectVersionWithPrerelease(self): @@ -533,7 +533,7 @@ prerelease=8)) ns = {'__name___': 'twisted.test_project'} execfile("test_project", ns) - self.assertEquals(ns["version"].base(), "0.82.7pre8") + self.assertEqual(ns["version"].base(), "0.82.7pre8") @@ -877,7 +877,7 @@ """ linkrel = self.builder.getLinkrel(FilePath("/foo/bar"), FilePath("/foo/bar")) - self.assertEquals(linkrel, "") + self.assertEqual(linkrel, "") def test_getLinkrelToParentDirectory(self): @@ -887,7 +887,7 @@ """ linkrel = self.builder.getLinkrel(FilePath("/foo"), FilePath("/foo/bar")) - self.assertEquals(linkrel, "../") + self.assertEqual(linkrel, "../") def test_getLinkrelToSibling(self): @@ -897,7 +897,7 @@ """ linkrel = self.builder.getLinkrel(FilePath("/foo/howto"), FilePath("/foo/examples")) - self.assertEquals(linkrel, "../howto/") + self.assertEqual(linkrel, "../howto/") def test_getLinkrelToUncle(self): @@ -908,7 +908,7 @@ """ linkrel = self.builder.getLinkrel(FilePath("/foo/howto"), FilePath("/foo/examples/quotes")) - self.assertEquals(linkrel, "../../howto/") + self.assertEqual(linkrel, "../../howto/") @@ -1047,7 +1047,7 @@ calls = [] script.buildAPIDocs = lambda a, b: calls.append((a, b)) script.main(["hello", "there"]) - self.assertEquals(calls, [(FilePath("hello"), FilePath("there"))]) + self.assertEqual(calls, [(FilePath("hello"), FilePath("there"))]) @@ -1091,7 +1091,7 @@ expected = self.getArbitraryManLoreOutput() # No-op on *nix, fix for windows expected = expected.replace('\n', os.linesep) - self.assertEquals(output, expected) + self.assertEqual(output, expected) def test_toHTML(self): @@ -1183,7 +1183,7 @@ successfully. """ builder = BookBuilder() - self.assertEquals( + self.assertEqual( builder.run([ sys.executable, '-c', 'import sys; ' @@ -1203,9 +1203,9 @@ exc = self.assertRaises( CommandFailed, builder.run, [sys.executable, '-c', 'print "hi"; raise SystemExit(1)']) - self.assertEquals(exc.exitStatus, 1) - self.assertEquals(exc.exitSignal, None) - self.assertEquals(exc.output, "hi\n") + self.assertEqual(exc.exitStatus, 1) + self.assertEqual(exc.exitSignal, None) + self.assertEqual(exc.output, "hi\n") def test_runSignaled(self): @@ -1219,9 +1219,9 @@ [sys.executable, '-c', 'import sys; print "hi"; sys.stdout.flush(); ' 'import os; os.kill(os.getpid(), 9)']) - self.assertEquals(exc.exitSignal, 9) - self.assertEquals(exc.exitStatus, None) - self.assertEquals(exc.output, "hi\n") + self.assertEqual(exc.exitSignal, 9) + self.assertEqual(exc.exitStatus, None) + self.assertEqual(exc.output, "hi\n") def test_buildTeX(self): @@ -1378,20 +1378,20 @@ # have a test which asserted the correctness of the contents of the # output files. I don't know how one could do that, though. -exarkun latex1, latex2, latex3, dvips, ps2pdf13 = builder.commands - self.assertEquals(latex1, latex2) - self.assertEquals(latex2, latex3) - self.assertEquals( + self.assertEqual(latex1, latex2) + self.assertEqual(latex2, latex3) + self.assertEqual( latex1[:1], ["latex"], "LaTeX command %r does not seem right." % (latex1,)) - self.assertEquals( + self.assertEqual( latex1[-1:], [bookPath.path], "LaTeX command %r does not end with the book path (%r)." % ( latex1, bookPath.path)) - self.assertEquals( + self.assertEqual( dvips[:1], ["dvips"], "dvips command %r does not seem right." % (dvips,)) - self.assertEquals( + self.assertEqual( ps2pdf13[:1], ["ps2pdf13"], "ps2pdf13 command %r does not seem right." % (ps2pdf13,)) @@ -1484,7 +1484,7 @@ """ L{filePathDelta} can create a simple relative path to a child path. """ - self.assertEquals(filePathDelta(FilePath("/foo/bar"), + self.assertEqual(filePathDelta(FilePath("/foo/bar"), FilePath("/foo/bar/baz")), ["baz"]) @@ -1494,7 +1494,7 @@ L{filePathDelta} can traverse upwards to create relative paths to siblings. """ - self.assertEquals(filePathDelta(FilePath("/foo/bar"), + self.assertEqual(filePathDelta(FilePath("/foo/bar"), FilePath("/foo/baz")), ["..", "baz"]) @@ -1504,7 +1504,7 @@ L{filePathDelta} can create relative paths to totally unrelated paths for maximum portability. """ - self.assertEquals(filePathDelta(FilePath("/foo/bar"), + self.assertEqual(filePathDelta(FilePath("/foo/bar"), FilePath("/baz/quux")), ["..", "..", "baz", "quux"]) @@ -1514,7 +1514,7 @@ L{filePathDelta} doesn't take into account final elements when comparing 2 paths, but stops at the first difference. """ - self.assertEquals(filePathDelta(FilePath("/foo/bar/bar/spam"), + self.assertEqual(filePathDelta(FilePath("/foo/bar/bar/spam"), FilePath("/foo/bar/baz/spam")), ["..", "..", "baz", "spam"]) @@ -1557,7 +1557,7 @@ """ L{NewsBuilder._today} returns today's date in YYYY-MM-DD form. """ - self.assertEquals( + self.assertEqual( self.builder._today(), date.today().strftime('%Y-%m-%d')) @@ -1569,7 +1569,7 @@ """ features = self.builder._findChanges( self.project, self.builder._FEATURE) - self.assertEquals( + self.assertEqual( features, [(5, "We now support the web."), (12, "The widget is more robust."), @@ -1588,7 +1588,7 @@ """ bugfixes = self.builder._findChanges( self.project, self.builder._BUGFIX) - self.assertEquals( + self.assertEqual( bugfixes, [(23, 'Broken stuff was fixed.')]) @@ -1601,7 +1601,7 @@ """ removals = self.builder._findChanges( self.project, self.builder._REMOVAL) - self.assertEquals( + self.assertEqual( removals, [(25, 'Stupid stuff was deprecated.')]) @@ -1614,7 +1614,7 @@ """ doc = self.builder._findChanges( self.project, self.builder._DOC) - self.assertEquals( + self.assertEqual( doc, [(40, 'foo.bar.Baz.quux'), (41, 'writing Foo servers')]) @@ -1628,7 +1628,7 @@ """ misc = self.builder._findChanges( self.project, self.builder._MISC) - self.assertEquals( + self.assertEqual( misc, [(30, ''), (35, '')]) @@ -1641,7 +1641,7 @@ """ output = StringIO() self.builder._writeHeader(output, "Super Awesometastic 32.16") - self.assertEquals( + self.assertEqual( output.getvalue(), "Super Awesometastic 32.16\n" "=========================\n" @@ -1661,7 +1661,7 @@ [(3, "Great stuff."), (17, "Very long line which goes on and on and on, seemingly " "without end until suddenly without warning it does end.")]) - self.assertEquals( + self.assertEqual( output.getvalue(), "Features\n" "--------\n" @@ -1682,7 +1682,7 @@ self.builder._writeMisc( output, "Other", [(x, "") for x in range(2, 50, 3)]) - self.assertEquals( + self.assertEqual( output.getvalue(), "Other\n" "-----\n" @@ -1701,7 +1701,7 @@ "Super Awesometastic 32.16") results = self.project.child('NEWS').getContent() - self.assertEquals( + self.assertEqual( results, 'Super Awesometastic 32.16\n' '=========================\n' @@ -1749,7 +1749,7 @@ project, project.child('NEWS'), "Super Awesometastic 32.16") results = project.child('NEWS').getContent() - self.assertEquals( + self.assertEqual( results, 'Super Awesometastic 32.16\n' '=========================\n' @@ -1772,7 +1772,7 @@ self.builder.build(self.project, news, "Super Awesometastic 32.16") - self.assertEquals( + self.assertEqual( news.getContent(), 'Ticket numbers in this file can be looked up by visiting\n' 'http://twistedmatrix.com/trac/ticket/\n' @@ -1822,7 +1822,7 @@ self.project, self.project.child('NEWS'), 'Some Thing 1.2') - self.assertEquals( + self.assertEqual( self.project.child('NEWS').getContent(), 'Some Thing 1.2\n' '==============\n' @@ -1852,7 +1852,7 @@ self.project, self.project.child('NEWS'), 'Project Name 5.0') - self.assertEquals( + self.assertEqual( self.project.child('NEWS').getContent(), 'Project Name 5.0\n' '================\n' @@ -1932,7 +1932,7 @@ aggregateNews = project.child("NEWS") - self.assertEquals( + self.assertEqual( builds, [(conchTopfiles, conchNews, conchHeader), (coreTopfiles, coreNews, coreHeader), @@ -1966,7 +1966,7 @@ 'Other\n' '-----\n' ' - #5\n\n\n') - self.assertEquals( + self.assertEqual( expectedCore + 'Old core news.\n', coreNews.getContent()) @@ -2370,7 +2370,7 @@ runCommand(["svn", "commit", checkout.path, "-m", "yay"]) buildAllTarballs(checkout, self.outputDir) - self.assertEquals( + self.assertEqual( set(self.outputDir.children()), set([self.outputDir.child("Twisted-1.2.0.tar.bz2"), self.outputDir.child("TwistedCore-1.2.0.tar.bz2"), @@ -2441,12 +2441,12 @@ if prerelease is not None: version += "pre%d" % (prerelease,) versionChanger.main([version]) - self.assertEquals(len(versionUpdates), 1) - self.assertEquals(versionUpdates[0][0], FilePath(".")) - self.assertEquals(versionUpdates[0][1].major, major) - self.assertEquals(versionUpdates[0][1].minor, minor) - self.assertEquals(versionUpdates[0][1].micro, micro) - self.assertEquals(versionUpdates[0][1].prerelease, prerelease) + self.assertEqual(len(versionUpdates), 1) + self.assertEqual(versionUpdates[0][0], FilePath(".")) + self.assertEqual(versionUpdates[0][1].major, major) + self.assertEqual(versionUpdates[0][1].minor, minor) + self.assertEqual(versionUpdates[0][1].micro, micro) + self.assertEqual(versionUpdates[0][1].prerelease, prerelease) def test_changeVersions(self): @@ -2470,7 +2470,7 @@ L{changeAllProjectVersions}. """ versionChanger = ChangeVersionsScript() - self.assertEquals(versionChanger.changeAllProjectVersions, + self.assertEqual(versionChanger.changeAllProjectVersions, changeAllProjectVersions) @@ -2515,7 +2515,7 @@ tarballBuilder.buildAllTarballs = myBuilder tarballBuilder.main(["checkoutDir", "destinationDir"]) - self.assertEquals( + self.assertEqual( builds, [(FilePath("checkoutDir"), FilePath("destinationDir"))]) @@ -2526,7 +2526,7 @@ is L{buildAllTarballs}. """ tarballBuilder = BuildTarballsScript() - self.assertEquals(tarballBuilder.buildAllTarballs, buildAllTarballs) + self.assertEqual(tarballBuilder.buildAllTarballs, buildAllTarballs) def test_badNumberOfArgumentsToBuildTarballs(self): @@ -2557,4 +2557,4 @@ newsBuilder = NewsBuilder() newsBuilder.buildAll = builds.append newsBuilder.main(["/foo/bar/baz"]) - self.assertEquals(builds, [FilePath("/foo/bar/baz")]) + self.assertEqual(builds, [FilePath("/foo/bar/baz")]) diff --git a/lib/twisted-trunk/twisted/python/test/test_runtime.py b/lib/twisted-trunk/twisted/python/test/test_runtime.py --- a/lib/twisted-trunk/twisted/python/test/test_runtime.py +++ b/lib/twisted-trunk/twisted/python/test/test_runtime.py @@ -14,7 +14,7 @@ class PlatformTests(TestCase): """ - Tests for L{Platform}. + Tests for the default L{Platform} initializer. """ def test_isVistaConsistency(self): @@ -27,3 +27,42 @@ self.assertTrue(platform.isWinNT()) self.assertTrue(platform.isWindows()) self.assertFalse(platform.isMacOSX()) + + + def test_isMacOSXConsistency(self): + """ + L{Platform.isMacOSX} can only return C{True} if L{Platform.getType} + returns C{'posix'}. + """ + platform = Platform() + if platform.isMacOSX(): + self.assertEqual(platform.getType(), 'posix') + + + +class ForeignPlatformTests(TestCase): + """ + Tests for L{Platform} based overridden initializer values. + """ + + def test_getType(self): + """ + If an operating system name is supplied to L{Platform}'s initializer, + L{Platform.getType} returns the platform type which corresponds to that + name. + """ + self.assertEqual(Platform('nt').getType(), 'win32') + self.assertEqual(Platform('ce').getType(), 'win32') + self.assertEqual(Platform('posix').getType(), 'posix') + self.assertEqual(Platform('java').getType(), 'java') + + + def test_isMacOSX(self): + """ + If a system platform name is supplied to L{Platform}'s initializer, it + is used to determine the result of L{Platform.isMacOSX}, which returns + C{True} for C{"darwin"}, C{False} otherwise. + """ + self.assertTrue(Platform(None, 'darwin').isMacOSX()) + self.assertFalse(Platform(None, 'linux2').isMacOSX()) + self.assertFalse(Platform(None, 'win32').isMacOSX()) diff --git a/lib/twisted-trunk/twisted/python/test/test_util.py b/lib/twisted-trunk/twisted/python/test/test_util.py --- a/lib/twisted-trunk/twisted/python/test/test_util.py +++ b/lib/twisted-trunk/twisted/python/test/test_util.py @@ -30,7 +30,7 @@ def testUniq(self): l = ["a", 1, "ab", "a", 3, 4, 1, 2, 2, 4, 6] - self.assertEquals(util.uniquify(l), ["a", 1, "ab", 3, 4, 2, 6]) + self.assertEqual(util.uniquify(l), ["a", 1, "ab", 3, 4, 2, 6]) def testRaises(self): self.failUnless(util.raises(ZeroDivisionError, divmod, 1, 0)) @@ -53,13 +53,13 @@ self.exceptions = [None] self.calls = 0 - self.assertEquals(util.untilConcludes(f, 1, 2), 3) - self.assertEquals(self.calls, 1) + self.assertEqual(util.untilConcludes(f, 1, 2), 3) + self.assertEqual(self.calls, 1) self.exceptions = [None, OSError, IOError] self.calls = 0 - self.assertEquals(util.untilConcludes(f, 2, 3), 5) - self.assertEquals(self.calls, 3) + self.assertEqual(util.untilConcludes(f, 2, 3), 5) + self.assertEqual(self.calls, 3) def testNameToLabel(self): """ @@ -74,7 +74,7 @@ ] for inp, out in nameData: got = util.nameToLabel(inp) - self.assertEquals( + self.assertEqual( got, out, "nameToLabel(%r) == %r != %r" % (inp, got, out)) @@ -126,11 +126,11 @@ util.moduleMovedForSplit("foo", "bar", "baz", "quux", "corge", {}) warnings = self.flushWarnings( offendingFunctions=[self.test_moduleMovedForSplitDeprecation]) - self.assertEquals( + self.assertEqual( warnings[0]['message'], "moduleMovedForSplit is deprecated since Twisted 9.0.") - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 1) @@ -163,8 +163,8 @@ the given uid. """ util.switchUID(12000, None) - self.assertEquals(self.initgroupsCalls, [(12000, None)]) - self.assertEquals(self.mockos.actions, [("setuid", 12000)]) + self.assertEqual(self.initgroupsCalls, [(12000, None)]) + self.assertEqual(self.mockos.actions, [("setuid", 12000)]) def test_euid(self): @@ -173,8 +173,8 @@ the given uid if the C{euid} parameter is set to C{True}. """ util.switchUID(12000, None, True) - self.assertEquals(self.initgroupsCalls, [(12000, None)]) - self.assertEquals(self.mockos.seteuidCalls, [12000]) + self.assertEqual(self.initgroupsCalls, [(12000, None)]) + self.assertEqual(self.mockos.seteuidCalls, [12000]) def test_currentUID(self): @@ -184,10 +184,10 @@ """ uid = self.mockos.getuid() util.switchUID(uid, None) - self.assertEquals(self.initgroupsCalls, []) - self.assertEquals(self.mockos.actions, []) + self.assertEqual(self.initgroupsCalls, []) + self.assertEqual(self.mockos.actions, []) warnings = self.flushWarnings([util.switchUID]) - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) self.assertIn('tried to drop privileges and setuid %i' % uid, warnings[0]['message']) self.assertIn('but uid is already %i' % uid, warnings[0]['message']) @@ -200,10 +200,10 @@ """ euid = self.mockos.geteuid() util.switchUID(euid, None, True) - self.assertEquals(self.initgroupsCalls, []) - self.assertEquals(self.mockos.seteuidCalls, []) + self.assertEqual(self.initgroupsCalls, []) + self.assertEqual(self.mockos.seteuidCalls, []) warnings = self.flushWarnings([util.switchUID]) - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) self.assertIn('tried to drop privileges and seteuid %i' % euid, warnings[0]['message']) self.assertIn('but euid is already %i' % euid, warnings[0]['message']) @@ -313,16 +313,16 @@ d['b'] = 'a' d[3] = 12 d[1234] = 4321 - self.assertEquals(repr(d), "{'a': 'b', 'b': 'a', 3: 12, 1234: 4321}") - self.assertEquals(d.values(), ['b', 'a', 12, 4321]) + self.assertEqual(repr(d), "{'a': 'b', 'b': 'a', 3: 12, 1234: 4321}") + self.assertEqual(d.values(), ['b', 'a', 12, 4321]) del d[3] - self.assertEquals(repr(d), "{'a': 'b', 'b': 'a', 1234: 4321}") - self.assertEquals(d, {'a': 'b', 'b': 'a', 1234:4321}) - self.assertEquals(d.keys(), ['a', 'b', 1234]) - self.assertEquals(list(d.iteritems()), + self.assertEqual(repr(d), "{'a': 'b', 'b': 'a', 1234: 4321}") + self.assertEqual(d, {'a': 'b', 'b': 'a', 1234:4321}) + self.assertEqual(d.keys(), ['a', 'b', 1234]) + self.assertEqual(list(d.iteritems()), [('a', 'b'), ('b','a'), (1234, 4321)]) item = d.popitem() - self.assertEquals(item, (1234, 4321)) + self.assertEqual(item, (1234, 4321)) def testInitialization(self): d = util.OrderedDict({'monkey': 'ook', @@ -330,23 +330,23 @@ self.failUnless(d._order) d = util.OrderedDict(((1,1),(3,3),(2,2),(0,0))) - self.assertEquals(repr(d), "{1: 1, 3: 3, 2: 2, 0: 0}") + self.assertEqual(repr(d), "{1: 1, 3: 3, 2: 2, 0: 0}") class InsensitiveDictTest(unittest.TestCase): def testPreserve(self): InsensitiveDict=util.InsensitiveDict dct=InsensitiveDict({'Foo':'bar', 1:2, 'fnz':{1:2}}, preserve=1) - self.assertEquals(dct['fnz'], {1:2}) - self.assertEquals(dct['foo'], 'bar') - self.assertEquals(dct.copy(), dct) - self.assertEquals(dct['foo'], dct.get('Foo')) + self.assertEqual(dct['fnz'], {1:2}) + self.assertEqual(dct['foo'], 'bar') + self.assertEqual(dct.copy(), dct) + self.assertEqual(dct['foo'], dct.get('Foo')) assert 1 in dct and 'foo' in dct - self.assertEquals(eval(repr(dct)), dct) + self.assertEqual(eval(repr(dct)), dct) keys=['Foo', 'fnz', 1] for x in keys: assert x in dct.keys() assert (x, dct[x]) in dct.items() - self.assertEquals(len(keys), len(dct)) + self.assertEqual(len(keys), len(dct)) del dct[1] del dct['foo'] @@ -357,7 +357,7 @@ for x in keys: assert x in dct.keys() assert (x, dct[x]) in dct.items() - self.assertEquals(len(keys), len(dct)) + self.assertEqual(len(keys), len(dct)) del dct[1] del dct['foo'] @@ -445,7 +445,7 @@ def test_dsu(self): L = [Foo(x) for x in range(20, 9, -1)] L2 = util.dsu(L, lambda o: o.x) - self.assertEquals(range(10, 21), [o.x for o in L2]) + self.assertEqual(range(10, 21), [o.x for o in L2]) def test_deprecation(self): @@ -460,76 +460,76 @@ def testDefault(self): d = iter(util.IntervalDifferential([], 10)) for i in range(100): - self.assertEquals(d.next(), (10, None)) + self.assertEqual(d.next(), (10, None)) def testSingle(self): d = iter(util.IntervalDifferential([5], 10)) for i in range(100): - self.assertEquals(d.next(), (5, 0)) + self.assertEqual(d.next(), (5, 0)) def testPair(self): d = iter(util.IntervalDifferential([5, 7], 10)) for i in range(100): - self.assertEquals(d.next(), (5, 0)) - self.assertEquals(d.next(), (2, 1)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (4, 1)) - self.assertEquals(d.next(), (1, 0)) - self.assertEquals(d.next(), (5, 0)) - self.assertEquals(d.next(), (1, 1)) - self.assertEquals(d.next(), (4, 0)) - self.assertEquals(d.next(), (3, 1)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (5, 0)) - self.assertEquals(d.next(), (0, 1)) + self.assertEqual(d.next(), (5, 0)) + self.assertEqual(d.next(), (2, 1)) + self.assertEqual(d.next(), (3, 0)) + self.assertEqual(d.next(), (4, 1)) + self.assertEqual(d.next(), (1, 0)) + self.assertEqual(d.next(), (5, 0)) + self.assertEqual(d.next(), (1, 1)) + self.assertEqual(d.next(), (4, 0)) + self.assertEqual(d.next(), (3, 1)) + self.assertEqual(d.next(), (2, 0)) + self.assertEqual(d.next(), (5, 0)) + self.assertEqual(d.next(), (0, 1)) def testTriple(self): d = iter(util.IntervalDifferential([2, 4, 5], 10)) for i in range(100): - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (1, 2)) - self.assertEquals(d.next(), (1, 0)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 2)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (1, 2)) - self.assertEquals(d.next(), (1, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (0, 2)) + self.assertEqual(d.next(), (2, 0)) + self.assertEqual(d.next(), (2, 0)) + self.assertEqual(d.next(), (0, 1)) + self.assertEqual(d.next(), (1, 2)) + self.assertEqual(d.next(), (1, 0)) + self.assertEqual(d.next(), (2, 0)) + self.assertEqual(d.next(), (0, 1)) + self.assertEqual(d.next(), (2, 0)) + self.assertEqual(d.next(), (0, 2)) + self.assertEqual(d.next(), (2, 0)) + self.assertEqual(d.next(), (0, 1)) + self.assertEqual(d.next(), (2, 0)) + self.assertEqual(d.next(), (1, 2)) + self.assertEqual(d.next(), (1, 0)) + self.assertEqual(d.next(), (0, 1)) + self.assertEqual(d.next(), (2, 0)) + self.assertEqual(d.next(), (2, 0)) + self.assertEqual(d.next(), (0, 1)) + self.assertEqual(d.next(), (0, 2)) def testInsert(self): d = iter(util.IntervalDifferential([], 10)) - self.assertEquals(d.next(), (10, None)) + self.assertEqual(d.next(), (10, None)) d.addInterval(3) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (3, 0)) + self.assertEqual(d.next(), (3, 0)) + self.assertEqual(d.next(), (3, 0)) d.addInterval(6) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (0, 1)) + self.assertEqual(d.next(), (3, 0)) + self.assertEqual(d.next(), (3, 0)) + self.assertEqual(d.next(), (0, 1)) + self.assertEqual(d.next(), (3, 0)) + self.assertEqual(d.next(), (3, 0)) + self.assertEqual(d.next(), (0, 1)) def testRemove(self): d = iter(util.IntervalDifferential([3, 5], 10)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (2, 1)) - self.assertEquals(d.next(), (1, 0)) + self.assertEqual(d.next(), (3, 0)) + self.assertEqual(d.next(), (2, 1)) + self.assertEqual(d.next(), (1, 0)) d.removeInterval(3) - self.assertEquals(d.next(), (4, 0)) - self.assertEquals(d.next(), (5, 0)) + self.assertEqual(d.next(), (4, 0)) + self.assertEqual(d.next(), (5, 0)) d.removeInterval(5) - self.assertEquals(d.next(), (10, None)) + self.assertEqual(d.next(), (10, None)) self.assertRaises(ValueError, d.removeInterval, 10) @@ -728,7 +728,7 @@ given function """ result = util.runAsEffectiveUser(0, 0, lambda: 1) - self.assertEquals(result, 1) + self.assertEqual(result, 1) def test_takeParameters(self): @@ -737,7 +737,7 @@ function. """ result = util.runAsEffectiveUser(0, 0, lambda x: 2*x, 3) - self.assertEquals(result, 6) + self.assertEqual(result, 6) def test_takesKeyworkArguments(self): @@ -746,7 +746,7 @@ function. """ result = util.runAsEffectiveUser(0, 0, lambda x, y=1, z=1: x*y*z, 2, z=3) - self.assertEquals(result, 6) + self.assertEqual(result, 6) def _testUIDGIDSwitch(self, startUID, startGID, wantUID, wantGID, @@ -761,8 +761,8 @@ util.runAsEffectiveUser( wantUID, wantGID, self._securedFunction, startUID, startGID, wantUID, wantGID) - self.assertEquals(self.mockos.seteuidCalls, expectedUIDSwitches) - self.assertEquals(self.mockos.setegidCalls, expectedGIDSwitches) + self.assertEqual(self.mockos.seteuidCalls, expectedUIDSwitches) + self.assertEqual(self.mockos.setegidCalls, expectedGIDSwitches) self.mockos.seteuidCalls = [] self.mockos.setegidCalls = [] @@ -849,8 +849,8 @@ util.setIDFunction(fakeId) - self.assertEquals(util.unsignedID(foo), 17) - self.assertEquals(util.unsignedID(bar), (sys.maxint + 1) * 2 - 73) + self.assertEqual(util.unsignedID(foo), 17) + self.assertEqual(util.unsignedID(bar), (sys.maxint + 1) * 2 - 73) def test_defaultIDFunction(self): @@ -862,7 +862,7 @@ if idValue < 0: idValue += (sys.maxint + 1) * 2 - self.assertEquals(util.unsignedID(obj), idValue) + self.assertEqual(util.unsignedID(obj), idValue) @@ -891,7 +891,7 @@ util.setgroups = calls.append util.initgroups(os.getuid(), 4) - self.assertEquals(calls, [(pwd.getpwuid(os.getuid())[0], 4)]) + self.assertEqual(calls, [(pwd.getpwuid(os.getuid())[0], 4)]) self.assertFalse(setgroupsCalls) diff --git a/lib/twisted-trunk/twisted/python/test/test_versions.py b/lib/twisted-trunk/twisted/python/test/test_versions.py --- a/lib/twisted-trunk/twisted/python/test/test_versions.py +++ b/lib/twisted-trunk/twisted/python/test/test_versions.py @@ -112,7 +112,7 @@ This is a regression test. """ - self.assertEquals(_inf, _inf) + self.assertEqual(_inf, _inf) def testDontAllowBuggyComparisons(self): @@ -127,7 +127,7 @@ Calling C{repr} on a version returns a human-readable string representation of the version. """ - self.assertEquals(repr(Version("dummy", 1, 2, 3)), + self.assertEqual(repr(Version("dummy", 1, 2, 3)), "Version('dummy', 1, 2, 3)") @@ -136,7 +136,7 @@ Calling C{repr} on a version with a prerelease returns a human-readable string representation of the version including the prerelease. """ - self.assertEquals(repr(Version("dummy", 1, 2, 3, prerelease=4)), + self.assertEqual(repr(Version("dummy", 1, 2, 3, prerelease=4)), "Version('dummy', 1, 2, 3, prerelease=4)") @@ -145,7 +145,7 @@ Calling C{str} on a version returns a human-readable string representation of the version. """ - self.assertEquals(str(Version("dummy", 1, 2, 3)), + self.assertEqual(str(Version("dummy", 1, 2, 3)), "[dummy, version 1.2.3]") @@ -153,12 +153,12 @@ """ Calling C{str} on a version with a prerelease includes the prerelease. """ - self.assertEquals(str(Version("dummy", 1, 0, 0, prerelease=1)), + self.assertEqual(str(Version("dummy", 1, 0, 0, prerelease=1)), "[dummy, version 1.0.0pre1]") def testShort(self): - self.assertEquals(Version('dummy', 1, 2, 3).short(), '1.2.3') + self.assertEqual(Version('dummy', 1, 2, 3).short(), '1.2.3') def test_goodSVNEntries_4(self): @@ -166,7 +166,7 @@ Version should be able to parse an SVN format 4 entries file. """ version = Version("dummy", 1, 0, 0) - self.assertEquals( + self.assertEqual( version._parseSVNEntries_4(StringIO(VERSION_4_ENTRIES)), '18211') @@ -219,14 +219,14 @@ """ The L{base} method returns a very simple representation of the version. """ - self.assertEquals(Version("foo", 1, 0, 0).base(), "1.0.0") + self.assertEqual(Version("foo", 1, 0, 0).base(), "1.0.0") def test_baseWithPrerelease(self): """ The base version includes 'preX' for versions with prereleases. """ - self.assertEquals(Version("foo", 1, 0, 0, prerelease=8).base(), + self.assertEqual(Version("foo", 1, 0, 0, prerelease=8).base(), "1.0.0pre8") @@ -313,7 +313,7 @@ line of the I{entries} file. """ self.svnEntries.child("entries").setContent(VERSION_10_ENTRIES) - self.assertEquals(self.getVersion()._getSVNVersion(), '22715') + self.assertEqual(self.getVersion()._getSVNVersion(), '22715') def test_detectUnknownVersion(self): diff --git a/lib/twisted-trunk/twisted/python/test/test_win32.py b/lib/twisted-trunk/twisted/python/test/test_win32.py --- a/lib/twisted-trunk/twisted/python/test/test_win32.py +++ b/lib/twisted-trunk/twisted/python/test/test_win32.py @@ -16,7 +16,7 @@ Calling C{cmdLineQuote} with an argument with no spaces should return the argument unchanged. """ - self.assertEquals(cmdLineQuote('an_argument'), 'an_argument') + self.assertEqual(cmdLineQuote('an_argument'), 'an_argument') def test_argWithSpaces(self): @@ -24,7 +24,7 @@ Calling C{cmdLineQuote} with an argument containing spaces should return the argument surrounded by quotes. """ - self.assertEquals(cmdLineQuote('An Argument'), '"An Argument"') + self.assertEqual(cmdLineQuote('An Argument'), '"An Argument"') def test_emptyStringArg(self): @@ -32,4 +32,4 @@ Calling C{cmdLineQuote} with an empty string should return a quoted empty string. """ - self.assertEquals(cmdLineQuote(''), '""') + self.assertEqual(cmdLineQuote(''), '""') diff --git a/lib/twisted-trunk/twisted/python/test/test_zipstream.py b/lib/twisted-trunk/twisted/python/test/test_zipstream.py --- a/lib/twisted-trunk/twisted/python/test/test_zipstream.py +++ b/lib/twisted-trunk/twisted/python/test/test_zipstream.py @@ -33,7 +33,7 @@ """ zip files should not be ttys, so isatty() should be false """ - self.assertEquals(self.getFileEntry('').isatty(), False) + self.assertEqual(self.getFileEntry('').isatty(), False) def test_closed(self): @@ -42,9 +42,9 @@ called. """ fileEntry = self.getFileEntry('') - self.assertEquals(fileEntry.closed, False) + self.assertEqual(fileEntry.closed, False) fileEntry.close() - self.assertEquals(fileEntry.closed, True) + self.assertEqual(fileEntry.closed, True) def test_readline(self): @@ -53,9 +53,9 @@ deliminter. """ fileEntry = self.getFileEntry('hoho\nho') - self.assertEquals(fileEntry.readline(), 'hoho\n') - self.assertEquals(fileEntry.readline(), 'ho') - self.assertEquals(fileEntry.readline(), '') + self.assertEqual(fileEntry.readline(), 'hoho\n') + self.assertEqual(fileEntry.readline(), 'ho') + self.assertEqual(fileEntry.readline(), '') def test_next(self): @@ -63,8 +63,8 @@ Zip file entries should implement the iterator protocol as files do. """ fileEntry = self.getFileEntry('ho\nhoho') - self.assertEquals(fileEntry.next(), 'ho\n') - self.assertEquals(fileEntry.next(), 'hoho') + self.assertEqual(fileEntry.next(), 'ho\n') + self.assertEqual(fileEntry.next(), 'hoho') self.assertRaises(StopIteration, fileEntry.next) @@ -73,7 +73,7 @@ C{readlines()} should return a list of all the lines. """ fileEntry = self.getFileEntry('ho\nho\nho') - self.assertEquals(fileEntry.readlines(), ['ho\n', 'ho\n', 'ho']) + self.assertEqual(fileEntry.readlines(), ['ho\n', 'ho\n', 'ho']) def test_iteration(self): @@ -91,7 +91,7 @@ """ contents = "Hello, world!" entry = self.getFileEntry(contents) - self.assertEquals(entry.read(), contents) + self.assertEqual(entry.read(), contents) def test_readPartial(self): @@ -102,8 +102,8 @@ entry = self.getFileEntry(contents) one = entry.read(4) two = entry.read(200) - self.assertEquals(one, "0123") - self.assertEquals(two, "456789") + self.assertEqual(one, "0123") + self.assertEqual(two, "456789") def test_tell(self): @@ -114,9 +114,9 @@ contents = "x" * 100 entry = self.getFileEntry(contents) entry.read(2) - self.assertEquals(entry.tell(), 2) + self.assertEqual(entry.tell(), 2) entry.read(4) - self.assertEquals(entry.tell(), 6) + self.assertEqual(entry.tell(), 6) @@ -177,7 +177,7 @@ "countZipFileEntries is deprecated.", __file__, lambda : zipstream.countZipFileEntries(name)) - self.assertEquals(result, 5) + self.assertEqual(result, 5) def test_invalidMode(self): @@ -216,7 +216,7 @@ scribble.close() czf = zipstream.ChunkingZipFile(fn) self.assertRaises(zipfile.BadZipfile, czf.readfile, "0") - self.assertEquals(czf.readfile("1").read(), "more contents") + self.assertEqual(czf.readfile("1").read(), "more contents") def test_filenameMismatch(self): @@ -237,7 +237,7 @@ czf = zipstream.ChunkingZipFile(fn) self.assertRaises(zipfile.BadZipfile, czf.readfile, "0") - self.assertEquals(czf.readfile("1").read(), "more contents") + self.assertEqual(czf.readfile("1").read(), "more contents") if sys.version_info < (2, 5): @@ -280,7 +280,7 @@ zf.writestr(zi, "the real data") zf.close() czf = zipstream.ChunkingZipFile(fn) - self.assertEquals(czf.readfile("0").read(), "the real data") + self.assertEqual(czf.readfile("0").read(), "the real data") def test_unzipIter(self): @@ -294,13 +294,13 @@ zpfilename = self.makeZipFile(contents) uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path) for i in range(numfiles): - self.assertEquals(len(list(self.unzipdir.children())), i) - self.assertEquals(uziter.next(), numfiles - i - 1) - self.assertEquals(len(list(self.unzipdir.children())), numfiles) + self.assertEqual(len(list(self.unzipdir.children())), i) + self.assertEqual(uziter.next(), numfiles - i - 1) + self.assertEqual(len(list(self.unzipdir.children())), numfiles) for child in self.unzipdir.children(): num = int(child.basename()) - self.assertEquals(child.open().read(), contents[num]) + self.assertEqual(child.open().read(), contents[num]) test_unzipIter.suppress = [ util.suppress(message="zipstream.unzipIter is deprecated")] @@ -312,15 +312,15 @@ """ zpfilename = self.makeZipFile('foo') - self.assertEquals(len(self.flushWarnings()), 0) + self.assertEqual(len(self.flushWarnings()), 0) for f in zipstream.unzipIter(zpfilename, self.unzipdir.path): pass warnings = self.flushWarnings() - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "zipstream.unzipIter is deprecated since Twisted 11.0.0 for " "security reasons. Use Python's zipfile instead.") @@ -335,13 +335,13 @@ contents = ['This is test file %d!' % i for i in range(numfiles)] zpfilename = self.makeZipFile(contents) list(zipstream.unzipIterChunky(zpfilename, self.unzipdir.path)) - self.assertEquals( + self.assertEqual( set(self.unzipdir.listdir()), set(map(str, range(numfiles)))) for child in self.unzipdir.children(): num = int(child.basename()) - self.assertEquals(child.getContent(), contents[num]) + self.assertEqual(child.getContent(), contents[num]) def test_unzipIterChunkyDirectory(self): @@ -354,13 +354,13 @@ contents = ['This is test file %d!' % i for i in range(numfiles)] zpfilename = self.makeZipFile(contents, 'foo') list(zipstream.unzipIterChunky(zpfilename, self.unzipdir.path)) - self.assertEquals( + self.assertEqual( set(self.unzipdir.child('foo').listdir()), set(map(str, range(numfiles)))) for child in self.unzipdir.child('foo').children(): num = int(child.basename()) - self.assertEquals(child.getContent(), contents[num]) + self.assertEqual(child.getContent(), contents[num]) def test_unzip(self): @@ -386,14 +386,14 @@ """ zpfilename = self.makeZipFile('foo') - self.assertEquals(len(self.flushWarnings()), 0) + self.assertEqual(len(self.flushWarnings()), 0) zipstream.unzip(zpfilename, self.unzipdir.path) warnings = self.flushWarnings() - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "zipstream.unzip is deprecated since Twisted 11.0.0 for " "security reasons. Use Python's zipfile instead.") @@ -429,18 +429,18 @@ testfile.setContent('NOT OVERWRITTEN') zipstream.unzip(zpfilename, self.unzipdir.path) - self.assertEquals(testfile.open().read(), 'NOT OVERWRITTEN') + self.assertEqual(testfile.open().read(), 'NOT OVERWRITTEN') zipstream.unzip(zpfilename, self.unzipdir.path, overwrite=True) - self.assertEquals(testfile.open().read(), 'OVERWRITTEN') + self.assertEqual(testfile.open().read(), 'OVERWRITTEN') testfile.setContent('NOT OVERWRITTEN') uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path) uziter.next() - self.assertEquals(testfile.open().read(), 'NOT OVERWRITTEN') + self.assertEqual(testfile.open().read(), 'NOT OVERWRITTEN') uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path, overwrite=True) uziter.next() - self.assertEquals(testfile.open().read(), 'OVERWRITTEN') + self.assertEqual(testfile.open().read(), 'OVERWRITTEN') test_overwrite.suppress = [ util.suppress(message="zipstream.unzip is deprecated"), util.suppress(message="zipstream.unzipIter is deprecated")] diff --git a/lib/twisted-trunk/twisted/python/text.py b/lib/twisted-trunk/twisted/python/text.py --- a/lib/twisted-trunk/twisted/python/text.py +++ b/lib/twisted-trunk/twisted/python/text.py @@ -134,7 +134,7 @@ if inString.find('\n\n') >= 0: paragraphs = string.split(inString, '\n\n') for para in paragraphs: - outLines.extend(greedyWrap(para) + ['']) + outLines.extend(greedyWrap(para, width) + ['']) return outLines inWords = string.split(inString) diff --git a/lib/twisted-trunk/twisted/python/usage.py b/lib/twisted-trunk/twisted/python/usage.py --- a/lib/twisted-trunk/twisted/python/usage.py +++ b/lib/twisted-trunk/twisted/python/usage.py @@ -307,13 +307,6 @@ parameters = [] - reflect.accumulateClassList(self.__class__, 'optStrings', - parameters) - if parameters: - import warnings - warnings.warn("Options.optStrings is deprecated, " - "please use optParameters instead.", stacklevel=2) - reflect.accumulateClassList(self.__class__, 'optParameters', parameters) diff --git a/lib/twisted-trunk/twisted/python/zshcomp.py b/lib/twisted-trunk/twisted/python/zshcomp.py --- a/lib/twisted-trunk/twisted/python/zshcomp.py +++ b/lib/twisted-trunk/twisted/python/zshcomp.py @@ -688,15 +688,7 @@ ('tkconch', 'twisted.conch.scripts.tkconch', 'GeneralOptions'), ('manhole', 'twisted.scripts.manhole', 'MyOptions'), ('tap2rpm', 'twisted.scripts.tap2rpm', 'MyOptions'), - ('websetroot', None, None), - ('tkmktap', None, None), ] -# NOTE: the commands using None above are no longer included in Twisted. -# However due to limitations in zsh's completion system the version of -# _twisted_zsh_stub shipped with zsh contains a static list of Twisted's -# commands. It will display errors if completion functions for these missing -# commands are not found :( So we just include dummy (empty) completion -# function files specialBuilders = {'mktap' : MktapBuilder, 'twistd' : TwistdBuilder} diff --git a/lib/twisted-trunk/twisted/runner/test/test_procmon.py b/lib/twisted-trunk/twisted/runner/test/test_procmon.py --- a/lib/twisted-trunk/twisted/runner/test/test_procmon.py +++ b/lib/twisted-trunk/twisted/runner/test/test_procmon.py @@ -135,7 +135,7 @@ """ self.pm.addProcess("foo", ["arg1", "arg2"], uid=1, gid=2, env={}) - self.assertEquals(self.pm.__getstate__()['processes'], + self.assertEqual(self.pm.__getstate__()['processes'], {'foo': (['arg1', 'arg2'], 1, 2, {})}) @@ -154,12 +154,12 @@ """ self.pm.addProcess("foo", ["arg1", "arg2"], uid=1, gid=2, env={}) - self.assertEquals(self.pm.protocols, {}) - self.assertEquals(self.pm.processes, + self.assertEqual(self.pm.protocols, {}) + self.assertEqual(self.pm.processes, {"foo": (["arg1", "arg2"], 1, 2, {})}) self.pm.startService() self.reactor.advance(0) - self.assertEquals(self.pm.protocols.keys(), ["foo"]) + self.assertEqual(self.pm.protocols.keys(), ["foo"]) def test_addProcessDuplicateKeyError(self): @@ -182,7 +182,7 @@ self.pm.startService() self.pm.addProcess("foo", ["foo"], uid=1, gid=2, env=fakeEnv) self.reactor.advance(0) - self.assertEquals( + self.assertEqual( self.reactor.spawnedProcesses[0]._environment, fakeEnv) @@ -193,9 +193,9 @@ """ self.pm.startService() self.pm.addProcess("foo", ["foo"]) - self.assertEquals(len(self.pm.processes), 1) + self.assertEqual(len(self.pm.processes), 1) self.pm.removeProcess("foo") - self.assertEquals(len(self.pm.processes), 0) + self.assertEqual(len(self.pm.processes), 0) def test_removeProcessUnknownKeyError(self): @@ -261,7 +261,7 @@ self.reactor.advance(timeToDie) # We expect it to be restarted immediately - self.assertEquals(self.reactor.seconds(), + self.assertEqual(self.reactor.seconds(), self.pm.timeStarted["foo"]) @@ -281,11 +281,11 @@ # If process doesn't die before the killTime, procmon should # terminate it self.reactor.advance(self.pm.killTime - 1) - self.assertEquals(0.0, self.pm.timeStarted["foo"]) + self.assertEqual(0.0, self.pm.timeStarted["foo"]) self.reactor.advance(1) # We expect it to be immediately restarted - self.assertEquals(self.reactor.seconds(), self.pm.timeStarted["foo"]) + self.assertEqual(self.reactor.seconds(), self.pm.timeStarted["foo"]) def test_stopProcessUnknownKeyError(self): @@ -390,10 +390,10 @@ self.pm.addProcess("foo", ["foo"]) self.reactor.advance(self.pm.threshold - 1) #9s self.assertIn("foo", self.pm.protocols) - self.assertEquals(self.pm.delay["foo"], self.pm.minRestartDelay) + self.assertEqual(self.pm.delay["foo"], self.pm.minRestartDelay) # process dies within the threshold and should not restart immediately self.pm.protocols["foo"].processEnded(Failure(ProcessDone(0))) - self.assertEquals(self.pm.delay["foo"], self.pm.minRestartDelay * 2) + self.assertEqual(self.pm.delay["foo"], self.pm.minRestartDelay * 2) def test_startService(self): @@ -428,7 +428,7 @@ # should have exited self.reactor.advance(self.pm.killTime + 1) # The processes shouldn't be restarted - self.assertEquals({}, self.pm.protocols) + self.assertEqual({}, self.pm.protocols) def test_stopServiceCancelRestarts(self): @@ -473,7 +473,7 @@ self.reactor.advance(6) # The process shouldn't have restarted because stopService has cancelled # all pending process restarts. - self.assertEquals(self.pm.protocols, {}) + self.assertEqual(self.pm.protocols, {}) def test_activeAttributeEqualsRunning(self): @@ -481,9 +481,9 @@ L{ProcessMonitor.active} unneccessarily duplicates the standard L{IService.running} flag. """ - self.assertEquals(self.pm.active, self.pm.running) + self.assertEqual(self.pm.active, self.pm.running) self.pm.startService() - self.assertEquals(self.pm.active, self.pm.running) + self.assertEqual(self.pm.active, self.pm.running) def test_activeAttributeDeprecation(self): diff --git a/lib/twisted-trunk/twisted/runner/test/test_procmontap.py b/lib/twisted-trunk/twisted/runner/test/test_procmontap.py --- a/lib/twisted-trunk/twisted/runner/test/test_procmontap.py +++ b/lib/twisted-trunk/twisted/runner/test/test_procmontap.py @@ -32,7 +32,7 @@ """ opt = tap.Options() opt.parseOptions(['--threshold', '7.5', 'foo']) - self.assertEquals(opt['threshold'], 7.5) + self.assertEqual(opt['threshold'], 7.5) def test_killTime(self): @@ -41,7 +41,7 @@ """ opt = tap.Options() opt.parseOptions(['--killtime', '7.5', 'foo']) - self.assertEquals(opt['killtime'], 7.5) + self.assertEqual(opt['killtime'], 7.5) def test_minRestartDelay(self): @@ -51,7 +51,7 @@ """ opt = tap.Options() opt.parseOptions(['--minrestartdelay', '7.5', 'foo']) - self.assertEquals(opt['minrestartdelay'], 7.5) + self.assertEqual(opt['minrestartdelay'], 7.5) def test_maxRestartDelay(self): @@ -61,7 +61,7 @@ """ opt = tap.Options() opt.parseOptions(['--maxrestartdelay', '7.5', 'foo']) - self.assertEquals(opt['maxrestartdelay'], 7.5) + self.assertEqual(opt['maxrestartdelay'], 7.5) def test_parameterDefaults(self): @@ -70,10 +70,10 @@ """ opt = tap.Options() opt.parseOptions(['foo']) - self.assertEquals(opt['threshold'], 1) - self.assertEquals(opt['killtime'], 5) - self.assertEquals(opt['minrestartdelay'], 1) - self.assertEquals(opt['maxrestartdelay'], 3600) + self.assertEqual(opt['threshold'], 1) + self.assertEqual(opt['killtime'], 5) + self.assertEqual(opt['minrestartdelay'], 1) + self.assertEqual(opt['maxrestartdelay'], 3600) def test_makeService(self): diff --git a/lib/twisted-trunk/twisted/scripts/test/test_tap2rpm.py b/lib/twisted-trunk/twisted/scripts/test/test_tap2rpm.py --- a/lib/twisted-trunk/twisted/scripts/test/test_tap2rpm.py +++ b/lib/twisted-trunk/twisted/scripts/test/test_tap2rpm.py @@ -150,7 +150,7 @@ """ d = _queryRPMTags(rpmfile, tags.keys()) - d.addCallback(self.assertEquals, tags) + d.addCallback(self.assertEqual, tags) return d @@ -164,18 +164,18 @@ config = tap2rpm.MyOptions() config.parseOptions([]) - self.assertEquals(config['tapfile'], 'twistd.tap') - self.assertEquals(config['maintainer'], 'tap2rpm') - self.assertEquals(config['protocol'], 'twistd') - self.assertEquals(config['description'], 'A TCP server for twistd') - self.assertEquals(config['long_description'], + self.assertEqual(config['tapfile'], 'twistd.tap') + self.assertEqual(config['maintainer'], 'tap2rpm') + self.assertEqual(config['protocol'], 'twistd') + self.assertEqual(config['description'], 'A TCP server for twistd') + self.assertEqual(config['long_description'], 'Automatically created by tap2rpm') - self.assertEquals(config['set-version'], '1.0') - self.assertEquals(config['rpmfile'], 'twisted-twistd') - self.assertEquals(config['type'], 'tap') - self.assertEquals(config['quiet'], False) - self.assertEquals(config['twistd_option'], 'file') - self.assertEquals(config['release-name'], 'twisted-twistd-1.0') + self.assertEqual(config['set-version'], '1.0') + self.assertEqual(config['rpmfile'], 'twisted-twistd') + self.assertEqual(config['type'], 'tap') + self.assertEqual(config['quiet'], False) + self.assertEqual(config['twistd_option'], 'file') + self.assertEqual(config['release-name'], 'twisted-twistd-1.0') def test_protocolCalculatedFromTapFile(self): @@ -185,8 +185,8 @@ config = tap2rpm.MyOptions() config.parseOptions(['--tapfile', 'pancakes.tap']) - self.assertEquals(config['tapfile'], 'pancakes.tap') - self.assertEquals(config['protocol'], 'pancakes') + self.assertEqual(config['tapfile'], 'pancakes.tap') + self.assertEqual(config['protocol'], 'pancakes') def test_optionsDefaultToProtocolValue(self): @@ -199,18 +199,18 @@ '--protocol', 'eggs', ]) - self.assertEquals(config['tapfile'], 'sausages.tap') - self.assertEquals(config['maintainer'], 'tap2rpm') - self.assertEquals(config['protocol'], 'eggs') - self.assertEquals(config['description'], 'A TCP server for eggs') - self.assertEquals(config['long_description'], + self.assertEqual(config['tapfile'], 'sausages.tap') + self.assertEqual(config['maintainer'], 'tap2rpm') + self.assertEqual(config['protocol'], 'eggs') + self.assertEqual(config['description'], 'A TCP server for eggs') + self.assertEqual(config['long_description'], 'Automatically created by tap2rpm') - self.assertEquals(config['set-version'], '1.0') - self.assertEquals(config['rpmfile'], 'twisted-eggs') - self.assertEquals(config['type'], 'tap') - self.assertEquals(config['quiet'], False) - self.assertEquals(config['twistd_option'], 'file') - self.assertEquals(config['release-name'], 'twisted-eggs-1.0') + self.assertEqual(config['set-version'], '1.0') + self.assertEqual(config['rpmfile'], 'twisted-eggs') + self.assertEqual(config['type'], 'tap') + self.assertEqual(config['quiet'], False) + self.assertEqual(config['twistd_option'], 'file') + self.assertEqual(config['release-name'], 'twisted-eggs-1.0') def test_releaseNameDefaultsToRpmfileValue(self): @@ -223,7 +223,7 @@ "--set-version", "1.2.3", ]) - self.assertEquals(config['release-name'], 'beans-1.2.3') + self.assertEqual(config['release-name'], 'beans-1.2.3') def test_basicOperation(self): diff --git a/lib/twisted-trunk/twisted/spread/flavors.py b/lib/twisted-trunk/twisted/spread/flavors.py --- a/lib/twisted-trunk/twisted/spread/flavors.py +++ b/lib/twisted-trunk/twisted/spread/flavors.py @@ -30,7 +30,7 @@ # sibling imports from jelly import setUnjellyableForClass, setUnjellyableForClassTree, setUnjellyableFactoryForClass, unjellyableRegistry -from jelly import Jellyable, Unjellyable, _Dummy, _DummyNewStyle +from jelly import Jellyable, Unjellyable, _newDummyLike from jelly import setInstanceState, getInstanceState # compatibility @@ -437,12 +437,7 @@ return setInstanceState(self, unjellier, jellyList) self.broker = unjellier.invoker self.luid = jellyList[1] - if isinstance(self.__class__, type): #new-style class - cProxy = _DummyNewStyle() - else: - cProxy = _Dummy() - cProxy.__class__ = self.__class__ - cProxy.__dict__ = self.__dict__ + cProxy = _newDummyLike(self) # XXX questionable whether this was a good design idea... init = getattr(cProxy, "__init__", None) if init: @@ -491,10 +486,7 @@ def unjellyCached(unjellier, unjellyList): luid = unjellyList[1] cNotProxy = unjellier.invoker.cachedLocallyAs(luid) - - cProxy = _Dummy() - cProxy.__class__ = cNotProxy.__class__ - cProxy.__dict__ = cNotProxy.__dict__ + cProxy = _newDummyLike(cNotProxy) return cProxy setUnjellyableForClass("cached", unjellyCached) diff --git a/lib/twisted-trunk/twisted/spread/jelly.py b/lib/twisted-trunk/twisted/spread/jelly.py --- a/lib/twisted-trunk/twisted/spread/jelly.py +++ b/lib/twisted-trunk/twisted/spread/jelly.py @@ -949,6 +949,25 @@ """ +def _newDummyLike(instance): + """ + Create a new instance like C{instance}. + + The new instance has the same class and instance dictionary as the given + instance. + + @return: The new instance. + """ + if isinstance(instance.__class__, type): + # New-style class + dummy = _DummyNewStyle() + else: + # Classic class + dummy = _Dummy() + dummy.__class__ = instance.__class__ + dummy.__dict__ = instance.__dict__ + return dummy + #### Published Interface. diff --git a/lib/twisted-trunk/twisted/spread/pb.py b/lib/twisted-trunk/twisted/spread/pb.py --- a/lib/twisted-trunk/twisted/spread/pb.py +++ b/lib/twisted-trunk/twisted/spread/pb.py @@ -76,17 +76,22 @@ portno = 8787 + class ProtocolError(Exception): """ This error is raised when an invalid protocol statement is received. """ + + class DeadReferenceError(ProtocolError): """ This error is raised when a method is called on a dead reference (one whose broker has been disconnected). """ + + class Error(Exception): """ This error can be raised to generate known error conditions. @@ -97,6 +102,34 @@ sent. """ + + +class RemoteError(Exception): + """ + This class is used to wrap a string-ified exception from the remote side to + be able to reraise it. (Raising string exceptions is no longer possible in + Python 2.6+) + + The value of this exception will be a str() representation of the remote + value. + + @ivar remoteType: The full import path of the exception class which was + raised on the remote end. + @type remoteType: C{str} + + @ivar remoteTraceback: The remote traceback. + @type remoteTraceback: C{str} + + @note: It's not possible to include the remoteTraceback if this exception is + thrown into a generator. It must be accessed as an attribute. + """ + def __init__(self, remoteType, value, remoteTraceback): + Exception.__init__(self, value) + self.remoteType = remoteType + self.remoteTraceback = remoteTraceback + + + class RemoteMethod: """This is a translucent reference to a remote message. """ @@ -106,12 +139,15 @@ self.obj = obj self.name = name + def __cmp__(self, other): return cmp((self.obj, self.name), other) + def __hash__(self): return hash((self.obj, self.name)) + def __call__(self, *args, **kw): """Asynchronously invoke a remote method. """ @@ -144,6 +180,7 @@ printTraceback = deprecated(Version("twisted", 8, 2, 0))(printTraceback) + class IPerspective(Interface): """ per*spec*tive, n. : The relationship of aspects of a subject to each @@ -311,7 +348,7 @@ def callRemote(self, _name, *args, **kw): """Asynchronously invoke a remote method. - @type _name: C{string} + @type _name: C{str} @param _name: the name of the remote method to invoke @param args: arguments to serialize for the remote function @param kw: keyword arguments to serialize for the remote function. @@ -400,10 +437,7 @@ state['tb'] = None state['frames'] = [] state['stack'] = [] - if isinstance(self.value, failure.Failure): - state['value'] = failure2Copyable(self.value, self.unsafeTracebacks) - else: - state['value'] = str(self.value) # Exception instance + state['value'] = str(self.value) # Exception instance if isinstance(self.type, str): state['type'] = self.type else: @@ -415,23 +449,57 @@ return state + class CopiedFailure(RemoteCopy, failure.Failure): + """ + A L{CopiedFailure} is a L{pb.RemoteCopy} of a L{failure.Failure} + transfered via PB. + + @ivar type: The full import path of the exception class which was raised on + the remote end. + @type type: C{str} + + @ivar value: A str() representation of the remote value. + @type value: L{CopiedFailure} or C{str} + + @ivar traceback: The remote traceback. + @type traceback: C{str} + """ + def printTraceback(self, file=None, elideFrameworkCode=0, detail='default'): if file is None: file = log.logfile file.write("Traceback from remote host -- ") file.write(self.traceback) + + def throwExceptionIntoGenerator(self, g): + """ + Throw the original exception into the given generator, preserving + traceback information if available. In the case of a L{CopiedFailure} + where the exception type is a string, a L{pb.RemoteError} is thrown + instead. + + @return: The next value yielded from the generator. + @raise StopIteration: If there are no more values in the generator. + @raise RemoteError: The wrapped remote exception. + """ + return g.throw(RemoteError(self.type, self.value, self.traceback)) + printBriefTraceback = printTraceback printDetailedTraceback = printTraceback setUnjellyableForClass(CopyableFailure, CopiedFailure) + + def failure2Copyable(fail, unsafeTracebacks=0): f = types.InstanceType(CopyableFailure, fail.__dict__) f.unsafeTracebacks = unsafeTracebacks return f + + class Broker(banana.Banana): """I am a broker for objects. """ @@ -1278,17 +1346,19 @@ puid = avatar.processUniqueID() - def dereferenceLogout(): - self.broker.dontNotifyOnDisconnect(logout) - logout() + # only call logout once, whether the connection is dropped (disconnect) + # or a logout occurs (cleanup), and be careful to drop the reference to + # it in either case + logout = [ logout ] + def maybeLogout(): + if not logout: + return + fn = logout[0] + del logout[0] + fn() + self.broker._localCleanup[puid] = maybeLogout + self.broker.notifyOnDisconnect(maybeLogout) - self.broker._localCleanup[puid] = dereferenceLogout - # No special helper function is necessary for notifyOnDisconnect - # because dereference callbacks won't be invoked if the connection is - # randomly dropped. I'm not sure those are ideal semantics, but this - # is the only user of the (private) API at the moment and it works just - # fine as things are. -exarkun - self.broker.notifyOnDisconnect(logout) return avatar diff --git a/lib/twisted-trunk/twisted/test/generator_failure_tests.py b/lib/twisted-trunk/twisted/test/generator_failure_tests.py --- a/lib/twisted-trunk/twisted/test/generator_failure_tests.py +++ b/lib/twisted-trunk/twisted/test/generator_failure_tests.py @@ -48,7 +48,7 @@ ic(d).addErrback(collect_error) newFailure, = failures - self.assertEquals( + self.assertEqual( traceback.extract_tb(newFailure.getTracebackObject())[-1][-1], "1/0" ) @@ -81,10 +81,10 @@ g.next() self._throwIntoGenerator(f, g) - self.assertEquals(stuff[0][0], ZeroDivisionError) + self.assertEqual(stuff[0][0], ZeroDivisionError) self.assertTrue(isinstance(stuff[0][1], ZeroDivisionError)) - self.assertEquals(traceback.extract_tb(stuff[0][2])[-1][-1], "1/0") + self.assertEqual(traceback.extract_tb(stuff[0][2])[-1][-1], "1/0") def test_findFailureInGenerator(self): diff --git a/lib/twisted-trunk/twisted/test/test_adbapi.py b/lib/twisted-trunk/twisted/test/test_adbapi.py --- a/lib/twisted-trunk/twisted/test/test_adbapi.py +++ b/lib/twisted-trunk/twisted/test/test_adbapi.py @@ -141,13 +141,13 @@ def _testPool_4(self, res): # runInteraction d = self.dbpool.runInteraction(self.interaction) - d.addCallback(lambda res: self.assertEquals(res, "done")) + d.addCallback(lambda res: self.assertEqual(res, "done")) return d def _testPool_5(self, res): # withConnection d = self.dbpool.runWithConnection(self.withConnection) - d.addCallback(lambda res: self.assertEquals(res, "done")) + d.addCallback(lambda res: self.assertEqual(res, "done")) return d def _testPool_6(self, res): @@ -196,12 +196,12 @@ curs.execute("insert into simple(x) values(1)") curs.execute("select x from simple") res = curs.fetchall() - self.failUnlessEqual(len(res), 1) - self.failUnlessEqual(len(res[0]), 1) - self.failUnlessEqual(res[0][0], 1) + self.assertEqual(len(res), 1) + self.assertEqual(len(res[0]), 1) + self.assertEqual(res[0][0], 1) curs.execute("delete from simple") curs.execute("select x from simple") - self.failUnlessEqual(len(curs.fetchall()), 0) + self.assertEqual(len(curs.fetchall()), 0) curs.close() self.dbpool.disconnect(conn) @@ -634,8 +634,8 @@ connection = Connection(pool) self.assertRaises(ConnectionLost, connection.rollback) errors = self.flushLoggedErrors(RuntimeError) - self.assertEquals(len(errors), 1) - self.assertEquals(errors[0].value.args[0], "problem!") + self.assertEqual(len(errors), 1) + self.assertEqual(errors[0].value.args[0], "problem!") @@ -664,8 +664,8 @@ transaction = Transaction(pool, ConnectionCursorRaise()) transaction.reopen() errors = self.flushLoggedErrors(RuntimeError) - self.assertEquals(len(errors), 1) - self.assertEquals(errors[0].value.args[0], "problem!") + self.assertEqual(len(errors), 1) + self.assertEqual(errors[0].value.args[0], "problem!") @@ -754,8 +754,8 @@ d = self.assertFailure(d, ValueError) def cbFailed(ignored): errors = self.flushLoggedErrors(RuntimeError) - self.assertEquals(len(errors), 1) - self.assertEquals(errors[0].value.args[0], "problem!") + self.assertEqual(len(errors), 1) + self.assertEqual(errors[0].value.args[0], "problem!") d.addCallback(cbFailed) return d @@ -772,8 +772,8 @@ pool._close(ConnectionCloseRaise()) errors = self.flushLoggedErrors(RuntimeError) - self.assertEquals(len(errors), 1) - self.assertEquals(errors[0].value.args[0], "problem!") + self.assertEqual(len(errors), 1) + self.assertEqual(errors[0].value.args[0], "problem!") def test_runWithInteractionRaiseOriginalError(self): @@ -803,8 +803,8 @@ d = self.assertFailure(d, ValueError) def cbFailed(ignored): errors = self.flushLoggedErrors(RuntimeError) - self.assertEquals(len(errors), 1) - self.assertEquals(errors[0].value.args[0], "problem!") + self.assertEqual(len(errors), 1) + self.assertEqual(errors[0].value.args[0], "problem!") d.addCallback(cbFailed) return d @@ -817,7 +817,7 @@ reactor = EventReactor(False) pool = ConnectionPool('twisted.test.test_adbapi', cp_reactor=reactor) # There should be a startup trigger waiting. - self.assertEquals(reactor.triggers, [('after', 'startup', pool._start)]) + self.assertEqual(reactor.triggers, [('after', 'startup', pool._start)]) pool.close() # But not anymore. self.assertFalse(reactor.triggers) @@ -831,7 +831,7 @@ reactor = EventReactor(True) pool = ConnectionPool('twisted.test.test_adbapi', cp_reactor=reactor) # There should be a shutdown trigger waiting. - self.assertEquals(reactor.triggers, [('during', 'shutdown', pool.finalClose)]) + self.assertEqual(reactor.triggers, [('during', 'shutdown', pool.finalClose)]) pool.close() # But not anymore. self.assertFalse(reactor.triggers) diff --git a/lib/twisted-trunk/twisted/test/test_amp.py b/lib/twisted-trunk/twisted/test/test_amp.py --- a/lib/twisted-trunk/twisted/test/test_amp.py +++ b/lib/twisted-trunk/twisted/test/test_amp.py @@ -382,7 +382,7 @@ Make sure that strs serialize to strs. """ a = amp.AmpBox(key='value') - self.assertEquals(type(a.serialize()), str) + self.assertEqual(type(a.serialize()), str) def test_serializeUnicodeKeyRaises(self): """ @@ -409,13 +409,13 @@ else. """ b = amp.Boolean() - self.assertEquals(b.fromString("True"), True) - self.assertEquals(b.fromString("False"), False) + self.assertEqual(b.fromString("True"), True) + self.assertEqual(b.fromString("False"), False) self.assertRaises(TypeError, b.fromString, "ninja") self.assertRaises(TypeError, b.fromString, "true") self.assertRaises(TypeError, b.fromString, "TRUE") - self.assertEquals(b.toString(True), 'True') - self.assertEquals(b.toString(False), 'False') + self.assertEqual(b.toString(True), 'True') + self.assertEqual(b.toString(False), 'False') def test_pathValueRoundTrip(self): """ @@ -426,7 +426,7 @@ s = p.toString(fp) v = p.fromString(s) self.assertNotIdentical(fp, v) # sanity check - self.assertEquals(fp, v) + self.assertEqual(fp, v) def test_sillyEmptyThing(self): @@ -470,7 +470,7 @@ jb.update(dict(test)) jb._sendTo(c) p.flush() - self.assertEquals(s.boxes[-1], jb) + self.assertEqual(s.boxes[-1], jb) @@ -571,7 +571,7 @@ hello="world") self.locator.commands['hello'] = thunk self.dispatcher.ampBoxReceived(input) - self.assertEquals(received, [input]) + self.assertEqual(received, [input]) def test_sendUnhandledError(self): @@ -603,8 +603,8 @@ hello="world") self.sender.expectError() self.dispatcher.ampBoxReceived(input) - self.assertEquals(len(self.sender.unhandledErrors), 1) - self.assertEquals(self.sender.unhandledErrors[0].value, err) + self.assertEqual(len(self.sender.unhandledErrors), 1) + self.assertEqual(self.sender.unhandledErrors[0].value, err) def test_callRemote(self): @@ -616,17 +616,17 @@ de-serialization. """ D = self.dispatcher.callRemote(Hello, hello='world') - self.assertEquals(self.sender.sentBoxes, + self.assertEqual(self.sender.sentBoxes, [amp.AmpBox(_command="hello", _ask="1", hello="world")]) answers = [] D.addCallback(answers.append) - self.assertEquals(answers, []) + self.assertEqual(answers, []) self.dispatcher.ampBoxReceived(amp.AmpBox({'hello': "yay", 'print': "ignored", '_answer': "1"})) - self.assertEquals(answers, [dict(hello="yay", + self.assertEqual(answers, [dict(hello="yay", Print=u"ignored")]) @@ -722,7 +722,7 @@ responderCallable = locator.locateResponder("simple") result = responderCallable(amp.Box(greeting="ni hao", cookie="5")) def done(values): - self.assertEquals(values, amp.AmpBox(cookieplus=str(expected))) + self.assertEqual(values, amp.AmpBox(cookieplus=str(expected))) return result.addCallback(done) @@ -765,7 +765,7 @@ PendingDeprecationWarning, "Override locateResponder, not lookupFunction.", __file__, lambda : locator.locateResponder("custom")) - self.assertEquals(locator.customResponder, customResponderObject) + self.assertEqual(locator.customResponder, customResponderObject) # Make sure upcalling works too normalResponderObject = self.assertWarns( PendingDeprecationWarning, @@ -773,7 +773,7 @@ __file__, lambda : locator.locateResponder("simple")) result = normalResponderObject(amp.Box(greeting="ni hao", cookie="5")) def done(values): - self.assertEquals(values, amp.AmpBox(cookieplus='8')) + self.assertEqual(values, amp.AmpBox(cookieplus='8')) return result.addCallback(done) @@ -789,7 +789,7 @@ lambda : locator.lookupFunction("simple")) result = responderCallable(amp.Box(greeting="ni hao", cookie="5")) def done(values): - self.assertEquals(values, amp.AmpBox(cookieplus='8')) + self.assertEqual(values, amp.AmpBox(cookieplus='8')) return result.addCallback(done) @@ -892,7 +892,7 @@ a.stringReceived("hello") a.stringReceived("world") a.stringReceived("") - self.assertEquals(self.boxes, [amp.AmpBox(hello="world")]) + self.assertEqual(self.boxes, [amp.AmpBox(hello="world")]) def test_firstBoxFirstKeyExcessiveLength(self): @@ -961,7 +961,7 @@ a = amp.BinaryBoxProtocol(self) a.dataReceived(amp.Box({"testKey": "valueTest", "anotherKey": "anotherValue"}).serialize()) - self.assertEquals(self.boxes, + self.assertEqual(self.boxes, [amp.Box({"testKey": "valueTest", "anotherKey": "anotherValue"})]) @@ -992,7 +992,7 @@ "someData": "hello"}) a.makeConnection(self) a.sendBox(aBox) - self.assertEquals(''.join(self.data), aBox.serialize()) + self.assertEqual(''.join(self.data), aBox.serialize()) def test_connectionLostStopSendingBoxes(self): @@ -1035,10 +1035,10 @@ moreThanOneBox = anyOldBox.serialize() + "\x00\x00Hello, world!" a.dataReceived(moreThanOneBox) self.assertIdentical(otherProto.transport, self) - self.assertEquals("".join(otherProto.data), "\x00\x00Hello, world!") - self.assertEquals(self.data, ["outgoing data"]) + self.assertEqual("".join(otherProto.data), "\x00\x00Hello, world!") + self.assertEqual(self.data, ["outgoing data"]) a.dataReceived("more data") - self.assertEquals("".join(otherProto.data), + self.assertEqual("".join(otherProto.data), "\x00\x00Hello, world!more data") self.assertRaises(amp.ProtocolSwitched, a.sendBox, anyOldBox) @@ -1053,7 +1053,7 @@ a.makeConnection(self) otherProto = TestProto(None, "") a._switchTo(otherProto) - self.assertEquals(otherProto.data, []) + self.assertEqual(otherProto.data, []) def test_protocolSwitchInvalidStates(self): @@ -1070,7 +1070,7 @@ self.assertRaises(amp.ProtocolSwitched, a.sendBox, sampleBox) a._unlockFromSwitch() a.sendBox(sampleBox) - self.assertEquals(''.join(self.data), sampleBox.serialize()) + self.assertEqual(''.join(self.data), sampleBox.serialize()) a._lockForSwitch() otherProto = TestProto(None, "outgoing data") a._switchTo(otherProto) @@ -1093,7 +1093,7 @@ a._switchTo(connectionLoser) connectionFailure = Failure(RuntimeError()) a.connectionLost(connectionFailure) - self.assertEquals(connectionLoser.reason, connectionFailure) + self.assertEqual(connectionLoser.reason, connectionFailure) def test_protocolSwitchLoseClientConnection(self): @@ -1113,7 +1113,7 @@ a._switchTo(connectionLoser, clientLoser) connectionFailure = Failure(RuntimeError()) a.connectionLost(connectionFailure) - self.assertEquals(clientLoser.reason, connectionFailure) + self.assertEqual(clientLoser.reason, connectionFailure) @@ -1145,7 +1145,7 @@ HELLO = 'world' c.sendHello(HELLO).addCallback(L.append) p.flush() - self.assertEquals(L[0]['hello'], HELLO) + self.assertEqual(L[0]['hello'], HELLO) def test_wireFormatRoundTrip(self): @@ -1158,7 +1158,7 @@ HELLO = 'world' c.sendHello(HELLO).addCallback(L.append) p.flush() - self.assertEquals(L[0]['hello'], HELLO) + self.assertEqual(L[0]['hello'], HELLO) def test_helloWorldUnicode(self): @@ -1173,8 +1173,8 @@ HELLO_UNICODE = 'wor\u1234ld' c.sendUnicodeHello(HELLO, HELLO_UNICODE).addCallback(L.append) p.flush() - self.assertEquals(L[0]['hello'], HELLO) - self.assertEquals(L[0]['Print'], HELLO_UNICODE) + self.assertEqual(L[0]['hello'], HELLO) + self.assertEqual(L[0]['Print'], HELLO_UNICODE) def test_callRemoteStringRequiresAnswerFalse(self): @@ -1202,11 +1202,11 @@ return "OK" c.callRemoteString("WTF").addErrback(clearAndAdd).addCallback(L.append) p.flush() - self.assertEquals(L.pop(), "OK") + self.assertEqual(L.pop(), "OK") HELLO = 'world' c.sendHello(HELLO).addCallback(L.append) p.flush() - self.assertEquals(L[0]['hello'], HELLO) + self.assertEqual(L[0]['hello'], HELLO) def test_unknownCommandHigh(self): @@ -1224,11 +1224,11 @@ return "OK" c.callRemote(WTF).addErrback(clearAndAdd).addCallback(L.append) p.flush() - self.assertEquals(L.pop(), "OK") + self.assertEqual(L.pop(), "OK") HELLO = 'world' c.sendHello(HELLO).addCallback(L.append) p.flush() - self.assertEquals(L[0]['hello'], HELLO) + self.assertEqual(L[0]['hello'], HELLO) def test_brokenReturnValue(self): @@ -1262,16 +1262,16 @@ bonus="I'm not in the book!").addCallback( L.append) p.flush() - self.assertEquals(L[0]['hello'], HELLO) + self.assertEqual(L[0]['hello'], HELLO) def test_simpleReprs(self): """ Verify that the various Box objects repr properly, for debugging. """ - self.assertEquals(type(repr(amp._SwitchBox('a'))), str) - self.assertEquals(type(repr(amp.QuitBox())), str) - self.assertEquals(type(repr(amp.AmpBox())), str) + self.assertEqual(type(repr(amp._SwitchBox('a'))), str) + self.assertEqual(type(repr(amp.QuitBox())), str) + self.assertEqual(type(repr(amp.AmpBox())), str) self.failUnless("AmpBox" in repr(amp.AmpBox())) @@ -1286,7 +1286,7 @@ return {a: 0x1234}.get(obj, id(obj)) self.addCleanup(setIDFunction, setIDFunction(fakeID)) - self.assertEquals( + self.assertEqual( repr(a), " at 0x1234>" % ( otherProto.instanceId,)) @@ -1300,14 +1300,14 @@ def fakeID(obj): return {a: 0x4321}.get(obj, id(obj)) self.addCleanup(setIDFunction, setIDFunction(fakeID)) - self.assertEquals(repr(a), "") + self.assertEqual(repr(a), "") def test_simpleSSLRepr(self): """ L{amp._TLSBox.__repr__} returns a string. """ - self.assertEquals(type(repr(amp._TLSBox())), str) + self.assertEqual(type(repr(amp._TLSBox())), str) test_simpleSSLRepr.skip = skipSSL @@ -1325,7 +1325,7 @@ self.assertTrue(tl.isKey) self.assertTrue(tl.isLocal) self.assertIdentical(tl.keyName, None) - self.assertEquals(tl.value, x) + self.assertEqual(tl.value, x) self.assertIn(str(len(x)), repr(tl)) self.assertIn("key", repr(tl)) @@ -1341,7 +1341,7 @@ p.flush() self.failIf(tl.isKey) self.failUnless(tl.isLocal) - self.assertEquals(tl.keyName, 'hello') + self.assertEqual(tl.keyName, 'hello') self.failUnlessIdentical(tl.value, x) self.failUnless(str(len(x)) in repr(tl)) self.failUnless("value" in repr(tl)) @@ -1360,7 +1360,7 @@ HELLO = 'world' c.sendHello(HELLO).addCallback(L.append) p.flush() - self.assertEquals(L[0]['hello'], HELLO) + self.assertEqual(L[0]['hello'], HELLO) def test_helloErrorHandling(self): @@ -1377,7 +1377,7 @@ c.sendHello(HELLO).addErrback(L.append) p.flush() L[0].trap(UnfriendlyGreeting) - self.assertEquals(str(L[0].value), "Don't be a dick.") + self.assertEqual(str(L[0].value), "Don't be a dick.") def test_helloFatalErrorHandling(self): @@ -1435,7 +1435,7 @@ L = [] c.callRemote(WaitForever).addErrback(L.append) p.flush() - self.assertEquals(L, []) + self.assertEqual(L, []) s.transport.loseConnection() p.flush() L.pop().trap(error.ConnectionDone) @@ -1492,7 +1492,7 @@ c.callRemote(NoAnswerHello, hello="hello") p.flush() le = self.flushLoggedErrors(amp.BadLocalReturn) - self.assertEquals(len(le), 1) + self.assertEqual(len(le), 1) def test_noAnswerResponderAskedForAnswer(self): @@ -1507,8 +1507,8 @@ L = [] c.callRemote(Hello, hello="Hello!").addCallback(L.append) p.flush() - self.assertEquals(len(L), 1) - self.assertEquals(L, [dict(hello="Hello!-noanswer", + self.assertEqual(len(L), 1) + self.assertEqual(L, [dict(hello="Hello!-noanswer", Print=None)]) # Optional response argument @@ -1523,7 +1523,7 @@ c.callRemote(GetList, length=10).addCallback(L.append) p.flush() values = L.pop().get('body') - self.assertEquals(values, [{'x': 1}] * 10) + self.assertEqual(values, [{'x': 1}] * 10) def test_optionalAmpListOmitted(self): @@ -1538,7 +1538,7 @@ c.callRemote(DontRejectMe, magicWord=u'please').addCallback(L.append) p.flush() response = L.pop().get('response') - self.assertEquals(response, 'list omitted') + self.assertEqual(response, 'list omitted') def test_optionalAmpListPresent(self): @@ -1553,7 +1553,7 @@ list=[{'name': 'foo'}]).addCallback(L.append) p.flush() response = L.pop().get('response') - self.assertEquals(response, 'foo accepted') + self.assertEqual(response, 'foo accepted') def test_failEarlyOnArgSending(self): @@ -1611,8 +1611,8 @@ (clientSuccess, clientData))): self.failUnless(serverSuccess) self.failUnless(clientSuccess) - self.assertEquals(''.join(serverData), SWITCH_CLIENT_DATA) - self.assertEquals(''.join(clientData), SWITCH_SERVER_DATA) + self.assertEqual(''.join(serverData), SWITCH_CLIENT_DATA) + self.assertEqual(''.join(clientData), SWITCH_SERVER_DATA) self.testSucceeded = True def cbSwitch(proto): @@ -1703,10 +1703,10 @@ GOODBYE = 'everyone' c.sendHello(HELLO).addCallback(L.append) p.flush() - self.assertEquals(L.pop()['hello'], HELLO) + self.assertEqual(L.pop()['hello'], HELLO) c.callRemote(Goodbye).addCallback(L.append) p.flush() - self.assertEquals(L.pop()['goodbye'], GOODBYE) + self.assertEqual(L.pop()['goodbye'], GOODBYE) c.sendHello(HELLO).addErrback(L.append) L.pop().trap(error.ConnectionDone) @@ -1722,15 +1722,15 @@ c.callRemote(Hello, hello='hello test', mixedCase='mixed case arg test', dash_arg='x', underscore_arg='y') p.flush() - self.assertEquals(len(L), 1) + self.assertEqual(len(L), 1) for k, v in [('_command', Hello.commandName), ('hello', 'hello test'), ('mixedCase', 'mixed case arg test'), ('dash-arg', 'x'), ('underscore_arg', 'y')]: - self.assertEquals(L[-1].pop(k), v) + self.assertEqual(L[-1].pop(k), v) L[-1].pop('_ask') - self.assertEquals(L[-1], {}) + self.assertEqual(L[-1], {}) def test_basicStructuredEmit(self): @@ -1749,8 +1749,8 @@ c.callRemote(Hello, hello='hello test', mixedCase='mixed case arg test', dash_arg='x', underscore_arg='y').addCallback(L.append) p.flush() - self.assertEquals(len(L), 2) - self.assertEquals(L[0], + self.assertEqual(len(L), 2) + self.assertEqual(L[0], ((), dict( hello='hello test', mixedCase='mixed case arg test', @@ -1764,7 +1764,7 @@ Print=None, optional=None, ))) - self.assertEquals(L[1], dict(Print=None, hello='aaa')) + self.assertEqual(L[1], dict(Print=None, hello='aaa')) class PretendRemoteCertificateAuthority: def checkIsPretendRemote(self): @@ -1845,7 +1845,7 @@ cli.callRemote(SecuredPing).addCallback(L.append) p.flush() # once for client once for server - self.assertEquals(okc.verifyCount, 2) + self.assertEqual(okc.verifyCount, 2) L = [] cli.callRemote(SecuredPing).addCallback(L.append) p.flush() @@ -1895,7 +1895,7 @@ p.flush() # once for client once for server - but both fail - self.assertEquals(badCert.verifyCount, 2) + self.assertEqual(badCert.verifyCount, 2) d = cli.callRemote(SecuredPing) p.flush() self.assertFailure(d, iosim.NativeOpenSSLError) @@ -1917,7 +1917,7 @@ p.flush() - self.assertEquals(droppyCert.verifyCount, 2) + self.assertEqual(droppyCert.verifyCount, 2) d = cli.callRemote(SecuredPing) p.flush() @@ -1983,7 +1983,7 @@ svr.sendBox = boxes.append svr.makeConnection(StringTransport()) svr.ampBoxReceived(box) - self.assertEquals(boxes, + self.assertEqual(boxes, [{'_error_code': 'TLS_ERROR', '_error': '1', '_error_description': 'TLS not available'}]) @@ -2222,10 +2222,10 @@ # cert until we negotiate. we should be able to do this in # 'secured' instead, but it looks like we can't. I think this # is a bug somewhere far deeper than here. - self.failUnlessEqual(x, self.cli.hostCertificate.digest()) - self.failUnlessEqual(x, self.cli.peerCertificate.digest()) - self.failUnlessEqual(x, self.svr.hostCertificate.digest()) - self.failUnlessEqual(x, self.svr.peerCertificate.digest()) + self.assertEqual(x, self.cli.hostCertificate.digest()) + self.assertEqual(x, self.cli.peerCertificate.digest()) + self.assertEqual(x, self.svr.hostCertificate.digest()) + self.assertEqual(x, self.svr.peerCertificate.digest()) return self.cli.callRemote(SecuredPing).addCallback(pinged) return self.cli.callRemote(amp.StartTLS, tls_localCertificate=cert, @@ -2441,7 +2441,7 @@ thingy = "weeoo" response = client.callRemote(MagicSchemaCommand, weird=thingy) def gotResponse(ign): - self.assertEquals(client.parseResponseArguments, + self.assertEqual(client.parseResponseArguments, ({"weird": thingy}, client)) response.addCallback(gotResponse) return response @@ -2582,7 +2582,7 @@ strings = amp.AmpBox() for key in self.objects: stringList.toBox(key, strings, self.objects.copy(), None) - self.assertEquals(strings, self.strings) + self.assertEqual(strings, self.strings) def test_fromBox(self): @@ -2593,7 +2593,7 @@ objects = {} for key in self.strings: stringList.fromBox(key, self.strings.copy(), objects, None) - self.assertEquals(objects, self.objects) + self.assertEqual(objects, self.objects) @@ -2836,7 +2836,7 @@ stringList = amp.ListOf(amp.Integer(), optional=True) strings = amp.AmpBox() stringList.toBox('omitted', strings, {'omitted': None}, None) - self.assertEquals(strings, {}) + self.assertEqual(strings, {}) def test_requiredArgumentWithKeyMissingRaisesKeyError(self): @@ -2867,7 +2867,7 @@ stringList = amp.ListOf(amp.Integer(), optional=True) objects = {} stringList.fromBox('omitted', {}, objects, None) - self.assertEquals(objects, {'omitted': None}) + self.assertEqual(objects, {'omitted': None}) @@ -2905,7 +2905,7 @@ """ argument = amp.DateTime() value = argument.fromString(self.string) - self.assertEquals(value, self.object) + self.assertEqual(value, self.object) def test_toString(self): @@ -2916,7 +2916,7 @@ """ argument = amp.DateTime() value = argument.toString(self.object) - self.assertEquals(value, self.string) + self.assertEqual(value, self.string) @@ -2929,21 +2929,21 @@ """ L{amp.utc.tzname} returns C{"+00:00"}. """ - self.assertEquals(amp.utc.tzname(None), '+00:00') + self.assertEqual(amp.utc.tzname(None), '+00:00') def test_dst(self): """ L{amp.utc.dst} returns a zero timedelta. """ - self.assertEquals(amp.utc.dst(None), datetime.timedelta(0)) + self.assertEqual(amp.utc.dst(None), datetime.timedelta(0)) def test_utcoffset(self): """ L{amp.utc.utcoffset} returns a zero timedelta. """ - self.assertEquals(amp.utc.utcoffset(None), datetime.timedelta(0)) + self.assertEqual(amp.utc.utcoffset(None), datetime.timedelta(0)) def test_badSign(self): diff --git a/lib/twisted-trunk/twisted/test/test_application.py b/lib/twisted-trunk/twisted/test/test_application.py --- a/lib/twisted-trunk/twisted/test/test_application.py +++ b/lib/twisted-trunk/twisted/test/test_application.py @@ -28,30 +28,30 @@ def testName(self): s = service.Service() s.setName("hello") - self.failUnlessEqual(s.name, "hello") + self.assertEqual(s.name, "hello") def testParent(self): s = service.Service() p = service.MultiService() s.setServiceParent(p) - self.failUnlessEqual(list(p), [s]) - self.failUnlessEqual(s.parent, p) + self.assertEqual(list(p), [s]) + self.assertEqual(s.parent, p) def testApplicationAsParent(self): s = service.Service() p = service.Application("") s.setServiceParent(p) - self.failUnlessEqual(list(service.IServiceCollection(p)), [s]) - self.failUnlessEqual(s.parent, service.IServiceCollection(p)) + self.assertEqual(list(service.IServiceCollection(p)), [s]) + self.assertEqual(s.parent, service.IServiceCollection(p)) def testNamedChild(self): s = service.Service() p = service.MultiService() s.setName("hello") s.setServiceParent(p) - self.failUnlessEqual(list(p), [s]) - self.failUnlessEqual(s.parent, p) - self.failUnlessEqual(p.getServiceNamed("hello"), s) + self.assertEqual(list(p), [s]) + self.assertEqual(s.parent, p) + self.assertEqual(p.getServiceNamed("hello"), s) def testDoublyNamedChild(self): s = service.Service() @@ -73,11 +73,11 @@ s = service.Service() p = service.MultiService() s.setServiceParent(p) - self.failUnlessEqual(list(p), [s]) - self.failUnlessEqual(s.parent, p) + self.assertEqual(list(p), [s]) + self.assertEqual(s.parent, p) s.disownServiceParent() - self.failUnlessEqual(list(p), []) - self.failUnlessEqual(s.parent, None) + self.assertEqual(list(p), []) + self.assertEqual(s.parent, None) def testRunning(self): s = service.Service() @@ -497,11 +497,11 @@ internet.GenericServer() warnings = self.flushWarnings( offendingFunctions=[self.test_genericServerDeprecated]) - self.assertEquals( + self.assertEqual( warnings[0]['message'], 'GenericServer was deprecated in Twisted 10.1.') - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 1) def test_genericClientDeprecated(self): @@ -511,11 +511,11 @@ internet.GenericClient() warnings = self.flushWarnings( offendingFunctions=[self.test_genericClientDeprecated]) - self.assertEquals( + self.assertEqual( warnings[0]['message'], 'GenericClient was deprecated in Twisted 10.1.') - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 1) def test_everythingThere(self): @@ -540,7 +540,7 @@ self.assertTrue(hasattr(reactor, prefix + method) or (prefix == "connect" and method == "UDP")) o = getattr(internet, tran + side)() - self.assertEquals(service.IService(o), o) + self.assertEqual(service.IService(o), o) test_everythingThere.suppress = [ util.suppress(message='GenericServer was deprecated in Twisted 10.1.', category=DeprecationWarning), @@ -573,7 +573,7 @@ factory = object() t = internet.TCPServer(1234, factory, reactor=reactor) t.startService() - self.assertEquals(reactor.tcpServers.pop()[:2], (1234, factory)) + self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory)) def test_reactorParametrizationInClient(self): @@ -587,7 +587,7 @@ factory = object() t = internet.TCPClient('127.0.0.1', 1234, factory, reactor=reactor) t.startService() - self.assertEquals( + self.assertEqual( reactor.tcpClients.pop()[:3], ('127.0.0.1', 1234, factory)) @@ -601,10 +601,10 @@ factory = object() t = internet.TCPServer(1234, factory, reactor=reactor) t.startService() - self.assertEquals(reactor.tcpServers.pop()[:2], (1234, factory)) + self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory)) t.stopService() t.startService() - self.assertEquals(reactor.tcpServers.pop()[:2], (1234, factory)) + self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory)) def test_reactorParametrizationInClientMultipleStart(self): @@ -617,11 +617,11 @@ factory = object() t = internet.TCPClient('127.0.0.1', 1234, factory, reactor=reactor) t.startService() - self.assertEquals( + self.assertEqual( reactor.tcpClients.pop()[:3], ('127.0.0.1', 1234, factory)) t.stopService() t.startService() - self.assertEquals( + self.assertEqual( reactor.tcpClients.pop()[:3], ('127.0.0.1', 1234, factory)) @@ -832,7 +832,7 @@ options.parseOptions(['--reactor', 'fakereactortest', 'subcommand']) self.assertEqual(executed[0], INSTALL_EVENT) self.assertEqual(executed.count(INSTALL_EVENT), 1) - self.assertEquals(options["reactor"], "fakereactortest") + self.assertEqual(options["reactor"], "fakereactortest") def test_reactorSelectionMixinNonExistent(self): diff --git a/lib/twisted-trunk/twisted/test/test_banana.py b/lib/twisted-trunk/twisted/test/test_banana.py --- a/lib/twisted-trunk/twisted/test/test_banana.py +++ b/lib/twisted-trunk/twisted/test/test_banana.py @@ -54,7 +54,7 @@ for value in (10151, 10151L): self.enc.sendEncoded(value) self.enc.dataReceived(self.io.getvalue()) - self.assertEquals(self.result, 10151) + self.assertEqual(self.result, 10151) self.assertIsInstance(self.result, int) @@ -72,7 +72,7 @@ self.io.truncate(0) self.enc.sendEncoded(n) self.enc.dataReceived(self.io.getvalue()) - self.assertEquals(self.result, n) + self.assertEqual(self.result, n) if n > sys.maxint or n < -sys.maxint - 1: self.assertIsInstance(self.result, long) else: diff --git a/lib/twisted-trunk/twisted/test/test_compat.py b/lib/twisted-trunk/twisted/test/test_compat.py --- a/lib/twisted-trunk/twisted/test/test_compat.py +++ b/lib/twisted-trunk/twisted/test/test_compat.py @@ -32,24 +32,24 @@ def testDict(self): d1 = {'a': 'b'} d2 = dict(d1) - self.assertEquals(d1, d2) + self.assertEqual(d1, d2) d1['a'] = 'c' self.assertNotEquals(d1, d2) d2 = dict(d1.items()) - self.assertEquals(d1, d2) + self.assertEqual(d1, d2) def testBool(self): - self.assertEquals(bool('hi'), True) - self.assertEquals(bool(True), True) - self.assertEquals(bool(''), False) - self.assertEquals(bool(False), False) + self.assertEqual(bool('hi'), True) + self.assertEqual(bool(True), True) + self.assertEqual(bool(''), False) + self.assertEqual(bool(False), False) def testIteration(self): lst1, lst2 = range(10), [] for i in iter(lst1): lst2.append(i) - self.assertEquals(lst1, lst2) + self.assertEqual(lst1, lst2) del lst2[:] try: @@ -58,12 +58,12 @@ lst2.append(iterable.next()) except StopIteration: pass - self.assertEquals(lst1, lst2) + self.assertEqual(lst1, lst2) del lst2[:] for i in iter(IterableCounter(10)): lst2.append(i) - self.assertEquals(lst1, lst2) + self.assertEqual(lst1, lst2) del lst2[:] try: @@ -72,12 +72,12 @@ lst2.append(iterable.next()) except StopIteration: pass - self.assertEquals(lst1, lst2) + self.assertEqual(lst1, lst2) del lst2[:] for i in iter(IterableCounter(20).next, 10): lst2.append(i) - self.assertEquals(lst1, lst2) + self.assertEqual(lst1, lst2) def testIsinstance(self): self.assert_(isinstance(u'hi', types.StringTypes)) @@ -87,20 +87,20 @@ # self.assert_(isinstance({}, dict)) def testStrip(self): - self.assertEquals(' x '.lstrip(' '), 'x ') - self.assertEquals(' x x'.lstrip(' '), 'x x') - self.assertEquals(' x '.rstrip(' '), ' x') - self.assertEquals('x x '.rstrip(' '), 'x x') + self.assertEqual(' x '.lstrip(' '), 'x ') + self.assertEqual(' x x'.lstrip(' '), 'x x') + self.assertEqual(' x '.rstrip(' '), ' x') + self.assertEqual('x x '.rstrip(' '), 'x x') - self.assertEquals('\t x '.lstrip('\t '), 'x ') - self.assertEquals(' \tx x'.lstrip('\t '), 'x x') - self.assertEquals(' x\t '.rstrip(' \t'), ' x') - self.assertEquals('x x \t'.rstrip(' \t'), 'x x') + self.assertEqual('\t x '.lstrip('\t '), 'x ') + self.assertEqual(' \tx x'.lstrip('\t '), 'x x') + self.assertEqual(' x\t '.rstrip(' \t'), ' x') + self.assertEqual('x x \t'.rstrip(' \t'), 'x x') - self.assertEquals('\t x '.strip('\t '), 'x') - self.assertEquals(' \tx x'.strip('\t '), 'x x') - self.assertEquals(' x\t '.strip(' \t'), 'x') - self.assertEquals('x x \t'.strip(' \t'), 'x x') + self.assertEqual('\t x '.strip('\t '), 'x') + self.assertEqual(' \tx x'.strip('\t '), 'x x') + self.assertEqual(' x\t '.strip(' \t'), 'x') + self.assertEqual('x x \t'.strip(' \t'), 'x x') def testNToP(self): from twisted.python.compat import inet_ntop @@ -108,18 +108,18 @@ f = lambda a: inet_ntop(socket.AF_INET6, a) g = lambda a: inet_ntop(socket.AF_INET, a) - self.assertEquals('::', f('\x00' * 16)) - self.assertEquals('::1', f('\x00' * 15 + '\x01')) - self.assertEquals( + self.assertEqual('::', f('\x00' * 16)) + self.assertEqual('::1', f('\x00' * 15 + '\x01')) + self.assertEqual( 'aef:b01:506:1001:ffff:9997:55:170', f('\x0a\xef\x0b\x01\x05\x06\x10\x01\xff\xff\x99\x97\x00\x55\x01\x70')) - self.assertEquals('1.0.1.0', g('\x01\x00\x01\x00')) - self.assertEquals('170.85.170.85', g('\xaa\x55\xaa\x55')) - self.assertEquals('255.255.255.255', g('\xff\xff\xff\xff')) + self.assertEqual('1.0.1.0', g('\x01\x00\x01\x00')) + self.assertEqual('170.85.170.85', g('\xaa\x55\xaa\x55')) + self.assertEqual('255.255.255.255', g('\xff\xff\xff\xff')) - self.assertEquals('100::', f('\x01' + '\x00' * 15)) - self.assertEquals('100::1', f('\x01' + '\x00' * 14 + '\x01')) + self.assertEqual('100::', f('\x01' + '\x00' * 15)) + self.assertEqual('100::1', f('\x01' + '\x00' * 14 + '\x01')) def testPToN(self): from twisted.python.compat import inet_pton @@ -127,20 +127,20 @@ f = lambda a: inet_pton(socket.AF_INET6, a) g = lambda a: inet_pton(socket.AF_INET, a) - self.assertEquals('\x00\x00\x00\x00', g('0.0.0.0')) - self.assertEquals('\xff\x00\xff\x00', g('255.0.255.0')) - self.assertEquals('\xaa\xaa\xaa\xaa', g('170.170.170.170')) + self.assertEqual('\x00\x00\x00\x00', g('0.0.0.0')) + self.assertEqual('\xff\x00\xff\x00', g('255.0.255.0')) + self.assertEqual('\xaa\xaa\xaa\xaa', g('170.170.170.170')) - self.assertEquals('\x00' * 16, f('::')) - self.assertEquals('\x00' * 16, f('0::0')) - self.assertEquals('\x00\x01' + '\x00' * 14, f('1::')) - self.assertEquals( + self.assertEqual('\x00' * 16, f('::')) + self.assertEqual('\x00' * 16, f('0::0')) + self.assertEqual('\x00\x01' + '\x00' * 14, f('1::')) + self.assertEqual( '\x45\xef\x76\xcb\x00\x1a\x56\xef\xaf\xeb\x0b\xac\x19\x24\xae\xae', f('45ef:76cb:1a:56ef:afeb:bac:1924:aeae')) - self.assertEquals('\x00' * 14 + '\x00\x01', f('::1')) - self.assertEquals('\x00' * 12 + '\x01\x02\x03\x04', f('::1.2.3.4')) - self.assertEquals( + self.assertEqual('\x00' * 14 + '\x00\x01', f('::1')) + self.assertEqual('\x00' * 12 + '\x01\x02\x03\x04', f('::1.2.3.4')) + self.assertEqual( '\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x01\x02\x03\xff', f('1:2:3:4:5:6:1.2.3.255')) @@ -161,11 +161,11 @@ a.add('a') b = list(a) b.sort() - self.assertEquals(b, ['a', 'b', 'c']) + self.assertEqual(b, ['a', 'b', 'c']) a.remove('b') b = list(a) b.sort() - self.assertEquals(b, ['a', 'c']) + self.assertEqual(b, ['a', 'c']) a.discard('d') @@ -173,7 +173,7 @@ d = a.union(b) b = list(d) b.sort() - self.assertEquals(b, ['a', 'c', 'r', 's']) + self.assertEqual(b, ['a', 'c', 'r', 's']) def test_frozenset(self): @@ -182,18 +182,18 @@ """ a = frozenset(['a', 'b']) self.assertRaises(AttributeError, getattr, a, "add") - self.assertEquals(list(a), ['a', 'b']) + self.assertEqual(list(a), ['a', 'b']) b = frozenset(['r', 's']) d = a.union(b) b = list(d) b.sort() - self.assertEquals(b, ['a', 'b', 'r', 's']) + self.assertEqual(b, ['a', 'b', 'r', 's']) def test_reduce(self): """ L{reduce} should behave like the builtin reduce. """ - self.assertEquals(15, reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])) - self.assertEquals(16, reduce(lambda x, y: x + y, [1, 2, 3, 4, 5], 1)) + self.assertEqual(15, reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])) + self.assertEqual(16, reduce(lambda x, y: x + y, [1, 2, 3, 4, 5], 1)) diff --git a/lib/twisted-trunk/twisted/test/test_context.py b/lib/twisted-trunk/twisted/test/test_context.py --- a/lib/twisted-trunk/twisted/test/test_context.py +++ b/lib/twisted-trunk/twisted/test/test_context.py @@ -10,6 +10,6 @@ class ContextTest(TestCase): def testBasicContext(self): - self.assertEquals(context.get("x"), None) - self.assertEquals(context.call({"x": "y"}, context.get, "x"), "y") - self.assertEquals(context.get("x"), None) + self.assertEqual(context.get("x"), None) + self.assertEqual(context.call({"x": "y"}, context.get, "x"), "y") + self.assertEqual(context.get("x"), None) diff --git a/lib/twisted-trunk/twisted/test/test_cooperator.py b/lib/twisted-trunk/twisted/test/test_cooperator.py --- a/lib/twisted-trunk/twisted/test/test_cooperator.py +++ b/lib/twisted-trunk/twisted/test/test_cooperator.py @@ -85,7 +85,7 @@ d.addCallback(self.cbIter) d.addErrback(self.ebIter) return d.addCallback(lambda result: - self.assertEquals(result, self.RESULT)) + self.assertEqual(result, self.RESULT)) return testwith(None).addCallback(lambda ign: testwith(defer.Deferred())) @@ -104,8 +104,8 @@ d.addErrback(self.ebIter) c.stop() def doasserts(result): - self.assertEquals(result, self.RESULT) - self.assertEquals(myiter.value, -1) + self.assertEqual(result, self.RESULT) + self.assertEqual(myiter.value, -1) d.addCallback(doasserts) return d @@ -133,7 +133,7 @@ d.addErrback(self.ebIter) return d.addCallback( - lambda result: self.assertEquals(result, self.RESULT)) + lambda result: self.assertEqual(result, self.RESULT)) def testUnexpectedError(self): @@ -182,7 +182,7 @@ tasks.append(c.coiterate(myiter(stuff))) return defer.DeferredList(tasks).addCallback( - lambda ign: self.assertEquals(tuple(L), sum(zip(*groupsOfThings), ()))) + lambda ign: self.assertEqual(tuple(L), sum(zip(*groupsOfThings), ()))) def testResourceExhaustion(self): @@ -207,7 +207,7 @@ c._tick() c.stop() self.failUnless(_TPF.stopped) - self.assertEquals(output, range(10)) + self.assertEqual(output, range(10)) def testCallbackReCoiterate(self): @@ -371,20 +371,20 @@ """ # first, sanity check self.scheduler.pump() - self.assertEquals(self.work, [1]) + self.assertEqual(self.work, [1]) self.scheduler.pump() - self.assertEquals(self.work, [1, 2]) + self.assertEqual(self.work, [1, 2]) # OK, now for real self.task.pause() self.scheduler.pump() - self.assertEquals(self.work, [1, 2]) + self.assertEqual(self.work, [1, 2]) self.task.resume() # Resuming itself shoult not do any work - self.assertEquals(self.work, [1, 2]) + self.assertEqual(self.work, [1, 2]) self.scheduler.pump() # But when the scheduler rolls around again... - self.assertEquals(self.work, [1, 2, 3]) + self.assertEqual(self.work, [1, 2, 3]) def test_resumeNotPaused(self): @@ -407,19 +407,19 @@ # pause once self.task.pause() self.scheduler.pump() - self.assertEquals(self.work, []) + self.assertEqual(self.work, []) # pause twice self.task.pause() self.scheduler.pump() - self.assertEquals(self.work, []) + self.assertEqual(self.work, []) # resume once (it shouldn't) self.task.resume() self.scheduler.pump() - self.assertEquals(self.work, []) + self.assertEqual(self.work, []) # resume twice (now it should go) self.task.resume() self.scheduler.pump() - self.assertEquals(self.work, [1]) + self.assertEqual(self.work, [1]) def test_pauseWhileDeferred(self): @@ -431,20 +431,20 @@ """ self.deferNext() self.scheduler.pump() - self.assertEquals(len(self.work), 1) + self.assertEqual(len(self.work), 1) self.failUnless(isinstance(self.work[0], defer.Deferred)) self.scheduler.pump() - self.assertEquals(len(self.work), 1) + self.assertEqual(len(self.work), 1) self.task.pause() self.scheduler.pump() - self.assertEquals(len(self.work), 1) + self.assertEqual(len(self.work), 1) self.task.resume() self.scheduler.pump() - self.assertEquals(len(self.work), 1) + self.assertEqual(len(self.work), 1) self.work[0].callback("STUFF!") self.scheduler.pump() - self.assertEquals(len(self.work), 2) - self.assertEquals(self.work[1], 2) + self.assertEqual(len(self.work), 2) + self.assertEqual(self.work[1], 2) def test_whenDone(self): @@ -481,14 +481,14 @@ self.stopNext() self.scheduler.pump() - self.assertEquals(len(results1), 1) - self.assertEquals(len(results2), 1) + self.assertEqual(len(results1), 1) + self.assertEqual(len(results2), 1) self.assertIdentical(results1[0], self.task._iterator) self.assertIdentical(results2[0], self.task._iterator) - self.assertEquals(final1, [1]) - self.assertEquals(final2, [2]) + self.assertEqual(final1, [1]) + self.assertEqual(final2, [2]) def test_whenDoneError(self): @@ -502,8 +502,8 @@ deferred1.addErrback(results.append) self.dieNext() self.scheduler.pump() - self.assertEquals(len(results), 1) - self.assertEquals(results[0].check(UnhandledException), UnhandledException) + self.assertEqual(len(results), 1) + self.assertEqual(results[0].check(UnhandledException), UnhandledException) def test_whenDoneStop(self): @@ -516,8 +516,8 @@ errors = [] deferred1.addErrback(errors.append) self.task.stop() - self.assertEquals(len(errors), 1) - self.assertEquals(errors[0].check(task.TaskStopped), task.TaskStopped) + self.assertEqual(len(errors), 1) + self.assertEqual(errors[0].check(task.TaskStopped), task.TaskStopped) def test_whenDoneAlreadyDone(self): @@ -529,7 +529,7 @@ self.scheduler.pump() results = [] self.task.whenDone().addCallback(results.append) - self.assertEquals(results, [self.task._iterator]) + self.assertEqual(results, [self.task._iterator]) def test_stopStops(self): @@ -540,12 +540,12 @@ """ self.task.stop() self.scheduler.pump() - self.assertEquals(len(self.work), 0) + self.assertEqual(len(self.work), 0) self.assertRaises(task.TaskStopped, self.task.stop) self.assertRaises(task.TaskStopped, self.task.pause) # Sanity check - it's still not scheduled, is it? self.scheduler.pump() - self.assertEquals(self.work, []) + self.assertEqual(self.work, []) def test_pauseStopResume(self): @@ -558,7 +558,7 @@ self.task.stop() self.task.resume() self.scheduler.pump() - self.assertEquals(self.work, []) + self.assertEqual(self.work, []) def test_stopDeferred(self): @@ -571,7 +571,7 @@ self.deferNext() self.scheduler.pump() d = self.work.pop() - self.assertEquals(self.task._pauseCount, 1) + self.assertEqual(self.task._pauseCount, 1) results = [] d.addBoth(results.append) self.scheduler.pump() @@ -583,9 +583,9 @@ # unhandled error that will be logged. The value is None, rather than # our test value, 7, because this Deferred is returned to and consumed # by the cooperator code. Its callback therefore has no contract. - self.assertEquals(results, [None]) + self.assertEqual(results, [None]) # But more importantly, no further work should have happened. - self.assertEquals(self.work, []) + self.assertEqual(self.work, []) def test_stopExhausted(self): @@ -628,7 +628,7 @@ self.task.whenDone().addCallback(stopit) self.stopNext() self.scheduler.pump() - self.assertEquals(callbackPhases, [self.task._iterator, "done"]) + self.assertEqual(callbackPhases, [self.task._iterator, "done"]) diff --git a/lib/twisted-trunk/twisted/test/test_defer.py b/lib/twisted-trunk/twisted/test/test_defer.py --- a/lib/twisted-trunk/twisted/test/test_defer.py +++ b/lib/twisted-trunk/twisted/test/test_defer.py @@ -24,6 +24,8 @@ self.callbackResults = None self.errbackResults = None self.callback2Results = None + # Restore the debug flag to its original state when done. + self.addCleanup(defer.setDebugging, defer.getDebugging()) def _callback(self, *args, **kw): self.callbackResults = args, kw @@ -39,22 +41,22 @@ deferred = defer.Deferred() deferred.addCallback(self._callback) deferred.callback("hello") - self.failUnlessEqual(self.errbackResults, None) - self.failUnlessEqual(self.callbackResults, (('hello',), {})) + self.assertEqual(self.errbackResults, None) + self.assertEqual(self.callbackResults, (('hello',), {})) def testCallbackWithArgs(self): deferred = defer.Deferred() deferred.addCallback(self._callback, "world") deferred.callback("hello") - self.failUnlessEqual(self.errbackResults, None) - self.failUnlessEqual(self.callbackResults, (('hello', 'world'), {})) + self.assertEqual(self.errbackResults, None) + self.assertEqual(self.callbackResults, (('hello', 'world'), {})) def testCallbackWithKwArgs(self): deferred = defer.Deferred() deferred.addCallback(self._callback, world="world") deferred.callback("hello") - self.failUnlessEqual(self.errbackResults, None) - self.failUnlessEqual(self.callbackResults, + self.assertEqual(self.errbackResults, None) + self.assertEqual(self.callbackResults, (('hello',), {'world': 'world'})) def testTwoCallbacks(self): @@ -62,10 +64,10 @@ deferred.addCallback(self._callback) deferred.addCallback(self._callback2) deferred.callback("hello") - self.failUnlessEqual(self.errbackResults, None) - self.failUnlessEqual(self.callbackResults, + self.assertEqual(self.errbackResults, None) + self.assertEqual(self.callbackResults, (('hello',), {})) - self.failUnlessEqual(self.callback2Results, + self.assertEqual(self.callback2Results, (('hello',), {})) def testDeferredList(self): @@ -89,7 +91,7 @@ # it from flunking the test. defr2.errback(GenericError("2")) defr3.callback("3") - self.failUnlessEqual([result[0], + self.assertEqual([result[0], #result[1][1] is now a Failure instead of an Exception (result[1][0], str(result[1][1].value)), result[2]], @@ -105,12 +107,12 @@ dl = defer.DeferredList([]) dl.addCallbacks(cb) - self.failUnlessEqual(result, [[]]) + self.assertEqual(result, [[]]) result[:] = [] dl = defer.DeferredList([], fireOnOneCallback=1) dl.addCallbacks(cb) - self.failUnlessEqual(result, []) + self.assertEqual(result, []) def testDeferredListFireOnOneError(self): defr1 = defer.Deferred() @@ -128,11 +130,11 @@ # fire one Deferred's callback, no result yet defr1.callback("1") - self.failUnlessEqual(result, []) + self.assertEqual(result, []) # fire one Deferred's errback -- now we have a result defr2.errback(GenericError("from def2")) - self.failUnlessEqual(len(result), 1) + self.assertEqual(len(result), 1) # extract the result from the list aFailure = result[0] @@ -147,9 +149,9 @@ # check that the GenericError("2") from the deferred at index 1 # (defr2) is intact inside failure.value - self.failUnlessEqual(firstError.subFailure.type, GenericError) - self.failUnlessEqual(firstError.subFailure.value.args, ("from def2",)) - self.failUnlessEqual(firstError.index, 1) + self.assertEqual(firstError.subFailure.type, GenericError) + self.assertEqual(firstError.subFailure.value.args, ("from def2",)) + self.assertEqual(firstError.index, 1) def testDeferredListDontConsumeErrors(self): @@ -163,9 +165,9 @@ dl.addCallback(result.append) d1.errback(GenericError('Bang')) - self.failUnlessEqual('Bang', errorTrap[0].value.args[0]) - self.failUnlessEqual(1, len(result)) - self.failUnlessEqual('Bang', result[0][0][1].value.args[0]) + self.assertEqual('Bang', errorTrap[0].value.args[0]) + self.assertEqual(1, len(result)) + self.assertEqual('Bang', result[0][0][1].value.args[0]) def testDeferredListConsumeErrors(self): d1 = defer.Deferred() @@ -178,9 +180,9 @@ dl.addCallback(result.append) d1.errback(GenericError('Bang')) - self.failUnlessEqual([], errorTrap) - self.failUnlessEqual(1, len(result)) - self.failUnlessEqual('Bang', result[0][0][1].value.args[0]) + self.assertEqual([], errorTrap) + self.assertEqual(1, len(result)) + self.assertEqual('Bang', result[0][0][1].value.args[0]) def testDeferredListFireOnOneErrorWithAlreadyFiredDeferreds(self): # Create some deferreds, and errback one @@ -192,7 +194,7 @@ dl = defer.DeferredList([d1, d2], fireOnOneErrback=True) result = [] dl.addErrback(result.append) - self.failUnlessEqual(1, len(result)) + self.assertEqual(1, len(result)) d1.addErrback(lambda e: None) # Swallow error @@ -209,7 +211,7 @@ result = [] dl.addCallback(result.append) - self.failUnlessEqual(1, len(result)) + self.assertEqual(1, len(result)) d1.addErrback(lambda e: None) # Swallow error @@ -218,23 +220,23 @@ l = [] d = defer.succeed("success") d.addCallback(l.append) - self.assertEquals(l, ["success"]) + self.assertEqual(l, ["success"]) def testImmediateFailure(self): l = [] d = defer.fail(GenericError("fail")) d.addErrback(l.append) - self.assertEquals(str(l[0].value), "fail") + self.assertEqual(str(l[0].value), "fail") def testPausedFailure(self): l = [] d = defer.fail(GenericError("fail")) d.pause() d.addErrback(l.append) - self.assertEquals(l, []) + self.assertEqual(l, []) d.unpause() - self.assertEquals(str(l[0].value), "fail") + self.assertEqual(str(l[0].value), "fail") def testCallbackErrors(self): l = [] @@ -283,9 +285,9 @@ result = [] chained.addCallback(result.append) - self.assertEquals(result, []) + self.assertEqual(result, []) paused.unpause() - self.assertEquals(result, [expected]) + self.assertEqual(result, [expected]) def test_pausedDeferredChained(self): @@ -302,19 +304,19 @@ second.callback(None) result = [] second.addCallback(result.append) - self.assertEquals(result, [None]) + self.assertEqual(result, [None]) def testGatherResults(self): # test successful list of deferreds l = [] defer.gatherResults([defer.succeed(1), defer.succeed(2)]).addCallback(l.append) - self.assertEquals(l, [[1, 2]]) + self.assertEqual(l, [[1, 2]]) # test failing list of deferreds l = [] dl = [defer.succeed(1), defer.fail(ValueError)] defer.gatherResults(dl).addErrback(l.append) - self.assertEquals(len(l), 1) + self.assertEqual(len(l), 1) self.assert_(isinstance(l[0], failure.Failure)) # get rid of error dl[1].addErrback(lambda e: 1) @@ -328,8 +330,8 @@ S, E = [], [] d = defer.maybeDeferred((lambda x: x + 5), 10) d.addCallbacks(S.append, E.append) - self.assertEquals(E, []) - self.assertEquals(S, [15]) + self.assertEqual(E, []) + self.assertEqual(S, [15]) return d @@ -345,9 +347,9 @@ expected = str(e) d = defer.maybeDeferred((lambda x: x + 5), '10') d.addCallbacks(S.append, E.append) - self.assertEquals(S, []) - self.assertEquals(len(E), 1) - self.assertEquals(str(E[0].value), expected) + self.assertEqual(S, []) + self.assertEqual(len(E), 1) + self.assertEqual(str(E[0].value), expected) return d @@ -359,7 +361,7 @@ d = defer.Deferred() d2 = defer.maybeDeferred(lambda: d) d.callback('Success') - return d2.addCallback(self.assertEquals, 'Success') + return d2.addCallback(self.assertEqual, 'Success') def test_maybeDeferredAsyncError(self): @@ -442,10 +444,10 @@ outer = defer.succeed('outer') outer.addCallback(cb) outer.addErrback(failures.append) - self.assertEquals([('cb', 'outer'), ('firstCallback', None)], results) + self.assertEqual([('cb', 'outer'), ('firstCallback', None)], results) a.callback('withers') - self.assertEquals([], failures) - self.assertEquals( + self.assertEqual([], failures) + self.assertEqual( results, [('cb', 'outer'), ('firstCallback', None), @@ -484,10 +486,10 @@ outer.addCallback(lambda x: results.append('final')) outer.addErrback(failures.append) outer.callback('outer') - self.assertEquals([('cb', 'outer'), ('firstCallback', None)], results) + self.assertEqual([('cb', 'outer'), ('firstCallback', None)], results) a.callback('withers') - self.assertEquals([], failures) - self.assertEquals( + self.assertEqual([], failures) + self.assertEqual( results, [('cb', 'outer'), ('firstCallback', None), @@ -526,7 +528,7 @@ def callback1(result): called.append(1) deferred.addCallback(callback2) - self.assertEquals(called, [1]) + self.assertEqual(called, [1]) deferred.addCallback(callback1) deferred.callback(None) self.assertEqual(called, [1, 2]) @@ -590,14 +592,14 @@ secondResult = [] second.addCallback(secondResult.append) - self.assertEquals(firstResult, []) - self.assertEquals(secondResult, []) + self.assertEqual(firstResult, []) + self.assertEqual(secondResult, []) result = object() first.callback(result) - self.assertEquals(firstResult, [None]) - self.assertEquals(secondResult, [result]) + self.assertEqual(firstResult, [None]) + self.assertEqual(secondResult, [result]) def test_synchronousImplicitErrorChain(self): @@ -638,13 +640,13 @@ secondResult = [] second.addCallback(secondResult.append) - self.assertEquals(firstResult, []) - self.assertEquals(secondResult, []) + self.assertEqual(firstResult, []) + self.assertEqual(secondResult, []) first.errback(RuntimeError("First Deferred's Failure")) - self.assertEquals(firstResult, [None]) - self.assertEquals(len(secondResult), 1) + self.assertEqual(firstResult, [None]) + self.assertEqual(len(secondResult), 1) def test_doubleAsynchronousImplicitChaining(self): @@ -671,12 +673,12 @@ third.callback(None) # Still waiting - self.assertEquals(thirdResult, []) + self.assertEqual(thirdResult, []) # This will tell second to continue which will tell third to continue. first.callback(result) - self.assertEquals(thirdResult, [result]) + self.assertEqual(thirdResult, [result]) def test_nestedAsynchronousChainedDeferreds(self): @@ -717,7 +719,7 @@ outer.addCallback(results.append) # At this point, the callback 'cb' has been entered, and the first # callback of 'd' has been called. - self.assertEquals( + self.assertEqual( results, [('start-of-cb', 'outer'), ('firstCallback', 'inner')]) # Once the inner Deferred is fired, processing of the outer Deferred's @@ -727,10 +729,10 @@ # Make sure there are no errors. inner.addErrback(failures.append) outer.addErrback(failures.append) - self.assertEquals( + self.assertEqual( [], failures, "Got errbacks but wasn't expecting any.") - self.assertEquals( + self.assertEqual( results, [('start-of-cb', 'outer'), ('firstCallback', 'inner'), @@ -782,7 +784,7 @@ outer.addCallback(results.append) # At this point, the callback 'cb' has been entered, and the first # callback of 'd' has been called. - self.assertEquals( + self.assertEqual( results, [('start-of-cb', 'outer'), ('firstCallback', 'inner')]) # Once the inner Deferred is fired, processing of the outer Deferred's @@ -792,10 +794,10 @@ # Make sure there are no errors. outer.addErrback(failures.append) inner.addErrback(failures.append) - self.assertEquals( + self.assertEqual( [], failures, "Got errbacks but wasn't expecting any.") - self.assertEquals( + self.assertEqual( results, [('start-of-cb', 'outer'), ('firstCallback', 'inner'), @@ -849,7 +851,7 @@ """ d = defer.Deferred() address = hex(unsignedID(d)) - self.assertEquals( + self.assertEqual( repr(d), '' % (address,)) @@ -860,7 +862,7 @@ """ d = defer.Deferred() d.callback('orange') - self.assertEquals( + self.assertEqual( repr(d), "" % ( hex(unsignedID(d)))) @@ -874,7 +876,7 @@ a = defer.Deferred() b = defer.Deferred() b.chainDeferred(a) - self.assertEquals( + self.assertEqual( repr(a), "" % ( hex(unsignedID(a)), hex(unsignedID(b)))) @@ -910,7 +912,7 @@ # Sanity check - the record callback is not intended to have # fired yet. - self.assertEquals(stack, []) + self.assertEqual(stack, []) # Now fire the last thing and return the stack depth at which the # callback was invoked. @@ -919,7 +921,7 @@ # Callbacks should be invoked at the same stack depth regardless of # how many Deferreds are chained. - self.assertEquals(chainDeferreds(1), chainDeferreds(2)) + self.assertEqual(chainDeferreds(1), chainDeferreds(2)) def test_resultOfDeferredResultOfDeferredOfFiredDeferredCalled(self): @@ -943,7 +945,89 @@ third.callback(None) L = [] second.addCallback(L.append) - self.assertEquals(L, [None]) + self.assertEqual(L, [None]) + + + def test_errbackWithNoArgsNoDebug(self): + """ + C{Deferred.errback()} creates a failure from the current Python + exception. When Deferred.debug is not set no globals or locals are + captured in that failure. + """ + defer.setDebugging(False) + d = defer.Deferred() + l = [] + exc = GenericError("Bang") + try: + raise exc + except: + d.errback() + d.addErrback(l.append) + fail = l[0] + self.assertEqual(fail.value, exc) + localz, globalz = fail.frames[0][-2:] + self.assertEqual([], localz) + self.assertEqual([], globalz) + + + def test_errbackWithNoArgs(self): + """ + C{Deferred.errback()} creates a failure from the current Python + exception. When Deferred.debug is set globals and locals are captured + in that failure. + """ + defer.setDebugging(True) + d = defer.Deferred() + l = [] + exc = GenericError("Bang") + try: + raise exc + except: + d.errback() + d.addErrback(l.append) + fail = l[0] + self.assertEqual(fail.value, exc) + localz, globalz = fail.frames[0][-2:] + self.assertNotEquals([], localz) + self.assertNotEquals([], globalz) + + + def test_errorInCallbackDoesNotCaptureVars(self): + """ + An error raised by a callback creates a Failure. The Failure captures + locals and globals if and only if C{Deferred.debug} is set. + """ + d = defer.Deferred() + d.callback(None) + defer.setDebugging(False) + def raiseError(ignored): + raise GenericError("Bang") + d.addCallback(raiseError) + l = [] + d.addErrback(l.append) + fail = l[0] + localz, globalz = fail.frames[0][-2:] + self.assertEqual([], localz) + self.assertEqual([], globalz) + + + def test_errorInCallbackCapturesVarsWhenDebugging(self): + """ + An error raised by a callback creates a Failure. The Failure captures + locals and globals if and only if C{Deferred.debug} is set. + """ + d = defer.Deferred() + d.callback(None) + defer.setDebugging(True) + def raiseError(ignored): + raise GenericError("Bang") + d.addCallback(raiseError) + l = [] + d.addErrback(l.append) + fail = l[0] + localz, globalz = fail.frames[0][-2:] + self.assertNotEquals([], localz) + self.assertNotEquals([], globalz) @@ -1192,8 +1276,8 @@ d = defer.Deferred() d.addCallbacks(self._callback, self._errback) d.cancel() - self.assertEquals(self.errbackResults.type, defer.CancelledError) - self.assertEquals(self.callbackResults, None) + self.assertEqual(self.errbackResults.type, defer.CancelledError) + self.assertEqual(self.callbackResults, None) def test_raisesAfterCancelAndCallback(self): @@ -1256,12 +1340,12 @@ d = defer.Deferred() d.addCallbacks(self._callback, self._errback) d.cancel() - self.assertEquals(self.errbackResults.type, defer.CancelledError) + self.assertEqual(self.errbackResults.type, defer.CancelledError) currentFailure = self.errbackResults # One errback will be ignored d.errback(GenericError()) # I.e., we should still have a CancelledError. - self.assertEquals(self.errbackResults.type, defer.CancelledError) + self.assertEqual(self.errbackResults.type, defer.CancelledError) d.cancel() self.assertIdentical(currentFailure, self.errbackResults) @@ -1275,7 +1359,7 @@ d = defer.Deferred() d.addCallbacks(self._callback, self._errback) d.cancel() - self.assertEquals(self.errbackResults.type, defer.CancelledError) + self.assertEqual(self.errbackResults.type, defer.CancelledError) currentFailure = self.errbackResults d.cancel() self.assertIdentical(currentFailure, self.errbackResults) @@ -1295,11 +1379,11 @@ d = defer.Deferred(canceller=cancel) d.addCallbacks(self._callback, self._errback) d.cancel() - self.assertEquals(self.errbackResults.type, defer.CancelledError) + self.assertEqual(self.errbackResults.type, defer.CancelledError) currentFailure = self.errbackResults d.cancel() self.assertIdentical(currentFailure, self.errbackResults) - self.assertEquals(self.cancellerCallCount, 1) + self.assertEqual(self.cancellerCallCount, 1) def test_simpleCanceller(self): @@ -1314,8 +1398,8 @@ d = defer.Deferred(canceller=cancel) d.addCallbacks(self._callback, self._errback) d.cancel() - self.assertEquals(self.cancellerCallCount, 1) - self.assertEquals(self.errbackResults.type, defer.CancelledError) + self.assertEqual(self.cancellerCallCount, 1) + self.assertEqual(self.errbackResults.type, defer.CancelledError) # Test that further call/errbacks are *not* swallowed self.assertRaises(defer.AlreadyCalledError, d.callback, None) @@ -1345,9 +1429,9 @@ d.addCallbacks(self._callback, self._errback) d.callback('biff!') d.cancel() - self.assertEquals(self.cancellerCallCount, 0) - self.assertEquals(self.errbackResults, None) - self.assertEquals(self.callbackResults, 'biff!') + self.assertEqual(self.cancellerCallCount, 0) + self.assertEqual(self.errbackResults, None) + self.assertEqual(self.callbackResults, 'biff!') def test_cancelAfterErrback(self): @@ -1362,9 +1446,9 @@ d.addCallbacks(self._callback, self._errback) d.errback(GenericError()) d.cancel() - self.assertEquals(self.cancellerCallCount, 0) - self.assertEquals(self.errbackResults.type, GenericError) - self.assertEquals(self.callbackResults, None) + self.assertEqual(self.cancellerCallCount, 0) + self.assertEqual(self.errbackResults.type, GenericError) + self.assertEqual(self.callbackResults, None) def test_cancellerThatErrbacks(self): @@ -1377,8 +1461,8 @@ d = defer.Deferred(canceller=cancel) d.addCallbacks(self._callback, self._errback) d.cancel() - self.assertEquals(self.cancellerCallCount, 1) - self.assertEquals(self.errbackResults.type, GenericError) + self.assertEqual(self.cancellerCallCount, 1) + self.assertEqual(self.errbackResults.type, GenericError) def test_cancellerThatCallbacks(self): @@ -1391,9 +1475,9 @@ d = defer.Deferred(canceller=cancel) d.addCallbacks(self._callback, self._errback) d.cancel() - self.assertEquals(self.cancellerCallCount, 1) - self.assertEquals(self.callbackResults, 'hello!') - self.assertEquals(self.errbackResults, None) + self.assertEqual(self.cancellerCallCount, 1) + self.assertEqual(self.callbackResults, 'hello!') + self.assertEqual(self.errbackResults, None) def test_cancelNestedDeferred(self): @@ -1414,10 +1498,10 @@ a.cancel() a.addCallbacks(self._callback, self._errback) # The cancel count should be one (the cancellation done by B) - self.assertEquals(self.cancellerCallCount, 1) + self.assertEqual(self.cancellerCallCount, 1) # B's canceller didn't errback, so defer.py will have called errback # with a CancelledError. - self.assertEquals(self.errbackResults.type, defer.CancelledError) + self.assertEqual(self.errbackResults.type, defer.CancelledError) @@ -1449,7 +1533,7 @@ Check the output of the log observer to see if the error is present. """ c2 = self._loggedErrors() - self.assertEquals(len(c2), 2) + self.assertEqual(len(c2), 2) c2[1]["failure"].trap(ZeroDivisionError) self.flushLoggedErrors(ZeroDivisionError) @@ -1506,8 +1590,8 @@ results = [] errors = [] d.addCallbacks(results.append, errors.append) - self.assertEquals(results, []) - self.assertEquals(len(errors), 1) + self.assertEqual(results, []) + self.assertEqual(len(errors), 1) errors[0].trap(Exception) # Get rid of any references we might have to the inner Deferred (none of @@ -1517,7 +1601,7 @@ # logged, if it's going to be logged. gc.collect() # And make sure it is not. - self.assertEquals(self._loggedErrors(), []) + self.assertEqual(self._loggedErrors(), []) def test_errorClearedByChaining(self): @@ -1535,7 +1619,7 @@ # so nothing should be logged. good = bad = None gc.collect() - self.assertEquals(self._loggedErrors(), []) + self.assertEqual(self._loggedErrors(), []) @@ -1550,7 +1634,7 @@ def cb_empty(self, res): self.callbackRan = 1 - self.failUnlessEqual([], res) + self.assertEqual([], res) def tearDown(self): self.failUnless(self.callbackRan, "Callback was never run.") @@ -1566,19 +1650,19 @@ lock = defer.DeferredLock() lock.acquire().addCallback(self._incr) self.failUnless(lock.locked) - self.assertEquals(self.counter, 1) + self.assertEqual(self.counter, 1) lock.acquire().addCallback(self._incr) self.failUnless(lock.locked) - self.assertEquals(self.counter, 1) + self.assertEqual(self.counter, 1) lock.release() self.failUnless(lock.locked) - self.assertEquals(self.counter, 2) + self.assertEqual(self.counter, 2) lock.release() self.failIf(lock.locked) - self.assertEquals(self.counter, 2) + self.assertEqual(self.counter, 2) self.assertRaises(TypeError, lock.run) @@ -1592,22 +1676,22 @@ resultDeferred = lock.run(helper, self=self, b=firstUnique) self.failUnless(lock.locked) - self.assertEquals(self.b, firstUnique) + self.assertEqual(self.b, firstUnique) resultDeferred.addCallback(lambda x: setattr(self, 'result', x)) lock.acquire().addCallback(self._incr) self.failUnless(lock.locked) - self.assertEquals(self.counter, 2) + self.assertEqual(self.counter, 2) controlDeferred.callback(secondUnique) - self.assertEquals(self.result, secondUnique) + self.assertEqual(self.result, secondUnique) self.failUnless(lock.locked) - self.assertEquals(self.counter, 3) + self.assertEqual(self.counter, 3) d = lock.acquire().addBoth(lambda x: setattr(self, 'result', x)) d.cancel() - self.assertEquals(self.result.type, defer.CancelledError) + self.assertEqual(self.result.type, defer.CancelledError) lock.release() self.failIf(lock.locked) @@ -1653,16 +1737,16 @@ resultDeferred = sem.run(helper, self=self, arg=uniqueObject) resultDeferred.addCallback(results.append) resultDeferred.addCallback(self._incr) - self.assertEquals(results, []) - self.assertEquals(self.arg, uniqueObject) + self.assertEqual(results, []) + self.assertEqual(self.arg, uniqueObject) controlDeferred.callback(None) - self.assertEquals(results.pop(), None) - self.assertEquals(self.counter, 1) + self.assertEqual(results.pop(), None) + self.assertEqual(self.counter, 1) self.counter = 0 for i in range(1, 1 + N): sem.acquire().addCallback(self._incr) - self.assertEquals(self.counter, i) + self.assertEqual(self.counter, i) success = [] @@ -1672,17 +1756,17 @@ success.append(True) d = sem.acquire().addCallbacks(fail, succeed) d.cancel() - self.assertEquals(success, [True]) + self.assertEqual(success, [True]) sem.acquire().addCallback(self._incr) - self.assertEquals(self.counter, N) + self.assertEqual(self.counter, N) sem.release() - self.assertEquals(self.counter, N + 1) + self.assertEqual(self.counter, N + 1) for i in range(1, 1 + N): sem.release() - self.assertEquals(self.counter, N + 1) + self.assertEqual(self.counter, N + 1) def test_semaphoreInvalidTokens(self): @@ -1734,16 +1818,16 @@ for i in range(M): queue.put(i) - self.assertEquals(gotten, range(i + 1)) + self.assertEqual(gotten, range(i + 1)) for i in range(N): queue.put(N + i) - self.assertEquals(gotten, range(M)) + self.assertEqual(gotten, range(M)) self.assertRaises(defer.QueueOverflow, queue.put, None) gotten = [] for i in range(N): queue.get().addCallback(gotten.append) - self.assertEquals(gotten, range(N, N + i + 1)) + self.assertEqual(gotten, range(N, N + i + 1)) queue = defer.DeferredQueue() gotten = [] @@ -1751,7 +1835,7 @@ queue.get().addCallback(gotten.append) for i in range(N): queue.put(i) - self.assertEquals(gotten, range(N)) + self.assertEqual(gotten, range(N)) queue = defer.DeferredQueue(size=0) self.assertRaises(defer.QueueOverflow, queue.put, None) @@ -1855,7 +1939,7 @@ """ lock = defer.DeferredFilesystemLock(self.mktemp()) - self.assertEquals(lock._scheduler, reactor) + self.assertEqual(lock._scheduler, reactor) def test_concurrentUsage(self): diff --git a/lib/twisted-trunk/twisted/test/test_defgen.py b/lib/twisted-trunk/twisted/test/test_defgen.py --- a/lib/twisted-trunk/twisted/test/test_defgen.py +++ b/lib/twisted-trunk/twisted/test/test_defgen.py @@ -4,7 +4,7 @@ from twisted.internet import reactor -from twisted.trial import unittest, util +from twisted.trial import unittest from twisted.internet.defer import waitForDeferred, deferredGenerator, Deferred from twisted.internet import defer @@ -101,14 +101,14 @@ yield x x = x.getResult() - self.assertEquals(x, "hi") + self.assertEqual(x, "hi") ow = waitForDeferred(getOwie()) yield ow try: ow.getResult() except ZeroDivisionError, e: - self.assertEquals(str(e), 'OMG') + self.assertEqual(str(e), 'OMG') yield "WOOSH" return _genBasics = deferredGenerator(_genBasics) @@ -187,12 +187,12 @@ x = yield getThing() - self.assertEquals(x, "hi") + self.assertEqual(x, "hi") try: ow = yield getOwie() except ZeroDivisionError, e: - self.assertEquals(str(e), 'OMG') + self.assertEqual(str(e), 'OMG') returnValue("WOOSH") _genBasics = inlineCallbacks(_genBasics) @@ -270,6 +270,32 @@ return _return().addCallback(self.assertEqual, 6) + + def test_nonGeneratorReturn(self): + """ + Ensure that C{TypeError} with a message about L{inlineCallbacks} is + raised when a non-generator returns something other than a generator. + """ + def _noYield(): + return 5 + _noYield = inlineCallbacks(_noYield) + + self.assertIn("inlineCallbacks", + str(self.assertRaises(TypeError, _noYield))) + + + def test_nonGeneratorReturnValue(self): + """ + Ensure that C{TypeError} with a message about L{inlineCallbacks} is + raised when a non-generator calls L{returnValue}. + """ + def _noYield(): + returnValue(5) + _noYield = inlineCallbacks(_noYield) + + self.assertIn("inlineCallbacks", + str(self.assertRaises(TypeError, _noYield))) + ''' if sys.version_info > (2, 5): diff --git a/lib/twisted-trunk/twisted/test/test_dict.py b/lib/twisted-trunk/twisted/test/test_dict.py --- a/lib/twisted-trunk/twisted/test/test_dict.py +++ b/lib/twisted-trunk/twisted/test/test_dict.py @@ -19,4 +19,4 @@ if param == None: break params.append(param) - self.failUnlessEqual(params, goodparams)#, "DictClient.parseParam returns unexpected results") + self.assertEqual(params, goodparams)#, "DictClient.parseParam returns unexpected results") diff --git a/lib/twisted-trunk/twisted/test/test_dirdbm.py b/lib/twisted-trunk/twisted/test/test_dirdbm.py --- a/lib/twisted-trunk/twisted/test/test_dirdbm.py +++ b/lib/twisted-trunk/twisted/test/test_dirdbm.py @@ -24,7 +24,7 @@ k = "//==".decode("base64") self.dbm[k] = "a" self.dbm[k] = "a" - self.assertEquals(self.dbm[k], "a") + self.assertEqual(self.dbm[k], "a") def testRebuildInteraction(self): diff --git a/lib/twisted-trunk/twisted/test/test_enterprise.py b/lib/twisted-trunk/twisted/test/test_enterprise.py --- a/lib/twisted-trunk/twisted/test/test_enterprise.py +++ b/lib/twisted-trunk/twisted/test/test_enterprise.py @@ -19,7 +19,7 @@ (12, "text", "'12'"), (u"123'456", "text", u"'123''456'") ]: - self.assertEquals( + self.assertEqual( self.callDeprecated(util._deprecatedVersion, util.quote, value, typ), expected) diff --git a/lib/twisted-trunk/twisted/test/test_epoll.py b/lib/twisted-trunk/twisted/test/test_epoll.py --- a/lib/twisted-trunk/twisted/test/test_epoll.py +++ b/lib/twisted-trunk/twisted/test/test_epoll.py @@ -48,7 +48,7 @@ try: client.connect(('127.0.0.1', self.serverSocket.getsockname()[1])) except socket.error, e: - self.assertEquals(e.args[0], errno.EINPROGRESS) + self.assertEqual(e.args[0], errno.EINPROGRESS) else: raise unittest.FailTest("Connect should have raised EINPROGRESS") server, addr = self.serverSocket.accept() @@ -120,7 +120,7 @@ (server.fileno(), _epoll.OUT)] expected.sort() - self.assertEquals(events, expected) + self.assertEqual(events, expected) now = time.time() events = untilConcludes(p.wait, 4, 200) @@ -141,7 +141,7 @@ (server.fileno(), _epoll.IN | _epoll.OUT)] expected.sort() - self.assertEquals(events, expected) + self.assertEqual(events, expected) if _epoll is None: EPoll.skip = "_epoll module unavailable" diff --git a/lib/twisted-trunk/twisted/test/test_error.py b/lib/twisted-trunk/twisted/test/test_error.py --- a/lib/twisted-trunk/twisted/test/test_error.py +++ b/lib/twisted-trunk/twisted/test/test_error.py @@ -148,7 +148,7 @@ except IndexError: kwargs = {} - self.failUnlessEqual( + self.assertEqual( str(exception(*args, **kwargs)), output) diff --git a/lib/twisted-trunk/twisted/test/test_explorer.py b/lib/twisted-trunk/twisted/test/test_explorer.py --- a/lib/twisted-trunk/twisted/test/test_explorer.py +++ b/lib/twisted-trunk/twisted/test/test_explorer.py @@ -46,11 +46,11 @@ def test_chain(self): "Following a chain of Explorers." xplorer = self.pool.getExplorer(self.testThing, 'testThing') - self.failUnlessEqual(xplorer.id, id(self.testThing)) - self.failUnlessEqual(xplorer.identifier, 'testThing') + self.assertEqual(xplorer.id, id(self.testThing)) + self.assertEqual(xplorer.identifier, 'testThing') dxplorer = xplorer.get_elements()[1] - self.failUnlessEqual(dxplorer.id, id(self.testThing[1])) + self.assertEqual(dxplorer.id, id(self.testThing[1])) class Watcher: zero = 0 @@ -94,10 +94,10 @@ testThing.someAttr = 'someValue' - self.failUnlessEqual(testThing.someAttr, 'someValue') + self.assertEqual(testThing.someAttr, 'someValue') self.failUnless(self.watcher.len()) olink = self.watcher.links[-1] - self.failUnlessEqual(olink.id, id(testThing)) + self.assertEqual(olink.id, id(testThing)) def test_setAttrChain(self): "Setting an attribute on a watched object that has __setattr__" @@ -109,10 +109,10 @@ testThing.someAttr = 'ZORT' - self.failUnlessEqual(testThing.someAttr, 'TROZ') + self.assertEqual(testThing.someAttr, 'TROZ') self.failUnless(self.watcher.len()) olink = self.watcher.links[-1] - self.failUnlessEqual(olink.id, id(testThing)) + self.assertEqual(olink.id, id(testThing)) def test_method(self): @@ -124,11 +124,11 @@ self.watcher.setZero() rval = testThing.bip() - self.failUnlessEqual(rval, ('pencil',)) + self.assertEqual(rval, ('pencil',)) self.failUnless(self.watcher.len()) olink = self.watcher.links[-1] - self.failUnlessEqual(olink.id, id(testThing)) + self.assertEqual(olink.id, id(testThing)) def function_noArgs(): @@ -164,11 +164,11 @@ xplorer = self.pool.getExplorer(f, f_name) - self.failUnlessEqual(xplorer.id, id(f)) + self.assertEqual(xplorer.id, id(f)) self.failUnless(isinstance(xplorer, explorer.ExplorerFunction)) - self.failUnlessEqual(xplorer.name, f_name) + self.assertEqual(xplorer.name, f_name) def test_signature_noArgs(self): """Testing zero-argument function signature. @@ -176,7 +176,7 @@ xplorer = self.pool.getExplorer(function_noArgs, 'function_noArgs') - self.failUnlessEqual(len(xplorer.signature), 0) + self.assertEqual(len(xplorer.signature), 0) def test_signature_simple(self): """Testing simple function signature. @@ -186,7 +186,7 @@ expected_signature = ('a','b','c') - self.failUnlessEqual(xplorer.signature.name, expected_signature) + self.assertEqual(xplorer.signature.name, expected_signature) def test_signature_variable(self): """Testing variable-argument function signature. @@ -198,7 +198,7 @@ expected_names = ('a','kw') signature = xplorer.signature - self.failUnlessEqual(signature.name, expected_names) + self.assertEqual(signature.name, expected_names) self.failUnless(signature.is_varlist(0)) self.failUnless(signature.is_keyword(1)) @@ -220,16 +220,16 @@ self.failUnless(signature.get_name(0)) self.failUnless(not signature.get_default(0)[0]) - self.failUnlessEqual(signature.get_name(1), 'c') + self.assertEqual(signature.get_name(1), 'c') # Get a list of values from a list of ExplorerImmutables. arg_2_default = map(lambda l: l.value, signature.get_default(2)[1].get_elements()) - self.failUnlessEqual(signature.get_name(2), 'd') - self.failUnlessEqual(arg_2_default, range(4)) + self.assertEqual(signature.get_name(2), 'd') + self.assertEqual(arg_2_default, range(4)) - self.failUnlessEqual(signature.get_name(3), 'kw') + self.assertEqual(signature.get_name(3), 'kw') self.failUnless(signature.is_keyword(3)) if __name__ == '__main__': diff --git a/lib/twisted-trunk/twisted/test/test_factories.py b/lib/twisted-trunk/twisted/test/test_factories.py --- a/lib/twisted-trunk/twisted/test/test_factories.py +++ b/lib/twisted-trunk/twisted/test/test_factories.py @@ -99,12 +99,12 @@ def _testStopTrying_1(self, res, f, c): - self.assertEquals(len(f.allMessages), 2, + self.assertEqual(len(f.allMessages), 2, "not enough messages -- %s" % f.allMessages) - self.assertEquals(f.connections, 2, + self.assertEqual(f.connections, 2, "Number of successful connections incorrect %d" % f.connections) - self.assertEquals(f.allMessages, [Out.msgs] * 2) + self.assertEqual(f.allMessages, [Out.msgs] * 2) self.failIf(c.continueTrying, "stopTrying never called or ineffective") @@ -194,4 +194,4 @@ factory.clock = clock factory.clientConnectionLost(FakeConnector(), None) - self.assertEquals(len(clock.calls), 1) + self.assertEqual(len(clock.calls), 1) diff --git a/lib/twisted-trunk/twisted/test/test_failure.py b/lib/twisted-trunk/twisted/test/test_failure.py --- a/lib/twisted-trunk/twisted/test/test_failure.py +++ b/lib/twisted-trunk/twisted/test/test_failure.py @@ -5,9 +5,11 @@ Test cases for failure module. """ +import re import sys import StringIO import traceback +import pdb from twisted.trial import unittest, util @@ -19,11 +21,17 @@ raiser = None -def getDivisionFailure(): +def getDivisionFailure(*args, **kwargs): + """ + Make a C{Failure} of a divide-by-zero error. + + @param args: Any C{*args} are passed to Failure's constructor. + @param kwargs: Any C{**kwargs} are passed to Failure's constructor. + """ try: 1/0 except: - f = failure.Failure() + f = failure.Failure(*args, **kwargs) return f @@ -36,8 +44,9 @@ except: f = failure.Failure() error = f.trap(SystemExit, RuntimeError) - self.assertEquals(error, RuntimeError) - self.assertEquals(f.type, NotImplementedError) + self.assertEqual(error, RuntimeError) + self.assertEqual(f.type, NotImplementedError) + def test_notTrapped(self): """Making sure trap doesn't trap what it shouldn't.""" @@ -47,21 +56,104 @@ f = failure.Failure() self.assertRaises(failure.Failure, f.trap, OverflowError) - def testPrinting(self): + + def assertStartsWith(self, s, prefix): + """ + Assert that s starts with a particular prefix. + """ + self.assertTrue(s.startswith(prefix), + '%r is not the start of %r' % (prefix, s)) + + + def test_printingSmokeTest(self): + """ + None of the print* methods fail when called. + """ + f = getDivisionFailure() out = StringIO.StringIO() - try: - 1/0 - except: - f = failure.Failure() f.printDetailedTraceback(out) + self.assertStartsWith(out.getvalue(), '*--- Failure') + out = StringIO.StringIO() f.printBriefTraceback(out) + self.assertStartsWith(out.getvalue(), 'Traceback') + out = StringIO.StringIO() f.printTraceback(out) + self.assertStartsWith(out.getvalue(), 'Traceback') + + + def test_printingCapturedVarsSmokeTest(self): + """ + None of the print* methods fail when called on a L{Failure} constructed + with C{captureVars=True}. + + Local variables on the stack can be seen in the detailed traceback. + """ + exampleLocalVar = 'xyzzy' + f = getDivisionFailure(captureVars=True) + out = StringIO.StringIO() + f.printDetailedTraceback(out) + self.assertStartsWith(out.getvalue(), '*--- Failure') + self.assertNotEqual(None, re.search('exampleLocalVar.*xyzzy', + out.getvalue())) + out = StringIO.StringIO() + f.printBriefTraceback(out) + self.assertStartsWith(out.getvalue(), 'Traceback') + out = StringIO.StringIO() + f.printTraceback(out) + self.assertStartsWith(out.getvalue(), 'Traceback') + + + def test_printingCapturedVarsCleanedSmokeTest(self): + """ + C{printDetailedTraceback} includes information about local variables on + the stack after C{cleanFailure} has been called. + """ + exampleLocalVar = 'xyzzy' + f = getDivisionFailure(captureVars=True) + f.cleanFailure() + out = StringIO.StringIO() + f.printDetailedTraceback(out) + self.assertNotEqual(None, re.search('exampleLocalVar.*xyzzy', + out.getvalue())) + + + def test_printingNoVars(self): + """ + Calling C{Failure()} with no arguments does not capture any locals or + globals, so L{printDetailedTraceback} cannot show them in its output. + """ + out = StringIO.StringIO() + f = getDivisionFailure() + f.printDetailedTraceback(out) + # There should be no variables in the detailed output. Variables are + # printed on lines with 2 leading spaces. + linesWithVars = [line for line in out.getvalue().splitlines() + if line.startswith(' ')] + self.assertEqual([], linesWithVars) + self.assertSubstring( + 'Capture of Locals and Globals disabled', out.getvalue()) + + + def test_printingCaptureVars(self): + """ + Calling C{Failure(captureVars=True)} captures the locals and globals + for its stack frames, so L{printDetailedTraceback} will show them in + its output. + """ + out = StringIO.StringIO() + f = getDivisionFailure(captureVars=True) + f.printDetailedTraceback(out) + # Variables are printed on lines with 2 leading spaces. + linesWithVars = [line for line in out.getvalue().splitlines() + if line.startswith(' ')] + self.assertNotEqual([], linesWithVars) + def testExplictPass(self): e = RuntimeError() f = failure.Failure(e) f.trap(RuntimeError) - self.assertEquals(f.value, e) + self.assertEqual(f.value, e) def _getInnermostFrameLine(self, f): @@ -78,14 +170,14 @@ def testRaiseExceptionWithTB(self): f = getDivisionFailure() innerline = self._getInnermostFrameLine(f) - self.assertEquals(innerline, '1/0') + self.assertEqual(innerline, '1/0') def testLackOfTB(self): f = getDivisionFailure() f.cleanFailure() innerline = self._getInnermostFrameLine(f) - self.assertEquals(innerline, '1/0') + self.assertEqual(innerline, '1/0') testLackOfTB.todo = "the traceback is not preserved, exarkun said he'll try to fix this! god knows how" @@ -98,13 +190,14 @@ f = failure.Failure() return f + def test_raiseStringExceptions(self): # String exceptions used to totally bugged f.raiseException f = self._getStringFailure() try: f.raiseException() except: - self.assertEquals(sys.exc_info()[0], self._stringException) + self.assertEqual(sys.exc_info()[0], self._stringException) else: raise AssertionError("Should have raised") test_raiseStringExceptions.suppress = [ @@ -141,31 +234,59 @@ """ self.assertRaises(failure.NoCurrentExceptionError, failure.Failure) + def test_getTracebackObject(self): """ If the C{Failure} has not been cleaned, then C{getTracebackObject} - should return the traceback object that it was given in the - constructor. + returns the traceback object that captured in its constructor. """ f = getDivisionFailure() self.assertEqual(f.getTracebackObject(), f.tb) + + def test_getTracebackObjectFromCaptureVars(self): + """ + C{captureVars=True} has no effect on the result of + C{getTracebackObject}. + """ + try: + 1/0 + except ZeroDivisionError: + noVarsFailure = failure.Failure() + varsFailure = failure.Failure(captureVars=True) + self.assertEqual(noVarsFailure.getTracebackObject(), varsFailure.tb) + + def test_getTracebackObjectFromClean(self): """ - If the Failure has been cleaned, then C{getTracebackObject} should - return an object that looks the same to L{traceback.extract_tb}. + If the Failure has been cleaned, then C{getTracebackObject} returns an + object that looks the same to L{traceback.extract_tb}. """ f = getDivisionFailure() expected = traceback.extract_tb(f.getTracebackObject()) f.cleanFailure() observed = traceback.extract_tb(f.getTracebackObject()) + self.assertNotEqual(None, expected) self.assertEqual(expected, observed) + + def test_getTracebackObjectFromCaptureVarsAndClean(self): + """ + If the Failure was created with captureVars, then C{getTracebackObject} + returns an object that looks the same to L{traceback.extract_tb}. + """ + f = getDivisionFailure(captureVars=True) + expected = traceback.extract_tb(f.getTracebackObject()) + f.cleanFailure() + observed = traceback.extract_tb(f.getTracebackObject()) + self.assertEqual(expected, observed) + + def test_getTracebackObjectWithoutTraceback(self): """ L{failure.Failure}s need not be constructed with traceback objects. If a C{Failure} has no traceback information at all, C{getTracebackObject} - should just return None. + just returns None. None is a good value, because traceback.extract_tb(None) -> []. """ @@ -383,6 +504,7 @@ self.assertEqual(traceback.extract_tb(tb), [('filename.py', 123, 'method', None)]) + def test_manyFrames(self): """ A C{_Traceback} object constructed with multiple frames should be able @@ -416,5 +538,57 @@ self.assertIsInstance(frame.f_code, failure._Code) + +class TestDebugMode(unittest.TestCase): + """ + Failure's debug mode should allow jumping into the debugger. + """ + + def setUp(self): + """ + Override pdb.post_mortem so we can make sure it's called. + """ + # Make sure any changes we make are reversed: + post_mortem = pdb.post_mortem + origInit = failure.Failure.__dict__['__init__'] + def restore(): + pdb.post_mortem = post_mortem + failure.Failure.__dict__['__init__'] = origInit + self.addCleanup(restore) + + self.result = [] + pdb.post_mortem = self.result.append + failure.startDebugMode() + + + def test_regularFailure(self): + """ + If startDebugMode() is called, calling Failure() will first call + pdb.post_mortem with the traceback. + """ + try: + 1/0 + except: + typ, exc, tb = sys.exc_info() + f = failure.Failure() + self.assertEqual(self.result, [tb]) + self.assertEqual(f.captureVars, False) + + + def test_captureVars(self): + """ + If startDebugMode() is called, passing captureVars to Failure() will + not blow up. + """ + try: + 1/0 + except: + typ, exc, tb = sys.exc_info() + f = failure.Failure(captureVars=True) + self.assertEqual(self.result, [tb]) + self.assertEqual(f.captureVars, True) + + + if sys.version_info[:2] >= (2, 5): from twisted.test.generator_failure_tests import TwoPointFiveFailureTests diff --git a/lib/twisted-trunk/twisted/test/test_fdesc.py b/lib/twisted-trunk/twisted/test/test_fdesc.py --- a/lib/twisted-trunk/twisted/test/test_fdesc.py +++ b/lib/twisted-trunk/twisted/test/test_fdesc.py @@ -77,8 +77,8 @@ n = self.write("hello") self.failUnless(n > 0) s = self.read() - self.assertEquals(len(s), n) - self.assertEquals("hello"[:n], s) + self.assertEqual(len(s), n) + self.assertEqual("hello"[:n], s) def test_writeAndReadLarge(self): @@ -98,8 +98,8 @@ # Increment a counter to be sure we'll exit at some point i += 1 result = "".join(result) - self.assertEquals(len(result), written) - self.assertEquals(orig[:written], result) + self.assertEqual(len(result), written) + self.assertEqual(orig[:written], result) def test_readFromEmpty(self): @@ -109,8 +109,8 @@ """ l = [] result = fdesc.readFromFD(self.r, l.append) - self.assertEquals(l, []) - self.assertEquals(result, None) + self.assertEqual(l, []) + self.assertEqual(result, None) def test_readFromCleanClose(self): @@ -119,7 +119,7 @@ returns a connection done indicator. """ os.close(self.w) - self.assertEquals(self.read(), fdesc.CONNECTION_DONE) + self.assertEqual(self.read(), fdesc.CONNECTION_DONE) def test_writeToClosed(self): @@ -128,7 +128,7 @@ results in a connection lost indicator. """ os.close(self.r) - self.assertEquals(self.write("s"), fdesc.CONNECTION_LOST) + self.assertEqual(self.write("s"), fdesc.CONNECTION_LOST) def test_readFromInvalid(self): @@ -137,7 +137,7 @@ closed results in a connection lost indicator. """ os.close(self.r) - self.assertEquals(self.read(), fdesc.CONNECTION_LOST) + self.assertEqual(self.read(), fdesc.CONNECTION_LOST) def test_writeToInvalid(self): @@ -146,7 +146,7 @@ closed results in a connection lost indicator. """ os.close(self.w) - self.assertEquals(self.write("s"), fdesc.CONNECTION_LOST) + self.assertEqual(self.write("s"), fdesc.CONNECTION_LOST) def test_writeErrors(self): @@ -160,7 +160,7 @@ raise err os.write = eagainWrite try: - self.assertEquals(self.write("s"), 0) + self.assertEqual(self.write("s"), 0) finally: os.write = oldOsWrite @@ -170,7 +170,7 @@ raise err os.write = eintrWrite try: - self.assertEquals(self.write("s"), 0) + self.assertEqual(self.write("s"), 0) finally: os.write = oldOsWrite diff --git a/lib/twisted-trunk/twisted/test/test_formmethod.py b/lib/twisted-trunk/twisted/test/test_formmethod.py --- a/lib/twisted-trunk/twisted/test/test_formmethod.py +++ b/lib/twisted-trunk/twisted/test/test_formmethod.py @@ -16,7 +16,7 @@ def argTest(self, argKlass, testPairs, badValues, *args, **kwargs): arg = argKlass("name", *args, **kwargs) for val, result in testPairs: - self.assertEquals(arg.coerce(val), result) + self.assertEqual(arg.coerce(val), result) for val in badValues: self.assertRaises(formmethod.InputError, arg.coerce, val) diff --git a/lib/twisted-trunk/twisted/test/test_ftp.py b/lib/twisted-trunk/twisted/test/test_ftp.py --- a/lib/twisted-trunk/twisted/test/test_ftp.py +++ b/lib/twisted-trunk/twisted/test/test_ftp.py @@ -133,7 +133,7 @@ def queueCommand(ignored): d = self.client.queueStringCommand(command) def gotResponse(responseLines): - self.assertEquals(expectedResponseLines, responseLines) + self.assertEqual(expectedResponseLines, responseLines) return d.addCallback(gotResponse) return chainDeferred.addCallback(queueCommand) @@ -148,7 +148,7 @@ self.assertFailure(chainDeferred, ftp.CommandFailed) def failed(exception): if expectedResponse is not None: - self.failUnlessEqual( + self.assertEqual( expectedResponse, exception.args[0]) return chainDeferred.addCallback(failed) @@ -316,7 +316,7 @@ return d def testDecodeHostPort(self): - self.assertEquals(ftp.decodeHostPort('25,234,129,22,100,23'), + self.assertEqual(ftp.decodeHostPort('25,234,129,22,100,23'), ('25.234.129.22', 25623)) nums = range(6) for i in range(6): @@ -378,11 +378,11 @@ self.serverProtocol.listenFactory = listenFactory port = self.serverProtocol.getDTPPort(protocol.Factory()) - self.assertEquals(port, 0) + self.assertEqual(port, 0) self.serverProtocol.passivePortRange = xrange(22032, 65536) port = self.serverProtocol.getDTPPort(protocol.Factory()) - self.assertEquals(port, 22035) + self.assertEqual(port, 22035) self.serverProtocol.passivePortRange = xrange(22032, 22035) self.assertRaises(error.CannotListenError, @@ -416,7 +416,7 @@ """ def eb(res): res.trap(ftp.CommandFailed) - self.assertEquals(res.value.args[0][0], + self.assertEqual(res.value.args[0][0], '550 foo: Permission denied.') d1, d2 = self.client.storeFile('foo') d2.addErrback(eb) @@ -443,7 +443,7 @@ def eb(res): self.flushLoggedErrors() res.trap(ftp.CommandFailed) - self.assertEquals( + self.assertEqual( res.value.args[0][0], "550 Cannot rmd, blah is not a directory") d1, d2 = self.client.storeFile('failing_file') @@ -565,7 +565,7 @@ def checkDownload(download): filenames = download[:-2].split('\r\n') filenames.sort() - self.assertEquals(['foo', 'test.txt'], filenames) + self.assertEqual(['foo', 'test.txt'], filenames) return d.addCallback(checkDownload) @@ -578,7 +578,7 @@ self._download('NLST nonexistent.txt', chainDeferred=d) def checkDownload(download): - self.assertEquals('', download) + self.assertEqual('', download) return d.addCallback(checkDownload) @@ -595,7 +595,7 @@ self._download('NLST test.txt', chainDeferred=d) def checkDownload(download): filenames = download[:-2].split('\r\n') - self.assertEquals(['test.txt'], filenames) + self.assertEqual(['test.txt'], filenames) return d.addCallback(checkDownload) @@ -970,14 +970,14 @@ """ Test the login part. """ - self.assertEquals(self.transport.value(), '') + self.assertEqual(self.transport.value(), '') self.client.lineReceived( '331 Guest login ok, type your email address as password.') - self.assertEquals(self.transport.value(), 'USER anonymous\r\n') + self.assertEqual(self.transport.value(), 'USER anonymous\r\n') self.transport.clear() self.client.lineReceived( '230 Anonymous login ok, access restrictions apply.') - self.assertEquals(self.transport.value(), 'TYPE I\r\n') + self.assertEqual(self.transport.value(), 'TYPE I\r\n') self.transport.clear() self.client.lineReceived('200 Type set to I.') @@ -993,11 +993,11 @@ (XXX - This is a bad API) """ def cbCdup(res): - self.assertEquals(res[0], '250 Requested File Action Completed OK') + self.assertEqual(res[0], '250 Requested File Action Completed OK') self._testLogin() d = self.client.cdup().addCallback(cbCdup) - self.assertEquals(self.transport.value(), 'CDUP\r\n') + self.assertEqual(self.transport.value(), 'CDUP\r\n') self.transport.clear() self.client.lineReceived('250 Requested File Action Completed OK') return d @@ -1013,7 +1013,7 @@ self._testLogin() d = self.client.cdup() self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'CDUP\r\n') + self.assertEqual(self.transport.value(), 'CDUP\r\n') self.transport.clear() self.client.lineReceived('550 ..: No such file or directory') return d @@ -1030,11 +1030,11 @@ (XXX - This is a bad API) """ def cbPwd(res): - self.assertEquals(ftp.parsePWDResponse(res[0]), "/bar/baz") + self.assertEqual(ftp.parsePWDResponse(res[0]), "/bar/baz") self._testLogin() d = self.client.pwd().addCallback(cbPwd) - self.assertEquals(self.transport.value(), 'PWD\r\n') + self.assertEqual(self.transport.value(), 'PWD\r\n') self.client.lineReceived('257 "/bar/baz"') return d @@ -1049,7 +1049,7 @@ self._testLogin() d = self.client.pwd() self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PWD\r\n') + self.assertEqual(self.transport.value(), 'PWD\r\n') self.client.lineReceived('550 /bar/baz: No such file or directory') return d @@ -1065,11 +1065,11 @@ (XXX - This is a bad API) """ def cbCwd(res): - self.assertEquals(res[0], '250 Requested File Action Completed OK') + self.assertEqual(res[0], '250 Requested File Action Completed OK') self._testLogin() d = self.client.cwd("bar/foo").addCallback(cbCwd) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') + self.assertEqual(self.transport.value(), 'CWD bar/foo\r\n') self.client.lineReceived('250 Requested File Action Completed OK') return d @@ -1084,7 +1084,7 @@ self._testLogin() d = self.client.cwd("bar/foo") self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') + self.assertEqual(self.transport.value(), 'CWD bar/foo\r\n') self.client.lineReceived('550 bar/foo: No such file or directory') return d @@ -1101,11 +1101,11 @@ (XXX - This API should be based on producers and consumers) """ def cbRetr(res, proto): - self.assertEquals(proto.buffer, 'x' * 1000) + self.assertEqual(proto.buffer, 'x' * 1000) def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) + self.assertEqual(host, '127.0.0.1') + self.assertEqual(port, 12345) proto = factory.buildProtocol((host, port)) proto.makeConnection(proto_helpers.StringTransport()) self.client.lineReceived( @@ -1118,11 +1118,11 @@ proto = _BufferingProtocol() d = self.client.retrieveFile("spam", proto) d.addCallback(cbRetr, proto) - self.assertEquals(self.transport.value(), 'PASV\r\n') + self.assertEqual(self.transport.value(), 'PASV\r\n') self.transport.clear() self.client.lineReceived('227 Entering Passive Mode (%s).' % (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'RETR spam\r\n') + self.assertEqual(self.transport.value(), 'RETR spam\r\n') self.transport.clear() self.client.lineReceived('226 Transfer Complete.') return d @@ -1146,18 +1146,18 @@ failure.Failure(error.ConnectionDone(""))) def cbRetr(res, proto): - self.assertEquals(proto.buffer, 'x' * 1000) + self.assertEqual(proto.buffer, 'x' * 1000) self.client.generatePortCommand = generatePort self._testLogin() proto = _BufferingProtocol() d = self.client.retrieveFile("spam", proto) d.addCallback(cbRetr, proto) - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % + self.assertEqual(self.transport.value(), 'PORT %s\r\n' % (ftp.encodeHostPort('127.0.0.1', 9876),)) self.transport.clear() self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'RETR spam\r\n') + self.assertEqual(self.transport.value(), 'RETR spam\r\n') self.transport.clear() self.client.lineReceived('226 Transfer Complete.') return d @@ -1172,8 +1172,8 @@ cannot be transferred for some reason. """ def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) + self.assertEqual(host, '127.0.0.1') + self.assertEqual(port, 12345) proto = factory.buildProtocol((host, port)) proto.makeConnection(proto_helpers.StringTransport()) self.client.lineReceived( @@ -1185,11 +1185,11 @@ proto = _BufferingProtocol() d = self.client.retrieveFile("spam", proto) self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PASV\r\n') + self.assertEqual(self.transport.value(), 'PASV\r\n') self.transport.clear() self.client.lineReceived('227 Entering Passive Mode (%s).' % (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'RETR spam\r\n') + self.assertEqual(self.transport.value(), 'RETR spam\r\n') self.transport.clear() self.client.lineReceived('550 spam: No such file or directory') return d @@ -1216,11 +1216,11 @@ self._testLogin() proto = _BufferingProtocol() d = self.client.retrieveFile("spam", proto) - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % + self.assertEqual(self.transport.value(), 'PORT %s\r\n' % (ftp.encodeHostPort('127.0.0.1', 9876),)) self.transport.clear() self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'RETR spam\r\n') + self.assertEqual(self.transport.value(), 'RETR spam\r\n') self.assert_(l) l[0].loseConnection() @@ -1253,11 +1253,11 @@ sender.connectionLost(failure.Failure(error.ConnectionDone(""))) def cbFinish(ign): - self.assertEquals(tr.value(), "x" * 1000) + self.assertEqual(tr.value(), "x" * 1000) def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) + self.assertEqual(host, '127.0.0.1') + self.assertEqual(port, 12345) proto = factory.buildProtocol((host, port)) proto.makeConnection(tr) @@ -1266,11 +1266,11 @@ d1, d2 = self.client.storeFile("spam") d1.addCallback(cbStore) d2.addCallback(cbFinish) - self.assertEquals(self.transport.value(), 'PASV\r\n') + self.assertEqual(self.transport.value(), 'PASV\r\n') self.transport.clear() self.client.lineReceived('227 Entering Passive Mode (%s).' % (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'STOR spam\r\n') + self.assertEqual(self.transport.value(), 'STOR spam\r\n') self.transport.clear() self.client.lineReceived('226 Transfer Complete.') return defer.gatherResults([d1, d2]) @@ -1293,8 +1293,8 @@ sender.connectionLost(failure.Failure(error.ConnectionDone(""))) def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) + self.assertEqual(host, '127.0.0.1') + self.assertEqual(port, 12345) proto = factory.buildProtocol((host, port)) proto.makeConnection(tr) @@ -1303,11 +1303,11 @@ d1, d2 = self.client.storeFile("spam") d1.addCallback(cbStore) self.assertFailure(d2, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PASV\r\n') + self.assertEqual(self.transport.value(), 'PASV\r\n') self.transport.clear() self.client.lineReceived('227 Entering Passive Mode (%s).' % (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'STOR spam\r\n') + self.assertEqual(self.transport.value(), 'STOR spam\r\n') self.transport.clear() self.client.lineReceived( '426 Transfer aborted. Data connection closed.') @@ -1329,11 +1329,11 @@ portCmd.protocol.makeConnection(tr) def cbStore(sender): - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % + self.assertEqual(self.transport.value(), 'PORT %s\r\n' % (ftp.encodeHostPort('127.0.0.1', 9876),)) self.transport.clear() self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'STOR spam\r\n') + self.assertEqual(self.transport.value(), 'STOR spam\r\n') self.transport.clear() self.client.lineReceived( '150 File status okay; about to open data connection.') @@ -1343,7 +1343,7 @@ self.client.lineReceived('226 Transfer Complete.') def cbFinish(ign): - self.assertEquals(tr.value(), "x" * 1000) + self.assertEqual(tr.value(), "x" * 1000) self.client.generatePortCommand = generatePort self._testLogin() @@ -1377,11 +1377,11 @@ expected = ["foo", "bar", "baz"] expected.sort() fls.sort() - self.assertEquals(fls, expected) + self.assertEqual(fls, expected) def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) + self.assertEqual(host, '127.0.0.1') + self.assertEqual(port, 12345) proto = factory.buildProtocol((host, port)) proto.makeConnection(proto_helpers.StringTransport()) self.client.lineReceived( @@ -1399,11 +1399,11 @@ self._testLogin() fileList = ftp.FTPFileListProtocol() d = self.client.list('foo/bar', fileList).addCallback(cbList, fileList) - self.assertEquals(self.transport.value(), 'PASV\r\n') + self.assertEqual(self.transport.value(), 'PASV\r\n') self.transport.clear() self.client.lineReceived('227 Entering Passive Mode (%s).' % (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'LIST foo/bar\r\n') + self.assertEqual(self.transport.value(), 'LIST foo/bar\r\n') self.client.lineReceived('226 Transfer Complete.') return d @@ -1437,17 +1437,17 @@ expected = ["foo", "bar", "baz"] expected.sort() fls.sort() - self.assertEquals(fls, expected) + self.assertEqual(fls, expected) self.client.generatePortCommand = generatePort self._testLogin() fileList = ftp.FTPFileListProtocol() d = self.client.list('foo/bar', fileList).addCallback(cbList, fileList) - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % + self.assertEqual(self.transport.value(), 'PORT %s\r\n' % (ftp.encodeHostPort('127.0.0.1', 9876),)) self.transport.clear() self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'LIST foo/bar\r\n') + self.assertEqual(self.transport.value(), 'LIST foo/bar\r\n') self.transport.clear() self.client.lineReceived('226 Transfer Complete.') return d @@ -1462,8 +1462,8 @@ invalid for some reason. """ def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) + self.assertEqual(host, '127.0.0.1') + self.assertEqual(port, 12345) proto = factory.buildProtocol((host, port)) proto.makeConnection(proto_helpers.StringTransport()) self.client.lineReceived( @@ -1475,11 +1475,11 @@ fileList = ftp.FTPFileListProtocol() d = self.client.list('foo/bar', fileList) self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PASV\r\n') + self.assertEqual(self.transport.value(), 'PASV\r\n') self.transport.clear() self.client.lineReceived('227 Entering Passive Mode (%s).' % (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'LIST foo/bar\r\n') + self.assertEqual(self.transport.value(), 'LIST foo/bar\r\n') self.client.lineReceived('550 foo/bar: No such file or directory') return d @@ -1508,17 +1508,17 @@ expected = ["foo", "bar", "baz"] expected.sort() fls.sort() - self.assertEquals(fls, expected) + self.assertEqual(fls, expected) self.client.generatePortCommand = generatePort self._testLogin() lstproto = _BufferingProtocol() d = self.client.nlst('foo/bar', lstproto).addCallback(cbList, lstproto) - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % + self.assertEqual(self.transport.value(), 'PORT %s\r\n' % (ftp.encodeHostPort('127.0.0.1', 9876),)) self.transport.clear() self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'NLST foo/bar\r\n') + self.assertEqual(self.transport.value(), 'NLST foo/bar\r\n') self.client.lineReceived('226 Transfer Complete.') return d @@ -1536,11 +1536,11 @@ expected = ["foo", "bar", "baz"] expected.sort() fls.sort() - self.assertEquals(fls, expected) + self.assertEqual(fls, expected) def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) + self.assertEqual(host, '127.0.0.1') + self.assertEqual(port, 12345) proto = factory.buildProtocol((host, port)) proto.makeConnection(proto_helpers.StringTransport()) self.client.lineReceived( @@ -1554,11 +1554,11 @@ self._testLogin() lstproto = _BufferingProtocol() d = self.client.nlst('foo/bar', lstproto).addCallback(cbList, lstproto) - self.assertEquals(self.transport.value(), 'PASV\r\n') + self.assertEqual(self.transport.value(), 'PASV\r\n') self.transport.clear() self.client.lineReceived('227 Entering Passive Mode (%s).' % (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'NLST foo/bar\r\n') + self.assertEqual(self.transport.value(), 'NLST foo/bar\r\n') self.client.lineReceived('226 Transfer Complete.') return d @@ -1573,8 +1573,8 @@ """ tr = proto_helpers.StringTransport() def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) + self.assertEqual(host, '127.0.0.1') + self.assertEqual(port, 12345) proto = factory.buildProtocol((host, port)) proto.makeConnection(tr) self.client.lineReceived( @@ -1586,11 +1586,11 @@ lstproto = _BufferingProtocol() d = self.client.nlst('foo/bar', lstproto) self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PASV\r\n') + self.assertEqual(self.transport.value(), 'PASV\r\n') self.transport.clear() self.client.lineReceived('227 Entering Passive Mode (%s).' % (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'NLST foo/bar\r\n') + self.assertEqual(self.transport.value(), 'NLST foo/bar\r\n') self.client.lineReceived('550 foo/bar: No such file or directory') return d @@ -1622,11 +1622,11 @@ with True if succeeded. """ def cbCd(res): - self.assertEquals(res, True) + self.assertEqual(res, True) self._testLogin() d = self.client.changeDirectory("bar/foo").addCallback(cbCd) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') + self.assertEqual(self.transport.value(), 'CWD bar/foo\r\n') self.client.lineReceived('250 Requested File Action Completed OK') return d test_changeDirectory.suppress = [_changeDirectorySuppression] @@ -1641,7 +1641,7 @@ self._testLogin() d = self.client.changeDirectory("bar/foo") self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') + self.assertEqual(self.transport.value(), 'CWD bar/foo\r\n') self.client.lineReceived('550 bar/foo: No such file or directory') return d test_failedChangeDirectory.suppress = [_changeDirectorySuppression] @@ -1657,7 +1657,7 @@ self._testLogin() d = self.client.changeDirectory("bar/foo") self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') + self.assertEqual(self.transport.value(), 'CWD bar/foo\r\n') self.client.lineReceived('252 I do what I want !') return d test_strangeFailedChangeDirectory.suppress = [_changeDirectorySuppression] @@ -1750,7 +1750,7 @@ self._testLogin() d = self.client.makeDirectory("/spam") - self.assertEquals(self.transport.value(), 'MKD /spam\r\n') + self.assertEqual(self.transport.value(), 'MKD /spam\r\n') self.client.lineReceived('257 "/spam" created.') return d.addCallback(self.assertEqual, ['257 "/spam" created.']) @@ -1778,7 +1778,7 @@ self._testLogin() d = self.client.makeDirectory("/spam") - self.assertEquals(self.transport.value(), 'MKD /spam\r\n') + self.assertEqual(self.transport.value(), 'MKD /spam\r\n') self.client.lineReceived('550 PERMISSION DENIED') return self.assertFailure(d, ftp.CommandFailed) @@ -1791,11 +1791,11 @@ the current directory on the server. It wraps PWD command. """ def cbGet(res): - self.assertEquals(res, "/bar/baz") + self.assertEqual(res, "/bar/baz") self._testLogin() d = self.client.getDirectory().addCallback(cbGet) - self.assertEquals(self.transport.value(), 'PWD\r\n') + self.assertEqual(self.transport.value(), 'PWD\r\n') self.client.lineReceived('257 "/bar/baz"') return d @@ -1809,7 +1809,7 @@ self._testLogin() d = self.client.getDirectory() self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PWD\r\n') + self.assertEqual(self.transport.value(), 'PWD\r\n') self.client.lineReceived('550 /bar/baz: No such file or directory') return d @@ -1824,7 +1824,7 @@ self._testLogin() d = self.client.getDirectory() self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PWD\r\n') + self.assertEqual(self.transport.value(), 'PWD\r\n') self.client.lineReceived('257 /bar/baz') return d @@ -1837,7 +1837,7 @@ """ self._testLogin() d = self.client.removeFile("/tmp/test") - self.assertEquals(self.transport.value(), 'DELE /tmp/test\r\n') + self.assertEqual(self.transport.value(), 'DELE /tmp/test\r\n') response = '250 Requested file action okay, completed.' self.client.lineReceived(response) return d.addCallback(self.assertEqual, [response]) @@ -1852,7 +1852,7 @@ """ self._testLogin() d = self.client.removeFile("/tmp/test") - self.assertEquals(self.transport.value(), 'DELE /tmp/test\r\n') + self.assertEqual(self.transport.value(), 'DELE /tmp/test\r\n') response = '501 Syntax error in parameters or arguments.' self.client.lineReceived(response) d = self.assertFailure(d, ftp.CommandFailed) @@ -1896,14 +1896,14 @@ # The first response is captured as a greeting. ftpClient = ftp.FTPClientBasic() ftpClient.lineReceived('220 Imaginary FTP.') - self.failUnlessEqual(['220 Imaginary FTP.'], ftpClient.greeting) + self.assertEqual(['220 Imaginary FTP.'], ftpClient.greeting) def testResponseWithNoMessage(self): # Responses with no message are still valid, i.e. three digits followed # by a space is complete response. ftpClient = ftp.FTPClientBasic() ftpClient.lineReceived('220 ') - self.failUnlessEqual(['220 '], ftpClient.greeting) + self.assertEqual(['220 '], ftpClient.greeting) def testMultilineResponse(self): ftpClient = ftp.FTPClientBasic() @@ -1919,31 +1919,31 @@ # Send the first line of a multiline response. ftpClient.lineReceived('210-First line.') - self.failUnlessEqual([], result) + self.assertEqual([], result) # Send a second line, again prefixed with "nnn-". ftpClient.lineReceived('123-Second line.') - self.failUnlessEqual([], result) + self.assertEqual([], result) # Send a plain line of text, no prefix. ftpClient.lineReceived('Just some text.') - self.failUnlessEqual([], result) + self.assertEqual([], result) # Now send a short (less than 4 chars) line. ftpClient.lineReceived('Hi') - self.failUnlessEqual([], result) + self.assertEqual([], result) # Now send an empty line. ftpClient.lineReceived('') - self.failUnlessEqual([], result) + self.assertEqual([], result) # And a line with 3 digits in it, and nothing else. ftpClient.lineReceived('321') - self.failUnlessEqual([], result) + self.assertEqual([], result) # Now finish it. ftpClient.lineReceived('210 Done.') - self.failUnlessEqual( + self.assertEqual( ['210-First line.', '123-Second line.', 'Just some text.', @@ -1964,7 +1964,7 @@ # Queue a login with no password ftpClient.queueLogin('bob', None) - self.assertEquals('USER bob\r\n', ftpClient.transport.value()) + self.assertEqual('USER bob\r\n', ftpClient.transport.value()) # Clear the test buffer, acknowledge the USER command. ftpClient.transport.clear() @@ -1972,7 +1972,7 @@ # The client shouldn't have sent anything more (i.e. it shouldn't have # sent a PASS command). - self.assertEquals('', ftpClient.transport.value()) + self.assertEqual('', ftpClient.transport.value()) def test_noPasswordNeeded(self): @@ -1986,7 +1986,7 @@ # Queue a login with no password ftpClient.queueLogin('bob', 'secret') - self.assertEquals('USER bob\r\n', ftpClient.transport.value()) + self.assertEqual('USER bob\r\n', ftpClient.transport.value()) # Clear the test buffer, acknowledge the USER command with a 230 # response code. @@ -1995,7 +1995,7 @@ # The client shouldn't have sent anything more (i.e. it shouldn't have # sent a PASS command). - self.assertEquals('', ftpClient.transport.value()) + self.assertEqual('', ftpClient.transport.value()) @@ -2008,7 +2008,7 @@ ('/a/b/c', ['a', 'b', 'c']), ('/a/', ['a']), ('a/', ['a'])]: - self.assertEquals(ftp.toSegments([], inp), outp) + self.assertEqual(ftp.toSegments([], inp), outp) for inp, outp in [('b', ['a', 'b']), ('b/', ['a', 'b']), @@ -2018,18 +2018,18 @@ ('b/c/', ['a', 'b', 'c']), ('/b/c', ['b', 'c']), ('/b/c/', ['b', 'c'])]: - self.assertEquals(ftp.toSegments(['a'], inp), outp) + self.assertEqual(ftp.toSegments(['a'], inp), outp) for inp, outp in [('//', []), ('//a', ['a']), ('a//', ['a']), ('a//b', ['a', 'b'])]: - self.assertEquals(ftp.toSegments([], inp), outp) + self.assertEqual(ftp.toSegments([], inp), outp) for inp, outp in [('//', []), ('//b', ['b']), ('b//c', ['a', 'b', 'c'])]: - self.assertEquals(ftp.toSegments(['a'], inp), outp) + self.assertEqual(ftp.toSegments(['a'], inp), outp) for inp, outp in [('..', []), ('../', []), @@ -2043,7 +2043,7 @@ ('/a/b/../../c/', ['c']), ('/a/b/../../c/..', []), ('/a/b/../../c/../', [])]: - self.assertEquals(ftp.toSegments(['x'], inp), outp) + self.assertEqual(ftp.toSegments(['x'], inp), outp) for inp in ['..', '../', 'a/../..', 'a/../../', '/..', '/../', '/a/../..', '/a/../../', @@ -2083,7 +2083,7 @@ iface, avatar, logout = realm.requestAvatar( "alice at example.com", None, ftp.IFTPShell) self.assertIsInstance(avatar, ftp.FTPShell) - self.assertEquals(avatar.filesystemRoot, result) + self.assertEqual(avatar.filesystemRoot, result) def test_anonymous(self): @@ -2096,7 +2096,7 @@ iface, avatar, logout = realm.requestAvatar( checkers.ANONYMOUS, None, ftp.IFTPShell) self.assertIsInstance(avatar, ftp.FTPAnonymousShell) - self.assertEquals(avatar.filesystemRoot, filepath.FilePath(anonymous)) + self.assertEqual(avatar.filesystemRoot, filepath.FilePath(anonymous)) def test_notImplemented(self): @@ -2122,7 +2122,7 @@ base = '/path/to/home' realm = ftp.FTPRealm(self.mktemp(), base) home = realm.getHomeDirectory('alice at example.com') - self.assertEquals( + self.assertEqual( filepath.FilePath(base).child('alice at example.com'), home) @@ -2133,7 +2133,7 @@ """ realm = ftp.FTPRealm(self.mktemp()) home = realm.getHomeDirectory('alice at example.com') - self.assertEquals(filepath.FilePath('/home/alice at example.com'), home) + self.assertEqual(filepath.FilePath('/home/alice at example.com'), home) @@ -2160,7 +2160,7 @@ realm = ftp.SystemFTPRealm(self.mktemp()) home = realm.getHomeDirectory(user) - self.assertEquals(home, filepath.FilePath(expected)) + self.assertEqual(home, filepath.FilePath(expected)) def test_noSuchUser(self): @@ -2426,7 +2426,7 @@ d = self.shell.list(('.',)) def cb(l): l.sort() - self.assertEquals(l, + self.assertEqual(l, [('file.txt', []), ('ned', [])]) return d.addCallback(cb) @@ -2440,13 +2440,13 @@ d = self.shell.list(('.',), ('size', 'permissions',)) def cb(l): l.sort() - self.assertEquals(len(l), 2) - self.assertEquals(l[0][0], 'file.txt') - self.assertEquals(l[1][0], 'ned') + self.assertEqual(len(l), 2) + self.assertEqual(l[0][0], 'file.txt') + self.assertEqual(l[1][0], 'ned') # Size and permissions are reported differently between platforms # so just check they are present - self.assertEquals(len(l[0][1]), 2) - self.assertEquals(len(l[1][1]), 2) + self.assertEqual(len(l[0][1]), 2) + self.assertEqual(len(l[1][1]), 2) return d.addCallback(cb) @@ -2467,7 +2467,7 @@ d = self.shell.list(('file.txt',)) def cb(l): l.sort() - self.assertEquals(l, + self.assertEqual(l, [('file.txt', [])]) return d.addCallback(cb) @@ -2570,7 +2570,7 @@ self.createFile('file.txt', fileContent) d = self.shell.stat(('file.txt',), ('size', 'directory')) def cb(res): - self.assertEquals(res[0], len(fileContent)) + self.assertEqual(res[0], len(fileContent)) self.assertFalse(res[1]) d.addCallback(cb) return d @@ -2595,7 +2595,7 @@ self.createDirectory('ned') d = self.shell.stat(('ned',), ('owner', 'group')) def cb(res): - self.assertEquals(len(res), 2) + self.assertEqual(len(res), 2) d.addCallback(cb) return d @@ -2783,7 +2783,7 @@ def cbGet(reader): return reader.send(consumer).addCallback(cbSend) def cbSend(res): - self.assertEquals("".join(consumer.buffer), content) + self.assertEqual("".join(consumer.buffer), content) return self.getFileReader(content).addCallback(cbGet) @@ -2804,7 +2804,7 @@ consumer.unregisterProducer() return writer.close().addCallback(cbClose) def cbClose(ignored): - self.assertEquals(self.getFileContent(), content) + self.assertEqual(self.getFileContent(), content) return self.getFileWriter().addCallback(cbGet) diff --git a/lib/twisted-trunk/twisted/test/test_hook.py b/lib/twisted-trunk/twisted/test/test_hook.py --- a/lib/twisted-trunk/twisted/test/test_hook.py +++ b/lib/twisted-trunk/twisted/test/test_hook.py @@ -95,56 +95,56 @@ """make sure that the base class's hook is called reliably """ base = BaseClass() - self.assertEquals(base.calledBase, 0) - self.assertEquals(base.calledBasePre, 0) + self.assertEqual(base.calledBase, 0) + self.assertEqual(base.calledBasePre, 0) base.func(1,2) - self.assertEquals(base.calledBase, 1) - self.assertEquals(base.calledBasePre, 0) + self.assertEqual(base.calledBase, 1) + self.assertEqual(base.calledBasePre, 0) hook.addPre(BaseClass, "func", basePre) base.func(1, b=2) - self.assertEquals(base.calledBase, 2) - self.assertEquals(base.calledBasePre, 1) + self.assertEqual(base.calledBase, 2) + self.assertEqual(base.calledBasePre, 1) hook.addPost(BaseClass, "func", basePost) base.func(1, b=2) - self.assertEquals(base.calledBasePost, 1) - self.assertEquals(base.calledBase, 3) - self.assertEquals(base.calledBasePre, 2) + self.assertEqual(base.calledBasePost, 1) + self.assertEqual(base.calledBase, 3) + self.assertEqual(base.calledBasePre, 2) hook.removePre(BaseClass, "func", basePre) hook.removePost(BaseClass, "func", basePost) base.func(1, b=2) - self.assertEquals(base.calledBasePost, 1) - self.assertEquals(base.calledBase, 4) - self.assertEquals(base.calledBasePre, 2) + self.assertEqual(base.calledBasePost, 1) + self.assertEqual(base.calledBase, 4) + self.assertEqual(base.calledBasePre, 2) def testSubHook(self): """test interactions between base-class hooks and subclass hooks """ sub = SubClass() - self.assertEquals(sub.calledSub, 0) - self.assertEquals(sub.calledBase, 0) + self.assertEqual(sub.calledSub, 0) + self.assertEqual(sub.calledBase, 0) sub.func(1, b=2) - self.assertEquals(sub.calledSub, 1) - self.assertEquals(sub.calledBase, 1) + self.assertEqual(sub.calledSub, 1) + self.assertEqual(sub.calledBase, 1) hook.addPre(SubClass, 'func', subPre) - self.assertEquals(sub.calledSub, 1) - self.assertEquals(sub.calledBase, 1) - self.assertEquals(sub.calledSubPre, 0) - self.assertEquals(sub.calledBasePre, 0) + self.assertEqual(sub.calledSub, 1) + self.assertEqual(sub.calledBase, 1) + self.assertEqual(sub.calledSubPre, 0) + self.assertEqual(sub.calledBasePre, 0) sub.func(1, b=2) - self.assertEquals(sub.calledSub, 2) - self.assertEquals(sub.calledBase, 2) - self.assertEquals(sub.calledSubPre, 1) - self.assertEquals(sub.calledBasePre, 0) + self.assertEqual(sub.calledSub, 2) + self.assertEqual(sub.calledBase, 2) + self.assertEqual(sub.calledSubPre, 1) + self.assertEqual(sub.calledBasePre, 0) # let the pain begin hook.addPre(BaseClass, 'func', basePre) BaseClass.func(sub, 1, b=2) # sub.func(1, b=2) - self.assertEquals(sub.calledBase, 3) - self.assertEquals(sub.calledBasePre, 1, str(sub.calledBasePre)) + self.assertEqual(sub.calledBase, 3) + self.assertEqual(sub.calledBasePre, 1, str(sub.calledBasePre)) sub.func(1, b=2) - self.assertEquals(sub.calledBasePre, 2) - self.assertEquals(sub.calledBase, 4) - self.assertEquals(sub.calledSubPre, 2) - self.assertEquals(sub.calledSub, 3) + self.assertEqual(sub.calledBasePre, 2) + self.assertEqual(sub.calledBase, 4) + self.assertEqual(sub.calledSubPre, 2) + self.assertEqual(sub.calledSub, 3) testCases = [HookTestCase] diff --git a/lib/twisted-trunk/twisted/test/test_htb.py b/lib/twisted-trunk/twisted/test/test_htb.py --- a/lib/twisted-trunk/twisted/test/test_htb.py +++ b/lib/twisted-trunk/twisted/test/test_htb.py @@ -31,7 +31,7 @@ """Testing the size of the bucket.""" b = SomeBucket() fit = b.add(1000) - self.failUnlessEqual(100, fit) + self.assertEqual(100, fit) def testBucketDrian(self): """Testing the bucket's drain rate.""" @@ -39,7 +39,7 @@ fit = b.add(1000) self.clock.set(10) fit = b.add(1000) - self.failUnlessEqual(20, fit) + self.assertEqual(20, fit) class TestBucketNesting(TestBucketBase): def setUp(self): @@ -52,7 +52,7 @@ # Use up most of the parent bucket. self.child1.add(90) fit = self.child2.add(90) - self.failUnlessEqual(10, fit) + self.assertEqual(10, fit) def testBucketParentRate(self): # Make the parent bucket drain slower. @@ -65,7 +65,7 @@ # but the parent bucket only ten (so no, it wouldn't make too much # sense to have a child bucket draining faster than its parent in a real # application.) - self.failUnlessEqual(10, fit) + self.assertEqual(10, fit) # TODO: Test the Transport stuff? @@ -87,10 +87,10 @@ self.shaped.write("x" * 100) self.clock.set(delta_t) self.shaped.resumeProducing() - self.failUnlessEqual(len(self.underlying.getvalue()), + self.assertEqual(len(self.underlying.getvalue()), delta_t * self.bucket.rate) def testBucketRefs(self): - self.failUnlessEqual(self.bucket._refcount, 1) + self.assertEqual(self.bucket._refcount, 1) self.shaped.stopProducing() - self.failUnlessEqual(self.bucket._refcount, 0) + self.assertEqual(self.bucket._refcount, 0) diff --git a/lib/twisted-trunk/twisted/test/test_ident.py b/lib/twisted-trunk/twisted/test/test_ident.py --- a/lib/twisted-trunk/twisted/test/test_ident.py +++ b/lib/twisted-trunk/twisted/test/test_ident.py @@ -105,31 +105,31 @@ p.exceptionType = ident.IdentError p.lineReceived('123, 345') - self.assertEquals(L[0], '123, 345 : ERROR : UNKNOWN-ERROR') + self.assertEqual(L[0], '123, 345 : ERROR : UNKNOWN-ERROR') p.exceptionType = ident.NoUser p.lineReceived('432, 210') - self.assertEquals(L[1], '432, 210 : ERROR : NO-USER') + self.assertEqual(L[1], '432, 210 : ERROR : NO-USER') p.exceptionType = ident.InvalidPort p.lineReceived('987, 654') - self.assertEquals(L[2], '987, 654 : ERROR : INVALID-PORT') + self.assertEqual(L[2], '987, 654 : ERROR : INVALID-PORT') p.exceptionType = ident.HiddenUser p.lineReceived('756, 827') - self.assertEquals(L[3], '756, 827 : ERROR : HIDDEN-USER') + self.assertEqual(L[3], '756, 827 : ERROR : HIDDEN-USER') p.exceptionType = NewException p.lineReceived('987, 789') - self.assertEquals(L[4], '987, 789 : ERROR : UNKNOWN-ERROR') + self.assertEqual(L[4], '987, 789 : ERROR : UNKNOWN-ERROR') errs = self.flushLoggedErrors(NewException) - self.assertEquals(len(errs), 1) + self.assertEqual(len(errs), 1) for port in -1, 0, 65536, 65537: del L[:] p.lineReceived('%d, 5' % (port,)) p.lineReceived('5, %d' % (port,)) - self.assertEquals( + self.assertEqual( L, ['%d, 5 : ERROR : INVALID-PORT' % (port,), '5, %d : ERROR : INVALID-PORT' % (port,)]) @@ -141,7 +141,7 @@ p.resultValue = ('SYS', 'USER') p.lineReceived('123, 456') - self.assertEquals(L[0], '123, 456 : USERID : SYS : USER') + self.assertEqual(L[0], '123, 456 : USERID : SYS : USER') if struct.pack('=L', 1)[0] == '\x01': @@ -159,16 +159,16 @@ def testDottedQuadFromHexString(self): p = ident.ProcServerMixin() - self.assertEquals(p.dottedQuadFromHexString(_addr1), '127.0.0.1') + self.assertEqual(p.dottedQuadFromHexString(_addr1), '127.0.0.1') def testUnpackAddress(self): p = ident.ProcServerMixin() - self.assertEquals(p.unpackAddress(_addr1 + ':0277'), + self.assertEqual(p.unpackAddress(_addr1 + ':0277'), ('127.0.0.1', 631)) def testLineParser(self): p = ident.ProcServerMixin() - self.assertEquals( + self.assertEqual( p.parseLine(self.line), (('127.0.0.1', 25), ('1.2.3.4', 762), 0)) @@ -177,10 +177,10 @@ p = ident.ProcServerMixin() p.entries = lambda: iter([self.line]) p.getUsername = lambda uid: (username.append(uid), 'root')[1] - self.assertEquals( + self.assertEqual( p.lookup(('127.0.0.1', 25), ('1.2.3.4', 762)), (p.SYSTEM_NAME, 'root')) - self.assertEquals(username, [0]) + self.assertEqual(username, [0]) def testNonExistingAddress(self): p = ident.ProcServerMixin() diff --git a/lib/twisted-trunk/twisted/test/test_internet.py b/lib/twisted-trunk/twisted/test/test_internet.py --- a/lib/twisted-trunk/twisted/test/test_internet.py +++ b/lib/twisted-trunk/twisted/test/test_internet.py @@ -667,7 +667,7 @@ floats: For example, datetime-datetime == timedelta(0). """ now = reactor.seconds() - self.assertEquals(now-now+now, now) + self.assertEqual(now-now+now, now) def test_callLaterUsesReactorSecondsInDelayedCall(self): @@ -679,7 +679,7 @@ reactor.seconds = lambda: 100 try: call = reactor.callLater(5, lambda: None) - self.assertEquals(call.getTime(), 105) + self.assertEqual(call.getTime(), 105) finally: reactor.seconds = oseconds @@ -693,7 +693,7 @@ reactor.seconds = lambda: 100 try: call = reactor.callLater(5, lambda: None) - self.assertEquals(call.seconds(), 100) + self.assertEqual(call.seconds(), 100) finally: reactor.seconds = oseconds @@ -795,9 +795,9 @@ def f2(x): l2.append(x) def done(): - self.assertEquals(l, range(20)) + self.assertEqual(l, range(20)) def done2(): - self.assertEquals(l2, range(10)) + self.assertEqual(l2, range(10)) for n in range(10): reactor.callLater(0, f, n) @@ -866,9 +866,9 @@ return 10 dc = base.DelayedCall(5, lambda: None, (), {}, lambda dc: None, lambda dc: None, seconds) - self.assertEquals(dc.getTime(), 5) + self.assertEqual(dc.getTime(), 5) dc.reset(3) - self.assertEquals(dc.getTime(), 13) + self.assertEqual(dc.getTime(), 13) class CallFromThreadTests(unittest.TestCase): @@ -987,10 +987,10 @@ L{IDelayedCall.active} returns False once the call has run. """ dcall = reactor.callLater(0.01, self.deferred.callback, True) - self.assertEquals(dcall.active(), True) + self.assertEqual(dcall.active(), True) def checkDeferredCall(success): - self.assertEquals(dcall.active(), False) + self.assertEqual(dcall.active(), False) return success self.deferred.addCallback(checkDeferredCall) @@ -1123,7 +1123,7 @@ order = [] def check(_): - self.assertEquals(order, [1, 2, 3]) + self.assertEqual(order, [1, 2, 3]) self.deferred.addCallback(check) self.schedule(order.append, 1) @@ -1144,7 +1144,7 @@ self.schedule(incAndFinish) # Callback shouldn't have fired yet. - self.assertEquals(self.counter, 0) + self.assertEqual(self.counter, 0) return self.deferred @@ -1168,7 +1168,7 @@ def testFactory(self): factory = MyFactory() protocol = factory.buildProtocol(None) - self.assertEquals(protocol.factory, factory) + self.assertEqual(protocol.factory, factory) self.assert_( isinstance(protocol, factory.protocol) ) @@ -1268,7 +1268,7 @@ fd.connected = 1 dp = DummyProducer() fd.registerProducer(dp, 0) - self.assertEquals(dp.events, ['resume']) + self.assertEqual(dp.events, ['resume']) self.assertRaises(RuntimeError, fd.registerProducer, DummyProducer(), 0) @@ -1281,7 +1281,7 @@ fd.disconnected = 1 dp = DummyProducer() fd.registerProducer(dp, 0) - self.assertEquals(dp.events, ['stop']) + self.assertEqual(dp.events, ['stop']) def _dontPausePullConsumerTest(self, methodName): diff --git a/lib/twisted-trunk/twisted/test/test_iutils.py b/lib/twisted-trunk/twisted/test/test_iutils.py --- a/lib/twisted-trunk/twisted/test/test_iutils.py +++ b/lib/twisted-trunk/twisted/test/test_iutils.py @@ -48,7 +48,7 @@ " sys.stdout.write(s)", " sys.stdout.flush()"]) d = utils.getProcessOutput(self.exe, ['-u', scriptFile]) - return d.addCallback(self.assertEquals, "hello world\n") + return d.addCallback(self.assertEqual, "hello world\n") def test_outputWithErrorIgnored(self): @@ -116,9 +116,9 @@ ]) def gotOutputAndValue((out, err, code)): - self.assertEquals(out, "hello world!\n") - self.assertEquals(err, "goodbye world!" + os.linesep) - self.assertEquals(code, 1) + self.assertEqual(out, "hello world!\n") + self.assertEqual(err, "goodbye world!" + os.linesep) + self.assertEqual(code, 1) d = utils.getProcessOutputAndValue(self.exe, ["-u", scriptFile]) return d.addCallback(gotOutputAndValue) @@ -142,9 +142,9 @@ "os.kill(os.getpid(), signal.SIGKILL)"]) def gotOutputAndValue((out, err, sig)): - self.assertEquals(out, "stdout bytes\n") - self.assertEquals(err, "stderr bytes\n") - self.assertEquals(sig, signal.SIGKILL) + self.assertEqual(out, "stdout bytes\n") + self.assertEqual(err, "stderr bytes\n") + self.assertEqual(sig, signal.SIGKILL) d = utils.getProcessOutputAndValue(self.exe, ['-u', scriptFile]) d = self.assertFailure(d, tuple) @@ -283,14 +283,14 @@ # Start off with a sanity check - calling the original function # should emit the warning. f("Sanity check message") - self.assertEquals(len(self.warnings), 1) + self.assertEqual(len(self.warnings), 1) # Now that that's out of the way, call the wrapped function, and # make sure no new warnings show up. g("This is message") - self.assertEquals(len(self.warnings), 1) + self.assertEqual(len(self.warnings), 1) # Finally, emit another warning which should not be ignored, and # make sure it is not. g("Unignored message") - self.assertEquals(len(self.warnings), 2) + self.assertEqual(len(self.warnings), 2) diff --git a/lib/twisted-trunk/twisted/test/test_jelly.py b/lib/twisted-trunk/twisted/test/test_jelly.py --- a/lib/twisted-trunk/twisted/test/test_jelly.py +++ b/lib/twisted-trunk/twisted/test/test_jelly.py @@ -151,7 +151,7 @@ a.bmethod = b.bmethod b.a = a im_ = jelly.unjelly(jelly.jelly(b)).a.bmethod - self.assertEquals(im_.im_class, im_.im_self.__class__) + self.assertEqual(im_.im_class, im_.im_self.__class__) def test_methodsNotSelfIdentity(self): @@ -194,7 +194,7 @@ c = jelly.jelly(n) m = jelly.unjelly(c) self.assertIsInstance(m, E) - self.assertEquals(n.x, 1) + self.assertEqual(n.x, 1) def test_typeOldStyle(self): @@ -204,7 +204,7 @@ """ t = [C] r = jelly.unjelly(jelly.jelly(t)) - self.assertEquals(t, r) + self.assertEqual(t, r) def test_typeNewStyle(self): @@ -214,7 +214,7 @@ """ t = [D] r = jelly.unjelly(jelly.jelly(t)) - self.assertEquals(t, r) + self.assertEqual(t, r) def test_typeBuiltin(self): @@ -224,7 +224,7 @@ """ t = [str] r = jelly.unjelly(jelly.jelly(t)) - self.assertEquals(t, r) + self.assertEqual(t, r) def test_dateTime(self): @@ -233,7 +233,7 @@ input = [dtn, dtd] c = jelly.jelly(input) output = jelly.unjelly(c) - self.assertEquals(input, output) + self.assertEqual(input, output) self.assertNotIdentical(input, output) @@ -249,7 +249,7 @@ decimal.Decimal('-78.901')] c = jelly.jelly(inputList) output = jelly.unjelly(c) - self.assertEquals(inputList, output) + self.assertEqual(inputList, output) self.assertNotIdentical(inputList, output) @@ -274,7 +274,7 @@ decimal.Decimal(123456), decimal.Decimal('-78.901')] output = jelly.unjelly(self.decimalData) - self.assertEquals(output, expected) + self.assertEqual(output, expected) def test_decimalMissing(self): @@ -284,16 +284,16 @@ """ self.patch(jelly, 'decimal', None) output = jelly.unjelly(self.decimalData) - self.assertEquals(len(output), 4) + self.assertEqual(len(output), 4) for i in range(4): self.assertIsInstance(output[i], jelly.Unpersistable) - self.assertEquals(output[0].reason, + self.assertEqual(output[0].reason, "Could not unpersist decimal: 9.95") - self.assertEquals(output[1].reason, + self.assertEqual(output[1].reason, "Could not unpersist decimal: 0") - self.assertEquals(output[2].reason, + self.assertEqual(output[2].reason, "Could not unpersist decimal: 123456") - self.assertEquals(output[3].reason, + self.assertEqual(output[3].reason, "Could not unpersist decimal: -78.901") @@ -321,7 +321,7 @@ """ inputList = [set([1, 2, 3])] output = jelly.unjelly(jelly.jelly(inputList)) - self.assertEquals(inputList, output) + self.assertEqual(inputList, output) self.assertNotIdentical(inputList, output) @@ -333,7 +333,7 @@ """ inputList = [frozenset([1, 2, 3])] output = jelly.unjelly(jelly.jelly(inputList)) - self.assertEquals(inputList, output) + self.assertEqual(inputList, output) self.assertNotIdentical(inputList, output) @@ -364,10 +364,10 @@ """ inputList = [jelly._sets.Set([1, 2, 3])] inputJelly = jelly.jelly(inputList) - self.assertEquals(inputJelly, jelly.jelly([set([1, 2, 3])])) + self.assertEqual(inputJelly, jelly.jelly([set([1, 2, 3])])) output = jelly.unjelly(inputJelly) # Even if the class is different, it should coerce to the same list - self.assertEquals(list(inputList[0]), list(output[0])) + self.assertEqual(list(inputList[0]), list(output[0])) if set is jelly._sets.Set: self.assertIsInstance(output[0], jelly._sets.Set) else: @@ -382,10 +382,10 @@ """ inputList = [jelly._sets.ImmutableSet([1, 2, 3])] inputJelly = jelly.jelly(inputList) - self.assertEquals(inputJelly, jelly.jelly([frozenset([1, 2, 3])])) + self.assertEqual(inputJelly, jelly.jelly([frozenset([1, 2, 3])])) output = jelly.unjelly(inputJelly) # Even if the class is different, it should coerce to the same list - self.assertEquals(list(inputList[0]), list(output[0])) + self.assertEqual(list(inputList[0]), list(output[0])) if frozenset is jelly._sets.ImmutableSet: self.assertIsInstance(output[0], jelly._sets.ImmutableSet) else: @@ -423,8 +423,8 @@ def test_unicode(self): x = unicode('blah') y = jelly.unjelly(jelly.jelly(x)) - self.assertEquals(x, y) - self.assertEquals(type(x), type(y)) + self.assertEqual(x, y) + self.assertEqual(type(x), type(y)) def test_stressReferences(self): @@ -471,7 +471,7 @@ items = [afunc, [1, 2, 3], not bool(1), bool(1), 'test', 20.3, (1, 2, 3), None, A, unittest, {'a': 1}, A.amethod] for i in items: - self.assertEquals(i, jelly.unjelly(jelly.jelly(i))) + self.assertEqual(i, jelly.unjelly(jelly.jelly(i))) def test_setState(self): @@ -534,7 +534,7 @@ input = JellyableTestClass() input.attribute = 'value' output = jelly.unjelly(jelly.jelly(input)) - self.assertEquals(output.attribute, 'value') + self.assertEqual(output.attribute, 'value') self.assertIsInstance(output, jelly.Unjellyable) @@ -655,7 +655,7 @@ s.add(a) res = jelly.unjelly(jelly.jelly(a)) self.assertIsInstance(res.x, set) - self.assertEquals(list(res.x), [res]) + self.assertEqual(list(res.x), [res]) def test_frozenset(self): @@ -668,4 +668,4 @@ a.x = s res = jelly.unjelly(jelly.jelly(a)) self.assertIsInstance(res.x, frozenset) - self.assertEquals(list(res.x), [res]) + self.assertEqual(list(res.x), [res]) diff --git a/lib/twisted-trunk/twisted/test/test_journal.py b/lib/twisted-trunk/twisted/test/test_journal.py --- a/lib/twisted-trunk/twisted/test/test_journal.py +++ b/lib/twisted-trunk/twisted/test/test_journal.py @@ -6,15 +6,16 @@ Testing for twisted.persisted.journal. """ +import shutil, os.path, sys + from twisted.trial import unittest -from twisted.test.test_modules import PySpaceTestCase + from twisted.persisted.journal.base import ICommand, MemoryJournal, serviceCommand, ServiceWrapperCommand, command, Wrappable from twisted.persisted.journal.picklelog import DirDBMLog from twisted.python import deprecate, versions from zope.interface import implements -import shutil, os.path, sys - +from twisted.python.test.modules_helpers import TwistedModulesTestCase class AddTime: @@ -133,7 +134,7 @@ def testCommandExecution(self): svc = self.svc svc.add(svc.journal, "foo", "bar") - self.assertEquals(svc.get("foo"), "bar") + self.assertEqual(svc.get("foo"), "bar") svc.delete(svc.journal, "foo") self.assertRaises(KeyError, svc.get, "foo") @@ -151,10 +152,10 @@ ServiceWrapperCommand("_add", (1, "hello")), ServiceWrapperCommand("_delete", ("foo",))] - self.assertEquals(log.getCurrentIndex(), 3) + self.assertEqual(log.getCurrentIndex(), 3) for i in range(1, 4): for a, b in zip(commands[i-1:], [c for t, c in log.getCommandsSince(i)]): - self.assertEquals(a, b) + self.assertEqual(a, b) def testRecovery(self): @@ -171,8 +172,8 @@ # first, load from snapshot svc = Service(self.logpath, self.journalpath) - self.assertEquals(svc.values, {1: "hello"}) - self.assertEquals(svc.counters[1].x, 1) + self.assertEqual(svc.values, {1: "hello"}) + self.assertEqual(svc.counters[1].x, 1) del svc # now, tamper with log, and then try @@ -180,8 +181,8 @@ f.write("sfsdfsdfsd") f.close() svc = Service(self.logpath, self.journalpath) - self.assertEquals(svc.values, {1: "hello"}) - self.assertEquals(svc.counters[1].x, 1) + self.assertEqual(svc.values, {1: "hello"}) + self.assertEqual(svc.counters[1].x, 1) def testTime(self): @@ -191,11 +192,11 @@ log = self.svc.journal.log (t2, c), = log.getCommandsSince(1) - self.assertEquals(t, t2) + self.assertEqual(t, t2) -class JournalDeprecationTest(PySpaceTestCase): +class JournalDeprecationTest(TwistedModulesTestCase): """ Tests for twisted.persisted.journal being deprecated. """ @@ -225,7 +226,6 @@ del(listOfStuff[j]) else: j += 1 - duplicates = [] def test_deprecated(self): @@ -240,9 +240,9 @@ # emitted twice in this case. Bug will be filed self.uniquify(warnings) - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], deprecate.getDeprecationWarningString(journal, versions.Version('twisted', 11, 0, 0)) + diff --git a/lib/twisted-trunk/twisted/test/test_log.py b/lib/twisted-trunk/twisted/test/test_log.py --- a/lib/twisted-trunk/twisted/test/test_log.py +++ b/lib/twisted-trunk/twisted/test/test_log.py @@ -34,10 +34,10 @@ catcher = self.catcher log.msg("test", testShouldCatch=True) i = catcher.pop() - self.assertEquals(i["message"][0], "test") - self.assertEquals(i["testShouldCatch"], True) + self.assertEqual(i["message"][0], "test") + self.assertEqual(i["testShouldCatch"], True) self.failUnless(i.has_key("time")) - self.assertEquals(len(catcher), 0) + self.assertEqual(len(catcher), 0) def testContext(self): @@ -48,10 +48,10 @@ log.callWithContext, {"subsubsystem": "b"}, log.msg, "foo", other="d") i = catcher.pop() - self.assertEquals(i['subsubsystem'], 'b') - self.assertEquals(i['subsystem'], 'not the default') - self.assertEquals(i['other'], 'd') - self.assertEquals(i['message'][0], 'foo') + self.assertEqual(i['subsubsystem'], 'b') + self.assertEqual(i['subsystem'], 'not the default') + self.assertEqual(i['other'], 'd') + self.assertEqual(i['message'][0], 'foo') def testErrors(self): for e, ig in [("hello world","hello world"), @@ -59,7 +59,7 @@ (failure.Failure(RuntimeError()), RuntimeError)]: log.err(e) i = self.catcher.pop() - self.assertEquals(i['isError'], 1) + self.assertEqual(i['isError'], 1) self.flushLoggedErrors(ig) def testErrorsWithWhy(self): @@ -68,8 +68,8 @@ (failure.Failure(RuntimeError()), RuntimeError)]: log.err(e, 'foobar') i = self.catcher.pop() - self.assertEquals(i['isError'], 1) - self.assertEquals(i['why'], 'foobar') + self.assertEqual(i['isError'], 1) + self.assertEqual(i['why'], 'foobar') self.flushLoggedErrors(ig) @@ -106,13 +106,66 @@ self.assertEqual(len(excs), 1) # Both other observers should have seen the message. - self.assertEquals(len(L1), 2) - self.assertEquals(len(L2), 2) + self.assertEqual(len(L1), 2) + self.assertEqual(len(L2), 2) # The order is slightly wrong here. The first event should be # delivered to all observers; then, errors should be delivered. - self.assertEquals(L1[1]['message'], ("Howdy, y'all.",)) - self.assertEquals(L2[0]['message'], ("Howdy, y'all.",)) + self.assertEqual(L1[1]['message'], ("Howdy, y'all.",)) + self.assertEqual(L2[0]['message'], ("Howdy, y'all.",)) + + + def test_doubleErrorDoesNotRemoveObserver(self): + """ + If logging causes an error, make sure that if logging the fact that + logging failed also causes an error, the log observer is not removed. + """ + catcher = [] + + publisher = log.LogPublisher() + oldLogPublisher = log.theLogPublisher + log.theLogPublisher = publisher + log.msg = publisher.msg + + def _cleanup(): + log.theLogPublisher = oldLogPublisher + log.msg = oldLogPublisher.msg + self.addCleanup(_cleanup) + + class FailingObserver(list): + calls = 0 + def log(self, msg, **kwargs): + # First call raises RuntimeError: + self.calls += 1 + if self.calls < 2: + raise RuntimeError("Failure #%s" % (len(calls),)) + else: + self.append(msg) + observer = FailingObserver() + publisher.addObserver(observer.log) + self.assertEqual(publisher.observers, [observer.log]) + + try: + # When observer throws, the publisher attempts to log the fact by + # calling err()... which also fails with recursion error: + oldError = log.err + def failingErr(*arg, **kwargs): + raise RuntimeError("Fake recursion error") + log.err = failingErr + publisher.msg("error in first observer") + finally: + log.err = oldError + # Observer should still exist; we do this in finally since before + # bug was fixed the test would fail due to uncaught exception, so + # we want failing assert too in that case: + self.assertEqual(publisher.observers, [observer.log]) + + # The next message should succeed: + publisher.msg("but this should succeed") + + self.assertEqual(observer.calls, 2) + self.assertEqual(len(observer), 1) + self.assertEqual(observer[0]['message'], ("but this should succeed",)) def test_showwarning(self): @@ -240,7 +293,7 @@ class LogPublisherTestCase(LogPublisherTestCaseMixin, unittest.TestCase): def testSingleString(self): self.lp.msg("Hello, world.") - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) def testMultipleString(self): @@ -248,12 +301,12 @@ # If you are reading this and trying to learn how the logging # system works, *do not use this feature*. self.lp.msg("Hello, ", "world.") - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) def testSingleUnicode(self): self.lp.msg(u"Hello, \N{VULGAR FRACTION ONE HALF} world.") - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) self.assertIn('with str error', self.out[0]) self.assertIn('UnicodeEncodeError', self.out[0]) @@ -326,88 +379,88 @@ # Pretend to be in US/Eastern for a moment self.flo.getTimezoneOffset = lambda when: 18000 - self.assertEquals(self.flo.formatTime(when), '2001-02-02 23:05:06-0500') + self.assertEqual(self.flo.formatTime(when), '2001-02-02 23:05:06-0500') # Okay now we're in Eastern Europe somewhere self.flo.getTimezoneOffset = lambda when: -3600 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 05:05:06+0100') + self.assertEqual(self.flo.formatTime(when), '2001-02-03 05:05:06+0100') # And off in the Pacific or someplace like that self.flo.getTimezoneOffset = lambda when: -39600 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 15:05:06+1100') + self.assertEqual(self.flo.formatTime(when), '2001-02-03 15:05:06+1100') # One of those weird places with a half-hour offset timezone self.flo.getTimezoneOffset = lambda when: 5400 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 02:35:06-0130') + self.assertEqual(self.flo.formatTime(when), '2001-02-03 02:35:06-0130') # Half-hour offset in the other direction self.flo.getTimezoneOffset = lambda when: -5400 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 05:35:06+0130') + self.assertEqual(self.flo.formatTime(when), '2001-02-03 05:35:06+0130') # Test an offset which is between 0 and 60 minutes to make sure the # sign comes out properly in that case. self.flo.getTimezoneOffset = lambda when: 1800 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 03:35:06-0030') + self.assertEqual(self.flo.formatTime(when), '2001-02-03 03:35:06-0030') # Test an offset between 0 and 60 minutes in the other direction. self.flo.getTimezoneOffset = lambda when: -1800 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 04:35:06+0030') + self.assertEqual(self.flo.formatTime(when), '2001-02-03 04:35:06+0030') # If a strftime-format string is present on the logger, it should # use that instead. Note we don't assert anything about day, hour # or minute because we cannot easily control what time.strftime() # thinks the local timezone is. self.flo.timeFormat = '%Y %m' - self.assertEquals(self.flo.formatTime(when), '2001 02') + self.assertEqual(self.flo.formatTime(when), '2001 02') def test_loggingAnObjectWithBroken__str__(self): #HELLO, MCFLY self.lp.msg(EvilStr()) - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) # Logging system shouldn't need to crap itself for this trivial case self.assertNotIn('UNFORMATTABLE', self.out[0]) def test_formattingAnObjectWithBroken__str__(self): self.lp.msg(format='%(blat)s', blat=EvilStr()) - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) self.assertIn('Invalid format string or unformattable object', self.out[0]) def test_brokenSystem__str__(self): self.lp.msg('huh', system=EvilStr()) - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) self.assertIn('Invalid format string or unformattable object', self.out[0]) def test_formattingAnObjectWithBroken__repr__Indirect(self): self.lp.msg(format='%(blat)s', blat=[EvilRepr()]) - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) self.assertIn('UNFORMATTABLE OBJECT', self.out[0]) def test_systemWithBroker__repr__Indirect(self): self.lp.msg('huh', system=[EvilRepr()]) - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) self.assertIn('UNFORMATTABLE OBJECT', self.out[0]) def test_simpleBrokenFormat(self): self.lp.msg(format='hooj %s %s', blat=1) - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) self.assertIn('Invalid format string or unformattable object', self.out[0]) def test_ridiculousFormat(self): self.lp.msg(format=42, blat=1) - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) self.assertIn('Invalid format string or unformattable object', self.out[0]) def test_evilFormat__repr__And__str__(self): self.lp.msg(format=EvilReprStr(), blat=1) - self.assertEquals(len(self.out), 1) + self.assertEqual(len(self.out), 1) self.assertIn('PATHOLOGICAL', self.out[0]) @@ -416,7 +469,31 @@ This kind of eventDict used to fail silently, so test it does. """ self.lp.msg(message='', isError=False) - self.assertEquals(len(self.out), 0) + self.assertEqual(len(self.out), 0) + + + def test_startLogging(self): + """ + startLogging() installs FileLogObserver and overrides sys.stdout and + sys.stderr. + """ + # When done with test, reset stdout and stderr to current values: + origStdout, origStderr = sys.stdout, sys.stderr + self.addCleanup(setattr, sys, 'stdout', sys.stdout) + self.addCleanup(setattr, sys, 'stderr', sys.stderr) + fakeFile = StringIO() + observer = log.startLogging(fakeFile) + self.addCleanup(observer.stop) + log.msg("Hello!") + self.assertIn("Hello!", fakeFile.getvalue()) + self.assertIsInstance(sys.stdout, log.StdioOnnaStick) + self.assertEqual(sys.stdout.isError, False) + self.assertEqual(sys.stdout.encoding, + origStdout.encoding or sys.getdefaultencoding()) + self.assertIsInstance(sys.stderr, log.StdioOnnaStick) + self.assertEqual(sys.stderr.isError, True) + self.assertEqual(sys.stderr.encoding, + origStderr.encoding or sys.getdefaultencoding()) def test_startLoggingTwice(self): @@ -429,7 +506,8 @@ # handle stdout. If we use our own stream, the error doesn't occur. If # we use our own LogPublisher, the error doesn't occur. sys.stdout = StringIO() - self.addCleanup(setattr, sys, 'stdout', sys.__stdout__) + self.addCleanup(setattr, sys, 'stdout', sys.stdout) + self.addCleanup(setattr, sys, 'stderr', sys.stderr) def showError(eventDict): if eventDict['isError']: @@ -511,7 +589,7 @@ message isn't recorded. """ self.lp.msg(message='', isError=False) - self.assertEquals(self.out.getvalue(), '') + self.assertEqual(self.out.getvalue(), '') class PythonLoggingIntegrationTestCase(unittest.TestCase): @@ -531,9 +609,9 @@ log.removeObserver = l.remove obs = log.PythonLoggingObserver() obs.start() - self.assertEquals(l[0], obs.emit) + self.assertEqual(l[0], obs.emit) obs.stop() - self.assertEquals(len(l), 0) + self.assertEqual(len(l), 0) finally: log.addObserver = oldAddObserver log.removeObserver = oldRemoveObserver @@ -553,7 +631,7 @@ try: log.PythonLoggingObserver.emit = l.append obs.emit('foo') - self.assertEquals(len(l), 1) + self.assertEqual(len(l), 1) finally: log.PythonLoggingObserver.emit = oldEmit @@ -569,7 +647,7 @@ generated by DefaultObserver. """ from StringIO import StringIO - + obs = log.DefaultObserver() obs.stderr = StringIO() obs.start() @@ -579,6 +657,101 @@ errors = self.flushLoggedErrors() self.assertSubstring(reason, obs.stderr.getvalue()) - self.assertEquals(len(errors), 1) + self.assertEqual(len(errors), 1) obs.stop() + + + +class StdioOnnaStickTestCase(unittest.TestCase): + """ + StdioOnnaStick should act like the normal sys.stdout object. + """ + + def setUp(self): + self.resultLogs = [] + log.addObserver(self.resultLogs.append) + + + def tearDown(self): + log.removeObserver(self.resultLogs.append) + + + def getLogMessages(self): + return ["".join(d['message']) for d in self.resultLogs] + + + def test_write(self): + """ + Writing to a StdioOnnaStick instance results in Twisted log messages. + + Log messages are generated every time a '\n' is encountered. + """ + stdio = log.StdioOnnaStick() + stdio.write("Hello there\nThis is a test") + self.assertEqual(self.getLogMessages(), ["Hello there"]) + stdio.write("!\n") + self.assertEqual(self.getLogMessages(), ["Hello there", "This is a test!"]) + + + def test_metadata(self): + """ + The log messages written by StdioOnnaStick have printed=1 keyword, and + by default are not errors. + """ + stdio = log.StdioOnnaStick() + stdio.write("hello\n") + self.assertEqual(self.resultLogs[0]['isError'], False) + self.assertEqual(self.resultLogs[0]['printed'], True) + + + def test_writeLines(self): + """ + Writing lines to a StdioOnnaStick results in Twisted log messages. + """ + stdio = log.StdioOnnaStick() + stdio.writelines(["log 1", "log 2"]) + self.assertEqual(self.getLogMessages(), ["log 1", "log 2"]) + + + def test_print(self): + """ + When StdioOnnaStick is set as sys.stdout, prints become log messages. + """ + oldStdout = sys.stdout + sys.stdout = log.StdioOnnaStick() + self.addCleanup(setattr, sys, "stdout", oldStdout) + print "This", + print "is a test" + self.assertEqual(self.getLogMessages(), ["This is a test"]) + + + def test_error(self): + """ + StdioOnnaStick created with isError=True log messages as errors. + """ + stdio = log.StdioOnnaStick(isError=True) + stdio.write("log 1\n") + self.assertEqual(self.resultLogs[0]['isError'], True) + + + def test_unicode(self): + """ + StdioOnnaStick converts unicode prints to strings, in order to be + compatible with the normal stdout/stderr objects. + """ + unicodeString = u"Hello, \N{VULGAR FRACTION ONE HALF} world." + stdio = log.StdioOnnaStick(encoding="utf-8") + self.assertEqual(stdio.encoding, "utf-8") + stdio.write(unicodeString + u"\n") + stdio.writelines([u"Also, " + unicodeString]) + oldStdout = sys.stdout + sys.stdout = stdio + self.addCleanup(setattr, sys, "stdout", oldStdout) + # This should go to the log, utf-8 encoded too: + print unicodeString + self.assertEqual(self.getLogMessages(), + [unicodeString.encode("utf-8"), + (u"Also, " + unicodeString).encode("utf-8"), + unicodeString.encode("utf-8")]) + diff --git a/lib/twisted-trunk/twisted/test/test_logfile.py b/lib/twisted-trunk/twisted/test/test_logfile.py --- a/lib/twisted-trunk/twisted/test/test_logfile.py +++ b/lib/twisted-trunk/twisted/test/test_logfile.py @@ -38,7 +38,7 @@ log.close() f = open(self.path, "r") - self.assertEquals(f.read(), "1234567890") + self.assertEqual(f.read(), "1234567890") f.close() def testRotation(self): @@ -64,7 +64,7 @@ self.assert_(not os.path.exists("%s.4" % self.path)) log.close() - self.assertEquals(log.listLogs(), [1, 2, 3]) + self.assertEqual(log.listLogs(), [1, 2, 3]) def testAppend(self): log = logfile.LogFile(self.name, self.dir) @@ -72,14 +72,14 @@ log.close() log = logfile.LogFile(self.name, self.dir) - self.assertEquals(log.size, 10) - self.assertEquals(log._file.tell(), log.size) + self.assertEqual(log.size, 10) + self.assertEqual(log._file.tell(), log.size) log.write("abc") - self.assertEquals(log.size, 13) - self.assertEquals(log._file.tell(), log.size) + self.assertEqual(log.size, 13) + self.assertEqual(log._file.tell(), log.size) f = log._file f.seek(0, 0) - self.assertEquals(f.read(), "0123456789abc") + self.assertEqual(f.read(), "0123456789abc") log.close() def testLogReader(self): @@ -91,15 +91,15 @@ log.flush() # check reading logs - self.assertEquals(log.listLogs(), [1]) + self.assertEqual(log.listLogs(), [1]) reader = log.getCurrentLog() reader._file.seek(0) - self.assertEquals(reader.readLines(), ["ghi\n"]) - self.assertEquals(reader.readLines(), []) + self.assertEqual(reader.readLines(), ["ghi\n"]) + self.assertEqual(reader.readLines(), []) reader.close() reader = log.getLog(1) - self.assertEquals(reader.readLines(), ["abc\n", "def\n"]) - self.assertEquals(reader.readLines(), []) + self.assertEqual(reader.readLines(), ["abc\n", "def\n"]) + self.assertEqual(reader.readLines(), []) reader.close() # check getting illegal log readers @@ -108,15 +108,15 @@ # check that log numbers are higher for older logs log.rotate() - self.assertEquals(log.listLogs(), [1, 2]) + self.assertEqual(log.listLogs(), [1, 2]) reader = log.getLog(1) reader._file.seek(0) - self.assertEquals(reader.readLines(), ["ghi\n"]) - self.assertEquals(reader.readLines(), []) + self.assertEqual(reader.readLines(), ["ghi\n"]) + self.assertEqual(reader.readLines(), []) reader.close() reader = log.getLog(2) - self.assertEquals(reader.readLines(), ["abc\n", "def\n"]) - self.assertEquals(reader.readLines(), []) + self.assertEqual(reader.readLines(), ["abc\n", "def\n"]) + self.assertEqual(reader.readLines(), []) reader.close() def testModePreservation(self): @@ -129,7 +129,7 @@ log = logfile.LogFile(self.name, self.dir) log.write("abc") log.rotate() - self.assertEquals(mode, os.stat(self.path)[stat.ST_MODE]) + self.assertEqual(mode, os.stat(self.path)[stat.ST_MODE]) def test_noPermission(self): @@ -158,9 +158,9 @@ log.flush() f = log._file - self.assertEquals(f.tell(), 6) + self.assertEqual(f.tell(), 6) f.seek(0, 0) - self.assertEquals(f.read(), "abcdef") + self.assertEqual(f.read(), "abcdef") log.close() @@ -180,10 +180,10 @@ log.write("4" * 11) self.failUnless(os.path.exists("%s.3" % self.path)) - self.assertEquals(file("%s.3" % self.path).read(), "1" * 11) + self.assertEqual(file("%s.3" % self.path).read(), "1" * 11) log.write("5" * 11) - self.assertEquals(file("%s.3" % self.path).read(), "2" * 11) + self.assertEqual(file("%s.3" % self.path).read(), "2" * 11) self.failUnless(not os.path.exists("%s.4" % self.path)) def test_fromFullPath(self): @@ -192,10 +192,10 @@ """ log1 = logfile.LogFile(self.name, self.dir, 10, defaultMode=0777) log2 = logfile.LogFile.fromFullPath(self.path, 10, defaultMode=0777) - self.assertEquals(log1.name, log2.name) - self.assertEquals(os.path.abspath(log1.path), log2.path) - self.assertEquals(log1.rotateLength, log2.rotateLength) - self.assertEquals(log1.defaultMode, log2.defaultMode) + self.assertEqual(log1.name, log2.name) + self.assertEqual(os.path.abspath(log1.path), log2.path) + self.assertEqual(log1.rotateLength, log2.rotateLength) + self.assertEqual(log1.defaultMode, log2.defaultMode) def test_defaultPermissions(self): """ @@ -207,7 +207,7 @@ currentMode = stat.S_IMODE(os.stat(self.path)[stat.ST_MODE]) f.close() log1 = logfile.LogFile(self.name, self.dir) - self.assertEquals(stat.S_IMODE(os.stat(self.path)[stat.ST_MODE]), + self.assertEqual(stat.S_IMODE(os.stat(self.path)[stat.ST_MODE]), currentMode) @@ -219,9 +219,9 @@ mode = stat.S_IMODE(os.stat(self.path)[stat.ST_MODE]) if runtime.platform.isWindows(): # The only thing we can get here is global read-only - self.assertEquals(mode, 0444) + self.assertEqual(mode, 0444) else: - self.assertEquals(mode, 0066) + self.assertEqual(mode, 0066) def test_reopen(self): @@ -238,10 +238,10 @@ log1.close() f = open(self.path, "r") - self.assertEquals(f.read(), "hello2") + self.assertEqual(f.read(), "hello2") f.close() f = open(savePath, "r") - self.assertEquals(f.read(), "hello1") + self.assertEqual(f.read(), "hello1") f.close() if runtime.platform.isWindows(): @@ -254,7 +254,7 @@ """ e = self.assertRaises( IOError, logfile.LogFile, self.name, 'this_dir_does_not_exist') - self.assertEquals(e.errno, errno.ENOENT) + self.assertEqual(e.errno, errno.ENOENT) @@ -292,7 +292,7 @@ log.close() f = open(self.path, "r") - self.assertEquals(f.read(), "1234567890") + self.assertEqual(f.read(), "1234567890") f.close() def testRotation(self): diff --git a/lib/twisted-trunk/twisted/test/test_loopback.py b/lib/twisted-trunk/twisted/test/test_loopback.py --- a/lib/twisted-trunk/twisted/test/test_loopback.py +++ b/lib/twisted-trunk/twisted/test/test_loopback.py @@ -57,9 +57,9 @@ s.conn.addCallback(sendALine) def check(ignored): - self.assertEquals(c.lines, ["THIS IS LINE ONE!"]) - self.assertEquals(len(s.connLost), 1) - self.assertEquals(len(c.connLost), 1) + self.assertEqual(c.lines, ["THIS IS LINE ONE!"]) + self.assertEqual(len(s.connLost), 1) + self.assertEqual(len(c.connLost), 1) d = defer.maybeDeferred(self.loopbackFunc, s, c) d.addCallback(check) return d @@ -73,10 +73,10 @@ s.conn.addCallback(sendALine) def check(ignored): - self.assertEquals(s.lines, ['Hello 1', 'Hello 2', 'Hello 3']) - self.assertEquals(c.lines, ['DOOM LINE', 'Hello 1', 'Hello 2', 'Hello 3']) - self.assertEquals(len(s.connLost), 1) - self.assertEquals(len(c.connLost), 1) + self.assertEqual(s.lines, ['Hello 1', 'Hello 2', 'Hello 3']) + self.assertEqual(c.lines, ['DOOM LINE', 'Hello 1', 'Hello 2', 'Hello 3']) + self.assertEqual(len(s.connLost), 1) + self.assertEqual(len(c.connLost), 1) d = defer.maybeDeferred(self.loopbackFunc, s, c) d.addCallback(check) return d @@ -351,7 +351,7 @@ server = Protocol() finished = loopback.loopbackAsync(server, client, dummyPolicy) - self.assertEquals(pumpCalls, []) + self.assertEqual(pumpCalls, []) client.transport.write("foo") client.transport.write("bar") @@ -360,7 +360,7 @@ server.transport.loseConnection() def cbComplete(ignored): - self.assertEquals( + self.assertEqual( pumpCalls, # The order here is somewhat arbitrary. The implementation # happens to always deliver data to the client first. @@ -385,7 +385,7 @@ loopback.identityPumpPolicy(queue, client) - self.assertEquals(bytes, ["foo", "bar"]) + self.assertEqual(bytes, ["foo", "bar"]) def test_collapsingPumpPolicy(self): @@ -404,7 +404,7 @@ loopback.collapsingPumpPolicy(queue, client) - self.assertEquals(bytes, ["foobar"]) + self.assertEqual(bytes, ["foobar"]) diff --git a/lib/twisted-trunk/twisted/test/test_manhole.py b/lib/twisted-trunk/twisted/test/test_manhole.py --- a/lib/twisted-trunk/twisted/test/test_manhole.py +++ b/lib/twisted-trunk/twisted/test/test_manhole.py @@ -60,7 +60,7 @@ self.client.setZero() self.p.perspective_do("int(service is sys.modules['twisted.manhole.service'])") msg = self.client.getMessages()[0] - self.failUnlessEqual(msg, ('result',"1\n")) + self.assertEqual(msg, ('result',"1\n")) def test_importMain(self): """Trying to import __main__""" diff --git a/lib/twisted-trunk/twisted/test/test_memcache.py b/lib/twisted-trunk/twisted/test/test_memcache.py --- a/lib/twisted-trunk/twisted/test/test_memcache.py +++ b/lib/twisted-trunk/twisted/test/test_memcache.py @@ -255,8 +255,8 @@ @type result: C{any} """ def cb(res): - self.assertEquals(res, result) - self.assertEquals(self.transport.value(), send) + self.assertEqual(res, result) + self.assertEqual(self.transport.value(), send) d.addCallback(cb) self.proto.dataReceived(recv) return d @@ -302,7 +302,7 @@ self.assertFailure(d1, TimeoutError) self.assertFailure(d2, TimeoutError) def checkMessage(error): - self.assertEquals(str(error), "Connection timeout") + self.assertEqual(str(error), "Connection timeout") d1.addCallback(checkMessage) return gatherResults([d1, d2, d3]) @@ -317,8 +317,8 @@ self.proto.dataReceived("VALUE foo 0 3\r\nbar\r\nEND\r\n") def check(result): - self.assertEquals(result, (0, "bar")) - self.assertEquals(len(self.clock.calls), 0) + self.assertEqual(result, (0, "bar")) + self.assertEqual(len(self.clock.calls), 0) d.addCallback(check) return d @@ -368,15 +368,15 @@ self.proto.dataReceived("VALUE foo 0 3\r\nbar\r\nEND\r\n") def check(result): - self.assertEquals(result, (0, "bar")) - self.assertEquals(len(self.clock.calls), 1) + self.assertEqual(result, (0, "bar")) + self.assertEqual(len(self.clock.calls), 1) for i in range(self.proto.persistentTimeOut): self.clock.advance(1) return self.assertFailure(d2, TimeoutError).addCallback(checkTime) def checkTime(ignored): # Check that the timeout happened C{self.proto.persistentTimeOut} # after the last response - self.assertEquals( + self.assertEqual( self.clock.seconds(), 2 * self.proto.persistentTimeOut - 1) d1.addCallback(check) return d1 @@ -454,7 +454,7 @@ L{NoSuchCommand}. """ d = self.proto._set("egg", "foo", "bar", 0, 0, "") - self.assertEquals(self.transport.value(), "egg foo 0 0 3\r\nbar\r\n") + self.assertEqual(self.transport.value(), "egg foo 0 0 3\r\nbar\r\n") self.assertFailure(d, NoSuchCommand) self.proto.dataReceived("ERROR\r\n") return d @@ -468,11 +468,11 @@ """ a = "eggspamm" d = self.proto.set("foo", a) - self.assertEquals(self.transport.value(), + self.assertEqual(self.transport.value(), "set foo 0 0 8\r\neggspamm\r\n") self.assertFailure(d, ClientError) def check(err): - self.assertEquals(str(err), "We don't like egg and spam") + self.assertEqual(str(err), "We don't like egg and spam") d.addCallback(check) self.proto.dataReceived("CLIENT_ERROR We don't like egg and spam\r\n") return d @@ -486,11 +486,11 @@ """ a = "eggspamm" d = self.proto.set("foo", a) - self.assertEquals(self.transport.value(), + self.assertEqual(self.transport.value(), "set foo 0 0 8\r\neggspamm\r\n") self.assertFailure(d, ServerError) def check(err): - self.assertEquals(str(err), "zomg") + self.assertEqual(str(err), "zomg") d.addCallback(check) self.proto.dataReceived("SERVER_ERROR zomg\r\n") return d @@ -525,12 +525,12 @@ corresponding client command. """ d1 = self.proto.get("foo") - d1.addCallback(self.assertEquals, (0, "bar")) + d1.addCallback(self.assertEqual, (0, "bar")) d2 = self.proto.set("bar", "spamspamspam") - d2.addCallback(self.assertEquals, True) + d2.addCallback(self.assertEqual, True) d3 = self.proto.get("egg") - d3.addCallback(self.assertEquals, (0, "spam")) - self.assertEquals(self.transport.value(), + d3.addCallback(self.assertEqual, (0, "spam")) + self.assertEqual(self.transport.value(), "get foo\r\nset bar 0 0 12\r\nspamspamspam\r\nget egg\r\n") self.proto.dataReceived("VALUE foo 0 3\r\nbar\r\nEND\r\n" "STORED\r\n" @@ -544,8 +544,8 @@ is able to reconstruct it and to produce the good value. """ d = self.proto.get("foo") - d.addCallback(self.assertEquals, (0, "0123456789")) - self.assertEquals(self.transport.value(), "get foo\r\n") + d.addCallback(self.assertEqual, (0, "0123456789")) + self.assertEqual(self.transport.value(), "get foo\r\n") self.proto.dataReceived("VALUE foo 0 10\r\n0123456") self.proto.dataReceived("789") self.proto.dataReceived("\r\nEND") diff --git a/lib/twisted-trunk/twisted/test/test_modules.py b/lib/twisted-trunk/twisted/test/test_modules.py --- a/lib/twisted-trunk/twisted/test/test_modules.py +++ b/lib/twisted-trunk/twisted/test/test_modules.py @@ -18,62 +18,90 @@ from twisted.python.filepath import FilePath from twisted.python.reflect import namedAny +from twisted.python.test.modules_helpers import TwistedModulesTestCase from twisted.test.test_paths import zipit -class PySpaceTestCase(TestCase): +class BasicTests(TwistedModulesTestCase): - def findByIteration(self, modname, where=modules, importPackages=False): + def test_namespacedPackages(self): """ - You don't ever actually want to do this, so it's not in the public API, but - sometimes we want to compare the result of an iterative call with a - lookup call and make sure they're the same for test purposes. + Duplicate packages are not yielded when iterating over namespace + packages. """ - for modinfo in where.walkModules(importPackages=importPackages): - if modinfo.name == modname: - return modinfo - self.fail("Unable to find module %r through iteration." % (modname,)) + # Force pkgutil to be loaded already, since the probe package being + # created depends on it, and the replaceSysPath call below will make + # pretty much everything unimportable. + __import__('pkgutil') + namespaceBoilerplate = ( + 'import pkgutil; ' + '__path__ = pkgutil.extend_path(__path__, __name__)') - def replaceSysPath(self, sysPath): - """ - Replace sys.path, for the duration of the test, with the given value. - """ - originalSysPath = sys.path[:] - def cleanUpSysPath(): - sys.path[:] = originalSysPath - self.addCleanup(cleanUpSysPath) - sys.path[:] = sysPath + # Create two temporary directories with packages: + # + # entry: + # test_package/ + # __init__.py + # nested_package/ + # __init__.py + # module.py + # + # anotherEntry: + # test_package/ + # __init__.py + # nested_package/ + # __init__.py + # module2.py + # + # test_package and test_package.nested_package are namespace packages, + # and when both of these are in sys.path, test_package.nested_package + # should become a virtual package containing both "module" and + # "module2" + entry = self.pathEntryWithOnePackage() + testPackagePath = entry.child('test_package') + testPackagePath.child('__init__.py').setContent(namespaceBoilerplate) - def replaceSysModules(self, sysModules): - """ - Replace sys.modules, for the duration of the test, with the given value. - """ - originalSysModules = sys.modules.copy() - def cleanUpSysModules(): - sys.modules.clear() - sys.modules.update(originalSysModules) - self.addCleanup(cleanUpSysModules) - sys.modules.clear() - sys.modules.update(sysModules) + nestedEntry = testPackagePath.child('nested_package') + nestedEntry.makedirs() + nestedEntry.child('__init__.py').setContent(namespaceBoilerplate) + nestedEntry.child('module.py').setContent('') + anotherEntry = self.pathEntryWithOnePackage() + anotherPackagePath = anotherEntry.child('test_package') + anotherPackagePath.child('__init__.py').setContent(namespaceBoilerplate) - def pathEntryWithOnePackage(self, pkgname="test_package"): - """ - Generate a L{FilePath} with one package, named C{pkgname}, on it, and - return the L{FilePath} of the path entry. - """ - entry = FilePath(self.mktemp()) - pkg = entry.child("test_package") - pkg.makedirs() - pkg.child("__init__.py").setContent("") - return entry + anotherNestedEntry = anotherPackagePath.child('nested_package') + anotherNestedEntry.makedirs() + anotherNestedEntry.child('__init__.py').setContent(namespaceBoilerplate) + anotherNestedEntry.child('module2.py').setContent('') + self.replaceSysPath([entry.path, anotherEntry.path]) + module = modules.getModule('test_package') -class BasicTests(PySpaceTestCase): + # We have to use importPackages=True in order to resolve the namespace + # packages, so we remove the imported packages from sys.modules after + # walking + try: + walkedNames = [ + mod.name for mod in module.walkModules(importPackages=True)] + finally: + for module in sys.modules.keys(): + if module.startswith('test_package'): + del sys.modules[module] + + expected = [ + 'test_package', + 'test_package.nested_package', + 'test_package.nested_package.module', + 'test_package.nested_package.module2', + ] + + self.assertEqual(walkedNames, expected) + def test_unimportablePackageGetItem(self): """ @@ -88,8 +116,8 @@ importerCache={}, sysPathHooks={}, moduleDict={'test_package': None}) - self.assertEquals(shouldNotLoad, []) - self.assertEquals(path['test_package'].isLoaded(), False) + self.assertEqual(shouldNotLoad, []) + self.assertEqual(path['test_package'].isLoaded(), False) def test_unimportablePackageWalkModules(self): @@ -104,9 +132,9 @@ self.replaceSysModules({"test_package": None}) walked = list(modules.walkModules()) - self.assertEquals([m.name for m in walked], + self.assertEqual([m.name for m in walked], ["test_package"]) - self.assertEquals(walked[0].isLoaded(), False) + self.assertEqual(walked[0].isLoaded(), False) def test_nonexistentPaths(self): @@ -127,8 +155,8 @@ sys.path.append(nonexistentPath.path) afterModules = list(modules.walkModules()) - self.assertEquals(beforeModules, expected) - self.assertEquals(afterModules, expected) + self.assertEqual(beforeModules, expected) + self.assertEqual(afterModules, expected) def test_nonDirectoryPaths(self): @@ -148,7 +176,7 @@ sys.path.append(nonDirectoryPath.path) afterModules = list(modules.walkModules()) - self.assertEquals(beforeModules, afterModules) + self.assertEqual(beforeModules, afterModules) def test_twistedShowsUp(self): @@ -157,7 +185,7 @@ Twisted shows up, and that the module thusly obtained is the same as the module that we find when we look for it explicitly by name. """ - self.assertEquals(modules.getModule('twisted'), + self.assertEqual(modules.getModule('twisted'), self.findByIteration("twisted")) @@ -166,7 +194,7 @@ Verify that the walkModules APIs will give us back subpackages, not just subpackages. """ - self.assertEquals( + self.assertEqual( modules.getModule('twisted.python'), self.findByIteration("twisted.python", where=modules.getModule('twisted'))) @@ -240,9 +268,9 @@ mypath.child("abcd.py").setContent('\n') compileall.compile_dir(mypath.path, quiet=True) # sanity check - self.assertEquals(len(mypath.children()), 2) + self.assertEqual(len(mypath.children()), 2) pp._smartPath = _evilSmartPath - self.assertEquals(pp['abcd'].filePath, + self.assertEqual(pp['abcd'].filePath, mypath.child('abcd.py')) @@ -258,19 +286,18 @@ subpath.createDirectory() subpath.child("__init__.py").setContent('del __path__\n') sys.path.append(mypath.path) - import abcd + __import__("abcd") try: l = list(pp.walkModules()) - self.assertEquals(len(l), 1) - self.assertEquals(l[0].name, 'abcd') + self.assertEqual(len(l), 1) + self.assertEqual(l[0].name, 'abcd') finally: - del abcd del sys.modules['abcd'] sys.path.remove(mypath.path) -class PathModificationTest(PySpaceTestCase): +class PathModificationTest(TwistedModulesTestCase): """ These tests share setup/cleanup behavior of creating a dummy package and stuffing some code in it. @@ -309,11 +336,11 @@ # Cut here self._setupSysPath() modinfo = modules.getModule(self.packageName) - self.assertEquals( + self.assertEqual( self.findByIteration(self.packageName+".foozle", modinfo, importPackages=doImport), modinfo['foozle']) - self.assertEquals(modinfo['foozle'].load().x, 123) + self.assertEqual(modinfo['foozle'].load().x, 123) def test_underUnderPathAlreadyImported(self): @@ -339,7 +366,7 @@ nfni = [modinfo.name.split(".")[-1] for modinfo in pkginfo.iterModules()] nfni.sort() - self.failUnlessEqual(nfni, ['a', 'b', 'c__init__']) + self.assertEqual(nfni, ['a', 'b', 'c__init__']) def test_listingModules(self): @@ -428,7 +455,7 @@ space = modules.PythonPath( syspath, sysmodules, syshooks, syscache, sysloader) entries = list(space.iterEntries()) - self.assertEquals(len(entries), 1) + self.assertEqual(len(entries), 1) self.assertRaises(KeyError, lambda: entries[0]['module']) @@ -441,11 +468,11 @@ space = modules.PythonPath([], sys.modules, [], {}) thisModule = space[__name__] warnings = self.flushWarnings([self.test_inconsistentImporterCache]) - self.assertEquals(warnings[0]['category'], UserWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], UserWarning) + self.assertEqual( warnings[0]['message'], FilePath(twisted.__file__).parent().dirname() + " (for module " + __name__ + ") not in path importer cache " "(PEP 302 violation - check your local configuration).") - self.assertEquals(len(warnings), 1) - self.assertEquals(thisModule.name, __name__) + self.assertEqual(len(warnings), 1) + self.assertEqual(thisModule.name, __name__) diff --git a/lib/twisted-trunk/twisted/test/test_monkey.py b/lib/twisted-trunk/twisted/test/test_monkey.py --- a/lib/twisted-trunk/twisted/test/test_monkey.py +++ b/lib/twisted-trunk/twisted/test/test_monkey.py @@ -35,9 +35,9 @@ # We can't assert that all state is unchanged, but at least we can # check our test object. - self.assertEquals(self.originalObject.foo, self.testObject.foo) - self.assertEquals(self.originalObject.bar, self.testObject.bar) - self.assertEquals(self.originalObject.baz, self.testObject.baz) + self.assertEqual(self.originalObject.foo, self.testObject.foo) + self.assertEqual(self.originalObject.bar, self.testObject.bar) + self.assertEqual(self.originalObject.baz, self.testObject.baz) def test_constructWithPatches(self): @@ -48,9 +48,9 @@ patcher = MonkeyPatcher((self.testObject, 'foo', 'haha'), (self.testObject, 'bar', 'hehe')) patcher.patch() - self.assertEquals('haha', self.testObject.foo) - self.assertEquals('hehe', self.testObject.bar) - self.assertEquals(self.originalObject.baz, self.testObject.baz) + self.assertEqual('haha', self.testObject.foo) + self.assertEqual('hehe', self.testObject.bar) + self.assertEqual(self.originalObject.baz, self.testObject.baz) def test_patchExisting(self): @@ -60,7 +60,7 @@ """ self.monkeyPatcher.addPatch(self.testObject, 'foo', 'haha') self.monkeyPatcher.patch() - self.assertEquals(self.testObject.foo, 'haha') + self.assertEqual(self.testObject.foo, 'haha') def test_patchNonExisting(self): @@ -80,9 +80,9 @@ self.monkeyPatcher.addPatch(self.testObject, 'foo', 'blah') self.monkeyPatcher.addPatch(self.testObject, 'foo', 'BLAH') self.monkeyPatcher.patch() - self.assertEquals(self.testObject.foo, 'BLAH') + self.assertEqual(self.testObject.foo, 'BLAH') self.monkeyPatcher.restore() - self.assertEquals(self.testObject.foo, self.originalObject.foo) + self.assertEqual(self.testObject.foo, self.originalObject.foo) def test_restoreTwiceIsANoOp(self): @@ -92,9 +92,9 @@ self.monkeyPatcher.addPatch(self.testObject, 'foo', 'blah') self.monkeyPatcher.patch() self.monkeyPatcher.restore() - self.assertEquals(self.testObject.foo, self.originalObject.foo) + self.assertEqual(self.testObject.foo, self.originalObject.foo) self.monkeyPatcher.restore() - self.assertEquals(self.testObject.foo, self.originalObject.foo) + self.assertEqual(self.testObject.foo, self.originalObject.foo) def test_runWithPatchesDecoration(self): @@ -109,8 +109,8 @@ return 'foo' result = self.monkeyPatcher.runWithPatches(f, 1, 2, c=10) - self.assertEquals('foo', result) - self.assertEquals([(1, 2, 10)], log) + self.assertEqual('foo', result) + self.assertEqual([(1, 2, 10)], log) def test_repeatedRunWithPatches(self): @@ -124,10 +124,10 @@ self.monkeyPatcher.addPatch(self.testObject, 'foo', 'haha') result = self.monkeyPatcher.runWithPatches(f) - self.assertEquals( + self.assertEqual( ('haha', self.originalObject.bar, self.originalObject.baz), result) result = self.monkeyPatcher.runWithPatches(f) - self.assertEquals( + self.assertEqual( ('haha', self.originalObject.bar, self.originalObject.baz), result) @@ -138,9 +138,9 @@ has executed. """ self.monkeyPatcher.addPatch(self.testObject, 'foo', 'haha') - self.assertEquals(self.originalObject.foo, self.testObject.foo) + self.assertEqual(self.originalObject.foo, self.testObject.foo) self.monkeyPatcher.runWithPatches(lambda: None) - self.assertEquals(self.originalObject.foo, self.testObject.foo) + self.assertEqual(self.originalObject.foo, self.testObject.foo) def test_runWithPatchesRestoresOnException(self): @@ -149,13 +149,13 @@ raises an exception. """ def _(): - self.assertEquals(self.testObject.foo, 'haha') - self.assertEquals(self.testObject.bar, 'blahblah') + self.assertEqual(self.testObject.foo, 'haha') + self.assertEqual(self.testObject.bar, 'blahblah') raise RuntimeError, "Something went wrong!" self.monkeyPatcher.addPatch(self.testObject, 'foo', 'haha') self.monkeyPatcher.addPatch(self.testObject, 'bar', 'blahblah') self.assertRaises(RuntimeError, self.monkeyPatcher.runWithPatches, _) - self.assertEquals(self.testObject.foo, self.originalObject.foo) - self.assertEquals(self.testObject.bar, self.originalObject.bar) + self.assertEqual(self.testObject.foo, self.originalObject.foo) + self.assertEqual(self.testObject.bar, self.originalObject.bar) diff --git a/lib/twisted-trunk/twisted/test/test_newcred.py b/lib/twisted-trunk/twisted/test/test_newcred.py --- a/lib/twisted-trunk/twisted/test/test_newcred.py +++ b/lib/twisted-trunk/twisted/test/test_newcred.py @@ -93,7 +93,7 @@ got = self.portal.listCredentialsInterfaces() expected.sort() got.sort() - self.assertEquals(got, expected) + self.assertEqual(got, expected) def testBasicLogin(self): l = []; f = [] @@ -105,7 +105,7 @@ # print l[0].getBriefTraceback() iface, impl, logout = l[0] # whitebox - self.assertEquals(iface, ITestable) + self.assertEqual(iface, ITestable) self.failUnless(iface.providedBy(impl), "%s does not implement %s" % (impl, iface)) # greybox @@ -128,7 +128,7 @@ raise f[0] iface, impl, logout = l[0] # whitebox - self.assertEquals(iface, ITestable) + self.assertEqual(iface, ITestable) self.failUnless(iface.providedBy(impl), "%s does not implement %s" % (impl, iface)) # greybox @@ -143,7 +143,7 @@ self, ITestable).addErrback( lambda x: x.trap(error.UnauthorizedLogin)).addCallback(l.append) self.failUnless(l) - self.failUnlessEqual(error.UnauthorizedLogin, l[0]) + self.assertEqual(error.UnauthorizedLogin, l[0]) def testFailedLoginName(self): l = [] @@ -151,14 +151,14 @@ self, ITestable).addErrback( lambda x: x.trap(error.UnauthorizedLogin)).addCallback(l.append) self.failUnless(l) - self.failUnlessEqual(error.UnauthorizedLogin, l[0]) + self.assertEqual(error.UnauthorizedLogin, l[0]) class CramMD5CredentialsTestCase(unittest.TestCase): def testIdempotentChallenge(self): c = credentials.CramMD5Credentials() chal = c.getChallenge() - self.assertEquals(chal, c.getChallenge()) + self.assertEqual(chal, c.getChallenge()) def testCheckPassword(self): c = credentials.CramMD5Credentials() @@ -188,7 +188,7 @@ for (u, p) in self.users: self.failUnlessRaises(KeyError, db.getUser, u.upper()) - self.assertEquals(db.getUser(u), (u, p)) + self.assertEqual(db.getUser(u), (u, p)) def testCaseInSensitivity(self): dbfile = self.mktemp() @@ -199,7 +199,7 @@ f.close() for (u, p) in self.users: - self.assertEquals(db.getUser(u.upper()), (u, p)) + self.assertEqual(db.getUser(u.upper()), (u, p)) def testRequestAvatarId(self): dbfile = self.mktemp() @@ -211,7 +211,7 @@ creds = [credentials.UsernamePassword(u, p) for u, p in self.users] d = defer.gatherResults( [defer.maybeDeferred(db.requestAvatarId, c) for c in creds]) - d.addCallback(self.assertEquals, [u for u, p in self.users]) + d.addCallback(self.assertEqual, [u for u, p in self.users]) return d def testRequestAvatarId_hashed(self): @@ -224,7 +224,7 @@ creds = [credentials.UsernameHashedPassword(u, p) for u, p in self.users] d = defer.gatherResults( [defer.maybeDeferred(db.requestAvatarId, c) for c in creds]) - d.addCallback(self.assertEquals, [u for u, p in self.users]) + d.addCallback(self.assertEqual, [u for u, p in self.users]) return d @@ -254,7 +254,7 @@ def testGoodCredentials(self): goodCreds = [credentials.UsernamePassword(u, p) for u, p in self.users] d = defer.gatherResults([self.db.requestAvatarId(c) for c in goodCreds]) - d.addCallback(self.assertEquals, [u for u, p in self.users]) + d.addCallback(self.assertEqual, [u for u, p in self.users]) return d def testGoodCredentials_login(self): @@ -262,7 +262,7 @@ d = defer.gatherResults([self.port.login(c, None, ITestable) for c in goodCreds]) d.addCallback(lambda x: [a.original.name for i, a, l in x]) - d.addCallback(self.assertEquals, [u for u, p in self.users]) + d.addCallback(self.assertEqual, [u for u, p in self.users]) return d def testBadCredentials(self): @@ -283,7 +283,7 @@ def _assertFailures(self, failures, *expectedFailures): for flag, failure in failures: - self.failUnlessEqual(flag, defer.FAILURE) + self.assertEqual(flag, defer.FAILURE) failure.trap(*expectedFailures) return None @@ -338,7 +338,7 @@ creds = credentials.PluggableAuthenticationModules('testuser', conv) d = db.requestAvatarId(creds) - d.addCallback(self.assertEquals, 'testuser') + d.addCallback(self.assertEqual, 'testuser') return d def testBadCredentials(self): @@ -368,7 +368,7 @@ for (cred, avatarId) in self.getGoodCredentials(): r = wFD(chk.requestAvatarId(cred)) yield r - self.assertEquals(r.getResult(), avatarId) + self.assertEqual(r.getResult(), avatarId) testPositive = dG(testPositive) def testNegative(self): diff --git a/lib/twisted-trunk/twisted/test/test_nmea.py b/lib/twisted-trunk/twisted/test/test_nmea.py --- a/lib/twisted-trunk/twisted/test/test_nmea.py +++ b/lib/twisted-trunk/twisted/test/test_nmea.py @@ -106,10 +106,10 @@ actualResult = munge(actualResult) if isinstance(expectedResult, Exception): if isinstance(actualResult, Exception): - self.failUnlessEqual(expectedResult.__class__, actualResult.__class__, "\nInput:\n%s\nExpected:\n%s.%s\nResults:\n%s.%s\n" % (message, expectedResult.__class__.__module__, expectedResult.__class__.__name__, actualResult.__class__.__module__, actualResult.__class__.__name__)) + self.assertEqual(expectedResult.__class__, actualResult.__class__, "\nInput:\n%s\nExpected:\n%s.%s\nResults:\n%s.%s\n" % (message, expectedResult.__class__.__module__, expectedResult.__class__.__name__, actualResult.__class__.__module__, actualResult.__class__.__name__)) else: - self.failUnlessEqual(1, 0, "\nInput:\n%s\nExpected:\n%s.%s\nResults:\n%r\n" % (message, expectedResult.__class__.__module__, expectedResult.__class__.__name__, actualResult)) + self.assertEqual(1, 0, "\nInput:\n%s\nExpected:\n%s.%s\nResults:\n%r\n" % (message, expectedResult.__class__.__module__, expectedResult.__class__.__name__, actualResult)) else: - self.failUnlessEqual(expectedResult, actualResult, "\nInput:\n%s\nExpected: %r\nResults: %r\n" % (message, expectedResult, actualResult)) + self.assertEqual(expectedResult, actualResult, "\nInput:\n%s\nExpected: %r\nResults: %r\n" % (message, expectedResult, actualResult)) testCases = [NMEAReceiverTestCase] diff --git a/lib/twisted-trunk/twisted/test/test_paths.py b/lib/twisted-trunk/twisted/test/test_paths.py --- a/lib/twisted-trunk/twisted/test/test_paths.py +++ b/lib/twisted-trunk/twisted/test/test_paths.py @@ -63,7 +63,7 @@ """ Verify that the segments between two paths are correctly identified. """ - self.assertEquals( + self.assertEqual( self.path.child("a").child("b").child("c").segmentsFrom(self.path), ["a", "b", "c"]) @@ -82,7 +82,7 @@ hierarchy. """ x = [foo.path for foo in self.path.walk()] - self.assertEquals(set(x), set(self.all)) + self.assertEqual(set(x), set(self.all)) def test_parents(self): @@ -99,7 +99,7 @@ L.append(thispath) lastpath = thispath thispath = os.path.dirname(thispath) - self.assertEquals([x.path for x in pathobj.parents()], L) + self.assertEqual([x.path for x in pathobj.parents()], L) def test_validSubdir(self): @@ -115,7 +115,7 @@ "It's a directory.") self.failUnless(not sub1.islink(), "It's a directory.") - self.failUnlessEqual(sub1.listdir(), + self.assertEqual(sub1.listdir(), ['file2']) @@ -132,9 +132,9 @@ Make sure that we can read existent non-empty files. """ f1 = self.path.child('file1') - self.failUnlessEqual(f1.open().read(), self.f1content) + self.assertEqual(f1.open().read(), self.f1content) f2 = self.path.child('sub1').child('file2') - self.failUnlessEqual(f2.open().read(), self.f2content) + self.assertEqual(f2.open().read(), self.f2content) def test_multipleChildSegments(self): @@ -144,7 +144,7 @@ """ multiple = self.path.descendant(['a', 'b', 'c']) single = self.path.child('a').child('b').child('c') - self.assertEquals(multiple, single) + self.assertEqual(multiple, single) def test_dictionaryKeys(self): @@ -157,13 +157,13 @@ dictoid = {} dictoid[f1] = 3 dictoid[f1prime] = 4 - self.assertEquals(dictoid[f1], 4) - self.assertEquals(dictoid.keys(), [f1]) + self.assertEqual(dictoid[f1], 4) + self.assertEqual(dictoid.keys(), [f1]) self.assertIdentical(dictoid.keys()[0], f1) self.assertNotIdentical(dictoid.keys()[0], f1prime) # sanity check dictoid[f2] = 5 - self.assertEquals(dictoid[f2], 5) - self.assertEquals(len(dictoid), 2) + self.assertEqual(dictoid[f2], 5) + self.assertEqual(len(dictoid), 2) def test_dictionaryKeyWithString(self): @@ -174,7 +174,7 @@ f1 = self.path.child('file1') dictoid = {f1: 'hello'} dictoid[f1.path] = 'goodbye' - self.assertEquals(len(dictoid), 2) + self.assertEqual(len(dictoid), 2) def test_childrenNonexistentError(self): @@ -200,9 +200,9 @@ (and hopefully therefore 'high precision'). """ for p in self.path, self.path.child('file1'): - self.failUnlessEqual(type(p.getAccessTime()), float) - self.failUnlessEqual(type(p.getModificationTime()), float) - self.failUnlessEqual(type(p.getStatusChangeTime()), float) + self.assertEqual(type(p.getAccessTime()), float) + self.assertEqual(type(p.getModificationTime()), float) + self.assertEqual(type(p.getStatusChangeTime()), float) def test_oldTimesAreInts(self): @@ -211,9 +211,9 @@ integers, for compatibility. """ for p in self.path, self.path.child('file1'): - self.failUnlessEqual(type(p.getatime()), int) - self.failUnlessEqual(type(p.getmtime()), int) - self.failUnlessEqual(type(p.getctime()), int) + self.assertEqual(type(p.getatime()), int) + self.assertEqual(type(p.getmtime()), int) + self.assertEqual(type(p.getctime()), int) @@ -267,7 +267,7 @@ d2 = ose.originalException.__dict__.keys() d1.sort() d2.sort() - self.assertEquals(d1, d2) + self.assertEqual(d1, d2) @@ -309,7 +309,7 @@ os.path.abspath(self.cmn + ".zip" + os.sep + 'foo'),) # Check for an absolute path - self.assertEquals(repr(child), pathRepr) + self.assertEqual(repr(child), pathRepr) # Create a path to the file rooted in the current working directory relativeCommon = self.cmn.replace(os.getcwd() + os.sep, "", 1) + ".zip" @@ -317,7 +317,7 @@ child = relpath.child("foo") # Check using a path without the cwd prepended - self.assertEquals(repr(child), pathRepr) + self.assertEqual(repr(child), pathRepr) def test_zipPathReprParentDirSegment(self): @@ -329,7 +329,7 @@ child = self.path.child("foo").child("..").child("bar") pathRepr = "ZipPath(%r)" % ( self.cmn + ".zip" + os.sep.join(["", "foo", "..", "bar"])) - self.assertEquals(repr(child), pathRepr) + self.assertEqual(repr(child), pathRepr) def test_zipPathReprEscaping(self): @@ -340,7 +340,7 @@ child = self.path.child("'") path = self.cmn + ".zip" + os.sep.join(["", "'"]) pathRepr = "ZipPath('%s')" % (path.encode('string-escape'),) - self.assertEquals(repr(child), pathRepr) + self.assertEqual(repr(child), pathRepr) def test_zipArchiveRepr(self): @@ -351,14 +351,14 @@ pathRepr = 'ZipArchive(%r)' % (os.path.abspath(self.cmn + '.zip'),) # Check for an absolute path - self.assertEquals(repr(self.path), pathRepr) + self.assertEqual(repr(self.path), pathRepr) # Create a path to the file rooted in the current working directory relativeCommon = self.cmn.replace(os.getcwd() + os.sep, "", 1) + ".zip" relpath = ZipArchive(relativeCommon) # Check using a path without the cwd prepended - self.assertEquals(repr(relpath), pathRepr) + self.assertEqual(repr(relpath), pathRepr) @@ -491,6 +491,153 @@ +class PermissionsTestCase(unittest.TestCase): + """ + Test Permissions and RWX classes + """ + + def assertNotUnequal(self, first, second, msg=None): + """ + Tests that C{first} != C{second} is false. This method tests the + __ne__ method, as opposed to L{assertEqual} (C{first} == C{second}), + which tests the __eq__ method. + + Note: this should really be part of trial + """ + if first != second: + if msg is None: + msg = ''; + if len(msg) > 0: + msg += '\n' + raise self.failureException( + '%snot not unequal (__ne__ not implemented correctly):' + '\na = %s\nb = %s\n' + % (msg, pformat(first), pformat(second))) + return first + + + def test_rwxFromBools(self): + """ + L{RWX}'s constructor takes a set of booleans + """ + for r in (True, False): + for w in (True, False): + for x in (True, False): + rwx = filepath.RWX(r, w, x) + self.assertEqual(rwx.read, r) + self.assertEqual(rwx.write, w) + self.assertEqual(rwx.execute, x) + rwx = filepath.RWX(True, True, True) + self.assertTrue(rwx.read and rwx.write and rwx.execute) + + + def test_rwxEqNe(self): + """ + L{RWX}'s created with the same booleans are equivalent. If booleans + are different, they are not equal. + """ + for r in (True, False): + for w in (True, False): + for x in (True, False): + self.assertEqual(filepath.RWX(r, w, x), + filepath.RWX(r, w, x)) + self.assertNotUnequal(filepath.RWX(r, w, x), + filepath.RWX(r, w, x)) + self.assertNotEqual(filepath.RWX(True, True, True), + filepath.RWX(True, True, False)) + self.assertNotEqual(3, filepath.RWX(True, True, True)) + + + def test_rwxShorthand(self): + """ + L{RWX}'s shorthand string should be 'rwx' if read, write, and execute + permission bits are true. If any of those permissions bits are false, + the character is replaced by a '-'. + """ + + def getChar(val, letter): + if val: + return letter + return '-' + + for r in (True, False): + for w in (True, False): + for x in (True, False): + rwx = filepath.RWX(r, w, x) + self.assertEqual(rwx.shorthand(), + getChar(r, 'r') + + getChar(w, 'w') + + getChar(x, 'x')) + self.assertEqual(filepath.RWX(True, False, True).shorthand(), "r-x") + + + def test_permissionsFromStat(self): + """ + L{Permissions}'s constructor takes a valid permissions bitmask and + parsaes it to produce the correct set of boolean permissions. + """ + def _rwxFromStat(statModeInt, who): + def getPermissionBit(what, who): + return (statModeInt & + getattr(stat, "S_I%s%s" % (what, who))) > 0 + return filepath.RWX(*[getPermissionBit(what, who) for what in + ('R', 'W', 'X')]) + + for u in range(0, 8): + for g in range(0, 8): + for o in range(0, 8): + chmodString = "%d%d%d" % (u, g, o) + chmodVal = int(chmodString, 8) + perm = filepath.Permissions(chmodVal) + self.assertEqual(perm.user, + _rwxFromStat(chmodVal, "USR"), + "%s: got user: %s" % + (chmodString, perm.user)) + self.assertEqual(perm.group, + _rwxFromStat(chmodVal, "GRP"), + "%s: got group: %s" % + (chmodString, perm.group)) + self.assertEqual(perm.other, + _rwxFromStat(chmodVal, "OTH"), + "%s: got other: %s" % + (chmodString, perm.other)) + perm = filepath.Permissions(0777) + for who in ("user", "group", "other"): + for what in ("read", "write", "execute"): + self.assertTrue(getattr(getattr(perm, who), what)) + + + def test_permissionsEq(self): + """ + Two L{Permissions}'s that are created with the same bitmask + are equivalent + """ + self.assertEqual(filepath.Permissions(0777), + filepath.Permissions(0777)) + self.assertNotUnequal(filepath.Permissions(0777), + filepath.Permissions(0777)) + self.assertNotEqual(filepath.Permissions(0777), + filepath.Permissions(0700)) + self.assertNotEqual(3, filepath.Permissions(0777)) + + + def test_permissionsShorthand(self): + """ + L{Permissions}'s shorthand string is the RWX shorthand string for its + user permission bits, group permission bits, and other permission bits + concatenated together, without a space. + """ + for u in range(0, 8): + for g in range(0, 8): + for o in range(0, 8): + perm = filepath.Permissions(eval("0%d%d%d" % (u, g, o))) + self.assertEqual(perm.shorthand(), + ''.join(x.shorthand() for x in ( + perm.user, perm.group, perm.other))) + self.assertEqual(filepath.Permissions(0770).shorthand(), "rwxrwx---") + + + class FilePathTestCase(AbstractFilePathTestCase): """ Test various L{FilePath} path manipulations. @@ -498,13 +645,13 @@ def test_chmod(self): """ - Make sure that calling L{FilePath.chmod} modifies the permissions of + L{FilePath.chmod} modifies the permissions of the passed file as expected (using C{os.stat} to check). We use some basic modes that should work everywhere (even on Windows). """ for mode in (0555, 0777): self.path.child("sub1").chmod(mode) - self.assertEquals( + self.assertEqual( stat.S_IMODE(os.stat(self.path.child("sub1").path).st_mode), mode) @@ -543,7 +690,7 @@ self.createLinks() self.symlink(self.path.child("file2.link").path, self.path.child("link.link").path) - self.assertEquals(self.path.child("link.link").realpath(), + self.assertEqual(self.path.child("link.link").realpath(), self.path.child("sub1").child("file2")) @@ -563,7 +710,7 @@ L{FilePath.realpath} returns the path itself if the path is not a symbolic link. """ - self.assertEquals(self.path.child("sub1").realpath(), + self.assertEqual(self.path.child("sub1").realpath(), self.path.child("sub1")) @@ -605,18 +752,18 @@ def noSymLinks(path): return not path.islink() x = [foo.path for foo in self.path.walk(descend=noSymLinks)] - self.assertEquals(set(x), set(self.all)) + self.assertEqual(set(x), set(self.all)) def test_getAndSet(self): content = 'newcontent' self.path.child('new').setContent(content) newcontent = self.path.child('new').getContent() - self.failUnlessEqual(content, newcontent) + self.assertEqual(content, newcontent) content = 'content' self.path.child('new').setContent(content, '.tmp') newcontent = self.path.child('new').getContent() - self.failUnlessEqual(content, newcontent) + self.assertEqual(content, newcontent) def test_getContentFileClosing(self): @@ -652,7 +799,7 @@ # Sanity check: setContent should only open one derivative path each # time to store the temporary file. openedSiblings = fp.openedPaths() - self.assertEquals(len(openedSiblings), 2) + self.assertEqual(len(openedSiblings), 2) self.assertNotEquals(openedSiblings[0], openedSiblings[1]) @@ -665,13 +812,13 @@ fp = TrackingFilePath(self.mktemp()) fp.setContent("hello") opened = fp.openedPaths() - self.assertEquals(len(opened), 1) + self.assertEqual(len(opened), 1) self.assertTrue(opened[0].basename().endswith(".new"), "%s does not end with default '.new' extension" % ( opened[0].basename())) fp.setContent("goodbye", "-something-else") opened = fp.openedPaths() - self.assertEquals(len(opened), 2) + self.assertEqual(len(opened), 2) self.assertTrue(opened[1].basename().endswith("-something-else"), "%s does not end with -something-else extension" % ( opened[1].basename())) @@ -706,8 +853,8 @@ for target, link in targetLinks: target.linkTo(link) self.assertTrue(link.islink(), "This is a link") - self.assertEquals(target.isdir(), link.isdir()) - self.assertEquals(target.isfile(), link.isfile()) + self.assertEqual(target.isdir(), link.isdir()) + self.assertEqual(target.isfile(), link.isfile()) def test_linkToErrors(self): @@ -748,26 +895,26 @@ def testStatCache(self): p = self.path.child('stattest') p.touch() - self.failUnlessEqual(p.getsize(), 0) - self.failUnlessEqual(abs(p.getmtime() - time.time()) // 20, 0) - self.failUnlessEqual(abs(p.getctime() - time.time()) // 20, 0) - self.failUnlessEqual(abs(p.getatime() - time.time()) // 20, 0) - self.failUnlessEqual(p.exists(), True) - self.failUnlessEqual(p.exists(), True) + self.assertEqual(p.getsize(), 0) + self.assertEqual(abs(p.getmtime() - time.time()) // 20, 0) + self.assertEqual(abs(p.getctime() - time.time()) // 20, 0) + self.assertEqual(abs(p.getatime() - time.time()) // 20, 0) + self.assertEqual(p.exists(), True) + self.assertEqual(p.exists(), True) # OOB removal: FilePath.remove() will automatically restat os.remove(p.path) # test caching - self.failUnlessEqual(p.exists(), True) + self.assertEqual(p.exists(), True) p.restat(reraise=False) - self.failUnlessEqual(p.exists(), False) - self.failUnlessEqual(p.islink(), False) - self.failUnlessEqual(p.isdir(), False) - self.failUnlessEqual(p.isfile(), False) + self.assertEqual(p.exists(), False) + self.assertEqual(p.islink(), False) + self.assertEqual(p.isdir(), False) + self.assertEqual(p.isfile(), False) def testPersist(self): newpath = pickle.loads(pickle.dumps(self.path)) - self.failUnlessEqual(self.path.__class__, newpath.__class__) - self.failUnlessEqual(self.path.path, newpath.path) + self.assertEqual(self.path.__class__, newpath.__class__) + self.assertEqual(self.path.path, newpath.path) def testInsecureUNIX(self): self.assertRaises(filepath.InsecurePath, self.path.child, "..") @@ -795,7 +942,7 @@ testInsecureWin32Whacky.skip = "Consider yourself lucky." def testComparison(self): - self.assertEquals(filepath.FilePath('a'), + self.assertEqual(filepath.FilePath('a'), filepath.FilePath('a')) self.failUnless(filepath.FilePath('z') > filepath.FilePath('a')) @@ -830,14 +977,14 @@ def testSibling(self): p = self.path.child('sibling_start') ts = p.sibling('sibling_test') - self.assertEquals(ts.dirname(), p.dirname()) - self.assertEquals(ts.basename(), 'sibling_test') + self.assertEqual(ts.dirname(), p.dirname()) + self.assertEqual(ts.basename(), 'sibling_test') ts.createDirectory() self.assertIn(ts, self.path.children()) def testTemporarySibling(self): ts = self.path.temporarySibling() - self.assertEquals(ts.dirname(), self.path.dirname()) + self.assertEqual(ts.dirname(), self.path.dirname()) self.assertNotIn(ts.basename(), self.path.listdir()) ts.createDirectory() self.assertIn(ts, self.path.parent().children()) @@ -890,7 +1037,7 @@ newPaths = list(self.path.walk()) # Record double-copy state newPaths.sort() oldPaths.sort() - self.assertEquals(newPaths, oldPaths) + self.assertEqual(newPaths, oldPaths) def test_copyToMissingDestFileClosing(self): @@ -946,7 +1093,7 @@ fp = filepath.FilePath(self.mktemp()) self.path.copyTo(fp) self.assertFalse(fp.child("link1").islink()) - self.assertEquals([x.basename() for x in fp.child("sub1").children()], + self.assertEqual([x.basename() for x in fp.child("sub1").children()], [x.basename() for x in fp.child("link1").children()]) @@ -958,7 +1105,7 @@ fp = filepath.FilePath(self.mktemp()) self.path.copyTo(fp, followLinks=False) self.assertTrue(fp.child("link1").islink()) - self.assertEquals(os.readlink(self.path.child("link1").path), + self.assertEqual(os.readlink(self.path.child("link1").path), os.readlink(fp.child("link1").path)) @@ -968,7 +1115,7 @@ """ path = filepath.FilePath(self.mktemp()) exc = self.assertRaises(OSError, path.copyTo, 'some other path') - self.assertEquals(exc.errno, errno.ENOENT) + self.assertEqual(exc.errno, errno.ENOENT) def test_moveTo(self): @@ -983,7 +1130,7 @@ newPaths = list(self.path.walk()) # Record double-move state newPaths.sort() oldPaths.sort() - self.assertEquals(newPaths, oldPaths) + self.assertEqual(newPaths, oldPaths) def test_moveToExistsCache(self): @@ -999,8 +1146,8 @@ # Both a sanity check (make sure the file status looks right) and an # enticement for stat-caching logic to kick in and remember that these # exist / don't exist. - self.assertEquals(fp.exists(), True) - self.assertEquals(fp2.exists(), False) + self.assertEqual(fp.exists(), True) + self.assertEqual(fp2.exists(), False) fp.moveTo(fp2) self.assertEqual(fp.exists(), False) @@ -1113,7 +1260,7 @@ self.symlink(self.path.child('file1').path, f2.path) f2.moveTo(f3) self.assertFalse(f3.islink()) - self.assertEquals(f3.getContent(), 'file 1') + self.assertEqual(f3.getContent(), 'file 1') self.assertTrue(invokedWith) @@ -1128,7 +1275,7 @@ self.symlink(self.path.child('file1').path, f2.path) f2.moveTo(f3, followLinks=False) self.assertTrue(f3.islink()) - self.assertEquals(f3.getContent(), 'file 1') + self.assertEqual(f3.getContent(), 'file 1') self.assertTrue(invokedWith) @@ -1154,7 +1301,7 @@ # Opening a file for reading when it does not already exist is an error nonexistent = self.path.child('nonexistent') e = self.assertRaises(IOError, nonexistent.open) - self.assertEquals(e.errno, errno.ENOENT) + self.assertEqual(e.errno, errno.ENOENT) # Opening a file for writing when it does not exist is okay writer = self.path.child('writer') @@ -1165,14 +1312,14 @@ # Make sure those bytes ended up there - and test opening a file for # reading when it does exist at the same time f = writer.open() - self.assertEquals(f.read(), 'abc\ndef') + self.assertEqual(f.read(), 'abc\ndef') f.close() # Re-opening that file in write mode should erase whatever was there. f = writer.open('w') f.close() f = writer.open() - self.assertEquals(f.read(), '') + self.assertEqual(f.read(), '') f.close() # Put some bytes in a file so we can test that appending does not @@ -1187,12 +1334,12 @@ f.close() f = appender.open('r') - self.assertEquals(f.read(), 'abcdef') + self.assertEqual(f.read(), 'abcdef') f.close() # read/write should let us do both without erasing those bytes f = appender.open('r+') - self.assertEquals(f.read(), 'abcdef') + self.assertEqual(f.read(), 'abcdef') # ANSI C *requires* an fseek or an fgetpos between an fread and an # fwrite or an fwrite and a fread. We can't reliable get Python to # invoke fgetpos, so we seek to a 0 byte offset from the current @@ -1206,13 +1353,13 @@ # Make sure those new bytes really showed up f = appender.open('r') - self.assertEquals(f.read(), 'abcdefghi') + self.assertEqual(f.read(), 'abcdefghi') f.close() # write/read should let us do both, but erase anything that's there # already. f = appender.open('w+') - self.assertEquals(f.read(), '') + self.assertEqual(f.read(), '') f.seek(0, 1) # Don't forget this! f.write('123') f.close() @@ -1225,10 +1372,10 @@ # The cursor is not at the end of the file until after the first write. f.write('456') f.seek(0, 1) # Asinine. - self.assertEquals(f.read(), '') + self.assertEqual(f.read(), '') f.seek(0, 0) - self.assertEquals(f.read(), '123456') + self.assertEqual(f.read(), '123456') f.close() # Opening a file exclusively must fail if that file exists already. @@ -1278,10 +1425,10 @@ an operation has occurred in the mean time. """ fp = filepath.FilePath(self.mktemp()) - self.assertEquals(fp.exists(), False) + self.assertEqual(fp.exists(), False) fp.makedirs() - self.assertEquals(fp.exists(), True) + self.assertEqual(fp.exists(), True) def test_changed(self): @@ -1292,7 +1439,7 @@ """ fp = filepath.FilePath(self.mktemp()) fp.setContent("12345") - self.assertEquals(fp.getsize(), 5) + self.assertEqual(fp.getsize(), 5) # Someone else comes along and changes the file. fObj = open(fp.path, 'wb') @@ -1300,13 +1447,54 @@ fObj.close() # Sanity check for caching: size should still be 5. - self.assertEquals(fp.getsize(), 5) + self.assertEqual(fp.getsize(), 5) fp.changed() # This path should look like we don't know what status it's in, not that # we know that it didn't exist when last we checked. self.assertEqual(fp.statinfo, None) - self.assertEquals(fp.getsize(), 8) + self.assertEqual(fp.getsize(), 8) + + + def test_getPermissions_POSIX(self): + """ + Getting permissions for a file returns a L{Permissions} object for + POSIX platforms (which supports separate user, group, and other + permissions bits. + """ + for mode in (0777, 0700): + self.path.child("sub1").chmod(mode) + self.assertEqual(self.path.child("sub1").getPermissions(), + filepath.Permissions(mode)) + self.path.child("sub1").chmod(0764) #sanity check + self.assertEqual(self.path.child("sub1").getPermissions().shorthand(), + "rwxrw-r--") + + + def test_getPermissions_Windows(self): + """ + Getting permissions for a file returns a L{Permissions} object in + Windows. Windows requires a different test, because user permissions + = group permissions = other permissions. Also, chmod may not be able + to set the execute bit, so we are skipping tests that set the execute + bit. + """ + for mode in (0777, 0555): + self.path.child("sub1").chmod(mode) + self.assertEqual(self.path.child("sub1").getPermissions(), + filepath.Permissions(mode)) + self.path.child("sub1").chmod(0511) #sanity check to make sure that + # user=group=other permissions + self.assertEqual(self.path.child("sub1").getPermissions().shorthand(), + "r-xr-xr-x") + + + def test_whetherBlockOrSocket(self): + """ + Ensure that a file is not a block or socket + """ + self.assertFalse(self.path.isBlockDevice()) + self.assertFalse(self.path.isSocket()) def test_statinfoBitsNotImplementedInWindows(self): @@ -1332,8 +1520,8 @@ self.assertIsInstance(p.getNumberOfHardLinks(), int) self.assertIsInstance(p.getUserID(), int) self.assertIsInstance(p.getGroupID(), int) - self.assertEquals(self.path.getUserID(), c.getUserID()) - self.assertEquals(self.path.getGroupID(), c.getGroupID()) + self.assertEqual(self.path.getUserID(), c.getUserID()) + self.assertEqual(self.path.getGroupID(), c.getGroupID()) def test_statinfoNumbersAreValid(self): @@ -1358,18 +1546,20 @@ # ensure that restat will need to be called to get values self.path.statinfo = None - self.assertEquals(self.path.getInodeNumber(), fake.st_ino) - self.assertEquals(self.path.getDevice(), fake.st_dev) - self.assertEquals(self.path.getNumberOfHardLinks(), fake.st_nlink) - self.assertEquals(self.path.getUserID(), fake.st_uid) - self.assertEquals(self.path.getGroupID(), fake.st_gid) + self.assertEqual(self.path.getInodeNumber(), fake.st_ino) + self.assertEqual(self.path.getDevice(), fake.st_dev) + self.assertEqual(self.path.getNumberOfHardLinks(), fake.st_nlink) + self.assertEqual(self.path.getUserID(), fake.st_uid) + self.assertEqual(self.path.getGroupID(), fake.st_gid) if platform.isWindows(): test_statinfoBitsAreNumbers.skip = True test_statinfoNumbersAreValid.skip = True + test_getPermissions_POSIX.skip = True else: test_statinfoBitsNotImplementedInWindows.skip = True + test_getPermissions_Windows.skip = True @@ -1380,31 +1570,31 @@ self.path = urlpath.URLPath.fromString("http://example.com/foo/bar?yes=no&no=yes#footer") def testStringConversion(self): - self.assertEquals(str(self.path), "http://example.com/foo/bar?yes=no&no=yes#footer") + self.assertEqual(str(self.path), "http://example.com/foo/bar?yes=no&no=yes#footer") def testChildString(self): - self.assertEquals(str(self.path.child('hello')), "http://example.com/foo/bar/hello") - self.assertEquals(str(self.path.child('hello').child('')), "http://example.com/foo/bar/hello/") + self.assertEqual(str(self.path.child('hello')), "http://example.com/foo/bar/hello") + self.assertEqual(str(self.path.child('hello').child('')), "http://example.com/foo/bar/hello/") def testSiblingString(self): - self.assertEquals(str(self.path.sibling('baz')), 'http://example.com/foo/baz') + self.assertEqual(str(self.path.sibling('baz')), 'http://example.com/foo/baz') # The sibling of http://example.com/foo/bar/ # is http://example.comf/foo/bar/baz # because really we are constructing a sibling of # http://example.com/foo/bar/index.html - self.assertEquals(str(self.path.child('').sibling('baz')), 'http://example.com/foo/bar/baz') + self.assertEqual(str(self.path.child('').sibling('baz')), 'http://example.com/foo/bar/baz') def testParentString(self): # parent should be equivalent to '..' # 'foo' is the current directory, '/' is the parent directory - self.assertEquals(str(self.path.parent()), 'http://example.com/') - self.assertEquals(str(self.path.child('').parent()), 'http://example.com/foo/') - self.assertEquals(str(self.path.child('baz').parent()), 'http://example.com/foo/') - self.assertEquals(str(self.path.parent().parent().parent().parent().parent()), 'http://example.com/') + self.assertEqual(str(self.path.parent()), 'http://example.com/') + self.assertEqual(str(self.path.child('').parent()), 'http://example.com/foo/') + self.assertEqual(str(self.path.child('baz').parent()), 'http://example.com/foo/') + self.assertEqual(str(self.path.parent().parent().parent().parent().parent()), 'http://example.com/') def testHereString(self): # here should be equivalent to '.' - self.assertEquals(str(self.path.here()), 'http://example.com/foo/') - self.assertEquals(str(self.path.child('').here()), 'http://example.com/foo/bar/') + self.assertEqual(str(self.path.here()), 'http://example.com/foo/') + self.assertEqual(str(self.path.child('').here()), 'http://example.com/foo/bar/') diff --git a/lib/twisted-trunk/twisted/test/test_pb.py b/lib/twisted-trunk/twisted/test/test_pb.py --- a/lib/twisted-trunk/twisted/test/test_pb.py +++ b/lib/twisted-trunk/twisted/test/test_pb.py @@ -11,7 +11,7 @@ # issue1195 TODOs: replace pump.pump() with something involving Deferreds. # Clean up warning suppression. -import sys, os, time, gc +import sys, os, time, gc, weakref from cStringIO import StringIO from zope.interface import implements, Interface @@ -23,6 +23,7 @@ from twisted.internet.error import ConnectionRefusedError from twisted.internet.defer import Deferred, gatherResults, succeed from twisted.protocols.policies import WrappingFactory +from twisted.protocols import loopback from twisted.python import failure, log from twisted.cred.error import UnauthorizedLogin, UnhandledCredentials from twisted.cred import portal, checkers, credentials @@ -66,17 +67,29 @@ self.clientIO = clientIO self.serverIO = serverIO + def flush(self): """ - Pump until there is no more input or output. This does not run any - timers, so don't use it with any code that calls reactor.callLater. + Pump until there is no more input or output or until L{stop} is called. + This does not run any timers, so don't use it with any code that calls + reactor.callLater. """ # failsafe timeout + self._stop = False timeout = time.time() + 5 - while self.pump(): + while not self._stop and self.pump(): if time.time() > timeout: return + + def stop(self): + """ + Stop a running L{flush} operation, even if data remains to be + transferred. + """ + self._stop = True + + def pump(self): """ Move data back and forth. @@ -103,13 +116,19 @@ return 0 -def connectedServerAndClient(): + +def connectedServerAndClient(realm=None): """ - Returns a 3-tuple: (client, server, pump). + Connect a client and server L{Broker} together with an L{IOPump} + + @param realm: realm to use, defaulting to a L{DummyRealm} + + @returns: a 3-tuple (client, server, pump). """ + realm = realm or DummyRealm() clientBroker = pb.Broker() checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(guest='guest') - factory = pb.PBServerFactory(portal.Portal(DummyRealm(), [checker])) + factory = pb.PBServerFactory(portal.Portal(realm, [checker])) serverBroker = factory.buildProtocol(('127.0.0.1',)) clientTransport = StringIO() @@ -390,7 +409,7 @@ d = self.ref.callRemote("echo", orig) def cb(res): self.failUnless(isinstance(res, NewStyleCopy)) - self.failUnlessEqual(res.s, "value") + self.assertEqual(res.s, "value") self.failIf(res is orig) # no cheating :) d.addCallback(cb) return d @@ -400,15 +419,15 @@ Send a new style object and check the number of allocations. """ orig = NewStyleCopy2() - self.failUnlessEqual(NewStyleCopy2.allocated, 1) - self.failUnlessEqual(NewStyleCopy2.initialized, 1) + self.assertEqual(NewStyleCopy2.allocated, 1) + self.assertEqual(NewStyleCopy2.initialized, 1) d = self.ref.callRemote("echo", orig) def cb(res): # receiving the response creates a third one on the way back self.failUnless(isinstance(res, NewStyleCopy2)) - self.failUnlessEqual(res.value, 2) - self.failUnlessEqual(NewStyleCopy2.allocated, 3) - self.failUnlessEqual(NewStyleCopy2.initialized, 1) + self.assertEqual(res.value, 2) + self.assertEqual(NewStyleCopy2.allocated, 3) + self.assertEqual(NewStyleCopy2.initialized, 1) self.failIf(res is orig) # no cheating :) # sending the object creates a second one on the far side d.addCallback(cb) @@ -480,14 +499,25 @@ def test_newStyleCache(self): """ - Get the object from the cache, and checks its properties. + A new-style cacheable object can be retrieved and re-retrieved over a + single connection. The value of an attribute of the cacheable can be + accessed on the receiving side. """ d = self.ref.callRemote("giveMeCache", self.orig) - def cb(res): - self.failUnless(isinstance(res, NewStyleCacheCopy)) - self.failUnlessEqual(res.s, "value") - self.failIf(res is self.orig) # no cheating :) - d.addCallback(cb) + def cb(res, again): + self.assertIsInstance(res, NewStyleCacheCopy) + self.assertEqual("value", res.s) + # no cheating :) + self.assertNotIdentical(self.orig, res) + + if again: + # Save a reference so it stays alive for the rest of this test + self.res = res + # And ask for it again to exercise the special re-jelly logic in + # Cacheable. + return self.ref.callRemote("giveMeCache", self.orig) + d.addCallback(cb, True) + d.addCallback(cb, False) return d @@ -536,7 +566,7 @@ self.assertIdentical(x.caught, z, "X should have caught Z") # make sure references to remote methods are equals - self.assertEquals(y.remoteMethod('throw'), y.remoteMethod('throw')) + self.assertEqual(y.remoteMethod('throw'), y.remoteMethod('throw')) def test_result(self): c, s, pump = connectedServerAndClient() @@ -553,7 +583,7 @@ # Send response. pump.pump() # Shouldn't require any more pumping than that... - self.assertEquals(self.thunkResult, self.expectedThunkResult, + self.assertEqual(self.thunkResult, self.expectedThunkResult, "result wasn't received.") def refcountResult(self, result): @@ -573,7 +603,7 @@ pump.pump() expected = (pb.MAX_BROKER_REFS - 1) self.assertTrue(s.transport.closed, "transport was not closed") - self.assertEquals(len(l), expected, + self.assertEqual(len(l), expected, "expected %s got %s" % (expected, len(l))) def test_copy(self): @@ -585,9 +615,9 @@ ).addCallbacks(self.thunkResultGood, self.thunkErrorBad) pump.pump() pump.pump() - self.assertEquals(self.thunkResult.x, 1) - self.assertEquals(self.thunkResult.y['Hello'], 'World') - self.assertEquals(self.thunkResult.z[0], 'test') + self.assertEqual(self.thunkResult.x, 1) + self.assertEqual(self.thunkResult.y['Hello'], 'World') + self.assertEqual(self.thunkResult.z[0], 'test') def test_observe(self): c, s, pump = connectedServerAndClient() @@ -607,7 +637,7 @@ pump.pump() pump.pump() self.assertNotIdentical(b.obj, None, "didn't notify") - self.assertEquals(b.obj, 1, 'notified too much') + self.assertEqual(b.obj, 1, 'notified too much') def test_defer(self): c, s, pump = connectedServerAndClient() @@ -620,9 +650,9 @@ pump.pump(); pump.pump() self.assertFalse(d.run, "Deferred method run too early.") d.d.callback(5) - self.assertEquals(d.run, 5, "Deferred method run too late.") + self.assertEqual(d.run, 5, "Deferred method run too late.") pump.pump(); pump.pump() - self.assertEquals(results[0], 6, "Incorrect result.") + self.assertEqual(results[0], 6, "Incorrect result.") def test_refcount(self): @@ -671,14 +701,14 @@ o3.callRemote("getCache").addCallback(complex.append) pump.flush() # `worst things first' - self.assertEquals(complex[0].x, 1) - self.assertEquals(complex[0].y, 2) - self.assertEquals(complex[0].foo, 3) + self.assertEqual(complex[0].x, 1) + self.assertEqual(complex[0].y, 2) + self.assertEqual(complex[0].foo, 3) vcc.setFoo4() pump.flush() - self.assertEquals(complex[0].foo, 4) - self.assertEquals(len(coll), 2) + self.assertEqual(complex[0].foo, 4) + self.assertEqual(len(coll), 2) cp = coll[0][0] self.assertIdentical(cp.checkMethod().im_self, cp, "potential refcounting issue") @@ -690,7 +720,7 @@ # The objects were the same (testing lcache identity) self.assertTrue(col2[0]) # test equality of references to methods - self.assertEquals(o2.remoteMethod("getCache"), + self.assertEqual(o2.remoteMethod("getCache"), o2.remoteMethod("getCache")) # now, refcounting (similiar to testRefCount) @@ -736,11 +766,11 @@ bar.callRemote('getPub').addCallbacks(accum.append, self.thunkErrorBad) pump.flush() obj = accum.pop() - self.assertEquals(obj.activateCalled, 1) - self.assertEquals(obj.isActivated, 1) - self.assertEquals(obj.yayIGotPublished, 1) + self.assertEqual(obj.activateCalled, 1) + self.assertEqual(obj.isActivated, 1) + self.assertEqual(obj.yayIGotPublished, 1) # timestamp's dirty, we don't have a cache file - self.assertEquals(obj._wasCleanWhenLoaded, 0) + self.assertEqual(obj._wasCleanWhenLoaded, 0) c, s, pump = connectedServerAndClient() s.setNameForLocal("foo", foo) bar = c.remoteForName("foo") @@ -748,7 +778,7 @@ pump.flush() obj = accum.pop() # timestamp's clean, our cache file is up-to-date - self.assertEquals(obj._wasCleanWhenLoaded, 1) + self.assertEqual(obj._wasCleanWhenLoaded, 1) def gotCopy(self, val): self.thunkResult = val.id @@ -765,7 +795,7 @@ pump.pump() pump.pump() pump.pump() - self.assertEquals(self.thunkResult, ID, + self.assertEqual(self.thunkResult, ID, "ID not correct on factory object %s" % (self.thunkResult,)) @@ -831,11 +861,11 @@ util.getAllPages(x, "getPages").addCallback(l.append) while not l: pump.pump() - self.assertEquals(''.join(l[0]), bigString, + self.assertEqual(''.join(l[0]), bigString, "Pages received not equal to pages sent!") - self.assertEquals(callbackArgs, ('hello',), + self.assertEqual(callbackArgs, ('hello',), "Completed callback not invoked") - self.assertEquals(callbackKeyword, {'value': 10}, + self.assertEqual(callbackKeyword, {'value': 10}, "Completed callback not invoked") @@ -850,7 +880,7 @@ util.getAllPages(x, "getPages").addCallback(l.append) while not l: pump.pump() - self.assertEquals(''.join(l[0]), bigString, + self.assertEqual(''.join(l[0]), bigString, "Pages received not equal to pages sent!") @@ -873,7 +903,7 @@ ttl -= 1 if not ttl: self.fail('getAllPages timed out') - self.assertEquals(''.join(l[0]), '', + self.assertEqual(''.join(l[0]), '', "Pages received not equal to pages sent!") @@ -891,13 +921,13 @@ util.getAllPages(x, "getPages").addCallback(l.append) while not l: pump.pump() - self.assertEquals(''.join(l[0]), bigString, + self.assertEqual(''.join(l[0]), bigString, "Pages received not equal to pages sent!") - self.assertEquals(callbackArgs, ('frodo',), + self.assertEqual(callbackArgs, ('frodo',), "Completed callback not invoked") - self.assertEquals(callbackKeyword, {'value': 9}, + self.assertEqual(callbackKeyword, {'value': 9}, "Completed callback not invoked") - self.assertEquals(pagerizer.pager.chunks, []) + self.assertEqual(pagerizer.pager.chunks, []) def test_filePagingWithoutCallback(self): @@ -912,9 +942,9 @@ util.getAllPages(x, "getPages").addCallback(l.append) while not l: pump.pump() - self.assertEquals(''.join(l[0]), bigString, + self.assertEqual(''.join(l[0]), bigString, "Pages received not equal to pages sent!") - self.assertEquals(pagerizer.pager.chunks, []) + self.assertEqual(pagerizer.pager.chunks, []) @@ -957,7 +987,7 @@ """ Called on RemoteReference disconnect. """ - self.assertEquals(o, self.remoteObject) + self.assertEqual(o, self.remoteObject) self.objectCallback = 1 def test_badSerialization(self): @@ -968,7 +998,7 @@ l = [] g.callRemote("setBadCopy", BadCopyable()).addErrback(l.append) pump.flush() - self.assertEquals(len(l), 1) + self.assertEqual(len(l), 1) def test_disconnection(self): c, s, pump = connectedServerAndClient() @@ -1117,6 +1147,74 @@ +class LeakyRealm(TestRealm): + """ + A realm which hangs onto a reference to the mind object in its logout + function. + """ + def __init__(self, mindEater): + """ + Create a L{LeakyRealm}. + + @param mindEater: a callable that will be called with the C{mind} + object when it is available + """ + self._mindEater = mindEater + + + def requestAvatar(self, avatarId, mind, interface): + self._mindEater(mind) + persp = self.perspectiveFactory(avatarId) + return (pb.IPerspective, persp, lambda : (mind, persp.logout())) + + + +class NewCredLeakTests(unittest.TestCase): + """ + Tests to try to trigger memory leaks. + """ + def test_logoutLeak(self): + """ + The server does not leak a reference when the client disconnects + suddenly, even if the cred logout function forms a reference cycle with + the perspective. + """ + # keep a weak reference to the mind object, which we can verify later + # evaluates to None, thereby ensuring the reference leak is fixed. + self.mindRef = None + def setMindRef(mind): + self.mindRef = weakref.ref(mind) + + clientBroker, serverBroker, pump = connectedServerAndClient( + LeakyRealm(setMindRef)) + + # log in from the client + connectionBroken = [] + root = clientBroker.remoteForName("root") + d = root.callRemote("login", 'guest') + def cbResponse((challenge, challenger)): + mind = SimpleRemote() + return challenger.callRemote("respond", + pb.respond(challenge, 'guest'), mind) + d.addCallback(cbResponse) + def connectionLost(_): + pump.stop() # don't try to pump data anymore - it won't work + connectionBroken.append(1) + serverBroker.connectionLost(failure.Failure(RuntimeError("boom"))) + d.addCallback(connectionLost) + + # flush out the response and connectionLost + pump.flush() + self.assertEqual(connectionBroken, [1]) + + # and check for lingering references - requestAvatar sets mindRef + # to a weakref to the mind; this object should be gc'd, and thus + # the ref should return None + gc.collect() + self.assertEqual(self.mindRef(), None) + + + class NewCredTestCase(unittest.TestCase): """ Tests related to the L{twisted.cred} support in PB. @@ -1402,7 +1500,7 @@ def cleanup(ignore): errors = self.flushLoggedErrors(UnauthorizedLogin) - self.assertEquals(len(errors), 2) + self.assertEqual(len(errors), 2) return self._disconnect(None, factory) d.addCallback(cleanup) @@ -1447,7 +1545,7 @@ def cleanup(ignore): errors = self.flushLoggedErrors(UnhandledCredentials) - self.assertEquals(len(errors), 1) + self.assertEqual(len(errors), 1) return self._disconnect(None, factory) d.addCallback(cleanup) @@ -1580,7 +1678,7 @@ "BRAINS!") reactor.connectTCP('127.0.0.1', self.portno, factory) d.addCallback(lambda p: p.callRemote('ANYTHING', 'here', bar='baz')) - d.addCallback(self.assertEquals, + d.addCallback(self.assertEqual, ('ANYTHING', ('here',), {'bar': 'baz'})) def cleanup(ignored): factory.disconnect() @@ -1651,7 +1749,7 @@ the result. """ o = LocalRemoteTest() - self.assertEquals(o.callRemote("add1", 2), 3) + self.assertEqual(o.callRemote("add1", 2), 3) def test_async(self): """ @@ -1662,7 +1760,7 @@ o = LocalRemoteTest() d = o.callRemote("add", 2, y=4) self.assertIsInstance(d, Deferred) - d.addCallback(self.assertEquals, 6) + d.addCallback(self.assertEqual, 6) return d def test_asyncFail(self): @@ -1683,7 +1781,7 @@ """ o = LocalRemoteTest() m = o.remoteMethod("add1") - self.assertEquals(m(3), 4) + self.assertEqual(m(3), 4) def test_localAsyncForwarder(self): """ diff --git a/lib/twisted-trunk/twisted/test/test_pbfailure.py b/lib/twisted-trunk/twisted/test/test_pbfailure.py --- a/lib/twisted-trunk/twisted/test/test_pbfailure.py +++ b/lib/twisted-trunk/twisted/test/test_pbfailure.py @@ -5,6 +5,9 @@ Tests for error handling in PB. """ +import sys + + from twisted.trial import unittest from twisted.spread import pb, flavors, jelly @@ -166,7 +169,7 @@ class PBFailureTest(PBConnTestCase): - compare = unittest.TestCase.assertEquals + compare = unittest.TestCase.assertEqual def _exceptionTest(self, method, exceptionType, flush): @@ -223,7 +226,7 @@ def _success(self, result, expectedResult): - self.assertEquals(result, expectedResult) + self.assertEqual(result, expectedResult) return result @@ -244,7 +247,7 @@ failureDeferred = self._addFailingCallbacks(obj.callRemote(method), expected, eb) if exc is not None: def gotFailure(err): - self.assertEquals(len(self.flushLoggedErrors(exc)), 1) + self.assertEqual(len(self.flushLoggedErrors(exc)), 1) return err failureDeferred.addBoth(gotFailure) return failureDeferred @@ -360,12 +363,42 @@ def exception(failure): log.err(failure) errs = self.flushLoggedErrors(SynchronousException) - self.assertEquals(len(errs), 2) + self.assertEqual(len(errs), 2) d.addErrback(exception) return d + def test_throwExceptionIntoGenerator(self): + """ + L{pb.CopiedFailure.throwExceptionIntoGenerator} will throw a + L{RemoteError} into the given paused generator at the point where it + last yielded. + """ + original = pb.CopyableFailure(AttributeError("foo")) + copy = jelly.unjelly(jelly.jelly(original, invoker=DummyInvoker())) + exception = [] + def generatorFunc(): + try: + yield None + except pb.RemoteError, exc: + exception.append(exc) + else: + self.fail("RemoteError not raised") + gen = generatorFunc() + gen.send(None) + self.assertRaises(StopIteration, copy.throwExceptionIntoGenerator, gen) + self.assertEqual(len(exception), 1) + exc = exception[0] + self.assertEqual(exc.remoteType, "exceptions.AttributeError") + self.assertEqual(exc.args, ("foo",)) + self.assertEqual(exc.remoteTraceback, 'Traceback unavailable\n') + + if sys.version_info[:2] < (2, 5): + test_throwExceptionIntoGenerator.skip = ( + "throwExceptionIntoGenerator is not supported in Python < 2.5") + + class PBFailureTestUnsafe(PBFailureTest): compare = unittest.TestCase.failIfEquals diff --git a/lib/twisted-trunk/twisted/test/test_pcp.py b/lib/twisted-trunk/twisted/test/test_pcp.py --- a/lib/twisted-trunk/twisted/test/test_pcp.py +++ b/lib/twisted-trunk/twisted/test/test_pcp.py @@ -147,7 +147,7 @@ self.producer = self.proxyClass(self.consumer) def testRegistersProducer(self): - self.failUnlessEqual(self.consumer.producer[0], self.producer) + self.assertEqual(self.consumer.producer[0], self.producer) def testPause(self): self.producer.pauseProducing() @@ -159,19 +159,19 @@ self.producer.pauseProducing() self.producer.resumeProducing() self.producer.write("yakkity yak") - self.failUnlessEqual(self.consumer.getvalue(), "yakkity yak") + self.assertEqual(self.consumer.getvalue(), "yakkity yak") def testResumeNoEmptyWrite(self): self.producer.pauseProducing() self.producer.resumeProducing() - self.failUnlessEqual(len(self.consumer._writes), 0, + self.assertEqual(len(self.consumer._writes), 0, "Resume triggered an empty write.") def testResumeBuffer(self): self.producer.pauseProducing() self.producer.write("buffer this") self.producer.resumeProducing() - self.failUnlessEqual(self.consumer.getvalue(), "buffer this") + self.assertEqual(self.consumer.getvalue(), "buffer this") def testStop(self): self.producer.stopProducing() @@ -219,7 +219,7 @@ def testWrite(self): # NOTE: This test only valid for streaming (Push) systems. self.consumer.write("some bytes") - self.failUnlessEqual(self.underlying.getvalue(), "some bytes") + self.assertEqual(self.underlying.getvalue(), "some bytes") def testFinish(self): self.consumer.finish() @@ -246,16 +246,16 @@ def testPull(self): self.proxy.write("hello") self.proxy.resumeProducing() - self.failUnlessEqual(self.underlying.getvalue(), "hello") + self.assertEqual(self.underlying.getvalue(), "hello") def testMergeWrites(self): self.proxy.write("hello ") self.proxy.write("sunshine") self.proxy.resumeProducing() nwrites = len(self.underlying._writes) - self.failUnlessEqual(nwrites, 1, "Pull resulted in %d writes instead " + self.assertEqual(nwrites, 1, "Pull resulted in %d writes instead " "of 1." % (nwrites,)) - self.failUnlessEqual(self.underlying.getvalue(), "hello sunshine") + self.assertEqual(self.underlying.getvalue(), "hello sunshine") def testLateWrite(self): @@ -263,7 +263,7 @@ self.proxy.resumeProducing() self.proxy.write("data") # This data should answer that pull request. - self.failUnlessEqual(self.underlying.getvalue(), "data") + self.assertEqual(self.underlying.getvalue(), "data") class PCP_PullProducerTest(PullProducerTest, unittest.TestCase): class proxyClass(pcp.BasicProducerConsumerProxy): @@ -356,9 +356,9 @@ self.proxy.resumeProducing() self.proxy.write("datum" * 21) # This data should answer that pull request. - self.failUnlessEqual(self.underlying.getvalue(), "datum" * 20) + self.assertEqual(self.underlying.getvalue(), "datum" * 20) # but there should be some left over - self.failUnlessEqual(self.proxy._buffer, ["datum"]) + self.assertEqual(self.proxy._buffer, ["datum"]) # TODO: diff --git a/lib/twisted-trunk/twisted/test/test_persisted.py b/lib/twisted-trunk/twisted/test/test_persisted.py --- a/lib/twisted-trunk/twisted/test/test_persisted.py +++ b/lib/twisted-trunk/twisted/test/test_persisted.py @@ -85,8 +85,8 @@ ClassWithCustomHash.upgradeToVersion1 = lambda self: setattr(self, 'upgraded', True) v1, v2 = pickle.loads(pkl) styles.doUpgrade() - self.assertEquals(v1.unique, 'v1') - self.assertEquals(v2.unique, 'v2') + self.assertEqual(v1.unique, 'v1') + self.assertEqual(v2.unique, 'v2') self.failUnless(v1.upgraded) self.failUnless(v2.upgraded) @@ -122,13 +122,13 @@ def testEphemeral(self): o = MyEphemeral(3) - self.assertEquals(o.__class__, MyEphemeral) - self.assertEquals(o.x, 3) + self.assertEqual(o.__class__, MyEphemeral) + self.assertEqual(o.x, 3) pickl = pickle.dumps(o) o = pickle.loads(pickl) - self.assertEquals(o.__class__, styles.Ephemeral) + self.assertEqual(o.__class__, styles.Ephemeral) self.assert_(not hasattr(o, 'x')) @@ -163,27 +163,27 @@ def testModule(self): pickl = pickle.dumps(styles) o = pickle.loads(pickl) - self.assertEquals(o, styles) + self.assertEqual(o, styles) def testClassMethod(self): pickl = pickle.dumps(Pickleable.getX) o = pickle.loads(pickl) - self.assertEquals(o, Pickleable.getX) + self.assertEqual(o, Pickleable.getX) def testInstanceMethod(self): obj = Pickleable(4) pickl = pickle.dumps(obj.getX) o = pickle.loads(pickl) - self.assertEquals(o(), 4) - self.assertEquals(type(o), type(obj.getX)) + self.assertEqual(o(), 4) + self.assertEqual(type(o), type(obj.getX)) def testStringIO(self): f = StringIO.StringIO() f.write("abc") pickl = pickle.dumps(f) o = pickle.loads(pickl) - self.assertEquals(type(o), type(f)) - self.assertEquals(f.getvalue(), "abc") + self.assertEqual(type(o), type(f)) + self.assertEqual(f.getvalue(), "abc") class EvilSourceror: @@ -202,7 +202,7 @@ def testSimpleTypes(self): obj = (1, 2.0, 3j, True, slice(1, 2, 3), 'hello', u'world', sys.maxint + 1, None, Ellipsis) rtObj = aot.unjellyFromSource(aot.jellyToSource(obj)) - self.assertEquals(obj, rtObj) + self.assertEqual(obj, rtObj) def testMethodSelfIdentity(self): a = A() @@ -210,7 +210,7 @@ a.bmethod = b.bmethod b.a = a im_ = aot.unjellyFromSource(aot.jellyToSource(b)).a.bmethod - self.assertEquals(im_.im_class, im_.im_self.__class__) + self.assertEqual(im_.im_class, im_.im_self.__class__) def test_methodNotSelfIdentity(self): diff --git a/lib/twisted-trunk/twisted/test/test_plugin.py b/lib/twisted-trunk/twisted/test/test_plugin.py --- a/lib/twisted-trunk/twisted/test/test_plugin.py +++ b/lib/twisted-trunk/twisted/test/test_plugin.py @@ -122,21 +122,21 @@ cache = plugin.getCache(self.module) dropin = cache[self.originalPlugin] - self.assertEquals(dropin.moduleName, + self.assertEqual(dropin.moduleName, 'mypackage.%s' % (self.originalPlugin,)) self.assertIn("I'm a test drop-in.", dropin.description) # Note, not the preferred way to get a plugin by its interface. p1 = [p for p in dropin.plugins if ITestPlugin in p.provided][0] self.assertIdentical(p1.dropin, dropin) - self.assertEquals(p1.name, "TestPlugin") + self.assertEqual(p1.name, "TestPlugin") # Check the content of the description comes from the plugin module # docstring - self.assertEquals( + self.assertEqual( p1.description.strip(), "A plugin used solely for testing purposes.") - self.assertEquals(p1.provided, [ITestPlugin, plugin.IPlugin]) + self.assertEqual(p1.provided, [ITestPlugin, plugin.IPlugin]) realPlugin = p1.load() # The plugin should match the class present in sys.modules self.assertIdentical( @@ -159,7 +159,7 @@ """ plugins = list(plugin.getPlugins(ITestPlugin2, self.module)) - self.assertEquals(len(plugins), 2) + self.assertEqual(len(plugins), 2) names = ['AnotherTestPlugin', 'ThirdTestPlugin'] for p in plugins: @@ -186,7 +186,7 @@ # We should find 2 plugins: the one in testplugin, and the one in # pluginextra - self.assertEquals(len(plgs), 2) + self.assertEqual(len(plgs), 2) names = ['TestPlugin', 'FourthTestPlugin'] for p in plgs: @@ -210,7 +210,7 @@ try: plgs = list(plugin.getPlugins(ITestPlugin, self.module)) # Sanity check - self.assertEquals(len(plgs), 2) + self.assertEqual(len(plgs), 2) FilePath(__file__).sibling('plugin_extra2.py' ).copyTo(self.package.child('pluginextra.py')) @@ -221,7 +221,7 @@ # Make sure additions are noticed plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - self.assertEquals(len(plgs), 3) + self.assertEqual(len(plgs), 3) names = ['TestPlugin', 'FourthTestPlugin', 'FifthTestPlugin'] for p in plgs: @@ -251,7 +251,7 @@ sys.modules['mypackage.pluginextra'], True) plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - self.assertEquals(1, len(plgs)) + self.assertEqual(1, len(plgs)) test_detectFilesRemoved = _withCacheness(test_detectFilesRemoved) diff --git a/lib/twisted-trunk/twisted/test/test_policies.py b/lib/twisted-trunk/twisted/test/test_policies.py --- a/lib/twisted-trunk/twisted/test/test_policies.py +++ b/lib/twisted-trunk/twisted/test/test_policies.py @@ -201,9 +201,9 @@ return c3.dDisconnected def _check123(results): - self.assertEquals([c.connected for c in c1, c2, c3], [1, 1, 1]) - self.assertEquals([c.disconnected for c in c1, c2, c3], [0, 0, 1]) - self.assertEquals(len(tServer.protocols.keys()), 2) + self.assertEqual([c.connected for c in c1, c2, c3], [1, 1, 1]) + self.assertEqual([c.disconnected for c in c1, c2, c3], [0, 0, 1]) + self.assertEqual(len(tServer.protocols.keys()), 2) return results def _lose1(results): @@ -216,8 +216,8 @@ return c4.dConnected def _check4(results): - self.assertEquals(c4.connected, 1) - self.assertEquals(c4.disconnected, 0) + self.assertEqual(c4.connected, 1) + self.assertEqual(c4.disconnected, 0) return results def _cleanup(results): @@ -252,19 +252,19 @@ port.dataReceived("0123456789") port.dataReceived("abcdefghij") - self.assertEquals(tr.value(), "0123456789abcdefghij") - self.assertEquals(tServer.writtenThisSecond, 20) + self.assertEqual(tr.value(), "0123456789abcdefghij") + self.assertEqual(tServer.writtenThisSecond, 20) self.assertFalse(port.wrappedProtocol.paused) # at this point server should've written 20 bytes, 10 bytes # above the limit so writing should be paused around 1 second # from 'now', and resumed a second after that tServer.clock.advance(1.05) - self.assertEquals(tServer.writtenThisSecond, 0) + self.assertEqual(tServer.writtenThisSecond, 0) self.assertTrue(port.wrappedProtocol.paused) tServer.clock.advance(1.05) - self.assertEquals(tServer.writtenThisSecond, 0) + self.assertEqual(tServer.writtenThisSecond, 0) self.assertFalse(port.wrappedProtocol.paused) @@ -282,30 +282,30 @@ port.dataReceived("0123456789") port.dataReceived("abcdefghij") - self.assertEquals(tr.value(), "0123456789abcdefghij") - self.assertEquals(tServer.readThisSecond, 20) + self.assertEqual(tr.value(), "0123456789abcdefghij") + self.assertEqual(tServer.readThisSecond, 20) tServer.clock.advance(1.05) - self.assertEquals(tServer.readThisSecond, 0) - self.assertEquals(tr.producerState, 'paused') + self.assertEqual(tServer.readThisSecond, 0) + self.assertEqual(tr.producerState, 'paused') tServer.clock.advance(1.05) - self.assertEquals(tServer.readThisSecond, 0) - self.assertEquals(tr.producerState, 'producing') + self.assertEqual(tServer.readThisSecond, 0) + self.assertEqual(tr.producerState, 'producing') tr.clear() port.dataReceived("0123456789") port.dataReceived("abcdefghij") - self.assertEquals(tr.value(), "0123456789abcdefghij") - self.assertEquals(tServer.readThisSecond, 20) + self.assertEqual(tr.value(), "0123456789abcdefghij") + self.assertEqual(tServer.readThisSecond, 20) tServer.clock.advance(1.05) - self.assertEquals(tServer.readThisSecond, 0) - self.assertEquals(tr.producerState, 'paused') + self.assertEqual(tServer.readThisSecond, 0) + self.assertEqual(tr.producerState, 'paused') tServer.clock.advance(1.05) - self.assertEquals(tServer.readThisSecond, 0) - self.assertEquals(tr.producerState, 'producing') + self.assertEqual(tServer.readThisSecond, 0) + self.assertEqual(tr.producerState, 'producing') @@ -469,7 +469,7 @@ C{reactor.callLater}. """ self.proto.setTimeout(10) - self.assertEquals(len(self.clock.calls), 1) + self.assertEqual(len(self.clock.calls), 1) def test_timeout(self): @@ -510,7 +510,7 @@ self.proto.makeConnection(StringTransport()) self.proto.setTimeout(1) - self.assertEquals(self.proto.timeOut, 1) + self.assertEqual(self.proto.timeOut, 1) self.clock.pump([0, 0.9]) self.failIf(self.proto.timedOut) @@ -526,7 +526,7 @@ self.proto.makeConnection(StringTransport()) self.proto.setTimeout(None) - self.assertEquals(self.proto.timeOut, None) + self.assertEqual(self.proto.timeOut, None) self.clock.pump([0, 5, 5, 5]) self.failIf(self.proto.timedOut) @@ -538,10 +538,10 @@ """ self.proto.timeOut = 5 - self.assertEquals(self.proto.setTimeout(10), 5) - self.assertEquals(self.proto.setTimeout(None), 10) - self.assertEquals(self.proto.setTimeout(1), None) - self.assertEquals(self.proto.timeOut, 1) + self.assertEqual(self.proto.setTimeout(10), 5) + self.assertEqual(self.proto.setTimeout(None), 10) + self.assertEqual(self.proto.setTimeout(1), None) + self.assertEqual(self.proto.timeOut, 1) # Clean up the DelayedCall self.proto.setTimeout(None) @@ -650,13 +650,13 @@ v = f.openFile.getvalue() self.assertIn("C 1: 'here are some bytes'", v) self.assertIn("S 1: 'here are some bytes'", v) - self.assertEquals(t.value(), 'here are some bytes') + self.assertEqual(t.value(), 'here are some bytes') t.clear() p.dataReceived('prepare for vector! to the extreme') v = f.openFile.getvalue() self.assertIn("SV 1: ['prepare for vector! to the extreme']", v) - self.assertEquals(t.value(), 'prepare for vector! to the extreme') + self.assertEqual(t.value(), 'prepare for vector! to the extreme') p.loseConnection() diff --git a/lib/twisted-trunk/twisted/test/test_postfix.py b/lib/twisted-trunk/twisted/test/test_postfix.py --- a/lib/twisted-trunk/twisted/test/test_postfix.py +++ b/lib/twisted-trunk/twisted/test/test_postfix.py @@ -27,9 +27,9 @@ raw = entry[0] quoted = entry[1:] - self.assertEquals(postfix.quote(raw), quoted[0]) + self.assertEqual(postfix.quote(raw), quoted[0]) for q in quoted: - self.assertEquals(postfix.unquote(q), raw) + self.assertEqual(postfix.unquote(q), raw) class PostfixTCPMapServerTestCase: data = { @@ -56,7 +56,7 @@ for input, expected_output in self.chat: protocol.lineReceived(input) - self.assertEquals( + self.assertEqual( transport.value(), expected_output, 'For %r, expected %r but got %r' % ( input, expected_output, transport.value())) @@ -80,7 +80,7 @@ for input, expected_output in self.chat: protocol.lineReceived(input) - self.assertEquals( + self.assertEqual( transport.value(), expected_output, 'For %r, expected %r but got %r' % ( input, expected_output, transport.value())) diff --git a/lib/twisted-trunk/twisted/test/test_process.py b/lib/twisted-trunk/twisted/test/test_process.py --- a/lib/twisted-trunk/twisted/test/test_process.py +++ b/lib/twisted-trunk/twisted/test/test_process.py @@ -494,7 +494,7 @@ p.transport.closeStdin() def processEnded(ign): - self.assertEquals(p.outF.getvalue(), "hello, worldabc123", + self.assertEqual(p.outF.getvalue(), "hello, worldabc123", "Output follows:\n" "%s\n" "Error message from process_twisted follows:\n" @@ -534,12 +534,12 @@ p.deferred = d reactor.spawnProcess(p, exe, [exe, "-u", scriptPath], env=None) def check(ignored): - self.assertEquals(p.stages, [1, 2, 3, 4, 5]) + self.assertEqual(p.stages, [1, 2, 3, 4, 5]) f = p.reason f.trap(error.ProcessTerminated) - self.assertEquals(f.value.exitCode, 23) + self.assertEqual(f.value.exitCode, 23) # would .signal be available on non-posix? - # self.assertEquals(f.value.signal, None) + # self.assertEqual(f.value.signal, None) self.assertRaises( error.ProcessExitedAlready, p.transport.signalProcess, 'INT') try: @@ -555,11 +555,11 @@ def _check(results, protocols): for p in protocols: - self.assertEquals(p.stages, [1, 2, 3, 4, 5], "[%d] stages = %s" % (id(p.transport), str(p.stages))) + self.assertEqual(p.stages, [1, 2, 3, 4, 5], "[%d] stages = %s" % (id(p.transport), str(p.stages))) # test status code f = p.reason f.trap(error.ProcessTerminated) - self.assertEquals(f.value.exitCode, 23) + self.assertEqual(f.value.exitCode, 23) exe = sys.executable scriptPath = util.sibpath(__file__, "process_tester.py") @@ -594,7 +594,7 @@ def asserts(ignored): self.failIf(p.failure, p.failure) self.failUnless(hasattr(p, 'buffer')) - self.assertEquals(len(''.join(p.buffer)), len(p.s * p.n)) + self.assertEqual(len(''.join(p.buffer)), len(p.s * p.n)) def takedownProcess(err): p.transport.closeStdin() @@ -613,9 +613,9 @@ path=None) def processEnded(ign): - self.assertEquals(p.errF.getvalue(), "") + self.assertEqual(p.errF.getvalue(), "") recvdArgs = p.outF.getvalue().splitlines() - self.assertEquals(recvdArgs, args) + self.assertEqual(recvdArgs, args) return d.addCallback(processEnded) @@ -953,7 +953,7 @@ childFDs={1:"r", 2:2}, ) def processEnded(ign): - self.failUnlessEqual(p.outF.getvalue(), + self.assertEqual(p.outF.getvalue(), "here is some text\ngoodbye\n") return d.addCallback(processEnded) @@ -1017,8 +1017,8 @@ usePTY=self.usePTY) def check(ignored): p.reason.trap(error.ProcessDone) - self.assertEquals(p.reason.value.exitCode, 0) - self.assertEquals(p.reason.value.signal, None) + self.assertEqual(p.reason.value.exitCode, 0) + self.assertEqual(p.reason.value.signal, None) d.addCallback(check) return d @@ -1038,8 +1038,8 @@ def check(ignored): p.reason.trap(error.ProcessTerminated) - self.assertEquals(p.reason.value.exitCode, 1) - self.assertEquals(p.reason.value.signal, None) + self.assertEqual(p.reason.value.exitCode, 1) + self.assertEqual(p.reason.value.signal, None) d.addCallback(check) return d @@ -1634,7 +1634,7 @@ usePTY=False) except SystemError: self.assert_(self.mockos.exited) - self.assertEquals( + self.assertEqual( self.mockos.actions, [("fork", False), "exec", "exit"]) else: self.fail("Should not be here") @@ -1658,7 +1658,7 @@ usePTY=False) # It should close the first read pipe, and the 2 last write pipes self.assertEqual(set(self.mockos.closed), set([-1, -4, -6])) - self.assertEquals(self.mockos.actions, [("fork", False), "waitpid"]) + self.assertEqual(self.mockos.actions, [("fork", False), "waitpid"]) def test_mockForkInParentGarbageCollectorEnabled(self): @@ -1699,7 +1699,7 @@ usePTY=True) except SystemError: self.assert_(self.mockos.exited) - self.assertEquals( + self.assertEqual( self.mockos.actions, [("fork", False), "exec", "exit"]) else: self.fail("Should not be here") @@ -1809,7 +1809,7 @@ usePTY=False) except SystemError: self.assert_(self.mockos.exited) - self.assertEquals( + self.assertEqual( self.mockos.actions, [("fork", False), "exec", "exit"]) # Check that fd have been closed self.assertIn(0, self.mockos.closed) @@ -1835,7 +1835,7 @@ usePTY=False, uid=8080) except SystemError: self.assert_(self.mockos.exited) - self.assertEquals(self.mockos.actions, + self.assertEqual(self.mockos.actions, [('setuid', 0), ('setgid', 0), ('fork', False), ('switchuid', 8080, 1234), 'exec', 'exit']) else: @@ -1854,7 +1854,7 @@ p = TrivialProcessProtocol(d) reactor.spawnProcess(p, cmd, ['ouch'], env=None, usePTY=False, uid=8080) - self.assertEquals(self.mockos.actions, + self.assertEqual(self.mockos.actions, [('setuid', 0), ('setgid', 0), ('fork', False), ('setregid', 1235, 1234), ('setreuid', 1237, 1236), 'waitpid']) @@ -1874,7 +1874,7 @@ usePTY=True, uid=8081) except SystemError: self.assert_(self.mockos.exited) - self.assertEquals(self.mockos.actions, + self.assertEqual(self.mockos.actions, [('setuid', 0), ('setgid', 0), ('fork', False), ('switchuid', 8081, 1234), 'exec', 'exit']) else: @@ -1898,7 +1898,7 @@ usePTY=True, uid=8080) finally: process.PTYProcess = oldPTYProcess - self.assertEquals(self.mockos.actions, + self.assertEqual(self.mockos.actions, [('setuid', 0), ('setgid', 0), ('fork', False), ('setregid', 1235, 1234), ('setreuid', 1237, 1236), 'waitpid']) @@ -1915,12 +1915,12 @@ p = TrivialProcessProtocol(d) proc = reactor.spawnProcess(p, cmd, ['ouch'], env=None, usePTY=False) - self.assertEquals(self.mockos.actions, [("fork", False), "waitpid"]) + self.assertEqual(self.mockos.actions, [("fork", False), "waitpid"]) self.mockos.raiseWaitPid = OSError() proc.reapProcess() errors = self.flushLoggedErrors() - self.assertEquals(len(errors), 1) + self.assertEqual(len(errors), 1) errors[0].trap(OSError) @@ -1937,7 +1937,7 @@ p = TrivialProcessProtocol(d) proc = reactor.spawnProcess(p, cmd, ['ouch'], env=None, usePTY=False) - self.assertEquals(self.mockos.actions, [("fork", False), "waitpid"]) + self.assertEqual(self.mockos.actions, [("fork", False), "waitpid"]) self.mockos.raiseWaitPid = OSError() self.mockos.raiseWaitPid.errno = errno.ECHILD @@ -2000,7 +2000,7 @@ usePTY=self.usePTY) def processEnded(ign): - self.assertEquals(value, p.errF.getvalue()) + self.assertEqual(value, p.errF.getvalue()) return d.addCallback(processEnded) @@ -2018,7 +2018,7 @@ f = p.outF f.seek(0, 0) gf = gzip.GzipFile(fileobj=f) - self.assertEquals(gf.read(), s) + self.assertEqual(gf.read(), s) return d.addCallback(processEnded) @@ -2047,7 +2047,7 @@ def processEnded(ign): self.assertRaises( error.ProcessExitedAlready, p.transport.signalProcess, 'HUP') - self.assertEquals( + self.assertEqual( p.outF.getvalue(), "hello world!\r\nhello world!\r\n", "Error message from process_tty follows:\n\n%s\n\n" % p.outF.getvalue()) @@ -2102,8 +2102,8 @@ p.transport.closeStdin() def processEnded(ign): - self.assertEquals(p.errF.getvalue(), "err\nerr\n") - self.assertEquals(p.outF.getvalue(), "out\nhello, world\nout\n") + self.assertEqual(p.errF.getvalue(), "err\nerr\n") + self.assertEqual(p.outF.getvalue(), "out\nhello, world\nout\n") return d.addCallback(processEnded) @@ -2227,7 +2227,7 @@ p = GetEnvironmentDictionary.run(reactor, [], {}) def gotEnvironment(environ): - self.assertEquals( + self.assertEqual( environ[self.goodKey.encode('ascii')], self.goodValue.encode('ascii')) return p.getResult().addCallback(gotEnvironment) @@ -2261,11 +2261,11 @@ cmd, {}, None) - self.assertEquals(42, p.pid) - self.assertEquals("", repr(p)) + self.assertEqual(42, p.pid) + self.assertEqual("", repr(p)) def pidCompleteCb(result): - self.assertEquals(None, p.pid) + self.assertEqual(None, p.pid) return d.addCallback(pidCompleteCb) @@ -2339,7 +2339,7 @@ j(self.bazfoo, "executable")] if runtime.platform.isWindows(): expectedPaths.append(j(self.bazbar, "executable")) - self.assertEquals(paths, expectedPaths) + self.assertEqual(paths, expectedPaths) def testWhichPathExt(self): @@ -2358,7 +2358,7 @@ j(self.bazfoo, "executable.bin")] if runtime.platform.isWindows(): expectedPaths.append(j(self.bazbar, "executable")) - self.assertEquals(paths, expectedPaths) + self.assertEqual(paths, expectedPaths) @@ -2432,7 +2432,7 @@ # child must not get past that write without raising self.assertNotEquals( reason.exitCode, 42, 'process reason was %r' % reason) - self.assertEquals(p.output, '') + self.assertEqual(p.output, '') return p.errput @@ -2457,7 +2457,7 @@ def _check(errput): # there should be no stderr open, so nothing for it to # write the error to. - self.assertEquals(errput, '') + self.assertEqual(errput, '') d.addCallback(_check) return d diff --git a/lib/twisted-trunk/twisted/test/test_protocols.py b/lib/twisted-trunk/twisted/test/test_protocols.py --- a/lib/twisted-trunk/twisted/test/test_protocols.py +++ b/lib/twisted-trunk/twisted/test/test_protocols.py @@ -129,7 +129,7 @@ a.dataReceived("how") a.dataReceived("are") a.dataReceived("you") - self.assertEquals(t.value(), "helloworldhowareyou") + self.assertEqual(t.value(), "helloworldhowareyou") def test_who(self): @@ -139,7 +139,7 @@ t = proto_helpers.StringTransport() a = wire.Who() a.makeConnection(t) - self.assertEquals(t.value(), "root\r\n") + self.assertEqual(t.value(), "root\r\n") def test_QOTD(self): @@ -149,7 +149,7 @@ t = proto_helpers.StringTransport() a = wire.QOTD() a.makeConnection(t) - self.assertEquals(t.value(), + self.assertEqual(t.value(), "An apple a day keeps the doctor away.\r\n") @@ -207,7 +207,7 @@ for i in range(len(self.buffer)/packet_size + 1): s = self.buffer[i*packet_size:(i+1)*packet_size] a.dataReceived(s) - self.failUnlessEqual(self.output, a.received) + self.assertEqual(self.output, a.received) pause_buf = 'twiddle1\ntwiddle2\npause\ntwiddle3\n' @@ -229,9 +229,9 @@ for i in range(len(self.pause_buf)/packet_size + 1): s = self.pause_buf[i*packet_size:(i+1)*packet_size] a.dataReceived(s) - self.assertEquals(self.pause_output1, a.received) + self.assertEqual(self.pause_output1, a.received) clock.advance(0) - self.assertEquals(self.pause_output2, a.received) + self.assertEqual(self.pause_output2, a.received) rawpause_buf = 'twiddle1\ntwiddle2\nlen 5\nrawpause\n12345twiddle3\n' @@ -252,9 +252,9 @@ for i in range(len(self.rawpause_buf)/packet_size + 1): s = self.rawpause_buf[i*packet_size:(i+1)*packet_size] a.dataReceived(s) - self.assertEquals(self.rawpause_output1, a.received) + self.assertEqual(self.rawpause_output1, a.received) clock.advance(0) - self.assertEquals(self.rawpause_output2, a.received) + self.assertEqual(self.rawpause_output2, a.received) stop_buf = 'twiddle1\ntwiddle2\nstop\nmore\nstuff\n' @@ -272,7 +272,7 @@ for i in range(len(self.stop_buf)/packet_size + 1): s = self.stop_buf[i*packet_size:(i+1)*packet_size] a.dataReceived(s) - self.assertEquals(self.stop_output, a.received) + self.assertEqual(self.stop_output, a.received) def test_lineReceiverAsProducer(self): @@ -283,7 +283,7 @@ t = proto_helpers.StringIOWithoutClosing() a.makeConnection(protocol.FileWrapper(t)) a.dataReceived('produce\nhello world\nunproduce\ngoodbye\n') - self.assertEquals(a.received, + self.assertEqual(a.received, ['produce', 'hello world', 'unproduce', 'goodbye']) @@ -329,7 +329,7 @@ a.makeConnection(t) for c in self.buffer: a.dataReceived(c) - self.assertEquals(a.received, self.buffer.split('\n')[:-1]) + self.assertEqual(a.received, self.buffer.split('\n')[:-1]) def test_lineTooLong(self): @@ -431,7 +431,7 @@ s = out[i*packet_size:(i+1)*packet_size] if s: a.dataReceived(s) - self.assertEquals(a.received, self.strings) + self.assertEqual(a.received, self.strings) def test_sendNonStrings(self): @@ -451,8 +451,8 @@ t.clear() length = out[:out.find(":")] data = out[out.find(":") + 1:-1] #[:-1] to ignore the trailing "," - self.assertEquals(int(length), len(str(s))) - self.assertEquals(data, str(s)) + self.assertEqual(int(length), len(str(s))) + self.assertEqual(data, str(s)) warnings = self.flushWarnings( offendingFunctions=[self.test_sendNonStrings]) @@ -471,7 +471,7 @@ Empty netstrings (with length '0') can be received. """ self.netstringReceiver.dataReceived("0:,") - self.assertEquals(self.netstringReceiver.received, [""]) + self.assertEqual(self.netstringReceiver.received, [""]) def test_receiveOneCharacter(self): @@ -479,7 +479,7 @@ One-character netstrings can be received. """ self.netstringReceiver.dataReceived("1:a,") - self.assertEquals(self.netstringReceiver.received, ["a"]) + self.assertEqual(self.netstringReceiver.received, ["a"]) def test_receiveTwoCharacters(self): @@ -487,7 +487,7 @@ Two-character netstrings can be received. """ self.netstringReceiver.dataReceived("2:ab,") - self.assertEquals(self.netstringReceiver.received, ["ab"]) + self.assertEqual(self.netstringReceiver.received, ["ab"]) def test_receiveNestedNetstring(self): @@ -497,7 +497,7 @@ characters appearing inside the data portion of the netstring. """ self.netstringReceiver.dataReceived("4:1:a,,") - self.assertEquals(self.netstringReceiver.received, ["1:a,"]) + self.assertEqual(self.netstringReceiver.received, ["1:a,"]) def test_moreDataThanSpecified(self): @@ -558,7 +558,7 @@ """ self.netstringReceiver.dataReceived("4:aa") self.netstringReceiver.dataReceived("aa,") - self.assertEquals(self.netstringReceiver.received, ["aaaa"]) + self.assertEqual(self.netstringReceiver.received, ["aaaa"]) self.assertTrue(self.netstringReceiver._payloadComplete()) @@ -569,7 +569,7 @@ """ for part in ["1", "0:01234", "56789", ","]: self.netstringReceiver.dataReceived(part) - self.assertEquals(self.netstringReceiver.received, ["0123456789"]) + self.assertEqual(self.netstringReceiver.received, ["0123456789"]) def test_receiveNetstringPortions_3(self): @@ -578,7 +578,7 @@ """ for part in "2:ab,": self.netstringReceiver.dataReceived(part) - self.assertEquals(self.netstringReceiver.received, ["ab"]) + self.assertEqual(self.netstringReceiver.received, ["ab"]) def test_receiveTwoNetstrings(self): @@ -589,9 +589,9 @@ """ self.netstringReceiver.dataReceived("1:a,1") self.assertTrue(self.netstringReceiver._payloadComplete()) - self.assertEquals(self.netstringReceiver.received, ["a"]) + self.assertEqual(self.netstringReceiver.received, ["a"]) self.netstringReceiver.dataReceived(":b,") - self.assertEquals(self.netstringReceiver.received, ["a", "b"]) + self.assertEqual(self.netstringReceiver.received, ["a", "b"]) def test_maxReceiveLimit(self): @@ -612,7 +612,7 @@ """ self.netstringReceiver._remainingData = "12:" self.netstringReceiver._consumeLength() - self.assertEquals(self.netstringReceiver._expectedPayloadSize, 13) + self.assertEqual(self.netstringReceiver._expectedPayloadSize, 13) def test_consumeLengthBorderCase1(self): @@ -623,7 +623,7 @@ self.netstringReceiver._remainingData = "12:" self.netstringReceiver.MAX_LENGTH = 12 self.netstringReceiver._consumeLength() - self.assertEquals(self.netstringReceiver._expectedPayloadSize, 13) + self.assertEqual(self.netstringReceiver._expectedPayloadSize, 13) def test_consumeLengthBorderCase2(self): @@ -659,22 +659,22 @@ warnings = self.flushWarnings( offendingFunctions=[self.test_deprecatedModuleAttributes]) - self.assertEquals(len(warnings), 4) + self.assertEqual(len(warnings), 4) for warning in warnings: - self.assertEquals(warning['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warning['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], ("twisted.protocols.basic.LENGTH was deprecated in Twisted 10.2.0: " "NetstringReceiver parser state is private.")) - self.assertEquals( + self.assertEqual( warnings[1]['message'], ("twisted.protocols.basic.DATA was deprecated in Twisted 10.2.0: " "NetstringReceiver parser state is private.")) - self.assertEquals( + self.assertEqual( warnings[2]['message'], ("twisted.protocols.basic.COMMA was deprecated in Twisted 10.2.0: " "NetstringReceiver parser state is private.")) - self.assertEquals( + self.assertEqual( warnings[3]['message'], ("twisted.protocols.basic.NUMBER was deprecated in Twisted 10.2.0: " "NetstringReceiver parser state is private.")) @@ -699,7 +699,7 @@ for s in self.strings: for c in struct.pack(r.structFormat,len(s)) + s: r.dataReceived(c) - self.assertEquals(r.received, self.strings) + self.assertEqual(r.received, self.strings) def test_partial(self): @@ -710,7 +710,7 @@ r = self.getProtocol() for c in s: r.dataReceived(c) - self.assertEquals(r.received, []) + self.assertEqual(r.received, []) def test_send(self): @@ -719,7 +719,7 @@ """ r = self.getProtocol() r.sendString("b" * 16) - self.assertEquals(r.transport.value(), + self.assertEqual(r.transport.value(), struct.pack(r.structFormat, 16) + "b" * 16) @@ -775,9 +775,9 @@ """ r = self.getProtocol() r.sendString("foo") - self.assertEquals(r.transport.value(), "\x00\x00\x00\x03foo") + self.assertEqual(r.transport.value(), "\x00\x00\x00\x03foo") r.dataReceived("\x00\x00\x00\x04ubar") - self.assertEquals(r.received, ["ubar"]) + self.assertEqual(r.received, ["ubar"]) @@ -805,9 +805,9 @@ """ r = self.getProtocol() r.sendString("foo") - self.assertEquals(r.transport.value(), "\x00\x03foo") + self.assertEqual(r.transport.value(), "\x00\x03foo") r.dataReceived("\x00\x04ubar") - self.assertEquals(r.received, ["ubar"]) + self.assertEqual(r.received, ["ubar"]) def test_tooLongSend(self): @@ -845,9 +845,9 @@ """ r = self.getProtocol() r.sendString("foo") - self.assertEquals(r.transport.value(), "\x03foo") + self.assertEqual(r.transport.value(), "\x03foo") r.dataReceived("\x04ubar") - self.assertEquals(r.received, ["ubar"]) + self.assertEqual(r.received, ["ubar"]) def test_tooLongSend(self): @@ -907,7 +907,7 @@ p.dataReceived('world\r\n') - self.assertEquals(t.data, ['hello, world']) + self.assertEqual(t.data, ['hello, world']) self.failUnless(t.paused) self.failUnless(p.paused) @@ -918,26 +918,26 @@ p.dataReceived('hello\r\nworld\r\n') - self.assertEquals(t.data, ['hello, world', 'hello']) + self.assertEqual(t.data, ['hello, world', 'hello']) self.failUnless(t.paused) self.failUnless(p.paused) p.resumeProducing() p.dataReceived('goodbye\r\n') - self.assertEquals(t.data, ['hello, world', 'hello', 'world']) + self.assertEqual(t.data, ['hello, world', 'hello', 'world']) self.failUnless(t.paused) self.failUnless(p.paused) p.resumeProducing() - self.assertEquals(t.data, ['hello, world', 'hello', 'world', 'goodbye']) + self.assertEqual(t.data, ['hello, world', 'hello', 'world', 'goodbye']) self.failUnless(t.paused) self.failUnless(p.paused) p.resumeProducing() - self.assertEquals(t.data, ['hello, world', 'hello', 'world', 'goodbye']) + self.assertEqual(t.data, ['hello, world', 'hello', 'world', 'goodbye']) self.failIf(t.paused) self.failIf(p.paused) @@ -1042,7 +1042,7 @@ def testDataReceived(data): received.extend(data) if len(received) >= nBytes: - self.assertEquals(''.join(received), 'x' * nBytes) + self.assertEqual(''.join(received), 'x' * nBytes) d.callback(None) self.clientProtocol.dataReceived = testDataReceived diff --git a/lib/twisted-trunk/twisted/test/test_randbytes.py b/lib/twisted-trunk/twisted/test/test_randbytes.py --- a/lib/twisted-trunk/twisted/test/test_randbytes.py +++ b/lib/twisted-trunk/twisted/test/test_randbytes.py @@ -27,9 +27,9 @@ """ for nbytes in range(17, 25): s = source(nbytes) - self.assertEquals(len(s), nbytes) + self.assertEqual(len(s), nbytes) s2 = source(nbytes) - self.assertEquals(len(s2), nbytes) + self.assertEqual(len(s2), nbytes) # This is crude but hey self.assertNotEquals(s2, s) @@ -106,7 +106,7 @@ "proceeding with non-cryptographically secure random source", __file__, wrapper) - self.assertEquals(len(s), 18) + self.assertEqual(len(s), 18) diff --git a/lib/twisted-trunk/twisted/test/test_rebuild.py b/lib/twisted-trunk/twisted/test/test_rebuild.py --- a/lib/twisted-trunk/twisted/test/test_rebuild.py +++ b/lib/twisted-trunk/twisted/test/test_rebuild.py @@ -70,7 +70,7 @@ test_rebuild.C = C c = C() i = myrebuilder.Inherit() - self.assertEquals(a.a(), 'a') + self.assertEqual(a.a(), 'a') # necessary because the file has not "changed" if a second has not gone # by in unix. This sucks, but it's not often that you'll be doing more # than one reload per second. @@ -84,12 +84,12 @@ pass else: b2 = myrebuilder.B() - self.assertEquals(b2.b(), 'c') - self.assertEquals(b.b(), 'c') - self.assertEquals(i.a(), 'd') - self.assertEquals(a.a(), 'b') + self.assertEqual(b2.b(), 'c') + self.assertEqual(b.b(), 'c') + self.assertEqual(i.a(), 'd') + self.assertEqual(a.a(), 'b') # more work to be done on new-style classes - # self.assertEquals(c.b(), 'c') + # self.assertEqual(c.b(), 'c') def testRebuild(self): """ @@ -117,7 +117,7 @@ newComponent.method() - self.assertEquals(newComponent.__class__, crash_test_dummy.XA) + self.assertEqual(newComponent.__class__, crash_test_dummy.XA) # Test that a duplicate registerAdapter is not allowed from twisted.python import components @@ -158,7 +158,7 @@ unhashableObject = None self.addCleanup(_cleanup) rebuild.rebuild(rebuild) - self.assertEquals(unhashableObject.hashCalled, True) + self.assertEqual(unhashableObject.hashCalled, True) diff --git a/lib/twisted-trunk/twisted/test/test_reflect.py b/lib/twisted-trunk/twisted/test/test_reflect.py --- a/lib/twisted-trunk/twisted/test/test_reflect.py +++ b/lib/twisted-trunk/twisted/test/test_reflect.py @@ -28,8 +28,8 @@ def testSet(self): self.setter(a=1, b=2) - self.failUnlessEqual(self.setter.a, 1) - self.failUnlessEqual(self.setter.b, 2) + self.assertEqual(self.setter.a, 1) + self.assertEqual(self.setter.b, 2) @@ -81,21 +81,21 @@ def testSet(self): self.tester.x = 1 - self.failUnlessEqual(self.tester.x, 1) - self.failUnlessEqual(self.tester.y, 1) + self.assertEqual(self.tester.x, 1) + self.assertEqual(self.tester.y, 1) def testGet(self): - self.failUnlessEqual(self.tester.z, 1) - self.failUnlessEqual(self.tester.q, 1) + self.assertEqual(self.tester.z, 1) + self.assertEqual(self.tester.q, 1) def testDel(self): self.tester.z - self.failUnlessEqual(self.tester.q, 1) + self.assertEqual(self.tester.q, 1) del self.tester.z - self.failUnlessEqual(hasattr(self.tester, "q"), 0) + self.assertEqual(hasattr(self.tester, "q"), 0) self.tester.x = 1 del self.tester.x - self.failUnlessEqual(hasattr(self.tester, "x"), 0) + self.assertEqual(hasattr(self.tester, "x"), 0) @@ -113,10 +113,10 @@ If an attribute is present in the class, it can be retrieved by default. """ - self.assertEquals(self.tester.r, 0) + self.assertEqual(self.tester.r, 0) self.tester.r = 1 - self.assertEquals(self.tester.r, 0) - self.assertEquals(self.tester.s, 1) + self.assertEqual(self.tester.r, 0) + self.assertEqual(self.tester.s, 1) def test_getValueInDict(self): @@ -125,7 +125,7 @@ C{__dict__}. """ self.tester.__dict__["r"] = 10 - self.assertEquals(self.tester.r, 10) + self.assertEqual(self.tester.r, 10) def test_notYetInDict(self): @@ -409,9 +409,9 @@ c = [a, b] d = [a, c] - self.assertEquals(['[0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=1)) - self.assertEquals(['[0]', '[1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=2)) - self.assertEquals(['[0]', '[1][0]', '[1][1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=3)) + self.assertEqual(['[0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=1)) + self.assertEqual(['[0]', '[1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=2)) + self.assertEqual(['[0]', '[1][0]', '[1][1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=3)) def test_deque(self): """ @@ -434,14 +434,14 @@ pass old = OldClass() self.assertIn(reflect.getClass(OldClass).__name__, ('class', 'classobj')) - self.assertEquals(reflect.getClass(old).__name__, 'OldClass') + self.assertEqual(reflect.getClass(old).__name__, 'OldClass') def testNew(self): class NewClass(object): pass new = NewClass() - self.assertEquals(reflect.getClass(NewClass).__name__, 'type') - self.assertEquals(reflect.getClass(new).__name__, 'NewClass') + self.assertEqual(reflect.getClass(NewClass).__name__, 'type') + self.assertEqual(reflect.getClass(new).__name__, 'NewClass') @@ -498,7 +498,7 @@ object. """ x = [1, 2, 3] - self.assertEquals(reflect.safe_repr(x), repr(x)) + self.assertEqual(reflect.safe_repr(x), repr(x)) def test_brokenRepr(self): @@ -522,7 +522,7 @@ """ b = Breakable() b.breakStr = True - self.assertEquals(reflect.safe_repr(b), repr(b)) + self.assertEqual(reflect.safe_repr(b), repr(b)) def test_brokenClassRepr(self): @@ -595,7 +595,7 @@ def test_workingStr(self): x = [1, 2, 3] - self.assertEquals(reflect.safe_str(x), str(x)) + self.assertEqual(reflect.safe_str(x), str(x)) def test_brokenStr(self): @@ -662,10 +662,10 @@ Tests it finds good name for directories/packages. """ module = reflect.filenameToModuleName(os.path.join('twisted', 'test')) - self.assertEquals(module, 'test') + self.assertEqual(module, 'test') module = reflect.filenameToModuleName(os.path.join('twisted', 'test') + os.path.sep) - self.assertEquals(module, 'test') + self.assertEqual(module, 'test') def test_file(self): """ @@ -673,7 +673,7 @@ """ module = reflect.filenameToModuleName( os.path.join('twisted', 'test', 'test_reflect.py')) - self.assertEquals(module, 'test_reflect') + self.assertEqual(module, 'test_reflect') @@ -687,7 +687,7 @@ Helper to check that fully qualified name of C{obj} results to C{expected}. """ - self.assertEquals( + self.assertEqual( reflect.fullyQualifiedName(obj), expected) @@ -753,7 +753,7 @@ """ result = self.callDeprecated(Version("Twisted", 8, 2, 0), reflect.macro, "test", __file__, "test = 1") - self.assertEquals(result, 1) + self.assertEqual(result, 1) def test_allYourBase(self): """ diff --git a/lib/twisted-trunk/twisted/test/test_roots.py b/lib/twisted-trunk/twisted/test/test_roots.py --- a/lib/twisted-trunk/twisted/test/test_roots.py +++ b/lib/twisted-trunk/twisted/test/test_roots.py @@ -25,10 +25,10 @@ def testCollection(self): collection = roots.Collection() collection.putEntity("x", 'test') - self.failUnlessEqual(collection.getStaticEntity("x"), + self.assertEqual(collection.getStaticEntity("x"), 'test') collection.delEntity("x") - self.failUnlessEqual(collection.getStaticEntity('x'), + self.assertEqual(collection.getStaticEntity('x'), None) try: collection.storeEntity("x", None) @@ -48,7 +48,7 @@ def nameConstraint(self, name): return (name == 'x') c = const() - self.failUnlessEqual(c.putEntity('x', 'test'), None) + self.assertEqual(c.putEntity('x', 'test'), None) self.failUnlessRaises(roots.ConstraintViolation, c.putEntity, 'y', 'test') @@ -57,7 +57,7 @@ h = roots.Homogenous() h.entityType = types.IntType h.putEntity('a', 1) - self.failUnlessEqual(h.getStaticEntity('a'),1 ) + self.assertEqual(h.getStaticEntity('a'),1 ) self.failUnlessRaises(roots.ConstraintViolation, h.putEntity, 'x', 'y') diff --git a/lib/twisted-trunk/twisted/test/test_sip.py b/lib/twisted-trunk/twisted/test/test_sip.py --- a/lib/twisted-trunk/twisted/test/test_sip.py +++ b/lib/twisted-trunk/twisted/test/test_sip.py @@ -101,16 +101,16 @@ def validateMessage(self, m, method, uri, headers, body): """Validate Requests.""" - self.assertEquals(m.method, method) - self.assertEquals(m.uri.toString(), uri) - self.assertEquals(m.headers, headers) - self.assertEquals(m.body, body) - self.assertEquals(m.finished, 1) + self.assertEqual(m.method, method) + self.assertEqual(m.uri.toString(), uri) + self.assertEqual(m.headers, headers) + self.assertEqual(m.body, body) + self.assertEqual(m.finished, 1) def testSimple(self): l = self.l self.feedMessage(request1) - self.assertEquals(len(l), 1) + self.assertEqual(len(l), 1) self.validateMessage( l[0], "INVITE", "sip:foo", {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, @@ -120,7 +120,7 @@ l = self.l self.feedMessage(request1) self.feedMessage(request2) - self.assertEquals(len(l), 2) + self.assertEqual(len(l), 2) self.validateMessage( l[0], "INVITE", "sip:foo", {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, @@ -132,7 +132,7 @@ def testGarbage(self): l = self.l self.feedMessage(request3) - self.assertEquals(len(l), 1) + self.assertEqual(len(l), 1) self.validateMessage( l[0], "INVITE", "sip:foo", {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, @@ -141,7 +141,7 @@ def testThreeInOne(self): l = self.l self.feedMessage(request4) - self.assertEquals(len(l), 3) + self.assertEqual(len(l), 3) self.validateMessage( l[0], "INVITE", "sip:foo", {"from": ["mo"], "to": ["joe"], "content-length": ["0"]}, @@ -158,7 +158,7 @@ def testShort(self): l = self.l self.feedMessage(request_short) - self.assertEquals(len(l), 1) + self.assertEqual(len(l), 1) self.validateMessage( l[0], "INVITE", "sip:foo", {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, @@ -167,15 +167,15 @@ def testSimpleResponse(self): l = self.l self.feedMessage(response1) - self.assertEquals(len(l), 1) + self.assertEqual(len(l), 1) m = l[0] - self.assertEquals(m.code, 200) - self.assertEquals(m.phrase, "OK") - self.assertEquals( + self.assertEqual(m.code, 200) + self.assertEqual(m.phrase, "OK") + self.assertEqual( m.headers, {"from": ["foo"], "to": ["bar"], "content-length": ["0"]}) - self.assertEquals(m.body, "") - self.assertEquals(m.finished, 1) + self.assertEqual(m.body, "") + self.assertEqual(m.finished, 1) class MessageParsingTestCase2(MessageParsingTestCase): @@ -192,7 +192,7 @@ def testRequest(self): r = sip.Request("INVITE", "sip:foo") r.addHeader("foo", "bar") - self.assertEquals( + self.assertEqual( r.toString(), "INVITE sip:foo SIP/2.0\r\nFoo: bar\r\n\r\n") @@ -201,27 +201,27 @@ r.addHeader("foo", "bar") r.addHeader("Content-Length", "4") r.bodyDataReceived("1234") - self.assertEquals( + self.assertEqual( r.toString(), "SIP/2.0 200 OK\r\nFoo: bar\r\nContent-Length: 4\r\n\r\n1234") def testStatusCode(self): r = sip.Response(200) - self.assertEquals(r.toString(), "SIP/2.0 200 OK\r\n\r\n") + self.assertEqual(r.toString(), "SIP/2.0 200 OK\r\n\r\n") class ViaTestCase(unittest.TestCase): def checkRoundtrip(self, v): s = v.toString() - self.assertEquals(s, sip.parseViaHeader(s).toString()) + self.assertEqual(s, sip.parseViaHeader(s).toString()) def testExtraWhitespace(self): v1 = sip.parseViaHeader('SIP/2.0/UDP 192.168.1.1:5060') v2 = sip.parseViaHeader('SIP/2.0/UDP 192.168.1.1:5060') - self.assertEquals(v1.transport, v2.transport) - self.assertEquals(v1.host, v2.host) - self.assertEquals(v1.port, v2.port) + self.assertEqual(v1.transport, v2.transport) + self.assertEqual(v1.host, v2.host) + self.assertEqual(v1.port, v2.port) def test_complex(self): """ @@ -230,17 +230,17 @@ s = ("SIP/2.0/UDP first.example.com:4000;ttl=16;maddr=224.2.0.1" " ;branch=a7c6a8dlze (Example)") v = sip.parseViaHeader(s) - self.assertEquals(v.transport, "UDP") - self.assertEquals(v.host, "first.example.com") - self.assertEquals(v.port, 4000) - self.assertEquals(v.rport, None) - self.assertEquals(v.rportValue, None) - self.assertEquals(v.rportRequested, False) - self.assertEquals(v.ttl, 16) - self.assertEquals(v.maddr, "224.2.0.1") - self.assertEquals(v.branch, "a7c6a8dlze") - self.assertEquals(v.hidden, 0) - self.assertEquals(v.toString(), + self.assertEqual(v.transport, "UDP") + self.assertEqual(v.host, "first.example.com") + self.assertEqual(v.port, 4000) + self.assertEqual(v.rport, None) + self.assertEqual(v.rportValue, None) + self.assertEqual(v.rportRequested, False) + self.assertEqual(v.ttl, 16) + self.assertEqual(v.maddr, "224.2.0.1") + self.assertEqual(v.branch, "a7c6a8dlze") + self.assertEqual(v.hidden, 0) + self.assertEqual(v.toString(), "SIP/2.0/UDP first.example.com:4000" ";ttl=16;branch=a7c6a8dlze;maddr=224.2.0.1") self.checkRoundtrip(v) @@ -251,17 +251,17 @@ """ s = "SIP/2.0/UDP example.com;hidden" v = sip.parseViaHeader(s) - self.assertEquals(v.transport, "UDP") - self.assertEquals(v.host, "example.com") - self.assertEquals(v.port, 5060) - self.assertEquals(v.rport, None) - self.assertEquals(v.rportValue, None) - self.assertEquals(v.rportRequested, False) - self.assertEquals(v.ttl, None) - self.assertEquals(v.maddr, None) - self.assertEquals(v.branch, None) - self.assertEquals(v.hidden, True) - self.assertEquals(v.toString(), + self.assertEqual(v.transport, "UDP") + self.assertEqual(v.host, "example.com") + self.assertEqual(v.port, 5060) + self.assertEqual(v.rport, None) + self.assertEqual(v.rportValue, None) + self.assertEqual(v.rportRequested, False) + self.assertEqual(v.ttl, None) + self.assertEqual(v.maddr, None) + self.assertEqual(v.branch, None) + self.assertEqual(v.hidden, True) + self.assertEqual(v.toString(), "SIP/2.0/UDP example.com:5060;hidden") self.checkRoundtrip(v) @@ -318,11 +318,11 @@ def testNAT(self): s = "SIP/2.0/UDP 10.0.0.1:5060;received=22.13.1.5;rport=12345" v = sip.parseViaHeader(s) - self.assertEquals(v.transport, "UDP") - self.assertEquals(v.host, "10.0.0.1") - self.assertEquals(v.port, 5060) - self.assertEquals(v.received, "22.13.1.5") - self.assertEquals(v.rport, 12345) + self.assertEqual(v.transport, "UDP") + self.assertEqual(v.host, "10.0.0.1") + self.assertEqual(v.port, 5060) + self.assertEqual(v.received, "22.13.1.5") + self.assertEqual(v.rport, 12345) self.assertNotEquals(v.toString().find("rport=12345"), -1) @@ -346,7 +346,7 @@ "sip:j.doe at big.com?subject=project", "sip:example.com", ]: - self.assertEquals(sip.parseURL(url).toString(), url) + self.assertEqual(sip.parseURL(url).toString(), url) def testComplex(self): s = ("sip:user:pass at hosta:123;transport=udp;user=phone;method=foo;" @@ -358,7 +358,7 @@ ("method", "foo"), ("ttl", 12), ("maddr", "1.2.3.4"), ("other", ["blah", "goo=bar"]), ("headers", {"a": "b", "c": "d"})]: - self.assertEquals(getattr(url, k), v) + self.assertEqual(getattr(url, k), v) class ParseTestCase(unittest.TestCase): @@ -374,9 +374,9 @@ "sip:foo at example.com", {"tag": "bar", "foo": "baz"}), ]: gname, gurl, gparams = sip.parseAddress(address) - self.assertEquals(name, gname) - self.assertEquals(gurl.toString(), urls) - self.assertEquals(gparams, params) + self.assertEqual(name, gname) + self.assertEqual(gurl.toString(), urls) + self.assertEqual(gparams, params) class DummyLocator: @@ -406,13 +406,13 @@ r.addHeader("to", "") r.addHeader("contact", "") self.proxy.datagramReceived(r.toString(), ("1.2.3.4", 5060)) - self.assertEquals(len(self.sent), 1) + self.assertEqual(len(self.sent), 1) dest, m = self.sent[0] - self.assertEquals(dest.port, 5060) - self.assertEquals(dest.host, "server.com") - self.assertEquals(m.uri.toString(), "sip:foo") - self.assertEquals(m.method, "INVITE") - self.assertEquals(m.headers["via"], + self.assertEqual(dest.port, 5060) + self.assertEqual(dest.host, "server.com") + self.assertEqual(m.uri.toString(), "sip:foo") + self.assertEqual(m.method, "INVITE") + self.assertEqual(m.headers["via"], ["SIP/2.0/UDP 127.0.0.1:5060", "SIP/2.0/UDP 1.2.3.4:5060", "SIP/2.0/UDP 1.2.3.5:5060"]) @@ -426,7 +426,7 @@ r.addHeader("contact", "") self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) dest, m = self.sent[0] - self.assertEquals(m.headers["via"], + self.assertEqual(m.headers["via"], ["SIP/2.0/UDP 127.0.0.1:5060", "SIP/2.0/UDP 1.2.3.4:5060;received=1.1.1.1"]) @@ -436,18 +436,18 @@ r = sip.Response(200) r.addHeader("via", sip.Via("foo.com").toString()) self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEquals(len(self.sent), 0) + self.assertEqual(len(self.sent), 0) def testResponseForward(self): r = sip.Response(200) r.addHeader("via", sip.Via("127.0.0.1").toString()) r.addHeader("via", sip.Via("client.com", port=1234).toString()) self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEquals(len(self.sent), 1) + self.assertEqual(len(self.sent), 1) dest, m = self.sent[0] - self.assertEquals((dest.host, dest.port), ("client.com", 1234)) - self.assertEquals(m.code, 200) - self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:1234"]) + self.assertEqual((dest.host, dest.port), ("client.com", 1234)) + self.assertEqual(m.code, 200) + self.assertEqual(m.headers["via"], ["SIP/2.0/UDP client.com:1234"]) def testReceivedResponseForward(self): r = sip.Response(200) @@ -456,9 +456,9 @@ "via", sip.Via("10.0.0.1", received="client.com").toString()) self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEquals(len(self.sent), 1) + self.assertEqual(len(self.sent), 1) dest, m = self.sent[0] - self.assertEquals((dest.host, dest.port), ("client.com", 5060)) + self.assertEqual((dest.host, dest.port), ("client.com", 5060)) def testResponseToUs(self): r = sip.Response(200) @@ -466,17 +466,17 @@ l = [] self.proxy.gotResponse = lambda *a: l.append(a) self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEquals(len(l), 1) + self.assertEqual(len(l), 1) m, addr = l[0] - self.assertEquals(len(m.headers.get("via", [])), 0) - self.assertEquals(m.code, 200) + self.assertEqual(len(m.headers.get("via", [])), 0) + self.assertEqual(m.code, 200) def testLoop(self): r = sip.Request("INVITE", "sip:foo") r.addHeader("via", sip.Via("1.2.3.4").toString()) r.addHeader("via", sip.Via("127.0.0.1").toString()) self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEquals(self.sent, []) + self.assertEqual(self.sent, []) def testCantForwardRequest(self): r = sip.Request("INVITE", "sip:foo") @@ -484,11 +484,11 @@ r.addHeader("to", "") self.proxy.locator = FailingLocator() self.proxy.datagramReceived(r.toString(), ("1.2.3.4", 5060)) - self.assertEquals(len(self.sent), 1) + self.assertEqual(len(self.sent), 1) dest, m = self.sent[0] - self.assertEquals((dest.host, dest.port), ("1.2.3.4", 5060)) - self.assertEquals(m.code, 404) - self.assertEquals(m.headers["via"], ["SIP/2.0/UDP 1.2.3.4:5060"]) + self.assertEqual((dest.host, dest.port), ("1.2.3.4", 5060)) + self.assertEqual(m.code, 404) + self.assertEqual(m.headers["via"], ["SIP/2.0/UDP 1.2.3.4:5060"]) def testCantForwardResponse(self): pass @@ -531,33 +531,33 @@ def testRegister(self): self.register() dest, m = self.sent[0] - self.assertEquals((dest.host, dest.port), ("client.com", 5060)) - self.assertEquals(m.code, 200) - self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:5060"]) - self.assertEquals(m.headers["to"], ["sip:joe at bell.example.com"]) - self.assertEquals(m.headers["contact"], ["sip:joe at client.com:5060"]) + self.assertEqual((dest.host, dest.port), ("client.com", 5060)) + self.assertEqual(m.code, 200) + self.assertEqual(m.headers["via"], ["SIP/2.0/UDP client.com:5060"]) + self.assertEqual(m.headers["to"], ["sip:joe at bell.example.com"]) + self.assertEqual(m.headers["contact"], ["sip:joe at client.com:5060"]) self.failUnless( int(m.headers["expires"][0]) in (3600, 3601, 3599, 3598)) - self.assertEquals(len(self.registry.users), 1) + self.assertEqual(len(self.registry.users), 1) dc, uri = self.registry.users["joe"] - self.assertEquals(uri.toString(), "sip:joe at client.com:5060") + self.assertEqual(uri.toString(), "sip:joe at client.com:5060") d = self.proxy.locator.getAddress(sip.URL(username="joe", host="bell.example.com")) d.addCallback(lambda desturl : (desturl.host, desturl.port)) - d.addCallback(self.assertEquals, ('client.com', 5060)) + d.addCallback(self.assertEqual, ('client.com', 5060)) return d def testUnregister(self): self.register() self.unregister() dest, m = self.sent[1] - self.assertEquals((dest.host, dest.port), ("client.com", 5060)) - self.assertEquals(m.code, 200) - self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:5060"]) - self.assertEquals(m.headers["to"], ["sip:joe at bell.example.com"]) - self.assertEquals(m.headers["contact"], ["sip:joe at client.com:5060"]) - self.assertEquals(m.headers["expires"], ["0"]) - self.assertEquals(self.registry.users, {}) + self.assertEqual((dest.host, dest.port), ("client.com", 5060)) + self.assertEqual(m.code, 200) + self.assertEqual(m.headers["via"], ["SIP/2.0/UDP client.com:5060"]) + self.assertEqual(m.headers["to"], ["sip:joe at bell.example.com"]) + self.assertEqual(m.headers["contact"], ["sip:joe at client.com:5060"]) + self.assertEqual(m.headers["expires"], ["0"]) + self.assertEqual(self.registry.users, {}) def addPortal(self): @@ -572,10 +572,10 @@ self.addPortal() self.register() - self.assertEquals(len(self.registry.users), 0) - self.assertEquals(len(self.sent), 1) + self.assertEqual(len(self.registry.users), 0) + self.assertEqual(len(self.sent), 1) dest, m = self.sent[0] - self.assertEquals(m.code, 401) + self.assertEqual(m.code, 401) def test_basicAuthentication(self): @@ -603,10 +603,10 @@ "Basic " + "userXname:passXword".encode('base64')) self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEquals(len(self.registry.users), 1) - self.assertEquals(len(self.sent), 1) + self.assertEqual(len(self.registry.users), 1) + self.assertEqual(len(self.sent), 1) dest, m = self.sent[0] - self.assertEquals(m.code, 200) + self.assertEqual(m.code, 200) def test_failedBasicAuthentication(self): @@ -635,10 +635,10 @@ "authorization", "Basic " + "userXname:password".encode('base64')) self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEquals(len(self.registry.users), 0) - self.assertEquals(len(self.sent), 1) + self.assertEqual(len(self.registry.users), 0) + self.assertEqual(len(self.sent), 1) dest, m = self.sent[0] - self.assertEquals(m.code, 401) + self.assertEqual(m.code, 401) def testWrongDomainRegister(self): @@ -647,7 +647,7 @@ r.addHeader("contact", "sip:joe at client.com:1234") r.addHeader("via", sip.Via("client.com").toString()) self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEquals(len(self.sent), 0) + self.assertEqual(len(self.sent), 0) def testWrongToDomainRegister(self): r = sip.Request("REGISTER", "sip:bell.example.com") @@ -655,7 +655,7 @@ r.addHeader("contact", "sip:joe at client.com:1234") r.addHeader("via", sip.Via("client.com").toString()) self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEquals(len(self.sent), 0) + self.assertEqual(len(self.sent), 0) def testWrongDomainLookup(self): self.register() @@ -718,9 +718,9 @@ sip.URL(host="127.0.0.1", port=self.serverAddress[1]), r) d = self.client.deferred def check(received): - self.assertEquals(len(received), 1) + self.assertEqual(len(received), 1) r = received[0] - self.assertEquals(r.code, 200) + self.assertEqual(r.code, 200) d.addCallback(check) return d @@ -752,9 +752,9 @@ r) d = self.client.deferred def check(received): - self.assertEquals(len(received), 1) + self.assertEqual(len(received), 1) r = received[0] - self.assertEquals(r.code, 200) + self.assertEqual(r.code, 200) d.addCallback(check) return d @@ -871,7 +871,7 @@ def testChallenge(self): self.proxy.datagramReceived(registerRequest, ("127.0.0.1", 5632)) - self.assertEquals( + self.assertEqual( self.transport.written[-1], ((challengeResponse, ("127.0.0.1", 5632))) ) @@ -879,7 +879,7 @@ self.proxy.datagramReceived(authRequest, ("127.0.0.1", 5632)) - self.assertEquals( + self.assertEqual( self.transport.written[-1], ((okResponse, ("127.0.0.1", 5632))) ) diff --git a/lib/twisted-trunk/twisted/test/test_sob.py b/lib/twisted-trunk/twisted/test/test_sob.py --- a/lib/twisted-trunk/twisted/test/test_sob.py +++ b/lib/twisted-trunk/twisted/test/test_sob.py @@ -35,7 +35,7 @@ p.setStyle(style) p.save(filename='persisttest.'+style) o1 = sob.load('persisttest.'+style, style) - self.failUnlessEqual(o, o1) + self.assertEqual(o, o1) def testStylesBeingSet(self): o = Dummy() @@ -45,8 +45,8 @@ sob.IPersistable(o).setStyle(style) sob.IPersistable(o).save(filename='lala.'+style) o1 = sob.load('lala.'+style, style) - self.failUnlessEqual(o.foo, o1.foo) - self.failUnlessEqual(sob.IPersistable(o1).style, style) + self.assertEqual(o.foo, o1.foo) + self.assertEqual(sob.IPersistable(o1).style, style) def testNames(self): @@ -56,11 +56,11 @@ p.setStyle(style) p.save() o1 = sob.load('object.ta'+style[0], style) - self.failUnlessEqual(o, o1) + self.assertEqual(o, o1) for tag in 'lala lolo'.split(): p.save(tag) o1 = sob.load('object-'+tag+'.ta'+style[0], style) - self.failUnlessEqual(o, o1) + self.assertEqual(o, o1) def testEncryptedStyles(self): for o in objects: @@ -70,7 +70,7 @@ p.setStyle(style) p.save(filename='epersisttest.'+style, passphrase=phrase) o1 = sob.load('epersisttest.'+style, style, phrase) - self.failUnlessEqual(o, o1) + self.assertEqual(o, o1) if Crypto is None: testEncryptedStyles.skip = "PyCrypto required for encrypted config" @@ -79,7 +79,7 @@ f.write('foo=[1,2,3] ') f.close() o = sob.loadValueFromFile('persisttest.python', 'foo') - self.failUnlessEqual(o, [1,2,3]) + self.assertEqual(o, [1,2,3]) def testEncryptedPython(self): phrase='once I was the king of spain' @@ -88,7 +88,7 @@ sob._encrypt(phrase, 'foo=[1,2,3]')) f.close() o = sob.loadValueFromFile('epersisttest.python', 'foo', phrase) - self.failUnlessEqual(o, [1,2,3]) + self.assertEqual(o, [1,2,3]) if Crypto is None: testEncryptedPython.skip = "PyCrypto required for encrypted config" diff --git a/lib/twisted-trunk/twisted/test/test_socks.py b/lib/twisted-trunk/twisted/test/test_socks.py --- a/lib/twisted-trunk/twisted/test/test_socks.py +++ b/lib/twisted-trunk/twisted/test/test_socks.py @@ -152,7 +152,7 @@ # Verify that the server responded with the address which will be # connected to. - self.assertEquals( + self.assertEqual( sent, struct.pack('!BBH', 0, 90, 34) + socket.inet_aton('127.0.0.1')) self.assertFalse(self.sock.transport.stringTCPTransport_closing) @@ -161,13 +161,13 @@ # Pass some data through and verify it is forwarded to the outgoing # connection. self.sock.dataReceived('hello, world') - self.assertEquals( + self.assertEqual( self.sock.driver_outgoing.transport.value(), 'hello, world') # Deliver some data from the output connection and verify it is # passed along to the incoming side. self.sock.driver_outgoing.dataReceived('hi there') - self.assertEquals(self.sock.transport.value(), 'hi there') + self.assertEqual(self.sock.transport.value(), 'hi there') self.sock.connectionLost('fake reason') @@ -192,7 +192,7 @@ # Verify that the server responds with a 91 error. sent = self.sock.transport.value() - self.assertEquals( + self.assertEqual( sent, struct.pack('!BBH', 0, 91, 0) + socket.inet_aton('0.0.0.0')) @@ -337,7 +337,7 @@ # Verify that the server responded with the address which will be # connected to. - self.assertEquals( + self.assertEqual( sent, struct.pack('!BBH', 0, 90, 1234) + socket.inet_aton('6.7.8.9')) self.assertFalse(self.sock.transport.stringTCPTransport_closing) @@ -361,7 +361,7 @@ # Deliver some data from the output connection and verify it is # passed along to the incoming side. self.sock.dataReceived('hi there') - self.assertEquals(incoming.transport.value(), 'hi there') + self.assertEqual(incoming.transport.value(), 'hi there') # the other way around incoming.dataReceived('hi there') @@ -390,7 +390,7 @@ # Verify that the server responds with a 91 error. sent = self.sock.transport.value() - self.assertEquals( + self.assertEqual( sent, struct.pack('!BBH', 0, 91, 0) + socket.inet_aton('0.0.0.0')) diff --git a/lib/twisted-trunk/twisted/test/test_ssl.py b/lib/twisted-trunk/twisted/test/test_ssl.py --- a/lib/twisted-trunk/twisted/test/test_ssl.py +++ b/lib/twisted-trunk/twisted/test/test_ssl.py @@ -7,6 +7,7 @@ from twisted.trial import unittest from twisted.internet import protocol, reactor, interfaces, defer +from twisted.internet.error import ConnectionDone from twisted.protocols import basic from twisted.python import util from twisted.python.runtime import platform @@ -26,6 +27,12 @@ SSL = ssl = None _noSSL() +try: + from twisted.protocols import tls as newTLS +except ImportError: + # Assuming SSL exists, we're using old version in reactor (i.e. non-protocol) + newTLS = None + certPath = util.sibpath(__file__, "server.pem") @@ -397,7 +404,7 @@ before and after the startTLS. """ def check(ignore): - self.assertEquals( + self.assertEqual( self.serverFactory.lines, UnintelligentProtocol.pretext + UnintelligentProtocol.posttext ) @@ -412,7 +419,7 @@ received after server startTLS should be received as raw. """ def check(ignored): - self.assertEquals( + self.assertEqual( self.serverFactory.lines, UnintelligentProtocol.pretext ) @@ -428,7 +435,7 @@ Test startTLS first initiated by client. """ def check(ignored): - self.assertEquals( + self.assertEqual( self.clientFactory.lines, UnintelligentProtocol.pretext + UnintelligentProtocol.posttext ) @@ -477,11 +484,14 @@ reactor.connectSSL('127.0.0.1', port.getHost().port, client, cCTX) return clientProto.deferred.addCallback( - self.assertEquals, "+OK \r\n") + self.assertEqual, "+OK \r\n") class ConnectionLostTestCase(unittest.TestCase, ContextGeneratingMixin): + """ + SSL connection closing tests. + """ def testImmediateDisconnect(self): org = "twisted.test.test_ssl" @@ -506,6 +516,55 @@ lambda ignoredResult: self.serverPort.stopListening()) + def test_bothSidesLoseConnection(self): + """ + Both sides of SSL connection close connection; the connections should + close cleanly, and only after the underlying TCP connection has + disconnected. + """ + class CloseAfterHandshake(protocol.Protocol): + def __init__(self): + self.done = defer.Deferred() + + def connectionMade(self): + self.transport.write("a") + + def dataReceived(self, data): + # If we got data, handshake is over: + self.transport.loseConnection() + + def connectionLost(self2, reason): + self2.done.errback(reason) + del self2.done + + org = "twisted.test.test_ssl" + self.setupServerAndClient( + (org, org + ", client"), {}, + (org, org + ", server"), {}) + + serverProtocol = CloseAfterHandshake() + serverProtocolFactory = protocol.ServerFactory() + serverProtocolFactory.protocol = lambda: serverProtocol + serverPort = reactor.listenSSL(0, + serverProtocolFactory, self.serverCtxFactory) + self.addCleanup(serverPort.stopListening) + + clientProtocol = CloseAfterHandshake() + clientProtocolFactory = protocol.ClientFactory() + clientProtocolFactory.protocol = lambda: clientProtocol + clientConnector = reactor.connectSSL('127.0.0.1', + serverPort.getHost().port, clientProtocolFactory, self.clientCtxFactory) + + def checkResult(failure): + failure.trap(ConnectionDone) + return defer.gatherResults( + [clientProtocol.done.addErrback(checkResult), + serverProtocol.done.addErrback(checkResult)]) + + if newTLS is None: + test_bothSidesLoseConnection.skip = "Old SSL code doesn't always close cleanly." + + def testFailedVerify(self): org = "twisted.test.test_ssl" self.setupServerAndClient( diff --git a/lib/twisted-trunk/twisted/test/test_sslverify.py b/lib/twisted-trunk/twisted/test/test_sslverify.py --- a/lib/twisted-trunk/twisted/test/test_sslverify.py +++ b/lib/twisted-trunk/twisted/test/test_sslverify.py @@ -171,7 +171,7 @@ Check that abbreviations used in certificates correctly map to complete names. """ - self.assertEquals( + self.assertEqual( sslverify.DN(CN='a', OU='hello'), sslverify.DistinguishedName(commonName='a', organizationalUnitName='hello')) @@ -180,9 +180,9 @@ sslverify.DN(CN='a', OU='hello', emailAddress='xxx')) dn = sslverify.DN(CN='abcdefg') self.assertRaises(AttributeError, setattr, dn, 'Cn', 'x') - self.assertEquals(dn.CN, dn.commonName) + self.assertEqual(dn.CN, dn.commonName) dn.CN = 'bcdefga' - self.assertEquals(dn.CN, dn.commonName) + self.assertEqual(dn.CN, dn.commonName) def testInspectDistinguishedName(self): @@ -300,7 +300,7 @@ """ opts = sslverify.OpenSSLCertificateOptions(enableSessionTickets=True) ctx = opts.getContext() - self.assertEquals(0, ctx.set_options(0) & 0x00004000) + self.assertEqual(0, ctx.set_options(0) & 0x00004000) def test_certificateOptionsSessionTicketsDisabled(self): @@ -309,7 +309,7 @@ """ opts = sslverify.OpenSSLCertificateOptions(enableSessionTickets=False) ctx = opts.getContext() - self.assertEquals(0x00004000, ctx.set_options(0) & 0x00004000) + self.assertEqual(0x00004000, ctx.set_options(0) & 0x00004000) def test_allowedAnonymousClientConnection(self): @@ -325,7 +325,7 @@ onData=onData) return onData.addCallback( - lambda result: self.assertEquals(result, WritingProtocol.byte)) + lambda result: self.assertEqual(result, WritingProtocol.byte)) def test_refusedAnonymousClientConnection(self): """ @@ -396,7 +396,7 @@ onData=onData) return onData.addCallback( - lambda result: self.assertEquals(result, WritingProtocol.byte)) + lambda result: self.assertEqual(result, WritingProtocol.byte)) def test_successfulSymmetricSelfSignedCertificateVerification(self): """ @@ -413,7 +413,7 @@ onData=onData) return onData.addCallback( - lambda result: self.assertEquals(result, WritingProtocol.byte)) + lambda result: self.assertEqual(result, WritingProtocol.byte)) def test_verification(self): """ @@ -455,7 +455,7 @@ onData=onData) return onData.addCallback( - lambda result: self.assertEquals(result, WritingProtocol.byte)) + lambda result: self.assertEqual(result, WritingProtocol.byte)) diff --git a/lib/twisted-trunk/twisted/test/test_stateful.py b/lib/twisted-trunk/twisted/test/test_stateful.py --- a/lib/twisted-trunk/twisted/test/test_stateful.py +++ b/lib/twisted-trunk/twisted/test/test_stateful.py @@ -73,5 +73,5 @@ for s in self.strings * 4: big += pack("!i", len(s)) + s r.dataReceived(big) - self.assertEquals(r.received, self.strings * 4) + self.assertEqual(r.received, self.strings * 4) diff --git a/lib/twisted-trunk/twisted/test/test_stdio.py b/lib/twisted-trunk/twisted/test/test_stdio.py --- a/lib/twisted-trunk/twisted/test/test_stdio.py +++ b/lib/twisted-trunk/twisted/test/test_stdio.py @@ -238,7 +238,7 @@ self._spawnProcess(p, 'stdio_test_write.py') def processEnded(reason): - self.assertEquals(p.data[1], 'ok!') + self.assertEqual(p.data[1], 'ok!') reason.trap(error.ProcessDone) return self._requireFailure(d, processEnded) @@ -254,7 +254,7 @@ self._spawnProcess(p, 'stdio_test_writeseq.py') def processEnded(reason): - self.assertEquals(p.data[1], 'ok!') + self.assertEqual(p.data[1], 'ok!') reason.trap(error.ProcessDone) return self._requireFailure(d, processEnded) @@ -290,7 +290,7 @@ p.onConnection.addCallback(connectionMade) def processEnded(reason): - self.assertEquals(p.data[1], ''.join(written)) + self.assertEqual(p.data[1], ''.join(written)) self.failIf(toWrite, "Connection lost with %d writes left to go." % (len(toWrite),)) reason.trap(error.ProcessDone) return self._requireFailure(d, processEnded) @@ -309,7 +309,7 @@ self._spawnProcess(p, 'stdio_test_consumer.py', junkPath) def processEnded(reason): - self.assertEquals(p.data[1], file(junkPath).read()) + self.assertEqual(p.data[1], file(junkPath).read()) reason.trap(error.ProcessDone) return self._requireFailure(d, processEnded) @@ -358,8 +358,8 @@ # Once the connection is lost, make sure the counter is at the # appropriate value. def cbLost(reason): - self.assertEquals(count.next(), howMany + 1) - self.assertEquals( + self.assertEqual(count.next(), howMany + 1) + self.assertEqual( path.getContent(), ''.join(map(str, range(howMany)))) onConnLost.addCallback(cbLost) @@ -389,7 +389,7 @@ RuntimeError, stdio.StandardIO, protocol.Protocol(), stdout=fd) - self.assertEquals( + self.assertEqual( str(exc), "This reactor does not support this type of file descriptor (fd " "%d, mode %d) (for example, epollreactor does not support normal " diff --git a/lib/twisted-trunk/twisted/test/test_strcred.py b/lib/twisted-trunk/twisted/test/test_strcred.py --- a/lib/twisted-trunk/twisted/test/test_strcred.py +++ b/lib/twisted-trunk/twisted/test/test_strcred.py @@ -121,7 +121,7 @@ Test that the checker works with valid credentials. """ def _gotAvatar(username): - self.assertEquals(username, self.admin.username) + self.assertEqual(username, self.admin.username) return (self.checker .requestAvatarId(self.admin) .addCallback(_gotAvatar)) @@ -221,7 +221,7 @@ Test that the checker works with valid credentials. """ def _gotAvatar(username): - self.assertEquals(username, self.admin.username) + self.assertEqual(username, self.admin.username) return (self.checker .requestAvatarId(self.admin) .addCallback(_gotAvatar)) @@ -293,7 +293,7 @@ Test that the checker works with valid credentials. """ def _gotAvatar(username): - self.assertEquals(username, self.admin.username) + self.assertEqual(username, self.admin.username) return (self.checker .requestAvatarId(self.admin) .addCallback(_gotAvatar)) @@ -385,8 +385,8 @@ options = DummyOptions() options.parseOptions(['--auth', 'memory', '--auth', 'anonymous']) chd = options['credInterfaces'] - self.assertEquals(len(chd[credentials.IAnonymous]), 1) - self.assertEquals(len(chd[credentials.IUsernamePassword]), 1) + self.assertEqual(len(chd[credentials.IAnonymous]), 1) + self.assertEqual(len(chd[credentials.IUsernamePassword]), 1) chdAnonymous = chd[credentials.IAnonymous][0] chdUserPass = chd[credentials.IUsernamePassword][0] self.assertTrue(checkers.ICredentialsChecker.providedBy(chdAnonymous)) @@ -404,7 +404,7 @@ """ options = DummyOptions() options.parseOptions(['--auth', 'memory', '--auth', 'unix']) - self.assertEquals( + self.assertEqual( options['credCheckers'], options['credInterfaces'][credentials.IUsernamePassword]) @@ -456,7 +456,7 @@ options = DummyOptions() err = self.assertRaises(usage.UsageError, options.parseOptions, ['--auth', 'file']) - self.assertEquals(str(err), + self.assertEqual(str(err), "Unexpected error: 'file' requires a filename") @@ -562,8 +562,8 @@ self.assertIdentical(options['credInterfaces'][iface][0], self.goodChecker) self.assertIdentical(options['credCheckers'][0], self.goodChecker) # Test that we didn't get IUsernameHashedPassword - self.assertEquals(len(options['credInterfaces'][iface]), 1) - self.assertEquals(len(options['credCheckers']), 1) + self.assertEqual(len(options['credInterfaces'][iface]), 1) + self.assertEqual(len(options['credCheckers']), 1) def test_failOnAddingUnsupportedChecker(self): diff --git a/lib/twisted-trunk/twisted/test/test_stringtransport.py b/lib/twisted-trunk/twisted/test/test_stringtransport.py --- a/lib/twisted-trunk/twisted/test/test_stringtransport.py +++ b/lib/twisted-trunk/twisted/test/test_stringtransport.py @@ -246,13 +246,13 @@ verifyObject(IConnector, connector) address = connector.getDestination() verifyObject(IAddress, address) - self.assertEquals(address.host, "test.example.com") - self.assertEquals(address.port, 8321) + self.assertEqual(address.host, "test.example.com") + self.assertEqual(address.port, 8321) connector = memoryReactor.connectUNIX("/fake/path", ClientFactory()) verifyObject(IConnector, connector) address = connector.getDestination() verifyObject(IAddress, address) - self.assertEquals(address.name, "/fake/path") + self.assertEqual(address.name, "/fake/path") def test_listenDefaultHost(self): @@ -270,10 +270,10 @@ verifyObject(IListeningPort, port) address = port.getHost() verifyObject(IAddress, address) - self.assertEquals(address.host, '0.0.0.0') - self.assertEquals(address.port, 8242) + self.assertEqual(address.host, '0.0.0.0') + self.assertEqual(address.port, 8242) port = memoryReactor.listenUNIX("/path/to/socket", Factory()) verifyObject(IListeningPort, port) address = port.getHost() verifyObject(IAddress, address) - self.assertEquals(address.name, "/path/to/socket") + self.assertEqual(address.name, "/path/to/socket") diff --git a/lib/twisted-trunk/twisted/test/test_strports.py b/lib/twisted-trunk/twisted/test/test_strports.py --- a/lib/twisted-trunk/twisted/test/test_strports.py +++ b/lib/twisted-trunk/twisted/test/test_strports.py @@ -23,8 +23,8 @@ def parse(self, *a, **kw): result = strports.parse(*a, **kw) warnings = self.flushWarnings([self.parse]) - self.assertEquals(len(warnings), 1) - self.assertEquals( + self.assertEqual(len(warnings), 1) + self.assertEqual( warnings[0]['message'], "twisted.application.strports.parse was deprecated " "in Twisted 10.2.0: in favor of twisted.internet.endpoints.serverFromString") @@ -35,7 +35,7 @@ """ Base numeric ports should be parsed as TCP. """ - self.assertEquals(self.parse('80', self.f), + self.assertEqual(self.parse('80', self.f), ('TCP', (80, self.f), {'interface':'', 'backlog':50})) @@ -44,7 +44,7 @@ A collection of keyword arguments with no prefixed type, like 'port=80', will be parsed as keyword arguments to 'tcp'. """ - self.assertEquals(self.parse('port=80', self.f), + self.assertEqual(self.parse('port=80', self.f), ('TCP', (80, self.f), {'interface':'', 'backlog':50})) @@ -69,10 +69,10 @@ # See twisted.application.test.test_internet.TestEndpointService. # test_synchronousRaiseRaisesSynchronously - self.assertEquals(svc._raiseSynchronously, True) + self.assertEqual(svc._raiseSynchronously, True) self.assertIsInstance(svc.endpoint, TCP4ServerEndpoint) # Maybe we should implement equality for endpoints. - self.assertEquals(svc.endpoint._port, aGoodPort) + self.assertEqual(svc.endpoint._port, aGoodPort) self.assertIdentical(svc.factory, aFactory) self.assertIdentical(svc.endpoint._reactor, reactor) @@ -96,23 +96,23 @@ svc = strports.service("8080", None, "unix") self.assertIsInstance(svc.endpoint, UNIXServerEndpoint) warnings = self.flushWarnings([self.test_serviceDeprecatedDefault]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "The 'default' parameter was deprecated in Twisted 10.2.0. " "Use qualified endpoint descriptions; for example, 'tcp:8080'.") - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) # Almost the same case, but slightly tricky - explicitly passing the old # default value, None, also must trigger a deprecation warning. svc = strports.service("tcp:8080", None, None) self.assertIsInstance(svc.endpoint, TCP4ServerEndpoint) warnings = self.flushWarnings([self.test_serviceDeprecatedDefault]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "The 'default' parameter was deprecated in Twisted 10.2.0.") - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) def test_serviceDeprecatedUnqualified(self): @@ -123,11 +123,11 @@ self.assertIsInstance(svc.endpoint, TCP4ServerEndpoint) warnings = self.flushWarnings( [self.test_serviceDeprecatedUnqualified]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "Unqualified strport description passed to 'service'." "Use qualified endpoint descriptions; for example, 'tcp:8080'.") - self.assertEquals(len(warnings), 1) + self.assertEqual(len(warnings), 1) diff --git a/lib/twisted-trunk/twisted/test/test_task.py b/lib/twisted-trunk/twisted/test/test_task.py --- a/lib/twisted-trunk/twisted/test/test_task.py +++ b/lib/twisted-trunk/twisted/test/test_task.py @@ -34,7 +34,7 @@ Test that the L{seconds} method of the fake clock returns fake time. """ c = task.Clock() - self.assertEquals(c.seconds(), 0) + self.assertEqual(c.seconds(), 0) def testCallLater(self): @@ -45,7 +45,7 @@ c = task.Clock() call = c.callLater(1, lambda a, b: None, 1, b=2) self.failUnless(interfaces.IDelayedCall.providedBy(call)) - self.assertEquals(call.getTime(), 1) + self.assertEqual(call.getTime(), 1) self.failUnless(call.active()) @@ -78,9 +78,9 @@ c = task.Clock() call = c.callLater(2, lambda: events.append(None)) c.advance(1) - self.assertEquals(events, []) + self.assertEqual(events, []) c.advance(1) - self.assertEquals(events, [None]) + self.assertEqual(events, [None]) self.failIf(call.active()) @@ -107,11 +107,11 @@ c = task.Clock() call = c.callLater(1, lambda a, b: events.append((a, b)), 1, b=2) call.delay(1) - self.assertEquals(call.getTime(), 2) + self.assertEqual(call.getTime(), 2) c.advance(1.5) - self.assertEquals(events, []) + self.assertEqual(events, []) c.advance(1.0) - self.assertEquals(events, [(1, 2)]) + self.assertEqual(events, [(1, 2)]) def testCallLaterResetLater(self): @@ -123,11 +123,11 @@ call = c.callLater(2, lambda a, b: events.append((a, b)), 1, b=2) c.advance(1) call.reset(3) - self.assertEquals(call.getTime(), 4) + self.assertEqual(call.getTime(), 4) c.advance(2) - self.assertEquals(events, []) + self.assertEqual(events, []) c.advance(1) - self.assertEquals(events, [(1, 2)]) + self.assertEqual(events, [(1, 2)]) def testCallLaterResetSooner(self): @@ -138,9 +138,9 @@ c = task.Clock() call = c.callLater(4, lambda a, b: events.append((a, b)), 1, b=2) call.reset(3) - self.assertEquals(call.getTime(), 3) + self.assertEqual(call.getTime(), 3) c.advance(3) - self.assertEquals(events, [(1, 2)]) + self.assertEqual(events, [(1, 2)]) def test_getDelayedCalls(self): @@ -153,7 +153,7 @@ calls = c.getDelayedCalls() - self.assertEquals(set([call, call2]), set(calls)) + self.assertEqual(set([call, call2]), set(calls)) def test_getDelayedCallsEmpty(self): @@ -162,7 +162,7 @@ constructed Clock. """ c = task.Clock() - self.assertEquals(c.getDelayedCalls(), []) + self.assertEqual(c.getDelayedCalls(), []) def test_providesIReactorTime(self): @@ -350,7 +350,7 @@ next interval which is still in the future. If it was created using L{LoopingCall.withCount}, a positional argument will be inserted at the beginning of the argument list, indicating the number - of calls that should have been made. + of calls that should have been made. """ times = [] clock = task.Clock() @@ -455,14 +455,14 @@ clock.pump(timings) - self.assertEquals(len(L), 3, + self.assertEqual(len(L), 3, "got %d iterations, not 3" % (len(L),)) for (a, b, c, d) in L: - self.assertEquals(a, "a") - self.assertEquals(b, "b") - self.assertEquals(c, None) - self.assertEquals(d, "d") + self.assertEqual(a, "a") + self.assertEqual(b, "b") + self.assertEqual(c, None) + self.assertEqual(d, "d") lc.stop() self.assertIdentical(theResult[0], lc) @@ -487,7 +487,7 @@ clock.pump(timings) - self.assertEquals(len(L), 2, + self.assertEqual(len(L), 2, "got %d iterations, not 2" % (len(L),)) lc.stop() self.assertIdentical(theResult[0], lc) @@ -522,6 +522,25 @@ return self._stoppingTest(10) + def test_reset(self): + """ + Test that L{LoopingCall} can be reset. + """ + ran = [] + def foo(): + ran.append(None) + + c = task.Clock() + lc = TestableLoopingCall(c, foo) + lc.start(2, now=False) + c.advance(1) + lc.reset() + c.advance(1) + self.assertEqual(ran, []) + c.advance(1) + self.assertEqual(ran, [None]) + + class ReactorLoopTestCase(unittest.TestCase): # Slightly inferior tests which exercise interactions with an actual @@ -554,7 +573,7 @@ lc = task.LoopingCall(foo) d = lc.start(0) def stopped(ign): - self.assertEquals(len(ran), 6) + self.assertEqual(len(ran), 6) return d.addCallback(stopped) @@ -644,21 +663,21 @@ d = lc.start(0.2, now=False) # Confirm that nothing has happened yet. - self.assertEquals(deferredCounts, []) + self.assertEqual(deferredCounts, []) # Advance the clock by 0.2 and then 0.4; testClock.pump([0.2, 0.4]) # We should now have exactly one count (of 1 call) - self.assertEquals(len(deferredCounts), 1) + self.assertEqual(len(deferredCounts), 1) # Fire the deferred, and advance the clock by another 0.2 d.callback(None) testClock.pump([0.2]) # We should now have exactly 2 counts... - self.assertEquals(len(deferredCounts), 2) + self.assertEqual(len(deferredCounts), 2) # The first count should be 1 (one call) # The second count should be 3 (calls were missed at about 0.6 and 0.8) - self.assertEquals(deferredCounts, [1, 3]) + self.assertEqual(deferredCounts, [1, 3]) @@ -712,7 +731,7 @@ d.cancel() def cbCancelled(ignored): # Make sure there are no calls outstanding. - self.assertEquals([], clock.getDelayedCalls()) + self.assertEqual([], clock.getDelayedCalls()) # And make sure the call didn't somehow happen already. self.assertFalse(called) self.assertFailure(d, defer.CancelledError) diff --git a/lib/twisted-trunk/twisted/test/test_tcp.py b/lib/twisted-trunk/twisted/test/test_tcp.py --- a/lib/twisted-trunk/twisted/test/test_tcp.py +++ b/lib/twisted-trunk/twisted/test/test_tcp.py @@ -235,7 +235,7 @@ self.addCleanup(connector.disconnect) def check((serverProto, clientProto)): portNumber = port.getHost().port - self.assertEquals( + self.assertEqual( repr(serverProto.transport), "" % (portNumber,)) serverProto.transport.loseConnection() @@ -434,11 +434,11 @@ def check(serverProtocol, clientProtocol): for p in [serverProtocol, clientProtocol]: transport = p.transport - self.assertEquals(transport.getTcpNoDelay(), 0) + self.assertEqual(transport.getTcpNoDelay(), 0) transport.setTcpNoDelay(1) - self.assertEquals(transport.getTcpNoDelay(), 1) + self.assertEqual(transport.getTcpNoDelay(), 1) transport.setTcpNoDelay(0) - self.assertEquals(transport.getTcpNoDelay(), 0) + self.assertEqual(transport.getTcpNoDelay(), 0) return self._connectedClientAndServerTest(check) @@ -452,11 +452,11 @@ def check(serverProtocol, clientProtocol): for p in [serverProtocol, clientProtocol]: transport = p.transport - self.assertEquals(transport.getTcpKeepAlive(), 0) + self.assertEqual(transport.getTcpKeepAlive(), 0) transport.setTcpKeepAlive(1) - self.assertEquals(transport.getTcpKeepAlive(), 1) + self.assertEqual(transport.getTcpKeepAlive(), 1) transport.setTcpKeepAlive(0) - self.assertEquals(transport.getTcpKeepAlive(), 0) + self.assertEqual(transport.getTcpKeepAlive(), 0) return self._connectedClientAndServerTest(check) @@ -654,7 +654,7 @@ closedDeferred.addCallback(cbClosed) def cbClosedAll(ignored): - self.assertEquals((f.started, f.stopped), (1, 1)) + self.assertEqual((f.started, f.stopped), (1, 1)) closedDeferred.addCallback(cbClosedAll) return closedDeferred @@ -705,9 +705,9 @@ connector = reactor.connectTCP("127.0.0.1", portNumber, clientFactory) self.assertTrue(interfaces.IConnector.providedBy(connector)) dest = connector.getDestination() - self.assertEquals(dest.type, "TCP") - self.assertEquals(dest.host, "127.0.0.1") - self.assertEquals(dest.port, portNumber) + self.assertEqual(dest.type, "TCP") + self.assertEqual(dest.host, "127.0.0.1") + self.assertEqual(dest.port, portNumber) d = loopUntil(lambda: clientFactory.stopped) def clientFactoryStopped(ignored): @@ -737,7 +737,7 @@ d = loopUntil(lambda: clientFactory.stopped) def check(ignored): - self.assertEquals(clientFactory.failed, 1) + self.assertEqual(clientFactory.failed, 1) clientFactory.reason.trap(error.UserError) return d.addCallback(check) @@ -787,9 +787,9 @@ self.addCleanup(p1.stopListening) n = p1.getHost().port dest = p1.getHost() - self.assertEquals(dest.type, "TCP") - self.assertEquals(dest.host, "127.0.0.1") - self.assertEquals(dest.port, n) + self.assertEqual(dest.type, "TCP") + self.assertEqual(dest.host, "127.0.0.1") + self.assertEqual(dest.port, n) # make sure new listen raises error self.assertRaises(error.CannotListenError, @@ -837,7 +837,7 @@ return d def _check1connect2(results, cf1): - self.assertEquals(cf1.protocol.made, 1) + self.assertEqual(cf1.protocol.made, 1) d1 = defer.Deferred() d2 = defer.Deferred() @@ -855,13 +855,13 @@ return dl def _check2failed(results, cf1, cf2): - self.assertEquals(cf2.failed, 1) + self.assertEqual(cf2.failed, 1) cf2.reason.trap(error.ConnectBindError) self.assertTrue(cf2.reason.check(error.ConnectBindError)) return results def _check2stopped(results, cf1, cf2): - self.assertEquals(cf2.stopped, 1) + self.assertEqual(cf2.stopped, 1) return results def _stop(results, cf1, cf2): @@ -872,7 +872,7 @@ return d def _check1cleanup(results, cf1): - self.assertEquals(cf1.stopped, 1) + self.assertEqual(cf1.stopped, 1) theDeferred.addCallback(_connect1) return theDeferred @@ -909,8 +909,8 @@ connector = reactor.connectTCP('127.0.0.1', n, clientFactory) def check(ignored): - self.assertEquals([port.getHost()], clientFactory.peerAddresses) - self.assertEquals( + self.assertEqual([port.getHost()], clientFactory.peerAddresses) + self.assertEqual( port.getHost(), clientFactory.protocol.transport.getPeer()) onConnection.addCallback(check) @@ -1447,25 +1447,6 @@ [IPv4Address('TCP', clientPeer.host, clientPeer.port)]) - def test_buildProtocolServer(self): - """ - L{ServerFactory.buildProtocol} should be invoked with the address of - the client which has connected to the port the factory is listening on, - which should be the same as the address reported by the C{getPeer} - method of the transport of the server protocol and as the C{getHost} - method of the transport of the client protocol. - """ - clientHost = self.client.protocol.transport.getHost() - serverPeer = self.server.protocol.transport.getPeer() - - self.assertEqual( - self.serverWrapper.addresses, - [IPv4Address('TCP', serverPeer.host, serverPeer.port)]) - self.assertEqual( - self.serverWrapper.addresses, - [IPv4Address('TCP', clientHost.host, clientHost.port)]) - - class LargeBufferWriterProtocol(protocol.Protocol): @@ -1594,12 +1575,12 @@ def _setUp(self, client): self.client = client self.clientProtoConnectionLost = self.client.closedDeferred = defer.Deferred() - self.assertEquals(self.client.transport.connected, 1) + self.assertEqual(self.client.transport.connected, 1) # Wait for the server to notice there is a connection, too. return loopUntil(lambda: getattr(self.f, 'protocol', None) is not None) def tearDown(self): - self.assertEquals(self.client.closed, 0) + self.assertEqual(self.client.closed, 0) self.client.transport.loseConnection() d = defer.maybeDeferred(self.p.stopListening) d.addCallback(lambda ign: self.clientProtoConnectionLost) @@ -1607,17 +1588,17 @@ return d def _tearDown(self, ignored): - self.assertEquals(self.client.closed, 1) + self.assertEqual(self.client.closed, 1) # because we did half-close, the server also needs to # closed explicitly. - self.assertEquals(self.f.protocol.closed, 0) + self.assertEqual(self.f.protocol.closed, 0) d = defer.Deferred() def _connectionLost(reason): self.f.protocol.closed = 1 d.callback(None) self.f.protocol.connectionLost = _connectionLost self.f.protocol.transport.loseConnection() - d.addCallback(lambda x:self.assertEquals(self.f.protocol.closed, 1)) + d.addCallback(lambda x:self.assertEqual(self.f.protocol.closed, 1)) return d def testCloseWriteCloser(self): @@ -1631,18 +1612,18 @@ t.loseWriteConnection() return loopUntil(lambda :t._writeDisconnected) def check(ignored): - self.assertEquals(client.closed, False) - self.assertEquals(client.writeHalfClosed, True) - self.assertEquals(client.readHalfClosed, False) + self.assertEqual(client.closed, False) + self.assertEqual(client.writeHalfClosed, True) + self.assertEqual(client.readHalfClosed, False) return loopUntil(lambda :f.protocol.readHalfClosed) def write(ignored): w = client.transport.write w(" world") w("lalala fooled you") - self.assertEquals(0, len(client.transport._tempDataBuffer)) - self.assertEquals(f.protocol.data, "hello") - self.assertEquals(f.protocol.closed, False) - self.assertEquals(f.protocol.readHalfClosed, True) + self.assertEqual(0, len(client.transport._tempDataBuffer)) + self.assertEqual(f.protocol.data, "hello") + self.assertEqual(f.protocol.closed, False) + self.assertEqual(f.protocol.readHalfClosed, True) return d.addCallback(loseWrite).addCallback(check).addCallback(write) def testWriteCloseNotification(self): @@ -1652,7 +1633,7 @@ d = defer.gatherResults([ loopUntil(lambda :f.protocol.writeHalfClosed), loopUntil(lambda :self.client.readHalfClosed)]) - d.addCallback(lambda _: self.assertEquals( + d.addCallback(lambda _: self.assertEqual( f.protocol.readHalfClosed, False)) return d @@ -1708,7 +1689,7 @@ self.f.protocol.closedDeferred = d = defer.Deferred() self.client.closedDeferred = d2 = defer.Deferred() d.addCallback(lambda x: - self.failUnlessEqual(self.f.protocol.closed, True)) + self.assertEqual(self.f.protocol.closed, True)) return defer.gatherResults([d, d2]) @@ -1804,11 +1785,11 @@ self.addCleanup(connector.disconnect) # It should still have the default value - self.assertEquals(connector.transport.logstr, + self.assertEqual(connector.transport.logstr, "Uninitialized") def cb(ign): - self.assertEquals(connector.transport.logstr, + self.assertEqual(connector.transport.logstr, "AccumulatingProtocol,client") client.protocolConnectionMade.addCallback(cb) return client.protocolConnectionMade @@ -1909,7 +1890,7 @@ return 'CL' def _cbGather(res): - self.assertEquals(res, ['CL', 'CCL']) + self.assertEqual(res, ['CL', 'CCL']) d = defer.gatherResults([ client.protocolConnectionLost.addCallback(_cbCL), diff --git a/lib/twisted-trunk/twisted/test/test_text.py b/lib/twisted-trunk/twisted/test/test_text.py --- a/lib/twisted-trunk/twisted/test/test_text.py +++ b/lib/twisted-trunk/twisted/test/test_text.py @@ -15,6 +15,7 @@ prominent place in chemistry - an aberration which is happily almost impossible - it would occasion a rapid and widespread degeneration of that science. + -- Auguste Comte, Philosophie Positive, Paris, 1838 """ @@ -38,7 +39,7 @@ wordCount = len(words) sampleTextWordCount = len(self.sampleSplitText) - self.failUnlessEqual(wordCount, sampleTextWordCount) + self.assertEqual(wordCount, sampleTextWordCount) def test_wordMatch(self): """Compare the lists of words.""" @@ -47,7 +48,7 @@ for line in self.output: words.extend(line.split()) - # Using failUnlessEqual here prints out some + # Using assertEqual here prints out some # rather too long lists. self.failUnless(self.sampleSplitText == words) @@ -71,12 +72,12 @@ """Splitting strings with one-word phrases.""" s = 'This code "works."' r = text.splitQuoted(s) - self.failUnlessEqual(['This', 'code', 'works.'], r) + self.assertEqual(['This', 'code', 'works.'], r) def test_multiWord(self): s = 'The "hairy monkey" likes pie.' r = text.splitQuoted(s) - self.failUnlessEqual(['The', 'hairy monkey', 'likes', 'pie.'], r) + self.assertEqual(['The', 'hairy monkey', 'likes', 'pie.'], r) # Some of the many tests that would fail: @@ -84,12 +85,12 @@ # phrase = '"MANY SPACES"' # s = 'With %s between.' % (phrase,) # r = text.splitQuoted(s) - # self.failUnlessEqual(['With', phrase, 'between.'], r) + # self.assertEqual(['With', phrase, 'between.'], r) #def test_escapedSpace(self): # s = r"One\ Phrase" # r = text.splitQuoted(s) - # self.failUnlessEqual(["One Phrase"], r) + # self.assertEqual(["One Phrase"], r) class StrFileTest(unittest.TestCase): def setUp(self): @@ -99,58 +100,58 @@ pass def test_1_f(self): - self.assertEquals(False, text.strFile("x", self.io)) + self.assertEqual(False, text.strFile("x", self.io)) def test_1_1(self): - self.assertEquals(True, text.strFile("t", self.io)) + self.assertEqual(True, text.strFile("t", self.io)) def test_1_2(self): - self.assertEquals(True, text.strFile("h", self.io)) + self.assertEqual(True, text.strFile("h", self.io)) def test_1_3(self): - self.assertEquals(True, text.strFile("i", self.io)) + self.assertEqual(True, text.strFile("i", self.io)) def test_1_4(self): - self.assertEquals(True, text.strFile("s", self.io)) + self.assertEqual(True, text.strFile("s", self.io)) def test_1_5(self): - self.assertEquals(True, text.strFile("n", self.io)) + self.assertEqual(True, text.strFile("n", self.io)) def test_1_6(self): - self.assertEquals(True, text.strFile("g", self.io)) + self.assertEqual(True, text.strFile("g", self.io)) def test_3_1(self): - self.assertEquals(True, text.strFile("thi", self.io)) + self.assertEqual(True, text.strFile("thi", self.io)) def test_3_2(self): - self.assertEquals(True, text.strFile("his", self.io)) + self.assertEqual(True, text.strFile("his", self.io)) def test_3_3(self): - self.assertEquals(True, text.strFile("is ", self.io)) + self.assertEqual(True, text.strFile("is ", self.io)) def test_3_4(self): - self.assertEquals(True, text.strFile("ing", self.io)) + self.assertEqual(True, text.strFile("ing", self.io)) def test_3_f(self): - self.assertEquals(False, text.strFile("bla", self.io)) + self.assertEqual(False, text.strFile("bla", self.io)) def test_large_1(self): - self.assertEquals(True, text.strFile("this is a test", self.io)) + self.assertEqual(True, text.strFile("this is a test", self.io)) def test_large_2(self): - self.assertEquals(True, text.strFile("is a test string", self.io)) + self.assertEqual(True, text.strFile("is a test string", self.io)) def test_large_f(self): - self.assertEquals(False, text.strFile("ds jhfsa k fdas", self.io)) + self.assertEqual(False, text.strFile("ds jhfsa k fdas", self.io)) def test_overlarge_f(self): - self.assertEquals(False, text.strFile("djhsakj dhsa fkhsa s,mdbnfsauiw bndasdf hreew", self.io)) + self.assertEqual(False, text.strFile("djhsakj dhsa fkhsa s,mdbnfsauiw bndasdf hreew", self.io)) def test_self(self): - self.assertEquals(True, text.strFile("this is a test string", self.io)) - + self.assertEqual(True, text.strFile("this is a test string", self.io)) + def test_insensitive(self): - self.assertEquals(True, text.strFile("ThIs is A test STRING", self.io, False)) + self.assertEqual(True, text.strFile("ThIs is A test STRING", self.io, False)) @@ -165,9 +166,9 @@ """ text.docstringLStrip("") warningsShown = self.flushWarnings([self.test_docstringLStrip]) - self.assertEquals(1, len(warningsShown)) + self.assertEqual(1, len(warningsShown)) self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEquals(warningsShown[0]['message'], + self.assertEqual(warningsShown[0]['message'], "twisted.python.text.docstringLStrip was " "deprecated in Twisted 10.2.0: Please use " "inspect.getdoc instead.") diff --git a/lib/twisted-trunk/twisted/test/test_threadpool.py b/lib/twisted-trunk/twisted/test/test_threadpool.py --- a/lib/twisted-trunk/twisted/test/test_threadpool.py +++ b/lib/twisted-trunk/twisted/test/test_threadpool.py @@ -131,8 +131,8 @@ del worker del unique gc.collect() - self.assertEquals(uniqueRef(), None) - self.assertEquals(workerRef(), None) + self.assertEqual(uniqueRef(), None) + self.assertEqual(workerRef(), None) def test_threadCreationArgumentsCallInThreadWithCallback(self): @@ -191,8 +191,8 @@ # wait for onResult onResultDone.wait(self.getTimeout()) - self.assertEquals(uniqueRef(), None) - self.assertEquals(workerRef(), None) + self.assertEqual(uniqueRef(), None) + self.assertEqual(workerRef(), None) # XXX There's a race right here - has onResult in the worker thread # returned and the locals in _worker holding it and the result been @@ -211,14 +211,14 @@ """ pool = threadpool.ThreadPool(7, 20) - self.assertEquals(pool.min, 7) - self.assertEquals(pool.max, 20) + self.assertEqual(pool.min, 7) + self.assertEqual(pool.max, 20) # check that unpickled threadpool has same number of threads copy = pickle.loads(pickle.dumps(pool)) - self.assertEquals(copy.min, 7) - self.assertEquals(copy.max, 20) + self.assertEqual(copy.min, 7) + self.assertEqual(copy.max, 20) def _threadpoolTest(self, method): @@ -554,7 +554,7 @@ N threads will ever be created. """ # Ensure no threads running - self.assertEquals(self.threadpool.workers, 0) + self.assertEqual(self.threadpool.workers, 0) loopDeferred = Deferred() @@ -590,9 +590,9 @@ threadpool.ThreadSafeList() warningsShown = self.flushWarnings([self.test_threadSafeList]) - self.assertEquals(len(warningsShown), 1) + self.assertEqual(len(warningsShown), 1) self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual( warningsShown[0]['message'], "twisted.python.threadpool.ThreadSafeList was deprecated in " "Twisted 10.1.0: This was an internal implementation detail of " diff --git a/lib/twisted-trunk/twisted/test/test_threads.py b/lib/twisted-trunk/twisted/test/test_threads.py --- a/lib/twisted-trunk/twisted/test/test_threads.py +++ b/lib/twisted-trunk/twisted/test/test_threads.py @@ -25,9 +25,9 @@ Try to change maximum number of threads. """ reactor.suggestThreadPoolSize(34) - self.assertEquals(reactor.threadpool.max, 34) + self.assertEqual(reactor.threadpool.max, 34) reactor.suggestThreadPoolSize(4) - self.assertEquals(reactor.threadpool.max, 4) + self.assertEqual(reactor.threadpool.max, 4) def _waitForThread(self): @@ -56,7 +56,7 @@ if not waiter.isSet(): self.fail("Timed out waiting for event.") else: - self.assertEquals(result, [False]) + self.assertEqual(result, [False]) return self._waitForThread().addCallback(cb) @@ -142,7 +142,7 @@ def reactorFunc(): return defer.succeed("foo") def cb(res): - self.assertEquals(res[0][0], "foo") + self.assertEqual(res[0][0], "foo") return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) @@ -156,7 +156,7 @@ reactor.callLater(0.1, d.callback, "egg") return d def cb(res): - self.assertEquals(res[0][0], "egg") + self.assertEqual(res[0][0], "egg") return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) @@ -168,7 +168,7 @@ return defer.fail(RuntimeError("bar")) def cb(res): self.assert_(isinstance(res[1][0], RuntimeError)) - self.assertEquals(res[1][0].args[0], "bar") + self.assertEqual(res[1][0].args[0], "bar") return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) @@ -183,7 +183,7 @@ return d def cb(res): self.assert_(isinstance(res[1][0], RuntimeError)) - self.assertEquals(res[1][0].args[0], "spam") + self.assertEqual(res[1][0].args[0], "spam") return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) @@ -226,7 +226,7 @@ d = defer.Deferred() def finished(): - self.assertEquals(L, range(N)) + self.assertEqual(L, range(N)) d.callback(None) threads.callMultipleInThread([ @@ -241,7 +241,7 @@ handles the positional and keyword arguments given. """ d = threads.deferToThread(lambda x, y=5: x + y, 3, y=4) - d.addCallback(self.assertEquals, 7) + d.addCallback(self.assertEqual, 7) return d diff --git a/lib/twisted-trunk/twisted/test/test_timehelpers.py b/lib/twisted-trunk/twisted/test/test_timehelpers.py --- a/lib/twisted-trunk/twisted/test/test_timehelpers.py +++ b/lib/twisted-trunk/twisted/test/test_timehelpers.py @@ -24,8 +24,8 @@ import twisted.test.time_helpers warnings = self.flushWarnings( offendingFunctions=[self.test_deprecated]) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals( + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( warnings[0]['message'], "twisted.test.time_helpers is deprecated since Twisted 10.0. " "See twisted.internet.task.Clock instead.") diff --git a/lib/twisted-trunk/twisted/test/test_tpfile.py b/lib/twisted-trunk/twisted/test/test_tpfile.py --- a/lib/twisted-trunk/twisted/test/test_tpfile.py +++ b/lib/twisted-trunk/twisted/test/test_tpfile.py @@ -31,7 +31,7 @@ c = FileSendingClient(StringIO.StringIO(testStr)) d = loopback.loopbackTCP(s, c) - d.addCallback(lambda x : self.assertEquals(s.buffer, testStr)) + d.addCallback(lambda x : self.assertEqual(s.buffer, testStr)) return d def testSendingEmptyFile(self): diff --git a/lib/twisted-trunk/twisted/test/test_twistd.py b/lib/twisted-trunk/twisted/test/test_twistd.py --- a/lib/twisted-trunk/twisted/test/test_twistd.py +++ b/lib/twisted-trunk/twisted/test/test_twistd.py @@ -7,12 +7,18 @@ import signal, inspect, errno -import os, sys, cPickle, StringIO +import os, sys, StringIO + try: import pwd, grp except ImportError: pwd = grp = None +try: + import cPickle as pickle +except ImportError: + import pickle + from zope.interface import implements from zope.interface.verify import verifyObject @@ -168,7 +174,7 @@ config = twistd.ServerOptions() config.subCommand = 'ueoa' config.postOptions() - self.assertEquals(config['no_save'], True) + self.assertEqual(config['no_save'], True) def test_postOptionsNoSubCommandSavesAsUsual(self): @@ -177,7 +183,7 @@ """ config = twistd.ServerOptions() config.postOptions() - self.assertEquals(config['no_save'], False) + self.assertEqual(config['no_save'], False) def test_listAllProfilers(self): @@ -236,7 +242,7 @@ """ self.tapfile = self.mktemp() f = file(self.tapfile, 'wb') - cPickle.dump(service.Application("Hi!"), f) + pickle.dump(service.Application("Hi!"), f) f.close() @@ -248,7 +254,7 @@ config = twistd.ServerOptions() config.parseOptions(['-f', self.tapfile]) application = CrippledApplicationRunner(config).createOrGetApplication() - self.assertEquals(service.IService(application).name, 'Hi!') + self.assertEqual(service.IService(application).name, 'Hi!') @@ -344,7 +350,7 @@ self.assertFalse(s.hadApplicationPreApplication) self.assertTrue(s.hadApplicationPostApplication) self.assertTrue(s.hadApplicationLogObserver) - self.assertEquals(s.order, ["pre", "log", "post"]) + self.assertEqual(s.order, ["pre", "log", "post"]) def _applicationStartsWithConfiguredID(self, argv, uid, gid): @@ -683,8 +689,8 @@ runner = UnixApplicationRunner({}) runner.removePID("fakepid") errors = self.flushLoggedErrors(OSError) - self.assertEquals(len(errors), 1) - self.assertEquals(errors[0].value.errno, errno.ENOENT) + self.assertEqual(len(errors), 1) + self.assertEqual(errors[0].value.errno, errno.ENOENT) @@ -975,7 +981,7 @@ config["profiler"] = "foobar" error = self.assertRaises(SystemExit, app.AppProfiler, config) - self.assertEquals(str(error), "Unsupported profiler name: foobar") + self.assertEqual(str(error), "Unsupported profiler name: foobar") def test_defaultProfiler(self): @@ -983,7 +989,7 @@ L{app.Profiler} defaults to the hotshot profiler if not specified. """ profiler = app.AppProfiler({}) - self.assertEquals(profiler.profiler, "hotshot") + self.assertEqual(profiler.profiler, "hotshot") def test_profilerNameCaseInsentive(self): @@ -992,7 +998,7 @@ relevant. """ profiler = app.AppProfiler({"profiler": "HotShot"}) - self.assertEquals(profiler.profiler, "hotshot") + self.assertEqual(profiler.profiler, "hotshot") @@ -1052,7 +1058,7 @@ @param logs: The list whose C{append} method was specified as the initial log observer. """ - self.assertEquals(self.observers, [logs.append]) + self.assertEqual(self.observers, [logs.append]) self.assertIn("starting up", logs[0]["message"][0]) self.assertIn("reactor class", logs[1]["message"][0]) @@ -1093,13 +1099,13 @@ observer = logger._getLogObserver() - self.assertEquals(len(logFiles), 1) + self.assertEqual(len(logFiles), 1) self.assertIdentical(logFiles[0], sys.stdout) logger = app.AppLogger({"logfile": ""}) observer = logger._getLogObserver() - self.assertEquals(len(logFiles), 2) + self.assertEqual(len(logFiles), 2) self.assertIdentical(logFiles[1], sys.stdout) @@ -1114,8 +1120,8 @@ observer = logger._getLogObserver() - self.assertEquals(len(logFiles), 1) - self.assertEquals(logFiles[0].path, + self.assertEqual(len(logFiles), 1) + self.assertEqual(logFiles[0].path, os.path.abspath(filename)) @@ -1133,9 +1139,9 @@ logger = app.AppLogger({}) logger._observer = observer logger.stop() - self.assertEquals(removed, [observer]) + self.assertEqual(removed, [observer]) logger.stop() - self.assertEquals(removed, [observer]) + self.assertEqual(removed, [observer]) self.assertIdentical(logger._observer, None) @@ -1171,12 +1177,12 @@ logger = UnixAppLogger({"logfile": "-", "nodaemon": True}) observer = logger._getLogObserver() - self.assertEquals(len(logFiles), 1) + self.assertEqual(len(logFiles), 1) self.assertIdentical(logFiles[0], sys.stdout) logger = UnixAppLogger({"logfile": "", "nodaemon": True}) observer = logger._getLogObserver() - self.assertEquals(len(logFiles), 2) + self.assertEqual(len(logFiles), 2) self.assertIdentical(logFiles[1], sys.stdout) @@ -1187,7 +1193,7 @@ """ logger = UnixAppLogger({"logfile": "-", "nodaemon": False}) error = self.assertRaises(SystemExit, logger._getLogObserver) - self.assertEquals(str(error), "Daemons cannot log to stdout, exiting!") + self.assertEqual(str(error), "Daemons cannot log to stdout, exiting!") def test_getLogObserverFile(self): @@ -1201,12 +1207,12 @@ logger = UnixAppLogger({"logfile": filename}) observer = logger._getLogObserver() - self.assertEquals(len(logFiles), 1) - self.assertEquals(logFiles[0].path, + self.assertEqual(len(logFiles), 1) + self.assertEqual(logFiles[0].path, os.path.abspath(filename)) - self.assertEquals(len(self.signals), 1) - self.assertEquals(self.signals[0][0], signal.SIGUSR1) + self.assertEqual(len(self.signals), 1) + self.assertEqual(self.signals[0][0], signal.SIGUSR1) d = Deferred() def rotate(): @@ -1224,14 +1230,14 @@ L{UnixAppLogger._getLogObserver} doesn't override it. """ def fakeGetSignal(sig): - self.assertEquals(sig, signal.SIGUSR1) + self.assertEqual(sig, signal.SIGUSR1) return object() self.patch(signal, "getsignal", fakeGetSignal) filename = self.mktemp() logger = UnixAppLogger({"logfile": filename}) observer = logger._getLogObserver() - self.assertEquals(self.signals, []) + self.assertEqual(self.signals, []) def test_getLogObserverDefaultFile(self): @@ -1244,8 +1250,8 @@ logger = UnixAppLogger({"logfile": "", "nodaemon": False}) observer = logger._getLogObserver() - self.assertEquals(len(logFiles), 1) - self.assertEquals(logFiles[0].path, + self.assertEqual(len(logFiles), 1) + self.assertEqual(logFiles[0].path, os.path.abspath("twistd.log")) @@ -1262,7 +1268,7 @@ self.patch(syslog, "SyslogObserver", fakesyslogobserver) logger = UnixAppLogger({"syslog": True, "prefix": "test-prefix"}) observer = logger._getLogObserver() - self.assertEquals(fakesyslogobserver.prefix, "test-prefix") + self.assertEqual(fakesyslogobserver.prefix, "test-prefix") if syslog is None: test_getLogObserverSyslog.skip = "Syslog not available" @@ -1282,6 +1288,6 @@ log.addObserver(logs.append) self.addCleanup(log.removeObserver, logs.append) self.callDeprecated(Version("Twisted", 8, 2, 0), app.initialLog) - self.assertEquals(len(logs), 2) + self.assertEqual(len(logs), 2) self.assertIn("starting up", logs[0]["message"][0]) self.assertIn("reactor class", logs[1]["message"][0]) diff --git a/lib/twisted-trunk/twisted/test/test_udp.py b/lib/twisted-trunk/twisted/test/test_udp.py --- a/lib/twisted-trunk/twisted/test/test_udp.py +++ b/lib/twisted-trunk/twisted/test/test_udp.py @@ -123,7 +123,7 @@ p = reactor.listenUDP(0, server, interface="127.0.0.1") def cbStarted(ignored): addr = p.getHost() - self.assertEquals(addr.type, 'UDP') + self.assertEqual(addr.type, 'UDP') return p.stopListening() return d.addCallback(cbStarted) @@ -138,11 +138,11 @@ d = server.startedDeferred = defer.Deferred() port1 = reactor.listenUDP(0, server, interface="127.0.0.1") def cbStarted(ignored): - self.assertEquals(server.started, 1) - self.assertEquals(server.stopped, 0) + self.assertEqual(server.started, 1) + self.assertEqual(server.stopped, 0) return port1.stopListening() def cbStopped(ignored): - self.assertEquals(server.stopped, 1) + self.assertEqual(server.stopped, 1) return d.addCallback(cbStarted).addCallback(cbStopped) @@ -176,7 +176,7 @@ port = reactor.listenUDP(0, server, interface='127.0.0.1') def cbStarted(ignored): - self.assertEquals(port.getHost(), server.transport.getHost()) + self.assertEqual(port.getHost(), server.transport.getHost()) server2 = Server() self.assertRaises( error.CannotListenError, @@ -242,11 +242,11 @@ def cbSendsFinished(ignored): cAddr = client.transport.getHost() sAddr = server.transport.getHost() - self.assertEquals( + self.assertEqual( client.packets, [("hello", (sAddr.host, sAddr.port))]) clientAddr = (cAddr.host, cAddr.port) - self.assertEquals( + self.assertEqual( server.packets, [("a", clientAddr), ("b", clientAddr), @@ -339,7 +339,7 @@ sure they're actually there. """ errs = self.flushLoggedErrors(BadClientError) - self.assertEquals(len(errs), 2, "Incorrectly found %d errors, expected 2" % (len(errs),)) + self.assertEqual(len(errs), 2, "Incorrectly found %d errors, expected 2" % (len(errs),)) finalDeferred.addCallback(cbCompleted) client = BadClient() @@ -458,7 +458,7 @@ p.write("test", ("", 1234)) warnings = self.flushWarnings([self.test_NoWarningOnBroadcast]) - self.assertEquals(len(warnings), 0) + self.assertEqual(len(warnings), 0) @@ -531,9 +531,9 @@ def testTTL(self): for o in self.client, self.server: - self.assertEquals(o.transport.getTTL(), 1) + self.assertEqual(o.transport.getTTL(), 1) o.transport.setTTL(2) - self.assertEquals(o.transport.getTTL(), 2) + self.assertEqual(o.transport.getTTL(), 2) def test_loopback(self): @@ -541,7 +541,7 @@ Test that after loopback mode has been set, multicast packets are delivered to their sender. """ - self.assertEquals(self.server.transport.getLoopbackMode(), 1) + self.assertEqual(self.server.transport.getLoopbackMode(), 1) addr = self.server.transport.getHost() joined = self.server.transport.joinGroup("225.0.0.250") @@ -554,7 +554,7 @@ def cbPacket(ignored): self.assertEqual(len(self.server.packets), 1) self.server.transport.setLoopbackMode(0) - self.assertEquals(self.server.transport.getLoopbackMode(), 0) + self.assertEqual(self.server.transport.getLoopbackMode(), 0) self.server.transport.write("hello", ("225.0.0.250", addr.port)) # This is fairly lame. @@ -644,7 +644,7 @@ joined.addCallback(cbJoined) def cbPacket(ignored): - self.assertEquals(self.server.packets[0][0], "hello world") + self.assertEqual(self.server.packets[0][0], "hello world") joined.addCallback(cbPacket) def cleanup(passthrough): @@ -681,8 +681,8 @@ joined.addCallback(serverJoined) def gotPackets(ignored): - self.assertEquals(firstClient.packets[0][0], "hello world") - self.assertEquals(secondClient.packets[0][0], "hello world") + self.assertEqual(firstClient.packets[0][0], "hello world") + self.assertEqual(secondClient.packets[0][0], "hello world") joined.addCallback(gotPackets) def cleanup(passthrough): diff --git a/lib/twisted-trunk/twisted/test/test_unix.py b/lib/twisted-trunk/twisted/test/test_unix.py --- a/lib/twisted-trunk/twisted/test/test_unix.py +++ b/lib/twisted-trunk/twisted/test/test_unix.py @@ -311,9 +311,9 @@ cp.deferredGotBack]) def _cbTestExchange(ignored): - self.failUnlessEqual("hi", sp.gotwhat) - self.failUnlessEqual(clientaddr, sp.gotfrom) - self.failUnlessEqual("hi back", cp.gotback) + self.assertEqual("hi", sp.gotwhat) + self.assertEqual(clientaddr, sp.gotfrom) + self.assertEqual("hi back", cp.gotback) d.addCallback(write) d.addCallback(_cbTestExchange) diff --git a/lib/twisted-trunk/twisted/test/test_usage.py b/lib/twisted-trunk/twisted/test/test_usage.py --- a/lib/twisted-trunk/twisted/test/test_usage.py +++ b/lib/twisted-trunk/twisted/test/test_usage.py @@ -55,24 +55,24 @@ """ Checking that parameters have correct values. """ - self.failUnlessEqual(self.nice.opts['long'], "Alpha") - self.failUnlessEqual(self.nice.opts['another'], "Beta") - self.failUnlessEqual(self.nice.opts['longonly'], "noshort") - self.failUnlessEqual(self.nice.opts['shortless'], "Gamma") + self.assertEqual(self.nice.opts['long'], "Alpha") + self.assertEqual(self.nice.opts['another'], "Beta") + self.assertEqual(self.nice.opts['longonly'], "noshort") + self.assertEqual(self.nice.opts['shortless'], "Gamma") def test_checkFlags(self): """ Checking that flags have correct values. """ - self.failUnlessEqual(self.nice.opts['aflag'], 1) - self.failUnlessEqual(self.nice.opts['flout'], 0) + self.assertEqual(self.nice.opts['aflag'], 1) + self.assertEqual(self.nice.opts['flout'], 0) def test_checkCustoms(self): """ Checking that custom flags and parameters have correct values. """ - self.failUnlessEqual(self.nice.opts['myflag'], "PONY!") - self.failUnlessEqual(self.nice.opts['myparam'], "Tofu WITH A PONY!") + self.assertEqual(self.nice.opts['myflag'], "PONY!") + self.assertEqual(self.nice.opts['myparam'], "Tofu WITH A PONY!") @@ -107,12 +107,12 @@ """ argV = [] self.usage.parseOptions(argV) - self.failUnlessEqual(self.usage.opts['fooint'], 392) + self.assertEqual(self.usage.opts['fooint'], 392) self.assert_(isinstance(self.usage.opts['fooint'], int)) - self.failUnlessEqual(self.usage.opts['foofloat'], 4.23) + self.assertEqual(self.usage.opts['foofloat'], 4.23) self.assert_(isinstance(self.usage.opts['foofloat'], float)) - self.failUnlessEqual(self.usage.opts['eggint'], None) - self.failUnlessEqual(self.usage.opts['eggfloat'], None) + self.assertEqual(self.usage.opts['eggint'], None) + self.assertEqual(self.usage.opts['eggfloat'], None) def test_parsingValues(self): @@ -122,13 +122,13 @@ argV = ("--fooint 912 --foofloat -823.1 " "--eggint 32 --eggfloat 21").split() self.usage.parseOptions(argV) - self.failUnlessEqual(self.usage.opts['fooint'], 912) + self.assertEqual(self.usage.opts['fooint'], 912) self.assert_(isinstance(self.usage.opts['fooint'], int)) - self.failUnlessEqual(self.usage.opts['foofloat'], -823.1) + self.assertEqual(self.usage.opts['foofloat'], -823.1) self.assert_(isinstance(self.usage.opts['foofloat'], float)) - self.failUnlessEqual(self.usage.opts['eggint'], 32) + self.assertEqual(self.usage.opts['eggint'], 32) self.assert_(isinstance(self.usage.opts['eggint'], int)) - self.failUnlessEqual(self.usage.opts['eggfloat'], 21.) + self.assertEqual(self.usage.opts['eggfloat'], 21.) self.assert_(isinstance(self.usage.opts['eggfloat'], float)) @@ -138,7 +138,7 @@ dispatched to a handler. """ self.usage.parseOptions(['--under-score', 'foo']) - self.assertEquals(self.usage.underscoreValue, 'foo') + self.assertEqual(self.usage.underscoreValue, 'foo') def test_underscoreOptionAlias(self): @@ -146,7 +146,7 @@ An option name with a dash in it can have an alias. """ self.usage.parseOptions(['-u', 'bar']) - self.assertEquals(self.usage.underscoreValue, 'bar') + self.assertEqual(self.usage.underscoreValue, 'bar') def test_invalidValues(self): @@ -204,7 +204,7 @@ argV = "--foowrong blah".split() # ValueError is swallowed as UsageError e = self.assertRaises(usage.UsageError, us.parseOptions, argV) - self.assertEquals(str(e), "Parameter type enforcement failed: Yay") + self.assertEqual(str(e), "Parameter type enforcement failed: Yay") us = WeirdCallableOptions() argV = "--barwrong blah".split() @@ -220,7 +220,7 @@ opt = WellBehaved() e = self.assertRaises(usage.UsageError, opt.parseOptions, ['-Z']) - self.assertEquals(str(e), 'option -Z not recognized') + self.assertEqual(str(e), 'option -Z not recognized') class InquisitionOptions(usage.Options): @@ -258,55 +258,55 @@ def test_simpleSubcommand(self): o = SubCommandOptions() o.parseOptions(['--europian-swallow', 'inquisition']) - self.failUnlessEqual(o['europian-swallow'], True) - self.failUnlessEqual(o.subCommand, 'inquisition') + self.assertEqual(o['europian-swallow'], True) + self.assertEqual(o.subCommand, 'inquisition') self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.failUnlessEqual(o.subOptions['expect'], False) - self.failUnlessEqual(o.subOptions['torture-device'], 'comfy-chair') + self.assertEqual(o.subOptions['expect'], False) + self.assertEqual(o.subOptions['torture-device'], 'comfy-chair') def test_subcommandWithFlagsAndOptions(self): o = SubCommandOptions() o.parseOptions(['inquisition', '--expect', '--torture-device=feather']) - self.failUnlessEqual(o['europian-swallow'], False) - self.failUnlessEqual(o.subCommand, 'inquisition') + self.assertEqual(o['europian-swallow'], False) + self.assertEqual(o.subCommand, 'inquisition') self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.failUnlessEqual(o.subOptions['expect'], True) - self.failUnlessEqual(o.subOptions['torture-device'], 'feather') + self.assertEqual(o.subOptions['expect'], True) + self.assertEqual(o.subOptions['torture-device'], 'feather') def test_subcommandAliasWithFlagsAndOptions(self): o = SubCommandOptions() o.parseOptions(['inquest', '--expect', '--torture-device=feather']) - self.failUnlessEqual(o['europian-swallow'], False) - self.failUnlessEqual(o.subCommand, 'inquisition') + self.assertEqual(o['europian-swallow'], False) + self.assertEqual(o.subCommand, 'inquisition') self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.failUnlessEqual(o.subOptions['expect'], True) - self.failUnlessEqual(o.subOptions['torture-device'], 'feather') + self.assertEqual(o.subOptions['expect'], True) + self.assertEqual(o.subOptions['torture-device'], 'feather') def test_anotherSubcommandWithFlagsAndOptions(self): o = SubCommandOptions() o.parseOptions(['holyquest', '--for-grail']) - self.failUnlessEqual(o['europian-swallow'], False) - self.failUnlessEqual(o.subCommand, 'holyquest') + self.assertEqual(o['europian-swallow'], False) + self.assertEqual(o.subCommand, 'holyquest') self.failUnless(isinstance(o.subOptions, HolyQuestOptions)) - self.failUnlessEqual(o.subOptions['horseback'], False) - self.failUnlessEqual(o.subOptions['for-grail'], True) + self.assertEqual(o.subOptions['horseback'], False) + self.assertEqual(o.subOptions['for-grail'], True) def test_noSubcommand(self): o = SubCommandOptions() o.parseOptions(['--europian-swallow']) - self.failUnlessEqual(o['europian-swallow'], True) - self.failUnlessEqual(o.subCommand, None) + self.assertEqual(o['europian-swallow'], True) + self.assertEqual(o.subCommand, None) self.failIf(hasattr(o, 'subOptions')) def test_defaultSubcommand(self): o = SubCommandOptions() o.defaultSubCommand = 'inquest' o.parseOptions(['--europian-swallow']) - self.failUnlessEqual(o['europian-swallow'], True) - self.failUnlessEqual(o.subCommand, 'inquisition') + self.assertEqual(o['europian-swallow'], True) + self.assertEqual(o.subCommand, 'inquisition') self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.failUnlessEqual(o.subOptions['expect'], False) - self.failUnlessEqual(o.subOptions['torture-device'], 'comfy-chair') + self.assertEqual(o.subOptions['expect'], False) + self.assertEqual(o.subOptions['torture-device'], 'comfy-chair') def test_subCommandParseOptionsHasParent(self): class SubOpt(usage.Options): @@ -320,7 +320,7 @@ o = Opt() o.parseOptions(['foo']) self.failUnless(hasattr(o.subOptions, 'sawParent')) - self.failUnlessEqual(o.subOptions.sawParent , o) + self.assertEqual(o.subOptions.sawParent , o) def test_subCommandInTwoPlaces(self): """ @@ -387,9 +387,9 @@ """ Test the answers with valid input. """ - self.assertEquals(0, usage.portCoerce("0")) - self.assertEquals(3210, usage.portCoerce("3210")) - self.assertEquals(65535, usage.portCoerce("65535")) + self.assertEqual(0, usage.portCoerce("0")) + self.assertEqual(3210, usage.portCoerce("3210")) + self.assertEqual(65535, usage.portCoerce("65535")) def test_errorCoerce(self): """ diff --git a/lib/twisted-trunk/twisted/test/test_zshcomp.py b/lib/twisted-trunk/twisted/test/test_zshcomp.py --- a/lib/twisted-trunk/twisted/test/test_zshcomp.py +++ b/lib/twisted-trunk/twisted/test/test_zshcomp.py @@ -45,13 +45,13 @@ actionDescr = TestOptions.zsh_actionDescr.copy() actionDescr.update(TestOptions2.zsh_actionDescr) - self.failUnlessEquals(ag.altArgDescr, altArgDescr) - self.failUnlessEquals(ag.actionDescr, actionDescr) - self.failUnlessEquals(ag.multiUse, TestOptions.zsh_multiUse) - self.failUnlessEquals(ag.mutuallyExclusive, + self.assertEqual(ag.altArgDescr, altArgDescr) + self.assertEqual(ag.actionDescr, actionDescr) + self.assertEqual(ag.multiUse, TestOptions.zsh_multiUse) + self.assertEqual(ag.mutuallyExclusive, TestOptions.zsh_mutuallyExclusive) - self.failUnlessEquals(ag.actions, TestOptions.zsh_actions) - self.failUnlessEquals(ag.extras, TestOptions.zsh_extras) + self.assertEqual(ag.actions, TestOptions.zsh_actions) + self.assertEqual(ag.extras, TestOptions.zsh_extras) def test_accumulateAdditionalOptions(self): """ @@ -90,7 +90,7 @@ b = zshcomp.Builder(cmd_name, opts, f) b.write() f.reset() - self.failUnlessEquals(f.read(), testOutput1) + self.assertEqual(f.read(), testOutput1) def test_skipBuild(self): """ @@ -100,9 +100,9 @@ generateFor = [('test_cmd', 'no.way.your.gonna.import.this', 'Foo')] skips = zshcomp.makeCompFunctionFiles('out_dir', generateFor, {}) # no exceptions should be raised. hooray. - self.failUnlessEqual(len(skips), 1) - self.failUnlessEqual(len(skips[0]), 2) - self.failUnlessEqual(skips[0][0], 'test_cmd') + self.assertEqual(len(skips), 1) + self.assertEqual(len(skips[0]), 2) + self.assertEqual(skips[0][0], 'test_cmd') self.failUnless(isinstance(skips[0][1], ImportError)) self.flushLoggedErrors(self, ImportError) diff --git a/lib/twisted-trunk/twisted/trial/runner.py b/lib/twisted-trunk/twisted/trial/runner.py --- a/lib/twisted-trunk/twisted/trial/runner.py +++ b/lib/twisted-trunk/twisted/trial/runner.py @@ -11,8 +11,8 @@ __all__ = [ 'suiteVisit', 'TestSuite', - 'DestructiveTestSuite', 'DocTestCase', 'DocTestSuite', - 'DryRunVisitor', 'ErrorHolder', 'LoggedSuite', 'PyUnitTestCase', + 'DestructiveTestSuite', 'DocTestCase', 'DryRunVisitor', + 'ErrorHolder', 'LoggedSuite', 'PyUnitTestCase', 'TestHolder', 'TestLoader', 'TrialRunner', 'TrialSuite', 'filenameToModule', 'isPackage', 'isPackageDirectory', 'isTestCase', @@ -184,25 +184,6 @@ -class DocTestSuite(TestSuite): - """ - DEPRECATED in Twisted 8.0. - - Behaves like doctest.DocTestSuite, but decorates individual TestCases so - they support visit and so that id() behaviour is meaningful and consistent - between Python versions. - """ - - def __init__(self, testModule): - warnings.warn("DocTestSuite is deprecated in Twisted 8.0.", - category=DeprecationWarning, stacklevel=2) - TestSuite.__init__(self) - suite = doctest.DocTestSuite(testModule) - for test in suite._tests: #yay encapsulation - self.addTest(ITestCase(test)) - - - class PyUnitTestCase(object): """ DEPRECATED in Twisted 8.0. @@ -308,7 +289,7 @@ def name(thing): """ @param thing: an object from modules (instance of PythonModule, - PythonAttribute), a TestCase subclass, or an instance of a TestCase. + PythonAttribute), a TestCase subclass, or an instance of a TestCase. """ if isTestCase(thing): # TestCase subclass @@ -326,8 +307,8 @@ def isTestCase(obj): """ - Returns C{True} if C{obj} is a class that contains test cases, C{False} - otherwise. Used to find all the tests in a module. + @return: C{True} if C{obj} is a class that contains test cases, C{False} + otherwise. Used to find all the tests in a module. """ try: return issubclass(obj, pyunit.TestCase) @@ -395,7 +376,7 @@ @param description: A string used by C{TestResult}s to identify this error. Generally, this is the name of a module that failed to import. - @param error: The error to be added to the result. Can be an exc_info + @param error: The error to be added to the result. Can be an `exc_info` tuple or a L{twisted.python.failure.Failure}. """ super(ErrorHolder, self).__init__(description) diff --git a/lib/twisted-trunk/twisted/trial/test/test_assertions.py b/lib/twisted-trunk/twisted/trial/test/test_assertions.py --- a/lib/twisted-trunk/twisted/trial/test/test_assertions.py +++ b/lib/twisted-trunk/twisted/trial/test/test_assertions.py @@ -32,6 +32,9 @@ Tests for TestCase's assertion methods. That is, failUnless*, failIf*, assert*. + Note: As of 11.2, assertEqual is preferred over the failUnlessEqual(s) + variants. Tests have been modified to reflect this preference. + This is pretty paranoid. Still, a certain paranoia is healthy if you are testing a unit testing framework. """ @@ -55,8 +58,8 @@ result = reporter.TestResult() test.run(result) self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.errors, []) - self.failUnlessEqual(len(result.failures), 1) + self.assertEqual(result.errors, []) + self.assertEqual(len(result.failures), 1) def test_failIf(self): for notTrue in [0, 0.0, False, None, (), []]: @@ -65,7 +68,7 @@ try: self.failIf(true, "failed on %r" % (true,)) except self.failureException, e: - self.failUnlessEqual(str(e), "failed on %r" % (true,)) + self.assertEqual(str(e), "failed on %r" % (true,)) else: self.fail("Call to failIf(%r) didn't fail" % (true,)) @@ -74,36 +77,40 @@ try: self.failUnless(notTrue, "failed on %r" % (notTrue,)) except self.failureException, e: - self.failUnlessEqual(str(e), "failed on %r" % (notTrue,)) + self.assertEqual(str(e), "failed on %r" % (notTrue,)) else: self.fail("Call to failUnless(%r) didn't fail" % (notTrue,)) for true in [1, True, 'cat', [1,2], (3,4)]: self.failUnless(true, "failed on %r" % (true,)) + def _testEqualPair(self, first, second): - x = self.failUnlessEqual(first, second) + x = self.assertEqual(first, second) if x != first: - self.fail("failUnlessEqual should return first parameter") + self.fail("assertEqual should return first parameter") + def _testUnequalPair(self, first, second): try: - self.failUnlessEqual(first, second) + self.assertEqual(first, second) except self.failureException, e: expected = 'not equal:\na = %s\nb = %s\n' % ( pformat(first), pformat(second)) if str(e) != expected: self.fail("Expected: %r; Got: %s" % (expected, str(e))) else: - self.fail("Call to failUnlessEqual(%r, %r) didn't fail" + self.fail("Call to assertEqual(%r, %r) didn't fail" % (first, second)) - def test_failUnlessEqual_basic(self): + + def test_assertEqual_basic(self): self._testEqualPair('cat', 'cat') self._testUnequalPair('cat', 'dog') self._testEqualPair([1], [1]) self._testUnequalPair([1], 'orange') - def test_failUnlessEqual_custom(self): + + def test_assertEqual_custom(self): x = MockEquality('first') y = MockEquality('second') z = MockEquality('fecund') @@ -112,7 +119,8 @@ self._testUnequalPair(x, y) self._testUnequalPair(y, z) - def test_failUnlessEqualMessage(self): + + def test_assertEqualMessage(self): """ When a message is passed to L{assertEqual}, it is included in the error message. @@ -125,7 +133,7 @@ "message\nnot equal:\na = 'foo'\nb = 'bar'\n") - def test_failUnlessEqualNoneMessage(self): + def test_assertEqualNoneMessage(self): """ If a message is specified as C{None}, it is not included in the error message of L{assertEqual}. @@ -135,11 +143,11 @@ self.assertEqual(str(exception), "not equal:\na = 'foo'\nb = 'bar'\n") - def test_failUnlessEqual_incomparable(self): + def test_assertEqual_incomparable(self): apple = MockEquality('apple') orange = ['orange'] try: - self.failUnlessEqual(apple, orange) + self.assertEqual(apple, orange) except self.failureException: self.fail("Fail raised when ValueError ought to have been raised.") except ValueError: @@ -149,6 +157,7 @@ self.fail("Comparing %r and %r should have raised an exception" % (apple, orange)) + def _raiseError(self, error): raise error @@ -174,7 +183,7 @@ try: self.failUnlessRaises(ValueError, lambda : None) except self.failureException, e: - self.failUnlessEqual(str(e), + self.assertEqual(str(e), 'ValueError not raised (None returned)') else: self.fail("Exception not raised. Should have failed") @@ -197,7 +206,7 @@ def test_failIfEqual_basic(self): x, y, z = [1], [2], [1] ret = self.failIfEqual(x, y) - self.failUnlessEqual(ret, x, + self.assertEqual(ret, x, "failIfEqual should return first parameter") self.failUnlessRaises(self.failureException, self.failIfEqual, x, x) @@ -209,7 +218,7 @@ y = MockEquality('second') z = MockEquality('fecund') ret = self.failIfEqual(x, y) - self.failUnlessEqual(ret, x, + self.assertEqual(ret, x, "failIfEqual should return first parameter") self.failUnlessRaises(self.failureException, self.failIfEqual, x, x) @@ -219,7 +228,7 @@ def test_failUnlessIdentical(self): x, y, z = [1], [1], [2] ret = self.failUnlessIdentical(x, x) - self.failUnlessEqual(ret, x, + self.assertEqual(ret, x, 'failUnlessIdentical should return first ' 'parameter') self.failUnlessRaises(self.failureException, @@ -231,7 +240,7 @@ x, y, z = 1.0, 1.1, 1.2 self.failUnlessApproximates(x, x, 0.2) ret = self.failUnlessApproximates(x, y, 0.2) - self.failUnlessEqual(ret, x, "failUnlessApproximates should return " + self.assertEqual(ret, x, "failUnlessApproximates should return " "first parameter") self.failUnlessRaises(self.failureException, self.failUnlessApproximates, x, z, 0.1) @@ -245,7 +254,7 @@ z = 8.000002 self.failUnlessAlmostEqual(x, x, precision) ret = self.failUnlessAlmostEqual(x, z, precision) - self.failUnlessEqual(ret, x, "failUnlessAlmostEqual should return " + self.assertEqual(ret, x, "failUnlessAlmostEqual should return " "first parameter (%r, %r)" % (ret, x)) self.failUnlessRaises(self.failureException, self.failUnlessAlmostEqual, x, y, precision) @@ -256,7 +265,7 @@ y = 8.00001 z = 8.000002 ret = self.failIfAlmostEqual(x, y, precision) - self.failUnlessEqual(ret, x, "failIfAlmostEqual should return " + self.assertEqual(ret, x, "failIfAlmostEqual should return " "first parameter (%r, %r)" % (ret, x)) self.failUnlessRaises(self.failureException, self.failIfAlmostEqual, x, x, precision) @@ -269,7 +278,7 @@ z = "the cat sat" self.failUnlessSubstring(x, x) ret = self.failUnlessSubstring(x, z) - self.failUnlessEqual(ret, x, 'should return first parameter') + self.assertEqual(ret, x, 'should return first parameter') self.failUnlessRaises(self.failureException, self.failUnlessSubstring, x, y) self.failUnlessRaises(self.failureException, @@ -281,7 +290,7 @@ z = "the cat sat" self.failIfSubstring(z, x) ret = self.failIfSubstring(x, y) - self.failUnlessEqual(ret, x, 'should return first parameter') + self.assertEqual(ret, x, 'should return first parameter') self.failUnlessRaises(self.failureException, self.failIfSubstring, x, x) self.failUnlessRaises(self.failureException, @@ -355,7 +364,7 @@ return a r = self.assertWarns(DeprecationWarning, "Woo deprecated", __file__, deprecated, 123) - self.assertEquals(r, 123) + self.assertEqual(r, 123) def test_assertWarnsRegistryClean(self): @@ -368,11 +377,11 @@ return a r1 = self.assertWarns(DeprecationWarning, "Woo deprecated", __file__, deprecated, 123) - self.assertEquals(r1, 123) + self.assertEqual(r1, 123) # The warning should be raised again r2 = self.assertWarns(DeprecationWarning, "Woo deprecated", __file__, deprecated, 321) - self.assertEquals(r2, 321) + self.assertEqual(r2, 321) def test_assertWarnsError(self): @@ -461,10 +470,10 @@ w = Warn() r = self.assertWarns(DeprecationWarning, "Bar deprecated", __file__, w.deprecated, 321) - self.assertEquals(r, 321) + self.assertEqual(r, 321) r = self.assertWarns(DeprecationWarning, "Bar deprecated", __file__, w.deprecated, 321) - self.assertEquals(r, 321) + self.assertEqual(r, 321) def test_assertWarnsOnCall(self): @@ -478,10 +487,10 @@ w = Warn() r = self.assertWarns(DeprecationWarning, "Egg deprecated", __file__, w, 321) - self.assertEquals(r, 321) + self.assertEqual(r, 321) r = self.assertWarns(DeprecationWarning, "Egg deprecated", __file__, w, 321) - self.assertEquals(r, 321) + self.assertEqual(r, 321) def test_assertWarnsFilter(self): @@ -493,7 +502,7 @@ return a r = self.assertWarns(PendingDeprecationWarning, "Woo deprecated", __file__, deprecated, 123) - self.assertEquals(r, 123) + self.assertEqual(r, 123) def test_assertWarnsMultipleWarnings(self): @@ -521,7 +530,7 @@ e = self.assertRaises(self.failureException, self.assertWarns, DeprecationWarning, "Woo deprecated", __file__, deprecated, 123) - self.assertEquals(str(e), "Can't handle different warnings") + self.assertEqual(str(e), "Can't handle different warnings") def test_assertWarnsAfterUnassertedWarning(self): @@ -603,7 +612,7 @@ a = A() error = self.assertRaises(self.failureException, self.assertNotIsInstance, a, A) - self.assertEquals(str(error), "%r is an instance of %s" % (a, A)) + self.assertEqual(str(error), "%r is an instance of %s" % (a, A)) def test_assertNotIsInstanceErrorMultipleClasses(self): """ @@ -640,14 +649,14 @@ """ asserts = set(self._getAsserts()) failUnlesses = set(reflect.prefixedMethods(self, 'failUnless')) - self.assertEquals( + self.assertEqual( failUnlesses, asserts.intersection(failUnlesses)) def test_failIf_matches_assertNot(self): asserts = reflect.prefixedMethods(unittest.TestCase, 'assertNot') failIfs = reflect.prefixedMethods(unittest.TestCase, 'failIf') - self.failUnlessEqual(sorted(asserts, key=self._name), + self.assertEqual(sorted(asserts, key=self._name), sorted(failIfs, key=self._name)) def test_equalSpelling(self): @@ -657,11 +666,11 @@ if name.endswith('Equal'): self.failUnless(hasattr(self, name+'s'), "%s but no %ss" % (name, name)) - self.failUnlessEqual(value, getattr(self, name+'s')) + self.assertEqual(value, getattr(self, name+'s')) if name.endswith('Equals'): self.failUnless(hasattr(self, name[:-1]), "%s but no %s" % (name, name[:-1])) - self.failUnlessEqual(value, getattr(self, name[:-1])) + self.assertEqual(value, getattr(self, name[:-1])) class TestCallDeprecated(unittest.TestCase): diff --git a/lib/twisted-trunk/twisted/trial/test/test_deferred.py b/lib/twisted-trunk/twisted/trial/test/test_deferred.py --- a/lib/twisted-trunk/twisted/trial/test/test_deferred.py +++ b/lib/twisted-trunk/twisted/trial/test/test_deferred.py @@ -15,16 +15,16 @@ result, suite = self._loadSuite(detests.DeferredSetUpOK) suite(result) self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) def test_fail(self): self.failIf(detests.DeferredSetUpFail.testCalled) result, suite = self._loadSuite(detests.DeferredSetUpFail) suite(result) self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.failures), 0) - self.failUnlessEqual(len(result.errors), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.failures), 0) + self.assertEqual(len(result.errors), 1) self.failIf(detests.DeferredSetUpFail.testCalled) def test_callbackFail(self): @@ -32,9 +32,9 @@ result, suite = self._loadSuite(detests.DeferredSetUpCallbackFail) suite(result) self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.failures), 0) - self.failUnlessEqual(len(result.errors), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.failures), 0) + self.assertEqual(len(result.errors), 1) self.failIf(detests.DeferredSetUpCallbackFail.testCalled) def test_error(self): @@ -42,9 +42,9 @@ result, suite = self._loadSuite(detests.DeferredSetUpError) suite(result) self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.failures), 0) - self.failUnlessEqual(len(result.errors), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.failures), 0) + self.assertEqual(len(result.errors), 1) self.failIf(detests.DeferredSetUpError.testCalled) def test_skip(self): @@ -52,10 +52,10 @@ result, suite = self._loadSuite(detests.DeferredSetUpSkip) suite(result) self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.failures), 0) - self.failUnlessEqual(len(result.errors), 0) - self.failUnlessEqual(len(result.skips), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.failures), 0) + self.assertEqual(len(result.errors), 0) + self.assertEqual(len(result.skips), 1) self.failIf(detests.DeferredSetUpSkip.testCalled) @@ -78,9 +78,9 @@ result, suite = self._loadSuite(detests.DeferredSetUpNeverFire) suite(result) self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.failures), 0) - self.failUnlessEqual(len(result.errors), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.failures), 0) + self.assertEqual(len(result.errors), 1) self.failIf(detests.DeferredSetUpNeverFire.testCalled) self.failUnless(result.errors[0][1].check(defer.TimeoutError)) @@ -102,50 +102,50 @@ def test_pass(self): result = self.runTest('test_pass') self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) def test_passGenerated(self): result = self.runTest('test_passGenerated') self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) self.failUnless(detests.DeferredTests.touched) def test_fail(self): result = self.runTest('test_fail') self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.failures), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.failures), 1) def test_failureInCallback(self): result = self.runTest('test_failureInCallback') self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.failures), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.failures), 1) def test_errorInCallback(self): result = self.runTest('test_errorInCallback') self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.errors), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.errors), 1) def test_skip(self): result = self.runTest('test_skip') self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.skips), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.skips), 1) self.failIf(detests.DeferredTests.touched) def test_todo(self): result = self.runTest('test_expectedFailure') self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.errors), 0) - self.failUnlessEqual(len(result.failures), 0) - self.failUnlessEqual(len(result.expectedFailures), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.errors), 0) + self.assertEqual(len(result.failures), 0) + self.assertEqual(len(result.expectedFailures), 1) def test_thread(self): result = self.runTest('test_thread') - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) self.failUnless(result.wasSuccessful(), result.errors) @@ -154,50 +154,50 @@ return detests.TimeoutTests(name) def _wasTimeout(self, error): - self.failUnlessEqual(error.check(defer.TimeoutError), + self.assertEqual(error.check(defer.TimeoutError), defer.TimeoutError) def test_pass(self): result = self.runTest('test_pass') self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) def test_passDefault(self): result = self.runTest('test_passDefault') self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) def test_timeout(self): result = self.runTest('test_timeout') self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.errors), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.errors), 1) self._wasTimeout(result.errors[0][1]) def test_timeoutZero(self): result = self.runTest('test_timeoutZero') self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.errors), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.errors), 1) self._wasTimeout(result.errors[0][1]) def test_skip(self): result = self.runTest('test_skip') self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.skips), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.skips), 1) def test_todo(self): result = self.runTest('test_expectedFailure') self.failUnless(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.expectedFailures), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.expectedFailures), 1) self._wasTimeout(result.expectedFailures[0][1]) def test_errorPropagation(self): result = self.runTest('test_errorPropagation') self.failIf(result.wasSuccessful()) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) self._wasTimeout(detests.TimeoutTests.timedOut) def test_classTimeout(self): @@ -205,7 +205,7 @@ suite = loader.loadClass(detests.TestClassTimeoutAttribute) result = reporter.TestResult() suite.run(result) - self.failUnlessEqual(len(result.errors), 1) + self.assertEqual(len(result.errors), 1) self._wasTimeout(result.errors[0][1]) def test_callbackReturnsNonCallingDeferred(self): diff --git a/lib/twisted-trunk/twisted/trial/test/test_doctest.py b/lib/twisted-trunk/twisted/trial/test/test_doctest.py --- a/lib/twisted-trunk/twisted/trial/test/test_doctest.py +++ b/lib/twisted-trunk/twisted/trial/test/test_doctest.py @@ -2,7 +2,7 @@ # See LICENSE for details. """ -Test twisted's doctest support. +Test Twisted's doctest support. """ from twisted.trial import itrial, runner, unittest, reporter @@ -27,23 +27,6 @@ self.assertIn(idPrefix, itrial.ITestCase(test).id()) - def makeDocSuite(self, module): - """ - Return a L{runner.DocTestSuite} for the doctests in C{module}. - """ - return self.assertWarns( - DeprecationWarning, "DocTestSuite is deprecated in Twisted 8.0.", - __file__, lambda: runner.DocTestSuite(mockdoctest)) - - - def test_correctCount(self): - """ - L{countTestCases} returns the number of doctests in the module. - """ - suite = self.makeDocSuite(mockdoctest) - self.assertEqual(7, suite.countTestCases()) - - def test_basicTrialIntegration(self): """ L{loadDoctests} loads all of the doctests in the given module. diff --git a/lib/twisted-trunk/twisted/trial/test/test_keyboard.py b/lib/twisted-trunk/twisted/trial/test/test_keyboard.py --- a/lib/twisted-trunk/twisted/trial/test/test_keyboard.py +++ b/lib/twisted-trunk/twisted/trial/test/test_keyboard.py @@ -27,14 +27,14 @@ TestInterruptInTest.test_03_doNothing_run = None def test_setUpOK(self): - self.failUnlessEqual(3, self.suite.countTestCases()) - self.failUnlessEqual(0, self.reporter.testsRun) + self.assertEqual(3, self.suite.countTestCases()) + self.assertEqual(0, self.reporter.testsRun) self.failIf(self.reporter.shouldStop) def test_interruptInTest(self): runner.TrialSuite([self.suite]).run(self.reporter) self.failUnless(self.reporter.shouldStop) - self.failUnlessEqual(2, self.reporter.testsRun) + self.assertEqual(2, self.reporter.testsRun) self.failIf(TestInterruptInTest.test_03_doNothing_run, "test_03_doNothing ran.") @@ -62,15 +62,15 @@ TestInterruptInSetUp.testsRun = 0 def test_setUpOK(self): - self.failUnlessEqual(0, TestInterruptInSetUp.testsRun) - self.failUnlessEqual(2, self.suite.countTestCases()) - self.failUnlessEqual(0, self.reporter.testsRun) + self.assertEqual(0, TestInterruptInSetUp.testsRun) + self.assertEqual(2, self.suite.countTestCases()) + self.assertEqual(0, self.reporter.testsRun) self.failIf(self.reporter.shouldStop) def test_interruptInSetUp(self): runner.TrialSuite([self.suite]).run(self.reporter) self.failUnless(self.reporter.shouldStop) - self.failUnlessEqual(2, self.reporter.testsRun) + self.assertEqual(2, self.reporter.testsRun) self.failIf(TestInterruptInSetUp.test_02_run, "test_02 ran") @@ -98,14 +98,14 @@ TestInterruptInTearDown.test_02_run = False def test_setUpOK(self): - self.failUnlessEqual(0, TestInterruptInTearDown.testsRun) - self.failUnlessEqual(2, self.suite.countTestCases()) - self.failUnlessEqual(0, self.reporter.testsRun) + self.assertEqual(0, TestInterruptInTearDown.testsRun) + self.assertEqual(2, self.suite.countTestCases()) + self.assertEqual(0, self.reporter.testsRun) self.failIf(self.reporter.shouldStop) def test_interruptInTearDown(self): runner.TrialSuite([self.suite]).run(self.reporter) - self.failUnlessEqual(1, self.reporter.testsRun) + self.assertEqual(1, self.reporter.testsRun) self.failUnless(self.reporter.shouldStop) self.failIf(TestInterruptInTearDown.test_02_run, "test_02 ran") diff --git a/lib/twisted-trunk/twisted/trial/test/test_loader.py b/lib/twisted-trunk/twisted/trial/test/test_loader.py --- a/lib/twisted-trunk/twisted/trial/test/test_loader.py +++ b/lib/twisted-trunk/twisted/trial/test/test_loader.py @@ -41,23 +41,23 @@ def test_findPackage(self): sample1 = self.loader.findByName('twisted') import twisted as sample2 - self.failUnlessEqual(sample1, sample2) + self.assertEqual(sample1, sample2) def test_findModule(self): sample1 = self.loader.findByName('twisted.trial.test.sample') import sample as sample2 - self.failUnlessEqual(sample1, sample2) + self.assertEqual(sample1, sample2) def test_findFile(self): path = util.sibpath(__file__, 'sample.py') sample1 = self.loader.findByName(path) import sample as sample2 - self.failUnlessEqual(sample1, sample2) + self.assertEqual(sample1, sample2) def test_findObject(self): sample1 = self.loader.findByName('twisted.trial.test.sample.FooTest') import sample - self.failUnlessEqual(sample.FooTest, sample1) + self.assertEqual(sample.FooTest, sample1) def test_findNonModule(self): self.failUnlessRaises(AttributeError, @@ -86,7 +86,7 @@ def test_moduleInPath(self): sample1 = runner.filenameToModule(util.sibpath(__file__, 'sample.py')) import sample as sample2 - self.failUnlessEqual(sample2, sample1) + self.assertEqual(sample2, sample1) def test_moduleNotInPath(self): @@ -108,7 +108,7 @@ os.path.join(self.parent, 'goodpackage', 'test_sample.py')) self.mangleSysPath(self.newPath) from goodpackage import test_sample as sample2 - self.failUnlessEqual(os.path.splitext(sample2.__file__)[0], + self.assertEqual(os.path.splitext(sample2.__file__)[0], os.path.splitext(sample1.__file__)[0]) @@ -116,7 +116,7 @@ package1 = runner.filenameToModule(os.path.join(self.parent, 'goodpackage')) import goodpackage - self.failUnlessEqual(goodpackage, package1) + self.assertEqual(goodpackage, package1) def test_packageNotInPath(self): @@ -138,7 +138,7 @@ os.path.join(self.parent, 'goodpackage')) self.mangleSysPath(self.newPath) import goodpackage - self.failUnlessEqual(os.path.splitext(goodpackage.__file__)[0], + self.assertEqual(os.path.splitext(goodpackage.__file__)[0], os.path.splitext(package1.__file__)[0]) @@ -157,7 +157,7 @@ fd.close() try: module = runner.filenameToModule(filename) - self.failUnlessEqual(filename, module.__file__) + self.assertEqual(filename, module.__file__) finally: os.remove(filename) @@ -193,21 +193,21 @@ def test_sortCases(self): import sample suite = self.loader.loadClass(sample.AlphabetTest) - self.failUnlessEqual(['test_a', 'test_b', 'test_c'], + self.assertEqual(['test_a', 'test_b', 'test_c'], [test._testMethodName for test in suite._tests]) newOrder = ['test_b', 'test_c', 'test_a'] sortDict = dict(zip(newOrder, range(3))) self.loader.sorter = lambda x : sortDict.get(x.shortDescription(), -1) suite = self.loader.loadClass(sample.AlphabetTest) - self.failUnlessEqual(newOrder, + self.assertEqual(newOrder, [test._testMethodName for test in suite._tests]) def test_loadMethod(self): import sample suite = self.loader.loadMethod(sample.FooTest.test_foo) - self.failUnlessEqual(1, suite.countTestCases()) - self.failUnlessEqual('test_foo', suite._testMethodName) + self.assertEqual(1, suite.countTestCases()) + self.assertEqual('test_foo', suite._testMethodName) def test_loadFailingMethod(self): @@ -216,8 +216,8 @@ suite = self.loader.loadMethod(erroneous.TestRegularFail.test_fail) result = reporter.TestResult() suite.run(result) - self.failUnlessEqual(result.testsRun, 1) - self.failUnlessEqual(len(result.failures), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(result.failures), 1) def test_loadNonMethod(self): @@ -238,8 +238,8 @@ """ import sample suite = self.loader.loadMethod(sample.DecorationTest.test_badDecorator) - self.assertEquals(1, suite.countTestCases()) - self.assertEquals('test_badDecorator', suite._testMethodName) + self.assertEqual(1, suite.countTestCases()) + self.assertEqual('test_badDecorator', suite._testMethodName) def test_loadGoodDecorator(self): @@ -250,8 +250,8 @@ import sample suite = self.loader.loadMethod( sample.DecorationTest.test_goodDecorator) - self.assertEquals(1, suite.countTestCases()) - self.assertEquals('test_goodDecorator', suite._testMethodName) + self.assertEqual(1, suite.countTestCases()) + self.assertEqual('test_goodDecorator', suite._testMethodName) def test_loadRenamedDecorator(self): @@ -263,15 +263,15 @@ import sample suite = self.loader.loadMethod( sample.DecorationTest.test_renamedDecorator) - self.assertEquals(1, suite.countTestCases()) - self.assertEquals('test_renamedDecorator', suite._testMethodName) + self.assertEqual(1, suite.countTestCases()) + self.assertEqual('test_renamedDecorator', suite._testMethodName) def test_loadClass(self): import sample suite = self.loader.loadClass(sample.FooTest) - self.failUnlessEqual(2, suite.countTestCases()) - self.failUnlessEqual(['test_bar', 'test_foo'], + self.assertEqual(2, suite.countTestCases()) + self.assertEqual(['test_bar', 'test_foo'], [test._testMethodName for test in suite._tests]) @@ -311,7 +311,7 @@ def test_loadPackage(self): import goodpackage suite = self.loader.loadPackage(goodpackage) - self.failUnlessEqual(7, suite.countTestCases()) + self.assertEqual(7, suite.countTestCases()) def test_loadNonPackage(self): @@ -334,40 +334,40 @@ def test_loadPackageRecursive(self): import goodpackage suite = self.loader.loadPackage(goodpackage, recurse=True) - self.failUnlessEqual(14, suite.countTestCases()) + self.assertEqual(14, suite.countTestCases()) def test_loadAnythingOnModule(self): import sample suite = self.loader.loadAnything(sample) - self.failUnlessEqual(sample.__name__, + self.assertEqual(sample.__name__, suite._tests[0]._tests[0].__class__.__module__) def test_loadAnythingOnClass(self): import sample suite = self.loader.loadAnything(sample.FooTest) - self.failUnlessEqual(2, suite.countTestCases()) + self.assertEqual(2, suite.countTestCases()) def test_loadAnythingOnMethod(self): import sample suite = self.loader.loadAnything(sample.FooTest.test_foo) - self.failUnlessEqual(1, suite.countTestCases()) + self.assertEqual(1, suite.countTestCases()) def test_loadAnythingOnPackage(self): import goodpackage suite = self.loader.loadAnything(goodpackage) self.failUnless(isinstance(suite, self.loader.suiteFactory)) - self.failUnlessEqual(7, suite.countTestCases()) + self.assertEqual(7, suite.countTestCases()) def test_loadAnythingOnPackageRecursive(self): import goodpackage suite = self.loader.loadAnything(goodpackage, recurse=True) self.failUnless(isinstance(suite, self.loader.suiteFactory)) - self.failUnlessEqual(14, suite.countTestCases()) + self.assertEqual(14, suite.countTestCases()) def test_loadAnythingOnString(self): @@ -382,11 +382,11 @@ suite = self.loader.loadPackage(package, recurse=True) result = reporter.Reporter() suite.run(result) - self.failUnlessEqual(False, result.wasSuccessful()) - self.failUnlessEqual(2, len(result.errors)) + self.assertEqual(False, result.wasSuccessful()) + self.assertEqual(2, len(result.errors)) errors = [test.id() for test, error in result.errors] errors.sort() - self.failUnlessEqual(errors, ['package.test_bad_module', + self.assertEqual(errors, ['package.test_bad_module', 'package.test_import_module']) @@ -416,8 +416,8 @@ """ from twisted.trial.test import mockcustomsuite suite = self.loader.loadModule(mockcustomsuite) - self.failUnlessEqual(0, suite.countTestCases()) - self.failUnlessEqual("MyCustomSuite", getattr(suite, 'name', None)) + self.assertEqual(0, suite.countTestCases()) + self.assertEqual("MyCustomSuite", getattr(suite, 'name', None)) def test_loadModuleWith_testSuite(self): diff --git a/lib/twisted-trunk/twisted/trial/test/test_plugins.py b/lib/twisted-trunk/twisted/trial/test/test_plugins.py --- a/lib/twisted-trunk/twisted/trial/test/test_plugins.py +++ b/lib/twisted-trunk/twisted/trial/test/test_plugins.py @@ -39,8 +39,8 @@ One of the reporter plugins is the subunit reporter plugin. """ subunitPlugin = self.getPluginsByLongOption('subunit') - self.assertEquals('Subunit Reporter', subunitPlugin.name) - self.assertEquals('twisted.trial.reporter', subunitPlugin.module) - self.assertEquals('subunit', subunitPlugin.longOpt) + self.assertEqual('Subunit Reporter', subunitPlugin.name) + self.assertEqual('twisted.trial.reporter', subunitPlugin.module) + self.assertEqual('subunit', subunitPlugin.longOpt) self.assertIdentical(None, subunitPlugin.shortOpt) - self.assertEquals('SubunitReporter', subunitPlugin.klass) + self.assertEqual('SubunitReporter', subunitPlugin.klass) diff --git a/lib/twisted-trunk/twisted/trial/test/test_reporter.py b/lib/twisted-trunk/twisted/trial/test/test_reporter.py --- a/lib/twisted-trunk/twisted/trial/test/test_reporter.py +++ b/lib/twisted-trunk/twisted/trial/test/test_reporter.py @@ -328,7 +328,7 @@ result = reporter.VerboseTextReporter(self.stream) result.startTest(self.test) output = self.stream.getvalue() - self.failUnlessEqual( + self.assertEqual( output, 'twisted.trial.test.sample.PyunitTest.test_foo ... ') def test_treeReporter(self): @@ -336,12 +336,12 @@ result.startTest(self.test) output = self.stream.getvalue() output = output.splitlines()[-1].strip() - self.failUnlessEqual(output, result.getDescription(self.test) + ' ...') + self.assertEqual(output, result.getDescription(self.test) + ' ...') def test_getDescription(self): result = reporter.TreeReporter(self.stream) output = result.getDescription(self.test) - self.failUnlessEqual(output, 'test_foo') + self.assertEqual(output, 'test_foo') def test_minimalReporter(self): @@ -360,7 +360,7 @@ self.test.run(result) result._printSummary() output = self.stream.getvalue().strip().split(' ') - self.failUnlessEqual(output[1:], ['1', '1', '0', '0', '0']) + self.assertEqual(output[1:], ['1', '1', '0', '0', '0']) def test_minimalReporterTime(self): @@ -375,7 +375,7 @@ result._printSummary() output = self.stream.getvalue().strip().split(' ') timer = output[0] - self.assertEquals(timer, "0.7") + self.assertEqual(timer, "0.7") def test_emptyMinimalReporter(self): @@ -386,7 +386,7 @@ result = reporter.MinimalReporter(self.stream) result._printSummary() output = self.stream.getvalue().strip().split(' ') - self.failUnlessEqual(output, ['0', '0', '0', '0', '0', '0']) + self.assertEqual(output, ['0', '0', '0', '0', '0', '0']) @@ -438,7 +438,7 @@ self.assertWarns(UserWarning, self.dirtyError.getErrorMessage(), reporter.__file__, result.addError, self.test, self.dirtyError) - self.assertEquals(result._originalReporter.errors, []) + self.assertEqual(result._originalReporter.errors, []) def test_dealsWithThreeTuples(self): @@ -454,9 +454,9 @@ result.addError(self.test, (self.dirtyError.type, self.dirtyError.value, None)) self.assertEqual(len(result._originalReporter.errors), 1) - self.assertEquals(result._originalReporter.errors[0][1].type, + self.assertEqual(result._originalReporter.errors[0][1].type, self.dirtyError.type) - self.assertEquals(result._originalReporter.errors[0][1].value, + self.assertEqual(result._originalReporter.errors[0][1].value, self.dirtyError.value) @@ -471,14 +471,14 @@ result = reporter.VerboseTextReporter(self.stream) result.startTest(self.test) output = self.stream.getvalue() - self.failUnlessEqual(output, self.test.id() + ' ... ') + self.assertEqual(output, self.test.id() + ' ... ') def test_treeReporter(self): result = reporter.TreeReporter(self.stream) result.startTest(self.test) output = self.stream.getvalue() output = output.splitlines()[-1].strip() - self.failUnlessEqual(output, result.getDescription(self.test) + ' ...') + self.assertEqual(output, result.getDescription(self.test) + ' ...') def test_treeReporterWithDocstrings(self): """A docstring""" @@ -489,7 +489,7 @@ def test_getDescription(self): result = reporter.TreeReporter(self.stream) output = result.getDescription(self.test) - self.failUnlessEqual(output, "test_foo") + self.assertEqual(output, "test_foo") class TestSkip(unittest.TestCase): @@ -513,7 +513,7 @@ def test_success(self): self.result.addSkip(self.test, 'some reason') - self.failUnlessEqual(True, self.result.wasSuccessful()) + self.assertEqual(True, self.result.wasSuccessful()) def test_summary(self): @@ -526,7 +526,7 @@ output = self.stream.getvalue().splitlines()[-1] prefix = 'PASSED ' self.failUnless(output.startswith(prefix)) - self.failUnlessEqual(output[len(prefix):].strip(), '(skips=1)') + self.assertEqual(output[len(prefix):].strip(), '(skips=1)') def test_basicErrors(self): @@ -537,7 +537,7 @@ self.result.addSkip(self.test, 'some reason') self.result.done() output = self.stream.getvalue().splitlines()[3] - self.failUnlessEqual(output.strip(), 'some reason') + self.assertEqual(output.strip(), 'some reason') def test_booleanSkip(self): @@ -549,7 +549,7 @@ self.result.addSkip(self.test, True) self.result.done() output = self.stream.getvalue().splitlines()[3] - self.failUnlessEqual(output, 'True') + self.assertEqual(output, 'True') def test_exceptionSkip(self): @@ -564,7 +564,7 @@ self.result.addSkip(self.test, error) self.result.done() output = '\n'.join(self.stream.getvalue().splitlines()[3:5]).strip() - self.failUnlessEqual(output, str(e)) + self.assertEqual(output, str(e)) class UncleanWarningSkipTest(TestSkip): @@ -791,8 +791,8 @@ """ self.result.addSuccess(self.test) self.result.done() - self.assertEquals(self.log[1], (self.result.SUCCESS, 'PASSED')) - self.assertEquals( + self.assertEqual(self.log[1], (self.result.SUCCESS, 'PASSED')) + self.assertEqual( self.stream.getvalue().splitlines()[-1].strip(), "(successes=1)") @@ -806,8 +806,8 @@ except RuntimeError: self.result.addError(self, sys.exc_info()) self.result.done() - self.assertEquals(self.log[1], (self.result.FAILURE, 'FAILED')) - self.assertEquals( + self.assertEqual(self.log[1], (self.result.FAILURE, 'FAILED')) + self.assertEqual( self.stream.getvalue().splitlines()[-1].strip(), "(errors=1)") @@ -846,8 +846,8 @@ self.result.done() grouped = self.result._groupResults( self.result.errors, self.result._formatFailureTraceback) - self.assertEquals(grouped[0][1], [self, self.test]) - self.assertEquals(grouped[1][1], [extra]) + self.assertEqual(grouped[0][1], [self, self.test]) + self.assertEqual(grouped[1][1], [extra]) def test_printResults(self): @@ -862,7 +862,7 @@ third = sample.PyunitTest('test_foo') self.result._printResults( 'FOO', [(first, 1), (second, 1), (third, 2)], formatter) - self.assertEquals( + self.assertEqual( self.stream.getvalue(), "%(double separator)s\n" "FOO\n" @@ -908,7 +908,7 @@ """ shouldStop is False to begin with. """ - self.assertEquals(False, self.result.shouldStop) + self.assertEqual(False, self.result.shouldStop) def test_shouldStopTrueAfterStop(self): @@ -916,14 +916,14 @@ shouldStop becomes True soon as someone calls stop(). """ self.result.stop() - self.assertEquals(True, self.result.shouldStop) + self.assertEqual(True, self.result.shouldStop) def test_wasSuccessfulInitiallyTrue(self): """ wasSuccessful() is True when there have been no results reported. """ - self.assertEquals(True, self.result.wasSuccessful()) + self.assertEqual(True, self.result.wasSuccessful()) def test_wasSuccessfulTrueAfterSuccesses(self): @@ -932,7 +932,7 @@ otherwise. """ self.result.addSuccess(self.test) - self.assertEquals(True, self.result.wasSuccessful()) + self.assertEqual(True, self.result.wasSuccessful()) def test_wasSuccessfulFalseAfterErrors(self): @@ -943,7 +943,7 @@ 1 / 0 except ZeroDivisionError: self.result.addError(self.test, sys.exc_info()) - self.assertEquals(False, self.result.wasSuccessful()) + self.assertEqual(False, self.result.wasSuccessful()) def test_wasSuccessfulFalseAfterFailures(self): @@ -954,7 +954,7 @@ self.fail("foo") except self.failureException: self.result.addFailure(self.test, sys.exc_info()) - self.assertEquals(False, self.result.wasSuccessful()) + self.assertEqual(False, self.result.wasSuccessful()) @@ -1198,8 +1198,8 @@ subunitReturn = getattr(subunitClient, methodName)(*args, **kwargs) subunitOutput = stream.getvalue() reporterReturn = getattr(self.result, methodName)(*args, **kwargs) - self.assertEquals(subunitReturn, reporterReturn) - self.assertEquals(subunitOutput, self.stream.getvalue()) + self.assertEqual(subunitReturn, reporterReturn) + self.assertEqual(subunitOutput, self.stream.getvalue()) def removeMethod(self, klass, methodName): @@ -1242,7 +1242,7 @@ self.stream.truncate(0) self.result.addSuccess(self.test) successOutput = self.stream.getvalue() - self.assertEquals(successOutput, expectedFailureOutput) + self.assertEqual(successOutput, expectedFailureOutput) def test_subunitWithoutAddSkipInstalled(self): @@ -1256,7 +1256,7 @@ self.stream.truncate(0) self.result.addSuccess(self.test) successOutput = self.stream.getvalue() - self.assertEquals(successOutput, skipOutput) + self.assertEqual(successOutput, skipOutput) def test_addExpectedFailurePassedThrough(self): @@ -1277,7 +1277,7 @@ except ZeroDivisionError: exc_info = sys.exc_info() self.result.addExpectedFailure(self.test, exc_info, 'todo') - self.assertEquals(addExpectedFailureCalls, [(self.test, exc_info)]) + self.assertEqual(addExpectedFailureCalls, [(self.test, exc_info)]) def test_addSkipSendsSubunitAddSkip(self): @@ -1294,7 +1294,7 @@ # subunit has addSkip. self.result._subunit.addSkip = addSkip self.result.addSkip(self.test, 'reason') - self.assertEquals(addSkipCalls, [(self.test, 'reason')]) + self.assertEqual(addSkipCalls, [(self.test, 'reason')]) def test_doneDoesNothing(self): @@ -1303,7 +1303,7 @@ of results is everything. Thus, done() does nothing. """ self.result.done() - self.assertEquals('', self.stream.getvalue()) + self.assertEqual('', self.stream.getvalue()) def test_startTestSendsSubunitStartTest(self): @@ -1359,7 +1359,7 @@ subunitClient.addSuccess(self.test) subunitOutput = stream.getvalue() self.result.addUnexpectedSuccess(self.test, 'todo') - self.assertEquals(subunitOutput, self.stream.getvalue()) + self.assertEqual(subunitOutput, self.stream.getvalue()) def test_loadTimeErrors(self): @@ -1388,7 +1388,7 @@ stream = StringIO.StringIO() self.patch(reporter, 'TestProtocolClient', None) e = self.assertRaises(Exception, reporter.SubunitReporter, stream) - self.assertEquals("Subunit not available", str(e)) + self.assertEqual("Subunit not available", str(e)) @@ -1595,7 +1595,7 @@ self.assertTrue(reporter._AnsiColorizer.supported(FakeStream())) self.assertTrue(reporter._AnsiColorizer.supported(FakeStream())) - self.assertEquals(sys.modules['curses'].setUp, 1) + self.assertEqual(sys.modules['curses'].setUp, 1) def test_supportedTigetNumWrongError(self): @@ -1646,4 +1646,4 @@ sys.modules['curses'] = fakecurses() self.assertFalse(reporter._AnsiColorizer.supported(FakeStream())) - self.assertEquals(sys.modules['curses'].setUp, 1) + self.assertEqual(sys.modules['curses'].setUp, 1) diff --git a/lib/twisted-trunk/twisted/trial/test/test_runner.py b/lib/twisted-trunk/twisted/trial/test/test_runner.py --- a/lib/twisted-trunk/twisted/trial/test/test_runner.py +++ b/lib/twisted-trunk/twisted/trial/test/test_runner.py @@ -134,7 +134,7 @@ self.runner._setUpLogFile = setUpLogFile self.runner.run(self.test) self.runner.run(self.test) - self.failUnlessEqual(len(l), 2) + self.assertEqual(len(l), 2) self.failIf(l[0] is l[1], "Should have created a new file observer") @@ -149,7 +149,7 @@ l.append(self.runner._logFileObject) self.runner._setUpLogFile = setUpLogFile self.runner.run(self.test) - self.failUnlessEqual(len(l), 1) + self.assertEqual(len(l), 1) self.failUnless(l[0].closed) @@ -371,7 +371,7 @@ def test_runner_working_directory(self): self.parseOptions(['--temp-directory', 'some_path']) runner = self.getRunner() - self.assertEquals(runner.workingDirectory, 'some_path') + self.assertEqual(runner.workingDirectory, 'some_path') def test_concurrentImplicitWorkingDirectory(self): @@ -571,7 +571,7 @@ dirPath.moveTo = dummyMoveTo error = self.assertRaises(OSError, util._removeSafely, dirPath) - self.assertEquals(str(error), "path movement failed") + self.assertEqual(str(error), "path movement failed") self.assertIn("could not remove FilePath", out.getvalue()) @@ -610,9 +610,9 @@ a few runs. """ result = self.runner.runUntilFailure(self.test) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) self.failIf(result.wasSuccessful()) - self.assertEquals(self._getFailures(result), 1) + self.assertEqual(self._getFailures(result), 1) def _getFailures(self, result): @@ -633,10 +633,10 @@ return test self.patch(unittest, "decorate", decorate) result = self.runner.runUntilFailure(self.test) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) - self.assertEquals(len(decorated), 1) - self.assertEquals(decorated, [(self.test, ITestCase)]) + self.assertEqual(len(decorated), 1) + self.assertEqual(decorated, [(self.test, ITestCase)]) def test_runUntilFailureForceGCDecorate(self): @@ -651,10 +651,10 @@ self.patch(unittest, "decorate", decorate) self.runner._forceGarbageCollection = True result = self.runner.runUntilFailure(self.test) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) - self.assertEquals(len(decorated), 2) - self.assertEquals(decorated, + self.assertEqual(len(decorated), 2) + self.assertEqual(decorated, [(self.test, ITestCase), (self.test, unittest._ForceGarbageCollectionDecorator)]) @@ -763,7 +763,7 @@ result = pyunit.TestResult() self.holder.run(result) self.assertTrue(result.wasSuccessful()) - self.assertEquals(1, result.testsRun) + self.assertEqual(1, result.testsRun) @@ -790,7 +790,7 @@ result = pyunit.TestResult() self.holder.run(result) self.assertFalse(result.wasSuccessful()) - self.assertEquals(1, result.testsRun) + self.assertEqual(1, result.testsRun) @@ -816,9 +816,9 @@ trialRunner = runner.TrialRunner(reporter.Reporter, stream=stream) test = TestMalformedMethod.ContainMalformed(method) result = trialRunner.run(test) - self.failUnlessEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 1) self.failIf(result.wasSuccessful()) - self.failUnlessEqual(len(result.errors), 1) + self.assertEqual(len(result.errors), 1) def test_extraArg(self): """ @@ -856,10 +856,10 @@ test = MockTest('test_foo') result = reporter.TestResult() suite = runner.DestructiveTestSuite([test]) - self.assertEquals(called, []) + self.assertEqual(called, []) suite.run(result) - self.assertEquals(called, [True]) - self.assertEquals(suite.countTestCases(), 0) + self.assertEqual(called, [True]) + self.assertEqual(suite.countTestCases(), 0) def test_shouldStop(self): @@ -879,11 +879,11 @@ loader = runner.TestLoader() loader.suiteFactory = runner.DestructiveTestSuite suite = loader.loadClass(MockTest) - self.assertEquals(called, []) + self.assertEqual(called, []) suite.run(result) - self.assertEquals(called, [1]) + self.assertEqual(called, [1]) # The last test shouldn't have been run - self.assertEquals(suite.countTestCases(), 1) + self.assertEqual(suite.countTestCases(), 1) def test_cleanup(self): @@ -897,9 +897,9 @@ test = MockTest('test_foo') result = reporter.TestResult() suite = runner.DestructiveTestSuite([test]) - self.assertEquals(suite.countTestCases(), 1) + self.assertEqual(suite.countTestCases(), 1) suite.run(result) - self.assertEquals(suite.countTestCases(), 0) + self.assertEqual(suite.countTestCases(), 0) diff --git a/lib/twisted-trunk/twisted/trial/test/test_script.py b/lib/twisted-trunk/twisted/trial/test/test_script.py --- a/lib/twisted-trunk/twisted/trial/test/test_script.py +++ b/lib/twisted-trunk/twisted/trial/test/test_script.py @@ -98,7 +98,7 @@ By default, the loader should use L{runner.DestructiveTestSuite} """ loader = trial._getLoader(self.config) - self.assertEquals(loader.suiteFactory, runner.DestructiveTestSuite) + self.assertEqual(loader.suiteFactory, runner.DestructiveTestSuite) def test_untilFailureSuite(self): @@ -108,7 +108,7 @@ """ self.config['until-failure'] = True loader = trial._getLoader(self.config) - self.assertEquals(loader.suiteFactory, runner.TestSuite) + self.assertEqual(loader.suiteFactory, runner.TestSuite) @@ -135,7 +135,7 @@ self.assertEqual(names1, names2) def test_baseState(self): - self.failUnlessEqual(0, len(self.config['tests'])) + self.assertEqual(0, len(self.config['tests'])) def test_testmoduleOnModule(self): """ @@ -196,8 +196,8 @@ filename = 'test_thisbetternoteverexist.py' try: self.config.opt_testmodule(filename) - self.failUnlessEqual(0, len(self.config['tests'])) - self.failUnlessEqual("File %r doesn't exist\n" % (filename,), + self.assertEqual(0, len(self.config['tests'])) + self.assertEqual("File %r doesn't exist\n" % (filename,), buffy.getvalue()) finally: sys.stderr = stderr @@ -208,7 +208,7 @@ which lack test-case-name buffer variables. """ self.config.opt_testmodule(sibpath('novars.py')) - self.failUnlessEqual(0, len(self.config['tests'])) + self.assertEqual(0, len(self.config['tests'])) def test_testmoduleOnModuleName(self): """ @@ -220,8 +220,8 @@ moduleName = 'twisted.trial.test.test_script' try: self.config.opt_testmodule(moduleName) - self.failUnlessEqual(0, len(self.config['tests'])) - self.failUnlessEqual("File %r doesn't exist\n" % (moduleName,), + self.assertEqual(0, len(self.config['tests'])) + self.assertEqual("File %r doesn't exist\n" % (moduleName,), buffy.getvalue()) finally: sys.stderr = stderr @@ -229,14 +229,14 @@ def test_parseLocalVariable(self): declaration = '-*- test-case-name: twisted.trial.test.test_tests -*-' localVars = trial._parseLocalVariables(declaration) - self.failUnlessEqual({'test-case-name': + self.assertEqual({'test-case-name': 'twisted.trial.test.test_tests'}, localVars) def test_trailingSemicolon(self): declaration = '-*- test-case-name: twisted.trial.test.test_tests; -*-' localVars = trial._parseLocalVariables(declaration) - self.failUnlessEqual({'test-case-name': + self.assertEqual({'test-case-name': 'twisted.trial.test.test_tests'}, localVars) @@ -244,7 +244,7 @@ declaration = ('-*- test-case-name: twisted.trial.test.test_tests; ' 'foo: bar -*-') localVars = trial._parseLocalVariables(declaration) - self.failUnlessEqual({'test-case-name': + self.assertEqual({'test-case-name': 'twisted.trial.test.test_tests', 'foo': 'bar'}, localVars) @@ -253,7 +253,7 @@ declaration = ('## -*- test-case-name: ' 'twisted.trial.test.test_tests -*- #') localVars = trial._parseLocalVariables(declaration) - self.failUnlessEqual({'test-case-name': + self.assertEqual({'test-case-name': 'twisted.trial.test.test_tests'}, localVars) @@ -271,32 +271,32 @@ def test_variablesFromFile(self): localVars = trial.loadLocalVariables(sibpath('moduletest.py')) - self.failUnlessEqual({'test-case-name': + self.assertEqual({'test-case-name': 'twisted.trial.test.test_test_visitor'}, localVars) def test_noVariablesInFile(self): localVars = trial.loadLocalVariables(sibpath('novars.py')) - self.failUnlessEqual({}, localVars) + self.assertEqual({}, localVars) def test_variablesFromScript(self): localVars = trial.loadLocalVariables(sibpath('scripttest.py')) - self.failUnlessEqual( + self.assertEqual( {'test-case-name': ('twisted.trial.test.test_test_visitor,' 'twisted.trial.test.test_class')}, localVars) def test_getTestModules(self): modules = trial.getTestModules(sibpath('moduletest.py')) - self.failUnlessEqual(modules, ['twisted.trial.test.test_test_visitor']) + self.assertEqual(modules, ['twisted.trial.test.test_test_visitor']) def test_getTestModules_noVars(self): modules = trial.getTestModules(sibpath('novars.py')) - self.failUnlessEqual(len(modules), 0) + self.assertEqual(len(modules), 0) def test_getTestModules_multiple(self): modules = trial.getTestModules(sibpath('scripttest.py')) - self.failUnlessEqual(set(modules), + self.assertEqual(set(modules), set(['twisted.trial.test.test_test_visitor', 'twisted.trial.test.test_class'])) @@ -414,7 +414,7 @@ """ options = trial.Options() options.parseOptions(["--coverage"]) - self.assertEquals(sys.gettrace(), options.tracer.globaltrace) + self.assertEqual(sys.gettrace(), options.tracer.globaltrace) def test_coverdirDefault(self): @@ -423,7 +423,7 @@ for the I{temp-directory} option if that option is not specified. """ options = trial.Options() - self.assertEquals( + self.assertEqual( options.coverdir(), FilePath(".").descendant([options["temp-directory"], "coverage"])) @@ -436,7 +436,7 @@ path = self.mktemp() options = trial.Options() options.parseOptions(["--temp-directory", path]) - self.assertEquals( + self.assertEqual( options.coverdir(), FilePath(path).child("coverage")) @@ -457,9 +457,9 @@ """ Check for a deprecation warning """ - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals(warnings[0]['message'], + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(warnings[0]['message'], deprecate.getDeprecationWarningString( deprecatedCallable, versions.Version('Twisted', 11, 0, 0))) diff --git a/lib/twisted-trunk/twisted/trial/test/test_testcase.py b/lib/twisted-trunk/twisted/trial/test/test_testcase.py --- a/lib/twisted-trunk/twisted/trial/test/test_testcase.py +++ b/lib/twisted-trunk/twisted/trial/test/test_testcase.py @@ -48,4 +48,4 @@ container = {} container[self.first] = None container[self.second] = None - self.assertEquals(len(container), 2) + self.assertEqual(len(container), 2) diff --git a/lib/twisted-trunk/twisted/trial/test/test_tests.py b/lib/twisted-trunk/twisted/trial/test/test_tests.py --- a/lib/twisted-trunk/twisted/trial/test/test_tests.py +++ b/lib/twisted-trunk/twisted/trial/test/test_tests.py @@ -21,14 +21,14 @@ def test_setUp(self): self.failUnless(self.reporter.wasSuccessful()) - self.failUnlessEqual(self.reporter.errors, []) - self.failUnlessEqual(self.reporter.failures, []) - self.failUnlessEqual(self.reporter.skips, []) + self.assertEqual(self.reporter.errors, []) + self.assertEqual(self.reporter.failures, []) + self.assertEqual(self.reporter.skips, []) def assertCount(self, numTests): - self.failUnlessEqual(self.suite.countTestCases(), numTests) + self.assertEqual(self.suite.countTestCases(), numTests) self.suite(self.reporter) - self.failUnlessEqual(self.reporter.testsRun, numTests) + self.assertEqual(self.reporter.testsRun, numTests) @@ -122,24 +122,24 @@ def test_results(self): self.suite(self.reporter) self.failUnless(self.reporter.wasSuccessful()) - self.failUnlessEqual(self.reporter.errors, []) - self.failUnlessEqual(self.reporter.failures, []) - self.failUnlessEqual(len(self.reporter.skips), 3) + self.assertEqual(self.reporter.errors, []) + self.assertEqual(self.reporter.failures, []) + self.assertEqual(len(self.reporter.skips), 3) def test_setUp(self): self.loadSuite(TestSkipMethods.SkippingSetUp) self.suite(self.reporter) self.failUnless(self.reporter.wasSuccessful()) - self.failUnlessEqual(self.reporter.errors, []) - self.failUnlessEqual(self.reporter.failures, []) - self.failUnlessEqual(len(self.reporter.skips), 2) + self.assertEqual(self.reporter.errors, []) + self.assertEqual(self.reporter.failures, []) + self.assertEqual(len(self.reporter.skips), 2) def test_reasons(self): self.suite(self.reporter) prefix = 'test_' # whiteboxing reporter for test, reason in self.reporter.skips: - self.failUnlessEqual(test.shortDescription()[len(prefix):], + self.assertEqual(test.shortDescription()[len(prefix):], str(reason)) @@ -187,9 +187,9 @@ """ self.suite(self.reporter) self.failUnless(self.reporter.wasSuccessful()) - self.failUnlessEqual(self.reporter.errors, []) - self.failUnlessEqual(self.reporter.failures, []) - self.failUnlessEqual(len(self.reporter.skips), 4) + self.assertEqual(self.reporter.errors, []) + self.assertEqual(self.reporter.failures, []) + self.assertEqual(len(self.reporter.skips), 4) def test_reasons(self): @@ -201,7 +201,7 @@ expectedReasons = ['class', 'skip2', 'class', 'class'] # whitebox reporter reasonsGiven = [reason for test, reason in self.reporter.skips] - self.assertEquals(expectedReasons, reasonsGiven) + self.assertEqual(expectedReasons, reasonsGiven) @@ -228,25 +228,25 @@ def test_results(self): self.suite(self.reporter) self.failUnless(self.reporter.wasSuccessful()) - self.failUnlessEqual(self.reporter.errors, []) - self.failUnlessEqual(self.reporter.failures, []) - self.failUnlessEqual(self.reporter.skips, []) - self.failUnlessEqual(len(self.reporter.expectedFailures), 2) - self.failUnlessEqual(len(self.reporter.unexpectedSuccesses), 1) + self.assertEqual(self.reporter.errors, []) + self.assertEqual(self.reporter.failures, []) + self.assertEqual(self.reporter.skips, []) + self.assertEqual(len(self.reporter.expectedFailures), 2) + self.assertEqual(len(self.reporter.unexpectedSuccesses), 1) def test_expectedFailures(self): self.suite(self.reporter) expectedReasons = ['todo1', 'todo2'] reasonsGiven = [ r.reason for t, e, r in self.reporter.expectedFailures ] - self.failUnlessEqual(expectedReasons, reasonsGiven) + self.assertEqual(expectedReasons, reasonsGiven) def test_unexpectedSuccesses(self): self.suite(self.reporter) expectedReasons = ['todo3'] reasonsGiven = [ r.reason for t, r in self.reporter.unexpectedSuccesses ] - self.failUnlessEqual(expectedReasons, reasonsGiven) + self.assertEqual(expectedReasons, reasonsGiven) class TestTodoClass(unittest.TestCase, ResultsTestMixin): @@ -272,25 +272,25 @@ def test_results(self): self.suite(self.reporter) self.failUnless(self.reporter.wasSuccessful()) - self.failUnlessEqual(self.reporter.errors, []) - self.failUnlessEqual(self.reporter.failures, []) - self.failUnlessEqual(self.reporter.skips, []) - self.failUnlessEqual(len(self.reporter.expectedFailures), 2) - self.failUnlessEqual(len(self.reporter.unexpectedSuccesses), 2) + self.assertEqual(self.reporter.errors, []) + self.assertEqual(self.reporter.failures, []) + self.assertEqual(self.reporter.skips, []) + self.assertEqual(len(self.reporter.expectedFailures), 2) + self.assertEqual(len(self.reporter.unexpectedSuccesses), 2) def test_expectedFailures(self): self.suite(self.reporter) expectedReasons = ['method', 'class'] reasonsGiven = [ r.reason for t, e, r in self.reporter.expectedFailures ] - self.failUnlessEqual(expectedReasons, reasonsGiven) + self.assertEqual(expectedReasons, reasonsGiven) def test_unexpectedSuccesses(self): self.suite(self.reporter) expectedReasons = ['method', 'class'] reasonsGiven = [ r.reason for t, r in self.reporter.unexpectedSuccesses ] - self.failUnlessEqual(expectedReasons, reasonsGiven) + self.assertEqual(expectedReasons, reasonsGiven) class TestStrictTodo(unittest.TestCase, ResultsTestMixin): @@ -332,25 +332,25 @@ def test_results(self): self.suite(self.reporter) self.failIf(self.reporter.wasSuccessful()) - self.failUnlessEqual(len(self.reporter.errors), 2) - self.failUnlessEqual(len(self.reporter.failures), 1) - self.failUnlessEqual(len(self.reporter.expectedFailures), 3) - self.failUnlessEqual(len(self.reporter.unexpectedSuccesses), 1) - self.failUnlessEqual(self.reporter.skips, []) + self.assertEqual(len(self.reporter.errors), 2) + self.assertEqual(len(self.reporter.failures), 1) + self.assertEqual(len(self.reporter.expectedFailures), 3) + self.assertEqual(len(self.reporter.unexpectedSuccesses), 1) + self.assertEqual(self.reporter.skips, []) def test_expectedFailures(self): self.suite(self.reporter) expectedReasons = ['todo1', 'todo2', 'todo5'] reasonsGotten = [ r.reason for t, e, r in self.reporter.expectedFailures ] - self.failUnlessEqual(expectedReasons, reasonsGotten) + self.assertEqual(expectedReasons, reasonsGotten) def test_unexpectedSuccesses(self): self.suite(self.reporter) expectedReasons = [([RuntimeError], 'todo7')] reasonsGotten = [ (r.errors, r.reason) for t, r in self.reporter.unexpectedSuccesses ] - self.failUnlessEqual(expectedReasons, reasonsGotten) + self.assertEqual(expectedReasons, reasonsGotten) @@ -552,7 +552,7 @@ test = self.BasicTest('test_foo') result = reporter.TestResult() test.run(result) - self.failUnlessEqual(self._collectCalled, ['setUp', 'test', 'tearDown']) + self.assertEqual(self._collectCalled, ['setUp', 'test', 'tearDown']) @@ -566,7 +566,7 @@ test = unittest._ForceGarbageCollectionDecorator(test) result = reporter.TestResult() test.run(result) - self.failUnlessEqual( + self.assertEqual( self._collectCalled, ['collect', 'setUp', 'test', 'tearDown', 'collect']) @@ -904,7 +904,7 @@ count1 = getrefcount(test) decoratedTest = unittest.decorate(suite, unittest.TestDecorator) count2 = getrefcount(test) - self.assertEquals(count1, count2) + self.assertEqual(count1, count2) def test_decorateNestedTestSuite(self): diff --git a/lib/twisted-trunk/twisted/trial/test/test_util.py b/lib/twisted-trunk/twisted/trial/test/test_util.py --- a/lib/twisted-trunk/twisted/trial/test/test_util.py +++ b/lib/twisted-trunk/twisted/trial/test/test_util.py @@ -25,7 +25,7 @@ def test_name(self): name = self.mktemp() dirs = os.path.dirname(name).split(os.sep)[:-1] - self.failUnlessEqual( + self.assertEqual( dirs, ['twisted.trial.test.test_util', 'TestMktemp', 'test_name']) def test_unique(self): @@ -50,7 +50,7 @@ suppression.TestSuppression2.testSuppressModule) expected = [suppression.TestSuppression2, suppression] for a, b in zip(parents, expected): - self.failUnlessEqual(a, b) + self.assertEqual(a, b) class TestFindObject(packages.SysPathManglingTest): @@ -64,9 +64,9 @@ """ util.findObject('') warningsShown = self.flushWarnings() - self.assertEquals(len(warningsShown), 1) + self.assertEqual(len(warningsShown), 1) self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEquals(warningsShown[0]['message'], + self.assertEqual(warningsShown[0]['message'], "twisted.trial.util.findObject was deprecated " "in Twisted 10.1.0: Please use " "twisted.python.reflect.namedAny instead.") @@ -75,12 +75,12 @@ def test_importPackage(self): package1 = util.findObject('package') import package as package2 - self.failUnlessEqual(package1, (True, package2)) + self.assertEqual(package1, (True, package2)) def test_importModule(self): test_sample2 = util.findObject('goodpackage.test_sample') from goodpackage import test_sample - self.failUnlessEqual((True, test_sample), test_sample2) + self.assertEqual((True, test_sample), test_sample2) def test_importError(self): self.failUnlessRaises(ZeroDivisionError, @@ -91,21 +91,21 @@ util.findObject, 'package2.test_module') def test_importNonexistentPackage(self): - self.failUnlessEqual(util.findObject('doesntexist')[0], False) + self.assertEqual(util.findObject('doesntexist')[0], False) def test_findNonexistentModule(self): - self.failUnlessEqual(util.findObject('package.doesntexist')[0], False) + self.assertEqual(util.findObject('package.doesntexist')[0], False) def test_findNonexistentObject(self): - self.failUnlessEqual(util.findObject( + self.assertEqual(util.findObject( 'goodpackage.test_sample.doesnt')[0], False) - self.failUnlessEqual(util.findObject( + self.assertEqual(util.findObject( 'goodpackage.test_sample.AlphabetTest.doesntexist')[0], False) def test_findObjectExist(self): alpha1 = util.findObject('goodpackage.test_sample.AlphabetTest') from goodpackage import test_sample - self.failUnlessEqual(alpha1, (True, test_sample.AlphabetTest)) + self.assertEqual(alpha1, (True, test_sample.AlphabetTest)) @@ -264,7 +264,7 @@ Delayed calls are formatted nicely. """ error = DirtyReactorAggregateError(["Foo", "bar"]) - self.assertEquals(str(error), + self.assertEqual(str(error), """\ Reactor was unclean. DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug) @@ -277,7 +277,7 @@ Selectables are formatted nicely. """ error = DirtyReactorAggregateError([], ["selectable 1", "selectable 2"]) - self.assertEquals(str(error), + self.assertEqual(str(error), """\ Reactor was unclean. Selectables: @@ -291,7 +291,7 @@ """ error = DirtyReactorAggregateError(["bleck", "Boozo"], ["Sel1", "Sel2"]) - self.assertEquals(str(error), + self.assertEqual(str(error), """\ Reactor was unclean. DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug) @@ -386,7 +386,7 @@ reactor = StubReactor([]) jan = _Janitor(None, None, reactor=reactor) jan._cleanPending() - self.assertEquals(reactor.iterations, [0, 0]) + self.assertEqual(reactor.iterations, [0, 0]) def test_cleanPendingCancelsCalls(self): @@ -401,7 +401,7 @@ reactor = StubReactor([delayedCall]) jan = _Janitor(None, None, reactor=reactor) jan._cleanPending() - self.assertEquals(cancelled, [delayedCall]) + self.assertEqual(cancelled, [delayedCall]) def test_cleanPendingReturnsDelayedCallStrings(self): @@ -419,7 +419,7 @@ reactor = StubReactor([delayedCall]) jan = _Janitor(None, None, reactor=reactor) strings = jan._cleanPending() - self.assertEquals(strings, [delayedCallString]) + self.assertEqual(strings, [delayedCallString]) def test_cleanReactorRemovesSelectables(self): @@ -429,7 +429,7 @@ reactor = StubReactor([]) jan = _Janitor(None, None, reactor=reactor) jan._cleanReactor() - self.assertEquals(reactor.removeAllCalled, 1) + self.assertEqual(reactor.removeAllCalled, 1) def test_cleanReactorKillsProcesses(self): @@ -456,7 +456,7 @@ reactor = StubReactor([], [pt]) jan = _Janitor(None, None, reactor=reactor) jan._cleanReactor() - self.assertEquals(pt.signals, ["KILL"]) + self.assertEqual(pt.signals, ["KILL"]) def test_cleanReactorReturnsSelectableStrings(self): @@ -474,7 +474,7 @@ reactor = StubReactor([], [Selectable()]) jan = _Janitor(None, None, reactor=reactor) - self.assertEquals(jan._cleanReactor(), ["(SELECTABLE!)"]) + self.assertEqual(jan._cleanReactor(), ["(SELECTABLE!)"]) def test_postCaseCleanupNoErrors(self): @@ -487,7 +487,7 @@ reporter = StubErrorReporter() jan = _Janitor(test, reporter, reactor=reactor) self.assertTrue(jan.postCaseCleanup()) - self.assertEquals(reporter.errors, []) + self.assertEqual(reporter.errors, []) def test_postCaseCleanupWithErrors(self): @@ -505,8 +505,8 @@ reporter = StubErrorReporter() jan = _Janitor(test, reporter, reactor=reactor) self.assertFalse(jan.postCaseCleanup()) - self.assertEquals(len(reporter.errors), 1) - self.assertEquals(reporter.errors[0][1].value.delayedCalls, + self.assertEqual(len(reporter.errors), 1) + self.assertEqual(reporter.errors[0][1].value.delayedCalls, [delayedCallString]) @@ -520,7 +520,7 @@ reporter = StubErrorReporter() jan = _Janitor(test, reporter, reactor=reactor) jan.postClassCleanup() - self.assertEquals(reporter.errors, []) + self.assertEqual(reporter.errors, []) def test_postClassCleanupWithPendingCallErrors(self): @@ -537,8 +537,8 @@ reporter = StubErrorReporter() jan = _Janitor(test, reporter, reactor=reactor) jan.postClassCleanup() - self.assertEquals(len(reporter.errors), 1) - self.assertEquals(reporter.errors[0][1].value.delayedCalls, + self.assertEqual(len(reporter.errors), 1) + self.assertEqual(reporter.errors[0][1].value.delayedCalls, [delayedCallString]) @@ -553,7 +553,7 @@ reporter = StubErrorReporter() jan = _Janitor(test, reporter, reactor=reactor) jan.postClassCleanup() - self.assertEquals(len(reporter.errors), 1) - self.assertEquals(reporter.errors[0][1].value.selectables, + self.assertEqual(len(reporter.errors), 1) + self.assertEqual(reporter.errors[0][1].value.selectables, [repr(selectable)]) diff --git a/lib/twisted-trunk/twisted/trial/test/test_warning.py b/lib/twisted-trunk/twisted/trial/test/test_warning.py --- a/lib/twisted-trunk/twisted/trial/test/test_warning.py +++ b/lib/twisted-trunk/twisted/trial/test/test_warning.py @@ -9,7 +9,8 @@ from StringIO import StringIO from twisted.python.filepath import FilePath -from twisted.trial.unittest import TestCase, _collectWarnings +from twisted.trial.unittest import (TestCase, _collectWarnings, + _setWarningRegistryToNone) from twisted.trial.reporter import TestResult class Mask(object): @@ -434,3 +435,38 @@ sys.modules[key] = key self.addCleanup(sys.modules.pop, key) self.test_duplicateWarningCollected() + + + def test_setWarningRegistryChangeWhileIterating(self): + """ + If the dictionary passed to L{_setWarningRegistryToNone} changes size + partway through the process, C{_setWarningRegistryToNone} continues to + set C{__warningregistry__} to C{None} on the rest of the values anyway. + + + This might be caused by C{sys.modules} containing something that's not + really a module and imports things on setattr. py.test does this, as + does L{twisted.python.deprecate.deprecatedModuleAttribute}. + """ + d = {} + + class A(object): + def __init__(self, key): + self.__dict__['_key'] = key + + def __setattr__(self, value, item): + d[self._key] = None + + key1 = object() + key2 = object() + d[key1] = A(key2) + + key3 = object() + key4 = object() + d[key3] = A(key4) + + _setWarningRegistryToNone(d) + + # If both key2 and key4 were added, then both A instanced were + # processed. + self.assertEqual(set([key1, key2, key3, key4]), set(d.keys())) diff --git a/lib/twisted-trunk/twisted/trial/unittest.py b/lib/twisted-trunk/twisted/trial/unittest.py --- a/lib/twisted-trunk/twisted/trial/unittest.py +++ b/lib/twisted-trunk/twisted/trial/unittest.py @@ -132,6 +132,23 @@ self.lineno = lineno +def _setWarningRegistryToNone(modules): + """ + Disable the per-module cache for every module found in C{modules}, typically + C{sys.modules}. + + @param modules: Dictionary of modules, typically sys.module dict + """ + for v in modules.values(): + if v is not None: + try: + v.__warningregistry__ = None + except: + # Don't specify a particular exception type to handle in case + # some wacky object raises some wacky exception in response to + # the setattr attempt. + pass + def _collectWarnings(observeWarning, f, *args, **kwargs): """ @@ -151,15 +168,7 @@ # Disable the per-module cache for every module otherwise if the warning # which the caller is expecting us to collect was already emitted it won't # be re-emitted by the call to f which happens below. - for v in sys.modules.itervalues(): - if v is not None: - try: - v.__warningregistry__ = None - except: - # Don't specify a particular exception type to handle in case - # some wacky object raises some wacky exception in response to - # the setattr attempt. - pass + _setWarningRegistryToNone(sys.modules) origFilters = warnings.filters[:] origShow = warnings.showwarning @@ -243,7 +252,8 @@ % (exception.__name__, result)) assertRaises = failUnlessRaises - def failUnlessEqual(self, first, second, msg=''): + + def assertEqual(self, first, second, msg=''): """ Fail the test if C{first} and C{second} are not equal. @@ -259,7 +269,8 @@ '%snot equal:\na = %s\nb = %s\n' % (msg, pformat(first), pformat(second))) return first - assertEqual = assertEquals = failUnlessEquals = failUnlessEqual + failUnlessEqual = failUnlessEquals = assertEquals = assertEqual + def failUnlessIdentical(self, first, second, msg=None): """ diff --git a/lib/twisted-trunk/twisted/web/_newclient.py b/lib/twisted-trunk/twisted/web/_newclient.py --- a/lib/twisted-trunk/twisted/web/_newclient.py +++ b/lib/twisted-trunk/twisted/web/_newclient.py @@ -39,7 +39,7 @@ from twisted.internet.defer import Deferred, succeed, fail, maybeDeferred from twisted.internet.protocol import Protocol from twisted.protocols.basic import LineReceiver -from twisted.web.iweb import UNKNOWN_LENGTH +from twisted.web.iweb import UNKNOWN_LENGTH, IResponse from twisted.web.http_headers import Headers from twisted.web.http import NO_CONTENT, NOT_MODIFIED from twisted.web.http import _DataLoss, PotentialDataLoss @@ -834,27 +834,6 @@ L{Response} should not be subclassed or instantiated. - @ivar version: A three-tuple describing the protocol and protocol version - of the response. The first element is of type C{str}, the second and - third are of type C{int}. For example, C{('HTTP', 1, 1)}. - @type version: C{tuple} - - @ivar code: The HTTP status code of this response. - @type code: C{int} - - @ivar phrase: The HTTP reason phrase of this response. - @type phrase: C{str} - - @ivar headers: The HTTP response headers of this response. - @type headers: L{Headers} - - @ivar length: The number of bytes expected to be in the body of this - response or L{UNKNOWN_LENGTH} if the server did not indicate how many - bytes to expect. For I{HEAD} responses, this will be 0; if the - response includes a I{Content-Length} header, it will be available in - C{headers}. - @type length: C{int} or something else - @ivar _transport: The transport which is delivering this response. @ivar _bodyProtocol: The L{IProtocol} provider to which the body is @@ -891,6 +870,7 @@ more data, the L{Response} moves to this state. Nothing else can happen once the L{Response} is in this state. """ + implements(IResponse) length = UNKNOWN_LENGTH @@ -909,23 +889,8 @@ def deliverBody(self, protocol): """ - Register an L{IProtocol} provider to receive the response body. - - The protocol will be connected to a transport which provides - L{IPushProducer}. The protocol's C{connectionLost} method will be - called with: - - - ResponseDone, which indicates that all bytes from the response - have been successfully delivered. - - - PotentialDataLoss, which indicates that it cannot be determined - if the entire response body has been delivered. This only occurs - when making requests to HTTP servers which do not set - I{Content-Length} or a I{Transfer-Encoding} in the response. - - - ResponseFailed, which indicates that some bytes from the response - were lost. The C{reasons} attribute of the exception may provide - more specific indications as to why. + Dispatch the given L{IProtocol} depending of the current state of the + response. """ deliverBody = makeStatefulDispatcher('deliverBody', deliverBody) diff --git a/lib/twisted-trunk/twisted/web/client.py b/lib/twisted-trunk/twisted/web/client.py --- a/lib/twisted-trunk/twisted/web/client.py +++ b/lib/twisted-trunk/twisted/web/client.py @@ -8,13 +8,20 @@ import os, types from urlparse import urlunparse +from urllib import splithost, splittype +import zlib + +from zope.interface import implements from twisted.python import log from twisted.web import http -from twisted.internet import defer, protocol, reactor +from twisted.internet import defer, protocol, task, reactor +from twisted.internet.interfaces import IProtocol from twisted.python import failure from twisted.python.util import InsensitiveDict +from twisted.python.components import proxyForInterface from twisted.web import error +from twisted.web.iweb import UNKNOWN_LENGTH, IBodyProducer, IResponse from twisted.web.http_headers import Headers from twisted.python.compat import set @@ -34,12 +41,21 @@ Typically used with L{HTTPClientFactory}. Note that this class does not, by itself, do anything with the response. If you want to download a resource into a file, use L{HTTPPageDownloader} instead. + + @ivar _completelyDone: A boolean indicating whether any further requests are + necessary after this one completes in order to provide a result to + C{self.factory.deferred}. If it is C{False}, then a redirect is going + to be followed. Otherwise, this protocol's connection is the last one + before firing the result Deferred. This is used to make sure the result + Deferred is only fired after the connection is cleaned up. """ quietLoss = 0 followRedirect = True failed = 0 + _completelyDone = True + _specialHeaders = set(('host', 'user-agent', 'cookie', 'content-length')) def connectionMade(self): @@ -128,6 +144,7 @@ self.transport.loseConnection() return + self._completelyDone = False self.factory.setURL(url) if self.factory.scheme == 'https': @@ -158,10 +175,21 @@ self.factory.method = 'GET' self.handleStatus_301() + def connectionLost(self, reason): + """ + When the connection used to issue the HTTP request is closed, notify the + factory if we have not already, so it can produce a result. + """ if not self.quietLoss: http.HTTPClient.connectionLost(self, reason) self.factory.noPage(reason) + if self._completelyDone: + # Only if we think we're completely done do we tell the factory that + # we're "disconnected". This way when we're following redirects, + # only the last protocol used will fire the _disconnectedDeferred. + self.factory._disconnectedDeferred.callback(None) + def handleResponse(self, response): if self.quietLoss: @@ -262,6 +290,12 @@ @type _redirectCount: int @ivar _redirectCount: The current number of HTTP redirects encountered. + + @ivar _disconnectedDeferred: A L{Deferred} which only fires after the last + connection associated with the request (redirects may cause multiple + connections to be required) has closed. The result Deferred will only + fire after this Deferred, so that callers can be assured that there are + no more event sources in the reactor once they get the result. """ protocol = HTTPPageGetter @@ -299,9 +333,24 @@ self.setURL(url) self.waiting = 1 + self._disconnectedDeferred = defer.Deferred() self.deferred = defer.Deferred() + # Make sure the first callback on the result Deferred pauses the + # callback chain until the request connection is closed. + self.deferred.addBoth(self._waitForDisconnect) self.response_headers = None + + def _waitForDisconnect(self, passthrough): + """ + Chain onto the _disconnectedDeferred, preserving C{passthrough}, so that + the result is only available after the associated connection has been + closed. + """ + self._disconnectedDeferred.addCallback(lambda ignored: passthrough) + return self._disconnectedDeferred + + def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.url) @@ -352,11 +401,20 @@ self.deferred.errback(reason) def clientConnectionFailed(self, _, reason): + """ + When a connection attempt fails, the request cannot be issued. If no + result has yet been provided to the result Deferred, provide the + connection failure reason as an error result. + """ if self.waiting: self.waiting = 0 + # If the connection attempt failed, there is nothing more to + # disconnect, so just fire that Deferred now. + self._disconnectedDeferred.callback(None) self.deferred.errback(reason) + class HTTPDownloader(HTTPClientFactory): """Download to a file.""" @@ -570,7 +628,7 @@ from twisted.internet.protocol import ClientCreator from twisted.web.error import SchemeNotSupported from twisted.web._newclient import ResponseDone, Request, HTTP11ClientProtocol -from twisted.web._newclient import Response +from twisted.web._newclient import Response, ResponseFailed try: from twisted.internet.ssl import ClientContextFactory @@ -621,7 +679,162 @@ -class Agent(object): +class FileBodyProducer(object): + """ + L{FileBodyProducer} produces bytes from an input file object incrementally + and writes them to a consumer. + + Since file-like objects cannot be read from in an event-driven manner, + L{FileBodyProducer} uses a L{Cooperator} instance to schedule reads from + the file. This process is also paused and resumed based on notifications + from the L{IConsumer} provider being written to. + + The file is closed after it has been read, or if the producer is stopped + early. + + @ivar _inputFile: Any file-like object, bytes read from which will be + written to a consumer. + + @ivar _cooperate: A method like L{Cooperator.cooperate} which is used to + schedule all reads. + + @ivar _readSize: The number of bytes to read from C{_inputFile} at a time. + """ + implements(IBodyProducer) + + # Python 2.4 doesn't have these symbolic constants + _SEEK_SET = getattr(os, 'SEEK_SET', 0) + _SEEK_END = getattr(os, 'SEEK_END', 2) + + def __init__(self, inputFile, cooperator=task, readSize=2 ** 16): + self._inputFile = inputFile + self._cooperate = cooperator.cooperate + self._readSize = readSize + self.length = self._determineLength(inputFile) + + + def _determineLength(self, fObj): + """ + Determine how many bytes can be read out of C{fObj} (assuming it is not + modified from this point on). If the determination cannot be made, + return C{UNKNOWN_LENGTH}. + """ + try: + seek = fObj.seek + tell = fObj.tell + except AttributeError: + return UNKNOWN_LENGTH + originalPosition = tell() + seek(0, self._SEEK_END) + end = tell() + seek(originalPosition, self._SEEK_SET) + return end - originalPosition + + + def stopProducing(self): + """ + Permanently stop writing bytes from the file to the consumer by + stopping the underlying L{CooperativeTask}. + """ + self._inputFile.close() + self._task.stop() + + + def startProducing(self, consumer): + """ + Start a cooperative task which will read bytes from the input file and + write them to C{consumer}. Return a L{Deferred} which fires after all + bytes have been written. + + @param consumer: Any L{IConsumer} provider + """ + self._task = self._cooperate(self._writeloop(consumer)) + d = self._task.whenDone() + def maybeStopped(reason): + # IBodyProducer.startProducing's Deferred isn't support to fire if + # stopProducing is called. + reason.trap(task.TaskStopped) + return defer.Deferred() + d.addCallbacks(lambda ignored: None, maybeStopped) + return d + + + def _writeloop(self, consumer): + """ + Return an iterator which reads one chunk of bytes from the input file + and writes them to the consumer for each time it is iterated. + """ + while True: + bytes = self._inputFile.read(self._readSize) + if not bytes: + self._inputFile.close() + break + consumer.write(bytes) + yield None + + + def pauseProducing(self): + """ + Temporarily suspend copying bytes from the input file to the consumer + by pausing the L{CooperativeTask} which drives that activity. + """ + self._task.pause() + + + def resumeProducing(self): + """ + Undo the effects of a previous C{pauseProducing} and resume copying + bytes to the consumer by resuming the L{CooperativeTask} which drives + the write activity. + """ + self._task.resume() + + + +class _AgentMixin(object): + """ + Base class offering facilities for L{Agent}-type classes. + + @since: 11.1 + """ + + def _connectAndRequest(self, method, uri, headers, bodyProducer, + requestPath=None): + """ + Internal helper to make the request. + + @param requestPath: If specified, the path to use for the request + instead of the path extracted from C{uri}. + """ + scheme, host, port, path = _parse(uri) + if requestPath is None: + requestPath = path + d = self._connect(scheme, host, port) + if headers is None: + headers = Headers() + if not headers.hasHeader('host'): + headers = headers.copy() + headers.addRawHeader( + 'host', self._computeHostValue(scheme, host, port)) + def cbConnected(proto): + return proto.request( + Request(method, requestPath, headers, bodyProducer)) + d.addCallback(cbConnected) + return d + + + def _computeHostValue(self, scheme, host, port): + """ + Compute the string to use for the value of the I{Host} header, based on + the given scheme, host name, and port number. + """ + if (scheme, port) in (('http', 80), ('https', 443)): + return host + return '%s:%d' % (host, port) + + + +class Agent(_AgentMixin): """ L{Agent} is a very basic HTTP client. It supports I{HTTP} and I{HTTPS} scheme URIs (but performs no certificate checking by default). It does not @@ -633,13 +846,22 @@ @ivar _contextFactory: A web context factory which will be used to create SSL context objects for any SSL connections the agent needs to make. + @ivar _connectTimeout: If not C{None}, the timeout passed to C{connectTCP} + or C{connectSSL} for specifying the connection timeout. + + @ivar _bindAddress: If not C{None}, the address passed to C{connectTCP} or + C{connectSSL} for specifying the local address to bind to. + @since: 9.0 """ _protocol = HTTP11ClientProtocol - def __init__(self, reactor, contextFactory=WebClientContextFactory()): + def __init__(self, reactor, contextFactory=WebClientContextFactory(), + connectTimeout=None, bindAddress=None): self._reactor = reactor self._contextFactory = contextFactory + self._connectTimeout = connectTimeout + self._bindAddress = bindAddress def _wrapContextFactory(self, host, port): @@ -651,9 +873,11 @@ @param host: A C{str} giving the hostname which will be connected to in order to issue a request. - @param port: An C{int} giving the port number the connection will be on. + @param port: An C{int} giving the port number the connection will be + on. - @return: A context factory suitable to be passed to C{reactor.connectSSL}. + @return: A context factory suitable to be passed to + C{reactor.connectSSL}. """ return _WebToNormalContextFactory(self._contextFactory, host, port) @@ -670,16 +894,22 @@ @param host: A C{str} giving the hostname which will be connected to in order to issue a request. - @param port: An C{int} giving the port number the connection will be on. + @param port: An C{int} giving the port number the connection will be + on. @return: A L{Deferred} which fires with a connected instance of C{self._protocol}. """ cc = ClientCreator(self._reactor, self._protocol) + kwargs = {} + if self._connectTimeout is not None: + kwargs['timeout'] = self._connectTimeout + kwargs['bindAddress'] = self._bindAddress if scheme == 'http': - d = cc.connectTCP(host, port) + d = cc.connectTCP(host, port, **kwargs) elif scheme == 'https': - d = cc.connectSSL(host, port, self._wrapContextFactory(host, port)) + d = cc.connectSSL(host, port, self._wrapContextFactory(host, port), + **kwargs) else: d = defer.fail(SchemeNotSupported( "Unsupported scheme: %r" % (scheme,))) @@ -705,42 +935,342 @@ @type bodyProducer: L{IBodyProducer} provider @return: A L{Deferred} which fires with the result of the request (a - L{Response} instance), or fails if there is a problem setting up a - connection over which to issue the request. It may also fail with - L{SchemeNotSupported} if the scheme of the given URI is not - supported. + L{twisted.web.iweb.IResponse} provider), or fails if there is a + problem setting up a connection over which to issue the request. + It may also fail with L{SchemeNotSupported} if the scheme of the + given URI is not supported. @rtype: L{Deferred} """ - scheme, host, port, path = _parse(uri) - d = self._connect(scheme, host, port) + return self._connectAndRequest(method, uri, headers, bodyProducer) + + + +class _HTTP11ClientFactory(protocol.ClientFactory): + """ + A simple factory for L{HTTP11ClientProtocol}, used by L{ProxyAgent}. + + @since: 11.1 + """ + protocol = HTTP11ClientProtocol + + + +class ProxyAgent(_AgentMixin): + """ + An HTTP agent able to cross HTTP proxies. + + @ivar _factory: The factory used to connect to the proxy. + + @ivar _proxyEndpoint: The endpoint used to connect to the proxy, passing + the factory. + + @since: 11.1 + """ + + _factory = _HTTP11ClientFactory + + def __init__(self, endpoint): + self._proxyEndpoint = endpoint + + + def _connect(self, scheme, host, port): + """ + Ignore the connection to the expected host, and connect to the proxy + instead. + """ + return self._proxyEndpoint.connect(self._factory()) + + + def request(self, method, uri, headers=None, bodyProducer=None): + """ + Issue a new request via the configured proxy. + """ + return self._connectAndRequest(method, uri, headers, bodyProducer, + requestPath=uri) + + + +class _FakeUrllib2Request(object): + """ + A fake C{urllib2.Request} object for C{cookielib} to work with. + + @see: U{http://docs.python.org/library/urllib2.html#request-objects} + + @type uri: C{str} + @ivar uri: Request URI. + + @type headers: L{twisted.web.http_headers.Headers} + @ivar headers: Request headers. + + @type type: C{str} + @ivar type: The scheme of the URI. + + @type host: C{str} + @ivar host: The host[:port] of the URI. + + @since: 11.1 + """ + def __init__(self, uri): + self.uri = uri + self.headers = Headers() + self.type, rest = splittype(self.uri) + self.host, rest = splithost(rest) + + + def has_header(self, header): + return self.headers.hasHeader(header) + + + def add_unredirected_header(self, name, value): + self.headers.addRawHeader(name, value) + + + def get_full_url(self): + return self.uri + + + def get_header(self, name, default=None): + headers = self.headers.getRawHeaders(name, default) + if headers is not None: + return headers[0] + return None + + + def get_host(self): + return self.host + + + def get_type(self): + return self.type + + + def is_unverifiable(self): + # In theory this shouldn't be hardcoded. + return False + + + +class _FakeUrllib2Response(object): + """ + A fake C{urllib2.Response} object for C{cookielib} to work with. + + @type response: C{twisted.web.iweb.IResponse} + @ivar response: Underlying Twisted Web response. + + @since: 11.1 + """ + def __init__(self, response): + self.response = response + + + def info(self): + class _Meta(object): + def getheaders(zelf, name): + return self.response.headers.getRawHeaders(name, []) + return _Meta() + + + +class CookieAgent(object): + """ + L{CookieAgent} extends the basic L{Agent} to add RFC-compliant + handling of HTTP cookies. Cookies are written to and extracted + from a C{cookielib.CookieJar} instance. + + The same cookie jar instance will be used for any requests through this + agent, mutating it whenever a I{Set-Cookie} header appears in a response. + + @type _agent: L{twisted.web.client.Agent} + @ivar _agent: Underlying Twisted Web agent to issue requests through. + + @type cookieJar: C{cookielib.CookieJar} + @ivar cookieJar: Initialized cookie jar to read cookies from and store + cookies to. + + @since: 11.1 + """ + def __init__(self, agent, cookieJar): + self._agent = agent + self.cookieJar = cookieJar + + + def request(self, method, uri, headers=None, bodyProducer=None): + """ + Issue a new request to the wrapped L{Agent}. + + Send a I{Cookie} header if a cookie for C{uri} is stored in + L{CookieAgent.cookieJar}. Cookies are automatically extracted and + stored from requests. + + If a C{'cookie'} header appears in C{headers} it will override the + automatic cookie header obtained from the cookie jar. + + @see: L{Agent.request} + """ if headers is None: headers = Headers() - if not headers.hasHeader('host'): - # This is a lot of copying. It might be nice if there were a bit - # less. - headers = Headers(dict(headers.getAllRawHeaders())) - headers.addRawHeader( - 'host', self._computeHostValue(scheme, host, port)) - def cbConnected(proto): - return proto.request(Request(method, path, headers, bodyProducer)) - d.addCallback(cbConnected) + lastRequest = _FakeUrllib2Request(uri) + # Setting a cookie header explicitly will disable automatic request + # cookies. + if not headers.hasHeader('cookie'): + self.cookieJar.add_cookie_header(lastRequest) + cookieHeader = lastRequest.get_header('Cookie', None) + if cookieHeader is not None: + headers = headers.copy() + headers.addRawHeader('cookie', cookieHeader) + + d = self._agent.request(method, uri, headers, bodyProducer) + d.addCallback(self._extractCookies, lastRequest) return d - def _computeHostValue(self, scheme, host, port): + def _extractCookies(self, response, request): """ - Compute the string to use for the value of the I{Host} header, based on - the given scheme, host name, and port number. + Extract response cookies and store them in the cookie jar. + + @type response: L{twisted.web.iweb.IResponse} + @param response: Twisted Web response. + + @param request: A urllib2 compatible request object. """ - if (scheme, port) in (('http', 80), ('https', 443)): - return host - return '%s:%d' % (host, port) + resp = _FakeUrllib2Response(response) + self.cookieJar.extract_cookies(resp, request) + return response + + + +class GzipDecoder(proxyForInterface(IResponse)): + """ + A wrapper for a L{Response} instance which handles gzip'ed body. + + @ivar original: The original L{Response} object. + + @since: 11.1 + """ + + def __init__(self, response): + self.original = response + self.length = UNKNOWN_LENGTH + + + def deliverBody(self, protocol): + """ + Override C{deliverBody} to wrap the given C{protocol} with + L{_GzipProtocol}. + """ + self.original.deliverBody(_GzipProtocol(protocol)) + + + +class _GzipProtocol(proxyForInterface(IProtocol)): + """ + A L{Protocol} implementation which wraps another one, transparently + decompressing received data. + + @ivar _zlibDecompress: A zlib decompress object used to decompress the data + stream. + + @since: 11.1 + """ + + def __init__(self, protocol): + self.original = protocol + self._zlibDecompress = zlib.decompressobj(16 + zlib.MAX_WBITS) + + + def dataReceived(self, data): + """ + Decompress C{data} with the zlib decompressor, forwarding the raw data + to the original protocol. + """ + try: + rawData = self._zlibDecompress.decompress(data) + except zlib.error: + raise ResponseFailed([failure.Failure()]) + if rawData: + self.original.dataReceived(rawData) + + + def connectionLost(self, reason): + """ + Forward the connection lost event, flushing remaining data from the + decompressor if any. + """ + try: + rawData = self._zlibDecompress.flush() + except zlib.error: + raise ResponseFailed([reason, failure.Failure()]) + if rawData: + self.original.dataReceived(rawData) + self.original.connectionLost(reason) + + + +class ContentDecoderAgent(object): + """ + An L{Agent} wrapper to handle encoded content. + + It takes care of declaring the support for content in the + I{Accept-Encoding} header, and automatically decompresses the received data + if it's effectively using compression. + + @param decoders: A list or tuple of (name, decoder) objects. The name + declares which decoding the decoder supports, and the decoder must + return a response object when called/instantiated. For example, + C{(('gzip', GzipDecoder))}. The order determines how the decoders are + going to be advertized to the server. + + @since: 11.1 + """ + + def __init__(self, agent, decoders): + self._agent = agent + self._decoders = dict(decoders) + self._supported = ','.join([decoder[0] for decoder in decoders]) + + + def request(self, method, uri, headers=None, bodyProducer=None): + """ + Send a client request which declares supporting compressed content. + + @see: L{Agent.request}. + """ + if headers is None: + headers = Headers() + else: + headers = headers.copy() + headers.addRawHeader('accept-encoding', self._supported) + deferred = self._agent.request(method, uri, headers, bodyProducer) + return deferred.addCallback(self._handleResponse) + + + def _handleResponse(self, response): + """ + Check if the response is encoded, and wrap it to handle decompression. + """ + contentEncodingHeaders = response.headers.getRawHeaders( + 'content-encoding', []) + contentEncodingHeaders = ','.join(contentEncodingHeaders).split(',') + while contentEncodingHeaders: + name = contentEncodingHeaders.pop().strip() + decoder = self._decoders.get(name) + if decoder is not None: + response = decoder(response) + else: + # Add it back + contentEncodingHeaders.append(name) + break + if contentEncodingHeaders: + response.headers.setRawHeaders( + 'content-encoding', [','.join(contentEncodingHeaders)]) + else: + response.headers.removeHeader('content-encoding') + return response __all__ = [ - 'PartialDownloadError', - 'HTTPPageGetter', 'HTTPPageDownloader', 'HTTPClientFactory', 'HTTPDownloader', - 'getPage', 'downloadPage', - - 'ResponseDone', 'Response', 'Agent'] + 'PartialDownloadError', 'HTTPPageGetter', 'HTTPPageDownloader', + 'HTTPClientFactory', 'HTTPDownloader', 'getPage', 'downloadPage', + 'ResponseDone', 'Response', 'ResponseFailed', 'Agent', 'CookieAgent', + 'ProxyAgent', 'ContentDecoderAgent', 'GzipDecoder'] diff --git a/lib/twisted-trunk/twisted/web/http_headers.py b/lib/twisted-trunk/twisted/web/http_headers.py --- a/lib/twisted-trunk/twisted/web/http_headers.py +++ b/lib/twisted-trunk/twisted/web/http_headers.py @@ -145,7 +145,7 @@ self._rawHeaders = {} if rawHeaders is not None: for name, values in rawHeaders.iteritems(): - self.setRawHeaders(name, values) + self.setRawHeaders(name, values[:]) def __repr__(self): @@ -165,6 +165,13 @@ return NotImplemented + def copy(self): + """ + Return a copy of itself with the same headers set. + """ + return self.__class__(self._rawHeaders) + + def hasHeader(self, name): """ Check for the existence of a given header. diff --git a/lib/twisted-trunk/twisted/web/iweb.py b/lib/twisted-trunk/twisted/web/iweb.py --- a/lib/twisted-trunk/twisted/web/iweb.py +++ b/lib/twisted-trunk/twisted/web/iweb.py @@ -463,10 +463,64 @@ +class IResponse(Interface): + """ + An object representing an HTTP response received from an HTTP server. + + @since: 11.1 + """ + + version = Attribute( + "A three-tuple describing the protocol and protocol version " + "of the response. The first element is of type C{str}, the second " + "and third are of type C{int}. For example, C{('HTTP', 1, 1)}.") + + + code = Attribute("The HTTP status code of this response, as a C{int}.") + + + phrase = Attribute( + "The HTTP reason phrase of this response, as a C{str}.") + + + headers = Attribute("The HTTP response L{Headers} of this response.") + + + length = Attribute( + "The C{int} number of bytes expected to be in the body of this " + "response or L{UNKNOWN_LENGTH} if the server did not indicate how " + "many bytes to expect. For I{HEAD} responses, this will be 0; if " + "the response includes a I{Content-Length} header, it will be " + "available in C{headers}.") + + + def deliverBody(protocol): + """ + Register an L{IProtocol} provider to receive the response body. + + The protocol will be connected to a transport which provides + L{IPushProducer}. The protocol's C{connectionLost} method will be + called with: + + - ResponseDone, which indicates that all bytes from the response + have been successfully delivered. + + - PotentialDataLoss, which indicates that it cannot be determined + if the entire response body has been delivered. This only occurs + when making requests to HTTP servers which do not set + I{Content-Length} or a I{Transfer-Encoding} in the response. + + - ResponseFailed, which indicates that some bytes from the response + were lost. The C{reasons} attribute of the exception may provide + more specific indications as to why. + """ + + + UNKNOWN_LENGTH = u"twisted.web.iweb.UNKNOWN_LENGTH" __all__ = [ "IUsernameDigestHash", "ICredentialFactory", "IRequest", - "IBodyProducer", "IRenderable", + "IBodyProducer", "IRenderable", "IResponse", "UNKNOWN_LENGTH"] diff --git a/lib/twisted-trunk/twisted/web/sux.py b/lib/twisted-trunk/twisted/web/sux.py --- a/lib/twisted-trunk/twisted/web/sux.py +++ b/lib/twisted-trunk/twisted/web/sux.py @@ -20,7 +20,7 @@ option, they're not on by default). """ -from twisted.internet.protocol import Protocol, FileWrapper +from twisted.internet.protocol import Protocol from twisted.python.reflect import prefixedMethodNames @@ -635,23 +635,3 @@ Default behaviour is to print.''' print 'end', name - -if __name__ == '__main__': - from cStringIO import StringIO - testDocument = ''' - - - - - A - - boz &zop; - - - ''' - x = XMLParser() - x.makeConnection(FileWrapper(StringIO())) - # fn = "/home/glyph/Projects/Twisted/doc/howto/ipc10paper.html" - fn = "/home/glyph/gruesome.xml" - # testDocument = open(fn).read() - x.dataReceived(testDocument) diff --git a/lib/twisted-trunk/twisted/web/test/test_cgi.py b/lib/twisted-trunk/twisted/web/test/test_cgi.py --- a/lib/twisted-trunk/twisted/web/test/test_cgi.py +++ b/lib/twisted-trunk/twisted/web/test/test_cgi.py @@ -109,7 +109,7 @@ def _testCGI_1(self, res): - self.failUnlessEqual(res, "cgi output" + os.linesep) + self.assertEqual(res, "cgi output" + os.linesep) def test_protectedServerAndDate(self): @@ -142,7 +142,7 @@ factory = client.HTTPClientFactory(url) reactor.connectTCP('localhost', portnum, factory) def checkResponse(ignored): - self.assertEquals( + self.assertEqual( factory.response_headers['content-type'], ['text/cgi-duplicate-test']) factory.deferred.addCallback(checkResponse) return factory.deferred @@ -160,7 +160,7 @@ factory = client.HTTPClientFactory(url) reactor.connectTCP('localhost', portnum, factory) def checkResponse(ignored): - self.assertEquals( + self.assertEqual( factory.response_headers['header'], ['spam', 'eggs']) factory.deferred.addCallback(checkResponse) return factory.deferred @@ -178,7 +178,7 @@ return d testReadEmptyInput.timeout = 5 def _testReadEmptyInput_1(self, res): - self.failUnlessEqual(res, "readinput ok%s" % os.linesep) + self.assertEqual(res, "readinput ok%s" % os.linesep) def testReadInput(self): cgiFilename = os.path.abspath(self.mktemp()) @@ -194,7 +194,7 @@ return d testReadInput.timeout = 5 def _testReadInput_1(self, res): - self.failUnlessEqual(res, "readinput ok%s" % os.linesep) + self.assertEqual(res, "readinput ok%s" % os.linesep) def testReadAllInput(self): @@ -211,7 +211,7 @@ return d testReadAllInput.timeout = 5 def _testReadAllInput_1(self, res): - self.failUnlessEqual(res, "readallinput ok%s" % os.linesep) + self.assertEqual(res, "readallinput ok%s" % os.linesep) @@ -282,8 +282,8 @@ twcgi.PHP3Script warnings = self.flushWarnings([self.test_PHP3ScriptIsDeprecated]) - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) self.assertIn("PHP3Script is deprecated. " "Use twisted.web.twcgi.FilteredScript instead.", warnings[0]['message']) @@ -296,8 +296,8 @@ twcgi.PHPScript warnings = self.flushWarnings([self.test_PHPScriptIsDeprecated]) - self.assertEquals(len(warnings), 1) - self.assertEquals(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 1) + self.assertEqual(warnings[0]['category'], DeprecationWarning) self.assertIn("PHPScript is deprecated. " "Use twisted.web.twcgi.FilteredScript instead.", warnings[0]['message']) diff --git a/lib/twisted-trunk/twisted/web/test/test_distrib.py b/lib/twisted-trunk/twisted/web/test/test_distrib.py --- a/lib/twisted-trunk/twisted/web/test/test_distrib.py +++ b/lib/twisted-trunk/twisted/web/test/test_distrib.py @@ -88,7 +88,7 @@ self.port2 = reactor.listenTCP(0, f2) d = client.getPage("http://127.0.0.1:%d/here/there" % \ self.port2.getHost().port) - d.addCallback(self.failUnlessEqual, 'root') + d.addCallback(self.assertEqual, 'root') return d @@ -141,7 +141,7 @@ request = self._requestTest( ReportRequestHeaders(), headers={'foo': 'bar'}) def cbRequested(result): - self.assertEquals(requestHeaders['Foo'], ['bar']) + self.assertEqual(requestHeaders['Foo'], ['bar']) request.addCallback(cbRequested) return request @@ -159,7 +159,7 @@ return server.NOT_DONE_YET request = self._requestTest(LargeWrite()) - request.addCallback(self.assertEquals, 'x' * SIZE_LIMIT + 'y') + request.addCallback(self.assertEqual, 'x' * SIZE_LIMIT + 'y') return request @@ -173,7 +173,7 @@ return 'x' * SIZE_LIMIT + 'y' request = self._requestTest(LargeReturn()) - request.addCallback(self.assertEquals, 'x' * SIZE_LIMIT + 'y') + request.addCallback(self.assertEqual, 'x' * SIZE_LIMIT + 'y') return request diff --git a/lib/twisted-trunk/twisted/web/test/test_domhelpers.py b/lib/twisted-trunk/twisted/web/test/test_domhelpers.py --- a/lib/twisted-trunk/twisted/web/test/test_domhelpers.py +++ b/lib/twisted-trunk/twisted/web/test/test_domhelpers.py @@ -27,7 +27,7 @@ doc1 = self.dom.parseString('') actual=domhelpers.getElementsByTagName(doc1, 'foo')[0].nodeName expected='foo' - self.assertEquals(actual, expected) + self.assertEqual(actual, expected) el1=doc1.documentElement actual=domhelpers.getElementsByTagName(el1, 'foo')[0].nodeName self.assertEqual(actual, expected) @@ -37,7 +37,7 @@ tag_list=domhelpers.getElementsByTagName(doc2, 'foo') actual=''.join([node.getAttribute('in') for node in tag_list]) expected='abcdefgh' - self.assertEquals(actual, expected) + self.assertEqual(actual, expected) el2=doc2.documentElement tag_list=domhelpers.getElementsByTagName(el2, 'foo') actual=''.join([node.getAttribute('in') for node in tag_list]) @@ -64,7 +64,7 @@ tag_list=domhelpers.getElementsByTagName(doc3, 'foo') actual=''.join([node.getAttribute('in') for node in tag_list]) expected='abdgheicfj' - self.assertEquals(actual, expected) + self.assertEqual(actual, expected) el3=doc3.documentElement tag_list=domhelpers.getElementsByTagName(el3, 'foo') actual=''.join([node.getAttribute('in') for node in tag_list]) @@ -75,7 +75,7 @@ actual=domhelpers.getElementsByTagName(doc4, 'foo') root=doc4.documentElement expected=[root, root.childNodes[-1].childNodes[0]] - self.assertEquals(actual, expected) + self.assertEqual(actual, expected) actual=domhelpers.getElementsByTagName(root, 'foo') self.assertEqual(actual, expected) diff --git a/lib/twisted-trunk/twisted/web/test/test_error.py b/lib/twisted-trunk/twisted/web/test/test_error.py --- a/lib/twisted-trunk/twisted/web/test/test_error.py +++ b/lib/twisted-trunk/twisted/web/test/test_error.py @@ -19,7 +19,7 @@ descriptive string to which C{message} is assigned. """ e = error.Error("200") - self.assertEquals(e.message, "OK") + self.assertEqual(e.message, "OK") def test_noMessageInvalidStatus(self): @@ -28,7 +28,7 @@ C{code} isn't a valid HTTP status code, C{message} stays C{None}. """ e = error.Error("InvalidCode") - self.assertEquals(e.message, None) + self.assertEqual(e.message, None) def test_messageExists(self): @@ -37,7 +37,7 @@ C{message} isn't affected by the value of C{status}. """ e = error.Error("200", "My own message") - self.assertEquals(e.message, "My own message") + self.assertEqual(e.message, "My own message") @@ -52,7 +52,7 @@ to a descriptive string to which C{message} is assigned. """ e = error.PageRedirect("200", location="/foo") - self.assertEquals(e.message, "OK to /foo") + self.assertEqual(e.message, "OK to /foo") def test_noMessageValidStatusNoLocation(self): @@ -63,7 +63,7 @@ C{message} is assigned without trying to include an empty location. """ e = error.PageRedirect("200") - self.assertEquals(e.message, "OK") + self.assertEqual(e.message, "OK") def test_noMessageInvalidStatusLocationExists(self): @@ -72,7 +72,7 @@ and C{code} isn't a valid HTTP status code, C{message} stays C{None}. """ e = error.PageRedirect("InvalidCode", location="/foo") - self.assertEquals(e.message, None) + self.assertEqual(e.message, None) def test_messageExistsLocationExists(self): @@ -81,7 +81,7 @@ the C{message} isn't affected by the value of C{status}. """ e = error.PageRedirect("200", "My own message", location="/foo") - self.assertEquals(e.message, "My own message to /foo") + self.assertEqual(e.message, "My own message to /foo") def test_messageExistsNoLocation(self): @@ -91,7 +91,7 @@ location. """ e = error.PageRedirect("200", "My own message") - self.assertEquals(e.message, "My own message") + self.assertEqual(e.message, "My own message") @@ -107,7 +107,7 @@ assigned. """ e = error.InfiniteRedirection("200", location="/foo") - self.assertEquals(e.message, "OK to /foo") + self.assertEqual(e.message, "OK to /foo") def test_noMessageValidStatusNoLocation(self): @@ -119,7 +119,7 @@ location. """ e = error.InfiniteRedirection("200") - self.assertEquals(e.message, "OK") + self.assertEqual(e.message, "OK") def test_noMessageInvalidStatusLocationExists(self): @@ -129,7 +129,7 @@ C{None}. """ e = error.InfiniteRedirection("InvalidCode", location="/foo") - self.assertEquals(e.message, None) + self.assertEqual(e.message, None) def test_messageExistsLocationExists(self): @@ -138,7 +138,7 @@ constructor, the C{message} isn't affected by the value of C{status}. """ e = error.InfiniteRedirection("200", "My own message", location="/foo") - self.assertEquals(e.message, "My own message to /foo") + self.assertEqual(e.message, "My own message to /foo") def test_messageExistsNoLocation(self): @@ -148,4 +148,4 @@ include the empty location. """ e = error.InfiniteRedirection("200", "My own message") - self.assertEquals(e.message, "My own message") + self.assertEqual(e.message, "My own message") diff --git a/lib/twisted-trunk/twisted/web/test/test_http.py b/lib/twisted-trunk/twisted/web/test/test_http.py --- a/lib/twisted-trunk/twisted/web/test/test_http.py +++ b/lib/twisted-trunk/twisted/web/test/test_http.py @@ -31,7 +31,7 @@ time = random.randint(0, 2000000000) timestr = http.datetimeToString(time) time2 = http.stringToDatetime(timestr) - self.assertEquals(time, time2) + self.assertEqual(time, time2) class DummyHTTPHandler(http.Request): @@ -216,7 +216,7 @@ def assertResponseEquals(self, response, expectedResponse): - self.assertEquals(response, expectedResponse) + self.assertEqual(response, expectedResponse) class HTTPLoopbackTestCase(unittest.TestCase): @@ -232,20 +232,20 @@ def _handleStatus(self, version, status, message): self.gotStatus = 1 - self.assertEquals(version, "HTTP/1.0") - self.assertEquals(status, "200") + self.assertEqual(version, "HTTP/1.0") + self.assertEqual(status, "200") def _handleResponse(self, data): self.gotResponse = 1 - self.assertEquals(data, "'''\n10\n0123456789'''\n") + self.assertEqual(data, "'''\n10\n0123456789'''\n") def _handleHeader(self, key, value): self.numHeaders = self.numHeaders + 1 - self.assertEquals(self.expectedHeaders[key.lower()], value) + self.assertEqual(self.expectedHeaders[key.lower()], value) def _handleEndHeaders(self): self.gotEndHeaders = 1 - self.assertEquals(self.numHeaders, 4) + self.assertEqual(self.numHeaders, 4) def testLoopback(self): server = http.HTTPChannel() @@ -298,9 +298,9 @@ c = http.HTTPChannel() for req, version, correctResult, resultHeaders in self.ptests: result = c.checkPersistence(req, version) - self.assertEquals(result, correctResult) + self.assertEqual(result, correctResult) for header in resultHeaders.keys(): - self.assertEquals(req.responseHeaders.getRawHeaders(header, None), resultHeaders[header]) + self.assertEqual(req.responseHeaders.getRawHeaders(header, None), resultHeaders[header]) @@ -583,7 +583,7 @@ def testChunks(self): for s in self.strings: - self.assertEquals((s, ''), http.fromChunk(''.join(http.toChunk(s)))) + self.assertEqual((s, ''), http.fromChunk(''.join(http.toChunk(s)))) self.assertRaises(ValueError, http.fromChunk, '-5\r\nmalformed!\r\n') def testConcatenatedChunks(self): @@ -597,7 +597,7 @@ result.append(data) except ValueError: pass - self.assertEquals(result, self.strings) + self.assertEqual(result, self.strings) @@ -618,7 +618,7 @@ a.dataReceived(byte) a.connectionLost(IOError("all done")) if success: - self.assertEquals(self.didRequest, 1) + self.assertEqual(self.didRequest, 1) del self.didRequest else: self.assert_(not hasattr(self, "didRequest")) @@ -635,8 +635,8 @@ class Request(http.Request): l = [] def process(self): - testcase.assertEquals(self.getUser(), self.l[0]) - testcase.assertEquals(self.getPassword(), self.l[1]) + testcase.assertEqual(self.getUser(), self.l[0]) + testcase.assertEqual(self.getPassword(), self.l[1]) for u, p in [("foo", "bar"), ("hello", "there:z")]: Request.l[:] = [u, p] s = "%s:%s" % (u, p) @@ -665,9 +665,9 @@ self.runRequest('\n'.join(requestLines), MyRequest, 0) [request] = processed - self.assertEquals( + self.assertEqual( request.requestHeaders.getRawHeaders('foo'), ['bar']) - self.assertEquals( + self.assertEqual( request.requestHeaders.getRawHeaders('bAz'), ['Quux', 'quux']) @@ -747,9 +747,9 @@ class MyRequest(http.Request): def process(self): - testcase.assertEquals(self.getCookie('rabbit'), '"eat carrot"') - testcase.assertEquals(self.getCookie('ninja'), 'secret') - testcase.assertEquals(self.getCookie('spam'), '"hey 1=1!"') + testcase.assertEqual(self.getCookie('rabbit'), '"eat carrot"') + testcase.assertEqual(self.getCookie('ninja'), 'secret') + testcase.assertEqual(self.getCookie('spam'), '"hey 1=1!"') testcase.didRequest = 1 self.finish() @@ -763,10 +763,10 @@ testcase = self class MyRequest(http.Request): def process(self): - testcase.assertEquals(self.method, "GET") - testcase.assertEquals(self.args["key"], ["value"]) - testcase.assertEquals(self.args["empty"], [""]) - testcase.assertEquals(self.args["multiple"], ["two words", "more words"]) + testcase.assertEqual(self.method, "GET") + testcase.assertEqual(self.args["key"], ["value"]) + testcase.assertEqual(self.args["empty"], [""]) + testcase.assertEqual(self.args["multiple"], ["two words", "more words"]) testcase.didRequest = 1 self.finish() @@ -813,14 +813,14 @@ testcase = self class MyRequest(http.Request): def process(self): - testcase.assertEquals(self.method, "POST") - testcase.assertEquals(self.args["key"], ["value"]) - testcase.assertEquals(self.args["empty"], [""]) - testcase.assertEquals(self.args["multiple"], ["two words", "more words"]) + testcase.assertEqual(self.method, "POST") + testcase.assertEqual(self.args["key"], ["value"]) + testcase.assertEqual(self.args["empty"], [""]) + testcase.assertEqual(self.args["multiple"], ["two words", "more words"]) # Reading from the content file-like must produce the entire # request body. - testcase.assertEquals(self.content.read(), query) + testcase.assertEqual(self.content.read(), query) testcase.didRequest = 1 self.finish() @@ -882,13 +882,13 @@ class QueryArgumentsTestCase(unittest.TestCase): def testParseqs(self): - self.failUnlessEqual(cgi.parse_qs("a=b&d=c;+=f"), + self.assertEqual(cgi.parse_qs("a=b&d=c;+=f"), http.parse_qs("a=b&d=c;+=f")) self.failUnlessRaises(ValueError, http.parse_qs, "blah", strict_parsing = 1) - self.failUnlessEqual(cgi.parse_qs("a=&b=c", keep_blank_values = 1), + self.assertEqual(cgi.parse_qs("a=&b=c", keep_blank_values = 1), http.parse_qs("a=&b=c", keep_blank_values = 1)) - self.failUnlessEqual(cgi.parse_qs("a=&b=c"), + self.assertEqual(cgi.parse_qs("a=&b=c"), http.parse_qs("a=&b=c")) @@ -965,23 +965,23 @@ def testBaseline(self): c = ClientDriver() c.lineReceived('HTTP/1.0 201 foo') - self.failUnlessEqual(c.version, 'HTTP/1.0') - self.failUnlessEqual(c.status, '201') - self.failUnlessEqual(c.message, 'foo') + self.assertEqual(c.version, 'HTTP/1.0') + self.assertEqual(c.status, '201') + self.assertEqual(c.message, 'foo') def testNoMessage(self): c = ClientDriver() c.lineReceived('HTTP/1.0 201') - self.failUnlessEqual(c.version, 'HTTP/1.0') - self.failUnlessEqual(c.status, '201') - self.failUnlessEqual(c.message, '') + self.assertEqual(c.version, 'HTTP/1.0') + self.assertEqual(c.status, '201') + self.assertEqual(c.message, '') def testNoMessage_trailingSpace(self): c = ClientDriver() c.lineReceived('HTTP/1.0 201 ') - self.failUnlessEqual(c.version, 'HTTP/1.0') - self.failUnlessEqual(c.status, '201') - self.failUnlessEqual(c.message, '') + self.assertEqual(c.version, 'HTTP/1.0') + self.assertEqual(c.status, '201') + self.assertEqual(c.message, '') @@ -1031,7 +1031,7 @@ """ req = http.Request(DummyChannel(), None) req.requestHeaders.setRawHeaders("test", ["lemur"]) - self.assertEquals(req.getHeader("test"), "lemur") + self.assertEqual(req.getHeader("test"), "lemur") def test_getHeaderReceivedMultiples(self): @@ -1041,7 +1041,7 @@ """ req = http.Request(DummyChannel(), None) req.requestHeaders.setRawHeaders("test", ["lemur", "panda"]) - self.assertEquals(req.getHeader("test"), "panda") + self.assertEqual(req.getHeader("test"), "panda") def test_getHeaderNotFound(self): @@ -1050,7 +1050,7 @@ request header which is not present. """ req = http.Request(DummyChannel(), None) - self.assertEquals(req.getHeader("test"), None) + self.assertEqual(req.getHeader("test"), None) def test_getAllHeaders(self): @@ -1060,7 +1060,7 @@ """ req = http.Request(DummyChannel(), None) req.requestHeaders.setRawHeaders("test", ["lemur"]) - self.assertEquals(req.getAllHeaders(), {"test": "lemur"}) + self.assertEqual(req.getAllHeaders(), {"test": "lemur"}) def test_getAllHeadersNoHeaders(self): @@ -1069,7 +1069,7 @@ request headers. """ req = http.Request(DummyChannel(), None) - self.assertEquals(req.getAllHeaders(), {}) + self.assertEqual(req.getAllHeaders(), {}) def test_getAllHeadersMultipleHeaders(self): @@ -1079,7 +1079,7 @@ """ req = http.Request(DummyChannel(), None) req.requestHeaders.setRawHeaders("test", ["lemur", "panda"]) - self.assertEquals(req.getAllHeaders(), {"test": "panda"}) + self.assertEqual(req.getAllHeaders(), {"test": "panda"}) def test_setResponseCode(self): @@ -1128,7 +1128,7 @@ """ req = http.Request(DummyChannel(), None) req.setHost("example.com", 80) - self.assertEquals( + self.assertEqual( req.requestHeaders.getRawHeaders("host"), ["example.com"]) @@ -1141,7 +1141,7 @@ d.transport = DummyChannel.SSL() req = http.Request(d, None) req.setHost("example.com", 443) - self.assertEquals( + self.assertEqual( req.requestHeaders.getRawHeaders("host"), ["example.com"]) @@ -1152,7 +1152,7 @@ """ req = http.Request(DummyChannel(), None) req.setHost("example.com", 81) - self.assertEquals( + self.assertEqual( req.requestHeaders.getRawHeaders("host"), ["example.com:81"]) @@ -1165,7 +1165,7 @@ d.transport = DummyChannel.SSL() req = http.Request(d, None) req.setHost("example.com", 81) - self.assertEquals( + self.assertEqual( req.requestHeaders.getRawHeaders("host"), ["example.com:81"]) @@ -1175,7 +1175,7 @@ """ req = http.Request(DummyChannel(), None) req.setHeader("test", "lemur") - self.assertEquals(req.responseHeaders.getRawHeaders("test"), ["lemur"]) + self.assertEqual(req.responseHeaders.getRawHeaders("test"), ["lemur"]) def test_firstWrite(self): @@ -1259,7 +1259,7 @@ req.requestHeaders.setRawHeaders( "cookie", ['test="lemur"; test2="panda"']) req.parseCookies() - self.assertEquals(req.received_cookies, {"test": '"lemur"', + self.assertEqual(req.received_cookies, {"test": '"lemur"', "test2": '"panda"'}) @@ -1272,7 +1272,7 @@ req.requestHeaders.setRawHeaders( "cookie", ['test="lemur"', 'test2="panda"']) req.parseCookies() - self.assertEquals(req.received_cookies, {"test": '"lemur"', + self.assertEqual(req.received_cookies, {"test": '"lemur"', "test2": '"panda"'}) @@ -1317,7 +1317,7 @@ req = http.Request(DummyChannel(), True) producer = DummyProducer() req.registerProducer(producer, True) - self.assertEquals(['pause'], producer.events) + self.assertEqual(['pause'], producer.events) def test_registerProducerWhenQueuedDoesntPausePullProducer(self): @@ -1329,7 +1329,7 @@ req = http.Request(DummyChannel(), True) producer = DummyProducer() req.registerProducer(producer, False) - self.assertEquals([], producer.events) + self.assertEqual([], producer.events) def test_registerProducerWhenQueuedDoesntRegisterPushProducer(self): @@ -1379,7 +1379,7 @@ req = http.Request(DummyChannel(), False) producer = DummyProducer() req.registerProducer(producer, True) - self.assertEquals([(producer, True)], req.transport.producers) + self.assertEqual([(producer, True)], req.transport.producers) def test_registerProducerWhenNotQueuedRegistersPullProducer(self): @@ -1391,7 +1391,7 @@ req = http.Request(DummyChannel(), False) producer = DummyProducer() req.registerProducer(producer, False) - self.assertEquals([(producer, False)], req.transport.producers) + self.assertEqual([(producer, False)], req.transport.producers) def test_connectionLostNotification(self): @@ -1475,7 +1475,7 @@ Dummy implementation of L{HTTPClient.handleHeader}. """ self.handleHeaderCalled = True - self.assertEquals(val, self.expectedHeaders[key]) + self.assertEqual(val, self.expectedHeaders[key]) def ourHandleEndHeaders(self): @@ -1506,7 +1506,7 @@ self.assertTrue(self.handleHeaderCalled) self.assertTrue(self.handleEndHeadersCalled) - self.assertEquals(c.length, 10) + self.assertEqual(c.length, 10) def test_noHeaders(self): @@ -1525,8 +1525,8 @@ self.assertFalse(self.handleHeaderCalled) self.assertTrue(self.handleEndHeadersCalled) - self.assertEquals(c.version, 'HTTP/1.0') - self.assertEquals(c.status, '201') + self.assertEqual(c.version, 'HTTP/1.0') + self.assertEqual(c.status, '201') def test_multilineHeaders(self): @@ -1555,6 +1555,6 @@ c.lineReceived('') self.assertTrue(self.handleEndHeadersCalled) - self.assertEquals(c.version, 'HTTP/1.0') - self.assertEquals(c.status, '201') - self.assertEquals(c.length, 10) + self.assertEqual(c.version, 'HTTP/1.0') + self.assertEqual(c.status, '201') + self.assertEqual(c.length, 10) diff --git a/lib/twisted-trunk/twisted/web/test/test_http_headers.py b/lib/twisted-trunk/twisted/web/test/test_http_headers.py --- a/lib/twisted-trunk/twisted/web/test/test_http_headers.py +++ b/lib/twisted-trunk/twisted/web/test/test_http_headers.py @@ -138,16 +138,16 @@ the given header. """ h = Headers() - self.assertEquals(h._canonicalNameCaps("test"), "Test") - self.assertEquals(h._canonicalNameCaps("test-stuff"), "Test-Stuff") - self.assertEquals(h._canonicalNameCaps("content-md5"), "Content-MD5") - self.assertEquals(h._canonicalNameCaps("dnt"), "DNT") - self.assertEquals(h._canonicalNameCaps("etag"), "ETag") - self.assertEquals(h._canonicalNameCaps("p3p"), "P3P") - self.assertEquals(h._canonicalNameCaps("te"), "TE") - self.assertEquals(h._canonicalNameCaps("www-authenticate"), + self.assertEqual(h._canonicalNameCaps("test"), "Test") + self.assertEqual(h._canonicalNameCaps("test-stuff"), "Test-Stuff") + self.assertEqual(h._canonicalNameCaps("content-md5"), "Content-MD5") + self.assertEqual(h._canonicalNameCaps("dnt"), "DNT") + self.assertEqual(h._canonicalNameCaps("etag"), "ETag") + self.assertEqual(h._canonicalNameCaps("p3p"), "P3P") + self.assertEqual(h._canonicalNameCaps("te"), "TE") + self.assertEqual(h._canonicalNameCaps("www-authenticate"), "WWW-Authenticate") - self.assertEquals(h._canonicalNameCaps("x-xss-protection"), + self.assertEqual(h._canonicalNameCaps("x-xss-protection"), "X-XSS-Protection") @@ -217,6 +217,22 @@ "FunnyHeaders({'foo': ['bar', 'baz']})") + def test_copy(self): + """ + L{Headers.copy} creates a new independant copy of an existing + L{Headers} instance, allowing future modifications without impacts + between the copies. + """ + h = Headers() + h.setRawHeaders('test', ['foo']) + i = h.copy() + self.assertEqual(i.getRawHeaders('test'), ['foo']) + h.addRawHeader('test', 'bar') + self.assertEqual(i.getRawHeaders('test'), ['foo']) + i.addRawHeader('test', 'baz') + self.assertEqual(h.getRawHeaders('test'), ['foo', 'bar']) + + class HeaderDictTests(TestCase): """ diff --git a/lib/twisted-trunk/twisted/web/test/test_httpauth.py b/lib/twisted-trunk/twisted/web/test/test_httpauth.py --- a/lib/twisted-trunk/twisted/web/test/test_httpauth.py +++ b/lib/twisted-trunk/twisted/web/test/test_httpauth.py @@ -193,9 +193,9 @@ None of the values may have newlines in them. """ challenge = self.credentialFactory.getChallenge(self.request) - self.assertEquals(challenge['qop'], 'auth') - self.assertEquals(challenge['realm'], 'test realm') - self.assertEquals(challenge['algorithm'], 'md5') + self.assertEqual(challenge['qop'], 'auth') + self.assertEqual(challenge['realm'], 'test realm') + self.assertEqual(challenge['algorithm'], 'md5') self.assertIn('nonce', challenge) self.assertIn('opaque', challenge) for v in challenge.values(): @@ -346,7 +346,7 @@ child = getChildForRequest(self.wrapper, request) d = request.notifyFinish() def cbFinished(result): - self.assertEquals(request.responseCode, 401) + self.assertEqual(request.responseCode, 401) d.addCallback(cbFinished) request.render(child) return d @@ -412,7 +412,7 @@ child = self._authorizedBasicLogin(request) d = request.notifyFinish() def cbFinished(ignored): - self.assertEquals(request.written, [self.childContent]) + self.assertEqual(request.written, [self.childContent]) d.addCallback(cbFinished) request.render(child) return d @@ -431,7 +431,7 @@ child = self._authorizedBasicLogin(request) d = request.notifyFinish() def cbFinished(ignored): - self.assertEquals(request.written, [self.avatarContent]) + self.assertEqual(request.written, [self.avatarContent]) d.addCallback(cbFinished) request.render(child) return d @@ -485,7 +485,7 @@ request = self.makeRequest([self.childName]) child = self._authorizedBasicLogin(request) request.render(child) - self.assertEquals(self.realm.loggedOut, 0) + self.assertEqual(self.realm.loggedOut, 0) return request @@ -495,7 +495,7 @@ """ request = self._logoutTest() request.finish() - self.assertEquals(self.realm.loggedOut, 1) + self.assertEqual(self.realm.loggedOut, 1) def test_logoutOnError(self): @@ -507,7 +507,7 @@ request = self._logoutTest() request.processingFailed( Failure(ConnectionDone("Simulated disconnect"))) - self.assertEquals(self.realm.loggedOut, 1) + self.assertEqual(self.realm.loggedOut, 1) def test_decodeRaises(self): @@ -607,7 +607,7 @@ child = getChildForRequest(self.wrapper, request) d = request.notifyFinish() def cbFinished(ignored): - self.assertEquals(request.written, [unprotectedContents]) + self.assertEqual(request.written, [unprotectedContents]) d.addCallback(cbFinished) request.render(child) return d diff --git a/lib/twisted-trunk/twisted/web/test/test_newclient.py b/lib/twisted-trunk/twisted/web/test/test_newclient.py --- a/lib/twisted-trunk/twisted/web/test/test_newclient.py +++ b/lib/twisted-trunk/twisted/web/test/test_newclient.py @@ -29,7 +29,7 @@ from twisted.web._newclient import TransportProxyProducer, LengthEnforcingConsumer, makeStatefulDispatcher from twisted.web.http_headers import Headers from twisted.web.http import _DataLoss -from twisted.web.iweb import IBodyProducer +from twisted.web.iweb import IBodyProducer, IResponse @@ -972,7 +972,7 @@ def check(ignore): error = errors[0] - self.assertEquals(error['why'], + self.assertEqual(error['why'], 'Error writing request, but not in valid state ' 'to finalize request: CONNECTION_LOST') @@ -1078,7 +1078,7 @@ request.finished.callback(None) # Nothing dire will happen when the connection is lost self.protocol.connectionLost(Failure(ArbitraryException())) - self.assertEquals(self.protocol._state, 'CONNECTION_LOST') + self.assertEqual(self.protocol._state, 'CONNECTION_LOST') d.addCallback(cbAllResponse) return d @@ -1588,7 +1588,7 @@ """ producer = StringProducer(3) request = Request('POST', '/bar', _boringHeaders, producer) - writeDeferred = request.writeTo(self.transport) + request.writeTo(self.transport) finishedConsuming = producer.consumer._finished @@ -1736,7 +1736,7 @@ """ producer = StringProducer(3) request = Request('GET', '/', _boringHeaders, producer) - d = request.writeTo(self.transport) + request.writeTo(self.transport) self.assertFalse(producer.stopped) request.stopWriting() self.assertTrue(producer.stopped) @@ -1753,7 +1753,7 @@ producer.stopProducing = brokenStopProducing request = Request('GET', '/', _boringHeaders, producer) - d = request.writeTo(self.transport) + request.writeTo(self.transport) request.stopWriting() self.assertEqual( len(self.flushLoggedErrors(ArbitraryException)), 1) @@ -2008,6 +2008,15 @@ """ Tests for L{Response}. """ + + def test_verifyInterface(self): + """ + L{Response} instances provide L{IResponse}. + """ + response = justTransportResponse(StringTransport()) + self.assertTrue(verifyObject(IResponse, response)) + + def test_makeConnection(self): """ The L{IProtocol} provider passed to L{Response.deliverBody} has its diff --git a/lib/twisted-trunk/twisted/web/test/test_proxy.py b/lib/twisted-trunk/twisted/web/test/test_proxy.py --- a/lib/twisted-trunk/twisted/web/test/test_proxy.py +++ b/lib/twisted-trunk/twisted/web/test/test_proxy.py @@ -42,15 +42,15 @@ (uri,)) # Check that one connection has been created, to the good host/port - self.assertEquals(len(reactor.tcpClients), 1) - self.assertEquals(reactor.tcpClients[0][0], "127.0.0.1") - self.assertEquals(reactor.tcpClients[0][1], 1234) + self.assertEqual(len(reactor.tcpClients), 1) + self.assertEqual(reactor.tcpClients[0][0], "127.0.0.1") + self.assertEqual(reactor.tcpClients[0][1], 1234) # Check the factory passed to the connect, and its given path factory = reactor.tcpClients[0][2] self.assertIsInstance(factory, ProxyClientFactory) - self.assertEquals(factory.rest, expectedURI) - self.assertEquals(factory.headers["host"], "127.0.0.1:1234") + self.assertEqual(factory.rest, expectedURI) + self.assertEqual(factory.headers["host"], "127.0.0.1:1234") def test_render(self): @@ -81,9 +81,9 @@ child = resource.getChild('foo', None) # The child should keep the same class self.assertIsInstance(child, ReverseProxyResource) - self.assertEquals(child.path, "/path/foo") - self.assertEquals(child.port, 1234) - self.assertEquals(child.host, "127.0.0.1") + self.assertEqual(child.path, "/path/foo") + self.assertEqual(child.port, 1234) + self.assertEqual(child.host, "127.0.0.1") self.assertIdentical(child.reactor, resource.reactor) @@ -201,8 +201,8 @@ requestContent = proxyClient.transport.value() receivedLine, receivedHeaders, body = self._parseOutHeaders( requestContent) - self.assertEquals(receivedLine, requestLine) - self.assertEquals(receivedHeaders, headers) + self.assertEqual(receivedLine, requestLine) + self.assertEqual(receivedHeaders, headers) return body @@ -225,14 +225,14 @@ @param headers: The expected HTTP headers. @param body: The expected response body. """ - self.assertEquals(request.responseCode, code) - self.assertEquals(request.responseMessage, message) + self.assertEqual(request.responseCode, code) + self.assertEqual(request.responseMessage, message) receivedHeaders = list(request.responseHeaders.getAllRawHeaders()) receivedHeaders.sort() expectedHeaders = headers[:] expectedHeaders.sort() - self.assertEquals(receivedHeaders, expectedHeaders) - self.assertEquals(''.join(request.written), body) + self.assertEqual(receivedHeaders, expectedHeaders) + self.assertEqual(''.join(request.written), body) def _testDataForward(self, code, message, headers, body, method="GET", @@ -249,7 +249,7 @@ client, '%s /foo HTTP/1.0' % (method,), {'connection': 'close', 'accept': 'text/html'}) - self.assertEquals(receivedBody, requestBody) + self.assertEqual(receivedBody, requestBody) # Fake an answer client.dataReceived( @@ -267,7 +267,7 @@ # disconnected. This lets us not rely on the server to close our # sockets for us. self.assertFalse(client.transport.connected) - self.assertEquals(request.finished, 1) + self.assertEqual(request.finished, 1) def test_forward(self): @@ -327,7 +327,7 @@ """ client = ProxyClient('GET', '/foo', 'HTTP/1.0', {"accept": "text/html", "proxy-connection": "foo"}, '', None) - self.assertEquals(client.headers, + self.assertEqual(client.headers, {"accept": "text/html", "connection": "close"}) @@ -389,15 +389,15 @@ {"accept": "text/html"}, '', request) factory.clientConnectionFailed(None, None) - self.assertEquals(request.responseCode, 501) - self.assertEquals(request.responseMessage, "Gateway error") - self.assertEquals( + self.assertEqual(request.responseCode, 501) + self.assertEqual(request.responseMessage, "Gateway error") + self.assertEqual( list(request.responseHeaders.getAllRawHeaders()), [("Content-Type", ["text/html"])]) - self.assertEquals( + self.assertEqual( ''.join(request.written), "

    Could not connect

    ") - self.assertEquals(request.finished, 1) + self.assertEqual(request.finished, 1) def test_buildProtocol(self): @@ -410,10 +410,10 @@ None) proto = factory.buildProtocol(None) self.assertIsInstance(proto, ProxyClient) - self.assertEquals(proto.command, 'GET') - self.assertEquals(proto.rest, '/foo') - self.assertEquals(proto.data, 'Some data') - self.assertEquals(proto.headers, + self.assertEqual(proto.command, 'GET') + self.assertEqual(proto.rest, '/foo') + self.assertEqual(proto.data, 'Some data') + self.assertEqual(proto.headers, {"accept": "text/html", "connection": "close"}) @@ -437,18 +437,18 @@ request.requestReceived(method, 'http://example.com%s' % (uri,), 'HTTP/1.0') - self.assertEquals(len(reactor.tcpClients), 1) - self.assertEquals(reactor.tcpClients[0][0], "example.com") - self.assertEquals(reactor.tcpClients[0][1], 80) + self.assertEqual(len(reactor.tcpClients), 1) + self.assertEqual(reactor.tcpClients[0][0], "example.com") + self.assertEqual(reactor.tcpClients[0][1], 80) factory = reactor.tcpClients[0][2] self.assertIsInstance(factory, ProxyClientFactory) - self.assertEquals(factory.command, method) - self.assertEquals(factory.version, 'HTTP/1.0') - self.assertEquals(factory.headers, {'host': 'example.com'}) - self.assertEquals(factory.data, data) - self.assertEquals(factory.rest, expectedURI) - self.assertEquals(factory.father, request) + self.assertEqual(factory.command, method) + self.assertEqual(factory.version, 'HTTP/1.0') + self.assertEqual(factory.headers, {'host': 'example.com'}) + self.assertEqual(factory.data, data) + self.assertEqual(factory.rest, expectedURI) + self.assertEqual(factory.father, request) def test_process(self): @@ -496,9 +496,9 @@ 'HTTP/1.0') # That should create one connection, with the port parsed from the URL - self.assertEquals(len(reactor.tcpClients), 1) - self.assertEquals(reactor.tcpClients[0][0], "example.com") - self.assertEquals(reactor.tcpClients[0][1], 1234) + self.assertEqual(len(reactor.tcpClients), 1) + self.assertEqual(reactor.tcpClients[0][0], "example.com") + self.assertEqual(reactor.tcpClients[0][1], 1234) @@ -534,11 +534,11 @@ request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') # Check that one connection has been created, to the good host/port - self.assertEquals(len(reactor.tcpClients), 1) - self.assertEquals(reactor.tcpClients[0][0], "example.com") - self.assertEquals(reactor.tcpClients[0][1], 1234) + self.assertEqual(len(reactor.tcpClients), 1) + self.assertEqual(reactor.tcpClients[0][0], "example.com") + self.assertEqual(reactor.tcpClients[0][1], 1234) # Check the factory passed to the connect, and its headers factory = reactor.tcpClients[0][2] self.assertIsInstance(factory, ProxyClientFactory) - self.assertEquals(factory.headers, {'host': 'example.com'}) + self.assertEqual(factory.headers, {'host': 'example.com'}) diff --git a/lib/twisted-trunk/twisted/web/test/test_soap.py b/lib/twisted-trunk/twisted/web/test/test_soap.py --- a/lib/twisted-trunk/twisted/web/test/test_soap.py +++ b/lib/twisted-trunk/twisted/web/test/test_soap.py @@ -77,13 +77,13 @@ dl = [] for meth, args, outp in inputOutput: d = self.proxy().callRemote(meth, *args) - d.addCallback(self.assertEquals, outp) + d.addCallback(self.assertEqual, outp) dl.append(d) # SOAPpy kinda blows. d = self.proxy().callRemote('complex') d.addCallback(lambda result: result._asdict()) - d.addCallback(self.assertEquals, {"a": ["b", "c", 12, []], "D": "foo"}) + d.addCallback(self.assertEqual, {"a": ["b", "c", 12, []], "D": "foo"}) dl.append(d) # We now return to our regularly scheduled program, already in progress. @@ -96,7 +96,7 @@ d = self.proxy().callRemote('doesntexist') self.assertFailure(d, error.Error) def cb(err): - self.assertEquals(int(err.status), 500) + self.assertEqual(int(err.status), 500) d.addCallback(cb) return d diff --git a/lib/twisted-trunk/twisted/web/test/test_stan.py b/lib/twisted-trunk/twisted/web/test/test_stan.py --- a/lib/twisted-trunk/twisted/web/test/test_stan.py +++ b/lib/twisted-trunk/twisted/web/test/test_stan.py @@ -32,12 +32,12 @@ tag.lineNumber = 6 tag.columnNumber = 12 clone = tag.clone(deep=False) - self.assertEquals(clone.attributes['hello'], 'world') + self.assertEqual(clone.attributes['hello'], 'world') self.assertNotIdentical(clone.attributes, tag.attributes) - self.assertEquals(clone.children, ["How are you", innerList]) + self.assertEqual(clone.children, ["How are you", innerList]) self.assertNotIdentical(clone.children, tag.children) self.assertIdentical(clone.children[1], innerList) - self.assertEquals(tag.slotData, clone.slotData) + self.assertEqual(tag.slotData, clone.slotData) self.assertNotIdentical(tag.slotData, clone.slotData) self.assertEqual(clone.filename, "foo/bar") self.assertEqual(clone.lineNumber, 6) @@ -60,7 +60,7 @@ tag.lineNumber = 6 tag.columnNumber = 12 clone = tag.clone() - self.assertEquals(clone.attributes['hello'], 'world') + self.assertEqual(clone.attributes['hello'], 'world') self.assertNotIdentical(clone.attributes, tag.attributes) self.assertNotIdentical(clone.children, tag.children) # sanity check @@ -71,7 +71,7 @@ self.assertIdentical(tag.children[2], innerList) # clone should have sub-clone self.assertNotIdentical(clone.children[2], innerList) - self.assertEquals(tag.slotData, clone.slotData) + self.assertEqual(tag.slotData, clone.slotData) self.assertNotIdentical(tag.slotData, clone.slotData) self.assertEqual(clone.filename, "foo/bar") self.assertEqual(clone.lineNumber, 6) @@ -86,8 +86,8 @@ """ tag = proto("these are", "children", "cool", andSoIs='this-attribute') tag.clear() - self.assertEquals(tag.children, []) - self.assertEquals(tag.attributes, {'andSoIs': 'this-attribute'}) + self.assertEqual(tag.children, []) + self.assertEqual(tag.attributes, {'andSoIs': 'this-attribute'}) def test_suffix(self): @@ -98,7 +98,7 @@ proto = Tag('div') tag = proto() tag(class_='a') - self.assertEquals(tag.attributes, {'class': 'a'}) + self.assertEqual(tag.attributes, {'class': 'a'}) def test_commentRepr(self): @@ -106,7 +106,7 @@ L{Comment.__repr__} returns a value which makes it easy to see what's in the comment. """ - self.assertEquals(repr(Comment(u"hello there")), + self.assertEqual(repr(Comment(u"hello there")), "Comment(u'hello there')") @@ -115,6 +115,6 @@ L{CDATA.__repr__} returns a value which makes it easy to see what's in the comment. """ - self.assertEquals(repr(CDATA(u"test data")), + self.assertEqual(repr(CDATA(u"test data")), "CDATA(u'test data')") diff --git a/lib/twisted-trunk/twisted/web/test/test_static.py b/lib/twisted-trunk/twisted/web/test/test_static.py --- a/lib/twisted-trunk/twisted/web/test/test_static.py +++ b/lib/twisted-trunk/twisted/web/test/test_static.py @@ -205,7 +205,7 @@ staticFile = static.File(self.mktemp()) request = DummyRequest(['foo.bar']) child = staticFile.getChild("foo.bar", request) - self.assertEquals(child, staticFile.childNotFound) + self.assertEqual(child, staticFile.childNotFound) def test_staticFileDeletedRender(self): @@ -220,7 +220,7 @@ d2 = self._render(staticFile.childNotFound, request2) def cbRendered2(ignored): def cbRendered(ignored): - self.assertEquals(''.join(request.written), + self.assertEqual(''.join(request.written), ''.join(request2.written)) d.addCallback(cbRendered) return d @@ -904,7 +904,7 @@ Asserts that a given log message occurred with an expected message. """ logItem = self.catcher.pop() - self.assertEquals(logItem["message"][0], expected) + self.assertEqual(logItem["message"][0], expected) self.assertEqual( self.catcher, [], "An additional log occured: %r" % (logItem,)) @@ -1010,7 +1010,7 @@ """ self.request.headers['range'] = 'bytes=0-43' self.resource.render(self.request) - self.assertEquals(len(''.join(self.request.written)), 44) + self.assertEqual(len(''.join(self.request.written)), 44) def test_invalidRangeRequest(self): @@ -1024,9 +1024,9 @@ self.resource.render(self.request) expected = "Ignoring malformed Range header %r" % (range,) self._assertLogged(expected) - self.assertEquals(''.join(self.request.written), self.payload) - self.assertEquals(self.request.responseCode, http.OK) - self.assertEquals( + self.assertEqual(''.join(self.request.written), self.payload) + self.assertEqual(self.request.responseCode, http.OK) + self.assertEqual( self.request.outgoingHeaders['content-length'], str(len(self.payload))) @@ -1040,8 +1040,8 @@ """ sep = "\r\n--" + boundary parts = ''.join(body).split(sep) - self.assertEquals('', parts[0]) - self.assertEquals('--\r\n', parts[-1]) + self.assertEqual('', parts[0]) + self.assertEqual('--\r\n', parts[-1]) parsed_parts = [] for part in parts[1:-1]: before, header1, header2, blank, partBody = part.split('\r\n', 4) @@ -1069,12 +1069,12 @@ rangeHeaderValue = ','.join(["%s-%s"%(s,e) for (s, e) in startEnds]) self.request.headers['range'] = 'bytes=' + rangeHeaderValue self.resource.render(self.request) - self.assertEquals(self.request.responseCode, http.PARTIAL_CONTENT) + self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) boundary = re.match( '^multipart/byteranges; boundary="(.*)"$', self.request.outgoingHeaders['content-type']).group(1) parts = self.parseMultipartBody(''.join(self.request.written), boundary) - self.assertEquals(len(startEnds), len(parts)) + self.assertEqual(len(startEnds), len(parts)) for part, (s, e) in zip(parts, startEnds): self.assertEqual(self.resource.type, part['contentType']) start, end, size = part['contentRange'] @@ -1094,12 +1094,12 @@ rangeHeaderValue = ','.join(["%s-%s"%(s,e) for (s, e) in startEnds]) self.request.headers['range'] = 'bytes=' + rangeHeaderValue self.resource.render(self.request) - self.assertEquals(self.request.responseCode, http.PARTIAL_CONTENT) + self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) boundary = re.match( '^multipart/byteranges; boundary="(.*)"$', self.request.outgoingHeaders['content-type']).group(1) parts = self.parseMultipartBody(''.join(self.request.written), boundary) - self.assertEquals(len(startEnds), len(parts)) + self.assertEqual(len(startEnds), len(parts)) for part, (s, e) in zip(parts, startEnds): self.assertEqual(self.resource.type, part['contentType']) start, end, size = part['contentRange'] @@ -1116,12 +1116,12 @@ """ self.request.headers['range'] = 'bytes=23-' self.resource.render(self.request) - self.assertEquals(''.join(self.request.written), self.payload[23:]) - self.assertEquals(len(''.join(self.request.written)), 41) - self.assertEquals(self.request.responseCode, http.PARTIAL_CONTENT) - self.assertEquals( + self.assertEqual(''.join(self.request.written), self.payload[23:]) + self.assertEqual(len(''.join(self.request.written)), 41) + self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) + self.assertEqual( self.request.outgoingHeaders['content-range'], 'bytes 23-63/64') - self.assertEquals(self.request.outgoingHeaders['content-length'], '41') + self.assertEqual(self.request.outgoingHeaders['content-length'], '41') def test_implicitStart(self): @@ -1132,12 +1132,12 @@ """ self.request.headers['range'] = 'bytes=-17' self.resource.render(self.request) - self.assertEquals(''.join(self.request.written), self.payload[-17:]) - self.assertEquals(len(''.join(self.request.written)), 17) - self.assertEquals(self.request.responseCode, http.PARTIAL_CONTENT) - self.assertEquals( + self.assertEqual(''.join(self.request.written), self.payload[-17:]) + self.assertEqual(len(''.join(self.request.written)), 17) + self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) + self.assertEqual( self.request.outgoingHeaders['content-range'], 'bytes 47-63/64') - self.assertEquals(self.request.outgoingHeaders['content-length'], '17') + self.assertEqual(self.request.outgoingHeaders['content-length'], '17') def test_explicitRange(self): @@ -1149,11 +1149,11 @@ self.request.headers['range'] = 'bytes=3-43' self.resource.render(self.request) written = ''.join(self.request.written) - self.assertEquals(written, self.payload[3:44]) - self.assertEquals(self.request.responseCode, http.PARTIAL_CONTENT) - self.assertEquals( + self.assertEqual(written, self.payload[3:44]) + self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) + self.assertEqual( self.request.outgoingHeaders['content-range'], 'bytes 3-43/64') - self.assertEquals( + self.assertEqual( str(len(written)), self.request.outgoingHeaders['content-length']) @@ -1167,11 +1167,11 @@ self.request.headers['range'] = 'bytes=40-100' self.resource.render(self.request) written = ''.join(self.request.written) - self.assertEquals(written, self.payload[40:]) - self.assertEquals(self.request.responseCode, http.PARTIAL_CONTENT) - self.assertEquals( + self.assertEqual(written, self.payload[40:]) + self.assertEqual(self.request.responseCode, http.PARTIAL_CONTENT) + self.assertEqual( self.request.outgoingHeaders['content-range'], 'bytes 40-63/64') - self.assertEquals( + self.assertEqual( str(len(written)), self.request.outgoingHeaders['content-length']) @@ -1183,9 +1183,9 @@ """ self.request.headers['range'] = 'bytes=20-13' self.resource.render(self.request) - self.assertEquals(self.request.responseCode, http.OK) - self.assertEquals(''.join(self.request.written), self.payload) - self.assertEquals( + self.assertEqual(self.request.responseCode, http.OK) + self.assertEqual(''.join(self.request.written), self.payload) + self.assertEqual( self.request.outgoingHeaders['content-length'], str(len(self.payload))) @@ -1199,12 +1199,12 @@ """ self.request.headers['range'] = 'bytes=67-108' self.resource.render(self.request) - self.assertEquals( + self.assertEqual( self.request.responseCode, http.REQUESTED_RANGE_NOT_SATISFIABLE) - self.assertEquals(''.join(self.request.written), '') - self.assertEquals(self.request.outgoingHeaders['content-length'], '0') + self.assertEqual(''.join(self.request.written), '') + self.assertEqual(self.request.outgoingHeaders['content-length'], '0') # Sections 10.4.17 and 14.16 - self.assertEquals( + self.assertEqual( self.request.outgoingHeaders['content-range'], 'bytes */%d' % (len(self.payload),)) @@ -1352,7 +1352,7 @@ "encoding": ""} for i in xrange(5)] content = lister._buildTableContent(elements) - self.assertEquals(len(content), 5) + self.assertEqual(len(content), 5) self.assertTrue(content[0].startswith('')) self.assertTrue(content[1].startswith('')) self.assertTrue(content[2].startswith('')) @@ -1370,7 +1370,7 @@ lister = static.DirectoryLister(path.path) req = self._request('') lister.render(req) - self.assertEquals(req.outgoingHeaders['content-type'], + self.assertEqual(req.outgoingHeaders['content-type'], "text/html; charset=utf-8") @@ -1397,8 +1397,8 @@ lister = static.DirectoryLister(path.path, contentTypes=contentTypes) dirs, files = lister._getFilesAndDirectories(directory) - self.assertEquals(dirs, []) - self.assertEquals(files, [ + self.assertEqual(dirs, []) + self.assertEqual(files, [ {'encoding': '', 'href': 'file1.txt', 'size': '5B', @@ -1437,8 +1437,8 @@ directory = os.listdir(path.path) directory.sort() dirs, files = lister._getFilesAndDirectories(directory) - self.assertEquals(dirs, []) - self.assertEquals(files, []) + self.assertEqual(dirs, []) + self.assertEqual(files, []) if getattr(os, "symlink", None) is None: test_brokenSymlink.skip = "No symlink support" @@ -1456,7 +1456,7 @@ child = resource.getChildForRequest(lister, request) result = _render(child, request) def cbRendered(ignored): - self.assertEquals(request.responseCode, http.NOT_FOUND) + self.assertEqual(request.responseCode, http.NOT_FOUND) result.addCallback(cbRendered) return result @@ -1467,9 +1467,9 @@ """ path = FilePath(self.mktemp()) lister = static.DirectoryLister(path.path) - self.assertEquals(repr(lister), + self.assertEqual(repr(lister), "" % (path.path,)) - self.assertEquals(str(lister), + self.assertEqual(str(lister), "" % (path.path,)) def test_formatFileSize(self): @@ -1477,12 +1477,12 @@ L{static.formatFileSize} format an amount of bytes into a more readable format. """ - self.assertEquals(static.formatFileSize(0), "0B") - self.assertEquals(static.formatFileSize(123), "123B") - self.assertEquals(static.formatFileSize(4567), "4K") - self.assertEquals(static.formatFileSize(8900000), "8M") - self.assertEquals(static.formatFileSize(1234000000), "1G") - self.assertEquals(static.formatFileSize(1234567890000), "1149G") + self.assertEqual(static.formatFileSize(0), "0B") + self.assertEqual(static.formatFileSize(123), "123B") + self.assertEqual(static.formatFileSize(4567), "4K") + self.assertEqual(static.formatFileSize(8900000), "8M") + self.assertEqual(static.formatFileSize(1234000000), "1G") + self.assertEqual(static.formatFileSize(1234567890000), "1149G") diff --git a/lib/twisted-trunk/twisted/web/test/test_util.py b/lib/twisted-trunk/twisted/web/test/test_util.py --- a/lib/twisted-trunk/twisted/web/test/test_util.py +++ b/lib/twisted-trunk/twisted/web/test/test_util.py @@ -66,10 +66,10 @@ request.method = 'GET' targetURL = "http://target.example.com/4321" redirectTo(targetURL, request) - self.assertEquals(request.code, FOUND) - self.assertEquals( + self.assertEqual(request.code, FOUND) + self.assertEqual( request.responseHeaders.getRawHeaders('location'), [targetURL]) - self.assertEquals( + self.assertEqual( request.responseHeaders.getRawHeaders('content-type'), ['text/html; charset=utf-8']) diff --git a/lib/twisted-trunk/twisted/web/test/test_web.py b/lib/twisted-trunk/twisted/web/test/test_web.py --- a/lib/twisted-trunk/twisted/web/test/test_web.py +++ b/lib/twisted-trunk/twisted/web/test/test_web.py @@ -192,7 +192,7 @@ class ResourceTestCase(unittest.TestCase): def testListEntities(self): r = resource.Resource() - self.failUnlessEqual([], r.listEntities()) + self.assertEqual([], r.listEntities()) class SimpleResource(resource.Resource): @@ -455,8 +455,8 @@ self.channel.lineReceived("If-Modified-Since: " + modifiedSince) self.channel.lineReceived('') result = self.transport.getvalue() - self.failUnlessEqual(httpCode(result), http.OK) - self.failUnlessEqual(httpBody(result), "correct") + self.assertEqual(httpCode(result), http.OK) + self.assertEqual(httpBody(result), "correct") def test_modified(self): @@ -480,8 +480,8 @@ % http.datetimeToString(100)) self.channel.lineReceived('') result = self.transport.getvalue() - self.failUnlessEqual(httpCode(result), http.NOT_MODIFIED) - self.failUnlessEqual(httpBody(result), "") + self.assertEqual(httpCode(result), http.NOT_MODIFIED) + self.assertEqual(httpBody(result), "") def test_invalidTimestamp(self): @@ -530,17 +530,17 @@ self.channel.lineReceived("If-None-Match: unmatchedTag") self.channel.lineReceived('') result = self.transport.getvalue() - self.failUnlessEqual(httpCode(result), http.OK) - self.failUnlessEqual(httpBody(result), "correct") + self.assertEqual(httpCode(result), http.OK) + self.assertEqual(httpBody(result), "correct") def test_etagMatched(self): """If-None-Match ETag cache validator (negative)""" self.channel.lineReceived("If-None-Match: MatchingTag") self.channel.lineReceived('') result = self.transport.getvalue() - self.failUnlessEqual(httpHeader(result, "ETag"), "MatchingTag") - self.failUnlessEqual(httpCode(result), http.NOT_MODIFIED) - self.failUnlessEqual(httpBody(result), "") + self.assertEqual(httpHeader(result, "ETag"), "MatchingTag") + self.assertEqual(httpCode(result), http.NOT_MODIFIED) + self.assertEqual(httpBody(result), "") @@ -549,7 +549,7 @@ def testCheckGoogle(self): raise unittest.SkipTest("no violation of google ToS") d = google.checkGoogle('site:www.twistedmatrix.com twisted') - d.addCallback(self.assertEquals, 'http://twistedmatrix.com/') + d.addCallback(self.assertEqual, 'http://twistedmatrix.com/') return d @@ -753,26 +753,26 @@ def testGoodMethods(self): req = self._getReq() req.requestReceived('GET', '/newrender', 'HTTP/1.0') - self.assertEquals(req.transport.getvalue().splitlines()[-1], 'hi hi') + self.assertEqual(req.transport.getvalue().splitlines()[-1], 'hi hi') req = self._getReq() req.requestReceived('HEH', '/newrender', 'HTTP/1.0') - self.assertEquals(req.transport.getvalue().splitlines()[-1], 'ho ho') + self.assertEqual(req.transport.getvalue().splitlines()[-1], 'ho ho') def testBadMethods(self): req = self._getReq() req.requestReceived('CONNECT', '/newrender', 'HTTP/1.0') - self.assertEquals(req.code, 501) + self.assertEqual(req.code, 501) req = self._getReq() req.requestReceived('hlalauguG', '/newrender', 'HTTP/1.0') - self.assertEquals(req.code, 501) + self.assertEqual(req.code, 501) def testImplicitHead(self): req = self._getReq() req.requestReceived('HEAD', '/newrender', 'HTTP/1.0') - self.assertEquals(req.code, 200) - self.assertEquals(-1, req.transport.getvalue().find('hi hi')) + self.assertEqual(req.code, 200) + self.assertEqual(-1, req.transport.getvalue().find('hi hi')) def test_unsupportedHead(self): @@ -835,7 +835,7 @@ """ res = GettableResource() allowedMethods = resource._computeAllowedMethods(res) - self.assertEquals(set(allowedMethods), + self.assertEqual(set(allowedMethods), set(['GET', 'HEAD', 'fred_render_ethel'])) @@ -849,8 +849,8 @@ """ req = self._getReq() req.requestReceived('POST', '/gettableresource', 'HTTP/1.0') - self.assertEquals(req.code, 405) - self.assertEquals( + self.assertEqual(req.code, 405) + self.assertEqual( set(req.responseHeaders.getRawHeaders('allow')[0].split(", ")), set(['GET', 'HEAD','fred_render_ethel']) ) @@ -866,7 +866,7 @@ req = self._getReq() req.requestReceived('POST', '/gettableresource?' 'value= """ d = microdom.parseString(s, beExtremelyLenient=1) - self.assertEquals(d.firstChild().firstChild().firstChild().data, + self.assertEqual(d.firstChild().firstChild().firstChild().data, "(foo < bar) and (bar > foo)") - self.assertEquals( + self.assertEqual( d.firstChild().getElementsByTagName("script")[1].firstChild().data, "foo """ - self.assertEquals( + self.assertEqual( microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) s = """""" - self.assertEquals( + self.assertEqual( microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) s = """""" - self.assertEquals( + self.assertEqual( microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) def testPreserveCase(self): @@ -222,7 +222,7 @@ # for the documents to be equivalent (i.e. to ), # however this assertion tests preserving case for start and # end tags while still matching stuff like - self.assertEquals(d.documentElement.toxml(), s) + self.assertEqual(d.documentElement.toxml(), s) self.assert_(d.isEqualToDocument(d2), "%r != %r" % (d.toxml(), d2.toxml())) self.assert_(d2.isEqualToDocument(d3), "%r != %r" % (d2.toxml(), d3.toxml())) # caseInsensitive=0 on the left, NOT perserveCase=1 on the right @@ -235,15 +235,15 @@ s = '' d = microdom.parseString(s) e = d.documentElement - self.assertEquals(e.getAttribute('a'), 'a') - self.assertEquals(e.getAttribute('b'), 'b') + self.assertEqual(e.getAttribute('a'), 'a') + self.assertEqual(e.getAttribute('b'), 'b') def testLinebreaks(self): s = '' d = microdom.parseString(s) e = d.documentElement - self.assertEquals(e.getAttribute('a'), 'a') - self.assertEquals(e.getAttribute('b'), '#b') + self.assertEqual(e.getAttribute('a'), 'a') + self.assertEqual(e.getAttribute('b'), '#b') def testMismatchedTags(self): for s in '', ' ', '': @@ -253,29 +253,29 @@ s = "" d = microdom.parseString(s) e = d.documentElement - self.assertEquals(e.nodeName, "bar") + self.assertEqual(e.nodeName, "bar") c = e.childNodes[0] self.assert_(isinstance(c, microdom.Comment)) - self.assertEquals(c.value, "") + self.assertEqual(c.value, "") c2 = c.cloneNode() self.assert_(c is not c2) - self.assertEquals(c2.toxml(), "") + self.assertEqual(c2.toxml(), "") def testText(self): d = microdom.parseString("xxxx").documentElement text = d.childNodes[0] self.assert_(isinstance(text, microdom.Text)) - self.assertEquals(text.value, "xxxx") + self.assertEqual(text.value, "xxxx") clone = text.cloneNode() self.assert_(clone is not text) - self.assertEquals(clone.toxml(), "xxxx") + self.assertEqual(clone.toxml(), "xxxx") def testEntities(self): nodes = microdom.parseString("& AB;").documentElement.childNodes - self.assertEquals(len(nodes), 2) - self.assertEquals(nodes[0].data, "&") - self.assertEquals(nodes[1].data, " AB;") - self.assertEquals(nodes[0].cloneNode().toxml(), "&") + self.assertEqual(len(nodes), 2) + self.assertEqual(nodes[0].data, "&") + self.assertEqual(nodes[1].data, " AB;") + self.assertEqual(nodes[0].cloneNode().toxml(), "&") for n in nodes: self.assert_(isinstance(n, microdom.EntityReference)) @@ -283,40 +283,40 @@ s = '\r\n & foo]]>' cdata = microdom.parseString(s).documentElement.childNodes[0] self.assert_(isinstance(cdata, microdom.CDATASection)) - self.assertEquals(cdata.data, "\r\n & foo") - self.assertEquals(cdata.cloneNode().toxml(), "\r\n & foo]]>") + self.assertEqual(cdata.data, "\r\n & foo") + self.assertEqual(cdata.cloneNode().toxml(), "\r\n & foo]]>") def testSingletons(self): s = "" s2 = "" nodes = microdom.parseString(s).documentElement.childNodes nodes2 = microdom.parseString(s2).documentElement.childNodes - self.assertEquals(len(nodes), 3) + self.assertEqual(len(nodes), 3) for (n, n2) in zip(nodes, nodes2): self.assert_(isinstance(n, microdom.Element)) - self.assertEquals(n.nodeName, "b") + self.assertEqual(n.nodeName, "b") self.assert_(n.isEqualToNode(n2)) def testAttributes(self): s = '' node = microdom.parseString(s).documentElement - self.assertEquals(node.getAttribute("a"), "b") - self.assertEquals(node.getAttribute("c"), None) + self.assertEqual(node.getAttribute("a"), "b") + self.assertEqual(node.getAttribute("c"), None) self.assert_(node.hasAttribute("a")) self.assert_(not node.hasAttribute("c")) a = node.getAttributeNode("a") - self.assertEquals(a.value, "b") + self.assertEqual(a.value, "b") node.setAttribute("foo", "bar") - self.assertEquals(node.getAttribute("foo"), "bar") + self.assertEqual(node.getAttribute("foo"), "bar") def testChildren(self): s = "foo" d = microdom.parseString(s).documentElement - self.assertEquals([n.nodeName for n in d.childNodes], ["bar", "baz", "bax"]) - self.assertEquals(d.lastChild().nodeName, "bax") - self.assertEquals(d.firstChild().nodeName, "bar") + self.assertEqual([n.nodeName for n in d.childNodes], ["bar", "baz", "bax"]) + self.assertEqual(d.lastChild().nodeName, "bax") + self.assertEqual(d.firstChild().nodeName, "bar") self.assert_(d.hasChildNodes()) self.assert_(not d.firstChild().hasChildNodes()) @@ -331,23 +331,23 @@ d.appendChild(d.cloneNode()) d.setAttribute("a", "b") child = d.childNodes[0] - self.assertEquals(child.getAttribute("a"), None) - self.assertEquals(child.nodeName, "foo") + self.assertEqual(child.getAttribute("a"), None) + self.assertEqual(child.nodeName, "foo") d.insertBefore(microdom.Element("bar"), child) - self.assertEquals(d.childNodes[0].nodeName, "bar") - self.assertEquals(d.childNodes[1], child) + self.assertEqual(d.childNodes[0].nodeName, "bar") + self.assertEqual(d.childNodes[1], child) for n in d.childNodes: - self.assertEquals(n.parentNode, d) + self.assertEqual(n.parentNode, d) self.assert_(d.isEqualToNode(d1)) d.removeChild(child) - self.assertEquals(len(d.childNodes), 1) - self.assertEquals(d.childNodes[0].nodeName, "bar") + self.assertEqual(len(d.childNodes), 1) + self.assertEqual(d.childNodes[0].nodeName, "bar") t = microdom.Text("foo") d.replaceChild(t, d.firstChild()) - self.assertEquals(d.firstChild(), t) + self.assertEqual(d.firstChild(), t) self.assert_(d.isEqualToNode(d2)) @@ -372,22 +372,22 @@ d3 = microdom.parseString(s2, caseInsensitive=1, preserveCase=1) root = d.documentElement - self.assertEquals(root.firstChild(), d.getElementById('me')) - self.assertEquals(d.getElementsByTagName("foo"), + self.assertEqual(root.firstChild(), d.getElementById('me')) + self.assertEqual(d.getElementsByTagName("foo"), [root, root.lastChild().firstChild()]) root = d2.documentElement - self.assertEquals(root.firstChild(), d2.getElementById('me')) - self.assertEquals(d2.getElementsByTagName('fOo'), [root]) - self.assertEquals(d2.getElementsByTagName('fOO'), + self.assertEqual(root.firstChild(), d2.getElementById('me')) + self.assertEqual(d2.getElementsByTagName('fOo'), [root]) + self.assertEqual(d2.getElementsByTagName('fOO'), [root.lastChild().firstChild()]) - self.assertEquals(d2.getElementsByTagName('foo'), []) + self.assertEqual(d2.getElementsByTagName('foo'), []) root = d3.documentElement - self.assertEquals(root.firstChild(), d3.getElementById('me')) - self.assertEquals(d3.getElementsByTagName('FOO'), + self.assertEqual(root.firstChild(), d3.getElementById('me')) + self.assertEqual(d3.getElementsByTagName('FOO'), [root, root.lastChild().firstChild()]) - self.assertEquals(d3.getElementsByTagName('fOo'), + self.assertEqual(d3.getElementsByTagName('fOo'), [root, root.lastChild().firstChild()]) def testDoctype(self): @@ -397,9 +397,9 @@ s2 = '' d = microdom.parseString(s) d2 = microdom.parseString(s2) - self.assertEquals(d.doctype, + self.assertEqual(d.doctype, 'foo PUBLIC "baz" "http://www.example.com/example.dtd"') - self.assertEquals(d.toxml(), s) + self.assertEqual(d.toxml(), s) self.failIf(d.isEqualToDocument(d2)) self.failUnless(d.documentElement.isEqualToNode(d2.documentElement)) @@ -415,7 +415,7 @@ d = microdom.parseString(s, caseInsensitive=0) d2 = microdom.parseString(out, caseInsensitive=0) testOut = d.documentElement.toxml() - self.assertEquals(out, testOut) + self.assertEqual(out, testOut) self.assert_(d.isEqualToDocument(d2)) def testErrors(self): @@ -436,13 +436,13 @@ out = microdom.parseString(s).documentElement.toxml() self.assertRaises(microdom.MismatchedTags, microdom.parseString, s, caseInsensitive=0) - self.assertEquals(out, s2) + self.assertEqual(out, s2) self.failUnless(d.isEqualToDocument(d2)) self.failUnless(d.isEqualToDocument(d3)) self.failUnless(d4.documentElement.hasAttribute('a')) self.failIf(d6.documentElement.hasAttribute('a')) - self.assertEquals(d4.documentElement.toxml(), 'x') - self.assertEquals(d5.documentElement.toxml(), 'x') + self.assertEqual(d4.documentElement.toxml(), 'x') + self.assertEqual(d5.documentElement.toxml(), 'x') def testEatingWhitespace(self): s = """ """ @@ -460,31 +460,31 @@ ("&hello monkey", "&hello monkey")]: d = microdom.parseString("%s
    %s
    " % (prefix, i), beExtremelyLenient=1) - self.assertEquals(d.documentElement.toxml(), "
    %s
    " % o) + self.assertEqual(d.documentElement.toxml(), "
    %s
    " % o) # non-space preserving d = microdom.parseString("hello & there", beExtremelyLenient=1) - self.assertEquals(d.documentElement.toxml(), "hello & there") + self.assertEqual(d.documentElement.toxml(), "hello & there") def testInsensitiveLenient(self): # testing issue #537 d = microdom.parseString( "c ", beExtremelyLenient=1) - self.assertEquals(d.documentElement.firstChild().toxml(), "c") + self.assertEqual(d.documentElement.firstChild().toxml(), "c") def testLaterCloserSimple(self): s = "
    • foo
    • bar
    • baz
    " d = microdom.parseString(s, beExtremelyLenient=1) expected = "
    • foo
    • bar
    • baz
    " actual = d.documentElement.toxml() - self.assertEquals(expected, actual) + self.assertEqual(expected, actual) def testLaterCloserCaseInsensitive(self): s = "

    foo
    bar
    " d = microdom.parseString(s, beExtremelyLenient=1) expected = "

    foo
    bar
    " actual = d.documentElement.toxml() - self.assertEquals(expected, actual) + self.assertEqual(expected, actual) def testLaterCloserTable(self): s = ("" @@ -499,7 +499,7 @@ "
    ") d = microdom.parseString(s, beExtremelyLenient=1) actual = d.documentElement.toxml() - self.assertEquals(expected, actual) + self.assertEqual(expected, actual) testLaterCloserTable.todo = "Table parsing needs to be fixed." def testLaterCloserDL(self): @@ -513,7 +513,7 @@ "") d = microdom.parseString(s, beExtremelyLenient=1) actual = d.documentElement.toxml() - self.assertEquals(expected, actual) + self.assertEqual(expected, actual) def testLaterCloserDL2(self): s = ("
    " @@ -526,7 +526,7 @@ "
    ") d = microdom.parseString(s, beExtremelyLenient=1) actual = d.documentElement.toxml() - self.assertEquals(expected, actual) + self.assertEqual(expected, actual) testLaterCloserDL2.todo = "unclosed

    messes it up." @@ -564,7 +564,7 @@ de=j3.documentElement de.appendChild(div) de.appendChild(j3.createComment(u'\u221a')) - self.assertEquals(j3.toxml(), hdr+ + self.assertEqual(j3.toxml(), hdr+ u'

    \u221a
    '.encode('utf8')) def testNamedChildren(self): @@ -576,7 +576,7 @@ for t in tests.keys(): node = microdom.parseString(t).documentElement result = domhelpers.namedChildren(node, 'bar') - self.assertEquals(len(result), tests[t]) + self.assertEqual(len(result), tests[t]) if result: self.assert_(hasattr(result[0], 'tagName')) @@ -585,13 +585,13 @@ node = microdom.parseString(s).documentElement clone = node.cloneNode(deep=1) self.failIfEquals(node, clone) - self.assertEquals(len(node.childNodes), len(clone.childNodes)) + self.assertEqual(len(node.childNodes), len(clone.childNodes)) c1, c2 = node.firstChild(), clone.firstChild() self.failIfEquals(c1, c2) - self.assertEquals(len(c1.childNodes), len(c2.childNodes)) + self.assertEqual(len(c1.childNodes), len(c2.childNodes)) self.failIfEquals(c1.firstChild(), c2.firstChild()) - self.assertEquals(s, clone.toxml()) - self.assertEquals(node.namespace, clone.namespace) + self.assertEqual(s, clone.toxml()) + self.assertEqual(node.namespace, clone.namespace) def testCloneDocument(self): s = ('' @@ -601,8 +601,8 @@ node = microdom.parseString(s) clone = node.cloneNode(deep=1) self.failIfEquals(node, clone) - self.assertEquals(len(node.childNodes), len(clone.childNodes)) - self.assertEquals(s, clone.toxml()) + self.assertEqual(len(node.childNodes), len(clone.childNodes)) + self.assertEqual(s, clone.toxml()) self.failUnless(clone.isEqualToDocument(node)) self.failUnless(node.isEqualToDocument(clone)) @@ -618,7 +618,7 @@ b.add("bar", c="y") s = '

    foo

    ' - self.assertEquals(s, n.toxml()) + self.assertEqual(s, n.toxml()) def testDict(self): n = microdom.Element("p") @@ -629,8 +629,8 @@ raw = "&'some \"stuff\"', " cooked = "&'some "stuff"', <what up?>" esc1 = microdom.escape(raw) - self.assertEquals(esc1, cooked) - self.assertEquals(microdom.unescape(esc1), raw) + self.assertEqual(esc1, cooked) + self.assertEqual(microdom.unescape(esc1), raw) def testNamespaces(self): s = ''' @@ -645,20 +645,20 @@ d = microdom.parseString(s) # at least make sure it doesn't traceback s2 = d.toprettyxml() - self.assertEquals(d.documentElement.namespace, + self.assertEqual(d.documentElement.namespace, "base") - self.assertEquals(d.documentElement.getElementsByTagName("y")[0].namespace, + self.assertEqual(d.documentElement.getElementsByTagName("y")[0].namespace, "base") - self.assertEquals( + self.assertEqual( d.documentElement.getElementsByTagName("y")[1].getAttributeNS('base','q'), '1') d2 = microdom.parseString(s2) - self.assertEquals(d2.documentElement.namespace, + self.assertEqual(d2.documentElement.namespace, "base") - self.assertEquals(d2.documentElement.getElementsByTagName("y")[0].namespace, + self.assertEqual(d2.documentElement.getElementsByTagName("y")[0].namespace, "base") - self.assertEquals( + self.assertEqual( d2.documentElement.getElementsByTagName("y")[1].getAttributeNS('base','q'), '1') @@ -669,7 +669,7 @@ s1 = ('' '') s2 = microdom.parseString(s1).toxml() - self.assertEquals(s1, s2) + self.assertEqual(s1, s2) def testNamespaceInheritance(self): """ @@ -680,7 +680,7 @@ child = microdom.Element('ol') parent = microdom.Element('div', namespace='http://www.w3.org/1999/xhtml') parent.childNodes = [child] - self.assertEquals(parent.toxml(), + self.assertEqual(parent.toxml(), '
      ') def test_prefixedTags(self): @@ -723,7 +723,7 @@ '') xmlOut = document.toxml() - self.assertEquals(xmlOut, xmlOk) + self.assertEqual(xmlOut, xmlOk) def test_prefixPropagation(self): @@ -783,7 +783,7 @@ '' ) xmlOut = document.toxml() - self.assertEquals(xmlOut, xmlOk) + self.assertEqual(xmlOut, xmlOk) @@ -802,7 +802,7 @@ """ output = microdom.parseString(input, beExtremelyLenient=beExtremelyLenient) - self.assertEquals(output.documentElement.toxml(), expected) + self.assertEqual(output.documentElement.toxml(), expected) def test_brokenAttributeName(self): diff --git a/lib/twisted-trunk/twisted/web/test/test_xmlrpc.py b/lib/twisted-trunk/twisted/web/test/test_xmlrpc.py --- a/lib/twisted-trunk/twisted/web/test/test_xmlrpc.py +++ b/lib/twisted-trunk/twisted/web/test/test_xmlrpc.py @@ -53,13 +53,13 @@ response to the request is the result of that L{defer.Deferred}. """ self.resource.render(self.request) - self.assertEquals(self.request.written, []) + self.assertEqual(self.request.written, []) self.result.callback("result") resp = xmlrpclib.loads("".join(self.request.written)) - self.assertEquals(resp, (('result',), None)) - self.assertEquals(self.request.finished, 1) + self.assertEqual(resp, (('result',), None)) + self.assertEqual(self.request.finished, 1) def test_interruptedDeferredResponse(self): @@ -73,8 +73,8 @@ self.request.processingFailed( failure.Failure(ConnectionDone("Simulated"))) self.result.callback("result") - self.assertEquals(self.request.written, []) - self.assertEquals(self.request.finished, 0) + self.assertEqual(self.request.written, []) + self.assertEqual(self.request.finished, 0) @@ -300,7 +300,7 @@ dl = [] for meth, args, outp in inputOutput: d = self.proxy().callRemote(meth, *args) - d.addCallback(self.assertEquals, outp) + d.addCallback(self.assertEqual, outp) dl.append(d) return defer.DeferredList(dl, fireOnOneErrback=True) @@ -318,12 +318,12 @@ d = self.proxy().callRemote(methodName) d = self.assertFailure(d, xmlrpc.Fault) d.addCallback(lambda exc, code=code: - self.assertEquals(exc.faultCode, code)) + self.assertEqual(exc.faultCode, code)) dl.append(d) d = defer.DeferredList(dl, fireOnOneErrback=True) def cb(ign): for factory in self.factories: - self.assertEquals(factory.headers['content-type'], + self.assertEqual(factory.headers['content-type'], 'text/xml') self.flushLoggedErrors(TestRuntimeError, TestValueError) d.addCallback(cb) @@ -341,7 +341,7 @@ d = self.proxy(factory).callRemote('add', 2, 3) self.assertNotEquals(factory.f.connector.state, "disconnected") d.cancel() - self.assertEquals(factory.f.connector.state, "disconnected") + self.assertEqual(factory.f.connector.state, "disconnected") d = self.assertFailure(d, defer.CancelledError) return d @@ -353,7 +353,7 @@ d = client.getPage("http://127.0.0.1:%d/" % (self.port,)) d = self.assertFailure(d, error.Error) d.addCallback( - lambda exc: self.assertEquals(int(exc.args[0]), http.NOT_ALLOWED)) + lambda exc: self.assertEqual(int(exc.args[0]), http.NOT_ALLOWED)) return d def test_errorXMLContent(self): @@ -428,7 +428,7 @@ proxy = xmlrpc.Proxy("http://127.0.0.1:69", connectTimeout=2.0, reactor=reactor) proxy.callRemote("someMethod") - self.assertEquals(reactor.tcpClients[0][3], 2.0) + self.assertEqual(reactor.tcpClients[0][3], 2.0) def test_sslTimeout(self): @@ -441,7 +441,7 @@ proxy = xmlrpc.Proxy("https://127.0.0.1:69", connectTimeout=3.0, reactor=reactor) proxy.callRemote("someMethod") - self.assertEquals(reactor.sslClients[0][4], 3.0) + self.assertEqual(reactor.sslClients[0][4], 3.0) test_sslTimeout.skip = sslSkip @@ -552,7 +552,7 @@ C{self.value} can be round-tripped over an XMLRPC method call/response. """ d = self.proxy.callRemote('defer', self.value) - d.addCallback(self.assertEquals, self.value) + d.addCallback(self.assertEqual, self.value) return d @@ -562,7 +562,7 @@ XMLRPC method call/response. """ d = self.proxy.callRemote('defer', {'a': self.value}) - d.addCallback(self.assertEquals, {'a': self.value}) + d.addCallback(self.assertEqual, {'a': self.value}) return d @@ -647,7 +647,7 @@ p = xmlrpc.Proxy("http://%s:%s at 127.0.0.1:%d/" % ( self.user, self.password, self.port)) d = p.callRemote("authinfo") - d.addCallback(self.assertEquals, [self.user, self.password]) + d.addCallback(self.assertEqual, [self.user, self.password]) return d @@ -655,7 +655,7 @@ p = xmlrpc.Proxy("http://127.0.0.1:%d/" % ( self.port,), self.user, self.password) d = p.callRemote("authinfo") - d.addCallback(self.assertEquals, [self.user, self.password]) + d.addCallback(self.assertEqual, [self.user, self.password]) return d @@ -663,7 +663,7 @@ p = xmlrpc.Proxy("http://wrong:info at 127.0.0.1:%d/" % ( self.port,), self.user, self.password) d = p.callRemote("authinfo") - d.addCallback(self.assertEquals, [self.user, self.password]) + d.addCallback(self.assertEqual, [self.user, self.password]) return d @@ -701,7 +701,7 @@ dl = [] for meth, expected in inputOutputs: d = self.proxy().callRemote("system.methodHelp", meth) - d.addCallback(self.assertEquals, expected) + d.addCallback(self.assertEqual, expected) dl.append(d) return defer.DeferredList(dl, fireOnOneErrback=True) @@ -715,7 +715,7 @@ dl = [] for meth, expected in inputOutputs: d = self.proxy().callRemote("system.methodSignature", meth) - d.addCallback(self.assertEquals, expected) + d.addCallback(self.assertEqual, expected) dl.append(d) return defer.DeferredList(dl, fireOnOneErrback=True) @@ -843,7 +843,7 @@ request.content = StringIO(xmlrpclib.dumps(("foo",), 'withRequest')) def valid(n, request): data = xmlrpclib.loads(request.written[0]) - self.assertEquals(data, (('POST foo',), None)) + self.assertEqual(data, (('POST foo',), None)) d = request.notifyFinish().addCallback(valid, request) self.resource.render_POST(request) return d diff --git a/lib/twisted-trunk/twisted/words/protocols/irc.py b/lib/twisted-trunk/twisted/words/protocols/irc.py --- a/lib/twisted-trunk/twisted/words/protocols/irc.py +++ b/lib/twisted-trunk/twisted/words/protocols/irc.py @@ -37,10 +37,11 @@ import textwrap from os import path -from twisted.internet import reactor, protocol +from twisted.internet import reactor, protocol, task from twisted.persisted import styles from twisted.protocols import basic from twisted.python import log, reflect, text +from twisted.python.compat import set NUL = chr(0) CR = chr(015) @@ -968,7 +969,8 @@ class IRCClient(basic.LineReceiver): - """Internet Relay Chat client protocol, with sprinkles. + """ + Internet Relay Chat client protocol, with sprinkles. In addition to providing an interface for an IRC client protocol, this class also contains reasonable implementations of many common @@ -980,11 +982,6 @@ does). - Add flood protection/rate limiting for my CTCP replies. - NickServ cooperation. (a mix-in?) - - Heartbeat. The transport may die in such a way that it does not realize - it is dead until it is written to. Sending something (like "PING - this.irc-host.net") during idle peroids would alleviate that. If - you're concerned with the stability of the host as well as that of the - transport, you might care to watch for the corresponding PONG. @ivar nickname: Nickname the client will use. @ivar password: Password used to log on to the server. May be C{None}. @@ -1036,7 +1033,23 @@ @type supported: L{ServerSupportedFeatures} @ivar supported: Available ISUPPORT features on the server + + @type hostname: C{str} + @ivar hostname: Host name of the IRC server the client is connected to. + Initially the host name is C{None} and later is set to the host name + from which the I{RPL_WELCOME} message is received. + + @type _heartbeat: L{task.LoopingCall} + @ivar _heartbeat: Looping call to perform the keepalive by calling + L{IRCClient._sendHeartbeat} every L{heartbeatInterval} seconds, or + C{None} if there is no heartbeat. + + @type heartbeatInterval: C{float} + @ivar heartbeatInterval: Interval, in seconds, to send I{PING} messages to + the server as a form of keepalive, defaults to 120 seconds. Use C{None} + to disable the heartbeat. """ + hostname = None motd = None nickname = 'irc' password = None @@ -1072,6 +1085,10 @@ _attemptedNick = '' erroneousNickFallback = 'defaultnick' + _heartbeat = None + heartbeatInterval = 120 + + def _reallySendLine(self, line): return basic.LineReceiver.sendLine(self, lowQuote(line) + '\r') @@ -1092,6 +1109,52 @@ self._queueEmptying = None + def connectionLost(self, reason): + basic.LineReceiver.connectionLost(self, reason) + self.stopHeartbeat() + + + def _createHeartbeat(self): + """ + Create the heartbeat L{LoopingCall}. + """ + return task.LoopingCall(self._sendHeartbeat) + + + def _sendHeartbeat(self): + """ + Send a I{PING} message to the IRC server as a form of keepalive. + """ + self.sendLine('PING ' + self.hostname) + + + def stopHeartbeat(self): + """ + Stop sending I{PING} messages to keep the connection to the server + alive. + + @since: 11.1 + """ + if self._heartbeat is not None: + self._heartbeat.stop() + self._heartbeat = None + + + def startHeartbeat(self): + """ + Start sending I{PING} messages every L{IRCClient.heartbeatInterval} + seconds to keep the connection to the server alive during periods of no + activity. + + @since: 11.1 + """ + self.stopHeartbeat() + if self.heartbeatInterval is None: + return + self._heartbeat = self._createHeartbeat() + self._heartbeat.start(self.heartbeatInterval, now=False) + + ### Interface level client->user output methods ### ### You'll want to override these. @@ -1735,13 +1798,17 @@ """ raise IRCPasswordMismatch("Password Incorrect.") + def irc_RPL_WELCOME(self, prefix, params): """ Called when we have received the welcome from the server. """ + self.hostname = prefix self._registered = True self.nickname = self._attemptedNick self.signedOn() + self.startHeartbeat() + def irc_JOIN(self, prefix, params): """ @@ -1818,9 +1885,11 @@ channel = params[0] message = params[-1] - if not message: return # don't raise an exception if some idiot sends us a blank message - - if message[0]==X_DELIM: + if not message: + # Don't raise an exception if we get blank message. + return + + if message[0] == X_DELIM: m = ctcpExtract(message) if m['extended']: self.ctcpQuery(user, channel, m['extended']) @@ -1972,15 +2041,34 @@ ### Receiving a CTCP query from another party ### It is safe to leave these alone. + def ctcpQuery(self, user, channel, messages): - """Dispatch method for any CTCP queries received. """ - for m in messages: - method = getattr(self, "ctcpQuery_%s" % m[0], None) - if method: - method(user, channel, m[1]) - else: - self.ctcpUnknownQuery(user, channel, m[0], m[1]) + Dispatch method for any CTCP queries received. + + Duplicated CTCP queries are ignored and no dispatch is + made. Unrecognized CTCP queries invoke L{IRCClient.ctcpUnknownQuery}. + """ + seen = set() + for tag, data in messages: + method = getattr(self, 'ctcpQuery_%s' % tag, None) + if tag not in seen: + if method is not None: + method(user, channel, data) + else: + self.ctcpUnknownQuery(user, channel, tag, data) + seen.add(tag) + + + def ctcpUnknownQuery(self, user, channel, tag, data): + """ + Fallback handler for unrecognized CTCP queries. + + No CTCP I{ERRMSG} reply is made to remove a potential denial of service + avenue. + """ + log.msg('Unknown CTCP query from %r: %r %r' % (user, tag, data)) + def ctcpQuery_ACTION(self, user, channel, data): self.action(user, channel, data) @@ -2206,14 +2294,6 @@ # """ # raise NotImplementedError - def ctcpUnknownQuery(self, user, channel, tag, data): - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, [('ERRMSG', - "%s %s: Unknown query '%s'" - % (tag, data, tag))]) - - log.msg("Unknown CTCP query from %s: %s %s\n" - % (user, tag, data)) def ctcpMakeReply(self, user, messages): """ @@ -2762,14 +2842,13 @@ X_DELIM = chr(001) def ctcpExtract(message): - """Extract CTCP data from a string. - - Returns a dictionary with two items: - - - C{'extended'}: a list of CTCP (tag, data) tuples - - C{'normal'}: a list of strings which were not inside a CTCP delimeter """ - + Extract CTCP data from a string. + + @return: A C{dict} containing two keys: + - C{'extended'}: A list of CTCP (tag, data) tuples. + - C{'normal'}: A list of strings which were not inside a CTCP delimiter. + """ extended_messages = [] normal_messages = [] retval = {'extended': extended_messages, diff --git a/lib/twisted-trunk/twisted/words/test/test_basechat.py b/lib/twisted-trunk/twisted/words/test/test_basechat.py --- a/lib/twisted-trunk/twisted/words/test/test_basechat.py +++ b/lib/twisted-trunk/twisted/words/test/test_basechat.py @@ -26,12 +26,12 @@ L{twisted.words.im.interfaces.IPerson} who doesn't have an account associated with the L{basechat.ChatUI} instance has no effect. """ - self.assertEquals(self.person.name, "foo") - self.assertEquals(self.person.account, self.account) + self.assertEqual(self.person.name, "foo") + self.assertEqual(self.person.account, self.account) self.ui.contactChangedNick(self.person, "bar") - self.assertEquals(self.person.name, "foo") - self.assertEquals(self.person.account, self.account) + self.assertEqual(self.person.name, "foo") + self.assertEqual(self.person.account, self.account) def test_contactChangedNickNoConversation(self): @@ -41,12 +41,12 @@ """ self.ui.persons[self.person.name, self.person.account] = self.person - self.assertEquals(self.person.name, "foo") - self.assertEquals(self.person.account, self.account) + self.assertEqual(self.person.name, "foo") + self.assertEqual(self.person.account, self.account) self.ui.contactChangedNick(self.person, "bar") - self.assertEquals(self.person.name, "bar") - self.assertEquals(self.person.account, self.account) + self.assertEqual(self.person.name, "bar") + self.assertEqual(self.person.account, self.account) def test_contactChangedNickHasConversation(self): @@ -60,9 +60,9 @@ conversation = basechat.Conversation(self.person, self.ui) self.ui.conversations[self.person] = conversation - self.assertEquals(self.person.name, "foo") - self.assertEquals(self.person.account, self.account) + self.assertEqual(self.person.name, "foo") + self.assertEqual(self.person.account, self.account) self.ui.contactChangedNick(self.person, "bar") - self.assertEquals(self.person.name, "bar") - self.assertEquals(self.person.account, self.account) + self.assertEqual(self.person.name, "bar") + self.assertEqual(self.person.account, self.account) diff --git a/lib/twisted-trunk/twisted/words/test/test_domish.py b/lib/twisted-trunk/twisted/words/test/test_domish.py --- a/lib/twisted-trunk/twisted/words/test/test_domish.py +++ b/lib/twisted-trunk/twisted/words/test/test_domish.py @@ -12,36 +12,36 @@ class DomishTestCase(unittest.TestCase): def testEscaping(self): s = "&<>'\"" - self.assertEquals(domish.escapeToXml(s), "&<>'\"") - self.assertEquals(domish.escapeToXml(s, 1), "&<>'"") + self.assertEqual(domish.escapeToXml(s), "&<>'\"") + self.assertEqual(domish.escapeToXml(s, 1), "&<>'"") def testNamespaceObject(self): ns = domish.Namespace("testns") - self.assertEquals(ns.foo, ("testns", "foo")) + self.assertEqual(ns.foo, ("testns", "foo")) def testElementInit(self): e = domish.Element((None, "foo")) - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, None) - self.assertEquals(e.defaultUri, None) - self.assertEquals(e.parent, None) + self.assertEqual(e.name, "foo") + self.assertEqual(e.uri, None) + self.assertEqual(e.defaultUri, None) + self.assertEqual(e.parent, None) e = domish.Element(("", "foo")) - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, "") - self.assertEquals(e.defaultUri, "") - self.assertEquals(e.parent, None) + self.assertEqual(e.name, "foo") + self.assertEqual(e.uri, "") + self.assertEqual(e.defaultUri, "") + self.assertEqual(e.parent, None) e = domish.Element(("testns", "foo")) - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, "testns") - self.assertEquals(e.defaultUri, "testns") - self.assertEquals(e.parent, None) + self.assertEqual(e.name, "foo") + self.assertEqual(e.uri, "testns") + self.assertEqual(e.defaultUri, "testns") + self.assertEqual(e.parent, None) e = domish.Element(("testns", "foo"), "test2ns") - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, "testns") - self.assertEquals(e.defaultUri, "test2ns") + self.assertEqual(e.name, "foo") + self.assertEqual(e.uri, "testns") + self.assertEqual(e.defaultUri, "test2ns") def testChildOps(self): e = domish.Element(("testns", "foo")) @@ -55,26 +55,26 @@ e.addContent("123") # Check content merging - self.assertEquals(e.children[-1], "abc123") + self.assertEqual(e.children[-1], "abc123") # Check str()/content extraction - self.assertEquals(str(e), "somecontent") + self.assertEqual(str(e), "somecontent") # Check direct child accessor - self.assertEquals(e.bar2, b2) + self.assertEqual(e.bar2, b2) e.bar2.addContent("subcontent") e.bar2["bar2value"] = "somevalue" # Check child ops - self.assertEquals(e.children[1], e.bar2) - self.assertEquals(e.children[2], e.bar) + self.assertEqual(e.children[1], e.bar2) + self.assertEqual(e.children[2], e.bar) # Check attribute ops - self.assertEquals(e["attrib1"], "value1") + self.assertEqual(e["attrib1"], "value1") del e["attrib1"] - self.assertEquals(e.hasAttribute("attrib1"), 0) - self.assertEquals(e.hasAttribute("attrib2"), 0) - self.assertEquals(e[("testns2", "attrib2")], "value2") + self.assertEqual(e.hasAttribute("attrib1"), 0) + self.assertEqual(e.hasAttribute("attrib2"), 0) + self.assertEqual(e[("testns2", "attrib2")], "value2") def test_elements(self): @@ -147,11 +147,11 @@ def testHarness(self): xml = "" self.stream.parse(xml) - self.assertEquals(self.doc_started, True) - self.assertEquals(self.root.name, 'root') - self.assertEquals(self.elements[0].name, 'child') - self.assertEquals(self.elements[1].name, 'child2') - self.assertEquals(self.doc_ended, True) + self.assertEqual(self.doc_started, True) + self.assertEqual(self.root.name, 'root') + self.assertEqual(self.elements[0].name, 'child') + self.assertEqual(self.elements[1].name, 'child2') + self.assertEqual(self.doc_ended, True) def testBasic(self): xml = "\n" + \ @@ -161,42 +161,42 @@ "" self.stream.parse(xml) - self.assertEquals(self.root.name, 'stream') - self.assertEquals(self.root.uri, 'etherx') - self.assertEquals(self.elements[0].name, 'message') - self.assertEquals(self.elements[0].uri, 'jabber') - self.assertEquals(self.elements[0]['to'], 'bar') - self.assertEquals(self.elements[0].x.uri, 'xdelay') - self.assertEquals(unicode(self.elements[0].x), 'some&data>') + self.assertEqual(self.root.name, 'stream') + self.assertEqual(self.root.uri, 'etherx') + self.assertEqual(self.elements[0].name, 'message') + self.assertEqual(self.elements[0].uri, 'jabber') + self.assertEqual(self.elements[0]['to'], 'bar') + self.assertEqual(self.elements[0].x.uri, 'xdelay') + self.assertEqual(unicode(self.elements[0].x), 'some&data>') def testNoRootNS(self): xml = "" self.stream.parse(xml) - self.assertEquals(self.root.uri, '') - self.assertEquals(self.elements[0].uri, 'etherx') + self.assertEqual(self.root.uri, '') + self.assertEqual(self.elements[0].uri, 'etherx') def testNoDefaultNS(self): xml = """" self.stream.parse(xml) - self.assertEquals(self.root.uri, 'etherx') - self.assertEquals(self.root.defaultUri, '') - self.assertEquals(self.elements[0].uri, '') - self.assertEquals(self.elements[0].defaultUri, '') + self.assertEqual(self.root.uri, 'etherx') + self.assertEqual(self.root.defaultUri, '') + self.assertEqual(self.elements[0].uri, '') + self.assertEqual(self.elements[0].defaultUri, '') def testChildDefaultNS(self): xml = "" self.stream.parse(xml) - self.assertEquals(self.root.uri, 'testns') - self.assertEquals(self.elements[0].uri, 'testns') + self.assertEqual(self.root.uri, 'testns') + self.assertEqual(self.elements[0].uri, 'testns') def testEmptyChildNS(self): xml = "" self.stream.parse(xml) - self.assertEquals(self.elements[0].child2.uri, '') + self.assertEqual(self.elements[0].child2.uri, '') def test_namespaceWithWhitespace(self): @@ -206,8 +206,8 @@ """ xml = "" self.stream.parse(xml) - self.assertEquals(self.elements[0].uri, " bar baz ") - self.assertEquals( + self.assertEqual(self.elements[0].uri, " bar baz ") + self.assertEqual( self.elements[0].attributes, {(" bar baz ", "baz"): "quux"}) @@ -215,8 +215,8 @@ xml = "" self.stream.parse(xml) - self.assertEquals(self.root.localPrefixes['foo'], 'testns2') - self.assertEquals(self.elements[0].uri, 'testns2') + self.assertEqual(self.root.localPrefixes['foo'], 'testns2') + self.assertEqual(self.elements[0].uri, 'testns2') def testUnclosedElement(self): self.assertRaises(domish.ParserError, self.stream.parse, @@ -238,14 +238,14 @@ """ self.stream.parse(xml) - self.assertEquals('child1', self.elements[0].name) - self.assertEquals('testns', self.elements[0].uri) - self.assertEquals('', self.elements[0].defaultUri) - self.assertEquals({'foo': 'testns'}, self.elements[0].localPrefixes) - self.assertEquals('child2', self.elements[1].name) - self.assertEquals('testns', self.elements[1].uri) - self.assertEquals('testns', self.elements[1].defaultUri) - self.assertEquals({}, self.elements[1].localPrefixes) + self.assertEqual('child1', self.elements[0].name) + self.assertEqual('testns', self.elements[0].uri) + self.assertEqual('', self.elements[0].defaultUri) + self.assertEqual({'foo': 'testns'}, self.elements[0].localPrefixes) + self.assertEqual('child2', self.elements[1].name) + self.assertEqual('testns', self.elements[1].uri) + self.assertEqual('testns', self.elements[1].defaultUri) + self.assertEqual({}, self.elements[1].localPrefixes) @@ -278,62 +278,62 @@ class SerializerTests(unittest.TestCase): def testNoNamespace(self): e = domish.Element((None, "foo")) - self.assertEquals(e.toXml(), "") - self.assertEquals(e.toXml(closeElement = 0), "") + self.assertEqual(e.toXml(), "") + self.assertEqual(e.toXml(closeElement = 0), "") def testDefaultNamespace(self): e = domish.Element(("testns", "foo")) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testOtherNamespace(self): e = domish.Element(("testns", "foo"), "testns2") - self.assertEquals(e.toXml({'testns': 'bar'}), + self.assertEqual(e.toXml({'testns': 'bar'}), "") def testChildDefaultNamespace(self): e = domish.Element(("testns", "foo")) e.addElement("bar") - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testChildSameNamespace(self): e = domish.Element(("testns", "foo")) e.addElement(("testns", "bar")) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testChildSameDefaultNamespace(self): e = domish.Element(("testns", "foo")) e.addElement("bar", "testns") - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testChildOtherDefaultNamespace(self): e = domish.Element(("testns", "foo")) e.addElement(("testns2", "bar"), 'testns2') - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testOnlyChildDefaultNamespace(self): e = domish.Element((None, "foo")) e.addElement(("ns2", "bar"), 'ns2') - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testOnlyChildDefaultNamespace2(self): e = domish.Element((None, "foo")) e.addElement("bar") - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testChildInDefaultNamespace(self): e = domish.Element(("testns", "foo"), "testns2") e.addElement(("testns2", "bar")) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testQualifiedAttribute(self): e = domish.Element((None, "foo"), attribs = {("testns2", "bar"): "baz"}) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testQualifiedAttributeDefaultNS(self): e = domish.Element(("testns", "foo"), attribs = {("testns", "bar"): "baz"}) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testTwoChilds(self): e = domish.Element(('', "foo")) @@ -341,18 +341,18 @@ child1.addElement(('testns2', 'quux')) child2 = e.addElement(("testns3", "baz"), "testns4") child2.addElement(('testns', 'quux')) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testXMLNamespace(self): e = domish.Element((None, "foo"), attribs = {("http://www.w3.org/XML/1998/namespace", "lang"): "en_US"}) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testQualifiedAttributeGivenListOfPrefixes(self): e = domish.Element((None, "foo"), attribs = {("testns2", "bar"): "baz"}) - self.assertEquals(e.toXml({"testns2": "qux"}), + self.assertEqual(e.toXml({"testns2": "qux"}), "") def testNSPrefix(self): @@ -361,7 +361,7 @@ c = e.addElement(("testns2", "qux")) c[("testns2", "bar")] = "quux" - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testDefaultNSPrefix(self): e = domish.Element((None, "foo"), @@ -370,24 +370,24 @@ c[("testns2", "bar")] = "quux" c.addElement('foo') - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testPrefixScope(self): e = domish.Element(('testns', 'foo')) - self.assertEquals(e.toXml(prefixes={'testns': 'bar'}, + self.assertEqual(e.toXml(prefixes={'testns': 'bar'}, prefixesInScope=['bar']), "") def testLocalPrefixes(self): e = domish.Element(('testns', 'foo'), localPrefixes={'bar': 'testns'}) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testLocalPrefixesWithChild(self): e = domish.Element(('testns', 'foo'), localPrefixes={'bar': 'testns'}) e.addElement('baz') self.assertIdentical(e.baz.defaultUri, None) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def test_prefixesReuse(self): """ @@ -407,10 +407,10 @@ # test proper serialization on prefixes reuse e = domish.Element(('testns2', 'foo'), localPrefixes={'quux': 'testns2'}) - self.assertEquals("", + self.assertEqual("", e.toXml(prefixes=prefixes)) e = domish.Element(('testns2', 'foo')) - self.assertEquals("", + self.assertEqual("", e.toXml(prefixes=prefixes)) def testRawXMLSerialization(self): @@ -419,16 +419,16 @@ # The testcase below should NOT generate valid XML -- that's # the whole point of using the raw XML call -- it's the callers # responsiblity to ensure that the data inserted is valid - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testRawXMLWithUnicodeSerialization(self): e = domish.Element((None, "foo")) e.addRawXml(u"\u00B0") - self.assertEquals(e.toXml(), u"\u00B0") + self.assertEqual(e.toXml(), u"\u00B0") def testUnicodeSerialization(self): e = domish.Element((None, "foo")) e["test"] = u"my value\u0221e" e.addContent(u"A degree symbol...\u00B0") - self.assertEquals(e.toXml(), + self.assertEqual(e.toXml(), u"A degree symbol...\u00B0") diff --git a/lib/twisted-trunk/twisted/words/test/test_irc.py b/lib/twisted-trunk/twisted/words/test/test_irc.py --- a/lib/twisted-trunk/twisted/words/test/test_irc.py +++ b/lib/twisted-trunk/twisted/words/test/test_irc.py @@ -11,7 +11,7 @@ from twisted.trial.unittest import TestCase from twisted.words.protocols import irc from twisted.words.protocols.irc import IRCClient -from twisted.internet import protocol +from twisted.internet import protocol, task from twisted.test.proto_helpers import StringTransport, StringIOWithoutClosing @@ -67,12 +67,12 @@ "removed" direction. """ added, removed = irc.parseModes('+s', []) - self.assertEquals(added, [('s', None)]) - self.assertEquals(removed, []) + self.assertEqual(added, [('s', None)]) + self.assertEqual(removed, []) added, removed = irc.parseModes('-s', []) - self.assertEquals(added, []) - self.assertEquals(removed, [('s', None)]) + self.assertEqual(added, []) + self.assertEqual(removed, [('s', None)]) def test_singleDirection(self): @@ -81,14 +81,14 @@ parameters, results in all modes falling into the same direction group. """ added, removed = irc.parseModes('+stn', []) - self.assertEquals(added, [('s', None), + self.assertEqual(added, [('s', None), ('t', None), ('n', None)]) - self.assertEquals(removed, []) + self.assertEqual(removed, []) added, removed = irc.parseModes('-nt', []) - self.assertEquals(added, []) - self.assertEquals(removed, [('n', None), + self.assertEqual(added, []) + self.assertEqual(removed, [('n', None), ('t', None)]) @@ -97,10 +97,10 @@ Parsing a multi-direction mode setting with no parameters. """ added, removed = irc.parseModes('+s-n+ti', []) - self.assertEquals(added, [('s', None), + self.assertEqual(added, [('s', None), ('t', None), ('i', None)]) - self.assertEquals(removed, [('n', None)]) + self.assertEqual(removed, [('n', None)]) def test_consecutiveDirection(self): @@ -110,11 +110,11 @@ there were only one mode sequence in the same direction. """ added, removed = irc.parseModes('+sn+ti', []) - self.assertEquals(added, [('s', None), + self.assertEqual(added, [('s', None), ('n', None), ('t', None), ('i', None)]) - self.assertEquals(removed, []) + self.assertEqual(removed, []) def test_mismatchedParams(self): @@ -142,18 +142,18 @@ '+klbb', ['somekey', '42', 'nick!user at host', 'other!*@*'], self.paramModes) - self.assertEquals(added, [('k', 'somekey'), + self.assertEqual(added, [('k', 'somekey'), ('l', '42'), ('b', 'nick!user at host'), ('b', 'other!*@*')]) - self.assertEquals(removed, []) + self.assertEqual(removed, []) added, removed = irc.parseModes( '-klbb', ['nick!user at host', 'other!*@*'], self.paramModes) - self.assertEquals(added, []) - self.assertEquals(removed, [('k', None), + self.assertEqual(added, []) + self.assertEqual(removed, [('k', None), ('l', None), ('b', 'nick!user at host'), ('b', 'other!*@*')]) @@ -163,11 +163,11 @@ '+knbb', ['somekey', 'nick!user at host', 'other!*@*'], self.paramModes) - self.assertEquals(added, [('k', 'somekey'), + self.assertEqual(added, [('k', 'somekey'), ('n', None), ('b', 'nick!user at host'), ('b', 'other!*@*')]) - self.assertEquals(removed, []) + self.assertEqual(removed, []) @@ -185,13 +185,13 @@ def test_lowquoteSanity(self): """Testing client-server level quote/dequote""" for s in stringSubjects: - self.failUnlessEqual(s, irc.lowDequote(irc.lowQuote(s))) + self.assertEqual(s, irc.lowDequote(irc.lowQuote(s))) def test_ctcpquoteSanity(self): """Testing CTCP message level quote/dequote""" for s in stringSubjects: - self.failUnlessEqual(s, irc.ctcpDequote(irc.ctcpQuote(s))) + self.assertEqual(s, irc.ctcpDequote(irc.ctcpQuote(s))) @@ -227,7 +227,7 @@ disp = Dispatcher() args = (1, 2) res = disp.dispatch('working', *args) - self.assertEquals(res, args) + self.assertEqual(res, args) def test_dispatchUnknown(self): @@ -238,7 +238,7 @@ name = 'missing' args = (1, 2) res = disp.dispatch(name, *args) - self.assertEquals(res, (name,) + args) + self.assertEqual(res, (name,) + args) def test_dispatchMissingUnknown(self): @@ -261,12 +261,12 @@ L{_intOrDefault} converts values to C{int} if possible, otherwise returns a default value. """ - self.assertEquals(irc._intOrDefault(None), None) - self.assertEquals(irc._intOrDefault([]), None) - self.assertEquals(irc._intOrDefault(''), None) - self.assertEquals(irc._intOrDefault('hello', 5), 5) - self.assertEquals(irc._intOrDefault('123'), 123) - self.assertEquals(irc._intOrDefault(123), 123) + self.assertEqual(irc._intOrDefault(None), None) + self.assertEqual(irc._intOrDefault([]), None) + self.assertEqual(irc._intOrDefault(''), None) + self.assertEqual(irc._intOrDefault('hello', 5), 5) + self.assertEqual(irc._intOrDefault('123'), 123) + self.assertEqual(irc._intOrDefault(123), 123) def test_splitParam(self): @@ -289,7 +289,7 @@ for param, expected in params: res = _splitParam(param) - self.assertEquals(res, expected) + self.assertEqual(res, expected) self.assertRaises(ValueError, _splitParam, 'FOO=\\x') self.assertRaises(ValueError, _splitParam, 'FOO=\\xNN') @@ -304,7 +304,7 @@ split into a key and an empty string. """ res = irc.ServerSupportedFeatures._splitParamArgs(['A:1', 'B:2', 'C:', 'D']) - self.assertEquals(res, [('A', '1'), + self.assertEqual(res, [('A', '1'), ('B', '2'), ('C', ''), ('D', '')]) @@ -318,7 +318,7 @@ """ res = irc.ServerSupportedFeatures._splitParamArgs(['A:1', 'B:2', 'C'], irc._intOrDefault) - self.assertEquals(res, [('A', 1), + self.assertEqual(res, [('A', 1), ('B', 2), ('C', None)]) @@ -331,9 +331,9 @@ C{ValueError} if the prefix parameter is malformed. """ _parsePrefixParam = irc.ServerSupportedFeatures._parsePrefixParam - self.assertEquals(_parsePrefixParam(''), None) + self.assertEqual(_parsePrefixParam(''), None) self.assertRaises(ValueError, _parsePrefixParam, 'hello') - self.assertEquals(_parsePrefixParam('(ov)@+'), + self.assertEqual(_parsePrefixParam('(ov)@+'), {'o': ('@', 0), 'v': ('+', 1)}) @@ -347,21 +347,21 @@ C{ValueError}. """ _parseChanModesParam = irc.ServerSupportedFeatures._parseChanModesParam - self.assertEquals( + self.assertEqual( _parseChanModesParam([]), {'addressModes': '', 'param': '', 'setParam': '', 'noParam': ''}) - self.assertEquals( + self.assertEqual( _parseChanModesParam(['b', 'k', 'l', 'imnpst']), {'addressModes': 'b', 'param': 'k', 'setParam': 'l', 'noParam': 'imnpst'}) - self.assertEquals( + self.assertEqual( _parseChanModesParam(['b', 'k', 'l']), {'addressModes': 'b', 'param': 'k', @@ -387,13 +387,13 @@ 'EXCEPTS=Z', 'UNKNOWN=A,B,C']) - self.assertEquals(supported.getFeature('MODES'), 4) - self.assertEquals(supported.getFeature('CHANLIMIT'), + self.assertEqual(supported.getFeature('MODES'), 4) + self.assertEqual(supported.getFeature('CHANLIMIT'), [('#', 20), ('&', 10)]) - self.assertEquals(supported.getFeature('INVEX'), 'I') - self.assertEquals(supported.getFeature('EXCEPTS'), 'Z') - self.assertEquals(supported.getFeature('UNKNOWN'), ('A', 'B', 'C')) + self.assertEqual(supported.getFeature('INVEX'), 'I') + self.assertEqual(supported.getFeature('EXCEPTS'), 'Z') + self.assertEqual(supported.getFeature('UNKNOWN'), ('A', 'B', 'C')) self.assertTrue(supported.hasFeature('INVEX')) supported.parse(['-INVEX']) @@ -431,13 +431,13 @@ """ Perform some common tests on a feature known to use L{_intOrDefault}. """ - self.assertEquals( + self.assertEqual( self._parseFeature(name, None), default) - self.assertEquals( + self.assertEqual( self._parseFeature(name, 'notanint'), default) - self.assertEquals( + self.assertEqual( self._parseFeature(name, '42'), 42) @@ -455,7 +455,7 @@ supported = self._parse(features) self.assertTrue(supported.hasFeature(name)) - self.assertEquals(supported.getFeature(name), default) + self.assertEqual(supported.getFeature(name), default) def test_support_CHANMODES(self): @@ -468,21 +468,21 @@ self._testFeatureDefault('CHANMODES', [('CHANMODES', 'b,,lk,')]) self._testFeatureDefault('CHANMODES', [('CHANMODES', 'b,,lk,ha,ha')]) - self.assertEquals( + self.assertEqual( self._parseFeature('CHANMODES', ''), {'addressModes': '', 'param': '', 'setParam': '', 'noParam': ''}) - self.assertEquals( + self.assertEqual( self._parseFeature('CHANMODES', ',A'), {'addressModes': '', 'param': 'A', 'setParam': '', 'noParam': ''}) - self.assertEquals( + self.assertEqual( self._parseFeature('CHANMODES', 'A,Bc,Def,Ghij'), {'addressModes': 'A', 'param': 'Bc', @@ -495,7 +495,7 @@ The IDCHAN support parameter is parsed into a sequence of two-tuples giving channel prefix and ID length pairs. """ - self.assertEquals( + self.assertEqual( self._parseFeature('IDCHAN', '!:5'), [('!', '5')]) @@ -505,14 +505,14 @@ The MAXLIST support parameter is parsed into a sequence of two-tuples giving modes and their limits. """ - self.assertEquals( + self.assertEqual( self._parseFeature('MAXLIST', 'b:25,eI:50'), [('b', 25), ('eI', 50)]) # A non-integer parameter argument results in None. - self.assertEquals( + self.assertEqual( self._parseFeature('MAXLIST', 'b:25,eI:50,a:3.1415'), [('b', 25), ('eI', 50), ('a', None)]) - self.assertEquals( + self.assertEqual( self._parseFeature('MAXLIST', 'b:25,eI:50,a:notanint'), [('b', 25), ('eI', 50), ('a', None)]) @@ -522,7 +522,7 @@ The NETWORK support parameter is parsed as the network name, as specified by the server. """ - self.assertEquals( + self.assertEqual( self._parseFeature('NETWORK', 'IRCNet'), 'IRCNet') @@ -532,7 +532,7 @@ The SAFELIST support parameter is parsed into a boolean indicating whether the safe "list" command is supported or not. """ - self.assertEquals( + self.assertEqual( self._parseFeature('SAFELIST'), True) @@ -542,7 +542,7 @@ The STATUSMSG support parameter is parsed into a string of channel status that support the exclusive channel notice method. """ - self.assertEquals( + self.assertEqual( self._parseFeature('STATUSMSG', '@+'), '@+') @@ -553,17 +553,17 @@ strings to integers, of the maximum number of targets for a particular command. """ - self.assertEquals( + self.assertEqual( self._parseFeature('TARGMAX', 'PRIVMSG:4,NOTICE:3'), {'PRIVMSG': 4, 'NOTICE': 3}) # A non-integer parameter argument results in None. - self.assertEquals( + self.assertEqual( self._parseFeature('TARGMAX', 'PRIVMSG:4,NOTICE:3,KICK:3.1415'), {'PRIVMSG': 4, 'NOTICE': 3, 'KICK': None}) - self.assertEquals( + self.assertEqual( self._parseFeature('TARGMAX', 'PRIVMSG:4,NOTICE:3,KICK:notanint'), {'PRIVMSG': 4, 'NOTICE': 3, @@ -599,7 +599,7 @@ """ self._testFeatureDefault('CHANTYPES') - self.assertEquals( + self.assertEqual( self._parseFeature('CHANTYPES', '#&%'), ('#', '&', '%')) @@ -620,15 +620,15 @@ self._testFeatureDefault('PREFIX') self._testFeatureDefault('PREFIX', [('PREFIX', 'hello')]) - self.assertEquals( + self.assertEqual( self._parseFeature('PREFIX', None), None) - self.assertEquals( + self.assertEqual( self._parseFeature('PREFIX', '(ohv)@%+'), {'o': ('@', 0), 'h': ('%', 1), 'v': ('+', 2)}) - self.assertEquals( + self.assertEqual( self._parseFeature('PREFIX', '(hov)@%+'), {'o': ('%', 1), 'h': ('@', 0), @@ -660,10 +660,10 @@ to be used for "ban exception" modes. If no parameter is specified then the character C{e} is assumed. """ - self.assertEquals( + self.assertEqual( self._parseFeature('EXCEPTS', 'Z'), 'Z') - self.assertEquals( + self.assertEqual( self._parseFeature('EXCEPTS'), 'e') @@ -674,10 +674,10 @@ used for "invite exception" modes. If no parameter is specified then the character C{I} is assumed. """ - self.assertEquals( + self.assertEqual( self._parseFeature('INVEX', 'Z'), 'Z') - self.assertEquals( + self.assertEqual( self._parseFeature('INVEX'), 'I') @@ -687,13 +687,20 @@ performLogin = 0 + class CTCPTest(unittest.TestCase): + """ + Tests for L{twisted.words.protocols.irc.IRCClient} CTCP handling. + """ def setUp(self): self.file = StringIOWithoutClosing() self.transport = protocol.FileWrapper(self.file) self.client = IRCClientWithoutLogin() self.client.makeConnection(self.transport) + self.addCleanup(self.transport.loseConnection) + self.addCleanup(self.client.connectionLost, None) + def test_ERRMSG(self): """Testing CTCP query ERRMSG. @@ -716,7 +723,7 @@ self.client.dataReceived(errQuery) reply = self.file.getvalue() - self.failUnlessEqual(errReply, reply) + self.assertEqual(errReply, reply) def test_noNumbersVERSION(self): @@ -733,7 +740,7 @@ 'EOL': irc.CR + irc.LF, 'vname': self.client.versionName}) reply = self.file.getvalue() - self.assertEquals(versionReply, reply) + self.assertEqual(versionReply, reply) def test_fullVERSION(self): @@ -754,14 +761,60 @@ 'vnum': self.client.versionNum, 'venv': self.client.versionEnv}) reply = self.file.getvalue() - self.assertEquals(versionReply, reply) + self.assertEqual(versionReply, reply) - def tearDown(self): - self.transport.loseConnection() - self.client.connectionLost() - del self.client - del self.transport + def test_noDuplicateCTCPDispatch(self): + """ + Duplicated CTCP messages are ignored and no reply is made. + """ + def testCTCP(user, channel, data): + self.called += 1 + + self.called = 0 + self.client.ctcpQuery_TESTTHIS = testCTCP + + self.client.irc_PRIVMSG( + 'foo!bar at baz.quux', [ + '#chan', + '%(X)sTESTTHIS%(X)sfoo%(X)sTESTTHIS%(X)s' % {'X': irc.X_DELIM}]) + self.assertEqual( + self.file.getvalue(), + '') + self.assertEqual(self.called, 1) + + + def test_noDefaultDispatch(self): + """ + The fallback handler is invoked for unrecognized CTCP messages. + """ + def unknownQuery(user, channel, tag, data): + self.calledWith = (user, channel, tag, data) + self.called += 1 + + self.called = 0 + self.patch(self.client, 'ctcpUnknownQuery', unknownQuery) + self.client.irc_PRIVMSG( + 'foo!bar at baz.quux', [ + '#chan', + '%(X)sNOTREAL%(X)s' % {'X': irc.X_DELIM}]) + self.assertEqual( + self.file.getvalue(), + '') + self.assertEqual( + self.calledWith, + ('foo!bar at baz.quux', '#chan', 'NOTREAL', None)) + self.assertEqual(self.called, 1) + + # The fallback handler is not invoked for duplicate unknown CTCP + # messages. + self.client.irc_PRIVMSG( + 'foo!bar at baz.quux', [ + '#chan', + '%(X)sNOTREAL%(X)sfoo%(X)sNOTREAL%(X)s' % {'X': irc.X_DELIM}]) + self.assertEqual(self.called, 2) + + class NoticingClient(IRCClientWithoutLogin, object): methods = { @@ -841,19 +894,16 @@ del dict[key] return value + + class ClientImplementationTests(unittest.TestCase): def setUp(self): - self.file = StringIOWithoutClosing() - self.transport = protocol.FileWrapper(self.file) + self.transport = StringTransport() self.client = NoticingClient() self.client.makeConnection(self.transport) - - def tearDown(self): - self.transport.loseConnection() - self.client.connectionLost() - del self.client - del self.transport + self.addCleanup(self.transport.loseConnection) + self.addCleanup(self.client.connectionLost, None) def _serverTestImpl(self, code, msg, func, **kw): @@ -869,7 +919,7 @@ msg + "\r\n") self.client.dataReceived(message) - self.assertEquals( + self.assertEqual( self.client.calls, [(func, kw)]) @@ -965,10 +1015,10 @@ ":host.name 372 nickname :- Welcome to host.name", ":host.name 376 nickname :End of /MOTD command."] for L in lines: - self.assertEquals(self.client.calls, []) + self.assertEqual(self.client.calls, []) self.client.dataReceived(L + '\r\n') - self.assertEquals( + self.assertEqual( self.client.calls, [("receivedMOTD", {"motd": ["host.name Message of the Day -", "Welcome to host.name"]})]) @@ -990,7 +1040,7 @@ for L in lines: self.client.dataReceived(L + '\r\n') - self.assertEquals( + self.assertEqual( self.client.calls, [("receivedMOTD", {"motd": ["Welcome to host.name"]})]) @@ -1006,7 +1056,7 @@ group + " :" + msg + "\r\n") self.client.dataReceived(message) - self.assertEquals( + self.assertEqual( self.client.calls, [(func, kw)]) self.client.calls = [] @@ -1036,8 +1086,8 @@ require arguments when being added or removed. """ add, remove = map(sorted, self.client.getChannelModeParams()) - self.assertEquals(add, ['b', 'h', 'k', 'l', 'o', 'v']) - self.assertEquals(remove, ['b', 'h', 'o', 'v']) + self.assertEqual(add, ['b', 'h', 'k', 'l', 'o', 'v']) + self.assertEqual(remove, ['b', 'h', 'o', 'v']) def removeFeature(name): name = '-' + name @@ -1052,14 +1102,14 @@ # None. removeFeature('CHANMODES') add, remove = map(sorted, self.client.getChannelModeParams()) - self.assertEquals(add, ['h', 'o', 'v']) - self.assertEquals(remove, ['h', 'o', 'v']) + self.assertEqual(add, ['h', 'o', 'v']) + self.assertEqual(remove, ['h', 'o', 'v']) # Remove PREFIX feature, causing getFeature('PREFIX') to return None. removeFeature('PREFIX') add, remove = map(sorted, self.client.getChannelModeParams()) - self.assertEquals(add, []) - self.assertEquals(remove, []) + self.assertEqual(add, []) + self.assertEqual(remove, []) # Restore ISUPPORT features. self._sendISUPPORT() @@ -1074,8 +1124,8 @@ parameters when added and removed, respectively. """ add, remove = map(sorted, self.client.getUserModeParams()) - self.assertEquals(add, []) - self.assertEquals(remove, []) + self.assertEqual(add, []) + self.assertEqual(remove, []) def _sendModeChange(self, msg, args='', target=None): @@ -1098,9 +1148,9 @@ for n, result in enumerate(results): method, data = result - self.assertEquals(method, 'modeChanged') - self.assertEquals(data['user'], 'Wolf!~wolf at yok.utu.fi') - self.assertEquals(data['channel'], target) + self.assertEqual(method, 'modeChanged') + self.assertEqual(data['user'], 'Wolf!~wolf at yok.utu.fi') + self.assertEqual(data['channel'], target) results[n] = tuple([data[key] for key in ('set', 'modes', 'args')]) return results @@ -1110,7 +1160,7 @@ Compare the expected result with the one returned by the client. """ result = self._parseModeChange(self.client.calls, target) - self.assertEquals(result, expected) + self.assertEqual(result, expected) self.client.calls = [] @@ -1166,7 +1216,7 @@ self._sendModeChange('+s', 'wrong') self._checkModeChange([]) errors = self.flushLoggedErrors(irc.IRCBadModes) - self.assertEquals(len(errors), 1) + self.assertEqual(len(errors), 1) self.assertSubstring( 'Too many parameters', errors[0].getErrorMessage()) @@ -1179,7 +1229,7 @@ self._sendModeChange('+o') self._checkModeChange([]) errors = self.flushLoggedErrors(irc.IRCBadModes) - self.assertEquals(len(errors), 1) + self.assertEqual(len(errors), 1) self.assertSubstring( 'Not enough parameters', errors[0].getErrorMessage()) @@ -1206,6 +1256,51 @@ self._checkModeChange([(True, 'Z', ('an_arg',))], target=target) + def test_heartbeat(self): + """ + When the I{RPL_WELCOME} message is received a heartbeat is started that + will send a I{PING} message to the IRC server every + L{irc.IRCClient.heartbeatInterval} seconds. When the transport is + closed the heartbeat looping call is stopped too. + """ + def _createHeartbeat(): + heartbeat = self._originalCreateHeartbeat() + heartbeat.clock = self.clock + return heartbeat + + self.clock = task.Clock() + self._originalCreateHeartbeat = self.client._createHeartbeat + self.patch(self.client, '_createHeartbeat', _createHeartbeat) + + self.assertIdentical(self.client._heartbeat, None) + self.client.irc_RPL_WELCOME('foo', []) + self.assertNotIdentical(self.client._heartbeat, None) + self.assertEqual(self.client.hostname, 'foo') + + # Pump the clock enough to trigger one LoopingCall. + self.assertEqual(self.transport.value(), '') + self.clock.advance(self.client.heartbeatInterval) + self.assertEqual(self.transport.value(), 'PING foo\r\n') + + # When the connection is lost the heartbeat is stopped. + self.transport.loseConnection() + self.client.connectionLost(None) + self.assertEqual( + len(self.clock.getDelayedCalls()), 0) + self.assertIdentical(self.client._heartbeat, None) + + + def test_heartbeatDisabled(self): + """ + If L{irc.IRCClient.heartbeatInterval} is set to C{None} then no + heartbeat is created. + """ + self.assertIdentical(self.client._heartbeat, None) + self.client.heartbeatInterval = None + self.client.irc_RPL_WELCOME('foo', []) + self.assertIdentical(self.client._heartbeat, None) + + class BasicServerFunctionalityTestCase(unittest.TestCase): def setUp(self): @@ -1216,7 +1311,7 @@ def check(self, s): - self.assertEquals(self.f.getvalue(), s) + self.assertEqual(self.f.getvalue(), s) def testPrivmsg(self): @@ -1291,7 +1386,7 @@ channel prefix character, one is prepended to it. """ self.client.invite('foo', 'bar') - self.assertEquals(self.client.lines, ['INVITE foo #bar']) + self.assertEqual(self.client.lines, ['INVITE foo #bar']) def test_invite(self): @@ -1300,7 +1395,7 @@ username and a channel. """ self.client.invite('foo', '#bar') - self.assertEquals(self.client.lines, ['INVITE foo #bar']) + self.assertEqual(self.client.lines, ['INVITE foo #bar']) @@ -1311,7 +1406,7 @@ def testSingleLine(self): self.client.msg('foo', 'bar') - self.assertEquals(self.client.lines, ['PRIVMSG foo :bar']) + self.assertEqual(self.client.lines, ['PRIVMSG foo :bar']) def testDodgyMaxLength(self): @@ -1322,7 +1417,7 @@ def testMultipleLine(self): maxLen = len('PRIVMSG foo :') + 3 + 2 # 2 for line endings self.client.msg('foo', 'barbazbo', maxLen) - self.assertEquals(self.client.lines, ['PRIVMSG foo :bar', + self.assertEqual(self.client.lines, ['PRIVMSG foo :bar', 'PRIVMSG foo :baz', 'PRIVMSG foo :bo']) @@ -1331,13 +1426,13 @@ msg = 'barbazbo' maxLen = len('PRIVMSG foo :%s' % (msg,)) + 2 self.client.msg('foo', msg, maxLen) - self.assertEquals(self.client.lines, ['PRIVMSG foo :%s' % (msg,)]) + self.assertEqual(self.client.lines, ['PRIVMSG foo :%s' % (msg,)]) self.client.lines = [] self.client.msg('foo', msg, maxLen-1) - self.assertEquals(2, len(self.client.lines)) + self.assertEqual(2, len(self.client.lines)) self.client.lines = [] self.client.msg('foo', msg, maxLen+1) - self.assertEquals(1, len(self.client.lines)) + self.assertEqual(1, len(self.client.lines)) def test_newlinesAtStart(self): @@ -1346,7 +1441,7 @@ """ self.client.lines = [] self.client.msg('foo', '\nbar') - self.assertEquals(self.client.lines, ['PRIVMSG foo :bar']) + self.assertEqual(self.client.lines, ['PRIVMSG foo :bar']) def test_newlinesAtEnd(self): @@ -1355,7 +1450,7 @@ """ self.client.lines = [] self.client.msg('foo', 'bar\n') - self.assertEquals(self.client.lines, ['PRIVMSG foo :bar']) + self.assertEqual(self.client.lines, ['PRIVMSG foo :bar']) def test_newlinesWithinMessage(self): @@ -1364,7 +1459,7 @@ """ self.client.lines = [] self.client.msg('foo', 'bar\n\nbaz') - self.assertEquals(self.client.lines, [ + self.assertEqual(self.client.lines, [ 'PRIVMSG foo :bar', 'PRIVMSG foo :baz' ]) @@ -1376,7 +1471,7 @@ """ self.client.lines = [] self.client.msg('foo', 'bar\n\nbaz') - self.assertEquals(self.client.lines, [ + self.assertEqual(self.client.lines, [ 'PRIVMSG foo :bar', 'PRIVMSG foo :baz', ]) @@ -1388,7 +1483,7 @@ maxLineLength = irc.MAX_COMMAND_LENGTH - 2 - len('PRIVMSG foo :') self.client.msg('foo', 'o' * (maxLineLength + 1), *args) - self.assertEquals(self.client.lines, [ + self.assertEqual(self.client.lines, [ 'PRIVMSG foo :' + maxLineLength * 'o', 'PRIVMSG foo :o', ]) @@ -1418,7 +1513,7 @@ longline = 'o' * (irc.MAX_COMMAND_LENGTH // 2) self.client.msg('foo', longline + '\n' + longline) - self.assertEquals(self.client.lines, [ + self.assertEqual(self.client.lines, [ 'PRIVMSG foo :' + longline, 'PRIVMSG foo :' + longline, ]) @@ -1433,7 +1528,7 @@ longline = 'o' * (irc.MAX_COMMAND_LENGTH // 2) self.client.msg('foo', longline + ' ' + longline) - self.assertEquals(self.client.lines, [ + self.assertEqual(self.client.lines, [ 'PRIVMSG foo :' + longline, 'PRIVMSG foo :' + longline, ]) @@ -1443,8 +1538,8 @@ # Whiteboxing self.assertRaises(ValueError, irc.split, 'foo', -1) self.assertRaises(ValueError, irc.split, 'foo', 0) - self.assertEquals([], irc.split('', 1)) - self.assertEquals([], irc.split('')) + self.assertEqual([], irc.split('', 1)) + self.assertEqual([], irc.split('')) def test_splitDelimiters(self): @@ -1454,9 +1549,9 @@ Nothing should be added to the output list because of it. """ r = irc.split("xx yyz", 2) - self.assertEquals(['xx', 'yy', 'z'], r) + self.assertEqual(['xx', 'yy', 'z'], r) r = irc.split("xx\nyyz", 2) - self.assertEquals(['xx', 'yy', 'z'], r) + self.assertEqual(['xx', 'yy', 'z'], r) def test_splitValidatesLength(self): @@ -1473,7 +1568,7 @@ then sends the message to the server for delivery to that channel. """ self.client.say("thechannel", "the message") - self.assertEquals(self.client.lines, ["PRIVMSG #thechannel :the message"]) + self.assertEqual(self.client.lines, ["PRIVMSG #thechannel :the message"]) @@ -1493,7 +1588,10 @@ # Sanity check - we don't want anything to have happened at this # point, since we're not in a test yet. - self.assertEquals(self.transport.value(), "") + self.assertEqual(self.transport.value(), "") + + self.addCleanup(self.transport.loseConnection) + self.addCleanup(self.protocol.connectionLost, None) def getLastLine(self, transport): @@ -1513,7 +1611,7 @@ 'AWAY :%s' % (message,), '', ] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) def test_back(self): @@ -1525,7 +1623,7 @@ 'AWAY :', '', ] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) def test_whois(self): @@ -1533,7 +1631,7 @@ L{IRCClient.whois} sends a WHOIS message. """ self.protocol.whois('alice') - self.assertEquals( + self.assertEqual( self.transport.value().split('\r\n'), ['WHOIS alice', '']) @@ -1544,7 +1642,7 @@ value is passed for the C{server} parameter. """ self.protocol.whois('alice', 'example.org') - self.assertEquals( + self.assertEqual( self.transport.value().split('\r\n'), ['WHOIS example.org alice', '']) @@ -1565,7 +1663,7 @@ 'USER %s %s %s :%s' % ( username, hostname, servername, self.protocol.realname), ''] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) def test_registerWithPassword(self): @@ -1586,7 +1684,7 @@ 'USER %s %s %s :%s' % ( username, hostname, servername, self.protocol.realname), ''] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) def test_registerWithTakenNick(self): @@ -1608,7 +1706,7 @@ # Keep chaining underscores for each collision self.protocol.irc_ERR_NICKNAMEINUSE('prefix', ['param']) lastLine = self.getLastLine(self.transport) - self.assertEquals(lastLine, 'NICK %s' % (username + '__',)) + self.assertEqual(lastLine, 'NICK %s' % (username + '__',)) def test_overrideAlterCollidedNick(self): @@ -1621,7 +1719,7 @@ self.protocol.register(nick) self.protocol.irc_ERR_NICKNAMEINUSE('prefix', ['param']) lastLine = self.getLastLine(self.transport) - self.assertEquals( + self.assertEqual( lastLine, 'NICK %s' % (nick + '***',)) @@ -1635,9 +1733,9 @@ self.protocol.register(oldnick) self.protocol.irc_RPL_WELCOME('prefix', ['param']) self.protocol.setNick(newnick) - self.assertEquals(self.protocol.nickname, oldnick) + self.assertEqual(self.protocol.nickname, oldnick) self.protocol.irc_NICK('%s!quux at qux' % (oldnick,), [newnick]) - self.assertEquals(self.protocol.nickname, newnick) + self.assertEqual(self.protocol.nickname, newnick) def test_erroneousNick(self): @@ -1648,16 +1746,16 @@ """ # Registration case: change illegal nickname to erroneousNickFallback badnick = 'foo' - self.assertEquals(self.protocol._registered, False) + self.assertEqual(self.protocol._registered, False) self.protocol.register(badnick) self.protocol.irc_ERR_ERRONEUSNICKNAME('prefix', ['param']) lastLine = self.getLastLine(self.transport) - self.assertEquals( + self.assertEqual( lastLine, 'NICK %s' % (self.protocol.erroneousNickFallback,)) self.protocol.irc_RPL_WELCOME('prefix', ['param']) - self.assertEquals(self.protocol._registered, True) + self.assertEqual(self.protocol._registered, True) self.protocol.setNick(self.protocol.erroneousNickFallback) - self.assertEquals( + self.assertEqual( self.protocol.nickname, self.protocol.erroneousNickFallback) # Illegal nick change attempt after registration. Fall back to the old @@ -1666,9 +1764,9 @@ self.protocol.setNick(badnick) self.protocol.irc_ERR_ERRONEUSNICKNAME('prefix', ['param']) lastLine = self.getLastLine(self.transport) - self.assertEquals( + self.assertEqual( lastLine, 'NICK %s' % (badnick,)) - self.assertEquals(self.protocol.nickname, oldnick) + self.assertEqual(self.protocol.nickname, oldnick) def test_describe(self): @@ -1685,7 +1783,7 @@ 'PRIVMSG %s :\01ACTION %s\01' % (target, action), 'PRIVMSG %s :\01ACTION %s\01' % (channel, action), ''] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) def test_me(self): @@ -1704,14 +1802,14 @@ 'PRIVMSG %s :\01ACTION %s\01' % ('#' + target, action), 'PRIVMSG %s :\01ACTION %s\01' % (channel, action), ''] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) warnings = self.flushWarnings( offendingFunctions=[self.test_me]) - self.assertEquals( + self.assertEqual( warnings[0]['message'], "me() is deprecated since Twisted 9.0. Use IRCClient.describe().") - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals(len(warnings), 2) + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 2) def test_noticedDoesntPrivmsg(self): diff --git a/lib/twisted-trunk/twisted/words/test/test_irc_service.py b/lib/twisted-trunk/twisted/words/test/test_irc_service.py --- a/lib/twisted-trunk/twisted/words/test/test_irc_service.py +++ b/lib/twisted-trunk/twisted/words/test/test_irc_service.py @@ -38,7 +38,7 @@ self.ircUser.irc_NICK("", ["mynick"]) self.stringTransport.clear() self.ircUser.sendMessage("foo") - self.assertEquals(":example.com foo mynick\r\n", + self.assertEqual(":example.com foo mynick\r\n", self.stringTransport.value()) @@ -77,9 +77,9 @@ response = self.response() start = list(self.scanResponse(response, irc.RPL_MOTDSTART)) end = list(self.scanResponse(response, irc.RPL_ENDOFMOTD)) - self.assertEquals(start, + self.assertEqual(start, [(0, ('example.com', '375', ['mynick', '- example.com Message of the Day - ']))]) - self.assertEquals(end, + self.assertEqual(end, [(1, ('example.com', '376', ['mynick', 'End of /MOTD command.']))]) @@ -98,7 +98,7 @@ creation = ('This server was created on %s' % (self.factory._serverInfo["creationDate"],)) - self.assertEquals(self.response(), + self.assertEqual(self.response(), [('example.com', '375', ['john', '- example.com Message of the Day - ']), ('example.com', '376', ['john', 'End of /MOTD command.']), diff --git a/lib/twisted-trunk/twisted/words/test/test_ircsupport.py b/lib/twisted-trunk/twisted/words/test/test_ircsupport.py --- a/lib/twisted-trunk/twisted/words/test/test_ircsupport.py +++ b/lib/twisted-trunk/twisted/words/test/test_ircsupport.py @@ -42,7 +42,7 @@ """ transport = StringTransport() self.proto.makeConnection(transport) - self.assertEquals( + self.assertEqual( transport.value(), "NICK alice\r\n" "USER alice foo bar :Twisted-IM user\r\n") @@ -56,7 +56,7 @@ self.account.password = "secret" transport = StringTransport() self.proto.makeConnection(transport) - self.assertEquals( + self.assertEqual( transport.value(), "PASS :secret\r\n" "NICK alice\r\n" @@ -71,7 +71,7 @@ self.account.channels = ['#foo', '#bar'] transport = StringTransport() self.proto.makeConnection(transport) - self.assertEquals( + self.assertEqual( transport.value(), "NICK alice\r\n" "USER alice foo bar :Twisted-IM user\r\n" diff --git a/lib/twisted-trunk/twisted/words/test/test_jabberclient.py b/lib/twisted-trunk/twisted/words/test/test_jabberclient.py --- a/lib/twisted-trunk/twisted/words/test/test_jabberclient.py +++ b/lib/twisted-trunk/twisted/words/test/test_jabberclient.py @@ -40,7 +40,7 @@ """ self.init.xmlstream.version = (0, 0) exc = self.assertRaises(error.StreamError, self.init.initialize) - self.assertEquals('unsupported-version', exc.condition) + self.assertEqual('unsupported-version', exc.condition) @@ -136,9 +136,9 @@ The server checks the credentials and responds with an empty result signalling success. """ - self.assertEquals('user', unicode(iq.query.username)) - self.assertEquals('secret', unicode(iq.query.password)) - self.assertEquals('resource', unicode(iq.query.resource)) + self.assertEqual('user', unicode(iq.query.username)) + self.assertEqual('secret', unicode(iq.query.password)) + self.assertEqual('resource', unicode(iq.query.resource)) # Send server response response = xmlstream.toResponse(iq, 'result') @@ -192,10 +192,10 @@ The server checks the credentials and responds with an empty result signalling success. """ - self.assertEquals('user', unicode(iq.query.username)) - self.assertEquals(sha1('12345secret').hexdigest(), + self.assertEqual('user', unicode(iq.query.username)) + self.assertEqual(sha1('12345secret').hexdigest(), unicode(iq.query.digest).encode('utf-8')) - self.assertEquals('resource', unicode(iq.query.resource)) + self.assertEqual('resource', unicode(iq.query.resource)) # Send server response response = xmlstream.toResponse(iq, 'result') @@ -312,7 +312,7 @@ self.pipe.source.send(response) def cb(result): - self.assertEquals(jid.JID('user at example.com/other resource'), + self.assertEqual(jid.JID('user at example.com/other resource'), self.authenticator.jid) d1 = self.waitFor(IQ_BIND_SET, onBind) diff --git a/lib/twisted-trunk/twisted/words/test/test_jabbercomponent.py b/lib/twisted-trunk/twisted/words/test/test_jabbercomponent.py --- a/lib/twisted-trunk/twisted/words/test/test_jabbercomponent.py +++ b/lib/twisted-trunk/twisted/words/test/test_jabbercomponent.py @@ -47,9 +47,9 @@ # the initializer should have sent the handshake request handshake = self.output[-1] - self.assertEquals('handshake', handshake.name) - self.assertEquals('test:component', handshake.uri) - self.assertEquals(sha1("%s%s" % ('12345', 'secret')).hexdigest(), + self.assertEqual('handshake', handshake.name) + self.assertEqual('test:component', handshake.uri) + self.assertEqual(sha1("%s%s" % ('12345', 'secret')).hexdigest(), unicode(handshake)) # successful authentication @@ -81,11 +81,11 @@ # Calculate what we expect the handshake value to be hv = sha1("%s%s" % ("12345", "secret")).hexdigest() - self.assertEquals(outlist[1], "%s" % (hv)) + self.assertEqual(outlist[1], "%s" % (hv)) xs.dataReceived("") - self.assertEquals(self.authComplete, True) + self.assertEqual(self.authComplete, True) class JabberServiceHarness(component.Service): @@ -123,19 +123,19 @@ xs.connectionMade() # Ensure the test service harness got notified - self.assertEquals(True, svc.transportConnectedFlag) + self.assertEqual(True, svc.transportConnectedFlag) # Jump ahead and pretend like the stream got auth'd xs.dispatch(xs, xmlstream.STREAM_AUTHD_EVENT) # Ensure the test service harness got notified - self.assertEquals(True, svc.componentConnectedFlag) + self.assertEqual(True, svc.componentConnectedFlag) # Pretend to drop the connection xs.connectionLost(None) # Ensure the test service harness got notified - self.assertEquals(True, svc.componentDisconnectedFlag) + self.assertEqual(True, svc.componentDisconnectedFlag) @@ -154,12 +154,12 @@ pipe = XmlPipe() router.addRoute('example.org', pipe.sink) - self.assertEquals(1, len(router.routes)) - self.assertEquals(pipe.sink, router.routes['example.org']) + self.assertEqual(1, len(router.routes)) + self.assertEqual(pipe.sink, router.routes['example.org']) element = domish.Element(('testns', 'test')) pipe.source.send(element) - self.assertEquals([element], routed) + self.assertEqual([element], routed) def test_route(self): @@ -179,7 +179,7 @@ stanza['from'] = 'component1.example.org' stanza['to'] = 'component2.example.org' component1.source.send(stanza) - self.assertEquals([stanza], outgoing) + self.assertEqual([stanza], outgoing) def test_routeDefault(self): @@ -202,7 +202,7 @@ stanza['from'] = 'component1.example.org' stanza['to'] = 'example.com' component1.source.send(stanza) - self.assertEquals([stanza], outgoing) + self.assertEqual([stanza], outgoing) @@ -247,7 +247,7 @@ self.assertEqual((0, 0), xs.version) self.assertNotIdentical(None, xs.sid) self.assertTrue(xs._headerSent) - self.assertEquals(('/*', xs.authenticator.onElement), observers[-1]) + self.assertEqual(('/*', xs.authenticator.onElement), observers[-1]) def test_streamStartedWrongNamespace(self): @@ -262,8 +262,8 @@ xs.dataReceived("") - self.assertEquals(1, len(streamErrors)) - self.assertEquals('invalid-namespace', streamErrors[-1].condition) + self.assertEqual(1, len(streamErrors)) + self.assertEqual('invalid-namespace', streamErrors[-1].condition) def test_streamStartedNoTo(self): @@ -277,8 +277,8 @@ xs.makeConnection(self) xs.dataReceived("") - self.assertEquals(1, len(streamErrors)) - self.assertEquals('improper-addressing', streamErrors[-1].condition) + self.assertEqual(1, len(streamErrors)) + self.assertEqual('improper-addressing', streamErrors[-1].condition) def test_onElement(self): @@ -309,7 +309,7 @@ element = domish.Element(('jabber:component:accept', 'message')) xs.authenticator.onElement(element) self.assertFalse(handshakes) - self.assertEquals('not-authorized', streamErrors[-1].condition) + self.assertEqual('not-authorized', streamErrors[-1].condition) def test_onHandshake(self): @@ -327,7 +327,7 @@ theHash = '32532c0f7dbf1253c095b18b18e36d38d94c1256' xs.authenticator.onHandshake(theHash) self.assertEqual('', self.output[-1]) - self.assertEquals(1, len(authd)) + self.assertEqual(1, len(authd)) def test_onHandshakeWrongHash(self): @@ -347,8 +347,8 @@ xs.sid = u'1234' theHash = '1234' xs.authenticator.onHandshake(theHash) - self.assertEquals('not-authorized', streamErrors[-1].condition) - self.assertEquals(0, len(authd)) + self.assertEqual('not-authorized', streamErrors[-1].condition) + self.assertEqual(0, len(authd)) diff --git a/lib/twisted-trunk/twisted/words/test/test_jabbererror.py b/lib/twisted-trunk/twisted/words/test/test_jabbererror.py --- a/lib/twisted-trunk/twisted/words/test/test_jabbererror.py +++ b/lib/twisted-trunk/twisted/words/test/test_jabbererror.py @@ -24,7 +24,7 @@ e = error.BaseError('feature-not-implemented') element = e.getElement() self.assertIdentical(element.uri, None) - self.assertEquals(len(element.children), 1) + self.assertEqual(len(element.children), 1) def test_getElementText(self): """ @@ -32,9 +32,9 @@ """ e = error.BaseError('feature-not-implemented', 'text') element = e.getElement() - self.assertEquals(len(element.children), 2) - self.assertEquals(unicode(element.text), 'text') - self.assertEquals(element.text.getAttribute((NS_XML, 'lang')), None) + self.assertEqual(len(element.children), 2) + self.assertEqual(unicode(element.text), 'text') + self.assertEqual(element.text.getAttribute((NS_XML, 'lang')), None) def test_getElementTextLang(self): """ @@ -42,9 +42,9 @@ """ e = error.BaseError('feature-not-implemented', 'text', 'en_US') element = e.getElement() - self.assertEquals(len(element.children), 2) - self.assertEquals(unicode(element.text), 'text') - self.assertEquals(element.text[(NS_XML, 'lang')], 'en_US') + self.assertEqual(len(element.children), 2) + self.assertEqual(unicode(element.text), 'text') + self.assertEqual(element.text[(NS_XML, 'lang')], 'en_US') def test_getElementAppCondition(self): """ @@ -53,8 +53,8 @@ ac = domish.Element(('testns', 'myerror')) e = error.BaseError('feature-not-implemented', appCondition=ac) element = e.getElement() - self.assertEquals(len(element.children), 2) - self.assertEquals(element.myerror, ac) + self.assertEqual(len(element.children), 2) + self.assertEqual(element.myerror, ac) class StreamErrorTest(unittest.TestCase): @@ -64,7 +64,7 @@ """ e = error.StreamError('feature-not-implemented') element = e.getElement() - self.assertEquals(element.uri, NS_STREAMS) + self.assertEqual(element.uri, NS_STREAMS) def test_getElementConditionNamespace(self): """ @@ -72,7 +72,7 @@ """ e = error.StreamError('feature-not-implemented') element = e.getElement() - self.assertEquals(NS_XMPP_STREAMS, getattr(element, 'feature-not-implemented').uri) + self.assertEqual(NS_XMPP_STREAMS, getattr(element, 'feature-not-implemented').uri) def test_getElementTextNamespace(self): """ @@ -80,7 +80,7 @@ """ e = error.StreamError('feature-not-implemented', 'text') element = e.getElement() - self.assertEquals(NS_XMPP_STREAMS, element.text.uri) + self.assertEqual(NS_XMPP_STREAMS, element.text.uri) @@ -95,8 +95,8 @@ Remote Server Timeout should yield type wait, code 504. """ e = error.StanzaError('remote-server-timeout') - self.assertEquals('wait', e.type) - self.assertEquals('504', e.code) + self.assertEqual('wait', e.type) + self.assertEqual('504', e.code) def test_getElementPlain(self): @@ -105,9 +105,9 @@ """ e = error.StanzaError('feature-not-implemented') element = e.getElement() - self.assertEquals(element.uri, None) - self.assertEquals(element['type'], 'cancel') - self.assertEquals(element['code'], '501') + self.assertEqual(element.uri, None) + self.assertEqual(element['type'], 'cancel') + self.assertEqual(element['code'], '501') def test_getElementType(self): @@ -116,9 +116,9 @@ """ e = error.StanzaError('feature-not-implemented', 'auth') element = e.getElement() - self.assertEquals(element.uri, None) - self.assertEquals(element['type'], 'auth') - self.assertEquals(element['code'], '501') + self.assertEqual(element.uri, None) + self.assertEqual(element['type'], 'auth') + self.assertEqual(element['code'], '501') def test_getElementConditionNamespace(self): @@ -127,7 +127,7 @@ """ e = error.StanzaError('feature-not-implemented') element = e.getElement() - self.assertEquals(NS_XMPP_STANZAS, getattr(element, 'feature-not-implemented').uri) + self.assertEqual(NS_XMPP_STANZAS, getattr(element, 'feature-not-implemented').uri) def test_getElementTextNamespace(self): @@ -136,7 +136,7 @@ """ e = error.StanzaError('feature-not-implemented', text='text') element = e.getElement() - self.assertEquals(NS_XMPP_STANZAS, element.text.uri) + self.assertEqual(NS_XMPP_STANZAS, element.text.uri) def test_toResponse(self): @@ -244,7 +244,7 @@ self.error.addElement(('testns', 'condition')) condition = self.error.addElement(('testns', 'condition2')) result = error._parseError(self.error, 'errorns') - self.assertEquals(condition, result['appCondition']) + self.assertEqual(condition, result['appCondition']) @@ -286,10 +286,10 @@ result = error.exceptionFromStanza(stanza) self.assert_(isinstance(result, error.StanzaError)) - self.assertEquals('feature-not-implemented', result.condition) - self.assertEquals('cancel', result.type) - self.assertEquals(uc, result.appCondition) - self.assertEquals([p], result.children) + self.assertEqual('feature-not-implemented', result.condition) + self.assertEqual('cancel', result.type) + self.assertEqual(uc, result.appCondition) + self.assertEqual([p], result.children) def test_legacy(self): """ @@ -314,10 +314,10 @@ result = error.exceptionFromStanza(stanza) self.assert_(isinstance(result, error.StanzaError)) - self.assertEquals('service-unavailable', result.condition) - self.assertEquals('wait', result.type) - self.assertEquals('Unable to resolve hostname.', result.text) - self.assertEquals([p], result.children) + self.assertEqual('service-unavailable', result.condition) + self.assertEqual('wait', result.type) + self.assertEqual('Unable to resolve hostname.', result.text) + self.assertEqual([p], result.children) class ExceptionFromStreamErrorTest(unittest.TestCase): @@ -339,4 +339,4 @@ result = error.exceptionFromStreamError(e) self.assert_(isinstance(result, error.StreamError)) - self.assertEquals('xml-not-well-formed', result.condition) + self.assertEqual('xml-not-well-formed', result.condition) diff --git a/lib/twisted-trunk/twisted/words/test/test_jabberjid.py b/lib/twisted-trunk/twisted/words/test/test_jabberjid.py --- a/lib/twisted-trunk/twisted/words/test/test_jabberjid.py +++ b/lib/twisted-trunk/twisted/words/test/test_jabberjid.py @@ -15,27 +15,27 @@ Test different forms of JIDs. """ # Basic forms - self.assertEquals(jid.parse("user at host/resource"), + self.assertEqual(jid.parse("user at host/resource"), ("user", "host", "resource")) - self.assertEquals(jid.parse("user at host"), + self.assertEqual(jid.parse("user at host"), ("user", "host", None)) - self.assertEquals(jid.parse("host"), + self.assertEqual(jid.parse("host"), (None, "host", None)) - self.assertEquals(jid.parse("host/resource"), + self.assertEqual(jid.parse("host/resource"), (None, "host", "resource")) # More interesting forms - self.assertEquals(jid.parse("foo/bar at baz"), + self.assertEqual(jid.parse("foo/bar at baz"), (None, "foo", "bar at baz")) - self.assertEquals(jid.parse("boo at foo/bar at baz"), + self.assertEqual(jid.parse("boo at foo/bar at baz"), ("boo", "foo", "bar at baz")) - self.assertEquals(jid.parse("boo at foo/bar/baz"), + self.assertEqual(jid.parse("boo at foo/bar/baz"), ("boo", "foo", "bar/baz")) - self.assertEquals(jid.parse("boo/foo at bar@baz"), + self.assertEqual(jid.parse("boo/foo at bar@baz"), (None, "boo", "foo at bar@baz")) - self.assertEquals(jid.parse("boo/foo/bar"), + self.assertEqual(jid.parse("boo/foo/bar"), (None, "boo", "foo/bar")) - self.assertEquals(jid.parse("boo//foo"), + self.assertEqual(jid.parse("boo//foo"), (None, "boo", "/foo")) def test_noHost(self): @@ -69,21 +69,21 @@ """ Test case mapping of the user part of the JID. """ - self.assertEquals(jid.prep("UsEr", "host", "resource"), + self.assertEqual(jid.prep("UsEr", "host", "resource"), ("user", "host", "resource")) def test_prepCaseMapHost(self): """ Test case mapping of the host part of the JID. """ - self.assertEquals(jid.prep("user", "hoST", "resource"), + self.assertEqual(jid.prep("user", "hoST", "resource"), ("user", "host", "resource")) def test_prepNoCaseMapResource(self): """ Test no case mapping of the resourcce part of the JID. """ - self.assertEquals(jid.prep("user", "hoST", "resource"), + self.assertEqual(jid.prep("user", "hoST", "resource"), ("user", "host", "resource")) self.assertNotEquals(jid.prep("user", "host", "Resource"), ("user", "host", "resource")) @@ -101,23 +101,23 @@ Test that the attributes correspond with the JID parts. """ j = jid.JID("user at host/resource") - self.assertEquals(j.user, "user") - self.assertEquals(j.host, "host") - self.assertEquals(j.resource, "resource") + self.assertEqual(j.user, "user") + self.assertEqual(j.host, "host") + self.assertEqual(j.resource, "resource") def test_userhost(self): """ Test the extraction of the bare JID. """ j = jid.JID("user at host/resource") - self.assertEquals("user at host", j.userhost()) + self.assertEqual("user at host", j.userhost()) def test_userhostOnlyHost(self): """ Test the extraction of the bare JID of the full form host/resource. """ j = jid.JID("host/resource") - self.assertEquals("host", j.userhost()) + self.assertEqual("host", j.userhost()) def test_userhostJID(self): """ @@ -206,14 +206,14 @@ Test unicode representation of JIDs. """ j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEquals("user at host/resource", unicode(j)) + self.assertEqual("user at host/resource", unicode(j)) def test_repr(self): """ Test representation of JID objects. """ j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEquals("JID(u'user at host/resource')", repr(j)) + self.assertEqual("JID(u'user at host/resource')", repr(j)) class InternJIDTest(unittest.TestCase): def test_identity(self): diff --git a/lib/twisted-trunk/twisted/words/test/test_jabberjstrports.py b/lib/twisted-trunk/twisted/words/test/test_jabberjstrports.py --- a/lib/twisted-trunk/twisted/words/test/test_jabberjstrports.py +++ b/lib/twisted-trunk/twisted/words/test/test_jabberjstrports.py @@ -23,7 +23,7 @@ """ expected = ('TCP', ('DOMAIN', 65535, 'Factory'), {}) got = jstrports.parse("tcp:DOMAIN:65535", "Factory") - self.assertEquals(expected, got) + self.assertEqual(expected, got) def test_client(self): diff --git a/lib/twisted-trunk/twisted/words/test/test_jabbersasl.py b/lib/twisted-trunk/twisted/words/test/test_jabbersasl.py --- a/lib/twisted-trunk/twisted/words/test/test_jabbersasl.py +++ b/lib/twisted-trunk/twisted/words/test/test_jabbersasl.py @@ -86,7 +86,7 @@ self.init.onFailure(failure) self.assertFailure(self.init._deferred, sasl.SASLAuthError) self.init._deferred.addCallback(lambda e: - self.assertEquals('not-authorized', + self.assertEqual('not-authorized', e.condition)) return self.init._deferred @@ -98,10 +98,10 @@ self.init.initialResponse = "dummy" self.init.start() auth = self.output[0] - self.assertEquals(NS_XMPP_SASL, auth.uri) - self.assertEquals('auth', auth.name) - self.assertEquals('DUMMY', auth['mechanism']) - self.assertEquals('ZHVtbXk=', str(auth)) + self.assertEqual(NS_XMPP_SASL, auth.uri) + self.assertEqual('auth', auth.name) + self.assertEqual('DUMMY', auth['mechanism']) + self.assertEqual('ZHVtbXk=', str(auth)) def test_sendAuthNoInitialResponse(self): @@ -111,7 +111,7 @@ self.init.initialResponse = None self.init.start() auth = self.output[0] - self.assertEquals('', str(auth)) + self.assertEqual('', str(auth)) def test_sendAuthEmptyInitialResponse(self): @@ -121,7 +121,7 @@ self.init.initialResponse = "" self.init.start() auth = self.output[0] - self.assertEquals('=', str(auth)) + self.assertEqual('=', str(auth)) def test_onChallenge(self): diff --git a/lib/twisted-trunk/twisted/words/test/test_jabbersaslmechanisms.py b/lib/twisted-trunk/twisted/words/test/test_jabbersaslmechanisms.py --- a/lib/twisted-trunk/twisted/words/test/test_jabbersaslmechanisms.py +++ b/lib/twisted-trunk/twisted/words/test/test_jabbersaslmechanisms.py @@ -15,7 +15,7 @@ Test the initial response. """ m = sasl_mechanisms.Plain(None, 'test', 'secret') - self.assertEquals(m.getInitialResponse(), '\x00test\x00secret') + self.assertEqual(m.getInitialResponse(), '\x00test\x00secret') @@ -28,7 +28,7 @@ Test the initial response to be empty. """ m = sasl_mechanisms.Anonymous() - self.assertEquals(m.getInitialResponse(), None) + self.assertEqual(m.getInitialResponse(), None) diff --git a/lib/twisted-trunk/twisted/words/test/test_jabberxmlstream.py b/lib/twisted-trunk/twisted/words/test/test_jabberxmlstream.py --- a/lib/twisted-trunk/twisted/words/test/test_jabberxmlstream.py +++ b/lib/twisted-trunk/twisted/words/test/test_jabberxmlstream.py @@ -81,20 +81,20 @@ def testBasic(self): - self.assertEquals(self.iq['type'], 'get') + self.assertEqual(self.iq['type'], 'get') self.assertTrue(self.iq['id']) def testSend(self): self.xmlstream.transport.clear() self.iq.send() - self.assertEquals("" % self.iq['id'], + self.assertEqual("" % self.iq['id'], self.xmlstream.transport.value()) def testResultResponse(self): def cb(result): - self.assertEquals(result['type'], 'result') + self.assertEqual(result['type'], 'result') d = self.iq.send() d.addCallback(cb) @@ -683,12 +683,12 @@ self.xmlstream.sendHeader = lambda: self.done.append('header') d = self.init.start() - d.addCallback(self.assertEquals, xmlstream.Reset) + d.addCallback(self.assertEqual, xmlstream.Reset) starttls = self.output[0] - self.assertEquals('starttls', starttls.name) - self.assertEquals(NS_XMPP_TLS, starttls.uri) + self.assertEqual('starttls', starttls.name) + self.assertEqual(NS_XMPP_TLS, starttls.uri) self.xmlstream.dataReceived("" % NS_XMPP_TLS) - self.assertEquals(['TLS', 'reset', 'header'], self.done) + self.assertEqual(['TLS', 'reset', 'header'], self.done) return d @@ -703,8 +703,8 @@ xmlstream.ssl = None d = self.init.start() - d.addCallback(self.assertEquals, None) - self.assertEquals([], self.output) + d.addCallback(self.assertEqual, None) + self.assertEqual([], self.output) return d @@ -718,7 +718,7 @@ d = self.init.start() self.assertFailure(d, xmlstream.TLSNotSupported) - self.assertEquals([], self.output) + self.assertEqual([], self.output) return d @@ -733,7 +733,7 @@ self.init.wanted = False d = self.init.start() - self.assertEquals([], self.output) + self.assertEqual([], self.output) self.assertFailure(d, xmlstream.TLSRequired) return d @@ -749,7 +749,7 @@ d = self.init.start() d.addCallback(self.assertEqual, None) - self.assertEquals([], self.output) + self.assertEqual([], self.output) return d @@ -964,7 +964,7 @@ handler = xmlstream.XMPPHandler() handler.parent = DummyStreamManager() handler.send('') - self.assertEquals([''], handler.parent.outlist) + self.assertEqual([''], handler.parent.outlist) def test_makeConnection(self): @@ -1048,14 +1048,14 @@ """ sm = self.streamManager self.assertIdentical(None, sm.xmlstream) - self.assertEquals([], sm.handlers) - self.assertEquals(sm._connected, + self.assertEqual([], sm.handlers) + self.assertEqual(sm._connected, sm.factory.callbacks['//event/stream/connected']) - self.assertEquals(sm._authd, + self.assertEqual(sm._authd, sm.factory.callbacks['//event/stream/authd']) - self.assertEquals(sm._disconnected, + self.assertEqual(sm._disconnected, sm.factory.callbacks['//event/stream/end']) - self.assertEquals(sm.initializationFailed, + self.assertEqual(sm.initializationFailed, sm.factory.callbacks['//event/xmpp/initfailed']) @@ -1069,9 +1069,9 @@ handler.setHandlerParent(sm) xs = xmlstream.XmlStream(xmlstream.Authenticator()) sm._connected(xs) - self.assertEquals(1, handler.doneMade) - self.assertEquals(0, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) + self.assertEqual(1, handler.doneMade) + self.assertEqual(0, handler.doneInitialized) + self.assertEqual(0, handler.doneLost) def test_connectedLogTrafficFalse(self): @@ -1111,9 +1111,9 @@ handler.setHandlerParent(sm) xs = xmlstream.XmlStream(xmlstream.Authenticator()) sm._authd(xs) - self.assertEquals(0, handler.doneMade) - self.assertEquals(1, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) + self.assertEqual(0, handler.doneMade) + self.assertEqual(1, handler.doneInitialized) + self.assertEqual(0, handler.doneLost) def test_disconnected(self): @@ -1126,9 +1126,9 @@ handler.setHandlerParent(sm) xs = xmlstream.XmlStream(xmlstream.Authenticator()) sm._disconnected(xs) - self.assertEquals(0, handler.doneMade) - self.assertEquals(0, handler.doneInitialized) - self.assertEquals(1, handler.doneLost) + self.assertEqual(0, handler.doneMade) + self.assertEqual(0, handler.doneInitialized) + self.assertEqual(1, handler.doneLost) def test_disconnectedReason(self): @@ -1141,7 +1141,7 @@ handler.setHandlerParent(sm) xs = xmlstream.XmlStream(xmlstream.Authenticator()) sm._disconnected(failure.Failure(Exception("no reason"))) - self.assertEquals(True, handler.gotFailureReason) + self.assertEqual(True, handler.gotFailureReason) def test_addHandler(self): @@ -1152,9 +1152,9 @@ handler = DummyXMPPHandler() handler.setHandlerParent(sm) - self.assertEquals(0, handler.doneMade) - self.assertEquals(0, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) + self.assertEqual(0, handler.doneMade) + self.assertEqual(0, handler.doneInitialized) + self.assertEqual(0, handler.doneLost) def test_addHandlerInitialized(self): @@ -1173,9 +1173,9 @@ handler = DummyXMPPHandler() handler.setHandlerParent(sm) - self.assertEquals(1, handler.doneMade) - self.assertEquals(1, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) + self.assertEqual(1, handler.doneMade) + self.assertEqual(1, handler.doneInitialized) + self.assertEqual(0, handler.doneLost) def test_sendInitialized(self): @@ -1194,7 +1194,7 @@ "from='example.com' id='12345'>") xs.dispatch(xs, "//event/stream/authd") sm.send("") - self.assertEquals("", xs.transport.value()) + self.assertEqual("", xs.transport.value()) def test_sendNotConnected(self): @@ -1212,19 +1212,19 @@ xs = factory.buildProtocol(None) xs.transport = proto_helpers.StringTransport() sm.send("") - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) + self.assertEqual("", xs.transport.value()) + self.assertEqual("", sm._packetQueue[0]) xs.connectionMade() - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) + self.assertEqual("", xs.transport.value()) + self.assertEqual("", sm._packetQueue[0]) xs.dataReceived("") xs.dispatch(xs, "//event/stream/authd") - self.assertEquals("", xs.transport.value()) + self.assertEqual("", xs.transport.value()) self.assertFalse(sm._packetQueue) @@ -1243,8 +1243,8 @@ "xmlns:stream='http://etherx.jabber.org/streams' " "from='example.com' id='12345'>") sm.send("") - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) + self.assertEqual("", xs.transport.value()) + self.assertEqual("", sm._packetQueue[0]) def test_sendDisconnected(self): @@ -1265,8 +1265,8 @@ xs.connectionLost(None) sm.send("") - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) + self.assertEqual("", xs.transport.value()) + self.assertEqual("", sm._packetQueue[0]) @@ -1310,7 +1310,7 @@ instance gets an authenticator. """ xs = self.factory.buildProtocol(None) - self.assertEquals([xs], xs.authenticator.xmlstreams) + self.assertEqual([xs], xs.authenticator.xmlstreams) def test_buildProtocolXmlStream(self): diff --git a/lib/twisted-trunk/twisted/words/test/test_jabberxmppstringprep.py b/lib/twisted-trunk/twisted/words/test/test_jabberxmppstringprep.py --- a/lib/twisted-trunk/twisted/words/test/test_jabberxmppstringprep.py +++ b/lib/twisted-trunk/twisted/words/test/test_jabberxmppstringprep.py @@ -23,26 +23,26 @@ """ def testResourcePrep(self): - self.assertEquals(resourceprep.prepare(u'resource'), u'resource') + self.assertEqual(resourceprep.prepare(u'resource'), u'resource') self.assertNotEquals(resourceprep.prepare(u'Resource'), u'resource') - self.assertEquals(resourceprep.prepare(u' '), u' ') + self.assertEqual(resourceprep.prepare(u' '), u' ') if crippled: return - self.assertEquals(resourceprep.prepare(u'Henry \u2163'), u'Henry IV') - self.assertEquals(resourceprep.prepare(u'foo\xad\u034f\u1806\u180b' + self.assertEqual(resourceprep.prepare(u'Henry \u2163'), u'Henry IV') + self.assertEqual(resourceprep.prepare(u'foo\xad\u034f\u1806\u180b' u'bar\u200b\u2060' u'baz\ufe00\ufe08\ufe0f\ufeff'), u'foobarbaz') - self.assertEquals(resourceprep.prepare(u'\u00a0'), u' ') + self.assertEqual(resourceprep.prepare(u'\u00a0'), u' ') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u1680') - self.assertEquals(resourceprep.prepare(u'\u2000'), u' ') - self.assertEquals(resourceprep.prepare(u'\u200b'), u'') + self.assertEqual(resourceprep.prepare(u'\u2000'), u' ') + self.assertEqual(resourceprep.prepare(u'\u200b'), u'') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0010\u007f') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0085') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u180e') - self.assertEquals(resourceprep.prepare(u'\ufeff'), u'') + self.assertEqual(resourceprep.prepare(u'\ufeff'), u'') self.assertRaises(UnicodeError, resourceprep.prepare, u'\uf123') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000f1234') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0010f234') @@ -51,23 +51,23 @@ self.assertRaises(UnicodeError, resourceprep.prepare, u'\udf42') self.assertRaises(UnicodeError, resourceprep.prepare, u'\ufffd') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u2ff5') - self.assertEquals(resourceprep.prepare(u'\u0341'), u'\u0301') + self.assertEqual(resourceprep.prepare(u'\u0341'), u'\u0301') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u200e') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u202a') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0001') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0042') self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\u05bebar') self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\ufd50bar') - #self.assertEquals(resourceprep.prepare(u'foo\ufb38bar'), + #self.assertEqual(resourceprep.prepare(u'foo\ufb38bar'), # u'foo\u064ebar') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u06271') - self.assertEquals(resourceprep.prepare(u'\u06271\u0628'), + self.assertEqual(resourceprep.prepare(u'\u06271\u0628'), u'\u06271\u0628') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0002') def testNodePrep(self): - self.assertEquals(nodeprep.prepare(u'user'), u'user') - self.assertEquals(nodeprep.prepare(u'User'), u'user') + self.assertEqual(nodeprep.prepare(u'user'), u'user') + self.assertEqual(nodeprep.prepare(u'User'), u'user') self.assertRaises(UnicodeError, nodeprep.prepare, u'us&er') @@ -79,8 +79,8 @@ def testNamePrep(self): - self.assertEquals(nameprep.prepare(u'example.com'), u'example.com') - self.assertEquals(nameprep.prepare(u'Example.com'), u'example.com') + self.assertEqual(nameprep.prepare(u'example.com'), u'example.com') + self.assertEqual(nameprep.prepare(u'Example.com'), u'example.com') self.assertRaises(UnicodeError, nameprep.prepare, u'ex at mple.com') self.assertRaises(UnicodeError, nameprep.prepare, u'-example.com') self.assertRaises(UnicodeError, nameprep.prepare, u'example-.com') @@ -88,5 +88,5 @@ if crippled: return - self.assertEquals(nameprep.prepare(u'stra\u00dfe.example.com'), + self.assertEqual(nameprep.prepare(u'stra\u00dfe.example.com'), u'strasse.example.com') diff --git a/lib/twisted-trunk/twisted/words/test/test_msn.py b/lib/twisted-trunk/twisted/words/test/test_msn.py --- a/lib/twisted-trunk/twisted/words/test/test_msn.py +++ b/lib/twisted-trunk/twisted/words/test/test_msn.py @@ -60,7 +60,7 @@ for (h, v) in headers.items(): protocol.dataReceived('%s: %s\r\n' % (h,v)) protocol.dataReceived('\r\n') - self.assertEquals(self.result[0], "https://login.myserver.com/") + self.assertEqual(self.result[0], "https://login.myserver.com/") def _doLoginTest(self, response, headers): @@ -175,12 +175,12 @@ transport = StringTransport() client.makeConnection(transport) - self.assertEquals( + self.assertEqual( transport.value(), "VER 1 MSNP8 CVR0\r\n") transport.clear() client.dataReceived(serverVersionResponse) - self.assertEquals( + self.assertEqual( transport.value(), "CVR 2 0x0409 win 4.10 i386 MSNMSGR 5.0.0544 MSMSGS foo\r\n") @@ -228,12 +228,12 @@ transport = StringTransport() self.client.makeConnection(transport) - self.assertEquals( + self.assertEqual( transport.value(), "VER 1 MSNP8 CVR0\r\n") transport.clear() self.client.dataReceived(serverVersionResponse) - self.assertEquals( + self.assertEqual( transport.value(), "CVR 2 0x0409 win 4.10 i386 MSNMSGR 5.0.0544 MSMSGS foo\r\n") @@ -273,9 +273,9 @@ # md5 of the challenge and a magic string defined by the protocol response = "8f2f5a91b72102cd28355e9fc9000d6e" # Sanity check - the response is what the comment above says it is. - self.assertEquals( + self.assertEqual( response, md5(challenge + "Q1P7W2E4J9R8U3S5").hexdigest()) - self.assertEquals( + self.assertEqual( transport.value(), # 2 is the next transaction identifier. 32 is the length of the # response. @@ -299,8 +299,8 @@ self.client.loginFailure = failure.append self.client.lineReceived('USR 6 TWN S opaque-string-goes-here') - self.assertEquals(success, []) - self.assertEquals( + self.assertEqual(success, []) + self.assertEqual( failure, ["Exception while authenticating: " "Connecting to the Passport server requires SSL, but SSL is " @@ -421,7 +421,7 @@ def testClientCapabilitiesCheck(self): m = msn.MSNMessage() m.setHeader('Content-Type', 'text/x-clientcaps') - self.assertEquals(self.client.checkMessage(m), 0, 'Failed to detect client capability message') + self.assertEqual(self.client.checkMessage(m), 0, 'Failed to detect client capability message') def testTypingCheck(self): m = msn.MSNMessage() diff --git a/lib/twisted-trunk/twisted/words/test/test_service.py b/lib/twisted-trunk/twisted/words/test/test_service.py --- a/lib/twisted-trunk/twisted/words/test/test_service.py +++ b/lib/twisted-trunk/twisted/words/test/test_service.py @@ -34,7 +34,7 @@ d = wFD(create(name)) yield d p = d.getResult() - self.assertEquals(p.name, name) + self.assertEqual(p.name, name) # Creating the same user again should not d = wFD(create(name)) @@ -46,7 +46,7 @@ d = wFD(get(u"new" + kind.lower())) yield d p = d.getResult() - self.assertEquals(p.name, "new" + kind.lower()) + self.assertEqual(p.name, "new" + kind.lower()) # Getting that user again should return the same object d = wFD(get(u"new" + kind.lower())) @@ -190,7 +190,7 @@ n = [g.name for g in groups] n.sort() - self.assertEquals(n, ["groupone", "grouptwo"]) + self.assertEqual(n, ["groupone", "grouptwo"]) testEnumeration = dG(testEnumeration) @@ -324,10 +324,10 @@ user = TestCaseUserAgg(firstuser, self.realm, self.factory) user.write('NICK firstuser extrainfo\r\n') response = self._response(user, 'PRIVMSG') - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], service.NICKSERV) - self.assertEquals(response[0][1], 'PRIVMSG') - self.assertEquals(response[0][2], ['firstuser', 'Password?']) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], service.NICKSERV) + self.assertEqual(response[0][1], 'PRIVMSG') + self.assertEqual(response[0][2], ['firstuser', 'Password?']) user.transport.clear() user.write('PRIVMSG nickserv firstuser_password\r\n') @@ -343,8 +343,8 @@ user = TestCaseUserAgg(firstuser, self.realm, self.factory) self._login(user, "firstuser", "wrongpass") response = self._response(user, "PRIVMSG") - self.assertEquals(len(response), 1) - self.assertEquals(response[0][2], ['firstuser', 'Login failed. Goodbye.']) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][2], ['firstuser', 'Login failed. Goodbye.']) testFailedLogin = dG(testFailedLogin) @@ -358,7 +358,7 @@ self._login(user, "firstuser") user.protocol.logout = lambda: logout.append(True) user.write('QUIT\r\n') - self.assertEquals(logout, [True]) + self.assertEqual(logout, [True]) testLogout = dG(testLogout) @@ -380,20 +380,20 @@ user.write('JOIN #somechannel\r\n') response = self._response(user) - self.assertEquals(len(response), 5) + self.assertEqual(len(response), 5) # Join message - self.assertEquals(response[0][0], 'firstuser!firstuser at realmname') - self.assertEquals(response[0][1], 'JOIN') - self.assertEquals(response[0][2], ['#somechannel']) + self.assertEqual(response[0][0], 'firstuser!firstuser at realmname') + self.assertEqual(response[0][1], 'JOIN') + self.assertEqual(response[0][2], ['#somechannel']) # User list - self.assertEquals(response[1][1], '353') - self.assertEquals(response[2][1], '366') + self.assertEqual(response[1][1], '353') + self.assertEqual(response[2][1], '366') # Topic (or lack thereof, as the case may be) - self.assertEquals(response[3][1], '332') - self.assertEquals(response[4][1], '333') + self.assertEqual(response[3][1], '332') + self.assertEqual(response[4][1], '333') # Hook up another client! It is a CHAT SYSTEM!!!!!!! @@ -409,14 +409,14 @@ response = self._response(other) event = self._response(user) - self.assertEquals(len(event), 1) - self.assertEquals(event[0][0], 'otheruser!otheruser at realmname') - self.assertEquals(event[0][1], 'JOIN') - self.assertEquals(event[0][2], ['#somechannel']) + self.assertEqual(len(event), 1) + self.assertEqual(event[0][0], 'otheruser!otheruser at realmname') + self.assertEqual(event[0][1], 'JOIN') + self.assertEqual(event[0][2], ['#somechannel']) - self.assertEquals(response[1][0], 'realmname') - self.assertEquals(response[1][1], '353') - self.assertEquals(response[1][2], ['otheruser', '=', '#somechannel', 'firstuser otheruser']) + self.assertEqual(response[1][0], 'realmname') + self.assertEqual(response[1][1], '353') + self.assertEqual(response[1][2], ['otheruser', '=', '#somechannel', 'firstuser otheruser']) testJoin = dG(testJoin) @@ -472,11 +472,11 @@ response = self._response(user) event = self._response(other) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'useruser!useruser at realmname') - self.assertEquals(response[0][1], 'PART') - self.assertEquals(response[0][2], ['#somechannel', 'leaving']) - self.assertEquals(response, event) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], 'useruser!useruser at realmname') + self.assertEqual(response[0][1], 'PART') + self.assertEqual(response[0][2], ['#somechannel', 'leaving']) + self.assertEqual(response, event) # Now again, with a part message user.write('JOIN #somechannel\r\n') @@ -489,11 +489,11 @@ response = self._response(user) event = self._response(other) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'useruser!useruser at realmname') - self.assertEquals(response[0][1], 'PART') - self.assertEquals(response[0][2], ['#somechannel', 'goodbye stupidheads']) - self.assertEquals(response, event) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], 'useruser!useruser at realmname') + self.assertEqual(response[0][1], 'PART') + self.assertEqual(response[0][2], ['#somechannel', 'goodbye stupidheads']) + self.assertEqual(response, event) testLeave = dG(testLeave) @@ -516,13 +516,13 @@ response = self._response(user) - self.assertEquals(response[3][0], 'realmname') - self.assertEquals(response[3][1], '332') + self.assertEqual(response[3][0], 'realmname') + self.assertEqual(response[3][1], '332') # XXX Sigh. irc.parsemsg() is not as correct as one might hope. - self.assertEquals(response[3][2], ['useruser', '#somechannel', 'This is a test topic.']) - self.assertEquals(response[4][1], '333') - self.assertEquals(response[4][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) + self.assertEqual(response[3][2], ['useruser', '#somechannel', 'This is a test topic.']) + self.assertEqual(response[4][1], '333') + self.assertEqual(response[4][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) user.transport.clear() @@ -530,10 +530,10 @@ response = self._response(user) - self.assertEquals(response[0][1], '332') - self.assertEquals(response[0][2], ['useruser', '#somechannel', 'This is a test topic.']) - self.assertEquals(response[1][1], '333') - self.assertEquals(response[1][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) + self.assertEqual(response[0][1], '332') + self.assertEqual(response[0][2], ['useruser', '#somechannel', 'This is a test topic.']) + self.assertEqual(response[1][1], '333') + self.assertEqual(response[1][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) testGetTopic = dG(testGetTopic) @@ -562,11 +562,11 @@ response = self._response(other) event = self._response(user) - self.assertEquals(response, event) + self.assertEqual(response, event) - self.assertEquals(response[0][0], 'otheruser!otheruser at realmname') - self.assertEquals(response[0][1], 'TOPIC') - self.assertEquals(response[0][2], ['#somechannel', 'This is the new topic.']) + self.assertEqual(response[0][0], 'otheruser!otheruser at realmname') + self.assertEqual(response[0][1], 'TOPIC') + self.assertEqual(response[0][2], ['#somechannel', 'This is the new topic.']) other.transport.clear() @@ -574,16 +574,16 @@ other.write('TOPIC #somechannel\r\n') response = self._response(other) - self.assertEquals(response[0][1], '332') - self.assertEquals(response[0][2], ['otheruser', '#somechannel', 'This is the new topic.']) - self.assertEquals(response[1][1], '333') - self.assertEquals(response[1][2], ['otheruser', '#somechannel', 'otheruser', '12345']) + self.assertEqual(response[0][1], '332') + self.assertEqual(response[0][2], ['otheruser', '#somechannel', 'This is the new topic.']) + self.assertEqual(response[1][1], '333') + self.assertEqual(response[1][2], ['otheruser', '#somechannel', 'otheruser', '12345']) other.transport.clear() other.write('TOPIC #asdlkjasd\r\n') response = self._response(other) - self.assertEquals(response[0][1], '403') + self.assertEqual(response[0][1], '403') testSetTopic = dG(testSetTopic) @@ -613,10 +613,10 @@ event = self._response(other) self.failIf(response) - self.assertEquals(len(event), 1) - self.assertEquals(event[0][0], 'useruser!useruser at realmname') - self.assertEquals(event[0][1], 'PRIVMSG', -1) - self.assertEquals(event[0][2], ['#somechannel', 'Hello, world.']) + self.assertEqual(len(event), 1) + self.assertEqual(event[0][0], 'useruser!useruser at realmname') + self.assertEqual(event[0][1], 'PRIVMSG', -1) + self.assertEqual(event[0][2], ['#somechannel', 'Hello, world.']) testGroupMessage = dG(testGroupMessage) @@ -638,19 +638,19 @@ event = self._response(other) self.failIf(response) - self.assertEquals(len(event), 1) - self.assertEquals(event[0][0], 'useruser!useruser at realmname') - self.assertEquals(event[0][1], 'PRIVMSG') - self.assertEquals(event[0][2], ['otheruser', 'Hello, monkey.']) + self.assertEqual(len(event), 1) + self.assertEqual(event[0][0], 'useruser!useruser at realmname') + self.assertEqual(event[0][1], 'PRIVMSG') + self.assertEqual(event[0][2], ['otheruser', 'Hello, monkey.']) user.write('PRIVMSG nousernamedthis :Hello, monkey.\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'realmname') - self.assertEquals(response[0][1], '401') - self.assertEquals(response[0][2], ['useruser', 'nousernamedthis', 'No such nick/channel.']) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], 'realmname') + self.assertEqual(response[0][1], '401') + self.assertEqual(response[0][2], ['useruser', 'nousernamedthis', 'No such nick/channel.']) testPrivateMessage = dG(testPrivateMessage) @@ -663,8 +663,8 @@ user.write('OPER user pass\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '491') + self.assertEqual(len(response), 1) + self.assertEqual(response[0][1], '491') testOper = dG(testOper) @@ -677,10 +677,10 @@ user.write('MODE useruser\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'realmname') - self.assertEquals(response[0][1], '221') - self.assertEquals(response[0][2], ['useruser', '+']) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], 'realmname') + self.assertEqual(response[0][1], '221') + self.assertEqual(response[0][2], ['useruser', '+']) testGetUserMode = dG(testGetUserMode) @@ -693,8 +693,8 @@ user.write('MODE useruser +abcd\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '472') + self.assertEqual(len(response), 1) + self.assertEqual(response[0][1], '472') testSetUserMode = dG(testSetUserMode) @@ -713,8 +713,8 @@ user.write('MODE #somechannel\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '324') + self.assertEqual(len(response), 1) + self.assertEqual(response[0][1], '324') testGetGroupMode = dG(testGetGroupMode) @@ -733,8 +733,8 @@ user.write('MODE #groupname +abcd\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '472') + self.assertEqual(len(response), 1) + self.assertEqual(response[0][1], '472') testSetGroupMode = dG(testSetGroupMode) @@ -762,27 +762,27 @@ wantusers = ['userone', 'usertwo', 'userthree'] for (prefix, code, stuff) in r[:-1]: - self.assertEquals(prefix, 'realmname') - self.assertEquals(code, '352') + self.assertEqual(prefix, 'realmname') + self.assertEqual(code, '352') (myname, group, theirname, theirhost, theirserver, theirnick, flag, extra) = stuff - self.assertEquals(myname, 'userone') - self.assertEquals(group, '#groupname') + self.assertEqual(myname, 'userone') + self.assertEqual(group, '#groupname') self.failUnless(theirname in wantusers) - self.assertEquals(theirhost, 'realmname') - self.assertEquals(theirserver, 'realmname') + self.assertEqual(theirhost, 'realmname') + self.assertEqual(theirserver, 'realmname') wantusers.remove(theirnick) - self.assertEquals(flag, 'H') - self.assertEquals(extra, '0 ' + theirnick) + self.assertEqual(flag, 'H') + self.assertEqual(extra, '0 ' + theirnick) self.failIf(wantusers) prefix, code, stuff = r[-1] - self.assertEquals(prefix, 'realmname') - self.assertEquals(code, '315') + self.assertEqual(prefix, 'realmname') + self.assertEqual(code, '315') myname, channel, extra = stuff - self.assertEquals(myname, 'userone') - self.assertEquals(channel, '#groupname') - self.assertEquals(extra, 'End of /WHO list.') + self.assertEqual(myname, 'userone') + self.assertEqual(channel, '#groupname') + self.assertEqual(extra, 'End of /WHO list.') testWho = dG(testWho) @@ -802,36 +802,36 @@ user.write('LIST #somegroup\r\n') r = self._response(user) - self.assertEquals(len(r), 2) + self.assertEqual(len(r), 2) resp, end = r - self.assertEquals(resp[0], 'realmname') - self.assertEquals(resp[1], '322') - self.assertEquals(resp[2][0], 'someuser') - self.assertEquals(resp[2][1], 'somegroup') - self.assertEquals(resp[2][2], '17') - self.assertEquals(resp[2][3], 'this is the topic woo') + self.assertEqual(resp[0], 'realmname') + self.assertEqual(resp[1], '322') + self.assertEqual(resp[2][0], 'someuser') + self.assertEqual(resp[2][1], 'somegroup') + self.assertEqual(resp[2][2], '17') + self.assertEqual(resp[2][3], 'this is the topic woo') - self.assertEquals(end[0], 'realmname') - self.assertEquals(end[1], '323') - self.assertEquals(end[2][0], 'someuser') - self.assertEquals(end[2][1], 'End of /LIST') + self.assertEqual(end[0], 'realmname') + self.assertEqual(end[1], '323') + self.assertEqual(end[2][0], 'someuser') + self.assertEqual(end[2][1], 'End of /LIST') user.transport.clear() # Test all groups user.write('LIST\r\n') r = self._response(user) - self.assertEquals(len(r), 2) + self.assertEqual(len(r), 2) fg1, end = r - self.assertEquals(fg1[1], '322') - self.assertEquals(fg1[2][1], 'somegroup') - self.assertEquals(fg1[2][2], '17') - self.assertEquals(fg1[2][3], 'this is the topic woo') + self.assertEqual(fg1[1], '322') + self.assertEqual(fg1[2][1], 'somegroup') + self.assertEqual(fg1[2][2], '17') + self.assertEqual(fg1[2][3], 'this is the topic woo') - self.assertEquals(end[1], '323') + self.assertEqual(end[1], '323') testList = dG(testList) @@ -855,44 +855,44 @@ user.write('WHOIS otherguy\r\n') r = self._response(user) - self.assertEquals(len(r), 5) + self.assertEqual(len(r), 5) wuser, wserver, idle, channels, end = r - self.assertEquals(wuser[0], 'realmname') - self.assertEquals(wuser[1], '311') - self.assertEquals(wuser[2][0], 'someguy') - self.assertEquals(wuser[2][1], 'otherguy') - self.assertEquals(wuser[2][2], 'otherguy') - self.assertEquals(wuser[2][3], 'realmname') - self.assertEquals(wuser[2][4], '*') - self.assertEquals(wuser[2][5], 'otherguy') + self.assertEqual(wuser[0], 'realmname') + self.assertEqual(wuser[1], '311') + self.assertEqual(wuser[2][0], 'someguy') + self.assertEqual(wuser[2][1], 'otherguy') + self.assertEqual(wuser[2][2], 'otherguy') + self.assertEqual(wuser[2][3], 'realmname') + self.assertEqual(wuser[2][4], '*') + self.assertEqual(wuser[2][5], 'otherguy') - self.assertEquals(wserver[0], 'realmname') - self.assertEquals(wserver[1], '312') - self.assertEquals(wserver[2][0], 'someguy') - self.assertEquals(wserver[2][1], 'otherguy') - self.assertEquals(wserver[2][2], 'realmname') - self.assertEquals(wserver[2][3], 'Hi mom!') + self.assertEqual(wserver[0], 'realmname') + self.assertEqual(wserver[1], '312') + self.assertEqual(wserver[2][0], 'someguy') + self.assertEqual(wserver[2][1], 'otherguy') + self.assertEqual(wserver[2][2], 'realmname') + self.assertEqual(wserver[2][3], 'Hi mom!') - self.assertEquals(idle[0], 'realmname') - self.assertEquals(idle[1], '317') - self.assertEquals(idle[2][0], 'someguy') - self.assertEquals(idle[2][1], 'otherguy') - self.assertEquals(idle[2][2], '15') - self.assertEquals(idle[2][3], '10') - self.assertEquals(idle[2][4], "seconds idle, signon time") + self.assertEqual(idle[0], 'realmname') + self.assertEqual(idle[1], '317') + self.assertEqual(idle[2][0], 'someguy') + self.assertEqual(idle[2][1], 'otherguy') + self.assertEqual(idle[2][2], '15') + self.assertEqual(idle[2][3], '10') + self.assertEqual(idle[2][4], "seconds idle, signon time") - self.assertEquals(channels[0], 'realmname') - self.assertEquals(channels[1], '319') - self.assertEquals(channels[2][0], 'someguy') - self.assertEquals(channels[2][1], 'otherguy') - self.assertEquals(channels[2][2], '#groupA #groupB') + self.assertEqual(channels[0], 'realmname') + self.assertEqual(channels[1], '319') + self.assertEqual(channels[2][0], 'someguy') + self.assertEqual(channels[2][1], 'otherguy') + self.assertEqual(channels[2][2], '#groupA #groupB') - self.assertEquals(end[0], 'realmname') - self.assertEquals(end[1], '318') - self.assertEquals(end[2][0], 'someguy') - self.assertEquals(end[2][1], 'otherguy') - self.assertEquals(end[2][2], 'End of WHOIS list.') + self.assertEqual(end[0], 'realmname') + self.assertEqual(end[1], '318') + self.assertEqual(end[2][0], 'someguy') + self.assertEqual(end[2][1], 'otherguy') + self.assertEqual(end[2][2], 'End of WHOIS list.') testWhois = dG(testWhois) diff --git a/lib/twisted-trunk/twisted/words/test/test_tap.py b/lib/twisted-trunk/twisted/words/test/test_tap.py --- a/lib/twisted-trunk/twisted/words/test/test_tap.py +++ b/lib/twisted-trunk/twisted/words/test/test_tap.py @@ -40,7 +40,7 @@ """ opt = tap.Options() opt.parseOptions(['--hostname', 'myhost']) - self.assertEquals(opt['hostname'], 'myhost') + self.assertEqual(opt['hostname'], 'myhost') def test_passwd(self): @@ -69,10 +69,10 @@ @param opt: An instance of L{tap.Options}. """ - self.assertEquals(len(opt['credCheckers']), 1) + self.assertEqual(len(opt['credCheckers']), 1) checker = opt['credCheckers'][0] self.assertFailure(checker.requestAvatarId(self.joeWrong), error.UnauthorizedLogin) def _gotAvatar(username): - self.assertEquals(username, self.admin.username) + self.assertEqual(username, self.admin.username) return checker.requestAvatarId(self.admin).addCallback(_gotAvatar) diff --git a/lib/twisted-trunk/twisted/words/test/test_xishutil.py b/lib/twisted-trunk/twisted/words/test/test_xishutil.py --- a/lib/twisted-trunk/twisted/words/test/test_xishutil.py +++ b/lib/twisted-trunk/twisted/words/test/test_xishutil.py @@ -76,23 +76,23 @@ pres.addElement("presence") d.dispatch(msg) - self.assertEquals(cb1.called, 2) - self.assertEquals(cb1.obj, msg) - self.assertEquals(cb2.called, 0) + self.assertEqual(cb1.called, 2) + self.assertEqual(cb1.obj, msg) + self.assertEqual(cb2.called, 0) d.dispatch(pres) - self.assertEquals(cb1.called, 2) - self.assertEquals(cb2.called, 1) - self.assertEquals(cb2.obj, pres) - self.assertEquals(cb3.called, 0) + self.assertEqual(cb1.called, 2) + self.assertEqual(cb2.called, 1) + self.assertEqual(cb2.obj, pres) + self.assertEqual(cb3.called, 0) d.dispatch(d, "//event/testevent") - self.assertEquals(cb3.called, 1) - self.assertEquals(cb3.obj, d) + self.assertEqual(cb3.called, 1) + self.assertEqual(cb3.obj, d) d.removeObserver("/presence", cb2.call) d.dispatch(pres) - self.assertEquals(cb2.called, 1) + self.assertEqual(cb2.called, 1) def test_addObserverTwice(self): @@ -109,10 +109,10 @@ d.addObserver("//event/testevent", cb2.call) d.dispatch(d, "//event/testevent") - self.assertEquals(cb1.called, 1) - self.assertEquals(cb1.obj, d) - self.assertEquals(cb2.called, 1) - self.assertEquals(cb2.obj, d) + self.assertEqual(cb1.called, 1) + self.assertEqual(cb1.obj, d) + self.assertEqual(cb2.called, 1) + self.assertEqual(cb2.obj, d) def test_addObserverInDispatch(self): @@ -129,13 +129,13 @@ d.addOnetimeObserver("/message", onMessage) d.dispatch(msg) - self.assertEquals(cb.called, 0) + self.assertEqual(cb.called, 0) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) d.dispatch(msg) - self.assertEquals(cb.called, 2) + self.assertEqual(cb.called, 2) def test_addOnetimeObserverInDispatch(self): @@ -152,13 +152,13 @@ d.addOnetimeObserver("/message", onMessage) d.dispatch(msg) - self.assertEquals(cb.called, 0) + self.assertEqual(cb.called, 0) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) def testOnetimeDispatch(self): @@ -168,9 +168,9 @@ d.addOnetimeObserver("/message", cb.call) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) def testDispatcherResult(self): @@ -181,10 +181,10 @@ d.addObserver("/presence", cb.call) result = d.dispatch(msg) - self.assertEquals(False, result) + self.assertEqual(False, result) result = d.dispatch(pres) - self.assertEquals(True, result) + self.assertEqual(True, result) def testOrderedXPathDispatch(self): @@ -197,7 +197,7 @@ msg = Element(("ns", "message")) msg.addElement("body") d.dispatch(msg) - self.assertEquals(cb.callList, [cb.call1, cb.call2, cb.call3], + self.assertEqual(cb.callList, [cb.call1, cb.call2, cb.call3], "Calls out of order: %s" % repr([c.__name__ for c in cb.callList])) @@ -328,7 +328,7 @@ self.pipe.sink.addObserver('/test[@xmlns="testns"]', cb) element = Element(('testns', 'test')) self.pipe.source.send(element) - self.assertEquals([element], called) + self.assertEqual([element], called) def test_sendFromSink(self): @@ -342,4 +342,4 @@ self.pipe.source.addObserver('/test[@xmlns="testns"]', cb) element = Element(('testns', 'test')) self.pipe.sink.send(element) - self.assertEquals([element], called) + self.assertEqual([element], called) diff --git a/lib/twisted-trunk/twisted/words/test/test_xmlstream.py b/lib/twisted-trunk/twisted/words/test/test_xmlstream.py --- a/lib/twisted-trunk/twisted/words/test/test_xmlstream.py +++ b/lib/twisted-trunk/twisted/words/test/test_xmlstream.py @@ -34,7 +34,7 @@ """ self.xmlstream.connectionMade() self.xmlstream.send("") - self.assertEquals(self.outlist[0], "") + self.assertEqual(self.outlist[0], "") def test_receiveRoot(self): @@ -50,7 +50,7 @@ streamStartEvent) self.xmlstream.connectionMade() self.xmlstream.dataReceived("") - self.assertEquals(1, len(streamStarted)) + self.assertEqual(1, len(streamStarted)) def test_receiveBadXML(self): @@ -73,13 +73,13 @@ self.xmlstream.connectionMade() self.xmlstream.dataReceived("") - self.assertEquals(0, len(streamError)) - self.assertEquals(0, len(streamEnd)) + self.assertEqual(0, len(streamError)) + self.assertEqual(0, len(streamEnd)) self.xmlstream.dataReceived("") - self.assertEquals(1, len(streamError)) + self.assertEqual(1, len(streamError)) self.assertTrue(streamError[0].check(domish.ParserError)) - self.assertEquals(1, len(streamEnd)) + self.assertEqual(1, len(streamEnd)) def test_streamEnd(self): @@ -95,9 +95,9 @@ streamEndEvent) self.xmlstream.connectionMade() self.loseConnection() - self.assertEquals(1, len(streamEnd)) + self.assertEqual(1, len(streamEnd)) self.assertIsInstance(streamEnd[0], failure.Failure) - self.assertEquals(streamEnd[0].getErrorMessage(), + self.assertEqual(streamEnd[0].getErrorMessage(), self.connectionLostMsg) @@ -144,7 +144,7 @@ self.factory.installBootstraps(dispatcher) dispatcher.dispatch(None, '//event/myevent') - self.assertEquals(1, len(called)) + self.assertEqual(1, len(called)) def test_addAndRemoveBootstrap(self): @@ -191,7 +191,7 @@ xs = self.factory.buildProtocol(None) xs.dispatch(None, '//event/myevent') - self.assertEquals(1, len(called)) + self.assertEqual(1, len(called)) def test_buildProtocolStoresFactory(self): @@ -220,5 +220,5 @@ """ xs = self.factory.buildProtocol(None) - self.assertEquals((None,), xs.args) - self.assertEquals({'test': None}, xs.kwargs) + self.assertEqual((None,), xs.args) + self.assertEqual({'test': None}, xs.kwargs) diff --git a/lib/twisted-trunk/twisted/words/test/test_xmpproutertap.py b/lib/twisted-trunk/twisted/words/test/test_xmpproutertap.py --- a/lib/twisted-trunk/twisted/words/test/test_xmpproutertap.py +++ b/lib/twisted-trunk/twisted/words/test/test_xmpproutertap.py @@ -18,7 +18,7 @@ """ opt = tap.Options() opt.parseOptions(['--port', '7001']) - self.assertEquals(opt['port'], '7001') + self.assertEqual(opt['port'], '7001') def test_portDefault(self): @@ -27,7 +27,7 @@ """ opt = tap.Options() opt.parseOptions([]) - self.assertEquals(opt['port'], 'tcp:5347:interface=127.0.0.1') + self.assertEqual(opt['port'], 'tcp:5347:interface=127.0.0.1') def test_secret(self): @@ -36,7 +36,7 @@ """ opt = tap.Options() opt.parseOptions(['--secret', 'hushhush']) - self.assertEquals(opt['secret'], 'hushhush') + self.assertEqual(opt['secret'], 'hushhush') def test_secretDefault(self): @@ -45,7 +45,7 @@ """ opt = tap.Options() opt.parseOptions([]) - self.assertEquals(opt['secret'], 'secret') + self.assertEqual(opt['secret'], 'secret') def test_verbose(self): @@ -65,12 +65,12 @@ opt.parseOptions([]) s = tap.makeService(opt) self.assertIsInstance(s, internet.StreamServerEndpointService) - self.assertEquals('127.0.0.1', s.endpoint._interface) - self.assertEquals(5347, s.endpoint._port) + self.assertEqual('127.0.0.1', s.endpoint._interface) + self.assertEqual(5347, s.endpoint._port) factory = s.factory self.assertIsInstance(factory, component.XMPPComponentServerFactory) self.assertIsInstance(factory.router, component.Router) - self.assertEquals('secret', factory.secret) + self.assertEqual('secret', factory.secret) self.assertFalse(factory.logTraffic) diff --git a/lib/twisted-trunk/twisted/words/test/test_xpath.py b/lib/twisted-trunk/twisted/words/test/test_xpath.py --- a/lib/twisted-trunk/twisted/words/test/test_xpath.py +++ b/lib/twisted-trunk/twisted/words/test/test_xpath.py @@ -72,14 +72,14 @@ """ Test basic operation of the static methods. """ - self.assertEquals(xpath.matches("/foo/bar", self.e), + self.assertEqual(xpath.matches("/foo/bar", self.e), True) - self.assertEquals(xpath.queryForNodes("/foo/bar", self.e), + self.assertEqual(xpath.queryForNodes("/foo/bar", self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7]) - self.assertEquals(xpath.queryForString("/foo", self.e), + self.assertEqual(xpath.queryForString("/foo", self.e), "somecontent") - self.assertEquals(xpath.queryForStringList("/foo", self.e), + self.assertEqual(xpath.queryForStringList("/foo", self.e), ["somecontent", "somemorecontent"]) def test_locationFooBar(self): @@ -87,15 +87,15 @@ Test matching foo with child bar. """ xp = XPathQuery("/foo/bar") - self.assertEquals(xp.matches(self.e), 1) + self.assertEqual(xp.matches(self.e), 1) def test_locationFooBarFoo(self): """ Test finding foos at the second level. """ xp = XPathQuery("/foo/bar/foo") - self.assertEquals(xp.matches(self.e), 1) - self.assertEquals(xp.queryForNodes(self.e), [self.subfoo, + self.assertEqual(xp.matches(self.e), 1) + self.assertEqual(xp.queryForNodes(self.e), [self.subfoo, self.subfoo3, self.subfoo4]) @@ -104,15 +104,15 @@ Test not finding bar3. """ xp = XPathQuery("/foo/bar3") - self.assertEquals(xp.matches(self.e), 0) + self.assertEqual(xp.matches(self.e), 0) def test_locationAllChilds(self): """ Test finding childs of foo. """ xp = XPathQuery("/foo/*") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7]) @@ -121,23 +121,23 @@ Test matching foo with attribute. """ xp = XPathQuery("/foo[@attrib1]") - self.assertEquals(xp.matches(self.e), True) + self.assertEqual(xp.matches(self.e), True) def test_attributeWithValueAny(self): """ Test find nodes with attribute having value. """ xp = XPathQuery("/foo/*[@attrib2='value2']") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar2]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar2]) def test_position(self): """ Test finding element at position. """ xp = XPathQuery("/foo/bar[2]") - self.assertEquals(xp.matches(self.e), 1) - self.assertEquals(xp.queryForNodes(self.e), [self.bar1]) + self.assertEqual(xp.matches(self.e), 1) + self.assertEqual(xp.queryForNodes(self.e), [self.bar1]) test_position.todo = "XPath queries with position are not working." @@ -146,29 +146,29 @@ Test matching node with namespace. """ xp = XPathQuery("/foo[@xmlns='testns']/bar") - self.assertEquals(xp.matches(self.e), 1) + self.assertEqual(xp.matches(self.e), 1) def test_namespaceNotFound(self): """ Test not matching node with wrong namespace. """ xp = XPathQuery("/foo[@xmlns='badns']/bar2") - self.assertEquals(xp.matches(self.e), 0) + self.assertEqual(xp.matches(self.e), 0) def test_attributeWithValue(self): """ Test matching node with attribute having value. """ xp = XPathQuery("/foo[@attrib1='value1']") - self.assertEquals(xp.matches(self.e), 1) + self.assertEqual(xp.matches(self.e), 1) def test_queryForString(self): """ Test for queryForString and queryForStringList. """ xp = XPathQuery("/foo") - self.assertEquals(xp.queryForString(self.e), "somecontent") - self.assertEquals(xp.queryForStringList(self.e), + self.assertEqual(xp.queryForString(self.e), "somecontent") + self.assertEqual(xp.queryForStringList(self.e), ["somecontent", "somemorecontent"]) def test_queryForNodes(self): @@ -176,7 +176,7 @@ Test finding nodes. """ xp = XPathQuery("/foo/bar") - self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, + self.assertEqual(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7]) @@ -185,24 +185,24 @@ Test matching a node with given text. """ xp = XPathQuery("/foo[text() = 'somecontent']") - self.assertEquals(xp.matches(self.e), True) + self.assertEqual(xp.matches(self.e), True) def test_textNotOperator(self): """ Test for not operator. """ xp = XPathQuery("/foo[not(@nosuchattrib)]") - self.assertEquals(xp.matches(self.e), True) + self.assertEqual(xp.matches(self.e), True) def test_anyLocationAndText(self): """ Test finding any nodes named gar and getting their text contents. """ xp = XPathQuery("//gar") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.gar1, self.gar2, + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.gar1, self.gar2, self.gar3, self.gar4]) - self.assertEquals(xp.queryForStringList(self.e), ["DEF", "ABC", + self.assertEqual(xp.queryForStringList(self.e), ["DEF", "ABC", "JKL", "MNO"]) def test_anyLocation(self): @@ -210,8 +210,8 @@ Test finding any nodes named bar. """ xp = XPathQuery("//bar") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar3, self.bar4, self.bar5, self.bar6, self.bar7]) @@ -229,16 +229,16 @@ Test boolean and operator in condition. """ xp = XPathQuery("//bar[@attrib4='value4' and @attrib5='value5']") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar5]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar5]) def test_orOperator(self): """ Test boolean or operator in condition. """ xp = XPathQuery("//bar[@attrib5='value4' or @attrib5='value5']") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar5, self.bar6]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar5, self.bar6]) def test_booleanOperatorsParens(self): """ @@ -246,8 +246,8 @@ """ xp = XPathQuery("""//bar[@attrib4='value4' and (@attrib5='value4' or @attrib5='value6')]""") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar6, self.bar7]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar6, self.bar7]) def test_booleanOperatorsNoParens(self): """ @@ -256,5 +256,5 @@ xp = XPathQuery("""//bar[@attrib5='value4' or @attrib5='value5' or @attrib5='value6']""") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar5, self.bar6, self.bar7]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar5, self.bar6, self.bar7]) From noreply at buildbot.pypy.org Fri Jul 15 16:04:33 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:33 +0200 (CEST) Subject: [pypy-commit] pypy jit-option-refactor: Close branch: not going anywhere. Message-ID: <20110715140433.A7E5A82931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-option-refactor Changeset: r45625:d5d8ff879a62 Date: 2011-07-15 15:56 +0200 http://bitbucket.org/pypy/pypy/changeset/d5d8ff879a62/ Log: Close branch: not going anywhere. From noreply at buildbot.pypy.org Fri Jul 15 16:04:34 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:34 +0200 (CEST) Subject: [pypy-commit] pypy jit-tagged: Abandon out-of-date branch. Message-ID: <20110715140434.D598A82931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-tagged Changeset: r45626:80826980b2de Date: 2011-07-15 16:01 +0200 http://bitbucket.org/pypy/pypy/changeset/80826980b2de/ Log: Abandon out-of-date branch. From noreply at buildbot.pypy.org Fri Jul 15 16:04:36 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:36 +0200 (CEST) Subject: [pypy-commit] pypy inline-shadowstack: Abandon unsuccessful attempt. Message-ID: <20110715140436.13FDA82931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: inline-shadowstack Changeset: r45627:627e43060c05 Date: 2011-07-15 16:02 +0200 http://bitbucket.org/pypy/pypy/changeset/627e43060c05/ Log: Abandon unsuccessful attempt. From noreply at buildbot.pypy.org Fri Jul 15 16:04:37 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:37 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head 6cc99b03661f on branch fast-ctypes Message-ID: <20110715140437.385E082931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r45628:36358ba488bc Date: 2011-07-15 16:03 +0200 http://bitbucket.org/pypy/pypy/changeset/36358ba488bc/ Log: Merge closed head 6cc99b03661f on branch fast-ctypes From noreply at buildbot.pypy.org Fri Jul 15 16:04:38 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:38 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head 6f55c82f615c on branch arm-backed-float Message-ID: <20110715140438.4CE1782931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r45629:ca43954a89f4 Date: 2011-07-15 16:03 +0200 http://bitbucket.org/pypy/pypy/changeset/ca43954a89f4/ Log: Merge closed head 6f55c82f615c on branch arm-backed-float From noreply at buildbot.pypy.org Fri Jul 15 16:04:39 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:39 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head b7e01d83d985 on branch numpy-impicit-convert Message-ID: <20110715140439.6B9C582931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r45630:d7508cbeea76 Date: 2011-07-15 16:03 +0200 http://bitbucket.org/pypy/pypy/changeset/d7508cbeea76/ Log: Merge closed head b7e01d83d985 on branch numpy-impicit-convert From noreply at buildbot.pypy.org Fri Jul 15 16:04:40 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:40 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head a82a876ec054 on branch failed-forcing-refactoring Message-ID: <20110715140440.7CF6E82931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r45631:9fc3b77c6dcc Date: 2011-07-15 16:03 +0200 http://bitbucket.org/pypy/pypy/changeset/9fc3b77c6dcc/ Log: Merge closed head a82a876ec054 on branch failed-forcing-refactoring From noreply at buildbot.pypy.org Fri Jul 15 16:04:41 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:41 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head d5d8ff879a62 on branch jit-option-refactor Message-ID: <20110715140441.8E52D82931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r45632:72154b3c7be9 Date: 2011-07-15 16:04 +0200 http://bitbucket.org/pypy/pypy/changeset/72154b3c7be9/ Log: Merge closed head d5d8ff879a62 on branch jit-option-refactor From noreply at buildbot.pypy.org Fri Jul 15 16:04:42 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:42 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head 80826980b2de on branch jit-tagged Message-ID: <20110715140442.BE08382931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r45633:6f3456edd522 Date: 2011-07-15 16:04 +0200 http://bitbucket.org/pypy/pypy/changeset/6f3456edd522/ Log: Merge closed head 80826980b2de on branch jit-tagged diff --git a/.hgsubstate b/.hgsubstate new file mode 100644 From noreply at buildbot.pypy.org Fri Jul 15 16:04:43 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:43 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head 627e43060c05 on branch inline-shadowstack Message-ID: <20110715140443.ED88782931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r45634:393f2527081d Date: 2011-07-15 16:04 +0200 http://bitbucket.org/pypy/pypy/changeset/393f2527081d/ Log: Merge closed head 627e43060c05 on branch inline-shadowstack diff --git a/.hgsubstate b/.hgsubstate deleted file mode 100644 From noreply at buildbot.pypy.org Fri Jul 15 16:04:45 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 15 Jul 2011 16:04:45 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: re-close this branch Message-ID: <20110715140445.0C60A82931@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r45635:07914f4a91cc Date: 2011-07-15 16:04 +0200 http://bitbucket.org/pypy/pypy/changeset/07914f4a91cc/ Log: re-close this branch From noreply at buildbot.pypy.org Fri Jul 15 17:07:43 2011 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 15 Jul 2011 17:07:43 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: update benchmark to have a TApplication as per ROOT rules Message-ID: <20110715150743.AC79082931@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45636:bacc1bb43dca Date: 2011-07-15 08:07 -0700 http://bitbucket.org/pypy/pypy/changeset/bacc1bb43dca/ Log: update benchmark to have a TApplication as per ROOT rules diff --git a/pypy/module/cppyy/bench/Makefile b/pypy/module/cppyy/bench/Makefile --- a/pypy/module/cppyy/bench/Makefile +++ b/pypy/module/cppyy/bench/Makefile @@ -26,4 +26,4 @@ bench02Dict_reflex.so: bench02.h bench02.xml $(genreflex) bench02.h $(genreflexflags) --selection=bench02.xml -I$(ROOTSYS)/include - g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -lReflex `root-config --libs` $(cppflags) $(cppflags2) + g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -lReflex -lHistPainter `root-config --libs` $(cppflags) $(cppflags2) diff --git a/pypy/module/cppyy/bench/bench02.cxx b/pypy/module/cppyy/bench/bench02.cxx --- a/pypy/module/cppyy/bench/bench02.cxx +++ b/pypy/module/cppyy/bench/bench02.cxx @@ -2,15 +2,93 @@ #include "TROOT.h" #include "TApplication.h" #include "TDirectory.h" +#include "TInterpreter.h" +#include "TSystem.h" +#include "TBenchmark.h" +#include "TStyle.h" +#include "TError.h" +#include "Getline.h" +#include "TVirtualX.h" + +// CINT +#include "Api.h" #include +class TTestApplication : public TApplication { +public: + TTestApplication( + const char* acn, Int_t* argc, char** argv, Bool_t bLoadLibs = kTRUE ); + + virtual ~TTestApplication(); +}; + + +//- constructors/destructor -------------------------------------------------- +TTestApplication::TTestApplication( + const char* acn, int* argc, char** argv, bool bLoadLibs ) : + TApplication( acn, argc, argv ) +{ +// Create a TApplication derived for use with interactive ROOT from python. A +// set of standard, often used libs is loaded if bLoadLibs is true (default). + + if ( bLoadLibs ) // note that this section could be programmed in python + { + // follow TRint to minimize differences with CINT + ProcessLine( "#include ", kTRUE ); + ProcessLine( "#include <_string>", kTRUE ); // for std::string iostream. + ProcessLine( "#include ", kTRUE ); // needed because they're used within the + ProcessLine( "#include ", kTRUE ); // core ROOT dicts and CINT won't be able + // to properly unload these files + + // following RINT, these are now commented out (rely on auto-loading) + // // the following libs are also useful to have, make sure they are loaded... + // gROOT->LoadClass("TMinuit", "Minuit"); + // gROOT->LoadClass("TPostScript", "Postscript"); + // gROOT->LoadClass("THtml", "Html"); + } + +#ifdef WIN32 + // switch win32 proxy main thread id + if (gVirtualX) + ProcessLine("((TGWin32 *)gVirtualX)->SetUserThreadId(0);", kTRUE); +#endif + +// save current interpreter context + gInterpreter->SaveContext(); + gInterpreter->SaveGlobalsContext(); + +// prevent crashes on accessing histor + Gl_histinit( (char*)"-" ); + +// prevent ROOT from exiting python + SetReturnFromRun( kTRUE ); +} + +TTestApplication::~TTestApplication() {} + +static const char* appname = "pypy-cppyy"; + CloserHack::CloserHack() { std::cout << "gROOT is: " << gROOT << std::endl; std::cout << "gApplication is: " << gApplication << std::endl; + + if ( ! gApplication ) { + // retrieve arg list from python, translate to raw C, pass on + int argc = 1; + char* argv[1]; argv[0] = (char*)appname; + gApplication = new TTestApplication( appname, &argc, argv, kTRUE ); + } + + std::cout << "gApplication is: " << gApplication << std::endl; } -CloserHack::~CloserHack() { +void CloserHack::report() { + std::cout << "gROOT is: " << gROOT << std::endl; + std::cout << "gApplication is: " << gApplication << std::endl; +} + +void CloserHack::close() { std::cout << "closing file ... " << std::endl; if (gDirectory && gDirectory != gROOT) { gDirectory->Write(); @@ -18,3 +96,6 @@ } } +CloserHack::~CloserHack() { +} + diff --git a/pypy/module/cppyy/bench/bench02.h b/pypy/module/cppyy/bench/bench02.h --- a/pypy/module/cppyy/bench/bench02.h +++ b/pypy/module/cppyy/bench/bench02.h @@ -13,6 +13,9 @@ public: CloserHack(); ~CloserHack(); + + void report(); + void close(); }; /* diff --git a/pypy/module/cppyy/bench/hsimple.py b/pypy/module/cppyy/bench/hsimple.py --- a/pypy/module/cppyy/bench/hsimple.py +++ b/pypy/module/cppyy/bench/hsimple.py @@ -20,6 +20,8 @@ TNtuple = cppyy.gbl.TNtuple TH1F = cppyy.gbl.TH1F TH2F = cppyy.gbl.TH2F + CH = cppyy.gbl.CloserHack() + CH.report() except ImportError: from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F import random @@ -32,7 +34,7 @@ #gROOT.Reset() # Create a new canvas, and customize it. -#c1 = TCanvas( 'c1', 'Dynamic Filling Example', 200, 10, 700, 500 ) +c1 = TCanvas( 'c1', 'Dynamic Filling Example', 200, 10, 700, 500 ) #c1.SetFillColor( 42 ) #c1.GetFrame().SetFillColor( 21 ) #c1.GetFrame().SetBorderSize( 6 ) @@ -80,9 +82,9 @@ # ntupleFill( px, py, pz, random, i ) # Update display every kUPDATE events. -# if i and i%kUPDATE == 0: -# if i == kUPDATE: -# hpx.Draw() + if i and i%kUPDATE == 0: + if i == kUPDATE: + hpx.Draw() # c1.Modified() # c1.Update() @@ -98,7 +100,8 @@ hfile.Close() #hpx.SetFillColor( 48 ) #c1.Modified() -#c1.Update() +c1.Update() +c1.Draw() #import gc #gc.collect() From noreply at buildbot.pypy.org Fri Jul 15 17:58:47 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 15 Jul 2011 17:58:47 +0200 (CEST) Subject: [pypy-commit] buildbot default: bah, this is a hack but I lost a whole afternoon trying to convince buildbot to do the "right thing"; use the svn interface exposed by bitbucket and checkout from the official repo instead of the old codespeak one Message-ID: <20110715155847.1A92282931@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r527:bbb9bb28c92f Date: 2011-07-15 17:58 +0200 http://bitbucket.org/pypy/buildbot/changeset/bbb9bb28c92f/ Log: bah, this is a hack but I lost a whole afternoon trying to convince buildbot to do the "right thing"; use the svn interface exposed by bitbucket and checkout from the official repo instead of the old codespeak one diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -282,7 +282,7 @@ setup_steps(platform, self) self.addStep(ShellCmd(description="checkout benchmarks", - command=['svn', 'co', 'http://codespeak.net/svn/pypy/benchmarks', + command=['svn', 'co', 'https://bitbucket.org/pypy/benchmarks/trunk', 'benchmarks'], workdir='.')) self.addStep(Translate(['-Ojit'], [])) From noreply at buildbot.pypy.org Fri Jul 15 19:39:12 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 15 Jul 2011 19:39:12 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: caching the setfield prioritized over moving the pure int_sub out of the loop Message-ID: <20110715173912.3924182931@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45637:8710093c4d2e Date: 2011-07-13 18:04 +0200 http://bitbucket.org/pypy/pypy/changeset/8710093c4d2e/ Log: caching the setfield prioritized over moving the pure int_sub out of the loop diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5485,16 +5485,16 @@ escape(i5) i4 = int_sub(i2, i1) setfield_gc(p2, i4, descr=valuedescr) - jump(p1, i1, i2, p2) + jump(p1, i1, i2, p2, i4) """ expected = """ [p1, i1, i2, p2, i5] escape(i5) - setfield_gc(p2, i5, descr=valuedescr) - jump(p1, i1, i2, p2, i5) - """ - #self.optimize_strunicode_loop(ops, expected, preamble) - self.optimize_loop(ops, preamble) + i6 = int_sub(i2, i1) + setfield_gc(p2, i6, descr=valuedescr) + jump(p1, i1, i2, p2, i6) + """ + self.optimize_strunicode_loop(ops, expected, preamble) def test_str_slice_1(self): ops = """ From noreply at buildbot.pypy.org Fri Jul 15 19:39:13 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 15 Jul 2011 19:39:13 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: revert/merge to version in default Message-ID: <20110715173913.6583282933@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45638:ebdc139c8c0d Date: 2011-07-13 18:08 +0200 http://bitbucket.org/pypy/pypy/changeset/ebdc139c8c0d/ Log: revert/merge to version in default diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5628,7 +5628,7 @@ [p0, i0] jump(p0, i0) """ - self.optimize_loop(ops, expected, expected) + self.optimize_loop(ops, expected) def test_strlen_positive(self): ops = """ From noreply at buildbot.pypy.org Fri Jul 15 19:39:14 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 15 Jul 2011 19:39:14 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: array accesses with variable indexes no longer supported Message-ID: <20110715173914.9101382931@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45639:836934d0268c Date: 2011-07-14 10:24 +0200 http://bitbucket.org/pypy/pypy/changeset/836934d0268c/ Log: array accesses with variable indexes no longer supported diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6201,7 +6201,7 @@ def test_constant_getfield1(self): ops = """ [p1, p187, i184] - p188 = getarrayitem_gc(p187, i184, descr=) + p188 = getarrayitem_gc(p187, 42, descr=) guard_value(p188, ConstPtr(myptr)) [] p25 = getfield_gc(ConstPtr(myptr), descr=otherdescr) jump(p25, p187, i184) From noreply at buildbot.pypy.org Fri Jul 15 19:39:15 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 15 Jul 2011 19:39:15 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: translation fix Message-ID: <20110715173915.B6A9F82931@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45640:ddba8a22157e Date: 2011-07-14 11:00 +0200 http://bitbucket.org/pypy/pypy/changeset/ddba8a22157e/ Log: translation fix diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -382,13 +382,15 @@ if emit: newop = self.short_inliner.inline_op(op) self.optimizer.send_extra_operation(newop) + else: + newop = None if op.is_ovf(): # FIXME: ensure that GUARD_OVERFLOW:ed ops not end up here guard = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) self.add_op_to_short(guard, short, short_seen, emit) - if emit: + if newop: return newop.result return None From noreply at buildbot.pypy.org Fri Jul 15 19:39:16 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 15 Jul 2011 19:39:16 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: ensure correct order of ops in short preamble Message-ID: <20110715173916.DE3F482931@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45641:d1907e233cb6 Date: 2011-07-14 16:28 +0200 http://bitbucket.org/pypy/pypy/changeset/d1907e233cb6/ Log: ensure correct order of ops in short preamble diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -279,12 +279,12 @@ short_seen = {} for box, const in self.constant_inputargs.items(): short_seen[box] = True - + for result, op in self.short_boxes.items(): if op is not None: assert result is op.result - for guard in self.getvalue(result).make_guards(result): - self.add_op_to_short(guard, short, short_seen, False) + if len(self.getvalue(result).make_guards(result)) > 0: + self.add_op_to_short(op, short, short_seen, False, True) # This loop is equivalent to the main optimization loop in # Optimizer.propagate_all_forward @@ -362,7 +362,7 @@ return inputargs, short_inputargs, short - def add_op_to_short(self, op, short, short_seen, emit=True): + def add_op_to_short(self, op, short, short_seen, emit=True, guards_needed=False): if op is None: return None if op.result is not None and op.result in short_seen: @@ -372,11 +372,17 @@ return None for a in op.getarglist(): if not isinstance(a, Const) and a not in short_seen: - self.add_op_to_short(self.short_boxes[a], short, short_seen, emit) + self.add_op_to_short(self.short_boxes[a], short, short_seen, + emit, guards_needed) if op.is_guard(): descr = self.start_resumedescr.clone_if_mutable() op.setdescr(descr) + if guards_needed and op.result in self.short_boxes: + value_guards = self.getvalue(op.result).make_guards(op.result) + else: + value_guards = [] + short.append(op) short_seen[op.result] = True if emit: @@ -388,7 +394,9 @@ if op.is_ovf(): # FIXME: ensure that GUARD_OVERFLOW:ed ops not end up here guard = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) - self.add_op_to_short(guard, short, short_seen, emit) + self.add_op_to_short(guard, short, short_seen, emit, guards_needed) + for guard in value_guards: + self.add_op_to_short(guard, short, short_seen, emit, guards_needed) if newop: return newop.result From noreply at buildbot.pypy.org Fri Jul 15 19:39:18 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Fri, 15 Jul 2011 19:39:18 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: Setup the state of new optimizer chain for the peeled loop by emitting the short preamble operations. This becomes a lot simpler and less errorprone than trying to copy the exact subset of the preamble optimizer state that would corespond to having executed those ops in the (short) preamble. Message-ID: <20110715173918.2A9EF82931@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45642:f443c6b9ddb5 Date: 2011-07-15 19:38 +0200 http://bitbucket.org/pypy/pypy/changeset/f443c6b9ddb5/ Log: Setup the state of new optimizer chain for the peeled loop by emitting the short preamble operations. This becomes a lot simpler and less errorprone than trying to copy the exact subset of the preamble optimizer state that would corespond to having executed those ops in the (short) preamble. diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -86,6 +86,9 @@ debug_stop('jit-log-ffiopt') Optimization.propagate_end_forward(self) + def new(self): + return OptFfiCall() + def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, optimizer, valuemap): return OptFfiCall() diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -163,6 +163,9 @@ def flush(self): self.force_all_lazy_setfields_and_arrayitems() + + def new(self): + return OptHeap() def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, optimizer, valuemap): @@ -170,7 +173,7 @@ for descr, d in self.cached_fields.items(): new.cached_fields[descr] = d.get_cloned(optimizer, valuemap, short_boxes) - + for descr, submap in self.cached_arrayitems.items(): newdict = {} for index, d in submap.items(): diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -13,6 +13,10 @@ self.posponedop = None self.nextop = None + def new(self): + assert self.posponedop is None + return OptIntBounds() + def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, optimizer, valuemap): assert self.posponedop is None diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -303,6 +303,9 @@ pass # It is too late to force stuff here, it must be done in force_at_end_of_preamble + def new(self): + raise NotImplementedError + def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes=None, optimizer=None, valuemap=None): raise NotImplementedError @@ -335,6 +338,7 @@ self.exception_might_have_happened = False self.quasi_immutable_deps = None self.newoperations = [] + self.emitting_dissabled = False if loop is not None: self.call_pure_results = loop.call_pure_results @@ -363,7 +367,15 @@ for o in self.optimizations: o.flush() assert self.posponedop is None - + + def new(self): + assert self.posponedop is None + new = Optimizer(self.metainterp_sd, self.loop) + optimizations = [o.new() for o in self.optimizations] + new.set_optimizations(optimizations) + new.quasi_immutable_deps = self.quasi_immutable_deps + return new + def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes=None, optimizer=None, valuemap=None): assert optimizer is None @@ -575,10 +587,11 @@ return True def emit_operation(self, op): - ###self.heap_op_optimizer.emitting_operation(op) - self._emit_operation(op) - - def _emit_operation(self, op): + if op.returns_bool_result(): + self.bool_boxes[self.getvalue(op.result)] = None + if self.emitting_dissabled: + return + for i in range(op.numargs()): arg = op.getarg(i) if arg in self.values: @@ -590,8 +603,6 @@ op = self.store_final_boxes_in_guard(op) elif op.can_raise(): self.exception_might_have_happened = True - elif op.returns_bool_result(): - self.bool_boxes[self.getvalue(op.result)] = None self.newoperations.append(op) def store_final_boxes_in_guard(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -14,8 +14,11 @@ """ def __init__(self): self.loop_invariant_results = {} - self.loop_invariant_producer = {} + self.loop_invariant_producer = {} + def new(self): + return OptRewrite() + def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, optimizer, valuemap): new = OptRewrite() @@ -24,7 +27,7 @@ value.get_cloned(new, valuemap) return new - def produce_potential_short_preamble_ops(self, potential_ops): + def produce_potential_short_preamble_ops(self, potential_ops): for op in self.loop_invariant_producer.values(): potential_ops[op.result] = op diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5092,32 +5092,38 @@ def test_invariant_ovf(self): ops = """ - [i0, i1, i10, i11, i12] + [i0, i1, i10, i11, i20, i21] i2 = int_add_ovf(i0, i1) guard_no_overflow() [] i3 = int_sub_ovf(i0, i1) guard_no_overflow() [] i4 = int_mul_ovf(i0, i1) guard_no_overflow() [] + escape(i2) + escape(i3) + escape(i4) i24 = int_mul_ovf(i10, i11) guard_no_overflow() [] i23 = int_sub_ovf(i10, i11) guard_no_overflow() [] i22 = int_add_ovf(i10, i11) guard_no_overflow() [] - jump(i0, i1, i2, i3, i4) - """ - expected = """ - [i0, i1, i10, i11, i12] + jump(i0, i1, i20, i21, i20, i21) + """ + expected = """ + [i0, i1, i10, i11, i2, i3, i4] + escape(i2) + escape(i3) + escape(i4) i24 = int_mul_ovf(i10, i11) guard_no_overflow() [] i23 = int_sub_ovf(i10, i11) guard_no_overflow() [] i22 = int_add_ovf(i10, i11) guard_no_overflow() [] - jump(i0, i1, i10, i11, i12) - """ - self.optimize_loop(ops, expected, ops) + jump(i0, i1, i10, i11, i2, i3, i4) + """ + self.optimize_loop(ops, expected) def test_value_proven_to_be_constant_after_two_iterations(self): class FakeDescr(AbstractDescr): @@ -6213,6 +6219,22 @@ self.optimize_loop(ops, expected, ops) # FIXME: check jumparg 0 == getfield_gc() + def test_constant_getfield1bis(self): + ops = """ + [p1, p187, i184] + p188 = getarrayitem_gc(p187, 42, descr=) + guard_value(p188, ConstPtr(myptr)) [] + p25 = getfield_gc(ConstPtr(myptr), descr=otherdescr) + p26 = call(p25, descr=nonwritedescr) + jump(p26, p187, i184) + """ + expected = """ + [p24, p187, i184, p25] + p26 = call(p25, descr=nonwritedescr) + jump(p26, p187, i184, p25) + """ + self.optimize_loop(ops, expected) + def test_constant_getfield2(self): ops = """ [p19] diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -147,9 +147,6 @@ snapshot_args = snapshot.boxes new_snapshot_args = [] for a in snapshot_args: - if not isinstance(a, Const): - a = loop.preamble.inputargs[jump_args.index(a)] - a = self.inliner.inline_arg(a) a = self.getvalue(a).get_key_box() new_snapshot_args.append(a) prev = self.fix_snapshot(loop, jump_args, snapshot.prev) @@ -173,13 +170,21 @@ self.optimizer.flush() KillHugeIntBounds(self.optimizer).apply() + + loop.preamble.operations = self.optimizer.newoperations + jump_args = [self.getvalue(a).get_key_box() for a in jump_args] - loop.preamble.operations = self.optimizer.newoperations + start_resumedescr = loop.preamble.start_resumedescr.clone_if_mutable() + self.start_resumedescr = start_resumedescr + assert isinstance(start_resumedescr, ResumeGuardDescr) + start_resumedescr.rd_snapshot = self.fix_snapshot(loop, jump_args, + start_resumedescr.rd_snapshot) modifier = VirtualStateAdder(self.optimizer) virtual_state = modifier.get_virtual_state(jump_args) values = [self.getvalue(arg) for arg in jump_args] inputargs = virtual_state.make_inputargs(values) + short_inputargs = virtual_state.make_inputargs(values, keyboxes=True) self.constant_inputargs = {} for box in jump_args: @@ -193,21 +198,44 @@ preamble_optimizer = self.optimizer loop.preamble.quasi_immutable_deps = ( self.optimizer.quasi_immutable_deps) - self.optimizer = self.optimizer.reconstruct_for_next_iteration(sb, jump_args) + self.optimizer = self.optimizer.new() loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps + # Force virtuals amoung the jump_args of the preamble to get the + # operations needed to setup the proper state of those virtuals + # in the peeled loop + inputarg_setup_ops = [] + preamble_optimizer.newoperations = [] + for box in short_inputargs: + value = preamble_optimizer.getvalue(box) + if value.is_virtual(): + value.force_box() + else: + inputarg_setup_ops.extend(value.make_guards(box)) + preamble_optimizer.flush() + inputarg_setup_ops += preamble_optimizer.newoperations + + # Setup the state of the new optimizer by emiting the + # short preamble operations and discarding the result + self.optimizer.emitting_dissabled = True + for op in inputarg_setup_ops: + self.optimizer.send_extra_operation(op) + seen = {} + for op in self.short_boxes.values(): + self.ensure_short_op_emitted(op, self.optimizer, seen) + if op and op.result: + value = preamble_optimizer.getvalue(op.result) + for guard in value.make_guards(op.result): + self.optimizer.send_extra_operation(guard) + self.optimizer.flush() + self.optimizer.emitting_dissabled = False + initial_inputargs_len = len(inputargs) self.inliner = Inliner(loop.inputargs, jump_args) - start_resumedescr = loop.preamble.start_resumedescr.clone_if_mutable() - self.start_resumedescr = start_resumedescr - assert isinstance(start_resumedescr, ResumeGuardDescr) - start_resumedescr.rd_snapshot = self.fix_snapshot(loop, jump_args, - start_resumedescr.rd_snapshot) - - inputargs, short_inputargs, short = self.inline(self.cloned_operations, - loop.inputargs, jump_args, - virtual_state) + short = self.inline(inputargs, self.cloned_operations, + loop.inputargs, short_inputargs, + virtual_state) #except KeyError: # debug_print("Unrolling failed.") @@ -267,13 +295,10 @@ if op.result: op.result.forget_value() - def inline(self, loop_operations, loop_args, jump_args, virtual_state): + def inline(self, inputargs, loop_operations, loop_args, short_inputargs, virtual_state): inliner = self.inliner - values = [self.getvalue(arg) for arg in jump_args] - inputargs = virtual_state.make_inputargs(values) short_jumpargs = inputargs[:] - short_inputargs = virtual_state.make_inputargs(values, keyboxes=True) short = [] short_seen = {} @@ -360,8 +385,22 @@ raise InvalidLoop debug_stop('jit-log-virtualstate') - return inputargs, short_inputargs, short + return short + def ensure_short_op_emitted(self, op, optimizer, seen): + if op is None: + return + if op.result is not None and op.result in seen: + return + for a in op.getarglist(): + if not isinstance(a, Const) and a not in seen: + self.ensure_short_op_emitted(self.short_boxes[a], optimizer, seen) + optimizer.send_extra_operation(op) + seen[op.result] = True + if op.is_ovf(): + guard = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) + optimizer.send_extra_operation(guard) + def add_op_to_short(self, op, short, short_seen, emit=True, guards_needed=False): if op is None: return None @@ -656,7 +695,10 @@ class OptInlineShortPreamble(Optimization): def __init__(self, retraced): self.retraced = retraced - + + def new(self): + return OptInlineShortPreamble(self.retraced) + def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, optimizer, valuemap): return OptInlineShortPreamble(self.retraced) diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -311,6 +311,9 @@ class OptVirtualize(optimizer.Optimization): "Virtualize objects until they escape." + def new(self): + return OptVirtualize() + def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, optimizer, valuemap): return OptVirtualize() diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -366,6 +366,9 @@ "Handling of strings and unicodes." enabled = True + def new(self): + return OptString() + def reconstruct_for_next_iteration(self, short_boxes, surviving_boxes, optimizer, valuemap): return OptString() From noreply at buildbot.pypy.org Fri Jul 15 21:41:30 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 15 Jul 2011 21:41:30 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: First try at being able to set slices in numpy Message-ID: <20110715194130.3A01A82931@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45643:479060a4dade Date: 2011-07-13 22:48 -0600 http://bitbucket.org/pypy/pypy/changeset/479060a4dade/ Log: First try at being able to set slices in numpy diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -267,10 +267,15 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().descr_setitem(space, start, space.float_w(w_value)) + else: + self.get_concrete().descr_setslice(space, start, stop, step, slice_length, w_value) def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) @@ -422,6 +427,7 @@ @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): + # need to change this so that it can deal with slices return self.parent.descr_setitem(space, self.calc_index(item), value) def descr_len(self, space): @@ -507,12 +513,54 @@ def descr_str(self,space): return space.wrap("[" + " ".join(self._getnums(True)) + "]") - @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) self.invalidated() self.storage[item] = value + def descr_setslice(self, space, start, stop, step, slice_length, w_value): + i = start + if step > 0: + stop = min(stop, self.find_size()) + else: + stop = max(stop, 0) + if isinstance(w_value, BaseArray): + j = 0 + if step > 0: + while i < stop: + self.storage[i] = w_value.get_concrete().getitem(j) + i += step + j += 1 + else: + while i > stop: + self.storage[i] = w_value.get_concrete().getitem(j) + i += step + j += 1 + elif space.issequence_w(w_value): + l = space.listview(w_value) + if step > 0: + for w_elem in l: + self.storage[i] = space.float_w(space.float(w_elem)) + i += step + if i >= stop: + break + else: + for w_elem in l: + self.storage[i] = space.float_w(space.float(w_elem)) + i += step + if i <= stop: + break + else: + value = space.float_w(space.float(w_value)) + if step > 0: + while i < stop: + self.storage[i] = value + i += step + else: + while i > stop: + self.storage[i] = value + i += step + def __del__(self): lltype.free(self.storage, flavor='raw') diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -74,6 +74,29 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Fri Jul 15 21:41:31 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 15 Jul 2011 21:41:31 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: micronumpy: second version of setslice including jit driver and test Message-ID: <20110715194131.644D982931@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45644:182a6ac8d391 Date: 2011-07-14 18:53 -0600 http://bitbucket.org/pypy/pypy/changeset/182a6ac8d391/ Log: micronumpy: second version of setslice including jit driver and test diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,6 +21,8 @@ reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) class Signature(object): def __init__(self): @@ -257,7 +259,7 @@ return self.get_concrete().descr_str(space) def descr_getitem(self, space, w_idx): - # TODO: indexing by tuples + # TODO: indexing by tuples and lists start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) if step == 0: # Single index @@ -268,6 +270,7 @@ return space.wrap(res) def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -513,53 +516,50 @@ def descr_str(self,space): return space.wrap("[" + " ".join(self._getnums(True)) + "]") + @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) self.invalidated() self.storage[item] = value - def descr_setslice(self, space, start, stop, step, slice_length, w_value): + def _setslice1(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def _setslice2(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def descr_setslice(self, space, start, stop, step, slice_length, arr): + i = start + if stop < 0: + stop += self.find_size() if step > 0: stop = min(stop, self.find_size()) else: stop = max(stop, 0) - if isinstance(w_value, BaseArray): - j = 0 - if step > 0: - while i < stop: - self.storage[i] = w_value.get_concrete().getitem(j) - i += step - j += 1 - else: - while i > stop: - self.storage[i] = w_value.get_concrete().getitem(j) - i += step - j += 1 - elif space.issequence_w(w_value): - l = space.listview(w_value) - if step > 0: - for w_elem in l: - self.storage[i] = space.float_w(space.float(w_elem)) - i += step - if i >= stop: - break - else: - for w_elem in l: - self.storage[i] = space.float_w(space.float(w_elem)) - i += step - if i <= stop: - break + if not isinstance(arr, BaseArray): + arr = convert_to_array(space, arr) + if step > 0: + self._setslice1(start, stop, step, arr) else: - value = space.float_w(space.float(w_value)) - if step > 0: - while i < stop: - self.storage[i] = value - i += step - else: - while i > stop: - self.storage[i] = value - i += step + self._setslice2(start, stop, step, arr) def __del__(self): lltype.free(self.storage, flavor='raw') diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -5,6 +5,7 @@ from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): w_ValueError = None @@ -248,6 +249,21 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar.descr_setslice(space, 0, step*i, step, i, ar2) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) From noreply at buildbot.pypy.org Fri Jul 15 21:41:32 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 15 Jul 2011 21:41:32 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: numpy: improved implementation of size and ndim Message-ID: <20110715194132.8C3C182931@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45645:a60790b8cf0d Date: 2011-07-14 23:14 -0600 http://bitbucket.org/pypy/pypy/changeset/a60790b8cf0d/ Log: numpy: improved implementation of size and ndim diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -247,10 +247,10 @@ return self.get_concrete().descr_len(space) def descr_get_size(self, space): - return self.get_concrete().descr_get_size(space) + return space.wrap(self.find_size()) def descr_get_ndim(self, space): - return self.get_concrete().descr_get_ndim(space) + return space.wrap(self.find_ndim()) def descr_repr(self, space): return self.get_concrete().descr_repr(space) @@ -309,6 +309,9 @@ def find_size(self): raise ValueError + def find_ndim(self): + raise ValueError + def eval(self, i): return self.float_value @@ -358,6 +361,12 @@ return self.forced_result.find_size() return self._find_size() + def find_ndim(self): + if self.forced_result is not None: + # The result has been computed and sources may be unavailable + return self.forced_result.find_ndim() + return self._find_ndim() + class Call1(VirtualArray): _immutable_fields_ = ["function", "values"] @@ -373,6 +382,9 @@ def _find_size(self): return self.values.find_size() + def _find_ndim(self): + return self.values.find_ndim() + def _eval(self, i): return self.function(self.values.eval(i)) @@ -399,6 +411,13 @@ pass return self.right.find_size() + def _find_ndim(self): + try: + return self.left.find_ndim() + except ValueError: + pass + return self.right.find_ndim() + def _eval(self, i): lhs, rhs = self.left.eval(i), self.right.eval(i) return self.function(lhs, rhs) @@ -434,6 +453,8 @@ return self.parent.descr_setitem(space, self.calc_index(item), value) def descr_len(self, space): + # This will need to change for multidimensional arrays. + # For them, len returns the size of the first dimension return space.wrap(self.find_size()) def calc_index(self, item): @@ -449,10 +470,14 @@ self.stop = stop self.step = step self.size = slice_length + self.ndim = 1 def find_size(self): return self.size + def find_ndim(self): + return self.ndim + def calc_index(self, item): return (self.start + item * self.step) @@ -463,16 +488,22 @@ def __init__(self, size): BaseArray.__init__(self) self.size = size + self.ndim = 1 self.storage = lltype.malloc(TP, size, zero=True, flavor='raw', track_allocation=False) # XXX find out why test_zjit explodes with trackign of allocations - + # we could probably put get_concrete, find_size, and find_dim all in + # a new class called ConcreteArray or some such because they will + # be the same for multi-dimensional arrays. def get_concrete(self): return self def find_size(self): return self.size + def find_ndim(self): + return self.ndim + def eval(self, i): return self.storage[i] @@ -490,11 +521,6 @@ def descr_len(self, space): return space.wrap(self.size) - descr_get_size = descr_len - - def descr_get_ndim(self, space): - return space.wrap(1) - def getitem(self, item): return self.storage[item] From noreply at buildbot.pypy.org Fri Jul 15 21:41:33 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 15 Jul 2011 21:41:33 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: numpy: added comments about simple repr and str implementations Message-ID: <20110715194133.B288C82931@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45646:bf62aedfaa55 Date: 2011-07-14 23:16 -0600 http://bitbucket.org/pypy/pypy/changeset/bf62aedfaa55/ Log: numpy: added comments about simple repr and str implementations diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -537,9 +537,11 @@ return nums def descr_repr(self, space): + # Simple implementation so that we can see the array. Needs work. return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") def descr_str(self,space): + # Simple implementation so that we can see the array. Needs work. return space.wrap("[" + " ".join(self._getnums(True)) + "]") @unwrap_spec(item=int, value=float) From noreply at buildbot.pypy.org Fri Jul 15 21:41:34 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 15 Jul 2011 21:41:34 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: numpy: added a check of array sizes to binary ops. added more tests for radd, etc. Message-ID: <20110715194134.D9DBA82931@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45647:dff713e0278f Date: 2011-07-15 13:36 -0600 http://bitbucket.org/pypy/pypy/changeset/dff713e0278f/ Log: numpy: added a check of array sizes to binary ops. added more tests for radd, etc. diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -4,6 +4,7 @@ """ from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.rlib.objectmodel import specialize class BogusBytecode(Exception): pass @@ -15,8 +16,12 @@ return a class TrivialSpace(object): - def wrap(self, x): - return x + w_ValueError = None + + @specialize.argtype(1) + def wrap(self, w_obj): + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -90,6 +90,18 @@ signature = Signature() def impl(self, space, w_other): w_other = convert_to_array(space, w_other) + try: + w_other_size = w_other.find_size() + self_size = self.find_size() + except ValueError: + # this will be raised if one of the arrays is a scalar. + pass + else: + # Need a better dimension check here for N-dim arrays + if w_other_size != self_size: + raise OperationError(space.w_ValueError, + space.wrap("Cannot %s arrays of unequal dimensions" \ + % function.__name__)) new_sig = self.signature.transition(signature) res = Call2( function, @@ -113,7 +125,7 @@ signature = Signature() def impl(self, space, w_other): new_sig = self.signature.transition(signature) - w_other = FloatWrapper(space.float_w(w_other)) + w_other = convert_to_array(space, w_other) res = Call2( function, w_other, diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -18,8 +18,8 @@ def test_slice_signature(self, space): ar = SingleDimArray(10) - v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1))) - v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1))) + v1 = ar.descr_getitem(space, space.wrap(slice(0, 10, 1))) + v2 = ar.descr_getitem(space, space.wrap(slice(9, None, -1))) assert v1.signature is v2.signature v3 = ar.descr_add(space, v1) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -145,6 +145,9 @@ b = a + 5 for i in range(5): assert b[i] == i + 5 + b = 5 + a + for i in range(5): + assert b[i] == 5 + i def test_add_list(self): from numpy import array @@ -154,6 +157,16 @@ assert isinstance(c, array) for i in range(5): assert c[i] == 4 + c = b + a + assert isinstance(c, array) + for i in range(5): + assert c[i] == 4 + + def test_add_unequal_size(self): + from numpy import array + a = array(range(5)) + b = array(range(3)) + raises(ValueError, "a + b") def test_subtract(self): from numpy import array @@ -176,6 +189,9 @@ b = a - 5 for i in range(5): assert b[i] == i - 5 + b = 5 - a + for i in range(5): + assert b[i] == 5 - i def test_mul(self): from numpy import array @@ -190,6 +206,9 @@ b = a * 5 for i in range(5): assert b[i] == i * 5 + b = 5 * a + for i in range(5): + assert b[i] == 5 * i def test_div(self): from numpy import array @@ -208,10 +227,13 @@ def test_div_constant(self): from numpy import array - a = array(range(5)) + a = array(range(1,6)) b = a / 5.0 for i in range(5): - assert b[i] == i / 5.0 + assert b[i] == (i+1) / 5.0 + b = 5.0 / a + for i in range(5): + assert b[i] == 5.0 / (i+1) def test_pow(self): from numpy import array @@ -235,6 +257,9 @@ b = a ** 2 for i in range(5): assert b[i] == i ** 2 + b = 2 ** a + for i in range(5): + assert b[i] == 2 ** i def test_mod(self): from numpy import array @@ -253,10 +278,13 @@ def test_mod_constant(self): from numpy import array - a = array(range(5)) + a = array(range(1,6)) b = a % 2 for i in range(5): - assert b[i] == i % 2 + assert b[i] == (i+1) % 2 + b = 2 % a + for i in range(5): + assert b[i] == 2 % (i+1) def test_pos(self): from numpy import array From noreply at buildbot.pypy.org Fri Jul 15 21:41:36 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 15 Jul 2011 21:41:36 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: numpy: first draft of the sort function Message-ID: <20110715194136.13A5482931@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45648:11f5df53c131 Date: 2011-07-15 13:41 -0600 http://bitbucket.org/pypy/pypy/changeset/11f5df53c131/ Log: numpy: first draft of the sort function diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -7,6 +7,8 @@ from pypy.tool.sourcetools import func_with_new_name import math +INSERT_SORT_THRESH = 15 + def dummy1(v): assert isinstance(v, float) return v @@ -249,6 +251,80 @@ else: return self.descr_mul(space, w_other) + def _insertion_sort(self, storage, left, right): + i = left + 1 + while i <= right: + temp = storage[i] + j = i - 1 + while j >= left and storage[j] > temp: + storage[j + 1] = storage[j] + j -= 1 + storage[j + 1] = temp + i += 1 + + def descr_sort(self, space): + storage = self.get_concrete().storage + # can replace these with integer/bool numpy arrays when we add dtypes + lefts = [0] + rights = [self.find_size() - 1] + checkpivots = [False] + while lefts: + left = lefts.pop() + right = rights.pop() + checkpivot = checkpivots.pop() + # just use middle element for now. will change to med of 3 soon + mid = left + (right - left) / 2 + pivot = storage[mid] + if checkpivot and pivot == storage[left - 1]: + storage[mid], storage[left] = storage[left], storage[mid] + i = left + 1 + j = right + while 1: + while storage[j] != pivot: + j -= 1 + while storage[i] == pivot: + if i >= j: break + i += 1 + if i >= j: break + storage[i], storage[j] = storage[j], storage[i] + storage[j] = pivot + if right > j + 1: + if right - j + 1 < INSERT_SORT_THRESH: + self._insertion_sort(storage, j + 1, right) + else: + lefts.append(j + 1) + rights.append(right) + checkpivots.append(False) + else: + storage[mid], storage[right] = storage[right], storage[mid] + i = left + j = right - 1 + while 1: + while storage[i] < pivot: + i += 1 + while storage[j] >= pivot: + if i >= j: break + j -= 1 + if i >= j: break + storage[i], storage[j] = storage[j], storage[i] + storage[right] = storage[i] + storage[i] = pivot + # we can have the smaller subarray sorted first + if left < i - 1: + if i - 1 - left < INSERT_SORT_THRESH: + self._insertion_sort(storage, left, i - 1) + else: + lefts.append(left) + rights.append(i - 1) + checkpivots.append(checkpivot) + if right > i + 1: + if right - i - 1 < INSERT_SORT_THRESH: + self._insertion_sort(storage, i + 1, right) + else: + lefts.append(i + 1) + rights.append(right) + checkpivots.append(True) + def get_concrete(self): raise NotImplementedError @@ -667,4 +743,5 @@ all = interp2app(BaseArray.descr_all), any = interp2app(BaseArray.descr_any), dot = interp2app(BaseArray.descr_dot), + sort = interp2app(BaseArray.descr_sort), ) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -443,6 +443,14 @@ for i in xrange(5): assert b[i] == 2.5*a[i] + def test_sort(self): + from numpy import array + a = array(range(19,-1,-1)) + b = array(range(20)) + a.sort() + for i in xrange(20): + assert a[i] == b[i] + class AppTestSupport(object): def setup_class(cls): From noreply at buildbot.pypy.org Sat Jul 16 00:12:56 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 00:12:56 +0200 (CEST) Subject: [pypy-commit] pypy faster-nested-scopes: make Cell.w_value quasi-immutable. This is useful for inner functions that survive their defining scope. Message-ID: <20110715221256.D5D9882933@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: faster-nested-scopes Changeset: r45650:ccb04f0a55e9 Date: 2011-07-15 19:33 +0200 http://bitbucket.org/pypy/pypy/changeset/ccb04f0a55e9/ Log: make Cell.w_value quasi-immutable. This is useful for inner functions that survive their defining scope. diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -8,7 +8,8 @@ class Cell(Wrappable): "A simple container for a wrapped value." - + _immutable_fields_ = ["w_value?"] + def __init__(self, w_value=None): self.w_value = w_value From noreply at buildbot.pypy.org Sat Jul 16 00:12:55 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 00:12:55 +0200 (CEST) Subject: [pypy-commit] pypy faster-nested-scopes: make Function.closure a quasi-immutable array. Pass it into createframe, Message-ID: <20110715221255.98EAE82931@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: faster-nested-scopes Changeset: r45649:29789b62e66d Date: 2011-07-15 19:32 +0200 http://bitbucket.org/pypy/pypy/changeset/29789b62e66d/ Log: make Function.closure a quasi-immutable array. Pass it into createframe, so that the reading of the cells is constant-folded. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -621,9 +621,9 @@ self.default_compiler = compiler return compiler - def createframe(self, code, w_globals, closure=None): + def createframe(self, code, w_globals, outer_func=None): "Create an empty PyFrame suitable for this code object." - return self.FrameClass(self, code, w_globals, closure) + return self.FrameClass(self, code, w_globals, outer_func) def allocate_lock(self): """Return an interp-level Lock object if threads are enabled, diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -30,7 +30,7 @@ can_change_code = True _immutable_fields_ = ['code?', 'w_func_globals?', - 'closure?', + 'closure?[*]', 'defs_w?[*]'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, @@ -95,7 +95,7 @@ assert isinstance(code, PyCode) if nargs < 5: new_frame = self.space.createframe(code, self.w_func_globals, - self.closure) + self) for i in funccallunrolling: if i < nargs: new_frame.locals_stack_w[i] = args_w[i] @@ -155,7 +155,7 @@ def _flat_pycall(self, code, nargs, frame): # code is a PyCode new_frame = self.space.createframe(code, self.w_func_globals, - self.closure) + self) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) new_frame.locals_stack_w[i] = w_arg @@ -166,7 +166,7 @@ def _flat_pycall_defaults(self, code, nargs, frame, defs_to_load): # code is a PyCode new_frame = self.space.createframe(code, self.w_func_globals, - self.closure) + self) for i in xrange(nargs): w_arg = frame.peekvalue(nargs-1-i) new_frame.locals_stack_w[i] = w_arg diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py --- a/pypy/interpreter/nestedscope.py +++ b/pypy/interpreter/nestedscope.py @@ -93,29 +93,31 @@ cells = None @jit.unroll_safe - def initialize_frame_scopes(self, closure, code): - super_initialize_frame_scopes(self, closure, code) + def initialize_frame_scopes(self, outer_func, code): + super_initialize_frame_scopes(self, outer_func, code) ncellvars = len(code.co_cellvars) nfreevars = len(code.co_freevars) if not nfreevars: if not ncellvars: return # no self.cells needed - fast path - if closure is None: - closure = [] - elif closure is None: + elif outer_func is None: space = self.space raise OperationError(space.w_TypeError, space.wrap("directly executed code object " "may not contain free variables")) - if len(closure) != nfreevars: + if outer_func and outer_func.closure: + closure_size = len(outer_func.closure) + else: + closure_size = 0 + if closure_size != nfreevars: raise ValueError("code object received a closure with " "an unexpected number of free variables") self.cells = [None] * (ncellvars + nfreevars) for i in range(ncellvars): self.cells[i] = Cell() for i in range(nfreevars): - self.cells[i + ncellvars] = closure[i] - + self.cells[i + ncellvars] = outer_func.closure[i] + def _getcells(self): return self.cells diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -198,7 +198,7 @@ def funcrun(self, func, args): frame = self.space.createframe(self, func.w_func_globals, - func.closure) + func) sig = self._signature # speed hack fresh_frame = jit.hint(frame, access_directly=True, @@ -211,7 +211,7 @@ def funcrun_obj(self, func, w_obj, args): frame = self.space.createframe(self, func.w_func_globals, - func.closure) + func) sig = self._signature # speed hack fresh_frame = jit.hint(frame, access_directly=True, diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -51,7 +51,7 @@ is_being_profiled = False escaped = False # see mark_as_escaped() - def __init__(self, space, code, w_globals, closure): + def __init__(self, space, code, w_globals, outer_func): self = hint(self, access_directly=True, fresh_virtualizable=True) assert isinstance(code, pycode.PyCode) self.pycode = code @@ -67,7 +67,7 @@ self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. - self.initialize_frame_scopes(closure, code) + self.initialize_frame_scopes(outer_func, code) self.f_lineno = code.co_firstlineno def mark_as_escaped(self): @@ -113,8 +113,8 @@ return self.builtin else: return self.space.builtin - - def initialize_frame_scopes(self, closure, code): + + def initialize_frame_scopes(self, outer_func, code): # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. # CO_NEWLOCALS: make a locals dict unless optimized is also set @@ -381,7 +381,11 @@ # do not use the instance's __init__ but the base's, because we set # everything like cells from here - PyFrame.__init__(self, space, pycode, w_globals, closure) + # XXX hack + from pypy.interpreter.function import Function + outer_func = Function(space, None, closure=closure, + forcename="") + PyFrame.__init__(self, space, pycode, w_globals, outer_func) f_back = space.interp_w(PyFrame, w_f_back, can_be_None=True) new_frame.f_backref = jit.non_virtual_ref(f_back) diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -293,7 +293,7 @@ raise break new_frame = space.createframe(code, w_func.w_func_globals, - w_func.closure) + w_func) new_frame.locals_stack_w[0] = w_item w_res = new_frame.run() result_w.append(w_res) diff --git a/pypy/objspace/std/fake.py b/pypy/objspace/std/fake.py --- a/pypy/objspace/std/fake.py +++ b/pypy/objspace/std/fake.py @@ -142,7 +142,7 @@ def funcrun(self, func, args): frame = func.space.createframe(self, func.w_func_globals, - func.closure) + func) sig = self.signature() scope_w = args.parse_obj(None, func.name, sig, func.defs_w) frame.setfastscope(scope_w) diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -130,12 +130,12 @@ ec._py_repr = None return ec - def createframe(self, code, w_globals, closure=None): + def createframe(self, code, w_globals, outer_func=None): from pypy.objspace.std.fake import CPythonFakeCode, CPythonFakeFrame if not we_are_translated() and isinstance(code, CPythonFakeCode): return CPythonFakeFrame(self, code, w_globals) else: - return ObjSpace.createframe(self, code, w_globals, closure) + return ObjSpace.createframe(self, code, w_globals, outer_func) def gettypefor(self, cls): return self.gettypeobject(cls.typedef) From noreply at buildbot.pypy.org Sat Jul 16 00:12:58 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 00:12:58 +0200 (CEST) Subject: [pypy-commit] pypy faster-nested-scopes: make PyFrame.cells a virtualizable array Message-ID: <20110715221258.1C79C82931@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: faster-nested-scopes Changeset: r45651:57b614c62cdc Date: 2011-07-15 19:34 +0200 http://bitbucket.org/pypy/pypy/changeset/57b614c62cdc/ Log: make PyFrame.cells a virtualizable array diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -22,6 +22,7 @@ PyFrame._virtualizable2_ = ['last_instr', 'pycode', 'valuestackdepth', 'locals_stack_w[*]', + 'cells[*]', 'last_exception', 'lastblock', 'is_being_profiled', From noreply at buildbot.pypy.org Sat Jul 16 00:12:59 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 00:12:59 +0200 (CEST) Subject: [pypy-commit] pypy faster-nested-scopes: fix Message-ID: <20110715221259.6D91382931@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: faster-nested-scopes Changeset: r45652:6202956627cc Date: 2011-07-15 20:09 +0200 http://bitbucket.org/pypy/pypy/changeset/6202956627cc/ Log: fix diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -384,7 +384,7 @@ # XXX hack from pypy.interpreter.function import Function outer_func = Function(space, None, closure=closure, - forcename="") + forcename="fake") PyFrame.__init__(self, space, pycode, w_globals, outer_func) f_back = space.interp_w(PyFrame, w_f_back, can_be_None=True) new_frame.f_backref = jit.non_virtual_ref(f_back) From noreply at buildbot.pypy.org Sat Jul 16 00:13:00 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 00:13:00 +0200 (CEST) Subject: [pypy-commit] pypy default: check only once during tracing whether a frame is a nonstandard-virtualizable Message-ID: <20110715221300.C76E782931@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45653:72d3b692033c Date: 2011-07-15 20:19 +0200 http://bitbucket.org/pypy/pypy/changeset/72d3b692033c/ Log: check only once during tracing whether a frame is a nonstandard- virtualizable diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -596,12 +596,16 @@ standard_box = self.metainterp.virtualizable_boxes[-1] if standard_box is box: return False + if box in self.metainterp.nonstandard_virtualizables: + return True eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None, box, standard_box) eqbox = self.implement_guard_value(pc, eqbox) isstandard = eqbox.getint() if isstandard: self.metainterp.replace_box(box, standard_box) + else: + self.metainterp.nonstandard_virtualizables[box] = None return not isstandard def _get_virtualizable_field_index(self, fielddescr): @@ -1456,6 +1460,8 @@ self.call_pure_results = args_dict_box() # contains boxes where the class is already known self.known_class_boxes = {} + # contains frame boxes that are not virtualizables + self.nonstandard_virtualizables = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1797,6 +1803,7 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} + self.nonstandard_virtualizables = {} # XXX maybe not needed? duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -1133,6 +1133,7 @@ res = self.meta_interp(f, [10]) assert res == 55 self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True) + self.check_history(ptr_eq=2) def test_virtual_child_frame_with_arrays(self): myjitdriver = JitDriver(greens = [], reds = ['frame'], From noreply at buildbot.pypy.org Sat Jul 16 00:13:03 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 00:13:03 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110715221303.3D56882931@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45654:9ed168d89332 Date: 2011-07-15 23:45 +0200 http://bitbucket.org/pypy/pypy/changeset/9ed168d89332/ Log: merge diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -19,12 +19,12 @@ section * Write them in pure python and use direct libffi low-level bindings, See - \_rawffi_ module description. + \_ffi_ module description. * Write them in RPython as mixedmodule_, using *rffi* as bindings. .. _ctypes: #CTypes -.. _\_rawffi: #LibFFI +.. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules CTypes @@ -42,41 +42,50 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. +ctypes call are optimized by the JIT and the resulting machine code contains a +direct call to the target C function. However, due to the very dynamic nature +of ctypes, some overhead over a bare C call is still present, in particular to +check/convert the types of the parameters. Moreover, even if most calls are +optimized, some cannot and thus need to follow the slow path, not optimized by +the JIT. + .. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure +.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html Pros ---- -Stable, CPython-compatible API +Stable, CPython-compatible API. Most calls are fast, optimized by JIT. Cons ---- -Only pure-python code (slow), problems with platform-dependency (although -we partially solve those). PyPy implementation is now very slow. +Problems with platform-dependency (although we partially solve +those). Although the JIT optimizes ctypes calls, some overhead is still +present. The slow-path is very slow. -_`CPython ctypes`: http://python.net/crew/theller/ctypes/ LibFFI ====== Mostly in order to be able to write a ctypes module, we developed a very -low-level libffi bindings. (libffi is a C-level library for dynamic calling, +low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling, which is used by CPython ctypes). This library provides stable and usable API, although it's API is a very low-level one. It does not contain any -magic. +magic. It is also optimized by the JIT, but has much less overhead than ctypes. Pros ---- -Works. Combines disadvantages of using ctypes with disadvantages of -using mixed modules. Probably more suitable for a delicate code -where ctypes magic goes in a way. +It Works. Probably more suitable for a delicate code where ctypes magic goes +in a way. All calls are optimized by the JIT, there is no slow path as in +ctypes. Cons ---- -Slow. CPython-incompatible API, very rough and low-level +It combines disadvantages of using ctypes with disadvantages of using mixed +modules. CPython-incompatible API, very rough and low-level. Mixed Modules ============= @@ -87,15 +96,15 @@ * a mixed module needs to be written in RPython, which is far more complicated than Python (XXX link) -* due to lack of separate compilation (as of April 2008), each +* due to lack of separate compilation (as of July 2011), each compilation-check requires to recompile whole PyPy python interpreter, which takes 0.5-1h. We plan to solve this at some point in near future. * although rpython is a garbage-collected language, the border between C and RPython needs to be managed by hand (each object that goes into the - C level must be explicitly freed) XXX we try to solve this + C level must be explicitly freed). -Some document is available `here`_ +Some documentation is available `here`_ .. _`here`: rffi.html diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -27,9 +27,10 @@ _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset) -def parse_future(tree): +def parse_future(tree, feature_flags): future_lineno = 0 future_column = 0 + flags = 0 have_docstring = False body = None if isinstance(tree, ast.Module): @@ -37,7 +38,7 @@ elif isinstance(tree, ast.Interactive): body = tree.body if body is None: - return 0, 0 + return 0, 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): if have_docstring: @@ -48,11 +49,16 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset + for alias in stmt.names: + assert isinstance(alias, ast.alias) + # If this is an invalid flag, it will be caught later in + # codegen.py. + flags |= feature_flags.get(alias.name, 0) else: break else: break - return future_lineno, future_column + return flags, future_lineno, future_column class ForbiddenNameAssignment(Exception): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,10 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - future_pos = misc.parse_future(node) + fut = misc.parse_future(node, self.future_flags.compiler_features) + f_flags, f_lineno, f_col = fut + future_pos = f_lineno, f_col + flags |= f_flags info = pyparse.CompileInfo(filename, mode, flags, future_pos) return self._compile_ast(node, info) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) - if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') + if parent_destructor is not None: + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -858,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -482,7 +482,7 @@ # rawstart = self.materialize_loop(original_loop_token) debug_start("jit-backend-addr") - debug_print("Bridge out of Guard %d has address %x to %x" % + debug_print("bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): @@ -44,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -58,10 +63,15 @@ expected = "\xE8" + struct.pack('", "exec") + mod = self.get_ast("from __future__ import division\nx = 1/2") + co = compile(mod, "", "exec") + ns = {} + exec co in ns + assert ns["x"] == .5 def test_field_attr_writable(self): import _ast as ast diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -43,11 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -57,6 +57,11 @@ def __del__(self): self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + + def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -10,7 +10,7 @@ class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 @@ -23,8 +23,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,11 +120,8 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: - w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) + assert isinstance(w_self, W_WeakrefBase) + w_self.space.call_function(w_self.w_callable, w_self) def descr__repr__(self, space): w_obj = self.dereference() diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -133,6 +133,7 @@ bz2f.seek(0) assert bz2f.tell() == 0 + del bz2f # delete from this frame, which is captured in the traceback def test_open_close_del(self): from bz2 import BZ2File @@ -246,11 +247,18 @@ assert text_read == self.TEXT bz2f.close() + def test_silently_closes(self): + from bz2 import BZ2File + self.create_broken_temp_file() + BZ2File(self.temppath) + # check that no C-level malloc is left behind + def test_read_broken_file(self): from bz2 import BZ2File self.create_broken_temp_file() bz2f = BZ2File(self.temppath) raises(EOFError, bz2f.read) + del bz2f # delete from this frame, which is captured in the traceback def test_subsequent_read_broken_file(self): from bz2 import BZ2File @@ -264,6 +272,7 @@ raise Exception("should generate EOFError earlier") except EOFError: pass + del bz2f # delete from this frame, which is captured in the traceback def test_read_chunk10(self): from bz2 import BZ2File @@ -416,6 +425,7 @@ bz2f.close() bz2f = BZ2File(self.temppath, 'r') assert bz2f.read() == self.random_data + del bz2f # delete from this frame, which is captured in the traceback def test_context_manager(self): from bz2 import BZ2File diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.1" /* PyPy version as a string */ -#define PYPY_VERSION "1.5.0" +#define PYPY_VERSION "1.6.0" /* Subversion Revision number of this file (not of the repository) */ #define PY_PATCHLEVEL_REVISION "$Revision: 77872 $" diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -22,7 +22,7 @@ def PySequence_Check(space, w_obj): """Return 1 if the object provides sequence protocol, and 0 otherwise. This function always succeeds.""" - return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None) + return int(space.issequence_w(w_obj)) @cpython_api([PyObject], Py_ssize_t, error=-1) def PySequence_Size(space, w_obj): diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py --- a/pypy/module/sys/test/test_sysmodule.py +++ b/pypy/module/sys/test/test_sysmodule.py @@ -476,7 +476,7 @@ assert isinstance(vi[0], int) assert isinstance(vi[1], int) assert isinstance(vi[2], int) - assert vi[3] in ("alpha", "beta", "candidate", "final") + assert vi[3] in ("alpha", "beta", "candidate", "dev", "final") assert isinstance(vi[4], int) def test_allattributes(self): @@ -523,4 +523,4 @@ # If this ever actually becomes a compilation option this test should # be changed. - assert sys.float_repr_style == "short" \ No newline at end of file + assert sys.float_repr_style == "short" diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ CPYTHON_VERSION = (2, 7, 1, "final", 42) #XXX # sync patchlevel.h CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (1, 5, 0, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (1, 6, 0, "dev", 1) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -21,6 +21,7 @@ 'RPyThreadAcquireLock', 'RPyThreadReleaseLock', 'RPyThreadYield', 'RPyThreadGetStackSize', 'RPyThreadSetStackSize', + 'RPyOpaqueDealloc_ThreadLock', 'RPyThreadAfterFork'] ) @@ -52,6 +53,9 @@ c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], rffi.INT, threadsafe=False) # may add in a global list +c_thread_lock_dealloc = llexternal('RPyOpaqueDealloc_ThreadLock', [TLOCKP], + lltype.Void, + threadsafe=True) c_thread_acquirelock = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT], rffi.INT, threadsafe=True) # release the GIL @@ -120,7 +124,7 @@ def __enter__(self): self.acquire(True) - + def __exit__(self, *args): self.release() @@ -156,6 +160,9 @@ return ll_lock def free_ll_lock(ll_lock): + c_thread_acquirelock(ll_lock, 0) + c_thread_releaselock(ll_lock) + c_thread_lock_dealloc(ll_lock) lltype.free(ll_lock, flavor='raw', track_allocation=False) def acquire_NOAUTO(ll_lock, flag): diff --git a/pypy/module/thread/test/test_import_lock.py b/pypy/module/thread/test/test_import_lock.py --- a/pypy/module/thread/test/test_import_lock.py +++ b/pypy/module/thread/test/test_import_lock.py @@ -66,6 +66,9 @@ def test_lock(self, space, monkeypatch): from pypy.module.imp.importing import getimportlock, importhook + # Force importing the module _file now + space.builtin.get('file') + # Monkeypatch the import lock and add a counter importlock = getimportlock(space) original_acquire = importlock.acquire_lock diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -431,12 +431,17 @@ return None assert isinstance(lifeline, WeakrefLifeline) return lifeline + getweakref._cannot_really_call_random_things_ = True def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline - assert (isinstance(weakreflifeline, WeakrefLifeline) or - weakreflifeline is None) + assert isinstance(weakreflifeline, WeakrefLifeline) self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + setweakref._cannot_really_call_random_things_ = True + + def delweakref(self): + self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + delweakref._cannot_really_call_random_things_ = True class ObjectMixin(object): _mixin_ = True diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -36,6 +36,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None class W_SetObject(W_BaseSetObject): from pypy.objspace.std.settype import set_typedef as typedef diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -171,7 +171,7 @@ obj = c.instantiate() assert obj.getweakref() is None obj.setweakref(space, lifeline1) - obj.setweakref(space, None) + obj.delweakref() diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -532,6 +532,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None # ____________________________________________________________ # Initialization of type objects diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -482,6 +482,13 @@ key[2:]) cache[key] = s_value + # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass) + try: + graph = self.bookkeeper.position_key[0] + graph.func._dont_reach_me_in_del_ = True + except (TypeError, AttributeError): + pass + return annmodel.s_None def annotate_hooks(self, **kwds_s): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -83,6 +83,9 @@ t, rtyper, fngraph = self.gengraph(fn, [int]) + # added by compute_result_annotation() + assert fn._dont_reach_me_in_del_ == True + def getargs(func): for graph in t.graphs: if getattr(graph, 'func', None) is func: diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py --- a/pypy/rpython/lltypesystem/rclass.py +++ b/pypy/rpython/lltypesystem/rclass.py @@ -400,6 +400,7 @@ assert len(s_func.descriptions) == 1 funcdesc, = s_func.descriptions graph = funcdesc.getuniquegraph() + self.check_graph_of_del_does_not_call_too_much(graph) FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void) destrptr = functionptr(FUNCTYPE, graph.name, graph=graph, diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,6 +34,13 @@ the GC in very small programs. Defaults to 8 times the nursery. + PYPY_GC_LOSTCARD If between two minor collections we see more than + 'PYPY_GC_LOSTCARD * length' writes to the same array, + then give up card marking and use the fast write + barrier instead. Defaults to 0.3333 for now. + Avoid values lower than 0.125: it is the growth + factor of list.append(). + PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -198,6 +205,9 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, + # See PYPY_GC_LOSTCARD. + "lost_card": 1.0 / 3.0, + # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -214,6 +224,7 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, + lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -235,6 +246,7 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 + self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -355,6 +367,10 @@ else: self.max_delta = 0.125 * env.get_total_memory() # + lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') + if lost_card > 0.0: + self.lost_card = lost_card + # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -649,7 +665,7 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only @@ -675,11 +691,15 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # (the loop is empty in C). - i = 0 - while i < cardheadersize: - llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) - i += 1 + # followed by a Signed (the loop is empty in C). + if cardheadersize > 0: + i = 0 + while i < cardheadersize - WORD: + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Char)) + i += 1 + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -903,14 +923,11 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # - size_gc_header = self.gcheaderbuilder.size_gc_header - p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: - p -= 1 - ll_assert(p.char[0] == '\x00', + i -= 1 + ll_assert(self.get_card(obj, i).char[0] == '\x00', "the card marker bits are not cleared") - i -= 1 # ---------- # Write barrier @@ -1008,6 +1025,8 @@ self.prebuilt_root_objects.append(addr_array) return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1025,10 +1044,6 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1057,6 +1072,8 @@ if not self.appears_to_be_young(newvalue): return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1069,10 +1086,6 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1090,11 +1103,36 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card(self, obj, byteindex): + def get_card_counter_addr(self, obj): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + return llarena.getfakearenaaddress(addr_byte) - WORD + def get_card(self, obj, byteindex): + return self.get_card_counter_addr(obj) + (~byteindex) + + def set_cards_flag(self, obj): + hdr = self.header(obj) + if hdr.tid & GCFLAG_CARDS_SET == 0: + # + # first time we set a card bit in this object + self.header(obj).tid |= GCFLAG_CARDS_SET + self.objects_with_cards_set.append(obj) + # + # initialize the counter with the array length and self.lost_card + typeid = self.get_type_id(obj) + offset_to_length = self.varsize_offset_to_length(typeid) + length = (obj + offset_to_length).signed[0] + counter = int(length * self.lost_card) + self.get_card_counter_addr(obj).signed[0] = counter + else: + # decrement the counter and if zero is reached, give up on + # card marking (up to the next collection). + addr = self.get_card_counter_addr(obj) + addr.signed[0] -= 1 + if addr.signed[0] < 0: + self.objects_pointing_to_young.append(obj) + hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1167,10 +1205,7 @@ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(dest_addr) - dest_hdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(dest_addr) # ---------- # Nursery collection @@ -1264,6 +1299,7 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) + p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1602,7 +1638,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 arena -= extra_words * WORD allocsize += extra_words * WORD # diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -525,6 +525,7 @@ def test_writebarrier_before_copy(self): from pypy.rpython.memory.gc import minimark largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 p_src = self.malloc(VAR, largeobj_size) p_dst = self.malloc(VAR, largeobj_size) # make them old @@ -564,6 +565,7 @@ from pypy.rpython.memory.gc import minimark tid = self.get_type_id(VAR) largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 addr_src = self.gc.external_malloc(tid, largeobj_size) addr_dst = self.gc.external_malloc(tid, largeobj_size) hdr_src = self.gc.header(addr_src) diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -374,6 +374,43 @@ def can_ll_be_null(self, s_value): return s_value.can_be_none() + def check_graph_of_del_does_not_call_too_much(self, graph): + # RPython-level __del__() methods should not do "too much". + # In the PyPy Python interpreter, they usually do simple things + # like file.__del__() closing the file descriptor; or if they + # want to do more like call an app-level __del__() method, they + # enqueue the object instead, and the actual call is done later. + # + # Here, as a quick way to check "not doing too much", we check + # that from no RPython-level __del__() method we can reach a + # JitDriver. + # + # XXX wrong complexity, but good enough because the set of + # reachable graphs should be small + callgraph = self.rtyper.annotator.translator.callgraph.values() + seen = {graph: None} + while True: + oldlength = len(seen) + for caller, callee in callgraph: + if caller in seen and callee not in seen: + func = getattr(callee, 'func', None) + if getattr(func, '_dont_reach_me_in_del_', False): + lst = [str(callee)] + g = caller + while g: + lst.append(str(g)) + g = seen.get(g) + lst.append('') + raise TyperError("the RPython-level __del__() method " + "in %r calls:%s" % ( + graph, '\n\t'.join(lst[::-1]))) + if getattr(func, '_cannot_really_call_random_things_', + False): + continue + seen[callee] = caller + if len(seen) == oldlength: + break + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops, classcallhop=None): diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -7,6 +7,7 @@ from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.rpython.error import TyperError from pypy.objspace.flow.model import summary class EmptyBase(object): @@ -1021,7 +1022,25 @@ assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] assert destrptra is not None assert destrptrb is not None - + + def test_del_forbidden(self): + class A(object): + def __del__(self): + self.foo() + def foo(self): + self.bar() + def bar(self): + pass + bar._dont_reach_me_in_del_ = True + def f(): + a = A() + a.foo() + a.bar() + t = TranslationContext() + t.buildannotator().build_types(f, []) + e = py.test.raises(TyperError, t.buildrtyper().specialize) + print e.value + def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int class FooBar(object): diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -231,7 +231,7 @@ const = self.const def fn(i): s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] - return s[i].startswith('o') + return s[i].startswith(const('o')) for i in range(10): res = self.interpret(fn, [i]) assert res == fn(i) @@ -251,7 +251,7 @@ const = self.const def fn(i): s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] - return s[i].endswith('e') + return s[i].endswith(const('e')) for i in range(10): res = self.interpret(fn, [i]) assert res == fn(i) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -337,8 +337,16 @@ addrs = {} for entry in extract_category(log, 'jit-backend-addr'): m = re.search('bootstrap ([\da-f]+)', entry) - name = entry[:entry.find('(') - 1] - addrs[int(m.group(1), 16)] = name + if not m: + # a bridge + m = re.search('has address ([\da-f]+)', entry) + addr = int(m.group(1), 16) + entry = entry.lower() + m = re.search('guard \d+', entry) + addrs[addr] = m.group(0) + else: + name = entry[:entry.find('(') - 1].lower() + addrs[int(m.group(1), 16)] = name dumps = {} for entry in extract_category(log, 'jit-backend-dump'): backend, _, dump, _ = entry.split("\n") @@ -353,7 +361,12 @@ nonstrict=True) loop = parser.parse() comm = loop.comment - name = comm[2:comm.find(':')-1] + comm = comm.lower() + if comm.startswith('# bridge'): + m = re.search('guard \d+', comm) + name = m.group(0) + else: + name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] parser.postprocess(loop, backend_tp=bname, backend_dump=dump, diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -214,3 +214,10 @@ _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) assert 'jge' in loops[0].operations[3].asm + +def test_import_log_2(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest2.log'))) + assert 'cmp' in loops[1].operations[1].asm + # bridge + assert 'cmp' in loops[3].operations[1].asm diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs --- a/pypy/translator/cli/src/pypylib.cs +++ b/pypy/translator/cli/src/pypylib.cs @@ -615,10 +615,28 @@ return s1.StartsWith(s2); } + public static bool ll_startswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[0] == c; + } + public static bool ll_endswith(string s1, string s2) { return s1.EndsWith(s2); } + + public static bool ll_endswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[s.Length - 1] == c; + } public static int ll_find(string s1, string s2, int start, int stop) { diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -791,6 +791,20 @@ return str.substring(start,start+cnt); } + public static boolean ll_startswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(0) == c; + } + + public static boolean ll_endswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(str.length() - 1) == c; + } + // ---------------------------------------------------------------------- // StringBuffer From noreply at buildbot.pypy.org Sat Jul 16 07:15:42 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 16 Jul 2011 07:15:42 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove a bunch of dead imports. Message-ID: <20110716051542.CD25D82962@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45655:add21ab2b28b Date: 2011-07-15 22:15 -0700 http://bitbucket.org/pypy/pypy/changeset/add21ab2b28b/ Log: Remove a bunch of dead imports. diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py --- a/pypy/module/__builtin__/compiling.py +++ b/pypy/module/__builtin__/compiling.py @@ -5,7 +5,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError from pypy.interpreter.astcompiler import consts, ast -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec @unwrap_spec(filename=str, mode=str, flags=int, dont_inherit=int) def compile(space, w_source, filename, mode, flags=0, dont_inherit=0): diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py --- a/pypy/module/__builtin__/descriptor.py +++ b/pypy/module/__builtin__/descriptor.py @@ -1,12 +1,9 @@ - -from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.descroperation import object_getattribute, object_setattr -from pypy.interpreter.function import StaticMethod, ClassMethod -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \ - descr_set_dict, interp_attrproperty_w, generic_new_descr +from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w, + generic_new_descr) +from pypy.objspace.descroperation import object_getattribute class W_Super(Wrappable): def __init__(self, space, w_starttype, w_objtype, w_self): diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -4,13 +4,12 @@ """ from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import NoneNotWrapped, applevel +from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.objectmodel import specialize -from inspect import getsource, getfile from pypy.rlib.rbigint import rbigint @@ -662,7 +661,6 @@ def descr_reduce(self): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns space = self.space w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -1,11 +1,9 @@ import new from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import NoneNotWrapped, applevel, interp2app +from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict -from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, descr_set_dict from pypy.rlib.objectmodel import compute_identity_hash from pypy.rlib.debug import make_sure_not_resized from pypy.rlib import jit diff --git a/pypy/module/__builtin__/interp_memoryview.py b/pypy/module/__builtin__/interp_memoryview.py --- a/pypy/module/__builtin__/interp_memoryview.py +++ b/pypy/module/__builtin__/interp_memoryview.py @@ -2,7 +2,7 @@ Implementation of the 'buffer' and 'memoryview' types. """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter import gateway, buffer +from pypy.interpreter import buffer from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -4,12 +4,10 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.runicode import UNICHR from pypy.rlib.rfloat import isnan, isinf, round_double from pypy.rlib import rfloat -import math import __builtin__ NoneNotWrapped = gateway.NoneNotWrapped diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,5 +1,4 @@ -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib import debug, jit diff --git a/pypy/module/__pypy__/interp_identitydict.py b/pypy/module/__pypy__/interp_identitydict.py --- a/pypy/module/__pypy__/interp_identitydict.py +++ b/pypy/module/__pypy__/interp_identitydict.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app from pypy.interpreter.baseobjspace import Wrappable class W_IdentityDict(Wrappable): diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.objectmodel import we_are_translated class CodecState(object): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -1,9 +1,8 @@ -import sys -from pypy.interpreter.baseobjspace import Wrappable, Arguments +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, \ operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi @@ -16,7 +15,7 @@ class W_FFIType(Wrappable): _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to'] - + def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None): self.name = name self.ffitype = ffitype @@ -83,7 +82,6 @@ def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P types = [ # note: most of the type name directly come from the C equivalent, # with the exception of bytes: in C, ubyte and char are equivalent, @@ -161,7 +159,7 @@ class W_FuncPtr(Wrappable): _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype'] - + def __init__(self, func, argtypes_w, w_restype): self.func = func self.argtypes_w = argtypes_w @@ -207,7 +205,7 @@ argchain.arg_singlefloat(space.float_w(w_arg)) elif w_argtype.is_struct(): # arg_raw directly takes value to put inside ll_args - w_arg = space.interp_w(W_StructureInstance, w_arg) + w_arg = space.interp_w(W_StructureInstance, w_arg) ptrval = w_arg.ll_buffer argchain.arg_raw(ptrval) else: @@ -404,7 +402,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + return W_FuncPtr(func, argtypes_w, w_restype) @unwrap_spec(name=str) diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,12 +3,10 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.gateway import ObjSpace from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -import os def wrap_streamerror(space, e, w_filename=None): if isinstance(e, streamio.StreamError): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -4,7 +4,6 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.buffer import RWBuffer -from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstring import StringBuilder from pypy.rlib.rarithmetic import r_longlong, intmask from pypy.tool.sourcetools import func_renamer diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py --- a/pypy/module/_io/interp_fileio.py +++ b/pypy/module/_io/interp_fileio.py @@ -1,5 +1,4 @@ -from pypy.interpreter.typedef import ( - TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty) +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 from pypy.rlib.rarithmetic import r_longlong diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -6,7 +6,6 @@ TypeDef, interp_attrproperty, generic_new_descr) from pypy.module.exceptions.interp_exceptions import W_IOError from pypy.module._io.interp_fileio import W_FileIO -from pypy.module._io.interp_iobase import W_IOBase from pypy.module._io.interp_textio import W_TextIOWrapper from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -4,7 +4,7 @@ generic_new_descr) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint from pypy.rlib.rbigint import rbigint from pypy.rlib.rstring import UnicodeBuilder diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py --- a/pypy/module/_locale/interp_locale.py +++ b/pypy/module/_locale/interp_locale.py @@ -1,4 +1,3 @@ -from pypy.rpython.tool import rffi_platform as platform from pypy.rlib import rposix from pypy.rlib.rarithmetic import intmask diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -2,12 +2,10 @@ """ The ffi for rpython, need to be imported for side effects """ -import sys from pypy.rpython.lltypesystem import rffi from pypy.rpython.lltypesystem import lltype from pypy.rpython.tool import rffi_platform from pypy.rpython.extfunc import register_external -from pypy.rpython.extregistry import ExtRegistryEntry from pypy.module._minimal_curses import interp_curses from pypy.translator.tool.cbuild import ExternalCompilationInfo @@ -82,7 +80,7 @@ return res finally: rffi.free_charp(ll_cap) - + register_external(interp_curses._curses_tigetstr, [str], str, export_name='_curses.tigetstr', llimpl=tigetstr_llimpl) diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -1,4 +1,4 @@ -import py, sys +import py from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -4,7 +4,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import ( OperationError, wrap_oserror, operationerrfmt) -from pypy.rpython.lltypesystem import rffi, lltype, llmemory +from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll import sys diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -15,7 +15,6 @@ if sys.platform == 'win32': from pypy.rlib import rwin32 - from pypy.interpreter.error import wrap_windowserror from pypy.module._multiprocessing.interp_win32 import ( handle_w, _GetTickCount) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -1,4 +1,4 @@ -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError from pypy.interpreter.nestedscope import Cell from pypy.interpreter.pycode import PyCode from pypy.interpreter.function import Function, Method @@ -8,7 +8,6 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec -from pypy.objspace.std.dicttype import dictiter_typedef from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject @@ -79,7 +78,7 @@ try: return gateway.BuiltinCode.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin code: "+ identifier)) @@ -89,7 +88,7 @@ try: return function.Function.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin function: "+ identifier)) diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,10 +2,10 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rpython.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import get_elem, push_elem +from pypy.module._rawffi.array import push_elem from pypy.module._rawffi.structure import W_Structure -from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \ - wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes +from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, + unwrap_value, unpack_argshapes) from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL from pypy.rlib.clibffi import ffi_type_void from pypy.rlib import rweakref diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -1,7 +1,6 @@ -import sys from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib.clibffi import * @@ -15,7 +14,7 @@ from pypy.rlib import rwin32 from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.tracker import tracker TYPEMAP = { diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py --- a/pypy/module/_socket/interp_func.py +++ b/pypy/module/_socket/interp_func.py @@ -1,9 +1,8 @@ -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._socket.interp_socket import converted_error, W_RSocket from pypy.rlib import rsocket from pypy.rlib.rsocket import SocketError -from pypy.rlib.rarithmetic import r_uint -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError def gethostname(space): """gethostname() -> string diff --git a/pypy/module/_sre/interp_sre.py b/pypy/module/_sre/interp_sre.py --- a/pypy/module/_sre/interp_sre.py +++ b/pypy/module/_sre/interp_sre.py @@ -14,7 +14,7 @@ # Constants and exposed functions from pypy.rlib.rsre import rsre_core -from pypy.rlib.rsre.rsre_char import MAGIC, CODESIZE, getlower, set_unicode_db +from pypy.rlib.rsre.rsre_char import CODESIZE, getlower, set_unicode_db @unwrap_spec(char_ord=int, flags=int) def w_getlower(space, char_ord, flags): diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,7 +1,7 @@ from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError -from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -11,7 +11,6 @@ from pypy.module._socket import interp_socket -import sys ## user defined constants X509_NAME_MAXLEN = 256 @@ -131,13 +130,13 @@ self._issuer = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN, flavor='raw') self._issuer[0] = '\0' self.shutdown_seen_zero = False - + def server(self): return self.space.wrap(rffi.charp2str(self._server)) - + def issuer(self): return self.space.wrap(rffi.charp2str(self._issuer)) - + def __del__(self): if self.peer_cert: libssl_X509_free(self.peer_cert) @@ -147,7 +146,7 @@ libssl_SSL_CTX_free(self.ctx) lltype.free(self._server, flavor='raw') lltype.free(self._issuer, flavor='raw') - + @unwrap_spec(data='bufferstr') def write(self, data): """write(s) -> len @@ -230,10 +229,10 @@ raw_buf, gc_buf = rffi.alloc_buffer(num_bytes) while True: err = 0 - + count = libssl_SSL_read(self.ssl, raw_buf, num_bytes) err = libssl_SSL_get_error(self.ssl, count) - + if err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout(self.space, self.w_socket, False) @@ -245,17 +244,17 @@ return self.space.wrap("") else: sockstate = SOCKET_OPERATION_OK - + if sockstate == SOCKET_HAS_TIMED_OUT: raise ssl_error(self.space, "The read operation timed out") elif sockstate == SOCKET_IS_NONBLOCKING: break - + if err == SSL_ERROR_WANT_READ or err == SSL_ERROR_WANT_WRITE: continue else: break - + if count <= 0: raise _ssl_seterror(self.space, self, count) @@ -351,7 +350,7 @@ self.shutdown_seen_zero = True continue - # Possibly retry shutdown until timeout or failure + # Possibly retry shutdown until timeout or failure ssl_err = libssl_SSL_get_error(self.ssl, ret) if ssl_err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout( @@ -397,7 +396,7 @@ else: w_proto = space.w_None - bits = libssl_SSL_CIPHER_get_bits(current, + bits = libssl_SSL_CIPHER_get_bits(current, lltype.nullptr(rffi.INTP.TO)) w_bits = space.newint(bits) @@ -552,7 +551,7 @@ ext = libssl_X509_get_ext(certificate, i) method = libssl_X509V3_EXT_get(ext) if not method: - raise ssl_error(space, + raise ssl_error(space, "No method for internalizing subjectAltName!'") with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr: @@ -858,7 +857,7 @@ cert = libssl_BIO_new(libssl_BIO_s_file()) if not cert: raise ssl_error(space, "Can't malloc memory to read file") - + try: if libssl_BIO_read_filename(cert, filename) <= 0: raise ssl_error(space, "Can't open file") @@ -873,7 +872,7 @@ libssl_X509_free(x) finally: libssl_BIO_free(cert) - + # this function is needed to perform locking on shared data # structures. (Note that OpenSSL uses a number of global data # structures that will be implicitly shared whenever multiple threads diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -15,13 +15,10 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import StaticMethod from pypy.module._stackless.stackless_flags import StacklessFlags from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit @@ -38,7 +35,7 @@ self.costate = costate if not space.is_true(space.callable(w_obj)): raise operationerrfmt( - space.w_TypeError, + space.w_TypeError, "'%s' object is not callable", space.type(w_obj).getname(space)) self.w_func = w_obj @@ -65,7 +62,7 @@ # Should be moved to interp_stackless.py if it's ever implemented... Currently # used by pypy/lib/stackless.py. -W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, +W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, """Tasklet killed manually.""") class AppCoroutine(Coroutine): # XXX, StacklessFlags): @@ -90,7 +87,7 @@ def _get_state(space): return space.fromcache(AppCoState) _get_state = staticmethod(_get_state) - + def w_bind(self, w_func, __args__): space = self.space if self.frame is not None: @@ -127,7 +124,7 @@ w_excvalue = operror.get_w_value(space) w_exctraceback = operror.get_traceback() w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback]) - + if w_exctype is self.costate.w_CoroutineExit: self.coroutine_exit = True else: @@ -146,22 +143,22 @@ def w_kill(self): self.kill() - + def w_throw(self, w_type, w_value=None, w_traceback=None): space = self.space operror = OperationError(w_type, w_value) operror.normalize_exception(space) - + if not space.is_w(w_traceback, space.w_None): from pypy.interpreter import pytraceback tb = space.interpclass_w(w_traceback) - if tb is None or not space.is_true(space.isinstance(tb, + if tb is None or not space.is_true(space.isinstance(tb, space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) operror.set_traceback(tb) - + self._kill(operror) def _userdel(self): @@ -280,7 +277,7 @@ assert isinstance(w_klass, W_TypeObject) old_flag = w_klass.flag_heaptype w_klass.flag_heaptype = True - + space.appexec([w_klass, space.wrap(funcname)], """ (klass, funcname): func = getattr(klass, funcname) @@ -332,23 +329,23 @@ # Exporting new exception to space self.w_CoroutineExit = space.gettypefor(W_CoroutineExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('CoroutineExit'), - self.w_CoroutineExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('CoroutineExit'), + space.exceptions_module.w_dict, + space.new_interned_str('CoroutineExit'), self.w_CoroutineExit) - + space.setitem(space.builtin.w_dict, + space.new_interned_str('CoroutineExit'), + self.w_CoroutineExit) + # Should be moved to interp_stackless.py if it's ever implemented... self.w_TaskletExit = space.gettypefor(W_TaskletExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - + space.exceptions_module.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + space.setitem(space.builtin.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + def post_install(self): self.current = self.main = AppCoroutine(self.space, state=self) self.main.subctx.clear_framestack() # wack @@ -378,7 +375,7 @@ instr = frame.last_instr opcode = ord(code[instr]) map = pythonopcode.opmap - call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], + call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] assert opcode in call_ops instr += 1 diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py --- a/pypy/module/_stackless/interp_stackless.py +++ b/pypy/module/_stackless/interp_stackless.py @@ -1,9 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError -from pypy.rlib.rarithmetic import intmask import os diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py --- a/pypy/module/_stackless/rclonable.py +++ b/pypy/module/_stackless/rclonable.py @@ -1,7 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.rlib.objectmodel import we_are_translated -from pypy.interpreter.error import OperationError class InterpClonableMixin: @@ -76,7 +75,7 @@ if not isinstance(current, InterpClonableCoroutine): raise RuntimeError("fork() in a non-clonable coroutine") thunk = ForkThunk(current) - coro_fork = InterpClonableCoroutine() + coro_fork = InterpClonableCoroutine() coro_fork.bind(thunk) coro_fork.switch() # we resume here twice. The following would need explanations about diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,9 +1,8 @@ import py -from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.interpreter.typedef import GetSetProperty, TypeDef +from pypy.interpreter.typedef import TypeDef from pypy.rlib import jit import weakref diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -1,6 +1,5 @@ from __future__ import with_statement from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError, wrap_windowserror diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,10 +1,9 @@ from __future__ import with_statement -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object from pypy.objspace.std.multimethod import FailedToImplement diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -4,9 +4,8 @@ from pypy.rpython.lltypesystem import lltype from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.rlib.streamio import Stream from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform as compiler @@ -67,7 +66,7 @@ 'BZ_OUTBUFF_FULL', 'BZ_CONFIG_ERROR'] for name in constant_names: setattr(CConfig, name, platform.DefinedConstantInteger(name)) - + class cConfig(object): pass for k, v in platform.configure(CConfig).items(): @@ -100,7 +99,7 @@ SMALLCHUNK = 8192 else: SMALLCHUNK = BUFSIZ - + if rffi.sizeof(rffi.INT) > 4: BIGCHUNK = 512 * 32 else: @@ -505,7 +504,7 @@ self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self._init_bz2comp(compresslevel) - + def _init_bz2comp(self, compresslevel): if compresslevel < 1 or compresslevel > 9: raise OperationError(self.space.w_ValueError, @@ -514,13 +513,13 @@ bzerror = intmask(BZ2_bzCompressInit(self.bzs, compresslevel, 0, 0)) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzCompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') - + @unwrap_spec(data='bufferstr') def compress(self, data): """compress(data) -> string @@ -529,12 +528,12 @@ compressed data whenever possible. When you've finished providing data to compress, call the flush() method to finish the compression process, and return what is left in the internal buffers.""" - + datasize = len(data) - + if datasize == 0: return self.space.wrap("") - + if not self.running: raise OperationError(self.space.w_ValueError, self.space.wrap("this object was already flushed")) @@ -562,7 +561,7 @@ res = out.make_result_string() return self.space.wrap(res) - + def flush(self): if not self.running: raise OperationError(self.space.w_ValueError, @@ -576,7 +575,7 @@ break elif bzerror != BZ_FINISH_OK: _catch_bz2_error(self.space, bzerror) - + if rffi.getintfield(self.bzs, 'c_avail_out') == 0: out.prepare_next_chunk() @@ -603,23 +602,23 @@ Create a new decompressor object. This object may be used to decompress data sequentially. If you want to decompress data in one shot, use the decompress() function instead.""" - + def __init__(self, space): self.space = space self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self.unused_data = "" - + self._init_bz2decomp() - + def _init_bz2decomp(self): bzerror = BZ2_bzDecompressInit(self.bzs, 0, 0) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzDecompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') @@ -687,7 +686,7 @@ Compress data in one shot. If you want to compress data sequentially, use an instance of BZ2Compressor instead. The compresslevel parameter, if given, must be a number between 1 and 9.""" - + if compresslevel < 1 or compresslevel > 9: raise OperationError(space.w_ValueError, space.wrap("compresslevel must be between 1 and 9")) @@ -731,7 +730,7 @@ Decompress data in one shot. If you want to decompress data sequentially, use an instance of BZ2Decompressor instead.""" - + in_bufsize = len(data) if in_bufsize == 0: return space.wrap("") diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -1,4 +1,3 @@ -import sys from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py --- a/pypy/module/cmath/interp_cmath.py +++ b/pypy/module/cmath/interp_cmath.py @@ -5,7 +5,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import NoneNotWrapped -from pypy.module.cmath import Module, names_and_docstrings +from pypy.module.cmath import names_and_docstrings from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG from pypy.module.cmath.constant import M_LN2, M_LN10 diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py --- a/pypy/module/cpyext/cdatetime.py +++ b/pypy/module/cpyext/cdatetime.py @@ -1,8 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib.objectmodel import we_are_translated -from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef -from pypy.module.cpyext.api import ( - cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields) +from pypy.module.cpyext.pyobject import PyObject, make_ref +from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct, + PyObjectFields) from pypy.module.cpyext.import_ import PyImport_Import from pypy.module.cpyext.typeobject import PyTypeObjectPtr from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py --- a/pypy/module/cpyext/complexobject.py +++ b/pypy/module/cpyext/complexobject.py @@ -1,7 +1,6 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.module.cpyext.api import ( cpython_api, cpython_struct, PyObject, build_type_checkers) -from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.floatobject import PyFloat_AsDouble from pypy.objspace.std.complexobject import W_ComplexObject from pypy.interpreter.error import OperationError diff --git a/pypy/module/crypt/interp_crypt.py b/pypy/module/crypt/interp_crypt.py --- a/pypy/module/crypt/interp_crypt.py +++ b/pypy/module/crypt/interp_crypt.py @@ -1,6 +1,5 @@ -from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.rpython.lltypesystem import rffi, lltype +from pypy.rpython.lltypesystem import rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo import sys @@ -22,4 +21,4 @@ if not res: return space.w_None str_res = rffi.charp2str(res) - return space.wrap(str_res) + return space.wrap(str_res) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -73,9 +73,8 @@ """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w,\ - GetSetProperty, interp_attrproperty, descr_get_dict, descr_set_dict,\ - descr_del_dict +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict, + descr_set_dict, descr_del_dict) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError from pypy.rlib import rwin32 diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -11,9 +11,8 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.eval import Code from pypy.interpreter.pycode import PyCode -from pypy.rlib import streamio, jit, rposix +from pypy.rlib import streamio, jit from pypy.rlib.streamio import StreamErrors -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -3,9 +3,9 @@ from pypy.rlib import streamio from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.module import Module -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import struct + def get_suffixes(space): w = space.wrap diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,7 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.rarithmetic import ovfcheck class W_Count(Wrappable): @@ -87,7 +86,7 @@ def __init__(self, space, w_obj, w_times): self.space = space self.w_obj = w_obj - + if space.is_w(w_times, space.w_None): self.counting = False self.count = 0 @@ -181,7 +180,7 @@ long as the predicate is true. Equivalent to : - + def takewhile(predicate, iterable): for x in iterable: if predicate(x): @@ -316,7 +315,7 @@ None, return the items that are false. Equivalent to : - + def ifilterfalse(predicate, iterable): if predicate is None: predicate = bool @@ -570,7 +569,7 @@ yield tuple(args) else: yield function(*args) - + """) @@ -728,9 +727,9 @@ __doc__ = """Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely. - + Equivalent to : - + def cycle(iterable): saved = [] for element in iterable: @@ -738,7 +737,7 @@ saved.append(element) while saved: for element in saved: - yield element + yield element """) class W_StarMap(Wrappable): @@ -778,7 +777,7 @@ def starmap(function, iterable): iterable = iter(iterable) while True: - yield function(*iterable.next()) + yield function(*iterable.next()) """) @@ -788,15 +787,15 @@ Note : once tee() has made a split, the original iterable should not be used anywhere else; otherwise, the iterable could get advanced without the tee objects being informed. - + Note : this member of the toolkit may require significant auxiliary storage (depending on how much temporary data needs to be stored). In general, if one iterator is going to use most or all of the data before the other iterator, it is faster to use list() instead of tee() - + Equivalent to : - + def tee(iterable, n=2): def gen(next, data={}, cnt=[0]): for i in count(): @@ -888,7 +887,7 @@ self.exhausted = False self.started = False # new_group - new group not started yet, next should not skip any items - self.new_group = True + self.new_group = True self.w_lookahead = self.space.w_None self.w_key = self.space.w_None diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -1,10 +1,8 @@ -from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask from pypy.rlib import rstackovf from pypy.module._file.interp_file import W_File -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import sys + Py_MARSHAL_VERSION = 2 diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,4 +1,4 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,7 +1,7 @@ import math -from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array +from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, + convert_to_array) from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py --- a/pypy/module/mmap/interp_mmap.py +++ b/pypy/module/mmap/interp_mmap.py @@ -1,21 +1,16 @@ -from pypy.rpython.tool import rffi_platform -from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped from pypy.rlib import rmmap from pypy.rlib.rmmap import RValueError, RTypeError, ROverflowError -import sys -import os -import platform -import stat + class W_MMap(Wrappable): def __init__(self, space, mmap_obj): self.space = space self.mmap = mmap_obj - + def close(self): self.mmap.close() diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -15,7 +15,6 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap -from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant from pypy.jit.metainterp.resoperation import rop from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes @@ -66,7 +65,7 @@ def on_compile(self, logger, looptoken, operations, type, next_instr, is_being_profiled, ll_pycode): from pypy.rpython.annlowlevel import cast_base_ptr_to_instance - + space = self.space cache = space.fromcache(Cache) if cache.in_recursion: @@ -170,7 +169,7 @@ # ____________________________________________________________ # -# Public interface +# Public interface def set_param(space, __args__): '''Configure the tunable JIT parameters. @@ -212,7 +211,7 @@ class Cache(object): in_recursion = False - + def __init__(self, space): self.w_compile_hook = space.w_None diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -1,9 +1,9 @@ from pypy.interpreter.typedef import TypeDef, interp_attrproperty -from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import unwrap_spec, interp2app from pypy.interpreter.pycode import PyCode -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.lltypesystem.rclass import OBJECT diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py --- a/pypy/module/rctime/interp_time.py +++ b/pypy/module/rctime/interp_time.py @@ -6,7 +6,6 @@ from pypy.rlib.rarithmetic import ovfcheck_float_to_int from pypy.rlib import rposix from pypy.translator.tool.cbuild import ExternalCompilationInfo -import math import os import sys import time as pytime @@ -102,7 +101,7 @@ CLOCKS_PER_SEC = platform.ConstantInteger("CLOCKS_PER_SEC") clock_t = platform.SimpleType("clock_t", rffi.ULONG) has_gettimeofday = platform.Has('gettimeofday') - + if _POSIX: calling_conv = 'c' CConfig.timeval = platform.Struct("struct timeval", @@ -235,7 +234,7 @@ _set_module_object(space, "timezone", space.wrap(timezone)) _set_module_object(space, 'daylight', space.wrap(daylight)) - tzname_w = [space.wrap(tzname[0]), space.wrap(tzname[1])] + tzname_w = [space.wrap(tzname[0]), space.wrap(tzname[1])] _set_module_object(space, 'tzname', space.newtuple(tzname_w)) _set_module_object(space, 'altzone', space.wrap(altzone)) @@ -310,7 +309,7 @@ space.wrap((rffi.getintfield(t, 'c_tm_wday') + 6) % 7), # want monday == 0 space.wrap(rffi.getintfield(t, 'c_tm_yday') + 1), # want january, 1 == 1 space.wrap(rffi.getintfield(t, 'c_tm_isdst'))] - + w_struct_time = _get_module_object(space, 'struct_time') w_time_tuple = space.newtuple(time_tuple) return space.call_function(w_struct_time, w_time_tuple) @@ -330,7 +329,7 @@ tup_w = space.fixedview(w_tup) if len(tup_w) != 9: - raise operationerrfmt(space.w_TypeError, + raise operationerrfmt(space.w_TypeError, "argument must be sequence of " "length 9, not %d", len(tup_w)) @@ -359,7 +358,7 @@ w_accept2dyear = _get_module_object(space, "accept2dyear") accept2dyear = space.int_w(w_accept2dyear) - + if y < 1900: if not accept2dyear: raise OperationError(space.w_ValueError, @@ -392,7 +391,7 @@ Return the current time in seconds since the Epoch. Fractions of a second may be present if the system clock provides them.""" - + secs = pytime.time() return space.wrap(secs) @@ -420,7 +419,7 @@ not present, current time as returned by localtime() is used.""" seconds = _get_inttime(space, w_seconds) - + t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw') t_ref[0] = seconds p = c_ctime(t_ref) @@ -444,7 +443,7 @@ if not p: raise OperationError(space.w_ValueError, space.wrap("unconvertible time")) - + return space.wrap(rffi.charp2str(p)[:-1]) # get rid of new line def gmtime(space, w_seconds=None): @@ -462,7 +461,7 @@ t_ref[0] = seconds p = c_gmtime(t_ref) lltype.free(t_ref, flavor='raw') - + if not p: raise OperationError(space.w_ValueError, space.wrap(_get_error_msg())) return _tm_to_tuple(space, p) @@ -479,7 +478,7 @@ t_ref[0] = seconds p = c_localtime(t_ref) lltype.free(t_ref, flavor='raw') - + if not p: raise OperationError(space.w_ValueError, space.wrap(_get_error_msg())) return _tm_to_tuple(space, p) @@ -524,7 +523,7 @@ See the library reference manual for formatting codes. When the time tuple is not present, current time as returned by localtime() is used.""" buf_value = _gettmarg(space, w_tup) - + # Checks added to make sure strftime() does not crash Python by # indexing blindly into some array for a textual representation # by some bad index (fixes bug #897625). diff --git a/pypy/module/select/interp_select.py b/pypy/module/select/interp_select.py --- a/pypy/module/select/interp_select.py +++ b/pypy/module/select/interp_select.py @@ -1,9 +1,7 @@ -import math from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import ( - OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.rlib import rpoll import errno @@ -122,7 +120,7 @@ w_errortype = space.fromcache(Cache).w_error raise OperationError(w_errortype, space.newtuple([ space.wrap(s.errno), space.wrap(s.get_msg())])) - + return space.newtuple([ space.newlist([iwtd_d[i] for i in iwtd]), space.newlist([owtd_d[i] for i in owtd]), diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py --- a/pypy/module/struct/formatiterator.py +++ b/pypy/module/struct/formatiterator.py @@ -1,11 +1,10 @@ - from pypy.interpreter.error import OperationError from pypy.rlib.objectmodel import specialize from pypy.rlib.rstruct.error import StructError from pypy.rlib.rstruct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT -from pypy.rlib.rstruct.formatiterator import (FormatIterator, - CalcSizeFormatIterator) +from pypy.rlib.rstruct.formatiterator import FormatIterator + class PackFormatIterator(FormatIterator): diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py --- a/pypy/module/struct/interp_struct.py +++ b/pypy/module/struct/interp_struct.py @@ -1,9 +1,7 @@ from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError from pypy.rlib.rstruct.error import StructError -from pypy.module.struct.formatiterator import CalcSizeFormatIterator -from pypy.module.struct.formatiterator import PackFormatIterator -from pypy.module.struct.formatiterator import UnpackFormatIterator +from pypy.module.struct.formatiterator import (CalcSizeFormatIterator, + PackFormatIterator, UnpackFormatIterator) @unwrap_spec(format=str) diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -1,9 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype, llmemory -from pypy.rpython.tool import rffi_platform as platform from pypy.translator.tool.cbuild import ExternalCompilationInfo -import py, os -from pypy.rpython.extregistry import ExtRegistryEntry +import py from pypy.rlib import jit from pypy.rlib.debug import ll_assert from pypy.rlib.objectmodel import we_are_translated diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py --- a/pypy/module/thread/os_local.py +++ b/pypy/module/thread/os_local.py @@ -1,9 +1,7 @@ from pypy.module.thread import ll_thread as thread -from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp2app -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict +from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty, + descr_get_dict) class Local(Wrappable): diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py --- a/pypy/module/thread/os_thread.py +++ b/pypy/module/thread/os_thread.py @@ -6,7 +6,6 @@ from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import unwrap_spec, NoneNotWrapped, Arguments -from pypy.rlib.objectmodel import free_non_gc_object # Here are the steps performed to start a new thread: # @@ -167,14 +166,14 @@ when the function raises an unhandled exception; a stack trace will be printed unless the exception is SystemExit.""" setup_threads(space) - if not space.is_true(space.isinstance(w_args, space.w_tuple)): - raise OperationError(space.w_TypeError, - space.wrap("2nd arg must be a tuple")) - if w_kwargs is not None and not space.is_true(space.isinstance(w_kwargs, space.w_dict)): - raise OperationError(space.w_TypeError, - space.wrap("optional 3rd arg must be a dictionary")) + if not space.is_true(space.isinstance(w_args, space.w_tuple)): + raise OperationError(space.w_TypeError, + space.wrap("2nd arg must be a tuple")) + if w_kwargs is not None and not space.is_true(space.isinstance(w_kwargs, space.w_dict)): + raise OperationError(space.w_TypeError, + space.wrap("optional 3rd arg must be a dictionary")) if not space.is_true(space.callable(w_callable)): - raise OperationError(space.w_TypeError, + raise OperationError(space.w_TypeError, space.wrap("first arg must be callable")) args = Arguments.frompacked(space, w_args, w_kwargs) diff --git a/pypy/module/unicodedata/generate_unicodedb.py b/pypy/module/unicodedata/generate_unicodedb.py --- a/pypy/module/unicodedata/generate_unicodedb.py +++ b/pypy/module/unicodedata/generate_unicodedb.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -import pprint - MAXUNICODE = 0x10FFFF # the value of sys.maxunicode of wide Python builds MANDATORY_LINE_BREAKS = ["BK", "CR", "LF", "NL"] # line break categories @@ -66,16 +64,16 @@ self.upper = int(data[12], 16) self.lower = None if data[13]: - self.lower = int(data[13], 16) + self.lower = int(data[13], 16) self.title = None if data[14]: self.title = int(data[14], 16) - + def copy(self): uc = Unicodechar() uc.__dict__.update(self.__dict__) return uc - + def get_compat_decomposition(table, code): if not table[code].decomposition: return [code] @@ -177,13 +175,13 @@ for code in range(len(table)): if table[code] is None: table[code] = defaultChar - + extra_numeric = read_unihan(unihan_file) for code, value in extra_numeric.iteritems(): uc = table[code].copy() uc.numeric = value table[code] = uc - + # Compute full decompositions. for code in range(len(table)): get_canonical_decomposition(table, code) @@ -365,7 +363,7 @@ print >> outfile, '%r: %r,' % (code, name) print >> outfile, '}' - + print >> outfile, '_names_corrected = {' for name, code in sorted(base_mod._orig_names.iteritems()): if name not in names: @@ -389,7 +387,7 @@ print >> outfile, '%r: None,' % name print >> outfile, '}' - + def writeUnicodedata(version, table, outfile, base): if base: print >> outfile, 'import %s as base_mod' % base @@ -406,7 +404,7 @@ cjk_end = 0x9FBB write_character_names(outfile, table, base_mod) - + print >> outfile, ''' _cjk_prefix = "CJK UNIFIED IDEOGRAPH-" _hangul_prefix = 'HANGUL SYLLABLE ' @@ -496,7 +494,7 @@ v_code = vl_code %% len(_hangul_V) return ("HANGUL SYLLABLE " + _hangul_L[l_code] + _hangul_V[v_code] + _hangul_T[t_code]) - + if not base_mod: return lookup_charcode(code) else: @@ -522,7 +520,7 @@ digit[code] = table[code].digit if table[code].numeric is not None: numeric[code] = table[code].numeric - + writeDict(outfile, '_decimal', decimal, base_mod) writeDict(outfile, '_digit', digit, base_mod) writeDict(outfile, '_numeric', numeric, base_mod) @@ -662,11 +660,11 @@ ''' def main(): - import re, sys + import sys from optparse import OptionParser infile = None outfile = sys.stdout - + parser = OptionParser('Usage: %prog [options]') parser.add_option('--base', metavar='FILENAME', help='Base python version (for import)') parser.add_option('--output', metavar='OUTPUT_MODULE', help='Output module (implied py extension)') From noreply at buildbot.pypy.org Sat Jul 16 08:08:50 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 16 Jul 2011 08:08:50 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix translation (whoops). Message-ID: <20110716060850.7BA0082962@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45656:cfa96ceb9935 Date: 2011-07-15 23:08 -0700 http://bitbucket.org/pypy/pypy/changeset/cfa96ceb9935/ Log: Fix translation (whoops). diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,7 +3,7 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app From noreply at buildbot.pypy.org Sat Jul 16 08:32:03 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 16 Jul 2011 08:32:03 +0200 (CEST) Subject: [pypy-commit] pypy default: fix more stuff. Message-ID: <20110716063203.31EF682962@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45657:39ad5205b27a Date: 2011-07-15 23:31 -0700 http://bitbucket.org/pypy/pypy/changeset/39ad5205b27a/ Log: fix more stuff. diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py --- a/pypy/module/__builtin__/descriptor.py +++ b/pypy/module/__builtin__/descriptor.py @@ -1,5 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError +from pypy.interpreter.function import StaticMethod, ClassMethod from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w, generic_new_descr) diff --git a/pypy/module/_sre/interp_sre.py b/pypy/module/_sre/interp_sre.py --- a/pypy/module/_sre/interp_sre.py +++ b/pypy/module/_sre/interp_sre.py @@ -14,7 +14,7 @@ # Constants and exposed functions from pypy.rlib.rsre import rsre_core -from pypy.rlib.rsre.rsre_char import CODESIZE, getlower, set_unicode_db +from pypy.rlib.rsre.rsre_char import MAGIC, CODESIZE, getlower, set_unicode_db @unwrap_spec(char_ord=int, flags=int) def w_getlower(space, char_ord, flags): diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py --- a/pypy/module/struct/interp_struct.py +++ b/pypy/module/struct/interp_struct.py @@ -1,8 +1,7 @@ from pypy.interpreter.gateway import unwrap_spec +from pypy.module.struct.formatiterator import PackFormatIterator, UnpackFormatIterator from pypy.rlib.rstruct.error import StructError -from pypy.module.struct.formatiterator import (CalcSizeFormatIterator, - PackFormatIterator, UnpackFormatIterator) - +from pypy.rlib.rstruct.formatiterator import CalcSizeFormatIterator @unwrap_spec(format=str) def calcsize(space, format): From noreply at buildbot.pypy.org Sat Jul 16 10:28:44 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Sat, 16 Jul 2011 10:28:44 +0200 (CEST) Subject: [pypy-commit] benchmarks default: kill the symlink, and use a python hack to share the content of util.py in both directories Message-ID: <20110716082844.7BFE782962@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r122:8c862863e7fb Date: 2011-07-16 10:27 +0200 http://bitbucket.org/pypy/benchmarks/changeset/8c862863e7fb/ Log: kill the symlink, and use a python hack to share the content of util.py in both directories diff --git a/own/util.py b/own/util.py old mode 120000 new mode 100644 --- a/own/util.py +++ b/own/util.py @@ -1,1 +1,5 @@ -../unladen_swallow/performance/util.py \ No newline at end of file +import os.path + +root = os.path.abspath(os.path.join(__file__, '..', '..')) +util_py = os.path.join(root, 'unladen_swallow', 'performance', 'util.py') +execfile(util_py) From noreply at buildbot.pypy.org Sat Jul 16 11:40:23 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 11:40:23 +0200 (CEST) Subject: [pypy-commit] pypy faster-nested-scopes: fix flow space. needs a slightly annoying hack Message-ID: <20110716094023.E080682962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: faster-nested-scopes Changeset: r45658:c6b24da7b2b9 Date: 2011-07-16 11:33 +0200 http://bitbucket.org/pypy/pypy/changeset/c6b24da7b2b9/ Log: fix flow space. needs a slightly annoying hack diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -184,7 +184,7 @@ class FlowExecutionContext(ExecutionContext): - def __init__(self, space, code, globals, constargs={}, closure=None, + def __init__(self, space, code, globals, constargs={}, outer_func=None, name=None): ExecutionContext.__init__(self, space) self.code = code @@ -193,11 +193,11 @@ self.crnt_offset = -1 self.crnt_frame = None - if closure is None: + if outer_func and outer_func.closure: + self.closure = [nestedscope.Cell(Constant(value)) + for value in outer_func.closure] + else: self.closure = None - else: - self.closure = [nestedscope.Cell(Constant(value)) - for value in closure] frame = self.create_frame() formalargcount = code.getformalargcount() arg_list = [Variable() for i in range(formalargcount)] @@ -216,7 +216,7 @@ # while ignoring any operation like the creation of the locals dict self.recorder = [] frame = FlowSpaceFrame(self.space, self.code, - self.w_globals, self.closure) + self.w_globals, self) frame.last_instr = 0 return frame diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py --- a/pypy/objspace/flow/objspace.py +++ b/pypy/objspace/flow/objspace.py @@ -252,9 +252,9 @@ raise TypeError("%r is a generator" % (func,)) code = PyCode._from_code(self, code) if func.func_closure is None: - closure = None + cl = None else: - closure = [extract_cell_content(c) for c in func.func_closure] + cl = [extract_cell_content(c) for c in func.func_closure] # CallableFactory.pycall may add class_ to functions that are methods name = func.func_name class_ = getattr(func, 'class_', None) @@ -262,8 +262,10 @@ name = '%s.%s' % (class_.__name__, name) for c in "<>&!": name = name.replace(c, '_') + class outerfunc: # hack + closure = cl ec = flowcontext.FlowExecutionContext(self, code, func.func_globals, - constargs, closure, name) + constargs, outerfunc, name) graph = ec.graph graph.func = func # attach a signature and defaults to the graph From noreply at buildbot.pypy.org Sat Jul 16 11:50:01 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 11:50:01 +0200 (CEST) Subject: [pypy-commit] pypy faster-nested-scopes: fix cpyext Message-ID: <20110716095001.6D43782962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: faster-nested-scopes Changeset: r45659:5994465ca0d0 Date: 2011-07-16 11:49 +0200 http://bitbucket.org/pypy/pypy/changeset/5994465ca0d0/ Log: fix cpyext diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py --- a/pypy/module/cpyext/frameobject.py +++ b/pypy/module/cpyext/frameobject.py @@ -57,7 +57,7 @@ code = space.interp_w(PyCode, w_code) w_globals = from_ref(space, py_frame.c_f_globals) - frame = PyFrame(space, code, w_globals, closure=None) + frame = PyFrame(space, code, w_globals, outer_func=None) frame.f_lineno = py_frame.c_f_lineno w_obj = space.wrap(frame) track_reference(space, py_obj, w_obj) From noreply at buildbot.pypy.org Sat Jul 16 13:08:08 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 13:08:08 +0200 (CEST) Subject: [pypy-commit] pypy default: typo Message-ID: <20110716110808.B376882962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45660:0eee4b30304a Date: 2011-07-16 13:06 +0200 http://bitbucket.org/pypy/pypy/changeset/0eee4b30304a/ Log: typo diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2381,7 +2381,7 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? - def test_retrace_ending_up_retrazing_another_loop(self): + def test_retrace_ending_up_retracing_another_loop(self): myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) bytecode = "0+sI0+SI" From noreply at buildbot.pypy.org Sat Jul 16 13:29:05 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Sat, 16 Jul 2011 13:29:05 +0200 (CEST) Subject: [pypy-commit] benchmarks default: kill the waf benchmark; it's broken right now, and we decided that it's not interesting Message-ID: <20110716112905.0874982962@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r123:b3ba07245ff9 Date: 2011-07-16 13:28 +0200 http://bitbucket.org/pypy/benchmarks/changeset/b3ba07245ff9/ Log: kill the waf benchmark; it's broken right now, and we decided that it's not interesting diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -41,13 +41,12 @@ opts = { 'gcbench' : {'iteration_scaling' : .10}, - 'waf' : {'iteration_scaling' : .10}, 'bm_mako' : {'bm_env': {'PYTHONPATH': relative('lib/mako')}}, } for name in ['float', 'nbody_modified', 'meteor-contest', 'fannkuch', 'spectral-norm', 'chaos', 'telco', 'go', 'pyflate-fast', - 'raytrace-simple', 'crypto_pyaes', 'waf', 'bm_mako']: + 'raytrace-simple', 'crypto_pyaes', 'bm_mako']: _register_new_bm(name, name, globals(), **opts.get(name, {})) for name in ['names', 'iteration', 'tcp', 'pb']:#, 'web', 'accepts']: iteration_scaling = 1.0 diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Build.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Build.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Build.py +++ /dev/null @@ -1,707 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,errno,re,datetime,shutil -try:import cPickle -except:import pickle as cPickle -from waflib import Runner,TaskGen,Utils,ConfigSet,Task,Logs,Options,Context,Errors -import waflib.Node -CACHE_DIR='c4che' -CACHE_SUFFIX='_cache.py' -INSTALL=1337 -UNINSTALL=-1337 -SAVED_ATTRS='root node_deps raw_deps task_sigs'.split() -CFG_FILES='cfg_files' -POST_AT_ONCE=0 -POST_LAZY=1 -POST_BOTH=2 -class BuildContext(Context.Context): - '''executes the build''' - cmd='build' - variant='' - def __init__(self,**kw): - super(BuildContext,self).__init__(**kw) - self.top_dir=kw.get('top_dir',Context.top_dir) - self.run_dir=kw.get('run_dir',Context.run_dir) - self.post_mode=POST_AT_ONCE - self.out_dir=kw.get('out_dir',Context.out_dir) - self.cache_dir=kw.get('cache_dir',None) - if not self.cache_dir: - self.cache_dir=self.out_dir+os.sep+CACHE_DIR - self.all_envs={} - for v in'task_sigs node_deps raw_deps'.split(): - setattr(self,v,{}) - self.cache_dir_contents={} - self.task_gen_cache_names={} - self.launch_dir=Context.launch_dir - self.targets=Options.options.targets - self.keep=Options.options.keep - self.cache_global=Options.cache_global - self.nocache=Options.options.nocache - self.progress_bar=Options.options.progress_bar - self.deps_man=Utils.defaultdict(list) - self.current_group=0 - self.groups=[] - self.group_names={} - def get_variant_dir(self): - if not self.variant: - return self.out_dir - return os.path.join(self.out_dir,self.variant) - variant_dir=property(get_variant_dir,None) - def __call__(self,*k,**kw): - kw['bld']=self - ret=TaskGen.task_gen(*k,**kw) - self.task_gen_cache_names={} - self.add_to_group(ret,group=kw.get('group',None)) - return ret - def __copy__(self): - raise Errors.WafError('build contexts are not supposed to be copied') - def install_files(self,*k,**kw): - pass - def install_as(self,*k,**kw): - pass - def symlink_as(self,*k,**kw): - pass - def load_envs(self): - try: - lst=Utils.listdir(self.cache_dir) - except OSError ,e: - if e.errno==errno.ENOENT: - raise Errors.WafError('The project was not configured: run "waf configure" first!') - else: - raise - if not lst: - raise Errors.WafError('The cache directory is empty: reconfigure the project') - for fname in lst: - if fname.endswith(CACHE_SUFFIX): - env=ConfigSet.ConfigSet(os.path.join(self.cache_dir,fname)) - name=fname[:-len(CACHE_SUFFIX)] - self.all_envs[name]=env - for f in env[CFG_FILES]: - newnode=self.root.find_resource(f) - try: - h=Utils.h_file(newnode.abspath()) - except(IOError,AttributeError): - Logs.error('cannot find %r'%f) - h=Utils.SIG_NIL - newnode.sig=h - def init_dirs(self): - if not(os.path.isabs(self.top_dir)and os.path.isabs(self.out_dir)): - raise Errors.WafError('The project was not configured: run "waf configure" first!') - self.path=self.srcnode=self.root.find_dir(self.top_dir) - self.bldnode=self.root.make_node(self.variant_dir) - self.bldnode.mkdir() - def execute(self): - self.restore() - if not self.all_envs: - self.load_envs() - self.execute_build() - def execute_build(self): - Logs.info("Waf: Entering directory `%s'"%self.variant_dir) - self.recurse([self.run_dir]) - self.pre_build() - self.timer=Utils.Timer() - if Options.options.progress_bar: - sys.stderr.write(Logs.colors.cursor_off) - try: - self.compile() - finally: - if Options.options.progress_bar: - sys.stderr.write(Logs.colors.cursor_on) - print('') - Logs.info("Waf: Leaving directory `%s'"%self.variant_dir) - self.post_build() - def restore(self): - try: - env=ConfigSet.ConfigSet(os.path.join(self.cache_dir,'build.config.py')) - except(IOError,OSError): - pass - else: - if env['version']').ljust(cols) - msg=Utils.indicator%(left,bar,right) - return msg - def declare_chain(self,*k,**kw): - return TaskGen.declare_chain(*k,**kw) - def pre_build(self): - for m in getattr(self,'pre_funs',[]): - m(self) - def post_build(self): - for m in getattr(self,'post_funs',[]): - m(self) - def add_pre_fun(self,meth): - try: - self.pre_funs.append(meth) - except AttributeError: - self.pre_funs=[meth] - def add_post_fun(self,meth): - try: - self.post_funs.append(meth) - except AttributeError: - self.post_funs=[meth] - def get_group(self,x): - if not self.groups: - self.add_group() - if x is None: - return self.groups[self.current_group] - if x in self.group_names: - return self.group_names[x] - return self.groups[x] - def add_to_group(self,tgen,group=None): - assert(isinstance(tgen,TaskGen.task_gen)or isinstance(tgen,Task.TaskBase)) - tgen.bld=self - self.get_group(group).append(tgen) - def get_group_name(self,g): - if not isinstance(g,list): - g=self.groups[g] - for x in self.group_names: - if id(self.group_names[x])==id(g): - return x - return'' - def get_group_idx(self,tg): - se=id(tg) - for i in range(len(self.groups)): - for t in self.groups[i]: - if id(t)==se: - return i - return None - def add_group(self,name=None,move=True): - if name and name in self.group_names: - Logs.error('add_group: name %s already present'%name) - g=[] - self.group_names[name]=g - self.groups.append(g) - if move: - self.current_group=len(self.groups)-1 - def set_group(self,idx): - if isinstance(idx,str): - g=self.group_names[idx] - for i in range(len(self.groups)): - if id(g)==id(self.groups[i]): - self.current_group=i - else: - self.current_group=idx - def total(self): - total=0 - for group in self.groups: - for tg in group: - try: - total+=len(tg.tasks) - except AttributeError: - total+=1 - return total - def get_targets(self): - to_post=[] - min_grp=0 - for name in self.targets.split(','): - tg=self.get_tgen_by_name(name) - if not tg: - raise Errors.WafError('target %r does not exist'%name) - m=self.get_group_idx(tg) - if m>min_grp: - min_grp=m - to_post=[tg] - elif m==min_grp: - to_post.append(tg) - return(min_grp,to_post) - def post_group(self): - if self.targets=='*': - for tg in self.groups[self.cur]: - try: - f=tg.post - except AttributeError: - pass - else: - f() - elif self.targets: - if self.cur=st2.st_mtime and st1.st_size==st2.st_size: - Logs.info('- install %s (from %s)'%(tgt,srclbl)) - return False - Logs.info('+ install %s (from %s)'%(tgt,srclbl)) - try: - os.remove(tgt) - except OSError: - pass - try: - shutil.copy2(src,tgt) - os.chmod(tgt,chmod) - except IOError: - try: - os.stat(src) - except(OSError,IOError): - Logs.error('File %r does not exist'%src) - raise Errors.WafError('Could not install the file %r'%tgt) - def do_link(self,src,tgt): - d,_=os.path.split(tgt) - Utils.check_dir(d) - link=False - if not os.path.islink(tgt): - link=True - elif os.readlink(tgt)!=src: - link=True - if link: - try:os.remove(tgt) - except OSError:pass - Logs.info('+ symlink %s (to %s)'%(tgt,src)) - os.symlink(src,tgt) - else: - Logs.info('- symlink %s (to %s)'%(tgt,src)) - def run_task_now(self,tsk,postpone): - tsk.post() - if not postpone: - if tsk.runnable_status()==Task.ASK_LATER: - raise self.WafError('cannot post the task %r'%tsk) - tsk.run() - def install_files(self,dest,files,env=None,chmod=Utils.O644,relative_trick=False,cwd=None,add=True,postpone=True): - tsk=inst_task(env=env or self.env) - tsk.bld=self - tsk.path=cwd or self.path - tsk.chmod=chmod - if isinstance(files,waflib.Node.Node): - tsk.source=[files] - else: - tsk.source=Utils.to_list(files) - tsk.dest=dest - tsk.exec_task=tsk.exec_install_files - tsk.relative_trick=relative_trick - if add:self.add_to_group(tsk) - self.run_task_now(tsk,postpone) - return tsk - def install_as(self,dest,srcfile,env=None,chmod=Utils.O644,cwd=None,add=True,postpone=True): - tsk=inst_task(env=env or self.env) - tsk.bld=self - tsk.path=cwd or self.path - tsk.chmod=chmod - tsk.source=[srcfile] - tsk.dest=dest - tsk.exec_task=tsk.exec_install_as - if add:self.add_to_group(tsk) - self.run_task_now(tsk,postpone) - return tsk - def symlink_as(self,dest,src,env=None,cwd=None,add=True,postpone=True): - if sys.platform=='win32': - return - tsk=inst_task(env=env or self.env) - tsk.bld=self - tsk.dest=dest - tsk.path=cwd or self.path - tsk.source=[] - tsk.link=src - tsk.exec_task=tsk.exec_symlink_as - if add:self.add_to_group(tsk) - self.run_task_now(tsk,postpone) - return tsk -class UninstallContext(InstallContext): - '''removes the targets installed''' - cmd='uninstall' - def __init__(self,**kw): - super(UninstallContext,self).__init__(**kw) - self.is_install=UNINSTALL - def do_install(self,src,tgt,chmod=Utils.O644): - Logs.info('- remove %s'%tgt) - self.uninstall.append(tgt) - try: - os.remove(tgt) - except OSError ,e: - if e.errno!=errno.ENOENT: - if not getattr(self,'uninstall_error',None): - self.uninstall_error=True - Logs.warn('build: some files could not be uninstalled (retry with -vv to list them)') - if Logs.verbose>1: - Logs.warn('could not remove %s (error code %r)'%(e.filename,e.errno)) - while tgt: - tgt=os.path.dirname(tgt) - try: - os.rmdir(tgt) - except OSError: - break - def do_link(self,src,tgt): - try: - Logs.info('- unlink %s'%tgt) - os.remove(tgt) - except OSError: - pass - while tgt: - tgt=os.path.dirname(tgt) - try: - os.rmdir(tgt) - except OSError: - break - def execute(self): - try: - def runnable_status(self): - return Task.SKIP_ME - setattr(Task.Task,'runnable_status_back',Task.Task.runnable_status) - setattr(Task.Task,'runnable_status',runnable_status) - super(UninstallContext,self).execute() - finally: - setattr(Task.Task,'runnable_status',Task.Task.runnable_status_back) -class CleanContext(BuildContext): - '''cleans the project''' - cmd='clean' - def execute(self): - self.restore() - if not self.all_envs: - self.load_envs() - self.recurse([self.run_dir]) - try: - self.clean() - finally: - self.store() - def clean(self): - Logs.debug('build: clean called') - if self.bldnode!=self.srcnode: - lst=[self.root.find_or_declare(f)for f in self.env[CFG_FILES]] - for n in self.bldnode.ant_glob('**/*',excl='lock* *conf_check_*/** config.log c4che/*'): - if n in lst: - continue - n.delete() - self.root.children={} - for v in'node_deps task_sigs raw_deps'.split(): - setattr(self,v,{}) -class ListContext(BuildContext): - '''lists the targets to execute''' - cmd='list' - def execute(self): - self.restore() - if not self.all_envs: - self.load_envs() - self.recurse([self.run_dir]) - self.pre_build() - self.timer=Utils.Timer() - for g in self.groups: - for tg in g: - try: - f=tg.post - except AttributeError: - pass - else: - f() - try: - self.get_tgen_by_name('') - except: - pass - lst=list(self.task_gen_cache_names.keys()) - lst.sort() - for k in lst: - Logs.pprint('GREEN',k) -class StepContext(BuildContext): - '''executes tasks in a step-by-step fashion, for debugging''' - cmd='step' - def __init__(self,**kw): - super(StepContext,self).__init__(**kw) - self.files=Options.options.files - def compile(self): - if not self.files: - Logs.warn('Add a pattern for the debug build, for example "waf step --files=main.c,app"') - BuildContext.compile(self) - return - for g in self.groups: - for tg in g: - try: - f=tg.post - except AttributeError: - pass - else: - f() - for pat in self.files.split(','): - inn=True - out=True - if pat.startswith('in:'): - out=False - pat=pat.replace('in:','') - elif pat.startswith('out:'): - inn=False - pat=pat.replace('out:','') - pat=re.compile(pat,re.M) - for g in self.groups: - for tg in g: - if isinstance(tg,Task.TaskBase): - lst=[tg] - else: - lst=tg.tasks - for tsk in lst: - do_exec=False - if inn: - for node in getattr(tsk,'inputs',[]): - if pat.search(node.abspath()): - do_exec=True - break - if out and not do_exec: - for node in getattr(tsk,'outputs',[]): - if pat.search(node.abspath()): - do_exec=True - break - if do_exec: - ret=tsk.run() - Logs.info('%s -> %r'%(str(tsk),ret)) -BuildContext.store=Utils.nogc(BuildContext.store) -BuildContext.load=Utils.nogc(BuildContext.load) diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/ConfigSet.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/ConfigSet.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/ConfigSet.py +++ /dev/null @@ -1,145 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -if sys.hexversion < 0x020400f0: from sets import Set as set -import os,copy,re -from waflib import Logs,Utils -re_imp=re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$',re.M) -class ConfigSet(object): - __slots__=('table','parent') - def __init__(self,filename=None): - self.table={} - if filename: - self.load(filename) - def __contains__(self,key): - if key in self.table:return True - try:return self.parent.__contains__(key) - except AttributeError:return False - def __str__(self): - keys=set() - cur=self - while cur: - keys.update(cur.table.keys()) - cur=getattr(cur,'parent',None) - keys=list(keys) - keys.sort() - return"\n".join(["%r %r"%(x,self.__getitem__(x))for x in keys]) - def __getitem__(self,key): - try: - while 1: - x=self.table.get(key,None) - if not x is None: - return x - self=self.parent - except AttributeError: - return[] - def __setitem__(self,key,value): - self.table[key]=value - def __delitem__(self,key,value): - del self.table[key] - def __getattr__(self,name): - if name in self.__slots__: - return object.__getattr__(self,name) - else: - return self[name] - def __setattr__(self,name,value): - if name in self.__slots__: - object.__setattr__(self,name,value) - else: - self[name]=value - def __delattr__(self,name): - if name in self.__slots__: - object.__delattr__(self,name) - else: - del self[name] - def derive(self): - newenv=ConfigSet() - newenv.parent=self - return newenv - def detach(self): - tbl=self.get_merged_dict() - try: - delattr(self,'parent') - except AttributeError: - pass - else: - keys=tbl.keys() - for x in keys: - tbl[x]=copy.deepcopy(tbl[x]) - self.table=tbl - def get_flat(self,key): - s=self[key] - if isinstance(s,str):return s - return' '.join(s) - def _get_list_value_for_modification(self,key): - try: - value=self.table[key] - except KeyError: - try:value=self.parent[key] - except AttributeError:value=[] - if isinstance(value,list): - value=value[:] - else: - value=[value] - else: - if not isinstance(value,list): - value=[value] - self.table[key]=value - return value - def append_value(self,var,val): - current_value=self._get_list_value_for_modification(var) - if isinstance(val,str): - val=[val] - current_value.extend(val) - def prepend_value(self,var,val): - if isinstance(val,str): - val=[val] - self.table[var]=val+self._get_list_value_for_modification(var) - def append_unique(self,var,val): - if isinstance(val,str): - val=[val] - current_value=self._get_list_value_for_modification(var) - for x in val: - if x not in current_value: - current_value.append(x) - def get_merged_dict(self): - table_list=[] - env=self - while 1: - table_list.insert(0,env.table) - try:env=env.parent - except AttributeError:break - merged_table={} - for table in table_list: - merged_table.update(table) - return merged_table - def store(self,filename): - f=None - try: - f=open(filename,'w') - merged_table=self.get_merged_dict() - keys=list(merged_table.keys()) - keys.sort() - for k in keys: - if k!='undo_stack': - f.write('%s = %r\n'%(k,merged_table[k])) - finally: - if f: - f.close() - def load(self,filename): - tbl=self.table - code=Utils.readf(filename) - for m in re_imp.finditer(code): - g=m.group - tbl[g(2)]=eval(g(3)) - Logs.debug('env: %s'%str(self.table)) - def update(self,d): - for k,v in d.items(): - self[k]=v - def stash(self): - self.undo_stack=self.undo_stack+[self.table] - self.table=self.table.copy() - def revert(self): - self.table=self.undo_stack.pop(-1) diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Configure.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Configure.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Configure.py +++ /dev/null @@ -1,304 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,shlex,sys,time -from waflib import ConfigSet,Utils,Options,Logs,Context,Build,Errors -try: - from urllib import request -except: - from urllib import urlopen -else: - urlopen=request.urlopen -BREAK='break' -CONTINUE='continue' -WAF_CONFIG_LOG='config.log' -autoconfig=False -conf_template='''# project %(app)s configured on %(now)s by -# waf %(wafver)s (abi %(abi)s, python %(pyver)x on %(systype)s) -# using %(args)s -#''' -def download_check(node): - Logs.warn('replace me to check %r'%node) -def download_tool(tool,force=False): - for x in Utils.to_list(Context.remote_repo): - for sub in Utils.to_list(Context.remote_locs): - url='/'.join((x,sub,tool+'.py')) - try: - web=urlopen(url) - if web.getcode()!=200: - continue - except Exception ,e: - continue - else: - tmp=self.root.make_node(os.sep.join((Context.waf_dir,'waflib','extras',tool+'.py'))) - tmp.write(web.read()) - Logs.warn('downloaded %s from %s'%(tool,url)) - download_check(tmp) - try: - module=Context.load_tool(tool) - except: - Logs.warn('module %s from %s is unusable'%(tool,url)) - try: - tmp.delete() - except: - pass - continue - return module - else: - break - raise Errors.WafError('Could not load the Waf tool') -class ConfigurationContext(Context.Context): - '''configures the project''' - cmd='configure' - error_handlers=[] - def __init__(self,**kw): - super(self.__class__,self).__init__(**kw) - self.environ=dict(os.environ) - self.all_envs={} - self.top_dir=None - self.out_dir=None - self.tools=[] - self.hash=0 - self.files=[] - self.tool_cache=[] - self.setenv('') - def setenv(self,name,env=None): - if not env: - env=ConfigSet.ConfigSet() - self.prepare_env(env) - else: - env=env.derive() - self.all_envs[name]=env - self.variant=name - def get_env(self): - return self.all_envs[self.variant] - def set_env(self,val): - self.all_envs[self.variant]=val - env=property(get_env,set_env) - def init_dirs(self): - top=self.top_dir - if not top: - top=Options.options.top - if not top: - top=getattr(Context.g_module,Context.TOP,None) - if not top: - top=self.path.abspath() - top=os.path.abspath(top) - self.srcnode=(os.path.isabs(top)and self.root or self.path).find_dir(top) - assert(self.srcnode) - out=self.out_dir - if not out: - out=Options.options.out - if not out: - out=getattr(Context.g_module,Context.OUT,None) - if not out: - out=Options.lockfile.replace('.lock-waf','') - self.bldnode=(os.path.isabs(out)and self.root or self.path).make_node(out) - self.bldnode.mkdir() - if not os.path.isdir(self.bldnode.abspath()): - conf.fatal('could not create the build directory %s'%self.bldnode.abspath()) - def execute(self): - self.init_dirs() - self.cachedir=self.bldnode.make_node(Build.CACHE_DIR) - self.cachedir.mkdir() - path=os.path.join(self.bldnode.abspath(),WAF_CONFIG_LOG) - self.logger=Logs.make_logger(path,'cfg') - app=getattr(Context.g_module,'APPNAME','') - if app: - ver=getattr(Context.g_module,'VERSION','') - if ver: - app="%s (%s)"%(app,ver) - now=time.ctime() - pyver=sys.hexversion - systype=sys.platform - args=" ".join(sys.argv) - wafver=Context.WAFVERSION - abi=Context.ABI - self.to_log(conf_template%vars()) - self.msg('Setting top to',self.srcnode.abspath()) - self.msg('Setting out to',self.bldnode.abspath()) - if id(self.srcnode)==id(self.bldnode): - Logs.warn('setting top == out') - elif id(self.path)!=id(self.srcnode): - if self.srcnode.is_child_of(self.path): - Logs.warn('Using an uncommon top directory') - super(ConfigurationContext,self).execute() - self.store() - Context.top_dir=self.srcnode.abspath() - Context.out_dir=self.bldnode.abspath() - env=ConfigSet.ConfigSet() - env['argv']=sys.argv - env['options']=Options.options.__dict__ - env.run_dir=Context.run_dir - env.top_dir=Context.top_dir - env.out_dir=Context.out_dir - env['hash']=self.hash - env['files']=self.files - env['environ']=dict(self.environ) - env.store(Context.run_dir+os.sep+Options.lockfile) - env.store(Context.top_dir+os.sep+Options.lockfile) - env.store(Context.out_dir+os.sep+Options.lockfile) - def prepare_env(self,env): - if not env.PREFIX: - env.PREFIX=os.path.abspath(os.path.expanduser(Options.options.prefix)) - if not env.BINDIR: - env.BINDIR=Utils.subst_vars('${PREFIX}/bin',env) - if not env.LIBDIR: - env.LIBDIR=Utils.subst_vars('${PREFIX}/lib',env) - def store(self): - n=self.cachedir.make_node('build.config.py') - n.write('version = 0x%x\ntools = %r\n'%(Context.HEXVERSION,self.tools)) - if not self.all_envs: - self.fatal('nothing to store in the configuration context!') - for key in self.all_envs: - tmpenv=self.all_envs[key] - tmpenv.store(os.path.join(self.cachedir.abspath(),key+Build.CACHE_SUFFIX)) - def load(self,input,tooldir=None,funs=None,download=True): - tools=Utils.to_list(input) - if tooldir:tooldir=Utils.to_list(tooldir) - for tool in tools: - mag=(tool,id(self.env),funs) - if mag in self.tool_cache: - self.to_log('(tool %s is already loaded, skipping)'%tool) - continue - self.tool_cache.append(mag) - module=None - try: - module=Context.load_tool(tool,tooldir) - except ImportError ,e: - if Options.options.download: - module=download_tool(tool) - if not module: - self.fatal('Could not load the Waf tool %r or download a suitable replacement from the repository (sys.path %r)\n%s'%(tool,sys.path,e)) - else: - self.fatal('Could not load the Waf tool %r from %r (try the --download option?):\n%s'%(tool,sys.path,e)) - except Exception ,e: - self.to_log('imp %r (%r & %r)'%(tool,tooldir,funs)) - self.to_log(Utils.ex_stack()) - raise - if funs is not None: - self.eval_rules(funs) - else: - func=getattr(module,'configure',None) - if func: - if type(func)is type(Utils.readf):func(self) - else:self.eval_rules(func) - self.tools.append({'tool':tool,'tooldir':tooldir,'funs':funs}) - def post_recurse(self,node): - super(ConfigurationContext,self).post_recurse(node) - self.hash=hash((self.hash,node.read('rb'))) - self.files.append(node.abspath()) - def add_os_flags(self,var,dest=None): - try:self.env.append_value(dest or var,Utils.to_list(self.environ[var])) - except KeyError:pass - def cmd_to_list(self,cmd): - if isinstance(cmd,str)and cmd.find(' '): - try: - os.stat(cmd) - except OSError: - return shlex.split(cmd) - else: - return[cmd] - return cmd - def eval_rules(self,rules): - self.rules=Utils.to_list(rules) - for x in self.rules: - f=getattr(self,x) - if not f:self.fatal("No such method '%s'."%x) - try: - f() - except Exception ,e: - ret=self.err_handler(x,e) - if ret==BREAK: - break - elif ret==CONTINUE: - continue - else: - raise - def err_handler(self,fun,error): - pass -def conf(f): - def fun(*k,**kw): - mandatory=True - if'mandatory'in kw: - mandatory=kw['mandatory'] - del kw['mandatory'] - try: - return f(*k,**kw) - except Errors.ConfigurationError ,e: - if mandatory: - raise e - setattr(ConfigurationContext,f.__name__,fun) - setattr(Build.BuildContext,f.__name__,fun) - return f -def check_waf_version(self,mini='1.6.0',maxi='1.7.0'): - self.start_msg('Checking for waf version in %s-%s'%(str(mini),str(maxi))) - ver=Context.HEXVERSION - if Utils.num2ver(mini)>ver: - self.fatal('waf version should be at least %r (%r found)'%(Utils.num2ver(mini),ver)) - if Utils.num2ver(maxi) %r'%(filename,path_list,var,ret)) - if not ret: - self.fatal(kw.get('errmsg','')or'Could not find the program %s'%','.join(filename)) - if var: - self.env[var]=ret - return ret -def find_perl_program(self,filename,path_list=[],var=None,environ=None,exts=''): - try: - app=self.find_program(filename,path_list=path_list,var=var,environ=environ,exts=exts) - except: - perl=self.find_program('perl',var='PERL') - app=self.find_file(filename,os.environ['PATH'].split(os.pathsep)) - if not app: - raise - if var: - self.env[var]=Utils.to_list(self.env['PERL'])+[app] - self.msg('Checking for %r'%filename,app) - -conf(check_waf_version) -conf(find_file) -conf(find_program) -conf(find_perl_program) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Context.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Context.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Context.py +++ /dev/null @@ -1,276 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import traceback,os,imp,sys -from waflib import Utils,Errors,Logs -import waflib.Node -HEXVERSION=0x1060000 -WAFVERSION="1.6.0" -WAFREVISION="10085" -ABI=98 -DBFILE='.wafpickle-%d'%ABI -APPNAME='APPNAME' -VERSION='VERSION' -TOP='top' -OUT='out' -WSCRIPT_FILE='wscript' -launch_dir='' -run_dir='' -top_dir='' -out_dir='' -waf_dir='' -local_repo='' -remote_repo='http://waf.googlecode.com/svn/' -remote_locs=['branches/waf-%s/waflib/extras'%WAFVERSION,'trunk/waflib/extras'] -g_module=None -STDOUT=1 -STDERR=-1 -BOTH=0 -classes=[] -def create_context(cmd_name,*k,**kw): - global classes - for x in classes: - if x.cmd==cmd_name: - return x(*k,**kw) - ctx=Context(*k,**kw) - ctx.fun=cmd_name - return ctx -class store_context(type): - def __init__(cls,name,bases,dict): - super(store_context,cls).__init__(name,bases,dict) - name=cls.__name__ - if name=='ctx'or name=='Context': - return - try: - cls.cmd - except AttributeError: - raise Errors.WafError('Missing command for the context class %r (cmd)'%name) - if not getattr(cls,'fun',None): - cls.fun=cls.cmd - global classes - classes.insert(0,cls) -ctx=store_context('ctx',(object,),{}) -class Context(ctx): - errors=Errors - tools={} - def __init__(self,**kw): - try: - rd=kw['run_dir'] - except KeyError: - global run_dir - rd=run_dir - class node_class(waflib.Node.Node): - pass - self.node_class=node_class - self.node_class.__module__="waflib.Node" - self.node_class.__name__="Nod3" - self.node_class.ctx=self - self.root=self.node_class('',None) - self.cur_script=None - self.path=self.root.find_dir(rd) - self.stack_path=[] - self.exec_dict={'ctx':self,'conf':self,'bld':self,'opt':self} - self.logger=None - def __hash__(self): - return id(self) - def load(self,tool_list,*k,**kw): - tools=Utils.to_list(tool_list) - path=Utils.to_list(kw.get('tooldir','')) - for t in tools: - module=load_tool(t,path) - fun=getattr(module,self.fun,None) - if fun: - fun(self) - def execute(self): - global g_module - self.recurse([os.path.dirname(g_module.root_path)]) - def pre_recurse(self,node): - self.stack_path.append(self.cur_script) - self.cur_script=node - self.path=node.parent - def post_recurse(self,node): - self.cur_script=self.stack_path.pop() - if self.cur_script: - self.path=self.cur_script.parent - def recurse(self,dirs,name=None): - for d in Utils.to_list(dirs): - if not os.path.isabs(d): - d=os.path.join(self.path.abspath(),d) - WSCRIPT=os.path.join(d,WSCRIPT_FILE) - WSCRIPT_FUN=WSCRIPT+'_'+(name or self.fun) - node=self.root.find_node(WSCRIPT_FUN) - if node: - self.pre_recurse(node) - function_code=node.read('rU') - exec(compile(function_code,node.abspath(),'exec'),self.exec_dict) - self.post_recurse(node) - else: - node=self.root.find_node(WSCRIPT) - if not node: - raise Errors.WafError('No wscript file in directory %s'%d) - self.pre_recurse(node) - wscript_module=load_module(node.abspath()) - user_function=getattr(wscript_module,(name or self.fun),None) - if not user_function: - raise Errors.WafError('No function %s defined in %s'%(name or self.fun,node.abspath())) - user_function(self) - self.post_recurse(node) - def fatal(self,msg,ex=None): - if self.logger: - self.logger.info('from %s: %s'%(self.path.abspath(),msg)) - try: - msg='%s\n(complete log in %s)'%(msg,self.logger.handlers[0].baseFilename) - except: - pass - raise self.errors.ConfigurationError(msg,ex=ex) - def to_log(self,var): - if not var: - return - if self.logger: - self.logger.info(var.strip()) - else: - sys.stderr.write(str(var)) - def exec_command(self,cmd,**kw): - subprocess=Utils.subprocess - kw['shell']=isinstance(cmd,str) - Logs.debug('runner: %r'%cmd) - try: - if self.logger: - kw['stdout']=kw['stderr']=subprocess.PIPE - p=subprocess.Popen(cmd,**kw) - (out,err)=p.communicate() - if out: - self.logger.debug('out: %s'%out) - if err: - self.logger.error('err: %s'%err) - return p.returncode - else: - p=subprocess.Popen(cmd,**kw) - return p.wait() - except OSError: - return-1 - def cmd_and_log(self,cmd,**kw): - subprocess=Utils.subprocess - kw['shell']=isinstance(cmd,str) - Logs.debug('runner: %r'%cmd) - if'quiet'in kw: - quiet=kw['quiet'] - del kw['quiet'] - else: - quiet=None - if'output'in kw: - to_ret=kw['output'] - del kw['output'] - else: - to_ret=STDOUT - kw['stdout']=kw['stderr']=subprocess.PIPE - if not quiet: - self.to_log(cmd) - try: - p=subprocess.Popen(cmd,**kw) - (out,err)=p.communicate() - except Exception ,e: - try: - self.to_log(str(err)) - except: - pass - raise Errors.WafError('Execution failure',ex=e) - if not isinstance(out,str): - out=out - if not isinstance(err,str): - err=err - if out and quiet!=STDOUT and quiet!=BOTH: - self.to_log('out: %s'%out) - if err and quiet!=STDERR and quiet!=BOTH: - self.to_log('err: %s'%err) - if p.returncode: - e=Errors.WafError('command %r returned %r'%(cmd,p.returncode)) - e.returncode=p.returncode - raise e - if to_ret==BOTH: - return(out,err) - elif to_ret==STDERR: - return err - return out - def msg(self,msg,result,color=None): - self.start_msg(msg) - if not isinstance(color,str): - color=result and'GREEN'or'YELLOW' - self.end_msg(result,color) - def start_msg(self,msg): - try: - if self.in_msg: - self.in_msg+=1 - return - except: - self.in_msg=0 - self.in_msg+=1 - try: - self.line_just=max(self.line_just,len(msg)) - except AttributeError: - self.line_just=max(40,len(msg)) - for x in(self.line_just*'-',msg): - self.to_log(x) - Logs.pprint('NORMAL',"%s :"%msg.ljust(self.line_just),sep='') - def end_msg(self,result,color=None): - self.in_msg-=1 - if self.in_msg: - return - defcolor='GREEN' - if result==True: - msg='ok' - elif result==False: - msg='not found' - defcolor='YELLOW' - else: - msg=str(result) - self.to_log(msg) - Logs.pprint(color or defcolor,msg) -cache_modules={} -def load_module(file_path): - try: - return cache_modules[file_path] - except KeyError: - pass - module=imp.new_module(WSCRIPT_FILE) - try: - code=Utils.readf(file_path,m='rU') - except(IOError,OSError): - raise Errors.WafError('Could not read the file %r'%file_path) - module_dir=os.path.dirname(file_path) - sys.path.insert(0,module_dir) - exec(compile(code,file_path,'exec'),module.__dict__) - sys.path.remove(module_dir) - cache_modules[file_path]=module - return module -def load_tool(tool,tooldir=None): - tool=tool.replace('++','xx') - tool=tool.replace('java','javaw') - tool=tool.replace('compiler_cc','compiler_c') - if tooldir: - assert isinstance(tooldir,list) - sys.path=tooldir+sys.path - try: - __import__(tool) - ret=sys.modules[tool] - Context.tools[tool]=ret - return ret - finally: - for d in tooldir: - sys.path.remove(d) - else: - global waf_dir - try: - os.stat(os.path.join(waf_dir,'waflib','Tools',tool+'.py')) - d='waflib.Tools.%s'%tool - except: - try: - os.stat(os.path.join(waf_dir,'waflib','extras',tool+'.py')) - d='waflib.extras.%s'%tool - except: - d=tool - __import__(d) - ret=sys.modules[d] - Context.tools[tool]=ret - return ret diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Errors.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Errors.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Errors.py +++ /dev/null @@ -1,37 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import traceback,os,sys -class WafError(Exception): - def __init__(self,msg='',ex=None): - self.msg=msg - assert not isinstance(msg,Exception) - self.stack=[] - if ex: - if not msg: - self.msg=str(ex) - if isinstance(ex,WafError): - self.stack=ex.stack - else: - self.stack=traceback.extract_tb(sys.exc_info()[2]) - self.stack+=traceback.extract_stack()[:-1] - self.verbose_msg=''.join(traceback.format_list(self.stack)) - def __str__(self): - return str(self.msg) -class BuildError(WafError): - def __init__(self,error_tasks=[]): - self.tasks=error_tasks - WafError.__init__(self,self.format_error()) - def format_error(self): - lst=['Build failed'] - for tsk in self.tasks: - txt=tsk.format_error() - if txt:lst.append(txt) - return'\n'.join(lst) -class ConfigurationError(WafError): - pass -class TaskRescan(WafError): - pass -class TaskNotReady(WafError): - pass diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Logs.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Logs.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Logs.py +++ /dev/null @@ -1,131 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,re,logging,traceback,sys -try: - if'NOCOLOR'not in os.environ: - import waflib.ansiterm -except: - pass -LOG_FORMAT="%(asctime)s %(c1)s%(zone)s%(c2)s %(message)s" -HOUR_FORMAT="%H:%M:%S" -zones='' -verbose=0 -colors_lst={'USE':True,'BOLD':'\x1b[01;1m','RED':'\x1b[01;31m','GREEN':'\x1b[32m','YELLOW':'\x1b[33m','PINK':'\x1b[35m','BLUE':'\x1b[01;34m','CYAN':'\x1b[36m','NORMAL':'\x1b[0m','cursor_on':'\x1b[?25h','cursor_off':'\x1b[?25l',} -got_tty=not os.environ.get('TERM','dumb')in['dumb','emacs'] -if got_tty: - try: - got_tty=sys.stderr.isatty() - except AttributeError: - got_tty=False -if not got_tty or'NOCOLOR'in os.environ: - colors_lst['USE']=False -def get_term_cols(): - return 80 -try: - import struct,fcntl,termios -except ImportError: - pass -else: - if got_tty: - def get_term_cols_real(): - dummy_lines,cols=struct.unpack("HHHH",fcntl.ioctl(sys.stderr.fileno(),termios.TIOCGWINSZ,struct.pack("HHHH",0,0,0,0)))[:2] - return cols - try: - get_term_cols_real() - except: - pass - else: - get_term_cols=get_term_cols_real -def get_color(cl): - if not colors_lst['USE']:return'' - return colors_lst.get(cl,'') -class color_dict(object): - def __getattr__(self,a): - return get_color(a) - def __call__(self,a): - return get_color(a) -colors=color_dict() -re_log=re.compile(r'(\w+): (.*)',re.M) -class log_filter(logging.Filter): - def __init__(self,name=None): - pass - def filter(self,rec): - rec.c1=colors.PINK - rec.c2=colors.NORMAL - rec.zone=rec.module - if rec.levelno>=logging.INFO: - if rec.levelno>=logging.ERROR: - rec.c1=colors.RED - elif rec.levelno>=logging.WARNING: - rec.c1=colors.YELLOW - else: - rec.c1=colors.GREEN - return True - zone='' - m=re_log.match(rec.msg) - if m: - zone=rec.zone=m.group(1) - rec.msg=m.group(2) - if zones: - return getattr(rec,'zone','')in zones or'*'in zones - elif not verbose>2: - return False - return True -class formatter(logging.Formatter): - def __init__(self): - logging.Formatter.__init__(self,LOG_FORMAT,HOUR_FORMAT) - def format(self,rec): - if rec.levelno>=logging.WARNING or rec.levelno==logging.INFO: - try: - return'%s%s%s'%(rec.c1,rec.msg,rec.c2) - except: - return rec.c1+rec.msg+rec.c2 - return logging.Formatter.format(self,rec) -log=None -def debug(*k,**kw): - if verbose: - k=list(k) - k[0]=k[0].replace('\n',' ') - global log - log.debug(*k,**kw) -def error(*k,**kw): - global log - log.error(*k,**kw) - if verbose>2: - st=traceback.extract_stack() - if st: - st=st[:-1] - buf=[] - for filename,lineno,name,line in st: - buf.append(' File "%s", line %d, in %s'%(filename,lineno,name)) - if line: - buf.append(' %s'%line.strip()) - if buf:log.error("\n".join(buf)) -def warn(*k,**kw): - global log - log.warn(*k,**kw) -def info(*k,**kw): - global log - log.info(*k,**kw) -def init_log(): - global log - log=logging.getLogger('waflib') - log.handlers=[] - log.filters=[] - hdlr=logging.StreamHandler() - hdlr.setFormatter(formatter()) - log.addHandler(hdlr) - log.addFilter(log_filter()) - log.setLevel(logging.DEBUG) -def make_logger(path,name): - logger=logging.getLogger(name) - hdlr=logging.FileHandler(path,'w') - formatter=logging.Formatter('%(message)s') - hdlr.setFormatter(formatter) - logger.addHandler(hdlr) - logger.setLevel(logging.DEBUG) - return logger -def pprint(col,str,label='',sep='\n'): - sys.stderr.write("%s%s%s %s%s"%(colors(col),str,colors.NORMAL,label,sep)) diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Node.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Node.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Node.py +++ /dev/null @@ -1,463 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -if sys.hexversion < 0x020400f0: from sets import Set as set -import os,re,sys,shutil -from waflib import Utils,Errors -prune_pats='.git .bzr .hg .svn _MTN _darcs CVS SCCS'.split() -exclude_pats=prune_pats+'*~ #*# .#* %*% ._* .gitignore .cvsignore vssver.scc .DS_Store'.split() -exclude_regs=''' -**/*~ -**/#*# -**/.#* -**/%*% -**/._* -**/CVS -**/CVS/** -**/.cvsignore -**/SCCS -**/SCCS/** -**/vssver.scc -**/.svn -**/.svn/** -**/BitKeeper -**/.git -**/.git/** -**/.gitignore -**/.bzr -**/.bzrignore -**/.bzr/** -**/.hg -**/.hg/** -**/_MTN -**/_MTN/** -**/.arch-ids -**/{arch} -**/_darcs -**/_darcs/** -**/.DS_Store''' -def split_path(path): - return path.split('/') -def split_path_cygwin(path): - if path.startswith('//'): - ret=path.split('/')[2:] - ret[0]='/'+ret[0] - return ret - return path.split('/') -re_sp=re.compile('[/\\\\]') -def split_path_win32(path): - if path.startswith('\\\\'): - ret=re.split(re_sp,path)[2:] - ret[0]='\\'+ret[0] - return ret - return re.split(re_sp,path) -if sys.platform=='cygwin': - split_path=split_path_cygwin -elif sys.platform=='win32': - split_path=split_path_win32 -class Node(object): - __slots__=('name','sig','children','parent','cache_abspath','cache_isdir') - def __init__(self,name,parent): - self.name=name - self.parent=parent - if parent: - if name in parent.children: - raise Errors.WafError('node %s exists in the parent files %r already'%(name,parent)) - parent.children[name]=self - def __setstate__(self,data): - self.name=data[0] - self.parent=data[1] - if data[2]is not None: - self.children=data[2] - if data[3]is not None: - self.sig=data[3] - def __getstate__(self): - return(self.name,self.parent,getattr(self,'children',None),getattr(self,'sig',None)) - def __str__(self): - return self.name - def __repr__(self): - return self.abspath() - def __hash__(self): - return id(self) - def __eq__(self,node): - return id(self)==id(node) - def __copy__(self): - raise Errors.WafError('nodes are not supposed to be copied') - def read(self,flags='r'): - return Utils.readf(self.abspath(),flags) - def write(self,data,flags='w'): - f=None - try: - f=open(self.abspath(),flags) - f.write(data) - finally: - if f: - f.close() - def chmod(self,val): - os.chmod(self.abspath(),val) - def delete(self): - try: - if getattr(self,'children',None): - shutil.rmtree(self.abspath()) - else: - os.unlink(self.abspath()) - except: - pass - try: - delattr(self,'children') - except: - pass - def suffix(self): - k=max(0,self.name.rfind('.')) - return self.name[k:] - def height(self): - d=self - val=-1 - while d: - d=d.parent - val+=1 - return val - def listdir(self): - return Utils.listdir(self.abspath()) - def mkdir(self): - if getattr(self,'cache_isdir',None): - return - try: - self.parent.mkdir() - except: - pass - if self.name: - try: - os.mkdir(self.abspath()) - except OSError ,e: - pass - if not os.path.isdir(self.abspath()): - raise Errors.WafError('%s is not a directory'%self) - try: - self.children - except: - self.children={} - self.cache_isdir=True - def find_node(self,lst): - if isinstance(lst,str): - lst=[x for x in split_path(lst)if x and x!='.'] - cur=self - for x in lst: - if x=='..': - cur=cur.parent - continue - try: - if x in cur.children: - cur=cur.children[x] - continue - except: - cur.children={} - cur=self.__class__(x,cur) - try: - os.stat(cur.abspath()) - except: - del cur.parent.children[x] - return None - ret=cur - try: - while not getattr(cur.parent,'cache_isdir',None): - cur=cur.parent - cur.cache_isdir=True - except AttributeError: - pass - return ret - def make_node(self,lst): - if isinstance(lst,str): - lst=[x for x in split_path(lst)if x and x!='.'] - cur=self - for x in lst: - if x=='..': - cur=cur.parent - continue - if getattr(cur,'children',{}): - if x in cur.children: - cur=cur.children[x] - continue - else: - cur.children={} - cur=self.__class__(x,cur) - return cur - def search(self,lst): - if isinstance(lst,str): - lst=[x for x in split_path(lst)if x and x!='.'] - cur=self - try: - for x in lst: - if x=='..': - cur=cur.parent - else: - cur=cur.children[x] - return cur - except: - pass - def path_from(self,node): - c1=self - c2=node - c1h=c1.height() - c2h=c2.height() - lst=[] - up=0 - while c1h>c2h: - lst.append(c1.name) - c1=c1.parent - c1h-=1 - while c2h>c1h: - up+=1 - c2=c2.parent - c2h-=1 - while id(c1)!=id(c2): - lst.append(c1.name) - up+=1 - c1=c1.parent - c2=c2.parent - for i in range(up): - lst.append('..') - lst.reverse() - return os.sep.join(lst)or'.' - def abspath(self): - try: - return self.cache_abspath - except: - pass - if not self.parent: - val=os.sep=='/'and os.sep or'' - elif not self.parent.name: - val=(os.sep=='/'and os.sep or'')+self.name - else: - val=self.parent.abspath()+os.sep+self.name - self.cache_abspath=val - return val - def is_child_of(self,node): - p=self - diff=self.height()-node.height() - while diff>0: - diff-=1 - p=p.parent - return id(p)==id(node) - def ant_iter(self,accept=None,maxdepth=25,pats=[],dir=False,src=True): - dircont=self.listdir() - dircont.sort() - try: - lst=set(self.children.keys()) - for x in lst-set(dircont): - del self.children[x] - except: - self.children={} - for name in dircont: - npats=accept(name,pats) - if npats and npats[0]: - accepted=[]in npats[0] - node=self.make_node([name]) - isdir=os.path.isdir(node.abspath()) - if accepted: - if isdir: - if dir: - yield node - else: - if src: - yield node - if getattr(node,'cache_isdir',None)or isdir: - node.cache_isdir=True - if maxdepth: - for k in node.ant_iter(accept=accept,maxdepth=maxdepth-1,pats=npats,dir=dir,src=src): - yield k - raise StopIteration - def ant_glob(self,*k,**kw): - src=kw.get('src',True) - dir=kw.get('dir',False) - excl=kw.get('excl',exclude_regs) - incl=k and k[0]or kw.get('incl','**') - def to_pat(s): - lst=Utils.to_list(s) - ret=[] - for x in lst: - x=x.replace('\\','/').replace('//','/') - if x.endswith('/'): - x+='**' - lst2=x.split('/') - accu=[] - for k in lst2: - if k=='**': - accu.append(k) - else: - k=k.replace('.','[.]').replace('*','.*').replace('?','.') - k='^%s$'%k - accu.append(re.compile(k)) - ret.append(accu) - return ret - def filtre(name,nn): - ret=[] - for lst in nn: - if not lst: - pass - elif lst[0]=='**': - ret.append(lst) - if len(lst)>1: - if lst[1].match(name): - ret.append(lst[2:]) - else: - ret.append([]) - elif lst[0].match(name): - ret.append(lst[1:]) - return ret - def accept(name,pats): - nacc=filtre(name,pats[0]) - nrej=filtre(name,pats[1]) - if[]in nrej: - nacc=[] - return[nacc,nrej] - ret=[x for x in self.ant_iter(accept=accept,pats=[to_pat(incl),to_pat(excl)],maxdepth=25,dir=dir,src=src)] - if kw.get('flat',False): - return' '.join([x.path_from(self)for x in ret]) - return ret - def is_src(self): - cur=self - x=id(self.ctx.srcnode) - y=id(self.ctx.bldnode) - while cur.parent: - if id(cur)==y: - return False - if id(cur)==x: - return True - cur=cur.parent - return False - def is_bld(self): - cur=self - y=id(self.ctx.bldnode) - while cur.parent: - if id(cur)==y: - return True - cur=cur.parent - return False - def get_src(self): - cur=self - x=id(self.ctx.srcnode) - y=id(self.ctx.bldnode) - lst=[] - while cur.parent: - if id(cur)==y: - lst.reverse() - return self.ctx.srcnode.make_node(lst) - if id(cur)==x: - return self - lst.append(cur.name) - cur=cur.parent - return self - def get_bld(self): - cur=self - x=id(self.ctx.srcnode) - y=id(self.ctx.bldnode) - lst=[] - while cur.parent: - if id(cur)==y: - return self - if id(cur)==x: - lst.reverse() - return self.ctx.bldnode.make_node(lst) - lst.append(cur.name) - cur=cur.parent - return self - def find_resource(self,lst): - if isinstance(lst,str): - lst=[x for x in split_path(lst)if x and x!='.'] - node=self.get_bld().search(lst) - if not node: - self=self.get_src() - node=self.search(lst) - if not node: - node=self.find_node(lst) - try: - pat=node.abspath() - if os.path.isdir(pat): - return None - except: - pass - return node - def find_or_declare(self,lst): - if isinstance(lst,str): - lst=[x for x in split_path(lst)if x and x!='.'] - node=self.get_bld().search(lst) - if node: - if not os.path.isfile(node.abspath()): - node.sig=None - try: - node.parent.mkdir() - except: - pass - return node - self=self.get_src() - node=self.find_node(lst) - if node: - if not os.path.isfile(node.abspath()): - node.sig=None - try: - node.parent.mkdir() - except: - pass - return node - node=self.get_bld().make_node(lst) - node.parent.mkdir() - return node - def find_dir(self,lst): - if isinstance(lst,str): - lst=[x for x in split_path(lst)if x and x!='.'] - node=self.find_node(lst) - try: - if not os.path.isdir(node.abspath()): - return None - except(OSError,AttributeError): - return None - return node - def change_ext(self,ext,ext_in=None): - name=self.name - if ext_in is None: - k=name.rfind('.') - if k>=0: - name=name[:k]+ext - else: - name=name+ext - else: - name=name[:-len(ext_in)]+ext - return self.parent.find_or_declare([name]) - def nice_path(self,env=None): - return self.path_from(self.ctx.launch_node()) - def bldpath(self): - return self.path_from(self.ctx.bldnode) - def srcpath(self): - return self.path_from(self.ctx.srcnode) - def relpath(self): - cur=self - x=id(self.ctx.bldnode) - while cur.parent: - if id(cur)==x: - return self.ctx.path() - cur=cur.parent - return self.srcpath() - def bld_dir(self): - return self.parent.bldpath() - def bld_base(self): - s=os.path.splitext(self.name)[0] - return self.bld_dir()+os.sep+s - def get_bld_sig(self): - try: - ret=self.ctx.hash_cache[id(self)] - except KeyError: - pass - except AttributeError: - self.ctx.hash_cache={} - else: - return ret - if not self.is_bld()or self.ctx.bldnode is self.ctx.srcnode: - self.sig=Utils.h_file(self.abspath()) - self.ctx.hash_cache[id(self)]=ret=self.sig - return ret -pickle_lock=Utils.threading.Lock() -class Nod3(Node): - pass diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Options.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Options.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Options.py +++ /dev/null @@ -1,118 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,types,tempfile,optparse,sys -from waflib import Logs,Utils,Context -cmds='distclean configure build install clean uninstall check dist distcheck'.split() -options={} -commands=[] -lockfile=os.environ.get('WAFLOCK','.lock-wafbuild') -try:cache_global=os.path.abspath(os.environ['WAFCACHE']) -except KeyError:cache_global='' -platform=Utils.unversioned_sys_platform() -class opt_parser(optparse.OptionParser): - def __init__(self,ctx): - optparse.OptionParser.__init__(self,conflict_handler="resolve",version='waf %s (%s)'%(Context.WAFVERSION,Context.WAFREVISION)) - self.formatter.width=Logs.get_term_cols() - p=self.add_option - self.ctx=ctx - jobs=ctx.jobs() - p('-j','--jobs',dest='jobs',default=jobs,type='int',help='amount of parallel jobs (%r)'%jobs) - p('-k','--keep',dest='keep',default=False,action='store_true',help='keep running happily on independent task groups') - p('-v','--verbose',dest='verbose',default=0,action='count',help='verbosity level -v -vv or -vvv [default: 0]') - p('--nocache',dest='nocache',default=False,action='store_true',help='ignore the WAFCACHE (if set)') - p('--zones',dest='zones',default='',action='store',help='debugging zones (task_gen, deps, tasks, etc)') - gr=optparse.OptionGroup(self,'configure options') - self.add_option_group(gr) - gr.add_option('-o','--out',action='store',default='',help='build dir for the project',dest='out') - gr.add_option('-t','--top',action='store',default='',help='src dir for the project',dest='top') - default_prefix=os.environ.get('PREFIX') - if not default_prefix: - if platform=='win32': - d=tempfile.gettempdir() - default_prefix=d[0].upper()+d[1:] - else: - default_prefix='/usr/local/' - gr.add_option('--prefix',dest='prefix',default=default_prefix,help='installation prefix [default: %r]'%default_prefix) - gr.add_option('--download',dest='download',default=False,action='store_true',help='try to download the tools if missing') - gr=optparse.OptionGroup(self,'build and install options') - self.add_option_group(gr) - gr.add_option('-p','--progress',dest='progress_bar',default=0,action='count',help='-p: progress bar; -pp: ide output') - gr.add_option('--targets',dest='targets',default='',action='store',help='task generators, e.g. "target1,target2"') - gr=optparse.OptionGroup(self,'step options') - self.add_option_group(gr) - gr.add_option('--files',dest='files',default='',action='store',help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"') - default_destdir=os.environ.get('DESTDIR','') - gr=optparse.OptionGroup(self,'install/uninstall options') - self.add_option_group(gr) - gr.add_option('--destdir',help='installation root [default: %r]'%default_destdir,default=default_destdir,dest='destdir') - gr.add_option('-f','--force',dest='force',default=False,action='store_true',help='force file installation') - def get_usage(self): - cmds_str={} - for cls in Context.classes: - if not cls.cmd: - continue - s=cls.__doc__ or'' - cmds_str[cls.cmd]=s - if Context.g_module: - for(k,v)in Context.g_module.__dict__.items(): - if k in['options','init','shutdown']: - continue - if type(v)is type(Context.create_context): - if v.__doc__ and not k.startswith('_'): - cmds_str[k]=v.__doc__ - just=0 - for k in cmds_str: - just=max(just,len(k)) - lst=[' %s: %s'%(k.ljust(just),v)for(k,v)in cmds_str.items()] - lst.sort() - ret='\n'.join(lst) - return'''waf [commands] [options] - -Main commands (example: ./waf build -j4) -%s -'''%ret -class OptionsContext(Context.Context): - cmd='' - fun='options' - def __init__(self,**kw): - super(self.__class__,self).__init__(**kw) - self.parser=opt_parser(self) - def jobs(self): - count=int(os.environ.get('JOBS',0)) - if count<1: - if sys.platform=='win32': - count=int(os.environ.get('NUMBER_OF_PROCESSORS',1)) - else: - if hasattr(os,'sysconf_names'): - if'SC_NPROCESSORS_ONLN'in os.sysconf_names: - count=int(os.sysconf('SC_NPROCESSORS_ONLN')) - elif'SC_NPROCESSORS_CONF'in os.sysconf_names: - count=int(os.sysconf('SC_NPROCESSORS_CONF')) - elif os.name!='java': - tmp=self.cmd_and_log(['sysctl','-n','hw.ncpu']) - if re.match('^[0-9]+$',tmp): - count=int(tmp) - if count<1: - count=1 - elif count>1024: - count=1024 - return count - def add_option(self,*k,**kw): - self.parser.add_option(*k,**kw) - def add_option_group(self,*k,**kw): - return self.parser.add_option_group(*k,**kw) - def get_option_group(self,opt_str): - return self.parser.get_option_group(opt_str) - def parse_args(self,_args=None): - global options,commands - (options,leftover_args)=self.parser.parse_args(args=_args) - commands=leftover_args - if options.destdir: - options.destdir=os.path.abspath(os.path.expanduser(options.destdir)) - if options.verbose>=2: - self.tool_options('errcheck') - def execute(self): - super(OptionsContext,self).execute() - self.parse_args() diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Runner.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Runner.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Runner.py +++ /dev/null @@ -1,171 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,random -try: - from queue import Queue -except: - from Queue import Queue -from waflib import Utils,Logs,Task,Errors -GAP=10 -MAXJOBS=999 -class TaskConsumer(Utils.threading.Thread): - def __init__(self): - Utils.threading.Thread.__init__(self) - self.ready=Queue() - self.setDaemon(1) - self.start() - def run(self): - try: - self.loop() - except: - pass - def loop(self): - while 1: - tsk=self.ready.get() - tsk.process() -pool=Queue() -def get_pool(): - try: - return pool.get(False) - except: - return TaskConsumer() -def put_pool(x): - pool.put(x) -class Parallel(object): - def __init__(self,bld,j=2): - self.numjobs=j - self.bld=bld - self.outstanding=[] - self.maxjobs=MAXJOBS - self.frozen=[] - self.out=Queue(0) - self.count=0 - self.processed=1 - self.stop=False - self.error=[] - self.biter=None - self.dirty=False - def get_next_task(self): - if not self.outstanding: - return None - return self.outstanding.pop(0) - def postpone(self,tsk): - if random.randint(0,1): - self.frozen.insert(0,tsk) - else: - self.frozen.append(tsk) - def refill_task_list(self): - while self.count>self.numjobs*GAP or self.count>=self.maxjobs: - self.get_out() - while not self.outstanding: - if self.count: - self.get_out() - elif self.frozen: - try: - cond=self.deadlock==self.processed - except: - pass - else: - if cond: - msg='check the build order for the tasks' - for tsk in self.frozen: - if not tsk.run_after: - msg='check the methods runnable_status' - break - lst=[] - for tsk in self.frozen: - lst.append('%s\t-> %r'%(repr(tsk),[id(x)for x in tsk.run_after])) - raise Errors.WafError("Deadlock detected: %s%s"%(msg,''.join(lst))) - self.deadlock=self.processed - if self.frozen: - self.outstanding+=self.frozen - self.frozen=[] - elif not self.count: - self.outstanding.extend(self.biter.next()) - self.total=self.bld.total() - break - def add_more_tasks(self,tsk): - if getattr(tsk,'more_tasks',None): - self.outstanding+=tsk.more_tasks - self.total+=len(tsk.more_tasks) - def get_out(self): - tsk=self.out.get() - if not self.stop: - self.add_more_tasks(tsk) - self.count-=1 - self.dirty=True - def error_handler(self,tsk): - if not self.bld.keep: - self.stop=True - self.error.append(tsk) - def add_task(self,tsk): - try: - pool=self.pool - except AttributeError: - pool=self.pool=[get_pool()for i in range(self.numjobs)] - a=pool[random.randint(0,len(pool)-1)] - siz=a.ready.qsize() - if not siz: - a.ready.put(tsk) - return - b=pool[random.randint(0,len(pool)-1)] - if siz>b.ready.qsize(): - b.ready.put(tsk) - else: - a.ready.put(tsk) - def start(self): - self.total=self.bld.total() - while not self.stop: - self.refill_task_list() - tsk=self.get_next_task() - if not tsk: - if self.count: - continue - else: - break - if tsk.hasrun: - self.processed+=1 - continue - try: - st=tsk.runnable_status() - except Exception ,e: - self.processed+=1 - if self.stop and not self.bld.keep: - tsk.hasrun=Task.SKIPPED - continue - tsk.err_msg=Utils.ex_stack() - tsk.hasrun=Task.EXCEPTION - self.error_handler(tsk) - continue - if st==Task.ASK_LATER: - self.postpone(tsk) - if self.outstanding: - for x in tsk.run_after: - if x in self.outstanding: - self.outstanding.remove(x) - self.outstanding.insert(0,x) - elif st==Task.SKIP_ME: - self.processed+=1 - tsk.hasrun=Task.SKIPPED - self.add_more_tasks(tsk) - else: - tsk.position=(self.processed,self.total) - self.count+=1 - tsk.master=self - self.processed+=1 - tsk.log_display(self.bld) - if self.numjobs==1: - tsk.process() - else: - self.add_task(tsk) - while self.error and self.count: - self.get_out() - try: - while self.pool: - x=self.pool.pop() - put_pool(x) - except AttributeError: - pass - assert(self.count==0 or self.stop) diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Scripting.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Scripting.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Scripting.py +++ /dev/null @@ -1,327 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,shutil,traceback,datetime,inspect,errno,sys -from waflib import Utils,Configure,Logs,Options,ConfigSet,Context,Errors,Build,Node -build_dir_override=None -no_climb_commands=['configure'] -def waf_entry_point(current_directory,version,wafdir): - Logs.init_log() - if Context.WAFVERSION!=version: - Logs.error('Waf script %r and library %r do not match (directory %r)'%(version,WAFVERSION,wafdir)) - sys.exit(1) - Context.waf_dir=wafdir - Context.launch_dir=current_directory - cur=current_directory - while cur: - lst=os.listdir(cur) - if Options.lockfile in lst: - env=ConfigSet.ConfigSet() - try: - env.load(os.path.join(cur,Options.lockfile)) - except Exception: - continue - Context.run_dir=env.run_dir - Context.top_dir=env.top_dir - Context.out_dir=env.out_dir - try: - os.stat(Context.run_dir) - except: - Context.run_dir=cur - break - if not Context.run_dir: - if Context.WSCRIPT_FILE in lst: - Context.run_dir=cur - next=os.path.dirname(cur) - if next==cur: - break - cur=next - for k in no_climb_commands: - if k in sys.argv: - break - else: - continue - break - if not Context.run_dir: - if'-h'in sys.argv or'--help'in sys.argv: - Logs.warn('No wscript file found: the help message may be incomplete') - opt_obj=Options.OptionsContext() - opt_obj.curdir=current_directory - opt_obj.parse_args() - sys.exit(0) - elif'--version'in sys.argv: - opt_obj=Options.OptionsContext() - opt_obj.curdir=current_directory - opt_obj.parse_args() - sys.exit(0) - Logs.error('Waf: Run from a directory containing a file named %r'%Context.WSCRIPT_FILE) - sys.exit(1) - try: - os.chdir(Context.run_dir) - except OSError: - Logs.error('Waf: The folder %r is unreadable'%Context.run_dir) - sys.exit(1) - try: - set_main_module(Context.run_dir+os.sep+Context.WSCRIPT_FILE) - except Errors.WafError ,e: - Logs.pprint('RED',e.verbose_msg) - Logs.error(str(e)) - sys.exit(1) - except Exception ,e: - Logs.error('Waf: The wscript in %r is unreadable'%Context.run_dir,e) - traceback.print_exc(file=sys.stdout) - sys.exit(2) - parse_options() - try: - run_commands() - except Errors.WafError ,e: - if Logs.verbose>1: - Logs.pprint('RED',e.verbose_msg) - Logs.error(e.msg) - sys.exit(1) - except Exception ,e: - traceback.print_exc(file=sys.stdout) - sys.exit(2) - except KeyboardInterrupt: - Logs.pprint('RED','Interrupted') - sys.exit(68) -def set_main_module(file_path): - Context.g_module=Context.load_module(file_path) - Context.g_module.root_path=file_path - def set_def(obj): - name=obj.__name__ - if not name in Context.g_module.__dict__: - setattr(Context.g_module,name,obj) - for k in[update,dist,distclean,distcheck]: - set_def(k) - if not'init'in Context.g_module.__dict__: - Context.g_module.init=Utils.nada - if not'shutdown'in Context.g_module.__dict__: - Context.g_module.shutdown=Utils.nada - if not'options'in Context.g_module.__dict__: - Context.g_module.options=Utils.nada -def parse_options(): - opt=Options.OptionsContext().execute() - if not Options.commands: - Options.commands=['build'] - Logs.verbose=Options.options.verbose - Logs.init_log() - if Options.options.zones: - Logs.zones=Options.options.zones.split(',') - if not Logs.verbose: - Logs.verbose=1 - elif Logs.verbose>0: - Logs.zones=['runner'] - if Logs.verbose>2: - Logs.zones=['*'] -def run_command(cmd_name): - ctx=Context.create_context(cmd_name) - ctx.options=Options.options - ctx.cmd=cmd_name - ctx.execute() - return ctx -def run_commands(): - run_command('init') - while Options.commands: - cmd_name=Options.commands.pop(0) - timer=Utils.Timer() - run_command(cmd_name) - if not Options.options.progress_bar: - elapsed=' (%s)'%str(timer) - Logs.info('%r finished successfully%s'%(cmd_name,elapsed)) - run_command('shutdown') -def _can_distclean(name): - for k in'.o .moc .exe'.split(): - if name.endswith(k): - return True - return False -def distclean_dir(dirname): - for(root,dirs,files)in os.walk(dirname): - for f in files: - if _can_distclean(f): - fname=root+os.sep+f - try: - os.unlink(fname) - except: - Logs.warn('could not remove %r'%fname) - for x in[DBFILE,'config.log']: - try: - os.unlink(x) - except: - pass - try: - shutil.rmtree('c4che') - except: - pass -def distclean(ctx): - '''removes the build directory''' - lst=os.listdir('.') - for f in lst: - if f==Options.lockfile: - try: - proj=ConfigSet.ConfigSet(f) - except: - Logs.warn('could not read %r'%f) - continue - if proj['out_dir']!=proj['top_dir']: - try: - shutil.rmtree(proj['out_dir']) - except IOError: - pass - except OSError ,e: - if e.errno!=errno.ENOENT: - Logs.warn('project %r cannot be removed'%proj[Context.OUT]) - else: - distclean_dir(proj['out_dir']) - for k in(proj['out_dir'],proj['top_dir'],proj['run_dir']): - try: - os.remove(os.path.join(k,Options.lockfile)) - except OSError ,e: - if e.errno!=errno.ENOENT: - Logs.warn('file %r cannot be removed'%f) - if f.startswith('.waf-')and not Options.commands: - shutil.rmtree(f,ignore_errors=True) -class Dist(Context.Context): - cmd='dist' - fun='dist' - algo='tar.bz2' - ext_algo={} - def execute(self): - self.recurse([os.path.dirname(Context.g_module.root_path)]) - self.archive() - def archive(self): - import tarfile - arch_name=self.get_arch_name() - try: - self.base_path - except: - self.base_path=self.path - node=self.base_path.make_node(arch_name) - try: - node.delete() - except: - pass - files=self.get_files() - if self.algo.startswith('tar.'): - tar=tarfile.open(arch_name,'w:'+self.algo.replace('tar.','')) - for x in files: - tinfo=tar.gettarinfo(name=x.abspath(),arcname=self.get_base_name()+'/'+x.path_from(self.base_path)) - tinfo.uid=0 - tinfo.gid=0 - tinfo.uname='root' - tinfo.gname='root' - fu=None - try: - fu=open(x.abspath()) - tar.addfile(tinfo,fileobj=fu) - finally: - fu.close() - tar.close() - elif self.algo=='zip': - import zipfile - zip=zipfile.ZipFile(arch_name,'w',compression=zipfile.ZIP_DEFLATED) - for x in files: - archive_name=self.get_base_name()+'/'+x.path_from(self.base_path) - zip.write(x.abspath(),archive_name,zipfile.ZIP_DEFLATED) - zip.close() - else: - self.fatal('Valid algo types are tar.bz2, tar.gz or zip') - try: - from hashlib import sha1 as sha - except ImportError: - from sha import sha - try: - digest=" (sha=%r)"%sha(node.read()).hexdigest() - except: - digest='' - Logs.info('New archive created: %s%s'%(self.arch_name,digest)) - def get_arch_name(self): - try: - self.arch_name - except: - self.arch_name=self.get_base_name()+'.'+self.ext_algo.get(self.algo,self.algo) - return self.arch_name - def get_base_name(self): - try: - self.base_name - except: - appname=getattr(Context.g_module,Context.APPNAME,'noname') - version=getattr(Context.g_module,Context.VERSION,'1.0') - self.base_name=appname+'-'+version - return self.base_name - def get_excl(self): - try: - return self.excl - except: - self.excl=Node.exclude_regs+' **/waf-1.6.* **/.waf-1.6* **/*~ **/*.rej **/*.orig **/*.pyc **/*.pyo **/*.bak **/*.swp **/.lock-w*' - nd=self.root.find_node(Context.out_dir) - if nd: - self.excl+=' '+nd.path_from(self.base_path) - return self.excl - def get_files(self): - try: - files=self.files - except: - files=self.base_path.ant_glob('**/*',excl=self.get_excl()) - return files -def dist(ctx): - '''makes a tarball for redistributing the sources''' - pass -class DistCheck(Dist): - fun='distcheck' - cmd='distcheck' - def execute(self): - self.recurse([os.path.dirname(Context.g_module.root_path)]) - self.archive() - self.check() - def check(self): - import tempfile,tarfile - t=None - try: - t=tarfile.open(self.get_arch_name()) - for x in t: - t.extract(x) - finally: - if t: - t.close() - instdir=tempfile.mkdtemp('.inst',self.get_base_name()) - ret=Utils.subprocess.Popen([sys.argv[0],'configure','install','uninstall','--destdir='+instdir],cwd=self.get_base_name()).wait() - if ret: - raise Errors.WafError('distcheck failed with code %i'%ret) - if os.path.exists(instdir): - raise Errors.WafError('distcheck succeeded, but files were left in %s'%instdir) - shutil.rmtree(self.get_base_name()) -def distcheck(ctx): - '''checks if the project compiles (tarball from 'dist')''' - pass -def update(ctx): - lst=os.listdir(Context.waf_dir+'/waflib/extras') - for x in lst: - if not x.endswith('.py'): - continue - tool=x.replace('.py','') - Configure.download_tool(tool,force=True) -def autoconfigure(execute_method): - def execute(self): - if not Configure.autoconfig: - return execute_method(self) - env=ConfigSet.ConfigSet() - do_config=False - try: - env.load(os.path.join(Context.top_dir,Options.lockfile)) - except Exception ,e: - Logs.warn('Configuring the project') - do_config=True - else: - h=0 - for f in env['files']: - h=hash((h,Utils.readf(f,'rb'))) - do_config=h!=env.hash - if do_config: - Options.commands.insert(0,self.cmd) - Options.commands.insert(0,'configure') - return - return execute_method(self) - return execute -Build.BuildContext.execute=autoconfigure(Build.BuildContext.execute) diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Task.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Task.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Task.py +++ /dev/null @@ -1,618 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -if sys.hexversion < 0x020400f0: from sets import Set as set -import os,shutil,re,tempfile -from waflib import Utils,Logs,Errors -NOT_RUN=0 -MISSING=1 -CRASHED=2 -EXCEPTION=3 -SKIPPED=8 -SUCCESS=9 -ASK_LATER=-1 -SKIP_ME=-2 -RUN_ME=-3 -COMPILE_TEMPLATE_SHELL=''' -def f(tsk): - env = tsk.env - gen = tsk.generator - bld = gen.bld - wd = getattr(tsk, 'cwd', None) - p = env.get_flat - tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s - return tsk.exec_command(cmd, cwd=wd, env=env.env or None) -''' -COMPILE_TEMPLATE_NOSHELL=''' -def f(tsk): - env = tsk.env - gen = tsk.generator - bld = gen.bld - wd = getattr(tsk, 'cwd', None) - def to_list(xx): - if isinstance(xx, str): return [xx] - return xx - tsk.last_cmd = lst = [] - %s - lst = [x for x in lst if x] - return tsk.exec_command(lst, cwd=wd, env=env.env or None) -''' -def cache_outputs(cls): - m1=cls.run - def run(self): - bld=self.generator.bld - if bld.cache_global and not bld.nocache: - if self.can_retrieve_cache(): - return 0 - return m1(self) - cls.run=run - m2=cls.post_run - def post_run(self): - bld=self.generator.bld - ret=m2(self) - if bld.cache_global and not bld.nocache: - self.put_files_cache() - return ret - cls.post_run=post_run - return cls -classes={} -class store_task_type(type): - def __init__(cls,name,bases,dict): - super(store_task_type,cls).__init__(name,bases,dict) - name=cls.__name__ - if name.endswith('_task'): - name=name.replace('_task','') - if name!='evil'and name!='TaskBase': - global classes - if getattr(cls,'run_str',None): - (f,dvars)=compile_fun(cls.run_str,cls.shell) - cls.hcode=cls.run_str - cls.run=f - cls.vars.extend(dvars) - elif getattr(cls,'run',None)and not getattr(cls,'hcode',None): - cls.hcode=Utils.h_fun(cls.run) - if not getattr(cls,'nocache',None): - cls=cache_outputs(cls) - classes[name]=cls -evil=store_task_type('evil',(object,),{}) -class TaskBase(evil): - color="GREEN" - ext_in=[] - ext_out=[] - before=[] - after=[] - hcode='' - def __init__(self,*k,**kw): - self.hasrun=NOT_RUN - try: - self.generator=kw['generator'] - except KeyError: - self.generator=self - def __repr__(self): - return'\n\t{task %r: %s %s}'%(self.__class__.__name__,id(self),str(getattr(self,"fun",""))) - def __str__(self): - if hasattr(self,'fun'): - return'executing: %s\n'%self.fun.__name__ - return self.__class__.__name__+'\n' - def __hash__(self): - return id(self) - def exec_command(self,cmd,**kw): - bld=self.generator.bld - try: - if not kw.get('cwd',None): - kw['cwd']=bld.cwd - except AttributeError: - bld.cwd=kw['cwd']=bld.variant_dir - return bld.exec_command(cmd,**kw) - def runnable_status(self): - return RUN_ME - def process(self): - m=self.master - if m.stop: - m.out.put(self) - return - try: - ret=self.run() - except Exception ,e: - self.err_msg=Utils.ex_stack() - self.hasrun=EXCEPTION - m.error_handler(self) - m.out.put(self) - return - if ret: - self.err_code=ret - self.hasrun=CRASHED - else: - try: - self.post_run() - except Errors.WafError: - pass - except Exception: - self.err_msg=Utils.ex_stack() - self.hasrun=EXCEPTION - else: - self.hasrun=SUCCESS - if self.hasrun!=SUCCESS: - m.error_handler(self) - m.out.put(self) - def run(self): - if hasattr(self,'fun'): - return self.fun(self) - return 0 - def post_run(self): - pass - def log_display(self,bld): - bld.to_log(self.display()) - def display(self): - col1=Logs.colors(self.color) - col2=Logs.colors.NORMAL - if self.generator.bld.progress_bar==1: - return self.generator.bld.progress_line(self.position[0],self.position[1],col1,col2) - if self.generator.bld.progress_bar==2: - ela=str(self.generator.bld.timer) - try: - ins=','.join([n.name for n in self.inputs]) - except AttributeError: - ins='' - try: - outs=','.join([n.name for n in self.outputs]) - except AttributeError: - outs='' - return'|Total %s|Current %s|Inputs %s|Outputs %s|Time %s|\n'%(self.position[1],self.position[0],ins,outs,ela) - s=str(self) - if not s: - return None - total=self.position[1] - n=len(str(total)) - fs='[%%%dd/%%%dd] %%s%%s%%s'%(n,n) - return fs%(self.position[0],self.position[1],col1,s,col2) - def attr(self,att,default=None): - ret=getattr(self,att,self) - if ret is self:return getattr(self.__class__,att,default) - return ret - def hash_constraints(self): - cls=self.__class__ - tup=(str(cls.before),str(cls.after),str(cls.ext_in),str(cls.ext_out)) - h=hash(tup) - return h - def format_error(self): - msg=getattr(self,'last_cmd','') - if getattr(self,"err_msg",None): - return self.err_msg - elif self.hasrun==CRASHED: - try: - return' -> task failed (exit status %r): %r\n%r'%(self.err_code,self,msg) - except AttributeError: - return' -> task failed: %r\n%r'%(self,msg) - elif self.hasrun==MISSING: - return' -> missing files: %r\n%r'%(self,msg) - else: - return'?' -class Task(TaskBase): - vars=[] - shell=False - def __init__(self,*k,**kw): - TaskBase.__init__(self,*k,**kw) - self.env=kw['env'] - self.inputs=[] - self.outputs=[] - self.dep_nodes=[] - self.run_after=set([]) - def __str__(self): - env=self.env - src_str=' '.join([a.nice_path(env)for a in self.inputs]) - tgt_str=' '.join([a.nice_path(env)for a in self.outputs]) - if self.outputs:sep=' -> ' - else:sep='' - return'%s: %s%s%s\n'%(self.__class__.__name__.replace('_task',''),src_str,sep,tgt_str) - def __repr__(self): - return"".join(['\n\t{task %r: '%id(self),self.__class__.__name__," ",",".join([x.name for x in self.inputs])," -> ",",".join([x.name for x in self.outputs]),'}']) - def uid(self): - try: - return self.uid_ - except AttributeError: - m=Utils.md5() - up=m.update - up(self.__class__.__name__) - for x in self.inputs+self.outputs: - up(x.abspath()) - self.uid_=m.digest() - return self.uid_ - def set_inputs(self,inp): - if isinstance(inp,list):self.inputs+=inp - else:self.inputs.append(inp) - def set_outputs(self,out): - if isinstance(out,list):self.outputs+=out - else:self.outputs.append(out) - def set_run_after(self,task): - assert isinstance(task,TaskBase) - self.run_after.add(task) - def signature(self): - try:return self.cache_sig - except AttributeError:pass - self.m=Utils.md5() - self.m.update(self.hcode) - self.sig_explicit_deps() - self.sig_vars() - if self.scan: - try: - imp_sig=self.sig_implicit_deps() - except Errors.TaskRescan: - return self.signature() - ret=self.cache_sig=self.m.digest() - return ret - def runnable_status(self): - for t in self.run_after: - if not t.hasrun: - return ASK_LATER - env=self.env - bld=self.generator.bld - try: - new_sig=self.signature() - except Errors.TaskNotReady: - return ASK_LATER - key=self.uid() - try: - prev_sig=bld.task_sigs[key] - except KeyError: - Logs.debug("task: task %r must run as it was never run before or the task code changed"%self) - return RUN_ME - for node in self.outputs: - try: - if node.sig!=new_sig: - return RUN_ME - except AttributeError: - Logs.debug("task: task %r must run as the output nodes do not exist"%self) - return RUN_ME - if new_sig!=prev_sig: - return RUN_ME - return SKIP_ME - def post_run(self): - bld=self.generator.bld - env=self.env - sig=self.signature() - cnt=0 - for node in self.outputs: - try: - os.stat(node.abspath()) - except OSError: - self.hasrun=MISSING - self.err_msg='-> missing file: %r'%node.abspath() - raise Errors.WafError(self.err_msg) - node.sig=sig - bld.task_sigs[self.uid()]=self.cache_sig - def sig_explicit_deps(self): - bld=self.generator.bld - upd=self.m.update - for x in self.inputs+self.dep_nodes: - try: - upd(x.get_bld_sig()) - except(AttributeError,TypeError): - raise Errors.WafError('Missing node signature for %r (required by %r)'%(x,self)) - if bld.deps_man: - additional_deps=bld.deps_man - for x in self.inputs+self.outputs: - try: - d=additional_deps[id(x)] - except KeyError: - continue - for v in d: - if isinstance(v,bld.root.__class__): - try: - v=v.get_bld_sig() - except AttributeError: - raise Errors.WafError('Missing node signature for %r (required by %r)'%(v,self)) - elif hasattr(v,'__call__'): - v=v() - upd(v) - return self.m.digest() - def sig_vars(self): - bld=self.generator.bld - env=self.env - upd=self.m.update - act_sig=bld.hash_env_vars(env,self.__class__.vars) - upd(act_sig) - dep_vars=getattr(self,'dep_vars',None) - if dep_vars: - upd(bld.hash_env_vars(env,dep_vars)) - return self.m.digest() - scan=None - def sig_implicit_deps(self): - bld=self.generator.bld - key=self.uid() - prev=bld.task_sigs.get((key,'imp'),[]) - if prev: - try: - if prev==self.compute_sig_implicit_deps(): - return prev - except IOError: - pass - del bld.task_sigs[(key,'imp')] - raise Errors.TaskRescan('rescan') - (nodes,names)=self.scan() - if Logs.verbose: - Logs.debug('deps: scanner for %s returned %s %s'%(str(self),str(nodes),str(names))) - bld.node_deps[key]=nodes - bld.raw_deps[key]=names - self.are_implicit_nodes_ready() - bld.task_sigs[(key,'imp')]=sig=self.compute_sig_implicit_deps() - return sig - def compute_sig_implicit_deps(self): - upd=self.m.update - bld=self.generator.bld - env=self.env - self.are_implicit_nodes_ready() - try: - for k in bld.node_deps.get(self.uid(),[]): - upd(k.get_bld_sig()) - except AttributeError: - nodes=[] - for k in bld.node_deps.get(self.uid(),[]): - try: - k.get_bld_sig() - except AttributeError: - nodes.append(k) - raise Errors.WafError('Missing node signature for %r (for implicit dependencies %r)'%(nodes,self)) - return self.m.digest() - def are_implicit_nodes_ready(self): - bld=self.generator.bld - try: - cache=bld.dct_implicit_nodes - except: - bld.dct_implicit_nodes=cache={} - try: - dct=cache[bld.cur] - except KeyError: - dct=cache[bld.cur]={} - for tsk in bld.cur_tasks: - for x in tsk.outputs: - dct[x]=tsk - modified=False - for x in bld.node_deps.get(self.uid(),[]): - if x in dct: - self.run_after.add(dct[x]) - modified=True - if modified: - for tsk in self.run_after: - if not tsk.hasrun: - raise Errors.TaskNotReady('not ready') - def can_retrieve_cache(self): - if not getattr(self,'outputs',None): - return None - env=self.env - sig=self.signature() - ssig=Utils.to_hex(sig) - dname=os.path.join(self.generator.bld.cache_global,ssig) - try: - t1=os.stat(dname).st_mtime - except OSError: - return None - for node in self.outputs: - orig=os.path.join(dname,node.name) - try: - shutil.copy2(orig,node.abspath()) - os.utime(orig,None) - except(OSError,IOError): - Logs.debug('task: failed retrieving file') - return None - try: - t2=os.stat(dname).st_mtime - except OSError: - return None - if t1!=t2: - return None - for node in self.outputs: - node.sig=sig - if self.generator.bld.progress_bar<1: - self.generator.bld.to_log('restoring from cache %r\n'%node.abspath()) - self.cached=True - return True - def put_files_cache(self): - if getattr(self,'cached',None): - return None - sig=self.signature() - ssig=Utils.to_hex(sig) - dname=os.path.join(self.generator.bld.cache_global,ssig) - tmpdir=tempfile.mkdtemp(prefix=self.generator.bld.cache_global+os.sep+'waf') - try: - shutil.rmtree(dname) - except: - pass - try: - for node in self.outputs: - dest=os.path.join(tmpdir,node.name) - shutil.copy2(node.abspath(),dest) - except(OSError,IOError): - try: - shutil.rmtree(tmpdir) - except: - pass - else: - try: - os.rename(tmpdir,dname) - except OSError: - try: - shutil.rmtree(tmpdir) - except: - pass - else: - try: - os.chmod(dname,Utils.O755) - except: - pass -def is_before(t1,t2): - to_list=Utils.to_list - for k in to_list(t2.ext_in): - if k in to_list(t1.ext_out): - return 1 - if t1.__class__.__name__ in to_list(t2.after): - return 1 - if t2.__class__.__name__ in to_list(t1.before): - return 1 - return 0 -def set_file_constraints(tasks): - ins=Utils.defaultdict(set) - outs=Utils.defaultdict(set) - for x in tasks: - for a in getattr(x,'inputs',[])+getattr(x,'dep_nodes',[]): - ins[id(a)].add(x) - for a in getattr(x,'outputs',[]): - outs[id(a)].add(x) - links=set(ins.keys()).intersection(outs.keys()) - for k in links: - for a in ins[k]: - a.run_after.update(outs[k]) -def set_precedence_constraints(tasks): - cstr_groups=Utils.defaultdict(list) - for x in tasks: - h=x.hash_constraints() - cstr_groups[h].append(x) - keys=list(cstr_groups.keys()) - maxi=len(keys) - for i in range(maxi): - t1=cstr_groups[keys[i]][0] - for j in range(i+1,maxi): - t2=cstr_groups[keys[j]][0] - if is_before(t1,t2): - a=i - b=j - elif is_before(t2,t1): - a=j - b=i - else: - continue - for x in cstr_groups[keys[b]]: - x.run_after.update(cstr_groups[keys[a]]) -def funex(c): - dc={} - exec(c,dc) - return dc['f'] -reg_act=re.compile(r"(?P\\)|(?P\$\$)|(?P\$\{(?P\w+)(?P.*?)\})",re.M) -def compile_fun_shell(line): - extr=[] - def repl(match): - g=match.group - if g('dollar'):return"$" - elif g('backslash'):return'\\\\' - elif g('subst'):extr.append((g('var'),g('code')));return"%s" - return None - line=reg_act.sub(repl,line)or line - parm=[] - dvars=[] - app=parm.append - for(var,meth)in extr: - if var=='SRC': - if meth:app('tsk.inputs%s'%meth) - else:app('" ".join([a.path_from(bld.bldnode) for a in tsk.inputs])') - elif var=='TGT': - if meth:app('tsk.outputs%s'%meth) - else:app('" ".join([a.path_from(bld.bldnode) for a in tsk.outputs])') - elif meth: - if meth.startswith(':'): - app('" ".join([env[%r] %% x for x in env[%r]])'%(var,meth[1:])) - dvars.extend([var,meth[1:]]) - else: - app('%s%s'%(var,meth)) - else: - if not var in dvars:dvars.append(var) - app("p('%s')"%var) - if parm:parm="%% (%s) "%(',\n\t\t'.join(parm)) - else:parm='' - c=COMPILE_TEMPLATE_SHELL%(line,parm) - Logs.debug('action: %s'%c) - return(funex(c),dvars) -def compile_fun_noshell(line): - extr=[] - def repl(match): - g=match.group - if g('dollar'):return"$" - elif g('subst'):extr.append((g('var'),g('code')));return"<<|@|>>" - return None - line2=reg_act.sub(repl,line) - params=line2.split('<<|@|>>') - assert(extr) - buf=[] - dvars=[] - app=buf.append - for x in range(len(extr)): - params[x]=params[x].strip() - if params[x]: - app("lst.extend(%r)"%params[x].split()) - (var,meth)=extr[x] - if var=='SRC': - if meth:app('lst.append(tsk.inputs%s)'%meth) - else:app("lst.extend([a.path_from(bld.bldnode) for a in tsk.inputs])") - elif var=='TGT': - if meth:app('lst.append(tsk.outputs%s)'%meth) - else:app("lst.extend([a.path_from(bld.bldnode) for a in tsk.outputs])") - elif meth: - if meth.startswith(':'): - app('lst.extend([env[%r] %% x for x in env[%r]])'%(var,meth[1:])) - dvars.extend([var,meth[1:]]) - else: - app('lst.extend(gen.to_list(%s%s))'%(var,meth)) - else: - app('lst.extend(to_list(env[%r]))'%var) - if not var in dvars:dvars.append(var) - if extr: - if params[-1]: - app("lst.extend(%r)"%params[-1].split()) - fun=COMPILE_TEMPLATE_NOSHELL%"\n\t".join(buf) - Logs.debug('action: %s'%fun) - return(funex(fun),dvars) -def compile_fun(line,shell=False): - if line.find('<')>0 or line.find('>')>0 or line.find('&&')>0: - shell=True - if shell: - return compile_fun_shell(line) - else: - return compile_fun_noshell(line) -def task_factory(name,func=None,vars=[],color='GREEN',ext_in=[],ext_out=[],before=[],after=[],shell=False,scan=None): - params={'vars':vars,'color':color,'name':name,'ext_in':Utils.to_list(ext_in),'ext_out':Utils.to_list(ext_out),'before':Utils.to_list(before),'after':Utils.to_list(after),'shell':shell,'scan':scan,} - if isinstance(func,str): - params['run_str']=func - else: - params['run']=func - cls=type(Task)(name,(Task,),params) - global classes - classes[name]=cls - return cls -def always_run(cls): - old=cls.runnable_status - def always(self): - ret=old(self) - if ret==SKIP_ME: - ret=RUN_ME - return ret - cls.runnable_status=always - return cls -def update_outputs(cls): - old_post_run=cls.post_run - def post_run(self): - old_post_run(self) - for node in self.outputs: - node.sig=Utils.h_file(node.abspath()) - cls.post_run=post_run - old_runnable_status=cls.runnable_status - def runnable_status(self): - status=old_runnable_status(self) - if status!=RUN_ME: - return status - try: - bld=self.generator.bld - new_sig=self.signature() - prev_sig=bld.task_sigs[self.uid()] - if prev_sig==new_sig: - for x in self.outputs: - if not x.sig: - return RUN_ME - return SKIP_ME - except KeyError: - pass - except IndexError: - pass - return RUN_ME - cls.runnable_status=runnable_status - return cls diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/TaskGen.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/TaskGen.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/TaskGen.py +++ /dev/null @@ -1,300 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -if sys.hexversion < 0x020400f0: from sets import Set as set -import copy,re -from waflib import Task,Utils,Logs,Errors -feats=Utils.defaultdict(set) -class task_gen(object): - mappings={} - prec=Utils.defaultdict(list) - def __init__(self,*k,**kw): - self.source='' - self.target='' - self.meths=[] - self.prec=Utils.defaultdict(list) - self.mappings={} - self.features=[] - self.tasks=[] - if not'bld'in kw: - self.env=ConfigSet.ConfigSet() - self.idx=0 - self.path=None - else: - self.bld=kw['bld'] - self.env=self.bld.env.derive() - self.path=self.bld.path - try: - self.idx=self.bld.idx[id(self.path)]=self.bld.idx.get(id(self.path),0)+1 - except AttributeError: - self.bld.idx={} - self.idx=self.bld.idx[id(self.path)]=0 - for key,val in kw.items(): - setattr(self,key,val) - def __str__(self): - return""%(self.name,self.path.abspath()) - def __repr__(self): - lst=[] - for x in self.__dict__.keys(): - if x not in['env','bld','compiled_tasks','tasks']: - lst.append("%s=%r"%(x,repr(getattr(self,x)))) - return"bld(%s) in %s"%(" ".join(lst),self.path.abspath()) - def get_name(self): - try: - return self._name - except AttributeError: - if isinstance(self.target,list): - lst=[str(x)for x in self.target] - name=self._name=','.join(lst) - else: - name=self._name=str(self.target) - return name - def set_name(self,name): - self._name=name - name=property(get_name,set_name) - def to_list(self,value): - if isinstance(value,str):return value.split() - else:return value - def post(self): - if getattr(self,'posted',None): - return False - self.posted=True - keys=set(self.meths) - self.features=Utils.to_list(self.features) - for x in self.features+['*']: - st=feats[x] - if not st: - Logs.warn('feature %r does not exist - bind at least one method to it'%x) - keys.update(st) - prec={} - prec_tbl=self.prec or task_gen.prec - for x in prec_tbl: - if x in keys: - prec[x]=prec_tbl[x] - tmp=[] - for a in keys: - for x in prec.values(): - if a in x:break - else: - tmp.append(a) - out=[] - while tmp: - e=tmp.pop() - if e in keys:out.append(e) - try: - nlst=prec[e] - except KeyError: - pass - else: - del prec[e] - for x in nlst: - for y in prec: - if x in prec[y]: - break - else: - tmp.append(x) - if prec: - raise Errors.WafError('Cycle detected in the method execution %r'%prec) - out.reverse() - self.meths=out - Logs.debug('task_gen: posting %s %d'%(self,id(self))) - for x in out: - try: - v=getattr(self,x) - except AttributeError: - raise Errors.WafError('%r is not a valid task generator method'%x) - Logs.debug('task_gen: -> %s (%d)'%(x,id(self))) - v() - Logs.debug('task_gen: posted %s'%self.name) - return True - def get_hook(self,node): - name=node.name - for k in self.mappings: - if name.endswith(k): - return self.mappings[k] - for k in task_gen.mappings: - if name.endswith(k): - return task_gen.mappings[k] - raise Errors.WafError("File %r has no mapping in %r (did you forget to load a waf tool?)"%(node,task_gen.mappings.keys())) - def create_task(self,name,src=None,tgt=None): - task=Task.classes[name](env=self.env.derive(),generator=self) - if src: - task.set_inputs(src) - if tgt: - task.set_outputs(tgt) - self.tasks.append(task) - return task - def clone(self,env): - newobj=self.bld() - for x in self.__dict__: - if x in['env','bld']: - continue - elif x in['path','features']: - setattr(newobj,x,getattr(self,x)) - else: - setattr(newobj,x,copy.copy(getattr(self,x))) - newobj.posted=False - if isinstance(env,str): - newobj.env=self.bld.all_envs[env].derive() - else: - newobj.env=env.derive() - return newobj -def declare_chain(name='',rule=None,reentrant=True,color='BLUE',ext_in=[],ext_out=[],before=[],after=[],decider=None,scan=None): - ext_in=Utils.to_list(ext_in) - ext_out=Utils.to_list(ext_out) - cls=Task.task_factory(name,rule,color=color,ext_in=ext_in,ext_out=ext_out,before=before,after=after,scan=scan) - def x_file(self,node): - ext=decider and decider(self,node)or cls.ext_out - if ext_in: - _ext_in=ext_in[0] - out_source=[node.change_ext(x,ext_in=_ext_in)for x in ext] - if reentrant: - for i in range(reentrant): - self.source.append(out_source[i]) - tsk=self.create_task(name,node,out_source) - for x in cls.ext_in: - task_gen.mappings[x]=x_file - return x_file -def taskgen_method(func): - setattr(task_gen,func.__name__,func) - return func -def feature(*k): - def deco(func): - setattr(task_gen,func.__name__,func) - for name in k: - feats[name].update([func.__name__]) - return func - return deco -def before(*k): - def deco(func): - setattr(task_gen,func.__name__,func) - for fun_name in k: - if not func.__name__ in task_gen.prec[fun_name]: - task_gen.prec[fun_name].append(func.__name__) - return func - return deco -def after(*k): - def deco(func): - setattr(task_gen,func.__name__,func) - for fun_name in k: - if not fun_name in task_gen.prec[func.__name__]: - task_gen.prec[func.__name__].append(fun_name) - return func - return deco -def extension(*k): - def deco(func): - setattr(task_gen,func.__name__,func) - for x in k: - task_gen.mappings[x]=func - return func - return deco -def to_nodes(self,lst,path=None): - tmp=[] - path=path or self.path - find=path.find_resource - if isinstance(lst,self.path.__class__): - lst=[lst] - for x in Utils.to_list(lst): - if isinstance(x,str): - node=find(x) - if not node: - raise Errors.WafError("source not found: %r in %r"%(x,path)) - else: - node=x - tmp.append(node) - return tmp -def process_source(self): - self.source=self.to_nodes(getattr(self,'source',[])) - for node in self.source: - self.get_hook(node)(self,node) -def process_rule(self): - if not getattr(self,'rule',None): - return - name=str(getattr(self,'name',None)or self.target or self.rule) - cls=Task.task_factory(name,self.rule,getattr(self,'vars',[]),shell=getattr(self,'shell',True),color=getattr(self,'color','BLUE')) - tsk=self.create_task(name) - if getattr(self,'target',None): - if isinstance(self.target,str): - self.target=self.target.split() - if not isinstance(self.target,list): - self.target=[self.target] - for x in self.target: - if isinstance(x,str): - tsk.outputs.append(self.path.find_or_declare(x)) - else: - x.parent.mkdir() - tsk.outputs.append(x) - if getattr(self,'install_path',None): - self.bld.install_files(self.install_path,tsk.outputs) - if getattr(self,'source',None): - tsk.inputs=self.to_nodes(self.source) - self.source=[] - if getattr(self,'scan',None): - cls.scan=self.scan - if getattr(self,'cwd',None): - tsk.cwd=self.cwd - if getattr(self,'update_outputs',None)or getattr(self,'on_results',None): - Task.update_outputs(cls) - if getattr(self,'always',None): - Task.always_run(cls) - for x in['after','before','ext_in','ext_out']: - setattr(cls,x,getattr(self,x,[])) -def sequence_order(self): - if self.meths and self.meths[-1]!='sequence_order': - self.meths.append('sequence_order') - return - if getattr(self,'seq_start',None): - return - if getattr(self.bld,'prev',None): - self.bld.prev.post() - for x in self.bld.prev.tasks: - for y in self.tasks: - y.set_run_after(x) - self.bld.prev=self -re_m4=re.compile('@(\w+)@',re.M) -class subst_pc(Task.Task): - def run(self): - code=self.inputs[0].read() - code=code.replace('%','%%') - lst=[] - def repl(match): - g=match.group - if g(1): - lst.append(g(1)) - return"%%(%s)s"%g(1) - return'' - code=re_m4.sub(repl,code) - try: - d=self.generator.dct - except AttributeError: - d={} - for x in lst: - d[x]=getattr(self.generator,x,'')or self.env.get_flat(x)or self.env.get_flat(x.upper()) - if not d[x]and not getattr(self.generator,'quiet',False): - raise ValueError('variable %r has no value for %r'%(x,self.outputs)) - self.outputs[0].write(code%d) - self.generator.bld.raw_deps[self.uid()]=self.dep_vars=lst - try:delattr(self,'cache_sig') - except AttributeError:pass - def sig_vars(self): - bld=self.generator.bld - env=self.env - upd=self.m.update - vars=self.generator.bld.raw_deps.get(self.uid(),[]) - act_sig=bld.hash_env_vars(env,vars) - upd(act_sig) - lst=[getattr(self.generator,x,'')for x in vars] - upd(Utils.h_list(lst)) - return self.m.digest() -def add_pcfile(self,node): - tsk=self.create_task('subst_pc',node,node.change_ext('.pc','.pc.in')) - self.bld.install_files('${PREFIX}/lib/pkgconfig/',tsk.outputs) - -taskgen_method(to_nodes) -feature('*')(process_source) -feature('*')(process_rule) -before('process_source')(process_rule) -feature('seq')(sequence_order) -extension('.pc.in')(add_pcfile) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/__init__.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/__init__.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/ar.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/ar.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/ar.py +++ /dev/null @@ -1,13 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os -from waflib.Configure import conf -def find_ar(conf): - conf.load('ar') -def configure(conf): - conf.find_program('ar',var='AR') - conf.env.ARFLAGS='rcs' - -conf(find_ar) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/bison.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/bison.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/bison.py +++ /dev/null @@ -1,29 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -from waflib import Task -from waflib.TaskGen import extension -class bison(Task.Task): - color='BLUE' - run_str='${BISON} ${BISONFLAGS} ${SRC[0].abspath()} -o ${TGT[0].name}' - ext_out=['.h'] -def big_bison(self,node): - has_h='-d'in self.env['BISONFLAGS'] - outs=[] - if node.name.endswith('.yc'): - outs.append(node.change_ext('.tab.cc')) - if has_h: - outs.append(node.change_ext('.tab.hh')) - else: - outs.append(node.change_ext('.tab.c')) - if has_h: - outs.append(node.change_ext('.tab.h')) - tsk=self.create_task('bison',node,outs) - tsk.cwd=node.parent.get_bld().abspath() - self.source.append(outs[0]) -def configure(conf): - conf.find_program('bison',var='BISON') - conf.env.BISONFLAGS=['-d'] - -extension('.y','.yc','.yy')(big_bison) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c.py +++ /dev/null @@ -1,27 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -from waflib import TaskGen,Task,Utils -from waflib.Tools import c_preproc -from waflib.Tools.ccroot import link_task,stlink_task -def c_hook(self,node): - return self.create_compiled_task('c',node) -class c(Task.Task): - color='GREEN' - run_str='${CC} ${CFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT}' - vars=['CCDEPS'] - ext_in=['.h'] - scan=c_preproc.scan -Task.classes['cc']=cc=c -class cprogram(link_task): - run_str='${LINK_CC} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${LINKFLAGS}' - ext_out=['.bin'] - inst_to='${BINDIR}' - chmod=Utils.O755 -class cshlib(cprogram): - inst_to='${LIBDIR}' -class cstlib(stlink_task): - pass - -TaskGen.extension('.c')(c_hook) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_aliases.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_aliases.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_aliases.py +++ /dev/null @@ -1,67 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,re -from waflib import Utils,Build -from waflib.Configure import conf -def get_extensions(lst): - ret=[] - for x in Utils.to_list(lst): - try: - if not isinstance(x,str): - x=x.name - ret.append(x[x.rfind('.')+1:]) - except: - pass - return ret -def sniff_features(**kw): - exts=get_extensions(kw['source']) - type=kw['_type'] - if'cxx'in exts or'cpp'in exts or'c++'in exts: - if type=='program': - return'cxx cxxprogram' - if type=='shlib': - return'cxx cxxshlib' - if type=='stlib': - return'cxx cxxstlib' - return'cxx' - if'd'in exts: - if type=='program': - return'd dprogram' - if type=='shlib': - return'd dshlib' - if type=='stlib': - return'd dstlib' - return'd' - if'vala'in exts or'c'in exts: - if type=='program': - return'c cprogram' - if type=='shlib': - return'c cshlib' - if type=='stlib': - return'c cstlib' - return'c' - if'java'in exts: - return'java' - return'' -def set_features(kw,_type): - kw['_type']=_type - kw['features']=Utils.to_list(kw.get('features',[]))+Utils.to_list(sniff_features(**kw)) -def program(bld,*k,**kw): - set_features(kw,'program') - return bld(*k,**kw) -def shlib(bld,*k,**kw): - set_features(kw,'shlib') - return bld(*k,**kw) -def stlib(bld,*k,**kw): - set_features(kw,'stlib') - return bld(*k,**kw) -def objects(bld,*k,**kw): - set_features(kw,'objects') - return bld(*k,**kw) - -conf(program) -conf(shlib) -conf(stlib) -conf(objects) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_asm.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_asm.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_asm.py +++ /dev/null @@ -1,14 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys -import waflib.Task -from waflib.TaskGen import extension,feature -class asm(waflib.Task.Task): - color='BLUE' - run_str='${AS} ${ASFLAGS} ${CPPPATH_ST:INCPATHS} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}' -def asm_hook(self,node): - return self.create_compiled_task('asm',node) - -extension('.s','.S','.asm','.ASM','.spp','.SPP')(asm_hook) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_config.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_config.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_config.py +++ /dev/null @@ -1,616 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -if sys.hexversion < 0x020400f0: from sets import Set as set -import os,imp,sys,shlex,shutil -from waflib import Build,Utils,Configure,Task,Options,Logs,TaskGen,Errors,ConfigSet -from waflib.TaskGen import before,after,feature -from waflib.Configure import conf -from waflib.Utils import subprocess -WAF_CONFIG_H='config.h' -DEFKEYS='define_key' -INCKEYS='include_key' -cfg_ver={'atleast-version':'>=','exact-version':'==','max-version':'<=',} -SNIP_FUNCTION=''' - int main() { - void *p; - p=(void*)(%s); - return 0; -} -''' -SNIP_TYPE=''' -int main() { - if ((%(type_name)s *) 0) return 0; - if (sizeof (%(type_name)s)) return 0; -} -''' -SNIP_CLASS=''' -int main() { - if ( -} -''' -SNIP_EMPTY_PROGRAM=''' -int main() { - return 0; -} -''' -SNIP_FIELD=''' -int main() { - char *off; - off = (char*) &((%(type_name)s*)0)->%(field_name)s; - return (size_t) off < sizeof(%(type_name)s); -} -''' -def parse_flags(self,line,uselib,env=None): - assert(isinstance(line,str)) - env=env or self.env - app=env.append_value - appu=env.append_unique - lst=shlex.split(line) - while lst: - x=lst.pop(0) - st=x[:2] - ot=x[2:] - if st=='-I'or st=='/I': - if not ot:ot=lst.pop(0) - appu('INCLUDES_'+uselib,[ot]) - elif st=='-D': - if not ot:ot=lst.pop(0) - app('DEFINES_'+uselib,[ot]) - elif st=='-l': - if not ot:ot=lst.pop(0) - appu('LIB_'+uselib,[ot]) - elif st=='-L': - if not ot:ot=lst.pop(0) - appu('LIBPATH_'+uselib,[ot]) - elif x=='-pthread'or x.startswith('+')or x.startswith('-std'): - app('CFLAGS_'+uselib,[x]) - app('CXXFLAGS_'+uselib,[x]) - app('LINKFLAGS_'+uselib,[x]) - elif x=='-framework': - appu('FRAMEWORK_'+uselib,[lst.pop(0)]) - elif x.startswith('-F'): - appu('FRAMEWORKPATH_'+uselib,[x[2:]]) - elif x.startswith('-Wl'): - app('LINKFLAGS_'+uselib,[x]) - elif x.startswith('-m')or x.startswith('-f')or x.startswith('-dynamic'): - app('CFLAGS_'+uselib,[x]) - app('CXXFLAGS_'+uselib,[x]) - elif x.startswith('-arch')or x.startswith('-isysroot'): - tmp=[x,lst.pop(0)] - app('CFLAGS_'+uselib,tmp) - app('CXXFLAGS_'+uselib,tmp) - app('LINKFLAGS_'+uselib,tmp) - elif x.endswith('.a')or x.endswith('.so')or x.endswith('.dylib'): - appu('LINKFLAGS_'+uselib,[x]) -def ret_msg(self,f,kw): - if isinstance(f,str): - return f - return f(kw) -def validate_cfg(self,kw): - if not'path'in kw: - if not self.env.PKGCONFIG: - self.find_program('pkg-config',var='PKGCONFIG') - kw['path']=self.env.PKGCONFIG - if'atleast_pkgconfig_version'in kw: - if not'msg'in kw: - kw['msg']='Checking for pkg-config version >= %r'%kw['atleast_pkgconfig_version'] - return - if not'okmsg'in kw: - kw['okmsg']='yes' - if not'errmsg'in kw: - kw['errmsg']='not found' - if'modversion'in kw: - if not'msg'in kw: - kw['msg']='Checking for %r version'%kw['modversion'] - return - for x in cfg_ver.keys(): - y=x.replace('-','_') - if y in kw: - if not'package'in kw: - raise ValueError('%s requires a package'%x) - if not'msg'in kw: - kw['msg']='Checking for %r %s %s'%(kw['package'],cfg_ver[x],kw[y]) - return - if not'msg'in kw: - kw['msg']='Checking for %r'%(kw['package']or kw['path']) -def exec_cfg(self,kw): - if'atleast_pkgconfig_version'in kw: - cmd=[kw['path'],'--atleast-pkgconfig-version=%s'%kw['atleast_pkgconfig_version']] - self.cmd_and_log(cmd) - if not'okmsg'in kw: - kw['okmsg']='yes' - return - for x in cfg_ver: - y=x.replace('-','_') - if y in kw: - self.cmd_and_log([kw['path'],'--%s=%s'%(x,kw[y]),kw['package']]) - if not'okmsg'in kw: - kw['okmsg']='yes' - self.define(self.have_define(kw.get('uselib_store',kw['package'])),1,0) - break - if'modversion'in kw: - version=self.cmd_and_log([kw['path'],'--modversion',kw['modversion']]).strip() - self.define('%s_VERSION'%Utils.quote_define_name(kw.get('uselib_store',kw['modversion'])),version) - return version - lst=[kw['path']] - defi=kw.get('define_variable',None) - if not defi: - defi=self.env.PKG_CONFIG_DEFINES or{} - for key,val in defi.items(): - lst.append('--define-variable=%s=%s'%(key,val)) - if kw['package']: - lst.extend(Utils.to_list(kw['package'])) - if'variables'in kw: - env=kw.get('env',self.env) - uselib=kw.get('uselib_store',kw['package'].upper()) - vars=Utils.to_list(kw['variables']) - for v in vars: - val=self.cmd_and_log(lst+['--variable='+v]).strip() - var='%s_%s'%(uselib,v) - env[var]=val - if not'okmsg'in kw: - kw['okmsg']='yes' - return - if'args'in kw: - lst+=Utils.to_list(kw['args']) - ret=self.cmd_and_log(lst) - if not'okmsg'in kw: - kw['okmsg']='yes' - self.define(self.have_define(kw.get('uselib_store',kw['package'])),1,0) - self.parse_flags(ret,kw.get('uselib_store',kw['package'].upper()),kw.get('env',self.env)) - return ret -def check_cfg(self,*k,**kw): - if k: - lst=k[0].split() - kw['package']=lst[0] - kw['args']=' '.join(lst[1:]) - self.validate_cfg(kw) - if'msg'in kw: - self.start_msg(kw['msg']) - ret=None - try: - ret=self.exec_cfg(kw) - except self.errors.WafError ,e: - if'errmsg'in kw: - self.end_msg(kw['errmsg'],'YELLOW') - if Logs.verbose>1: - raise - else: - self.fatal('The configuration failed') - else: - kw['success']=ret - if'okmsg'in kw: - self.end_msg(self.ret_msg(kw['okmsg'],kw)) - return ret -def validate_c(self,kw): - if not'env'in kw: - kw['env']=self.env.derive() - env=kw['env'] - if not'compiler'in kw and not'features'in kw: - kw['compiler']='c' - if env['CXX_NAME']and Task.classes.get('cxx',None): - kw['compiler']='cxx' - if not self.env['CXX']: - self.fatal('a c++ compiler is required') - else: - if not self.env['CC']: - self.fatal('a c compiler is required') - if not'compile_mode'in kw: - kw['compile_mode']=(kw.get('compiler','')=='cxx')and'cxx'or'c' - if not'type'in kw: - kw['type']='cprogram' - if not'features'in kw: - kw['features']=[kw['compile_mode'],kw['type']] - else: - kw['features']=Utils.to_list(kw['features']) - if not'compile_filename'in kw: - kw['compile_filename']='test.c'+((kw['compile_mode']=='cxx')and'pp'or'') - def to_header(dct): - if'header_name'in dct: - dct=Utils.to_list(dct['header_name']) - return''.join(['#include <%s>\n'%x for x in dct]) - return'' - if'framework_name'in kw: - fwkname=kw['framework_name'] - if not'uselib_store'in kw: - kw['uselib_store']=fwkname.upper() - if not kw.get('no_header',False): - if not'header_name'in kw: - kw['header_name']=[] - fwk='%s/%s.h'%(fwkname,fwkname) - if kw.get('remove_dot_h',None): - fwk=fwk[:-2] - kw['header_name']=Utils.to_list(kw['header_name'])+[fwk] - kw['msg']='Checking for framework %s'%fwkname - kw['framework']=fwkname - if'function_name'in kw: - fu=kw['function_name'] - if not'msg'in kw: - kw['msg']='Checking for function %s'%fu - kw['code']=to_header(kw)+SNIP_FUNCTION%fu - if not'uselib_store'in kw: - kw['uselib_store']=fu.upper() - if not'define_name'in kw: - kw['define_name']=self.have_define(fu) - elif'type_name'in kw: - tu=kw['type_name'] - if not'header_name'in kw: - kw['header_name']='stdint.h' - if'field_name'in kw: - field=kw['field_name'] - kw['code']=to_header(kw)+SNIP_FIELD%{'type_name':tu,'field_name':field} - if not'msg'in kw: - kw['msg']='Checking for field %s in %s'%(field,tu) - if not'define_name'in kw: - kw['define_name']=self.have_define((tu+'_'+field).upper()) - else: - kw['code']=to_header(kw)+SNIP_TYPE%{'type_name':tu} - if not'msg'in kw: - kw['msg']='Checking for type %s'%tu - if not'define_name'in kw: - kw['define_name']=self.have_define(tu.upper()) - elif'header_name'in kw: - if not'msg'in kw: - kw['msg']='Checking for header %s'%kw['header_name'] - l=Utils.to_list(kw['header_name']) - assert len(l)>0,'list of headers in header_name is empty' - kw['code']=to_header(kw)+SNIP_EMPTY_PROGRAM - if not'uselib_store'in kw: - kw['uselib_store']=l[0].upper() - if not'define_name'in kw: - kw['define_name']=self.have_define(l[0]) - if'lib'in kw: - if not'msg'in kw: - kw['msg']='Checking for library %s'%kw['lib'] - if not'uselib_store'in kw: - kw['uselib_store']=kw['lib'].upper() - if'stlib'in kw: - if not'msg'in kw: - kw['msg']='Checking for static library %s'%kw['stlib'] - if not'uselib_store'in kw: - kw['uselib_store']=kw['stlib'].upper() - if'fragment'in kw: - kw['code']=kw['fragment'] - if not'msg'in kw: - kw['msg']='Checking for code snippet' - if not'errmsg'in kw: - kw['errmsg']='no' - for(flagsname,flagstype)in[('cxxflags','compiler'),('cflags','compiler'),('linkflags','linker')]: - if flagsname in kw: - if not'msg'in kw: - kw['msg']='Checking for %s flags %s'%(flagstype,kw[flagsname]) - if not'errmsg'in kw: - kw['errmsg']='no' - if not'execute'in kw: - kw['execute']=False - if kw['execute']: - kw['features'].append('test_exec') - if not'errmsg'in kw: - kw['errmsg']='not found' - if not'okmsg'in kw: - kw['okmsg']='yes' - if not'code'in kw: - kw['code']=SNIP_EMPTY_PROGRAM - if self.env[INCKEYS]: - kw['code']='\n'.join(['#include <%s>'%x for x in self.env[INCKEYS]])+'\n'+kw['code'] - if not kw.get('success'):kw['success']=None - assert'msg'in kw,'invalid parameters, read http://freehackers.org/~tnagy/wafbook/single.html#config_helpers_c' -def post_check(self,*k,**kw): - is_success=0 - if kw['execute']: - if kw['success']is not None: - if kw.get('define_ret',False): - is_success=kw['success'] - else: - is_success=(kw['success']==0) - else: - is_success=(kw['success']==0) - def define_or_stuff(): - nm=kw['define_name'] - if kw['execute']and kw.get('define_ret',None)and isinstance(is_success,str): - self.define(kw['define_name'],is_success,quote=kw.get('quote',1)) - else: - self.define_cond(kw['define_name'],is_success) - if'define_name'in kw: - if'header_name'in kw or'function_name'in kw or'type_name'in kw or'fragment'in kw: - define_or_stuff() - if'header_name'in kw: - if kw.get('auto_add_header_name',False): - self.env.append_value(INCKEYS,Utils.to_list(kw['header_name'])) - if is_success and'uselib_store'in kw: - from waflib.Tools import ccroot - _vars=set([]) - for x in kw['features']: - if x in ccroot.USELIB_VARS: - _vars|=ccroot.USELIB_VARS[x] - for k in _vars: - lk=k.lower() - if k=='INCLUDES':lk='includes' - if k=='DEFINES':lk='defines' - if lk in kw: - val=kw[lk] - if isinstance(val,str): - val=val.rstrip(os.path.sep) - self.env.append_unique(k+'_'+kw['uselib_store'],val) -def check(self,*k,**kw): - self.validate_c(kw) - self.start_msg(kw['msg']) - ret=None - try: - ret=self.run_c_code(*k,**kw) - except self.errors.ConfigurationError ,e: - self.end_msg(kw['errmsg'],'YELLOW') - if Logs.verbose>1: - raise - else: - self.fatal('The configuration failed') - else: - kw['success']=ret - self.end_msg(self.ret_msg(kw['okmsg'],kw)) - self.post_check(*k,**kw) - if isinstance(ret,int): - return ret==0 - return ret -class test_exec_task(Task.Task): - color='PINK' - def run(self): - if getattr(self.generator,'rpath',None): - if getattr(self.generator,'define_ret',False): - self.generator.bld.retval=self.generator.bld.cmd_and_log([self.inputs[0].abspath()]) - else: - self.generator.bld.retval=self.generator.bld.exec_command([self.inputs[0].abspath()]) - else: - env={} - env.update(dict(os.environ)) - env['LD_LIBRARY_PATH']=self.inputs[0].parent.abspath() - if getattr(self.generator,'define_ret',False): - self.generator.bld.retval=self.generator.bld.cmd_and_log([self.inputs[0].abspath()],env=env) - else: - self.generator.bld.retval=self.generator.bld.exec_command([self.inputs[0].abspath()],env=env) -def test_exec_fun(self): - self.create_task('test_exec',self.link_task.outputs[0]) -CACHE_RESULTS=1 -COMPILE_ERRORS=2 -def run_c_code(self,*k,**kw): - lst=[str(v)for(p,v)in kw.items()if p!='env'] - h=Utils.h_list(lst) - dir=self.bldnode.abspath()+os.sep+(sys.platform!='win32'and'.'or'')+'conf_check_'+Utils.to_hex(h) - try: - os.makedirs(dir) - except: - pass - try: - os.stat(dir) - except: - self.fatal('cannot use the configuration test folder %r'%dir) - cachemode=getattr(Options.options,'confcache',None) - if cachemode==CACHE_RESULTS: - try: - proj=ConfigSet.ConfigSet(os.path.join(dir,'cache_run_c_code')) - ret=proj['cache_run_c_code'] - except: - pass - else: - if isinstance(ret,str)and ret.startswith('Test does not build'): - self.fatal(ret) - return ret - bdir=os.path.join(dir,'testbuild') - if not os.path.exists(bdir): - os.makedirs(bdir) - self.test_bld=bld=Build.BuildContext(top_dir=dir,out_dir=bdir) - bld.init_dirs() - bld.progress_bar=0 - bld.targets='*' - if kw['compile_filename']: - node=bld.srcnode.make_node(kw['compile_filename']) - node.write(kw['code']) - bld.logger=self.logger - bld.all_envs.update(self.all_envs) - bld.env=kw['env'] - o=bld(features=kw['features'],source=kw['compile_filename'],target='testprog') - for k,v in kw.items(): - setattr(o,k,v) - self.to_log("==>\n%s\n<=="%kw['code']) - bld.targets='*' - ret=-1 - try: - try: - bld.compile() - except Errors.WafError: - ret='Test does not build: %s'%Utils.ex_stack() - self.fatal(ret) - else: - ret=getattr(bld,'retval',0) - finally: - proj=ConfigSet.ConfigSet() - proj['cache_run_c_code']=ret - proj.store(os.path.join(dir,'cache_run_c_code')) - return ret -def check_cxx(self,*k,**kw): - kw['compiler']='cxx' - return self.check(*k,**kw) -def check_cc(self,*k,**kw): - kw['compiler']='c' - return self.check(*k,**kw) -def define(self,key,val,quote=True): - assert key and isinstance(key,str) - if isinstance(val,int)or isinstance(val,float): - s='%s=%s' - else: - s=quote and'%s="%s"'or'%s=%s' - app=s%(key,str(val)) - ban=key+'=' - lst=self.env['DEFINES'] - for x in lst: - if x.startswith(ban): - lst[lst.index(x)]=app - break - else: - self.env.append_value('DEFINES',app) - self.env.append_unique(DEFKEYS,key) -def undefine(self,key): - assert key and isinstance(key,str) - ban=key+'=' - lst=[x for x in self.env['DEFINES']if not x.startswith(ban)] - self.env['DEFINES']=lst - self.env.append_unique(DEFKEYS,key) -def define_cond(self,key,val): - assert key and isinstance(key,str) - if val: - self.define(key,1) - else: - self.undefine(key) -def is_defined(self,key): - assert key and isinstance(key,str) - ban=key+'=' - for x in self.env['DEFINES']: - if x.startswith(ban): - return True - return False -def get_define(self,key): - assert key and isinstance(key,str) - ban=key+'=' - for x in self.env['DEFINES']: - if x.startswith(ban): - return x[len(ban):] - return None -def have_define(self,key): - return self.__dict__.get('HAVE_PAT','HAVE_%s')%Utils.quote_define_name(key) -def write_config_header(self,configfile='',guard='',top=False,env=None,defines=True,headers=False,remove=True): - if not configfile:configfile=WAF_CONFIG_H - waf_guard=guard or'_%s_WAF'%Utils.quote_define_name(configfile) - node=top and self.bldnode or self.path.get_bld() - node=node.make_node(configfile) - node.parent.mkdir() - lst=['/* WARNING! All changes made to this file will be lost! */\n'] - lst.append('#ifndef %s\n#define %s\n'%(waf_guard,waf_guard)) - lst.append(self.get_config_header(defines,headers)) - lst.append('\n#endif /* %s */\n'%waf_guard) - node.write('\n'.join(lst)) - env=env or self.env - env.append_unique(Build.CFG_FILES,[node.abspath()]) - if remove: - for key in self.env[DEFKEYS]: - self.undefine(key) - self.env[DEFKEYS]=[] -def get_config_header(self,defines=True,headers=False): - lst=[] - if headers: - for x in self.env[INCKEYS]: - lst.append('#include <%s>'%x) - if defines: - for x in self.env[DEFKEYS]: - if self.is_defined(x): - val=self.get_define(x) - lst.append('#define %s %s'%(x,val)) - else: - lst.append('/* #undef %s */'%x) - return"\n".join(lst) -def cc_add_flags(conf): - conf.add_os_flags('CFLAGS') -def cxx_add_flags(conf): - conf.add_os_flags('CXXFLAGS') -def link_add_flags(conf): - conf.add_os_flags('LINKFLAGS') - conf.add_os_flags('LDFLAGS','LINKFLAGS') -def cc_load_tools(conf): - if not conf.env.DEST_OS: - conf.env.DEST_OS=Utils.unversioned_sys_platform() - conf.load('c') -def cxx_load_tools(conf): - if not conf.env.DEST_OS: - conf.env.DEST_OS=Utils.unversioned_sys_platform() - conf.load('cxx') -def get_cc_version(conf,cc,gcc=False,icc=False): - cmd=cc+['-dM','-E','-'] - try: - p=subprocess.Popen(cmd,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - p.stdin.write('\n') - out=p.communicate()[0] - except: - conf.fatal('could not determine the compiler version %r'%cmd) - if not isinstance(out,str): - out=out - if gcc: - if out.find('__INTEL_COMPILER')>=0: - conf.fatal('The intel compiler pretends to be gcc') - if out.find('__GNUC__')<0: - conf.fatal('Could not determine the compiler type') - if icc and out.find('__INTEL_COMPILER')<0: - conf.fatal('Not icc/icpc') - k={} - if icc or gcc: - out=out.split('\n') - import shlex - for line in out: - lst=shlex.split(line) - if len(lst)>2: - key=lst[1] - val=lst[2] - k[key]=val - def isD(var): - return var in k - def isT(var): - return var in k and k[var]!='0' - mp1={'__linux__':'linux','__GNU__':'gnu','__FreeBSD__':'freebsd','__NetBSD__':'netbsd','__OpenBSD__':'openbsd','__sun':'sunos','__hpux':'hpux','__sgi':'irix','_AIX':'aix','__CYGWIN__':'cygwin','__MSYS__':'msys','_UWIN':'uwin','_WIN64':'win32','_WIN32':'win32','__POWERPC__':'powerpc',} - for i in mp1: - if isD(i): - conf.env.DEST_OS=mp1[i] - break - else: - if isD('__APPLE__')and isD('__MACH__'): - conf.env.DEST_OS='darwin' - elif isD('__unix__'): - conf.env.DEST_OS='generic' - if isD('__ELF__'): - conf.env.DEST_BINFMT='elf' - elif isD('__WINNT__')or isD('__CYGWIN__'): - conf.env.DEST_BINFMT='pe' - conf.env.LIBDIR=conf.env['PREFIX']+'/bin' - elif isD('__APPLE__'): - conf.env.DEST_BINFMT='mac-o' - if not conf.env.DEST_BINFMT: - conf.env.DEST_BINFMT=Utils.destos_to_binfmt(conf.env.DEST_OS) - mp2={'__x86_64__':'x86_64','__i386__':'x86','__ia64__':'ia','__mips__':'mips','__sparc__':'sparc','__alpha__':'alpha','__arm__':'arm','__hppa__':'hppa','__powerpc__':'powerpc',} - for i in mp2: - if isD(i): - conf.env.DEST_CPU=mp2[i] - break - Logs.debug('ccroot: dest platform: '+' '.join([conf.env[x]or'?'for x in('DEST_OS','DEST_BINFMT','DEST_CPU')])) - conf.env['CC_VERSION']=(k['__GNUC__'],k['__GNUC_MINOR__'],k['__GNUC_PATCHLEVEL__']) - return k -def add_as_needed(self): - if self.env.DEST_BINFMT=='elf'and'gcc'in(self.env.CXX_NAME,self.env.CC_NAME): - self.env.append_unique('LINKFLAGS','--as-needed') - -conf(parse_flags) -conf(ret_msg) -conf(validate_cfg) -conf(exec_cfg) -conf(check_cfg) -conf(validate_c) -conf(post_check) -conf(check) -feature('test_exec')(test_exec_fun) -after('apply_link')(test_exec_fun) -conf(run_c_code) -conf(check_cxx) -conf(check_cc) -conf(define) -conf(undefine) -conf(define_cond) -conf(is_defined) -conf(get_define) -conf(have_define) -conf(write_config_header) -conf(get_config_header) -conf(cc_add_flags) -conf(cxx_add_flags) -conf(link_add_flags) -conf(cc_load_tools) -conf(cxx_load_tools) -conf(get_cc_version) -conf(add_as_needed) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_osx.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_osx.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_osx.py +++ /dev/null @@ -1,114 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,shutil,sys,platform -from waflib import TaskGen,Task,Build,Options,Utils -from waflib.TaskGen import taskgen_method,feature,after,before -app_info=''' - - - - - CFBundlePackageType - APPL - CFBundleGetInfoString - Created by Waf - CFBundleSignature - ???? - NOTE - THIS IS A GENERATED FILE, DO NOT MODIFY - CFBundleExecutable - %s - - -''' -def set_macosx_deployment_target(self): - if self.env['MACOSX_DEPLOYMENT_TARGET']: - os.environ['MACOSX_DEPLOYMENT_TARGET']=self.env['MACOSX_DEPLOYMENT_TARGET'] - elif'MACOSX_DEPLOYMENT_TARGET'not in os.environ: - if sys.platform=='darwin': - os.environ['MACOSX_DEPLOYMENT_TARGET']='.'.join(platform.mac_ver()[0].split('.')[:2]) -def create_bundle_dirs(self,name,out): - bld=self.bld - dir=out.parent.get_dir(name) - if not dir: - dir=out.__class__(name,out.parent,1) - bld.rescan(dir) - contents=out.__class__('Contents',dir,1) - bld.rescan(contents) - macos=out.__class__('MacOS',contents,1) - bld.rescan(macos) - return dir -def bundle_name_for_output(out): - name=out.name - k=name.rfind('.') - if k>=0: - name=name[:k]+'.app' - else: - name=name+'.app' - return name -def create_task_macapp(self): - if self.env['MACAPP']or getattr(self,'mac_app',False): - apptask=self.create_task('macapp') - apptask.set_inputs(self.link_task.outputs) - out=self.link_task.outputs[0] - name=bundle_name_for_output(out) - dir=self.create_bundle_dirs(name,out) - n1=dir.find_or_declare(['Contents','MacOS',out.name]) - apptask.set_outputs([n1]) - apptask.chmod=Utils.O755 - apptask.install_path=os.path.join(self.install_path,name,'Contents','MacOS') - self.apptask=apptask -def create_task_macplist(self): - if self.env['MACAPP']or getattr(self,'mac_app',False): - if not getattr(self,'mac_plist',False): - self.mac_plist=app_info - plisttask=self.create_task('macplist') - plisttask.set_inputs(self.link_task.outputs) - out=self.link_task.outputs[0] - self.mac_plist=self.mac_plist%(out.name) - name=bundle_name_for_output(out) - dir=self.create_bundle_dirs(name,out) - n1=dir.find_or_declare(['Contents','Info.plist']) - plisttask.set_outputs([n1]) - plisttask.mac_plist=self.mac_plist - plisttask.install_path=os.path.join(self.install_path,name,'Contents') - self.plisttask=plisttask -def apply_bundle(self): - if not('cshlib'in self.features or'cxxshlib'in self.features): - return - if self.env['MACBUNDLE']or getattr(self,'mac_bundle',False): - self.env['cshlib_PATTERN']=self.env['cxxshlib_PATTERN']=self.env['macbundle_PATTERN'] - uselib=self.uselib=self.to_list(getattr(self,'use',[])) - if not'MACBUNDLE'in uselib: - uselib.append('MACBUNDLE') -def apply_bundle_remove_dynamiclib(self): - if self.env['MACBUNDLE']or getattr(self,'mac_bundle',False): - if not getattr(self,'vnum',None): - try: - self.env['LINKFLAGS'].remove('-dynamiclib') - except ValueError: - pass -app_dirs=['Contents','Contents/MacOS','Contents/Resources'] -class macapp(Task.Task): - color='PINK' - def run(self): - shutil.copy2(self.inputs[0].srcpath(),self.outputs[0].abspath(self.env)) -class macplist(Task.Task): - color='PINK' - ext_in=['.bin'] - def run(self): - self.outputs[0].write(self.mac_plist) - -feature('c','cxx')(set_macosx_deployment_target) -before('apply_lib_vars')(set_macosx_deployment_target) -taskgen_method(create_bundle_dirs) -feature('cprogram','cxxprogram')(create_task_macapp) -after('apply_link')(create_task_macapp) -feature('cprogram','cxxprogram')(create_task_macplist) -after('apply_link')(create_task_macplist) -feature('c','cxx')(apply_bundle) -before('apply_link','propagate_uselib_vars')(apply_bundle) -feature('cshlib','cxxshlib')(apply_bundle_remove_dynamiclib) -after('apply_link')(apply_bundle_remove_dynamiclib) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_preproc.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_preproc.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_preproc.py +++ /dev/null @@ -1,594 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -if sys.hexversion < 0x020400f0: from sets import Set as set -import re,sys,os,string,traceback -from waflib import Logs,Build,Utils,Errors -from waflib.Logs import debug,error -class PreprocError(Errors.WafError): - pass -POPFILE='-' -go_absolute=False -standard_includes=['/usr/include'] -if sys.platform=="win32": - standard_includes=[] -use_trigraphs=0 -'apply the trigraph rules first' -strict_quotes=0 -g_optrans={'not':'!','and':'&&','bitand':'&','and_eq':'&=','or':'||','bitor':'|','or_eq':'|=','xor':'^','xor_eq':'^=','compl':'~',} -re_lines=re.compile('^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*)\r*$',re.IGNORECASE|re.MULTILINE) -re_mac=re.compile("^[a-zA-Z_]\w*") -re_fun=re.compile('^[a-zA-Z_][a-zA-Z0-9_]*[(]') -re_pragma_once=re.compile('^\s*once\s*',re.IGNORECASE) -re_nl=re.compile('\\\\\r*\n',re.MULTILINE) -re_cpp=re.compile(r"""(/\*[^*]*\*+([^/*][^*]*\*+)*/)|//[^\n]*|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)""",re.MULTILINE) -trig_def=[('??'+a,b)for a,b in zip("=-/!'()<>",r'#~\|^[]{}')] -chr_esc={'0':0,'a':7,'b':8,'t':9,'n':10,'f':11,'v':12,'r':13,'\\':92,"'":39} -NUM='i' -OP='O' -IDENT='T' -STR='s' -CHAR='c' -tok_types=[NUM,STR,IDENT,OP] -exp_types=[r"""0[xX](?P[a-fA-F0-9]+)(?P[uUlL]*)|L*?'(?P(\\.|[^\\'])+)'|(?P\d+)[Ee](?P[+-]*?\d+)(?P[fFlL]*)|(?P\d*\.\d+)([Ee](?P[+-]*?\d+))?(?P[fFlL]*)|(?P\d+\.\d*)([Ee](?P[+-]*?\d+))?(?P[fFlL]*)|(?P0*)(?P\d+)(?P[uUlL]*)""",r'L?"([^"\\]|\\.)*"',r'[a-zA-Z_]\w*',r'%:%:|<<=|>>=|\.\.\.|<<|<%|<:|<=|>>|>=|\+\+|\+=|--|->|-=|\*=|/=|%:|%=|%>|==|&&|&=|\|\||\|=|\^=|:>|!=|##|[\(\)\{\}\[\]<>\?\|\^\*\+&=:!#;,%/\-\?\~\.]',] -re_clexer=re.compile('|'.join(["(?P<%s>%s)"%(name,part)for name,part in zip(tok_types,exp_types)]),re.M) -accepted='a' -ignored='i' -undefined='u' -skipped='s' -def repl(m): - s=m.group(1) - if s: - return' ' - return m.group(3)or'' -def filter_comments(filename): - code=Utils.readf(filename) - if use_trigraphs: - for(a,b)in trig_def:code=code.split(a).join(b) - code=re_nl.sub('',code) - code=re_cpp.sub(repl,code) - return[(m.group(2),m.group(3))for m in re.finditer(re_lines,code)] -prec={} -ops=['* / %','+ -','<< >>','< <= >= >','== !=','& | ^','&& ||',','] -for x in range(len(ops)): - syms=ops[x] - for u in syms.split(): - prec[u]=x -def trimquotes(s): - if not s:return'' - s=s.rstrip() - if s[0]=="'"and s[-1]=="'":return s[1:-1] - return s -def reduce_nums(val_1,val_2,val_op): - try:a=0+val_1 - except TypeError:a=int(val_1) - try:b=0+val_2 - except TypeError:b=int(val_2) - d=val_op - if d=='%':c=a%b - elif d=='+':c=a+b - elif d=='-':c=a-b - elif d=='*':c=a*b - elif d=='/':c=a/b - elif d=='^':c=a^b - elif d=='|':c=a|b - elif d=='||':c=int(a or b) - elif d=='&':c=a&b - elif d=='&&':c=int(a and b) - elif d=='==':c=int(a==b) - elif d=='!=':c=int(a!=b) - elif d=='<=':c=int(a<=b) - elif d=='<':c=int(a':c=int(a>b) - elif d=='>=':c=int(a>=b) - elif d=='^':c=int(a^b) - elif d=='<<':c=a<>':c=a>>b - else:c=0 - return c -def get_num(lst): - if not lst:raise PreprocError("empty list for get_num") - (p,v)=lst[0] - if p==OP: - if v=='(': - count_par=1 - i=1 - while i=prec[v]: - num2=reduce_nums(num,num2,v) - return get_term([(NUM,num2)]+lst) - else: - num3,lst=get_num(lst[1:]) - num3=reduce_nums(num2,num3,v2) - return get_term([(NUM,num),(p,v),(NUM,num3)]+lst) - raise PreprocError("cannot reduce %r"%lst) -def reduce_eval(lst): - num,lst=get_term(lst) - return(NUM,num) -def stringize(lst): - lst=[str(v2)for(p2,v2)in lst] - return"".join(lst) -def paste_tokens(t1,t2): - p1=None - if t1[0]==OP and t2[0]==OP: - p1=OP - elif t1[0]==IDENT and(t2[0]==IDENT or t2[0]==NUM): - p1=IDENT - elif t1[0]==NUM and t2[0]==NUM: - p1=NUM - if not p1: - raise PreprocError('tokens do not make a valid paste %r and %r'%(t1,t2)) - return(p1,t1[1]+t2[1]) -def reduce_tokens(lst,defs,ban=[]): - i=0 - while i=len(lst): - raise PreprocError("expected '(' after %r (got nothing)"%v) - (p2,v2)=lst[i] - if p2!=OP or v2!='(': - raise PreprocError("expected '(' after %r"%v) - del lst[i] - one_param=[] - count_paren=0 - while i1: - (p3,v3)=accu[-1] - (p4,v4)=accu[-2] - if v3=='##': - accu.pop() - if v4==','and pt.*)>|"(?P.*)")') -def extract_include(txt,defs): - m=re_include.search(txt) - if m: - if m.group('a'):return'<',m.group('a') - if m.group('b'):return'"',m.group('b') - toks=tokenize(txt) - reduce_tokens(toks,defs,['waf_include']) - if not toks: - raise PreprocError("could not parse include %s"%txt) - if len(toks)==1: - if toks[0][0]==STR: - return'"',toks[0][1] - else: - if toks[0][1]=='<'and toks[-1][1]=='>': - return stringize(toks).lstrip('<').rstrip('>') - raise PreprocError("could not parse include %s."%txt) -def parse_char(txt): - if not txt:raise PreprocError("attempted to parse a null char") - if txt[0]!='\\': - return ord(txt) - c=txt[1] - if c=='x': - if len(txt)==4 and txt[3]in string.hexdigits:return int(txt[2:],16) - return int(txt[2:],16) - elif c.isdigit(): - if c=='0'and len(txt)==2:return 0 - for i in 3,2,1: - if len(txt)>i and txt[1:1+i].isdigit(): - return(1+i,int(txt[1:1+i],8)) - else: - try:return chr_esc[c] - except KeyError:raise PreprocError("could not parse char literal '%s'"%txt) -def tokenize(s): - ret=[] - for match in re_clexer.finditer(s): - m=match.group - for name in tok_types: - v=m(name) - if v: - if name==IDENT: - try:v=g_optrans[v];name=OP - except KeyError: - if v.lower()=="true": - v=1 - name=NUM - elif v.lower()=="false": - v=0 - name=NUM - elif name==NUM: - if m('oct'):v=int(v,8) - elif m('hex'):v=int(m('hex'),16) - elif m('n0'):v=m('n0') - else: - v=m('char') - if v:v=parse_char(v) - else:v=m('n2')or m('n4') - elif name==OP: - if v=='%:':v='#' - elif v=='%:%:':v='##' - elif name==STR: - v=v[1:-1] - ret.append((name,v)) - break - return ret -def define_name(line): - return re_mac.match(line).group(0) -class c_parser(object): - def __init__(self,nodepaths=None,defines=None): - self.lines=[] - if defines is None: - self.defs={} - else: - self.defs=dict(defines) - self.state=[] - self.count_files=0 - self.currentnode_stack=[] - self.nodepaths=nodepaths or[] - self.nodes=[] - self.names=[] - self.curfile='' - self.ban_includes=set([]) - def cached_find_resource(self,node,filename): - try: - nd=node.ctx.cache_nd - except: - nd=node.ctx.cache_nd={} - tup=(node,filename) - try: - return nd[tup] - except KeyError: - ret=node.find_resource(filename) - nd[tup]=ret - return ret - def tryfind(self,filename): - self.curfile=filename - found=self.cached_find_resource(self.currentnode_stack[-1],filename) - for n in self.nodepaths: - if found: - break - found=self.cached_find_resource(n,filename) - if found: - self.nodes.append(found) - if filename[-4:]!='.moc': - self.addlines(found) - else: - if not filename in self.names: - self.names.append(filename) - return found - def addlines(self,node): - self.currentnode_stack.append(node.parent) - filepath=node.abspath() - self.count_files+=1 - if self.count_files>9000:raise PreprocError("recursion limit exceeded") - pc=self.parse_cache - debug('preproc: reading file %r',filepath) - try: - lns=pc[filepath] - except KeyError: - pass - else: - self.lines.extend(lns) - return - try: - lines=filter_comments(filepath) - lines.append((POPFILE,'')) - lines.reverse() - pc[filepath]=lines - self.lines.extend(lines) - except IOError: - raise PreprocError("could not read the file %s"%filepath) - except Exception: - if Logs.verbose>0: - error("parsing %s failed"%filepath) - traceback.print_exc() - def start(self,node,env): - debug('preproc: scanning %s (in %s)',node.name,node.parent.name) - bld=node.ctx - try: - self.parse_cache=bld.parse_cache - except AttributeError: - bld.parse_cache={} - self.parse_cache=bld.parse_cache - self.addlines(node) - if env['DEFINES']: - lst=['%s %s'%(x[0],trimquotes('='.join(x[1:])))for x in[y.split('=')for y in env['DEFINES']]] - lst.reverse() - self.lines.extend([('define',x)for x in lst]) - while self.lines: - (token,line)=self.lines.pop() - if token==POPFILE: - self.currentnode_stack.pop() - continue - try: - ve=Logs.verbose - if ve:debug('preproc: line is %s - %s state is %s',token,line,self.state) - state=self.state - if token[:2]=='if': - state.append(undefined) - elif token=='endif': - state.pop() - if token[0]!='e': - if skipped in self.state or ignored in self.state: - continue - if token=='if': - ret=eval_macro(tokenize(line),self.defs) - if ret:state[-1]=accepted - else:state[-1]=ignored - elif token=='ifdef': - m=re_mac.match(line) - if m and m.group(0)in self.defs:state[-1]=accepted - else:state[-1]=ignored - elif token=='ifndef': - m=re_mac.match(line) - if m and m.group(0)in self.defs:state[-1]=ignored - else:state[-1]=accepted - elif token=='include'or token=='import': - (kind,inc)=extract_include(line,self.defs) - if inc in self.ban_includes: - continue - if token=='import':self.ban_includes.add(inc) - if ve:debug('preproc: include found %s (%s) ',inc,kind) - if kind=='"'or not strict_quotes: - self.tryfind(inc) - elif token=='elif': - if state[-1]==accepted: - state[-1]=skipped - elif state[-1]==ignored: - if eval_macro(tokenize(line),self.defs): - state[-1]=accepted - elif token=='else': - if state[-1]==accepted:state[-1]=skipped - elif state[-1]==ignored:state[-1]=accepted - elif token=='define': - try: - self.defs[define_name(line)]=line - except: - raise PreprocError("invalid define line %s"%line) - elif token=='undef': - m=re_mac.match(line) - if m and m.group(0)in self.defs: - self.defs.__delitem__(m.group(0)) - elif token=='pragma': - if re_pragma_once.match(line.lower()): - self.ban_includes.add(self.curfile) - except Exception ,e: - if Logs.verbose: - debug('preproc: line parsing failed (%s): %s %s',e,line,Utils.ex_stack()) -def scan(task): - global go_absolute - try: - incn=task.generator.includes_nodes - except AttributeError: - raise Errors.WafError('%r is missing a feature such as "c" or "cxx"'%task.generator) - if go_absolute: - nodepaths=incn - else: - nodepaths=[x for x in incn if x.is_child_of(x.ctx.srcnode)or x.is_child_of(x.ctx.bldnode)] - tmp=c_parser(nodepaths) - tmp.start(task.inputs[0],task.env) - if Logs.verbose: - debug('deps: deps for %r: %r; unresolved %r'%(task.inputs,tmp.nodes,tmp.names)) - return(tmp.nodes,tmp.names) - -Utils.run_once(tokenize) -Utils.run_once(define_name) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_tests.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_tests.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_tests.py +++ /dev/null @@ -1,108 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -from waflib.Configure import conf -from waflib.TaskGen import feature,before -import sys -LIB_CODE=''' -#ifdef _MSC_VER -#define testEXPORT __declspec(dllexport) -#else -#define testEXPORT -#endif -testEXPORT int lib_func(void) { return 9; } -''' -MAIN_CODE=''' -#ifdef _MSC_VER -#define testEXPORT __declspec(dllimport) -#else -#define testEXPORT -#endif -testEXPORT int lib_func(void); -int main(void) {return !(lib_func() == 9);} -''' -def link_lib_test_fun(self): - def write_test_file(task): - task.outputs[0].write(task.generator.code) - rpath=[] - if getattr(self,'add_rpath',False): - rpath=[self.bld.path.get_bld().abspath()] - mode=self.mode - m='%s %s'%(mode,mode) - bld=self.bld - bld(rule=write_test_file,target='test.c',code=LIB_CODE) - bld(rule=write_test_file,target='main.c',code=MAIN_CODE) - bld(features=m+'shlib',source='test.c',target='test') - bld(features=m+'program test_exec',source='main.c',target='app',use='test',rpath=rpath) -def check_library(self,mode=None): - if not mode: - mode='c' - if self.env.CXX: - mode='cxx' - self.check(compile_filename=[],features='link_lib_test',msg='Checking for libraries',mode=mode) -INLINE_CODE=''' -typedef int foo_t; -static %s foo_t static_foo () {return 0; } -%s foo_t foo () { - return 0; -} -''' -INLINE_VALUES=['inline','__inline__','__inline'] -def check_inline(self,**kw): - self.start_msg('Checking for inline') - if not'define_name'in kw: - kw['define_name']='INLINE_MACRO' - if not'features'in kw: - if self.env.CXX: - kw['features']=['cxx'] - else: - kw['features']=['c'] - for x in INLINE_VALUES: - kw['fragment']=INLINE_CODE%(x,x) - try: - self.check(**kw) - except self.errors.ConfigurationError: - continue - else: - self.end_msg(x) - if x!='inline': - self.define('inline',x,quote=False) - return x - self.fatal('could not use inline functions') -LARGE_FRAGMENT='#include \nint main() { return !(sizeof(off_t) >= 8); };' -def check_large_file(self,**kw): - if not'define_name'in kw: - kw['define_name']='HAVE_LARGEFILE' - if not'execute'in kw: - kw['execute']=True - if not'features'in kw: - if self.env.CXX: - kw['features']=['cxx','cxxprogram'] - else: - kw['features']=['c','cprogram'] - kw['fragment']=LARGE_FRAGMENT - kw['msg']='Checking for large file support' - try: - if self.env.DEST_BINFMT!='pe': - self.check(**kw) - except self.errors.ConfigurationError: - pass - else: - return True - kw['msg']='Checking for -D_FILE_OFFSET_BITS=64' - kw['defines']=['_FILE_OFFSET_BITS=64'] - try: - self.check(**kw) - except self.errors.ConfigurationError: - pass - else: - self.define('_FILE_OFFSET_BITS',64) - return True - self.fatal('There is no support for large files') - -feature('link_lib_test')(link_lib_test_fun) -before('process_source')(link_lib_test_fun) -conf(check_library) -conf(check_inline) -conf(check_large_file) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_use.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_use.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/c_use.py +++ /dev/null @@ -1,4 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/ccroot.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/ccroot.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/ccroot.py +++ /dev/null @@ -1,285 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -if sys.hexversion < 0x020400f0: from sets import Set as set -import os,sys,re -from waflib import TaskGen,Task,Utils,Logs,Build,Options,Node,Errors -from waflib.Logs import error,debug,warn -from waflib.TaskGen import after,before,feature,taskgen_method -from waflib.Tools import c_aliases,c_preproc,c_config,c_asm,c_osx,c_tests -from waflib.Configure import conf -USELIB_VARS=Utils.defaultdict(set) -USELIB_VARS['c']=set(['INCLUDES','FRAMEWORKPATH','DEFINES','CCDEPS','CFLAGS']) -USELIB_VARS['cxx']=set(['INCLUDES','FRAMEWORKPATH','DEFINES','CXXDEPS','CXXFLAGS']) -USELIB_VARS['d']=set(['INCLUDES','DFLAGS']) -USELIB_VARS['cprogram']=USELIB_VARS['cxxprogram']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS','FRAMEWORK','FRAMEWORKPATH']) -USELIB_VARS['cshlib']=USELIB_VARS['cxxshlib']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS','FRAMEWORK','FRAMEWORKPATH']) -USELIB_VARS['cstlib']=USELIB_VARS['cxxstlib']=set(['ARFLAGS','LINKDEPS']) -USELIB_VARS['dprogram']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS']) -USELIB_VARS['dshlib']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS']) -USELIB_VARS['dstlib']=set(['ARFLAGS','LINKDEPS']) -USELIB_VARS['go']=set(['GOCFLAGS']) -USELIB_VARS['goprogram']=set(['GOLFLAGS']) -USELIB_VARS['asm']=set(['ASFLAGS']) -def create_compiled_task(self,name,node): - out='%s.%d.o'%(node.name,self.idx) - task=self.create_task(name,node,node.parent.find_or_declare(out)) - try: - self.compiled_tasks.append(task) - except AttributeError: - self.compiled_tasks=[task] - return task -def to_incnodes(self,inlst): - lst=[] - seen=set([]) - for x in self.to_list(inlst): - if x in seen: - continue - seen.add(x) - if isinstance(x,Node.Node): - lst.append(x) - else: - if os.path.isabs(x): - lst.append(self.bld.root.find_dir(x)) - else: - if x[0]=='#': - lst.append(self.bld.bldnode.find_dir(x[1:])) - lst.append(self.bld.srcnode.find_dir(x[1:])) - else: - lst.append(self.path.get_bld().find_dir(x)) - lst.append(self.path.find_dir(x)) - lst=[x for x in lst if x] - return lst -def apply_incpaths(self): - lst=self.to_incnodes(self.to_list(getattr(self,'includes',[]))+self.env['INCLUDES']) - self.includes_nodes=lst - self.env['INCPATHS']=[x.abspath()for x in lst] -class link_task(Task.Task): - color='YELLOW' - inst_to=None - chmod=Utils.O644 - def add_target(self,target): - if isinstance(target,str): - pattern=self.env[self.__class__.__name__+'_PATTERN'] - if not pattern: - pattern='%s' - folder,name=os.path.split(target) - if self.__class__.__name__.find('shlib')>0: - if self.env.DEST_BINFMT=='pe'and getattr(self.generator,'vnum',None): - name=name+'-'+self.generator.vnum.split('.')[0] - tmp=folder+os.sep+pattern%name - target=self.generator.path.find_or_declare(tmp) - self.set_outputs(target) -class stlink_task(link_task): - run_str='${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}' - def run(self): - try: - os.remove(self.outputs[0].abspath()) - except OSError: - pass - return Task.Task.run(self) -def apply_link(self): - for x in self.features: - if x=='cprogram'and'cxx'in self.features: - x='cxxprogram' - elif x=='cshlib'and'cxx'in self.features: - x='cxxshlib' - if x in Task.classes: - if issubclass(Task.classes[x],link_task): - link=x - break - else: - return - objs=[t.outputs[0]for t in getattr(self,'compiled_tasks',[])] - self.link_task=self.create_task(link,objs) - self.link_task.add_target(self.target) - if getattr(self.bld,'is_install',None): - try: - inst_to=self.install_path - except AttributeError: - inst_to=self.link_task.__class__.inst_to - if inst_to: - self.install_task=self.bld.install_files(inst_to,self.link_task.outputs[:],env=self.env,chmod=self.link_task.chmod) -def use_rec(self,name,objects=True,stlib=True): - if name in self.seen_libs: - return - else: - self.seen_libs.add(name) - get=self.bld.get_tgen_by_name - try: - y=get(name) - except Errors.WafError: - self.uselib.append(name) - return - y.post() - has_link=getattr(y,'link_task',None) - is_static=has_link and isinstance(y.link_task,stlink_task) - for x in self.to_list(getattr(y,'use',[])): - self.use_rec(x,objects and not has_link,stlib and(is_static or not has_link)) - if getattr(self,'link_task',None): - if has_link: - if(not is_static)or(is_static and stlib): - var=isinstance(y.link_task,stlink_task)and'STLIB'or'LIB' - self.env.append_value(var,[y.target[y.target.rfind(os.sep)+1:]]) - self.link_task.set_run_after(y.link_task) - self.link_task.dep_nodes.extend(y.link_task.outputs) - tmp_path=y.link_task.outputs[0].parent.bldpath() - if not tmp_path in self.env[var+'PATH']: - self.env.prepend_value(var+'PATH',[tmp_path]) - elif objects: - for t in getattr(y,'compiled_tasks',[]): - self.link_task.inputs.extend(t.outputs) - for v in self.to_list(getattr(y,'uselib',[])): - if not self.env['STLIB_'+v]: - if not v in self.uselib: - self.uselib.insert(0,v) - if getattr(y,'export_includes',None): - self.includes.extend(y.to_incnodes(y.export_includes)) -def process_use(self): - self.uselib=self.to_list(getattr(self,'uselib',[])) - self.includes=self.to_list(getattr(self,'includes',[])) - names=self.to_list(getattr(self,'use',[])) - self.seen_libs=set([]) - for x in names: - self.use_rec(x) -def get_uselib_vars(self): - _vars=set([]) - for x in self.features: - if x in USELIB_VARS: - _vars|=USELIB_VARS[x] - return _vars -def propagate_uselib_vars(self): - _vars=self.get_uselib_vars() - env=self.env - for x in _vars: - y=x.lower() - env.append_unique(x,self.to_list(getattr(self,y,[]))) - for x in self.features: - for var in _vars: - compvar='%s_%s'%(var,x) - env.append_value(var,env[compvar]) - for x in self.to_list(getattr(self,'uselib',[])): - for v in _vars: - env.append_value(v,env[v+'_'+x]) -def apply_implib(self): - if not self.env.DEST_BINFMT=='pe': - return - dll=self.link_task.outputs[0] - implib=self.env['implib_PATTERN']%os.path.split(self.target)[1] - implib=dll.parent.find_or_declare(implib) - self.env.append_value('LINKFLAGS',self.env['IMPLIB_ST']%implib.bldpath()) - self.link_task.outputs.append(implib) - if getattr(self,'defs',None)and self.env.DEST_BINFMT=='pe': - node=self.path.find_resource(self.defs) - if not node: - raise Errors.WafError('invalid def file %r'%self.defs) - if'msvc'in(self.env.CC_NAME,self.env.CXX_NAME): - self.env.append_value('LINKFLAGS','/def:%s'%node.abspath()) - else: - self.link_task.inputs.append(node) - try: - inst_to=self.install_path - except AttributeError: - inst_to=self.link_task.__class__.inst_to - if not inst_to: - return - self.implib_install_task=self.bld.install_as('${PREFIX}/lib/%s'%implib.name,implib,self.env) -def apply_vnum(self): - if not getattr(self,'vnum','')or os.name!='posix'or self.env.DEST_BINFMT not in('elf','mac-o'): - return - link=self.link_task - nums=self.vnum.split('.') - node=link.outputs[0] - libname=node.name - if libname.endswith('.dylib'): - name3=libname.replace('.dylib','.%s.dylib'%self.vnum) - name2=libname.replace('.dylib','.%s.dylib'%nums[0]) - else: - name3=libname+'.'+self.vnum - name2=libname+'.'+nums[0] - if self.env.SONAME_ST: - v=self.env.SONAME_ST%name2 - self.env.append_value('LINKFLAGS',v.split()) - tsk=self.create_task('vnum',node,[node.parent.find_or_declare(name2),node.parent.find_or_declare(name3)]) - if getattr(self.bld,'is_install',None): - self.install_task.hasrun=Task.SKIP_ME - bld=self.bld - path=self.install_task.dest - t1=bld.install_as(path+os.sep+name3,node,env=self.env) - t2=bld.symlink_as(path+os.sep+name2,name3) - t3=bld.symlink_as(path+os.sep+libname,name3) - self.vnum_install_task=(t1,t2,t3) -class vnum_task(Task.Task): - color='CYAN' - quient=True - ext_in=['.bin'] - def run(self): - for x in self.outputs: - path=x.abspath() - try: - os.remove(path) - except OSError: - pass - try: - os.symlink(self.inputs[0].name,path) - except OSError: - return 1 -class fake_shlib(link_task): - def runnable_status(self): - for x in self.outputs: - x.sig=Utils.h_file(x.abspath()) - return Task.SKIP_ME -class fake_stlib(stlink_task): - def runnable_status(self): - for x in self.outputs: - x.sig=Utils.h_file(x.abspath()) - return Task.SKIP_ME -def read_shlib(self,name,paths=[]): - return self(name=name,features='fake_lib',lib_paths=paths,lib_type='shlib') -def read_stlib(self,name,paths=[]): - return self(name=name,features='fake_lib',lib_paths=paths,lib_type='stlib') -lib_patterns={'shlib':['lib%s.so','%s.so','lib%s.dll','%s.dll'],'stlib':['lib%s.a','%s.a','lib%s.dll','%s.dll','lib%s.lib','%s.lib'],} -def process_lib(self): - node=None - names=[x%self.name for x in lib_patterns[self.lib_type]] - for x in self.lib_paths+[self.path,'/usr/lib64','/usr/lib','/usr/local/lib64','/usr/local/lib']: - if not isinstance(x,Node.Node): - x=self.bld.root.find_node(x)or self.path.find_node(x) - if not x: - continue - for y in names: - node=x.find_node(y) - if node: - node.sig=Utils.h_file(node.abspath()) - break - else: - continue - break - else: - raise Errors.WafError('could not find library %r'%self.name) - self.link_task=self.create_task('fake_%s'%self.lib_type,[],[node]) - self.target=self.name - -taskgen_method(create_compiled_task) -taskgen_method(to_incnodes) -feature('c','cxx','d','go','asm','fc','includes')(apply_incpaths) -after('propagate_uselib_vars','process_source')(apply_incpaths) -feature('c','cxx','d','go','fc')(apply_link) -after('process_source')(apply_link) -taskgen_method(use_rec) -feature('c','cxx','d','use','fc')(process_use) -before('apply_incpaths','propagate_uselib_vars')(process_use) -after('apply_link','process_source')(process_use) -taskgen_method(get_uselib_vars) -feature('c','cxx','d','fc','cs','uselib')(propagate_uselib_vars) -after('process_use')(propagate_uselib_vars) -feature('cshlib','cxxshlib')(apply_implib) -after('apply_link')(apply_implib) -before('apply_lib_vars','apply_objdeps')(apply_implib) -feature('cshlib','cxxshlib','dshlib','fcshlib','vnum')(apply_vnum) -after('apply_link')(apply_vnum) -conf(read_shlib) -conf(read_stlib) -feature('fake_lib')(process_lib) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/compiler_c.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/compiler_c.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/compiler_c.py +++ /dev/null @@ -1,38 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,imp,types -from waflib.Tools import ccroot -from waflib import Utils,Configure -from waflib.Logs import debug -c_compiler={'win32':['msvc','gcc'],'cygwin':['gcc'],'darwin':['gcc'],'aix':['xlc','gcc'],'linux':['gcc','icc','suncc'],'sunos':['gcc','suncc'],'irix':['gcc'],'hpux':['gcc'],'gnu':['gcc'],'java':['gcc','msvc','icc'],'default':['gcc'],} -def configure(conf): - try:test_for_compiler=conf.options.check_c_compiler - except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_c')") - for compiler in test_for_compiler.split(): - conf.env.stash() - conf.start_msg('Checking for %r (c compiler)'%compiler) - try: - conf.load(compiler) - except conf.errors.ConfigurationError ,e: - conf.env.revert() - conf.end_msg(False) - debug('compiler_c: %r'%e) - else: - if conf.env['CC']: - conf.end_msg(True) - conf.env['COMPILER_CC']=compiler - break - conf.end_msg(False) - else: - conf.fatal('could not configure a c compiler!') -def options(opt): - global c_compiler - build_platform=Utils.unversioned_sys_platform() - possible_compiler_list=c_compiler[build_platform in c_compiler and build_platform or'default'] - test_for_compiler=' '.join(possible_compiler_list) - cc_compiler_opts=opt.add_option_group("C Compiler Options") - cc_compiler_opts.add_option('--check-c-compiler',default="%s"%test_for_compiler,help='On this platform (%s) the following C-Compiler will be checked by default: "%s"'%(build_platform,test_for_compiler),dest="check_c_compiler") - for x in test_for_compiler.split(): - opt.load('%s'%x) diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/compiler_cxx.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/compiler_cxx.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/compiler_cxx.py +++ /dev/null @@ -1,38 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,imp,types -from waflib.Tools import ccroot -from waflib import Utils,Configure -from waflib.Logs import debug -cxx_compiler={'win32':['msvc','g++'],'cygwin':['g++'],'darwin':['g++'],'aix':['xlc++','g++'],'linux':['g++','icpc','sunc++'],'sunos':['g++','sunc++'],'irix':['g++'],'hpux':['g++'],'gnu':['g++'],'java':['g++','msvc','icpc'],'default':['g++']} -def configure(conf): - try:test_for_compiler=conf.options.check_cxx_compiler - except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_cxx')") - for compiler in test_for_compiler.split(): - conf.env.stash() - conf.start_msg('Checking for %r (c++ compiler)'%compiler) - try: - conf.load(compiler) - except conf.errors.ConfigurationError ,e: - conf.env.revert() - conf.end_msg(False) - debug('compiler_cxx: %r'%e) - else: - if conf.env['CXX']: - conf.end_msg(True) - conf.env['COMPILER_CXX']=compiler - break - conf.end_msg(False) - else: - conf.fatal('could not configure a c++ compiler!') -def options(opt): - global cxx_compiler - build_platform=Utils.unversioned_sys_platform() - possible_compiler_list=cxx_compiler[build_platform in cxx_compiler and build_platform or'default'] - test_for_compiler=' '.join(possible_compiler_list) - cxx_compiler_opts=opt.add_option_group('C++ Compiler Options') - cxx_compiler_opts.add_option('--check-cxx-compiler',default="%s"%test_for_compiler,help='On this platform (%s) the following C++ Compiler will be checked by default: "%s"'%(build_platform,test_for_compiler),dest="check_cxx_compiler") - for x in test_for_compiler.split(): - opt.load('%s'%x) diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/compiler_d.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/compiler_d.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/compiler_d.py +++ /dev/null @@ -1,30 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,imp,types -from waflib import Utils,Configure,Options,Logs -def configure(conf): - for compiler in conf.options.dcheck.split(','): - conf.env.stash() - conf.start_msg('Checking for %r (d compiler)'%compiler) - try: - conf.load(compiler) - except conf.errors.ConfigurationError ,e: - conf.env.revert() - conf.end_msg(False) - Logs.debug('compiler_cxx: %r'%e) - else: - if conf.env.D: - conf.end_msg(True) - conf.env['COMPILER_D']=compiler - conf.env.D_COMPILER=conf.env.D - break - conf.end_msg(False) - else: - conf.fatal('no suitable d compiler was found') -def options(opt): - d_compiler_opts=opt.add_option_group('D Compiler Options') - d_compiler_opts.add_option('--check-d-compiler',default='gdc,dmd',action='store',help='check for the compiler [Default:gdc,dmd]',dest='dcheck') - for d_compiler in['gdc','dmd']: - opt.load('%s'%d_compiler) diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/cxx.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/cxx.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/cxx.py +++ /dev/null @@ -1,27 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -from waflib import TaskGen,Task,Utils -from waflib.Tools import c_preproc -from waflib.Tools.ccroot import link_task,stlink_task -def cxx_hook(self,node): - return self.create_compiled_task('cxx',node) -TaskGen.extension('.cpp','.cc','.cxx','.C','.c++')(cxx_hook) -if not'.c'in TaskGen.task_gen.mappings: - TaskGen.task_gen.mappings['.c']=TaskGen.task_gen.mappings['.cpp'] -class cxx(Task.Task): - color='GREEN' - run_str='${CXX} ${CXXFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT}' - vars=['CXXDEPS'] - ext_in=['.h'] - scan=c_preproc.scan -class cxxprogram(link_task): - run_str='${LINK_CXX} ${CXXLNK_SRC_F}${SRC} ${CXXLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${LINKFLAGS}' - ext_out=['.bin'] - inst_to='${BINDIR}' - chmod=Utils.O755 -class cxxshlib(cxxprogram): - inst_to='${LIBDIR}' -class cxxstlib(stlink_task): - pass diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/d.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/d.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/d.py +++ /dev/null @@ -1,69 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys -from waflib import Utils,Task,Errors -from waflib.TaskGen import taskgen_method,feature,after,before,extension -from waflib.Configure import conf -from waflib.Tools.ccroot import link_task -from waflib.Tools import d_scan,d_config -from waflib.Tools.ccroot import link_task,stlink_task -class d(Task.Task): - color='GREEN' - run_str='${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_SRC_F}${SRC} ${D_TGT_F}${TGT}' - scan=d_scan.scan - def exec_command(self,*k,**kw): - if isinstance(k[0],list): - lst=k[0] - for i in range(len(lst)): - if lst[i]=='-of': - del lst[i] - lst[i]='-of'+lst[i] - break - return super(d,self).exec_command(*k,**kw) -class d_with_header(d): - run_str='${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_HDR_F}${TGT[1].bldpath()} ${D_SRC_F}${SRC} ${D_TGT_F}${TGT[0].bldpath()}' -class d_header(Task.Task): - color='BLUE' - run_str='${D} ${D_HEADER} ${SRC}' -class dprogram(link_task): - run_str='${D_LINKER} ${DLNK_SRC_F}${SRC} ${DLNK_TGT_F}${TGT} ${RPATH_ST:RPATH} ${DSTLIB_MARKER} ${DSTLIBPATH_ST:STLIBPATH} ${DSTLIB_ST:STLIB} ${DSHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${DSHLIB_ST:LIB} ${LINKFLAGS}' - inst_to='${BINDIR}' - chmod=Utils.O755 - def exec_command(self,*k,**kw): - if isinstance(k[0],list): - lst=k[0] - for i in range(len(lst)): - if lst[i]=='-of': - del lst[i] - lst[i]='-of'+lst[i] - break - return super(dprogram,self).exec_command(*k,**kw) -class dshlib(dprogram): - inst_to='${LIBDIR}' -class dstlib(stlink_task): - pass -def d_hook(self,node): - if getattr(self,'generate_headers',None): - task=self.create_compiled_task('d_with_header',node) - header_node=node.change_ext(self.env['DHEADER_ext']) - task.outputs.append(header_node) - else: - task=self.create_compiled_task('d',node) - return task -def generate_header(self,filename,install_path=None): - try: - self.header_lst.append([filename,install_path]) - except AttributeError: - self.header_lst=[[filename,install_path]] -def process_header(self): - for i in getattr(self,'header_lst',[]): - node=self.path.find_resource(i[0]) - if not node: - raise Errors.WafError('file %r not found on d obj'%i[0]) - self.create_task('d_header',node,node.change_ext('.di')) - -extension('.d','.di','.D')(d_hook) -taskgen_method(generate_header) -feature('d')(process_header) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/d_config.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/d_config.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/d_config.py +++ /dev/null @@ -1,47 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -from waflib import Utils -from waflib.Configure import conf -def d_platform_flags(self): - v=self.env - if not v.DEST_OS: - v.DEST_OS=Utils.unversioned_sys_platform() - if Utils.destos_to_binfmt(self.env.DEST_OS)=='pe': - v['dprogram_PATTERN']='%s.exe' - v['dshlib_PATTERN']='lib%s.dll' - v['dstlib_PATTERN']='lib%s.a' - else: - v['dprogram_PATTERN']='%s' - v['dshlib_PATTERN']='lib%s.so' - v['dstlib_PATTERN']='lib%s.a' -DLIB=""" -version(D_Version2) { - import std.stdio; - int main() { - writefln("phobos2"); - return 0; - } -} else { - version(Tango) { - import tango.stdc.stdio; - int main() { - printf("tango"); - return 0; - } - } else { - import std.stdio; - int main() { - writefln("phobos1"); - return 0; - } - } -} -""" -def check_dlibrary(self): - ret=self.check_cc(features='d dprogram',fragment=DLIB,compile_filename='test.d',execute=True,define_ret=True) - self.env.DLIBRARY=ret.strip() - -conf(d_platform_flags) -conf(check_dlibrary) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/d_scan.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/d_scan.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/d_scan.py +++ /dev/null @@ -1,133 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import re -from waflib import Utils,Logs -def filter_comments(filename): - txt=Utils.readf(filename) - i=0 - buf=[] - max=len(txt) - begin=0 - while i-1: - conf.common_flags_ldc() - -conf(find_dmd) -conf(common_flags_ldc) -conf(common_flags_dmd) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/errcheck.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/errcheck.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/errcheck.py +++ /dev/null @@ -1,47 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -typos={'feature':'features','sources':'source','targets':'target','include':'includes','export_include':'export_includes','define':'defines','importpath':'includes','installpath':'install_path',} -meths_typos=['__call__','program','shlib','stlib','objects'] -from waflib import Logs,Build,Node,Task,TaskGen -import waflib.Tools.ccroot -def replace(m): - oldcall=getattr(Build.BuildContext,m) - def call(self,*k,**kw): - for x in typos: - if x in kw: - kw[typos[x]]=kw[x] - del kw[x] - Logs.error('typo %r -> %r'%(x,typos[x])) - return oldcall(self,*k,**kw) - setattr(Build.BuildContext,m,call) -def enhance_lib(): - for m in meths_typos: - replace(m) - old_ant_glob=Node.Node.ant_glob - def ant_glob(self,*k,**kw): - for x in k[0].split('/'): - if x=='..': - Logs.error("In ant_glob pattern %r: '..' means 'two dots', not 'parent directory'"%k[0]) - return old_ant_glob(self,*k,**kw) - Node.Node.ant_glob=ant_glob - old=Task.is_before - def is_before(t1,t2): - ret=old(t1,t2) - if ret and old(t2,t1): - Logs.error('Contradictory order constraints in classes %r %r'%(t1,t2)) - return ret - Task.is_before=is_before - def check_err_features(self): - lst=self.to_list(self.features) - if'shlib'in lst: - Logs.error('feature shlib -> cshlib, dshlib or cxxshlib') - for x in('c','cxx','d','fc'): - if not x in lst and lst and lst[0]in[x+y for y in('program','shlib','stlib')]: - Logs.error('%r features is probably missing %r'%(self,x)) - TaskGen.feature('*')(check_err_features) -def options(opt): - enhance_lib() -def configure(conf): - pass diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/flex.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/flex.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/flex.py +++ /dev/null @@ -1,12 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import waflib.TaskGen -def decide_ext(self,node): - if'cxx'in self.features: - return['.lex.cc'] - return['.lex.c'] -waflib.TaskGen.declare_chain(name='flex',rule='${FLEX} -o${TGT} ${FLEXFLAGS} ${SRC}',ext_in='.l',decider=decide_ext) -def configure(conf): - conf.find_program('flex',var='FLEX') diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gas.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gas.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gas.py +++ /dev/null @@ -1,8 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import waflib.Tools.ccroot -def configure(conf): - conf.find_program(['gas','as','gcc'],var='AS') - conf.env.AS_TGT_F='-o' diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gcc.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gcc.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gcc.py +++ /dev/null @@ -1,92 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys -from waflib import Configure,Options,Utils -from waflib.Tools import ccroot,ar -from waflib.Configure import conf -def find_gcc(conf): - cc=conf.find_program(['gcc','cc'],var='CC') - cc=conf.cmd_to_list(cc) - conf.get_cc_version(cc,gcc=True) - conf.env.CC_NAME='gcc' - conf.env.CC=cc -def gcc_common_flags(conf): - v=conf.env - v['CC_SRC_F']='' - v['CC_TGT_F']=['-c','-o',''] - if not v['LINK_CC']:v['LINK_CC']=v['CC'] - v['CCLNK_SRC_F']='' - v['CCLNK_TGT_F']=['-o',''] - v['CPPPATH_ST']='-I%s' - v['DEFINES_ST']='-D%s' - v['LIB_ST']='-l%s' - v['LIBPATH_ST']='-L%s' - v['STLIB_ST']='-l%s' - v['STLIBPATH_ST']='-L%s' - v['RPATH_ST']='-Wl,-rpath,%s' - v['SONAME_ST']='-Wl,-h,%s' - v['SHLIB_MARKER']='-Wl,-Bdynamic' - v['STLIB_MARKER']='-Wl,-Bstatic' - v['cprogram_PATTERN']='%s' - v['CFLAGS_cshlib']=['-fPIC'] - v['LINKFLAGS_cshlib']=['-shared'] - v['cshlib_PATTERN']='lib%s.so' - v['LINKFLAGS_cstlib']=['-Wl,-Bstatic'] - v['cstlib_PATTERN']='lib%s.a' - v['LINKFLAGS_MACBUNDLE']=['-bundle','-undefined','dynamic_lookup'] - v['CFLAGS_MACBUNDLE']=['-fPIC'] - v['macbundle_PATTERN']='%s.bundle' -def gcc_modifier_win32(conf): - v=conf.env - v['cprogram_PATTERN']='%s.exe' - v['cshlib_PATTERN']='%s.dll' - v['implib_PATTERN']='lib%s.dll.a' - v['IMPLIB_ST']='-Wl,--out-implib,%s' - v['CFLAGS_cshlib']=[] - v.append_value('CFLAGS_cshlib',['-DDLL_EXPORT']) - v.append_value('LINKFLAGS',['-Wl,--enable-auto-import']) -def gcc_modifier_cygwin(conf): - gcc_modifier_win32(conf) - v=conf.env - v['cshlib_PATTERN']='cyg%s.dll' - v.append_value('LINKFLAGS_cshlib',['-Wl,--enable-auto-image-base']) - v['CFLAGS_cshlib']=[] -def gcc_modifier_darwin(conf): - v=conf.env - v['CFLAGS_cshlib']=['-fPIC','-compatibility_version','1','-current_version','1'] - v['LINKFLAGS_cshlib']=['-dynamiclib'] - v['cshlib_PATTERN']='lib%s.dylib' - v['FRAMEWORKPATH_ST']='-F%s' - v['FRAMEWORK_ST']='-framework %s' - v['LINKFLAGS_cstlib']=[] - v['SHLIB_MARKER']='' - v['STLIB_MARKER']='' - v['SONAME_ST']='' -def gcc_modifier_aix(conf): - v=conf.env - v['LINKFLAGS_cprogram']=['-Wl,-brtl'] - v['LINKFLAGS_cshlib']=['-shared','-Wl,-brtl,-bexpfull'] - v['SHLIB_MARKER']='' -def gcc_modifier_platform(conf): - gcc_modifier_func=globals().get('gcc_modifier_'+conf.env.DEST_OS) - if gcc_modifier_func: - gcc_modifier_func(conf) -configure=''' -find_gcc -find_ar -gcc_common_flags -gcc_modifier_platform -cc_load_tools -cc_add_flags -link_add_flags -''' - -conf(find_gcc) -conf(gcc_common_flags) -conf(gcc_modifier_win32) -conf(gcc_modifier_cygwin) -conf(gcc_modifier_darwin) -conf(gcc_modifier_aix) -conf(gcc_modifier_platform) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gdc.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gdc.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gdc.py +++ /dev/null @@ -1,33 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -from waflib.Tools import ar,d -from waflib.Configure import conf -def find_gdc(conf): - conf.find_program('gdc',var='D') -def common_flags_gdc(conf): - v=conf.env - v['DFLAGS']=[] - v['D_SRC_F']='' - v['D_TGT_F']=['-c','-o',''] - v['D_LINKER']=v['D'] - v['DLNK_SRC_F']='' - v['DLNK_TGT_F']=['-o',''] - v['DINC_ST']='-I%s' - v['DSHLIB_MARKER']=v['DSTLIB_MARKER']='' - v['DSTLIB_ST']=v['DSHLIB_ST']='-l%s' - v['DSTLIBPATH_ST']=v['DLIBPATH_ST']='-L%s' - v['LINKFLAGS_dshlib']=['-shared'] - v['DHEADER_ext']='.di' - v['D_HDR_F']='-fintfc -fintfc-file=' -def configure(conf): - conf.find_gdc() - conf.load('ar') - conf.load('d') - conf.common_flags_gdc() - conf.d_platform_flags() - -conf(find_gdc) -conf(common_flags_gdc) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/glib2.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/glib2.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/glib2.py +++ /dev/null @@ -1,164 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os -from waflib import Task,Utils,Options,Errors,Logs -from waflib.TaskGen import taskgen_method,before,after,feature -def add_marshal_file(self,filename,prefix): - if not hasattr(self,'marshal_list'): - self.marshal_list=[] - self.meths.append('process_marshal') - self.marshal_list.append((filename,prefix)) -def process_marshal(self): - for f,prefix in getattr(self,'marshal_list',[]): - node=self.path.find_resource(f) - if not node: - raise Errors.WafError('file not found %r'%f) - h_node=node.change_ext('.h') - c_node=node.change_ext('.c') - task=self.create_task('glib_genmarshal',node,[h_node,c_node]) - task.env.GLIB_GENMARSHAL_PREFIX=prefix - self.source.append(c_node) -def genmarshal_func(self): - bld=self.inputs[0].__class__.ctx - get=self.env.get_flat - cmd1="%s %s --prefix=%s --header > %s"%(get('GLIB_GENMARSHAL'),self.inputs[0].srcpath(self.env),get('GLIB_GENMARSHAL_PREFIX'),self.outputs[0].abspath(self.env)) - ret=bld.exec_command(cmd1) - if ret:return ret - c='''#include "%s"\n'''%self.outputs[0].name - self.outputs[1].write(c.encode("utf-8")) - cmd2="%s %s --prefix=%s --body >> %s"%(get('GLIB_GENMARSHAL'),self.inputs[0].srcpath(),get('GLIB_GENMARSHAL_PREFIX'),self.outputs[1].abspath()) - ret=bld.exec_command(cmd2) - if ret:return ret -def add_enums_from_template(self,source='',target='',template='',comments=''): - if not hasattr(self,'enums_list'): - self.enums_list=[] - self.meths.append('process_enums') - self.enums_list.append({'source':source,'target':target,'template':template,'file-head':'','file-prod':'','file-tail':'','enum-prod':'','value-head':'','value-prod':'','value-tail':'','comments':comments}) -def add_enums(self,source='',target='',file_head='',file_prod='',file_tail='',enum_prod='',value_head='',value_prod='',value_tail='',comments=''): - if not hasattr(self,'enums_list'): - self.enums_list=[] - self.meths.append('process_enums') - self.enums_list.append({'source':source,'template':'','target':target,'file-head':file_head,'file-prod':file_prod,'file-tail':file_tail,'enum-prod':enum_prod,'value-head':value_head,'value-prod':value_prod,'value-tail':value_tail,'comments':comments}) -def process_enums(self): - for enum in getattr(self,'enums_list',[]): - task=self.create_task('glib_mkenums') - env=task.env - inputs=[] - source_list=self.to_list(enum['source']) - if not source_list: - raise Errors.WafError('missing source '+str(enum)) - source_list=[self.path.find_resource(k)for k in source_list] - inputs+=source_list - env['GLIB_MKENUMS_SOURCE']=[k.srcpath(env)for k in source_list] - if not enum['target']: - raise Errors.WafError('missing target '+str(enum)) - tgt_node=self.path.find_or_declare(enum['target']) - if tgt_node.name.endswith('.c'): - self.source.append(tgt_node) - env['GLIB_MKENUMS_TARGET']=tgt_node.abspath(env) - options=[] - if enum['template']: - template_node=self.path.find_resource(enum['template']) - options.append('--template %s'%(template_node.abspath(env))) - inputs.append(template_node) - params={'file-head':'--fhead','file-prod':'--fprod','file-tail':'--ftail','enum-prod':'--eprod','value-head':'--vhead','value-prod':'--vprod','value-tail':'--vtail','comments':'--comments'} - for param,option in params.items(): - if enum[param]: - options.append('%s %r'%(option,enum[param])) - env['GLIB_MKENUMS_OPTIONS']=' '.join(options) - task.set_inputs(inputs) - task.set_outputs(tgt_node) -def add_settings_schemas(self,filename_list): - if not hasattr(self,'settings_schema_files'): - self.settings_schema_files=[] - if not isinstance(filename_list,list): - filename_list=[filename_list] - self.settings_schema_files.extend(filename_list) -def add_settings_enums(self,namespace,filename_list): - if hasattr(self,'settings_enum_namespace'): - raise Errors.WafError("Tried to add gsettings enums to '%s' more than once"%self.name) - self.settings_enum_namespace=namespace - if type(filename_list)!='list': - filename_list=[filename_list] - self.settings_enum_files=filename_list -def r_change_ext(self,ext): - name=self.name - k=name.rfind('.') - if k>=0: - name=name[:k]+ext - else: - name=name+ext - return self.parent.find_or_declare([name]) -def process_settings(self): - if not self.env['GLIB_COMPILE_SCHEMAS']: - raise Errors.WafError("Unable to process GSettings schemas - glib-compile-schemas was not found during configure") - enums_tgt_node=[] - install_files=[] - if hasattr(self,'settings_enum_files'): - enums_task=self.create_task('glib_mkenums') - source_list=self.settings_enum_files - source_list=[self.path.find_resource(k)for k in source_list] - enums_task.set_inputs(source_list) - enums_task.env['GLIB_MKENUMS_SOURCE']=[k.abspath()for k in source_list] - target=self.settings_enum_namespace+'.enums.xml' - tgt_node=self.path.find_or_declare(target) - enums_task.set_outputs(tgt_node) - enums_task.env['GLIB_MKENUMS_TARGET']=tgt_node.abspath() - enums_tgt_node=[tgt_node] - install_files.append(target) - options='--comments "" --fhead "" --vhead " <@type@ id=\\"%s. at EnumName@\\">" --vprod " " --vtail " " --ftail "" '%(self.settings_enum_namespace) - enums_task.env['GLIB_MKENUMS_OPTIONS']=options - for schema in getattr(self,'settings_schema_files',[]): - schema_task=self.create_task('glib_validate_schema') - install_files.append(schema) - schema_node=self.path.find_resource(schema) - if not schema_node: - raise Errors.WafError("Cannot find the schema file '%s'"%schema) - source_list=enums_tgt_node+[schema_node] - schema_task.set_inputs(source_list) - schema_task.env['GLIB_COMPILE_SCHEMAS_OPTIONS']=[("--schema-file="+k.abspath())for k in source_list] - target_node=r_change_ext(schema_node,'.xml.valid') - schema_task.set_outputs(target_node) - schema_task.env['GLIB_VALIDATE_SCHEMA_OUTPUT']=target_node.abspath() - def compile_schemas_callback(bld): - if not bld.is_install:return - Logs.pprint('YELLOW','Updating GSettings schema cache') - command=Utils.subst_vars("${GLIB_COMPILE_SCHEMAS} ${GSETTINGSSCHEMADIR}",bld.env) - ret=self.bld.exec_command(command) - if self.bld.is_install: - if not self.env['GSETTINGSSCHEMADIR']: - raise Errors.WafError('GSETTINGSSCHEMADIR not defined (should have been set up automatically during configure)') - self.bld.install_files(self.env['GSETTINGSSCHEMADIR'],install_files) - if not hasattr(self.bld,'_compile_schemas_registered'): - self.bld.add_post_fun(compile_schemas_callback) - self.bld._compile_schemas_registered=True -Task.task_factory('glib_genmarshal',func=genmarshal_func,vars=['GLIB_GENMARSHAL_PREFIX','GLIB_GENMARSHAL'],color='BLUE',ext_out=['.h']) -Task.task_factory('glib_mkenums','${GLIB_MKENUMS} ${GLIB_MKENUMS_OPTIONS} ${GLIB_MKENUMS_SOURCE} > ${GLIB_MKENUMS_TARGET}',color='PINK',ext_out=['.h']) -Task.task_factory('glib_validate_schema','rm -f ${GLIB_VALIDATE_SCHEMA_OUTPUT} && ${GLIB_COMPILE_SCHEMAS} --dry-run ${GLIB_COMPILE_SCHEMAS_OPTIONS} && touch ${GLIB_VALIDATE_SCHEMA_OUTPUT}',color='PINK') -def configure(conf): - conf.find_program('glib-genmarshal',var='GLIB_GENMARSHAL') - conf.find_perl_program('glib-mkenums',var='GLIB_MKENUMS') - conf.find_program('glib-compile-schemas',var='GLIB_COMPILE_SCHEMAS',mandatory=False) - def getstr(varname): - return getattr(Options.options,varname,getattr(conf.env,varname,'')) - gsettingsschemadir=getstr('GSETTINGSSCHEMADIR') - if not gsettingsschemadir: - datadir=getstr('DATADIR') - if not datadir: - prefix=conf.env['PREFIX'] - datadir=os.path.join(prefix,'share') - gsettingsschemadir=os.path.join(datadir,'glib-2.0','schemas') - conf.env['GSETTINGSSCHEMADIR']=gsettingsschemadir -def options(opt): - opt.add_option('--gsettingsschemadir',help='GSettings schema location [Default: ${datadir}/glib-2.0/schemas]',default='',dest='GSETTINGSSCHEMADIR') - -taskgen_method(add_marshal_file) -before('process_source')(process_marshal) -taskgen_method(add_enums_from_template) -taskgen_method(add_enums) -before('process_source')(process_enums) -taskgen_method(add_settings_schemas) -taskgen_method(add_settings_enums) -feature('glib2')(process_settings) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gnu_dirs.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gnu_dirs.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/gnu_dirs.py +++ /dev/null @@ -1,63 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -from waflib import Utils,Options,Context -_options=[x.split(', ')for x in''' -bindir, user executables, ${EXEC_PREFIX}/bin -sbindir, system admin executables, ${EXEC_PREFIX}/sbin -libexecdir, program executables, ${EXEC_PREFIX}/libexec -sysconfdir, read-only single-machine data, ${PREFIX}/etc -sharedstatedir, modifiable architecture-independent data, ${PREFIX}/com -localstatedir, modifiable single-machine data, ${PREFIX}/var -libdir, object code libraries, ${EXEC_PREFIX}/lib -includedir, C header files, ${PREFIX}/include -oldincludedir, C header files for non-gcc, /usr/include -datarootdir, read-only arch.-independent data root, ${PREFIX}/share -datadir, read-only architecture-independent data, ${DATAROOTDIR} -infodir, info documentation, ${DATAROOTDIR}/info -localedir, locale-dependent data, ${DATAROOTDIR}/locale -mandir, man documentation, ${DATAROOTDIR}/man -docdir, documentation root, ${DATAROOTDIR}/doc/${PACKAGE} -htmldir, html documentation, ${DOCDIR} -dvidir, dvi documentation, ${DOCDIR} -pdfdir, pdf documentation, ${DOCDIR} -psdir, ps documentation, ${DOCDIR} -'''.split('\n')if x] -def configure(conf): - def get_param(varname,default): - return getattr(Options.options,varname,'')or default - env=conf.env - env['EXEC_PREFIX']=get_param('EXEC_PREFIX',env['PREFIX']) - env['PACKAGE']=getattr(Context.g_module,'APPNAME',None)or env['PACKAGE'] - complete=False - iter=0 - while not complete and iter=0: - node=k.find_or_declare(u) - inner.append(node) - to_add=set(inner)-set(self.outputs) - self.outputs.extend(list(to_add)) - self.cached=True - return super(javac,self).post_run() -def configure(self): - java_path=self.environ['PATH'].split(os.pathsep) - v=self.env - if'JAVA_HOME'in self.environ: - java_path=[os.path.join(self.environ['JAVA_HOME'],'bin')]+java_path - self.env['JAVA_HOME']=[self.environ['JAVA_HOME']] - for x in'javac java jar'.split(): - self.find_program(x,var=x.upper(),path_list=java_path) - self.env[x.upper()]=self.cmd_to_list(self.env[x.upper()]) - if'CLASSPATH'in self.environ: - v['CLASSPATH']=self.environ['CLASSPATH'] - if not v['JAR']:self.fatal('jar is required for making java packages') - if not v['JAVAC']:self.fatal('javac is required for compiling java classes') - v['JARCREATE']='cf' -def check_java_class(self,classname,with_classpath=None): - import shutil - javatestdir='.waf-javatest' - classpath=javatestdir - if self.env['CLASSPATH']: - classpath+=os.pathsep+self.env['CLASSPATH'] - if isinstance(with_classpath,str): - classpath+=os.pathsep+with_classpath - shutil.rmtree(javatestdir,True) - os.mkdir(javatestdir) - java_file=open(os.path.join(javatestdir,'Test.java'),'w') - java_file.write(class_check_source) - java_file.close() - self.exec_command(self.env['JAVAC']+[os.path.join(javatestdir,'Test.java')],shell=False) - cmd=self.env['JAVA']+['-cp',classpath,'Test',classname] - self.to_log("%s\n"%str(cmd)) - found=self.exec_command(cmd,shell=False) - self.msg('Checking for java class %s'%classname,not found) - shutil.rmtree(javatestdir,True) - return found -def check_jni_headers(conf): - if not conf.env.CC_NAME and not conf.env.CXX_NAME: - conf.fatal('load a compiler first (gcc, g++, ..)') - if not conf.env.JAVA_HOME: - conf.fatal('set JAVA_HOME in the system environment') - javaHome=conf.env['JAVA_HOME'][0] - dir=conf.root.find_dir(conf.env.JAVA_HOME[0]+'/include') - f=dir.ant_glob('**/(jni|jni_md).h') - incDirs=[x.parent.abspath()for x in f] - dir=conf.root.find_dir(conf.env.JAVA_HOME[0]) - f=dir.ant_glob('**/*jvm.(so|dll)') - libDirs=[x.parent.abspath()for x in f]or[javaHome] - for i,d in enumerate(libDirs): - if conf.check(header_name='jni.h',define_name='HAVE_JNI_H',lib='jvm',libpath=d,includes=incDirs,uselib_store='JAVA',uselib='JAVA'): - break - else: - conf.fatal('could not find lib jvm in %r (see config.log)'%libDirs) - -feature('javac')(apply_java) -before('process_source')(apply_java) -feature('javac')(use_javac_files) -after('apply_java')(use_javac_files) -feature('jar')(jar_files) -after('apply_java','use_javac_files')(jar_files) -before('process_source')(jar_files) -feature('jar')(use_jar_files) -after('jar_files')(use_jar_files) -conf(check_java_class) -conf(check_jni_headers) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/kde4.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/kde4.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/kde4.py +++ /dev/null @@ -1,58 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,re -from waflib import Options,TaskGen,Task,Utils -from waflib.TaskGen import feature,after -def init_msgfmt(self): - try: - self.install_path - except: - self.install_path='${KDE4_LOCALE_INSTALL_DIR}' -def apply_msgfmt(self): - for lang in self.to_list(self.langs): - node=self.path.find_resource(lang+'.po') - task=self.create_task('msgfmt',node,node.change_ext('.mo')) - if not self.bld.is_install:continue - langname=lang.split('/') - langname=langname[-1] - task.install_path=self.install_path+os.sep+langname+os.sep+'LC_MESSAGES' - task.filename=getattr(self,'appname','set_your_appname')+'.mo' - task.chmod=self.chmod -def configure(self): - kdeconfig=self.find_program('kde4-config') - prefix=self.cmd_and_log('%s --prefix'%kdeconfig).strip() - fname='%s/share/apps/cmake/modules/KDELibsDependencies.cmake'%prefix - try:os.stat(fname) - except OSError: - fname='%s/share/kde4/apps/cmake/modules/KDELibsDependencies.cmake'%prefix - try:os.stat(fname) - except OSError:self.fatal('could not open %s'%fname) - try: - txt=Utils.readf(fname) - except(OSError,IOError): - self.fatal('could not read %s'%fname) - txt=txt.replace('\\\n','\n') - fu=re.compile('#(.*)\n') - txt=fu.sub('',txt) - setregexp=re.compile('([sS][eE][tT]\s*\()\s*([^\s]+)\s+\"([^"]+)\"\)') - found=setregexp.findall(txt) - for(_,key,val)in found: - self.env[key]=val - self.env['LIB_KDECORE']=['kdecore'] - self.env['LIB_KDEUI']=['kdeui'] - self.env['LIB_KIO']=['kio'] - self.env['LIB_KHTML']=['khtml'] - self.env['LIB_KPARTS']=['kparts'] - self.env['LIBPATH_KDECORE']=[self.env['KDE4_LIB_INSTALL_DIR']] - self.env['INCLUDES_KDECORE']=[self.env['KDE4_INCLUDE_INSTALL_DIR']] - self.env.append_value('INCLUDES_KDECORE',[self.env['KDE4_INCLUDE_INSTALL_DIR']+os.sep+'KDE']) - self.find_program('msgfmt',var='MSGFMT') -class msgfmt(Task.Task): - color='BLUE' - run_str='${MSGFMT} ${SRC} -o ${TGT}' - -feature('msgfmt')(init_msgfmt) -feature('msgfmt')(apply_msgfmt) -after('init_msgfmt')(apply_msgfmt) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/lua.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/lua.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/lua.py +++ /dev/null @@ -1,12 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -from waflib import TaskGen,Utils -TaskGen.declare_chain(name='luac',rule='${LUAC} -s -o ${TGT} ${SRC}',ext_in='.lua',ext_out='.luac',reentrant=False) -def init_lua(self): - self.default_chmod=Utils.O755 -def configure(conf): - conf.find_program('luac',var='LUAC') - -TaskGen.feature('lua')(init_lua) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/msvc.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/msvc.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/msvc.py +++ /dev/null @@ -1,542 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,re -try: - import _winreg -except: - import winreg as _winreg -from waflib import Utils,TaskGen,Runner,Configure,Task,Options -from waflib.Logs import debug,info,warn,error -from waflib.TaskGen import after,before,feature -from waflib.Configure import conf -from waflib.Tools import ccroot,c,cxx,ar,winres -g_msvc_systemlibs=""" -aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet -cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs -credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d -ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp -faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid -gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop -kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi -mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree -msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm -netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp -odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32 -osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu -ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm -rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32 -shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32 -traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg -version vfw32 wbemuuid webpost wiaguid wininet winmm winscard winspool winstrm -wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp -""".split() -all_msvc_platforms=[('x64','amd64'),('x86','x86'),('ia64','ia64'),('x86_amd64','amd64'),('x86_ia64','ia64')] -all_wince_platforms=[('armv4','arm'),('armv4i','arm'),('mipsii','mips'),('mipsii_fp','mips'),('mipsiv','mips'),('mipsiv_fp','mips'),('sh4','sh'),('x86','cex86')] -all_icl_platforms=[('intel64','amd64'),('em64t','amd64'),('ia32','x86'),('Itanium','ia64')] -def setup_msvc(conf,versions): - platforms=Utils.to_list(conf.env['MSVC_TARGETS'])or[i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms] - desired_versions=conf.env['MSVC_VERSIONS']or[v for v,_ in versions][::-1] - versiondict=dict(versions) - for version in desired_versions: - try: - targets=dict(versiondict[version]) - for target in platforms: - try: - arch,(p1,p2,p3)=targets[target] - compiler,revision=version.split() - return compiler,revision,p1,p2,p3 - except KeyError:continue - except KeyError:continue - conf.fatal('msvc: Impossible to find a valid architecture for building (in setup_msvc)') -def get_msvc_version(conf,compiler,version,target,vcvars): - debug('msvc: get_msvc_version: %r %r %r',compiler,version,target) - batfile=conf.bldnode.make_node('waf-print-msvc.bat') - batfile.write("""@echo off -set INCLUDE= -set LIB= -call "%s" %s -echo PATH=%%PATH%% -echo INCLUDE=%%INCLUDE%% -echo LIB=%%LIB%% -"""%(vcvars,target)) - sout=conf.cmd_and_log(['cmd','/E:on','/V:on','/C',batfile.abspath()]) - lines=sout.splitlines() - for x in('Setting environment','Setting SDK environment','Intel(R) C++ Compiler'): - if lines[0].find(x)!=-1: - break - else: - debug('msvc: get_msvc_version: %r %r %r -> not found',compiler,version,target) - conf.fatal('msvc: Impossible to find a valid architecture for building (in get_msvc_version)') - for line in lines[1:]: - if line.startswith('PATH='): - path=line[5:] - MSVC_PATH=path.split(';') - elif line.startswith('INCLUDE='): - MSVC_INCDIR=[i for i in line[8:].split(';')if i] - elif line.startswith('LIB='): - MSVC_LIBDIR=[i for i in line[4:].split(';')if i] - env={} - env.update(os.environ) - env.update(PATH=path) - compiler_name,linker_name,lib_name=_get_prog_names(conf,compiler) - cxx=conf.find_program(compiler_name,path_list=MSVC_PATH) - cxx=conf.cmd_to_list(cxx) - if'CL'in env: - del(env['CL']) - try: - conf.cmd_and_log(cxx+['/help'],env=env) - except Exception ,e: - debug('msvc: get_msvc_version: %r %r %r -> failure'%(compiler,version,target)) - debug(str(e)) - conf.fatal('msvc: cannot run the compiler (in get_msvc_version)') - else: - debug('msvc: get_msvc_version: %r %r %r -> OK',compiler,version,target) - conf.env[compiler_name]='' - return(MSVC_PATH,MSVC_INCDIR,MSVC_LIBDIR) -def gather_wsdk_versions(conf,versions): - version_pattern=re.compile('^v..?.?\...?.?') - try: - all_versions=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows') - except WindowsError: - try: - all_versions=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows') - except WindowsError: - return - index=0 - while 1: - try: - version=_winreg.EnumKey(all_versions,index) - except WindowsError: - break - index=index+1 - if not version_pattern.match(version): - continue - try: - msvc_version=_winreg.OpenKey(all_versions,version) - path,type=_winreg.QueryValueEx(msvc_version,'InstallationFolder') - except WindowsError: - continue - if os.path.isfile(os.path.join(path,'bin','SetEnv.cmd')): - targets=[] - for target,arch in all_msvc_platforms: - try: - targets.append((target,(arch,conf.get_msvc_version('wsdk',version,'/'+target,os.path.join(path,'bin','SetEnv.cmd'))))) - except conf.errors.ConfigurationError: - pass - versions.append(('wsdk '+version[1:],targets)) -def gather_msvc_versions(conf,versions): - try: - ce_sdk=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs') - except WindowsError: - try: - ce_sdk=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs') - except WindowsError: - ce_sdk='' - if ce_sdk: - supported_wince_platforms=[] - ce_index=0 - while 1: - try: - sdk_device=_winreg.EnumKey(ce_sdk,ce_index) - except WindowsError: - break - ce_index=ce_index+1 - sdk=_winreg.OpenKey(ce_sdk,sdk_device) - path,type=_winreg.QueryValueEx(sdk,'SDKRootDir') - path=str(path) - path,device=os.path.split(path) - if not device: - path,device=os.path.split(path) - for arch,compiler in all_wince_platforms: - platforms=[] - if os.path.isdir(os.path.join(path,device,'Lib',arch)): - platforms.append((arch,compiler,os.path.join(path,device,'Include',arch),os.path.join(path,device,'Lib',arch))) - if platforms: - supported_wince_platforms.append((device,platforms)) - version_pattern=re.compile('^..?\...?') - detected_versions=[] - for vcver,vcvar in[('VCExpress','Exp'),('VisualStudio','')]: - try: - prefix='SOFTWARE\\Wow6432node\\Microsoft\\'+vcver - all_versions=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,prefix) - except WindowsError: - try: - prefix='SOFTWARE\\Microsoft\\'+vcver - all_versions=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,prefix) - except WindowsError: - continue - index=0 - while 1: - try: - version=_winreg.EnumKey(all_versions,index) - except WindowsError: - break - index=index+1 - if not version_pattern.match(version): - continue - if version.endswith('Exp'): - versionnumber=float(version[:-3]) - else: - versionnumber=float(version) - detected_versions.append((versionnumber,version,prefix+"\\"+version)) - def fun(tup): - return tup[0] - detected_versions.sort(key=fun) - for(v,version,reg)in detected_versions: - try: - msvc_version=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,reg+"\\Setup\\VS") - path,type=_winreg.QueryValueEx(msvc_version,'ProductDir') - path=str(path) - targets=[] - if ce_sdk: - for device,platforms in supported_wince_platforms: - cetargets=[] - for platform,compiler,include,lib in platforms: - winCEpath=os.path.join(path,'VC','ce') - if os.path.isdir(winCEpath): - common_bindirs,_1,_2=conf.get_msvc_version('msvc',version,'x86',os.path.join(path,'Common7','Tools','vsvars32.bat')) - if os.path.isdir(os.path.join(winCEpath,'lib',platform)): - bindirs=[os.path.join(winCEpath,'bin',compiler),os.path.join(winCEpath,'bin','x86_'+compiler)]+common_bindirs - incdirs=[include,os.path.join(winCEpath,'include'),os.path.join(winCEpath,'atlmfc','include')] - libdirs=[lib,os.path.join(winCEpath,'lib',platform),os.path.join(winCEpath,'atlmfc','lib',platform)] - cetargets.append((platform,(platform,(bindirs,incdirs,libdirs)))) - versions.append((device+' '+version,cetargets)) - if os.path.isfile(os.path.join(path,'VC','vcvarsall.bat')): - for target,realtarget in all_msvc_platforms[::-1]: - try: - targets.append((target,(realtarget,conf.get_msvc_version('msvc',version,target,os.path.join(path,'VC','vcvarsall.bat'))))) - except: - pass - elif os.path.isfile(os.path.join(path,'Common7','Tools','vsvars32.bat')): - try: - targets.append(('x86',('x86',conf.get_msvc_version('msvc',version,'x86',os.path.join(path,'Common7','Tools','vsvars32.bat'))))) - except conf.errors.ConfigurationError: - pass - versions.append(('msvc '+version,targets)) - except WindowsError: - continue -def gather_icl_versions(conf,versions): - version_pattern=re.compile('^...?.?\....?.?') - try: - all_versions=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++') - except WindowsError: - try: - all_versions=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Intel\\Compilers\\C++') - except WindowsError: - return - index=0 - while 1: - try: - version=_winreg.EnumKey(all_versions,index) - except WindowsError: - break - index=index+1 - if not version_pattern.match(version): - continue - targets=[] - for target,arch in all_icl_platforms: - try: - icl_version=_winreg.OpenKey(all_versions,version+'\\'+target) - path,type=_winreg.QueryValueEx(icl_version,'ProductDir') - if os.path.isfile(os.path.join(path,'bin','iclvars.bat')): - try: - targets.append((target,(arch,conf.get_msvc_version('intel',version,target,os.path.join(path,'bin','iclvars.bat'))))) - except conf.errors.ConfigurationError: - pass - except WindowsError: - continue - major=version[0:2] - versions.append(('intel '+major,targets)) -def get_msvc_versions(conf): - if not conf.env['MSVC_INSTALLED_VERSIONS']: - lst=[] - conf.gather_icl_versions(lst) - conf.gather_wsdk_versions(lst) - conf.gather_msvc_versions(lst) - conf.env['MSVC_INSTALLED_VERSIONS']=lst - return conf.env['MSVC_INSTALLED_VERSIONS'] -def print_all_msvc_detected(conf): - for version,targets in conf.env['MSVC_INSTALLED_VERSIONS']: - info(version) - for target,l in targets: - info("\t"+target) -def detect_msvc(conf): - versions=get_msvc_versions(conf) - return setup_msvc(conf,versions) -def find_lt_names_msvc(self,libname,is_static=False): - lt_names=['lib%s.la'%libname,'%s.la'%libname,] - for path in self.env['LIBPATH']: - for la in lt_names: - laf=os.path.join(path,la) - dll=None - if os.path.exists(laf): - ltdict=Utils.read_la_file(laf) - lt_libdir=None - if ltdict.get('libdir',''): - lt_libdir=ltdict['libdir'] - if not is_static and ltdict.get('library_names',''): - dllnames=ltdict['library_names'].split() - dll=dllnames[0].lower() - dll=re.sub('\.dll$','',dll) - return(lt_libdir,dll,False) - elif ltdict.get('old_library',''): - olib=ltdict['old_library'] - if os.path.exists(os.path.join(path,olib)): - return(path,olib,True) - elif lt_libdir!=''and os.path.exists(os.path.join(lt_libdir,olib)): - return(lt_libdir,olib,True) - else: - return(None,olib,True) - else: - raise Errors.WafError('invalid libtool object file: %s'%laf) - return(None,None,None) -def libname_msvc(self,libname,is_static=False): - lib=libname.lower() - lib=re.sub('\.lib$','',lib) - if lib in g_msvc_systemlibs: - return lib - lib=re.sub('^lib','',lib) - if lib=='m': - return None - (lt_path,lt_libname,lt_static)=self.find_lt_names_msvc(lib,is_static) - if lt_path!=None and lt_libname!=None: - if lt_static==True: - return os.path.join(lt_path,lt_libname) - if lt_path!=None: - _libpaths=[lt_path]+self.env['LIBPATH'] - else: - _libpaths=self.env['LIBPATH'] - static_libs=['lib%ss.lib'%lib,'lib%s.lib'%lib,'%ss.lib'%lib,'%s.lib'%lib,] - dynamic_libs=['lib%s.dll.lib'%lib,'lib%s.dll.a'%lib,'%s.dll.lib'%lib,'%s.dll.a'%lib,'lib%s_d.lib'%lib,'%s_d.lib'%lib,'%s.lib'%lib,] - libnames=static_libs - if not is_static: - libnames=dynamic_libs+static_libs - for path in _libpaths: - for libn in libnames: - if os.path.exists(os.path.join(path,libn)): - debug('msvc: lib found: %s'%os.path.join(path,libn)) - return re.sub('\.lib$','',libn) - self.fatal("The library %r could not be found"%libname) - return re.sub('\.lib$','',libname) -def check_lib_msvc(self,libname,is_static=False,uselib_store=None): - libn=self.libname_msvc(libname,is_static) - if not uselib_store: - uselib_store=libname.upper() - if False and is_static: - self.env['STLIB_'+uselib_store]=[libn] - else: - self.env['LIB_'+uselib_store]=[libn] -def check_libs_msvc(self,libnames,is_static=False): - for libname in Utils.to_list(libnames): - self.check_lib_msvc(libname,is_static) -def no_autodetect(conf): - conf.eval_rules(detect.replace('autodetect','')) -configure=''' -autodetect -find_msvc -msvc_common_flags -cc_load_tools -cxx_load_tools -cc_add_flags -cxx_add_flags -link_add_flags -''' -def autodetect(conf): - v=conf.env - compiler,version,path,includes,libdirs=detect_msvc(conf) - v['PATH']=path - v['INCLUDES']=includes - v['LIBPATH']=libdirs - v['MSVC_COMPILER']=compiler -def _get_prog_names(conf,compiler): - if compiler=='intel': - compiler_name='ICL' - linker_name='XILINK' - lib_name='XILIB' - else: - compiler_name='CL' - linker_name='LINK' - lib_name='LIB' - return compiler_name,linker_name,lib_name -def find_msvc(conf): - if sys.platform!='win32': - conf.fatal('MSVC module only works under native Win32 Python! cygwin is not supported yet') - v=conf.env - compiler,version,path,includes,libdirs=detect_msvc(conf) - v['PATH']=path - v['INCLUDES']=includes - v['LIBPATH']=libdirs - compiler_name,linker_name,lib_name=_get_prog_names(conf,compiler) - v.MSVC_MANIFEST=(compiler=='msvc'and float(version)>=8)or(compiler=='wsdk'and float(version)>=6)or(compiler=='intel'and float(version)>=11) - cxx=None - if v['CXX']:cxx=v['CXX'] - elif'CXX'in conf.environ:cxx=conf.environ['CXX'] - cxx=conf.find_program(compiler_name,var='CXX',path_list=path) - cxx=conf.cmd_to_list(cxx) - env=dict(conf.environ) - env.update(PATH=';'.join(path)) - if not conf.cmd_and_log(cxx+['/nologo','/?'],env=env): - conf.fatal('the msvc compiler could not be identified') - v['CC']=v['CXX']=cxx - v['CC_NAME']=v['CXX_NAME']='msvc' - try:v.prepend_value('INCLUDES',conf.environ['INCLUDE']) - except KeyError:pass - try:v.prepend_value('LIBPATH',conf.environ['LIB']) - except KeyError:pass - if not v['LINK_CXX']: - link=conf.find_program(linker_name,path_list=path) - if link:v['LINK_CXX']=link - else:conf.fatal('%s was not found (linker)'%linker_name) - v['LINK']=link - if not v['LINK_CC']: - v['LINK_CC']=v['LINK_CXX'] - if not v['AR']: - stliblink=conf.find_program(lib_name,path_list=path,var='AR') - if not stliblink:return - v['ARFLAGS']=['/NOLOGO'] - if v.MSVC_MANIFEST: - mt=conf.find_program('MT',path_list=path,var='MT') - v['MTFLAGS']=['/NOLOGO'] - conf.load('winres') - if not conf.env['WINRC']: - warn('Resource compiler not found. Compiling resource file is disabled') -def msvc_common_flags(conf): - v=conf.env - v['DEST_BINFMT']='pe' - v['LIBDIR']=v['PREFIX']+r'\bin' - v['CFLAGS']=v['CXXFLAGS']=['/nologo'] - v['DEFINES_ST']='/D%s' - v['CC_SRC_F']='' - v['CC_TGT_F']=['/c','/Fo'] - v['CXX_SRC_F']='' - v['CXX_TGT_F']=['/c','/Fo'] - v['CPPPATH_ST']='/I%s' - v['AR_TGT_F']=v['CCLNK_TGT_F']=v['CXXLNK_TGT_F']='/OUT:' - v['CFLAGS_CONSOLE']=v['CXXFLAGS_CONSOLE']=['/SUBSYSTEM:CONSOLE'] - v['CFLAGS_NATIVE']=v['CXXFLAGS_NATIVE']=['/SUBSYSTEM:NATIVE'] - v['CFLAGS_POSIX']=v['CXXFLAGS_POSIX']=['/SUBSYSTEM:POSIX'] - v['CFLAGS_WINDOWS']=v['CXXFLAGS_WINDOWS']=['/SUBSYSTEM:WINDOWS'] - v['CFLAGS_WINDOWSCE']=v['CXXFLAGS_WINDOWSCE']=['/SUBSYSTEM:WINDOWSCE'] - v['CFLAGS_CRT_MULTITHREADED']=v['CXXFLAGS_CRT_MULTITHREADED']=['/MT'] - v['CFLAGS_CRT_MULTITHREADED_DLL']=v['CXXFLAGS_CRT_MULTITHREADED_DLL']=['/MD'] - v['CFLAGS_CRT_MULTITHREADED_DBG']=v['CXXFLAGS_CRT_MULTITHREADED_DBG']=['/MTd'] - v['CFLAGS_CRT_MULTITHREADED_DLL_DBG']=v['CXXFLAGS_CRT_MULTITHREADED_DLL_DBG']=['/MDd'] - v['LIB_ST']='%s.lib' - v['LIBPATH_ST']='/LIBPATH:%s' - v['STLIB_ST']='lib%s.lib' - v['STLIBPATH_ST']='/LIBPATH:%s' - v['LINKFLAGS']=['/NOLOGO'] - if v['MSVC_MANIFEST']: - v.append_value('LINKFLAGS','/MANIFEST') - v['CFLAGS_cshlib']=[''] - v['CXXFLAGS_cxxshlib']=[''] - v['LINKFLAGS_cshlib']=v['LINKFLAGS_cxxshlib']=['/DLL'] - v['cshlib_PATTERN']=v['cxxshlib_PATTERN']='%s.dll' - v['implib_PATTERN']='%s.lib' - v['IMPLIB_ST']='/IMPLIB:%s' - v['LINKFLAGS_cstlib']=[''] - v['cstlib_PATTERN']=v['cxxstlib_PATTERN']='lib%s.lib' - v['cprogram_PATTERN']=v['cxxprogram_PATTERN']='%s.exe' -def apply_flags_msvc(self): - if self.env.CC_NAME!='msvc'or not getattr(self,'link_task',None): - return - is_static=isinstance(self.link_task,ccroot.stlink_task) - subsystem=getattr(self,'subsystem','') - if subsystem: - subsystem='/subsystem:%s'%subsystem - flags=is_static and'ARFLAGS'or'LINKFLAGS' - self.env.append_value(flags,subsystem) - if not is_static: - for f in self.env.LINKFLAGS: - d=f.lower() - if d[1:]=='debug': - pdbnode=self.link_task.outputs[0].change_ext('.pdb') - pdbfile=pdbnode.bldpath() - self.link_task.outputs.append(pdbnode) - self.bld.install_files(self.install_path,[pdbnode],env=self.env) - break -def apply_manifest(self): - if self.env.CC_NAME=='msvc'and self.env.MSVC_MANIFEST and getattr(self,'link_task',None): - out_node=self.link_task.outputs[0] - man_node=out_node.parent.find_or_declare(out_node.name+'.manifest') - self.link_task.outputs.append(man_node) - self.link_task.do_manifest=True -def exec_mf(self): - env=self.env - mtool=env['MT'] - if not mtool: - return 0 - self.do_manifest=False - outfile=self.outputs[0].abspath() - manifest=None - for out_node in self.outputs: - if out_node.name.endswith('.manifest'): - manifest=out_node.abspath() - break - if manifest is None: - return 0 - mode='' - if'cprogram'in self.generator.features or'cxxprogram'in self.generator.features: - mode='1' - elif'cshlib'in self.generator.features or'cxxshlib'in self.generator.features: - mode='2' - debug('msvc: embedding manifest in mode %r'%mode) - lst=[] - lst.extend([env['MT']]) - lst.extend(Utils.to_list(env['MTFLAGS'])) - lst.extend(Utils.to_list("-manifest")) - lst.extend(Utils.to_list(manifest)) - lst.extend(Utils.to_list("-outputresource:%s;%s"%(outfile,mode))) - lst=[lst] - return self.exec_command(*lst) -def exec_command_msvc(self,*k,**kw): - if self.env['CC_NAME']=='msvc': - if isinstance(k[0],list): - lst=[] - carry='' - for a in k[0]: - if len(a)==3 and a.startswith('/F')or a=='/doc'or a[-1]==':': - carry=a - else: - lst.append(carry+a) - carry='' - k=[lst] - env=dict(os.environ) - env.update(PATH=';'.join(self.env['PATH'])) - kw['env']=env - bld=self.generator.bld - try: - if not kw.get('cwd',None): - kw['cwd']=bld.cwd - except AttributeError: - bld.cwd=kw['cwd']=bld.variant_dir - ret=self.generator.bld.exec_command(*k,**kw) - if ret:return ret - if getattr(self,'do_manifest',None): - ret=exec_mf(self) - return ret -for k in'c cxx winrc cprogram cxxprogram cshlib cxxshlib cstlib cxxstlib qxx'.split(): - cls=Task.classes.get(k,None) - if cls: - cls.exec_command=exec_command_msvc - -conf(get_msvc_version) -conf(gather_wsdk_versions) -conf(gather_msvc_versions) -conf(gather_icl_versions) -conf(get_msvc_versions) -conf(print_all_msvc_detected) -conf(find_lt_names_msvc) -conf(libname_msvc) -conf(check_lib_msvc) -conf(check_libs_msvc) -conf(no_autodetect) -conf(autodetect) -conf(find_msvc) -conf(msvc_common_flags) -after('apply_link')(apply_flags_msvc) -feature('c','cxx')(apply_flags_msvc) -feature('cprogram','cshlib','cxxprogram','cxxshlib')(apply_manifest) -after('apply_link')(apply_manifest) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/nasm.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/nasm.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/nasm.py +++ /dev/null @@ -1,13 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import waflib.Tools.ccroot -from waflib.TaskGen import feature -def apply_nasm_vars(self): - self.env.append_value('ASFLAGS',self.to_list(getattr(self,'nasm_flags',[]))) -def configure(conf): - nasm=conf.find_program(['nasm','yasm'],var='AS') - conf.env.AS_TGT_F='-o' - -feature('asm')(apply_nasm_vars) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/perl.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/perl.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/perl.py +++ /dev/null @@ -1,79 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os -from waflib import Task,Options,Utils -from waflib.Configure import conf -from waflib.TaskGen import extension,feature,before -def init_perlext(self): - self.uselib=self.to_list(getattr(self,'uselib',[])) - if not'PERLEXT'in self.uselib:self.uselib.append('PERLEXT') - self.env['cshlib_PATTERN']=self.env['cxxshlib_PATTERN']=self.env['perlext_PATTERN'] -def xsubpp_file(self,node): - outnode=node.change_ext('.c') - self.create_task('xsubpp',node,outnode) - self.source.append(outnode) -class xsubpp(Task.Task): - run_str='${PERL} ${XSUBPP} -noprototypes -typemap ${EXTUTILS_TYPEMAP} ${SRC} > ${TGT}' - color='BLUE' - ext_out=['.h'] -def check_perl_version(self,minver=None): - res=True - if not getattr(Options.options,'perlbinary',None): - perl=self.find_program('perl',var='PERL') - if not perl: - return False - else: - self.env['PERL']=perl=Options.options.perlbinary - version=self.cmd_and_log([perl,"-e",'printf \"%vd\", $^V']) - if not version: - res=False - version="Unknown" - elif not minver is None: - ver=tuple(map(int,version.split("."))) - if ver0: - if self.env['PYC']or self.env['PYO']: - info("+ byte compiling %r"%path) - if self.env['PYC']: - argv=[self.env['PYTHON'],'-c',INST%'c',path] - ret=Utils.subprocess.Popen(argv).wait() - if ret: - raise Errors.WafError('pyc compilation failed %r'%path) - if self.env['PYO']: - argv=[self.env['PYTHON'],self.env['PYFLAGS_OPT'],'-c',INST%'o',path] - ret=Utils.subprocess.Popen(argv).wait() - if ret: - raise Errors.WafError('pyo compilation failed %r'%path) -def feature_py(self): - pass -def init_pyext(self): - if not getattr(self,'install_path',None): - self.install_path='${PYTHONDIR}' - self.uselib=self.to_list(getattr(self,'uselib',[])) - if not'PYEXT'in self.uselib: - self.uselib.append('PYEXT') - self.env['cshlib_PATTERN']=self.env['cxxshlib_PATTERN']=self.env['pyext_PATTERN'] -def init_pyembed(self): - self.uselib=self.to_list(getattr(self,'uselib',[])) - if not'PYEMBED'in self.uselib: - self.uselib.append('PYEMBED') -def get_python_variables(conf,python_exe,variables,imports=['import sys']): - program=list(imports) - program.append('') - for v in variables: - program.append("print(repr(%s))"%v) - os_env=dict(os.environ) - try: - del os_env['MACOSX_DEPLOYMENT_TARGET'] - except KeyError: - pass - out=conf.cmd_and_log([python_exe,'-c','\n'.join(program)],env=os_env) - return_values=[] - for s in out.split('\n'): - s=s.strip() - if not s: - continue - if s=='None': - return_values.append(None) - elif s[0]=="'"and s[-1]=="'": - return_values.append(s[1:-1]) - elif s[0].isdigit(): - return_values.append(int(s)) - else:break - return return_values -def check_python_headers(conf): - if not conf.env['CC_NAME']and not conf.env['CXX_NAME']: - conf.fatal('load a compiler first (gcc, g++, ..)') - if not conf.env['PYTHON_VERSION']: - conf.check_python_version() - env=conf.env - python=env['PYTHON'] - if not python: - conf.fatal('could not find the python executable') - v='prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS'.split() - try: - lst=conf.get_python_variables(python,["get_config_var('%s')"%x for x in v],['from distutils.sysconfig import get_config_var']) - except RuntimeError: - conf.fatal("Python development headers not found (-v for details).") - vals=['%s = %r'%(x,y)for(x,y)in zip(v,lst)] - conf.to_log("Configuration returned from %r:\n%r\n"%(python,'\n'.join(vals))) - dct=dict(zip(v,lst)) - x='MACOSX_DEPLOYMENT_TARGET' - if dct[x]: - conf.env[x]=conf.environ[x]=dct[x] - env['pyext_PATTERN']='%s'+dct['SO'] - all_flags=dct['LDFLAGS']+' '+dct['LDSHARED']+' '+dct['CFLAGS'] - conf.parse_flags(all_flags,'PYEMBED') - conf.parse_flags(all_flags,'PYEXT') - result=None - name='python'+env['PYTHON_VERSION'] - path=env['LIBPATH_PYEMBED'] - conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n"%path) - result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False) - if not result: - conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n"%path) - path=[dct['LIBDIR']or''] - result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False) - if not result: - conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n") - path=[dct['LIBPL']or''] - result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False) - if not result: - conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n") - path=[os.path.join(dct['prefix'],"libs")] - name='python'+env['PYTHON_VERSION'].replace('.','') - result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False) - if result: - env['LIBPATH_PYEMBED']=path - env.append_value('LIB_PYEMBED',[name]) - else: - conf.to_log("\n\n### LIB NOT FOUND\n") - if(sys.platform=='win32'or sys.platform.startswith('os2')or sys.platform=='darwin'or dct['Py_ENABLE_SHARED']): - env['LIBPATH_PYEXT']=env['LIBPATH_PYEMBED'] - env['LIB_PYEXT']=env['LIB_PYEMBED'] - num='.'.join(env['PYTHON_VERSION'].split('.')[:2]) - try: - conf.find_program('python%s-config'%num,var='PYTHON_CONFIG') - except conf.errors.ConfigurationError: - conf.find_program('python-config-%s'%num,var='PYTHON_CONFIG',mandatory=False) - includes=[] - if conf.env.PYTHON_CONFIG: - for incstr in conf.cmd_and_log("%s %s --includes"%(python,conf.env.PYTHON_CONFIG)).strip().split(): - if(incstr.startswith('-I')or incstr.startswith('/I')): - incstr=incstr[2:] - if incstr not in includes: - includes.append(incstr) - conf.to_log("Include path for Python extensions ""(found via python-config --includes): %r\n"%(includes,)) - env['INCLUDES_PYEXT']=includes - env['INCLUDES_PYEMBED']=includes - else: - conf.to_log("Include path for Python extensions ""(found via distutils module): %r\n"%(dct['INCLUDEPY'],)) - env['INCLUDES_PYEXT']=[dct['INCLUDEPY']] - env['INCLUDES_PYEMBED']=[dct['INCLUDEPY']] - if env['CC_NAME']=='gcc': - env.append_value('CFLAGS_PYEMBED',['-fno-strict-aliasing']) - env.append_value('CFLAGS_PYEXT',['-fno-strict-aliasing']) - if env['CXX_NAME']=='gcc': - env.append_value('CXXFLAGS_PYEMBED',['-fno-strict-aliasing']) - env.append_value('CXXFLAGS_PYEXT',['-fno-strict-aliasing']) - conf.check(header_name='Python.h',define_name='HAVE_PYTHON_H',uselib='PYEMBED',fragment=FRAG,errmsg='Could not find the python development headers') -def check_python_version(conf,minver=None): - assert minver is None or isinstance(minver,tuple) - python=conf.env['PYTHON'] - if not python: - conf.fatal('could not find the python executable') - cmd=[python,'-c','import sys\nfor x in sys.version_info: print(str(x))'] - debug('python: Running python command %r'%cmd) - lines=conf.cmd_and_log(cmd).split() - assert len(lines)==5,"found %i lines, expected 5: %r"%(len(lines),lines) - pyver_tuple=(int(lines[0]),int(lines[1]),int(lines[2]),lines[3],int(lines[4])) - result=(minver is None)or(pyver_tuple>=minver) - if result: - pyver='.'.join([str(x)for x in pyver_tuple[:2]]) - conf.env['PYTHON_VERSION']=pyver - if'PYTHONDIR'in conf.environ: - pydir=conf.environ['PYTHONDIR'] - else: - if sys.platform=='win32': - (python_LIBDEST,pydir)=conf.get_python_variables(python,["get_config_var('LIBDEST')","get_python_lib(standard_lib=0, prefix=%r)"%conf.env['PREFIX']],['from distutils.sysconfig import get_config_var, get_python_lib']) - else: - python_LIBDEST=None - (pydir,)=conf.get_python_variables(python,["get_python_lib(standard_lib=0, prefix=%r)"%conf.env['PREFIX']],['from distutils.sysconfig import get_config_var, get_python_lib']) - if python_LIBDEST is None: - if conf.env['LIBDIR']: - python_LIBDEST=os.path.join(conf.env['LIBDIR'],"python"+pyver) - else: - python_LIBDEST=os.path.join(conf.env['PREFIX'],"lib","python"+pyver) - if hasattr(conf,'define'): - conf.define('PYTHONDIR',pydir) - conf.env['PYTHONDIR']=pydir - pyver_full='.'.join(map(str,pyver_tuple[:3])) - if minver is None: - conf.msg('Checking for python version',pyver_full) - else: - minver_str='.'.join(map(str,minver)) - conf.msg('Checking for python version',pyver_tuple,">= %s"%(minver_str,)and'GREEN'or'YELLOW') - if not result: - conf.fatal('The python version is too old, expecting %r'%(minver,)) -def check_python_module(conf,module_name): - conf.start_msg('Python module %s'%module_name) - try: - conf.cmd_and_log([conf.env['PYTHON'],'-c','import %s\nprint(1)\n'%module_name]) - except: - conf.end_msg(False) - conf.fatal('Could not find the python module %r'%module_name) - conf.end_msg(True) -def configure(conf): - try: - conf.find_program('python',var='PYTHON') - except conf.errors.ConfigurationError: - warn("could not find a python executable, setting to sys.executable '%s'"%sys.executable) - conf.env.PYTHON=sys.executable - if conf.env.PYTHON!=sys.executable: - warn("python executable '%s' different from sys.executable '%s'"%(conf.env.PYTHON,sys.executable)) - v=conf.env - v['PYCMD']='"import sys, py_compile;py_compile.compile(sys.argv[1], sys.argv[2])"' - v['PYFLAGS']='' - v['PYFLAGS_OPT']='-O' - v['PYC']=getattr(Options.options,'pyc',1) - v['PYO']=getattr(Options.options,'pyo',1) -def options(opt): - opt.add_option('--nopyc',action='store_false',default=1,help='Do not install bytecode compiled .pyc files (configuration) [Default:install]',dest='pyc') - opt.add_option('--nopyo',action='store_false',default=1,help='Do not install optimised compiled .pyo files (configuration) [Default:install]',dest='pyo') - -extension('.py')(process_py) -feature('py')(feature_py) -feature('pyext')(init_pyext) -before('propagate_uselib_vars','apply_link')(init_pyext) -before('propagate_uselib_vars')(init_pyembed) -feature('pyembed')(init_pyembed) -conf(get_python_variables) -conf(check_python_headers) -conf(check_python_version) -conf(check_python_module) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/qt4.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/qt4.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/qt4.py +++ /dev/null @@ -1,355 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -if sys.hexversion < 0x020400f0: from sets import Set as set -try: - from xml.sax import make_parser - from xml.sax.handler import ContentHandler -except ImportError: - has_xml=False - ContentHandler=object -else: - has_xml=True -import os,sys -from waflib.Tools import c_preproc,cxx -from waflib import TaskGen,Task,Utils,Runner,Options,Node,Errors -from waflib.TaskGen import feature,after,extension -from waflib.Logs import error -MOC_H=['.h','.hpp','.hxx','.hh'] -EXT_RCC=['.qrc'] -EXT_UI=['.ui'] -EXT_QT4=['.cpp','.cc','.cxx','.C'] -class qxx(cxx.cxx): - def __init__(self,*k,**kw): - Task.Task.__init__(self,*k,**kw) - self.moc_done=0 - def scan(self): - (nodes,names)=c_preproc.scan(self) - for x in nodes: - if x.name.endswith('.moc'): - nodes.remove(x) - names.append(x.path_from(self.inputs[0].parent.get_bld())) - return(nodes,names) - def runnable_status(self): - if self.moc_done: - for t in self.run_after: - if not t.hasrun: - return Task.ASK_LATER - self.signature() - return Task.Task.runnable_status(self) - else: - for t in self.run_after: - if not t.hasrun: - return Task.ASK_LATER - self.add_moc_tasks() - return Task.ASK_LATER - def add_moc_tasks(self): - node=self.inputs[0] - bld=self.generator.bld - try: - self.signature() - except KeyError: - pass - else: - delattr(self,'cache_sig') - moctasks=[] - mocfiles=[] - try: - tmp_lst=bld.raw_deps[self.uid()] - bld.raw_deps[self.uid()]=[] - except KeyError: - tmp_lst=[] - for d in tmp_lst: - if not d.endswith('.moc'): - continue - if d in mocfiles: - error("paranoia owns") - continue - mocfiles.append(d) - ext='' - try:ext=Options.options.qt_header_ext - except AttributeError:pass - if not ext: - base2=d[:-4] - for exth in MOC_H: - k=node.parent.find_node(base2+exth) - if k: - break - else: - raise Errors.WafError('no header found for %r which is a moc file'%d) - h_node=node.parent.find_resource(base2+exth) - m_node=h_node.change_ext('.moc') - bld.node_deps[(self.inputs[0].parent.abspath(),m_node.name)]=h_node - task=Task.classes['moc'](env=self.env,generator=self.generator) - task.set_inputs(h_node) - task.set_outputs(m_node) - gen=bld.producer - gen.outstanding.insert(0,task) - gen.total+=1 - moctasks.append(task) - tmp_lst=bld.raw_deps[self.uid()]=mocfiles - lst=bld.node_deps.get(self.uid(),()) - for d in lst: - name=d.name - if name.endswith('.moc'): - task=Task.classes['moc'](env=self.env,generator=self.generator) - task.set_inputs(bld.node_deps[(self.inputs[0].parent.abspath(),name)]) - task.set_outputs(d) - gen=bld.producer - gen.outstanding.insert(0,task) - gen.total+=1 - moctasks.append(task) - self.run_after.update(set(moctasks)) - self.moc_done=1 - run=Task.classes['cxx'].__dict__['run'] -def translation_update(task): - outs=[a.abspath()for a in task.outputs] - outs=" ".join(outs) - lupdate=task.env['QT_LUPDATE'] - for x in task.inputs: - file=x.abspath() - cmd="%s %s -ts %s"%(lupdate,file,outs) - Logs.pprint('BLUE',cmd) - task.generator.bld.exec_command(cmd) -class XMLHandler(ContentHandler): - def __init__(self): - self.buf=[] - self.files=[] - def startElement(self,name,attrs): - if name=='file': - self.buf=[] - def endElement(self,name): - if name=='file': - self.files.append(str(''.join(self.buf))) - def characters(self,cars): - self.buf.append(cars) -def create_rcc_task(self,node): - rcnode=node.change_ext('_rc.cpp') - rcctask=self.create_task('rcc',node,rcnode) - cpptask=self.create_task('cxx',rcnode,rcnode.change_ext('.o')) - self.compiled_tasks.append(cpptask) - return cpptask -def create_uic_task(self,node): - uictask=self.create_task('ui4',node) - uictask.outputs=[self.path.find_or_declare(self.env['ui_PATTERN']%node.name[:-3])] -def add_lang(self,node): - self.lang=self.to_list(getattr(self,'lang',[]))+[node] -def apply_qt4(self): - if getattr(self,'lang',None): - update=getattr(self,'update',None) - lst=[] - trans=[] - for l in self.to_list(self.lang): - if not isinstance(l,Node.Node): - l=self.path.find_resource(l+'.ts') - t=self.create_task('ts2qm',l,l.change_ext('.qm')) - lst.append(t.outputs[0]) - if update: - trans.append(t.inputs[0]) - if update and Options.options.trans_qt4: - u=Task.TaskCmd(translation_update,self.env,2) - u.inputs=[a.inputs[0]for a in self.compiled_tasks] - u.outputs=trans - if getattr(self,'langname',None): - t=Task.classes['qm2rcc'](self.env) - t.set_inputs(lst) - t.set_outputs(self.path.find_or_declare(self.langname+'.qrc')) - t.path=self.path - k=create_rcc_task(self,t.outputs[0]) - self.link_task.inputs.append(k.outputs[0]) - lst=[] - for flag in self.to_list(self.env['CXXFLAGS']): - if len(flag)<2:continue - if flag[0:2]=='-D'or flag[0:2]=='-I': - lst.append(flag) - self.env['MOC_FLAGS']=lst -def cxx_hook(self,node): - return self.create_compiled_task('qxx',node) -class rcc(Task.Task): - color='BLUE' - run_str='${QT_RCC} -name ${SRC[0].name} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}' - ext_out=['.h'] - def scan(self): - node=self.inputs[0] - parser=make_parser() - curHandler=XMLHandler() - parser.setContentHandler(curHandler) - fi=open(self.inputs[0].abspath()) - parser.parse(fi) - fi.close() - nodes=[] - names=[] - root=self.inputs[0].parent - for x in curHandler.files: - nd=root.find_resource(x) - if nd:nodes.append(nd) - else:names.append(x) - return(nodes,names) -class moc(Task.Task): - color='BLUE' - run_str='${QT_MOC} ${MOC_FLAGS} ${SRC} ${MOC_ST} ${TGT}' -class ui4(Task.Task): - color='BLUE' - run_str='${QT_UIC} ${SRC} -o ${TGT}' - ext_out=['.h'] -class ts2qm(Task.Task): - color='BLUE' - run_str='${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}' -class qm2rcc(Task.Task): - color='BLUE' - after='ts2qm' - before='rcc' - def process_qm2rcc(self): - txt='\n'.join(['%s'%k.path_from(self.path)for k in self.inputs]) - code='\n\n%s\n\n'%txt - task.outputs[0].write(code) -def configure(self): - env=self.env - opt=Options.options - qtdir=getattr(opt,'qtdir','') - qtbin=getattr(opt,'qtbin','') - qtlibs=getattr(opt,'qtlibs','') - useframework=getattr(opt,'use_qt4_osxframework',True) - paths=[] - if qtbin: - paths=[qtbin] - if not qtdir: - qtdir=self.environ.get('QT4_ROOT','') - qtbin=os.path.join(qtdir,'bin') - paths=[qtbin] - if not qtdir: - paths=os.environ.get('PATH','').split(os.pathsep) - paths.append('/usr/share/qt4/bin/') - try: - lst=os.listdir('/usr/local/Trolltech/') - except OSError: - pass - else: - if lst: - lst.sort() - lst.reverse() - qtdir='/usr/local/Trolltech/%s/'%lst[0] - qtbin=os.path.join(qtdir,'bin') - paths.append(qtbin) - cand=None - prev_ver=['4','0','0'] - for qmk in['qmake-qt4','qmake4','qmake']: - try: - qmake=self.find_program(qmk,path_list=paths) - except self.errors.ConfigurationError: - pass - else: - try: - version=self.cmd_and_log([qmake,'-query','QT_VERSION']).strip() - except self.errors.ConfigurationError: - pass - else: - if version: - new_ver=version.split('.') - if new_ver>prev_ver: - cand=qmake - prev_ver=new_ver - if cand: - qmake=cand - else: - self.fatal('could not find qmake for qt4') - self.env.QMAKE=qmake - qtincludes=self.cmd_and_log([qmake,'-query','QT_INSTALL_HEADERS']).strip() - qtdir=self.cmd_and_log([qmake,'-query','QT_INSTALL_PREFIX']).strip()+os.sep - qtbin=self.cmd_and_log([qmake,'-query','QT_INSTALL_BINS']).strip()+os.sep - if not qtlibs: - try: - qtlibs=self.cmd_and_log([qmake,'-query','QT_INSTALL_LIBS']).strip() - except Errors.WafError: - qtlibs=os.path.join(qtdir,'lib') - def find_bin(lst,var): - for f in lst: - try: - ret=self.find_program(f,path_list=paths) - except self.errors.ConfigurationError: - pass - else: - env[var]=ret - break - find_bin(['uic-qt3','uic3'],'QT_UIC3') - find_bin(['uic-qt4','uic'],'QT_UIC') - if not env['QT_UIC']: - self.fatal('cannot find the uic compiler for qt4') - try: - version=self.cmd_and_log(env['QT_UIC']+" -version 2>&1").strip() - except self.errors.ConfigurationError: - self.fatal('your uic compiler is for qt3, add uic for qt4 to your path') - version=version.replace('Qt User Interface Compiler ','') - version=version.replace('User Interface Compiler for Qt','') - if version.find(' 3.')!=-1: - self.msg('Checking for uic version','(%s: too old)'%version,False) - self.fatal('uic is too old') - self.msg('Checking for uic version','(%s)'%version) - find_bin(['moc-qt4','moc'],'QT_MOC') - find_bin(['rcc'],'QT_RCC') - find_bin(['lrelease-qt4','lrelease'],'QT_LRELEASE') - find_bin(['lupdate-qt4','lupdate'],'QT_LUPDATE') - env['UIC3_ST']='%s -o %s' - env['UIC_ST']='%s -o %s' - env['MOC_ST']='-o' - env['ui_PATTERN']='ui_%s.h' - env['QT_LRELEASE_FLAGS']=['-silent'] - vars="QtCore QtGui QtUiTools QtNetwork QtOpenGL QtSql QtSvg QtTest QtXml QtWebKit Qt3Support".split() - vars_debug=[a+'_debug'for a in vars] - if not'PKG_CONFIG_PATH'in os.environ: - os.environ['PKG_CONFIG_PATH']='%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib pkg-config --silence-errors'%(qtlibs,qtlibs) - pkgconfig=env['pkg-config']or'pkg-config' - for i in vars_debug+vars: - try: - self.check_cfg(package=i,args='--cflags --libs',path=pkgconfig) - except self.errors.ConfigurationError: - pass - def process_lib(vars_,coreval): - for d in vars_: - var=d.upper() - if var=='QTCORE': - continue - value=env['LIBPATH_'+var] - if value: - core=env[coreval] - accu=[] - for lib in value: - if lib in core: - continue - accu.append(lib) - env['LIBPATH_'+var]=accu - process_lib(vars,'LIBPATH_QTCORE') - process_lib(vars_debug,'LIBPATH_QTCORE_DEBUG') - if Options.options.want_rpath: - def process_rpath(vars_,coreval): - for d in vars_: - var=d.upper() - value=env['LIBPATH_'+var] - if value: - core=env[coreval] - accu=[] - for lib in value: - if var!='QTCORE': - if lib in core: - continue - accu.append('-Wl,--rpath='+lib) - env['RPATH_'+var]=accu - process_rpath(vars,'LIBPATH_QTCORE') - process_rpath(vars_debug,'LIBPATH_QTCORE_DEBUG') -def options(opt): - opt.add_option('--want-rpath',action='store_true',default=False,dest='want_rpath',help='enable the rpath for qt libraries') - opt.add_option('--header-ext',type='string',default='',help='header extension for moc files',dest='qt_header_ext') - for i in'qtdir qtbin qtlibs'.split(): - opt.add_option('--'+i,type='string',default='',dest=i) - if sys.platform=="darwin": - opt.add_option('--no-qt4-framework',action="store_false",help='do not use the framework version of Qt4 in OS X',dest='use_qt4_osxframework',default=True) - opt.add_option('--translate',action="store_true",help="collect translation strings",dest="trans_qt4",default=False) - -extension(*EXT_RCC)(create_rcc_task) -extension(*EXT_UI)(create_uic_task) -extension('.ts')(add_lang) -feature('qt4')(apply_qt4) -after('apply_link')(apply_qt4) -extension(*EXT_QT4)(cxx_hook) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/ruby.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/ruby.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/ruby.py +++ /dev/null @@ -1,89 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os -from waflib import Task,Options,Utils -from waflib.TaskGen import before,feature,after -from waflib.Configure import conf -def init_rubyext(self): - self.install_path='${ARCHDIR_RUBY}' - self.uselib=self.to_list(getattr(self,'uselib','')) - if not'RUBY'in self.uselib: - self.uselib.append('RUBY') - if not'RUBYEXT'in self.uselib: - self.uselib.append('RUBYEXT') -def apply_ruby_so_name(self): - self.env['cshlib_PATTERN']=self.env['cxxshlib_PATTERN']=self.env['rubyext_PATTERN'] -def check_ruby_version(self,minver=()): - if Options.options.rubybinary: - self.env.RUBY=Options.options.rubybinary - else: - self.find_program('ruby',var='RUBY') - ruby=self.env.RUBY - try: - version=self.cmd_and_log([ruby,'-e','puts defined?(VERSION) ? VERSION : RUBY_VERSION']).strip() - except: - self.fatal('could not determine ruby version') - self.env.RUBY_VERSION=version - try: - ver=tuple(map(int,version.split("."))) - except: - self.fatal('unsupported ruby version %r'%version) - cver='' - if minver: - if ver=(1,9,0): - ruby_hdrdir=read_config('rubyhdrdir') - cpppath+=ruby_hdrdir - cpppath+=[os.path.join(ruby_hdrdir[0],read_config('arch')[0])] - self.check(header_name='ruby.h',includes=cpppath,errmsg='could not find ruby header file') - self.env.LIBPATH_RUBYEXT=read_config('libdir') - self.env.LIBPATH_RUBYEXT+=archdir - self.env.INCLUDES_RUBYEXT=cpppath - self.env.CFLAGS_RUBYEXT=read_config('CCDLFLAGS') - self.env.rubyext_PATTERN='%s.'+read_config('DLEXT')[0] - flags=read_config('LDSHARED') - while flags and flags[0][0]!='-': - flags=flags[1:] - if len(flags)>1 and flags[1]=="ppc": - flags=flags[2:] - self.env.LINKFLAGS_RUBYEXT=flags - self.env.LINKFLAGS_RUBYEXT+=read_config('LIBS') - self.env.LINKFLAGS_RUBYEXT+=read_config('LIBRUBYARG_SHARED') - if Options.options.rubyarchdir: - self.env.ARCHDIR_RUBY=Options.options.rubyarchdir - else: - self.env.ARCHDIR_RUBY=read_config('sitearchdir')[0] - if Options.options.rubylibdir: - self.env.LIBDIR_RUBY=Options.options.rubylibdir - else: - self.env.LIBDIR_RUBY=read_config('sitelibdir')[0] -def options(opt): - opt.add_option('--with-ruby-archdir',type='string',dest='rubyarchdir',help='Specify directory where to install arch specific files') - opt.add_option('--with-ruby-libdir',type='string',dest='rubylibdir',help='Specify alternate ruby library path') - opt.add_option('--with-ruby-binary',type='string',dest='rubybinary',help='Specify alternate ruby binary') - -feature('rubyext')(init_rubyext) -before('apply_incpaths','apply_lib_vars','apply_bundle','apply_link')(init_rubyext) -after('vars_target_cshlib')(init_rubyext) -feature('rubyext')(apply_ruby_so_name) -before('apply_link','propagate_uselib')(apply_ruby_so_name) -conf(check_ruby_version) -conf(check_ruby_ext_devel) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/suncc.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/suncc.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/suncc.py +++ /dev/null @@ -1,54 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os -from waflib import Utils -from waflib.Tools import ccroot,ar -from waflib.Configure import conf -def find_scc(conf): - v=conf.env - cc=None - if v['CC']:cc=v['CC'] - elif'CC'in conf.environ:cc=conf.environ['CC'] - if not cc:cc=conf.find_program('cc',var='CC') - if not cc:conf.fatal('suncc was not found') - try: - conf.cmd_and_log('%s -flags'%cc) - except: - conf.fatal('suncc %r was not found'%cc) - v['CC']=cc - v['CC_NAME']='sun' -def scc_common_flags(conf): - v=conf.env - v['CC_SRC_F']='' - v['CC_TGT_F']=['-c','-o',''] - if not v['LINK_CC']:v['LINK_CC']=v['CC'] - v['CCLNK_SRC_F']='' - v['CCLNK_TGT_F']=['-o',''] - v['CPPPATH_ST']='-I%s' - v['DEFINES_ST']='-D%s' - v['LIB_ST']='-l%s' - v['LIBPATH_ST']='-L%s' - v['STLIB_ST']='-l%s' - v['STLIBPATH_ST']='-L%s' - v['SONAME_ST']='-Wl,-h -Wl,%s' - v['SHLIB_MARKER']='-Bdynamic' - v['STLIB_MARKER']='-Bstatic' - v['cprogram_PATTERN']='%s' - v['CFLAGS_cshlib']=['-Kpic','-DPIC'] - v['LINKFLAGS_cshlib']=['-G'] - v['cshlib_PATTERN']='lib%s.so' - v['LINKFLAGS_cstlib']=['-Bstatic'] - v['cstlib_PATTERN']='lib%s.a' -configure=''' -find_scc -find_ar -scc_common_flags -cc_load_tools -cc_add_flags -link_add_flags -''' - -conf(find_scc) -conf(scc_common_flags) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/suncxx.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/suncxx.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/suncxx.py +++ /dev/null @@ -1,51 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os -from waflib import Utils -from waflib.Tools import ccroot,ar -from waflib.Configure import conf -def find_sxx(conf): - v=conf.env - cc=None - if v['CXX']:cc=v['CXX'] - elif'CXX'in conf.environ:cc=conf.environ['CXX'] - if not cc:cc=conf.find_program('c++',var='CXX') - if not cc:cc=conf.find_program('CC',var='CXX') - if not cc:conf.fatal('sunc++ was not found') - v['CXX']=cc - v['CXX_NAME']='sun' -def sxx_common_flags(conf): - v=conf.env - v['CXX_SRC_F']='' - v['CXX_TGT_F']=['-c','-o',''] - if not v['LINK_CXX']:v['LINK_CXX']=v['CXX'] - v['CXXLNK_SRC_F']='' - v['CXXLNK_TGT_F']=['-o',''] - v['CPPPATH_ST']='-I%s' - v['DEFINES_ST']='-D%s' - v['LIB_ST']='-l%s' - v['LIBPATH_ST']='-L%s' - v['STLIB_ST']='-l%s' - v['STLIBPATH_ST']='-L%s' - v['SONAME_ST']='-Wl,-h -Wl,%s' - v['SHLIB_MARKER']='-Bdynamic' - v['STLIB_MARKER']='-Bstatic' - v['cxxprogram_PATTERN']='%s' - v['CXXFLAGS_cxxshlib']=['-Kpic','-DPIC'] - v['LINKFLAGS_cxxshlib']=['-G'] - v['cxxshlib_PATTERN']='lib%s.so' - v['LINKFLAGS_cxxstlib']=['-Bstatic'] - v['cxxstlib_PATTERN']='lib%s.a' -configure=''' -find_sxx -find_ar -sxx_common_flags -cxx_load_tools -cxx_add_flags -link_add_flags -''' - -conf(find_sxx) -conf(sxx_common_flags) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/tex.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/tex.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/tex.py +++ /dev/null @@ -1,165 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,re -from waflib import Utils,Task,Runner,Build -from waflib.TaskGen import feature,before -from waflib.Logs import error,warn,debug -re_tex=re.compile(r'\\(?Pinclude|bibliography|includegraphics|input|import|bringin|lstinputlisting)(\[[^\[\]]*\])?{(?P[^{}]*)}',re.M) -def scan(self): - node=self.inputs[0] - env=self.env - nodes=[] - names=[] - if not node:return(nodes,names) - code=Utils.readf(node.abspath()) - global re_tex - for match in re_tex.finditer(code): - path=match.group('file') - if path: - for k in['','.tex','.ltx','.bib']: - debug('tex: trying %s%s'%(path,k)) - fi=node.parent.find_resource(path+k) - if fi: - nodes.append(fi) - else: - debug('tex: could not find %s'%path) - names.append(path) - debug("tex: found the following : %s and names %s"%(nodes,names)) - return(nodes,names) -latex_fun,_=Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}',shell=False) -pdflatex_fun,_=Task.compile_fun('${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}',shell=False) -bibtex_fun,_=Task.compile_fun('${BIBTEX} ${BIBTEXFLAGS} ${SRCFILE}',shell=False) -makeindex_fun,_=Task.compile_fun('${MAKEINDEX} ${MAKEINDEXFLAGS} ${SRCFILE}',shell=False) -g_bibtex_re=re.compile('bibdata',re.M) -def tex_build(task,command='LATEX'): - env=task.env - bld=task.generator.bld - if not env['PROMPT_LATEX']: - env.append_value('LATEXFLAGS','-interaction=batchmode') - env.append_value('PDFLATEXFLAGS','-interaction=batchmode') - fun=latex_fun - if command=='PDFLATEX': - fun=pdflatex_fun - node=task.inputs[0] - srcfile=node.abspath() - sr2=node.parent.get_bld().abspath()+os.pathsep+node.parent.get_src().abspath()+os.pathsep - aux_node=node.change_ext('.aux') - idx_node=node.change_ext('.idx') - nm=aux_node.name - docuname=nm[:len(nm)-4] - task.cwd=task.inputs[0].parent.get_bld().abspath() - warn('first pass on %s'%command) - task.env.env={'TEXINPUTS':sr2} - task.env.SRCFILE=srcfile - ret=fun(task) - if ret: - return ret - try: - ct=Utils.readf(aux_node.abspath()) - except(OSError,IOError): - error('error bibtex scan') - else: - fo=g_bibtex_re.findall(ct) - if fo: - warn('calling bibtex') - task.env.env={'BIBINPUTS':sr2,'BSTINPUTS':sr2} - task.env.SRCFILE=docuname - ret=bibtex_fun(task) - if ret: - error('error when calling bibtex %s'%docuname) - return ret - try: - idx_path=idx_node.abspath() - os.stat(idx_path) - except OSError: - error('error file.idx scan') - else: - warn('calling makeindex') - task.env.SRCFILE=idx_node.name - task.env.env={} - ret=makeindex_fun(task) - if ret: - error('error when calling makeindex %s'%idx_path) - return ret - hash='' - i=0 - while i<10: - i+=1 - prev_hash=hash - try: - hash=Utils.h_file(aux_node.abspath()) - except KeyError: - error('could not read aux.h -> %s'%aux_node.abspath()) - pass - if hash and hash==prev_hash: - break - warn('calling %s'%command) - task.env.env={'TEXINPUTS':sr2+os.pathsep} - task.env.SRCFILE=srcfile - ret=fun(task) - if ret: - error('error when calling %s %s'%(command,latex_compile_cmd)) - return ret - return None -latex_vardeps=['LATEX','LATEXFLAGS'] -def latex_build(task): - return tex_build(task,'LATEX') -pdflatex_vardeps=['PDFLATEX','PDFLATEXFLAGS'] -def pdflatex_build(task): - return tex_build(task,'PDFLATEX') -def apply_tex(self): - if not getattr(self,'type',None)in['latex','pdflatex']: - self.type='pdflatex' - tree=self.bld - outs=Utils.to_list(getattr(self,'outs',[])) - self.env['PROMPT_LATEX']=getattr(self,'prompt',1) - deps_lst=[] - if getattr(self,'deps',None): - deps=self.to_list(self.deps) - for filename in deps: - n=self.path.find_resource(filename) - if not n in deps_lst:deps_lst.append(n) - for node in self.to_nodes(self.source): - if self.type=='latex': - task=self.create_task('latex',node,node.change_ext('.dvi')) - elif self.type=='pdflatex': - task=self.create_task('pdflatex',node,node.change_ext('.pdf')) - task.env=self.env - if deps_lst: - try: - lst=tree.node_deps[task.uid()] - for n in deps_lst: - if not n in lst: - lst.append(n) - except KeyError: - tree.node_deps[task.uid()]=deps_lst - if self.type=='latex': - if'ps'in outs: - tsk=self.create_task('dvips',task.outputs,node.change_ext('.ps')) - tsk.env.env={'TEXINPUTS':node.parent.abspath()+os.pathsep+self.path.abspath()+os.pathsep+self.path.get_bld().abspath()} - if'pdf'in outs: - tsk=self.create_task('dvipdf',task.outputs,node.change_ext('.pdf')) - tsk.env.env={'TEXINPUTS':node.parent.abspath()+os.pathsep+self.path.abspath()+os.pathsep+self.path.get_bld().abspath()} - elif self.type=='pdflatex': - if'ps'in outs: - self.create_task('pdf2ps',task.outputs,node.change_ext('.ps')) - self.source=[] -def configure(self): - v=self.env - for p in'tex latex pdflatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps'.split(): - try: - self.find_program(p,var=p.upper()) - except self.errors.ConfigurationError: - pass - v['DVIPSFLAGS']='-Ppdf' -b=Task.task_factory -b('dvips','${DVIPS} ${DVIPSFLAGS} ${SRC} -o ${TGT}',color='BLUE',after=["latex","pdflatex","tex","bibtex"],shell=False) -b('dvipdf','${DVIPDF} ${DVIPDFFLAGS} ${SRC} ${TGT}',color='BLUE',after=["latex","pdflatex","tex","bibtex"],shell=False) -b('pdf2ps','${PDF2PS} ${PDF2PSFLAGS} ${SRC} ${TGT}',color='BLUE',after=["dvipdf","pdflatex"],shell=False) -b('latex',latex_build,vars=latex_vardeps,scan=scan) -b('pdflatex',pdflatex_build,vars=pdflatex_vardeps,scan=scan) - -feature('tex')(apply_tex) -before('process_source')(apply_tex) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/vala.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/vala.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/vala.py +++ /dev/null @@ -1,207 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os.path,shutil,re -from waflib import Context,Task,Runner,Utils,Logs,Build,Node,Options,Errors -from waflib.TaskGen import extension,after,before -from waflib.Configure import conf -class valac_task(Task.Task): - vars=["VALAC","VALAC_VERSION","VALAFLAGS"] - ext_out=['.h'] - def run(self): - env=self.env - cmd=[env['VALAC'],'-C','--quiet'] - cmd.extend(Utils.to_list(env['VALAFLAGS'])) - if self.threading: - cmd.append('--thread') - if self.profile: - cmd.append('--profile=%s'%self.profile) - if self.target_glib: - cmd.append('--target-glib=%s'%self.target_glib) - if self.is_lib: - output_dir=self.outputs[0].bld_dir() - cmd.append('--library='+self.target) - for x in self.outputs: - if x.name.endswith('.h'): - cmd.append('--header='+x.name) - if self.gir: - cmd.append('--gir=%s.gir'%self.gir) - for vapi_dir in self.vapi_dirs: - cmd.append('--vapidir=%s'%vapi_dir) - for package in self.packages: - cmd.append('--pkg=%s'%package) - for package in self.packages_private: - cmd.append('--pkg=%s'%package) - for define in self.vala_defines: - cmd.append('--define=%s'%define) - cmd.extend([a.abspath()for a in self.inputs]) - ret=self.exec_command(cmd,cwd=self.outputs[0].parent.abspath()) - if ret: - return ret - for x in self.outputs: - if id(x.parent)!=id(self.outputs[0].parent): - shutil.move(self.outputs[0].parent.abspath()+os.sep+x.name,x.abspath()) - if self.packages and getattr(self,'deps_node',None): - self.deps_node.write('\n'.join(self.packages)) - return ret -def vala_file(self,node): - valatask=getattr(self,"valatask",None) - if not valatask: - def _get_api_version(): - api_version=getattr(Context.g_module,'API_VERSION',None) - if api_version==None: - version=Context.g_module.VERSION.split(".") - if version[0]=="0": - api_version="0."+version[1] - else: - api_version=version[0]+".0" - return api_version - valatask=self.create_task('valac') - self.valatask=valatask - self.includes=Utils.to_list(getattr(self,'includes',[])) - self.uselib=self.to_list(getattr(self,'uselib',[])) - valatask.packages=[] - valatask.packages_private=Utils.to_list(getattr(self,'packages_private',[])) - valatask.vapi_dirs=[] - valatask.target=self.target - valatask.threading=False - valatask.install_path=getattr(self,'install_path','') - valatask.profile=getattr(self,'profile','gobject') - valatask.vala_defines=getattr(self,'vala_defines',[]) - valatask.target_glib=None - valatask.gir=getattr(self,'gir',None) - valatask.gir_path=getattr(self,'gir_path','${DATAROOTDIR}/gir-1.0') - valatask.vapi_path=getattr(self,'vapi_path','${DATAROOTDIR}/vala/vapi') - valatask.pkg_name=getattr(self,'pkg_name',self.env['PACKAGE']) - valatask.header_path=getattr(self,'header_path','${INCLUDEDIR}/%s-%s'%(valatask.pkg_name,_get_api_version())) - valatask.is_lib=False - if not'cprogram'in self.features: - valatask.is_lib=True - packages=Utils.to_list(getattr(self,'packages',[])) - vapi_dirs=Utils.to_list(getattr(self,'vapi_dirs',[])) - includes=[] - if hasattr(self,'use'): - local_packages=Utils.to_list(self.use)[:] - seen=[] - while len(local_packages)>0: - package=local_packages.pop() - if package in seen: - continue - seen.append(package) - try: - package_obj=self.bld.get_tgen_by_name(package) - except Errors.WafError: - continue - package_name=package_obj.target - package_node=package_obj.path - package_dir=package_node.relpath_gen(self.path) - for task in package_obj.tasks: - for output in task.outputs: - if output.name==package_name+".vapi": - valatask.set_run_after(task) - if package_name not in packages: - packages.append(package_name) - if package_dir not in vapi_dirs: - vapi_dirs.append(package_dir) - if package_dir not in includes: - includes.append(package_dir) - if hasattr(package_obj,'use'): - lst=self.to_list(package_obj.use) - lst.reverse() - local_packages=[pkg for pkg in lst if pkg not in seen]+local_packages - valatask.packages=packages - for vapi_dir in vapi_dirs: - try: - valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).abspath()) - valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).get_bld().abspath()) - except AttributeError: - Logs.warn("Unable to locate Vala API directory: '%s'"%vapi_dir) - self.includes.append(self.bld.srcnode.abspath()) - self.includes.append(self.bld.bldnode.abspath()) - for include in includes: - try: - self.includes.append(self.path.find_dir(include).abspath()) - self.includes.append(self.path.find_dir(include).get_bld().abspath()) - except AttributeError: - Logs.warn("Unable to locate include directory: '%s'"%include) - if valatask.profile=='gobject': - if hasattr(self,'target_glib'): - Logs.warn('target_glib on vala tasks is not supported --vala-target-glib=MAJOR.MINOR from the vala tool options') - if getattr(Options.options,'vala_target_glib',None): - valatask.target_glib=Options.options.vala_target_glib - if not'GOBJECT'in self.uselib: - self.uselib.append('GOBJECT') - if hasattr(self,'threading'): - if valatask.profile=='gobject': - valatask.threading=self.threading - if not'GTHREAD'in self.uselib: - self.uselib.append('GTHREAD') - else: - Logs.warn("Profile %s does not have threading support"%valatask.profile) - if valatask.is_lib: - valatask.outputs.append(self.path.find_or_declare('%s.h'%self.target)) - valatask.outputs.append(self.path.find_or_declare('%s.vapi'%self.target)) - if valatask.gir: - valatask.outputs.append(self.path.find_or_declare('%s.gir'%self.gir)) - if valatask.packages: - d=self.path.find_or_declare('%s.deps'%self.target) - valatask.outputs.append(d) - valatask.deps_node=d - valatask.inputs.append(node) - c_node=node.change_ext('.c') - valatask.outputs.append(c_node) - self.source.append(c_node) - if valatask.is_lib: - headers_list=[o for o in valatask.outputs if o.suffix()==".h"] - self.install_vheader=self.bld.install_files(valatask.header_path,headers_list,self.env) - vapi_list=[o for o in valatask.outputs if(o.suffix()in(".vapi",".deps"))] - self.install_vapi=self.bld.install_files(valatask.vapi_path,vapi_list,self.env) - gir_list=[o for o in valatask.outputs if o.suffix()==".gir"] - self.install_gir=self.bld.install_files(valatask.gir_path,gir_list,self.env) -valac_task=Task.update_outputs(valac_task) -def find_valac(self,valac_name,min_version): - valac=self.find_program(valac_name,var='VALAC') - try: - output=self.cmd_and_log(valac+' --version') - except Exception: - valac_version=None - else: - ver=re.search(r'\d+.\d+.\d+',output).group(0).split('.') - valac_version=tuple([int(x)for x in ver]) - self.msg('Checking for %s version >= %r'%(valac_name,min_version),valac_version,valac_version and valac_version>=min_version) - if valac and valac_version= %r"%(valac_name,valac_version,min_version)) - self.env['VALAC_VERSION']=valac_version - return valac -def check_vala(self,min_version=(0,8,0),branch=None): - if not branch: - branch=min_version[:2] - try: - find_valac(self,'valac-%d.%d'%(branch[0],branch[1]),min_version) - except self.errors.ConfigurationError: - find_valac(self,'valac',min_version) -def check_vala_deps(self): - if not self.env['HAVE_GOBJECT']: - pkg_args={'package':'gobject-2.0','uselib_store':'GOBJECT','args':'--cflags --libs'} - if getattr(Options.options,'vala_target_glib',None): - pkg_args['atleast_version']=Options.options.vala_target_glib - self.check_cfg(**pkg_args) - if not self.env['HAVE_GTHREAD']: - pkg_args={'package':'gthread-2.0','uselib_store':'GTHREAD','args':'--cflags --libs'} - if getattr(Options.options,'vala_target_glib',None): - pkg_args['atleast_version']=Options.options.vala_target_glib - self.check_cfg(**pkg_args) -def configure(self): - self.load('gnu_dirs') - self.check_vala_deps() - self.check_vala() -def options(opt): - opt.load('gnu_dirs') - valaopts=opt.add_option_group('Vala Compiler Options') - valaopts.add_option('--vala-target-glib',default=None,dest='vala_target_glib',metavar='MAJOR.MINOR',help='Target version of glib for Vala GObject code generation') - -extension('.vala','.gs')(vala_file) -conf(find_valac) -conf(check_vala) -conf(check_vala_deps) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/waf_unit_test.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/waf_unit_test.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/waf_unit_test.py +++ /dev/null @@ -1,81 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys -from waflib.TaskGen import feature,after -from waflib import Utils,Task,Logs,Options -testlock=Utils.threading.Lock() -def make_test(self): - if getattr(self,'link_task',None): - self.default_install_path=None - self.create_task('utest',self.link_task.outputs) -class utest(Task.Task): - color='PINK' - ext_in=['.bin'] - vars=[] - def runnable_status(self): - ret=super(utest,self).runnable_status() - if ret==Task.SKIP_ME: - if getattr(Options.options,'all_tests',False): - return Task.RUN_ME - return ret - def run(self): - status=0 - filename=self.inputs[0].abspath() - self.ut_exec=getattr(self,'ut_exec',[filename]) - if getattr(self.generator,'ut_fun',None): - self.generator.ut_fun(self) - try: - fu=getattr(self.generator.bld,'all_test_paths') - except AttributeError: - fu=os.environ.copy() - self.generator.bld.all_test_paths=fu - lst=[] - for g in self.generator.bld.groups: - for tg in g: - if getattr(tg,'link_task',None): - lst.append(tg.link_task.outputs[0].parent.abspath()) - def add_path(dct,path,var): - dct[var]=os.pathsep.join(Utils.to_list(path)+[os.environ.get(var,'')]) - if sys.platform=='win32': - add_path(fu,lst,'PATH') - elif sys.platform=='darwin': - add_path(fu,lst,'DYLD_LIBRARY_PATH') - add_path(fu,lst,'LD_LIBRARY_PATH') - else: - add_path(fu,lst,'LD_LIBRARY_PATH') - cwd=getattr(self.generator,'ut_cwd','')or self.inputs[0].parent.abspath() - proc=Utils.subprocess.Popen(self.ut_exec,cwd=cwd,env=fu,stderr=Utils.subprocess.PIPE,stdout=Utils.subprocess.PIPE) - (stdout,stderr)=proc.communicate() - tup=(filename,proc.returncode,stdout,stderr) - self.generator.utest_result=tup - testlock.acquire() - try: - bld=self.generator.bld - Logs.debug("ut: %r",tup) - try: - bld.utest_results.append(tup) - except AttributeError: - bld.utest_results=[tup] - finally: - testlock.release() -def summary(bld): - lst=getattr(bld,'utest_results',[]) - if lst: - Logs.pprint('CYAN','execution summary') - total=len(lst) - tfail=len([x for x in lst if x[1]]) - Logs.pprint('CYAN',' tests that pass %d/%d'%(total-tfail,total)) - for(f,code,out,err)in lst: - if not code: - Logs.pprint('CYAN',' %s'%f) - Logs.pprint('CYAN',' tests that fail %d/%d'%(tfail,total)) - for(f,code,out,err)in lst: - if code: - Logs.pprint('CYAN',' %s'%f) -def options(opt): - opt.add_option('--alltests',action='store_true',default=False,help='Exec all unit tests',dest='all_tests') - -feature('test')(make_test) -after('apply_link')(make_test) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/winres.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/winres.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/winres.py +++ /dev/null @@ -1,32 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,re -from waflib import TaskGen,Task -from waflib.TaskGen import extension -def rc_file(self,node): - obj_ext='.rc.o' - if self.env['WINRC_TGT_F']=='/fo': - obj_ext='.res' - rctask=self.create_task('winrc',node,node.change_ext(obj_ext)) - self.compiled_tasks.append(rctask) -class winrc(Task.Task): - run_str='${WINRC} ${WINRCFLAGS} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${WINRC_TGT_F} ${TGT} ${WINRC_SRC_F} ${SRC}' - color='BLUE' -def configure(conf): - v=conf.env - v['WINRC_TGT_F']='-o' - v['WINRC_SRC_F']='-i' - if not conf.env.WINRC: - if v.CC_NAME=='msvc': - winrc=conf.find_program('RC',var='WINRC',path_list=v['PATH']) - v['WINRC_TGT_F']='/fo' - v['WINRC_SRC_F']='' - else: - winrc=conf.find_program('windres',var='WINRC',path_list=v['PATH']) - if not conf.env.WINRC: - conf.fatal('winrc was not found!') - v['WINRCFLAGS']=[] - -extension('.rc')(rc_file) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/xlc.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/xlc.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/xlc.py +++ /dev/null @@ -1,47 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys -from waflib.Tools import ccroot,ar -from waflib.Configure import conf -def find_xlc(conf): - cc=conf.find_program(['xlc_r','xlc'],var='CC') - cc=conf.cmd_to_list(cc) - conf.env.CC_NAME='xlc' - conf.env.CC=cc -def xlc_common_flags(conf): - v=conf.env - v['CC_SRC_F']='' - v['CC_TGT_F']=['-c','-o',''] - if not v['LINK_CC']:v['LINK_CC']=v['CC'] - v['CCLNK_SRC_F']='' - v['CCLNK_TGT_F']=['-o',''] - v['CPPPATH_ST']='-I%s' - v['DEFINES_ST']='-D%s' - v['LIB_ST']='-l%s' - v['LIBPATH_ST']='-L%s' - v['STLIB_ST']='-l%s' - v['STLIBPATH_ST']='-L%s' - v['RPATH_ST']='-Wl,-rpath,%s' - v['SONAME_ST']='' - v['SHLIB_MARKER']='' - v['STLIB_MARKER']='' - v['LINKFLAGS_cprogram']=['-Wl,-brtl'] - v['cprogram_PATTERN']='%s' - v['CFLAGS_cshlib']=['-fPIC'] - v['LINKFLAGS_cshlib']=['-G','-Wl,-brtl,-bexpfull'] - v['cshlib_PATTERN']='lib%s.so' - v['LINKFLAGS_cstlib']='' - v['cstlib_PATTERN']='lib%s.a' -configure=''' -find_xlc -find_ar -xlc_common_flags -cc_load_tools -cc_add_flags -link_add_flags -''' - -conf(find_xlc) -conf(xlc_common_flags) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/xlcxx.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/xlcxx.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Tools/xlcxx.py +++ /dev/null @@ -1,47 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys -from waflib.Tools import ccroot,ar -from waflib.Configure import conf -def find_xlcxx(conf): - cxx=conf.find_program(['xlc++_r','xlc++'],var='CXX') - cxx=conf.cmd_to_list(cxx) - conf.env.CXX_NAME='xlc++' - conf.env.CXX=cxx -def xlcxx_common_flags(conf): - v=conf.env - v['CXX_SRC_F']='' - v['CXX_TGT_F']=['-c','-o',''] - if not v['LINK_CXX']:v['LINK_CXX']=v['CXX'] - v['CXXLNK_SRC_F']='' - v['CXXLNK_TGT_F']=['-o',''] - v['CPPPATH_ST']='-I%s' - v['DEFINES_ST']='-D%s' - v['LIB_ST']='-l%s' - v['LIBPATH_ST']='-L%s' - v['STLIB_ST']='-l%s' - v['STLIBPATH_ST']='-L%s' - v['RPATH_ST']='-Wl,-rpath,%s' - v['SONAME_ST']='' - v['SHLIB_MARKER']='' - v['STLIB_MARKER']='' - v['LINKFLAGS_cxxprogram']=['-Wl,-brtl'] - v['cxxprogram_PATTERN']='%s' - v['CXXFLAGS_cxxshlib']=['-fPIC'] - v['LINKFLAGS_cxxshlib']=['-G','-Wl,-brtl,-bexpfull'] - v['cxxshlib_PATTERN']='lib%s.so' - v['LINKFLAGS_cxxstlib']='' - v['cxxstlib_PATTERN']='lib%s.a' -configure=''' -find_xlcxx -find_ar -xlcxx_common_flags -cxx_load_tools -cxx_add_flags -link_add_flags -''' - -conf(find_xlcxx) -conf(xlcxx_common_flags) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Utils.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Utils.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/Utils.py +++ /dev/null @@ -1,299 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os,sys,errno,traceback,inspect,re,shutil,datetime,gc -try: - import subprocess -except: - try: - import waflib.extras.subprocess as subprocess - except: - print("the subprocess module is missing, try to add it to the folder waflib/extras (python 2.3?)") -try: - from collections import deque -except ImportError: - class deque(list): - def popleft(self): - return self.pop(0) -from waflib import Errors -try: - from collections import UserDict -except: - from UserDict import UserDict -try: - from hashlib import md5 -except: - try: - from md5 import md5 - except: - pass -try: - import threading -except: - class threading(object): - pass - class Lock(object): - def acquire(self): - pass - def release(self): - pass - threading.Lock=threading.Thread=Lock -else: - run_old=threading.Thread.run - def run(*args,**kwargs): - try: - run_old(*args,**kwargs) - except(KeyboardInterrupt,SystemExit): - raise - except: - sys.excepthook(*sys.exc_info()) - threading.Thread.run=run -SIG_NIL='iluvcuteoverload' -O644=420 -O755=493 -try: - from collections import defaultdict -except ImportError: - class defaultdict(dict): - def __init__(self,default_factory): - super(defaultdict,self).__init__() - self.default_factory=default_factory - def __getitem__(self,key): - try: - return super(defaultdict,self).__getitem__(key) - except KeyError: - value=self.default_factory() - self[key]=value - return value -is_win32=sys.platform=='win32' -indicator=is_win32 and'\x1b[A\x1b[K%s%s%s\r'or'\x1b[K%s%s%s\r' -def readf(fname,m='r'): - f=open(fname,m) - try: - txt=f.read() - finally: - f.close() - return txt -def h_file(filename): - f=open(filename,'rb') - m=md5() - while(filename): - filename=f.read(100000) - m.update(filename) - f.close() - return m.digest() -try: - x=''.encode('hex') -except: - import binascii - def to_hex(s): - ret=binascii.hexlify(s) - if not isinstance(ret,str): - ret=ret - return ret -else: - def to_hex(s): - return s.encode('hex') -listdir=os.listdir -if is_win32: - def listdir_win32(s): - if not s: - return[] - if re.match('^[A-Za-z]:$',s): - s+=os.sep - if not os.path.isdir(s): - e=OSError() - e.errno=errno.ENOENT - raise e - return os.listdir(s) - listdir=listdir_win32 -def num2ver(ver): - if isinstance(ver,str): - ver=tuple(ver.split('.')) - if isinstance(ver,tuple): - ret=0 - for i in range(4): - if i>2) - def set_color(self,param): - cols=param.split(';') - sbinfo=CONSOLE_SCREEN_BUFFER_INFO() - windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole,byref(sbinfo)) - attr=sbinfo.Attributes - neg=False - for c in cols: - c=to_int(c,0) - if c in range(30,38): - attr=(attr&0xfff0)|self.rgb2bgr(c-30) - elif c in range(40,48): - attr=(attr&0xff0f)|(self.rgb2bgr(c-40)<<4) - elif c==0: - attr=self.orig_sbinfo.Attributes - elif c==1: - attr|=0x08 - elif c==4: - attr|=0x80 - elif c==7: - attr=(attr&0xff88)|((attr&0x70)>>4)|((attr&0x07)<<4) - windll.kernel32.SetConsoleTextAttribute(self.hconsole,attr) - def show_cursor(self,param): - csinfo.bVisible=1 - windll.kernel32.SetConsoleCursorInfo(self.hconsole,byref(csinfo)) - def hide_cursor(self,param): - csinfo.bVisible=0 - windll.kernel32.SetConsoleCursorInfo(self.hconsole,byref(csinfo)) - ansi_command_table={'A':move_up,'B':move_down,'C':move_right,'D':move_left,'E':next_line,'F':prev_line,'G':set_column,'H':set_cursor,'f':set_cursor,'J':clear_screen,'K':clear_line,'h':show_cursor,'l':hide_cursor,'m':set_color,'s':push_cursor,'u':pop_cursor,} - ansi_tokens=re.compile('(?:\x1b\[([0-9?;]*)([a-zA-Z])|([^\x1b]+))') - def write(self,text): - try: - wlock.acquire() - for param,cmd,txt in self.ansi_tokens.findall(text): - if cmd: - cmd_func=self.ansi_command_table.get(cmd) - if cmd_func: - cmd_func(self,param) - else: - self.writeconsole(txt) - finally: - wlock.release() - def writeconsole(self,txt): - chars_written=c_int() - writeconsole=windll.kernel32.WriteConsoleA - if isinstance(txt,_type): - writeconsole=windll.kernel32.WriteConsoleW - TINY_STEP=3000 - for x in range(0,len(txt),TINY_STEP): - tiny=txt[x:x+TINY_STEP] - writeconsole(self.hconsole,tiny,len(tiny),byref(chars_written),None) - def flush(self): - pass - def isatty(self): - return True - sys.stderr=sys.stdout=AnsiTerm() - os.environ['TERM']='vt100' diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/extras/__init__.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/extras/__init__.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/extras/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/extras/compat15.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/extras/compat15.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/extras/compat15.py +++ /dev/null @@ -1,223 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import sys -if sys.hexversion < 0x020400f0: from sets import Set as set -import sys -from waflib import ConfigSet,Logs,Options,Scripting,Task,Build,Configure,Node,Runner,TaskGen,Utils,Errors,Context -sys.modules['Environment']=ConfigSet -ConfigSet.Environment=ConfigSet.ConfigSet -sys.modules['Logs']=Logs -sys.modules['Options']=Options -sys.modules['Scripting']=Scripting -sys.modules['Task']=Task -sys.modules['Build']=Build -sys.modules['Configure']=Configure -sys.modules['Node']=Node -sys.modules['Runner']=Runner -sys.modules['TaskGen']=TaskGen -sys.modules['Utils']=Utils -from waflib.Tools import c_preproc -sys.modules['preproc']=c_preproc -from waflib.Tools import c_config -sys.modules['config_c']=c_config -ConfigSet.ConfigSet.copy=ConfigSet.ConfigSet.derive -ConfigSet.ConfigSet.set_variant=Utils.nada -Build.BuildContext.add_subdirs=Build.BuildContext.recurse -Build.BuildContext.new_task_gen=Build.BuildContext.__call__ -Build.BuildContext.is_install=0 -Node.Node.relpath_gen=Node.Node.path_from -def name_to_obj(self,s,env=None): - Logs.warn('compat: change "name_to_obj(name, env)" by "get_tgen_by_name(name)"') - return self.get_tgen_by_name(s) -Build.BuildContext.name_to_obj=name_to_obj -def env_of_name(self,name): - try: - return self.all_envs[name] - except KeyError: - Logs.error('no such environment: '+name) - return None -Build.BuildContext.env_of_name=env_of_name -def set_env_name(self,name,env): - self.all_envs[name]=env - return env -Configure.ConfigurationContext.set_env_name=set_env_name -def retrieve(self,name,fromenv=None): - try: - env=self.all_envs[name] - except KeyError: - env=ConfigSet.ConfigSet() - self.prepare_env(env) - self.all_envs[name]=env - else: - if fromenv:Logs.warn("The environment %s may have been configured already"%name) - return env -Configure.ConfigurationContext.retrieve=retrieve -Configure.ConfigurationContext.sub_config=Configure.ConfigurationContext.recurse -Configure.ConfigurationContext.check_tool=Configure.ConfigurationContext.load -Configure.conftest=Configure.conf -Configure.ConfigurationError=Errors.ConfigurationError -Options.OptionsContext.sub_options=Options.OptionsContext.recurse -Options.OptionsContext.tool_options=Context.Context.load -Options.Handler=Options.OptionsContext -Task.simple_task_type=Task.task_type_from_func=Task.task_factory -Task.TaskBase.classes=Task.classes -def setitem(self,key,value): - if key.startswith('CCFLAGS'): - key=key[1:] - self.table[key]=value -ConfigSet.ConfigSet.__setitem__=setitem -def old_importpaths(self): - if getattr(self,'importpaths',[]): - self.includes=self.importpaths -from waflib import Context -eld=Context.load_tool -def load_tool(*k,**kw): - ret=eld(*k,**kw) - if'set_options'in ret.__dict__: - Logs.warn('compat: rename "set_options" to options') - ret.options=ret.set_options - if'detect'in ret.__dict__: - Logs.warn('compat: rename "detect" to "configure"') - ret.configure=ret.detect - return ret -Context.load_tool=load_tool -rev=Context.load_module -def load_module(path): - ret=rev(path) - if'set_options'in ret.__dict__: - Logs.warn('compat: rename "set_options" to "options" (%r)'%path) - ret.options=ret.set_options - if'srcdir'in ret.__dict__: - Logs.warn('compat: rename "srcdir" to "top" (%r)'%path) - ret.top=ret.srcdir - if'blddir'in ret.__dict__: - Logs.warn('compat: rename "blddir" to "out" (%r)'%path) - ret.out=ret.blddir - return ret -Context.load_module=load_module -old_post=TaskGen.task_gen.post -def post(self): - self.features=self.to_list(self.features) - if'cc'in self.features: - Logs.warn('compat: the feature cc does not exist anymore (use "c")') - self.features.remove('cc') - self.features.append('c') - if'cstaticlib'in self.features: - Logs.warn('compat: the feature cstaticlib does not exist anymore (use "cstlib" or "cxxstlib")') - self.features.remove('cstaticlib') - self.features.append(('cxx'in self.features)and'cxxstlib'or'cstlib') - if getattr(self,'ccflags',None): - Logs.warn('compat: "ccflags" was renamed to "cflags"') - self.cflags=self.ccflags - return old_post(self) -TaskGen.task_gen.post=post -def waf_version(*k,**kw): - Logs.warn('wrong version (waf_version was removed in waf 1.6)') -Utils.waf_version=waf_version -import os -def apply_uselib_local(self): - env=self.env - from waflib.Tools.ccroot import stlink_task - self.uselib=self.to_list(getattr(self,'uselib',[])) - self.includes=self.to_list(getattr(self,'includes',[])) - names=self.to_list(getattr(self,'uselib_local',[])) - get=self.bld.get_tgen_by_name - seen=set([]) - tmp=Utils.deque(names) - if tmp: - Logs.warn('"uselib_local" is deprecated, replace by "use"') - while tmp: - lib_name=tmp.popleft() - if lib_name in seen: - continue - y=get(lib_name) - y.post() - seen.add(lib_name) - if getattr(y,'uselib_local',None): - for x in self.to_list(getattr(y,'uselib_local',[])): - obj=get(x) - obj.post() - if getattr(obj,'link_task',None): - if not isinstance(obj.link_task,stlink_task): - tmp.append(x) - if getattr(y,'link_task',None): - link_name=y.target[y.target.rfind(os.sep)+1:] - if isinstance(y.link_task,stlink_task): - env.append_value('STLIB',[link_name]) - else: - env.append_value('LIB',[link_name]) - self.link_task.set_run_after(y.link_task) - self.link_task.dep_nodes+=y.link_task.outputs - tmp_path=y.link_task.outputs[0].parent.bldpath() - if not tmp_path in env['LIBPATH']: - env.prepend_value('LIBPATH',[tmp_path]) - for v in self.to_list(getattr(y,'uselib',[])): - if not env['STLIB_'+v]: - if not v in self.uselib: - self.uselib.insert(0,v) - if getattr(y,'export_includes',None): - self.includes.extend(y.to_incnodes(y.export_includes)) -def apply_objdeps(self): - names=getattr(self,'add_objects',[]) - if not names: - return - names=self.to_list(names) - get=self.bld.get_tgen_by_name - seen=[] - while names: - x=names[0] - if x in seen: - names=names[1:] - continue - y=get(x) - if getattr(y,'add_objects',None): - added=0 - lst=y.to_list(y.add_objects) - lst.reverse() - for u in lst: - if u in seen:continue - added=1 - names=[u]+names - if added:continue - y.post() - seen.append(x) - for t in getattr(y,'compiled_tasks',[]): - self.link_task.inputs.extend(t.outputs) -def process_obj_files(self): - if not hasattr(self,'obj_files'): - return - for x in self.obj_files: - node=self.path.find_resource(x) - self.link_task.inputs.append(node) -def add_obj_file(self,file): - if not hasattr(self,'obj_files'):self.obj_files=[] - if not'process_obj_files'in self.meths:self.meths.append('process_obj_files') - self.obj_files.append(file) -old_define=Configure.ConfigurationContext.__dict__['define'] -def define(self,key,val,quote=True): - old_define(self,key,val,quote) - if key.startswith('HAVE_'): - self.env[key]=1 -old_undefine=Configure.ConfigurationContext.__dict__['undefine'] -def undefine(self,key): - old_undefine(self,key) - if key.startswith('HAVE_'): - self.env[key]=0 -def set_incdirs(self,val): - Logs.warn('compat: change "export_incdirs" by "export_includes"') - self.export_includes=val -TaskGen.task_gen.export_incdirs=property(None,set_incdirs) - -TaskGen.feature('d')(old_importpaths) -TaskGen.before('apply_incpaths')(old_importpaths) -TaskGen.feature('c','cxx','d')(apply_uselib_local) -TaskGen.before('apply_incpaths','propagate_uselib_vars')(apply_uselib_local) -TaskGen.after('apply_link','process_source')(apply_uselib_local) -TaskGen.feature('cprogram','cxxprogram','cstlib','cxxstlib','cshlib','cxxshlib','dprogram','dstlib','dshlib')(apply_objdeps) -TaskGen.after('apply_link')(apply_objdeps) -TaskGen.after('apply_link')(process_obj_files) -TaskGen.taskgen_method(add_obj_file) -Configure.conf(define) -Configure.conf(undefine) \ No newline at end of file diff --git a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/fixpy2.py b/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/fixpy2.py deleted file mode 100644 --- a/lib/waf/build/.waf-1.6.0-de8365f31a356c903011491e9c4c7cdb/waflib/fixpy2.py +++ /dev/null @@ -1,50 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# WARNING! All changes made to this file will be lost! - -import os -all_modifs={} -def fixdir(dir): - global all_modifs - for k in all_modifs: - for v in all_modifs[k]: - modif(os.path.join(dir,'waflib'),k,v) -def modif(dir,name,fun): - if name=='*': - lst=[] - for y in'. Tools extras'.split(): - for x in os.listdir(os.path.join(dir,y)): - if x.endswith('.py'): - lst.append(y+os.sep+x) - for x in lst: - modif(dir,x,fun) - return - filename=os.path.join(dir,name) - f=open(filename,'r') - txt=f.read() - f.close() - txt=fun(txt) - f=open(filename,'w') - f.write(txt) - f.close() -def subst(*k): - def do_subst(fun): - global all_modifs - for x in k: - try: - all_modifs[x].append(fun) - except KeyError: - all_modifs[x]=[fun] - return fun - return do_subst -def r1(code): - code=code.replace(',e:',',e:') - code=code.replace("",'') - code=code.replace('','') - return code -def r4(code): - code=code.replace('next(self.biter)','self.biter.next()') - return code - -subst('*')(r1) -subst('Runner.py')(r4) \ No newline at end of file diff --git a/lib/waf/build/Makefile b/lib/waf/build/Makefile deleted file mode 100644 --- a/lib/waf/build/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -subdirs = \ -lib_0\ -lib_1\ -lib_2\ -lib_3\ -lib_4\ -lib_5\ -lib_6\ -lib_7\ -lib_8\ -lib_9\ -lib_10\ -lib_11\ -lib_12\ - - -all: $(subdirs) - @for i in $(subdirs); do $(MAKE) -C $$i all; done - -clean: - @for i in $(subdirs); do (cd $$i; $(MAKE) clean); done - -depend: - @for i in $(subdirs); do (cd $$i; $(MAKE) depend); done diff --git a/lib/waf/build/Makefile.am b/lib/waf/build/Makefile.am deleted file mode 100644 --- a/lib/waf/build/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -AM_CPPFLAGS = -I$(srcdir) -lib_LTLIBRARIES = -include lib_0/Makefile.am -include lib_1/Makefile.am -include lib_2/Makefile.am -include lib_3/Makefile.am -include lib_4/Makefile.am -include lib_5/Makefile.am -include lib_6/Makefile.am -include lib_7/Makefile.am -include lib_8/Makefile.am -include lib_9/Makefile.am -include lib_10/Makefile.am -include lib_11/Makefile.am -include lib_12/Makefile.am diff --git a/lib/waf/build/SConstruct b/lib/waf/build/SConstruct deleted file mode 100644 --- a/lib/waf/build/SConstruct +++ /dev/null @@ -1,17 +0,0 @@ -env = Environment(CPPFLAGS=['-Wall'], CPPDEFINES=['LINUX'], CPPPATH=[Dir('#')]) -env.Decider('timestamp-newer') -env.SetOption('implicit_cache', True) -env.SourceCode('.', None) -env.SConscript("lib_0/SConscript", exports=['env']) -env.SConscript("lib_1/SConscript", exports=['env']) -env.SConscript("lib_2/SConscript", exports=['env']) -env.SConscript("lib_3/SConscript", exports=['env']) -env.SConscript("lib_4/SConscript", exports=['env']) -env.SConscript("lib_5/SConscript", exports=['env']) -env.SConscript("lib_6/SConscript", exports=['env']) -env.SConscript("lib_7/SConscript", exports=['env']) -env.SConscript("lib_8/SConscript", exports=['env']) -env.SConscript("lib_9/SConscript", exports=['env']) -env.SConscript("lib_10/SConscript", exports=['env']) -env.SConscript("lib_11/SConscript", exports=['env']) -env.SConscript("lib_12/SConscript", exports=['env']) diff --git a/lib/waf/build/configure.ac b/lib/waf/build/configure.ac deleted file mode 100644 --- a/lib/waf/build/configure.ac +++ /dev/null @@ -1,7 +0,0 @@ -AC_INIT([bench], [1.0.0]) -AC_CONFIG_AUX_DIR([autotools-aux]) -AM_INIT_AUTOMAKE([subdir-objects nostdinc no-define tar-pax dist-bzip2]) -AM_PROG_LIBTOOL -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT diff --git a/lib/waf/build/lib_0/Makefile b/lib/waf/build/lib_0/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_0/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_0.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_0/Makefile.am b/lib/waf/build/lib_0/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_0/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib0.la -lib0_la_SOURCES = lib_0/class_0.cpp lib_0/class_1.cpp lib_0/class_2.cpp lib_0/class_3.cpp lib_0/class_4.cpp lib_0/class_5.cpp lib_0/class_6.cpp lib_0/class_7.cpp lib_0/class_8.cpp lib_0/class_9.cpp lib_0/class_10.cpp lib_0/class_11.cpp lib_0/class_12.cpp lib_0/class_13.cpp lib_0/class_14.cpp lib_0/class_15.cpp lib_0/class_16.cpp lib_0/class_17.cpp lib_0/class_18.cpp lib_0/class_19.cpp lib_0/class_20.cpp lib_0/class_21.cpp lib_0/class_22.cpp lib_0/class_23.cpp lib_0/class_24.cpp lib_0/class_25.cpp lib_0/class_26.cpp lib_0/class_27.cpp lib_0/class_28.cpp lib_0/class_29.cpp lib_0/class_30.cpp lib_0/class_31.cpp lib_0/class_32.cpp lib_0/class_33.cpp lib_0/class_34.cpp lib_0/class_35.cpp lib_0/class_36.cpp lib_0/class_37.cpp lib_0/class_38.cpp lib_0/class_39.cpp lib_0/class_40.cpp lib_0/class_41.cpp lib_0/class_42.cpp lib_0/class_43.cpp lib_0/class_44.cpp lib_0/class_45.cpp lib_0/class_46.cpp lib_0/class_47.cpp lib_0/class_48.cpp lib_0/class_49.cpp lib_0/class_50.cpp lib_0/class_51.cpp lib_0/class_52.cpp lib_0/class_53.cpp lib_0/class_54.cpp lib_0/class_55.cpp lib_0/class_56.cpp lib_0/class_57.cpp lib_0/class_58.cpp lib_0/class_59.cpp lib_0/class_60.cpp lib_0/class_61.cpp lib_0/class_62.cpp lib_0/class_63.cpp lib_0/class_64.cpp lib_0/class_65.cpp lib_0/class_66.cpp lib_0/class_67.cpp lib_0/class_68.cpp lib_0/class_69.cpp lib_0/class_70.cpp lib_0/class_71.cpp lib_0/class_72.cpp lib_0/class_73.cpp lib_0/class_74.cpp lib_0/class_75.cpp lib_0/class_76.cpp lib_0/class_77.cpp lib_0/class_78.cpp lib_0/class_79.cpp lib_0/class_80.cpp lib_0/class_81.cpp lib_0/class_82.cpp lib_0/class_83.cpp lib_0/class_84.cpp lib_0/class_85.cpp lib_0/class_86.cpp lib_0/class_87.cpp lib_0/class_88.cpp lib_0/class_89.cpp lib_0/class_90.cpp lib_0/class_91.cpp lib_0/class_92.cpp lib_0/class_93.cpp lib_0/class_94.cpp lib_0/class_95.cpp lib_0/class_96.cpp lib_0/class_97.cpp lib_0/class_98.cpp lib_0/class_99.cpp diff --git a/lib/waf/build/lib_0/SConscript b/lib/waf/build/lib_0/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_0/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_0", list) - diff --git a/lib/waf/build/lib_0/class_0.cpp b/lib/waf/build/lib_0/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_0.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_0.h" -#include "class_84.h" -#include "class_75.h" -#include "class_42.h" -#include "class_25.h" -#include "class_51.h" -#include "class_40.h" -#include "class_78.h" -#include "class_30.h" -#include "class_47.h" -#include "class_58.h" -#include "class_90.h" -#include "class_50.h" -#include "class_28.h" -#include "class_61.h" -#include "class_98.h" - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_0/class_0.h b/lib/waf/build/lib_0/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_1.cpp b/lib/waf/build/lib_0/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_1.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_1.h" -#include "class_81.h" -#include "class_90.h" -#include "class_31.h" -#include "class_72.h" -#include "class_89.h" -#include "class_68.h" -#include "class_47.h" -#include "class_10.h" -#include "class_43.h" -#include "class_61.h" -#include "class_91.h" -#include "class_96.h" -#include "class_86.h" -#include "class_26.h" -#include "class_80.h" - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_0/class_1.h b/lib/waf/build/lib_0/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_10.cpp b/lib/waf/build/lib_0/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_10.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_10.h" -#include "class_50.h" -#include "class_31.h" -#include "class_35.h" -#include "class_83.h" -#include "class_25.h" -#include "class_56.h" -#include "class_1.h" -#include "class_74.h" -#include "class_33.h" -#include "class_4.h" -#include "class_28.h" -#include "class_24.h" -#include "class_95.h" -#include "class_94.h" -#include "class_63.h" - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_0/class_10.h b/lib/waf/build/lib_0/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_11.cpp b/lib/waf/build/lib_0/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_11.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_11.h" -#include "class_62.h" -#include "class_71.h" -#include "class_38.h" -#include "class_41.h" -#include "class_65.h" -#include "class_0.h" -#include "class_19.h" -#include "class_33.h" -#include "class_23.h" -#include "class_63.h" -#include "class_37.h" -#include "class_87.h" -#include "class_56.h" -#include "class_40.h" -#include "class_70.h" - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_0/class_11.h b/lib/waf/build/lib_0/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_12.cpp b/lib/waf/build/lib_0/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_12.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_12.h" -#include "class_41.h" -#include "class_66.h" -#include "class_4.h" -#include "class_44.h" -#include "class_25.h" -#include "class_15.h" -#include "class_52.h" -#include "class_48.h" -#include "class_56.h" -#include "class_75.h" -#include "class_88.h" -#include "class_49.h" -#include "class_31.h" -#include "class_46.h" -#include "class_80.h" - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_0/class_12.h b/lib/waf/build/lib_0/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_13.cpp b/lib/waf/build/lib_0/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_13.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_13.h" -#include "class_87.h" -#include "class_81.h" -#include "class_18.h" -#include "class_99.h" -#include "class_63.h" -#include "class_8.h" -#include "class_72.h" -#include "class_98.h" -#include "class_40.h" -#include "class_67.h" -#include "class_31.h" -#include "class_21.h" -#include "class_71.h" -#include "class_0.h" -#include "class_82.h" - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_0/class_13.h b/lib/waf/build/lib_0/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_14.cpp b/lib/waf/build/lib_0/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_14.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_14.h" -#include "class_52.h" -#include "class_9.h" -#include "class_11.h" -#include "class_64.h" -#include "class_87.h" -#include "class_27.h" -#include "class_97.h" -#include "class_10.h" -#include "class_85.h" -#include "class_39.h" -#include "class_8.h" -#include "class_45.h" -#include "class_79.h" -#include "class_86.h" -#include "class_13.h" - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_0/class_14.h b/lib/waf/build/lib_0/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_15.cpp b/lib/waf/build/lib_0/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_15.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_15.h" -#include "class_52.h" -#include "class_65.h" -#include "class_34.h" -#include "class_87.h" -#include "class_27.h" -#include "class_1.h" -#include "class_4.h" -#include "class_68.h" -#include "class_55.h" -#include "class_94.h" -#include "class_93.h" -#include "class_90.h" -#include "class_74.h" -#include "class_70.h" -#include "class_71.h" - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_0/class_15.h b/lib/waf/build/lib_0/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_16.cpp b/lib/waf/build/lib_0/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_16.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_16.h" -#include "class_90.h" -#include "class_64.h" -#include "class_37.h" -#include "class_53.h" -#include "class_20.h" -#include "class_58.h" -#include "class_0.h" -#include "class_15.h" -#include "class_33.h" -#include "class_78.h" -#include "class_71.h" -#include "class_62.h" -#include "class_4.h" -#include "class_16.h" -#include "class_98.h" - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_0/class_16.h b/lib/waf/build/lib_0/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_17.cpp b/lib/waf/build/lib_0/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_17.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_17.h" -#include "class_28.h" -#include "class_39.h" -#include "class_54.h" -#include "class_29.h" -#include "class_47.h" -#include "class_23.h" -#include "class_4.h" -#include "class_17.h" -#include "class_52.h" -#include "class_7.h" -#include "class_40.h" -#include "class_32.h" -#include "class_41.h" -#include "class_9.h" -#include "class_90.h" - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_0/class_17.h b/lib/waf/build/lib_0/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_18.cpp b/lib/waf/build/lib_0/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_18.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_18.h" -#include "class_47.h" -#include "class_84.h" -#include "class_97.h" -#include "class_34.h" -#include "class_69.h" -#include "class_42.h" -#include "class_30.h" -#include "class_73.h" -#include "class_89.h" -#include "class_91.h" -#include "class_62.h" -#include "class_37.h" -#include "class_63.h" -#include "class_6.h" -#include "class_8.h" - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_0/class_18.h b/lib/waf/build/lib_0/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_19.cpp b/lib/waf/build/lib_0/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_19.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_19.h" -#include "class_74.h" -#include "class_6.h" -#include "class_0.h" -#include "class_39.h" -#include "class_51.h" -#include "class_44.h" -#include "class_48.h" -#include "class_58.h" -#include "class_67.h" -#include "class_42.h" -#include "class_36.h" -#include "class_98.h" -#include "class_26.h" -#include "class_77.h" -#include "class_43.h" - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_0/class_19.h b/lib/waf/build/lib_0/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_2.cpp b/lib/waf/build/lib_0/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_2.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_2.h" -#include "class_54.h" -#include "class_1.h" -#include "class_71.h" -#include "class_39.h" -#include "class_82.h" -#include "class_66.h" -#include "class_0.h" -#include "class_49.h" -#include "class_86.h" -#include "class_24.h" -#include "class_32.h" -#include "class_87.h" -#include "class_19.h" -#include "class_56.h" -#include "class_23.h" - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_0/class_2.h b/lib/waf/build/lib_0/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_20.cpp b/lib/waf/build/lib_0/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_20.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_20.h" -#include "class_35.h" -#include "class_6.h" -#include "class_86.h" -#include "class_70.h" -#include "class_90.h" -#include "class_45.h" -#include "class_67.h" -#include "class_11.h" -#include "class_39.h" -#include "class_20.h" -#include "class_4.h" -#include "class_94.h" -#include "class_21.h" -#include "class_14.h" -#include "class_19.h" - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_0/class_20.h b/lib/waf/build/lib_0/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_21.cpp b/lib/waf/build/lib_0/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_21.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_21.h" -#include "class_37.h" -#include "class_54.h" -#include "class_15.h" -#include "class_98.h" -#include "class_14.h" -#include "class_40.h" -#include "class_67.h" -#include "class_87.h" -#include "class_49.h" -#include "class_91.h" -#include "class_32.h" -#include "class_20.h" -#include "class_60.h" -#include "class_21.h" -#include "class_34.h" - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_0/class_21.h b/lib/waf/build/lib_0/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_22.cpp b/lib/waf/build/lib_0/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_22.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_22.h" -#include "class_96.h" -#include "class_89.h" -#include "class_81.h" -#include "class_3.h" -#include "class_14.h" -#include "class_25.h" -#include "class_78.h" -#include "class_84.h" -#include "class_58.h" -#include "class_71.h" -#include "class_80.h" -#include "class_6.h" -#include "class_8.h" -#include "class_86.h" -#include "class_22.h" - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_0/class_22.h b/lib/waf/build/lib_0/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_23.cpp b/lib/waf/build/lib_0/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_23.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_23.h" -#include "class_4.h" -#include "class_1.h" -#include "class_84.h" -#include "class_33.h" -#include "class_16.h" -#include "class_14.h" -#include "class_65.h" -#include "class_96.h" -#include "class_50.h" -#include "class_90.h" -#include "class_57.h" -#include "class_67.h" -#include "class_80.h" -#include "class_75.h" -#include "class_99.h" - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_0/class_23.h b/lib/waf/build/lib_0/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_24.cpp b/lib/waf/build/lib_0/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_24.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_24.h" -#include "class_74.h" -#include "class_90.h" -#include "class_20.h" -#include "class_53.h" -#include "class_59.h" -#include "class_82.h" -#include "class_48.h" -#include "class_79.h" -#include "class_38.h" -#include "class_58.h" -#include "class_85.h" -#include "class_65.h" -#include "class_0.h" -#include "class_18.h" -#include "class_50.h" - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_0/class_24.h b/lib/waf/build/lib_0/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_25.cpp b/lib/waf/build/lib_0/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_25.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_25.h" -#include "class_25.h" -#include "class_6.h" -#include "class_85.h" -#include "class_94.h" -#include "class_30.h" -#include "class_40.h" -#include "class_81.h" -#include "class_64.h" -#include "class_12.h" -#include "class_28.h" -#include "class_82.h" -#include "class_5.h" -#include "class_3.h" -#include "class_41.h" -#include "class_49.h" - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_0/class_25.h b/lib/waf/build/lib_0/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_26.cpp b/lib/waf/build/lib_0/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_26.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_26.h" -#include "class_86.h" -#include "class_71.h" -#include "class_67.h" -#include "class_15.h" -#include "class_98.h" -#include "class_41.h" -#include "class_61.h" -#include "class_38.h" -#include "class_4.h" -#include "class_47.h" -#include "class_3.h" -#include "class_62.h" -#include "class_10.h" -#include "class_54.h" -#include "class_34.h" - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_0/class_26.h b/lib/waf/build/lib_0/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_27.cpp b/lib/waf/build/lib_0/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_27.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_27.h" -#include "class_38.h" -#include "class_77.h" -#include "class_49.h" -#include "class_88.h" -#include "class_61.h" -#include "class_46.h" -#include "class_63.h" -#include "class_33.h" -#include "class_12.h" -#include "class_68.h" -#include "class_62.h" -#include "class_78.h" -#include "class_91.h" -#include "class_79.h" -#include "class_87.h" - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_0/class_27.h b/lib/waf/build/lib_0/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_28.cpp b/lib/waf/build/lib_0/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_28.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_28.h" -#include "class_68.h" -#include "class_81.h" -#include "class_51.h" -#include "class_78.h" -#include "class_18.h" -#include "class_44.h" -#include "class_75.h" -#include "class_45.h" -#include "class_7.h" -#include "class_4.h" -#include "class_93.h" -#include "class_48.h" -#include "class_90.h" -#include "class_94.h" -#include "class_66.h" - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_0/class_28.h b/lib/waf/build/lib_0/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_29.cpp b/lib/waf/build/lib_0/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_29.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_29.h" -#include "class_57.h" -#include "class_21.h" -#include "class_9.h" -#include "class_81.h" -#include "class_88.h" -#include "class_77.h" -#include "class_69.h" -#include "class_42.h" -#include "class_30.h" -#include "class_11.h" -#include "class_56.h" -#include "class_92.h" -#include "class_93.h" -#include "class_41.h" -#include "class_73.h" - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_0/class_29.h b/lib/waf/build/lib_0/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_3.cpp b/lib/waf/build/lib_0/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_3.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_3.h" -#include "class_96.h" -#include "class_80.h" -#include "class_44.h" -#include "class_8.h" -#include "class_32.h" -#include "class_50.h" -#include "class_93.h" -#include "class_10.h" -#include "class_55.h" -#include "class_70.h" -#include "class_54.h" -#include "class_81.h" -#include "class_60.h" -#include "class_58.h" -#include "class_59.h" - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_0/class_3.h b/lib/waf/build/lib_0/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_30.cpp b/lib/waf/build/lib_0/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_30.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_30.h" -#include "class_3.h" -#include "class_44.h" -#include "class_68.h" -#include "class_91.h" -#include "class_96.h" -#include "class_72.h" -#include "class_7.h" -#include "class_35.h" -#include "class_2.h" -#include "class_34.h" -#include "class_0.h" -#include "class_97.h" -#include "class_81.h" -#include "class_89.h" -#include "class_20.h" - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_0/class_30.h b/lib/waf/build/lib_0/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_31.cpp b/lib/waf/build/lib_0/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_31.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_31.h" -#include "class_20.h" -#include "class_67.h" -#include "class_93.h" -#include "class_12.h" -#include "class_0.h" -#include "class_36.h" -#include "class_2.h" -#include "class_60.h" -#include "class_85.h" -#include "class_18.h" -#include "class_11.h" -#include "class_34.h" -#include "class_95.h" -#include "class_13.h" -#include "class_96.h" - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_0/class_31.h b/lib/waf/build/lib_0/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_32.cpp b/lib/waf/build/lib_0/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_32.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_32.h" -#include "class_36.h" -#include "class_47.h" -#include "class_29.h" -#include "class_93.h" -#include "class_95.h" -#include "class_63.h" -#include "class_18.h" -#include "class_99.h" -#include "class_10.h" -#include "class_58.h" -#include "class_15.h" -#include "class_89.h" -#include "class_94.h" -#include "class_80.h" -#include "class_31.h" - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_0/class_32.h b/lib/waf/build/lib_0/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_33.cpp b/lib/waf/build/lib_0/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_33.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_33.h" -#include "class_24.h" -#include "class_75.h" -#include "class_29.h" -#include "class_41.h" -#include "class_4.h" -#include "class_13.h" -#include "class_2.h" -#include "class_7.h" -#include "class_42.h" -#include "class_55.h" -#include "class_74.h" -#include "class_14.h" -#include "class_63.h" -#include "class_8.h" -#include "class_44.h" - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_0/class_33.h b/lib/waf/build/lib_0/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_34.cpp b/lib/waf/build/lib_0/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_34.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_34.h" -#include "class_36.h" -#include "class_94.h" -#include "class_5.h" -#include "class_40.h" -#include "class_41.h" -#include "class_72.h" -#include "class_32.h" -#include "class_20.h" -#include "class_29.h" -#include "class_47.h" -#include "class_95.h" -#include "class_79.h" -#include "class_27.h" -#include "class_55.h" -#include "class_68.h" - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_0/class_34.h b/lib/waf/build/lib_0/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_35.cpp b/lib/waf/build/lib_0/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_35.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_35.h" -#include "class_79.h" -#include "class_44.h" -#include "class_39.h" -#include "class_76.h" -#include "class_43.h" -#include "class_24.h" -#include "class_45.h" -#include "class_93.h" -#include "class_14.h" -#include "class_46.h" -#include "class_63.h" -#include "class_48.h" -#include "class_20.h" -#include "class_0.h" -#include "class_69.h" - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_0/class_35.h b/lib/waf/build/lib_0/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_36.cpp b/lib/waf/build/lib_0/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_36.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_36.h" -#include "class_61.h" -#include "class_0.h" -#include "class_29.h" -#include "class_76.h" -#include "class_62.h" -#include "class_54.h" -#include "class_15.h" -#include "class_70.h" -#include "class_47.h" -#include "class_67.h" -#include "class_23.h" -#include "class_28.h" -#include "class_98.h" -#include "class_12.h" -#include "class_88.h" - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_0/class_36.h b/lib/waf/build/lib_0/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_37.cpp b/lib/waf/build/lib_0/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_37.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_37.h" -#include "class_4.h" -#include "class_25.h" -#include "class_52.h" -#include "class_58.h" -#include "class_39.h" -#include "class_10.h" -#include "class_28.h" -#include "class_75.h" -#include "class_90.h" -#include "class_59.h" -#include "class_3.h" -#include "class_79.h" -#include "class_30.h" -#include "class_33.h" -#include "class_53.h" - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_0/class_37.h b/lib/waf/build/lib_0/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_38.cpp b/lib/waf/build/lib_0/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_38.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_38.h" -#include "class_24.h" -#include "class_91.h" -#include "class_16.h" -#include "class_41.h" -#include "class_28.h" -#include "class_51.h" -#include "class_57.h" -#include "class_62.h" -#include "class_53.h" -#include "class_63.h" -#include "class_40.h" -#include "class_77.h" -#include "class_78.h" -#include "class_29.h" -#include "class_37.h" - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_0/class_38.h b/lib/waf/build/lib_0/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_39.cpp b/lib/waf/build/lib_0/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_39.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_39.h" -#include "class_62.h" -#include "class_15.h" -#include "class_69.h" -#include "class_38.h" -#include "class_59.h" -#include "class_13.h" -#include "class_66.h" -#include "class_35.h" -#include "class_47.h" -#include "class_41.h" -#include "class_31.h" -#include "class_65.h" -#include "class_6.h" -#include "class_30.h" -#include "class_74.h" - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_0/class_39.h b/lib/waf/build/lib_0/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_4.cpp b/lib/waf/build/lib_0/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_4.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_4.h" -#include "class_38.h" -#include "class_57.h" -#include "class_29.h" -#include "class_18.h" -#include "class_61.h" -#include "class_65.h" -#include "class_47.h" -#include "class_8.h" -#include "class_75.h" -#include "class_87.h" -#include "class_92.h" -#include "class_84.h" -#include "class_89.h" -#include "class_54.h" -#include "class_39.h" - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_0/class_4.h b/lib/waf/build/lib_0/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_40.cpp b/lib/waf/build/lib_0/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_40.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_40.h" -#include "class_5.h" -#include "class_62.h" -#include "class_2.h" -#include "class_47.h" -#include "class_88.h" -#include "class_1.h" -#include "class_52.h" -#include "class_6.h" -#include "class_86.h" -#include "class_68.h" -#include "class_74.h" -#include "class_66.h" -#include "class_0.h" -#include "class_4.h" -#include "class_99.h" - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_0/class_40.h b/lib/waf/build/lib_0/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_41.cpp b/lib/waf/build/lib_0/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_41.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_41.h" -#include "class_87.h" -#include "class_69.h" -#include "class_72.h" -#include "class_22.h" -#include "class_75.h" -#include "class_28.h" -#include "class_10.h" -#include "class_46.h" -#include "class_33.h" -#include "class_16.h" -#include "class_42.h" -#include "class_89.h" -#include "class_43.h" -#include "class_44.h" -#include "class_70.h" - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_0/class_41.h b/lib/waf/build/lib_0/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_42.cpp b/lib/waf/build/lib_0/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_42.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_42.h" -#include "class_52.h" -#include "class_12.h" -#include "class_91.h" -#include "class_44.h" -#include "class_78.h" -#include "class_38.h" -#include "class_80.h" -#include "class_22.h" -#include "class_19.h" -#include "class_94.h" -#include "class_58.h" -#include "class_4.h" -#include "class_23.h" -#include "class_8.h" -#include "class_18.h" - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_0/class_42.h b/lib/waf/build/lib_0/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_43.cpp b/lib/waf/build/lib_0/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_43.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_43.h" -#include "class_5.h" -#include "class_63.h" -#include "class_17.h" -#include "class_61.h" -#include "class_70.h" -#include "class_51.h" -#include "class_28.h" -#include "class_87.h" -#include "class_35.h" -#include "class_45.h" -#include "class_95.h" -#include "class_92.h" -#include "class_93.h" -#include "class_58.h" -#include "class_49.h" - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_0/class_43.h b/lib/waf/build/lib_0/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_44.cpp b/lib/waf/build/lib_0/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_44.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_44.h" -#include "class_70.h" -#include "class_21.h" -#include "class_26.h" -#include "class_4.h" -#include "class_16.h" -#include "class_0.h" -#include "class_65.h" -#include "class_14.h" -#include "class_78.h" -#include "class_68.h" -#include "class_97.h" -#include "class_39.h" -#include "class_92.h" -#include "class_45.h" -#include "class_33.h" - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_0/class_44.h b/lib/waf/build/lib_0/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_45.cpp b/lib/waf/build/lib_0/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_45.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_45.h" -#include "class_10.h" -#include "class_88.h" -#include "class_79.h" -#include "class_32.h" -#include "class_45.h" -#include "class_2.h" -#include "class_4.h" -#include "class_36.h" -#include "class_20.h" -#include "class_52.h" -#include "class_18.h" -#include "class_67.h" -#include "class_73.h" -#include "class_31.h" -#include "class_85.h" - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_0/class_45.h b/lib/waf/build/lib_0/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_46.cpp b/lib/waf/build/lib_0/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_46.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_46.h" -#include "class_25.h" -#include "class_34.h" -#include "class_71.h" -#include "class_4.h" -#include "class_93.h" -#include "class_7.h" -#include "class_46.h" -#include "class_72.h" -#include "class_80.h" -#include "class_97.h" -#include "class_11.h" -#include "class_8.h" -#include "class_9.h" -#include "class_76.h" -#include "class_41.h" - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_0/class_46.h b/lib/waf/build/lib_0/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_47.cpp b/lib/waf/build/lib_0/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_47.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_47.h" -#include "class_91.h" -#include "class_44.h" -#include "class_7.h" -#include "class_42.h" -#include "class_75.h" -#include "class_82.h" -#include "class_3.h" -#include "class_18.h" -#include "class_49.h" -#include "class_12.h" -#include "class_87.h" -#include "class_93.h" -#include "class_31.h" -#include "class_43.h" -#include "class_55.h" - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_0/class_47.h b/lib/waf/build/lib_0/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_48.cpp b/lib/waf/build/lib_0/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_48.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_48.h" -#include "class_28.h" -#include "class_54.h" -#include "class_20.h" -#include "class_29.h" -#include "class_44.h" -#include "class_60.h" -#include "class_53.h" -#include "class_26.h" -#include "class_23.h" -#include "class_11.h" -#include "class_78.h" -#include "class_9.h" -#include "class_73.h" -#include "class_24.h" -#include "class_65.h" - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_0/class_48.h b/lib/waf/build/lib_0/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_49.cpp b/lib/waf/build/lib_0/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_49.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_49.h" -#include "class_74.h" -#include "class_51.h" -#include "class_85.h" -#include "class_12.h" -#include "class_64.h" -#include "class_11.h" -#include "class_73.h" -#include "class_35.h" -#include "class_67.h" -#include "class_70.h" -#include "class_66.h" -#include "class_22.h" -#include "class_83.h" -#include "class_24.h" -#include "class_23.h" - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_0/class_49.h b/lib/waf/build/lib_0/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_5.cpp b/lib/waf/build/lib_0/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_5.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_5.h" -#include "class_70.h" -#include "class_27.h" -#include "class_81.h" -#include "class_84.h" -#include "class_89.h" -#include "class_58.h" -#include "class_94.h" -#include "class_57.h" -#include "class_45.h" -#include "class_66.h" -#include "class_99.h" -#include "class_91.h" -#include "class_79.h" -#include "class_8.h" -#include "class_61.h" - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_0/class_5.h b/lib/waf/build/lib_0/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_50.cpp b/lib/waf/build/lib_0/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_50.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_50.h" -#include "class_62.h" -#include "class_28.h" -#include "class_17.h" -#include "class_80.h" -#include "class_55.h" -#include "class_32.h" -#include "class_58.h" -#include "class_2.h" -#include "class_12.h" -#include "class_39.h" -#include "class_97.h" -#include "class_51.h" -#include "class_7.h" -#include "class_76.h" -#include "class_78.h" - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_0/class_50.h b/lib/waf/build/lib_0/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_51.cpp b/lib/waf/build/lib_0/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_51.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_51.h" -#include "class_77.h" -#include "class_56.h" -#include "class_69.h" -#include "class_21.h" -#include "class_73.h" -#include "class_81.h" -#include "class_75.h" -#include "class_35.h" -#include "class_59.h" -#include "class_62.h" -#include "class_90.h" -#include "class_10.h" -#include "class_83.h" -#include "class_52.h" -#include "class_45.h" - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_0/class_51.h b/lib/waf/build/lib_0/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_52.cpp b/lib/waf/build/lib_0/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_52.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_52.h" -#include "class_1.h" -#include "class_22.h" -#include "class_65.h" -#include "class_66.h" -#include "class_49.h" -#include "class_95.h" -#include "class_48.h" -#include "class_31.h" -#include "class_84.h" -#include "class_25.h" -#include "class_60.h" -#include "class_70.h" -#include "class_82.h" -#include "class_78.h" -#include "class_38.h" - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_0/class_52.h b/lib/waf/build/lib_0/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_53.cpp b/lib/waf/build/lib_0/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_53.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_53.h" -#include "class_5.h" -#include "class_3.h" -#include "class_72.h" -#include "class_96.h" -#include "class_34.h" -#include "class_44.h" -#include "class_65.h" -#include "class_26.h" -#include "class_67.h" -#include "class_30.h" -#include "class_35.h" -#include "class_53.h" -#include "class_73.h" -#include "class_15.h" -#include "class_2.h" - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_0/class_53.h b/lib/waf/build/lib_0/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_54.cpp b/lib/waf/build/lib_0/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_54.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_54.h" -#include "class_62.h" -#include "class_2.h" -#include "class_4.h" -#include "class_22.h" -#include "class_65.h" -#include "class_6.h" -#include "class_97.h" -#include "class_42.h" -#include "class_89.h" -#include "class_21.h" -#include "class_43.h" -#include "class_35.h" -#include "class_17.h" -#include "class_32.h" -#include "class_98.h" - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_0/class_54.h b/lib/waf/build/lib_0/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_55.cpp b/lib/waf/build/lib_0/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_55.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_55.h" -#include "class_74.h" -#include "class_38.h" -#include "class_40.h" -#include "class_26.h" -#include "class_53.h" -#include "class_73.h" -#include "class_68.h" -#include "class_46.h" -#include "class_4.h" -#include "class_92.h" -#include "class_39.h" -#include "class_0.h" -#include "class_13.h" -#include "class_86.h" -#include "class_51.h" - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_0/class_55.h b/lib/waf/build/lib_0/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_56.cpp b/lib/waf/build/lib_0/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_56.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_56.h" -#include "class_73.h" -#include "class_14.h" -#include "class_33.h" -#include "class_84.h" -#include "class_82.h" -#include "class_24.h" -#include "class_2.h" -#include "class_80.h" -#include "class_16.h" -#include "class_78.h" -#include "class_68.h" -#include "class_7.h" -#include "class_92.h" -#include "class_59.h" -#include "class_62.h" - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_0/class_56.h b/lib/waf/build/lib_0/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_57.cpp b/lib/waf/build/lib_0/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_57.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_57.h" -#include "class_45.h" -#include "class_15.h" -#include "class_60.h" -#include "class_25.h" -#include "class_80.h" -#include "class_73.h" -#include "class_2.h" -#include "class_93.h" -#include "class_3.h" -#include "class_8.h" -#include "class_29.h" -#include "class_23.h" -#include "class_35.h" -#include "class_40.h" -#include "class_26.h" - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_0/class_57.h b/lib/waf/build/lib_0/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_58.cpp b/lib/waf/build/lib_0/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_58.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_58.h" -#include "class_49.h" -#include "class_39.h" -#include "class_31.h" -#include "class_90.h" -#include "class_55.h" -#include "class_97.h" -#include "class_77.h" -#include "class_57.h" -#include "class_26.h" -#include "class_68.h" -#include "class_45.h" -#include "class_72.h" -#include "class_40.h" -#include "class_2.h" -#include "class_73.h" - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_0/class_58.h b/lib/waf/build/lib_0/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_59.cpp b/lib/waf/build/lib_0/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_59.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_59.h" -#include "class_3.h" -#include "class_68.h" -#include "class_58.h" -#include "class_77.h" -#include "class_28.h" -#include "class_20.h" -#include "class_52.h" -#include "class_34.h" -#include "class_97.h" -#include "class_56.h" -#include "class_32.h" -#include "class_96.h" -#include "class_92.h" -#include "class_72.h" -#include "class_35.h" - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_0/class_59.h b/lib/waf/build/lib_0/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_6.cpp b/lib/waf/build/lib_0/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_6.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_6.h" -#include "class_48.h" -#include "class_63.h" -#include "class_84.h" -#include "class_24.h" -#include "class_73.h" -#include "class_11.h" -#include "class_22.h" -#include "class_79.h" -#include "class_33.h" -#include "class_81.h" -#include "class_10.h" -#include "class_14.h" -#include "class_69.h" -#include "class_4.h" -#include "class_57.h" - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_0/class_6.h b/lib/waf/build/lib_0/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_60.cpp b/lib/waf/build/lib_0/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_60.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_60.h" -#include "class_91.h" -#include "class_89.h" -#include "class_33.h" -#include "class_74.h" -#include "class_0.h" -#include "class_81.h" -#include "class_56.h" -#include "class_95.h" -#include "class_36.h" -#include "class_62.h" -#include "class_32.h" -#include "class_78.h" -#include "class_60.h" -#include "class_98.h" -#include "class_14.h" - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_0/class_60.h b/lib/waf/build/lib_0/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_61.cpp b/lib/waf/build/lib_0/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_61.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_61.h" -#include "class_4.h" -#include "class_12.h" -#include "class_92.h" -#include "class_94.h" -#include "class_48.h" -#include "class_81.h" -#include "class_77.h" -#include "class_74.h" -#include "class_18.h" -#include "class_54.h" -#include "class_42.h" -#include "class_17.h" -#include "class_16.h" -#include "class_65.h" -#include "class_15.h" - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_0/class_61.h b/lib/waf/build/lib_0/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_62.cpp b/lib/waf/build/lib_0/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_62.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_62.h" -#include "class_11.h" -#include "class_50.h" -#include "class_79.h" -#include "class_60.h" -#include "class_75.h" -#include "class_26.h" -#include "class_28.h" -#include "class_42.h" -#include "class_99.h" -#include "class_71.h" -#include "class_94.h" -#include "class_53.h" -#include "class_55.h" -#include "class_18.h" -#include "class_78.h" - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_0/class_62.h b/lib/waf/build/lib_0/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_63.cpp b/lib/waf/build/lib_0/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_63.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_63.h" -#include "class_79.h" -#include "class_84.h" -#include "class_75.h" -#include "class_15.h" -#include "class_66.h" -#include "class_92.h" -#include "class_56.h" -#include "class_36.h" -#include "class_94.h" -#include "class_41.h" -#include "class_61.h" -#include "class_80.h" -#include "class_22.h" -#include "class_1.h" -#include "class_52.h" - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_0/class_63.h b/lib/waf/build/lib_0/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_64.cpp b/lib/waf/build/lib_0/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_64.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_64.h" -#include "class_94.h" -#include "class_68.h" -#include "class_63.h" -#include "class_62.h" -#include "class_49.h" -#include "class_73.h" -#include "class_24.h" -#include "class_89.h" -#include "class_27.h" -#include "class_92.h" -#include "class_7.h" -#include "class_44.h" -#include "class_74.h" -#include "class_50.h" -#include "class_80.h" - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_0/class_64.h b/lib/waf/build/lib_0/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_65.cpp b/lib/waf/build/lib_0/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_65.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_65.h" -#include "class_70.h" -#include "class_95.h" -#include "class_16.h" -#include "class_92.h" -#include "class_63.h" -#include "class_94.h" -#include "class_25.h" -#include "class_88.h" -#include "class_77.h" -#include "class_60.h" -#include "class_9.h" -#include "class_3.h" -#include "class_1.h" -#include "class_76.h" -#include "class_38.h" - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_0/class_65.h b/lib/waf/build/lib_0/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_66.cpp b/lib/waf/build/lib_0/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_66.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_66.h" -#include "class_77.h" -#include "class_62.h" -#include "class_38.h" -#include "class_88.h" -#include "class_3.h" -#include "class_46.h" -#include "class_82.h" -#include "class_12.h" -#include "class_71.h" -#include "class_32.h" -#include "class_2.h" -#include "class_47.h" -#include "class_52.h" -#include "class_4.h" -#include "class_56.h" - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_0/class_66.h b/lib/waf/build/lib_0/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_67.cpp b/lib/waf/build/lib_0/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_67.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_67.h" -#include "class_34.h" -#include "class_0.h" -#include "class_19.h" -#include "class_11.h" -#include "class_54.h" -#include "class_4.h" -#include "class_92.h" -#include "class_84.h" -#include "class_94.h" -#include "class_31.h" -#include "class_90.h" -#include "class_98.h" -#include "class_76.h" -#include "class_27.h" -#include "class_67.h" - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_0/class_67.h b/lib/waf/build/lib_0/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_68.cpp b/lib/waf/build/lib_0/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_68.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_68.h" -#include "class_59.h" -#include "class_40.h" -#include "class_30.h" -#include "class_5.h" -#include "class_12.h" -#include "class_13.h" -#include "class_48.h" -#include "class_64.h" -#include "class_76.h" -#include "class_4.h" -#include "class_82.h" -#include "class_55.h" -#include "class_74.h" -#include "class_63.h" -#include "class_94.h" - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_0/class_68.h b/lib/waf/build/lib_0/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_69.cpp b/lib/waf/build/lib_0/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_69.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_69.h" -#include "class_34.h" -#include "class_58.h" -#include "class_8.h" -#include "class_55.h" -#include "class_81.h" -#include "class_20.h" -#include "class_26.h" -#include "class_70.h" -#include "class_25.h" -#include "class_93.h" -#include "class_99.h" -#include "class_15.h" -#include "class_90.h" -#include "class_3.h" -#include "class_64.h" - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_0/class_69.h b/lib/waf/build/lib_0/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_7.cpp b/lib/waf/build/lib_0/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_7.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_7.h" -#include "class_91.h" -#include "class_53.h" -#include "class_68.h" -#include "class_2.h" -#include "class_63.h" -#include "class_60.h" -#include "class_57.h" -#include "class_39.h" -#include "class_37.h" -#include "class_98.h" -#include "class_3.h" -#include "class_96.h" -#include "class_18.h" -#include "class_12.h" -#include "class_21.h" - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_0/class_7.h b/lib/waf/build/lib_0/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_70.cpp b/lib/waf/build/lib_0/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_70.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_70.h" -#include "class_3.h" -#include "class_75.h" -#include "class_81.h" -#include "class_7.h" -#include "class_64.h" -#include "class_45.h" -#include "class_23.h" -#include "class_15.h" -#include "class_33.h" -#include "class_65.h" -#include "class_47.h" -#include "class_55.h" -#include "class_54.h" -#include "class_82.h" -#include "class_34.h" - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_0/class_70.h b/lib/waf/build/lib_0/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_71.cpp b/lib/waf/build/lib_0/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_71.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_71.h" -#include "class_81.h" -#include "class_7.h" -#include "class_42.h" -#include "class_35.h" -#include "class_45.h" -#include "class_83.h" -#include "class_51.h" -#include "class_98.h" -#include "class_86.h" -#include "class_11.h" -#include "class_31.h" -#include "class_2.h" -#include "class_73.h" -#include "class_1.h" -#include "class_88.h" - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_0/class_71.h b/lib/waf/build/lib_0/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_72.cpp b/lib/waf/build/lib_0/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_72.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_72.h" -#include "class_19.h" -#include "class_41.h" -#include "class_6.h" -#include "class_31.h" -#include "class_38.h" -#include "class_5.h" -#include "class_76.h" -#include "class_71.h" -#include "class_35.h" -#include "class_83.h" -#include "class_7.h" -#include "class_90.h" -#include "class_75.h" -#include "class_67.h" -#include "class_56.h" - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_0/class_72.h b/lib/waf/build/lib_0/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_73.cpp b/lib/waf/build/lib_0/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_73.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_73.h" -#include "class_80.h" -#include "class_41.h" -#include "class_3.h" -#include "class_19.h" -#include "class_38.h" -#include "class_35.h" -#include "class_12.h" -#include "class_17.h" -#include "class_61.h" -#include "class_65.h" -#include "class_1.h" -#include "class_45.h" -#include "class_55.h" -#include "class_87.h" -#include "class_49.h" - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_0/class_73.h b/lib/waf/build/lib_0/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_74.cpp b/lib/waf/build/lib_0/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_74.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_74.h" -#include "class_8.h" -#include "class_5.h" -#include "class_86.h" -#include "class_79.h" -#include "class_85.h" -#include "class_26.h" -#include "class_64.h" -#include "class_9.h" -#include "class_82.h" -#include "class_33.h" -#include "class_95.h" -#include "class_47.h" -#include "class_3.h" -#include "class_90.h" -#include "class_62.h" - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_0/class_74.h b/lib/waf/build/lib_0/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_75.cpp b/lib/waf/build/lib_0/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_75.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_75.h" -#include "class_28.h" -#include "class_3.h" -#include "class_37.h" -#include "class_15.h" -#include "class_54.h" -#include "class_14.h" -#include "class_17.h" -#include "class_92.h" -#include "class_64.h" -#include "class_24.h" -#include "class_87.h" -#include "class_62.h" -#include "class_94.h" -#include "class_48.h" -#include "class_88.h" - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_0/class_75.h b/lib/waf/build/lib_0/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_76.cpp b/lib/waf/build/lib_0/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_76.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_76.h" -#include "class_67.h" -#include "class_4.h" -#include "class_24.h" -#include "class_28.h" -#include "class_17.h" -#include "class_23.h" -#include "class_22.h" -#include "class_87.h" -#include "class_46.h" -#include "class_13.h" -#include "class_56.h" -#include "class_1.h" -#include "class_93.h" -#include "class_0.h" -#include "class_38.h" - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_0/class_76.h b/lib/waf/build/lib_0/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_77.cpp b/lib/waf/build/lib_0/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_77.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_77.h" -#include "class_80.h" -#include "class_99.h" -#include "class_1.h" -#include "class_82.h" -#include "class_51.h" -#include "class_3.h" -#include "class_77.h" -#include "class_11.h" -#include "class_61.h" -#include "class_67.h" -#include "class_37.h" -#include "class_2.h" -#include "class_43.h" -#include "class_91.h" -#include "class_33.h" - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_0/class_77.h b/lib/waf/build/lib_0/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_78.cpp b/lib/waf/build/lib_0/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_78.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_78.h" -#include "class_24.h" -#include "class_13.h" -#include "class_51.h" -#include "class_53.h" -#include "class_7.h" -#include "class_40.h" -#include "class_65.h" -#include "class_96.h" -#include "class_43.h" -#include "class_47.h" -#include "class_22.h" -#include "class_39.h" -#include "class_64.h" -#include "class_58.h" -#include "class_83.h" - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_0/class_78.h b/lib/waf/build/lib_0/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_79.cpp b/lib/waf/build/lib_0/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_79.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_79.h" -#include "class_99.h" -#include "class_88.h" -#include "class_37.h" -#include "class_2.h" -#include "class_61.h" -#include "class_47.h" -#include "class_23.h" -#include "class_4.h" -#include "class_32.h" -#include "class_79.h" -#include "class_96.h" -#include "class_10.h" -#include "class_87.h" -#include "class_71.h" -#include "class_42.h" - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_0/class_79.h b/lib/waf/build/lib_0/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_8.cpp b/lib/waf/build/lib_0/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_8.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_8.h" -#include "class_80.h" -#include "class_93.h" -#include "class_2.h" -#include "class_42.h" -#include "class_10.h" -#include "class_25.h" -#include "class_22.h" -#include "class_64.h" -#include "class_35.h" -#include "class_18.h" -#include "class_50.h" -#include "class_3.h" -#include "class_98.h" -#include "class_19.h" -#include "class_73.h" - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_0/class_8.h b/lib/waf/build/lib_0/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_80.cpp b/lib/waf/build/lib_0/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_80.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_80.h" -#include "class_87.h" -#include "class_39.h" -#include "class_92.h" -#include "class_71.h" -#include "class_60.h" -#include "class_16.h" -#include "class_34.h" -#include "class_41.h" -#include "class_59.h" -#include "class_99.h" -#include "class_28.h" -#include "class_50.h" -#include "class_93.h" -#include "class_62.h" -#include "class_76.h" - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_0/class_80.h b/lib/waf/build/lib_0/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_81.cpp b/lib/waf/build/lib_0/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_81.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_81.h" -#include "class_63.h" -#include "class_75.h" -#include "class_19.h" -#include "class_95.h" -#include "class_17.h" -#include "class_58.h" -#include "class_29.h" -#include "class_43.h" -#include "class_68.h" -#include "class_26.h" -#include "class_72.h" -#include "class_34.h" -#include "class_13.h" -#include "class_61.h" -#include "class_16.h" - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_0/class_81.h b/lib/waf/build/lib_0/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_82.cpp b/lib/waf/build/lib_0/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_82.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_82.h" -#include "class_43.h" -#include "class_39.h" -#include "class_7.h" -#include "class_71.h" -#include "class_68.h" -#include "class_77.h" -#include "class_54.h" -#include "class_55.h" -#include "class_16.h" -#include "class_20.h" -#include "class_22.h" -#include "class_52.h" -#include "class_81.h" -#include "class_35.h" -#include "class_88.h" - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_0/class_82.h b/lib/waf/build/lib_0/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_83.cpp b/lib/waf/build/lib_0/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_83.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_83.h" -#include "class_73.h" -#include "class_71.h" -#include "class_33.h" -#include "class_11.h" -#include "class_96.h" -#include "class_85.h" -#include "class_40.h" -#include "class_86.h" -#include "class_89.h" -#include "class_34.h" -#include "class_50.h" -#include "class_69.h" -#include "class_91.h" -#include "class_98.h" -#include "class_74.h" - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_0/class_83.h b/lib/waf/build/lib_0/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_84.cpp b/lib/waf/build/lib_0/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_84.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_84.h" -#include "class_30.h" -#include "class_88.h" -#include "class_99.h" -#include "class_34.h" -#include "class_94.h" -#include "class_51.h" -#include "class_96.h" -#include "class_81.h" -#include "class_68.h" -#include "class_15.h" -#include "class_0.h" -#include "class_59.h" -#include "class_70.h" -#include "class_93.h" -#include "class_69.h" - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_0/class_84.h b/lib/waf/build/lib_0/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_85.cpp b/lib/waf/build/lib_0/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_85.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_85.h" -#include "class_64.h" -#include "class_20.h" -#include "class_98.h" -#include "class_11.h" -#include "class_68.h" -#include "class_61.h" -#include "class_37.h" -#include "class_79.h" -#include "class_1.h" -#include "class_89.h" -#include "class_81.h" -#include "class_48.h" -#include "class_10.h" -#include "class_45.h" -#include "class_58.h" - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_0/class_85.h b/lib/waf/build/lib_0/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_86.cpp b/lib/waf/build/lib_0/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_86.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_86.h" -#include "class_25.h" -#include "class_48.h" -#include "class_77.h" -#include "class_92.h" -#include "class_56.h" -#include "class_82.h" -#include "class_7.h" -#include "class_85.h" -#include "class_16.h" -#include "class_84.h" -#include "class_87.h" -#include "class_51.h" -#include "class_60.h" -#include "class_20.h" -#include "class_70.h" - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_0/class_86.h b/lib/waf/build/lib_0/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_87.cpp b/lib/waf/build/lib_0/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_87.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_87.h" -#include "class_40.h" -#include "class_2.h" -#include "class_13.h" -#include "class_38.h" -#include "class_88.h" -#include "class_56.h" -#include "class_91.h" -#include "class_92.h" -#include "class_8.h" -#include "class_58.h" -#include "class_33.h" -#include "class_50.h" -#include "class_45.h" -#include "class_47.h" -#include "class_10.h" - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_0/class_87.h b/lib/waf/build/lib_0/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_88.cpp b/lib/waf/build/lib_0/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_88.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_88.h" -#include "class_83.h" -#include "class_49.h" -#include "class_64.h" -#include "class_47.h" -#include "class_18.h" -#include "class_54.h" -#include "class_15.h" -#include "class_85.h" -#include "class_14.h" -#include "class_6.h" -#include "class_39.h" -#include "class_95.h" -#include "class_55.h" -#include "class_26.h" -#include "class_22.h" - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_0/class_88.h b/lib/waf/build/lib_0/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_89.cpp b/lib/waf/build/lib_0/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_89.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_89.h" -#include "class_11.h" -#include "class_14.h" -#include "class_81.h" -#include "class_13.h" -#include "class_86.h" -#include "class_82.h" -#include "class_55.h" -#include "class_0.h" -#include "class_75.h" -#include "class_49.h" -#include "class_69.h" -#include "class_93.h" -#include "class_87.h" -#include "class_34.h" -#include "class_9.h" - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_0/class_89.h b/lib/waf/build/lib_0/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_9.cpp b/lib/waf/build/lib_0/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_9.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_9.h" -#include "class_83.h" -#include "class_91.h" -#include "class_16.h" -#include "class_67.h" -#include "class_96.h" -#include "class_5.h" -#include "class_84.h" -#include "class_34.h" -#include "class_25.h" -#include "class_59.h" -#include "class_44.h" -#include "class_17.h" -#include "class_47.h" -#include "class_40.h" -#include "class_56.h" - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_0/class_9.h b/lib/waf/build/lib_0/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_90.cpp b/lib/waf/build/lib_0/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_90.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_90.h" -#include "class_0.h" -#include "class_22.h" -#include "class_83.h" -#include "class_31.h" -#include "class_49.h" -#include "class_94.h" -#include "class_50.h" -#include "class_34.h" -#include "class_7.h" -#include "class_57.h" -#include "class_36.h" -#include "class_38.h" -#include "class_75.h" -#include "class_23.h" -#include "class_93.h" - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_0/class_90.h b/lib/waf/build/lib_0/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_91.cpp b/lib/waf/build/lib_0/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_91.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_91.h" -#include "class_74.h" -#include "class_48.h" -#include "class_88.h" -#include "class_35.h" -#include "class_38.h" -#include "class_12.h" -#include "class_77.h" -#include "class_40.h" -#include "class_50.h" -#include "class_47.h" -#include "class_65.h" -#include "class_37.h" -#include "class_91.h" -#include "class_43.h" -#include "class_76.h" - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_0/class_91.h b/lib/waf/build/lib_0/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_92.cpp b/lib/waf/build/lib_0/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_92.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_92.h" -#include "class_99.h" -#include "class_86.h" -#include "class_47.h" -#include "class_29.h" -#include "class_44.h" -#include "class_34.h" -#include "class_24.h" -#include "class_18.h" -#include "class_95.h" -#include "class_49.h" -#include "class_10.h" -#include "class_38.h" -#include "class_51.h" -#include "class_98.h" -#include "class_97.h" - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_0/class_92.h b/lib/waf/build/lib_0/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_93.cpp b/lib/waf/build/lib_0/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_93.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_93.h" -#include "class_56.h" -#include "class_61.h" -#include "class_67.h" -#include "class_50.h" -#include "class_48.h" -#include "class_31.h" -#include "class_68.h" -#include "class_9.h" -#include "class_89.h" -#include "class_22.h" -#include "class_96.h" -#include "class_98.h" -#include "class_57.h" -#include "class_4.h" -#include "class_20.h" - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_0/class_93.h b/lib/waf/build/lib_0/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_94.cpp b/lib/waf/build/lib_0/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_94.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_94.h" -#include "class_32.h" -#include "class_11.h" -#include "class_79.h" -#include "class_36.h" -#include "class_23.h" -#include "class_4.h" -#include "class_38.h" -#include "class_0.h" -#include "class_60.h" -#include "class_93.h" -#include "class_19.h" -#include "class_74.h" -#include "class_89.h" -#include "class_84.h" -#include "class_6.h" - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_0/class_94.h b/lib/waf/build/lib_0/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_95.cpp b/lib/waf/build/lib_0/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_95.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_95.h" -#include "class_17.h" -#include "class_23.h" -#include "class_92.h" -#include "class_38.h" -#include "class_80.h" -#include "class_43.h" -#include "class_76.h" -#include "class_61.h" -#include "class_26.h" -#include "class_58.h" -#include "class_70.h" -#include "class_82.h" -#include "class_67.h" -#include "class_64.h" -#include "class_59.h" - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_0/class_95.h b/lib/waf/build/lib_0/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_96.cpp b/lib/waf/build/lib_0/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_96.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_96.h" -#include "class_9.h" -#include "class_94.h" -#include "class_71.h" -#include "class_27.h" -#include "class_69.h" -#include "class_62.h" -#include "class_65.h" -#include "class_37.h" -#include "class_57.h" -#include "class_66.h" -#include "class_20.h" -#include "class_50.h" -#include "class_12.h" -#include "class_10.h" -#include "class_91.h" - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_0/class_96.h b/lib/waf/build/lib_0/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_97.cpp b/lib/waf/build/lib_0/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_97.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_97.h" -#include "class_12.h" -#include "class_89.h" -#include "class_46.h" -#include "class_45.h" -#include "class_33.h" -#include "class_41.h" -#include "class_37.h" -#include "class_56.h" -#include "class_82.h" -#include "class_23.h" -#include "class_24.h" -#include "class_48.h" -#include "class_93.h" -#include "class_2.h" -#include "class_72.h" - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_0/class_97.h b/lib/waf/build/lib_0/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_98.cpp b/lib/waf/build/lib_0/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_98.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_98.h" -#include "class_0.h" -#include "class_40.h" -#include "class_76.h" -#include "class_44.h" -#include "class_42.h" -#include "class_25.h" -#include "class_47.h" -#include "class_22.h" -#include "class_28.h" -#include "class_65.h" -#include "class_59.h" -#include "class_92.h" -#include "class_96.h" -#include "class_52.h" -#include "class_8.h" - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_0/class_98.h b/lib/waf/build/lib_0/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_0/class_99.cpp b/lib/waf/build/lib_0/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_0/class_99.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "class_99.h" -#include "class_29.h" -#include "class_51.h" -#include "class_67.h" -#include "class_94.h" -#include "class_15.h" -#include "class_3.h" -#include "class_87.h" -#include "class_80.h" -#include "class_76.h" -#include "class_46.h" -#include "class_41.h" -#include "class_19.h" -#include "class_39.h" -#include "class_78.h" -#include "class_96.h" - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_0/class_99.h b/lib/waf/build/lib_0/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_0/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_1/Makefile b/lib/waf/build/lib_1/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_1/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_1.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_1/Makefile.am b/lib/waf/build/lib_1/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_1/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib1.la -lib1_la_SOURCES = lib_1/class_0.cpp lib_1/class_1.cpp lib_1/class_2.cpp lib_1/class_3.cpp lib_1/class_4.cpp lib_1/class_5.cpp lib_1/class_6.cpp lib_1/class_7.cpp lib_1/class_8.cpp lib_1/class_9.cpp lib_1/class_10.cpp lib_1/class_11.cpp lib_1/class_12.cpp lib_1/class_13.cpp lib_1/class_14.cpp lib_1/class_15.cpp lib_1/class_16.cpp lib_1/class_17.cpp lib_1/class_18.cpp lib_1/class_19.cpp lib_1/class_20.cpp lib_1/class_21.cpp lib_1/class_22.cpp lib_1/class_23.cpp lib_1/class_24.cpp lib_1/class_25.cpp lib_1/class_26.cpp lib_1/class_27.cpp lib_1/class_28.cpp lib_1/class_29.cpp lib_1/class_30.cpp lib_1/class_31.cpp lib_1/class_32.cpp lib_1/class_33.cpp lib_1/class_34.cpp lib_1/class_35.cpp lib_1/class_36.cpp lib_1/class_37.cpp lib_1/class_38.cpp lib_1/class_39.cpp lib_1/class_40.cpp lib_1/class_41.cpp lib_1/class_42.cpp lib_1/class_43.cpp lib_1/class_44.cpp lib_1/class_45.cpp lib_1/class_46.cpp lib_1/class_47.cpp lib_1/class_48.cpp lib_1/class_49.cpp lib_1/class_50.cpp lib_1/class_51.cpp lib_1/class_52.cpp lib_1/class_53.cpp lib_1/class_54.cpp lib_1/class_55.cpp lib_1/class_56.cpp lib_1/class_57.cpp lib_1/class_58.cpp lib_1/class_59.cpp lib_1/class_60.cpp lib_1/class_61.cpp lib_1/class_62.cpp lib_1/class_63.cpp lib_1/class_64.cpp lib_1/class_65.cpp lib_1/class_66.cpp lib_1/class_67.cpp lib_1/class_68.cpp lib_1/class_69.cpp lib_1/class_70.cpp lib_1/class_71.cpp lib_1/class_72.cpp lib_1/class_73.cpp lib_1/class_74.cpp lib_1/class_75.cpp lib_1/class_76.cpp lib_1/class_77.cpp lib_1/class_78.cpp lib_1/class_79.cpp lib_1/class_80.cpp lib_1/class_81.cpp lib_1/class_82.cpp lib_1/class_83.cpp lib_1/class_84.cpp lib_1/class_85.cpp lib_1/class_86.cpp lib_1/class_87.cpp lib_1/class_88.cpp lib_1/class_89.cpp lib_1/class_90.cpp lib_1/class_91.cpp lib_1/class_92.cpp lib_1/class_93.cpp lib_1/class_94.cpp lib_1/class_95.cpp lib_1/class_96.cpp lib_1/class_97.cpp lib_1/class_98.cpp lib_1/class_99.cpp diff --git a/lib/waf/build/lib_1/SConscript b/lib/waf/build/lib_1/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_1/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_1", list) - diff --git a/lib/waf/build/lib_1/class_0.cpp b/lib/waf/build/lib_1/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_88.h" -#include "class_68.h" -#include "class_52.h" -#include "class_72.h" -#include "class_18.h" -#include "class_92.h" -#include "class_71.h" -#include "class_59.h" -#include "class_43.h" -#include "class_63.h" -#include "class_61.h" -#include "class_89.h" -#include "class_57.h" -#include "class_21.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_1/class_0.h b/lib/waf/build/lib_1/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_1.cpp b/lib/waf/build/lib_1/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_68.h" -#include "class_86.h" -#include "class_75.h" -#include "class_42.h" -#include "class_64.h" -#include "class_98.h" -#include "class_88.h" -#include "class_33.h" -#include "class_16.h" -#include "class_55.h" -#include "class_35.h" -#include "class_43.h" -#include "class_66.h" -#include "class_84.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_1/class_1.h b/lib/waf/build/lib_1/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_10.cpp b/lib/waf/build/lib_1/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_12.h" -#include "class_8.h" -#include "class_1.h" -#include "class_82.h" -#include "class_96.h" -#include "class_98.h" -#include "class_74.h" -#include "class_45.h" -#include "class_27.h" -#include "class_41.h" -#include "class_34.h" -#include "class_39.h" -#include "class_72.h" -#include "class_89.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_1/class_10.h b/lib/waf/build/lib_1/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_11.cpp b/lib/waf/build/lib_1/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_13.h" -#include "class_62.h" -#include "class_50.h" -#include "class_1.h" -#include "class_14.h" -#include "class_66.h" -#include "class_36.h" -#include "class_96.h" -#include "class_68.h" -#include "class_47.h" -#include "class_73.h" -#include "class_83.h" -#include "class_19.h" -#include "class_39.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_1/class_11.h b/lib/waf/build/lib_1/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_12.cpp b/lib/waf/build/lib_1/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_67.h" -#include "class_75.h" -#include "class_84.h" -#include "class_18.h" -#include "class_21.h" -#include "class_51.h" -#include "class_50.h" -#include "class_80.h" -#include "class_90.h" -#include "class_77.h" -#include "class_82.h" -#include "class_47.h" -#include "class_34.h" -#include "class_43.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_1/class_12.h b/lib/waf/build/lib_1/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_13.cpp b/lib/waf/build/lib_1/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_0.h" -#include "class_87.h" -#include "class_93.h" -#include "class_18.h" -#include "class_17.h" -#include "class_96.h" -#include "class_36.h" -#include "class_81.h" -#include "class_99.h" -#include "class_1.h" -#include "class_60.h" -#include "class_92.h" -#include "class_83.h" -#include "class_31.h" -#include "class_82.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_1/class_13.h b/lib/waf/build/lib_1/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_14.cpp b/lib/waf/build/lib_1/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_35.h" -#include "class_20.h" -#include "class_92.h" -#include "class_19.h" -#include "class_18.h" -#include "class_17.h" -#include "class_65.h" -#include "class_61.h" -#include "class_50.h" -#include "class_58.h" -#include "class_94.h" -#include "class_86.h" -#include "class_90.h" -#include "class_5.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_1/class_14.h b/lib/waf/build/lib_1/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_15.cpp b/lib/waf/build/lib_1/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_33.h" -#include "class_13.h" -#include "class_97.h" -#include "class_65.h" -#include "class_27.h" -#include "class_60.h" -#include "class_89.h" -#include "class_7.h" -#include "class_80.h" -#include "class_15.h" -#include "class_10.h" -#include "class_25.h" -#include "class_71.h" -#include "class_42.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_1/class_15.h b/lib/waf/build/lib_1/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_16.cpp b/lib/waf/build/lib_1/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_10.h" -#include "class_76.h" -#include "class_26.h" -#include "class_78.h" -#include "class_63.h" -#include "class_50.h" -#include "class_53.h" -#include "class_7.h" -#include "class_4.h" -#include "class_1.h" -#include "class_77.h" -#include "class_13.h" -#include "class_12.h" -#include "class_38.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_1/class_16.h b/lib/waf/build/lib_1/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_17.cpp b/lib/waf/build/lib_1/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_2.h" -#include "class_59.h" -#include "class_39.h" -#include "class_56.h" -#include "class_70.h" -#include "class_40.h" -#include "class_89.h" -#include "class_95.h" -#include "class_98.h" -#include "class_5.h" -#include "class_83.h" -#include "class_87.h" -#include "class_14.h" -#include "class_94.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_1/class_17.h b/lib/waf/build/lib_1/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_18.cpp b/lib/waf/build/lib_1/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_77.h" -#include "class_7.h" -#include "class_1.h" -#include "class_28.h" -#include "class_83.h" -#include "class_50.h" -#include "class_93.h" -#include "class_11.h" -#include "class_33.h" -#include "class_74.h" -#include "class_32.h" -#include "class_14.h" -#include "class_57.h" -#include "class_6.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_1/class_18.h b/lib/waf/build/lib_1/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_19.cpp b/lib/waf/build/lib_1/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_7.h" -#include "class_21.h" -#include "class_64.h" -#include "class_82.h" -#include "class_51.h" -#include "class_14.h" -#include "class_15.h" -#include "class_38.h" -#include "class_56.h" -#include "class_66.h" -#include "class_52.h" -#include "class_35.h" -#include "class_72.h" -#include "class_40.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_1/class_19.h b/lib/waf/build/lib_1/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_2.cpp b/lib/waf/build/lib_1/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_85.h" -#include "class_58.h" -#include "class_87.h" -#include "class_41.h" -#include "class_21.h" -#include "class_0.h" -#include "class_99.h" -#include "class_13.h" -#include "class_64.h" -#include "class_48.h" -#include "class_38.h" -#include "class_53.h" -#include "class_7.h" -#include "class_97.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_1/class_2.h b/lib/waf/build/lib_1/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_20.cpp b/lib/waf/build/lib_1/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_24.h" -#include "class_7.h" -#include "class_11.h" -#include "class_43.h" -#include "class_61.h" -#include "class_54.h" -#include "class_51.h" -#include "class_4.h" -#include "class_35.h" -#include "class_94.h" -#include "class_17.h" -#include "class_26.h" -#include "class_48.h" -#include "class_91.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_1/class_20.h b/lib/waf/build/lib_1/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_21.cpp b/lib/waf/build/lib_1/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_73.h" -#include "class_52.h" -#include "class_99.h" -#include "class_16.h" -#include "class_38.h" -#include "class_28.h" -#include "class_87.h" -#include "class_48.h" -#include "class_91.h" -#include "class_70.h" -#include "class_59.h" -#include "class_97.h" -#include "class_17.h" -#include "class_44.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_1/class_21.h b/lib/waf/build/lib_1/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_22.cpp b/lib/waf/build/lib_1/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_53.h" -#include "class_86.h" -#include "class_88.h" -#include "class_94.h" -#include "class_23.h" -#include "class_33.h" -#include "class_63.h" -#include "class_32.h" -#include "class_14.h" -#include "class_75.h" -#include "class_55.h" -#include "class_71.h" -#include "class_11.h" -#include "class_92.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_1/class_22.h b/lib/waf/build/lib_1/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_23.cpp b/lib/waf/build/lib_1/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_73.h" -#include "class_4.h" -#include "class_95.h" -#include "class_60.h" -#include "class_16.h" -#include "class_55.h" -#include "class_8.h" -#include "class_50.h" -#include "class_68.h" -#include "class_41.h" -#include "class_31.h" -#include "class_67.h" -#include "class_93.h" -#include "class_87.h" -#include "class_38.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_1/class_23.h b/lib/waf/build/lib_1/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_24.cpp b/lib/waf/build/lib_1/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_48.h" -#include "class_22.h" -#include "class_67.h" -#include "class_72.h" -#include "class_99.h" -#include "class_79.h" -#include "class_9.h" -#include "class_98.h" -#include "class_85.h" -#include "class_58.h" -#include "class_33.h" -#include "class_73.h" -#include "class_59.h" -#include "class_56.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_1/class_24.h b/lib/waf/build/lib_1/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_25.cpp b/lib/waf/build/lib_1/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_53.h" -#include "class_86.h" -#include "class_19.h" -#include "class_29.h" -#include "class_90.h" -#include "class_59.h" -#include "class_22.h" -#include "class_13.h" -#include "class_49.h" -#include "class_30.h" -#include "class_73.h" -#include "class_27.h" -#include "class_7.h" -#include "class_89.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_1/class_25.h b/lib/waf/build/lib_1/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_26.cpp b/lib/waf/build/lib_1/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_69.h" -#include "class_85.h" -#include "class_86.h" -#include "class_79.h" -#include "class_73.h" -#include "class_0.h" -#include "class_14.h" -#include "class_20.h" -#include "class_57.h" -#include "class_12.h" -#include "class_48.h" -#include "class_4.h" -#include "class_31.h" -#include "class_21.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_1/class_26.h b/lib/waf/build/lib_1/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_27.cpp b/lib/waf/build/lib_1/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_96.h" -#include "class_21.h" -#include "class_55.h" -#include "class_6.h" -#include "class_37.h" -#include "class_95.h" -#include "class_90.h" -#include "class_9.h" -#include "class_85.h" -#include "class_71.h" -#include "class_91.h" -#include "class_46.h" -#include "class_42.h" -#include "class_89.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_1/class_27.h b/lib/waf/build/lib_1/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_28.cpp b/lib/waf/build/lib_1/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_12.h" -#include "class_70.h" -#include "class_54.h" -#include "class_15.h" -#include "class_3.h" -#include "class_61.h" -#include "class_51.h" -#include "class_57.h" -#include "class_41.h" -#include "class_46.h" -#include "class_39.h" -#include "class_8.h" -#include "class_53.h" -#include "class_67.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_1/class_28.h b/lib/waf/build/lib_1/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_29.cpp b/lib/waf/build/lib_1/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_92.h" -#include "class_9.h" -#include "class_13.h" -#include "class_19.h" -#include "class_57.h" -#include "class_63.h" -#include "class_43.h" -#include "class_39.h" -#include "class_64.h" -#include "class_26.h" -#include "class_80.h" -#include "class_60.h" -#include "class_2.h" -#include "class_34.h" -#include "class_76.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_1/class_29.h b/lib/waf/build/lib_1/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_3.cpp b/lib/waf/build/lib_1/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_51.h" -#include "class_15.h" -#include "class_25.h" -#include "class_59.h" -#include "class_27.h" -#include "class_83.h" -#include "class_21.h" -#include "class_38.h" -#include "class_50.h" -#include "class_33.h" -#include "class_82.h" -#include "class_26.h" -#include "class_8.h" -#include "class_62.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_1/class_3.h b/lib/waf/build/lib_1/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_30.cpp b/lib/waf/build/lib_1/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_83.h" -#include "class_29.h" -#include "class_32.h" -#include "class_72.h" -#include "class_66.h" -#include "class_71.h" -#include "class_87.h" -#include "class_8.h" -#include "class_12.h" -#include "class_49.h" -#include "class_61.h" -#include "class_65.h" -#include "class_23.h" -#include "class_13.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_1/class_30.h b/lib/waf/build/lib_1/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_31.cpp b/lib/waf/build/lib_1/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_35.h" -#include "class_81.h" -#include "class_19.h" -#include "class_99.h" -#include "class_52.h" -#include "class_42.h" -#include "class_72.h" -#include "class_37.h" -#include "class_3.h" -#include "class_44.h" -#include "class_28.h" -#include "class_66.h" -#include "class_83.h" -#include "class_48.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_1/class_31.h b/lib/waf/build/lib_1/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_32.cpp b/lib/waf/build/lib_1/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_29.h" -#include "class_47.h" -#include "class_8.h" -#include "class_36.h" -#include "class_92.h" -#include "class_10.h" -#include "class_24.h" -#include "class_4.h" -#include "class_86.h" -#include "class_68.h" -#include "class_58.h" -#include "class_46.h" -#include "class_26.h" -#include "class_70.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_1/class_32.h b/lib/waf/build/lib_1/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_33.cpp b/lib/waf/build/lib_1/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_14.h" -#include "class_60.h" -#include "class_76.h" -#include "class_63.h" -#include "class_15.h" -#include "class_82.h" -#include "class_62.h" -#include "class_6.h" -#include "class_27.h" -#include "class_26.h" -#include "class_46.h" -#include "class_78.h" -#include "class_57.h" -#include "class_99.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_1/class_33.h b/lib/waf/build/lib_1/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_34.cpp b/lib/waf/build/lib_1/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_59.h" -#include "class_14.h" -#include "class_87.h" -#include "class_21.h" -#include "class_31.h" -#include "class_76.h" -#include "class_42.h" -#include "class_51.h" -#include "class_97.h" -#include "class_71.h" -#include "class_65.h" -#include "class_98.h" -#include "class_92.h" -#include "class_29.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_1/class_34.h b/lib/waf/build/lib_1/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_35.cpp b/lib/waf/build/lib_1/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_77.h" -#include "class_28.h" -#include "class_62.h" -#include "class_42.h" -#include "class_61.h" -#include "class_56.h" -#include "class_51.h" -#include "class_16.h" -#include "class_0.h" -#include "class_10.h" -#include "class_38.h" -#include "class_25.h" -#include "class_48.h" -#include "class_47.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_1/class_35.h b/lib/waf/build/lib_1/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_36.cpp b/lib/waf/build/lib_1/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_62.h" -#include "class_92.h" -#include "class_33.h" -#include "class_77.h" -#include "class_12.h" -#include "class_64.h" -#include "class_24.h" -#include "class_76.h" -#include "class_91.h" -#include "class_44.h" -#include "class_68.h" -#include "class_35.h" -#include "class_84.h" -#include "class_41.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_1/class_36.h b/lib/waf/build/lib_1/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_37.cpp b/lib/waf/build/lib_1/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_9.h" -#include "class_5.h" -#include "class_84.h" -#include "class_60.h" -#include "class_30.h" -#include "class_52.h" -#include "class_55.h" -#include "class_67.h" -#include "class_0.h" -#include "class_14.h" -#include "class_75.h" -#include "class_45.h" -#include "class_19.h" -#include "class_37.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_1/class_37.h b/lib/waf/build/lib_1/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_38.cpp b/lib/waf/build/lib_1/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_88.h" -#include "class_10.h" -#include "class_61.h" -#include "class_74.h" -#include "class_24.h" -#include "class_83.h" -#include "class_68.h" -#include "class_44.h" -#include "class_16.h" -#include "class_25.h" -#include "class_82.h" -#include "class_70.h" -#include "class_57.h" -#include "class_56.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_1/class_38.h b/lib/waf/build/lib_1/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_39.cpp b/lib/waf/build/lib_1/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_42.h" -#include "class_80.h" -#include "class_58.h" -#include "class_97.h" -#include "class_60.h" -#include "class_28.h" -#include "class_51.h" -#include "class_47.h" -#include "class_85.h" -#include "class_73.h" -#include "class_88.h" -#include "class_71.h" -#include "class_25.h" -#include "class_27.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_1/class_39.h b/lib/waf/build/lib_1/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_4.cpp b/lib/waf/build/lib_1/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_88.h" -#include "class_11.h" -#include "class_42.h" -#include "class_3.h" -#include "class_27.h" -#include "class_38.h" -#include "class_34.h" -#include "class_37.h" -#include "class_80.h" -#include "class_18.h" -#include "class_82.h" -#include "class_54.h" -#include "class_33.h" -#include "class_55.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_1/class_4.h b/lib/waf/build/lib_1/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_40.cpp b/lib/waf/build/lib_1/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_72.h" -#include "class_81.h" -#include "class_18.h" -#include "class_95.h" -#include "class_60.h" -#include "class_55.h" -#include "class_3.h" -#include "class_41.h" -#include "class_46.h" -#include "class_44.h" -#include "class_1.h" -#include "class_56.h" -#include "class_6.h" -#include "class_99.h" -#include "class_65.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_1/class_40.h b/lib/waf/build/lib_1/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_41.cpp b/lib/waf/build/lib_1/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_0.h" -#include "class_61.h" -#include "class_83.h" -#include "class_86.h" -#include "class_76.h" -#include "class_41.h" -#include "class_70.h" -#include "class_6.h" -#include "class_3.h" -#include "class_34.h" -#include "class_64.h" -#include "class_38.h" -#include "class_77.h" -#include "class_28.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_1/class_41.h b/lib/waf/build/lib_1/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_42.cpp b/lib/waf/build/lib_1/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_99.h" -#include "class_83.h" -#include "class_58.h" -#include "class_60.h" -#include "class_46.h" -#include "class_36.h" -#include "class_41.h" -#include "class_91.h" -#include "class_64.h" -#include "class_16.h" -#include "class_3.h" -#include "class_43.h" -#include "class_44.h" -#include "class_6.h" -#include "class_22.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_1/class_42.h b/lib/waf/build/lib_1/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_43.cpp b/lib/waf/build/lib_1/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_64.h" -#include "class_17.h" -#include "class_65.h" -#include "class_98.h" -#include "class_91.h" -#include "class_43.h" -#include "class_28.h" -#include "class_44.h" -#include "class_95.h" -#include "class_3.h" -#include "class_47.h" -#include "class_89.h" -#include "class_10.h" -#include "class_11.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_1/class_43.h b/lib/waf/build/lib_1/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_44.cpp b/lib/waf/build/lib_1/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_21.h" -#include "class_93.h" -#include "class_63.h" -#include "class_54.h" -#include "class_20.h" -#include "class_87.h" -#include "class_42.h" -#include "class_4.h" -#include "class_92.h" -#include "class_36.h" -#include "class_29.h" -#include "class_5.h" -#include "class_3.h" -#include "class_86.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_1/class_44.h b/lib/waf/build/lib_1/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_45.cpp b/lib/waf/build/lib_1/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_93.h" -#include "class_43.h" -#include "class_11.h" -#include "class_71.h" -#include "class_44.h" -#include "class_50.h" -#include "class_88.h" -#include "class_53.h" -#include "class_13.h" -#include "class_37.h" -#include "class_84.h" -#include "class_51.h" -#include "class_8.h" -#include "class_3.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_1/class_45.h b/lib/waf/build/lib_1/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_46.cpp b/lib/waf/build/lib_1/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_69.h" -#include "class_15.h" -#include "class_40.h" -#include "class_77.h" -#include "class_36.h" -#include "class_28.h" -#include "class_35.h" -#include "class_37.h" -#include "class_0.h" -#include "class_14.h" -#include "class_74.h" -#include "class_65.h" -#include "class_13.h" -#include "class_11.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_1/class_46.h b/lib/waf/build/lib_1/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_47.cpp b/lib/waf/build/lib_1/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_9.h" -#include "class_79.h" -#include "class_14.h" -#include "class_25.h" -#include "class_18.h" -#include "class_11.h" -#include "class_67.h" -#include "class_24.h" -#include "class_76.h" -#include "class_95.h" -#include "class_77.h" -#include "class_99.h" -#include "class_55.h" -#include "class_3.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_1/class_47.h b/lib/waf/build/lib_1/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_48.cpp b/lib/waf/build/lib_1/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_64.h" -#include "class_0.h" -#include "class_67.h" -#include "class_22.h" -#include "class_98.h" -#include "class_93.h" -#include "class_86.h" -#include "class_70.h" -#include "class_25.h" -#include "class_92.h" -#include "class_82.h" -#include "class_63.h" -#include "class_17.h" -#include "class_19.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_1/class_48.h b/lib/waf/build/lib_1/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_49.cpp b/lib/waf/build/lib_1/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_54.h" -#include "class_19.h" -#include "class_96.h" -#include "class_64.h" -#include "class_75.h" -#include "class_89.h" -#include "class_45.h" -#include "class_44.h" -#include "class_61.h" -#include "class_33.h" -#include "class_82.h" -#include "class_36.h" -#include "class_77.h" -#include "class_1.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_1/class_49.h b/lib/waf/build/lib_1/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_5.cpp b/lib/waf/build/lib_1/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_57.h" -#include "class_52.h" -#include "class_86.h" -#include "class_58.h" -#include "class_48.h" -#include "class_78.h" -#include "class_34.h" -#include "class_55.h" -#include "class_70.h" -#include "class_99.h" -#include "class_69.h" -#include "class_96.h" -#include "class_39.h" -#include "class_60.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_1/class_5.h b/lib/waf/build/lib_1/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_50.cpp b/lib/waf/build/lib_1/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_41.h" -#include "class_39.h" -#include "class_15.h" -#include "class_42.h" -#include "class_99.h" -#include "class_82.h" -#include "class_73.h" -#include "class_64.h" -#include "class_21.h" -#include "class_6.h" -#include "class_93.h" -#include "class_90.h" -#include "class_0.h" -#include "class_91.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_1/class_50.h b/lib/waf/build/lib_1/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_51.cpp b/lib/waf/build/lib_1/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_31.h" -#include "class_25.h" -#include "class_28.h" -#include "class_60.h" -#include "class_2.h" -#include "class_93.h" -#include "class_51.h" -#include "class_50.h" -#include "class_42.h" -#include "class_73.h" -#include "class_76.h" -#include "class_72.h" -#include "class_96.h" -#include "class_41.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_1/class_51.h b/lib/waf/build/lib_1/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_52.cpp b/lib/waf/build/lib_1/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_70.h" -#include "class_47.h" -#include "class_18.h" -#include "class_58.h" -#include "class_2.h" -#include "class_35.h" -#include "class_30.h" -#include "class_6.h" -#include "class_9.h" -#include "class_78.h" -#include "class_45.h" -#include "class_12.h" -#include "class_93.h" -#include "class_31.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_1/class_52.h b/lib/waf/build/lib_1/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_53.cpp b/lib/waf/build/lib_1/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_51.h" -#include "class_39.h" -#include "class_53.h" -#include "class_89.h" -#include "class_9.h" -#include "class_50.h" -#include "class_14.h" -#include "class_93.h" -#include "class_19.h" -#include "class_2.h" -#include "class_47.h" -#include "class_57.h" -#include "class_5.h" -#include "class_62.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_1/class_53.h b/lib/waf/build/lib_1/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_54.cpp b/lib/waf/build/lib_1/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_65.h" -#include "class_99.h" -#include "class_36.h" -#include "class_77.h" -#include "class_47.h" -#include "class_40.h" -#include "class_21.h" -#include "class_41.h" -#include "class_26.h" -#include "class_48.h" -#include "class_66.h" -#include "class_88.h" -#include "class_14.h" -#include "class_80.h" -#include "class_76.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_1/class_54.h b/lib/waf/build/lib_1/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_55.cpp b/lib/waf/build/lib_1/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_70.h" -#include "class_80.h" -#include "class_49.h" -#include "class_9.h" -#include "class_58.h" -#include "class_44.h" -#include "class_31.h" -#include "class_8.h" -#include "class_27.h" -#include "class_35.h" -#include "class_71.h" -#include "class_11.h" -#include "class_37.h" -#include "class_75.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_1/class_55.h b/lib/waf/build/lib_1/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_56.cpp b/lib/waf/build/lib_1/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_89.h" -#include "class_10.h" -#include "class_37.h" -#include "class_8.h" -#include "class_46.h" -#include "class_66.h" -#include "class_70.h" -#include "class_5.h" -#include "class_11.h" -#include "class_63.h" -#include "class_83.h" -#include "class_60.h" -#include "class_9.h" -#include "class_58.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_1/class_56.h b/lib/waf/build/lib_1/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_57.cpp b/lib/waf/build/lib_1/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_89.h" -#include "class_17.h" -#include "class_16.h" -#include "class_72.h" -#include "class_21.h" -#include "class_52.h" -#include "class_90.h" -#include "class_35.h" -#include "class_73.h" -#include "class_86.h" -#include "class_65.h" -#include "class_9.h" -#include "class_51.h" -#include "class_79.h" -#include "class_99.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_1/class_57.h b/lib/waf/build/lib_1/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_58.cpp b/lib/waf/build/lib_1/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_12.h" -#include "class_13.h" -#include "class_23.h" -#include "class_54.h" -#include "class_66.h" -#include "class_86.h" -#include "class_58.h" -#include "class_63.h" -#include "class_48.h" -#include "class_50.h" -#include "class_26.h" -#include "class_29.h" -#include "class_62.h" -#include "class_18.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_1/class_58.h b/lib/waf/build/lib_1/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_59.cpp b/lib/waf/build/lib_1/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_87.h" -#include "class_31.h" -#include "class_79.h" -#include "class_22.h" -#include "class_33.h" -#include "class_49.h" -#include "class_51.h" -#include "class_73.h" -#include "class_2.h" -#include "class_80.h" -#include "class_0.h" -#include "class_56.h" -#include "class_1.h" -#include "class_13.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_1/class_59.h b/lib/waf/build/lib_1/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_6.cpp b/lib/waf/build/lib_1/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_76.h" -#include "class_8.h" -#include "class_81.h" -#include "class_30.h" -#include "class_70.h" -#include "class_95.h" -#include "class_3.h" -#include "class_61.h" -#include "class_29.h" -#include "class_11.h" -#include "class_71.h" -#include "class_97.h" -#include "class_51.h" -#include "class_34.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_1/class_6.h b/lib/waf/build/lib_1/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_60.cpp b/lib/waf/build/lib_1/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_53.h" -#include "class_67.h" -#include "class_36.h" -#include "class_41.h" -#include "class_39.h" -#include "class_3.h" -#include "class_73.h" -#include "class_56.h" -#include "class_88.h" -#include "class_77.h" -#include "class_6.h" -#include "class_63.h" -#include "class_93.h" -#include "class_89.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_1/class_60.h b/lib/waf/build/lib_1/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_61.cpp b/lib/waf/build/lib_1/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_40.h" -#include "class_33.h" -#include "class_89.h" -#include "class_28.h" -#include "class_69.h" -#include "class_21.h" -#include "class_90.h" -#include "class_46.h" -#include "class_29.h" -#include "class_42.h" -#include "class_73.h" -#include "class_85.h" -#include "class_81.h" -#include "class_12.h" -#include "class_96.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_1/class_61.h b/lib/waf/build/lib_1/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_62.cpp b/lib/waf/build/lib_1/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_66.h" -#include "class_12.h" -#include "class_93.h" -#include "class_43.h" -#include "class_18.h" -#include "class_84.h" -#include "class_5.h" -#include "class_3.h" -#include "class_73.h" -#include "class_8.h" -#include "class_74.h" -#include "class_9.h" -#include "class_13.h" -#include "class_56.h" -#include "class_64.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_1/class_62.h b/lib/waf/build/lib_1/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_63.cpp b/lib/waf/build/lib_1/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_14.h" -#include "class_83.h" -#include "class_9.h" -#include "class_90.h" -#include "class_94.h" -#include "class_13.h" -#include "class_92.h" -#include "class_26.h" -#include "class_79.h" -#include "class_32.h" -#include "class_44.h" -#include "class_71.h" -#include "class_54.h" -#include "class_75.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_1/class_63.h b/lib/waf/build/lib_1/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_64.cpp b/lib/waf/build/lib_1/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_87.h" -#include "class_5.h" -#include "class_33.h" -#include "class_97.h" -#include "class_56.h" -#include "class_94.h" -#include "class_0.h" -#include "class_81.h" -#include "class_62.h" -#include "class_85.h" -#include "class_73.h" -#include "class_99.h" -#include "class_74.h" -#include "class_84.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_1/class_64.h b/lib/waf/build/lib_1/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_65.cpp b/lib/waf/build/lib_1/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_32.h" -#include "class_60.h" -#include "class_48.h" -#include "class_44.h" -#include "class_90.h" -#include "class_41.h" -#include "class_2.h" -#include "class_85.h" -#include "class_95.h" -#include "class_80.h" -#include "class_15.h" -#include "class_42.h" -#include "class_75.h" -#include "class_86.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_1/class_65.h b/lib/waf/build/lib_1/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_66.cpp b/lib/waf/build/lib_1/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_47.h" -#include "class_90.h" -#include "class_97.h" -#include "class_65.h" -#include "class_19.h" -#include "class_79.h" -#include "class_37.h" -#include "class_26.h" -#include "class_58.h" -#include "class_44.h" -#include "class_51.h" -#include "class_3.h" -#include "class_87.h" -#include "class_43.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_1/class_66.h b/lib/waf/build/lib_1/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_67.cpp b/lib/waf/build/lib_1/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_56.h" -#include "class_29.h" -#include "class_16.h" -#include "class_72.h" -#include "class_28.h" -#include "class_80.h" -#include "class_94.h" -#include "class_35.h" -#include "class_37.h" -#include "class_30.h" -#include "class_25.h" -#include "class_99.h" -#include "class_82.h" -#include "class_86.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_1/class_67.h b/lib/waf/build/lib_1/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_68.cpp b/lib/waf/build/lib_1/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_71.h" -#include "class_79.h" -#include "class_77.h" -#include "class_81.h" -#include "class_15.h" -#include "class_60.h" -#include "class_87.h" -#include "class_43.h" -#include "class_26.h" -#include "class_53.h" -#include "class_49.h" -#include "class_1.h" -#include "class_4.h" -#include "class_18.h" -#include "class_65.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_1/class_68.h b/lib/waf/build/lib_1/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_69.cpp b/lib/waf/build/lib_1/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_89.h" -#include "class_79.h" -#include "class_58.h" -#include "class_1.h" -#include "class_41.h" -#include "class_7.h" -#include "class_96.h" -#include "class_82.h" -#include "class_34.h" -#include "class_10.h" -#include "class_56.h" -#include "class_35.h" -#include "class_72.h" -#include "class_83.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_1/class_69.h b/lib/waf/build/lib_1/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_7.cpp b/lib/waf/build/lib_1/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_3.h" -#include "class_83.h" -#include "class_63.h" -#include "class_26.h" -#include "class_87.h" -#include "class_66.h" -#include "class_31.h" -#include "class_54.h" -#include "class_97.h" -#include "class_4.h" -#include "class_70.h" -#include "class_84.h" -#include "class_69.h" -#include "class_14.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_1/class_7.h b/lib/waf/build/lib_1/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_70.cpp b/lib/waf/build/lib_1/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_1.h" -#include "class_4.h" -#include "class_9.h" -#include "class_39.h" -#include "class_59.h" -#include "class_73.h" -#include "class_65.h" -#include "class_10.h" -#include "class_86.h" -#include "class_81.h" -#include "class_17.h" -#include "class_38.h" -#include "class_67.h" -#include "class_63.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_1/class_70.h b/lib/waf/build/lib_1/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_71.cpp b/lib/waf/build/lib_1/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_18.h" -#include "class_19.h" -#include "class_3.h" -#include "class_11.h" -#include "class_75.h" -#include "class_32.h" -#include "class_30.h" -#include "class_14.h" -#include "class_57.h" -#include "class_41.h" -#include "class_5.h" -#include "class_38.h" -#include "class_80.h" -#include "class_97.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_1/class_71.h b/lib/waf/build/lib_1/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_72.cpp b/lib/waf/build/lib_1/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_64.h" -#include "class_52.h" -#include "class_21.h" -#include "class_39.h" -#include "class_22.h" -#include "class_72.h" -#include "class_54.h" -#include "class_15.h" -#include "class_16.h" -#include "class_2.h" -#include "class_11.h" -#include "class_61.h" -#include "class_63.h" -#include "class_78.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_1/class_72.h b/lib/waf/build/lib_1/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_73.cpp b/lib/waf/build/lib_1/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_58.h" -#include "class_19.h" -#include "class_66.h" -#include "class_69.h" -#include "class_26.h" -#include "class_37.h" -#include "class_29.h" -#include "class_99.h" -#include "class_35.h" -#include "class_34.h" -#include "class_24.h" -#include "class_83.h" -#include "class_18.h" -#include "class_53.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_1/class_73.h b/lib/waf/build/lib_1/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_74.cpp b/lib/waf/build/lib_1/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_30.h" -#include "class_8.h" -#include "class_96.h" -#include "class_50.h" -#include "class_42.h" -#include "class_55.h" -#include "class_17.h" -#include "class_79.h" -#include "class_28.h" -#include "class_84.h" -#include "class_73.h" -#include "class_29.h" -#include "class_48.h" -#include "class_94.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_1/class_74.h b/lib/waf/build/lib_1/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_75.cpp b/lib/waf/build/lib_1/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_62.h" -#include "class_50.h" -#include "class_6.h" -#include "class_76.h" -#include "class_40.h" -#include "class_48.h" -#include "class_82.h" -#include "class_31.h" -#include "class_14.h" -#include "class_4.h" -#include "class_68.h" -#include "class_59.h" -#include "class_11.h" -#include "class_39.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_1/class_75.h b/lib/waf/build/lib_1/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_76.cpp b/lib/waf/build/lib_1/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_77.h" -#include "class_16.h" -#include "class_65.h" -#include "class_94.h" -#include "class_53.h" -#include "class_14.h" -#include "class_35.h" -#include "class_51.h" -#include "class_43.h" -#include "class_59.h" -#include "class_88.h" -#include "class_97.h" -#include "class_18.h" -#include "class_2.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_1/class_76.h b/lib/waf/build/lib_1/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_77.cpp b/lib/waf/build/lib_1/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_88.h" -#include "class_9.h" -#include "class_4.h" -#include "class_92.h" -#include "class_25.h" -#include "class_71.h" -#include "class_21.h" -#include "class_58.h" -#include "class_34.h" -#include "class_72.h" -#include "class_74.h" -#include "class_90.h" -#include "class_80.h" -#include "class_45.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_1/class_77.h b/lib/waf/build/lib_1/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_78.cpp b/lib/waf/build/lib_1/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_36.h" -#include "class_35.h" -#include "class_94.h" -#include "class_37.h" -#include "class_1.h" -#include "class_96.h" -#include "class_58.h" -#include "class_30.h" -#include "class_79.h" -#include "class_2.h" -#include "class_85.h" -#include "class_11.h" -#include "class_14.h" -#include "class_83.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_1/class_78.h b/lib/waf/build/lib_1/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_79.cpp b/lib/waf/build/lib_1/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_62.h" -#include "class_2.h" -#include "class_46.h" -#include "class_63.h" -#include "class_38.h" -#include "class_16.h" -#include "class_91.h" -#include "class_1.h" -#include "class_86.h" -#include "class_99.h" -#include "class_9.h" -#include "class_76.h" -#include "class_66.h" -#include "class_49.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_1/class_79.h b/lib/waf/build/lib_1/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_8.cpp b/lib/waf/build/lib_1/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_52.h" -#include "class_23.h" -#include "class_80.h" -#include "class_38.h" -#include "class_30.h" -#include "class_82.h" -#include "class_90.h" -#include "class_96.h" -#include "class_1.h" -#include "class_75.h" -#include "class_12.h" -#include "class_24.h" -#include "class_28.h" -#include "class_40.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_1/class_8.h b/lib/waf/build/lib_1/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_80.cpp b/lib/waf/build/lib_1/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_12.h" -#include "class_21.h" -#include "class_23.h" -#include "class_14.h" -#include "class_4.h" -#include "class_55.h" -#include "class_58.h" -#include "class_72.h" -#include "class_61.h" -#include "class_45.h" -#include "class_44.h" -#include "class_1.h" -#include "class_63.h" -#include "class_62.h" -#include "class_96.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_1/class_80.h b/lib/waf/build/lib_1/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_81.cpp b/lib/waf/build/lib_1/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_26.h" -#include "class_66.h" -#include "class_73.h" -#include "class_82.h" -#include "class_57.h" -#include "class_97.h" -#include "class_96.h" -#include "class_51.h" -#include "class_45.h" -#include "class_10.h" -#include "class_58.h" -#include "class_31.h" -#include "class_68.h" -#include "class_71.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_1/class_81.h b/lib/waf/build/lib_1/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_82.cpp b/lib/waf/build/lib_1/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_1.h" -#include "class_31.h" -#include "class_46.h" -#include "class_51.h" -#include "class_90.h" -#include "class_49.h" -#include "class_23.h" -#include "class_85.h" -#include "class_78.h" -#include "class_26.h" -#include "class_94.h" -#include "class_40.h" -#include "class_44.h" -#include "class_47.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_1/class_82.h b/lib/waf/build/lib_1/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_83.cpp b/lib/waf/build/lib_1/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_68.h" -#include "class_74.h" -#include "class_22.h" -#include "class_18.h" -#include "class_96.h" -#include "class_46.h" -#include "class_47.h" -#include "class_8.h" -#include "class_17.h" -#include "class_5.h" -#include "class_25.h" -#include "class_33.h" -#include "class_67.h" -#include "class_28.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_1/class_83.h b/lib/waf/build/lib_1/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_84.cpp b/lib/waf/build/lib_1/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_89.h" -#include "class_29.h" -#include "class_26.h" -#include "class_0.h" -#include "class_15.h" -#include "class_34.h" -#include "class_23.h" -#include "class_87.h" -#include "class_4.h" -#include "class_44.h" -#include "class_37.h" -#include "class_86.h" -#include "class_83.h" -#include "class_32.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_1/class_84.h b/lib/waf/build/lib_1/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_85.cpp b/lib/waf/build/lib_1/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_66.h" -#include "class_82.h" -#include "class_28.h" -#include "class_6.h" -#include "class_48.h" -#include "class_33.h" -#include "class_4.h" -#include "class_51.h" -#include "class_44.h" -#include "class_70.h" -#include "class_67.h" -#include "class_38.h" -#include "class_97.h" -#include "class_20.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_1/class_85.h b/lib/waf/build/lib_1/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_86.cpp b/lib/waf/build/lib_1/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_17.h" -#include "class_36.h" -#include "class_67.h" -#include "class_84.h" -#include "class_73.h" -#include "class_62.h" -#include "class_22.h" -#include "class_0.h" -#include "class_85.h" -#include "class_76.h" -#include "class_94.h" -#include "class_13.h" -#include "class_97.h" -#include "class_33.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_1/class_86.h b/lib/waf/build/lib_1/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_87.cpp b/lib/waf/build/lib_1/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_77.h" -#include "class_76.h" -#include "class_23.h" -#include "class_91.h" -#include "class_36.h" -#include "class_34.h" -#include "class_98.h" -#include "class_67.h" -#include "class_37.h" -#include "class_6.h" -#include "class_18.h" -#include "class_94.h" -#include "class_57.h" -#include "class_79.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_1/class_87.h b/lib/waf/build/lib_1/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_88.cpp b/lib/waf/build/lib_1/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_25.h" -#include "class_26.h" -#include "class_18.h" -#include "class_41.h" -#include "class_9.h" -#include "class_14.h" -#include "class_85.h" -#include "class_17.h" -#include "class_44.h" -#include "class_8.h" -#include "class_79.h" -#include "class_66.h" -#include "class_81.h" -#include "class_20.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_1/class_88.h b/lib/waf/build/lib_1/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_89.cpp b/lib/waf/build/lib_1/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_97.h" -#include "class_84.h" -#include "class_99.h" -#include "class_28.h" -#include "class_68.h" -#include "class_43.h" -#include "class_87.h" -#include "class_61.h" -#include "class_40.h" -#include "class_94.h" -#include "class_49.h" -#include "class_42.h" -#include "class_30.h" -#include "class_16.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_1/class_89.h b/lib/waf/build/lib_1/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_9.cpp b/lib/waf/build/lib_1/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_25.h" -#include "class_2.h" -#include "class_23.h" -#include "class_82.h" -#include "class_41.h" -#include "class_88.h" -#include "class_94.h" -#include "class_24.h" -#include "class_55.h" -#include "class_58.h" -#include "class_16.h" -#include "class_98.h" -#include "class_29.h" -#include "class_86.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_1/class_9.h b/lib/waf/build/lib_1/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_90.cpp b/lib/waf/build/lib_1/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_86.h" -#include "class_50.h" -#include "class_21.h" -#include "class_56.h" -#include "class_2.h" -#include "class_69.h" -#include "class_27.h" -#include "class_37.h" -#include "class_62.h" -#include "class_95.h" -#include "class_22.h" -#include "class_0.h" -#include "class_85.h" -#include "class_60.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_1/class_90.h b/lib/waf/build/lib_1/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_91.cpp b/lib/waf/build/lib_1/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_48.h" -#include "class_89.h" -#include "class_82.h" -#include "class_46.h" -#include "class_71.h" -#include "class_13.h" -#include "class_74.h" -#include "class_39.h" -#include "class_34.h" -#include "class_79.h" -#include "class_29.h" -#include "class_49.h" -#include "class_99.h" -#include "class_24.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_1/class_91.h b/lib/waf/build/lib_1/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_92.cpp b/lib/waf/build/lib_1/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_10.h" -#include "class_27.h" -#include "class_15.h" -#include "class_20.h" -#include "class_13.h" -#include "class_34.h" -#include "class_87.h" -#include "class_59.h" -#include "class_99.h" -#include "class_25.h" -#include "class_28.h" -#include "class_18.h" -#include "class_94.h" -#include "class_37.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_1/class_92.h b/lib/waf/build/lib_1/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_93.cpp b/lib/waf/build/lib_1/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_48.h" -#include "class_31.h" -#include "class_66.h" -#include "class_80.h" -#include "class_11.h" -#include "class_42.h" -#include "class_59.h" -#include "class_87.h" -#include "class_54.h" -#include "class_88.h" -#include "class_15.h" -#include "class_0.h" -#include "class_38.h" -#include "class_36.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_1/class_93.h b/lib/waf/build/lib_1/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_94.cpp b/lib/waf/build/lib_1/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_21.h" -#include "class_64.h" -#include "class_40.h" -#include "class_4.h" -#include "class_89.h" -#include "class_91.h" -#include "class_63.h" -#include "class_20.h" -#include "class_41.h" -#include "class_69.h" -#include "class_11.h" -#include "class_9.h" -#include "class_93.h" -#include "class_75.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_1/class_94.h b/lib/waf/build/lib_1/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_95.cpp b/lib/waf/build/lib_1/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_78.h" -#include "class_96.h" -#include "class_10.h" -#include "class_75.h" -#include "class_36.h" -#include "class_88.h" -#include "class_86.h" -#include "class_99.h" -#include "class_50.h" -#include "class_49.h" -#include "class_21.h" -#include "class_5.h" -#include "class_90.h" -#include "class_43.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_1/class_95.h b/lib/waf/build/lib_1/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_96.cpp b/lib/waf/build/lib_1/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_32.h" -#include "class_13.h" -#include "class_71.h" -#include "class_5.h" -#include "class_47.h" -#include "class_55.h" -#include "class_42.h" -#include "class_24.h" -#include "class_62.h" -#include "class_9.h" -#include "class_17.h" -#include "class_29.h" -#include "class_44.h" -#include "class_20.h" -#include "class_64.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_1/class_96.h b/lib/waf/build/lib_1/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_97.cpp b/lib/waf/build/lib_1/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_59.h" -#include "class_49.h" -#include "class_79.h" -#include "class_60.h" -#include "class_34.h" -#include "class_85.h" -#include "class_27.h" -#include "class_30.h" -#include "class_86.h" -#include "class_97.h" -#include "class_21.h" -#include "class_22.h" -#include "class_57.h" -#include "class_2.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_1/class_97.h b/lib/waf/build/lib_1/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_98.cpp b/lib/waf/build/lib_1/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_64.h" -#include "class_90.h" -#include "class_38.h" -#include "class_42.h" -#include "class_79.h" -#include "class_4.h" -#include "class_33.h" -#include "class_6.h" -#include "class_65.h" -#include "class_67.h" -#include "class_66.h" -#include "class_62.h" -#include "class_74.h" -#include "class_1.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_1/class_98.h b/lib/waf/build/lib_1/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_1/class_99.cpp b/lib/waf/build/lib_1/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_1/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_23.h" -#include "class_48.h" -#include "class_60.h" -#include "class_25.h" -#include "class_20.h" -#include "class_52.h" -#include "class_7.h" -#include "class_22.h" -#include "class_39.h" -#include "class_93.h" -#include "class_45.h" -#include "class_24.h" -#include "class_87.h" -#include "class_99.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_1/class_99.h b/lib/waf/build/lib_1/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_1/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_10/Makefile b/lib/waf/build/lib_10/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_10/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_10.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_10/Makefile.am b/lib/waf/build/lib_10/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_10/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib10.la -lib10_la_SOURCES = lib_10/class_0.cpp lib_10/class_1.cpp lib_10/class_2.cpp lib_10/class_3.cpp lib_10/class_4.cpp lib_10/class_5.cpp lib_10/class_6.cpp lib_10/class_7.cpp lib_10/class_8.cpp lib_10/class_9.cpp lib_10/class_10.cpp lib_10/class_11.cpp lib_10/class_12.cpp lib_10/class_13.cpp lib_10/class_14.cpp lib_10/class_15.cpp lib_10/class_16.cpp lib_10/class_17.cpp lib_10/class_18.cpp lib_10/class_19.cpp lib_10/class_20.cpp lib_10/class_21.cpp lib_10/class_22.cpp lib_10/class_23.cpp lib_10/class_24.cpp lib_10/class_25.cpp lib_10/class_26.cpp lib_10/class_27.cpp lib_10/class_28.cpp lib_10/class_29.cpp lib_10/class_30.cpp lib_10/class_31.cpp lib_10/class_32.cpp lib_10/class_33.cpp lib_10/class_34.cpp lib_10/class_35.cpp lib_10/class_36.cpp lib_10/class_37.cpp lib_10/class_38.cpp lib_10/class_39.cpp lib_10/class_40.cpp lib_10/class_41.cpp lib_10/class_42.cpp lib_10/class_43.cpp lib_10/class_44.cpp lib_10/class_45.cpp lib_10/class_46.cpp lib_10/class_47.cpp lib_10/class_48.cpp lib_10/class_49.cpp lib_10/class_50.cpp lib_10/class_51.cpp lib_10/class_52.cpp lib_10/class_53.cpp lib_10/class_54.cpp lib_10/class_55.cpp lib_10/class_56.cpp lib_10/class_57.cpp lib_10/class_58.cpp lib_10/class_59.cpp lib_10/class_60.cpp lib_10/class_61.cpp lib_10/class_62.cpp lib_10/class_63.cpp lib_10/class_64.cpp lib_10/class_65.cpp lib_10/class_66.cpp lib_10/class_67.cpp lib_10/class_68.cpp lib_10/class_69.cpp lib_10/class_70.cpp lib_10/class_71.cpp lib_10/class_72.cpp lib_10/class_73.cpp lib_10/class_74.cpp lib_10/class_75.cpp lib_10/class_76.cpp lib_10/class_77.cpp lib_10/class_78.cpp lib_10/class_79.cpp lib_10/class_80.cpp lib_10/class_81.cpp lib_10/class_82.cpp lib_10/class_83.cpp lib_10/class_84.cpp lib_10/class_85.cpp lib_10/class_86.cpp lib_10/class_87.cpp lib_10/class_88.cpp lib_10/class_89.cpp lib_10/class_90.cpp lib_10/class_91.cpp lib_10/class_92.cpp lib_10/class_93.cpp lib_10/class_94.cpp lib_10/class_95.cpp lib_10/class_96.cpp lib_10/class_97.cpp lib_10/class_98.cpp lib_10/class_99.cpp diff --git a/lib/waf/build/lib_10/SConscript b/lib/waf/build/lib_10/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_10/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_10", list) - diff --git a/lib/waf/build/lib_10/class_0.cpp b/lib/waf/build/lib_10/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_5.h" -#include "class_46.h" -#include "class_68.h" -#include "class_38.h" -#include "class_45.h" -#include "class_50.h" -#include "class_87.h" -#include "class_18.h" -#include "class_2.h" -#include "class_19.h" -#include "class_1.h" -#include "class_66.h" -#include "class_44.h" -#include "class_61.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_10/class_0.h b/lib/waf/build/lib_10/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_1.cpp b/lib/waf/build/lib_10/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_59.h" -#include "class_18.h" -#include "class_0.h" -#include "class_69.h" -#include "class_31.h" -#include "class_36.h" -#include "class_22.h" -#include "class_51.h" -#include "class_70.h" -#include "class_57.h" -#include "class_61.h" -#include "class_19.h" -#include "class_58.h" -#include "class_6.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_10/class_1.h b/lib/waf/build/lib_10/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_10.cpp b/lib/waf/build/lib_10/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_10.h" -#include "class_46.h" -#include "class_38.h" -#include "class_70.h" -#include "class_48.h" -#include "class_7.h" -#include "class_84.h" -#include "class_67.h" -#include "class_64.h" -#include "class_37.h" -#include "class_87.h" -#include "class_15.h" -#include "class_60.h" -#include "class_4.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_10/class_10.h b/lib/waf/build/lib_10/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_11.cpp b/lib/waf/build/lib_10/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_74.h" -#include "class_26.h" -#include "class_60.h" -#include "class_63.h" -#include "class_55.h" -#include "class_83.h" -#include "class_65.h" -#include "class_17.h" -#include "class_66.h" -#include "class_41.h" -#include "class_61.h" -#include "class_7.h" -#include "class_52.h" -#include "class_45.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_10/class_11.h b/lib/waf/build/lib_10/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_12.cpp b/lib/waf/build/lib_10/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_78.h" -#include "class_6.h" -#include "class_99.h" -#include "class_22.h" -#include "class_45.h" -#include "class_84.h" -#include "class_25.h" -#include "class_20.h" -#include "class_85.h" -#include "class_31.h" -#include "class_5.h" -#include "class_28.h" -#include "class_44.h" -#include "class_23.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_10/class_12.h b/lib/waf/build/lib_10/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_13.cpp b/lib/waf/build/lib_10/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_10.h" -#include "class_90.h" -#include "class_46.h" -#include "class_36.h" -#include "class_16.h" -#include "class_12.h" -#include "class_45.h" -#include "class_38.h" -#include "class_55.h" -#include "class_4.h" -#include "class_43.h" -#include "class_68.h" -#include "class_49.h" -#include "class_18.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_10/class_13.h b/lib/waf/build/lib_10/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_14.cpp b/lib/waf/build/lib_10/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_82.h" -#include "class_25.h" -#include "class_76.h" -#include "class_92.h" -#include "class_8.h" -#include "class_89.h" -#include "class_66.h" -#include "class_84.h" -#include "class_54.h" -#include "class_5.h" -#include "class_81.h" -#include "class_4.h" -#include "class_77.h" -#include "class_74.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_10/class_14.h b/lib/waf/build/lib_10/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_15.cpp b/lib/waf/build/lib_10/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_97.h" -#include "class_12.h" -#include "class_60.h" -#include "class_21.h" -#include "class_81.h" -#include "class_98.h" -#include "class_43.h" -#include "class_83.h" -#include "class_27.h" -#include "class_99.h" -#include "class_31.h" -#include "class_23.h" -#include "class_14.h" -#include "class_44.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_10/class_15.h b/lib/waf/build/lib_10/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_16.cpp b/lib/waf/build/lib_10/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_35.h" -#include "class_92.h" -#include "class_41.h" -#include "class_94.h" -#include "class_10.h" -#include "class_26.h" -#include "class_34.h" -#include "class_91.h" -#include "class_9.h" -#include "class_42.h" -#include "class_21.h" -#include "class_93.h" -#include "class_55.h" -#include "class_40.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_10/class_16.h b/lib/waf/build/lib_10/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_17.cpp b/lib/waf/build/lib_10/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_82.h" -#include "class_11.h" -#include "class_66.h" -#include "class_17.h" -#include "class_46.h" -#include "class_14.h" -#include "class_18.h" -#include "class_83.h" -#include "class_31.h" -#include "class_65.h" -#include "class_15.h" -#include "class_42.h" -#include "class_13.h" -#include "class_50.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_10/class_17.h b/lib/waf/build/lib_10/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_18.cpp b/lib/waf/build/lib_10/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_15.h" -#include "class_41.h" -#include "class_92.h" -#include "class_12.h" -#include "class_24.h" -#include "class_5.h" -#include "class_80.h" -#include "class_48.h" -#include "class_83.h" -#include "class_9.h" -#include "class_34.h" -#include "class_7.h" -#include "class_53.h" -#include "class_1.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_10/class_18.h b/lib/waf/build/lib_10/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_19.cpp b/lib/waf/build/lib_10/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_57.h" -#include "class_83.h" -#include "class_89.h" -#include "class_33.h" -#include "class_44.h" -#include "class_85.h" -#include "class_24.h" -#include "class_47.h" -#include "class_48.h" -#include "class_70.h" -#include "class_80.h" -#include "class_86.h" -#include "class_12.h" -#include "class_98.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_10/class_19.h b/lib/waf/build/lib_10/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_2.cpp b/lib/waf/build/lib_10/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_30.h" -#include "class_84.h" -#include "class_49.h" -#include "class_0.h" -#include "class_50.h" -#include "class_68.h" -#include "class_54.h" -#include "class_34.h" -#include "class_61.h" -#include "class_44.h" -#include "class_88.h" -#include "class_12.h" -#include "class_93.h" -#include "class_77.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_10/class_2.h b/lib/waf/build/lib_10/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_20.cpp b/lib/waf/build/lib_10/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_62.h" -#include "class_90.h" -#include "class_43.h" -#include "class_11.h" -#include "class_30.h" -#include "class_80.h" -#include "class_1.h" -#include "class_78.h" -#include "class_6.h" -#include "class_49.h" -#include "class_66.h" -#include "class_47.h" -#include "class_83.h" -#include "class_59.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_10/class_20.h b/lib/waf/build/lib_10/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_21.cpp b/lib/waf/build/lib_10/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_20.h" -#include "class_89.h" -#include "class_5.h" -#include "class_26.h" -#include "class_6.h" -#include "class_88.h" -#include "class_42.h" -#include "class_30.h" -#include "class_27.h" -#include "class_95.h" -#include "class_67.h" -#include "class_11.h" -#include "class_52.h" -#include "class_82.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_10/class_21.h b/lib/waf/build/lib_10/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_22.cpp b/lib/waf/build/lib_10/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_74.h" -#include "class_92.h" -#include "class_40.h" -#include "class_49.h" -#include "class_75.h" -#include "class_14.h" -#include "class_6.h" -#include "class_31.h" -#include "class_65.h" -#include "class_73.h" -#include "class_88.h" -#include "class_70.h" -#include "class_52.h" -#include "class_26.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_10/class_22.h b/lib/waf/build/lib_10/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_23.cpp b/lib/waf/build/lib_10/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_66.h" -#include "class_35.h" -#include "class_78.h" -#include "class_38.h" -#include "class_53.h" -#include "class_8.h" -#include "class_88.h" -#include "class_21.h" -#include "class_79.h" -#include "class_77.h" -#include "class_28.h" -#include "class_99.h" -#include "class_41.h" -#include "class_85.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_10/class_23.h b/lib/waf/build/lib_10/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_24.cpp b/lib/waf/build/lib_10/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_73.h" -#include "class_7.h" -#include "class_89.h" -#include "class_80.h" -#include "class_24.h" -#include "class_76.h" -#include "class_97.h" -#include "class_62.h" -#include "class_67.h" -#include "class_72.h" -#include "class_66.h" -#include "class_40.h" -#include "class_29.h" -#include "class_86.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_10/class_24.h b/lib/waf/build/lib_10/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_25.cpp b/lib/waf/build/lib_10/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_11.h" -#include "class_56.h" -#include "class_23.h" -#include "class_86.h" -#include "class_5.h" -#include "class_84.h" -#include "class_73.h" -#include "class_98.h" -#include "class_39.h" -#include "class_1.h" -#include "class_29.h" -#include "class_48.h" -#include "class_53.h" -#include "class_27.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_10/class_25.h b/lib/waf/build/lib_10/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_26.cpp b/lib/waf/build/lib_10/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_50.h" -#include "class_3.h" -#include "class_11.h" -#include "class_92.h" -#include "class_86.h" -#include "class_95.h" -#include "class_70.h" -#include "class_31.h" -#include "class_2.h" -#include "class_71.h" -#include "class_69.h" -#include "class_28.h" -#include "class_61.h" -#include "class_18.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_10/class_26.h b/lib/waf/build/lib_10/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_27.cpp b/lib/waf/build/lib_10/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_27.h" -#include "class_5.h" -#include "class_74.h" -#include "class_3.h" -#include "class_48.h" -#include "class_99.h" -#include "class_18.h" -#include "class_93.h" -#include "class_13.h" -#include "class_42.h" -#include "class_90.h" -#include "class_38.h" -#include "class_10.h" -#include "class_44.h" -#include "class_88.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_10/class_27.h b/lib/waf/build/lib_10/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_28.cpp b/lib/waf/build/lib_10/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_59.h" -#include "class_61.h" -#include "class_54.h" -#include "class_55.h" -#include "class_31.h" -#include "class_93.h" -#include "class_57.h" -#include "class_88.h" -#include "class_43.h" -#include "class_67.h" -#include "class_40.h" -#include "class_36.h" -#include "class_51.h" -#include "class_81.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_10/class_28.h b/lib/waf/build/lib_10/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_29.cpp b/lib/waf/build/lib_10/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_35.h" -#include "class_12.h" -#include "class_56.h" -#include "class_67.h" -#include "class_4.h" -#include "class_46.h" -#include "class_52.h" -#include "class_94.h" -#include "class_33.h" -#include "class_80.h" -#include "class_38.h" -#include "class_47.h" -#include "class_59.h" -#include "class_40.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_10/class_29.h b/lib/waf/build/lib_10/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_3.cpp b/lib/waf/build/lib_10/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_86.h" -#include "class_41.h" -#include "class_96.h" -#include "class_60.h" -#include "class_42.h" -#include "class_92.h" -#include "class_78.h" -#include "class_29.h" -#include "class_54.h" -#include "class_74.h" -#include "class_7.h" -#include "class_6.h" -#include "class_26.h" -#include "class_81.h" -#include "class_75.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_10/class_3.h b/lib/waf/build/lib_10/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_30.cpp b/lib/waf/build/lib_10/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_26.h" -#include "class_80.h" -#include "class_83.h" -#include "class_12.h" -#include "class_37.h" -#include "class_71.h" -#include "class_43.h" -#include "class_59.h" -#include "class_44.h" -#include "class_15.h" -#include "class_39.h" -#include "class_17.h" -#include "class_32.h" -#include "class_91.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_10/class_30.h b/lib/waf/build/lib_10/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_31.cpp b/lib/waf/build/lib_10/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_52.h" -#include "class_84.h" -#include "class_3.h" -#include "class_86.h" -#include "class_9.h" -#include "class_66.h" -#include "class_71.h" -#include "class_28.h" -#include "class_92.h" -#include "class_61.h" -#include "class_39.h" -#include "class_13.h" -#include "class_15.h" -#include "class_27.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_10/class_31.h b/lib/waf/build/lib_10/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_32.cpp b/lib/waf/build/lib_10/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_49.h" -#include "class_38.h" -#include "class_78.h" -#include "class_91.h" -#include "class_22.h" -#include "class_40.h" -#include "class_96.h" -#include "class_97.h" -#include "class_51.h" -#include "class_56.h" -#include "class_81.h" -#include "class_14.h" -#include "class_45.h" -#include "class_98.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_10/class_32.h b/lib/waf/build/lib_10/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_33.cpp b/lib/waf/build/lib_10/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_68.h" -#include "class_44.h" -#include "class_49.h" -#include "class_21.h" -#include "class_76.h" -#include "class_93.h" -#include "class_81.h" -#include "class_9.h" -#include "class_96.h" -#include "class_53.h" -#include "class_12.h" -#include "class_72.h" -#include "class_54.h" -#include "class_25.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_10/class_33.h b/lib/waf/build/lib_10/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_34.cpp b/lib/waf/build/lib_10/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_59.h" -#include "class_87.h" -#include "class_75.h" -#include "class_62.h" -#include "class_57.h" -#include "class_2.h" -#include "class_8.h" -#include "class_11.h" -#include "class_24.h" -#include "class_52.h" -#include "class_56.h" -#include "class_42.h" -#include "class_3.h" -#include "class_76.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_10/class_34.h b/lib/waf/build/lib_10/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_35.cpp b/lib/waf/build/lib_10/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_37.h" -#include "class_26.h" -#include "class_56.h" -#include "class_38.h" -#include "class_58.h" -#include "class_9.h" -#include "class_40.h" -#include "class_10.h" -#include "class_74.h" -#include "class_22.h" -#include "class_73.h" -#include "class_29.h" -#include "class_44.h" -#include "class_34.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_10/class_35.h b/lib/waf/build/lib_10/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_36.cpp b/lib/waf/build/lib_10/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_10.h" -#include "class_12.h" -#include "class_9.h" -#include "class_8.h" -#include "class_26.h" -#include "class_49.h" -#include "class_79.h" -#include "class_6.h" -#include "class_11.h" -#include "class_29.h" -#include "class_61.h" -#include "class_68.h" -#include "class_36.h" -#include "class_94.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_10/class_36.h b/lib/waf/build/lib_10/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_37.cpp b/lib/waf/build/lib_10/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_81.h" -#include "class_59.h" -#include "class_78.h" -#include "class_97.h" -#include "class_51.h" -#include "class_12.h" -#include "class_4.h" -#include "class_84.h" -#include "class_63.h" -#include "class_91.h" -#include "class_6.h" -#include "class_55.h" -#include "class_13.h" -#include "class_72.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_10/class_37.h b/lib/waf/build/lib_10/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_38.cpp b/lib/waf/build/lib_10/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_73.h" -#include "class_16.h" -#include "class_98.h" -#include "class_21.h" -#include "class_52.h" -#include "class_14.h" -#include "class_36.h" -#include "class_12.h" -#include "class_57.h" -#include "class_44.h" -#include "class_22.h" -#include "class_46.h" -#include "class_47.h" -#include "class_88.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_10/class_38.h b/lib/waf/build/lib_10/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_39.cpp b/lib/waf/build/lib_10/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_95.h" -#include "class_72.h" -#include "class_15.h" -#include "class_79.h" -#include "class_74.h" -#include "class_11.h" -#include "class_0.h" -#include "class_55.h" -#include "class_60.h" -#include "class_90.h" -#include "class_76.h" -#include "class_19.h" -#include "class_31.h" -#include "class_30.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_10/class_39.h b/lib/waf/build/lib_10/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_4.cpp b/lib/waf/build/lib_10/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_22.h" -#include "class_20.h" -#include "class_12.h" -#include "class_89.h" -#include "class_16.h" -#include "class_39.h" -#include "class_14.h" -#include "class_0.h" -#include "class_13.h" -#include "class_53.h" -#include "class_8.h" -#include "class_4.h" -#include "class_3.h" -#include "class_36.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_10/class_4.h b/lib/waf/build/lib_10/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_40.cpp b/lib/waf/build/lib_10/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_79.h" -#include "class_3.h" -#include "class_83.h" -#include "class_25.h" -#include "class_38.h" -#include "class_24.h" -#include "class_60.h" -#include "class_39.h" -#include "class_57.h" -#include "class_19.h" -#include "class_98.h" -#include "class_34.h" -#include "class_23.h" -#include "class_84.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_10/class_40.h b/lib/waf/build/lib_10/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_41.cpp b/lib/waf/build/lib_10/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_13.h" -#include "class_48.h" -#include "class_91.h" -#include "class_58.h" -#include "class_14.h" -#include "class_49.h" -#include "class_60.h" -#include "class_96.h" -#include "class_35.h" -#include "class_90.h" -#include "class_52.h" -#include "class_39.h" -#include "class_94.h" -#include "class_22.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_10/class_41.h b/lib/waf/build/lib_10/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_42.cpp b/lib/waf/build/lib_10/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_23.h" -#include "class_34.h" -#include "class_66.h" -#include "class_69.h" -#include "class_59.h" -#include "class_87.h" -#include "class_15.h" -#include "class_83.h" -#include "class_64.h" -#include "class_94.h" -#include "class_86.h" -#include "class_42.h" -#include "class_46.h" -#include "class_40.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_10/class_42.h b/lib/waf/build/lib_10/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_43.cpp b/lib/waf/build/lib_10/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_49.h" -#include "class_51.h" -#include "class_39.h" -#include "class_96.h" -#include "class_66.h" -#include "class_11.h" -#include "class_68.h" -#include "class_22.h" -#include "class_50.h" -#include "class_41.h" -#include "class_10.h" -#include "class_27.h" -#include "class_40.h" -#include "class_45.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_10/class_43.h b/lib/waf/build/lib_10/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_44.cpp b/lib/waf/build/lib_10/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_58.h" -#include "class_9.h" -#include "class_36.h" -#include "class_8.h" -#include "class_53.h" -#include "class_31.h" -#include "class_59.h" -#include "class_34.h" -#include "class_18.h" -#include "class_23.h" -#include "class_57.h" -#include "class_92.h" -#include "class_88.h" -#include "class_3.h" -#include "class_38.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_10/class_44.h b/lib/waf/build/lib_10/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_45.cpp b/lib/waf/build/lib_10/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_31.h" -#include "class_90.h" -#include "class_76.h" -#include "class_58.h" -#include "class_91.h" -#include "class_56.h" -#include "class_55.h" -#include "class_25.h" -#include "class_60.h" -#include "class_20.h" -#include "class_43.h" -#include "class_80.h" -#include "class_79.h" -#include "class_96.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_10/class_45.h b/lib/waf/build/lib_10/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_46.cpp b/lib/waf/build/lib_10/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_14.h" -#include "class_61.h" -#include "class_35.h" -#include "class_92.h" -#include "class_64.h" -#include "class_9.h" -#include "class_51.h" -#include "class_49.h" -#include "class_88.h" -#include "class_95.h" -#include "class_72.h" -#include "class_73.h" -#include "class_60.h" -#include "class_97.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_10/class_46.h b/lib/waf/build/lib_10/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_47.cpp b/lib/waf/build/lib_10/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_6.h" -#include "class_27.h" -#include "class_68.h" -#include "class_53.h" -#include "class_59.h" -#include "class_71.h" -#include "class_10.h" -#include "class_12.h" -#include "class_66.h" -#include "class_82.h" -#include "class_24.h" -#include "class_15.h" -#include "class_23.h" -#include "class_3.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_10/class_47.h b/lib/waf/build/lib_10/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_48.cpp b/lib/waf/build/lib_10/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_57.h" -#include "class_84.h" -#include "class_35.h" -#include "class_50.h" -#include "class_36.h" -#include "class_0.h" -#include "class_19.h" -#include "class_20.h" -#include "class_30.h" -#include "class_96.h" -#include "class_77.h" -#include "class_47.h" -#include "class_24.h" -#include "class_80.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_10/class_48.h b/lib/waf/build/lib_10/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_49.cpp b/lib/waf/build/lib_10/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_24.h" -#include "class_51.h" -#include "class_17.h" -#include "class_0.h" -#include "class_59.h" -#include "class_91.h" -#include "class_90.h" -#include "class_22.h" -#include "class_83.h" -#include "class_30.h" -#include "class_81.h" -#include "class_77.h" -#include "class_37.h" -#include "class_48.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_10/class_49.h b/lib/waf/build/lib_10/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_5.cpp b/lib/waf/build/lib_10/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_98.h" -#include "class_47.h" -#include "class_85.h" -#include "class_35.h" -#include "class_7.h" -#include "class_26.h" -#include "class_44.h" -#include "class_95.h" -#include "class_38.h" -#include "class_11.h" -#include "class_59.h" -#include "class_10.h" -#include "class_25.h" -#include "class_81.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_10/class_5.h b/lib/waf/build/lib_10/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_50.cpp b/lib/waf/build/lib_10/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_31.h" -#include "class_85.h" -#include "class_46.h" -#include "class_93.h" -#include "class_21.h" -#include "class_9.h" -#include "class_98.h" -#include "class_96.h" -#include "class_26.h" -#include "class_58.h" -#include "class_74.h" -#include "class_77.h" -#include "class_89.h" -#include "class_30.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_10/class_50.h b/lib/waf/build/lib_10/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_51.cpp b/lib/waf/build/lib_10/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_6.h" -#include "class_5.h" -#include "class_13.h" -#include "class_9.h" -#include "class_64.h" -#include "class_80.h" -#include "class_25.h" -#include "class_1.h" -#include "class_81.h" -#include "class_0.h" -#include "class_62.h" -#include "class_84.h" -#include "class_34.h" -#include "class_2.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_10/class_51.h b/lib/waf/build/lib_10/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_52.cpp b/lib/waf/build/lib_10/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_71.h" -#include "class_5.h" -#include "class_75.h" -#include "class_47.h" -#include "class_86.h" -#include "class_45.h" -#include "class_87.h" -#include "class_3.h" -#include "class_56.h" -#include "class_90.h" -#include "class_54.h" -#include "class_46.h" -#include "class_89.h" -#include "class_27.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_10/class_52.h b/lib/waf/build/lib_10/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_53.cpp b/lib/waf/build/lib_10/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_41.h" -#include "class_18.h" -#include "class_91.h" -#include "class_73.h" -#include "class_6.h" -#include "class_70.h" -#include "class_35.h" -#include "class_95.h" -#include "class_54.h" -#include "class_0.h" -#include "class_8.h" -#include "class_36.h" -#include "class_42.h" -#include "class_15.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_10/class_53.h b/lib/waf/build/lib_10/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_54.cpp b/lib/waf/build/lib_10/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_37.h" -#include "class_31.h" -#include "class_11.h" -#include "class_98.h" -#include "class_33.h" -#include "class_76.h" -#include "class_67.h" -#include "class_70.h" -#include "class_73.h" -#include "class_71.h" -#include "class_68.h" -#include "class_85.h" -#include "class_99.h" -#include "class_97.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_10/class_54.h b/lib/waf/build/lib_10/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_55.cpp b/lib/waf/build/lib_10/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_32.h" -#include "class_89.h" -#include "class_5.h" -#include "class_65.h" -#include "class_17.h" -#include "class_42.h" -#include "class_8.h" -#include "class_53.h" -#include "class_4.h" -#include "class_15.h" -#include "class_81.h" -#include "class_69.h" -#include "class_35.h" -#include "class_71.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_10/class_55.h b/lib/waf/build/lib_10/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_56.cpp b/lib/waf/build/lib_10/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_78.h" -#include "class_86.h" -#include "class_68.h" -#include "class_88.h" -#include "class_95.h" -#include "class_85.h" -#include "class_87.h" -#include "class_96.h" -#include "class_63.h" -#include "class_47.h" -#include "class_79.h" -#include "class_54.h" -#include "class_71.h" -#include "class_10.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_10/class_56.h b/lib/waf/build/lib_10/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_57.cpp b/lib/waf/build/lib_10/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_83.h" -#include "class_12.h" -#include "class_62.h" -#include "class_37.h" -#include "class_24.h" -#include "class_46.h" -#include "class_75.h" -#include "class_66.h" -#include "class_9.h" -#include "class_43.h" -#include "class_68.h" -#include "class_10.h" -#include "class_39.h" -#include "class_50.h" -#include "class_42.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_10/class_57.h b/lib/waf/build/lib_10/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_58.cpp b/lib/waf/build/lib_10/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_1.h" -#include "class_71.h" -#include "class_94.h" -#include "class_34.h" -#include "class_74.h" -#include "class_4.h" -#include "class_5.h" -#include "class_12.h" -#include "class_84.h" -#include "class_32.h" -#include "class_48.h" -#include "class_83.h" -#include "class_86.h" -#include "class_47.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_10/class_58.h b/lib/waf/build/lib_10/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_59.cpp b/lib/waf/build/lib_10/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_49.h" -#include "class_87.h" -#include "class_27.h" -#include "class_33.h" -#include "class_30.h" -#include "class_46.h" -#include "class_84.h" -#include "class_79.h" -#include "class_97.h" -#include "class_52.h" -#include "class_90.h" -#include "class_34.h" -#include "class_1.h" -#include "class_73.h" -#include "class_64.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_10/class_59.h b/lib/waf/build/lib_10/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_6.cpp b/lib/waf/build/lib_10/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_46.h" -#include "class_55.h" -#include "class_79.h" -#include "class_90.h" -#include "class_88.h" -#include "class_2.h" -#include "class_93.h" -#include "class_54.h" -#include "class_15.h" -#include "class_6.h" -#include "class_69.h" -#include "class_14.h" -#include "class_8.h" -#include "class_10.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_10/class_6.h b/lib/waf/build/lib_10/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_60.cpp b/lib/waf/build/lib_10/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_71.h" -#include "class_10.h" -#include "class_80.h" -#include "class_62.h" -#include "class_4.h" -#include "class_63.h" -#include "class_16.h" -#include "class_52.h" -#include "class_30.h" -#include "class_45.h" -#include "class_3.h" -#include "class_39.h" -#include "class_78.h" -#include "class_28.h" -#include "class_65.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_10/class_60.h b/lib/waf/build/lib_10/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_61.cpp b/lib/waf/build/lib_10/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_9.h" -#include "class_38.h" -#include "class_47.h" -#include "class_60.h" -#include "class_95.h" -#include "class_85.h" -#include "class_8.h" -#include "class_71.h" -#include "class_99.h" -#include "class_43.h" -#include "class_34.h" -#include "class_13.h" -#include "class_25.h" -#include "class_77.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_10/class_61.h b/lib/waf/build/lib_10/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_62.cpp b/lib/waf/build/lib_10/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_54.h" -#include "class_19.h" -#include "class_22.h" -#include "class_13.h" -#include "class_38.h" -#include "class_39.h" -#include "class_56.h" -#include "class_3.h" -#include "class_2.h" -#include "class_40.h" -#include "class_59.h" -#include "class_55.h" -#include "class_31.h" -#include "class_65.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_10/class_62.h b/lib/waf/build/lib_10/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_63.cpp b/lib/waf/build/lib_10/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_92.h" -#include "class_88.h" -#include "class_64.h" -#include "class_35.h" -#include "class_53.h" -#include "class_23.h" -#include "class_93.h" -#include "class_20.h" -#include "class_50.h" -#include "class_51.h" -#include "class_74.h" -#include "class_96.h" -#include "class_42.h" -#include "class_47.h" -#include "class_6.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_10/class_63.h b/lib/waf/build/lib_10/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_64.cpp b/lib/waf/build/lib_10/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_59.h" -#include "class_87.h" -#include "class_12.h" -#include "class_25.h" -#include "class_65.h" -#include "class_48.h" -#include "class_15.h" -#include "class_17.h" -#include "class_50.h" -#include "class_32.h" -#include "class_47.h" -#include "class_29.h" -#include "class_58.h" -#include "class_53.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_10/class_64.h b/lib/waf/build/lib_10/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_65.cpp b/lib/waf/build/lib_10/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_81.h" -#include "class_33.h" -#include "class_49.h" -#include "class_67.h" -#include "class_88.h" -#include "class_52.h" -#include "class_22.h" -#include "class_59.h" -#include "class_86.h" -#include "class_99.h" -#include "class_76.h" -#include "class_69.h" -#include "class_19.h" -#include "class_23.h" -#include "class_6.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_10/class_65.h b/lib/waf/build/lib_10/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_66.cpp b/lib/waf/build/lib_10/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_19.h" -#include "class_40.h" -#include "class_91.h" -#include "class_36.h" -#include "class_18.h" -#include "class_25.h" -#include "class_47.h" -#include "class_58.h" -#include "class_43.h" -#include "class_79.h" -#include "class_33.h" -#include "class_60.h" -#include "class_11.h" -#include "class_48.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_10/class_66.h b/lib/waf/build/lib_10/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_67.cpp b/lib/waf/build/lib_10/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_10.h" -#include "class_85.h" -#include "class_19.h" -#include "class_37.h" -#include "class_54.h" -#include "class_80.h" -#include "class_46.h" -#include "class_57.h" -#include "class_48.h" -#include "class_38.h" -#include "class_24.h" -#include "class_75.h" -#include "class_66.h" -#include "class_15.h" -#include "class_95.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_10/class_67.h b/lib/waf/build/lib_10/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_68.cpp b/lib/waf/build/lib_10/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_27.h" -#include "class_21.h" -#include "class_20.h" -#include "class_59.h" -#include "class_36.h" -#include "class_99.h" -#include "class_35.h" -#include "class_17.h" -#include "class_1.h" -#include "class_26.h" -#include "class_87.h" -#include "class_25.h" -#include "class_6.h" -#include "class_93.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_10/class_68.h b/lib/waf/build/lib_10/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_69.cpp b/lib/waf/build/lib_10/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_60.h" -#include "class_22.h" -#include "class_74.h" -#include "class_29.h" -#include "class_43.h" -#include "class_41.h" -#include "class_85.h" -#include "class_92.h" -#include "class_39.h" -#include "class_97.h" -#include "class_52.h" -#include "class_33.h" -#include "class_40.h" -#include "class_71.h" -#include "class_88.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_10/class_69.h b/lib/waf/build/lib_10/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_7.cpp b/lib/waf/build/lib_10/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_8.h" -#include "class_15.h" -#include "class_57.h" -#include "class_97.h" -#include "class_7.h" -#include "class_92.h" -#include "class_51.h" -#include "class_66.h" -#include "class_3.h" -#include "class_74.h" -#include "class_82.h" -#include "class_70.h" -#include "class_83.h" -#include "class_88.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_10/class_7.h b/lib/waf/build/lib_10/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_70.cpp b/lib/waf/build/lib_10/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_15.h" -#include "class_59.h" -#include "class_46.h" -#include "class_11.h" -#include "class_58.h" -#include "class_20.h" -#include "class_18.h" -#include "class_30.h" -#include "class_73.h" -#include "class_8.h" -#include "class_4.h" -#include "class_70.h" -#include "class_93.h" -#include "class_43.h" -#include "class_76.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_10/class_70.h b/lib/waf/build/lib_10/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_71.cpp b/lib/waf/build/lib_10/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_6.h" -#include "class_70.h" -#include "class_11.h" -#include "class_31.h" -#include "class_71.h" -#include "class_13.h" -#include "class_53.h" -#include "class_14.h" -#include "class_20.h" -#include "class_36.h" -#include "class_73.h" -#include "class_61.h" -#include "class_8.h" -#include "class_93.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_10/class_71.h b/lib/waf/build/lib_10/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_72.cpp b/lib/waf/build/lib_10/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_17.h" -#include "class_93.h" -#include "class_88.h" -#include "class_22.h" -#include "class_14.h" -#include "class_64.h" -#include "class_96.h" -#include "class_87.h" -#include "class_37.h" -#include "class_7.h" -#include "class_82.h" -#include "class_13.h" -#include "class_34.h" -#include "class_54.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_10/class_72.h b/lib/waf/build/lib_10/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_73.cpp b/lib/waf/build/lib_10/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_53.h" -#include "class_93.h" -#include "class_18.h" -#include "class_77.h" -#include "class_20.h" -#include "class_16.h" -#include "class_55.h" -#include "class_37.h" -#include "class_28.h" -#include "class_48.h" -#include "class_56.h" -#include "class_26.h" -#include "class_32.h" -#include "class_31.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_10/class_73.h b/lib/waf/build/lib_10/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_74.cpp b/lib/waf/build/lib_10/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_0.h" -#include "class_75.h" -#include "class_85.h" -#include "class_20.h" -#include "class_22.h" -#include "class_59.h" -#include "class_53.h" -#include "class_48.h" -#include "class_99.h" -#include "class_32.h" -#include "class_30.h" -#include "class_35.h" -#include "class_54.h" -#include "class_89.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_10/class_74.h b/lib/waf/build/lib_10/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_75.cpp b/lib/waf/build/lib_10/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_23.h" -#include "class_39.h" -#include "class_31.h" -#include "class_96.h" -#include "class_34.h" -#include "class_87.h" -#include "class_78.h" -#include "class_79.h" -#include "class_90.h" -#include "class_14.h" -#include "class_70.h" -#include "class_24.h" -#include "class_92.h" -#include "class_60.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_10/class_75.h b/lib/waf/build/lib_10/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_76.cpp b/lib/waf/build/lib_10/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_65.h" -#include "class_32.h" -#include "class_2.h" -#include "class_86.h" -#include "class_36.h" -#include "class_83.h" -#include "class_75.h" -#include "class_70.h" -#include "class_54.h" -#include "class_29.h" -#include "class_71.h" -#include "class_79.h" -#include "class_5.h" -#include "class_26.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_10/class_76.h b/lib/waf/build/lib_10/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_77.cpp b/lib/waf/build/lib_10/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_70.h" -#include "class_23.h" -#include "class_71.h" -#include "class_27.h" -#include "class_5.h" -#include "class_87.h" -#include "class_99.h" -#include "class_29.h" -#include "class_19.h" -#include "class_74.h" -#include "class_10.h" -#include "class_85.h" -#include "class_14.h" -#include "class_94.h" -#include "class_75.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_10/class_77.h b/lib/waf/build/lib_10/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_78.cpp b/lib/waf/build/lib_10/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_88.h" -#include "class_15.h" -#include "class_54.h" -#include "class_53.h" -#include "class_47.h" -#include "class_75.h" -#include "class_59.h" -#include "class_9.h" -#include "class_18.h" -#include "class_97.h" -#include "class_48.h" -#include "class_77.h" -#include "class_91.h" -#include "class_34.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_10/class_78.h b/lib/waf/build/lib_10/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_79.cpp b/lib/waf/build/lib_10/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_47.h" -#include "class_83.h" -#include "class_58.h" -#include "class_92.h" -#include "class_82.h" -#include "class_13.h" -#include "class_72.h" -#include "class_11.h" -#include "class_65.h" -#include "class_19.h" -#include "class_57.h" -#include "class_44.h" -#include "class_3.h" -#include "class_98.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_10/class_79.h b/lib/waf/build/lib_10/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_8.cpp b/lib/waf/build/lib_10/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_44.h" -#include "class_89.h" -#include "class_50.h" -#include "class_71.h" -#include "class_60.h" -#include "class_68.h" -#include "class_30.h" -#include "class_73.h" -#include "class_20.h" -#include "class_52.h" -#include "class_21.h" -#include "class_99.h" -#include "class_35.h" -#include "class_91.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_10/class_8.h b/lib/waf/build/lib_10/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_80.cpp b/lib/waf/build/lib_10/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_88.h" -#include "class_61.h" -#include "class_60.h" -#include "class_63.h" -#include "class_78.h" -#include "class_50.h" -#include "class_81.h" -#include "class_83.h" -#include "class_21.h" -#include "class_94.h" -#include "class_3.h" -#include "class_34.h" -#include "class_37.h" -#include "class_76.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_10/class_80.h b/lib/waf/build/lib_10/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_81.cpp b/lib/waf/build/lib_10/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_1.h" -#include "class_77.h" -#include "class_49.h" -#include "class_28.h" -#include "class_66.h" -#include "class_69.h" -#include "class_83.h" -#include "class_13.h" -#include "class_38.h" -#include "class_51.h" -#include "class_81.h" -#include "class_15.h" -#include "class_47.h" -#include "class_72.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_10/class_81.h b/lib/waf/build/lib_10/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_82.cpp b/lib/waf/build/lib_10/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_92.h" -#include "class_85.h" -#include "class_46.h" -#include "class_14.h" -#include "class_90.h" -#include "class_75.h" -#include "class_3.h" -#include "class_52.h" -#include "class_32.h" -#include "class_24.h" -#include "class_53.h" -#include "class_67.h" -#include "class_74.h" -#include "class_61.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_10/class_82.h b/lib/waf/build/lib_10/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_83.cpp b/lib/waf/build/lib_10/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_63.h" -#include "class_40.h" -#include "class_5.h" -#include "class_35.h" -#include "class_84.h" -#include "class_43.h" -#include "class_79.h" -#include "class_93.h" -#include "class_24.h" -#include "class_86.h" -#include "class_69.h" -#include "class_47.h" -#include "class_91.h" -#include "class_4.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_10/class_83.h b/lib/waf/build/lib_10/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_84.cpp b/lib/waf/build/lib_10/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_69.h" -#include "class_42.h" -#include "class_39.h" -#include "class_59.h" -#include "class_91.h" -#include "class_80.h" -#include "class_32.h" -#include "class_15.h" -#include "class_33.h" -#include "class_85.h" -#include "class_41.h" -#include "class_2.h" -#include "class_73.h" -#include "class_56.h" -#include "class_64.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_10/class_84.h b/lib/waf/build/lib_10/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_85.cpp b/lib/waf/build/lib_10/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_66.h" -#include "class_15.h" -#include "class_42.h" -#include "class_36.h" -#include "class_41.h" -#include "class_6.h" -#include "class_32.h" -#include "class_12.h" -#include "class_73.h" -#include "class_71.h" -#include "class_68.h" -#include "class_29.h" -#include "class_43.h" -#include "class_1.h" -#include "class_96.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_10/class_85.h b/lib/waf/build/lib_10/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_86.cpp b/lib/waf/build/lib_10/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_55.h" -#include "class_13.h" -#include "class_78.h" -#include "class_59.h" -#include "class_54.h" -#include "class_32.h" -#include "class_8.h" -#include "class_6.h" -#include "class_86.h" -#include "class_44.h" -#include "class_63.h" -#include "class_61.h" -#include "class_12.h" -#include "class_91.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_10/class_86.h b/lib/waf/build/lib_10/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_87.cpp b/lib/waf/build/lib_10/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_45.h" -#include "class_76.h" -#include "class_96.h" -#include "class_21.h" -#include "class_47.h" -#include "class_16.h" -#include "class_86.h" -#include "class_55.h" -#include "class_19.h" -#include "class_5.h" -#include "class_30.h" -#include "class_51.h" -#include "class_20.h" -#include "class_41.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_10/class_87.h b/lib/waf/build/lib_10/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_88.cpp b/lib/waf/build/lib_10/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_55.h" -#include "class_38.h" -#include "class_64.h" -#include "class_44.h" -#include "class_91.h" -#include "class_36.h" -#include "class_58.h" -#include "class_3.h" -#include "class_45.h" -#include "class_39.h" -#include "class_33.h" -#include "class_6.h" -#include "class_71.h" -#include "class_14.h" -#include "class_76.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_10/class_88.h b/lib/waf/build/lib_10/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_89.cpp b/lib/waf/build/lib_10/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_77.h" -#include "class_28.h" -#include "class_80.h" -#include "class_2.h" -#include "class_52.h" -#include "class_1.h" -#include "class_18.h" -#include "class_74.h" -#include "class_33.h" -#include "class_14.h" -#include "class_79.h" -#include "class_43.h" -#include "class_58.h" -#include "class_84.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_10/class_89.h b/lib/waf/build/lib_10/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_9.cpp b/lib/waf/build/lib_10/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_39.h" -#include "class_87.h" -#include "class_46.h" -#include "class_2.h" -#include "class_65.h" -#include "class_93.h" -#include "class_5.h" -#include "class_66.h" -#include "class_36.h" -#include "class_23.h" -#include "class_91.h" -#include "class_90.h" -#include "class_96.h" -#include "class_13.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_10/class_9.h b/lib/waf/build/lib_10/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_90.cpp b/lib/waf/build/lib_10/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_67.h" -#include "class_73.h" -#include "class_95.h" -#include "class_49.h" -#include "class_26.h" -#include "class_92.h" -#include "class_5.h" -#include "class_76.h" -#include "class_53.h" -#include "class_16.h" -#include "class_81.h" -#include "class_80.h" -#include "class_63.h" -#include "class_84.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_10/class_90.h b/lib/waf/build/lib_10/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_91.cpp b/lib/waf/build/lib_10/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_4.h" -#include "class_24.h" -#include "class_14.h" -#include "class_22.h" -#include "class_63.h" -#include "class_16.h" -#include "class_10.h" -#include "class_38.h" -#include "class_73.h" -#include "class_56.h" -#include "class_35.h" -#include "class_80.h" -#include "class_42.h" -#include "class_72.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_10/class_91.h b/lib/waf/build/lib_10/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_92.cpp b/lib/waf/build/lib_10/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_86.h" -#include "class_85.h" -#include "class_8.h" -#include "class_49.h" -#include "class_61.h" -#include "class_66.h" -#include "class_42.h" -#include "class_67.h" -#include "class_17.h" -#include "class_16.h" -#include "class_30.h" -#include "class_97.h" -#include "class_96.h" -#include "class_54.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_10/class_92.h b/lib/waf/build/lib_10/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_93.cpp b/lib/waf/build/lib_10/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_4.h" -#include "class_95.h" -#include "class_0.h" -#include "class_1.h" -#include "class_85.h" -#include "class_25.h" -#include "class_30.h" -#include "class_93.h" -#include "class_54.h" -#include "class_78.h" -#include "class_91.h" -#include "class_99.h" -#include "class_52.h" -#include "class_33.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_10/class_93.h b/lib/waf/build/lib_10/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_94.cpp b/lib/waf/build/lib_10/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_43.h" -#include "class_84.h" -#include "class_62.h" -#include "class_32.h" -#include "class_86.h" -#include "class_51.h" -#include "class_11.h" -#include "class_6.h" -#include "class_90.h" -#include "class_44.h" -#include "class_67.h" -#include "class_2.h" -#include "class_66.h" -#include "class_75.h" -#include "class_64.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_10/class_94.h b/lib/waf/build/lib_10/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_95.cpp b/lib/waf/build/lib_10/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_44.h" -#include "class_31.h" -#include "class_25.h" -#include "class_81.h" -#include "class_71.h" -#include "class_92.h" -#include "class_59.h" -#include "class_27.h" -#include "class_46.h" -#include "class_10.h" -#include "class_91.h" -#include "class_93.h" -#include "class_52.h" -#include "class_39.h" -#include "class_95.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_10/class_95.h b/lib/waf/build/lib_10/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_96.cpp b/lib/waf/build/lib_10/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_98.h" -#include "class_23.h" -#include "class_91.h" -#include "class_69.h" -#include "class_90.h" -#include "class_70.h" -#include "class_51.h" -#include "class_82.h" -#include "class_39.h" -#include "class_13.h" -#include "class_76.h" -#include "class_99.h" -#include "class_42.h" -#include "class_89.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_10/class_96.h b/lib/waf/build/lib_10/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_97.cpp b/lib/waf/build/lib_10/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_86.h" -#include "class_71.h" -#include "class_61.h" -#include "class_45.h" -#include "class_33.h" -#include "class_21.h" -#include "class_30.h" -#include "class_49.h" -#include "class_82.h" -#include "class_65.h" -#include "class_17.h" -#include "class_13.h" -#include "class_76.h" -#include "class_39.h" -#include "class_22.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_10/class_97.h b/lib/waf/build/lib_10/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_98.cpp b/lib/waf/build/lib_10/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_31.h" -#include "class_91.h" -#include "class_19.h" -#include "class_92.h" -#include "class_80.h" -#include "class_39.h" -#include "class_65.h" -#include "class_69.h" -#include "class_99.h" -#include "class_42.h" -#include "class_87.h" -#include "class_89.h" -#include "class_86.h" -#include "class_27.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_10/class_98.h b/lib/waf/build/lib_10/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_10/class_99.cpp b/lib/waf/build/lib_10/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_10/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_65.h" -#include "class_29.h" -#include "class_6.h" -#include "class_37.h" -#include "class_16.h" -#include "class_31.h" -#include "class_62.h" -#include "class_88.h" -#include "class_98.h" -#include "class_28.h" -#include "class_7.h" -#include "class_55.h" -#include "class_14.h" -#include "class_90.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_10/class_99.h b/lib/waf/build/lib_10/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_10/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_11/Makefile b/lib/waf/build/lib_11/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_11/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_11.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_11/Makefile.am b/lib/waf/build/lib_11/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_11/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib11.la -lib11_la_SOURCES = lib_11/class_0.cpp lib_11/class_1.cpp lib_11/class_2.cpp lib_11/class_3.cpp lib_11/class_4.cpp lib_11/class_5.cpp lib_11/class_6.cpp lib_11/class_7.cpp lib_11/class_8.cpp lib_11/class_9.cpp lib_11/class_10.cpp lib_11/class_11.cpp lib_11/class_12.cpp lib_11/class_13.cpp lib_11/class_14.cpp lib_11/class_15.cpp lib_11/class_16.cpp lib_11/class_17.cpp lib_11/class_18.cpp lib_11/class_19.cpp lib_11/class_20.cpp lib_11/class_21.cpp lib_11/class_22.cpp lib_11/class_23.cpp lib_11/class_24.cpp lib_11/class_25.cpp lib_11/class_26.cpp lib_11/class_27.cpp lib_11/class_28.cpp lib_11/class_29.cpp lib_11/class_30.cpp lib_11/class_31.cpp lib_11/class_32.cpp lib_11/class_33.cpp lib_11/class_34.cpp lib_11/class_35.cpp lib_11/class_36.cpp lib_11/class_37.cpp lib_11/class_38.cpp lib_11/class_39.cpp lib_11/class_40.cpp lib_11/class_41.cpp lib_11/class_42.cpp lib_11/class_43.cpp lib_11/class_44.cpp lib_11/class_45.cpp lib_11/class_46.cpp lib_11/class_47.cpp lib_11/class_48.cpp lib_11/class_49.cpp lib_11/class_50.cpp lib_11/class_51.cpp lib_11/class_52.cpp lib_11/class_53.cpp lib_11/class_54.cpp lib_11/class_55.cpp lib_11/class_56.cpp lib_11/class_57.cpp lib_11/class_58.cpp lib_11/class_59.cpp lib_11/class_60.cpp lib_11/class_61.cpp lib_11/class_62.cpp lib_11/class_63.cpp lib_11/class_64.cpp lib_11/class_65.cpp lib_11/class_66.cpp lib_11/class_67.cpp lib_11/class_68.cpp lib_11/class_69.cpp lib_11/class_70.cpp lib_11/class_71.cpp lib_11/class_72.cpp lib_11/class_73.cpp lib_11/class_74.cpp lib_11/class_75.cpp lib_11/class_76.cpp lib_11/class_77.cpp lib_11/class_78.cpp lib_11/class_79.cpp lib_11/class_80.cpp lib_11/class_81.cpp lib_11/class_82.cpp lib_11/class_83.cpp lib_11/class_84.cpp lib_11/class_85.cpp lib_11/class_86.cpp lib_11/class_87.cpp lib_11/class_88.cpp lib_11/class_89.cpp lib_11/class_90.cpp lib_11/class_91.cpp lib_11/class_92.cpp lib_11/class_93.cpp lib_11/class_94.cpp lib_11/class_95.cpp lib_11/class_96.cpp lib_11/class_97.cpp lib_11/class_98.cpp lib_11/class_99.cpp diff --git a/lib/waf/build/lib_11/SConscript b/lib/waf/build/lib_11/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_11/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_11", list) - diff --git a/lib/waf/build/lib_11/class_0.cpp b/lib/waf/build/lib_11/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_95.h" -#include "class_46.h" -#include "class_28.h" -#include "class_30.h" -#include "class_66.h" -#include "class_39.h" -#include "class_48.h" -#include "class_32.h" -#include "class_96.h" -#include "class_11.h" -#include "class_19.h" -#include "class_67.h" -#include "class_97.h" -#include "class_31.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_11/class_0.h b/lib/waf/build/lib_11/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_1.cpp b/lib/waf/build/lib_11/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_35.h" -#include "class_70.h" -#include "class_83.h" -#include "class_60.h" -#include "class_54.h" -#include "class_3.h" -#include "class_91.h" -#include "class_8.h" -#include "class_62.h" -#include "class_59.h" -#include "class_76.h" -#include "class_68.h" -#include "class_52.h" -#include "class_66.h" -#include "class_7.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_11/class_1.h b/lib/waf/build/lib_11/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_10.cpp b/lib/waf/build/lib_11/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_55.h" -#include "class_42.h" -#include "class_16.h" -#include "class_65.h" -#include "class_98.h" -#include "class_61.h" -#include "class_43.h" -#include "class_66.h" -#include "class_59.h" -#include "class_58.h" -#include "class_7.h" -#include "class_53.h" -#include "class_88.h" -#include "class_62.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_11/class_10.h b/lib/waf/build/lib_11/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_11.cpp b/lib/waf/build/lib_11/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_56.h" -#include "class_28.h" -#include "class_2.h" -#include "class_27.h" -#include "class_93.h" -#include "class_40.h" -#include "class_31.h" -#include "class_82.h" -#include "class_26.h" -#include "class_23.h" -#include "class_58.h" -#include "class_65.h" -#include "class_37.h" -#include "class_35.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_11/class_11.h b/lib/waf/build/lib_11/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_12.cpp b/lib/waf/build/lib_11/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_34.h" -#include "class_36.h" -#include "class_30.h" -#include "class_86.h" -#include "class_33.h" -#include "class_98.h" -#include "class_91.h" -#include "class_49.h" -#include "class_47.h" -#include "class_52.h" -#include "class_73.h" -#include "class_41.h" -#include "class_70.h" -#include "class_23.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_11/class_12.h b/lib/waf/build/lib_11/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_13.cpp b/lib/waf/build/lib_11/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_45.h" -#include "class_66.h" -#include "class_71.h" -#include "class_36.h" -#include "class_70.h" -#include "class_89.h" -#include "class_21.h" -#include "class_3.h" -#include "class_93.h" -#include "class_22.h" -#include "class_27.h" -#include "class_51.h" -#include "class_84.h" -#include "class_37.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_11/class_13.h b/lib/waf/build/lib_11/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_14.cpp b/lib/waf/build/lib_11/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_97.h" -#include "class_67.h" -#include "class_55.h" -#include "class_43.h" -#include "class_38.h" -#include "class_71.h" -#include "class_86.h" -#include "class_10.h" -#include "class_59.h" -#include "class_90.h" -#include "class_16.h" -#include "class_48.h" -#include "class_78.h" -#include "class_13.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_11/class_14.h b/lib/waf/build/lib_11/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_15.cpp b/lib/waf/build/lib_11/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_17.h" -#include "class_88.h" -#include "class_53.h" -#include "class_77.h" -#include "class_87.h" -#include "class_62.h" -#include "class_36.h" -#include "class_11.h" -#include "class_73.h" -#include "class_38.h" -#include "class_13.h" -#include "class_55.h" -#include "class_4.h" -#include "class_7.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_11/class_15.h b/lib/waf/build/lib_11/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_16.cpp b/lib/waf/build/lib_11/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_74.h" -#include "class_42.h" -#include "class_46.h" -#include "class_55.h" -#include "class_27.h" -#include "class_79.h" -#include "class_98.h" -#include "class_20.h" -#include "class_96.h" -#include "class_73.h" -#include "class_36.h" -#include "class_52.h" -#include "class_9.h" -#include "class_40.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_11/class_16.h b/lib/waf/build/lib_11/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_17.cpp b/lib/waf/build/lib_11/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_58.h" -#include "class_62.h" -#include "class_24.h" -#include "class_31.h" -#include "class_65.h" -#include "class_28.h" -#include "class_95.h" -#include "class_40.h" -#include "class_68.h" -#include "class_83.h" -#include "class_45.h" -#include "class_35.h" -#include "class_84.h" -#include "class_8.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_11/class_17.h b/lib/waf/build/lib_11/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_18.cpp b/lib/waf/build/lib_11/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_48.h" -#include "class_12.h" -#include "class_55.h" -#include "class_39.h" -#include "class_27.h" -#include "class_98.h" -#include "class_7.h" -#include "class_42.h" -#include "class_56.h" -#include "class_79.h" -#include "class_84.h" -#include "class_8.h" -#include "class_20.h" -#include "class_57.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_11/class_18.h b/lib/waf/build/lib_11/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_19.cpp b/lib/waf/build/lib_11/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_15.h" -#include "class_1.h" -#include "class_99.h" -#include "class_7.h" -#include "class_39.h" -#include "class_66.h" -#include "class_73.h" -#include "class_75.h" -#include "class_22.h" -#include "class_56.h" -#include "class_76.h" -#include "class_91.h" -#include "class_27.h" -#include "class_34.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_11/class_19.h b/lib/waf/build/lib_11/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_2.cpp b/lib/waf/build/lib_11/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_49.h" -#include "class_47.h" -#include "class_9.h" -#include "class_62.h" -#include "class_37.h" -#include "class_13.h" -#include "class_44.h" -#include "class_98.h" -#include "class_99.h" -#include "class_97.h" -#include "class_88.h" -#include "class_95.h" -#include "class_16.h" -#include "class_79.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_11/class_2.h b/lib/waf/build/lib_11/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_20.cpp b/lib/waf/build/lib_11/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_30.h" -#include "class_6.h" -#include "class_53.h" -#include "class_81.h" -#include "class_87.h" -#include "class_54.h" -#include "class_18.h" -#include "class_68.h" -#include "class_44.h" -#include "class_64.h" -#include "class_77.h" -#include "class_91.h" -#include "class_93.h" -#include "class_37.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_11/class_20.h b/lib/waf/build/lib_11/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_21.cpp b/lib/waf/build/lib_11/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_59.h" -#include "class_70.h" -#include "class_40.h" -#include "class_94.h" -#include "class_39.h" -#include "class_76.h" -#include "class_6.h" -#include "class_74.h" -#include "class_86.h" -#include "class_72.h" -#include "class_91.h" -#include "class_37.h" -#include "class_63.h" -#include "class_92.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_11/class_21.h b/lib/waf/build/lib_11/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_22.cpp b/lib/waf/build/lib_11/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_79.h" -#include "class_74.h" -#include "class_95.h" -#include "class_28.h" -#include "class_44.h" -#include "class_6.h" -#include "class_39.h" -#include "class_88.h" -#include "class_90.h" -#include "class_37.h" -#include "class_27.h" -#include "class_5.h" -#include "class_53.h" -#include "class_76.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_11/class_22.h b/lib/waf/build/lib_11/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_23.cpp b/lib/waf/build/lib_11/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_85.h" -#include "class_24.h" -#include "class_17.h" -#include "class_88.h" -#include "class_89.h" -#include "class_51.h" -#include "class_53.h" -#include "class_6.h" -#include "class_66.h" -#include "class_71.h" -#include "class_28.h" -#include "class_9.h" -#include "class_70.h" -#include "class_54.h" -#include "class_96.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_11/class_23.h b/lib/waf/build/lib_11/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_24.cpp b/lib/waf/build/lib_11/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_42.h" -#include "class_47.h" -#include "class_9.h" -#include "class_87.h" -#include "class_51.h" -#include "class_94.h" -#include "class_34.h" -#include "class_16.h" -#include "class_10.h" -#include "class_5.h" -#include "class_60.h" -#include "class_19.h" -#include "class_22.h" -#include "class_63.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_11/class_24.h b/lib/waf/build/lib_11/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_25.cpp b/lib/waf/build/lib_11/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_45.h" -#include "class_34.h" -#include "class_90.h" -#include "class_40.h" -#include "class_70.h" -#include "class_33.h" -#include "class_84.h" -#include "class_99.h" -#include "class_37.h" -#include "class_82.h" -#include "class_56.h" -#include "class_2.h" -#include "class_23.h" -#include "class_9.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_11/class_25.h b/lib/waf/build/lib_11/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_26.cpp b/lib/waf/build/lib_11/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_55.h" -#include "class_61.h" -#include "class_3.h" -#include "class_75.h" -#include "class_89.h" -#include "class_19.h" -#include "class_71.h" -#include "class_59.h" -#include "class_16.h" -#include "class_64.h" -#include "class_9.h" -#include "class_42.h" -#include "class_52.h" -#include "class_56.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_11/class_26.h b/lib/waf/build/lib_11/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_27.cpp b/lib/waf/build/lib_11/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_70.h" -#include "class_94.h" -#include "class_44.h" -#include "class_13.h" -#include "class_91.h" -#include "class_40.h" -#include "class_17.h" -#include "class_96.h" -#include "class_21.h" -#include "class_33.h" -#include "class_55.h" -#include "class_75.h" -#include "class_47.h" -#include "class_68.h" -#include "class_95.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_11/class_27.h b/lib/waf/build/lib_11/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_28.cpp b/lib/waf/build/lib_11/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_70.h" -#include "class_19.h" -#include "class_57.h" -#include "class_36.h" -#include "class_6.h" -#include "class_45.h" -#include "class_47.h" -#include "class_8.h" -#include "class_4.h" -#include "class_20.h" -#include "class_78.h" -#include "class_17.h" -#include "class_12.h" -#include "class_30.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_11/class_28.h b/lib/waf/build/lib_11/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_29.cpp b/lib/waf/build/lib_11/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_25.h" -#include "class_92.h" -#include "class_86.h" -#include "class_74.h" -#include "class_97.h" -#include "class_11.h" -#include "class_48.h" -#include "class_80.h" -#include "class_94.h" -#include "class_54.h" -#include "class_56.h" -#include "class_39.h" -#include "class_42.h" -#include "class_82.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_11/class_29.h b/lib/waf/build/lib_11/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_3.cpp b/lib/waf/build/lib_11/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_15.h" -#include "class_1.h" -#include "class_13.h" -#include "class_25.h" -#include "class_5.h" -#include "class_28.h" -#include "class_92.h" -#include "class_19.h" -#include "class_52.h" -#include "class_51.h" -#include "class_84.h" -#include "class_76.h" -#include "class_48.h" -#include "class_20.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_11/class_3.h b/lib/waf/build/lib_11/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_30.cpp b/lib/waf/build/lib_11/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_92.h" -#include "class_62.h" -#include "class_72.h" -#include "class_13.h" -#include "class_71.h" -#include "class_59.h" -#include "class_17.h" -#include "class_15.h" -#include "class_26.h" -#include "class_8.h" -#include "class_18.h" -#include "class_35.h" -#include "class_70.h" -#include "class_63.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_11/class_30.h b/lib/waf/build/lib_11/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_31.cpp b/lib/waf/build/lib_11/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_85.h" -#include "class_84.h" -#include "class_66.h" -#include "class_16.h" -#include "class_32.h" -#include "class_25.h" -#include "class_98.h" -#include "class_19.h" -#include "class_73.h" -#include "class_43.h" -#include "class_8.h" -#include "class_9.h" -#include "class_42.h" -#include "class_90.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_11/class_31.h b/lib/waf/build/lib_11/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_32.cpp b/lib/waf/build/lib_11/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_54.h" -#include "class_98.h" -#include "class_0.h" -#include "class_65.h" -#include "class_46.h" -#include "class_29.h" -#include "class_96.h" -#include "class_67.h" -#include "class_11.h" -#include "class_23.h" -#include "class_91.h" -#include "class_2.h" -#include "class_53.h" -#include "class_34.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_11/class_32.h b/lib/waf/build/lib_11/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_33.cpp b/lib/waf/build/lib_11/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_57.h" -#include "class_30.h" -#include "class_49.h" -#include "class_18.h" -#include "class_76.h" -#include "class_95.h" -#include "class_82.h" -#include "class_23.h" -#include "class_12.h" -#include "class_69.h" -#include "class_28.h" -#include "class_1.h" -#include "class_55.h" -#include "class_99.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_11/class_33.h b/lib/waf/build/lib_11/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_34.cpp b/lib/waf/build/lib_11/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_38.h" -#include "class_13.h" -#include "class_35.h" -#include "class_42.h" -#include "class_11.h" -#include "class_29.h" -#include "class_7.h" -#include "class_88.h" -#include "class_23.h" -#include "class_39.h" -#include "class_9.h" -#include "class_40.h" -#include "class_30.h" -#include "class_92.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_11/class_34.h b/lib/waf/build/lib_11/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_35.cpp b/lib/waf/build/lib_11/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_26.h" -#include "class_36.h" -#include "class_90.h" -#include "class_73.h" -#include "class_45.h" -#include "class_75.h" -#include "class_12.h" -#include "class_49.h" -#include "class_39.h" -#include "class_6.h" -#include "class_94.h" -#include "class_37.h" -#include "class_4.h" -#include "class_92.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_11/class_35.h b/lib/waf/build/lib_11/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_36.cpp b/lib/waf/build/lib_11/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_82.h" -#include "class_96.h" -#include "class_25.h" -#include "class_39.h" -#include "class_69.h" -#include "class_33.h" -#include "class_14.h" -#include "class_53.h" -#include "class_40.h" -#include "class_83.h" -#include "class_18.h" -#include "class_92.h" -#include "class_5.h" -#include "class_63.h" -#include "class_99.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_11/class_36.h b/lib/waf/build/lib_11/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_37.cpp b/lib/waf/build/lib_11/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_39.h" -#include "class_32.h" -#include "class_29.h" -#include "class_14.h" -#include "class_23.h" -#include "class_76.h" -#include "class_98.h" -#include "class_75.h" -#include "class_21.h" -#include "class_10.h" -#include "class_68.h" -#include "class_63.h" -#include "class_6.h" -#include "class_93.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_11/class_37.h b/lib/waf/build/lib_11/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_38.cpp b/lib/waf/build/lib_11/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_20.h" -#include "class_66.h" -#include "class_28.h" -#include "class_74.h" -#include "class_14.h" -#include "class_92.h" -#include "class_72.h" -#include "class_98.h" -#include "class_39.h" -#include "class_86.h" -#include "class_1.h" -#include "class_69.h" -#include "class_43.h" -#include "class_51.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_11/class_38.h b/lib/waf/build/lib_11/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_39.cpp b/lib/waf/build/lib_11/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_28.h" -#include "class_21.h" -#include "class_31.h" -#include "class_24.h" -#include "class_2.h" -#include "class_4.h" -#include "class_50.h" -#include "class_97.h" -#include "class_61.h" -#include "class_5.h" -#include "class_59.h" -#include "class_43.h" -#include "class_22.h" -#include "class_96.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_11/class_39.h b/lib/waf/build/lib_11/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_4.cpp b/lib/waf/build/lib_11/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_81.h" -#include "class_59.h" -#include "class_57.h" -#include "class_68.h" -#include "class_41.h" -#include "class_93.h" -#include "class_42.h" -#include "class_9.h" -#include "class_84.h" -#include "class_25.h" -#include "class_70.h" -#include "class_22.h" -#include "class_78.h" -#include "class_55.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_11/class_4.h b/lib/waf/build/lib_11/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_40.cpp b/lib/waf/build/lib_11/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_94.h" -#include "class_61.h" -#include "class_89.h" -#include "class_46.h" -#include "class_66.h" -#include "class_15.h" -#include "class_51.h" -#include "class_2.h" -#include "class_13.h" -#include "class_79.h" -#include "class_67.h" -#include "class_4.h" -#include "class_44.h" -#include "class_74.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_11/class_40.h b/lib/waf/build/lib_11/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_41.cpp b/lib/waf/build/lib_11/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_46.h" -#include "class_55.h" -#include "class_66.h" -#include "class_89.h" -#include "class_37.h" -#include "class_81.h" -#include "class_63.h" -#include "class_50.h" -#include "class_79.h" -#include "class_39.h" -#include "class_27.h" -#include "class_99.h" -#include "class_36.h" -#include "class_78.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_11/class_41.h b/lib/waf/build/lib_11/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_42.cpp b/lib/waf/build/lib_11/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_60.h" -#include "class_18.h" -#include "class_42.h" -#include "class_41.h" -#include "class_64.h" -#include "class_47.h" -#include "class_12.h" -#include "class_56.h" -#include "class_21.h" -#include "class_74.h" -#include "class_58.h" -#include "class_99.h" -#include "class_30.h" -#include "class_62.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_11/class_42.h b/lib/waf/build/lib_11/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_43.cpp b/lib/waf/build/lib_11/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_68.h" -#include "class_12.h" -#include "class_39.h" -#include "class_23.h" -#include "class_74.h" -#include "class_7.h" -#include "class_92.h" -#include "class_70.h" -#include "class_95.h" -#include "class_52.h" -#include "class_73.h" -#include "class_84.h" -#include "class_77.h" -#include "class_81.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_11/class_43.h b/lib/waf/build/lib_11/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_44.cpp b/lib/waf/build/lib_11/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_9.h" -#include "class_81.h" -#include "class_78.h" -#include "class_32.h" -#include "class_90.h" -#include "class_43.h" -#include "class_25.h" -#include "class_77.h" -#include "class_56.h" -#include "class_23.h" -#include "class_91.h" -#include "class_26.h" -#include "class_46.h" -#include "class_28.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_11/class_44.h b/lib/waf/build/lib_11/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_45.cpp b/lib/waf/build/lib_11/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_50.h" -#include "class_94.h" -#include "class_95.h" -#include "class_97.h" -#include "class_1.h" -#include "class_92.h" -#include "class_46.h" -#include "class_11.h" -#include "class_7.h" -#include "class_81.h" -#include "class_55.h" -#include "class_18.h" -#include "class_75.h" -#include "class_85.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_11/class_45.h b/lib/waf/build/lib_11/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_46.cpp b/lib/waf/build/lib_11/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_26.h" -#include "class_70.h" -#include "class_3.h" -#include "class_16.h" -#include "class_0.h" -#include "class_33.h" -#include "class_96.h" -#include "class_56.h" -#include "class_22.h" -#include "class_7.h" -#include "class_20.h" -#include "class_21.h" -#include "class_28.h" -#include "class_34.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_11/class_46.h b/lib/waf/build/lib_11/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_47.cpp b/lib/waf/build/lib_11/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_48.h" -#include "class_86.h" -#include "class_31.h" -#include "class_56.h" -#include "class_7.h" -#include "class_90.h" -#include "class_71.h" -#include "class_91.h" -#include "class_81.h" -#include "class_64.h" -#include "class_77.h" -#include "class_15.h" -#include "class_63.h" -#include "class_5.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_11/class_47.h b/lib/waf/build/lib_11/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_48.cpp b/lib/waf/build/lib_11/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_70.h" -#include "class_5.h" -#include "class_80.h" -#include "class_60.h" -#include "class_46.h" -#include "class_76.h" -#include "class_94.h" -#include "class_84.h" -#include "class_97.h" -#include "class_20.h" -#include "class_87.h" -#include "class_3.h" -#include "class_85.h" -#include "class_1.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_11/class_48.h b/lib/waf/build/lib_11/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_49.cpp b/lib/waf/build/lib_11/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_8.h" -#include "class_76.h" -#include "class_6.h" -#include "class_85.h" -#include "class_45.h" -#include "class_80.h" -#include "class_54.h" -#include "class_25.h" -#include "class_14.h" -#include "class_69.h" -#include "class_98.h" -#include "class_57.h" -#include "class_95.h" -#include "class_62.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_11/class_49.h b/lib/waf/build/lib_11/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_5.cpp b/lib/waf/build/lib_11/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_41.h" -#include "class_48.h" -#include "class_10.h" -#include "class_66.h" -#include "class_57.h" -#include "class_44.h" -#include "class_30.h" -#include "class_14.h" -#include "class_84.h" -#include "class_20.h" -#include "class_42.h" -#include "class_68.h" -#include "class_58.h" -#include "class_52.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_11/class_5.h b/lib/waf/build/lib_11/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_50.cpp b/lib/waf/build/lib_11/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_8.h" -#include "class_87.h" -#include "class_34.h" -#include "class_97.h" -#include "class_35.h" -#include "class_48.h" -#include "class_88.h" -#include "class_6.h" -#include "class_31.h" -#include "class_44.h" -#include "class_14.h" -#include "class_12.h" -#include "class_29.h" -#include "class_75.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_11/class_50.h b/lib/waf/build/lib_11/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_51.cpp b/lib/waf/build/lib_11/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_57.h" -#include "class_85.h" -#include "class_6.h" -#include "class_98.h" -#include "class_2.h" -#include "class_46.h" -#include "class_35.h" -#include "class_41.h" -#include "class_62.h" -#include "class_94.h" -#include "class_91.h" -#include "class_18.h" -#include "class_37.h" -#include "class_73.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_11/class_51.h b/lib/waf/build/lib_11/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_52.cpp b/lib/waf/build/lib_11/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_83.h" -#include "class_37.h" -#include "class_38.h" -#include "class_59.h" -#include "class_61.h" -#include "class_96.h" -#include "class_20.h" -#include "class_73.h" -#include "class_36.h" -#include "class_26.h" -#include "class_49.h" -#include "class_48.h" -#include "class_18.h" -#include "class_28.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_11/class_52.h b/lib/waf/build/lib_11/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_53.cpp b/lib/waf/build/lib_11/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_11.h" -#include "class_80.h" -#include "class_30.h" -#include "class_24.h" -#include "class_54.h" -#include "class_12.h" -#include "class_60.h" -#include "class_72.h" -#include "class_63.h" -#include "class_82.h" -#include "class_86.h" -#include "class_56.h" -#include "class_66.h" -#include "class_64.h" -#include "class_99.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_11/class_53.h b/lib/waf/build/lib_11/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_54.cpp b/lib/waf/build/lib_11/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_3.h" -#include "class_7.h" -#include "class_34.h" -#include "class_73.h" -#include "class_79.h" -#include "class_47.h" -#include "class_62.h" -#include "class_40.h" -#include "class_51.h" -#include "class_42.h" -#include "class_36.h" -#include "class_56.h" -#include "class_6.h" -#include "class_83.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_11/class_54.h b/lib/waf/build/lib_11/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_55.cpp b/lib/waf/build/lib_11/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_28.h" -#include "class_66.h" -#include "class_49.h" -#include "class_83.h" -#include "class_65.h" -#include "class_75.h" -#include "class_13.h" -#include "class_31.h" -#include "class_85.h" -#include "class_59.h" -#include "class_24.h" -#include "class_95.h" -#include "class_16.h" -#include "class_92.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_11/class_55.h b/lib/waf/build/lib_11/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_56.cpp b/lib/waf/build/lib_11/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_79.h" -#include "class_97.h" -#include "class_19.h" -#include "class_92.h" -#include "class_60.h" -#include "class_50.h" -#include "class_47.h" -#include "class_44.h" -#include "class_28.h" -#include "class_51.h" -#include "class_1.h" -#include "class_20.h" -#include "class_18.h" -#include "class_6.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_11/class_56.h b/lib/waf/build/lib_11/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_57.cpp b/lib/waf/build/lib_11/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_14.h" -#include "class_80.h" -#include "class_24.h" -#include "class_4.h" -#include "class_86.h" -#include "class_89.h" -#include "class_95.h" -#include "class_39.h" -#include "class_19.h" -#include "class_43.h" -#include "class_57.h" -#include "class_26.h" -#include "class_25.h" -#include "class_98.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_11/class_57.h b/lib/waf/build/lib_11/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_58.cpp b/lib/waf/build/lib_11/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_33.h" -#include "class_62.h" -#include "class_47.h" -#include "class_15.h" -#include "class_53.h" -#include "class_51.h" -#include "class_96.h" -#include "class_20.h" -#include "class_31.h" -#include "class_81.h" -#include "class_50.h" -#include "class_35.h" -#include "class_21.h" -#include "class_0.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_11/class_58.h b/lib/waf/build/lib_11/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_59.cpp b/lib/waf/build/lib_11/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_73.h" -#include "class_81.h" -#include "class_13.h" -#include "class_63.h" -#include "class_87.h" -#include "class_41.h" -#include "class_94.h" -#include "class_64.h" -#include "class_2.h" -#include "class_48.h" -#include "class_32.h" -#include "class_29.h" -#include "class_58.h" -#include "class_66.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_11/class_59.h b/lib/waf/build/lib_11/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_6.cpp b/lib/waf/build/lib_11/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_27.h" -#include "class_8.h" -#include "class_20.h" -#include "class_50.h" -#include "class_2.h" -#include "class_28.h" -#include "class_37.h" -#include "class_97.h" -#include "class_31.h" -#include "class_46.h" -#include "class_72.h" -#include "class_65.h" -#include "class_49.h" -#include "class_44.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_11/class_6.h b/lib/waf/build/lib_11/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_60.cpp b/lib/waf/build/lib_11/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_96.h" -#include "class_5.h" -#include "class_79.h" -#include "class_69.h" -#include "class_57.h" -#include "class_89.h" -#include "class_33.h" -#include "class_74.h" -#include "class_62.h" -#include "class_73.h" -#include "class_25.h" -#include "class_98.h" -#include "class_70.h" -#include "class_38.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_11/class_60.h b/lib/waf/build/lib_11/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_61.cpp b/lib/waf/build/lib_11/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_64.h" -#include "class_30.h" -#include "class_87.h" -#include "class_33.h" -#include "class_6.h" -#include "class_95.h" -#include "class_31.h" -#include "class_77.h" -#include "class_93.h" -#include "class_57.h" -#include "class_13.h" -#include "class_70.h" -#include "class_90.h" -#include "class_8.h" -#include "class_88.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_11/class_61.h b/lib/waf/build/lib_11/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_62.cpp b/lib/waf/build/lib_11/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_24.h" -#include "class_73.h" -#include "class_33.h" -#include "class_55.h" -#include "class_0.h" -#include "class_70.h" -#include "class_79.h" -#include "class_77.h" -#include "class_50.h" -#include "class_16.h" -#include "class_36.h" -#include "class_87.h" -#include "class_47.h" -#include "class_89.h" -#include "class_6.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_11/class_62.h b/lib/waf/build/lib_11/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_63.cpp b/lib/waf/build/lib_11/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_46.h" -#include "class_88.h" -#include "class_80.h" -#include "class_32.h" -#include "class_64.h" -#include "class_55.h" -#include "class_26.h" -#include "class_54.h" -#include "class_39.h" -#include "class_49.h" -#include "class_9.h" -#include "class_13.h" -#include "class_84.h" -#include "class_17.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_11/class_63.h b/lib/waf/build/lib_11/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_64.cpp b/lib/waf/build/lib_11/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_67.h" -#include "class_85.h" -#include "class_65.h" -#include "class_28.h" -#include "class_72.h" -#include "class_99.h" -#include "class_79.h" -#include "class_7.h" -#include "class_78.h" -#include "class_37.h" -#include "class_58.h" -#include "class_68.h" -#include "class_75.h" -#include "class_71.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_11/class_64.h b/lib/waf/build/lib_11/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_65.cpp b/lib/waf/build/lib_11/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_45.h" -#include "class_31.h" -#include "class_94.h" -#include "class_26.h" -#include "class_53.h" -#include "class_79.h" -#include "class_89.h" -#include "class_71.h" -#include "class_87.h" -#include "class_68.h" -#include "class_52.h" -#include "class_57.h" -#include "class_74.h" -#include "class_60.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_11/class_65.h b/lib/waf/build/lib_11/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_66.cpp b/lib/waf/build/lib_11/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_14.h" -#include "class_27.h" -#include "class_66.h" -#include "class_73.h" -#include "class_19.h" -#include "class_11.h" -#include "class_49.h" -#include "class_38.h" -#include "class_15.h" -#include "class_62.h" -#include "class_71.h" -#include "class_41.h" -#include "class_4.h" -#include "class_56.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_11/class_66.h b/lib/waf/build/lib_11/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_67.cpp b/lib/waf/build/lib_11/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_60.h" -#include "class_29.h" -#include "class_55.h" -#include "class_95.h" -#include "class_71.h" -#include "class_14.h" -#include "class_63.h" -#include "class_28.h" -#include "class_11.h" -#include "class_54.h" -#include "class_24.h" -#include "class_79.h" -#include "class_57.h" -#include "class_92.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_11/class_67.h b/lib/waf/build/lib_11/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_68.cpp b/lib/waf/build/lib_11/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_1.h" -#include "class_31.h" -#include "class_36.h" -#include "class_78.h" -#include "class_2.h" -#include "class_12.h" -#include "class_51.h" -#include "class_75.h" -#include "class_11.h" -#include "class_17.h" -#include "class_16.h" -#include "class_15.h" -#include "class_86.h" -#include "class_8.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_11/class_68.h b/lib/waf/build/lib_11/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_69.cpp b/lib/waf/build/lib_11/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_54.h" -#include "class_36.h" -#include "class_83.h" -#include "class_38.h" -#include "class_17.h" -#include "class_76.h" -#include "class_14.h" -#include "class_84.h" -#include "class_45.h" -#include "class_33.h" -#include "class_35.h" -#include "class_73.h" -#include "class_51.h" -#include "class_49.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_11/class_69.h b/lib/waf/build/lib_11/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_7.cpp b/lib/waf/build/lib_11/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_71.h" -#include "class_89.h" -#include "class_69.h" -#include "class_52.h" -#include "class_35.h" -#include "class_31.h" -#include "class_82.h" -#include "class_48.h" -#include "class_73.h" -#include "class_20.h" -#include "class_46.h" -#include "class_79.h" -#include "class_49.h" -#include "class_7.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_11/class_7.h b/lib/waf/build/lib_11/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_70.cpp b/lib/waf/build/lib_11/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_79.h" -#include "class_56.h" -#include "class_29.h" -#include "class_49.h" -#include "class_24.h" -#include "class_13.h" -#include "class_4.h" -#include "class_43.h" -#include "class_64.h" -#include "class_5.h" -#include "class_60.h" -#include "class_40.h" -#include "class_87.h" -#include "class_63.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_11/class_70.h b/lib/waf/build/lib_11/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_71.cpp b/lib/waf/build/lib_11/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_30.h" -#include "class_15.h" -#include "class_56.h" -#include "class_82.h" -#include "class_85.h" -#include "class_37.h" -#include "class_71.h" -#include "class_68.h" -#include "class_51.h" -#include "class_9.h" -#include "class_62.h" -#include "class_5.h" -#include "class_50.h" -#include "class_81.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_11/class_71.h b/lib/waf/build/lib_11/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_72.cpp b/lib/waf/build/lib_11/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_51.h" -#include "class_25.h" -#include "class_73.h" -#include "class_44.h" -#include "class_40.h" -#include "class_49.h" -#include "class_45.h" -#include "class_95.h" -#include "class_96.h" -#include "class_87.h" -#include "class_85.h" -#include "class_94.h" -#include "class_81.h" -#include "class_68.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_11/class_72.h b/lib/waf/build/lib_11/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_73.cpp b/lib/waf/build/lib_11/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_32.h" -#include "class_74.h" -#include "class_15.h" -#include "class_27.h" -#include "class_69.h" -#include "class_59.h" -#include "class_89.h" -#include "class_66.h" -#include "class_99.h" -#include "class_64.h" -#include "class_83.h" -#include "class_13.h" -#include "class_34.h" -#include "class_10.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_11/class_73.h b/lib/waf/build/lib_11/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_74.cpp b/lib/waf/build/lib_11/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_25.h" -#include "class_2.h" -#include "class_64.h" -#include "class_80.h" -#include "class_84.h" -#include "class_23.h" -#include "class_19.h" -#include "class_57.h" -#include "class_98.h" -#include "class_86.h" -#include "class_0.h" -#include "class_92.h" -#include "class_97.h" -#include "class_26.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_11/class_74.h b/lib/waf/build/lib_11/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_75.cpp b/lib/waf/build/lib_11/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_44.h" -#include "class_51.h" -#include "class_65.h" -#include "class_52.h" -#include "class_41.h" -#include "class_87.h" -#include "class_42.h" -#include "class_68.h" -#include "class_73.h" -#include "class_77.h" -#include "class_81.h" -#include "class_90.h" -#include "class_23.h" -#include "class_79.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_11/class_75.h b/lib/waf/build/lib_11/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_76.cpp b/lib/waf/build/lib_11/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_48.h" -#include "class_38.h" -#include "class_82.h" -#include "class_94.h" -#include "class_3.h" -#include "class_87.h" -#include "class_14.h" -#include "class_35.h" -#include "class_11.h" -#include "class_50.h" -#include "class_58.h" -#include "class_32.h" -#include "class_66.h" -#include "class_95.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_11/class_76.h b/lib/waf/build/lib_11/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_77.cpp b/lib/waf/build/lib_11/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_52.h" -#include "class_92.h" -#include "class_4.h" -#include "class_62.h" -#include "class_18.h" -#include "class_87.h" -#include "class_28.h" -#include "class_27.h" -#include "class_13.h" -#include "class_42.h" -#include "class_90.h" -#include "class_50.h" -#include "class_32.h" -#include "class_2.h" -#include "class_6.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_11/class_77.h b/lib/waf/build/lib_11/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_78.cpp b/lib/waf/build/lib_11/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_51.h" -#include "class_4.h" -#include "class_63.h" -#include "class_26.h" -#include "class_86.h" -#include "class_5.h" -#include "class_18.h" -#include "class_0.h" -#include "class_2.h" -#include "class_48.h" -#include "class_61.h" -#include "class_42.h" -#include "class_89.h" -#include "class_17.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_11/class_78.h b/lib/waf/build/lib_11/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_79.cpp b/lib/waf/build/lib_11/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_15.h" -#include "class_93.h" -#include "class_91.h" -#include "class_6.h" -#include "class_81.h" -#include "class_22.h" -#include "class_8.h" -#include "class_58.h" -#include "class_63.h" -#include "class_92.h" -#include "class_71.h" -#include "class_79.h" -#include "class_2.h" -#include "class_11.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_11/class_79.h b/lib/waf/build/lib_11/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_8.cpp b/lib/waf/build/lib_11/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_19.h" -#include "class_90.h" -#include "class_39.h" -#include "class_50.h" -#include "class_94.h" -#include "class_24.h" -#include "class_95.h" -#include "class_11.h" -#include "class_23.h" -#include "class_33.h" -#include "class_56.h" -#include "class_32.h" -#include "class_41.h" -#include "class_31.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_11/class_8.h b/lib/waf/build/lib_11/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_80.cpp b/lib/waf/build/lib_11/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_91.h" -#include "class_77.h" -#include "class_34.h" -#include "class_46.h" -#include "class_62.h" -#include "class_58.h" -#include "class_55.h" -#include "class_3.h" -#include "class_8.h" -#include "class_44.h" -#include "class_35.h" -#include "class_96.h" -#include "class_14.h" -#include "class_1.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_11/class_80.h b/lib/waf/build/lib_11/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_81.cpp b/lib/waf/build/lib_11/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_24.h" -#include "class_73.h" -#include "class_44.h" -#include "class_84.h" -#include "class_27.h" -#include "class_88.h" -#include "class_2.h" -#include "class_0.h" -#include "class_81.h" -#include "class_41.h" -#include "class_20.h" -#include "class_18.h" -#include "class_15.h" -#include "class_19.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_11/class_81.h b/lib/waf/build/lib_11/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_82.cpp b/lib/waf/build/lib_11/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_98.h" -#include "class_16.h" -#include "class_60.h" -#include "class_55.h" -#include "class_49.h" -#include "class_34.h" -#include "class_47.h" -#include "class_17.h" -#include "class_21.h" -#include "class_27.h" -#include "class_68.h" -#include "class_29.h" -#include "class_73.h" -#include "class_80.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_11/class_82.h b/lib/waf/build/lib_11/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_83.cpp b/lib/waf/build/lib_11/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_64.h" -#include "class_52.h" -#include "class_57.h" -#include "class_19.h" -#include "class_98.h" -#include "class_2.h" -#include "class_81.h" -#include "class_56.h" -#include "class_70.h" -#include "class_13.h" -#include "class_5.h" -#include "class_68.h" -#include "class_97.h" -#include "class_9.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_11/class_83.h b/lib/waf/build/lib_11/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_84.cpp b/lib/waf/build/lib_11/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_81.h" -#include "class_22.h" -#include "class_59.h" -#include "class_32.h" -#include "class_12.h" -#include "class_41.h" -#include "class_57.h" -#include "class_92.h" -#include "class_56.h" -#include "class_51.h" -#include "class_50.h" -#include "class_72.h" -#include "class_77.h" -#include "class_95.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_11/class_84.h b/lib/waf/build/lib_11/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_85.cpp b/lib/waf/build/lib_11/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_2.h" -#include "class_43.h" -#include "class_26.h" -#include "class_1.h" -#include "class_54.h" -#include "class_72.h" -#include "class_68.h" -#include "class_67.h" -#include "class_47.h" -#include "class_7.h" -#include "class_13.h" -#include "class_40.h" -#include "class_24.h" -#include "class_17.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_11/class_85.h b/lib/waf/build/lib_11/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_86.cpp b/lib/waf/build/lib_11/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_92.h" -#include "class_76.h" -#include "class_19.h" -#include "class_67.h" -#include "class_55.h" -#include "class_60.h" -#include "class_50.h" -#include "class_93.h" -#include "class_30.h" -#include "class_87.h" -#include "class_15.h" -#include "class_89.h" -#include "class_77.h" -#include "class_53.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_11/class_86.h b/lib/waf/build/lib_11/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_87.cpp b/lib/waf/build/lib_11/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_11.h" -#include "class_19.h" -#include "class_44.h" -#include "class_24.h" -#include "class_41.h" -#include "class_75.h" -#include "class_5.h" -#include "class_12.h" -#include "class_35.h" -#include "class_6.h" -#include "class_49.h" -#include "class_68.h" -#include "class_76.h" -#include "class_65.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_11/class_87.h b/lib/waf/build/lib_11/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_88.cpp b/lib/waf/build/lib_11/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_69.h" -#include "class_96.h" -#include "class_56.h" -#include "class_57.h" -#include "class_6.h" -#include "class_17.h" -#include "class_94.h" -#include "class_44.h" -#include "class_21.h" -#include "class_19.h" -#include "class_85.h" -#include "class_73.h" -#include "class_75.h" -#include "class_50.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_11/class_88.h b/lib/waf/build/lib_11/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_89.cpp b/lib/waf/build/lib_11/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_96.h" -#include "class_38.h" -#include "class_65.h" -#include "class_97.h" -#include "class_1.h" -#include "class_5.h" -#include "class_18.h" -#include "class_55.h" -#include "class_94.h" -#include "class_66.h" -#include "class_56.h" -#include "class_88.h" -#include "class_99.h" -#include "class_47.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_11/class_89.h b/lib/waf/build/lib_11/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_9.cpp b/lib/waf/build/lib_11/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_59.h" -#include "class_30.h" -#include "class_77.h" -#include "class_53.h" -#include "class_23.h" -#include "class_75.h" -#include "class_64.h" -#include "class_69.h" -#include "class_56.h" -#include "class_10.h" -#include "class_46.h" -#include "class_13.h" -#include "class_39.h" -#include "class_33.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_11/class_9.h b/lib/waf/build/lib_11/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_90.cpp b/lib/waf/build/lib_11/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_29.h" -#include "class_34.h" -#include "class_91.h" -#include "class_21.h" -#include "class_47.h" -#include "class_28.h" -#include "class_3.h" -#include "class_38.h" -#include "class_52.h" -#include "class_87.h" -#include "class_49.h" -#include "class_51.h" -#include "class_0.h" -#include "class_80.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_11/class_90.h b/lib/waf/build/lib_11/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_91.cpp b/lib/waf/build/lib_11/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_85.h" -#include "class_8.h" -#include "class_25.h" -#include "class_73.h" -#include "class_9.h" -#include "class_37.h" -#include "class_13.h" -#include "class_44.h" -#include "class_92.h" -#include "class_71.h" -#include "class_17.h" -#include "class_39.h" -#include "class_43.h" -#include "class_52.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_11/class_91.h b/lib/waf/build/lib_11/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_92.cpp b/lib/waf/build/lib_11/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_56.h" -#include "class_4.h" -#include "class_77.h" -#include "class_70.h" -#include "class_0.h" -#include "class_94.h" -#include "class_54.h" -#include "class_37.h" -#include "class_21.h" -#include "class_84.h" -#include "class_76.h" -#include "class_74.h" -#include "class_7.h" -#include "class_53.h" -#include "class_6.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_11/class_92.h b/lib/waf/build/lib_11/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_93.cpp b/lib/waf/build/lib_11/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_55.h" -#include "class_7.h" -#include "class_47.h" -#include "class_26.h" -#include "class_42.h" -#include "class_37.h" -#include "class_94.h" -#include "class_90.h" -#include "class_22.h" -#include "class_28.h" -#include "class_88.h" -#include "class_76.h" -#include "class_64.h" -#include "class_53.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_11/class_93.h b/lib/waf/build/lib_11/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_94.cpp b/lib/waf/build/lib_11/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_93.h" -#include "class_28.h" -#include "class_68.h" -#include "class_43.h" -#include "class_34.h" -#include "class_61.h" -#include "class_94.h" -#include "class_30.h" -#include "class_71.h" -#include "class_78.h" -#include "class_39.h" -#include "class_1.h" -#include "class_59.h" -#include "class_19.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_11/class_94.h b/lib/waf/build/lib_11/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_95.cpp b/lib/waf/build/lib_11/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_20.h" -#include "class_2.h" -#include "class_84.h" -#include "class_29.h" -#include "class_65.h" -#include "class_93.h" -#include "class_58.h" -#include "class_95.h" -#include "class_68.h" -#include "class_57.h" -#include "class_9.h" -#include "class_50.h" -#include "class_61.h" -#include "class_99.h" -#include "class_42.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_11/class_95.h b/lib/waf/build/lib_11/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_96.cpp b/lib/waf/build/lib_11/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_34.h" -#include "class_53.h" -#include "class_64.h" -#include "class_12.h" -#include "class_16.h" -#include "class_73.h" -#include "class_30.h" -#include "class_86.h" -#include "class_66.h" -#include "class_81.h" -#include "class_89.h" -#include "class_91.h" -#include "class_15.h" -#include "class_33.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_11/class_96.h b/lib/waf/build/lib_11/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_97.cpp b/lib/waf/build/lib_11/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_61.h" -#include "class_7.h" -#include "class_39.h" -#include "class_93.h" -#include "class_4.h" -#include "class_74.h" -#include "class_85.h" -#include "class_41.h" -#include "class_31.h" -#include "class_16.h" -#include "class_9.h" -#include "class_5.h" -#include "class_14.h" -#include "class_73.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_11/class_97.h b/lib/waf/build/lib_11/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_98.cpp b/lib/waf/build/lib_11/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_98.h" -#include "class_79.h" -#include "class_7.h" -#include "class_13.h" -#include "class_22.h" -#include "class_42.h" -#include "class_99.h" -#include "class_33.h" -#include "class_2.h" -#include "class_8.h" -#include "class_30.h" -#include "class_92.h" -#include "class_41.h" -#include "class_62.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_11/class_98.h b/lib/waf/build/lib_11/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_11/class_99.cpp b/lib/waf/build/lib_11/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_11/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_83.h" -#include "class_45.h" -#include "class_51.h" -#include "class_26.h" -#include "class_97.h" -#include "class_17.h" -#include "class_95.h" -#include "class_0.h" -#include "class_46.h" -#include "class_21.h" -#include "class_62.h" -#include "class_14.h" -#include "class_88.h" -#include "class_41.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_11/class_99.h b/lib/waf/build/lib_11/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_11/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_12/Makefile b/lib/waf/build/lib_12/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_12/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_12.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_12/Makefile.am b/lib/waf/build/lib_12/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_12/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib12.la -lib12_la_SOURCES = lib_12/class_0.cpp lib_12/class_1.cpp lib_12/class_2.cpp lib_12/class_3.cpp lib_12/class_4.cpp lib_12/class_5.cpp lib_12/class_6.cpp lib_12/class_7.cpp lib_12/class_8.cpp lib_12/class_9.cpp lib_12/class_10.cpp lib_12/class_11.cpp lib_12/class_12.cpp lib_12/class_13.cpp lib_12/class_14.cpp lib_12/class_15.cpp lib_12/class_16.cpp lib_12/class_17.cpp lib_12/class_18.cpp lib_12/class_19.cpp lib_12/class_20.cpp lib_12/class_21.cpp lib_12/class_22.cpp lib_12/class_23.cpp lib_12/class_24.cpp lib_12/class_25.cpp lib_12/class_26.cpp lib_12/class_27.cpp lib_12/class_28.cpp lib_12/class_29.cpp lib_12/class_30.cpp lib_12/class_31.cpp lib_12/class_32.cpp lib_12/class_33.cpp lib_12/class_34.cpp lib_12/class_35.cpp lib_12/class_36.cpp lib_12/class_37.cpp lib_12/class_38.cpp lib_12/class_39.cpp lib_12/class_40.cpp lib_12/class_41.cpp lib_12/class_42.cpp lib_12/class_43.cpp lib_12/class_44.cpp lib_12/class_45.cpp lib_12/class_46.cpp lib_12/class_47.cpp lib_12/class_48.cpp lib_12/class_49.cpp lib_12/class_50.cpp lib_12/class_51.cpp lib_12/class_52.cpp lib_12/class_53.cpp lib_12/class_54.cpp lib_12/class_55.cpp lib_12/class_56.cpp lib_12/class_57.cpp lib_12/class_58.cpp lib_12/class_59.cpp lib_12/class_60.cpp lib_12/class_61.cpp lib_12/class_62.cpp lib_12/class_63.cpp lib_12/class_64.cpp lib_12/class_65.cpp lib_12/class_66.cpp lib_12/class_67.cpp lib_12/class_68.cpp lib_12/class_69.cpp lib_12/class_70.cpp lib_12/class_71.cpp lib_12/class_72.cpp lib_12/class_73.cpp lib_12/class_74.cpp lib_12/class_75.cpp lib_12/class_76.cpp lib_12/class_77.cpp lib_12/class_78.cpp lib_12/class_79.cpp lib_12/class_80.cpp lib_12/class_81.cpp lib_12/class_82.cpp lib_12/class_83.cpp lib_12/class_84.cpp lib_12/class_85.cpp lib_12/class_86.cpp lib_12/class_87.cpp lib_12/class_88.cpp lib_12/class_89.cpp lib_12/class_90.cpp lib_12/class_91.cpp lib_12/class_92.cpp lib_12/class_93.cpp lib_12/class_94.cpp lib_12/class_95.cpp lib_12/class_96.cpp lib_12/class_97.cpp lib_12/class_98.cpp lib_12/class_99.cpp diff --git a/lib/waf/build/lib_12/SConscript b/lib/waf/build/lib_12/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_12/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_12", list) - diff --git a/lib/waf/build/lib_12/class_0.cpp b/lib/waf/build/lib_12/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_18.h" -#include "class_88.h" -#include "class_28.h" -#include "class_5.h" -#include "class_42.h" -#include "class_12.h" -#include "class_91.h" -#include "class_58.h" -#include "class_82.h" -#include "class_11.h" -#include "class_52.h" -#include "class_50.h" -#include "class_17.h" -#include "class_25.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_12/class_0.h b/lib/waf/build/lib_12/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_1.cpp b/lib/waf/build/lib_12/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_19.h" -#include "class_20.h" -#include "class_34.h" -#include "class_43.h" -#include "class_59.h" -#include "class_45.h" -#include "class_14.h" -#include "class_5.h" -#include "class_41.h" -#include "class_35.h" -#include "class_71.h" -#include "class_82.h" -#include "class_58.h" -#include "class_93.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_12/class_1.h b/lib/waf/build/lib_12/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_10.cpp b/lib/waf/build/lib_12/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_47.h" -#include "class_81.h" -#include "class_77.h" -#include "class_31.h" -#include "class_53.h" -#include "class_4.h" -#include "class_92.h" -#include "class_61.h" -#include "class_66.h" -#include "class_26.h" -#include "class_37.h" -#include "class_60.h" -#include "class_91.h" -#include "class_95.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_12/class_10.h b/lib/waf/build/lib_12/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_11.cpp b/lib/waf/build/lib_12/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_17.h" -#include "class_15.h" -#include "class_0.h" -#include "class_47.h" -#include "class_86.h" -#include "class_54.h" -#include "class_25.h" -#include "class_96.h" -#include "class_67.h" -#include "class_59.h" -#include "class_34.h" -#include "class_41.h" -#include "class_56.h" -#include "class_64.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_12/class_11.h b/lib/waf/build/lib_12/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_12.cpp b/lib/waf/build/lib_12/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_35.h" -#include "class_80.h" -#include "class_0.h" -#include "class_65.h" -#include "class_99.h" -#include "class_69.h" -#include "class_10.h" -#include "class_70.h" -#include "class_37.h" -#include "class_1.h" -#include "class_58.h" -#include "class_62.h" -#include "class_20.h" -#include "class_88.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_12/class_12.h b/lib/waf/build/lib_12/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_13.cpp b/lib/waf/build/lib_12/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_47.h" -#include "class_70.h" -#include "class_29.h" -#include "class_98.h" -#include "class_84.h" -#include "class_85.h" -#include "class_66.h" -#include "class_39.h" -#include "class_75.h" -#include "class_60.h" -#include "class_94.h" -#include "class_10.h" -#include "class_25.h" -#include "class_95.h" -#include "class_36.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_12/class_13.h b/lib/waf/build/lib_12/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_14.cpp b/lib/waf/build/lib_12/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_4.h" -#include "class_64.h" -#include "class_25.h" -#include "class_60.h" -#include "class_54.h" -#include "class_85.h" -#include "class_34.h" -#include "class_97.h" -#include "class_7.h" -#include "class_2.h" -#include "class_83.h" -#include "class_29.h" -#include "class_76.h" -#include "class_91.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_12/class_14.h b/lib/waf/build/lib_12/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_15.cpp b/lib/waf/build/lib_12/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_88.h" -#include "class_35.h" -#include "class_56.h" -#include "class_13.h" -#include "class_33.h" -#include "class_70.h" -#include "class_22.h" -#include "class_83.h" -#include "class_97.h" -#include "class_26.h" -#include "class_4.h" -#include "class_54.h" -#include "class_69.h" -#include "class_38.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_12/class_15.h b/lib/waf/build/lib_12/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_16.cpp b/lib/waf/build/lib_12/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_87.h" -#include "class_71.h" -#include "class_81.h" -#include "class_9.h" -#include "class_79.h" -#include "class_82.h" -#include "class_24.h" -#include "class_55.h" -#include "class_60.h" -#include "class_13.h" -#include "class_33.h" -#include "class_63.h" -#include "class_36.h" -#include "class_20.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_12/class_16.h b/lib/waf/build/lib_12/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_17.cpp b/lib/waf/build/lib_12/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_37.h" -#include "class_60.h" -#include "class_93.h" -#include "class_62.h" -#include "class_41.h" -#include "class_97.h" -#include "class_77.h" -#include "class_6.h" -#include "class_65.h" -#include "class_30.h" -#include "class_38.h" -#include "class_87.h" -#include "class_26.h" -#include "class_21.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_12/class_17.h b/lib/waf/build/lib_12/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_18.cpp b/lib/waf/build/lib_12/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_43.h" -#include "class_17.h" -#include "class_88.h" -#include "class_39.h" -#include "class_90.h" -#include "class_56.h" -#include "class_49.h" -#include "class_59.h" -#include "class_35.h" -#include "class_42.h" -#include "class_58.h" -#include "class_45.h" -#include "class_2.h" -#include "class_22.h" -#include "class_75.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_12/class_18.h b/lib/waf/build/lib_12/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_19.cpp b/lib/waf/build/lib_12/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_99.h" -#include "class_75.h" -#include "class_34.h" -#include "class_98.h" -#include "class_27.h" -#include "class_32.h" -#include "class_48.h" -#include "class_65.h" -#include "class_45.h" -#include "class_22.h" -#include "class_87.h" -#include "class_35.h" -#include "class_10.h" -#include "class_29.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_12/class_19.h b/lib/waf/build/lib_12/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_2.cpp b/lib/waf/build/lib_12/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_77.h" -#include "class_45.h" -#include "class_72.h" -#include "class_84.h" -#include "class_46.h" -#include "class_2.h" -#include "class_6.h" -#include "class_9.h" -#include "class_91.h" -#include "class_8.h" -#include "class_69.h" -#include "class_82.h" -#include "class_34.h" -#include "class_47.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_12/class_2.h b/lib/waf/build/lib_12/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_20.cpp b/lib/waf/build/lib_12/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_97.h" -#include "class_56.h" -#include "class_36.h" -#include "class_24.h" -#include "class_12.h" -#include "class_10.h" -#include "class_48.h" -#include "class_91.h" -#include "class_92.h" -#include "class_9.h" -#include "class_55.h" -#include "class_5.h" -#include "class_4.h" -#include "class_15.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_12/class_20.h b/lib/waf/build/lib_12/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_21.cpp b/lib/waf/build/lib_12/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_60.h" -#include "class_51.h" -#include "class_20.h" -#include "class_47.h" -#include "class_83.h" -#include "class_66.h" -#include "class_13.h" -#include "class_59.h" -#include "class_99.h" -#include "class_15.h" -#include "class_33.h" -#include "class_34.h" -#include "class_11.h" -#include "class_76.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_12/class_21.h b/lib/waf/build/lib_12/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_22.cpp b/lib/waf/build/lib_12/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_71.h" -#include "class_86.h" -#include "class_87.h" -#include "class_85.h" -#include "class_98.h" -#include "class_49.h" -#include "class_43.h" -#include "class_79.h" -#include "class_63.h" -#include "class_58.h" -#include "class_78.h" -#include "class_12.h" -#include "class_75.h" -#include "class_90.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_12/class_22.h b/lib/waf/build/lib_12/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_23.cpp b/lib/waf/build/lib_12/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_99.h" -#include "class_12.h" -#include "class_40.h" -#include "class_43.h" -#include "class_8.h" -#include "class_72.h" -#include "class_66.h" -#include "class_91.h" -#include "class_67.h" -#include "class_79.h" -#include "class_92.h" -#include "class_54.h" -#include "class_38.h" -#include "class_5.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_12/class_23.h b/lib/waf/build/lib_12/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_24.cpp b/lib/waf/build/lib_12/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_22.h" -#include "class_90.h" -#include "class_40.h" -#include "class_7.h" -#include "class_55.h" -#include "class_42.h" -#include "class_64.h" -#include "class_21.h" -#include "class_82.h" -#include "class_69.h" -#include "class_37.h" -#include "class_67.h" -#include "class_57.h" -#include "class_36.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_12/class_24.h b/lib/waf/build/lib_12/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_25.cpp b/lib/waf/build/lib_12/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_35.h" -#include "class_30.h" -#include "class_76.h" -#include "class_71.h" -#include "class_74.h" -#include "class_53.h" -#include "class_98.h" -#include "class_69.h" -#include "class_20.h" -#include "class_64.h" -#include "class_14.h" -#include "class_80.h" -#include "class_95.h" -#include "class_50.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_12/class_25.h b/lib/waf/build/lib_12/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_26.cpp b/lib/waf/build/lib_12/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_53.h" -#include "class_88.h" -#include "class_98.h" -#include "class_1.h" -#include "class_78.h" -#include "class_10.h" -#include "class_24.h" -#include "class_97.h" -#include "class_6.h" -#include "class_93.h" -#include "class_92.h" -#include "class_47.h" -#include "class_75.h" -#include "class_43.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_12/class_26.h b/lib/waf/build/lib_12/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_27.cpp b/lib/waf/build/lib_12/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_3.h" -#include "class_57.h" -#include "class_98.h" -#include "class_84.h" -#include "class_30.h" -#include "class_59.h" -#include "class_49.h" -#include "class_27.h" -#include "class_25.h" -#include "class_63.h" -#include "class_48.h" -#include "class_10.h" -#include "class_96.h" -#include "class_1.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_12/class_27.h b/lib/waf/build/lib_12/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_28.cpp b/lib/waf/build/lib_12/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_62.h" -#include "class_37.h" -#include "class_28.h" -#include "class_83.h" -#include "class_25.h" -#include "class_64.h" -#include "class_18.h" -#include "class_5.h" -#include "class_55.h" -#include "class_58.h" -#include "class_8.h" -#include "class_91.h" -#include "class_84.h" -#include "class_85.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_12/class_28.h b/lib/waf/build/lib_12/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_29.cpp b/lib/waf/build/lib_12/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_81.h" -#include "class_5.h" -#include "class_24.h" -#include "class_35.h" -#include "class_1.h" -#include "class_22.h" -#include "class_88.h" -#include "class_38.h" -#include "class_72.h" -#include "class_96.h" -#include "class_43.h" -#include "class_8.h" -#include "class_69.h" -#include "class_91.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_12/class_29.h b/lib/waf/build/lib_12/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_3.cpp b/lib/waf/build/lib_12/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_7.h" -#include "class_2.h" -#include "class_30.h" -#include "class_89.h" -#include "class_70.h" -#include "class_25.h" -#include "class_78.h" -#include "class_57.h" -#include "class_29.h" -#include "class_14.h" -#include "class_8.h" -#include "class_53.h" -#include "class_37.h" -#include "class_13.h" -#include "class_93.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_12/class_3.h b/lib/waf/build/lib_12/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_30.cpp b/lib/waf/build/lib_12/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_4.h" -#include "class_28.h" -#include "class_26.h" -#include "class_6.h" -#include "class_76.h" -#include "class_82.h" -#include "class_50.h" -#include "class_51.h" -#include "class_13.h" -#include "class_94.h" -#include "class_69.h" -#include "class_85.h" -#include "class_59.h" -#include "class_58.h" -#include "class_38.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_12/class_30.h b/lib/waf/build/lib_12/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_31.cpp b/lib/waf/build/lib_12/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_81.h" -#include "class_18.h" -#include "class_34.h" -#include "class_7.h" -#include "class_20.h" -#include "class_88.h" -#include "class_84.h" -#include "class_5.h" -#include "class_25.h" -#include "class_82.h" -#include "class_42.h" -#include "class_30.h" -#include "class_83.h" -#include "class_0.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_12/class_31.h b/lib/waf/build/lib_12/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_32.cpp b/lib/waf/build/lib_12/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_83.h" -#include "class_93.h" -#include "class_20.h" -#include "class_75.h" -#include "class_85.h" -#include "class_87.h" -#include "class_97.h" -#include "class_19.h" -#include "class_28.h" -#include "class_86.h" -#include "class_0.h" -#include "class_61.h" -#include "class_98.h" -#include "class_26.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_12/class_32.h b/lib/waf/build/lib_12/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_33.cpp b/lib/waf/build/lib_12/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_62.h" -#include "class_49.h" -#include "class_33.h" -#include "class_52.h" -#include "class_83.h" -#include "class_85.h" -#include "class_61.h" -#include "class_95.h" -#include "class_13.h" -#include "class_79.h" -#include "class_38.h" -#include "class_70.h" -#include "class_4.h" -#include "class_57.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_12/class_33.h b/lib/waf/build/lib_12/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_34.cpp b/lib/waf/build/lib_12/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_27.h" -#include "class_64.h" -#include "class_96.h" -#include "class_32.h" -#include "class_29.h" -#include "class_10.h" -#include "class_92.h" -#include "class_30.h" -#include "class_52.h" -#include "class_62.h" -#include "class_98.h" -#include "class_73.h" -#include "class_9.h" -#include "class_16.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_12/class_34.h b/lib/waf/build/lib_12/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_35.cpp b/lib/waf/build/lib_12/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_75.h" -#include "class_10.h" -#include "class_27.h" -#include "class_16.h" -#include "class_82.h" -#include "class_93.h" -#include "class_39.h" -#include "class_15.h" -#include "class_32.h" -#include "class_7.h" -#include "class_41.h" -#include "class_63.h" -#include "class_44.h" -#include "class_72.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_12/class_35.h b/lib/waf/build/lib_12/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_36.cpp b/lib/waf/build/lib_12/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_4.h" -#include "class_54.h" -#include "class_26.h" -#include "class_18.h" -#include "class_67.h" -#include "class_38.h" -#include "class_32.h" -#include "class_35.h" -#include "class_98.h" -#include "class_8.h" -#include "class_91.h" -#include "class_9.h" -#include "class_83.h" -#include "class_86.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_12/class_36.h b/lib/waf/build/lib_12/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_37.cpp b/lib/waf/build/lib_12/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_0.h" -#include "class_64.h" -#include "class_59.h" -#include "class_92.h" -#include "class_21.h" -#include "class_56.h" -#include "class_51.h" -#include "class_54.h" -#include "class_60.h" -#include "class_65.h" -#include "class_37.h" -#include "class_13.h" -#include "class_80.h" -#include "class_72.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_12/class_37.h b/lib/waf/build/lib_12/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_38.cpp b/lib/waf/build/lib_12/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_22.h" -#include "class_69.h" -#include "class_50.h" -#include "class_11.h" -#include "class_84.h" -#include "class_27.h" -#include "class_23.h" -#include "class_12.h" -#include "class_87.h" -#include "class_34.h" -#include "class_63.h" -#include "class_32.h" -#include "class_26.h" -#include "class_97.h" -#include "class_93.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_12/class_38.h b/lib/waf/build/lib_12/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_39.cpp b/lib/waf/build/lib_12/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_19.h" -#include "class_38.h" -#include "class_46.h" -#include "class_30.h" -#include "class_92.h" -#include "class_69.h" -#include "class_56.h" -#include "class_25.h" -#include "class_55.h" -#include "class_66.h" -#include "class_6.h" -#include "class_67.h" -#include "class_43.h" -#include "class_75.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_12/class_39.h b/lib/waf/build/lib_12/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_4.cpp b/lib/waf/build/lib_12/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_96.h" -#include "class_40.h" -#include "class_99.h" -#include "class_5.h" -#include "class_36.h" -#include "class_85.h" -#include "class_18.h" -#include "class_50.h" -#include "class_12.h" -#include "class_93.h" -#include "class_24.h" -#include "class_66.h" -#include "class_39.h" -#include "class_17.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_12/class_4.h b/lib/waf/build/lib_12/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_40.cpp b/lib/waf/build/lib_12/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_34.h" -#include "class_44.h" -#include "class_97.h" -#include "class_61.h" -#include "class_84.h" -#include "class_43.h" -#include "class_81.h" -#include "class_16.h" -#include "class_71.h" -#include "class_88.h" -#include "class_85.h" -#include "class_11.h" -#include "class_65.h" -#include "class_96.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_12/class_40.h b/lib/waf/build/lib_12/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_41.cpp b/lib/waf/build/lib_12/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_49.h" -#include "class_64.h" -#include "class_96.h" -#include "class_22.h" -#include "class_10.h" -#include "class_30.h" -#include "class_54.h" -#include "class_3.h" -#include "class_47.h" -#include "class_11.h" -#include "class_97.h" -#include "class_40.h" -#include "class_25.h" -#include "class_89.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_12/class_41.h b/lib/waf/build/lib_12/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_42.cpp b/lib/waf/build/lib_12/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_44.h" -#include "class_77.h" -#include "class_58.h" -#include "class_5.h" -#include "class_21.h" -#include "class_23.h" -#include "class_98.h" -#include "class_0.h" -#include "class_65.h" -#include "class_50.h" -#include "class_86.h" -#include "class_29.h" -#include "class_51.h" -#include "class_10.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_12/class_42.h b/lib/waf/build/lib_12/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_43.cpp b/lib/waf/build/lib_12/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_14.h" -#include "class_73.h" -#include "class_10.h" -#include "class_90.h" -#include "class_2.h" -#include "class_35.h" -#include "class_63.h" -#include "class_57.h" -#include "class_70.h" -#include "class_3.h" -#include "class_18.h" -#include "class_5.h" -#include "class_56.h" -#include "class_92.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_12/class_43.h b/lib/waf/build/lib_12/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_44.cpp b/lib/waf/build/lib_12/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_89.h" -#include "class_70.h" -#include "class_75.h" -#include "class_83.h" -#include "class_80.h" -#include "class_47.h" -#include "class_39.h" -#include "class_68.h" -#include "class_76.h" -#include "class_66.h" -#include "class_64.h" -#include "class_12.h" -#include "class_71.h" -#include "class_57.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_12/class_44.h b/lib/waf/build/lib_12/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_45.cpp b/lib/waf/build/lib_12/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_5.h" -#include "class_2.h" -#include "class_68.h" -#include "class_72.h" -#include "class_51.h" -#include "class_8.h" -#include "class_47.h" -#include "class_54.h" -#include "class_16.h" -#include "class_75.h" -#include "class_81.h" -#include "class_97.h" -#include "class_36.h" -#include "class_7.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_12/class_45.h b/lib/waf/build/lib_12/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_46.cpp b/lib/waf/build/lib_12/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_26.h" -#include "class_33.h" -#include "class_62.h" -#include "class_38.h" -#include "class_6.h" -#include "class_5.h" -#include "class_0.h" -#include "class_12.h" -#include "class_54.h" -#include "class_99.h" -#include "class_2.h" -#include "class_9.h" -#include "class_10.h" -#include "class_8.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_12/class_46.h b/lib/waf/build/lib_12/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_47.cpp b/lib/waf/build/lib_12/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_6.h" -#include "class_39.h" -#include "class_64.h" -#include "class_47.h" -#include "class_89.h" -#include "class_92.h" -#include "class_19.h" -#include "class_67.h" -#include "class_80.h" -#include "class_72.h" -#include "class_18.h" -#include "class_68.h" -#include "class_75.h" -#include "class_4.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_12/class_47.h b/lib/waf/build/lib_12/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_48.cpp b/lib/waf/build/lib_12/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_34.h" -#include "class_32.h" -#include "class_95.h" -#include "class_35.h" -#include "class_60.h" -#include "class_89.h" -#include "class_28.h" -#include "class_29.h" -#include "class_9.h" -#include "class_42.h" -#include "class_13.h" -#include "class_10.h" -#include "class_81.h" -#include "class_43.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_12/class_48.h b/lib/waf/build/lib_12/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_49.cpp b/lib/waf/build/lib_12/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_23.h" -#include "class_67.h" -#include "class_93.h" -#include "class_87.h" -#include "class_6.h" -#include "class_42.h" -#include "class_61.h" -#include "class_76.h" -#include "class_63.h" -#include "class_90.h" -#include "class_95.h" -#include "class_75.h" -#include "class_32.h" -#include "class_81.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_12/class_49.h b/lib/waf/build/lib_12/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_5.cpp b/lib/waf/build/lib_12/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_9.h" -#include "class_53.h" -#include "class_7.h" -#include "class_67.h" -#include "class_47.h" -#include "class_5.h" -#include "class_96.h" -#include "class_84.h" -#include "class_32.h" -#include "class_11.h" -#include "class_79.h" -#include "class_8.h" -#include "class_18.h" -#include "class_33.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_12/class_5.h b/lib/waf/build/lib_12/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_50.cpp b/lib/waf/build/lib_12/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_95.h" -#include "class_76.h" -#include "class_38.h" -#include "class_5.h" -#include "class_26.h" -#include "class_23.h" -#include "class_78.h" -#include "class_47.h" -#include "class_6.h" -#include "class_96.h" -#include "class_62.h" -#include "class_69.h" -#include "class_80.h" -#include "class_25.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_12/class_50.h b/lib/waf/build/lib_12/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_51.cpp b/lib/waf/build/lib_12/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_26.h" -#include "class_63.h" -#include "class_56.h" -#include "class_9.h" -#include "class_53.h" -#include "class_3.h" -#include "class_80.h" -#include "class_70.h" -#include "class_93.h" -#include "class_96.h" -#include "class_83.h" -#include "class_41.h" -#include "class_15.h" -#include "class_11.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_12/class_51.h b/lib/waf/build/lib_12/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_52.cpp b/lib/waf/build/lib_12/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_67.h" -#include "class_1.h" -#include "class_44.h" -#include "class_59.h" -#include "class_68.h" -#include "class_22.h" -#include "class_73.h" -#include "class_75.h" -#include "class_77.h" -#include "class_6.h" -#include "class_16.h" -#include "class_69.h" -#include "class_4.h" -#include "class_14.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_12/class_52.h b/lib/waf/build/lib_12/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_53.cpp b/lib/waf/build/lib_12/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_44.h" -#include "class_82.h" -#include "class_1.h" -#include "class_84.h" -#include "class_0.h" -#include "class_53.h" -#include "class_39.h" -#include "class_64.h" -#include "class_61.h" -#include "class_80.h" -#include "class_60.h" -#include "class_72.h" -#include "class_69.h" -#include "class_14.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_12/class_53.h b/lib/waf/build/lib_12/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_54.cpp b/lib/waf/build/lib_12/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_20.h" -#include "class_64.h" -#include "class_68.h" -#include "class_91.h" -#include "class_55.h" -#include "class_29.h" -#include "class_36.h" -#include "class_42.h" -#include "class_41.h" -#include "class_6.h" -#include "class_12.h" -#include "class_57.h" -#include "class_58.h" -#include "class_22.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_12/class_54.h b/lib/waf/build/lib_12/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_55.cpp b/lib/waf/build/lib_12/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_86.h" -#include "class_39.h" -#include "class_2.h" -#include "class_61.h" -#include "class_64.h" -#include "class_77.h" -#include "class_52.h" -#include "class_72.h" -#include "class_24.h" -#include "class_51.h" -#include "class_57.h" -#include "class_11.h" -#include "class_49.h" -#include "class_58.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_12/class_55.h b/lib/waf/build/lib_12/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_56.cpp b/lib/waf/build/lib_12/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_7.h" -#include "class_85.h" -#include "class_94.h" -#include "class_65.h" -#include "class_81.h" -#include "class_56.h" -#include "class_71.h" -#include "class_57.h" -#include "class_50.h" -#include "class_70.h" -#include "class_17.h" -#include "class_61.h" -#include "class_15.h" -#include "class_68.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_12/class_56.h b/lib/waf/build/lib_12/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_57.cpp b/lib/waf/build/lib_12/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_81.h" -#include "class_6.h" -#include "class_51.h" -#include "class_5.h" -#include "class_50.h" -#include "class_86.h" -#include "class_93.h" -#include "class_52.h" -#include "class_0.h" -#include "class_20.h" -#include "class_26.h" -#include "class_36.h" -#include "class_37.h" -#include "class_38.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_12/class_57.h b/lib/waf/build/lib_12/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_58.cpp b/lib/waf/build/lib_12/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_62.h" -#include "class_21.h" -#include "class_12.h" -#include "class_5.h" -#include "class_93.h" -#include "class_64.h" -#include "class_17.h" -#include "class_83.h" -#include "class_1.h" -#include "class_76.h" -#include "class_18.h" -#include "class_89.h" -#include "class_71.h" -#include "class_35.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_12/class_58.h b/lib/waf/build/lib_12/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_59.cpp b/lib/waf/build/lib_12/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_87.h" -#include "class_46.h" -#include "class_88.h" -#include "class_85.h" -#include "class_48.h" -#include "class_77.h" -#include "class_54.h" -#include "class_61.h" -#include "class_50.h" -#include "class_19.h" -#include "class_98.h" -#include "class_92.h" -#include "class_56.h" -#include "class_97.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_12/class_59.h b/lib/waf/build/lib_12/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_6.cpp b/lib/waf/build/lib_12/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_44.h" -#include "class_66.h" -#include "class_18.h" -#include "class_75.h" -#include "class_35.h" -#include "class_13.h" -#include "class_40.h" -#include "class_73.h" -#include "class_50.h" -#include "class_24.h" -#include "class_51.h" -#include "class_85.h" -#include "class_76.h" -#include "class_1.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_12/class_6.h b/lib/waf/build/lib_12/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_60.cpp b/lib/waf/build/lib_12/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_97.h" -#include "class_0.h" -#include "class_39.h" -#include "class_70.h" -#include "class_37.h" -#include "class_17.h" -#include "class_21.h" -#include "class_6.h" -#include "class_20.h" -#include "class_53.h" -#include "class_75.h" -#include "class_78.h" -#include "class_94.h" -#include "class_11.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_12/class_60.h b/lib/waf/build/lib_12/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_61.cpp b/lib/waf/build/lib_12/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_95.h" -#include "class_64.h" -#include "class_83.h" -#include "class_57.h" -#include "class_94.h" -#include "class_22.h" -#include "class_2.h" -#include "class_21.h" -#include "class_27.h" -#include "class_84.h" -#include "class_36.h" -#include "class_15.h" -#include "class_61.h" -#include "class_14.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_12/class_61.h b/lib/waf/build/lib_12/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_62.cpp b/lib/waf/build/lib_12/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_20.h" -#include "class_60.h" -#include "class_76.h" -#include "class_46.h" -#include "class_70.h" -#include "class_93.h" -#include "class_47.h" -#include "class_68.h" -#include "class_99.h" -#include "class_86.h" -#include "class_94.h" -#include "class_73.h" -#include "class_10.h" -#include "class_22.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_12/class_62.h b/lib/waf/build/lib_12/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_63.cpp b/lib/waf/build/lib_12/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_73.h" -#include "class_29.h" -#include "class_33.h" -#include "class_49.h" -#include "class_16.h" -#include "class_92.h" -#include "class_25.h" -#include "class_39.h" -#include "class_87.h" -#include "class_32.h" -#include "class_51.h" -#include "class_17.h" -#include "class_99.h" -#include "class_21.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_12/class_63.h b/lib/waf/build/lib_12/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_64.cpp b/lib/waf/build/lib_12/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_50.h" -#include "class_60.h" -#include "class_43.h" -#include "class_15.h" -#include "class_98.h" -#include "class_75.h" -#include "class_96.h" -#include "class_19.h" -#include "class_46.h" -#include "class_61.h" -#include "class_99.h" -#include "class_1.h" -#include "class_91.h" -#include "class_27.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_12/class_64.h b/lib/waf/build/lib_12/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_65.cpp b/lib/waf/build/lib_12/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_15.h" -#include "class_31.h" -#include "class_68.h" -#include "class_89.h" -#include "class_81.h" -#include "class_0.h" -#include "class_75.h" -#include "class_36.h" -#include "class_3.h" -#include "class_37.h" -#include "class_13.h" -#include "class_6.h" -#include "class_65.h" -#include "class_82.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_12/class_65.h b/lib/waf/build/lib_12/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_66.cpp b/lib/waf/build/lib_12/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_35.h" -#include "class_99.h" -#include "class_62.h" -#include "class_41.h" -#include "class_68.h" -#include "class_37.h" -#include "class_77.h" -#include "class_17.h" -#include "class_24.h" -#include "class_12.h" -#include "class_53.h" -#include "class_44.h" -#include "class_39.h" -#include "class_72.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_12/class_66.h b/lib/waf/build/lib_12/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_67.cpp b/lib/waf/build/lib_12/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_31.h" -#include "class_14.h" -#include "class_90.h" -#include "class_71.h" -#include "class_55.h" -#include "class_58.h" -#include "class_84.h" -#include "class_15.h" -#include "class_91.h" -#include "class_12.h" -#include "class_44.h" -#include "class_60.h" -#include "class_8.h" -#include "class_47.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_12/class_67.h b/lib/waf/build/lib_12/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_68.cpp b/lib/waf/build/lib_12/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_16.h" -#include "class_48.h" -#include "class_70.h" -#include "class_21.h" -#include "class_87.h" -#include "class_24.h" -#include "class_54.h" -#include "class_80.h" -#include "class_73.h" -#include "class_62.h" -#include "class_14.h" -#include "class_38.h" -#include "class_93.h" -#include "class_85.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_12/class_68.h b/lib/waf/build/lib_12/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_69.cpp b/lib/waf/build/lib_12/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_16.h" -#include "class_44.h" -#include "class_35.h" -#include "class_65.h" -#include "class_4.h" -#include "class_93.h" -#include "class_82.h" -#include "class_54.h" -#include "class_70.h" -#include "class_46.h" -#include "class_1.h" -#include "class_89.h" -#include "class_20.h" -#include "class_64.h" -#include "class_91.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_12/class_69.h b/lib/waf/build/lib_12/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_7.cpp b/lib/waf/build/lib_12/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_60.h" -#include "class_19.h" -#include "class_77.h" -#include "class_13.h" -#include "class_24.h" -#include "class_11.h" -#include "class_94.h" -#include "class_76.h" -#include "class_31.h" -#include "class_15.h" -#include "class_82.h" -#include "class_83.h" -#include "class_39.h" -#include "class_16.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_12/class_7.h b/lib/waf/build/lib_12/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_70.cpp b/lib/waf/build/lib_12/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_76.h" -#include "class_63.h" -#include "class_61.h" -#include "class_74.h" -#include "class_88.h" -#include "class_58.h" -#include "class_51.h" -#include "class_89.h" -#include "class_97.h" -#include "class_11.h" -#include "class_93.h" -#include "class_72.h" -#include "class_36.h" -#include "class_34.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_12/class_70.h b/lib/waf/build/lib_12/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_71.cpp b/lib/waf/build/lib_12/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_0.h" -#include "class_51.h" -#include "class_14.h" -#include "class_45.h" -#include "class_68.h" -#include "class_13.h" -#include "class_34.h" -#include "class_50.h" -#include "class_61.h" -#include "class_31.h" -#include "class_22.h" -#include "class_35.h" -#include "class_46.h" -#include "class_43.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_12/class_71.h b/lib/waf/build/lib_12/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_72.cpp b/lib/waf/build/lib_12/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_53.h" -#include "class_26.h" -#include "class_88.h" -#include "class_31.h" -#include "class_34.h" -#include "class_60.h" -#include "class_52.h" -#include "class_49.h" -#include "class_17.h" -#include "class_59.h" -#include "class_7.h" -#include "class_66.h" -#include "class_82.h" -#include "class_83.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_12/class_72.h b/lib/waf/build/lib_12/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_73.cpp b/lib/waf/build/lib_12/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_78.h" -#include "class_32.h" -#include "class_87.h" -#include "class_7.h" -#include "class_30.h" -#include "class_26.h" -#include "class_14.h" -#include "class_57.h" -#include "class_58.h" -#include "class_16.h" -#include "class_34.h" -#include "class_93.h" -#include "class_60.h" -#include "class_59.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_12/class_73.h b/lib/waf/build/lib_12/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_74.cpp b/lib/waf/build/lib_12/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_52.h" -#include "class_80.h" -#include "class_86.h" -#include "class_51.h" -#include "class_32.h" -#include "class_61.h" -#include "class_3.h" -#include "class_72.h" -#include "class_71.h" -#include "class_91.h" -#include "class_62.h" -#include "class_7.h" -#include "class_76.h" -#include "class_89.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_12/class_74.h b/lib/waf/build/lib_12/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_75.cpp b/lib/waf/build/lib_12/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_47.h" -#include "class_45.h" -#include "class_67.h" -#include "class_1.h" -#include "class_15.h" -#include "class_92.h" -#include "class_98.h" -#include "class_41.h" -#include "class_80.h" -#include "class_90.h" -#include "class_49.h" -#include "class_30.h" -#include "class_6.h" -#include "class_65.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_12/class_75.h b/lib/waf/build/lib_12/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_76.cpp b/lib/waf/build/lib_12/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_99.h" -#include "class_79.h" -#include "class_50.h" -#include "class_31.h" -#include "class_98.h" -#include "class_24.h" -#include "class_22.h" -#include "class_9.h" -#include "class_33.h" -#include "class_14.h" -#include "class_26.h" -#include "class_10.h" -#include "class_62.h" -#include "class_85.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_12/class_76.h b/lib/waf/build/lib_12/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_77.cpp b/lib/waf/build/lib_12/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_76.h" -#include "class_23.h" -#include "class_16.h" -#include "class_56.h" -#include "class_48.h" -#include "class_75.h" -#include "class_72.h" -#include "class_30.h" -#include "class_91.h" -#include "class_43.h" -#include "class_80.h" -#include "class_68.h" -#include "class_85.h" -#include "class_55.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_12/class_77.h b/lib/waf/build/lib_12/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_78.cpp b/lib/waf/build/lib_12/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_11.h" -#include "class_25.h" -#include "class_91.h" -#include "class_69.h" -#include "class_98.h" -#include "class_64.h" -#include "class_39.h" -#include "class_48.h" -#include "class_59.h" -#include "class_89.h" -#include "class_4.h" -#include "class_35.h" -#include "class_42.h" -#include "class_94.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_12/class_78.h b/lib/waf/build/lib_12/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_79.cpp b/lib/waf/build/lib_12/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_26.h" -#include "class_46.h" -#include "class_47.h" -#include "class_59.h" -#include "class_91.h" -#include "class_60.h" -#include "class_16.h" -#include "class_78.h" -#include "class_9.h" -#include "class_2.h" -#include "class_94.h" -#include "class_28.h" -#include "class_31.h" -#include "class_68.h" -#include "class_22.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_12/class_79.h b/lib/waf/build/lib_12/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_8.cpp b/lib/waf/build/lib_12/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_53.h" -#include "class_28.h" -#include "class_77.h" -#include "class_42.h" -#include "class_64.h" -#include "class_91.h" -#include "class_94.h" -#include "class_58.h" -#include "class_95.h" -#include "class_86.h" -#include "class_71.h" -#include "class_12.h" -#include "class_46.h" -#include "class_36.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_12/class_8.h b/lib/waf/build/lib_12/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_80.cpp b/lib/waf/build/lib_12/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_18.h" -#include "class_45.h" -#include "class_64.h" -#include "class_17.h" -#include "class_40.h" -#include "class_25.h" -#include "class_92.h" -#include "class_36.h" -#include "class_60.h" -#include "class_85.h" -#include "class_4.h" -#include "class_65.h" -#include "class_29.h" -#include "class_42.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_12/class_80.h b/lib/waf/build/lib_12/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_81.cpp b/lib/waf/build/lib_12/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_17.h" -#include "class_42.h" -#include "class_78.h" -#include "class_97.h" -#include "class_36.h" -#include "class_96.h" -#include "class_10.h" -#include "class_33.h" -#include "class_31.h" -#include "class_68.h" -#include "class_57.h" -#include "class_45.h" -#include "class_60.h" -#include "class_47.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_12/class_81.h b/lib/waf/build/lib_12/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_82.cpp b/lib/waf/build/lib_12/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_3.h" -#include "class_45.h" -#include "class_59.h" -#include "class_65.h" -#include "class_95.h" -#include "class_39.h" -#include "class_41.h" -#include "class_91.h" -#include "class_58.h" -#include "class_43.h" -#include "class_46.h" -#include "class_1.h" -#include "class_0.h" -#include "class_61.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_12/class_82.h b/lib/waf/build/lib_12/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_83.cpp b/lib/waf/build/lib_12/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_96.h" -#include "class_51.h" -#include "class_82.h" -#include "class_68.h" -#include "class_24.h" -#include "class_72.h" -#include "class_35.h" -#include "class_98.h" -#include "class_34.h" -#include "class_58.h" -#include "class_25.h" -#include "class_12.h" -#include "class_61.h" -#include "class_11.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_12/class_83.h b/lib/waf/build/lib_12/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_84.cpp b/lib/waf/build/lib_12/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_64.h" -#include "class_39.h" -#include "class_7.h" -#include "class_95.h" -#include "class_32.h" -#include "class_88.h" -#include "class_87.h" -#include "class_41.h" -#include "class_22.h" -#include "class_55.h" -#include "class_90.h" -#include "class_60.h" -#include "class_21.h" -#include "class_75.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_12/class_84.h b/lib/waf/build/lib_12/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_85.cpp b/lib/waf/build/lib_12/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_80.h" -#include "class_40.h" -#include "class_66.h" -#include "class_11.h" -#include "class_79.h" -#include "class_48.h" -#include "class_6.h" -#include "class_53.h" -#include "class_57.h" -#include "class_37.h" -#include "class_77.h" -#include "class_78.h" -#include "class_85.h" -#include "class_13.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_12/class_85.h b/lib/waf/build/lib_12/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_86.cpp b/lib/waf/build/lib_12/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_37.h" -#include "class_97.h" -#include "class_78.h" -#include "class_64.h" -#include "class_54.h" -#include "class_53.h" -#include "class_0.h" -#include "class_60.h" -#include "class_28.h" -#include "class_15.h" -#include "class_94.h" -#include "class_41.h" -#include "class_77.h" -#include "class_2.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_12/class_86.h b/lib/waf/build/lib_12/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_87.cpp b/lib/waf/build/lib_12/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_76.h" -#include "class_71.h" -#include "class_11.h" -#include "class_20.h" -#include "class_29.h" -#include "class_93.h" -#include "class_74.h" -#include "class_15.h" -#include "class_79.h" -#include "class_96.h" -#include "class_80.h" -#include "class_7.h" -#include "class_87.h" -#include "class_99.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_12/class_87.h b/lib/waf/build/lib_12/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_88.cpp b/lib/waf/build/lib_12/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_81.h" -#include "class_36.h" -#include "class_20.h" -#include "class_71.h" -#include "class_89.h" -#include "class_82.h" -#include "class_31.h" -#include "class_68.h" -#include "class_79.h" -#include "class_25.h" -#include "class_83.h" -#include "class_97.h" -#include "class_64.h" -#include "class_38.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_12/class_88.h b/lib/waf/build/lib_12/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_89.cpp b/lib/waf/build/lib_12/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_55.h" -#include "class_46.h" -#include "class_29.h" -#include "class_81.h" -#include "class_82.h" -#include "class_43.h" -#include "class_27.h" -#include "class_52.h" -#include "class_87.h" -#include "class_32.h" -#include "class_65.h" -#include "class_39.h" -#include "class_84.h" -#include "class_99.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_12/class_89.h b/lib/waf/build/lib_12/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_9.cpp b/lib/waf/build/lib_12/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_35.h" -#include "class_90.h" -#include "class_42.h" -#include "class_69.h" -#include "class_43.h" -#include "class_26.h" -#include "class_97.h" -#include "class_88.h" -#include "class_82.h" -#include "class_58.h" -#include "class_25.h" -#include "class_9.h" -#include "class_63.h" -#include "class_89.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_12/class_9.h b/lib/waf/build/lib_12/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_90.cpp b/lib/waf/build/lib_12/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_51.h" -#include "class_0.h" -#include "class_82.h" -#include "class_11.h" -#include "class_75.h" -#include "class_60.h" -#include "class_86.h" -#include "class_38.h" -#include "class_79.h" -#include "class_77.h" -#include "class_54.h" -#include "class_12.h" -#include "class_2.h" -#include "class_34.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_12/class_90.h b/lib/waf/build/lib_12/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_91.cpp b/lib/waf/build/lib_12/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_50.h" -#include "class_10.h" -#include "class_72.h" -#include "class_49.h" -#include "class_24.h" -#include "class_58.h" -#include "class_53.h" -#include "class_6.h" -#include "class_80.h" -#include "class_39.h" -#include "class_44.h" -#include "class_90.h" -#include "class_63.h" -#include "class_71.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_12/class_91.h b/lib/waf/build/lib_12/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_92.cpp b/lib/waf/build/lib_12/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_73.h" -#include "class_79.h" -#include "class_54.h" -#include "class_67.h" -#include "class_66.h" -#include "class_96.h" -#include "class_3.h" -#include "class_52.h" -#include "class_28.h" -#include "class_85.h" -#include "class_21.h" -#include "class_58.h" -#include "class_80.h" -#include "class_83.h" -#include "class_99.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_12/class_92.h b/lib/waf/build/lib_12/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_93.cpp b/lib/waf/build/lib_12/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_83.h" -#include "class_92.h" -#include "class_13.h" -#include "class_62.h" -#include "class_43.h" -#include "class_36.h" -#include "class_95.h" -#include "class_63.h" -#include "class_44.h" -#include "class_68.h" -#include "class_73.h" -#include "class_80.h" -#include "class_94.h" -#include "class_60.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_12/class_93.h b/lib/waf/build/lib_12/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_94.cpp b/lib/waf/build/lib_12/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_50.h" -#include "class_5.h" -#include "class_0.h" -#include "class_3.h" -#include "class_68.h" -#include "class_8.h" -#include "class_44.h" -#include "class_2.h" -#include "class_73.h" -#include "class_63.h" -#include "class_16.h" -#include "class_21.h" -#include "class_75.h" -#include "class_6.h" -#include "class_96.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_12/class_94.h b/lib/waf/build/lib_12/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_95.cpp b/lib/waf/build/lib_12/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_67.h" -#include "class_88.h" -#include "class_25.h" -#include "class_96.h" -#include "class_14.h" -#include "class_56.h" -#include "class_65.h" -#include "class_78.h" -#include "class_55.h" -#include "class_22.h" -#include "class_57.h" -#include "class_21.h" -#include "class_20.h" -#include "class_50.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_12/class_95.h b/lib/waf/build/lib_12/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_96.cpp b/lib/waf/build/lib_12/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_68.h" -#include "class_34.h" -#include "class_41.h" -#include "class_7.h" -#include "class_54.h" -#include "class_71.h" -#include "class_76.h" -#include "class_51.h" -#include "class_50.h" -#include "class_19.h" -#include "class_85.h" -#include "class_83.h" -#include "class_42.h" -#include "class_30.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_12/class_96.h b/lib/waf/build/lib_12/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_97.cpp b/lib/waf/build/lib_12/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_40.h" -#include "class_68.h" -#include "class_6.h" -#include "class_55.h" -#include "class_5.h" -#include "class_87.h" -#include "class_63.h" -#include "class_17.h" -#include "class_32.h" -#include "class_65.h" -#include "class_95.h" -#include "class_28.h" -#include "class_64.h" -#include "class_39.h" -#include "class_7.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_12/class_97.h b/lib/waf/build/lib_12/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_98.cpp b/lib/waf/build/lib_12/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_33.h" -#include "class_93.h" -#include "class_7.h" -#include "class_43.h" -#include "class_95.h" -#include "class_40.h" -#include "class_81.h" -#include "class_49.h" -#include "class_47.h" -#include "class_62.h" -#include "class_20.h" -#include "class_61.h" -#include "class_55.h" -#include "class_16.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_12/class_98.h b/lib/waf/build/lib_12/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_12/class_99.cpp b/lib/waf/build/lib_12/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_12/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_51.h" -#include "class_25.h" -#include "class_79.h" -#include "class_30.h" -#include "class_20.h" -#include "class_46.h" -#include "class_99.h" -#include "class_3.h" -#include "class_21.h" -#include "class_59.h" -#include "class_83.h" -#include "class_40.h" -#include "class_37.h" -#include "class_41.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_12/class_99.h b/lib/waf/build/lib_12/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_12/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_2/Makefile b/lib/waf/build/lib_2/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_2/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_2.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_2/Makefile.am b/lib/waf/build/lib_2/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_2/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib2.la -lib2_la_SOURCES = lib_2/class_0.cpp lib_2/class_1.cpp lib_2/class_2.cpp lib_2/class_3.cpp lib_2/class_4.cpp lib_2/class_5.cpp lib_2/class_6.cpp lib_2/class_7.cpp lib_2/class_8.cpp lib_2/class_9.cpp lib_2/class_10.cpp lib_2/class_11.cpp lib_2/class_12.cpp lib_2/class_13.cpp lib_2/class_14.cpp lib_2/class_15.cpp lib_2/class_16.cpp lib_2/class_17.cpp lib_2/class_18.cpp lib_2/class_19.cpp lib_2/class_20.cpp lib_2/class_21.cpp lib_2/class_22.cpp lib_2/class_23.cpp lib_2/class_24.cpp lib_2/class_25.cpp lib_2/class_26.cpp lib_2/class_27.cpp lib_2/class_28.cpp lib_2/class_29.cpp lib_2/class_30.cpp lib_2/class_31.cpp lib_2/class_32.cpp lib_2/class_33.cpp lib_2/class_34.cpp lib_2/class_35.cpp lib_2/class_36.cpp lib_2/class_37.cpp lib_2/class_38.cpp lib_2/class_39.cpp lib_2/class_40.cpp lib_2/class_41.cpp lib_2/class_42.cpp lib_2/class_43.cpp lib_2/class_44.cpp lib_2/class_45.cpp lib_2/class_46.cpp lib_2/class_47.cpp lib_2/class_48.cpp lib_2/class_49.cpp lib_2/class_50.cpp lib_2/class_51.cpp lib_2/class_52.cpp lib_2/class_53.cpp lib_2/class_54.cpp lib_2/class_55.cpp lib_2/class_56.cpp lib_2/class_57.cpp lib_2/class_58.cpp lib_2/class_59.cpp lib_2/class_60.cpp lib_2/class_61.cpp lib_2/class_62.cpp lib_2/class_63.cpp lib_2/class_64.cpp lib_2/class_65.cpp lib_2/class_66.cpp lib_2/class_67.cpp lib_2/class_68.cpp lib_2/class_69.cpp lib_2/class_70.cpp lib_2/class_71.cpp lib_2/class_72.cpp lib_2/class_73.cpp lib_2/class_74.cpp lib_2/class_75.cpp lib_2/class_76.cpp lib_2/class_77.cpp lib_2/class_78.cpp lib_2/class_79.cpp lib_2/class_80.cpp lib_2/class_81.cpp lib_2/class_82.cpp lib_2/class_83.cpp lib_2/class_84.cpp lib_2/class_85.cpp lib_2/class_86.cpp lib_2/class_87.cpp lib_2/class_88.cpp lib_2/class_89.cpp lib_2/class_90.cpp lib_2/class_91.cpp lib_2/class_92.cpp lib_2/class_93.cpp lib_2/class_94.cpp lib_2/class_95.cpp lib_2/class_96.cpp lib_2/class_97.cpp lib_2/class_98.cpp lib_2/class_99.cpp diff --git a/lib/waf/build/lib_2/SConscript b/lib/waf/build/lib_2/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_2/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_2", list) - diff --git a/lib/waf/build/lib_2/class_0.cpp b/lib/waf/build/lib_2/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_80.h" -#include "class_4.h" -#include "class_30.h" -#include "class_58.h" -#include "class_66.h" -#include "class_59.h" -#include "class_33.h" -#include "class_63.h" -#include "class_53.h" -#include "class_84.h" -#include "class_29.h" -#include "class_23.h" -#include "class_92.h" -#include "class_96.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_2/class_0.h b/lib/waf/build/lib_2/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_1.cpp b/lib/waf/build/lib_2/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_94.h" -#include "class_16.h" -#include "class_21.h" -#include "class_79.h" -#include "class_86.h" -#include "class_24.h" -#include "class_52.h" -#include "class_36.h" -#include "class_58.h" -#include "class_47.h" -#include "class_67.h" -#include "class_98.h" -#include "class_63.h" -#include "class_80.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_2/class_1.h b/lib/waf/build/lib_2/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_10.cpp b/lib/waf/build/lib_2/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_67.h" -#include "class_43.h" -#include "class_20.h" -#include "class_82.h" -#include "class_40.h" -#include "class_47.h" -#include "class_16.h" -#include "class_98.h" -#include "class_52.h" -#include "class_7.h" -#include "class_41.h" -#include "class_87.h" -#include "class_32.h" -#include "class_73.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_2/class_10.h b/lib/waf/build/lib_2/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_11.cpp b/lib/waf/build/lib_2/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_66.h" -#include "class_92.h" -#include "class_59.h" -#include "class_65.h" -#include "class_49.h" -#include "class_47.h" -#include "class_72.h" -#include "class_68.h" -#include "class_36.h" -#include "class_6.h" -#include "class_30.h" -#include "class_75.h" -#include "class_98.h" -#include "class_46.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_2/class_11.h b/lib/waf/build/lib_2/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_12.cpp b/lib/waf/build/lib_2/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_72.h" -#include "class_87.h" -#include "class_58.h" -#include "class_76.h" -#include "class_69.h" -#include "class_53.h" -#include "class_45.h" -#include "class_55.h" -#include "class_27.h" -#include "class_0.h" -#include "class_64.h" -#include "class_90.h" -#include "class_35.h" -#include "class_43.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_2/class_12.h b/lib/waf/build/lib_2/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_13.cpp b/lib/waf/build/lib_2/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_60.h" -#include "class_6.h" -#include "class_25.h" -#include "class_14.h" -#include "class_76.h" -#include "class_97.h" -#include "class_89.h" -#include "class_21.h" -#include "class_64.h" -#include "class_90.h" -#include "class_65.h" -#include "class_44.h" -#include "class_33.h" -#include "class_4.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_2/class_13.h b/lib/waf/build/lib_2/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_14.cpp b/lib/waf/build/lib_2/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_62.h" -#include "class_84.h" -#include "class_98.h" -#include "class_67.h" -#include "class_87.h" -#include "class_21.h" -#include "class_51.h" -#include "class_29.h" -#include "class_24.h" -#include "class_18.h" -#include "class_6.h" -#include "class_28.h" -#include "class_50.h" -#include "class_52.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_2/class_14.h b/lib/waf/build/lib_2/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_15.cpp b/lib/waf/build/lib_2/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_73.h" -#include "class_31.h" -#include "class_75.h" -#include "class_5.h" -#include "class_3.h" -#include "class_23.h" -#include "class_82.h" -#include "class_11.h" -#include "class_94.h" -#include "class_97.h" -#include "class_9.h" -#include "class_25.h" -#include "class_76.h" -#include "class_42.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_2/class_15.h b/lib/waf/build/lib_2/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_16.cpp b/lib/waf/build/lib_2/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_5.h" -#include "class_40.h" -#include "class_94.h" -#include "class_79.h" -#include "class_27.h" -#include "class_89.h" -#include "class_13.h" -#include "class_33.h" -#include "class_20.h" -#include "class_42.h" -#include "class_53.h" -#include "class_7.h" -#include "class_17.h" -#include "class_61.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_2/class_16.h b/lib/waf/build/lib_2/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_17.cpp b/lib/waf/build/lib_2/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_91.h" -#include "class_96.h" -#include "class_89.h" -#include "class_35.h" -#include "class_86.h" -#include "class_31.h" -#include "class_71.h" -#include "class_69.h" -#include "class_60.h" -#include "class_90.h" -#include "class_79.h" -#include "class_81.h" -#include "class_42.h" -#include "class_88.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_2/class_17.h b/lib/waf/build/lib_2/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_18.cpp b/lib/waf/build/lib_2/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_66.h" -#include "class_79.h" -#include "class_6.h" -#include "class_37.h" -#include "class_20.h" -#include "class_19.h" -#include "class_33.h" -#include "class_85.h" -#include "class_84.h" -#include "class_78.h" -#include "class_54.h" -#include "class_4.h" -#include "class_15.h" -#include "class_35.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_2/class_18.h b/lib/waf/build/lib_2/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_19.cpp b/lib/waf/build/lib_2/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_35.h" -#include "class_12.h" -#include "class_93.h" -#include "class_70.h" -#include "class_69.h" -#include "class_32.h" -#include "class_20.h" -#include "class_71.h" -#include "class_28.h" -#include "class_61.h" -#include "class_9.h" -#include "class_43.h" -#include "class_63.h" -#include "class_55.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_2/class_19.h b/lib/waf/build/lib_2/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_2.cpp b/lib/waf/build/lib_2/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_92.h" -#include "class_66.h" -#include "class_57.h" -#include "class_1.h" -#include "class_8.h" -#include "class_15.h" -#include "class_61.h" -#include "class_55.h" -#include "class_16.h" -#include "class_85.h" -#include "class_33.h" -#include "class_13.h" -#include "class_29.h" -#include "class_75.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_2/class_2.h b/lib/waf/build/lib_2/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_20.cpp b/lib/waf/build/lib_2/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_85.h" -#include "class_0.h" -#include "class_61.h" -#include "class_34.h" -#include "class_41.h" -#include "class_73.h" -#include "class_43.h" -#include "class_54.h" -#include "class_69.h" -#include "class_66.h" -#include "class_47.h" -#include "class_53.h" -#include "class_64.h" -#include "class_1.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_2/class_20.h b/lib/waf/build/lib_2/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_21.cpp b/lib/waf/build/lib_2/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_30.h" -#include "class_38.h" -#include "class_86.h" -#include "class_53.h" -#include "class_57.h" -#include "class_92.h" -#include "class_59.h" -#include "class_46.h" -#include "class_17.h" -#include "class_19.h" -#include "class_50.h" -#include "class_4.h" -#include "class_88.h" -#include "class_83.h" -#include "class_75.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_2/class_21.h b/lib/waf/build/lib_2/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_22.cpp b/lib/waf/build/lib_2/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_47.h" -#include "class_42.h" -#include "class_76.h" -#include "class_97.h" -#include "class_3.h" -#include "class_92.h" -#include "class_73.h" -#include "class_38.h" -#include "class_23.h" -#include "class_58.h" -#include "class_53.h" -#include "class_94.h" -#include "class_77.h" -#include "class_87.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_2/class_22.h b/lib/waf/build/lib_2/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_23.cpp b/lib/waf/build/lib_2/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_36.h" -#include "class_39.h" -#include "class_77.h" -#include "class_67.h" -#include "class_85.h" -#include "class_80.h" -#include "class_48.h" -#include "class_10.h" -#include "class_42.h" -#include "class_78.h" -#include "class_84.h" -#include "class_81.h" -#include "class_75.h" -#include "class_0.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_2/class_23.h b/lib/waf/build/lib_2/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_24.cpp b/lib/waf/build/lib_2/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_64.h" -#include "class_41.h" -#include "class_11.h" -#include "class_20.h" -#include "class_29.h" -#include "class_21.h" -#include "class_93.h" -#include "class_23.h" -#include "class_69.h" -#include "class_97.h" -#include "class_63.h" -#include "class_81.h" -#include "class_15.h" -#include "class_49.h" -#include "class_75.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_2/class_24.h b/lib/waf/build/lib_2/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_25.cpp b/lib/waf/build/lib_2/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_98.h" -#include "class_30.h" -#include "class_18.h" -#include "class_32.h" -#include "class_96.h" -#include "class_29.h" -#include "class_45.h" -#include "class_85.h" -#include "class_17.h" -#include "class_26.h" -#include "class_41.h" -#include "class_43.h" -#include "class_6.h" -#include "class_89.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_2/class_25.h b/lib/waf/build/lib_2/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_26.cpp b/lib/waf/build/lib_2/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_43.h" -#include "class_34.h" -#include "class_65.h" -#include "class_45.h" -#include "class_11.h" -#include "class_67.h" -#include "class_97.h" -#include "class_41.h" -#include "class_3.h" -#include "class_54.h" -#include "class_63.h" -#include "class_35.h" -#include "class_89.h" -#include "class_95.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_2/class_26.h b/lib/waf/build/lib_2/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_27.cpp b/lib/waf/build/lib_2/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_40.h" -#include "class_54.h" -#include "class_26.h" -#include "class_33.h" -#include "class_45.h" -#include "class_72.h" -#include "class_14.h" -#include "class_58.h" -#include "class_59.h" -#include "class_97.h" -#include "class_60.h" -#include "class_48.h" -#include "class_61.h" -#include "class_53.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_2/class_27.h b/lib/waf/build/lib_2/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_28.cpp b/lib/waf/build/lib_2/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_71.h" -#include "class_14.h" -#include "class_78.h" -#include "class_19.h" -#include "class_20.h" -#include "class_61.h" -#include "class_38.h" -#include "class_16.h" -#include "class_68.h" -#include "class_90.h" -#include "class_9.h" -#include "class_98.h" -#include "class_30.h" -#include "class_2.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_2/class_28.h b/lib/waf/build/lib_2/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_29.cpp b/lib/waf/build/lib_2/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_36.h" -#include "class_53.h" -#include "class_77.h" -#include "class_14.h" -#include "class_47.h" -#include "class_85.h" -#include "class_88.h" -#include "class_52.h" -#include "class_79.h" -#include "class_68.h" -#include "class_81.h" -#include "class_7.h" -#include "class_9.h" -#include "class_4.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_2/class_29.h b/lib/waf/build/lib_2/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_3.cpp b/lib/waf/build/lib_2/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_80.h" -#include "class_97.h" -#include "class_65.h" -#include "class_3.h" -#include "class_0.h" -#include "class_39.h" -#include "class_9.h" -#include "class_86.h" -#include "class_2.h" -#include "class_67.h" -#include "class_46.h" -#include "class_50.h" -#include "class_25.h" -#include "class_37.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_2/class_3.h b/lib/waf/build/lib_2/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_30.cpp b/lib/waf/build/lib_2/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_47.h" -#include "class_77.h" -#include "class_54.h" -#include "class_41.h" -#include "class_42.h" -#include "class_55.h" -#include "class_24.h" -#include "class_97.h" -#include "class_86.h" -#include "class_33.h" -#include "class_53.h" -#include "class_64.h" -#include "class_49.h" -#include "class_17.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_2/class_30.h b/lib/waf/build/lib_2/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_31.cpp b/lib/waf/build/lib_2/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_5.h" -#include "class_95.h" -#include "class_18.h" -#include "class_82.h" -#include "class_99.h" -#include "class_88.h" -#include "class_63.h" -#include "class_15.h" -#include "class_59.h" -#include "class_67.h" -#include "class_92.h" -#include "class_68.h" -#include "class_16.h" -#include "class_3.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_2/class_31.h b/lib/waf/build/lib_2/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_32.cpp b/lib/waf/build/lib_2/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_96.h" -#include "class_60.h" -#include "class_59.h" -#include "class_3.h" -#include "class_53.h" -#include "class_11.h" -#include "class_81.h" -#include "class_93.h" -#include "class_56.h" -#include "class_29.h" -#include "class_90.h" -#include "class_10.h" -#include "class_78.h" -#include "class_4.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_2/class_32.h b/lib/waf/build/lib_2/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_33.cpp b/lib/waf/build/lib_2/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_1.h" -#include "class_92.h" -#include "class_56.h" -#include "class_44.h" -#include "class_45.h" -#include "class_78.h" -#include "class_31.h" -#include "class_42.h" -#include "class_19.h" -#include "class_48.h" -#include "class_77.h" -#include "class_4.h" -#include "class_84.h" -#include "class_15.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_2/class_33.h b/lib/waf/build/lib_2/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_34.cpp b/lib/waf/build/lib_2/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_75.h" -#include "class_67.h" -#include "class_5.h" -#include "class_10.h" -#include "class_52.h" -#include "class_56.h" -#include "class_71.h" -#include "class_61.h" -#include "class_0.h" -#include "class_93.h" -#include "class_25.h" -#include "class_45.h" -#include "class_97.h" -#include "class_30.h" -#include "class_65.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_2/class_34.h b/lib/waf/build/lib_2/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_35.cpp b/lib/waf/build/lib_2/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_12.h" -#include "class_62.h" -#include "class_39.h" -#include "class_37.h" -#include "class_58.h" -#include "class_60.h" -#include "class_1.h" -#include "class_9.h" -#include "class_4.h" -#include "class_3.h" -#include "class_21.h" -#include "class_91.h" -#include "class_7.h" -#include "class_19.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_2/class_35.h b/lib/waf/build/lib_2/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_36.cpp b/lib/waf/build/lib_2/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_11.h" -#include "class_60.h" -#include "class_43.h" -#include "class_69.h" -#include "class_44.h" -#include "class_0.h" -#include "class_24.h" -#include "class_93.h" -#include "class_83.h" -#include "class_75.h" -#include "class_31.h" -#include "class_72.h" -#include "class_27.h" -#include "class_3.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_2/class_36.h b/lib/waf/build/lib_2/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_37.cpp b/lib/waf/build/lib_2/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_39.h" -#include "class_62.h" -#include "class_80.h" -#include "class_43.h" -#include "class_45.h" -#include "class_87.h" -#include "class_58.h" -#include "class_77.h" -#include "class_54.h" -#include "class_69.h" -#include "class_83.h" -#include "class_18.h" -#include "class_70.h" -#include "class_71.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_2/class_37.h b/lib/waf/build/lib_2/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_38.cpp b/lib/waf/build/lib_2/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_49.h" -#include "class_81.h" -#include "class_70.h" -#include "class_8.h" -#include "class_75.h" -#include "class_50.h" -#include "class_22.h" -#include "class_45.h" -#include "class_82.h" -#include "class_86.h" -#include "class_42.h" -#include "class_17.h" -#include "class_40.h" -#include "class_79.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_2/class_38.h b/lib/waf/build/lib_2/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_39.cpp b/lib/waf/build/lib_2/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_49.h" -#include "class_63.h" -#include "class_4.h" -#include "class_41.h" -#include "class_60.h" -#include "class_84.h" -#include "class_32.h" -#include "class_31.h" -#include "class_16.h" -#include "class_99.h" -#include "class_7.h" -#include "class_78.h" -#include "class_98.h" -#include "class_92.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_2/class_39.h b/lib/waf/build/lib_2/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_4.cpp b/lib/waf/build/lib_2/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_55.h" -#include "class_39.h" -#include "class_27.h" -#include "class_73.h" -#include "class_5.h" -#include "class_95.h" -#include "class_98.h" -#include "class_89.h" -#include "class_88.h" -#include "class_60.h" -#include "class_83.h" -#include "class_18.h" -#include "class_45.h" -#include "class_2.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_2/class_4.h b/lib/waf/build/lib_2/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_40.cpp b/lib/waf/build/lib_2/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_29.h" -#include "class_70.h" -#include "class_35.h" -#include "class_66.h" -#include "class_1.h" -#include "class_2.h" -#include "class_46.h" -#include "class_91.h" -#include "class_4.h" -#include "class_8.h" -#include "class_99.h" -#include "class_31.h" -#include "class_7.h" -#include "class_6.h" -#include "class_22.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_2/class_40.h b/lib/waf/build/lib_2/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_41.cpp b/lib/waf/build/lib_2/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_73.h" -#include "class_72.h" -#include "class_40.h" -#include "class_85.h" -#include "class_2.h" -#include "class_35.h" -#include "class_82.h" -#include "class_17.h" -#include "class_19.h" -#include "class_5.h" -#include "class_88.h" -#include "class_77.h" -#include "class_54.h" -#include "class_84.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_2/class_41.h b/lib/waf/build/lib_2/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_42.cpp b/lib/waf/build/lib_2/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_61.h" -#include "class_81.h" -#include "class_29.h" -#include "class_39.h" -#include "class_69.h" -#include "class_7.h" -#include "class_47.h" -#include "class_26.h" -#include "class_3.h" -#include "class_36.h" -#include "class_89.h" -#include "class_56.h" -#include "class_23.h" -#include "class_30.h" -#include "class_52.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_2/class_42.h b/lib/waf/build/lib_2/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_43.cpp b/lib/waf/build/lib_2/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_27.h" -#include "class_37.h" -#include "class_94.h" -#include "class_52.h" -#include "class_64.h" -#include "class_70.h" -#include "class_92.h" -#include "class_41.h" -#include "class_77.h" -#include "class_44.h" -#include "class_34.h" -#include "class_73.h" -#include "class_61.h" -#include "class_30.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_2/class_43.h b/lib/waf/build/lib_2/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_44.cpp b/lib/waf/build/lib_2/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_9.h" -#include "class_29.h" -#include "class_49.h" -#include "class_88.h" -#include "class_5.h" -#include "class_54.h" -#include "class_86.h" -#include "class_37.h" -#include "class_47.h" -#include "class_66.h" -#include "class_22.h" -#include "class_63.h" -#include "class_44.h" -#include "class_24.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_2/class_44.h b/lib/waf/build/lib_2/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_45.cpp b/lib/waf/build/lib_2/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_82.h" -#include "class_45.h" -#include "class_99.h" -#include "class_95.h" -#include "class_25.h" -#include "class_12.h" -#include "class_70.h" -#include "class_3.h" -#include "class_19.h" -#include "class_29.h" -#include "class_23.h" -#include "class_48.h" -#include "class_32.h" -#include "class_18.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_2/class_45.h b/lib/waf/build/lib_2/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_46.cpp b/lib/waf/build/lib_2/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_67.h" -#include "class_25.h" -#include "class_38.h" -#include "class_8.h" -#include "class_5.h" -#include "class_92.h" -#include "class_58.h" -#include "class_82.h" -#include "class_22.h" -#include "class_56.h" -#include "class_53.h" -#include "class_12.h" -#include "class_81.h" -#include "class_94.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_2/class_46.h b/lib/waf/build/lib_2/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_47.cpp b/lib/waf/build/lib_2/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_11.h" -#include "class_21.h" -#include "class_22.h" -#include "class_15.h" -#include "class_51.h" -#include "class_30.h" -#include "class_29.h" -#include "class_34.h" -#include "class_13.h" -#include "class_47.h" -#include "class_88.h" -#include "class_76.h" -#include "class_38.h" -#include "class_99.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_2/class_47.h b/lib/waf/build/lib_2/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_48.cpp b/lib/waf/build/lib_2/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_41.h" -#include "class_59.h" -#include "class_17.h" -#include "class_1.h" -#include "class_25.h" -#include "class_81.h" -#include "class_27.h" -#include "class_96.h" -#include "class_70.h" -#include "class_84.h" -#include "class_10.h" -#include "class_40.h" -#include "class_33.h" -#include "class_20.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_2/class_48.h b/lib/waf/build/lib_2/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_49.cpp b/lib/waf/build/lib_2/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_77.h" -#include "class_45.h" -#include "class_84.h" -#include "class_13.h" -#include "class_30.h" -#include "class_53.h" -#include "class_65.h" -#include "class_34.h" -#include "class_67.h" -#include "class_93.h" -#include "class_33.h" -#include "class_6.h" -#include "class_36.h" -#include "class_1.h" -#include "class_14.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_2/class_49.h b/lib/waf/build/lib_2/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_5.cpp b/lib/waf/build/lib_2/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_53.h" -#include "class_5.h" -#include "class_23.h" -#include "class_57.h" -#include "class_85.h" -#include "class_75.h" -#include "class_81.h" -#include "class_45.h" -#include "class_95.h" -#include "class_61.h" -#include "class_27.h" -#include "class_33.h" -#include "class_37.h" -#include "class_13.h" -#include "class_64.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_2/class_5.h b/lib/waf/build/lib_2/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_50.cpp b/lib/waf/build/lib_2/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_97.h" -#include "class_51.h" -#include "class_19.h" -#include "class_48.h" -#include "class_37.h" -#include "class_39.h" -#include "class_49.h" -#include "class_82.h" -#include "class_54.h" -#include "class_70.h" -#include "class_93.h" -#include "class_12.h" -#include "class_72.h" -#include "class_79.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_2/class_50.h b/lib/waf/build/lib_2/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_51.cpp b/lib/waf/build/lib_2/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_2.h" -#include "class_18.h" -#include "class_60.h" -#include "class_34.h" -#include "class_77.h" -#include "class_30.h" -#include "class_78.h" -#include "class_56.h" -#include "class_32.h" -#include "class_40.h" -#include "class_7.h" -#include "class_91.h" -#include "class_63.h" -#include "class_58.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_2/class_51.h b/lib/waf/build/lib_2/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_52.cpp b/lib/waf/build/lib_2/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_83.h" -#include "class_47.h" -#include "class_76.h" -#include "class_23.h" -#include "class_69.h" -#include "class_97.h" -#include "class_41.h" -#include "class_86.h" -#include "class_5.h" -#include "class_7.h" -#include "class_3.h" -#include "class_85.h" -#include "class_74.h" -#include "class_88.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_2/class_52.h b/lib/waf/build/lib_2/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_53.cpp b/lib/waf/build/lib_2/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_61.h" -#include "class_88.h" -#include "class_81.h" -#include "class_15.h" -#include "class_26.h" -#include "class_93.h" -#include "class_72.h" -#include "class_84.h" -#include "class_67.h" -#include "class_29.h" -#include "class_33.h" -#include "class_94.h" -#include "class_64.h" -#include "class_19.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_2/class_53.h b/lib/waf/build/lib_2/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_54.cpp b/lib/waf/build/lib_2/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_71.h" -#include "class_53.h" -#include "class_65.h" -#include "class_85.h" -#include "class_8.h" -#include "class_84.h" -#include "class_23.h" -#include "class_96.h" -#include "class_45.h" -#include "class_41.h" -#include "class_97.h" -#include "class_55.h" -#include "class_4.h" -#include "class_89.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_2/class_54.h b/lib/waf/build/lib_2/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_55.cpp b/lib/waf/build/lib_2/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_95.h" -#include "class_66.h" -#include "class_74.h" -#include "class_92.h" -#include "class_94.h" -#include "class_97.h" -#include "class_0.h" -#include "class_58.h" -#include "class_96.h" -#include "class_64.h" -#include "class_19.h" -#include "class_15.h" -#include "class_33.h" -#include "class_52.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_2/class_55.h b/lib/waf/build/lib_2/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_56.cpp b/lib/waf/build/lib_2/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_16.h" -#include "class_37.h" -#include "class_35.h" -#include "class_17.h" -#include "class_65.h" -#include "class_75.h" -#include "class_73.h" -#include "class_9.h" -#include "class_41.h" -#include "class_49.h" -#include "class_96.h" -#include "class_45.h" -#include "class_53.h" -#include "class_52.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_2/class_56.h b/lib/waf/build/lib_2/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_57.cpp b/lib/waf/build/lib_2/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_42.h" -#include "class_73.h" -#include "class_39.h" -#include "class_0.h" -#include "class_28.h" -#include "class_55.h" -#include "class_68.h" -#include "class_41.h" -#include "class_31.h" -#include "class_70.h" -#include "class_97.h" -#include "class_86.h" -#include "class_49.h" -#include "class_12.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_2/class_57.h b/lib/waf/build/lib_2/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_58.cpp b/lib/waf/build/lib_2/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_74.h" -#include "class_89.h" -#include "class_21.h" -#include "class_67.h" -#include "class_0.h" -#include "class_30.h" -#include "class_55.h" -#include "class_88.h" -#include "class_54.h" -#include "class_29.h" -#include "class_12.h" -#include "class_33.h" -#include "class_5.h" -#include "class_65.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_2/class_58.h b/lib/waf/build/lib_2/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_59.cpp b/lib/waf/build/lib_2/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_1.h" -#include "class_23.h" -#include "class_0.h" -#include "class_43.h" -#include "class_87.h" -#include "class_88.h" -#include "class_60.h" -#include "class_95.h" -#include "class_91.h" -#include "class_51.h" -#include "class_39.h" -#include "class_31.h" -#include "class_16.h" -#include "class_55.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_2/class_59.h b/lib/waf/build/lib_2/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_6.cpp b/lib/waf/build/lib_2/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_73.h" -#include "class_51.h" -#include "class_89.h" -#include "class_6.h" -#include "class_65.h" -#include "class_66.h" -#include "class_93.h" -#include "class_57.h" -#include "class_71.h" -#include "class_45.h" -#include "class_7.h" -#include "class_9.h" -#include "class_62.h" -#include "class_38.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_2/class_6.h b/lib/waf/build/lib_2/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_60.cpp b/lib/waf/build/lib_2/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_90.h" -#include "class_30.h" -#include "class_44.h" -#include "class_59.h" -#include "class_41.h" -#include "class_20.h" -#include "class_74.h" -#include "class_81.h" -#include "class_65.h" -#include "class_56.h" -#include "class_88.h" -#include "class_86.h" -#include "class_1.h" -#include "class_67.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_2/class_60.h b/lib/waf/build/lib_2/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_61.cpp b/lib/waf/build/lib_2/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_38.h" -#include "class_15.h" -#include "class_12.h" -#include "class_6.h" -#include "class_4.h" -#include "class_86.h" -#include "class_36.h" -#include "class_46.h" -#include "class_43.h" -#include "class_80.h" -#include "class_40.h" -#include "class_35.h" -#include "class_67.h" -#include "class_65.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_2/class_61.h b/lib/waf/build/lib_2/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_62.cpp b/lib/waf/build/lib_2/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_53.h" -#include "class_25.h" -#include "class_65.h" -#include "class_8.h" -#include "class_31.h" -#include "class_30.h" -#include "class_43.h" -#include "class_0.h" -#include "class_20.h" -#include "class_85.h" -#include "class_79.h" -#include "class_1.h" -#include "class_60.h" -#include "class_51.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_2/class_62.h b/lib/waf/build/lib_2/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_63.cpp b/lib/waf/build/lib_2/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_70.h" -#include "class_95.h" -#include "class_41.h" -#include "class_62.h" -#include "class_34.h" -#include "class_96.h" -#include "class_14.h" -#include "class_33.h" -#include "class_25.h" -#include "class_99.h" -#include "class_88.h" -#include "class_73.h" -#include "class_27.h" -#include "class_28.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_2/class_63.h b/lib/waf/build/lib_2/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_64.cpp b/lib/waf/build/lib_2/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_0.h" -#include "class_36.h" -#include "class_93.h" -#include "class_62.h" -#include "class_94.h" -#include "class_45.h" -#include "class_5.h" -#include "class_15.h" -#include "class_48.h" -#include "class_22.h" -#include "class_9.h" -#include "class_26.h" -#include "class_46.h" -#include "class_42.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_2/class_64.h b/lib/waf/build/lib_2/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_65.cpp b/lib/waf/build/lib_2/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_97.h" -#include "class_16.h" -#include "class_92.h" -#include "class_41.h" -#include "class_88.h" -#include "class_37.h" -#include "class_91.h" -#include "class_83.h" -#include "class_32.h" -#include "class_25.h" -#include "class_9.h" -#include "class_77.h" -#include "class_40.h" -#include "class_46.h" -#include "class_6.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_2/class_65.h b/lib/waf/build/lib_2/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_66.cpp b/lib/waf/build/lib_2/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_66.h" -#include "class_56.h" -#include "class_70.h" -#include "class_89.h" -#include "class_32.h" -#include "class_65.h" -#include "class_1.h" -#include "class_29.h" -#include "class_2.h" -#include "class_44.h" -#include "class_85.h" -#include "class_67.h" -#include "class_84.h" -#include "class_47.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_2/class_66.h b/lib/waf/build/lib_2/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_67.cpp b/lib/waf/build/lib_2/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_54.h" -#include "class_49.h" -#include "class_45.h" -#include "class_56.h" -#include "class_30.h" -#include "class_11.h" -#include "class_96.h" -#include "class_90.h" -#include "class_68.h" -#include "class_44.h" -#include "class_89.h" -#include "class_46.h" -#include "class_64.h" -#include "class_92.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_2/class_67.h b/lib/waf/build/lib_2/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_68.cpp b/lib/waf/build/lib_2/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_15.h" -#include "class_9.h" -#include "class_71.h" -#include "class_33.h" -#include "class_3.h" -#include "class_69.h" -#include "class_29.h" -#include "class_81.h" -#include "class_91.h" -#include "class_58.h" -#include "class_93.h" -#include "class_92.h" -#include "class_39.h" -#include "class_1.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_2/class_68.h b/lib/waf/build/lib_2/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_69.cpp b/lib/waf/build/lib_2/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_1.h" -#include "class_2.h" -#include "class_42.h" -#include "class_29.h" -#include "class_3.h" -#include "class_81.h" -#include "class_9.h" -#include "class_30.h" -#include "class_82.h" -#include "class_73.h" -#include "class_76.h" -#include "class_25.h" -#include "class_31.h" -#include "class_80.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_2/class_69.h b/lib/waf/build/lib_2/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_7.cpp b/lib/waf/build/lib_2/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_18.h" -#include "class_66.h" -#include "class_67.h" -#include "class_93.h" -#include "class_83.h" -#include "class_44.h" -#include "class_72.h" -#include "class_50.h" -#include "class_13.h" -#include "class_53.h" -#include "class_71.h" -#include "class_92.h" -#include "class_55.h" -#include "class_26.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_2/class_7.h b/lib/waf/build/lib_2/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_70.cpp b/lib/waf/build/lib_2/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_0.h" -#include "class_99.h" -#include "class_57.h" -#include "class_31.h" -#include "class_26.h" -#include "class_65.h" -#include "class_42.h" -#include "class_12.h" -#include "class_25.h" -#include "class_70.h" -#include "class_23.h" -#include "class_17.h" -#include "class_3.h" -#include "class_5.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_2/class_70.h b/lib/waf/build/lib_2/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_71.cpp b/lib/waf/build/lib_2/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_89.h" -#include "class_50.h" -#include "class_69.h" -#include "class_58.h" -#include "class_16.h" -#include "class_38.h" -#include "class_96.h" -#include "class_5.h" -#include "class_76.h" -#include "class_61.h" -#include "class_56.h" -#include "class_49.h" -#include "class_15.h" -#include "class_60.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_2/class_71.h b/lib/waf/build/lib_2/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_72.cpp b/lib/waf/build/lib_2/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_36.h" -#include "class_61.h" -#include "class_66.h" -#include "class_29.h" -#include "class_40.h" -#include "class_58.h" -#include "class_50.h" -#include "class_93.h" -#include "class_72.h" -#include "class_8.h" -#include "class_68.h" -#include "class_59.h" -#include "class_52.h" -#include "class_32.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_2/class_72.h b/lib/waf/build/lib_2/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_73.cpp b/lib/waf/build/lib_2/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_70.h" -#include "class_82.h" -#include "class_88.h" -#include "class_74.h" -#include "class_66.h" -#include "class_9.h" -#include "class_57.h" -#include "class_3.h" -#include "class_43.h" -#include "class_8.h" -#include "class_60.h" -#include "class_73.h" -#include "class_13.h" -#include "class_77.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_2/class_73.h b/lib/waf/build/lib_2/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_74.cpp b/lib/waf/build/lib_2/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_15.h" -#include "class_60.h" -#include "class_24.h" -#include "class_11.h" -#include "class_48.h" -#include "class_50.h" -#include "class_71.h" -#include "class_90.h" -#include "class_21.h" -#include "class_82.h" -#include "class_45.h" -#include "class_12.h" -#include "class_75.h" -#include "class_38.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_2/class_74.h b/lib/waf/build/lib_2/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_75.cpp b/lib/waf/build/lib_2/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_37.h" -#include "class_7.h" -#include "class_93.h" -#include "class_71.h" -#include "class_14.h" -#include "class_23.h" -#include "class_61.h" -#include "class_29.h" -#include "class_15.h" -#include "class_83.h" -#include "class_27.h" -#include "class_70.h" -#include "class_39.h" -#include "class_86.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_2/class_75.h b/lib/waf/build/lib_2/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_76.cpp b/lib/waf/build/lib_2/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_87.h" -#include "class_68.h" -#include "class_29.h" -#include "class_82.h" -#include "class_13.h" -#include "class_94.h" -#include "class_70.h" -#include "class_56.h" -#include "class_20.h" -#include "class_46.h" -#include "class_42.h" -#include "class_52.h" -#include "class_76.h" -#include "class_48.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_2/class_76.h b/lib/waf/build/lib_2/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_77.cpp b/lib/waf/build/lib_2/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_40.h" -#include "class_54.h" -#include "class_26.h" -#include "class_5.h" -#include "class_77.h" -#include "class_48.h" -#include "class_13.h" -#include "class_70.h" -#include "class_98.h" -#include "class_93.h" -#include "class_96.h" -#include "class_45.h" -#include "class_65.h" -#include "class_8.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_2/class_77.h b/lib/waf/build/lib_2/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_78.cpp b/lib/waf/build/lib_2/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_23.h" -#include "class_82.h" -#include "class_48.h" -#include "class_83.h" -#include "class_43.h" -#include "class_0.h" -#include "class_22.h" -#include "class_60.h" -#include "class_16.h" -#include "class_59.h" -#include "class_39.h" -#include "class_2.h" -#include "class_6.h" -#include "class_80.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_2/class_78.h b/lib/waf/build/lib_2/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_79.cpp b/lib/waf/build/lib_2/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_82.h" -#include "class_32.h" -#include "class_9.h" -#include "class_89.h" -#include "class_77.h" -#include "class_1.h" -#include "class_6.h" -#include "class_86.h" -#include "class_40.h" -#include "class_0.h" -#include "class_56.h" -#include "class_99.h" -#include "class_98.h" -#include "class_24.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_2/class_79.h b/lib/waf/build/lib_2/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_8.cpp b/lib/waf/build/lib_2/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_1.h" -#include "class_16.h" -#include "class_10.h" -#include "class_41.h" -#include "class_87.h" -#include "class_26.h" -#include "class_40.h" -#include "class_35.h" -#include "class_15.h" -#include "class_9.h" -#include "class_21.h" -#include "class_4.h" -#include "class_39.h" -#include "class_75.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_2/class_8.h b/lib/waf/build/lib_2/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_80.cpp b/lib/waf/build/lib_2/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_8.h" -#include "class_44.h" -#include "class_34.h" -#include "class_0.h" -#include "class_19.h" -#include "class_70.h" -#include "class_4.h" -#include "class_1.h" -#include "class_85.h" -#include "class_91.h" -#include "class_3.h" -#include "class_25.h" -#include "class_35.h" -#include "class_58.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_2/class_80.h b/lib/waf/build/lib_2/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_81.cpp b/lib/waf/build/lib_2/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_19.h" -#include "class_4.h" -#include "class_86.h" -#include "class_35.h" -#include "class_87.h" -#include "class_62.h" -#include "class_58.h" -#include "class_88.h" -#include "class_30.h" -#include "class_38.h" -#include "class_84.h" -#include "class_90.h" -#include "class_78.h" -#include "class_91.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_2/class_81.h b/lib/waf/build/lib_2/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_82.cpp b/lib/waf/build/lib_2/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_82.h" -#include "class_70.h" -#include "class_32.h" -#include "class_93.h" -#include "class_22.h" -#include "class_74.h" -#include "class_50.h" -#include "class_25.h" -#include "class_51.h" -#include "class_31.h" -#include "class_52.h" -#include "class_20.h" -#include "class_26.h" -#include "class_24.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_2/class_82.h b/lib/waf/build/lib_2/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_83.cpp b/lib/waf/build/lib_2/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_84.h" -#include "class_34.h" -#include "class_45.h" -#include "class_86.h" -#include "class_89.h" -#include "class_53.h" -#include "class_54.h" -#include "class_8.h" -#include "class_21.h" -#include "class_11.h" -#include "class_32.h" -#include "class_1.h" -#include "class_50.h" -#include "class_0.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_2/class_83.h b/lib/waf/build/lib_2/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_84.cpp b/lib/waf/build/lib_2/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_3.h" -#include "class_50.h" -#include "class_89.h" -#include "class_0.h" -#include "class_57.h" -#include "class_24.h" -#include "class_68.h" -#include "class_92.h" -#include "class_48.h" -#include "class_87.h" -#include "class_38.h" -#include "class_21.h" -#include "class_42.h" -#include "class_65.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_2/class_84.h b/lib/waf/build/lib_2/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_85.cpp b/lib/waf/build/lib_2/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_86.h" -#include "class_52.h" -#include "class_65.h" -#include "class_78.h" -#include "class_99.h" -#include "class_27.h" -#include "class_94.h" -#include "class_19.h" -#include "class_79.h" -#include "class_7.h" -#include "class_90.h" -#include "class_70.h" -#include "class_69.h" -#include "class_47.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_2/class_85.h b/lib/waf/build/lib_2/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_86.cpp b/lib/waf/build/lib_2/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_63.h" -#include "class_99.h" -#include "class_60.h" -#include "class_78.h" -#include "class_40.h" -#include "class_13.h" -#include "class_36.h" -#include "class_79.h" -#include "class_50.h" -#include "class_49.h" -#include "class_20.h" -#include "class_74.h" -#include "class_41.h" -#include "class_17.h" -#include "class_95.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_2/class_86.h b/lib/waf/build/lib_2/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_87.cpp b/lib/waf/build/lib_2/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_43.h" -#include "class_93.h" -#include "class_88.h" -#include "class_89.h" -#include "class_78.h" -#include "class_20.h" -#include "class_66.h" -#include "class_36.h" -#include "class_34.h" -#include "class_59.h" -#include "class_82.h" -#include "class_32.h" -#include "class_12.h" -#include "class_35.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_2/class_87.h b/lib/waf/build/lib_2/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_88.cpp b/lib/waf/build/lib_2/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_11.h" -#include "class_47.h" -#include "class_31.h" -#include "class_22.h" -#include "class_78.h" -#include "class_16.h" -#include "class_62.h" -#include "class_55.h" -#include "class_54.h" -#include "class_18.h" -#include "class_70.h" -#include "class_92.h" -#include "class_99.h" -#include "class_60.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_2/class_88.h b/lib/waf/build/lib_2/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_89.cpp b/lib/waf/build/lib_2/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_15.h" -#include "class_63.h" -#include "class_16.h" -#include "class_84.h" -#include "class_77.h" -#include "class_9.h" -#include "class_73.h" -#include "class_82.h" -#include "class_62.h" -#include "class_53.h" -#include "class_60.h" -#include "class_32.h" -#include "class_58.h" -#include "class_78.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_2/class_89.h b/lib/waf/build/lib_2/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_9.cpp b/lib/waf/build/lib_2/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_7.h" -#include "class_23.h" -#include "class_39.h" -#include "class_63.h" -#include "class_2.h" -#include "class_61.h" -#include "class_71.h" -#include "class_89.h" -#include "class_65.h" -#include "class_56.h" -#include "class_29.h" -#include "class_38.h" -#include "class_80.h" -#include "class_34.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_2/class_9.h b/lib/waf/build/lib_2/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_90.cpp b/lib/waf/build/lib_2/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_49.h" -#include "class_44.h" -#include "class_76.h" -#include "class_74.h" -#include "class_70.h" -#include "class_97.h" -#include "class_83.h" -#include "class_62.h" -#include "class_12.h" -#include "class_51.h" -#include "class_58.h" -#include "class_55.h" -#include "class_22.h" -#include "class_46.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_2/class_90.h b/lib/waf/build/lib_2/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_91.cpp b/lib/waf/build/lib_2/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_81.h" -#include "class_83.h" -#include "class_47.h" -#include "class_48.h" -#include "class_53.h" -#include "class_65.h" -#include "class_95.h" -#include "class_27.h" -#include "class_3.h" -#include "class_97.h" -#include "class_8.h" -#include "class_18.h" -#include "class_84.h" -#include "class_31.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_2/class_91.h b/lib/waf/build/lib_2/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_92.cpp b/lib/waf/build/lib_2/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_59.h" -#include "class_12.h" -#include "class_14.h" -#include "class_98.h" -#include "class_69.h" -#include "class_66.h" -#include "class_48.h" -#include "class_32.h" -#include "class_85.h" -#include "class_93.h" -#include "class_24.h" -#include "class_34.h" -#include "class_31.h" -#include "class_57.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_2/class_92.h b/lib/waf/build/lib_2/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_93.cpp b/lib/waf/build/lib_2/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_52.h" -#include "class_43.h" -#include "class_30.h" -#include "class_66.h" -#include "class_0.h" -#include "class_91.h" -#include "class_61.h" -#include "class_6.h" -#include "class_59.h" -#include "class_24.h" -#include "class_33.h" -#include "class_87.h" -#include "class_78.h" -#include "class_51.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_2/class_93.h b/lib/waf/build/lib_2/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_94.cpp b/lib/waf/build/lib_2/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_34.h" -#include "class_62.h" -#include "class_90.h" -#include "class_24.h" -#include "class_0.h" -#include "class_54.h" -#include "class_42.h" -#include "class_39.h" -#include "class_38.h" -#include "class_67.h" -#include "class_52.h" -#include "class_44.h" -#include "class_35.h" -#include "class_49.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_2/class_94.h b/lib/waf/build/lib_2/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_95.cpp b/lib/waf/build/lib_2/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_60.h" -#include "class_35.h" -#include "class_79.h" -#include "class_99.h" -#include "class_29.h" -#include "class_61.h" -#include "class_65.h" -#include "class_31.h" -#include "class_10.h" -#include "class_94.h" -#include "class_49.h" -#include "class_70.h" -#include "class_78.h" -#include "class_26.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_2/class_95.h b/lib/waf/build/lib_2/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_96.cpp b/lib/waf/build/lib_2/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_98.h" -#include "class_61.h" -#include "class_17.h" -#include "class_90.h" -#include "class_29.h" -#include "class_81.h" -#include "class_66.h" -#include "class_34.h" -#include "class_60.h" -#include "class_37.h" -#include "class_78.h" -#include "class_71.h" -#include "class_58.h" -#include "class_80.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_2/class_96.h b/lib/waf/build/lib_2/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_97.cpp b/lib/waf/build/lib_2/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_47.h" -#include "class_24.h" -#include "class_10.h" -#include "class_14.h" -#include "class_27.h" -#include "class_78.h" -#include "class_12.h" -#include "class_99.h" -#include "class_4.h" -#include "class_56.h" -#include "class_57.h" -#include "class_50.h" -#include "class_16.h" -#include "class_46.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_2/class_97.h b/lib/waf/build/lib_2/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_98.cpp b/lib/waf/build/lib_2/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_29.h" -#include "class_83.h" -#include "class_99.h" -#include "class_57.h" -#include "class_48.h" -#include "class_38.h" -#include "class_33.h" -#include "class_35.h" -#include "class_80.h" -#include "class_34.h" -#include "class_14.h" -#include "class_88.h" -#include "class_30.h" -#include "class_45.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_2/class_98.h b/lib/waf/build/lib_2/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_2/class_99.cpp b/lib/waf/build/lib_2/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_2/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_26.h" -#include "class_89.h" -#include "class_59.h" -#include "class_0.h" -#include "class_63.h" -#include "class_86.h" -#include "class_9.h" -#include "class_19.h" -#include "class_54.h" -#include "class_4.h" -#include "class_38.h" -#include "class_57.h" -#include "class_24.h" -#include "class_85.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_2/class_99.h b/lib/waf/build/lib_2/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_2/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_3/Makefile b/lib/waf/build/lib_3/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_3/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_3.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_3/Makefile.am b/lib/waf/build/lib_3/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_3/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib3.la -lib3_la_SOURCES = lib_3/class_0.cpp lib_3/class_1.cpp lib_3/class_2.cpp lib_3/class_3.cpp lib_3/class_4.cpp lib_3/class_5.cpp lib_3/class_6.cpp lib_3/class_7.cpp lib_3/class_8.cpp lib_3/class_9.cpp lib_3/class_10.cpp lib_3/class_11.cpp lib_3/class_12.cpp lib_3/class_13.cpp lib_3/class_14.cpp lib_3/class_15.cpp lib_3/class_16.cpp lib_3/class_17.cpp lib_3/class_18.cpp lib_3/class_19.cpp lib_3/class_20.cpp lib_3/class_21.cpp lib_3/class_22.cpp lib_3/class_23.cpp lib_3/class_24.cpp lib_3/class_25.cpp lib_3/class_26.cpp lib_3/class_27.cpp lib_3/class_28.cpp lib_3/class_29.cpp lib_3/class_30.cpp lib_3/class_31.cpp lib_3/class_32.cpp lib_3/class_33.cpp lib_3/class_34.cpp lib_3/class_35.cpp lib_3/class_36.cpp lib_3/class_37.cpp lib_3/class_38.cpp lib_3/class_39.cpp lib_3/class_40.cpp lib_3/class_41.cpp lib_3/class_42.cpp lib_3/class_43.cpp lib_3/class_44.cpp lib_3/class_45.cpp lib_3/class_46.cpp lib_3/class_47.cpp lib_3/class_48.cpp lib_3/class_49.cpp lib_3/class_50.cpp lib_3/class_51.cpp lib_3/class_52.cpp lib_3/class_53.cpp lib_3/class_54.cpp lib_3/class_55.cpp lib_3/class_56.cpp lib_3/class_57.cpp lib_3/class_58.cpp lib_3/class_59.cpp lib_3/class_60.cpp lib_3/class_61.cpp lib_3/class_62.cpp lib_3/class_63.cpp lib_3/class_64.cpp lib_3/class_65.cpp lib_3/class_66.cpp lib_3/class_67.cpp lib_3/class_68.cpp lib_3/class_69.cpp lib_3/class_70.cpp lib_3/class_71.cpp lib_3/class_72.cpp lib_3/class_73.cpp lib_3/class_74.cpp lib_3/class_75.cpp lib_3/class_76.cpp lib_3/class_77.cpp lib_3/class_78.cpp lib_3/class_79.cpp lib_3/class_80.cpp lib_3/class_81.cpp lib_3/class_82.cpp lib_3/class_83.cpp lib_3/class_84.cpp lib_3/class_85.cpp lib_3/class_86.cpp lib_3/class_87.cpp lib_3/class_88.cpp lib_3/class_89.cpp lib_3/class_90.cpp lib_3/class_91.cpp lib_3/class_92.cpp lib_3/class_93.cpp lib_3/class_94.cpp lib_3/class_95.cpp lib_3/class_96.cpp lib_3/class_97.cpp lib_3/class_98.cpp lib_3/class_99.cpp diff --git a/lib/waf/build/lib_3/SConscript b/lib/waf/build/lib_3/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_3/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_3", list) - diff --git a/lib/waf/build/lib_3/class_0.cpp b/lib/waf/build/lib_3/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_8.h" -#include "class_45.h" -#include "class_27.h" -#include "class_88.h" -#include "class_4.h" -#include "class_76.h" -#include "class_87.h" -#include "class_61.h" -#include "class_19.h" -#include "class_0.h" -#include "class_82.h" -#include "class_64.h" -#include "class_90.h" -#include "class_69.h" -#include "class_10.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_3/class_0.h b/lib/waf/build/lib_3/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_1.cpp b/lib/waf/build/lib_3/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_50.h" -#include "class_33.h" -#include "class_27.h" -#include "class_38.h" -#include "class_10.h" -#include "class_0.h" -#include "class_75.h" -#include "class_87.h" -#include "class_34.h" -#include "class_29.h" -#include "class_74.h" -#include "class_88.h" -#include "class_4.h" -#include "class_18.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_3/class_1.h b/lib/waf/build/lib_3/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_10.cpp b/lib/waf/build/lib_3/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_45.h" -#include "class_42.h" -#include "class_50.h" -#include "class_13.h" -#include "class_80.h" -#include "class_49.h" -#include "class_7.h" -#include "class_91.h" -#include "class_6.h" -#include "class_2.h" -#include "class_0.h" -#include "class_54.h" -#include "class_32.h" -#include "class_4.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_3/class_10.h b/lib/waf/build/lib_3/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_11.cpp b/lib/waf/build/lib_3/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_34.h" -#include "class_62.h" -#include "class_97.h" -#include "class_6.h" -#include "class_86.h" -#include "class_45.h" -#include "class_91.h" -#include "class_37.h" -#include "class_4.h" -#include "class_51.h" -#include "class_93.h" -#include "class_55.h" -#include "class_24.h" -#include "class_67.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_3/class_11.h b/lib/waf/build/lib_3/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_12.cpp b/lib/waf/build/lib_3/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_72.h" -#include "class_67.h" -#include "class_42.h" -#include "class_57.h" -#include "class_75.h" -#include "class_23.h" -#include "class_6.h" -#include "class_73.h" -#include "class_48.h" -#include "class_66.h" -#include "class_28.h" -#include "class_70.h" -#include "class_86.h" -#include "class_60.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_3/class_12.h b/lib/waf/build/lib_3/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_13.cpp b/lib/waf/build/lib_3/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_27.h" -#include "class_67.h" -#include "class_20.h" -#include "class_90.h" -#include "class_84.h" -#include "class_25.h" -#include "class_51.h" -#include "class_95.h" -#include "class_85.h" -#include "class_10.h" -#include "class_40.h" -#include "class_37.h" -#include "class_87.h" -#include "class_96.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_3/class_13.h b/lib/waf/build/lib_3/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_14.cpp b/lib/waf/build/lib_3/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_88.h" -#include "class_53.h" -#include "class_55.h" -#include "class_58.h" -#include "class_81.h" -#include "class_84.h" -#include "class_31.h" -#include "class_39.h" -#include "class_72.h" -#include "class_69.h" -#include "class_52.h" -#include "class_30.h" -#include "class_77.h" -#include "class_67.h" -#include "class_91.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_3/class_14.h b/lib/waf/build/lib_3/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_15.cpp b/lib/waf/build/lib_3/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_69.h" -#include "class_49.h" -#include "class_68.h" -#include "class_88.h" -#include "class_60.h" -#include "class_35.h" -#include "class_17.h" -#include "class_47.h" -#include "class_0.h" -#include "class_26.h" -#include "class_52.h" -#include "class_54.h" -#include "class_39.h" -#include "class_84.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_3/class_15.h b/lib/waf/build/lib_3/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_16.cpp b/lib/waf/build/lib_3/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_38.h" -#include "class_64.h" -#include "class_39.h" -#include "class_19.h" -#include "class_65.h" -#include "class_5.h" -#include "class_57.h" -#include "class_52.h" -#include "class_2.h" -#include "class_67.h" -#include "class_49.h" -#include "class_24.h" -#include "class_53.h" -#include "class_61.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_3/class_16.h b/lib/waf/build/lib_3/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_17.cpp b/lib/waf/build/lib_3/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_53.h" -#include "class_74.h" -#include "class_57.h" -#include "class_22.h" -#include "class_49.h" -#include "class_41.h" -#include "class_11.h" -#include "class_35.h" -#include "class_99.h" -#include "class_4.h" -#include "class_15.h" -#include "class_85.h" -#include "class_10.h" -#include "class_84.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_3/class_17.h b/lib/waf/build/lib_3/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_18.cpp b/lib/waf/build/lib_3/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_38.h" -#include "class_59.h" -#include "class_26.h" -#include "class_85.h" -#include "class_52.h" -#include "class_65.h" -#include "class_8.h" -#include "class_82.h" -#include "class_20.h" -#include "class_68.h" -#include "class_43.h" -#include "class_75.h" -#include "class_9.h" -#include "class_62.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_3/class_18.h b/lib/waf/build/lib_3/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_19.cpp b/lib/waf/build/lib_3/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_71.h" -#include "class_37.h" -#include "class_53.h" -#include "class_20.h" -#include "class_84.h" -#include "class_6.h" -#include "class_78.h" -#include "class_50.h" -#include "class_51.h" -#include "class_11.h" -#include "class_21.h" -#include "class_73.h" -#include "class_31.h" -#include "class_59.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_3/class_19.h b/lib/waf/build/lib_3/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_2.cpp b/lib/waf/build/lib_3/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_88.h" -#include "class_91.h" -#include "class_49.h" -#include "class_62.h" -#include "class_40.h" -#include "class_34.h" -#include "class_63.h" -#include "class_77.h" -#include "class_44.h" -#include "class_54.h" -#include "class_13.h" -#include "class_89.h" -#include "class_61.h" -#include "class_35.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_3/class_2.h b/lib/waf/build/lib_3/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_20.cpp b/lib/waf/build/lib_3/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_79.h" -#include "class_68.h" -#include "class_46.h" -#include "class_39.h" -#include "class_87.h" -#include "class_21.h" -#include "class_58.h" -#include "class_18.h" -#include "class_93.h" -#include "class_10.h" -#include "class_89.h" -#include "class_96.h" -#include "class_72.h" -#include "class_94.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_3/class_20.h b/lib/waf/build/lib_3/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_21.cpp b/lib/waf/build/lib_3/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_62.h" -#include "class_89.h" -#include "class_69.h" -#include "class_68.h" -#include "class_81.h" -#include "class_8.h" -#include "class_65.h" -#include "class_41.h" -#include "class_71.h" -#include "class_31.h" -#include "class_56.h" -#include "class_76.h" -#include "class_90.h" -#include "class_88.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_3/class_21.h b/lib/waf/build/lib_3/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_22.cpp b/lib/waf/build/lib_3/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_6.h" -#include "class_39.h" -#include "class_98.h" -#include "class_80.h" -#include "class_79.h" -#include "class_10.h" -#include "class_11.h" -#include "class_2.h" -#include "class_4.h" -#include "class_96.h" -#include "class_94.h" -#include "class_95.h" -#include "class_56.h" -#include "class_14.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_3/class_22.h b/lib/waf/build/lib_3/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_23.cpp b/lib/waf/build/lib_3/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_79.h" -#include "class_90.h" -#include "class_85.h" -#include "class_53.h" -#include "class_70.h" -#include "class_34.h" -#include "class_66.h" -#include "class_61.h" -#include "class_43.h" -#include "class_37.h" -#include "class_48.h" -#include "class_93.h" -#include "class_82.h" -#include "class_0.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_3/class_23.h b/lib/waf/build/lib_3/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_24.cpp b/lib/waf/build/lib_3/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_32.h" -#include "class_87.h" -#include "class_41.h" -#include "class_17.h" -#include "class_65.h" -#include "class_74.h" -#include "class_91.h" -#include "class_67.h" -#include "class_31.h" -#include "class_19.h" -#include "class_58.h" -#include "class_81.h" -#include "class_10.h" -#include "class_76.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_3/class_24.h b/lib/waf/build/lib_3/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_25.cpp b/lib/waf/build/lib_3/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_59.h" -#include "class_97.h" -#include "class_91.h" -#include "class_95.h" -#include "class_34.h" -#include "class_24.h" -#include "class_67.h" -#include "class_19.h" -#include "class_88.h" -#include "class_32.h" -#include "class_83.h" -#include "class_93.h" -#include "class_94.h" -#include "class_37.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_3/class_25.h b/lib/waf/build/lib_3/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_26.cpp b/lib/waf/build/lib_3/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_94.h" -#include "class_11.h" -#include "class_6.h" -#include "class_24.h" -#include "class_5.h" -#include "class_56.h" -#include "class_33.h" -#include "class_86.h" -#include "class_7.h" -#include "class_14.h" -#include "class_57.h" -#include "class_17.h" -#include "class_76.h" -#include "class_13.h" -#include "class_52.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_3/class_26.h b/lib/waf/build/lib_3/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_27.cpp b/lib/waf/build/lib_3/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_78.h" -#include "class_26.h" -#include "class_30.h" -#include "class_98.h" -#include "class_14.h" -#include "class_32.h" -#include "class_56.h" -#include "class_86.h" -#include "class_10.h" -#include "class_33.h" -#include "class_61.h" -#include "class_80.h" -#include "class_66.h" -#include "class_29.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_3/class_27.h b/lib/waf/build/lib_3/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_28.cpp b/lib/waf/build/lib_3/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_82.h" -#include "class_44.h" -#include "class_30.h" -#include "class_47.h" -#include "class_88.h" -#include "class_69.h" -#include "class_85.h" -#include "class_89.h" -#include "class_99.h" -#include "class_10.h" -#include "class_16.h" -#include "class_60.h" -#include "class_56.h" -#include "class_19.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_3/class_28.h b/lib/waf/build/lib_3/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_29.cpp b/lib/waf/build/lib_3/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_58.h" -#include "class_28.h" -#include "class_42.h" -#include "class_19.h" -#include "class_69.h" -#include "class_24.h" -#include "class_64.h" -#include "class_97.h" -#include "class_22.h" -#include "class_2.h" -#include "class_41.h" -#include "class_8.h" -#include "class_53.h" -#include "class_95.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_3/class_29.h b/lib/waf/build/lib_3/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_3.cpp b/lib/waf/build/lib_3/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_41.h" -#include "class_44.h" -#include "class_88.h" -#include "class_67.h" -#include "class_98.h" -#include "class_10.h" -#include "class_49.h" -#include "class_63.h" -#include "class_1.h" -#include "class_15.h" -#include "class_64.h" -#include "class_5.h" -#include "class_70.h" -#include "class_13.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_3/class_3.h b/lib/waf/build/lib_3/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_30.cpp b/lib/waf/build/lib_3/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_35.h" -#include "class_77.h" -#include "class_14.h" -#include "class_49.h" -#include "class_18.h" -#include "class_32.h" -#include "class_68.h" -#include "class_15.h" -#include "class_81.h" -#include "class_7.h" -#include "class_43.h" -#include "class_53.h" -#include "class_42.h" -#include "class_74.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_3/class_30.h b/lib/waf/build/lib_3/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_31.cpp b/lib/waf/build/lib_3/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_12.h" -#include "class_59.h" -#include "class_11.h" -#include "class_15.h" -#include "class_33.h" -#include "class_30.h" -#include "class_89.h" -#include "class_54.h" -#include "class_34.h" -#include "class_62.h" -#include "class_88.h" -#include "class_14.h" -#include "class_77.h" -#include "class_24.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_3/class_31.h b/lib/waf/build/lib_3/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_32.cpp b/lib/waf/build/lib_3/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_40.h" -#include "class_50.h" -#include "class_78.h" -#include "class_72.h" -#include "class_97.h" -#include "class_67.h" -#include "class_48.h" -#include "class_27.h" -#include "class_42.h" -#include "class_19.h" -#include "class_71.h" -#include "class_7.h" -#include "class_34.h" -#include "class_8.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_3/class_32.h b/lib/waf/build/lib_3/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_33.cpp b/lib/waf/build/lib_3/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_12.h" -#include "class_85.h" -#include "class_55.h" -#include "class_32.h" -#include "class_60.h" -#include "class_40.h" -#include "class_22.h" -#include "class_33.h" -#include "class_80.h" -#include "class_17.h" -#include "class_86.h" -#include "class_27.h" -#include "class_75.h" -#include "class_78.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_3/class_33.h b/lib/waf/build/lib_3/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_34.cpp b/lib/waf/build/lib_3/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_84.h" -#include "class_68.h" -#include "class_82.h" -#include "class_13.h" -#include "class_89.h" -#include "class_17.h" -#include "class_42.h" -#include "class_99.h" -#include "class_62.h" -#include "class_52.h" -#include "class_4.h" -#include "class_60.h" -#include "class_27.h" -#include "class_76.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_3/class_34.h b/lib/waf/build/lib_3/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_35.cpp b/lib/waf/build/lib_3/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_61.h" -#include "class_7.h" -#include "class_48.h" -#include "class_55.h" -#include "class_93.h" -#include "class_71.h" -#include "class_62.h" -#include "class_43.h" -#include "class_57.h" -#include "class_23.h" -#include "class_77.h" -#include "class_80.h" -#include "class_54.h" -#include "class_59.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_3/class_35.h b/lib/waf/build/lib_3/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_36.cpp b/lib/waf/build/lib_3/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_82.h" -#include "class_57.h" -#include "class_27.h" -#include "class_61.h" -#include "class_12.h" -#include "class_28.h" -#include "class_69.h" -#include "class_3.h" -#include "class_73.h" -#include "class_99.h" -#include "class_54.h" -#include "class_37.h" -#include "class_5.h" -#include "class_14.h" -#include "class_93.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_3/class_36.h b/lib/waf/build/lib_3/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_37.cpp b/lib/waf/build/lib_3/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_36.h" -#include "class_94.h" -#include "class_2.h" -#include "class_7.h" -#include "class_66.h" -#include "class_48.h" -#include "class_73.h" -#include "class_9.h" -#include "class_54.h" -#include "class_65.h" -#include "class_16.h" -#include "class_52.h" -#include "class_91.h" -#include "class_20.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_3/class_37.h b/lib/waf/build/lib_3/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_38.cpp b/lib/waf/build/lib_3/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_10.h" -#include "class_87.h" -#include "class_76.h" -#include "class_29.h" -#include "class_30.h" -#include "class_12.h" -#include "class_72.h" -#include "class_42.h" -#include "class_74.h" -#include "class_37.h" -#include "class_14.h" -#include "class_98.h" -#include "class_7.h" -#include "class_1.h" -#include "class_68.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_3/class_38.h b/lib/waf/build/lib_3/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_39.cpp b/lib/waf/build/lib_3/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_86.h" -#include "class_6.h" -#include "class_52.h" -#include "class_54.h" -#include "class_81.h" -#include "class_61.h" -#include "class_78.h" -#include "class_11.h" -#include "class_41.h" -#include "class_60.h" -#include "class_73.h" -#include "class_76.h" -#include "class_3.h" -#include "class_40.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_3/class_39.h b/lib/waf/build/lib_3/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_4.cpp b/lib/waf/build/lib_3/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_78.h" -#include "class_95.h" -#include "class_70.h" -#include "class_80.h" -#include "class_73.h" -#include "class_69.h" -#include "class_0.h" -#include "class_46.h" -#include "class_40.h" -#include "class_76.h" -#include "class_43.h" -#include "class_72.h" -#include "class_17.h" -#include "class_86.h" -#include "class_7.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_3/class_4.h b/lib/waf/build/lib_3/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_40.cpp b/lib/waf/build/lib_3/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_29.h" -#include "class_94.h" -#include "class_55.h" -#include "class_9.h" -#include "class_68.h" -#include "class_19.h" -#include "class_96.h" -#include "class_44.h" -#include "class_41.h" -#include "class_11.h" -#include "class_0.h" -#include "class_13.h" -#include "class_78.h" -#include "class_38.h" -#include "class_82.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_3/class_40.h b/lib/waf/build/lib_3/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_41.cpp b/lib/waf/build/lib_3/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_86.h" -#include "class_52.h" -#include "class_83.h" -#include "class_54.h" -#include "class_87.h" -#include "class_92.h" -#include "class_39.h" -#include "class_25.h" -#include "class_33.h" -#include "class_66.h" -#include "class_72.h" -#include "class_7.h" -#include "class_59.h" -#include "class_9.h" -#include "class_6.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_3/class_41.h b/lib/waf/build/lib_3/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_42.cpp b/lib/waf/build/lib_3/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_15.h" -#include "class_19.h" -#include "class_43.h" -#include "class_66.h" -#include "class_90.h" -#include "class_68.h" -#include "class_28.h" -#include "class_84.h" -#include "class_92.h" -#include "class_63.h" -#include "class_57.h" -#include "class_74.h" -#include "class_69.h" -#include "class_27.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_3/class_42.h b/lib/waf/build/lib_3/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_43.cpp b/lib/waf/build/lib_3/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_6.h" -#include "class_57.h" -#include "class_35.h" -#include "class_99.h" -#include "class_34.h" -#include "class_46.h" -#include "class_98.h" -#include "class_74.h" -#include "class_70.h" -#include "class_62.h" -#include "class_83.h" -#include "class_13.h" -#include "class_73.h" -#include "class_37.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_3/class_43.h b/lib/waf/build/lib_3/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_44.cpp b/lib/waf/build/lib_3/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_78.h" -#include "class_21.h" -#include "class_19.h" -#include "class_73.h" -#include "class_41.h" -#include "class_62.h" -#include "class_67.h" -#include "class_33.h" -#include "class_95.h" -#include "class_0.h" -#include "class_98.h" -#include "class_37.h" -#include "class_27.h" -#include "class_68.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_3/class_44.h b/lib/waf/build/lib_3/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_45.cpp b/lib/waf/build/lib_3/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_36.h" -#include "class_60.h" -#include "class_58.h" -#include "class_12.h" -#include "class_78.h" -#include "class_93.h" -#include "class_76.h" -#include "class_33.h" -#include "class_9.h" -#include "class_17.h" -#include "class_87.h" -#include "class_19.h" -#include "class_44.h" -#include "class_16.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_3/class_45.h b/lib/waf/build/lib_3/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_46.cpp b/lib/waf/build/lib_3/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_3.h" -#include "class_32.h" -#include "class_11.h" -#include "class_98.h" -#include "class_48.h" -#include "class_82.h" -#include "class_84.h" -#include "class_57.h" -#include "class_27.h" -#include "class_81.h" -#include "class_24.h" -#include "class_66.h" -#include "class_73.h" -#include "class_0.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_3/class_46.h b/lib/waf/build/lib_3/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_47.cpp b/lib/waf/build/lib_3/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_40.h" -#include "class_93.h" -#include "class_78.h" -#include "class_96.h" -#include "class_83.h" -#include "class_73.h" -#include "class_46.h" -#include "class_99.h" -#include "class_36.h" -#include "class_16.h" -#include "class_87.h" -#include "class_86.h" -#include "class_7.h" -#include "class_5.h" -#include "class_82.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_3/class_47.h b/lib/waf/build/lib_3/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_48.cpp b/lib/waf/build/lib_3/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_93.h" -#include "class_5.h" -#include "class_12.h" -#include "class_97.h" -#include "class_45.h" -#include "class_49.h" -#include "class_54.h" -#include "class_59.h" -#include "class_1.h" -#include "class_92.h" -#include "class_69.h" -#include "class_72.h" -#include "class_10.h" -#include "class_50.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_3/class_48.h b/lib/waf/build/lib_3/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_49.cpp b/lib/waf/build/lib_3/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_31.h" -#include "class_58.h" -#include "class_4.h" -#include "class_52.h" -#include "class_49.h" -#include "class_57.h" -#include "class_93.h" -#include "class_68.h" -#include "class_32.h" -#include "class_47.h" -#include "class_50.h" -#include "class_92.h" -#include "class_64.h" -#include "class_34.h" -#include "class_88.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_3/class_49.h b/lib/waf/build/lib_3/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_5.cpp b/lib/waf/build/lib_3/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_31.h" -#include "class_95.h" -#include "class_41.h" -#include "class_26.h" -#include "class_65.h" -#include "class_82.h" -#include "class_93.h" -#include "class_73.h" -#include "class_8.h" -#include "class_92.h" -#include "class_0.h" -#include "class_54.h" -#include "class_29.h" -#include "class_39.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_3/class_5.h b/lib/waf/build/lib_3/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_50.cpp b/lib/waf/build/lib_3/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_72.h" -#include "class_93.h" -#include "class_80.h" -#include "class_92.h" -#include "class_15.h" -#include "class_25.h" -#include "class_87.h" -#include "class_84.h" -#include "class_76.h" -#include "class_71.h" -#include "class_85.h" -#include "class_47.h" -#include "class_10.h" -#include "class_24.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_3/class_50.h b/lib/waf/build/lib_3/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_51.cpp b/lib/waf/build/lib_3/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_45.h" -#include "class_38.h" -#include "class_93.h" -#include "class_82.h" -#include "class_84.h" -#include "class_80.h" -#include "class_72.h" -#include "class_90.h" -#include "class_31.h" -#include "class_91.h" -#include "class_41.h" -#include "class_75.h" -#include "class_34.h" -#include "class_47.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_3/class_51.h b/lib/waf/build/lib_3/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_52.cpp b/lib/waf/build/lib_3/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_29.h" -#include "class_31.h" -#include "class_72.h" -#include "class_41.h" -#include "class_6.h" -#include "class_69.h" -#include "class_22.h" -#include "class_99.h" -#include "class_2.h" -#include "class_81.h" -#include "class_51.h" -#include "class_26.h" -#include "class_15.h" -#include "class_20.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_3/class_52.h b/lib/waf/build/lib_3/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_53.cpp b/lib/waf/build/lib_3/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_87.h" -#include "class_46.h" -#include "class_61.h" -#include "class_60.h" -#include "class_96.h" -#include "class_91.h" -#include "class_98.h" -#include "class_93.h" -#include "class_21.h" -#include "class_7.h" -#include "class_27.h" -#include "class_79.h" -#include "class_99.h" -#include "class_11.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_3/class_53.h b/lib/waf/build/lib_3/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_54.cpp b/lib/waf/build/lib_3/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_62.h" -#include "class_24.h" -#include "class_69.h" -#include "class_65.h" -#include "class_91.h" -#include "class_29.h" -#include "class_3.h" -#include "class_17.h" -#include "class_96.h" -#include "class_63.h" -#include "class_41.h" -#include "class_68.h" -#include "class_33.h" -#include "class_11.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_3/class_54.h b/lib/waf/build/lib_3/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_55.cpp b/lib/waf/build/lib_3/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_75.h" -#include "class_21.h" -#include "class_41.h" -#include "class_17.h" -#include "class_9.h" -#include "class_78.h" -#include "class_1.h" -#include "class_70.h" -#include "class_81.h" -#include "class_93.h" -#include "class_83.h" -#include "class_80.h" -#include "class_95.h" -#include "class_38.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_3/class_55.h b/lib/waf/build/lib_3/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_56.cpp b/lib/waf/build/lib_3/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_26.h" -#include "class_95.h" -#include "class_77.h" -#include "class_51.h" -#include "class_54.h" -#include "class_8.h" -#include "class_35.h" -#include "class_79.h" -#include "class_6.h" -#include "class_34.h" -#include "class_80.h" -#include "class_50.h" -#include "class_68.h" -#include "class_40.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_3/class_56.h b/lib/waf/build/lib_3/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_57.cpp b/lib/waf/build/lib_3/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_83.h" -#include "class_78.h" -#include "class_65.h" -#include "class_80.h" -#include "class_49.h" -#include "class_17.h" -#include "class_6.h" -#include "class_54.h" -#include "class_55.h" -#include "class_57.h" -#include "class_23.h" -#include "class_39.h" -#include "class_12.h" -#include "class_81.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_3/class_57.h b/lib/waf/build/lib_3/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_58.cpp b/lib/waf/build/lib_3/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_78.h" -#include "class_44.h" -#include "class_79.h" -#include "class_67.h" -#include "class_20.h" -#include "class_18.h" -#include "class_26.h" -#include "class_25.h" -#include "class_54.h" -#include "class_23.h" -#include "class_57.h" -#include "class_62.h" -#include "class_66.h" -#include "class_76.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_3/class_58.h b/lib/waf/build/lib_3/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_59.cpp b/lib/waf/build/lib_3/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_54.h" -#include "class_71.h" -#include "class_64.h" -#include "class_23.h" -#include "class_40.h" -#include "class_84.h" -#include "class_24.h" -#include "class_93.h" -#include "class_80.h" -#include "class_51.h" -#include "class_81.h" -#include "class_52.h" -#include "class_89.h" -#include "class_8.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_3/class_59.h b/lib/waf/build/lib_3/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_6.cpp b/lib/waf/build/lib_3/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_27.h" -#include "class_12.h" -#include "class_24.h" -#include "class_61.h" -#include "class_20.h" -#include "class_97.h" -#include "class_86.h" -#include "class_49.h" -#include "class_95.h" -#include "class_5.h" -#include "class_65.h" -#include "class_47.h" -#include "class_4.h" -#include "class_69.h" -#include "class_68.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_3/class_6.h b/lib/waf/build/lib_3/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_60.cpp b/lib/waf/build/lib_3/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_74.h" -#include "class_95.h" -#include "class_33.h" -#include "class_28.h" -#include "class_91.h" -#include "class_58.h" -#include "class_6.h" -#include "class_31.h" -#include "class_37.h" -#include "class_46.h" -#include "class_61.h" -#include "class_10.h" -#include "class_47.h" -#include "class_94.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_3/class_60.h b/lib/waf/build/lib_3/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_61.cpp b/lib/waf/build/lib_3/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_77.h" -#include "class_7.h" -#include "class_90.h" -#include "class_72.h" -#include "class_74.h" -#include "class_19.h" -#include "class_12.h" -#include "class_64.h" -#include "class_96.h" -#include "class_48.h" -#include "class_94.h" -#include "class_35.h" -#include "class_45.h" -#include "class_25.h" -#include "class_75.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_3/class_61.h b/lib/waf/build/lib_3/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_62.cpp b/lib/waf/build/lib_3/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_57.h" -#include "class_25.h" -#include "class_34.h" -#include "class_80.h" -#include "class_87.h" -#include "class_67.h" -#include "class_74.h" -#include "class_94.h" -#include "class_56.h" -#include "class_84.h" -#include "class_14.h" -#include "class_86.h" -#include "class_4.h" -#include "class_2.h" -#include "class_22.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_3/class_62.h b/lib/waf/build/lib_3/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_63.cpp b/lib/waf/build/lib_3/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_22.h" -#include "class_28.h" -#include "class_75.h" -#include "class_88.h" -#include "class_0.h" -#include "class_81.h" -#include "class_84.h" -#include "class_97.h" -#include "class_67.h" -#include "class_13.h" -#include "class_95.h" -#include "class_74.h" -#include "class_50.h" -#include "class_57.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_3/class_63.h b/lib/waf/build/lib_3/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_64.cpp b/lib/waf/build/lib_3/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_12.h" -#include "class_51.h" -#include "class_80.h" -#include "class_28.h" -#include "class_89.h" -#include "class_82.h" -#include "class_41.h" -#include "class_76.h" -#include "class_42.h" -#include "class_78.h" -#include "class_33.h" -#include "class_56.h" -#include "class_40.h" -#include "class_45.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_3/class_64.h b/lib/waf/build/lib_3/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_65.cpp b/lib/waf/build/lib_3/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_26.h" -#include "class_20.h" -#include "class_22.h" -#include "class_36.h" -#include "class_77.h" -#include "class_4.h" -#include "class_61.h" -#include "class_31.h" -#include "class_49.h" -#include "class_29.h" -#include "class_39.h" -#include "class_41.h" -#include "class_12.h" -#include "class_74.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_3/class_65.h b/lib/waf/build/lib_3/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_66.cpp b/lib/waf/build/lib_3/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_69.h" -#include "class_19.h" -#include "class_46.h" -#include "class_49.h" -#include "class_25.h" -#include "class_82.h" -#include "class_12.h" -#include "class_47.h" -#include "class_60.h" -#include "class_75.h" -#include "class_86.h" -#include "class_57.h" -#include "class_97.h" -#include "class_6.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_3/class_66.h b/lib/waf/build/lib_3/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_67.cpp b/lib/waf/build/lib_3/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_25.h" -#include "class_19.h" -#include "class_34.h" -#include "class_28.h" -#include "class_41.h" -#include "class_53.h" -#include "class_50.h" -#include "class_64.h" -#include "class_23.h" -#include "class_16.h" -#include "class_9.h" -#include "class_56.h" -#include "class_78.h" -#include "class_61.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_3/class_67.h b/lib/waf/build/lib_3/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_68.cpp b/lib/waf/build/lib_3/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_59.h" -#include "class_38.h" -#include "class_43.h" -#include "class_8.h" -#include "class_28.h" -#include "class_85.h" -#include "class_45.h" -#include "class_71.h" -#include "class_80.h" -#include "class_63.h" -#include "class_99.h" -#include "class_32.h" -#include "class_23.h" -#include "class_25.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_3/class_68.h b/lib/waf/build/lib_3/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_69.cpp b/lib/waf/build/lib_3/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_50.h" -#include "class_58.h" -#include "class_45.h" -#include "class_31.h" -#include "class_27.h" -#include "class_74.h" -#include "class_75.h" -#include "class_82.h" -#include "class_33.h" -#include "class_85.h" -#include "class_16.h" -#include "class_62.h" -#include "class_43.h" -#include "class_72.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_3/class_69.h b/lib/waf/build/lib_3/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_7.cpp b/lib/waf/build/lib_3/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_97.h" -#include "class_90.h" -#include "class_79.h" -#include "class_57.h" -#include "class_29.h" -#include "class_14.h" -#include "class_25.h" -#include "class_54.h" -#include "class_41.h" -#include "class_24.h" -#include "class_67.h" -#include "class_50.h" -#include "class_13.h" -#include "class_27.h" -#include "class_36.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_3/class_7.h b/lib/waf/build/lib_3/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_70.cpp b/lib/waf/build/lib_3/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_76.h" -#include "class_56.h" -#include "class_74.h" -#include "class_27.h" -#include "class_73.h" -#include "class_0.h" -#include "class_13.h" -#include "class_85.h" -#include "class_67.h" -#include "class_72.h" -#include "class_28.h" -#include "class_44.h" -#include "class_49.h" -#include "class_1.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_3/class_70.h b/lib/waf/build/lib_3/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_71.cpp b/lib/waf/build/lib_3/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_78.h" -#include "class_61.h" -#include "class_40.h" -#include "class_68.h" -#include "class_90.h" -#include "class_65.h" -#include "class_11.h" -#include "class_58.h" -#include "class_79.h" -#include "class_56.h" -#include "class_9.h" -#include "class_81.h" -#include "class_45.h" -#include "class_57.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_3/class_71.h b/lib/waf/build/lib_3/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_72.cpp b/lib/waf/build/lib_3/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_95.h" -#include "class_15.h" -#include "class_11.h" -#include "class_81.h" -#include "class_2.h" -#include "class_1.h" -#include "class_96.h" -#include "class_7.h" -#include "class_73.h" -#include "class_27.h" -#include "class_57.h" -#include "class_47.h" -#include "class_14.h" -#include "class_10.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_3/class_72.h b/lib/waf/build/lib_3/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_73.cpp b/lib/waf/build/lib_3/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_19.h" -#include "class_21.h" -#include "class_17.h" -#include "class_69.h" -#include "class_76.h" -#include "class_29.h" -#include "class_15.h" -#include "class_88.h" -#include "class_68.h" -#include "class_2.h" -#include "class_84.h" -#include "class_9.h" -#include "class_10.h" -#include "class_70.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_3/class_73.h b/lib/waf/build/lib_3/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_74.cpp b/lib/waf/build/lib_3/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_84.h" -#include "class_33.h" -#include "class_59.h" -#include "class_18.h" -#include "class_34.h" -#include "class_41.h" -#include "class_20.h" -#include "class_80.h" -#include "class_65.h" -#include "class_60.h" -#include "class_39.h" -#include "class_14.h" -#include "class_22.h" -#include "class_19.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_3/class_74.h b/lib/waf/build/lib_3/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_75.cpp b/lib/waf/build/lib_3/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_94.h" -#include "class_53.h" -#include "class_1.h" -#include "class_84.h" -#include "class_91.h" -#include "class_13.h" -#include "class_39.h" -#include "class_71.h" -#include "class_43.h" -#include "class_46.h" -#include "class_80.h" -#include "class_79.h" -#include "class_52.h" -#include "class_67.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_3/class_75.h b/lib/waf/build/lib_3/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_76.cpp b/lib/waf/build/lib_3/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_9.h" -#include "class_50.h" -#include "class_49.h" -#include "class_38.h" -#include "class_27.h" -#include "class_95.h" -#include "class_0.h" -#include "class_13.h" -#include "class_39.h" -#include "class_26.h" -#include "class_65.h" -#include "class_85.h" -#include "class_52.h" -#include "class_71.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_3/class_76.h b/lib/waf/build/lib_3/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_77.cpp b/lib/waf/build/lib_3/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_60.h" -#include "class_53.h" -#include "class_16.h" -#include "class_80.h" -#include "class_72.h" -#include "class_2.h" -#include "class_48.h" -#include "class_77.h" -#include "class_63.h" -#include "class_58.h" -#include "class_91.h" -#include "class_41.h" -#include "class_69.h" -#include "class_84.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_3/class_77.h b/lib/waf/build/lib_3/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_78.cpp b/lib/waf/build/lib_3/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_54.h" -#include "class_11.h" -#include "class_58.h" -#include "class_2.h" -#include "class_60.h" -#include "class_95.h" -#include "class_17.h" -#include "class_75.h" -#include "class_79.h" -#include "class_66.h" -#include "class_84.h" -#include "class_59.h" -#include "class_71.h" -#include "class_32.h" -#include "class_91.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_3/class_78.h b/lib/waf/build/lib_3/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_79.cpp b/lib/waf/build/lib_3/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_66.h" -#include "class_9.h" -#include "class_84.h" -#include "class_89.h" -#include "class_70.h" -#include "class_86.h" -#include "class_76.h" -#include "class_19.h" -#include "class_64.h" -#include "class_54.h" -#include "class_72.h" -#include "class_44.h" -#include "class_77.h" -#include "class_35.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_3/class_79.h b/lib/waf/build/lib_3/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_8.cpp b/lib/waf/build/lib_3/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_37.h" -#include "class_44.h" -#include "class_70.h" -#include "class_77.h" -#include "class_72.h" -#include "class_26.h" -#include "class_54.h" -#include "class_84.h" -#include "class_33.h" -#include "class_29.h" -#include "class_73.h" -#include "class_0.h" -#include "class_71.h" -#include "class_81.h" -#include "class_88.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_3/class_8.h b/lib/waf/build/lib_3/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_80.cpp b/lib/waf/build/lib_3/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_9.h" -#include "class_19.h" -#include "class_96.h" -#include "class_17.h" -#include "class_7.h" -#include "class_39.h" -#include "class_73.h" -#include "class_50.h" -#include "class_8.h" -#include "class_79.h" -#include "class_67.h" -#include "class_58.h" -#include "class_16.h" -#include "class_1.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_3/class_80.h b/lib/waf/build/lib_3/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_81.cpp b/lib/waf/build/lib_3/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_17.h" -#include "class_64.h" -#include "class_56.h" -#include "class_51.h" -#include "class_29.h" -#include "class_14.h" -#include "class_66.h" -#include "class_87.h" -#include "class_11.h" -#include "class_76.h" -#include "class_15.h" -#include "class_84.h" -#include "class_36.h" -#include "class_43.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_3/class_81.h b/lib/waf/build/lib_3/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_82.cpp b/lib/waf/build/lib_3/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_9.h" -#include "class_17.h" -#include "class_82.h" -#include "class_58.h" -#include "class_92.h" -#include "class_8.h" -#include "class_7.h" -#include "class_64.h" -#include "class_79.h" -#include "class_57.h" -#include "class_39.h" -#include "class_24.h" -#include "class_36.h" -#include "class_10.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_3/class_82.h b/lib/waf/build/lib_3/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_83.cpp b/lib/waf/build/lib_3/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_59.h" -#include "class_34.h" -#include "class_81.h" -#include "class_12.h" -#include "class_28.h" -#include "class_67.h" -#include "class_95.h" -#include "class_14.h" -#include "class_18.h" -#include "class_53.h" -#include "class_64.h" -#include "class_48.h" -#include "class_11.h" -#include "class_20.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_3/class_83.h b/lib/waf/build/lib_3/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_84.cpp b/lib/waf/build/lib_3/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_53.h" -#include "class_30.h" -#include "class_35.h" -#include "class_14.h" -#include "class_18.h" -#include "class_99.h" -#include "class_25.h" -#include "class_62.h" -#include "class_54.h" -#include "class_86.h" -#include "class_94.h" -#include "class_17.h" -#include "class_5.h" -#include "class_65.h" -#include "class_64.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_3/class_84.h b/lib/waf/build/lib_3/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_85.cpp b/lib/waf/build/lib_3/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_99.h" -#include "class_35.h" -#include "class_27.h" -#include "class_22.h" -#include "class_72.h" -#include "class_8.h" -#include "class_23.h" -#include "class_38.h" -#include "class_87.h" -#include "class_45.h" -#include "class_7.h" -#include "class_79.h" -#include "class_84.h" -#include "class_30.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_3/class_85.h b/lib/waf/build/lib_3/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_86.cpp b/lib/waf/build/lib_3/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_22.h" -#include "class_89.h" -#include "class_9.h" -#include "class_78.h" -#include "class_31.h" -#include "class_16.h" -#include "class_95.h" -#include "class_43.h" -#include "class_83.h" -#include "class_15.h" -#include "class_39.h" -#include "class_85.h" -#include "class_5.h" -#include "class_52.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_3/class_86.h b/lib/waf/build/lib_3/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_87.cpp b/lib/waf/build/lib_3/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_82.h" -#include "class_60.h" -#include "class_9.h" -#include "class_24.h" -#include "class_20.h" -#include "class_52.h" -#include "class_29.h" -#include "class_67.h" -#include "class_41.h" -#include "class_28.h" -#include "class_74.h" -#include "class_46.h" -#include "class_18.h" -#include "class_1.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_3/class_87.h b/lib/waf/build/lib_3/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_88.cpp b/lib/waf/build/lib_3/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_96.h" -#include "class_72.h" -#include "class_22.h" -#include "class_71.h" -#include "class_37.h" -#include "class_41.h" -#include "class_30.h" -#include "class_36.h" -#include "class_73.h" -#include "class_7.h" -#include "class_84.h" -#include "class_60.h" -#include "class_23.h" -#include "class_68.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_3/class_88.h b/lib/waf/build/lib_3/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_89.cpp b/lib/waf/build/lib_3/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_37.h" -#include "class_5.h" -#include "class_63.h" -#include "class_82.h" -#include "class_9.h" -#include "class_72.h" -#include "class_56.h" -#include "class_81.h" -#include "class_69.h" -#include "class_76.h" -#include "class_1.h" -#include "class_18.h" -#include "class_87.h" -#include "class_26.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_3/class_89.h b/lib/waf/build/lib_3/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_9.cpp b/lib/waf/build/lib_3/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_78.h" -#include "class_20.h" -#include "class_27.h" -#include "class_59.h" -#include "class_25.h" -#include "class_30.h" -#include "class_51.h" -#include "class_80.h" -#include "class_96.h" -#include "class_33.h" -#include "class_56.h" -#include "class_11.h" -#include "class_49.h" -#include "class_39.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_3/class_9.h b/lib/waf/build/lib_3/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_90.cpp b/lib/waf/build/lib_3/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_44.h" -#include "class_75.h" -#include "class_46.h" -#include "class_51.h" -#include "class_30.h" -#include "class_87.h" -#include "class_29.h" -#include "class_17.h" -#include "class_12.h" -#include "class_72.h" -#include "class_74.h" -#include "class_77.h" -#include "class_99.h" -#include "class_32.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_3/class_90.h b/lib/waf/build/lib_3/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_91.cpp b/lib/waf/build/lib_3/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_51.h" -#include "class_87.h" -#include "class_14.h" -#include "class_81.h" -#include "class_18.h" -#include "class_79.h" -#include "class_69.h" -#include "class_31.h" -#include "class_49.h" -#include "class_54.h" -#include "class_94.h" -#include "class_50.h" -#include "class_19.h" -#include "class_20.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_3/class_91.h b/lib/waf/build/lib_3/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_92.cpp b/lib/waf/build/lib_3/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_76.h" -#include "class_70.h" -#include "class_26.h" -#include "class_10.h" -#include "class_0.h" -#include "class_86.h" -#include "class_16.h" -#include "class_23.h" -#include "class_31.h" -#include "class_38.h" -#include "class_97.h" -#include "class_77.h" -#include "class_24.h" -#include "class_28.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_3/class_92.h b/lib/waf/build/lib_3/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_93.cpp b/lib/waf/build/lib_3/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_40.h" -#include "class_24.h" -#include "class_49.h" -#include "class_4.h" -#include "class_65.h" -#include "class_34.h" -#include "class_88.h" -#include "class_90.h" -#include "class_6.h" -#include "class_37.h" -#include "class_10.h" -#include "class_72.h" -#include "class_84.h" -#include "class_75.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_3/class_93.h b/lib/waf/build/lib_3/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_94.cpp b/lib/waf/build/lib_3/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_82.h" -#include "class_14.h" -#include "class_78.h" -#include "class_96.h" -#include "class_63.h" -#include "class_1.h" -#include "class_77.h" -#include "class_26.h" -#include "class_7.h" -#include "class_13.h" -#include "class_16.h" -#include "class_3.h" -#include "class_38.h" -#include "class_6.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_3/class_94.h b/lib/waf/build/lib_3/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_95.cpp b/lib/waf/build/lib_3/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_84.h" -#include "class_0.h" -#include "class_73.h" -#include "class_50.h" -#include "class_62.h" -#include "class_28.h" -#include "class_94.h" -#include "class_30.h" -#include "class_68.h" -#include "class_42.h" -#include "class_76.h" -#include "class_36.h" -#include "class_83.h" -#include "class_98.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_3/class_95.h b/lib/waf/build/lib_3/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_96.cpp b/lib/waf/build/lib_3/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_30.h" -#include "class_87.h" -#include "class_2.h" -#include "class_80.h" -#include "class_36.h" -#include "class_18.h" -#include "class_33.h" -#include "class_35.h" -#include "class_54.h" -#include "class_43.h" -#include "class_75.h" -#include "class_77.h" -#include "class_92.h" -#include "class_29.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_3/class_96.h b/lib/waf/build/lib_3/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_97.cpp b/lib/waf/build/lib_3/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_13.h" -#include "class_40.h" -#include "class_92.h" -#include "class_52.h" -#include "class_53.h" -#include "class_25.h" -#include "class_50.h" -#include "class_16.h" -#include "class_32.h" -#include "class_72.h" -#include "class_44.h" -#include "class_64.h" -#include "class_89.h" -#include "class_99.h" -#include "class_36.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_3/class_97.h b/lib/waf/build/lib_3/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_98.cpp b/lib/waf/build/lib_3/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_7.h" -#include "class_32.h" -#include "class_41.h" -#include "class_14.h" -#include "class_22.h" -#include "class_50.h" -#include "class_20.h" -#include "class_88.h" -#include "class_18.h" -#include "class_0.h" -#include "class_70.h" -#include "class_39.h" -#include "class_43.h" -#include "class_45.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_3/class_98.h b/lib/waf/build/lib_3/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_3/class_99.cpp b/lib/waf/build/lib_3/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_3/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_73.h" -#include "class_38.h" -#include "class_84.h" -#include "class_15.h" -#include "class_63.h" -#include "class_4.h" -#include "class_20.h" -#include "class_7.h" -#include "class_29.h" -#include "class_46.h" -#include "class_50.h" -#include "class_44.h" -#include "class_40.h" -#include "class_37.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_3/class_99.h b/lib/waf/build/lib_3/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_3/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_4/Makefile b/lib/waf/build/lib_4/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_4/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_4.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_4/Makefile.am b/lib/waf/build/lib_4/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_4/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib4.la -lib4_la_SOURCES = lib_4/class_0.cpp lib_4/class_1.cpp lib_4/class_2.cpp lib_4/class_3.cpp lib_4/class_4.cpp lib_4/class_5.cpp lib_4/class_6.cpp lib_4/class_7.cpp lib_4/class_8.cpp lib_4/class_9.cpp lib_4/class_10.cpp lib_4/class_11.cpp lib_4/class_12.cpp lib_4/class_13.cpp lib_4/class_14.cpp lib_4/class_15.cpp lib_4/class_16.cpp lib_4/class_17.cpp lib_4/class_18.cpp lib_4/class_19.cpp lib_4/class_20.cpp lib_4/class_21.cpp lib_4/class_22.cpp lib_4/class_23.cpp lib_4/class_24.cpp lib_4/class_25.cpp lib_4/class_26.cpp lib_4/class_27.cpp lib_4/class_28.cpp lib_4/class_29.cpp lib_4/class_30.cpp lib_4/class_31.cpp lib_4/class_32.cpp lib_4/class_33.cpp lib_4/class_34.cpp lib_4/class_35.cpp lib_4/class_36.cpp lib_4/class_37.cpp lib_4/class_38.cpp lib_4/class_39.cpp lib_4/class_40.cpp lib_4/class_41.cpp lib_4/class_42.cpp lib_4/class_43.cpp lib_4/class_44.cpp lib_4/class_45.cpp lib_4/class_46.cpp lib_4/class_47.cpp lib_4/class_48.cpp lib_4/class_49.cpp lib_4/class_50.cpp lib_4/class_51.cpp lib_4/class_52.cpp lib_4/class_53.cpp lib_4/class_54.cpp lib_4/class_55.cpp lib_4/class_56.cpp lib_4/class_57.cpp lib_4/class_58.cpp lib_4/class_59.cpp lib_4/class_60.cpp lib_4/class_61.cpp lib_4/class_62.cpp lib_4/class_63.cpp lib_4/class_64.cpp lib_4/class_65.cpp lib_4/class_66.cpp lib_4/class_67.cpp lib_4/class_68.cpp lib_4/class_69.cpp lib_4/class_70.cpp lib_4/class_71.cpp lib_4/class_72.cpp lib_4/class_73.cpp lib_4/class_74.cpp lib_4/class_75.cpp lib_4/class_76.cpp lib_4/class_77.cpp lib_4/class_78.cpp lib_4/class_79.cpp lib_4/class_80.cpp lib_4/class_81.cpp lib_4/class_82.cpp lib_4/class_83.cpp lib_4/class_84.cpp lib_4/class_85.cpp lib_4/class_86.cpp lib_4/class_87.cpp lib_4/class_88.cpp lib_4/class_89.cpp lib_4/class_90.cpp lib_4/class_91.cpp lib_4/class_92.cpp lib_4/class_93.cpp lib_4/class_94.cpp lib_4/class_95.cpp lib_4/class_96.cpp lib_4/class_97.cpp lib_4/class_98.cpp lib_4/class_99.cpp diff --git a/lib/waf/build/lib_4/SConscript b/lib/waf/build/lib_4/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_4/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_4", list) - diff --git a/lib/waf/build/lib_4/class_0.cpp b/lib/waf/build/lib_4/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_86.h" -#include "class_50.h" -#include "class_67.h" -#include "class_43.h" -#include "class_42.h" -#include "class_30.h" -#include "class_13.h" -#include "class_53.h" -#include "class_99.h" -#include "class_3.h" -#include "class_76.h" -#include "class_51.h" -#include "class_59.h" -#include "class_23.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_4/class_0.h b/lib/waf/build/lib_4/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_1.cpp b/lib/waf/build/lib_4/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_43.h" -#include "class_99.h" -#include "class_3.h" -#include "class_61.h" -#include "class_78.h" -#include "class_30.h" -#include "class_94.h" -#include "class_24.h" -#include "class_31.h" -#include "class_40.h" -#include "class_7.h" -#include "class_64.h" -#include "class_69.h" -#include "class_8.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_4/class_1.h b/lib/waf/build/lib_4/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_10.cpp b/lib/waf/build/lib_4/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_50.h" -#include "class_1.h" -#include "class_90.h" -#include "class_58.h" -#include "class_18.h" -#include "class_38.h" -#include "class_12.h" -#include "class_3.h" -#include "class_77.h" -#include "class_40.h" -#include "class_46.h" -#include "class_68.h" -#include "class_41.h" -#include "class_44.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_4/class_10.h b/lib/waf/build/lib_4/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_11.cpp b/lib/waf/build/lib_4/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_14.h" -#include "class_24.h" -#include "class_67.h" -#include "class_32.h" -#include "class_68.h" -#include "class_71.h" -#include "class_93.h" -#include "class_25.h" -#include "class_62.h" -#include "class_50.h" -#include "class_11.h" -#include "class_12.h" -#include "class_30.h" -#include "class_18.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_4/class_11.h b/lib/waf/build/lib_4/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_12.cpp b/lib/waf/build/lib_4/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_81.h" -#include "class_10.h" -#include "class_1.h" -#include "class_18.h" -#include "class_57.h" -#include "class_17.h" -#include "class_35.h" -#include "class_28.h" -#include "class_3.h" -#include "class_83.h" -#include "class_72.h" -#include "class_91.h" -#include "class_45.h" -#include "class_50.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_4/class_12.h b/lib/waf/build/lib_4/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_13.cpp b/lib/waf/build/lib_4/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_84.h" -#include "class_80.h" -#include "class_63.h" -#include "class_55.h" -#include "class_33.h" -#include "class_23.h" -#include "class_4.h" -#include "class_87.h" -#include "class_82.h" -#include "class_74.h" -#include "class_29.h" -#include "class_47.h" -#include "class_76.h" -#include "class_88.h" -#include "class_95.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_4/class_13.h b/lib/waf/build/lib_4/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_14.cpp b/lib/waf/build/lib_4/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_88.h" -#include "class_95.h" -#include "class_2.h" -#include "class_99.h" -#include "class_19.h" -#include "class_25.h" -#include "class_31.h" -#include "class_47.h" -#include "class_73.h" -#include "class_28.h" -#include "class_81.h" -#include "class_38.h" -#include "class_1.h" -#include "class_76.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_4/class_14.h b/lib/waf/build/lib_4/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_15.cpp b/lib/waf/build/lib_4/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_75.h" -#include "class_77.h" -#include "class_2.h" -#include "class_33.h" -#include "class_31.h" -#include "class_22.h" -#include "class_54.h" -#include "class_15.h" -#include "class_89.h" -#include "class_35.h" -#include "class_42.h" -#include "class_36.h" -#include "class_69.h" -#include "class_97.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_4/class_15.h b/lib/waf/build/lib_4/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_16.cpp b/lib/waf/build/lib_4/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_69.h" -#include "class_20.h" -#include "class_11.h" -#include "class_61.h" -#include "class_1.h" -#include "class_46.h" -#include "class_26.h" -#include "class_39.h" -#include "class_40.h" -#include "class_42.h" -#include "class_9.h" -#include "class_53.h" -#include "class_91.h" -#include "class_84.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_4/class_16.h b/lib/waf/build/lib_4/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_17.cpp b/lib/waf/build/lib_4/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_31.h" -#include "class_67.h" -#include "class_83.h" -#include "class_62.h" -#include "class_77.h" -#include "class_19.h" -#include "class_59.h" -#include "class_15.h" -#include "class_91.h" -#include "class_97.h" -#include "class_0.h" -#include "class_68.h" -#include "class_8.h" -#include "class_17.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_4/class_17.h b/lib/waf/build/lib_4/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_18.cpp b/lib/waf/build/lib_4/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_81.h" -#include "class_63.h" -#include "class_64.h" -#include "class_8.h" -#include "class_56.h" -#include "class_72.h" -#include "class_9.h" -#include "class_14.h" -#include "class_20.h" -#include "class_24.h" -#include "class_76.h" -#include "class_10.h" -#include "class_46.h" -#include "class_61.h" -#include "class_99.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_4/class_18.h b/lib/waf/build/lib_4/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_19.cpp b/lib/waf/build/lib_4/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_74.h" -#include "class_2.h" -#include "class_88.h" -#include "class_72.h" -#include "class_55.h" -#include "class_58.h" -#include "class_76.h" -#include "class_9.h" -#include "class_67.h" -#include "class_56.h" -#include "class_32.h" -#include "class_37.h" -#include "class_91.h" -#include "class_30.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_4/class_19.h b/lib/waf/build/lib_4/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_2.cpp b/lib/waf/build/lib_4/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_89.h" -#include "class_0.h" -#include "class_39.h" -#include "class_96.h" -#include "class_93.h" -#include "class_81.h" -#include "class_53.h" -#include "class_34.h" -#include "class_73.h" -#include "class_60.h" -#include "class_68.h" -#include "class_56.h" -#include "class_50.h" -#include "class_38.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_4/class_2.h b/lib/waf/build/lib_4/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_20.cpp b/lib/waf/build/lib_4/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_47.h" -#include "class_49.h" -#include "class_98.h" -#include "class_82.h" -#include "class_24.h" -#include "class_34.h" -#include "class_22.h" -#include "class_33.h" -#include "class_39.h" -#include "class_20.h" -#include "class_52.h" -#include "class_84.h" -#include "class_61.h" -#include "class_58.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_4/class_20.h b/lib/waf/build/lib_4/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_21.cpp b/lib/waf/build/lib_4/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_2.h" -#include "class_57.h" -#include "class_75.h" -#include "class_29.h" -#include "class_25.h" -#include "class_55.h" -#include "class_80.h" -#include "class_51.h" -#include "class_43.h" -#include "class_88.h" -#include "class_83.h" -#include "class_73.h" -#include "class_69.h" -#include "class_65.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_4/class_21.h b/lib/waf/build/lib_4/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_22.cpp b/lib/waf/build/lib_4/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_90.h" -#include "class_95.h" -#include "class_41.h" -#include "class_47.h" -#include "class_58.h" -#include "class_43.h" -#include "class_97.h" -#include "class_63.h" -#include "class_61.h" -#include "class_17.h" -#include "class_8.h" -#include "class_4.h" -#include "class_26.h" -#include "class_19.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_4/class_22.h b/lib/waf/build/lib_4/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_23.cpp b/lib/waf/build/lib_4/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_73.h" -#include "class_79.h" -#include "class_56.h" -#include "class_26.h" -#include "class_28.h" -#include "class_95.h" -#include "class_16.h" -#include "class_46.h" -#include "class_3.h" -#include "class_55.h" -#include "class_48.h" -#include "class_27.h" -#include "class_30.h" -#include "class_77.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_4/class_23.h b/lib/waf/build/lib_4/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_24.cpp b/lib/waf/build/lib_4/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_49.h" -#include "class_4.h" -#include "class_89.h" -#include "class_42.h" -#include "class_53.h" -#include "class_2.h" -#include "class_25.h" -#include "class_36.h" -#include "class_57.h" -#include "class_51.h" -#include "class_67.h" -#include "class_17.h" -#include "class_52.h" -#include "class_38.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_4/class_24.h b/lib/waf/build/lib_4/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_25.cpp b/lib/waf/build/lib_4/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_15.h" -#include "class_62.h" -#include "class_72.h" -#include "class_6.h" -#include "class_0.h" -#include "class_71.h" -#include "class_84.h" -#include "class_2.h" -#include "class_56.h" -#include "class_70.h" -#include "class_88.h" -#include "class_38.h" -#include "class_39.h" -#include "class_58.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_4/class_25.h b/lib/waf/build/lib_4/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_26.cpp b/lib/waf/build/lib_4/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_87.h" -#include "class_39.h" -#include "class_0.h" -#include "class_98.h" -#include "class_81.h" -#include "class_33.h" -#include "class_8.h" -#include "class_55.h" -#include "class_26.h" -#include "class_7.h" -#include "class_56.h" -#include "class_2.h" -#include "class_78.h" -#include "class_23.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_4/class_26.h b/lib/waf/build/lib_4/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_27.cpp b/lib/waf/build/lib_4/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_48.h" -#include "class_66.h" -#include "class_39.h" -#include "class_9.h" -#include "class_74.h" -#include "class_6.h" -#include "class_72.h" -#include "class_5.h" -#include "class_83.h" -#include "class_22.h" -#include "class_10.h" -#include "class_78.h" -#include "class_14.h" -#include "class_25.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_4/class_27.h b/lib/waf/build/lib_4/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_28.cpp b/lib/waf/build/lib_4/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_59.h" -#include "class_78.h" -#include "class_32.h" -#include "class_40.h" -#include "class_75.h" -#include "class_82.h" -#include "class_17.h" -#include "class_34.h" -#include "class_97.h" -#include "class_98.h" -#include "class_85.h" -#include "class_67.h" -#include "class_9.h" -#include "class_66.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_4/class_28.h b/lib/waf/build/lib_4/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_29.cpp b/lib/waf/build/lib_4/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_96.h" -#include "class_90.h" -#include "class_1.h" -#include "class_12.h" -#include "class_65.h" -#include "class_28.h" -#include "class_6.h" -#include "class_27.h" -#include "class_81.h" -#include "class_56.h" -#include "class_89.h" -#include "class_58.h" -#include "class_8.h" -#include "class_41.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_4/class_29.h b/lib/waf/build/lib_4/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_3.cpp b/lib/waf/build/lib_4/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_2.h" -#include "class_58.h" -#include "class_74.h" -#include "class_16.h" -#include "class_33.h" -#include "class_77.h" -#include "class_46.h" -#include "class_12.h" -#include "class_78.h" -#include "class_41.h" -#include "class_14.h" -#include "class_97.h" -#include "class_31.h" -#include "class_73.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_4/class_3.h b/lib/waf/build/lib_4/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_30.cpp b/lib/waf/build/lib_4/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_80.h" -#include "class_52.h" -#include "class_42.h" -#include "class_95.h" -#include "class_92.h" -#include "class_93.h" -#include "class_61.h" -#include "class_11.h" -#include "class_44.h" -#include "class_73.h" -#include "class_54.h" -#include "class_86.h" -#include "class_30.h" -#include "class_63.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_4/class_30.h b/lib/waf/build/lib_4/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_31.cpp b/lib/waf/build/lib_4/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_20.h" -#include "class_97.h" -#include "class_75.h" -#include "class_69.h" -#include "class_0.h" -#include "class_67.h" -#include "class_37.h" -#include "class_50.h" -#include "class_93.h" -#include "class_24.h" -#include "class_14.h" -#include "class_70.h" -#include "class_53.h" -#include "class_8.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_4/class_31.h b/lib/waf/build/lib_4/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_32.cpp b/lib/waf/build/lib_4/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_82.h" -#include "class_84.h" -#include "class_11.h" -#include "class_74.h" -#include "class_97.h" -#include "class_57.h" -#include "class_17.h" -#include "class_36.h" -#include "class_71.h" -#include "class_59.h" -#include "class_16.h" -#include "class_53.h" -#include "class_7.h" -#include "class_76.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_4/class_32.h b/lib/waf/build/lib_4/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_33.cpp b/lib/waf/build/lib_4/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_50.h" -#include "class_38.h" -#include "class_40.h" -#include "class_73.h" -#include "class_52.h" -#include "class_21.h" -#include "class_83.h" -#include "class_36.h" -#include "class_2.h" -#include "class_64.h" -#include "class_68.h" -#include "class_62.h" -#include "class_3.h" -#include "class_23.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_4/class_33.h b/lib/waf/build/lib_4/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_34.cpp b/lib/waf/build/lib_4/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_40.h" -#include "class_53.h" -#include "class_64.h" -#include "class_6.h" -#include "class_78.h" -#include "class_90.h" -#include "class_87.h" -#include "class_1.h" -#include "class_45.h" -#include "class_23.h" -#include "class_81.h" -#include "class_16.h" -#include "class_75.h" -#include "class_60.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_4/class_34.h b/lib/waf/build/lib_4/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_35.cpp b/lib/waf/build/lib_4/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_85.h" -#include "class_45.h" -#include "class_36.h" -#include "class_31.h" -#include "class_67.h" -#include "class_9.h" -#include "class_30.h" -#include "class_87.h" -#include "class_26.h" -#include "class_40.h" -#include "class_48.h" -#include "class_80.h" -#include "class_60.h" -#include "class_42.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_4/class_35.h b/lib/waf/build/lib_4/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_36.cpp b/lib/waf/build/lib_4/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_88.h" -#include "class_10.h" -#include "class_6.h" -#include "class_44.h" -#include "class_77.h" -#include "class_20.h" -#include "class_46.h" -#include "class_34.h" -#include "class_78.h" -#include "class_48.h" -#include "class_92.h" -#include "class_2.h" -#include "class_27.h" -#include "class_71.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_4/class_36.h b/lib/waf/build/lib_4/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_37.cpp b/lib/waf/build/lib_4/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_99.h" -#include "class_49.h" -#include "class_79.h" -#include "class_57.h" -#include "class_18.h" -#include "class_61.h" -#include "class_0.h" -#include "class_89.h" -#include "class_25.h" -#include "class_16.h" -#include "class_77.h" -#include "class_95.h" -#include "class_86.h" -#include "class_11.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_4/class_37.h b/lib/waf/build/lib_4/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_38.cpp b/lib/waf/build/lib_4/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_83.h" -#include "class_44.h" -#include "class_31.h" -#include "class_85.h" -#include "class_97.h" -#include "class_47.h" -#include "class_54.h" -#include "class_30.h" -#include "class_61.h" -#include "class_25.h" -#include "class_66.h" -#include "class_91.h" -#include "class_53.h" -#include "class_89.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_4/class_38.h b/lib/waf/build/lib_4/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_39.cpp b/lib/waf/build/lib_4/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_41.h" -#include "class_4.h" -#include "class_13.h" -#include "class_78.h" -#include "class_62.h" -#include "class_20.h" -#include "class_86.h" -#include "class_54.h" -#include "class_25.h" -#include "class_48.h" -#include "class_34.h" -#include "class_61.h" -#include "class_99.h" -#include "class_65.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_4/class_39.h b/lib/waf/build/lib_4/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_4.cpp b/lib/waf/build/lib_4/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_22.h" -#include "class_37.h" -#include "class_10.h" -#include "class_70.h" -#include "class_36.h" -#include "class_95.h" -#include "class_97.h" -#include "class_4.h" -#include "class_79.h" -#include "class_90.h" -#include "class_84.h" -#include "class_27.h" -#include "class_59.h" -#include "class_89.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_4/class_4.h b/lib/waf/build/lib_4/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_40.cpp b/lib/waf/build/lib_4/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_64.h" -#include "class_46.h" -#include "class_54.h" -#include "class_86.h" -#include "class_58.h" -#include "class_1.h" -#include "class_78.h" -#include "class_30.h" -#include "class_38.h" -#include "class_96.h" -#include "class_84.h" -#include "class_31.h" -#include "class_23.h" -#include "class_39.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_4/class_40.h b/lib/waf/build/lib_4/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_41.cpp b/lib/waf/build/lib_4/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_89.h" -#include "class_43.h" -#include "class_38.h" -#include "class_54.h" -#include "class_63.h" -#include "class_11.h" -#include "class_1.h" -#include "class_95.h" -#include "class_41.h" -#include "class_21.h" -#include "class_80.h" -#include "class_35.h" -#include "class_78.h" -#include "class_92.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_4/class_41.h b/lib/waf/build/lib_4/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_42.cpp b/lib/waf/build/lib_4/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_71.h" -#include "class_49.h" -#include "class_25.h" -#include "class_89.h" -#include "class_30.h" -#include "class_57.h" -#include "class_69.h" -#include "class_53.h" -#include "class_74.h" -#include "class_9.h" -#include "class_13.h" -#include "class_73.h" -#include "class_47.h" -#include "class_8.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_4/class_42.h b/lib/waf/build/lib_4/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_43.cpp b/lib/waf/build/lib_4/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_46.h" -#include "class_96.h" -#include "class_3.h" -#include "class_66.h" -#include "class_32.h" -#include "class_14.h" -#include "class_53.h" -#include "class_45.h" -#include "class_20.h" -#include "class_69.h" -#include "class_2.h" -#include "class_15.h" -#include "class_98.h" -#include "class_11.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_4/class_43.h b/lib/waf/build/lib_4/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_44.cpp b/lib/waf/build/lib_4/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_62.h" -#include "class_58.h" -#include "class_15.h" -#include "class_23.h" -#include "class_6.h" -#include "class_96.h" -#include "class_93.h" -#include "class_4.h" -#include "class_65.h" -#include "class_42.h" -#include "class_63.h" -#include "class_84.h" -#include "class_18.h" -#include "class_72.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_4/class_44.h b/lib/waf/build/lib_4/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_45.cpp b/lib/waf/build/lib_4/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_38.h" -#include "class_1.h" -#include "class_95.h" -#include "class_5.h" -#include "class_85.h" -#include "class_62.h" -#include "class_29.h" -#include "class_4.h" -#include "class_22.h" -#include "class_72.h" -#include "class_79.h" -#include "class_69.h" -#include "class_80.h" -#include "class_82.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_4/class_45.h b/lib/waf/build/lib_4/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_46.cpp b/lib/waf/build/lib_4/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_93.h" -#include "class_26.h" -#include "class_9.h" -#include "class_94.h" -#include "class_35.h" -#include "class_51.h" -#include "class_29.h" -#include "class_37.h" -#include "class_61.h" -#include "class_56.h" -#include "class_52.h" -#include "class_57.h" -#include "class_62.h" -#include "class_8.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_4/class_46.h b/lib/waf/build/lib_4/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_47.cpp b/lib/waf/build/lib_4/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_51.h" -#include "class_97.h" -#include "class_32.h" -#include "class_99.h" -#include "class_3.h" -#include "class_52.h" -#include "class_74.h" -#include "class_93.h" -#include "class_67.h" -#include "class_89.h" -#include "class_11.h" -#include "class_46.h" -#include "class_73.h" -#include "class_53.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_4/class_47.h b/lib/waf/build/lib_4/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_48.cpp b/lib/waf/build/lib_4/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_51.h" -#include "class_95.h" -#include "class_37.h" -#include "class_85.h" -#include "class_88.h" -#include "class_78.h" -#include "class_70.h" -#include "class_54.h" -#include "class_6.h" -#include "class_53.h" -#include "class_13.h" -#include "class_36.h" -#include "class_23.h" -#include "class_49.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_4/class_48.h b/lib/waf/build/lib_4/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_49.cpp b/lib/waf/build/lib_4/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_98.h" -#include "class_81.h" -#include "class_41.h" -#include "class_54.h" -#include "class_26.h" -#include "class_47.h" -#include "class_68.h" -#include "class_86.h" -#include "class_95.h" -#include "class_66.h" -#include "class_19.h" -#include "class_93.h" -#include "class_74.h" -#include "class_71.h" -#include "class_14.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_4/class_49.h b/lib/waf/build/lib_4/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_5.cpp b/lib/waf/build/lib_4/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_79.h" -#include "class_97.h" -#include "class_68.h" -#include "class_90.h" -#include "class_83.h" -#include "class_15.h" -#include "class_22.h" -#include "class_17.h" -#include "class_51.h" -#include "class_30.h" -#include "class_50.h" -#include "class_3.h" -#include "class_40.h" -#include "class_42.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_4/class_5.h b/lib/waf/build/lib_4/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_50.cpp b/lib/waf/build/lib_4/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_52.h" -#include "class_24.h" -#include "class_40.h" -#include "class_19.h" -#include "class_91.h" -#include "class_46.h" -#include "class_90.h" -#include "class_16.h" -#include "class_37.h" -#include "class_95.h" -#include "class_66.h" -#include "class_58.h" -#include "class_36.h" -#include "class_88.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_4/class_50.h b/lib/waf/build/lib_4/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_51.cpp b/lib/waf/build/lib_4/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_51.h" -#include "class_57.h" -#include "class_17.h" -#include "class_68.h" -#include "class_87.h" -#include "class_69.h" -#include "class_19.h" -#include "class_63.h" -#include "class_95.h" -#include "class_40.h" -#include "class_93.h" -#include "class_72.h" -#include "class_45.h" -#include "class_46.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_4/class_51.h b/lib/waf/build/lib_4/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_52.cpp b/lib/waf/build/lib_4/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_77.h" -#include "class_67.h" -#include "class_70.h" -#include "class_73.h" -#include "class_64.h" -#include "class_15.h" -#include "class_3.h" -#include "class_16.h" -#include "class_98.h" -#include "class_51.h" -#include "class_40.h" -#include "class_39.h" -#include "class_92.h" -#include "class_11.h" -#include "class_96.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_4/class_52.h b/lib/waf/build/lib_4/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_53.cpp b/lib/waf/build/lib_4/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_72.h" -#include "class_17.h" -#include "class_20.h" -#include "class_29.h" -#include "class_88.h" -#include "class_89.h" -#include "class_78.h" -#include "class_98.h" -#include "class_2.h" -#include "class_6.h" -#include "class_36.h" -#include "class_39.h" -#include "class_84.h" -#include "class_9.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_4/class_53.h b/lib/waf/build/lib_4/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_54.cpp b/lib/waf/build/lib_4/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_15.h" -#include "class_9.h" -#include "class_67.h" -#include "class_38.h" -#include "class_31.h" -#include "class_35.h" -#include "class_50.h" -#include "class_23.h" -#include "class_27.h" -#include "class_96.h" -#include "class_36.h" -#include "class_81.h" -#include "class_12.h" -#include "class_7.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_4/class_54.h b/lib/waf/build/lib_4/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_55.cpp b/lib/waf/build/lib_4/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_55.h" -#include "class_21.h" -#include "class_73.h" -#include "class_95.h" -#include "class_24.h" -#include "class_84.h" -#include "class_15.h" -#include "class_33.h" -#include "class_38.h" -#include "class_34.h" -#include "class_31.h" -#include "class_69.h" -#include "class_74.h" -#include "class_97.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_4/class_55.h b/lib/waf/build/lib_4/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_56.cpp b/lib/waf/build/lib_4/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_23.h" -#include "class_13.h" -#include "class_69.h" -#include "class_66.h" -#include "class_70.h" -#include "class_4.h" -#include "class_92.h" -#include "class_72.h" -#include "class_55.h" -#include "class_52.h" -#include "class_82.h" -#include "class_45.h" -#include "class_86.h" -#include "class_41.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_4/class_56.h b/lib/waf/build/lib_4/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_57.cpp b/lib/waf/build/lib_4/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_52.h" -#include "class_42.h" -#include "class_75.h" -#include "class_71.h" -#include "class_14.h" -#include "class_30.h" -#include "class_72.h" -#include "class_62.h" -#include "class_27.h" -#include "class_44.h" -#include "class_96.h" -#include "class_83.h" -#include "class_60.h" -#include "class_87.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_4/class_57.h b/lib/waf/build/lib_4/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_58.cpp b/lib/waf/build/lib_4/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_58.h" -#include "class_10.h" -#include "class_62.h" -#include "class_81.h" -#include "class_96.h" -#include "class_63.h" -#include "class_19.h" -#include "class_20.h" -#include "class_24.h" -#include "class_67.h" -#include "class_55.h" -#include "class_45.h" -#include "class_37.h" -#include "class_76.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_4/class_58.h b/lib/waf/build/lib_4/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_59.cpp b/lib/waf/build/lib_4/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_76.h" -#include "class_71.h" -#include "class_20.h" -#include "class_47.h" -#include "class_30.h" -#include "class_34.h" -#include "class_62.h" -#include "class_15.h" -#include "class_27.h" -#include "class_55.h" -#include "class_18.h" -#include "class_93.h" -#include "class_92.h" -#include "class_97.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_4/class_59.h b/lib/waf/build/lib_4/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_6.cpp b/lib/waf/build/lib_4/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_2.h" -#include "class_8.h" -#include "class_26.h" -#include "class_88.h" -#include "class_28.h" -#include "class_59.h" -#include "class_67.h" -#include "class_96.h" -#include "class_63.h" -#include "class_40.h" -#include "class_43.h" -#include "class_5.h" -#include "class_44.h" -#include "class_18.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_4/class_6.h b/lib/waf/build/lib_4/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_60.cpp b/lib/waf/build/lib_4/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_63.h" -#include "class_28.h" -#include "class_88.h" -#include "class_29.h" -#include "class_84.h" -#include "class_61.h" -#include "class_38.h" -#include "class_18.h" -#include "class_47.h" -#include "class_57.h" -#include "class_8.h" -#include "class_16.h" -#include "class_53.h" -#include "class_14.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_4/class_60.h b/lib/waf/build/lib_4/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_61.cpp b/lib/waf/build/lib_4/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_34.h" -#include "class_15.h" -#include "class_86.h" -#include "class_58.h" -#include "class_14.h" -#include "class_82.h" -#include "class_77.h" -#include "class_63.h" -#include "class_67.h" -#include "class_41.h" -#include "class_70.h" -#include "class_85.h" -#include "class_33.h" -#include "class_10.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_4/class_61.h b/lib/waf/build/lib_4/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_62.cpp b/lib/waf/build/lib_4/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_99.h" -#include "class_60.h" -#include "class_17.h" -#include "class_29.h" -#include "class_18.h" -#include "class_34.h" -#include "class_50.h" -#include "class_62.h" -#include "class_33.h" -#include "class_8.h" -#include "class_2.h" -#include "class_86.h" -#include "class_87.h" -#include "class_94.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_4/class_62.h b/lib/waf/build/lib_4/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_63.cpp b/lib/waf/build/lib_4/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_16.h" -#include "class_56.h" -#include "class_4.h" -#include "class_82.h" -#include "class_41.h" -#include "class_21.h" -#include "class_99.h" -#include "class_26.h" -#include "class_20.h" -#include "class_46.h" -#include "class_75.h" -#include "class_31.h" -#include "class_22.h" -#include "class_47.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_4/class_63.h b/lib/waf/build/lib_4/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_64.cpp b/lib/waf/build/lib_4/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_11.h" -#include "class_78.h" -#include "class_76.h" -#include "class_99.h" -#include "class_42.h" -#include "class_39.h" -#include "class_50.h" -#include "class_66.h" -#include "class_90.h" -#include "class_88.h" -#include "class_23.h" -#include "class_32.h" -#include "class_70.h" -#include "class_37.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_4/class_64.h b/lib/waf/build/lib_4/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_65.cpp b/lib/waf/build/lib_4/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_76.h" -#include "class_36.h" -#include "class_98.h" -#include "class_96.h" -#include "class_27.h" -#include "class_66.h" -#include "class_18.h" -#include "class_67.h" -#include "class_57.h" -#include "class_56.h" -#include "class_11.h" -#include "class_84.h" -#include "class_73.h" -#include "class_53.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_4/class_65.h b/lib/waf/build/lib_4/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_66.cpp b/lib/waf/build/lib_4/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_12.h" -#include "class_47.h" -#include "class_40.h" -#include "class_68.h" -#include "class_4.h" -#include "class_73.h" -#include "class_98.h" -#include "class_17.h" -#include "class_41.h" -#include "class_51.h" -#include "class_56.h" -#include "class_16.h" -#include "class_27.h" -#include "class_14.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_4/class_66.h b/lib/waf/build/lib_4/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_67.cpp b/lib/waf/build/lib_4/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_88.h" -#include "class_51.h" -#include "class_69.h" -#include "class_81.h" -#include "class_28.h" -#include "class_23.h" -#include "class_9.h" -#include "class_41.h" -#include "class_80.h" -#include "class_58.h" -#include "class_45.h" -#include "class_82.h" -#include "class_14.h" -#include "class_5.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_4/class_67.h b/lib/waf/build/lib_4/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_68.cpp b/lib/waf/build/lib_4/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_17.h" -#include "class_45.h" -#include "class_10.h" -#include "class_95.h" -#include "class_12.h" -#include "class_55.h" -#include "class_49.h" -#include "class_92.h" -#include "class_81.h" -#include "class_34.h" -#include "class_90.h" -#include "class_7.h" -#include "class_22.h" -#include "class_76.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_4/class_68.h b/lib/waf/build/lib_4/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_69.cpp b/lib/waf/build/lib_4/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_19.h" -#include "class_97.h" -#include "class_16.h" -#include "class_1.h" -#include "class_87.h" -#include "class_38.h" -#include "class_15.h" -#include "class_21.h" -#include "class_53.h" -#include "class_39.h" -#include "class_18.h" -#include "class_10.h" -#include "class_99.h" -#include "class_70.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_4/class_69.h b/lib/waf/build/lib_4/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_7.cpp b/lib/waf/build/lib_4/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_61.h" -#include "class_76.h" -#include "class_33.h" -#include "class_87.h" -#include "class_86.h" -#include "class_78.h" -#include "class_70.h" -#include "class_1.h" -#include "class_83.h" -#include "class_22.h" -#include "class_14.h" -#include "class_17.h" -#include "class_48.h" -#include "class_34.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_4/class_7.h b/lib/waf/build/lib_4/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_70.cpp b/lib/waf/build/lib_4/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_28.h" -#include "class_37.h" -#include "class_77.h" -#include "class_64.h" -#include "class_47.h" -#include "class_17.h" -#include "class_40.h" -#include "class_69.h" -#include "class_54.h" -#include "class_60.h" -#include "class_82.h" -#include "class_10.h" -#include "class_91.h" -#include "class_55.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_4/class_70.h b/lib/waf/build/lib_4/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_71.cpp b/lib/waf/build/lib_4/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_56.h" -#include "class_3.h" -#include "class_85.h" -#include "class_99.h" -#include "class_44.h" -#include "class_70.h" -#include "class_59.h" -#include "class_62.h" -#include "class_79.h" -#include "class_42.h" -#include "class_26.h" -#include "class_29.h" -#include "class_16.h" -#include "class_76.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_4/class_71.h b/lib/waf/build/lib_4/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_72.cpp b/lib/waf/build/lib_4/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_48.h" -#include "class_13.h" -#include "class_53.h" -#include "class_56.h" -#include "class_49.h" -#include "class_33.h" -#include "class_63.h" -#include "class_21.h" -#include "class_45.h" -#include "class_14.h" -#include "class_97.h" -#include "class_91.h" -#include "class_1.h" -#include "class_20.h" -#include "class_76.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_4/class_72.h b/lib/waf/build/lib_4/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_73.cpp b/lib/waf/build/lib_4/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_8.h" -#include "class_77.h" -#include "class_85.h" -#include "class_34.h" -#include "class_80.h" -#include "class_96.h" -#include "class_3.h" -#include "class_14.h" -#include "class_75.h" -#include "class_38.h" -#include "class_42.h" -#include "class_92.h" -#include "class_51.h" -#include "class_10.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_4/class_73.h b/lib/waf/build/lib_4/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_74.cpp b/lib/waf/build/lib_4/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_69.h" -#include "class_41.h" -#include "class_26.h" -#include "class_60.h" -#include "class_29.h" -#include "class_12.h" -#include "class_16.h" -#include "class_38.h" -#include "class_42.h" -#include "class_58.h" -#include "class_75.h" -#include "class_40.h" -#include "class_54.h" -#include "class_79.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_4/class_74.h b/lib/waf/build/lib_4/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_75.cpp b/lib/waf/build/lib_4/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_54.h" -#include "class_58.h" -#include "class_28.h" -#include "class_44.h" -#include "class_85.h" -#include "class_71.h" -#include "class_1.h" -#include "class_49.h" -#include "class_82.h" -#include "class_93.h" -#include "class_34.h" -#include "class_15.h" -#include "class_10.h" -#include "class_17.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_4/class_75.h b/lib/waf/build/lib_4/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_76.cpp b/lib/waf/build/lib_4/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_59.h" -#include "class_23.h" -#include "class_77.h" -#include "class_76.h" -#include "class_93.h" -#include "class_0.h" -#include "class_42.h" -#include "class_56.h" -#include "class_33.h" -#include "class_99.h" -#include "class_5.h" -#include "class_2.h" -#include "class_63.h" -#include "class_12.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_4/class_76.h b/lib/waf/build/lib_4/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_77.cpp b/lib/waf/build/lib_4/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_54.h" -#include "class_36.h" -#include "class_80.h" -#include "class_56.h" -#include "class_4.h" -#include "class_41.h" -#include "class_91.h" -#include "class_72.h" -#include "class_12.h" -#include "class_90.h" -#include "class_62.h" -#include "class_73.h" -#include "class_78.h" -#include "class_7.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_4/class_77.h b/lib/waf/build/lib_4/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_78.cpp b/lib/waf/build/lib_4/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_53.h" -#include "class_3.h" -#include "class_27.h" -#include "class_2.h" -#include "class_74.h" -#include "class_35.h" -#include "class_90.h" -#include "class_12.h" -#include "class_5.h" -#include "class_17.h" -#include "class_56.h" -#include "class_57.h" -#include "class_70.h" -#include "class_45.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_4/class_78.h b/lib/waf/build/lib_4/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_79.cpp b/lib/waf/build/lib_4/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_67.h" -#include "class_92.h" -#include "class_79.h" -#include "class_62.h" -#include "class_2.h" -#include "class_94.h" -#include "class_1.h" -#include "class_70.h" -#include "class_12.h" -#include "class_29.h" -#include "class_36.h" -#include "class_86.h" -#include "class_5.h" -#include "class_33.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_4/class_79.h b/lib/waf/build/lib_4/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_8.cpp b/lib/waf/build/lib_4/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_13.h" -#include "class_41.h" -#include "class_81.h" -#include "class_39.h" -#include "class_65.h" -#include "class_15.h" -#include "class_18.h" -#include "class_60.h" -#include "class_19.h" -#include "class_62.h" -#include "class_84.h" -#include "class_53.h" -#include "class_1.h" -#include "class_75.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_4/class_8.h b/lib/waf/build/lib_4/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_80.cpp b/lib/waf/build/lib_4/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_73.h" -#include "class_93.h" -#include "class_20.h" -#include "class_12.h" -#include "class_60.h" -#include "class_75.h" -#include "class_9.h" -#include "class_11.h" -#include "class_35.h" -#include "class_13.h" -#include "class_27.h" -#include "class_25.h" -#include "class_62.h" -#include "class_85.h" -#include "class_38.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_4/class_80.h b/lib/waf/build/lib_4/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_81.cpp b/lib/waf/build/lib_4/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_13.h" -#include "class_50.h" -#include "class_81.h" -#include "class_9.h" -#include "class_89.h" -#include "class_2.h" -#include "class_31.h" -#include "class_24.h" -#include "class_94.h" -#include "class_85.h" -#include "class_68.h" -#include "class_74.h" -#include "class_37.h" -#include "class_52.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_4/class_81.h b/lib/waf/build/lib_4/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_82.cpp b/lib/waf/build/lib_4/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_83.h" -#include "class_5.h" -#include "class_69.h" -#include "class_4.h" -#include "class_55.h" -#include "class_91.h" -#include "class_85.h" -#include "class_25.h" -#include "class_84.h" -#include "class_33.h" -#include "class_22.h" -#include "class_0.h" -#include "class_56.h" -#include "class_41.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_4/class_82.h b/lib/waf/build/lib_4/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_83.cpp b/lib/waf/build/lib_4/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_55.h" -#include "class_58.h" -#include "class_65.h" -#include "class_21.h" -#include "class_73.h" -#include "class_66.h" -#include "class_75.h" -#include "class_64.h" -#include "class_62.h" -#include "class_72.h" -#include "class_15.h" -#include "class_60.h" -#include "class_80.h" -#include "class_90.h" -#include "class_82.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_4/class_83.h b/lib/waf/build/lib_4/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_84.cpp b/lib/waf/build/lib_4/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_61.h" -#include "class_78.h" -#include "class_25.h" -#include "class_58.h" -#include "class_52.h" -#include "class_64.h" -#include "class_40.h" -#include "class_87.h" -#include "class_14.h" -#include "class_33.h" -#include "class_24.h" -#include "class_20.h" -#include "class_95.h" -#include "class_43.h" -#include "class_93.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_4/class_84.h b/lib/waf/build/lib_4/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_85.cpp b/lib/waf/build/lib_4/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_51.h" -#include "class_63.h" -#include "class_42.h" -#include "class_30.h" -#include "class_94.h" -#include "class_80.h" -#include "class_4.h" -#include "class_32.h" -#include "class_33.h" -#include "class_40.h" -#include "class_8.h" -#include "class_17.h" -#include "class_16.h" -#include "class_55.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_4/class_85.h b/lib/waf/build/lib_4/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_86.cpp b/lib/waf/build/lib_4/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_9.h" -#include "class_48.h" -#include "class_66.h" -#include "class_28.h" -#include "class_74.h" -#include "class_95.h" -#include "class_38.h" -#include "class_2.h" -#include "class_60.h" -#include "class_23.h" -#include "class_27.h" -#include "class_52.h" -#include "class_25.h" -#include "class_87.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_4/class_86.h b/lib/waf/build/lib_4/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_87.cpp b/lib/waf/build/lib_4/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_24.h" -#include "class_97.h" -#include "class_28.h" -#include "class_19.h" -#include "class_47.h" -#include "class_4.h" -#include "class_89.h" -#include "class_18.h" -#include "class_72.h" -#include "class_10.h" -#include "class_29.h" -#include "class_99.h" -#include "class_55.h" -#include "class_76.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_4/class_87.h b/lib/waf/build/lib_4/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_88.cpp b/lib/waf/build/lib_4/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_76.h" -#include "class_51.h" -#include "class_59.h" -#include "class_62.h" -#include "class_23.h" -#include "class_5.h" -#include "class_67.h" -#include "class_33.h" -#include "class_81.h" -#include "class_93.h" -#include "class_68.h" -#include "class_85.h" -#include "class_84.h" -#include "class_77.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_4/class_88.h b/lib/waf/build/lib_4/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_89.cpp b/lib/waf/build/lib_4/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_89.h" -#include "class_99.h" -#include "class_27.h" -#include "class_2.h" -#include "class_85.h" -#include "class_4.h" -#include "class_32.h" -#include "class_62.h" -#include "class_49.h" -#include "class_66.h" -#include "class_40.h" -#include "class_25.h" -#include "class_77.h" -#include "class_48.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_4/class_89.h b/lib/waf/build/lib_4/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_9.cpp b/lib/waf/build/lib_4/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_1.h" -#include "class_11.h" -#include "class_3.h" -#include "class_5.h" -#include "class_95.h" -#include "class_22.h" -#include "class_8.h" -#include "class_26.h" -#include "class_61.h" -#include "class_91.h" -#include "class_88.h" -#include "class_89.h" -#include "class_76.h" -#include "class_79.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_4/class_9.h b/lib/waf/build/lib_4/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_90.cpp b/lib/waf/build/lib_4/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_65.h" -#include "class_34.h" -#include "class_93.h" -#include "class_11.h" -#include "class_2.h" -#include "class_15.h" -#include "class_53.h" -#include "class_94.h" -#include "class_99.h" -#include "class_72.h" -#include "class_38.h" -#include "class_62.h" -#include "class_44.h" -#include "class_50.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_4/class_90.h b/lib/waf/build/lib_4/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_91.cpp b/lib/waf/build/lib_4/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_76.h" -#include "class_84.h" -#include "class_33.h" -#include "class_60.h" -#include "class_93.h" -#include "class_87.h" -#include "class_22.h" -#include "class_57.h" -#include "class_1.h" -#include "class_96.h" -#include "class_78.h" -#include "class_55.h" -#include "class_54.h" -#include "class_65.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_4/class_91.h b/lib/waf/build/lib_4/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_92.cpp b/lib/waf/build/lib_4/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_78.h" -#include "class_70.h" -#include "class_22.h" -#include "class_88.h" -#include "class_98.h" -#include "class_50.h" -#include "class_24.h" -#include "class_83.h" -#include "class_72.h" -#include "class_12.h" -#include "class_54.h" -#include "class_59.h" -#include "class_51.h" -#include "class_53.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_4/class_92.h b/lib/waf/build/lib_4/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_93.cpp b/lib/waf/build/lib_4/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_91.h" -#include "class_73.h" -#include "class_93.h" -#include "class_14.h" -#include "class_59.h" -#include "class_30.h" -#include "class_17.h" -#include "class_19.h" -#include "class_41.h" -#include "class_32.h" -#include "class_77.h" -#include "class_15.h" -#include "class_61.h" -#include "class_1.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_4/class_93.h b/lib/waf/build/lib_4/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_94.cpp b/lib/waf/build/lib_4/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_28.h" -#include "class_67.h" -#include "class_42.h" -#include "class_1.h" -#include "class_79.h" -#include "class_8.h" -#include "class_31.h" -#include "class_15.h" -#include "class_76.h" -#include "class_82.h" -#include "class_80.h" -#include "class_96.h" -#include "class_12.h" -#include "class_91.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_4/class_94.h b/lib/waf/build/lib_4/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_95.cpp b/lib/waf/build/lib_4/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_31.h" -#include "class_61.h" -#include "class_56.h" -#include "class_87.h" -#include "class_57.h" -#include "class_92.h" -#include "class_18.h" -#include "class_1.h" -#include "class_33.h" -#include "class_66.h" -#include "class_46.h" -#include "class_6.h" -#include "class_45.h" -#include "class_3.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_4/class_95.h b/lib/waf/build/lib_4/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_96.cpp b/lib/waf/build/lib_4/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_39.h" -#include "class_14.h" -#include "class_68.h" -#include "class_29.h" -#include "class_24.h" -#include "class_11.h" -#include "class_81.h" -#include "class_20.h" -#include "class_26.h" -#include "class_79.h" -#include "class_69.h" -#include "class_78.h" -#include "class_87.h" -#include "class_53.h" -#include "class_22.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_4/class_96.h b/lib/waf/build/lib_4/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_97.cpp b/lib/waf/build/lib_4/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_68.h" -#include "class_90.h" -#include "class_82.h" -#include "class_33.h" -#include "class_76.h" -#include "class_79.h" -#include "class_1.h" -#include "class_15.h" -#include "class_37.h" -#include "class_69.h" -#include "class_36.h" -#include "class_28.h" -#include "class_54.h" -#include "class_10.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_4/class_97.h b/lib/waf/build/lib_4/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_98.cpp b/lib/waf/build/lib_4/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_77.h" -#include "class_13.h" -#include "class_71.h" -#include "class_43.h" -#include "class_51.h" -#include "class_27.h" -#include "class_4.h" -#include "class_92.h" -#include "class_87.h" -#include "class_47.h" -#include "class_5.h" -#include "class_56.h" -#include "class_40.h" -#include "class_53.h" -#include "class_42.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_4/class_98.h b/lib/waf/build/lib_4/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_4/class_99.cpp b/lib/waf/build/lib_4/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_4/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_66.h" -#include "class_81.h" -#include "class_88.h" -#include "class_91.h" -#include "class_79.h" -#include "class_33.h" -#include "class_27.h" -#include "class_89.h" -#include "class_9.h" -#include "class_39.h" -#include "class_50.h" -#include "class_47.h" -#include "class_57.h" -#include "class_92.h" -#include "class_7.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_4/class_99.h b/lib/waf/build/lib_4/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_4/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_5/Makefile b/lib/waf/build/lib_5/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_5/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_5.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_5/Makefile.am b/lib/waf/build/lib_5/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_5/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib5.la -lib5_la_SOURCES = lib_5/class_0.cpp lib_5/class_1.cpp lib_5/class_2.cpp lib_5/class_3.cpp lib_5/class_4.cpp lib_5/class_5.cpp lib_5/class_6.cpp lib_5/class_7.cpp lib_5/class_8.cpp lib_5/class_9.cpp lib_5/class_10.cpp lib_5/class_11.cpp lib_5/class_12.cpp lib_5/class_13.cpp lib_5/class_14.cpp lib_5/class_15.cpp lib_5/class_16.cpp lib_5/class_17.cpp lib_5/class_18.cpp lib_5/class_19.cpp lib_5/class_20.cpp lib_5/class_21.cpp lib_5/class_22.cpp lib_5/class_23.cpp lib_5/class_24.cpp lib_5/class_25.cpp lib_5/class_26.cpp lib_5/class_27.cpp lib_5/class_28.cpp lib_5/class_29.cpp lib_5/class_30.cpp lib_5/class_31.cpp lib_5/class_32.cpp lib_5/class_33.cpp lib_5/class_34.cpp lib_5/class_35.cpp lib_5/class_36.cpp lib_5/class_37.cpp lib_5/class_38.cpp lib_5/class_39.cpp lib_5/class_40.cpp lib_5/class_41.cpp lib_5/class_42.cpp lib_5/class_43.cpp lib_5/class_44.cpp lib_5/class_45.cpp lib_5/class_46.cpp lib_5/class_47.cpp lib_5/class_48.cpp lib_5/class_49.cpp lib_5/class_50.cpp lib_5/class_51.cpp lib_5/class_52.cpp lib_5/class_53.cpp lib_5/class_54.cpp lib_5/class_55.cpp lib_5/class_56.cpp lib_5/class_57.cpp lib_5/class_58.cpp lib_5/class_59.cpp lib_5/class_60.cpp lib_5/class_61.cpp lib_5/class_62.cpp lib_5/class_63.cpp lib_5/class_64.cpp lib_5/class_65.cpp lib_5/class_66.cpp lib_5/class_67.cpp lib_5/class_68.cpp lib_5/class_69.cpp lib_5/class_70.cpp lib_5/class_71.cpp lib_5/class_72.cpp lib_5/class_73.cpp lib_5/class_74.cpp lib_5/class_75.cpp lib_5/class_76.cpp lib_5/class_77.cpp lib_5/class_78.cpp lib_5/class_79.cpp lib_5/class_80.cpp lib_5/class_81.cpp lib_5/class_82.cpp lib_5/class_83.cpp lib_5/class_84.cpp lib_5/class_85.cpp lib_5/class_86.cpp lib_5/class_87.cpp lib_5/class_88.cpp lib_5/class_89.cpp lib_5/class_90.cpp lib_5/class_91.cpp lib_5/class_92.cpp lib_5/class_93.cpp lib_5/class_94.cpp lib_5/class_95.cpp lib_5/class_96.cpp lib_5/class_97.cpp lib_5/class_98.cpp lib_5/class_99.cpp diff --git a/lib/waf/build/lib_5/SConscript b/lib/waf/build/lib_5/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_5/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_5", list) - diff --git a/lib/waf/build/lib_5/class_0.cpp b/lib/waf/build/lib_5/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_4.h" -#include "class_32.h" -#include "class_51.h" -#include "class_17.h" -#include "class_5.h" -#include "class_98.h" -#include "class_22.h" -#include "class_54.h" -#include "class_80.h" -#include "class_99.h" -#include "class_48.h" -#include "class_9.h" -#include "class_19.h" -#include "class_8.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_5/class_0.h b/lib/waf/build/lib_5/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_1.cpp b/lib/waf/build/lib_5/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_68.h" -#include "class_18.h" -#include "class_73.h" -#include "class_4.h" -#include "class_3.h" -#include "class_27.h" -#include "class_72.h" -#include "class_99.h" -#include "class_45.h" -#include "class_62.h" -#include "class_82.h" -#include "class_21.h" -#include "class_83.h" -#include "class_60.h" -#include "class_7.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_5/class_1.h b/lib/waf/build/lib_5/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_10.cpp b/lib/waf/build/lib_5/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_78.h" -#include "class_72.h" -#include "class_74.h" -#include "class_27.h" -#include "class_84.h" -#include "class_15.h" -#include "class_29.h" -#include "class_43.h" -#include "class_2.h" -#include "class_93.h" -#include "class_40.h" -#include "class_59.h" -#include "class_62.h" -#include "class_22.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_5/class_10.h b/lib/waf/build/lib_5/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_11.cpp b/lib/waf/build/lib_5/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_13.h" -#include "class_7.h" -#include "class_31.h" -#include "class_30.h" -#include "class_67.h" -#include "class_52.h" -#include "class_48.h" -#include "class_36.h" -#include "class_58.h" -#include "class_87.h" -#include "class_81.h" -#include "class_39.h" -#include "class_97.h" -#include "class_95.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_5/class_11.h b/lib/waf/build/lib_5/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_12.cpp b/lib/waf/build/lib_5/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_90.h" -#include "class_50.h" -#include "class_22.h" -#include "class_45.h" -#include "class_36.h" -#include "class_78.h" -#include "class_2.h" -#include "class_11.h" -#include "class_93.h" -#include "class_56.h" -#include "class_99.h" -#include "class_62.h" -#include "class_9.h" -#include "class_91.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_5/class_12.h b/lib/waf/build/lib_5/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_13.cpp b/lib/waf/build/lib_5/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_78.h" -#include "class_82.h" -#include "class_86.h" -#include "class_97.h" -#include "class_64.h" -#include "class_31.h" -#include "class_4.h" -#include "class_25.h" -#include "class_79.h" -#include "class_77.h" -#include "class_14.h" -#include "class_26.h" -#include "class_53.h" -#include "class_18.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_5/class_13.h b/lib/waf/build/lib_5/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_14.cpp b/lib/waf/build/lib_5/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_79.h" -#include "class_53.h" -#include "class_36.h" -#include "class_98.h" -#include "class_72.h" -#include "class_19.h" -#include "class_82.h" -#include "class_99.h" -#include "class_81.h" -#include "class_46.h" -#include "class_37.h" -#include "class_90.h" -#include "class_91.h" -#include "class_88.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_5/class_14.h b/lib/waf/build/lib_5/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_15.cpp b/lib/waf/build/lib_5/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_39.h" -#include "class_43.h" -#include "class_38.h" -#include "class_3.h" -#include "class_75.h" -#include "class_80.h" -#include "class_20.h" -#include "class_59.h" -#include "class_30.h" -#include "class_93.h" -#include "class_33.h" -#include "class_83.h" -#include "class_97.h" -#include "class_14.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_5/class_15.h b/lib/waf/build/lib_5/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_16.cpp b/lib/waf/build/lib_5/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_36.h" -#include "class_25.h" -#include "class_90.h" -#include "class_78.h" -#include "class_82.h" -#include "class_10.h" -#include "class_93.h" -#include "class_32.h" -#include "class_66.h" -#include "class_44.h" -#include "class_14.h" -#include "class_99.h" -#include "class_59.h" -#include "class_30.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_5/class_16.h b/lib/waf/build/lib_5/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_17.cpp b/lib/waf/build/lib_5/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_93.h" -#include "class_34.h" -#include "class_4.h" -#include "class_90.h" -#include "class_58.h" -#include "class_3.h" -#include "class_6.h" -#include "class_88.h" -#include "class_19.h" -#include "class_79.h" -#include "class_12.h" -#include "class_8.h" -#include "class_57.h" -#include "class_47.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_5/class_17.h b/lib/waf/build/lib_5/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_18.cpp b/lib/waf/build/lib_5/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_44.h" -#include "class_5.h" -#include "class_85.h" -#include "class_95.h" -#include "class_36.h" -#include "class_47.h" -#include "class_22.h" -#include "class_61.h" -#include "class_21.h" -#include "class_93.h" -#include "class_29.h" -#include "class_3.h" -#include "class_78.h" -#include "class_33.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_5/class_18.h b/lib/waf/build/lib_5/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_19.cpp b/lib/waf/build/lib_5/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_70.h" -#include "class_84.h" -#include "class_8.h" -#include "class_57.h" -#include "class_82.h" -#include "class_74.h" -#include "class_61.h" -#include "class_13.h" -#include "class_78.h" -#include "class_38.h" -#include "class_42.h" -#include "class_96.h" -#include "class_92.h" -#include "class_6.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_5/class_19.h b/lib/waf/build/lib_5/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_2.cpp b/lib/waf/build/lib_5/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_99.h" -#include "class_69.h" -#include "class_54.h" -#include "class_11.h" -#include "class_79.h" -#include "class_20.h" -#include "class_36.h" -#include "class_18.h" -#include "class_39.h" -#include "class_25.h" -#include "class_61.h" -#include "class_14.h" -#include "class_86.h" -#include "class_94.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_5/class_2.h b/lib/waf/build/lib_5/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_20.cpp b/lib/waf/build/lib_5/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_81.h" -#include "class_67.h" -#include "class_3.h" -#include "class_87.h" -#include "class_71.h" -#include "class_30.h" -#include "class_93.h" -#include "class_9.h" -#include "class_2.h" -#include "class_79.h" -#include "class_83.h" -#include "class_25.h" -#include "class_88.h" -#include "class_52.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_5/class_20.h b/lib/waf/build/lib_5/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_21.cpp b/lib/waf/build/lib_5/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_71.h" -#include "class_65.h" -#include "class_64.h" -#include "class_13.h" -#include "class_91.h" -#include "class_44.h" -#include "class_33.h" -#include "class_34.h" -#include "class_31.h" -#include "class_89.h" -#include "class_7.h" -#include "class_56.h" -#include "class_25.h" -#include "class_10.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_5/class_21.h b/lib/waf/build/lib_5/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_22.cpp b/lib/waf/build/lib_5/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_45.h" -#include "class_46.h" -#include "class_78.h" -#include "class_84.h" -#include "class_79.h" -#include "class_76.h" -#include "class_33.h" -#include "class_60.h" -#include "class_6.h" -#include "class_18.h" -#include "class_14.h" -#include "class_97.h" -#include "class_68.h" -#include "class_82.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_5/class_22.h b/lib/waf/build/lib_5/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_23.cpp b/lib/waf/build/lib_5/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_26.h" -#include "class_3.h" -#include "class_25.h" -#include "class_74.h" -#include "class_14.h" -#include "class_93.h" -#include "class_2.h" -#include "class_73.h" -#include "class_98.h" -#include "class_10.h" -#include "class_44.h" -#include "class_4.h" -#include "class_75.h" -#include "class_38.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_5/class_23.h b/lib/waf/build/lib_5/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_24.cpp b/lib/waf/build/lib_5/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_48.h" -#include "class_63.h" -#include "class_11.h" -#include "class_40.h" -#include "class_32.h" -#include "class_71.h" -#include "class_38.h" -#include "class_80.h" -#include "class_4.h" -#include "class_47.h" -#include "class_51.h" -#include "class_6.h" -#include "class_5.h" -#include "class_26.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_5/class_24.h b/lib/waf/build/lib_5/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_25.cpp b/lib/waf/build/lib_5/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_63.h" -#include "class_3.h" -#include "class_39.h" -#include "class_54.h" -#include "class_15.h" -#include "class_21.h" -#include "class_89.h" -#include "class_8.h" -#include "class_70.h" -#include "class_23.h" -#include "class_36.h" -#include "class_29.h" -#include "class_84.h" -#include "class_50.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_5/class_25.h b/lib/waf/build/lib_5/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_26.cpp b/lib/waf/build/lib_5/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_26.h" -#include "class_15.h" -#include "class_17.h" -#include "class_23.h" -#include "class_61.h" -#include "class_99.h" -#include "class_40.h" -#include "class_12.h" -#include "class_37.h" -#include "class_64.h" -#include "class_59.h" -#include "class_35.h" -#include "class_71.h" -#include "class_97.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_5/class_26.h b/lib/waf/build/lib_5/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_27.cpp b/lib/waf/build/lib_5/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_8.h" -#include "class_45.h" -#include "class_95.h" -#include "class_64.h" -#include "class_10.h" -#include "class_65.h" -#include "class_56.h" -#include "class_42.h" -#include "class_72.h" -#include "class_19.h" -#include "class_71.h" -#include "class_55.h" -#include "class_20.h" -#include "class_61.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_5/class_27.h b/lib/waf/build/lib_5/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_28.cpp b/lib/waf/build/lib_5/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_83.h" -#include "class_17.h" -#include "class_67.h" -#include "class_36.h" -#include "class_3.h" -#include "class_42.h" -#include "class_79.h" -#include "class_23.h" -#include "class_34.h" -#include "class_75.h" -#include "class_87.h" -#include "class_57.h" -#include "class_61.h" -#include "class_16.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_5/class_28.h b/lib/waf/build/lib_5/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_29.cpp b/lib/waf/build/lib_5/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_25.h" -#include "class_2.h" -#include "class_46.h" -#include "class_97.h" -#include "class_44.h" -#include "class_9.h" -#include "class_6.h" -#include "class_86.h" -#include "class_7.h" -#include "class_99.h" -#include "class_10.h" -#include "class_22.h" -#include "class_45.h" -#include "class_76.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_5/class_29.h b/lib/waf/build/lib_5/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_3.cpp b/lib/waf/build/lib_5/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_49.h" -#include "class_84.h" -#include "class_39.h" -#include "class_6.h" -#include "class_8.h" -#include "class_70.h" -#include "class_72.h" -#include "class_23.h" -#include "class_83.h" -#include "class_79.h" -#include "class_18.h" -#include "class_46.h" -#include "class_22.h" -#include "class_85.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_5/class_3.h b/lib/waf/build/lib_5/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_30.cpp b/lib/waf/build/lib_5/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_93.h" -#include "class_19.h" -#include "class_15.h" -#include "class_63.h" -#include "class_31.h" -#include "class_91.h" -#include "class_85.h" -#include "class_46.h" -#include "class_48.h" -#include "class_29.h" -#include "class_52.h" -#include "class_35.h" -#include "class_98.h" -#include "class_53.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_5/class_30.h b/lib/waf/build/lib_5/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_31.cpp b/lib/waf/build/lib_5/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_79.h" -#include "class_19.h" -#include "class_57.h" -#include "class_22.h" -#include "class_91.h" -#include "class_41.h" -#include "class_56.h" -#include "class_4.h" -#include "class_68.h" -#include "class_52.h" -#include "class_42.h" -#include "class_37.h" -#include "class_58.h" -#include "class_12.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_5/class_31.h b/lib/waf/build/lib_5/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_32.cpp b/lib/waf/build/lib_5/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_31.h" -#include "class_32.h" -#include "class_82.h" -#include "class_47.h" -#include "class_39.h" -#include "class_28.h" -#include "class_24.h" -#include "class_66.h" -#include "class_70.h" -#include "class_60.h" -#include "class_15.h" -#include "class_61.h" -#include "class_89.h" -#include "class_18.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_5/class_32.h b/lib/waf/build/lib_5/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_33.cpp b/lib/waf/build/lib_5/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_73.h" -#include "class_86.h" -#include "class_89.h" -#include "class_91.h" -#include "class_55.h" -#include "class_50.h" -#include "class_29.h" -#include "class_72.h" -#include "class_43.h" -#include "class_59.h" -#include "class_61.h" -#include "class_45.h" -#include "class_92.h" -#include "class_3.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_5/class_33.h b/lib/waf/build/lib_5/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_34.cpp b/lib/waf/build/lib_5/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_46.h" -#include "class_78.h" -#include "class_24.h" -#include "class_53.h" -#include "class_43.h" -#include "class_22.h" -#include "class_45.h" -#include "class_23.h" -#include "class_33.h" -#include "class_27.h" -#include "class_52.h" -#include "class_67.h" -#include "class_74.h" -#include "class_76.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_5/class_34.h b/lib/waf/build/lib_5/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_35.cpp b/lib/waf/build/lib_5/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_47.h" -#include "class_43.h" -#include "class_86.h" -#include "class_19.h" -#include "class_55.h" -#include "class_56.h" -#include "class_64.h" -#include "class_16.h" -#include "class_21.h" -#include "class_27.h" -#include "class_58.h" -#include "class_75.h" -#include "class_97.h" -#include "class_67.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_5/class_35.h b/lib/waf/build/lib_5/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_36.cpp b/lib/waf/build/lib_5/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_82.h" -#include "class_34.h" -#include "class_55.h" -#include "class_41.h" -#include "class_62.h" -#include "class_40.h" -#include "class_77.h" -#include "class_70.h" -#include "class_92.h" -#include "class_72.h" -#include "class_52.h" -#include "class_31.h" -#include "class_6.h" -#include "class_49.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_5/class_36.h b/lib/waf/build/lib_5/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_37.cpp b/lib/waf/build/lib_5/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_50.h" -#include "class_4.h" -#include "class_36.h" -#include "class_18.h" -#include "class_66.h" -#include "class_26.h" -#include "class_0.h" -#include "class_79.h" -#include "class_3.h" -#include "class_97.h" -#include "class_87.h" -#include "class_52.h" -#include "class_19.h" -#include "class_24.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_5/class_37.h b/lib/waf/build/lib_5/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_38.cpp b/lib/waf/build/lib_5/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_87.h" -#include "class_91.h" -#include "class_66.h" -#include "class_62.h" -#include "class_71.h" -#include "class_0.h" -#include "class_30.h" -#include "class_63.h" -#include "class_78.h" -#include "class_18.h" -#include "class_12.h" -#include "class_60.h" -#include "class_52.h" -#include "class_53.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_5/class_38.h b/lib/waf/build/lib_5/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_39.cpp b/lib/waf/build/lib_5/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_93.h" -#include "class_77.h" -#include "class_88.h" -#include "class_35.h" -#include "class_40.h" -#include "class_21.h" -#include "class_2.h" -#include "class_46.h" -#include "class_63.h" -#include "class_95.h" -#include "class_97.h" -#include "class_24.h" -#include "class_17.h" -#include "class_15.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_5/class_39.h b/lib/waf/build/lib_5/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_4.cpp b/lib/waf/build/lib_5/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_33.h" -#include "class_85.h" -#include "class_42.h" -#include "class_35.h" -#include "class_43.h" -#include "class_34.h" -#include "class_86.h" -#include "class_50.h" -#include "class_54.h" -#include "class_61.h" -#include "class_8.h" -#include "class_12.h" -#include "class_7.h" -#include "class_27.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_5/class_4.h b/lib/waf/build/lib_5/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_40.cpp b/lib/waf/build/lib_5/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_51.h" -#include "class_14.h" -#include "class_55.h" -#include "class_20.h" -#include "class_68.h" -#include "class_61.h" -#include "class_41.h" -#include "class_87.h" -#include "class_31.h" -#include "class_99.h" -#include "class_58.h" -#include "class_90.h" -#include "class_54.h" -#include "class_59.h" -#include "class_76.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_5/class_40.h b/lib/waf/build/lib_5/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_41.cpp b/lib/waf/build/lib_5/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_75.h" -#include "class_78.h" -#include "class_7.h" -#include "class_48.h" -#include "class_30.h" -#include "class_86.h" -#include "class_64.h" -#include "class_46.h" -#include "class_41.h" -#include "class_35.h" -#include "class_34.h" -#include "class_62.h" -#include "class_52.h" -#include "class_50.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_5/class_41.h b/lib/waf/build/lib_5/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_42.cpp b/lib/waf/build/lib_5/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_85.h" -#include "class_44.h" -#include "class_80.h" -#include "class_56.h" -#include "class_35.h" -#include "class_15.h" -#include "class_7.h" -#include "class_50.h" -#include "class_76.h" -#include "class_86.h" -#include "class_48.h" -#include "class_64.h" -#include "class_23.h" -#include "class_6.h" -#include "class_91.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_5/class_42.h b/lib/waf/build/lib_5/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_43.cpp b/lib/waf/build/lib_5/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_69.h" -#include "class_6.h" -#include "class_73.h" -#include "class_9.h" -#include "class_39.h" -#include "class_51.h" -#include "class_4.h" -#include "class_7.h" -#include "class_85.h" -#include "class_96.h" -#include "class_15.h" -#include "class_81.h" -#include "class_60.h" -#include "class_93.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_5/class_43.h b/lib/waf/build/lib_5/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_44.cpp b/lib/waf/build/lib_5/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_4.h" -#include "class_74.h" -#include "class_40.h" -#include "class_86.h" -#include "class_68.h" -#include "class_9.h" -#include "class_37.h" -#include "class_57.h" -#include "class_82.h" -#include "class_10.h" -#include "class_52.h" -#include "class_53.h" -#include "class_8.h" -#include "class_23.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_5/class_44.h b/lib/waf/build/lib_5/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_45.cpp b/lib/waf/build/lib_5/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_32.h" -#include "class_30.h" -#include "class_86.h" -#include "class_1.h" -#include "class_22.h" -#include "class_51.h" -#include "class_98.h" -#include "class_6.h" -#include "class_10.h" -#include "class_27.h" -#include "class_46.h" -#include "class_2.h" -#include "class_25.h" -#include "class_59.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_5/class_45.h b/lib/waf/build/lib_5/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_46.cpp b/lib/waf/build/lib_5/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_15.h" -#include "class_90.h" -#include "class_81.h" -#include "class_37.h" -#include "class_19.h" -#include "class_49.h" -#include "class_83.h" -#include "class_20.h" -#include "class_16.h" -#include "class_79.h" -#include "class_60.h" -#include "class_72.h" -#include "class_31.h" -#include "class_96.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_5/class_46.h b/lib/waf/build/lib_5/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_47.cpp b/lib/waf/build/lib_5/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_58.h" -#include "class_92.h" -#include "class_95.h" -#include "class_71.h" -#include "class_16.h" -#include "class_74.h" -#include "class_12.h" -#include "class_33.h" -#include "class_7.h" -#include "class_81.h" -#include "class_51.h" -#include "class_3.h" -#include "class_17.h" -#include "class_20.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_5/class_47.h b/lib/waf/build/lib_5/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_48.cpp b/lib/waf/build/lib_5/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_12.h" -#include "class_31.h" -#include "class_70.h" -#include "class_11.h" -#include "class_89.h" -#include "class_6.h" -#include "class_77.h" -#include "class_68.h" -#include "class_51.h" -#include "class_76.h" -#include "class_54.h" -#include "class_69.h" -#include "class_14.h" -#include "class_29.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_5/class_48.h b/lib/waf/build/lib_5/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_49.cpp b/lib/waf/build/lib_5/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_54.h" -#include "class_81.h" -#include "class_23.h" -#include "class_53.h" -#include "class_60.h" -#include "class_11.h" -#include "class_41.h" -#include "class_10.h" -#include "class_35.h" -#include "class_65.h" -#include "class_99.h" -#include "class_69.h" -#include "class_90.h" -#include "class_71.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_5/class_49.h b/lib/waf/build/lib_5/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_5.cpp b/lib/waf/build/lib_5/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_19.h" -#include "class_24.h" -#include "class_32.h" -#include "class_63.h" -#include "class_65.h" -#include "class_97.h" -#include "class_90.h" -#include "class_56.h" -#include "class_80.h" -#include "class_53.h" -#include "class_64.h" -#include "class_54.h" -#include "class_47.h" -#include "class_13.h" -#include "class_82.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_5/class_5.h b/lib/waf/build/lib_5/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_50.cpp b/lib/waf/build/lib_5/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_61.h" -#include "class_42.h" -#include "class_96.h" -#include "class_94.h" -#include "class_29.h" -#include "class_22.h" -#include "class_36.h" -#include "class_35.h" -#include "class_46.h" -#include "class_24.h" -#include "class_17.h" -#include "class_45.h" -#include "class_15.h" -#include "class_68.h" -#include "class_76.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_5/class_50.h b/lib/waf/build/lib_5/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_51.cpp b/lib/waf/build/lib_5/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_98.h" -#include "class_96.h" -#include "class_47.h" -#include "class_5.h" -#include "class_40.h" -#include "class_1.h" -#include "class_9.h" -#include "class_28.h" -#include "class_31.h" -#include "class_85.h" -#include "class_93.h" -#include "class_71.h" -#include "class_23.h" -#include "class_38.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_5/class_51.h b/lib/waf/build/lib_5/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_52.cpp b/lib/waf/build/lib_5/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_70.h" -#include "class_45.h" -#include "class_23.h" -#include "class_73.h" -#include "class_42.h" -#include "class_39.h" -#include "class_27.h" -#include "class_84.h" -#include "class_80.h" -#include "class_37.h" -#include "class_59.h" -#include "class_62.h" -#include "class_43.h" -#include "class_40.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_5/class_52.h b/lib/waf/build/lib_5/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_53.cpp b/lib/waf/build/lib_5/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_96.h" -#include "class_47.h" -#include "class_70.h" -#include "class_75.h" -#include "class_65.h" -#include "class_20.h" -#include "class_3.h" -#include "class_83.h" -#include "class_30.h" -#include "class_12.h" -#include "class_66.h" -#include "class_52.h" -#include "class_55.h" -#include "class_51.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_5/class_53.h b/lib/waf/build/lib_5/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_54.cpp b/lib/waf/build/lib_5/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_91.h" -#include "class_68.h" -#include "class_6.h" -#include "class_64.h" -#include "class_15.h" -#include "class_65.h" -#include "class_3.h" -#include "class_58.h" -#include "class_87.h" -#include "class_63.h" -#include "class_21.h" -#include "class_14.h" -#include "class_83.h" -#include "class_23.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_5/class_54.h b/lib/waf/build/lib_5/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_55.cpp b/lib/waf/build/lib_5/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_30.h" -#include "class_91.h" -#include "class_77.h" -#include "class_21.h" -#include "class_44.h" -#include "class_55.h" -#include "class_2.h" -#include "class_73.h" -#include "class_79.h" -#include "class_41.h" -#include "class_43.h" -#include "class_86.h" -#include "class_78.h" -#include "class_72.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_5/class_55.h b/lib/waf/build/lib_5/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_56.cpp b/lib/waf/build/lib_5/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_0.h" -#include "class_79.h" -#include "class_33.h" -#include "class_53.h" -#include "class_31.h" -#include "class_19.h" -#include "class_89.h" -#include "class_49.h" -#include "class_71.h" -#include "class_82.h" -#include "class_40.h" -#include "class_64.h" -#include "class_9.h" -#include "class_4.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_5/class_56.h b/lib/waf/build/lib_5/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_57.cpp b/lib/waf/build/lib_5/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_30.h" -#include "class_49.h" -#include "class_73.h" -#include "class_72.h" -#include "class_8.h" -#include "class_4.h" -#include "class_21.h" -#include "class_19.h" -#include "class_42.h" -#include "class_69.h" -#include "class_13.h" -#include "class_70.h" -#include "class_79.h" -#include "class_62.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_5/class_57.h b/lib/waf/build/lib_5/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_58.cpp b/lib/waf/build/lib_5/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_43.h" -#include "class_3.h" -#include "class_0.h" -#include "class_99.h" -#include "class_8.h" -#include "class_42.h" -#include "class_70.h" -#include "class_50.h" -#include "class_40.h" -#include "class_84.h" -#include "class_18.h" -#include "class_87.h" -#include "class_4.h" -#include "class_10.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_5/class_58.h b/lib/waf/build/lib_5/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_59.cpp b/lib/waf/build/lib_5/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_76.h" -#include "class_26.h" -#include "class_7.h" -#include "class_28.h" -#include "class_12.h" -#include "class_91.h" -#include "class_1.h" -#include "class_84.h" -#include "class_16.h" -#include "class_69.h" -#include "class_33.h" -#include "class_47.h" -#include "class_98.h" -#include "class_66.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_5/class_59.h b/lib/waf/build/lib_5/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_6.cpp b/lib/waf/build/lib_5/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_1.h" -#include "class_73.h" -#include "class_3.h" -#include "class_37.h" -#include "class_24.h" -#include "class_15.h" -#include "class_46.h" -#include "class_74.h" -#include "class_77.h" -#include "class_96.h" -#include "class_27.h" -#include "class_5.h" -#include "class_2.h" -#include "class_29.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_5/class_6.h b/lib/waf/build/lib_5/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_60.cpp b/lib/waf/build/lib_5/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_10.h" -#include "class_72.h" -#include "class_81.h" -#include "class_16.h" -#include "class_14.h" -#include "class_49.h" -#include "class_59.h" -#include "class_73.h" -#include "class_26.h" -#include "class_28.h" -#include "class_83.h" -#include "class_42.h" -#include "class_17.h" -#include "class_75.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_5/class_60.h b/lib/waf/build/lib_5/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_61.cpp b/lib/waf/build/lib_5/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_1.h" -#include "class_33.h" -#include "class_55.h" -#include "class_41.h" -#include "class_52.h" -#include "class_82.h" -#include "class_90.h" -#include "class_21.h" -#include "class_6.h" -#include "class_80.h" -#include "class_47.h" -#include "class_28.h" -#include "class_5.h" -#include "class_93.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_5/class_61.h b/lib/waf/build/lib_5/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_62.cpp b/lib/waf/build/lib_5/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_38.h" -#include "class_35.h" -#include "class_37.h" -#include "class_24.h" -#include "class_46.h" -#include "class_59.h" -#include "class_28.h" -#include "class_74.h" -#include "class_68.h" -#include "class_41.h" -#include "class_17.h" -#include "class_12.h" -#include "class_63.h" -#include "class_5.h" -#include "class_96.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_5/class_62.h b/lib/waf/build/lib_5/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_63.cpp b/lib/waf/build/lib_5/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_81.h" -#include "class_78.h" -#include "class_97.h" -#include "class_10.h" -#include "class_90.h" -#include "class_50.h" -#include "class_87.h" -#include "class_80.h" -#include "class_2.h" -#include "class_48.h" -#include "class_60.h" -#include "class_33.h" -#include "class_59.h" -#include "class_14.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_5/class_63.h b/lib/waf/build/lib_5/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_64.cpp b/lib/waf/build/lib_5/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_82.h" -#include "class_12.h" -#include "class_67.h" -#include "class_79.h" -#include "class_91.h" -#include "class_34.h" -#include "class_26.h" -#include "class_74.h" -#include "class_39.h" -#include "class_56.h" -#include "class_69.h" -#include "class_30.h" -#include "class_93.h" -#include "class_73.h" -#include "class_32.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_5/class_64.h b/lib/waf/build/lib_5/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_65.cpp b/lib/waf/build/lib_5/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_92.h" -#include "class_15.h" -#include "class_65.h" -#include "class_40.h" -#include "class_36.h" -#include "class_71.h" -#include "class_43.h" -#include "class_18.h" -#include "class_28.h" -#include "class_39.h" -#include "class_58.h" -#include "class_81.h" -#include "class_45.h" -#include "class_94.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_5/class_65.h b/lib/waf/build/lib_5/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_66.cpp b/lib/waf/build/lib_5/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_8.h" -#include "class_13.h" -#include "class_35.h" -#include "class_64.h" -#include "class_27.h" -#include "class_34.h" -#include "class_69.h" -#include "class_4.h" -#include "class_99.h" -#include "class_86.h" -#include "class_61.h" -#include "class_52.h" -#include "class_54.h" -#include "class_82.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_5/class_66.h b/lib/waf/build/lib_5/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_67.cpp b/lib/waf/build/lib_5/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_90.h" -#include "class_3.h" -#include "class_45.h" -#include "class_53.h" -#include "class_39.h" -#include "class_8.h" -#include "class_65.h" -#include "class_72.h" -#include "class_93.h" -#include "class_15.h" -#include "class_91.h" -#include "class_81.h" -#include "class_6.h" -#include "class_59.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_5/class_67.h b/lib/waf/build/lib_5/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_68.cpp b/lib/waf/build/lib_5/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_82.h" -#include "class_25.h" -#include "class_96.h" -#include "class_58.h" -#include "class_71.h" -#include "class_9.h" -#include "class_90.h" -#include "class_88.h" -#include "class_95.h" -#include "class_76.h" -#include "class_34.h" -#include "class_50.h" -#include "class_97.h" -#include "class_3.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_5/class_68.h b/lib/waf/build/lib_5/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_69.cpp b/lib/waf/build/lib_5/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_21.h" -#include "class_13.h" -#include "class_56.h" -#include "class_2.h" -#include "class_19.h" -#include "class_78.h" -#include "class_57.h" -#include "class_93.h" -#include "class_87.h" -#include "class_31.h" -#include "class_98.h" -#include "class_29.h" -#include "class_86.h" -#include "class_71.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_5/class_69.h b/lib/waf/build/lib_5/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_7.cpp b/lib/waf/build/lib_5/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_75.h" -#include "class_63.h" -#include "class_17.h" -#include "class_58.h" -#include "class_16.h" -#include "class_81.h" -#include "class_26.h" -#include "class_32.h" -#include "class_40.h" -#include "class_30.h" -#include "class_10.h" -#include "class_46.h" -#include "class_13.h" -#include "class_53.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_5/class_7.h b/lib/waf/build/lib_5/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_70.cpp b/lib/waf/build/lib_5/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_24.h" -#include "class_27.h" -#include "class_48.h" -#include "class_79.h" -#include "class_18.h" -#include "class_43.h" -#include "class_66.h" -#include "class_47.h" -#include "class_86.h" -#include "class_57.h" -#include "class_29.h" -#include "class_5.h" -#include "class_67.h" -#include "class_28.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_5/class_70.h b/lib/waf/build/lib_5/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_71.cpp b/lib/waf/build/lib_5/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_37.h" -#include "class_77.h" -#include "class_74.h" -#include "class_97.h" -#include "class_36.h" -#include "class_69.h" -#include "class_2.h" -#include "class_7.h" -#include "class_78.h" -#include "class_5.h" -#include "class_6.h" -#include "class_83.h" -#include "class_33.h" -#include "class_76.h" -#include "class_99.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_5/class_71.h b/lib/waf/build/lib_5/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_72.cpp b/lib/waf/build/lib_5/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_57.h" -#include "class_6.h" -#include "class_41.h" -#include "class_9.h" -#include "class_62.h" -#include "class_52.h" -#include "class_56.h" -#include "class_60.h" -#include "class_15.h" -#include "class_43.h" -#include "class_51.h" -#include "class_7.h" -#include "class_88.h" -#include "class_34.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_5/class_72.h b/lib/waf/build/lib_5/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_73.cpp b/lib/waf/build/lib_5/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_52.h" -#include "class_43.h" -#include "class_53.h" -#include "class_68.h" -#include "class_15.h" -#include "class_39.h" -#include "class_50.h" -#include "class_22.h" -#include "class_51.h" -#include "class_56.h" -#include "class_61.h" -#include "class_31.h" -#include "class_73.h" -#include "class_21.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_5/class_73.h b/lib/waf/build/lib_5/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_74.cpp b/lib/waf/build/lib_5/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_38.h" -#include "class_66.h" -#include "class_56.h" -#include "class_5.h" -#include "class_91.h" -#include "class_35.h" -#include "class_0.h" -#include "class_92.h" -#include "class_3.h" -#include "class_95.h" -#include "class_24.h" -#include "class_2.h" -#include "class_20.h" -#include "class_11.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_5/class_74.h b/lib/waf/build/lib_5/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_75.cpp b/lib/waf/build/lib_5/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_21.h" -#include "class_12.h" -#include "class_81.h" -#include "class_61.h" -#include "class_67.h" -#include "class_77.h" -#include "class_29.h" -#include "class_47.h" -#include "class_6.h" -#include "class_32.h" -#include "class_24.h" -#include "class_36.h" -#include "class_2.h" -#include "class_17.h" -#include "class_14.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_5/class_75.h b/lib/waf/build/lib_5/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_76.cpp b/lib/waf/build/lib_5/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_56.h" -#include "class_81.h" -#include "class_52.h" -#include "class_21.h" -#include "class_33.h" -#include "class_19.h" -#include "class_94.h" -#include "class_42.h" -#include "class_72.h" -#include "class_0.h" -#include "class_41.h" -#include "class_6.h" -#include "class_20.h" -#include "class_3.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_5/class_76.h b/lib/waf/build/lib_5/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_77.cpp b/lib/waf/build/lib_5/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_92.h" -#include "class_35.h" -#include "class_2.h" -#include "class_67.h" -#include "class_0.h" -#include "class_75.h" -#include "class_20.h" -#include "class_18.h" -#include "class_30.h" -#include "class_16.h" -#include "class_59.h" -#include "class_98.h" -#include "class_39.h" -#include "class_17.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_5/class_77.h b/lib/waf/build/lib_5/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_78.cpp b/lib/waf/build/lib_5/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_11.h" -#include "class_64.h" -#include "class_30.h" -#include "class_80.h" -#include "class_55.h" -#include "class_86.h" -#include "class_46.h" -#include "class_33.h" -#include "class_67.h" -#include "class_26.h" -#include "class_21.h" -#include "class_49.h" -#include "class_99.h" -#include "class_50.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_5/class_78.h b/lib/waf/build/lib_5/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_79.cpp b/lib/waf/build/lib_5/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_11.h" -#include "class_82.h" -#include "class_32.h" -#include "class_9.h" -#include "class_7.h" -#include "class_1.h" -#include "class_42.h" -#include "class_55.h" -#include "class_36.h" -#include "class_80.h" -#include "class_0.h" -#include "class_20.h" -#include "class_86.h" -#include "class_61.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_5/class_79.h b/lib/waf/build/lib_5/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_8.cpp b/lib/waf/build/lib_5/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_67.h" -#include "class_45.h" -#include "class_34.h" -#include "class_29.h" -#include "class_96.h" -#include "class_15.h" -#include "class_52.h" -#include "class_72.h" -#include "class_0.h" -#include "class_44.h" -#include "class_16.h" -#include "class_59.h" -#include "class_71.h" -#include "class_73.h" -#include "class_92.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_5/class_8.h b/lib/waf/build/lib_5/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_80.cpp b/lib/waf/build/lib_5/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_76.h" -#include "class_85.h" -#include "class_94.h" -#include "class_79.h" -#include "class_49.h" -#include "class_52.h" -#include "class_28.h" -#include "class_4.h" -#include "class_99.h" -#include "class_91.h" -#include "class_75.h" -#include "class_27.h" -#include "class_36.h" -#include "class_73.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_5/class_80.h b/lib/waf/build/lib_5/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_81.cpp b/lib/waf/build/lib_5/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_50.h" -#include "class_65.h" -#include "class_17.h" -#include "class_32.h" -#include "class_59.h" -#include "class_76.h" -#include "class_23.h" -#include "class_8.h" -#include "class_39.h" -#include "class_52.h" -#include "class_43.h" -#include "class_28.h" -#include "class_1.h" -#include "class_68.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_5/class_81.h b/lib/waf/build/lib_5/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_82.cpp b/lib/waf/build/lib_5/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_29.h" -#include "class_8.h" -#include "class_12.h" -#include "class_18.h" -#include "class_9.h" -#include "class_92.h" -#include "class_56.h" -#include "class_34.h" -#include "class_99.h" -#include "class_50.h" -#include "class_23.h" -#include "class_53.h" -#include "class_79.h" -#include "class_87.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_5/class_82.h b/lib/waf/build/lib_5/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_83.cpp b/lib/waf/build/lib_5/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_32.h" -#include "class_20.h" -#include "class_67.h" -#include "class_7.h" -#include "class_8.h" -#include "class_33.h" -#include "class_95.h" -#include "class_38.h" -#include "class_23.h" -#include "class_24.h" -#include "class_43.h" -#include "class_5.h" -#include "class_61.h" -#include "class_0.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_5/class_83.h b/lib/waf/build/lib_5/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_84.cpp b/lib/waf/build/lib_5/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_27.h" -#include "class_10.h" -#include "class_77.h" -#include "class_47.h" -#include "class_63.h" -#include "class_2.h" -#include "class_90.h" -#include "class_96.h" -#include "class_89.h" -#include "class_80.h" -#include "class_39.h" -#include "class_70.h" -#include "class_69.h" -#include "class_22.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_5/class_84.h b/lib/waf/build/lib_5/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_85.cpp b/lib/waf/build/lib_5/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_16.h" -#include "class_38.h" -#include "class_83.h" -#include "class_30.h" -#include "class_68.h" -#include "class_12.h" -#include "class_39.h" -#include "class_55.h" -#include "class_81.h" -#include "class_37.h" -#include "class_10.h" -#include "class_82.h" -#include "class_2.h" -#include "class_56.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_5/class_85.h b/lib/waf/build/lib_5/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_86.cpp b/lib/waf/build/lib_5/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_61.h" -#include "class_57.h" -#include "class_20.h" -#include "class_2.h" -#include "class_13.h" -#include "class_11.h" -#include "class_24.h" -#include "class_87.h" -#include "class_52.h" -#include "class_70.h" -#include "class_6.h" -#include "class_94.h" -#include "class_89.h" -#include "class_54.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_5/class_86.h b/lib/waf/build/lib_5/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_87.cpp b/lib/waf/build/lib_5/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_30.h" -#include "class_61.h" -#include "class_12.h" -#include "class_38.h" -#include "class_64.h" -#include "class_10.h" -#include "class_72.h" -#include "class_20.h" -#include "class_18.h" -#include "class_88.h" -#include "class_73.h" -#include "class_28.h" -#include "class_78.h" -#include "class_90.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_5/class_87.h b/lib/waf/build/lib_5/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_88.cpp b/lib/waf/build/lib_5/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_94.h" -#include "class_37.h" -#include "class_74.h" -#include "class_46.h" -#include "class_4.h" -#include "class_89.h" -#include "class_71.h" -#include "class_61.h" -#include "class_53.h" -#include "class_98.h" -#include "class_27.h" -#include "class_31.h" -#include "class_84.h" -#include "class_67.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_5/class_88.h b/lib/waf/build/lib_5/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_89.cpp b/lib/waf/build/lib_5/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_38.h" -#include "class_98.h" -#include "class_99.h" -#include "class_84.h" -#include "class_2.h" -#include "class_59.h" -#include "class_71.h" -#include "class_15.h" -#include "class_50.h" -#include "class_6.h" -#include "class_53.h" -#include "class_8.h" -#include "class_96.h" -#include "class_13.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_5/class_89.h b/lib/waf/build/lib_5/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_9.cpp b/lib/waf/build/lib_5/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_84.h" -#include "class_79.h" -#include "class_87.h" -#include "class_68.h" -#include "class_6.h" -#include "class_57.h" -#include "class_33.h" -#include "class_21.h" -#include "class_11.h" -#include "class_74.h" -#include "class_0.h" -#include "class_49.h" -#include "class_7.h" -#include "class_42.h" -#include "class_95.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_5/class_9.h b/lib/waf/build/lib_5/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_90.cpp b/lib/waf/build/lib_5/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_33.h" -#include "class_73.h" -#include "class_48.h" -#include "class_78.h" -#include "class_23.h" -#include "class_89.h" -#include "class_50.h" -#include "class_17.h" -#include "class_20.h" -#include "class_1.h" -#include "class_66.h" -#include "class_83.h" -#include "class_6.h" -#include "class_88.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_5/class_90.h b/lib/waf/build/lib_5/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_91.cpp b/lib/waf/build/lib_5/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_23.h" -#include "class_39.h" -#include "class_78.h" -#include "class_88.h" -#include "class_0.h" -#include "class_58.h" -#include "class_87.h" -#include "class_17.h" -#include "class_54.h" -#include "class_16.h" -#include "class_86.h" -#include "class_73.h" -#include "class_7.h" -#include "class_95.h" -#include "class_65.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_5/class_91.h b/lib/waf/build/lib_5/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_92.cpp b/lib/waf/build/lib_5/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_47.h" -#include "class_74.h" -#include "class_5.h" -#include "class_4.h" -#include "class_55.h" -#include "class_7.h" -#include "class_66.h" -#include "class_2.h" -#include "class_10.h" -#include "class_43.h" -#include "class_72.h" -#include "class_59.h" -#include "class_42.h" -#include "class_82.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_5/class_92.h b/lib/waf/build/lib_5/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_93.cpp b/lib/waf/build/lib_5/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_88.h" -#include "class_23.h" -#include "class_79.h" -#include "class_51.h" -#include "class_56.h" -#include "class_97.h" -#include "class_5.h" -#include "class_2.h" -#include "class_43.h" -#include "class_93.h" -#include "class_99.h" -#include "class_39.h" -#include "class_32.h" -#include "class_27.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_5/class_93.h b/lib/waf/build/lib_5/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_94.cpp b/lib/waf/build/lib_5/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_31.h" -#include "class_39.h" -#include "class_30.h" -#include "class_44.h" -#include "class_23.h" -#include "class_98.h" -#include "class_19.h" -#include "class_80.h" -#include "class_0.h" -#include "class_42.h" -#include "class_48.h" -#include "class_52.h" -#include "class_37.h" -#include "class_2.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_5/class_94.h b/lib/waf/build/lib_5/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_95.cpp b/lib/waf/build/lib_5/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_27.h" -#include "class_23.h" -#include "class_17.h" -#include "class_30.h" -#include "class_34.h" -#include "class_3.h" -#include "class_50.h" -#include "class_1.h" -#include "class_45.h" -#include "class_13.h" -#include "class_12.h" -#include "class_90.h" -#include "class_41.h" -#include "class_98.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_5/class_95.h b/lib/waf/build/lib_5/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_96.cpp b/lib/waf/build/lib_5/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_31.h" -#include "class_72.h" -#include "class_77.h" -#include "class_48.h" -#include "class_22.h" -#include "class_76.h" -#include "class_32.h" -#include "class_16.h" -#include "class_38.h" -#include "class_81.h" -#include "class_33.h" -#include "class_59.h" -#include "class_21.h" -#include "class_90.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_5/class_96.h b/lib/waf/build/lib_5/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_97.cpp b/lib/waf/build/lib_5/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_84.h" -#include "class_0.h" -#include "class_14.h" -#include "class_7.h" -#include "class_43.h" -#include "class_66.h" -#include "class_76.h" -#include "class_53.h" -#include "class_12.h" -#include "class_19.h" -#include "class_70.h" -#include "class_98.h" -#include "class_45.h" -#include "class_48.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_5/class_97.h b/lib/waf/build/lib_5/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_98.cpp b/lib/waf/build/lib_5/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_26.h" -#include "class_36.h" -#include "class_70.h" -#include "class_77.h" -#include "class_87.h" -#include "class_21.h" -#include "class_6.h" -#include "class_35.h" -#include "class_28.h" -#include "class_71.h" -#include "class_9.h" -#include "class_57.h" -#include "class_27.h" -#include "class_46.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_5/class_98.h b/lib/waf/build/lib_5/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_5/class_99.cpp b/lib/waf/build/lib_5/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_5/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_87.h" -#include "class_22.h" -#include "class_62.h" -#include "class_98.h" -#include "class_2.h" -#include "class_9.h" -#include "class_36.h" -#include "class_92.h" -#include "class_55.h" -#include "class_20.h" -#include "class_14.h" -#include "class_7.h" -#include "class_64.h" -#include "class_86.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_5/class_99.h b/lib/waf/build/lib_5/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_5/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_6/Makefile b/lib/waf/build/lib_6/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_6/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_6.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_6/Makefile.am b/lib/waf/build/lib_6/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_6/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib6.la -lib6_la_SOURCES = lib_6/class_0.cpp lib_6/class_1.cpp lib_6/class_2.cpp lib_6/class_3.cpp lib_6/class_4.cpp lib_6/class_5.cpp lib_6/class_6.cpp lib_6/class_7.cpp lib_6/class_8.cpp lib_6/class_9.cpp lib_6/class_10.cpp lib_6/class_11.cpp lib_6/class_12.cpp lib_6/class_13.cpp lib_6/class_14.cpp lib_6/class_15.cpp lib_6/class_16.cpp lib_6/class_17.cpp lib_6/class_18.cpp lib_6/class_19.cpp lib_6/class_20.cpp lib_6/class_21.cpp lib_6/class_22.cpp lib_6/class_23.cpp lib_6/class_24.cpp lib_6/class_25.cpp lib_6/class_26.cpp lib_6/class_27.cpp lib_6/class_28.cpp lib_6/class_29.cpp lib_6/class_30.cpp lib_6/class_31.cpp lib_6/class_32.cpp lib_6/class_33.cpp lib_6/class_34.cpp lib_6/class_35.cpp lib_6/class_36.cpp lib_6/class_37.cpp lib_6/class_38.cpp lib_6/class_39.cpp lib_6/class_40.cpp lib_6/class_41.cpp lib_6/class_42.cpp lib_6/class_43.cpp lib_6/class_44.cpp lib_6/class_45.cpp lib_6/class_46.cpp lib_6/class_47.cpp lib_6/class_48.cpp lib_6/class_49.cpp lib_6/class_50.cpp lib_6/class_51.cpp lib_6/class_52.cpp lib_6/class_53.cpp lib_6/class_54.cpp lib_6/class_55.cpp lib_6/class_56.cpp lib_6/class_57.cpp lib_6/class_58.cpp lib_6/class_59.cpp lib_6/class_60.cpp lib_6/class_61.cpp lib_6/class_62.cpp lib_6/class_63.cpp lib_6/class_64.cpp lib_6/class_65.cpp lib_6/class_66.cpp lib_6/class_67.cpp lib_6/class_68.cpp lib_6/class_69.cpp lib_6/class_70.cpp lib_6/class_71.cpp lib_6/class_72.cpp lib_6/class_73.cpp lib_6/class_74.cpp lib_6/class_75.cpp lib_6/class_76.cpp lib_6/class_77.cpp lib_6/class_78.cpp lib_6/class_79.cpp lib_6/class_80.cpp lib_6/class_81.cpp lib_6/class_82.cpp lib_6/class_83.cpp lib_6/class_84.cpp lib_6/class_85.cpp lib_6/class_86.cpp lib_6/class_87.cpp lib_6/class_88.cpp lib_6/class_89.cpp lib_6/class_90.cpp lib_6/class_91.cpp lib_6/class_92.cpp lib_6/class_93.cpp lib_6/class_94.cpp lib_6/class_95.cpp lib_6/class_96.cpp lib_6/class_97.cpp lib_6/class_98.cpp lib_6/class_99.cpp diff --git a/lib/waf/build/lib_6/SConscript b/lib/waf/build/lib_6/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_6/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_6", list) - diff --git a/lib/waf/build/lib_6/class_0.cpp b/lib/waf/build/lib_6/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_49.h" -#include "class_94.h" -#include "class_85.h" -#include "class_72.h" -#include "class_60.h" -#include "class_47.h" -#include "class_76.h" -#include "class_19.h" -#include "class_29.h" -#include "class_69.h" -#include "class_2.h" -#include "class_5.h" -#include "class_78.h" -#include "class_23.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_6/class_0.h b/lib/waf/build/lib_6/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_1.cpp b/lib/waf/build/lib_6/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_43.h" -#include "class_68.h" -#include "class_55.h" -#include "class_75.h" -#include "class_6.h" -#include "class_76.h" -#include "class_27.h" -#include "class_80.h" -#include "class_82.h" -#include "class_0.h" -#include "class_95.h" -#include "class_78.h" -#include "class_51.h" -#include "class_77.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_6/class_1.h b/lib/waf/build/lib_6/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_10.cpp b/lib/waf/build/lib_6/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_11.h" -#include "class_10.h" -#include "class_70.h" -#include "class_40.h" -#include "class_80.h" -#include "class_12.h" -#include "class_82.h" -#include "class_81.h" -#include "class_20.h" -#include "class_60.h" -#include "class_36.h" -#include "class_32.h" -#include "class_79.h" -#include "class_29.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_6/class_10.h b/lib/waf/build/lib_6/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_11.cpp b/lib/waf/build/lib_6/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_18.h" -#include "class_33.h" -#include "class_55.h" -#include "class_73.h" -#include "class_31.h" -#include "class_82.h" -#include "class_97.h" -#include "class_63.h" -#include "class_54.h" -#include "class_95.h" -#include "class_88.h" -#include "class_15.h" -#include "class_39.h" -#include "class_9.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_6/class_11.h b/lib/waf/build/lib_6/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_12.cpp b/lib/waf/build/lib_6/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_25.h" -#include "class_33.h" -#include "class_55.h" -#include "class_24.h" -#include "class_82.h" -#include "class_67.h" -#include "class_18.h" -#include "class_32.h" -#include "class_16.h" -#include "class_8.h" -#include "class_91.h" -#include "class_43.h" -#include "class_81.h" -#include "class_13.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_6/class_12.h b/lib/waf/build/lib_6/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_13.cpp b/lib/waf/build/lib_6/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_12.h" -#include "class_21.h" -#include "class_46.h" -#include "class_84.h" -#include "class_87.h" -#include "class_32.h" -#include "class_67.h" -#include "class_66.h" -#include "class_75.h" -#include "class_16.h" -#include "class_24.h" -#include "class_7.h" -#include "class_93.h" -#include "class_96.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_6/class_13.h b/lib/waf/build/lib_6/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_14.cpp b/lib/waf/build/lib_6/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_33.h" -#include "class_69.h" -#include "class_73.h" -#include "class_24.h" -#include "class_92.h" -#include "class_39.h" -#include "class_17.h" -#include "class_22.h" -#include "class_84.h" -#include "class_90.h" -#include "class_62.h" -#include "class_16.h" -#include "class_20.h" -#include "class_82.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_6/class_14.h b/lib/waf/build/lib_6/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_15.cpp b/lib/waf/build/lib_6/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_34.h" -#include "class_51.h" -#include "class_64.h" -#include "class_25.h" -#include "class_41.h" -#include "class_86.h" -#include "class_28.h" -#include "class_99.h" -#include "class_8.h" -#include "class_83.h" -#include "class_89.h" -#include "class_10.h" -#include "class_61.h" -#include "class_92.h" -#include "class_68.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_6/class_15.h b/lib/waf/build/lib_6/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_16.cpp b/lib/waf/build/lib_6/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_55.h" -#include "class_29.h" -#include "class_77.h" -#include "class_57.h" -#include "class_54.h" -#include "class_46.h" -#include "class_22.h" -#include "class_5.h" -#include "class_41.h" -#include "class_11.h" -#include "class_1.h" -#include "class_19.h" -#include "class_96.h" -#include "class_16.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_6/class_16.h b/lib/waf/build/lib_6/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_17.cpp b/lib/waf/build/lib_6/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_42.h" -#include "class_9.h" -#include "class_90.h" -#include "class_96.h" -#include "class_92.h" -#include "class_78.h" -#include "class_25.h" -#include "class_1.h" -#include "class_5.h" -#include "class_60.h" -#include "class_47.h" -#include "class_88.h" -#include "class_98.h" -#include "class_12.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_6/class_17.h b/lib/waf/build/lib_6/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_18.cpp b/lib/waf/build/lib_6/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_96.h" -#include "class_46.h" -#include "class_19.h" -#include "class_38.h" -#include "class_57.h" -#include "class_23.h" -#include "class_3.h" -#include "class_10.h" -#include "class_27.h" -#include "class_93.h" -#include "class_99.h" -#include "class_98.h" -#include "class_63.h" -#include "class_48.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_6/class_18.h b/lib/waf/build/lib_6/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_19.cpp b/lib/waf/build/lib_6/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_74.h" -#include "class_3.h" -#include "class_40.h" -#include "class_73.h" -#include "class_52.h" -#include "class_2.h" -#include "class_50.h" -#include "class_87.h" -#include "class_12.h" -#include "class_22.h" -#include "class_36.h" -#include "class_60.h" -#include "class_77.h" -#include "class_59.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_6/class_19.h b/lib/waf/build/lib_6/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_2.cpp b/lib/waf/build/lib_6/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_0.h" -#include "class_99.h" -#include "class_17.h" -#include "class_63.h" -#include "class_51.h" -#include "class_13.h" -#include "class_95.h" -#include "class_29.h" -#include "class_52.h" -#include "class_74.h" -#include "class_93.h" -#include "class_79.h" -#include "class_47.h" -#include "class_54.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_6/class_2.h b/lib/waf/build/lib_6/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_20.cpp b/lib/waf/build/lib_6/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_48.h" -#include "class_87.h" -#include "class_0.h" -#include "class_73.h" -#include "class_25.h" -#include "class_12.h" -#include "class_13.h" -#include "class_17.h" -#include "class_7.h" -#include "class_46.h" -#include "class_28.h" -#include "class_31.h" -#include "class_62.h" -#include "class_72.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_6/class_20.h b/lib/waf/build/lib_6/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_21.cpp b/lib/waf/build/lib_6/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_73.h" -#include "class_38.h" -#include "class_98.h" -#include "class_16.h" -#include "class_77.h" -#include "class_39.h" -#include "class_74.h" -#include "class_1.h" -#include "class_21.h" -#include "class_55.h" -#include "class_3.h" -#include "class_31.h" -#include "class_20.h" -#include "class_11.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_6/class_21.h b/lib/waf/build/lib_6/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_22.cpp b/lib/waf/build/lib_6/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_10.h" -#include "class_8.h" -#include "class_30.h" -#include "class_69.h" -#include "class_92.h" -#include "class_67.h" -#include "class_77.h" -#include "class_35.h" -#include "class_64.h" -#include "class_34.h" -#include "class_71.h" -#include "class_38.h" -#include "class_6.h" -#include "class_82.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_6/class_22.h b/lib/waf/build/lib_6/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_23.cpp b/lib/waf/build/lib_6/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_9.h" -#include "class_60.h" -#include "class_70.h" -#include "class_1.h" -#include "class_63.h" -#include "class_35.h" -#include "class_90.h" -#include "class_0.h" -#include "class_42.h" -#include "class_59.h" -#include "class_62.h" -#include "class_98.h" -#include "class_34.h" -#include "class_46.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_6/class_23.h b/lib/waf/build/lib_6/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_24.cpp b/lib/waf/build/lib_6/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_32.h" -#include "class_24.h" -#include "class_46.h" -#include "class_27.h" -#include "class_55.h" -#include "class_31.h" -#include "class_65.h" -#include "class_60.h" -#include "class_79.h" -#include "class_61.h" -#include "class_87.h" -#include "class_84.h" -#include "class_20.h" -#include "class_0.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_6/class_24.h b/lib/waf/build/lib_6/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_25.cpp b/lib/waf/build/lib_6/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_20.h" -#include "class_15.h" -#include "class_78.h" -#include "class_92.h" -#include "class_26.h" -#include "class_12.h" -#include "class_40.h" -#include "class_9.h" -#include "class_3.h" -#include "class_84.h" -#include "class_50.h" -#include "class_44.h" -#include "class_69.h" -#include "class_57.h" -#include "class_22.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_6/class_25.h b/lib/waf/build/lib_6/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_26.cpp b/lib/waf/build/lib_6/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_75.h" -#include "class_89.h" -#include "class_81.h" -#include "class_8.h" -#include "class_95.h" -#include "class_56.h" -#include "class_27.h" -#include "class_47.h" -#include "class_87.h" -#include "class_74.h" -#include "class_78.h" -#include "class_92.h" -#include "class_42.h" -#include "class_5.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_6/class_26.h b/lib/waf/build/lib_6/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_27.cpp b/lib/waf/build/lib_6/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_20.h" -#include "class_88.h" -#include "class_25.h" -#include "class_73.h" -#include "class_68.h" -#include "class_72.h" -#include "class_27.h" -#include "class_54.h" -#include "class_5.h" -#include "class_59.h" -#include "class_11.h" -#include "class_95.h" -#include "class_71.h" -#include "class_19.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_6/class_27.h b/lib/waf/build/lib_6/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_28.cpp b/lib/waf/build/lib_6/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_68.h" -#include "class_73.h" -#include "class_21.h" -#include "class_75.h" -#include "class_50.h" -#include "class_10.h" -#include "class_72.h" -#include "class_18.h" -#include "class_70.h" -#include "class_86.h" -#include "class_60.h" -#include "class_87.h" -#include "class_33.h" -#include "class_85.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_6/class_28.h b/lib/waf/build/lib_6/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_29.cpp b/lib/waf/build/lib_6/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_91.h" -#include "class_57.h" -#include "class_16.h" -#include "class_44.h" -#include "class_88.h" -#include "class_45.h" -#include "class_61.h" -#include "class_40.h" -#include "class_81.h" -#include "class_69.h" -#include "class_27.h" -#include "class_29.h" -#include "class_32.h" -#include "class_76.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_6/class_29.h b/lib/waf/build/lib_6/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_3.cpp b/lib/waf/build/lib_6/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_7.h" -#include "class_51.h" -#include "class_12.h" -#include "class_47.h" -#include "class_21.h" -#include "class_27.h" -#include "class_60.h" -#include "class_38.h" -#include "class_8.h" -#include "class_34.h" -#include "class_94.h" -#include "class_83.h" -#include "class_99.h" -#include "class_97.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_6/class_3.h b/lib/waf/build/lib_6/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_30.cpp b/lib/waf/build/lib_6/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_97.h" -#include "class_89.h" -#include "class_20.h" -#include "class_44.h" -#include "class_98.h" -#include "class_52.h" -#include "class_58.h" -#include "class_57.h" -#include "class_31.h" -#include "class_5.h" -#include "class_30.h" -#include "class_95.h" -#include "class_86.h" -#include "class_66.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_6/class_30.h b/lib/waf/build/lib_6/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_31.cpp b/lib/waf/build/lib_6/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_17.h" -#include "class_13.h" -#include "class_26.h" -#include "class_18.h" -#include "class_7.h" -#include "class_96.h" -#include "class_95.h" -#include "class_37.h" -#include "class_23.h" -#include "class_8.h" -#include "class_94.h" -#include "class_4.h" -#include "class_80.h" -#include "class_34.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_6/class_31.h b/lib/waf/build/lib_6/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_32.cpp b/lib/waf/build/lib_6/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_42.h" -#include "class_35.h" -#include "class_83.h" -#include "class_12.h" -#include "class_16.h" -#include "class_66.h" -#include "class_79.h" -#include "class_3.h" -#include "class_19.h" -#include "class_1.h" -#include "class_72.h" -#include "class_90.h" -#include "class_10.h" -#include "class_94.h" -#include "class_95.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_6/class_32.h b/lib/waf/build/lib_6/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_33.cpp b/lib/waf/build/lib_6/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_72.h" -#include "class_3.h" -#include "class_7.h" -#include "class_18.h" -#include "class_25.h" -#include "class_59.h" -#include "class_54.h" -#include "class_10.h" -#include "class_74.h" -#include "class_95.h" -#include "class_66.h" -#include "class_67.h" -#include "class_75.h" -#include "class_9.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_6/class_33.h b/lib/waf/build/lib_6/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_34.cpp b/lib/waf/build/lib_6/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_50.h" -#include "class_21.h" -#include "class_9.h" -#include "class_48.h" -#include "class_78.h" -#include "class_64.h" -#include "class_34.h" -#include "class_69.h" -#include "class_39.h" -#include "class_52.h" -#include "class_22.h" -#include "class_45.h" -#include "class_37.h" -#include "class_28.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_6/class_34.h b/lib/waf/build/lib_6/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_35.cpp b/lib/waf/build/lib_6/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_33.h" -#include "class_76.h" -#include "class_55.h" -#include "class_19.h" -#include "class_36.h" -#include "class_99.h" -#include "class_25.h" -#include "class_5.h" -#include "class_17.h" -#include "class_84.h" -#include "class_34.h" -#include "class_44.h" -#include "class_14.h" -#include "class_56.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_6/class_35.h b/lib/waf/build/lib_6/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_36.cpp b/lib/waf/build/lib_6/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_12.h" -#include "class_20.h" -#include "class_66.h" -#include "class_2.h" -#include "class_25.h" -#include "class_85.h" -#include "class_69.h" -#include "class_95.h" -#include "class_43.h" -#include "class_74.h" -#include "class_80.h" -#include "class_89.h" -#include "class_68.h" -#include "class_10.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_6/class_36.h b/lib/waf/build/lib_6/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_37.cpp b/lib/waf/build/lib_6/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_3.h" -#include "class_56.h" -#include "class_60.h" -#include "class_30.h" -#include "class_70.h" -#include "class_57.h" -#include "class_68.h" -#include "class_38.h" -#include "class_2.h" -#include "class_71.h" -#include "class_85.h" -#include "class_80.h" -#include "class_26.h" -#include "class_74.h" -#include "class_91.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_6/class_37.h b/lib/waf/build/lib_6/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_38.cpp b/lib/waf/build/lib_6/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_19.h" -#include "class_74.h" -#include "class_32.h" -#include "class_81.h" -#include "class_25.h" -#include "class_86.h" -#include "class_1.h" -#include "class_29.h" -#include "class_91.h" -#include "class_48.h" -#include "class_67.h" -#include "class_60.h" -#include "class_96.h" -#include "class_72.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_6/class_38.h b/lib/waf/build/lib_6/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_39.cpp b/lib/waf/build/lib_6/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_92.h" -#include "class_51.h" -#include "class_28.h" -#include "class_13.h" -#include "class_14.h" -#include "class_10.h" -#include "class_17.h" -#include "class_16.h" -#include "class_58.h" -#include "class_1.h" -#include "class_97.h" -#include "class_26.h" -#include "class_62.h" -#include "class_93.h" -#include "class_65.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_6/class_39.h b/lib/waf/build/lib_6/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_4.cpp b/lib/waf/build/lib_6/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_97.h" -#include "class_72.h" -#include "class_46.h" -#include "class_64.h" -#include "class_99.h" -#include "class_95.h" -#include "class_94.h" -#include "class_69.h" -#include "class_68.h" -#include "class_18.h" -#include "class_78.h" -#include "class_28.h" -#include "class_12.h" -#include "class_13.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_6/class_4.h b/lib/waf/build/lib_6/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_40.cpp b/lib/waf/build/lib_6/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_10.h" -#include "class_99.h" -#include "class_94.h" -#include "class_79.h" -#include "class_16.h" -#include "class_76.h" -#include "class_84.h" -#include "class_72.h" -#include "class_25.h" -#include "class_61.h" -#include "class_73.h" -#include "class_36.h" -#include "class_8.h" -#include "class_96.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_6/class_40.h b/lib/waf/build/lib_6/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_41.cpp b/lib/waf/build/lib_6/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_39.h" -#include "class_72.h" -#include "class_55.h" -#include "class_64.h" -#include "class_15.h" -#include "class_71.h" -#include "class_70.h" -#include "class_86.h" -#include "class_37.h" -#include "class_99.h" -#include "class_96.h" -#include "class_1.h" -#include "class_79.h" -#include "class_68.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_6/class_41.h b/lib/waf/build/lib_6/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_42.cpp b/lib/waf/build/lib_6/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_57.h" -#include "class_39.h" -#include "class_17.h" -#include "class_64.h" -#include "class_68.h" -#include "class_93.h" -#include "class_24.h" -#include "class_91.h" -#include "class_10.h" -#include "class_62.h" -#include "class_92.h" -#include "class_50.h" -#include "class_2.h" -#include "class_99.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_6/class_42.h b/lib/waf/build/lib_6/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_43.cpp b/lib/waf/build/lib_6/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_53.h" -#include "class_52.h" -#include "class_79.h" -#include "class_18.h" -#include "class_41.h" -#include "class_35.h" -#include "class_38.h" -#include "class_22.h" -#include "class_93.h" -#include "class_70.h" -#include "class_42.h" -#include "class_89.h" -#include "class_96.h" -#include "class_56.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_6/class_43.h b/lib/waf/build/lib_6/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_44.cpp b/lib/waf/build/lib_6/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_12.h" -#include "class_4.h" -#include "class_19.h" -#include "class_14.h" -#include "class_96.h" -#include "class_56.h" -#include "class_99.h" -#include "class_66.h" -#include "class_57.h" -#include "class_74.h" -#include "class_77.h" -#include "class_31.h" -#include "class_92.h" -#include "class_26.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_6/class_44.h b/lib/waf/build/lib_6/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_45.cpp b/lib/waf/build/lib_6/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_85.h" -#include "class_46.h" -#include "class_54.h" -#include "class_0.h" -#include "class_73.h" -#include "class_60.h" -#include "class_61.h" -#include "class_68.h" -#include "class_79.h" -#include "class_87.h" -#include "class_99.h" -#include "class_66.h" -#include "class_56.h" -#include "class_13.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_6/class_45.h b/lib/waf/build/lib_6/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_46.cpp b/lib/waf/build/lib_6/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_10.h" -#include "class_64.h" -#include "class_38.h" -#include "class_44.h" -#include "class_97.h" -#include "class_45.h" -#include "class_77.h" -#include "class_83.h" -#include "class_65.h" -#include "class_41.h" -#include "class_24.h" -#include "class_34.h" -#include "class_68.h" -#include "class_11.h" -#include "class_88.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_6/class_46.h b/lib/waf/build/lib_6/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_47.cpp b/lib/waf/build/lib_6/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_85.h" -#include "class_49.h" -#include "class_0.h" -#include "class_47.h" -#include "class_75.h" -#include "class_54.h" -#include "class_38.h" -#include "class_39.h" -#include "class_43.h" -#include "class_64.h" -#include "class_98.h" -#include "class_80.h" -#include "class_11.h" -#include "class_93.h" -#include "class_29.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_6/class_47.h b/lib/waf/build/lib_6/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_48.cpp b/lib/waf/build/lib_6/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_29.h" -#include "class_27.h" -#include "class_89.h" -#include "class_98.h" -#include "class_73.h" -#include "class_14.h" -#include "class_35.h" -#include "class_97.h" -#include "class_76.h" -#include "class_31.h" -#include "class_50.h" -#include "class_43.h" -#include "class_24.h" -#include "class_63.h" -#include "class_2.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_6/class_48.h b/lib/waf/build/lib_6/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_49.cpp b/lib/waf/build/lib_6/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_14.h" -#include "class_25.h" -#include "class_37.h" -#include "class_96.h" -#include "class_21.h" -#include "class_15.h" -#include "class_31.h" -#include "class_41.h" -#include "class_38.h" -#include "class_9.h" -#include "class_30.h" -#include "class_27.h" -#include "class_91.h" -#include "class_29.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_6/class_49.h b/lib/waf/build/lib_6/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_5.cpp b/lib/waf/build/lib_6/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_36.h" -#include "class_53.h" -#include "class_65.h" -#include "class_91.h" -#include "class_12.h" -#include "class_55.h" -#include "class_62.h" -#include "class_69.h" -#include "class_50.h" -#include "class_25.h" -#include "class_16.h" -#include "class_96.h" -#include "class_71.h" -#include "class_26.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_6/class_5.h b/lib/waf/build/lib_6/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_50.cpp b/lib/waf/build/lib_6/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_99.h" -#include "class_43.h" -#include "class_64.h" -#include "class_97.h" -#include "class_90.h" -#include "class_82.h" -#include "class_16.h" -#include "class_32.h" -#include "class_57.h" -#include "class_31.h" -#include "class_42.h" -#include "class_23.h" -#include "class_3.h" -#include "class_68.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_6/class_50.h b/lib/waf/build/lib_6/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_51.cpp b/lib/waf/build/lib_6/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_29.h" -#include "class_68.h" -#include "class_48.h" -#include "class_98.h" -#include "class_88.h" -#include "class_16.h" -#include "class_35.h" -#include "class_24.h" -#include "class_87.h" -#include "class_46.h" -#include "class_52.h" -#include "class_79.h" -#include "class_91.h" -#include "class_62.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_6/class_51.h b/lib/waf/build/lib_6/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_52.cpp b/lib/waf/build/lib_6/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_60.h" -#include "class_85.h" -#include "class_99.h" -#include "class_58.h" -#include "class_14.h" -#include "class_79.h" -#include "class_36.h" -#include "class_12.h" -#include "class_53.h" -#include "class_76.h" -#include "class_33.h" -#include "class_16.h" -#include "class_29.h" -#include "class_17.h" -#include "class_88.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_6/class_52.h b/lib/waf/build/lib_6/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_53.cpp b/lib/waf/build/lib_6/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_62.h" -#include "class_2.h" -#include "class_32.h" -#include "class_61.h" -#include "class_78.h" -#include "class_85.h" -#include "class_81.h" -#include "class_21.h" -#include "class_68.h" -#include "class_57.h" -#include "class_44.h" -#include "class_86.h" -#include "class_13.h" -#include "class_52.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_6/class_53.h b/lib/waf/build/lib_6/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_54.cpp b/lib/waf/build/lib_6/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_42.h" -#include "class_26.h" -#include "class_29.h" -#include "class_68.h" -#include "class_16.h" -#include "class_88.h" -#include "class_32.h" -#include "class_94.h" -#include "class_78.h" -#include "class_87.h" -#include "class_45.h" -#include "class_24.h" -#include "class_93.h" -#include "class_47.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_6/class_54.h b/lib/waf/build/lib_6/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_55.cpp b/lib/waf/build/lib_6/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_94.h" -#include "class_72.h" -#include "class_16.h" -#include "class_99.h" -#include "class_66.h" -#include "class_20.h" -#include "class_63.h" -#include "class_2.h" -#include "class_38.h" -#include "class_17.h" -#include "class_88.h" -#include "class_36.h" -#include "class_50.h" -#include "class_93.h" -#include "class_75.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_6/class_55.h b/lib/waf/build/lib_6/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_56.cpp b/lib/waf/build/lib_6/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_79.h" -#include "class_0.h" -#include "class_37.h" -#include "class_35.h" -#include "class_64.h" -#include "class_25.h" -#include "class_13.h" -#include "class_63.h" -#include "class_36.h" -#include "class_6.h" -#include "class_98.h" -#include "class_29.h" -#include "class_2.h" -#include "class_78.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_6/class_56.h b/lib/waf/build/lib_6/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_57.cpp b/lib/waf/build/lib_6/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_66.h" -#include "class_33.h" -#include "class_86.h" -#include "class_91.h" -#include "class_9.h" -#include "class_83.h" -#include "class_4.h" -#include "class_67.h" -#include "class_55.h" -#include "class_12.h" -#include "class_22.h" -#include "class_6.h" -#include "class_17.h" -#include "class_23.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_6/class_57.h b/lib/waf/build/lib_6/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_58.cpp b/lib/waf/build/lib_6/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_61.h" -#include "class_28.h" -#include "class_25.h" -#include "class_58.h" -#include "class_10.h" -#include "class_41.h" -#include "class_83.h" -#include "class_57.h" -#include "class_67.h" -#include "class_53.h" -#include "class_13.h" -#include "class_60.h" -#include "class_54.h" -#include "class_98.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_6/class_58.h b/lib/waf/build/lib_6/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_59.cpp b/lib/waf/build/lib_6/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_6.h" -#include "class_47.h" -#include "class_4.h" -#include "class_9.h" -#include "class_39.h" -#include "class_92.h" -#include "class_43.h" -#include "class_11.h" -#include "class_90.h" -#include "class_94.h" -#include "class_58.h" -#include "class_49.h" -#include "class_57.h" -#include "class_23.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_6/class_59.h b/lib/waf/build/lib_6/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_6.cpp b/lib/waf/build/lib_6/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_82.h" -#include "class_70.h" -#include "class_58.h" -#include "class_81.h" -#include "class_94.h" -#include "class_54.h" -#include "class_97.h" -#include "class_57.h" -#include "class_5.h" -#include "class_14.h" -#include "class_63.h" -#include "class_17.h" -#include "class_40.h" -#include "class_93.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_6/class_6.h b/lib/waf/build/lib_6/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_60.cpp b/lib/waf/build/lib_6/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_1.h" -#include "class_3.h" -#include "class_34.h" -#include "class_42.h" -#include "class_58.h" -#include "class_21.h" -#include "class_36.h" -#include "class_57.h" -#include "class_65.h" -#include "class_19.h" -#include "class_2.h" -#include "class_16.h" -#include "class_17.h" -#include "class_25.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_6/class_60.h b/lib/waf/build/lib_6/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_61.cpp b/lib/waf/build/lib_6/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_14.h" -#include "class_72.h" -#include "class_40.h" -#include "class_23.h" -#include "class_8.h" -#include "class_34.h" -#include "class_92.h" -#include "class_12.h" -#include "class_0.h" -#include "class_82.h" -#include "class_5.h" -#include "class_2.h" -#include "class_17.h" -#include "class_27.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_6/class_61.h b/lib/waf/build/lib_6/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_62.cpp b/lib/waf/build/lib_6/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_21.h" -#include "class_34.h" -#include "class_85.h" -#include "class_58.h" -#include "class_83.h" -#include "class_28.h" -#include "class_67.h" -#include "class_59.h" -#include "class_9.h" -#include "class_54.h" -#include "class_40.h" -#include "class_42.h" -#include "class_1.h" -#include "class_79.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_6/class_62.h b/lib/waf/build/lib_6/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_63.cpp b/lib/waf/build/lib_6/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_32.h" -#include "class_84.h" -#include "class_3.h" -#include "class_68.h" -#include "class_37.h" -#include "class_85.h" -#include "class_40.h" -#include "class_48.h" -#include "class_50.h" -#include "class_17.h" -#include "class_52.h" -#include "class_41.h" -#include "class_43.h" -#include "class_49.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_6/class_63.h b/lib/waf/build/lib_6/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_64.cpp b/lib/waf/build/lib_6/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_95.h" -#include "class_96.h" -#include "class_70.h" -#include "class_7.h" -#include "class_24.h" -#include "class_32.h" -#include "class_10.h" -#include "class_71.h" -#include "class_62.h" -#include "class_51.h" -#include "class_26.h" -#include "class_2.h" -#include "class_58.h" -#include "class_56.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_6/class_64.h b/lib/waf/build/lib_6/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_65.cpp b/lib/waf/build/lib_6/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_57.h" -#include "class_34.h" -#include "class_3.h" -#include "class_30.h" -#include "class_58.h" -#include "class_7.h" -#include "class_82.h" -#include "class_87.h" -#include "class_43.h" -#include "class_25.h" -#include "class_71.h" -#include "class_83.h" -#include "class_66.h" -#include "class_32.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_6/class_65.h b/lib/waf/build/lib_6/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_66.cpp b/lib/waf/build/lib_6/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_96.h" -#include "class_25.h" -#include "class_93.h" -#include "class_54.h" -#include "class_77.h" -#include "class_35.h" -#include "class_91.h" -#include "class_38.h" -#include "class_80.h" -#include "class_3.h" -#include "class_82.h" -#include "class_39.h" -#include "class_48.h" -#include "class_21.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_6/class_66.h b/lib/waf/build/lib_6/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_67.cpp b/lib/waf/build/lib_6/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_11.h" -#include "class_29.h" -#include "class_71.h" -#include "class_38.h" -#include "class_0.h" -#include "class_79.h" -#include "class_47.h" -#include "class_69.h" -#include "class_78.h" -#include "class_3.h" -#include "class_22.h" -#include "class_16.h" -#include "class_72.h" -#include "class_53.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_6/class_67.h b/lib/waf/build/lib_6/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_68.cpp b/lib/waf/build/lib_6/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_6.h" -#include "class_33.h" -#include "class_73.h" -#include "class_50.h" -#include "class_95.h" -#include "class_29.h" -#include "class_66.h" -#include "class_38.h" -#include "class_92.h" -#include "class_51.h" -#include "class_37.h" -#include "class_53.h" -#include "class_94.h" -#include "class_39.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_6/class_68.h b/lib/waf/build/lib_6/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_69.cpp b/lib/waf/build/lib_6/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_62.h" -#include "class_58.h" -#include "class_12.h" -#include "class_56.h" -#include "class_98.h" -#include "class_4.h" -#include "class_10.h" -#include "class_40.h" -#include "class_53.h" -#include "class_16.h" -#include "class_19.h" -#include "class_0.h" -#include "class_66.h" -#include "class_8.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_6/class_69.h b/lib/waf/build/lib_6/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_7.cpp b/lib/waf/build/lib_6/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_70.h" -#include "class_8.h" -#include "class_26.h" -#include "class_93.h" -#include "class_29.h" -#include "class_19.h" -#include "class_53.h" -#include "class_22.h" -#include "class_35.h" -#include "class_82.h" -#include "class_4.h" -#include "class_5.h" -#include "class_55.h" -#include "class_65.h" -#include "class_75.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_6/class_7.h b/lib/waf/build/lib_6/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_70.cpp b/lib/waf/build/lib_6/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_55.h" -#include "class_94.h" -#include "class_73.h" -#include "class_58.h" -#include "class_98.h" -#include "class_53.h" -#include "class_46.h" -#include "class_40.h" -#include "class_82.h" -#include "class_62.h" -#include "class_75.h" -#include "class_28.h" -#include "class_61.h" -#include "class_79.h" -#include "class_69.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_6/class_70.h b/lib/waf/build/lib_6/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_71.cpp b/lib/waf/build/lib_6/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_58.h" -#include "class_29.h" -#include "class_63.h" -#include "class_52.h" -#include "class_56.h" -#include "class_85.h" -#include "class_24.h" -#include "class_41.h" -#include "class_46.h" -#include "class_92.h" -#include "class_33.h" -#include "class_70.h" -#include "class_19.h" -#include "class_76.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_6/class_71.h b/lib/waf/build/lib_6/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_72.cpp b/lib/waf/build/lib_6/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_34.h" -#include "class_72.h" -#include "class_42.h" -#include "class_97.h" -#include "class_31.h" -#include "class_43.h" -#include "class_98.h" -#include "class_20.h" -#include "class_40.h" -#include "class_3.h" -#include "class_22.h" -#include "class_57.h" -#include "class_66.h" -#include "class_59.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_6/class_72.h b/lib/waf/build/lib_6/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_73.cpp b/lib/waf/build/lib_6/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_38.h" -#include "class_41.h" -#include "class_83.h" -#include "class_31.h" -#include "class_29.h" -#include "class_22.h" -#include "class_27.h" -#include "class_70.h" -#include "class_2.h" -#include "class_32.h" -#include "class_45.h" -#include "class_47.h" -#include "class_7.h" -#include "class_10.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_6/class_73.h b/lib/waf/build/lib_6/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_74.cpp b/lib/waf/build/lib_6/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_23.h" -#include "class_35.h" -#include "class_82.h" -#include "class_40.h" -#include "class_67.h" -#include "class_13.h" -#include "class_97.h" -#include "class_60.h" -#include "class_8.h" -#include "class_42.h" -#include "class_89.h" -#include "class_28.h" -#include "class_16.h" -#include "class_34.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_6/class_74.h b/lib/waf/build/lib_6/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_75.cpp b/lib/waf/build/lib_6/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_52.h" -#include "class_19.h" -#include "class_77.h" -#include "class_13.h" -#include "class_21.h" -#include "class_51.h" -#include "class_60.h" -#include "class_70.h" -#include "class_3.h" -#include "class_2.h" -#include "class_15.h" -#include "class_0.h" -#include "class_38.h" -#include "class_34.h" -#include "class_7.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_6/class_75.h b/lib/waf/build/lib_6/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_76.cpp b/lib/waf/build/lib_6/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_23.h" -#include "class_32.h" -#include "class_4.h" -#include "class_71.h" -#include "class_27.h" -#include "class_60.h" -#include "class_33.h" -#include "class_57.h" -#include "class_73.h" -#include "class_30.h" -#include "class_12.h" -#include "class_72.h" -#include "class_99.h" -#include "class_24.h" -#include "class_70.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_6/class_76.h b/lib/waf/build/lib_6/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_77.cpp b/lib/waf/build/lib_6/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_99.h" -#include "class_13.h" -#include "class_50.h" -#include "class_80.h" -#include "class_61.h" -#include "class_22.h" -#include "class_81.h" -#include "class_52.h" -#include "class_14.h" -#include "class_77.h" -#include "class_23.h" -#include "class_28.h" -#include "class_87.h" -#include "class_57.h" -#include "class_68.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_6/class_77.h b/lib/waf/build/lib_6/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_78.cpp b/lib/waf/build/lib_6/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_20.h" -#include "class_1.h" -#include "class_30.h" -#include "class_52.h" -#include "class_59.h" -#include "class_86.h" -#include "class_84.h" -#include "class_53.h" -#include "class_21.h" -#include "class_34.h" -#include "class_68.h" -#include "class_23.h" -#include "class_88.h" -#include "class_87.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_6/class_78.h b/lib/waf/build/lib_6/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_79.cpp b/lib/waf/build/lib_6/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_77.h" -#include "class_94.h" -#include "class_34.h" -#include "class_16.h" -#include "class_10.h" -#include "class_93.h" -#include "class_44.h" -#include "class_46.h" -#include "class_88.h" -#include "class_25.h" -#include "class_43.h" -#include "class_29.h" -#include "class_20.h" -#include "class_81.h" -#include "class_82.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_6/class_79.h b/lib/waf/build/lib_6/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_8.cpp b/lib/waf/build/lib_6/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_14.h" -#include "class_58.h" -#include "class_72.h" -#include "class_37.h" -#include "class_63.h" -#include "class_23.h" -#include "class_59.h" -#include "class_33.h" -#include "class_64.h" -#include "class_57.h" -#include "class_54.h" -#include "class_12.h" -#include "class_86.h" -#include "class_35.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_6/class_8.h b/lib/waf/build/lib_6/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_80.cpp b/lib/waf/build/lib_6/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_37.h" -#include "class_22.h" -#include "class_28.h" -#include "class_67.h" -#include "class_24.h" -#include "class_50.h" -#include "class_13.h" -#include "class_88.h" -#include "class_63.h" -#include "class_87.h" -#include "class_74.h" -#include "class_55.h" -#include "class_41.h" -#include "class_38.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_6/class_80.h b/lib/waf/build/lib_6/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_81.cpp b/lib/waf/build/lib_6/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_8.h" -#include "class_69.h" -#include "class_62.h" -#include "class_34.h" -#include "class_97.h" -#include "class_44.h" -#include "class_55.h" -#include "class_60.h" -#include "class_91.h" -#include "class_10.h" -#include "class_35.h" -#include "class_43.h" -#include "class_57.h" -#include "class_93.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_6/class_81.h b/lib/waf/build/lib_6/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_82.cpp b/lib/waf/build/lib_6/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_58.h" -#include "class_3.h" -#include "class_12.h" -#include "class_74.h" -#include "class_83.h" -#include "class_68.h" -#include "class_96.h" -#include "class_34.h" -#include "class_89.h" -#include "class_84.h" -#include "class_88.h" -#include "class_98.h" -#include "class_70.h" -#include "class_26.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_6/class_82.h b/lib/waf/build/lib_6/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_83.cpp b/lib/waf/build/lib_6/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_42.h" -#include "class_51.h" -#include "class_97.h" -#include "class_55.h" -#include "class_74.h" -#include "class_17.h" -#include "class_5.h" -#include "class_14.h" -#include "class_13.h" -#include "class_73.h" -#include "class_33.h" -#include "class_26.h" -#include "class_19.h" -#include "class_91.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_6/class_83.h b/lib/waf/build/lib_6/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_84.cpp b/lib/waf/build/lib_6/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_90.h" -#include "class_38.h" -#include "class_49.h" -#include "class_94.h" -#include "class_88.h" -#include "class_16.h" -#include "class_96.h" -#include "class_74.h" -#include "class_99.h" -#include "class_6.h" -#include "class_95.h" -#include "class_61.h" -#include "class_3.h" -#include "class_7.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_6/class_84.h b/lib/waf/build/lib_6/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_85.cpp b/lib/waf/build/lib_6/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_77.h" -#include "class_75.h" -#include "class_71.h" -#include "class_95.h" -#include "class_26.h" -#include "class_41.h" -#include "class_13.h" -#include "class_31.h" -#include "class_22.h" -#include "class_29.h" -#include "class_10.h" -#include "class_59.h" -#include "class_33.h" -#include "class_50.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_6/class_85.h b/lib/waf/build/lib_6/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_86.cpp b/lib/waf/build/lib_6/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_41.h" -#include "class_74.h" -#include "class_24.h" -#include "class_97.h" -#include "class_79.h" -#include "class_32.h" -#include "class_25.h" -#include "class_30.h" -#include "class_18.h" -#include "class_40.h" -#include "class_29.h" -#include "class_13.h" -#include "class_5.h" -#include "class_89.h" -#include "class_64.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_6/class_86.h b/lib/waf/build/lib_6/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_87.cpp b/lib/waf/build/lib_6/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_56.h" -#include "class_80.h" -#include "class_27.h" -#include "class_81.h" -#include "class_54.h" -#include "class_38.h" -#include "class_21.h" -#include "class_55.h" -#include "class_66.h" -#include "class_28.h" -#include "class_22.h" -#include "class_73.h" -#include "class_30.h" -#include "class_52.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_6/class_87.h b/lib/waf/build/lib_6/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_88.cpp b/lib/waf/build/lib_6/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_68.h" -#include "class_63.h" -#include "class_19.h" -#include "class_71.h" -#include "class_40.h" -#include "class_27.h" -#include "class_93.h" -#include "class_22.h" -#include "class_95.h" -#include "class_23.h" -#include "class_31.h" -#include "class_43.h" -#include "class_13.h" -#include "class_56.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_6/class_88.h b/lib/waf/build/lib_6/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_89.cpp b/lib/waf/build/lib_6/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_57.h" -#include "class_21.h" -#include "class_13.h" -#include "class_43.h" -#include "class_91.h" -#include "class_67.h" -#include "class_82.h" -#include "class_30.h" -#include "class_66.h" -#include "class_54.h" -#include "class_45.h" -#include "class_10.h" -#include "class_69.h" -#include "class_88.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_6/class_89.h b/lib/waf/build/lib_6/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_9.cpp b/lib/waf/build/lib_6/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_87.h" -#include "class_2.h" -#include "class_53.h" -#include "class_51.h" -#include "class_44.h" -#include "class_75.h" -#include "class_73.h" -#include "class_47.h" -#include "class_37.h" -#include "class_13.h" -#include "class_40.h" -#include "class_50.h" -#include "class_28.h" -#include "class_6.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_6/class_9.h b/lib/waf/build/lib_6/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_90.cpp b/lib/waf/build/lib_6/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_54.h" -#include "class_96.h" -#include "class_10.h" -#include "class_62.h" -#include "class_26.h" -#include "class_35.h" -#include "class_50.h" -#include "class_37.h" -#include "class_64.h" -#include "class_30.h" -#include "class_68.h" -#include "class_42.h" -#include "class_67.h" -#include "class_8.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_6/class_90.h b/lib/waf/build/lib_6/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_91.cpp b/lib/waf/build/lib_6/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_26.h" -#include "class_57.h" -#include "class_41.h" -#include "class_51.h" -#include "class_85.h" -#include "class_83.h" -#include "class_46.h" -#include "class_21.h" -#include "class_61.h" -#include "class_71.h" -#include "class_8.h" -#include "class_89.h" -#include "class_27.h" -#include "class_81.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_6/class_91.h b/lib/waf/build/lib_6/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_92.cpp b/lib/waf/build/lib_6/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_41.h" -#include "class_75.h" -#include "class_99.h" -#include "class_70.h" -#include "class_25.h" -#include "class_94.h" -#include "class_27.h" -#include "class_42.h" -#include "class_14.h" -#include "class_1.h" -#include "class_9.h" -#include "class_81.h" -#include "class_72.h" -#include "class_65.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_6/class_92.h b/lib/waf/build/lib_6/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_93.cpp b/lib/waf/build/lib_6/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_68.h" -#include "class_63.h" -#include "class_98.h" -#include "class_60.h" -#include "class_99.h" -#include "class_9.h" -#include "class_44.h" -#include "class_82.h" -#include "class_43.h" -#include "class_49.h" -#include "class_27.h" -#include "class_39.h" -#include "class_70.h" -#include "class_25.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_6/class_93.h b/lib/waf/build/lib_6/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_94.cpp b/lib/waf/build/lib_6/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_86.h" -#include "class_17.h" -#include "class_57.h" -#include "class_24.h" -#include "class_35.h" -#include "class_65.h" -#include "class_95.h" -#include "class_0.h" -#include "class_5.h" -#include "class_87.h" -#include "class_46.h" -#include "class_7.h" -#include "class_41.h" -#include "class_63.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_6/class_94.h b/lib/waf/build/lib_6/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_95.cpp b/lib/waf/build/lib_6/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_84.h" -#include "class_77.h" -#include "class_92.h" -#include "class_7.h" -#include "class_86.h" -#include "class_93.h" -#include "class_87.h" -#include "class_48.h" -#include "class_33.h" -#include "class_81.h" -#include "class_28.h" -#include "class_82.h" -#include "class_31.h" -#include "class_18.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_6/class_95.h b/lib/waf/build/lib_6/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_96.cpp b/lib/waf/build/lib_6/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_32.h" -#include "class_90.h" -#include "class_25.h" -#include "class_19.h" -#include "class_9.h" -#include "class_5.h" -#include "class_81.h" -#include "class_67.h" -#include "class_42.h" -#include "class_57.h" -#include "class_41.h" -#include "class_89.h" -#include "class_65.h" -#include "class_22.h" -#include "class_38.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_6/class_96.h b/lib/waf/build/lib_6/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_97.cpp b/lib/waf/build/lib_6/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_51.h" -#include "class_13.h" -#include "class_57.h" -#include "class_60.h" -#include "class_68.h" -#include "class_16.h" -#include "class_49.h" -#include "class_84.h" -#include "class_58.h" -#include "class_37.h" -#include "class_63.h" -#include "class_90.h" -#include "class_70.h" -#include "class_53.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_6/class_97.h b/lib/waf/build/lib_6/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_98.cpp b/lib/waf/build/lib_6/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_4.h" -#include "class_12.h" -#include "class_23.h" -#include "class_67.h" -#include "class_96.h" -#include "class_93.h" -#include "class_72.h" -#include "class_15.h" -#include "class_28.h" -#include "class_61.h" -#include "class_30.h" -#include "class_99.h" -#include "class_85.h" -#include "class_17.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_6/class_98.h b/lib/waf/build/lib_6/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_6/class_99.cpp b/lib/waf/build/lib_6/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_6/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_8.h" -#include "class_23.h" -#include "class_46.h" -#include "class_59.h" -#include "class_24.h" -#include "class_88.h" -#include "class_25.h" -#include "class_56.h" -#include "class_12.h" -#include "class_78.h" -#include "class_33.h" -#include "class_2.h" -#include "class_41.h" -#include "class_74.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_6/class_99.h b/lib/waf/build/lib_6/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_6/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_7/Makefile b/lib/waf/build/lib_7/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_7/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_7.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_7/Makefile.am b/lib/waf/build/lib_7/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_7/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib7.la -lib7_la_SOURCES = lib_7/class_0.cpp lib_7/class_1.cpp lib_7/class_2.cpp lib_7/class_3.cpp lib_7/class_4.cpp lib_7/class_5.cpp lib_7/class_6.cpp lib_7/class_7.cpp lib_7/class_8.cpp lib_7/class_9.cpp lib_7/class_10.cpp lib_7/class_11.cpp lib_7/class_12.cpp lib_7/class_13.cpp lib_7/class_14.cpp lib_7/class_15.cpp lib_7/class_16.cpp lib_7/class_17.cpp lib_7/class_18.cpp lib_7/class_19.cpp lib_7/class_20.cpp lib_7/class_21.cpp lib_7/class_22.cpp lib_7/class_23.cpp lib_7/class_24.cpp lib_7/class_25.cpp lib_7/class_26.cpp lib_7/class_27.cpp lib_7/class_28.cpp lib_7/class_29.cpp lib_7/class_30.cpp lib_7/class_31.cpp lib_7/class_32.cpp lib_7/class_33.cpp lib_7/class_34.cpp lib_7/class_35.cpp lib_7/class_36.cpp lib_7/class_37.cpp lib_7/class_38.cpp lib_7/class_39.cpp lib_7/class_40.cpp lib_7/class_41.cpp lib_7/class_42.cpp lib_7/class_43.cpp lib_7/class_44.cpp lib_7/class_45.cpp lib_7/class_46.cpp lib_7/class_47.cpp lib_7/class_48.cpp lib_7/class_49.cpp lib_7/class_50.cpp lib_7/class_51.cpp lib_7/class_52.cpp lib_7/class_53.cpp lib_7/class_54.cpp lib_7/class_55.cpp lib_7/class_56.cpp lib_7/class_57.cpp lib_7/class_58.cpp lib_7/class_59.cpp lib_7/class_60.cpp lib_7/class_61.cpp lib_7/class_62.cpp lib_7/class_63.cpp lib_7/class_64.cpp lib_7/class_65.cpp lib_7/class_66.cpp lib_7/class_67.cpp lib_7/class_68.cpp lib_7/class_69.cpp lib_7/class_70.cpp lib_7/class_71.cpp lib_7/class_72.cpp lib_7/class_73.cpp lib_7/class_74.cpp lib_7/class_75.cpp lib_7/class_76.cpp lib_7/class_77.cpp lib_7/class_78.cpp lib_7/class_79.cpp lib_7/class_80.cpp lib_7/class_81.cpp lib_7/class_82.cpp lib_7/class_83.cpp lib_7/class_84.cpp lib_7/class_85.cpp lib_7/class_86.cpp lib_7/class_87.cpp lib_7/class_88.cpp lib_7/class_89.cpp lib_7/class_90.cpp lib_7/class_91.cpp lib_7/class_92.cpp lib_7/class_93.cpp lib_7/class_94.cpp lib_7/class_95.cpp lib_7/class_96.cpp lib_7/class_97.cpp lib_7/class_98.cpp lib_7/class_99.cpp diff --git a/lib/waf/build/lib_7/SConscript b/lib/waf/build/lib_7/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_7/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_7", list) - diff --git a/lib/waf/build/lib_7/class_0.cpp b/lib/waf/build/lib_7/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_81.h" -#include "class_94.h" -#include "class_45.h" -#include "class_15.h" -#include "class_73.h" -#include "class_9.h" -#include "class_19.h" -#include "class_77.h" -#include "class_40.h" -#include "class_35.h" -#include "class_46.h" -#include "class_80.h" -#include "class_90.h" -#include "class_18.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_7/class_0.h b/lib/waf/build/lib_7/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_1.cpp b/lib/waf/build/lib_7/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_78.h" -#include "class_75.h" -#include "class_10.h" -#include "class_79.h" -#include "class_58.h" -#include "class_81.h" -#include "class_49.h" -#include "class_90.h" -#include "class_77.h" -#include "class_80.h" -#include "class_12.h" -#include "class_44.h" -#include "class_9.h" -#include "class_52.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_7/class_1.h b/lib/waf/build/lib_7/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_10.cpp b/lib/waf/build/lib_7/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_69.h" -#include "class_14.h" -#include "class_43.h" -#include "class_37.h" -#include "class_64.h" -#include "class_35.h" -#include "class_82.h" -#include "class_48.h" -#include "class_22.h" -#include "class_17.h" -#include "class_52.h" -#include "class_13.h" -#include "class_33.h" -#include "class_36.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_7/class_10.h b/lib/waf/build/lib_7/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_11.cpp b/lib/waf/build/lib_7/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_66.h" -#include "class_94.h" -#include "class_97.h" -#include "class_3.h" -#include "class_63.h" -#include "class_27.h" -#include "class_49.h" -#include "class_22.h" -#include "class_41.h" -#include "class_95.h" -#include "class_61.h" -#include "class_79.h" -#include "class_11.h" -#include "class_16.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_7/class_11.h b/lib/waf/build/lib_7/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_12.cpp b/lib/waf/build/lib_7/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_88.h" -#include "class_55.h" -#include "class_75.h" -#include "class_62.h" -#include "class_92.h" -#include "class_84.h" -#include "class_90.h" -#include "class_96.h" -#include "class_53.h" -#include "class_59.h" -#include "class_56.h" -#include "class_38.h" -#include "class_21.h" -#include "class_60.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_7/class_12.h b/lib/waf/build/lib_7/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_13.cpp b/lib/waf/build/lib_7/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_31.h" -#include "class_88.h" -#include "class_73.h" -#include "class_93.h" -#include "class_63.h" -#include "class_74.h" -#include "class_44.h" -#include "class_20.h" -#include "class_4.h" -#include "class_94.h" -#include "class_79.h" -#include "class_83.h" -#include "class_70.h" -#include "class_41.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_7/class_13.h b/lib/waf/build/lib_7/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_14.cpp b/lib/waf/build/lib_7/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_44.h" -#include "class_48.h" -#include "class_60.h" -#include "class_94.h" -#include "class_92.h" -#include "class_86.h" -#include "class_55.h" -#include "class_77.h" -#include "class_78.h" -#include "class_14.h" -#include "class_39.h" -#include "class_53.h" -#include "class_9.h" -#include "class_74.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_7/class_14.h b/lib/waf/build/lib_7/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_15.cpp b/lib/waf/build/lib_7/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_75.h" -#include "class_41.h" -#include "class_25.h" -#include "class_31.h" -#include "class_19.h" -#include "class_97.h" -#include "class_92.h" -#include "class_10.h" -#include "class_88.h" -#include "class_72.h" -#include "class_49.h" -#include "class_11.h" -#include "class_13.h" -#include "class_96.h" -#include "class_52.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_7/class_15.h b/lib/waf/build/lib_7/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_16.cpp b/lib/waf/build/lib_7/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_28.h" -#include "class_52.h" -#include "class_79.h" -#include "class_71.h" -#include "class_15.h" -#include "class_62.h" -#include "class_16.h" -#include "class_45.h" -#include "class_81.h" -#include "class_12.h" -#include "class_41.h" -#include "class_86.h" -#include "class_53.h" -#include "class_35.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_7/class_16.h b/lib/waf/build/lib_7/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_17.cpp b/lib/waf/build/lib_7/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_87.h" -#include "class_81.h" -#include "class_18.h" -#include "class_57.h" -#include "class_79.h" -#include "class_82.h" -#include "class_5.h" -#include "class_37.h" -#include "class_64.h" -#include "class_61.h" -#include "class_10.h" -#include "class_92.h" -#include "class_85.h" -#include "class_25.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_7/class_17.h b/lib/waf/build/lib_7/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_18.cpp b/lib/waf/build/lib_7/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_58.h" -#include "class_17.h" -#include "class_94.h" -#include "class_72.h" -#include "class_12.h" -#include "class_43.h" -#include "class_71.h" -#include "class_60.h" -#include "class_25.h" -#include "class_22.h" -#include "class_23.h" -#include "class_92.h" -#include "class_84.h" -#include "class_38.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_7/class_18.h b/lib/waf/build/lib_7/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_19.cpp b/lib/waf/build/lib_7/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_12.h" -#include "class_21.h" -#include "class_2.h" -#include "class_3.h" -#include "class_83.h" -#include "class_7.h" -#include "class_87.h" -#include "class_14.h" -#include "class_29.h" -#include "class_98.h" -#include "class_50.h" -#include "class_39.h" -#include "class_57.h" -#include "class_62.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_7/class_19.h b/lib/waf/build/lib_7/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_2.cpp b/lib/waf/build/lib_7/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_96.h" -#include "class_12.h" -#include "class_69.h" -#include "class_55.h" -#include "class_30.h" -#include "class_72.h" -#include "class_2.h" -#include "class_68.h" -#include "class_86.h" -#include "class_23.h" -#include "class_51.h" -#include "class_99.h" -#include "class_67.h" -#include "class_54.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_7/class_2.h b/lib/waf/build/lib_7/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_20.cpp b/lib/waf/build/lib_7/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_70.h" -#include "class_6.h" -#include "class_72.h" -#include "class_57.h" -#include "class_27.h" -#include "class_77.h" -#include "class_47.h" -#include "class_16.h" -#include "class_59.h" -#include "class_22.h" -#include "class_63.h" -#include "class_48.h" -#include "class_97.h" -#include "class_21.h" -#include "class_88.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_7/class_20.h b/lib/waf/build/lib_7/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_21.cpp b/lib/waf/build/lib_7/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_98.h" -#include "class_62.h" -#include "class_66.h" -#include "class_14.h" -#include "class_81.h" -#include "class_42.h" -#include "class_78.h" -#include "class_43.h" -#include "class_61.h" -#include "class_28.h" -#include "class_10.h" -#include "class_33.h" -#include "class_56.h" -#include "class_37.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_7/class_21.h b/lib/waf/build/lib_7/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_22.cpp b/lib/waf/build/lib_7/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_47.h" -#include "class_28.h" -#include "class_93.h" -#include "class_45.h" -#include "class_36.h" -#include "class_50.h" -#include "class_11.h" -#include "class_51.h" -#include "class_90.h" -#include "class_30.h" -#include "class_34.h" -#include "class_29.h" -#include "class_95.h" -#include "class_70.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_7/class_22.h b/lib/waf/build/lib_7/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_23.cpp b/lib/waf/build/lib_7/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_76.h" -#include "class_50.h" -#include "class_61.h" -#include "class_94.h" -#include "class_83.h" -#include "class_26.h" -#include "class_4.h" -#include "class_73.h" -#include "class_8.h" -#include "class_41.h" -#include "class_37.h" -#include "class_93.h" -#include "class_42.h" -#include "class_27.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_7/class_23.h b/lib/waf/build/lib_7/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_24.cpp b/lib/waf/build/lib_7/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_50.h" -#include "class_33.h" -#include "class_23.h" -#include "class_62.h" -#include "class_30.h" -#include "class_72.h" -#include "class_61.h" -#include "class_94.h" -#include "class_0.h" -#include "class_13.h" -#include "class_90.h" -#include "class_35.h" -#include "class_73.h" -#include "class_39.h" -#include "class_65.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_7/class_24.h b/lib/waf/build/lib_7/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_25.cpp b/lib/waf/build/lib_7/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_75.h" -#include "class_3.h" -#include "class_2.h" -#include "class_10.h" -#include "class_39.h" -#include "class_62.h" -#include "class_49.h" -#include "class_4.h" -#include "class_73.h" -#include "class_65.h" -#include "class_46.h" -#include "class_58.h" -#include "class_52.h" -#include "class_70.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_7/class_25.h b/lib/waf/build/lib_7/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_26.cpp b/lib/waf/build/lib_7/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_80.h" -#include "class_98.h" -#include "class_41.h" -#include "class_91.h" -#include "class_51.h" -#include "class_36.h" -#include "class_53.h" -#include "class_97.h" -#include "class_21.h" -#include "class_33.h" -#include "class_2.h" -#include "class_89.h" -#include "class_48.h" -#include "class_14.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_7/class_26.h b/lib/waf/build/lib_7/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_27.cpp b/lib/waf/build/lib_7/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_55.h" -#include "class_10.h" -#include "class_66.h" -#include "class_72.h" -#include "class_51.h" -#include "class_39.h" -#include "class_49.h" -#include "class_14.h" -#include "class_78.h" -#include "class_81.h" -#include "class_64.h" -#include "class_4.h" -#include "class_5.h" -#include "class_84.h" -#include "class_91.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_7/class_27.h b/lib/waf/build/lib_7/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_28.cpp b/lib/waf/build/lib_7/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_41.h" -#include "class_32.h" -#include "class_63.h" -#include "class_90.h" -#include "class_36.h" -#include "class_87.h" -#include "class_22.h" -#include "class_23.h" -#include "class_97.h" -#include "class_89.h" -#include "class_46.h" -#include "class_56.h" -#include "class_21.h" -#include "class_76.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_7/class_28.h b/lib/waf/build/lib_7/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_29.cpp b/lib/waf/build/lib_7/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_95.h" -#include "class_38.h" -#include "class_85.h" -#include "class_62.h" -#include "class_40.h" -#include "class_99.h" -#include "class_76.h" -#include "class_26.h" -#include "class_81.h" -#include "class_21.h" -#include "class_71.h" -#include "class_42.h" -#include "class_18.h" -#include "class_11.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_7/class_29.h b/lib/waf/build/lib_7/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_3.cpp b/lib/waf/build/lib_7/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_18.h" -#include "class_94.h" -#include "class_4.h" -#include "class_14.h" -#include "class_75.h" -#include "class_95.h" -#include "class_93.h" -#include "class_21.h" -#include "class_91.h" -#include "class_32.h" -#include "class_80.h" -#include "class_20.h" -#include "class_48.h" -#include "class_27.h" -#include "class_63.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_7/class_3.h b/lib/waf/build/lib_7/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_30.cpp b/lib/waf/build/lib_7/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_69.h" -#include "class_75.h" -#include "class_9.h" -#include "class_90.h" -#include "class_76.h" -#include "class_16.h" -#include "class_65.h" -#include "class_77.h" -#include "class_6.h" -#include "class_46.h" -#include "class_38.h" -#include "class_25.h" -#include "class_26.h" -#include "class_12.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_7/class_30.h b/lib/waf/build/lib_7/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_31.cpp b/lib/waf/build/lib_7/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_96.h" -#include "class_67.h" -#include "class_15.h" -#include "class_70.h" -#include "class_42.h" -#include "class_73.h" -#include "class_4.h" -#include "class_36.h" -#include "class_62.h" -#include "class_31.h" -#include "class_25.h" -#include "class_80.h" -#include "class_75.h" -#include "class_26.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_7/class_31.h b/lib/waf/build/lib_7/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_32.cpp b/lib/waf/build/lib_7/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_55.h" -#include "class_81.h" -#include "class_67.h" -#include "class_23.h" -#include "class_14.h" -#include "class_87.h" -#include "class_95.h" -#include "class_85.h" -#include "class_90.h" -#include "class_48.h" -#include "class_21.h" -#include "class_13.h" -#include "class_36.h" -#include "class_80.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_7/class_32.h b/lib/waf/build/lib_7/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_33.cpp b/lib/waf/build/lib_7/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_17.h" -#include "class_2.h" -#include "class_8.h" -#include "class_73.h" -#include "class_94.h" -#include "class_15.h" -#include "class_64.h" -#include "class_14.h" -#include "class_91.h" -#include "class_38.h" -#include "class_97.h" -#include "class_52.h" -#include "class_53.h" -#include "class_37.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_7/class_33.h b/lib/waf/build/lib_7/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_34.cpp b/lib/waf/build/lib_7/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_56.h" -#include "class_6.h" -#include "class_43.h" -#include "class_55.h" -#include "class_23.h" -#include "class_40.h" -#include "class_77.h" -#include "class_27.h" -#include "class_48.h" -#include "class_18.h" -#include "class_74.h" -#include "class_35.h" -#include "class_80.h" -#include "class_37.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_7/class_34.h b/lib/waf/build/lib_7/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_35.cpp b/lib/waf/build/lib_7/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_31.h" -#include "class_76.h" -#include "class_53.h" -#include "class_58.h" -#include "class_93.h" -#include "class_92.h" -#include "class_36.h" -#include "class_74.h" -#include "class_75.h" -#include "class_17.h" -#include "class_0.h" -#include "class_66.h" -#include "class_90.h" -#include "class_79.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_7/class_35.h b/lib/waf/build/lib_7/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_36.cpp b/lib/waf/build/lib_7/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_82.h" -#include "class_58.h" -#include "class_70.h" -#include "class_75.h" -#include "class_99.h" -#include "class_39.h" -#include "class_50.h" -#include "class_4.h" -#include "class_91.h" -#include "class_65.h" -#include "class_59.h" -#include "class_87.h" -#include "class_6.h" -#include "class_21.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_7/class_36.h b/lib/waf/build/lib_7/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_37.cpp b/lib/waf/build/lib_7/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_30.h" -#include "class_43.h" -#include "class_26.h" -#include "class_33.h" -#include "class_91.h" -#include "class_63.h" -#include "class_99.h" -#include "class_76.h" -#include "class_97.h" -#include "class_74.h" -#include "class_61.h" -#include "class_20.h" -#include "class_87.h" -#include "class_1.h" -#include "class_81.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_7/class_37.h b/lib/waf/build/lib_7/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_38.cpp b/lib/waf/build/lib_7/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_37.h" -#include "class_94.h" -#include "class_14.h" -#include "class_23.h" -#include "class_62.h" -#include "class_52.h" -#include "class_34.h" -#include "class_19.h" -#include "class_58.h" -#include "class_77.h" -#include "class_4.h" -#include "class_17.h" -#include "class_47.h" -#include "class_64.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_7/class_38.h b/lib/waf/build/lib_7/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_39.cpp b/lib/waf/build/lib_7/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_46.h" -#include "class_12.h" -#include "class_67.h" -#include "class_66.h" -#include "class_85.h" -#include "class_65.h" -#include "class_4.h" -#include "class_15.h" -#include "class_37.h" -#include "class_34.h" -#include "class_14.h" -#include "class_86.h" -#include "class_75.h" -#include "class_93.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_7/class_39.h b/lib/waf/build/lib_7/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_4.cpp b/lib/waf/build/lib_7/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_94.h" -#include "class_14.h" -#include "class_12.h" -#include "class_55.h" -#include "class_31.h" -#include "class_66.h" -#include "class_28.h" -#include "class_68.h" -#include "class_16.h" -#include "class_98.h" -#include "class_46.h" -#include "class_97.h" -#include "class_86.h" -#include "class_40.h" -#include "class_52.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_7/class_4.h b/lib/waf/build/lib_7/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_40.cpp b/lib/waf/build/lib_7/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_72.h" -#include "class_54.h" -#include "class_61.h" -#include "class_76.h" -#include "class_38.h" -#include "class_30.h" -#include "class_1.h" -#include "class_75.h" -#include "class_78.h" -#include "class_42.h" -#include "class_47.h" -#include "class_69.h" -#include "class_88.h" -#include "class_36.h" -#include "class_65.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_7/class_40.h b/lib/waf/build/lib_7/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_41.cpp b/lib/waf/build/lib_7/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_19.h" -#include "class_94.h" -#include "class_80.h" -#include "class_57.h" -#include "class_96.h" -#include "class_2.h" -#include "class_3.h" -#include "class_6.h" -#include "class_4.h" -#include "class_33.h" -#include "class_5.h" -#include "class_65.h" -#include "class_28.h" -#include "class_90.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_7/class_41.h b/lib/waf/build/lib_7/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_42.cpp b/lib/waf/build/lib_7/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_13.h" -#include "class_71.h" -#include "class_9.h" -#include "class_7.h" -#include "class_36.h" -#include "class_87.h" -#include "class_50.h" -#include "class_18.h" -#include "class_40.h" -#include "class_46.h" -#include "class_39.h" -#include "class_22.h" -#include "class_96.h" -#include "class_29.h" -#include "class_95.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_7/class_42.h b/lib/waf/build/lib_7/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_43.cpp b/lib/waf/build/lib_7/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_3.h" -#include "class_78.h" -#include "class_51.h" -#include "class_17.h" -#include "class_13.h" -#include "class_75.h" -#include "class_34.h" -#include "class_63.h" -#include "class_42.h" -#include "class_89.h" -#include "class_35.h" -#include "class_55.h" -#include "class_73.h" -#include "class_5.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_7/class_43.h b/lib/waf/build/lib_7/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_44.cpp b/lib/waf/build/lib_7/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_3.h" -#include "class_46.h" -#include "class_62.h" -#include "class_24.h" -#include "class_69.h" -#include "class_85.h" -#include "class_26.h" -#include "class_33.h" -#include "class_50.h" -#include "class_82.h" -#include "class_29.h" -#include "class_93.h" -#include "class_57.h" -#include "class_99.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_7/class_44.h b/lib/waf/build/lib_7/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_45.cpp b/lib/waf/build/lib_7/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_59.h" -#include "class_41.h" -#include "class_2.h" -#include "class_89.h" -#include "class_49.h" -#include "class_86.h" -#include "class_81.h" -#include "class_28.h" -#include "class_60.h" -#include "class_83.h" -#include "class_67.h" -#include "class_45.h" -#include "class_17.h" -#include "class_8.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_7/class_45.h b/lib/waf/build/lib_7/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_46.cpp b/lib/waf/build/lib_7/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_77.h" -#include "class_80.h" -#include "class_37.h" -#include "class_75.h" -#include "class_74.h" -#include "class_89.h" -#include "class_71.h" -#include "class_88.h" -#include "class_18.h" -#include "class_98.h" -#include "class_28.h" -#include "class_78.h" -#include "class_79.h" -#include "class_48.h" -#include "class_91.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_7/class_46.h b/lib/waf/build/lib_7/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_47.cpp b/lib/waf/build/lib_7/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_11.h" -#include "class_87.h" -#include "class_3.h" -#include "class_51.h" -#include "class_61.h" -#include "class_7.h" -#include "class_40.h" -#include "class_88.h" -#include "class_74.h" -#include "class_70.h" -#include "class_52.h" -#include "class_20.h" -#include "class_94.h" -#include "class_76.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_7/class_47.h b/lib/waf/build/lib_7/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_48.cpp b/lib/waf/build/lib_7/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_5.h" -#include "class_39.h" -#include "class_57.h" -#include "class_17.h" -#include "class_79.h" -#include "class_77.h" -#include "class_96.h" -#include "class_18.h" -#include "class_38.h" -#include "class_76.h" -#include "class_40.h" -#include "class_44.h" -#include "class_64.h" -#include "class_43.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_7/class_48.h b/lib/waf/build/lib_7/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_49.cpp b/lib/waf/build/lib_7/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_19.h" -#include "class_73.h" -#include "class_52.h" -#include "class_46.h" -#include "class_39.h" -#include "class_87.h" -#include "class_79.h" -#include "class_74.h" -#include "class_67.h" -#include "class_51.h" -#include "class_55.h" -#include "class_28.h" -#include "class_18.h" -#include "class_49.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_7/class_49.h b/lib/waf/build/lib_7/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_5.cpp b/lib/waf/build/lib_7/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_63.h" -#include "class_70.h" -#include "class_3.h" -#include "class_37.h" -#include "class_23.h" -#include "class_35.h" -#include "class_0.h" -#include "class_43.h" -#include "class_67.h" -#include "class_27.h" -#include "class_60.h" -#include "class_40.h" -#include "class_89.h" -#include "class_69.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_7/class_5.h b/lib/waf/build/lib_7/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_50.cpp b/lib/waf/build/lib_7/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_14.h" -#include "class_66.h" -#include "class_20.h" -#include "class_88.h" -#include "class_78.h" -#include "class_92.h" -#include "class_49.h" -#include "class_94.h" -#include "class_32.h" -#include "class_79.h" -#include "class_72.h" -#include "class_29.h" -#include "class_97.h" -#include "class_70.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_7/class_50.h b/lib/waf/build/lib_7/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_51.cpp b/lib/waf/build/lib_7/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_15.h" -#include "class_37.h" -#include "class_30.h" -#include "class_91.h" -#include "class_56.h" -#include "class_26.h" -#include "class_78.h" -#include "class_66.h" -#include "class_28.h" -#include "class_14.h" -#include "class_59.h" -#include "class_9.h" -#include "class_32.h" -#include "class_29.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_7/class_51.h b/lib/waf/build/lib_7/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_52.cpp b/lib/waf/build/lib_7/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_60.h" -#include "class_68.h" -#include "class_55.h" -#include "class_7.h" -#include "class_59.h" -#include "class_47.h" -#include "class_99.h" -#include "class_96.h" -#include "class_51.h" -#include "class_87.h" -#include "class_75.h" -#include "class_98.h" -#include "class_50.h" -#include "class_89.h" -#include "class_82.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_7/class_52.h b/lib/waf/build/lib_7/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_53.cpp b/lib/waf/build/lib_7/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_71.h" -#include "class_37.h" -#include "class_2.h" -#include "class_79.h" -#include "class_68.h" -#include "class_28.h" -#include "class_97.h" -#include "class_88.h" -#include "class_73.h" -#include "class_1.h" -#include "class_90.h" -#include "class_50.h" -#include "class_89.h" -#include "class_53.h" -#include "class_6.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_7/class_53.h b/lib/waf/build/lib_7/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_54.cpp b/lib/waf/build/lib_7/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_36.h" -#include "class_63.h" -#include "class_51.h" -#include "class_32.h" -#include "class_28.h" -#include "class_70.h" -#include "class_40.h" -#include "class_62.h" -#include "class_25.h" -#include "class_91.h" -#include "class_97.h" -#include "class_75.h" -#include "class_52.h" -#include "class_29.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_7/class_54.h b/lib/waf/build/lib_7/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_55.cpp b/lib/waf/build/lib_7/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_60.h" -#include "class_79.h" -#include "class_53.h" -#include "class_38.h" -#include "class_77.h" -#include "class_74.h" -#include "class_13.h" -#include "class_41.h" -#include "class_72.h" -#include "class_99.h" -#include "class_4.h" -#include "class_73.h" -#include "class_18.h" -#include "class_5.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_7/class_55.h b/lib/waf/build/lib_7/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_56.cpp b/lib/waf/build/lib_7/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_26.h" -#include "class_57.h" -#include "class_72.h" -#include "class_79.h" -#include "class_1.h" -#include "class_56.h" -#include "class_28.h" -#include "class_58.h" -#include "class_48.h" -#include "class_4.h" -#include "class_99.h" -#include "class_77.h" -#include "class_68.h" -#include "class_92.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_7/class_56.h b/lib/waf/build/lib_7/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_57.cpp b/lib/waf/build/lib_7/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_93.h" -#include "class_33.h" -#include "class_41.h" -#include "class_95.h" -#include "class_90.h" -#include "class_11.h" -#include "class_79.h" -#include "class_78.h" -#include "class_25.h" -#include "class_70.h" -#include "class_99.h" -#include "class_21.h" -#include "class_76.h" -#include "class_96.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_7/class_57.h b/lib/waf/build/lib_7/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_58.cpp b/lib/waf/build/lib_7/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_54.h" -#include "class_38.h" -#include "class_39.h" -#include "class_41.h" -#include "class_35.h" -#include "class_96.h" -#include "class_52.h" -#include "class_71.h" -#include "class_29.h" -#include "class_14.h" -#include "class_72.h" -#include "class_61.h" -#include "class_22.h" -#include "class_5.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_7/class_58.h b/lib/waf/build/lib_7/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_59.cpp b/lib/waf/build/lib_7/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_21.h" -#include "class_9.h" -#include "class_66.h" -#include "class_80.h" -#include "class_10.h" -#include "class_68.h" -#include "class_72.h" -#include "class_23.h" -#include "class_29.h" -#include "class_32.h" -#include "class_3.h" -#include "class_12.h" -#include "class_78.h" -#include "class_54.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_7/class_59.h b/lib/waf/build/lib_7/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_6.cpp b/lib/waf/build/lib_7/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_11.h" -#include "class_73.h" -#include "class_45.h" -#include "class_37.h" -#include "class_14.h" -#include "class_52.h" -#include "class_38.h" -#include "class_47.h" -#include "class_50.h" -#include "class_21.h" -#include "class_2.h" -#include "class_3.h" -#include "class_82.h" -#include "class_49.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_7/class_6.h b/lib/waf/build/lib_7/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_60.cpp b/lib/waf/build/lib_7/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_84.h" -#include "class_21.h" -#include "class_74.h" -#include "class_22.h" -#include "class_89.h" -#include "class_88.h" -#include "class_77.h" -#include "class_66.h" -#include "class_71.h" -#include "class_9.h" -#include "class_30.h" -#include "class_50.h" -#include "class_59.h" -#include "class_17.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_7/class_60.h b/lib/waf/build/lib_7/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_61.cpp b/lib/waf/build/lib_7/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_0.h" -#include "class_39.h" -#include "class_85.h" -#include "class_3.h" -#include "class_78.h" -#include "class_59.h" -#include "class_82.h" -#include "class_87.h" -#include "class_64.h" -#include "class_5.h" -#include "class_51.h" -#include "class_68.h" -#include "class_84.h" -#include "class_18.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_7/class_61.h b/lib/waf/build/lib_7/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_62.cpp b/lib/waf/build/lib_7/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_53.h" -#include "class_41.h" -#include "class_38.h" -#include "class_27.h" -#include "class_10.h" -#include "class_15.h" -#include "class_82.h" -#include "class_54.h" -#include "class_51.h" -#include "class_16.h" -#include "class_86.h" -#include "class_93.h" -#include "class_64.h" -#include "class_19.h" -#include "class_65.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_7/class_62.h b/lib/waf/build/lib_7/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_63.cpp b/lib/waf/build/lib_7/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_70.h" -#include "class_13.h" -#include "class_54.h" -#include "class_69.h" -#include "class_58.h" -#include "class_30.h" -#include "class_52.h" -#include "class_66.h" -#include "class_80.h" -#include "class_33.h" -#include "class_56.h" -#include "class_36.h" -#include "class_10.h" -#include "class_21.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_7/class_63.h b/lib/waf/build/lib_7/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_64.cpp b/lib/waf/build/lib_7/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_59.h" -#include "class_75.h" -#include "class_92.h" -#include "class_72.h" -#include "class_17.h" -#include "class_43.h" -#include "class_8.h" -#include "class_5.h" -#include "class_80.h" -#include "class_36.h" -#include "class_86.h" -#include "class_93.h" -#include "class_60.h" -#include "class_23.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_7/class_64.h b/lib/waf/build/lib_7/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_65.cpp b/lib/waf/build/lib_7/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_0.h" -#include "class_37.h" -#include "class_78.h" -#include "class_24.h" -#include "class_4.h" -#include "class_22.h" -#include "class_3.h" -#include "class_27.h" -#include "class_49.h" -#include "class_26.h" -#include "class_23.h" -#include "class_96.h" -#include "class_64.h" -#include "class_50.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_7/class_65.h b/lib/waf/build/lib_7/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_66.cpp b/lib/waf/build/lib_7/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_21.h" -#include "class_70.h" -#include "class_56.h" -#include "class_19.h" -#include "class_11.h" -#include "class_81.h" -#include "class_36.h" -#include "class_78.h" -#include "class_49.h" -#include "class_92.h" -#include "class_22.h" -#include "class_67.h" -#include "class_52.h" -#include "class_16.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_7/class_66.h b/lib/waf/build/lib_7/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_67.cpp b/lib/waf/build/lib_7/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_75.h" -#include "class_42.h" -#include "class_57.h" -#include "class_60.h" -#include "class_78.h" -#include "class_83.h" -#include "class_26.h" -#include "class_70.h" -#include "class_46.h" -#include "class_89.h" -#include "class_5.h" -#include "class_0.h" -#include "class_47.h" -#include "class_8.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_7/class_67.h b/lib/waf/build/lib_7/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_68.cpp b/lib/waf/build/lib_7/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_99.h" -#include "class_71.h" -#include "class_51.h" -#include "class_83.h" -#include "class_57.h" -#include "class_33.h" -#include "class_63.h" -#include "class_53.h" -#include "class_54.h" -#include "class_24.h" -#include "class_75.h" -#include "class_73.h" -#include "class_35.h" -#include "class_85.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_7/class_68.h b/lib/waf/build/lib_7/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_69.cpp b/lib/waf/build/lib_7/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_70.h" -#include "class_84.h" -#include "class_34.h" -#include "class_20.h" -#include "class_96.h" -#include "class_29.h" -#include "class_50.h" -#include "class_32.h" -#include "class_45.h" -#include "class_64.h" -#include "class_33.h" -#include "class_1.h" -#include "class_39.h" -#include "class_49.h" -#include "class_38.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_7/class_69.h b/lib/waf/build/lib_7/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_7.cpp b/lib/waf/build/lib_7/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_54.h" -#include "class_24.h" -#include "class_81.h" -#include "class_69.h" -#include "class_36.h" -#include "class_84.h" -#include "class_34.h" -#include "class_43.h" -#include "class_40.h" -#include "class_80.h" -#include "class_1.h" -#include "class_99.h" -#include "class_42.h" -#include "class_57.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_7/class_7.h b/lib/waf/build/lib_7/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_70.cpp b/lib/waf/build/lib_7/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_99.h" -#include "class_63.h" -#include "class_89.h" -#include "class_75.h" -#include "class_33.h" -#include "class_29.h" -#include "class_26.h" -#include "class_79.h" -#include "class_46.h" -#include "class_0.h" -#include "class_77.h" -#include "class_54.h" -#include "class_59.h" -#include "class_65.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_7/class_70.h b/lib/waf/build/lib_7/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_71.cpp b/lib/waf/build/lib_7/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_38.h" -#include "class_2.h" -#include "class_67.h" -#include "class_14.h" -#include "class_5.h" -#include "class_77.h" -#include "class_1.h" -#include "class_79.h" -#include "class_84.h" -#include "class_35.h" -#include "class_21.h" -#include "class_83.h" -#include "class_40.h" -#include "class_33.h" -#include "class_10.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_7/class_71.h b/lib/waf/build/lib_7/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_72.cpp b/lib/waf/build/lib_7/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_25.h" -#include "class_84.h" -#include "class_40.h" -#include "class_44.h" -#include "class_45.h" -#include "class_91.h" -#include "class_42.h" -#include "class_4.h" -#include "class_88.h" -#include "class_35.h" -#include "class_29.h" -#include "class_54.h" -#include "class_10.h" -#include "class_83.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_7/class_72.h b/lib/waf/build/lib_7/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_73.cpp b/lib/waf/build/lib_7/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_76.h" -#include "class_42.h" -#include "class_69.h" -#include "class_32.h" -#include "class_85.h" -#include "class_70.h" -#include "class_13.h" -#include "class_64.h" -#include "class_27.h" -#include "class_75.h" -#include "class_3.h" -#include "class_59.h" -#include "class_39.h" -#include "class_94.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_7/class_73.h b/lib/waf/build/lib_7/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_74.cpp b/lib/waf/build/lib_7/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_75.h" -#include "class_22.h" -#include "class_94.h" -#include "class_61.h" -#include "class_33.h" -#include "class_49.h" -#include "class_76.h" -#include "class_77.h" -#include "class_37.h" -#include "class_16.h" -#include "class_5.h" -#include "class_62.h" -#include "class_90.h" -#include "class_35.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_7/class_74.h b/lib/waf/build/lib_7/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_75.cpp b/lib/waf/build/lib_7/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_7.h" -#include "class_36.h" -#include "class_53.h" -#include "class_58.h" -#include "class_79.h" -#include "class_60.h" -#include "class_73.h" -#include "class_64.h" -#include "class_26.h" -#include "class_5.h" -#include "class_71.h" -#include "class_42.h" -#include "class_19.h" -#include "class_49.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_7/class_75.h b/lib/waf/build/lib_7/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_76.cpp b/lib/waf/build/lib_7/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_42.h" -#include "class_58.h" -#include "class_41.h" -#include "class_92.h" -#include "class_73.h" -#include "class_53.h" -#include "class_9.h" -#include "class_89.h" -#include "class_51.h" -#include "class_33.h" -#include "class_70.h" -#include "class_50.h" -#include "class_45.h" -#include "class_71.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_7/class_76.h b/lib/waf/build/lib_7/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_77.cpp b/lib/waf/build/lib_7/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_74.h" -#include "class_58.h" -#include "class_3.h" -#include "class_11.h" -#include "class_43.h" -#include "class_89.h" -#include "class_88.h" -#include "class_46.h" -#include "class_16.h" -#include "class_49.h" -#include "class_4.h" -#include "class_77.h" -#include "class_65.h" -#include "class_94.h" -#include "class_41.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_7/class_77.h b/lib/waf/build/lib_7/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_78.cpp b/lib/waf/build/lib_7/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_32.h" -#include "class_30.h" -#include "class_52.h" -#include "class_47.h" -#include "class_16.h" -#include "class_48.h" -#include "class_10.h" -#include "class_58.h" -#include "class_77.h" -#include "class_41.h" -#include "class_90.h" -#include "class_19.h" -#include "class_74.h" -#include "class_56.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_7/class_78.h b/lib/waf/build/lib_7/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_79.cpp b/lib/waf/build/lib_7/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_77.h" -#include "class_84.h" -#include "class_12.h" -#include "class_17.h" -#include "class_65.h" -#include "class_13.h" -#include "class_4.h" -#include "class_92.h" -#include "class_63.h" -#include "class_26.h" -#include "class_64.h" -#include "class_39.h" -#include "class_38.h" -#include "class_10.h" -#include "class_93.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_7/class_79.h b/lib/waf/build/lib_7/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_8.cpp b/lib/waf/build/lib_7/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_29.h" -#include "class_34.h" -#include "class_68.h" -#include "class_61.h" -#include "class_30.h" -#include "class_1.h" -#include "class_84.h" -#include "class_57.h" -#include "class_99.h" -#include "class_49.h" -#include "class_36.h" -#include "class_85.h" -#include "class_10.h" -#include "class_17.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_7/class_8.h b/lib/waf/build/lib_7/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_80.cpp b/lib/waf/build/lib_7/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_9.h" -#include "class_41.h" -#include "class_85.h" -#include "class_60.h" -#include "class_52.h" -#include "class_49.h" -#include "class_30.h" -#include "class_80.h" -#include "class_54.h" -#include "class_21.h" -#include "class_75.h" -#include "class_91.h" -#include "class_38.h" -#include "class_27.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_7/class_80.h b/lib/waf/build/lib_7/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_81.cpp b/lib/waf/build/lib_7/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_21.h" -#include "class_54.h" -#include "class_40.h" -#include "class_3.h" -#include "class_33.h" -#include "class_98.h" -#include "class_26.h" -#include "class_22.h" -#include "class_7.h" -#include "class_81.h" -#include "class_50.h" -#include "class_79.h" -#include "class_66.h" -#include "class_10.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_7/class_81.h b/lib/waf/build/lib_7/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_82.cpp b/lib/waf/build/lib_7/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_42.h" -#include "class_47.h" -#include "class_27.h" -#include "class_4.h" -#include "class_62.h" -#include "class_76.h" -#include "class_10.h" -#include "class_31.h" -#include "class_25.h" -#include "class_13.h" -#include "class_73.h" -#include "class_6.h" -#include "class_12.h" -#include "class_39.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_7/class_82.h b/lib/waf/build/lib_7/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_83.cpp b/lib/waf/build/lib_7/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_6.h" -#include "class_17.h" -#include "class_43.h" -#include "class_5.h" -#include "class_27.h" -#include "class_65.h" -#include "class_88.h" -#include "class_67.h" -#include "class_25.h" -#include "class_40.h" -#include "class_73.h" -#include "class_15.h" -#include "class_99.h" -#include "class_26.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_7/class_83.h b/lib/waf/build/lib_7/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_84.cpp b/lib/waf/build/lib_7/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_39.h" -#include "class_32.h" -#include "class_70.h" -#include "class_23.h" -#include "class_98.h" -#include "class_76.h" -#include "class_75.h" -#include "class_12.h" -#include "class_58.h" -#include "class_51.h" -#include "class_64.h" -#include "class_84.h" -#include "class_67.h" -#include "class_11.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_7/class_84.h b/lib/waf/build/lib_7/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_85.cpp b/lib/waf/build/lib_7/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_25.h" -#include "class_33.h" -#include "class_34.h" -#include "class_4.h" -#include "class_93.h" -#include "class_46.h" -#include "class_2.h" -#include "class_58.h" -#include "class_83.h" -#include "class_98.h" -#include "class_57.h" -#include "class_82.h" -#include "class_17.h" -#include "class_77.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_7/class_85.h b/lib/waf/build/lib_7/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_86.cpp b/lib/waf/build/lib_7/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_57.h" -#include "class_25.h" -#include "class_26.h" -#include "class_33.h" -#include "class_63.h" -#include "class_91.h" -#include "class_38.h" -#include "class_61.h" -#include "class_27.h" -#include "class_92.h" -#include "class_43.h" -#include "class_4.h" -#include "class_7.h" -#include "class_30.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_7/class_86.h b/lib/waf/build/lib_7/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_87.cpp b/lib/waf/build/lib_7/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_27.h" -#include "class_76.h" -#include "class_24.h" -#include "class_25.h" -#include "class_4.h" -#include "class_83.h" -#include "class_58.h" -#include "class_9.h" -#include "class_52.h" -#include "class_92.h" -#include "class_26.h" -#include "class_60.h" -#include "class_18.h" -#include "class_33.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_7/class_87.h b/lib/waf/build/lib_7/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_88.cpp b/lib/waf/build/lib_7/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_44.h" -#include "class_83.h" -#include "class_28.h" -#include "class_3.h" -#include "class_45.h" -#include "class_93.h" -#include "class_10.h" -#include "class_86.h" -#include "class_50.h" -#include "class_51.h" -#include "class_18.h" -#include "class_84.h" -#include "class_77.h" -#include "class_82.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_7/class_88.h b/lib/waf/build/lib_7/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_89.cpp b/lib/waf/build/lib_7/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_26.h" -#include "class_90.h" -#include "class_44.h" -#include "class_70.h" -#include "class_11.h" -#include "class_13.h" -#include "class_62.h" -#include "class_49.h" -#include "class_61.h" -#include "class_65.h" -#include "class_31.h" -#include "class_52.h" -#include "class_3.h" -#include "class_87.h" -#include "class_14.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_7/class_89.h b/lib/waf/build/lib_7/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_9.cpp b/lib/waf/build/lib_7/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_51.h" -#include "class_21.h" -#include "class_50.h" -#include "class_92.h" -#include "class_78.h" -#include "class_4.h" -#include "class_88.h" -#include "class_35.h" -#include "class_14.h" -#include "class_82.h" -#include "class_95.h" -#include "class_1.h" -#include "class_69.h" -#include "class_74.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_7/class_9.h b/lib/waf/build/lib_7/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_90.cpp b/lib/waf/build/lib_7/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_83.h" -#include "class_81.h" -#include "class_66.h" -#include "class_3.h" -#include "class_5.h" -#include "class_9.h" -#include "class_69.h" -#include "class_62.h" -#include "class_27.h" -#include "class_40.h" -#include "class_20.h" -#include "class_25.h" -#include "class_65.h" -#include "class_16.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_7/class_90.h b/lib/waf/build/lib_7/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_91.cpp b/lib/waf/build/lib_7/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_22.h" -#include "class_49.h" -#include "class_96.h" -#include "class_80.h" -#include "class_30.h" -#include "class_93.h" -#include "class_50.h" -#include "class_56.h" -#include "class_61.h" -#include "class_18.h" -#include "class_60.h" -#include "class_23.h" -#include "class_35.h" -#include "class_53.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_7/class_91.h b/lib/waf/build/lib_7/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_92.cpp b/lib/waf/build/lib_7/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_36.h" -#include "class_14.h" -#include "class_92.h" -#include "class_56.h" -#include "class_1.h" -#include "class_67.h" -#include "class_79.h" -#include "class_49.h" -#include "class_54.h" -#include "class_16.h" -#include "class_87.h" -#include "class_32.h" -#include "class_70.h" -#include "class_6.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_7/class_92.h b/lib/waf/build/lib_7/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_93.cpp b/lib/waf/build/lib_7/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_60.h" -#include "class_11.h" -#include "class_96.h" -#include "class_68.h" -#include "class_67.h" -#include "class_35.h" -#include "class_64.h" -#include "class_18.h" -#include "class_41.h" -#include "class_61.h" -#include "class_82.h" -#include "class_77.h" -#include "class_72.h" -#include "class_80.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_7/class_93.h b/lib/waf/build/lib_7/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_94.cpp b/lib/waf/build/lib_7/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_41.h" -#include "class_73.h" -#include "class_16.h" -#include "class_88.h" -#include "class_4.h" -#include "class_47.h" -#include "class_8.h" -#include "class_18.h" -#include "class_60.h" -#include "class_93.h" -#include "class_2.h" -#include "class_45.h" -#include "class_84.h" -#include "class_11.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_7/class_94.h b/lib/waf/build/lib_7/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_95.cpp b/lib/waf/build/lib_7/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_92.h" -#include "class_36.h" -#include "class_43.h" -#include "class_52.h" -#include "class_67.h" -#include "class_64.h" -#include "class_18.h" -#include "class_8.h" -#include "class_21.h" -#include "class_12.h" -#include "class_48.h" -#include "class_14.h" -#include "class_94.h" -#include "class_31.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_7/class_95.h b/lib/waf/build/lib_7/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_96.cpp b/lib/waf/build/lib_7/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_66.h" -#include "class_12.h" -#include "class_78.h" -#include "class_65.h" -#include "class_58.h" -#include "class_88.h" -#include "class_74.h" -#include "class_91.h" -#include "class_4.h" -#include "class_11.h" -#include "class_36.h" -#include "class_23.h" -#include "class_82.h" -#include "class_64.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_7/class_96.h b/lib/waf/build/lib_7/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_97.cpp b/lib/waf/build/lib_7/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_87.h" -#include "class_82.h" -#include "class_42.h" -#include "class_10.h" -#include "class_7.h" -#include "class_39.h" -#include "class_30.h" -#include "class_75.h" -#include "class_70.h" -#include "class_48.h" -#include "class_98.h" -#include "class_21.h" -#include "class_72.h" -#include "class_27.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_7/class_97.h b/lib/waf/build/lib_7/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_98.cpp b/lib/waf/build/lib_7/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_57.h" -#include "class_83.h" -#include "class_17.h" -#include "class_88.h" -#include "class_40.h" -#include "class_89.h" -#include "class_27.h" -#include "class_68.h" -#include "class_16.h" -#include "class_76.h" -#include "class_12.h" -#include "class_41.h" -#include "class_20.h" -#include "class_97.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_7/class_98.h b/lib/waf/build/lib_7/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_7/class_99.cpp b/lib/waf/build/lib_7/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_7/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_1.h" -#include "class_20.h" -#include "class_41.h" -#include "class_63.h" -#include "class_26.h" -#include "class_15.h" -#include "class_67.h" -#include "class_34.h" -#include "class_65.h" -#include "class_80.h" -#include "class_33.h" -#include "class_79.h" -#include "class_22.h" -#include "class_24.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_7/class_99.h b/lib/waf/build/lib_7/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_7/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_8/Makefile b/lib/waf/build/lib_8/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_8/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_8.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_8/Makefile.am b/lib/waf/build/lib_8/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_8/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib8.la -lib8_la_SOURCES = lib_8/class_0.cpp lib_8/class_1.cpp lib_8/class_2.cpp lib_8/class_3.cpp lib_8/class_4.cpp lib_8/class_5.cpp lib_8/class_6.cpp lib_8/class_7.cpp lib_8/class_8.cpp lib_8/class_9.cpp lib_8/class_10.cpp lib_8/class_11.cpp lib_8/class_12.cpp lib_8/class_13.cpp lib_8/class_14.cpp lib_8/class_15.cpp lib_8/class_16.cpp lib_8/class_17.cpp lib_8/class_18.cpp lib_8/class_19.cpp lib_8/class_20.cpp lib_8/class_21.cpp lib_8/class_22.cpp lib_8/class_23.cpp lib_8/class_24.cpp lib_8/class_25.cpp lib_8/class_26.cpp lib_8/class_27.cpp lib_8/class_28.cpp lib_8/class_29.cpp lib_8/class_30.cpp lib_8/class_31.cpp lib_8/class_32.cpp lib_8/class_33.cpp lib_8/class_34.cpp lib_8/class_35.cpp lib_8/class_36.cpp lib_8/class_37.cpp lib_8/class_38.cpp lib_8/class_39.cpp lib_8/class_40.cpp lib_8/class_41.cpp lib_8/class_42.cpp lib_8/class_43.cpp lib_8/class_44.cpp lib_8/class_45.cpp lib_8/class_46.cpp lib_8/class_47.cpp lib_8/class_48.cpp lib_8/class_49.cpp lib_8/class_50.cpp lib_8/class_51.cpp lib_8/class_52.cpp lib_8/class_53.cpp lib_8/class_54.cpp lib_8/class_55.cpp lib_8/class_56.cpp lib_8/class_57.cpp lib_8/class_58.cpp lib_8/class_59.cpp lib_8/class_60.cpp lib_8/class_61.cpp lib_8/class_62.cpp lib_8/class_63.cpp lib_8/class_64.cpp lib_8/class_65.cpp lib_8/class_66.cpp lib_8/class_67.cpp lib_8/class_68.cpp lib_8/class_69.cpp lib_8/class_70.cpp lib_8/class_71.cpp lib_8/class_72.cpp lib_8/class_73.cpp lib_8/class_74.cpp lib_8/class_75.cpp lib_8/class_76.cpp lib_8/class_77.cpp lib_8/class_78.cpp lib_8/class_79.cpp lib_8/class_80.cpp lib_8/class_81.cpp lib_8/class_82.cpp lib_8/class_83.cpp lib_8/class_84.cpp lib_8/class_85.cpp lib_8/class_86.cpp lib_8/class_87.cpp lib_8/class_88.cpp lib_8/class_89.cpp lib_8/class_90.cpp lib_8/class_91.cpp lib_8/class_92.cpp lib_8/class_93.cpp lib_8/class_94.cpp lib_8/class_95.cpp lib_8/class_96.cpp lib_8/class_97.cpp lib_8/class_98.cpp lib_8/class_99.cpp diff --git a/lib/waf/build/lib_8/SConscript b/lib/waf/build/lib_8/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_8/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_8", list) - diff --git a/lib/waf/build/lib_8/class_0.cpp b/lib/waf/build/lib_8/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_38.h" -#include "class_4.h" -#include "class_99.h" -#include "class_33.h" -#include "class_63.h" -#include "class_6.h" -#include "class_29.h" -#include "class_48.h" -#include "class_75.h" -#include "class_35.h" -#include "class_87.h" -#include "class_92.h" -#include "class_86.h" -#include "class_58.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_8/class_0.h b/lib/waf/build/lib_8/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_1.cpp b/lib/waf/build/lib_8/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_25.h" -#include "class_38.h" -#include "class_21.h" -#include "class_70.h" -#include "class_69.h" -#include "class_42.h" -#include "class_29.h" -#include "class_90.h" -#include "class_33.h" -#include "class_52.h" -#include "class_54.h" -#include "class_46.h" -#include "class_19.h" -#include "class_75.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_8/class_1.h b/lib/waf/build/lib_8/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_10.cpp b/lib/waf/build/lib_8/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_60.h" -#include "class_15.h" -#include "class_66.h" -#include "class_98.h" -#include "class_70.h" -#include "class_56.h" -#include "class_51.h" -#include "class_6.h" -#include "class_92.h" -#include "class_85.h" -#include "class_2.h" -#include "class_17.h" -#include "class_80.h" -#include "class_63.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_8/class_10.h b/lib/waf/build/lib_8/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_11.cpp b/lib/waf/build/lib_8/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_37.h" -#include "class_52.h" -#include "class_62.h" -#include "class_0.h" -#include "class_22.h" -#include "class_65.h" -#include "class_76.h" -#include "class_94.h" -#include "class_80.h" -#include "class_95.h" -#include "class_23.h" -#include "class_58.h" -#include "class_11.h" -#include "class_60.h" -#include "class_24.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_8/class_11.h b/lib/waf/build/lib_8/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_12.cpp b/lib/waf/build/lib_8/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_57.h" -#include "class_19.h" -#include "class_87.h" -#include "class_60.h" -#include "class_8.h" -#include "class_77.h" -#include "class_26.h" -#include "class_56.h" -#include "class_34.h" -#include "class_70.h" -#include "class_16.h" -#include "class_20.h" -#include "class_79.h" -#include "class_27.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_8/class_12.h b/lib/waf/build/lib_8/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_13.cpp b/lib/waf/build/lib_8/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_26.h" -#include "class_92.h" -#include "class_21.h" -#include "class_48.h" -#include "class_75.h" -#include "class_28.h" -#include "class_64.h" -#include "class_1.h" -#include "class_83.h" -#include "class_86.h" -#include "class_76.h" -#include "class_82.h" -#include "class_89.h" -#include "class_72.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_8/class_13.h b/lib/waf/build/lib_8/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_14.cpp b/lib/waf/build/lib_8/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_58.h" -#include "class_52.h" -#include "class_2.h" -#include "class_30.h" -#include "class_88.h" -#include "class_8.h" -#include "class_78.h" -#include "class_68.h" -#include "class_6.h" -#include "class_41.h" -#include "class_46.h" -#include "class_91.h" -#include "class_53.h" -#include "class_54.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_8/class_14.h b/lib/waf/build/lib_8/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_15.cpp b/lib/waf/build/lib_8/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_5.h" -#include "class_94.h" -#include "class_3.h" -#include "class_14.h" -#include "class_50.h" -#include "class_92.h" -#include "class_77.h" -#include "class_22.h" -#include "class_66.h" -#include "class_13.h" -#include "class_12.h" -#include "class_47.h" -#include "class_46.h" -#include "class_75.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_8/class_15.h b/lib/waf/build/lib_8/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_16.cpp b/lib/waf/build/lib_8/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_12.h" -#include "class_74.h" -#include "class_24.h" -#include "class_85.h" -#include "class_44.h" -#include "class_37.h" -#include "class_90.h" -#include "class_69.h" -#include "class_43.h" -#include "class_49.h" -#include "class_93.h" -#include "class_32.h" -#include "class_86.h" -#include "class_71.h" -#include "class_80.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_8/class_16.h b/lib/waf/build/lib_8/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_17.cpp b/lib/waf/build/lib_8/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_7.h" -#include "class_51.h" -#include "class_80.h" -#include "class_8.h" -#include "class_41.h" -#include "class_86.h" -#include "class_82.h" -#include "class_30.h" -#include "class_55.h" -#include "class_68.h" -#include "class_70.h" -#include "class_76.h" -#include "class_34.h" -#include "class_6.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_8/class_17.h b/lib/waf/build/lib_8/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_18.cpp b/lib/waf/build/lib_8/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_74.h" -#include "class_45.h" -#include "class_52.h" -#include "class_65.h" -#include "class_60.h" -#include "class_46.h" -#include "class_75.h" -#include "class_36.h" -#include "class_97.h" -#include "class_44.h" -#include "class_28.h" -#include "class_64.h" -#include "class_84.h" -#include "class_86.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_8/class_18.h b/lib/waf/build/lib_8/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_19.cpp b/lib/waf/build/lib_8/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_67.h" -#include "class_73.h" -#include "class_27.h" -#include "class_77.h" -#include "class_37.h" -#include "class_47.h" -#include "class_23.h" -#include "class_62.h" -#include "class_10.h" -#include "class_57.h" -#include "class_33.h" -#include "class_54.h" -#include "class_48.h" -#include "class_71.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_8/class_19.h b/lib/waf/build/lib_8/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_2.cpp b/lib/waf/build/lib_8/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_1.h" -#include "class_4.h" -#include "class_37.h" -#include "class_40.h" -#include "class_48.h" -#include "class_16.h" -#include "class_66.h" -#include "class_7.h" -#include "class_30.h" -#include "class_44.h" -#include "class_38.h" -#include "class_46.h" -#include "class_36.h" -#include "class_70.h" -#include "class_10.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_8/class_2.h b/lib/waf/build/lib_8/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_20.cpp b/lib/waf/build/lib_8/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_17.h" -#include "class_9.h" -#include "class_34.h" -#include "class_90.h" -#include "class_54.h" -#include "class_25.h" -#include "class_74.h" -#include "class_4.h" -#include "class_33.h" -#include "class_91.h" -#include "class_26.h" -#include "class_75.h" -#include "class_63.h" -#include "class_58.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_8/class_20.h b/lib/waf/build/lib_8/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_21.cpp b/lib/waf/build/lib_8/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_58.h" -#include "class_3.h" -#include "class_90.h" -#include "class_81.h" -#include "class_43.h" -#include "class_5.h" -#include "class_95.h" -#include "class_49.h" -#include "class_67.h" -#include "class_86.h" -#include "class_12.h" -#include "class_82.h" -#include "class_70.h" -#include "class_61.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_8/class_21.h b/lib/waf/build/lib_8/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_22.cpp b/lib/waf/build/lib_8/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_32.h" -#include "class_39.h" -#include "class_36.h" -#include "class_81.h" -#include "class_24.h" -#include "class_76.h" -#include "class_85.h" -#include "class_7.h" -#include "class_26.h" -#include "class_8.h" -#include "class_62.h" -#include "class_2.h" -#include "class_41.h" -#include "class_58.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_8/class_22.h b/lib/waf/build/lib_8/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_23.cpp b/lib/waf/build/lib_8/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_97.h" -#include "class_6.h" -#include "class_12.h" -#include "class_53.h" -#include "class_75.h" -#include "class_94.h" -#include "class_27.h" -#include "class_57.h" -#include "class_32.h" -#include "class_86.h" -#include "class_52.h" -#include "class_61.h" -#include "class_16.h" -#include "class_98.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_8/class_23.h b/lib/waf/build/lib_8/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_24.cpp b/lib/waf/build/lib_8/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_47.h" -#include "class_76.h" -#include "class_4.h" -#include "class_91.h" -#include "class_85.h" -#include "class_82.h" -#include "class_78.h" -#include "class_45.h" -#include "class_57.h" -#include "class_84.h" -#include "class_25.h" -#include "class_1.h" -#include "class_49.h" -#include "class_63.h" -#include "class_75.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_8/class_24.h b/lib/waf/build/lib_8/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_25.cpp b/lib/waf/build/lib_8/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_54.h" -#include "class_64.h" -#include "class_74.h" -#include "class_3.h" -#include "class_83.h" -#include "class_95.h" -#include "class_51.h" -#include "class_25.h" -#include "class_89.h" -#include "class_49.h" -#include "class_79.h" -#include "class_60.h" -#include "class_92.h" -#include "class_90.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_8/class_25.h b/lib/waf/build/lib_8/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_26.cpp b/lib/waf/build/lib_8/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_86.h" -#include "class_73.h" -#include "class_62.h" -#include "class_85.h" -#include "class_68.h" -#include "class_12.h" -#include "class_15.h" -#include "class_55.h" -#include "class_37.h" -#include "class_56.h" -#include "class_30.h" -#include "class_11.h" -#include "class_51.h" -#include "class_91.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_8/class_26.h b/lib/waf/build/lib_8/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_27.cpp b/lib/waf/build/lib_8/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_69.h" -#include "class_23.h" -#include "class_55.h" -#include "class_50.h" -#include "class_64.h" -#include "class_62.h" -#include "class_52.h" -#include "class_89.h" -#include "class_79.h" -#include "class_27.h" -#include "class_29.h" -#include "class_54.h" -#include "class_58.h" -#include "class_15.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_8/class_27.h b/lib/waf/build/lib_8/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_28.cpp b/lib/waf/build/lib_8/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_23.h" -#include "class_15.h" -#include "class_24.h" -#include "class_64.h" -#include "class_44.h" -#include "class_61.h" -#include "class_91.h" -#include "class_7.h" -#include "class_72.h" -#include "class_51.h" -#include "class_58.h" -#include "class_88.h" -#include "class_93.h" -#include "class_52.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_8/class_28.h b/lib/waf/build/lib_8/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_29.cpp b/lib/waf/build/lib_8/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_7.h" -#include "class_28.h" -#include "class_57.h" -#include "class_87.h" -#include "class_14.h" -#include "class_3.h" -#include "class_0.h" -#include "class_97.h" -#include "class_17.h" -#include "class_55.h" -#include "class_35.h" -#include "class_19.h" -#include "class_74.h" -#include "class_46.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_8/class_29.h b/lib/waf/build/lib_8/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_3.cpp b/lib/waf/build/lib_8/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_30.h" -#include "class_5.h" -#include "class_41.h" -#include "class_86.h" -#include "class_66.h" -#include "class_74.h" -#include "class_54.h" -#include "class_3.h" -#include "class_60.h" -#include "class_48.h" -#include "class_0.h" -#include "class_62.h" -#include "class_77.h" -#include "class_73.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_8/class_3.h b/lib/waf/build/lib_8/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_30.cpp b/lib/waf/build/lib_8/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_33.h" -#include "class_6.h" -#include "class_1.h" -#include "class_56.h" -#include "class_34.h" -#include "class_37.h" -#include "class_44.h" -#include "class_57.h" -#include "class_36.h" -#include "class_47.h" -#include "class_25.h" -#include "class_81.h" -#include "class_5.h" -#include "class_87.h" -#include "class_49.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_8/class_30.h b/lib/waf/build/lib_8/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_31.cpp b/lib/waf/build/lib_8/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_62.h" -#include "class_86.h" -#include "class_71.h" -#include "class_32.h" -#include "class_60.h" -#include "class_0.h" -#include "class_92.h" -#include "class_39.h" -#include "class_77.h" -#include "class_6.h" -#include "class_50.h" -#include "class_2.h" -#include "class_9.h" -#include "class_20.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_8/class_31.h b/lib/waf/build/lib_8/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_32.cpp b/lib/waf/build/lib_8/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_43.h" -#include "class_15.h" -#include "class_2.h" -#include "class_54.h" -#include "class_0.h" -#include "class_5.h" -#include "class_25.h" -#include "class_99.h" -#include "class_46.h" -#include "class_16.h" -#include "class_60.h" -#include "class_45.h" -#include "class_69.h" -#include "class_59.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_8/class_32.h b/lib/waf/build/lib_8/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_33.cpp b/lib/waf/build/lib_8/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_26.h" -#include "class_17.h" -#include "class_20.h" -#include "class_22.h" -#include "class_18.h" -#include "class_95.h" -#include "class_45.h" -#include "class_33.h" -#include "class_55.h" -#include "class_80.h" -#include "class_23.h" -#include "class_59.h" -#include "class_83.h" -#include "class_43.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_8/class_33.h b/lib/waf/build/lib_8/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_34.cpp b/lib/waf/build/lib_8/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_89.h" -#include "class_93.h" -#include "class_11.h" -#include "class_2.h" -#include "class_38.h" -#include "class_30.h" -#include "class_9.h" -#include "class_77.h" -#include "class_50.h" -#include "class_92.h" -#include "class_96.h" -#include "class_26.h" -#include "class_80.h" -#include "class_65.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_8/class_34.h b/lib/waf/build/lib_8/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_35.cpp b/lib/waf/build/lib_8/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_9.h" -#include "class_48.h" -#include "class_10.h" -#include "class_77.h" -#include "class_95.h" -#include "class_29.h" -#include "class_62.h" -#include "class_11.h" -#include "class_15.h" -#include "class_34.h" -#include "class_17.h" -#include "class_41.h" -#include "class_65.h" -#include "class_2.h" -#include "class_28.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_8/class_35.h b/lib/waf/build/lib_8/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_36.cpp b/lib/waf/build/lib_8/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_13.h" -#include "class_97.h" -#include "class_79.h" -#include "class_38.h" -#include "class_32.h" -#include "class_41.h" -#include "class_31.h" -#include "class_77.h" -#include "class_37.h" -#include "class_86.h" -#include "class_21.h" -#include "class_39.h" -#include "class_78.h" -#include "class_55.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_8/class_36.h b/lib/waf/build/lib_8/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_37.cpp b/lib/waf/build/lib_8/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_30.h" -#include "class_17.h" -#include "class_10.h" -#include "class_72.h" -#include "class_1.h" -#include "class_69.h" -#include "class_50.h" -#include "class_58.h" -#include "class_61.h" -#include "class_80.h" -#include "class_67.h" -#include "class_41.h" -#include "class_0.h" -#include "class_93.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_8/class_37.h b/lib/waf/build/lib_8/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_38.cpp b/lib/waf/build/lib_8/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_39.h" -#include "class_84.h" -#include "class_72.h" -#include "class_69.h" -#include "class_17.h" -#include "class_11.h" -#include "class_59.h" -#include "class_33.h" -#include "class_73.h" -#include "class_47.h" -#include "class_3.h" -#include "class_21.h" -#include "class_82.h" -#include "class_65.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_8/class_38.h b/lib/waf/build/lib_8/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_39.cpp b/lib/waf/build/lib_8/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_71.h" -#include "class_30.h" -#include "class_42.h" -#include "class_35.h" -#include "class_63.h" -#include "class_61.h" -#include "class_90.h" -#include "class_3.h" -#include "class_78.h" -#include "class_79.h" -#include "class_96.h" -#include "class_52.h" -#include "class_19.h" -#include "class_8.h" -#include "class_7.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_8/class_39.h b/lib/waf/build/lib_8/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_4.cpp b/lib/waf/build/lib_8/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_8.h" -#include "class_31.h" -#include "class_9.h" -#include "class_3.h" -#include "class_84.h" -#include "class_41.h" -#include "class_51.h" -#include "class_13.h" -#include "class_93.h" -#include "class_21.h" -#include "class_73.h" -#include "class_20.h" -#include "class_42.h" -#include "class_46.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_8/class_4.h b/lib/waf/build/lib_8/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_40.cpp b/lib/waf/build/lib_8/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_53.h" -#include "class_28.h" -#include "class_74.h" -#include "class_40.h" -#include "class_68.h" -#include "class_94.h" -#include "class_55.h" -#include "class_23.h" -#include "class_2.h" -#include "class_87.h" -#include "class_17.h" -#include "class_51.h" -#include "class_79.h" -#include "class_70.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_8/class_40.h b/lib/waf/build/lib_8/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_41.cpp b/lib/waf/build/lib_8/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_64.h" -#include "class_44.h" -#include "class_62.h" -#include "class_78.h" -#include "class_17.h" -#include "class_61.h" -#include "class_88.h" -#include "class_28.h" -#include "class_35.h" -#include "class_51.h" -#include "class_0.h" -#include "class_7.h" -#include "class_85.h" -#include "class_80.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_8/class_41.h b/lib/waf/build/lib_8/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_42.cpp b/lib/waf/build/lib_8/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_9.h" -#include "class_43.h" -#include "class_16.h" -#include "class_35.h" -#include "class_95.h" -#include "class_63.h" -#include "class_70.h" -#include "class_50.h" -#include "class_27.h" -#include "class_58.h" -#include "class_8.h" -#include "class_99.h" -#include "class_54.h" -#include "class_25.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_8/class_42.h b/lib/waf/build/lib_8/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_43.cpp b/lib/waf/build/lib_8/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_33.h" -#include "class_7.h" -#include "class_27.h" -#include "class_45.h" -#include "class_42.h" -#include "class_67.h" -#include "class_68.h" -#include "class_44.h" -#include "class_17.h" -#include "class_39.h" -#include "class_81.h" -#include "class_30.h" -#include "class_79.h" -#include "class_57.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_8/class_43.h b/lib/waf/build/lib_8/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_44.cpp b/lib/waf/build/lib_8/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_55.h" -#include "class_30.h" -#include "class_24.h" -#include "class_64.h" -#include "class_16.h" -#include "class_27.h" -#include "class_37.h" -#include "class_73.h" -#include "class_96.h" -#include "class_28.h" -#include "class_33.h" -#include "class_81.h" -#include "class_15.h" -#include "class_58.h" -#include "class_42.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_8/class_44.h b/lib/waf/build/lib_8/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_45.cpp b/lib/waf/build/lib_8/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_64.h" -#include "class_34.h" -#include "class_86.h" -#include "class_51.h" -#include "class_7.h" -#include "class_97.h" -#include "class_29.h" -#include "class_32.h" -#include "class_73.h" -#include "class_61.h" -#include "class_54.h" -#include "class_50.h" -#include "class_49.h" -#include "class_14.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_8/class_45.h b/lib/waf/build/lib_8/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_46.cpp b/lib/waf/build/lib_8/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_22.h" -#include "class_31.h" -#include "class_80.h" -#include "class_65.h" -#include "class_27.h" -#include "class_99.h" -#include "class_37.h" -#include "class_83.h" -#include "class_81.h" -#include "class_18.h" -#include "class_90.h" -#include "class_19.h" -#include "class_54.h" -#include "class_36.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_8/class_46.h b/lib/waf/build/lib_8/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_47.cpp b/lib/waf/build/lib_8/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_91.h" -#include "class_33.h" -#include "class_98.h" -#include "class_14.h" -#include "class_28.h" -#include "class_26.h" -#include "class_53.h" -#include "class_22.h" -#include "class_35.h" -#include "class_85.h" -#include "class_11.h" -#include "class_63.h" -#include "class_76.h" -#include "class_67.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_8/class_47.h b/lib/waf/build/lib_8/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_48.cpp b/lib/waf/build/lib_8/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_5.h" -#include "class_38.h" -#include "class_32.h" -#include "class_12.h" -#include "class_13.h" -#include "class_3.h" -#include "class_44.h" -#include "class_59.h" -#include "class_90.h" -#include "class_45.h" -#include "class_15.h" -#include "class_30.h" -#include "class_11.h" -#include "class_46.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_8/class_48.h b/lib/waf/build/lib_8/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_49.cpp b/lib/waf/build/lib_8/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_40.h" -#include "class_58.h" -#include "class_48.h" -#include "class_22.h" -#include "class_6.h" -#include "class_55.h" -#include "class_79.h" -#include "class_19.h" -#include "class_17.h" -#include "class_15.h" -#include "class_1.h" -#include "class_39.h" -#include "class_77.h" -#include "class_64.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_8/class_49.h b/lib/waf/build/lib_8/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_5.cpp b/lib/waf/build/lib_8/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_9.h" -#include "class_14.h" -#include "class_24.h" -#include "class_96.h" -#include "class_25.h" -#include "class_30.h" -#include "class_60.h" -#include "class_51.h" -#include "class_53.h" -#include "class_2.h" -#include "class_22.h" -#include "class_90.h" -#include "class_23.h" -#include "class_93.h" -#include "class_67.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_8/class_5.h b/lib/waf/build/lib_8/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_50.cpp b/lib/waf/build/lib_8/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_75.h" -#include "class_69.h" -#include "class_40.h" -#include "class_30.h" -#include "class_19.h" -#include "class_11.h" -#include "class_61.h" -#include "class_34.h" -#include "class_91.h" -#include "class_23.h" -#include "class_74.h" -#include "class_71.h" -#include "class_79.h" -#include "class_0.h" -#include "class_7.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_8/class_50.h b/lib/waf/build/lib_8/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_51.cpp b/lib/waf/build/lib_8/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_8.h" -#include "class_81.h" -#include "class_3.h" -#include "class_21.h" -#include "class_26.h" -#include "class_79.h" -#include "class_25.h" -#include "class_82.h" -#include "class_83.h" -#include "class_11.h" -#include "class_67.h" -#include "class_10.h" -#include "class_4.h" -#include "class_52.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_8/class_51.h b/lib/waf/build/lib_8/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_52.cpp b/lib/waf/build/lib_8/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_68.h" -#include "class_70.h" -#include "class_9.h" -#include "class_67.h" -#include "class_45.h" -#include "class_20.h" -#include "class_87.h" -#include "class_69.h" -#include "class_13.h" -#include "class_44.h" -#include "class_50.h" -#include "class_17.h" -#include "class_14.h" -#include "class_54.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_8/class_52.h b/lib/waf/build/lib_8/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_53.cpp b/lib/waf/build/lib_8/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_28.h" -#include "class_46.h" -#include "class_48.h" -#include "class_38.h" -#include "class_84.h" -#include "class_69.h" -#include "class_71.h" -#include "class_2.h" -#include "class_78.h" -#include "class_43.h" -#include "class_80.h" -#include "class_91.h" -#include "class_29.h" -#include "class_36.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_8/class_53.h b/lib/waf/build/lib_8/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_54.cpp b/lib/waf/build/lib_8/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_9.h" -#include "class_22.h" -#include "class_21.h" -#include "class_29.h" -#include "class_90.h" -#include "class_61.h" -#include "class_34.h" -#include "class_86.h" -#include "class_67.h" -#include "class_84.h" -#include "class_65.h" -#include "class_31.h" -#include "class_38.h" -#include "class_19.h" -#include "class_14.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_8/class_54.h b/lib/waf/build/lib_8/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_55.cpp b/lib/waf/build/lib_8/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_51.h" -#include "class_86.h" -#include "class_80.h" -#include "class_19.h" -#include "class_52.h" -#include "class_18.h" -#include "class_39.h" -#include "class_48.h" -#include "class_38.h" -#include "class_68.h" -#include "class_5.h" -#include "class_88.h" -#include "class_1.h" -#include "class_61.h" -#include "class_14.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_8/class_55.h b/lib/waf/build/lib_8/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_56.cpp b/lib/waf/build/lib_8/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_78.h" -#include "class_62.h" -#include "class_13.h" -#include "class_70.h" -#include "class_4.h" -#include "class_12.h" -#include "class_85.h" -#include "class_89.h" -#include "class_54.h" -#include "class_46.h" -#include "class_53.h" -#include "class_86.h" -#include "class_2.h" -#include "class_21.h" -#include "class_77.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_8/class_56.h b/lib/waf/build/lib_8/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_57.cpp b/lib/waf/build/lib_8/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_21.h" -#include "class_48.h" -#include "class_15.h" -#include "class_36.h" -#include "class_30.h" -#include "class_77.h" -#include "class_68.h" -#include "class_35.h" -#include "class_18.h" -#include "class_23.h" -#include "class_59.h" -#include "class_87.h" -#include "class_37.h" -#include "class_85.h" -#include "class_10.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_8/class_57.h b/lib/waf/build/lib_8/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_58.cpp b/lib/waf/build/lib_8/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_80.h" -#include "class_71.h" -#include "class_89.h" -#include "class_39.h" -#include "class_90.h" -#include "class_66.h" -#include "class_19.h" -#include "class_5.h" -#include "class_83.h" -#include "class_14.h" -#include "class_96.h" -#include "class_61.h" -#include "class_58.h" -#include "class_52.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_8/class_58.h b/lib/waf/build/lib_8/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_59.cpp b/lib/waf/build/lib_8/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_92.h" -#include "class_85.h" -#include "class_32.h" -#include "class_99.h" -#include "class_59.h" -#include "class_86.h" -#include "class_98.h" -#include "class_75.h" -#include "class_47.h" -#include "class_12.h" -#include "class_48.h" -#include "class_74.h" -#include "class_95.h" -#include "class_52.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_8/class_59.h b/lib/waf/build/lib_8/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_6.cpp b/lib/waf/build/lib_8/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_89.h" -#include "class_12.h" -#include "class_82.h" -#include "class_76.h" -#include "class_9.h" -#include "class_99.h" -#include "class_56.h" -#include "class_44.h" -#include "class_57.h" -#include "class_17.h" -#include "class_70.h" -#include "class_69.h" -#include "class_26.h" -#include "class_91.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_8/class_6.h b/lib/waf/build/lib_8/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_60.cpp b/lib/waf/build/lib_8/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_75.h" -#include "class_1.h" -#include "class_17.h" -#include "class_40.h" -#include "class_96.h" -#include "class_8.h" -#include "class_57.h" -#include "class_88.h" -#include "class_66.h" -#include "class_12.h" -#include "class_67.h" -#include "class_32.h" -#include "class_52.h" -#include "class_30.h" -#include "class_61.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_8/class_60.h b/lib/waf/build/lib_8/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_61.cpp b/lib/waf/build/lib_8/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_94.h" -#include "class_27.h" -#include "class_64.h" -#include "class_98.h" -#include "class_72.h" -#include "class_86.h" -#include "class_1.h" -#include "class_18.h" -#include "class_90.h" -#include "class_54.h" -#include "class_34.h" -#include "class_91.h" -#include "class_20.h" -#include "class_6.h" -#include "class_68.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_8/class_61.h b/lib/waf/build/lib_8/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_62.cpp b/lib/waf/build/lib_8/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_8.h" -#include "class_27.h" -#include "class_96.h" -#include "class_2.h" -#include "class_46.h" -#include "class_90.h" -#include "class_73.h" -#include "class_39.h" -#include "class_14.h" -#include "class_45.h" -#include "class_23.h" -#include "class_84.h" -#include "class_52.h" -#include "class_1.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_8/class_62.h b/lib/waf/build/lib_8/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_63.cpp b/lib/waf/build/lib_8/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_58.h" -#include "class_55.h" -#include "class_10.h" -#include "class_34.h" -#include "class_36.h" -#include "class_84.h" -#include "class_76.h" -#include "class_42.h" -#include "class_63.h" -#include "class_8.h" -#include "class_82.h" -#include "class_79.h" -#include "class_11.h" -#include "class_23.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_8/class_63.h b/lib/waf/build/lib_8/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_64.cpp b/lib/waf/build/lib_8/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_29.h" -#include "class_81.h" -#include "class_65.h" -#include "class_98.h" -#include "class_69.h" -#include "class_24.h" -#include "class_87.h" -#include "class_51.h" -#include "class_63.h" -#include "class_92.h" -#include "class_23.h" -#include "class_59.h" -#include "class_28.h" -#include "class_18.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_8/class_64.h b/lib/waf/build/lib_8/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_65.cpp b/lib/waf/build/lib_8/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_78.h" -#include "class_80.h" -#include "class_89.h" -#include "class_27.h" -#include "class_35.h" -#include "class_42.h" -#include "class_77.h" -#include "class_88.h" -#include "class_69.h" -#include "class_54.h" -#include "class_50.h" -#include "class_24.h" -#include "class_10.h" -#include "class_87.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_8/class_65.h b/lib/waf/build/lib_8/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_66.cpp b/lib/waf/build/lib_8/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_23.h" -#include "class_8.h" -#include "class_25.h" -#include "class_6.h" -#include "class_78.h" -#include "class_85.h" -#include "class_73.h" -#include "class_42.h" -#include "class_44.h" -#include "class_62.h" -#include "class_1.h" -#include "class_74.h" -#include "class_41.h" -#include "class_80.h" -#include "class_88.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_8/class_66.h b/lib/waf/build/lib_8/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_67.cpp b/lib/waf/build/lib_8/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_53.h" -#include "class_81.h" -#include "class_73.h" -#include "class_2.h" -#include "class_71.h" -#include "class_29.h" -#include "class_89.h" -#include "class_45.h" -#include "class_61.h" -#include "class_93.h" -#include "class_34.h" -#include "class_86.h" -#include "class_96.h" -#include "class_63.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_8/class_67.h b/lib/waf/build/lib_8/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_68.cpp b/lib/waf/build/lib_8/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_46.h" -#include "class_65.h" -#include "class_22.h" -#include "class_53.h" -#include "class_35.h" -#include "class_38.h" -#include "class_90.h" -#include "class_3.h" -#include "class_50.h" -#include "class_52.h" -#include "class_80.h" -#include "class_70.h" -#include "class_25.h" -#include "class_78.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_8/class_68.h b/lib/waf/build/lib_8/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_69.cpp b/lib/waf/build/lib_8/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_5.h" -#include "class_64.h" -#include "class_93.h" -#include "class_37.h" -#include "class_71.h" -#include "class_73.h" -#include "class_52.h" -#include "class_22.h" -#include "class_49.h" -#include "class_58.h" -#include "class_15.h" -#include "class_34.h" -#include "class_18.h" -#include "class_55.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_8/class_69.h b/lib/waf/build/lib_8/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_7.cpp b/lib/waf/build/lib_8/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_98.h" -#include "class_28.h" -#include "class_42.h" -#include "class_14.h" -#include "class_95.h" -#include "class_44.h" -#include "class_58.h" -#include "class_90.h" -#include "class_18.h" -#include "class_71.h" -#include "class_16.h" -#include "class_92.h" -#include "class_40.h" -#include "class_33.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_8/class_7.h b/lib/waf/build/lib_8/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_70.cpp b/lib/waf/build/lib_8/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_77.h" -#include "class_7.h" -#include "class_32.h" -#include "class_54.h" -#include "class_17.h" -#include "class_51.h" -#include "class_63.h" -#include "class_69.h" -#include "class_83.h" -#include "class_23.h" -#include "class_87.h" -#include "class_91.h" -#include "class_11.h" -#include "class_90.h" -#include "class_14.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_8/class_70.h b/lib/waf/build/lib_8/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_71.cpp b/lib/waf/build/lib_8/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_57.h" -#include "class_65.h" -#include "class_60.h" -#include "class_30.h" -#include "class_77.h" -#include "class_91.h" -#include "class_95.h" -#include "class_1.h" -#include "class_56.h" -#include "class_23.h" -#include "class_92.h" -#include "class_26.h" -#include "class_86.h" -#include "class_37.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_8/class_71.h b/lib/waf/build/lib_8/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_72.cpp b/lib/waf/build/lib_8/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_17.h" -#include "class_39.h" -#include "class_5.h" -#include "class_73.h" -#include "class_49.h" -#include "class_81.h" -#include "class_95.h" -#include "class_94.h" -#include "class_35.h" -#include "class_16.h" -#include "class_91.h" -#include "class_76.h" -#include "class_90.h" -#include "class_79.h" -#include "class_82.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_8/class_72.h b/lib/waf/build/lib_8/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_73.cpp b/lib/waf/build/lib_8/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_50.h" -#include "class_28.h" -#include "class_66.h" -#include "class_72.h" -#include "class_22.h" -#include "class_33.h" -#include "class_36.h" -#include "class_40.h" -#include "class_37.h" -#include "class_59.h" -#include "class_10.h" -#include "class_57.h" -#include "class_92.h" -#include "class_9.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_8/class_73.h b/lib/waf/build/lib_8/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_74.cpp b/lib/waf/build/lib_8/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_2.h" -#include "class_67.h" -#include "class_43.h" -#include "class_69.h" -#include "class_42.h" -#include "class_7.h" -#include "class_63.h" -#include "class_68.h" -#include "class_54.h" -#include "class_16.h" -#include "class_45.h" -#include "class_85.h" -#include "class_95.h" -#include "class_39.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_8/class_74.h b/lib/waf/build/lib_8/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_75.cpp b/lib/waf/build/lib_8/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_11.h" -#include "class_88.h" -#include "class_23.h" -#include "class_21.h" -#include "class_31.h" -#include "class_77.h" -#include "class_60.h" -#include "class_68.h" -#include "class_69.h" -#include "class_40.h" -#include "class_54.h" -#include "class_49.h" -#include "class_37.h" -#include "class_73.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_8/class_75.h b/lib/waf/build/lib_8/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_76.cpp b/lib/waf/build/lib_8/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_71.h" -#include "class_12.h" -#include "class_33.h" -#include "class_55.h" -#include "class_31.h" -#include "class_50.h" -#include "class_58.h" -#include "class_81.h" -#include "class_53.h" -#include "class_61.h" -#include "class_36.h" -#include "class_51.h" -#include "class_90.h" -#include "class_86.h" -#include "class_68.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_8/class_76.h b/lib/waf/build/lib_8/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_77.cpp b/lib/waf/build/lib_8/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_67.h" -#include "class_52.h" -#include "class_58.h" -#include "class_55.h" -#include "class_33.h" -#include "class_16.h" -#include "class_94.h" -#include "class_38.h" -#include "class_23.h" -#include "class_43.h" -#include "class_48.h" -#include "class_83.h" -#include "class_72.h" -#include "class_10.h" -#include "class_36.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_8/class_77.h b/lib/waf/build/lib_8/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_78.cpp b/lib/waf/build/lib_8/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_43.h" -#include "class_20.h" -#include "class_60.h" -#include "class_73.h" -#include "class_58.h" -#include "class_78.h" -#include "class_82.h" -#include "class_30.h" -#include "class_87.h" -#include "class_28.h" -#include "class_29.h" -#include "class_97.h" -#include "class_91.h" -#include "class_40.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_8/class_78.h b/lib/waf/build/lib_8/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_79.cpp b/lib/waf/build/lib_8/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_63.h" -#include "class_98.h" -#include "class_61.h" -#include "class_47.h" -#include "class_60.h" -#include "class_77.h" -#include "class_26.h" -#include "class_99.h" -#include "class_88.h" -#include "class_36.h" -#include "class_90.h" -#include "class_18.h" -#include "class_57.h" -#include "class_25.h" -#include "class_93.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_8/class_79.h b/lib/waf/build/lib_8/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_8.cpp b/lib/waf/build/lib_8/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_55.h" -#include "class_61.h" -#include "class_39.h" -#include "class_58.h" -#include "class_26.h" -#include "class_54.h" -#include "class_70.h" -#include "class_10.h" -#include "class_57.h" -#include "class_45.h" -#include "class_4.h" -#include "class_21.h" -#include "class_82.h" -#include "class_63.h" -#include "class_64.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_8/class_8.h b/lib/waf/build/lib_8/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_80.cpp b/lib/waf/build/lib_8/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_31.h" -#include "class_75.h" -#include "class_45.h" -#include "class_65.h" -#include "class_70.h" -#include "class_88.h" -#include "class_90.h" -#include "class_48.h" -#include "class_98.h" -#include "class_60.h" -#include "class_69.h" -#include "class_36.h" -#include "class_53.h" -#include "class_42.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_8/class_80.h b/lib/waf/build/lib_8/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_81.cpp b/lib/waf/build/lib_8/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_78.h" -#include "class_20.h" -#include "class_56.h" -#include "class_35.h" -#include "class_37.h" -#include "class_58.h" -#include "class_99.h" -#include "class_0.h" -#include "class_72.h" -#include "class_29.h" -#include "class_63.h" -#include "class_60.h" -#include "class_62.h" -#include "class_7.h" -#include "class_98.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_8/class_81.h b/lib/waf/build/lib_8/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_82.cpp b/lib/waf/build/lib_8/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_23.h" -#include "class_28.h" -#include "class_13.h" -#include "class_82.h" -#include "class_59.h" -#include "class_96.h" -#include "class_45.h" -#include "class_68.h" -#include "class_84.h" -#include "class_41.h" -#include "class_0.h" -#include "class_70.h" -#include "class_36.h" -#include "class_32.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_8/class_82.h b/lib/waf/build/lib_8/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_83.cpp b/lib/waf/build/lib_8/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_77.h" -#include "class_81.h" -#include "class_82.h" -#include "class_26.h" -#include "class_40.h" -#include "class_11.h" -#include "class_17.h" -#include "class_50.h" -#include "class_32.h" -#include "class_45.h" -#include "class_99.h" -#include "class_53.h" -#include "class_95.h" -#include "class_55.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_8/class_83.h b/lib/waf/build/lib_8/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_84.cpp b/lib/waf/build/lib_8/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_21.h" -#include "class_14.h" -#include "class_51.h" -#include "class_17.h" -#include "class_30.h" -#include "class_42.h" -#include "class_81.h" -#include "class_6.h" -#include "class_85.h" -#include "class_18.h" -#include "class_8.h" -#include "class_45.h" -#include "class_28.h" -#include "class_25.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_8/class_84.h b/lib/waf/build/lib_8/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_85.cpp b/lib/waf/build/lib_8/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_50.h" -#include "class_14.h" -#include "class_15.h" -#include "class_55.h" -#include "class_63.h" -#include "class_25.h" -#include "class_30.h" -#include "class_88.h" -#include "class_49.h" -#include "class_52.h" -#include "class_83.h" -#include "class_86.h" -#include "class_87.h" -#include "class_7.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_8/class_85.h b/lib/waf/build/lib_8/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_86.cpp b/lib/waf/build/lib_8/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_79.h" -#include "class_0.h" -#include "class_64.h" -#include "class_20.h" -#include "class_52.h" -#include "class_4.h" -#include "class_12.h" -#include "class_40.h" -#include "class_5.h" -#include "class_92.h" -#include "class_66.h" -#include "class_96.h" -#include "class_51.h" -#include "class_93.h" -#include "class_1.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_8/class_86.h b/lib/waf/build/lib_8/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_87.cpp b/lib/waf/build/lib_8/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_32.h" -#include "class_8.h" -#include "class_88.h" -#include "class_18.h" -#include "class_4.h" -#include "class_97.h" -#include "class_87.h" -#include "class_96.h" -#include "class_60.h" -#include "class_66.h" -#include "class_20.h" -#include "class_83.h" -#include "class_22.h" -#include "class_73.h" -#include "class_57.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_8/class_87.h b/lib/waf/build/lib_8/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_88.cpp b/lib/waf/build/lib_8/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_28.h" -#include "class_15.h" -#include "class_6.h" -#include "class_19.h" -#include "class_95.h" -#include "class_73.h" -#include "class_71.h" -#include "class_27.h" -#include "class_33.h" -#include "class_87.h" -#include "class_17.h" -#include "class_74.h" -#include "class_25.h" -#include "class_65.h" -#include "class_16.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_8/class_88.h b/lib/waf/build/lib_8/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_89.cpp b/lib/waf/build/lib_8/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_53.h" -#include "class_17.h" -#include "class_74.h" -#include "class_28.h" -#include "class_35.h" -#include "class_5.h" -#include "class_76.h" -#include "class_80.h" -#include "class_33.h" -#include "class_2.h" -#include "class_77.h" -#include "class_11.h" -#include "class_0.h" -#include "class_12.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_8/class_89.h b/lib/waf/build/lib_8/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_9.cpp b/lib/waf/build/lib_8/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_9.h" -#include "class_85.h" -#include "class_45.h" -#include "class_30.h" -#include "class_36.h" -#include "class_10.h" -#include "class_94.h" -#include "class_48.h" -#include "class_31.h" -#include "class_7.h" -#include "class_79.h" -#include "class_80.h" -#include "class_98.h" -#include "class_46.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_8/class_9.h b/lib/waf/build/lib_8/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_90.cpp b/lib/waf/build/lib_8/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_3.h" -#include "class_7.h" -#include "class_48.h" -#include "class_18.h" -#include "class_23.h" -#include "class_68.h" -#include "class_58.h" -#include "class_49.h" -#include "class_35.h" -#include "class_4.h" -#include "class_67.h" -#include "class_6.h" -#include "class_0.h" -#include "class_43.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_8/class_90.h b/lib/waf/build/lib_8/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_91.cpp b/lib/waf/build/lib_8/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_46.h" -#include "class_24.h" -#include "class_80.h" -#include "class_64.h" -#include "class_54.h" -#include "class_85.h" -#include "class_22.h" -#include "class_57.h" -#include "class_34.h" -#include "class_99.h" -#include "class_93.h" -#include "class_72.h" -#include "class_1.h" -#include "class_27.h" -#include "class_74.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_8/class_91.h b/lib/waf/build/lib_8/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_92.cpp b/lib/waf/build/lib_8/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_40.h" -#include "class_24.h" -#include "class_53.h" -#include "class_97.h" -#include "class_81.h" -#include "class_2.h" -#include "class_95.h" -#include "class_25.h" -#include "class_15.h" -#include "class_19.h" -#include "class_20.h" -#include "class_86.h" -#include "class_14.h" -#include "class_23.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_8/class_92.h b/lib/waf/build/lib_8/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_93.cpp b/lib/waf/build/lib_8/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_73.h" -#include "class_5.h" -#include "class_10.h" -#include "class_77.h" -#include "class_65.h" -#include "class_90.h" -#include "class_48.h" -#include "class_39.h" -#include "class_31.h" -#include "class_24.h" -#include "class_50.h" -#include "class_97.h" -#include "class_70.h" -#include "class_52.h" -#include "class_96.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_8/class_93.h b/lib/waf/build/lib_8/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_94.cpp b/lib/waf/build/lib_8/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_10.h" -#include "class_35.h" -#include "class_97.h" -#include "class_54.h" -#include "class_58.h" -#include "class_75.h" -#include "class_93.h" -#include "class_13.h" -#include "class_17.h" -#include "class_0.h" -#include "class_6.h" -#include "class_70.h" -#include "class_64.h" -#include "class_85.h" -#include "class_25.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_8/class_94.h b/lib/waf/build/lib_8/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_95.cpp b/lib/waf/build/lib_8/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_89.h" -#include "class_77.h" -#include "class_43.h" -#include "class_5.h" -#include "class_20.h" -#include "class_19.h" -#include "class_51.h" -#include "class_35.h" -#include "class_82.h" -#include "class_54.h" -#include "class_83.h" -#include "class_92.h" -#include "class_29.h" -#include "class_22.h" -#include "class_47.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_8/class_95.h b/lib/waf/build/lib_8/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_96.cpp b/lib/waf/build/lib_8/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_3.h" -#include "class_67.h" -#include "class_5.h" -#include "class_72.h" -#include "class_44.h" -#include "class_34.h" -#include "class_75.h" -#include "class_35.h" -#include "class_16.h" -#include "class_55.h" -#include "class_74.h" -#include "class_83.h" -#include "class_38.h" -#include "class_30.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_8/class_96.h b/lib/waf/build/lib_8/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_97.cpp b/lib/waf/build/lib_8/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_33.h" -#include "class_21.h" -#include "class_35.h" -#include "class_37.h" -#include "class_64.h" -#include "class_51.h" -#include "class_9.h" -#include "class_92.h" -#include "class_32.h" -#include "class_61.h" -#include "class_52.h" -#include "class_15.h" -#include "class_28.h" -#include "class_7.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_8/class_97.h b/lib/waf/build/lib_8/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_98.cpp b/lib/waf/build/lib_8/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_47.h" -#include "class_78.h" -#include "class_88.h" -#include "class_76.h" -#include "class_22.h" -#include "class_57.h" -#include "class_24.h" -#include "class_28.h" -#include "class_6.h" -#include "class_73.h" -#include "class_31.h" -#include "class_36.h" -#include "class_50.h" -#include "class_55.h" -#include "class_62.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_8/class_98.h b/lib/waf/build/lib_8/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_8/class_99.cpp b/lib/waf/build/lib_8/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_8/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_51.h" -#include "class_5.h" -#include "class_11.h" -#include "class_79.h" -#include "class_1.h" -#include "class_38.h" -#include "class_14.h" -#include "class_81.h" -#include "class_2.h" -#include "class_27.h" -#include "class_70.h" -#include "class_20.h" -#include "class_45.h" -#include "class_91.h" -#include "class_39.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_8/class_99.h b/lib/waf/build/lib_8/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_8/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/lib_9/Makefile b/lib/waf/build/lib_9/Makefile deleted file mode 100644 --- a/lib/waf/build/lib_9/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -COMPILER = g++ -INC = -I.. -CCFLAGS = -g -Wall $(INC) -ARCHIVE = ar -DEPEND = makedepend -.SUFFIXES: .o .cpp - -lib = lib_9.a -src = \ -class_0.cpp \ -class_1.cpp \ -class_2.cpp \ -class_3.cpp \ -class_4.cpp \ -class_5.cpp \ -class_6.cpp \ -class_7.cpp \ -class_8.cpp \ -class_9.cpp \ -class_10.cpp \ -class_11.cpp \ -class_12.cpp \ -class_13.cpp \ -class_14.cpp \ -class_15.cpp \ -class_16.cpp \ -class_17.cpp \ -class_18.cpp \ -class_19.cpp \ -class_20.cpp \ -class_21.cpp \ -class_22.cpp \ -class_23.cpp \ -class_24.cpp \ -class_25.cpp \ -class_26.cpp \ -class_27.cpp \ -class_28.cpp \ -class_29.cpp \ -class_30.cpp \ -class_31.cpp \ -class_32.cpp \ -class_33.cpp \ -class_34.cpp \ -class_35.cpp \ -class_36.cpp \ -class_37.cpp \ -class_38.cpp \ -class_39.cpp \ -class_40.cpp \ -class_41.cpp \ -class_42.cpp \ -class_43.cpp \ -class_44.cpp \ -class_45.cpp \ -class_46.cpp \ -class_47.cpp \ -class_48.cpp \ -class_49.cpp \ -class_50.cpp \ -class_51.cpp \ -class_52.cpp \ -class_53.cpp \ -class_54.cpp \ -class_55.cpp \ -class_56.cpp \ -class_57.cpp \ -class_58.cpp \ -class_59.cpp \ -class_60.cpp \ -class_61.cpp \ -class_62.cpp \ -class_63.cpp \ -class_64.cpp \ -class_65.cpp \ -class_66.cpp \ -class_67.cpp \ -class_68.cpp \ -class_69.cpp \ -class_70.cpp \ -class_71.cpp \ -class_72.cpp \ -class_73.cpp \ -class_74.cpp \ -class_75.cpp \ -class_76.cpp \ -class_77.cpp \ -class_78.cpp \ -class_79.cpp \ -class_80.cpp \ -class_81.cpp \ -class_82.cpp \ -class_83.cpp \ -class_84.cpp \ -class_85.cpp \ -class_86.cpp \ -class_87.cpp \ -class_88.cpp \ -class_89.cpp \ -class_90.cpp \ -class_91.cpp \ -class_92.cpp \ -class_93.cpp \ -class_94.cpp \ -class_95.cpp \ -class_96.cpp \ -class_97.cpp \ -class_98.cpp \ -class_99.cpp \ - - -objects = $(patsubst %.cpp, %.o, $(src)) - -all: depend $(lib) - -$(lib): $(objects) - $(ARCHIVE) cr $@ $^ - touch $@ - -.cpp.o: - $(COMPILER) $(CCFLAGS) -c $< - -clean: - @rm $(objects) $(lib) 2> /dev/null - -depend: - @$(DEPEND) $(INC) $(src) - diff --git a/lib/waf/build/lib_9/Makefile.am b/lib/waf/build/lib_9/Makefile.am deleted file mode 100644 --- a/lib/waf/build/lib_9/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -lib_LTLIBRARIES += lib9.la -lib9_la_SOURCES = lib_9/class_0.cpp lib_9/class_1.cpp lib_9/class_2.cpp lib_9/class_3.cpp lib_9/class_4.cpp lib_9/class_5.cpp lib_9/class_6.cpp lib_9/class_7.cpp lib_9/class_8.cpp lib_9/class_9.cpp lib_9/class_10.cpp lib_9/class_11.cpp lib_9/class_12.cpp lib_9/class_13.cpp lib_9/class_14.cpp lib_9/class_15.cpp lib_9/class_16.cpp lib_9/class_17.cpp lib_9/class_18.cpp lib_9/class_19.cpp lib_9/class_20.cpp lib_9/class_21.cpp lib_9/class_22.cpp lib_9/class_23.cpp lib_9/class_24.cpp lib_9/class_25.cpp lib_9/class_26.cpp lib_9/class_27.cpp lib_9/class_28.cpp lib_9/class_29.cpp lib_9/class_30.cpp lib_9/class_31.cpp lib_9/class_32.cpp lib_9/class_33.cpp lib_9/class_34.cpp lib_9/class_35.cpp lib_9/class_36.cpp lib_9/class_37.cpp lib_9/class_38.cpp lib_9/class_39.cpp lib_9/class_40.cpp lib_9/class_41.cpp lib_9/class_42.cpp lib_9/class_43.cpp lib_9/class_44.cpp lib_9/class_45.cpp lib_9/class_46.cpp lib_9/class_47.cpp lib_9/class_48.cpp lib_9/class_49.cpp lib_9/class_50.cpp lib_9/class_51.cpp lib_9/class_52.cpp lib_9/class_53.cpp lib_9/class_54.cpp lib_9/class_55.cpp lib_9/class_56.cpp lib_9/class_57.cpp lib_9/class_58.cpp lib_9/class_59.cpp lib_9/class_60.cpp lib_9/class_61.cpp lib_9/class_62.cpp lib_9/class_63.cpp lib_9/class_64.cpp lib_9/class_65.cpp lib_9/class_66.cpp lib_9/class_67.cpp lib_9/class_68.cpp lib_9/class_69.cpp lib_9/class_70.cpp lib_9/class_71.cpp lib_9/class_72.cpp lib_9/class_73.cpp lib_9/class_74.cpp lib_9/class_75.cpp lib_9/class_76.cpp lib_9/class_77.cpp lib_9/class_78.cpp lib_9/class_79.cpp lib_9/class_80.cpp lib_9/class_81.cpp lib_9/class_82.cpp lib_9/class_83.cpp lib_9/class_84.cpp lib_9/class_85.cpp lib_9/class_86.cpp lib_9/class_87.cpp lib_9/class_88.cpp lib_9/class_89.cpp lib_9/class_90.cpp lib_9/class_91.cpp lib_9/class_92.cpp lib_9/class_93.cpp lib_9/class_94.cpp lib_9/class_95.cpp lib_9/class_96.cpp lib_9/class_97.cpp lib_9/class_98.cpp lib_9/class_99.cpp diff --git a/lib/waf/build/lib_9/SConscript b/lib/waf/build/lib_9/SConscript deleted file mode 100644 --- a/lib/waf/build/lib_9/SConscript +++ /dev/null @@ -1,106 +0,0 @@ -Import('env') -list = Split(""" - class_0.cpp - class_1.cpp - class_2.cpp - class_3.cpp - class_4.cpp - class_5.cpp - class_6.cpp - class_7.cpp - class_8.cpp - class_9.cpp - class_10.cpp - class_11.cpp - class_12.cpp - class_13.cpp - class_14.cpp - class_15.cpp - class_16.cpp - class_17.cpp - class_18.cpp - class_19.cpp - class_20.cpp - class_21.cpp - class_22.cpp - class_23.cpp - class_24.cpp - class_25.cpp - class_26.cpp - class_27.cpp - class_28.cpp - class_29.cpp - class_30.cpp - class_31.cpp - class_32.cpp - class_33.cpp - class_34.cpp - class_35.cpp - class_36.cpp - class_37.cpp - class_38.cpp - class_39.cpp - class_40.cpp - class_41.cpp - class_42.cpp - class_43.cpp - class_44.cpp - class_45.cpp - class_46.cpp - class_47.cpp - class_48.cpp - class_49.cpp - class_50.cpp - class_51.cpp - class_52.cpp - class_53.cpp - class_54.cpp - class_55.cpp - class_56.cpp - class_57.cpp - class_58.cpp - class_59.cpp - class_60.cpp - class_61.cpp - class_62.cpp - class_63.cpp - class_64.cpp - class_65.cpp - class_66.cpp - class_67.cpp - class_68.cpp - class_69.cpp - class_70.cpp - class_71.cpp - class_72.cpp - class_73.cpp - class_74.cpp - class_75.cpp - class_76.cpp - class_77.cpp - class_78.cpp - class_79.cpp - class_80.cpp - class_81.cpp - class_82.cpp - class_83.cpp - class_84.cpp - class_85.cpp - class_86.cpp - class_87.cpp - class_88.cpp - class_89.cpp - class_90.cpp - class_91.cpp - class_92.cpp - class_93.cpp - class_94.cpp - class_95.cpp - class_96.cpp - class_97.cpp - class_98.cpp - class_99.cpp - """) - -env.StaticLibrary("lib_9", list) - diff --git a/lib/waf/build/lib_9/class_0.cpp b/lib/waf/build/lib_9/class_0.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_0.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_0.h" -#include "class_96.h" -#include "class_79.h" -#include "class_88.h" -#include "class_55.h" -#include "class_84.h" -#include "class_15.h" -#include "class_76.h" -#include "class_80.h" -#include "class_37.h" -#include "class_78.h" -#include "class_91.h" -#include "class_13.h" -#include "class_87.h" -#include "class_75.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_0::class_0() {} -class_0::~class_0() {} diff --git a/lib/waf/build/lib_9/class_0.h b/lib/waf/build/lib_9/class_0.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_0.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_0_h_ -#define class_0_h_ - -class class_0 { -public: - class_0(); - ~class_0(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_1.cpp b/lib/waf/build/lib_9/class_1.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_1.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_1.h" -#include "class_34.h" -#include "class_66.h" -#include "class_64.h" -#include "class_73.h" -#include "class_29.h" -#include "class_98.h" -#include "class_51.h" -#include "class_40.h" -#include "class_44.h" -#include "class_86.h" -#include "class_60.h" -#include "class_25.h" -#include "class_57.h" -#include "class_46.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_1::class_1() {} -class_1::~class_1() {} diff --git a/lib/waf/build/lib_9/class_1.h b/lib/waf/build/lib_9/class_1.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_1.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_1_h_ -#define class_1_h_ - -class class_1 { -public: - class_1(); - ~class_1(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_10.cpp b/lib/waf/build/lib_9/class_10.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_10.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_10.h" -#include "class_2.h" -#include "class_22.h" -#include "class_45.h" -#include "class_36.h" -#include "class_43.h" -#include "class_13.h" -#include "class_21.h" -#include "class_79.h" -#include "class_4.h" -#include "class_56.h" -#include "class_27.h" -#include "class_46.h" -#include "class_90.h" -#include "class_51.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_10::class_10() {} -class_10::~class_10() {} diff --git a/lib/waf/build/lib_9/class_10.h b/lib/waf/build/lib_9/class_10.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_10_h_ -#define class_10_h_ - -class class_10 { -public: - class_10(); - ~class_10(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_11.cpp b/lib/waf/build/lib_9/class_11.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_11.h" -#include "class_90.h" -#include "class_47.h" -#include "class_77.h" -#include "class_18.h" -#include "class_58.h" -#include "class_33.h" -#include "class_85.h" -#include "class_78.h" -#include "class_71.h" -#include "class_13.h" -#include "class_91.h" -#include "class_68.h" -#include "class_89.h" -#include "class_72.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_11::class_11() {} -class_11::~class_11() {} diff --git a/lib/waf/build/lib_9/class_11.h b/lib/waf/build/lib_9/class_11.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_11.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_11_h_ -#define class_11_h_ - -class class_11 { -public: - class_11(); - ~class_11(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_12.cpp b/lib/waf/build/lib_9/class_12.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_12.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_12.h" -#include "class_37.h" -#include "class_40.h" -#include "class_51.h" -#include "class_1.h" -#include "class_78.h" -#include "class_53.h" -#include "class_91.h" -#include "class_99.h" -#include "class_31.h" -#include "class_65.h" -#include "class_52.h" -#include "class_21.h" -#include "class_24.h" -#include "class_60.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_12::class_12() {} -class_12::~class_12() {} diff --git a/lib/waf/build/lib_9/class_12.h b/lib/waf/build/lib_9/class_12.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_12.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_12_h_ -#define class_12_h_ - -class class_12 { -public: - class_12(); - ~class_12(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_13.cpp b/lib/waf/build/lib_9/class_13.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_13.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_13.h" -#include "class_82.h" -#include "class_88.h" -#include "class_78.h" -#include "class_64.h" -#include "class_35.h" -#include "class_93.h" -#include "class_51.h" -#include "class_99.h" -#include "class_33.h" -#include "class_0.h" -#include "class_94.h" -#include "class_11.h" -#include "class_63.h" -#include "class_77.h" -#include "class_84.h" -#include -#include -#include -#include -#include - -class_13::class_13() {} -class_13::~class_13() {} diff --git a/lib/waf/build/lib_9/class_13.h b/lib/waf/build/lib_9/class_13.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_13.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_13_h_ -#define class_13_h_ - -class class_13 { -public: - class_13(); - ~class_13(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_14.cpp b/lib/waf/build/lib_9/class_14.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_14.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_14.h" -#include "class_25.h" -#include "class_66.h" -#include "class_30.h" -#include "class_0.h" -#include "class_53.h" -#include "class_67.h" -#include "class_21.h" -#include "class_46.h" -#include "class_68.h" -#include "class_84.h" -#include "class_78.h" -#include "class_29.h" -#include "class_10.h" -#include "class_31.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_14::class_14() {} -class_14::~class_14() {} diff --git a/lib/waf/build/lib_9/class_14.h b/lib/waf/build/lib_9/class_14.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_14.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_14_h_ -#define class_14_h_ - -class class_14 { -public: - class_14(); - ~class_14(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_15.cpp b/lib/waf/build/lib_9/class_15.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_15.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_15.h" -#include "class_32.h" -#include "class_95.h" -#include "class_40.h" -#include "class_76.h" -#include "class_51.h" -#include "class_15.h" -#include "class_30.h" -#include "class_64.h" -#include "class_80.h" -#include "class_31.h" -#include "class_33.h" -#include "class_84.h" -#include "class_4.h" -#include "class_96.h" -#include "class_83.h" -#include -#include -#include -#include -#include - -class_15::class_15() {} -class_15::~class_15() {} diff --git a/lib/waf/build/lib_9/class_15.h b/lib/waf/build/lib_9/class_15.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_15.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_15_h_ -#define class_15_h_ - -class class_15 { -public: - class_15(); - ~class_15(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_16.cpp b/lib/waf/build/lib_9/class_16.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_16.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_16.h" -#include "class_42.h" -#include "class_93.h" -#include "class_72.h" -#include "class_34.h" -#include "class_66.h" -#include "class_55.h" -#include "class_53.h" -#include "class_91.h" -#include "class_97.h" -#include "class_61.h" -#include "class_79.h" -#include "class_86.h" -#include "class_88.h" -#include "class_18.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_16::class_16() {} -class_16::~class_16() {} diff --git a/lib/waf/build/lib_9/class_16.h b/lib/waf/build/lib_9/class_16.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_16.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_16_h_ -#define class_16_h_ - -class class_16 { -public: - class_16(); - ~class_16(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_17.cpp b/lib/waf/build/lib_9/class_17.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_17.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_17.h" -#include "class_99.h" -#include "class_65.h" -#include "class_14.h" -#include "class_20.h" -#include "class_76.h" -#include "class_80.h" -#include "class_36.h" -#include "class_51.h" -#include "class_4.h" -#include "class_1.h" -#include "class_88.h" -#include "class_48.h" -#include "class_2.h" -#include "class_90.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_17::class_17() {} -class_17::~class_17() {} diff --git a/lib/waf/build/lib_9/class_17.h b/lib/waf/build/lib_9/class_17.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_17.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_17_h_ -#define class_17_h_ - -class class_17 { -public: - class_17(); - ~class_17(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_18.cpp b/lib/waf/build/lib_9/class_18.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_18.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_18.h" -#include "class_38.h" -#include "class_11.h" -#include "class_72.h" -#include "class_50.h" -#include "class_18.h" -#include "class_53.h" -#include "class_88.h" -#include "class_1.h" -#include "class_74.h" -#include "class_97.h" -#include "class_5.h" -#include "class_68.h" -#include "class_78.h" -#include "class_96.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_18::class_18() {} -class_18::~class_18() {} diff --git a/lib/waf/build/lib_9/class_18.h b/lib/waf/build/lib_9/class_18.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_18.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_18_h_ -#define class_18_h_ - -class class_18 { -public: - class_18(); - ~class_18(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_19.cpp b/lib/waf/build/lib_9/class_19.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_19.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_19.h" -#include "class_49.h" -#include "class_73.h" -#include "class_74.h" -#include "class_98.h" -#include "class_61.h" -#include "class_58.h" -#include "class_95.h" -#include "class_85.h" -#include "class_23.h" -#include "class_93.h" -#include "class_89.h" -#include "class_35.h" -#include "class_43.h" -#include "class_54.h" -#include "class_91.h" -#include -#include -#include -#include -#include - -class_19::class_19() {} -class_19::~class_19() {} diff --git a/lib/waf/build/lib_9/class_19.h b/lib/waf/build/lib_9/class_19.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_19.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_19_h_ -#define class_19_h_ - -class class_19 { -public: - class_19(); - ~class_19(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_2.cpp b/lib/waf/build/lib_9/class_2.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_2.h" -#include "class_71.h" -#include "class_64.h" -#include "class_3.h" -#include "class_80.h" -#include "class_31.h" -#include "class_83.h" -#include "class_26.h" -#include "class_96.h" -#include "class_30.h" -#include "class_72.h" -#include "class_25.h" -#include "class_97.h" -#include "class_1.h" -#include "class_29.h" -#include "class_19.h" -#include -#include -#include -#include -#include - -class_2::class_2() {} -class_2::~class_2() {} diff --git a/lib/waf/build/lib_9/class_2.h b/lib/waf/build/lib_9/class_2.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_2_h_ -#define class_2_h_ - -class class_2 { -public: - class_2(); - ~class_2(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_20.cpp b/lib/waf/build/lib_9/class_20.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_20.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_20.h" -#include "class_2.h" -#include "class_42.h" -#include "class_14.h" -#include "class_39.h" -#include "class_73.h" -#include "class_80.h" -#include "class_46.h" -#include "class_90.h" -#include "class_86.h" -#include "class_52.h" -#include "class_68.h" -#include "class_34.h" -#include "class_70.h" -#include "class_61.h" -#include "class_38.h" -#include -#include -#include -#include -#include - -class_20::class_20() {} -class_20::~class_20() {} diff --git a/lib/waf/build/lib_9/class_20.h b/lib/waf/build/lib_9/class_20.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_20.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_20_h_ -#define class_20_h_ - -class class_20 { -public: - class_20(); - ~class_20(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_21.cpp b/lib/waf/build/lib_9/class_21.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_21.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_21.h" -#include "class_80.h" -#include "class_86.h" -#include "class_28.h" -#include "class_56.h" -#include "class_34.h" -#include "class_93.h" -#include "class_30.h" -#include "class_62.h" -#include "class_42.h" -#include "class_0.h" -#include "class_38.h" -#include "class_97.h" -#include "class_74.h" -#include "class_32.h" -#include "class_5.h" -#include -#include -#include -#include -#include - -class_21::class_21() {} -class_21::~class_21() {} diff --git a/lib/waf/build/lib_9/class_21.h b/lib/waf/build/lib_9/class_21.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_21.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_21_h_ -#define class_21_h_ - -class class_21 { -public: - class_21(); - ~class_21(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_22.cpp b/lib/waf/build/lib_9/class_22.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_22.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_22.h" -#include "class_29.h" -#include "class_31.h" -#include "class_89.h" -#include "class_71.h" -#include "class_70.h" -#include "class_79.h" -#include "class_39.h" -#include "class_15.h" -#include "class_5.h" -#include "class_91.h" -#include "class_63.h" -#include "class_76.h" -#include "class_49.h" -#include "class_62.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_22::class_22() {} -class_22::~class_22() {} diff --git a/lib/waf/build/lib_9/class_22.h b/lib/waf/build/lib_9/class_22.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_22.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_22_h_ -#define class_22_h_ - -class class_22 { -public: - class_22(); - ~class_22(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_23.cpp b/lib/waf/build/lib_9/class_23.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_23.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_23.h" -#include "class_26.h" -#include "class_76.h" -#include "class_45.h" -#include "class_20.h" -#include "class_73.h" -#include "class_10.h" -#include "class_5.h" -#include "class_48.h" -#include "class_62.h" -#include "class_49.h" -#include "class_11.h" -#include "class_7.h" -#include "class_63.h" -#include "class_85.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_23::class_23() {} -class_23::~class_23() {} diff --git a/lib/waf/build/lib_9/class_23.h b/lib/waf/build/lib_9/class_23.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_23.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_23_h_ -#define class_23_h_ - -class class_23 { -public: - class_23(); - ~class_23(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_24.cpp b/lib/waf/build/lib_9/class_24.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_24.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_24.h" -#include "class_7.h" -#include "class_78.h" -#include "class_27.h" -#include "class_21.h" -#include "class_95.h" -#include "class_99.h" -#include "class_55.h" -#include "class_30.h" -#include "class_69.h" -#include "class_34.h" -#include "class_81.h" -#include "class_96.h" -#include "class_98.h" -#include "class_49.h" -#include "class_93.h" -#include -#include -#include -#include -#include - -class_24::class_24() {} -class_24::~class_24() {} diff --git a/lib/waf/build/lib_9/class_24.h b/lib/waf/build/lib_9/class_24.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_24.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_24_h_ -#define class_24_h_ - -class class_24 { -public: - class_24(); - ~class_24(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_25.cpp b/lib/waf/build/lib_9/class_25.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_25.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_25.h" -#include "class_2.h" -#include "class_43.h" -#include "class_32.h" -#include "class_97.h" -#include "class_95.h" -#include "class_96.h" -#include "class_88.h" -#include "class_65.h" -#include "class_71.h" -#include "class_93.h" -#include "class_8.h" -#include "class_61.h" -#include "class_0.h" -#include "class_13.h" -#include "class_14.h" -#include -#include -#include -#include -#include - -class_25::class_25() {} -class_25::~class_25() {} diff --git a/lib/waf/build/lib_9/class_25.h b/lib/waf/build/lib_9/class_25.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_25_h_ -#define class_25_h_ - -class class_25 { -public: - class_25(); - ~class_25(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_26.cpp b/lib/waf/build/lib_9/class_26.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_26.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_26.h" -#include "class_2.h" -#include "class_88.h" -#include "class_84.h" -#include "class_83.h" -#include "class_8.h" -#include "class_21.h" -#include "class_11.h" -#include "class_97.h" -#include "class_28.h" -#include "class_59.h" -#include "class_16.h" -#include "class_51.h" -#include "class_23.h" -#include "class_19.h" -#include "class_93.h" -#include -#include -#include -#include -#include - -class_26::class_26() {} -class_26::~class_26() {} diff --git a/lib/waf/build/lib_9/class_26.h b/lib/waf/build/lib_9/class_26.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_26.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_26_h_ -#define class_26_h_ - -class class_26 { -public: - class_26(); - ~class_26(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_27.cpp b/lib/waf/build/lib_9/class_27.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_27.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_27.h" -#include "class_95.h" -#include "class_56.h" -#include "class_1.h" -#include "class_3.h" -#include "class_76.h" -#include "class_93.h" -#include "class_62.h" -#include "class_57.h" -#include "class_24.h" -#include "class_23.h" -#include "class_48.h" -#include "class_60.h" -#include "class_14.h" -#include "class_28.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_27::class_27() {} -class_27::~class_27() {} diff --git a/lib/waf/build/lib_9/class_27.h b/lib/waf/build/lib_9/class_27.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_27.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_27_h_ -#define class_27_h_ - -class class_27 { -public: - class_27(); - ~class_27(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_28.cpp b/lib/waf/build/lib_9/class_28.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_28.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_28.h" -#include "class_19.h" -#include "class_46.h" -#include "class_54.h" -#include "class_97.h" -#include "class_9.h" -#include "class_67.h" -#include "class_75.h" -#include "class_42.h" -#include "class_81.h" -#include "class_34.h" -#include "class_70.h" -#include "class_85.h" -#include "class_0.h" -#include "class_10.h" -#include "class_58.h" -#include -#include -#include -#include -#include - -class_28::class_28() {} -class_28::~class_28() {} diff --git a/lib/waf/build/lib_9/class_28.h b/lib/waf/build/lib_9/class_28.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_28.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_28_h_ -#define class_28_h_ - -class class_28 { -public: - class_28(); - ~class_28(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_29.cpp b/lib/waf/build/lib_9/class_29.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_29.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_29.h" -#include "class_86.h" -#include "class_9.h" -#include "class_46.h" -#include "class_48.h" -#include "class_50.h" -#include "class_70.h" -#include "class_12.h" -#include "class_29.h" -#include "class_17.h" -#include "class_99.h" -#include "class_98.h" -#include "class_18.h" -#include "class_77.h" -#include "class_22.h" -#include "class_11.h" -#include -#include -#include -#include -#include - -class_29::class_29() {} -class_29::~class_29() {} diff --git a/lib/waf/build/lib_9/class_29.h b/lib/waf/build/lib_9/class_29.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_29.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_29_h_ -#define class_29_h_ - -class class_29 { -public: - class_29(); - ~class_29(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_3.cpp b/lib/waf/build/lib_9/class_3.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_3.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_3.h" -#include "class_23.h" -#include "class_70.h" -#include "class_54.h" -#include "class_45.h" -#include "class_91.h" -#include "class_81.h" -#include "class_9.h" -#include "class_36.h" -#include "class_42.h" -#include "class_20.h" -#include "class_69.h" -#include "class_84.h" -#include "class_34.h" -#include "class_96.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_3::class_3() {} -class_3::~class_3() {} diff --git a/lib/waf/build/lib_9/class_3.h b/lib/waf/build/lib_9/class_3.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_3.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_3_h_ -#define class_3_h_ - -class class_3 { -public: - class_3(); - ~class_3(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_30.cpp b/lib/waf/build/lib_9/class_30.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_30.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_30.h" -#include "class_58.h" -#include "class_27.h" -#include "class_6.h" -#include "class_69.h" -#include "class_41.h" -#include "class_5.h" -#include "class_72.h" -#include "class_67.h" -#include "class_21.h" -#include "class_39.h" -#include "class_85.h" -#include "class_77.h" -#include "class_73.h" -#include "class_3.h" -#include "class_94.h" -#include -#include -#include -#include -#include - -class_30::class_30() {} -class_30::~class_30() {} diff --git a/lib/waf/build/lib_9/class_30.h b/lib/waf/build/lib_9/class_30.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_30.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_30_h_ -#define class_30_h_ - -class class_30 { -public: - class_30(); - ~class_30(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_31.cpp b/lib/waf/build/lib_9/class_31.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_31.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_31.h" -#include "class_18.h" -#include "class_3.h" -#include "class_58.h" -#include "class_21.h" -#include "class_9.h" -#include "class_68.h" -#include "class_61.h" -#include "class_23.h" -#include "class_91.h" -#include "class_72.h" -#include "class_55.h" -#include "class_56.h" -#include "class_87.h" -#include "class_93.h" -#include "class_27.h" -#include -#include -#include -#include -#include - -class_31::class_31() {} -class_31::~class_31() {} diff --git a/lib/waf/build/lib_9/class_31.h b/lib/waf/build/lib_9/class_31.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_31.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_31_h_ -#define class_31_h_ - -class class_31 { -public: - class_31(); - ~class_31(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_32.cpp b/lib/waf/build/lib_9/class_32.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_32.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_32.h" -#include "class_30.h" -#include "class_75.h" -#include "class_20.h" -#include "class_62.h" -#include "class_19.h" -#include "class_77.h" -#include "class_85.h" -#include "class_6.h" -#include "class_14.h" -#include "class_11.h" -#include "class_99.h" -#include "class_35.h" -#include "class_25.h" -#include "class_70.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_32::class_32() {} -class_32::~class_32() {} diff --git a/lib/waf/build/lib_9/class_32.h b/lib/waf/build/lib_9/class_32.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_32.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_32_h_ -#define class_32_h_ - -class class_32 { -public: - class_32(); - ~class_32(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_33.cpp b/lib/waf/build/lib_9/class_33.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_33.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_33.h" -#include "class_24.h" -#include "class_96.h" -#include "class_85.h" -#include "class_83.h" -#include "class_71.h" -#include "class_72.h" -#include "class_53.h" -#include "class_92.h" -#include "class_1.h" -#include "class_55.h" -#include "class_10.h" -#include "class_97.h" -#include "class_49.h" -#include "class_60.h" -#include "class_18.h" -#include -#include -#include -#include -#include - -class_33::class_33() {} -class_33::~class_33() {} diff --git a/lib/waf/build/lib_9/class_33.h b/lib/waf/build/lib_9/class_33.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_33.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_33_h_ -#define class_33_h_ - -class class_33 { -public: - class_33(); - ~class_33(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_34.cpp b/lib/waf/build/lib_9/class_34.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_34.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_34.h" -#include "class_89.h" -#include "class_39.h" -#include "class_86.h" -#include "class_32.h" -#include "class_26.h" -#include "class_99.h" -#include "class_9.h" -#include "class_80.h" -#include "class_37.h" -#include "class_40.h" -#include "class_70.h" -#include "class_74.h" -#include "class_62.h" -#include "class_35.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_34::class_34() {} -class_34::~class_34() {} diff --git a/lib/waf/build/lib_9/class_34.h b/lib/waf/build/lib_9/class_34.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_34.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_34_h_ -#define class_34_h_ - -class class_34 { -public: - class_34(); - ~class_34(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_35.cpp b/lib/waf/build/lib_9/class_35.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_35.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_35.h" -#include "class_64.h" -#include "class_84.h" -#include "class_37.h" -#include "class_11.h" -#include "class_99.h" -#include "class_39.h" -#include "class_90.h" -#include "class_47.h" -#include "class_17.h" -#include "class_13.h" -#include "class_55.h" -#include "class_68.h" -#include "class_5.h" -#include "class_29.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_35::class_35() {} -class_35::~class_35() {} diff --git a/lib/waf/build/lib_9/class_35.h b/lib/waf/build/lib_9/class_35.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_35.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_35_h_ -#define class_35_h_ - -class class_35 { -public: - class_35(); - ~class_35(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_36.cpp b/lib/waf/build/lib_9/class_36.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_36.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_36.h" -#include "class_36.h" -#include "class_74.h" -#include "class_21.h" -#include "class_40.h" -#include "class_68.h" -#include "class_83.h" -#include "class_29.h" -#include "class_66.h" -#include "class_89.h" -#include "class_4.h" -#include "class_5.h" -#include "class_37.h" -#include "class_71.h" -#include "class_38.h" -#include "class_22.h" -#include -#include -#include -#include -#include - -class_36::class_36() {} -class_36::~class_36() {} diff --git a/lib/waf/build/lib_9/class_36.h b/lib/waf/build/lib_9/class_36.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_36.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_36_h_ -#define class_36_h_ - -class class_36 { -public: - class_36(); - ~class_36(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_37.cpp b/lib/waf/build/lib_9/class_37.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_37.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_37.h" -#include "class_67.h" -#include "class_4.h" -#include "class_31.h" -#include "class_79.h" -#include "class_87.h" -#include "class_95.h" -#include "class_23.h" -#include "class_19.h" -#include "class_8.h" -#include "class_73.h" -#include "class_93.h" -#include "class_94.h" -#include "class_27.h" -#include "class_66.h" -#include "class_78.h" -#include -#include -#include -#include -#include - -class_37::class_37() {} -class_37::~class_37() {} diff --git a/lib/waf/build/lib_9/class_37.h b/lib/waf/build/lib_9/class_37.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_37.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_37_h_ -#define class_37_h_ - -class class_37 { -public: - class_37(); - ~class_37(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_38.cpp b/lib/waf/build/lib_9/class_38.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_38.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_38.h" -#include "class_40.h" -#include "class_83.h" -#include "class_7.h" -#include "class_82.h" -#include "class_67.h" -#include "class_1.h" -#include "class_68.h" -#include "class_39.h" -#include "class_96.h" -#include "class_25.h" -#include "class_43.h" -#include "class_48.h" -#include "class_0.h" -#include "class_95.h" -#include "class_6.h" -#include -#include -#include -#include -#include - -class_38::class_38() {} -class_38::~class_38() {} diff --git a/lib/waf/build/lib_9/class_38.h b/lib/waf/build/lib_9/class_38.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_38.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_38_h_ -#define class_38_h_ - -class class_38 { -public: - class_38(); - ~class_38(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_39.cpp b/lib/waf/build/lib_9/class_39.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_39.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_39.h" -#include "class_75.h" -#include "class_61.h" -#include "class_2.h" -#include "class_4.h" -#include "class_25.h" -#include "class_9.h" -#include "class_74.h" -#include "class_56.h" -#include "class_90.h" -#include "class_81.h" -#include "class_20.h" -#include "class_91.h" -#include "class_50.h" -#include "class_63.h" -#include "class_38.h" -#include -#include -#include -#include -#include - -class_39::class_39() {} -class_39::~class_39() {} diff --git a/lib/waf/build/lib_9/class_39.h b/lib/waf/build/lib_9/class_39.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_39.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_39_h_ -#define class_39_h_ - -class class_39 { -public: - class_39(); - ~class_39(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_4.cpp b/lib/waf/build/lib_9/class_4.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_4.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_4.h" -#include "class_85.h" -#include "class_55.h" -#include "class_34.h" -#include "class_6.h" -#include "class_37.h" -#include "class_9.h" -#include "class_81.h" -#include "class_79.h" -#include "class_69.h" -#include "class_38.h" -#include "class_7.h" -#include "class_48.h" -#include "class_80.h" -#include "class_82.h" -#include "class_40.h" -#include -#include -#include -#include -#include - -class_4::class_4() {} -class_4::~class_4() {} diff --git a/lib/waf/build/lib_9/class_4.h b/lib/waf/build/lib_9/class_4.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_4_h_ -#define class_4_h_ - -class class_4 { -public: - class_4(); - ~class_4(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_40.cpp b/lib/waf/build/lib_9/class_40.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_40.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_40.h" -#include "class_93.h" -#include "class_16.h" -#include "class_21.h" -#include "class_34.h" -#include "class_41.h" -#include "class_68.h" -#include "class_51.h" -#include "class_80.h" -#include "class_15.h" -#include "class_56.h" -#include "class_31.h" -#include "class_76.h" -#include "class_72.h" -#include "class_37.h" -#include "class_90.h" -#include -#include -#include -#include -#include - -class_40::class_40() {} -class_40::~class_40() {} diff --git a/lib/waf/build/lib_9/class_40.h b/lib/waf/build/lib_9/class_40.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_40.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_40_h_ -#define class_40_h_ - -class class_40 { -public: - class_40(); - ~class_40(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_41.cpp b/lib/waf/build/lib_9/class_41.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_41.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_41.h" -#include "class_48.h" -#include "class_92.h" -#include "class_61.h" -#include "class_18.h" -#include "class_13.h" -#include "class_65.h" -#include "class_4.h" -#include "class_90.h" -#include "class_23.h" -#include "class_98.h" -#include "class_85.h" -#include "class_74.h" -#include "class_37.h" -#include "class_62.h" -#include "class_51.h" -#include -#include -#include -#include -#include - -class_41::class_41() {} -class_41::~class_41() {} diff --git a/lib/waf/build/lib_9/class_41.h b/lib/waf/build/lib_9/class_41.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_41.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_41_h_ -#define class_41_h_ - -class class_41 { -public: - class_41(); - ~class_41(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_42.cpp b/lib/waf/build/lib_9/class_42.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_42.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_42.h" -#include "class_32.h" -#include "class_53.h" -#include "class_4.h" -#include "class_98.h" -#include "class_59.h" -#include "class_85.h" -#include "class_5.h" -#include "class_65.h" -#include "class_23.h" -#include "class_78.h" -#include "class_84.h" -#include "class_36.h" -#include "class_0.h" -#include "class_19.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_42::class_42() {} -class_42::~class_42() {} diff --git a/lib/waf/build/lib_9/class_42.h b/lib/waf/build/lib_9/class_42.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_42.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_42_h_ -#define class_42_h_ - -class class_42 { -public: - class_42(); - ~class_42(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_43.cpp b/lib/waf/build/lib_9/class_43.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_43.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_43.h" -#include "class_52.h" -#include "class_93.h" -#include "class_95.h" -#include "class_69.h" -#include "class_67.h" -#include "class_23.h" -#include "class_1.h" -#include "class_87.h" -#include "class_77.h" -#include "class_84.h" -#include "class_22.h" -#include "class_44.h" -#include "class_0.h" -#include "class_34.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_43::class_43() {} -class_43::~class_43() {} diff --git a/lib/waf/build/lib_9/class_43.h b/lib/waf/build/lib_9/class_43.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_43.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_43_h_ -#define class_43_h_ - -class class_43 { -public: - class_43(); - ~class_43(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_44.cpp b/lib/waf/build/lib_9/class_44.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_44.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_44.h" -#include "class_99.h" -#include "class_19.h" -#include "class_70.h" -#include "class_79.h" -#include "class_93.h" -#include "class_30.h" -#include "class_86.h" -#include "class_82.h" -#include "class_91.h" -#include "class_36.h" -#include "class_34.h" -#include "class_38.h" -#include "class_13.h" -#include "class_8.h" -#include "class_89.h" -#include -#include -#include -#include -#include - -class_44::class_44() {} -class_44::~class_44() {} diff --git a/lib/waf/build/lib_9/class_44.h b/lib/waf/build/lib_9/class_44.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_44_h_ -#define class_44_h_ - -class class_44 { -public: - class_44(); - ~class_44(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_45.cpp b/lib/waf/build/lib_9/class_45.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_45.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_45.h" -#include "class_22.h" -#include "class_68.h" -#include "class_7.h" -#include "class_90.h" -#include "class_2.h" -#include "class_75.h" -#include "class_19.h" -#include "class_51.h" -#include "class_76.h" -#include "class_12.h" -#include "class_20.h" -#include "class_56.h" -#include "class_57.h" -#include "class_91.h" -#include "class_3.h" -#include -#include -#include -#include -#include - -class_45::class_45() {} -class_45::~class_45() {} diff --git a/lib/waf/build/lib_9/class_45.h b/lib/waf/build/lib_9/class_45.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_45.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_45_h_ -#define class_45_h_ - -class class_45 { -public: - class_45(); - ~class_45(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_46.cpp b/lib/waf/build/lib_9/class_46.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_46.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_46.h" -#include "class_3.h" -#include "class_53.h" -#include "class_80.h" -#include "class_19.h" -#include "class_98.h" -#include "class_83.h" -#include "class_94.h" -#include "class_59.h" -#include "class_85.h" -#include "class_13.h" -#include "class_14.h" -#include "class_6.h" -#include "class_89.h" -#include "class_56.h" -#include "class_34.h" -#include -#include -#include -#include -#include - -class_46::class_46() {} -class_46::~class_46() {} diff --git a/lib/waf/build/lib_9/class_46.h b/lib/waf/build/lib_9/class_46.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_46.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_46_h_ -#define class_46_h_ - -class class_46 { -public: - class_46(); - ~class_46(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_47.cpp b/lib/waf/build/lib_9/class_47.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_47.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_47.h" -#include "class_16.h" -#include "class_92.h" -#include "class_58.h" -#include "class_53.h" -#include "class_80.h" -#include "class_93.h" -#include "class_19.h" -#include "class_39.h" -#include "class_59.h" -#include "class_69.h" -#include "class_89.h" -#include "class_81.h" -#include "class_14.h" -#include "class_96.h" -#include "class_12.h" -#include -#include -#include -#include -#include - -class_47::class_47() {} -class_47::~class_47() {} diff --git a/lib/waf/build/lib_9/class_47.h b/lib/waf/build/lib_9/class_47.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_47.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_47_h_ -#define class_47_h_ - -class class_47 { -public: - class_47(); - ~class_47(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_48.cpp b/lib/waf/build/lib_9/class_48.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_48.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_48.h" -#include "class_93.h" -#include "class_76.h" -#include "class_8.h" -#include "class_75.h" -#include "class_53.h" -#include "class_22.h" -#include "class_62.h" -#include "class_95.h" -#include "class_28.h" -#include "class_9.h" -#include "class_24.h" -#include "class_34.h" -#include "class_39.h" -#include "class_98.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_48::class_48() {} -class_48::~class_48() {} diff --git a/lib/waf/build/lib_9/class_48.h b/lib/waf/build/lib_9/class_48.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_48.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_48_h_ -#define class_48_h_ - -class class_48 { -public: - class_48(); - ~class_48(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_49.cpp b/lib/waf/build/lib_9/class_49.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_49.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_49.h" -#include "class_66.h" -#include "class_6.h" -#include "class_20.h" -#include "class_5.h" -#include "class_28.h" -#include "class_60.h" -#include "class_40.h" -#include "class_56.h" -#include "class_10.h" -#include "class_49.h" -#include "class_98.h" -#include "class_19.h" -#include "class_42.h" -#include "class_94.h" -#include "class_91.h" -#include -#include -#include -#include -#include - -class_49::class_49() {} -class_49::~class_49() {} diff --git a/lib/waf/build/lib_9/class_49.h b/lib/waf/build/lib_9/class_49.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_49.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_49_h_ -#define class_49_h_ - -class class_49 { -public: - class_49(); - ~class_49(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_5.cpp b/lib/waf/build/lib_9/class_5.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_5.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_5.h" -#include "class_9.h" -#include "class_76.h" -#include "class_28.h" -#include "class_42.h" -#include "class_49.h" -#include "class_81.h" -#include "class_22.h" -#include "class_45.h" -#include "class_93.h" -#include "class_60.h" -#include "class_80.h" -#include "class_25.h" -#include "class_17.h" -#include "class_48.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_5::class_5() {} -class_5::~class_5() {} diff --git a/lib/waf/build/lib_9/class_5.h b/lib/waf/build/lib_9/class_5.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_5.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_5_h_ -#define class_5_h_ - -class class_5 { -public: - class_5(); - ~class_5(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_50.cpp b/lib/waf/build/lib_9/class_50.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_50.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_50.h" -#include "class_76.h" -#include "class_95.h" -#include "class_38.h" -#include "class_27.h" -#include "class_90.h" -#include "class_35.h" -#include "class_93.h" -#include "class_80.h" -#include "class_98.h" -#include "class_56.h" -#include "class_9.h" -#include "class_85.h" -#include "class_88.h" -#include "class_23.h" -#include "class_0.h" -#include -#include -#include -#include -#include - -class_50::class_50() {} -class_50::~class_50() {} diff --git a/lib/waf/build/lib_9/class_50.h b/lib/waf/build/lib_9/class_50.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_50_h_ -#define class_50_h_ - -class class_50 { -public: - class_50(); - ~class_50(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_51.cpp b/lib/waf/build/lib_9/class_51.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_51.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_51.h" -#include "class_4.h" -#include "class_35.h" -#include "class_25.h" -#include "class_19.h" -#include "class_78.h" -#include "class_27.h" -#include "class_94.h" -#include "class_85.h" -#include "class_13.h" -#include "class_51.h" -#include "class_95.h" -#include "class_97.h" -#include "class_30.h" -#include "class_69.h" -#include "class_36.h" -#include -#include -#include -#include -#include - -class_51::class_51() {} -class_51::~class_51() {} diff --git a/lib/waf/build/lib_9/class_51.h b/lib/waf/build/lib_9/class_51.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_51.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_51_h_ -#define class_51_h_ - -class class_51 { -public: - class_51(); - ~class_51(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_52.cpp b/lib/waf/build/lib_9/class_52.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_52.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_52.h" -#include "class_31.h" -#include "class_3.h" -#include "class_74.h" -#include "class_9.h" -#include "class_47.h" -#include "class_90.h" -#include "class_65.h" -#include "class_91.h" -#include "class_17.h" -#include "class_44.h" -#include "class_5.h" -#include "class_75.h" -#include "class_79.h" -#include "class_63.h" -#include "class_20.h" -#include -#include -#include -#include -#include - -class_52::class_52() {} -class_52::~class_52() {} diff --git a/lib/waf/build/lib_9/class_52.h b/lib/waf/build/lib_9/class_52.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_52.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_52_h_ -#define class_52_h_ - -class class_52 { -public: - class_52(); - ~class_52(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_53.cpp b/lib/waf/build/lib_9/class_53.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_53.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_53.h" -#include "class_32.h" -#include "class_53.h" -#include "class_41.h" -#include "class_57.h" -#include "class_28.h" -#include "class_80.h" -#include "class_79.h" -#include "class_48.h" -#include "class_30.h" -#include "class_16.h" -#include "class_1.h" -#include "class_83.h" -#include "class_5.h" -#include "class_3.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_53::class_53() {} -class_53::~class_53() {} diff --git a/lib/waf/build/lib_9/class_53.h b/lib/waf/build/lib_9/class_53.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_53.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_53_h_ -#define class_53_h_ - -class class_53 { -public: - class_53(); - ~class_53(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_54.cpp b/lib/waf/build/lib_9/class_54.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_54.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_54.h" -#include "class_17.h" -#include "class_5.h" -#include "class_88.h" -#include "class_52.h" -#include "class_97.h" -#include "class_74.h" -#include "class_6.h" -#include "class_39.h" -#include "class_65.h" -#include "class_81.h" -#include "class_69.h" -#include "class_99.h" -#include "class_86.h" -#include "class_13.h" -#include "class_33.h" -#include -#include -#include -#include -#include - -class_54::class_54() {} -class_54::~class_54() {} diff --git a/lib/waf/build/lib_9/class_54.h b/lib/waf/build/lib_9/class_54.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_54.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_54_h_ -#define class_54_h_ - -class class_54 { -public: - class_54(); - ~class_54(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_55.cpp b/lib/waf/build/lib_9/class_55.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_55.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_55.h" -#include "class_64.h" -#include "class_76.h" -#include "class_11.h" -#include "class_83.h" -#include "class_57.h" -#include "class_81.h" -#include "class_65.h" -#include "class_96.h" -#include "class_93.h" -#include "class_14.h" -#include "class_42.h" -#include "class_34.h" -#include "class_38.h" -#include "class_70.h" -#include "class_97.h" -#include -#include -#include -#include -#include - -class_55::class_55() {} -class_55::~class_55() {} diff --git a/lib/waf/build/lib_9/class_55.h b/lib/waf/build/lib_9/class_55.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_55.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_55_h_ -#define class_55_h_ - -class class_55 { -public: - class_55(); - ~class_55(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_56.cpp b/lib/waf/build/lib_9/class_56.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_56.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_56.h" -#include "class_58.h" -#include "class_35.h" -#include "class_40.h" -#include "class_34.h" -#include "class_21.h" -#include "class_97.h" -#include "class_4.h" -#include "class_22.h" -#include "class_88.h" -#include "class_13.h" -#include "class_39.h" -#include "class_96.h" -#include "class_24.h" -#include "class_5.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_56::class_56() {} -class_56::~class_56() {} diff --git a/lib/waf/build/lib_9/class_56.h b/lib/waf/build/lib_9/class_56.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_56.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_56_h_ -#define class_56_h_ - -class class_56 { -public: - class_56(); - ~class_56(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_57.cpp b/lib/waf/build/lib_9/class_57.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_57.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_57.h" -#include "class_8.h" -#include "class_97.h" -#include "class_52.h" -#include "class_93.h" -#include "class_35.h" -#include "class_6.h" -#include "class_51.h" -#include "class_27.h" -#include "class_19.h" -#include "class_63.h" -#include "class_86.h" -#include "class_40.h" -#include "class_18.h" -#include "class_92.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_57::class_57() {} -class_57::~class_57() {} diff --git a/lib/waf/build/lib_9/class_57.h b/lib/waf/build/lib_9/class_57.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_57.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_57_h_ -#define class_57_h_ - -class class_57 { -public: - class_57(); - ~class_57(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_58.cpp b/lib/waf/build/lib_9/class_58.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_58.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_58.h" -#include "class_70.h" -#include "class_20.h" -#include "class_85.h" -#include "class_74.h" -#include "class_41.h" -#include "class_17.h" -#include "class_2.h" -#include "class_63.h" -#include "class_97.h" -#include "class_76.h" -#include "class_55.h" -#include "class_72.h" -#include "class_36.h" -#include "class_52.h" -#include "class_56.h" -#include -#include -#include -#include -#include - -class_58::class_58() {} -class_58::~class_58() {} diff --git a/lib/waf/build/lib_9/class_58.h b/lib/waf/build/lib_9/class_58.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_58.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_58_h_ -#define class_58_h_ - -class class_58 { -public: - class_58(); - ~class_58(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_59.cpp b/lib/waf/build/lib_9/class_59.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_59.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_59.h" -#include "class_64.h" -#include "class_97.h" -#include "class_94.h" -#include "class_71.h" -#include "class_43.h" -#include "class_70.h" -#include "class_88.h" -#include "class_25.h" -#include "class_59.h" -#include "class_20.h" -#include "class_51.h" -#include "class_18.h" -#include "class_6.h" -#include "class_5.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_59::class_59() {} -class_59::~class_59() {} diff --git a/lib/waf/build/lib_9/class_59.h b/lib/waf/build/lib_9/class_59.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_59.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_59_h_ -#define class_59_h_ - -class class_59 { -public: - class_59(); - ~class_59(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_6.cpp b/lib/waf/build/lib_9/class_6.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_6.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_6.h" -#include "class_84.h" -#include "class_71.h" -#include "class_28.h" -#include "class_95.h" -#include "class_54.h" -#include "class_31.h" -#include "class_41.h" -#include "class_86.h" -#include "class_97.h" -#include "class_7.h" -#include "class_49.h" -#include "class_88.h" -#include "class_42.h" -#include "class_12.h" -#include "class_50.h" -#include -#include -#include -#include -#include - -class_6::class_6() {} -class_6::~class_6() {} diff --git a/lib/waf/build/lib_9/class_6.h b/lib/waf/build/lib_9/class_6.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_6.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_6_h_ -#define class_6_h_ - -class class_6 { -public: - class_6(); - ~class_6(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_60.cpp b/lib/waf/build/lib_9/class_60.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_60.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_60.h" -#include "class_95.h" -#include "class_90.h" -#include "class_34.h" -#include "class_41.h" -#include "class_53.h" -#include "class_9.h" -#include "class_26.h" -#include "class_77.h" -#include "class_40.h" -#include "class_91.h" -#include "class_6.h" -#include "class_16.h" -#include "class_5.h" -#include "class_32.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_60::class_60() {} -class_60::~class_60() {} diff --git a/lib/waf/build/lib_9/class_60.h b/lib/waf/build/lib_9/class_60.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_60.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_60_h_ -#define class_60_h_ - -class class_60 { -public: - class_60(); - ~class_60(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_61.cpp b/lib/waf/build/lib_9/class_61.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_61.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_61.h" -#include "class_85.h" -#include "class_90.h" -#include "class_68.h" -#include "class_21.h" -#include "class_99.h" -#include "class_23.h" -#include "class_88.h" -#include "class_81.h" -#include "class_72.h" -#include "class_11.h" -#include "class_48.h" -#include "class_15.h" -#include "class_42.h" -#include "class_32.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_61::class_61() {} -class_61::~class_61() {} diff --git a/lib/waf/build/lib_9/class_61.h b/lib/waf/build/lib_9/class_61.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_61.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_61_h_ -#define class_61_h_ - -class class_61 { -public: - class_61(); - ~class_61(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_62.cpp b/lib/waf/build/lib_9/class_62.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_62.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_62.h" -#include "class_22.h" -#include "class_26.h" -#include "class_86.h" -#include "class_65.h" -#include "class_36.h" -#include "class_28.h" -#include "class_58.h" -#include "class_14.h" -#include "class_15.h" -#include "class_85.h" -#include "class_89.h" -#include "class_27.h" -#include "class_38.h" -#include "class_87.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_62::class_62() {} -class_62::~class_62() {} diff --git a/lib/waf/build/lib_9/class_62.h b/lib/waf/build/lib_9/class_62.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_62.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_62_h_ -#define class_62_h_ - -class class_62 { -public: - class_62(); - ~class_62(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_63.cpp b/lib/waf/build/lib_9/class_63.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_63.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_63.h" -#include "class_86.h" -#include "class_25.h" -#include "class_78.h" -#include "class_41.h" -#include "class_54.h" -#include "class_79.h" -#include "class_21.h" -#include "class_60.h" -#include "class_62.h" -#include "class_88.h" -#include "class_82.h" -#include "class_94.h" -#include "class_18.h" -#include "class_76.h" -#include "class_44.h" -#include -#include -#include -#include -#include - -class_63::class_63() {} -class_63::~class_63() {} diff --git a/lib/waf/build/lib_9/class_63.h b/lib/waf/build/lib_9/class_63.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_63.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_63_h_ -#define class_63_h_ - -class class_63 { -public: - class_63(); - ~class_63(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_64.cpp b/lib/waf/build/lib_9/class_64.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_64.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_64.h" -#include "class_18.h" -#include "class_11.h" -#include "class_9.h" -#include "class_7.h" -#include "class_22.h" -#include "class_12.h" -#include "class_61.h" -#include "class_21.h" -#include "class_19.h" -#include "class_86.h" -#include "class_56.h" -#include "class_62.h" -#include "class_89.h" -#include "class_31.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_64::class_64() {} -class_64::~class_64() {} diff --git a/lib/waf/build/lib_9/class_64.h b/lib/waf/build/lib_9/class_64.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_64_h_ -#define class_64_h_ - -class class_64 { -public: - class_64(); - ~class_64(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_65.cpp b/lib/waf/build/lib_9/class_65.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_65.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_65.h" -#include "class_90.h" -#include "class_48.h" -#include "class_20.h" -#include "class_25.h" -#include "class_73.h" -#include "class_97.h" -#include "class_93.h" -#include "class_50.h" -#include "class_28.h" -#include "class_95.h" -#include "class_84.h" -#include "class_22.h" -#include "class_47.h" -#include "class_74.h" -#include "class_60.h" -#include -#include -#include -#include -#include - -class_65::class_65() {} -class_65::~class_65() {} diff --git a/lib/waf/build/lib_9/class_65.h b/lib/waf/build/lib_9/class_65.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_65.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_65_h_ -#define class_65_h_ - -class class_65 { -public: - class_65(); - ~class_65(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_66.cpp b/lib/waf/build/lib_9/class_66.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_66.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_66.h" -#include "class_96.h" -#include "class_98.h" -#include "class_90.h" -#include "class_83.h" -#include "class_53.h" -#include "class_12.h" -#include "class_26.h" -#include "class_39.h" -#include "class_5.h" -#include "class_89.h" -#include "class_93.h" -#include "class_30.h" -#include "class_92.h" -#include "class_69.h" -#include "class_45.h" -#include -#include -#include -#include -#include - -class_66::class_66() {} -class_66::~class_66() {} diff --git a/lib/waf/build/lib_9/class_66.h b/lib/waf/build/lib_9/class_66.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_66.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_66_h_ -#define class_66_h_ - -class class_66 { -public: - class_66(); - ~class_66(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_67.cpp b/lib/waf/build/lib_9/class_67.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_67.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_67.h" -#include "class_75.h" -#include "class_66.h" -#include "class_65.h" -#include "class_96.h" -#include "class_33.h" -#include "class_70.h" -#include "class_98.h" -#include "class_56.h" -#include "class_71.h" -#include "class_38.h" -#include "class_88.h" -#include "class_8.h" -#include "class_35.h" -#include "class_69.h" -#include "class_93.h" -#include -#include -#include -#include -#include - -class_67::class_67() {} -class_67::~class_67() {} diff --git a/lib/waf/build/lib_9/class_67.h b/lib/waf/build/lib_9/class_67.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_67.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_67_h_ -#define class_67_h_ - -class class_67 { -public: - class_67(); - ~class_67(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_68.cpp b/lib/waf/build/lib_9/class_68.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_68.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_68.h" -#include "class_39.h" -#include "class_9.h" -#include "class_7.h" -#include "class_52.h" -#include "class_50.h" -#include "class_98.h" -#include "class_94.h" -#include "class_19.h" -#include "class_66.h" -#include "class_53.h" -#include "class_25.h" -#include "class_10.h" -#include "class_2.h" -#include "class_59.h" -#include "class_48.h" -#include -#include -#include -#include -#include - -class_68::class_68() {} -class_68::~class_68() {} diff --git a/lib/waf/build/lib_9/class_68.h b/lib/waf/build/lib_9/class_68.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_68.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_68_h_ -#define class_68_h_ - -class class_68 { -public: - class_68(); - ~class_68(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_69.cpp b/lib/waf/build/lib_9/class_69.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_69.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_69.h" -#include "class_20.h" -#include "class_28.h" -#include "class_58.h" -#include "class_35.h" -#include "class_69.h" -#include "class_12.h" -#include "class_43.h" -#include "class_47.h" -#include "class_56.h" -#include "class_31.h" -#include "class_95.h" -#include "class_55.h" -#include "class_5.h" -#include "class_96.h" -#include "class_86.h" -#include -#include -#include -#include -#include - -class_69::class_69() {} -class_69::~class_69() {} diff --git a/lib/waf/build/lib_9/class_69.h b/lib/waf/build/lib_9/class_69.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_69.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_69_h_ -#define class_69_h_ - -class class_69 { -public: - class_69(); - ~class_69(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_7.cpp b/lib/waf/build/lib_9/class_7.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_7.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_7.h" -#include "class_44.h" -#include "class_42.h" -#include "class_13.h" -#include "class_34.h" -#include "class_14.h" -#include "class_97.h" -#include "class_4.h" -#include "class_74.h" -#include "class_68.h" -#include "class_83.h" -#include "class_46.h" -#include "class_30.h" -#include "class_45.h" -#include "class_79.h" -#include "class_31.h" -#include -#include -#include -#include -#include - -class_7::class_7() {} -class_7::~class_7() {} diff --git a/lib/waf/build/lib_9/class_7.h b/lib/waf/build/lib_9/class_7.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_7.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_7_h_ -#define class_7_h_ - -class class_7 { -public: - class_7(); - ~class_7(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_70.cpp b/lib/waf/build/lib_9/class_70.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_70.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_70.h" -#include "class_90.h" -#include "class_56.h" -#include "class_47.h" -#include "class_48.h" -#include "class_15.h" -#include "class_58.h" -#include "class_74.h" -#include "class_45.h" -#include "class_1.h" -#include "class_11.h" -#include "class_26.h" -#include "class_24.h" -#include "class_92.h" -#include "class_33.h" -#include "class_7.h" -#include -#include -#include -#include -#include - -class_70::class_70() {} -class_70::~class_70() {} diff --git a/lib/waf/build/lib_9/class_70.h b/lib/waf/build/lib_9/class_70.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_70.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_70_h_ -#define class_70_h_ - -class class_70 { -public: - class_70(); - ~class_70(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_71.cpp b/lib/waf/build/lib_9/class_71.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_71.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_71.h" -#include "class_63.h" -#include "class_0.h" -#include "class_98.h" -#include "class_77.h" -#include "class_68.h" -#include "class_18.h" -#include "class_33.h" -#include "class_80.h" -#include "class_76.h" -#include "class_99.h" -#include "class_12.h" -#include "class_67.h" -#include "class_56.h" -#include "class_45.h" -#include "class_13.h" -#include -#include -#include -#include -#include - -class_71::class_71() {} -class_71::~class_71() {} diff --git a/lib/waf/build/lib_9/class_71.h b/lib/waf/build/lib_9/class_71.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_71.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_71_h_ -#define class_71_h_ - -class class_71 { -public: - class_71(); - ~class_71(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_72.cpp b/lib/waf/build/lib_9/class_72.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_72.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_72.h" -#include "class_24.h" -#include "class_40.h" -#include "class_13.h" -#include "class_25.h" -#include "class_47.h" -#include "class_27.h" -#include "class_90.h" -#include "class_38.h" -#include "class_23.h" -#include "class_71.h" -#include "class_46.h" -#include "class_9.h" -#include "class_59.h" -#include "class_32.h" -#include "class_35.h" -#include -#include -#include -#include -#include - -class_72::class_72() {} -class_72::~class_72() {} diff --git a/lib/waf/build/lib_9/class_72.h b/lib/waf/build/lib_9/class_72.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_72.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_72_h_ -#define class_72_h_ - -class class_72 { -public: - class_72(); - ~class_72(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_73.cpp b/lib/waf/build/lib_9/class_73.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_73.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_73.h" -#include "class_65.h" -#include "class_89.h" -#include "class_46.h" -#include "class_36.h" -#include "class_38.h" -#include "class_86.h" -#include "class_85.h" -#include "class_0.h" -#include "class_78.h" -#include "class_32.h" -#include "class_19.h" -#include "class_92.h" -#include "class_50.h" -#include "class_31.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_73::class_73() {} -class_73::~class_73() {} diff --git a/lib/waf/build/lib_9/class_73.h b/lib/waf/build/lib_9/class_73.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_73.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_73_h_ -#define class_73_h_ - -class class_73 { -public: - class_73(); - ~class_73(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_74.cpp b/lib/waf/build/lib_9/class_74.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_74.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_74.h" -#include "class_67.h" -#include "class_34.h" -#include "class_64.h" -#include "class_86.h" -#include "class_65.h" -#include "class_74.h" -#include "class_72.h" -#include "class_3.h" -#include "class_57.h" -#include "class_93.h" -#include "class_76.h" -#include "class_32.h" -#include "class_35.h" -#include "class_0.h" -#include "class_59.h" -#include -#include -#include -#include -#include - -class_74::class_74() {} -class_74::~class_74() {} diff --git a/lib/waf/build/lib_9/class_74.h b/lib/waf/build/lib_9/class_74.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_74.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_74_h_ -#define class_74_h_ - -class class_74 { -public: - class_74(); - ~class_74(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_75.cpp b/lib/waf/build/lib_9/class_75.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_75.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_75.h" -#include "class_34.h" -#include "class_46.h" -#include "class_50.h" -#include "class_61.h" -#include "class_7.h" -#include "class_68.h" -#include "class_66.h" -#include "class_69.h" -#include "class_78.h" -#include "class_58.h" -#include "class_70.h" -#include "class_52.h" -#include "class_77.h" -#include "class_64.h" -#include "class_54.h" -#include -#include -#include -#include -#include - -class_75::class_75() {} -class_75::~class_75() {} diff --git a/lib/waf/build/lib_9/class_75.h b/lib/waf/build/lib_9/class_75.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_75.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_75_h_ -#define class_75_h_ - -class class_75 { -public: - class_75(); - ~class_75(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_76.cpp b/lib/waf/build/lib_9/class_76.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_76.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_76.h" -#include "class_52.h" -#include "class_32.h" -#include "class_88.h" -#include "class_51.h" -#include "class_10.h" -#include "class_16.h" -#include "class_54.h" -#include "class_78.h" -#include "class_49.h" -#include "class_93.h" -#include "class_64.h" -#include "class_21.h" -#include "class_96.h" -#include "class_14.h" -#include "class_87.h" -#include -#include -#include -#include -#include - -class_76::class_76() {} -class_76::~class_76() {} diff --git a/lib/waf/build/lib_9/class_76.h b/lib/waf/build/lib_9/class_76.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_76.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_76_h_ -#define class_76_h_ - -class class_76 { -public: - class_76(); - ~class_76(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_77.cpp b/lib/waf/build/lib_9/class_77.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_77.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_77.h" -#include "class_97.h" -#include "class_81.h" -#include "class_67.h" -#include "class_73.h" -#include "class_79.h" -#include "class_25.h" -#include "class_2.h" -#include "class_46.h" -#include "class_94.h" -#include "class_5.h" -#include "class_70.h" -#include "class_13.h" -#include "class_11.h" -#include "class_90.h" -#include "class_95.h" -#include -#include -#include -#include -#include - -class_77::class_77() {} -class_77::~class_77() {} diff --git a/lib/waf/build/lib_9/class_77.h b/lib/waf/build/lib_9/class_77.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_77.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_77_h_ -#define class_77_h_ - -class class_77 { -public: - class_77(); - ~class_77(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_78.cpp b/lib/waf/build/lib_9/class_78.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_78.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_78.h" -#include "class_69.h" -#include "class_36.h" -#include "class_34.h" -#include "class_80.h" -#include "class_75.h" -#include "class_16.h" -#include "class_45.h" -#include "class_48.h" -#include "class_13.h" -#include "class_49.h" -#include "class_92.h" -#include "class_65.h" -#include "class_23.h" -#include "class_51.h" -#include "class_71.h" -#include -#include -#include -#include -#include - -class_78::class_78() {} -class_78::~class_78() {} diff --git a/lib/waf/build/lib_9/class_78.h b/lib/waf/build/lib_9/class_78.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_78.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_78_h_ -#define class_78_h_ - -class class_78 { -public: - class_78(); - ~class_78(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_79.cpp b/lib/waf/build/lib_9/class_79.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_79.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_79.h" -#include "class_53.h" -#include "class_58.h" -#include "class_34.h" -#include "class_42.h" -#include "class_74.h" -#include "class_81.h" -#include "class_66.h" -#include "class_28.h" -#include "class_19.h" -#include "class_47.h" -#include "class_51.h" -#include "class_65.h" -#include "class_73.h" -#include "class_54.h" -#include "class_46.h" -#include -#include -#include -#include -#include - -class_79::class_79() {} -class_79::~class_79() {} diff --git a/lib/waf/build/lib_9/class_79.h b/lib/waf/build/lib_9/class_79.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_79.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_79_h_ -#define class_79_h_ - -class class_79 { -public: - class_79(); - ~class_79(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_8.cpp b/lib/waf/build/lib_9/class_8.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_8.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_8.h" -#include "class_34.h" -#include "class_13.h" -#include "class_5.h" -#include "class_72.h" -#include "class_0.h" -#include "class_49.h" -#include "class_85.h" -#include "class_48.h" -#include "class_15.h" -#include "class_51.h" -#include "class_97.h" -#include "class_89.h" -#include "class_86.h" -#include "class_76.h" -#include "class_68.h" -#include -#include -#include -#include -#include - -class_8::class_8() {} -class_8::~class_8() {} diff --git a/lib/waf/build/lib_9/class_8.h b/lib/waf/build/lib_9/class_8.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_8.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_8_h_ -#define class_8_h_ - -class class_8 { -public: - class_8(); - ~class_8(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_80.cpp b/lib/waf/build/lib_9/class_80.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_80.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_80.h" -#include "class_41.h" -#include "class_76.h" -#include "class_29.h" -#include "class_98.h" -#include "class_74.h" -#include "class_50.h" -#include "class_1.h" -#include "class_70.h" -#include "class_67.h" -#include "class_88.h" -#include "class_97.h" -#include "class_75.h" -#include "class_89.h" -#include "class_55.h" -#include "class_8.h" -#include -#include -#include -#include -#include - -class_80::class_80() {} -class_80::~class_80() {} diff --git a/lib/waf/build/lib_9/class_80.h b/lib/waf/build/lib_9/class_80.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_80.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_80_h_ -#define class_80_h_ - -class class_80 { -public: - class_80(); - ~class_80(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_81.cpp b/lib/waf/build/lib_9/class_81.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_81.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_81.h" -#include "class_97.h" -#include "class_2.h" -#include "class_82.h" -#include "class_59.h" -#include "class_79.h" -#include "class_57.h" -#include "class_76.h" -#include "class_26.h" -#include "class_49.h" -#include "class_70.h" -#include "class_35.h" -#include "class_63.h" -#include "class_29.h" -#include "class_78.h" -#include "class_15.h" -#include -#include -#include -#include -#include - -class_81::class_81() {} -class_81::~class_81() {} diff --git a/lib/waf/build/lib_9/class_81.h b/lib/waf/build/lib_9/class_81.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_81.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_81_h_ -#define class_81_h_ - -class class_81 { -public: - class_81(); - ~class_81(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_82.cpp b/lib/waf/build/lib_9/class_82.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_82.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_82.h" -#include "class_67.h" -#include "class_66.h" -#include "class_28.h" -#include "class_69.h" -#include "class_77.h" -#include "class_91.h" -#include "class_8.h" -#include "class_68.h" -#include "class_41.h" -#include "class_31.h" -#include "class_95.h" -#include "class_64.h" -#include "class_6.h" -#include "class_86.h" -#include "class_79.h" -#include -#include -#include -#include -#include - -class_82::class_82() {} -class_82::~class_82() {} diff --git a/lib/waf/build/lib_9/class_82.h b/lib/waf/build/lib_9/class_82.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_82.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_82_h_ -#define class_82_h_ - -class class_82 { -public: - class_82(); - ~class_82(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_83.cpp b/lib/waf/build/lib_9/class_83.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_83.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_83.h" -#include "class_61.h" -#include "class_18.h" -#include "class_74.h" -#include "class_10.h" -#include "class_62.h" -#include "class_13.h" -#include "class_77.h" -#include "class_68.h" -#include "class_3.h" -#include "class_37.h" -#include "class_11.h" -#include "class_9.h" -#include "class_45.h" -#include "class_25.h" -#include "class_85.h" -#include -#include -#include -#include -#include - -class_83::class_83() {} -class_83::~class_83() {} diff --git a/lib/waf/build/lib_9/class_83.h b/lib/waf/build/lib_9/class_83.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_83.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_83_h_ -#define class_83_h_ - -class class_83 { -public: - class_83(); - ~class_83(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_84.cpp b/lib/waf/build/lib_9/class_84.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_84.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_84.h" -#include "class_76.h" -#include "class_5.h" -#include "class_81.h" -#include "class_56.h" -#include "class_7.h" -#include "class_64.h" -#include "class_32.h" -#include "class_73.h" -#include "class_8.h" -#include "class_12.h" -#include "class_9.h" -#include "class_23.h" -#include "class_29.h" -#include "class_1.h" -#include "class_53.h" -#include -#include -#include -#include -#include - -class_84::class_84() {} -class_84::~class_84() {} diff --git a/lib/waf/build/lib_9/class_84.h b/lib/waf/build/lib_9/class_84.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_84.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_84_h_ -#define class_84_h_ - -class class_84 { -public: - class_84(); - ~class_84(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_85.cpp b/lib/waf/build/lib_9/class_85.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_85.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_85.h" -#include "class_1.h" -#include "class_92.h" -#include "class_22.h" -#include "class_60.h" -#include "class_79.h" -#include "class_64.h" -#include "class_69.h" -#include "class_21.h" -#include "class_0.h" -#include "class_24.h" -#include "class_78.h" -#include "class_25.h" -#include "class_28.h" -#include "class_95.h" -#include "class_73.h" -#include -#include -#include -#include -#include - -class_85::class_85() {} -class_85::~class_85() {} diff --git a/lib/waf/build/lib_9/class_85.h b/lib/waf/build/lib_9/class_85.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_85.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_85_h_ -#define class_85_h_ - -class class_85 { -public: - class_85(); - ~class_85(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_86.cpp b/lib/waf/build/lib_9/class_86.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_86.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_86.h" -#include "class_30.h" -#include "class_6.h" -#include "class_16.h" -#include "class_37.h" -#include "class_39.h" -#include "class_70.h" -#include "class_54.h" -#include "class_48.h" -#include "class_52.h" -#include "class_1.h" -#include "class_0.h" -#include "class_66.h" -#include "class_93.h" -#include "class_46.h" -#include "class_4.h" -#include -#include -#include -#include -#include - -class_86::class_86() {} -class_86::~class_86() {} diff --git a/lib/waf/build/lib_9/class_86.h b/lib/waf/build/lib_9/class_86.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_86.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_86_h_ -#define class_86_h_ - -class class_86 { -public: - class_86(); - ~class_86(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_87.cpp b/lib/waf/build/lib_9/class_87.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_87.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_87.h" -#include "class_16.h" -#include "class_58.h" -#include "class_13.h" -#include "class_70.h" -#include "class_14.h" -#include "class_31.h" -#include "class_97.h" -#include "class_8.h" -#include "class_61.h" -#include "class_32.h" -#include "class_40.h" -#include "class_93.h" -#include "class_57.h" -#include "class_20.h" -#include "class_43.h" -#include -#include -#include -#include -#include - -class_87::class_87() {} -class_87::~class_87() {} diff --git a/lib/waf/build/lib_9/class_87.h b/lib/waf/build/lib_9/class_87.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_87.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_87_h_ -#define class_87_h_ - -class class_87 { -public: - class_87(); - ~class_87(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_88.cpp b/lib/waf/build/lib_9/class_88.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_88.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_88.h" -#include "class_82.h" -#include "class_66.h" -#include "class_84.h" -#include "class_79.h" -#include "class_40.h" -#include "class_46.h" -#include "class_37.h" -#include "class_80.h" -#include "class_78.h" -#include "class_51.h" -#include "class_57.h" -#include "class_36.h" -#include "class_32.h" -#include "class_11.h" -#include "class_26.h" -#include -#include -#include -#include -#include - -class_88::class_88() {} -class_88::~class_88() {} diff --git a/lib/waf/build/lib_9/class_88.h b/lib/waf/build/lib_9/class_88.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_88.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_88_h_ -#define class_88_h_ - -class class_88 { -public: - class_88(); - ~class_88(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_89.cpp b/lib/waf/build/lib_9/class_89.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_89.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_89.h" -#include "class_0.h" -#include "class_73.h" -#include "class_99.h" -#include "class_57.h" -#include "class_91.h" -#include "class_28.h" -#include "class_1.h" -#include "class_15.h" -#include "class_46.h" -#include "class_82.h" -#include "class_67.h" -#include "class_89.h" -#include "class_16.h" -#include "class_74.h" -#include "class_55.h" -#include -#include -#include -#include -#include - -class_89::class_89() {} -class_89::~class_89() {} diff --git a/lib/waf/build/lib_9/class_89.h b/lib/waf/build/lib_9/class_89.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_89.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_89_h_ -#define class_89_h_ - -class class_89 { -public: - class_89(); - ~class_89(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_9.cpp b/lib/waf/build/lib_9/class_9.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_9.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_9.h" -#include "class_32.h" -#include "class_34.h" -#include "class_65.h" -#include "class_78.h" -#include "class_14.h" -#include "class_88.h" -#include "class_7.h" -#include "class_3.h" -#include "class_87.h" -#include "class_28.h" -#include "class_91.h" -#include "class_73.h" -#include "class_57.h" -#include "class_56.h" -#include "class_10.h" -#include -#include -#include -#include -#include - -class_9::class_9() {} -class_9::~class_9() {} diff --git a/lib/waf/build/lib_9/class_9.h b/lib/waf/build/lib_9/class_9.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_9.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_9_h_ -#define class_9_h_ - -class class_9 { -public: - class_9(); - ~class_9(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_90.cpp b/lib/waf/build/lib_9/class_90.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_90.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_90.h" -#include "class_12.h" -#include "class_35.h" -#include "class_97.h" -#include "class_44.h" -#include "class_20.h" -#include "class_68.h" -#include "class_95.h" -#include "class_87.h" -#include "class_50.h" -#include "class_52.h" -#include "class_3.h" -#include "class_55.h" -#include "class_86.h" -#include "class_22.h" -#include "class_9.h" -#include -#include -#include -#include -#include - -class_90::class_90() {} -class_90::~class_90() {} diff --git a/lib/waf/build/lib_9/class_90.h b/lib/waf/build/lib_9/class_90.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_90.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_90_h_ -#define class_90_h_ - -class class_90 { -public: - class_90(); - ~class_90(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_91.cpp b/lib/waf/build/lib_9/class_91.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_91.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_91.h" -#include "class_65.h" -#include "class_71.h" -#include "class_61.h" -#include "class_57.h" -#include "class_49.h" -#include "class_77.h" -#include "class_16.h" -#include "class_54.h" -#include "class_86.h" -#include "class_37.h" -#include "class_34.h" -#include "class_60.h" -#include "class_56.h" -#include "class_53.h" -#include "class_30.h" -#include -#include -#include -#include -#include - -class_91::class_91() {} -class_91::~class_91() {} diff --git a/lib/waf/build/lib_9/class_91.h b/lib/waf/build/lib_9/class_91.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_91.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_91_h_ -#define class_91_h_ - -class class_91 { -public: - class_91(); - ~class_91(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_92.cpp b/lib/waf/build/lib_9/class_92.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_92.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_92.h" -#include "class_54.h" -#include "class_69.h" -#include "class_94.h" -#include "class_50.h" -#include "class_72.h" -#include "class_26.h" -#include "class_86.h" -#include "class_73.h" -#include "class_23.h" -#include "class_51.h" -#include "class_38.h" -#include "class_74.h" -#include "class_67.h" -#include "class_19.h" -#include "class_21.h" -#include -#include -#include -#include -#include - -class_92::class_92() {} -class_92::~class_92() {} diff --git a/lib/waf/build/lib_9/class_92.h b/lib/waf/build/lib_9/class_92.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_92.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_92_h_ -#define class_92_h_ - -class class_92 { -public: - class_92(); - ~class_92(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_93.cpp b/lib/waf/build/lib_9/class_93.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_93.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_93.h" -#include "class_2.h" -#include "class_99.h" -#include "class_93.h" -#include "class_26.h" -#include "class_70.h" -#include "class_21.h" -#include "class_50.h" -#include "class_62.h" -#include "class_91.h" -#include "class_16.h" -#include "class_67.h" -#include "class_8.h" -#include "class_10.h" -#include "class_46.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_93::class_93() {} -class_93::~class_93() {} diff --git a/lib/waf/build/lib_9/class_93.h b/lib/waf/build/lib_9/class_93.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_93.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_93_h_ -#define class_93_h_ - -class class_93 { -public: - class_93(); - ~class_93(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_94.cpp b/lib/waf/build/lib_9/class_94.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_94.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_94.h" -#include "class_73.h" -#include "class_50.h" -#include "class_33.h" -#include "class_30.h" -#include "class_62.h" -#include "class_8.h" -#include "class_0.h" -#include "class_45.h" -#include "class_61.h" -#include "class_20.h" -#include "class_57.h" -#include "class_48.h" -#include "class_90.h" -#include "class_35.h" -#include "class_17.h" -#include -#include -#include -#include -#include - -class_94::class_94() {} -class_94::~class_94() {} diff --git a/lib/waf/build/lib_9/class_94.h b/lib/waf/build/lib_9/class_94.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_94.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_94_h_ -#define class_94_h_ - -class class_94 { -public: - class_94(); - ~class_94(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_95.cpp b/lib/waf/build/lib_9/class_95.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_95.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_95.h" -#include "class_96.h" -#include "class_47.h" -#include "class_67.h" -#include "class_74.h" -#include "class_41.h" -#include "class_6.h" -#include "class_71.h" -#include "class_11.h" -#include "class_30.h" -#include "class_60.h" -#include "class_5.h" -#include "class_55.h" -#include "class_90.h" -#include "class_16.h" -#include "class_23.h" -#include -#include -#include -#include -#include - -class_95::class_95() {} -class_95::~class_95() {} diff --git a/lib/waf/build/lib_9/class_95.h b/lib/waf/build/lib_9/class_95.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_95.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_95_h_ -#define class_95_h_ - -class class_95 { -public: - class_95(); - ~class_95(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_96.cpp b/lib/waf/build/lib_9/class_96.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_96.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_96.h" -#include "class_35.h" -#include "class_5.h" -#include "class_63.h" -#include "class_62.h" -#include "class_58.h" -#include "class_96.h" -#include "class_14.h" -#include "class_53.h" -#include "class_59.h" -#include "class_74.h" -#include "class_34.h" -#include "class_30.h" -#include "class_0.h" -#include "class_20.h" -#include "class_66.h" -#include -#include -#include -#include -#include - -class_96::class_96() {} -class_96::~class_96() {} diff --git a/lib/waf/build/lib_9/class_96.h b/lib/waf/build/lib_9/class_96.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_96.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_96_h_ -#define class_96_h_ - -class class_96 { -public: - class_96(); - ~class_96(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_97.cpp b/lib/waf/build/lib_9/class_97.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_97.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_97.h" -#include "class_39.h" -#include "class_53.h" -#include "class_90.h" -#include "class_55.h" -#include "class_78.h" -#include "class_56.h" -#include "class_52.h" -#include "class_47.h" -#include "class_48.h" -#include "class_24.h" -#include "class_12.h" -#include "class_87.h" -#include "class_32.h" -#include "class_20.h" -#include "class_36.h" -#include -#include -#include -#include -#include - -class_97::class_97() {} -class_97::~class_97() {} diff --git a/lib/waf/build/lib_9/class_97.h b/lib/waf/build/lib_9/class_97.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_97.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_97_h_ -#define class_97_h_ - -class class_97 { -public: - class_97(); - ~class_97(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_98.cpp b/lib/waf/build/lib_9/class_98.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_98.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_98.h" -#include "class_29.h" -#include "class_27.h" -#include "class_64.h" -#include "class_15.h" -#include "class_44.h" -#include "class_37.h" -#include "class_95.h" -#include "class_51.h" -#include "class_62.h" -#include "class_4.h" -#include "class_97.h" -#include "class_80.h" -#include "class_22.h" -#include "class_78.h" -#include "class_72.h" -#include -#include -#include -#include -#include - -class_98::class_98() {} -class_98::~class_98() {} diff --git a/lib/waf/build/lib_9/class_98.h b/lib/waf/build/lib_9/class_98.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_98.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_98_h_ -#define class_98_h_ - -class class_98 { -public: - class_98(); - ~class_98(); -}; - -#endif diff --git a/lib/waf/build/lib_9/class_99.cpp b/lib/waf/build/lib_9/class_99.cpp deleted file mode 100644 --- a/lib/waf/build/lib_9/class_99.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "class_99.h" -#include "class_62.h" -#include "class_15.h" -#include "class_9.h" -#include "class_46.h" -#include "class_24.h" -#include "class_16.h" -#include "class_80.h" -#include "class_28.h" -#include "class_73.h" -#include "class_97.h" -#include "class_8.h" -#include "class_18.h" -#include "class_99.h" -#include "class_64.h" -#include "class_37.h" -#include -#include -#include -#include -#include - -class_99::class_99() {} -class_99::~class_99() {} diff --git a/lib/waf/build/lib_9/class_99.h b/lib/waf/build/lib_9/class_99.h deleted file mode 100644 --- a/lib/waf/build/lib_9/class_99.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef class_99_h_ -#define class_99_h_ - -class class_99 { -public: - class_99(); - ~class_99(); -}; - -#endif diff --git a/lib/waf/build/log b/lib/waf/build/log deleted file mode 100644 --- a/lib/waf/build/log +++ /dev/null @@ -1,854 +0,0 @@ -[c55b67b5b33] {jit-log-opt-loop -# Loop 0 : loop with 39 ops -[p0, p1, p2, p3, i4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, i30, p31, p32, p33, p34, p35, p36] -debug_merge_point(' #290 FOR_ITER') -guard_class(p5, 144273824, descr=) [p1, p0, p5, p2, p3, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p35, p36, i30] -p38 = getfield_gc(p5, descr=) -guard_nonnull(p38, descr=) [p1, p0, p5, p38, p2, p3, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p35, p36, i30] -i39 = getfield_gc(p5, descr=) -p41 = call(ConstClass(ll_getitem_nonneg__dum_checkidxConst_listPtr_Signed), p38, i39, descr=) -guard_no_exception(, descr=) [p1, p0, p5, i39, p41, p2, p3, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p35, p36, i30] -i43 = int_add(i39, 1) -debug_merge_point(' #293 STORE_FAST') -debug_merge_point(' #296 LOAD_FAST') -setfield_gc(p5, i43, descr=) -guard_nonnull_class(p41, ConstClass(W_IntObject), descr=) [p1, p0, p41, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p36, i30] -debug_merge_point(' #299 JUMP_IF_FALSE') -i45 = getfield_gc_pure(p41, descr=) -i46 = int_is_true(i45) -guard_false(i46, descr=) [p1, p0, p41, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p36, i30] -debug_merge_point(' #339 POP_TOP') -debug_merge_point(' #340 LOAD_FAST') -guard_nonnull_class(p32, ConstClass(W_IntObject), descr=) [p1, p0, p32, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p33, p34, p41, p36, i30] -debug_merge_point(' #343 JUMP_IF_FALSE') -i48 = getfield_gc_pure(p32, descr=) -i49 = int_is_true(i48) -guard_false(i49, descr=) [p1, p0, p32, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p33, p34, p41, p36, i30] -debug_merge_point(' #372 POP_TOP') -debug_merge_point(' #373 LOAD_FAST') -debug_merge_point(' #376 LOAD_CONST') -debug_merge_point(' #379 BINARY_ADD') -i51 = int_add_ovf(i30, 1) -guard_no_overflow(, descr=) [p1, p0, i51, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p41, p36, i30] -debug_merge_point(' #380 STORE_FAST') -debug_merge_point(' #383 JUMP_ABSOLUTE') -i53 = getfield_raw(151877184, descr=) -i55 = int_add(i53, 1) -setfield_raw(151877184, i55, descr=) -i58 = int_and(i55, 1089470464) -i59 = int_is_true(i58) -guard_false(i59, descr=) [p1, p0, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p41, p36, i51, None] -debug_merge_point(' #290 FOR_ITER') -jump(p0, p1, p2, p3, 290, p5, ConstPtr(ptr62), ConstPtr(ptr63), p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, i51, p31, p32, p33, p34, p41, p36, descr=) -[c55b684b2b9] jit-log-opt-loop} -[c55b8596f25] {jit-log-opt-loop -# Loop 1 : loop with 46 ops -[p0, p1, p2, p3, i4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18] -debug_merge_point(' #66 FOR_ITER') -guard_class(p5, 144273824, descr=) [p1, p0, p5, p2, p3, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p17, p18, p16] -p20 = getfield_gc(p5, descr=) -guard_nonnull(p20, descr=) [p1, p0, p5, p20, p2, p3, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p17, p18, p16] -i21 = getfield_gc(p5, descr=) -p23 = call(ConstClass(ll_getitem_nonneg__dum_checkidxConst_listPtr_Signed), p20, i21, descr=) -guard_no_exception(, descr=) [p1, p0, p5, i21, p23, p2, p3, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p17, p18, p16] -i25 = int_add(i21, 1) -debug_merge_point(' #69 STORE_FAST') -debug_merge_point(' #72 LOAD_FAST') -setfield_gc(p5, i25, descr=) -guard_nonnull_class(p23, ConstClass(W_IntObject), descr=) [p1, p0, p23, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p17, p16] -debug_merge_point(' #75 JUMP_IF_FALSE') -i27 = getfield_gc_pure(p23, descr=) -i28 = int_is_true(i27) -guard_false(i28, descr=) [p1, p0, p23, p2, p3, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p17, p16] -debug_merge_point(' #92 POP_TOP') -debug_merge_point(' #93 LOAD_FAST') -debug_merge_point(' #96 LOAD_FAST') -debug_merge_point(' #99 BINARY_ADD') -p30 = call(ConstClass(rbigint.add), p16, p16, descr=) -guard_no_exception(, descr=) [p1, p0, p30, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p17, p23, p16] -debug_merge_point(' #100 STORE_FAST') -debug_merge_point(' #103 LOAD_FAST') -debug_merge_point(' #106 LOAD_GLOBAL') -p31 = getfield_gc(p0, descr=) -guard_value(p31, ConstPtr(ptr32), descr=) [p1, p0, p31, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p17, p23, p30, None] -p34 = getfield_gc(p31, descr=) -guard_isnull(p34, descr=) [p1, p0, p34, p31, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p17, p23, p30, None] -p36 = getfield_gc(ConstPtr(ptr35), descr=) -guard_nonnull_class(p36, ConstClass(W_LongObject), descr=) [p1, p0, p36, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p17, p23, p30, None] -debug_merge_point(' #109 COMPARE_OP') -p38 = getfield_gc_pure(p36, descr=) -i40 = call(ConstClass(rbigint.gt), p30, p38, descr=) -guard_false(i40, descr=) [p1, p0, p36, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p17, p23, p30, None] -debug_merge_point(' #112 JUMP_IF_FALSE') -debug_merge_point(' #141 POP_TOP') -debug_merge_point(' #142 JUMP_ABSOLUTE') -i42 = getfield_raw(151877184, descr=) -i44 = int_add(i42, 1) -setfield_raw(151877184, i44, descr=) -i47 = int_and(i44, 1089470464) -i48 = int_is_true(i47) -guard_false(i48, descr=) [p1, p0, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p17, p23, p30, None] -debug_merge_point(' #66 FOR_ITER') -jump(p0, p1, p2, p3, 66, p5, ConstPtr(ptr50), ConstPtr(ptr51), p8, p9, p10, p11, p12, p13, p14, p15, p30, p17, p23, descr=) -[c55b85f6e61] jit-log-opt-loop} -[c55b8b293a3] {jit-log-opt-loop -# Loop 2 : entry bridge with 43 ops -[p0, p1, p2, p3, i4, p5, i6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38] -debug_merge_point(' #290 FOR_ITER') -guard_value(i4, 1, descr=) [i4, p1, p0, p2, p3, p5, i6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38] -guard_class(p7, 144273824, descr=) [p1, p0, p7, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38] -p41 = getfield_gc(p7, descr=) -guard_nonnull(p41, descr=) [p1, p0, p7, p41, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38] -i42 = getfield_gc(p7, descr=) -p44 = call(ConstClass(ll_getitem_nonneg__dum_checkidxConst_listPtr_Signed), p41, i42, descr=) -guard_no_exception(, descr=) [p1, p0, p7, i42, p44, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38] -i46 = int_add(i42, 1) -debug_merge_point(' #293 STORE_FAST') -debug_merge_point(' #296 LOAD_FAST') -setfield_gc(p7, i46, descr=) -guard_nonnull_class(p44, ConstClass(W_IntObject), descr=) [p1, p0, p44, p2, p3, p5, p7, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p38] -debug_merge_point(' #299 JUMP_IF_FALSE') -i48 = getfield_gc_pure(p44, descr=) -i49 = int_is_true(i48) -guard_false(i49, descr=) [p1, p0, p44, p2, p3, p5, p7, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p38] -debug_merge_point(' #339 POP_TOP') -debug_merge_point(' #340 LOAD_FAST') -guard_nonnull_class(p34, ConstClass(W_IntObject), descr=) [p1, p0, p34, p2, p3, p5, p7, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p35, p36, p44, p38] -debug_merge_point(' #343 JUMP_IF_FALSE') -i51 = getfield_gc_pure(p34, descr=) -i52 = int_is_true(i51) -guard_false(i52, descr=) [p1, p0, p34, p2, p3, p5, p7, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p35, p36, p44, p38] -debug_merge_point(' #372 POP_TOP') -debug_merge_point(' #373 LOAD_FAST') -guard_nonnull_class(p32, ConstClass(W_IntObject), descr=) [p1, p0, p32, p2, p3, p5, p7, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p33, p34, p35, p36, p44, p38] -debug_merge_point(' #376 LOAD_CONST') -guard_value(p2, ConstPtr(ptr54), descr=) [p1, p0, p2, p3, p5, p7, p32, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p33, p34, p35, p36, p44, p38] -debug_merge_point(' #379 BINARY_ADD') -i55 = getfield_gc_pure(p32, descr=) -i57 = int_add_ovf(i55, 1) -guard_no_overflow(, descr=) [p1, p0, p32, i57, p3, p5, p7, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p33, p34, p35, p36, p44, p38] -debug_merge_point(' #380 STORE_FAST') -debug_merge_point(' #383 JUMP_ABSOLUTE') -i59 = getfield_raw(151877184, descr=) -i61 = int_add(i59, 1) -setfield_raw(151877184, i61, descr=) -i64 = int_and(i61, 1089470464) -i65 = int_is_true(i64) -guard_false(i65, descr=) [p1, p0, p3, p5, p7, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p33, p34, p35, p36, p44, p38, i57] -debug_merge_point(' #290 FOR_ITER') -jump(p0, p1, p3, p5, 290, p7, ConstPtr(ptr67), ConstPtr(ptr68), p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, i57, p33, p34, p35, p36, p44, p38, descr=) -[c55b8b75163] jit-log-opt-loop} -[c55b907c52f] {jit-log-opt-loop -# Loop 3 : entry bridge with 50 ops -[p0, p1, p2, p3, i4, p5, i6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20] -debug_merge_point(' #66 FOR_ITER') -guard_value(i4, 1, descr=) [i4, p1, p0, p2, p3, p5, i6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20] -guard_class(p7, 144273824, descr=) [p1, p0, p7, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20] -p23 = getfield_gc(p7, descr=) -guard_nonnull(p23, descr=) [p1, p0, p7, p23, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20] -i24 = getfield_gc(p7, descr=) -p26 = call(ConstClass(ll_getitem_nonneg__dum_checkidxConst_listPtr_Signed), p23, i24, descr=) -guard_no_exception(, descr=) [p1, p0, p7, i24, p26, p2, p3, p5, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20] -i28 = int_add(i24, 1) -debug_merge_point(' #69 STORE_FAST') -debug_merge_point(' #72 LOAD_FAST') -setfield_gc(p7, i28, descr=) -guard_nonnull_class(p26, ConstClass(W_IntObject), descr=) [p1, p0, p26, p2, p3, p5, p7, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19] -debug_merge_point(' #75 JUMP_IF_FALSE') -i30 = getfield_gc_pure(p26, descr=) -i31 = int_is_true(i30) -guard_false(i31, descr=) [p1, p0, p26, p2, p3, p5, p7, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19] -debug_merge_point(' #92 POP_TOP') -debug_merge_point(' #93 LOAD_FAST') -guard_nonnull_class(p18, ConstClass(W_LongObject), descr=) [p1, p0, p18, p2, p3, p5, p7, p9, p10, p11, p12, p13, p14, p15, p16, p17, p19, p26] -debug_merge_point(' #96 LOAD_FAST') -debug_merge_point(' #99 BINARY_ADD') -p33 = getfield_gc_pure(p18, descr=) -p35 = call(ConstClass(rbigint.add), p33, p33, descr=) -guard_no_exception(, descr=) [p1, p0, p18, p35, p2, p3, p5, p7, p10, p11, p12, p13, p14, p15, p16, p17, p19, p26] -debug_merge_point(' #100 STORE_FAST') -debug_merge_point(' #103 LOAD_FAST') -debug_merge_point(' #106 LOAD_GLOBAL') -guard_value(p2, ConstPtr(ptr36), descr=) [p1, p0, p2, p3, p5, p7, p10, p11, p12, p13, p14, p15, p16, p17, p19, p26, p35] -p37 = getfield_gc(p0, descr=) -guard_value(p37, ConstPtr(ptr38), descr=) [p1, p0, p37, p3, p5, p7, p10, p11, p12, p13, p14, p15, p16, p17, p19, p26, p35] -p39 = getfield_gc(p37, descr=) -guard_isnull(p39, descr=) [p1, p0, p39, p37, p3, p5, p7, p10, p11, p12, p13, p14, p15, p16, p17, p19, p26, p35] -p41 = getfield_gc(ConstPtr(ptr40), descr=) -guard_nonnull_class(p41, ConstClass(W_LongObject), descr=) [p1, p0, p41, p3, p5, p7, p10, p11, p12, p13, p14, p15, p16, p17, p19, p26, p35] -debug_merge_point(' #109 COMPARE_OP') -p43 = getfield_gc_pure(p41, descr=) -i45 = call(ConstClass(rbigint.gt), p35, p43, descr=) -guard_false(i45, descr=) [p1, p0, p41, p3, p5, p7, p10, p11, p12, p13, p14, p15, p16, p17, p19, p26, p35] -debug_merge_point(' #112 JUMP_IF_FALSE') -debug_merge_point(' #141 POP_TOP') -debug_merge_point(' #142 JUMP_ABSOLUTE') -i47 = getfield_raw(151877184, descr=) -i49 = int_add(i47, 1) -setfield_raw(151877184, i49, descr=) -i52 = int_and(i49, 1089470464) -i53 = int_is_true(i52) -guard_false(i53, descr=) [p1, p0, p3, p5, p7, p10, p11, p12, p13, p14, p15, p16, p17, p19, p26, p35] -debug_merge_point(' #66 FOR_ITER') -jump(p0, p1, p3, p5, 66, p7, ConstPtr(ptr55), ConstPtr(ptr56), p10, p11, p12, p13, p14, p15, p16, p17, p35, p19, p26, descr=) -[c55b90b7317] jit-log-opt-loop} -[c55be84cb56] {jit-log-opt-loop -# Loop 4 : loop with 11 ops -[i0, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 47) -guard_false(i5, descr=) [i0, p1] -i7 = int_add(i0, 1) -i8 = getfield_gc_pure(p1, descr=) -i9 = int_lt(i7, i8) -guard_true(i9, descr=) [i7, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i7, p1, descr=) -[c55be878248] jit-log-opt-loop} -[c55be94d1b8] {jit-log-opt-loop -# Loop 5 : loop with 16 ops -[i0, i1, p2] -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -i3 = int_lt(i0, i1) -guard_true(i3, descr=) [i1, i0, p2] -p4 = getfield_gc(p2, descr=) -i5 = strgetitem(p4, i0) -i7 = int_eq(40, i5) -guard_false(i7, descr=) [i1, i0, p2, i5] -i9 = int_eq(41, i5) -guard_false(i9, descr=) [i1, i0, p2, i5] -i11 = int_eq(i5, 32) -guard_false(i11, descr=) [i1, i0, p2, i5] -i13 = int_le(i5, 13) -guard_false(i13, descr=) [i1, i0, p2, i5] -i15 = int_add(i0, 1) -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i15, i1, p2, descr=) -[c55be987844] jit-log-opt-loop} -[c55bea30852] {jit-log-opt-loop -# Loop 6 : loop with 16 ops -[i0, p1, p2] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p3 = getfield_gc(p1, descr=) -guard_class(p2, 146873440, descr=) [i0, p2, p1, p3] -i5 = getfield_gc_pure(p2, descr=) -i6 = int_ge(i0, i5) -guard_false(i6, descr=) [i0, p2, p1, p3] -p7 = getfield_gc(p2, descr=) -i8 = strgetitem(p7, i0) -i10 = int_ne(i8, 108) -guard_true(i10, descr=) [i0, p2, p1, p3] -i12 = int_sub(i0, 1) -i13 = getfield_gc(p1, descr=) -i14 = int_ge(i12, i13) -guard_true(i14, descr=) [i12, p2, p1] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i12, p1, p2, descr=) -[c55bea55de2] jit-log-opt-loop} -[c55beb77096] {jit-log-opt-loop -# Loop 7 : entry bridge with 11 ops -[i0, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 47) -guard_false(i5, descr=) [i0, p1] -i7 = int_add(i0, 1) -i8 = getfield_gc_pure(p1, descr=) -i9 = int_lt(i7, i8) -guard_true(i9, descr=) [i7, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i7, p1, descr=) -[c55beb8e59e] jit-log-opt-loop} -[c55bec27b4a] {jit-log-opt-loop -# Loop 8 : entry bridge with 16 ops -[i0, i1, p2] -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -i3 = int_lt(i0, i1) -guard_true(i3, descr=) [i1, i0, p2] -p4 = getfield_gc(p2, descr=) -i5 = strgetitem(p4, i0) -i7 = int_eq(40, i5) -guard_false(i7, descr=) [i1, i0, p2, i5] -i9 = int_eq(41, i5) -guard_false(i9, descr=) [i1, i0, p2, i5] -i11 = int_eq(i5, 32) -guard_false(i11, descr=) [i1, i0, p2, i5] -i13 = int_le(i5, 13) -guard_false(i13, descr=) [i1, i0, p2, i5] -i15 = int_add(i0, 1) -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i15, i1, p2, descr=) -[c55bec478ea] jit-log-opt-loop} -[c55becd5da8] {jit-log-opt-loop -# Loop 9 : entry bridge with 16 ops -[i0, p1, p2] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p3 = getfield_gc(p1, descr=) -guard_class(p2, 146873440, descr=) [i0, p2, p1, p3] -i5 = getfield_gc_pure(p2, descr=) -i6 = int_ge(i0, i5) -guard_false(i6, descr=) [i0, p2, p1, p3] -p7 = getfield_gc(p2, descr=) -i8 = strgetitem(p7, i0) -i10 = int_ne(i8, 108) -guard_true(i10, descr=) [i0, p2, p1, p3] -i12 = int_sub(i0, 1) -i13 = getfield_gc(p1, descr=) -i14 = int_ge(i12, i13) -guard_true(i14, descr=) [i12, p2, p1] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i12, p1, p2, descr=) -[c55bed049c2] jit-log-opt-loop} -[c55bf04c08c] {jit-log-opt-bridge -# bridge out of Guard 57 with 26 ops -[i0, p1, p2, p3] -i5 = int_add(i0, 1) -i6 = getfield_gc_pure(p1, descr=) -i7 = int_ge(i5, i6) -guard_false(i7, descr=) [i0, p1, p2, i5, p3] -p8 = getfield_gc(p1, descr=) -i9 = strgetitem(p8, i5) -i11 = int_ne(i9, 105) -guard_false(i11, descr=) [i0, p1, p2, i5, p3] -i13 = int_add(i5, 1) -i14 = int_ge(i13, i6) -guard_false(i14, descr=) [i0, p1, p2, i13, p3] -i15 = strgetitem(p8, i13) -i17 = int_ne(i15, 98) -guard_false(i17, descr=) [i0, p1, p2, i13, p3] -i19 = int_add(i13, 1) -i20 = int_ge(i19, i6) -guard_false(i20, descr=) [i0, p1, p2, i19, p3] -i21 = strgetitem(p8, i19) -i23 = int_ne(i21, 115) -guard_true(i23, descr=) [i0, p1, p2, i19, p3] -i25 = int_sub(i0, 1) -i26 = getfield_gc(p2, descr=) -i27 = int_ge(i25, i26) -guard_true(i27, descr=) [i25, p1, p2] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i25, p2, p1, descr=) -[c55bf08119e] jit-log-opt-bridge} -[c55bf29a732] {jit-log-opt-bridge -# bridge out of Guard 48 with 23 ops -[i0, p1] -i3 = int_add(i0, 1) -i4 = getfield_gc_pure(p1, descr=) -i5 = int_gt(i3, i4) -guard_false(i5, descr=) [i0, p1, i3] -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -i6 = call_assembler(i3, i4, p1, descr=) -guard_not_forced(, descr=) [i0, p1, i3, i6] -guard_no_exception(, descr=) [i0, p1, i3, i6] -i7 = int_ge(i6, i3) -guard_true(i7, descr=) [i0, p1, i6, i3] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p9 = new_with_vtable(144271028) -setfield_gc(p9, 26, descr=) -setfield_gc(p9, i3, descr=) -setfield_gc(p9, i6, descr=) -p11 = call_assembler(i6, p9, p1, descr=) -guard_not_forced(, descr=) [i0, p1, p11] -guard_no_exception(, descr=) [i0, p1, p11] -guard_isnull(p11, descr=) [i0, p1, p11] -i12 = int_lt(i3, i4) -guard_true(i12, descr=) [i3, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 8, 131078, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i3, p1, descr=) -[c55bf2c654a] jit-log-opt-bridge} -[c55bf34d760] {jit-log-opt-bridge -# bridge out of Guard 54 with 3 ops -[i0, i1, p2, i3] -i5 = int_ge(i3, 9) -guard_true(i5, descr=) [i0, i1, p2, i3] -finish(i1, descr=) -[c55bf35b050] jit-log-opt-bridge} -[c55bf452fd6] {jit-log-opt-bridge -# bridge out of Guard 76 with 1 ops -[i0, p1, p2] -finish(ConstPtr(ptr3), descr=) -[c55bf465432] jit-log-opt-bridge} -[c55c218ad82] {jit-log-opt-loop -# Loop 10 : loop with 19 ops -[i0, p1] -debug_merge_point('StrCharsetSearch at 8 [17, 7, 4, 9, 131077, 9, 2, 0, 15, 4, 9, 2, 0, 19, 83, 19, 79, 19, 78, 19, 65, 19, 77, 19, 69, 29, 9, 1, 65535...') -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 32) -guard_true(i5, descr=) [i0, p1, i3] -i6 = getfield_gc_pure(p1, descr=) -i7 = int_ge(i0, i6) -guard_false(i7, descr=) [i0, p1] -i8 = strgetitem(p2, i0) -i10 = int_eq(i8, 32) -guard_true(i10, descr=) [i0, p1, i8] -i12 = int_add(i0, 1) -i13 = int_ge(i12, i6) -guard_false(i13, descr=) [i0, p1, i12] -i14 = strgetitem(p2, i12) -i16 = int_ne(i14, 83) -guard_true(i16, descr=) [i0, p1, i12] -debug_merge_point('StrCharsetSearch at 8 [17, 7, 4, 9, 131077, 9, 2, 0, 15, 4, 9, 2, 0, 19, 83, 19, 79, 19, 78, 19, 65, 19, 77, 19, 69, 29, 9, 1, 65535...') -jump(i12, p1, descr=) -[c55c21a9c0a] jit-log-opt-loop} -[c55c3b4d3eb] {jit-log-opt-bridge -# bridge out of Guard 27 with 37 ops -[p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35] -debug_merge_point(' #302 POP_TOP') -debug_merge_point(' #303 LOAD_FAST') -guard_nonnull_class(p32, ConstClass(W_IntObject), descr=) [p0, p1, p32, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p33, p34, p2, p35] -debug_merge_point(' #306 LOAD_CONST') -guard_value(p3, ConstPtr(ptr37), descr=) [p0, p1, p3, p4, p5, p6, p32, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p33, p34, p2, p35] -debug_merge_point(' #309 COMPARE_OP') -i38 = getfield_gc_pure(p32, descr=) -i40 = int_eq(i38, 0) -guard_false(i40, descr=) [p0, p1, p32, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p33, p34, p2, p35] -debug_merge_point(' #312 JUMP_IF_FALSE') -debug_merge_point(' #325 POP_TOP') -debug_merge_point(' #326 LOAD_FAST') -debug_merge_point(' #329 LOAD_CONST') -debug_merge_point(' #332 BINARY_ADD') -i42 = int_add_ovf(i38, 1) -guard_no_overflow(, descr=) [p0, p1, p32, i42, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p33, p34, p2, p35] -debug_merge_point(' #333 STORE_FAST') -debug_merge_point(' #336 JUMP_FORWARD') -debug_merge_point(' #373 LOAD_FAST') -guard_nonnull_class(p30, ConstClass(W_IntObject), descr=) [p0, p1, p30, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p33, p34, p2, p35, i42] -debug_merge_point(' #376 LOAD_CONST') -debug_merge_point(' #379 BINARY_ADD') -i44 = getfield_gc_pure(p30, descr=) -i46 = int_add_ovf(i44, 1) -guard_no_overflow(, descr=) [p0, p1, p30, i46, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p33, p34, p2, p35, i42] -debug_merge_point(' #380 STORE_FAST') -debug_merge_point(' #383 JUMP_ABSOLUTE') -i48 = getfield_raw(151877184, descr=) -i50 = int_add(i48, 1) -setfield_raw(151877184, i50, descr=) -i53 = int_and(i50, 1089470464) -i54 = int_is_true(i53) -guard_false(i54, descr=) [p0, p1, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p33, p34, p2, p35, i46, i42] -debug_merge_point(' #290 FOR_ITER') -p56 = new_with_vtable(ConstClass(W_IntObject)) -setfield_gc(p56, i42, descr=) -jump(p1, p0, p4, p5, 290, p6, ConstPtr(ptr58), ConstPtr(ptr59), p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, i46, p31, p56, p33, p34, p2, p35, descr=) -[c55c3b911ff] jit-log-opt-bridge} -[c55c3de9edf] {jit-log-opt-bridge -# bridge out of Guard 6 with 34 ops -[p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, i34] -debug_merge_point(' #302 POP_TOP') -debug_merge_point(' #303 LOAD_FAST') -guard_nonnull_class(p30, ConstClass(W_IntObject), descr=) [p0, p1, p30, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p2, p33, i34] -debug_merge_point(' #306 LOAD_CONST') -debug_merge_point(' #309 COMPARE_OP') -i36 = getfield_gc_pure(p30, descr=) -i38 = int_eq(i36, 0) -guard_false(i38, descr=) [p0, p1, p30, p3, p4, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p2, p33, i34] -debug_merge_point(' #312 JUMP_IF_FALSE') -debug_merge_point(' #325 POP_TOP') -debug_merge_point(' #326 LOAD_FAST') -debug_merge_point(' #329 LOAD_CONST') -debug_merge_point(' #332 BINARY_ADD') -i40 = int_add_ovf(i36, 1) -guard_no_overflow(, descr=) [p0, p1, p30, i40, p3, p4, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p2, p33, i34] -debug_merge_point(' #333 STORE_FAST') -debug_merge_point(' #336 JUMP_FORWARD') -debug_merge_point(' #373 LOAD_FAST') -debug_merge_point(' #376 LOAD_CONST') -debug_merge_point(' #379 BINARY_ADD') -i42 = int_add_ovf(i34, 1) -guard_no_overflow(, descr=) [p0, p1, i42, p3, p4, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p2, p33, i40, i34] -debug_merge_point(' #380 STORE_FAST') -debug_merge_point(' #383 JUMP_ABSOLUTE') -i44 = getfield_raw(151877184, descr=) -i46 = int_add(i44, 1) -setfield_raw(151877184, i46, descr=) -i49 = int_and(i46, 1089470464) -i50 = int_is_true(i49) -guard_false(i50, descr=) [p0, p1, p3, p4, p5, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p2, p33, i42, i40, None] -debug_merge_point(' #290 FOR_ITER') -p53 = new_with_vtable(ConstClass(W_IntObject)) -setfield_gc(p53, i40, descr=) -jump(p1, p0, p3, p4, 290, p5, ConstPtr(ptr55), ConstPtr(ptr56), p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, i42, p29, p53, p31, p32, p2, p33, descr=) -[c55c3e1ac61] jit-log-opt-bridge} -[c55c6f4964c] {jit-log-opt-loop -# Loop 11 : loop with 11 ops -[i0, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 47) -guard_false(i5, descr=) [i0, p1] -i7 = int_add(i0, 1) -i8 = getfield_gc_pure(p1, descr=) -i9 = int_lt(i7, i8) -guard_true(i9, descr=) [i7, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i7, p1, descr=) -[c55c6f60cce] jit-log-opt-loop} -[c55c6fd67c3] {jit-log-opt-loop -# Loop 12 : loop with 16 ops -[i0, i1, p2] -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -i3 = int_lt(i0, i1) -guard_true(i3, descr=) [i1, i0, p2] -p4 = getfield_gc(p2, descr=) -i5 = strgetitem(p4, i0) -i7 = int_eq(40, i5) -guard_false(i7, descr=) [i1, i0, p2, i5] -i9 = int_eq(41, i5) -guard_false(i9, descr=) [i1, i0, p2, i5] -i11 = int_eq(i5, 32) -guard_false(i11, descr=) [i1, i0, p2, i5] -i13 = int_le(i5, 13) -guard_false(i13, descr=) [i1, i0, p2, i5] -i15 = int_add(i0, 1) -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i15, i1, p2, descr=) -[c55c6ffbca2] jit-log-opt-loop} -[c55c7096ad2] {jit-log-opt-loop -# Loop 13 : loop with 16 ops -[i0, p1, p2] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p3 = getfield_gc(p1, descr=) -guard_class(p2, 146873440, descr=) [i0, p2, p1, p3] -i5 = getfield_gc_pure(p2, descr=) -i6 = int_ge(i0, i5) -guard_false(i6, descr=) [i0, p2, p1, p3] -p7 = getfield_gc(p2, descr=) -i8 = strgetitem(p7, i0) -i10 = int_ne(i8, 108) -guard_true(i10, descr=) [i0, p2, p1, p3] -i12 = int_sub(i0, 1) -i13 = getfield_gc(p1, descr=) -i14 = int_ge(i12, i13) -guard_true(i14, descr=) [i12, p2, p1] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i12, p1, p2, descr=) -[c55c70bb306] jit-log-opt-loop} -[c55c71f4746] {jit-log-opt-loop -# Loop 14 : entry bridge with 11 ops -[i0, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 47) -guard_false(i5, descr=) [i0, p1] -i7 = int_add(i0, 1) -i8 = getfield_gc_pure(p1, descr=) -i9 = int_lt(i7, i8) -guard_true(i9, descr=) [i7, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i7, p1, descr=) -[c55c720b16e] jit-log-opt-loop} -[c55c729f91a] {jit-log-opt-loop -# Loop 15 : entry bridge with 16 ops -[i0, i1, p2] -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -i3 = int_lt(i0, i1) -guard_true(i3, descr=) [i1, i0, p2] -p4 = getfield_gc(p2, descr=) -i5 = strgetitem(p4, i0) -i7 = int_eq(40, i5) -guard_false(i7, descr=) [i1, i0, p2, i5] -i9 = int_eq(41, i5) -guard_false(i9, descr=) [i1, i0, p2, i5] -i11 = int_eq(i5, 32) -guard_false(i11, descr=) [i1, i0, p2, i5] -i13 = int_le(i5, 13) -guard_false(i13, descr=) [i1, i0, p2, i5] -i15 = int_add(i0, 1) -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i15, i1, p2, descr=) -[c55c72beb08] jit-log-opt-loop} -[c55c7c44338] {jit-log-opt-loop -# Loop 16 : entry bridge with 16 ops -[i0, p1, p2] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p3 = getfield_gc(p1, descr=) -guard_class(p2, 146873440, descr=) [i0, p2, p1, p3] -i5 = getfield_gc_pure(p2, descr=) -i6 = int_ge(i0, i5) -guard_false(i6, descr=) [i0, p2, p1, p3] -p7 = getfield_gc(p2, descr=) -i8 = strgetitem(p7, i0) -i10 = int_ne(i8, 108) -guard_true(i10, descr=) [i0, p2, p1, p3] -i12 = int_sub(i0, 1) -i13 = getfield_gc(p1, descr=) -i14 = int_ge(i12, i13) -guard_true(i14, descr=) [i12, p2, p1] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i12, p1, p2, descr=) -[c55c7c7b84a] jit-log-opt-loop} -[c55c7f266bd] {jit-log-opt-bridge -# bridge out of Guard 112 with 26 ops -[i0, p1, p2, p3] -i5 = int_add(i0, 1) -i6 = getfield_gc_pure(p1, descr=) -i7 = int_ge(i5, i6) -guard_false(i7, descr=) [i0, p1, p2, i5, p3] -p8 = getfield_gc(p1, descr=) -i9 = strgetitem(p8, i5) -i11 = int_ne(i9, 105) -guard_false(i11, descr=) [i0, p1, p2, i5, p3] -i13 = int_add(i5, 1) -i14 = int_ge(i13, i6) -guard_false(i14, descr=) [i0, p1, p2, i13, p3] -i15 = strgetitem(p8, i13) -i17 = int_ne(i15, 98) -guard_false(i17, descr=) [i0, p1, p2, i13, p3] -i19 = int_add(i13, 1) -i20 = int_ge(i19, i6) -guard_false(i20, descr=) [i0, p1, p2, i19, p3] -i21 = strgetitem(p8, i19) -i23 = int_ne(i21, 99) -guard_true(i23, descr=) [i0, p1, p2, i19, p3] -i25 = int_sub(i0, 1) -i26 = getfield_gc(p2, descr=) -i27 = int_ge(i25, i26) -guard_true(i27, descr=) [i25, p1, p2] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i25, p2, p1, descr=) -[c55c7f3b6d1] jit-log-opt-bridge} -[c55c801abeb] {jit-log-opt-bridge -# bridge out of Guard 103 with 23 ops -[i0, p1] -i3 = int_add(i0, 1) -i4 = getfield_gc_pure(p1, descr=) -i5 = int_gt(i3, i4) -guard_false(i5, descr=) [i0, p1, i3] -debug_merge_point('StrMatchIn at 15 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -i6 = call_assembler(i3, i4, p1, descr=) -guard_not_forced(, descr=) [i0, p1, i3, i6] -guard_no_exception(, descr=) [i0, p1, i3, i6] -i7 = int_ge(i6, i3) -guard_true(i7, descr=) [i0, p1, i6, i3] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -p9 = new_with_vtable(144271028) -setfield_gc(p9, 26, descr=) -setfield_gc(p9, i3, descr=) -setfield_gc(p9, i6, descr=) -p11 = call_assembler(i6, p9, p1, descr=) -guard_not_forced(, descr=) [i0, p1, p11] -guard_no_exception(, descr=) [i0, p1, p11] -guard_isnull(p11, descr=) [i0, p1, p11] -i12 = int_lt(i3, i4) -guard_true(i12, descr=) [i3, p1] -debug_merge_point('StrLiteralSearch at 11/47 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i3, p1, descr=) -[c55c802ce4b] jit-log-opt-bridge} -[c55c806f52b] {jit-log-opt-bridge -# bridge out of Guard 109 with 3 ops -[i0, i1, p2, i3] -i5 = int_ge(i3, 9) -guard_true(i5, descr=) [i0, i1, p2, i3] -finish(i1, descr=) -[c55c807be79] jit-log-opt-bridge} -[c55c80e6b8d] {jit-log-opt-bridge -# bridge out of Guard 131 with 1 ops -[i0, p1, p2] -finish(ConstPtr(ptr3), descr=) -[c55c80ea5eb] jit-log-opt-bridge} -[c55c814889b] {jit-log-opt-bridge -# bridge out of Guard 113 with 1 ops -[i0, p1, p2] -finish(ConstPtr(ptr3), descr=) -[c55c814bb2d] jit-log-opt-bridge} -[c55c819d3f1] {jit-log-opt-bridge -# bridge out of Guard 126 with 6 ops -[i0, p1, p2, i3, p4] -i6 = int_sub(i0, 1) -i7 = getfield_gc(p2, descr=) -i8 = int_ge(i6, i7) -guard_true(i8, descr=) [i6, p1, p2] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i6, p2, p1, descr=) -[c55c81a4285] jit-log-opt-bridge} -[c55c83a0a91] {jit-log-opt-bridge -# bridge out of Guard 130 with 14 ops -[i0, p1, p2, i3, p4] -i6 = int_add(i3, 1) -i7 = getfield_gc_pure(p1, descr=) -i8 = int_ge(i6, i7) -guard_false(i8, descr=) [i0, p1, p2, i6, p4] -p9 = getfield_gc(p1, descr=) -i10 = strgetitem(p9, i6) -i12 = int_ne(i10, 46) -guard_true(i12, descr=) [i0, p1, p2, i6, p4] -i14 = int_sub(i0, 1) -i15 = getfield_gc(p2, descr=) -i16 = int_ge(i14, i15) -guard_true(i16, descr=) [i14, p1, p2] -debug_merge_point('RepeatOne at 26 [17, 8, 1, 6, 131076, 1, 1, 47, 0, 19, 47, 29, 14, 0, 65535, 15, 9, 26, 19, 40, 19, 41, 9, 2, 0, 1, 19, 108, 1...') -jump(i14, p2, p1, descr=) -[c55c83ad21d] jit-log-opt-bridge} -[c55ca173c02] {jit-log-opt-loop -# Loop 17 : entry bridge with 13 ops -[i0, p1] -debug_merge_point('StrCharsetSearch at 8 [17, 7, 4, 9, 131077, 9, 2, 0, 15, 4, 9, 2, 0, 19, 83, 19, 79, 19, 78, 19, 65, 19, 77, 19, 69, 29, 9, 1, 65535...') -p2 = getfield_gc(p1, descr=) -i3 = strgetitem(p2, i0) -i5 = int_eq(i3, 32) -guard_false(i5, descr=) [i0, p1, i3] -i7 = int_le(i3, 13) -guard_false(i7, descr=) [i0, p1, i3] -i9 = int_add(i0, 1) -i10 = getfield_gc_pure(p1, descr=) -i11 = int_lt(i9, i10) -guard_true(i11, descr=) [i9, p1] -debug_merge_point('StrCharsetSearch at 8 [17, 7, 4, 9, 131077, 9, 2, 0, 15, 4, 9, 2, 0, 19, 83, 19, 79, 19, 78, 19, 65, 19, 77, 19, 69, 29, 9, 1, 65535...') -jump(i9, p1, descr=) -[c55ca18bf14] jit-log-opt-loop} -[c55ca2710b1] {jit-log-opt-bridge -# bridge out of Guard 86 with 8 ops -[i0, p1, i2] -i4 = int_le(i2, 13) -guard_false(i4, descr=) [i0, p1, i2] -i6 = int_add(i0, 1) -i7 = getfield_gc_pure(p1, descr=) -i8 = int_lt(i6, i7) -guard_true(i8, descr=) [i6, p1] -debug_merge_point('StrCharsetSearch at 8 [17, 7, 4, 9, 131077, 9, 2, 0, 15, 4, 9, 2, 0, 19, 83, 19, 79, 19, 78, 19, 65, 19, 77, 19, 69, 29, 9, 1, 65535...') -jump(i6, p1, descr=) -[c55ca27bfc5] jit-log-opt-bridge} -[c55cd82f115] {jit-log-opt-bridge -# bridge out of Guard 29 with 45 ops -[p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35] -debug_merge_point(' #346 POP_TOP') -debug_merge_point(' #347 LOAD_FAST') -guard_nonnull_class(p33, 143883328, descr=) [p0, p1, p33, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p2, p32, p34, p35] -debug_merge_point(' #350 LOAD_FAST') -guard_nonnull(p31, descr=) [p0, p1, p31, p3, p4, p5, p6, p33, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p2, p32, p34, p35] -debug_merge_point(' #353 LOAD_FAST') -guard_nonnull(p2, descr=) [p0, p1, p2, p3, p4, p5, p6, p33, p31, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p32, p34, p35] -debug_merge_point(' #356 BUILD_TUPLE') -debug_merge_point(' #359 CALL_FUNCTION') -i37 = getfield_gc(p1, descr=) -guard_false(i37, descr=) [p0, p1, p33, p3, p4, p5, p6, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p2, p32, p34, p35] -p38 = getfield_gc(p33, descr=) -guard_nonnull_class(p38, ConstClass(W_ListObject), descr=) [p0, p1, p38, p33, p3, p4, p5, p6, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p2, p32, p34, p35] -p40 = getfield_gc(p33, descr=) -guard_value(p40, ConstPtr(ptr41), descr=) [p0, p1, p40, p3, p4, p5, p6, p38, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p2, p32, p33, p34, p35] -p42 = getfield_gc(p38, descr=) -p44 = new_with_vtable(143919296) -p46 = new_array(2, descr=) -setarrayitem_gc(p46, 0, p31, descr=) -setarrayitem_gc(p46, 1, p2, descr=) -setfield_gc(p44, p46, descr=) -call(ConstClass(ll_append__listPtr_objectPtr), p42, p44, descr=) -guard_no_exception(, descr=) [p0, p1, p44, p38, p3, p4, p5, p6, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p2, p32, p33, p34, p35] -debug_merge_point(' #362 POP_TOP') -debug_merge_point(' #363 LOAD_CONST') -guard_value(p3, ConstPtr(ptr50), descr=) [p0, p1, p3, p4, p5, p6, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p2, p32, p33, p34, p35] -debug_merge_point(' #366 STORE_FAST') -debug_merge_point(' #369 JUMP_FORWARD') -debug_merge_point(' #373 LOAD_FAST') -guard_nonnull_class(p30, ConstClass(W_IntObject), descr=) [p0, p1, p30, p4, p5, p6, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p35] -debug_merge_point(' #376 LOAD_CONST') -debug_merge_point(' #379 BINARY_ADD') -i52 = getfield_gc_pure(p30, descr=) -i54 = int_add_ovf(i52, 1) -guard_no_overflow(, descr=) [p0, p1, p30, i54, p4, p5, p6, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p35] -debug_merge_point(' #380 STORE_FAST') -debug_merge_point(' #383 JUMP_ABSOLUTE') -i56 = getfield_raw(151877184, descr=) -i58 = int_add(i56, 1) -setfield_raw(151877184, i58, descr=) -i61 = int_and(i58, 1089470464) -i62 = int_is_true(i61) -guard_false(i62, descr=) [p0, p1, p4, p5, p6, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p31, p32, p33, p34, p35, i54] -debug_merge_point(' #290 FOR_ITER') -jump(p1, p0, p4, p5, 290, p6, ConstPtr(ptr64), ConstPtr(ptr65), ConstPtr(ptr66), p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, i54, p31, ConstPtr(ptr67), p32, p33, p34, p35, descr=) -[c55cd887489] jit-log-opt-bridge} -[c55cdb835c7] {jit-log-opt-bridge -# bridge out of Guard 39 with 44 ops -[p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17] -debug_merge_point(' #78 POP_TOP') -debug_merge_point(' #79 LOAD_FAST') -guard_nonnull_class(p17, ConstClass(W_LongObject), descr=) [p0, p1, p17, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p2] -debug_merge_point(' #82 LOAD_FAST') -guard_nonnull_class(p16, ConstClass(W_LongObject), descr=) [p0, p1, p16, p3, p4, p5, p6, p17, p7, p8, p9, p10, p11, p12, p13, p14, p15, p2] -debug_merge_point(' #85 BINARY_ADD') -p20 = getfield_gc_pure(p17, descr=) -p21 = getfield_gc_pure(p16, descr=) -p23 = call(ConstClass(rbigint.add), p20, p21, descr=) -guard_no_exception(, descr=) [p0, p1, p16, p17, p23, p3, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p2] -debug_merge_point(' #86 STORE_FAST') -debug_merge_point(' #89 JUMP_FORWARD') -debug_merge_point(' #93 LOAD_FAST') -debug_merge_point(' #96 LOAD_FAST') -debug_merge_point(' #99 BINARY_ADD') -p25 = call(ConstClass(rbigint.add), p21, p21, descr=) -guard_no_exception(, descr=) [p0, p1, p16, p25, p3, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p2, p23] -debug_merge_point(' #100 STORE_FAST') -debug_merge_point(' #103 LOAD_FAST') -debug_merge_point(' #106 LOAD_GLOBAL') -guard_value(p3, ConstPtr(ptr26), descr=) [p0, p1, p3, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p2, p25, p23] -p27 = getfield_gc(p1, descr=) -guard_value(p27, ConstPtr(ptr28), descr=) [p0, p1, p27, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p2, p25, p23] -p29 = getfield_gc(p27, descr=) -guard_isnull(p29, descr=) [p0, p1, p29, p27, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p2, p25, p23] -p31 = getfield_gc(ConstPtr(ptr30), descr=) -guard_nonnull_class(p31, ConstClass(W_LongObject), descr=) [p0, p1, p31, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p2, p25, p23] -debug_merge_point(' #109 COMPARE_OP') -p33 = getfield_gc_pure(p31, descr=) -i35 = call(ConstClass(rbigint.gt), p25, p33, descr=) -guard_false(i35, descr=) [p0, p1, p31, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p2, p25, p23] -debug_merge_point(' #112 JUMP_IF_FALSE') -debug_merge_point(' #141 POP_TOP') -debug_merge_point(' #142 JUMP_ABSOLUTE') -i37 = getfield_raw(151877184, descr=) -i39 = int_add(i37, 1) -setfield_raw(151877184, i39, descr=) -i42 = int_and(i39, 1089470464) -i43 = int_is_true(i42) -guard_false(i43, descr=) [p0, p1, p4, p5, p6, p8, p9, p10, p11, p12, p13, p14, p15, p2, p25, p23] -debug_merge_point(' #66 FOR_ITER') -p45 = new_with_vtable(ConstClass(W_LongObject)) -setfield_gc(p45, p23, descr=) -jump(p1, p0, p4, p5, 66, p6, ConstPtr(ptr47), ConstPtr(ptr48), p8, p9, p10, p11, p12, p13, p14, p15, p25, p45, p2, descr=) -[c55cdbb68f5] jit-log-opt-bridge} -[c55cef225e5] {jit-log-opt-bridge -# bridge out of Guard 20 with 37 ops -[p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16] -debug_merge_point(' #112 JUMP_IF_FALSE') -debug_merge_point(' #115 POP_TOP') -debug_merge_point(' #116 LOAD_FAST') -guard_nonnull_class(p12, 143883328, descr=) [p0, p1, p12, p3, p4, p5, p6, p7, p8, p9, p10, p11, p13, p14, p15, p16] -debug_merge_point(' #119 LOAD_FAST') -guard_nonnull_class(p14, ConstClass(W_LongObject), descr=) [p0, p1, p14, p3, p4, p5, p12, p6, p7, p8, p9, p10, p11, p13, p15, p16] -debug_merge_point(' #122 CALL_FUNCTION') -i19 = getfield_gc(p1, descr=) -guard_false(i19, descr=) [p0, p1, p12, p3, p4, p5, p14, p6, p7, p8, p9, p10, p11, p13, p15, p16] -p20 = getfield_gc(p12, descr=) -guard_nonnull_class(p20, ConstClass(W_ListObject), descr=) [p0, p1, p20, p12, p3, p4, p5, p14, p6, p7, p8, p9, p10, p11, p13, p15, p16] -p22 = getfield_gc(p12, descr=) -guard_value(p22, ConstPtr(ptr23), descr=) [p0, p1, p22, p3, p4, p5, p20, p14, p6, p7, p8, p9, p10, p11, p12, p13, p15, p16] -p24 = getfield_gc(p20, descr=) -call(ConstClass(ll_append__listPtr_objectPtr), p24, p14, descr=) -guard_no_exception(, descr=) [p0, p1, p14, p20, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p15, p16] -debug_merge_point(' #125 POP_TOP') -debug_merge_point(' #126 LOAD_FAST') -guard_nonnull_class(p13, 143919296, descr=) [p0, p1, p13, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p14, p15, p16] -debug_merge_point(' #129 UNPACK_SEQUENCE') -p27 = getfield_gc_pure(p13, descr=) -i28 = arraylen_gc(p27, descr=) -i30 = int_ne(i28, 2) -guard_false(i30, descr=) [p0, p1, p27, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16] -p32 = getarrayitem_gc(p27, 1, descr=) -p34 = getarrayitem_gc(p27, 0, descr=) -debug_merge_point(' #132 STORE_FAST') -debug_merge_point(' #135 STORE_FAST') -debug_merge_point(' #138 JUMP_ABSOLUTE') -i36 = getfield_raw(151877184, descr=) -i38 = int_add(i36, 1) -setfield_raw(151877184, i38, descr=) -i41 = int_and(i38, 1089470464) -i42 = int_is_true(i41) -guard_false(i42, descr=) [p0, p1, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p34, p32, p15, None] -debug_merge_point(' #66 FOR_ITER') -jump(p1, p0, ConstPtr(ptr44), p3, 1, p4, 66, p5, ConstPtr(ptr47), ConstPtr(ptr48), p6, p7, p8, p9, p10, p11, p12, p13, p34, p32, p15, descr=) -[c55cef611c5] jit-log-opt-bridge} diff --git a/lib/waf/build/log.count b/lib/waf/build/log.count deleted file mode 100644 --- a/lib/waf/build/log.count +++ /dev/null @@ -1,35 +0,0 @@ -0:27365 -1:6580 -2:843 -3:636 -4:13281 -5:12986 -6:12644 -7:198 -8:614 -9:952 -10:1986 -11:838 -12:832 -13:248 -14:865 -15:148 -16:734 -17:76365 -18:73762 -19:73192 -20:198 -21:3549 -22:4115 -23:14030 -24:6708 -25:6702 -26:4222 -27:1758 -28:1892 -29:76 -30:319 -31:1128 -32:112 -33:186 -34:32 diff --git a/lib/waf/build/waf b/lib/waf/build/waf deleted file mode 100755 Binary file lib/waf/build/waf has changed diff --git a/lib/waf/build/wscript b/lib/waf/build/wscript deleted file mode 100644 --- a/lib/waf/build/wscript +++ /dev/null @@ -1,28 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 - -VERSION = '0.0.2' -APPNAME = 'build_bench' -top = '.' -out = 'out' - -def configure(conf): - conf.load('g++') - -def build(bld): - for i in xrange(13): - filez = ' '.join(['lib_%d/class_%d.cpp' % (i, j) for j in xrange(100)]) - bld.stlib( - source = filez, - target = 'lib_%d' % i, - includes = '.', # include the top-level - ) - - # disables the calls to gcc to measure the subprocess performance - from waflib import Task - def run_override(self): - return bld.exec_command('touch %s' % self.outputs[0].abspath()) - Task.classes['cxx'].run = run_override - Task.classes['cxxstlib'].run = run_override - - diff --git a/own/waf.py b/own/waf.py deleted file mode 100644 --- a/own/waf.py +++ /dev/null @@ -1,26 +0,0 @@ - -from subprocess import Popen, PIPE -import os -import time - -def main(n): - d = os.path.dirname - directory = os.path.join(d(d(os.path.abspath(__file__))), 'lib', 'waf', 'build') - times = [] - for i in range(n): - t0 = time.time() - Popen(['./waf', 'configure'], cwd=directory, - stdout=PIPE, stderr=PIPE).communicate() - Popen(['./waf', 'clean', 'build', '-j3', '-p'], - cwd=directory, stdout=PIPE, stderr=PIPE).communicate() - times.append(time.time() - t0) - return times - -if __name__ == "__main__": - import util, optparse - parser = optparse.OptionParser( - usage="%prog [options]", - description="Test the performance of the Waf benchmark") - util.add_standard_options_to(parser) - options, args = parser.parse_args() - util.run_benchmark(options, options.num_runs, main) From noreply at buildbot.pypy.org Sat Jul 16 14:33:12 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 14:33:12 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: add a minimal heap cache to be used when tracing Message-ID: <20110716123312.5151682962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45661:be79442107df Date: 2011-07-16 14:32 +0200 http://bitbucket.org/pypy/pypy/changeset/be79442107df/ Log: add a minimal heap cache to be used when tracing diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -502,7 +502,12 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @@ -532,7 +537,11 @@ @arguments("box", "descr", "box") def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box and tobox is valuebox: + return self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + self.metainterp.heap_cache[fielddescr] = (box, valuebox) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any @@ -617,7 +626,7 @@ @arguments("orgpc", "box", "descr") def _opimpl_getfield_vable(self, pc, box, fielddescr): if self._nonstandard_virtualizable(pc, box): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any(box, fielddescr) self.metainterp.check_synchronized_virtualizable() index = self._get_virtualizable_field_index(fielddescr) return self.metainterp.virtualizable_boxes[index] @@ -629,8 +638,7 @@ @arguments("orgpc", "box", "descr", "box") def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox): if self._nonstandard_virtualizable(pc, box): - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) - return + return self._opimpl_setfield_gc_any(box, fielddescr, valuebox) index = self._get_virtualizable_field_index(fielddescr) self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -1462,6 +1470,9 @@ self.known_class_boxes = {} # contains frame boxes that are not virtualizables self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1637,6 +1648,9 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + if opnum != rop.SETFIELD_GC and self.heap_cache: + if not (rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST): + self.heap_cache = {} op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox @@ -1804,6 +1818,7 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1024,69 +1024,6 @@ res = self.meta_interp(main, []) assert res == 55 - def test_dont_record_repeated_guard_class(self): - class A: - pass - class B(A): - pass - @dont_look_inside - def extern(n): - if n == -7: - return None - elif n: - return A() - else: - return B() - def fn(n): - obj = extern(n) - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=1, guard_nonnull=1) - res = self.interp_operations(fn, [1]) - assert not res - - def test_dont_record_guard_class_after_new(self): - class A: - pass - class B(A): - pass - def fn(n): - if n == -7: - obj = None - elif n: - obj = A() - else: - obj = B() - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=0, guard_nonnull=0) - res = self.interp_operations(fn, [1]) - assert not res - - def test_guard_isnull_nullifies(self): - class A: - pass - a = A() - a.x = None - def fn(n): - if n == -7: - a.x = "" - obj = a.x - res = 0 - if not obj: - res += 1 - if obj: - res += 1 - if obj is None: - res += 1 - if obj is not None: - res += 1 - return res - res = self.interp_operations(fn, [0]) - assert res == 2 - self.check_operations_history(guard_isnull=1) def test_assert_isinstance(self): class A: diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,147 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + return a.x + x1 + res = self.interp_operations(fn, [7]) + assert res == 5 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) From noreply at buildbot.pypy.org Sat Jul 16 14:59:45 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sat, 16 Jul 2011 14:59:45 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: Some extra debug prints. Make optimize_STRLEN keep the original result box if the strlen op is emitted. Message-ID: <20110716125945.44D7482962@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45662:a8eedb9a9b64 Date: 2011-07-16 14:59 +0200 http://bitbucket.org/pypy/pypy/changeset/a8eedb9a9b64/ Log: Some extra debug prints. Make optimize_STRLEN keep the original result box if the strlen op is emitted. diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6453,6 +6453,20 @@ """ self.optimize_loop(ops, expected) + def test_loopinvariant_strlen(self): + ops = """ + [p9] + i843 = strlen(p9) + call(i843, descr=nonwritedescr) + jump(p9) + """ + expected = """ + [p9, i2] + call(i2, descr=nonwritedescr) + jump(p9, i2) + """ + self.optimize_loop(ops, expected) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -184,7 +184,7 @@ virtual_state = modifier.get_virtual_state(jump_args) values = [self.getvalue(arg) for arg in jump_args] inputargs = virtual_state.make_inputargs(values) - short_inputargs = virtual_state.make_inputargs(values, keyboxes=True) + short_inputargs = virtual_state.make_inputargs(values, keyboxes=True) self.constant_inputargs = {} for box in jump_args: @@ -201,6 +201,20 @@ self.optimizer = self.optimizer.new() loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps + logops = self.optimizer.loop.logops + if logops: + args = ", ".join([logops.repr_of_arg(arg) for arg in inputargs]) + debug_print('inputargs: ' + args) + args = ", ".join([logops.repr_of_arg(arg) for arg in short_inputargs]) + debug_print('short inputargs: ' + args) + debug_start('jit-short-boxes') + for box, op in self.short_boxes.items(): + if op: + debug_print(logops.repr_of_arg(box) + ': ' + logops.repr_of_resop(op)) + else: + debug_print(logops.repr_of_arg(box) + ': None') + debug_stop('jit-short-boxes') + # Force virtuals amoung the jump_args of the preamble to get the # operations needed to setup the proper state of those virtuals # in the peeled loop @@ -229,7 +243,7 @@ self.optimizer.send_extra_operation(guard) self.optimizer.flush() self.optimizer.emitting_dissabled = False - + initial_inputargs_len = len(inputargs) self.inliner = Inliner(loop.inputargs, jump_args) @@ -351,8 +365,12 @@ args = op.getarglist() if op.is_guard(): args = args + op.getfailargs() - + + if self.optimizer.loop.logops: + debug_print('OP: ' + self.optimizer.loop.logops.repr_of_resop(op)) for a in args: + if self.optimizer.loop.logops: + debug_print('A: ' + self.optimizer.loop.logops.repr_of_arg(a)) self.import_box(a, inputargs, short, short_jumpargs, jumpargs, short_seen) i += 1 diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -47,7 +47,7 @@ class __extend__(optimizer.OptValue): """New methods added to the base class OptValue for this file.""" - def getstrlen(self, optimization, mode): + def getstrlen(self, optimization, mode, lengthbox=None): if mode is mode_string: s = self.get_constant_string_spec(mode_string) if s is not None: @@ -60,7 +60,8 @@ return None self.ensure_nonnull() box = self.force_box() - lengthbox = BoxInt() + if not lengthbox: + lengthbox = BoxInt() optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @@ -124,7 +125,7 @@ assert 0 <= start <= stop <= len(longerlist) self._chars = longerlist[start:stop] - def getstrlen(self, _, mode): + def getstrlen(self, _, mode, lengthbox=None): if self._lengthbox is None: self._lengthbox = ConstInt(len(self._chars)) return self._lengthbox @@ -185,7 +186,7 @@ self.left = left self.right = right - def getstrlen(self, optimizer, mode): + def getstrlen(self, optimizer, mode, lengthbox=None): if self.lengthbox is None: len1box = self.left.getstrlen(optimizer, mode) if len1box is None: @@ -249,7 +250,7 @@ self.vstart = vstart self.vlength = vlength - def getstrlen(self, _, mode): + def getstrlen(self, _, mode, lengthbox=None): return self.vlength.force_box() @specialize.arg(1) @@ -453,8 +454,9 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode) - self.make_equal_to(op.result, self.getvalue(lengthbox)) + lengthbox = value.getstrlen(self, mode, op.result) + if lengthbox is not op.result: + self.make_equal_to(op.result, self.getvalue(lengthbox)) def optimize_CALL(self, op): # dispatch based on 'oopspecindex' to a method that handles From noreply at buildbot.pypy.org Sat Jul 16 16:06:48 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 16 Jul 2011 16:06:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Write the progbits section magic marker to make the stack non-executable under (at least) Gentoo linux. Thanks Amaury. Message-ID: <20110716140648.87FA782962@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45663:eef75a4b072e Date: 2011-07-16 16:06 +0200 http://bitbucket.org/pypy/pypy/changeset/eef75a4b072e/ Log: Write the progbits section magic marker to make the stack non-executable under (at least) Gentoo linux. Thanks Amaury. diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1824,6 +1824,11 @@ __gccallshapes: """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) + print >> output, """\ + #if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits + #endif + """ def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) From noreply at buildbot.pypy.org Sat Jul 16 16:18:24 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 16:18:24 +0200 (CEST) Subject: [pypy-commit] pypy default: fix tests Message-ID: <20110716141824.4432382962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45664:f12c4e733acd Date: 2011-07-16 10:00 +0200 http://bitbucket.org/pypy/pypy/changeset/f12c4e733acd/ Log: fix tests diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -4,6 +4,7 @@ """ from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.rlib.objectmodel import specialize class BogusBytecode(Exception): pass @@ -15,8 +16,12 @@ return a class TrivialSpace(object): - def wrap(self, x): - return x + w_ValueError = None + + @specialize.argtype(1) + def wrap(self, w_obj): + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -7,6 +7,8 @@ from pypy.tool.sourcetools import func_with_new_name import math +INSERT_SORT_THRESH = 15 + def dummy1(v): assert isinstance(v, float) return v @@ -21,6 +23,8 @@ reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) class Signature(object): def __init__(self): @@ -88,6 +92,18 @@ signature = Signature() def impl(self, space, w_other): w_other = convert_to_array(space, w_other) + try: + w_other_size = w_other.find_size() + self_size = self.find_size() + except ValueError: + # this will be raised if one of the arrays is a scalar. + pass + else: + # Need a better dimension check here for N-dim arrays + if w_other_size != self_size: + raise OperationError(space.w_ValueError, + space.wrap("Cannot %s arrays of unequal dimensions" \ + % function.__name__)) new_sig = self.signature.transition(signature) res = Call2( function, @@ -111,7 +127,7 @@ signature = Signature() def impl(self, space, w_other): new_sig = self.signature.transition(signature) - w_other = FloatWrapper(space.float_w(w_other)) + w_other = convert_to_array(space, w_other) res = Call2( function, w_other, @@ -235,6 +251,80 @@ else: return self.descr_mul(space, w_other) + def _insertion_sort(self, storage, left, right): + i = left + 1 + while i <= right: + temp = storage[i] + j = i - 1 + while j >= left and storage[j] > temp: + storage[j + 1] = storage[j] + j -= 1 + storage[j + 1] = temp + i += 1 + + def descr_sort(self, space): + storage = self.get_concrete().storage + # can replace these with integer/bool numpy arrays when we add dtypes + lefts = [0] + rights = [self.find_size() - 1] + checkpivots = [False] + while lefts: + left = lefts.pop() + right = rights.pop() + checkpivot = checkpivots.pop() + # just use middle element for now. will change to med of 3 soon + mid = left + (right - left) / 2 + pivot = storage[mid] + if checkpivot and pivot == storage[left - 1]: + storage[mid], storage[left] = storage[left], storage[mid] + i = left + 1 + j = right + while 1: + while storage[j] != pivot: + j -= 1 + while storage[i] == pivot: + if i >= j: break + i += 1 + if i >= j: break + storage[i], storage[j] = storage[j], storage[i] + storage[j] = pivot + if right > j + 1: + if right - j + 1 < INSERT_SORT_THRESH: + self._insertion_sort(storage, j + 1, right) + else: + lefts.append(j + 1) + rights.append(right) + checkpivots.append(False) + else: + storage[mid], storage[right] = storage[right], storage[mid] + i = left + j = right - 1 + while 1: + while storage[i] < pivot: + i += 1 + while storage[j] >= pivot: + if i >= j: break + j -= 1 + if i >= j: break + storage[i], storage[j] = storage[j], storage[i] + storage[right] = storage[i] + storage[i] = pivot + # we can have the smaller subarray sorted first + if left < i - 1: + if i - 1 - left < INSERT_SORT_THRESH: + self._insertion_sort(storage, left, i - 1) + else: + lefts.append(left) + rights.append(i - 1) + checkpivots.append(checkpivot) + if right > i + 1: + if right - i - 1 < INSERT_SORT_THRESH: + self._insertion_sort(storage, i + 1, right) + else: + lefts.append(i + 1) + rights.append(right) + checkpivots.append(True) + def get_concrete(self): raise NotImplementedError @@ -244,8 +334,20 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_get_size(self, space): + return space.wrap(self.find_size()) + + def descr_get_ndim(self, space): + return space.wrap(self.find_ndim()) + + def descr_repr(self, space): + return self.get_concrete().descr_repr(space) + + def descr_str(self, space): + return self.get_concrete().descr_str(space) + def descr_getitem(self, space, w_idx): - # TODO: indexing by tuples + # TODO: indexing by tuples and lists start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) if step == 0: # Single index @@ -255,10 +357,16 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().descr_setitem(space, start, space.float_w(w_value)) + else: + self.get_concrete().descr_setslice(space, start, stop, step, slice_length, w_value) def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) @@ -287,6 +395,9 @@ def find_size(self): raise ValueError + def find_ndim(self): + raise ValueError + def eval(self, i): return self.float_value @@ -336,6 +447,12 @@ return self.forced_result.find_size() return self._find_size() + def find_ndim(self): + if self.forced_result is not None: + # The result has been computed and sources may be unavailable + return self.forced_result.find_ndim() + return self._find_ndim() + class Call1(VirtualArray): _immutable_fields_ = ["function", "values"] @@ -351,6 +468,9 @@ def _find_size(self): return self.values.find_size() + def _find_ndim(self): + return self.values.find_ndim() + def _eval(self, i): return self.function(self.values.eval(i)) @@ -377,6 +497,13 @@ pass return self.right.find_size() + def _find_ndim(self): + try: + return self.left.find_ndim() + except ValueError: + pass + return self.right.find_ndim() + def _eval(self, i): lhs, rhs = self.left.eval(i), self.right.eval(i) return self.function(lhs, rhs) @@ -408,9 +535,12 @@ @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): + # need to change this so that it can deal with slices return self.parent.descr_setitem(space, self.calc_index(item), value) def descr_len(self, space): + # This will need to change for multidimensional arrays. + # For them, len returns the size of the first dimension return space.wrap(self.find_size()) def calc_index(self, item): @@ -426,10 +556,14 @@ self.stop = stop self.step = step self.size = slice_length + self.ndim = 1 def find_size(self): return self.size + def find_ndim(self): + return self.ndim + def calc_index(self, item): return (self.start + item * self.step) @@ -440,16 +574,22 @@ def __init__(self, size): BaseArray.__init__(self) self.size = size + self.ndim = 1 self.storage = lltype.malloc(TP, size, zero=True, flavor='raw', track_allocation=False) # XXX find out why test_zjit explodes with trackign of allocations - + # we could probably put get_concrete, find_size, and find_dim all in + # a new class called ConcreteArray or some such because they will + # be the same for multi-dimensional arrays. def get_concrete(self): return self def find_size(self): return self.size + def find_ndim(self): + return self.ndim + def eval(self, i): return self.storage[i] @@ -470,12 +610,72 @@ def getitem(self, item): return self.storage[item] + def _getnums(self, comma): + # XXX this should be improved in the future + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def descr_repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def descr_str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) self.invalidated() self.storage[item] = value + def _setslice1(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def _setslice2(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def descr_setslice(self, space, start, stop, step, slice_length, arr): + i = start + if stop < 0: + stop += self.find_size() + if step > 0: + stop = min(stop, self.find_size()) + else: + stop = max(stop, 0) + if not isinstance(arr, BaseArray): + arr = convert_to_array(space, arr) + if step > 0: + self._setslice1(start, stop, step, arr) + else: + self._setslice2(start, stop, step, arr) + def __del__(self): lltype.free(self.storage, flavor='raw') @@ -538,4 +738,5 @@ all = interp2app(BaseArray.descr_all), any = interp2app(BaseArray.descr_any), dot = interp2app(BaseArray.descr_dot), + sort = interp2app(BaseArray.descr_sort), ) diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -18,8 +18,8 @@ def test_slice_signature(self, space): ar = SingleDimArray(10) - v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1))) - v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1))) + v1 = ar.descr_getitem(space, space.wrap(slice(0, 10, 1))) + v2 = ar.descr_getitem(space, space.wrap(slice(9, None, -1))) assert v1.signature is v2.signature v3 = ar.descr_add(space, v1) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -60,6 +60,29 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) @@ -96,6 +119,9 @@ b = a + 5 for i in range(5): assert b[i] == i + 5 + b = 5 + a + for i in range(5): + assert b[i] == 5 + i def test_add_list(self): from numpy import array @@ -105,6 +131,16 @@ assert isinstance(c, array) for i in range(5): assert c[i] == 4 + c = b + a + assert isinstance(c, array) + for i in range(5): + assert c[i] == 4 + + def test_add_unequal_size(self): + from numpy import array + a = array(range(5)) + b = array(range(3)) + raises(ValueError, "a + b") def test_subtract(self): from numpy import array @@ -127,6 +163,9 @@ b = a - 5 for i in range(5): assert b[i] == i - 5 + b = 5 - a + for i in range(5): + assert b[i] == 5 - i def test_mul(self): from numpy import array @@ -141,6 +180,9 @@ b = a * 5 for i in range(5): assert b[i] == i * 5 + b = 5 * a + for i in range(5): + assert b[i] == 5 * i def test_div(self): from numpy import array @@ -159,10 +201,13 @@ def test_div_constant(self): from numpy import array - a = array(range(5)) + a = array(range(1,6)) b = a / 5.0 for i in range(5): - assert b[i] == i / 5.0 + assert b[i] == (i+1) / 5.0 + b = 5.0 / a + for i in range(5): + assert b[i] == 5.0 / (i+1) def test_pow(self): from numpy import array @@ -186,6 +231,9 @@ b = a ** 2 for i in range(5): assert b[i] == i ** 2 + b = 2 ** a + for i in range(5): + assert b[i] == 2 ** i def test_mod(self): from numpy import array @@ -204,10 +252,13 @@ def test_mod_constant(self): from numpy import array - a = array(range(5)) + a = array(range(1,6)) b = a % 2 for i in range(5): - assert b[i] == i % 2 + assert b[i] == (i+1) % 2 + b = 2 % a + for i in range(5): + assert b[i] == 2 % (i+1) def test_pos(self): from numpy import array @@ -366,6 +417,14 @@ for i in xrange(5): assert b[i] == 2.5*a[i] + def test_sort(self): + from numpy import array + a = array(range(19,-1,-1)) + b = array(range(20)) + a.sort() + for i in xrange(20): + assert a[i] == b[i] + class AppTestSupport(object): def setup_class(cls): diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -5,6 +5,7 @@ from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): w_ValueError = None @@ -248,6 +249,21 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar.descr_setslice(space, 0, step*i, step, i, ar2) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -89,7 +89,7 @@ while asm[asm_index][0] < op.offset: asm_index += 1 end_index = asm_index - while asm[end_index][0] < end: + while asm[end_index][0] < end and end_index < len(asm) - 1: end_index += 1 op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) return loop @@ -369,7 +369,11 @@ name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] - parser.postprocess(loop, backend_tp=bname, backend_dump=dump, - dump_start=start_ofs) + try: + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) + except: + import pdb, sys + pdb.post_mortem(sys.exc_info()[2]) loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest2.log @@ -0,0 +1,301 @@ +[1f5e7f69779] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f7fe75] jit-backend-dump} +[1f5e7f84fc4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f87ac1] jit-backend-dump} +[1f5e7f8a0b4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b08a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f8da6b] jit-backend-dump} +[1f5e7f8f4f6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b13d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f92b83] jit-backend-dump} +[1f5e7f95b99] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 +[1f5e7f988d0] jit-backend-dump} +[1f5e7fa16fb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b28e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 +[1f5e7fa47ac] jit-backend-dump} +[1f5e7fab3a4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 +[1f5e7faf1ca] jit-backend-dump} +[1f5e7fb0813] {jit-backend-counts +[1f5e7fb0f61] jit-backend-counts} +[1f5fd38be3e] {jit-backend +[1f5fe729336] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB30B00C0A897F00004D8B334983C60149BB30B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030300000049BB00B0A007897F000041FFD34440484C3D39030400000049BB00B0A007897F000041FFD34440484C3907070305000000 +[1f5fe73276a] jit-backend-dump} +[1f5fe73438f] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f8907a0b45d to 7f8907a0b4c3 (bootstrap 7f8907a0b3d5) +[1f5fe7369af] jit-backend-addr} +[1f5fe737940] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3e5 +0 50FFFFFF +[1f5fe74b40e] jit-backend-dump} +[1f5fe74c63d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b484 +0 95000000 +[1f5fe74da6a] jit-backend-dump} +[1f5fe74e438] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 9B000000 +[1f5fe74f513] jit-backend-dump} +[1f5fe74fd2e] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b4b7 +0 91000000 +[1f5fe750d8c] jit-backend-dump} +[1f5fe75373f] jit-backend} +[1f5fe755abc] {jit-log-opt-loop +# Loop 0 : loop with 26 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 1) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f5fe92b8af] jit-log-opt-loop} +[1f5fe944ae5] {jit-backend +[1f5fee20651] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b565 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C254010000000049BB38B00C0A897F0000498B0B4883C10149BB38B00C0A897F000049890B4983F8010F85000000004883FE017206813E980700000F85000000004983FA000F850000000049BBA8F0B407897F00004D39DC0F8500000000488B56084881FA102700000F8D000000004989D44883E2024883FA000F85000000004983C403488B1425A0536B024883EA0148891425A0536B024883FA000F8C000000004C89BD70FFFFFF4C89B568FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4D89E749BB5DB4A007897F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DAE9CCFEFFFF49BB00B0A007897F000041FFD321383C343029241D180C08030600000049BB00B0A007897F000041FFD3383C18343029240C08030700000049BB00B0A007897F000041FFD329383C3430241808030800000049BB00B0A007897F000041FFD3383C3034241808030900000049BB00B0A007897F000041FFD3383C183424030A00000049BB00B0A007897F000041FFD3383C34241809030B00000049BB00B0A007897F000041FFD3383C34243107030C000000 +[1f5fee2e673] jit-backend-dump} +[1f5fee2f38d] {jit-backend-addr +Loop 1 ( #9 LOAD_FAST) has address 7f8907a0b631 to 7f8907a0b6f8 (bootstrap 7f8907a0b565) +[1f5fee312e3] jit-backend-addr} +[1f5fee320ed] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b575 +0 50FFFFFF +[1f5fee3e903] jit-backend-dump} +[1f5fee3fbff] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b655 +0 0C010000 +[1f5fee41579] jit-backend-dump} +[1f5fee421af] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b667 +0 17010000 +[1f5fee43835] jit-backend-dump} +[1f5fee44261] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b671 +0 28010000 +[1f5fee457c1] jit-backend-dump} +[1f5fee461a5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b684 +0 2F010000 +[1f5fee475d3] jit-backend-dump} +[1f5fee47f57] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b695 +0 37010000 +[1f5fee4933d] jit-backend-dump} +[1f5fee49cd9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6a6 +0 3D010000 +[1f5fee4b0ad] jit-backend-dump} +[1f5fee4ba4f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6c8 +0 33010000 +[1f5fee4cf61] jit-backend-dump} +[1f5fee4dc45] jit-backend} +[1f5fee4f3a9] {jit-log-opt-loop +# Loop 1 : entry bridge with 31 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10] +debug_merge_point(0, ' #9 LOAD_FAST') ++234: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10] ++244: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10] ++262: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p10] +debug_merge_point(0, ' #12 LOAD_CONST') ++272: guard_value(p3, ConstPtr(ptr14), descr=) [p1, p0, p3, p2, p5, p8, p10] +debug_merge_point(0, ' #15 COMPARE_OP') ++291: i15 = getfield_gc_pure(p8, descr=) ++295: i17 = int_lt(i15, 10000) +guard_true(i17, descr=) [p1, p0, p8, p2, p5] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++308: i19 = int_and(i15, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++315: i20 = int_is_true(i19) +guard_false(i20, descr=) [p1, p0, p2, p5, p8, i19] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++325: i22 = int_add(i15, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++329: i24 = getfield_raw(40588192, descr=) ++337: i26 = int_sub(i24, 1) ++341: setfield_raw(40588192, i26, descr=) ++349: i28 = int_lt(i26, 0) +guard_false(i28, descr=) [p1, p0, p2, p5, i22, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++359: jump(p0, p1, p2, p5, i22, descr=) ++403: --end of the loop-- +[1f60036d952] jit-log-opt-loop} +[1f600719a74] {jit-backend +[1f600759dac] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b817 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB40B00C0A897F00004D8B334983C60149BB40B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF024C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030D00000049BB00B0A007897F000041FFD34440484C3D39030E00000049BB00B0A007897F000041FFD34440484C390707030F000000 +[1f60076fd90] jit-backend-dump} +[1f600770f30] {jit-backend-addr +Loop 2 ( #9 LOAD_FAST) has address 7f8907a0b89f to 7f8907a0b905 (bootstrap 7f8907a0b817) +[1f6007730fc] jit-backend-addr} +[1f600773fde] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b827 +0 50FFFFFF +[1f600775c76] jit-backend-dump} +[1f600776a38] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8c6 +0 95000000 +[1f600778112] jit-backend-dump} +[1f600778b8c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8d7 +0 9B000000 +[1f60077a04a] jit-backend-dump} +[1f60077aa6a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8f9 +0 91000000 +[1f60077bf10] jit-backend-dump} +[1f60077cc24] jit-backend} +[1f60077e094] {jit-log-opt-loop +# Loop 2 : loop with 25 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 2) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f6007a567c] jit-log-opt-loop} +[1f600802cd6] {jit-backend +[1f600862dd8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9b7 +0 488DA50000000049BB48B00C0A897F00004D8B3B4983C70149BB48B00C0A897F00004D893B4D89F74983C6010F80000000004C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C00000000488B0425704F3D01488D5010483B1425784F3D01761A49BB10B2A007897F000041FFD349BB8EB2A007897F000041FFD348C7009807000048891425704F3D014C89700848898550FFFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBA8F0B407897F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00100000048C7C709000000488BB550FFFFFF48C7C30000000048C7C20000000049BB31B6A007897F000041FFE349BB00B0A007897F000041FFD3444039484C3D031000000049BB00B0A007897F000041FFD34440484C39070311000000 +[1f60086ba5a] jit-backend-dump} +[1f60086d36e] {jit-backend-addr +Bridge out of guard 4 has address 7f8907a0b9b7 to 7f8907a0bab1 +[1f60086ffd2] jit-backend-addr} +[1f600870dca] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9ba +0 C0FEFFFF +[1f60087281c] jit-backend-dump} +[1f600873506] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9e5 +0 C8000000 +[1f600874b44] jit-backend-dump} +[1f6008754d4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0ba03 +0 C2000000 +[1f600876956] jit-backend-dump} +[1f600877b1a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 1E050000 +[1f600878f4e] jit-backend-dump} +[1f600884c12] jit-backend} +[1f60088780a] {jit-log-opt-bridge +# bridge out of Guard 4 with 16 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #31 LOAD_FAST') +debug_merge_point(0, ' #34 LOAD_CONST') +debug_merge_point(0, ' #37 INPLACE_ADD') ++37: i7 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i7, p2, p3, i5] +debug_merge_point(0, ' #38 STORE_FAST') +debug_merge_point(0, ' #41 JUMP_ABSOLUTE') ++50: i9 = getfield_raw(40588192, descr=) ++58: i11 = int_sub(i9, 1) ++62: setfield_raw(40588192, i11, descr=) ++70: i13 = int_lt(i11, 0) +guard_false(i13, descr=) [p0, p1, p2, p3, i7, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++80: p16 = new_with_vtable(ConstClass(W_IntObject)) ++143: setfield_gc(p16, i7, descr=) ++147: jump(p1, p0, p2, ConstPtr(ptr17), 0, p3, 1, 9, p16, ConstPtr(ptr21), ConstPtr(ptr22), descr=) ++250: --end of the loop-- +[1f6008aa976] jit-log-opt-bridge} +[1f600912c98] {jit-backend-counts +0:1982 +1:1985 +2:0 +3:1782 +[1f600916544] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -220,4 +220,4 @@ 'logtest2.log'))) assert 'cmp' in loops[1].operations[1].asm # bridge - assert 'cmp' in loops[3].operations[1].asm + assert 'jo' in loops[3].operations[3].asm From noreply at buildbot.pypy.org Sat Jul 16 16:18:25 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 16:18:25 +0200 (CEST) Subject: [pypy-commit] pypy default: Backed out changeset f12c4e733acd Message-ID: <20110716141825.7337C82962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45665:eaa6922449c1 Date: 2011-07-16 10:14 +0200 http://bitbucket.org/pypy/pypy/changeset/eaa6922449c1/ Log: Backed out changeset f12c4e733acd Ops, too much diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -4,7 +4,6 @@ """ from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray -from pypy.rlib.objectmodel import specialize class BogusBytecode(Exception): pass @@ -16,12 +15,8 @@ return a class TrivialSpace(object): - w_ValueError = None - - @specialize.argtype(1) - def wrap(self, w_obj): - return w_obj - + def wrap(self, x): + return x def numpy_compile(bytecode, array_size): space = TrivialSpace() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -7,8 +7,6 @@ from pypy.tool.sourcetools import func_with_new_name import math -INSERT_SORT_THRESH = 15 - def dummy1(v): assert isinstance(v, float) return v @@ -23,8 +21,6 @@ reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) -slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) -slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) class Signature(object): def __init__(self): @@ -92,18 +88,6 @@ signature = Signature() def impl(self, space, w_other): w_other = convert_to_array(space, w_other) - try: - w_other_size = w_other.find_size() - self_size = self.find_size() - except ValueError: - # this will be raised if one of the arrays is a scalar. - pass - else: - # Need a better dimension check here for N-dim arrays - if w_other_size != self_size: - raise OperationError(space.w_ValueError, - space.wrap("Cannot %s arrays of unequal dimensions" \ - % function.__name__)) new_sig = self.signature.transition(signature) res = Call2( function, @@ -127,7 +111,7 @@ signature = Signature() def impl(self, space, w_other): new_sig = self.signature.transition(signature) - w_other = convert_to_array(space, w_other) + w_other = FloatWrapper(space.float_w(w_other)) res = Call2( function, w_other, @@ -251,80 +235,6 @@ else: return self.descr_mul(space, w_other) - def _insertion_sort(self, storage, left, right): - i = left + 1 - while i <= right: - temp = storage[i] - j = i - 1 - while j >= left and storage[j] > temp: - storage[j + 1] = storage[j] - j -= 1 - storage[j + 1] = temp - i += 1 - - def descr_sort(self, space): - storage = self.get_concrete().storage - # can replace these with integer/bool numpy arrays when we add dtypes - lefts = [0] - rights = [self.find_size() - 1] - checkpivots = [False] - while lefts: - left = lefts.pop() - right = rights.pop() - checkpivot = checkpivots.pop() - # just use middle element for now. will change to med of 3 soon - mid = left + (right - left) / 2 - pivot = storage[mid] - if checkpivot and pivot == storage[left - 1]: - storage[mid], storage[left] = storage[left], storage[mid] - i = left + 1 - j = right - while 1: - while storage[j] != pivot: - j -= 1 - while storage[i] == pivot: - if i >= j: break - i += 1 - if i >= j: break - storage[i], storage[j] = storage[j], storage[i] - storage[j] = pivot - if right > j + 1: - if right - j + 1 < INSERT_SORT_THRESH: - self._insertion_sort(storage, j + 1, right) - else: - lefts.append(j + 1) - rights.append(right) - checkpivots.append(False) - else: - storage[mid], storage[right] = storage[right], storage[mid] - i = left - j = right - 1 - while 1: - while storage[i] < pivot: - i += 1 - while storage[j] >= pivot: - if i >= j: break - j -= 1 - if i >= j: break - storage[i], storage[j] = storage[j], storage[i] - storage[right] = storage[i] - storage[i] = pivot - # we can have the smaller subarray sorted first - if left < i - 1: - if i - 1 - left < INSERT_SORT_THRESH: - self._insertion_sort(storage, left, i - 1) - else: - lefts.append(left) - rights.append(i - 1) - checkpivots.append(checkpivot) - if right > i + 1: - if right - i - 1 < INSERT_SORT_THRESH: - self._insertion_sort(storage, i + 1, right) - else: - lefts.append(i + 1) - rights.append(right) - checkpivots.append(True) - def get_concrete(self): raise NotImplementedError @@ -334,20 +244,8 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) - def descr_get_size(self, space): - return space.wrap(self.find_size()) - - def descr_get_ndim(self, space): - return space.wrap(self.find_ndim()) - - def descr_repr(self, space): - return self.get_concrete().descr_repr(space) - - def descr_str(self, space): - return self.get_concrete().descr_str(space) - def descr_getitem(self, space, w_idx): - # TODO: indexing by tuples and lists + # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) if step == 0: # Single index @@ -357,16 +255,10 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - def descr_setitem(self, space, w_idx, w_value): - # TODO: indexing by tuples and lists + @unwrap_spec(item=int, value=float) + def descr_setitem(self, space, item, value): self.invalidated() - start, stop, step, slice_length = space.decode_index4(w_idx, - self.find_size()) - if step == 0: - # Single index - self.get_concrete().descr_setitem(space, start, space.float_w(w_value)) - else: - self.get_concrete().descr_setslice(space, start, stop, step, slice_length, w_value) + return self.get_concrete().descr_setitem(space, item, value) def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) @@ -395,9 +287,6 @@ def find_size(self): raise ValueError - def find_ndim(self): - raise ValueError - def eval(self, i): return self.float_value @@ -447,12 +336,6 @@ return self.forced_result.find_size() return self._find_size() - def find_ndim(self): - if self.forced_result is not None: - # The result has been computed and sources may be unavailable - return self.forced_result.find_ndim() - return self._find_ndim() - class Call1(VirtualArray): _immutable_fields_ = ["function", "values"] @@ -468,9 +351,6 @@ def _find_size(self): return self.values.find_size() - def _find_ndim(self): - return self.values.find_ndim() - def _eval(self, i): return self.function(self.values.eval(i)) @@ -497,13 +377,6 @@ pass return self.right.find_size() - def _find_ndim(self): - try: - return self.left.find_ndim() - except ValueError: - pass - return self.right.find_ndim() - def _eval(self, i): lhs, rhs = self.left.eval(i), self.right.eval(i) return self.function(lhs, rhs) @@ -535,12 +408,9 @@ @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): - # need to change this so that it can deal with slices return self.parent.descr_setitem(space, self.calc_index(item), value) def descr_len(self, space): - # This will need to change for multidimensional arrays. - # For them, len returns the size of the first dimension return space.wrap(self.find_size()) def calc_index(self, item): @@ -556,14 +426,10 @@ self.stop = stop self.step = step self.size = slice_length - self.ndim = 1 def find_size(self): return self.size - def find_ndim(self): - return self.ndim - def calc_index(self, item): return (self.start + item * self.step) @@ -574,22 +440,16 @@ def __init__(self, size): BaseArray.__init__(self) self.size = size - self.ndim = 1 self.storage = lltype.malloc(TP, size, zero=True, flavor='raw', track_allocation=False) # XXX find out why test_zjit explodes with trackign of allocations - # we could probably put get_concrete, find_size, and find_dim all in - # a new class called ConcreteArray or some such because they will - # be the same for multi-dimensional arrays. + def get_concrete(self): return self def find_size(self): return self.size - def find_ndim(self): - return self.ndim - def eval(self, i): return self.storage[i] @@ -610,72 +470,12 @@ def getitem(self, item): return self.storage[item] - def _getnums(self, comma): - # XXX this should be improved in the future - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def descr_repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def descr_str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) self.invalidated() self.storage[item] = value - def _setslice1(self, start, stop, step, arr): - signature = Signature() - new_sig = self.signature.transition(signature) - i = start - j = 0 - while i < stop: - slice_driver1.jit_merge_point(signature=signature, self=self, - step=step, stop=stop, i=i, j=j, arr=arr) - self.storage[i] = arr.eval(j) - j += 1 - i += step - - def _setslice2(self, start, stop, step, arr): - signature = Signature() - new_sig = self.signature.transition(signature) - i = start - j = 0 - while i > stop: - slice_driver2.jit_merge_point(signature=signature, self=self, - step=step, stop=stop, i=i, j=j, arr=arr) - self.storage[i] = arr.eval(j) - j += 1 - i += step - - def descr_setslice(self, space, start, stop, step, slice_length, arr): - i = start - if stop < 0: - stop += self.find_size() - if step > 0: - stop = min(stop, self.find_size()) - else: - stop = max(stop, 0) - if not isinstance(arr, BaseArray): - arr = convert_to_array(space, arr) - if step > 0: - self._setslice1(start, stop, step, arr) - else: - self._setslice2(start, stop, step, arr) - def __del__(self): lltype.free(self.storage, flavor='raw') @@ -738,5 +538,4 @@ all = interp2app(BaseArray.descr_all), any = interp2app(BaseArray.descr_any), dot = interp2app(BaseArray.descr_dot), - sort = interp2app(BaseArray.descr_sort), ) diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -18,8 +18,8 @@ def test_slice_signature(self, space): ar = SingleDimArray(10) - v1 = ar.descr_getitem(space, space.wrap(slice(0, 10, 1))) - v2 = ar.descr_getitem(space, space.wrap(slice(9, None, -1))) + v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1))) + v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1))) assert v1.signature is v2.signature v3 = ar.descr_add(space, v1) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -60,29 +60,6 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") - def test_setslice_array(self): - from numpy import array - a = array(range(5)) - b = array(range(2)) - a[1:4:2] = b - assert a[1] == 0. - assert a[3] == 1. - - def test_setslice_list(self): - from numpy import array - a = array(range(5)) - b = [0., 1.] - a[1:4:2] = b - assert a[1] == 0. - assert a[3] == 1. - - def test_setslice_constant(self): - from numpy import array - a = array(range(5)) - a[1:4:2] = 0. - assert a[1] == 0. - assert a[3] == 0. - def test_len(self): from numpy import array a = array(range(5)) @@ -119,9 +96,6 @@ b = a + 5 for i in range(5): assert b[i] == i + 5 - b = 5 + a - for i in range(5): - assert b[i] == 5 + i def test_add_list(self): from numpy import array @@ -131,16 +105,6 @@ assert isinstance(c, array) for i in range(5): assert c[i] == 4 - c = b + a - assert isinstance(c, array) - for i in range(5): - assert c[i] == 4 - - def test_add_unequal_size(self): - from numpy import array - a = array(range(5)) - b = array(range(3)) - raises(ValueError, "a + b") def test_subtract(self): from numpy import array @@ -163,9 +127,6 @@ b = a - 5 for i in range(5): assert b[i] == i - 5 - b = 5 - a - for i in range(5): - assert b[i] == 5 - i def test_mul(self): from numpy import array @@ -180,9 +141,6 @@ b = a * 5 for i in range(5): assert b[i] == i * 5 - b = 5 * a - for i in range(5): - assert b[i] == 5 * i def test_div(self): from numpy import array @@ -201,13 +159,10 @@ def test_div_constant(self): from numpy import array - a = array(range(1,6)) + a = array(range(5)) b = a / 5.0 for i in range(5): - assert b[i] == (i+1) / 5.0 - b = 5.0 / a - for i in range(5): - assert b[i] == 5.0 / (i+1) + assert b[i] == i / 5.0 def test_pow(self): from numpy import array @@ -231,9 +186,6 @@ b = a ** 2 for i in range(5): assert b[i] == i ** 2 - b = 2 ** a - for i in range(5): - assert b[i] == 2 ** i def test_mod(self): from numpy import array @@ -252,13 +204,10 @@ def test_mod_constant(self): from numpy import array - a = array(range(1,6)) + a = array(range(5)) b = a % 2 for i in range(5): - assert b[i] == (i+1) % 2 - b = 2 % a - for i in range(5): - assert b[i] == 2 % (i+1) + assert b[i] == i % 2 def test_pos(self): from numpy import array @@ -417,14 +366,6 @@ for i in xrange(5): assert b[i] == 2.5*a[i] - def test_sort(self): - from numpy import array - a = array(range(19,-1,-1)) - b = array(range(20)) - a.sort() - for i in xrange(20): - assert a[i] == b[i] - class AppTestSupport(object): def setup_class(cls): diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -5,7 +5,6 @@ from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize -from pypy.rlib.nonconst import NonConstant class FakeSpace(object): w_ValueError = None @@ -249,21 +248,6 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) - def test_setslice(self): - space = self.space - - def f(i): - step = NonConstant(3) - ar = SingleDimArray(step*i) - ar2 = SingleDimArray(i) - ar.descr_setslice(space, 0, step*i, step, i, ar2) - return ar.get_concrete().storage[3] - - result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({'getarrayitem_raw': 1, - 'setarrayitem_raw': 1, 'int_add': 2, - 'int_lt': 1, 'guard_true': 1, 'jump': 1}) - class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -89,7 +89,7 @@ while asm[asm_index][0] < op.offset: asm_index += 1 end_index = asm_index - while asm[end_index][0] < end and end_index < len(asm) - 1: + while asm[end_index][0] < end: end_index += 1 op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) return loop @@ -369,11 +369,7 @@ name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] - try: - parser.postprocess(loop, backend_tp=bname, backend_dump=dump, - dump_start=start_ofs) - except: - import pdb, sys - pdb.post_mortem(sys.exc_info()[2]) + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log deleted file mode 100644 --- a/pypy/tool/jitlogparser/test/logtest2.log +++ /dev/null @@ -1,301 +0,0 @@ -[1f5e7f69779] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 -[1f5e7f7fe75] jit-backend-dump} -[1f5e7f84fc4] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 -[1f5e7f87ac1] jit-backend-dump} -[1f5e7f8a0b4] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b08a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 -[1f5e7f8da6b] jit-backend-dump} -[1f5e7f8f4f6] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b13d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 -[1f5e7f92b83] jit-backend-dump} -[1f5e7f95b99] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 -[1f5e7f988d0] jit-backend-dump} -[1f5e7fa16fb] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b28e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 -[1f5e7fa47ac] jit-backend-dump} -[1f5e7fab3a4] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 -[1f5e7faf1ca] jit-backend-dump} -[1f5e7fb0813] {jit-backend-counts -[1f5e7fb0f61] jit-backend-counts} -[1f5fd38be3e] {jit-backend -[1f5fe729336] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b3d5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB30B00C0A897F00004D8B334983C60149BB30B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030300000049BB00B0A007897F000041FFD34440484C3D39030400000049BB00B0A007897F000041FFD34440484C3907070305000000 -[1f5fe73276a] jit-backend-dump} -[1f5fe73438f] {jit-backend-addr -Loop 0 ( #9 LOAD_FAST) has address 7f8907a0b45d to 7f8907a0b4c3 (bootstrap 7f8907a0b3d5) -[1f5fe7369af] jit-backend-addr} -[1f5fe737940] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b3e5 +0 50FFFFFF -[1f5fe74b40e] jit-backend-dump} -[1f5fe74c63d] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b484 +0 95000000 -[1f5fe74da6a] jit-backend-dump} -[1f5fe74e438] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b495 +0 9B000000 -[1f5fe74f513] jit-backend-dump} -[1f5fe74fd2e] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b4b7 +0 91000000 -[1f5fe750d8c] jit-backend-dump} -[1f5fe75373f] jit-backend} -[1f5fe755abc] {jit-log-opt-loop -# Loop 0 : loop with 26 ops -[p0, p1, p2, p3, i4] -debug_merge_point(0, ' #9 LOAD_FAST') -debug_merge_point(0, ' #12 LOAD_CONST') -debug_merge_point(0, ' #15 COMPARE_OP') -+166: i6 = int_lt(i4, 10000) -guard_true(i6, descr=) [p1, p0, p2, p3, i4] -debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') -debug_merge_point(0, ' #21 LOAD_FAST') -debug_merge_point(0, ' #24 LOAD_CONST') -debug_merge_point(0, ' #27 BINARY_AND') -+179: i8 = int_and(i4, 2) -debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') -+186: i9 = int_is_true(i8) -guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] -debug_merge_point(0, ' #44 LOAD_FAST') -debug_merge_point(0, ' #47 LOAD_CONST') -debug_merge_point(0, ' #50 INPLACE_ADD') -+196: i11 = int_add(i4, 3) -debug_merge_point(0, ' #51 STORE_FAST') -debug_merge_point(0, ' #54 JUMP_ABSOLUTE') -+200: i13 = getfield_raw(40588192, descr=) -+208: i15 = int_sub(i13, 1) -+212: setfield_raw(40588192, i15, descr=) -+220: i17 = int_lt(i15, 0) -guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] -debug_merge_point(0, ' #9 LOAD_FAST') -+230: jump(p0, p1, p2, p3, i11, descr=) -+238: --end of the loop-- -[1f5fe92b8af] jit-log-opt-loop} -[1f5fe944ae5] {jit-backend -[1f5fee20651] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b565 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C254010000000049BB38B00C0A897F0000498B0B4883C10149BB38B00C0A897F000049890B4983F8010F85000000004883FE017206813E980700000F85000000004983FA000F850000000049BBA8F0B407897F00004D39DC0F8500000000488B56084881FA102700000F8D000000004989D44883E2024883FA000F85000000004983C403488B1425A0536B024883EA0148891425A0536B024883FA000F8C000000004C89BD70FFFFFF4C89B568FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4D89E749BB5DB4A007897F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DAE9CCFEFFFF49BB00B0A007897F000041FFD321383C343029241D180C08030600000049BB00B0A007897F000041FFD3383C18343029240C08030700000049BB00B0A007897F000041FFD329383C3430241808030800000049BB00B0A007897F000041FFD3383C3034241808030900000049BB00B0A007897F000041FFD3383C183424030A00000049BB00B0A007897F000041FFD3383C34241809030B00000049BB00B0A007897F000041FFD3383C34243107030C000000 -[1f5fee2e673] jit-backend-dump} -[1f5fee2f38d] {jit-backend-addr -Loop 1 ( #9 LOAD_FAST) has address 7f8907a0b631 to 7f8907a0b6f8 (bootstrap 7f8907a0b565) -[1f5fee312e3] jit-backend-addr} -[1f5fee320ed] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b575 +0 50FFFFFF -[1f5fee3e903] jit-backend-dump} -[1f5fee3fbff] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b655 +0 0C010000 -[1f5fee41579] jit-backend-dump} -[1f5fee421af] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b667 +0 17010000 -[1f5fee43835] jit-backend-dump} -[1f5fee44261] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b671 +0 28010000 -[1f5fee457c1] jit-backend-dump} -[1f5fee461a5] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b684 +0 2F010000 -[1f5fee475d3] jit-backend-dump} -[1f5fee47f57] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b695 +0 37010000 -[1f5fee4933d] jit-backend-dump} -[1f5fee49cd9] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b6a6 +0 3D010000 -[1f5fee4b0ad] jit-backend-dump} -[1f5fee4ba4f] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b6c8 +0 33010000 -[1f5fee4cf61] jit-backend-dump} -[1f5fee4dc45] jit-backend} -[1f5fee4f3a9] {jit-log-opt-loop -# Loop 1 : entry bridge with 31 ops -[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10] -debug_merge_point(0, ' #9 LOAD_FAST') -+234: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10] -+244: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10] -+262: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p10] -debug_merge_point(0, ' #12 LOAD_CONST') -+272: guard_value(p3, ConstPtr(ptr14), descr=) [p1, p0, p3, p2, p5, p8, p10] -debug_merge_point(0, ' #15 COMPARE_OP') -+291: i15 = getfield_gc_pure(p8, descr=) -+295: i17 = int_lt(i15, 10000) -guard_true(i17, descr=) [p1, p0, p8, p2, p5] -debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') -debug_merge_point(0, ' #21 LOAD_FAST') -debug_merge_point(0, ' #24 LOAD_CONST') -debug_merge_point(0, ' #27 BINARY_AND') -+308: i19 = int_and(i15, 2) -debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') -+315: i20 = int_is_true(i19) -guard_false(i20, descr=) [p1, p0, p2, p5, p8, i19] -debug_merge_point(0, ' #44 LOAD_FAST') -debug_merge_point(0, ' #47 LOAD_CONST') -debug_merge_point(0, ' #50 INPLACE_ADD') -+325: i22 = int_add(i15, 3) -debug_merge_point(0, ' #51 STORE_FAST') -debug_merge_point(0, ' #54 JUMP_ABSOLUTE') -+329: i24 = getfield_raw(40588192, descr=) -+337: i26 = int_sub(i24, 1) -+341: setfield_raw(40588192, i26, descr=) -+349: i28 = int_lt(i26, 0) -guard_false(i28, descr=) [p1, p0, p2, p5, i22, None] -debug_merge_point(0, ' #9 LOAD_FAST') -+359: jump(p0, p1, p2, p5, i22, descr=) -+403: --end of the loop-- -[1f60036d952] jit-log-opt-loop} -[1f600719a74] {jit-backend -[1f600759dac] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b817 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB40B00C0A897F00004D8B334983C60149BB40B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF024C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030D00000049BB00B0A007897F000041FFD34440484C3D39030E00000049BB00B0A007897F000041FFD34440484C390707030F000000 -[1f60076fd90] jit-backend-dump} -[1f600770f30] {jit-backend-addr -Loop 2 ( #9 LOAD_FAST) has address 7f8907a0b89f to 7f8907a0b905 (bootstrap 7f8907a0b817) -[1f6007730fc] jit-backend-addr} -[1f600773fde] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b827 +0 50FFFFFF -[1f600775c76] jit-backend-dump} -[1f600776a38] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b8c6 +0 95000000 -[1f600778112] jit-backend-dump} -[1f600778b8c] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b8d7 +0 9B000000 -[1f60077a04a] jit-backend-dump} -[1f60077aa6a] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b8f9 +0 91000000 -[1f60077bf10] jit-backend-dump} -[1f60077cc24] jit-backend} -[1f60077e094] {jit-log-opt-loop -# Loop 2 : loop with 25 ops -[p0, p1, p2, p3, i4] -debug_merge_point(0, ' #12 LOAD_CONST') -debug_merge_point(0, ' #15 COMPARE_OP') -+166: i6 = int_lt(i4, 10000) -guard_true(i6, descr=) [p1, p0, p2, p3, i4] -debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') -debug_merge_point(0, ' #21 LOAD_FAST') -debug_merge_point(0, ' #24 LOAD_CONST') -debug_merge_point(0, ' #27 BINARY_AND') -+179: i8 = int_and(i4, 2) -debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') -+186: i9 = int_is_true(i8) -guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] -debug_merge_point(0, ' #44 LOAD_FAST') -debug_merge_point(0, ' #47 LOAD_CONST') -debug_merge_point(0, ' #50 INPLACE_ADD') -+196: i11 = int_add(i4, 3) -debug_merge_point(0, ' #51 STORE_FAST') -debug_merge_point(0, ' #54 JUMP_ABSOLUTE') -+200: i13 = getfield_raw(40588192, descr=) -+208: i15 = int_sub(i13, 2) -+212: setfield_raw(40588192, i15, descr=) -+220: i17 = int_lt(i15, 0) -guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] -debug_merge_point(0, ' #9 LOAD_FAST') -+230: jump(p0, p1, p2, p3, i11, descr=) -+238: --end of the loop-- -[1f6007a567c] jit-log-opt-loop} -[1f600802cd6] {jit-backend -[1f600862dd8] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b9b7 +0 488DA50000000049BB48B00C0A897F00004D8B3B4983C70149BB48B00C0A897F00004D893B4D89F74983C6010F80000000004C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C00000000488B0425704F3D01488D5010483B1425784F3D01761A49BB10B2A007897F000041FFD349BB8EB2A007897F000041FFD348C7009807000048891425704F3D014C89700848898550FFFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBA8F0B407897F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00100000048C7C709000000488BB550FFFFFF48C7C30000000048C7C20000000049BB31B6A007897F000041FFE349BB00B0A007897F000041FFD3444039484C3D031000000049BB00B0A007897F000041FFD34440484C39070311000000 -[1f60086ba5a] jit-backend-dump} -[1f60086d36e] {jit-backend-addr -Bridge out of guard 4 has address 7f8907a0b9b7 to 7f8907a0bab1 -[1f60086ffd2] jit-backend-addr} -[1f600870dca] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b9ba +0 C0FEFFFF -[1f60087281c] jit-backend-dump} -[1f600873506] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b9e5 +0 C8000000 -[1f600874b44] jit-backend-dump} -[1f6008754d4] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0ba03 +0 C2000000 -[1f600876956] jit-backend-dump} -[1f600877b1a] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b495 +0 1E050000 -[1f600878f4e] jit-backend-dump} -[1f600884c12] jit-backend} -[1f60088780a] {jit-log-opt-bridge -# bridge out of Guard 4 with 16 ops -[p0, p1, p2, p3, i4, i5] -debug_merge_point(0, ' #31 LOAD_FAST') -debug_merge_point(0, ' #34 LOAD_CONST') -debug_merge_point(0, ' #37 INPLACE_ADD') -+37: i7 = int_add_ovf(i5, 1) -guard_no_overflow(, descr=) [p0, p1, i7, p2, p3, i5] -debug_merge_point(0, ' #38 STORE_FAST') -debug_merge_point(0, ' #41 JUMP_ABSOLUTE') -+50: i9 = getfield_raw(40588192, descr=) -+58: i11 = int_sub(i9, 1) -+62: setfield_raw(40588192, i11, descr=) -+70: i13 = int_lt(i11, 0) -guard_false(i13, descr=) [p0, p1, p2, p3, i7, None] -debug_merge_point(0, ' #9 LOAD_FAST') -+80: p16 = new_with_vtable(ConstClass(W_IntObject)) -+143: setfield_gc(p16, i7, descr=) -+147: jump(p1, p0, p2, ConstPtr(ptr17), 0, p3, 1, 9, p16, ConstPtr(ptr21), ConstPtr(ptr22), descr=) -+250: --end of the loop-- -[1f6008aa976] jit-log-opt-bridge} -[1f600912c98] {jit-backend-counts -0:1982 -1:1985 -2:0 -3:1782 -[1f600916544] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -220,4 +220,4 @@ 'logtest2.log'))) assert 'cmp' in loops[1].operations[1].asm # bridge - assert 'jo' in loops[3].operations[3].asm + assert 'cmp' in loops[3].operations[1].asm From noreply at buildbot.pypy.org Sat Jul 16 16:18:26 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 16:18:26 +0200 (CEST) Subject: [pypy-commit] pypy default: fix tests Message-ID: <20110716141826.9D5BF82962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45666:a3c110ceadc2 Date: 2011-07-16 10:16 +0200 http://bitbucket.org/pypy/pypy/changeset/a3c110ceadc2/ Log: fix tests diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -89,7 +89,7 @@ while asm[asm_index][0] < op.offset: asm_index += 1 end_index = asm_index - while asm[end_index][0] < end: + while asm[end_index][0] < end and end_index < len(asm) - 1: end_index += 1 op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) return loop diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest2.log @@ -0,0 +1,301 @@ +[1f5e7f69779] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f7fe75] jit-backend-dump} +[1f5e7f84fc4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f87ac1] jit-backend-dump} +[1f5e7f8a0b4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b08a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f8da6b] jit-backend-dump} +[1f5e7f8f4f6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b13d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f92b83] jit-backend-dump} +[1f5e7f95b99] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 +[1f5e7f988d0] jit-backend-dump} +[1f5e7fa16fb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b28e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 +[1f5e7fa47ac] jit-backend-dump} +[1f5e7fab3a4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 +[1f5e7faf1ca] jit-backend-dump} +[1f5e7fb0813] {jit-backend-counts +[1f5e7fb0f61] jit-backend-counts} +[1f5fd38be3e] {jit-backend +[1f5fe729336] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB30B00C0A897F00004D8B334983C60149BB30B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030300000049BB00B0A007897F000041FFD34440484C3D39030400000049BB00B0A007897F000041FFD34440484C3907070305000000 +[1f5fe73276a] jit-backend-dump} +[1f5fe73438f] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f8907a0b45d to 7f8907a0b4c3 (bootstrap 7f8907a0b3d5) +[1f5fe7369af] jit-backend-addr} +[1f5fe737940] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3e5 +0 50FFFFFF +[1f5fe74b40e] jit-backend-dump} +[1f5fe74c63d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b484 +0 95000000 +[1f5fe74da6a] jit-backend-dump} +[1f5fe74e438] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 9B000000 +[1f5fe74f513] jit-backend-dump} +[1f5fe74fd2e] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b4b7 +0 91000000 +[1f5fe750d8c] jit-backend-dump} +[1f5fe75373f] jit-backend} +[1f5fe755abc] {jit-log-opt-loop +# Loop 0 : loop with 26 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 1) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f5fe92b8af] jit-log-opt-loop} +[1f5fe944ae5] {jit-backend +[1f5fee20651] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b565 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C254010000000049BB38B00C0A897F0000498B0B4883C10149BB38B00C0A897F000049890B4983F8010F85000000004883FE017206813E980700000F85000000004983FA000F850000000049BBA8F0B407897F00004D39DC0F8500000000488B56084881FA102700000F8D000000004989D44883E2024883FA000F85000000004983C403488B1425A0536B024883EA0148891425A0536B024883FA000F8C000000004C89BD70FFFFFF4C89B568FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4D89E749BB5DB4A007897F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DAE9CCFEFFFF49BB00B0A007897F000041FFD321383C343029241D180C08030600000049BB00B0A007897F000041FFD3383C18343029240C08030700000049BB00B0A007897F000041FFD329383C3430241808030800000049BB00B0A007897F000041FFD3383C3034241808030900000049BB00B0A007897F000041FFD3383C183424030A00000049BB00B0A007897F000041FFD3383C34241809030B00000049BB00B0A007897F000041FFD3383C34243107030C000000 +[1f5fee2e673] jit-backend-dump} +[1f5fee2f38d] {jit-backend-addr +Loop 1 ( #9 LOAD_FAST) has address 7f8907a0b631 to 7f8907a0b6f8 (bootstrap 7f8907a0b565) +[1f5fee312e3] jit-backend-addr} +[1f5fee320ed] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b575 +0 50FFFFFF +[1f5fee3e903] jit-backend-dump} +[1f5fee3fbff] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b655 +0 0C010000 +[1f5fee41579] jit-backend-dump} +[1f5fee421af] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b667 +0 17010000 +[1f5fee43835] jit-backend-dump} +[1f5fee44261] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b671 +0 28010000 +[1f5fee457c1] jit-backend-dump} +[1f5fee461a5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b684 +0 2F010000 +[1f5fee475d3] jit-backend-dump} +[1f5fee47f57] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b695 +0 37010000 +[1f5fee4933d] jit-backend-dump} +[1f5fee49cd9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6a6 +0 3D010000 +[1f5fee4b0ad] jit-backend-dump} +[1f5fee4ba4f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6c8 +0 33010000 +[1f5fee4cf61] jit-backend-dump} +[1f5fee4dc45] jit-backend} +[1f5fee4f3a9] {jit-log-opt-loop +# Loop 1 : entry bridge with 31 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10] +debug_merge_point(0, ' #9 LOAD_FAST') ++234: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10] ++244: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10] ++262: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p10] +debug_merge_point(0, ' #12 LOAD_CONST') ++272: guard_value(p3, ConstPtr(ptr14), descr=) [p1, p0, p3, p2, p5, p8, p10] +debug_merge_point(0, ' #15 COMPARE_OP') ++291: i15 = getfield_gc_pure(p8, descr=) ++295: i17 = int_lt(i15, 10000) +guard_true(i17, descr=) [p1, p0, p8, p2, p5] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++308: i19 = int_and(i15, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++315: i20 = int_is_true(i19) +guard_false(i20, descr=) [p1, p0, p2, p5, p8, i19] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++325: i22 = int_add(i15, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++329: i24 = getfield_raw(40588192, descr=) ++337: i26 = int_sub(i24, 1) ++341: setfield_raw(40588192, i26, descr=) ++349: i28 = int_lt(i26, 0) +guard_false(i28, descr=) [p1, p0, p2, p5, i22, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++359: jump(p0, p1, p2, p5, i22, descr=) ++403: --end of the loop-- +[1f60036d952] jit-log-opt-loop} +[1f600719a74] {jit-backend +[1f600759dac] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b817 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB40B00C0A897F00004D8B334983C60149BB40B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF024C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030D00000049BB00B0A007897F000041FFD34440484C3D39030E00000049BB00B0A007897F000041FFD34440484C390707030F000000 +[1f60076fd90] jit-backend-dump} +[1f600770f30] {jit-backend-addr +Loop 2 ( #9 LOAD_FAST) has address 7f8907a0b89f to 7f8907a0b905 (bootstrap 7f8907a0b817) +[1f6007730fc] jit-backend-addr} +[1f600773fde] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b827 +0 50FFFFFF +[1f600775c76] jit-backend-dump} +[1f600776a38] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8c6 +0 95000000 +[1f600778112] jit-backend-dump} +[1f600778b8c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8d7 +0 9B000000 +[1f60077a04a] jit-backend-dump} +[1f60077aa6a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8f9 +0 91000000 +[1f60077bf10] jit-backend-dump} +[1f60077cc24] jit-backend} +[1f60077e094] {jit-log-opt-loop +# Loop 2 : loop with 25 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 2) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f6007a567c] jit-log-opt-loop} +[1f600802cd6] {jit-backend +[1f600862dd8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9b7 +0 488DA50000000049BB48B00C0A897F00004D8B3B4983C70149BB48B00C0A897F00004D893B4D89F74983C6010F80000000004C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C00000000488B0425704F3D01488D5010483B1425784F3D01761A49BB10B2A007897F000041FFD349BB8EB2A007897F000041FFD348C7009807000048891425704F3D014C89700848898550FFFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBA8F0B407897F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00100000048C7C709000000488BB550FFFFFF48C7C30000000048C7C20000000049BB31B6A007897F000041FFE349BB00B0A007897F000041FFD3444039484C3D031000000049BB00B0A007897F000041FFD34440484C39070311000000 +[1f60086ba5a] jit-backend-dump} +[1f60086d36e] {jit-backend-addr +Bridge out of guard 4 has address 7f8907a0b9b7 to 7f8907a0bab1 +[1f60086ffd2] jit-backend-addr} +[1f600870dca] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9ba +0 C0FEFFFF +[1f60087281c] jit-backend-dump} +[1f600873506] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9e5 +0 C8000000 +[1f600874b44] jit-backend-dump} +[1f6008754d4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0ba03 +0 C2000000 +[1f600876956] jit-backend-dump} +[1f600877b1a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 1E050000 +[1f600878f4e] jit-backend-dump} +[1f600884c12] jit-backend} +[1f60088780a] {jit-log-opt-bridge +# bridge out of Guard 4 with 16 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #31 LOAD_FAST') +debug_merge_point(0, ' #34 LOAD_CONST') +debug_merge_point(0, ' #37 INPLACE_ADD') ++37: i7 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i7, p2, p3, i5] +debug_merge_point(0, ' #38 STORE_FAST') +debug_merge_point(0, ' #41 JUMP_ABSOLUTE') ++50: i9 = getfield_raw(40588192, descr=) ++58: i11 = int_sub(i9, 1) ++62: setfield_raw(40588192, i11, descr=) ++70: i13 = int_lt(i11, 0) +guard_false(i13, descr=) [p0, p1, p2, p3, i7, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++80: p16 = new_with_vtable(ConstClass(W_IntObject)) ++143: setfield_gc(p16, i7, descr=) ++147: jump(p1, p0, p2, ConstPtr(ptr17), 0, p3, 1, 9, p16, ConstPtr(ptr21), ConstPtr(ptr22), descr=) ++250: --end of the loop-- +[1f6008aa976] jit-log-opt-bridge} +[1f600912c98] {jit-backend-counts +0:1982 +1:1985 +2:0 +3:1782 +[1f600916544] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -220,4 +220,4 @@ 'logtest2.log'))) assert 'cmp' in loops[1].operations[1].asm # bridge - assert 'cmp' in loops[3].operations[1].asm + assert 'jo' in loops[3].operations[3].asm From noreply at buildbot.pypy.org Sat Jul 16 16:18:28 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 16:18:28 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110716141828.1285D82962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45667:30cdf33c3942 Date: 2011-07-16 16:18 +0200 http://bitbucket.org/pypy/pypy/changeset/30cdf33c3942/ Log: merge diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -596,12 +596,16 @@ standard_box = self.metainterp.virtualizable_boxes[-1] if standard_box is box: return False + if box in self.metainterp.nonstandard_virtualizables: + return True eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None, box, standard_box) eqbox = self.implement_guard_value(pc, eqbox) isstandard = eqbox.getint() if isstandard: self.metainterp.replace_box(box, standard_box) + else: + self.metainterp.nonstandard_virtualizables[box] = None return not isstandard def _get_virtualizable_field_index(self, fielddescr): @@ -1456,6 +1460,8 @@ self.call_pure_results = args_dict_box() # contains boxes where the class is already known self.known_class_boxes = {} + # contains frame boxes that are not virtualizables + self.nonstandard_virtualizables = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1797,6 +1803,7 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} + self.nonstandard_virtualizables = {} # XXX maybe not needed? duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2381,7 +2381,7 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? - def test_retrace_ending_up_retrazing_another_loop(self): + def test_retrace_ending_up_retracing_another_loop(self): myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) bytecode = "0+sI0+SI" diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -1133,6 +1133,7 @@ res = self.meta_interp(f, [10]) assert res == 55 self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True) + self.check_history(ptr_eq=2) def test_virtual_child_frame_with_arrays(self): myjitdriver = JitDriver(greens = [], reds = ['frame'], diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py --- a/pypy/module/__builtin__/compiling.py +++ b/pypy/module/__builtin__/compiling.py @@ -5,7 +5,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError from pypy.interpreter.astcompiler import consts, ast -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec @unwrap_spec(filename=str, mode=str, flags=int, dont_inherit=int) def compile(space, w_source, filename, mode, flags=0, dont_inherit=0): diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py --- a/pypy/module/__builtin__/descriptor.py +++ b/pypy/module/__builtin__/descriptor.py @@ -1,12 +1,10 @@ - -from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.function import StaticMethod, ClassMethod from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.descroperation import object_getattribute, object_setattr -from pypy.interpreter.function import StaticMethod, ClassMethod -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \ - descr_set_dict, interp_attrproperty_w, generic_new_descr +from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w, + generic_new_descr) +from pypy.objspace.descroperation import object_getattribute class W_Super(Wrappable): def __init__(self, space, w_starttype, w_objtype, w_self): diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -4,13 +4,12 @@ """ from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import NoneNotWrapped, applevel +from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.objectmodel import specialize -from inspect import getsource, getfile from pypy.rlib.rbigint import rbigint @@ -662,7 +661,6 @@ def descr_reduce(self): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns space = self.space w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -1,11 +1,9 @@ import new from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import NoneNotWrapped, applevel, interp2app +from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict -from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, descr_set_dict from pypy.rlib.objectmodel import compute_identity_hash from pypy.rlib.debug import make_sure_not_resized from pypy.rlib import jit diff --git a/pypy/module/__builtin__/interp_memoryview.py b/pypy/module/__builtin__/interp_memoryview.py --- a/pypy/module/__builtin__/interp_memoryview.py +++ b/pypy/module/__builtin__/interp_memoryview.py @@ -2,7 +2,7 @@ Implementation of the 'buffer' and 'memoryview' types. """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter import gateway, buffer +from pypy.interpreter import buffer from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -4,12 +4,10 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.runicode import UNICHR from pypy.rlib.rfloat import isnan, isinf, round_double from pypy.rlib import rfloat -import math import __builtin__ NoneNotWrapped = gateway.NoneNotWrapped diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,5 +1,4 @@ -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib import debug, jit diff --git a/pypy/module/__pypy__/interp_identitydict.py b/pypy/module/__pypy__/interp_identitydict.py --- a/pypy/module/__pypy__/interp_identitydict.py +++ b/pypy/module/__pypy__/interp_identitydict.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app from pypy.interpreter.baseobjspace import Wrappable class W_IdentityDict(Wrappable): diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.objectmodel import we_are_translated class CodecState(object): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -1,9 +1,8 @@ -import sys -from pypy.interpreter.baseobjspace import Wrappable, Arguments +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, \ operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi @@ -16,7 +15,7 @@ class W_FFIType(Wrappable): _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to'] - + def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None): self.name = name self.ffitype = ffitype @@ -83,7 +82,6 @@ def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P types = [ # note: most of the type name directly come from the C equivalent, # with the exception of bytes: in C, ubyte and char are equivalent, @@ -161,7 +159,7 @@ class W_FuncPtr(Wrappable): _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype'] - + def __init__(self, func, argtypes_w, w_restype): self.func = func self.argtypes_w = argtypes_w @@ -207,7 +205,7 @@ argchain.arg_singlefloat(space.float_w(w_arg)) elif w_argtype.is_struct(): # arg_raw directly takes value to put inside ll_args - w_arg = space.interp_w(W_StructureInstance, w_arg) + w_arg = space.interp_w(W_StructureInstance, w_arg) ptrval = w_arg.ll_buffer argchain.arg_raw(ptrval) else: @@ -404,7 +402,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + return W_FuncPtr(func, argtypes_w, w_restype) @unwrap_spec(name=str) diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,12 +3,10 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.gateway import ObjSpace -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -import os def wrap_streamerror(space, e, w_filename=None): if isinstance(e, streamio.StreamError): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -4,7 +4,6 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.buffer import RWBuffer -from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstring import StringBuilder from pypy.rlib.rarithmetic import r_longlong, intmask from pypy.tool.sourcetools import func_renamer diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py --- a/pypy/module/_io/interp_fileio.py +++ b/pypy/module/_io/interp_fileio.py @@ -1,5 +1,4 @@ -from pypy.interpreter.typedef import ( - TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty) +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 from pypy.rlib.rarithmetic import r_longlong diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -6,7 +6,6 @@ TypeDef, interp_attrproperty, generic_new_descr) from pypy.module.exceptions.interp_exceptions import W_IOError from pypy.module._io.interp_fileio import W_FileIO -from pypy.module._io.interp_iobase import W_IOBase from pypy.module._io.interp_textio import W_TextIOWrapper from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -4,7 +4,7 @@ generic_new_descr) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint from pypy.rlib.rbigint import rbigint from pypy.rlib.rstring import UnicodeBuilder diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py --- a/pypy/module/_locale/interp_locale.py +++ b/pypy/module/_locale/interp_locale.py @@ -1,4 +1,3 @@ -from pypy.rpython.tool import rffi_platform as platform from pypy.rlib import rposix from pypy.rlib.rarithmetic import intmask diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -2,12 +2,10 @@ """ The ffi for rpython, need to be imported for side effects """ -import sys from pypy.rpython.lltypesystem import rffi from pypy.rpython.lltypesystem import lltype from pypy.rpython.tool import rffi_platform from pypy.rpython.extfunc import register_external -from pypy.rpython.extregistry import ExtRegistryEntry from pypy.module._minimal_curses import interp_curses from pypy.translator.tool.cbuild import ExternalCompilationInfo @@ -82,7 +80,7 @@ return res finally: rffi.free_charp(ll_cap) - + register_external(interp_curses._curses_tigetstr, [str], str, export_name='_curses.tigetstr', llimpl=tigetstr_llimpl) diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -1,4 +1,4 @@ -import py, sys +import py from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -4,7 +4,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import ( OperationError, wrap_oserror, operationerrfmt) -from pypy.rpython.lltypesystem import rffi, lltype, llmemory +from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll import sys diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -15,7 +15,6 @@ if sys.platform == 'win32': from pypy.rlib import rwin32 - from pypy.interpreter.error import wrap_windowserror from pypy.module._multiprocessing.interp_win32 import ( handle_w, _GetTickCount) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -1,4 +1,4 @@ -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError from pypy.interpreter.nestedscope import Cell from pypy.interpreter.pycode import PyCode from pypy.interpreter.function import Function, Method @@ -8,7 +8,6 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec -from pypy.objspace.std.dicttype import dictiter_typedef from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject @@ -79,7 +78,7 @@ try: return gateway.BuiltinCode.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin code: "+ identifier)) @@ -89,7 +88,7 @@ try: return function.Function.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin function: "+ identifier)) diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,10 +2,10 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rpython.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import get_elem, push_elem +from pypy.module._rawffi.array import push_elem from pypy.module._rawffi.structure import W_Structure -from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \ - wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes +from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, + unwrap_value, unpack_argshapes) from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL from pypy.rlib.clibffi import ffi_type_void from pypy.rlib import rweakref diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -1,7 +1,6 @@ -import sys from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib.clibffi import * @@ -15,7 +14,7 @@ from pypy.rlib import rwin32 from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.tracker import tracker TYPEMAP = { diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py --- a/pypy/module/_socket/interp_func.py +++ b/pypy/module/_socket/interp_func.py @@ -1,9 +1,8 @@ -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._socket.interp_socket import converted_error, W_RSocket from pypy.rlib import rsocket from pypy.rlib.rsocket import SocketError -from pypy.rlib.rarithmetic import r_uint -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError def gethostname(space): """gethostname() -> string diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,7 +1,7 @@ from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError -from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -11,7 +11,6 @@ from pypy.module._socket import interp_socket -import sys ## user defined constants X509_NAME_MAXLEN = 256 @@ -131,13 +130,13 @@ self._issuer = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN, flavor='raw') self._issuer[0] = '\0' self.shutdown_seen_zero = False - + def server(self): return self.space.wrap(rffi.charp2str(self._server)) - + def issuer(self): return self.space.wrap(rffi.charp2str(self._issuer)) - + def __del__(self): if self.peer_cert: libssl_X509_free(self.peer_cert) @@ -147,7 +146,7 @@ libssl_SSL_CTX_free(self.ctx) lltype.free(self._server, flavor='raw') lltype.free(self._issuer, flavor='raw') - + @unwrap_spec(data='bufferstr') def write(self, data): """write(s) -> len @@ -230,10 +229,10 @@ raw_buf, gc_buf = rffi.alloc_buffer(num_bytes) while True: err = 0 - + count = libssl_SSL_read(self.ssl, raw_buf, num_bytes) err = libssl_SSL_get_error(self.ssl, count) - + if err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout(self.space, self.w_socket, False) @@ -245,17 +244,17 @@ return self.space.wrap("") else: sockstate = SOCKET_OPERATION_OK - + if sockstate == SOCKET_HAS_TIMED_OUT: raise ssl_error(self.space, "The read operation timed out") elif sockstate == SOCKET_IS_NONBLOCKING: break - + if err == SSL_ERROR_WANT_READ or err == SSL_ERROR_WANT_WRITE: continue else: break - + if count <= 0: raise _ssl_seterror(self.space, self, count) @@ -351,7 +350,7 @@ self.shutdown_seen_zero = True continue - # Possibly retry shutdown until timeout or failure + # Possibly retry shutdown until timeout or failure ssl_err = libssl_SSL_get_error(self.ssl, ret) if ssl_err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout( @@ -397,7 +396,7 @@ else: w_proto = space.w_None - bits = libssl_SSL_CIPHER_get_bits(current, + bits = libssl_SSL_CIPHER_get_bits(current, lltype.nullptr(rffi.INTP.TO)) w_bits = space.newint(bits) @@ -552,7 +551,7 @@ ext = libssl_X509_get_ext(certificate, i) method = libssl_X509V3_EXT_get(ext) if not method: - raise ssl_error(space, + raise ssl_error(space, "No method for internalizing subjectAltName!'") with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr: @@ -858,7 +857,7 @@ cert = libssl_BIO_new(libssl_BIO_s_file()) if not cert: raise ssl_error(space, "Can't malloc memory to read file") - + try: if libssl_BIO_read_filename(cert, filename) <= 0: raise ssl_error(space, "Can't open file") @@ -873,7 +872,7 @@ libssl_X509_free(x) finally: libssl_BIO_free(cert) - + # this function is needed to perform locking on shared data # structures. (Note that OpenSSL uses a number of global data # structures that will be implicitly shared whenever multiple threads diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -15,13 +15,10 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import StaticMethod from pypy.module._stackless.stackless_flags import StacklessFlags from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit @@ -38,7 +35,7 @@ self.costate = costate if not space.is_true(space.callable(w_obj)): raise operationerrfmt( - space.w_TypeError, + space.w_TypeError, "'%s' object is not callable", space.type(w_obj).getname(space)) self.w_func = w_obj @@ -65,7 +62,7 @@ # Should be moved to interp_stackless.py if it's ever implemented... Currently # used by pypy/lib/stackless.py. -W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, +W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, """Tasklet killed manually.""") class AppCoroutine(Coroutine): # XXX, StacklessFlags): @@ -90,7 +87,7 @@ def _get_state(space): return space.fromcache(AppCoState) _get_state = staticmethod(_get_state) - + def w_bind(self, w_func, __args__): space = self.space if self.frame is not None: @@ -127,7 +124,7 @@ w_excvalue = operror.get_w_value(space) w_exctraceback = operror.get_traceback() w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback]) - + if w_exctype is self.costate.w_CoroutineExit: self.coroutine_exit = True else: @@ -146,22 +143,22 @@ def w_kill(self): self.kill() - + def w_throw(self, w_type, w_value=None, w_traceback=None): space = self.space operror = OperationError(w_type, w_value) operror.normalize_exception(space) - + if not space.is_w(w_traceback, space.w_None): from pypy.interpreter import pytraceback tb = space.interpclass_w(w_traceback) - if tb is None or not space.is_true(space.isinstance(tb, + if tb is None or not space.is_true(space.isinstance(tb, space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) operror.set_traceback(tb) - + self._kill(operror) def _userdel(self): @@ -280,7 +277,7 @@ assert isinstance(w_klass, W_TypeObject) old_flag = w_klass.flag_heaptype w_klass.flag_heaptype = True - + space.appexec([w_klass, space.wrap(funcname)], """ (klass, funcname): func = getattr(klass, funcname) @@ -332,23 +329,23 @@ # Exporting new exception to space self.w_CoroutineExit = space.gettypefor(W_CoroutineExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('CoroutineExit'), - self.w_CoroutineExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('CoroutineExit'), + space.exceptions_module.w_dict, + space.new_interned_str('CoroutineExit'), self.w_CoroutineExit) - + space.setitem(space.builtin.w_dict, + space.new_interned_str('CoroutineExit'), + self.w_CoroutineExit) + # Should be moved to interp_stackless.py if it's ever implemented... self.w_TaskletExit = space.gettypefor(W_TaskletExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - + space.exceptions_module.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + space.setitem(space.builtin.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + def post_install(self): self.current = self.main = AppCoroutine(self.space, state=self) self.main.subctx.clear_framestack() # wack @@ -378,7 +375,7 @@ instr = frame.last_instr opcode = ord(code[instr]) map = pythonopcode.opmap - call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], + call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] assert opcode in call_ops instr += 1 diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py --- a/pypy/module/_stackless/interp_stackless.py +++ b/pypy/module/_stackless/interp_stackless.py @@ -1,9 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError -from pypy.rlib.rarithmetic import intmask import os diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py --- a/pypy/module/_stackless/rclonable.py +++ b/pypy/module/_stackless/rclonable.py @@ -1,7 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.rlib.objectmodel import we_are_translated -from pypy.interpreter.error import OperationError class InterpClonableMixin: @@ -76,7 +75,7 @@ if not isinstance(current, InterpClonableCoroutine): raise RuntimeError("fork() in a non-clonable coroutine") thunk = ForkThunk(current) - coro_fork = InterpClonableCoroutine() + coro_fork = InterpClonableCoroutine() coro_fork.bind(thunk) coro_fork.switch() # we resume here twice. The following would need explanations about diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,9 +1,8 @@ import py -from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.interpreter.typedef import GetSetProperty, TypeDef +from pypy.interpreter.typedef import TypeDef from pypy.rlib import jit import weakref diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -1,6 +1,5 @@ from __future__ import with_statement from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError, wrap_windowserror diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,10 +1,9 @@ from __future__ import with_statement -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object from pypy.objspace.std.multimethod import FailedToImplement diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -4,9 +4,8 @@ from pypy.rpython.lltypesystem import lltype from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.rlib.streamio import Stream from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform as compiler @@ -67,7 +66,7 @@ 'BZ_OUTBUFF_FULL', 'BZ_CONFIG_ERROR'] for name in constant_names: setattr(CConfig, name, platform.DefinedConstantInteger(name)) - + class cConfig(object): pass for k, v in platform.configure(CConfig).items(): @@ -100,7 +99,7 @@ SMALLCHUNK = 8192 else: SMALLCHUNK = BUFSIZ - + if rffi.sizeof(rffi.INT) > 4: BIGCHUNK = 512 * 32 else: @@ -505,7 +504,7 @@ self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self._init_bz2comp(compresslevel) - + def _init_bz2comp(self, compresslevel): if compresslevel < 1 or compresslevel > 9: raise OperationError(self.space.w_ValueError, @@ -514,13 +513,13 @@ bzerror = intmask(BZ2_bzCompressInit(self.bzs, compresslevel, 0, 0)) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzCompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') - + @unwrap_spec(data='bufferstr') def compress(self, data): """compress(data) -> string @@ -529,12 +528,12 @@ compressed data whenever possible. When you've finished providing data to compress, call the flush() method to finish the compression process, and return what is left in the internal buffers.""" - + datasize = len(data) - + if datasize == 0: return self.space.wrap("") - + if not self.running: raise OperationError(self.space.w_ValueError, self.space.wrap("this object was already flushed")) @@ -562,7 +561,7 @@ res = out.make_result_string() return self.space.wrap(res) - + def flush(self): if not self.running: raise OperationError(self.space.w_ValueError, @@ -576,7 +575,7 @@ break elif bzerror != BZ_FINISH_OK: _catch_bz2_error(self.space, bzerror) - + if rffi.getintfield(self.bzs, 'c_avail_out') == 0: out.prepare_next_chunk() @@ -603,23 +602,23 @@ Create a new decompressor object. This object may be used to decompress data sequentially. If you want to decompress data in one shot, use the decompress() function instead.""" - + def __init__(self, space): self.space = space self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self.unused_data = "" - + self._init_bz2decomp() - + def _init_bz2decomp(self): bzerror = BZ2_bzDecompressInit(self.bzs, 0, 0) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzDecompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') @@ -687,7 +686,7 @@ Compress data in one shot. If you want to compress data sequentially, use an instance of BZ2Compressor instead. The compresslevel parameter, if given, must be a number between 1 and 9.""" - + if compresslevel < 1 or compresslevel > 9: raise OperationError(space.w_ValueError, space.wrap("compresslevel must be between 1 and 9")) @@ -731,7 +730,7 @@ Decompress data in one shot. If you want to decompress data sequentially, use an instance of BZ2Decompressor instead.""" - + in_bufsize = len(data) if in_bufsize == 0: return space.wrap("") diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -1,4 +1,3 @@ -import sys from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py --- a/pypy/module/cmath/interp_cmath.py +++ b/pypy/module/cmath/interp_cmath.py @@ -5,7 +5,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import NoneNotWrapped -from pypy.module.cmath import Module, names_and_docstrings +from pypy.module.cmath import names_and_docstrings from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG from pypy.module.cmath.constant import M_LN2, M_LN10 diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py --- a/pypy/module/cpyext/cdatetime.py +++ b/pypy/module/cpyext/cdatetime.py @@ -1,8 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib.objectmodel import we_are_translated -from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef -from pypy.module.cpyext.api import ( - cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields) +from pypy.module.cpyext.pyobject import PyObject, make_ref +from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct, + PyObjectFields) from pypy.module.cpyext.import_ import PyImport_Import from pypy.module.cpyext.typeobject import PyTypeObjectPtr from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py --- a/pypy/module/cpyext/complexobject.py +++ b/pypy/module/cpyext/complexobject.py @@ -1,7 +1,6 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.module.cpyext.api import ( cpython_api, cpython_struct, PyObject, build_type_checkers) -from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.floatobject import PyFloat_AsDouble from pypy.objspace.std.complexobject import W_ComplexObject from pypy.interpreter.error import OperationError diff --git a/pypy/module/crypt/interp_crypt.py b/pypy/module/crypt/interp_crypt.py --- a/pypy/module/crypt/interp_crypt.py +++ b/pypy/module/crypt/interp_crypt.py @@ -1,6 +1,5 @@ -from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.rpython.lltypesystem import rffi, lltype +from pypy.rpython.lltypesystem import rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo import sys @@ -22,4 +21,4 @@ if not res: return space.w_None str_res = rffi.charp2str(res) - return space.wrap(str_res) + return space.wrap(str_res) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -73,9 +73,8 @@ """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w,\ - GetSetProperty, interp_attrproperty, descr_get_dict, descr_set_dict,\ - descr_del_dict +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict, + descr_set_dict, descr_del_dict) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError from pypy.rlib import rwin32 diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -11,9 +11,8 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.eval import Code from pypy.interpreter.pycode import PyCode -from pypy.rlib import streamio, jit, rposix +from pypy.rlib import streamio, jit from pypy.rlib.streamio import StreamErrors -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -3,9 +3,9 @@ from pypy.rlib import streamio from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.module import Module -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import struct + def get_suffixes(space): w = space.wrap diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,7 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.rarithmetic import ovfcheck class W_Count(Wrappable): @@ -87,7 +86,7 @@ def __init__(self, space, w_obj, w_times): self.space = space self.w_obj = w_obj - + if space.is_w(w_times, space.w_None): self.counting = False self.count = 0 @@ -181,7 +180,7 @@ long as the predicate is true. Equivalent to : - + def takewhile(predicate, iterable): for x in iterable: if predicate(x): @@ -316,7 +315,7 @@ None, return the items that are false. Equivalent to : - + def ifilterfalse(predicate, iterable): if predicate is None: predicate = bool @@ -570,7 +569,7 @@ yield tuple(args) else: yield function(*args) - + """) @@ -728,9 +727,9 @@ __doc__ = """Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely. - + Equivalent to : - + def cycle(iterable): saved = [] for element in iterable: @@ -738,7 +737,7 @@ saved.append(element) while saved: for element in saved: - yield element + yield element """) class W_StarMap(Wrappable): @@ -778,7 +777,7 @@ def starmap(function, iterable): iterable = iter(iterable) while True: - yield function(*iterable.next()) + yield function(*iterable.next()) """) @@ -788,15 +787,15 @@ Note : once tee() has made a split, the original iterable should not be used anywhere else; otherwise, the iterable could get advanced without the tee objects being informed. - + Note : this member of the toolkit may require significant auxiliary storage (depending on how much temporary data needs to be stored). In general, if one iterator is going to use most or all of the data before the other iterator, it is faster to use list() instead of tee() - + Equivalent to : - + def tee(iterable, n=2): def gen(next, data={}, cnt=[0]): for i in count(): @@ -888,7 +887,7 @@ self.exhausted = False self.started = False # new_group - new group not started yet, next should not skip any items - self.new_group = True + self.new_group = True self.w_lookahead = self.space.w_None self.w_key = self.space.w_None diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -1,10 +1,8 @@ -from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask from pypy.rlib import rstackovf from pypy.module._file.interp_file import W_File -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import sys + Py_MARSHAL_VERSION = 2 diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,4 +1,4 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,7 +1,7 @@ import math -from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array +from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, + convert_to_array) from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py --- a/pypy/module/mmap/interp_mmap.py +++ b/pypy/module/mmap/interp_mmap.py @@ -1,21 +1,16 @@ -from pypy.rpython.tool import rffi_platform -from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped from pypy.rlib import rmmap from pypy.rlib.rmmap import RValueError, RTypeError, ROverflowError -import sys -import os -import platform -import stat + class W_MMap(Wrappable): def __init__(self, space, mmap_obj): self.space = space self.mmap = mmap_obj - + def close(self): self.mmap.close() diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -15,7 +15,6 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap -from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant from pypy.jit.metainterp.resoperation import rop from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes @@ -66,7 +65,7 @@ def on_compile(self, logger, looptoken, operations, type, next_instr, is_being_profiled, ll_pycode): from pypy.rpython.annlowlevel import cast_base_ptr_to_instance - + space = self.space cache = space.fromcache(Cache) if cache.in_recursion: @@ -170,7 +169,7 @@ # ____________________________________________________________ # -# Public interface +# Public interface def set_param(space, __args__): '''Configure the tunable JIT parameters. @@ -212,7 +211,7 @@ class Cache(object): in_recursion = False - + def __init__(self, space): self.w_compile_hook = space.w_None diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -1,9 +1,9 @@ from pypy.interpreter.typedef import TypeDef, interp_attrproperty -from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import unwrap_spec, interp2app from pypy.interpreter.pycode import PyCode -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.lltypesystem.rclass import OBJECT diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py --- a/pypy/module/rctime/interp_time.py +++ b/pypy/module/rctime/interp_time.py @@ -6,7 +6,6 @@ from pypy.rlib.rarithmetic import ovfcheck_float_to_int from pypy.rlib import rposix from pypy.translator.tool.cbuild import ExternalCompilationInfo -import math import os import sys import time as pytime @@ -102,7 +101,7 @@ CLOCKS_PER_SEC = platform.ConstantInteger("CLOCKS_PER_SEC") clock_t = platform.SimpleType("clock_t", rffi.ULONG) has_gettimeofday = platform.Has('gettimeofday') - + if _POSIX: calling_conv = 'c' CConfig.timeval = platform.Struct("struct timeval", @@ -235,7 +234,7 @@ _set_module_object(space, "timezone", space.wrap(timezone)) _set_module_object(space, 'daylight', space.wrap(daylight)) - tzname_w = [space.wrap(tzname[0]), space.wrap(tzname[1])] + tzname_w = [space.wrap(tzname[0]), space.wrap(tzname[1])] _set_module_object(space, 'tzname', space.newtuple(tzname_w)) _set_module_object(space, 'altzone', space.wrap(altzone)) @@ -310,7 +309,7 @@ space.wrap((rffi.getintfield(t, 'c_tm_wday') + 6) % 7), # want monday == 0 space.wrap(rffi.getintfield(t, 'c_tm_yday') + 1), # want january, 1 == 1 space.wrap(rffi.getintfield(t, 'c_tm_isdst'))] - + w_struct_time = _get_module_object(space, 'struct_time') w_time_tuple = space.newtuple(time_tuple) return space.call_function(w_struct_time, w_time_tuple) @@ -330,7 +329,7 @@ tup_w = space.fixedview(w_tup) if len(tup_w) != 9: - raise operationerrfmt(space.w_TypeError, + raise operationerrfmt(space.w_TypeError, "argument must be sequence of " "length 9, not %d", len(tup_w)) @@ -359,7 +358,7 @@ w_accept2dyear = _get_module_object(space, "accept2dyear") accept2dyear = space.int_w(w_accept2dyear) - + if y < 1900: if not accept2dyear: raise OperationError(space.w_ValueError, @@ -392,7 +391,7 @@ Return the current time in seconds since the Epoch. Fractions of a second may be present if the system clock provides them.""" - + secs = pytime.time() return space.wrap(secs) @@ -420,7 +419,7 @@ not present, current time as returned by localtime() is used.""" seconds = _get_inttime(space, w_seconds) - + t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw') t_ref[0] = seconds p = c_ctime(t_ref) @@ -444,7 +443,7 @@ if not p: raise OperationError(space.w_ValueError, space.wrap("unconvertible time")) - + return space.wrap(rffi.charp2str(p)[:-1]) # get rid of new line def gmtime(space, w_seconds=None): @@ -462,7 +461,7 @@ t_ref[0] = seconds p = c_gmtime(t_ref) lltype.free(t_ref, flavor='raw') - + if not p: raise OperationError(space.w_ValueError, space.wrap(_get_error_msg())) return _tm_to_tuple(space, p) @@ -479,7 +478,7 @@ t_ref[0] = seconds p = c_localtime(t_ref) lltype.free(t_ref, flavor='raw') - + if not p: raise OperationError(space.w_ValueError, space.wrap(_get_error_msg())) return _tm_to_tuple(space, p) @@ -524,7 +523,7 @@ See the library reference manual for formatting codes. When the time tuple is not present, current time as returned by localtime() is used.""" buf_value = _gettmarg(space, w_tup) - + # Checks added to make sure strftime() does not crash Python by # indexing blindly into some array for a textual representation # by some bad index (fixes bug #897625). diff --git a/pypy/module/select/interp_select.py b/pypy/module/select/interp_select.py --- a/pypy/module/select/interp_select.py +++ b/pypy/module/select/interp_select.py @@ -1,9 +1,7 @@ -import math from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import ( - OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.rlib import rpoll import errno @@ -122,7 +120,7 @@ w_errortype = space.fromcache(Cache).w_error raise OperationError(w_errortype, space.newtuple([ space.wrap(s.errno), space.wrap(s.get_msg())])) - + return space.newtuple([ space.newlist([iwtd_d[i] for i in iwtd]), space.newlist([owtd_d[i] for i in owtd]), diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py --- a/pypy/module/struct/formatiterator.py +++ b/pypy/module/struct/formatiterator.py @@ -1,11 +1,10 @@ - from pypy.interpreter.error import OperationError from pypy.rlib.objectmodel import specialize from pypy.rlib.rstruct.error import StructError from pypy.rlib.rstruct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT -from pypy.rlib.rstruct.formatiterator import (FormatIterator, - CalcSizeFormatIterator) +from pypy.rlib.rstruct.formatiterator import FormatIterator + class PackFormatIterator(FormatIterator): diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py --- a/pypy/module/struct/interp_struct.py +++ b/pypy/module/struct/interp_struct.py @@ -1,10 +1,7 @@ from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.module.struct.formatiterator import PackFormatIterator, UnpackFormatIterator from pypy.rlib.rstruct.error import StructError -from pypy.module.struct.formatiterator import CalcSizeFormatIterator -from pypy.module.struct.formatiterator import PackFormatIterator -from pypy.module.struct.formatiterator import UnpackFormatIterator - +from pypy.rlib.rstruct.formatiterator import CalcSizeFormatIterator @unwrap_spec(format=str) def calcsize(space, format): diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -1,9 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype, llmemory -from pypy.rpython.tool import rffi_platform as platform from pypy.translator.tool.cbuild import ExternalCompilationInfo -import py, os -from pypy.rpython.extregistry import ExtRegistryEntry +import py from pypy.rlib import jit from pypy.rlib.debug import ll_assert from pypy.rlib.objectmodel import we_are_translated diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py --- a/pypy/module/thread/os_local.py +++ b/pypy/module/thread/os_local.py @@ -1,9 +1,7 @@ from pypy.module.thread import ll_thread as thread -from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp2app -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict +from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty, + descr_get_dict) class Local(Wrappable): diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py --- a/pypy/module/thread/os_thread.py +++ b/pypy/module/thread/os_thread.py @@ -6,7 +6,6 @@ from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import unwrap_spec, NoneNotWrapped, Arguments -from pypy.rlib.objectmodel import free_non_gc_object # Here are the steps performed to start a new thread: # @@ -167,14 +166,14 @@ when the function raises an unhandled exception; a stack trace will be printed unless the exception is SystemExit.""" setup_threads(space) - if not space.is_true(space.isinstance(w_args, space.w_tuple)): - raise OperationError(space.w_TypeError, - space.wrap("2nd arg must be a tuple")) - if w_kwargs is not None and not space.is_true(space.isinstance(w_kwargs, space.w_dict)): - raise OperationError(space.w_TypeError, - space.wrap("optional 3rd arg must be a dictionary")) + if not space.is_true(space.isinstance(w_args, space.w_tuple)): + raise OperationError(space.w_TypeError, + space.wrap("2nd arg must be a tuple")) + if w_kwargs is not None and not space.is_true(space.isinstance(w_kwargs, space.w_dict)): + raise OperationError(space.w_TypeError, + space.wrap("optional 3rd arg must be a dictionary")) if not space.is_true(space.callable(w_callable)): - raise OperationError(space.w_TypeError, + raise OperationError(space.w_TypeError, space.wrap("first arg must be callable")) args = Arguments.frompacked(space, w_args, w_kwargs) diff --git a/pypy/module/unicodedata/generate_unicodedb.py b/pypy/module/unicodedata/generate_unicodedb.py --- a/pypy/module/unicodedata/generate_unicodedb.py +++ b/pypy/module/unicodedata/generate_unicodedb.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -import pprint - MAXUNICODE = 0x10FFFF # the value of sys.maxunicode of wide Python builds MANDATORY_LINE_BREAKS = ["BK", "CR", "LF", "NL"] # line break categories @@ -66,16 +64,16 @@ self.upper = int(data[12], 16) self.lower = None if data[13]: - self.lower = int(data[13], 16) + self.lower = int(data[13], 16) self.title = None if data[14]: self.title = int(data[14], 16) - + def copy(self): uc = Unicodechar() uc.__dict__.update(self.__dict__) return uc - + def get_compat_decomposition(table, code): if not table[code].decomposition: return [code] @@ -177,13 +175,13 @@ for code in range(len(table)): if table[code] is None: table[code] = defaultChar - + extra_numeric = read_unihan(unihan_file) for code, value in extra_numeric.iteritems(): uc = table[code].copy() uc.numeric = value table[code] = uc - + # Compute full decompositions. for code in range(len(table)): get_canonical_decomposition(table, code) @@ -365,7 +363,7 @@ print >> outfile, '%r: %r,' % (code, name) print >> outfile, '}' - + print >> outfile, '_names_corrected = {' for name, code in sorted(base_mod._orig_names.iteritems()): if name not in names: @@ -389,7 +387,7 @@ print >> outfile, '%r: None,' % name print >> outfile, '}' - + def writeUnicodedata(version, table, outfile, base): if base: print >> outfile, 'import %s as base_mod' % base @@ -406,7 +404,7 @@ cjk_end = 0x9FBB write_character_names(outfile, table, base_mod) - + print >> outfile, ''' _cjk_prefix = "CJK UNIFIED IDEOGRAPH-" _hangul_prefix = 'HANGUL SYLLABLE ' @@ -496,7 +494,7 @@ v_code = vl_code %% len(_hangul_V) return ("HANGUL SYLLABLE " + _hangul_L[l_code] + _hangul_V[v_code] + _hangul_T[t_code]) - + if not base_mod: return lookup_charcode(code) else: @@ -522,7 +520,7 @@ digit[code] = table[code].digit if table[code].numeric is not None: numeric[code] = table[code].numeric - + writeDict(outfile, '_decimal', decimal, base_mod) writeDict(outfile, '_digit', digit, base_mod) writeDict(outfile, '_numeric', numeric, base_mod) @@ -662,11 +660,11 @@ ''' def main(): - import re, sys + import sys from optparse import OptionParser infile = None outfile = sys.stdout - + parser = OptionParser('Usage: %prog [options]') parser.add_option('--base', metavar='FILENAME', help='Base python version (for import)') parser.add_option('--output', metavar='OUTPUT_MODULE', help='Output module (implied py extension)') diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1824,6 +1824,11 @@ __gccallshapes: """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) + print >> output, """\ + #if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits + #endif + """ def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) From noreply at buildbot.pypy.org Sat Jul 16 16:29:48 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 16:29:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix bug with regard to multiple loops at the same assembler piece. Make parsing Message-ID: <20110716142948.23FA882962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45668:402d04acdc09 Date: 2011-07-16 16:29 +0200 http://bitbucket.org/pypy/pypy/changeset/402d04acdc09/ Log: Fix bug with regard to multiple loops at the same assembler piece. Make parsing assembler lazy (a bit ugly) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -343,18 +343,20 @@ addr = int(m.group(1), 16) entry = entry.lower() m = re.search('guard \d+', entry) - addrs[addr] = m.group(0) + name = m.group(0) else: name = entry[:entry.find('(') - 1].lower() - addrs[int(m.group(1), 16)] = name + addr = int(m.group(1), 16) + addrs.setdefault(addr, []).append(name) dumps = {} for entry in extract_category(log, 'jit-backend-dump'): backend, _, dump, _ = entry.split("\n") _, addr, _, data = re.split(" +", dump) backend_name = backend.split(" ")[1] addr = int(addr[1:], 16) - if addr in addrs: - dumps[addrs[addr]] = (backend_name, addr, data) + if addr in addrs and addrs[addr]: + name = addrs[addr].pop(0) # they should come in order + dumps[name] = (backend_name, addr, data) loops = [] for entry in extract_category(log, 'jit-log-opt'): parser = ParserCls(entry, None, {}, 'lltype', None, @@ -369,7 +371,10 @@ name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] - parser.postprocess(loop, backend_tp=bname, backend_dump=dump, - dump_start=start_ofs) + loop.force_asm = (lambda dump=dump, start_ofs=start_ofs, + bname=bname, loop=loop: + parser.postprocess(loop, backend_tp=bname, + backend_dump=dump, + dump_start=start_ofs)) loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log --- a/pypy/tool/jitlogparser/test/logtest2.log +++ b/pypy/tool/jitlogparser/test/logtest2.log @@ -259,7 +259,7 @@ [1f600873506] {jit-backend-dump BACKEND x86_64 SYS_EXECUTABLE python -CODE_DUMP @7f8907a0b9e5 +0 C8000000 +CODE_DUMP @7f8907a0b3d5 +0 C8000000 [1f600874b44] jit-backend-dump} [1f6008754d4] {jit-backend-dump BACKEND x86_64 diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -213,11 +213,15 @@ def test_import_log(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) + for loop in loops: + loop.force_asm() assert 'jge' in loops[0].operations[3].asm def test_import_log_2(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest2.log'))) + for loop in loops: + loop.force_asm() assert 'cmp' in loops[1].operations[1].asm # bridge assert 'jo' in loops[3].operations[3].asm From noreply at buildbot.pypy.org Sat Jul 16 16:41:32 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 16:41:32 +0200 (CEST) Subject: [pypy-commit] jitviewer default: use the lazy loading of loops Message-ID: <20110716144132.6BAE782962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r145:6159d4330dce Date: 2011-07-16 16:39 +0200 http://bitbucket.org/pypy/jitviewer/changeset/6159d4330dce/ Log: use the lazy loading of loops diff --git a/bin/jitviewer.py b/bin/jitviewer.py --- a/bin/jitviewer.py +++ b/bin/jitviewer.py @@ -96,6 +96,8 @@ def loop(self): no = int(flask.request.args.get('no', '0')) orig_loop = self.storage.loops[no] + if hasattr(orig_loop, 'force_asm'): + orig_loop.force_asm() ops = adjust_bridges(orig_loop, flask.request.args) loop = FunctionHtml.from_operations(ops, self.storage, inputargs=orig_loop.inputargs) From noreply at buildbot.pypy.org Sat Jul 16 17:12:54 2011 From: noreply at buildbot.pypy.org (bivab) Date: Sat, 16 Jul 2011 17:12:54 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: fix Message-ID: <20110716151254.EED6282962@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45669:05def4b63047 Date: 2011-07-15 15:00 +0200 http://bitbucket.org/pypy/pypy/changeset/05def4b63047/ Log: fix diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -117,7 +117,7 @@ ll_new_unicode) if gc_ll_descr.get_malloc_slowpath_addr is not None: self._build_malloc_slowpath() - if gc_ll_descr.gcrootmap and gc_ll_descr.is_shadow_stack: + if gc_ll_descr.gcrootmap and gc_ll_descr.gcrootmap.is_shadow_stack: self._build_release_gil(gc_ll_descr.gcrootmap) self.memcpy_addr = self.cpu.cast_ptr_to_int(memcpy_fn) self._exit_code_addr = self._gen_exit_path() From noreply at buildbot.pypy.org Sat Jul 16 17:12:56 2011 From: noreply at buildbot.pypy.org (bivab) Date: Sat, 16 Jul 2011 17:12:56 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: merge default Message-ID: <20110716151256.EF63B82962@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45670:57c5578f3895 Date: 2011-07-15 15:02 +0200 http://bitbucket.org/pypy/pypy/changeset/57c5578f3895/ Log: merge default diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -27,9 +27,10 @@ _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset) -def parse_future(tree): +def parse_future(tree, feature_flags): future_lineno = 0 future_column = 0 + flags = 0 have_docstring = False body = None if isinstance(tree, ast.Module): @@ -37,7 +38,7 @@ elif isinstance(tree, ast.Interactive): body = tree.body if body is None: - return 0, 0 + return 0, 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): if have_docstring: @@ -48,11 +49,16 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset + for alias in stmt.names: + assert isinstance(alias, ast.alias) + # If this is an invalid flag, it will be caught later in + # codegen.py. + flags |= feature_flags.get(alias.name, 0) else: break else: break - return future_lineno, future_column + return flags, future_lineno, future_column class ForbiddenNameAssignment(Exception): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): @@ -925,6 +927,9 @@ return self.w_True return self.w_False + def issequence_w(self, w_obj): + return (self.findattr(w_obj, self.wrap("__getitem__")) is not None) + def isinstance_w(self, w_obj, w_type): return self.is_true(self.isinstance(w_obj, w_type)) diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,10 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - future_pos = misc.parse_future(node) + fut = misc.parse_future(node, self.future_flags.compiler_features) + f_flags, f_lineno, f_col = fut + future_pos = f_lineno, f_col + flags |= f_flags info = pyparse.CompileInfo(filename, mode, flags, future_pos) return self._compile_ast(node, info) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) - if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') + if parent_destructor is not None: + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -858,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -482,7 +482,7 @@ # rawstart = self.materialize_loop(original_loop_token) debug_start("jit-backend-addr") - debug_print("Bridge out of Guard %d has address %x to %x" % + debug_print("bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): @@ -44,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -58,10 +63,15 @@ expected = "\xE8" + struct.pack('= sizeof(lltype.Signed): + # + if (v_result.concretetype in (FLOAT, lltype.Float) or + v_arg.concretetype in (FLOAT, lltype.Float)): + assert (v_result.concretetype == lltype.Float and + v_arg.concretetype == lltype.Float), "xxx unsupported cast" + return + # + size2, unsigned2 = size_and_sign(v_result.concretetype) + assert size2 <= sizeof(lltype.Signed) + if size2 == sizeof(lltype.Signed): return # the target type is LONG or ULONG - size1, unsigned1 = size_and_sign(op.args[0].concretetype) + size1, unsigned1 = size_and_sign(v_arg.concretetype) + assert size1 <= sizeof(lltype.Signed) # def bounds(size, unsigned): if unsigned: @@ -784,20 +836,19 @@ return # the target type includes the source range # result = [] - v1 = op.args[0] if min2: c_min2 = Constant(min2, lltype.Signed) - v2 = Variable(); v2.concretetype = lltype.Signed - result.append(SpaceOperation('int_sub', [v1, c_min2], v2)) + v2 = varoftype(lltype.Signed) + result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2)) else: - v2 = v1 + v2 = v_arg c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed) - v3 = Variable(); v3.concretetype = lltype.Signed + v3 = varoftype(lltype.Signed) result.append(SpaceOperation('int_and', [v2, c_mask], v3)) if min2: - result.append(SpaceOperation('int_add', [v3, c_min2], op.result)) + result.append(SpaceOperation('int_add', [v3, c_min2], v_result)) else: - result[-1].result = op.result + result[-1].result = v_result return result def rewrite_op_direct_ptradd(self, op): @@ -890,30 +941,7 @@ rewrite_op_ullong_is_true = rewrite_op_llong_is_true def rewrite_op_cast_primitive(self, op): - fromll = longlong.is_longlong(op.args[0].concretetype) - toll = longlong.is_longlong(op.result.concretetype) - if fromll != toll: - args = op.args - if fromll: - opname = 'truncate_longlong_to_int' - RESULT = lltype.Signed - else: - from pypy.rpython.lltypesystem import rffi - if rffi.cast(op.args[0].concretetype, -1) < 0: - opname = 'cast_int_to_longlong' - else: - opname = 'cast_uint_to_longlong' - RESULT = lltype.SignedLongLong - v = varoftype(RESULT) - op1 = SpaceOperation(opname, args, v) - op2 = self.rewrite_operation(op1) - # - # force a renaming to put the correct result in place, even though - # it might be slightly mistyped (e.g. Signed versus Unsigned) - assert op2.result is v - op2.result = op.result - # - return op2 + return self.rewrite_op_force_cast(op) # ---------- # Renames, from the _old opname to the _new one. @@ -1247,7 +1275,7 @@ calldescr = self.callcontrol.getcalldescr(op, oopspecindex, extraeffect) if extraeffect is not None: - assert (type(calldescr) is str # for tests + assert (is_test_calldescr(calldescr) # for tests or calldescr.get_extra_info().extraeffect == extraeffect) if isinstance(op.args[0].value, str): pass # for tests only @@ -1408,6 +1436,9 @@ return "using virtualizable array in illegal way in %r" % ( self.args[0],) +def is_test_calldescr(calldescr): + return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False) + def _with_prefix(prefix): result = {} for name in dir(Transformer): diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -96,6 +96,7 @@ def _try_coalesce(self, v, w): if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: + assert getkind(w.concretetype) == self.kind dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -3,6 +3,7 @@ from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register from pypy.jit.codewriter.format import assert_format +from pypy.jit.codewriter import longlong from pypy.jit.metainterp.history import AbstractDescr from pypy.rpython.lltypesystem import lltype, rclass, rstr from pypy.objspace.flow.model import SpaceOperation, Variable, Constant @@ -30,6 +31,9 @@ 'float': FakeRegAlloc()} class FakeDescr(AbstractDescr): + _for_tests_only = True + def __init__(self, oopspecindex=None): + self.oopspecindex = oopspecindex def __repr__(self): return '' def as_vtable_size_descr(self): @@ -55,19 +59,24 @@ def arraydescrof(self, ARRAY): return FakeDescr() +class FakeCallInfoCollection: + def add(self, *args): + pass + class FakeCallControl: _descr_cannot_raise = FakeDescr() + callinfocollection = FakeCallInfoCollection() def guess_call_kind(self, op): return 'residual' - def getcalldescr(self, op): + def getcalldescr(self, op, oopspecindex=None, extraeffect=None): try: if 'cannot_raise' in op.args[0].value._obj.graph.name: return self._descr_cannot_raise except AttributeError: pass - return FakeDescr() + return FakeDescr(oopspecindex) def calldescr_canraise(self, calldescr): - return calldescr is not self._descr_cannot_raise + return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None def get_vinfo(self, VTYPEPTR): return None @@ -734,7 +743,9 @@ def test_force_cast(self): from pypy.rpython.lltypesystem import rffi - + # NB: we don't need to test for INT here, the logic in jtransform is + # general enough so that if we have the below cases it should + # generalize also to INT for FROM, TO, expected in [ (rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""), (rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"), @@ -797,14 +808,44 @@ expected = [s.strip() for s in expected.splitlines()] check_force_cast(FROM, TO, expected, 42) check_force_cast(FROM, TO, expected, -42) - expected.append('int_return %i' + str(len(expected))) - expected = '\n'.join(expected) + returnvar = "%i" + str(len(expected)) + expected.append('int_return ' + returnvar) + expectedstr = '\n'.join(expected) # def f(n): return rffi.cast(TO, n) - self.encoding_test(f, [rffi.cast(FROM, 42)], expected, + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, transform=True) + if not longlong.is_64_bit: + if FROM in (rffi.LONG, rffi.ULONG): + if FROM == rffi.LONG: + FROM = rffi.LONGLONG + else: + FROM = rffi.ULONGLONG + expected.insert(0, + "residual_call_irf_i $<* fn llong_to_int>, , I[], R[], F[%f0] -> %i0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + elif TO in (rffi.LONG, rffi.ULONG): + if TO == rffi.LONG: + TO = rffi.LONGLONG + else: + TO = rffi.ULONGLONG + if rffi.cast(FROM, -1) < 0: + fnname = "llong_from_int" + else: + fnname = "llong_from_uint" + expected.pop() # remove int_return + expected.append( + "residual_call_irf_f $<* fn %s>, , I[%s], R[], F[] -> %%f0" + % (fnname, returnvar)) + expected.append("float_return %f0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + def test_force_cast_pointer(self): from pypy.rpython.lltypesystem import rffi def h(p): @@ -813,6 +854,14 @@ int_return %i0 """, transform=True) + def test_force_cast_float(self): + from pypy.rpython.lltypesystem import rffi + def f(n): + return rffi.cast(lltype.Float, n) + self.encoding_test(f, [12.456], """ + float_return %f0 + """, transform=True) + def test_direct_ptradd(self): from pypy.rpython.lltypesystem import rffi def f(p, n): diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py --- a/pypy/jit/codewriter/test/test_longlong.py +++ b/pypy/jit/codewriter/test/test_longlong.py @@ -37,7 +37,7 @@ class TestLongLong: def setup_class(cls): - if sys.maxint > 2147483647: + if longlong.is_64_bit: py.test.skip("only for 32-bit platforms") def do_check(self, opname, oopspecindex, ARGS, RESULT): @@ -46,6 +46,8 @@ op = SpaceOperation(opname, vlist, v_result) tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) op1 = tr.rewrite_operation(op) + if isinstance(op1, list): + [op1] = op1 # def is_llf(TYPE): return (TYPE == lltype.SignedLongLong or @@ -196,6 +198,23 @@ for T2 in [lltype.Signed, lltype.Unsigned]: self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT, [T1], T2) + self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT, + [T1], T2) + if T2 == lltype.Signed: + expected = EffectInfo.OS_LLONG_FROM_INT + else: + expected = EffectInfo.OS_LLONG_FROM_UINT + self.do_check('cast_primitive', expected, [T2], T1) + self.do_check('force_cast', expected, [T2], T1) + # + for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + vlist = [varoftype(T1)] + v_result = varoftype(T2) + op = SpaceOperation('force_cast', vlist, v_result) + tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) + op1 = tr.rewrite_operation(op) + assert op1 is None def test_constants(self): for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]: diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -21,7 +21,7 @@ continue if hasattr(Class, name_prefix + name): opclass = resoperation.opclasses[getattr(rop, name)] - print value, name, opclass + assert name in opclass.__name__ result.append((value, opclass, getattr(Class, name_prefix + name))) return unrolling_iterable(result) diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -186,6 +186,11 @@ mod = self.get_ast("from __future__ import with_statement; import y; " \ "from __future__ import nested_scopes") raises(SyntaxError, compile, mod, "", "exec") + mod = self.get_ast("from __future__ import division\nx = 1/2") + co = compile(mod, "", "exec") + ns = {} + exec co in ns + assert ns["x"] == .5 def test_field_attr_writable(self): import _ast as ast diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -43,11 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -57,6 +57,11 @@ def __del__(self): self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + + def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -10,7 +10,7 @@ class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 @@ -23,8 +23,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,11 +120,8 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: - w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) + assert isinstance(w_self, W_WeakrefBase) + w_self.space.call_function(w_self.w_callable, w_self) def descr__repr__(self, space): w_obj = self.dereference() diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -133,6 +133,7 @@ bz2f.seek(0) assert bz2f.tell() == 0 + del bz2f # delete from this frame, which is captured in the traceback def test_open_close_del(self): from bz2 import BZ2File @@ -246,11 +247,18 @@ assert text_read == self.TEXT bz2f.close() + def test_silently_closes(self): + from bz2 import BZ2File + self.create_broken_temp_file() + BZ2File(self.temppath) + # check that no C-level malloc is left behind + def test_read_broken_file(self): from bz2 import BZ2File self.create_broken_temp_file() bz2f = BZ2File(self.temppath) raises(EOFError, bz2f.read) + del bz2f # delete from this frame, which is captured in the traceback def test_subsequent_read_broken_file(self): from bz2 import BZ2File @@ -264,6 +272,7 @@ raise Exception("should generate EOFError earlier") except EOFError: pass + del bz2f # delete from this frame, which is captured in the traceback def test_read_chunk10(self): from bz2 import BZ2File @@ -416,6 +425,7 @@ bz2f.close() bz2f = BZ2File(self.temppath, 'r') assert bz2f.read() == self.random_data + del bz2f # delete from this frame, which is captured in the traceback def test_context_manager(self): from bz2 import BZ2File diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.1" /* PyPy version as a string */ -#define PYPY_VERSION "1.5.0" +#define PYPY_VERSION "1.6.0" /* Subversion Revision number of this file (not of the repository) */ #define PY_PATCHLEVEL_REVISION "$Revision: 77872 $" diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -22,7 +22,7 @@ def PySequence_Check(space, w_obj): """Return 1 if the object provides sequence protocol, and 0 otherwise. This function always succeeds.""" - return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None) + return int(space.issequence_w(w_obj)) @cpython_api([PyObject], Py_ssize_t, error=-1) def PySequence_Size(space, w_obj): diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt, OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit @@ -7,7 +7,6 @@ from pypy.tool.sourcetools import func_with_new_name import math - def dummy1(v): assert isinstance(v, float) return v @@ -88,23 +87,15 @@ def _binop_impl(function): signature = Signature() def impl(self, space, w_other): + w_other = convert_to_array(space, w_other) new_sig = self.signature.transition(signature) - if isinstance(w_other, BaseArray): - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - else: - w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) + res = Call2( + function, + self, + w_other, + new_sig.transition(w_other.signature) + ) + w_other.invalidates.append(res) self.invalidates.append(res) return space.wrap(res) return func_with_new_name(impl, "binop_%s_impl" % function.__name__) @@ -272,6 +263,16 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) +def convert_to_array (space, w_obj): + if isinstance(w_obj, BaseArray): + return w_obj + elif space.issequence_w(w_obj): + # Convert to array. + return new_numarray(space, w_obj) + else: + # If it's a scalar + return FloatWrapper(space.float_w(w_obj)) + class FloatWrapper(BaseArray): """ Intermediate class representing a float literal. @@ -478,14 +479,17 @@ def __del__(self): lltype.free(self.storage, flavor='raw') -def descr_new_numarray(space, w_type, w_size_or_iterable): +def new_numarray(space, w_size_or_iterable): l = space.listview(w_size_or_iterable) arr = SingleDimArray(len(l)) i = 0 for w_elem in l: arr.storage[i] = space.float_w(space.float(w_elem)) i += 1 - return space.wrap(arr) + return arr + +def descr_new_numarray(space, w_type, w_size_or_iterable): + return space.wrap(new_numarray(space, w_size_or_iterable)) @unwrap_spec(size=int) def zeros(space, size): diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,31 +1,35 @@ import math from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature +from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name - def ufunc(func): signature = Signature() def impl(space, w_obj): - if isinstance(w_obj, BaseArray): - w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) - w_obj.invalidates.append(w_res) + if space.issequence_w(w_obj): + w_obj_arr = convert_to_array(space, w_obj) + w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) + w_obj_arr.invalidates.append(w_res) return w_res - return space.wrap(func(space.float_w(w_obj))) + else: + return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): - if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): - new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) - w_res = Call2(func, w_lhs, w_rhs, new_sig) - w_lhs.invalidates.append(w_res) - w_rhs.invalidates.append(w_res) + if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): + w_lhs_arr = convert_to_array(space, w_lhs) + w_rhs_arr = convert_to_array(space, w_rhs) + new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature) + w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig) + w_lhs_arr.invalidates.append(w_res) + w_rhs_arr.invalidates.append(w_res) return w_res - return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) + else: + return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @ufunc diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -1,12 +1,10 @@ from pypy.conftest import gettestobjspace from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper - class BaseNumpyAppTest(object): def setup_class(cls): cls.space = gettestobjspace(usemodules=('micronumpy',)) - class TestSignature(object): def test_binop_signature(self, space): ar = SingleDimArray(10) @@ -26,4 +24,4 @@ v3 = ar.descr_add(space, v1) v4 = ar.descr_add(space, v2) - assert v3.signature is v4.signature \ No newline at end of file + assert v3.signature is v4.signature diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -97,6 +97,15 @@ for i in range(5): assert b[i] == i + 5 + def test_add_list(self): + from numpy import array + a = array(range(5)) + b = list(reversed(range(5))) + c = a + b + assert isinstance(c, array) + for i in range(5): + assert c[i] == 4 + def test_subtract(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -10,6 +10,40 @@ assert sign(-0.0) == 0.0 assert minimum(2.0, 3.0) == 2.0 + def test_sequence(self): + from numpy import array, negative, minimum + a = array(range(3)) + b = [2.0, 1.0, 0.0] + c = 1.0 + b_neg = negative(b) + assert isinstance(b_neg, array) + for i in range(3): + assert b_neg[i] == -b[i] + min_a_b = minimum(a, b) + assert isinstance(min_a_b, array) + for i in range(3): + assert min_a_b[i] == min(a[i], b[i]) + min_b_a = minimum(b, a) + assert isinstance(min_b_a, array) + for i in range(3): + assert min_b_a[i] == min(a[i], b[i]) + min_a_c = minimum(a, c) + assert isinstance(min_a_c, array) + for i in range(3): + assert min_a_c[i] == min(a[i], c) + min_c_a = minimum(c, a) + assert isinstance(min_c_a, array) + for i in range(3): + assert min_c_a[i] == min(a[i], c) + min_b_c = minimum(b, c) + assert isinstance(min_b_c, array) + for i in range(3): + assert min_b_c[i] == min(b[i], c) + min_c_b = minimum(c, b) + assert isinstance(min_c_b, array) + for i in range(3): + assert min_c_b[i] == min(b[i], c) + def test_negative(self): from numpy import array, negative diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -8,9 +8,16 @@ class FakeSpace(object): w_ValueError = None + + def issequence_w(self, w_obj): + return True + @specialize.argtype(1) - def wrap(self, v): - return v + def wrap(self, w_obj): + return w_obj + + def float_w(self, w_obj): + return float(w_obj) class TestNumpyJIt(LLJitMixin): def setup_class(cls): diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py --- a/pypy/module/sys/test/test_sysmodule.py +++ b/pypy/module/sys/test/test_sysmodule.py @@ -476,7 +476,7 @@ assert isinstance(vi[0], int) assert isinstance(vi[1], int) assert isinstance(vi[2], int) - assert vi[3] in ("alpha", "beta", "candidate", "final") + assert vi[3] in ("alpha", "beta", "candidate", "dev", "final") assert isinstance(vi[4], int) def test_allattributes(self): @@ -523,4 +523,4 @@ # If this ever actually becomes a compilation option this test should # be changed. - assert sys.float_repr_style == "short" \ No newline at end of file + assert sys.float_repr_style == "short" diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ CPYTHON_VERSION = (2, 7, 1, "final", 42) #XXX # sync patchlevel.h CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (1, 5, 0, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (1, 6, 0, "dev", 1) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -21,6 +21,7 @@ 'RPyThreadAcquireLock', 'RPyThreadReleaseLock', 'RPyThreadYield', 'RPyThreadGetStackSize', 'RPyThreadSetStackSize', + 'RPyOpaqueDealloc_ThreadLock', 'RPyThreadAfterFork'] ) @@ -52,6 +53,9 @@ c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], rffi.INT, threadsafe=False) # may add in a global list +c_thread_lock_dealloc = llexternal('RPyOpaqueDealloc_ThreadLock', [TLOCKP], + lltype.Void, + threadsafe=True) c_thread_acquirelock = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT], rffi.INT, threadsafe=True) # release the GIL @@ -120,7 +124,7 @@ def __enter__(self): self.acquire(True) - + def __exit__(self, *args): self.release() @@ -156,6 +160,9 @@ return ll_lock def free_ll_lock(ll_lock): + c_thread_acquirelock(ll_lock, 0) + c_thread_releaselock(ll_lock) + c_thread_lock_dealloc(ll_lock) lltype.free(ll_lock, flavor='raw', track_allocation=False) def acquire_NOAUTO(ll_lock, flag): diff --git a/pypy/module/thread/test/test_import_lock.py b/pypy/module/thread/test/test_import_lock.py --- a/pypy/module/thread/test/test_import_lock.py +++ b/pypy/module/thread/test/test_import_lock.py @@ -66,6 +66,9 @@ def test_lock(self, space, monkeypatch): from pypy.module.imp.importing import getimportlock, importhook + # Force importing the module _file now + space.builtin.get('file') + # Monkeypatch the import lock and add a counter importlock = getimportlock(space) original_acquire = importlock.acquire_lock diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -431,12 +431,17 @@ return None assert isinstance(lifeline, WeakrefLifeline) return lifeline + getweakref._cannot_really_call_random_things_ = True def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline - assert (isinstance(weakreflifeline, WeakrefLifeline) or - weakreflifeline is None) + assert isinstance(weakreflifeline, WeakrefLifeline) self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + setweakref._cannot_really_call_random_things_ = True + + def delweakref(self): + self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + delweakref._cannot_really_call_random_things_ = True class ObjectMixin(object): _mixin_ = True diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -36,6 +36,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None class W_SetObject(W_BaseSetObject): from pypy.objspace.std.settype import set_typedef as typedef diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -171,7 +171,7 @@ obj = c.instantiate() assert obj.getweakref() is None obj.setweakref(space, lifeline1) - obj.setweakref(space, None) + obj.delweakref() diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -532,6 +532,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None # ____________________________________________________________ # Initialization of type objects diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -482,6 +482,13 @@ key[2:]) cache[key] = s_value + # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass) + try: + graph = self.bookkeeper.position_key[0] + graph.func._dont_reach_me_in_del_ = True + except (TypeError, AttributeError): + pass + return annmodel.s_None def annotate_hooks(self, **kwds_s): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -83,6 +83,9 @@ t, rtyper, fngraph = self.gengraph(fn, [int]) + # added by compute_result_annotation() + assert fn._dont_reach_me_in_del_ == True + def getargs(func): for graph in t.graphs: if getattr(graph, 'func', None) is func: diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -172,17 +172,6 @@ assert max_n >= 0 ITEM = A.OF ctypes_item = get_ctypes_type(ITEM, delayed_builders) - # Python 2.5 ctypes can raise OverflowError on 64-bit builds - for n in [sys.maxint, 2**31]: - MAX_SIZE = n/64 - try: - PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item) - except OverflowError, e: - pass - else: - break - else: - raise e class CArray(ctypes.Structure): if not A._hints.get('nolength'): @@ -191,6 +180,7 @@ else: _fields_ = [('items', max_n * ctypes_item)] + @classmethod def _malloc(cls, n=None): if not isinstance(n, int): raise TypeError, "array length must be an int" @@ -199,10 +189,29 @@ if hasattr(bigarray, 'length'): bigarray.length = n return bigarray - _malloc = classmethod(_malloc) + + _ptrtype = None + + @classmethod + def _get_ptrtype(cls): + if cls._ptrtype: + return cls._ptrtype + # ctypes can raise OverflowError on 64-bit builds + for n in [sys.maxint, 2**31]: + cls.MAX_SIZE = n/64 + try: + cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item) + except OverflowError, e: + pass + else: + break + else: + raise e + return cls._ptrtype def _indexable(self, index): - assert index + 1 < MAX_SIZE + PtrType = self._get_ptrtype() + assert index + 1 < self.MAX_SIZE p = ctypes.cast(ctypes.pointer(self.items), PtrType) return p.contents diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py --- a/pypy/rpython/lltypesystem/rclass.py +++ b/pypy/rpython/lltypesystem/rclass.py @@ -400,6 +400,7 @@ assert len(s_func.descriptions) == 1 funcdesc, = s_func.descriptions graph = funcdesc.getuniquegraph() + self.check_graph_of_del_does_not_call_too_much(graph) FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void) destrptr = functionptr(FUNCTYPE, graph.name, graph=graph, diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -671,7 +671,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_arrayofstruct(self): - S1 = lltype.Struct('S1', ('x', lltype.Signed)) + S1 = lltype.Struct('S2', ('x', lltype.Signed)) A = lltype.Array(S1, hints={'nolength': True}) a = lltype.malloc(A, 5, flavor='raw') a[0].x = 100 diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,6 +34,13 @@ the GC in very small programs. Defaults to 8 times the nursery. + PYPY_GC_LOSTCARD If between two minor collections we see more than + 'PYPY_GC_LOSTCARD * length' writes to the same array, + then give up card marking and use the fast write + barrier instead. Defaults to 0.3333 for now. + Avoid values lower than 0.125: it is the growth + factor of list.append(). + PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -198,6 +205,9 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, + # See PYPY_GC_LOSTCARD. + "lost_card": 1.0 / 3.0, + # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -214,6 +224,7 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, + lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -235,6 +246,7 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 + self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -355,6 +367,10 @@ else: self.max_delta = 0.125 * env.get_total_memory() # + lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') + if lost_card > 0.0: + self.lost_card = lost_card + # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -649,7 +665,7 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only @@ -675,11 +691,15 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # (the loop is empty in C). - i = 0 - while i < cardheadersize: - llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) - i += 1 + # followed by a Signed (the loop is empty in C). + if cardheadersize > 0: + i = 0 + while i < cardheadersize - WORD: + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Char)) + i += 1 + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -903,14 +923,11 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # - size_gc_header = self.gcheaderbuilder.size_gc_header - p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: - p -= 1 - ll_assert(p.char[0] == '\x00', + i -= 1 + ll_assert(self.get_card(obj, i).char[0] == '\x00', "the card marker bits are not cleared") - i -= 1 # ---------- # Write barrier @@ -1008,6 +1025,8 @@ self.prebuilt_root_objects.append(addr_array) return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1025,10 +1044,6 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1057,6 +1072,8 @@ if not self.appears_to_be_young(newvalue): return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1069,10 +1086,6 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1090,11 +1103,36 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card(self, obj, byteindex): + def get_card_counter_addr(self, obj): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + return llarena.getfakearenaaddress(addr_byte) - WORD + def get_card(self, obj, byteindex): + return self.get_card_counter_addr(obj) + (~byteindex) + + def set_cards_flag(self, obj): + hdr = self.header(obj) + if hdr.tid & GCFLAG_CARDS_SET == 0: + # + # first time we set a card bit in this object + self.header(obj).tid |= GCFLAG_CARDS_SET + self.objects_with_cards_set.append(obj) + # + # initialize the counter with the array length and self.lost_card + typeid = self.get_type_id(obj) + offset_to_length = self.varsize_offset_to_length(typeid) + length = (obj + offset_to_length).signed[0] + counter = int(length * self.lost_card) + self.get_card_counter_addr(obj).signed[0] = counter + else: + # decrement the counter and if zero is reached, give up on + # card marking (up to the next collection). + addr = self.get_card_counter_addr(obj) + addr.signed[0] -= 1 + if addr.signed[0] < 0: + self.objects_pointing_to_young.append(obj) + hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1167,10 +1205,7 @@ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(dest_addr) - dest_hdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(dest_addr) # ---------- # Nursery collection @@ -1264,6 +1299,7 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) + p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1602,7 +1638,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 arena -= extra_words * WORD allocsize += extra_words * WORD # diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -525,6 +525,7 @@ def test_writebarrier_before_copy(self): from pypy.rpython.memory.gc import minimark largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 p_src = self.malloc(VAR, largeobj_size) p_dst = self.malloc(VAR, largeobj_size) # make them old @@ -564,6 +565,7 @@ from pypy.rpython.memory.gc import minimark tid = self.get_type_id(VAR) largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 addr_src = self.gc.external_malloc(tid, largeobj_size) addr_dst = self.gc.external_malloc(tid, largeobj_size) hdr_src = self.gc.header(addr_src) diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -374,6 +374,43 @@ def can_ll_be_null(self, s_value): return s_value.can_be_none() + def check_graph_of_del_does_not_call_too_much(self, graph): + # RPython-level __del__() methods should not do "too much". + # In the PyPy Python interpreter, they usually do simple things + # like file.__del__() closing the file descriptor; or if they + # want to do more like call an app-level __del__() method, they + # enqueue the object instead, and the actual call is done later. + # + # Here, as a quick way to check "not doing too much", we check + # that from no RPython-level __del__() method we can reach a + # JitDriver. + # + # XXX wrong complexity, but good enough because the set of + # reachable graphs should be small + callgraph = self.rtyper.annotator.translator.callgraph.values() + seen = {graph: None} + while True: + oldlength = len(seen) + for caller, callee in callgraph: + if caller in seen and callee not in seen: + func = getattr(callee, 'func', None) + if getattr(func, '_dont_reach_me_in_del_', False): + lst = [str(callee)] + g = caller + while g: + lst.append(str(g)) + g = seen.get(g) + lst.append('') + raise TyperError("the RPython-level __del__() method " + "in %r calls:%s" % ( + graph, '\n\t'.join(lst[::-1]))) + if getattr(func, '_cannot_really_call_random_things_', + False): + continue + seen[callee] = caller + if len(seen) == oldlength: + break + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops, classcallhop=None): diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -7,6 +7,7 @@ from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.rpython.error import TyperError from pypy.objspace.flow.model import summary class EmptyBase(object): @@ -1021,7 +1022,25 @@ assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] assert destrptra is not None assert destrptrb is not None - + + def test_del_forbidden(self): + class A(object): + def __del__(self): + self.foo() + def foo(self): + self.bar() + def bar(self): + pass + bar._dont_reach_me_in_del_ = True + def f(): + a = A() + a.foo() + a.bar() + t = TranslationContext() + t.buildannotator().build_types(f, []) + e = py.test.raises(TyperError, t.buildrtyper().specialize) + print e.value + def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int class FooBar(object): diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -231,7 +231,7 @@ const = self.const def fn(i): s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] - return s[i].startswith('o') + return s[i].startswith(const('o')) for i in range(10): res = self.interpret(fn, [i]) assert res == fn(i) @@ -251,7 +251,7 @@ const = self.const def fn(i): s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] - return s[i].endswith('e') + return s[i].endswith(const('e')) for i in range(10): res = self.interpret(fn, [i]) assert res == fn(i) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -337,8 +337,16 @@ addrs = {} for entry in extract_category(log, 'jit-backend-addr'): m = re.search('bootstrap ([\da-f]+)', entry) - name = entry[:entry.find('(') - 1] - addrs[int(m.group(1), 16)] = name + if not m: + # a bridge + m = re.search('has address ([\da-f]+)', entry) + addr = int(m.group(1), 16) + entry = entry.lower() + m = re.search('guard \d+', entry) + addrs[addr] = m.group(0) + else: + name = entry[:entry.find('(') - 1].lower() + addrs[int(m.group(1), 16)] = name dumps = {} for entry in extract_category(log, 'jit-backend-dump'): backend, _, dump, _ = entry.split("\n") @@ -353,7 +361,12 @@ nonstrict=True) loop = parser.parse() comm = loop.comment - name = comm[2:comm.find(':')-1] + comm = comm.lower() + if comm.startswith('# bridge'): + m = re.search('guard \d+', comm) + name = m.group(0) + else: + name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] parser.postprocess(loop, backend_tp=bname, backend_dump=dump, diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -214,3 +214,10 @@ _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) assert 'jge' in loops[0].operations[3].asm + +def test_import_log_2(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest2.log'))) + assert 'cmp' in loops[1].operations[1].asm + # bridge + assert 'cmp' in loops[3].operations[1].asm diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs --- a/pypy/translator/cli/src/pypylib.cs +++ b/pypy/translator/cli/src/pypylib.cs @@ -615,10 +615,28 @@ return s1.StartsWith(s2); } + public static bool ll_startswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[0] == c; + } + public static bool ll_endswith(string s1, string s2) { return s1.EndsWith(s2); } + + public static bool ll_endswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[s.Length - 1] == c; + } public static int ll_find(string s1, string s2, int start, int stop) { diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -791,6 +791,20 @@ return str.substring(start,start+cnt); } + public static boolean ll_startswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(0) == c; + } + + public static boolean ll_endswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(str.length() - 1) == c; + } + // ---------------------------------------------------------------------- // StringBuffer From noreply at buildbot.pypy.org Sat Jul 16 17:12:58 2011 From: noreply at buildbot.pypy.org (bivab) Date: Sat, 16 Jul 2011 17:12:58 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: add a check for the size of the value stored in size Message-ID: <20110716151258.253F082962@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45671:5690763bfdba Date: 2011-07-16 17:11 +0200 http://bitbucket.org/pypy/pypy/changeset/5690763bfdba/ Log: add a check for the size of the value stored in size diff --git a/pypy/jit/backend/arm/assembler.py b/pypy/jit/backend/arm/assembler.py --- a/pypy/jit/backend/arm/assembler.py +++ b/pypy/jit/backend/arm/assembler.py @@ -988,9 +988,13 @@ self.mc.gen_load_int(r.r0.value, nursery_free_adr) self.mc.LDR_ri(r.r0.value, r.r0.value) - self.mc.ADD_ri(r.r1.value, r.r0.value, size) + if _check_imm_arg(ConstInt(size)): + self.mc.ADD_ri(r.r1.value, r.r0.value, size) + else: + self.mc.gen_load_int(r.r1.value, size) + self.mc.ADD_rr(r.r1.value, r.r0.value, r.r1.value) - # XXX maybe use an offset from the valeu nursery_free_addr + # XXX maybe use an offset from the value nursery_free_addr self.mc.gen_load_int(r.ip.value, nursery_top_adr) self.mc.LDR_ri(r.ip.value, r.ip.value) diff --git a/pypy/jit/backend/arm/helper/regalloc.py b/pypy/jit/backend/arm/helper/regalloc.py --- a/pypy/jit/backend/arm/helper/regalloc.py +++ b/pypy/jit/backend/arm/helper/regalloc.py @@ -4,6 +4,7 @@ from pypy.jit.metainterp.history import ConstInt, BoxInt, Box from pypy.jit.metainterp.history import ConstInt +# XXX create a version that does not need a ConstInt def _check_imm_arg(arg, size=0xFF, allow_zero=True): if isinstance(arg, ConstInt): i = arg.getint() From noreply at buildbot.pypy.org Sat Jul 16 17:12:59 2011 From: noreply at buildbot.pypy.org (bivab) Date: Sat, 16 Jul 2011 17:12:59 +0200 (CEST) Subject: [pypy-commit] pypy arm-backend-2: merge default Message-ID: <20110716151259.93CBA82962@wyvern.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-backend-2 Changeset: r45672:8ca230890525 Date: 2011-07-16 17:12 +0200 http://bitbucket.org/pypy/pypy/changeset/8ca230890525/ Log: merge default diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -19,12 +19,12 @@ section * Write them in pure python and use direct libffi low-level bindings, See - \_rawffi_ module description. + \_ffi_ module description. * Write them in RPython as mixedmodule_, using *rffi* as bindings. .. _ctypes: #CTypes -.. _\_rawffi: #LibFFI +.. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules CTypes @@ -42,41 +42,50 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. +ctypes call are optimized by the JIT and the resulting machine code contains a +direct call to the target C function. However, due to the very dynamic nature +of ctypes, some overhead over a bare C call is still present, in particular to +check/convert the types of the parameters. Moreover, even if most calls are +optimized, some cannot and thus need to follow the slow path, not optimized by +the JIT. + .. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure +.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html Pros ---- -Stable, CPython-compatible API +Stable, CPython-compatible API. Most calls are fast, optimized by JIT. Cons ---- -Only pure-python code (slow), problems with platform-dependency (although -we partially solve those). PyPy implementation is now very slow. +Problems with platform-dependency (although we partially solve +those). Although the JIT optimizes ctypes calls, some overhead is still +present. The slow-path is very slow. -_`CPython ctypes`: http://python.net/crew/theller/ctypes/ LibFFI ====== Mostly in order to be able to write a ctypes module, we developed a very -low-level libffi bindings. (libffi is a C-level library for dynamic calling, +low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling, which is used by CPython ctypes). This library provides stable and usable API, although it's API is a very low-level one. It does not contain any -magic. +magic. It is also optimized by the JIT, but has much less overhead than ctypes. Pros ---- -Works. Combines disadvantages of using ctypes with disadvantages of -using mixed modules. Probably more suitable for a delicate code -where ctypes magic goes in a way. +It Works. Probably more suitable for a delicate code where ctypes magic goes +in a way. All calls are optimized by the JIT, there is no slow path as in +ctypes. Cons ---- -Slow. CPython-incompatible API, very rough and low-level +It combines disadvantages of using ctypes with disadvantages of using mixed +modules. CPython-incompatible API, very rough and low-level. Mixed Modules ============= @@ -87,15 +96,15 @@ * a mixed module needs to be written in RPython, which is far more complicated than Python (XXX link) -* due to lack of separate compilation (as of April 2008), each +* due to lack of separate compilation (as of July 2011), each compilation-check requires to recompile whole PyPy python interpreter, which takes 0.5-1h. We plan to solve this at some point in near future. * although rpython is a garbage-collected language, the border between C and RPython needs to be managed by hand (each object that goes into the - C level must be explicitly freed) XXX we try to solve this + C level must be explicitly freed). -Some document is available `here`_ +Some documentation is available `here`_ .. _`here`: rffi.html diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -596,12 +596,16 @@ standard_box = self.metainterp.virtualizable_boxes[-1] if standard_box is box: return False + if box in self.metainterp.nonstandard_virtualizables: + return True eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None, box, standard_box) eqbox = self.implement_guard_value(pc, eqbox) isstandard = eqbox.getint() if isstandard: self.metainterp.replace_box(box, standard_box) + else: + self.metainterp.nonstandard_virtualizables[box] = None return not isstandard def _get_virtualizable_field_index(self, fielddescr): @@ -1456,6 +1460,8 @@ self.call_pure_results = args_dict_box() # contains boxes where the class is already known self.known_class_boxes = {} + # contains frame boxes that are not virtualizables + self.nonstandard_virtualizables = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1797,6 +1803,7 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} + self.nonstandard_virtualizables = {} # XXX maybe not needed? duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2381,7 +2381,7 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? - def test_retrace_ending_up_retrazing_another_loop(self): + def test_retrace_ending_up_retracing_another_loop(self): myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) bytecode = "0+sI0+SI" diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -1133,6 +1133,7 @@ res = self.meta_interp(f, [10]) assert res == 55 self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True) + self.check_history(ptr_eq=2) def test_virtual_child_frame_with_arrays(self): myjitdriver = JitDriver(greens = [], reds = ['frame'], diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py --- a/pypy/module/__builtin__/compiling.py +++ b/pypy/module/__builtin__/compiling.py @@ -5,7 +5,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError from pypy.interpreter.astcompiler import consts, ast -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec @unwrap_spec(filename=str, mode=str, flags=int, dont_inherit=int) def compile(space, w_source, filename, mode, flags=0, dont_inherit=0): diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py --- a/pypy/module/__builtin__/descriptor.py +++ b/pypy/module/__builtin__/descriptor.py @@ -1,12 +1,10 @@ - -from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.function import StaticMethod, ClassMethod from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.descroperation import object_getattribute, object_setattr -from pypy.interpreter.function import StaticMethod, ClassMethod -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \ - descr_set_dict, interp_attrproperty_w, generic_new_descr +from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w, + generic_new_descr) +from pypy.objspace.descroperation import object_getattribute class W_Super(Wrappable): def __init__(self, space, w_starttype, w_objtype, w_self): diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -4,13 +4,12 @@ """ from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import NoneNotWrapped, applevel +from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.objectmodel import specialize -from inspect import getsource, getfile from pypy.rlib.rbigint import rbigint @@ -662,7 +661,6 @@ def descr_reduce(self): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns space = self.space w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -1,11 +1,9 @@ import new from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import NoneNotWrapped, applevel, interp2app +from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict -from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, descr_set_dict from pypy.rlib.objectmodel import compute_identity_hash from pypy.rlib.debug import make_sure_not_resized from pypy.rlib import jit diff --git a/pypy/module/__builtin__/interp_memoryview.py b/pypy/module/__builtin__/interp_memoryview.py --- a/pypy/module/__builtin__/interp_memoryview.py +++ b/pypy/module/__builtin__/interp_memoryview.py @@ -2,7 +2,7 @@ Implementation of the 'buffer' and 'memoryview' types. """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter import gateway, buffer +from pypy.interpreter import buffer from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -4,12 +4,10 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.runicode import UNICHR from pypy.rlib.rfloat import isnan, isinf, round_double from pypy.rlib import rfloat -import math import __builtin__ NoneNotWrapped = gateway.NoneNotWrapped diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,5 +1,4 @@ -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib import debug, jit diff --git a/pypy/module/__pypy__/interp_identitydict.py b/pypy/module/__pypy__/interp_identitydict.py --- a/pypy/module/__pypy__/interp_identitydict.py +++ b/pypy/module/__pypy__/interp_identitydict.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app from pypy.interpreter.baseobjspace import Wrappable class W_IdentityDict(Wrappable): diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.objectmodel import we_are_translated class CodecState(object): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -1,9 +1,8 @@ -import sys -from pypy.interpreter.baseobjspace import Wrappable, Arguments +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, \ operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi @@ -16,7 +15,7 @@ class W_FFIType(Wrappable): _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to'] - + def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None): self.name = name self.ffitype = ffitype @@ -83,7 +82,6 @@ def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P types = [ # note: most of the type name directly come from the C equivalent, # with the exception of bytes: in C, ubyte and char are equivalent, @@ -161,7 +159,7 @@ class W_FuncPtr(Wrappable): _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype'] - + def __init__(self, func, argtypes_w, w_restype): self.func = func self.argtypes_w = argtypes_w @@ -207,7 +205,7 @@ argchain.arg_singlefloat(space.float_w(w_arg)) elif w_argtype.is_struct(): # arg_raw directly takes value to put inside ll_args - w_arg = space.interp_w(W_StructureInstance, w_arg) + w_arg = space.interp_w(W_StructureInstance, w_arg) ptrval = w_arg.ll_buffer argchain.arg_raw(ptrval) else: @@ -404,7 +402,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + return W_FuncPtr(func, argtypes_w, w_restype) @unwrap_spec(name=str) diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,12 +3,10 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.gateway import ObjSpace -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -import os def wrap_streamerror(space, e, w_filename=None): if isinstance(e, streamio.StreamError): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -4,7 +4,6 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.buffer import RWBuffer -from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstring import StringBuilder from pypy.rlib.rarithmetic import r_longlong, intmask from pypy.tool.sourcetools import func_renamer diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py --- a/pypy/module/_io/interp_fileio.py +++ b/pypy/module/_io/interp_fileio.py @@ -1,5 +1,4 @@ -from pypy.interpreter.typedef import ( - TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty) +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 from pypy.rlib.rarithmetic import r_longlong diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -6,7 +6,6 @@ TypeDef, interp_attrproperty, generic_new_descr) from pypy.module.exceptions.interp_exceptions import W_IOError from pypy.module._io.interp_fileio import W_FileIO -from pypy.module._io.interp_iobase import W_IOBase from pypy.module._io.interp_textio import W_TextIOWrapper from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -4,7 +4,7 @@ generic_new_descr) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint from pypy.rlib.rbigint import rbigint from pypy.rlib.rstring import UnicodeBuilder diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py --- a/pypy/module/_locale/interp_locale.py +++ b/pypy/module/_locale/interp_locale.py @@ -1,4 +1,3 @@ -from pypy.rpython.tool import rffi_platform as platform from pypy.rlib import rposix from pypy.rlib.rarithmetic import intmask diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -2,12 +2,10 @@ """ The ffi for rpython, need to be imported for side effects """ -import sys from pypy.rpython.lltypesystem import rffi from pypy.rpython.lltypesystem import lltype from pypy.rpython.tool import rffi_platform from pypy.rpython.extfunc import register_external -from pypy.rpython.extregistry import ExtRegistryEntry from pypy.module._minimal_curses import interp_curses from pypy.translator.tool.cbuild import ExternalCompilationInfo @@ -82,7 +80,7 @@ return res finally: rffi.free_charp(ll_cap) - + register_external(interp_curses._curses_tigetstr, [str], str, export_name='_curses.tigetstr', llimpl=tigetstr_llimpl) diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -1,4 +1,4 @@ -import py, sys +import py from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -4,7 +4,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import ( OperationError, wrap_oserror, operationerrfmt) -from pypy.rpython.lltypesystem import rffi, lltype, llmemory +from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll import sys diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -15,7 +15,6 @@ if sys.platform == 'win32': from pypy.rlib import rwin32 - from pypy.interpreter.error import wrap_windowserror from pypy.module._multiprocessing.interp_win32 import ( handle_w, _GetTickCount) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -1,4 +1,4 @@ -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError from pypy.interpreter.nestedscope import Cell from pypy.interpreter.pycode import PyCode from pypy.interpreter.function import Function, Method @@ -8,7 +8,6 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec -from pypy.objspace.std.dicttype import dictiter_typedef from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject @@ -79,7 +78,7 @@ try: return gateway.BuiltinCode.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin code: "+ identifier)) @@ -89,7 +88,7 @@ try: return function.Function.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin function: "+ identifier)) diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,10 +2,10 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rpython.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import get_elem, push_elem +from pypy.module._rawffi.array import push_elem from pypy.module._rawffi.structure import W_Structure -from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \ - wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes +from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, + unwrap_value, unpack_argshapes) from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL from pypy.rlib.clibffi import ffi_type_void from pypy.rlib import rweakref diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -1,7 +1,6 @@ -import sys from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib.clibffi import * @@ -15,7 +14,7 @@ from pypy.rlib import rwin32 from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.tracker import tracker TYPEMAP = { diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py --- a/pypy/module/_socket/interp_func.py +++ b/pypy/module/_socket/interp_func.py @@ -1,9 +1,8 @@ -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._socket.interp_socket import converted_error, W_RSocket from pypy.rlib import rsocket from pypy.rlib.rsocket import SocketError -from pypy.rlib.rarithmetic import r_uint -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError def gethostname(space): """gethostname() -> string diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,7 +1,7 @@ from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError -from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -11,7 +11,6 @@ from pypy.module._socket import interp_socket -import sys ## user defined constants X509_NAME_MAXLEN = 256 @@ -131,13 +130,13 @@ self._issuer = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN, flavor='raw') self._issuer[0] = '\0' self.shutdown_seen_zero = False - + def server(self): return self.space.wrap(rffi.charp2str(self._server)) - + def issuer(self): return self.space.wrap(rffi.charp2str(self._issuer)) - + def __del__(self): if self.peer_cert: libssl_X509_free(self.peer_cert) @@ -147,7 +146,7 @@ libssl_SSL_CTX_free(self.ctx) lltype.free(self._server, flavor='raw') lltype.free(self._issuer, flavor='raw') - + @unwrap_spec(data='bufferstr') def write(self, data): """write(s) -> len @@ -230,10 +229,10 @@ raw_buf, gc_buf = rffi.alloc_buffer(num_bytes) while True: err = 0 - + count = libssl_SSL_read(self.ssl, raw_buf, num_bytes) err = libssl_SSL_get_error(self.ssl, count) - + if err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout(self.space, self.w_socket, False) @@ -245,17 +244,17 @@ return self.space.wrap("") else: sockstate = SOCKET_OPERATION_OK - + if sockstate == SOCKET_HAS_TIMED_OUT: raise ssl_error(self.space, "The read operation timed out") elif sockstate == SOCKET_IS_NONBLOCKING: break - + if err == SSL_ERROR_WANT_READ or err == SSL_ERROR_WANT_WRITE: continue else: break - + if count <= 0: raise _ssl_seterror(self.space, self, count) @@ -351,7 +350,7 @@ self.shutdown_seen_zero = True continue - # Possibly retry shutdown until timeout or failure + # Possibly retry shutdown until timeout or failure ssl_err = libssl_SSL_get_error(self.ssl, ret) if ssl_err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout( @@ -397,7 +396,7 @@ else: w_proto = space.w_None - bits = libssl_SSL_CIPHER_get_bits(current, + bits = libssl_SSL_CIPHER_get_bits(current, lltype.nullptr(rffi.INTP.TO)) w_bits = space.newint(bits) @@ -552,7 +551,7 @@ ext = libssl_X509_get_ext(certificate, i) method = libssl_X509V3_EXT_get(ext) if not method: - raise ssl_error(space, + raise ssl_error(space, "No method for internalizing subjectAltName!'") with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr: @@ -858,7 +857,7 @@ cert = libssl_BIO_new(libssl_BIO_s_file()) if not cert: raise ssl_error(space, "Can't malloc memory to read file") - + try: if libssl_BIO_read_filename(cert, filename) <= 0: raise ssl_error(space, "Can't open file") @@ -873,7 +872,7 @@ libssl_X509_free(x) finally: libssl_BIO_free(cert) - + # this function is needed to perform locking on shared data # structures. (Note that OpenSSL uses a number of global data # structures that will be implicitly shared whenever multiple threads diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -15,13 +15,10 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import StaticMethod from pypy.module._stackless.stackless_flags import StacklessFlags from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit @@ -38,7 +35,7 @@ self.costate = costate if not space.is_true(space.callable(w_obj)): raise operationerrfmt( - space.w_TypeError, + space.w_TypeError, "'%s' object is not callable", space.type(w_obj).getname(space)) self.w_func = w_obj @@ -65,7 +62,7 @@ # Should be moved to interp_stackless.py if it's ever implemented... Currently # used by pypy/lib/stackless.py. -W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, +W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, """Tasklet killed manually.""") class AppCoroutine(Coroutine): # XXX, StacklessFlags): @@ -90,7 +87,7 @@ def _get_state(space): return space.fromcache(AppCoState) _get_state = staticmethod(_get_state) - + def w_bind(self, w_func, __args__): space = self.space if self.frame is not None: @@ -127,7 +124,7 @@ w_excvalue = operror.get_w_value(space) w_exctraceback = operror.get_traceback() w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback]) - + if w_exctype is self.costate.w_CoroutineExit: self.coroutine_exit = True else: @@ -146,22 +143,22 @@ def w_kill(self): self.kill() - + def w_throw(self, w_type, w_value=None, w_traceback=None): space = self.space operror = OperationError(w_type, w_value) operror.normalize_exception(space) - + if not space.is_w(w_traceback, space.w_None): from pypy.interpreter import pytraceback tb = space.interpclass_w(w_traceback) - if tb is None or not space.is_true(space.isinstance(tb, + if tb is None or not space.is_true(space.isinstance(tb, space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) operror.set_traceback(tb) - + self._kill(operror) def _userdel(self): @@ -280,7 +277,7 @@ assert isinstance(w_klass, W_TypeObject) old_flag = w_klass.flag_heaptype w_klass.flag_heaptype = True - + space.appexec([w_klass, space.wrap(funcname)], """ (klass, funcname): func = getattr(klass, funcname) @@ -332,23 +329,23 @@ # Exporting new exception to space self.w_CoroutineExit = space.gettypefor(W_CoroutineExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('CoroutineExit'), - self.w_CoroutineExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('CoroutineExit'), + space.exceptions_module.w_dict, + space.new_interned_str('CoroutineExit'), self.w_CoroutineExit) - + space.setitem(space.builtin.w_dict, + space.new_interned_str('CoroutineExit'), + self.w_CoroutineExit) + # Should be moved to interp_stackless.py if it's ever implemented... self.w_TaskletExit = space.gettypefor(W_TaskletExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - + space.exceptions_module.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + space.setitem(space.builtin.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + def post_install(self): self.current = self.main = AppCoroutine(self.space, state=self) self.main.subctx.clear_framestack() # wack @@ -378,7 +375,7 @@ instr = frame.last_instr opcode = ord(code[instr]) map = pythonopcode.opmap - call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], + call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] assert opcode in call_ops instr += 1 diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py --- a/pypy/module/_stackless/interp_stackless.py +++ b/pypy/module/_stackless/interp_stackless.py @@ -1,9 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError -from pypy.rlib.rarithmetic import intmask import os diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py --- a/pypy/module/_stackless/rclonable.py +++ b/pypy/module/_stackless/rclonable.py @@ -1,7 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.rlib.objectmodel import we_are_translated -from pypy.interpreter.error import OperationError class InterpClonableMixin: @@ -76,7 +75,7 @@ if not isinstance(current, InterpClonableCoroutine): raise RuntimeError("fork() in a non-clonable coroutine") thunk = ForkThunk(current) - coro_fork = InterpClonableCoroutine() + coro_fork = InterpClonableCoroutine() coro_fork.bind(thunk) coro_fork.switch() # we resume here twice. The following would need explanations about diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,9 +1,8 @@ import py -from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.interpreter.typedef import GetSetProperty, TypeDef +from pypy.interpreter.typedef import TypeDef from pypy.rlib import jit import weakref diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -1,6 +1,5 @@ from __future__ import with_statement from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError, wrap_windowserror diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,10 +1,9 @@ from __future__ import with_statement -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object from pypy.objspace.std.multimethod import FailedToImplement diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -4,9 +4,8 @@ from pypy.rpython.lltypesystem import lltype from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.rlib.streamio import Stream from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform as compiler @@ -67,7 +66,7 @@ 'BZ_OUTBUFF_FULL', 'BZ_CONFIG_ERROR'] for name in constant_names: setattr(CConfig, name, platform.DefinedConstantInteger(name)) - + class cConfig(object): pass for k, v in platform.configure(CConfig).items(): @@ -100,7 +99,7 @@ SMALLCHUNK = 8192 else: SMALLCHUNK = BUFSIZ - + if rffi.sizeof(rffi.INT) > 4: BIGCHUNK = 512 * 32 else: @@ -505,7 +504,7 @@ self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self._init_bz2comp(compresslevel) - + def _init_bz2comp(self, compresslevel): if compresslevel < 1 or compresslevel > 9: raise OperationError(self.space.w_ValueError, @@ -514,13 +513,13 @@ bzerror = intmask(BZ2_bzCompressInit(self.bzs, compresslevel, 0, 0)) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzCompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') - + @unwrap_spec(data='bufferstr') def compress(self, data): """compress(data) -> string @@ -529,12 +528,12 @@ compressed data whenever possible. When you've finished providing data to compress, call the flush() method to finish the compression process, and return what is left in the internal buffers.""" - + datasize = len(data) - + if datasize == 0: return self.space.wrap("") - + if not self.running: raise OperationError(self.space.w_ValueError, self.space.wrap("this object was already flushed")) @@ -562,7 +561,7 @@ res = out.make_result_string() return self.space.wrap(res) - + def flush(self): if not self.running: raise OperationError(self.space.w_ValueError, @@ -576,7 +575,7 @@ break elif bzerror != BZ_FINISH_OK: _catch_bz2_error(self.space, bzerror) - + if rffi.getintfield(self.bzs, 'c_avail_out') == 0: out.prepare_next_chunk() @@ -603,23 +602,23 @@ Create a new decompressor object. This object may be used to decompress data sequentially. If you want to decompress data in one shot, use the decompress() function instead.""" - + def __init__(self, space): self.space = space self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self.unused_data = "" - + self._init_bz2decomp() - + def _init_bz2decomp(self): bzerror = BZ2_bzDecompressInit(self.bzs, 0, 0) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzDecompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') @@ -687,7 +686,7 @@ Compress data in one shot. If you want to compress data sequentially, use an instance of BZ2Compressor instead. The compresslevel parameter, if given, must be a number between 1 and 9.""" - + if compresslevel < 1 or compresslevel > 9: raise OperationError(space.w_ValueError, space.wrap("compresslevel must be between 1 and 9")) @@ -731,7 +730,7 @@ Decompress data in one shot. If you want to decompress data sequentially, use an instance of BZ2Decompressor instead.""" - + in_bufsize = len(data) if in_bufsize == 0: return space.wrap("") diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -1,4 +1,3 @@ -import sys from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py --- a/pypy/module/cmath/interp_cmath.py +++ b/pypy/module/cmath/interp_cmath.py @@ -5,7 +5,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import NoneNotWrapped -from pypy.module.cmath import Module, names_and_docstrings +from pypy.module.cmath import names_and_docstrings from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG from pypy.module.cmath.constant import M_LN2, M_LN10 diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py --- a/pypy/module/cpyext/cdatetime.py +++ b/pypy/module/cpyext/cdatetime.py @@ -1,8 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib.objectmodel import we_are_translated -from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef -from pypy.module.cpyext.api import ( - cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields) +from pypy.module.cpyext.pyobject import PyObject, make_ref +from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct, + PyObjectFields) from pypy.module.cpyext.import_ import PyImport_Import from pypy.module.cpyext.typeobject import PyTypeObjectPtr from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py --- a/pypy/module/cpyext/complexobject.py +++ b/pypy/module/cpyext/complexobject.py @@ -1,7 +1,6 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.module.cpyext.api import ( cpython_api, cpython_struct, PyObject, build_type_checkers) -from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.floatobject import PyFloat_AsDouble from pypy.objspace.std.complexobject import W_ComplexObject from pypy.interpreter.error import OperationError diff --git a/pypy/module/crypt/interp_crypt.py b/pypy/module/crypt/interp_crypt.py --- a/pypy/module/crypt/interp_crypt.py +++ b/pypy/module/crypt/interp_crypt.py @@ -1,6 +1,5 @@ -from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.rpython.lltypesystem import rffi, lltype +from pypy.rpython.lltypesystem import rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo import sys @@ -22,4 +21,4 @@ if not res: return space.w_None str_res = rffi.charp2str(res) - return space.wrap(str_res) + return space.wrap(str_res) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -73,9 +73,8 @@ """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w,\ - GetSetProperty, interp_attrproperty, descr_get_dict, descr_set_dict,\ - descr_del_dict +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict, + descr_set_dict, descr_del_dict) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError from pypy.rlib import rwin32 diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -11,9 +11,8 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.eval import Code from pypy.interpreter.pycode import PyCode -from pypy.rlib import streamio, jit, rposix +from pypy.rlib import streamio, jit from pypy.rlib.streamio import StreamErrors -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -3,9 +3,9 @@ from pypy.rlib import streamio from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.module import Module -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import struct + def get_suffixes(space): w = space.wrap diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,7 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.rarithmetic import ovfcheck class W_Count(Wrappable): @@ -87,7 +86,7 @@ def __init__(self, space, w_obj, w_times): self.space = space self.w_obj = w_obj - + if space.is_w(w_times, space.w_None): self.counting = False self.count = 0 @@ -181,7 +180,7 @@ long as the predicate is true. Equivalent to : - + def takewhile(predicate, iterable): for x in iterable: if predicate(x): @@ -316,7 +315,7 @@ None, return the items that are false. Equivalent to : - + def ifilterfalse(predicate, iterable): if predicate is None: predicate = bool @@ -570,7 +569,7 @@ yield tuple(args) else: yield function(*args) - + """) @@ -728,9 +727,9 @@ __doc__ = """Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely. - + Equivalent to : - + def cycle(iterable): saved = [] for element in iterable: @@ -738,7 +737,7 @@ saved.append(element) while saved: for element in saved: - yield element + yield element """) class W_StarMap(Wrappable): @@ -778,7 +777,7 @@ def starmap(function, iterable): iterable = iter(iterable) while True: - yield function(*iterable.next()) + yield function(*iterable.next()) """) @@ -788,15 +787,15 @@ Note : once tee() has made a split, the original iterable should not be used anywhere else; otherwise, the iterable could get advanced without the tee objects being informed. - + Note : this member of the toolkit may require significant auxiliary storage (depending on how much temporary data needs to be stored). In general, if one iterator is going to use most or all of the data before the other iterator, it is faster to use list() instead of tee() - + Equivalent to : - + def tee(iterable, n=2): def gen(next, data={}, cnt=[0]): for i in count(): @@ -888,7 +887,7 @@ self.exhausted = False self.started = False # new_group - new group not started yet, next should not skip any items - self.new_group = True + self.new_group = True self.w_lookahead = self.space.w_None self.w_key = self.space.w_None diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -1,10 +1,8 @@ -from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask from pypy.rlib import rstackovf from pypy.module._file.interp_file import W_File -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import sys + Py_MARSHAL_VERSION = 2 diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,4 +1,4 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,7 +1,7 @@ import math -from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array +from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, + convert_to_array) from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py --- a/pypy/module/mmap/interp_mmap.py +++ b/pypy/module/mmap/interp_mmap.py @@ -1,21 +1,16 @@ -from pypy.rpython.tool import rffi_platform -from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped from pypy.rlib import rmmap from pypy.rlib.rmmap import RValueError, RTypeError, ROverflowError -import sys -import os -import platform -import stat + class W_MMap(Wrappable): def __init__(self, space, mmap_obj): self.space = space self.mmap = mmap_obj - + def close(self): self.mmap.close() diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -15,7 +15,6 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap -from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant from pypy.jit.metainterp.resoperation import rop from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes @@ -66,7 +65,7 @@ def on_compile(self, logger, looptoken, operations, type, next_instr, is_being_profiled, ll_pycode): from pypy.rpython.annlowlevel import cast_base_ptr_to_instance - + space = self.space cache = space.fromcache(Cache) if cache.in_recursion: @@ -170,7 +169,7 @@ # ____________________________________________________________ # -# Public interface +# Public interface def set_param(space, __args__): '''Configure the tunable JIT parameters. @@ -212,7 +211,7 @@ class Cache(object): in_recursion = False - + def __init__(self, space): self.w_compile_hook = space.w_None diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -1,9 +1,9 @@ from pypy.interpreter.typedef import TypeDef, interp_attrproperty -from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import unwrap_spec, interp2app from pypy.interpreter.pycode import PyCode -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.lltypesystem.rclass import OBJECT diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py --- a/pypy/module/rctime/interp_time.py +++ b/pypy/module/rctime/interp_time.py @@ -6,7 +6,6 @@ from pypy.rlib.rarithmetic import ovfcheck_float_to_int from pypy.rlib import rposix from pypy.translator.tool.cbuild import ExternalCompilationInfo -import math import os import sys import time as pytime @@ -102,7 +101,7 @@ CLOCKS_PER_SEC = platform.ConstantInteger("CLOCKS_PER_SEC") clock_t = platform.SimpleType("clock_t", rffi.ULONG) has_gettimeofday = platform.Has('gettimeofday') - + if _POSIX: calling_conv = 'c' CConfig.timeval = platform.Struct("struct timeval", @@ -235,7 +234,7 @@ _set_module_object(space, "timezone", space.wrap(timezone)) _set_module_object(space, 'daylight', space.wrap(daylight)) - tzname_w = [space.wrap(tzname[0]), space.wrap(tzname[1])] + tzname_w = [space.wrap(tzname[0]), space.wrap(tzname[1])] _set_module_object(space, 'tzname', space.newtuple(tzname_w)) _set_module_object(space, 'altzone', space.wrap(altzone)) @@ -310,7 +309,7 @@ space.wrap((rffi.getintfield(t, 'c_tm_wday') + 6) % 7), # want monday == 0 space.wrap(rffi.getintfield(t, 'c_tm_yday') + 1), # want january, 1 == 1 space.wrap(rffi.getintfield(t, 'c_tm_isdst'))] - + w_struct_time = _get_module_object(space, 'struct_time') w_time_tuple = space.newtuple(time_tuple) return space.call_function(w_struct_time, w_time_tuple) @@ -330,7 +329,7 @@ tup_w = space.fixedview(w_tup) if len(tup_w) != 9: - raise operationerrfmt(space.w_TypeError, + raise operationerrfmt(space.w_TypeError, "argument must be sequence of " "length 9, not %d", len(tup_w)) @@ -359,7 +358,7 @@ w_accept2dyear = _get_module_object(space, "accept2dyear") accept2dyear = space.int_w(w_accept2dyear) - + if y < 1900: if not accept2dyear: raise OperationError(space.w_ValueError, @@ -392,7 +391,7 @@ Return the current time in seconds since the Epoch. Fractions of a second may be present if the system clock provides them.""" - + secs = pytime.time() return space.wrap(secs) @@ -420,7 +419,7 @@ not present, current time as returned by localtime() is used.""" seconds = _get_inttime(space, w_seconds) - + t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw') t_ref[0] = seconds p = c_ctime(t_ref) @@ -444,7 +443,7 @@ if not p: raise OperationError(space.w_ValueError, space.wrap("unconvertible time")) - + return space.wrap(rffi.charp2str(p)[:-1]) # get rid of new line def gmtime(space, w_seconds=None): @@ -462,7 +461,7 @@ t_ref[0] = seconds p = c_gmtime(t_ref) lltype.free(t_ref, flavor='raw') - + if not p: raise OperationError(space.w_ValueError, space.wrap(_get_error_msg())) return _tm_to_tuple(space, p) @@ -479,7 +478,7 @@ t_ref[0] = seconds p = c_localtime(t_ref) lltype.free(t_ref, flavor='raw') - + if not p: raise OperationError(space.w_ValueError, space.wrap(_get_error_msg())) return _tm_to_tuple(space, p) @@ -524,7 +523,7 @@ See the library reference manual for formatting codes. When the time tuple is not present, current time as returned by localtime() is used.""" buf_value = _gettmarg(space, w_tup) - + # Checks added to make sure strftime() does not crash Python by # indexing blindly into some array for a textual representation # by some bad index (fixes bug #897625). diff --git a/pypy/module/select/interp_select.py b/pypy/module/select/interp_select.py --- a/pypy/module/select/interp_select.py +++ b/pypy/module/select/interp_select.py @@ -1,9 +1,7 @@ -import math from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import ( - OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.rlib import rpoll import errno @@ -122,7 +120,7 @@ w_errortype = space.fromcache(Cache).w_error raise OperationError(w_errortype, space.newtuple([ space.wrap(s.errno), space.wrap(s.get_msg())])) - + return space.newtuple([ space.newlist([iwtd_d[i] for i in iwtd]), space.newlist([owtd_d[i] for i in owtd]), diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py --- a/pypy/module/struct/formatiterator.py +++ b/pypy/module/struct/formatiterator.py @@ -1,11 +1,10 @@ - from pypy.interpreter.error import OperationError from pypy.rlib.objectmodel import specialize from pypy.rlib.rstruct.error import StructError from pypy.rlib.rstruct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT -from pypy.rlib.rstruct.formatiterator import (FormatIterator, - CalcSizeFormatIterator) +from pypy.rlib.rstruct.formatiterator import FormatIterator + class PackFormatIterator(FormatIterator): diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py --- a/pypy/module/struct/interp_struct.py +++ b/pypy/module/struct/interp_struct.py @@ -1,10 +1,7 @@ from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.module.struct.formatiterator import PackFormatIterator, UnpackFormatIterator from pypy.rlib.rstruct.error import StructError -from pypy.module.struct.formatiterator import CalcSizeFormatIterator -from pypy.module.struct.formatiterator import PackFormatIterator -from pypy.module.struct.formatiterator import UnpackFormatIterator - +from pypy.rlib.rstruct.formatiterator import CalcSizeFormatIterator @unwrap_spec(format=str) def calcsize(space, format): diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -1,9 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype, llmemory -from pypy.rpython.tool import rffi_platform as platform from pypy.translator.tool.cbuild import ExternalCompilationInfo -import py, os -from pypy.rpython.extregistry import ExtRegistryEntry +import py from pypy.rlib import jit from pypy.rlib.debug import ll_assert from pypy.rlib.objectmodel import we_are_translated diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py --- a/pypy/module/thread/os_local.py +++ b/pypy/module/thread/os_local.py @@ -1,9 +1,7 @@ from pypy.module.thread import ll_thread as thread -from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp2app -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict +from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty, + descr_get_dict) class Local(Wrappable): diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py --- a/pypy/module/thread/os_thread.py +++ b/pypy/module/thread/os_thread.py @@ -6,7 +6,6 @@ from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import unwrap_spec, NoneNotWrapped, Arguments -from pypy.rlib.objectmodel import free_non_gc_object # Here are the steps performed to start a new thread: # @@ -167,14 +166,14 @@ when the function raises an unhandled exception; a stack trace will be printed unless the exception is SystemExit.""" setup_threads(space) - if not space.is_true(space.isinstance(w_args, space.w_tuple)): - raise OperationError(space.w_TypeError, - space.wrap("2nd arg must be a tuple")) - if w_kwargs is not None and not space.is_true(space.isinstance(w_kwargs, space.w_dict)): - raise OperationError(space.w_TypeError, - space.wrap("optional 3rd arg must be a dictionary")) + if not space.is_true(space.isinstance(w_args, space.w_tuple)): + raise OperationError(space.w_TypeError, + space.wrap("2nd arg must be a tuple")) + if w_kwargs is not None and not space.is_true(space.isinstance(w_kwargs, space.w_dict)): + raise OperationError(space.w_TypeError, + space.wrap("optional 3rd arg must be a dictionary")) if not space.is_true(space.callable(w_callable)): - raise OperationError(space.w_TypeError, + raise OperationError(space.w_TypeError, space.wrap("first arg must be callable")) args = Arguments.frompacked(space, w_args, w_kwargs) diff --git a/pypy/module/unicodedata/generate_unicodedb.py b/pypy/module/unicodedata/generate_unicodedb.py --- a/pypy/module/unicodedata/generate_unicodedb.py +++ b/pypy/module/unicodedata/generate_unicodedb.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -import pprint - MAXUNICODE = 0x10FFFF # the value of sys.maxunicode of wide Python builds MANDATORY_LINE_BREAKS = ["BK", "CR", "LF", "NL"] # line break categories @@ -66,16 +64,16 @@ self.upper = int(data[12], 16) self.lower = None if data[13]: - self.lower = int(data[13], 16) + self.lower = int(data[13], 16) self.title = None if data[14]: self.title = int(data[14], 16) - + def copy(self): uc = Unicodechar() uc.__dict__.update(self.__dict__) return uc - + def get_compat_decomposition(table, code): if not table[code].decomposition: return [code] @@ -177,13 +175,13 @@ for code in range(len(table)): if table[code] is None: table[code] = defaultChar - + extra_numeric = read_unihan(unihan_file) for code, value in extra_numeric.iteritems(): uc = table[code].copy() uc.numeric = value table[code] = uc - + # Compute full decompositions. for code in range(len(table)): get_canonical_decomposition(table, code) @@ -365,7 +363,7 @@ print >> outfile, '%r: %r,' % (code, name) print >> outfile, '}' - + print >> outfile, '_names_corrected = {' for name, code in sorted(base_mod._orig_names.iteritems()): if name not in names: @@ -389,7 +387,7 @@ print >> outfile, '%r: None,' % name print >> outfile, '}' - + def writeUnicodedata(version, table, outfile, base): if base: print >> outfile, 'import %s as base_mod' % base @@ -406,7 +404,7 @@ cjk_end = 0x9FBB write_character_names(outfile, table, base_mod) - + print >> outfile, ''' _cjk_prefix = "CJK UNIFIED IDEOGRAPH-" _hangul_prefix = 'HANGUL SYLLABLE ' @@ -496,7 +494,7 @@ v_code = vl_code %% len(_hangul_V) return ("HANGUL SYLLABLE " + _hangul_L[l_code] + _hangul_V[v_code] + _hangul_T[t_code]) - + if not base_mod: return lookup_charcode(code) else: @@ -522,7 +520,7 @@ digit[code] = table[code].digit if table[code].numeric is not None: numeric[code] = table[code].numeric - + writeDict(outfile, '_decimal', decimal, base_mod) writeDict(outfile, '_digit', digit, base_mod) writeDict(outfile, '_numeric', numeric, base_mod) @@ -662,11 +660,11 @@ ''' def main(): - import re, sys + import sys from optparse import OptionParser infile = None outfile = sys.stdout - + parser = OptionParser('Usage: %prog [options]') parser.add_option('--base', metavar='FILENAME', help='Base python version (for import)') parser.add_option('--output', metavar='OUTPUT_MODULE', help='Output module (implied py extension)') diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -89,7 +89,7 @@ while asm[asm_index][0] < op.offset: asm_index += 1 end_index = asm_index - while asm[end_index][0] < end: + while asm[end_index][0] < end and end_index < len(asm) - 1: end_index += 1 op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) return loop @@ -343,18 +343,20 @@ addr = int(m.group(1), 16) entry = entry.lower() m = re.search('guard \d+', entry) - addrs[addr] = m.group(0) + name = m.group(0) else: name = entry[:entry.find('(') - 1].lower() - addrs[int(m.group(1), 16)] = name + addr = int(m.group(1), 16) + addrs.setdefault(addr, []).append(name) dumps = {} for entry in extract_category(log, 'jit-backend-dump'): backend, _, dump, _ = entry.split("\n") _, addr, _, data = re.split(" +", dump) backend_name = backend.split(" ")[1] addr = int(addr[1:], 16) - if addr in addrs: - dumps[addrs[addr]] = (backend_name, addr, data) + if addr in addrs and addrs[addr]: + name = addrs[addr].pop(0) # they should come in order + dumps[name] = (backend_name, addr, data) loops = [] for entry in extract_category(log, 'jit-log-opt'): parser = ParserCls(entry, None, {}, 'lltype', None, @@ -369,7 +371,10 @@ name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] - parser.postprocess(loop, backend_tp=bname, backend_dump=dump, - dump_start=start_ofs) + loop.force_asm = (lambda dump=dump, start_ofs=start_ofs, + bname=bname, loop=loop: + parser.postprocess(loop, backend_tp=bname, + backend_dump=dump, + dump_start=start_ofs)) loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest2.log @@ -0,0 +1,301 @@ +[1f5e7f69779] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f7fe75] jit-backend-dump} +[1f5e7f84fc4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f87ac1] jit-backend-dump} +[1f5e7f8a0b4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b08a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f8da6b] jit-backend-dump} +[1f5e7f8f4f6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b13d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f92b83] jit-backend-dump} +[1f5e7f95b99] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 +[1f5e7f988d0] jit-backend-dump} +[1f5e7fa16fb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b28e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 +[1f5e7fa47ac] jit-backend-dump} +[1f5e7fab3a4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 +[1f5e7faf1ca] jit-backend-dump} +[1f5e7fb0813] {jit-backend-counts +[1f5e7fb0f61] jit-backend-counts} +[1f5fd38be3e] {jit-backend +[1f5fe729336] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB30B00C0A897F00004D8B334983C60149BB30B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030300000049BB00B0A007897F000041FFD34440484C3D39030400000049BB00B0A007897F000041FFD34440484C3907070305000000 +[1f5fe73276a] jit-backend-dump} +[1f5fe73438f] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f8907a0b45d to 7f8907a0b4c3 (bootstrap 7f8907a0b3d5) +[1f5fe7369af] jit-backend-addr} +[1f5fe737940] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3e5 +0 50FFFFFF +[1f5fe74b40e] jit-backend-dump} +[1f5fe74c63d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b484 +0 95000000 +[1f5fe74da6a] jit-backend-dump} +[1f5fe74e438] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 9B000000 +[1f5fe74f513] jit-backend-dump} +[1f5fe74fd2e] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b4b7 +0 91000000 +[1f5fe750d8c] jit-backend-dump} +[1f5fe75373f] jit-backend} +[1f5fe755abc] {jit-log-opt-loop +# Loop 0 : loop with 26 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 1) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f5fe92b8af] jit-log-opt-loop} +[1f5fe944ae5] {jit-backend +[1f5fee20651] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b565 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C254010000000049BB38B00C0A897F0000498B0B4883C10149BB38B00C0A897F000049890B4983F8010F85000000004883FE017206813E980700000F85000000004983FA000F850000000049BBA8F0B407897F00004D39DC0F8500000000488B56084881FA102700000F8D000000004989D44883E2024883FA000F85000000004983C403488B1425A0536B024883EA0148891425A0536B024883FA000F8C000000004C89BD70FFFFFF4C89B568FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4D89E749BB5DB4A007897F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DAE9CCFEFFFF49BB00B0A007897F000041FFD321383C343029241D180C08030600000049BB00B0A007897F000041FFD3383C18343029240C08030700000049BB00B0A007897F000041FFD329383C3430241808030800000049BB00B0A007897F000041FFD3383C3034241808030900000049BB00B0A007897F000041FFD3383C183424030A00000049BB00B0A007897F000041FFD3383C34241809030B00000049BB00B0A007897F000041FFD3383C34243107030C000000 +[1f5fee2e673] jit-backend-dump} +[1f5fee2f38d] {jit-backend-addr +Loop 1 ( #9 LOAD_FAST) has address 7f8907a0b631 to 7f8907a0b6f8 (bootstrap 7f8907a0b565) +[1f5fee312e3] jit-backend-addr} +[1f5fee320ed] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b575 +0 50FFFFFF +[1f5fee3e903] jit-backend-dump} +[1f5fee3fbff] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b655 +0 0C010000 +[1f5fee41579] jit-backend-dump} +[1f5fee421af] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b667 +0 17010000 +[1f5fee43835] jit-backend-dump} +[1f5fee44261] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b671 +0 28010000 +[1f5fee457c1] jit-backend-dump} +[1f5fee461a5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b684 +0 2F010000 +[1f5fee475d3] jit-backend-dump} +[1f5fee47f57] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b695 +0 37010000 +[1f5fee4933d] jit-backend-dump} +[1f5fee49cd9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6a6 +0 3D010000 +[1f5fee4b0ad] jit-backend-dump} +[1f5fee4ba4f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6c8 +0 33010000 +[1f5fee4cf61] jit-backend-dump} +[1f5fee4dc45] jit-backend} +[1f5fee4f3a9] {jit-log-opt-loop +# Loop 1 : entry bridge with 31 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10] +debug_merge_point(0, ' #9 LOAD_FAST') ++234: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10] ++244: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10] ++262: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p10] +debug_merge_point(0, ' #12 LOAD_CONST') ++272: guard_value(p3, ConstPtr(ptr14), descr=) [p1, p0, p3, p2, p5, p8, p10] +debug_merge_point(0, ' #15 COMPARE_OP') ++291: i15 = getfield_gc_pure(p8, descr=) ++295: i17 = int_lt(i15, 10000) +guard_true(i17, descr=) [p1, p0, p8, p2, p5] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++308: i19 = int_and(i15, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++315: i20 = int_is_true(i19) +guard_false(i20, descr=) [p1, p0, p2, p5, p8, i19] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++325: i22 = int_add(i15, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++329: i24 = getfield_raw(40588192, descr=) ++337: i26 = int_sub(i24, 1) ++341: setfield_raw(40588192, i26, descr=) ++349: i28 = int_lt(i26, 0) +guard_false(i28, descr=) [p1, p0, p2, p5, i22, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++359: jump(p0, p1, p2, p5, i22, descr=) ++403: --end of the loop-- +[1f60036d952] jit-log-opt-loop} +[1f600719a74] {jit-backend +[1f600759dac] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b817 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB40B00C0A897F00004D8B334983C60149BB40B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF024C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030D00000049BB00B0A007897F000041FFD34440484C3D39030E00000049BB00B0A007897F000041FFD34440484C390707030F000000 +[1f60076fd90] jit-backend-dump} +[1f600770f30] {jit-backend-addr +Loop 2 ( #9 LOAD_FAST) has address 7f8907a0b89f to 7f8907a0b905 (bootstrap 7f8907a0b817) +[1f6007730fc] jit-backend-addr} +[1f600773fde] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b827 +0 50FFFFFF +[1f600775c76] jit-backend-dump} +[1f600776a38] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8c6 +0 95000000 +[1f600778112] jit-backend-dump} +[1f600778b8c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8d7 +0 9B000000 +[1f60077a04a] jit-backend-dump} +[1f60077aa6a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8f9 +0 91000000 +[1f60077bf10] jit-backend-dump} +[1f60077cc24] jit-backend} +[1f60077e094] {jit-log-opt-loop +# Loop 2 : loop with 25 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 2) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f6007a567c] jit-log-opt-loop} +[1f600802cd6] {jit-backend +[1f600862dd8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9b7 +0 488DA50000000049BB48B00C0A897F00004D8B3B4983C70149BB48B00C0A897F00004D893B4D89F74983C6010F80000000004C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C00000000488B0425704F3D01488D5010483B1425784F3D01761A49BB10B2A007897F000041FFD349BB8EB2A007897F000041FFD348C7009807000048891425704F3D014C89700848898550FFFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBA8F0B407897F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00100000048C7C709000000488BB550FFFFFF48C7C30000000048C7C20000000049BB31B6A007897F000041FFE349BB00B0A007897F000041FFD3444039484C3D031000000049BB00B0A007897F000041FFD34440484C39070311000000 +[1f60086ba5a] jit-backend-dump} +[1f60086d36e] {jit-backend-addr +Bridge out of guard 4 has address 7f8907a0b9b7 to 7f8907a0bab1 +[1f60086ffd2] jit-backend-addr} +[1f600870dca] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9ba +0 C0FEFFFF +[1f60087281c] jit-backend-dump} +[1f600873506] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 C8000000 +[1f600874b44] jit-backend-dump} +[1f6008754d4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0ba03 +0 C2000000 +[1f600876956] jit-backend-dump} +[1f600877b1a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 1E050000 +[1f600878f4e] jit-backend-dump} +[1f600884c12] jit-backend} +[1f60088780a] {jit-log-opt-bridge +# bridge out of Guard 4 with 16 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #31 LOAD_FAST') +debug_merge_point(0, ' #34 LOAD_CONST') +debug_merge_point(0, ' #37 INPLACE_ADD') ++37: i7 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i7, p2, p3, i5] +debug_merge_point(0, ' #38 STORE_FAST') +debug_merge_point(0, ' #41 JUMP_ABSOLUTE') ++50: i9 = getfield_raw(40588192, descr=) ++58: i11 = int_sub(i9, 1) ++62: setfield_raw(40588192, i11, descr=) ++70: i13 = int_lt(i11, 0) +guard_false(i13, descr=) [p0, p1, p2, p3, i7, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++80: p16 = new_with_vtable(ConstClass(W_IntObject)) ++143: setfield_gc(p16, i7, descr=) ++147: jump(p1, p0, p2, ConstPtr(ptr17), 0, p3, 1, 9, p16, ConstPtr(ptr21), ConstPtr(ptr22), descr=) ++250: --end of the loop-- +[1f6008aa976] jit-log-opt-bridge} +[1f600912c98] {jit-backend-counts +0:1982 +1:1985 +2:0 +3:1782 +[1f600916544] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -213,11 +213,15 @@ def test_import_log(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) + for loop in loops: + loop.force_asm() assert 'jge' in loops[0].operations[3].asm def test_import_log_2(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest2.log'))) + for loop in loops: + loop.force_asm() assert 'cmp' in loops[1].operations[1].asm # bridge - assert 'cmp' in loops[3].operations[1].asm + assert 'jo' in loops[3].operations[3].asm diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1824,6 +1824,11 @@ __gccallshapes: """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) + print >> output, """\ + #if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits + #endif + """ def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) From noreply at buildbot.pypy.org Sat Jul 16 17:16:33 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 17:16:33 +0200 (CEST) Subject: [pypy-commit] benchmarks default: remove name errors Message-ID: <20110716151633.3636F82962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r124:1beaa1484ca2 Date: 2011-07-16 17:14 +0200 http://bitbucket.org/pypy/benchmarks/changeset/1beaa1484ca2/ Log: remove name errors diff --git a/own/chaos.py b/own/chaos.py --- a/own/chaos.py +++ b/own/chaos.py @@ -29,7 +29,7 @@ def __add__(self, other): if not isinstance(other, GVector): - raise exceptions.ValueError, \ + raise ValueError, \ "Can't add GVector to " + str(type(other)) v = GVector(self.x + other.x, self.y + other.y, self.z + other.z) return v @@ -71,13 +71,13 @@ self.knots = GetKnots(points, degree) else: if len(points) > len(knots) - degree + 1: - raise exceptions.ValueError, "too many control points" + raise ValueError, "too many control points" elif len(points) < len(knots) - degree + 1: - raise exceptions.ValueError, "not enough control points" + raise ValueError, "not enough control points" last = knots[0] for cur in knots[1:]: if cur < last: - raise exceptions.ValueError, \ + raise ValueError, \ "knots not strictly increasing" last = cur self.knots = knots @@ -93,7 +93,7 @@ """Calculates a point of the B-Spline using de Boors Algorithm""" dom = self.GetDomain() if u < dom[0] or u > dom[1]: - raise exceptions.ValueError, "Function value not in domain" + raise ValueError, "Function value not in domain" if u == dom[0]: return self.points[0] if u == dom[1]: From noreply at buildbot.pypy.org Sat Jul 16 17:16:34 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 17:16:34 +0200 (CEST) Subject: [pypy-commit] benchmarks default: improve uploading so we can benchmark pypy against pypy no jit Message-ID: <20110716151634.59C2582962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r125:a8836ad0cec7 Date: 2011-07-16 17:15 +0200 http://bitbucket.org/pypy/benchmarks/changeset/a8836ad0cec7/ Log: improve uploading so we can benchmark pypy against pypy no jit diff --git a/runner.py b/runner.py --- a/runner.py +++ b/runner.py @@ -2,12 +2,30 @@ """ Usage: runner.py """ -import os import json import sys from unladen_swallow import perf import benchmarks import socket + +def perform_upload(pypy_c_path, args, force_host, options, res, revision, + changed=True): + from saveresults import save + project = 'PyPy' + if "--jit" in args: + name = "pypy-c" + else: + name = "pypy-c-jit" + if "psyco.sh" in pypy_c_path: + name = "cpython psyco-profile" + revision = 100 + project = 'cpython' + if force_host is not None: + host = force_host + else: + host = socket.gethostname() + print save(project, revision, res, options, name, host, changed=changed) + def run_and_store(benchmark_set, result_filename, pypy_c_path, revision=0, options='', branch='trunk', args='', upload=False, @@ -36,21 +54,15 @@ })) f.close() if upload: - from saveresults import save - project = 'PyPy' - if "--jit threshold" in args: - name = "pypy-c" + if ',' in args: + argsbase, argschanged = args.split(',') else: - name = "pypy-c-jit" - if "psyco.sh" in pypy_c_path: - name = "cpython psyco-profile" - revision = 100 - project = 'cpython' - if force_host is not None: - host = force_host - else: - host = socket.gethostname() - save(project, revision, res, options, name, host) + argsbase, argschanged = args, args + if 'pypy' in baseline: + perform_upload(pypy_c_path, argsbase, force_host, options, res, + revision, changed=False) + perform_upload(pypy_c_path, argschanged, force_host, options, res, + revision, changed=True) BENCHMARK_SET = ['richards', 'slowspitfire', 'django', 'spambayes', 'rietveld', 'html5lib', 'ai'] diff --git a/saveresults.py b/saveresults.py --- a/saveresults.py +++ b/saveresults.py @@ -8,7 +8,8 @@ SPEEDURL = "http://speed.pypy.org/" -def save(project, revision, results, options, interpreter, host, testing=False): +def save(project, revision, results, options, interpreter, host, testing=True, + changed=True): testparams = [] #Parse data data = {} @@ -20,9 +21,15 @@ results = b[2] value = 0 if res_type == "SimpleComparisonResult": - value = results['changed_time'] + if changed: + value = results['changed_time'] + else: + value = results['base_time'] elif res_type == "ComparisonResult": - value = results['avg_changed'] + if changed: + value = results['avg_changed'] + else: + value = results['avg_base'] else: print("ERROR: result type unknown " + b[1]) return 1 @@ -35,7 +42,10 @@ 'result_value': value, } if res_type == "ComparisonResult": - data['std_dev'] = results['std_changed'] + if changed: + data['std_dev'] = results['std_changed'] + else: + data['std_dev'] = results['std_base'] if testing: testparams.append(data) else: error |= send(data) if error: From noreply at buildbot.pypy.org Sat Jul 16 17:22:40 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 17:22:40 +0200 (CEST) Subject: [pypy-commit] buildbot default: clean up - now we dont benchmark cpython nightly twice Message-ID: <20110716152240.3F8E182962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r528:6717b3a4b6a8 Date: 2011-07-16 17:22 +0200 http://bitbucket.org/pypy/buildbot/changeset/6717b3a4b6a8/ Log: clean up - now we dont benchmark cpython nightly twice diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -288,9 +288,11 @@ self.addStep(Translate(['-Ojit'], [])) pypy_c_rel = "../build/pypy/translator/goal/pypy-c" self.addStep(ShellCmd( - description="run benchmarks on top of pypy-c-jit", + description="run benchmarks on top of pypy-c", command=["python", "runner.py", '--output-filename', 'result.json', '--pypy-c', pypy_c_rel, + '--baseline', pypy_c_rel, + '--args', ',--jit off' '--upload', #'--force-host', 'bigdog', '--revision', WithProperties('%(got_revision)s'), '--branch', WithProperties('%(branch)s')], @@ -301,20 +303,6 @@ self.addStep(transfer.FileUpload(slavesrc="benchmarks/result.json", masterdest=WithProperties(resfile), workdir=".")) - self.addStep(ShellCmd( - description="run benchmarks on top of pypy-c no jit", - command=["python", "runner.py", '--output-filename', 'result.json', - '--pypy-c', '../build/pypy/translator/goal/pypy-c', - '--revision', WithProperties('%(got_revision)s'), - '--upload', #'--force-host', 'bigdog', - '--branch', WithProperties('%(branch)s'), - '--args', ',--jit off'], - workdir='./benchmarks', - haltOnFailure=True)) - resfile = os.path.expanduser("~/bench_results_nojit/%(got_revision)s.json") - self.addStep(transfer.FileUpload(slavesrc="benchmarks/result.json", - masterdest=WithProperties(resfile), - workdir=".")) ## self.addStep(ShellCmd( ## description="run on top of python with psyco", From noreply at buildbot.pypy.org Sat Jul 16 18:22:24 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 18:22:24 +0200 (CEST) Subject: [pypy-commit] buildbot default: grrr, missing coma Message-ID: <20110716162224.8584B82962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r529:f1174e9107a5 Date: 2011-07-16 18:22 +0200 http://bitbucket.org/pypy/buildbot/changeset/f1174e9107a5/ Log: grrr, missing coma diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -292,7 +292,7 @@ command=["python", "runner.py", '--output-filename', 'result.json', '--pypy-c', pypy_c_rel, '--baseline', pypy_c_rel, - '--args', ',--jit off' + '--args', ',--jit off', '--upload', #'--force-host', 'bigdog', '--revision', WithProperties('%(got_revision)s'), '--branch', WithProperties('%(branch)s')], From noreply at buildbot.pypy.org Sat Jul 16 18:38:23 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Sat, 16 Jul 2011 18:38:23 +0200 (CEST) Subject: [pypy-commit] pypy numpy-singledim: Added simple repr and str for ViewArrays Message-ID: <20110716163823.1C1AB82962@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-singledim Changeset: r45673:29e15adb6915 Date: 2011-07-15 18:10 -0600 http://bitbucket.org/pypy/pypy/changeset/29e15adb6915/ Log: Added simple repr and str for ViewArrays diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -341,10 +341,10 @@ return space.wrap(self.find_ndim()) def descr_repr(self, space): - return self.get_concrete().descr_repr(space) + return self.get_concrete()._repr(space) def descr_str(self, space): - return self.get_concrete().descr_str(space) + return self.get_concrete()._str(space) def descr_getitem(self, space, w_idx): # TODO: indexing by tuples and lists @@ -548,6 +548,26 @@ def calc_index(self, item): raise NotImplementedError + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + class SingleDimSlice(ViewArray): _immutable_fields_ = ["start", "stop", "step", "size"] static_signature = Signature() @@ -624,11 +644,11 @@ in range(self.find_size())] return nums - def descr_repr(self, space): + def _repr(self, space): # Simple implementation so that we can see the array. Needs work. return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - def descr_str(self,space): + def _str(self,space): # Simple implementation so that we can see the array. Needs work. return space.wrap("[" + " ".join(self._getnums(True)) + "]") diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -50,6 +50,15 @@ a = zeros(1001) assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + def test_repr_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert repr(b) == "array([1.0, 3.0])" + a = zeros(2002) + b = a[::2] + assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + def test_str(self): from numpy import array, zeros a = array(range(5)) @@ -57,6 +66,15 @@ a = zeros(1001) assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_str_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert str(b) == "[1.0 3.0]" + a = zeros(2002) + b = a[::2] + assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_getitem(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Sat Jul 16 18:38:24 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Sat, 16 Jul 2011 18:38:24 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ndim-size: numpy: added ndim and size attributes. This includes work by Timo. Message-ID: <20110716163824.4705582962@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-ndim-size Changeset: r45674:db28a9352aa2 Date: 2011-07-16 10:38 -0600 http://bitbucket.org/pypy/pypy/changeset/db28a9352aa2/ Log: numpy: added ndim and size attributes. This includes work by Timo. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -244,6 +244,12 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_get_size(self, space): + return space.wrap(self.find_size()) + + def descr_get_ndim(self, space): + return space.wrap(self.find_ndim()) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -287,6 +293,9 @@ def find_size(self): raise ValueError + def find_ndim(self): + raise ValueError + def eval(self, i): return self.float_value @@ -336,6 +345,12 @@ return self.forced_result.find_size() return self._find_size() + def find_ndim(self): + if self.forced_result is not None: + # The result has been computed and sources may be unavailable + return self.forced_result.find_ndim() + return self._find_ndim() + class Call1(VirtualArray): _immutable_fields_ = ["function", "values"] @@ -351,6 +366,9 @@ def _find_size(self): return self.values.find_size() + def _find_ndim(self): + return self.values.find_ndim() + def _eval(self, i): return self.function(self.values.eval(i)) @@ -377,6 +395,13 @@ pass return self.right.find_size() + def _find_ndim(self): + try: + return self.left.find_ndim() + except ValueError: + pass + return self.right.find_ndim() + def _eval(self, i): lhs, rhs = self.left.eval(i), self.right.eval(i) return self.function(lhs, rhs) @@ -426,10 +451,14 @@ self.stop = stop self.step = step self.size = slice_length + self.ndim = 1 def find_size(self): return self.size + def find_ndim(self): + return self.ndim + def calc_index(self, item): return (self.start + item * self.step) @@ -440,6 +469,7 @@ def __init__(self, size): BaseArray.__init__(self) self.size = size + self.ndim = 1 self.storage = lltype.malloc(TP, size, zero=True, flavor='raw', track_allocation=False) # XXX find out why test_zjit explodes with trackign of allocations @@ -450,6 +480,9 @@ def find_size(self): return self.size + def find_ndim(self): + return self.ndim + def eval(self, i): return self.storage[i] @@ -507,6 +540,8 @@ __new__ = interp2app(descr_new_numarray), shape = GetSetProperty(BaseArray.descr_get_shape), + size = GetSetProperty(BaseArray.descr_get_size), + ndim = GetSetProperty(BaseArray.descr_get_ndim), __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -66,6 +66,20 @@ assert len(a) == 5 assert len(a + a) == 5 + def test_ndim(self): + from numpy import array + a = array(range(4)) + assert a.ndim == 1 + assert (a + a).ndim == 1 + assert a[:3].ndim == 1 + + def test_size(self): + from numpy import array + a = array(range(4)) + assert a.size == 4 + assert (a + a).size == 4 + assert a[:3].size == 3 + def test_shape(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Sat Jul 16 18:53:59 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Sat, 16 Jul 2011 18:53:59 +0200 (CEST) Subject: [pypy-commit] pypy numpy-repr-str: numpy: simple implementations of repr and str. includes work by Timo. Message-ID: <20110716165359.E614E82962@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-repr-str Changeset: r45675:9e83042f6f27 Date: 2011-07-16 10:53 -0600 http://bitbucket.org/pypy/pypy/changeset/9e83042f6f27/ Log: numpy: simple implementations of repr and str. includes work by Timo. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -244,6 +244,12 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_repr(self, space): + return self.get_concrete()._repr(space) + + def descr_str(self, space): + return self.get_concrete()._str(space) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -433,6 +439,26 @@ def calc_index(self, item): return (self.start + item * self.step) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + class SingleDimArray(BaseArray): signature = Signature() @@ -470,6 +496,26 @@ def getitem(self, item): return self.storage[item] + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) @@ -527,6 +573,8 @@ __rdiv__ = interp2app(BaseArray.descr_rdiv), __rpow__ = interp2app(BaseArray.descr_rpow), __rmod__ = interp2app(BaseArray.descr_rmod), + __repr__ = interp2app(BaseArray.descr_repr), + __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), sum = interp2app(BaseArray.descr_sum), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -43,6 +43,38 @@ a = array(range(5)) assert a[3] == 3 + def test_repr(self): + from numpy import array, zeros + a = array(range(5)) + assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" + a = zeros(1001) + assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_repr_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert repr(b) == "array([1.0, 3.0])" + a = zeros(2002) + b = a[::2] + assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_str(self): + from numpy import array, zeros + a = array(range(5)) + assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + a = zeros(1001) + assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + + def test_str_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert str(b) == "[1.0 3.0]" + a = zeros(2002) + b = a[::2] + assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_getitem(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Sat Jul 16 19:44:48 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 19:44:48 +0200 (CEST) Subject: [pypy-commit] pypy default: bug in lazy setarrayitem. test and fix Message-ID: <20110716174448.3614F82962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45676:e5d0029d562d Date: 2011-07-16 19:44 +0200 http://bitbucket.org/pypy/pypy/changeset/e5d0029d562d/ Log: bug in lazy setarrayitem. test and fix diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -73,7 +73,7 @@ assert self._lazy_setfield is None self._cached_fields[structvalue] = fieldvalue - def force_lazy_setfield(self, optheap): + def force_lazy_setfield(self, optheap, can_cache=True): op = self._lazy_setfield if op is not None: # This is the way _lazy_setfield is usually reset to None. @@ -83,6 +83,8 @@ self._cached_fields.clear() self._lazy_setfield = None optheap.next_optimization.propagate_forward(op) + if not can_cache: + return # Once it is done, we can put at least one piece of information # back in the cache: the value of this particular structure's # field. @@ -245,13 +247,13 @@ return cf.force_lazy_setfield(self) - def force_lazy_setarrayitem(self, arraydescr): + def force_lazy_setarrayitem(self, arraydescr, can_cache=True): try: submap = self.cached_arrayitems[arraydescr] except KeyError: return for cf in submap.values(): - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes @@ -387,7 +389,7 @@ cf.do_setfield(self, op) else: # variable index, so make sure the lazy setarrayitems are done - self.force_lazy_setarrayitem(op.getdescr()) + self.force_lazy_setarrayitem(op.getdescr(), can_cache=False) # and then emit the operation self.emit_operation(op) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1755,6 +1755,27 @@ """ self.optimize_loop(ops, expected) + def test_duplicate_getarrayitem_after_setarrayitem_bug(self): + ops = """ + [p0, i0, i1] + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i6 = int_add(i0, 1) + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + def test_bug_1(self): ops = """ [i0, p1] From noreply at buildbot.pypy.org Sat Jul 16 20:04:30 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 20:04:30 +0200 (CEST) Subject: [pypy-commit] pypy default: broken test (armin will try to fix it) Message-ID: <20110716180430.42D0D82962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45677:8327f6fea2b2 Date: 2011-07-16 20:03 +0200 http://bitbucket.org/pypy/pypy/changeset/8327f6fea2b2/ Log: broken test (armin will try to fix it) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1776,6 +1776,27 @@ """ self.optimize_loop(ops, expected) + def test_duplicate_getarrayitem_after_setarrayitem_bug2(self): + ops = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + def test_bug_1(self): ops = """ [i0, p1] From noreply at buildbot.pypy.org Sat Jul 16 20:07:49 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 16 Jul 2011 20:07:49 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix the test by always clear()ing _cache_fields if can_cache=False. Message-ID: <20110716180749.9749982962@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45678:e911b2205846 Date: 2011-07-16 20:07 +0200 http://bitbucket.org/pypy/pypy/changeset/e911b2205846/ Log: Fix the test by always clear()ing _cache_fields if can_cache=False. Rewrote some redundant try:except KeyError: code by using the new can_cache=False flag. diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -91,6 +91,8 @@ structvalue = optheap.getvalue(op.getarg(0)) fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) + elif not can_cache: + self._cached_fields.clear() def get_reconstructed(self, optimizer, valuemap): assert self._lazy_setfield is None @@ -204,20 +206,9 @@ for arraydescr in effectinfo.readonly_descrs_arrays: self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: - self.force_lazy_setfield(fielddescr) - try: - cf = self.cached_fields[fielddescr] - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setfield(fielddescr, can_cache=False) for arraydescr in effectinfo.write_descrs_arrays: - self.force_lazy_setarrayitem(arraydescr) - try: - submap = self.cached_arrayitems[arraydescr] - for cf in submap.itervalues(): - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setarrayitem(arraydescr, can_cache=False) if effectinfo.check_forces_virtual_or_virtualizable(): vrefinfo = self.optimizer.metainterp_sd.virtualref_info self.force_lazy_setfield(vrefinfo.descr_forced) @@ -240,12 +231,12 @@ if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] - def force_lazy_setfield(self, descr): + def force_lazy_setfield(self, descr, can_cache=True): try: cf = self.cached_fields[descr] except KeyError: return - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) def force_lazy_setarrayitem(self, arraydescr, can_cache=True): try: From noreply at buildbot.pypy.org Sat Jul 16 20:11:51 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 20:11:51 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: setarrayitem does not influence the heap cache Message-ID: <20110716181151.15C2A82962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45679:afd433b6fc94 Date: 2011-07-16 18:37 +0200 http://bitbucket.org/pypy/pypy/changeset/afd433b6fc94/ Log: setarrayitem does not influence the heap cache diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1648,7 +1648,8 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) - if opnum != rop.SETFIELD_GC and self.heap_cache: + if (self.heap_cache and opnum != rop.SETFIELD_GC and + opnum != rop.SETARRAYITEM_GC): if not (rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST): self.heap_cache = {} op = self.history.record(opnum, argboxes, resbox, descr) diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -113,6 +113,7 @@ @jit.dont_look_inside def f(a): a.x = 5 + l = [1] def fn(n): if n > 0: a = a1 @@ -121,9 +122,11 @@ a.x = n x1 = a.x f(a) - return a.x + x1 + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 res = self.interp_operations(fn, [7]) - assert res == 5 + 7 + assert res == 5 * 2 + 7 self.check_operations_history(getfield_gc=1) def test_heap_caching_dont_store_same(self): From noreply at buildbot.pypy.org Sat Jul 16 20:11:52 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 20:11:52 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: intermediate checkin: starting an array cache. stopped by a bug on trunk. Message-ID: <20110716181152.436E082962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45680:aacbf098fe2c Date: 2011-07-16 19:49 +0200 http://bitbucket.org/pypy/pypy/changeset/aacbf098fe2c/ Log: intermediate checkin: starting an array cache. stopped by a bug on trunk. diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -390,8 +390,17 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + index = -1 + if cache and isinstance(indexbox, ConstInt): + index = indexbox.getint() + frombox, tobox = cache.get(index, (None, None)) + if frombox is arraybox: + return tobox + resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, + arraydescr, arraybox, indexbox) + return resbox + opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any @@ -419,6 +428,13 @@ indexbox, itembox): self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, itembox) + if isinstance(indexbox, ConstInt): + cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {}) + cache[indexbox.getint()] = arraybox, itembox + else: + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache: + cache.clear() opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any @@ -1473,6 +1489,9 @@ # heap cache # maps descrs to (from_box, to_box) tuples self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1820,6 +1839,7 @@ self.known_class_boxes = {} self.nonstandard_virtualizables = {} # XXX maybe not needed? self.heap_cache = {} + self.heap_array_cache = {} duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -148,3 +148,39 @@ res = self.interp_operations(fn, [-7]) assert res == -7 self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) From noreply at buildbot.pypy.org Sat Jul 16 20:11:53 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 20:11:53 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: merge default Message-ID: <20110716181153.774C682962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45681:b60a9b13da69 Date: 2011-07-16 19:50 +0200 http://bitbucket.org/pypy/pypy/changeset/b60a9b13da69/ Log: merge default diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -73,7 +73,7 @@ assert self._lazy_setfield is None self._cached_fields[structvalue] = fieldvalue - def force_lazy_setfield(self, optheap): + def force_lazy_setfield(self, optheap, can_cache=True): op = self._lazy_setfield if op is not None: # This is the way _lazy_setfield is usually reset to None. @@ -83,6 +83,8 @@ self._cached_fields.clear() self._lazy_setfield = None optheap.next_optimization.propagate_forward(op) + if not can_cache: + return # Once it is done, we can put at least one piece of information # back in the cache: the value of this particular structure's # field. @@ -245,13 +247,13 @@ return cf.force_lazy_setfield(self) - def force_lazy_setarrayitem(self, arraydescr): + def force_lazy_setarrayitem(self, arraydescr, can_cache=True): try: submap = self.cached_arrayitems[arraydescr] except KeyError: return for cf in submap.values(): - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes @@ -387,7 +389,7 @@ cf.do_setfield(self, op) else: # variable index, so make sure the lazy setarrayitems are done - self.force_lazy_setarrayitem(op.getdescr()) + self.force_lazy_setarrayitem(op.getdescr(), can_cache=False) # and then emit the operation self.emit_operation(op) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1755,6 +1755,27 @@ """ self.optimize_loop(ops, expected) + def test_duplicate_getarrayitem_after_setarrayitem_bug(self): + ops = """ + [p0, i0, i1] + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i6 = int_add(i0, 1) + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + def test_bug_1(self): ops = """ [i0, p1] diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -89,7 +89,7 @@ while asm[asm_index][0] < op.offset: asm_index += 1 end_index = asm_index - while asm[end_index][0] < end: + while asm[end_index][0] < end and end_index < len(asm) - 1: end_index += 1 op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) return loop @@ -343,18 +343,20 @@ addr = int(m.group(1), 16) entry = entry.lower() m = re.search('guard \d+', entry) - addrs[addr] = m.group(0) + name = m.group(0) else: name = entry[:entry.find('(') - 1].lower() - addrs[int(m.group(1), 16)] = name + addr = int(m.group(1), 16) + addrs.setdefault(addr, []).append(name) dumps = {} for entry in extract_category(log, 'jit-backend-dump'): backend, _, dump, _ = entry.split("\n") _, addr, _, data = re.split(" +", dump) backend_name = backend.split(" ")[1] addr = int(addr[1:], 16) - if addr in addrs: - dumps[addrs[addr]] = (backend_name, addr, data) + if addr in addrs and addrs[addr]: + name = addrs[addr].pop(0) # they should come in order + dumps[name] = (backend_name, addr, data) loops = [] for entry in extract_category(log, 'jit-log-opt'): parser = ParserCls(entry, None, {}, 'lltype', None, @@ -369,7 +371,10 @@ name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] - parser.postprocess(loop, backend_tp=bname, backend_dump=dump, - dump_start=start_ofs) + loop.force_asm = (lambda dump=dump, start_ofs=start_ofs, + bname=bname, loop=loop: + parser.postprocess(loop, backend_tp=bname, + backend_dump=dump, + dump_start=start_ofs)) loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest2.log @@ -0,0 +1,301 @@ +[1f5e7f69779] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f7fe75] jit-backend-dump} +[1f5e7f84fc4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f87ac1] jit-backend-dump} +[1f5e7f8a0b4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b08a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f8da6b] jit-backend-dump} +[1f5e7f8f4f6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b13d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f92b83] jit-backend-dump} +[1f5e7f95b99] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 +[1f5e7f988d0] jit-backend-dump} +[1f5e7fa16fb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b28e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 +[1f5e7fa47ac] jit-backend-dump} +[1f5e7fab3a4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 +[1f5e7faf1ca] jit-backend-dump} +[1f5e7fb0813] {jit-backend-counts +[1f5e7fb0f61] jit-backend-counts} +[1f5fd38be3e] {jit-backend +[1f5fe729336] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB30B00C0A897F00004D8B334983C60149BB30B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030300000049BB00B0A007897F000041FFD34440484C3D39030400000049BB00B0A007897F000041FFD34440484C3907070305000000 +[1f5fe73276a] jit-backend-dump} +[1f5fe73438f] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f8907a0b45d to 7f8907a0b4c3 (bootstrap 7f8907a0b3d5) +[1f5fe7369af] jit-backend-addr} +[1f5fe737940] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3e5 +0 50FFFFFF +[1f5fe74b40e] jit-backend-dump} +[1f5fe74c63d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b484 +0 95000000 +[1f5fe74da6a] jit-backend-dump} +[1f5fe74e438] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 9B000000 +[1f5fe74f513] jit-backend-dump} +[1f5fe74fd2e] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b4b7 +0 91000000 +[1f5fe750d8c] jit-backend-dump} +[1f5fe75373f] jit-backend} +[1f5fe755abc] {jit-log-opt-loop +# Loop 0 : loop with 26 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 1) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f5fe92b8af] jit-log-opt-loop} +[1f5fe944ae5] {jit-backend +[1f5fee20651] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b565 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C254010000000049BB38B00C0A897F0000498B0B4883C10149BB38B00C0A897F000049890B4983F8010F85000000004883FE017206813E980700000F85000000004983FA000F850000000049BBA8F0B407897F00004D39DC0F8500000000488B56084881FA102700000F8D000000004989D44883E2024883FA000F85000000004983C403488B1425A0536B024883EA0148891425A0536B024883FA000F8C000000004C89BD70FFFFFF4C89B568FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4D89E749BB5DB4A007897F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DAE9CCFEFFFF49BB00B0A007897F000041FFD321383C343029241D180C08030600000049BB00B0A007897F000041FFD3383C18343029240C08030700000049BB00B0A007897F000041FFD329383C3430241808030800000049BB00B0A007897F000041FFD3383C3034241808030900000049BB00B0A007897F000041FFD3383C183424030A00000049BB00B0A007897F000041FFD3383C34241809030B00000049BB00B0A007897F000041FFD3383C34243107030C000000 +[1f5fee2e673] jit-backend-dump} +[1f5fee2f38d] {jit-backend-addr +Loop 1 ( #9 LOAD_FAST) has address 7f8907a0b631 to 7f8907a0b6f8 (bootstrap 7f8907a0b565) +[1f5fee312e3] jit-backend-addr} +[1f5fee320ed] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b575 +0 50FFFFFF +[1f5fee3e903] jit-backend-dump} +[1f5fee3fbff] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b655 +0 0C010000 +[1f5fee41579] jit-backend-dump} +[1f5fee421af] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b667 +0 17010000 +[1f5fee43835] jit-backend-dump} +[1f5fee44261] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b671 +0 28010000 +[1f5fee457c1] jit-backend-dump} +[1f5fee461a5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b684 +0 2F010000 +[1f5fee475d3] jit-backend-dump} +[1f5fee47f57] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b695 +0 37010000 +[1f5fee4933d] jit-backend-dump} +[1f5fee49cd9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6a6 +0 3D010000 +[1f5fee4b0ad] jit-backend-dump} +[1f5fee4ba4f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6c8 +0 33010000 +[1f5fee4cf61] jit-backend-dump} +[1f5fee4dc45] jit-backend} +[1f5fee4f3a9] {jit-log-opt-loop +# Loop 1 : entry bridge with 31 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10] +debug_merge_point(0, ' #9 LOAD_FAST') ++234: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10] ++244: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10] ++262: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p10] +debug_merge_point(0, ' #12 LOAD_CONST') ++272: guard_value(p3, ConstPtr(ptr14), descr=) [p1, p0, p3, p2, p5, p8, p10] +debug_merge_point(0, ' #15 COMPARE_OP') ++291: i15 = getfield_gc_pure(p8, descr=) ++295: i17 = int_lt(i15, 10000) +guard_true(i17, descr=) [p1, p0, p8, p2, p5] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++308: i19 = int_and(i15, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++315: i20 = int_is_true(i19) +guard_false(i20, descr=) [p1, p0, p2, p5, p8, i19] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++325: i22 = int_add(i15, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++329: i24 = getfield_raw(40588192, descr=) ++337: i26 = int_sub(i24, 1) ++341: setfield_raw(40588192, i26, descr=) ++349: i28 = int_lt(i26, 0) +guard_false(i28, descr=) [p1, p0, p2, p5, i22, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++359: jump(p0, p1, p2, p5, i22, descr=) ++403: --end of the loop-- +[1f60036d952] jit-log-opt-loop} +[1f600719a74] {jit-backend +[1f600759dac] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b817 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB40B00C0A897F00004D8B334983C60149BB40B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF024C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030D00000049BB00B0A007897F000041FFD34440484C3D39030E00000049BB00B0A007897F000041FFD34440484C390707030F000000 +[1f60076fd90] jit-backend-dump} +[1f600770f30] {jit-backend-addr +Loop 2 ( #9 LOAD_FAST) has address 7f8907a0b89f to 7f8907a0b905 (bootstrap 7f8907a0b817) +[1f6007730fc] jit-backend-addr} +[1f600773fde] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b827 +0 50FFFFFF +[1f600775c76] jit-backend-dump} +[1f600776a38] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8c6 +0 95000000 +[1f600778112] jit-backend-dump} +[1f600778b8c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8d7 +0 9B000000 +[1f60077a04a] jit-backend-dump} +[1f60077aa6a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8f9 +0 91000000 +[1f60077bf10] jit-backend-dump} +[1f60077cc24] jit-backend} +[1f60077e094] {jit-log-opt-loop +# Loop 2 : loop with 25 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 2) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f6007a567c] jit-log-opt-loop} +[1f600802cd6] {jit-backend +[1f600862dd8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9b7 +0 488DA50000000049BB48B00C0A897F00004D8B3B4983C70149BB48B00C0A897F00004D893B4D89F74983C6010F80000000004C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C00000000488B0425704F3D01488D5010483B1425784F3D01761A49BB10B2A007897F000041FFD349BB8EB2A007897F000041FFD348C7009807000048891425704F3D014C89700848898550FFFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBA8F0B407897F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00100000048C7C709000000488BB550FFFFFF48C7C30000000048C7C20000000049BB31B6A007897F000041FFE349BB00B0A007897F000041FFD3444039484C3D031000000049BB00B0A007897F000041FFD34440484C39070311000000 +[1f60086ba5a] jit-backend-dump} +[1f60086d36e] {jit-backend-addr +Bridge out of guard 4 has address 7f8907a0b9b7 to 7f8907a0bab1 +[1f60086ffd2] jit-backend-addr} +[1f600870dca] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9ba +0 C0FEFFFF +[1f60087281c] jit-backend-dump} +[1f600873506] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 C8000000 +[1f600874b44] jit-backend-dump} +[1f6008754d4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0ba03 +0 C2000000 +[1f600876956] jit-backend-dump} +[1f600877b1a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 1E050000 +[1f600878f4e] jit-backend-dump} +[1f600884c12] jit-backend} +[1f60088780a] {jit-log-opt-bridge +# bridge out of Guard 4 with 16 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #31 LOAD_FAST') +debug_merge_point(0, ' #34 LOAD_CONST') +debug_merge_point(0, ' #37 INPLACE_ADD') ++37: i7 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i7, p2, p3, i5] +debug_merge_point(0, ' #38 STORE_FAST') +debug_merge_point(0, ' #41 JUMP_ABSOLUTE') ++50: i9 = getfield_raw(40588192, descr=) ++58: i11 = int_sub(i9, 1) ++62: setfield_raw(40588192, i11, descr=) ++70: i13 = int_lt(i11, 0) +guard_false(i13, descr=) [p0, p1, p2, p3, i7, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++80: p16 = new_with_vtable(ConstClass(W_IntObject)) ++143: setfield_gc(p16, i7, descr=) ++147: jump(p1, p0, p2, ConstPtr(ptr17), 0, p3, 1, 9, p16, ConstPtr(ptr21), ConstPtr(ptr22), descr=) ++250: --end of the loop-- +[1f6008aa976] jit-log-opt-bridge} +[1f600912c98] {jit-backend-counts +0:1982 +1:1985 +2:0 +3:1782 +[1f600916544] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -213,11 +213,15 @@ def test_import_log(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) + for loop in loops: + loop.force_asm() assert 'jge' in loops[0].operations[3].asm def test_import_log_2(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest2.log'))) + for loop in loops: + loop.force_asm() assert 'cmp' in loops[1].operations[1].asm # bridge - assert 'cmp' in loops[3].operations[1].asm + assert 'jo' in loops[3].operations[3].asm diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1824,6 +1824,11 @@ __gccallshapes: """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) + print >> output, """\ + #if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits + #endif + """ def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) From noreply at buildbot.pypy.org Sat Jul 16 20:11:54 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 20:11:54 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: merge Message-ID: <20110716181154.A40FA82962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45682:e617ed3242d8 Date: 2011-07-16 20:08 +0200 http://bitbucket.org/pypy/pypy/changeset/e617ed3242d8/ Log: merge diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -91,6 +91,8 @@ structvalue = optheap.getvalue(op.getarg(0)) fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) + elif not can_cache: + self._cached_fields.clear() def get_reconstructed(self, optimizer, valuemap): assert self._lazy_setfield is None @@ -204,20 +206,9 @@ for arraydescr in effectinfo.readonly_descrs_arrays: self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: - self.force_lazy_setfield(fielddescr) - try: - cf = self.cached_fields[fielddescr] - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setfield(fielddescr, can_cache=False) for arraydescr in effectinfo.write_descrs_arrays: - self.force_lazy_setarrayitem(arraydescr) - try: - submap = self.cached_arrayitems[arraydescr] - for cf in submap.itervalues(): - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setarrayitem(arraydescr, can_cache=False) if effectinfo.check_forces_virtual_or_virtualizable(): vrefinfo = self.optimizer.metainterp_sd.virtualref_info self.force_lazy_setfield(vrefinfo.descr_forced) @@ -240,12 +231,12 @@ if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] - def force_lazy_setfield(self, descr): + def force_lazy_setfield(self, descr, can_cache=True): try: cf = self.cached_fields[descr] except KeyError: return - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) def force_lazy_setarrayitem(self, arraydescr, can_cache=True): try: diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1776,6 +1776,27 @@ """ self.optimize_loop(ops, expected) + def test_duplicate_getarrayitem_after_setarrayitem_bug2(self): + ops = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + def test_bug_1(self): ops = """ [i0, p1] From noreply at buildbot.pypy.org Sat Jul 16 20:11:55 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 20:11:55 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: fix second half of the test Message-ID: <20110716181155.CF22F82962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45683:feafe98006d1 Date: 2011-07-16 20:10 +0200 http://bitbucket.org/pypy/pypy/changeset/feafe98006d1/ Log: fix second half of the test diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -399,6 +399,10 @@ return tobox resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) + if index >= 0: + if not cache: + cache = self.metainterp.heap_array_cache[arraydescr] = {} + cache[index] = arraybox, resbox return resbox From noreply at buildbot.pypy.org Sat Jul 16 20:22:10 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 20:22:10 +0200 (CEST) Subject: [pypy-commit] pypy faster-nested-scopes: merge default Message-ID: <20110716182210.DE96C82962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: faster-nested-scopes Changeset: r45684:623f7c22e667 Date: 2011-07-16 20:21 +0200 http://bitbucket.org/pypy/pypy/changeset/623f7c22e667/ Log: merge default diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -19,12 +19,12 @@ section * Write them in pure python and use direct libffi low-level bindings, See - \_rawffi_ module description. + \_ffi_ module description. * Write them in RPython as mixedmodule_, using *rffi* as bindings. .. _ctypes: #CTypes -.. _\_rawffi: #LibFFI +.. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules CTypes @@ -42,41 +42,50 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. +ctypes call are optimized by the JIT and the resulting machine code contains a +direct call to the target C function. However, due to the very dynamic nature +of ctypes, some overhead over a bare C call is still present, in particular to +check/convert the types of the parameters. Moreover, even if most calls are +optimized, some cannot and thus need to follow the slow path, not optimized by +the JIT. + .. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure +.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html Pros ---- -Stable, CPython-compatible API +Stable, CPython-compatible API. Most calls are fast, optimized by JIT. Cons ---- -Only pure-python code (slow), problems with platform-dependency (although -we partially solve those). PyPy implementation is now very slow. +Problems with platform-dependency (although we partially solve +those). Although the JIT optimizes ctypes calls, some overhead is still +present. The slow-path is very slow. -_`CPython ctypes`: http://python.net/crew/theller/ctypes/ LibFFI ====== Mostly in order to be able to write a ctypes module, we developed a very -low-level libffi bindings. (libffi is a C-level library for dynamic calling, +low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling, which is used by CPython ctypes). This library provides stable and usable API, although it's API is a very low-level one. It does not contain any -magic. +magic. It is also optimized by the JIT, but has much less overhead than ctypes. Pros ---- -Works. Combines disadvantages of using ctypes with disadvantages of -using mixed modules. Probably more suitable for a delicate code -where ctypes magic goes in a way. +It Works. Probably more suitable for a delicate code where ctypes magic goes +in a way. All calls are optimized by the JIT, there is no slow path as in +ctypes. Cons ---- -Slow. CPython-incompatible API, very rough and low-level +It combines disadvantages of using ctypes with disadvantages of using mixed +modules. CPython-incompatible API, very rough and low-level. Mixed Modules ============= @@ -87,15 +96,15 @@ * a mixed module needs to be written in RPython, which is far more complicated than Python (XXX link) -* due to lack of separate compilation (as of April 2008), each +* due to lack of separate compilation (as of July 2011), each compilation-check requires to recompile whole PyPy python interpreter, which takes 0.5-1h. We plan to solve this at some point in near future. * although rpython is a garbage-collected language, the border between C and RPython needs to be managed by hand (each object that goes into the - C level must be explicitly freed) XXX we try to solve this + C level must be explicitly freed). -Some document is available `here`_ +Some documentation is available `here`_ .. _`here`: rffi.html diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -27,9 +27,10 @@ _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset) -def parse_future(tree): +def parse_future(tree, feature_flags): future_lineno = 0 future_column = 0 + flags = 0 have_docstring = False body = None if isinstance(tree, ast.Module): @@ -37,7 +38,7 @@ elif isinstance(tree, ast.Interactive): body = tree.body if body is None: - return 0, 0 + return 0, 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): if have_docstring: @@ -48,11 +49,16 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset + for alias in stmt.names: + assert isinstance(alias, ast.alias) + # If this is an invalid flag, it will be caught later in + # codegen.py. + flags |= feature_flags.get(alias.name, 0) else: break else: break - return future_lineno, future_column + return flags, future_lineno, future_column class ForbiddenNameAssignment(Exception): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,10 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - future_pos = misc.parse_future(node) + fut = misc.parse_future(node, self.future_flags.compiler_features) + f_flags, f_lineno, f_col = fut + future_pos = f_lineno, f_col + flags |= f_flags info = pyparse.CompileInfo(filename, mode, flags, future_pos) return self._compile_ast(node, info) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) - if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') + if parent_destructor is not None: + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -858,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -482,7 +482,7 @@ # rawstart = self.materialize_loop(original_loop_token) debug_start("jit-backend-addr") - debug_print("Bridge out of Guard %d has address %x to %x" % + debug_print("bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): @@ -44,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -58,10 +63,15 @@ expected = "\xE8" + struct.pack('", "exec") + mod = self.get_ast("from __future__ import division\nx = 1/2") + co = compile(mod, "", "exec") + ns = {} + exec co in ns + assert ns["x"] == .5 def test_field_attr_writable(self): import _ast as ast diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.objectmodel import we_are_translated class CodecState(object): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -1,9 +1,8 @@ -import sys -from pypy.interpreter.baseobjspace import Wrappable, Arguments +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, \ operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi @@ -16,7 +15,7 @@ class W_FFIType(Wrappable): _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to'] - + def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None): self.name = name self.ffitype = ffitype @@ -83,7 +82,6 @@ def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P types = [ # note: most of the type name directly come from the C equivalent, # with the exception of bytes: in C, ubyte and char are equivalent, @@ -161,7 +159,7 @@ class W_FuncPtr(Wrappable): _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype'] - + def __init__(self, func, argtypes_w, w_restype): self.func = func self.argtypes_w = argtypes_w @@ -207,7 +205,7 @@ argchain.arg_singlefloat(space.float_w(w_arg)) elif w_argtype.is_struct(): # arg_raw directly takes value to put inside ll_args - w_arg = space.interp_w(W_StructureInstance, w_arg) + w_arg = space.interp_w(W_StructureInstance, w_arg) ptrval = w_arg.ll_buffer argchain.arg_raw(ptrval) else: @@ -404,7 +402,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + return W_FuncPtr(func, argtypes_w, w_restype) @unwrap_spec(name=str) diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -43,11 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,12 +3,10 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.gateway import ObjSpace -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -import os def wrap_streamerror(space, e, w_filename=None): if isinstance(e, streamio.StreamError): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -4,7 +4,6 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.buffer import RWBuffer -from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstring import StringBuilder from pypy.rlib.rarithmetic import r_longlong, intmask from pypy.tool.sourcetools import func_renamer diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py --- a/pypy/module/_io/interp_fileio.py +++ b/pypy/module/_io/interp_fileio.py @@ -1,5 +1,4 @@ -from pypy.interpreter.typedef import ( - TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty) +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 from pypy.rlib.rarithmetic import r_longlong diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -6,7 +6,6 @@ TypeDef, interp_attrproperty, generic_new_descr) from pypy.module.exceptions.interp_exceptions import W_IOError from pypy.module._io.interp_fileio import W_FileIO -from pypy.module._io.interp_iobase import W_IOBase from pypy.module._io.interp_textio import W_TextIOWrapper from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -57,6 +57,11 @@ def __del__(self): self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + + def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -4,7 +4,7 @@ generic_new_descr) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint from pypy.rlib.rbigint import rbigint from pypy.rlib.rstring import UnicodeBuilder diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py --- a/pypy/module/_locale/interp_locale.py +++ b/pypy/module/_locale/interp_locale.py @@ -1,4 +1,3 @@ -from pypy.rpython.tool import rffi_platform as platform from pypy.rlib import rposix from pypy.rlib.rarithmetic import intmask diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -2,12 +2,10 @@ """ The ffi for rpython, need to be imported for side effects """ -import sys from pypy.rpython.lltypesystem import rffi from pypy.rpython.lltypesystem import lltype from pypy.rpython.tool import rffi_platform from pypy.rpython.extfunc import register_external -from pypy.rpython.extregistry import ExtRegistryEntry from pypy.module._minimal_curses import interp_curses from pypy.translator.tool.cbuild import ExternalCompilationInfo @@ -82,7 +80,7 @@ return res finally: rffi.free_charp(ll_cap) - + register_external(interp_curses._curses_tigetstr, [str], str, export_name='_curses.tigetstr', llimpl=tigetstr_llimpl) diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -1,4 +1,4 @@ -import py, sys +import py from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -4,7 +4,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import ( OperationError, wrap_oserror, operationerrfmt) -from pypy.rpython.lltypesystem import rffi, lltype, llmemory +from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll import sys diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -15,7 +15,6 @@ if sys.platform == 'win32': from pypy.rlib import rwin32 - from pypy.interpreter.error import wrap_windowserror from pypy.module._multiprocessing.interp_win32 import ( handle_w, _GetTickCount) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -1,4 +1,4 @@ -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError from pypy.interpreter.nestedscope import Cell from pypy.interpreter.pycode import PyCode from pypy.interpreter.function import Function, Method @@ -8,7 +8,6 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec -from pypy.objspace.std.dicttype import dictiter_typedef from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject @@ -79,7 +78,7 @@ try: return gateway.BuiltinCode.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin code: "+ identifier)) @@ -89,7 +88,7 @@ try: return function.Function.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin function: "+ identifier)) diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,10 +2,10 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rpython.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import get_elem, push_elem +from pypy.module._rawffi.array import push_elem from pypy.module._rawffi.structure import W_Structure -from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \ - wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes +from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, + unwrap_value, unpack_argshapes) from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL from pypy.rlib.clibffi import ffi_type_void from pypy.rlib import rweakref diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -1,7 +1,6 @@ -import sys from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib.clibffi import * @@ -15,7 +14,7 @@ from pypy.rlib import rwin32 from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.tracker import tracker TYPEMAP = { diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py --- a/pypy/module/_socket/interp_func.py +++ b/pypy/module/_socket/interp_func.py @@ -1,9 +1,8 @@ -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._socket.interp_socket import converted_error, W_RSocket from pypy.rlib import rsocket from pypy.rlib.rsocket import SocketError -from pypy.rlib.rarithmetic import r_uint -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError def gethostname(space): """gethostname() -> string diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,7 +1,7 @@ from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError -from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -11,7 +11,6 @@ from pypy.module._socket import interp_socket -import sys ## user defined constants X509_NAME_MAXLEN = 256 @@ -131,13 +130,13 @@ self._issuer = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN, flavor='raw') self._issuer[0] = '\0' self.shutdown_seen_zero = False - + def server(self): return self.space.wrap(rffi.charp2str(self._server)) - + def issuer(self): return self.space.wrap(rffi.charp2str(self._issuer)) - + def __del__(self): if self.peer_cert: libssl_X509_free(self.peer_cert) @@ -147,7 +146,7 @@ libssl_SSL_CTX_free(self.ctx) lltype.free(self._server, flavor='raw') lltype.free(self._issuer, flavor='raw') - + @unwrap_spec(data='bufferstr') def write(self, data): """write(s) -> len @@ -230,10 +229,10 @@ raw_buf, gc_buf = rffi.alloc_buffer(num_bytes) while True: err = 0 - + count = libssl_SSL_read(self.ssl, raw_buf, num_bytes) err = libssl_SSL_get_error(self.ssl, count) - + if err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout(self.space, self.w_socket, False) @@ -245,17 +244,17 @@ return self.space.wrap("") else: sockstate = SOCKET_OPERATION_OK - + if sockstate == SOCKET_HAS_TIMED_OUT: raise ssl_error(self.space, "The read operation timed out") elif sockstate == SOCKET_IS_NONBLOCKING: break - + if err == SSL_ERROR_WANT_READ or err == SSL_ERROR_WANT_WRITE: continue else: break - + if count <= 0: raise _ssl_seterror(self.space, self, count) @@ -351,7 +350,7 @@ self.shutdown_seen_zero = True continue - # Possibly retry shutdown until timeout or failure + # Possibly retry shutdown until timeout or failure ssl_err = libssl_SSL_get_error(self.ssl, ret) if ssl_err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout( @@ -397,7 +396,7 @@ else: w_proto = space.w_None - bits = libssl_SSL_CIPHER_get_bits(current, + bits = libssl_SSL_CIPHER_get_bits(current, lltype.nullptr(rffi.INTP.TO)) w_bits = space.newint(bits) @@ -552,7 +551,7 @@ ext = libssl_X509_get_ext(certificate, i) method = libssl_X509V3_EXT_get(ext) if not method: - raise ssl_error(space, + raise ssl_error(space, "No method for internalizing subjectAltName!'") with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr: @@ -858,7 +857,7 @@ cert = libssl_BIO_new(libssl_BIO_s_file()) if not cert: raise ssl_error(space, "Can't malloc memory to read file") - + try: if libssl_BIO_read_filename(cert, filename) <= 0: raise ssl_error(space, "Can't open file") @@ -873,7 +872,7 @@ libssl_X509_free(x) finally: libssl_BIO_free(cert) - + # this function is needed to perform locking on shared data # structures. (Note that OpenSSL uses a number of global data # structures that will be implicitly shared whenever multiple threads diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -15,13 +15,10 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import StaticMethod from pypy.module._stackless.stackless_flags import StacklessFlags from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit @@ -38,7 +35,7 @@ self.costate = costate if not space.is_true(space.callable(w_obj)): raise operationerrfmt( - space.w_TypeError, + space.w_TypeError, "'%s' object is not callable", space.type(w_obj).getname(space)) self.w_func = w_obj @@ -65,7 +62,7 @@ # Should be moved to interp_stackless.py if it's ever implemented... Currently # used by pypy/lib/stackless.py. -W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, +W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, """Tasklet killed manually.""") class AppCoroutine(Coroutine): # XXX, StacklessFlags): @@ -90,7 +87,7 @@ def _get_state(space): return space.fromcache(AppCoState) _get_state = staticmethod(_get_state) - + def w_bind(self, w_func, __args__): space = self.space if self.frame is not None: @@ -127,7 +124,7 @@ w_excvalue = operror.get_w_value(space) w_exctraceback = operror.get_traceback() w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback]) - + if w_exctype is self.costate.w_CoroutineExit: self.coroutine_exit = True else: @@ -146,22 +143,22 @@ def w_kill(self): self.kill() - + def w_throw(self, w_type, w_value=None, w_traceback=None): space = self.space operror = OperationError(w_type, w_value) operror.normalize_exception(space) - + if not space.is_w(w_traceback, space.w_None): from pypy.interpreter import pytraceback tb = space.interpclass_w(w_traceback) - if tb is None or not space.is_true(space.isinstance(tb, + if tb is None or not space.is_true(space.isinstance(tb, space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) operror.set_traceback(tb) - + self._kill(operror) def _userdel(self): @@ -280,7 +277,7 @@ assert isinstance(w_klass, W_TypeObject) old_flag = w_klass.flag_heaptype w_klass.flag_heaptype = True - + space.appexec([w_klass, space.wrap(funcname)], """ (klass, funcname): func = getattr(klass, funcname) @@ -332,23 +329,23 @@ # Exporting new exception to space self.w_CoroutineExit = space.gettypefor(W_CoroutineExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('CoroutineExit'), - self.w_CoroutineExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('CoroutineExit'), + space.exceptions_module.w_dict, + space.new_interned_str('CoroutineExit'), self.w_CoroutineExit) - + space.setitem(space.builtin.w_dict, + space.new_interned_str('CoroutineExit'), + self.w_CoroutineExit) + # Should be moved to interp_stackless.py if it's ever implemented... self.w_TaskletExit = space.gettypefor(W_TaskletExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - + space.exceptions_module.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + space.setitem(space.builtin.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + def post_install(self): self.current = self.main = AppCoroutine(self.space, state=self) self.main.subctx.clear_framestack() # wack @@ -378,7 +375,7 @@ instr = frame.last_instr opcode = ord(code[instr]) map = pythonopcode.opmap - call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], + call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] assert opcode in call_ops instr += 1 diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py --- a/pypy/module/_stackless/interp_stackless.py +++ b/pypy/module/_stackless/interp_stackless.py @@ -1,9 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError -from pypy.rlib.rarithmetic import intmask import os diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py --- a/pypy/module/_stackless/rclonable.py +++ b/pypy/module/_stackless/rclonable.py @@ -1,7 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.rlib.objectmodel import we_are_translated -from pypy.interpreter.error import OperationError class InterpClonableMixin: @@ -76,7 +75,7 @@ if not isinstance(current, InterpClonableCoroutine): raise RuntimeError("fork() in a non-clonable coroutine") thunk = ForkThunk(current) - coro_fork = InterpClonableCoroutine() + coro_fork = InterpClonableCoroutine() coro_fork.bind(thunk) coro_fork.switch() # we resume here twice. The following would need explanations about diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,16 +1,15 @@ import py -from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.interpreter.typedef import GetSetProperty, TypeDef +from pypy.interpreter.typedef import TypeDef from pypy.rlib import jit import weakref class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 @@ -23,8 +22,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,11 +119,8 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: - w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) + assert isinstance(w_self, W_WeakrefBase) + w_self.space.call_function(w_self.w_callable, w_self) def descr__repr__(self, space): w_obj = self.dereference() diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -1,6 +1,5 @@ from __future__ import with_statement from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError, wrap_windowserror diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,10 +1,9 @@ from __future__ import with_statement -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object from pypy.objspace.std.multimethod import FailedToImplement diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -4,9 +4,8 @@ from pypy.rpython.lltypesystem import lltype from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.rlib.streamio import Stream from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform as compiler @@ -67,7 +66,7 @@ 'BZ_OUTBUFF_FULL', 'BZ_CONFIG_ERROR'] for name in constant_names: setattr(CConfig, name, platform.DefinedConstantInteger(name)) - + class cConfig(object): pass for k, v in platform.configure(CConfig).items(): @@ -100,7 +99,7 @@ SMALLCHUNK = 8192 else: SMALLCHUNK = BUFSIZ - + if rffi.sizeof(rffi.INT) > 4: BIGCHUNK = 512 * 32 else: @@ -505,7 +504,7 @@ self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self._init_bz2comp(compresslevel) - + def _init_bz2comp(self, compresslevel): if compresslevel < 1 or compresslevel > 9: raise OperationError(self.space.w_ValueError, @@ -514,13 +513,13 @@ bzerror = intmask(BZ2_bzCompressInit(self.bzs, compresslevel, 0, 0)) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzCompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') - + @unwrap_spec(data='bufferstr') def compress(self, data): """compress(data) -> string @@ -529,12 +528,12 @@ compressed data whenever possible. When you've finished providing data to compress, call the flush() method to finish the compression process, and return what is left in the internal buffers.""" - + datasize = len(data) - + if datasize == 0: return self.space.wrap("") - + if not self.running: raise OperationError(self.space.w_ValueError, self.space.wrap("this object was already flushed")) @@ -562,7 +561,7 @@ res = out.make_result_string() return self.space.wrap(res) - + def flush(self): if not self.running: raise OperationError(self.space.w_ValueError, @@ -576,7 +575,7 @@ break elif bzerror != BZ_FINISH_OK: _catch_bz2_error(self.space, bzerror) - + if rffi.getintfield(self.bzs, 'c_avail_out') == 0: out.prepare_next_chunk() @@ -603,23 +602,23 @@ Create a new decompressor object. This object may be used to decompress data sequentially. If you want to decompress data in one shot, use the decompress() function instead.""" - + def __init__(self, space): self.space = space self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self.unused_data = "" - + self._init_bz2decomp() - + def _init_bz2decomp(self): bzerror = BZ2_bzDecompressInit(self.bzs, 0, 0) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzDecompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') @@ -687,7 +686,7 @@ Compress data in one shot. If you want to compress data sequentially, use an instance of BZ2Compressor instead. The compresslevel parameter, if given, must be a number between 1 and 9.""" - + if compresslevel < 1 or compresslevel > 9: raise OperationError(space.w_ValueError, space.wrap("compresslevel must be between 1 and 9")) @@ -731,7 +730,7 @@ Decompress data in one shot. If you want to decompress data sequentially, use an instance of BZ2Decompressor instead.""" - + in_bufsize = len(data) if in_bufsize == 0: return space.wrap("") diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -133,6 +133,7 @@ bz2f.seek(0) assert bz2f.tell() == 0 + del bz2f # delete from this frame, which is captured in the traceback def test_open_close_del(self): from bz2 import BZ2File @@ -246,11 +247,18 @@ assert text_read == self.TEXT bz2f.close() + def test_silently_closes(self): + from bz2 import BZ2File + self.create_broken_temp_file() + BZ2File(self.temppath) + # check that no C-level malloc is left behind + def test_read_broken_file(self): from bz2 import BZ2File self.create_broken_temp_file() bz2f = BZ2File(self.temppath) raises(EOFError, bz2f.read) + del bz2f # delete from this frame, which is captured in the traceback def test_subsequent_read_broken_file(self): from bz2 import BZ2File @@ -264,6 +272,7 @@ raise Exception("should generate EOFError earlier") except EOFError: pass + del bz2f # delete from this frame, which is captured in the traceback def test_read_chunk10(self): from bz2 import BZ2File @@ -416,6 +425,7 @@ bz2f.close() bz2f = BZ2File(self.temppath, 'r') assert bz2f.read() == self.random_data + del bz2f # delete from this frame, which is captured in the traceback def test_context_manager(self): from bz2 import BZ2File diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -1,4 +1,3 @@ -import sys from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py --- a/pypy/module/cmath/interp_cmath.py +++ b/pypy/module/cmath/interp_cmath.py @@ -5,7 +5,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import NoneNotWrapped -from pypy.module.cmath import Module, names_and_docstrings +from pypy.module.cmath import names_and_docstrings from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG from pypy.module.cmath.constant import M_LN2, M_LN10 diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py --- a/pypy/module/cpyext/cdatetime.py +++ b/pypy/module/cpyext/cdatetime.py @@ -1,8 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib.objectmodel import we_are_translated -from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef -from pypy.module.cpyext.api import ( - cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields) +from pypy.module.cpyext.pyobject import PyObject, make_ref +from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct, + PyObjectFields) from pypy.module.cpyext.import_ import PyImport_Import from pypy.module.cpyext.typeobject import PyTypeObjectPtr from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py --- a/pypy/module/cpyext/complexobject.py +++ b/pypy/module/cpyext/complexobject.py @@ -1,7 +1,6 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.module.cpyext.api import ( cpython_api, cpython_struct, PyObject, build_type_checkers) -from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.floatobject import PyFloat_AsDouble from pypy.objspace.std.complexobject import W_ComplexObject from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.1" /* PyPy version as a string */ -#define PYPY_VERSION "1.5.0" +#define PYPY_VERSION "1.6.0" /* Subversion Revision number of this file (not of the repository) */ #define PY_PATCHLEVEL_REVISION "$Revision: 77872 $" diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -22,7 +22,7 @@ def PySequence_Check(space, w_obj): """Return 1 if the object provides sequence protocol, and 0 otherwise. This function always succeeds.""" - return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None) + return int(space.issequence_w(w_obj)) @cpython_api([PyObject], Py_ssize_t, error=-1) def PySequence_Size(space, w_obj): diff --git a/pypy/module/crypt/interp_crypt.py b/pypy/module/crypt/interp_crypt.py --- a/pypy/module/crypt/interp_crypt.py +++ b/pypy/module/crypt/interp_crypt.py @@ -1,6 +1,5 @@ -from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.rpython.lltypesystem import rffi, lltype +from pypy.rpython.lltypesystem import rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo import sys @@ -22,4 +21,4 @@ if not res: return space.w_None str_res = rffi.charp2str(res) - return space.wrap(str_res) + return space.wrap(str_res) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -73,9 +73,8 @@ """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w,\ - GetSetProperty, interp_attrproperty, descr_get_dict, descr_set_dict,\ - descr_del_dict +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict, + descr_set_dict, descr_del_dict) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError from pypy.rlib import rwin32 diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -11,9 +11,8 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.eval import Code from pypy.interpreter.pycode import PyCode -from pypy.rlib import streamio, jit, rposix +from pypy.rlib import streamio, jit from pypy.rlib.streamio import StreamErrors -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -3,9 +3,9 @@ from pypy.rlib import streamio from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.module import Module -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import struct + def get_suffixes(space): w = space.wrap diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,7 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.rarithmetic import ovfcheck class W_Count(Wrappable): @@ -87,7 +86,7 @@ def __init__(self, space, w_obj, w_times): self.space = space self.w_obj = w_obj - + if space.is_w(w_times, space.w_None): self.counting = False self.count = 0 @@ -181,7 +180,7 @@ long as the predicate is true. Equivalent to : - + def takewhile(predicate, iterable): for x in iterable: if predicate(x): @@ -316,7 +315,7 @@ None, return the items that are false. Equivalent to : - + def ifilterfalse(predicate, iterable): if predicate is None: predicate = bool @@ -570,7 +569,7 @@ yield tuple(args) else: yield function(*args) - + """) @@ -728,9 +727,9 @@ __doc__ = """Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely. - + Equivalent to : - + def cycle(iterable): saved = [] for element in iterable: @@ -738,7 +737,7 @@ saved.append(element) while saved: for element in saved: - yield element + yield element """) class W_StarMap(Wrappable): @@ -778,7 +777,7 @@ def starmap(function, iterable): iterable = iter(iterable) while True: - yield function(*iterable.next()) + yield function(*iterable.next()) """) @@ -788,15 +787,15 @@ Note : once tee() has made a split, the original iterable should not be used anywhere else; otherwise, the iterable could get advanced without the tee objects being informed. - + Note : this member of the toolkit may require significant auxiliary storage (depending on how much temporary data needs to be stored). In general, if one iterator is going to use most or all of the data before the other iterator, it is faster to use list() instead of tee() - + Equivalent to : - + def tee(iterable, n=2): def gen(next, data={}, cnt=[0]): for i in count(): @@ -888,7 +887,7 @@ self.exhausted = False self.started = False # new_group - new group not started yet, next should not skip any items - self.new_group = True + self.new_group = True self.w_lookahead = self.space.w_None self.w_key = self.space.w_None diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -1,10 +1,8 @@ -from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask from pypy.rlib import rstackovf from pypy.module._file.interp_file import W_File -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import sys + Py_MARSHAL_VERSION = 2 diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,4 +1,4 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,7 +1,7 @@ import math -from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array +from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, + convert_to_array) from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py --- a/pypy/module/mmap/interp_mmap.py +++ b/pypy/module/mmap/interp_mmap.py @@ -1,21 +1,16 @@ -from pypy.rpython.tool import rffi_platform -from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped from pypy.rlib import rmmap from pypy.rlib.rmmap import RValueError, RTypeError, ROverflowError -import sys -import os -import platform -import stat + class W_MMap(Wrappable): def __init__(self, space, mmap_obj): self.space = space self.mmap = mmap_obj - + def close(self): self.mmap.close() diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -15,7 +15,6 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap -from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant from pypy.jit.metainterp.resoperation import rop from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes @@ -67,7 +66,7 @@ def on_compile(self, logger, looptoken, operations, type, next_instr, is_being_profiled, ll_pycode): from pypy.rpython.annlowlevel import cast_base_ptr_to_instance - + space = self.space cache = space.fromcache(Cache) if cache.in_recursion: @@ -171,7 +170,7 @@ # ____________________________________________________________ # -# Public interface +# Public interface def set_param(space, __args__): '''Configure the tunable JIT parameters. @@ -213,7 +212,7 @@ class Cache(object): in_recursion = False - + def __init__(self, space): self.w_compile_hook = space.w_None diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -1,9 +1,9 @@ from pypy.interpreter.typedef import TypeDef, interp_attrproperty -from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import unwrap_spec, interp2app from pypy.interpreter.pycode import PyCode -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.lltypesystem.rclass import OBJECT diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py --- a/pypy/module/rctime/interp_time.py +++ b/pypy/module/rctime/interp_time.py @@ -6,7 +6,6 @@ from pypy.rlib.rarithmetic import ovfcheck_float_to_int from pypy.rlib import rposix from pypy.translator.tool.cbuild import ExternalCompilationInfo -import math import os import sys import time as pytime @@ -102,7 +101,7 @@ CLOCKS_PER_SEC = platform.ConstantInteger("CLOCKS_PER_SEC") clock_t = platform.SimpleType("clock_t", rffi.ULONG) has_gettimeofday = platform.Has('gettimeofday') - + if _POSIX: calling_conv = 'c' CConfig.timeval = platform.Struct("struct timeval", @@ -235,7 +234,7 @@ _set_module_object(space, "timezone", space.wrap(timezone)) _set_module_object(space, 'daylight', space.wrap(daylight)) - tzname_w = [space.wrap(tzname[0]), space.wrap(tzname[1])] + tzname_w = [space.wrap(tzname[0]), space.wrap(tzname[1])] _set_module_object(space, 'tzname', space.newtuple(tzname_w)) _set_module_object(space, 'altzone', space.wrap(altzone)) @@ -310,7 +309,7 @@ space.wrap((rffi.getintfield(t, 'c_tm_wday') + 6) % 7), # want monday == 0 space.wrap(rffi.getintfield(t, 'c_tm_yday') + 1), # want january, 1 == 1 space.wrap(rffi.getintfield(t, 'c_tm_isdst'))] - + w_struct_time = _get_module_object(space, 'struct_time') w_time_tuple = space.newtuple(time_tuple) return space.call_function(w_struct_time, w_time_tuple) @@ -330,7 +329,7 @@ tup_w = space.fixedview(w_tup) if len(tup_w) != 9: - raise operationerrfmt(space.w_TypeError, + raise operationerrfmt(space.w_TypeError, "argument must be sequence of " "length 9, not %d", len(tup_w)) @@ -359,7 +358,7 @@ w_accept2dyear = _get_module_object(space, "accept2dyear") accept2dyear = space.int_w(w_accept2dyear) - + if y < 1900: if not accept2dyear: raise OperationError(space.w_ValueError, @@ -392,7 +391,7 @@ Return the current time in seconds since the Epoch. Fractions of a second may be present if the system clock provides them.""" - + secs = pytime.time() return space.wrap(secs) @@ -420,7 +419,7 @@ not present, current time as returned by localtime() is used.""" seconds = _get_inttime(space, w_seconds) - + t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw') t_ref[0] = seconds p = c_ctime(t_ref) @@ -444,7 +443,7 @@ if not p: raise OperationError(space.w_ValueError, space.wrap("unconvertible time")) - + return space.wrap(rffi.charp2str(p)[:-1]) # get rid of new line def gmtime(space, w_seconds=None): @@ -462,7 +461,7 @@ t_ref[0] = seconds p = c_gmtime(t_ref) lltype.free(t_ref, flavor='raw') - + if not p: raise OperationError(space.w_ValueError, space.wrap(_get_error_msg())) return _tm_to_tuple(space, p) @@ -479,7 +478,7 @@ t_ref[0] = seconds p = c_localtime(t_ref) lltype.free(t_ref, flavor='raw') - + if not p: raise OperationError(space.w_ValueError, space.wrap(_get_error_msg())) return _tm_to_tuple(space, p) @@ -524,7 +523,7 @@ See the library reference manual for formatting codes. When the time tuple is not present, current time as returned by localtime() is used.""" buf_value = _gettmarg(space, w_tup) - + # Checks added to make sure strftime() does not crash Python by # indexing blindly into some array for a textual representation # by some bad index (fixes bug #897625). diff --git a/pypy/module/select/interp_select.py b/pypy/module/select/interp_select.py --- a/pypy/module/select/interp_select.py +++ b/pypy/module/select/interp_select.py @@ -1,9 +1,7 @@ -import math from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import ( - OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.rlib import rpoll import errno @@ -122,7 +120,7 @@ w_errortype = space.fromcache(Cache).w_error raise OperationError(w_errortype, space.newtuple([ space.wrap(s.errno), space.wrap(s.get_msg())])) - + return space.newtuple([ space.newlist([iwtd_d[i] for i in iwtd]), space.newlist([owtd_d[i] for i in owtd]), diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py --- a/pypy/module/struct/formatiterator.py +++ b/pypy/module/struct/formatiterator.py @@ -1,11 +1,10 @@ - from pypy.interpreter.error import OperationError from pypy.rlib.objectmodel import specialize from pypy.rlib.rstruct.error import StructError from pypy.rlib.rstruct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT -from pypy.rlib.rstruct.formatiterator import (FormatIterator, - CalcSizeFormatIterator) +from pypy.rlib.rstruct.formatiterator import FormatIterator + class PackFormatIterator(FormatIterator): diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py --- a/pypy/module/struct/interp_struct.py +++ b/pypy/module/struct/interp_struct.py @@ -1,10 +1,7 @@ from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.module.struct.formatiterator import PackFormatIterator, UnpackFormatIterator from pypy.rlib.rstruct.error import StructError -from pypy.module.struct.formatiterator import CalcSizeFormatIterator -from pypy.module.struct.formatiterator import PackFormatIterator -from pypy.module.struct.formatiterator import UnpackFormatIterator - +from pypy.rlib.rstruct.formatiterator import CalcSizeFormatIterator @unwrap_spec(format=str) def calcsize(space, format): diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py --- a/pypy/module/sys/test/test_sysmodule.py +++ b/pypy/module/sys/test/test_sysmodule.py @@ -476,7 +476,7 @@ assert isinstance(vi[0], int) assert isinstance(vi[1], int) assert isinstance(vi[2], int) - assert vi[3] in ("alpha", "beta", "candidate", "final") + assert vi[3] in ("alpha", "beta", "candidate", "dev", "final") assert isinstance(vi[4], int) def test_allattributes(self): @@ -523,4 +523,4 @@ # If this ever actually becomes a compilation option this test should # be changed. - assert sys.float_repr_style == "short" \ No newline at end of file + assert sys.float_repr_style == "short" diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ CPYTHON_VERSION = (2, 7, 1, "final", 42) #XXX # sync patchlevel.h CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (1, 5, 0, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (1, 6, 0, "dev", 1) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -1,9 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype, llmemory -from pypy.rpython.tool import rffi_platform as platform from pypy.translator.tool.cbuild import ExternalCompilationInfo -import py, os -from pypy.rpython.extregistry import ExtRegistryEntry +import py from pypy.rlib import jit from pypy.rlib.debug import ll_assert from pypy.rlib.objectmodel import we_are_translated @@ -21,6 +19,7 @@ 'RPyThreadAcquireLock', 'RPyThreadReleaseLock', 'RPyThreadYield', 'RPyThreadGetStackSize', 'RPyThreadSetStackSize', + 'RPyOpaqueDealloc_ThreadLock', 'RPyThreadAfterFork'] ) @@ -52,6 +51,9 @@ c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], rffi.INT, threadsafe=False) # may add in a global list +c_thread_lock_dealloc = llexternal('RPyOpaqueDealloc_ThreadLock', [TLOCKP], + lltype.Void, + threadsafe=True) c_thread_acquirelock = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT], rffi.INT, threadsafe=True) # release the GIL @@ -120,7 +122,7 @@ def __enter__(self): self.acquire(True) - + def __exit__(self, *args): self.release() @@ -156,6 +158,9 @@ return ll_lock def free_ll_lock(ll_lock): + c_thread_acquirelock(ll_lock, 0) + c_thread_releaselock(ll_lock) + c_thread_lock_dealloc(ll_lock) lltype.free(ll_lock, flavor='raw', track_allocation=False) def acquire_NOAUTO(ll_lock, flag): diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py --- a/pypy/module/thread/os_local.py +++ b/pypy/module/thread/os_local.py @@ -1,9 +1,7 @@ from pypy.module.thread import ll_thread as thread -from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp2app -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict +from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty, + descr_get_dict) class Local(Wrappable): diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py --- a/pypy/module/thread/os_thread.py +++ b/pypy/module/thread/os_thread.py @@ -6,7 +6,6 @@ from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import unwrap_spec, NoneNotWrapped, Arguments -from pypy.rlib.objectmodel import free_non_gc_object # Here are the steps performed to start a new thread: # @@ -167,14 +166,14 @@ when the function raises an unhandled exception; a stack trace will be printed unless the exception is SystemExit.""" setup_threads(space) - if not space.is_true(space.isinstance(w_args, space.w_tuple)): - raise OperationError(space.w_TypeError, - space.wrap("2nd arg must be a tuple")) - if w_kwargs is not None and not space.is_true(space.isinstance(w_kwargs, space.w_dict)): - raise OperationError(space.w_TypeError, - space.wrap("optional 3rd arg must be a dictionary")) + if not space.is_true(space.isinstance(w_args, space.w_tuple)): + raise OperationError(space.w_TypeError, + space.wrap("2nd arg must be a tuple")) + if w_kwargs is not None and not space.is_true(space.isinstance(w_kwargs, space.w_dict)): + raise OperationError(space.w_TypeError, + space.wrap("optional 3rd arg must be a dictionary")) if not space.is_true(space.callable(w_callable)): - raise OperationError(space.w_TypeError, + raise OperationError(space.w_TypeError, space.wrap("first arg must be callable")) args = Arguments.frompacked(space, w_args, w_kwargs) diff --git a/pypy/module/thread/test/test_import_lock.py b/pypy/module/thread/test/test_import_lock.py --- a/pypy/module/thread/test/test_import_lock.py +++ b/pypy/module/thread/test/test_import_lock.py @@ -66,6 +66,9 @@ def test_lock(self, space, monkeypatch): from pypy.module.imp.importing import getimportlock, importhook + # Force importing the module _file now + space.builtin.get('file') + # Monkeypatch the import lock and add a counter importlock = getimportlock(space) original_acquire = importlock.acquire_lock diff --git a/pypy/module/unicodedata/generate_unicodedb.py b/pypy/module/unicodedata/generate_unicodedb.py --- a/pypy/module/unicodedata/generate_unicodedb.py +++ b/pypy/module/unicodedata/generate_unicodedb.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -import pprint - MAXUNICODE = 0x10FFFF # the value of sys.maxunicode of wide Python builds MANDATORY_LINE_BREAKS = ["BK", "CR", "LF", "NL"] # line break categories @@ -66,16 +64,16 @@ self.upper = int(data[12], 16) self.lower = None if data[13]: - self.lower = int(data[13], 16) + self.lower = int(data[13], 16) self.title = None if data[14]: self.title = int(data[14], 16) - + def copy(self): uc = Unicodechar() uc.__dict__.update(self.__dict__) return uc - + def get_compat_decomposition(table, code): if not table[code].decomposition: return [code] @@ -177,13 +175,13 @@ for code in range(len(table)): if table[code] is None: table[code] = defaultChar - + extra_numeric = read_unihan(unihan_file) for code, value in extra_numeric.iteritems(): uc = table[code].copy() uc.numeric = value table[code] = uc - + # Compute full decompositions. for code in range(len(table)): get_canonical_decomposition(table, code) @@ -365,7 +363,7 @@ print >> outfile, '%r: %r,' % (code, name) print >> outfile, '}' - + print >> outfile, '_names_corrected = {' for name, code in sorted(base_mod._orig_names.iteritems()): if name not in names: @@ -389,7 +387,7 @@ print >> outfile, '%r: None,' % name print >> outfile, '}' - + def writeUnicodedata(version, table, outfile, base): if base: print >> outfile, 'import %s as base_mod' % base @@ -406,7 +404,7 @@ cjk_end = 0x9FBB write_character_names(outfile, table, base_mod) - + print >> outfile, ''' _cjk_prefix = "CJK UNIFIED IDEOGRAPH-" _hangul_prefix = 'HANGUL SYLLABLE ' @@ -496,7 +494,7 @@ v_code = vl_code %% len(_hangul_V) return ("HANGUL SYLLABLE " + _hangul_L[l_code] + _hangul_V[v_code] + _hangul_T[t_code]) - + if not base_mod: return lookup_charcode(code) else: @@ -522,7 +520,7 @@ digit[code] = table[code].digit if table[code].numeric is not None: numeric[code] = table[code].numeric - + writeDict(outfile, '_decimal', decimal, base_mod) writeDict(outfile, '_digit', digit, base_mod) writeDict(outfile, '_numeric', numeric, base_mod) @@ -662,11 +660,11 @@ ''' def main(): - import re, sys + import sys from optparse import OptionParser infile = None outfile = sys.stdout - + parser = OptionParser('Usage: %prog [options]') parser.add_option('--base', metavar='FILENAME', help='Base python version (for import)') parser.add_option('--output', metavar='OUTPUT_MODULE', help='Output module (implied py extension)') diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -431,12 +431,17 @@ return None assert isinstance(lifeline, WeakrefLifeline) return lifeline + getweakref._cannot_really_call_random_things_ = True def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline - assert (isinstance(weakreflifeline, WeakrefLifeline) or - weakreflifeline is None) + assert isinstance(weakreflifeline, WeakrefLifeline) self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + setweakref._cannot_really_call_random_things_ = True + + def delweakref(self): + self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + delweakref._cannot_really_call_random_things_ = True class ObjectMixin(object): _mixin_ = True diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -36,6 +36,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None class W_SetObject(W_BaseSetObject): from pypy.objspace.std.settype import set_typedef as typedef diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -171,7 +171,7 @@ obj = c.instantiate() assert obj.getweakref() is None obj.setweakref(space, lifeline1) - obj.setweakref(space, None) + obj.delweakref() diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -532,6 +532,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None # ____________________________________________________________ # Initialization of type objects diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -482,6 +482,13 @@ key[2:]) cache[key] = s_value + # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass) + try: + graph = self.bookkeeper.position_key[0] + graph.func._dont_reach_me_in_del_ = True + except (TypeError, AttributeError): + pass + return annmodel.s_None def annotate_hooks(self, **kwds_s): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -83,6 +83,9 @@ t, rtyper, fngraph = self.gengraph(fn, [int]) + # added by compute_result_annotation() + assert fn._dont_reach_me_in_del_ == True + def getargs(func): for graph in t.graphs: if getattr(graph, 'func', None) is func: diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py --- a/pypy/rpython/lltypesystem/rclass.py +++ b/pypy/rpython/lltypesystem/rclass.py @@ -400,6 +400,7 @@ assert len(s_func.descriptions) == 1 funcdesc, = s_func.descriptions graph = funcdesc.getuniquegraph() + self.check_graph_of_del_does_not_call_too_much(graph) FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void) destrptr = functionptr(FUNCTYPE, graph.name, graph=graph, diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,6 +34,13 @@ the GC in very small programs. Defaults to 8 times the nursery. + PYPY_GC_LOSTCARD If between two minor collections we see more than + 'PYPY_GC_LOSTCARD * length' writes to the same array, + then give up card marking and use the fast write + barrier instead. Defaults to 0.3333 for now. + Avoid values lower than 0.125: it is the growth + factor of list.append(). + PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -198,6 +205,9 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, + # See PYPY_GC_LOSTCARD. + "lost_card": 1.0 / 3.0, + # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -214,6 +224,7 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, + lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -235,6 +246,7 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 + self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -355,6 +367,10 @@ else: self.max_delta = 0.125 * env.get_total_memory() # + lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') + if lost_card > 0.0: + self.lost_card = lost_card + # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -649,7 +665,7 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only @@ -675,11 +691,15 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # (the loop is empty in C). - i = 0 - while i < cardheadersize: - llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) - i += 1 + # followed by a Signed (the loop is empty in C). + if cardheadersize > 0: + i = 0 + while i < cardheadersize - WORD: + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Char)) + i += 1 + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -903,14 +923,11 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # - size_gc_header = self.gcheaderbuilder.size_gc_header - p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: - p -= 1 - ll_assert(p.char[0] == '\x00', + i -= 1 + ll_assert(self.get_card(obj, i).char[0] == '\x00', "the card marker bits are not cleared") - i -= 1 # ---------- # Write barrier @@ -1008,6 +1025,8 @@ self.prebuilt_root_objects.append(addr_array) return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1025,10 +1044,6 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1057,6 +1072,8 @@ if not self.appears_to_be_young(newvalue): return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1069,10 +1086,6 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1090,11 +1103,36 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card(self, obj, byteindex): + def get_card_counter_addr(self, obj): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + return llarena.getfakearenaaddress(addr_byte) - WORD + def get_card(self, obj, byteindex): + return self.get_card_counter_addr(obj) + (~byteindex) + + def set_cards_flag(self, obj): + hdr = self.header(obj) + if hdr.tid & GCFLAG_CARDS_SET == 0: + # + # first time we set a card bit in this object + self.header(obj).tid |= GCFLAG_CARDS_SET + self.objects_with_cards_set.append(obj) + # + # initialize the counter with the array length and self.lost_card + typeid = self.get_type_id(obj) + offset_to_length = self.varsize_offset_to_length(typeid) + length = (obj + offset_to_length).signed[0] + counter = int(length * self.lost_card) + self.get_card_counter_addr(obj).signed[0] = counter + else: + # decrement the counter and if zero is reached, give up on + # card marking (up to the next collection). + addr = self.get_card_counter_addr(obj) + addr.signed[0] -= 1 + if addr.signed[0] < 0: + self.objects_pointing_to_young.append(obj) + hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1167,10 +1205,7 @@ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(dest_addr) - dest_hdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(dest_addr) # ---------- # Nursery collection @@ -1264,6 +1299,7 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) + p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1602,7 +1638,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 arena -= extra_words * WORD allocsize += extra_words * WORD # diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -525,6 +525,7 @@ def test_writebarrier_before_copy(self): from pypy.rpython.memory.gc import minimark largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 p_src = self.malloc(VAR, largeobj_size) p_dst = self.malloc(VAR, largeobj_size) # make them old @@ -564,6 +565,7 @@ from pypy.rpython.memory.gc import minimark tid = self.get_type_id(VAR) largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 addr_src = self.gc.external_malloc(tid, largeobj_size) addr_dst = self.gc.external_malloc(tid, largeobj_size) hdr_src = self.gc.header(addr_src) diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -374,6 +374,43 @@ def can_ll_be_null(self, s_value): return s_value.can_be_none() + def check_graph_of_del_does_not_call_too_much(self, graph): + # RPython-level __del__() methods should not do "too much". + # In the PyPy Python interpreter, they usually do simple things + # like file.__del__() closing the file descriptor; or if they + # want to do more like call an app-level __del__() method, they + # enqueue the object instead, and the actual call is done later. + # + # Here, as a quick way to check "not doing too much", we check + # that from no RPython-level __del__() method we can reach a + # JitDriver. + # + # XXX wrong complexity, but good enough because the set of + # reachable graphs should be small + callgraph = self.rtyper.annotator.translator.callgraph.values() + seen = {graph: None} + while True: + oldlength = len(seen) + for caller, callee in callgraph: + if caller in seen and callee not in seen: + func = getattr(callee, 'func', None) + if getattr(func, '_dont_reach_me_in_del_', False): + lst = [str(callee)] + g = caller + while g: + lst.append(str(g)) + g = seen.get(g) + lst.append('') + raise TyperError("the RPython-level __del__() method " + "in %r calls:%s" % ( + graph, '\n\t'.join(lst[::-1]))) + if getattr(func, '_cannot_really_call_random_things_', + False): + continue + seen[callee] = caller + if len(seen) == oldlength: + break + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops, classcallhop=None): diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -7,6 +7,7 @@ from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.rpython.error import TyperError from pypy.objspace.flow.model import summary class EmptyBase(object): @@ -1021,7 +1022,25 @@ assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] assert destrptra is not None assert destrptrb is not None - + + def test_del_forbidden(self): + class A(object): + def __del__(self): + self.foo() + def foo(self): + self.bar() + def bar(self): + pass + bar._dont_reach_me_in_del_ = True + def f(): + a = A() + a.foo() + a.bar() + t = TranslationContext() + t.buildannotator().build_types(f, []) + e = py.test.raises(TyperError, t.buildrtyper().specialize) + print e.value + def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int class FooBar(object): diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -231,7 +231,7 @@ const = self.const def fn(i): s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] - return s[i].startswith('o') + return s[i].startswith(const('o')) for i in range(10): res = self.interpret(fn, [i]) assert res == fn(i) @@ -251,7 +251,7 @@ const = self.const def fn(i): s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] - return s[i].endswith('e') + return s[i].endswith(const('e')) for i in range(10): res = self.interpret(fn, [i]) assert res == fn(i) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -89,7 +89,7 @@ while asm[asm_index][0] < op.offset: asm_index += 1 end_index = asm_index - while asm[end_index][0] < end: + while asm[end_index][0] < end and end_index < len(asm) - 1: end_index += 1 op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) return loop @@ -337,26 +337,44 @@ addrs = {} for entry in extract_category(log, 'jit-backend-addr'): m = re.search('bootstrap ([\da-f]+)', entry) - name = entry[:entry.find('(') - 1] - addrs[int(m.group(1), 16)] = name + if not m: + # a bridge + m = re.search('has address ([\da-f]+)', entry) + addr = int(m.group(1), 16) + entry = entry.lower() + m = re.search('guard \d+', entry) + name = m.group(0) + else: + name = entry[:entry.find('(') - 1].lower() + addr = int(m.group(1), 16) + addrs.setdefault(addr, []).append(name) dumps = {} for entry in extract_category(log, 'jit-backend-dump'): backend, _, dump, _ = entry.split("\n") _, addr, _, data = re.split(" +", dump) backend_name = backend.split(" ")[1] addr = int(addr[1:], 16) - if addr in addrs: - dumps[addrs[addr]] = (backend_name, addr, data) + if addr in addrs and addrs[addr]: + name = addrs[addr].pop(0) # they should come in order + dumps[name] = (backend_name, addr, data) loops = [] for entry in extract_category(log, 'jit-log-opt'): parser = ParserCls(entry, None, {}, 'lltype', None, nonstrict=True) loop = parser.parse() comm = loop.comment - name = comm[2:comm.find(':')-1] + comm = comm.lower() + if comm.startswith('# bridge'): + m = re.search('guard \d+', comm) + name = m.group(0) + else: + name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] - parser.postprocess(loop, backend_tp=bname, backend_dump=dump, - dump_start=start_ofs) + loop.force_asm = (lambda dump=dump, start_ofs=start_ofs, + bname=bname, loop=loop: + parser.postprocess(loop, backend_tp=bname, + backend_dump=dump, + dump_start=start_ofs)) loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest2.log @@ -0,0 +1,301 @@ +[1f5e7f69779] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f7fe75] jit-backend-dump} +[1f5e7f84fc4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f87ac1] jit-backend-dump} +[1f5e7f8a0b4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b08a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f8da6b] jit-backend-dump} +[1f5e7f8f4f6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b13d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f92b83] jit-backend-dump} +[1f5e7f95b99] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 +[1f5e7f988d0] jit-backend-dump} +[1f5e7fa16fb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b28e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 +[1f5e7fa47ac] jit-backend-dump} +[1f5e7fab3a4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 +[1f5e7faf1ca] jit-backend-dump} +[1f5e7fb0813] {jit-backend-counts +[1f5e7fb0f61] jit-backend-counts} +[1f5fd38be3e] {jit-backend +[1f5fe729336] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB30B00C0A897F00004D8B334983C60149BB30B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030300000049BB00B0A007897F000041FFD34440484C3D39030400000049BB00B0A007897F000041FFD34440484C3907070305000000 +[1f5fe73276a] jit-backend-dump} +[1f5fe73438f] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f8907a0b45d to 7f8907a0b4c3 (bootstrap 7f8907a0b3d5) +[1f5fe7369af] jit-backend-addr} +[1f5fe737940] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3e5 +0 50FFFFFF +[1f5fe74b40e] jit-backend-dump} +[1f5fe74c63d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b484 +0 95000000 +[1f5fe74da6a] jit-backend-dump} +[1f5fe74e438] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 9B000000 +[1f5fe74f513] jit-backend-dump} +[1f5fe74fd2e] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b4b7 +0 91000000 +[1f5fe750d8c] jit-backend-dump} +[1f5fe75373f] jit-backend} +[1f5fe755abc] {jit-log-opt-loop +# Loop 0 : loop with 26 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 1) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f5fe92b8af] jit-log-opt-loop} +[1f5fe944ae5] {jit-backend +[1f5fee20651] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b565 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C254010000000049BB38B00C0A897F0000498B0B4883C10149BB38B00C0A897F000049890B4983F8010F85000000004883FE017206813E980700000F85000000004983FA000F850000000049BBA8F0B407897F00004D39DC0F8500000000488B56084881FA102700000F8D000000004989D44883E2024883FA000F85000000004983C403488B1425A0536B024883EA0148891425A0536B024883FA000F8C000000004C89BD70FFFFFF4C89B568FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4D89E749BB5DB4A007897F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DAE9CCFEFFFF49BB00B0A007897F000041FFD321383C343029241D180C08030600000049BB00B0A007897F000041FFD3383C18343029240C08030700000049BB00B0A007897F000041FFD329383C3430241808030800000049BB00B0A007897F000041FFD3383C3034241808030900000049BB00B0A007897F000041FFD3383C183424030A00000049BB00B0A007897F000041FFD3383C34241809030B00000049BB00B0A007897F000041FFD3383C34243107030C000000 +[1f5fee2e673] jit-backend-dump} +[1f5fee2f38d] {jit-backend-addr +Loop 1 ( #9 LOAD_FAST) has address 7f8907a0b631 to 7f8907a0b6f8 (bootstrap 7f8907a0b565) +[1f5fee312e3] jit-backend-addr} +[1f5fee320ed] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b575 +0 50FFFFFF +[1f5fee3e903] jit-backend-dump} +[1f5fee3fbff] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b655 +0 0C010000 +[1f5fee41579] jit-backend-dump} +[1f5fee421af] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b667 +0 17010000 +[1f5fee43835] jit-backend-dump} +[1f5fee44261] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b671 +0 28010000 +[1f5fee457c1] jit-backend-dump} +[1f5fee461a5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b684 +0 2F010000 +[1f5fee475d3] jit-backend-dump} +[1f5fee47f57] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b695 +0 37010000 +[1f5fee4933d] jit-backend-dump} +[1f5fee49cd9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6a6 +0 3D010000 +[1f5fee4b0ad] jit-backend-dump} +[1f5fee4ba4f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6c8 +0 33010000 +[1f5fee4cf61] jit-backend-dump} +[1f5fee4dc45] jit-backend} +[1f5fee4f3a9] {jit-log-opt-loop +# Loop 1 : entry bridge with 31 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10] +debug_merge_point(0, ' #9 LOAD_FAST') ++234: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10] ++244: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10] ++262: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p10] +debug_merge_point(0, ' #12 LOAD_CONST') ++272: guard_value(p3, ConstPtr(ptr14), descr=) [p1, p0, p3, p2, p5, p8, p10] +debug_merge_point(0, ' #15 COMPARE_OP') ++291: i15 = getfield_gc_pure(p8, descr=) ++295: i17 = int_lt(i15, 10000) +guard_true(i17, descr=) [p1, p0, p8, p2, p5] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++308: i19 = int_and(i15, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++315: i20 = int_is_true(i19) +guard_false(i20, descr=) [p1, p0, p2, p5, p8, i19] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++325: i22 = int_add(i15, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++329: i24 = getfield_raw(40588192, descr=) ++337: i26 = int_sub(i24, 1) ++341: setfield_raw(40588192, i26, descr=) ++349: i28 = int_lt(i26, 0) +guard_false(i28, descr=) [p1, p0, p2, p5, i22, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++359: jump(p0, p1, p2, p5, i22, descr=) ++403: --end of the loop-- +[1f60036d952] jit-log-opt-loop} +[1f600719a74] {jit-backend +[1f600759dac] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b817 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB40B00C0A897F00004D8B334983C60149BB40B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF024C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030D00000049BB00B0A007897F000041FFD34440484C3D39030E00000049BB00B0A007897F000041FFD34440484C390707030F000000 +[1f60076fd90] jit-backend-dump} +[1f600770f30] {jit-backend-addr +Loop 2 ( #9 LOAD_FAST) has address 7f8907a0b89f to 7f8907a0b905 (bootstrap 7f8907a0b817) +[1f6007730fc] jit-backend-addr} +[1f600773fde] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b827 +0 50FFFFFF +[1f600775c76] jit-backend-dump} +[1f600776a38] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8c6 +0 95000000 +[1f600778112] jit-backend-dump} +[1f600778b8c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8d7 +0 9B000000 +[1f60077a04a] jit-backend-dump} +[1f60077aa6a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8f9 +0 91000000 +[1f60077bf10] jit-backend-dump} +[1f60077cc24] jit-backend} +[1f60077e094] {jit-log-opt-loop +# Loop 2 : loop with 25 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 2) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f6007a567c] jit-log-opt-loop} +[1f600802cd6] {jit-backend +[1f600862dd8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9b7 +0 488DA50000000049BB48B00C0A897F00004D8B3B4983C70149BB48B00C0A897F00004D893B4D89F74983C6010F80000000004C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C00000000488B0425704F3D01488D5010483B1425784F3D01761A49BB10B2A007897F000041FFD349BB8EB2A007897F000041FFD348C7009807000048891425704F3D014C89700848898550FFFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBA8F0B407897F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00100000048C7C709000000488BB550FFFFFF48C7C30000000048C7C20000000049BB31B6A007897F000041FFE349BB00B0A007897F000041FFD3444039484C3D031000000049BB00B0A007897F000041FFD34440484C39070311000000 +[1f60086ba5a] jit-backend-dump} +[1f60086d36e] {jit-backend-addr +Bridge out of guard 4 has address 7f8907a0b9b7 to 7f8907a0bab1 +[1f60086ffd2] jit-backend-addr} +[1f600870dca] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9ba +0 C0FEFFFF +[1f60087281c] jit-backend-dump} +[1f600873506] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 C8000000 +[1f600874b44] jit-backend-dump} +[1f6008754d4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0ba03 +0 C2000000 +[1f600876956] jit-backend-dump} +[1f600877b1a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 1E050000 +[1f600878f4e] jit-backend-dump} +[1f600884c12] jit-backend} +[1f60088780a] {jit-log-opt-bridge +# bridge out of Guard 4 with 16 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #31 LOAD_FAST') +debug_merge_point(0, ' #34 LOAD_CONST') +debug_merge_point(0, ' #37 INPLACE_ADD') ++37: i7 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i7, p2, p3, i5] +debug_merge_point(0, ' #38 STORE_FAST') +debug_merge_point(0, ' #41 JUMP_ABSOLUTE') ++50: i9 = getfield_raw(40588192, descr=) ++58: i11 = int_sub(i9, 1) ++62: setfield_raw(40588192, i11, descr=) ++70: i13 = int_lt(i11, 0) +guard_false(i13, descr=) [p0, p1, p2, p3, i7, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++80: p16 = new_with_vtable(ConstClass(W_IntObject)) ++143: setfield_gc(p16, i7, descr=) ++147: jump(p1, p0, p2, ConstPtr(ptr17), 0, p3, 1, 9, p16, ConstPtr(ptr21), ConstPtr(ptr22), descr=) ++250: --end of the loop-- +[1f6008aa976] jit-log-opt-bridge} +[1f600912c98] {jit-backend-counts +0:1982 +1:1985 +2:0 +3:1782 +[1f600916544] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -213,4 +213,15 @@ def test_import_log(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) + for loop in loops: + loop.force_asm() assert 'jge' in loops[0].operations[3].asm + +def test_import_log_2(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest2.log'))) + for loop in loops: + loop.force_asm() + assert 'cmp' in loops[1].operations[1].asm + # bridge + assert 'jo' in loops[3].operations[3].asm diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1824,6 +1824,11 @@ __gccallshapes: """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) + print >> output, """\ + #if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits + #endif + """ def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs --- a/pypy/translator/cli/src/pypylib.cs +++ b/pypy/translator/cli/src/pypylib.cs @@ -615,10 +615,28 @@ return s1.StartsWith(s2); } + public static bool ll_startswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[0] == c; + } + public static bool ll_endswith(string s1, string s2) { return s1.EndsWith(s2); } + + public static bool ll_endswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[s.Length - 1] == c; + } public static int ll_find(string s1, string s2, int start, int stop) { diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -791,6 +791,20 @@ return str.substring(start,start+cnt); } + public static boolean ll_startswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(0) == c; + } + + public static boolean ll_endswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(str.length() - 1) == c; + } + // ---------------------------------------------------------------------- // StringBuffer From noreply at buildbot.pypy.org Sat Jul 16 20:49:15 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Sat, 16 Jul 2011 20:49:15 +0200 (CEST) Subject: [pypy-commit] pypy numpy-setslice: numpy: setslice added but doesn't work correctly for setting a slice of a slice yet Message-ID: <20110716184915.1B24382962@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-setslice Changeset: r45685:9d55cebe8768 Date: 2011-07-16 12:49 -0600 http://bitbucket.org/pypy/pypy/changeset/9d55cebe8768/ Log: numpy: setslice added but doesn't work correctly for setting a slice of a slice yet diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,6 +21,8 @@ reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) class Signature(object): def __init__(self): @@ -255,10 +257,18 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().setitem(start, + space.float_w(w_value)) + else: + self.get_concrete().setslice(space, start, stop, step, + slice_length, w_value) def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) @@ -407,8 +417,8 @@ return self.parent.getitem(self.calc_index(item)) @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - return self.parent.descr_setitem(space, self.calc_index(item), value) + def setitem(self, item, value): + return self.parent.setitem(self.calc_index(item), value) def descr_len(self, space): return space.wrap(self.find_size()) @@ -430,6 +440,47 @@ def find_size(self): return self.size + def _sliceloop1(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.parent.setitem(i, arr.eval(j)) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.parent.setitem(i, arr.eval(j)) + j += 1 + i += step + + def setslice(self, space, start, stop, step, slice_length, arr): + # can't set a slice of a slice yet + if stop < 0: + stop += self.find_size() + if step > 0: + stop = min(stop, self.find_size()) + else: + stop = max(stop, 0) + arr = convert_to_array(space, arr) + start = self.calc_index(start) + stop = self.calc_index(stop) + step = self.step * step + if step > 0: + self._sliceloop1(start, stop, step, arr) + else: + self._sliceloop2(start, stop, step, arr) + def calc_index(self, item): return (self.start + item * self.step) @@ -453,7 +504,7 @@ def eval(self, i): return self.storage[i] - def getindex(self, space, item): + def getindex(self, item): if item >= self.size: raise operationerrfmt(space.w_IndexError, '%d above array size', item) @@ -471,11 +522,50 @@ return self.storage[item] @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - item = self.getindex(space, item) + def setitem(self, item, value): + item = self.getindex(item) self.invalidated() self.storage[item] = value + def _sliceloop1(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def setslice(self, space, start, stop, step, slice_length, arr): + i = start + if stop < 0: + stop += self.find_size() + if step > 0: + stop = min(stop, self.find_size()) + else: + stop = max(stop, 0) + if not isinstance(arr, BaseArray): + arr = convert_to_array(space, arr) + if step > 0: + self._sliceloop1(start, stop, step, arr) + else: + self._sliceloop2(start, stop, step, arr) + def __del__(self): lltype.free(self.storage, flavor='raw') diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -60,6 +60,34 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + # a[1:4:2][::-1] = b # does not work yet + c=a[1:4:2][::-1] + c[:] = b + assert a[1] == 1. + assert a[3] == 0. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -5,6 +5,7 @@ from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): w_ValueError = None @@ -248,6 +249,21 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar.setslice(space, 0, step*i, step, i, ar2) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) From noreply at buildbot.pypy.org Sat Jul 16 22:00:04 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 22:00:04 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: proper invalidation for the array cache Message-ID: <20110716200004.37BA982962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45686:420fc8c6b8cd Date: 2011-07-16 21:27 +0200 http://bitbucket.org/pypy/pypy/changeset/420fc8c6b8cd/ Log: proper invalidation for the array cache diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -391,7 +391,6 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): cache = self.metainterp.heap_array_cache.get(arraydescr, None) - index = -1 if cache and isinstance(indexbox, ConstInt): index = indexbox.getint() frombox, tobox = cache.get(index, (None, None)) @@ -399,9 +398,10 @@ return tobox resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) - if index >= 0: + if isinstance(indexbox, ConstInt): if not cache: cache = self.metainterp.heap_array_cache[arraydescr] = {} + index = indexbox.getint() cache[index] = arraybox, resbox return resbox @@ -1671,10 +1671,13 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) - if (self.heap_cache and opnum != rop.SETFIELD_GC and + if (opnum != rop.SETFIELD_GC and opnum != rop.SETARRAYITEM_GC): if not (rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST): - self.heap_cache = {} + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -184,3 +184,27 @@ res = self.interp_operations(fn, [-7, 1, 1]) assert res == -7 * 2 self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + From noreply at buildbot.pypy.org Sat Jul 16 22:00:05 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 22:00:05 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: a passing test Message-ID: <20110716200005.5F23382962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45687:ca2a85b7eef9 Date: 2011-07-16 21:50 +0200 http://bitbucket.org/pypy/pypy/changeset/ca2a85b7eef9/ Log: a passing test diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -208,3 +208,27 @@ assert res == 5 * 2 + 7 self.check_operations_history(getarrayitem_gc=1) + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + From noreply at buildbot.pypy.org Sat Jul 16 22:00:06 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 16 Jul 2011 22:00:06 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: make promotion influence the heap cache Message-ID: <20110716200006.8CCF082962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45688:22dc9cdf9e06 Date: 2011-07-16 21:59 +0200 http://bitbucket.org/pypy/pypy/changeset/22dc9cdf9e06/ Log: make promotion influence the heap cache diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -2354,6 +2354,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -232,3 +232,27 @@ self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, getarrayitem_gc=0, getfield_gc=1) + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) From noreply at buildbot.pypy.org Sat Jul 16 22:07:11 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 22:07:11 +0200 (CEST) Subject: [pypy-commit] benchmarks default: oops Message-ID: <20110716200711.BB83D82962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r126:0893b0a1eea4 Date: 2011-07-16 22:07 +0200 http://bitbucket.org/pypy/benchmarks/changeset/0893b0a1eea4/ Log: oops diff --git a/saveresults.py b/saveresults.py --- a/saveresults.py +++ b/saveresults.py @@ -8,7 +8,7 @@ SPEEDURL = "http://speed.pypy.org/" -def save(project, revision, results, options, interpreter, host, testing=True, +def save(project, revision, results, options, interpreter, host, testing=False, changed=True): testparams = [] #Parse data From noreply at buildbot.pypy.org Sat Jul 16 23:21:54 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 23:21:54 +0200 (CEST) Subject: [pypy-commit] benchmarks default: add a postfix parameter Message-ID: <20110716212154.7E06582962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r127:846fa56a282b Date: 2011-07-16 23:21 +0200 http://bitbucket.org/pypy/benchmarks/changeset/846fa56a282b/ Log: add a postfix parameter diff --git a/runner.py b/runner.py --- a/runner.py +++ b/runner.py @@ -9,13 +9,13 @@ import socket def perform_upload(pypy_c_path, args, force_host, options, res, revision, - changed=True): + changed=True, postfix=''): from saveresults import save project = 'PyPy' if "--jit" in args: - name = "pypy-c" + name = "pypy-c" + postfix else: - name = "pypy-c-jit" + name = "pypy-c-jit" + postfix if "psyco.sh" in pypy_c_path: name = "cpython psyco-profile" revision = 100 @@ -30,7 +30,7 @@ def run_and_store(benchmark_set, result_filename, pypy_c_path, revision=0, options='', branch='trunk', args='', upload=False, force_host=None, fast=False, baseline=sys.executable, - full_store=False): + full_store=False, postfix=''): funcs = perf.BENCH_FUNCS.copy() funcs.update(perf._FindAllBenchmarks(benchmarks.__dict__)) opts = ['-b', ','.join(benchmark_set), '--inherit_env=PATH', @@ -60,9 +60,9 @@ argsbase, argschanged = args, args if 'pypy' in baseline: perform_upload(pypy_c_path, argsbase, force_host, options, res, - revision, changed=False) + revision, changed=False, postfix=postfix) perform_upload(pypy_c_path, argschanged, force_host, options, res, - revision, changed=True) + revision, changed=True, postfix=postfix) BENCHMARK_SET = ['richards', 'slowspitfire', 'django', 'spambayes', 'rietveld', 'html5lib', 'ai'] @@ -110,6 +110,8 @@ help="Run shorter benchmark runs") parser.add_option("--full-store", default=False, action="store_true", help="") + parser.add_option('--postfix', default='', action='store', + help='Append a postfix to uploaded executable') options, args = parser.parse_args(argv) benchmarks = options.benchmarks.split(',') for benchmark in benchmarks: @@ -118,7 +120,8 @@ run_and_store(benchmarks, options.output_filename, options.pypy_c, options.revision, args=options.args, upload=options.upload, force_host=options.force_host, fast=options.fast, - baseline=options.baseline, full_store=options.full_store) + baseline=options.baseline, full_store=options.full_store, + postfix=options.postfix) if __name__ == '__main__': main(sys.argv[1:]) From noreply at buildbot.pypy.org Sat Jul 16 23:22:54 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 23:22:54 +0200 (CEST) Subject: [pypy-commit] buildbot default: change the URL to the canonical one. will revert if it breaks stuff Message-ID: <20110716212254.C0E2082962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r530:3ca6784afb86 Date: 2011-07-16 18:35 +0200 http://bitbucket.org/pypy/buildbot/changeset/3ca6784afb86/ Log: change the URL to the canonical one. will revert if it breaks stuff diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py --- a/bot2/pypybuildbot/master.py +++ b/bot2/pypybuildbot/master.py @@ -338,6 +338,6 @@ }, ], - 'buildbotURL': 'http://wyvern.cs.uni-duesseldorf.de:%d/'%(httpPortNumber), + 'buildbotURL': 'http://buildbot.pypy.org), 'projectURL': 'http://pypy.org/', 'projectName': 'PyPy'} From noreply at buildbot.pypy.org Sat Jul 16 23:22:55 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 23:22:55 +0200 (CEST) Subject: [pypy-commit] buildbot default: enable nightly builds of pypy-c-64bit Message-ID: <20110716212255.CFE7E82962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r531:9f67b389b4fa Date: 2011-07-16 23:22 +0200 http://bitbucket.org/pypy/buildbot/changeset/9f67b389b4fa/ Log: enable nightly builds of pypy-c-64bit diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -277,7 +277,7 @@ blocksize=100*1024)) class JITBenchmark(factory.BuildFactory): - def __init__(self, platform='linux'): + def __init__(self, platform='linux', host='tannit', postfix=None): factory.BuildFactory.__init__(self) setup_steps(platform, self) @@ -287,15 +287,20 @@ workdir='.')) self.addStep(Translate(['-Ojit'], [])) pypy_c_rel = "../build/pypy/translator/goal/pypy-c" + if postfix: + addopts = ['--postfix', postfix] + else: + addopts = None self.addStep(ShellCmd( description="run benchmarks on top of pypy-c", command=["python", "runner.py", '--output-filename', 'result.json', '--pypy-c', pypy_c_rel, '--baseline', pypy_c_rel, '--args', ',--jit off', - '--upload', #'--force-host', 'bigdog', + '--upload', '--revision', WithProperties('%(got_revision)s'), - '--branch', WithProperties('%(branch)s')], + '--branch', WithProperties('%(branch)s'), + ] + addopts, workdir='./benchmarks', haltOnFailure=True)) # a bit obscure hack to get both os.path.expand and a property @@ -303,14 +308,3 @@ self.addStep(transfer.FileUpload(slavesrc="benchmarks/result.json", masterdest=WithProperties(resfile), workdir=".")) - -## self.addStep(ShellCmd( -## description="run on top of python with psyco", -## command=["python", "runner.py", '--output-filename', 'result.json', -## '--pypy-c', 'psyco/python_with_psyco.sh', -## '--revision', WithProperties('%(got_revision)s'), -## '--upload', #'--force-host', 'bigdog', -## '--branch', WithProperties('%(branch)s'), -## ], -## workdir='./benchmarks', -## haltOnFailure=True)) diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py --- a/bot2/pypybuildbot/master.py +++ b/bot2/pypybuildbot/master.py @@ -180,6 +180,8 @@ ) pypyJITBenchmarkFactory = pypybuilds.JITBenchmark() +pypyJITBenchmarkFactory64 = pypybuilds.JITBenchmark(platform='linux64', + postfix='-64') LINUX32 = "own-linux-x86-32" LINUX64 = "own-linux-x86-64" @@ -200,16 +202,20 @@ JITONLYLINUX32 = "jitonly-own-linux-x86-32" JITBENCH = "jit-benchmark-linux-x86-32" +JITBENCH64 = "jit-benchmark-linux-x86-64" BuildmasterConfig = { 'slavePortnum': slavePortnum, 'change_source': [], 'schedulers': [ - Nightly("nightly-0-45", [ + Nightly("nightly-0-00", [ JITBENCH, # on tannit -- nothing else there during first round! MACOSX32, # on minime - ], hour=0, minute=45), + ], hour=0, minute=0), + Nightly("nighly-2-00", [ + JITBENCH64, # on tannit -- nothing else there during first round! + ], hour=2, minute=0), Nightly("nightly-4-00", [ # rule: what we pick here on tannit should take at most 8 cores # and be hopefully finished after 2 hours @@ -336,6 +342,12 @@ "factory": pypyJITBenchmarkFactory, "category": 'benchmark-run', }, + {"name": JITBENCH64, + "slavenames": ["tannit64"], + "builddir": JITBENCH64, + "factory": pypyJITBenchmarkFactory64, + "category": "benchmark-run", + }, ], 'buildbotURL': 'http://buildbot.pypy.org), From noreply at buildbot.pypy.org Sat Jul 16 23:24:24 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 23:24:24 +0200 (CEST) Subject: [pypy-commit] buildbot default: typo Message-ID: <20110716212424.9AE2482962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r532:ada781d23a2d Date: 2011-07-16 23:24 +0200 http://bitbucket.org/pypy/buildbot/changeset/ada781d23a2d/ Log: typo diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py --- a/bot2/pypybuildbot/master.py +++ b/bot2/pypybuildbot/master.py @@ -350,6 +350,6 @@ }, ], - 'buildbotURL': 'http://buildbot.pypy.org), + 'buildbotURL': 'http://buildbot.pypy.org', 'projectURL': 'http://pypy.org/', 'projectName': 'PyPy'} From noreply at buildbot.pypy.org Sat Jul 16 23:25:05 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 16 Jul 2011 23:25:05 +0200 (CEST) Subject: [pypy-commit] buildbot default: another fix Message-ID: <20110716212505.B267B82962@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r533:00b2db6f1765 Date: 2011-07-16 23:24 +0200 http://bitbucket.org/pypy/buildbot/changeset/00b2db6f1765/ Log: another fix diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -290,7 +290,7 @@ if postfix: addopts = ['--postfix', postfix] else: - addopts = None + addopts = [] self.addStep(ShellCmd( description="run benchmarks on top of pypy-c", command=["python", "runner.py", '--output-filename', 'result.json', From noreply at buildbot.pypy.org Sun Jul 17 00:38:04 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sun, 17 Jul 2011 00:38:04 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: make new construction go via the normal setfield code Message-ID: <20110716223804.B4E4D82966@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45690:34414cbab3ef Date: 2011-07-17 00:22 +0200 http://bitbucket.org/pypy/pypy/changeset/34414cbab3ef/ Log: make new construction go via the normal setfield code diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -474,12 +474,10 @@ def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, - sbox, sizebox) + self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox) abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, sizebox) - self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, - sbox, abox) + self._opimpl_setfield_gc_any(sbox, itemsdescr, abox) return sbox @arguments("box", "descr", "descr", "box") diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -300,3 +300,18 @@ assert res == -7 * 2 self.check_operations_history(getarrayitem_gc=1, getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + jit.promote(n) + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) From noreply at buildbot.pypy.org Sun Jul 17 00:38:05 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sun, 17 Jul 2011 00:38:05 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: make virtualizable code delegate to default implementations to get the right Message-ID: <20110716223805.E3E0482966@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45691:823933ada2fb Date: 2011-07-17 00:37 +0200 http://bitbucket.org/pypy/pypy/changeset/823933ada2fb/ Log: make virtualizable code delegate to default implementations to get the right caching effect. diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -683,10 +683,8 @@ @arguments("orgpc", "box", "descr", "descr", "box") def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr, - arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox) self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) return self.metainterp.virtualizable_boxes[index] @@ -699,10 +697,9 @@ def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox, valuebox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - self.execute_with_descr(rop.SETARRAYITEM_GC, adescr, - arraybox, indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + self._opimpl_setarrayitem_gc_any(arraybox, adescr, + indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -315,3 +315,45 @@ assert res == 7 + 7 + 1 self.check_operations_history(setarrayitem_gc=2, setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * 4 + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) From noreply at buildbot.pypy.org Sun Jul 17 00:38:03 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sun, 17 Jul 2011 00:38:03 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: make sure the stuff works with resizable lists too Message-ID: <20110716223803.873B782962@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45689:160b69e37ce6 Date: 2011-07-16 23:04 +0200 http://bitbucket.org/pypy/pypy/changeset/160b69e37ce6/ Log: make sure the stuff works with resizable lists too diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -485,10 +485,8 @@ @arguments("box", "descr", "descr", "box") def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox) opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any @@ -497,10 +495,9 @@ @arguments("box", "descr", "descr", "box", "box") def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, - indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox, + valuebox) opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -256,3 +256,47 @@ assert res == 7 * 2 + 1 self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) From noreply at buildbot.pypy.org Sun Jul 17 04:03:13 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 17 Jul 2011 04:03:13 +0200 (CEST) Subject: [pypy-commit] pypy default: name this something useful. Message-ID: <20110717020313.751B682962@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45692:a279306f0a8e Date: 2011-07-16 19:03 -0700 http://bitbucket.org/pypy/pypy/changeset/a279306f0a8e/ Log: name this something useful. diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4553,7 +4553,7 @@ """ self.optimize_loop(ops, expected) - def test_strslice_with_other_stuff(self): + def test_strslice_subtraction_folds(self): ops = """ [p0, i0] i1 = int_add(i0, 1) From noreply at buildbot.pypy.org Sun Jul 17 04:07:24 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 17 Jul 2011 04:07:24 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: Another thing I keep seeing. Message-ID: <20110717020724.E829A82962@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3833:44e83b7f5d3d Date: 2011-07-16 19:07 -0700 http://bitbucket.org/pypy/extradoc/changeset/44e83b7f5d3d/ Log: Another thing I keep seeing. diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -80,6 +80,16 @@ maybe we should move promote even higher, before the first use and we could possibly remove more stuff? + This shows up in another way as well, the Python code + + if x is None: + i += x + + We promote the guard_nonnull when we load x into guard_nonnull class, + however this happens after the optimizer sees `x is None`, so that ptr_eq + still remains, even though it's obviously not necessary since x and None + will have different known_classes. + - f31 = f17 * f16 f32 = f16 * f17 From noreply at buildbot.pypy.org Sun Jul 17 04:07:26 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 17 Jul 2011 04:07:26 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: merged upstream Message-ID: <20110717020726.2132282962@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3834:b9f7d7a21139 Date: 2011-07-16 19:07 -0700 http://bitbucket.org/pypy/extradoc/changeset/b9f7d7a21139/ Log: merged upstream diff --git a/sprintinfo/ddorf2011-cppyy/planning.txt b/sprintinfo/ddorf2011-cppyy/planning.txt new file mode 100644 --- /dev/null +++ b/sprintinfo/ddorf2011-cppyy/planning.txt @@ -0,0 +1,25 @@ +people: + + - Sven + - Armin + - Carl Friedrich + - Wim + - Lukas + - David + +tasks: + +cppyy + - memory management + - split between rpython/python (Carl Friedrich) + - fast path improvements DONE + - test fast path (Carl Friedrich) + - global data members + - code duplication: IN PROGRESS + - array problems: IN PROGRESS (Armin, Wim) + + +auxilliary tasks + + - look more into PPC (Sven, David) + - list/set improvements (Lukas) From noreply at buildbot.pypy.org Sun Jul 17 04:36:02 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 17 Jul 2011 04:36:02 +0200 (CEST) Subject: [pypy-commit] pypy default: synthesize reverse operations for float multiplcatoin. Message-ID: <20110717023602.BDEAF82962@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45693:3468fc4c3e4a Date: 2011-07-16 19:35 -0700 http://bitbucket.org/pypy/pypy/changeset/3468fc4c3e4a/ Log: synthesize reverse operations for float multiplcatoin. diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -199,6 +199,7 @@ )) return self.emit_operation(op) + self.pure(rop.FLOAT_MUL, [arg2, arg1], op.result) def optimize_FLOAT_NEG(self, op): v1 = op.getarg(0) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4572,6 +4572,20 @@ """ self.optimize_strunicode_loop(ops, expected) + def test_float_mul_reversed(self): + ops = """ + [f0, f1] + f2 = float_mul(f0, f1) + f3 = float_mul(f1, f0) + jump(f2, f3) + """ + expected = """ + [f0, f1] + f2 = float_mul(f0, f1) + jump(f2, f2) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass From noreply at buildbot.pypy.org Sun Jul 17 06:50:46 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 17 Jul 2011 06:50:46 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: did this. Message-ID: <20110717045046.3DC1B820AA@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3835:58e1c1b75f8a Date: 2011-07-16 21:48 -0700 http://bitbucket.org/pypy/extradoc/changeset/58e1c1b75f8a/ Log: did this. diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -80,11 +80,6 @@ maybe we should move promote even higher, before the first use and we could possibly remove more stuff? -- f31 = f17 * f16 - f32 = f16 * f17 - - Should be just a matter of synthesizing reverse operations in rewrite.py - - optimize arraycopy also in the cases where one of the arrays is a virtual and short. This is seen a lot in translate.py From noreply at buildbot.pypy.org Sun Jul 17 06:50:47 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 17 Jul 2011 06:50:47 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: mergec upstream. Message-ID: <20110717045047.67DDD820AA@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3836:ec767df04faa Date: 2011-07-16 21:50 -0700 http://bitbucket.org/pypy/extradoc/changeset/ec767df04faa/ Log: mergec upstream. diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -80,6 +80,16 @@ maybe we should move promote even higher, before the first use and we could possibly remove more stuff? + This shows up in another way as well, the Python code + + if x is None: + i += x + + We promote the guard_nonnull when we load x into guard_nonnull class, + however this happens after the optimizer sees `x is None`, so that ptr_eq + still remains, even though it's obviously not necessary since x and None + will have different known_classes. + - optimize arraycopy also in the cases where one of the arrays is a virtual and short. This is seen a lot in translate.py diff --git a/sprintinfo/ddorf2011-cppyy/planning.txt b/sprintinfo/ddorf2011-cppyy/planning.txt new file mode 100644 --- /dev/null +++ b/sprintinfo/ddorf2011-cppyy/planning.txt @@ -0,0 +1,25 @@ +people: + + - Sven + - Armin + - Carl Friedrich + - Wim + - Lukas + - David + +tasks: + +cppyy + - memory management + - split between rpython/python (Carl Friedrich) + - fast path improvements DONE + - test fast path (Carl Friedrich) + - global data members + - code duplication: IN PROGRESS + - array problems: IN PROGRESS (Armin, Wim) + + +auxilliary tasks + + - look more into PPC (Sven, David) + - list/set improvements (Lukas) From noreply at buildbot.pypy.org Sun Jul 17 09:09:59 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sun, 17 Jul 2011 09:09:59 +0200 (CEST) Subject: [pypy-commit] pypy default: add an XXX Message-ID: <20110717070959.F3B37820AA@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45694:546ae03a77b7 Date: 2011-07-17 09:09 +0200 http://bitbucket.org/pypy/pypy/changeset/546ae03a77b7/ Log: add an XXX diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -1118,6 +1118,9 @@ return meth(op, args, *descrs) def _get_list_nonneg_canraise_flags(self, op): + # XXX as far as I can see, this function will always return True + # because functions that are neither nonneg nor fast don't have an + # oopspec any more # xxx break of abstraction: func = get_funcobj(op.args[0].value)._callable # base hints on the name of the ll function, which is a bit xxx-ish From noreply at buildbot.pypy.org Sun Jul 17 11:06:41 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sun, 17 Jul 2011 11:06:41 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: fix len(virtualizable.array) Message-ID: <20110717090641.24CBE820AA@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45695:c5da400baff3 Date: 2011-07-17 08:02 +0200 http://bitbucket.org/pypy/pypy/changeset/c5da400baff3/ Log: fix len(virtualizable.array) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -713,8 +713,7 @@ @arguments("orgpc", "box", "descr", "descr") def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -325,7 +325,7 @@ def __init__(self, a, s): self = jit.hint(self, access_directly=True, fresh_virtualizable=True) - self.l = [0] * 4 + self.l = [0] * (4 + a) self.s = s def f(n, a, i): @@ -335,7 +335,7 @@ frame.l[2] = a + 2 frame.l[3] = a + 3 if not i: - return frame.l[0] + return frame.l[0] + len(frame.l) x = 0 while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) From noreply at buildbot.pypy.org Sun Jul 17 11:06:42 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sun, 17 Jul 2011 11:06:42 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: caching for pure ops Message-ID: <20110717090642.55ED2820AA@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45696:559198bd1ea6 Date: 2011-07-17 09:31 +0200 http://bitbucket.org/pypy/pypy/changeset/559198bd1ea6/ Log: caching for pure ops diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -517,23 +517,29 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) - if frombox is box: - return tobox - resbox = self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) - self.metainterp.heap_cache[fielddescr] = (box, resbox) - return resbox + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC, box, fielddescr) opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @arguments("box", "descr") def _opimpl_getfield_gc_pure_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_PURE, box, fielddescr) opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any + @specialize.arg(1) + def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(opnum, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox + @arguments("orgpc", "box", "descr") def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr): ginfo = self.metainterp.jitdriver_sd.greenfield_info diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -303,7 +303,6 @@ def test_list_caching_negative(self): def fn(n): - jit.promote(n) a = [0] * n if n > 1000: a.append(0) @@ -357,3 +356,25 @@ res = self.meta_interp(f, [10, 1, 1], listops=True) assert res == f(10, 1, 1) self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) From noreply at buildbot.pypy.org Sun Jul 17 11:28:27 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 17 Jul 2011 11:28:27 +0200 (CEST) Subject: [pypy-commit] pypy default: merge numpy-str-repr Message-ID: <20110717092827.66114820AA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45697:05ceb71b63ac Date: 2011-07-17 11:27 +0200 http://bitbucket.org/pypy/pypy/changeset/05ceb71b63ac/ Log: merge numpy-str-repr diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -244,6 +244,12 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_repr(self, space): + return self.get_concrete()._repr(space) + + def descr_str(self, space): + return self.get_concrete()._str(space) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -433,6 +439,26 @@ def calc_index(self, item): return (self.start + item * self.step) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + class SingleDimArray(BaseArray): signature = Signature() @@ -470,6 +496,26 @@ def getitem(self, item): return self.storage[item] + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) @@ -527,6 +573,8 @@ __rdiv__ = interp2app(BaseArray.descr_rdiv), __rpow__ = interp2app(BaseArray.descr_rpow), __rmod__ = interp2app(BaseArray.descr_rmod), + __repr__ = interp2app(BaseArray.descr_repr), + __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), sum = interp2app(BaseArray.descr_sum), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -43,6 +43,38 @@ a = array(range(5)) assert a[3] == 3 + def test_repr(self): + from numpy import array, zeros + a = array(range(5)) + assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" + a = zeros(1001) + assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_repr_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert repr(b) == "array([1.0, 3.0])" + a = zeros(2002) + b = a[::2] + assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_str(self): + from numpy import array, zeros + a = array(range(5)) + assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + a = zeros(1001) + assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + + def test_str_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert str(b) == "[1.0 3.0]" + a = zeros(2002) + b = a[::2] + assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_getitem(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Sun Jul 17 11:28:28 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 17 Jul 2011 11:28:28 +0200 (CEST) Subject: [pypy-commit] pypy numpy-repr-str: close merged branch Message-ID: <20110717092828.90DC3820AA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: numpy-repr-str Changeset: r45698:8027075b9e9e Date: 2011-07-17 11:28 +0200 http://bitbucket.org/pypy/pypy/changeset/8027075b9e9e/ Log: close merged branch From noreply at buildbot.pypy.org Sun Jul 17 11:59:20 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sun, 17 Jul 2011 11:59:20 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: pothential rpython fix? Message-ID: <20110717095920.D71CF820AA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45699:0c4fd61358ff Date: 2011-07-17 11:58 +0200 http://bitbucket.org/pypy/pypy/changeset/0c4fd61358ff/ Log: pothential rpython fix? diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -454,7 +454,7 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode, op.result) + lengthbox = value.getstrlen(self, mode, lengthbox=op.result) if lengthbox is not op.result: self.make_equal_to(op.result, self.getvalue(lengthbox)) From noreply at buildbot.pypy.org Sun Jul 17 12:43:34 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 17 Jul 2011 12:43:34 +0200 (CEST) Subject: [pypy-commit] pypy default: allow negative offsets for now, should be reverted once we fix reporting Message-ID: <20110717104334.A04EA829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45700:c3294f3c5888 Date: 2011-07-17 12:43 +0200 http://bitbucket.org/pypy/pypy/changeset/c3294f3c5888/ Log: allow negative offsets for now, should be reverted once we fix reporting diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -336,10 +336,10 @@ log = parse_log_file(logname) addrs = {} for entry in extract_category(log, 'jit-backend-addr'): - m = re.search('bootstrap ([\da-f]+)', entry) + m = re.search('bootstrap ([-\da-f]+)', entry) if not m: # a bridge - m = re.search('has address ([\da-f]+)', entry) + m = re.search('has address ([-\da-f]+)', entry) addr = int(m.group(1), 16) entry = entry.lower() m = re.search('guard \d+', entry) From noreply at buildbot.pypy.org Sun Jul 17 12:52:32 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 17 Jul 2011 12:52:32 +0200 (CEST) Subject: [pypy-commit] jitviewer default: add a demo Message-ID: <20110717105232.BCB40829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r146:0a357b9257ac Date: 2011-07-17 12:52 +0200 http://bitbucket.org/pypy/jitviewer/changeset/0a357b9257ac/ Log: add a demo diff --git a/demo.py b/demo.py new file mode 100644 --- /dev/null +++ b/demo.py @@ -0,0 +1,24 @@ + +import re +from numpy import zeros + +def g(): + return 1 + +def loop(): + i = 0 + while i < 10000: + if i & 2: + i += g() + else: + i += 3 + +def other_loop(): + for i in range(2000): + re.search("0", str(i)) + +if __name__ == '__main__': + loop() + other_loop() + a = zeros(10000) + repr(a + a / a) From noreply at buildbot.pypy.org Mon Jul 18 00:02:12 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 18 Jul 2011 00:02:12 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream. Message-ID: <20110717220212.94E16829B9@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45702:a4096819e9eb Date: 2011-07-17 15:02 -0700 http://bitbucket.org/pypy/pypy/changeset/a4096819e9eb/ Log: merged upstream. diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -1118,6 +1118,9 @@ return meth(op, args, *descrs) def _get_list_nonneg_canraise_flags(self, op): + # XXX as far as I can see, this function will always return True + # because functions that are neither nonneg nor fast don't have an + # oopspec any more # xxx break of abstraction: func = get_funcobj(op.args[0].value)._callable # base hints on the name of the ll function, which is a bit xxx-ish diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -244,6 +244,12 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_repr(self, space): + return self.get_concrete()._repr(space) + + def descr_str(self, space): + return self.get_concrete()._str(space) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -433,6 +439,26 @@ def calc_index(self, item): return (self.start + item * self.step) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + class SingleDimArray(BaseArray): signature = Signature() @@ -470,6 +496,26 @@ def getitem(self, item): return self.storage[item] + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) @@ -527,6 +573,8 @@ __rdiv__ = interp2app(BaseArray.descr_rdiv), __rpow__ = interp2app(BaseArray.descr_rpow), __rmod__ = interp2app(BaseArray.descr_rmod), + __repr__ = interp2app(BaseArray.descr_repr), + __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), sum = interp2app(BaseArray.descr_sum), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -43,6 +43,38 @@ a = array(range(5)) assert a[3] == 3 + def test_repr(self): + from numpy import array, zeros + a = array(range(5)) + assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" + a = zeros(1001) + assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_repr_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert repr(b) == "array([1.0, 3.0])" + a = zeros(2002) + b = a[::2] + assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_str(self): + from numpy import array, zeros + a = array(range(5)) + assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + a = zeros(1001) + assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + + def test_str_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert str(b) == "[1.0 3.0]" + a = zeros(2002) + b = a[::2] + assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_getitem(self): from numpy import array a = array(range(5)) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -336,10 +336,10 @@ log = parse_log_file(logname) addrs = {} for entry in extract_category(log, 'jit-backend-addr'): - m = re.search('bootstrap ([\da-f]+)', entry) + m = re.search('bootstrap ([-\da-f]+)', entry) if not m: # a bridge - m = re.search('has address ([\da-f]+)', entry) + m = re.search('has address ([-\da-f]+)', entry) addr = int(m.group(1), 16) entry = entry.lower() m = re.search('guard \d+', entry) From noreply at buildbot.pypy.org Mon Jul 18 00:02:11 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 18 Jul 2011 00:02:11 +0200 (CEST) Subject: [pypy-commit] pypy default: Use absolute imports, and add back a test that was lost. Message-ID: <20110717220211.682FA829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45701:52aa0420607b Date: 2011-07-17 14:52 -0700 http://bitbucket.org/pypy/pypy/changeset/52aa0420607b/ Log: Use absolute imports, and add back a test that was lost. diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py --- a/pypy/rpython/extfuncregistry.py +++ b/pypy/rpython/extfuncregistry.py @@ -1,6 +1,6 @@ # this registry uses the new interface for external functions -from extfunc import register_external +from pypy.rpython.extfunc import register_external # ___________________________ # math functions diff --git a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py --- a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py +++ b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py @@ -38,21 +38,21 @@ return getattr(math, name)(x, y) assert self.interpret(f, [0.3, 0.4]) == f(0.3, 0.4) return next_test - - for name in ll_math.unary_math_functions: + + for name in ll_math.unary_math_functions + ['sqrt']: func_name = 'test_%s' % (name,) next_test = new_unary_test(name) next_test.func_name = func_name locals()[func_name] = next_test del next_test - + for name in ['atan2', 'fmod', 'hypot', 'pow']: func_name = 'test_%s' % (name,) next_test = new_binary_test(name) next_test.func_name = func_name locals()[func_name] = next_test del next_test - + def test_ldexp(self): def f(x, y): return math.ldexp(x, y) From noreply at buildbot.pypy.org Mon Jul 18 00:19:04 2011 From: noreply at buildbot.pypy.org (brettsky) Date: Mon, 18 Jul 2011 00:19:04 +0200 (CEST) Subject: [pypy-commit] pypy default: (B. Cannon, A. Gaynor) Specialize math.log and math.log10. Message-ID: <20110717221904.236E9829B8@wyvern.cs.uni-duesseldorf.de> Author: Brett Cannon Branch: Changeset: r45703:522ca49e62aa Date: 2011-07-17 15:18 -0700 http://bitbucket.org/pypy/pypy/changeset/522ca49e62aa/ Log: (B. Cannon, A. Gaynor) Specialize math.log and math.log10. diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -185,6 +185,7 @@ Jim Baker Philip Jenvey Rodrigo Araújo + Brett Cannon Heinrich-Heine University, Germany Open End AB (formerly AB Strakt), Sweden diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -0,0 +1,32 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestMath(BaseTestPyPyC): + def test_log(self): + def main(n): + import math + + i = 1 + s = 0.0 + while i < n: + s += math.log(i) - math.log10(i) + i += 1 + return s + log = self.run(main, [500]) + assert round(log.result, 6) == round(main(500), 6) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i2 = int_lt(i0, i1) + guard_true(i2, descr=...) + guard_not_invalidated(descr=...) + f1 = cast_int_to_float(i0) + i3 = float_le(f1, 0) + guard_false(i3, descr=...) + f2 = call(ConstClass(log), f1) + f3 = call(ConstClass(log10), f1) + f4 = float_sub(f2, f3) + f5 = float_add(f0, f4) + i4 = int_add(i0, 1) + --TICK-- + jump(i4, i1, f5) + """) diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py --- a/pypy/rpython/extfuncregistry.py +++ b/pypy/rpython/extfuncregistry.py @@ -30,24 +30,28 @@ export_name="ll_math.ll_math_%s" % name, sandboxsafe=True, llimpl=llimpl) -register_external(rfloat.isinf, [float], bool, - export_name="ll_math.ll_math_isinf", sandboxsafe=True, - llimpl=ll_math.ll_math_isinf) -register_external(rfloat.isnan, [float], bool, - export_name="ll_math.ll_math_isnan", sandboxsafe=True, - llimpl=ll_math.ll_math_isnan) -register_external(rfloat.isfinite, [float], bool, - export_name="ll_math.ll_math_isfinite", sandboxsafe=True, - llimpl=ll_math.ll_math_isfinite) -register_external(rfloat.copysign, [float, float], float, - export_name="ll_math.ll_math_copysign", sandboxsafe=True, - llimpl=ll_math.ll_math_copysign) -register_external(math.floor, [float], float, - export_name="ll_math.ll_math_floor", sandboxsafe=True, - llimpl=ll_math.ll_math_floor) -register_external(math.sqrt, [float], float, - export_name="ll_math.ll_math_sqrt", sandboxsafe=True, - llimpl=ll_math.ll_math_sqrt) +_register = [ # (module, [(method name, arg types, return type), ...], ...) + (rfloat, [ + ('isinf', [float], bool), + ('isnan', [float], bool), + ('isfinite', [float], bool), + ('copysign', [float, float], float), + ]), + (math, [ + ('floor', [float], float), + ('sqrt', [float], float), + ('log', [float], float), + ('log10', [float], float), + ]), +] +for module, methods in _register: + for name, arg_types, return_type in methods: + method_name = 'll_math_%s' % name + register_external(getattr(module, name), arg_types, return_type, + export_name='ll_math.%s' % method_name, + sandboxsafe=True, + llimpl=getattr(ll_math, method_name)) + complex_math_functions = [ ('frexp', [float], (float, int)), diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -68,8 +68,9 @@ math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) - math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) +math_log = llexternal('log', [rffi.DOUBLE], rffi.DOUBLE) +math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -329,12 +330,22 @@ def ll_math_sqrt(x): if x < 0.0: raise ValueError, "math domain error" - + if isfinite(x): return sqrt_nonneg(x) return x # +inf or nan +def ll_math_log(x): + if x <= 0: + raise ValueError("math domain error") + return math_log(x) + +def ll_math_log10(x): + if x <= 0: + raise ValueError("math domain error") + return math_log10(x) + # ____________________________________________________________ # # Default implementations @@ -373,7 +384,7 @@ unary_math_functions = [ 'acos', 'asin', 'atan', 'ceil', 'cos', 'cosh', 'exp', 'fabs', - 'sin', 'sinh', 'tan', 'tanh', 'log', 'log10', + 'sin', 'sinh', 'tan', 'tanh', 'acosh', 'asinh', 'atanh', 'log1p', 'expm1', ] unary_math_functions_can_overflow = [ diff --git a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py --- a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py +++ b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py @@ -1,6 +1,4 @@ - -""" Just another bunch of tests for llmath, run on top of llinterp -""" +"""Just another bunch of tests for llmath, run on top of llinterp.""" from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin from pypy.rpython.lltypesystem.module import ll_math @@ -39,7 +37,7 @@ assert self.interpret(f, [0.3, 0.4]) == f(0.3, 0.4) return next_test - for name in ll_math.unary_math_functions + ['sqrt']: + for name in ll_math.unary_math_functions + ['log', 'log10', 'sqrt']: func_name = 'test_%s' % (name,) next_test = new_unary_test(name) next_test.func_name = func_name From noreply at buildbot.pypy.org Mon Jul 18 01:13:35 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 18 Jul 2011 01:13:35 +0200 (CEST) Subject: [pypy-commit] pypy default: Added the descrs to the JIT test from Brett's last commit, the actual resops were correct. Message-ID: <20110717231335.E4F59829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45704:983ca5a89054 Date: 2011-07-17 16:13 -0700 http://bitbucket.org/pypy/pypy/changeset/983ca5a89054/ Log: Added the descrs to the JIT test from Brett's last commit, the actual resops were correct. diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py --- a/pypy/module/pypyjit/test_pypy_c/test_math.py +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -22,11 +22,11 @@ f1 = cast_int_to_float(i0) i3 = float_le(f1, 0) guard_false(i3, descr=...) - f2 = call(ConstClass(log), f1) - f3 = call(ConstClass(log10), f1) + f2 = call(ConstClass(log), f1, descr=) + f3 = call(ConstClass(log10), f1, descr=) f4 = float_sub(f2, f3) f5 = float_add(f0, f4) i4 = int_add(i0, 1) --TICK-- - jump(i4, i1, f5) + jump(..., descr=) """) From noreply at buildbot.pypy.org Mon Jul 18 08:06:42 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Mon, 18 Jul 2011 08:06:42 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ndim-size: Added a bounds check on binary operations. Message-ID: <20110718060642.99EB5829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-ndim-size Changeset: r45705:76e17925faf1 Date: 2011-07-17 23:53 -0600 http://bitbucket.org/pypy/pypy/changeset/76e17925faf1/ Log: Added a bounds check on binary operations. diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -4,6 +4,7 @@ """ from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.rlib.objectmodel import specialize class BogusBytecode(Exception): pass @@ -15,8 +16,11 @@ return a class TrivialSpace(object): - def wrap(self, x): - return x + w_ValueError = None + + @specialize.argtype(1) + def wrap(self, w_obj): + return w_obj def numpy_compile(bytecode, array_size): space = TrivialSpace() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -88,6 +88,18 @@ signature = Signature() def impl(self, space, w_other): w_other = convert_to_array(space, w_other) + try: + w_other_size = w_other.find_size() + self_size = self.find_size() + except ValueError: + # this will be raised if one of the arrays is a scalar. + pass + else: + # Need a better dimension check here for N-dim arrays + if w_other_size != self_size: + raise OperationError(space.w_ValueError, + space.wrap("Cannot %s arrays of unequal dimensions" \ + % function.__name__)) new_sig = self.signature.transition(signature) res = Call2( function, diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -18,8 +18,8 @@ def test_slice_signature(self, space): ar = SingleDimArray(10) - v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1))) - v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1))) + v1 = ar.descr_getitem(space, space.wrap(slice(0, 10, 1))) + v2 = ar.descr_getitem(space, space.wrap(slice(9, None, -1))) assert v1.signature is v2.signature v3 = ar.descr_add(space, v1) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -120,6 +120,12 @@ for i in range(5): assert c[i] == 4 + def test_add_unequal_size(self): + from numpy import array + a = array(range(5)) + b = array(range(3)) + raises(ValueError, "a + b") + def test_subtract(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Mon Jul 18 08:06:45 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Mon, 18 Jul 2011 08:06:45 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ndim-size: Changed size and ndim on FloatWrapper to not use exceptions. Instead, size and ndim are -1 on such types. Message-ID: <20110718060645.8670E829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-ndim-size Changeset: r45706:0b020cb8d109 Date: 2011-07-18 00:06 -0600 http://bitbucket.org/pypy/pypy/changeset/0b020cb8d109/ Log: Changed size and ndim on FloatWrapper to not use exceptions. Instead, size and ndim are -1 on such types. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -88,18 +88,12 @@ signature = Signature() def impl(self, space, w_other): w_other = convert_to_array(space, w_other) - try: - w_other_size = w_other.find_size() - self_size = self.find_size() - except ValueError: - # this will be raised if one of the arrays is a scalar. - pass - else: + w_other_size = w_other.find_size() + if w_other_size != -1 and w_other_size != self.find_size(): # Need a better dimension check here for N-dim arrays - if w_other_size != self_size: - raise OperationError(space.w_ValueError, - space.wrap("Cannot %s arrays of unequal dimensions" \ - % function.__name__)) + raise OperationError(space.w_ValueError, + space.wrap("Cannot %s arrays of unequal dimensions" \ + % function.__name__)) new_sig = self.signature.transition(signature) res = Call2( function, @@ -257,6 +251,8 @@ return self.get_concrete().descr_len(space) def descr_get_size(self, space): + # for arrays generated by things like arr[arr>0] we will need + # to have find_size force them to be concrete return space.wrap(self.find_size()) def descr_get_ndim(self, space): @@ -303,10 +299,10 @@ self.float_value = float_value def find_size(self): - raise ValueError + return -1 def find_ndim(self): - raise ValueError + return -1 def eval(self, i): return self.float_value @@ -401,18 +397,16 @@ self.right = None def _find_size(self): - try: - return self.left.find_size() - except ValueError: - pass - return self.right.find_size() + size = self.left.find_size() + if size == -1: + return self.right.find_size() + return size def _find_ndim(self): - try: - return self.left.find_ndim() - except ValueError: - pass - return self.right.find_ndim() + ndim = self.left.find_ndim() + if ndim == -1: + return self.right.find_ndim() + return ndim def _eval(self, i): lhs, rhs = self.left.eval(i), self.right.eval(i) From noreply at buildbot.pypy.org Mon Jul 18 08:16:47 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Mon, 18 Jul 2011 08:16:47 +0200 (CEST) Subject: [pypy-commit] pypy numpy-sort: First rendition of sort. Needs more work and tests. Message-ID: <20110718061648.005AE829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-sort Changeset: r45707:6fcaedcfdebb Date: 2011-07-18 00:16 -0600 http://bitbucket.org/pypy/pypy/changeset/6fcaedcfdebb/ Log: First rendition of sort. Needs more work and tests. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -7,6 +7,8 @@ from pypy.tool.sourcetools import func_with_new_name import math +INSERT_SORT_THRESH = 15 + def dummy1(v): assert isinstance(v, float) return v @@ -235,6 +237,80 @@ else: return self.descr_mul(space, w_other) + def _insertion_sort(self, storage, left, right): + i = left + 1 + while i <= right: + temp = storage[i] + j = i - 1 + while j >= left and storage[j] > temp: + storage[j + 1] = storage[j] + j -= 1 + storage[j + 1] = temp + i += 1 + + def descr_sort(self, space): + storage = self.get_concrete().storage + # can replace these with integer/bool numpy arrays when we add dtypes + lefts = [0] + rights = [self.find_size() - 1] + checkpivots = [False] + while lefts: + left = lefts.pop() + right = rights.pop() + checkpivot = checkpivots.pop() + # just use middle element for now. will change to med of 3 soon + mid = left + (right - left) / 2 + pivot = storage[mid] + if checkpivot and pivot == storage[left - 1]: + storage[mid], storage[left] = storage[left], storage[mid] + i = left + 1 + j = right + while 1: + while storage[j] != pivot: + j -= 1 + while storage[i] == pivot: + if i >= j: break + i += 1 + if i >= j: break + storage[i], storage[j] = storage[j], storage[i] + storage[j] = pivot + if right > j + 1: + if right - j + 1 < INSERT_SORT_THRESH: + self._insertion_sort(storage, j + 1, right) + else: + lefts.append(j + 1) + rights.append(right) + checkpivots.append(False) + else: + storage[mid], storage[right] = storage[right], storage[mid] + i = left + j = right - 1 + while 1: + while storage[i] < pivot: + i += 1 + while storage[j] >= pivot: + if i >= j: break + j -= 1 + if i >= j: break + storage[i], storage[j] = storage[j], storage[i] + storage[right] = storage[i] + storage[i] = pivot + # we can have the smaller subarray sorted first + if left < i - 1: + if i - 1 - left < INSERT_SORT_THRESH: + self._insertion_sort(storage, left, i - 1) + else: + lefts.append(left) + rights.append(i - 1) + checkpivots.append(checkpivot) + if right > i + 1: + if right - i - 1 < INSERT_SORT_THRESH: + self._insertion_sort(storage, i + 1, right) + else: + lefts.append(i + 1) + rights.append(right) + checkpivots.append(True) + def get_concrete(self): raise NotImplementedError @@ -586,4 +662,5 @@ all = interp2app(BaseArray.descr_all), any = interp2app(BaseArray.descr_any), dot = interp2app(BaseArray.descr_dot), + sort = interp2app(BaseArray.descr_sort), ) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -398,6 +398,15 @@ for i in xrange(5): assert b[i] == 2.5*a[i] + def test_sort(self): + # needs a lot more tests of sort + from numpy import array + a = array(range(19,-1,-1)) + b = array(range(20)) + a.sort() + for i in xrange(20): + assert a[i] == b[i] + class AppTestSupport(object): def setup_class(cls): From noreply at buildbot.pypy.org Mon Jul 18 08:52:08 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Mon, 18 Jul 2011 08:52:08 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ufuncs: added ufuncs add, divide, multiply, subtract Message-ID: <20110718065208.F36EB829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-ufuncs Changeset: r45708:02090c007d03 Date: 2011-07-18 00:51 -0600 http://bitbucket.org/pypy/pypy/changeset/02090c007d03/ Log: added ufuncs add, divide, multiply, subtract diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -15,14 +15,19 @@ # ufuncs 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', + 'add': 'interp_ufuncs.add', 'copysign': 'interp_ufuncs.copysign', + 'divide': 'interp_ufuncs.divide', 'exp': 'interp_ufuncs.exp', + 'fabs': 'interp_ufuncs.fabs', 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', + 'multiply': 'interp_ufuncs.multiply', 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'subtract': 'interp_ufuncs.subtract', } appleveldefs = { diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -37,9 +37,17 @@ return abs(value) @ufunc2 +def add(lvalue, rvalue): + return lvalue + rvalue + + at ufunc2 def copysign(lvalue, rvalue): return rfloat.copysign(lvalue, rvalue) + at ufunc2 +def divide(lvalue, rvalue): + return lvalue / rvalue + @ufunc def exp(value): try: @@ -47,6 +55,10 @@ except OverflowError: return rfloat.INFINITY + at ufunc +def fabs(value): + return math.fabs(value) + @ufunc2 def maximum(lvalue, rvalue): return max(lvalue, rvalue) @@ -55,6 +67,10 @@ def minimum(lvalue, rvalue): return min(lvalue, rvalue) + at ufunc2 +def multiply(lvalue, rvalue): + return lvalue * rvalue + @ufunc def negative(value): return -value @@ -65,6 +81,10 @@ return rfloat.copysign(rfloat.INFINITY, value) return 1.0 / value + at ufunc2 +def subtract(lvalue, rvalue): + return lvalue - rvalue + @ufunc def floor(value): return math.floor(value) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -65,6 +65,33 @@ for i in range(3): assert b[i] == abs(a[i]) + def test_add(self): + from numpy import array, add + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = add(a, b) + for i in range(3): + assert c[i] == a[i] + b[i] + + def test_divide(self): + from numpy import array, divide + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = divide(a, b) + for i in range(3): + assert c[i] == a[i] / b[i] + + def test_fabs(self): + from numpy import array, fabs + from math import fabs as math_fabs + + a = array([-5.0, -0.0, 1.0]) + b = fabs(a) + for i in range(3): + assert b[i] == math_fabs(a[i]) + def test_minimum(self): from numpy import array, minimum @@ -83,6 +110,15 @@ for i in range(3): assert c[i] == max(a[i], b[i]) + def test_multiply(self): + from numpy import array, multiply + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = multiply(a, b) + for i in range(3): + assert c[i] == a[i] * b[i] + def test_sign(self): from numpy import array, sign @@ -101,6 +137,15 @@ for i in range(4): assert b[i] == reference[i] + def test_subtract(self): + from numpy import array, subtract + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = subtract(a, b) + for i in range(3): + assert c[i] == a[i] - b[i] + def test_floor(self): from numpy import array, floor From noreply at buildbot.pypy.org Mon Jul 18 10:28:56 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 18 Jul 2011 10:28:56 +0200 (CEST) Subject: [pypy-commit] jitviewer default: cleanup unused imports Message-ID: <20110718082856.1F1B3829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r147:0af34b2fce30 Date: 2011-07-18 10:20 +0200 http://bitbucket.org/pypy/jitviewer/changeset/0af34b2fce30/ Log: cleanup unused imports diff --git a/_jitviewer/display.py b/_jitviewer/display.py --- a/_jitviewer/display.py +++ b/_jitviewer/display.py @@ -1,4 +1,3 @@ -from pypy.jit.metainterp.resoperation import rop from _jitviewer.parser import cssclass class LineRepr(object): diff --git a/_jitviewer/parser.py b/_jitviewer/parser.py --- a/_jitviewer/parser.py +++ b/_jitviewer/parser.py @@ -1,7 +1,4 @@ -import re, sys -from lib_pypy.disassembler import dis # imported from the pypy source tree -from pypy.jit.metainterp.resoperation import rop, opname -from pypy.jit.tool.oparser import OpParser +import re from pypy.tool.jitlogparser import parser class Html(str): @@ -11,7 +8,6 @@ def plaintext(self): # This is not a general way to strip tags, but it's good enough to use # in tests - import re s = re.sub('<.*?>', '', self) s = s.replace("<", "<") s = s.replace(">", ">") From noreply at buildbot.pypy.org Mon Jul 18 11:31:04 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 18 Jul 2011 11:31:04 +0200 (CEST) Subject: [pypy-commit] pypy default: add an option to not write C files, but only simulate writing them. Useful for benchmarking without actually write to the disk Message-ID: <20110718093104.CCAA3829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45709:90fbcd637136 Date: 2011-07-09 19:10 +0200 http://bitbucket.org/pypy/pypy/changeset/90fbcd637136/ Log: add an option to not write C files, but only simulate writing them. Useful for benchmarking without actually write to the disk diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -140,7 +140,10 @@ ["annotate", "rtype", "backendopt", "database", "source", "pyjitpl"], default=None, cmdline="--fork-before"), - + BoolOption("dont_write_c_files", + "Make the C backend write everyting to /dev/null. " + + "Useful for benchmarking, so you don't actually involve the disk", + default=False, cmdline="--dont-write-c-files"), ArbitraryOption("instrumentctl", "internal", default=None), StrOption("output", "Output file name", cmdline="--output"), diff --git a/pypy/tool/nullpath.py b/pypy/tool/nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/nullpath.py @@ -0,0 +1,12 @@ +import py + +class NullPyPathLocal(py.path.local): + + def join(self, *args): + return self.__class__(py.path.local.join(self, *args)) + + def open(self, mode): + return open('/dev/null', mode) + + def __repr__(self): + return py.path.local.__repr__(self) + ' [fake]' diff --git a/pypy/tool/test/test_nullpath.py b/pypy/tool/test/test_nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/test/test_nullpath.py @@ -0,0 +1,16 @@ +import sys +import py +from pypy.tool.nullpath import NullPyPathLocal + +def setup_module(): + if 'posix' not in sys.builtin_module_names: + py.test.skip('posix only') + +def test_nullpath(tmpdir): + path = NullPyPathLocal(tmpdir) + assert repr(path).endswith('[fake]') + foo_txt = path.join('foo.txt') + assert isinstance(foo_txt, NullPyPathLocal) + # + f = foo_txt.open('w') + assert f.name == '/dev/null' diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -13,6 +13,7 @@ from pypy.rpython.typesystem import getfunctionptr from pypy.translator.c import gc from pypy.rlib import exports +from pypy.tool.nullpath import NullPyPathLocal def import_module_from_directory(dir, modname): file, pathname, description = imp.find_module(modname, [str(dir)]) @@ -237,7 +238,9 @@ self.modulename = uniquemodulename('testing') modulename = self.modulename targetdir = udir.ensure(modulename, dir=1) - + if self.config.translation.dont_write_c_files: + targetdir = NullPyPathLocal(targetdir) + self.targetdir = targetdir defines = defines.copy() if self.config.translation.countmallocs: @@ -944,11 +947,13 @@ ] return eci.merge(ExternalCompilationInfo(separate_module_files=files)) + def gen_source_standalone(database, modulename, targetdir, eci, entrypointname, defines={}): assert database.standalone if isinstance(targetdir, str): targetdir = py.path.local(targetdir) + filename = targetdir.join(modulename + '.c') f = filename.open('w') incfilename = targetdir.join('common_header.h') @@ -1002,6 +1007,7 @@ assert not database.standalone if isinstance(targetdir, str): targetdir = py.path.local(targetdir) + filename = targetdir.join(modulename + '.c') f = filename.open('w') incfilename = targetdir.join('common_header.h') diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py --- a/pypy/translator/c/test/test_genc.py +++ b/pypy/translator/c/test/test_genc.py @@ -13,6 +13,7 @@ from pypy.translator.backendopt.all import backend_optimizations from pypy.translator.interactive import Translation from pypy.rlib.entrypoint import entrypoint +from pypy.tool.nullpath import NullPyPathLocal def compile(fn, argtypes, view=False, gcpolicy="ref", backendopt=True, annotatorpolicy=None): @@ -63,6 +64,22 @@ py.test.raises(Exception, f1, "world") # check that it's really typed + +def test_dont_write_source_files(): + def f(x): + return x*2 + t = TranslationContext() + t.buildannotator().build_types(f, [int]) + t.buildrtyper().specialize() + + t.config.translation.countmallocs = True + t.config.translation.dont_write_c_files = True + builder = genc.CExtModuleBuilder(t, f, config=t.config) + builder.generate_source() + assert isinstance(builder.targetdir, NullPyPathLocal) + assert builder.targetdir.listdir() == [] + + def test_simple_lambda(): f = lambda x: x*2 t = TranslationContext() From noreply at buildbot.pypy.org Mon Jul 18 11:52:07 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 18 Jul 2011 11:52:07 +0200 (CEST) Subject: [pypy-commit] pypy default: add a __dir__ method to Config objects. This way we can tab-complete also the option names Message-ID: <20110718095207.13536829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45710:b16d0240b5d4 Date: 2011-07-18 11:52 +0200 http://bitbucket.org/pypy/pypy/changeset/b16d0240b5d4/ Log: add a __dir__ method to Config objects. This way we can tab-complete also the option names diff --git a/pypy/config/config.py b/pypy/config/config.py --- a/pypy/config/config.py +++ b/pypy/config/config.py @@ -81,6 +81,12 @@ (self.__class__, name)) return self._cfgimpl_values[name] + def __dir__(self): + from_type = dir(type(self)) + from_dict = list(self.__dict__) + extras = list(self._cfgimpl_values) + return sorted(set(extras + from_type + from_dict)) + def __delattr__(self, name): # XXX if you use delattr you are responsible for all bad things # happening diff --git a/pypy/config/test/test_config.py b/pypy/config/test/test_config.py --- a/pypy/config/test/test_config.py +++ b/pypy/config/test/test_config.py @@ -63,6 +63,20 @@ py.test.raises(ConfigError, 'config.gc.name = "ref"') config.gc.name = "framework" +def test___dir__(): + descr = make_description() + config = Config(descr, bool=False) + attrs = dir(config) + assert '__repr__' in attrs # from the type + assert '_cfgimpl_values' in attrs # from self + assert 'gc' in attrs # custom attribute + assert 'objspace' in attrs # custom attribute + # + attrs = dir(config.gc) + assert 'name' in attrs + assert 'dummy' in attrs + assert 'float' in attrs + def test_arbitrary_option(): descr = OptionDescription("top", "", [ ArbitraryOption("a", "no help", default=None) From noreply at buildbot.pypy.org Mon Jul 18 17:01:45 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 18 Jul 2011 17:01:45 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: make call_pure not invalidate the heap caches (annoying to find) Message-ID: <20110718150145.AF096829B8@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45711:47b01028f999 Date: 2011-07-18 17:00 +0200 http://bitbucket.org/pypy/pypy/changeset/47b01028f999/ Log: make call_pure not invalidate the heap caches (annoying to find) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1668,17 +1668,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) - if (opnum != rop.SETFIELD_GC and - opnum != rop.SETARRAYITEM_GC): - if not (rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST): - if self.heap_cache: - self.heap_cache.clear() - if self.heap_array_cache: - self.heap_array_cache.clear() + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py --- a/pypy/jit/metainterp/test/test_tracingopts.py +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -378,3 +378,30 @@ res = self.interp_operations(fn, [-7]) assert res == -7 - 7 + 1 self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return From noreply at buildbot.pypy.org Mon Jul 18 17:37:43 2011 From: noreply at buildbot.pypy.org (hager) Date: Mon, 18 Jul 2011 17:37:43 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: bootstrapped branch for powerpc JIT backend, made first test run Message-ID: <20110718153743.18E8F829B8@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45712:65df23bd8e99 Date: 2011-07-12 17:40 +0200 http://bitbucket.org/pypy/pypy/changeset/65df23bd8e99/ Log: bootstrapped branch for powerpc JIT backend, made first test run diff --git a/pypy/jit/backend/arm/tool/objdump.py b/pypy/jit/backend/arm/tool/objdump.py --- a/pypy/jit/backend/arm/tool/objdump.py +++ b/pypy/jit/backend/arm/tool/objdump.py @@ -7,7 +7,7 @@ import os, sys, py def objdump(input): - os.system('objdump -D --architecture=arm --target=binary %s' % input) + os.system('objdump -D --architecture=powerpc:common64 --target=binary %s' % input) def get_tmp_file(): diff --git a/pypy/jit/backend/detect_cpu.py b/pypy/jit/backend/detect_cpu.py --- a/pypy/jit/backend/detect_cpu.py +++ b/pypy/jit/backend/detect_cpu.py @@ -31,6 +31,7 @@ 'i86pc': 'x86', # Solaris/Intel 'x86': 'x86', # Apple 'Power Macintosh': 'ppc', + 'ppc64': 'ppc64', 'x86_64': 'x86', 'amd64': 'x86', # freebsd 'AMD64': 'x86', # win64 @@ -76,6 +77,8 @@ return "pypy.jit.backend.llvm.runner", "LLVMCPU" elif backend_name == 'arm': return "pypy.jit.backend.arm.runner", "ArmCPU" + elif backend_name == 'ppc64': + return "pypy.jit.backend.ppc.runner", "PPC_64_CPU" else: raise ProcessorAutodetectError, ( "we have no JIT backend for this cpu: '%s'" % backend_name) From noreply at buildbot.pypy.org Mon Jul 18 17:37:44 2011 From: noreply at buildbot.pypy.org (hager) Date: Mon, 18 Jul 2011 17:37:44 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: forgot to add files -.- Message-ID: <20110718153744.75080829B9@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45713:7c61615e731c Date: 2011-07-12 17:41 +0200 http://bitbucket.org/pypy/pypy/changeset/7c61615e731c/ Log: forgot to add files -.- diff --git a/pypy/jit/backend/ppc/__init__.py b/pypy/jit/backend/ppc/__init__.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/__init__.py @@ -0,0 +1,1 @@ +# diff --git a/pypy/jit/backend/ppc/_flush_icache.c b/pypy/jit/backend/ppc/_flush_icache.c new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/_flush_icache.c @@ -0,0 +1,26 @@ +#include +#include "../../../translator/c/src/asm_ppc.h" + +static PyObject* +_flush_icache(PyObject *self, PyObject *args) +{ + long base, size; + + if (!PyArg_ParseTuple(args, "ii:_flush_icache", &base, &size)) + return NULL; + + LL_flush_icache(base, size); + Py_INCREF(Py_None); + return Py_None; +} + +PyMethodDef _flush_icache_methods[] = { + {"_flush_icache", _flush_icache, METH_VARARGS, ""}, + {0, 0} +}; + +PyMODINIT_FUNC +init_flush_icache(void) +{ + Py_InitModule("_flush_icache", _flush_icache_methods); +} diff --git a/pypy/jit/backend/ppc/codebuf.py b/pypy/jit/backend/ppc/codebuf.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/codebuf.py @@ -0,0 +1,5 @@ +from pypy.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin + +class MachineCodeBlockWrapper(BlockBuilderMixin): + def __init__(self): + self.init_block_builder() diff --git a/pypy/jit/backend/ppc/instruction.py b/pypy/jit/backend/ppc/instruction.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/instruction.py @@ -0,0 +1,842 @@ +r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, \ + r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, \ + r23, r24, r25, r26, r27, r28, r29, r30, r31 = range(32) +rSCRATCH = r0 +rSP = r1 +rFP = r2 # the ABI doesn't specify a frame pointer. however, we want one + +class AllocationSlot(object): + offset = 0 + number = 0 + def __init__(self): + # The field alloc points to a singleton used by the register + # allocator to detect conflicts. No two AllocationSlot + # instances with the same value in self.alloc can be used at + # once. + self.alloc = self + + def make_loc(self): + """ When we assign a variable to one of these registers, we + call make_loc() to get the actual location instance; that + instance will have its alloc field set to self. For + everything but condition registers, this is self.""" + return self + +class _StackSlot(AllocationSlot): + is_register = False + def __init__(self, offset): + AllocationSlot.__init__(self) + self.offset = offset + def __repr__(self): + return "stack@%s"%(self.offset,) + +_stack_slot_cache = {} +def stack_slot(offset): + # because stack slots are put into dictionaries which compare by + # identity, it is important that there's a unique _StackSlot + # object for each offset, at least per function generated or + # something. doing the caching here is easier, though. + if offset in _stack_slot_cache: + return _stack_slot_cache[offset] + _stack_slot_cache[offset] = res = _StackSlot(offset) + return res + +NO_REGISTER = -1 +GP_REGISTER = 0 +FP_REGISTER = 1 +CR_FIELD = 2 +CT_REGISTER = 3 + +class Register(AllocationSlot): + is_register = True + def __init__(self): + AllocationSlot.__init__(self) + +class GPR(Register): + regclass = GP_REGISTER + def __init__(self, number): + Register.__init__(self) + self.number = number + def __repr__(self): + return 'r' + str(self.number) +gprs = map(GPR, range(32)) + +class FPR(Register): + regclass = FP_REGISTER + def __init__(self, number): + Register.__init__(self) + self.number = number + +fprs = map(FPR, range(32)) + +class BaseCRF(Register): + """ These represent condition registers; however, we never actually + use these as the location of something in the register allocator. + Instead, we place it in an instance of CRF which indicates which + bits are required to extract the value. Note that CRF().alloc will + always be an instance of this. """ + regclass = CR_FIELD + def __init__(self, number): + self.number = number + self.alloc = self + def make_loc(self): + return CRF(self) + +crfs = map(BaseCRF, range(8)) + +class CRF(Register): + regclass = CR_FIELD + def __init__(self, crf): + Register.__init__(self) + self.alloc = crf + self.number = crf.number + self.info = (-1,-1) # (bit, negated) + def set_info(self, info): + assert len(info) == 2 + self.info = info + def make_loc(self): + # should never call this on a CRF, only a BaseCRF + raise NotImplementedError + def move_to_gpr(self, gpr): + bit, negated = self.info + return _CRF2GPR(gpr, self.alloc.number*4 + bit, negated) + def move_from_gpr(self, gpr): + # cmp2info['ne'] + self.set_info((2, 1)) + return _GPR2CRF(self, gpr) + def __repr__(self): + return 'crf' + str(self.number) + str(self.info) + +class CTR(Register): + regclass = CT_REGISTER + def move_from_gpr(self, gpr): + return _GPR2CTR(gpr) + +ctr = CTR() + +_insn_index = [0] + +class Insn(object): + ''' + result is the Var instance that holds the result, or None + result_regclass is the class of the register the result goes into + + reg_args is the vars that need to have registers allocated for them + reg_arg_regclasses is the type of register that needs to be allocated + ''' + def __init__(self): + self._magic_index = _insn_index[0] + _insn_index[0] += 1 + def __repr__(self): + return "<%s %d>" % (self.__class__.__name__, self._magic_index) + def emit(self, asm): + pass + +class Insn_GPR__GPR_GPR(Insn): + def __init__(self, methptr, result, args): + Insn.__init__(self) + self.methptr = methptr + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = args + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] + + self.result_reg = None + self.arg_reg1 = None + self.arg_reg2 = None + + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + self.arg_reg1 = allocator.loc_of(self.reg_args[0]) + self.arg_reg2 = allocator.loc_of(self.reg_args[1]) + + def __repr__(self): + if self.result_reg: + r = "%s@%s"%(self.result, self.result_reg) + else: + r = str(self.result) + if self.arg_reg1: + a1 = "%s@%s"%(self.reg_args[0], self.arg_reg1) + else: + a1 = str(self.reg_args[0]) + if self.arg_reg2: + a2 = "%s@%s"%(self.reg_args[1], self.arg_reg2) + else: + a2 = str(self.reg_args[1]) + return "<%s-%s %s %s, %s, %s>" % (self.__class__.__name__, self._magic_index, + self.methptr.im_func.func_name, + r, a1, a2) + + def emit(self, asm): + self.methptr(asm, + self.result_reg.number, + self.arg_reg1.number, + self.arg_reg2.number) + +class Insn_GPR__GPR_IMM(Insn): + def __init__(self, methptr, result, args): + Insn.__init__(self) + self.methptr = methptr + self.imm = args[1] + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = [args[0]] + self.reg_arg_regclasses = [GP_REGISTER] + self.result_reg = None + self.arg_reg = None + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + self.arg_reg = allocator.loc_of(self.reg_args[0]) + def __repr__(self): + if self.result_reg: + r = "%s@%s"%(self.result, self.result_reg) + else: + r = str(self.result) + if self.arg_reg: + a = "%s@%s"%(self.reg_args[0], self.arg_reg) + else: + a = str(self.reg_args[0]) + return "<%s-%d %s %s, %s, (%s)>" % (self.__class__.__name__, self._magic_index, + self.methptr.im_func.func_name, + r, a, self.imm.value) + + def emit(self, asm): + self.methptr(asm, + self.result_reg.number, + self.arg_reg.number, + self.imm.value) + +class Insn_GPR__GPR(Insn): + def __init__(self, methptr, result, arg): + Insn.__init__(self) + self.methptr = methptr + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = [arg] + self.reg_arg_regclasses = [GP_REGISTER] + + self.result_reg = None + self.arg_reg = None + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + self.arg_reg = allocator.loc_of(self.reg_args[0]) + def __repr__(self): + if self.result_reg: + r = "%s@%s"%(self.result, self.result_reg) + else: + r = str(self.result) + if self.arg_reg: + a = "%s@%s"%(self.reg_args[0], self.arg_reg) + else: + a = str(self.reg_args[0]) + return "<%s-%d %s %s, %s>" % (self.__class__.__name__, self._magic_index, + self.methptr.im_func.func_name, r, a) + def emit(self, asm): + self.methptr(asm, + self.result_reg.number, + self.arg_reg.number) + + +class Insn_GPR(Insn): + def __init__(self, methptr, result): + Insn.__init__(self) + self.methptr = methptr + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result_reg = None + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + def __repr__(self): + if self.result_reg: + r = "%s@%s"%(self.result, self.result_reg) + else: + r = str(self.result) + return "<%s-%d %s %s>" % (self.__class__.__name__, self._magic_index, + self.methptr.im_func.func_name, r) + def emit(self, asm): + self.methptr(asm, + self.result_reg.number) + +class Insn_GPR__IMM(Insn): + def __init__(self, methptr, result, args): + Insn.__init__(self) + self.methptr = methptr + self.imm = args[0] + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result_reg = None + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + def __repr__(self): + if self.result_reg: + r = "%s@%s"%(self.result, self.result_reg) + else: + r = str(self.result) + return "<%s-%d %s %s, (%s)>" % (self.__class__.__name__, self._magic_index, + self.methptr.im_func.func_name, r, + self.imm.value) + def emit(self, asm): + self.methptr(asm, + self.result_reg.number, + self.imm.value) + +class MoveCRB2GPR(Insn): + def __init__(self, result, gv_condition): + Insn.__init__(self) + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = [gv_condition] + self.reg_arg_regclasses = [CR_FIELD] + def allocate(self, allocator): + self.targetreg = allocator.loc_of(self.result) + self.crf = allocator.loc_of(self.reg_args[0]) + def emit(self, asm): + assert isinstance(self.crf, CRF) + bit, negated = self.crf.info + asm.mfcr(self.targetreg.number) + asm.extrwi(self.targetreg.number, self.targetreg.number, 1, self.crf.number*4+bit) + if negated: + asm.xori(self.targetreg.number, self.targetreg.number, 1) + +class Insn_None__GPR_GPR_IMM(Insn): + def __init__(self, methptr, args): + Insn.__init__(self) + self.methptr = methptr + self.imm = args[2] + + self.result = None + self.result_regclass = NO_REGISTER + self.reg_args = args[:2] + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] + def allocate(self, allocator): + self.reg1 = allocator.loc_of(self.reg_args[0]) + self.reg2 = allocator.loc_of(self.reg_args[1]) + def __repr__(self): + return "<%s %s %d>" % (self.__class__.__name__, self.methptr.im_func.func_name, self._magic_index) + + def emit(self, asm): + self.methptr(asm, + self.reg1.number, + self.reg2.number, + self.imm.value) + +class Insn_None__GPR_GPR_GPR(Insn): + def __init__(self, methptr, args): + Insn.__init__(self) + self.methptr = methptr + + self.result = None + self.result_regclass = NO_REGISTER + self.reg_args = args + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER, GP_REGISTER] + def allocate(self, allocator): + self.reg1 = allocator.loc_of(self.reg_args[0]) + self.reg2 = allocator.loc_of(self.reg_args[1]) + self.reg3 = allocator.loc_of(self.reg_args[2]) + def __repr__(self): + return "<%s %s %d>" % (self.__class__.__name__, self.methptr.im_func.func_name, self._magic_index) + + def emit(self, asm): + self.methptr(asm, + self.reg1.number, + self.reg2.number, + self.reg3.number) + +class Extrwi(Insn): + def __init__(self, result, source, size, bit): + Insn.__init__(self) + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = [source] + self.reg_arg_regclasses = [GP_REGISTER] + self.result_reg = None + self.arg_reg = None + + self.size = size + self.bit = bit + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + self.arg_reg = allocator.loc_of(self.reg_args[0]) + def __repr__(self): + if self.result_reg: + r = "%s@%s"%(self.result, self.result_reg) + else: + r = str(self.result) + if self.arg_reg: + a = "%s@%s"%(self.reg_args[0], self.arg_reg) + else: + a = str(self.reg_args[0]) + return "<%s-%d extrwi %s, %s, %s, %s>" % (self.__class__.__name__, self._magic_index, + r, a, self.size, self.bit) + + def emit(self, asm): + asm.extrwi(self.result_reg.number, + self.arg_reg.number, + self.size, self.bit) + + +class CMPInsn(Insn): + def __init__(self, info, result): + Insn.__init__(self) + self.info = info + self.result = result + self.result_reg = None + + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + assert isinstance(self.result_reg, CRF) + self.result_reg.set_info(self.info) + +class CMPW(CMPInsn): + def __init__(self, info, result, args): + CMPInsn.__init__(self, info, result) + self.result_regclass = CR_FIELD + self.reg_args = args + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] + self.arg_reg1 = None + self.arg_reg2 = None + + def allocate(self, allocator): + CMPInsn.allocate(self, allocator) + self.arg_reg1 = allocator.loc_of(self.reg_args[0]) + self.arg_reg2 = allocator.loc_of(self.reg_args[1]) + + def __repr__(self): + if self.result_reg: + r = "%s@%s"%(self.result, self.result_reg) + else: + r = str(self.result) + if self.arg_reg1: + a1 = "%s@%s"%(self.reg_args[0], self.arg_reg1) + else: + a1 = str(self.reg_args[0]) + if self.arg_reg2: + a2 = "%s@%s"%(self.reg_args[1], self.arg_reg2) + else: + a2 = str(self.reg_args[1]) + return "<%s-%d %s %s, %s, %s>"%(self.__class__.__name__, self._magic_index, + self.__class__.__name__.lower(), + r, a1, a2) + + def emit(self, asm): + asm.cmpw(self.result_reg.number, self.arg_reg1.number, self.arg_reg2.number) + +class CMPWL(CMPW): + def emit(self, asm): + asm.cmplw(self.result_reg.number, self.arg_reg1.number, self.arg_reg2.number) + +class CMPWI(CMPInsn): + def __init__(self, info, result, args): + CMPInsn.__init__(self, info, result) + self.imm = args[1] + self.result_regclass = CR_FIELD + self.reg_args = [args[0]] + self.reg_arg_regclasses = [GP_REGISTER] + self.arg_reg = None + + def allocate(self, allocator): + CMPInsn.allocate(self, allocator) + self.arg_reg = allocator.loc_of(self.reg_args[0]) + + def __repr__(self): + if self.result_reg: + r = "%s@%s"%(self.result, self.result_reg) + else: + r = str(self.result) + if self.arg_reg: + a = "%s@%s"%(self.reg_args[0], self.arg_reg) + else: + a = str(self.reg_args[0]) + return "<%s-%d %s %s, %s, (%s)>"%(self.__class__.__name__, self._magic_index, + self.__class__.__name__.lower(), + r, a, self.imm.value) + def emit(self, asm): + #print "CMPWI", asm.mc.tell() + asm.cmpwi(self.result_reg.number, self.arg_reg.number, self.imm.value) + +class CMPWLI(CMPWI): + def emit(self, asm): + asm.cmplwi(self.result_reg.number, self.arg_reg.number, self.imm.value) + + +## class MTCTR(Insn): +## def __init__(self, result, args): +## Insn.__init__(self) +## self.result = result +## self.result_regclass = CT_REGISTER + +## self.reg_args = args +## self.reg_arg_regclasses = [GP_REGISTER] + +## def allocate(self, allocator): +## self.arg_reg = allocator.loc_of(self.reg_args[0]) + +## def emit(self, asm): +## asm.mtctr(self.arg_reg.number) + +class Jump(Insn): + def __init__(self, gv_cond, targetbuilder, jump_if_true, jump_args_gv): + Insn.__init__(self) + self.gv_cond = gv_cond + self.jump_if_true = jump_if_true + + self.result = None + self.result_regclass = NO_REGISTER + self.reg_args = [gv_cond] + self.reg_arg_regclasses = [CR_FIELD] + self.crf = None + + self.jump_args_gv = jump_args_gv + self.targetbuilder = targetbuilder + def allocate(self, allocator): + self.crf = allocator.loc_of(self.reg_args[0]) + assert self.crf.info[0] != -1 + + assert self.targetbuilder.initial_var2loc is None + self.targetbuilder.initial_var2loc = {} + from pypy.jit.codegen.ppc.rgenop import Var + for gv_arg in self.jump_args_gv: + if isinstance(gv_arg, Var): + self.targetbuilder.initial_var2loc[gv_arg] = allocator.var2loc[gv_arg] + allocator.builders_to_tell_spill_offset_to.append(self.targetbuilder) + def __repr__(self): + if self.jump_if_true: + op = 'if_true' + else: + op = 'if_false' + if self.crf: + a = '%s@%s'%(self.reg_args[0], self.crf) + else: + a = self.reg_args[0] + return '<%s-%d %s %s>'%(self.__class__.__name__, self._magic_index, + op, a) + def emit(self, asm): + if self.targetbuilder.start: + asm.load_word(rSCRATCH, self.targetbuilder.start) + else: + self.targetbuilder.patch_start_here = asm.mc.tell() + asm.load_word(rSCRATCH, 0) + asm.mtctr(rSCRATCH) + bit, negated = self.crf.info + assert bit != -1 + if negated ^ self.jump_if_true: + BO = 12 # jump if relavent bit is set in the CR + else: + BO = 4 # jump if relavent bit is NOT set in the CR + asm.bcctr(BO, self.crf.number*4 + bit) + +class Label(Insn): + def __init__(self, label): + Insn.__init__(self) + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result_regclass = NO_REGISTER + self.result = None + self.label = label + def allocate(self, allocator): + for gv in self.label.args_gv: + loc = allocator.loc_of(gv) + if isinstance(loc, CRF): + allocator.forget(gv, loc) + allocator.lru.remove(gv) + allocator.freeregs[loc.regclass].append(loc.alloc) + new_loc = allocator._allocate_reg(GP_REGISTER, gv) + allocator.lru.append(gv) + allocator.insns.append(loc.move_to_gpr(new_loc.number)) + loc = new_loc + self.label.arg_locations = [] + for gv in self.label.args_gv: + loc = allocator.loc_of(gv) + self.label.arg_locations.append(loc) + allocator.labels_to_tell_spill_offset_to.append(self.label) + def __repr__(self): + if hasattr(self.label, 'arg_locations'): + arg_locations = '[' + ', '.join( + ['%s@%s'%(gv, loc) for gv, loc in + zip(self.label.args_gv, self.label.arg_locations)]) + ']' + else: + arg_locations = str(self.label.args_gv) + return ''%(self._magic_index, + arg_locations) + def emit(self, asm): + self.label.startaddr = asm.mc.tell() + +class LoadFramePointer(Insn): + def __init__(self, result): + Insn.__init__(self) + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result = result + self.result_regclass = GP_REGISTER + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + def emit(self, asm): + asm.mr(self.result_reg.number, rFP) + +class CopyIntoStack(Insn): + def __init__(self, place, v): + Insn.__init__(self) + self.reg_args = [v] + self.reg_arg_regclasses = [GP_REGISTER] + self.result = None + self.result_regclass = NO_REGISTER + self.place = place + def allocate(self, allocator): + self.arg_reg = allocator.loc_of(self.reg_args[0]) + self.target_slot = allocator.spill_slot() + self.place.offset = self.target_slot.offset + def emit(self, asm): + asm.stw(self.arg_reg.number, rFP, self.target_slot.offset) + +class CopyOffStack(Insn): + def __init__(self, v, place): + Insn.__init__(self) + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result = v + self.result_regclass = GP_REGISTER + self.place = place + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + allocator.free_stack_slots.append(stack_slot(self.place.offset)) + def emit(self, asm): + asm.lwz(self.result_reg.number, rFP, self.place.offset) + +class SpillCalleeSaves(Insn): + def __init__(self): + Insn.__init__(self) + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result = None + self.result_regclass = NO_REGISTER + def allocate(self, allocator): + # cough cough cough + callersave = gprs[3:13] + for v in allocator.var2loc: + loc = allocator.loc_of(v) + if loc in callersave: + allocator.spill(loc, v) + allocator.freeregs[GP_REGISTER].append(loc) + def emit(self, asm): + pass + +class LoadArg(Insn): + def __init__(self, argnumber, arg): + Insn.__init__(self) + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result = None + self.result_regclass = NO_REGISTER + + self.argnumber = argnumber + self.arg = arg + def allocate(self, allocator): + from pypy.jit.codegen.ppc.rgenop import Var + if isinstance(self.arg, Var): + self.loc = allocator.loc_of(self.arg) + else: + self.loc = None + def emit(self, asm): + if self.argnumber < 8: # magic numbers 'r' us + targetreg = 3+self.argnumber + if self.loc is None: + self.arg.load_now(asm, gprs[targetreg]) + elif self.loc.is_register: + asm.mr(targetreg, self.loc.number) + else: + asm.lwz(targetreg, rFP, self.loc.offset) + else: + targetoffset = 24+self.argnumber*4 + if self.loc is None: + self.arg.load_now(asm, gprs[0]) + asm.stw(r0, r1, targetoffset) + elif self.loc.is_register: + asm.stw(self.loc.number, r1, targetoffset) + else: + asm.lwz(r0, rFP, self.loc.offset) + asm.stw(r0, r1, targetoffset) + +class CALL(Insn): + def __init__(self, result, target): + Insn.__init__(self) + from pypy.jit.codegen.ppc.rgenop import Var + if isinstance(target, Var): + self.reg_args = [target] + self.reg_arg_regclasses = [CT_REGISTER] + else: + self.reg_args = [] + self.reg_arg_regclasses = [] + self.target = target + self.result = result + self.result_regclass = GP_REGISTER + def allocate(self, allocator): + if self.reg_args: + assert allocator.loc_of(self.reg_args[0]) is ctr + self.resultreg = allocator.loc_of(self.result) + def emit(self, asm): + if not self.reg_args: + self.target.load_now(asm, gprs[0]) + asm.mtctr(0) + asm.bctrl() + asm.lwz(rFP, rSP, 0) + if self.resultreg != gprs[3]: + asm.mr(self.resultreg.number, 3) + + +class AllocTimeInsn(Insn): + def __init__(self): + Insn.__init__(self) + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result_regclass = NO_REGISTER + self.result = None + +class Move(AllocTimeInsn): + def __init__(self, dest, src): + AllocTimeInsn.__init__(self) + self.dest = dest + self.src = src + def emit(self, asm): + asm.mr(self.dest.number, self.src.number) + +class Load(AllocTimeInsn): + def __init__(self, dest, const): + AllocTimeInsn.__init__(self) + self.dest = dest + self.const = const + def __repr__(self): + return ""%(self._magic_index, self.dest, self.const) + def emit(self, asm): + self.const.load_now(asm, self.dest) + +class Unspill(AllocTimeInsn): + """ A special instruction inserted by our register "allocator." It + indicates that we need to load a value from the stack into a register + because we spilled a particular value. """ + def __init__(self, var, reg, stack): + """ + var --- the var we spilled (a Var) + reg --- the reg we spilled it from (an integer) + offset --- the offset on the stack we spilled it to (an integer) + """ + AllocTimeInsn.__init__(self) + self.var = var + self.reg = reg + self.stack = stack + if not isinstance(self.reg, GPR): + assert isinstance(self.reg, CRF) or isinstance(self.reg, CTR) + self.moveinsn = self.reg.move_from_gpr(0) + else: + self.moveinsn = None + def __repr__(self): + return ''%(self._magic_index, self.var, self.reg, self.stack) + def emit(self, asm): + if isinstance(self.reg, GPR): + r = self.reg.number + else: + r = 0 + asm.lwz(r, rFP, self.stack.offset) + if self.moveinsn: + self.moveinsn.emit(asm) + +class Spill(AllocTimeInsn): + """ A special instruction inserted by our register "allocator." + It indicates that we need to store a value from the register into + the stack because we spilled a particular value.""" + def __init__(self, var, reg, stack): + """ + var --- the var we are spilling (a Var) + reg --- the reg we are spilling it from (an integer) + offset --- the offset on the stack we are spilling it to (an integer) + """ + AllocTimeInsn.__init__(self) + self.var = var + self.reg = reg + self.stack = stack + def __repr__(self): + return ''%(self._magic_index, self.var, self.stack, self.reg) + def emit(self, asm): + if isinstance(self.reg, GPR): + r = self.reg.number + else: + assert isinstance(self.reg, CRF) + self.reg.move_to_gpr(0).emit(asm) + r = 0 + #print 'spilling to', self.stack.offset + asm.stw(r, rFP, self.stack.offset) + +class _CRF2GPR(AllocTimeInsn): + def __init__(self, targetreg, bit, negated): + AllocTimeInsn.__init__(self) + self.targetreg = targetreg + self.bit = bit + self.negated = negated + def __repr__(self): + number = self.bit // 4 + bit = self.bit % 4 + return '' % ( + self._magic_index, self.targetreg, number, bit, self.negated) + def emit(self, asm): + asm.mfcr(self.targetreg) + asm.extrwi(self.targetreg, self.targetreg, 1, self.bit) + if self.negated: + asm.xori(self.targetreg, self.targetreg, 1) + +class _GPR2CRF(AllocTimeInsn): + def __init__(self, targetreg, fromreg): + AllocTimeInsn.__init__(self) + self.targetreg = targetreg + self.fromreg = fromreg + def __repr__(self): + return '' % ( + self._magic_index, self.targetreg, self.fromreg) + def emit(self, asm): + asm.cmpwi(self.targetreg.number, self.fromreg, 0) + +class _GPR2CTR(AllocTimeInsn): + def __init__(self, fromreg): + AllocTimeInsn.__init__(self) + self.fromreg = fromreg + def emit(self, asm): + asm.mtctr(self.fromreg) + +class Return(Insn): + """ Ensures the return value is in r3 """ + def __init__(self, var): + Insn.__init__(self) + self.var = var + self.reg_args = [self.var] + self.reg_arg_regclasses = [GP_REGISTER] + self.result = None + self.result_regclass = NO_REGISTER + self.reg = None + def allocate(self, allocator): + self.reg = allocator.loc_of(self.reg_args[0]) + def emit(self, asm): + if self.reg.number != 3: + asm.mr(r3, self.reg.number) + +class FakeUse(Insn): + """ A fake use of a var to get it into a register. And reserving + a condition register field.""" + def __init__(self, rvar, var): + Insn.__init__(self) + self.var = var + self.reg_args = [self.var] + self.reg_arg_regclasses = [GP_REGISTER] + self.result = rvar + self.result_regclass = CR_FIELD + def allocate(self, allocator): + pass + def emit(self, asm): + pass diff --git a/pypy/jit/backend/ppc/ppcgen/__init__.py b/pypy/jit/backend/ppc/ppcgen/__init__.py new file mode 100644 diff --git a/pypy/jit/backend/ppc/ppcgen/_ppcgen.c b/pypy/jit/backend/ppc/ppcgen/_ppcgen.c new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/_ppcgen.c @@ -0,0 +1,154 @@ +#include +#include + +#define __dcbf(base, index) \ + __asm__ ("dcbf %0, %1" : /*no result*/ : "b%" (index), "r" (base) : "memory") + + +static PyTypeObject* mmap_type; + +#if defined(__APPLE__) + +#include + +static PyObject* +_ppy_NSLookupAndBindSymbol(PyObject* self, PyObject* args) +{ + char *s; + NSSymbol sym; + + if (!PyArg_ParseTuple(args, "s", &s)) + return NULL; + + if (!NSIsSymbolNameDefined(s)) { + return PyErr_Format(PyExc_ValueError, + "symbol '%s' not found", s); + } + + sym = NSLookupAndBindSymbol(s); + + return PyInt_FromLong((long)NSAddressOfSymbol(sym)); +} + + +#elif defined(linux) + +#include + +static PyObject* +_ppy_dlsym(PyObject* self, PyObject* args) +{ + char *s; + void *handle; + void *sym; + + if (!PyArg_ParseTuple(args, "s", &s)) + return NULL; + + handle = dlopen(RTLD_DEFAULT, RTLD_LAZY); + sym = dlsym(handle, s); + if (sym == NULL) { + return PyErr_Format(PyExc_ValueError, + "symbol '%s' not found", s); + } + return PyInt_FromLong((long)sym); +} + +#else + +#error "OS not supported" + +#endif + + +static PyObject* +_ppy_mmap_exec(PyObject* self, PyObject* args) +{ + PyObject* code_args; + PyObject* r; + PyObject* mmap_obj; + char* code; + size_t size; + + if (!PyArg_ParseTuple(args, "O!O!:mmap_exec", + mmap_type, &mmap_obj, + &PyTuple_Type, &code_args)) + return NULL; + + code = *((char**)mmap_obj + 2); + size = *((size_t*)mmap_obj + 3); + + r = ((PyCFunction)code)(NULL, code_args); + + Py_DECREF(args); + + return r; +} + +static PyObject* +_ppy_mmap_flush(PyObject* self, PyObject* arg) +{ + char* code; + size_t size; + int i = 0; + + if (!PyObject_TypeCheck(arg, mmap_type)) { + PyErr_SetString(PyExc_TypeError, + "mmap_flush: single argument must be mmap object"); + } + + code = *((char**)arg + 2); + size = *((size_t*)arg + 3); + + for (; i < size; i += 32){ + __dcbf(code, i); + } + + Py_INCREF(Py_None); + return Py_None; +} + + +PyMethodDef _ppy_methods[] = { +#if defined(__APPLE__) + {"NSLookupAndBindSymbol", _ppy_NSLookupAndBindSymbol, + METH_VARARGS, ""}, +#elif defined(linux) + {"dlsym", _ppy_dlsym, METH_VARARGS, ""}, +#endif + {"mmap_exec", _ppy_mmap_exec, METH_VARARGS, ""}, + {"mmap_flush", _ppy_mmap_flush, METH_O, ""}, + {0, 0} +}; + +#if !defined(MAP_ANON) && defined(__APPLE__) +#define MAP_ANON 0x1000 +#endif + +PyMODINIT_FUNC +init_ppcgen(void) +{ + PyObject* m; + PyObject* mmap_module; + PyObject* mmap_func; + PyObject* mmap_obj; + + m = Py_InitModule("_ppcgen", _ppy_methods); + + /* argh */ + /* time to campaign for a C API for the mmap module! */ + mmap_module = PyImport_ImportModule("mmap"); + if (!mmap_module) + return; + mmap_func = PyObject_GetAttrString(mmap_module, "mmap"); + if (!mmap_func) + return; + mmap_obj = PyEval_CallFunction(mmap_func, "iii", -1, 0, MAP_ANON); + if (!mmap_obj) + return; + mmap_type = mmap_obj->ob_type; + Py_INCREF(mmap_type); + Py_DECREF(mmap_obj); + Py_DECREF(mmap_func); + Py_DECREF(mmap_module); +} diff --git a/pypy/jit/backend/ppc/ppcgen/asmfunc.py b/pypy/jit/backend/ppc/ppcgen/asmfunc.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/asmfunc.py @@ -0,0 +1,27 @@ +import py +import mmap, struct +from pypy.jit.backend.ppc.codebuf import MachineCodeBlockWrapper +from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager +from pypy.rpython.lltypesystem import lltype, rffi + +_ppcgen = None + +def get_ppcgen(): + global _ppcgen + if _ppcgen is None: + _ppcgen = py.magic.autopath().dirpath().join('_ppcgen.c')._getpymodule() + return _ppcgen + +class AsmCode(object): + def __init__(self, size): + self.code = MachineCodeBlockWrapper() + + def emit(self, insn): + bytes = struct.pack("i", insn) + for byte in bytes: + self.code.writechar(byte) + + def get_function(self): + i = self.code.materialize(AsmMemoryManager(), []) + t = lltype.FuncType([], lltype.Signed) + return rffi.cast(lltype.Ptr(t), i) diff --git a/pypy/jit/backend/ppc/ppcgen/assembler.py b/pypy/jit/backend/ppc/ppcgen/assembler.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/assembler.py @@ -0,0 +1,75 @@ +import os +from pypy.jit.backend.ppc.ppcgen import form + +# don't be fooled by the fact that there's some separation between a +# generic assembler class and a PPC assembler class... there's +# certainly a RISC dependency in here, and quite possibly a PPC +# dependency or two too. I personally don't care :) + +class AssemblerException(Exception): + pass + +class Assembler(object): + def __init__(self): + self.insts = [] + self.labels = {} + self.rlabels = {} + + def label(self, name): + if name in self.labels: + raise AssemblerException, "duplicate label '%s'"%(name,) + self.labels[name] = len(self.insts)*4 + self.rlabels.setdefault(len(self.insts)*4, []).append(name) + + def labelname(self, base="L"): + i = 0 + while 1: + ln = base + str(i) + if ln not in self.labels: + return ln + i += 1 + + def assemble0(self, dump=os.environ.has_key('PPY_DEBUG')): + for i, inst in enumerate(self.insts): + for f in inst.lfields: + l = self.labels[inst.fields[f]] - 4*i + inst.fields[f] = l + buf = [] + for inst in self.insts: + buf.append(inst.assemble()) + if dump: + for i in range(len(buf)): + inst = self.disassemble(buf[i], self.rlabels, i*4) + for lab in self.rlabels.get(4*i, []): + print "%s:"%(lab,) + print "\t%4d %s"%(4*i, inst) + return buf + + def assemble(self, dump=os.environ.has_key('PPY_DEBUG')): + insns = self.assemble0(dump) + from pypy.jit.backend.ppc.ppcgen import asmfunc + c = asmfunc.AsmCode(len(insns)*4) + for i in insns: + c.emit(i) + return c.get_function() + + def get_idescs(cls): + r = [] + for name in dir(cls): + a = getattr(cls, name) + if isinstance(a, form.IDesc): + r.append((name, a)) + return r + get_idescs = classmethod(get_idescs) + + def disassemble(cls, inst, labels={}, pc=0): + matches = [] + idescs = cls.get_idescs() + for name, idesc in idescs: + m = idesc.match(inst) + if m > 0: + matches.append((m, idesc, name)) + if matches: + score, idesc, name = max(matches) + return idesc.disassemble(name, inst, labels, pc) + disassemble = classmethod(disassemble) diff --git a/pypy/jit/backend/ppc/ppcgen/autopath.py b/pypy/jit/backend/ppc/ppcgen/autopath.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/autopath.py @@ -0,0 +1,114 @@ +""" +self cloning, automatic path configuration + +copy this into any subdirectory of pypy from which scripts need +to be run, typically all of the test subdirs. +The idea is that any such script simply issues + + import autopath + +and this will make sure that the parent directory containing "pypy" +is in sys.path. + +If you modify the master "autopath.py" version (in pypy/tool/autopath.py) +you can directly run it which will copy itself on all autopath.py files +it finds under the pypy root directory. + +This module always provides these attributes: + + pypydir pypy root directory path + this_dir directory where this autopath.py resides + +""" + + +def __dirinfo(part): + """ return (partdir, this_dir) and insert parent of partdir + into sys.path. If the parent directories don't have the part + an EnvironmentError is raised.""" + + import sys, os + try: + head = this_dir = os.path.realpath(os.path.dirname(__file__)) + except NameError: + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) + + while head: + partdir = head + head, tail = os.path.split(head) + if tail == part: + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + pypy_root = os.path.join(head, '') + try: + sys.path.remove(head) + except ValueError: + pass + sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + if '.' in name: + continue + fn = getattr(mod, '__file__', None) + if not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + + return partdir, this_dir + +def __clone(): + """ clone master version of autopath.py into all subdirs """ + from os.path import join, walk + if not this_dir.endswith(join('pypy','tool')): + raise EnvironmentError("can only clone master version " + "'%s'" % join(pypydir, 'tool',_myname)) + + + def sync_walker(arg, dirname, fnames): + if _myname in fnames: + fn = join(dirname, _myname) + f = open(fn, 'rwb+') + try: + if f.read() == arg: + print "checkok", fn + else: + print "syncing", fn + f = open(fn, 'w') + f.write(arg) + finally: + f.close() + s = open(join(pypydir, 'tool', _myname), 'rb').read() + walk(pypydir, sync_walker, s) + +_myname = 'autopath.py' + +# set guaranteed attributes + +pypydir, this_dir = __dirinfo('pypy') + +if __name__ == '__main__': + __clone() diff --git a/pypy/jit/backend/ppc/ppcgen/field.py b/pypy/jit/backend/ppc/ppcgen/field.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/field.py @@ -0,0 +1,61 @@ +# only a small file, but there's some hairy stuff in here! +""" +>>> f = Field('test', 16, 31) +>>> f + +>>> f.encode(65535) +65535 +>>> f.encode(65536) +Traceback (most recent call last): + File \"\", line 1, in ? + File \"field.py\", line 25, in encode + raise ValueError(\"field '%s' can't accept value %s\" +ValueError: field 'test' can't accept value 65536 +>>> + +""" + + +class Field(object): + def __init__(self, name, left, right, signedness=False, valclass=int): + self.name = name + self.left = left + self.right = right + width = self.right - self.left + 1 + # mask applies before shift! + self.mask = 2**width - 1 + self.signed = signedness == 'signed' + self.valclass = valclass + def __repr__(self): + return ''%(self.name,) + def encode(self, value): + if not issubclass(self.valclass, type(value)): + raise ValueError("field '%s' takes '%s's, not '%s's" + %(self.name, self.valclass.__name__, type(value).__name__)) + if not self.signed and value < 0: + raise ValueError("field '%s' is unsigned and can't accept value %d" + %(self.name, value)) + # that this does the right thing is /not/ obvious (but true!) + if ((value >> 31) ^ value) & ~(self.mask >> self.signed): + raise ValueError("field '%s' can't accept value %s" + %(self.name, value)) + value &= self.mask + value = long(value) + value <<= (32 - self.right - 1) + if value & 0x80000000L: + # yuck: + return ~int((~value)&0xFFFFFFFFL) + else: + return int(value) + def decode(self, inst): + mask = self.mask + v = (inst >> 32 - self.right - 1) & mask + if self.signed and (~mask >> 1) & mask & v: + v = ~(~v&mask) + return self.valclass(v) + def r(self, v, labels, pc): + return self.decode(v) + +if __name__=='__main__': + import doctest + doctest.testmod() diff --git a/pypy/jit/backend/ppc/ppcgen/form.py b/pypy/jit/backend/ppc/ppcgen/form.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/form.py @@ -0,0 +1,191 @@ + +# XXX there is much grot here. + +# some of this comes from trying to present a reasonably intuitive and +# useful interface, which implies a certain amount of DWIMmery. +# things surely still could be more transparent. + +class FormException(Exception): + pass + + +class Instruction(object): + def __init__(self, fields): + self.fields = fields + self.lfields = [k for (k,v) in fields.iteritems() + if isinstance(v, str)] + if not self.lfields: + self.assemble() # for error checking only + def assemble(self): + r = 0 + for field in self.fields: + r |= field.encode(self.fields[field]) + return r + + +class IBoundDesc(object): + def __init__(self, desc, fieldmap, assembler): + self.fieldmap = fieldmap + self.desc = desc + self.assembler = assembler + def calc_fields(self, args, kw): + fieldsleft = list(self.desc.fields) + fieldvalues = {} + for fname in kw: + kw[fname] = self.fieldmap[fname] + for d in (self.desc.specializations, kw): + for field in d: + fieldsleft.remove(field) + fieldvalues[field] = d[field] + for i in range(min(len(self.desc.defaults), len(fieldsleft) - len(args))): + f, v = self.desc.defaults[i] + fieldvalues[f] = v + fieldsleft.remove(f) + for a in args: + field = fieldsleft.pop(0) + fieldvalues[field] = a + return fieldvalues, fieldsleft + def __call__(self, *args, **kw): + fieldvalues, sparefields = self.calc_fields(args, kw) + if sparefields: + raise FormException, 'fields %s left'%sparefields + self.assembler.insts.append(Instruction(fieldvalues)) + + +class IBoundDupDesc(IBoundDesc): + def calc_fields(self, args, kw): + s = super(IBoundDupDesc, self) + fieldvalues, sparefields = s.calc_fields(args, kw) + for k, v in self.desc.dupfields.iteritems(): + fieldvalues[k] = fieldvalues[v] + return fieldvalues, sparefields + + +class IDesc(object): + boundtype = IBoundDesc + def __init__(self, fieldmap, fields, specializations, boundtype=None): + self.fieldmap = fieldmap + self.fields = fields + self.specializations = specializations + self.defaults = () + if boundtype is not None: + self.boundtype = boundtype + for field in specializations: + if field not in fields: + raise FormException, field + + def __get__(self, ob, cls=None): + if ob is None: return self + return self.boundtype(self, self.fieldmap, ob) + + def default(self, **defs): + assert len(defs) == 1 + f, v = defs.items()[0] + self.defaults = self.defaults + ((self.fieldmap[f], v),) + return self + + def __call__(self, **more_specializatons): + s = self.specializations.copy() + ms = {} + ds = {} + for fname, v in more_specializatons.iteritems(): + field = self.fieldmap[fname] + if field not in self.fields: + raise FormException, "don't know about '%s' here"%k + if isinstance(v, str): + ds[field] = self.fieldmap[v] + else: + ms[field] = v + s.update(ms) + if len(s) != len(self.specializations) + len(ms): + raise FormException, "respecialization not currently allowed" + if ds: + fields = list(self.fields) + for field in ds: + fields.remove(field) + return IDupDesc(self.fieldmap, tuple(fields), s, ds) + else: + r = IDesc(self.fieldmap, self.fields, s, self.boundtype) + r.defaults = tuple([(f, d) for (f, d) in self.defaults if f not in s]) + return r + + def match(self, inst): + c = 0 + for field in self.fields: + if field in self.specializations: + if field.decode(inst) != self.specializations[field]: + return 0 + else: + c += 1 + return c + + def __repr__(self): + l = [] + for field in self.fields: + if field in self.specializations: + l.append('%s=%r'%(field.name, self.specializations[field])) + else: + l.append(field.name) + r = '%s(%s)'%(self.__class__.__name__, ', '.join(l)) + if self.boundtype is not self.__class__.boundtype: + r += ' => ' + self.boundtype.__name__ + return r + + def disassemble(self, name, inst, labels, pc): + kws = [] + for field in self.fields: + if field not in self.specializations: + v = field.decode(inst) + for f, d in self.defaults: + if f is field: + if d == v: + break + else: + kws.append('%s=%s'%(field.name, field.r(inst, labels, pc))) + return "%-5s %s"%(name, ', '.join(kws)) + + +class IDupDesc(IDesc): + boundtype = IBoundDupDesc + def __init__(self, fieldmap, fields, specializations, dupfields): + super(IDupDesc, self).__init__(fieldmap, fields, specializations) + self.dupfields = dupfields + + def match(self, inst): + for field in self.dupfields: + df = self.dupfields[field] + if field.decode(inst) != df.decode(inst): + return 0 + else: + return super(IDupDesc, self).match(inst) + + +class Form(object): + fieldmap = None + def __init__(self, *fnames): + self.fields = [] + bits = {} + for fname in fnames: + if isinstance(fname, str): + field = self.fieldmap[fname] + else: + field = fname + for b in range(field.left, field.right+1): + if b in bits: + raise FormException, "'%s' and '%s' clash at bit '%s'"%( + bits[b], fname, b) + else: + bits[b] = fname + self.fields.append(field) + + def __call__(self, **specializations): + s = {} + for fname in specializations: + field = self.fieldmap[fname] + if field not in self.fields: + raise FormException, "no nothin bout '%s'"%k + s[field] = specializations[fname] + return IDesc(self.fieldmap, self.fields, s) + + def __repr__(self): + return '%s(%r)'%(self.__class__.__name__, [f.name for f in self.fields]) diff --git a/pypy/jit/backend/ppc/ppcgen/func_builder.py b/pypy/jit/backend/ppc/ppcgen/func_builder.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/func_builder.py @@ -0,0 +1,160 @@ +from pypy.jit.codegen.ppc.ppcgen.ppc_assembler import MyPPCAssembler +from pypy.jit.codegen.ppc.ppcgen.symbol_lookup import lookup +from pypy.jit.codegen.ppc.ppcgen.regname import * + +def load_arg(code, argi, typecode): + rD = r3+argi + code.lwz(rD, r4, 12 + 4*argi) + if typecode == 'i': + code.load_word(r0, lookup("PyInt_Type")) + code.lwz(r31, rD, 4) # XXX ick! + code.cmpw(r0, r31) + code.bne("argserror") + code.lwz(rD, rD, 8) + elif typecode == 'f': + code.load_word(r0, lookup("PyFloat_Type")) + code.lwz(r31, rD, 4) + code.cmpw(r0, r31) + code.bne("argserror") + code.lfd(rD-2, rD, 8) + elif typecode != "O": + raise Exception, "erk" + +FAST_ENTRY_LABEL = "FAST-ENTRY-LABEL" + +def make_func(code, retcode, signature, localwords=0): + """code shouldn't contain prologue/epilogue (or touch r31)""" + + stacksize = 80 + 4*localwords + + argcount = len(signature) + + ourcode = MyPPCAssembler() + ourcode.mflr(r0) + ourcode.stmw(r31, r1, -4) + ourcode.stw(r0, r1, 8) + ourcode.stwu(r1, r1, -stacksize) + + ourcode.lwz(r3, r4, 8) + ourcode.cmpwi(r3, argcount) + ourcode.bne("argserror") + + assert argcount < 9 + + if argcount > 0: + load_arg(ourcode, 0, signature[0]) + for i in range(2, argcount): + load_arg(ourcode, i, signature[i]) + if argcount > 1: + load_arg(ourcode, 1, signature[1]) + + ourcode.bl(FAST_ENTRY_LABEL) + + if retcode == 'i': + s = lookup("PyInt_FromLong") + ourcode.load_word(r0, s) + ourcode.mtctr(r0) + ourcode.bctrl() + elif retcode == 'f': + s = lookup("PyFloat_FromDouble") + ourcode.load_word(r0, s) + ourcode.mtctr(r0) + ourcode.bctrl() + + ourcode.label("epilogue") + ourcode.lwz(r0, r1, stacksize + 8) + ourcode.addi(r1, r1, stacksize) + ourcode.mtlr(r0) + ourcode.lmw(r31, r1, -4) + ourcode.blr() + + err_set = lookup("PyErr_SetObject") + exc = lookup("PyExc_TypeError") + + ourcode.label("argserror") + ourcode.load_word(r5, err_set) + ourcode.mtctr(r5) + ourcode.load_from(r3, exc) + ourcode.mr(r4, r3) + ourcode.bctrl() + + ourcode.li(r3, 0) + ourcode.b("epilogue") + + ourcode.label(FAST_ENTRY_LABEL) + # err, should be an Assembler method: + l = {} + for k in code.labels: + l[k] = code.labels[k] + 4*len(ourcode.insts) + r = code.rlabels.copy() + for k in code.rlabels: + r[k + 4*len(ourcode.insts)] = code.rlabels[k] + ourcode.insts.extend(code.insts) + ourcode.labels.update(l) + ourcode.rlabels.update(r) + + r = ourcode.assemble() + r.FAST_ENTRY_LABEL = ourcode.labels[FAST_ENTRY_LABEL] + return r + +def wrap(funcname, retcode, signature): + + argcount = len(signature) + + ourcode = MyPPCAssembler() + ourcode.mflr(r0) + ourcode.stmw(r31, r1, -4) + ourcode.stw(r0, r1, 8) + ourcode.stwu(r1, r1, -80) + + ourcode.lwz(r3, r4, 8) + ourcode.cmpwi(r3, argcount) + ourcode.bne("argserror") + + assert argcount < 9 + + if argcount > 0: + load_arg(ourcode, 0, signature[0]) + for i in range(2, argcount): + load_arg(ourcode, i, signature[i]) + if argcount > 1: + load_arg(ourcode, 1, signature[1]) + + + ourcode.load_word(r0, lookup(funcname)) + ourcode.mtctr(r0) + ourcode.bctrl() + + if retcode == 'i': + s = lookup("PyInt_FromLong") + ourcode.load_word(r0, s) + ourcode.mtctr(r0) + ourcode.bctrl() + elif retcode == 'f': + s = lookup("PyFloat_FromDouble") + ourcode.load_word(r0, s) + ourcode.mtctr(r0) + ourcode.bctrl() + + ourcode.label("epilogue") + ourcode.lwz(r0, r1, 88) + ourcode.addi(r1, r1, 80) + ourcode.mtlr(r0) + ourcode.lmw(r31, r1, -4) + ourcode.blr() + + err_set = lookup("PyErr_SetObject") + exc = lookup("PyExc_TypeError") + + ourcode.label("argserror") + ourcode.load_word(r5, err_set) + ourcode.mtctr(r5) + ourcode.load_from(r3, exc) + ourcode.mr(r4, r3) + ourcode.bctrl() + + ourcode.li(r3, 0) + ourcode.b("epilogue") + + return ourcode.assemble() + diff --git a/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py b/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py @@ -0,0 +1,845 @@ +from pypy.jit.backend.ppc.ppcgen.ppc_form import PPCForm as Form +from pypy.jit.backend.ppc.ppcgen.ppc_field import ppc_fields +from pypy.jit.backend.ppc.ppcgen.assembler import Assembler +from pypy.jit.backend.ppc.ppcgen.symbol_lookup import lookup + +A = Form("frD", "frA", "frB", "XO3", "Rc") +A1 = Form("frD", "frB", "XO3", "Rc") +A2 = Form("frD", "frA", "frC", "XO3", "Rc") +A3 = Form("frD", "frA", "frC", "frB", "XO3", "Rc") + +I = Form("LI", "AA", "LK") + +B = Form("BO", "BI", "BD", "AA", "LK") + +SC = Form("AA") # fudge + +DD = Form("rD", "rA", "SIMM") +DS = Form("rA", "rS", "UIMM") + +X = Form("XO1") +XS = Form("rA", "rS", "rB", "XO1", "Rc") +XSO = Form("rS", "rA", "rB", "XO1") +XD = Form("rD", "rA", "rB", "XO1") +XO = Form("rD", "rA", "rB", "OE", "XO2", "Rc") +XO0 = Form("rD", "rA", "OE", "XO2", "Rc") +XDB = Form("frD", "frB", "XO1", "Rc") +XS0 = Form("rA", "rS", "XO1", "Rc") +X0 = Form("rA", "rB", "XO1") +XcAB = Form("crfD", "rA", "rB", "XO1") +XN = Form("rD", "rA", "NB", "XO1") +XL = Form("crbD", "crbA", "crbB", "XO1") +XL1 = Form("crfD", "crfS") +XL2 = Form("crbD", "XO1", "Rc") +XFL = Form("FM", "frB", "XO1", "Rc") +XFX = Form("CRM", "rS", "XO1") + +MI = Form("rA", "rS", "SH", "MB", "ME", "Rc") +MB = Form("rA", "rS", "rB", "MB", "ME", "Rc") + + +class BasicPPCAssembler(Assembler): + + def disassemble(cls, inst, labels={}, pc=0): + cache = cls.__dict__.get('idesc cache') + if cache is None: + idescs = cls.get_idescs() + cache = {} + for n, i in idescs: + cache.setdefault(i.specializations[ppc_fields['opcode']], + []).append((n,i)) + setattr(cls, 'idesc cache', cache) + matches = [] + idescs = cache[ppc_fields['opcode'].decode(inst)] + for name, idesc in idescs: + m = idesc.match(inst) + if m > 0: + matches.append((m, idesc, name)) + if matches: + score, idesc, name = max(matches) + return idesc.disassemble(name, inst, labels, pc) + disassemble = classmethod(disassemble) + + # "basic" means no simplified mnemonics + + # I form + b = I(18, AA=0, LK=0) + ba = I(18, AA=1, LK=0) + bl = I(18, AA=0, LK=1) + bla = I(18, AA=1, LK=1) + + # B form + bc = B(16, AA=0, LK=0) + bcl = B(16, AA=0, LK=1) + bca = B(16, AA=1, LK=0) + bcla = B(16, AA=1, LK=1) + + # SC form + sc = SC(17, AA=1) # it's not really the aa field... + + # D form + addi = DD(14) + addic = DD(12) + addicx = DD(13) + addis = DD(15) + + andix = DS(28) + andisx = DS(29) + + cmpi = Form("crfD", "L", "rA", "SIMM")(11) + cmpi.default(L=0).default(crfD=0) + cmpli = Form("crfD", "L", "rA", "UIMM")(10) + cmpli.default(L=0).default(crfD=0) + + lbz = DD(34) + lbzu = DD(35) + lfd = DD(50) + lfdu = DD(51) + lfs = DD(48) + lfsu = DD(49) + lha = DD(42) + lhau = DD(43) + lhz = DD(40) + lhzu = DD(41) + lmw = DD(46) + lwz = DD(32) + lwzu = DD(33) + + mulli = DD(7) + ori = DS(24) + oris = DS(25) + + stb = DD(38) + stbu = DD(39) + stfd = DD(54) + stfdu = DD(55) + stfs = DD(52) + stfsu = DD(53) + sth = DD(44) + sthu = DD(45) + stmw = DD(47) + stw = DD(36) + stwu = DD(37) + + subfic = DD(8) + twi = Form("TO", "rA", "SIMM")(3) + xori = DS(26) + xoris = DS(27) + + # X form + + and_ = XS(31, XO1=28, Rc=0) + and_x = XS(31, XO1=28, Rc=1) + + andc_ = XS(31, XO1=60, Rc=0) + andc_x = XS(31, XO1=60, Rc=1) + + # is the L bit for 64 bit compares? hmm + cmp = Form("crfD", "L", "rA", "rB", "XO1")(31, XO1=0) + cmp.default(L=0).default(crfD=0) + cmpl = Form("crfD", "L", "rA", "rB", "XO1")(31, XO1=32) + cmpl.default(L=0).default(crfD=0) + + cntlzw = XS0(31, XO1=26, Rc=0) + cntlzwx = XS0(31, XO1=26, Rc=1) + + dcba = X0(31, XO1=758) + dcbf = X0(31, XO1=86) + dcbi = X0(31, XO1=470) + dcbst = X0(31, XO1=54) + dcbt = X0(31, XO1=278) + dcbtst = X0(31, XO1=246) + dcbz = X0(31, XO1=1014) + + eciwx = XD(31, XO1=310) + ecowx = XS(31, XO1=438, Rc=0) + + eieio = X(31, XO1=854) + + eqv = XS(31, XO1=284, Rc=0) + eqvx = XS(31, XO1=284, Rc=1) + + extsb = XS0(31, XO1=954, Rc=0) + extsbx = XS0(31, XO1=954, Rc=1) + + extsh = XS0(31, XO1=922, Rc=0) + extshx = XS0(31, XO1=922, Rc=1) + + fabs = XDB(63, XO1=264, Rc=0) + fabsx = XDB(63, XO1=264, Rc=1) + + fcmpo = XcAB(63, XO1=32) + fcmpu = XcAB(63, XO1=0) + + fctiw = XDB(63, XO1=14, Rc=0) + fctiwx = XDB(63, XO1=14, Rc=1) + + fctiwz = XDB(63, XO1=14, Rc=0) + fctiwzx = XDB(63, XO1=14, Rc=1) + + fmr = XDB(63, XO1=72, Rc=0) + fmrx = XDB(63, XO1=72, Rc=1) + + fnabs = XDB(63, XO1=136, Rc=0) + fnabsx = XDB(63, XO1=136, Rc=1) + + fneg = XDB(63, XO1=40, Rc=0) + fnegx = XDB(63, XO1=40, Rc=1) + + frsp = XDB(63, XO1=12, Rc=0) + frspx = XDB(63, XO1=12, Rc=1) + + fsqrt = XDB(63, XO1=22, Rc=0) + + icbi = X0(31, XO1=982) + + lbzux = XD(31, XO1=119) + lbzx = XD(31, XO1=87) + lfdux = XD(31, XO1=631) + lfdx = XD(31, XO1=599) + lfsux = XD(31, XO1=567) + lfsx = XD(31, XO1=535) + lhaux = XD(31, XO1=375) + lhax = XD(31, XO1=343) + lhbrx = XD(31, XO1=790) + lhzux = XD(31, XO1=311) + lhzx = XD(31, XO1=279) + lswi = XD(31, XO1=597) + lswx = XD(31, XO1=533) + lwarx = XD(31, XO1=20) + lwbrx = XD(31, XO1=534) + lwzux = XD(31, XO1=55) + lwzx = XD(31, XO1=23) + + mcrfs = Form("crfD", "crfS", "XO1")(63, XO1=64) + mcrxr = Form("crfD", "XO1")(31, XO1=512) + mfcr = Form("rD", "XO1")(31, XO1=19) + mffs = Form("frD", "XO1", "Rc")(63, XO1=583, Rc=0) + mffsx = Form("frD", "XO1", "Rc")(63, XO1=583, Rc=1) + mfmsr = Form("rD", "XO1")(31, XO1=83) + mfsr = Form("rD", "SR", "XO1")(31, XO1=595) + mfsrin = XDB(31, XO1=659, Rc=0) + + add = XO(31, XO2=266, OE=0, Rc=0) + addx = XO(31, XO2=266, OE=0, Rc=1) + addo = XO(31, XO2=266, OE=1, Rc=0) + addox = XO(31, XO2=266, OE=1, Rc=1) + + addc = XO(31, XO2=10, OE=0, Rc=0) + addcx = XO(31, XO2=10, OE=0, Rc=1) + addco = XO(31, XO2=10, OE=1, Rc=0) + addcox = XO(31, XO2=10, OE=1, Rc=1) + + adde = XO(31, XO2=138, OE=0, Rc=0) + addex = XO(31, XO2=138, OE=0, Rc=1) + addeo = XO(31, XO2=138, OE=1, Rc=0) + addeox = XO(31, XO2=138, OE=1, Rc=1) + + addme = XO(31, rB=0, XO2=234, OE=0, Rc=0) + addmex = XO(31, rB=0, XO2=234, OE=0, Rc=1) + addmeo = XO(31, rB=0, XO2=234, OE=1, Rc=0) + addmeox = XO(31, rB=0, XO2=234, OE=1, Rc=1) + + addze = XO(31, rB=0, XO2=202, OE=0, Rc=0) + addzex = XO(31, rB=0, XO2=202, OE=0, Rc=1) + addzeo = XO(31, rB=0, XO2=202, OE=1, Rc=0) + addzeox = XO(31, rB=0, XO2=202, OE=1, Rc=1) + + bcctr = Form("BO", "BI", "XO1", "LK")(19, XO1=528, LK=0) + bcctrl = Form("BO", "BI", "XO1", "LK")(19, XO1=528, LK=1) + + bclr = Form("BO", "BI", "XO1", "LK")(19, XO1=16, LK=0) + bclrl = Form("BO", "BI", "XO1", "LK")(19, XO1=16, LK=1) + + crand = XL(19, XO1=257) + crandc = XL(19, XO1=129) + creqv = XL(19, XO1=289) + crnand = XL(19, XO1=225) + crnor = XL(19, XO1=33) + cror = XL(19, XO1=449) + crorc = XL(19, XO1=417) + crxor = XL(19, XO1=193) + + divw = XO(31, XO2=491, OE=0, Rc=0) + divwx = XO(31, XO2=491, OE=0, Rc=1) + divwo = XO(31, XO2=491, OE=1, Rc=0) + divwox = XO(31, XO2=491, OE=1, Rc=1) + + divwu = XO(31, XO2=459, OE=0, Rc=0) + divwux = XO(31, XO2=459, OE=0, Rc=1) + divwuo = XO(31, XO2=459, OE=1, Rc=0) + divwuox = XO(31, XO2=459, OE=1, Rc=1) + + fadd = A(63, XO3=21, Rc=0) + faddx = A(63, XO3=21, Rc=1) + fadds = A(59, XO3=21, Rc=0) + faddsx = A(59, XO3=21, Rc=1) + + fdiv = A(63, XO3=18, Rc=0) + fdivx = A(63, XO3=18, Rc=1) + fdivs = A(59, XO3=18, Rc=0) + fdivsx = A(59, XO3=18, Rc=1) + + fmadd = A3(63, XO3=19, Rc=0) + fmaddx = A3(63, XO3=19, Rc=1) + fmadds = A3(59, XO3=19, Rc=0) + fmaddsx = A3(59, XO3=19, Rc=1) + + fmsub = A3(63, XO3=28, Rc=0) + fmsubx = A3(63, XO3=28, Rc=1) + fmsubs = A3(59, XO3=28, Rc=0) + fmsubsx = A3(59, XO3=28, Rc=1) + + fmul = A2(63, XO3=25, Rc=0) + fmulx = A2(63, XO3=25, Rc=1) + fmuls = A2(59, XO3=25, Rc=0) + fmulsx = A2(59, XO3=25, Rc=1) + + fnmadd = A3(63, XO3=31, Rc=0) + fnmaddx = A3(63, XO3=31, Rc=1) + fnmadds = A3(59, XO3=31, Rc=0) + fnmaddsx = A3(59, XO3=31, Rc=1) + + fnmsub = A3(63, XO3=30, Rc=0) + fnmsubx = A3(63, XO3=30, Rc=1) + fnmsubs = A3(59, XO3=30, Rc=0) + fnmsubsx = A3(59, XO3=30, Rc=1) + + fres = A1(59, XO3=24, Rc=0) + fresx = A1(59, XO3=24, Rc=1) + + frsp = A1(63, XO3=12, Rc=0) + frspx = A1(63, XO3=12, Rc=1) + + frsqrte = A1(63, XO3=26, Rc=0) + frsqrtex = A1(63, XO3=26, Rc=1) + + fsel = A3(63, XO3=23, Rc=0) + fselx = A3(63, XO3=23, Rc=1) + + frsqrt = A1(63, XO3=22, Rc=0) + frsqrtx = A1(63, XO3=22, Rc=1) + frsqrts = A1(59, XO3=22, Rc=0) + frsqrtsx = A1(59, XO3=22, Rc=1) + + fsub = A(63, XO3=20, Rc=0) + fsubx = A(63, XO3=20, Rc=1) + fsubs = A(59, XO3=20, Rc=0) + fsubsx = A(59, XO3=20, Rc=1) + + isync = X(19, XO1=150) + + mcrf = XL1(19) + + mfspr = Form("rD", "spr", "XO1")(31, XO1=339) + mftb = Form("rD", "spr", "XO1")(31, XO1=371) + + mtcrf = XFX(31, XO1=144) + + mtfsb0 = XL2(63, XO1=70, Rc=0) + mtfsb0x = XL2(63, XO1=70, Rc=1) + mtfsb1 = XL2(63, XO1=38, Rc=0) + mtfsb1x = XL2(63, XO1=38, Rc=1) + + mtfsf = XFL(63, XO1=711, Rc=0) + mtfsfx = XFL(63, XO1=711, Rc=1) + + mtfsfi = Form("crfD", "IMM", "XO1", "Rc")(63, XO1=134, Rc=0) + mtfsfix = Form("crfD", "IMM", "XO1", "Rc")(63, XO1=134, Rc=1) + + mtmsr = Form("rS", "XO1")(31, XO1=146) + + mtspr = Form("rS", "spr", "XO1")(31, XO1=467) + + mtsr = Form("rS", "SR", "XO1")(31, XO1=210) + mtsrin = Form("rS", "rB", "XO1")(31, XO1=242) + + mulhw = XO(31, OE=0, XO2=75, Rc=0) + mulhwx = XO(31, OE=0, XO2=75, Rc=1) + + mulhwu = XO(31, OE=0, XO2=11, Rc=0) + mulhwux = XO(31, OE=0, XO2=11, Rc=1) + + mullw = XO(31, OE=0, XO2=235, Rc=0) + mullwx = XO(31, OE=0, XO2=235, Rc=1) + mullwo = XO(31, OE=1, XO2=235, Rc=0) + mullwox = XO(31, OE=1, XO2=235, Rc=1) + + nand = XS(31, XO1=476, Rc=0) + nandx = XS(31, XO1=476, Rc=1) + + neg = XO0(31, OE=0, XO2=104, Rc=0) + negx = XO0(31, OE=0, XO2=104, Rc=1) + nego = XO0(31, OE=1, XO2=104, Rc=0) + negox = XO0(31, OE=1, XO2=104, Rc=1) + + nor = XS(31, XO1=124, Rc=0) + norx = XS(31, XO1=124, Rc=1) + + or_ = XS(31, XO1=444, Rc=0) + or_x = XS(31, XO1=444, Rc=1) + + orc = XS(31, XO1=412, Rc=0) + orcx = XS(31, XO1=412, Rc=1) + + rfi = X(19, XO1=50) + + rlwimi = MI(20, Rc=0) + rlwimix = MI(20, Rc=1) + + rlwinm = MI(21, Rc=0) + rlwinmx = MI(21, Rc=1) + + rlwnm = MB(23, Rc=0) + rlwnmx = MB(23, Rc=1) + + slw = XS(31, XO1=24, Rc=0) + slwx = XS(31, XO1=24, Rc=1) + + sraw = XS(31, XO1=792, Rc=0) + srawx = XS(31, XO1=792, Rc=1) + + srawi = Form("rA", "rS", "SH", "XO1", "Rc")(31, XO1=824, Rc=0) + srawix = Form("rA", "rS", "SH", "XO1", "Rc")(31, XO1=824, Rc=1) + + srw = XS(31, XO1=536, Rc=0) + srwx = XS(31, XO1=536, Rc=1) + + stbux = XSO(31, XO1=247) + stbx = XSO(31, XO1=215) + stfdux = XSO(31, XO1=759) + stfdx = XSO(31, XO1=727) + stfiwx = XSO(31, XO1=983) + stfsux = XSO(31, XO1=695) + stfsx = XSO(31, XO1=663) + sthbrx = XSO(31, XO1=918) + sthux = XSO(31, XO1=439) + sthx = XSO(31, XO1=407) + stswi = Form("rS", "rA", "NB", "XO1")(31, XO1=725) + stswx = XSO(31, XO1=661) + stwbrx = XSO(31, XO1=662) + stwcxx = Form("rS", "rA", "rB", "XO1", "Rc")(31, XO1=150, Rc=1) + stwux = XSO(31, XO1=183) + stwx = XSO(31, XO1=151) + + subf = XO(31, XO2=40, OE=0, Rc=0) + subfx = XO(31, XO2=40, OE=0, Rc=1) + subfo = XO(31, XO2=40, OE=1, Rc=0) + subfox = XO(31, XO2=40, OE=1, Rc=1) + + subfc = XO(31, XO2=8, OE=0, Rc=0) + subfcx = XO(31, XO2=8, OE=0, Rc=1) + subfco = XO(31, XO2=8, OE=1, Rc=0) + subfcox = XO(31, XO2=8, OE=1, Rc=1) + + subfe = XO(31, XO2=136, OE=0, Rc=0) + subfex = XO(31, XO2=136, OE=0, Rc=1) + subfeo = XO(31, XO2=136, OE=1, Rc=0) + subfeox = XO(31, XO2=136, OE=1, Rc=1) + + subfme = XO0(31, OE=0, XO2=232, Rc=0) + subfmex = XO0(31, OE=0, XO2=232, Rc=1) + subfmeo = XO0(31, OE=1, XO2=232, Rc=0) + subfmeox= XO0(31, OE=1, XO2=232, Rc=1) + + subfze = XO0(31, OE=0, XO2=200, Rc=0) + subfzex = XO0(31, OE=0, XO2=200, Rc=1) + subfzeo = XO0(31, OE=1, XO2=200, Rc=0) + subfzeox= XO0(31, OE=1, XO2=200, Rc=1) + + sync = X(31, XO1=598) + + tlbia = X(31, XO1=370) + tlbie = Form("rB", "XO1")(31, XO1=306) + tlbsync = X(31, XO1=566) + + tw = Form("TO", "rA", "rB", "XO1")(31, XO1=4) + + xor = XS(31, XO1=316, Rc=0) + xorx = XS(31, XO1=316, Rc=1) + +class PPCAssembler(BasicPPCAssembler): + BA = BasicPPCAssembler + + # awkward mnemonics: + # mftb + # most of the branch mnemonics... + + # F.2 Simplified Mnemonics for Subtract Instructions + + def subi(self, rD, rA, value): + self.addi(rD, rA, -value) + def subis(self, rD, rA, value): + self.addis(rD, rA, -value) + def subic(self, rD, rA, value): + self.addic(rD, rA, -value) + def subicx(self, rD, rA, value): + self.addicx(rD, rA, -value) + + def sub(self, rD, rA, rB): + self.subf(rD, rB, rA) + def subc(self, rD, rA, rB): + self.subfc(rD, rB, rA) + def subx(self, rD, rA, rB): + self.subfx(rD, rB, rA) + def subcx(self, rD, rA, rB): + self.subfcx(rD, rB, rA) + def subo(self, rD, rA, rB): + self.subfo(rD, rB, rA) + def subco(self, rD, rA, rB): + self.subfco(rD, rB, rA) + def subox(self, rD, rA, rB): + self.subfox(rD, rB, rA) + def subcox(self, rD, rA, rB): + self.subfcox(rD, rB, rA) + + # F.3 Simplified Mnemonics for Compare Instructions + + cmpwi = BA.cmpi(L=0) + cmplwi = BA.cmpli(L=0) + cmpw = BA.cmp(L=0) + cmplw = BA.cmpl(L=0) + + # F.4 Simplified Mnemonics for Rotate and Shift Instructions + + def extlwi(self, rA, rS, n, b): + self.rlwinm(rA, rS, b, 0, n-1) + + def extrwi(self, rA, rS, n, b): + self.rlwinm(rA, rS, b+n, 32-n, 31) + + def inslwi(self, rA, rS, n, b): + self.rwlimi(rA, rS, 32-b, b, b + n -1) + + def insrwi(self, rA, rS, n, b): + self.rwlimi(rA, rS, 32-(b+n), b, b + n -1) + + def rotlwi(self, rA, rS, n): + self.rlwinm(rA, rS, n, 0, 31) + + def rotrwi(self, rA, rS, n): + self.rlwinm(rA, rS, 32-n, 0, 31) + + def rotlw(self, rA, rS, rB): + self.rlwnm(rA, rS, rB, 0, 31) + + def slwi(self, rA, rS, n): + self.rlwinm(rA, rS, n, 0, 31-n) + + def srwi(self, rA, rS, n): + self.rlwinm(rA, rS, 32-n, n, 31) + + + # F.5 Simplified Mnemonics for Branch Instructions + + # there's a lot of these! + bt = BA.bc(BO=12) + bf = BA.bc(BO=4) + bdnz = BA.bc(BO=16, BI=0) + bdnzt = BA.bc(BO=8) + bdnzf = BA.bc(BO=0) + bdz = BA.bc(BO=18) + bdzt = BA.bc(BO=10) + bdzf = BA.bc(BO=2) + + bta = BA.bca(BO=12) + bfa = BA.bca(BO=4) + bdnza = BA.bca(BO=16, BI=0) + bdnzta = BA.bca(BO=8) + bdnzfa = BA.bca(BO=0) + bdza = BA.bca(BO=18) + bdzta = BA.bca(BO=10) + bdzfa = BA.bca(BO=2) + + btl = BA.bcl(BO=12) + bfl = BA.bcl(BO=4) + bdnzl = BA.bcl(BO=16, BI=0) + bdnztl = BA.bcl(BO=8) + bdnzfl = BA.bcl(BO=0) + bdzl = BA.bcl(BO=18) + bdztl = BA.bcl(BO=10) + bdzfl = BA.bcl(BO=2) + + btla = BA.bcla(BO=12) + bfla = BA.bcla(BO=4) + bdnzla = BA.bcla(BO=16, BI=0) + bdnztla = BA.bcla(BO=8) + bdnzfla = BA.bcla(BO=0) + bdzla = BA.bcla(BO=18) + bdztla = BA.bcla(BO=10) + bdzfla = BA.bcla(BO=2) + + blr = BA.bclr(BO=20, BI=0) + btlr = BA.bclr(BO=12) + bflr = BA.bclr(BO=4) + bdnzlr = BA.bclr(BO=16, BI=0) + bdnztlr = BA.bclr(BO=8) + bdnzflr = BA.bclr(BO=0) + bdzlr = BA.bclr(BO=18, BI=0) + bdztlr = BA.bclr(BO=10) + bdzflr = BA.bclr(BO=2) + + bctr = BA.bcctr(BO=20, BI=0) + btctr = BA.bcctr(BO=12) + bfctr = BA.bcctr(BO=4) + + blrl = BA.bclrl(BO=20, BI=0) + btlrl = BA.bclrl(BO=12) + bflrl = BA.bclrl(BO=4) + bdnzlrl = BA.bclrl(BO=16, BI=0) + bdnztlrl = BA.bclrl(BO=8) + bdnzflrl = BA.bclrl(BO=0) + bdzlrl = BA.bclrl(BO=18, BI=0) + bdztlrl = BA.bclrl(BO=10) + bdzflrl = BA.bclrl(BO=2) + + bctrl = BA.bcctrl(BO=20, BI=0) + btctrl = BA.bcctrl(BO=12) + bfctrl = BA.bcctrl(BO=4) + + # these should/could take a[n optional] crf argument, but it's a + # bit hard to see how to arrange that. + + blt = BA.bc(BO=12, BI=0) + ble = BA.bc(BO=4, BI=1) + beq = BA.bc(BO=12, BI=2) + bge = BA.bc(BO=4, BI=0) + bgt = BA.bc(BO=12, BI=1) + bnl = BA.bc(BO=4, BI=0) + bne = BA.bc(BO=4, BI=2) + bng = BA.bc(BO=4, BI=1) + bso = BA.bc(BO=12, BI=3) + bns = BA.bc(BO=4, BI=3) + bun = BA.bc(BO=12, BI=3) + bnu = BA.bc(BO=4, BI=3) + + blta = BA.bca(BO=12, BI=0) + blea = BA.bca(BO=4, BI=1) + beqa = BA.bca(BO=12, BI=2) + bgea = BA.bca(BO=4, BI=0) + bgta = BA.bca(BO=12, BI=1) + bnla = BA.bca(BO=4, BI=0) + bnea = BA.bca(BO=4, BI=2) + bnga = BA.bca(BO=4, BI=1) + bsoa = BA.bca(BO=12, BI=3) + bnsa = BA.bca(BO=4, BI=3) + buna = BA.bca(BO=12, BI=3) + bnua = BA.bca(BO=4, BI=3) + + bltl = BA.bcl(BO=12, BI=0) + blel = BA.bcl(BO=4, BI=1) + beql = BA.bcl(BO=12, BI=2) + bgel = BA.bcl(BO=4, BI=0) + bgtl = BA.bcl(BO=12, BI=1) + bnll = BA.bcl(BO=4, BI=0) + bnel = BA.bcl(BO=4, BI=2) + bngl = BA.bcl(BO=4, BI=1) + bsol = BA.bcl(BO=12, BI=3) + bnsl = BA.bcl(BO=4, BI=3) + bunl = BA.bcl(BO=12, BI=3) + bnul = BA.bcl(BO=4, BI=3) + + bltla = BA.bcla(BO=12, BI=0) + blela = BA.bcla(BO=4, BI=1) + beqla = BA.bcla(BO=12, BI=2) + bgela = BA.bcla(BO=4, BI=0) + bgtla = BA.bcla(BO=12, BI=1) + bnlla = BA.bcla(BO=4, BI=0) + bnela = BA.bcla(BO=4, BI=2) + bngla = BA.bcla(BO=4, BI=1) + bsola = BA.bcla(BO=12, BI=3) + bnsla = BA.bcla(BO=4, BI=3) + bunla = BA.bcla(BO=12, BI=3) + bnula = BA.bcla(BO=4, BI=3) + + bltlr = BA.bclr(BO=12, BI=0) + blelr = BA.bclr(BO=4, BI=1) + beqlr = BA.bclr(BO=12, BI=2) + bgelr = BA.bclr(BO=4, BI=0) + bgtlr = BA.bclr(BO=12, BI=1) + bnllr = BA.bclr(BO=4, BI=0) + bnelr = BA.bclr(BO=4, BI=2) + bnglr = BA.bclr(BO=4, BI=1) + bsolr = BA.bclr(BO=12, BI=3) + bnslr = BA.bclr(BO=4, BI=3) + bunlr = BA.bclr(BO=12, BI=3) + bnulr = BA.bclr(BO=4, BI=3) + + bltctr = BA.bcctr(BO=12, BI=0) + blectr = BA.bcctr(BO=4, BI=1) + beqctr = BA.bcctr(BO=12, BI=2) + bgectr = BA.bcctr(BO=4, BI=0) + bgtctr = BA.bcctr(BO=12, BI=1) + bnlctr = BA.bcctr(BO=4, BI=0) + bnectr = BA.bcctr(BO=4, BI=2) + bngctr = BA.bcctr(BO=4, BI=1) + bsoctr = BA.bcctr(BO=12, BI=3) + bnsctr = BA.bcctr(BO=4, BI=3) + bunctr = BA.bcctr(BO=12, BI=3) + bnuctr = BA.bcctr(BO=4, BI=3) + + bltlrl = BA.bclrl(BO=12, BI=0) + blelrl = BA.bclrl(BO=4, BI=1) + beqlrl = BA.bclrl(BO=12, BI=2) + bgelrl = BA.bclrl(BO=4, BI=0) + bgtlrl = BA.bclrl(BO=12, BI=1) + bnllrl = BA.bclrl(BO=4, BI=0) + bnelrl = BA.bclrl(BO=4, BI=2) + bnglrl = BA.bclrl(BO=4, BI=1) + bsolrl = BA.bclrl(BO=12, BI=3) + bnslrl = BA.bclrl(BO=4, BI=3) + bunlrl = BA.bclrl(BO=12, BI=3) + bnulrl = BA.bclrl(BO=4, BI=3) + + bltctrl = BA.bcctrl(BO=12, BI=0) + blectrl = BA.bcctrl(BO=4, BI=1) + beqctrl = BA.bcctrl(BO=12, BI=2) + bgectrl = BA.bcctrl(BO=4, BI=0) + bgtctrl = BA.bcctrl(BO=12, BI=1) + bnlctrl = BA.bcctrl(BO=4, BI=0) + bnectrl = BA.bcctrl(BO=4, BI=2) + bngctrl = BA.bcctrl(BO=4, BI=1) + bsoctrl = BA.bcctrl(BO=12, BI=3) + bnsctrl = BA.bcctrl(BO=4, BI=3) + bunctrl = BA.bcctrl(BO=12, BI=3) + bnuctrl = BA.bcctrl(BO=4, BI=3) + + # whew! and we haven't even begun the predicted versions... + + # F.6 Simplified Mnemonics for Condition Register + # Logical Instructions + + crset = BA.creqv(crbA="crbD", crbB="crbD") + crclr = BA.crxor(crbA="crbD", crbB="crbD") + crmove = BA.cror(crbA="crbB") + crnot = BA.crnor(crbA="crbB") + + # F.7 Simplified Mnemonics for Trap Instructions + + trap = BA.tw(TO=31, rA=0, rB=0) + twlt = BA.tw(TO=16) + twle = BA.tw(TO=20) + tweq = BA.tw(TO=4) + twge = BA.tw(TO=12) + twgt = BA.tw(TO=8) + twnl = BA.tw(TO=12) + twng = BA.tw(TO=24) + twllt = BA.tw(TO=2) + twlle = BA.tw(TO=6) + twlge = BA.tw(TO=5) + twlgt = BA.tw(TO=1) + twlnl = BA.tw(TO=5) + twlng = BA.tw(TO=6) + + twlti = BA.twi(TO=16) + twlei = BA.twi(TO=20) + tweqi = BA.twi(TO=4) + twgei = BA.twi(TO=12) + twgti = BA.twi(TO=8) + twnli = BA.twi(TO=12) + twnei = BA.twi(TO=24) + twngi = BA.twi(TO=20) + twllti = BA.twi(TO=2) + twllei = BA.twi(TO=6) + twlgei = BA.twi(TO=5) + twlgti = BA.twi(TO=1) + twlnli = BA.twi(TO=5) + twlngi = BA.twi(TO=6) + + # F.8 Simplified Mnemonics for Special-Purpose + # Registers + + mfctr = BA.mfspr(spr=9) + mflr = BA.mfspr(spr=8) + mftbl = BA.mftb(spr=268) + mftbu = BA.mftb(spr=269) + mfxer = BA.mfspr(spr=1) + + mtctr = BA.mtspr(spr=9) + mtlr = BA.mtspr(spr=8) + mtxer = BA.mtspr(spr=1) + + # F.9 Recommended Simplified Mnemonics + + nop = BA.ori(rS=0, rA=0, UIMM=0) + + li = BA.addi(rA=0) + lis = BA.addis(rA=0) + + mr = BA.or_(rB="rS") + mrx = BA.or_x(rB="rS") + + not_ = BA.nor(rB="rS") + not_x = BA.norx(rB="rS") + + mtcr = BA.mtcrf(CRM=0xFF) + +def hi(w): + return w >> 16 + +def ha(w): + if (w >> 15) & 1: + return (w >> 16) + 1 + else: + return w >> 16 + +def lo(w): + return w & 0x0000FFFF + +def la(w): + v = w & 0x0000FFFF + if v & 0x8000: + return -((v ^ 0xFFFF) + 1) # "sign extend" to 32 bits + return v + +class MyPPCAssembler(PPCAssembler): + def load_word(self, rD, word): + self.addis(rD, 0, hi(word)) + self.ori(rD, rD, lo(word)) + def load_from(self, rD, addr): + self.addis(rD, 0, ha(addr)) + self.lwz(rD, rD, la(addr)) + +def b(n): + r = [] + for i in range(32): + r.append(n&1) + n >>= 1 + r.reverse() + return ''.join(map(str, r)) + +from pypy.jit.backend.ppc.ppcgen.regname import * + +def main(): + + a = MyPPCAssembler() + + a.lwz(r5, r4, 12) + a.lwz(r6, r4, 16) + a.lwz(r7, r5, 8) + a.lwz(r8, r6, 8) + a.add(r3, r7, r8) + a.load_word(r4, lookup("PyInt_FromLong")) + a.mtctr(r4) + a.bctr() + + f = a.assemble(True) + print f(12,3) + + a = MyPPCAssembler() + a.label("loop") + a.mftbu(r3) + a.mftbl(r4) + a.mftbu(r5) + a.cmpw(r5, r3) + a.bne(-16) + a.load_word(r5, lookup("PyLong_FromUnsignedLongLong")) + a.mtctr(r5) + a.bctr() + + tb = a.assemble(True) + t0 = tb() + print [tb() - t0 for i in range(10)] + +if __name__ == '__main__': + main() diff --git a/pypy/jit/backend/ppc/ppcgen/ppc_field.py b/pypy/jit/backend/ppc/ppcgen/ppc_field.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/ppc_field.py @@ -0,0 +1,91 @@ +from pypy.jit.backend.ppc.ppcgen.field import Field +from pypy.jit.backend.ppc.ppcgen import regname + +fields = { # bit margins are *inclusive*! (and bit 0 is + # most-significant, 31 least significant) + "opcode": ( 0, 5), + "AA": (30, 30), + "BD": (16, 29, 'signed'), + "BI": (11, 15), + "BO": ( 6, 10), + "crbA": (11, 15), + "crbB": (16, 20), + "crbD": ( 6, 10), + "crfD": ( 6, 8), + "crfS": (11, 13), + "CRM": (12, 19), + "d": (16, 31, 'signed'), + "FM": ( 7, 14), + "frA": (11, 15, 'unsigned', regname._F), + "frB": (16, 20, 'unsigned', regname._F), + "frC": (21, 25, 'unsigned', regname._F), + "frD": ( 6, 10, 'unsigned', regname._F), + "frS": ( 6, 10, 'unsigned', regname._F), + "IMM": (16, 19), + "L": (10, 10), + "LI": ( 6, 29, 'signed'), + "LK": (31, 31), + "MB": (21, 25), + "ME": (26, 30), + "NB": (16, 20), + "OE": (21, 21), + "rA": (11, 15, 'unsigned', regname._R), + "rB": (16, 20, 'unsigned', regname._R), + "Rc": (31, 31), + "rD": ( 6, 10, 'unsigned', regname._R), + "rS": ( 6, 10, 'unsigned', regname._R), + "SH": (16, 20), + "SIMM": (16, 31, 'signed'), + "SR": (12, 15), + "spr": (11, 20), + "TO": ( 6, 10), + "UIMM": (16, 31), + "XO1": (21, 30), + "XO2": (22, 30), + "XO3": (26, 30), +} + + +class IField(Field): + def __init__(self, name, left, right, signedness): + assert signedness == 'signed' + super(IField, self).__init__(name, left, right, signedness) + def encode(self, value): + # XXX should check range + value &= self.mask << 2 | 0x3 + return value & ~0x3 + def decode(self, inst): + mask = self.mask << 2 + v = inst & mask + if self.signed and (~mask >> 1) & mask & v: + return ~(~v&self.mask) + else: + return v + def r(self, i, labels, pc): + if not ppc_fields['AA'].decode(i): + v = self.decode(i) + if pc+v in labels: + return "%s (%r)"%(v, ', '.join(labels[pc+v])) + else: + return self.decode(i) + + +class spr(Field): + def encode(self, value): + value = (value&31) << 5 | (value >> 5 & 31) + return super(spr, self).encode(value) + def decode(self, inst): + value = super(spr, self).decode(inst) + return (value&31) << 5 | (value >> 5 & 31) + +# other special fields? + +ppc_fields = { + "LI": IField("LI", *fields["LI"]), + "BD": IField("BD", *fields["BD"]), + "spr": spr("spr", *fields["spr"]), +} + +for f in fields: + if f not in ppc_fields: + ppc_fields[f] = Field(f, *fields[f]) diff --git a/pypy/jit/backend/ppc/ppcgen/ppc_form.py b/pypy/jit/backend/ppc/ppcgen/ppc_form.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/ppc_form.py @@ -0,0 +1,13 @@ +from pypy.jit.backend.ppc.ppcgen.form import Form +from pypy.jit.backend.ppc.ppcgen.ppc_field import ppc_fields + +class PPCForm(Form): + fieldmap = ppc_fields + + def __init__(self, *fnames): + super(PPCForm, self).__init__(*("opcode",) + fnames) + + def __call__(self, opcode, **specializations): + specializations['opcode'] = opcode + return super(PPCForm, self).__call__(**specializations) + diff --git a/pypy/jit/backend/ppc/ppcgen/pystructs.py b/pypy/jit/backend/ppc/ppcgen/pystructs.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/pystructs.py @@ -0,0 +1,22 @@ +class PyVarObject(object): + ob_size = 8 + +class PyObject(object): + ob_refcnt = 0 + ob_type = 4 + +class PyTupleObject(object): + ob_item = 12 + +class PyTypeObject(object): + tp_name = 12 + tp_basicsize = 16 + tp_itemsize = 20 + tp_dealloc = 24 + +class PyFloatObject(object): + ob_fval = 8 + +class PyIntObject(object): + ob_ival = 8 + diff --git a/pypy/jit/backend/ppc/ppcgen/rassemblermaker.py b/pypy/jit/backend/ppc/ppcgen/rassemblermaker.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/rassemblermaker.py @@ -0,0 +1,63 @@ +from pypy.tool.sourcetools import compile2 +from pypy.rlib.rarithmetic import r_uint +from pypy.jit.codegen.ppc.ppcgen.form import IDesc, IDupDesc + +## "opcode": ( 0, 5), +## "rA": (11, 15, 'unsigned', regname._R), +## "rB": (16, 20, 'unsigned', regname._R), +## "Rc": (31, 31), +## "rD": ( 6, 10, 'unsigned', regname._R), +## "OE": (21, 21), +## "XO2": (22, 30), + +## XO = Form("rD", "rA", "rB", "OE", "XO2", "Rc") + +## add = XO(31, XO2=266, OE=0, Rc=0) + +## def add(rD, rA, rB): +## v = 0 +## v |= (31&(2**(5-0+1)-1)) << (32-5-1) +## ... +## return v + +def make_func(name, desc): + sig = [] + fieldvalues = [] + for field in desc.fields: + if field in desc.specializations: + fieldvalues.append((field, desc.specializations[field])) + else: + sig.append(field.name) + fieldvalues.append((field, field.name)) + if isinstance(desc, IDupDesc): + for destfield, srcfield in desc.dupfields.iteritems(): + fieldvalues.append((destfield, srcfield.name)) + body = ['v = r_uint(0)'] + assert 'v' not in sig # that wouldn't be funny + #body.append('print %r'%name + ', ' + ', '.join(["'%s:', %s"%(s, s) for s in sig])) + for field, value in fieldvalues: + if field.name == 'spr': + body.append('spr = (%s&31) << 5 | (%s >> 5 & 31)'%(value, value)) + value = 'spr' + body.append('v |= (%3s & r_uint(%#05x)) << %d'%(value, + field.mask, + (32 - field.right - 1))) + body.append('self.emit(v)') + src = 'def %s(self, %s):\n %s'%(name, ', '.join(sig), '\n '.join(body)) + d = {'r_uint':r_uint} + #print src + exec compile2(src) in d + return d[name] + +def make_rassembler(cls): + bases = [make_rassembler(b) for b in cls.__bases__] + ns = {} + for k, v in cls.__dict__.iteritems(): + if isinstance(v, IDesc): + v = make_func(k, v) + ns[k] = v + rcls = type('R' + cls.__name__, tuple(bases), ns) + def emit(self, value): + self.insts.append(value) + rcls.emit = emit + return rcls diff --git a/pypy/jit/backend/ppc/ppcgen/regname.py b/pypy/jit/backend/ppc/ppcgen/regname.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/regname.py @@ -0,0 +1,18 @@ +class _R(int): + def __repr__(self): + return "r%s"%(super(_R, self).__repr__(),) + __str__ = __repr__ +class _F(int): + def __repr__(self): + return "fr%s"%(super(_F, self).__repr__(),) + __str__ = __repr__ + +r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, \ + r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, \ + r23, r24, r25, r26, r27, r28, r29, r30, r31 = map(_R, range(32)) + +fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, fr8, fr9, fr10, fr11, fr12, \ + fr13, fr14, fr15, fr16, fr17, fr18, fr19, fr20, fr21, fr22, \ + fr23, fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31 = map(_F, range(32)) + +crf0, crf1, crf2, crf3, crf4, crf5, crf6, crf7 = range(8) diff --git a/pypy/jit/backend/ppc/ppcgen/symbol_lookup.py b/pypy/jit/backend/ppc/ppcgen/symbol_lookup.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/symbol_lookup.py @@ -0,0 +1,15 @@ + +def lookup(sym): + global lookup + import py + + _ppcgen = py.magic.autopath().dirpath().join('_ppcgen.c')._getpymodule() + + try: + from _ppcgen import NSLookupAndBindSymbol + + def lookup(sym): + return NSLookupAndBindSymbol('_' + sym) + except ImportError: + from _ppcgen import dlsym as lookup + return lookup(sym) diff --git a/pypy/jit/backend/ppc/ppcgen/test/__init__.py b/pypy/jit/backend/ppc/ppcgen/test/__init__.py new file mode 100644 diff --git a/pypy/jit/backend/ppc/ppcgen/test/autopath.py b/pypy/jit/backend/ppc/ppcgen/test/autopath.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/test/autopath.py @@ -0,0 +1,114 @@ +""" +self cloning, automatic path configuration + +copy this into any subdirectory of pypy from which scripts need +to be run, typically all of the test subdirs. +The idea is that any such script simply issues + + import autopath + +and this will make sure that the parent directory containing "pypy" +is in sys.path. + +If you modify the master "autopath.py" version (in pypy/tool/autopath.py) +you can directly run it which will copy itself on all autopath.py files +it finds under the pypy root directory. + +This module always provides these attributes: + + pypydir pypy root directory path + this_dir directory where this autopath.py resides + +""" + + +def __dirinfo(part): + """ return (partdir, this_dir) and insert parent of partdir + into sys.path. If the parent directories don't have the part + an EnvironmentError is raised.""" + + import sys, os + try: + head = this_dir = os.path.realpath(os.path.dirname(__file__)) + except NameError: + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) + + while head: + partdir = head + head, tail = os.path.split(head) + if tail == part: + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + pypy_root = os.path.join(head, '') + try: + sys.path.remove(head) + except ValueError: + pass + sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + if '.' in name: + continue + fn = getattr(mod, '__file__', None) + if not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + + return partdir, this_dir + +def __clone(): + """ clone master version of autopath.py into all subdirs """ + from os.path import join, walk + if not this_dir.endswith(join('pypy','tool')): + raise EnvironmentError("can only clone master version " + "'%s'" % join(pypydir, 'tool',_myname)) + + + def sync_walker(arg, dirname, fnames): + if _myname in fnames: + fn = join(dirname, _myname) + f = open(fn, 'rwb+') + try: + if f.read() == arg: + print "checkok", fn + else: + print "syncing", fn + f = open(fn, 'w') + f.write(arg) + finally: + f.close() + s = open(join(pypydir, 'tool', _myname), 'rb').read() + walk(pypydir, sync_walker, s) + +_myname = 'autopath.py' + +# set guaranteed attributes + +pypydir, this_dir = __dirinfo('pypy') + +if __name__ == '__main__': + __clone() diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_field.py b/pypy/jit/backend/ppc/ppcgen/test/test_field.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/test/test_field.py @@ -0,0 +1,66 @@ +import autopath + +from pypy.jit.codegen.ppc.ppcgen.field import Field +from py.test import raises + +import random + +maxppcint = 0x7fffffff + +class TestFields(object): + def test_decode(self): + # this test is crappy + field = Field("test", 0, 31) + for i in range(100): + j = random.randrange(maxppcint) + assert field.decode(j) == j + field = Field("test", 0, 31-4) + for i in range(100): + j = random.randrange(maxppcint) + assert field.decode(j) == j>>4 + assert field.decode(j) == j>>4 + field = Field("test", 3, 31-4) + for i in range(100): + j = random.randrange(maxppcint>>3) + assert field.decode(j) == j>>4 + + + def test_decode_unsigned(self): + field = Field("test", 16, 31) + for i in range(1000): + hi = long(random.randrange(0x10000)) << 16 + lo = long(random.randrange(0x10000)) + assert field.decode(hi|lo) == lo + + + def test_decode_signed(self): + field = Field("test", 16, 31, 'signed') + for i in range(1000): + hi = long(random.randrange(0x10000)) << 16 + lo = long(random.randrange(0x10000)) + word = hi|lo + if lo & 0x8000: + lo |= ~0xFFFF + assert field.decode(word) == lo + + + def test_error_checking_unsigned(self): + for b in range(0, 17): + field = Field("test", b, 15+b) + assert field.decode(field.encode(0)) == 0 + assert field.decode(field.encode(32768)) == 32768 + assert field.decode(field.encode(65535)) == 65535 + raises(ValueError, field.encode, -32768) + raises(ValueError, field.encode, -1) + raises(ValueError, field.encode, 65536) + + + def test_error_checking_signed(self): + for b in range(0, 17): + field = Field("test", b, 15+b, 'signed') + assert field.decode(field.encode(0)) == 0 + assert field.decode(field.encode(-32768)) == -32768 + assert field.decode(field.encode(32767)) == 32767 + raises(ValueError, field.encode, 32768) + raises(ValueError, field.encode, -32769) + diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_form.py b/pypy/jit/backend/ppc/ppcgen/test/test_form.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/test/test_form.py @@ -0,0 +1,68 @@ +import autopath +from pypy.jit.codegen.ppc.ppcgen.ppc_assembler import b +import random +import sys + +from pypy.jit.codegen.ppc.ppcgen.form import Form, FormException +from pypy.jit.codegen.ppc.ppcgen.field import Field +from pypy.jit.codegen.ppc.ppcgen.assembler import Assembler + +# 0 31 +# +-------------------------------+ +# | h | l | +# +-------------------------------+ +# | hh | hl | lh | ll | +# +-------------------------------+ + +test_fieldmap = { + 'l' : Field('l', 16, 31), + 'h' : Field('h', 0, 15), + 'll': Field('ll', 24, 31), + 'lh': Field('lh', 16, 23), + 'hl': Field('hl', 8, 15), + 'hh': Field('hh', 0, 7), +} + +def p(w): + import struct + return struct.pack('>i', w) + + +class TestForm(Form): + fieldmap = test_fieldmap + +class TestForms(object): + def test_bitclash(self): + raises(FormException, TestForm, 'h', 'hh') + raises(FormException, TestForm, + Field('t1', 0, 0), Field('t2', 0, 0)) + + def test_basic(self): + class T(Assembler): + i = TestForm('h', 'l')() + j = i(h=1) + k = i(l=3) + raises(FormException, k, l=0) + a = T() + a.i(5, 6) + assert p(a.assemble0()[0]) == '\000\005\000\006' + a = T() + a.j(2) + assert p(a.assemble0()[0]) == '\000\001\000\002' + a = T() + a.k(4) + assert p(a.assemble0()[0]) == '\000\004\000\003' + + def test_defdesc(self): + class T(Assembler): + i = TestForm('hh', 'hl', 'lh', 'll')() + i.default(hl=0).default(hh=1) + a = T() + a.i(1, 2, 3, 4) + assert p(a.assemble0()[0]) == '\001\002\003\004' + a = T() + a.i(1, 3, 4) + assert p(a.assemble0()[0]) == '\001\000\003\004' + a = T() + a.i(3, 4) + assert p(a.assemble0()[0]) == '\001\000\003\004' diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_func_builder.py b/pypy/jit/backend/ppc/ppcgen/test/test_func_builder.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/test/test_func_builder.py @@ -0,0 +1,87 @@ +import py +import random, sys, os + +from pypy.jit.codegen.ppc.ppcgen.ppc_assembler import MyPPCAssembler +from pypy.jit.codegen.ppc.ppcgen.symbol_lookup import lookup +from pypy.jit.codegen.ppc.ppcgen.func_builder import make_func +from pypy.jit.codegen.ppc.ppcgen import form, func_builder +from pypy.jit.codegen.ppc.ppcgen.regname import * + +class TestFuncBuilderTest(object): + def setup_class(cls): + if (not hasattr(os, 'uname') or + os.uname()[-1] != 'Power Macintosh'): + py.test.skip("can't test all of ppcgen on non-PPC!") + + def test_simple(self): + a = MyPPCAssembler() + a.blr() + f = make_func(a, "O", "O") + assert f(1) == 1 + raises(TypeError, f) + raises(TypeError, f, 1, 2) + + def test_less_simple(self): + a = MyPPCAssembler() + s = lookup("PyNumber_Add") + a.load_word(r5, s) + a.mtctr(r5) + a.bctr() + f = make_func(a, "O", "OO") + raises(TypeError, f) + raises(TypeError, f, 1) + assert f(1, 2) == 3 + raises(TypeError, f, 1, 2, 3) + + def test_signature(self): + a = MyPPCAssembler() + a.add(r3, r3, r4) + a.blr() + f = make_func(a, "i", "ii") + raises(TypeError, f) + raises(TypeError, f, 1) + assert f(1, 2) == 3 + raises(TypeError, f, 1, 2, 3) + raises(TypeError, f, 1, "2") + + def test_signature2(self): + a = MyPPCAssembler() + a.add(r3, r3, r4) + a.add(r3, r3, r5) + a.add(r3, r3, r6) + a.add(r3, r3, r7) + s = lookup("PyInt_FromLong") + a.load_word(r0, s) + a.mtctr(r0) + a.bctr() + f = make_func(a, "O", "iiiii") + raises(TypeError, f) + raises(TypeError, f, 1) + assert f(1, 2, 3, 4, 5) == 1 + 2 + 3 + 4 + 5 + raises(TypeError, f, 1, 2, 3) + raises(TypeError, f, 1, "2", 3, 4, 5) + + def test_floats(self): + a = MyPPCAssembler() + a.fadd(fr1, fr1, fr2) + a.blr() + f = make_func(a, 'f', 'ff') + raises(TypeError, f) + raises(TypeError, f, 1.0) + assert f(1.0, 2.0) == 3.0 + raises(TypeError, f, 1.0, 2.0, 3.0) + raises(TypeError, f, 1.0, 2) + + def test_fast_entry(self): + a = MyPPCAssembler() + a.blr() + f = make_func(a, "O", "O") + assert f(1) == 1 + b = MyPPCAssembler() + from pypy.jit.codegen.ppc.ppcgen import util + # eurgh!: + b.load_word(r0, util.access_at(id(f.code), 8) + f.FAST_ENTRY_LABEL) + b.mtctr(r0) + b.bctr() + g = make_func(b, "O", "O") + assert g(1) == 1 diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py @@ -0,0 +1,212 @@ +import py +import random, sys, os + +from pypy.jit.backend.ppc.ppcgen.ppc_assembler import BasicPPCAssembler, MyPPCAssembler +from pypy.jit.backend.ppc.ppcgen.symbol_lookup import lookup +from pypy.jit.backend.ppc.ppcgen.regname import * +from pypy.jit.backend.ppc.ppcgen import form, pystructs +from pypy.jit.backend.detect_cpu import autodetect_main_model + + +class TestDisassemble(object): + def test_match(self): + A = BasicPPCAssembler + a = A() + a.add(1, 2, 3) + inst = a.insts[-1] + assert A.add.match(inst.assemble()) + +class TestAssemble(object): + def setup_class(cls): + if autodetect_main_model() not in ["ppc", "ppc64"]: + py.test.skip("can't test all of ppcgen on non-PPC!") + + def test_add_imm(self): + a = MyPPCAssembler() + + a.li(3, 6) + a.addi(3, 3, 1) + a.blr() + + f = a.assemble() + assert f() == 7 + +""" +class TestAssemble(object): + + def setup_class(cls): + #if (not hasattr(os, 'uname') or + if autodetect_main_model() not in ["ppc", "ppc64"]: + #os.uname()[-1] in ['Power Macintosh', 'PPC64']: + + py.test.skip("can't test all of ppcgen on non-PPC!") + + def test_tuplelength(self): + a = MyPPCAssembler() + + a.lwz(3, 4, pystructs.PyVarObject.ob_size) + a.load_word(5, lookup("PyInt_FromLong")) + a.mtctr(5) + a.bctr() + + f = a.assemble() + assert f() == 0 + assert f(1) == 1 + assert f('') == 1 + + + def test_tuplelength2(self): + a = MyPPCAssembler() + + a.mflr(0) + a.stw(0, 1, 8) + a.stwu(1, 1, -80) + a.mr(3, 4) + a.load_word(5, lookup("PyTuple_Size")) + a.mtctr(5) + a.bctrl() + a.load_word(5, lookup("PyInt_FromLong")) + a.mtctr(5) + a.bctrl() + a.lwz(0, 1, 88) + a.addi(1, 1, 80) + a.mtlr(0) + a.blr() + + f = a.assemble() + assert f() == 0 + assert f(1) == 1 + assert f('') == 1 + assert f('', 3) == 2 + + + def test_intcheck(self): + a = MyPPCAssembler() + + a.lwz(r5, r4, pystructs.PyVarObject.ob_size) + a.cmpwi(r5, 1) + a.bne("not_one") + a.lwz(r5, r4, pystructs.PyTupleObject.ob_item + 0*4) + a.lwz(r5, r5, 4) + a.load_word(r6, lookup("PyInt_Type")) + a.cmpw(r5, r6) + a.bne("not_int") + a.li(r3, 1) + a.b("exit") + a.label("not_int") + a.li(r3, 0) + a.b("exit") + a.label("not_one") + a.li(r3, 2) + a.label("exit") + a.load_word(r5, lookup("PyInt_FromLong")) + a.mtctr(r5) + a.bctr() + + f = a.assemble() + + assert f() == 2 + assert f("", "") == 2 + assert f("") == 0 + assert f(1) == 1 + + + def test_raise(self): + a = MyPPCAssembler() + + a.mflr(0) + a.stw(0, 1, 8) + a.stwu(1, 1, -80) + + err_set = lookup("PyErr_SetObject") + exc = lookup("PyExc_ValueError") + + a.load_word(5, err_set) + a.mtctr(5) + a.load_from(3, exc) + a.mr(4, 3) + a.bctrl() + + a.li(3, 0) + + a.lwz(0, 1, 88) + a.addi(1, 1, 80) + a.mtlr(0) + a.blr() + + raises(ValueError, a.assemble()) + + + def test_makestring(self): + a = MyPPCAssembler() + + a.li(r3, 0) + a.li(r4, 0) + a.load_word(r5, lookup("PyString_FromStringAndSize")) + a.mtctr(r5) + a.bctr() + + f = a.assemble() + assert f() == '' + + + def test_numberadd(self): + a = MyPPCAssembler() + + a.lwz(r5, r4, pystructs.PyVarObject.ob_size) + a.cmpwi(r5, 2) + a.bne("err_out") + + a.lwz(r3, r4, 12) + a.lwz(r4, r4, 16) + + a.load_word(r5, lookup("PyNumber_Add")) + a.mtctr(r5) + a.bctr() + + a.label("err_out") + + a.mflr(r0) + a.stw(r0, r1, 8) + a.stwu(r1, r1, -80) + + err_set = lookup("PyErr_SetObject") + exc = lookup("PyExc_TypeError") + + a.load_word(r5, err_set) + a.mtctr(r5) + a.load_from(r3, exc) + a.mr(r4, r3) + a.bctrl() + + a.li(r3, 0) + + a.lwz(r0, r1, 88) + a.addi(r1, r1, 80) + a.mtlr(r0) + a.blr() + + f = a.assemble() + + raises(TypeError, f) + raises(TypeError, f, '', 1) + raises(TypeError, f, 1) + raises(TypeError, f, 1, 2, 3) + assert f(1, 2) == 3 + assert f('a', 'b') == 'ab' + + + def test_assemblerChecks(self): + def testFailure(idesc, *args): + a = MyPPCAssembler() + raises(ValueError, idesc.__get__(a), *args) + def testSucceed(idesc, *args): + a = MyPPCAssembler() + # "assertNotRaises" :-) + idesc.__get__(a)(*args) + testFailure(MyPPCAssembler.add, 32, 31, 30) + testFailure(MyPPCAssembler.add, -1, 31, 30) + testSucceed(MyPPCAssembler.bne, -12) + testSucceed(MyPPCAssembler.lwz, 0, 0, 32767) + testSucceed(MyPPCAssembler.lwz, 0, 0, -32768) +""" diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_rassemblermaker.py b/pypy/jit/backend/ppc/ppcgen/test/test_rassemblermaker.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/test/test_rassemblermaker.py @@ -0,0 +1,39 @@ +from pypy.jit.codegen.ppc.ppcgen.rassemblermaker import make_rassembler +from pypy.jit.codegen.ppc.ppcgen.ppc_assembler import PPCAssembler + +RPPCAssembler = make_rassembler(PPCAssembler) + +_a = PPCAssembler() +_a.add(3, 3, 4) +add_r3_r3_r4 = _a.insts[0].assemble() + +def test_simple(): + ra = RPPCAssembler() + ra.add(3, 3, 4) + assert ra.insts == [add_r3_r3_r4] + +def test_rtyped(): + from pypy.rpython.test.test_llinterp import interpret + def f(): + ra = RPPCAssembler() + ra.add(3, 3, 4) + ra.lwz(1, 1, 1) # ensure that high bit doesn't produce long but r_uint + return ra.insts[0] + res = interpret(f, []) + assert res == add_r3_r3_r4 + +def test_mnemonic(): + mrs = [] + for A in PPCAssembler, RPPCAssembler: + a = A() + a.mr(3, 4) + mrs.append(a.insts[0]) + assert mrs[0].assemble() == mrs[1] + +def test_spr_coding(): + mrs = [] + for A in PPCAssembler, RPPCAssembler: + a = A() + a.mtctr(3) + mrs.append(a.insts[0]) + assert mrs[0].assemble() == mrs[1] diff --git a/pypy/jit/backend/ppc/ppcgen/util.py b/pypy/jit/backend/ppc/ppcgen/util.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/util.py @@ -0,0 +1,23 @@ +from pypy.jit.codegen.ppc.ppcgen.ppc_assembler import MyPPCAssembler +from pypy.jit.codegen.ppc.ppcgen.func_builder import make_func + +from regname import * + +def access_at(): + a = MyPPCAssembler() + + a.lwzx(r3, r3, r4) + a.blr() + + return make_func(a, "i", "ii") + +access_at = access_at() + +def itoO(): + a = MyPPCAssembler() + + a.blr() + + return make_func(a, "O", "i") + +itoO = itoO() diff --git a/pypy/jit/backend/ppc/regalloc.py b/pypy/jit/backend/ppc/regalloc.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/regalloc.py @@ -0,0 +1,213 @@ +from pypy.jit.codegen.ppc.instruction import \ + gprs, fprs, crfs, ctr, \ + NO_REGISTER, GP_REGISTER, FP_REGISTER, CR_FIELD, CT_REGISTER, \ + CMPInsn, Spill, Unspill, stack_slot, \ + rSCRATCH + +from pypy.jit.codegen.ppc.conftest import option + +DEBUG_PRINT = option.debug_print + +class RegisterAllocation: + def __init__(self, freeregs, initial_mapping, initial_spill_offset): + if DEBUG_PRINT: + print + print "RegisterAllocation __init__", initial_mapping.items() + + self.insns = [] # output list of instructions + + # registers with dead values + self.freeregs = {} + for regcls in freeregs: + self.freeregs[regcls] = freeregs[regcls][:] + + self.var2loc = {} # maps Vars to AllocationSlots + self.lru = [] # least-recently-used list of vars; first is oldest. + # contains all vars in registers, and no vars on stack + + self.spill_offset = initial_spill_offset # where to put next spilled + # value, relative to rFP, + # measured in bytes + self.free_stack_slots = [] # a free list for stack slots + + # go through the initial mapping and initialize the data structures + for var, loc in initial_mapping.iteritems(): + self.set(var, loc) + if loc.is_register: + if loc.alloc in self.freeregs[loc.regclass]: + self.freeregs[loc.regclass].remove(loc.alloc) + self.lru.append(var) + else: + assert loc.offset >= self.spill_offset + + self.labels_to_tell_spill_offset_to = [] + self.builders_to_tell_spill_offset_to = [] + + def set(self, var, loc): + assert var not in self.var2loc + self.var2loc[var] = loc + + def forget(self, var, loc): + assert self.var2loc[var] is loc + del self.var2loc[var] + + def loc_of(self, var): + return self.var2loc[var] + + def spill_slot(self): + """ Returns an unused stack location. """ + if self.free_stack_slots: + return self.free_stack_slots.pop() + else: + self.spill_offset -= 4 + return stack_slot(self.spill_offset) + + def spill(self, reg, argtospill): + if argtospill in self.lru: + self.lru.remove(argtospill) + self.forget(argtospill, reg) + spillslot = self.spill_slot() + if reg.regclass != GP_REGISTER: + self.insns.append(reg.move_to_gpr(0)) + reg = gprs[0] + self.insns.append(Spill(argtospill, reg, spillslot)) + self.set(argtospill, spillslot) + + def _allocate_reg(self, regclass, newarg): + + # check if there is a register available + freeregs = self.freeregs[regclass] + + if freeregs: + reg = freeregs.pop().make_loc() + self.set(newarg, reg) + if DEBUG_PRINT: + print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) + return reg + + # if not, find something to spill + for i in range(len(self.lru)): + argtospill = self.lru[i] + reg = self.loc_of(argtospill) + assert reg.is_register + if reg.regclass == regclass: + del self.lru[i] + break + else: + assert 0 + + # Move the value we are spilling onto the stack, both in the + # data structures and in the instructions: + + self.spill(reg, argtospill) + + if DEBUG_PRINT: + print "allocate_reg: Spilled %r from %r to %r." % (argtospill, reg, self.loc_of(argtospill)) + + # update data structures to put newarg into the register + reg = reg.alloc.make_loc() + self.set(newarg, reg) + if DEBUG_PRINT: + print "allocate_reg: Put %r in stolen reg %r." % (newarg, reg) + return reg + + def _promote(self, arg): + if arg in self.lru: + self.lru.remove(arg) + self.lru.append(arg) + + def allocate_for_insns(self, insns): + from pypy.jit.codegen.ppc.rgenop import Var + + insns2 = [] + + # make a pass through the instructions, loading constants into + # Vars where needed. + for insn in insns: + newargs = [] + for arg in insn.reg_args: + if not isinstance(arg, Var): + newarg = Var() + arg.load(insns2, newarg) + newargs.append(newarg) + else: + newargs.append(arg) + insn.reg_args[0:len(newargs)] = newargs + insns2.append(insn) + + # Walk through instructions in forward order + for insn in insns2: + + if DEBUG_PRINT: + print "Processing instruction" + print insn + print "LRU list was:", self.lru + print 'located at', [self.loc_of(a) for a in self.lru] + + # put things into the lru + for arg in insn.reg_args: + self._promote(arg) + if insn.result: + self._promote(insn.result) + if DEBUG_PRINT: + print "LRU list is now:", self.lru + print 'located at', [self.loc_of(a) for a in self.lru if a is not insn.result] + + # We need to allocate a register for each used + # argument that is not already in one + for i in range(len(insn.reg_args)): + arg = insn.reg_args[i] + argcls = insn.reg_arg_regclasses[i] + if DEBUG_PRINT: + print "Allocating register for", arg, "..." + argloc = self.loc_of(arg) + if DEBUG_PRINT: + print "currently in", argloc + + if not argloc.is_register: + # It has no register now because it has been spilled + self.forget(arg, argloc) + newargloc = self._allocate_reg(argcls, arg) + if DEBUG_PRINT: + print "unspilling to", newargloc + self.insns.append(Unspill(arg, newargloc, argloc)) + self.free_stack_slots.append(argloc) + elif argloc.regclass != argcls: + # it's in the wrong kind of register + # (this code is excessively confusing) + self.forget(arg, argloc) + self.freeregs[argloc.regclass].append(argloc.alloc) + if argloc.regclass != GP_REGISTER: + if argcls == GP_REGISTER: + gpr = self._allocate_reg(GP_REGISTER, arg).number + else: + gpr = rSCRATCH + self.insns.append( + argloc.move_to_gpr(gpr)) + else: + gpr = argloc.number + if argcls != GP_REGISTER: + newargloc = self._allocate_reg(argcls, arg) + self.insns.append( + newargloc.move_from_gpr(gpr)) + else: + if DEBUG_PRINT: + print "it was in ", argloc + pass + + # Need to allocate a register for the destination + assert not insn.result or insn.result not in self.var2loc + if insn.result_regclass != NO_REGISTER: + if DEBUG_PRINT: + print "Allocating register for result %r..." % (insn.result,) + resultreg = self._allocate_reg(insn.result_regclass, insn.result) + insn.allocate(self) + if DEBUG_PRINT: + print insn + print + self.insns.append(insn) + #print 'allocation done' + #for i in self.insns: + # print i + #print self.var2loc + return self.insns diff --git a/pypy/jit/backend/ppc/rgenop.py b/pypy/jit/backend/ppc/rgenop.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/rgenop.py @@ -0,0 +1,1427 @@ +import py +from pypy.jit.codegen.model import AbstractRGenOp, GenLabel, GenBuilder +from pypy.jit.codegen.model import GenVar, GenConst, CodeGenSwitch +from pypy.jit.codegen.model import ReplayBuilder, dummy_var +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lloperation +from pypy.rpython.extfunc import register_external +from pypy.rlib.objectmodel import specialize, we_are_translated +from pypy.jit.codegen.conftest import option +from ctypes import POINTER, cast, c_void_p, c_int, CFUNCTYPE + +from pypy.jit.codegen.ppc import codebuf +from pypy.jit.codegen.ppc.instruction import rSP, rFP, rSCRATCH, gprs +from pypy.jit.codegen.ppc import instruction as insn +from pypy.jit.codegen.ppc.regalloc import RegisterAllocation +from pypy.jit.codegen.emit_moves import emit_moves, emit_moves_safe + +from pypy.jit.codegen.ppc.ppcgen.rassemblermaker import make_rassembler +from pypy.jit.codegen.ppc.ppcgen.ppc_assembler import MyPPCAssembler + +from pypy.jit.codegen.i386.rgenop import gc_malloc_fnaddr +from pypy.rpython.annlowlevel import llhelper + +class RPPCAssembler(make_rassembler(MyPPCAssembler)): + def emit(self, value): + self.mc.write(value) + +_PPC = RPPCAssembler + + +_flush_icache = None +def flush_icache(base, size): + global _flush_icache + if _flush_icache == None: + cpath = py.magic.autopath().dirpath().join('_flush_icache.c') + _flush_icache = cpath._getpymodule()._flush_icache + _flush_icache(base, size) +register_external(flush_icache, [int, int], None, "LL_flush_icache") + + +NSAVEDREGISTERS = 19 + +DEBUG_TRAP = option.trap +DEBUG_PRINT = option.debug_print + +_var_index = [0] +class Var(GenVar): + conditional = False + def __init__(self): + self.__magic_index = _var_index[0] + _var_index[0] += 1 + def __repr__(self): + return "v%d" % self.__magic_index + def fits_in_uimm(self): + return False + def fits_in_simm(self): + return False + +class ConditionVar(Var): + """ Used for vars that originated as the result of a conditional + operation, like a == b """ + conditional = True + +class IntConst(GenConst): + + def __init__(self, value): + self.value = value + + def __repr__(self): + return 'IntConst(%d)'%self.value + + @specialize.arg(1) + def revealconst(self, T): + if isinstance(T, lltype.Ptr): + return lltype.cast_int_to_ptr(T, self.value) + elif T is llmemory.Address: + return llmemory.cast_int_to_adr(self.value) + else: + return lltype.cast_primitive(T, self.value) + + def load(self, insns, var): + insns.append( + insn.Insn_GPR__IMM(_PPC.load_word, + var, [self])) + + def load_now(self, asm, loc): + if loc.is_register: + assert isinstance(loc, insn.GPR) + asm.load_word(loc.number, self.value) + else: + #print 'load_now to', loc.offset + asm.load_word(rSCRATCH, self.value) + asm.stw(rSCRATCH, rFP, loc.offset) + + def fits_in_simm(self): + return abs(self.value) < 2**15 + + def fits_in_uimm(self): + return 0 <= self.value < 2**16 + +class AddrConst(GenConst): + + def __init__(self, addr): + self.addr = addr + + @specialize.arg(1) + def revealconst(self, T): + if T is llmemory.Address: + return self.addr + elif isinstance(T, lltype.Ptr): + return llmemory.cast_adr_to_ptr(self.addr, T) + elif T is lltype.Signed: + return llmemory.cast_adr_to_int(self.addr) + else: + assert 0, "XXX not implemented" + + def fits_in_simm(self): + return False + + def fits_in_uimm(self): + return False + + def load(self, insns, var): + i = IntConst(llmemory.cast_adr_to_int(self.addr)) + insns.append( + insn.Insn_GPR__IMM(RPPCAssembler.load_word, + var, [i])) + + def load_now(self, asm, loc): + value = llmemory.cast_adr_to_int(self.addr) + if loc.is_register: + assert isinstance(loc, insn.GPR) + asm.load_word(loc.number, value) + else: + #print 'load_now to', loc.offset + asm.load_word(rSCRATCH, value) + asm.stw(rSCRATCH, rFP, loc.offset) + + +class JumpPatchupGenerator(object): + + def __init__(self, insns, allocator): + self.insns = insns + self.allocator = allocator + + def emit_move(self, tarloc, srcloc): + srcvar = None + if DEBUG_PRINT: + for v, loc in self.allocator.var2loc.iteritems(): + if loc is srcloc: + srcvar = v + break + emit = self.insns.append + if tarloc == srcloc: + return + if tarloc.is_register and srcloc.is_register: + assert isinstance(tarloc, insn.GPR) + if isinstance(srcloc, insn.GPR): + emit(insn.Move(tarloc, srcloc)) + else: + assert isinstance(srcloc, insn.CRF) + emit(srcloc.move_to_gpr(tarloc.number)) + elif tarloc.is_register and not srcloc.is_register: + emit(insn.Unspill(srcvar, tarloc, srcloc)) + elif not tarloc.is_register and srcloc.is_register: + emit(insn.Spill(srcvar, srcloc, tarloc)) + elif not tarloc.is_register and not srcloc.is_register: + emit(insn.Unspill(srcvar, insn.gprs[0], srcloc)) + emit(insn.Spill(srcvar, insn.gprs[0], tarloc)) + + def create_fresh_location(self): + return self.allocator.spill_slot() + +class StackInfo(Var): + # not really a Var at all, but needs to be mixable with Consts.... + # offset will be assigned later + offset = 0 + pass + +def prepare_for_jump(insns, sourcevars, src2loc, target, allocator): + + tar2src = {} # tar var -> src var + tar2loc = {} + + # construct mapping of targets to sources; note that "target vars" + # and "target locs" are the same thing right now + targetlocs = target.arg_locations + tarvars = [] + +## if DEBUG_PRINT: +## print targetlocs +## print allocator.var2loc + + for i in range(len(targetlocs)): + tloc = targetlocs[i] + src = sourcevars[i] + if isinstance(src, Var): + tar2loc[tloc] = tloc + tar2src[tloc] = src + tarvars.append(tloc) + if not tloc.is_register: + if tloc in allocator.free_stack_slots: + allocator.free_stack_slots.remove(tloc) + + gen = JumpPatchupGenerator(insns, allocator) + emit_moves(gen, tarvars, tar2src, tar2loc, src2loc) + + for i in range(len(targetlocs)): + tloc = targetlocs[i] + src = sourcevars[i] + if not isinstance(src, Var): + insns.append(insn.Load(tloc, src)) + +class Label(GenLabel): + + def __init__(self, args_gv): + self.args_gv = args_gv + #self.startaddr = startaddr + #self.arg_locations = arg_locations + self.min_stack_offset = 1 + +# our approach to stack layout: + +# on function entry, the stack looks like this: + +# .... +# | parameter area | +# | linkage area | <- rSP points to the last word of the linkage area +# +----------------+ + +# we set things up like so: + +# | parameter area | +# | linkage area | <- rFP points to where the rSP was +# | saved registers | +# | local variables | +# +-----------------+ <- rSP points here, and moves around between basic blocks + +# points of note (as of 2006-11-09 anyway :-): +# 1. we currently never spill to the parameter area (should fix?) +# 2. we always save all callee-save registers +# 3. as each basic block can move the SP around as it sees fit, we index +# into the local variables area from the FP (frame pointer; it is not +# usual on the PPC to have a frame pointer, but there's no reason we +# can't have one :-) + + +class Builder(GenBuilder): + + def __init__(self, rgenop): + self.rgenop = rgenop + self.asm = RPPCAssembler() + self.asm.mc = None + self.insns = [] + self.initial_spill_offset = 0 + self.initial_var2loc = None + self.max_param_space = -1 + self.final_jump_addr = 0 + + self.start = 0 + self.closed = True + self.patch_start_here = 0 + + # ---------------------------------------------------------------- + # the public Builder interface: + + def end(self): + pass + + @specialize.arg(1) + def genop1(self, opname, gv_arg): + #print opname, 'on', id(self) + genmethod = getattr(self, 'op_' + opname) + r = genmethod(gv_arg) + #print '->', id(r) + return r + + @specialize.arg(1) + def genop2(self, opname, gv_arg1, gv_arg2): + #print opname, 'on', id(self) + genmethod = getattr(self, 'op_' + opname) + r = genmethod(gv_arg1, gv_arg2) + #print '->', id(r) + return r + + @specialize.arg(1) + def genraisingop2(self, opname, gv_arg1, gv_arg2): + genmethod = getattr(self, 'raisingop_' + opname) + r = genmethod(gv_arg1, gv_arg2) + return r + + @specialize.arg(1) + def genraisingop1(self, opname, gv_arg): + genmethod = getattr(self, 'raisingop_' + opname) + r = genmethod(gv_arg) + return r + + def genop_call(self, sigtoken, gv_fnptr, args_gv): + self.insns.append(insn.SpillCalleeSaves()) + for i in range(len(args_gv)): + self.insns.append(insn.LoadArg(i, args_gv[i])) + gv_result = Var() + self.max_param_space = max(self.max_param_space, len(args_gv)*4) + self.insns.append(insn.CALL(gv_result, gv_fnptr)) + return gv_result + + def genop_getfield(self, fieldtoken, gv_ptr): + fieldoffset, fieldsize = fieldtoken + opcode = {1:_PPC.lbz, 2:_PPC.lhz, 4:_PPC.lwz}[fieldsize] + return self._arg_simm_op(gv_ptr, IntConst(fieldoffset), opcode) + + def genop_setfield(self, fieldtoken, gv_ptr, gv_value): + gv_result = Var() + fieldoffset, fieldsize = fieldtoken + opcode = {1:_PPC.stb, 2:_PPC.sth, 4:_PPC.stw}[fieldsize] + self.insns.append( + insn.Insn_None__GPR_GPR_IMM(opcode, + [gv_value, gv_ptr, IntConst(fieldoffset)])) + return gv_result + + def genop_getsubstruct(self, fieldtoken, gv_ptr): + return self._arg_simm_op(gv_ptr, IntConst(fieldtoken[0]), _PPC.addi) + + def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index): + _, _, itemsize = arraytoken + opcode = {1:_PPC.lbzx, + 2:_PPC.lhzx, + 4:_PPC.lwzx}[itemsize] + opcodei = {1:_PPC.lbz, + 2:_PPC.lhz, + 4:_PPC.lwz}[itemsize] + gv_itemoffset = self.itemoffset(arraytoken, gv_index) + return self._arg_arg_op_with_simm(gv_ptr, gv_itemoffset, opcode, opcodei) + + def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index): + _, _, itemsize = arraytoken + assert itemsize == 4 + gv_itemoffset = self.itemoffset(arraytoken, gv_index) + return self._arg_arg_op_with_simm(gv_ptr, gv_itemoffset, _PPC.add, _PPC.addi, + commutative=True) + + def genop_getarraysize(self, arraytoken, gv_ptr): + lengthoffset, _, _ = arraytoken + return self._arg_simm_op(gv_ptr, IntConst(lengthoffset), _PPC.lwz) + + def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value): + _, _, itemsize = arraytoken + gv_itemoffset = self.itemoffset(arraytoken, gv_index) + gv_result = Var() + if gv_itemoffset.fits_in_simm(): + opcode = {1:_PPC.stb, + 2:_PPC.sth, + 4:_PPC.stw}[itemsize] + self.insns.append( + insn.Insn_None__GPR_GPR_IMM(opcode, + [gv_value, gv_ptr, gv_itemoffset])) + else: + opcode = {1:_PPC.stbx, + 2:_PPC.sthx, + 4:_PPC.stwx}[itemsize] + self.insns.append( + insn.Insn_None__GPR_GPR_GPR(opcode, + [gv_value, gv_ptr, gv_itemoffset])) + + def genop_malloc_fixedsize(self, alloctoken): + return self.genop_call(1, # COUGH + IntConst(gc_malloc_fnaddr()), + [IntConst(alloctoken)]) + + def genop_malloc_varsize(self, varsizealloctoken, gv_size): + gv_itemoffset = self.itemoffset(varsizealloctoken, gv_size) + gv_result = self.genop_call(1, # COUGH + IntConst(gc_malloc_fnaddr()), + [gv_itemoffset]) + lengthoffset, _, _ = varsizealloctoken + self.insns.append( + insn.Insn_None__GPR_GPR_IMM(_PPC.stw, + [gv_size, gv_result, IntConst(lengthoffset)])) + return gv_result + + def genop_same_as(self, gv_arg): + if not isinstance(gv_arg, Var): + gv_result = Var() + gv_arg.load(self.insns, gv_result) + return gv_result + else: + return gv_arg + + def genop_cast_int_to_ptr(self, kind, gv_int): + return gv_int + +## def genop_debug_pdb(self): # may take an args_gv later + + def genop_get_frame_base(self): + gv_result = Var() + self.insns.append( + insn.LoadFramePointer(gv_result)) + return gv_result + + def get_frame_info(self, vars_gv): + result = [] + for v in vars_gv: + if isinstance(v, Var): + place = StackInfo() + self.insns.append(insn.CopyIntoStack(place, v)) + result.append(place) + else: + result.append(None) + return result + + def alloc_frame_place(self, kind, gv_initial_value=None): + place = StackInfo() + if gv_initial_value is None: + gv_initial_value = AddrConst(llmemory.NULL) + self.insns.append(insn.CopyIntoStack(place, gv_initial_value)) + return place + + def genop_absorb_place(self, place): + var = Var() + self.insns.append(insn.CopyOffStack(var, place)) + return var + + def enter_next_block(self, args_gv): + if DEBUG_PRINT: + print 'enter_next_block1', args_gv + seen = {} + for i in range(len(args_gv)): + gv = args_gv[i] + if isinstance(gv, Var): + if gv in seen: + new_gv = self._arg_op(gv, _PPC.mr) + args_gv[i] = new_gv + seen[gv] = True + else: + new_gv = Var() + gv.load(self.insns, new_gv) + args_gv[i] = new_gv + + if DEBUG_PRINT: + print 'enter_next_block2', args_gv + + r = Label(args_gv) + self.insns.append(insn.Label(r)) + return r + + def jump_if_false(self, gv_condition, args_gv): + return self._jump(gv_condition, False, args_gv) + + def jump_if_true(self, gv_condition, args_gv): + return self._jump(gv_condition, True, args_gv) + + def finish_and_return(self, sigtoken, gv_returnvar): + self.insns.append(insn.Return(gv_returnvar)) + self.allocate_and_emit([]) + + # standard epilogue: + + # restore old SP + self.asm.lwz(rSP, rSP, 0) + # restore all callee-save GPRs + self.asm.lmw(gprs[32-NSAVEDREGISTERS].number, rSP, -4*(NSAVEDREGISTERS+1)) + # restore Condition Register + self.asm.lwz(rSCRATCH, rSP, 4) + self.asm.mtcr(rSCRATCH) + # restore Link Register and jump to it + self.asm.lwz(rSCRATCH, rSP, 8) + self.asm.mtlr(rSCRATCH) + self.asm.blr() + + self._close() + + def finish_and_goto(self, outputargs_gv, target): + if target.min_stack_offset == 1: + self.pause_writing(outputargs_gv) + self.start_writing() + allocator = self.allocate(outputargs_gv) + if DEBUG_PRINT: + before_moves = len(self.insns) + print outputargs_gv + print target.args_gv + allocator.spill_offset = min(allocator.spill_offset, target.min_stack_offset) + prepare_for_jump( + self.insns, outputargs_gv, allocator.var2loc, target, allocator) + if DEBUG_PRINT: + print 'moves:' + for i in self.insns[before_moves:]: + print ' ', i + self.emit(allocator) + here_size = self._stack_size(allocator.spill_offset) + there_size = self._stack_size(target.min_stack_offset) + if here_size != there_size: + self.emit_stack_adjustment(there_size) + if self.rgenop.DEBUG_SCRIBBLE: + if here_size > there_size: + offsets = range(there_size, here_size, 4) + else: + offsets = range(here_size, there_size, 4) + for offset in offsets: + self.asm.load_word(rSCRATCH, 0x23456789) + self.asm.stw(rSCRATCH, rSP, -offset) + self.asm.load_word(rSCRATCH, target.startaddr) + self.asm.mtctr(rSCRATCH) + self.asm.bctr() + self._close() + + def flexswitch(self, gv_exitswitch, args_gv): + # make sure the exitswitch ends the block in a register: + crresult = Var() + self.insns.append(insn.FakeUse(crresult, gv_exitswitch)) + allocator = self.allocate_and_emit(args_gv) + switch_mc = self.asm.mc.reserve(7 * 5 + 4) + self._close() + result = FlexSwitch(self.rgenop, switch_mc, + allocator.loc_of(gv_exitswitch), + allocator.loc_of(crresult), + allocator.var2loc, + allocator.spill_offset) + return result, result.add_default() + + def start_writing(self): + if not self.closed: + return self + assert self.asm.mc is None + if self.final_jump_addr != 0: + mc = self.rgenop.open_mc() + target = mc.tell() + if target == self.final_jump_addr + 16: + mc.setpos(mc.getpos()-4) + else: + self.asm.mc = self.rgenop.ExistingCodeBlock( + self.final_jump_addr, self.final_jump_addr+8) + self.asm.load_word(rSCRATCH, target) + flush_icache(self.final_jump_addr, 8) + self._code_start = mc.tell() + self.asm.mc = mc + self.final_jump_addr = 0 + self.closed = False + return self + else: + self._open() + self.maybe_patch_start_here() + return self + + def maybe_patch_start_here(self): + if self.patch_start_here: + mc = self.asm.mc + self.asm.mc = self.rgenop.ExistingCodeBlock( + self.patch_start_here, self.patch_start_here+8) + self.asm.load_word(rSCRATCH, mc.tell()) + flush_icache(self.patch_start_here, 8) + self.asm.mc = mc + self.patch_start_here = 0 + + def pause_writing(self, args_gv): + allocator = self.allocate_and_emit(args_gv) + self.initial_var2loc = allocator.var2loc + self.initial_spill_offset = allocator.spill_offset + self.insns = [] + self.max_param_space = -1 + self.final_jump_addr = self.asm.mc.tell() + self.closed = True + self.asm.nop() + self.asm.nop() + self.asm.mtctr(rSCRATCH) + self.asm.bctr() + self._close() + return self + + # ---------------------------------------------------------------- + # ppc-specific interface: + + def itemoffset(self, arraytoken, gv_index): + # if gv_index is constant, this can return a constant... + lengthoffset, startoffset, itemsize = arraytoken + + gv_offset = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.mulli, + gv_offset, [gv_index, IntConst(itemsize)])) + gv_itemoffset = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, + gv_itemoffset, [gv_offset, IntConst(startoffset)])) + return gv_itemoffset + + def _write_prologue(self, sigtoken): + numargs = sigtoken # for now + if DEBUG_TRAP: + self.asm.trap() + inputargs = [Var() for i in range(numargs)] + assert self.initial_var2loc is None + self.initial_var2loc = {} + for arg in inputargs[:8]: + self.initial_var2loc[arg] = gprs[3+len(self.initial_var2loc)] + if len(inputargs) > 8: + for i in range(8, len(inputargs)): + arg = inputargs[i] + self.initial_var2loc[arg] = insn.stack_slot(24 + 4 * len(self.initial_var2loc)) + self.initial_spill_offset = self._var_offset(0) + + # Standard prologue: + + # Minimum stack space = 24+params+lv+4*GPRSAVE+8*FPRSAVE + # params = stack space for parameters for functions we call + # lv = stack space for local variables + # GPRSAVE = the number of callee-save GPRs we save, currently + # NSAVEDREGISTERS which is 19, i.e. all of them + # FPRSAVE = the number of callee-save FPRs we save, currently 0 + # Initially, we set params == lv == 0 and allow each basic block to + # ensure it has enough space to continue. + + minspace = self._stack_size(self._var_offset(0)) + # save Link Register + self.asm.mflr(rSCRATCH) + self.asm.stw(rSCRATCH, rSP, 8) + # save Condition Register + self.asm.mfcr(rSCRATCH) + self.asm.stw(rSCRATCH, rSP, 4) + # save the callee-save GPRs + self.asm.stmw(gprs[32-NSAVEDREGISTERS].number, rSP, -4*(NSAVEDREGISTERS + 1)) + # set up frame pointer + self.asm.mr(rFP, rSP) + # save stack pointer into linkage area and set stack pointer for us. + self.asm.stwu(rSP, rSP, -minspace) + + if self.rgenop.DEBUG_SCRIBBLE: + # write junk into all non-argument, non rFP or rSP registers + self.asm.load_word(rSCRATCH, 0x12345678) + for i in range(min(11, 3+len(self.initial_var2loc)), 32): + self.asm.load_word(i, 0x12345678) + # scribble the part of the stack between + # self._var_offset(0) and minspace + for offset in range(self._var_offset(0), -minspace, -4): + self.asm.stw(rSCRATCH, rFP, offset) + # and then a bit more + for offset in range(-minspace-4, -minspace-200, -4): + self.asm.stw(rSCRATCH, rFP, offset) + + return inputargs + + def _var_offset(self, v): + """v represents an offset into the local variable area in bytes; + this returns the offset relative to rFP""" + return -(4*NSAVEDREGISTERS+4+v) + + def _stack_size(self, lv): + """ Returns the required stack size to store all data, assuming + that there are 'param' bytes of parameters for callee functions and + 'lv' is the largest (wrt to abs() :) rFP-relative byte offset of + any variable on the stack. Plus 4 because the rFP actually points + into our caller's linkage area.""" + assert lv <= 0 + if self.max_param_space >= 0: + param = max(self.max_param_space, 32) + 24 + else: + param = 0 + return ((4 + param - lv + 15) & ~15) + + def _open(self): + self.asm.mc = self.rgenop.open_mc() + self._code_start = self.asm.mc.tell() + self.closed = False + + def _close(self): + _code_stop = self.asm.mc.tell() + code_size = _code_stop - self._code_start + flush_icache(self._code_start, code_size) + self.rgenop.close_mc(self.asm.mc) + self.asm.mc = None + + def allocate_and_emit(self, live_vars_gv): + allocator = self.allocate(live_vars_gv) + return self.emit(allocator) + + def allocate(self, live_vars_gv): + assert self.initial_var2loc is not None + allocator = RegisterAllocation( + self.rgenop.freeregs, + self.initial_var2loc, + self.initial_spill_offset) + self.insns = allocator.allocate_for_insns(self.insns) + return allocator + + def emit(self, allocator): + in_size = self._stack_size(self.initial_spill_offset) + our_size = self._stack_size(allocator.spill_offset) + if in_size != our_size: + assert our_size > in_size + self.emit_stack_adjustment(our_size) + if self.rgenop.DEBUG_SCRIBBLE: + for offset in range(in_size, our_size, 4): + self.asm.load_word(rSCRATCH, 0x23456789) + self.asm.stw(rSCRATCH, rSP, -offset) + if self.rgenop.DEBUG_SCRIBBLE: + locs = {} + for _, loc in self.initial_var2loc.iteritems(): + locs[loc] = True + regs = insn.gprs[3:] + for reg in regs: + if reg not in locs: + self.asm.load_word(reg.number, 0x3456789) + self.asm.load_word(0, 0x3456789) + for offset in range(self._var_offset(0), + self.initial_spill_offset, + -4): + if insn.stack_slot(offset) not in locs: + self.asm.stw(0, rFP, offset) + for insn_ in self.insns: + insn_.emit(self.asm) + for label in allocator.labels_to_tell_spill_offset_to: + label.min_stack_offset = allocator.spill_offset + for builder in allocator.builders_to_tell_spill_offset_to: + builder.initial_spill_offset = allocator.spill_offset + return allocator + + def emit_stack_adjustment(self, newsize): + # the ABI requires that at all times that r1 is valid, in the + # sense that it must point to the bottom of the stack and that + # executing SP <- *(SP) repeatedly walks the stack. + # this code satisfies this, although there is a 1-instruction + # window where such walking would find a strange intermediate + # "frame" + self.asm.addi(rSCRATCH, rFP, -newsize) + self.asm.sub(rSCRATCH, rSCRATCH, rSP) + + # this is a pure debugging check that we avoid the situation + # where *(r1) == r1 which would violates the ABI rules listed + # above. after a while it can be removed or maybe made + # conditional on some --option passed to py.test + self.asm.tweqi(rSCRATCH, 0) + + self.asm.stwux(rSP, rSP, rSCRATCH) + self.asm.stw(rFP, rSP, 0) + + def _arg_op(self, gv_arg, opcode): + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR(opcode, gv_result, gv_arg)) + return gv_result + + def _arg_arg_op(self, gv_x, gv_y, opcode): + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR_GPR(opcode, gv_result, [gv_x, gv_y])) + return gv_result + + def _arg_simm_op(self, gv_x, gv_imm, opcode): + assert gv_imm.fits_in_simm() + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(opcode, gv_result, [gv_x, gv_imm])) + return gv_result + + def _arg_uimm_op(self, gv_x, gv_imm, opcode): + assert gv_imm.fits_in_uimm() + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(opcode, gv_result, [gv_x, gv_imm])) + return gv_result + + def _arg_arg_op_with_simm(self, gv_x, gv_y, opcode, opcodei, + commutative=False): + if gv_y.fits_in_simm(): + return self._arg_simm_op(gv_x, gv_y, opcodei) + elif gv_x.fits_in_simm() and commutative: + return self._arg_simm_op(gv_y, gv_x, opcodei) + else: + return self._arg_arg_op(gv_x, gv_y, opcode) + + def _arg_arg_op_with_uimm(self, gv_x, gv_y, opcode, opcodei, + commutative=False): + if gv_y.fits_in_uimm(): + return self._arg_uimm_op(gv_x, gv_y, opcodei) + elif gv_x.fits_in_uimm() and commutative: + return self._arg_uimm_op(gv_y, gv_x, opcodei) + else: + return self._arg_arg_op(gv_x, gv_y, opcode) + + def _identity(self, gv_arg): + return gv_arg + + cmp2info = { + # bit-in-crf negated + 'gt': ( 1, 0 ), + 'lt': ( 0, 0 ), + 'le': ( 1, 1 ), + 'ge': ( 0, 1 ), + 'eq': ( 2, 0 ), + 'ne': ( 2, 1 ), + } + + cmp2info_flipped = { + # bit-in-crf negated + 'gt': ( 0, 0 ), + 'lt': ( 1, 0 ), + 'le': ( 0, 1 ), + 'ge': ( 1, 1 ), + 'eq': ( 2, 0 ), + 'ne': ( 2, 1 ), + } + + def _compare(self, op, gv_x, gv_y): + #print "op", op + gv_result = ConditionVar() + if gv_y.fits_in_simm(): + self.insns.append( + insn.CMPWI(self.cmp2info[op], gv_result, [gv_x, gv_y])) + elif gv_x.fits_in_simm(): + self.insns.append( + insn.CMPWI(self.cmp2info_flipped[op], gv_result, [gv_y, gv_x])) + else: + self.insns.append( + insn.CMPW(self.cmp2info[op], gv_result, [gv_x, gv_y])) + return gv_result + + def _compare_u(self, op, gv_x, gv_y): + gv_result = ConditionVar() + if gv_y.fits_in_uimm(): + self.insns.append( + insn.CMPWLI(self.cmp2info[op], gv_result, [gv_x, gv_y])) + elif gv_x.fits_in_uimm(): + self.insns.append( + insn.CMPWLI(self.cmp2info_flipped[op], gv_result, [gv_y, gv_x])) + else: + self.insns.append( + insn.CMPWL(self.cmp2info[op], gv_result, [gv_x, gv_y])) + return gv_result + + def _jump(self, gv_condition, if_true, args_gv): + targetbuilder = self.rgenop.newbuilder() + + self.insns.append( + insn.Jump(gv_condition, targetbuilder, if_true, args_gv)) + + return targetbuilder + + def _ov(self): + # mfxer rFOO + # extrwi rBAR, rFOO, 1, 1 + gv_xer = Var() + self.insns.append( + insn.Insn_GPR(_PPC.mfxer, gv_xer)) + gv_ov = Var() + self.insns.append(insn.Extrwi(gv_ov, gv_xer, 1, 1)) + return gv_ov + + def op_bool_not(self, gv_arg): + return self._arg_uimm_op(gv_arg, self.rgenop.genconst(1), RPPCAssembler.xori) + + def op_int_is_true(self, gv_arg): + return self._compare('ne', gv_arg, self.rgenop.genconst(0)) + + def op_int_neg(self, gv_arg): + return self._arg_op(gv_arg, _PPC.neg) + + def raisingop_int_neg_ovf(self, gv_arg): + gv_result = self._arg_op(gv_arg, _PPC.nego) + gv_ov = self._ov() + return (gv_result, gv_ov) + + def op_int_abs(self, gv_arg): + gv_sign = self._arg_uimm_op(gv_arg, self.rgenop.genconst(31), _PPC.srawi) + gv_maybe_inverted = self._arg_arg_op(gv_arg, gv_sign, _PPC.xor) + return self._arg_arg_op(gv_sign, gv_maybe_inverted, _PPC.subf) + + def raisingop_int_abs_ovf(self, gv_arg): + gv_sign = self._arg_uimm_op(gv_arg, self.rgenop.genconst(31), _PPC.srawi) + gv_maybe_inverted = self._arg_arg_op(gv_arg, gv_sign, _PPC.xor) + gv_result = self._arg_arg_op(gv_sign, gv_maybe_inverted, _PPC.subfo) + return (gv_result, self._ov()) + + def op_int_invert(self, gv_arg): + return self._arg_op(gv_arg, _PPC.not_) + + def op_int_add(self, gv_x, gv_y): + return self._arg_arg_op_with_simm(gv_x, gv_y, _PPC.add, _PPC.addi, + commutative=True) + + def raisingop_int_add_ovf(self, gv_x, gv_y): + gv_result = self._arg_arg_op(gv_x, gv_y, _PPC.addo) + gv_ov = self._ov() + return (gv_result, gv_ov) + + def op_int_sub(self, gv_x, gv_y): + return self._arg_arg_op_with_simm(gv_x, gv_y, _PPC.sub, _PPC.subi) + + def raisingop_int_sub_ovf(self, gv_x, gv_y): + gv_result = self._arg_arg_op(gv_x, gv_y, _PPC.subo) + gv_ov = self._ov() + return (gv_result, gv_ov) + + def op_int_mul(self, gv_x, gv_y): + return self._arg_arg_op_with_simm(gv_x, gv_y, _PPC.mullw, _PPC.mulli, + commutative=True) + + def raisingop_int_mul_ovf(self, gv_x, gv_y): + gv_result = self._arg_arg_op(gv_x, gv_y, _PPC.mullwo) + gv_ov = self._ov() + return (gv_result, gv_ov) + + def op_int_floordiv(self, gv_x, gv_y): + return self._arg_arg_op(gv_x, gv_y, _PPC.divw) + + ## def op_int_floordiv_zer(self, gv_x, gv_y): + + def op_int_mod(self, gv_x, gv_y): + gv_dividend = self.op_int_floordiv(gv_x, gv_y) + gv_z = self.op_int_mul(gv_dividend, gv_y) + return self.op_int_sub(gv_x, gv_z) + + ## def op_int_mod_zer(self, gv_x, gv_y): + + def op_int_lt(self, gv_x, gv_y): + return self._compare('lt', gv_x, gv_y) + + def op_int_le(self, gv_x, gv_y): + return self._compare('le', gv_x, gv_y) + + def op_int_eq(self, gv_x, gv_y): + return self._compare('eq', gv_x, gv_y) + + def op_int_ne(self, gv_x, gv_y): + return self._compare('ne', gv_x, gv_y) + + def op_int_gt(self, gv_x, gv_y): + return self._compare('gt', gv_x, gv_y) + + def op_int_ge(self, gv_x, gv_y): + return self._compare('ge', gv_x, gv_y) + + op_char_lt = op_int_lt + op_char_le = op_int_le + op_char_eq = op_int_eq + op_char_ne = op_int_ne + op_char_gt = op_int_gt + op_char_ge = op_int_ge + + op_unichar_eq = op_int_eq + op_unichar_ne = op_int_ne + + def op_int_and(self, gv_x, gv_y): + return self._arg_arg_op(gv_x, gv_y, _PPC.and_) + + def op_int_or(self, gv_x, gv_y): + return self._arg_arg_op_with_uimm(gv_x, gv_y, _PPC.or_, _PPC.ori, + commutative=True) + + def op_int_lshift(self, gv_x, gv_y): + if gv_y.fits_in_simm(): + if abs(gv_y.value) >= 32: + return self.rgenop.genconst(0) + else: + return self._arg_uimm_op(gv_x, gv_y, _PPC.slwi) + # computing x << y when you don't know y is <=32 + # (we can assume y >= 0 though) + # here's the plan: + # + # z = nltu(y, 32) (as per cwg) + # w = x << y + # r = w&z + gv_a = self._arg_simm_op(gv_y, self.rgenop.genconst(32), _PPC.subfic) + gv_b = self._arg_op(gv_y, _PPC.addze) + gv_z = self._arg_arg_op(gv_b, gv_y, _PPC.subf) + gv_w = self._arg_arg_op(gv_x, gv_y, _PPC.slw) + return self._arg_arg_op(gv_z, gv_w, _PPC.and_) + + ## def op_int_lshift_val(self, gv_x, gv_y): + + def op_int_rshift(self, gv_x, gv_y): + if gv_y.fits_in_simm(): + if abs(gv_y.value) >= 32: + gv_y = self.rgenop.genconst(31) + return self._arg_simm_op(gv_x, gv_y, _PPC.srawi) + # computing x >> y when you don't know y is <=32 + # (we can assume y >= 0 though) + # here's the plan: + # + # ntlu_y_32 = nltu(y, 32) (as per cwg) + # o = srawi(x, 31) & ~ntlu_y_32 + # w = (x >> y) & ntlu_y_32 + # r = w|o + gv_a = self._arg_uimm_op(gv_y, self.rgenop.genconst(32), _PPC.subfic) + gv_b = self._arg_op(gv_y, _PPC.addze) + gv_ntlu_y_32 = self._arg_arg_op(gv_b, gv_y, _PPC.subf) + + gv_c = self._arg_uimm_op(gv_x, self.rgenop.genconst(31), _PPC.srawi) + gv_o = self._arg_arg_op(gv_c, gv_ntlu_y_32, _PPC.andc_) + + gv_e = self._arg_arg_op(gv_x, gv_y, _PPC.sraw) + gv_w = self._arg_arg_op(gv_e, gv_ntlu_y_32, _PPC.and_) + + return self._arg_arg_op(gv_o, gv_w, _PPC.or_) + + ## def op_int_rshift_val(self, gv_x, gv_y): + + def op_int_xor(self, gv_x, gv_y): + return self._arg_arg_op_with_uimm(gv_x, gv_y, _PPC.xor, _PPC.xori, + commutative=True) + + ## various int_*_ovfs + + op_uint_is_true = op_int_is_true + op_uint_invert = op_int_invert + + op_uint_add = op_int_add + op_uint_sub = op_int_sub + op_uint_mul = op_int_mul + + def op_uint_floordiv(self, gv_x, gv_y): + return self._arg_arg_op(gv_x, gv_y, _PPC.divwu) + + ## def op_uint_floordiv_zer(self, gv_x, gv_y): + + def op_uint_mod(self, gv_x, gv_y): + gv_dividend = self.op_uint_floordiv(gv_x, gv_y) + gv_z = self.op_uint_mul(gv_dividend, gv_y) + return self.op_uint_sub(gv_x, gv_z) + + ## def op_uint_mod_zer(self, gv_x, gv_y): + + def op_uint_lt(self, gv_x, gv_y): + return self._compare_u('lt', gv_x, gv_y) + + def op_uint_le(self, gv_x, gv_y): + return self._compare_u('le', gv_x, gv_y) + + def op_uint_eq(self, gv_x, gv_y): + return self._compare_u('eq', gv_x, gv_y) + + def op_uint_ne(self, gv_x, gv_y): + return self._compare_u('ne', gv_x, gv_y) + + def op_uint_gt(self, gv_x, gv_y): + return self._compare_u('gt', gv_x, gv_y) + + def op_uint_ge(self, gv_x, gv_y): + return self._compare_u('ge', gv_x, gv_y) + + op_uint_and = op_int_and + op_uint_or = op_int_or + + op_uint_lshift = op_int_lshift + + ## def op_uint_lshift_val(self, gv_x, gv_y): + + def op_uint_rshift(self, gv_x, gv_y): + if gv_y.fits_in_simm(): + if abs(gv_y.value) >= 32: + return self.rgenop.genconst(0) + else: + return self._arg_simm_op(gv_x, gv_y, _PPC.srwi) + # computing x << y when you don't know y is <=32 + # (we can assume y >=0 though, i think) + # here's the plan: + # + # z = ngeu(y, 32) (as per cwg) + # w = x >> y + # r = w&z + gv_a = self._arg_simm_op(gv_y, self.rgenop.genconst(32), _PPC.subfic) + gv_b = self._arg_op(gv_y, _PPC.addze) + gv_z = self._arg_arg_op(gv_b, gv_y, _PPC.subf) + gv_w = self._arg_arg_op(gv_x, gv_y, _PPC.srw) + return self._arg_arg_op(gv_z, gv_w, _PPC.and_) + ## def op_uint_rshift_val(self, gv_x, gv_y): + + op_uint_xor = op_int_xor + + # ... floats ... + + # ... llongs, ullongs ... + + # here we assume that booleans are always 1 or 0 and chars are + # always zero-padded. + + op_cast_bool_to_int = _identity + op_cast_bool_to_uint = _identity + ## def op_cast_bool_to_float(self, gv_arg): + op_cast_char_to_int = _identity + op_cast_unichar_to_int = _identity + op_cast_int_to_char = _identity + + op_cast_int_to_unichar = _identity + op_cast_int_to_uint = _identity + ## def op_cast_int_to_float(self, gv_arg): + ## def op_cast_int_to_longlong(self, gv_arg): + op_cast_uint_to_int = _identity + ## def op_cast_uint_to_float(self, gv_arg): + ## def op_cast_float_to_int(self, gv_arg): + ## def op_cast_float_to_uint(self, gv_arg): + ## def op_truncate_longlong_to_int(self, gv_arg): + + # many pointer operations are genop_* special cases above + + op_ptr_eq = op_int_eq + op_ptr_ne = op_int_ne + + op_ptr_nonzero = op_int_is_true + op_ptr_ne = op_int_ne + op_ptr_eq = op_int_eq + + def op_ptr_iszero(self, gv_arg): + return self._compare('eq', gv_arg, self.rgenop.genconst(0)) + + op_cast_ptr_to_int = _identity + + # ... address operations ... + + at specialize.arg(0) +def cast_int_to_whatever(T, value): + if isinstance(T, lltype.Ptr): + return lltype.cast_int_to_ptr(T, value) + elif T is llmemory.Address: + return llmemory.cast_int_to_adr(value) + else: + return lltype.cast_primitive(T, value) + + at specialize.arg(0) +def cast_whatever_to_int(T, value): + if isinstance(T, lltype.Ptr): + return lltype.cast_ptr_to_int(value) + elif T is llmemory.Address: + return llmemory.cast_adr_to_int(value) + else: + return lltype.cast_primitive(lltype.Signed, value) + +class RPPCGenOp(AbstractRGenOp): + + # the set of registers we consider available for allocation + # we can artifically restrict it for testing purposes + freeregs = { + insn.GP_REGISTER:insn.gprs[3:], + insn.FP_REGISTER:insn.fprs, + insn.CR_FIELD:insn.crfs, + insn.CT_REGISTER:[insn.ctr]} + DEBUG_SCRIBBLE = option.debug_scribble + MC_SIZE = 65536 + + def __init__(self): + self.mcs = [] # machine code blocks where no-one is currently writing + self.keepalive_gc_refs = [] + + # ---------------------------------------------------------------- + # the public RGenOp interface + + def newgraph(self, sigtoken, name): + numargs = sigtoken # for now + builder = self.newbuilder() + builder._open() + entrypoint = builder.asm.mc.tell() + inputargs_gv = builder._write_prologue(sigtoken) + return builder, IntConst(entrypoint), inputargs_gv + + @specialize.genconst(1) + def genconst(self, llvalue): + T = lltype.typeOf(llvalue) + if T is llmemory.Address: + return AddrConst(llvalue) + elif isinstance(T, lltype.Primitive): + return IntConst(lltype.cast_primitive(lltype.Signed, llvalue)) + elif isinstance(T, lltype.Ptr): + lladdr = llmemory.cast_ptr_to_adr(llvalue) + if T.TO._gckind == 'gc': + self.keepalive_gc_refs.append(lltype.cast_opaque_ptr(llmemory.GCREF, llvalue)) + return AddrConst(lladdr) + else: + assert 0, "XXX not implemented" + +## @staticmethod +## @specialize.genconst(0) +## def constPrebuiltGlobal(llvalue): + + @staticmethod + def genzeroconst(kind): + return zero_const + + def replay(self, label): + return ReplayBuilder(self), [dummy_var] * len(label.args_gv) + + @staticmethod + def erasedType(T): + if T is llmemory.Address: + return llmemory.Address + if isinstance(T, lltype.Primitive): + return lltype.Signed + elif isinstance(T, lltype.Ptr): + return llmemory.GCREF + else: + assert 0, "XXX not implemented" + + @staticmethod + @specialize.memo() + def fieldToken(T, name): + FIELD = getattr(T, name) + if isinstance(FIELD, lltype.ContainerType): + fieldsize = 0 # not useful for getsubstruct + else: + fieldsize = llmemory.sizeof(FIELD) + return (llmemory.offsetof(T, name), fieldsize) + + @staticmethod + @specialize.memo() + def allocToken(T): + return llmemory.sizeof(T) + + @staticmethod + @specialize.memo() + def varsizeAllocToken(T): + if isinstance(T, lltype.Array): + return RPPCGenOp.arrayToken(T) + else: + # var-sized structs + arrayfield = T._arrayfld + ARRAYFIELD = getattr(T, arrayfield) + arraytoken = RPPCGenOp.arrayToken(ARRAYFIELD) + length_offset, items_offset, item_size = arraytoken + arrayfield_offset = llmemory.offsetof(T, arrayfield) + return (arrayfield_offset+length_offset, + arrayfield_offset+items_offset, + item_size) + + @staticmethod + @specialize.memo() + def arrayToken(A): + return (llmemory.ArrayLengthOffset(A), + llmemory.ArrayItemsOffset(A), + llmemory.ItemOffset(A.OF)) + + @staticmethod + @specialize.memo() + def kindToken(T): + if T is lltype.Float: + py.test.skip("not implemented: floats in the i386^WPPC back-end") + return None # for now + + @staticmethod + @specialize.memo() + def sigToken(FUNCTYPE): + return len(FUNCTYPE.ARGS) # for now + + @staticmethod + @specialize.arg(0) + def read_frame_var(T, base, info, index): + """Read from the stack frame of a caller. The 'base' is the + frame stack pointer captured by the operation generated by + genop_get_frame_base(). The 'info' is the object returned by + get_frame_info(); we are looking for the index-th variable + in the list passed to get_frame_info().""" + place = info[index] + if isinstance(place, StackInfo): + #print '!!!', base, place.offset + #print '???', [peek_word_at(base + place.offset + i) + # for i in range(-64, 65, 4)] + assert place.offset != 0 + value = peek_word_at(base + place.offset) + return cast_int_to_whatever(T, value) + else: + assert isinstance(place, GenConst) + return place.revealconst(T) + + @staticmethod + @specialize.arg(0) + def genconst_from_frame_var(kind, base, info, index): + place = info[index] + if isinstance(place, StackInfo): + #print '!!!', base, place.offset + #print '???', [peek_word_at(base + place.offset + i) + # for i in range(-64, 65, 4)] + assert place.offset != 0 + value = peek_word_at(base + place.offset) + return IntConst(value) + else: + assert isinstance(place, GenConst) + return place + + + @staticmethod + @specialize.arg(0) + def write_frame_place(T, base, place, value): + assert place.offset != 0 + value = cast_whatever_to_int(T, value) + poke_word_into(base + place.offset, value) + + @staticmethod + @specialize.arg(0) + def read_frame_place(T, base, place): + value = peek_word_at(base + place.offset) + return cast_int_to_whatever(T, value) + + def check_no_open_mc(self): + pass + + # ---------------------------------------------------------------- + # ppc-specific interface: + + MachineCodeBlock = codebuf.OwningMachineCodeBlock + ExistingCodeBlock = codebuf.ExistingCodeBlock + + def open_mc(self): + if self.mcs: + return self.mcs.pop() + else: + return self.MachineCodeBlock(self.MC_SIZE) # XXX supposed infinite for now + + def close_mc(self, mc): +## from pypy.jit.codegen.ppc.ppcgen.asmfunc import get_ppcgen +## print '!!!!', cast(mc._data, c_void_p).value +## print '!!!!', mc._data.contents[0] +## get_ppcgen().flush2(cast(mc._data, c_void_p).value, +## mc._size*4) + self.mcs.append(mc) + + def newbuilder(self): + return Builder(self) + +# a switch can take 7 instructions: + +# load_word rSCRATCH, gv_case.value (really two instructions) +# cmpw crf, rSWITCH, rSCRATCH +# load_word rSCRATCH, targetaddr (again two instructions) +# mtctr rSCRATCH +# beqctr crf + +# yay RISC :/ + +class FlexSwitch(CodeGenSwitch): + + # a fair part of this code could likely be shared with the i386 + # backend. + + def __init__(self, rgenop, mc, switch_reg, crf, var2loc, initial_spill_offset): + self.rgenop = rgenop + self.crf = crf + self.switch_reg = switch_reg + self.var2loc = var2loc + self.initial_spill_offset = initial_spill_offset + self.asm = RPPCAssembler() + self.asm.mc = mc + self.default_target_addr = 0 + + def add_case(self, gv_case): + targetbuilder = self.rgenop.newbuilder() + targetbuilder._open() + targetbuilder.initial_var2loc = self.var2loc + targetbuilder.initial_spill_offset = self.initial_spill_offset + target_addr = targetbuilder.asm.mc.tell() + p = self.asm.mc.getpos() + # that this works depends a bit on the fixed length of the + # instruction sequences we use to jump around. if the code is + # ever updated to use the branch-relative instructions (a good + # idea, btw) this will need to be thought about again + try: + self._add_case(gv_case, target_addr) + except codebuf.CodeBlockOverflow: + self.asm.mc.setpos(p) + base = self.asm.mc.tell() + mc = self.rgenop.open_mc() + newmc = mc.reserve(7 * 5 + 4) + self.rgenop.close_mc(mc) + new_addr = newmc.tell() + self.asm.load_word(rSCRATCH, new_addr) + self.asm.mtctr(rSCRATCH) + self.asm.bctr() + size = self.asm.mc.tell() - base + flush_icache(base, size) + self.asm.mc = newmc + self._add_case(gv_case, target_addr) + return targetbuilder + + def _add_case(self, gv_case, target_addr): + asm = self.asm + base = self.asm.mc.tell() + assert isinstance(gv_case, GenConst) + gv_case.load_now(asm, insn.gprs[0]) + asm.cmpw(self.crf.number, rSCRATCH, self.switch_reg.number) + asm.load_word(rSCRATCH, target_addr) + asm.mtctr(rSCRATCH) + asm.bcctr(12, self.crf.number*4 + 2) + if self.default_target_addr: + self._write_default() + size = self.asm.mc.tell() - base + flush_icache(base, size) + + def add_default(self): + targetbuilder = self.rgenop.newbuilder() + targetbuilder._open() + targetbuilder.initial_var2loc = self.var2loc + targetbuilder.initial_spill_offset = self.initial_spill_offset + base = self.asm.mc.tell() + self.default_target_addr = targetbuilder.asm.mc.tell() + self._write_default() + size = self.asm.mc.tell() - base + flush_icache(base, size) + return targetbuilder + + def _write_default(self): + pos = self.asm.mc.getpos() + self.asm.load_word(rSCRATCH, self.default_target_addr) + self.asm.mtctr(rSCRATCH) + self.asm.bctr() + self.asm.mc.setpos(pos) + +global_rgenop = RPPCGenOp() +RPPCGenOp.constPrebuiltGlobal = global_rgenop.genconst + +def peek_word_at(addr): + # now the Very Obscure Bit: when translated, 'addr' is an + # address. When not, it's an integer. It just happens to + # make the test pass, but that's probably going to change. + if we_are_translated(): + return addr.signed[0] + else: + from ctypes import cast, c_void_p, c_int, POINTER + p = cast(c_void_p(addr), POINTER(c_int)) + return p[0] + +def poke_word_into(addr, value): + # now the Very Obscure Bit: when translated, 'addr' is an + # address. When not, it's an integer. It just happens to + # make the test pass, but that's probably going to change. + if we_are_translated(): + addr.signed[0] = value + else: + from ctypes import cast, c_void_p, c_int, POINTER + p = cast(c_void_p(addr), POINTER(c_int)) + p[0] = value + +zero_const = AddrConst(llmemory.NULL) diff --git a/pypy/jit/backend/ppc/runner.py b/pypy/jit/backend/ppc/runner.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/runner.py @@ -0,0 +1,152 @@ +import py +from pypy.rpython.lltypesystem import lltype, llmemory, rffi +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.llinterp import LLInterpreter +from pypy.rlib.objectmodel import we_are_translated +from pypy.jit.metainterp import history, compile +from pypy.jit.backend.x86.assembler import Assembler386 +from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS +from pypy.jit.backend.x86.profagent import ProfileAgent +from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU +from pypy.jit.backend.x86 import regloc +import sys + +from pypy.tool.ansi_print import ansi_log +log = py.log.Producer('jitbackend') +py.log.setconsumer('jitbackend', ansi_log) + + +class PPC_64_CPU(AbstractLLCPU): + debug = True + supports_floats = False + + BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) + dont_keepalive_stuff = False # for tests + + def __init__(self, rtyper, stats, opts=None, translate_support_code=False, + gcdescr=None): + if gcdescr is not None: + gcdescr.force_index_ofs = FORCE_INDEX_OFS + AbstractLLCPU.__init__(self, rtyper, stats, opts, + translate_support_code, gcdescr) + + def setup(self): + if self.opts is not None: + failargs_limit = self.opts.failargs_limit + else: + failargs_limit = 1000 + self.assembler = Assembler386(self, self.translate_support_code, + failargs_limit) + + def get_on_leave_jitted_hook(self): + return self.assembler.leave_jitted_hook + + def setup_once(self): + self.assembler.setup_once() + + def finish_once(self): + self.assembler.finish_once() + + def compile_loop(self, inputargs, operations, looptoken, log=True): + return self.assembler.assemble_loop(inputargs, operations, looptoken, + log=log) + + def compile_bridge(self, faildescr, inputargs, operations, + original_loop_token, log=True): + clt = original_loop_token.compiled_loop_token + clt.compiling_a_bridge() + return self.assembler.assemble_bridge(faildescr, inputargs, operations, + original_loop_token, log=log) + + def set_future_value_int(self, index, intvalue): + self.assembler.fail_boxes_int.setitem(index, intvalue) + + def set_future_value_float(self, index, floatvalue): + self.assembler.fail_boxes_float.setitem(index, floatvalue) + + def set_future_value_ref(self, index, ptrvalue): + self.assembler.fail_boxes_ptr.setitem(index, ptrvalue) + + def get_latest_value_int(self, index): + return self.assembler.fail_boxes_int.getitem(index) + + def get_latest_value_float(self, index): + return self.assembler.fail_boxes_float.getitem(index) + + def get_latest_value_ref(self, index): + return self.assembler.fail_boxes_ptr.getitem(index) + + def get_latest_value_count(self): + return self.assembler.fail_boxes_count + + def clear_latest_values(self, count): + setitem = self.assembler.fail_boxes_ptr.setitem + null = lltype.nullptr(llmemory.GCREF.TO) + for index in range(count): + setitem(index, null) + + def get_latest_force_token(self): + return self.assembler.fail_ebp + FORCE_INDEX_OFS + + def execute_token(self, executable_token): + addr = executable_token._x86_bootstrap_code + #llop.debug_print(lltype.Void, ">>>> Entering", addr) + func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr) + #llop.debug_print(lltype.Void, "<<<< Back") + fail_index = self._execute_call(func) + return self.get_fail_descr_from_number(fail_index) + + def _execute_call(self, func): + # help flow objspace + prev_interpreter = None + if not self.translate_support_code: + prev_interpreter = LLInterpreter.current_interpreter + LLInterpreter.current_interpreter = self.debug_ll_interpreter + res = 0 + try: + res = func() + finally: + if not self.translate_support_code: + LLInterpreter.current_interpreter = prev_interpreter + return res + + @staticmethod + def cast_ptr_to_int(x): + adr = llmemory.cast_ptr_to_adr(x) + return CPU386.cast_adr_to_int(adr) + + all_null_registers = lltype.malloc(rffi.LONGP.TO, 24, + flavor='raw', zero=True, + immortal=True) + + def force(self, addr_of_force_index): + TP = rffi.CArrayPtr(lltype.Signed) + fail_index = rffi.cast(TP, addr_of_force_index)[0] + assert fail_index >= 0, "already forced!" + faildescr = self.get_fail_descr_from_number(fail_index) + rffi.cast(TP, addr_of_force_index)[0] = ~fail_index + frb = self.assembler._find_failure_recovery_bytecode(faildescr) + bytecode = rffi.cast(rffi.UCHARP, frb) + # start of "no gc operation!" block + fail_index_2 = self.assembler.grab_frame_values( + bytecode, + addr_of_force_index - FORCE_INDEX_OFS, + self.all_null_registers) + self.assembler.leave_jitted_hook() + # end of "no gc operation!" block + assert fail_index == fail_index_2 + return faildescr + + def redirect_call_assembler(self, oldlooptoken, newlooptoken): + self.assembler.redirect_call_assembler(oldlooptoken, newlooptoken) + + def invalidate_loop(self, looptoken): + from pypy.jit.backend.x86 import codebuf + + for addr, tgt in looptoken.compiled_loop_token.invalidate_positions: + mc = codebuf.MachineCodeBlockWrapper() + mc.JMP_l(tgt) + assert mc.get_relative_pos() == 5 # [JMP] [tgt 4 bytes] + mc.copy_to_raw_memory(addr - 1) + # positions invalidated + looptoken.compiled_loop_token.invalidate_positions = [] diff --git a/pypy/jit/backend/ppc/test/__init__.py b/pypy/jit/backend/ppc/test/__init__.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/test/__init__.py @@ -0,0 +1,1 @@ +# diff --git a/pypy/jit/backend/ppc/test/test_genc_ts.py b/pypy/jit/backend/ppc/test/test_genc_ts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/test/test_genc_ts.py @@ -0,0 +1,16 @@ +import py +from pypy.jit.codegen.i386.test.test_genc_ts import I386TimeshiftingTestMixin +from pypy.jit.timeshifter.test import test_timeshift +from pypy.jit.codegen.ppc.rgenop import RPPCGenOp + +class PPCTimeshiftingTestMixin(I386TimeshiftingTestMixin): + RGenOp = RPPCGenOp + +class TestTimeshiftPPC(PPCTimeshiftingTestMixin, + test_timeshift.TestLLType): + + # for the individual tests see + # ====> ../../../timeshifter/test/test_timeshift.py + + pass + diff --git a/pypy/jit/backend/ppc/test/test_interp.py b/pypy/jit/backend/ppc/test/test_interp.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/test/test_interp.py @@ -0,0 +1,22 @@ +from pypy.jit.codegen.ppc import codebuf, rgenop +from pypy.rpython.lltypesystem import lltype +from pypy.jit.codegen.test import rgenop_tests +from pypy.rpython.test.test_llinterp import interpret +from pypy.jit.codegen.ppc.test import test_rgenop + +class LLTypeRGenOp(rgenop.RPPCGenOp): + MachineCodeBlock = codebuf.LLTypeMachineCodeBlock + ExistingCodeBlock = codebuf.LLTypeExistingCodeBlock + +def test_simple(): + FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) + def f(n): + rgenop = LLTypeRGenOp() + sigtoken = rgenop.sigToken(FUNC) + builder, gv_add_one, [gv_x] = rgenop.newgraph(sigtoken, "adder") + builder.start_writing() + gv_result = builder.genop2("int_add", gv_x, rgenop.genconst(n)) + builder.finish_and_return(sigtoken, gv_result) + builder.end() + res = interpret(f, [5], policy=rgenop_tests.GENOP_POLICY) + # just testing that this didn't crash diff --git a/pypy/jit/backend/ppc/test/test_interp_ts.py b/pypy/jit/backend/ppc/test/test_interp_ts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/test/test_interp_ts.py @@ -0,0 +1,21 @@ +from pypy.jit.codegen.ppc.conftest import option +import py +from pypy.jit.codegen.i386.test.test_interp_ts import I386LLInterpTimeshiftingTestMixin +from pypy.jit.timeshifter.test import test_timeshift + +def setup_module(mod): + if not option.run_interp_tests: + py.test.skip("these tests take ages and are not really useful") + + +class PPCLLInterpTimeshiftingTestMixin(I386LLInterpTimeshiftingTestMixin): + from pypy.jit.codegen.ppc.test.test_interp import LLTypeRGenOp as RGenOp + +class TestTimeshiftPPC(PPCLLInterpTimeshiftingTestMixin, + test_timeshift.TestLLType): + + # for the individual tests see + # ====> ../../../timeshifter/test/test_timeshift.py + + pass + diff --git a/pypy/jit/backend/ppc/test/test_operation.py b/pypy/jit/backend/ppc/test/test_operation.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/test/test_operation.py @@ -0,0 +1,43 @@ +from pypy.jit.codegen.test.operation_tests import OperationTests +from pypy.jit.codegen.ppc.rgenop import RPPCGenOp +from pypy.rpython.memory.lltypelayout import convert_offset_to_int +from pypy.rlib.objectmodel import specialize + +def conv(n): + if not isinstance(n, int): + n = convert_offset_to_int(n) + return n + + +class RGenOpPacked(RPPCGenOp): + """Like RPPCGenOp, but produces concrete offsets in the tokens + instead of llmemory.offsets. These numbers may not agree with + your C compiler's. + """ + + @staticmethod + @specialize.memo() + def fieldToken(T, name): + return tuple(map(conv, RPPCGenOp.fieldToken(T, name))) + + @staticmethod + @specialize.memo() + def arrayToken(A): + return tuple(map(conv, RPPCGenOp.arrayToken(A))) + + @staticmethod + @specialize.memo() + def allocToken(T): + return conv(RPPCGenOp.allocToken(T)) + + @staticmethod + @specialize.memo() + def varsizeAllocToken(A): + return tuple(map(conv, RPPCGenOp.varsizeAllocToken(A))) + + +class PPCTestMixin(object): + RGenOp = RGenOpPacked + +class TestOperation(PPCTestMixin, OperationTests): + pass diff --git a/pypy/jit/backend/ppc/test/test_rgenop.py b/pypy/jit/backend/ppc/test/test_rgenop.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/test/test_rgenop.py @@ -0,0 +1,33 @@ +import py +from pypy.jit.codegen.ppc.rgenop import RPPCGenOp +from pypy.rpython.lltypesystem import lltype +from pypy.jit.codegen.test.rgenop_tests import FUNC, FUNC2 +from pypy.jit.codegen.test.rgenop_tests import AbstractRGenOpTestsDirect +from pypy.jit.codegen.test.rgenop_tests import AbstractRGenOpTestsCompile +from ctypes import cast, c_int, c_void_p, CFUNCTYPE +from pypy.jit.codegen.ppc import instruction as insn + +# for the individual tests see +# ====> ../../test/rgenop_tests.py + +class FewRegisters(RPPCGenOp): + freeregs = { + insn.GP_REGISTER:insn.gprs[3:6], + insn.FP_REGISTER:insn.fprs, + insn.CR_FIELD:insn.crfs[:1], + insn.CT_REGISTER:[insn.ctr]} + +class FewRegistersAndScribble(FewRegisters): + DEBUG_SCRIBBLE = True + +class TestRPPCGenopDirect(AbstractRGenOpTestsDirect): + RGenOp = RPPCGenOp + +class TestRPPCGenopCompile(AbstractRGenOpTestsCompile): + RGenOp = RPPCGenOp + +class TestRPPCGenopNoRegs(AbstractRGenOpTestsDirect): + RGenOp = FewRegisters + +class TestRPPCGenopNoRegsAndScribble(AbstractRGenOpTestsDirect): + RGenOp = FewRegistersAndScribble From noreply at buildbot.pypy.org Mon Jul 18 17:37:45 2011 From: noreply at buildbot.pypy.org (hager) Date: Mon, 18 Jul 2011 17:37:45 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Added test for mr instruction. Message-ID: <20110718153745.9FC51829B8@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45714:3f73bf15742d Date: 2011-07-12 17:51 +0200 http://bitbucket.org/pypy/pypy/changeset/3f73bf15742d/ Log: Added test for mr instruction. diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py --- a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py +++ b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py @@ -21,15 +21,21 @@ if autodetect_main_model() not in ["ppc", "ppc64"]: py.test.skip("can't test all of ppcgen on non-PPC!") + def test_load_imm(self): + a = MyPPCAssembler() + a.li(3, 200) + a.blr() + f = a.assemble() + assert f() == 200 + def test_add_imm(self): a = MyPPCAssembler() - a.li(3, 6) a.addi(3, 3, 1) a.blr() - f = a.assemble() assert f() == 7 + """ class TestAssemble(object): From noreply at buildbot.pypy.org Mon Jul 18 17:37:46 2011 From: noreply at buildbot.pypy.org (hager) Date: Mon, 18 Jul 2011 17:37:46 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Added some more tests. Message-ID: <20110718153746.C82CD829B8@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45715:83298f0b8507 Date: 2011-07-15 15:39 +0200 http://bitbucket.org/pypy/pypy/changeset/83298f0b8507/ Log: Added some more tests. diff --git a/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py b/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py --- a/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py +++ b/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py @@ -1,7 +1,12 @@ +import os +import struct from pypy.jit.backend.ppc.ppcgen.ppc_form import PPCForm as Form from pypy.jit.backend.ppc.ppcgen.ppc_field import ppc_fields from pypy.jit.backend.ppc.ppcgen.assembler import Assembler from pypy.jit.backend.ppc.ppcgen.symbol_lookup import lookup +from pypy.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin +from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager +from pypy.rpython.lltypesystem import lltype, rffi A = Form("frD", "frA", "frB", "XO3", "Rc") A1 = Form("frD", "frB", "XO3", "Rc") @@ -458,7 +463,7 @@ xor = XS(31, XO1=316, Rc=0) xorx = XS(31, XO1=316, Rc=1) -class PPCAssembler(BasicPPCAssembler): +class PPCAssembler(BasicPPCAssembler, BlockBuilderMixin): BA = BasicPPCAssembler # awkward mnemonics: @@ -774,6 +779,11 @@ mtcr = BA.mtcrf(CRM=0xFF) + def emit(self, insn): + bytes = struct.pack("i", insn) + for byte in bytes: + self.writechar(byte) + def hi(w): return w >> 16 @@ -793,13 +803,68 @@ return v class MyPPCAssembler(PPCAssembler): + def __init__(self): + PPCAssembler.__init__(self) + self.init_block_builder() + self.patch_list = [] + def load_word(self, rD, word): self.addis(rD, 0, hi(word)) self.ori(rD, rD, lo(word)) + def load_from(self, rD, addr): self.addis(rD, 0, ha(addr)) self.lwz(rD, rD, la(addr)) + def nop(self): + self.ori(0, 0, 0) + + #def bl(self, addr): + # offset = 4 * len(self.insts) + # self.nop() + # self.patch_list.append((offset, addr)) + + #def assemble(self, dump=os.environ.has_key('PYPY_DEBUG')): + # insns = self.assemble0(dump) + # for i in insns: + # self.emit(i) + # i = self.materialize(AsmMemoryManager(), []) + # t = lltype.FuncType([], lltype.Signed) + # self.patch_jumps(i) + # return rffi.cast(lltype.Ptr(t), i) + # + #def patch_jumps(self, rawstart): + # #import pdb; pdb.set_trace() + + # for offset, addr in self.patch_list: + # #delta = (rawstart + offset) - addr + # delta = addr - (rawstart + offset) + # delta >>= 2 + # print "delta =", delta + # #assert (delta >> 24) == -1 + + # updater = BranchUpdater() + # #updater.bl(delta) + # self.load_word(reg, h) + + + # updater.bctrl() + # updater.write_to_mem(rawstart + offset) + +class BranchUpdater(PPCAssembler): + def __init__(self): + PPCAssembler.__init__(self) + self.init_block_builder() + + def write_to_mem(self, addr): + self.assemble() + self.copy_to_raw_memory(addr) + + def assemble(self, dump=os.environ.has_key('PYPY_DEBUG')): + insns = self.assemble0(dump) + for i in insns: + self.emit(i) + def b(n): r = [] for i in range(32): @@ -843,3 +908,5 @@ if __name__ == '__main__': main() + + diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py --- a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py +++ b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py @@ -7,6 +7,8 @@ from pypy.jit.backend.ppc.ppcgen import form, pystructs from pypy.jit.backend.detect_cpu import autodetect_main_model +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.rpython.annlowlevel import llhelper class TestDisassemble(object): def test_match(self): @@ -36,7 +38,55 @@ f = a.assemble() assert f() == 7 - + def test_load_word(self): + a = MyPPCAssembler() + word = 12341234 + a.load_word(10, word) + a.mtctr(10) + a.mfctr(11) + a.mr(3, 11) + a.blr() + f = a.assemble() + assert f() == word + + def test_call_function(self): + functype = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) + call_addr = rffi.cast(lltype.Signed, llhelper(functype, func)) + a = MyPPCAssembler() + + # NOW EXPLICITLY: + # + # - Load the address of the function to call into a register x + # - Move the content of this register x into CTR + # - Set the LR manually (or with bctrl) + # - Do jump + # - hopefully no segfault =) + + a.li(3, 50) + a.load_word(10, call_addr) + a.mtctr(10) + a.bctr() + a.blr() + + f = a.assemble() + assert f() == 65 + +class AsmCode(object): + def __init__(self, size): + self.code = MachineCodeBlockWrapper() + + def emit(self, insn): + bytes = struct.pack("i", insn) + for byte in bytes: + self.code.writechar(byte) + + def get_function(self): + i = self.code.materialize(AsmMemoryManager(), []) + t = lltype.FuncType([], lltype.Signed) + return rffi.cast(lltype.Ptr(t), i) + +def func(arg): + return arg + 15 """ class TestAssemble(object): From noreply at buildbot.pypy.org Mon Jul 18 17:37:47 2011 From: noreply at buildbot.pypy.org (hager) Date: Mon, 18 Jul 2011 17:37:47 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Added some more assembler tests. Message-ID: <20110718153747.F00FC829B8@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45716:77eb70dec1b5 Date: 2011-07-18 11:17 +0200 http://bitbucket.org/pypy/pypy/changeset/77eb70dec1b5/ Log: Added some more assembler tests. diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py --- a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py +++ b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py @@ -18,6 +18,7 @@ inst = a.insts[-1] assert A.add.match(inst.assemble()) +# Testing simple assembler instructions class TestAssemble(object): def setup_class(cls): if autodetect_main_model() not in ["ppc", "ppc64"]: @@ -41,14 +42,66 @@ def test_load_word(self): a = MyPPCAssembler() word = 12341234 + a.load_word(10, word) a.mtctr(10) a.mfctr(11) a.mr(3, 11) a.blr() + f = a.assemble() assert f() == word + def test_add_reg(self): + a = MyPPCAssembler() + word1 = 11111111 + word2 = 22222222 + + a.load_word(10, word1) + a.load_word(11, word2) + a.add(12, 10, 11) + a.mr(3, 12) + a.blr() + + f = a.assemble() + assert f() == word1 + word2 + + def test_add_pos_and_neg(self): + a = MyPPCAssembler() + word1 = 2000 + word2 = -3000 + + a.load_word(10, word1) + a.load_word(11, word2) + a.add(3, 10, 11) + a.blr() + + f = a.assemble() + assert f() == -1000 + + def test_sub_imm(self): + a = MyPPCAssembler() + + a.li(3, 10) + a.subi(3, 3, 3) + a.blr() + + f = a.assemble() + assert f() == 7 + + def test_sub_reg(self): + a = MyPPCAssembler() + word1 = 123435 + word2 = 76457 + + a.load_word(5, word1) + a.load_word(6, word2) + a.sub(3, 5, 6) + a.blr() + + f = a.assemble() + assert f() == word1 - word2 + def test_call_function(self): functype = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) call_addr = rffi.cast(lltype.Signed, llhelper(functype, func)) From noreply at buildbot.pypy.org Mon Jul 18 17:37:49 2011 From: noreply at buildbot.pypy.org (hager) Date: Mon, 18 Jul 2011 17:37:49 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Added decorator for tests, so less boilerplate code is needed. Message-ID: <20110718153749.234A9829B8@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45717:ae262073e390 Date: 2011-07-18 14:45 +0200 http://bitbucket.org/pypy/pypy/changeset/ae262073e390/ Log: Added decorator for tests, so less boilerplate code is needed. diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py --- a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py +++ b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py @@ -18,89 +18,154 @@ inst = a.insts[-1] assert A.add.match(inst.assemble()) + +""" +Creates the boilerplate code for the tests. +- Make an MyPPCAssembler object +- Let the given test create the machine code +- Create a function and call it +- Compare the return value with the expected result +""" +def asmtest(expected=-1): + def testmaker(test): + def newtest(self): + a = MyPPCAssembler() + test(self, a) + f = a.assemble() + assert f() == expected + return newtest + return testmaker + + +""" +Treats the given bitstring as binary representation +of an integer in two's complement. +""" +def bits_to_signed_int(bits): + assert len(bits) > 0 + sign = 1 + if bits[0] == "1": + sign = -1 + bits = bits[1:].replace("0", "$").replace("1", "0").replace("$", "1") + return sign * (int(bits, 2) + 1) + # Testing simple assembler instructions class TestAssemble(object): def setup_class(cls): if autodetect_main_model() not in ["ppc", "ppc64"]: py.test.skip("can't test all of ppcgen on non-PPC!") - def test_load_imm(self): - a = MyPPCAssembler() + """ + Tests are build like this: + + @asmtest(expected=) + def testX(self, assembler): + + + + This is equivalent to: + + + def testX(self): + assembler = MyPPCAssembler() + + + + f = assembler.assemble() + assert f() == + """ + + @asmtest(expected=200) + def test_load_imm(self, a): a.li(3, 200) a.blr() - f = a.assemble() - assert f() == 200 - def test_add_imm(self): - a = MyPPCAssembler() + @asmtest(expected=7) + def test_add_imm(self, a): a.li(3, 6) a.addi(3, 3, 1) a.blr() - f = a.assemble() - assert f() == 7 - def test_load_word(self): - a = MyPPCAssembler() - word = 12341234 - - a.load_word(10, word) + @asmtest(expected=12341234) + def test_load_word(self, a): + a.load_word(10, 12341234) a.mtctr(10) a.mfctr(11) a.mr(3, 11) a.blr() - f = a.assemble() - assert f() == word - - def test_add_reg(self): - a = MyPPCAssembler() - word1 = 11111111 - word2 = 22222222 - - a.load_word(10, word1) - a.load_word(11, word2) + @asmtest(expected=33333333) + def test_add_reg(self, a): + a.load_word(10, 11111111) + a.load_word(11, 22222222) a.add(12, 10, 11) a.mr(3, 12) a.blr() - f = a.assemble() - assert f() == word1 + word2 - - def test_add_pos_and_neg(self): - a = MyPPCAssembler() - word1 = 2000 - word2 = -3000 - - a.load_word(10, word1) - a.load_word(11, word2) + @asmtest(expected=-1000) + def test_add_pos_and_neg(self, a): + a.load_word(10, 2000) + a.load_word(11, -3000) a.add(3, 10, 11) a.blr() - f = a.assemble() - assert f() == -1000 - - def test_sub_imm(self): - a = MyPPCAssembler() - + @asmtest(expected=7) + def test_sub_imm(self, a): a.li(3, 10) a.subi(3, 3, 3) a.blr() - f = a.assemble() - assert f() == 7 - - def test_sub_reg(self): - a = MyPPCAssembler() - word1 = 123435 - word2 = 76457 - - a.load_word(5, word1) - a.load_word(6, word2) + @asmtest(expected=(123435 - 76457)) + def test_sub_reg(self, a): + a.load_word(5, 123435) + a.load_word(6, 76457) a.sub(3, 5, 6) a.blr() - f = a.assemble() - assert f() == word1 - word2 + @asmtest(expected=(10000 * 5000)) + def test_mul_imm(self, a): + a.load_word(3, 10000) + a.mulli(3, 3, 5000) + a.blr() + + # 1000000 * 1000000 = 0b1110100011010100101001010001000000000000 + # expect: r3 = -HWORD-|11010100101001010001000000000000 + @asmtest(expected=bits_to_signed_int('11010100101001010001000000000000')) + def test_mullw(self, a): + word = 1000000 + a.load_word(5, word) + a.load_word(6, word) + a.mullw(3, 5, 6) + a.blr() + + # 1000000 * 1000000 = 0b1110100011010100101001010001000000000000 + # expect: r3 = 11101000|------------LWORD-------------- + @asmtest(expected=int('11101000', 2)) + def test_mulhw(self, a): + word = 1000000 + a.load_word(5, word) + a.load_word(6, word) + a.mulhw(3, 5, 6) + a.blr() + + # 1000000 * 1000000 = 0b1110100011010100101001010001000000000000 + # expect: r3 = 11101000|------------LWORD-------------- + @asmtest(expected=int('11101000', 2)) + def test_mulhwu(self, a): + word = 1000000 + a.load_word(5, word) + a.load_word(6, word) + a.mulhwu(3, 5, 6) + a.blr() + + @asmtest(expected=10000) + def test_divw(self, a): + divident = 1000000 + divisor = 100 + a.load_word(10, divident) + a.load_word(11, divisor) + a.divw(3, 10, 11) + a.blr() def test_call_function(self): functype = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) @@ -113,7 +178,6 @@ # - Move the content of this register x into CTR # - Set the LR manually (or with bctrl) # - Do jump - # - hopefully no segfault =) a.li(3, 50) a.load_word(10, call_addr) @@ -138,6 +202,8 @@ t = lltype.FuncType([], lltype.Signed) return rffi.cast(lltype.Ptr(t), i) + + def func(arg): return arg + 15 """ From noreply at buildbot.pypy.org Mon Jul 18 17:37:50 2011 From: noreply at buildbot.pypy.org (hager) Date: Mon, 18 Jul 2011 17:37:50 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Added further tests. Message-ID: <20110718153750.5B4FA829B8@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45718:cba5428f7d3a Date: 2011-07-18 17:33 +0200 http://bitbucket.org/pypy/pypy/changeset/cba5428f7d3a/ Log: Added further tests. diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py --- a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py +++ b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py @@ -49,6 +49,9 @@ bits = bits[1:].replace("0", "$").replace("1", "0").replace("$", "1") return sign * (int(bits, 2) + 1) +def hex_to_signed_int(hx): + return bits_to_signed_int(bin(int(hx, 16))[2:]) + # Testing simple assembler instructions class TestAssemble(object): def setup_class(cls): @@ -188,6 +191,82 @@ f = a.assemble() assert f() == 65 + @asmtest(expected=0) + def test_and(self, a): + a.load_word(10, 8) + a.load_word(11, 7) + a.and_(3, 10, 11) + a.blr() + + @asmtest(expected=15) + def test_or(self, a): + a.load_word(10, 8) + a.load_word(11, 7) + a.or_(3, 10, 11) + a.blr() + + @asmtest(expected=15) + def test_nand(self, a): + a.load_word(10, 8) + a.load_word(11, 7) + a.nand(3, 10, 11) + a.load_word(12, 0x0000000F) # zero out first 28 bits + a.and_(3, 3, 12) # + a.blr() + + @asmtest(expected=1) + def test_nor(self, a): + a.load_word(10, 10) + a.load_word(11, 6) + a.nor(3, 10, 11) + a.load_word(12, 0x0000000F) # zero out first 28 bits + a.and_(3, 3, 12) # + a.blr() + + @asmtest(expected=5) + def test_xor(self, a): + a.load_word(10, 15) + a.load_word(11, 10) + a.xor(3, 10, 11) + a.blr() + + @asmtest(expected=0x120) + def test_slw(self, a): + a.load_word(10, 9) + a.load_word(11, 5) + a.slw(3, 10, 11) + a.blr() + + @asmtest(expected=9) + def test_srw(self, a): + a.load_word(10, 0x120) + a.load_word(11, 5) + a.srw(3, 10, 11) + a.blr() + + def test_neg(self): + a = MyPPCAssembler() + a.load_word(10, 0x0000F0F0) + a.neg(3, 10) + a.blr() + f = a.assemble() + assert f() == hex_to_signed_int("FFFF0F10") + + def test_load_and_store(self): + a = MyPPCAssembler() + word1 = 1000 + word2 = 2000 + a.load_word(10, word1) + a.load_word(11, word2) + a.stw(10, 8, 0) + a.stw(11, 9, 0) + a.lwz(4, 8, 0) + a.lwz(5, 9, 0) + a.add(3, 4, 5) + a.blr() + f = a.assemble() + assert f() == word1 + word2 + class AsmCode(object): def __init__(self, size): self.code = MachineCodeBlockWrapper() From noreply at buildbot.pypy.org Mon Jul 18 18:40:37 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 18 Jul 2011 18:40:37 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: fix some tests Message-ID: <20110718164037.24E85829B8@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45719:e1a8eecf6ae8 Date: 2011-07-18 18:40 +0200 http://bitbucket.org/pypy/pypy/changeset/e1a8eecf6ae8/ Log: fix some tests diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1185,7 +1185,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ From noreply at buildbot.pypy.org Mon Jul 18 20:28:57 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Mon, 18 Jul 2011 20:28:57 +0200 (CEST) Subject: [pypy-commit] pypy numpy-setslice: setslice seems to be all working. needs more tests. Message-ID: <20110718182857.BD8B4829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-setslice Changeset: r45720:2e37d616a1ee Date: 2011-07-18 12:28 -0600 http://bitbucket.org/pypy/pypy/changeset/2e37d616a1ee/ Log: setslice seems to be all working. needs more tests. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -402,6 +402,7 @@ BaseArray.__init__(self) self.signature = signature self.parent = parent + self.storage = parent.storage self.invalidates = parent.invalidates def get_concrete(self): @@ -432,9 +433,14 @@ def __init__(self, start, stop, step, slice_length, parent, signature): ViewArray.__init__(self, parent, signature) - self.start = start - self.stop = stop - self.step = step + if isinstance(parent, SingleDimSlice): + self.start = parent.calc_index(start) + self.stop = parent.calc_index(stop) + self.step = parent.step * self.step + else: + self.start = start + self.stop = stop + self.step = step self.size = slice_length def find_size(self): @@ -448,7 +454,7 @@ while i < stop: slice_driver1.jit_merge_point(signature=signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) - self.parent.setitem(i, arr.eval(j)) + self.storage[i] = arr.eval(j) j += 1 i += step @@ -460,21 +466,15 @@ while i > stop: slice_driver2.jit_merge_point(signature=signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) - self.parent.setitem(i, arr.eval(j)) + self.storage[i] = arr.eval(j) j += 1 i += step def setslice(self, space, start, stop, step, slice_length, arr): - # can't set a slice of a slice yet - if stop < 0: - stop += self.find_size() - if step > 0: - stop = min(stop, self.find_size()) - else: - stop = max(stop, 0) arr = convert_to_array(space, arr) start = self.calc_index(start) - stop = self.calc_index(stop) + if stop != -1: + stop = self.calc_index(stop) step = self.step * step if step > 0: self._sliceloop1(start, stop, step, arr) @@ -553,12 +553,12 @@ def setslice(self, space, start, stop, step, slice_length, arr): i = start - if stop < 0: - stop += self.find_size() - if step > 0: - stop = min(stop, self.find_size()) - else: - stop = max(stop, 0) + #if stop < 0: + # stop += self.find_size() + #if step > 0: + # stop = min(stop, self.find_size()) + #else: + # stop = max(stop, 0) if not isinstance(arr, BaseArray): arr = convert_to_array(space, arr) if step > 0: diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -67,11 +67,16 @@ a[1:4:2] = b assert a[1] == 0. assert a[3] == 1. - # a[1:4:2][::-1] = b # does not work yet - c=a[1:4:2][::-1] - c[:] = b + a[::2] = array([9., 10., 11.]) + assert a[0] == 9. + assert a[2] == 10. + assert a[4] == 11. + a[1:4:2][::-1] = b + assert a[0] == 9. assert a[1] == 1. + assert a[2] == 10. assert a[3] == 0. + assert a[4] == 11. def test_setslice_list(self): from numpy import array From noreply at buildbot.pypy.org Mon Jul 18 21:46:34 2011 From: noreply at buildbot.pypy.org (wlav) Date: Mon, 18 Jul 2011 21:46:34 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: some makefile cleanup Message-ID: <20110718194634.41505829B8@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45721:5d81cf7584a2 Date: 2011-07-18 10:03 -0700 http://bitbucket.org/pypy/pypy/changeset/5d81cf7584a2/ Log: some makefile cleanup diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile --- a/pypy/module/cppyy/test/Makefile +++ b/pypy/module/cppyy/test/Makefile @@ -1,4 +1,5 @@ -all: example01Dict.so datatypesDict.so advancedcppDict.so stltypesDict.so operatorsDict.so +dicts = example01Dict.so datatypesDict.so advancedcppDict.so stltypesDict.so operatorsDict.so +all : $(dicts) ROOTSYS := ${ROOTSYS} @@ -23,26 +24,24 @@ cppflags2=-Wno-pmf-conversions -O3 endif +%Dict.so: %_rflx.cpp %.cxx + g++ -o $@ $^ -shared -lReflex $(cppflags) $(cppflags2) -example01Dict.so: example01.cxx example01.h example01.xml - $(genreflex) example01.h $(genreflexflags) --selection=example01.xml - g++ -o $@ example01_rflx.cpp example01.cxx -shared -lReflex $(cppflags) $(cppflags2) +%_rflx.cpp: %.h %.xml + $(genreflex) $< $(genreflexflags) --selection=$*.xml # rootcint -f example01_cint.cxx -c example01.h example01_LinkDef.h # g++ -I$ROOTSYS/include example01_cint.cxx example01.cxx -shared -o example01Dict.so -L$ROOTSYS/lib -lCore -lCint -datatypesDict.so: datatypes.cxx datatypes.h - $(genreflex) datatypes.h $(genreflexflags) - g++ -o $@ datatypes_rflx.cpp datatypes.cxx -shared -lReflex $(cppflags) $(cppflags2) - -advancedcppDict.so: advancedcpp.cxx advancedcpp.h advancedcpp.xml - $(genreflex) advancedcpp.h $(genreflexflags) --selection=advancedcpp.xml - g++ -o $@ advancedcpp_rflx.cpp advancedcpp.cxx -shared -lReflex $(cppflags) $(cppflags2) - +# TODO: methptrgetter causes these tests to crash, so don't use it for now stltypesDict.so: stltypes.cxx stltypes.h stltypes.xml $(genreflex) stltypes.h --selection=stltypes.xml g++ -o $@ stltypes_rflx.cpp stltypes.cxx -shared -lReflex $(cppflags) $(cppflags2) -operatorsDict.so: operators.cxx operators.h - $(genreflex) operators.h +operatorsDict.so: operators.cxx operators.h operators.xml + $(genreflex) operators.h --selection=operators.xml g++ -o $@ operators_rflx.cpp operators.cxx -shared -lReflex $(cppflags) $(cppflags2) + +.PHONY: clean +clean: + -rm -f $(dicts) diff --git a/pypy/module/cppyy/test/datatypes.xml b/pypy/module/cppyy/test/datatypes.xml new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/datatypes.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pypy/module/cppyy/test/operators.h b/pypy/module/cppyy/test/operators.h --- a/pypy/module/cppyy/test/operators.h +++ b/pypy/module/cppyy/test/operators.h @@ -3,8 +3,6 @@ number() { m_int = 0; } number(int i) { m_int = i; } - int AsInt() { return m_int; } - number operator+(const number& n) const { return number(m_int + n.m_int); } number operator+(int n) const { return number(m_int + n); } number operator-(const number& n) const { return number(m_int - n.m_int); } diff --git a/pypy/module/cppyy/test/operators.xml b/pypy/module/cppyy/test/operators.xml new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/operators.xml @@ -0,0 +1,6 @@ + + + + + + From noreply at buildbot.pypy.org Mon Jul 18 21:46:35 2011 From: noreply at buildbot.pypy.org (wlav) Date: Mon, 18 Jul 2011 21:46:35 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: coding convention consistency Message-ID: <20110718194635.7369E829B8@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45722:f9a70b1a3c66 Date: 2011-07-18 12:45 -0700 http://bitbucket.org/pypy/pypy/changeset/f9a70b1a3c66/ Log: coding convention consistency diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py --- a/pypy/module/cppyy/test/test_cppyy.py +++ b/pypy/module/cppyy/test/test_cppyy.py @@ -36,7 +36,7 @@ cppyy.load_lib(%r) return cppyy._type_byname('example01'), cppyy._type_byname('payload')""" % (shared_lib, ))) - def test_example01static_int(self): + def test01_static_int(self): """Test passing of an int, returning of an int, and overloading on a differening number of arguments.""" @@ -61,7 +61,7 @@ raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, None, 1.)') raises(OverflowError, 't.get_overload("staticAddOneToInt").call(None, None, maxint32+1)') - def test_example01static_double(self): + def test02_static_double(self): """Test passing of a double and returning of a double on a static function.""" t = self.example01 @@ -69,7 +69,7 @@ res = t.get_overload("staticAddToDouble").call(None, None, 0.09) assert res == 0.09 + 0.01 - def test_example01static_constcharp(self): + def test03_static_constcharp(self): """Test passing of a C string and returning of a C string on a static function.""" @@ -84,7 +84,7 @@ raises(TypeError, 't.get_overload("staticStrcpy").call(None, None, 1.)') # TODO: this leaks - def test_example01method_int(self): + def test04_method_int(self): """Test passing of a int, returning of a int, and memory cleanup, on a method.""" import cppyy @@ -117,7 +117,7 @@ raises(TypeError, t.get_overload("addDataToInt").call, 41, None, 4) - def test_example01memory(self): + def test05_memory(self): """Test memory destruction and integrity.""" import gc @@ -149,7 +149,7 @@ gc.collect() assert t.get_overload("getCount").call(None, None) == 0 - def test_example01method_double(self): + def test06_method_double(self): """Test passing of a double and returning of double on a method""" import cppyy @@ -166,7 +166,7 @@ e.destruct() assert t.get_overload("getCount").call(None, None) == 0 - def test_example01method_constcharp(self): + def test07_method_constcharp(self): """Test passing of a C string and returning of a C string on a method.""" import cppyy @@ -183,7 +183,7 @@ e.destruct() assert t.get_overload("getCount").call(None, None) == 0 - def testPassingOfAnObjectByPointer(self): + def test08_pass_object_by_pointer(self): """Test passing of an instance as an argument.""" import cppyy @@ -203,7 +203,7 @@ pl.destruct() assert t1.get_overload("getCount").call(None, None) == 0 - def testReturningOfAnObjectByPointer(self): + def test09_return_object_by_pointer(self): """Test returning of an instance as an argument.""" import cppyy From noreply at buildbot.pypy.org Mon Jul 18 21:46:36 2011 From: noreply at buildbot.pypy.org (wlav) Date: Mon, 18 Jul 2011 21:46:36 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: make CINT back-end work for test_cppyy Message-ID: <20110718194636.A1C00829B8@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45723:d7afd561c4f6 Date: 2011-07-18 12:46 -0700 http://bitbucket.org/pypy/pypy/changeset/d7afd561c4f6/ Log: make CINT back-end work for test_cppyy diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -429,6 +429,7 @@ argtype = capi.charp2str_free(capi.c_method_arg_type(self.handle, method_index, i)) argtypes.append(argtype) if capi.c_is_constructor(self.handle, method_index): + result_type = "void" # b/c otherwise CINT v.s. Reflex difference cls = CPPConstructor elif capi.c_is_staticmethod(self.handle, method_index): cls = CPPFunction diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx --- a/pypy/module/cppyy/src/cintcwrapper.cxx +++ b/pypy/module/cppyy/src/cintcwrapper.cxx @@ -21,6 +21,9 @@ #include +/* CINT internal (won't work on Windwos) -------------------------------- */ +extern long G__store_struct_offset; + /* data for life time management ------------------------------------------ */ typedef std::vector ClassRefs_t; static ClassRefs_t g_classrefs(1); @@ -91,15 +94,19 @@ G__param* libp = (G__param*)((char*)args - offsetof(G__param, para)); assert(libp->paran == numargs); - long obj = (long)cppyy_allocate(rettype); - G__setgvp(obj); + // TODO: access to store_struct_offset won't work on Windows + G__setgvp((long)self); + long store_struct_offset = G__store_struct_offset; + G__store_struct_offset = (long)self; G__value result; G__setnull(&result); meth(&result, 0, libp, 0); + G__store_struct_offset = store_struct_offset; + // G__pop_tempobject_nodel(); # TODO: not sure ... - return obj; + return G__int(result); } static inline G__value cppyy_call_T(cppyy_typehandle_t handle, @@ -111,10 +118,17 @@ G__param* libp = (G__param*)((char*)args - offsetof(G__param, para)); assert(libp->paran == numargs); + // TODO: access to store_struct_offset won't work on Windows + G__setgvp((long)self); + long store_struct_offset = G__store_struct_offset; + G__store_struct_offset = (long)self; + G__value result; G__setnull(&result); meth(&result, 0, libp, 0); - + + G__store_struct_offset = store_struct_offset; + return result; } @@ -261,8 +275,7 @@ char* cppyy_method_result_type(cppyy_typehandle_t handle, int method_index) { TClassRef cr = type_from_handle(handle); TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index); - std::string name = TClassEdit::CleanType(m->GetReturnTypeName(), 1); - return type_cppstring_to_cstring(name); + return type_cppstring_to_cstring(m->GetReturnTypeName()); } int cppyy_method_num_args(cppyy_typehandle_t handle, int method_index) { From noreply at buildbot.pypy.org Mon Jul 18 23:32:57 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 18 Jul 2011 23:32:57 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Added microinstructions for boxing and unboxing integers Message-ID: <20110718213257.55DD3829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45724:ebe84b0f0660 Date: 2011-07-18 14:19 -0700 http://bitbucket.org/pypy/pypy/changeset/ebe84b0f0660/ Log: Added microinstructions for boxing and unboxing integers diff --git a/pypy/translator/jvm/typesystem.py b/pypy/translator/jvm/typesystem.py --- a/pypy/translator/jvm/typesystem.py +++ b/pypy/translator/jvm/typesystem.py @@ -963,6 +963,8 @@ PYPYRUNTIMENEW = Method.s(jPyPy, 'RuntimeNew', (jClass,), jObject) PYPYSTRING2BYTES = Method.s(jPyPy, 'string2bytes', (jString,), jByteArray) PYPYARRAYTOLIST = Method.s(jPyPy, 'array_to_list', (jObjectArray,), jArrayList) +PYPYBOXINT = Method.s(jPyPy, 'box_integer', (jInt,), jIntegerClass) +PYPYUNBOXINT = Method.s(jPyPy, 'unbox_integer', (jIntegerClass,), jInt) PYPYOOPARSEFLOAT = Method.v(jPyPy, 'ooparse_float', (jString,), jDouble) OBJECTGETCLASS = Method.v(jObject, 'getClass', (), jClass) CLASSGETNAME = Method.v(jClass, 'getName', (), jString) From noreply at buildbot.pypy.org Mon Jul 18 23:32:58 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 18 Jul 2011 23:32:58 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Added opcodes to list. Message-ID: <20110718213258.8D761829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45725:bdc008c4d87c Date: 2011-07-18 14:20 -0700 http://bitbucket.org/pypy/pypy/changeset/bdc008c4d87c/ Log: Added opcodes to list. diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -77,6 +77,8 @@ 'oosend': [JvmCallMethod, StoreResult], 'ooupcast': DoNothing, 'oodowncast': [DownCast, StoreResult], + 'oobox_int': jvm.PYPYBOXINT, + 'oounbox_int': jvm.PYPYUNBOXINT, 'cast_to_object': DoNothing, 'cast_from_object': [DownCast, StoreResult], 'instanceof': [CastTo, StoreResult], From noreply at buildbot.pypy.org Mon Jul 18 23:32:59 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 18 Jul 2011 23:32:59 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Actually implemented the opcodes. Message-ID: <20110718213259.B7530829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45726:87e475193302 Date: 2011-07-18 14:20 -0700 http://bitbucket.org/pypy/pypy/changeset/87e475193302/ Log: Actually implemented the opcodes. diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -307,6 +307,14 @@ return result; } + public static Object box_integer(int x) { + return new Integer(x); + } + + public static int unbox_integer(Object o) { + Integer x = (Integer)o; + return x.intValue(); + } // Used in testing the JVM backend: // // A series of methods which serve a similar purpose to repr() in Python: From noreply at buildbot.pypy.org Mon Jul 18 23:33:00 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 18 Jul 2011 23:33:00 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Accept i_force_non_null option, currently ignore it. Message-ID: <20110718213300.DEF85829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45727:96d4be71cc26 Date: 2011-07-18 14:22 -0700 http://bitbucket.org/pypy/pypy/changeset/96d4be71cc26/ Log: Accept i_force_non_null option, currently ignore it. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -255,7 +255,7 @@ methodname = None return fn, v_obj, methodname -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): from pypy.rlib import jit r_dict = hop.r_result From noreply at buildbot.pypy.org Mon Jul 18 23:33:02 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 18 Jul 2011 23:33:02 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Implement rerased and create test for ootype. One (unmarked) xfail currently. Message-ID: <20110718213302.1342D829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45728:428c4305ccd4 Date: 2011-07-18 14:25 -0700 http://bitbucket.org/pypy/pypy/changeset/428c4305ccd4/ Log: Implement rerased and create test for ootype. One (unmarked) xfail currently. diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py --- a/pypy/rlib/rerased.py +++ b/pypy/rlib/rerased.py @@ -113,7 +113,7 @@ if hop.r_result.lowleveltype is lltype.Void: return hop.inputconst(lltype.Void, None) [v] = hop.inputargs(hop.args_r[0]) - return hop.genop('cast_opaque_ptr', [v], resulttype = hop.r_result) + return hop.args_r[0].rtype_unerase(hop, v) return erase, unerase @@ -147,7 +147,7 @@ def specialize_call(self, hop): [v] = hop.inputargs(hop.args_r[0]) assert isinstance(hop.s_result, annmodel.SomeInteger) - return hop.gendirectcall(ll_unerase_int, v) + return hop.args_r[0].rtype_unerase_int(hop, v) def ll_unerase_int(gcref): from pypy.rpython.lltypesystem.lloperation import llop @@ -174,7 +174,10 @@ return False # cannot be None, but can contain a None def rtyper_makerepr(self, rtyper): - return ErasedRepr(rtyper) + if rtyper.type_system.name == 'lltypesystem': + return ErasedRepr(rtyper) + elif rtyper.type_system.name == 'ootypesystem': + return OOErasedRepr(rtyper) def rtyper_makekey(self): return self.__class__, @@ -200,6 +203,13 @@ return hop.genop('cast_opaque_ptr', [v_obj], resulttype=self.lowleveltype) + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_opaque_ptr', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + return hop.gendirectcall(ll_unerase_int, v) + def rtype_erase_int(self, hop): [v_value] = hop.inputargs(lltype.Signed) c_one = hop.inputconst(lltype.Signed, 1) @@ -224,3 +234,50 @@ return lltype.nullptr(self.lowleveltype.TO) v = r_obj.convert_const(value._x) return lltype.cast_opaque_ptr(self.lowleveltype, v) + +from pypy.rpython.ootypesystem import ootype + +class OOErasedRepr(Repr): + lowleveltype = ootype.Object + def __init__(self, rtyper): + self.rtyper = rtyper + + def rtype_erase(self, hop, s_obj): + hop.exception_cannot_occur() + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return hop.inputconst(self.lowleveltype, + ootype.NULL) + [v_obj] = hop.inputargs(r_obj) + return hop.genop('cast_to_object', [v_obj], + resulttype=self.lowleveltype) + + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_from_object', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('oounbox_int', [v], resulttype=hop.r_result) + return hop.genop('int_rshift', [v2, c_one], resulttype=lltype.Signed) + + def rtype_erase_int(self, hop): + hop.exception_is_here() + [v_value] = hop.inputargs(lltype.Signed) + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('int_lshift_ovf', [v_value, c_one], + resulttype = lltype.Signed) + v2p1 = hop.genop('int_add', [v2, c_one], + resulttype = lltype.Signed) + return hop.genop('oobox_int', [v2p1], resulttype=hop.r_result) + + def convert_const(self, value): + if value._identity is _identity_for_ints: + return value._x # FIXME: what should we do here? + bk = self.rtyper.annotator.bookkeeper + s_obj = value._identity.get_input_annotation(bk) + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return ootype.NULL + v = r_obj.convert_const(value._x) + return ootype.cast_to_object(v) From noreply at buildbot.pypy.org Mon Jul 18 23:33:03 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 18 Jul 2011 23:33:03 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Tests which were missing from previous commit. Message-ID: <20110718213303.3CBBD829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45729:b2db2a3ba4a3 Date: 2011-07-18 14:26 -0700 http://bitbucket.org/pypy/pypy/changeset/b2db2a3ba4a3/ Log: Tests which were missing from previous commit. diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py --- a/pypy/rlib/test/test_rerased.py +++ b/pypy/rlib/test/test_rerased.py @@ -5,8 +5,10 @@ from pypy.annotation.annrpython import RPythonAnnotator from pypy.rpython.test.test_llinterp import interpret from pypy.rpython.lltypesystem.rclass import OBJECTPTR +from pypy.rpython.ootypesystem.rclass import OBJECT from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin class X(object): pass @@ -79,136 +81,6 @@ s = a.build_types(f, []) assert isinstance(s, annmodel.SomeInteger) -def test_rtype_1(): - def f(): - return eraseX(X()) - x = interpret(f, []) - assert lltype.typeOf(x) == llmemory.GCREF - -def test_rtype_2(): - def f(): - x1 = X() - e = eraseX(x1) - #assert not is_integer(e) - x2 = uneraseX(e) - return x2 - x = interpret(f, []) - assert lltype.castable(OBJECTPTR, lltype.typeOf(x)) > 0 - -def test_rtype_3(): - def f(): - e = erase_int(16) - #assert is_integer(e) - x2 = unerase_int(e) - return x2 - x = interpret(f, []) - assert x == 16 - - -def test_prebuilt_erased(): - e1 = erase_int(16) - x1 = X() - x1.foobar = 42 - e2 = eraseX(x1) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = unerase_int(e1) + uneraseX(e2).foobar - return x2 - x = interpret(f, []) - assert x == 16 + 42 + 1 - -def test_prebuilt_erased_in_instance(): - erase_empty, unerase_empty = new_erasing_pair("empty") - class FakeList(object): - pass - - x1 = X() - x1.foobar = 42 - l1 = FakeList() - l1.storage = eraseX(x1) - l2 = FakeList() - l2.storage = erase_empty(None) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) - return x2 - x = interpret(f, []) - assert x == 43 + True - - -def test_overflow(): - def f(i): - try: - e = erase_int(i) - except OverflowError: - return -1 - #assert is_integer(e) - return unerase_int(e) - x = interpret(f, [16]) - assert x == 16 - x = interpret(f, [sys.maxint]) - assert x == -1 - -def test_none(): - def foo(): - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - # - def foo(): - eraseX(X()) - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - -def test_union(): - s_e1 = SomeErased() - s_e1.const = 1 - s_e2 = SomeErased() - s_e2.const = 3 - assert not annmodel.pair(s_e1, s_e2).union().is_constant() - - -def test_rtype_list(): - prebuilt_l = [X()] - prebuilt_e = erase_list_X(prebuilt_l) - def l(flag): - if flag == 1: - l = [X()] - e = erase_list_X(l) - elif flag == 2: - l = prebuilt_l - e = erase_list_X(l) - else: - l = prebuilt_l - e = prebuilt_e - #assert is_integer(e) is False - assert unerase_list_X(e) is l - interpret(l, [0]) - interpret(l, [1]) - interpret(l, [2]) - -# ____________________________________________________________ - -def test_erasing_pair(): - erase, unerase = new_erasing_pair("test1") - class X: - pass - x = X() - erased = erase(x) - assert unerase(erased) is x - # - erase2, unerase2 = new_erasing_pair("test2") - py.test.raises(AssertionError, unerase2, erased) - def test_annotate_erasing_pair(): erase, unerase = new_erasing_pair("test1") erase2, unerase2 = new_erasing_pair("test2") @@ -296,3 +168,143 @@ a = RPythonAnnotator() s = a.build_types(f, [int]) assert isinstance(s, annmodel.SomeInteger) + +class BaseTestRErased(BaseRtypingTest): + def test_rtype_1(self): + def f(): + return eraseX(X()) + x = self.interpret(f, []) + assert lltype.typeOf(x) == self.ERASED_TYPE + + def test_rtype_2(self): + def f(): + x1 = X() + e = eraseX(x1) + #assert not is_integer(e) + x2 = uneraseX(e) + return x2 + x = self.interpret(f, []) + assert self.castable(self.UNERASED_TYPE, x) + + def test_rtype_3(self): + def f(): + e = erase_int(16) + #assert is_integer(e) + x2 = unerase_int(e) + return x2 + x = self.interpret(f, []) + assert x == 16 + + def test_prebuilt_erased(self): + e1 = erase_int(16) + x1 = X() + x1.foobar = 42 + e2 = eraseX(x1) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = unerase_int(e1) + uneraseX(e2).foobar + return x2 + x = self.interpret(f, []) + assert x == 16 + 42 + 1 + + def test_prebuilt_erased_in_instance(self): + erase_empty, unerase_empty = new_erasing_pair("empty") + class FakeList(object): + pass + + x1 = X() + x1.foobar = 42 + l1 = FakeList() + l1.storage = eraseX(x1) + l2 = FakeList() + l2.storage = erase_empty(None) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) + return x2 + x = self.interpret(f, []) + assert x == 43 + True + + def test_overflow(self): + def f(i): + try: + e = erase_int(i) + except OverflowError: + return -1 + #assert is_integer(e) + return unerase_int(e) + x = self.interpret(f, [16]) + assert x == 16 + x = self.interpret(f, [sys.maxint]) + assert x == -1 + + def test_none(self): + def foo(): + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + # + def foo(): + eraseX(X()) + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + + def test_rtype_list(self): + prebuilt_l = [X()] + prebuilt_e = erase_list_X(prebuilt_l) + def l(flag): + if flag == 1: + l = [X()] + e = erase_list_X(l) + elif flag == 2: + l = prebuilt_l + e = erase_list_X(l) + else: + l = prebuilt_l + e = prebuilt_e + #assert is_integer(e) is False + assert unerase_list_X(e) is l + self.interpret(l, [0]) + self.interpret(l, [1]) + self.interpret(l, [2]) + +class TestLLtype(BaseTestRErased, LLRtypeMixin): + ERASED_TYPE = llmemory.GCREF + UNERASED_TYPE = OBJECTPTR + def castable(self, TO, var): + return lltype.castable(TO, lltype.typeOf(var)) > 0 + +class TestOOtype(BaseTestRErased, OORtypeMixin): + ERASED_TYPE = Object + UNERASED_TYPE = OBJECT + def castable(self, TO, var): + return ootype.isSubclass(lltype.typeOf(var), TO) + +def test_union(): + s_e1 = SomeErased() + s_e1.const = 1 + s_e2 = SomeErased() + s_e2.const = 3 + assert not annmodel.pair(s_e1, s_e2).union().is_constant() + +# ____________________________________________________________ + +def test_erasing_pair(): + erase, unerase = new_erasing_pair("test1") + class X: + pass + x = X() + erased = erase(x) + assert unerase(erased) is x + # + erase2, unerase2 = new_erasing_pair("test2") + py.test.raises(AssertionError, unerase2, erased) From noreply at buildbot.pypy.org Mon Jul 18 23:33:04 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 18 Jul 2011 23:33:04 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Implement version for llinterp. Message-ID: <20110718213304.67E6B829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45730:c455e9b2ae16 Date: 2011-07-18 14:28 -0700 http://bitbucket.org/pypy/pypy/changeset/c455e9b2ae16/ Log: Implement version for llinterp. diff --git a/pypy/rpython/ootypesystem/ooopimpl.py b/pypy/rpython/ootypesystem/ooopimpl.py --- a/pypy/rpython/ootypesystem/ooopimpl.py +++ b/pypy/rpython/ootypesystem/ooopimpl.py @@ -3,7 +3,6 @@ # ____________________________________________________________ # Implementation of the 'canfold' oo operations - def op_ooupcast(INST, inst): return ootype.ooupcast(INST, inst) op_ooupcast.need_result_type = True diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -1928,6 +1928,19 @@ assert typeOf(obj) is Object return obj._cast_to(EXPECTED_TYPE) +class Box(_object): + def __init__(self, i): + self._TYPE = Object + self.i = i + +def oobox_int(i): + return Box(i) +oobox_int.need_result_type = True + +def oounbox_int(x): + return x.i +oounbox_int.need_result_type = True + def oostring(obj, base): """ Convert char, int, float, instances and str to str. From noreply at buildbot.pypy.org Mon Jul 18 23:33:05 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 18 Jul 2011 23:33:05 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Add to llinterp. Message-ID: <20110718213305.92D4E829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45731:63f10ae57971 Date: 2011-07-18 14:28 -0700 http://bitbucket.org/pypy/pypy/changeset/63f10ae57971/ Log: Add to llinterp. diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -1225,6 +1225,12 @@ except ValueError: self.make_llexception() + def op_oobox_int(self, i): + return ootype.oobox_int(i) + + def op_oounbox_int(self, x): + return ootype.oounbox_int(x) + class Tracer(object): Counter = 0 file = None From noreply at buildbot.pypy.org Tue Jul 19 00:14:00 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 19 Jul 2011 00:14:00 +0200 (CEST) Subject: [pypy-commit] pypy release-gil-flush-heapcache: (fijal, alex) a failing JIT test. Message-ID: <20110718221400.436AA829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: release-gil-flush-heapcache Changeset: r45732:01554c7acfbe Date: 2011-07-18 15:12 -0700 http://bitbucket.org/pypy/pypy/changeset/01554c7acfbe/ Log: (fijal, alex) a failing JIT test. diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2061,7 +2061,7 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if 0 < a <= 5: pass if 0 < b <= 5: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa @@ -2071,10 +2071,10 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa - + assert self.meta_interp(f1, [5, 5]) == 50 self.check_loops(int_rshift=0, everywhere=True) @@ -2106,7 +2106,7 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if -5 <= a < 0: pass if 0 < b <= 5: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa @@ -2116,10 +2116,10 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa - + assert self.meta_interp(f1, [-5, 5]) == -50 self.check_loops(int_rshift=0, everywhere=True) @@ -2190,7 +2190,7 @@ def get_printable_location(i): return str(i) - + myjitdriver = JitDriver(greens = ['i'], reds = ['j', 'c', 'a'], get_printable_location=get_printable_location) bytecode = "0j10jc20a3" @@ -2299,7 +2299,7 @@ assert self.meta_interp(build, []) == 7 self.check_loops(getfield_gc_pure=0) self.check_loops(getfield_gc_pure=2, everywhere=True) - + def test_frame_finished_during_retrace(self): class Base(object): pass @@ -2330,7 +2330,7 @@ return sa res = self.meta_interp(f, []) assert res == f() - + def test_frame_finished_during_continued_retrace(self): class Base(object): pass @@ -2414,12 +2414,12 @@ def g(n1, n2): for i in range(10): f(n1) - for i in range(10): + for i in range(10): f(n2) nn = [10, 3] assert self.meta_interp(g, nn) == g(*nn) - + # The attempts of retracing first loop will end up retracing the # second and thus fail 5 times, saturating the retrace_count. Instead a # bridge back to the preamble of the first loop is produced. A guard in @@ -2430,7 +2430,7 @@ self.check_tree_loop_count(2 + 3) # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. - + def g(n): for i in range(n): for j in range(10): @@ -2619,5 +2619,40 @@ self.meta_interp(f, [], enable_opts='') self.check_loops(new_with_vtable=1) + def test_release_gil_flush_heap_cache(self): + from pypy.rpython.lltypesystem import rffi + + T = rffi.CArrayPtr(rffi.TIME_T) + + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + # Not a real lock, has all the same properties with respect to GIL + # release though, so good for this test. + class Lock(object): + @dont_look_inside + def acquire(self): + external(lltype.nullptr(T.TO)) + @dont_look_inside + def release(self): + external(lltype.nullptr(T.TO)) + @dont_look_inside + def get_lst(): + return [0] + myjitdriver = JitDriver(greens=[], reds=["n", "l", "lock"]) + def f(n): + lock = Lock() + l = 0 + while n > 0: + myjitdriver.jit_merge_point(lock=lock, l=l, n=n) + x = get_lst() + l += len(x) + lock.acquire() + # This must not reuse the previous one. + n -= len(x) + lock.release() + return n + res = self.meta_interp(f, [10]) + self.check_loops(arraylen_gc=2) + + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass From noreply at buildbot.pypy.org Tue Jul 19 02:24:34 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 19 Jul 2011 02:24:34 +0200 (CEST) Subject: [pypy-commit] pypy release-gil-flush-heapcache: Added a can release GIL analyzer to codewriter, use it. This still doesn't fix the original JIT test and I can't figure out why, I don't know what actually caches the arraylen_gc. Message-ID: <20110719002434.4B0AF829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: release-gil-flush-heapcache Changeset: r45733:16efefdef73e Date: 2011-07-18 17:24 -0700 http://bitbucket.org/pypy/pypy/changeset/16efefdef73e/ Log: Added a can release GIL analyzer to codewriter, use it. This still doesn't fix the original JIT test and I can't figure out why, I don't know what actually caches the arraylen_gc. diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -5,10 +5,9 @@ from pypy.jit.codewriter import support from pypy.jit.codewriter.jitcode import JitCode -from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer -from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer -from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze -from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection +from pypy.jit.codewriter.effectinfo import (VirtualizableAnalyzer, + QuasiImmutAnalyzer, CanReleaseGILAnalyzer, effectinfo_from_writeanalyze, + EffectInfo, CallInfoCollection) from pypy.translator.simplify import get_funcobj, get_functype from pypy.rpython.lltypesystem import lltype, llmemory from pypy.translator.backendopt.canraise import RaiseAnalyzer @@ -32,6 +31,7 @@ self.readwrite_analyzer = ReadWriteAnalyzer(translator) self.virtualizable_analyzer = VirtualizableAnalyzer(translator) self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator) + self.canreleasegil_analyzer = CanReleaseGILAnalyzer(translator) # for index, jd in enumerate(jitdrivers_sd): jd.index = index @@ -219,7 +219,9 @@ assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect - can_invalidate = self.quasiimmut_analyzer.analyze(op) + can_release_gil = self.canreleasegil_analyzer.analyze(op) + # can_release_gil implies can_invalidate + can_invalidate = can_release_gil or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE @@ -235,7 +237,7 @@ # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, - oopspecindex, can_invalidate) + oopspecindex, can_invalidate, can_release_gil) # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -79,13 +79,15 @@ write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, - can_invalidate=False): + can_invalidate=False, can_release_gil=False): key = (frozenset(readonly_descrs_fields), frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, - oopspecindex) + oopspecindex, + can_invalidate, + can_release_gil) if key in cls._cache: return cls._cache[key] result = object.__new__(cls) @@ -100,6 +102,7 @@ result.write_descrs_arrays = write_descrs_arrays result.extraeffect = extraeffect result.can_invalidate = can_invalidate + result.can_release_gil = can_release_gil result.oopspecindex = oopspecindex cls._cache[key] = result return result @@ -111,12 +114,13 @@ return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE def has_random_effects(self): - return self.oopspecindex == self.OS_LIBFFI_CALL + return self.oopspecindex == self.OS_LIBFFI_CALL or self.can_release_gil def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, - can_invalidate=False): + can_invalidate=False, + can_release_gil=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: return None @@ -158,7 +162,8 @@ write_descrs_arrays, extraeffect, oopspecindex, - can_invalidate) + can_invalidate, + can_release_gil) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: @@ -194,6 +199,16 @@ def analyze_simple_operation(self, op, graphinfo): return op.opname == 'jit_force_quasi_immutable' +class CanReleaseGILAnalyzer(BoolGraphAnalyzer): + def analyze_direct_call(self, graph, seen=None): + releases_gil = False + if hasattr(graph.func, "_ptr"): + releases_gil = graph.func._ptr._obj.releases_gil + return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen) + + def analyze_simple_operation(self, op, graphinfo): + return False + # ____________________________________________________________ class CallInfoCollection(object): diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -185,7 +185,7 @@ return llop.int_floordiv(lltype.Signed, x, y) def _ll_2_int_floordiv_ovf(x, y): - if x == -sys.maxint - 1 and y == -1: + if x == -sys.maxint - 1 and y == -1: raise OverflowError return llop.int_floordiv(lltype.Signed, x, y) @@ -222,7 +222,7 @@ return -x else: return x - + # math support # ------------ diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py --- a/pypy/jit/codewriter/test/test_call.py +++ b/pypy/jit/codewriter/test/test_call.py @@ -1,6 +1,6 @@ import py from pypy.objspace.flow.model import SpaceOperation, Constant, Variable -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.unsimplify import varoftype from pypy.rlib import jit from pypy.jit.codewriter.call import CallControl @@ -103,7 +103,7 @@ op = SpaceOperation('direct_call', [Constant(object())], Variable()) - assert cc.guess_call_kind(op) == 'residual' + assert cc.guess_call_kind(op) == 'residual' class funcptr: class graph: @@ -118,7 +118,7 @@ op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) - assert res == [g] + assert res == [g] assert cc.guess_call_kind(op) == 'regular' class funcptr: @@ -126,7 +126,7 @@ op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) - assert res is None + assert res is None assert cc.guess_call_kind(op) == 'residual' h = object() @@ -142,7 +142,7 @@ Variable()) res = cc.graphs_from(op) assert res is None - assert cc.guess_call_kind(op) == 'residual' + assert cc.guess_call_kind(op) == 'residual' # ____________________________________________________________ @@ -171,3 +171,24 @@ def test_jit_force_virtualizable_effectinfo(): py.test.skip("XXX add a test for CallControl.getcalldescr() -> EF_xxx") + +def test_releases_gil_analyzer(): + from pypy.jit.backend.llgraph.runner import LLtypeCPU + + T = rffi.CArrayPtr(rffi.TIME_T) + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + + @jit.dont_look_inside + def f(): + return external(lltype.nullptr(T.TO)) + + rtyper = support.annotate(f, []) + jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) + cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) + res = cc.find_all_graphs(FakePolicy()) + + [f_graph] = [x for x in res if x.func is f] + [block, _] = list(f_graph.iterblocks()) + [op] = block.operations + call_descr = cc.getcalldescr(op) + assert call_descr.extrainfo.can_release_gil \ No newline at end of file diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -11,7 +11,7 @@ from pypy import conftest from pypy.rlib.rarithmetic import ovfcheck from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -1616,8 +1616,6 @@ assert res == 1 def test_raw_malloc_and_access(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Signed) def f(n): @@ -1631,8 +1629,6 @@ assert res == 10 def test_raw_malloc_and_access_float(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Float) def f(n, f): @@ -2620,8 +2616,6 @@ self.check_loops(new_with_vtable=1) def test_release_gil_flush_heap_cache(self): - from pypy.rpython.lltypesystem import rffi - T = rffi.CArrayPtr(rffi.TIME_T) external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -102,19 +102,6 @@ else: callbackholder = None - funcptr = lltype.functionptr(ext_type, name, external='C', - compilation_info=compilation_info, - _callable=_callable, - _safe_not_sandboxed=sandboxsafe, - _debugexc=True, # on top of llinterp - canraise=False, - **kwds) - if isinstance(_callable, ll2ctypes.LL2CtypesCallable): - _callable.funcptr = funcptr - - if _nowrapper: - return funcptr - if threadsafe in (False, True): # invoke the around-handlers, which release the GIL, if and only if # the C function is thread-safe. @@ -125,6 +112,21 @@ # sandboxsafe is a hint for "too-small-ness" (e.g. math functions). invoke_around_handlers = not sandboxsafe + funcptr = lltype.functionptr(ext_type, name, external='C', + compilation_info=compilation_info, + _callable=_callable, + _safe_not_sandboxed=sandboxsafe, + _debugexc=True, # on top of llinterp + canraise=False, + releases_gil=invoke_around_handlers, + **kwds) + if isinstance(_callable, ll2ctypes.LL2CtypesCallable): + _callable.funcptr = funcptr + + if _nowrapper: + return funcptr + + if invoke_around_handlers: # The around-handlers are releasing the GIL in a threaded pypy. # We need tons of care to ensure that no GC operation and no From noreply at buildbot.pypy.org Tue Jul 19 02:55:18 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 19 Jul 2011 02:55:18 +0200 (CEST) Subject: [pypy-commit] pypy release-gil-flush-heapcache: It didn't work because array's have a fixed length and the JIT is very smart. Rewrite the test to ues an attribute (could have also used a non-fixed-size array), it fails before this patch and passes afterwords. Message-ID: <20110719005518.9C03A829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: release-gil-flush-heapcache Changeset: r45734:ce8caa1e35db Date: 2011-07-18 17:55 -0700 http://bitbucket.org/pypy/pypy/changeset/ce8caa1e35db/ Log: It didn't work because array's have a fixed length and the JIT is very smart. Rewrite the test to ues an attribute (could have also used a non-fixed-size array), it fails before this patch and passes afterwords. diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -61,7 +61,6 @@ optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble, retraced) - if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2628,24 +2628,27 @@ @dont_look_inside def release(self): external(lltype.nullptr(T.TO)) + class X(object): + def __init__(self, idx): + self.field = idx @dont_look_inside - def get_lst(): - return [0] - myjitdriver = JitDriver(greens=[], reds=["n", "l", "lock"]) - def f(n): + def get_obj(z): + return X(z) + myjitdriver = JitDriver(greens=[], reds=["n", "l", "z", "lock"]) + def f(n, z): lock = Lock() l = 0 while n > 0: - myjitdriver.jit_merge_point(lock=lock, l=l, n=n) - x = get_lst() - l += len(x) + myjitdriver.jit_merge_point(lock=lock, l=l, n=n, z=z) + x = get_obj(z) + l += x.field lock.acquire() # This must not reuse the previous one. - n -= len(x) + n -= x.field lock.release() return n - res = self.meta_interp(f, [10]) - self.check_loops(arraylen_gc=2) + res = self.meta_interp(f, [10, 1]) + self.check_loops(getfield_gc=2) class TestLLtype(BaseLLtypeTests, LLJitMixin): From noreply at buildbot.pypy.org Tue Jul 19 04:29:28 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 19 Jul 2011 04:29:28 +0200 (CEST) Subject: [pypy-commit] pypy release-gil-flush-heapcache: Fix for translation, not everything has a func (why? I don't know). With this patch it actually seems to fix my deadlock. I get some other weird error though. Somehow that seems better. Message-ID: <20110719022928.25113829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: release-gil-flush-heapcache Changeset: r45735:e4e34dd540f5 Date: 2011-07-18 19:29 -0700 http://bitbucket.org/pypy/pypy/changeset/e4e34dd540f5/ Log: Fix for translation, not everything has a func (why? I don't know). With this patch it actually seems to fix my deadlock. I get some other weird error though. Somehow that seems better. diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -202,7 +202,7 @@ class CanReleaseGILAnalyzer(BoolGraphAnalyzer): def analyze_direct_call(self, graph, seen=None): releases_gil = False - if hasattr(graph.func, "_ptr"): + if hasattr(graph, "func") and hasattr(graph.func, "_ptr"): releases_gil = graph.func._ptr._obj.releases_gil return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen) From noreply at buildbot.pypy.org Tue Jul 19 11:55:01 2011 From: noreply at buildbot.pypy.org (wlav) Date: Tue, 19 Jul 2011 11:55:01 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: enable global and now mode for dlopen Message-ID: <20110719095501.ABD22829B8@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45736:fce0d480d104 Date: 2011-07-19 02:54 -0700 http://bitbucket.org/pypy/pypy/changeset/fce0d480d104/ Log: enable global and now mode for dlopen diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -18,8 +18,8 @@ NULL_VOIDP = lltype.nullptr(rffi.VOIDP.TO) def load_lib(space, name): - # TODO: allow open in RTLD_GLOBAL mode - cdll = libffi.CDLL(name) #, 0x100 | 0x02) + # TODO: the following uses a hacked CDLL that won't work on Windows + cdll = libffi.CDLL(name, 0x100 | 0x02) return W_CPPLibrary(space, cdll) load_lib.unwrap_spec = [ObjSpace, str] diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -419,11 +419,11 @@ # XXX: it partially duplicate the code in clibffi.py class CDLL(object): - def __init__(self, libname): + def __init__(self, libname, mode=-1): """Load the library, or raises DLOpenError.""" self.lib = rffi.cast(DLLHANDLE, 0) with rffi.scoped_str2charp(libname) as ll_libname: - self.lib = dlopen(ll_libname) + self.lib = dlopen(ll_libname, mode) def __del__(self): if self.lib: From noreply at buildbot.pypy.org Tue Jul 19 12:24:20 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 19 Jul 2011 12:24:20 +0200 (CEST) Subject: [pypy-commit] buildbot default: ignore whitespace when doing the diff Message-ID: <20110719102420.79E69829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r534:c620633ed570 Date: 2011-07-19 12:24 +0200 http://bitbucket.org/pypy/buildbot/changeset/c620633ed570/ Log: ignore whitespace when doing the diff diff --git a/bbhook/scm.py b/bbhook/scm.py --- a/bbhook/scm.py +++ b/bbhook/scm.py @@ -20,7 +20,7 @@ def get_diff(local_repo, hgid): - out = hg('-R', local_repo, 'diff', '--git', '-c', hgid) + out = hg('-R', local_repo, 'diff', '-b', '--git', '-c', hgid) out = out.splitlines(True) out_iter = iter(out) lines = [] From noreply at buildbot.pypy.org Tue Jul 19 12:24:31 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 19 Jul 2011 12:24:31 +0200 (CEST) Subject: [pypy-commit] pypy default: (fijal, alex_gaynor) merge release-gil-flush-heapcache Message-ID: <20110719102431.3154E829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45737:10d2740f6ab6 Date: 2011-07-19 12:24 +0200 http://bitbucket.org/pypy/pypy/changeset/10d2740f6ab6/ Log: (fijal, alex_gaynor) merge release-gil-flush-heapcache diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -5,10 +5,9 @@ from pypy.jit.codewriter import support from pypy.jit.codewriter.jitcode import JitCode -from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer -from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer -from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze -from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection +from pypy.jit.codewriter.effectinfo import (VirtualizableAnalyzer, + QuasiImmutAnalyzer, CanReleaseGILAnalyzer, effectinfo_from_writeanalyze, + EffectInfo, CallInfoCollection) from pypy.translator.simplify import get_funcobj, get_functype from pypy.rpython.lltypesystem import lltype, llmemory from pypy.translator.backendopt.canraise import RaiseAnalyzer @@ -32,6 +31,7 @@ self.readwrite_analyzer = ReadWriteAnalyzer(translator) self.virtualizable_analyzer = VirtualizableAnalyzer(translator) self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator) + self.canreleasegil_analyzer = CanReleaseGILAnalyzer(translator) # for index, jd in enumerate(jitdrivers_sd): jd.index = index @@ -219,7 +219,9 @@ assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect - can_invalidate = self.quasiimmut_analyzer.analyze(op) + can_release_gil = self.canreleasegil_analyzer.analyze(op) + # can_release_gil implies can_invalidate + can_invalidate = can_release_gil or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE @@ -235,7 +237,7 @@ # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, - oopspecindex, can_invalidate) + oopspecindex, can_invalidate, can_release_gil) # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -79,13 +79,15 @@ write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, - can_invalidate=False): + can_invalidate=False, can_release_gil=False): key = (frozenset(readonly_descrs_fields), frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, - oopspecindex) + oopspecindex, + can_invalidate, + can_release_gil) if key in cls._cache: return cls._cache[key] result = object.__new__(cls) @@ -100,6 +102,7 @@ result.write_descrs_arrays = write_descrs_arrays result.extraeffect = extraeffect result.can_invalidate = can_invalidate + result.can_release_gil = can_release_gil result.oopspecindex = oopspecindex cls._cache[key] = result return result @@ -111,12 +114,13 @@ return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE def has_random_effects(self): - return self.oopspecindex == self.OS_LIBFFI_CALL + return self.oopspecindex == self.OS_LIBFFI_CALL or self.can_release_gil def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, - can_invalidate=False): + can_invalidate=False, + can_release_gil=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: return None @@ -158,7 +162,8 @@ write_descrs_arrays, extraeffect, oopspecindex, - can_invalidate) + can_invalidate, + can_release_gil) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: @@ -194,6 +199,16 @@ def analyze_simple_operation(self, op, graphinfo): return op.opname == 'jit_force_quasi_immutable' +class CanReleaseGILAnalyzer(BoolGraphAnalyzer): + def analyze_direct_call(self, graph, seen=None): + releases_gil = False + if hasattr(graph, "func") and hasattr(graph.func, "_ptr"): + releases_gil = graph.func._ptr._obj.releases_gil + return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen) + + def analyze_simple_operation(self, op, graphinfo): + return False + # ____________________________________________________________ class CallInfoCollection(object): diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -185,7 +185,7 @@ return llop.int_floordiv(lltype.Signed, x, y) def _ll_2_int_floordiv_ovf(x, y): - if x == -sys.maxint - 1 and y == -1: + if x == -sys.maxint - 1 and y == -1: raise OverflowError return llop.int_floordiv(lltype.Signed, x, y) @@ -222,7 +222,7 @@ return -x else: return x - + # math support # ------------ diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py --- a/pypy/jit/codewriter/test/test_call.py +++ b/pypy/jit/codewriter/test/test_call.py @@ -1,6 +1,6 @@ import py from pypy.objspace.flow.model import SpaceOperation, Constant, Variable -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.unsimplify import varoftype from pypy.rlib import jit from pypy.jit.codewriter.call import CallControl @@ -103,7 +103,7 @@ op = SpaceOperation('direct_call', [Constant(object())], Variable()) - assert cc.guess_call_kind(op) == 'residual' + assert cc.guess_call_kind(op) == 'residual' class funcptr: class graph: @@ -118,7 +118,7 @@ op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) - assert res == [g] + assert res == [g] assert cc.guess_call_kind(op) == 'regular' class funcptr: @@ -126,7 +126,7 @@ op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) - assert res is None + assert res is None assert cc.guess_call_kind(op) == 'residual' h = object() @@ -142,7 +142,7 @@ Variable()) res = cc.graphs_from(op) assert res is None - assert cc.guess_call_kind(op) == 'residual' + assert cc.guess_call_kind(op) == 'residual' # ____________________________________________________________ @@ -171,3 +171,24 @@ def test_jit_force_virtualizable_effectinfo(): py.test.skip("XXX add a test for CallControl.getcalldescr() -> EF_xxx") + +def test_releases_gil_analyzer(): + from pypy.jit.backend.llgraph.runner import LLtypeCPU + + T = rffi.CArrayPtr(rffi.TIME_T) + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + + @jit.dont_look_inside + def f(): + return external(lltype.nullptr(T.TO)) + + rtyper = support.annotate(f, []) + jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) + cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) + res = cc.find_all_graphs(FakePolicy()) + + [f_graph] = [x for x in res if x.func is f] + [block, _] = list(f_graph.iterblocks()) + [op] = block.operations + call_descr = cc.getcalldescr(op) + assert call_descr.extrainfo.can_release_gil \ No newline at end of file diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -61,7 +61,6 @@ optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble, retraced) - if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -11,7 +11,7 @@ from pypy import conftest from pypy.rlib.rarithmetic import ovfcheck from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -1616,8 +1616,6 @@ assert res == 1 def test_raw_malloc_and_access(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Signed) def f(n): @@ -1631,8 +1629,6 @@ assert res == 10 def test_raw_malloc_and_access_float(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Float) def f(n, f): @@ -2061,7 +2057,7 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if 0 < a <= 5: pass if 0 < b <= 5: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa @@ -2071,10 +2067,10 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa - + assert self.meta_interp(f1, [5, 5]) == 50 self.check_loops(int_rshift=0, everywhere=True) @@ -2106,7 +2102,7 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if -5 <= a < 0: pass if 0 < b <= 5: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa @@ -2116,10 +2112,10 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa - + assert self.meta_interp(f1, [-5, 5]) == -50 self.check_loops(int_rshift=0, everywhere=True) @@ -2190,7 +2186,7 @@ def get_printable_location(i): return str(i) - + myjitdriver = JitDriver(greens = ['i'], reds = ['j', 'c', 'a'], get_printable_location=get_printable_location) bytecode = "0j10jc20a3" @@ -2299,7 +2295,7 @@ assert self.meta_interp(build, []) == 7 self.check_loops(getfield_gc_pure=0) self.check_loops(getfield_gc_pure=2, everywhere=True) - + def test_frame_finished_during_retrace(self): class Base(object): pass @@ -2330,7 +2326,7 @@ return sa res = self.meta_interp(f, []) assert res == f() - + def test_frame_finished_during_continued_retrace(self): class Base(object): pass @@ -2414,12 +2410,12 @@ def g(n1, n2): for i in range(10): f(n1) - for i in range(10): + for i in range(10): f(n2) nn = [10, 3] assert self.meta_interp(g, nn) == g(*nn) - + # The attempts of retracing first loop will end up retracing the # second and thus fail 5 times, saturating the retrace_count. Instead a # bridge back to the preamble of the first loop is produced. A guard in @@ -2430,7 +2426,7 @@ self.check_tree_loop_count(2 + 3) # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. - + def g(n): for i in range(n): for j in range(10): @@ -2619,5 +2615,41 @@ self.meta_interp(f, [], enable_opts='') self.check_loops(new_with_vtable=1) + def test_release_gil_flush_heap_cache(self): + T = rffi.CArrayPtr(rffi.TIME_T) + + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + # Not a real lock, has all the same properties with respect to GIL + # release though, so good for this test. + class Lock(object): + @dont_look_inside + def acquire(self): + external(lltype.nullptr(T.TO)) + @dont_look_inside + def release(self): + external(lltype.nullptr(T.TO)) + class X(object): + def __init__(self, idx): + self.field = idx + @dont_look_inside + def get_obj(z): + return X(z) + myjitdriver = JitDriver(greens=[], reds=["n", "l", "z", "lock"]) + def f(n, z): + lock = Lock() + l = 0 + while n > 0: + myjitdriver.jit_merge_point(lock=lock, l=l, n=n, z=z) + x = get_obj(z) + l += x.field + lock.acquire() + # This must not reuse the previous one. + n -= x.field + lock.release() + return n + res = self.meta_interp(f, [10, 1]) + self.check_loops(getfield_gc=2) + + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -102,19 +102,6 @@ else: callbackholder = None - funcptr = lltype.functionptr(ext_type, name, external='C', - compilation_info=compilation_info, - _callable=_callable, - _safe_not_sandboxed=sandboxsafe, - _debugexc=True, # on top of llinterp - canraise=False, - **kwds) - if isinstance(_callable, ll2ctypes.LL2CtypesCallable): - _callable.funcptr = funcptr - - if _nowrapper: - return funcptr - if threadsafe in (False, True): # invoke the around-handlers, which release the GIL, if and only if # the C function is thread-safe. @@ -125,6 +112,21 @@ # sandboxsafe is a hint for "too-small-ness" (e.g. math functions). invoke_around_handlers = not sandboxsafe + funcptr = lltype.functionptr(ext_type, name, external='C', + compilation_info=compilation_info, + _callable=_callable, + _safe_not_sandboxed=sandboxsafe, + _debugexc=True, # on top of llinterp + canraise=False, + releases_gil=invoke_around_handlers, + **kwds) + if isinstance(_callable, ll2ctypes.LL2CtypesCallable): + _callable.funcptr = funcptr + + if _nowrapper: + return funcptr + + if invoke_around_handlers: # The around-handlers are releasing the GIL in a threaded pypy. # We need tons of care to ensure that no GC operation and no From noreply at buildbot.pypy.org Tue Jul 19 12:24:32 2011 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 19 Jul 2011 12:24:32 +0200 (CEST) Subject: [pypy-commit] pypy release-gil-flush-heapcache: close merged branch Message-ID: <20110719102432.594F3829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: release-gil-flush-heapcache Changeset: r45738:995cbdd4ffa1 Date: 2011-07-19 12:24 +0200 http://bitbucket.org/pypy/pypy/changeset/995cbdd4ffa1/ Log: close merged branch From noreply at buildbot.pypy.org Tue Jul 19 18:44:16 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 19 Jul 2011 18:44:16 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: a branch in which to develop a dict strategy for user instances which use the default by-identity comparison Message-ID: <20110719164416.E3706829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45739:4de5eefc2d61 Date: 2011-07-19 14:38 +0200 http://bitbucket.org/pypy/pypy/changeset/4de5eefc2d61/ Log: a branch in which to develop a dict strategy for user instances which use the default by-identity comparison From noreply at buildbot.pypy.org Tue Jul 19 18:44:18 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 19 Jul 2011 18:44:18 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: add a way to check whether a type has custom versions of __eq__, __hash__ or __cmp__ Message-ID: <20110719164418.27D31829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45740:a2ad83608b4b Date: 2011-07-19 17:02 +0200 http://bitbucket.org/pypy/pypy/changeset/a2ad83608b4b/ Log: add a way to check whether a type has custom versions of __eq__, __hash__ or __cmp__ diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -327,6 +327,9 @@ BoolOption("mutable_builtintypes", "Allow the changing of builtin types", default=False, requires=[("objspace.std.builtinshortcut", True)]), + BoolOption("trackcomparebyidentity", + "track types that override __hash__, __eq__ or __cmp__", + default=True), ]), ]) diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -28,6 +28,13 @@ return w_delattr object_delattr._annspecialcase_ = 'specialize:memo' +def object_hash(space): + "Utility that returns the app-level descriptor object.__hash__." + w_src, w_hash = space.lookup_in_type_where(space.w_object, + '__hash__') + return w_hash +object_hash._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): w_type = space.type(w_obj) typename = w_type.getname(space) diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1199,3 +1199,37 @@ return x + 1 a = A() assert a.f(1) == 2 + + +class AppTestTrackCompareByIdentity: + + def setup_class(cls): + cls.space = gettestobjspace( + **{"objspace.std.trackcomparebyidentity": True}) + + def compares_by_identity(space, w_cls): + return space.wrap(w_cls.compares_by_identity()) + + cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) + + def test_compares_by_identity(self): + class Plain(object): + pass + + class CustomEq(object): + def __eq__(self, other): + return True + + class CustomCmp (object): + def __cmp__(self, other): + return 0 + + class CustomHash(object): + def __hash__(self): + return 0 + + + assert self.compares_by_identity(Plain) + assert not self.compares_by_identity(CustomEq) + assert not self.compares_by_identity(CustomCmp) + assert not self.compares_by_identity(CustomHash) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -102,6 +102,10 @@ # (False is a conservative default, fixed during real usage) uses_object_getattribute = False + # for config.objspace.std.trackcomparebyidentity + # (True is a conservative default, fixed during real usage) + overrides_hash_eq_or_cmp = True + # used to cache the type __new__ function if it comes from a builtin type # != 'type', in that case call__Type will also assumes the result # of the __new__ is an instance of the type @@ -207,6 +211,21 @@ def has_object_getattribute(w_self): return w_self.getattribute_if_not_from_object() is None + def compares_by_identity(w_self): + from pypy.objspace.descroperation import object_hash + track = w_self.space.config.objspace.std.trackcomparebyidentity + if not track: + return False # conservative + # + if not w_self.overrides_hash_eq_or_cmp: + return True # fast path + # + default_hash = object_hash(w_self.space) + w_self.overrides_hash_eq_or_cmp = (w_self.lookup('__eq__') or + w_self.lookup('__cmp__') or + w_self.lookup('__hash__') is not default_hash) + return not w_self.overrides_hash_eq_or_cmp + def ready(w_self): for w_base in w_self.bases_w: if not isinstance(w_base, W_TypeObject): From noreply at buildbot.pypy.org Tue Jul 19 18:44:19 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 19 Jul 2011 18:44:19 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: invalidate the cache when the type is mutated Message-ID: <20110719164419.5CF63829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45741:62b65edc5a4b Date: 2011-07-19 17:09 +0200 http://bitbucket.org/pypy/pypy/changeset/62b65edc5a4b/ Log: invalidate the cache when the type is mutated diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1228,8 +1228,20 @@ def __hash__(self): return 0 - assert self.compares_by_identity(Plain) assert not self.compares_by_identity(CustomEq) assert not self.compares_by_identity(CustomCmp) assert not self.compares_by_identity(CustomHash) + + def test_modify_class(self): + def foo(self, *args): + pass + + class X(object): + pass + + assert self.compares_by_identity(X) + X.__eq__ = foo + assert not self.compares_by_identity(X) + del X.__eq__ + assert self.compares_by_identity(X) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -155,6 +155,7 @@ assert w_self.is_heaptype() or space.config.objspace.std.mutable_builtintypes if (not space.config.objspace.std.withtypeversion and not space.config.objspace.std.getattributeshortcut and + not space.config.objspace.std.trackcomparebyidentity and not space.config.objspace.std.newshortcut): return @@ -162,6 +163,10 @@ w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage + if space.config.objspace.std.trackcomparebyidentity: + w_self.overrides_hash_eq_or_cmp = True + # ^^^ conservative default, fixed during real usage + if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None From noreply at buildbot.pypy.org Tue Jul 19 18:44:20 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 19 Jul 2011 18:44:20 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: add an XXX Message-ID: <20110719164420.8991D829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45742:2f37e2d466b7 Date: 2011-07-19 17:15 +0200 http://bitbucket.org/pypy/pypy/changeset/2f37e2d466b7/ Log: add an XXX diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -225,6 +225,8 @@ if not w_self.overrides_hash_eq_or_cmp: return True # fast path # + # XXX: if the class *does* overrides, we always hit the slow path. Do + # we care? default_hash = object_hash(w_self.space) w_self.overrides_hash_eq_or_cmp = (w_self.lookup('__eq__') or w_self.lookup('__cmp__') or From noreply at buildbot.pypy.org Tue Jul 19 18:44:21 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 19 Jul 2011 18:44:21 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: implement a global version counter to track changes to classes that changed their compares_by_identity() status Message-ID: <20110719164421.BBF85829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45743:923f2db3961e Date: 2011-07-19 18:19 +0200 http://bitbucket.org/pypy/pypy/changeset/923f2db3961e/ Log: implement a global version counter to track changes to classes that changed their compares_by_identity() status diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -32,18 +32,19 @@ from pypy.objspace.std.smallintobject import W_SmallIntObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.typeobject import W_TypeObject +from pypy.objspace.std.typeobject import W_TypeObject, VersionTag # types from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.stringtype import wrapstr from pypy.objspace.std.unicodetype import wrapunicode - class StdObjSpace(ObjSpace, DescrOperation): """The standard object space, implementing a general-purpose object library in Restricted Python.""" + compares_by_identity_version = None + def initialize(self): "NOT_RPYTHON: only for initializing the space." # setup all the object types and implementations @@ -80,6 +81,15 @@ # the type of old-style classes self.w_classobj = self.builtin.get('__metaclass__') + # a global version counter to track live instances which "compare by + # identity" (i.e., whose __eq__, __cmp__ and __hash__ are the default + # ones). The idea is to track only classes for which we checked the + # compares_by_identity() status at least once: we increment the + # version if its status might change, e.g. because we set one of those + # attributes. The actual work is done by W_TypeObject.mutated() + if self.config.objspace.std.trackcomparebyidentity: + self.compares_by_identity_version = VersionTag() + # final setup self.setup_builtin_modules() # Adding transparent proxy call diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1209,8 +1209,13 @@ def compares_by_identity(space, w_cls): return space.wrap(w_cls.compares_by_identity()) + cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) - cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) + versions = {} + def get_version(space): + v = versions.setdefault(space.compares_by_identity_version, len(versions)) + return space.wrap(v) + cls.w_get_version = cls.space.wrap(interp2app(get_version)) def test_compares_by_identity(self): class Plain(object): @@ -1234,14 +1239,43 @@ assert not self.compares_by_identity(CustomHash) def test_modify_class(self): - def foo(self, *args): - pass - class X(object): pass assert self.compares_by_identity(X) - X.__eq__ = foo + X.__eq__ = lambda x: None assert not self.compares_by_identity(X) del X.__eq__ assert self.compares_by_identity(X) + + def test_versioning(self): + class X(object): + pass + + class Y(object): + def __eq__(self, other): + pass + + assert self.get_version() == 0 + X.__eq__ = lambda x: None + # modifying a class for which we never checked the + # compares_by_identity() status does not increase the version + assert self.get_version() == 0 + + del X.__eq__ + assert self.compares_by_identity(X) # now we check it + X.__add__ = lambda x: None + assert self.get_version() == 0 # innocent change + # + X.__eq__ = lambda x: None + assert self.get_version() == 1 # BUMP! + + del X.__eq__ + assert self.compares_by_identity(X) + X.__bases__ = (object,) + assert self.get_version() == 2 # BUMP! + + # modifying a class which is already "bad" does not increase the + # version + Y.__eq__ = lambda x: None + assert self.get_version() == 2 diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -150,7 +150,12 @@ else: w_self.terminator = NoDictTerminator(space, w_self) - def mutated(w_self): + def mutated(w_self, key): + """ + The type is being mutated. key is either the string containing the + specific attribute which is being deleted/set or None to indicate a + generic mutation. + """ space = w_self.space assert w_self.is_heaptype() or space.config.objspace.std.mutable_builtintypes if (not space.config.objspace.std.withtypeversion and @@ -164,8 +169,13 @@ # ^^^ conservative default, fixed during real usage if space.config.objspace.std.trackcomparebyidentity: + did_compare_by_identity = not w_self.overrides_hash_eq_or_cmp + if did_compare_by_identity and (key is None or + key == '__eq__' or + key == '__cmp__' or + key == '__hash__'): w_self.overrides_hash_eq_or_cmp = True - # ^^^ conservative default, fixed during real usage + w_self.space.compares_by_identity_version = VersionTag() if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None @@ -177,7 +187,7 @@ subclasses_w = w_self.get_subclasses() for w_subclass in subclasses_w: assert isinstance(w_subclass, W_TypeObject) - w_subclass.mutated() + w_subclass.mutated(key) def version_tag(w_self): if (not we_are_jitted() or w_self.is_heaptype() or @@ -295,7 +305,7 @@ w_curr.w_value = w_value return True w_value = TypeCell(w_value) - w_self.mutated() + w_self.mutated(name) w_self.dict_w[name] = w_value return True @@ -312,7 +322,7 @@ except KeyError: return False else: - w_self.mutated() + w_self.mutated(key) return True def lookup(w_self, name): diff --git a/pypy/objspace/std/typetype.py b/pypy/objspace/std/typetype.py --- a/pypy/objspace/std/typetype.py +++ b/pypy/objspace/std/typetype.py @@ -141,7 +141,7 @@ w_oldbestbase.getname(space)) # invalidate the version_tag of all the current subclasses - w_type.mutated() + w_type.mutated(None) # now we can go ahead and change 'w_type.bases_w' saved_bases_w = w_type.bases_w From noreply at buildbot.pypy.org Tue Jul 19 18:44:22 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 19 Jul 2011 18:44:22 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: update the global version counter if we change the class of an object whose old class was tracked as compares_by_identity Message-ID: <20110719164422.EE420829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45744:6a28c75d117e Date: 2011-07-19 18:30 +0200 http://bitbucket.org/pypy/pypy/changeset/6a28c75d117e/ Log: update the global version counter if we change the class of an object whose old class was tracked as compares_by_identity diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -43,6 +43,9 @@ assert isinstance(w_oldcls, W_TypeObject) if w_oldcls.get_full_instance_layout() == w_newcls.get_full_instance_layout(): w_obj.setclass(space, w_newcls) + if space.config.objspace.std.trackcomparebyidentity: + if not w_oldcls.overrides_hash_eq_or_cmp and not w_newcls.compares_by_identity(): + space.bump_compares_by_identity_version() else: raise operationerrfmt(space.w_TypeError, "__class__ assignment: '%s' object layout differs from '%s'", diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -43,6 +43,13 @@ """The standard object space, implementing a general-purpose object library in Restricted Python.""" + # a global version counter to track live instances which "compare by + # identity" (i.e., whose __eq__, __cmp__ and __hash__ are the default + # ones). The idea is to track only classes for which we checked the + # compares_by_identity() status at least once: we increment the version if + # its status might change, e.g. because we set one of those attributes. + # The actual work is done by W_TypeObject.mutated() and + # objecttype:descr_setclass compares_by_identity_version = None def initialize(self): @@ -81,14 +88,8 @@ # the type of old-style classes self.w_classobj = self.builtin.get('__metaclass__') - # a global version counter to track live instances which "compare by - # identity" (i.e., whose __eq__, __cmp__ and __hash__ are the default - # ones). The idea is to track only classes for which we checked the - # compares_by_identity() status at least once: we increment the - # version if its status might change, e.g. because we set one of those - # attributes. The actual work is done by W_TypeObject.mutated() if self.config.objspace.std.trackcomparebyidentity: - self.compares_by_identity_version = VersionTag() + self.bump_compares_by_identity_version() # final setup self.setup_builtin_modules() @@ -579,3 +580,6 @@ if isinstance(w_sub, W_TypeObject) and isinstance(w_type, W_TypeObject): return self.wrap(w_sub.issubtype(w_type)) raise OperationError(self.w_TypeError, self.wrap("need type objects")) + + def bump_compares_by_identity_version(self): + self.compares_by_identity_version = VersionTag() diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1279,3 +1279,22 @@ # version Y.__eq__ = lambda x: None assert self.get_version() == 2 + + def test_change___class__(self): + class X(object): + pass + + class Y(object): + pass + + class Z(object): + def __eq__(self, other): + pass + + x = X() + assert self.compares_by_identity(X) + assert self.get_version() == 0 + x.__class__ = Y + assert self.get_version() == 0 + x.__class__ = Z + assert self.get_version() == 1 diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -175,7 +175,7 @@ key == '__cmp__' or key == '__hash__'): w_self.overrides_hash_eq_or_cmp = True - w_self.space.compares_by_identity_version = VersionTag() + w_self.space.bump_compares_by_identity_version() if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None From noreply at buildbot.pypy.org Tue Jul 19 18:44:24 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 19 Jul 2011 18:44:24 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: reset the version numbers after each test Message-ID: <20110719164424.24C64829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45745:78d8ec2a9f71 Date: 2011-07-19 18:32 +0200 http://bitbucket.org/pypy/pypy/changeset/78d8ec2a9f71/ Log: reset the version numbers after each test diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1211,12 +1211,15 @@ return space.wrap(w_cls.compares_by_identity()) cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) - versions = {} def get_version(space): - v = versions.setdefault(space.compares_by_identity_version, len(versions)) + v = cls.versions.setdefault(space.compares_by_identity_version, + len(cls.versions)) return space.wrap(v) cls.w_get_version = cls.space.wrap(interp2app(get_version)) + def setup_method(self, m): + self.__class__.versions = {} + def test_compares_by_identity(self): class Plain(object): pass From noreply at buildbot.pypy.org Tue Jul 19 18:44:25 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 19 Jul 2011 18:44:25 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: use an enum instead of a bool to keep track of the comparse_by_identiy status; this way, we can cache also the False case Message-ID: <20110719164425.5860F829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45746:f99a873a003f Date: 2011-07-19 18:43 +0200 http://bitbucket.org/pypy/pypy/changeset/f99a873a003f/ Log: use an enum instead of a bool to keep track of the comparse_by_identiy status; this way, we can cache also the False case diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -44,7 +44,7 @@ if w_oldcls.get_full_instance_layout() == w_newcls.get_full_instance_layout(): w_obj.setclass(space, w_newcls) if space.config.objspace.std.trackcomparebyidentity: - if not w_oldcls.overrides_hash_eq_or_cmp and not w_newcls.compares_by_identity(): + if w_oldcls.compares_by_identity() and not w_newcls.compares_by_identity(): space.bump_compares_by_identity_version() else: raise operationerrfmt(space.w_TypeError, diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -76,6 +76,10 @@ for i in range(len(self.lookup_where)): self.lookup_where[i] = None_None +# possible values of compares_by_identity_status +UNKNOWN = 0 +COMPARES_BY_IDENTITY = 1 +OVERRIDES_EQ_CMP_OR_HASH = 2 class W_TypeObject(W_Object): from pypy.objspace.std.typetype import type_typedef as typedef @@ -103,8 +107,7 @@ uses_object_getattribute = False # for config.objspace.std.trackcomparebyidentity - # (True is a conservative default, fixed during real usage) - overrides_hash_eq_or_cmp = True + compares_by_identity_status = UNKNOWN # used to cache the type __new__ function if it comes from a builtin type # != 'type', in that case call__Type will also assumes the result @@ -169,12 +172,12 @@ # ^^^ conservative default, fixed during real usage if space.config.objspace.std.trackcomparebyidentity: - did_compare_by_identity = not w_self.overrides_hash_eq_or_cmp - if did_compare_by_identity and (key is None or - key == '__eq__' or - key == '__cmp__' or - key == '__hash__'): - w_self.overrides_hash_eq_or_cmp = True + did_compare_by_identity = ( + w_self.compares_by_identity_status == COMPARES_BY_IDENTITY) + if (key is None or key == '__eq__' or + key == '__cmp__' or key == '__hash__'): + w_self.compares_by_identity_status = UNKNOWN + if did_compare_by_identity: w_self.space.bump_compares_by_identity_version() if space.config.objspace.std.newshortcut: @@ -232,16 +235,19 @@ if not track: return False # conservative # - if not w_self.overrides_hash_eq_or_cmp: - return True # fast path + if w_self.compares_by_identity_status != UNKNOWN: + # fast path + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY # - # XXX: if the class *does* overrides, we always hit the slow path. Do - # we care? default_hash = object_hash(w_self.space) - w_self.overrides_hash_eq_or_cmp = (w_self.lookup('__eq__') or + overrides_eq_cmp_or_hash = (w_self.lookup('__eq__') or w_self.lookup('__cmp__') or w_self.lookup('__hash__') is not default_hash) - return not w_self.overrides_hash_eq_or_cmp + if overrides_eq_cmp_or_hash: + w_self.compares_by_identity_status = OVERRIDES_EQ_CMP_OR_HASH + else: + w_self.compares_by_identity_status = COMPARES_BY_IDENTITY + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY def ready(w_self): for w_base in w_self.bases_w: From noreply at buildbot.pypy.org Tue Jul 19 20:06:45 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Tue, 19 Jul 2011 20:06:45 +0200 (CEST) Subject: [pypy-commit] pypy numpy-setslice: Fixed setslice and added extra tests for slice of slice. Everything appears to be working for setting slices. Message-ID: <20110719180646.01051829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: numpy-setslice Changeset: r45747:818b17e123de Date: 2011-07-18 18:15 -0600 http://bitbucket.org/pypy/pypy/changeset/818b17e123de/ Log: Fixed setslice and added extra tests for slice of slice. Everything appears to be working for setting slices. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -402,7 +402,6 @@ BaseArray.__init__(self) self.signature = signature self.parent = parent - self.storage = parent.storage self.invalidates = parent.invalidates def get_concrete(self): @@ -436,17 +435,20 @@ if isinstance(parent, SingleDimSlice): self.start = parent.calc_index(start) self.stop = parent.calc_index(stop) - self.step = parent.step * self.step + self.step = parent.step * step + self.parent = parent.parent else: self.start = start self.stop = stop self.step = step + self.parent = parent self.size = slice_length def find_size(self): return self.size def _sliceloop1(self, start, stop, step, arr): + storage = self.parent.storage signature = Signature() new_sig = self.signature.transition(signature) i = start @@ -454,11 +456,12 @@ while i < stop: slice_driver1.jit_merge_point(signature=signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) - self.storage[i] = arr.eval(j) + storage[i] = arr.eval(j) j += 1 i += step def _sliceloop2(self, start, stop, step, arr): + storage = self.parent.storage signature = Signature() new_sig = self.signature.transition(signature) i = start @@ -466,7 +469,7 @@ while i > stop: slice_driver2.jit_merge_point(signature=signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) - self.storage[i] = arr.eval(j) + storage[i] = arr.eval(j) j += 1 i += step @@ -553,12 +556,6 @@ def setslice(self, space, start, stop, step, slice_length, arr): i = start - #if stop < 0: - # stop += self.find_size() - #if step > 0: - # stop = min(stop, self.find_size()) - #else: - # stop = max(stop, 0) if not isinstance(arr, BaseArray): arr = convert_to_array(space, arr) if step > 0: diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -67,16 +67,25 @@ a[1:4:2] = b assert a[1] == 0. assert a[3] == 1. + + def test_setslice_of_slice_array(self): + from numpy import array, zeros + a = zeros(5) a[::2] = array([9., 10., 11.]) assert a[0] == 9. assert a[2] == 10. assert a[4] == 11. - a[1:4:2][::-1] = b + a[1:4:2][::-1] = array([1., 2.]) assert a[0] == 9. - assert a[1] == 1. + assert a[1] == 2. assert a[2] == 10. - assert a[3] == 0. + assert a[3] == 1. assert a[4] == 11. + a = zeros(10) + a[::2][::-1][::2] = array(range(1,4)) + a[8] = 1. + a[4] = 2. + a[0] = 3. def test_setslice_list(self): from numpy import array From noreply at buildbot.pypy.org Tue Jul 19 21:20:39 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 19 Jul 2011 21:20:39 +0200 (CEST) Subject: [pypy-commit] pypy default: Kill some duplicate code (thanks to Zain Memon for spotting the log duplication). Message-ID: <20110719192039.834BE829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45748:625c07c3be9d Date: 2011-07-19 12:20 -0700 http://bitbucket.org/pypy/pypy/changeset/625c07c3be9d/ Log: Kill some duplicate code (thanks to Zain Memon for spotting the log duplication). diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -395,7 +395,7 @@ ('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed), ('int_abs', [lltype.Signed], lltype.Signed), ('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float), - ] +] class LLtypeHelpers: diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -69,8 +69,6 @@ [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) -math_log = llexternal('log', [rffi.DOUBLE], rffi.DOUBLE) -math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -222,10 +220,6 @@ return (fracpart, intpart) -def ll_math_copysign(x, y): - return math_copysign(x, y) # no error checking needed - - def ll_math_fmod(x, y): if isinf(y): if isinf(x): From noreply at buildbot.pypy.org Tue Jul 19 21:50:32 2011 From: noreply at buildbot.pypy.org (ademan) Date: Tue, 19 Jul 2011 21:50:32 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: merge default. Message-ID: <20110719195032.DBE61829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45749:2029d76c7884 Date: 2011-07-19 12:35 -0700 http://bitbucket.org/pypy/pypy/changeset/2029d76c7884/ Log: merge default. diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -185,6 +185,7 @@ Jim Baker Philip Jenvey Rodrigo Araújo + Brett Cannon Heinrich-Heine University, Germany Open End AB (formerly AB Strakt), Sweden diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -48,7 +48,8 @@ return self.from_param(as_parameter) def get_ffi_param(self, value): - return self.from_param(value)._to_ffi_param() + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() def get_ffi_argtype(self): if self._ffiargtype: @@ -139,7 +140,10 @@ return buffer(self._buffer) def _get_b_base(self): + try: return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -218,5 +222,7 @@ 'z' : _ffi.types.void_p, 'O' : _ffi.types.void_p, 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, } diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -322,20 +322,20 @@ RuntimeWarning, stacklevel=2) if self._com_index: - assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None - - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -343,6 +343,11 @@ if not outargs: return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + if len(outargs) == 1: return outargs[0] return tuple(outargs) @@ -398,10 +403,10 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) cdll = self.dll._handle try: @@ -434,16 +439,15 @@ @classmethod def _conv_param(cls, argtype, arg): if isinstance(argtype, _CDataMeta): - #arg = argtype.from_param(arg) - arg = argtype.get_ffi_param(arg) - return arg, argtype + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - return arg._to_ffi_param(), type(arg) + return arg, arg._to_ffi_param(), type(arg) # # non-usual case: we do the import here to save a lot of code in the # jit trace of the normal case @@ -460,18 +464,15 @@ else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj._to_ffi_param(), type(cobj) + return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] + keepalives = [] newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: inargs_idx = 0 if not paramflags and total < len(argtypes): @@ -496,7 +497,8 @@ val = defval if val is marker: val = 0 - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): @@ -512,28 +514,32 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - newarg, newargtype = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) + keepalive = None newarg = ctypes.byref(val) newargtype = type(newarg) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - newarg, newargtype = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) inargs_idx += 1 @@ -542,12 +548,13 @@ extra = args[len(newargs):] for i, arg in enumerate(extra): try: - newarg, newargtype = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) - return newargs, newargtypes, outargs + return keepalives, newargs, newargtypes, outargs def _wrap_result(self, restype, result): @@ -587,13 +594,7 @@ retval = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, argsandobjs[0]) - else: - retval = int(resbuffer[0]) - elif restype is not None: + if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) @@ -601,6 +602,12 @@ # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -216,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -29,7 +29,7 @@ PythonPickler.__init__(self, *args, **kw) def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): diff --git a/pypy/config/config.py b/pypy/config/config.py --- a/pypy/config/config.py +++ b/pypy/config/config.py @@ -81,6 +81,12 @@ (self.__class__, name)) return self._cfgimpl_values[name] + def __dir__(self): + from_type = dir(type(self)) + from_dict = list(self.__dict__) + extras = list(self._cfgimpl_values) + return sorted(set(extras + from_type + from_dict)) + def __delattr__(self, name): # XXX if you use delattr you are responsible for all bad things # happening diff --git a/pypy/config/test/test_config.py b/pypy/config/test/test_config.py --- a/pypy/config/test/test_config.py +++ b/pypy/config/test/test_config.py @@ -63,6 +63,20 @@ py.test.raises(ConfigError, 'config.gc.name = "ref"') config.gc.name = "framework" +def test___dir__(): + descr = make_description() + config = Config(descr, bool=False) + attrs = dir(config) + assert '__repr__' in attrs # from the type + assert '_cfgimpl_values' in attrs # from self + assert 'gc' in attrs # custom attribute + assert 'objspace' in attrs # custom attribute + # + attrs = dir(config.gc) + assert 'name' in attrs + assert 'dummy' in attrs + assert 'float' in attrs + def test_arbitrary_option(): descr = OptionDescription("top", "", [ ArbitraryOption("a", "no help", default=None) diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -140,7 +140,10 @@ ["annotate", "rtype", "backendopt", "database", "source", "pyjitpl"], default=None, cmdline="--fork-before"), - + BoolOption("dont_write_c_files", + "Make the C backend write everyting to /dev/null. " + + "Useful for benchmarking, so you don't actually involve the disk", + default=False, cmdline="--dont-write-c-files"), ArbitraryOption("instrumentctl", "internal", default=None), StrOption("output", "Output file name", cmdline="--output"), diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -19,12 +19,12 @@ section * Write them in pure python and use direct libffi low-level bindings, See - \_rawffi_ module description. + \_ffi_ module description. * Write them in RPython as mixedmodule_, using *rffi* as bindings. .. _ctypes: #CTypes -.. _\_rawffi: #LibFFI +.. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules CTypes @@ -42,41 +42,50 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. +ctypes call are optimized by the JIT and the resulting machine code contains a +direct call to the target C function. However, due to the very dynamic nature +of ctypes, some overhead over a bare C call is still present, in particular to +check/convert the types of the parameters. Moreover, even if most calls are +optimized, some cannot and thus need to follow the slow path, not optimized by +the JIT. + .. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure +.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html Pros ---- -Stable, CPython-compatible API +Stable, CPython-compatible API. Most calls are fast, optimized by JIT. Cons ---- -Only pure-python code (slow), problems with platform-dependency (although -we partially solve those). PyPy implementation is now very slow. +Problems with platform-dependency (although we partially solve +those). Although the JIT optimizes ctypes calls, some overhead is still +present. The slow-path is very slow. -_`CPython ctypes`: http://python.net/crew/theller/ctypes/ LibFFI ====== Mostly in order to be able to write a ctypes module, we developed a very -low-level libffi bindings. (libffi is a C-level library for dynamic calling, +low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling, which is used by CPython ctypes). This library provides stable and usable API, although it's API is a very low-level one. It does not contain any -magic. +magic. It is also optimized by the JIT, but has much less overhead than ctypes. Pros ---- -Works. Combines disadvantages of using ctypes with disadvantages of -using mixed modules. Probably more suitable for a delicate code -where ctypes magic goes in a way. +It Works. Probably more suitable for a delicate code where ctypes magic goes +in a way. All calls are optimized by the JIT, there is no slow path as in +ctypes. Cons ---- -Slow. CPython-incompatible API, very rough and low-level +It combines disadvantages of using ctypes with disadvantages of using mixed +modules. CPython-incompatible API, very rough and low-level. Mixed Modules ============= @@ -87,15 +96,15 @@ * a mixed module needs to be written in RPython, which is far more complicated than Python (XXX link) -* due to lack of separate compilation (as of April 2008), each +* due to lack of separate compilation (as of July 2011), each compilation-check requires to recompile whole PyPy python interpreter, which takes 0.5-1h. We plan to solve this at some point in near future. * although rpython is a garbage-collected language, the border between C and RPython needs to be managed by hand (each object that goes into the - C level must be explicitly freed) XXX we try to solve this + C level must be explicitly freed). -Some document is available `here`_ +Some documentation is available `here`_ .. _`here`: rffi.html diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -26,13 +30,6 @@ Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ @@ -289,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -27,9 +27,10 @@ _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset) -def parse_future(tree): +def parse_future(tree, feature_flags): future_lineno = 0 future_column = 0 + flags = 0 have_docstring = False body = None if isinstance(tree, ast.Module): @@ -37,7 +38,7 @@ elif isinstance(tree, ast.Interactive): body = tree.body if body is None: - return 0, 0 + return 0, 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): if have_docstring: @@ -48,11 +49,16 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset + for alias in stmt.names: + assert isinstance(alias, ast.alias) + # If this is an invalid flag, it will be caught later in + # codegen.py. + flags |= feature_flags.get(alias.name, 0) else: break else: break - return future_lineno, future_column + return flags, future_lineno, future_column class ForbiddenNameAssignment(Exception): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): @@ -925,6 +927,9 @@ return self.w_True return self.w_False + def issequence_w(self, w_obj): + return (self.findattr(w_obj, self.wrap("__getitem__")) is not None) + def isinstance_w(self, w_obj, w_type): return self.is_true(self.isinstance(w_obj, w_type)) diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -396,11 +396,14 @@ fastfunc = func else: # try to avoid excessive bloat - if func.__module__ == 'pypy.interpreter.astcompiler.ast': + mod = func.__module__ + if mod is None: + mod = "" + if mod == 'pypy.interpreter.astcompiler.ast': raise FastFuncNotSupported - if (not func.__module__.startswith('pypy.module.__builtin__') and - not func.__module__.startswith('pypy.module.sys') and - not func.__module__.startswith('pypy.module.math')): + if (not mod.startswith('pypy.module.__builtin__') and + not mod.startswith('pypy.module.sys') and + not mod.startswith('pypy.module.math')): if not func.__name__.startswith('descr'): raise FastFuncNotSupported d = {} diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,10 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - future_pos = misc.parse_future(node) + fut = misc.parse_future(node, self.future_flags.compiler_features) + f_flags, f_lineno, f_col = fut + future_pos = f_lineno, f_col + flags |= f_flags info = pyparse.CompileInfo(filename, mode, flags, future_pos) return self._compile_ast(node, info) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -858,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -416,10 +416,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -478,9 +481,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d has address %x to %x" % + debug_start("jit-backend-addr") + debug_print("bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -464,7 +464,7 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ @@ -632,16 +632,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): @@ -44,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -58,10 +63,15 @@ expected = "\xE8" + struct.pack(' movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -765,13 +765,65 @@ raise NotImplementedError("cast_ptr_to_int") def rewrite_op_force_cast(self, op): - from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof + assert not self._is_gc(op.args[0]) + fromll = longlong.is_longlong(op.args[0].concretetype) + toll = longlong.is_longlong(op.result.concretetype) + if fromll and toll: + return + if fromll: + args = op.args + opname = 'truncate_longlong_to_int' + RESULT = lltype.Signed + v = varoftype(RESULT) + op1 = SpaceOperation(opname, args, v) + op2 = self.rewrite_operation(op1) + oplist = self.force_cast_without_longlong(op2.result, op.result) + if oplist: + return [op2] + oplist + # + # force a renaming to put the correct result in place, even though + # it might be slightly mistyped (e.g. Signed versus Unsigned) + assert op2.result is v + op2.result = op.result + return op2 + elif toll: + from pypy.rpython.lltypesystem import rffi + size, unsigned = rffi.size_and_sign(op.args[0].concretetype) + if unsigned: + INTERMEDIATE = lltype.Unsigned + else: + INTERMEDIATE = lltype.Signed + v = varoftype(INTERMEDIATE) + oplist = self.force_cast_without_longlong(op.args[0], v) + if not oplist: + v = op.args[0] + oplist = [] + if unsigned: + opname = 'cast_uint_to_longlong' + else: + opname = 'cast_int_to_longlong' + op1 = SpaceOperation(opname, [v], op.result) + op2 = self.rewrite_operation(op1) + return oplist + [op2] + else: + return self.force_cast_without_longlong(op.args[0], op.result) + + def force_cast_without_longlong(self, v_arg, v_result): + from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT from pypy.rlib.rarithmetic import intmask - assert not self._is_gc(op.args[0]) - size2, unsigned2 = size_and_sign(op.result.concretetype) - if size2 >= sizeof(lltype.Signed): + # + if (v_result.concretetype in (FLOAT, lltype.Float) or + v_arg.concretetype in (FLOAT, lltype.Float)): + assert (v_result.concretetype == lltype.Float and + v_arg.concretetype == lltype.Float), "xxx unsupported cast" + return + # + size2, unsigned2 = size_and_sign(v_result.concretetype) + assert size2 <= sizeof(lltype.Signed) + if size2 == sizeof(lltype.Signed): return # the target type is LONG or ULONG - size1, unsigned1 = size_and_sign(op.args[0].concretetype) + size1, unsigned1 = size_and_sign(v_arg.concretetype) + assert size1 <= sizeof(lltype.Signed) # def bounds(size, unsigned): if unsigned: @@ -784,22 +836,28 @@ return # the target type includes the source range # result = [] - v1 = op.args[0] if min2: c_min2 = Constant(min2, lltype.Signed) - v2 = Variable(); v2.concretetype = lltype.Signed - result.append(SpaceOperation('int_sub', [v1, c_min2], v2)) + v2 = varoftype(lltype.Signed) + result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2)) else: - v2 = v1 + v2 = v_arg c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed) - v3 = Variable(); v3.concretetype = lltype.Signed + v3 = varoftype(lltype.Signed) result.append(SpaceOperation('int_and', [v2, c_mask], v3)) if min2: - result.append(SpaceOperation('int_add', [v3, c_min2], op.result)) + result.append(SpaceOperation('int_add', [v3, c_min2], v_result)) else: - result[-1].result = op.result + result[-1].result = v_result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from @@ -883,30 +941,7 @@ rewrite_op_ullong_is_true = rewrite_op_llong_is_true def rewrite_op_cast_primitive(self, op): - fromll = longlong.is_longlong(op.args[0].concretetype) - toll = longlong.is_longlong(op.result.concretetype) - if fromll != toll: - args = op.args - if fromll: - opname = 'truncate_longlong_to_int' - RESULT = lltype.Signed - else: - from pypy.rpython.lltypesystem import rffi - if rffi.cast(op.args[0].concretetype, -1) < 0: - opname = 'cast_int_to_longlong' - else: - opname = 'cast_uint_to_longlong' - RESULT = lltype.SignedLongLong - v = varoftype(RESULT) - op1 = SpaceOperation(opname, args, v) - op2 = self.rewrite_operation(op1) - # - # force a renaming to put the correct result in place, even though - # it might be slightly mistyped (e.g. Signed versus Unsigned) - assert op2.result is v - op2.result = op.result - # - return op2 + return self.rewrite_op_force_cast(op) # ---------- # Renames, from the _old opname to the _new one. @@ -1083,6 +1118,9 @@ return meth(op, args, *descrs) def _get_list_nonneg_canraise_flags(self, op): + # XXX as far as I can see, this function will always return True + # because functions that are neither nonneg nor fast don't have an + # oopspec any more # xxx break of abstraction: func = get_funcobj(op.args[0].value)._callable # base hints on the name of the ll function, which is a bit xxx-ish @@ -1240,7 +1278,7 @@ calldescr = self.callcontrol.getcalldescr(op, oopspecindex, extraeffect) if extraeffect is not None: - assert (type(calldescr) is str # for tests + assert (is_test_calldescr(calldescr) # for tests or calldescr.get_extra_info().extraeffect == extraeffect) if isinstance(op.args[0].value, str): pass # for tests only @@ -1401,6 +1439,9 @@ return "using virtualizable array in illegal way in %r" % ( self.args[0],) +def is_test_calldescr(calldescr): + return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False) + def _with_prefix(prefix): result = {} for name in dir(Transformer): diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -96,6 +96,7 @@ def _try_coalesce(self, v, w): if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: + assert getkind(w.concretetype) == self.kind dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -3,6 +3,7 @@ from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register from pypy.jit.codewriter.format import assert_format +from pypy.jit.codewriter import longlong from pypy.jit.metainterp.history import AbstractDescr from pypy.rpython.lltypesystem import lltype, rclass, rstr from pypy.objspace.flow.model import SpaceOperation, Variable, Constant @@ -30,6 +31,9 @@ 'float': FakeRegAlloc()} class FakeDescr(AbstractDescr): + _for_tests_only = True + def __init__(self, oopspecindex=None): + self.oopspecindex = oopspecindex def __repr__(self): return '' def as_vtable_size_descr(self): @@ -55,19 +59,24 @@ def arraydescrof(self, ARRAY): return FakeDescr() +class FakeCallInfoCollection: + def add(self, *args): + pass + class FakeCallControl: _descr_cannot_raise = FakeDescr() + callinfocollection = FakeCallInfoCollection() def guess_call_kind(self, op): return 'residual' - def getcalldescr(self, op): + def getcalldescr(self, op, oopspecindex=None, extraeffect=None): try: if 'cannot_raise' in op.args[0].value._obj.graph.name: return self._descr_cannot_raise except AttributeError: pass - return FakeDescr() + return FakeDescr(oopspecindex) def calldescr_canraise(self, calldescr): - return calldescr is not self._descr_cannot_raise + return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None def get_vinfo(self, VTYPEPTR): return None @@ -734,7 +743,9 @@ def test_force_cast(self): from pypy.rpython.lltypesystem import rffi - + # NB: we don't need to test for INT here, the logic in jtransform is + # general enough so that if we have the below cases it should + # generalize also to INT for FROM, TO, expected in [ (rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""), (rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"), @@ -797,12 +808,42 @@ expected = [s.strip() for s in expected.splitlines()] check_force_cast(FROM, TO, expected, 42) check_force_cast(FROM, TO, expected, -42) - expected.append('int_return %i' + str(len(expected))) - expected = '\n'.join(expected) + returnvar = "%i" + str(len(expected)) + expected.append('int_return ' + returnvar) + expectedstr = '\n'.join(expected) # def f(n): return rffi.cast(TO, n) - self.encoding_test(f, [rffi.cast(FROM, 42)], expected, + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + + if not longlong.is_64_bit: + if FROM in (rffi.LONG, rffi.ULONG): + if FROM == rffi.LONG: + FROM = rffi.LONGLONG + else: + FROM = rffi.ULONGLONG + expected.insert(0, + "residual_call_irf_i $<* fn llong_to_int>, , I[], R[], F[%f0] -> %i0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + elif TO in (rffi.LONG, rffi.ULONG): + if TO == rffi.LONG: + TO = rffi.LONGLONG + else: + TO = rffi.ULONGLONG + if rffi.cast(FROM, -1) < 0: + fnname = "llong_from_int" + else: + fnname = "llong_from_uint" + expected.pop() # remove int_return + expected.append( + "residual_call_irf_f $<* fn %s>, , I[%s], R[], F[] -> %%f0" + % (fnname, returnvar)) + expected.append("float_return %f0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, transform=True) def test_force_cast_pointer(self): @@ -813,6 +854,23 @@ int_return %i0 """, transform=True) + def test_force_cast_float(self): + from pypy.rpython.lltypesystem import rffi + def f(n): + return rffi.cast(lltype.Float, n) + self.encoding_test(f, [12.456], """ + float_return %f0 + """, transform=True) + + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py --- a/pypy/jit/codewriter/test/test_longlong.py +++ b/pypy/jit/codewriter/test/test_longlong.py @@ -37,7 +37,7 @@ class TestLongLong: def setup_class(cls): - if sys.maxint > 2147483647: + if longlong.is_64_bit: py.test.skip("only for 32-bit platforms") def do_check(self, opname, oopspecindex, ARGS, RESULT): @@ -46,6 +46,8 @@ op = SpaceOperation(opname, vlist, v_result) tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) op1 = tr.rewrite_operation(op) + if isinstance(op1, list): + [op1] = op1 # def is_llf(TYPE): return (TYPE == lltype.SignedLongLong or @@ -196,6 +198,23 @@ for T2 in [lltype.Signed, lltype.Unsigned]: self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT, [T1], T2) + self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT, + [T1], T2) + if T2 == lltype.Signed: + expected = EffectInfo.OS_LLONG_FROM_INT + else: + expected = EffectInfo.OS_LLONG_FROM_UINT + self.do_check('cast_primitive', expected, [T2], T1) + self.do_check('force_cast', expected, [T2], T1) + # + for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + vlist = [varoftype(T1)] + v_result = varoftype(T2) + op = SpaceOperation('force_cast', vlist, v_result) + tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) + op1 = tr.rewrite_operation(op) + assert op1 is None def test_constants(self): for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]: diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -73,7 +73,7 @@ assert self._lazy_setfield is None self._cached_fields[structvalue] = fieldvalue - def force_lazy_setfield(self, optheap): + def force_lazy_setfield(self, optheap, can_cache=True): op = self._lazy_setfield if op is not None: # This is the way _lazy_setfield is usually reset to None. @@ -83,12 +83,16 @@ self._cached_fields.clear() self._lazy_setfield = None optheap.next_optimization.propagate_forward(op) + if not can_cache: + return # Once it is done, we can put at least one piece of information # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) + elif not can_cache: + self._cached_fields.clear() def get_reconstructed(self, optimizer, valuemap): assert self._lazy_setfield is None @@ -202,20 +206,9 @@ for arraydescr in effectinfo.readonly_descrs_arrays: self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: - self.force_lazy_setfield(fielddescr) - try: - cf = self.cached_fields[fielddescr] - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setfield(fielddescr, can_cache=False) for arraydescr in effectinfo.write_descrs_arrays: - self.force_lazy_setarrayitem(arraydescr) - try: - submap = self.cached_arrayitems[arraydescr] - for cf in submap.itervalues(): - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setarrayitem(arraydescr, can_cache=False) if effectinfo.check_forces_virtual_or_virtualizable(): vrefinfo = self.optimizer.metainterp_sd.virtualref_info self.force_lazy_setfield(vrefinfo.descr_forced) @@ -238,20 +231,20 @@ if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] - def force_lazy_setfield(self, descr): + def force_lazy_setfield(self, descr, can_cache=True): try: cf = self.cached_fields[descr] except KeyError: return - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) - def force_lazy_setarrayitem(self, arraydescr): + def force_lazy_setarrayitem(self, arraydescr, can_cache=True): try: submap = self.cached_arrayitems[arraydescr] except KeyError: return for cf in submap.values(): - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes @@ -387,7 +380,7 @@ cf.do_setfield(self, op) else: # variable index, so make sure the lazy setarrayitems are done - self.force_lazy_setarrayitem(op.getdescr()) + self.force_lazy_setarrayitem(op.getdescr(), can_cache=False) # and then emit the operation self.emit_operation(op) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -199,6 +199,7 @@ )) return self.emit_operation(op) + self.pure(rop.FLOAT_MUL, [arg2, arg1], op.result) def optimize_FLOAT_NEG(self, op): v1 = op.getarg(0) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1755,6 +1755,48 @@ """ self.optimize_loop(ops, expected) + def test_duplicate_getarrayitem_after_setarrayitem_bug(self): + ops = """ + [p0, i0, i1] + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i6 = int_add(i0, 1) + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + + def test_duplicate_getarrayitem_after_setarrayitem_bug2(self): + ops = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + def test_bug_1(self): ops = """ [i0, p1] @@ -3916,11 +3958,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3941,9 +3980,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3962,10 +3999,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -3987,14 +4023,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -4010,10 +4041,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4131,9 +4160,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -4178,11 +4205,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4374,11 +4398,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -4532,6 +4553,39 @@ """ self.optimize_loop(ops, expected) + def test_strslice_subtraction_folds(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + + def test_float_mul_reversed(self): + ops = """ + [f0, f1] + f2 = float_mul(f0, f1) + f3 = float_mul(f1, f0) + jump(f2, f3) + """ + expected = """ + [f0, f1] + f2 = float_mul(f0, f1) + jump(f2, f2) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5082,11 +5082,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5107,9 +5104,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5128,10 +5123,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5153,14 +5147,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -5176,10 +5165,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5303,9 +5290,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -5411,11 +5396,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5609,11 +5591,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -21,7 +21,7 @@ continue if hasattr(Class, name_prefix + name): opclass = resoperation.opclasses[getattr(rop, name)] - print value, name, opclass + assert name in opclass.__name__ result.append((value, opclass, getattr(Class, name_prefix + name))) return unrolling_iterable(result) diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -61,7 +61,7 @@ self.ensure_nonnull() box = self.force_box() lengthbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) + optimization.optimize_default(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -72,13 +72,13 @@ else: return None - def string_copy_parts(self, optimization, targetbox, offsetbox, mode): + def string_copy_parts(self, optimizer, targetbox, offsetbox, mode): # Copies the pointer-to-string 'self' into the target string # given by 'targetbox', at the specified offset. Returns the offset # at the end of the copy. - lengthbox = self.getstrlen(optimization, mode) + lengthbox = self.getstrlen(optimizer, mode) srcbox = self.force_box() - return copy_str_content(optimization, srcbox, targetbox, + return copy_str_content(optimizer, srcbox, targetbox, CONST_0, offsetbox, lengthbox, mode) @@ -335,7 +335,7 @@ if optimizer is None: return None resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_ADD, [box1, box2], resbox)) return resbox def _int_sub(optimizer, box1, box2): @@ -345,10 +345,10 @@ if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimization, strbox, indexbox, mode): +def _strgetitem(optimizer, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimizer.optimize_default(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,7 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) + resbox = _strgetitem(self.optimizer, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): @@ -450,7 +450,7 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode) + lengthbox = value.getstrlen(self.optimizer, mode) self.make_equal_to(op.result, self.getvalue(lengthbox)) def optimize_CALL(self, op): diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -310,26 +310,27 @@ self.opimpl_goto_if_not(condbox, target) ''' % (_opimpl, _opimpl.upper())).compile() + + def _establish_nullity(self, box, orgpc): + value = box.nonnull() + if value: + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc) + else: + if not isinstance(box, Const): + self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + promoted_box = box.constbox() + self.metainterp.replace_box(box, promoted_box) + return value + @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_nonzero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if not value: + if not self._establish_nullity(box, orgpc): self.pc = target @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_iszero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if value: + if self._establish_nullity(box, orgpc): self.pc = target @arguments("box", "box", "box") @@ -364,7 +365,9 @@ def opimpl_new_with_vtable(self, sizedescr): cpu = self.metainterp.cpu cls = heaptracker.descr2vtable(cpu, sizedescr) - return self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + resbox = self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + self.metainterp.known_class_boxes[resbox] = None + return resbox ## @FixME #arguments("box") ## def opimpl_runtimenew(self, classbox): @@ -593,12 +596,16 @@ standard_box = self.metainterp.virtualizable_boxes[-1] if standard_box is box: return False + if box in self.metainterp.nonstandard_virtualizables: + return True eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None, box, standard_box) eqbox = self.implement_guard_value(pc, eqbox) isstandard = eqbox.getint() if isstandard: self.metainterp.replace_box(box, standard_box) + else: + self.metainterp.nonstandard_virtualizables[box] = None return not isstandard def _get_virtualizable_field_index(self, fielddescr): @@ -845,7 +852,9 @@ @arguments("orgpc", "box") def opimpl_guard_class(self, orgpc, box): clsbox = self.cls_of_box(box) + if box not in self.metainterp.known_class_boxes: self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + self.metainterp.known_class_boxes[box] = None return clsbox @arguments("int", "orgpc") @@ -1449,6 +1458,10 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} + # contains frame boxes that are not virtualizables + self.nonstandard_virtualizables = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1789,6 +1802,9 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + self.nonstandard_virtualizables = {} # XXX maybe not needed? + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -281,9 +281,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -984,11 +984,14 @@ pass class B(A): pass + @dont_look_inside + def extern(n): + if n: + return A() + else: + return B() def fn(n): - if n: - obj = A() - else: - obj = B() + obj = extern(n) return isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res @@ -1021,6 +1024,70 @@ res = self.meta_interp(main, []) assert res == 55 + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass @@ -2314,7 +2381,7 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? - def test_retrace_ending_up_retrazing_another_loop(self): + def test_retrace_ending_up_retracing_another_loop(self): myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) bytecode = "0+sI0+SI" diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -1133,6 +1133,7 @@ res = self.meta_interp(f, [10]) assert res == 55 self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True) + self.check_history(ptr_eq=2) def test_virtual_child_frame_with_arrays(self): myjitdriver = JitDriver(greens = [], reds = ['frame'], diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -337,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py --- a/pypy/module/__builtin__/compiling.py +++ b/pypy/module/__builtin__/compiling.py @@ -5,7 +5,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError from pypy.interpreter.astcompiler import consts, ast -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec @unwrap_spec(filename=str, mode=str, flags=int, dont_inherit=int) def compile(space, w_source, filename, mode, flags=0, dont_inherit=0): diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py --- a/pypy/module/__builtin__/descriptor.py +++ b/pypy/module/__builtin__/descriptor.py @@ -1,12 +1,10 @@ - -from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.function import StaticMethod, ClassMethod from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.descroperation import object_getattribute, object_setattr -from pypy.interpreter.function import StaticMethod, ClassMethod -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \ - descr_set_dict, interp_attrproperty_w, generic_new_descr +from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w, + generic_new_descr) +from pypy.objspace.descroperation import object_getattribute class W_Super(Wrappable): def __init__(self, space, w_starttype, w_objtype, w_self): diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -4,13 +4,12 @@ """ from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import NoneNotWrapped, applevel +from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.objectmodel import specialize -from inspect import getsource, getfile from pypy.rlib.rbigint import rbigint @@ -662,7 +661,6 @@ def descr_reduce(self): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns space = self.space w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -1,11 +1,9 @@ import new from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import NoneNotWrapped, applevel, interp2app +from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict -from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, descr_set_dict from pypy.rlib.objectmodel import compute_identity_hash from pypy.rlib.debug import make_sure_not_resized from pypy.rlib import jit diff --git a/pypy/module/__builtin__/interp_memoryview.py b/pypy/module/__builtin__/interp_memoryview.py --- a/pypy/module/__builtin__/interp_memoryview.py +++ b/pypy/module/__builtin__/interp_memoryview.py @@ -2,7 +2,7 @@ Implementation of the 'buffer' and 'memoryview' types. """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter import gateway, buffer +from pypy.interpreter import buffer from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -4,12 +4,10 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.runicode import UNICHR from pypy.rlib.rfloat import isnan, isinf, round_double from pypy.rlib import rfloat -import math import __builtin__ NoneNotWrapped = gateway.NoneNotWrapped diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,5 +1,4 @@ -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib import debug, jit diff --git a/pypy/module/__pypy__/interp_identitydict.py b/pypy/module/__pypy__/interp_identitydict.py --- a/pypy/module/__pypy__/interp_identitydict.py +++ b/pypy/module/__pypy__/interp_identitydict.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app from pypy.interpreter.baseobjspace import Wrappable class W_IdentityDict(Wrappable): diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -186,6 +186,11 @@ mod = self.get_ast("from __future__ import with_statement; import y; " \ "from __future__ import nested_scopes") raises(SyntaxError, compile, mod, "", "exec") + mod = self.get_ast("from __future__ import division\nx = 1/2") + co = compile(mod, "", "exec") + ns = {} + exec co in ns + assert ns["x"] == .5 def test_field_attr_writable(self): import _ast as ast diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.objectmodel import we_are_translated class CodecState(object): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -1,9 +1,8 @@ -import sys -from pypy.interpreter.baseobjspace import Wrappable, Arguments +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, \ operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi @@ -83,7 +82,6 @@ def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P types = [ # note: most of the type name directly come from the C equivalent, # with the exception of bytes: in C, ubyte and char are equivalent, @@ -149,6 +147,12 @@ raise OperationError(space.w_TypeError, space.wrap(msg)) return res +def unwrap_truncate_int(TP, space, w_arg): + if space.is_true(space.isinstance(w_arg, space.w_int)): + return rffi.cast(TP, space.int_w(w_arg)) + else: + return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask()) +unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)' # ======================================================================== @@ -181,15 +185,14 @@ # note that we must check for longlong first, because either # is_signed or is_unsigned returns true anyway assert libffi.IS_32_BIT - kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind - self.arg_longlong(space, argchain, kind, w_arg) + self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): - argchain.arg(space.int_w(w_arg)) + argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) elif w_argtype.is_unsigned(): - argchain.arg(intmask(space.uint_w(w_arg))) + argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg)) elif w_argtype.is_char(): w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) @@ -220,15 +223,10 @@ return w_arg @jit.dont_look_inside - def arg_longlong(self, space, argchain, kind, w_arg): + def arg_longlong(self, space, argchain, w_arg): bigarg = space.bigint_w(w_arg) - if kind == 'I': - llval = bigarg.tolonglong() - elif kind == 'U': - ullval = bigarg.toulonglong() + ullval = bigarg.ulonglongmask() llval = rffi.cast(rffi.LONGLONG, ullval) - else: - assert False # this is a hack: we store the 64 bits of the long long into the # 64 bits of a float (i.e., a C double) floatval = libffi.longlong2float(llval) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -111,7 +111,6 @@ types.double) assert pow(2, 3) == 8 - def test_int_args(self): """ DLLEXPORT int sum_xy(int x, int y) @@ -119,10 +118,12 @@ return x+y; } """ + import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint) assert sum_xy(30, 12) == 42 + assert sum_xy(sys.maxint*2, 0) == -2 def test_void_result(self): """ @@ -247,6 +248,9 @@ types.ulong) assert sum_xy(sys.maxint, 12) == sys.maxint+12 assert sum_xy(sys.maxint+1, 12) == sys.maxint+13 + # + res = sum_xy(sys.maxint*2+3, 0) + assert res == 1 def test_unsigned_short_args(self): """ @@ -375,6 +379,9 @@ res = sum_xy(x, y) expected = maxint64 + 3 assert res == expected + # + res = sum_xy(maxint64*2+3, 0) + assert res == 1 def test_byval_argument(self): """ diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -43,11 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,12 +3,10 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.gateway import ObjSpace -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -import os def wrap_streamerror(space, e, w_filename=None): if isinstance(e, streamio.StreamError): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -4,7 +4,6 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.buffer import RWBuffer -from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstring import StringBuilder from pypy.rlib.rarithmetic import r_longlong, intmask from pypy.tool.sourcetools import func_renamer diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py --- a/pypy/module/_io/interp_fileio.py +++ b/pypy/module/_io/interp_fileio.py @@ -1,5 +1,4 @@ -from pypy.interpreter.typedef import ( - TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty) +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 from pypy.rlib.rarithmetic import r_longlong diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -6,7 +6,6 @@ TypeDef, interp_attrproperty, generic_new_descr) from pypy.module.exceptions.interp_exceptions import W_IOError from pypy.module._io.interp_fileio import W_FileIO -from pypy.module._io.interp_iobase import W_IOBase from pypy.module._io.interp_textio import W_TextIOWrapper from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -57,6 +57,11 @@ def __del__(self): self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + + def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -4,7 +4,7 @@ generic_new_descr) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint from pypy.rlib.rbigint import rbigint from pypy.rlib.rstring import UnicodeBuilder diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py --- a/pypy/module/_locale/interp_locale.py +++ b/pypy/module/_locale/interp_locale.py @@ -1,4 +1,3 @@ -from pypy.rpython.tool import rffi_platform as platform from pypy.rlib import rposix from pypy.rlib.rarithmetic import intmask diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -2,12 +2,10 @@ """ The ffi for rpython, need to be imported for side effects """ -import sys from pypy.rpython.lltypesystem import rffi from pypy.rpython.lltypesystem import lltype from pypy.rpython.tool import rffi_platform from pypy.rpython.extfunc import register_external -from pypy.rpython.extregistry import ExtRegistryEntry from pypy.module._minimal_curses import interp_curses from pypy.translator.tool.cbuild import ExternalCompilationInfo diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -1,4 +1,4 @@ -import py, sys +import py from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -4,7 +4,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import ( OperationError, wrap_oserror, operationerrfmt) -from pypy.rpython.lltypesystem import rffi, lltype, llmemory +from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll import sys diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -15,7 +15,6 @@ if sys.platform == 'win32': from pypy.rlib import rwin32 - from pypy.interpreter.error import wrap_windowserror from pypy.module._multiprocessing.interp_win32 import ( handle_w, _GetTickCount) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -8,7 +8,6 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec -from pypy.objspace.std.dicttype import dictiter_typedef from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,10 +2,10 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rpython.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import get_elem, push_elem +from pypy.module._rawffi.array import push_elem from pypy.module._rawffi.structure import W_Structure -from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \ - wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes +from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, + unwrap_value, unpack_argshapes) from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL from pypy.rlib.clibffi import ffi_type_void from pypy.rlib import rweakref diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -1,7 +1,6 @@ -import sys from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib.clibffi import * @@ -15,7 +14,7 @@ from pypy.rlib import rwin32 from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.tracker import tracker TYPEMAP = { diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py --- a/pypy/module/_socket/interp_func.py +++ b/pypy/module/_socket/interp_func.py @@ -1,9 +1,8 @@ -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._socket.interp_socket import converted_error, W_RSocket from pypy.rlib import rsocket from pypy.rlib.rsocket import SocketError -from pypy.rlib.rarithmetic import r_uint -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError def gethostname(space): """gethostname() -> string diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,7 +1,7 @@ from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError -from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -11,7 +11,6 @@ from pypy.module._socket import interp_socket -import sys ## user defined constants X509_NAME_MAXLEN = 256 diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -15,13 +15,10 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import StaticMethod from pypy.module._stackless.stackless_flags import StacklessFlags from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py --- a/pypy/module/_stackless/interp_stackless.py +++ b/pypy/module/_stackless/interp_stackless.py @@ -1,9 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError -from pypy.rlib.rarithmetic import intmask import os diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py --- a/pypy/module/_stackless/rclonable.py +++ b/pypy/module/_stackless/rclonable.py @@ -1,7 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.rlib.objectmodel import we_are_translated -from pypy.interpreter.error import OperationError class InterpClonableMixin: diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,16 +1,15 @@ import py -from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.interpreter.typedef import GetSetProperty, TypeDef +from pypy.interpreter.typedef import TypeDef from pypy.rlib import jit import weakref class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 @@ -23,8 +22,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,11 +119,8 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: + assert isinstance(w_self, W_WeakrefBase) w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) def descr__repr__(self, space): w_obj = self.dereference() diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -1,6 +1,5 @@ from __future__ import with_statement from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError, wrap_windowserror diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,10 +1,9 @@ from __future__ import with_statement -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object from pypy.objspace.std.multimethod import FailedToImplement @@ -572,10 +571,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -4,9 +4,8 @@ from pypy.rpython.lltypesystem import lltype from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.rlib.streamio import Stream from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform as compiler diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -133,6 +133,7 @@ bz2f.seek(0) assert bz2f.tell() == 0 + del bz2f # delete from this frame, which is captured in the traceback def test_open_close_del(self): from bz2 import BZ2File @@ -246,11 +247,18 @@ assert text_read == self.TEXT bz2f.close() + def test_silently_closes(self): + from bz2 import BZ2File + self.create_broken_temp_file() + BZ2File(self.temppath) + # check that no C-level malloc is left behind + def test_read_broken_file(self): from bz2 import BZ2File self.create_broken_temp_file() bz2f = BZ2File(self.temppath) raises(EOFError, bz2f.read) + del bz2f # delete from this frame, which is captured in the traceback def test_subsequent_read_broken_file(self): from bz2 import BZ2File @@ -264,6 +272,7 @@ raise Exception("should generate EOFError earlier") except EOFError: pass + del bz2f # delete from this frame, which is captured in the traceback def test_read_chunk10(self): from bz2 import BZ2File @@ -416,6 +425,7 @@ bz2f.close() bz2f = BZ2File(self.temppath, 'r') assert bz2f.read() == self.random_data + del bz2f # delete from this frame, which is captured in the traceback def test_context_manager(self): from bz2 import BZ2File diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -1,4 +1,3 @@ -import sys from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py --- a/pypy/module/cmath/interp_cmath.py +++ b/pypy/module/cmath/interp_cmath.py @@ -5,7 +5,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import NoneNotWrapped -from pypy.module.cmath import Module, names_and_docstrings +from pypy.module.cmath import names_and_docstrings from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG from pypy.module.cmath.constant import M_LN2, M_LN10 diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py --- a/pypy/module/cpyext/cdatetime.py +++ b/pypy/module/cpyext/cdatetime.py @@ -1,8 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib.objectmodel import we_are_translated -from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef -from pypy.module.cpyext.api import ( - cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields) +from pypy.module.cpyext.pyobject import PyObject, make_ref +from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct, + PyObjectFields) from pypy.module.cpyext.import_ import PyImport_Import from pypy.module.cpyext.typeobject import PyTypeObjectPtr from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py --- a/pypy/module/cpyext/complexobject.py +++ b/pypy/module/cpyext/complexobject.py @@ -1,7 +1,6 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.module.cpyext.api import ( cpython_api, cpython_struct, PyObject, build_type_checkers) -from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.floatobject import PyFloat_AsDouble from pypy.objspace.std.complexobject import W_ComplexObject from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.1" /* PyPy version as a string */ -#define PYPY_VERSION "1.5.0" +#define PYPY_VERSION "1.6.0" /* Subversion Revision number of this file (not of the repository) */ #define PY_PATCHLEVEL_REVISION "$Revision: 77872 $" diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -22,7 +22,7 @@ def PySequence_Check(space, w_obj): """Return 1 if the object provides sequence protocol, and 0 otherwise. This function always succeeds.""" - return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None) + return int(space.issequence_w(w_obj)) @cpython_api([PyObject], Py_ssize_t, error=-1) def PySequence_Size(space, w_obj): diff --git a/pypy/module/crypt/interp_crypt.py b/pypy/module/crypt/interp_crypt.py --- a/pypy/module/crypt/interp_crypt.py +++ b/pypy/module/crypt/interp_crypt.py @@ -1,6 +1,5 @@ -from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.rpython.lltypesystem import rffi, lltype +from pypy.rpython.lltypesystem import rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo import sys diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -73,9 +73,8 @@ """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w,\ - GetSetProperty, interp_attrproperty, descr_get_dict, descr_set_dict,\ - descr_del_dict +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict, + descr_set_dict, descr_del_dict) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError from pypy.rlib import rwin32 diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -11,9 +11,8 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.eval import Code from pypy.interpreter.pycode import PyCode -from pypy.rlib import streamio, jit, rposix +from pypy.rlib import streamio, jit from pypy.rlib.streamio import StreamErrors -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -3,9 +3,9 @@ from pypy.rlib import streamio from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.module import Module -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import struct + def get_suffixes(space): w = space.wrap diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,7 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.rarithmetic import ovfcheck class W_Count(Wrappable): diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -1,10 +1,8 @@ -from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask from pypy.rlib import rstackovf from pypy.module._file.interp_file import W_File -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import sys + Py_MARSHAL_VERSION = 2 diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -10,6 +10,7 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + 'fromstring': 'interp_support.fromstring', # ufuncs 'abs': 'interp_ufuncs.absolute', diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,5 +1,5 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit @@ -7,7 +7,6 @@ from pypy.tool.sourcetools import func_with_new_name import math - def dummy1(v): assert isinstance(v, float) return v @@ -20,6 +19,8 @@ numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) +all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) class Signature(object): def __init__(self): @@ -45,10 +46,14 @@ return v1 * v2 def div(v1, v2): return v1 / v2 -def pow(v1, v2): +def power(v1, v2): return math.pow(v1, v2) def mod(v1, v2): return math.fmod(v1, v2) +def maximum(v1, v2): + return max(v1, v2) +def minimum(v1, v2): + return min(v1, v2) class BaseArray(Wrappable): def __init__(self): @@ -82,8 +87,8 @@ def _binop_impl(function): signature = Signature() def impl(self, space, w_other): + w_other = convert_to_array(space, w_other) new_sig = self.signature.transition(signature) - if isinstance(w_other, BaseArray): res = Call2( function, self, @@ -91,14 +96,6 @@ new_sig.transition(w_other.signature) ) w_other.invalidates.append(res) - else: - w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) self.invalidates.append(res) return space.wrap(res) return func_with_new_name(impl, "binop_%s_impl" % function.__name__) @@ -107,9 +104,137 @@ descr_sub = _binop_impl(sub) descr_mul = _binop_impl(mul) descr_div = _binop_impl(div) - descr_pow = _binop_impl(pow) + descr_pow = _binop_impl(power) descr_mod = _binop_impl(mod) + def _binop_right_impl(function): + signature = Signature() + def impl(self, space, w_other): + new_sig = self.signature.transition(signature) + w_other = FloatWrapper(space.float_w(w_other)) + res = Call2( + function, + w_other, + self, + new_sig.transition(w_other.signature) + ) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, + "binop_right_%s_impl" % function.__name__) + + descr_radd = _binop_right_impl(add) + descr_rsub = _binop_right_impl(sub) + descr_rmul = _binop_right_impl(mul) + descr_rdiv = _binop_right_impl(div) + descr_rpow = _binop_right_impl(power) + descr_rmod = _binop_right_impl(mod) + + def _reduce_sum_prod_impl(function, init): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + return space.wrap(loop(self, init, self.find_size())) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_max_min_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, result, size): + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, self.eval(0), size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_argmax_argmin_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self', 'cur_best']) + def loop(self, size): + result = 0 + cur_best = self.eval(0) + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result, cur_best=cur_best) + new_best = function(cur_best, self.eval(i)) + if new_best != cur_best: + result = i + cur_best = new_best + i += 1 + return result + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, size)) + return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) + + def _all(self): + size = self.find_size() + i = 0 + while i < size: + all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if not self.eval(i): + return False + i += 1 + return True + def descr_all(self, space): + return space.wrap(self._all()) + + def _any(self): + size = self.find_size() + i = 0 + while i < size: + any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if self.eval(i): + return True + i += 1 + return False + def descr_any(self, space): + return space.wrap(self._any()) + + descr_sum = _reduce_sum_prod_impl(add, 0.0) + descr_prod = _reduce_sum_prod_impl(mul, 1.0) + descr_max = _reduce_max_min_impl(maximum) + descr_min = _reduce_max_min_impl(minimum) + descr_argmax = _reduce_argmax_argmin_impl(maximum) + descr_argmin = _reduce_argmax_argmin_impl(minimum) + + def descr_dot(self, space, w_other): + if isinstance(w_other, BaseArray): + w_res = self.descr_mul(space, w_other) + assert isinstance(w_res, BaseArray) + return w_res.descr_sum(space) + else: + return self.descr_mul(space, w_other) + def get_concrete(self): raise NotImplementedError @@ -119,6 +244,12 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_repr(self, space): + return self.get_concrete()._repr(space) + + def descr_str(self, space): + return self.get_concrete()._str(space) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -136,13 +267,17 @@ return self.get_concrete().descr_setitem(space, item, value) def descr_mean(self, space): - s = 0 - concrete = self.get_concrete() - size = concrete.find_size() - for i in xrange(size): - s += concrete.getitem(i) - return space.wrap(s / size) + return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) +def convert_to_array (space, w_obj): + if isinstance(w_obj, BaseArray): + return w_obj + elif space.issequence_w(w_obj): + # Convert to array. + return new_numarray(space, w_obj) + else: + # If it's a scalar + return FloatWrapper(space.float_w(w_obj)) class FloatWrapper(BaseArray): """ @@ -304,6 +439,26 @@ def calc_index(self, item): return (self.start + item * self.step) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + class SingleDimArray(BaseArray): signature = Signature() @@ -341,6 +496,26 @@ def getitem(self, item): return self.storage[item] + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) @@ -350,14 +525,17 @@ def __del__(self): lltype.free(self.storage, flavor='raw') -def descr_new_numarray(space, w_type, w_size_or_iterable): +def new_numarray(space, w_size_or_iterable): l = space.listview(w_size_or_iterable) arr = SingleDimArray(len(l)) i = 0 for w_elem in l: arr.storage[i] = space.float_w(space.float(w_elem)) i += 1 - return space.wrap(arr) + return arr + +def descr_new_numarray(space, w_type, w_size_or_iterable): + return space.wrap(new_numarray(space, w_size_or_iterable)) @unwrap_spec(size=int) def zeros(space, size): @@ -389,6 +567,23 @@ __div__ = interp2app(BaseArray.descr_div), __pow__ = interp2app(BaseArray.descr_pow), __mod__ = interp2app(BaseArray.descr_mod), + __radd__ = interp2app(BaseArray.descr_radd), + __rsub__ = interp2app(BaseArray.descr_rsub), + __rmul__ = interp2app(BaseArray.descr_rmul), + __rdiv__ = interp2app(BaseArray.descr_rdiv), + __rpow__ = interp2app(BaseArray.descr_rpow), + __rmod__ = interp2app(BaseArray.descr_rmod), + __repr__ = interp2app(BaseArray.descr_repr), + __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), + sum = interp2app(BaseArray.descr_sum), + prod = interp2app(BaseArray.descr_prod), + max = interp2app(BaseArray.descr_max), + min = interp2app(BaseArray.descr_min), + argmax = interp2app(BaseArray.descr_argmax), + argmin = interp2app(BaseArray.descr_argmin), + all = interp2app(BaseArray.descr_all), + any = interp2app(BaseArray.descr_any), + dot = interp2app(BaseArray.descr_dot), ) diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_support.py @@ -0,0 +1,32 @@ + +from pypy.rlib.rstruct.runpack import runpack +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.error import OperationError +from pypy.module.micronumpy.interp_numarray import SingleDimArray + +FLOAT_SIZE = rffi.sizeof(lltype.Float) + + at unwrap_spec(s=str) +def fromstring(space, s): + length = len(s) + + if length % FLOAT_SIZE == 0: + number = length/FLOAT_SIZE + else: + raise OperationError(space.w_ValueError, space.wrap( + "string length %d not divisable by %d" % (length, FLOAT_SIZE))) + + a = SingleDimArray(number) + + start = 0 + end = FLOAT_SIZE + i = 0 + while i < number: + part = s[start:end] + a.storage[i] = runpack('d', part) + i += 1 + start += FLOAT_SIZE + end += FLOAT_SIZE + + return space.wrap(a) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,30 +1,34 @@ import math -from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature +from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, + convert_to_array) from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name - def ufunc(func): signature = Signature() def impl(space, w_obj): - if isinstance(w_obj, BaseArray): - w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) - w_obj.invalidates.append(w_res) + if space.issequence_w(w_obj): + w_obj_arr = convert_to_array(space, w_obj) + w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) + w_obj_arr.invalidates.append(w_res) return w_res + else: return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): - if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): - new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) - w_res = Call2(func, w_lhs, w_rhs, new_sig) - w_lhs.invalidates.append(w_res) - w_rhs.invalidates.append(w_res) + if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): + w_lhs_arr = convert_to_array(space, w_lhs) + w_rhs_arr = convert_to_array(space, w_rhs) + new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature) + w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig) + w_lhs_arr.invalidates.append(w_res) + w_rhs_arr.invalidates.append(w_res) return w_res + else: return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -1,12 +1,10 @@ from pypy.conftest import gettestobjspace from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper - class BaseNumpyAppTest(object): def setup_class(cls): cls.space = gettestobjspace(usemodules=('micronumpy',)) - class TestSignature(object): def test_binop_signature(self, space): ar = SingleDimArray(10) @@ -26,4 +24,4 @@ v3 = ar.descr_add(space, v1) v4 = ar.descr_add(space, v2) - assert v3.signature is v4.signature \ No newline at end of file + assert v3.signature is v4.signature diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1,6 +1,7 @@ import py from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest +from pypy.conftest import gettestobjspace class AppTestNumArray(BaseNumpyAppTest): @@ -42,6 +43,38 @@ a = array(range(5)) assert a[3] == 3 + def test_repr(self): + from numpy import array, zeros + a = array(range(5)) + assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" + a = zeros(1001) + assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_repr_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert repr(b) == "array([1.0, 3.0])" + a = zeros(2002) + b = a[::2] + assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_str(self): + from numpy import array, zeros + a = array(range(5)) + assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + a = zeros(1001) + assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + + def test_str_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert str(b) == "[1.0 3.0]" + a = zeros(2002) + b = a[::2] + assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_getitem(self): from numpy import array a = array(range(5)) @@ -96,6 +129,15 @@ for i in range(5): assert b[i] == i + 5 + def test_add_list(self): + from numpy import array + a = array(range(5)) + b = list(reversed(range(5))) + c = a + b + assert isinstance(c, array) + for i in range(5): + assert c[i] == 4 + def test_subtract(self): from numpy import array a = array(range(5)) @@ -276,7 +318,97 @@ assert d[1] == 12 def test_mean(self): - from numpy import array, mean + from numpy import array a = array(range(5)) assert a.mean() == 2.0 assert a[:4].mean() == 1.5 + + def test_sum(self): + from numpy import array + a = array(range(5)) + assert a.sum() == 10.0 + assert a[:4].sum() == 6.0 + + def test_prod(self): + from numpy import array + a = array(range(1,6)) + assert a.prod() == 120.0 + assert a[:4].prod() == 24.0 + + def test_max(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.max() == 5.7 + b = array([]) + raises(ValueError, "b.max()") + + def test_max_add(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert (a+a).max() == 11.4 + + def test_min(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.min() == -3.0 + b = array([]) + raises(ValueError, "b.min()") + + def test_argmax(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmax() == 2 + b = array([]) + raises(ValueError, "b.argmax()") + + def test_argmin(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmin() == 3 + b = array([]) + raises(ValueError, "b.argmin()") + + def test_all(self): + from numpy import array + a = array(range(5)) + assert a.all() == False + a[0] = 3.0 + assert a.all() == True + b = array([]) + assert b.all() == True + + def test_any(self): + from numpy import array, zeros + a = array(range(5)) + assert a.any() == True + b = zeros(5) + assert b.any() == False + c = array([]) + assert c.any() == False + + def test_dot(self): + from numpy import array + a = array(range(5)) + assert a.dot(a) == 30.0 + + def test_dot_constant(self): + from numpy import array + a = array(range(5)) + b = a.dot(2.5) + for i in xrange(5): + assert b[i] == 2.5*a[i] + + +class AppTestSupport(object): + def setup_class(cls): + import struct + cls.space = gettestobjspace(usemodules=('micronumpy',)) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + + def test_fromstring(self): + from numpy import fromstring + a = fromstring(self.data) + for i in range(4): + assert a[i] == i + 1 + raises(ValueError, fromstring, "abc") + diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -10,6 +10,40 @@ assert sign(-0.0) == 0.0 assert minimum(2.0, 3.0) == 2.0 + def test_sequence(self): + from numpy import array, negative, minimum + a = array(range(3)) + b = [2.0, 1.0, 0.0] + c = 1.0 + b_neg = negative(b) + assert isinstance(b_neg, array) + for i in range(3): + assert b_neg[i] == -b[i] + min_a_b = minimum(a, b) + assert isinstance(min_a_b, array) + for i in range(3): + assert min_a_b[i] == min(a[i], b[i]) + min_b_a = minimum(b, a) + assert isinstance(min_b_a, array) + for i in range(3): + assert min_b_a[i] == min(a[i], b[i]) + min_a_c = minimum(a, c) + assert isinstance(min_a_c, array) + for i in range(3): + assert min_a_c[i] == min(a[i], c) + min_c_a = minimum(c, a) + assert isinstance(min_c_a, array) + for i in range(3): + assert min_c_a[i] == min(a[i], c) + min_b_c = minimum(b, c) + assert isinstance(min_b_c, array) + for i in range(3): + assert min_b_c[i] == min(b[i], c) + min_c_b = minimum(c, b) + assert isinstance(min_c_b, array) + for i in range(3): + assert min_c_b[i] == min(b[i], c) + def test_negative(self): from numpy import array, negative diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -4,9 +4,20 @@ FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile +from pypy.rlib.objectmodel import specialize class FakeSpace(object): - pass + w_ValueError = None + + def issequence_w(self, w_obj): + return True + + @specialize.argtype(1) + def wrap(self, w_obj): + return w_obj + + def float_w(self, w_obj): + return float(w_obj) class TestNumpyJIt(LLJitMixin): def setup_class(cls): @@ -51,6 +62,110 @@ assert result == f(5) + def test_sum(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_sum(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 2, + "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_prod(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_prod(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_max(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_max(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_gt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, + "guard_false": 1, "jump": 1}) + + def test_min(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_min(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_argmin(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_argmin(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_all(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = 1.0 + j += 1 + return ar.descr_add(space, ar).descr_all(space) + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, + "int_lt": 1, "guard_true": 2, "jump": 1}) + + def test_any(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_any(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, "guard_false": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + def test_already_forecd(self): def f(i): ar = SingleDimArray(i) diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py --- a/pypy/module/mmap/interp_mmap.py +++ b/pypy/module/mmap/interp_mmap.py @@ -1,15 +1,10 @@ -from pypy.rpython.tool import rffi_platform -from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped from pypy.rlib import rmmap from pypy.rlib.rmmap import RValueError, RTypeError, ROverflowError -import sys -import os -import platform -import stat + class W_MMap(Wrappable): def __init__(self, space, mmap_obj): diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -15,7 +15,6 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap -from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant from pypy.jit.metainterp.resoperation import rop from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -1,9 +1,9 @@ from pypy.interpreter.typedef import TypeDef, interp_attrproperty -from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import unwrap_spec, interp2app from pypy.interpreter.pycode import PyCode -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.lltypesystem.rclass import OBJECT diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -19,7 +19,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) + guard_true(i7, descr=...) i9 = int_add(i5, 1) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) @@ -39,11 +39,12 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated(descr=...) i13 = int_lt(i7, i9) - guard_true(i13, descr=) + guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = int_add(i7, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) @@ -68,16 +69,17 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i13 = int_lt(i8, 307200) - guard_true(i13, descr=) + guard_true(i13, descr=...) + guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) # on 64bit, there is a guard checking that i19 actually fits into 32bit ... setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -80,19 +80,19 @@ # assert entry_bridge.match_by_id('call', """ p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) + guard_nonnull_class(p29, ConstClass(Function), descr=...) p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) + guard_value(p33, ConstPtr(ptr34), descr=...) p35 = getfield_gc(p29, descr=) p36 = getfield_gc(p29, descr=) p38 = call(ConstClass(getexecutioncontext), descr=) p39 = getfield_gc(p38, descr=) i40 = force_token() p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) + guard_isnull(p41, descr=...) i42 = getfield_gc(p38, descr=) i43 = int_is_zero(i42) - guard_true(i43, descr=) + guard_true(i43, descr=...) i50 = force_token() """) # @@ -101,16 +101,16 @@ loop, = log.loops_by_id('call') assert loop.match(""" i12 = int_lt(i5, i6) - guard_true(i12, descr=) + guard_true(i12, descr=...) i13 = force_token() i15 = int_add(i5, 1) i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) """) @@ -146,14 +146,14 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i15 = int_lt(i6, i9) - guard_true(i15, descr=) - guard_not_invalidated(descr=) + guard_true(i15, descr=...) + guard_not_invalidated(descr=...) i16 = force_token() i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) """) @@ -180,11 +180,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) - guard_not_invalidated(descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = force_token() i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() --TICK-- jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) @@ -281,32 +281,30 @@ loop0, = log.loops_by_id('g1') assert loop0.match_by_id('g1', """ i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('h1', """ i20 = force_token() i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('g2', """ i27 = force_token() i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) # loop1, = log.loops_by_id('g3') assert loop1.match_by_id('g3', """ i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) def test_stararg(self): @@ -352,7 +350,7 @@ i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) p17 = getfield_gc(p8, descr=) p19 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p19, i12, descr=) @@ -404,9 +402,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i10 = int_lt(i5, i6) - guard_true(i10, descr=) + guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i120 = int_add(i5, 1) - guard_not_invalidated(descr=) --TICK-- jump(..., descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py --- a/pypy/module/pypyjit/test_pypy_c/test_exception.py +++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py @@ -36,11 +36,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i5 = int_is_true(i3) - guard_true(i5, descr=) - guard_not_invalidated(descr=) + guard_true(i5, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -84,8 +84,8 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i4, i5) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i14 = int_add(i4, 1) --TICK-- diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -0,0 +1,30 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGlobals(BaseTestPyPyC): + def test_load_builtin(self): + def main(n): + import pypyjit + + i = 0 + while i < n: + l = len # ID: loadglobal + i += pypyjit.residual_call(l, "a") + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("loadglobal", """ + p10 = getfield_gc(p0, descr=) + guard_value(p10, ConstPtr(ptr11), descr=...) + p12 = getfield_gc(p10, descr=) + guard_value(p12, ConstPtr(ptr13), descr=...) + p15 = getfield_gc(ConstPtr(ptr14), descr=) + guard_isnull(p15, descr=...) + guard_not_invalidated(descr=...) + p19 = getfield_gc(ConstPtr(p17), descr=) + guard_value(p19, ConstPtr(ptr20), descr=...) + p22 = getfield_gc(ConstPtr(ptr21), descr=) + guard_nonnull(p22, descr=...) + """) \ No newline at end of file diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py --- a/pypy/module/pypyjit/test_pypy_c/test_import.py +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -15,13 +15,13 @@ assert log.result == 500 loop, = log.loops_by_id('import') assert loop.match_by_id('import', """ + guard_not_invalidated(descr=...) p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) + guard_value(p11, ConstPtr(ptr12), descr=...) p14 = getfield_gc(ConstPtr(ptr13), descr=) p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) + guard_value(p14, ConstPtr(ptr17), descr=...) + guard_isnull(p16, descr=...) """) def test_import_fast_path(self, tmpdir): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -22,10 +22,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) """) @@ -47,10 +47,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = int_lt(i5, i6) - guard_true(i9, descr=) - guard_not_invalidated(descr=) + guard_true(i9, descr=...) + guard_not_invalidated(descr=...) i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) """) @@ -115,7 +115,7 @@ # ---------------------- loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i9 = int_lt(i7, i8) + i9 = int_lt(i8, i7) guard_true(i9, descr=.*) guard_not_invalidated(descr=.*) i11 = int_add(i8, 1) @@ -124,7 +124,7 @@ p20 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p20, i11, descr=) setfield_gc(ConstPtr(ptr21), p20, descr=) - jump(p0, p1, p2, p3, p4, p20, p6, i11, i8, descr=) + jump(p0, p1, p2, p3, p4, p20, p6, i11, i7, descr=) """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -0,0 +1,32 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestMath(BaseTestPyPyC): + def test_log(self): + def main(n): + import math + + i = 1 + s = 0.0 + while i < n: + s += math.log(i) - math.log10(i) + i += 1 + return s + log = self.run(main, [500]) + assert round(log.result, 6) == round(main(500), 6) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i2 = int_lt(i0, i1) + guard_true(i2, descr=...) + guard_not_invalidated(descr=...) + f1 = cast_int_to_float(i0) + i3 = float_le(f1, 0) + guard_false(i3, descr=...) + f2 = call(ConstClass(log), f1, descr=) + f3 = call(ConstClass(log10), f1, descr=) + f4 = float_sub(f2, f3) + f5 = float_add(f0, f4) + i4 = int_add(i0, 1) + --TICK-- + jump(..., descr=) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -17,6 +17,7 @@ assert loop.match(""" i7 = int_lt(i4, 300) guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 3000) guard_no_overflow(descr=...) i11 = int_add(i4, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -84,7 +84,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = float_lt(f5, f7) - guard_true(i9, descr=) + guard_true(i9, descr=...) f10 = float_add(f8, f5) --TICK-- jump(p0, p1, p2, p3, p4, f10, p6, f7, f8, descr=) @@ -107,19 +107,19 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i11, i12) - guard_false(i16, descr=) + guard_false(i16, descr=...) i17 = int_mul(i11, i14) i18 = int_add(i15, i17) i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=) + guard_not_invalidated(descr=...) i23 = int_lt(i18, 0) - guard_false(i23, descr=) + guard_false(i23, descr=...) i25 = int_ge(i18, i9) - guard_false(i25, descr=) + guard_false(i25, descr=...) i27 = int_add_ovf(i7, i18) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -164,20 +164,20 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i12, i13) - guard_false(i16, descr=) + guard_false(i16, descr=...) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) - guard_nonnull_class(p17, 146982464, descr=) + guard_nonnull_class(p17, 146982464, descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) - guard_true(i23, descr=) + guard_true(i23, descr=...) i24 = getfield_gc(p17, descr=) i25 = getarrayitem_raw(i24, 0, descr=<.*>) i27 = int_lt(1, i21) - guard_false(i27, descr=) + guard_false(i27, descr=...) i28 = int_add_ovf(i10, i25) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) @@ -201,9 +201,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i11 = int_lt(i7, 300) - guard_true(i11, descr=) + guard_true(i11, descr=...) i12 = int_add_ovf(i8, i9) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i14 = int_add(i7, 1) --TICK-- jump(..., descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -16,27 +16,92 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = int_mod(i6, i10) i17 = int_rshift(i15, 63) i18 = int_and(i10, i17) i19 = int_add(i15, i18) i21 = int_lt(i19, 0) - guard_false(i21, descr=) + guard_false(i21, descr=...) i22 = int_ge(i19, i10) - guard_false(i22, descr=) + guard_false(i22, descr=...) i23 = strgetitem(p11, i19) i24 = int_ge(i19, i12) - guard_false(i24, descr=) + guard_false(i24, descr=...) i25 = unicodegetitem(p13, i19) - guard_not_invalidated(descr=) p27 = newstr(1) strsetitem(p27, 0, i23) p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) - guard_true(i32, descr=) + guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) + + def test_long(self): + def main(n): + import string + i = 1 + while i < n: + i += int(long(string.digits[i % len(string.digits)], 16)) + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i13 = int_eq(i6, -9223372036854775808) + guard_false(i13, descr=...) + i15 = int_mod(i6, i8) + i17 = int_rshift(i15, 63) + i18 = int_and(i8, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i8) + guard_false(i22, descr=...) + i23 = strgetitem(p10, i19) + p25 = newstr(1) + strsetitem(p25, 0, i23) + p28 = call(ConstClass(strip_spaces), p25, descr=) + guard_no_exception(descr=...) + i29 = strlen(p28) + i30 = int_is_true(i29) + guard_true(i30, descr=...) + i32 = int_sub(i29, 1) + i33 = strgetitem(p28, i32) + i35 = int_eq(i33, 108) + guard_false(i35, descr=...) + i37 = int_eq(i33, 76) + guard_false(i37, descr=...) + i39 = strgetitem(p28, 0) + i41 = int_eq(i39, 45) + guard_false(i41, descr=...) + i43 = int_eq(i39, 43) + guard_false(i43, descr=...) + i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=) + guard_false(i43, descr=...) + i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=) + guard_false(i46, descr=...) + p51 = new_with_vtable(21136408) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, i29, descr=) + setfield_gc(p51, 1, descr=) + setfield_gc(p51, 16, descr=) + setfield_gc(p51, p28, descr=) + p55 = call(ConstClass(parse_digit_string), p51, descr=) + guard_no_exception(descr=...) + i57 = call(ConstClass(rbigint.toint), p55, descr=) + guard_no_exception(descr=...) + i58 = int_add_ovf(i6, i57) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) """) \ No newline at end of file diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py --- a/pypy/module/rctime/interp_time.py +++ b/pypy/module/rctime/interp_time.py @@ -6,7 +6,6 @@ from pypy.rlib.rarithmetic import ovfcheck_float_to_int from pypy.rlib import rposix from pypy.translator.tool.cbuild import ExternalCompilationInfo -import math import os import sys import time as pytime diff --git a/pypy/module/select/interp_select.py b/pypy/module/select/interp_select.py --- a/pypy/module/select/interp_select.py +++ b/pypy/module/select/interp_select.py @@ -1,9 +1,7 @@ -import math from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import ( - OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.rlib import rpoll import errno diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py --- a/pypy/module/struct/formatiterator.py +++ b/pypy/module/struct/formatiterator.py @@ -1,11 +1,10 @@ - from pypy.interpreter.error import OperationError from pypy.rlib.objectmodel import specialize from pypy.rlib.rstruct.error import StructError from pypy.rlib.rstruct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT -from pypy.rlib.rstruct.formatiterator import (FormatIterator, - CalcSizeFormatIterator) +from pypy.rlib.rstruct.formatiterator import FormatIterator + class PackFormatIterator(FormatIterator): diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py --- a/pypy/module/struct/interp_struct.py +++ b/pypy/module/struct/interp_struct.py @@ -1,10 +1,7 @@ from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.module.struct.formatiterator import PackFormatIterator, UnpackFormatIterator from pypy.rlib.rstruct.error import StructError -from pypy.module.struct.formatiterator import CalcSizeFormatIterator -from pypy.module.struct.formatiterator import PackFormatIterator -from pypy.module.struct.formatiterator import UnpackFormatIterator - +from pypy.rlib.rstruct.formatiterator import CalcSizeFormatIterator @unwrap_spec(format=str) def calcsize(space, format): diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py --- a/pypy/module/sys/test/test_sysmodule.py +++ b/pypy/module/sys/test/test_sysmodule.py @@ -476,7 +476,7 @@ assert isinstance(vi[0], int) assert isinstance(vi[1], int) assert isinstance(vi[2], int) - assert vi[3] in ("alpha", "beta", "candidate", "final") + assert vi[3] in ("alpha", "beta", "candidate", "dev", "final") assert isinstance(vi[4], int) def test_allattributes(self): @@ -523,4 +523,4 @@ # If this ever actually becomes a compilation option this test should # be changed. - assert sys.float_repr_style == "short" \ No newline at end of file + assert sys.float_repr_style == "short" diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ CPYTHON_VERSION = (2, 7, 1, "final", 42) #XXX # sync patchlevel.h CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (1, 5, 0, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (1, 6, 0, "dev", 1) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_commethods.py @@ -0,0 +1,82 @@ +# unittest for SOME ctypes com function calls. +# Can't resist from implementing some kind of mini-comtypes +# theller ;-) + +import py +import sys +if sys.platform != "win32": + py.test.skip('windows only test') + +import ctypes, new, unittest +from ctypes.wintypes import HRESULT +from _ctypes import COMError + +oleaut32 = ctypes.OleDLL("oleaut32") + +class UnboundMethod(object): + def __init__(self, func, index, name): + self.func = func + self.index = index + self.name = name + self.__doc__ = func.__doc__ + + def __repr__(self): + return "" % (self.index, self.name, id(self)) + + def __get__(self, instance, owner): + if instance is None: + return self + return new.instancemethod(self.func, instance, owner) + +def commethod(index, restype, *argtypes): + """A decorator that generates COM methods. The decorated function + itself is not used except for it's name.""" + def make_commethod(func): + comfunc = ctypes.WINFUNCTYPE(restype, *argtypes)(index, func.__name__) + comfunc.__name__ = func.__name__ + comfunc.__doc__ = func.__doc__ + return UnboundMethod(comfunc, index, func.__name__) + return make_commethod + +class ICreateTypeLib2(ctypes.c_void_p): + + @commethod(1, ctypes.c_long) + def AddRef(self): + pass + + @commethod(2, ctypes.c_long) + def Release(self): + pass + + @commethod(4, HRESULT, ctypes.c_wchar_p) + def SetName(self): + """Set the name of the library.""" + + @commethod(12, HRESULT) + def SaveAllChanges(self): + pass + + +CreateTypeLib2 = oleaut32.CreateTypeLib2 +CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, ctypes.POINTER(ICreateTypeLib2)) + +################################################################ + +def test_basic_comtypes(): + punk = ICreateTypeLib2() + hr = CreateTypeLib2(0, "foobar.tlb", punk) + assert hr == 0 + + assert 2 == punk.AddRef() + assert 3 == punk.AddRef() + assert 4 == punk.AddRef() + + punk.SetName("TypeLib_ByPYPY") + py.test.raises(COMError, lambda: punk.SetName(None)) + + # This would save the typelib to disk. + ## punk.SaveAllChanges() + + assert 3 == punk.Release() + assert 2 == punk.Release() + assert 1 == punk.Release() diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -132,6 +132,16 @@ # You cannot assing character format codes as restype any longer raises(TypeError, setattr, f, "restype", "i") + + def test_truncate_python_longs(self): + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_int + x = sys.maxint * 2 + result = f(x, x, x, x, 0, 0) + assert result == -8 + + def test_floatresult(self): f = dll._testfunc_f_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] @@ -411,6 +421,23 @@ result = f("abcd", ord("b")) assert result == "bcd" + def test_keepalive_buffers(self, monkeypatch): + import gc + f = dll.my_strchr + f.argtypes = [c_char_p] + f.restype = c_char_p + # + orig__call_funcptr = f._call_funcptr + def _call_funcptr(funcptr, *newargs): + gc.collect() + gc.collect() + gc.collect() + return orig__call_funcptr(funcptr, *newargs) + monkeypatch.setattr(f, '_call_funcptr', _call_funcptr) + # + result = f("abcd", ord("b")) + assert result == "bcd" + def test_caching_bug_1(self): # the same test as test_call_some_args, with two extra lines # in the middle that trigger caching in f._ptr, which then diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py @@ -12,7 +12,7 @@ from _ctypes.function import CFuncPtr def guess(value): - cobj, ctype = CFuncPtr._conv_param(None, value) + _, cobj, ctype = CFuncPtr._conv_param(None, value) return ctype ## cobj = CFuncPtr._conv_param(None, value) ## return type(cobj) diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -1,9 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype, llmemory -from pypy.rpython.tool import rffi_platform as platform from pypy.translator.tool.cbuild import ExternalCompilationInfo -import py, os -from pypy.rpython.extregistry import ExtRegistryEntry +import py from pypy.rlib import jit from pypy.rlib.debug import ll_assert from pypy.rlib.objectmodel import we_are_translated @@ -21,6 +19,7 @@ 'RPyThreadAcquireLock', 'RPyThreadReleaseLock', 'RPyThreadYield', 'RPyThreadGetStackSize', 'RPyThreadSetStackSize', + 'RPyOpaqueDealloc_ThreadLock', 'RPyThreadAfterFork'] ) @@ -52,6 +51,9 @@ c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], rffi.INT, threadsafe=False) # may add in a global list +c_thread_lock_dealloc = llexternal('RPyOpaqueDealloc_ThreadLock', [TLOCKP], + lltype.Void, + threadsafe=True) c_thread_acquirelock = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT], rffi.INT, threadsafe=True) # release the GIL @@ -156,6 +158,9 @@ return ll_lock def free_ll_lock(ll_lock): + c_thread_acquirelock(ll_lock, 0) + c_thread_releaselock(ll_lock) + c_thread_lock_dealloc(ll_lock) lltype.free(ll_lock, flavor='raw', track_allocation=False) def acquire_NOAUTO(ll_lock, flag): diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py --- a/pypy/module/thread/os_local.py +++ b/pypy/module/thread/os_local.py @@ -1,9 +1,7 @@ from pypy.module.thread import ll_thread as thread -from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp2app -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict +from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty, + descr_get_dict) class Local(Wrappable): diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py --- a/pypy/module/thread/os_thread.py +++ b/pypy/module/thread/os_thread.py @@ -6,7 +6,6 @@ from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import unwrap_spec, NoneNotWrapped, Arguments -from pypy.rlib.objectmodel import free_non_gc_object # Here are the steps performed to start a new thread: # diff --git a/pypy/module/thread/test/test_import_lock.py b/pypy/module/thread/test/test_import_lock.py --- a/pypy/module/thread/test/test_import_lock.py +++ b/pypy/module/thread/test/test_import_lock.py @@ -66,6 +66,9 @@ def test_lock(self, space, monkeypatch): from pypy.module.imp.importing import getimportlock, importhook + # Force importing the module _file now + space.builtin.get('file') + # Monkeypatch the import lock and add a counter importlock = getimportlock(space) original_acquire = importlock.acquire_lock diff --git a/pypy/module/unicodedata/generate_unicodedb.py b/pypy/module/unicodedata/generate_unicodedb.py --- a/pypy/module/unicodedata/generate_unicodedb.py +++ b/pypy/module/unicodedata/generate_unicodedb.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -import pprint - MAXUNICODE = 0x10FFFF # the value of sys.maxunicode of wide Python builds MANDATORY_LINE_BREAKS = ["BK", "CR", "LF", "NL"] # line break categories @@ -662,7 +660,7 @@ ''' def main(): - import re, sys + import sys from optparse import OptionParser infile = None outfile = sys.stdout diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -736,6 +736,8 @@ class W_DictMultiIterObject(W_Object): from pypy.objspace.std.dicttype import dictiter_typedef as typedef + _immutable_fields_ = ["iteratorimplementation", "itertype"] + def __init__(w_self, space, iteratorimplementation, itertype): w_self.space = space w_self.iteratorimplementation = iteratorimplementation diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -431,12 +431,17 @@ return None assert isinstance(lifeline, WeakrefLifeline) return lifeline + getweakref._cannot_really_call_random_things_ = True def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline - assert (isinstance(weakreflifeline, WeakrefLifeline) or - weakreflifeline is None) + assert isinstance(weakreflifeline, WeakrefLifeline) self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + setweakref._cannot_really_call_random_things_ = True + + def delweakref(self): + self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + delweakref._cannot_really_call_random_things_ = True class ObjectMixin(object): _mixin_ = True diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -36,6 +36,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None class W_SetObject(W_BaseSetObject): from pypy.objspace.std.settype import set_typedef as typedef diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -171,7 +171,7 @@ obj = c.instantiate() assert obj.getweakref() is None obj.setweakref(space, lifeline1) - obj.setweakref(space, None) + obj.delweakref() diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -532,6 +532,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None # ____________________________________________________________ # Initialization of type objects diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -482,6 +482,13 @@ key[2:]) cache[key] = s_value + # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass) + try: + graph = self.bookkeeper.position_key[0] + graph.func._dont_reach_me_in_del_ = True + except (TypeError, AttributeError): + pass + return annmodel.s_None def annotate_hooks(self, **kwds_s): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -83,6 +83,9 @@ t, rtyper, fngraph = self.gengraph(fn, [int]) + # added by compute_result_annotation() + assert fn._dont_reach_me_in_del_ == True + def getargs(func): for graph in t.graphs: if getattr(graph, 'func', None) is func: diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py --- a/pypy/rpython/extfuncregistry.py +++ b/pypy/rpython/extfuncregistry.py @@ -1,6 +1,6 @@ # this registry uses the new interface for external functions -from extfunc import register_external +from pypy.rpython.extfunc import register_external # ___________________________ # math functions @@ -30,24 +30,28 @@ export_name="ll_math.ll_math_%s" % name, sandboxsafe=True, llimpl=llimpl) -register_external(rfloat.isinf, [float], bool, - export_name="ll_math.ll_math_isinf", sandboxsafe=True, - llimpl=ll_math.ll_math_isinf) -register_external(rfloat.isnan, [float], bool, - export_name="ll_math.ll_math_isnan", sandboxsafe=True, - llimpl=ll_math.ll_math_isnan) -register_external(rfloat.isfinite, [float], bool, - export_name="ll_math.ll_math_isfinite", sandboxsafe=True, - llimpl=ll_math.ll_math_isfinite) -register_external(rfloat.copysign, [float, float], float, - export_name="ll_math.ll_math_copysign", sandboxsafe=True, - llimpl=ll_math.ll_math_copysign) -register_external(math.floor, [float], float, - export_name="ll_math.ll_math_floor", sandboxsafe=True, - llimpl=ll_math.ll_math_floor) -register_external(math.sqrt, [float], float, - export_name="ll_math.ll_math_sqrt", sandboxsafe=True, - llimpl=ll_math.ll_math_sqrt) +_register = [ # (module, [(method name, arg types, return type), ...], ...) + (rfloat, [ + ('isinf', [float], bool), + ('isnan', [float], bool), + ('isfinite', [float], bool), + ('copysign', [float, float], float), + ]), + (math, [ + ('floor', [float], float), + ('sqrt', [float], float), + ('log', [float], float), + ('log10', [float], float), + ]), +] +for module, methods in _register: + for name, arg_types, return_type in methods: + method_name = 'll_math_%s' % name + register_external(getattr(module, name), arg_types, return_type, + export_name='ll_math.%s' % method_name, + sandboxsafe=True, + llimpl=getattr(ll_math, method_name)) + complex_math_functions = [ ('frexp', [float], (float, int)), diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -172,17 +172,6 @@ assert max_n >= 0 ITEM = A.OF ctypes_item = get_ctypes_type(ITEM, delayed_builders) - # Python 2.5 ctypes can raise OverflowError on 64-bit builds - for n in [sys.maxint, 2**31]: - MAX_SIZE = n/64 - try: - PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item) - except OverflowError, e: - pass - else: - break - else: - raise e class CArray(ctypes.Structure): if not A._hints.get('nolength'): @@ -191,6 +180,7 @@ else: _fields_ = [('items', max_n * ctypes_item)] + @classmethod def _malloc(cls, n=None): if not isinstance(n, int): raise TypeError, "array length must be an int" @@ -199,10 +189,29 @@ if hasattr(bigarray, 'length'): bigarray.length = n return bigarray - _malloc = classmethod(_malloc) + + _ptrtype = None + + @classmethod + def _get_ptrtype(cls): + if cls._ptrtype: + return cls._ptrtype + # ctypes can raise OverflowError on 64-bit builds + for n in [sys.maxint, 2**31]: + cls.MAX_SIZE = n/64 + try: + cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item) + except OverflowError, e: + pass + else: + break + else: + raise e + return cls._ptrtype def _indexable(self, index): - assert index + 1 < MAX_SIZE + PtrType = self._get_ptrtype() + assert index + 1 < self.MAX_SIZE p = ctypes.cast(ctypes.pointer(self.items), PtrType) return p.contents diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -68,8 +68,9 @@ math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) - math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) +math_log = llexternal('log', [rffi.DOUBLE], rffi.DOUBLE) +math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -335,6 +336,16 @@ return x # +inf or nan +def ll_math_log(x): + if x <= 0: + raise ValueError("math domain error") + return math_log(x) + +def ll_math_log10(x): + if x <= 0: + raise ValueError("math domain error") + return math_log10(x) + # ____________________________________________________________ # # Default implementations @@ -373,7 +384,7 @@ unary_math_functions = [ 'acos', 'asin', 'atan', 'ceil', 'cos', 'cosh', 'exp', 'fabs', - 'sin', 'sinh', 'tan', 'tanh', 'log', 'log10', + 'sin', 'sinh', 'tan', 'tanh', 'acosh', 'asinh', 'atanh', 'log1p', 'expm1', ] unary_math_functions_can_overflow = [ diff --git a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py --- a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py +++ b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py @@ -1,6 +1,4 @@ - -""" Just another bunch of tests for llmath, run on top of llinterp -""" +"""Just another bunch of tests for llmath, run on top of llinterp.""" from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin from pypy.rpython.lltypesystem.module import ll_math @@ -39,7 +37,7 @@ assert self.interpret(f, [0.3, 0.4]) == f(0.3, 0.4) return next_test - for name in ll_math.unary_math_functions: + for name in ll_math.unary_math_functions + ['log', 'log10', 'sqrt']: func_name = 'test_%s' % (name,) next_test = new_unary_test(name) next_test.func_name = func_name diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py --- a/pypy/rpython/lltypesystem/rclass.py +++ b/pypy/rpython/lltypesystem/rclass.py @@ -400,6 +400,7 @@ assert len(s_func.descriptions) == 1 funcdesc, = s_func.descriptions graph = funcdesc.getuniquegraph() + self.check_graph_of_del_does_not_call_too_much(graph) FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void) destrptr = functionptr(FUNCTYPE, graph.name, graph=graph, diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -486,6 +486,11 @@ return True + def ll_startswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[0] == ch + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) @@ -503,6 +508,11 @@ return True + def ll_endswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[len(s.chars) - 1] == ch + @elidable def ll_find_char(s, ch, start, end): i = start diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -671,7 +671,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_arrayofstruct(self): - S1 = lltype.Struct('S1', ('x', lltype.Signed)) + S1 = lltype.Struct('S2', ('x', lltype.Signed)) A = lltype.Array(S1, hints={'nolength': True}) a = lltype.malloc(A, 5, flavor='raw') a[0].x = 100 diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,6 +34,13 @@ the GC in very small programs. Defaults to 8 times the nursery. + PYPY_GC_LOSTCARD If between two minor collections we see more than + 'PYPY_GC_LOSTCARD * length' writes to the same array, + then give up card marking and use the fast write + barrier instead. Defaults to 0.3333 for now. + Avoid values lower than 0.125: it is the growth + factor of list.append(). + PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -198,6 +205,9 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, + # See PYPY_GC_LOSTCARD. + "lost_card": 1.0 / 3.0, + # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -214,6 +224,7 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, + lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -235,6 +246,7 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 + self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -256,10 +268,6 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - class Cls(self.AddressStack): - def append(self2, addr): - assert addr not in self2.tolist() - self.AddressStack.append(self2, addr) self.objects_pointing_to_young = self.AddressStack() # # Similar to 'objects_pointing_to_young', but lists objects @@ -359,6 +367,10 @@ else: self.max_delta = 0.125 * env.get_total_memory() # + lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') + if lost_card > 0.0: + self.lost_card = lost_card + # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -653,7 +665,7 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only @@ -679,11 +691,15 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # (the loop is empty in C). + # followed by a Signed (the loop is empty in C). + if cardheadersize > 0: i = 0 - while i < cardheadersize: - llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) + while i < cardheadersize - WORD: + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Char)) i += 1 + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -907,14 +923,11 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # - size_gc_header = self.gcheaderbuilder.size_gc_header - p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: - p -= 1 - ll_assert(p.char[0] == '\x00', + i -= 1 + ll_assert(self.get_card(obj, i).char[0] == '\x00', "the card marker bits are not cleared") - i -= 1 # ---------- # Write barrier @@ -1012,6 +1025,8 @@ self.prebuilt_root_objects.append(addr_array) return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1029,10 +1044,6 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1061,6 +1072,8 @@ if not self.appears_to_be_young(newvalue): return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1073,10 +1086,6 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1094,11 +1103,36 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card(self, obj, byteindex): + def get_card_counter_addr(self, obj): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + return llarena.getfakearenaaddress(addr_byte) - WORD + def get_card(self, obj, byteindex): + return self.get_card_counter_addr(obj) + (~byteindex) + + def set_cards_flag(self, obj): + hdr = self.header(obj) + if hdr.tid & GCFLAG_CARDS_SET == 0: + # + # first time we set a card bit in this object + self.header(obj).tid |= GCFLAG_CARDS_SET + self.objects_with_cards_set.append(obj) + # + # initialize the counter with the array length and self.lost_card + typeid = self.get_type_id(obj) + offset_to_length = self.varsize_offset_to_length(typeid) + length = (obj + offset_to_length).signed[0] + counter = int(length * self.lost_card) + self.get_card_counter_addr(obj).signed[0] = counter + else: + # decrement the counter and if zero is reached, give up on + # card marking (up to the next collection). + addr = self.get_card_counter_addr(obj) + addr.signed[0] -= 1 + if addr.signed[0] < 0: + self.objects_pointing_to_young.append(obj) + hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1171,10 +1205,7 @@ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(dest_addr) - dest_hdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(dest_addr) # ---------- # Nursery collection @@ -1268,6 +1299,7 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) + p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1606,7 +1638,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 arena -= extra_words * WORD allocsize += extra_words * WORD # diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -525,6 +525,7 @@ def test_writebarrier_before_copy(self): from pypy.rpython.memory.gc import minimark largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 p_src = self.malloc(VAR, largeobj_size) p_dst = self.malloc(VAR, largeobj_size) # make them old @@ -564,6 +565,7 @@ from pypy.rpython.memory.gc import minimark tid = self.get_type_id(VAR) largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 addr_src = self.gc.external_malloc(tid, largeobj_size) addr_dst = self.gc.external_malloc(tid, largeobj_size) hdr_src = self.gc.header(addr_src) diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -433,7 +433,9 @@ "ll_streq": Meth([self.SELFTYPE_T], Bool), "ll_strcmp": Meth([self.SELFTYPE_T], Signed), "ll_startswith": Meth([self.SELFTYPE_T], Bool), + "ll_startswith_char": Meth([self.CHAR], Bool), "ll_endswith": Meth([self.SELFTYPE_T], Bool), + "ll_endswith_char": Meth([self.CHAR], Bool), "ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed), @@ -1429,10 +1431,18 @@ # NOT_RPYTHON return self._str.startswith(s._str) + def ll_startswith_char(self, s): + # NOT_RPYTHON + return self._str.startswith(s) + def ll_endswith(self, s): # NOT_RPYTHON return self._str.endswith(s._str) + def ll_endswith_char(self, s): + # NOT_RPYTHON + return self._str.endswith(s) + def ll_find(self, s, start, end): # NOT_RPYTHON if start > len(self._str): # workaround to cope with corner case diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -374,6 +374,43 @@ def can_ll_be_null(self, s_value): return s_value.can_be_none() + def check_graph_of_del_does_not_call_too_much(self, graph): + # RPython-level __del__() methods should not do "too much". + # In the PyPy Python interpreter, they usually do simple things + # like file.__del__() closing the file descriptor; or if they + # want to do more like call an app-level __del__() method, they + # enqueue the object instead, and the actual call is done later. + # + # Here, as a quick way to check "not doing too much", we check + # that from no RPython-level __del__() method we can reach a + # JitDriver. + # + # XXX wrong complexity, but good enough because the set of + # reachable graphs should be small + callgraph = self.rtyper.annotator.translator.callgraph.values() + seen = {graph: None} + while True: + oldlength = len(seen) + for caller, callee in callgraph: + if caller in seen and callee not in seen: + func = getattr(callee, 'func', None) + if getattr(func, '_dont_reach_me_in_del_', False): + lst = [str(callee)] + g = caller + while g: + lst.append(str(g)) + g = seen.get(g) + lst.append('') + raise TyperError("the RPython-level __del__() method " + "in %r calls:%s" % ( + graph, '\n\t'.join(lst[::-1]))) + if getattr(func, '_cannot_really_call_random_things_', + False): + continue + seen[callee] = caller + if len(seen) == oldlength: + break + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops, classcallhop=None): diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -667,7 +667,6 @@ res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res -ll_pop.oopspec = 'list.pop(l, index)' def ll_reverse(l): length = l.ll_length() diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py --- a/pypy/rpython/rstr.py +++ b/pypy/rpython/rstr.py @@ -81,16 +81,30 @@ return super(AbstractStringRepr, self).rtype_is_true(hop) def rtype_method_startswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_startswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_startswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_endswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_endswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_endswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_find(self, hop, reverse=False): # XXX binaryop diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -7,6 +7,7 @@ from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.rpython.error import TyperError from pypy.objspace.flow.model import summary class EmptyBase(object): @@ -1022,6 +1023,24 @@ assert destrptra is not None assert destrptrb is not None + def test_del_forbidden(self): + class A(object): + def __del__(self): + self.foo() + def foo(self): + self.bar() + def bar(self): + pass + bar._dont_reach_me_in_del_ = True + def f(): + a = A() + a.foo() + a.bar() + t = TranslationContext() + t.buildannotator().build_types(f, []) + e = py.test.raises(TyperError, t.buildrtyper().specialize) + print e.value + def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int class FooBar(object): diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -227,6 +227,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_startswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].startswith(const('o')) + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_endswith(self): const = self.const def fn(i, j): @@ -238,6 +247,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_endswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].endswith(const('e')) + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_find(self): const = self.const def fn(i, j): diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,10 +1,13 @@ import re, sys -from pypy.jit.metainterp.resoperation import rop, opname +from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser +from pypy.tool.logparser import parse_log_file, extract_category class Op(object): bridge = None + offset = None + asm = None def __init__(self, name, args, res, descr): self.name = name @@ -54,10 +57,53 @@ Op = Op use_mock_model = True + def postprocess(self, loop, backend_dump=None, backend_tp=None, + dump_start=0): + if backend_dump is not None: + raw_asm = self._asm_disassemble(backend_dump.decode('hex'), + backend_tp, dump_start) + asm = [] + start = 0 + for elem in raw_asm: + if len(elem.split("\t")) != 3: + continue + adr, _, v = elem.split("\t") + if not start: + start = int(adr.strip(":"), 16) + ofs = int(adr.strip(":"), 16) - start + if ofs >= 0: + asm.append((ofs, v.strip("\n"))) + asm_index = 0 + for i, op in enumerate(loop.operations): + end = 0 + j = i + 1 + while end == 0: + if j == len(loop.operations): + end = loop.last_offset + break + if loop.operations[j].offset is None: + j += 1 + else: + end = loop.operations[j].offset + if op.offset is not None: + while asm[asm_index][0] < op.offset: + asm_index += 1 + end_index = asm_index + while asm[end_index][0] < end and end_index < len(asm) - 1: + end_index += 1 + op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) + return loop + + def _asm_disassemble(self, d, origin_addr, tp): + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + return list(machine_code_dump(d, tp, origin_addr)) + @classmethod - def parse_from_input(cls, input): - return cls(input, None, {}, 'lltype', None, - nonstrict=True).parse() + def parse_from_input(cls, input, **kwds): + parser = cls(input, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + return parser.postprocess(loop, **kwds) def parse_args(self, opname, argspec): if not argspec.strip(): @@ -284,3 +330,51 @@ res.append(op) i += 1 return res + + +def import_log(logname, ParserCls=SimpleParser): + log = parse_log_file(logname) + addrs = {} + for entry in extract_category(log, 'jit-backend-addr'): + m = re.search('bootstrap ([-\da-f]+)', entry) + if not m: + # a bridge + m = re.search('has address ([-\da-f]+)', entry) + addr = int(m.group(1), 16) + entry = entry.lower() + m = re.search('guard \d+', entry) + name = m.group(0) + else: + name = entry[:entry.find('(') - 1].lower() + addr = int(m.group(1), 16) + addrs.setdefault(addr, []).append(name) + dumps = {} + for entry in extract_category(log, 'jit-backend-dump'): + backend, _, dump, _ = entry.split("\n") + _, addr, _, data = re.split(" +", dump) + backend_name = backend.split(" ")[1] + addr = int(addr[1:], 16) + if addr in addrs and addrs[addr]: + name = addrs[addr].pop(0) # they should come in order + dumps[name] = (backend_name, addr, data) + loops = [] + for entry in extract_category(log, 'jit-log-opt'): + parser = ParserCls(entry, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + comm = loop.comment + comm = comm.lower() + if comm.startswith('# bridge'): + m = re.search('guard \d+', comm) + name = m.group(0) + else: + name = comm[2:comm.find(':')-1] + if name in dumps: + bname, start_ofs, dump = dumps[name] + loop.force_asm = (lambda dump=dump, start_ofs=start_ofs, + bname=bname, loop=loop: + parser.postprocess(loop, backend_tp=bname, + backend_dump=dump, + dump_start=start_ofs)) + loops.append(loop) + return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -0,0 +1,38 @@ +[11f210b47027] {jit-backend +[11f210b900f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 +[11f210b949b3] jit-backend-dump} +[11f210b949b4] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab188] jit-backend-addr} +[11f210bab189] jit-backend} +[11f210bacbb7] {jit-log-opt-loop +# Loop 0 : loop with 19 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 INPLACE_ADD') ++179: i8 = int_add(i4, 1) +debug_merge_point(0, ' #28 STORE_FAST') +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++183: i10 = getfield_raw(40564608, descr=) ++191: i12 = int_sub(i10, 1) ++195: setfield_raw(40564608, i12, descr=) ++203: i14 = int_lt(i12, 0) +guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++213: jump(p0, p1, p2, p3, i8, descr=) ++218: --end of the loop-- +[11f210c17981] jit-log-opt-loop} +[11f210fb1d21] {jit-backend-counts +0:8965 +1:2 +[11f210fb381b] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest2.log @@ -0,0 +1,301 @@ +[1f5e7f69779] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f7fe75] jit-backend-dump} +[1f5e7f84fc4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f87ac1] jit-backend-dump} +[1f5e7f8a0b4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b08a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f8da6b] jit-backend-dump} +[1f5e7f8f4f6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b13d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f92b83] jit-backend-dump} +[1f5e7f95b99] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 +[1f5e7f988d0] jit-backend-dump} +[1f5e7fa16fb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b28e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 +[1f5e7fa47ac] jit-backend-dump} +[1f5e7fab3a4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 +[1f5e7faf1ca] jit-backend-dump} +[1f5e7fb0813] {jit-backend-counts +[1f5e7fb0f61] jit-backend-counts} +[1f5fd38be3e] {jit-backend +[1f5fe729336] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB30B00C0A897F00004D8B334983C60149BB30B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030300000049BB00B0A007897F000041FFD34440484C3D39030400000049BB00B0A007897F000041FFD34440484C3907070305000000 +[1f5fe73276a] jit-backend-dump} +[1f5fe73438f] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f8907a0b45d to 7f8907a0b4c3 (bootstrap 7f8907a0b3d5) +[1f5fe7369af] jit-backend-addr} +[1f5fe737940] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3e5 +0 50FFFFFF +[1f5fe74b40e] jit-backend-dump} +[1f5fe74c63d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b484 +0 95000000 +[1f5fe74da6a] jit-backend-dump} +[1f5fe74e438] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 9B000000 +[1f5fe74f513] jit-backend-dump} +[1f5fe74fd2e] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b4b7 +0 91000000 +[1f5fe750d8c] jit-backend-dump} +[1f5fe75373f] jit-backend} +[1f5fe755abc] {jit-log-opt-loop +# Loop 0 : loop with 26 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 1) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f5fe92b8af] jit-log-opt-loop} +[1f5fe944ae5] {jit-backend +[1f5fee20651] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b565 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C254010000000049BB38B00C0A897F0000498B0B4883C10149BB38B00C0A897F000049890B4983F8010F85000000004883FE017206813E980700000F85000000004983FA000F850000000049BBA8F0B407897F00004D39DC0F8500000000488B56084881FA102700000F8D000000004989D44883E2024883FA000F85000000004983C403488B1425A0536B024883EA0148891425A0536B024883FA000F8C000000004C89BD70FFFFFF4C89B568FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4D89E749BB5DB4A007897F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DAE9CCFEFFFF49BB00B0A007897F000041FFD321383C343029241D180C08030600000049BB00B0A007897F000041FFD3383C18343029240C08030700000049BB00B0A007897F000041FFD329383C3430241808030800000049BB00B0A007897F000041FFD3383C3034241808030900000049BB00B0A007897F000041FFD3383C183424030A00000049BB00B0A007897F000041FFD3383C34241809030B00000049BB00B0A007897F000041FFD3383C34243107030C000000 +[1f5fee2e673] jit-backend-dump} +[1f5fee2f38d] {jit-backend-addr +Loop 1 ( #9 LOAD_FAST) has address 7f8907a0b631 to 7f8907a0b6f8 (bootstrap 7f8907a0b565) +[1f5fee312e3] jit-backend-addr} +[1f5fee320ed] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b575 +0 50FFFFFF +[1f5fee3e903] jit-backend-dump} +[1f5fee3fbff] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b655 +0 0C010000 +[1f5fee41579] jit-backend-dump} +[1f5fee421af] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b667 +0 17010000 +[1f5fee43835] jit-backend-dump} +[1f5fee44261] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b671 +0 28010000 +[1f5fee457c1] jit-backend-dump} +[1f5fee461a5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b684 +0 2F010000 +[1f5fee475d3] jit-backend-dump} +[1f5fee47f57] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b695 +0 37010000 +[1f5fee4933d] jit-backend-dump} +[1f5fee49cd9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6a6 +0 3D010000 +[1f5fee4b0ad] jit-backend-dump} +[1f5fee4ba4f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6c8 +0 33010000 +[1f5fee4cf61] jit-backend-dump} +[1f5fee4dc45] jit-backend} +[1f5fee4f3a9] {jit-log-opt-loop +# Loop 1 : entry bridge with 31 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10] +debug_merge_point(0, ' #9 LOAD_FAST') ++234: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10] ++244: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10] ++262: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p10] +debug_merge_point(0, ' #12 LOAD_CONST') ++272: guard_value(p3, ConstPtr(ptr14), descr=) [p1, p0, p3, p2, p5, p8, p10] +debug_merge_point(0, ' #15 COMPARE_OP') ++291: i15 = getfield_gc_pure(p8, descr=) ++295: i17 = int_lt(i15, 10000) +guard_true(i17, descr=) [p1, p0, p8, p2, p5] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++308: i19 = int_and(i15, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++315: i20 = int_is_true(i19) +guard_false(i20, descr=) [p1, p0, p2, p5, p8, i19] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++325: i22 = int_add(i15, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++329: i24 = getfield_raw(40588192, descr=) ++337: i26 = int_sub(i24, 1) ++341: setfield_raw(40588192, i26, descr=) ++349: i28 = int_lt(i26, 0) +guard_false(i28, descr=) [p1, p0, p2, p5, i22, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++359: jump(p0, p1, p2, p5, i22, descr=) ++403: --end of the loop-- +[1f60036d952] jit-log-opt-loop} +[1f600719a74] {jit-backend +[1f600759dac] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b817 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB40B00C0A897F00004D8B334983C60149BB40B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF024C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030D00000049BB00B0A007897F000041FFD34440484C3D39030E00000049BB00B0A007897F000041FFD34440484C390707030F000000 +[1f60076fd90] jit-backend-dump} +[1f600770f30] {jit-backend-addr +Loop 2 ( #9 LOAD_FAST) has address 7f8907a0b89f to 7f8907a0b905 (bootstrap 7f8907a0b817) +[1f6007730fc] jit-backend-addr} +[1f600773fde] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b827 +0 50FFFFFF +[1f600775c76] jit-backend-dump} +[1f600776a38] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8c6 +0 95000000 +[1f600778112] jit-backend-dump} +[1f600778b8c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8d7 +0 9B000000 +[1f60077a04a] jit-backend-dump} +[1f60077aa6a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8f9 +0 91000000 +[1f60077bf10] jit-backend-dump} +[1f60077cc24] jit-backend} +[1f60077e094] {jit-log-opt-loop +# Loop 2 : loop with 25 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 2) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f6007a567c] jit-log-opt-loop} +[1f600802cd6] {jit-backend +[1f600862dd8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9b7 +0 488DA50000000049BB48B00C0A897F00004D8B3B4983C70149BB48B00C0A897F00004D893B4D89F74983C6010F80000000004C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C00000000488B0425704F3D01488D5010483B1425784F3D01761A49BB10B2A007897F000041FFD349BB8EB2A007897F000041FFD348C7009807000048891425704F3D014C89700848898550FFFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBA8F0B407897F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00100000048C7C709000000488BB550FFFFFF48C7C30000000048C7C20000000049BB31B6A007897F000041FFE349BB00B0A007897F000041FFD3444039484C3D031000000049BB00B0A007897F000041FFD34440484C39070311000000 +[1f60086ba5a] jit-backend-dump} +[1f60086d36e] {jit-backend-addr +Bridge out of guard 4 has address 7f8907a0b9b7 to 7f8907a0bab1 +[1f60086ffd2] jit-backend-addr} +[1f600870dca] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9ba +0 C0FEFFFF +[1f60087281c] jit-backend-dump} +[1f600873506] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 C8000000 +[1f600874b44] jit-backend-dump} +[1f6008754d4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0ba03 +0 C2000000 +[1f600876956] jit-backend-dump} +[1f600877b1a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 1E050000 +[1f600878f4e] jit-backend-dump} +[1f600884c12] jit-backend} +[1f60088780a] {jit-log-opt-bridge +# bridge out of Guard 4 with 16 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #31 LOAD_FAST') +debug_merge_point(0, ' #34 LOAD_CONST') +debug_merge_point(0, ' #37 INPLACE_ADD') ++37: i7 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i7, p2, p3, i5] +debug_merge_point(0, ' #38 STORE_FAST') +debug_merge_point(0, ' #41 JUMP_ABSOLUTE') ++50: i9 = getfield_raw(40588192, descr=) ++58: i11 = int_sub(i9, 1) ++62: setfield_raw(40588192, i11, descr=) ++70: i13 = int_lt(i11, 0) +guard_false(i13, descr=) [p0, p1, p2, p3, i7, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++80: p16 = new_with_vtable(ConstClass(W_IntObject)) ++143: setfield_gc(p16, i7, descr=) ++147: jump(p1, p0, p2, ConstPtr(ptr17), 0, p3, 1, 9, p16, ConstPtr(ptr21), ConstPtr(ptr22), descr=) ++250: --end of the loop-- +[1f6008aa976] jit-log-opt-bridge} +[1f600912c98] {jit-backend-counts +0:1982 +1:1985 +2:0 +3:1782 +[1f600916544] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,12 +1,11 @@ -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, Const -from pypy.tool.jitlogparser.parser import SimpleParser, TraceForOpcode, Function,\ - adjust_bridges +from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, + Function, adjust_bridges, + import_log) from pypy.tool.jitlogparser.storage import LoopStorage -import py +import py, sys -def parse(input): - return SimpleParser.parse_from_input(input) +def parse(input, **kwds): + return SimpleParser.parse_from_input(input, **kwds) def test_parse(): @@ -111,6 +110,8 @@ assert res.chunks[1].lineno == 3 def test_linerange(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] @@ -125,6 +126,8 @@ assert res.lineset == set([7, 8, 9]) def test_linerange_notstarts(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] @@ -179,3 +182,46 @@ ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] assert chunk.bytecode_name == 'StrLiteralSearch' + +def test_parsing_assembler(): + backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" + dump_start = 0x7f3b0b2e63d5 + loop = parse(""" + # Loop 0 : loop with 19 ops + [p0, p1, p2, p3, i4] + debug_merge_point(0, ' #15 COMPARE_OP') + +166: i6 = int_lt(i4, 10000) + guard_true(i6, descr=) [p1, p0, p2, p3, i4] + debug_merge_point(0, ' #27 INPLACE_ADD') + +179: i8 = int_add(i4, 1) + debug_merge_point(0, ' #31 JUMP_ABSOLUTE') + +183: i10 = getfield_raw(40564608, descr=) + +191: i12 = int_sub(i10, 1) + +195: setfield_raw(40564608, i12, descr=) + +203: i14 = int_lt(i12, 0) + guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] + debug_merge_point(0, ' #9 LOAD_FAST') + +213: jump(p0, p1, p2, p3, i8, descr=) + +218: --end of the loop--""", backend_dump=backend_dump, + dump_start=dump_start, + backend_tp='x86_64') + cmp = loop.operations[1] + assert 'jge' in cmp.asm + assert '0x2710' in cmp.asm + assert 'jmp' in loop.operations[-1].asm + +def test_import_log(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest.log'))) + for loop in loops: + loop.force_asm() + assert 'jge' in loops[0].operations[3].asm + +def test_import_log_2(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest2.log'))) + for loop in loops: + loop.force_asm() + assert 'cmp' in loops[1].operations[1].asm + # bridge + assert 'jo' in loops[3].operations[3].asm diff --git a/pypy/tool/nullpath.py b/pypy/tool/nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/nullpath.py @@ -0,0 +1,12 @@ +import py + +class NullPyPathLocal(py.path.local): + + def join(self, *args): + return self.__class__(py.path.local.join(self, *args)) + + def open(self, mode): + return open('/dev/null', mode) + + def __repr__(self): + return py.path.local.__repr__(self) + ' [fake]' diff --git a/pypy/tool/test/test_nullpath.py b/pypy/tool/test/test_nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/test/test_nullpath.py @@ -0,0 +1,16 @@ +import sys +import py +from pypy.tool.nullpath import NullPyPathLocal + +def setup_module(): + if 'posix' not in sys.builtin_module_names: + py.test.skip('posix only') + +def test_nullpath(tmpdir): + path = NullPyPathLocal(tmpdir) + assert repr(path).endswith('[fake]') + foo_txt = path.join('foo.txt') + assert isinstance(foo_txt, NullPyPathLocal) + # + f = foo_txt.open('w') + assert f.name == '/dev/null' diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1824,6 +1824,11 @@ __gccallshapes: """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) + print >> output, """\ + #if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits + #endif + """ def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -13,6 +13,7 @@ from pypy.rpython.typesystem import getfunctionptr from pypy.translator.c import gc from pypy.rlib import exports +from pypy.tool.nullpath import NullPyPathLocal def import_module_from_directory(dir, modname): file, pathname, description = imp.find_module(modname, [str(dir)]) @@ -237,6 +238,8 @@ self.modulename = uniquemodulename('testing') modulename = self.modulename targetdir = udir.ensure(modulename, dir=1) + if self.config.translation.dont_write_c_files: + targetdir = NullPyPathLocal(targetdir) self.targetdir = targetdir defines = defines.copy() @@ -688,11 +691,37 @@ def getothernodes(self): return self.othernodes[:] + def getbasecfilefornode(self, node, basecname): + # For FuncNode instances, use the python source filename (relative to + # the top directory): + if hasattr(node.obj, 'graph'): + g = node.obj.graph + # Lookup the filename from the function. + # However, not all FunctionGraph objs actually have a "func": + if hasattr(g, 'func'): + if g.filename.endswith('.py'): + localpath = py.path.local(g.filename) + pypkgpath = localpath.pypkgpath() + if pypkgpath: + relpypath = localpath.relto(pypkgpath) + return relpypath.replace('.py', '.c') + return basecname + def splitnodesimpl(self, basecname, nodes, nextra, nbetween, split_criteria=SPLIT_CRITERIA): + # Gather nodes by some criteria: + nodes_by_base_cfile = {} + for node in nodes: + c_filename = self.getbasecfilefornode(node, basecname) + if c_filename in nodes_by_base_cfile: + nodes_by_base_cfile[c_filename].append(node) + else: + nodes_by_base_cfile[c_filename] = [node] + # produce a sequence of nodes, grouped into files # which have no more than SPLIT_CRITERIA lines - iternodes = iter(nodes) + for basecname in nodes_by_base_cfile: + iternodes = iter(nodes_by_base_cfile[basecname]) done = [False] def subiter(): used = nextra @@ -918,11 +947,13 @@ ] return eci.merge(ExternalCompilationInfo(separate_module_files=files)) + def gen_source_standalone(database, modulename, targetdir, eci, entrypointname, defines={}): assert database.standalone if isinstance(targetdir, str): targetdir = py.path.local(targetdir) + filename = targetdir.join(modulename + '.c') f = filename.open('w') incfilename = targetdir.join('common_header.h') @@ -976,6 +1007,7 @@ assert not database.standalone if isinstance(targetdir, str): targetdir = py.path.local(targetdir) + filename = targetdir.join(modulename + '.c') f = filename.open('w') incfilename = targetdir.join('common_header.h') diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py --- a/pypy/translator/c/test/test_genc.py +++ b/pypy/translator/c/test/test_genc.py @@ -13,6 +13,7 @@ from pypy.translator.backendopt.all import backend_optimizations from pypy.translator.interactive import Translation from pypy.rlib.entrypoint import entrypoint +from pypy.tool.nullpath import NullPyPathLocal def compile(fn, argtypes, view=False, gcpolicy="ref", backendopt=True, annotatorpolicy=None): @@ -63,6 +64,22 @@ py.test.raises(Exception, f1, "world") # check that it's really typed + +def test_dont_write_source_files(): + def f(x): + return x*2 + t = TranslationContext() + t.buildannotator().build_types(f, [int]) + t.buildrtyper().specialize() + + t.config.translation.countmallocs = True + t.config.translation.dont_write_c_files = True + builder = genc.CExtModuleBuilder(t, f, config=t.config) + builder.generate_source() + assert isinstance(builder.targetdir, NullPyPathLocal) + assert builder.targetdir.listdir() == [] + + def test_simple_lambda(): f = lambda x: x*2 t = TranslationContext() diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -55,6 +55,13 @@ data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + # Verify that the generated C files have sane names: + gen_c_files = [str(f) for f in cbuilder.extrafiles] + for expfile in ('rlib_rposix.c', + 'rpython_lltypesystem_rstr.c', + 'translator_c_test_test_standalone.c'): + assert cbuilder.targetdir.join(expfile) in gen_c_files + def test_print(self): def entry_point(argv): print "hello simpler world" diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs --- a/pypy/translator/cli/src/pypylib.cs +++ b/pypy/translator/cli/src/pypylib.cs @@ -615,11 +615,29 @@ return s1.StartsWith(s2); } + public static bool ll_startswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[0] == c; + } + public static bool ll_endswith(string s1, string s2) { return s1.EndsWith(s2); } + public static bool ll_endswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[s.Length - 1] == c; + } + public static int ll_find(string s1, string s2, int start, int stop) { if (stop > s1.Length) diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -799,6 +799,20 @@ return str.substring(start,start+cnt); } + public static boolean ll_startswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(0) == c; + } + + public static boolean ll_endswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(str.length() - 1) == c; + } + // ---------------------------------------------------------------------- // StringBuffer From noreply at buildbot.pypy.org Tue Jul 19 21:50:34 2011 From: noreply at buildbot.pypy.org (ademan) Date: Tue, 19 Jul 2011 21:50:34 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Merge default. (Again) Message-ID: <20110719195034.2F771829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45750:f4898b2258db Date: 2011-07-19 12:36 -0700 http://bitbucket.org/pypy/pypy/changeset/f4898b2258db/ Log: Merge default. (Again) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -5,10 +5,9 @@ from pypy.jit.codewriter import support from pypy.jit.codewriter.jitcode import JitCode -from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer -from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer -from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze -from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection +from pypy.jit.codewriter.effectinfo import (VirtualizableAnalyzer, + QuasiImmutAnalyzer, CanReleaseGILAnalyzer, effectinfo_from_writeanalyze, + EffectInfo, CallInfoCollection) from pypy.translator.simplify import get_funcobj, get_functype from pypy.rpython.lltypesystem import lltype, llmemory from pypy.translator.backendopt.canraise import RaiseAnalyzer @@ -32,6 +31,7 @@ self.readwrite_analyzer = ReadWriteAnalyzer(translator) self.virtualizable_analyzer = VirtualizableAnalyzer(translator) self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator) + self.canreleasegil_analyzer = CanReleaseGILAnalyzer(translator) # for index, jd in enumerate(jitdrivers_sd): jd.index = index @@ -219,7 +219,9 @@ assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect - can_invalidate = self.quasiimmut_analyzer.analyze(op) + can_release_gil = self.canreleasegil_analyzer.analyze(op) + # can_release_gil implies can_invalidate + can_invalidate = can_release_gil or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE @@ -235,7 +237,7 @@ # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, - oopspecindex, can_invalidate) + oopspecindex, can_invalidate, can_release_gil) # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -79,13 +79,15 @@ write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, - can_invalidate=False): + can_invalidate=False, can_release_gil=False): key = (frozenset(readonly_descrs_fields), frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, - oopspecindex) + oopspecindex, + can_invalidate, + can_release_gil) if key in cls._cache: return cls._cache[key] result = object.__new__(cls) @@ -100,6 +102,7 @@ result.write_descrs_arrays = write_descrs_arrays result.extraeffect = extraeffect result.can_invalidate = can_invalidate + result.can_release_gil = can_release_gil result.oopspecindex = oopspecindex cls._cache[key] = result return result @@ -111,12 +114,13 @@ return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE def has_random_effects(self): - return self.oopspecindex == self.OS_LIBFFI_CALL + return self.oopspecindex == self.OS_LIBFFI_CALL or self.can_release_gil def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, - can_invalidate=False): + can_invalidate=False, + can_release_gil=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: return None @@ -158,7 +162,8 @@ write_descrs_arrays, extraeffect, oopspecindex, - can_invalidate) + can_invalidate, + can_release_gil) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: @@ -194,6 +199,16 @@ def analyze_simple_operation(self, op, graphinfo): return op.opname == 'jit_force_quasi_immutable' +class CanReleaseGILAnalyzer(BoolGraphAnalyzer): + def analyze_direct_call(self, graph, seen=None): + releases_gil = False + if hasattr(graph, "func") and hasattr(graph.func, "_ptr"): + releases_gil = graph.func._ptr._obj.releases_gil + return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen) + + def analyze_simple_operation(self, op, graphinfo): + return False + # ____________________________________________________________ class CallInfoCollection(object): diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -395,7 +395,7 @@ ('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed), ('int_abs', [lltype.Signed], lltype.Signed), ('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float), - ] +] class LLtypeHelpers: diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py --- a/pypy/jit/codewriter/test/test_call.py +++ b/pypy/jit/codewriter/test/test_call.py @@ -1,6 +1,6 @@ import py from pypy.objspace.flow.model import SpaceOperation, Constant, Variable -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.unsimplify import varoftype from pypy.rlib import jit from pypy.jit.codewriter.call import CallControl @@ -171,3 +171,24 @@ def test_jit_force_virtualizable_effectinfo(): py.test.skip("XXX add a test for CallControl.getcalldescr() -> EF_xxx") + +def test_releases_gil_analyzer(): + from pypy.jit.backend.llgraph.runner import LLtypeCPU + + T = rffi.CArrayPtr(rffi.TIME_T) + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + + @jit.dont_look_inside + def f(): + return external(lltype.nullptr(T.TO)) + + rtyper = support.annotate(f, []) + jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) + cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) + res = cc.find_all_graphs(FakePolicy()) + + [f_graph] = [x for x in res if x.func is f] + [block, _] = list(f_graph.iterblocks()) + [op] = block.operations + call_descr = cc.getcalldescr(op) + assert call_descr.extrainfo.can_release_gil \ No newline at end of file diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -61,7 +61,6 @@ optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble, retraced) - if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -11,7 +11,7 @@ from pypy import conftest from pypy.rlib.rarithmetic import ovfcheck from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -1616,8 +1616,6 @@ assert res == 1 def test_raw_malloc_and_access(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Signed) def f(n): @@ -1631,8 +1629,6 @@ assert res == 10 def test_raw_malloc_and_access_float(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Float) def f(n, f): @@ -2619,5 +2615,41 @@ self.meta_interp(f, [], enable_opts='') self.check_loops(new_with_vtable=1) + def test_release_gil_flush_heap_cache(self): + T = rffi.CArrayPtr(rffi.TIME_T) + + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + # Not a real lock, has all the same properties with respect to GIL + # release though, so good for this test. + class Lock(object): + @dont_look_inside + def acquire(self): + external(lltype.nullptr(T.TO)) + @dont_look_inside + def release(self): + external(lltype.nullptr(T.TO)) + class X(object): + def __init__(self, idx): + self.field = idx + @dont_look_inside + def get_obj(z): + return X(z) + myjitdriver = JitDriver(greens=[], reds=["n", "l", "z", "lock"]) + def f(n, z): + lock = Lock() + l = 0 + while n > 0: + myjitdriver.jit_merge_point(lock=lock, l=l, n=n, z=z) + x = get_obj(z) + l += x.field + lock.acquire() + # This must not reuse the previous one. + n -= x.field + lock.release() + return n + res = self.meta_interp(f, [10, 1]) + self.check_loops(getfield_gc=2) + + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -69,8 +69,6 @@ [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) -math_log = llexternal('log', [rffi.DOUBLE], rffi.DOUBLE) -math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -222,10 +220,6 @@ return (fracpart, intpart) -def ll_math_copysign(x, y): - return math_copysign(x, y) # no error checking needed - - def ll_math_fmod(x, y): if isinf(y): if isinf(x): diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -102,19 +102,6 @@ else: callbackholder = None - funcptr = lltype.functionptr(ext_type, name, external='C', - compilation_info=compilation_info, - _callable=_callable, - _safe_not_sandboxed=sandboxsafe, - _debugexc=True, # on top of llinterp - canraise=False, - **kwds) - if isinstance(_callable, ll2ctypes.LL2CtypesCallable): - _callable.funcptr = funcptr - - if _nowrapper: - return funcptr - if threadsafe in (False, True): # invoke the around-handlers, which release the GIL, if and only if # the C function is thread-safe. @@ -125,6 +112,21 @@ # sandboxsafe is a hint for "too-small-ness" (e.g. math functions). invoke_around_handlers = not sandboxsafe + funcptr = lltype.functionptr(ext_type, name, external='C', + compilation_info=compilation_info, + _callable=_callable, + _safe_not_sandboxed=sandboxsafe, + _debugexc=True, # on top of llinterp + canraise=False, + releases_gil=invoke_around_handlers, + **kwds) + if isinstance(_callable, ll2ctypes.LL2CtypesCallable): + _callable.funcptr = funcptr + + if _nowrapper: + return funcptr + + if invoke_around_handlers: # The around-handlers are releasing the GIL in a threaded pypy. # We need tons of care to ensure that no GC operation and no From noreply at buildbot.pypy.org Tue Jul 19 21:50:35 2011 From: noreply at buildbot.pypy.org (ademan) Date: Tue, 19 Jul 2011 21:50:35 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Fixed test and removed useless need_result_type for ll operations Message-ID: <20110719195035.5D94A829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45751:03db3de729eb Date: 2011-07-19 12:50 -0700 http://bitbucket.org/pypy/pypy/changeset/03db3de729eb/ Log: Fixed test and removed useless need_result_type for ll operations diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py --- a/pypy/rlib/test/test_rerased.py +++ b/pypy/rlib/test/test_rerased.py @@ -283,6 +283,8 @@ def castable(self, TO, var): return lltype.castable(TO, lltype.typeOf(var)) > 0 +from pypy.rpython.ootypesystem.ootype import Object + class TestOOtype(BaseTestRErased, OORtypeMixin): ERASED_TYPE = Object UNERASED_TYPE = OBJECT diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -1945,11 +1945,9 @@ def oobox_int(i): return Box(i) -oobox_int.need_result_type = True def oounbox_int(x): return x.i -oounbox_int.need_result_type = True def oostring(obj, base): """ From noreply at buildbot.pypy.org Wed Jul 20 00:38:50 2011 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 20 Jul 2011 00:38:50 +0200 (CEST) Subject: [pypy-commit] pypy default: export missing symbols Message-ID: <20110719223850.2040C829B8@wyvern.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r45752:e490f90f2aa1 Date: 2011-07-19 15:37 -0700 http://bitbucket.org/pypy/pypy/changeset/e490f90f2aa1/ Log: export missing symbols diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) From notifications-noreply at bitbucket.org Wed Jul 20 04:28:21 2011 From: notifications-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 02:28:21 -0000 Subject: [pypy-commit] Notification: pypy Message-ID: <20110720022821.17718.96616@bitbucket02.managed.contegix.com> You have received a notification from lambacck. Hi, I forked pypy. My fork is at https://bitbucket.org/lambacck/pypy. -- Change your notification settings at https://bitbucket.org/account/notifications/ From pullrequests-noreply at bitbucket.org Wed Jul 20 04:40:31 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 02:40:31 -0000 Subject: [pypy-commit] [OPEN] Pull request #3 for pypy: Add the undocumented _PyString_Join function to cpyext Message-ID: A new pull request has been opened by lambacck. lambacck/pypy has changes to be pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/3/add-the-undocumented-_pystring_join Title: Add the undocumented _PyString_Join function to cpyext Also included is a test. I modeled it after the PyUnicode_Join function which does essentially the same thing and has the same function signature. -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From pullrequests-noreply at bitbucket.org Wed Jul 20 04:58:19 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 02:58:19 -0000 Subject: [pypy-commit] [ACCEPTED] Pull request #3 for pypy: Add the undocumented _PyString_Join function to cpyext In-Reply-To: References: Message-ID: <20110720025819.6345.88961@bitbucket03.managed.contegix.com> Pull request #3 has been accepted by Alex Gaynor. Changes in lambacck/pypy have been pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/3/add-the-undocumented-_pystring_join -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From pullrequests-noreply at bitbucket.org Wed Jul 20 04:58:19 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 02:58:19 -0000 Subject: [pypy-commit] [ACCEPTED] Pull request #3 for pypy: Add the undocumented _PyString_Join function to cpyext In-Reply-To: References: Message-ID: <20110720025819.3853.47626@bitbucket02.managed.contegix.com> Pull request #3 has been accepted by Alex Gaynor. Changes in lambacck/pypy have been pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/3/add-the-undocumented-_pystring_join -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From pullrequests-noreply at bitbucket.org Wed Jul 20 04:58:20 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 02:58:20 -0000 Subject: [pypy-commit] [ACCEPTED] Pull request #3 for pypy: Add the undocumented _PyString_Join function to cpyext In-Reply-To: References: Message-ID: <20110720025820.16027.14256@bitbucket02.managed.contegix.com> Pull request #3 has been accepted by Alex Gaynor. Changes in lambacck/pypy have been pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/3/add-the-undocumented-_pystring_join -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From pullrequests-noreply at bitbucket.org Wed Jul 20 04:58:20 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 02:58:20 -0000 Subject: [pypy-commit] [ACCEPTED] Pull request #3 for pypy: Add the undocumented _PyString_Join function to cpyext In-Reply-To: References: Message-ID: <20110720025820.10247.23057@bitbucket03.managed.contegix.com> Pull request #3 has been accepted by Alex Gaynor. Changes in lambacck/pypy have been pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/3/add-the-undocumented-_pystring_join -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From pullrequests-noreply at bitbucket.org Wed Jul 20 04:58:20 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 02:58:20 -0000 Subject: [pypy-commit] [ACCEPTED] Pull request #3 for pypy: Add the undocumented _PyString_Join function to cpyext In-Reply-To: References: Message-ID: <20110720025820.12329.79811@bitbucket03.managed.contegix.com> Pull request #3 has been accepted by Alex Gaynor. Changes in lambacck/pypy have been pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/3/add-the-undocumented-_pystring_join -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From pullrequests-noreply at bitbucket.org Wed Jul 20 04:58:21 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 02:58:21 -0000 Subject: [pypy-commit] [ACCEPTED] Pull request #3 for pypy: Add the undocumented _PyString_Join function to cpyext In-Reply-To: References: Message-ID: <20110720025821.32405.73433@bitbucket03.managed.contegix.com> Pull request #3 has been accepted by Alex Gaynor. Changes in lambacck/pypy have been pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/3/add-the-undocumented-_pystring_join -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From noreply at buildbot.pypy.org Wed Jul 20 04:58:07 2011 From: noreply at buildbot.pypy.org (lambacck) Date: Wed, 20 Jul 2011 04:58:07 +0200 (CEST) Subject: [pypy-commit] pypy default: Add undocumented _PyString_Join function and test Message-ID: <20110720025807.0C4C1829B8@wyvern.cs.uni-duesseldorf.de> Author: Chris Lambacher Branch: Changeset: r45753:1a887e1b99cc Date: 2011-07-19 22:37 -0400 http://bitbucket.org/pypy/pypy/changeset/1a887e1b99cc/ Log: Add undocumented _PyString_Join function and test diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -268,3 +268,7 @@ if errors: w_errors = space.wrap(rffi.charp2str(errors)) return space.call_method(w_str, 'encode', w_encoding, w_errors) + + at cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -287,3 +287,9 @@ def test_eq(self, space, api): assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'ab' From noreply at buildbot.pypy.org Wed Jul 20 05:27:41 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 20 Jul 2011 05:27:41 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix formatting of numarray's str and repr to be fancy when translated. Message-ID: <20110720032741.1DEC4829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45754:5a66b387f79e Date: 2011-07-19 20:27 -0700 http://bitbucket.org/pypy/pypy/changeset/5a66b387f79e/ Log: Fix formatting of numarray's str and repr to be fancy when translated. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,7 +2,9 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit +from pypy.rlib.rfloat import DTSF_STR_PRECISION from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name import math @@ -55,6 +57,9 @@ def minimum(v1, v2): return min(v1, v2) +def float2string(x): + return float2string_orig(x, 'g', DTSF_STR_PRECISION) + class BaseArray(Wrappable): def __init__(self): self.invalidates = [] @@ -441,14 +446,20 @@ def _getnums(self, comma): if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] return nums def _repr(self, space): @@ -498,14 +509,20 @@ def _getnums(self, comma): if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] return nums def _repr(self, space): diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -133,8 +133,7 @@ else: return space.wrap("0x%sp%s%d" % (s, sign, exp)) -def float2string(space, w_float, code, precision): - x = w_float.floatval +def float2string(x, code, precision): # we special-case explicitly inf and nan here if isfinite(x): s = formatd(x, code, precision, DTSF_ADD_DOT_0) @@ -145,13 +144,13 @@ s = "-inf" else: # isnan(x): s = "nan" - return space.wrap(s) + return s def repr__Float(space, w_float): - return float2string(space, w_float, 'r', 0) + return space.wrap(float2string(w_float.floatval, 'r', 0)) def str__Float(space, w_float): - return float2string(space, w_float, 'g', DTSF_STR_PRECISION) + return space.wrap(float2string(w_float.floatval, 'g', DTSF_STR_PRECISION)) def format__Float_ANY(space, w_float, w_spec): return newformat.run_formatter(space, w_spec, "format_float", w_float) From noreply at buildbot.pypy.org Wed Jul 20 05:27:42 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 20 Jul 2011 05:27:42 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream. Message-ID: <20110720032742.4C261829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45755:5cdc83706551 Date: 2011-07-19 20:27 -0700 http://bitbucket.org/pypy/pypy/changeset/5cdc83706551/ Log: merged upstream. diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -268,3 +268,7 @@ if errors: w_errors = space.wrap(rffi.charp2str(errors)) return space.call_method(w_str, 'encode', w_encoding, w_errors) + + at cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -287,3 +287,9 @@ def test_eq(self, space, api): assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'ab' From noreply at buildbot.pypy.org Wed Jul 20 05:54:25 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 20 Jul 2011 05:54:25 +0200 (CEST) Subject: [pypy-commit] pypy default: Name is a quassiimmut field. Message-ID: <20110720035425.ECF0F829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45756:dff2f4c69db1 Date: 2011-07-19 20:54 -0700 http://bitbucket.org/pypy/pypy/changeset/dff2f4c69db1/ Log: Name is a quassiimmut field. diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -31,7 +31,8 @@ _immutable_fields_ = ['code?', 'w_func_globals?', 'closure?', - 'defs_w?[*]'] + 'defs_w?[*]', + 'name?'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): From noreply at buildbot.pypy.org Wed Jul 20 05:54:27 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 20 Jul 2011 05:54:27 +0200 (CEST) Subject: [pypy-commit] pypy default: Kill a bunch of duplicate code. Message-ID: <20110720035427.23087829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45757:fabe4fc0dc08 Date: 2011-07-19 20:54 -0700 http://bitbucket.org/pypy/pypy/changeset/fabe4fc0dc08/ Log: Kill a bunch of duplicate code. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -240,6 +240,24 @@ else: return self.descr_mul(space, w_other) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] + nums.append("..." + "," * comma) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) + else: + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] + return nums + def get_concrete(self): raise NotImplementedError @@ -250,10 +268,14 @@ return self.get_concrete().descr_len(space) def descr_repr(self, space): - return self.get_concrete()._repr(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])") def descr_str(self, space): - return self.get_concrete()._str(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("[" + " ".join(concrete._getnums(True)) + "]") def descr_getitem(self, space, w_idx): # TODO: indexing by tuples @@ -444,32 +466,6 @@ def calc_index(self, item): return (self.start + item * self.step) - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [ - float2string(self.getitem(index)) - for index in range(3) - ] - nums.append("..." + "," * comma) - nums.extend([ - float2string(self.getitem(index)) - for index in range(self.find_size() - 3, self.find_size()) - ]) - else: - nums = [ - float2string(self.getitem(index)) - for index in range(self.find_size()) - ] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - class SingleDimArray(BaseArray): signature = Signature() @@ -507,32 +503,6 @@ def getitem(self, item): return self.storage[item] - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [ - float2string(self.getitem(index)) - for index in range(3) - ] - nums.append("..." + "," * comma) - nums.extend([ - float2string(self.getitem(index)) - for index in range(self.find_size() - 3, self.find_size()) - ]) - else: - nums = [ - float2string(self.getitem(index)) - for index in range(self.find_size()) - ] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) From noreply at buildbot.pypy.org Wed Jul 20 10:10:59 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 10:10:59 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: first version of the strategy for instances which compares by identity. Broken in case we mutate the class after they are already in the dict Message-ID: <20110720081059.03810829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45758:beb63ba8a93a Date: 2011-07-20 10:07 +0200 http://bitbucket.org/pypy/pypy/changeset/beb63ba8a93a/ Log: first version of the strategy for instances which compares by identity. Broken in case we mutate the class after they are already in the dict diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -157,11 +157,15 @@ return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): - #XXX implement other strategies later + trackcomparebyidentity = self.space.config.objspace.std.trackcomparebyidentity if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) - elif self.space.is_w(self.space.type(w_key), self.space.w_int): + return + w_type = self.space.type(w_key) + if self.space.is_w(w_type, self.space.w_int): self.switch_to_int_strategy(w_dict) + elif trackcomparebyidentity and w_type.compares_by_identity(): + self.switch_to_identity_strategy(w_dict) else: self.switch_to_object_strategy(w_dict) @@ -177,6 +181,12 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_identity_strategy(self, w_dict): + strategy = self.space.fromcache(IdentityDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): strategy = self.space.fromcache(ObjectDictStrategy) storage = strategy.get_empty_storage() @@ -338,7 +348,6 @@ def getitem(self, w_dict, w_key): space = self.space - if self.is_correct_type(w_key): return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) elif self._never_equal_to(space.type(w_key)): @@ -404,6 +413,23 @@ def keys(self, w_dict): return self.unerase(w_dict.dstorage).keys() + +class IdentityDictStrategy(ObjectDictStrategy): + """ + Strategy for custom instances which compares by identity (i.e., the + default unless you override __hash__, __eq__ or __cmp__). The storage is + just a normal RPython dict, which has already the correct by-identity + semantics. + """ + + def is_correct_type(self, w_obj): + w_type = self.space.type(w_obj) + return w_type.compares_by_identity() + + def get_empty_storage(self): + return self.erase({}) + + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1105,3 +1105,60 @@ fakespace = FakeSpace() d = fakespace.newdict(module=True) assert type(d.strategy) is StringDictStrategy + + +class AppTestIdentityDict(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.trackcomparebyidentity": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_uses_identity_strategy(self, obj): + import __pypy__ + return "IdentityDictStrategy" in __pypy__.internal_repr(obj) + + def test_use_strategy(self): + class X(object): + pass + d = {} + x = X() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[x] == 1 + + def test_bad_item(self): + class X(object): + pass + class Y(object): + def __hash__(self): + return 32 + + d = {} + x = X() + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + d[y] = 2 + assert not self.uses_identity_strategy(d) + assert d[x] == 1 + assert d[y] == 2 + + def test_bad_key(self): + class X(object): + pass + d = {} + x = X() + + class Y(object): + def __hash__(self): + return hash(x) # to make sure we do x == y + + def __eq__(self, other): + return True + + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[y] == 1 + assert not self.uses_identity_strategy(d) + From noreply at buildbot.pypy.org Wed Jul 20 10:16:20 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 10:16:20 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: as cfbolz points out, we cannot mutate the space, because it's frozen. Instead, store the mutable version in an object attached to the space Message-ID: <20110720081620.DED23829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45759:5ee41f314843 Date: 2011-07-20 10:16 +0200 http://bitbucket.org/pypy/pypy/changeset/5ee41f314843/ Log: as cfbolz points out, we cannot mutate the space, because it's frozen. Instead, store the mutable version in an object attached to the space diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -45,7 +45,7 @@ w_obj.setclass(space, w_newcls) if space.config.objspace.std.trackcomparebyidentity: if w_oldcls.compares_by_identity() and not w_newcls.compares_by_identity(): - space.bump_compares_by_identity_version() + space.compares_by_identity_version.bump() else: raise operationerrfmt(space.w_TypeError, "__class__ assignment: '%s' object layout differs from '%s'", diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -89,7 +89,7 @@ self.w_classobj = self.builtin.get('__metaclass__') if self.config.objspace.std.trackcomparebyidentity: - self.bump_compares_by_identity_version() + self.compares_by_identity_version = ComparesByIdentityVersion() # final setup self.setup_builtin_modules() @@ -581,5 +581,11 @@ return self.wrap(w_sub.issubtype(w_type)) raise OperationError(self.w_TypeError, self.wrap("need type objects")) - def bump_compares_by_identity_version(self): - self.compares_by_identity_version = VersionTag() + +class ComparesByIdentityVersion(object): + + def __init__(self): + self.bump() + + def bump(self): + self._version = VersionTag() diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1212,7 +1212,7 @@ cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) def get_version(space): - v = cls.versions.setdefault(space.compares_by_identity_version, + v = cls.versions.setdefault(space.compares_by_identity_version._version, len(cls.versions)) return space.wrap(v) cls.w_get_version = cls.space.wrap(interp2app(get_version)) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -178,7 +178,7 @@ key == '__cmp__' or key == '__hash__'): w_self.compares_by_identity_status = UNKNOWN if did_compare_by_identity: - w_self.space.bump_compares_by_identity_version() + w_self.space.compares_by_identity_version.bump() if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None From noreply at buildbot.pypy.org Wed Jul 20 10:19:34 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 20 Jul 2011 10:19:34 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: renamed paramter to make translation happy Message-ID: <20110720081934.03596829BA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45760:55a935a20e28 Date: 2011-07-17 13:31 +0200 http://bitbucket.org/pypy/pypy/changeset/55a935a20e28/ Log: renamed paramter to make translation happy diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -47,7 +47,7 @@ class __extend__(optimizer.OptValue): """New methods added to the base class OptValue for this file.""" - def getstrlen(self, optimization, mode, lengthbox=None): + def getstrlen(self, optimizer, mode, lengthbox=None): if mode is mode_string: s = self.get_constant_string_spec(mode_string) if s is not None: @@ -56,13 +56,13 @@ s = self.get_constant_string_spec(mode_unicode) if s is not None: return ConstInt(len(s)) - if optimization is None: + if optimizer is None: return None self.ensure_nonnull() box = self.force_box() if not lengthbox: lengthbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) + optimizer.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -125,7 +125,7 @@ assert 0 <= start <= stop <= len(longerlist) self._chars = longerlist[start:stop] - def getstrlen(self, _, mode, lengthbox=None): + def getstrlen(self, optimizer, mode, lengthbox=None): if self._lengthbox is None: self._lengthbox = ConstInt(len(self._chars)) return self._lengthbox @@ -250,7 +250,7 @@ self.vstart = vstart self.vlength = vlength - def getstrlen(self, _, mode, lengthbox=None): + def getstrlen(self, optimizer, mode, lengthbox=None): return self.vlength.force_box() @specialize.arg(1) From noreply at buildbot.pypy.org Wed Jul 20 10:19:35 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 20 Jul 2011 10:19:35 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: short_inputargs can contain the same keybox twice. The virtual_state check will ensure that any jump using the short preamble as target will have the exact same duplicated keyboxes. This is maybe not so nice a property... Message-ID: <20110720081935.4AA43829BA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45761:2729c61219e4 Date: 2011-07-17 16:50 +0200 http://bitbucket.org/pypy/pypy/changeset/2729c61219e4/ Log: short_inputargs can contain the same keybox twice. The virtual_state check will ensure that any jump using the short preamble as target will have the exact same duplicated keyboxes. This is maybe not so nice a property... diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6467,6 +6467,18 @@ """ self.optimize_loop(ops, expected) + def test_duplicated_virtual(self): + ops = """ + [p1, p2] + p3 = new_with_vtable(ConstClass(node_vtable)) + jump(p3, p3) + """ + expected = """ + [] + jump() + """ + self.optimize_loop(ops, expected) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -84,6 +84,9 @@ assert len(inputargs) == len(jump_args) self.argmap = {} for i in range(len(inputargs)): + if inputargs[i] in self.argmap: + assert self.argmap[inputargs[i]] == jump_args[i] + else: self.argmap[inputargs[i]] = jump_args[i] self.snapshot_map = {None: None} @@ -220,7 +223,11 @@ # in the peeled loop inputarg_setup_ops = [] preamble_optimizer.newoperations = [] + seen = {} for box in short_inputargs: + if box in seen: + continue + seen[box] = True value = preamble_optimizer.getvalue(box) if value.is_virtual(): value.force_box() @@ -284,7 +291,15 @@ short_loop.operations = short # Clone ops and boxes to get private versions and - newargs = [a.clonebox() for a in short_loop.inputargs] + boxmap = {} + newargs = [None] * len(short_loop.inputargs) + for i in range(len(short_loop.inputargs)): + a = short_loop.inputargs[i] + if a in boxmap: + newargs[i] = boxmap[a] + else: + newargs[i] = a.clonebox() + boxmap[a] = newargs[i] inliner = Inliner(short_loop.inputargs, newargs) for box, const in self.constant_inputargs.items(): inliner.argmap[box] = const From noreply at buildbot.pypy.org Wed Jul 20 10:19:36 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 20 Jul 2011 10:19:36 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: make optimize_STRGETITEM reusing original result box when emitted Message-ID: <20110720081936.85CF0829BA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45762:298d0583fc21 Date: 2011-07-17 17:05 +0200 http://bitbucket.org/pypy/pypy/changeset/298d0583fc21/ Log: make optimize_STRGETITEM reusing original result box when emitted diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6467,6 +6467,62 @@ """ self.optimize_loop(ops, expected) + def test_loopinvariant_strgetitem(self): + ops = """ + [p9, i1] + i843 = strgetitem(p9, i1) + call(i843, descr=nonwritedescr) + jump(p9, i1) + """ + expected = """ + [p9, i1, i2] + call(i2, descr=nonwritedescr) + jump(p9, i1, i2) + """ + self.optimize_loop(ops, expected) + + def test_loopinvariant_unicodelen(self): + ops = """ + [p9] + i843 = unicodelen(p9) + call(i843, descr=nonwritedescr) + jump(p9) + """ + expected = """ + [p9, i2] + call(i2, descr=nonwritedescr) + jump(p9, i2) + """ + self.optimize_loop(ops, expected) + + def test_loopinvariant_unicodegetitem(self): + ops = """ + [p9, i1] + i843 = unicodegetitem(p9, i1) + call(i843, descr=nonwritedescr) + jump(p9, i1) + """ + expected = """ + [p9, i1, i2] + call(i2, descr=nonwritedescr) + jump(p9, i1, i2) + """ + self.optimize_loop(ops, expected) + + def test_loopinvariant_arraylen(self): + ops = """ + [p9] + i843 = arraylen_gc(p9) + call(i843, descr=nonwritedescr) + jump(p9) + """ + expected = """ + [p9, i2] + call(i2, descr=nonwritedescr) + jump(p9, i2) + """ + self.optimize_loop(ops, expected) + def test_duplicated_virtual(self): ops = """ [p1, p2] diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -349,7 +349,7 @@ optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimization, strbox, indexbox, mode): +def _strgetitem(optimization, strbox, indexbox, mode, resbox=None): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,6 +357,7 @@ else: s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) + if not resbox: resbox = BoxInt() optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) @@ -427,10 +428,11 @@ def _optimize_STRGETITEM(self, op, mode): value = self.getvalue(op.getarg(0)) vindex = self.getvalue(op.getarg(1)) - vresult = self.strgetitem(value, vindex, mode) + vresult = self.strgetitem(value, vindex, mode, op.result) + if op.result not in self.optimizer.values: self.make_equal_to(op.result, vresult) - def strgetitem(self, value, vindex, mode): + def strgetitem(self, value, vindex, mode, result=None): value.ensure_nonnull() # if value.is_virtual() and isinstance(value, VStringSliceValue): @@ -444,7 +446,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) + resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode, result) return self.getvalue(resbox) def optimize_STRLEN(self, op): From noreply at buildbot.pypy.org Wed Jul 20 10:19:37 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 20 Jul 2011 10:19:37 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: failing test Message-ID: <20110720081937.B5567829BA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45763:15bf96a5cf7e Date: 2011-07-17 21:58 +0200 http://bitbucket.org/pypy/pypy/changeset/15bf96a5cf7e/ Log: failing test diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2782,6 +2782,24 @@ res = self.meta_interp(f, [16]) assert res == f(16) + def test_loopinvariant_array_shrinking(self): + myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a']) + def f(n): + sa = i = 0 + a = [0, 1, 2, 3, 4] + while i < n: + myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i) + if i < n/2: + sa += a[4] + elif i == n/2: + a.pop() + i += 1 + res = self.meta_interp(f, [32]) + assert res == f(32) + self.check_loops(arraylen_gc=1) + + + class TestOOtype(BasicTests, OOJitMixin): From noreply at buildbot.pypy.org Wed Jul 20 10:19:38 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 20 Jul 2011 10:19:38 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: started to move the handling of short_boxes into a class of its own Message-ID: <20110720081938.F0913829BA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45764:a994ad085d26 Date: 2011-07-18 09:57 +0200 http://bitbucket.org/pypy/pypy/changeset/a994ad085d26/ Log: started to move the handling of short_boxes into a class of its own diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -117,8 +117,7 @@ cf._cached_fields[structvalue2] = fieldvalue2 return cf - def produce_potential_short_preamble_ops(self, optimizer, - potential_ops, descr): + def produce_potential_short_preamble_ops(self, optimizer, shortboxes, descr): if self._lazy_setfield is not None: return for structvalue in self._cached_fields_getfield_op.keys(): @@ -126,20 +125,19 @@ if op and structvalue in self._cached_fields: if op.getopnum() == rop.SETFIELD_GC: result = op.getarg(1) - if result in potential_ops and potential_ops[result] is None: + if result in shortboxes.potential_ops and \ + shortboxes.potential_ops[result] is None: newresult = result.clonebox() optimizer.make_equal_to(newresult, optimizer.getvalue(result)) result = newresult # XXX this will not allow for chains of operations getop = ResOperation(rop.GETFIELD_GC, [op.getarg(0)], result, op.getdescr()) - potential_ops[result] = getop + shortboxes.add_potential(getop) self._cached_fields_getfield_op[structvalue] = getop self._cached_fields[structvalue] = optimizer.getvalue(result) elif op.result is not None: - potential_ops[op.result] = op - - + shortboxes.add_potential(op) class BogusPureField(JitException): pass @@ -182,15 +180,13 @@ return new - def produce_potential_short_preamble_ops(self, potential_ops): + def produce_potential_short_preamble_ops(self, sb): for descr, d in self.cached_fields.items(): - d.produce_potential_short_preamble_ops(self.optimizer, - potential_ops, descr) + d.produce_potential_short_preamble_ops(self.optimizer, sb, descr) for descr, submap in self.cached_arrayitems.items(): for index, d in submap.items(): - d.produce_potential_short_preamble_ops(self.optimizer, - potential_ops, descr) + d.produce_potential_short_preamble_ops(self.optimizer, sb, descr) def clean_caches(self): del self._lazy_setfields_and_arrayitems[:] diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -317,9 +317,6 @@ def produce_potential_short_preamble_ops(self, potential_ops): pass -class BoxNotProducable(Exception): - pass - class Optimizer(Optimization): def __init__(self, metainterp_sd, loop, optimizations=None): @@ -429,41 +426,11 @@ return new - def produce_potential_short_preamble_ops(self, potential_ops): + def produce_potential_short_preamble_ops(self, sb): for op in self.emitted_pure_operations: - potential_ops[op.result] = op + sb.add_potential(op) for opt in self.optimizations: - opt.produce_potential_short_preamble_ops(potential_ops) - - def produce_short_preamble_ops(self, surviving_boxes): - potential_ops = {} - self.produce_potential_short_preamble_ops(potential_ops) - - short_boxes = {} - for box in surviving_boxes: - short_boxes[box] = None - - for box in potential_ops.keys(): - try: - self.produce_short_preamble_box(box, short_boxes, - potential_ops) - except BoxNotProducable: - pass - return short_boxes - - def produce_short_preamble_box(self, box, short_boxes, potential_ops): - if box in short_boxes: - return - if isinstance(box, Const): - return - if box in potential_ops: - op = potential_ops[box] - for arg in op.getarglist(): - self.produce_short_preamble_box(arg, short_boxes, - potential_ops) - short_boxes[box] = op - else: - raise BoxNotProducable + opt.produce_potential_short_preamble_ops(sb) def turned_constant(self, value): for o in self.optimizations: diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -27,10 +27,9 @@ value.get_cloned(new, valuemap) return new - def produce_potential_short_preamble_ops(self, potential_ops): + def produce_potential_short_preamble_ops(self, sb): for op in self.loop_invariant_producer.values(): - potential_ops[op.result] = op - + sb.add_potential(op) def propagate_forward(self, op): args = self.optimizer.make_args_key(op) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * -from pypy.jit.metainterp.optimizeopt.virtualstate import VirtualStateAdder +from pypy.jit.metainterp.optimizeopt.virtualstate import VirtualStateAdder, ShortBoxes from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.compile import ResumeGuardDescr from pypy.jit.metainterp.resume import Snapshot @@ -195,8 +195,7 @@ if const: self.constant_inputargs[box] = const - sb = self.optimizer.produce_short_preamble_ops(inputargs + - self.constant_inputargs.keys()) + sb = ShortBoxes(self.optimizer, inputargs + self.constant_inputargs.keys()) self.short_boxes = sb preamble_optimizer = self.optimizer loop.preamble.quasi_immutable_deps = ( @@ -210,13 +209,7 @@ debug_print('inputargs: ' + args) args = ", ".join([logops.repr_of_arg(arg) for arg in short_inputargs]) debug_print('short inputargs: ' + args) - debug_start('jit-short-boxes') - for box, op in self.short_boxes.items(): - if op: - debug_print(logops.repr_of_arg(box) + ': ' + logops.repr_of_resop(op)) - else: - debug_print(logops.repr_of_arg(box) + ': None') - debug_stop('jit-short-boxes') + self.short_boxes.debug_print(logops) # Force virtuals amoung the jump_args of the preamble to get the # operations needed to setup the proper state of those virtuals @@ -242,7 +235,7 @@ for op in inputarg_setup_ops: self.optimizer.send_extra_operation(op) seen = {} - for op in self.short_boxes.values(): + for op in self.short_boxes.operations(): self.ensure_short_op_emitted(op, self.optimizer, seen) if op and op.result: value = preamble_optimizer.getvalue(op.result) @@ -334,10 +327,9 @@ for box, const in self.constant_inputargs.items(): short_seen[box] = True - for result, op in self.short_boxes.items(): + for op in self.short_boxes.operations(): if op is not None: - assert result is op.result - if len(self.getvalue(result).make_guards(result)) > 0: + if len(self.getvalue(op.result).make_guards(op.result)) > 0: self.add_op_to_short(op, short, short_seen, False, True) # This loop is equivalent to the main optimization loop in @@ -427,7 +419,7 @@ return for a in op.getarglist(): if not isinstance(a, Const) and a not in seen: - self.ensure_short_op_emitted(self.short_boxes[a], optimizer, seen) + self.ensure_short_op_emitted(self.short_boxes.producer(a), optimizer, seen) optimizer.send_extra_operation(op) seen[op.result] = True if op.is_ovf(): @@ -444,13 +436,13 @@ return None for a in op.getarglist(): if not isinstance(a, Const) and a not in short_seen: - self.add_op_to_short(self.short_boxes[a], short, short_seen, + self.add_op_to_short(self.short_boxes.producer(a), short, short_seen, emit, guards_needed) if op.is_guard(): descr = self.start_resumedescr.clone_if_mutable() op.setdescr(descr) - if guards_needed and op.result in self.short_boxes: + if guards_needed and self.short_boxes.has_producer(op.result): value_guards = self.getvalue(op.result).make_guards(op.result) else: value_guards = [] @@ -482,7 +474,7 @@ if box in self.boxes_created_this_iteration: return - short_op = self.short_boxes[box] + short_op = self.short_boxes.producer(box) newresult = self.add_op_to_short(short_op, short, short_seen) short_jumpargs.append(short_op.result) diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py --- a/pypy/jit/metainterp/optimizeopt/virtualstate.py +++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py @@ -431,3 +431,55 @@ def make_varray(self, arraydescr): return VArrayStateInfo(arraydescr) +class BoxNotProducable(Exception): + pass + +class ShortBoxes(object): + def __init__(self, optimizer, surviving_boxes): + self.potential_ops = {} + optimizer.produce_potential_short_preamble_ops(self) + + self.short_boxes = {} + for box in surviving_boxes: + self.short_boxes[box] = None + + for box in self.potential_ops.keys(): + try: + self.produce_short_preamble_box(box) + except BoxNotProducable: + pass + + def produce_short_preamble_box(self, box): + if box in self.short_boxes: + return + if isinstance(box, Const): + return + if box in self.potential_ops: + op = self.potential_ops[box] + for arg in op.getarglist(): + self.produce_short_preamble_box(arg) + self.short_boxes[box] = op + else: + raise BoxNotProducable + + def add_potential(self, op): + self.potential_ops[op.result] = op + + def debug_print(self, logops): + debug_start('jit-short-boxes') + for box, op in self.short_boxes.items(): + if op: + debug_print(logops.repr_of_arg(box) + ': ' + logops.repr_of_resop(op)) + else: + debug_print(logops.repr_of_arg(box) + ': None') + debug_stop('jit-short-boxes') + + def operations(self): + return self.short_boxes.values() + + def producer(self, box): + return self.short_boxes[box] + + def has_producer(self, box): + return box in self.short_boxes + diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2799,9 +2799,6 @@ self.check_loops(arraylen_gc=1) - - - class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): From noreply at buildbot.pypy.org Wed Jul 20 10:19:40 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 20 Jul 2011 10:19:40 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: failing tests Message-ID: <20110720081940.3967F829BA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45765:ecf28ed48baf Date: 2011-07-18 16:35 +0200 http://bitbucket.org/pypy/pypy/changeset/ecf28ed48baf/ Log: failing tests diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6523,6 +6523,26 @@ """ self.optimize_loop(ops, expected) + def test_loopinvariant_getarrayitem(self): + ops = """ + [p1] + p2 = getarrayitem_gc(p1, 7, descr=) + call(p2, descr=nonwritedescr) + jump(p1) + """ + short = """ + [p1] + i1 = arraylen_gc(p1) + p2 = getarrayitem_gc(p1, 7, descr=) + jump(p1, p2) + """ + expected = """ + [p1, p2] + call(p2, descr=nonwritedescr) + jump(p1, p2) + """ + self.optimize_loop(ops, expected, expected_short=short) + def test_duplicated_virtual(self): ops = """ [p1, p2] From noreply at buildbot.pypy.org Wed Jul 20 10:19:41 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 20 Jul 2011 10:19:41 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: keep track of array/str/unicode length and guard for them to make getitems safe in short preamble Message-ID: <20110720081941.8307A829BA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45766:3f1e8b5dd3b0 Date: 2011-07-20 09:38 +0200 http://bitbucket.org/pypy/pypy/changeset/3f1e8b5dd3b0/ Log: keep track of array/str/unicode length and guard for them to make getitems safe in short preamble diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException -from pypy.jit.metainterp.optimizeopt.optimizer import Optimization +from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY from pypy.jit.metainterp.history import ConstInt, Const @@ -407,6 +407,7 @@ indexvalue = self.getvalue(op.getarg(1)) cf = None if indexvalue.is_constant(): + arrayvalue.make_len_gt(MODE_ARRAY, op.getdescr(), indexvalue.box.getint()) # use the cache on (arraydescr, index), which is a constant cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) fieldvalue = cf.getfield_from_cache(self, arrayvalue) @@ -434,6 +435,8 @@ # indexvalue = self.getvalue(op.getarg(1)) if indexvalue.is_constant(): + arrayvalue = self.getvalue(op.getarg(0)) + arrayvalue.make_len_gt(MODE_ARRAY, op.getdescr(), indexvalue.box.getint()) # use the cache on (arraydescr, index), which is a constant cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint()) cf.do_setfield(self, op) diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,4 +1,5 @@ -from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 +from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0, \ + MODE_ARRAY, MODE_STR, MODE_UNICODE from pypy.jit.metainterp.optimizeopt.util import _findall from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, IntLowerBound, IntUpperBound) @@ -285,10 +286,24 @@ def optimize_ARRAYLEN_GC(self, op): self.emit_operation(op) - v1 = self.getvalue(op.result) - v1.intbound.make_ge(IntLowerBound(0)) + array = self.getvalue(op.getarg(0)) + result = self.getvalue(op.result) + array.make_len_gt(MODE_ARRAY, op.getdescr(), -1) + result.intbound = array.lenbound[2] - optimize_STRLEN = optimize_UNICODELEN = optimize_ARRAYLEN_GC + def optimize_STRLEN(self, op): + self.emit_operation(op) + array = self.getvalue(op.getarg(0)) + result = self.getvalue(op.result) + array.make_len_gt(MODE_STR, op.getdescr(), -1) + result.intbound = array.lenbound[2] + + def optimize_UNICODELEN(self, op): + self.emit_operation(op) + array = self.getvalue(op.getarg(0)) + result = self.getvalue(op.result) + array.make_len_gt(MODE_UNICODE, op.getdescr(), -1) + result.intbound = array.lenbound[2] def optimize_STRGETITEM(self, op): self.emit_operation(op) diff --git a/pypy/jit/metainterp/optimizeopt/intutils.py b/pypy/jit/metainterp/optimizeopt/intutils.py --- a/pypy/jit/metainterp/optimizeopt/intutils.py +++ b/pypy/jit/metainterp/optimizeopt/intutils.py @@ -1,4 +1,9 @@ from pypy.rlib.rarithmetic import ovfcheck, ovfcheck_lshift, LONG_BIT +from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.history import BoxInt, ConstInt +import sys +MAXINT = sys.maxint +MININT = -sys.maxint - 1 class IntBound(object): _attrs_ = ('has_upper', 'has_lower', 'upper', 'lower') @@ -225,6 +230,23 @@ res.has_upper = self.has_upper return res + def make_guards(self, box, guards): + if self.has_lower and self.lower > MININT: + bound = self.lower + res = BoxInt() + op = ResOperation(rop.INT_GE, [box, ConstInt(bound)], res) + guards.append(op) + op = ResOperation(rop.GUARD_TRUE, [res], None) + guards.append(op) + if self.has_upper and self.upper < MAXINT: + bound = self.upper + res = BoxInt() + op = ResOperation(rop.INT_LE, [box, ConstInt(bound)], res) + guards.append(op) + op = ResOperation(rop.GUARD_TRUE, [res], None) + guards.append(op) + + class IntUpperBound(IntBound): def __init__(self, upper): self.has_upper = True diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -12,26 +12,29 @@ from pypy.rpython.lltypesystem import lltype from pypy.jit.metainterp.history import AbstractDescr, make_hashable_int from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \ - ImmutableIntUnbounded + ImmutableIntUnbounded, \ + IntLowerBound, MININT, MAXINT from pypy.tool.pairtype import extendabletype +from pypy.rlib.debug import debug_start, debug_stop, debug_print LEVEL_UNKNOWN = '\x00' LEVEL_NONNULL = '\x01' LEVEL_KNOWNCLASS = '\x02' # might also mean KNOWNARRAYDESCR, for arrays LEVEL_CONSTANT = '\x03' -import sys -MAXINT = sys.maxint -MININT = -sys.maxint - 1 +MODE_ARRAY = '\x00' +MODE_STR = '\x01' +MODE_UNICODE = '\x02' class OptValue(object): __metaclass__ = extendabletype - _attrs_ = ('box', 'known_class', 'last_guard_index', 'level', 'intbound') + _attrs_ = ('box', 'known_class', 'last_guard_index', 'level', 'intbound', 'lenbound') last_guard_index = -1 level = LEVEL_UNKNOWN known_class = None intbound = ImmutableIntUnbounded() + lenbound = None def __init__(self, box, level=None, known_class=None, intbound=None): self.box = box @@ -50,6 +53,14 @@ self.make_constant(box) # invariant: box is a Const if and only if level == LEVEL_CONSTANT + def make_len_gt(self, mode, descr, val): + if self.lenbound: + assert self.lenbound[0] == mode + assert self.lenbound[1] == descr + self.lenbound[2].make_gt(IntBound(val, val)) + else: + self.lenbound = (mode, descr, IntLowerBound(val + 1)) + def make_guards(self, box): guards = [] if self.level == LEVEL_CONSTANT: @@ -64,20 +75,21 @@ if self.level == LEVEL_NONNULL: op = ResOperation(rop.GUARD_NONNULL, [box], None) guards.append(op) - if self.intbound.has_lower and self.intbound.lower > MININT: - bound = self.intbound.lower - res = BoxInt() - op = ResOperation(rop.INT_GE, [box, ConstInt(bound)], res) + self.intbound.make_guards(box, guards) + if self.lenbound: + lenbox = BoxInt() + if self.lenbound[0] == MODE_ARRAY: + op = ResOperation(rop.ARRAYLEN_GC, [box], lenbox, self.lenbound[1]) + elif self.lenbound[0] == MODE_STR: + op = ResOperation(rop.STRLEN, [box], lenbox, self.lenbound[1]) + elif self.lenbound[0] == MODE_UNICODE: + op = ResOperation(rop.UNICODELEN, [box], lenbox, self.lenbound[1]) + else: + debug_print("Unknown lenbound mode") + assert False guards.append(op) - op = ResOperation(rop.GUARD_TRUE, [res], None) - guards.append(op) - if self.intbound.has_upper and self.intbound.upper < MAXINT: - bound = self.intbound.upper - res = BoxInt() - op = ResOperation(rop.INT_LE, [box, ConstInt(bound)], res) - guards.append(op) - op = ResOperation(rop.GUARD_TRUE, [res], None) - guards.append(op) + self.lenbound[2].make_guards(lenbox, guards) + return guards def force_box(self): @@ -428,6 +440,11 @@ def produce_potential_short_preamble_ops(self, sb): for op in self.emitted_pure_operations: + if op.getopnum() == rop.GETARRAYITEM_GC_PURE or \ + op.getopnum() == rop.STRGETITEM or \ + op.getopnum() == rop.UNICODEGETITEM: + if not self.getvalue(op.getarg(1)).is_constant(): + continue sb.add_potential(op) for opt in self.optimizations: opt.produce_potential_short_preamble_ops(sb) @@ -676,6 +693,30 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) + def optimize_GETARRAYITEM_GC_PURE(self, op): + indexvalue = self.getvalue(op.getarg(1)) + if indexvalue.is_constant(): + arrayvalue = self.getvalue(op.getarg(0)) + arrayvalue.make_len_gt(MODE_ARRAY, op.getdescr(), indexvalue.box.getint()) + self.optimize_default(op) + + def optimize_STRGETITEM(self, op): + indexvalue = self.getvalue(op.getarg(1)) + if indexvalue.is_constant(): + arrayvalue = self.getvalue(op.getarg(0)) + arrayvalue.make_len_gt(MODE_STR, op.getdescr(), indexvalue.box.getint()) + self.optimize_default(op) + + def optimize_UNICODEGETITEM(self, op): + indexvalue = self.getvalue(op.getarg(1)) + if indexvalue.is_constant(): + arrayvalue = self.getvalue(op.getarg(0)) + arrayvalue.make_len_gt(MODE_UNICODE, op.getdescr(), indexvalue.box.getint()) + self.optimize_default(op) + + + + optimize_ops = _findall(Optimizer, 'optimize_') diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6467,6 +6467,22 @@ """ self.optimize_loop(ops, expected) + def test_loopinvariant_strlen_with_bound(self): + ops = """ + [p9] + i843 = strlen(p9) + i1 = int_gt(i843, 7) + guard_true(i1) [] + call(i843, descr=nonwritedescr) + jump(p9) + """ + expected = """ + [p9, i2] + call(i2, descr=nonwritedescr) + jump(p9, i2) + """ + self.optimize_loop(ops, expected) + def test_loopinvariant_strgetitem(self): ops = """ [p9, i1] @@ -6474,12 +6490,7 @@ call(i843, descr=nonwritedescr) jump(p9, i1) """ - expected = """ - [p9, i1, i2] - call(i2, descr=nonwritedescr) - jump(p9, i1, i2) - """ - self.optimize_loop(ops, expected) + self.optimize_loop(ops, ops) def test_loopinvariant_unicodelen(self): ops = """ @@ -6502,12 +6513,7 @@ call(i843, descr=nonwritedescr) jump(p9, i1) """ - expected = """ - [p9, i1, i2] - call(i2, descr=nonwritedescr) - jump(p9, i1, i2) - """ - self.optimize_loop(ops, expected) + self.optimize_loop(ops, ops) def test_loopinvariant_arraylen(self): ops = """ @@ -6525,21 +6531,26 @@ def test_loopinvariant_getarrayitem(self): ops = """ - [p1] + [p0] + p1 = getfield_gc(p0, descr=nextdescr) p2 = getarrayitem_gc(p1, 7, descr=) call(p2, descr=nonwritedescr) - jump(p1) + jump(p0) """ short = """ - [p1] + [p0] + p1 = getfield_gc(p0, descr=nextdescr) + guard_nonnull(p1) [] i1 = arraylen_gc(p1) + i2 = int_ge(i1, 8) + guard_true(i2) [] p2 = getarrayitem_gc(p1, 7, descr=) - jump(p1, p2) - """ - expected = """ - [p1, p2] + jump(p0, p2) + """ + expected = """ + [p0, p2] call(p2, descr=nonwritedescr) - jump(p1, p2) + jump(p0, p2) """ self.optimize_loop(ops, expected, expected_short=short) @@ -6555,6 +6566,115 @@ """ self.optimize_loop(ops, expected) + def test_arraylen_bound(self): + ops = """ + [p1, i] + p2 = getarrayitem_gc(p1, 7, descr=) + i1 = arraylen_gc(p1) + i2 = int_ge(i1, 8) + guard_true(i2) [] + jump(p2, i2) + """ + expected = """ + [p1] + p2 = getarrayitem_gc(p1, 7, descr=) + i1 = arraylen_gc(p1) + jump(p2) + """ + self.optimize_loop(ops, expected) + + def test_loopinvariant_getarrayitem_gc_pure(self): + ops = """ + [p9, i1] + i843 = getarrayitem_gc_pure(p9, i1) + call(i843, descr=nonwritedescr) + jump(p9, i1) + """ + self.optimize_loop(ops, ops) + + def test_loopinvariant_constant_getarrayitem_pure(self): + ops = """ + [p0] + p1 = getfield_gc(p0, descr=nextdescr) + p2 = getarrayitem_gc_pure(p1, 7, descr=) + call(p2, descr=nonwritedescr) + jump(p0) + """ + short = """ + [p0] + p1 = getfield_gc(p0, descr=nextdescr) + guard_nonnull(p1) [] + i1 = arraylen_gc(p1) + i2 = int_ge(i1, 8) + guard_true(i2) [] + p2 = getarrayitem_gc_pure(p1, 7, descr=) + jump(p0, p2) + """ + expected = """ + [p0, p2] + call(p2, descr=nonwritedescr) + jump(p0, p2) + """ + self.optimize_loop(ops, expected, expected_short=short) + + + def test_loopinvariant_constant_strgetitem(self): + ops = """ + [p0] + p1 = getfield_gc(p0, descr=nextdescr) + p2 = strgetitem(p1, 7) + call(p2, descr=nonwritedescr) + jump(p0) + """ + short = """ + [p0] + p1 = getfield_gc(p0, descr=nextdescr) + guard_nonnull(p1) [] + i1 = strlen(p1) + i2 = int_ge(i1, 8) + guard_true(i2) [] + p2 = strgetitem(p1, 7, descr=) + i8 = int_ge(p2, 0) + guard_true(i8) [] + i9 = int_le(p2, 255) + guard_true(i9) [] + jump(p0, p2) + """ + expected = """ + [p0, p2] + call(p2, descr=nonwritedescr) + jump(p0, p2) + """ + self.optimize_loop(ops, expected, expected_short=short) + + def test_loopinvariant_constant_unicodegetitem(self): + ops = """ + [p0] + p1 = getfield_gc(p0, descr=nextdescr) + p2 = unicodegetitem(p1, 7) + call(p2, descr=nonwritedescr) + jump(p0) + """ + short = """ + [p0] + p1 = getfield_gc(p0, descr=nextdescr) + guard_nonnull(p1) [] + i1 = unicodelen(p1) + i2 = int_ge(i1, 8) + guard_true(i2) [] + p2 = unicodegetitem(p1, 7, descr=) + i8 = int_ge(p2, 0) + guard_true(i8) [] + jump(p0, p2) + """ + expected = """ + [p0, p2] + call(p2, descr=nonwritedescr) + jump(p0, p2) + """ + self.optimize_loop(ops, expected, expected_short=short) + + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -247,6 +247,7 @@ initial_inputargs_len = len(inputargs) self.inliner = Inliner(loop.inputargs, jump_args) + short = self.inline(inputargs, self.cloned_operations, loop.inputargs, short_inputargs, virtual_state) diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py --- a/pypy/jit/metainterp/optimizeopt/virtualstate.py +++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py @@ -201,6 +201,7 @@ else: self.constbox = None self.position_in_notvirtuals = -1 + self.lenbound = value.lenbound def generalization_of(self, other, renum, bad): # XXX This will always retrace instead of forcing anything which @@ -235,12 +236,26 @@ bad[self] = True bad[other] = True return False + if self.lenbound and other.lenbound: + if self.lenbound[0] != other.lenbound[0] or \ + self.lenbound[1] != other.lenbound[1] or \ + not self.lenbound[2].contains_bound(other.lenbound[2]): + bad[self] = True + bad[other] = True + return False + elif self.lenbound or other.lenbound: + bad[self] = True + bad[other] = True + return False return True def _generate_guards(self, other, box, cpu, extra_guards): if not isinstance(other, NotVirtualStateInfo): raise InvalidLoop + if self.lenbound or other.lenbound: + raise InvalidLoop + if self.level == LEVEL_KNOWNCLASS and \ box.nonnull() and \ self.known_class.same_constant(cpu.ts.cls_of_box(box)): @@ -324,8 +339,12 @@ LEVEL_CONSTANT: 'Constant(%r)' % self.constbox, }[self.level] + lb = '' + if self.lenbound: + lb = ', ' + self.lenbound[2].__repr__() + debug_print(indent + mark + 'NotVirtualInfo(%d' % self.position + - ', ' + l + ', ' + self.intbound.__repr__() + ')') + ', ' + l + ', ' + self.intbound.__repr__() + lb + ')') class VirtualState(object): def __init__(self, state): diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2782,7 +2782,7 @@ res = self.meta_interp(f, [16]) assert res == f(16) - def test_loopinvariant_array_shrinking(self): + def test_loopinvariant_array_shrinking1(self): myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a']) def f(n): sa = i = 0 @@ -2798,7 +2798,6 @@ assert res == f(32) self.check_loops(arraylen_gc=1) - class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): @@ -2976,5 +2975,97 @@ self.meta_interp(f, [], enable_opts='') self.check_loops(new_with_vtable=1) + def test_two_loopinvariant_arrays1(self): + from pypy.rpython.lltypesystem import lltype, llmemory, rffi + myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a']) + TP = lltype.GcArray(lltype.Signed) + def f(n): + sa = i = 0 + a = lltype.malloc(TP, 5) + a[4] = 7 + while i < n: + myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i) + if i < n/2: + sa += a[4] + if i == n/2: + a = lltype.malloc(TP, 3) + i += 1 + return sa + res = self.meta_interp(f, [32]) + assert res == f(32) + self.check_tree_loop_count(3) + + def test_two_loopinvariant_arrays2(self): + from pypy.rpython.lltypesystem import lltype, llmemory, rffi + myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a']) + TP = lltype.GcArray(lltype.Signed) + def f(n): + sa = i = 0 + a = lltype.malloc(TP, 5) + a[4] = 7 + while i < n: + myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i) + if i < n/2: + sa += a[4] + elif i > n/2: + sa += a[2] + if i == n/2: + a = lltype.malloc(TP, 3) + a[2] = 42 + i += 1 + return sa + res = self.meta_interp(f, [32]) + assert res == f(32) + self.check_tree_loop_count(3) + + def test_two_loopinvariant_arrays3(self): + from pypy.rpython.lltypesystem import lltype, llmemory, rffi + myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a']) + TP = lltype.GcArray(lltype.Signed) + def f(n): + sa = i = 0 + a = lltype.malloc(TP, 5) + a[2] = 7 + while i < n: + myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i) + if i < n/2: + sa += a[2] + elif i > n/2: + sa += a[3] + if i == n/2: + a = lltype.malloc(TP, 7) + a[3] = 10 + a[2] = 42 + i += 1 + return sa + res = self.meta_interp(f, [32]) + assert res == f(32) + self.check_tree_loop_count(2) + + def test_two_loopinvariant_arrays_boxed(self): + class A(object): + def __init__(self, a): + self.a = a + from pypy.rpython.lltypesystem import lltype, llmemory, rffi + myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a']) + TP = lltype.GcArray(lltype.Signed) + a1 = A(lltype.malloc(TP, 5)) + a2 = A(lltype.malloc(TP, 3)) + def f(n): + sa = i = 0 + a = a1 + a.a[4] = 7 + while i < n: + myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i) + if i < n/2: + sa += a.a[4] + if i == n/2: + a = a2 + i += 1 + return sa + res = self.meta_interp(f, [32]) + assert res == f(32) + self.check_loops(arraylen_gc=1, everywhere=True) + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass From noreply at buildbot.pypy.org Wed Jul 20 10:19:42 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 20 Jul 2011 10:19:42 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: hg revert -r 45534 optimizeopt/vstring.py Message-ID: <20110720081942.B5B73829BA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45767:2386d79fafa6 Date: 2011-07-20 09:41 +0200 http://bitbucket.org/pypy/pypy/changeset/2386d79fafa6/ Log: hg revert -r 45534 optimizeopt/vstring.py diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -47,7 +47,7 @@ class __extend__(optimizer.OptValue): """New methods added to the base class OptValue for this file.""" - def getstrlen(self, optimizer, mode, lengthbox=None): + def getstrlen(self, optimization, mode): if mode is mode_string: s = self.get_constant_string_spec(mode_string) if s is not None: @@ -56,13 +56,12 @@ s = self.get_constant_string_spec(mode_unicode) if s is not None: return ConstInt(len(s)) - if optimizer is None: + if optimization is None: return None self.ensure_nonnull() box = self.force_box() - if not lengthbox: lengthbox = BoxInt() - optimizer.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) + optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -125,7 +124,7 @@ assert 0 <= start <= stop <= len(longerlist) self._chars = longerlist[start:stop] - def getstrlen(self, optimizer, mode, lengthbox=None): + def getstrlen(self, _, mode): if self._lengthbox is None: self._lengthbox = ConstInt(len(self._chars)) return self._lengthbox @@ -186,7 +185,7 @@ self.left = left self.right = right - def getstrlen(self, optimizer, mode, lengthbox=None): + def getstrlen(self, optimizer, mode): if self.lengthbox is None: len1box = self.left.getstrlen(optimizer, mode) if len1box is None: @@ -250,7 +249,7 @@ self.vstart = vstart self.vlength = vlength - def getstrlen(self, optimizer, mode, lengthbox=None): + def getstrlen(self, _, mode): return self.vlength.force_box() @specialize.arg(1) @@ -349,7 +348,7 @@ optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimization, strbox, indexbox, mode, resbox=None): +def _strgetitem(optimization, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +356,6 @@ else: s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) - if not resbox: resbox = BoxInt() optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) @@ -428,11 +426,10 @@ def _optimize_STRGETITEM(self, op, mode): value = self.getvalue(op.getarg(0)) vindex = self.getvalue(op.getarg(1)) - vresult = self.strgetitem(value, vindex, mode, op.result) - if op.result not in self.optimizer.values: + vresult = self.strgetitem(value, vindex, mode) self.make_equal_to(op.result, vresult) - def strgetitem(self, value, vindex, mode, result=None): + def strgetitem(self, value, vindex, mode): value.ensure_nonnull() # if value.is_virtual() and isinstance(value, VStringSliceValue): @@ -446,7 +443,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode, result) + resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): @@ -456,8 +453,7 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode, lengthbox=op.result) - if lengthbox is not op.result: + lengthbox = value.getstrlen(self, mode) self.make_equal_to(op.result, self.getvalue(lengthbox)) def optimize_CALL(self, op): From noreply at buildbot.pypy.org Wed Jul 20 10:19:43 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Wed, 20 Jul 2011 10:19:43 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: allow boxes to be replaced during initial setup of the peeled loop optimizer Message-ID: <20110720081943.ED7FD829BA@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45768:5c992bef0561 Date: 2011-07-20 10:19 +0200 http://bitbucket.org/pypy/pypy/changeset/5c992bef0561/ Log: allow boxes to be replaced during initial setup of the peeled loop optimizer diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6460,12 +6460,25 @@ call(i843, descr=nonwritedescr) jump(p9) """ + preamble = """ + [p9] + i843 = strlen(p9) + call(i843, descr=nonwritedescr) + jump(p9, i843) + """ + short = """ + [p9] + i843 = strlen(p9) + i848 = int_ge(i843, 0) + guard_true(i848)[] + jump(p9, i843) + """ expected = """ [p9, i2] call(i2, descr=nonwritedescr) jump(p9, i2) """ - self.optimize_loop(ops, expected) + self.optimize_loop(ops, expected, preamble, expected_short=short) def test_loopinvariant_strlen_with_bound(self): ops = """ diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -241,6 +241,10 @@ value = preamble_optimizer.getvalue(op.result) for guard in value.make_guards(op.result): self.optimizer.send_extra_operation(guard) + newresult = self.optimizer.getvalue(op.result).get_key_box() + if newresult is not op.result: + self.short_boxes.alias(newresult, op.result) + self.optimizer.flush() self.optimizer.emitting_dissabled = False @@ -259,7 +263,8 @@ # preamble_optimizer.send_extra_operation(jumpop) # return loop.inputargs = inputargs - jmp = ResOperation(rop.JUMP, loop.inputargs[:], None) + args = [self.short_boxes.original(a) for a in inputargs] + jmp = ResOperation(rop.JUMP, args, None) jmp.setdescr(loop.token) loop.preamble.operations.append(jmp) diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py --- a/pypy/jit/metainterp/optimizeopt/virtualstate.py +++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py @@ -458,6 +458,7 @@ self.potential_ops = {} optimizer.produce_potential_short_preamble_ops(self) + self.aliases = {} self.short_boxes = {} for box in surviving_boxes: self.short_boxes[box] = None @@ -502,3 +503,11 @@ def has_producer(self, box): return box in self.short_boxes + def alias(self, newbox, oldbox): + self.short_boxes[newbox] = self.short_boxes[oldbox] + self.aliases[newbox] = oldbox + + def original(self, box): + while box in self.aliases: + box = self.aliases[box] + return box From noreply at buildbot.pypy.org Wed Jul 20 12:45:53 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 20 Jul 2011 12:45:53 +0200 (CEST) Subject: [pypy-commit] jitviewer default: fix for weird classes (pdb is intentiional) Message-ID: <20110720104553.E5EA5829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r148:dde7241b441f Date: 2011-07-20 12:01 +0200 http://bitbucket.org/pypy/jitviewer/changeset/dde7241b441f/ Log: fix for weird classes (pdb is intentiional) diff --git a/_jitviewer/parser.py b/_jitviewer/parser.py --- a/_jitviewer/parser.py +++ b/_jitviewer/parser.py @@ -1,4 +1,5 @@ import re +import cgi from pypy.tool.jitlogparser import parser class Html(str): @@ -16,12 +17,13 @@ def cssclass(cls, s, **kwds): + cls = re.sub("[^\w]", "_", cls) attrs = ['%s="%s"' % (name, value) for name, value in kwds.iteritems()] - return '%s' % (cls, ' '.join(attrs), s) + return '%s' % (cls, ' '.join(attrs), + cgi.escape(s)) def _new_binop(name): - import cgi name = cgi.escape(name) def f(self): return '%s = %s %s %s' % (self.getres(), self.getarg(0), name, self.getarg(1)) @@ -114,6 +116,8 @@ class TraceForOpcodeHtml(parser.TraceForOpcode): def html_repr(self): + #import pdb + #pdb.set_trace() if self.filename is not None: code = self.getcode() if code is None: diff --git a/_jitviewer/test/test_parser.py b/_jitviewer/test/test_parser.py --- a/_jitviewer/test/test_parser.py +++ b/_jitviewer/test/test_parser.py @@ -35,3 +35,8 @@ html = op.html_repr() p0 = cssclass('p0', 'p0', onmouseover="highlight_var(this)", onmouseout="disable_var(this)") assert p0 in html + +def test_cssclass(): + s = cssclass('asd$%', 'v') + print s.__class__, s + assert '$' not in s diff --git a/bin/jitviewer.py b/bin/jitviewer.py --- a/bin/jitviewer.py +++ b/bin/jitviewer.py @@ -157,15 +157,6 @@ orig___init__(self2, *args, **kwds) BaseServer.__init__ = __init__ - -class CheckingLoopStorage(LoopStorage): - def disassemble_code(self, fname, startlineno, name): - result = super(CheckingLoopStorage, self).disassemble_code(fname, startlineno, name) - #if result is None and fname is not None: - # raise CannotFindFile(fname) - return result - - def main(): PATH = os.path.join(os.path.dirname((_jitviewer.__file__))) print PATH @@ -187,7 +178,7 @@ port = 5000 else: port = int(sys.argv[2]) - storage = CheckingLoopStorage(extra_path) + storage = LoopStorage(extra_path) log, loops = import_log(filename, ParserWithHtmlRepr) parse_log_counts(extract_category(log, 'jit-backend-count'), loops) storage.reconnect_loops(loops) From noreply at buildbot.pypy.org Wed Jul 20 13:13:18 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 20 Jul 2011 13:13:18 +0200 (CEST) Subject: [pypy-commit] benchmarks default: improve the error message as well as temporarily fix the problem Message-ID: <20110720111318.BE9D5829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r128:607ab424c877 Date: 2011-07-20 13:13 +0200 http://bitbucket.org/pypy/benchmarks/changeset/607ab424c877/ Log: improve the error message as well as temporarily fix the problem diff --git a/saveresults.py b/saveresults.py --- a/saveresults.py +++ b/saveresults.py @@ -40,6 +40,7 @@ 'benchmark': bench_name, 'environment': host, 'result_value': value, + 'branch': 'default', } if res_type == "ComparisonResult": if changed: @@ -71,6 +72,7 @@ response += ' Reason: ' + str(e.reason) elif hasattr(e, 'code'): response = '\n The server couldn\'t fulfill the request' + response = "\n".join([response] + e.readlines()) print("Server (%s) response: %s" % (SPEEDURL, response)) print(' Error code: %s\n' % (e,)) return 1 From noreply at buildbot.pypy.org Wed Jul 20 13:15:18 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 20 Jul 2011 13:15:18 +0200 (CEST) Subject: [pypy-commit] benchmarks default: use default instead of trunk Message-ID: <20110720111518.A883A829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r129:f79a86221205 Date: 2011-07-20 13:15 +0200 http://bitbucket.org/pypy/benchmarks/changeset/f79a86221205/ Log: use default instead of trunk diff --git a/runner.py b/runner.py --- a/runner.py +++ b/runner.py @@ -28,7 +28,7 @@ def run_and_store(benchmark_set, result_filename, pypy_c_path, revision=0, - options='', branch='trunk', args='', upload=False, + options='', branch='default', args='', upload=False, force_host=None, fast=False, baseline=sys.executable, full_store=False, postfix=''): funcs = perf.BENCH_FUNCS.copy() @@ -90,7 +90,7 @@ help='specify output filename to store resulting json') parser.add_option('--options', default='', action='store', help='a string describing picked options, no spaces') - parser.add_option('--branch', default='trunk', action='store', + parser.add_option('--branch', default='default', action='store', help="pypy's branch") parser.add_option('--baseline', default=sys.executable, action='store', help='baseline interpreter, defaults to host one') From noreply at buildbot.pypy.org Wed Jul 20 13:47:06 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Wed, 20 Jul 2011 13:47:06 +0200 (CEST) Subject: [pypy-commit] pypy heap-caching-during-tracing: close about-to-be-merged branch Message-ID: <20110720114706.9AE97829BA@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: heap-caching-during-tracing Changeset: r45769:6f28bd4db53f Date: 2011-07-20 13:40 +0200 http://bitbucket.org/pypy/pypy/changeset/6f28bd4db53f/ Log: close about-to-be-merged branch From noreply at buildbot.pypy.org Wed Jul 20 13:47:07 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Wed, 20 Jul 2011 13:47:07 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heap-caching-during-tracing: Message-ID: <20110720114707.EB62A829BA@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45770:3f7ee4a5a25a Date: 2011-07-20 13:46 +0200 http://bitbucket.org/pypy/pypy/changeset/3f7ee4a5a25a/ Log: merge heap-caching-during-tracing: perform some very simple and straightforward heap caching while tracing. this brings down the JIT overhead considerable, making warmup faster. diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -390,8 +390,21 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): - return self.execute_with_descr(rop.GETARRAYITEM_GC, + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache and isinstance(indexbox, ConstInt): + index = indexbox.getint() + frombox, tobox = cache.get(index, (None, None)) + if frombox is arraybox: + return tobox + resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) + if isinstance(indexbox, ConstInt): + if not cache: + cache = self.metainterp.heap_array_cache[arraydescr] = {} + index = indexbox.getint() + cache[index] = arraybox, resbox + return resbox + opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any @@ -419,6 +432,13 @@ indexbox, itembox): self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, itembox) + if isinstance(indexbox, ConstInt): + cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {}) + cache[indexbox.getint()] = arraybox, itembox + else: + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache: + cache.clear() opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any @@ -454,21 +474,17 @@ def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, - sbox, sizebox) + self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox) abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, sizebox) - self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, - sbox, abox) + self._opimpl_setfield_gc_any(sbox, itemsdescr, abox) return sbox @arguments("box", "descr", "descr", "box") def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox) opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any @@ -477,10 +493,9 @@ @arguments("box", "descr", "descr", "box", "box") def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, - indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox, + valuebox) opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any @@ -502,18 +517,29 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC, box, fielddescr) opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @arguments("box", "descr") def _opimpl_getfield_gc_pure_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_PURE, box, fielddescr) opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any + @specialize.arg(1) + def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(opnum, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox + @arguments("orgpc", "box", "descr") def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr): ginfo = self.metainterp.jitdriver_sd.greenfield_info @@ -532,7 +558,11 @@ @arguments("box", "descr", "box") def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box and tobox is valuebox: + return self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + self.metainterp.heap_cache[fielddescr] = (box, valuebox) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any @@ -617,7 +647,7 @@ @arguments("orgpc", "box", "descr") def _opimpl_getfield_vable(self, pc, box, fielddescr): if self._nonstandard_virtualizable(pc, box): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any(box, fielddescr) self.metainterp.check_synchronized_virtualizable() index = self._get_virtualizable_field_index(fielddescr) return self.metainterp.virtualizable_boxes[index] @@ -629,8 +659,7 @@ @arguments("orgpc", "box", "descr", "box") def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox): if self._nonstandard_virtualizable(pc, box): - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) - return + return self._opimpl_setfield_gc_any(box, fielddescr, valuebox) index = self._get_virtualizable_field_index(fielddescr) self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -660,10 +689,8 @@ @arguments("orgpc", "box", "descr", "descr", "box") def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr, - arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox) self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) return self.metainterp.virtualizable_boxes[index] @@ -676,10 +703,9 @@ def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox, valuebox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - self.execute_with_descr(rop.SETARRAYITEM_GC, adescr, - arraybox, indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + self._opimpl_setarrayitem_gc_any(arraybox, adescr, + indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -693,8 +719,7 @@ @arguments("orgpc", "box", "descr", "descr") def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -1462,6 +1487,12 @@ self.known_class_boxes = {} # contains frame boxes that are not virtualizables self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1637,10 +1668,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1804,6 +1852,8 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} + self.heap_array_cache = {} duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), @@ -2311,6 +2361,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1024,69 +1024,6 @@ res = self.meta_interp(main, []) assert res == 55 - def test_dont_record_repeated_guard_class(self): - class A: - pass - class B(A): - pass - @dont_look_inside - def extern(n): - if n == -7: - return None - elif n: - return A() - else: - return B() - def fn(n): - obj = extern(n) - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=1, guard_nonnull=1) - res = self.interp_operations(fn, [1]) - assert not res - - def test_dont_record_guard_class_after_new(self): - class A: - pass - class B(A): - pass - def fn(n): - if n == -7: - obj = None - elif n: - obj = A() - else: - obj = B() - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=0, guard_nonnull=0) - res = self.interp_operations(fn, [1]) - assert not res - - def test_guard_isnull_nullifies(self): - class A: - pass - a = A() - a.x = None - def fn(n): - if n == -7: - a.x = "" - obj = a.x - res = 0 - if not obj: - res += 1 - if obj: - res += 1 - if obj is None: - res += 1 - if obj is not None: - res += 1 - return res - res = self.interp_operations(fn, [0]) - assert res == 2 - self.check_operations_history(guard_isnull=1) def test_assert_isinstance(self): class A: @@ -1248,7 +1185,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,407 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + l = [1] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * (4 + a) + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + len(frame.l) + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ From noreply at buildbot.pypy.org Wed Jul 20 14:17:06 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 14:17:06 +0200 (CEST) Subject: [pypy-commit] buildbot default: make sure to save 32 and 64 bit results with different names Message-ID: <20110720121706.3B6F0829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r535:1176d49f7533 Date: 2011-07-20 14:17 +0200 http://bitbucket.org/pypy/buildbot/changeset/1176d49f7533/ Log: make sure to save 32 and 64 bit results with different names diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -304,7 +304,8 @@ workdir='./benchmarks', haltOnFailure=True)) # a bit obscure hack to get both os.path.expand and a property - resfile = os.path.expanduser("~/bench_results/%(got_revision)s.json") + filename = '%(got_revision)s' + (postfix or '') + resfile = os.path.expanduser("~/bench_results/%s.json" % filename) self.addStep(transfer.FileUpload(slavesrc="benchmarks/result.json", masterdest=WithProperties(resfile), workdir=".")) From noreply at buildbot.pypy.org Wed Jul 20 14:59:58 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 14:59:58 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: completely remove the global identitydict version from the space, and use the space.fromcache() approach instead Message-ID: <20110720125958.8CC47829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45771:0bba35bd5cfc Date: 2011-07-20 11:48 +0200 http://bitbucket.org/pypy/pypy/changeset/0bba35bd5cfc/ Log: completely remove the global identitydict version from the space, and use the space.fromcache() approach instead diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/identitydict.py @@ -0,0 +1,27 @@ +# a global (per-space) version counter to track live instances which "compare +# by identity" (i.e., whose __eq__, __cmp__ and __hash__ are the default +# ones). The idea is to track only classes for which we checked the +# compares_by_identity() status at least once: we increment the version if its +# status might change, e.g. because we set one of those attributes. The +# actual work is done by W_TypeObject.mutated() and objecttype:descr_setclass + +def bump_global_version(space): + if space.config.objspace.std.trackcomparebyidentity: + space.fromcache(ComparesByIdentityVersion).bump() + +def get_global_version(space): + if space.config.objspace.std.trackcomparebyidentity: + return space.fromcache(ComparesByIdentityVersion).get() + return None + +class ComparesByIdentityVersion(object): + + def __init__(self, space): + self.bump() + + def bump(self): + from pypy.objspace.std.typeobject import VersionTag + self._version = VersionTag() + + def get(self): + return self._version diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -6,7 +6,7 @@ from pypy.objspace.descroperation import Object from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.register_all import register_all - +from pypy.objspace.std import identitydict def descr__repr__(space, w_obj): w = space.wrap @@ -45,7 +45,7 @@ w_obj.setclass(space, w_newcls) if space.config.objspace.std.trackcomparebyidentity: if w_oldcls.compares_by_identity() and not w_newcls.compares_by_identity(): - space.compares_by_identity_version.bump() + identitydict.bump_global_version(space) else: raise operationerrfmt(space.w_TypeError, "__class__ assignment: '%s' object layout differs from '%s'", diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -32,7 +32,7 @@ from pypy.objspace.std.smallintobject import W_SmallIntObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.typeobject import W_TypeObject, VersionTag +from pypy.objspace.std.typeobject import W_TypeObject # types from pypy.objspace.std.inttype import wrapint @@ -43,15 +43,6 @@ """The standard object space, implementing a general-purpose object library in Restricted Python.""" - # a global version counter to track live instances which "compare by - # identity" (i.e., whose __eq__, __cmp__ and __hash__ are the default - # ones). The idea is to track only classes for which we checked the - # compares_by_identity() status at least once: we increment the version if - # its status might change, e.g. because we set one of those attributes. - # The actual work is done by W_TypeObject.mutated() and - # objecttype:descr_setclass - compares_by_identity_version = None - def initialize(self): "NOT_RPYTHON: only for initializing the space." # setup all the object types and implementations @@ -88,9 +79,6 @@ # the type of old-style classes self.w_classobj = self.builtin.get('__metaclass__') - if self.config.objspace.std.trackcomparebyidentity: - self.compares_by_identity_version = ComparesByIdentityVersion() - # final setup self.setup_builtin_modules() # Adding transparent proxy call @@ -580,12 +568,3 @@ if isinstance(w_sub, W_TypeObject) and isinstance(w_type, W_TypeObject): return self.wrap(w_sub.issubtype(w_type)) raise OperationError(self.w_TypeError, self.wrap("need type objects")) - - -class ComparesByIdentityVersion(object): - - def __init__(self): - self.bump() - - def bump(self): - self._version = VersionTag() diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1204,6 +1204,7 @@ class AppTestTrackCompareByIdentity: def setup_class(cls): + from pypy.objspace.std import identitydict cls.space = gettestobjspace( **{"objspace.std.trackcomparebyidentity": True}) @@ -1212,7 +1213,7 @@ cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) def get_version(space): - v = cls.versions.setdefault(space.compares_by_identity_version._version, + v = cls.versions.setdefault(identitydict.get_global_version(space), len(cls.versions)) return space.wrap(v) cls.w_get_version = cls.space.wrap(interp2app(get_version)) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -7,6 +7,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member from pypy.objspace.std.objecttype import object_typedef +from pypy.objspace.std import identitydict from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash from pypy.rlib.jit import promote, elidable_promote, we_are_jitted @@ -178,7 +179,7 @@ key == '__cmp__' or key == '__hash__'): w_self.compares_by_identity_status = UNKNOWN if did_compare_by_identity: - w_self.space.compares_by_identity_version.bump() + identitydict.bump_global_version(w_self.space) if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None From noreply at buildbot.pypy.org Wed Jul 20 14:59:59 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 14:59:59 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: rename the option to withidentitydict Message-ID: <20110720125959.CA8FB829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45772:deabe6d95200 Date: 2011-07-20 12:01 +0200 http://bitbucket.org/pypy/pypy/changeset/deabe6d95200/ Log: rename the option to withidentitydict diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -327,8 +327,8 @@ BoolOption("mutable_builtintypes", "Allow the changing of builtin types", default=False, requires=[("objspace.std.builtinshortcut", True)]), - BoolOption("trackcomparebyidentity", - "track types that override __hash__, __eq__ or __cmp__", + BoolOption("withidentitydict", + "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not", default=True), ]), ]) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -157,14 +157,14 @@ return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): - trackcomparebyidentity = self.space.config.objspace.std.trackcomparebyidentity + withidentitydict = self.space.config.objspace.std.withidentitydict if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) return w_type = self.space.type(w_key) if self.space.is_w(w_type, self.space.w_int): self.switch_to_int_strategy(w_dict) - elif trackcomparebyidentity and w_type.compares_by_identity(): + elif withidentitydict and w_type.compares_by_identity(): self.switch_to_identity_strategy(w_dict) else: self.switch_to_object_strategy(w_dict) diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py --- a/pypy/objspace/std/identitydict.py +++ b/pypy/objspace/std/identitydict.py @@ -6,11 +6,11 @@ # actual work is done by W_TypeObject.mutated() and objecttype:descr_setclass def bump_global_version(space): - if space.config.objspace.std.trackcomparebyidentity: + if space.config.objspace.std.withidentitydict: space.fromcache(ComparesByIdentityVersion).bump() def get_global_version(space): - if space.config.objspace.std.trackcomparebyidentity: + if space.config.objspace.std.withidentitydict: return space.fromcache(ComparesByIdentityVersion).get() return None diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -43,7 +43,7 @@ assert isinstance(w_oldcls, W_TypeObject) if w_oldcls.get_full_instance_layout() == w_newcls.get_full_instance_layout(): w_obj.setclass(space, w_newcls) - if space.config.objspace.std.trackcomparebyidentity: + if space.config.objspace.std.withidentitydict: if w_oldcls.compares_by_identity() and not w_newcls.compares_by_identity(): identitydict.bump_global_version(space) else: diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1109,7 +1109,7 @@ class AppTestIdentityDict(object): def setup_class(cls): - cls.space = gettestobjspace(**{"objspace.std.trackcomparebyidentity": True}) + cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) if option.runappdirect: py.test.skip("__repr__ doesn't work on appdirect") diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1201,12 +1201,12 @@ assert a.f(1) == 2 -class AppTestTrackCompareByIdentity: +class AppTestWithIdentityDict: def setup_class(cls): from pypy.objspace.std import identitydict cls.space = gettestobjspace( - **{"objspace.std.trackcomparebyidentity": True}) + **{"objspace.std.withidentitydict": True}) def compares_by_identity(space, w_cls): return space.wrap(w_cls.compares_by_identity()) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -107,7 +107,7 @@ # (False is a conservative default, fixed during real usage) uses_object_getattribute = False - # for config.objspace.std.trackcomparebyidentity + # for config.objspace.std.withidentitydict compares_by_identity_status = UNKNOWN # used to cache the type __new__ function if it comes from a builtin type @@ -164,7 +164,7 @@ assert w_self.is_heaptype() or space.config.objspace.std.mutable_builtintypes if (not space.config.objspace.std.withtypeversion and not space.config.objspace.std.getattributeshortcut and - not space.config.objspace.std.trackcomparebyidentity and + not space.config.objspace.std.withidentitydict and not space.config.objspace.std.newshortcut): return @@ -172,7 +172,7 @@ w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage - if space.config.objspace.std.trackcomparebyidentity: + if space.config.objspace.std.withidentitydict: did_compare_by_identity = ( w_self.compares_by_identity_status == COMPARES_BY_IDENTITY) if (key is None or key == '__eq__' or @@ -232,8 +232,7 @@ def compares_by_identity(w_self): from pypy.objspace.descroperation import object_hash - track = w_self.space.config.objspace.std.trackcomparebyidentity - if not track: + if not w_self.space.config.objspace.std.withidentitydict: return False # conservative # if w_self.compares_by_identity_status != UNKNOWN: From noreply at buildbot.pypy.org Wed Jul 20 15:00:01 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 15:00:01 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: IdentityDictStrategy cannot inherit from ObjectDictStrategy, else translation fails Message-ID: <20110720130001.07FC2829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45773:a37a1c0b4a30 Date: 2011-07-20 12:26 +0200 http://bitbucket.org/pypy/pypy/changeset/a37a1c0b4a30/ Log: IdentityDictStrategy cannot inherit from ObjectDictStrategy, else translation fails diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,4 +1,5 @@ import py, sys +from pypy.tool.sourcetools import func_with_new_name from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.settype import set_typedef as settypedef @@ -414,7 +415,7 @@ return self.unerase(w_dict.dstorage).keys() -class IdentityDictStrategy(ObjectDictStrategy): +class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): """ Strategy for custom instances which compares by identity (i.e., the default unless you override __hash__, __eq__ or __cmp__). The storage is @@ -422,6 +423,16 @@ semantics. """ + erase, unerase = rerased.new_erasing_pair("identitydict") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + def is_correct_type(self, w_obj): w_type = self.space.type(w_obj) return w_type.compares_by_identity() @@ -429,6 +440,15 @@ def get_empty_storage(self): return self.erase({}) + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return IdentityDictIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): @@ -542,6 +562,13 @@ return None, None +class IdentityDictIteratorImplementation(IteratorImplementation): + __init__ = func_with_new_name( + ObjectIteratorImplementation.__init__.im_func, '__init__') + + next_entry = func_with_new_name( + ObjectIteratorImplementation.next_entry.im_func, 'next_entry') + init_signature = Signature(['seq_or_map'], None, 'kwargs') init_defaults = [None] diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1162,3 +1162,10 @@ assert d[y] == 1 assert not self.uses_identity_strategy(d) + def test_iter(self): + class X(object): + pass + x = X() + d = {x: 1} + assert self.uses_identity_strategy(d) + assert list(iter(d)) == [x] From noreply at buildbot.pypy.org Wed Jul 20 15:00:02 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 15:00:02 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: store the dict as a tuple (version, d) Message-ID: <20110720130002.328B3829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45774:e7d4a83227a4 Date: 2011-07-20 12:33 +0200 http://bitbucket.org/pypy/pypy/changeset/e7d4a83227a4/ Log: store the dict as a tuple (version, d) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -3,6 +3,7 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.objspace.std import identitydict from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt @@ -423,9 +424,9 @@ semantics. """ - erase, unerase = rerased.new_erasing_pair("identitydict") - erase = staticmethod(erase) - unerase = staticmethod(unerase) + _erase_tuple, _unerase_tuple = rerased.new_erasing_pair("identitydict") + _erase_tuple = staticmethod(_erase_tuple) + _unerase_tuple = staticmethod(_unerase_tuple) def wrap(self, unwrapped): return unwrapped @@ -433,13 +434,25 @@ def unwrap(self, wrapped): return wrapped + def erase(self, d): + current_version = identitydict.get_global_version(self.space) + return self._erase_tuple((current_version, d)) + + def unerase(self, dstorage): + version, d = self._unerase_tuple(dstorage) + return d + + def get_current_version(self, dstorage): + version, d = self._unerase_tuple(dstorage) + return version + + def get_empty_storage(self): + return self.erase({}) + def is_correct_type(self, w_obj): w_type = self.space.type(w_obj) return w_type.compares_by_identity() - def get_empty_storage(self): - return self.erase({}) - def _never_equal_to(self, w_lookup_type): return False From noreply at buildbot.pypy.org Wed Jul 20 15:00:03 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 15:00:03 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: move the strategy to identitydict.py Message-ID: <20110720130003.6488D829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45775:be0b34777be3 Date: 2011-07-20 12:37 +0200 http://bitbucket.org/pypy/pypy/changeset/be0b34777be3/ Log: move the strategy to identitydict.py diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,9 +1,7 @@ import py, sys -from pypy.tool.sourcetools import func_with_new_name from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.settype import set_typedef as settypedef -from pypy.objspace.std import identitydict from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt @@ -184,6 +182,7 @@ w_dict.dstorage = storage def switch_to_identity_strategy(self, w_dict): + from pypy.objspace.std.identitydict import IdentityDictStrategy strategy = self.space.fromcache(IdentityDictStrategy) storage = strategy.get_empty_storage() w_dict.strategy = strategy @@ -416,53 +415,6 @@ return self.unerase(w_dict.dstorage).keys() -class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): - """ - Strategy for custom instances which compares by identity (i.e., the - default unless you override __hash__, __eq__ or __cmp__). The storage is - just a normal RPython dict, which has already the correct by-identity - semantics. - """ - - _erase_tuple, _unerase_tuple = rerased.new_erasing_pair("identitydict") - _erase_tuple = staticmethod(_erase_tuple) - _unerase_tuple = staticmethod(_unerase_tuple) - - def wrap(self, unwrapped): - return unwrapped - - def unwrap(self, wrapped): - return wrapped - - def erase(self, d): - current_version = identitydict.get_global_version(self.space) - return self._erase_tuple((current_version, d)) - - def unerase(self, dstorage): - version, d = self._unerase_tuple(dstorage) - return d - - def get_current_version(self, dstorage): - version, d = self._unerase_tuple(dstorage) - return version - - def get_empty_storage(self): - return self.erase({}) - - def is_correct_type(self, w_obj): - w_type = self.space.type(w_obj) - return w_type.compares_by_identity() - - def _never_equal_to(self, w_lookup_type): - return False - - def iter(self, w_dict): - return IdentityDictIteratorImplementation(self.space, self, w_dict) - - def keys(self, w_dict): - return self.unerase(w_dict.dstorage).keys() - - class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") @@ -574,14 +526,6 @@ else: return None, None - -class IdentityDictIteratorImplementation(IteratorImplementation): - __init__ = func_with_new_name( - ObjectIteratorImplementation.__init__.im_func, '__init__') - - next_entry = func_with_new_name( - ObjectIteratorImplementation.next_entry.im_func, 'next_entry') - init_signature = Signature(['seq_or_map'], None, 'kwargs') init_defaults = [None] diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py --- a/pypy/objspace/std/identitydict.py +++ b/pypy/objspace/std/identitydict.py @@ -1,3 +1,9 @@ +from pypy.rlib import rerased +from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, + DictStrategy, + IteratorImplementation) + + # a global (per-space) version counter to track live instances which "compare # by identity" (i.e., whose __eq__, __cmp__ and __hash__ are the default # ones). The idea is to track only classes for which we checked the @@ -25,3 +31,68 @@ def get(self): return self._version + + + +## ---------------------------------------------------------------------------- +## dict strategy (see dict_multiobject.py) + +# this strategy is selected by EmptyDictStrategy.switch_to_correct_strategy +class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): + """ + Strategy for custom instances which compares by identity (i.e., the + default unless you override __hash__, __eq__ or __cmp__). The storage is + just a normal RPython dict, which has already the correct by-identity + semantics. + """ + + _erase_tuple, _unerase_tuple = rerased.new_erasing_pair("identitydict") + _erase_tuple = staticmethod(_erase_tuple) + _unerase_tuple = staticmethod(_unerase_tuple) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def erase(self, d): + current_version = get_global_version(self.space) + return self._erase_tuple((current_version, d)) + + def unerase(self, dstorage): + version, d = self._unerase_tuple(dstorage) + return d + + def get_current_version(self, dstorage): + version, d = self._unerase_tuple(dstorage) + return version + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): + w_type = self.space.type(w_obj) + return w_type.compares_by_identity() + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return IdentityDictIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + + +class IdentityDictIteratorImplementation(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value + else: + return None, None From noreply at buildbot.pypy.org Wed Jul 20 15:00:04 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 15:00:04 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: move tests to their own file Message-ID: <20110720130004.95F02829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45776:cb2f09a69bda Date: 2011-07-20 13:25 +0200 http://bitbucket.org/pypy/pypy/changeset/cb2f09a69bda/ Log: move tests to their own file diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -1106,66 +1106,3 @@ d = fakespace.newdict(module=True) assert type(d.strategy) is StringDictStrategy - -class AppTestIdentityDict(object): - def setup_class(cls): - cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) - if option.runappdirect: - py.test.skip("__repr__ doesn't work on appdirect") - - def w_uses_identity_strategy(self, obj): - import __pypy__ - return "IdentityDictStrategy" in __pypy__.internal_repr(obj) - - def test_use_strategy(self): - class X(object): - pass - d = {} - x = X() - d[x] = 1 - assert self.uses_identity_strategy(d) - assert d[x] == 1 - - def test_bad_item(self): - class X(object): - pass - class Y(object): - def __hash__(self): - return 32 - - d = {} - x = X() - y = Y() - d[x] = 1 - assert self.uses_identity_strategy(d) - d[y] = 2 - assert not self.uses_identity_strategy(d) - assert d[x] == 1 - assert d[y] == 2 - - def test_bad_key(self): - class X(object): - pass - d = {} - x = X() - - class Y(object): - def __hash__(self): - return hash(x) # to make sure we do x == y - - def __eq__(self, other): - return True - - y = Y() - d[x] = 1 - assert self.uses_identity_strategy(d) - assert d[y] == 1 - assert not self.uses_identity_strategy(d) - - def test_iter(self): - class X(object): - pass - x = X() - d = {x: 1} - assert self.uses_identity_strategy(d) - assert list(iter(d)) == [x] diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_identitydict.py @@ -0,0 +1,169 @@ +from pypy.interpreter.gateway import interp2app +from pypy.conftest import gettestobjspace +from pypy.conftest import option + +class AppTestTrackVersion: + + def setup_class(cls): + from pypy.objspace.std import identitydict + cls.space = gettestobjspace( + **{"objspace.std.withidentitydict": True}) + + def compares_by_identity(space, w_cls): + return space.wrap(w_cls.compares_by_identity()) + cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) + + def get_version(space): + v = cls.versions.setdefault(identitydict.get_global_version(space), + len(cls.versions)) + return space.wrap(v) + cls.w_get_version = cls.space.wrap(interp2app(get_version)) + + def setup_method(self, m): + self.__class__.versions = {} + + def test_compares_by_identity(self): + class Plain(object): + pass + + class CustomEq(object): + def __eq__(self, other): + return True + + class CustomCmp (object): + def __cmp__(self, other): + return 0 + + class CustomHash(object): + def __hash__(self): + return 0 + + assert self.compares_by_identity(Plain) + assert not self.compares_by_identity(CustomEq) + assert not self.compares_by_identity(CustomCmp) + assert not self.compares_by_identity(CustomHash) + + def test_modify_class(self): + class X(object): + pass + + assert self.compares_by_identity(X) + X.__eq__ = lambda x: None + assert not self.compares_by_identity(X) + del X.__eq__ + assert self.compares_by_identity(X) + + def test_versioning(self): + class X(object): + pass + + class Y(object): + def __eq__(self, other): + pass + + assert self.get_version() == 0 + X.__eq__ = lambda x: None + # modifying a class for which we never checked the + # compares_by_identity() status does not increase the version + assert self.get_version() == 0 + + del X.__eq__ + assert self.compares_by_identity(X) # now we check it + X.__add__ = lambda x: None + assert self.get_version() == 0 # innocent change + # + X.__eq__ = lambda x: None + assert self.get_version() == 1 # BUMP! + + del X.__eq__ + assert self.compares_by_identity(X) + X.__bases__ = (object,) + assert self.get_version() == 2 # BUMP! + + # modifying a class which is already "bad" does not increase the + # version + Y.__eq__ = lambda x: None + assert self.get_version() == 2 + + def test_change___class__(self): + class X(object): + pass + + class Y(object): + pass + + class Z(object): + def __eq__(self, other): + pass + + x = X() + assert self.compares_by_identity(X) + assert self.get_version() == 0 + x.__class__ = Y + assert self.get_version() == 0 + x.__class__ = Z + assert self.get_version() == 1 + + +class AppTestIdentityDict(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_uses_identity_strategy(self, obj): + import __pypy__ + return "IdentityDictStrategy" in __pypy__.internal_repr(obj) + + def test_use_strategy(self): + class X(object): + pass + d = {} + x = X() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[x] == 1 + + def test_bad_item(self): + class X(object): + pass + class Y(object): + def __hash__(self): + return 32 + + d = {} + x = X() + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + d[y] = 2 + assert not self.uses_identity_strategy(d) + assert d[x] == 1 + assert d[y] == 2 + + def test_bad_key(self): + class X(object): + pass + d = {} + x = X() + + class Y(object): + def __hash__(self): + return hash(x) # to make sure we do x == y + + def __eq__(self, other): + return True + + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[y] == 1 + assert not self.uses_identity_strategy(d) + + def test_iter(self): + class X(object): + pass + x = X() + d = {x: 1} + assert self.uses_identity_strategy(d) + assert list(iter(d)) == [x] diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1199,106 +1199,3 @@ return x + 1 a = A() assert a.f(1) == 2 - - -class AppTestWithIdentityDict: - - def setup_class(cls): - from pypy.objspace.std import identitydict - cls.space = gettestobjspace( - **{"objspace.std.withidentitydict": True}) - - def compares_by_identity(space, w_cls): - return space.wrap(w_cls.compares_by_identity()) - cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) - - def get_version(space): - v = cls.versions.setdefault(identitydict.get_global_version(space), - len(cls.versions)) - return space.wrap(v) - cls.w_get_version = cls.space.wrap(interp2app(get_version)) - - def setup_method(self, m): - self.__class__.versions = {} - - def test_compares_by_identity(self): - class Plain(object): - pass - - class CustomEq(object): - def __eq__(self, other): - return True - - class CustomCmp (object): - def __cmp__(self, other): - return 0 - - class CustomHash(object): - def __hash__(self): - return 0 - - assert self.compares_by_identity(Plain) - assert not self.compares_by_identity(CustomEq) - assert not self.compares_by_identity(CustomCmp) - assert not self.compares_by_identity(CustomHash) - - def test_modify_class(self): - class X(object): - pass - - assert self.compares_by_identity(X) - X.__eq__ = lambda x: None - assert not self.compares_by_identity(X) - del X.__eq__ - assert self.compares_by_identity(X) - - def test_versioning(self): - class X(object): - pass - - class Y(object): - def __eq__(self, other): - pass - - assert self.get_version() == 0 - X.__eq__ = lambda x: None - # modifying a class for which we never checked the - # compares_by_identity() status does not increase the version - assert self.get_version() == 0 - - del X.__eq__ - assert self.compares_by_identity(X) # now we check it - X.__add__ = lambda x: None - assert self.get_version() == 0 # innocent change - # - X.__eq__ = lambda x: None - assert self.get_version() == 1 # BUMP! - - del X.__eq__ - assert self.compares_by_identity(X) - X.__bases__ = (object,) - assert self.get_version() == 2 # BUMP! - - # modifying a class which is already "bad" does not increase the - # version - Y.__eq__ = lambda x: None - assert self.get_version() == 2 - - def test_change___class__(self): - class X(object): - pass - - class Y(object): - pass - - class Z(object): - def __eq__(self, other): - pass - - x = X() - assert self.compares_by_identity(X) - assert self.get_version() == 0 - x.__class__ = Y - assert self.get_version() == 0 - x.__class__ = Z - assert self.get_version() == 1 From noreply at buildbot.pypy.org Wed Jul 20 15:00:05 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 15:00:05 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: fix test Message-ID: <20110720130005.C2669829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45777:9c8a3b6a766b Date: 2011-07-20 13:39 +0200 http://bitbucket.org/pypy/pypy/changeset/9c8a3b6a766b/ Log: fix test diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -898,6 +898,7 @@ withsmalldicts = False withcelldict = False withmethodcache = False + withidentitydict = False FakeSpace.config = Config() From noreply at buildbot.pypy.org Wed Jul 20 15:00:06 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 15:00:06 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: kill a bit of duplicated code by using mixins Message-ID: <20110720130006.EF6C4829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45778:fba910e841e1 Date: 2011-07-20 13:51 +0200 http://bitbucket.org/pypy/pypy/changeset/fba910e841e1/ Log: kill a bit of duplicated code by using mixins diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -459,7 +459,9 @@ return StrIteratorImplementation(self.space, self, w_dict) -class StrIteratorImplementation(IteratorImplementation): +class _WrappedIteratorMixin(object): + _mixin_ = True + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() @@ -471,6 +473,23 @@ else: return None, None +class _UnwrappedIteratorMixin(IteratorImplementation): + _mixin_ = True + + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value + else: + return None, None + + +class StrIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass class IntDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("int") @@ -501,30 +520,11 @@ def iter(self, w_dict): return IntIteratorImplementation(self.space, self, w_dict) -class IntIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() +class IntIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass - def next_entry(self): - # note that this 'for' loop only runs once, at most - for key, w_value in self.iterator: - return self.space.wrap(key), w_value - else: - return None, None - - -class ObjectIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() - - def next_entry(self): - # note that this 'for' loop only runs once, at most - for w_key, w_value in self.iterator: - return w_key, w_value - else: - return None, None +class ObjectIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass init_signature = Signature(['seq_or_map'], None, 'kwargs') init_defaults = [None] diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py --- a/pypy/objspace/std/identitydict.py +++ b/pypy/objspace/std/identitydict.py @@ -1,7 +1,8 @@ from pypy.rlib import rerased from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, DictStrategy, - IteratorImplementation) + IteratorImplementation, + _UnwrappedIteratorMixin) # a global (per-space) version counter to track live instances which "compare @@ -85,14 +86,5 @@ return self.unerase(w_dict.dstorage).keys() -class IdentityDictIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() - - def next_entry(self): - # note that this 'for' loop only runs once, at most - for w_key, w_value in self.iterator: - return w_key, w_value - else: - return None, None +class IdentityDictIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass From noreply at buildbot.pypy.org Wed Jul 20 15:36:29 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 15:36:29 +0200 (CEST) Subject: [pypy-commit] benchmarks default: turn saveresult.py into a script which can be invoked from the command line Message-ID: <20110720133629.74CC0829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r130:0f41c4155021 Date: 2011-07-20 15:36 +0200 http://bitbucket.org/pypy/benchmarks/changeset/0f41c4155021/ Log: turn saveresult.py into a script which can be invoked from the command line diff --git a/saveresults.py b/saveresults.py old mode 100644 new mode 100755 --- a/saveresults.py +++ b/saveresults.py @@ -1,10 +1,29 @@ +#!/usr/bin/env python # -*- coding: utf-8 -*- ####################################################### # This script saves result data # # It expects the format of unladen swallow's perf.py # ####################################################### + +""" +Upload a json file generated by runner.py. + +Revision, name and host are required. + +Example usage: + + $ ./saveresults.py result.json -r '45757:fabe4fc0dc08' -n pypy-c-jit -H tannit + + OR + + $ ./saveresults.py result.json -r '45757:fabe4fc0dc08' -n pypy-c-jit-64 -H tannit + +""" + +import sys import urllib, urllib2 from datetime import datetime +import optparse SPEEDURL = "http://speed.pypy.org/" @@ -79,3 +98,31 @@ print "saved correctly!\n" return 0 + +def main(jsonfile, options): + import simplejson + with open(jsonfile) as f: + data = simplejson.load(f) + results = data['results'] + print 'uploading results...', + save('PyPy', options.revision, results, '', options.name, options.host, + changed=options.changed) + print 'done' + + +if __name__ == '__main__': + parser = optparse.OptionParser(usage="%prog result.json [options]") + parser.add_option('-r', '--revision', dest='revision', default=None, type=str) + parser.add_option('-n', '--name', dest='name', default=None, type=str) + parser.add_option('-H', '--host', dest='host', default=None, type=str) + parser.add_option('-b', '--baseline', dest='changed', default=True, + action='store_false', + help='upload the results as baseline instead of changed') + parser.format_description = lambda fmt: __doc__ + parser.description = __doc__ + options, args = parser.parse_args() + if options.revision is None or options.name is None or options.host is None or \ + len(args) != 1: + parser.print_help() + sys.exit(2) + main(args[0], options) From noreply at buildbot.pypy.org Wed Jul 20 16:46:05 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 20 Jul 2011 16:46:05 +0200 (CEST) Subject: [pypy-commit] pypy default: bah. use full name of missing debug merge point Message-ID: <20110720144605.05F2F829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45779:081e9f2ae2b2 Date: 2011-07-20 16:46 +0200 http://bitbucket.org/pypy/pypy/changeset/081e9f2ae2b2/ Log: bah. use full name of missing debug merge point diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -148,7 +148,7 @@ operations[0].getarg(1)) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) From noreply at buildbot.pypy.org Wed Jul 20 17:20:24 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 20 Jul 2011 17:20:24 +0200 (CEST) Subject: [pypy-commit] jitviewer default: remove the pdb Message-ID: <20110720152024.F135C829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r149:a0458e4c4015 Date: 2011-07-20 17:20 +0200 http://bitbucket.org/pypy/jitviewer/changeset/a0458e4c4015/ Log: remove the pdb diff --git a/_jitviewer/parser.py b/_jitviewer/parser.py --- a/_jitviewer/parser.py +++ b/_jitviewer/parser.py @@ -116,8 +116,6 @@ class TraceForOpcodeHtml(parser.TraceForOpcode): def html_repr(self): - #import pdb - #pdb.set_trace() if self.filename is not None: code = self.getcode() if code is None: From noreply at buildbot.pypy.org Wed Jul 20 17:42:37 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 20 Jul 2011 17:42:37 +0200 (CEST) Subject: [pypy-commit] jitviewer default: warn about wrong jinja version Message-ID: <20110720154237.40BB2829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r150:c52176233061 Date: 2011-07-20 17:42 +0200 http://bitbucket.org/pypy/jitviewer/changeset/c52176233061/ Log: warn about wrong jinja version diff --git a/bin/jitviewer.py b/bin/jitviewer.py --- a/bin/jitviewer.py +++ b/bin/jitviewer.py @@ -37,11 +37,15 @@ raise ImportError('Could not import pypy module, make sure to ' 'add the pypy module to PYTHONPATH') +import jinja2 +if jinja2.__version__ < '2.6': + raise ImportError("Required jinja version is 2.6 (the git tip), older versions might segfault PyPy") + import flask import inspect import threading import time -from pypy.tool.logparser import parse_log_file, extract_category +from pypy.tool.logparser import extract_category from pypy.tool.jitlogparser.storage import LoopStorage from pypy.tool.jitlogparser.parser import adjust_bridges, import_log # From noreply at buildbot.pypy.org Wed Jul 20 18:04:09 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 20 Jul 2011 18:04:09 +0200 (CEST) Subject: [pypy-commit] jitviewer default: start working on a filter bar Message-ID: <20110720160409.EC874829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r151:220ed6187123 Date: 2011-07-20 18:04 +0200 http://bitbucket.org/pypy/jitviewer/changeset/220ed6187123/ Log: start working on a filter bar diff --git a/_jitviewer/static/script.js b/_jitviewer/static/script.js --- a/_jitviewer/static/script.js +++ b/_jitviewer/static/script.js @@ -35,6 +35,11 @@ show_loop(val); } } + $("#inp-bar").focus(); + $("#inp-bar").bind("click keyup", function() { + var value = $("#inp-bar")[0].value; + + }); } function replace_from(elem, bridge_id) diff --git a/_jitviewer/templates/index.html b/_jitviewer/templates/index.html --- a/_jitviewer/templates/index.html +++ b/_jitviewer/templates/index.html @@ -22,13 +22,16 @@
      +
      + Filter: +
        {% for is_entry_bridge, index, item in loops %} {% if is_entry_bridge %} -
      • Entry bridge: {{item.repr()}} run {{item.count}} times
      • +
      • Entry bridge: {{item.repr()}} run {{item.count}} times
      • {% else %} -
      • {{item.repr()}} run {{item.count}} times
      • +
      • {{item.repr()}} run {{item.count}} times
      • {% endif %} {% endfor %}
      From noreply at buildbot.pypy.org Wed Jul 20 18:51:28 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 20 Jul 2011 18:51:28 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix a veeeery slow leak. Message-ID: <20110720165128.89458829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45780:27f5477fcaa7 Date: 2011-07-20 18:51 +0200 http://bitbucket.org/pypy/pypy/changeset/27f5477fcaa7/ Log: Fix a veeeery slow leak. diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py --- a/pypy/rpython/memory/gctransform/asmgcroot.py +++ b/pypy/rpython/memory/gctransform/asmgcroot.py @@ -184,7 +184,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.aid2stack = copy_without_null_values(gcdata.aid2stack) + copy = copy_without_null_values(gcdata.aid2stack) + gcdata.aid2stack.delete() + gcdata.aid2stack = copy def belongs_to_current_thread(framedata): # xxx obscure: the answer is Yes if, as a pointer, framedata diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1449,8 +1449,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.thread_stacks = copy_without_null_values( - gcdata.thread_stacks) + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy def switch_shadow_stacks(new_aid): save_away_current_stack() From noreply at buildbot.pypy.org Wed Jul 20 19:17:41 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 20 Jul 2011 19:17:41 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: new fragility tests for better error reporting Message-ID: <20110720171741.5919D829BA@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45781:8e482e29abf4 Date: 2011-07-20 09:18 -0700 http://bitbucket.org/pypy/pypy/changeset/8e482e29abf4/ Log: new fragility tests for better error reporting diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -142,7 +142,7 @@ self.name = name def convert_argument(self, space, w_obj, address): - raise OperationError(space.w_TypeError, + raise OperationError(space.w_RuntimeError, space.wrap('no converter available for type "%s"' % self.name)) diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -20,7 +20,9 @@ self.name = name def execute(self, space, w_returntype, func, cppthis, num_args, args): - raise NotImplementedError + rtype = capi.charp2str_free(capi.c_method_result_type(func.cpptype.handle, func.method_index)) + raise OperationError(space.w_NotImplementedError, + space.wrap('return type not available or supported ("%s")' % rtype)) def execute_libffi(self, space, w_returntype, libffifunc, argchain): from pypy.module.cppyy.interp_cppyy import FastCallNotPossible diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -7,7 +7,7 @@ from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib import libffi +from pypy.rlib import libffi, rdynload from pypy.rlib import jit, debug from pypy.module.cppyy import converter, executor, helper @@ -19,7 +19,10 @@ def load_lib(space, name): # TODO: the following uses a hacked CDLL that won't work on Windows + try: cdll = libffi.CDLL(name, 0x100 | 0x02) + except rdynload.DLOpenError, e: + raise OperationError(space.w_RuntimeError, space.wrap(str(e))) return W_CPPLibrary(space, cdll) load_lib.unwrap_spec = [ObjSpace, str] @@ -215,8 +218,6 @@ newthis = capi.c_allocate(self.cpptype.handle) assert lltype.typeOf(newthis) == rffi.VOIDP try: - # TODO: this does not work for CINT, as it calls a temp object - # by value returning method, not placement on newthis ... CPPMethod.call(self, newthis, None, args_w) except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile --- a/pypy/module/cppyy/test/Makefile +++ b/pypy/module/cppyy/test/Makefile @@ -1,4 +1,4 @@ -dicts = example01Dict.so datatypesDict.so advancedcppDict.so stltypesDict.so operatorsDict.so +dicts = example01Dict.so datatypesDict.so advancedcppDict.so stltypesDict.so operatorsDict.so fragileDict.so all : $(dicts) ROOTSYS := ${ROOTSYS} diff --git a/pypy/module/cppyy/test/fragile.cxx b/pypy/module/cppyy/test/fragile.cxx new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/fragile.cxx @@ -0,0 +1,1 @@ +#include "fragile.h" diff --git a/pypy/module/cppyy/test/fragile.h b/pypy/module/cppyy/test/fragile.h new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/fragile.h @@ -0,0 +1,16 @@ +namespace fragile { + +class no_such_class; + +class A { +public: + virtual int check() { return (int)'A'; } +}; + +class B { +public: + virtual int check() { return (int)'B'; } + no_such_class* gime_no_such() { return 0; } +}; + +} // namespace fragile diff --git a/pypy/module/cppyy/test/fragile.xml b/pypy/module/cppyy/test/fragile.xml new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/fragile.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/pypy/module/cppyy/test/test_fragile.py b/pypy/module/cppyy/test/test_fragile.py new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/test_fragile.py @@ -0,0 +1,47 @@ +import py, os, sys +from pypy.conftest import gettestobjspace + + +currpath = py.path.local(__file__).dirpath() +shared_lib = str(currpath.join("fragileDict.so")) + +space = gettestobjspace(usemodules=['cppyy']) + +def setup_module(mod): + if sys.platform == 'win32': + py.test.skip("win32 not supported so far") + err = os.system("cd '%s' && make fragileDict.so" % currpath) + if err: + raise OSError("'make' failed (see stderr)") + +class AppTestSTL: + def setup_class(cls): + cls.space = space + env = os.environ + cls.w_shared_lib = space.wrap(shared_lib) + cls.w_datatypes = cls.space.appexec([], """(): + import cppyy + return cppyy.load_lib(%r)""" % (shared_lib, )) + + def test01_load_failure(self): + """Test failure to load dictionary""" + + import cppyy + raises(RuntimeError, cppyy.load_lib, "does_not_exist.so") + + def test02_missing_classes(self): + """Test (non-)access to missing classes""" + + import cppyy + + raises(AttributeError, getattr, cppyy.gbl, "no_such_class") + + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + + raises(AttributeError, getattr, fragile, "no_such_class") + + assert fragile.B == fragile.B + assert fragile.B().check() == ord('B') + + raises(NotImplementedError, fragile.B().gime_no_such) diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py --- a/pypy/module/cppyy/test/test_zjit.py +++ b/pypy/module/cppyy/test/test_zjit.py @@ -38,6 +38,8 @@ w_TypeError = FakeType("TypeError") w_AttributeError = FakeType("AttributeError") w_ReferenceError = FakeType("ReferenceError") + w_NotImplementedError = FakeType("NotImplementedError") + w_RuntimeError = FakeType("RuntimeError") w_None = None w_str = FakeType("str") From noreply at buildbot.pypy.org Wed Jul 20 19:17:42 2011 From: noreply at buildbot.pypy.org (wlav) Date: Wed, 20 Jul 2011 19:17:42 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: more error reporting improvements Message-ID: <20110720171742.868CF829BA@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45782:99b892c7fff4 Date: 2011-07-20 10:17 -0700 http://bitbucket.org/pypy/pypy/changeset/99b892c7fff4/ Log: more error reporting improvements diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -142,7 +142,7 @@ self.name = name def convert_argument(self, space, w_obj, address): - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_NotImplementedError, space.wrap('no converter available for type "%s"' % self.name)) diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py --- a/pypy/module/cppyy/interp_cppyy.py +++ b/pypy/module/cppyy/interp_cppyy.py @@ -111,7 +111,7 @@ raise OperationError(self.space.w_TypeError, self.space.wrap("return type not handled")) if len(self.arg_types) < len(args_w) or len(args_w) < self.args_required: - raise OperationError(self.space.w_TypeError, self.space.wrap("wrong number of args")) + raise OperationError(self.space.w_TypeError, self.space.wrap("wrong number of arguments")) if self.methgetter and cppthis: # only for methods try: @@ -261,7 +261,8 @@ return cppinstance # recycle object to preserve identity return cppresult except OperationError, e: - if not e.match(space, space.w_TypeError): + if not (e.match(space, space.w_TypeError) or \ + e.match(space, space.w_NotImplementedError)): raise errmsg += '\n\t'+str(e) except KeyError: diff --git a/pypy/module/cppyy/test/fragile.h b/pypy/module/cppyy/test/fragile.h --- a/pypy/module/cppyy/test/fragile.h +++ b/pypy/module/cppyy/test/fragile.h @@ -13,4 +13,19 @@ no_such_class* gime_no_such() { return 0; } }; +class C { +public: + virtual int check() { return (int)'C'; } + void use_no_such(no_such_class*) {} +}; + +class D { +public: + virtual int check() { return (int)'D'; } + void overload() {} + void overload(no_such_class*) {} + void overload(char, int i = 0) {} // Reflex requires a named arg + void overload(int, no_such_class* p = 0) {} +}; + } // namespace fragile diff --git a/pypy/module/cppyy/test/fragile.xml b/pypy/module/cppyy/test/fragile.xml --- a/pypy/module/cppyy/test/fragile.xml +++ b/pypy/module/cppyy/test/fragile.xml @@ -4,5 +4,7 @@ + + diff --git a/pypy/module/cppyy/test/test_fragile.py b/pypy/module/cppyy/test/test_fragile.py --- a/pypy/module/cppyy/test/test_fragile.py +++ b/pypy/module/cppyy/test/test_fragile.py @@ -41,7 +41,27 @@ raises(AttributeError, getattr, fragile, "no_such_class") + assert fragile.C == fragile.C + assert fragile.C().check() == ord('C') + assert fragile.B == fragile.B assert fragile.B().check() == ord('B') + raises(TypeError, fragile.B().gime_no_such) - raises(NotImplementedError, fragile.B().gime_no_such) + assert fragile.C == fragile.C + assert fragile.C().check() == ord('C') + raises(TypeError, fragile.C().use_no_such, None) + + def test03_arguments(self): + """Test reporting when providing wrong arguments""" + + import cppyy + + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + + assert fragile.D == fragile.D + assert fragile.D().check() == ord('D') + + d = fragile.D() + raises(TypeError, d.overload, None) From noreply at buildbot.pypy.org Wed Jul 20 20:50:09 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 20 Jul 2011 20:50:09 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: fix translation Message-ID: <20110720185009.EA94F829BA@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45783:cd9422d1a4fa Date: 2011-07-20 20:48 +0200 http://bitbucket.org/pypy/pypy/changeset/cd9422d1a4fa/ Log: fix translation diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -473,7 +473,7 @@ else: return None, None -class _UnwrappedIteratorMixin(IteratorImplementation): +class _UnwrappedIteratorMixin: _mixin_ = True def __init__(self, space, strategy, dictimplementation): diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -86,7 +86,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated() + self.unerase(w_dict.dstorage).mutated(None) class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): From notifications-noreply at bitbucket.org Wed Jul 20 22:54:51 2011 From: notifications-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 20:54:51 -0000 Subject: [pypy-commit] Notification: pypy Message-ID: <20110720205451.1048.62098@bitbucket03.managed.contegix.com> You have received a notification from cgerum. Hi, I forked pypy. My fork is at https://bitbucket.org/cgerum/pypy. -- Change your notification settings at https://bitbucket.org/account/notifications/ From pullrequests-noreply at bitbucket.org Wed Jul 20 23:30:48 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Wed, 20 Jul 2011 21:30:48 -0000 Subject: [pypy-commit] [OPEN] Pull request #4 for pypy: trigonometric ufuncs Message-ID: A new pull request has been opened by cgerum. cgerum/pypy has changes to be pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/4/trigonometric-ufuncs Title: trigonometric ufuncs This patch implements the ufuncs sin, cos and tan for micronumpy. -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From noreply at buildbot.pypy.org Wed Jul 20 23:35:52 2011 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 20 Jul 2011 23:35:52 +0200 (CEST) Subject: [pypy-commit] pypy default: (chrisge) sin/cos/tan ufuncs Message-ID: <20110720213552.5DB5B829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45784:4761f5600f29 Date: 2011-07-20 23:35 +0200 http://bitbucket.org/pypy/pypy/changeset/4761f5600f29/ Log: (chrisge) sin/cos/tan ufuncs diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -23,6 +23,9 @@ 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'sin': 'interp_ufuncs.sin', + 'cos': 'interp_ufuncs.cos', + 'tan': 'interp_ufuncs.tan', } appleveldefs = { diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -74,3 +74,15 @@ if value == 0.0: return 0.0 return rfloat.copysign(1.0, value) + + at ufunc +def sin(value): + return math.sin(value) + + at ufunc +def cos(value): + return math.cos(value) + + at ufunc +def tan(value): + return math.tan(value) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -133,3 +133,30 @@ except OverflowError: res = float('inf') assert b[i] == res + + def test_sin(self): + import math + from numpy import array, sin + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = sin(a) + for i in range(len(a)): + assert b[i] == math.sin(a[i]) + + def test_cos(self): + import math + from numpy import array, cos + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = cos(a) + for i in range(len(a)): + assert b[i] == math.cos(a[i]) + + def test_tan(self): + import math + from numpy import array, tan + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = tan(a) + for i in range(len(a)): + assert b[i] == math.tan(a[i]) From noreply at buildbot.pypy.org Thu Jul 21 00:02:06 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 21 Jul 2011 00:02:06 +0200 (CEST) Subject: [pypy-commit] pypy streamio-bufout: Sped up BufferingOutputStream and LineBufferingOutputStream Message-ID: <20110720220206.CEB4B829BA@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: streamio-bufout Changeset: r45785:5d4b20b417a5 Date: 2011-07-19 17:19 -0600 http://bitbucket.org/pypy/pypy/changeset/5d4b20b417a5/ Log: Sped up BufferingOutputStream and LineBufferingOutputStream diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -875,27 +875,30 @@ if bufsize == -1: # Get default from the class bufsize = self.bufsize self.bufsize = bufsize # buffer size (hint only) - self.buf = "" + self.buf = [] + self.buflen = 0 def flush_buffers(self): if self.buf: - self.do_write(self.buf) - self.buf = "" + self.do_write(''.join(self.buf)) + self.buf = [] def tell(self): return self.do_tell() + len(self.buf) def write(self, data): - buflen = len(self.buf) + buflen = self.buflen datalen = len(data) if datalen + buflen < self.bufsize: - self.buf += data + self.buf.append(data) + self.buflen += datalen elif buflen: slice = self.bufsize - buflen assert slice >= 0 - self.buf += data[:slice] - self.do_write(self.buf) - self.buf = "" + self.buf.append(data[:slice]) + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 self.write(data[slice:]) else: self.do_write(data) @@ -922,11 +925,29 @@ """ def write(self, data): - BufferingOutputStream.write(self, data) - p = self.buf.rfind('\n') + 1 + p = data.rfind('\n') + 1 + L = len(data) if p >= 0: - self.do_write(self.buf[:p]) - self.buf = self.buf[p:] + if self.buf: + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 + if L - p > self.bufsize: + self.do_write(data) + else: + self.do_write(data[:p]) + if p != L: + self.buf.append(data[p:]) + self.buflen = L - p + else: + if L + self.buflen > self.bufsize: + self.do_write(''.join(self.buf)) + self.do_write(data) + self.buf = [] + self.buflen = 0 + else: + self.buf.append(data) + self.buflen += L # ____________________________________________________________ From noreply at buildbot.pypy.org Thu Jul 21 00:02:08 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 21 Jul 2011 00:02:08 +0200 (CEST) Subject: [pypy-commit] pypy streamio-bufout: Fixed BufferedOutputStream and LineBufferedOutputStream so that they fully pass all tests. Message-ID: <20110720220208.054C3829BA@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: streamio-bufout Changeset: r45786:a93fcd815003 Date: 2011-07-19 23:25 -0600 http://bitbucket.org/pypy/pypy/changeset/a93fcd815003/ Log: Fixed BufferedOutputStream and LineBufferedOutputStream so that they fully pass all tests. diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -882,9 +882,10 @@ if self.buf: self.do_write(''.join(self.buf)) self.buf = [] + self.buflen = 0 def tell(self): - return self.do_tell() + len(self.buf) + return self.do_tell() + self.buflen def write(self, data): buflen = self.buflen @@ -893,13 +894,13 @@ self.buf.append(data) self.buflen += datalen elif buflen: - slice = self.bufsize - buflen - assert slice >= 0 - self.buf.append(data[:slice]) + i = self.bufsize - buflen + assert i >= 0 + self.buf.append(data[:i]) self.do_write(''.join(self.buf)) self.buf = [] self.buflen = 0 - self.write(data[slice:]) + self.write(data[i:]) else: self.do_write(data) @@ -926,28 +927,26 @@ def write(self, data): p = data.rfind('\n') + 1 - L = len(data) - if p >= 0: - if self.buf: + assert p >= 0 + if self.buflen + len(data) < self.bufsize: + if p == 0: + self.buf.append(data) + self.buflen += len(data) + else: + if self.buflen: self.do_write(''.join(self.buf)) - self.buf = [] - self.buflen = 0 - if L - p > self.bufsize: - self.do_write(data) + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) else: + if self.buflen + p < self.bufsize: + p = self.bufsize - self.buflen + if self.buflen: + self.do_write(''.join(self.buf)) + assert p >= 0 self.do_write(data[:p]) - if p != L: - self.buf.append(data[p:]) - self.buflen = L - p - else: - if L + self.buflen > self.bufsize: - self.do_write(''.join(self.buf)) - self.do_write(data) - self.buf = [] - self.buflen = 0 - else: - self.buf.append(data) - self.buflen += L + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) # ____________________________________________________________ From noreply at buildbot.pypy.org Thu Jul 21 00:38:08 2011 From: noreply at buildbot.pypy.org (amauryfa) Date: Thu, 21 Jul 2011 00:38:08 +0200 (CEST) Subject: [pypy-commit] pypy default: Simplification in genc: merge gen_source_standalone() into gen_source() Message-ID: <20110720223808.EFCC3829BA@wyvern.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r45787:e4eef33f1a65 Date: 2011-07-20 22:15 +0200 http://bitbucket.org/pypy/pypy/changeset/e4eef33f1a65/ Log: Simplification in genc: merge gen_source_standalone() into gen_source() diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -251,12 +251,8 @@ CBuilder.have___thread = self.translator.platform.check___thread() if not self.standalone: assert not self.config.translation.instrument - self.eci, cfile, extra = gen_source(db, modulename, targetdir, - self.eci, - defines = defines, - split=self.split) else: - pfname = db.get(pf) + defines['PYPY_STANDALONE'] = db.get(pf) if self.config.translation.instrument: defines['INSTRUMENT'] = 1 if CBuilder.have___thread: @@ -266,11 +262,9 @@ defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( export_symbols=["pypy_main_startup"])) - self.eci, cfile, extra = gen_source_standalone(db, modulename, - targetdir, - self.eci, - entrypointname = pfname, - defines = defines) + self.eci, cfile, extra = gen_source(db, modulename, targetdir, + self.eci, defines=defines, + split=self.split) self.c_source_filename = py.path.local(cfile) self.extrafiles = self.eventually_copy(extra) self.gen_makefile(targetdir, exe_name=exe_name) @@ -435,6 +429,7 @@ class CStandaloneBuilder(CBuilder): standalone = True + split = True executable_name = None shared_library_name = None @@ -948,63 +943,8 @@ return eci.merge(ExternalCompilationInfo(separate_module_files=files)) -def gen_source_standalone(database, modulename, targetdir, eci, - entrypointname, defines={}): - assert database.standalone - if isinstance(targetdir, str): - targetdir = py.path.local(targetdir) - - filename = targetdir.join(modulename + '.c') - f = filename.open('w') - incfilename = targetdir.join('common_header.h') - fi = incfilename.open('w') - - # - # Header - # - print >> f, '#include "common_header.h"' - print >> f - commondefs(defines) - defines['PYPY_STANDALONE'] = entrypointname - for key, value in defines.items(): - print >> fi, '#define %s %s' % (key, value) - - eci.write_c_header(fi) - print >> fi, '#include "src/g_prerequisite.h"' - - fi.close() - - preimplementationlines = list( - pre_include_code_lines(database, database.translator.rtyper)) - - # - # 1) All declarations - # 2) Implementation of functions and global structures and arrays - # - sg = SourceGenerator(database, preimplementationlines) - sg.set_strategy(targetdir) - database.prepare_inline_helpers() - sg.gen_readable_parts_of_source(f) - - # 3) start-up code - print >> f - gen_startupcode(f, database) - - f.close() - - if 'INSTRUMENT' in defines: - fi = incfilename.open('a') - n = database.instrument_ncounter - print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n - fi.close() - - eci = add_extra_files(eci) - eci = eci.convert_sources_to_files(being_main=True) - files, eci = eci.get_module_files() - return eci, filename, sg.getextrafiles() + list(files) - -def gen_source(database, modulename, targetdir, eci, defines={}, split=False): - assert not database.standalone +def gen_source(database, modulename, targetdir, + eci, defines={}, split=False): if isinstance(targetdir, str): targetdir = py.path.local(targetdir) @@ -1046,6 +986,12 @@ gen_startupcode(f, database) f.close() + if 'INSTRUMENT' in defines: + fi = incfilename.open('a') + n = database.instrument_ncounter + print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n + fi.close() + eci = add_extra_files(eci) eci = eci.convert_sources_to_files(being_main=True) files, eci = eci.get_module_files() diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py --- a/pypy/translator/c/test/test_genc.py +++ b/pypy/translator/c/test/test_genc.py @@ -4,7 +4,6 @@ from pypy.translator.translator import TranslationContext from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c import genc -from pypy.translator.c.genc import gen_source from pypy.translator.c.gc import NoneGcPolicy from pypy.objspace.flow.model import Constant, Variable, SpaceOperation from pypy.objspace.flow.model import Block, Link, FunctionGraph From noreply at buildbot.pypy.org Thu Jul 21 09:38:54 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 21 Jul 2011 09:38:54 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ufuncs: Merged default. Message-ID: <20110721073854.AC350829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: numpy-ufuncs Changeset: r45788:913b1e486c54 Date: 2011-07-21 00:19 -0700 http://bitbucket.org/pypy/pypy/changeset/913b1e486c54/ Log: Merged default. diff --git a/pypy/config/config.py b/pypy/config/config.py --- a/pypy/config/config.py +++ b/pypy/config/config.py @@ -81,6 +81,12 @@ (self.__class__, name)) return self._cfgimpl_values[name] + def __dir__(self): + from_type = dir(type(self)) + from_dict = list(self.__dict__) + extras = list(self._cfgimpl_values) + return sorted(set(extras + from_type + from_dict)) + def __delattr__(self, name): # XXX if you use delattr you are responsible for all bad things # happening diff --git a/pypy/config/test/test_config.py b/pypy/config/test/test_config.py --- a/pypy/config/test/test_config.py +++ b/pypy/config/test/test_config.py @@ -63,6 +63,20 @@ py.test.raises(ConfigError, 'config.gc.name = "ref"') config.gc.name = "framework" +def test___dir__(): + descr = make_description() + config = Config(descr, bool=False) + attrs = dir(config) + assert '__repr__' in attrs # from the type + assert '_cfgimpl_values' in attrs # from self + assert 'gc' in attrs # custom attribute + assert 'objspace' in attrs # custom attribute + # + attrs = dir(config.gc) + assert 'name' in attrs + assert 'dummy' in attrs + assert 'float' in attrs + def test_arbitrary_option(): descr = OptionDescription("top", "", [ ArbitraryOption("a", "no help", default=None) diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -140,7 +140,10 @@ ["annotate", "rtype", "backendopt", "database", "source", "pyjitpl"], default=None, cmdline="--fork-before"), - + BoolOption("dont_write_c_files", + "Make the C backend write everyting to /dev/null. " + + "Useful for benchmarking, so you don't actually involve the disk", + default=False, cmdline="--dont-write-c-files"), ArbitraryOption("instrumentctl", "internal", default=None), StrOption("output", "Output file name", cmdline="--output"), diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -31,7 +31,8 @@ _immutable_fields_ = ['code?', 'w_func_globals?', 'closure?', - 'defs_w?[*]'] + 'defs_w?[*]', + 'name?'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -5,10 +5,9 @@ from pypy.jit.codewriter import support from pypy.jit.codewriter.jitcode import JitCode -from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer -from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer -from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze -from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection +from pypy.jit.codewriter.effectinfo import (VirtualizableAnalyzer, + QuasiImmutAnalyzer, CanReleaseGILAnalyzer, effectinfo_from_writeanalyze, + EffectInfo, CallInfoCollection) from pypy.translator.simplify import get_funcobj, get_functype from pypy.rpython.lltypesystem import lltype, llmemory from pypy.translator.backendopt.canraise import RaiseAnalyzer @@ -32,6 +31,7 @@ self.readwrite_analyzer = ReadWriteAnalyzer(translator) self.virtualizable_analyzer = VirtualizableAnalyzer(translator) self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator) + self.canreleasegil_analyzer = CanReleaseGILAnalyzer(translator) # for index, jd in enumerate(jitdrivers_sd): jd.index = index @@ -219,7 +219,9 @@ assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect - can_invalidate = self.quasiimmut_analyzer.analyze(op) + can_release_gil = self.canreleasegil_analyzer.analyze(op) + # can_release_gil implies can_invalidate + can_invalidate = can_release_gil or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE @@ -235,7 +237,7 @@ # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, - oopspecindex, can_invalidate) + oopspecindex, can_invalidate, can_release_gil) # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -79,13 +79,15 @@ write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, - can_invalidate=False): + can_invalidate=False, can_release_gil=False): key = (frozenset(readonly_descrs_fields), frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, - oopspecindex) + oopspecindex, + can_invalidate, + can_release_gil) if key in cls._cache: return cls._cache[key] result = object.__new__(cls) @@ -100,6 +102,7 @@ result.write_descrs_arrays = write_descrs_arrays result.extraeffect = extraeffect result.can_invalidate = can_invalidate + result.can_release_gil = can_release_gil result.oopspecindex = oopspecindex cls._cache[key] = result return result @@ -111,12 +114,13 @@ return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE def has_random_effects(self): - return self.oopspecindex == self.OS_LIBFFI_CALL + return self.oopspecindex == self.OS_LIBFFI_CALL or self.can_release_gil def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, - can_invalidate=False): + can_invalidate=False, + can_release_gil=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: return None @@ -158,7 +162,8 @@ write_descrs_arrays, extraeffect, oopspecindex, - can_invalidate) + can_invalidate, + can_release_gil) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: @@ -194,6 +199,16 @@ def analyze_simple_operation(self, op, graphinfo): return op.opname == 'jit_force_quasi_immutable' +class CanReleaseGILAnalyzer(BoolGraphAnalyzer): + def analyze_direct_call(self, graph, seen=None): + releases_gil = False + if hasattr(graph, "func") and hasattr(graph.func, "_ptr"): + releases_gil = graph.func._ptr._obj.releases_gil + return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen) + + def analyze_simple_operation(self, op, graphinfo): + return False + # ____________________________________________________________ class CallInfoCollection(object): diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -395,7 +395,7 @@ ('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed), ('int_abs', [lltype.Signed], lltype.Signed), ('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float), - ] +] class LLtypeHelpers: diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py --- a/pypy/jit/codewriter/test/test_call.py +++ b/pypy/jit/codewriter/test/test_call.py @@ -1,6 +1,6 @@ import py from pypy.objspace.flow.model import SpaceOperation, Constant, Variable -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.unsimplify import varoftype from pypy.rlib import jit from pypy.jit.codewriter.call import CallControl @@ -171,3 +171,24 @@ def test_jit_force_virtualizable_effectinfo(): py.test.skip("XXX add a test for CallControl.getcalldescr() -> EF_xxx") + +def test_releases_gil_analyzer(): + from pypy.jit.backend.llgraph.runner import LLtypeCPU + + T = rffi.CArrayPtr(rffi.TIME_T) + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + + @jit.dont_look_inside + def f(): + return external(lltype.nullptr(T.TO)) + + rtyper = support.annotate(f, []) + jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) + cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) + res = cc.find_all_graphs(FakePolicy()) + + [f_graph] = [x for x in res if x.func is f] + [block, _] = list(f_graph.iterblocks()) + [op] = block.operations + call_descr = cc.getcalldescr(op) + assert call_descr.extrainfo.can_release_gil \ No newline at end of file diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -61,7 +61,6 @@ optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble, retraced) - if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -390,8 +390,21 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): - return self.execute_with_descr(rop.GETARRAYITEM_GC, + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache and isinstance(indexbox, ConstInt): + index = indexbox.getint() + frombox, tobox = cache.get(index, (None, None)) + if frombox is arraybox: + return tobox + resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) + if isinstance(indexbox, ConstInt): + if not cache: + cache = self.metainterp.heap_array_cache[arraydescr] = {} + index = indexbox.getint() + cache[index] = arraybox, resbox + return resbox + opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any @@ -419,6 +432,13 @@ indexbox, itembox): self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, itembox) + if isinstance(indexbox, ConstInt): + cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {}) + cache[indexbox.getint()] = arraybox, itembox + else: + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache: + cache.clear() opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any @@ -454,21 +474,17 @@ def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, - sbox, sizebox) + self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox) abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, sizebox) - self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, - sbox, abox) + self._opimpl_setfield_gc_any(sbox, itemsdescr, abox) return sbox @arguments("box", "descr", "descr", "box") def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox) opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any @@ -477,10 +493,9 @@ @arguments("box", "descr", "descr", "box", "box") def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, - indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox, + valuebox) opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any @@ -502,18 +517,29 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC, box, fielddescr) opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @arguments("box", "descr") def _opimpl_getfield_gc_pure_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_PURE, box, fielddescr) opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any + @specialize.arg(1) + def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(opnum, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox + @arguments("orgpc", "box", "descr") def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr): ginfo = self.metainterp.jitdriver_sd.greenfield_info @@ -532,7 +558,11 @@ @arguments("box", "descr", "box") def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box and tobox is valuebox: + return self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + self.metainterp.heap_cache[fielddescr] = (box, valuebox) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any @@ -617,7 +647,7 @@ @arguments("orgpc", "box", "descr") def _opimpl_getfield_vable(self, pc, box, fielddescr): if self._nonstandard_virtualizable(pc, box): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any(box, fielddescr) self.metainterp.check_synchronized_virtualizable() index = self._get_virtualizable_field_index(fielddescr) return self.metainterp.virtualizable_boxes[index] @@ -629,8 +659,7 @@ @arguments("orgpc", "box", "descr", "box") def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox): if self._nonstandard_virtualizable(pc, box): - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) - return + return self._opimpl_setfield_gc_any(box, fielddescr, valuebox) index = self._get_virtualizable_field_index(fielddescr) self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -660,10 +689,8 @@ @arguments("orgpc", "box", "descr", "descr", "box") def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr, - arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox) self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) return self.metainterp.virtualizable_boxes[index] @@ -676,10 +703,9 @@ def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox, valuebox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - self.execute_with_descr(rop.SETARRAYITEM_GC, adescr, - arraybox, indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + self._opimpl_setarrayitem_gc_any(arraybox, adescr, + indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -693,8 +719,7 @@ @arguments("orgpc", "box", "descr", "descr") def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -1462,6 +1487,12 @@ self.known_class_boxes = {} # contains frame boxes that are not virtualizables self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1637,10 +1668,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1804,6 +1852,8 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} + self.heap_array_cache = {} duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), @@ -2311,6 +2361,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -11,7 +11,7 @@ from pypy import conftest from pypy.rlib.rarithmetic import ovfcheck from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -1024,69 +1024,6 @@ res = self.meta_interp(main, []) assert res == 55 - def test_dont_record_repeated_guard_class(self): - class A: - pass - class B(A): - pass - @dont_look_inside - def extern(n): - if n == -7: - return None - elif n: - return A() - else: - return B() - def fn(n): - obj = extern(n) - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=1, guard_nonnull=1) - res = self.interp_operations(fn, [1]) - assert not res - - def test_dont_record_guard_class_after_new(self): - class A: - pass - class B(A): - pass - def fn(n): - if n == -7: - obj = None - elif n: - obj = A() - else: - obj = B() - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=0, guard_nonnull=0) - res = self.interp_operations(fn, [1]) - assert not res - - def test_guard_isnull_nullifies(self): - class A: - pass - a = A() - a.x = None - def fn(n): - if n == -7: - a.x = "" - obj = a.x - res = 0 - if not obj: - res += 1 - if obj: - res += 1 - if obj is None: - res += 1 - if obj is not None: - res += 1 - return res - res = self.interp_operations(fn, [0]) - assert res == 2 - self.check_operations_history(guard_isnull=1) def test_assert_isinstance(self): class A: @@ -1248,7 +1185,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: @@ -1616,8 +1553,6 @@ assert res == 1 def test_raw_malloc_and_access(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Signed) def f(n): @@ -1631,8 +1566,6 @@ assert res == 10 def test_raw_malloc_and_access_float(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Float) def f(n, f): @@ -2619,5 +2552,41 @@ self.meta_interp(f, [], enable_opts='') self.check_loops(new_with_vtable=1) + def test_release_gil_flush_heap_cache(self): + T = rffi.CArrayPtr(rffi.TIME_T) + + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + # Not a real lock, has all the same properties with respect to GIL + # release though, so good for this test. + class Lock(object): + @dont_look_inside + def acquire(self): + external(lltype.nullptr(T.TO)) + @dont_look_inside + def release(self): + external(lltype.nullptr(T.TO)) + class X(object): + def __init__(self, idx): + self.field = idx + @dont_look_inside + def get_obj(z): + return X(z) + myjitdriver = JitDriver(greens=[], reds=["n", "l", "z", "lock"]) + def f(n, z): + lock = Lock() + l = 0 + while n > 0: + myjitdriver.jit_merge_point(lock=lock, l=l, n=n, z=z) + x = get_obj(z) + l += x.field + lock.acquire() + # This must not reuse the previous one. + n -= x.field + lock.release() + return n + res = self.meta_interp(f, [10, 1]) + self.check_loops(getfield_gc=2) + + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,407 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + l = [1] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * (4 + a) + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + len(frame.l) + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -268,3 +268,7 @@ if errors: w_errors = space.wrap(rffi.charp2str(errors)) return space.call_method(w_str, 'encode', w_encoding, w_errors) + + at cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -287,3 +287,9 @@ def test_eq(self, space, api): assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'ab' diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -28,6 +28,9 @@ 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', 'subtract': 'interp_ufuncs.subtract', + 'sin': 'interp_ufuncs.sin', + 'cos': 'interp_ufuncs.cos', + 'tan': 'interp_ufuncs.tan', } appleveldefs = { diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,7 +2,9 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit +from pypy.rlib.rfloat import DTSF_STR_PRECISION from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name import math @@ -55,6 +57,9 @@ def minimum(v1, v2): return min(v1, v2) +def float2string(x): + return float2string_orig(x, 'g', DTSF_STR_PRECISION) + class BaseArray(Wrappable): def __init__(self): self.invalidates = [] @@ -235,6 +240,24 @@ else: return self.descr_mul(space, w_other) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] + nums.append("..." + "," * comma) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) + else: + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] + return nums + def get_concrete(self): raise NotImplementedError @@ -245,10 +268,14 @@ return self.get_concrete().descr_len(space) def descr_repr(self, space): - return self.get_concrete()._repr(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])") def descr_str(self, space): - return self.get_concrete()._str(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("[" + " ".join(concrete._getnums(True)) + "]") def descr_getitem(self, space, w_idx): # TODO: indexing by tuples @@ -439,26 +466,6 @@ def calc_index(self, item): return (self.start + item * self.step) - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - class SingleDimArray(BaseArray): signature = Signature() @@ -496,26 +503,6 @@ def getitem(self, item): return self.storage[item] - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -94,3 +94,15 @@ if value == 0.0: return 0.0 return rfloat.copysign(1.0, value) + + at ufunc +def sin(value): + return math.sin(value) + + at ufunc +def cos(value): + return math.cos(value) + + at ufunc +def tan(value): + return math.tan(value) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -178,3 +178,30 @@ except OverflowError: res = float('inf') assert b[i] == res + + def test_sin(self): + import math + from numpy import array, sin + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = sin(a) + for i in range(len(a)): + assert b[i] == math.sin(a[i]) + + def test_cos(self): + import math + from numpy import array, cos + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = cos(a) + for i in range(len(a)): + assert b[i] == math.cos(a[i]) + + def test_tan(self): + import math + from numpy import array, tan + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = tan(a) + for i in range(len(a)): + assert b[i] == math.tan(a[i]) diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -133,8 +133,7 @@ else: return space.wrap("0x%sp%s%d" % (s, sign, exp)) -def float2string(space, w_float, code, precision): - x = w_float.floatval +def float2string(x, code, precision): # we special-case explicitly inf and nan here if isfinite(x): s = formatd(x, code, precision, DTSF_ADD_DOT_0) @@ -145,13 +144,13 @@ s = "-inf" else: # isnan(x): s = "nan" - return space.wrap(s) + return s def repr__Float(space, w_float): - return float2string(space, w_float, 'r', 0) + return space.wrap(float2string(w_float.floatval, 'r', 0)) def str__Float(space, w_float): - return float2string(space, w_float, 'g', DTSF_STR_PRECISION) + return space.wrap(float2string(w_float.floatval, 'g', DTSF_STR_PRECISION)) def format__Float_ANY(space, w_float, w_spec): return newformat.run_formatter(space, w_spec, "format_float", w_float) diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -69,8 +69,6 @@ [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) -math_log = llexternal('log', [rffi.DOUBLE], rffi.DOUBLE) -math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -222,10 +220,6 @@ return (fracpart, intpart) -def ll_math_copysign(x, y): - return math_copysign(x, y) # no error checking needed - - def ll_math_fmod(x, y): if isinf(y): if isinf(x): diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -102,19 +102,6 @@ else: callbackholder = None - funcptr = lltype.functionptr(ext_type, name, external='C', - compilation_info=compilation_info, - _callable=_callable, - _safe_not_sandboxed=sandboxsafe, - _debugexc=True, # on top of llinterp - canraise=False, - **kwds) - if isinstance(_callable, ll2ctypes.LL2CtypesCallable): - _callable.funcptr = funcptr - - if _nowrapper: - return funcptr - if threadsafe in (False, True): # invoke the around-handlers, which release the GIL, if and only if # the C function is thread-safe. @@ -125,6 +112,21 @@ # sandboxsafe is a hint for "too-small-ness" (e.g. math functions). invoke_around_handlers = not sandboxsafe + funcptr = lltype.functionptr(ext_type, name, external='C', + compilation_info=compilation_info, + _callable=_callable, + _safe_not_sandboxed=sandboxsafe, + _debugexc=True, # on top of llinterp + canraise=False, + releases_gil=invoke_around_handlers, + **kwds) + if isinstance(_callable, ll2ctypes.LL2CtypesCallable): + _callable.funcptr = funcptr + + if _nowrapper: + return funcptr + + if invoke_around_handlers: # The around-handlers are releasing the GIL in a threaded pypy. # We need tons of care to ensure that no GC operation and no diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py --- a/pypy/rpython/memory/gctransform/asmgcroot.py +++ b/pypy/rpython/memory/gctransform/asmgcroot.py @@ -184,7 +184,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.aid2stack = copy_without_null_values(gcdata.aid2stack) + copy = copy_without_null_values(gcdata.aid2stack) + gcdata.aid2stack.delete() + gcdata.aid2stack = copy def belongs_to_current_thread(framedata): # xxx obscure: the answer is Yes if, as a pointer, framedata diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1449,8 +1449,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.thread_stacks = copy_without_null_values( - gcdata.thread_stacks) + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy def switch_shadow_stacks(new_aid): save_away_current_stack() diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -148,7 +148,7 @@ operations[0].getarg(1)) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) diff --git a/pypy/tool/nullpath.py b/pypy/tool/nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/nullpath.py @@ -0,0 +1,12 @@ +import py + +class NullPyPathLocal(py.path.local): + + def join(self, *args): + return self.__class__(py.path.local.join(self, *args)) + + def open(self, mode): + return open('/dev/null', mode) + + def __repr__(self): + return py.path.local.__repr__(self) + ' [fake]' diff --git a/pypy/tool/test/test_nullpath.py b/pypy/tool/test/test_nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/test/test_nullpath.py @@ -0,0 +1,16 @@ +import sys +import py +from pypy.tool.nullpath import NullPyPathLocal + +def setup_module(): + if 'posix' not in sys.builtin_module_names: + py.test.skip('posix only') + +def test_nullpath(tmpdir): + path = NullPyPathLocal(tmpdir) + assert repr(path).endswith('[fake]') + foo_txt = path.join('foo.txt') + assert isinstance(foo_txt, NullPyPathLocal) + # + f = foo_txt.open('w') + assert f.name == '/dev/null' diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -13,6 +13,7 @@ from pypy.rpython.typesystem import getfunctionptr from pypy.translator.c import gc from pypy.rlib import exports +from pypy.tool.nullpath import NullPyPathLocal def import_module_from_directory(dir, modname): file, pathname, description = imp.find_module(modname, [str(dir)]) @@ -237,6 +238,8 @@ self.modulename = uniquemodulename('testing') modulename = self.modulename targetdir = udir.ensure(modulename, dir=1) + if self.config.translation.dont_write_c_files: + targetdir = NullPyPathLocal(targetdir) self.targetdir = targetdir defines = defines.copy() @@ -248,12 +251,8 @@ CBuilder.have___thread = self.translator.platform.check___thread() if not self.standalone: assert not self.config.translation.instrument - self.eci, cfile, extra = gen_source(db, modulename, targetdir, - self.eci, - defines = defines, - split=self.split) else: - pfname = db.get(pf) + defines['PYPY_STANDALONE'] = db.get(pf) if self.config.translation.instrument: defines['INSTRUMENT'] = 1 if CBuilder.have___thread: @@ -263,11 +262,9 @@ defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( export_symbols=["pypy_main_startup"])) - self.eci, cfile, extra = gen_source_standalone(db, modulename, - targetdir, - self.eci, - entrypointname = pfname, - defines = defines) + self.eci, cfile, extra = gen_source(db, modulename, targetdir, + self.eci, defines=defines, + split=self.split) self.c_source_filename = py.path.local(cfile) self.extrafiles = self.eventually_copy(extra) self.gen_makefile(targetdir, exe_name=exe_name) @@ -432,6 +429,7 @@ class CStandaloneBuilder(CBuilder): standalone = True + split = True executable_name = None shared_library_name = None @@ -944,64 +942,12 @@ ] return eci.merge(ExternalCompilationInfo(separate_module_files=files)) -def gen_source_standalone(database, modulename, targetdir, eci, - entrypointname, defines={}): - assert database.standalone + +def gen_source(database, modulename, targetdir, + eci, defines={}, split=False): if isinstance(targetdir, str): targetdir = py.path.local(targetdir) - filename = targetdir.join(modulename + '.c') - f = filename.open('w') - incfilename = targetdir.join('common_header.h') - fi = incfilename.open('w') - # - # Header - # - print >> f, '#include "common_header.h"' - print >> f - commondefs(defines) - defines['PYPY_STANDALONE'] = entrypointname - for key, value in defines.items(): - print >> fi, '#define %s %s' % (key, value) - - eci.write_c_header(fi) - print >> fi, '#include "src/g_prerequisite.h"' - - fi.close() - - preimplementationlines = list( - pre_include_code_lines(database, database.translator.rtyper)) - - # - # 1) All declarations - # 2) Implementation of functions and global structures and arrays - # - sg = SourceGenerator(database, preimplementationlines) - sg.set_strategy(targetdir) - database.prepare_inline_helpers() - sg.gen_readable_parts_of_source(f) - - # 3) start-up code - print >> f - gen_startupcode(f, database) - - f.close() - - if 'INSTRUMENT' in defines: - fi = incfilename.open('a') - n = database.instrument_ncounter - print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n - fi.close() - - eci = add_extra_files(eci) - eci = eci.convert_sources_to_files(being_main=True) - files, eci = eci.get_module_files() - return eci, filename, sg.getextrafiles() + list(files) - -def gen_source(database, modulename, targetdir, eci, defines={}, split=False): - assert not database.standalone - if isinstance(targetdir, str): - targetdir = py.path.local(targetdir) filename = targetdir.join(modulename + '.c') f = filename.open('w') incfilename = targetdir.join('common_header.h') @@ -1040,6 +986,12 @@ gen_startupcode(f, database) f.close() + if 'INSTRUMENT' in defines: + fi = incfilename.open('a') + n = database.instrument_ncounter + print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n + fi.close() + eci = add_extra_files(eci) eci = eci.convert_sources_to_files(being_main=True) files, eci = eci.get_module_files() diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py --- a/pypy/translator/c/test/test_genc.py +++ b/pypy/translator/c/test/test_genc.py @@ -4,7 +4,6 @@ from pypy.translator.translator import TranslationContext from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c import genc -from pypy.translator.c.genc import gen_source from pypy.translator.c.gc import NoneGcPolicy from pypy.objspace.flow.model import Constant, Variable, SpaceOperation from pypy.objspace.flow.model import Block, Link, FunctionGraph @@ -13,6 +12,7 @@ from pypy.translator.backendopt.all import backend_optimizations from pypy.translator.interactive import Translation from pypy.rlib.entrypoint import entrypoint +from pypy.tool.nullpath import NullPyPathLocal def compile(fn, argtypes, view=False, gcpolicy="ref", backendopt=True, annotatorpolicy=None): @@ -63,6 +63,22 @@ py.test.raises(Exception, f1, "world") # check that it's really typed + +def test_dont_write_source_files(): + def f(x): + return x*2 + t = TranslationContext() + t.buildannotator().build_types(f, [int]) + t.buildrtyper().specialize() + + t.config.translation.countmallocs = True + t.config.translation.dont_write_c_files = True + builder = genc.CExtModuleBuilder(t, f, config=t.config) + builder.generate_source() + assert isinstance(builder.targetdir, NullPyPathLocal) + assert builder.targetdir.listdir() == [] + + def test_simple_lambda(): f = lambda x: x*2 t = TranslationContext() From noreply at buildbot.pypy.org Thu Jul 21 09:38:55 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 21 Jul 2011 09:38:55 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ufuncs: Make the operators on an array use the ufuncs internally. Message-ID: <20110721073855.DBE85829BA@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: numpy-ufuncs Changeset: r45789:cb06fc29e57c Date: 2011-07-21 00:38 -0700 http://bitbucket.org/pypy/pypy/changeset/cb06fc29e57c/ Log: Make the operators on an array use the ufuncs internally. diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -3,7 +3,7 @@ It should not be imported by the module itself """ -from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray class BogusBytecode(Exception): pass @@ -18,6 +18,14 @@ def wrap(self, x): return x + def issequence_w(self, w_obj): + # Completley wrong in the general case, but good enough for this. + return isinstance(w_obj, BaseArray) + + def float_w(self, w_obj): + assert isinstance(w_obj, float) + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() stack = [] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,6 +2,8 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy.interp_support import Signature +from pypy.module.micronumpy import interp_ufuncs from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit from pypy.rlib.rfloat import DTSF_STR_PRECISION @@ -24,16 +26,6 @@ all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) -class Signature(object): - def __init__(self): - self.transitions = {} - - def transition(self, target): - if target in self.transitions: - return self.transitions[target] - self.transitions[target] = new = Signature() - return new - def pos(v): return v def neg(v): @@ -42,16 +34,8 @@ return abs(v) def add(v1, v2): return v1 + v2 -def sub(v1, v2): - return v1 - v2 def mul(v1, v2): return v1 * v2 -def div(v1, v2): - return v1 / v2 -def power(v1, v2): - return math.pow(v1, v2) -def mod(v1, v2): - return math.fmod(v1, v2) def maximum(v1, v2): return max(v1, v2) def minimum(v1, v2): @@ -89,51 +73,30 @@ descr_neg = _unop_impl(neg) descr_abs = _unop_impl(absolute) - def _binop_impl(function): - signature = Signature() + def _binop_impl(w_ufunc): def impl(self, space, w_other): - w_other = convert_to_array(space, w_other) - new_sig = self.signature.transition(signature) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + return w_ufunc(space, self, w_other) + return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__) - descr_add = _binop_impl(add) - descr_sub = _binop_impl(sub) - descr_mul = _binop_impl(mul) - descr_div = _binop_impl(div) - descr_pow = _binop_impl(power) - descr_mod = _binop_impl(mod) + descr_add = _binop_impl(interp_ufuncs.add) + descr_sub = _binop_impl(interp_ufuncs.subtract) + descr_mul = _binop_impl(interp_ufuncs.multiply) + descr_div = _binop_impl(interp_ufuncs.divide) + descr_pow = _binop_impl(interp_ufuncs.power) + descr_mod = _binop_impl(interp_ufuncs.mod) - def _binop_right_impl(function): - signature = Signature() + def _binop_right_impl(w_ufunc): def impl(self, space, w_other): - new_sig = self.signature.transition(signature) w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - w_other, - self, - new_sig.transition(w_other.signature) - ) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, - "binop_right_%s_impl" % function.__name__) + return w_ufunc(space, w_other, self) + return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__) - descr_radd = _binop_right_impl(add) - descr_rsub = _binop_right_impl(sub) - descr_rmul = _binop_right_impl(mul) - descr_rdiv = _binop_right_impl(div) - descr_rpow = _binop_right_impl(power) - descr_rmod = _binop_right_impl(mod) + descr_radd = _binop_right_impl(interp_ufuncs.add) + descr_rsub = _binop_right_impl(interp_ufuncs.subtract) + descr_rmul = _binop_right_impl(interp_ufuncs.multiply) + descr_rdiv = _binop_right_impl(interp_ufuncs.divide) + descr_rpow = _binop_right_impl(interp_ufuncs.power) + descr_rmod = _binop_right_impl(interp_ufuncs.mod) def _reduce_sum_prod_impl(function, init): reduce_driver = jit.JitDriver(greens=['signature'], diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py --- a/pypy/module/micronumpy/interp_support.py +++ b/pypy/module/micronumpy/interp_support.py @@ -1,14 +1,14 @@ - from pypy.rlib.rstruct.runpack import runpack from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.interp_numarray import SingleDimArray + FLOAT_SIZE = rffi.sizeof(lltype.Float) @unwrap_spec(s=str) def fromstring(space, s): + from pypy.module.micronumpy.interp_numarray import SingleDimArray length = len(s) if length % FLOAT_SIZE == 0: @@ -30,3 +30,13 @@ end += FLOAT_SIZE return space.wrap(a) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,13 +1,13 @@ import math -from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, - convert_to_array) +from pypy.module.micronumpy.interp_support import Signature from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name def ufunc(func): signature = Signature() def impl(space, w_obj): + from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array if space.issequence_w(w_obj): w_obj_arr = convert_to_array(space, w_obj) w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) @@ -20,6 +20,7 @@ def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): + from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): w_lhs_arr = convert_to_array(space, w_lhs) w_rhs_arr = convert_to_array(space, w_rhs) @@ -106,3 +107,11 @@ @ufunc def tan(value): return math.tan(value) + + at ufunc2 +def power(lvalue, rvalue): + return math.pow(lvalue, rvalue) + + at ufunc2 +def mod(lvalue, rvalue): + return math.fmod(lvalue, rvalue) \ No newline at end of file From noreply at buildbot.pypy.org Thu Jul 21 09:44:38 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 21 Jul 2011 09:44:38 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ufuncs: Closing about to be merged branch. Message-ID: <20110721074438.6C485829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: numpy-ufuncs Changeset: r45790:2722bcb465c0 Date: 2011-07-21 00:44 -0700 http://bitbucket.org/pypy/pypy/changeset/2722bcb465c0/ Log: Closing about to be merged branch. From noreply at buildbot.pypy.org Thu Jul 21 09:44:39 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 21 Jul 2011 09:44:39 +0200 (CEST) Subject: [pypy-commit] pypy default: Merged numpy-ufuncs into trunk. Message-ID: <20110721074439.9AC5C829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45791:a3f9ed7d37a7 Date: 2011-07-21 00:44 -0700 http://bitbucket.org/pypy/pypy/changeset/a3f9ed7d37a7/ Log: Merged numpy-ufuncs into trunk. diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -15,14 +15,19 @@ # ufuncs 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', + 'add': 'interp_ufuncs.add', 'copysign': 'interp_ufuncs.copysign', + 'divide': 'interp_ufuncs.divide', 'exp': 'interp_ufuncs.exp', + 'fabs': 'interp_ufuncs.fabs', 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', + 'multiply': 'interp_ufuncs.multiply', 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'subtract': 'interp_ufuncs.subtract', 'sin': 'interp_ufuncs.sin', 'cos': 'interp_ufuncs.cos', 'tan': 'interp_ufuncs.tan', diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -3,7 +3,7 @@ It should not be imported by the module itself """ -from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray class BogusBytecode(Exception): pass @@ -18,6 +18,14 @@ def wrap(self, x): return x + def issequence_w(self, w_obj): + # Completley wrong in the general case, but good enough for this. + return isinstance(w_obj, BaseArray) + + def float_w(self, w_obj): + assert isinstance(w_obj, float) + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() stack = [] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,6 +2,8 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy.interp_support import Signature +from pypy.module.micronumpy import interp_ufuncs from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit from pypy.rlib.rfloat import DTSF_STR_PRECISION @@ -24,16 +26,6 @@ all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) -class Signature(object): - def __init__(self): - self.transitions = {} - - def transition(self, target): - if target in self.transitions: - return self.transitions[target] - self.transitions[target] = new = Signature() - return new - def pos(v): return v def neg(v): @@ -42,16 +34,8 @@ return abs(v) def add(v1, v2): return v1 + v2 -def sub(v1, v2): - return v1 - v2 def mul(v1, v2): return v1 * v2 -def div(v1, v2): - return v1 / v2 -def power(v1, v2): - return math.pow(v1, v2) -def mod(v1, v2): - return math.fmod(v1, v2) def maximum(v1, v2): return max(v1, v2) def minimum(v1, v2): @@ -89,51 +73,30 @@ descr_neg = _unop_impl(neg) descr_abs = _unop_impl(absolute) - def _binop_impl(function): - signature = Signature() + def _binop_impl(w_ufunc): def impl(self, space, w_other): - w_other = convert_to_array(space, w_other) - new_sig = self.signature.transition(signature) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + return w_ufunc(space, self, w_other) + return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__) - descr_add = _binop_impl(add) - descr_sub = _binop_impl(sub) - descr_mul = _binop_impl(mul) - descr_div = _binop_impl(div) - descr_pow = _binop_impl(power) - descr_mod = _binop_impl(mod) + descr_add = _binop_impl(interp_ufuncs.add) + descr_sub = _binop_impl(interp_ufuncs.subtract) + descr_mul = _binop_impl(interp_ufuncs.multiply) + descr_div = _binop_impl(interp_ufuncs.divide) + descr_pow = _binop_impl(interp_ufuncs.power) + descr_mod = _binop_impl(interp_ufuncs.mod) - def _binop_right_impl(function): - signature = Signature() + def _binop_right_impl(w_ufunc): def impl(self, space, w_other): - new_sig = self.signature.transition(signature) w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - w_other, - self, - new_sig.transition(w_other.signature) - ) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, - "binop_right_%s_impl" % function.__name__) + return w_ufunc(space, w_other, self) + return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__) - descr_radd = _binop_right_impl(add) - descr_rsub = _binop_right_impl(sub) - descr_rmul = _binop_right_impl(mul) - descr_rdiv = _binop_right_impl(div) - descr_rpow = _binop_right_impl(power) - descr_rmod = _binop_right_impl(mod) + descr_radd = _binop_right_impl(interp_ufuncs.add) + descr_rsub = _binop_right_impl(interp_ufuncs.subtract) + descr_rmul = _binop_right_impl(interp_ufuncs.multiply) + descr_rdiv = _binop_right_impl(interp_ufuncs.divide) + descr_rpow = _binop_right_impl(interp_ufuncs.power) + descr_rmod = _binop_right_impl(interp_ufuncs.mod) def _reduce_sum_prod_impl(function, init): reduce_driver = jit.JitDriver(greens=['signature'], diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py --- a/pypy/module/micronumpy/interp_support.py +++ b/pypy/module/micronumpy/interp_support.py @@ -1,14 +1,14 @@ - from pypy.rlib.rstruct.runpack import runpack from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.interp_numarray import SingleDimArray + FLOAT_SIZE = rffi.sizeof(lltype.Float) @unwrap_spec(s=str) def fromstring(space, s): + from pypy.module.micronumpy.interp_numarray import SingleDimArray length = len(s) if length % FLOAT_SIZE == 0: @@ -30,3 +30,13 @@ end += FLOAT_SIZE return space.wrap(a) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,13 +1,13 @@ import math -from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, - convert_to_array) +from pypy.module.micronumpy.interp_support import Signature from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name def ufunc(func): signature = Signature() def impl(space, w_obj): + from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array if space.issequence_w(w_obj): w_obj_arr = convert_to_array(space, w_obj) w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) @@ -20,6 +20,7 @@ def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): + from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): w_lhs_arr = convert_to_array(space, w_lhs) w_rhs_arr = convert_to_array(space, w_rhs) @@ -37,9 +38,17 @@ return abs(value) @ufunc2 +def add(lvalue, rvalue): + return lvalue + rvalue + + at ufunc2 def copysign(lvalue, rvalue): return rfloat.copysign(lvalue, rvalue) + at ufunc2 +def divide(lvalue, rvalue): + return lvalue / rvalue + @ufunc def exp(value): try: @@ -47,6 +56,10 @@ except OverflowError: return rfloat.INFINITY + at ufunc +def fabs(value): + return math.fabs(value) + @ufunc2 def maximum(lvalue, rvalue): return max(lvalue, rvalue) @@ -55,6 +68,10 @@ def minimum(lvalue, rvalue): return min(lvalue, rvalue) + at ufunc2 +def multiply(lvalue, rvalue): + return lvalue * rvalue + @ufunc def negative(value): return -value @@ -65,6 +82,10 @@ return rfloat.copysign(rfloat.INFINITY, value) return 1.0 / value + at ufunc2 +def subtract(lvalue, rvalue): + return lvalue - rvalue + @ufunc def floor(value): return math.floor(value) @@ -86,3 +107,11 @@ @ufunc def tan(value): return math.tan(value) + + at ufunc2 +def power(lvalue, rvalue): + return math.pow(lvalue, rvalue) + + at ufunc2 +def mod(lvalue, rvalue): + return math.fmod(lvalue, rvalue) \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -65,6 +65,33 @@ for i in range(3): assert b[i] == abs(a[i]) + def test_add(self): + from numpy import array, add + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = add(a, b) + for i in range(3): + assert c[i] == a[i] + b[i] + + def test_divide(self): + from numpy import array, divide + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = divide(a, b) + for i in range(3): + assert c[i] == a[i] / b[i] + + def test_fabs(self): + from numpy import array, fabs + from math import fabs as math_fabs + + a = array([-5.0, -0.0, 1.0]) + b = fabs(a) + for i in range(3): + assert b[i] == math_fabs(a[i]) + def test_minimum(self): from numpy import array, minimum @@ -83,6 +110,15 @@ for i in range(3): assert c[i] == max(a[i], b[i]) + def test_multiply(self): + from numpy import array, multiply + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = multiply(a, b) + for i in range(3): + assert c[i] == a[i] * b[i] + def test_sign(self): from numpy import array, sign @@ -101,6 +137,15 @@ for i in range(4): assert b[i] == reference[i] + def test_subtract(self): + from numpy import array, subtract + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = subtract(a, b) + for i in range(3): + assert c[i] == a[i] - b[i] + def test_floor(self): from numpy import array, floor From noreply at buildbot.pypy.org Thu Jul 21 09:51:25 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 09:51:25 +0200 (CEST) Subject: [pypy-commit] pypy numpy-setslice: improve tests Message-ID: <20110721075125.AAF65829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: numpy-setslice Changeset: r45792:4ee6a8782003 Date: 2011-07-21 09:51 +0200 http://bitbucket.org/pypy/pypy/changeset/4ee6a8782003/ Log: improve tests diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -256,13 +256,16 @@ step = NonConstant(3) ar = SingleDimArray(step*i) ar2 = SingleDimArray(i) - ar.setslice(space, 0, step*i, step, i, ar2) + ar2.storage[1] = 5.5 + ar.setslice(space, 0, step*i, step, i, ar2.descr_add(space, ar2)) return ar.get_concrete().storage[3] result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({'getarrayitem_raw': 1, + self.check_loops({'getarrayitem_raw': 2, + 'float_add' : 1, 'setarrayitem_raw': 1, 'int_add': 2, 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == 11.0 class TestTranslation(object): def test_compile(self): From noreply at buildbot.pypy.org Thu Jul 21 09:55:41 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 09:55:41 +0200 (CEST) Subject: [pypy-commit] pypy default: merge numpy-slice Message-ID: <20110721075541.7CFBB829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45793:fb245ad56f79 Date: 2011-07-21 09:54 +0200 http://bitbucket.org/pypy/pypy/changeset/fb245ad56f79/ Log: merge numpy-slice diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -23,6 +23,8 @@ reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) class Signature(object): def __init__(self): @@ -288,10 +290,18 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().setitem(start, + space.float_w(w_value)) + else: + self.get_concrete().setslice(space, start, stop, step, + slice_length, w_value) def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) @@ -440,8 +450,8 @@ return self.parent.getitem(self.calc_index(item)) @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - return self.parent.descr_setitem(space, self.calc_index(item), value) + def setitem(self, item, value): + return self.parent.setitem(self.calc_index(item), value) def descr_len(self, space): return space.wrap(self.find_size()) @@ -455,14 +465,58 @@ def __init__(self, start, stop, step, slice_length, parent, signature): ViewArray.__init__(self, parent, signature) + if isinstance(parent, SingleDimSlice): + self.start = parent.calc_index(start) + self.stop = parent.calc_index(stop) + self.step = parent.step * step + self.parent = parent.parent + else: self.start = start self.stop = stop self.step = step + self.parent = parent self.size = slice_length def find_size(self): return self.size + def _sliceloop1(self, start, stop, step, arr): + storage = self.parent.storage + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + storage[i] = arr.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, arr): + storage = self.parent.storage + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + storage[i] = arr.eval(j) + j += 1 + i += step + + def setslice(self, space, start, stop, step, slice_length, arr): + arr = convert_to_array(space, arr) + start = self.calc_index(start) + if stop != -1: + stop = self.calc_index(stop) + step = self.step * step + if step > 0: + self._sliceloop1(start, stop, step, arr) + else: + self._sliceloop2(start, stop, step, arr) + def calc_index(self, item): return (self.start + item * self.step) @@ -486,7 +540,7 @@ def eval(self, i): return self.storage[i] - def getindex(self, space, item): + def getindex(self, item): if item >= self.size: raise operationerrfmt(space.w_IndexError, '%d above array size', item) @@ -504,11 +558,44 @@ return self.storage[item] @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - item = self.getindex(space, item) + def setitem(self, item, value): + item = self.getindex(item) self.invalidated() self.storage[item] = value + def _sliceloop1(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, arr): + signature = Signature() + new_sig = self.signature.transition(signature) + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def setslice(self, space, start, stop, step, slice_length, arr): + i = start + if not isinstance(arr, BaseArray): + arr = convert_to_array(space, arr) + if step > 0: + self._sliceloop1(start, stop, step, arr) + else: + self._sliceloop2(start, stop, step, arr) + def __del__(self): lltype.free(self.storage, flavor='raw') diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -92,6 +92,48 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_of_slice_array(self): + from numpy import array, zeros + a = zeros(5) + a[::2] = array([9., 10., 11.]) + assert a[0] == 9. + assert a[2] == 10. + assert a[4] == 11. + a[1:4:2][::-1] = array([1., 2.]) + assert a[0] == 9. + assert a[1] == 2. + assert a[2] == 10. + assert a[3] == 1. + assert a[4] == 11. + a = zeros(10) + a[::2][::-1][::2] = array(range(1,4)) + a[8] = 1. + a[4] = 2. + a[0] = 3. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -5,6 +5,7 @@ from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): w_ValueError = None @@ -248,6 +249,24 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar2.storage[1] = 5.5 + ar.setslice(space, 0, step*i, step, i, ar2.descr_add(space, ar2)) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 2, + 'float_add' : 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == 11.0 + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) From noreply at buildbot.pypy.org Thu Jul 21 09:55:42 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 09:55:42 +0200 (CEST) Subject: [pypy-commit] pypy numpy-setslice: close merged branch Message-ID: <20110721075542.AC552829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: numpy-setslice Changeset: r45794:bb33f506f1a2 Date: 2011-07-21 09:54 +0200 http://bitbucket.org/pypy/pypy/changeset/bb33f506f1a2/ Log: close merged branch From noreply at buildbot.pypy.org Thu Jul 21 09:55:43 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 09:55:43 +0200 (CEST) Subject: [pypy-commit] pypy default: merge default Message-ID: <20110721075543.DBDC0829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45795:95a8a9907969 Date: 2011-07-21 09:55 +0200 http://bitbucket.org/pypy/pypy/changeset/95a8a9907969/ Log: merge default diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -15,14 +15,19 @@ # ufuncs 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', + 'add': 'interp_ufuncs.add', 'copysign': 'interp_ufuncs.copysign', + 'divide': 'interp_ufuncs.divide', 'exp': 'interp_ufuncs.exp', + 'fabs': 'interp_ufuncs.fabs', 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', + 'multiply': 'interp_ufuncs.multiply', 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'subtract': 'interp_ufuncs.subtract', 'sin': 'interp_ufuncs.sin', 'cos': 'interp_ufuncs.cos', 'tan': 'interp_ufuncs.tan', diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -3,7 +3,7 @@ It should not be imported by the module itself """ -from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray class BogusBytecode(Exception): pass @@ -18,6 +18,14 @@ def wrap(self, x): return x + def issequence_w(self, w_obj): + # Completley wrong in the general case, but good enough for this. + return isinstance(w_obj, BaseArray) + + def float_w(self, w_obj): + assert isinstance(w_obj, float) + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() stack = [] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,6 +2,8 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy.interp_support import Signature +from pypy.module.micronumpy import interp_ufuncs from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit from pypy.rlib.rfloat import DTSF_STR_PRECISION @@ -26,16 +28,6 @@ slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) -class Signature(object): - def __init__(self): - self.transitions = {} - - def transition(self, target): - if target in self.transitions: - return self.transitions[target] - self.transitions[target] = new = Signature() - return new - def pos(v): return v def neg(v): @@ -44,16 +36,8 @@ return abs(v) def add(v1, v2): return v1 + v2 -def sub(v1, v2): - return v1 - v2 def mul(v1, v2): return v1 * v2 -def div(v1, v2): - return v1 / v2 -def power(v1, v2): - return math.pow(v1, v2) -def mod(v1, v2): - return math.fmod(v1, v2) def maximum(v1, v2): return max(v1, v2) def minimum(v1, v2): @@ -91,51 +75,30 @@ descr_neg = _unop_impl(neg) descr_abs = _unop_impl(absolute) - def _binop_impl(function): - signature = Signature() + def _binop_impl(w_ufunc): def impl(self, space, w_other): - w_other = convert_to_array(space, w_other) - new_sig = self.signature.transition(signature) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + return w_ufunc(space, self, w_other) + return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__) - descr_add = _binop_impl(add) - descr_sub = _binop_impl(sub) - descr_mul = _binop_impl(mul) - descr_div = _binop_impl(div) - descr_pow = _binop_impl(power) - descr_mod = _binop_impl(mod) + descr_add = _binop_impl(interp_ufuncs.add) + descr_sub = _binop_impl(interp_ufuncs.subtract) + descr_mul = _binop_impl(interp_ufuncs.multiply) + descr_div = _binop_impl(interp_ufuncs.divide) + descr_pow = _binop_impl(interp_ufuncs.power) + descr_mod = _binop_impl(interp_ufuncs.mod) - def _binop_right_impl(function): - signature = Signature() + def _binop_right_impl(w_ufunc): def impl(self, space, w_other): - new_sig = self.signature.transition(signature) w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - w_other, - self, - new_sig.transition(w_other.signature) - ) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, - "binop_right_%s_impl" % function.__name__) + return w_ufunc(space, w_other, self) + return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__) - descr_radd = _binop_right_impl(add) - descr_rsub = _binop_right_impl(sub) - descr_rmul = _binop_right_impl(mul) - descr_rdiv = _binop_right_impl(div) - descr_rpow = _binop_right_impl(power) - descr_rmod = _binop_right_impl(mod) + descr_radd = _binop_right_impl(interp_ufuncs.add) + descr_rsub = _binop_right_impl(interp_ufuncs.subtract) + descr_rmul = _binop_right_impl(interp_ufuncs.multiply) + descr_rdiv = _binop_right_impl(interp_ufuncs.divide) + descr_rpow = _binop_right_impl(interp_ufuncs.power) + descr_rmod = _binop_right_impl(interp_ufuncs.mod) def _reduce_sum_prod_impl(function, init): reduce_driver = jit.JitDriver(greens=['signature'], diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py --- a/pypy/module/micronumpy/interp_support.py +++ b/pypy/module/micronumpy/interp_support.py @@ -1,14 +1,14 @@ - from pypy.rlib.rstruct.runpack import runpack from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.interp_numarray import SingleDimArray + FLOAT_SIZE = rffi.sizeof(lltype.Float) @unwrap_spec(s=str) def fromstring(space, s): + from pypy.module.micronumpy.interp_numarray import SingleDimArray length = len(s) if length % FLOAT_SIZE == 0: @@ -30,3 +30,13 @@ end += FLOAT_SIZE return space.wrap(a) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,13 +1,13 @@ import math -from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, - convert_to_array) +from pypy.module.micronumpy.interp_support import Signature from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name def ufunc(func): signature = Signature() def impl(space, w_obj): + from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array if space.issequence_w(w_obj): w_obj_arr = convert_to_array(space, w_obj) w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) @@ -20,6 +20,7 @@ def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): + from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): w_lhs_arr = convert_to_array(space, w_lhs) w_rhs_arr = convert_to_array(space, w_rhs) @@ -37,9 +38,17 @@ return abs(value) @ufunc2 +def add(lvalue, rvalue): + return lvalue + rvalue + + at ufunc2 def copysign(lvalue, rvalue): return rfloat.copysign(lvalue, rvalue) + at ufunc2 +def divide(lvalue, rvalue): + return lvalue / rvalue + @ufunc def exp(value): try: @@ -47,6 +56,10 @@ except OverflowError: return rfloat.INFINITY + at ufunc +def fabs(value): + return math.fabs(value) + @ufunc2 def maximum(lvalue, rvalue): return max(lvalue, rvalue) @@ -55,6 +68,10 @@ def minimum(lvalue, rvalue): return min(lvalue, rvalue) + at ufunc2 +def multiply(lvalue, rvalue): + return lvalue * rvalue + @ufunc def negative(value): return -value @@ -65,6 +82,10 @@ return rfloat.copysign(rfloat.INFINITY, value) return 1.0 / value + at ufunc2 +def subtract(lvalue, rvalue): + return lvalue - rvalue + @ufunc def floor(value): return math.floor(value) @@ -86,3 +107,11 @@ @ufunc def tan(value): return math.tan(value) + + at ufunc2 +def power(lvalue, rvalue): + return math.pow(lvalue, rvalue) + + at ufunc2 +def mod(lvalue, rvalue): + return math.fmod(lvalue, rvalue) \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -65,6 +65,33 @@ for i in range(3): assert b[i] == abs(a[i]) + def test_add(self): + from numpy import array, add + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = add(a, b) + for i in range(3): + assert c[i] == a[i] + b[i] + + def test_divide(self): + from numpy import array, divide + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = divide(a, b) + for i in range(3): + assert c[i] == a[i] / b[i] + + def test_fabs(self): + from numpy import array, fabs + from math import fabs as math_fabs + + a = array([-5.0, -0.0, 1.0]) + b = fabs(a) + for i in range(3): + assert b[i] == math_fabs(a[i]) + def test_minimum(self): from numpy import array, minimum @@ -83,6 +110,15 @@ for i in range(3): assert c[i] == max(a[i], b[i]) + def test_multiply(self): + from numpy import array, multiply + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = multiply(a, b) + for i in range(3): + assert c[i] == a[i] * b[i] + def test_sign(self): from numpy import array, sign @@ -101,6 +137,15 @@ for i in range(4): assert b[i] == reference[i] + def test_subtract(self): + from numpy import array, subtract + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = subtract(a, b) + for i in range(3): + assert c[i] == a[i] - b[i] + def test_floor(self): from numpy import array, floor From noreply at buildbot.pypy.org Thu Jul 21 10:22:29 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 10:22:29 +0200 (CEST) Subject: [pypy-commit] pypy default: that was easy, fix arg usage Message-ID: <20110721082229.33B80829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45796:065c98a10f0d Date: 2011-07-21 10:22 +0200 http://bitbucket.org/pypy/pypy/changeset/065c98a10f0d/ Log: that was easy, fix arg usage diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -37,7 +37,7 @@ return self._is_guard def repr(self): - args = self.getargs() + args = self.args if self.descr is not None: args.append('descr=%s' % self.descr) arglist = ', '.join(args) @@ -145,7 +145,7 @@ if operations[0].name == 'debug_merge_point': self.inline_level = int(operations[0].args[0]) m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', - operations[0].getarg(1)) + operations[0].args[1]) if m is None: # a non-code loop, like StrLiteralSearch or something self.bytecode_name = operations[0].args[1] From noreply at buildbot.pypy.org Thu Jul 21 10:25:15 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 10:25:15 +0200 (CEST) Subject: [pypy-commit] pypy default: improve display a bit and fix the test Message-ID: <20110721082515.AE4EB829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45797:e03df75209a9 Date: 2011-07-21 10:25 +0200 http://bitbucket.org/pypy/pypy/changeset/e03df75209a9/ Log: improve display a bit and fix the test diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -148,7 +148,7 @@ operations[0].args[1]) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1] + self.bytecode_name = operations[0].args[1][1:-1] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -181,7 +181,7 @@ """) ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] - assert chunk.bytecode_name == 'StrLiteralSearch' + assert chunk.bytecode_name.startswith('StrLiteralSearch') def test_parsing_assembler(): backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" From noreply at buildbot.pypy.org Thu Jul 21 10:32:04 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 10:32:04 +0200 (CEST) Subject: [pypy-commit] pypy default: cleanup Message-ID: <20110721083204.D2685829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45798:6bc10a129273 Date: 2011-07-21 10:32 +0200 http://bitbucket.org/pypy/pypy/changeset/6bc10a129273/ Log: cleanup diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -260,8 +260,7 @@ self.find_size()) if step == 0: # Single index - self.get_concrete().setitem(start, - space.float_w(w_value)) + self.get_concrete().setitem(start, space.float_w(w_value)) else: self.get_concrete().setslice(space, start, stop, step, slice_length, w_value) @@ -503,55 +502,37 @@ def eval(self, i): return self.storage[i] - def getindex(self, item): - if item >= self.size: - raise operationerrfmt(space.w_IndexError, - '%d above array size', item) - if item < 0: - item += self.size - if item < 0: - raise operationerrfmt(space.w_IndexError, - '%d below zero', item) - return item - def descr_len(self, space): return space.wrap(self.size) def getitem(self, item): return self.storage[item] - @unwrap_spec(item=int, value=float) def setitem(self, item, value): - item = self.getindex(item) self.invalidated() self.storage[item] = value def _sliceloop1(self, start, stop, step, arr): - signature = Signature() - new_sig = self.signature.transition(signature) i = start j = 0 while i < stop: - slice_driver1.jit_merge_point(signature=signature, self=self, + slice_driver1.jit_merge_point(signature=self.signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) self.storage[i] = arr.eval(j) j += 1 i += step def _sliceloop2(self, start, stop, step, arr): - signature = Signature() - new_sig = self.signature.transition(signature) i = start j = 0 while i > stop: - slice_driver2.jit_merge_point(signature=signature, self=self, + slice_driver2.jit_merge_point(signature=self.signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) self.storage[i] = arr.eval(j) j += 1 i += step def setslice(self, space, start, stop, step, slice_length, arr): - i = start if not isinstance(arr, BaseArray): arr = convert_to_array(space, arr) if step > 0: From noreply at buildbot.pypy.org Thu Jul 21 10:41:23 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 10:41:23 +0200 (CEST) Subject: [pypy-commit] pypy default: fix tests and improve signature Message-ID: <20110721084123.548C1829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45799:2c43451adecb Date: 2011-07-21 10:41 +0200 http://bitbucket.org/pypy/pypy/changeset/2c43451adecb/ Log: fix tests and improve signature diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -444,12 +444,10 @@ def _sliceloop1(self, start, stop, step, arr): storage = self.parent.storage - signature = Signature() - new_sig = self.signature.transition(signature) i = start j = 0 while i < stop: - slice_driver1.jit_merge_point(signature=signature, self=self, + slice_driver1.jit_merge_point(signature=arr.signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) storage[i] = arr.eval(j) j += 1 @@ -457,12 +455,10 @@ def _sliceloop2(self, start, stop, step, arr): storage = self.parent.storage - signature = Signature() - new_sig = self.signature.transition(signature) i = start j = 0 while i > stop: - slice_driver2.jit_merge_point(signature=signature, self=self, + slice_driver2.jit_merge_point(signature=arr.signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) storage[i] = arr.eval(j) j += 1 @@ -516,7 +512,7 @@ i = start j = 0 while i < stop: - slice_driver1.jit_merge_point(signature=self.signature, self=self, + slice_driver1.jit_merge_point(signature=arr.signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) self.storage[i] = arr.eval(j) j += 1 @@ -526,7 +522,7 @@ i = start j = 0 while i > stop: - slice_driver2.jit_merge_point(signature=self.signature, self=self, + slice_driver2.jit_merge_point(signature=arr.signature, self=self, step=step, stop=stop, i=i, j=j, arr=arr) self.storage[i] = arr.eval(j) j += 1 diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -49,8 +49,6 @@ assert result == f(5) def test_neg(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call1(neg, ar, Signature()) @@ -105,6 +103,7 @@ "float_gt": 1, "int_add": 1, "int_lt": 1, "guard_true": 1, "guard_false": 1, "jump": 1}) + assert result == f(5) def test_min(self): space = self.space @@ -122,6 +121,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_argmin(self): space = self.space @@ -139,6 +139,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_all(self): space = self.space @@ -154,6 +155,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_any(self): space = self.space @@ -166,6 +168,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "guard_false": 1, "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) def test_already_forecd(self): def f(i): @@ -257,7 +260,11 @@ ar = SingleDimArray(step*i) ar2 = SingleDimArray(i) ar2.storage[1] = 5.5 - ar.setslice(space, 0, step*i, step, i, ar2.descr_add(space, ar2)) + if NonConstant(False): + arg = ar2 + else: + arg = ar2.descr_add(space, ar2) + ar.setslice(space, 0, step*i, step, i, arg) return ar.get_concrete().storage[3] result = self.meta_interp(f, [5], listops=True, backendopt=True) From noreply at buildbot.pypy.org Thu Jul 21 10:43:39 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 10:43:39 +0200 (CEST) Subject: [pypy-commit] pypy default: make the test assert something Message-ID: <20110721084339.436EE829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45800:96cbeff5195d Date: 2011-07-21 10:42 +0200 http://bitbucket.org/pypy/pypy/changeset/96cbeff5195d/ Log: make the test assert something diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -115,9 +115,9 @@ assert a[4] == 11. a = zeros(10) a[::2][::-1][::2] = array(range(1,4)) - a[8] = 1. - a[4] = 2. - a[0] = 3. + assert a[8] == 1. + assert a[4] == 2. + assert a[0] == 3. def test_setslice_list(self): from numpy import array From noreply at buildbot.pypy.org Thu Jul 21 11:43:31 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 11:43:31 +0200 (CEST) Subject: [pypy-commit] jitviewer default: first go at working filter Message-ID: <20110721094331.556E0829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r152:3b5afee740b3 Date: 2011-07-21 11:43 +0200 http://bitbucket.org/pypy/jitviewer/changeset/3b5afee740b3/ Log: first go at working filter diff --git a/_jitviewer/static/script.js b/_jitviewer/static/script.js --- a/_jitviewer/static/script.js +++ b/_jitviewer/static/script.js @@ -38,7 +38,14 @@ $("#inp-bar").focus(); $("#inp-bar").bind("click keyup", function() { var value = $("#inp-bar")[0].value; - + $(".loopitem").each(function (i, l) { + glob = l; + if (l.getAttribute('name').search(value) != -1) { + $(l).show(); + } else { + $(l).hide(); + } + }); }); } diff --git a/_jitviewer/templates/index.html b/_jitviewer/templates/index.html --- a/_jitviewer/templates/index.html +++ b/_jitviewer/templates/index.html @@ -29,9 +29,9 @@
        {% for is_entry_bridge, index, item in loops %} {% if is_entry_bridge %} -
      • Entry bridge: {{item.repr()}} run {{item.count}} times
      • +
      • Entry bridge: {{item.repr()}} run {{item.count}} times
      • {% else %} -
      • {{item.repr()}} run {{item.count}} times
      • +
      • {{item.repr()}} run {{item.count}} times
      • {% endif %} {% endfor %}
      From noreply at buildbot.pypy.org Thu Jul 21 12:14:23 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Thu, 21 Jul 2011 12:14:23 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: cleaner Message-ID: <20110721101423.27406829B8@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45801:d5c554280935 Date: 2011-07-20 16:48 +0200 http://bitbucket.org/pypy/pypy/changeset/d5c554280935/ Log: cleaner diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -289,21 +289,21 @@ array = self.getvalue(op.getarg(0)) result = self.getvalue(op.result) array.make_len_gt(MODE_ARRAY, op.getdescr(), -1) - result.intbound = array.lenbound[2] + result.intbound = array.lenbound.bound def optimize_STRLEN(self, op): self.emit_operation(op) array = self.getvalue(op.getarg(0)) result = self.getvalue(op.result) array.make_len_gt(MODE_STR, op.getdescr(), -1) - result.intbound = array.lenbound[2] + result.intbound = array.lenbound.bound def optimize_UNICODELEN(self, op): self.emit_operation(op) array = self.getvalue(op.getarg(0)) result = self.getvalue(op.result) array.make_len_gt(MODE_UNICODE, op.getdescr(), -1) - result.intbound = array.lenbound[2] + result.intbound = array.lenbound.bound def optimize_STRGETITEM(self, op): self.emit_operation(op) diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -25,6 +25,11 @@ MODE_ARRAY = '\x00' MODE_STR = '\x01' MODE_UNICODE = '\x02' +class LenBound(object): + def __init__(self, mode, descr, bound): + self.mode = mode + self.descr = descr + self.bound = bound class OptValue(object): __metaclass__ = extendabletype @@ -55,11 +60,11 @@ def make_len_gt(self, mode, descr, val): if self.lenbound: - assert self.lenbound[0] == mode - assert self.lenbound[1] == descr - self.lenbound[2].make_gt(IntBound(val, val)) + assert self.lenbound.mode == mode + assert self.lenbound.descr == descr + self.lenbound.bound.make_gt(IntBound(val, val)) else: - self.lenbound = (mode, descr, IntLowerBound(val + 1)) + self.lenbound = LenBound(mode, descr, IntLowerBound(val + 1)) def make_guards(self, box): guards = [] @@ -78,17 +83,17 @@ self.intbound.make_guards(box, guards) if self.lenbound: lenbox = BoxInt() - if self.lenbound[0] == MODE_ARRAY: - op = ResOperation(rop.ARRAYLEN_GC, [box], lenbox, self.lenbound[1]) - elif self.lenbound[0] == MODE_STR: - op = ResOperation(rop.STRLEN, [box], lenbox, self.lenbound[1]) - elif self.lenbound[0] == MODE_UNICODE: - op = ResOperation(rop.UNICODELEN, [box], lenbox, self.lenbound[1]) + if self.lenbound.mode == MODE_ARRAY: + op = ResOperation(rop.ARRAYLEN_GC, [box], lenbox, self.lenbound.descr) + elif self.lenbound.mode == MODE_STR: + op = ResOperation(rop.STRLEN, [box], lenbox, self.lenbound.descr) + elif self.lenbound.mode == MODE_UNICODE: + op = ResOperation(rop.UNICODELEN, [box], lenbox, self.lenbound.descr) else: debug_print("Unknown lenbound mode") assert False guards.append(op) - self.lenbound[2].make_guards(lenbox, guards) + self.lenbound.bound.make_guards(lenbox, guards) return guards diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py --- a/pypy/jit/metainterp/optimizeopt/virtualstate.py +++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py @@ -237,9 +237,9 @@ bad[other] = True return False if self.lenbound and other.lenbound: - if self.lenbound[0] != other.lenbound[0] or \ - self.lenbound[1] != other.lenbound[1] or \ - not self.lenbound[2].contains_bound(other.lenbound[2]): + if self.lenbound.mode != other.lenbound.mode or \ + self.lenbound.descr != other.lenbound.descr or \ + not self.lenbound.bound.contains_bound(other.lenbound.bound): bad[self] = True bad[other] = True return False @@ -341,7 +341,7 @@ lb = '' if self.lenbound: - lb = ', ' + self.lenbound[2].__repr__() + lb = ', ' + self.lenbound.bound.__repr__() debug_print(indent + mark + 'NotVirtualInfo(%d' % self.position + ', ' + l + ', ' + self.intbound.__repr__() + lb + ')') From noreply at buildbot.pypy.org Thu Jul 21 12:14:24 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Thu, 21 Jul 2011 12:14:24 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: dont lose intbound on lengths of virtuals Message-ID: <20110721101424.651D6829B8@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45802:9b09294e5686 Date: 2011-07-21 12:14 +0200 http://bitbucket.org/pypy/pypy/changeset/9b09294e5686/ Log: dont lose intbound on lengths of virtuals diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -289,6 +289,7 @@ array = self.getvalue(op.getarg(0)) result = self.getvalue(op.result) array.make_len_gt(MODE_ARRAY, op.getdescr(), -1) + array.lenbound.bound.intersect(result.intbound) result.intbound = array.lenbound.bound def optimize_STRLEN(self, op): @@ -296,6 +297,7 @@ array = self.getvalue(op.getarg(0)) result = self.getvalue(op.result) array.make_len_gt(MODE_STR, op.getdescr(), -1) + array.lenbound.bound.intersect(result.intbound) result.intbound = array.lenbound.bound def optimize_UNICODELEN(self, op): @@ -303,6 +305,7 @@ array = self.getvalue(op.getarg(0)) result = self.getvalue(op.result) array.make_len_gt(MODE_UNICODE, op.getdescr(), -1) + array.lenbound.bound.intersect(result.intbound) result.intbound = array.lenbound.bound def optimize_STRGETITEM(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6687,7 +6687,43 @@ """ self.optimize_loop(ops, expected, expected_short=short) - + def test_propagate_virtual_arryalen(self): + ops = """ + [p0] + p404 = new_array(2, descr=arraydescr) + p403 = new_array(3, descr=arraydescr) + i405 = arraylen_gc(p404, descr=arraydescr) + i406 = arraylen_gc(p403, descr=arraydescr) + i407 = int_add_ovf(i405, i406) + guard_no_overflow() [] + call(i407, descr=nonwritedescr) + jump(p0) + """ + expected = """ + [p0] + call(5, descr=nonwritedescr) + jump(p0) + """ + self.optimize_loop(ops, expected) + + def test_propagate_virtual_strunicodelen(self): + ops = """ + [p0] + p404 = newstr(2) + p403 = newunicode(3) + i405 = strlen(p404) + i406 = unicodelen(p403) + i407 = int_add_ovf(i405, i406) + guard_no_overflow() [] + call(i407, descr=nonwritedescr) + jump(p0) + """ + expected = """ + [p0] + call(5, descr=nonwritedescr) + jump(p0) + """ + self.optimize_loop(ops, expected) class TestLLtype(OptimizeOptTest, LLtypeMixin): pass From noreply at buildbot.pypy.org Thu Jul 21 13:48:47 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 13:48:47 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: write a test_pypy_c test Message-ID: <20110721114847.AB139829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45803:2171351a31a8 Date: 2011-07-21 11:29 +0200 http://bitbucket.org/pypy/pypy/changeset/2171351a31a8/ Log: write a test_pypy_c test diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -23,3 +23,29 @@ ops = loop.ops_by_id('look') assert log.opnames(ops) == ['setfield_gc', 'guard_not_invalidated'] + + def test_identitydict(self): + def fn(n): + class X(object): + pass + x = X() + d = {} + d[x] = 1 + res = 0 + for i in range(300): + value = d[x] # ID: getitem + res += value + return res + # + log = self.run(fn, [1000]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # check that the call to ll_dict_lookup is not a call_may_force + assert loop.match_by_id("getitem", """ + i25 = call(ConstClass(_ll_1_gc_identityhash__objectPtr), p6, descr=...) + ... + i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...) + ... + p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...) + ... + """) From noreply at buildbot.pypy.org Thu Jul 21 13:48:48 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 13:48:48 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: a passing test Message-ID: <20110721114848.D7139829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45804:3fa4e79e2664 Date: 2011-07-21 11:42 +0200 http://bitbucket.org/pypy/pypy/changeset/3fa4e79e2664/ Log: a passing test diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py --- a/pypy/objspace/std/test/test_identitydict.py +++ b/pypy/objspace/std/test/test_identitydict.py @@ -167,3 +167,23 @@ d = {x: 1} assert self.uses_identity_strategy(d) assert list(iter(d)) == [x] + + def test_mutate_class_and_then_compare(self): + class X(object): + pass + class Y(object): + pass + + x = X() + y = Y() + d1 = {x: 1} + d2 = {y: 1} + assert self.uses_identity_strategy(d1) + assert self.uses_identity_strategy(d2) + # + X.__hash__ = lambda self: hash(y) + X.__eq__ = lambda self, other: True + # + assert d1 == d2 + assert self.uses_identity_strategy(d1) + assert not self.uses_identity_strategy(d2) From noreply at buildbot.pypy.org Thu Jul 21 13:48:50 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 13:48:50 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: kill the global versioning logic, and add a big comment which explains why it's not needed Message-ID: <20110721114850.14C5B829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45805:76c609d60ebd Date: 2011-07-21 12:11 +0200 http://bitbucket.org/pypy/pypy/changeset/76c609d60ebd/ Log: kill the global versioning logic, and add a big comment which explains why it's not needed diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py --- a/pypy/objspace/std/identitydict.py +++ b/pypy/objspace/std/identitydict.py @@ -1,3 +1,6 @@ +## ---------------------------------------------------------------------------- +## dict strategy (see dict_multiobject.py) + from pypy.rlib import rerased from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, DictStrategy, @@ -5,39 +8,6 @@ _UnwrappedIteratorMixin) -# a global (per-space) version counter to track live instances which "compare -# by identity" (i.e., whose __eq__, __cmp__ and __hash__ are the default -# ones). The idea is to track only classes for which we checked the -# compares_by_identity() status at least once: we increment the version if its -# status might change, e.g. because we set one of those attributes. The -# actual work is done by W_TypeObject.mutated() and objecttype:descr_setclass - -def bump_global_version(space): - if space.config.objspace.std.withidentitydict: - space.fromcache(ComparesByIdentityVersion).bump() - -def get_global_version(space): - if space.config.objspace.std.withidentitydict: - return space.fromcache(ComparesByIdentityVersion).get() - return None - -class ComparesByIdentityVersion(object): - - def __init__(self, space): - self.bump() - - def bump(self): - from pypy.objspace.std.typeobject import VersionTag - self._version = VersionTag() - - def get(self): - return self._version - - - -## ---------------------------------------------------------------------------- -## dict strategy (see dict_multiobject.py) - # this strategy is selected by EmptyDictStrategy.switch_to_correct_strategy class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): """ @@ -45,11 +15,48 @@ default unless you override __hash__, __eq__ or __cmp__). The storage is just a normal RPython dict, which has already the correct by-identity semantics. + + Note that at a first sight, you might have problems if you mutate the + class of an object which is already inside an identitydict. Consider this + example:: + + class X(object): + pass + d = {x(): 1} + X.__eq__ = ... + d[y] # might trigger a call to __eq__? + + We want to be sure that x.__eq__ is called in the same cases as in + CPython. However, as long as the strategy is IdentityDictStrategy, the + __eq__ will never be called. + + It turns out that it's not a problem. In CPython (and in PyPy without + this strategy), the __eq__ is called if ``hash(y) == hash(x)`` and ``x is + not y``. Note that hash(x) is computed at the time when we insert x in + the dict, not at the time we lookup y. + + Now, how can hash(y) == hash(x)? There are two possibilities: + + 1. we write a custom __hash__ for the class of y, thus making it a not + "compares by reference" type + + 2. the class of y is "compares by reference" type, and by chance the + hash is the same as x + + In the first case, the getitem immediately notice that y is not of the + right type, and switches the strategy to ObjectDictStrategy, then the + lookup works as usual. + + The second case is completely non-deterministic, even in CPython. + Depending on the phase of the moon, you might call the __eq__ or not, so + it is perfectly fine to *never* call it. Morever, in practice with the + minimar GC we never have two live objects with the same hash, so it would + never happen anyway. """ - _erase_tuple, _unerase_tuple = rerased.new_erasing_pair("identitydict") - _erase_tuple = staticmethod(_erase_tuple) - _unerase_tuple = staticmethod(_unerase_tuple) + erase, unerase = rerased.new_erasing_pair("identitydict") + erase = staticmethod(erase) + unerase = staticmethod(unerase) def wrap(self, unwrapped): return unwrapped @@ -57,18 +64,6 @@ def unwrap(self, wrapped): return wrapped - def erase(self, d): - current_version = get_global_version(self.space) - return self._erase_tuple((current_version, d)) - - def unerase(self, dstorage): - version, d = self._unerase_tuple(dstorage) - return d - - def get_current_version(self, dstorage): - version, d = self._unerase_tuple(dstorage) - return version - def get_empty_storage(self): return self.erase({}) diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -43,9 +43,6 @@ assert isinstance(w_oldcls, W_TypeObject) if w_oldcls.get_full_instance_layout() == w_newcls.get_full_instance_layout(): w_obj.setclass(space, w_newcls) - if space.config.objspace.std.withidentitydict: - if w_oldcls.compares_by_identity() and not w_newcls.compares_by_identity(): - identitydict.bump_global_version(space) else: raise operationerrfmt(space.w_TypeError, "__class__ assignment: '%s' object layout differs from '%s'", diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py --- a/pypy/objspace/std/test/test_identitydict.py +++ b/pypy/objspace/std/test/test_identitydict.py @@ -2,7 +2,7 @@ from pypy.conftest import gettestobjspace from pypy.conftest import option -class AppTestTrackVersion: +class AppTestComparesByIdentity: def setup_class(cls): from pypy.objspace.std import identitydict @@ -13,15 +13,6 @@ return space.wrap(w_cls.compares_by_identity()) cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) - def get_version(space): - v = cls.versions.setdefault(identitydict.get_global_version(space), - len(cls.versions)) - return space.wrap(v) - cls.w_get_version = cls.space.wrap(interp2app(get_version)) - - def setup_method(self, m): - self.__class__.versions = {} - def test_compares_by_identity(self): class Plain(object): pass @@ -53,56 +44,6 @@ del X.__eq__ assert self.compares_by_identity(X) - def test_versioning(self): - class X(object): - pass - - class Y(object): - def __eq__(self, other): - pass - - assert self.get_version() == 0 - X.__eq__ = lambda x: None - # modifying a class for which we never checked the - # compares_by_identity() status does not increase the version - assert self.get_version() == 0 - - del X.__eq__ - assert self.compares_by_identity(X) # now we check it - X.__add__ = lambda x: None - assert self.get_version() == 0 # innocent change - # - X.__eq__ = lambda x: None - assert self.get_version() == 1 # BUMP! - - del X.__eq__ - assert self.compares_by_identity(X) - X.__bases__ = (object,) - assert self.get_version() == 2 # BUMP! - - # modifying a class which is already "bad" does not increase the - # version - Y.__eq__ = lambda x: None - assert self.get_version() == 2 - - def test_change___class__(self): - class X(object): - pass - - class Y(object): - pass - - class Z(object): - def __eq__(self, other): - pass - - x = X() - assert self.compares_by_identity(X) - assert self.get_version() == 0 - x.__class__ = Y - assert self.get_version() == 0 - x.__class__ = Z - assert self.get_version() == 1 class AppTestIdentityDict(object): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -178,8 +178,6 @@ if (key is None or key == '__eq__' or key == '__cmp__' or key == '__hash__'): w_self.compares_by_identity_status = UNKNOWN - if did_compare_by_identity: - identitydict.bump_global_version(w_self.space) if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None From noreply at buildbot.pypy.org Thu Jul 21 13:48:51 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 13:48:51 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: add a test for old classes, which are not supported Message-ID: <20110721114851.605F9829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45806:d8d5656b9fb0 Date: 2011-07-21 13:40 +0200 http://bitbucket.org/pypy/pypy/changeset/d8d5656b9fb0/ Log: add a test for old classes, which are not supported diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py --- a/pypy/objspace/std/test/test_identitydict.py +++ b/pypy/objspace/std/test/test_identitydict.py @@ -45,7 +45,6 @@ assert self.compares_by_identity(X) - class AppTestIdentityDict(object): def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) @@ -128,3 +127,10 @@ assert d1 == d2 assert self.uses_identity_strategy(d1) assert not self.uses_identity_strategy(d2) + + def test_old_style_classes(self): + class X: + pass + + d = {X(): 1} + assert not self.uses_identity_strategy(d) From noreply at buildbot.pypy.org Thu Jul 21 13:48:52 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 13:48:52 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: kill empty line Message-ID: <20110721114852.8B17F829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45807:23f86e47c147 Date: 2011-07-21 13:48 +0200 http://bitbucket.org/pypy/pypy/changeset/23f86e47c147/ Log: kill empty line diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py --- a/pypy/objspace/std/test/test_identitydict.py +++ b/pypy/objspace/std/test/test_identitydict.py @@ -131,6 +131,5 @@ def test_old_style_classes(self): class X: pass - d = {X(): 1} assert not self.uses_identity_strategy(d) From noreply at buildbot.pypy.org Thu Jul 21 13:49:47 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 13:49:47 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: hg merge default Message-ID: <20110721114947.38DC4829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45808:29e2cbaf79cd Date: 2011-07-21 13:49 +0200 http://bitbucket.org/pypy/pypy/changeset/29e2cbaf79cd/ Log: hg merge default diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -31,7 +31,8 @@ _immutable_fields_ = ['code?', 'w_func_globals?', 'closure?', - 'defs_w?[*]'] + 'defs_w?[*]', + 'name?'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -395,7 +395,7 @@ ('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed), ('int_abs', [lltype.Signed], lltype.Signed), ('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float), - ] +] class LLtypeHelpers: diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -390,8 +390,21 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): - return self.execute_with_descr(rop.GETARRAYITEM_GC, + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache and isinstance(indexbox, ConstInt): + index = indexbox.getint() + frombox, tobox = cache.get(index, (None, None)) + if frombox is arraybox: + return tobox + resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) + if isinstance(indexbox, ConstInt): + if not cache: + cache = self.metainterp.heap_array_cache[arraydescr] = {} + index = indexbox.getint() + cache[index] = arraybox, resbox + return resbox + opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any @@ -419,6 +432,13 @@ indexbox, itembox): self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, itembox) + if isinstance(indexbox, ConstInt): + cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {}) + cache[indexbox.getint()] = arraybox, itembox + else: + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache: + cache.clear() opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any @@ -454,21 +474,17 @@ def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, - sbox, sizebox) + self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox) abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, sizebox) - self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, - sbox, abox) + self._opimpl_setfield_gc_any(sbox, itemsdescr, abox) return sbox @arguments("box", "descr", "descr", "box") def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox) opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any @@ -477,10 +493,9 @@ @arguments("box", "descr", "descr", "box", "box") def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, - indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox, + valuebox) opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any @@ -502,18 +517,29 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC, box, fielddescr) opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @arguments("box", "descr") def _opimpl_getfield_gc_pure_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_PURE, box, fielddescr) opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any + @specialize.arg(1) + def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(opnum, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox + @arguments("orgpc", "box", "descr") def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr): ginfo = self.metainterp.jitdriver_sd.greenfield_info @@ -532,7 +558,11 @@ @arguments("box", "descr", "box") def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box and tobox is valuebox: + return self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + self.metainterp.heap_cache[fielddescr] = (box, valuebox) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any @@ -617,7 +647,7 @@ @arguments("orgpc", "box", "descr") def _opimpl_getfield_vable(self, pc, box, fielddescr): if self._nonstandard_virtualizable(pc, box): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any(box, fielddescr) self.metainterp.check_synchronized_virtualizable() index = self._get_virtualizable_field_index(fielddescr) return self.metainterp.virtualizable_boxes[index] @@ -629,8 +659,7 @@ @arguments("orgpc", "box", "descr", "box") def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox): if self._nonstandard_virtualizable(pc, box): - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) - return + return self._opimpl_setfield_gc_any(box, fielddescr, valuebox) index = self._get_virtualizable_field_index(fielddescr) self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -660,10 +689,8 @@ @arguments("orgpc", "box", "descr", "descr", "box") def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr, - arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox) self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) return self.metainterp.virtualizable_boxes[index] @@ -676,10 +703,9 @@ def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox, valuebox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - self.execute_with_descr(rop.SETARRAYITEM_GC, adescr, - arraybox, indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + self._opimpl_setarrayitem_gc_any(arraybox, adescr, + indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -693,8 +719,7 @@ @arguments("orgpc", "box", "descr", "descr") def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -1462,6 +1487,12 @@ self.known_class_boxes = {} # contains frame boxes that are not virtualizables self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1637,10 +1668,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1804,6 +1852,8 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} + self.heap_array_cache = {} duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), @@ -2311,6 +2361,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1024,69 +1024,6 @@ res = self.meta_interp(main, []) assert res == 55 - def test_dont_record_repeated_guard_class(self): - class A: - pass - class B(A): - pass - @dont_look_inside - def extern(n): - if n == -7: - return None - elif n: - return A() - else: - return B() - def fn(n): - obj = extern(n) - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=1, guard_nonnull=1) - res = self.interp_operations(fn, [1]) - assert not res - - def test_dont_record_guard_class_after_new(self): - class A: - pass - class B(A): - pass - def fn(n): - if n == -7: - obj = None - elif n: - obj = A() - else: - obj = B() - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=0, guard_nonnull=0) - res = self.interp_operations(fn, [1]) - assert not res - - def test_guard_isnull_nullifies(self): - class A: - pass - a = A() - a.x = None - def fn(n): - if n == -7: - a.x = "" - obj = a.x - res = 0 - if not obj: - res += 1 - if obj: - res += 1 - if obj is None: - res += 1 - if obj is not None: - res += 1 - return res - res = self.interp_operations(fn, [0]) - assert res == 2 - self.check_operations_history(guard_isnull=1) def test_assert_isinstance(self): class A: @@ -1248,7 +1185,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,407 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + l = [1] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * (4 + a) + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + len(frame.l) + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -268,3 +268,7 @@ if errors: w_errors = space.wrap(rffi.charp2str(errors)) return space.call_method(w_str, 'encode', w_encoding, w_errors) + + at cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -287,3 +287,9 @@ def test_eq(self, space, api): assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'ab' diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -15,14 +15,22 @@ # ufuncs 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', + 'add': 'interp_ufuncs.add', 'copysign': 'interp_ufuncs.copysign', + 'divide': 'interp_ufuncs.divide', 'exp': 'interp_ufuncs.exp', + 'fabs': 'interp_ufuncs.fabs', 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', + 'multiply': 'interp_ufuncs.multiply', 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'subtract': 'interp_ufuncs.subtract', + 'sin': 'interp_ufuncs.sin', + 'cos': 'interp_ufuncs.cos', + 'tan': 'interp_ufuncs.tan', } appleveldefs = { diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -3,7 +3,7 @@ It should not be imported by the module itself """ -from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray class BogusBytecode(Exception): pass @@ -18,6 +18,14 @@ def wrap(self, x): return x + def issequence_w(self, w_obj): + # Completley wrong in the general case, but good enough for this. + return isinstance(w_obj, BaseArray) + + def float_w(self, w_obj): + assert isinstance(w_obj, float) + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() stack = [] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,7 +2,11 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy.interp_support import Signature +from pypy.module.micronumpy import interp_ufuncs +from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit +from pypy.rlib.rfloat import DTSF_STR_PRECISION from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name import math @@ -21,16 +25,8 @@ reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) - -class Signature(object): - def __init__(self): - self.transitions = {} - - def transition(self, target): - if target in self.transitions: - return self.transitions[target] - self.transitions[target] = new = Signature() - return new +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) def pos(v): return v @@ -40,21 +36,16 @@ return abs(v) def add(v1, v2): return v1 + v2 -def sub(v1, v2): - return v1 - v2 def mul(v1, v2): return v1 * v2 -def div(v1, v2): - return v1 / v2 -def power(v1, v2): - return math.pow(v1, v2) -def mod(v1, v2): - return math.fmod(v1, v2) def maximum(v1, v2): return max(v1, v2) def minimum(v1, v2): return min(v1, v2) +def float2string(x): + return float2string_orig(x, 'g', DTSF_STR_PRECISION) + class BaseArray(Wrappable): def __init__(self): self.invalidates = [] @@ -84,51 +75,30 @@ descr_neg = _unop_impl(neg) descr_abs = _unop_impl(absolute) - def _binop_impl(function): - signature = Signature() + def _binop_impl(w_ufunc): def impl(self, space, w_other): - w_other = convert_to_array(space, w_other) - new_sig = self.signature.transition(signature) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + return w_ufunc(space, self, w_other) + return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__) - descr_add = _binop_impl(add) - descr_sub = _binop_impl(sub) - descr_mul = _binop_impl(mul) - descr_div = _binop_impl(div) - descr_pow = _binop_impl(power) - descr_mod = _binop_impl(mod) + descr_add = _binop_impl(interp_ufuncs.add) + descr_sub = _binop_impl(interp_ufuncs.subtract) + descr_mul = _binop_impl(interp_ufuncs.multiply) + descr_div = _binop_impl(interp_ufuncs.divide) + descr_pow = _binop_impl(interp_ufuncs.power) + descr_mod = _binop_impl(interp_ufuncs.mod) - def _binop_right_impl(function): - signature = Signature() + def _binop_right_impl(w_ufunc): def impl(self, space, w_other): - new_sig = self.signature.transition(signature) w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - w_other, - self, - new_sig.transition(w_other.signature) - ) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, - "binop_right_%s_impl" % function.__name__) + return w_ufunc(space, w_other, self) + return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__) - descr_radd = _binop_right_impl(add) - descr_rsub = _binop_right_impl(sub) - descr_rmul = _binop_right_impl(mul) - descr_rdiv = _binop_right_impl(div) - descr_rpow = _binop_right_impl(power) - descr_rmod = _binop_right_impl(mod) + descr_radd = _binop_right_impl(interp_ufuncs.add) + descr_rsub = _binop_right_impl(interp_ufuncs.subtract) + descr_rmul = _binop_right_impl(interp_ufuncs.multiply) + descr_rdiv = _binop_right_impl(interp_ufuncs.divide) + descr_rpow = _binop_right_impl(interp_ufuncs.power) + descr_rmod = _binop_right_impl(interp_ufuncs.mod) def _reduce_sum_prod_impl(function, init): reduce_driver = jit.JitDriver(greens=['signature'], @@ -235,6 +205,24 @@ else: return self.descr_mul(space, w_other) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] + nums.append("..." + "," * comma) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) + else: + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] + return nums + def get_concrete(self): raise NotImplementedError @@ -245,10 +233,14 @@ return self.get_concrete().descr_len(space) def descr_repr(self, space): - return self.get_concrete()._repr(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])") def descr_str(self, space): - return self.get_concrete()._str(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("[" + " ".join(concrete._getnums(True)) + "]") def descr_getitem(self, space, w_idx): # TODO: indexing by tuples @@ -261,10 +253,17 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().setitem(start, space.float_w(w_value)) + else: + self.get_concrete().setslice(space, start, stop, step, + slice_length, w_value) def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) @@ -413,8 +412,8 @@ return self.parent.getitem(self.calc_index(item)) @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - return self.parent.descr_setitem(space, self.calc_index(item), value) + def setitem(self, item, value): + return self.parent.setitem(self.calc_index(item), value) def descr_len(self, space): return space.wrap(self.find_size()) @@ -428,37 +427,57 @@ def __init__(self, start, stop, step, slice_length, parent, signature): ViewArray.__init__(self, parent, signature) + if isinstance(parent, SingleDimSlice): + self.start = parent.calc_index(start) + self.stop = parent.calc_index(stop) + self.step = parent.step * step + self.parent = parent.parent + else: self.start = start self.stop = stop self.step = step + self.parent = parent self.size = slice_length def find_size(self): return self.size + def _sliceloop1(self, start, stop, step, arr): + storage = self.parent.storage + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=arr.signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + storage[i] = arr.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, arr): + storage = self.parent.storage + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=arr.signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + storage[i] = arr.eval(j) + j += 1 + i += step + + def setslice(self, space, start, stop, step, slice_length, arr): + arr = convert_to_array(space, arr) + start = self.calc_index(start) + if stop != -1: + stop = self.calc_index(stop) + step = self.step * step + if step > 0: + self._sliceloop1(start, stop, step, arr) + else: + self._sliceloop2(start, stop, step, arr) + def calc_index(self, item): return (self.start + item * self.step) - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - class SingleDimArray(BaseArray): signature = Signature() @@ -479,49 +498,44 @@ def eval(self, i): return self.storage[i] - def getindex(self, space, item): - if item >= self.size: - raise operationerrfmt(space.w_IndexError, - '%d above array size', item) - if item < 0: - item += self.size - if item < 0: - raise operationerrfmt(space.w_IndexError, - '%d below zero', item) - return item - def descr_len(self, space): return space.wrap(self.size) def getitem(self, item): return self.storage[item] - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - item = self.getindex(space, item) + def setitem(self, item, value): self.invalidated() self.storage[item] = value + def _sliceloop1(self, start, stop, step, arr): + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=arr.signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, arr): + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=arr.signature, self=self, + step=step, stop=stop, i=i, j=j, arr=arr) + self.storage[i] = arr.eval(j) + j += 1 + i += step + + def setslice(self, space, start, stop, step, slice_length, arr): + if not isinstance(arr, BaseArray): + arr = convert_to_array(space, arr) + if step > 0: + self._sliceloop1(start, stop, step, arr) + else: + self._sliceloop2(start, stop, step, arr) + def __del__(self): lltype.free(self.storage, flavor='raw') diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py --- a/pypy/module/micronumpy/interp_support.py +++ b/pypy/module/micronumpy/interp_support.py @@ -1,14 +1,14 @@ - from pypy.rlib.rstruct.runpack import runpack from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.interp_numarray import SingleDimArray + FLOAT_SIZE = rffi.sizeof(lltype.Float) @unwrap_spec(s=str) def fromstring(space, s): + from pypy.module.micronumpy.interp_numarray import SingleDimArray length = len(s) if length % FLOAT_SIZE == 0: @@ -30,3 +30,13 @@ end += FLOAT_SIZE return space.wrap(a) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,13 +1,13 @@ import math -from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, - convert_to_array) +from pypy.module.micronumpy.interp_support import Signature from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name def ufunc(func): signature = Signature() def impl(space, w_obj): + from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array if space.issequence_w(w_obj): w_obj_arr = convert_to_array(space, w_obj) w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) @@ -20,6 +20,7 @@ def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): + from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): w_lhs_arr = convert_to_array(space, w_lhs) w_rhs_arr = convert_to_array(space, w_rhs) @@ -37,9 +38,17 @@ return abs(value) @ufunc2 +def add(lvalue, rvalue): + return lvalue + rvalue + + at ufunc2 def copysign(lvalue, rvalue): return rfloat.copysign(lvalue, rvalue) + at ufunc2 +def divide(lvalue, rvalue): + return lvalue / rvalue + @ufunc def exp(value): try: @@ -47,6 +56,10 @@ except OverflowError: return rfloat.INFINITY + at ufunc +def fabs(value): + return math.fabs(value) + @ufunc2 def maximum(lvalue, rvalue): return max(lvalue, rvalue) @@ -55,6 +68,10 @@ def minimum(lvalue, rvalue): return min(lvalue, rvalue) + at ufunc2 +def multiply(lvalue, rvalue): + return lvalue * rvalue + @ufunc def negative(value): return -value @@ -65,6 +82,10 @@ return rfloat.copysign(rfloat.INFINITY, value) return 1.0 / value + at ufunc2 +def subtract(lvalue, rvalue): + return lvalue - rvalue + @ufunc def floor(value): return math.floor(value) @@ -74,3 +95,23 @@ if value == 0.0: return 0.0 return rfloat.copysign(1.0, value) + + at ufunc +def sin(value): + return math.sin(value) + + at ufunc +def cos(value): + return math.cos(value) + + at ufunc +def tan(value): + return math.tan(value) + + at ufunc2 +def power(lvalue, rvalue): + return math.pow(lvalue, rvalue) + + at ufunc2 +def mod(lvalue, rvalue): + return math.fmod(lvalue, rvalue) \ No newline at end of file diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -92,6 +92,48 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_of_slice_array(self): + from numpy import array, zeros + a = zeros(5) + a[::2] = array([9., 10., 11.]) + assert a[0] == 9. + assert a[2] == 10. + assert a[4] == 11. + a[1:4:2][::-1] = array([1., 2.]) + assert a[0] == 9. + assert a[1] == 2. + assert a[2] == 10. + assert a[3] == 1. + assert a[4] == 11. + a = zeros(10) + a[::2][::-1][::2] = array(range(1,4)) + assert a[8] == 1. + assert a[4] == 2. + assert a[0] == 3. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -65,6 +65,33 @@ for i in range(3): assert b[i] == abs(a[i]) + def test_add(self): + from numpy import array, add + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = add(a, b) + for i in range(3): + assert c[i] == a[i] + b[i] + + def test_divide(self): + from numpy import array, divide + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = divide(a, b) + for i in range(3): + assert c[i] == a[i] / b[i] + + def test_fabs(self): + from numpy import array, fabs + from math import fabs as math_fabs + + a = array([-5.0, -0.0, 1.0]) + b = fabs(a) + for i in range(3): + assert b[i] == math_fabs(a[i]) + def test_minimum(self): from numpy import array, minimum @@ -83,6 +110,15 @@ for i in range(3): assert c[i] == max(a[i], b[i]) + def test_multiply(self): + from numpy import array, multiply + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = multiply(a, b) + for i in range(3): + assert c[i] == a[i] * b[i] + def test_sign(self): from numpy import array, sign @@ -101,6 +137,15 @@ for i in range(4): assert b[i] == reference[i] + def test_subtract(self): + from numpy import array, subtract + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = subtract(a, b) + for i in range(3): + assert c[i] == a[i] - b[i] + def test_floor(self): from numpy import array, floor @@ -133,3 +178,30 @@ except OverflowError: res = float('inf') assert b[i] == res + + def test_sin(self): + import math + from numpy import array, sin + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = sin(a) + for i in range(len(a)): + assert b[i] == math.sin(a[i]) + + def test_cos(self): + import math + from numpy import array, cos + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = cos(a) + for i in range(len(a)): + assert b[i] == math.cos(a[i]) + + def test_tan(self): + import math + from numpy import array, tan + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = tan(a) + for i in range(len(a)): + assert b[i] == math.tan(a[i]) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -5,6 +5,7 @@ from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): w_ValueError = None @@ -48,8 +49,6 @@ assert result == f(5) def test_neg(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call1(neg, ar, Signature()) @@ -104,6 +103,7 @@ "float_gt": 1, "int_add": 1, "int_lt": 1, "guard_true": 1, "guard_false": 1, "jump": 1}) + assert result == f(5) def test_min(self): space = self.space @@ -121,6 +121,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_argmin(self): space = self.space @@ -138,6 +139,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_all(self): space = self.space @@ -153,6 +155,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_any(self): space = self.space @@ -165,6 +168,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "guard_false": 1, "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) def test_already_forecd(self): def f(i): @@ -248,6 +252,28 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar2.storage[1] = 5.5 + if NonConstant(False): + arg = ar2 + else: + arg = ar2.descr_add(space, ar2) + ar.setslice(space, 0, step*i, step, i, arg) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 2, + 'float_add' : 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == 11.0 + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -133,8 +133,7 @@ else: return space.wrap("0x%sp%s%d" % (s, sign, exp)) -def float2string(space, w_float, code, precision): - x = w_float.floatval +def float2string(x, code, precision): # we special-case explicitly inf and nan here if isfinite(x): s = formatd(x, code, precision, DTSF_ADD_DOT_0) @@ -145,13 +144,13 @@ s = "-inf" else: # isnan(x): s = "nan" - return space.wrap(s) + return s def repr__Float(space, w_float): - return float2string(space, w_float, 'r', 0) + return space.wrap(float2string(w_float.floatval, 'r', 0)) def str__Float(space, w_float): - return float2string(space, w_float, 'g', DTSF_STR_PRECISION) + return space.wrap(float2string(w_float.floatval, 'g', DTSF_STR_PRECISION)) def format__Float_ANY(space, w_float, w_spec): return newformat.run_formatter(space, w_spec, "format_float", w_float) diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -69,8 +69,6 @@ [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) -math_log = llexternal('log', [rffi.DOUBLE], rffi.DOUBLE) -math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -222,10 +220,6 @@ return (fracpart, intpart) -def ll_math_copysign(x, y): - return math_copysign(x, y) # no error checking needed - - def ll_math_fmod(x, y): if isinf(y): if isinf(x): diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py --- a/pypy/rpython/memory/gctransform/asmgcroot.py +++ b/pypy/rpython/memory/gctransform/asmgcroot.py @@ -184,7 +184,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.aid2stack = copy_without_null_values(gcdata.aid2stack) + copy = copy_without_null_values(gcdata.aid2stack) + gcdata.aid2stack.delete() + gcdata.aid2stack = copy def belongs_to_current_thread(framedata): # xxx obscure: the answer is Yes if, as a pointer, framedata diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1449,8 +1449,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.thread_stacks = copy_without_null_values( - gcdata.thread_stacks) + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy def switch_shadow_stacks(new_aid): save_away_current_stack() diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -37,7 +37,7 @@ return self._is_guard def repr(self): - args = self.getargs() + args = self.args if self.descr is not None: args.append('descr=%s' % self.descr) arglist = ', '.join(args) @@ -145,10 +145,10 @@ if operations[0].name == 'debug_merge_point': self.inline_level = int(operations[0].args[0]) m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', - operations[0].getarg(1)) + operations[0].args[1]) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1][1:-1] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -181,7 +181,7 @@ """) ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] - assert chunk.bytecode_name == 'StrLiteralSearch' + assert chunk.bytecode_name.startswith('StrLiteralSearch') def test_parsing_assembler(): backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -251,12 +251,8 @@ CBuilder.have___thread = self.translator.platform.check___thread() if not self.standalone: assert not self.config.translation.instrument - self.eci, cfile, extra = gen_source(db, modulename, targetdir, - self.eci, - defines = defines, - split=self.split) else: - pfname = db.get(pf) + defines['PYPY_STANDALONE'] = db.get(pf) if self.config.translation.instrument: defines['INSTRUMENT'] = 1 if CBuilder.have___thread: @@ -266,11 +262,9 @@ defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( export_symbols=["pypy_main_startup"])) - self.eci, cfile, extra = gen_source_standalone(db, modulename, - targetdir, - self.eci, - entrypointname = pfname, - defines = defines) + self.eci, cfile, extra = gen_source(db, modulename, targetdir, + self.eci, defines=defines, + split=self.split) self.c_source_filename = py.path.local(cfile) self.extrafiles = self.eventually_copy(extra) self.gen_makefile(targetdir, exe_name=exe_name) @@ -435,6 +429,7 @@ class CStandaloneBuilder(CBuilder): standalone = True + split = True executable_name = None shared_library_name = None @@ -948,63 +943,8 @@ return eci.merge(ExternalCompilationInfo(separate_module_files=files)) -def gen_source_standalone(database, modulename, targetdir, eci, - entrypointname, defines={}): - assert database.standalone - if isinstance(targetdir, str): - targetdir = py.path.local(targetdir) - - filename = targetdir.join(modulename + '.c') - f = filename.open('w') - incfilename = targetdir.join('common_header.h') - fi = incfilename.open('w') - - # - # Header - # - print >> f, '#include "common_header.h"' - print >> f - commondefs(defines) - defines['PYPY_STANDALONE'] = entrypointname - for key, value in defines.items(): - print >> fi, '#define %s %s' % (key, value) - - eci.write_c_header(fi) - print >> fi, '#include "src/g_prerequisite.h"' - - fi.close() - - preimplementationlines = list( - pre_include_code_lines(database, database.translator.rtyper)) - - # - # 1) All declarations - # 2) Implementation of functions and global structures and arrays - # - sg = SourceGenerator(database, preimplementationlines) - sg.set_strategy(targetdir) - database.prepare_inline_helpers() - sg.gen_readable_parts_of_source(f) - - # 3) start-up code - print >> f - gen_startupcode(f, database) - - f.close() - - if 'INSTRUMENT' in defines: - fi = incfilename.open('a') - n = database.instrument_ncounter - print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n - fi.close() - - eci = add_extra_files(eci) - eci = eci.convert_sources_to_files(being_main=True) - files, eci = eci.get_module_files() - return eci, filename, sg.getextrafiles() + list(files) - -def gen_source(database, modulename, targetdir, eci, defines={}, split=False): - assert not database.standalone +def gen_source(database, modulename, targetdir, + eci, defines={}, split=False): if isinstance(targetdir, str): targetdir = py.path.local(targetdir) @@ -1046,6 +986,12 @@ gen_startupcode(f, database) f.close() + if 'INSTRUMENT' in defines: + fi = incfilename.open('a') + n = database.instrument_ncounter + print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n + fi.close() + eci = add_extra_files(eci) eci = eci.convert_sources_to_files(being_main=True) files, eci = eci.get_module_files() diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py --- a/pypy/translator/c/test/test_genc.py +++ b/pypy/translator/c/test/test_genc.py @@ -4,7 +4,6 @@ from pypy.translator.translator import TranslationContext from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c import genc -from pypy.translator.c.genc import gen_source from pypy.translator.c.gc import NoneGcPolicy from pypy.objspace.flow.model import Constant, Variable, SpaceOperation from pypy.objspace.flow.model import Block, Link, FunctionGraph From noreply at buildbot.pypy.org Thu Jul 21 14:05:58 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 21 Jul 2011 14:05:58 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: update to new interp interface and bench for PyROOT Message-ID: <20110721120558.DDD7B829B8@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45809:dbf532b2eb5c Date: 2011-07-19 06:50 -0700 http://bitbucket.org/pypy/pypy/changeset/dbf532b2eb5c/ Log: update to new interp interface and bench for PyROOT diff --git a/pypy/module/cppyy/test/bench1.py b/pypy/module/cppyy/test/bench1.py --- a/pypy/module/cppyy/test/bench1.py +++ b/pypy/module/cppyy/test/bench1.py @@ -15,7 +15,7 @@ def print_bench(name, t_bench): global t_cppref - print ':::: %s cost: %#6.3fs (%#4dx)' % (name, t_bench, t_bench/t_cppref) + print ':::: %s cost: %#6.3fs (%#4.1fx)' % (name, t_bench, float(t_bench)/t_cppref) def python_loop_offset(): for i in range(NNN): @@ -40,6 +40,14 @@ instance.addDataToInt(i) return i +class PyROOTBench1(PyCintexBench1): + def __init__(self): + import ROOT + self.lib = ROOT.gSystem.Load("./example01Dict_cint.so") + + self.cls = ROOT.example01 + self.inst = self.cls(0) + class CppyyInterpBench1(object): scale = 1 def __init__(self): @@ -47,15 +55,13 @@ self.lib = cppyy.load_lib("./example01Dict.so") self.cls = cppyy._type_byname("example01") - self.inst = self.cls.construct(0) + self.inst = self.cls.get_overload(self.cls.type_name).call(None, cppyy.CPPInstance, 0) def __call__(self): addDataToInt = self.cls.get_overload("addDataToInt") instance = self.inst for i in range(NNN): - #inst.invoke(cls.get_overload("addDataToDouble"), float(i)) - #inst.invoke(cls.get_overload("addDataToInt"), i) - instance.invoke(addDataToInt, i) + addDataToInt.call(instance, None, i) return i class CppyyPythonBench1(object): @@ -89,6 +95,12 @@ print run_bench(cintex_bench1) sys.exit(0) + # special case for PyCintex (run under python, not pypy-c) + if '--pyroot' in sys.argv: + pyroot_bench1 = PyROOTBench1() + print run_bench(pyroot_bench1) + sys.exit(0) + # get C++ reference point if not os.path.exists("bench1.exe") or\ os.stat("bench1.exe").st_mtime < os.stat("bench1.cxx").st_mtime: @@ -111,3 +123,5 @@ print_bench("cppyy python", run_bench(python_bench1)) stat, t_cintex = commands.getstatusoutput("python bench1.py --pycintex") print_bench("pycintex ", float(t_cintex)) + #stat, t_pyroot = commands.getstatusoutput("python bench1.py --pyroot") + #print_bench("pyroot ", float(t_pyroot)) From noreply at buildbot.pypy.org Thu Jul 21 14:06:00 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 21 Jul 2011 14:06:00 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: rules for compiling .cxx in generated makefile Message-ID: <20110721120600.13D44829B8@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45810:f93d9c300124 Date: 2011-07-21 05:04 -0700 http://bitbucket.org/pypy/pypy/changeset/f93d9c300124/ Log: rules for compiling .cxx in generated makefile diff --git a/pypy/translator/platform/posix.py b/pypy/translator/platform/posix.py --- a/pypy/translator/platform/posix.py +++ b/pypy/translator/platform/posix.py @@ -125,7 +125,7 @@ return fpath rel_cfiles = [m.pathrel(cfile) for cfile in cfiles] - rel_ofiles = [rel_cfile[:-2]+'.o' for rel_cfile in rel_cfiles] + rel_ofiles = [rel_cfile[:rel_cfile.rfind('.')]+'.o' for rel_cfile in rel_cfiles] m.cfiles = rel_cfiles rel_includedirs = [pypyrel(incldir) for incldir in @@ -159,6 +159,7 @@ ('all', '$(DEFAULT_TARGET)', []), ('$(TARGET)', '$(OBJECTS)', '$(CC_LINK) $(LDFLAGS) $(LDFLAGSEXTRA) -o $@ $(OBJECTS) $(LIBDIRS) $(LIBS) $(LINKFILES)'), ('%.o', '%.c', '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)'), + ('%.o', '%.cxx', '$(CXX) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)'), ] for rule in rules: From noreply at buildbot.pypy.org Thu Jul 21 14:06:01 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 21 Jul 2011 14:06:01 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: merge heads Message-ID: <20110721120601.3E809829B8@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45811:bddd0178cf08 Date: 2011-07-21 05:05 -0700 http://bitbucket.org/pypy/pypy/changeset/bddd0178cf08/ Log: merge heads diff --git a/pypy/module/cppyy/test/bench1.py b/pypy/module/cppyy/test/bench1.py --- a/pypy/module/cppyy/test/bench1.py +++ b/pypy/module/cppyy/test/bench1.py @@ -15,7 +15,7 @@ def print_bench(name, t_bench): global t_cppref - print ':::: %s cost: %#6.3fs (%#4dx)' % (name, t_bench, t_bench/t_cppref) + print ':::: %s cost: %#6.3fs (%#4.1fx)' % (name, t_bench, float(t_bench)/t_cppref) def python_loop_offset(): for i in range(NNN): @@ -40,6 +40,14 @@ instance.addDataToInt(i) return i +class PyROOTBench1(PyCintexBench1): + def __init__(self): + import ROOT + self.lib = ROOT.gSystem.Load("./example01Dict_cint.so") + + self.cls = ROOT.example01 + self.inst = self.cls(0) + class CppyyInterpBench1(object): scale = 1 def __init__(self): @@ -47,15 +55,13 @@ self.lib = cppyy.load_lib("./example01Dict.so") self.cls = cppyy._type_byname("example01") - self.inst = self.cls.construct(0) + self.inst = self.cls.get_overload(self.cls.type_name).call(None, cppyy.CPPInstance, 0) def __call__(self): addDataToInt = self.cls.get_overload("addDataToInt") instance = self.inst for i in range(NNN): - #inst.invoke(cls.get_overload("addDataToDouble"), float(i)) - #inst.invoke(cls.get_overload("addDataToInt"), i) - instance.invoke(addDataToInt, i) + addDataToInt.call(instance, None, i) return i class CppyyPythonBench1(object): @@ -89,6 +95,12 @@ print run_bench(cintex_bench1) sys.exit(0) + # special case for PyCintex (run under python, not pypy-c) + if '--pyroot' in sys.argv: + pyroot_bench1 = PyROOTBench1() + print run_bench(pyroot_bench1) + sys.exit(0) + # get C++ reference point if not os.path.exists("bench1.exe") or\ os.stat("bench1.exe").st_mtime < os.stat("bench1.cxx").st_mtime: @@ -111,3 +123,5 @@ print_bench("cppyy python", run_bench(python_bench1)) stat, t_cintex = commands.getstatusoutput("python bench1.py --pycintex") print_bench("pycintex ", float(t_cintex)) + #stat, t_pyroot = commands.getstatusoutput("python bench1.py --pyroot") + #print_bench("pyroot ", float(t_pyroot)) From noreply at buildbot.pypy.org Thu Jul 21 14:07:44 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 14:07:44 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: document this small difference Message-ID: <20110721120744.94526829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45812:a02a3e34b4f2 Date: 2011-07-21 14:07 +0200 http://bitbucket.org/pypy/pypy/changeset/a02a3e34b4f2/ Log: document this small difference diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -211,6 +211,38 @@ >>>> print d1['a'] 42 +Mutating classes of objects which are already used as dictionary keys +--------------------------------------------------------------------- + +Consider the following snippet of code:: + + class X(object): + pass + + def __evil_eq__(self, other): + print 'hello world' + return False + + def evil(y): + d = {x(): 1} + X.__eq__ = __evil_eq__ + d[y] # might trigger a call to __eq__? + +In CPython, __evil_eq__ **might** be called, although there is no way to write +a test which reliably calls it. It happens if ``y is not x`` and ``hash(y) == +hash(x)``, where ``hash(x)`` is computed when ``x`` is inserted into the +dictionary. If **by chance** the condition is satisfied, then ``__evil_eq__`` +is called. + +PyPy uses a special strategy to optimize dictionaries whose keys are instances +of user-defined classes which do not override the default ``__hash__``, +``__eq__`` and ``__cmp__``: when using this strategy, ``__eq__`` and +``__cmp__`` are never called, but instead the lookup is done by identity, so +in the case above it is guaranteed that ``__eq__`` won't be called. + +Note that in all other cases (e.g., if you have a custom ``__hash__`` and +``__eq__`` in ``y``) the behavior is exactly the same as CPython. + Ignored exceptions ----------------------- From noreply at buildbot.pypy.org Thu Jul 21 14:15:30 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 21 Jul 2011 14:15:30 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: bench02 code cleanup and test of bench Message-ID: <20110721121530.52DED829B8@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45813:41aebf1d8db1 Date: 2011-07-21 05:15 -0700 http://bitbucket.org/pypy/pypy/changeset/41aebf1d8db1/ Log: bench02 code cleanup and test of bench diff --git a/pypy/module/cppyy/bench/bench02.cxx b/pypy/module/cppyy/bench/bench02.cxx --- a/pypy/module/cppyy/bench/bench02.cxx +++ b/pypy/module/cppyy/bench/bench02.cxx @@ -1,4 +1,5 @@ #include "bench02.h" + #include "TROOT.h" #include "TApplication.h" #include "TDirectory.h" @@ -10,92 +11,64 @@ #include "Getline.h" #include "TVirtualX.h" -// CINT #include "Api.h" #include + class TTestApplication : public TApplication { public: TTestApplication( - const char* acn, Int_t* argc, char** argv, Bool_t bLoadLibs = kTRUE ); - + const char* acn, Int_t* argc, char** argv, Bool_t bLoadLibs = kTRUE); virtual ~TTestApplication(); }; - -//- constructors/destructor -------------------------------------------------- TTestApplication::TTestApplication( - const char* acn, int* argc, char** argv, bool bLoadLibs ) : - TApplication( acn, argc, argv ) -{ -// Create a TApplication derived for use with interactive ROOT from python. A -// set of standard, often used libs is loaded if bLoadLibs is true (default). - - if ( bLoadLibs ) // note that this section could be programmed in python - { + const char* acn, int* argc, char** argv, bool do_load) : TApplication(acn, argc, argv) { + if (do_load) { // follow TRint to minimize differences with CINT - ProcessLine( "#include ", kTRUE ); - ProcessLine( "#include <_string>", kTRUE ); // for std::string iostream. - ProcessLine( "#include ", kTRUE ); // needed because they're used within the - ProcessLine( "#include ", kTRUE ); // core ROOT dicts and CINT won't be able + ProcessLine("#include ", kTRUE); + ProcessLine("#include <_string>", kTRUE); // for std::string iostream. + ProcessLine("#include ", kTRUE); // needed because they're used within the + ProcessLine("#include ", kTRUE); // core ROOT dicts and CINT won't be able // to properly unload these files - - // following RINT, these are now commented out (rely on auto-loading) - // // the following libs are also useful to have, make sure they are loaded... - // gROOT->LoadClass("TMinuit", "Minuit"); - // gROOT->LoadClass("TPostScript", "Postscript"); - // gROOT->LoadClass("THtml", "Html"); } -#ifdef WIN32 - // switch win32 proxy main thread id - if (gVirtualX) - ProcessLine("((TGWin32 *)gVirtualX)->SetUserThreadId(0);", kTRUE); -#endif - -// save current interpreter context + // save current interpreter context gInterpreter->SaveContext(); gInterpreter->SaveGlobalsContext(); -// prevent crashes on accessing histor - Gl_histinit( (char*)"-" ); + // prevent crashes on accessing history + Gl_histinit((char*)"-"); -// prevent ROOT from exiting python - SetReturnFromRun( kTRUE ); + // prevent ROOT from exiting python + SetReturnFromRun(kTRUE); } TTestApplication::~TTestApplication() {} static const char* appname = "pypy-cppyy"; -CloserHack::CloserHack() { - std::cout << "gROOT is: " << gROOT << std::endl; - std::cout << "gApplication is: " << gApplication << std::endl; - - if ( ! gApplication ) { - // retrieve arg list from python, translate to raw C, pass on +Bench02RootApp::Bench02RootApp() { + if (!gApplication) { int argc = 1; char* argv[1]; argv[0] = (char*)appname; - gApplication = new TTestApplication( appname, &argc, argv, kTRUE ); + gApplication = new TTestApplication(appname, &argc, argv, kTRUE); } - - std::cout << "gApplication is: " << gApplication << std::endl; } -void CloserHack::report() { +Bench02RootApp::~Bench02RootApp() { + // TODO: ROOT globals cleanup ... (?) +} + +void Bench02RootApp::report() { std::cout << "gROOT is: " << gROOT << std::endl; std::cout << "gApplication is: " << gApplication << std::endl; } -void CloserHack::close() { - std::cout << "closing file ... " << std::endl; - if (gDirectory && gDirectory != gROOT) { - gDirectory->Write(); - gDirectory->Close(); - } +void Bench02RootApp::close_file(TFile* f) { + std::cout << "closing file " << f->GetName() << " ... " << std::endl; + f->Write(); + f->Close(); + std::cout << "... file closed" << std::endl; } - -CloserHack::~CloserHack() { -} - diff --git a/pypy/module/cppyy/bench/bench02.h b/pypy/module/cppyy/bench/bench02.h --- a/pypy/module/cppyy/bench/bench02.h +++ b/pypy/module/cppyy/bench/bench02.h @@ -4,18 +4,45 @@ #include "TNtuple.h" #include "TH1F.h" #include "TH2F.h" +#include "TRandom.h" #include "TROOT.h" #include "TApplication.h" +#include "TBox.h" +#include "TClassGenerator.h" +#include "TF1.h" +#include "TFileMergeInfo.h" +#include "TFolder.h" +#include "TFunction.h" +#include "TFrame.h" +#include "TGlobal.h" +#include "TInetAddress.h" +#include "TInterpreter.h" +#include "TKey.h" +#include "TLegend.h" +#include "TPluginManager.h" +#include "TProcessUUID.h" +#include "TStyle.h" +#include "TSysEvtHandler.h" +#include "TTimer.h" +#include "TView.h" +#include "TVirtualFFT.h" +#include "TVirtualHistPainter.h" +#include "TVirtualPadPainter.h" +#include "TVirtualViewer3D.h" -class CloserHack { +#include +#include + + +class Bench02RootApp { public: - CloserHack(); - ~CloserHack(); + Bench02RootApp(); + ~Bench02RootApp(); void report(); - void close(); + void close_file(TFile* f); }; /* diff --git a/pypy/module/cppyy/bench/bench02.xml b/pypy/module/cppyy/bench/bench02.xml --- a/pypy/module/cppyy/bench/bench02.xml +++ b/pypy/module/cppyy/bench/bench02.xml @@ -1,42 +1,31 @@ - - - + - - + + - - - - - - - - - - - - - - - - - - - - --> - - - - - - - - + + + + - + + + + + + + + + + + + + + + + diff --git a/pypy/module/cppyy/bench/hsimple.C b/pypy/module/cppyy/bench/hsimple.C --- a/pypy/module/cppyy/bench/hsimple.C +++ b/pypy/module/cppyy/bench/hsimple.C @@ -10,6 +10,8 @@ #include #include +#include + TFile *hsimple(Int_t get=0) { // This program creates : @@ -80,13 +82,13 @@ */ // Fill histograms randomly gRandom->SetSeed(); - Float_t px, py, pz; + Float_t px, py, pt; const Int_t kUPDATE = 1000; for (Int_t i = 0; i < 2500000; i++) { gRandom->Rannor(px,py); - pz = px*px + py*py; + pt = sqrt(px*px + py*py); // Float_t random = gRandom->Rndm(1); - hpx->Fill(px); + hpx->Fill(pt); /* hpxpy->Fill(px,py); hprof->Fill(px,pz); diff --git a/pypy/module/cppyy/bench/hsimple.py b/pypy/module/cppyy/bench/hsimple.py --- a/pypy/module/cppyy/bench/hsimple.py +++ b/pypy/module/cppyy/bench/hsimple.py @@ -14,18 +14,19 @@ import cppyy, random cppyy.load_lib('bench02Dict_reflex.so') + app = cppyy.gbl.Bench02RootApp() TCanvas = cppyy.gbl.TCanvas TFile = cppyy.gbl.TFile TProfile = cppyy.gbl.TProfile TNtuple = cppyy.gbl.TNtuple TH1F = cppyy.gbl.TH1F TH2F = cppyy.gbl.TH2F - CH = cppyy.gbl.CloserHack() - CH.report() + TRandom = cppyy.gbl.TRandom except ImportError: - from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F + from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F, TRandom import random +import math #gROOT = cppyy.gbl.gROOT #gBenchmark = cppyy.gbl.gBenchmark #gRandom = cppyy.gbl.gRandom @@ -34,7 +35,7 @@ #gROOT.Reset() # Create a new canvas, and customize it. -c1 = TCanvas( 'c1', 'Dynamic Filling Example', 200, 10, 700, 500 ) +#c1 = TCanvas( 'c1', 'Dynamic Filling Example', 200, 10, 700, 500 ) #c1.SetFillColor( 42 ) #c1.GetFrame().SetFillColor( 21 ) #c1.GetFrame().SetBorderSize( 6 ) @@ -65,14 +66,18 @@ #gRandom.SetSeed() #rannor, rndm = gRandom.Rannor, gRandom.Rndm +#random = TRandom() + # Fill histograms randomly. #px, py = Double(), Double() kUPDATE = 1000 for i in xrange( 2500000 ): # Generate random values. px, py = random.gauss(0, 1), random.gauss(0, 1) +# px, py = random.Gaus(0, 1), random.Gaus(0, 1) # pt = (px*px + py*py)**0.5 - pt = (px*px + py*py) + pt = math.sqrt(px*px + py*py) +# pt = (px*px + py*py) # random = rndm(1) # Fill histograms. @@ -82,9 +87,9 @@ # ntupleFill( px, py, pz, random, i ) # Update display every kUPDATE events. - if i and i%kUPDATE == 0: - if i == kUPDATE: - hpx.Draw() +# if i and i%kUPDATE == 0: +# if i == kUPDATE: +# hpx.Draw() # c1.Modified() # c1.Update() @@ -100,8 +105,8 @@ hfile.Close() #hpx.SetFillColor( 48 ) #c1.Modified() -c1.Update() -c1.Draw() +#c1.Update() +#c1.Draw() #import gc #gc.collect() From noreply at buildbot.pypy.org Thu Jul 21 14:15:31 2011 From: noreply at buildbot.pypy.org (wlav) Date: Thu, 21 Jul 2011 14:15:31 +0200 (CEST) Subject: [pypy-commit] pypy reflex-support: improved error reporting for unknown typed data members Message-ID: <20110721121531.8279E829B8@wyvern.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: reflex-support Changeset: r45814:d3333099ce6f Date: 2011-07-21 05:15 -0700 http://bitbucket.org/pypy/pypy/changeset/d3333099ce6f/ Log: improved error reporting for unknown typed data members diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -43,22 +43,22 @@ fieldptr = rffi.cast(rffi.CCHARP, offset) return fieldptr - def _is_abstract(self): - raise NotImplementedError( - "abstract base class" ) # more detailed part is not rpython: (actual: %s)" % type(self).__name__) + def _is_abstract(self, space): + raise OperationError(space.w_NotImplementedError, + space.wrap("no converter available")) # more detailed part is not rpython: (actual: %s)" % type(self).__name__)) def convert_argument(self, space, w_obj, address): - self._is_abstract() + self._is_abstract(space) def convert_argument_libffi(self, space, w_obj, argchain): from pypy.module.cppyy.interp_cppyy import FastCallNotPossible raise FastCallNotPossible def from_memory(self, space, w_obj, w_type, offset): - self._is_abstract() + self._is_abstract(space) def to_memory(self, space, w_obj, w_value, offset): - self._is_abstract() + self._is_abstract(space) def free_argument(self, arg): pass diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py --- a/pypy/module/cppyy/pythonify.py +++ b/pypy/module/cppyy/pythonify.py @@ -74,7 +74,13 @@ if not rettype: # return builtin type cppclass = None else: # return instance + try: cppclass = get_cppclass(rettype) + except AttributeError, e: + import warnings + warnings.warn("class %s unknown: no data member access" % rettype, + RuntimeWarning) + cppclass = None if cppdm.is_static(): def binder(obj): return cppdm.get(None, cppclass) diff --git a/pypy/module/cppyy/test/fragile.h b/pypy/module/cppyy/test/fragile.h --- a/pypy/module/cppyy/test/fragile.h +++ b/pypy/module/cppyy/test/fragile.h @@ -28,4 +28,15 @@ void overload(int, no_such_class* p = 0) {} }; +class E { +public: + E() : m_pp_no_such(0), m_pp_a(0) {} + + virtual int check() { return (int)'E'; } + void overload(no_such_class**) {} + + no_such_class** m_pp_no_such; + A** m_pp_a; +}; + } // namespace fragile diff --git a/pypy/module/cppyy/test/fragile.xml b/pypy/module/cppyy/test/fragile.xml --- a/pypy/module/cppyy/test/fragile.xml +++ b/pypy/module/cppyy/test/fragile.xml @@ -2,9 +2,6 @@ - - - - + diff --git a/pypy/module/cppyy/test/test_fragile.py b/pypy/module/cppyy/test/test_fragile.py --- a/pypy/module/cppyy/test/test_fragile.py +++ b/pypy/module/cppyy/test/test_fragile.py @@ -14,7 +14,7 @@ if err: raise OSError("'make' failed (see stderr)") -class AppTestSTL: +class AppTestFRAGILE: def setup_class(cls): cls.space = space env = os.environ @@ -65,3 +65,24 @@ d = fragile.D() raises(TypeError, d.overload, None) + raises(TypeError, d.overload, None, None, None) + + # TODO: the following fails in the fast path, b/c the default + # arguments are not properly filled + #d.overload('a') + #d.overload(1) + + def test04_unsupported_arguments(self): + """Test arguments that are yet unsupported""" + + import cppyy + + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + + assert fragile.E == fragile.E + assert fragile.E().check() == ord('E') + + e = fragile.E() + raises(TypeError, e.overload, None) + raises(NotImplementedError, getattr, e, 'm_pp_no_such') From noreply at buildbot.pypy.org Thu Jul 21 15:10:42 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 15:10:42 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: write doc for this option Message-ID: <20110721131042.BC7EF829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45815:9c9eaa7e08db Date: 2011-07-21 15:09 +0200 http://bitbucket.org/pypy/pypy/changeset/9c9eaa7e08db/ Log: write doc for this option diff --git a/pypy/doc/config/objspace.std.withidentitydict.txt b/pypy/doc/config/objspace.std.withidentitydict.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withidentitydict.txt @@ -0,0 +1,21 @@ +============================= +objspace.std.withidentitydict +============================= + +* **name:** withidentitydict + +* **description:** enable a dictionary strategy for "by identity" comparisons + +* **command-line:** --objspace-std-withidentitydict + +* **command-line for negation:** --no-objspace-std-withidentitydict + +* **option type:** boolean option + +* **default:** True + + +Enable a dictionary strategy specialized for instances of classes which +compares "by identity", which is the default unless you override ``__hash__``, +``__eq__`` or ``__cmp__``. This strategy will be used only with new-style +classes. From noreply at buildbot.pypy.org Thu Jul 21 15:10:43 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 15:10:43 +0200 (CEST) Subject: [pypy-commit] pypy identity-dict-strategy: close about-to-be-merged branch Message-ID: <20110721131043.E3FD4829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: identity-dict-strategy Changeset: r45816:6746c1579cab Date: 2011-07-21 15:10 +0200 http://bitbucket.org/pypy/pypy/changeset/6746c1579cab/ Log: close about-to-be-merged branch From noreply at buildbot.pypy.org Thu Jul 21 15:10:45 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 15:10:45 +0200 (CEST) Subject: [pypy-commit] pypy default: merge the identity-dict-strategy branch, which optimizes access to dictionary containing only classes which compare 'by identity' Message-ID: <20110721131045.4F5D1829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45817:69a7e76a319a Date: 2011-07-21 15:10 +0200 http://bitbucket.org/pypy/pypy/changeset/69a7e76a319a/ Log: merge the identity-dict-strategy branch, which optimizes access to dictionary containing only classes which compare 'by identity' diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -327,6 +327,9 @@ BoolOption("mutable_builtintypes", "Allow the changing of builtin types", default=False, requires=[("objspace.std.builtinshortcut", True)]), + BoolOption("withidentitydict", + "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not", + default=True), ]), ]) diff --git a/pypy/doc/config/objspace.std.withidentitydict.txt b/pypy/doc/config/objspace.std.withidentitydict.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withidentitydict.txt @@ -0,0 +1,21 @@ +============================= +objspace.std.withidentitydict +============================= + +* **name:** withidentitydict + +* **description:** enable a dictionary strategy for "by identity" comparisons + +* **command-line:** --objspace-std-withidentitydict + +* **command-line for negation:** --no-objspace-std-withidentitydict + +* **option type:** boolean option + +* **default:** True + + +Enable a dictionary strategy specialized for instances of classes which +compares "by identity", which is the default unless you override ``__hash__``, +``__eq__`` or ``__cmp__``. This strategy will be used only with new-style +classes. diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -211,6 +211,38 @@ >>>> print d1['a'] 42 +Mutating classes of objects which are already used as dictionary keys +--------------------------------------------------------------------- + +Consider the following snippet of code:: + + class X(object): + pass + + def __evil_eq__(self, other): + print 'hello world' + return False + + def evil(y): + d = {x(): 1} + X.__eq__ = __evil_eq__ + d[y] # might trigger a call to __eq__? + +In CPython, __evil_eq__ **might** be called, although there is no way to write +a test which reliably calls it. It happens if ``y is not x`` and ``hash(y) == +hash(x)``, where ``hash(x)`` is computed when ``x`` is inserted into the +dictionary. If **by chance** the condition is satisfied, then ``__evil_eq__`` +is called. + +PyPy uses a special strategy to optimize dictionaries whose keys are instances +of user-defined classes which do not override the default ``__hash__``, +``__eq__`` and ``__cmp__``: when using this strategy, ``__eq__`` and +``__cmp__`` are never called, but instead the lookup is done by identity, so +in the case above it is guaranteed that ``__eq__`` won't be called. + +Note that in all other cases (e.g., if you have a custom ``__hash__`` and +``__eq__`` in ``y``) the behavior is exactly the same as CPython. + Ignored exceptions ----------------------- diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -23,3 +23,29 @@ ops = loop.ops_by_id('look') assert log.opnames(ops) == ['setfield_gc', 'guard_not_invalidated'] + + def test_identitydict(self): + def fn(n): + class X(object): + pass + x = X() + d = {} + d[x] = 1 + res = 0 + for i in range(300): + value = d[x] # ID: getitem + res += value + return res + # + log = self.run(fn, [1000]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # check that the call to ll_dict_lookup is not a call_may_force + assert loop.match_by_id("getitem", """ + i25 = call(ConstClass(_ll_1_gc_identityhash__objectPtr), p6, descr=...) + ... + i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...) + ... + p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...) + ... + """) diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -28,6 +28,13 @@ return w_delattr object_delattr._annspecialcase_ = 'specialize:memo' +def object_hash(space): + "Utility that returns the app-level descriptor object.__hash__." + w_src, w_hash = space.lookup_in_type_where(space.w_object, + '__hash__') + return w_hash +object_hash._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): w_type = space.type(w_obj) typename = w_type.getname(space) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -157,11 +157,15 @@ return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): - #XXX implement other strategies later + withidentitydict = self.space.config.objspace.std.withidentitydict if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) - elif self.space.is_w(self.space.type(w_key), self.space.w_int): + return + w_type = self.space.type(w_key) + if self.space.is_w(w_type, self.space.w_int): self.switch_to_int_strategy(w_dict) + elif withidentitydict and w_type.compares_by_identity(): + self.switch_to_identity_strategy(w_dict) else: self.switch_to_object_strategy(w_dict) @@ -177,6 +181,13 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_identity_strategy(self, w_dict): + from pypy.objspace.std.identitydict import IdentityDictStrategy + strategy = self.space.fromcache(IdentityDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): strategy = self.space.fromcache(ObjectDictStrategy) storage = strategy.get_empty_storage() @@ -338,7 +349,6 @@ def getitem(self, w_dict, w_key): space = self.space - if self.is_correct_type(w_key): return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) elif self._never_equal_to(space.type(w_key)): @@ -404,6 +414,7 @@ def keys(self, w_dict): return self.unerase(w_dict.dstorage).keys() + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") @@ -448,7 +459,9 @@ return StrIteratorImplementation(self.space, self, w_dict) -class StrIteratorImplementation(IteratorImplementation): +class _WrappedIteratorMixin(object): + _mixin_ = True + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() @@ -460,6 +473,23 @@ else: return None, None +class _UnwrappedIteratorMixin: + _mixin_ = True + + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value + else: + return None, None + + +class StrIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass class IntDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("int") @@ -490,31 +520,11 @@ def iter(self, w_dict): return IntIteratorImplementation(self.space, self, w_dict) -class IntIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() +class IntIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass - def next_entry(self): - # note that this 'for' loop only runs once, at most - for key, w_value in self.iterator: - return self.space.wrap(key), w_value - else: - return None, None - - -class ObjectIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() - - def next_entry(self): - # note that this 'for' loop only runs once, at most - for w_key, w_value in self.iterator: - return w_key, w_value - else: - return None, None - +class ObjectIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass init_signature = Signature(['seq_or_map'], None, 'kwargs') init_defaults = [None] diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -86,7 +86,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated() + self.unerase(w_dict.dstorage).mutated(None) class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/identitydict.py @@ -0,0 +1,85 @@ +## ---------------------------------------------------------------------------- +## dict strategy (see dict_multiobject.py) + +from pypy.rlib import rerased +from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, + DictStrategy, + IteratorImplementation, + _UnwrappedIteratorMixin) + + +# this strategy is selected by EmptyDictStrategy.switch_to_correct_strategy +class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): + """ + Strategy for custom instances which compares by identity (i.e., the + default unless you override __hash__, __eq__ or __cmp__). The storage is + just a normal RPython dict, which has already the correct by-identity + semantics. + + Note that at a first sight, you might have problems if you mutate the + class of an object which is already inside an identitydict. Consider this + example:: + + class X(object): + pass + d = {x(): 1} + X.__eq__ = ... + d[y] # might trigger a call to __eq__? + + We want to be sure that x.__eq__ is called in the same cases as in + CPython. However, as long as the strategy is IdentityDictStrategy, the + __eq__ will never be called. + + It turns out that it's not a problem. In CPython (and in PyPy without + this strategy), the __eq__ is called if ``hash(y) == hash(x)`` and ``x is + not y``. Note that hash(x) is computed at the time when we insert x in + the dict, not at the time we lookup y. + + Now, how can hash(y) == hash(x)? There are two possibilities: + + 1. we write a custom __hash__ for the class of y, thus making it a not + "compares by reference" type + + 2. the class of y is "compares by reference" type, and by chance the + hash is the same as x + + In the first case, the getitem immediately notice that y is not of the + right type, and switches the strategy to ObjectDictStrategy, then the + lookup works as usual. + + The second case is completely non-deterministic, even in CPython. + Depending on the phase of the moon, you might call the __eq__ or not, so + it is perfectly fine to *never* call it. Morever, in practice with the + minimar GC we never have two live objects with the same hash, so it would + never happen anyway. + """ + + erase, unerase = rerased.new_erasing_pair("identitydict") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): + w_type = self.space.type(w_obj) + return w_type.compares_by_identity() + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return IdentityDictIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + + +class IdentityDictIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -6,7 +6,7 @@ from pypy.objspace.descroperation import Object from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.register_all import register_all - +from pypy.objspace.std import identitydict def descr__repr__(space, w_obj): w = space.wrap diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -39,7 +39,6 @@ from pypy.objspace.std.stringtype import wrapstr from pypy.objspace.std.unicodetype import wrapunicode - class StdObjSpace(ObjSpace, DescrOperation): """The standard object space, implementing a general-purpose object library in Restricted Python.""" diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -898,6 +898,7 @@ withsmalldicts = False withcelldict = False withmethodcache = False + withidentitydict = False FakeSpace.config = Config() @@ -1105,3 +1106,4 @@ fakespace = FakeSpace() d = fakespace.newdict(module=True) assert type(d.strategy) is StringDictStrategy + diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_identitydict.py @@ -0,0 +1,135 @@ +from pypy.interpreter.gateway import interp2app +from pypy.conftest import gettestobjspace +from pypy.conftest import option + +class AppTestComparesByIdentity: + + def setup_class(cls): + from pypy.objspace.std import identitydict + cls.space = gettestobjspace( + **{"objspace.std.withidentitydict": True}) + + def compares_by_identity(space, w_cls): + return space.wrap(w_cls.compares_by_identity()) + cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) + + def test_compares_by_identity(self): + class Plain(object): + pass + + class CustomEq(object): + def __eq__(self, other): + return True + + class CustomCmp (object): + def __cmp__(self, other): + return 0 + + class CustomHash(object): + def __hash__(self): + return 0 + + assert self.compares_by_identity(Plain) + assert not self.compares_by_identity(CustomEq) + assert not self.compares_by_identity(CustomCmp) + assert not self.compares_by_identity(CustomHash) + + def test_modify_class(self): + class X(object): + pass + + assert self.compares_by_identity(X) + X.__eq__ = lambda x: None + assert not self.compares_by_identity(X) + del X.__eq__ + assert self.compares_by_identity(X) + + +class AppTestIdentityDict(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_uses_identity_strategy(self, obj): + import __pypy__ + return "IdentityDictStrategy" in __pypy__.internal_repr(obj) + + def test_use_strategy(self): + class X(object): + pass + d = {} + x = X() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[x] == 1 + + def test_bad_item(self): + class X(object): + pass + class Y(object): + def __hash__(self): + return 32 + + d = {} + x = X() + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + d[y] = 2 + assert not self.uses_identity_strategy(d) + assert d[x] == 1 + assert d[y] == 2 + + def test_bad_key(self): + class X(object): + pass + d = {} + x = X() + + class Y(object): + def __hash__(self): + return hash(x) # to make sure we do x == y + + def __eq__(self, other): + return True + + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[y] == 1 + assert not self.uses_identity_strategy(d) + + def test_iter(self): + class X(object): + pass + x = X() + d = {x: 1} + assert self.uses_identity_strategy(d) + assert list(iter(d)) == [x] + + def test_mutate_class_and_then_compare(self): + class X(object): + pass + class Y(object): + pass + + x = X() + y = Y() + d1 = {x: 1} + d2 = {y: 1} + assert self.uses_identity_strategy(d1) + assert self.uses_identity_strategy(d2) + # + X.__hash__ = lambda self: hash(y) + X.__eq__ = lambda self, other: True + # + assert d1 == d2 + assert self.uses_identity_strategy(d1) + assert not self.uses_identity_strategy(d2) + + def test_old_style_classes(self): + class X: + pass + d = {X(): 1} + assert not self.uses_identity_strategy(d) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -7,6 +7,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member from pypy.objspace.std.objecttype import object_typedef +from pypy.objspace.std import identitydict from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash from pypy.rlib.jit import promote, elidable_promote, we_are_jitted @@ -76,6 +77,10 @@ for i in range(len(self.lookup_where)): self.lookup_where[i] = None_None +# possible values of compares_by_identity_status +UNKNOWN = 0 +COMPARES_BY_IDENTITY = 1 +OVERRIDES_EQ_CMP_OR_HASH = 2 class W_TypeObject(W_Object): from pypy.objspace.std.typetype import type_typedef as typedef @@ -102,6 +107,9 @@ # (False is a conservative default, fixed during real usage) uses_object_getattribute = False + # for config.objspace.std.withidentitydict + compares_by_identity_status = UNKNOWN + # used to cache the type __new__ function if it comes from a builtin type # != 'type', in that case call__Type will also assumes the result # of the __new__ is an instance of the type @@ -146,11 +154,17 @@ else: w_self.terminator = NoDictTerminator(space, w_self) - def mutated(w_self): + def mutated(w_self, key): + """ + The type is being mutated. key is either the string containing the + specific attribute which is being deleted/set or None to indicate a + generic mutation. + """ space = w_self.space assert w_self.is_heaptype() or space.config.objspace.std.mutable_builtintypes if (not space.config.objspace.std.withtypeversion and not space.config.objspace.std.getattributeshortcut and + not space.config.objspace.std.withidentitydict and not space.config.objspace.std.newshortcut): return @@ -158,6 +172,13 @@ w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage + if space.config.objspace.std.withidentitydict: + did_compare_by_identity = ( + w_self.compares_by_identity_status == COMPARES_BY_IDENTITY) + if (key is None or key == '__eq__' or + key == '__cmp__' or key == '__hash__'): + w_self.compares_by_identity_status = UNKNOWN + if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None @@ -168,7 +189,7 @@ subclasses_w = w_self.get_subclasses() for w_subclass in subclasses_w: assert isinstance(w_subclass, W_TypeObject) - w_subclass.mutated() + w_subclass.mutated(key) def version_tag(w_self): if (not we_are_jitted() or w_self.is_heaptype() or @@ -207,6 +228,25 @@ def has_object_getattribute(w_self): return w_self.getattribute_if_not_from_object() is None + def compares_by_identity(w_self): + from pypy.objspace.descroperation import object_hash + if not w_self.space.config.objspace.std.withidentitydict: + return False # conservative + # + if w_self.compares_by_identity_status != UNKNOWN: + # fast path + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + # + default_hash = object_hash(w_self.space) + overrides_eq_cmp_or_hash = (w_self.lookup('__eq__') or + w_self.lookup('__cmp__') or + w_self.lookup('__hash__') is not default_hash) + if overrides_eq_cmp_or_hash: + w_self.compares_by_identity_status = OVERRIDES_EQ_CMP_OR_HASH + else: + w_self.compares_by_identity_status = COMPARES_BY_IDENTITY + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + def ready(w_self): for w_base in w_self.bases_w: if not isinstance(w_base, W_TypeObject): @@ -269,7 +309,7 @@ w_curr.w_value = w_value return True w_value = TypeCell(w_value) - w_self.mutated() + w_self.mutated(name) w_self.dict_w[name] = w_value return True @@ -286,7 +326,7 @@ except KeyError: return False else: - w_self.mutated() + w_self.mutated(key) return True def lookup(w_self, name): diff --git a/pypy/objspace/std/typetype.py b/pypy/objspace/std/typetype.py --- a/pypy/objspace/std/typetype.py +++ b/pypy/objspace/std/typetype.py @@ -141,7 +141,7 @@ w_oldbestbase.getname(space)) # invalidate the version_tag of all the current subclasses - w_type.mutated() + w_type.mutated(None) # now we can go ahead and change 'w_type.bases_w' saved_bases_w = w_type.bases_w From noreply at buildbot.pypy.org Thu Jul 21 15:15:49 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 15:15:49 +0200 (CEST) Subject: [pypy-commit] pypy default: write doc for this option Message-ID: <20110721131549.57A0C829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45818:5f668bf0e242 Date: 2011-07-21 15:15 +0200 http://bitbucket.org/pypy/pypy/changeset/5f668bf0e242/ Log: write doc for this option diff --git a/pypy/doc/config/translation.dont_write_c_files.txt b/pypy/doc/config/translation.dont_write_c_files.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/translation.dont_write_c_files.txt @@ -0,0 +1,4 @@ +write the generated C files to ``/dev/null`` instead of to the disk. Useful if +you want to use translate.py as a benchmark and don't want to access the disk. + +.. _`translation documentation`: ../translation.html From noreply at buildbot.pypy.org Thu Jul 21 15:57:37 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 15:57:37 +0200 (CEST) Subject: [pypy-commit] pypy default: remove code duplication and fix the translation hopefully Message-ID: <20110721135737.EC0BF829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45819:aa1f3c5c459c Date: 2011-07-21 15:57 +0200 http://bitbucket.org/pypy/pypy/changeset/aa1f3c5c459c/ Log: remove code duplication and fix the translation hopefully diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -25,8 +25,8 @@ reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) -slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) -slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'self', 'arr']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) def pos(v): return v @@ -268,6 +268,26 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) + def _sliceloop1(self, start, stop, step, arr, storage): + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=arr.signature, + step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + storage[i] = arr.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, arr, storage): + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=arr.signature, + step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + storage[i] = arr.eval(j) + j += 1 + i += step + def convert_to_array (space, w_obj): if isinstance(w_obj, BaseArray): return w_obj @@ -442,28 +462,6 @@ def find_size(self): return self.size - def _sliceloop1(self, start, stop, step, arr): - storage = self.parent.storage - i = start - j = 0 - while i < stop: - slice_driver1.jit_merge_point(signature=arr.signature, self=self, - step=step, stop=stop, i=i, j=j, arr=arr) - storage[i] = arr.eval(j) - j += 1 - i += step - - def _sliceloop2(self, start, stop, step, arr): - storage = self.parent.storage - i = start - j = 0 - while i > stop: - slice_driver2.jit_merge_point(signature=arr.signature, self=self, - step=step, stop=stop, i=i, j=j, arr=arr) - storage[i] = arr.eval(j) - j += 1 - i += step - def setslice(self, space, start, stop, step, slice_length, arr): arr = convert_to_array(space, arr) start = self.calc_index(start) @@ -471,9 +469,9 @@ stop = self.calc_index(stop) step = self.step * step if step > 0: - self._sliceloop1(start, stop, step, arr) + self._sliceloop1(start, stop, step, arr, self.parent.storage) else: - self._sliceloop2(start, stop, step, arr) + self._sliceloop2(start, stop, step, arr, self.parent.storage) def calc_index(self, item): return (self.start + item * self.step) @@ -508,33 +506,13 @@ self.invalidated() self.storage[item] = value - def _sliceloop1(self, start, stop, step, arr): - i = start - j = 0 - while i < stop: - slice_driver1.jit_merge_point(signature=arr.signature, self=self, - step=step, stop=stop, i=i, j=j, arr=arr) - self.storage[i] = arr.eval(j) - j += 1 - i += step - - def _sliceloop2(self, start, stop, step, arr): - i = start - j = 0 - while i > stop: - slice_driver2.jit_merge_point(signature=arr.signature, self=self, - step=step, stop=stop, i=i, j=j, arr=arr) - self.storage[i] = arr.eval(j) - j += 1 - i += step - def setslice(self, space, start, stop, step, slice_length, arr): if not isinstance(arr, BaseArray): arr = convert_to_array(space, arr) if step > 0: - self._sliceloop1(start, stop, step, arr) + self._sliceloop1(start, stop, step, arr, self.storage) else: - self._sliceloop2(start, stop, step, arr) + self._sliceloop2(start, stop, step, arr, self.storage) def __del__(self): lltype.free(self.storage, flavor='raw') From noreply at buildbot.pypy.org Thu Jul 21 16:12:30 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 16:12:30 +0200 (CEST) Subject: [pypy-commit] pypy default: translation fix Message-ID: <20110721141230.CFC2D829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45820:abaf35bf5217 Date: 2011-07-21 16:11 +0200 http://bitbucket.org/pypy/pypy/changeset/abaf35bf5217/ Log: translation fix diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -86,7 +86,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated(None) + self.unerase(w_dict.dstorage).mutated() class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): From noreply at buildbot.pypy.org Thu Jul 21 16:12:32 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 16:12:32 +0200 (CEST) Subject: [pypy-commit] pypy default: this field is now quasi-immutable Message-ID: <20110721141232.06432829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45821:3e31e1098d65 Date: 2011-07-21 16:12 +0200 http://bitbucket.org/pypy/pypy/changeset/3e31e1098d65/ Log: this field is now quasi-immutable diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -30,7 +30,6 @@ assert res == 8.0 * 300 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('fficall', """ - p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>) guard_not_invalidated(descr=...) i17 = force_token() setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>) From noreply at buildbot.pypy.org Thu Jul 21 16:18:13 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 21 Jul 2011 16:18:13 +0200 (CEST) Subject: [pypy-commit] pypy custom-trace: A branch in which to implement custom "tracers" for the GC. Message-ID: <20110721141813.1A1CD829B8@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: custom-trace Changeset: r45822:6e4633e7cfeb Date: 2011-07-21 15:56 +0200 http://bitbucket.org/pypy/pypy/changeset/6e4633e7cfeb/ Log: A branch in which to implement custom "tracers" for the GC. The goal is to let some special object types have a custom trace() function. From noreply at buildbot.pypy.org Thu Jul 21 16:18:14 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 21 Jul 2011 16:18:14 +0200 (CEST) Subject: [pypy-commit] pypy default: Easter-egg-like implementation of __pypy__.do_what_I_mean(). Message-ID: <20110721141814.43B9D829B8@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45823:96b67e33eb50 Date: 2011-07-21 16:18 +0200 http://bitbucket.org/pypy/pypy/changeset/96b67e33eb50/ Log: Easter-egg-like implementation of __pypy__.do_what_I_mean(). diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -25,6 +25,7 @@ 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', 'lookup_special' : 'interp_magic.lookup_special', + 'do_what_I_mean' : 'interp_magic.do_what_I_mean', } submodules = { diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -70,3 +70,6 @@ if w_descr is None: return space.w_None return space.get(w_descr, w_obj) + +def do_what_I_mean(space): + return space.wrap(42) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -49,3 +49,8 @@ class X: pass raises(TypeError, lookup_special, X(), "foo") + + def test_do_what_I_mean(self): + from __pypy__ import do_what_I_mean + x = do_what_I_mean() + assert x == 42 From noreply at buildbot.pypy.org Thu Jul 21 16:49:42 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 16:49:42 +0200 (CEST) Subject: [pypy-commit] pypy range-immutable: kill the silly speedups - sort and reverse force the list. Message-ID: <20110721144942.53A3C829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: range-immutable Changeset: r45824:d1de6e6a2438 Date: 2011-07-21 16:46 +0200 http://bitbucket.org/pypy/pypy/changeset/d1de6e6a2438/ Log: kill the silly speedups - sort and reverse force the list. diff --git a/pypy/objspace/std/rangeobject.py b/pypy/objspace/std/rangeobject.py --- a/pypy/objspace/std/rangeobject.py +++ b/pypy/objspace/std/rangeobject.py @@ -161,29 +161,6 @@ space.wrap("pop index out of range")) raise FailedToImplement -def list_reverse__RangeList(space, w_rangelist): - # probably somewhat useless, but well... - if w_rangelist.w_list is not None: - raise FailedToImplement - w_rangelist.start = w_rangelist.getitem_unchecked(w_rangelist.length-1) - w_rangelist.step = -w_rangelist.step - -def list_sort__RangeList_None_None_ANY(space, w_rangelist, w_cmp, - w_keyfunc, w_reverse): - # even more useless but fun - has_reverse = space.is_true(w_reverse) - if w_rangelist.w_list is not None: - raise FailedToImplement - if has_reverse: - factor = -1 - else: - factor = 1 - reverse = w_rangelist.step * factor < 0 - if reverse: - w_rangelist.start = w_rangelist.getitem_unchecked(w_rangelist.length-1) - w_rangelist.step = -w_rangelist.step - return space.w_None - class W_RangeIterObject(iterobject.W_AbstractSeqIterObject): pass diff --git a/pypy/objspace/std/test/test_rangeobject.py b/pypy/objspace/std/test/test_rangeobject.py --- a/pypy/objspace/std/test/test_rangeobject.py +++ b/pypy/objspace/std/test/test_rangeobject.py @@ -16,7 +16,6 @@ "W_ListObject" not in __pypy__.internal_repr(r)) return f """) - cls.w_SORT_FORCES_LISTS = cls.space.wrap(False) def test_simple(self): result = [] @@ -44,12 +43,10 @@ def test_empty_range(self): r = range(10, 10) - if not self.SORT_FORCES_LISTS: r.sort(reverse=True) assert len(r) == 0 assert list(reversed(r)) == [] assert r[:] == [] - assert self.not_forced(r) def test_repr(self): r = range(5) @@ -65,7 +62,6 @@ def test_reverse(self): r = range(10) r.reverse() - assert self.not_forced(r) assert r == range(9, -1, -1) r = range(3) r[0] = 1 @@ -74,19 +70,14 @@ assert r == [2, 1, 1] def test_sort(self): - if self.SORT_FORCES_LISTS: - skip("sort() forces these lists") r = range(10, -1, -1) r.sort() - assert self.not_forced(r) assert r == range(11) r = range(11) r.sort(reverse=True) - assert self.not_forced(r) assert r == range(10, -1, -1) r = range(100) r[0] = 999 - assert not self.not_forced(r) r.sort() assert r == range(1, 100) + [999] From noreply at buildbot.pypy.org Thu Jul 21 16:49:43 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 16:49:43 +0200 (CEST) Subject: [pypy-commit] pypy range-immutable: kill some dead code and make fields immutable Message-ID: <20110721144943.7EC05829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: range-immutable Changeset: r45825:143aa349dc6d Date: 2011-07-21 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/143aa349dc6d/ Log: kill some dead code and make fields immutable diff --git a/pypy/objspace/std/rangeobject.py b/pypy/objspace/std/rangeobject.py --- a/pypy/objspace/std/rangeobject.py +++ b/pypy/objspace/std/rangeobject.py @@ -24,6 +24,8 @@ class W_RangeListObject(W_Object): typedef = listtype.list_typedef + _immutable_fields_ = ['start', 'step', 'length'] + def __init__(w_self, start, step, length): assert step != 0 w_self.start = start @@ -193,16 +195,6 @@ w_rangeiter.index = index + 1 return w_item -# XXX __length_hint__() -##def len__RangeIter(space, w_rangeiter): -## if w_rangeiter.w_seq is None: -## return wrapint(space, 0) -## index = w_rangeiter.index -## w_length = space.len(w_rangeiter.w_seq) -## w_len = space.sub(w_length, wrapint(space, index)) -## if space.is_true(space.lt(w_len, wrapint(space, 0))): -## w_len = wrapint(space, 0) -## return w_len registerimplementation(W_RangeListObject) registerimplementation(W_RangeIterObject) From noreply at buildbot.pypy.org Thu Jul 21 17:02:00 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 17:02:00 +0200 (CEST) Subject: [pypy-commit] pypy default: bah, I don't know why I did it, but the fix in abaf35bf5217 actually breaks things. Revert Message-ID: <20110721150200.D7D09829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45826:ebd8af15b4e6 Date: 2011-07-21 17:00 +0200 http://bitbucket.org/pypy/pypy/changeset/ebd8af15b4e6/ Log: bah, I don't know why I did it, but the fix in abaf35bf5217 actually breaks things. Revert diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -86,7 +86,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated() + self.unerase(w_dict.dstorage).mutated(None) class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): From noreply at buildbot.pypy.org Thu Jul 21 17:48:40 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 17:48:40 +0200 (CEST) Subject: [pypy-commit] pypy range-immutable: merge default Message-ID: <20110721154840.CB5C0829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: range-immutable Changeset: r45827:3e3564841c5c Date: 2011-07-21 16:58 +0200 http://bitbucket.org/pypy/pypy/changeset/3e3564841c5c/ Log: merge default diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -25,6 +25,7 @@ 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', 'lookup_special' : 'interp_magic.lookup_special', + 'do_what_I_mean' : 'interp_magic.do_what_I_mean', } submodules = { diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -70,3 +70,6 @@ if w_descr is None: return space.w_None return space.get(w_descr, w_obj) + +def do_what_I_mean(space): + return space.wrap(42) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -49,3 +49,8 @@ class X: pass raises(TypeError, lookup_special, X(), "foo") + + def test_do_what_I_mean(self): + from __pypy__ import do_what_I_mean + x = do_what_I_mean() + assert x == 42 From noreply at buildbot.pypy.org Thu Jul 21 17:48:42 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 17:48:42 +0200 (CEST) Subject: [pypy-commit] pypy range-immutable: merge default again Message-ID: <20110721154842.02980829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: range-immutable Changeset: r45828:b93130fd5be1 Date: 2011-07-21 17:06 +0200 http://bitbucket.org/pypy/pypy/changeset/b93130fd5be1/ Log: merge default again diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -86,7 +86,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated() + self.unerase(w_dict.dstorage).mutated(None) class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): From noreply at buildbot.pypy.org Thu Jul 21 17:48:43 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 17:48:43 +0200 (CEST) Subject: [pypy-commit] pypy default: Disable those jitdrivers for now - they break translation Message-ID: <20110721154843.33E48829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45829:558c3a321a43 Date: 2011-07-21 17:48 +0200 http://bitbucket.org/pypy/pypy/changeset/558c3a321a43/ Log: Disable those jitdrivers for now - they break translation diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -272,8 +272,8 @@ i = start j = 0 while i < stop: - slice_driver1.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + #slice_driver1.jit_merge_point(signature=arr.signature, + # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step @@ -282,8 +282,8 @@ i = start j = 0 while i > stop: - slice_driver2.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + #slice_driver2.jit_merge_point(signature=arr.signature, + # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step From noreply at buildbot.pypy.org Thu Jul 21 17:49:57 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 17:49:57 +0200 (CEST) Subject: [pypy-commit] pypy default: add a failing test Message-ID: <20110721154957.7F2A9829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45830:f653dfeacbc6 Date: 2011-07-21 17:49 +0200 http://bitbucket.org/pypy/pypy/changeset/f653dfeacbc6/ Log: add a failing test diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2586,7 +2586,23 @@ return n res = self.meta_interp(f, [10, 1]) self.check_loops(getfield_gc=2) + assert res == f(10, 1) + def test_jit_merge_point_with_raw_pointer(self): + driver = JitDriver(greens = [], reds = ['n', 'x']) + + TP = lltype.Array(lltype.Signed) + + def f(n): + x = lltype.malloc(TP, 10, flavor='raw') + x[0] = 1 + while n > 0: + driver.jit_merge_point(n=n, x=x) + n -= x[0] + lltype.free(x, flavor='raw') + return n + + self.meta_interp(f, [10], repeat=3) class TestLLtype(BaseLLtypeTests, LLJitMixin): pass From noreply at buildbot.pypy.org Thu Jul 21 18:14:54 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 18:14:54 +0200 (CEST) Subject: [pypy-commit] pypy default: fix the test Message-ID: <20110721161454.913AC829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45831:531879ba26f2 Date: 2011-07-21 18:14 +0200 http://bitbucket.org/pypy/pypy/changeset/531879ba26f2/ Log: fix the test diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2591,7 +2591,7 @@ def test_jit_merge_point_with_raw_pointer(self): driver = JitDriver(greens = [], reds = ['n', 'x']) - TP = lltype.Array(lltype.Signed) + TP = lltype.Array(lltype.Signed, hints={'nolength': True}) def f(n): x = lltype.malloc(TP, 10, flavor='raw') diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -138,6 +138,9 @@ refvalue = cpu.ts.cast_to_ref(value) cpu.set_future_value_ref(j, refvalue) elif typecode == 'int': + if isinstance(lltype.typeOf(value), lltype.Ptr): + intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value)) + else: intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) elif typecode == 'float': From noreply at buildbot.pypy.org Thu Jul 21 18:17:05 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 18:17:05 +0200 (CEST) Subject: [pypy-commit] pypy range-immutable: merge default again x2 Message-ID: <20110721161705.5C8BB829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: range-immutable Changeset: r45832:a17d21b7ede9 Date: 2011-07-21 18:15 +0200 http://bitbucket.org/pypy/pypy/changeset/a17d21b7ede9/ Log: merge default again x2 diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2586,7 +2586,23 @@ return n res = self.meta_interp(f, [10, 1]) self.check_loops(getfield_gc=2) + assert res == f(10, 1) + def test_jit_merge_point_with_raw_pointer(self): + driver = JitDriver(greens = [], reds = ['n', 'x']) + + TP = lltype.Array(lltype.Signed, hints={'nolength': True}) + + def f(n): + x = lltype.malloc(TP, 10, flavor='raw') + x[0] = 1 + while n > 0: + driver.jit_merge_point(n=n, x=x) + n -= x[0] + lltype.free(x, flavor='raw') + return n + + self.meta_interp(f, [10], repeat=3) class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -138,6 +138,9 @@ refvalue = cpu.ts.cast_to_ref(value) cpu.set_future_value_ref(j, refvalue) elif typecode == 'int': + if isinstance(lltype.typeOf(value), lltype.Ptr): + intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value)) + else: intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) elif typecode == 'float': diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -272,8 +272,8 @@ i = start j = 0 while i < stop: - slice_driver1.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + #slice_driver1.jit_merge_point(signature=arr.signature, + # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step @@ -282,8 +282,8 @@ i = start j = 0 while i > stop: - slice_driver2.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + #slice_driver2.jit_merge_point(signature=arr.signature, + # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step From noreply at buildbot.pypy.org Thu Jul 21 18:56:33 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 21 Jul 2011 18:56:33 +0200 (CEST) Subject: [pypy-commit] pypy default: fix tests to consistenty use array descrs Message-ID: <20110721165633.C3F9A829B8@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r45833:2ead4778c7ac Date: 2011-07-21 18:56 +0200 http://bitbucket.org/pypy/pypy/changeset/2ead4778c7ac/ Log: fix tests to consistenty use array descrs diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2820,11 +2820,11 @@ def test_residual_call_invalidate_some_arrays(self): ops = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) - p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p2, 0, descr=arraydescr2) p6 = getarrayitem_gc(p2, 1, descr=arraydescr2) i4 = getarrayitem_gc(p1, 1, descr=arraydescr) escape(p3) @@ -2837,7 +2837,7 @@ """ expected = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) From noreply at buildbot.pypy.org Thu Jul 21 19:20:45 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 21 Jul 2011 19:20:45 +0200 (CEST) Subject: [pypy-commit] pypy default: numpy: changed numarray unary functions to use ufuncs Message-ID: <20110721172045.6C137829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45834:136146a41b4a Date: 2011-07-21 11:18 -0600 http://bitbucket.org/pypy/pypy/changeset/136146a41b4a/ Log: numpy: changed numarray unary functions to use ufuncs diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -28,12 +28,6 @@ slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) -def pos(v): - return v -def neg(v): - return -v -def absolute(v): - return abs(v) def add(v1, v2): return v1 + v2 def mul(v1, v2): @@ -59,21 +53,14 @@ arr.force_if_needed() del self.invalidates[:] - def _unop_impl(function): - signature = Signature() + def _unaryop_impl(w_ufunc): def impl(self, space): - new_sig = self.signature.transition(signature) - res = Call1( - function, - self, - new_sig) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + return w_ufunc(space, self) + return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__) - descr_pos = _unop_impl(pos) - descr_neg = _unop_impl(neg) - descr_abs = _unop_impl(absolute) + descr_pos = _unaryop_impl(interp_ufuncs.positive) + descr_neg = _unaryop_impl(interp_ufuncs.negative) + descr_abs = _unaryop_impl(interp_ufuncs.absolute) def _binop_impl(w_ufunc): def impl(self, space, w_other): diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -72,6 +72,11 @@ def multiply(lvalue, rvalue): return lvalue * rvalue +# Used by numarray for __pos__. Not visible from numpy application space. + at ufunc +def positive(value): + return value + @ufunc def negative(value): return -value @@ -114,4 +119,4 @@ @ufunc2 def mod(lvalue, rvalue): - return math.fmod(lvalue, rvalue) \ No newline at end of file + return math.fmod(lvalue, rvalue) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) + FloatWrapper, Call2, SingleDimSlice, add, mul, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize @@ -48,19 +48,6 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_neg(self): - def f(i): - ar = SingleDimArray(i) - v = Call1(neg, ar, Signature()) - return v.get_concrete().storage[3] - - result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, - "setarrayitem_raw": 1, "int_add": 1, - "int_lt": 1, "guard_true": 1, "jump": 1}) - - assert result == f(5) - def test_sum(self): space = self.space From noreply at buildbot.pypy.org Thu Jul 21 19:20:46 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 21 Jul 2011 19:20:46 +0200 (CEST) Subject: [pypy-commit] pypy default: merged unary functs Message-ID: <20110721172046.996F6829BA@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45835:9b3ddfcb4c38 Date: 2011-07-21 11:20 -0600 http://bitbucket.org/pypy/pypy/changeset/9b3ddfcb4c38/ Log: merged unary functs diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -28,12 +28,6 @@ slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) -def pos(v): - return v -def neg(v): - return -v -def absolute(v): - return abs(v) def add(v1, v2): return v1 + v2 def mul(v1, v2): @@ -59,21 +53,14 @@ arr.force_if_needed() del self.invalidates[:] - def _unop_impl(function): - signature = Signature() + def _unaryop_impl(w_ufunc): def impl(self, space): - new_sig = self.signature.transition(signature) - res = Call1( - function, - self, - new_sig) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + return w_ufunc(space, self) + return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__) - descr_pos = _unop_impl(pos) - descr_neg = _unop_impl(neg) - descr_abs = _unop_impl(absolute) + descr_pos = _unaryop_impl(interp_ufuncs.positive) + descr_neg = _unaryop_impl(interp_ufuncs.negative) + descr_abs = _unaryop_impl(interp_ufuncs.absolute) def _binop_impl(w_ufunc): def impl(self, space, w_other): diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -72,6 +72,11 @@ def multiply(lvalue, rvalue): return lvalue * rvalue +# Used by numarray for __pos__. Not visible from numpy application space. + at ufunc +def positive(value): + return value + @ufunc def negative(value): return -value @@ -114,4 +119,4 @@ @ufunc2 def mod(lvalue, rvalue): - return math.fmod(lvalue, rvalue) \ No newline at end of file + return math.fmod(lvalue, rvalue) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) + FloatWrapper, Call2, SingleDimSlice, add, mul, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize @@ -48,19 +48,6 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_neg(self): - def f(i): - ar = SingleDimArray(i) - v = Call1(neg, ar, Signature()) - return v.get_concrete().storage[3] - - result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, - "setarrayitem_raw": 1, "int_add": 1, - "int_lt": 1, "guard_true": 1, "jump": 1}) - - assert result == f(5) - def test_sum(self): space = self.space From noreply at buildbot.pypy.org Thu Jul 21 19:22:27 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 19:22:27 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: done Message-ID: <20110721172227.C2CD7829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3837:886df227da76 Date: 2011-07-21 19:22 +0200 http://bitbucket.org/pypy/extradoc/changeset/886df227da76/ Log: done diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -8,11 +8,6 @@ [arigo] - cpython has sys._current_frames(), but not pypy; however relying on this looks like it's not the job of the jit -* we should run nightly 64bit benchmarks. As of mid-April, richards - was noticably (30-50%) slower on 64bit than 32bit. I didn't notice - other benchmarks, but since we don't run it, we don't have a way - to compare. - NEW TASKS --------- From noreply at buildbot.pypy.org Thu Jul 21 19:40:08 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 21 Jul 2011 19:40:08 +0200 (CEST) Subject: [pypy-commit] pypy default: Re-enable set slice drivers for numarrays for that the zjit tests succeed. Message-ID: <20110721174008.054BF829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45836:acad170d7ecf Date: 2011-07-21 11:39 -0600 http://bitbucket.org/pypy/pypy/changeset/acad170d7ecf/ Log: Re-enable set slice drivers for numarrays for that the zjit tests succeed. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -259,8 +259,8 @@ i = start j = 0 while i < stop: - #slice_driver1.jit_merge_point(signature=arr.signature, - # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + slice_driver1.jit_merge_point(signature=arr.signature, + step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step @@ -269,8 +269,8 @@ i = start j = 0 while i > stop: - #slice_driver2.jit_merge_point(signature=arr.signature, - # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + slice_driver2.jit_merge_point(signature=arr.signature, + step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step From noreply at buildbot.pypy.org Thu Jul 21 20:55:41 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Thu, 21 Jul 2011 20:55:41 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: produce guards before forcing virtuals as one force might lead to another Message-ID: <20110721185541.C87CB829B8@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45837:3c2afbf75c4a Date: 2011-07-21 20:37 +0200 http://bitbucket.org/pypy/pypy/changeset/3c2afbf75c4a/ Log: produce guards before forcing virtuals as one force might lead to another diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6579,6 +6579,20 @@ """ self.optimize_loop(ops, expected) + def test_chained_virtuals(self): + ops = """ + [p0, p1] + p2 = new_with_vtable(ConstClass(node_vtable)) + p3 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p2, p3, descr=nextdescr) + jump(p2, p3) + """ + expected = """ + [] + jump() + """ + self.optimize_loop(ops, expected) + def test_arraylen_bound(self): ops = """ [p1, i] diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -217,15 +217,18 @@ inputarg_setup_ops = [] preamble_optimizer.newoperations = [] seen = {} + for box in inputargs: + if box in seen: + continue + seen[box] = True + value = preamble_optimizer.getvalue(box) + inputarg_setup_ops.extend(value.make_guards(box)) for box in short_inputargs: if box in seen: continue seen[box] = True value = preamble_optimizer.getvalue(box) - if value.is_virtual(): value.force_box() - else: - inputarg_setup_ops.extend(value.make_guards(box)) preamble_optimizer.flush() inputarg_setup_ops += preamble_optimizer.newoperations From noreply at buildbot.pypy.org Thu Jul 21 20:55:43 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Thu, 21 Jul 2011 20:55:43 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: fix test Message-ID: <20110721185543.0BD1F829B8@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45838:5b76193812ac Date: 2011-07-21 20:43 +0200 http://bitbucket.org/pypy/pypy/changeset/5b76193812ac/ Log: fix test diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5139,8 +5139,8 @@ ops = """ [p0, p1, p2, p3, i4, p5, i6, p7, p8, p9, p14] guard_value(i4, 3) [] - guard_class(p9, 17278984) [] - guard_class(p9, 17278984) [] + guard_class(p9, ConstClass(node_vtable)) [] + guard_class(p9, ConstClass(node_vtable)) [] p22 = getfield_gc(p9, descr=inst_w_seq) guard_nonnull(p22) [] i23 = getfield_gc(p9, descr=inst_index) @@ -5155,11 +5155,11 @@ guard_class(p14, 17273920) [] guard_class(p14, 17273920) [] - p75 = new_with_vtable(17278984) + p75 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p75, p14, descr=inst_w_seq) setfield_gc(p75, 0, descr=inst_index) - guard_class(p75, 17278984) [] - guard_class(p75, 17278984) [] + guard_class(p75, ConstClass(node_vtable)) [] + guard_class(p75, ConstClass(node_vtable)) [] p79 = getfield_gc(p75, descr=inst_w_seq) guard_nonnull(p79) [] i80 = getfield_gc(p75, descr=inst_index) From noreply at buildbot.pypy.org Thu Jul 21 20:55:44 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Thu, 21 Jul 2011 20:55:44 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: variable index strgetitem nolong cached across loop boundaries Message-ID: <20110721185544.42471829B8@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45839:aad66f8cf6be Date: 2011-07-21 20:46 +0200 http://bitbucket.org/pypy/pypy/changeset/aad66f8cf6be/ Log: variable index strgetitem nolong cached across loop boundaries diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5610,6 +5610,7 @@ ops = """ [p0, i0] i1 = strgetitem(p0, i0) + i10 = strgetitem(p0, i0) i2 = int_lt(i1, 256) guard_true(i2) [] i3 = int_ge(i1, 0) @@ -5618,6 +5619,7 @@ """ expected = """ [p0, i0] + i1 = strgetitem(p0, i0) jump(p0, i0) """ self.optimize_loop(ops, expected) From noreply at buildbot.pypy.org Thu Jul 21 20:55:45 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Thu, 21 Jul 2011 20:55:45 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: variable index unicodegetitem nolong cached across loop boundaries Message-ID: <20110721185545.79AE7829B8@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45840:1bf3cbdade3a Date: 2011-07-21 20:46 +0200 http://bitbucket.org/pypy/pypy/changeset/1bf3cbdade3a/ Log: variable index unicodegetitem nolong cached across loop boundaries diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5628,12 +5628,14 @@ ops = """ [p0, i0] i1 = unicodegetitem(p0, i0) + i10 = unicodegetitem(p0, i0) i2 = int_lt(i1, 0) guard_false(i2) [] jump(p0, i0) """ expected = """ [p0, i0] + i1 = unicodegetitem(p0, i0) jump(p0, i0) """ self.optimize_loop(ops, expected) From noreply at buildbot.pypy.org Thu Jul 21 20:55:46 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Thu, 21 Jul 2011 20:55:46 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: fixed test Message-ID: <20110721185546.AF41E829B8@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45841:74ad7bd66501 Date: 2011-07-21 20:55 +0200 http://bitbucket.org/pypy/pypy/changeset/74ad7bd66501/ Log: fixed test diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -6653,8 +6653,8 @@ ops = """ [p0] p1 = getfield_gc(p0, descr=nextdescr) - p2 = strgetitem(p1, 7) - call(p2, descr=nonwritedescr) + i22 = strgetitem(p1, 7) + call(i22, descr=nonwritedescr) jump(p0) """ short = """ @@ -6664,17 +6664,17 @@ i1 = strlen(p1) i2 = int_ge(i1, 8) guard_true(i2) [] - p2 = strgetitem(p1, 7, descr=) - i8 = int_ge(p2, 0) + i22 = strgetitem(p1, 7, descr=) + i8 = int_ge(i22, 0) guard_true(i8) [] - i9 = int_le(p2, 255) + i9 = int_le(i22, 255) guard_true(i9) [] - jump(p0, p2) - """ - expected = """ - [p0, p2] - call(p2, descr=nonwritedescr) - jump(p0, p2) + jump(p0, i22) + """ + expected = """ + [p0, i22] + call(i22, descr=nonwritedescr) + jump(p0, i22) """ self.optimize_loop(ops, expected, expected_short=short) @@ -6682,8 +6682,8 @@ ops = """ [p0] p1 = getfield_gc(p0, descr=nextdescr) - p2 = unicodegetitem(p1, 7) - call(p2, descr=nonwritedescr) + i22 = unicodegetitem(p1, 7) + call(i22, descr=nonwritedescr) jump(p0) """ short = """ @@ -6693,15 +6693,15 @@ i1 = unicodelen(p1) i2 = int_ge(i1, 8) guard_true(i2) [] - p2 = unicodegetitem(p1, 7, descr=) - i8 = int_ge(p2, 0) + i22 = unicodegetitem(p1, 7, descr=) + i8 = int_ge(i22, 0) guard_true(i8) [] - jump(p0, p2) - """ - expected = """ - [p0, p2] - call(p2, descr=nonwritedescr) - jump(p0, p2) + jump(p0, i22) + """ + expected = """ + [p0, i22] + call(i22, descr=nonwritedescr) + jump(p0, i22) """ self.optimize_loop(ops, expected, expected_short=short) From noreply at buildbot.pypy.org Thu Jul 21 21:13:41 2011 From: noreply at buildbot.pypy.org (ademan) Date: Thu, 21 Jul 2011 21:13:41 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Added test for oo{, un}box_integer. Currently fails. Message-ID: <20110721191341.E0C74829B8@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45842:3af86a0633cc Date: 2011-07-21 12:12 -0700 http://bitbucket.org/pypy/pypy/changeset/3af86a0633cc/ Log: Added test for oo{,un}box_integer. Currently fails. diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -585,6 +585,8 @@ 'classof': LLOp(oo=True, canfold=True), 'subclassof': LLOp(oo=True, canfold=True), 'oostring': LLOp(oo=True, sideeffects=False), + 'oobox_int': LLOp(oo=True, sideeffects=False), + 'oounbox_int': LLOp(oo=True, sideeffects=False), 'ooparse_int': LLOp(oo=True, canraise=(ValueError,)), 'ooparse_float': LLOp(oo=True, canraise=(ValueError,)), 'oounicode': LLOp(oo=True, canraise=(UnicodeDecodeError,)), diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py --- a/pypy/translator/oosupport/test_template/operations.py +++ b/pypy/translator/oosupport/test_template/operations.py @@ -1,3 +1,6 @@ +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype from pypy.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, ovfcheck from pypy.rlib import rstack from pypy.annotation import model as annmodel @@ -204,6 +207,13 @@ return bool(x) self._check_all(fn) + def test_box(self): + def f(): + x = 42 + y = llop.oobox_int(ootype.Object, x) + return llop.oounbox_int(lltype.Signed, y) + assert self.interpret(f, []) == 42 + def test_ullong_rshift(self): def f(x): return x >> 1 From noreply at buildbot.pypy.org Thu Jul 21 23:39:41 2011 From: noreply at buildbot.pypy.org (RonnyPfannschmidt) Date: Thu, 21 Jul 2011 23:39:41 +0200 (CEST) Subject: [pypy-commit] pypy default: inline the pytest coverage plugin, and autoload it in pypy/test_all.py Message-ID: <20110721213941.EB8B0829B8@wyvern.cs.uni-duesseldorf.de> Author: Ronny Pfannschmidt Branch: Changeset: r45843:b1ae5324c66b Date: 2011-07-21 23:37 +0200 http://bitbucket.org/pypy/pypy/changeset/b1ae5324c66b/ Log: inline the pytest coverage plugin, and autoload it in pypy/test_all.py diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -18,4 +18,5 @@ if __name__ == '__main__': import tool.autopath import pytest - sys.exit(pytest.main()) + import pytest_cov + sys.exit(pytest.main(plugins=[pytest_cov])) diff --git a/pytest_cov.py b/pytest_cov.py new file mode 100644 --- /dev/null +++ b/pytest_cov.py @@ -0,0 +1,351 @@ +"""produce code coverage reports using the 'coverage' package, including support for distributed testing. + +This plugin produces coverage reports. It supports centralised testing and distributed testing in +both load and each modes. It also supports coverage of subprocesses. + +All features offered by the coverage package should be available, either through pytest-cov or +through coverage's config file. + + +Installation +------------ + +The `pytest-cov`_ package may be installed with pip or easy_install:: + + pip install pytest-cov + easy_install pytest-cov + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov/ + + +Uninstallation +-------------- + +Uninstalling packages is supported by pip:: + + pip uninstall pytest-cov + +However easy_install does not provide an uninstall facility. + +.. IMPORTANT:: + + Ensure that you manually delete the init_cov_core.pth file in your site-packages directory. + + This file starts coverage collection of subprocesses if appropriate during site initialisation + at python startup. + + +Usage +----- + +Centralised Testing +~~~~~~~~~~~~~~~~~~~ + +Centralised testing will report on the combined coverage of the main process and all of it's +subprocesses. + +Running centralised testing:: + + py.test --cov myproj tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Load +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to load will report on the combined coverage of all slaves. +The slaves may be spread out over any number of hosts and each slave may be located anywhere on the +file system. Each slave will have it's subprocesses measured. + +Running distributed testing with dist mode set to load:: + + py.test --cov myproj -n 2 tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Again but spread over different hosts and different directories:: + + py.test --cov myproj --dist load + --tx ssh=memedough at host1//chdir=testenv1 + --tx ssh=memedough at host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Each +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to each will report on the combined coverage of all slaves. +Since each slave is running all tests this allows generating a combined coverage report for multiple +environments. + +Running distributed testing with dist mode set to each:: + + py.test --cov myproj --dist each + --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python + --tx ssh=memedough at host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + ---------------------------------------- coverage ---------------------------------------- + platform linux2, python 2.6.5-final-0 + platform linux2, python 2.7.0-final-0 + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Reporting +--------- + +It is possible to generate any combination of the reports for a single test run. + +The available reports are terminal (with or without missing line numbers shown), HTML, XML and +annotated source code. + +The terminal report without line numbers (default):: + + py.test --cov-report term --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +The terminal report with line numbers:: + + py.test --cov-report term-missing --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover Missing + -------------------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% 24-26, 99, 149, 233-236, 297-298, 369-370 + myproj/feature4286 94 7 92% 183-188, 197 + -------------------------------------------------- + TOTAL 353 20 94% + + +The remaining three reports output to files without showing anything on the terminal (useful for +when the output is going to a continuous integration server):: + + py.test --cov-report html + --cov-report xml + --cov-report annotate + --cov myproj tests/ + + +Coverage Data File +------------------ + +The data file is erased at the beginning of testing to ensure clean data for each test run. + +The data file is left at the end of testing so that it is possible to use normal coverage tools to +examine it. + + +Coverage Config File +-------------------- + +This plugin provides a clean minimal set of command line options that are added to pytest. For +further control of coverage use a coverage config file. + +For example if tests are contained within the directory tree being measured the tests may be +excluded if desired by using a .coveragerc file with the omit option set:: + + py.test --cov-config .coveragerc + --cov myproj + myproj/tests/ + +Where the .coveragerc file contains file globs:: + + [run] + omit = tests/* + +For full details refer to the `coverage config file`_ documentation. + +.. _`coverage config file`: http://nedbatchelder.com/code/coverage/config.html + +Note that this plugin controls some options and setting the option in the config file will have no +effect. These include specifying source to be measured (source option) and all data file handling +(data_file and parallel options). + + +Limitations +----------- + +For distributed testing the slaves must have the pytest-cov package installed. This is needed since +the plugin must be registered through setuptools / distribute for pytest to start the plugin on the +slave. + +For subprocess measurement environment variables must make it from the main process to the +subprocess. The python used by the subprocess must have pytest-cov installed. The subprocess must +do normal site initialisation so that the environment variables can be detected and coverage +started. + + +Acknowledgements +---------------- + +Whilst this plugin has been built fresh from the ground up it has been influenced by the work done +on pytest-coverage (Ross Lawley, James Mills, Holger Krekel) and nose-cover (Jason Pellerin) which are +other coverage plugins. + +Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs. + +Holger Krekel for pytest with its distributed testing support. + +Jason Pellerin for nose. + +Michael Foord for unittest2. + +No doubt others have contributed to these tools as well. +""" + + +def pytest_addoption(parser): + """Add options to control coverage.""" + + group = parser.getgroup('coverage reporting with distributed testing support') + group.addoption('--cov', action='append', default=[], metavar='path', + dest='cov_source', + help='measure coverage for filesystem path (multi-allowed)') + group.addoption('--cov-report', action='append', default=[], metavar='type', + choices=['term', 'term-missing', 'annotate', 'html', 'xml'], + dest='cov_report', + help='type of report to generate: term, term-missing, annotate, html, xml (multi-allowed)') + group.addoption('--cov-config', action='store', default='.coveragerc', metavar='path', + dest='cov_config', + help='config file for coverage, default: .coveragerc') + + +def pytest_configure(config): + """Activate coverage plugin if appropriate.""" + + if config.getvalue('cov_source'): + config.pluginmanager.register(CovPlugin(), '_cov') + + +class CovPlugin(object): + """Use coverage package to produce code coverage reports. + + Delegates all work to a particular implementation based on whether + this test process is centralised, a distributed master or a + distributed slave. + """ + + def __init__(self): + """Creates a coverage pytest plugin. + + We read the rc file that coverage uses to get the data file + name. This is needed since we give coverage through it's API + the data file name. + """ + + # Our implementation is unknown at this time. + self.cov_controller = None + + def pytest_sessionstart(self, session): + """At session start determine our implementation and delegate to it.""" + + import cov_core + + cov_source = session.config.getvalue('cov_source') + cov_report = session.config.getvalue('cov_report') or ['term'] + cov_config = session.config.getvalue('cov_config') + + session_name = session.__class__.__name__ + is_master = (session.config.pluginmanager.hasplugin('dsession') or + session_name == 'DSession') + is_slave = (hasattr(session.config, 'slaveinput') or + session_name == 'SlaveSession') + nodeid = None + + if is_master: + controller_cls = cov_core.DistMaster + elif is_slave: + controller_cls = cov_core.DistSlave + nodeid = session.config.slaveinput.get('slaveid', getattr(session, 'nodeid')) + else: + controller_cls = cov_core.Central + + self.cov_controller = controller_cls(cov_source, + cov_report, + cov_config, + session.config, + nodeid) + + self.cov_controller.start() + + def pytest_configure_node(self, node): + """Delegate to our implementation.""" + + self.cov_controller.configure_node(node) + + def pytest_testnodedown(self, node, error): + """Delegate to our implementation.""" + + self.cov_controller.testnodedown(node, error) + + def pytest_sessionfinish(self, session, exitstatus): + """Delegate to our implementation.""" + + self.cov_controller.finish() + + def pytest_terminal_summary(self, terminalreporter): + """Delegate to our implementation.""" + + self.cov_controller.summary(terminalreporter._tw) + + +def pytest_funcarg__cov(request): + """A pytest funcarg that provides access to the underlying coverage object.""" + + # Check with hasplugin to avoid getplugin exception in older pytest. + if request.config.pluginmanager.hasplugin('_cov'): + plugin = request.config.pluginmanager.getplugin('_cov') + if plugin.cov_controller: + return plugin.cov_controller.cov + return None From noreply at buildbot.pypy.org Thu Jul 21 23:46:26 2011 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 21 Jul 2011 23:46:26 +0200 (CEST) Subject: [pypy-commit] pypy default: disable those until we know it works Message-ID: <20110721214626.17ADB829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45844:cb95026e7622 Date: 2011-07-21 23:46 +0200 http://bitbucket.org/pypy/pypy/changeset/cb95026e7622/ Log: disable those until we know it works diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -259,8 +259,8 @@ i = start j = 0 while i < stop: - slice_driver1.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + #slice_driver1.jit_merge_point(signature=arr.signature, + # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step @@ -269,8 +269,8 @@ i = start j = 0 while i > stop: - slice_driver2.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + #slice_driver2.jit_merge_point(signature=arr.signature, + # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step From noreply at buildbot.pypy.org Thu Jul 21 23:55:16 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 21 Jul 2011 23:55:16 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: fix the signature of the oo{box, unbox}_int java methods Message-ID: <20110721215516.90FD0829B8@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: ootype-rerased Changeset: r45845:21953bca75cb Date: 2011-07-21 23:55 +0200 http://bitbucket.org/pypy/pypy/changeset/21953bca75cb/ Log: fix the signature of the oo{box,unbox}_int java methods diff --git a/pypy/translator/jvm/typesystem.py b/pypy/translator/jvm/typesystem.py --- a/pypy/translator/jvm/typesystem.py +++ b/pypy/translator/jvm/typesystem.py @@ -963,8 +963,8 @@ PYPYRUNTIMENEW = Method.s(jPyPy, 'RuntimeNew', (jClass,), jObject) PYPYSTRING2BYTES = Method.s(jPyPy, 'string2bytes', (jString,), jByteArray) PYPYARRAYTOLIST = Method.s(jPyPy, 'array_to_list', (jObjectArray,), jArrayList) -PYPYBOXINT = Method.s(jPyPy, 'box_integer', (jInt,), jIntegerClass) -PYPYUNBOXINT = Method.s(jPyPy, 'unbox_integer', (jIntegerClass,), jInt) +PYPYBOXINT = Method.s(jPyPy, 'box_integer', (jInt,), jObject) +PYPYUNBOXINT = Method.s(jPyPy, 'unbox_integer', (jObject,), jInt) PYPYOOPARSEFLOAT = Method.v(jPyPy, 'ooparse_float', (jString,), jDouble) OBJECTGETCLASS = Method.v(jObject, 'getClass', (), jClass) CLASSGETNAME = Method.v(jClass, 'getName', (), jString) From noreply at buildbot.pypy.org Fri Jul 22 00:13:08 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 22 Jul 2011 00:13:08 +0200 (CEST) Subject: [pypy-commit] pypy default: respect CFLAGS when installing stuff with distutils. Message-ID: <20110721221308.CF14F829B8@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45846:7203ebd350a7 Date: 2011-07-21 15:13 -0700 http://bitbucket.org/pypy/pypy/changeset/7203ebd350a7/ Log: respect CFLAGS when installing stuff with distutils. diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,6 +116,12 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + if "CFLAGS" in os.environ: + cflags = os.environ["CFLAGS"] + compiler.compiler.append(cflags) + compiler.compiler_so.append(cflags) + compiler.linker_so.append(cflags) + from sysconfig_cpython import ( parse_makefile, _variable_rx, expand_makefile_vars) From noreply at buildbot.pypy.org Fri Jul 22 00:24:52 2011 From: noreply at buildbot.pypy.org (RonnyPfannschmidt) Date: Fri, 22 Jul 2011 00:24:52 +0200 (CEST) Subject: [pypy-commit] pypy default: also use pytest_cov in the normal pytest script Message-ID: <20110721222452.AFBB3829B8@wyvern.cs.uni-duesseldorf.de> Author: Ronny Pfannschmidt Branch: Changeset: r45847:ff4a90f9be99 Date: 2011-07-21 23:59 +0200 http://bitbucket.org/pypy/pypy/changeset/ff4a90f9be99/ Log: also use pytest_cov in the normal pytest script diff --git a/pytest.py b/pytest.py --- a/pytest.py +++ b/pytest.py @@ -9,6 +9,8 @@ from _pytest import __version__ if __name__ == '__main__': # if run as a script or by 'python -m pytest' - raise SystemExit(main()) + #XXX: sync to upstream later + import pytest_cov + raise SystemExit(main(plugins=[pytest_cov])) else: _preloadplugins() # to populate pytest.* namespace so help(pytest) works From noreply at buildbot.pypy.org Fri Jul 22 00:24:53 2011 From: noreply at buildbot.pypy.org (RonnyPfannschmidt) Date: Fri, 22 Jul 2011 00:24:53 +0200 (CEST) Subject: [pypy-commit] pypy default: mark the xdist hooks of pytest_cov optional Message-ID: <20110721222453.DBA89829B8@wyvern.cs.uni-duesseldorf.de> Author: Ronny Pfannschmidt Branch: Changeset: r45848:e16267c17fb1 Date: 2011-07-22 00:21 +0200 http://bitbucket.org/pypy/pypy/changeset/e16267c17fb1/ Log: mark the xdist hooks of pytest_cov optional diff --git a/pytest_cov.py b/pytest_cov.py --- a/pytest_cov.py +++ b/pytest_cov.py @@ -323,11 +323,13 @@ """Delegate to our implementation.""" self.cov_controller.configure_node(node) + pytest_configure_node.optionalhook = True def pytest_testnodedown(self, node, error): """Delegate to our implementation.""" self.cov_controller.testnodedown(node, error) + pytest_testnodedown.optionalhook = True def pytest_sessionfinish(self, session, exitstatus): """Delegate to our implementation.""" From noreply at buildbot.pypy.org Fri Jul 22 00:24:55 2011 From: noreply at buildbot.pypy.org (RonnyPfannschmidt) Date: Fri, 22 Jul 2011 00:24:55 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110721222455.12CFA829B8@wyvern.cs.uni-duesseldorf.de> Author: Ronny Pfannschmidt Branch: Changeset: r45849:cededc37c18e Date: 2011-07-22 00:22 +0200 http://bitbucket.org/pypy/pypy/changeset/cededc37c18e/ Log: merge diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,6 +116,12 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + if "CFLAGS" in os.environ: + cflags = os.environ["CFLAGS"] + compiler.compiler.append(cflags) + compiler.compiler_so.append(cflags) + compiler.linker_so.append(cflags) + from sysconfig_cpython import ( parse_makefile, _variable_rx, expand_makefile_vars) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -259,8 +259,8 @@ i = start j = 0 while i < stop: - slice_driver1.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + #slice_driver1.jit_merge_point(signature=arr.signature, + # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step @@ -269,8 +269,8 @@ i = start j = 0 while i > stop: - slice_driver2.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) + #slice_driver2.jit_merge_point(signature=arr.signature, + # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) storage[i] = arr.eval(j) j += 1 i += step From noreply at buildbot.pypy.org Fri Jul 22 00:47:55 2011 From: noreply at buildbot.pypy.org (RonnyPfannschmidt) Date: Fri, 22 Jul 2011 00:47:55 +0200 (CEST) Subject: [pypy-commit] pypy default: add using coverage reports to the coding guide Message-ID: <20110721224755.782F3829B8@wyvern.cs.uni-duesseldorf.de> Author: Ronny Pfannschmidt Branch: Changeset: r45850:38aa87797a59 Date: 2011-07-22 00:45 +0200 http://bitbucket.org/pypy/pypy/changeset/38aa87797a59/ Log: add using coverage reports to the coding guide diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -929,6 +929,19 @@ located in the ``py/bin/`` directory. For switches to modify test execution pass the ``-h`` option. +Coverage reports +---------------- + +In order to get coverage reports the `pytest-cov`_ plugin is included. +it adds some extra requirements ( coverage_ and `cov-core`_ ) +and can once they are installed coverage testing can be invoked via:: + + python test_all.py --cov file_or_direcory_to_cover file_or_directory + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov +.. _`coverage`: http://pypi.python.org/pypi/coverage +.. _`cov-core`: http://pypi.python.org/pypi/cov-core + Test conventions ---------------- From noreply at buildbot.pypy.org Fri Jul 22 00:50:06 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 00:50:06 +0200 (CEST) Subject: [pypy-commit] pypy default: kill some dead code Message-ID: <20110721225006.3254E829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45851:d6837e825d00 Date: 2011-07-22 00:49 +0200 http://bitbucket.org/pypy/pypy/changeset/d6837e825d00/ Log: kill some dead code diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -11,14 +11,6 @@ from pypy.tool.sourcetools import func_with_new_name import math -def dummy1(v): - assert isinstance(v, float) - return v - -def dummy2(v): - assert isinstance(v, float) - return v - TP = lltype.Array(lltype.Float, hints={'nolength': True}) numpy_driver = jit.JitDriver(greens = ['signature'], From noreply at buildbot.pypy.org Fri Jul 22 00:56:16 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 00:56:16 +0200 (CEST) Subject: [pypy-commit] pypy default: a missing test Message-ID: <20110721225616.5D8D7829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45852:7b3a66f3c80a Date: 2011-07-22 00:56 +0200 http://bitbucket.org/pypy/pypy/changeset/7b3a66f3c80a/ Log: a missing test diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -171,6 +171,10 @@ for i in range(5): assert b[i] == i + 5 + def test_radd(self): + from numpy import array + assert 3 + array(range(3)) == array([3, 4, 5]) + def test_add_list(self): from numpy import array a = array(range(5)) From noreply at buildbot.pypy.org Fri Jul 22 01:05:48 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 01:05:48 +0200 (CEST) Subject: [pypy-commit] pypy default: fix the test, thanks justin Message-ID: <20110721230548.D43FF829B8@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45853:9b2cf174334c Date: 2011-07-22 01:05 +0200 http://bitbucket.org/pypy/pypy/changeset/9b2cf174334c/ Log: fix the test, thanks justin diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -173,7 +173,9 @@ def test_radd(self): from numpy import array - assert 3 + array(range(3)) == array([3, 4, 5]) + r = 3 + array(range(3))\ + for i in range(3): + assert r[i] == i + 3 def test_add_list(self): from numpy import array From noreply at buildbot.pypy.org Fri Jul 22 03:20:29 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 22 Jul 2011 03:20:29 +0200 (CEST) Subject: [pypy-commit] pypy default: fixed numpy's setslice to play nicely with the jit. Message-ID: <20110722012029.4BE7F829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45854:631e083bd996 Date: 2011-07-21 19:20 -0600 http://bitbucket.org/pypy/pypy/changeset/631e083bd996/ Log: fixed numpy's setslice to play nicely with the jit. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -17,8 +17,8 @@ reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) -slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) -slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) def add(v1, v2): return v1 + v2 @@ -247,23 +247,25 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) - def _sliceloop1(self, start, stop, step, arr, storage): + def _sliceloop1(self, start, stop, step, source, dest): i = start j = 0 while i < stop: - #slice_driver1.jit_merge_point(signature=arr.signature, - # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) - storage[i] = arr.eval(j) + slice_driver1.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) j += 1 i += step - def _sliceloop2(self, start, stop, step, arr, storage): + def _sliceloop2(self, start, stop, step, source, dest): i = start j = 0 while i > stop: - #slice_driver2.jit_merge_point(signature=arr.signature, - # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) - storage[i] = arr.eval(j) + slice_driver2.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) j += 1 i += step @@ -448,9 +450,9 @@ stop = self.calc_index(stop) step = self.step * step if step > 0: - self._sliceloop1(start, stop, step, arr, self.parent.storage) + self._sliceloop1(start, stop, step, arr, self.parent) else: - self._sliceloop2(start, stop, step, arr, self.parent.storage) + self._sliceloop2(start, stop, step, arr, self.parent) def calc_index(self, item): return (self.start + item * self.step) @@ -489,9 +491,9 @@ if not isinstance(arr, BaseArray): arr = convert_to_array(space, arr) if step > 0: - self._sliceloop1(start, stop, step, arr, self.storage) + self._sliceloop1(start, stop, step, arr, self) else: - self._sliceloop2(start, stop, step, arr, self.storage) + self._sliceloop2(start, stop, step, arr, self) def __del__(self): lltype.free(self.storage, flavor='raw') From noreply at buildbot.pypy.org Fri Jul 22 04:22:23 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 22 Jul 2011 04:22:23 +0200 (CEST) Subject: [pypy-commit] pypy default: Fixed a typo in a test Message-ID: <20110722022223.1FA5A829B8@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45855:cc2ae015c7fb Date: 2011-07-21 20:22 -0600 http://bitbucket.org/pypy/pypy/changeset/cc2ae015c7fb/ Log: Fixed a typo in a test diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -173,7 +173,7 @@ def test_radd(self): from numpy import array - r = 3 + array(range(3))\ + r = 3 + array(range(3)) for i in range(3): assert r[i] == i + 3 From noreply at buildbot.pypy.org Fri Jul 22 08:45:36 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 22 Jul 2011 08:45:36 +0200 (CEST) Subject: [pypy-commit] pypy streamio-bufout: merge Message-ID: <20110722064536.81FDD82961@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: streamio-bufout Changeset: r45856:eec37a903e60 Date: 2011-07-21 20:49 -0600 http://bitbucket.org/pypy/pypy/changeset/eec37a903e60/ Log: merge diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,6 +116,12 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + if "CFLAGS" in os.environ: + cflags = os.environ["CFLAGS"] + compiler.compiler.append(cflags) + compiler.compiler_so.append(cflags) + compiler.linker_so.append(cflags) + from sysconfig_cpython import ( parse_makefile, _variable_rx, expand_makefile_vars) diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -327,6 +327,9 @@ BoolOption("mutable_builtintypes", "Allow the changing of builtin types", default=False, requires=[("objspace.std.builtinshortcut", True)]), + BoolOption("withidentitydict", + "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not", + default=True), ]), ]) diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -929,6 +929,19 @@ located in the ``py/bin/`` directory. For switches to modify test execution pass the ``-h`` option. +Coverage reports +---------------- + +In order to get coverage reports the `pytest-cov`_ plugin is included. +it adds some extra requirements ( coverage_ and `cov-core`_ ) +and can once they are installed coverage testing can be invoked via:: + + python test_all.py --cov file_or_direcory_to_cover file_or_directory + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov +.. _`coverage`: http://pypi.python.org/pypi/coverage +.. _`cov-core`: http://pypi.python.org/pypi/cov-core + Test conventions ---------------- diff --git a/pypy/doc/config/objspace.std.withidentitydict.txt b/pypy/doc/config/objspace.std.withidentitydict.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withidentitydict.txt @@ -0,0 +1,21 @@ +============================= +objspace.std.withidentitydict +============================= + +* **name:** withidentitydict + +* **description:** enable a dictionary strategy for "by identity" comparisons + +* **command-line:** --objspace-std-withidentitydict + +* **command-line for negation:** --no-objspace-std-withidentitydict + +* **option type:** boolean option + +* **default:** True + + +Enable a dictionary strategy specialized for instances of classes which +compares "by identity", which is the default unless you override ``__hash__``, +``__eq__`` or ``__cmp__``. This strategy will be used only with new-style +classes. diff --git a/pypy/doc/config/translation.dont_write_c_files.txt b/pypy/doc/config/translation.dont_write_c_files.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/translation.dont_write_c_files.txt @@ -0,0 +1,4 @@ +write the generated C files to ``/dev/null`` instead of to the disk. Useful if +you want to use translate.py as a benchmark and don't want to access the disk. + +.. _`translation documentation`: ../translation.html diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -211,6 +211,38 @@ >>>> print d1['a'] 42 +Mutating classes of objects which are already used as dictionary keys +--------------------------------------------------------------------- + +Consider the following snippet of code:: + + class X(object): + pass + + def __evil_eq__(self, other): + print 'hello world' + return False + + def evil(y): + d = {x(): 1} + X.__eq__ = __evil_eq__ + d[y] # might trigger a call to __eq__? + +In CPython, __evil_eq__ **might** be called, although there is no way to write +a test which reliably calls it. It happens if ``y is not x`` and ``hash(y) == +hash(x)``, where ``hash(x)`` is computed when ``x`` is inserted into the +dictionary. If **by chance** the condition is satisfied, then ``__evil_eq__`` +is called. + +PyPy uses a special strategy to optimize dictionaries whose keys are instances +of user-defined classes which do not override the default ``__hash__``, +``__eq__`` and ``__cmp__``: when using this strategy, ``__eq__`` and +``__cmp__`` are never called, but instead the lookup is done by identity, so +in the case above it is guaranteed that ``__eq__`` won't be called. + +Note that in all other cases (e.g., if you have a custom ``__hash__`` and +``__eq__`` in ``y``) the behavior is exactly the same as CPython. + Ignored exceptions ----------------------- diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -31,7 +31,8 @@ _immutable_fields_ = ['code?', 'w_func_globals?', 'closure?', - 'defs_w?[*]'] + 'defs_w?[*]', + 'name?'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2820,11 +2820,11 @@ def test_residual_call_invalidate_some_arrays(self): ops = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) - p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p2, 0, descr=arraydescr2) p6 = getarrayitem_gc(p2, 1, descr=arraydescr2) i4 = getarrayitem_gc(p1, 1, descr=arraydescr) escape(p3) @@ -2837,7 +2837,7 @@ """ expected = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -390,8 +390,21 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): - return self.execute_with_descr(rop.GETARRAYITEM_GC, + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache and isinstance(indexbox, ConstInt): + index = indexbox.getint() + frombox, tobox = cache.get(index, (None, None)) + if frombox is arraybox: + return tobox + resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) + if isinstance(indexbox, ConstInt): + if not cache: + cache = self.metainterp.heap_array_cache[arraydescr] = {} + index = indexbox.getint() + cache[index] = arraybox, resbox + return resbox + opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any @@ -419,6 +432,13 @@ indexbox, itembox): self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, itembox) + if isinstance(indexbox, ConstInt): + cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {}) + cache[indexbox.getint()] = arraybox, itembox + else: + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache: + cache.clear() opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any @@ -454,21 +474,17 @@ def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, - sbox, sizebox) + self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox) abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, sizebox) - self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, - sbox, abox) + self._opimpl_setfield_gc_any(sbox, itemsdescr, abox) return sbox @arguments("box", "descr", "descr", "box") def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox) opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any @@ -477,10 +493,9 @@ @arguments("box", "descr", "descr", "box", "box") def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, - indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox, + valuebox) opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any @@ -502,18 +517,29 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC, box, fielddescr) opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @arguments("box", "descr") def _opimpl_getfield_gc_pure_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_PURE, box, fielddescr) opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any + @specialize.arg(1) + def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(opnum, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox + @arguments("orgpc", "box", "descr") def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr): ginfo = self.metainterp.jitdriver_sd.greenfield_info @@ -532,7 +558,11 @@ @arguments("box", "descr", "box") def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box and tobox is valuebox: + return self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + self.metainterp.heap_cache[fielddescr] = (box, valuebox) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any @@ -617,7 +647,7 @@ @arguments("orgpc", "box", "descr") def _opimpl_getfield_vable(self, pc, box, fielddescr): if self._nonstandard_virtualizable(pc, box): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any(box, fielddescr) self.metainterp.check_synchronized_virtualizable() index = self._get_virtualizable_field_index(fielddescr) return self.metainterp.virtualizable_boxes[index] @@ -629,8 +659,7 @@ @arguments("orgpc", "box", "descr", "box") def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox): if self._nonstandard_virtualizable(pc, box): - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) - return + return self._opimpl_setfield_gc_any(box, fielddescr, valuebox) index = self._get_virtualizable_field_index(fielddescr) self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -660,10 +689,8 @@ @arguments("orgpc", "box", "descr", "descr", "box") def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr, - arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox) self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) return self.metainterp.virtualizable_boxes[index] @@ -676,10 +703,9 @@ def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox, valuebox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - self.execute_with_descr(rop.SETARRAYITEM_GC, adescr, - arraybox, indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + self._opimpl_setarrayitem_gc_any(arraybox, adescr, + indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -693,8 +719,7 @@ @arguments("orgpc", "box", "descr", "descr") def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -1462,6 +1487,12 @@ self.known_class_boxes = {} # contains frame boxes that are not virtualizables self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1637,10 +1668,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1804,6 +1852,8 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} + self.heap_array_cache = {} duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), @@ -2311,6 +2361,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1024,69 +1024,6 @@ res = self.meta_interp(main, []) assert res == 55 - def test_dont_record_repeated_guard_class(self): - class A: - pass - class B(A): - pass - @dont_look_inside - def extern(n): - if n == -7: - return None - elif n: - return A() - else: - return B() - def fn(n): - obj = extern(n) - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=1, guard_nonnull=1) - res = self.interp_operations(fn, [1]) - assert not res - - def test_dont_record_guard_class_after_new(self): - class A: - pass - class B(A): - pass - def fn(n): - if n == -7: - obj = None - elif n: - obj = A() - else: - obj = B() - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=0, guard_nonnull=0) - res = self.interp_operations(fn, [1]) - assert not res - - def test_guard_isnull_nullifies(self): - class A: - pass - a = A() - a.x = None - def fn(n): - if n == -7: - a.x = "" - obj = a.x - res = 0 - if not obj: - res += 1 - if obj: - res += 1 - if obj is None: - res += 1 - if obj is not None: - res += 1 - return res - res = self.interp_operations(fn, [0]) - assert res == 2 - self.check_operations_history(guard_isnull=1) def test_assert_isinstance(self): class A: @@ -1248,7 +1185,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: @@ -2649,7 +2586,23 @@ return n res = self.meta_interp(f, [10, 1]) self.check_loops(getfield_gc=2) + assert res == f(10, 1) + def test_jit_merge_point_with_raw_pointer(self): + driver = JitDriver(greens = [], reds = ['n', 'x']) + + TP = lltype.Array(lltype.Signed, hints={'nolength': True}) + + def f(n): + x = lltype.malloc(TP, 10, flavor='raw') + x[0] = 1 + while n > 0: + driver.jit_merge_point(n=n, x=x) + n -= x[0] + lltype.free(x, flavor='raw') + return n + + self.meta_interp(f, [10], repeat=3) class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,407 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + l = [1] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * (4 + a) + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + len(frame.l) + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -138,6 +138,9 @@ refvalue = cpu.ts.cast_to_ref(value) cpu.set_future_value_ref(j, refvalue) elif typecode == 'int': + if isinstance(lltype.typeOf(value), lltype.Ptr): + intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value)) + else: intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) elif typecode == 'float': diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -25,6 +25,7 @@ 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', 'lookup_special' : 'interp_magic.lookup_special', + 'do_what_I_mean' : 'interp_magic.do_what_I_mean', } submodules = { diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -70,3 +70,6 @@ if w_descr is None: return space.w_None return space.get(w_descr, w_obj) + +def do_what_I_mean(space): + return space.wrap(42) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -49,3 +49,8 @@ class X: pass raises(TypeError, lookup_special, X(), "foo") + + def test_do_what_I_mean(self): + from __pypy__ import do_what_I_mean + x = do_what_I_mean() + assert x == 42 diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -268,3 +268,7 @@ if errors: w_errors = space.wrap(rffi.charp2str(errors)) return space.call_method(w_str, 'encode', w_encoding, w_errors) + + at cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -287,3 +287,9 @@ def test_eq(self, space, api): assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'ab' diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -15,14 +15,22 @@ # ufuncs 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', + 'add': 'interp_ufuncs.add', 'copysign': 'interp_ufuncs.copysign', + 'divide': 'interp_ufuncs.divide', 'exp': 'interp_ufuncs.exp', + 'fabs': 'interp_ufuncs.fabs', 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', + 'multiply': 'interp_ufuncs.multiply', 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'subtract': 'interp_ufuncs.subtract', + 'sin': 'interp_ufuncs.sin', + 'cos': 'interp_ufuncs.cos', + 'tan': 'interp_ufuncs.tan', } appleveldefs = { diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -3,7 +3,7 @@ It should not be imported by the module itself """ -from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray class BogusBytecode(Exception): pass @@ -18,6 +18,14 @@ def wrap(self, x): return x + def issequence_w(self, w_obj): + # Completley wrong in the general case, but good enough for this. + return isinstance(w_obj, BaseArray) + + def float_w(self, w_obj): + assert isinstance(w_obj, float) + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() stack = [] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,59 +2,36 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy.interp_support import Signature +from pypy.module.micronumpy import interp_ufuncs +from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit +from pypy.rlib.rfloat import DTSF_STR_PRECISION from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name import math -def dummy1(v): - assert isinstance(v, float) - return v - -def dummy2(v): - assert isinstance(v, float) - return v - TP = lltype.Array(lltype.Float, hints={'nolength': True}) numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) -class Signature(object): - def __init__(self): - self.transitions = {} - - def transition(self, target): - if target in self.transitions: - return self.transitions[target] - self.transitions[target] = new = Signature() - return new - -def pos(v): - return v -def neg(v): - return -v -def absolute(v): - return abs(v) def add(v1, v2): return v1 + v2 -def sub(v1, v2): - return v1 - v2 def mul(v1, v2): return v1 * v2 -def div(v1, v2): - return v1 / v2 -def power(v1, v2): - return math.pow(v1, v2) -def mod(v1, v2): - return math.fmod(v1, v2) def maximum(v1, v2): return max(v1, v2) def minimum(v1, v2): return min(v1, v2) +def float2string(x): + return float2string_orig(x, 'g', DTSF_STR_PRECISION) + class BaseArray(Wrappable): def __init__(self): self.invalidates = [] @@ -68,67 +45,39 @@ arr.force_if_needed() del self.invalidates[:] - def _unop_impl(function): - signature = Signature() + def _unaryop_impl(w_ufunc): def impl(self, space): - new_sig = self.signature.transition(signature) - res = Call1( - function, - self, - new_sig) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + return w_ufunc(space, self) + return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__) - descr_pos = _unop_impl(pos) - descr_neg = _unop_impl(neg) - descr_abs = _unop_impl(absolute) + descr_pos = _unaryop_impl(interp_ufuncs.positive) + descr_neg = _unaryop_impl(interp_ufuncs.negative) + descr_abs = _unaryop_impl(interp_ufuncs.absolute) - def _binop_impl(function): - signature = Signature() + def _binop_impl(w_ufunc): def impl(self, space, w_other): - w_other = convert_to_array(space, w_other) - new_sig = self.signature.transition(signature) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + return w_ufunc(space, self, w_other) + return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__) - descr_add = _binop_impl(add) - descr_sub = _binop_impl(sub) - descr_mul = _binop_impl(mul) - descr_div = _binop_impl(div) - descr_pow = _binop_impl(power) - descr_mod = _binop_impl(mod) + descr_add = _binop_impl(interp_ufuncs.add) + descr_sub = _binop_impl(interp_ufuncs.subtract) + descr_mul = _binop_impl(interp_ufuncs.multiply) + descr_div = _binop_impl(interp_ufuncs.divide) + descr_pow = _binop_impl(interp_ufuncs.power) + descr_mod = _binop_impl(interp_ufuncs.mod) - def _binop_right_impl(function): - signature = Signature() + def _binop_right_impl(w_ufunc): def impl(self, space, w_other): - new_sig = self.signature.transition(signature) w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - w_other, - self, - new_sig.transition(w_other.signature) - ) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, - "binop_right_%s_impl" % function.__name__) + return w_ufunc(space, w_other, self) + return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__) - descr_radd = _binop_right_impl(add) - descr_rsub = _binop_right_impl(sub) - descr_rmul = _binop_right_impl(mul) - descr_rdiv = _binop_right_impl(div) - descr_rpow = _binop_right_impl(power) - descr_rmod = _binop_right_impl(mod) + descr_radd = _binop_right_impl(interp_ufuncs.add) + descr_rsub = _binop_right_impl(interp_ufuncs.subtract) + descr_rmul = _binop_right_impl(interp_ufuncs.multiply) + descr_rdiv = _binop_right_impl(interp_ufuncs.divide) + descr_rpow = _binop_right_impl(interp_ufuncs.power) + descr_rmod = _binop_right_impl(interp_ufuncs.mod) def _reduce_sum_prod_impl(function, init): reduce_driver = jit.JitDriver(greens=['signature'], @@ -235,6 +184,24 @@ else: return self.descr_mul(space, w_other) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] + nums.append("..." + "," * comma) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) + else: + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] + return nums + def get_concrete(self): raise NotImplementedError @@ -245,10 +212,14 @@ return self.get_concrete().descr_len(space) def descr_repr(self, space): - return self.get_concrete()._repr(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])") def descr_str(self, space): - return self.get_concrete()._str(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("[" + " ".join(concrete._getnums(True)) + "]") def descr_getitem(self, space, w_idx): # TODO: indexing by tuples @@ -261,14 +232,43 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().setitem(start, space.float_w(w_value)) + else: + self.get_concrete().setslice(space, start, stop, step, + slice_length, w_value) def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) + def _sliceloop1(self, start, stop, step, source, dest): + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, source, dest): + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + def convert_to_array (space, w_obj): if isinstance(w_obj, BaseArray): return w_obj @@ -413,8 +413,8 @@ return self.parent.getitem(self.calc_index(item)) @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - return self.parent.descr_setitem(space, self.calc_index(item), value) + def setitem(self, item, value): + return self.parent.setitem(self.calc_index(item), value) def descr_len(self, space): return space.wrap(self.find_size()) @@ -428,37 +428,35 @@ def __init__(self, start, stop, step, slice_length, parent, signature): ViewArray.__init__(self, parent, signature) + if isinstance(parent, SingleDimSlice): + self.start = parent.calc_index(start) + self.stop = parent.calc_index(stop) + self.step = parent.step * step + self.parent = parent.parent + else: self.start = start self.stop = stop self.step = step + self.parent = parent self.size = slice_length def find_size(self): return self.size + def setslice(self, space, start, stop, step, slice_length, arr): + arr = convert_to_array(space, arr) + start = self.calc_index(start) + if stop != -1: + stop = self.calc_index(stop) + step = self.step * step + if step > 0: + self._sliceloop1(start, stop, step, arr, self.parent) + else: + self._sliceloop2(start, stop, step, arr, self.parent) + def calc_index(self, item): return (self.start + item * self.step) - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - class SingleDimArray(BaseArray): signature = Signature() @@ -479,49 +477,24 @@ def eval(self, i): return self.storage[i] - def getindex(self, space, item): - if item >= self.size: - raise operationerrfmt(space.w_IndexError, - '%d above array size', item) - if item < 0: - item += self.size - if item < 0: - raise operationerrfmt(space.w_IndexError, - '%d below zero', item) - return item - def descr_len(self, space): return space.wrap(self.size) def getitem(self, item): return self.storage[item] - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - item = self.getindex(space, item) + def setitem(self, item, value): self.invalidated() self.storage[item] = value + def setslice(self, space, start, stop, step, slice_length, arr): + if not isinstance(arr, BaseArray): + arr = convert_to_array(space, arr) + if step > 0: + self._sliceloop1(start, stop, step, arr, self) + else: + self._sliceloop2(start, stop, step, arr, self) + def __del__(self): lltype.free(self.storage, flavor='raw') diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py --- a/pypy/module/micronumpy/interp_support.py +++ b/pypy/module/micronumpy/interp_support.py @@ -1,14 +1,14 @@ - from pypy.rlib.rstruct.runpack import runpack from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.interp_numarray import SingleDimArray + FLOAT_SIZE = rffi.sizeof(lltype.Float) @unwrap_spec(s=str) def fromstring(space, s): + from pypy.module.micronumpy.interp_numarray import SingleDimArray length = len(s) if length % FLOAT_SIZE == 0: @@ -30,3 +30,13 @@ end += FLOAT_SIZE return space.wrap(a) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,13 +1,13 @@ import math -from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, - convert_to_array) +from pypy.module.micronumpy.interp_support import Signature from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name def ufunc(func): signature = Signature() def impl(space, w_obj): + from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array if space.issequence_w(w_obj): w_obj_arr = convert_to_array(space, w_obj) w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) @@ -20,6 +20,7 @@ def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): + from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): w_lhs_arr = convert_to_array(space, w_lhs) w_rhs_arr = convert_to_array(space, w_rhs) @@ -37,9 +38,17 @@ return abs(value) @ufunc2 +def add(lvalue, rvalue): + return lvalue + rvalue + + at ufunc2 def copysign(lvalue, rvalue): return rfloat.copysign(lvalue, rvalue) + at ufunc2 +def divide(lvalue, rvalue): + return lvalue / rvalue + @ufunc def exp(value): try: @@ -47,6 +56,10 @@ except OverflowError: return rfloat.INFINITY + at ufunc +def fabs(value): + return math.fabs(value) + @ufunc2 def maximum(lvalue, rvalue): return max(lvalue, rvalue) @@ -55,6 +68,15 @@ def minimum(lvalue, rvalue): return min(lvalue, rvalue) + at ufunc2 +def multiply(lvalue, rvalue): + return lvalue * rvalue + +# Used by numarray for __pos__. Not visible from numpy application space. + at ufunc +def positive(value): + return value + @ufunc def negative(value): return -value @@ -65,6 +87,10 @@ return rfloat.copysign(rfloat.INFINITY, value) return 1.0 / value + at ufunc2 +def subtract(lvalue, rvalue): + return lvalue - rvalue + @ufunc def floor(value): return math.floor(value) @@ -74,3 +100,23 @@ if value == 0.0: return 0.0 return rfloat.copysign(1.0, value) + + at ufunc +def sin(value): + return math.sin(value) + + at ufunc +def cos(value): + return math.cos(value) + + at ufunc +def tan(value): + return math.tan(value) + + at ufunc2 +def power(lvalue, rvalue): + return math.pow(lvalue, rvalue) + + at ufunc2 +def mod(lvalue, rvalue): + return math.fmod(lvalue, rvalue) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -92,6 +92,48 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_of_slice_array(self): + from numpy import array, zeros + a = zeros(5) + a[::2] = array([9., 10., 11.]) + assert a[0] == 9. + assert a[2] == 10. + assert a[4] == 11. + a[1:4:2][::-1] = array([1., 2.]) + assert a[0] == 9. + assert a[1] == 2. + assert a[2] == 10. + assert a[3] == 1. + assert a[4] == 11. + a = zeros(10) + a[::2][::-1][::2] = array(range(1,4)) + assert a[8] == 1. + assert a[4] == 2. + assert a[0] == 3. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) @@ -129,6 +171,12 @@ for i in range(5): assert b[i] == i + 5 + def test_radd(self): + from numpy import array + r = 3 + array(range(3)) + for i in range(3): + assert r[i] == i + 3 + def test_add_list(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -65,6 +65,33 @@ for i in range(3): assert b[i] == abs(a[i]) + def test_add(self): + from numpy import array, add + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = add(a, b) + for i in range(3): + assert c[i] == a[i] + b[i] + + def test_divide(self): + from numpy import array, divide + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = divide(a, b) + for i in range(3): + assert c[i] == a[i] / b[i] + + def test_fabs(self): + from numpy import array, fabs + from math import fabs as math_fabs + + a = array([-5.0, -0.0, 1.0]) + b = fabs(a) + for i in range(3): + assert b[i] == math_fabs(a[i]) + def test_minimum(self): from numpy import array, minimum @@ -83,6 +110,15 @@ for i in range(3): assert c[i] == max(a[i], b[i]) + def test_multiply(self): + from numpy import array, multiply + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = multiply(a, b) + for i in range(3): + assert c[i] == a[i] * b[i] + def test_sign(self): from numpy import array, sign @@ -101,6 +137,15 @@ for i in range(4): assert b[i] == reference[i] + def test_subtract(self): + from numpy import array, subtract + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = subtract(a, b) + for i in range(3): + assert c[i] == a[i] - b[i] + def test_floor(self): from numpy import array, floor @@ -133,3 +178,30 @@ except OverflowError: res = float('inf') assert b[i] == res + + def test_sin(self): + import math + from numpy import array, sin + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = sin(a) + for i in range(len(a)): + assert b[i] == math.sin(a[i]) + + def test_cos(self): + import math + from numpy import array, cos + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = cos(a) + for i in range(len(a)): + assert b[i] == math.cos(a[i]) + + def test_tan(self): + import math + from numpy import array, tan + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = tan(a) + for i in range(len(a)): + assert b[i] == math.tan(a[i]) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,10 +1,11 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) + FloatWrapper, Call2, SingleDimSlice, add, mul, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): w_ValueError = None @@ -47,21 +48,6 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_neg(self): - space = self.space - - def f(i): - ar = SingleDimArray(i) - v = Call1(neg, ar, Signature()) - return v.get_concrete().storage[3] - - result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, - "setarrayitem_raw": 1, "int_add": 1, - "int_lt": 1, "guard_true": 1, "jump": 1}) - - assert result == f(5) - def test_sum(self): space = self.space @@ -104,6 +90,7 @@ "float_gt": 1, "int_add": 1, "int_lt": 1, "guard_true": 1, "guard_false": 1, "jump": 1}) + assert result == f(5) def test_min(self): space = self.space @@ -121,6 +108,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_argmin(self): space = self.space @@ -138,6 +126,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_all(self): space = self.space @@ -153,6 +142,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_any(self): space = self.space @@ -165,6 +155,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "guard_false": 1, "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) def test_already_forecd(self): def f(i): @@ -248,6 +239,28 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar2.storage[1] = 5.5 + if NonConstant(False): + arg = ar2 + else: + arg = ar2.descr_add(space, ar2) + ar.setslice(space, 0, step*i, step, i, arg) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 2, + 'float_add' : 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == 11.0 + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -30,7 +30,6 @@ assert res == 8.0 * 300 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('fficall', """ - p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>) guard_not_invalidated(descr=...) i17 = force_token() setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -23,3 +23,29 @@ ops = loop.ops_by_id('look') assert log.opnames(ops) == ['setfield_gc', 'guard_not_invalidated'] + + def test_identitydict(self): + def fn(n): + class X(object): + pass + x = X() + d = {} + d[x] = 1 + res = 0 + for i in range(300): + value = d[x] # ID: getitem + res += value + return res + # + log = self.run(fn, [1000]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # check that the call to ll_dict_lookup is not a call_may_force + assert loop.match_by_id("getitem", """ + i25 = call(ConstClass(_ll_1_gc_identityhash__objectPtr), p6, descr=...) + ... + i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...) + ... + p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...) + ... + """) diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -28,6 +28,13 @@ return w_delattr object_delattr._annspecialcase_ = 'specialize:memo' +def object_hash(space): + "Utility that returns the app-level descriptor object.__hash__." + w_src, w_hash = space.lookup_in_type_where(space.w_object, + '__hash__') + return w_hash +object_hash._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): w_type = space.type(w_obj) typename = w_type.getname(space) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -157,11 +157,15 @@ return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): - #XXX implement other strategies later + withidentitydict = self.space.config.objspace.std.withidentitydict if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) - elif self.space.is_w(self.space.type(w_key), self.space.w_int): + return + w_type = self.space.type(w_key) + if self.space.is_w(w_type, self.space.w_int): self.switch_to_int_strategy(w_dict) + elif withidentitydict and w_type.compares_by_identity(): + self.switch_to_identity_strategy(w_dict) else: self.switch_to_object_strategy(w_dict) @@ -177,6 +181,13 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_identity_strategy(self, w_dict): + from pypy.objspace.std.identitydict import IdentityDictStrategy + strategy = self.space.fromcache(IdentityDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): strategy = self.space.fromcache(ObjectDictStrategy) storage = strategy.get_empty_storage() @@ -338,7 +349,6 @@ def getitem(self, w_dict, w_key): space = self.space - if self.is_correct_type(w_key): return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) elif self._never_equal_to(space.type(w_key)): @@ -404,6 +414,7 @@ def keys(self, w_dict): return self.unerase(w_dict.dstorage).keys() + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") @@ -448,7 +459,9 @@ return StrIteratorImplementation(self.space, self, w_dict) -class StrIteratorImplementation(IteratorImplementation): +class _WrappedIteratorMixin(object): + _mixin_ = True + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() @@ -460,6 +473,23 @@ else: return None, None +class _UnwrappedIteratorMixin: + _mixin_ = True + + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value + else: + return None, None + + +class StrIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass class IntDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("int") @@ -490,31 +520,11 @@ def iter(self, w_dict): return IntIteratorImplementation(self.space, self, w_dict) -class IntIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() +class IntIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass - def next_entry(self): - # note that this 'for' loop only runs once, at most - for key, w_value in self.iterator: - return self.space.wrap(key), w_value - else: - return None, None - - -class ObjectIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() - - def next_entry(self): - # note that this 'for' loop only runs once, at most - for w_key, w_value in self.iterator: - return w_key, w_value - else: - return None, None - +class ObjectIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass init_signature = Signature(['seq_or_map'], None, 'kwargs') init_defaults = [None] diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -86,7 +86,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated() + self.unerase(w_dict.dstorage).mutated(None) class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -133,8 +133,7 @@ else: return space.wrap("0x%sp%s%d" % (s, sign, exp)) -def float2string(space, w_float, code, precision): - x = w_float.floatval +def float2string(x, code, precision): # we special-case explicitly inf and nan here if isfinite(x): s = formatd(x, code, precision, DTSF_ADD_DOT_0) @@ -145,13 +144,13 @@ s = "-inf" else: # isnan(x): s = "nan" - return space.wrap(s) + return s def repr__Float(space, w_float): - return float2string(space, w_float, 'r', 0) + return space.wrap(float2string(w_float.floatval, 'r', 0)) def str__Float(space, w_float): - return float2string(space, w_float, 'g', DTSF_STR_PRECISION) + return space.wrap(float2string(w_float.floatval, 'g', DTSF_STR_PRECISION)) def format__Float_ANY(space, w_float, w_spec): return newformat.run_formatter(space, w_spec, "format_float", w_float) diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/identitydict.py @@ -0,0 +1,85 @@ +## ---------------------------------------------------------------------------- +## dict strategy (see dict_multiobject.py) + +from pypy.rlib import rerased +from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, + DictStrategy, + IteratorImplementation, + _UnwrappedIteratorMixin) + + +# this strategy is selected by EmptyDictStrategy.switch_to_correct_strategy +class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): + """ + Strategy for custom instances which compares by identity (i.e., the + default unless you override __hash__, __eq__ or __cmp__). The storage is + just a normal RPython dict, which has already the correct by-identity + semantics. + + Note that at a first sight, you might have problems if you mutate the + class of an object which is already inside an identitydict. Consider this + example:: + + class X(object): + pass + d = {x(): 1} + X.__eq__ = ... + d[y] # might trigger a call to __eq__? + + We want to be sure that x.__eq__ is called in the same cases as in + CPython. However, as long as the strategy is IdentityDictStrategy, the + __eq__ will never be called. + + It turns out that it's not a problem. In CPython (and in PyPy without + this strategy), the __eq__ is called if ``hash(y) == hash(x)`` and ``x is + not y``. Note that hash(x) is computed at the time when we insert x in + the dict, not at the time we lookup y. + + Now, how can hash(y) == hash(x)? There are two possibilities: + + 1. we write a custom __hash__ for the class of y, thus making it a not + "compares by reference" type + + 2. the class of y is "compares by reference" type, and by chance the + hash is the same as x + + In the first case, the getitem immediately notice that y is not of the + right type, and switches the strategy to ObjectDictStrategy, then the + lookup works as usual. + + The second case is completely non-deterministic, even in CPython. + Depending on the phase of the moon, you might call the __eq__ or not, so + it is perfectly fine to *never* call it. Morever, in practice with the + minimar GC we never have two live objects with the same hash, so it would + never happen anyway. + """ + + erase, unerase = rerased.new_erasing_pair("identitydict") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): + w_type = self.space.type(w_obj) + return w_type.compares_by_identity() + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return IdentityDictIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + + +class IdentityDictIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -6,7 +6,7 @@ from pypy.objspace.descroperation import Object from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.register_all import register_all - +from pypy.objspace.std import identitydict def descr__repr__(space, w_obj): w = space.wrap diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -39,7 +39,6 @@ from pypy.objspace.std.stringtype import wrapstr from pypy.objspace.std.unicodetype import wrapunicode - class StdObjSpace(ObjSpace, DescrOperation): """The standard object space, implementing a general-purpose object library in Restricted Python.""" diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -898,6 +898,7 @@ withsmalldicts = False withcelldict = False withmethodcache = False + withidentitydict = False FakeSpace.config = Config() @@ -1105,3 +1106,4 @@ fakespace = FakeSpace() d = fakespace.newdict(module=True) assert type(d.strategy) is StringDictStrategy + diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_identitydict.py @@ -0,0 +1,135 @@ +from pypy.interpreter.gateway import interp2app +from pypy.conftest import gettestobjspace +from pypy.conftest import option + +class AppTestComparesByIdentity: + + def setup_class(cls): + from pypy.objspace.std import identitydict + cls.space = gettestobjspace( + **{"objspace.std.withidentitydict": True}) + + def compares_by_identity(space, w_cls): + return space.wrap(w_cls.compares_by_identity()) + cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) + + def test_compares_by_identity(self): + class Plain(object): + pass + + class CustomEq(object): + def __eq__(self, other): + return True + + class CustomCmp (object): + def __cmp__(self, other): + return 0 + + class CustomHash(object): + def __hash__(self): + return 0 + + assert self.compares_by_identity(Plain) + assert not self.compares_by_identity(CustomEq) + assert not self.compares_by_identity(CustomCmp) + assert not self.compares_by_identity(CustomHash) + + def test_modify_class(self): + class X(object): + pass + + assert self.compares_by_identity(X) + X.__eq__ = lambda x: None + assert not self.compares_by_identity(X) + del X.__eq__ + assert self.compares_by_identity(X) + + +class AppTestIdentityDict(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_uses_identity_strategy(self, obj): + import __pypy__ + return "IdentityDictStrategy" in __pypy__.internal_repr(obj) + + def test_use_strategy(self): + class X(object): + pass + d = {} + x = X() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[x] == 1 + + def test_bad_item(self): + class X(object): + pass + class Y(object): + def __hash__(self): + return 32 + + d = {} + x = X() + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + d[y] = 2 + assert not self.uses_identity_strategy(d) + assert d[x] == 1 + assert d[y] == 2 + + def test_bad_key(self): + class X(object): + pass + d = {} + x = X() + + class Y(object): + def __hash__(self): + return hash(x) # to make sure we do x == y + + def __eq__(self, other): + return True + + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[y] == 1 + assert not self.uses_identity_strategy(d) + + def test_iter(self): + class X(object): + pass + x = X() + d = {x: 1} + assert self.uses_identity_strategy(d) + assert list(iter(d)) == [x] + + def test_mutate_class_and_then_compare(self): + class X(object): + pass + class Y(object): + pass + + x = X() + y = Y() + d1 = {x: 1} + d2 = {y: 1} + assert self.uses_identity_strategy(d1) + assert self.uses_identity_strategy(d2) + # + X.__hash__ = lambda self: hash(y) + X.__eq__ = lambda self, other: True + # + assert d1 == d2 + assert self.uses_identity_strategy(d1) + assert not self.uses_identity_strategy(d2) + + def test_old_style_classes(self): + class X: + pass + d = {X(): 1} + assert not self.uses_identity_strategy(d) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -7,6 +7,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member from pypy.objspace.std.objecttype import object_typedef +from pypy.objspace.std import identitydict from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash from pypy.rlib.jit import promote, elidable_promote, we_are_jitted @@ -76,6 +77,10 @@ for i in range(len(self.lookup_where)): self.lookup_where[i] = None_None +# possible values of compares_by_identity_status +UNKNOWN = 0 +COMPARES_BY_IDENTITY = 1 +OVERRIDES_EQ_CMP_OR_HASH = 2 class W_TypeObject(W_Object): from pypy.objspace.std.typetype import type_typedef as typedef @@ -102,6 +107,9 @@ # (False is a conservative default, fixed during real usage) uses_object_getattribute = False + # for config.objspace.std.withidentitydict + compares_by_identity_status = UNKNOWN + # used to cache the type __new__ function if it comes from a builtin type # != 'type', in that case call__Type will also assumes the result # of the __new__ is an instance of the type @@ -146,11 +154,17 @@ else: w_self.terminator = NoDictTerminator(space, w_self) - def mutated(w_self): + def mutated(w_self, key): + """ + The type is being mutated. key is either the string containing the + specific attribute which is being deleted/set or None to indicate a + generic mutation. + """ space = w_self.space assert w_self.is_heaptype() or space.config.objspace.std.mutable_builtintypes if (not space.config.objspace.std.withtypeversion and not space.config.objspace.std.getattributeshortcut and + not space.config.objspace.std.withidentitydict and not space.config.objspace.std.newshortcut): return @@ -158,6 +172,13 @@ w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage + if space.config.objspace.std.withidentitydict: + did_compare_by_identity = ( + w_self.compares_by_identity_status == COMPARES_BY_IDENTITY) + if (key is None or key == '__eq__' or + key == '__cmp__' or key == '__hash__'): + w_self.compares_by_identity_status = UNKNOWN + if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None @@ -168,7 +189,7 @@ subclasses_w = w_self.get_subclasses() for w_subclass in subclasses_w: assert isinstance(w_subclass, W_TypeObject) - w_subclass.mutated() + w_subclass.mutated(key) def version_tag(w_self): if (not we_are_jitted() or w_self.is_heaptype() or @@ -207,6 +228,25 @@ def has_object_getattribute(w_self): return w_self.getattribute_if_not_from_object() is None + def compares_by_identity(w_self): + from pypy.objspace.descroperation import object_hash + if not w_self.space.config.objspace.std.withidentitydict: + return False # conservative + # + if w_self.compares_by_identity_status != UNKNOWN: + # fast path + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + # + default_hash = object_hash(w_self.space) + overrides_eq_cmp_or_hash = (w_self.lookup('__eq__') or + w_self.lookup('__cmp__') or + w_self.lookup('__hash__') is not default_hash) + if overrides_eq_cmp_or_hash: + w_self.compares_by_identity_status = OVERRIDES_EQ_CMP_OR_HASH + else: + w_self.compares_by_identity_status = COMPARES_BY_IDENTITY + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + def ready(w_self): for w_base in w_self.bases_w: if not isinstance(w_base, W_TypeObject): @@ -269,7 +309,7 @@ w_curr.w_value = w_value return True w_value = TypeCell(w_value) - w_self.mutated() + w_self.mutated(name) w_self.dict_w[name] = w_value return True @@ -286,7 +326,7 @@ except KeyError: return False else: - w_self.mutated() + w_self.mutated(key) return True def lookup(w_self, name): diff --git a/pypy/objspace/std/typetype.py b/pypy/objspace/std/typetype.py --- a/pypy/objspace/std/typetype.py +++ b/pypy/objspace/std/typetype.py @@ -141,7 +141,7 @@ w_oldbestbase.getname(space)) # invalidate the version_tag of all the current subclasses - w_type.mutated() + w_type.mutated(None) # now we can go ahead and change 'w_type.bases_w' saved_bases_w = w_type.bases_w diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py --- a/pypy/rpython/memory/gctransform/asmgcroot.py +++ b/pypy/rpython/memory/gctransform/asmgcroot.py @@ -184,7 +184,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.aid2stack = copy_without_null_values(gcdata.aid2stack) + copy = copy_without_null_values(gcdata.aid2stack) + gcdata.aid2stack.delete() + gcdata.aid2stack = copy def belongs_to_current_thread(framedata): # xxx obscure: the answer is Yes if, as a pointer, framedata diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1449,8 +1449,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.thread_stacks = copy_without_null_values( - gcdata.thread_stacks) + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy def switch_shadow_stacks(new_aid): save_away_current_stack() diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -18,4 +18,5 @@ if __name__ == '__main__': import tool.autopath import pytest - sys.exit(pytest.main()) + import pytest_cov + sys.exit(pytest.main(plugins=[pytest_cov])) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -37,7 +37,7 @@ return self._is_guard def repr(self): - args = self.getargs() + args = self.args if self.descr is not None: args.append('descr=%s' % self.descr) arglist = ', '.join(args) @@ -145,10 +145,10 @@ if operations[0].name == 'debug_merge_point': self.inline_level = int(operations[0].args[0]) m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', - operations[0].getarg(1)) + operations[0].args[1]) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1][1:-1] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -181,7 +181,7 @@ """) ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] - assert chunk.bytecode_name == 'StrLiteralSearch' + assert chunk.bytecode_name.startswith('StrLiteralSearch') def test_parsing_assembler(): backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -251,12 +251,8 @@ CBuilder.have___thread = self.translator.platform.check___thread() if not self.standalone: assert not self.config.translation.instrument - self.eci, cfile, extra = gen_source(db, modulename, targetdir, - self.eci, - defines = defines, - split=self.split) else: - pfname = db.get(pf) + defines['PYPY_STANDALONE'] = db.get(pf) if self.config.translation.instrument: defines['INSTRUMENT'] = 1 if CBuilder.have___thread: @@ -266,11 +262,9 @@ defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( export_symbols=["pypy_main_startup"])) - self.eci, cfile, extra = gen_source_standalone(db, modulename, - targetdir, - self.eci, - entrypointname = pfname, - defines = defines) + self.eci, cfile, extra = gen_source(db, modulename, targetdir, + self.eci, defines=defines, + split=self.split) self.c_source_filename = py.path.local(cfile) self.extrafiles = self.eventually_copy(extra) self.gen_makefile(targetdir, exe_name=exe_name) @@ -435,6 +429,7 @@ class CStandaloneBuilder(CBuilder): standalone = True + split = True executable_name = None shared_library_name = None @@ -948,63 +943,8 @@ return eci.merge(ExternalCompilationInfo(separate_module_files=files)) -def gen_source_standalone(database, modulename, targetdir, eci, - entrypointname, defines={}): - assert database.standalone - if isinstance(targetdir, str): - targetdir = py.path.local(targetdir) - - filename = targetdir.join(modulename + '.c') - f = filename.open('w') - incfilename = targetdir.join('common_header.h') - fi = incfilename.open('w') - - # - # Header - # - print >> f, '#include "common_header.h"' - print >> f - commondefs(defines) - defines['PYPY_STANDALONE'] = entrypointname - for key, value in defines.items(): - print >> fi, '#define %s %s' % (key, value) - - eci.write_c_header(fi) - print >> fi, '#include "src/g_prerequisite.h"' - - fi.close() - - preimplementationlines = list( - pre_include_code_lines(database, database.translator.rtyper)) - - # - # 1) All declarations - # 2) Implementation of functions and global structures and arrays - # - sg = SourceGenerator(database, preimplementationlines) - sg.set_strategy(targetdir) - database.prepare_inline_helpers() - sg.gen_readable_parts_of_source(f) - - # 3) start-up code - print >> f - gen_startupcode(f, database) - - f.close() - - if 'INSTRUMENT' in defines: - fi = incfilename.open('a') - n = database.instrument_ncounter - print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n - fi.close() - - eci = add_extra_files(eci) - eci = eci.convert_sources_to_files(being_main=True) - files, eci = eci.get_module_files() - return eci, filename, sg.getextrafiles() + list(files) - -def gen_source(database, modulename, targetdir, eci, defines={}, split=False): - assert not database.standalone +def gen_source(database, modulename, targetdir, + eci, defines={}, split=False): if isinstance(targetdir, str): targetdir = py.path.local(targetdir) @@ -1046,6 +986,12 @@ gen_startupcode(f, database) f.close() + if 'INSTRUMENT' in defines: + fi = incfilename.open('a') + n = database.instrument_ncounter + print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n + fi.close() + eci = add_extra_files(eci) eci = eci.convert_sources_to_files(being_main=True) files, eci = eci.get_module_files() diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py --- a/pypy/translator/c/test/test_genc.py +++ b/pypy/translator/c/test/test_genc.py @@ -4,7 +4,6 @@ from pypy.translator.translator import TranslationContext from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c import genc -from pypy.translator.c.genc import gen_source from pypy.translator.c.gc import NoneGcPolicy from pypy.objspace.flow.model import Constant, Variable, SpaceOperation from pypy.objspace.flow.model import Block, Link, FunctionGraph diff --git a/pytest.py b/pytest.py --- a/pytest.py +++ b/pytest.py @@ -9,6 +9,8 @@ from _pytest import __version__ if __name__ == '__main__': # if run as a script or by 'python -m pytest' - raise SystemExit(main()) + #XXX: sync to upstream later + import pytest_cov + raise SystemExit(main(plugins=[pytest_cov])) else: _preloadplugins() # to populate pytest.* namespace so help(pytest) works diff --git a/pytest_cov.py b/pytest_cov.py new file mode 100644 --- /dev/null +++ b/pytest_cov.py @@ -0,0 +1,353 @@ +"""produce code coverage reports using the 'coverage' package, including support for distributed testing. + +This plugin produces coverage reports. It supports centralised testing and distributed testing in +both load and each modes. It also supports coverage of subprocesses. + +All features offered by the coverage package should be available, either through pytest-cov or +through coverage's config file. + + +Installation +------------ + +The `pytest-cov`_ package may be installed with pip or easy_install:: + + pip install pytest-cov + easy_install pytest-cov + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov/ + + +Uninstallation +-------------- + +Uninstalling packages is supported by pip:: + + pip uninstall pytest-cov + +However easy_install does not provide an uninstall facility. + +.. IMPORTANT:: + + Ensure that you manually delete the init_cov_core.pth file in your site-packages directory. + + This file starts coverage collection of subprocesses if appropriate during site initialisation + at python startup. + + +Usage +----- + +Centralised Testing +~~~~~~~~~~~~~~~~~~~ + +Centralised testing will report on the combined coverage of the main process and all of it's +subprocesses. + +Running centralised testing:: + + py.test --cov myproj tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Load +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to load will report on the combined coverage of all slaves. +The slaves may be spread out over any number of hosts and each slave may be located anywhere on the +file system. Each slave will have it's subprocesses measured. + +Running distributed testing with dist mode set to load:: + + py.test --cov myproj -n 2 tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Again but spread over different hosts and different directories:: + + py.test --cov myproj --dist load + --tx ssh=memedough at host1//chdir=testenv1 + --tx ssh=memedough at host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Each +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to each will report on the combined coverage of all slaves. +Since each slave is running all tests this allows generating a combined coverage report for multiple +environments. + +Running distributed testing with dist mode set to each:: + + py.test --cov myproj --dist each + --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python + --tx ssh=memedough at host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + ---------------------------------------- coverage ---------------------------------------- + platform linux2, python 2.6.5-final-0 + platform linux2, python 2.7.0-final-0 + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Reporting +--------- + +It is possible to generate any combination of the reports for a single test run. + +The available reports are terminal (with or without missing line numbers shown), HTML, XML and +annotated source code. + +The terminal report without line numbers (default):: + + py.test --cov-report term --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +The terminal report with line numbers:: + + py.test --cov-report term-missing --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover Missing + -------------------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% 24-26, 99, 149, 233-236, 297-298, 369-370 + myproj/feature4286 94 7 92% 183-188, 197 + -------------------------------------------------- + TOTAL 353 20 94% + + +The remaining three reports output to files without showing anything on the terminal (useful for +when the output is going to a continuous integration server):: + + py.test --cov-report html + --cov-report xml + --cov-report annotate + --cov myproj tests/ + + +Coverage Data File +------------------ + +The data file is erased at the beginning of testing to ensure clean data for each test run. + +The data file is left at the end of testing so that it is possible to use normal coverage tools to +examine it. + + +Coverage Config File +-------------------- + +This plugin provides a clean minimal set of command line options that are added to pytest. For +further control of coverage use a coverage config file. + +For example if tests are contained within the directory tree being measured the tests may be +excluded if desired by using a .coveragerc file with the omit option set:: + + py.test --cov-config .coveragerc + --cov myproj + myproj/tests/ + +Where the .coveragerc file contains file globs:: + + [run] + omit = tests/* + +For full details refer to the `coverage config file`_ documentation. + +.. _`coverage config file`: http://nedbatchelder.com/code/coverage/config.html + +Note that this plugin controls some options and setting the option in the config file will have no +effect. These include specifying source to be measured (source option) and all data file handling +(data_file and parallel options). + + +Limitations +----------- + +For distributed testing the slaves must have the pytest-cov package installed. This is needed since +the plugin must be registered through setuptools / distribute for pytest to start the plugin on the +slave. + +For subprocess measurement environment variables must make it from the main process to the +subprocess. The python used by the subprocess must have pytest-cov installed. The subprocess must +do normal site initialisation so that the environment variables can be detected and coverage +started. + + +Acknowledgements +---------------- + +Whilst this plugin has been built fresh from the ground up it has been influenced by the work done +on pytest-coverage (Ross Lawley, James Mills, Holger Krekel) and nose-cover (Jason Pellerin) which are +other coverage plugins. + +Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs. + +Holger Krekel for pytest with its distributed testing support. + +Jason Pellerin for nose. + +Michael Foord for unittest2. + +No doubt others have contributed to these tools as well. +""" + + +def pytest_addoption(parser): + """Add options to control coverage.""" + + group = parser.getgroup('coverage reporting with distributed testing support') + group.addoption('--cov', action='append', default=[], metavar='path', + dest='cov_source', + help='measure coverage for filesystem path (multi-allowed)') + group.addoption('--cov-report', action='append', default=[], metavar='type', + choices=['term', 'term-missing', 'annotate', 'html', 'xml'], + dest='cov_report', + help='type of report to generate: term, term-missing, annotate, html, xml (multi-allowed)') + group.addoption('--cov-config', action='store', default='.coveragerc', metavar='path', + dest='cov_config', + help='config file for coverage, default: .coveragerc') + + +def pytest_configure(config): + """Activate coverage plugin if appropriate.""" + + if config.getvalue('cov_source'): + config.pluginmanager.register(CovPlugin(), '_cov') + + +class CovPlugin(object): + """Use coverage package to produce code coverage reports. + + Delegates all work to a particular implementation based on whether + this test process is centralised, a distributed master or a + distributed slave. + """ + + def __init__(self): + """Creates a coverage pytest plugin. + + We read the rc file that coverage uses to get the data file + name. This is needed since we give coverage through it's API + the data file name. + """ + + # Our implementation is unknown at this time. + self.cov_controller = None + + def pytest_sessionstart(self, session): + """At session start determine our implementation and delegate to it.""" + + import cov_core + + cov_source = session.config.getvalue('cov_source') + cov_report = session.config.getvalue('cov_report') or ['term'] + cov_config = session.config.getvalue('cov_config') + + session_name = session.__class__.__name__ + is_master = (session.config.pluginmanager.hasplugin('dsession') or + session_name == 'DSession') + is_slave = (hasattr(session.config, 'slaveinput') or + session_name == 'SlaveSession') + nodeid = None + + if is_master: + controller_cls = cov_core.DistMaster + elif is_slave: + controller_cls = cov_core.DistSlave + nodeid = session.config.slaveinput.get('slaveid', getattr(session, 'nodeid')) + else: + controller_cls = cov_core.Central + + self.cov_controller = controller_cls(cov_source, + cov_report, + cov_config, + session.config, + nodeid) + + self.cov_controller.start() + + def pytest_configure_node(self, node): + """Delegate to our implementation.""" + + self.cov_controller.configure_node(node) + pytest_configure_node.optionalhook = True + + def pytest_testnodedown(self, node, error): + """Delegate to our implementation.""" + + self.cov_controller.testnodedown(node, error) + pytest_testnodedown.optionalhook = True + + def pytest_sessionfinish(self, session, exitstatus): + """Delegate to our implementation.""" + + self.cov_controller.finish() + + def pytest_terminal_summary(self, terminalreporter): + """Delegate to our implementation.""" + + self.cov_controller.summary(terminalreporter._tw) + + +def pytest_funcarg__cov(request): + """A pytest funcarg that provides access to the underlying coverage object.""" + + # Check with hasplugin to avoid getplugin exception in older pytest. + if request.config.pluginmanager.hasplugin('_cov'): + plugin = request.config.pluginmanager.getplugin('_cov') + if plugin.cov_controller: + return plugin.cov_controller.cov + return None From noreply at buildbot.pypy.org Fri Jul 22 08:45:37 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 22 Jul 2011 08:45:37 +0200 (CEST) Subject: [pypy-commit] pypy streamio-bufout: close for merge Message-ID: <20110722064537.ABBDF82961@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: streamio-bufout Changeset: r45857:89c23d06a9c3 Date: 2011-07-22 00:44 -0600 http://bitbucket.org/pypy/pypy/changeset/89c23d06a9c3/ Log: close for merge From noreply at buildbot.pypy.org Fri Jul 22 08:49:01 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 22 Jul 2011 08:49:01 +0200 (CEST) Subject: [pypy-commit] pypy default: merged streamio-bufout Message-ID: <20110722064901.DA3AC82961@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45858:a02ff8434e20 Date: 2011-07-22 00:48 -0600 http://bitbucket.org/pypy/pypy/changeset/a02ff8434e20/ Log: merged streamio-bufout diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -875,28 +875,32 @@ if bufsize == -1: # Get default from the class bufsize = self.bufsize self.bufsize = bufsize # buffer size (hint only) - self.buf = "" + self.buf = [] + self.buflen = 0 def flush_buffers(self): if self.buf: - self.do_write(self.buf) - self.buf = "" + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 def tell(self): - return self.do_tell() + len(self.buf) + return self.do_tell() + self.buflen def write(self, data): - buflen = len(self.buf) + buflen = self.buflen datalen = len(data) if datalen + buflen < self.bufsize: - self.buf += data + self.buf.append(data) + self.buflen += datalen elif buflen: - slice = self.bufsize - buflen - assert slice >= 0 - self.buf += data[:slice] - self.do_write(self.buf) - self.buf = "" - self.write(data[slice:]) + i = self.bufsize - buflen + assert i >= 0 + self.buf.append(data[:i]) + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 + self.write(data[i:]) else: self.do_write(data) @@ -922,11 +926,27 @@ """ def write(self, data): - BufferingOutputStream.write(self, data) - p = self.buf.rfind('\n') + 1 - if p >= 0: - self.do_write(self.buf[:p]) - self.buf = self.buf[p:] + p = data.rfind('\n') + 1 + assert p >= 0 + if self.buflen + len(data) < self.bufsize: + if p == 0: + self.buf.append(data) + self.buflen += len(data) + else: + if self.buflen: + self.do_write(''.join(self.buf)) + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) + else: + if self.buflen + p < self.bufsize: + p = self.bufsize - self.buflen + if self.buflen: + self.do_write(''.join(self.buf)) + assert p >= 0 + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) # ____________________________________________________________ From noreply at buildbot.pypy.org Fri Jul 22 09:51:09 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 22 Jul 2011 09:51:09 +0200 (CEST) Subject: [pypy-commit] pypy default: bah, test&fix for a bug introduced by 065c98a10f0d (commit message: "that way easy" :-)) Message-ID: <20110722075109.3AEB782961@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45859:0a106042ba51 Date: 2011-07-22 09:50 +0200 http://bitbucket.org/pypy/pypy/changeset/0a106042ba51/ Log: bah, test&fix for a bug introduced by 065c98a10f0d (commit message: "that way easy" :-)) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -37,7 +37,7 @@ return self._is_guard def repr(self): - args = self.args + args = self.args[:] if self.descr is not None: args.append('descr=%s' % self.descr) arglist = ', '.join(args) diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,6 +1,6 @@ from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, Function, adjust_bridges, - import_log) + import_log, Op) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys @@ -225,3 +225,9 @@ assert 'cmp' in loops[1].operations[1].asm # bridge assert 'jo' in loops[3].operations[3].asm + +def test_Op_repr_is_pure(): + op = Op('foobar', ['a', 'b'], 'c', 'mydescr') + myrepr = 'c = foobar(a, b, descr=mydescr)' + assert op.repr() == myrepr + assert op.repr() == myrepr # do it twice From noreply at buildbot.pypy.org Fri Jul 22 10:15:51 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 22 Jul 2011 10:15:51 +0200 (CEST) Subject: [pypy-commit] pypy default: this setfield_gc is now put after the others, not sure why Message-ID: <20110722081551.3518B82961@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45860:5f276f80b50d Date: 2011-07-22 10:15 +0200 http://bitbucket.org/pypy/pypy/changeset/5f276f80b50d/ Log: this setfield_gc is now put after the others, not sure why diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -92,10 +92,10 @@ p51 = new_with_vtable(21136408) setfield_gc(p51, p28, descr=) setfield_gc(p51, ConstPtr(ptr51), descr=) - setfield_gc(p51, i29, descr=) setfield_gc(p51, 1, descr=) setfield_gc(p51, 16, descr=) setfield_gc(p51, p28, descr=) + setfield_gc(p51, i29, descr=) p55 = call(ConstClass(parse_digit_string), p51, descr=) guard_no_exception(descr=...) i57 = call(ConstClass(rbigint.toint), p55, descr=) @@ -104,4 +104,4 @@ guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) - """) \ No newline at end of file + """) From noreply at buildbot.pypy.org Fri Jul 22 10:19:26 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 22 Jul 2011 10:19:26 +0200 (CEST) Subject: [pypy-commit] pypy default: skip these tests with -A Message-ID: <20110722081926.4EDC082961@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45861:52ac2c66da7a Date: 2011-07-22 10:19 +0200 http://bitbucket.org/pypy/pypy/changeset/52ac2c66da7a/ Log: skip these tests with -A diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py --- a/pypy/objspace/std/test/test_identitydict.py +++ b/pypy/objspace/std/test/test_identitydict.py @@ -1,3 +1,4 @@ +import py from pypy.interpreter.gateway import interp2app from pypy.conftest import gettestobjspace from pypy.conftest import option @@ -8,6 +9,8 @@ from pypy.objspace.std import identitydict cls.space = gettestobjspace( **{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("interp2app doesn't work on appdirect") def compares_by_identity(space, w_cls): return space.wrap(w_cls.compares_by_identity()) @@ -49,7 +52,7 @@ def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) if option.runappdirect: - py.test.skip("__repr__ doesn't work on appdirect") + py.test.skip("interp2app doesn't work on appdirect") def w_uses_identity_strategy(self, obj): import __pypy__ From noreply at buildbot.pypy.org Fri Jul 22 10:21:55 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 22 Jul 2011 10:21:55 +0200 (CEST) Subject: [pypy-commit] pypy default: I got a value of 0.014 on tannit, use a more relaxed limit Message-ID: <20110722082155.9F9F082961@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45862:aa59a8ff9a8a Date: 2011-07-22 10:22 +0200 http://bitbucket.org/pypy/pypy/changeset/aa59a8ff9a8a/ Log: I got a value of 0.014 on tannit, use a more relaxed limit diff --git a/pypy/module/select/test/test_epoll.py b/pypy/module/select/test/test_epoll.py --- a/pypy/module/select/test/test_epoll.py +++ b/pypy/module/select/test/test_epoll.py @@ -138,7 +138,7 @@ expected.sort() assert events == expected - assert then - now < 0.01 + assert then - now < 0.02 now = time.time() events = ep.poll(timeout=2.1, maxevents=4) @@ -151,7 +151,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 events.sort() expected = [ @@ -168,7 +168,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 expected = [(server.fileno(), select.EPOLLOUT)] assert events == expected @@ -192,7 +192,7 @@ now = time.time() ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 server.close() ep.unregister(fd) From noreply at buildbot.pypy.org Fri Jul 22 10:55:59 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 10:55:59 +0200 (CEST) Subject: [pypy-commit] pypy default: we always require opt level Message-ID: <20110722085559.A757D82961@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45863:e843aa0db385 Date: 2011-07-22 10:54 +0200 http://bitbucket.org/pypy/pypy/changeset/e843aa0db385/ Log: we always require opt level diff --git a/pypy/tool/release/win32build.py b/pypy/tool/release/win32build.py --- a/pypy/tool/release/win32build.py +++ b/pypy/tool/release/win32build.py @@ -24,6 +24,6 @@ shutil.copy(str(pypydir.join('..', '..', 'expat-2.0.1', 'win32', 'bin', 'release', 'libexpat.dll')), str(builddir)) make_pypy('', ['-Ojit']) -make_pypy('-nojit', []) +make_pypy('-nojit', ['-O2']) #make_pypy('-stackless', [--stackless]) #make_pypy('-sandbox', [--sandbox]) From noreply at buildbot.pypy.org Fri Jul 22 10:56:00 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 10:56:00 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20110722085600.DFD1882961@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45864:275b0363057a Date: 2011-07-22 10:55 +0200 http://bitbucket.org/pypy/pypy/changeset/275b0363057a/ Log: merge diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -17,8 +17,8 @@ reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) -slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) -slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) def add(v1, v2): return v1 + v2 @@ -247,23 +247,25 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) - def _sliceloop1(self, start, stop, step, arr, storage): + def _sliceloop1(self, start, stop, step, source, dest): i = start j = 0 while i < stop: - #slice_driver1.jit_merge_point(signature=arr.signature, - # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) - storage[i] = arr.eval(j) + slice_driver1.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) j += 1 i += step - def _sliceloop2(self, start, stop, step, arr, storage): + def _sliceloop2(self, start, stop, step, source, dest): i = start j = 0 while i > stop: - #slice_driver2.jit_merge_point(signature=arr.signature, - # step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) - storage[i] = arr.eval(j) + slice_driver2.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) j += 1 i += step @@ -448,9 +450,9 @@ stop = self.calc_index(stop) step = self.step * step if step > 0: - self._sliceloop1(start, stop, step, arr, self.parent.storage) + self._sliceloop1(start, stop, step, arr, self.parent) else: - self._sliceloop2(start, stop, step, arr, self.parent.storage) + self._sliceloop2(start, stop, step, arr, self.parent) def calc_index(self, item): return (self.start + item * self.step) @@ -489,9 +491,9 @@ if not isinstance(arr, BaseArray): arr = convert_to_array(space, arr) if step > 0: - self._sliceloop1(start, stop, step, arr, self.storage) + self._sliceloop1(start, stop, step, arr, self) else: - self._sliceloop2(start, stop, step, arr, self.storage) + self._sliceloop2(start, stop, step, arr, self) def __del__(self): lltype.free(self.storage, flavor='raw') diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -173,7 +173,7 @@ def test_radd(self): from numpy import array - r = 3 + array(range(3))\ + r = 3 + array(range(3)) for i in range(3): assert r[i] == i + 3 diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -92,10 +92,10 @@ p51 = new_with_vtable(21136408) setfield_gc(p51, p28, descr=) setfield_gc(p51, ConstPtr(ptr51), descr=) - setfield_gc(p51, i29, descr=) setfield_gc(p51, 1, descr=) setfield_gc(p51, 16, descr=) setfield_gc(p51, p28, descr=) + setfield_gc(p51, i29, descr=) p55 = call(ConstClass(parse_digit_string), p51, descr=) guard_no_exception(descr=...) i57 = call(ConstClass(rbigint.toint), p55, descr=) @@ -104,4 +104,4 @@ guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) - """) \ No newline at end of file + """) diff --git a/pypy/module/select/test/test_epoll.py b/pypy/module/select/test/test_epoll.py --- a/pypy/module/select/test/test_epoll.py +++ b/pypy/module/select/test/test_epoll.py @@ -138,7 +138,7 @@ expected.sort() assert events == expected - assert then - now < 0.01 + assert then - now < 0.02 now = time.time() events = ep.poll(timeout=2.1, maxevents=4) @@ -151,7 +151,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 events.sort() expected = [ @@ -168,7 +168,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 expected = [(server.fileno(), select.EPOLLOUT)] assert events == expected @@ -192,7 +192,7 @@ now = time.time() ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 server.close() ep.unregister(fd) diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py --- a/pypy/objspace/std/test/test_identitydict.py +++ b/pypy/objspace/std/test/test_identitydict.py @@ -1,3 +1,4 @@ +import py from pypy.interpreter.gateway import interp2app from pypy.conftest import gettestobjspace from pypy.conftest import option @@ -8,6 +9,8 @@ from pypy.objspace.std import identitydict cls.space = gettestobjspace( **{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("interp2app doesn't work on appdirect") def compares_by_identity(space, w_cls): return space.wrap(w_cls.compares_by_identity()) @@ -49,7 +52,7 @@ def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) if option.runappdirect: - py.test.skip("__repr__ doesn't work on appdirect") + py.test.skip("interp2app doesn't work on appdirect") def w_uses_identity_strategy(self, obj): import __pypy__ diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -875,28 +875,32 @@ if bufsize == -1: # Get default from the class bufsize = self.bufsize self.bufsize = bufsize # buffer size (hint only) - self.buf = "" + self.buf = [] + self.buflen = 0 def flush_buffers(self): if self.buf: - self.do_write(self.buf) - self.buf = "" + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 def tell(self): - return self.do_tell() + len(self.buf) + return self.do_tell() + self.buflen def write(self, data): - buflen = len(self.buf) + buflen = self.buflen datalen = len(data) if datalen + buflen < self.bufsize: - self.buf += data + self.buf.append(data) + self.buflen += datalen elif buflen: - slice = self.bufsize - buflen - assert slice >= 0 - self.buf += data[:slice] - self.do_write(self.buf) - self.buf = "" - self.write(data[slice:]) + i = self.bufsize - buflen + assert i >= 0 + self.buf.append(data[:i]) + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 + self.write(data[i:]) else: self.do_write(data) @@ -922,11 +926,27 @@ """ def write(self, data): - BufferingOutputStream.write(self, data) - p = self.buf.rfind('\n') + 1 - if p >= 0: - self.do_write(self.buf[:p]) - self.buf = self.buf[p:] + p = data.rfind('\n') + 1 + assert p >= 0 + if self.buflen + len(data) < self.bufsize: + if p == 0: + self.buf.append(data) + self.buflen += len(data) + else: + if self.buflen: + self.do_write(''.join(self.buf)) + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) + else: + if self.buflen + p < self.bufsize: + p = self.bufsize - self.buflen + if self.buflen: + self.do_write(''.join(self.buf)) + assert p >= 0 + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) # ____________________________________________________________ diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -37,7 +37,7 @@ return self._is_guard def repr(self): - args = self.args + args = self.args[:] if self.descr is not None: args.append('descr=%s' % self.descr) arglist = ', '.join(args) diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,6 +1,6 @@ from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, Function, adjust_bridges, - import_log) + import_log, Op) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys @@ -225,3 +225,9 @@ assert 'cmp' in loops[1].operations[1].asm # bridge assert 'jo' in loops[3].operations[3].asm + +def test_Op_repr_is_pure(): + op = Op('foobar', ['a', 'b'], 'c', 'mydescr') + myrepr = 'c = foobar(a, b, descr=mydescr)' + assert op.repr() == myrepr + assert op.repr() == myrepr # do it twice From noreply at buildbot.pypy.org Fri Jul 22 10:58:57 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 10:58:57 +0200 (CEST) Subject: [pypy-commit] pypy default: (brutal_chaos) add instructions about large builds Message-ID: <20110722085857.249B482961@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45865:3512ed4d4408 Date: 2011-07-22 10:58 +0200 http://bitbucket.org/pypy/pypy/changeset/3512ed4d4408/ Log: (brutal_chaos) add instructions about large builds diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -32,6 +32,15 @@ modules that relies on third-party libraries. See below how to get and build them. +Preping Windows for the Large Build +----------------------------------- + +Follow http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 to allow Windows up to 3GB for 32bit applications if you are on a 32bit version of windows. If you are using Visual C++ 2008 (untested with 2005), then you will have a utility called editbin.exe within Visual Studio 9.0\VC\bin. You will need to execute:: + + editbin /largeaddressaware pypy.exe + +on the pypy.exe or python.exe you are using to buld the new pypy. Reboot now if you followed the 3G instructions for 32bit windows. + Installing external packages ---------------------------- From noreply at buildbot.pypy.org Fri Jul 22 11:34:10 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 11:34:10 +0200 (CEST) Subject: [pypy-commit] pypy default: I think getargs() here was intentional Message-ID: <20110722093410.D532A82961@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45866:db35aeee54c8 Date: 2011-07-22 11:34 +0200 http://bitbucket.org/pypy/pypy/changeset/db35aeee54c8/ Log: I think getargs() here was intentional diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -30,6 +30,9 @@ def getres(self): return self._getvar(self.res) + def getdescr(self): + return self.descr + def _getvar(self, v): return v @@ -37,9 +40,9 @@ return self._is_guard def repr(self): - args = self.args[:] + args = self.getargs() if self.descr is not None: - args.append('descr=%s' % self.descr) + args.append('descr=%s' % self.getdescr()) arglist = ', '.join(args) if self.res is not None: return '%s = %s(%s)' % (self.getres(), self.name, arglist) From noreply at buildbot.pypy.org Fri Jul 22 11:36:51 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 11:36:51 +0200 (CEST) Subject: [pypy-commit] jitviewer default: improve demos and escape the descr Message-ID: <20110722093651.7EE6B82961@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r153:df44fc655ba2 Date: 2011-07-22 11:34 +0200 http://bitbucket.org/pypy/jitviewer/changeset/df44fc655ba2/ Log: improve demos and escape the descr diff --git a/_jitviewer/parser.py b/_jitviewer/parser.py --- a/_jitviewer/parser.py +++ b/_jitviewer/parser.py @@ -34,12 +34,16 @@ Subclass of Op with human-friendly html representation """ + def html_class(self): + if self.is_guard(): + return "single-operation guard" + elif 'call' in self.name: + return "single-operation call" + else: + return "single-operation" + def html_repr(self): s = getattr(self, 'repr_' + self.name, self.repr)() - if self.is_guard(): - s = 'guard(' + s + ')' - elif 'call' in self.name: - s = '' + s + '' return Html(s) def _getvar(self, v): @@ -109,6 +113,12 @@ return ("" % no + self.repr() + "") + def getdescr(self): + return cgi.escape(self.descr) + + #def repr_call_assembler(self): + # xxxx + class ParserWithHtmlRepr(parser.SimpleParser): Op = OpHtml diff --git a/_jitviewer/templates/loop.html b/_jitviewer/templates/loop.html --- a/_jitviewer/templates/loop.html +++ b/_jitviewer/templates/loop.html @@ -14,7 +14,7 @@ {% if op.bridge %} {{op.html_repr()}} >>show bridge (taken {{op.percentage}}%)
      {% else %} - {{op.html_repr()}}
      + {{op.html_repr()}}
      {% if op.asm %}

      {{op.asm}}

      {% endif %} diff --git a/demo.py b/demo.py deleted file mode 100644 --- a/demo.py +++ /dev/null @@ -1,24 +0,0 @@ - -import re -from numpy import zeros - -def g(): - return 1 - -def loop(): - i = 0 - while i < 10000: - if i & 2: - i += g() - else: - i += 3 - -def other_loop(): - for i in range(2000): - re.search("0", str(i)) - -if __name__ == '__main__': - loop() - other_loop() - a = zeros(10000) - repr(a + a / a) diff --git a/log b/log --- a/log +++ b/log @@ -1,747 +1,2130 @@ -[1af179b69b26d] {jit-backend-counts -[1af179b6aaa20] jit-backend-counts} -[1af179bd270bb] {jit-log-opt-loop -# Loop 0 : loop with 35 ops +[4cac93478f8a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[4cac9348d29a] jit-backend-dump} +[4cac93490d4d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[4cac93492757] jit-backend-dump} +[4cac934942ae] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b908a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[4cac93496777] jit-backend-dump} +[4cac934976da] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b913d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[4cac93499888] jit-backend-dump} +[4cac9349bec2] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 +[4cac9349dd04] jit-backend-dump} +[4cac934a41de] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b928e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 +[4cac934a5e7f] jit-backend-dump} +[4cac934aad48] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 +[4cac934ad355] jit-backend-dump} +[4cac934ae420] {jit-backend-counts +[4cac934ae846] jit-backend-counts} +[4cac9a58f8bb] {jit-backend +[4cac9a6633f5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b93d5 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C2540100000000488B0C25E8C2540148C70425E8C2540100000000488B0425F0C2540148C70425F0C254010000000048898570FFFFFF49BB30A0CFB8A07F0000498B034883C00149BB30A0CFB8A07F00004989034983F8030F8500000000813AD03000000F8500000000488B7A104885FF0F84000000004C8B4208488B47204885C00F8500000000488B47084939C00F8C0000000048C74210000000004983FA000F85000000004D8B5110418139302301000F85000000004D8B49184983F9020F85000000004885F60F84000000004D85D20F85000000004D8B576841C687950000000141F64704017418515641524C89FF4C89EE49C7C310734D0041FFD3415A5E594D896F5041F64704017418515641524C89FF4C89E649C7C310734D0041FFD3415A5E594D89677841C687960000000049C747600000000049C787800000000200000049C747582A00000041F6420401741F515641524C89D74889F248C7C60000000049C7C380DEB20041FFD3415A5E594989721041F6420401741F515641524C89D748C7C6010000004889DA49C7C380DEB20041FFD3415A5E5949895A1849C742200000000041F6420401741F515641524C89D748C7C6030000004889CA49C7C380DEB20041FFD3415A5E5949894A28488B8D70FFFFFF41F6420401741F515641524C89D748C7C6040000004889CA49C7C380DEB20041FFD3415A5E5949894A304889342590C2540149C7C340BC920041FFD348C7C000000000488D65D8415F415E415D415C5B5DC3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA570FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D94C8B5D404C899D70FFFFFFE98BFDFFFF49BB00905BB6A07F000041FFD321383C343029241D180C080440030300000049BB00905BB6A07F000041FFD3383C0834302924180C0440030400000049BB00905BB6A07F000041FFD3383C081C34302924180C0440030500000049BB00905BB6A07F000041FFD3383C08211C0034302924180C0440030600000049BB00905BB6A07F000041FFD3383C08211C34302924180C0440030700000049BB00905BB6A07F000041FFD329383C343024180C0440030800000049BB00905BB6A07F000041FFD3383C24343028180C0440030900000049BB00905BB6A07F000041FFD3383C25343028180C0440030A00000049BB00905BB6A07F000041FFD3383C183430280C0440030B00000049BB00905BB6A07F000041FFD3383C182834300C0440030C000000 +[4cac9a688c4a] jit-backend-dump} +[4cac9a68ad9c] {jit-backend-addr +Loop #0 ( #19 FOR_ITER) has address 7fa0b65b94d0 to 7fa0b65b96c6 (bootstrap 7fa0b65b93d5) +[4cac9a68d731] jit-backend-addr} +[4cac9a68e7e9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b93e5 +0 70FFFFFF +[4cac9a690058] jit-backend-dump} +[4cac9a691034] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b94f4 +0 4D020000 +[4cac9a6922d1] jit-backend-dump} +[4cac9a692c27] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9500 +0 60020000 +[4cac9a693cd5] jit-backend-dump} +[4cac9a6944c3] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b950d +0 70020000 +[4cac9a695535] jit-backend-dump} +[4cac9a695d05] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b951e +0 7D020000 +[4cac9a696d8b] jit-backend-dump} +[4cac9a697597] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b952b +0 90020000 +[4cac9a698893] jit-backend-dump} +[4cac9a69918f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b953d +0 9D020000 +[4cac9a69a2ce] jit-backend-dump} +[4cac9a69aac6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b954e +0 A8020000 +[4cac9a69bb3d] jit-backend-dump} +[4cac9a69c32b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b955c +0 B6020000 +[4cac9a69d3ac] jit-backend-dump} +[4cac9a69db90] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9565 +0 C9020000 +[4cac9a69ec11] jit-backend-dump} +[4cac9a69f517] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b956e +0 DB020000 +[4cac9a6a0719] jit-backend-dump} +[4cac9a6a3351] jit-backend} +[4cac9a6a4959] {jit-log-opt-loop +# Loop 0 : entry bridge with 36 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11, p12] +debug_merge_point(0, ' #19 FOR_ITER') ++281: guard_value(i6, 3, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12] ++291: guard_class(p10, 20808496, descr=) [p1, p0, p10, p2, p3, i4, p5, p8, p9, p11, p12] ++303: p15 = getfield_gc(p10, descr=) ++307: guard_nonnull(p15, descr=) [p1, p0, p10, p15, p2, p3, i4, p5, p8, p9, p11, p12] ++316: i16 = getfield_gc(p10, descr=) ++320: p17 = getfield_gc(p15, descr=) ++324: guard_isnull(p17, descr=) [p1, p0, p10, i16, p15, p17, p2, p3, i4, p5, p8, p9, p11, p12] ++333: i18 = getfield_gc(p15, descr=) ++337: i19 = int_ge(i16, i18) +guard_true(i19, descr=) [p1, p0, p10, i16, p15, p2, p3, i4, p5, p8, p9, p11, p12] ++346: setfield_gc(p10, ConstPtr(ptr20), descr=) ++354: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p11, p12] +debug_merge_point(0, ' #38 POP_BLOCK') ++364: p22 = getfield_gc_pure(p5, descr=) ++368: guard_class(p5, 20870544, descr=) [p1, p0, p5, p2, p3, p22, p8, p9, p11, p12] ++381: i24 = getfield_gc_pure(p5, descr=) ++385: guard_value(i24, 2, descr=) [p1, p0, i24, p2, p3, p22, p8, p9, p11, p12] +debug_merge_point(0, ' #39 LOAD_FAST') ++395: guard_nonnull(p8, descr=) [p1, p0, p8, p2, p3, p22, p9, p11, p12] +debug_merge_point(0, ' #42 RETURN_VALUE') ++404: guard_isnull(p22, descr=) [p1, p0, p8, p22, p2, p3, p9, p11, p12] ++413: p26 = getfield_gc(p0, descr=) ++417: setfield_gc(p0, 1, descr=) +setfield_gc(p0, p2, descr=) +setfield_gc(p0, p3, descr=) ++495: setfield_gc(p0, 0, descr=) ++503: setfield_gc(p0, ConstPtr(ptr28), descr=) ++511: setfield_gc(p0, 2, descr=) ++522: setfield_gc(p0, 42, descr=) +setarrayitem_gc(p26, 0, p8, descr=) +setarrayitem_gc(p26, 1, p9, descr=) ++614: setarrayitem_gc(p26, 2, ConstPtr(ptr34), descr=) +setarrayitem_gc(p26, 3, p11, descr=) +setarrayitem_gc(p26, 4, p12, descr=) ++713: finish(p8, descr=) ++753: --end of the loop-- +[4cac9a791478] jit-log-opt-loop} +[4cac9adac196] {jit-backend +[4cac9ae4da16] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9888 +0 488DA50000000049BB38A0CFB8A07F0000498B0B4883C10149BB38A0CFB8A07F000049890B488B4F10488B7F184C89C04C0FAFC74C01C14883C001488942084983FA000F85000000004883FE017206813E980700000F850000000049BB88F377B6A07F00004D39DC0F85000000004C8B66084983C4010F8000000000488B3425A0536B024883EE0148893425A0536B024883FE000F8C0000000048898D68FFFFFF48899560FFFFFF4C898D58FFFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C89600848898550FFFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C8B9568FFFFFF4C89500848898548FFFFFF49BB88F377B6A07F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00300000048C7C713000000488BB550FFFFFF488B9D48FFFFFF488B9560FFFFFF48C7C10000000048C78570FFFFFF0000000049BBD0945BB6A07F000041FFE349BB00905BB6A07F000041FFD329383C343024180C084005030D00000049BB00905BB6A07F000041FFD3383C18343024084005030E00000049BB00905BB6A07F000041FFD3383C30342418084005030F00000049BB00905BB6A07F000041FFD3383C183134240805031000000049BB00905BB6A07F000041FFD3383C34240831050311000000 +[4cac9ae59dbe] jit-backend-dump} +[4cac9ae5b714] {jit-backend-addr +Bridge out of guard 7 has address 7fa0b65b9888 to 7fa0b65b9a2f +[4cac9ae5e1a4] jit-backend-addr} +[4cac9ae5f098] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b988b +0 C0FEFFFF +[4cac9ae60d9c] jit-backend-dump} +[4cac9ae61ca2] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b98cd +0 5E010000 +[4cac9ae6dd50] jit-backend-dump} +[4cac9ae6ec8c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b98df +0 69010000 +[4cac9ae702fa] jit-backend-dump} +[4cac9ae70daa] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b98f2 +0 71010000 +[4cac9ae72460] jit-backend-dump} +[4cac9ae72f28] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9900 +0 7E010000 +[4cac9ae74362] jit-backend-dump} +[4cac9ae74cf8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b991e +0 7A010000 +[4cac9ae76156] jit-backend-dump} +[4cac9ae77284] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b952b +0 59030000 +[4cac9ae786dc] jit-backend-dump} +[4cac9ae792a6] jit-backend} +[4cac9ae7c63c] {jit-log-opt-bridge +# bridge out of Guard 7 with 29 ops +[p0, p1, p2, i3, p4, p5, p6, i7, p8, p9, p10, p11, p12] ++37: i13 = getfield_gc(p4, descr=) ++41: i14 = getfield_gc(p4, descr=) ++45: i15 = int_mul(i3, i14) ++52: i16 = int_add(i13, i15) ++55: i18 = int_add(i3, 1) ++59: setfield_gc(p2, i18, descr=) ++63: guard_value(i7, 0, descr=) [i7, p0, p1, p5, p6, p8, p9, p10, p2, p12, i16] +debug_merge_point(0, ' #22 STORE_FAST') +debug_merge_point(0, ' #25 LOAD_FAST') ++73: guard_nonnull_class(p9, ConstClass(W_IntObject), descr=) [p0, p1, p9, p5, p6, p8, p2, p12, i16] +debug_merge_point(0, ' #28 LOAD_CONST') ++91: guard_value(p6, ConstPtr(ptr21), descr=) [p0, p1, p6, p5, p8, p9, p2, p12, i16] +debug_merge_point(0, ' #31 INPLACE_ADD') ++110: i22 = getfield_gc_pure(p9, descr=) ++114: i24 = int_add_ovf(i22, 1) +guard_no_overflow(, descr=) [p0, p1, p9, i24, p5, p8, p2, i16] +debug_merge_point(0, ' #32 STORE_FAST') +debug_merge_point(0, ' #35 JUMP_ABSOLUTE') ++124: i26 = getfield_raw(40588192, descr=) ++132: i28 = int_sub(i26, 1) ++136: setfield_raw(40588192, i28, descr=) ++144: i30 = int_lt(i28, 0) +guard_false(i30, descr=) [p0, p1, p5, p8, p2, i24, i16] +debug_merge_point(0, ' #19 FOR_ITER') ++154: p32 = new_with_vtable(ConstClass(W_IntObject)) ++238: setfield_gc(p32, i24, descr=) ++242: p34 = new_with_vtable(ConstClass(W_IntObject)) ++312: setfield_gc(p34, i16, descr=) ++323: jump(p1, p0, p5, ConstPtr(ptr35), 0, p8, 3, 19, p32, p34, p2, ConstPtr(ptr39), ConstPtr(ptr40), descr=) ++423: --end of the loop-- +[4cac9aebd2aa] jit-log-opt-bridge} +[4cac9b1ed9a0] {jit-backend +[4cac9b2540ba] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9ab5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B014C8B3425D84D5B0149BB40A0CFB8A07F00004D8B2B4983C50149BB40A0CFB8A07F00004D892B4981FE102700000F8D000000004C89F048C7C10200000048898550FFFFFF489948F7F94889D048C1FA3F49C7C6020000004921D64C01F04883F8000F85000000004C89F84983C7010F8000000000488B8550FFFFFF4883C0014C8B3425A0536B024983EE014C893425A0536B024983FE000F8C0000000048898548FFFFFF4C8BB548FFFFFFE958FFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA540FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C74D89CEE9FBFEFFFF49BB00905BB6A07F000041FFD34440484C393D031200000049BB00905BB6A07F000041FFD34440484C01513D031300000049BB00905BB6A07F000041FFD344403D484C075101031400000049BB00905BB6A07F000041FFD34440484C013D0707070315000000 +[4cac9b26ab54] jit-backend-dump} +[4cac9b26bd8a] {jit-backend-addr +Loop #1 ( #15 LOAD_FAST) has address 7fa0b65b9b45 to 7fa0b65b9bed (bootstrap 7fa0b65b9ab5) +[4cac9b26e0d0] jit-backend-addr} +[4cac9b26f1e6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9ac5 +0 40FFFFFF +[4cac9b270e96] jit-backend-dump} +[4cac9b271d42] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9b6c +0 DA000000 +[4cac9b2734ac] jit-backend-dump} +[4cac9b273ff2] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9ba0 +0 BE000000 +[4cac9b2754e0] jit-backend-dump} +[4cac9b275efa] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9bad +0 CA000000 +[4cac9b277334] jit-backend-dump} +[4cac9b277cd0] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9bd6 +0 BB000000 +[4cac9b2790ec] jit-backend-dump} +[4cac9b279f2c] jit-backend} +[4cac9b27b3fc] {jit-log-opt-loop +# Loop 1 : loop with 35 ops [p0, p1, p2, p3, i4, i5] -debug_merge_point(0, ' #15 LOAD_FAST') -debug_merge_point(0, ' #18 LOAD_CONST') -debug_merge_point(0, ' #21 COMPARE_OP') +debug_merge_point(0, ' #15 LOAD_FAST') +debug_merge_point(0, ' #18 LOAD_CONST') +debug_merge_point(0, ' #21 COMPARE_OP') +174: i7 = int_lt(i5, 10000) -guard_true(i7, descr=) [p1, p0, p2, p3, i4, i5] -debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') -debug_merge_point(0, ' #27 LOAD_FAST') -debug_merge_point(0, ' #30 LOAD_CONST') -debug_merge_point(0, ' #33 BINARY_MODULO') +guard_true(i7, descr=) [p1, p0, p2, p3, i5, i4] +debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #27 LOAD_FAST') +debug_merge_point(0, ' #30 LOAD_CONST') +debug_merge_point(0, ' #33 BINARY_MODULO') +187: i9 = int_mod(i5, 2) +209: i11 = int_rshift(i9, 63) +216: i12 = int_and(2, i11) +226: i13 = int_add(i9, i12) -debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') +229: i14 = int_is_true(i13) -guard_false(i14, descr=) [p1, p0, p2, p3, i13, i4, i5] -debug_merge_point(0, ' #50 LOAD_FAST') -debug_merge_point(0, ' #53 LOAD_CONST') -debug_merge_point(0, ' #56 INPLACE_ADD') -+239: i16 = int_add_ovf(i4, 2) -guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i4, i5] -debug_merge_point(0, ' #57 STORE_FAST') -debug_merge_point(0, ' #60 LOAD_FAST') -debug_merge_point(0, ' #63 LOAD_CONST') -debug_merge_point(0, ' #66 INPLACE_ADD') +guard_false(i14, descr=) [p1, p0, p2, p3, i13, i5, i4] +debug_merge_point(0, ' #53 LOAD_FAST') +debug_merge_point(0, ' #56 LOAD_CONST') +debug_merge_point(0, ' #59 INPLACE_ADD') ++239: i16 = int_add_ovf(i4, 1) +guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i5, i4] +debug_merge_point(0, ' #60 STORE_FAST') +debug_merge_point(0, ' #63 LOAD_FAST') +debug_merge_point(0, ' #66 LOAD_CONST') +debug_merge_point(0, ' #69 INPLACE_ADD') +252: i19 = int_add(i5, 1) -debug_merge_point(0, ' #67 STORE_FAST') -debug_merge_point(0, ' #70 JUMP_ABSOLUTE') -+263: i21 = getfield_raw(40681184, descr=) +debug_merge_point(0, ' #70 STORE_FAST') +debug_merge_point(0, ' #73 JUMP_ABSOLUTE') ++263: i21 = getfield_raw(40588192, descr=) +271: i23 = int_sub(i21, 1) -+275: setfield_raw(40681184, i23, descr=) ++275: setfield_raw(40588192, i23, descr=) +283: i25 = int_lt(i23, 0) -guard_false(i25, descr=) [p1, p0, p2, p3, i16, i19, None, None, None] -debug_merge_point(0, ' #15 LOAD_FAST') -+293: jump(p0, p1, p2, p3, i16, i19, descr=) +guard_false(i25, descr=) [p1, p0, p2, p3, i19, i16, None, None, None] +debug_merge_point(0, ' #15 LOAD_FAST') ++293: jump(p0, p1, p2, p3, i16, i19, descr=) +312: --end of the loop-- -[1af179bdc2aa7] jit-log-opt-loop} -[1af179be14e5b] {jit-log-opt-loop -# Loop 1 : entry bridge with 44 ops +[4cac9b2b109c] jit-log-opt-loop} +[4cac9b2b409c] {jit-backend +[4cac9b78442f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9cb0 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C2540100000000488B0C25E8C2540148C70425E8C254010000000049BB48A0CFB8A07F0000498B034883C00149BB48A0CFB8A07F00004989034983F8020F85000000004883FB017206813B980700000F85000000004983FA000F850000000049BB40F477B6A07F00004D39DC0F8500000000488B4B084881F9102700000F8D0000000049BB00000000000000804C39D90F84000000004889C848C7C10200000048898570FFFFFF489948F7F94889D048C1FA3F48C7C1020000004821D14801C84883F8000F85000000004883FE017206813E980700000F8500000000488B46084883C0010F8000000000488B9D70FFFFFF4883C301488B3425A0536B024883EE0148893425A0536B024883FE000F8C0000000048898568FFFFFF4C89BD70FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4C8BBD68FFFFFF4C89B568FFFFFF4989DE49BB459B5BB6A07F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA540FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D9E95AFEFFFF49BB00905BB6A07F000041FFD321383C343029241D180C0804031600000049BB00905BB6A07F000041FFD3383C0C34302924180804031700000049BB00905BB6A07F000041FFD329383C343024180C04031800000049BB00905BB6A07F000041FFD3383C303424180C04031900000049BB00905BB6A07F000041FFD3383C0C342418031A00000049BB00905BB6A07F000041FFD3383C0C05342418031B00000049BB00905BB6A07F000041FFD3383C3424180C01031C00000049BB00905BB6A07F000041FFD3383C1834240C07031D00000049BB00905BB6A07F000041FFD3383C180134240C07031E00000049BB00905BB6A07F000041FFD3383C3424010D07031F000000 +[4cac9b794481] jit-backend-dump} +[4cac9b794cf3] {jit-backend-addr +Loop #2 ( #15 LOAD_FAST) has address 7fa0b65b9d90 to 7fa0b65b9ec2 (bootstrap 7fa0b65b9cb0) +[4cac9b795ba9] jit-backend-addr} +[4cac9b79637b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9cc0 +0 40FFFFFF +[4cac9b796ff1] jit-backend-dump} +[4cac9b7975e7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9db4 +0 7E010000 +[4cac9b79807f] jit-backend-dump} +[4cac9b798617] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9dc6 +0 8A010000 +[4cac9b79903b] jit-backend-dump} +[4cac9b79951f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9dd0 +0 9C010000 +[4cac9b799e89] jit-backend-dump} +[4cac9b79a2c7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9de3 +0 A4010000 +[4cac9b79ab5d] jit-backend-dump} +[4cac9b79af97] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9df4 +0 AD010000 +[4cac9b79b911] jit-backend-dump} +[4cac9b79be79] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9e07 +0 B2010000 +[4cac9b79cb47] jit-backend-dump} +[4cac9b79d0d7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9e3b +0 97010000 +[4cac9b79da99] jit-backend-dump} +[4cac9b79dee5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9e4d +0 9E010000 +[4cac9b79e769] jit-backend-dump} +[4cac9b79ebb5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9e5b +0 A9010000 +[4cac9b79f44b] jit-backend-dump} +[4cac9b79f9d9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9e84 +0 9A010000 +[4cac9b7a0481] jit-backend-dump} +[4cac9b7a0ad7] jit-backend} +[4cac9b7a16cd] {jit-log-opt-loop +# Loop 2 : entry bridge with 44 ops [p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11] -debug_merge_point(0, ' #15 LOAD_FAST') -+254: guard_value(i6, 0, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11] -+264: guard_nonnull_class(p11, ConstClass(W_IntObject), descr=) [p1, p0, p11, p2, p3, i4, p5, p8, p9, p10] -+282: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p11, p9, p10] -debug_merge_point(0, ' #18 LOAD_CONST') -+292: guard_value(p3, ConstPtr(ptr15), descr=) [p1, p0, p3, p2, p5, p11, p9, p10] -debug_merge_point(0, ' #21 COMPARE_OP') -+311: i16 = getfield_gc_pure(p11, descr=) +debug_merge_point(0, ' #15 LOAD_FAST') ++254: guard_value(i6, 2, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11] ++264: guard_nonnull_class(p9, ConstClass(W_IntObject), descr=) [p1, p0, p9, p2, p3, i4, p5, p8, p10, p11] ++282: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p11] +debug_merge_point(0, ' #18 LOAD_CONST') ++292: guard_value(p3, ConstPtr(ptr15), descr=) [p1, p0, p3, p2, p5, p8, p9, p11] +debug_merge_point(0, ' #21 COMPARE_OP') ++311: i16 = getfield_gc_pure(p9, descr=) +315: i18 = int_lt(i16, 10000) -guard_true(i18, descr=) [p1, p0, p11, p2, p5, p10] -debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') -debug_merge_point(0, ' #27 LOAD_FAST') -debug_merge_point(0, ' #30 LOAD_CONST') -debug_merge_point(0, ' #33 BINARY_MODULO') +guard_true(i18, descr=) [p1, p0, p9, p2, p5, p8] +debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #27 LOAD_FAST') +debug_merge_point(0, ' #30 LOAD_CONST') +debug_merge_point(0, ' #33 BINARY_MODULO') +328: i20 = int_eq(i16, -9223372036854775808) -guard_false(i20, descr=) [p1, p0, p11, i16, p2, p5, p10] +guard_false(i20, descr=) [p1, p0, p9, i16, p2, p5, p8] +347: i22 = int_mod(i16, 2) -+383: i24 = int_rshift(i22, 63) -+390: i25 = int_and(2, i24) -+400: i26 = int_add(i22, i25) -debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') -+403: i27 = int_is_true(i26) -guard_false(i27, descr=) [p1, p0, p2, p5, p10, p11, i26] -debug_merge_point(0, ' #50 LOAD_FAST') -+413: guard_nonnull_class(p10, ConstClass(W_IntObject), descr=) [p1, p0, p10, p2, p5, p11, None] -debug_merge_point(0, ' #53 LOAD_CONST') -debug_merge_point(0, ' #56 INPLACE_ADD') -+438: i30 = getfield_gc_pure(p10, descr=) -+442: i32 = int_add_ovf(i30, 2) -guard_no_overflow(, descr=) [p1, p0, p10, i32, p2, p5, p11, None] -debug_merge_point(0, ' #57 STORE_FAST') -debug_merge_point(0, ' #60 LOAD_FAST') -debug_merge_point(0, ' #63 LOAD_CONST') -debug_merge_point(0, ' #66 INPLACE_ADD') -+452: i34 = int_add(i16, 1) -debug_merge_point(0, ' #67 STORE_FAST') -debug_merge_point(0, ' #70 JUMP_ABSOLUTE') -+463: i36 = getfield_raw(40681184, descr=) -+471: i38 = int_sub(i36, 1) -+475: setfield_raw(40681184, i38, descr=) -+483: i40 = int_lt(i38, 0) -guard_false(i40, descr=) [p1, p0, p2, p5, i34, i32, None] -debug_merge_point(0, ' #15 LOAD_FAST') -+493: jump(p0, p1, p2, p5, i32, i34, descr=) -+551: --end of the loop-- -[1af179be57387] jit-log-opt-loop} -[1af179c15cdcd] {jit-log-opt-loop -# Loop 2 : loop with 34 ops ++369: i24 = int_rshift(i22, 63) ++376: i25 = int_and(2, i24) ++386: i26 = int_add(i22, i25) +debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') ++389: i27 = int_is_true(i26) +guard_false(i27, descr=) [p1, p0, p2, p5, p8, p9, i26] +debug_merge_point(0, ' #53 LOAD_FAST') ++399: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p5, p9, None] +debug_merge_point(0, ' #56 LOAD_CONST') +debug_merge_point(0, ' #59 INPLACE_ADD') ++417: i30 = getfield_gc_pure(p8, descr=) ++421: i32 = int_add_ovf(i30, 1) +guard_no_overflow(, descr=) [p1, p0, p8, i32, p2, p5, p9, None] +debug_merge_point(0, ' #60 STORE_FAST') +debug_merge_point(0, ' #63 LOAD_FAST') +debug_merge_point(0, ' #66 LOAD_CONST') +debug_merge_point(0, ' #69 INPLACE_ADD') ++431: i34 = int_add(i16, 1) +debug_merge_point(0, ' #70 STORE_FAST') +debug_merge_point(0, ' #73 JUMP_ABSOLUTE') ++442: i36 = getfield_raw(40588192, descr=) ++450: i38 = int_sub(i36, 1) ++454: setfield_raw(40588192, i38, descr=) ++462: i40 = int_lt(i38, 0) +guard_false(i40, descr=) [p1, p0, p2, p5, i32, i34, None] +debug_merge_point(0, ' #15 LOAD_FAST') ++472: jump(p0, p1, p2, p5, i32, i34, descr=) ++530: --end of the loop-- +[4cac9b7c5c13] jit-log-opt-loop} +[4caca24c49a7] {jit-backend +[4caca25290e7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba03b +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B014C8B3425D84D5B0149BB50A0CFB8A07F00004D8B2B4983C50149BB50A0CFB8A07F00004D892B4981FE102700000F8D000000004C89F048C7C10200000048898550FFFFFF489948F7F94889D048C1FA3F49C7C6020000004921D64C01F04883F8000F85000000004C89F84983C7010F8000000000488B8550FFFFFF4883C0014C8B3425A0536B024983EE1C4C893425A0536B024983FE000F8C0000000048898548FFFFFF4C8BB548FFFFFFE958FFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA540FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C74D89CEE9FBFEFFFF49BB00905BB6A07F000041FFD34440484C3D39032000000049BB00905BB6A07F000041FFD34440484C013D51032100000049BB00905BB6A07F000041FFD344403D484C070151032200000049BB00905BB6A07F000041FFD34440484C013D0707070323000000 +[4caca2535c6f] jit-backend-dump} +[4caca2536b09] {jit-backend-addr +Loop #3 ( #15 LOAD_FAST) has address 7fa0b65ba0cb to 7fa0b65ba173 (bootstrap 7fa0b65ba03b) +[4caca25499b5] jit-backend-addr} +[4caca254ae61] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba04b +0 40FFFFFF +[4caca254cf85] jit-backend-dump} +[4caca254e18b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba0f2 +0 DA000000 +[4caca254f985] jit-backend-dump} +[4caca255041d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba126 +0 BE000000 +[4caca2551995] jit-backend-dump} +[4caca2552337] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba133 +0 CA000000 +[4caca25538d3] jit-backend-dump} +[4caca2554317] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba15c +0 BB000000 +[4caca25558ad] jit-backend-dump} +[4caca255673b] jit-backend} +[4caca2557d67] {jit-log-opt-loop +# Loop 3 : loop with 34 ops [p0, p1, p2, p3, i4, i5] -debug_merge_point(0, ' #18 LOAD_CONST') -debug_merge_point(0, ' #21 COMPARE_OP') +debug_merge_point(0, ' #18 LOAD_CONST') +debug_merge_point(0, ' #21 COMPARE_OP') +174: i7 = int_lt(i5, 10000) -guard_true(i7, descr=) [p1, p0, p2, p3, i5, i4] -debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') -debug_merge_point(0, ' #27 LOAD_FAST') -debug_merge_point(0, ' #30 LOAD_CONST') -debug_merge_point(0, ' #33 BINARY_MODULO') +guard_true(i7, descr=) [p1, p0, p2, p3, i4, i5] +debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #27 LOAD_FAST') +debug_merge_point(0, ' #30 LOAD_CONST') +debug_merge_point(0, ' #33 BINARY_MODULO') +187: i9 = int_mod(i5, 2) +209: i11 = int_rshift(i9, 63) +216: i12 = int_and(2, i11) +226: i13 = int_add(i9, i12) -debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') +229: i14 = int_is_true(i13) -guard_false(i14, descr=) [p1, p0, p2, p3, i13, i5, i4] -debug_merge_point(0, ' #50 LOAD_FAST') -debug_merge_point(0, ' #53 LOAD_CONST') -debug_merge_point(0, ' #56 INPLACE_ADD') -+239: i16 = int_add_ovf(i4, 2) -guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i5, i4] -debug_merge_point(0, ' #57 STORE_FAST') -debug_merge_point(0, ' #60 LOAD_FAST') -debug_merge_point(0, ' #63 LOAD_CONST') -debug_merge_point(0, ' #66 INPLACE_ADD') +guard_false(i14, descr=) [p1, p0, p2, p3, i13, i4, i5] +debug_merge_point(0, ' #53 LOAD_FAST') +debug_merge_point(0, ' #56 LOAD_CONST') +debug_merge_point(0, ' #59 INPLACE_ADD') ++239: i16 = int_add_ovf(i4, 1) +guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i4, i5] +debug_merge_point(0, ' #60 STORE_FAST') +debug_merge_point(0, ' #63 LOAD_FAST') +debug_merge_point(0, ' #66 LOAD_CONST') +debug_merge_point(0, ' #69 INPLACE_ADD') +252: i19 = int_add(i5, 1) -debug_merge_point(0, ' #67 STORE_FAST') -debug_merge_point(0, ' #70 JUMP_ABSOLUTE') -+263: i21 = getfield_raw(40681184, descr=) -+271: i23 = int_sub(i21, 3) -+275: setfield_raw(40681184, i23, descr=) +debug_merge_point(0, ' #70 STORE_FAST') +debug_merge_point(0, ' #73 JUMP_ABSOLUTE') ++263: i21 = getfield_raw(40588192, descr=) ++271: i23 = int_sub(i21, 28) ++275: setfield_raw(40588192, i23, descr=) +283: i25 = int_lt(i23, 0) -guard_false(i25, descr=) [p1, p0, p2, p3, i19, i16, None, None, None] -debug_merge_point(0, ' #15 LOAD_FAST') -+293: jump(p0, p1, p2, p3, i16, i19, descr=) +guard_false(i25, descr=) [p1, p0, p2, p3, i19, i16, None, None, None] +debug_merge_point(0, ' #15 LOAD_FAST') ++293: jump(p0, p1, p2, p3, i16, i19, descr=) +312: --end of the loop-- -[1af179c182ffd] jit-log-opt-loop} -[1af179c1f947d] {jit-log-opt-bridge -# bridge out of Guard 4 with 25 ops +[4caca258fbfd] jit-log-opt-loop} +[4caca2e41c45] {jit-backend +[4caca43342ad] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba350 +0 488DA50000000049BB58A0CFB8A07F0000498B034883C00149BB58A0CFB8A07F0000498903488B8570FFFFFF4C8B700849BBA0217CB6A07F00004D39DE0F85000000004D8B6E104981FDC07446010F850000000049BB58026CB6A07F00004D8B334983FE01720741813E082601000F85000000004D8B6E1849BB88F377B6A07F00004D39DD0F85000000004D8B6E4049C7C3B0A0500041FFD34C8B60384C8D9578FFFFFF4C8B48484D85C90F85000000004C8B48284983F9000F850000000049BBA0217CB6A07F00004D39DD0F85000000004D8B4D104981F9C07446010F850000000049BBF80F6CB6A07F00004D8B2B4D85ED0F85000000004C8B2C2508DF45014981FD706A49010F85000000004D8B4D104981F9C07446010F85000000004C8B2C2508B65D014981FD603B62010F85000000004C8B2C25883B62014C8B2C25A0536B024983ED174C892C25A0536B024983FD000F8C000000004C8DAD78FFFFFF48898548FFFFFF4C899540FFFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B9540FFFFFF4C8950084C8B9548FFFFFF41F642040174164152504C89D74889C649C7C310734D0041FFD358415A498942384C8B8D70FFFFFF4D89691848898538FFFFFF488B0425704F3D01488D9098000000483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700381F010048891425704F3D0149BB88F377B6A07F00004C89587849BBA00171B6A07F00004C89586048C740700200000048898530FFFFFF488B0425704F3D01488D5038483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7008800000048891425704F3D0148C740080500000048898528FFFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D0148C74008010000004C8B9528FFFFFF41F642040174164152504C89D74889C649C7C310734D0041FFD358415A4989421048898520FFFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C8B9528FFFFFF41F642040174165041524C89D74889C649C7C310734D0041FFD3415A584989421848898518FFFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700D030000048891425704F3D0148898510FFFFFF488B0425704F3D01488D5028483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7007038000048891425704F3D0148C740180100000048C74008030000004C8B9510FFFFFF41F642040174165041524C89D74889C649C7C310734D0041FFD3415A584989421049C7420801000000488B8528FFFFFFF640040174165041524889C74C89D649C7C310734D0041FFD3415A584C8950204C8B8D30FFFFFF41F6410401741A50415241514C89CF4889C649C7C310734D0041FFD34159415A584989416849C741581300000049C781800000000300000041F64104017418415241514C89CF4C89E649C7C310734D0041FFD34159415A4D89613041C781900000001500000041F64104017422415241514C89CF49BBA0217CB6A07F00004C89DE49C7C310734D0041FFD34159415A49BBA0217CB6A07F00004D8959084C89BD08FFFFFF4C89B500FFFFFF48C78578FFFFFF2400000049C7C3030000004C891C2449C7C3130000004C895C24084C8B9D20FFFFFF4C895C24104C8B9D18FFFFFF4C895C24184C8954242049C7C3000000004C895C242849C7C3000000004C895C24304C89CF488BB548FFFFFF48C7C20000000049BB88F377B6A07F00004C89D949C7C00000000049BBA00171B6A07F00004D89D949BBC6965BB6A07F000041FFD34883F80074164889C7488BB530FFFFFF49C7C3D0D88C0041FFD3EB23488B8530FFFFFF48C7401800000000488B042590C2540148C7042590C25401000000004883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004C8BB548FFFFFF4D8B56484D85D20F85000000004C8B9530FFFFFF4C3B9570FFFFFF0F84000000004D8B4E2849C74250000000004983F9000F85000000004D8B4E384D8B7A304D0FB6A29400000041F6460401741A41514152504C89F74C89FE49C7C310734D0041FFD358415A41594D897E384D85E40F85000000004C8BA538FFFFFF49C7442408FDFFFFFF8138980700000F85000000004C8B60084C8BB508FFFFFF4D01E60F8000000000488B8550FFFFFF4883C0010F80000000004C8B2425A0536B024983EC1A4C892425A0536B024983FC000F8C00000000488985F8FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C897008488985F0FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C8B95F8FEFFFF4C895008488985E8FEFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BB40F477B6A07F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00200000048C7C70F000000488BB5F0FEFFFF488B9DE8FEFFFF48C7C20000000048C7C10000000049BB909D5BB6A07F000041FFE349BB00905BB6A07F000041FFD3440038484C3D51032500000049BB00905BB6A07F000041FFD344003438484C3D51032600000049BB00905BB6A07F000041FFD3440038484C3D51032700000049BB00905BB6A07F000041FFD344003438484C3D51032800000049BB00905BB6A07F000041FFD344400024484C382930343D51032900000049BB00905BB6A07F000041FFD3444000484C382930343D51032A00000049BB00905BB6A07F000041FFD344400034484C382930073D51032B00000049BB00905BB6A07F000041FFD34440002434484C382930073D51032C00000049BB00905BB6A07F000041FFD344400034484C382930073D51032D00000049BB00905BB6A07F000041FFD344400034484C382930073D51032E00000049BB00905BB6A07F000041FFD34440002434484C382930073D51032F00000049BB00905BB6A07F000041FFD344400034484C382930073D51033000000049BB00905BB6A07F000041FFD344400034484C382930073D51033100000049BB00905BB6A07F000041FFD3444000484C382930073D51033200000049BB45905BB6A07F000041FFD344405460005C484C787551032400000049BB45905BB6A07F000041FFD344405460005C484C787551033300000049BB00905BB6A07F000041FFD34440380060285C484C787551033400000049BB00905BB6A07F000041FFD344403800285C484C787551033500000049BB00905BB6A07F000041FFD344400028385C484C787551033600000049BB00905BB6A07F000041FFD34440002428385C484C787551033700000049BB00905BB6A07F000041FFD3444000484C7551033800000049BB00905BB6A07F000041FFD344400039484C7551033900000049BB00905BB6A07F000041FFD3444001484C390751033A00000049BB00905BB6A07F000041FFD34440484C01390707033B000000 +[4caca436d577] jit-backend-dump} +[4caca436ec69] {jit-backend-addr +Bridge out of guard 19 has address 7fa0b65ba350 to 7fa0b65bab56 +[4caca4370ee3] jit-backend-addr} +[4caca43720d1] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba353 +0 60FEFFFF +[4caca4373f79] jit-backend-dump} +[4caca43750e9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba38f +0 C3070000 +[4caca43766bb] jit-backend-dump} +[4caca4377105] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba3a0 +0 CB070000 +[4caca43785f9] jit-backend-dump} +[4caca4379169] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba3c0 +0 C5070000 +[4caca437a6e1] jit-backend-dump} +[4caca437b233] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba3d7 +0 C7070000 +[4caca437cb5f] jit-backend-dump} +[4caca437d4dd] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba3fd +0 BB070000 +[4caca437e905] jit-backend-dump} +[4caca437f28f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba40b +0 CB070000 +[4caca43806b1] jit-backend-dump} +[4caca4381071] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba41e +0 D5070000 +[4caca4382739] jit-backend-dump} +[4caca4383237] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba42f +0 E2070000 +[4caca43847d9] jit-backend-dump} +[4caca4385175] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba445 +0 EB070000 +[4caca438659d] jit-backend-dump} +[4caca4386f1b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba45a +0 F4070000 +[4caca4388331] jit-backend-dump} +[4caca4388cf1] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba46b +0 01080000 +[4caca438a101] jit-backend-dump} +[4caca438abe7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba480 +0 0B080000 +[4caca438c219] jit-backend-dump} +[4caca438d161] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba4a6 +0 21080000 +[4caca438e673] jit-backend-dump} +[4caca438f04b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba95f +0 85030000 +[4caca4390461] jit-backend-dump} +[4caca4390e21] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba96e +0 93030000 +[4caca439222b] jit-backend-dump} +[4caca4392bdf] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba982 +0 9C030000 +[4caca4394217] jit-backend-dump} +[4caca4394d15] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba996 +0 A6030000 +[4caca43962f3] jit-backend-dump} +[4caca4396c8f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba9ac +0 AD030000 +[4caca43980b7] jit-backend-dump} +[4caca4398a89] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65ba9ea +0 8C030000 +[4caca4399e99] jit-backend-dump} +[4caca439a85f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65baa06 +0 8E030000 +[4caca439bca5] jit-backend-dump} +[4caca439c731] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65baa1a +0 93030000 +[4caca439dd99] jit-backend-dump} +[4caca439e807] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65baa2b +0 9C030000 +[4caca439fd13] jit-backend-dump} +[4caca43a06f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65baa49 +0 98030000 +[4caca43a6019] jit-backend-dump} +[4caca43a771d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65b9ba0 +0 AC070000 +[4caca43a8cb9] jit-backend-dump} +[4caca43a9949] jit-backend} +[4caca43ab1c1] {jit-log-opt-bridge +# bridge out of Guard 19 with 124 ops [p0, p1, p2, p3, i4, i5, i6] -debug_merge_point(0, ' #37 LOAD_FAST') -debug_merge_point(0, ' #40 LOAD_CONST') -debug_merge_point(0, ' #43 INPLACE_ADD') -+37: i8 = int_add_ovf(i5, 1) -guard_no_overflow(, descr=) [p0, p1, i8, p2, p3, i5, i6] -debug_merge_point(0, ' #44 STORE_FAST') -debug_merge_point(0, ' #47 JUMP_FORWARD') -debug_merge_point(0, ' #60 LOAD_FAST') -debug_merge_point(0, ' #63 LOAD_CONST') -debug_merge_point(0, ' #66 INPLACE_ADD') -+50: i10 = int_add_ovf(i6, 1) -guard_no_overflow(, descr=) [p0, p1, i10, p2, p3, i8, None, i6] -debug_merge_point(0, ' #67 STORE_FAST') -debug_merge_point(0, ' #70 JUMP_ABSOLUTE') -+67: i13 = getfield_raw(40681184, descr=) -+75: i15 = int_sub(i13, 1) -+79: setfield_raw(40681184, i15, descr=) -+87: i17 = int_lt(i15, 0) -guard_false(i17, descr=) [p0, p1, p2, p3, i10, i8, None, None] -debug_merge_point(0, ' #15 LOAD_FAST') -+97: p19 = new_with_vtable(ConstClass(W_IntObject)) -+167: setfield_gc(p19, i8, descr=) -+171: p21 = new_with_vtable(ConstClass(W_IntObject)) -+241: setfield_gc(p21, i10, descr=) -+252: jump(p1, p0, p2, ConstPtr(ptr22), 0, p3, 0, 15, ConstPtr(ptr26), ConstPtr(ptr27), p19, p21, descr=) -+362: --end of the loop-- -[1af179c2137b0] jit-log-opt-bridge} -[1af179c97806b] {jit-log-opt-loop -# Loop 3 : loop with 30 ops -[p0, p1, p2, p3, p4, p5, p6, i7, p8, p9, i10, i11, p12, i13, i14, p15, p16] -debug_merge_point(0, ' #13 FOR_ITER') +debug_merge_point(0, ' #37 LOAD_FAST') +debug_merge_point(0, ' #40 LOAD_GLOBAL') ++37: p7 = getfield_gc(p1, descr=) ++48: guard_value(p7, ConstPtr(ptr8), descr=) [p0, p1, p7, p2, p3, i6, i5] ++67: p9 = getfield_gc(p7, descr=) ++71: guard_value(p9, ConstPtr(ptr10), descr=) [p0, p1, p9, p7, p2, p3, i6, i5] ++84: p12 = getfield_gc(ConstPtr(ptr11), descr=) ++97: guard_nonnull_class(p12, ConstClass(Function), descr=) [p0, p1, p12, p2, p3, i6, i5] +debug_merge_point(0, ' #43 CALL_FUNCTION') ++116: p14 = getfield_gc(p12, descr=) ++120: guard_value(p14, ConstPtr(ptr15), descr=) [p0, p1, p14, p12, p2, p3, i6, i5] ++139: p16 = getfield_gc(p12, descr=) ++143: p17 = getfield_gc(p12, descr=) ++143: p19 = call(ConstClass(getexecutioncontext), descr=) ++153: p20 = getfield_gc(p19, descr=) ++157: i21 = force_token() ++164: p22 = getfield_gc(p19, descr=) ++168: guard_isnull(p22, descr=) [p0, p1, p19, p22, p2, p3, p12, i21, p20, p16, i6, i5] ++177: i23 = getfield_gc(p19, descr=) ++181: i24 = int_is_zero(i23) +guard_true(i24, descr=) [p0, p1, p19, p2, p3, p12, i21, p20, p16, i6, i5] +debug_merge_point(1, ' #0 LOAD_CONST') +debug_merge_point(1, ' #3 STORE_FAST') +debug_merge_point(1, ' #6 SETUP_LOOP') +debug_merge_point(1, ' #9 LOAD_GLOBAL') ++191: guard_value(p16, ConstPtr(ptr25), descr=) [p0, p1, p19, p16, p2, p3, p12, i21, p20, None, i6, i5] ++210: p27 = getfield_gc(p16, descr=) ++214: guard_value(p27, ConstPtr(ptr28), descr=) [p0, p1, p19, p27, p16, p2, p3, p12, i21, p20, None, i6, i5] ++227: p30 = getfield_gc(ConstPtr(ptr29), descr=) ++240: guard_isnull(p30, descr=) [p0, p1, p19, p30, p2, p3, p12, i21, p20, None, i6, i5] ++249: p32 = getfield_gc(ConstPtr(ptr31), descr=) ++257: guard_value(p32, ConstPtr(ptr33), descr=) [p0, p1, p19, p32, p2, p3, p12, i21, p20, None, i6, i5] ++270: p34 = getfield_gc(p32, descr=) ++274: guard_value(p34, ConstPtr(ptr35), descr=) [p0, p1, p19, p34, p32, p2, p3, p12, i21, p20, None, i6, i5] ++287: p37 = getfield_gc(ConstPtr(ptr36), descr=) ++295: guard_value(p37, ConstPtr(ptr38), descr=) [p0, p1, p19, p37, p2, p3, p12, i21, p20, None, i6, i5] +debug_merge_point(1, ' #12 LOAD_CONST') +debug_merge_point(1, ' #15 CALL_FUNCTION') ++308: p39 = getfield_gc(ConstPtr(ptr38), descr=) ++316: guard_not_invalidated(, descr=) [p0, p1, p19, p39, p2, p3, p12, i21, p20, None, i6, i5] +debug_merge_point(1, ' #18 GET_ITER') +debug_merge_point(1, ' #19 FOR_ITER') +debug_merge_point(1, ' #22 STORE_FAST') +debug_merge_point(1, ' #25 LOAD_FAST') +debug_merge_point(1, ' #28 LOAD_CONST') +debug_merge_point(1, ' #31 INPLACE_ADD') +debug_merge_point(1, ' #32 STORE_FAST') +debug_merge_point(1, ' #35 JUMP_ABSOLUTE') ++316: i41 = getfield_raw(40588192, descr=) ++324: i43 = int_sub(i41, 23) ++328: setfield_raw(40588192, i43, descr=) ++336: i45 = int_lt(i43, 0) +guard_false(i45, descr=) [p0, p1, p19, p2, p3, p12, i21, p20, None, i6, i5] +debug_merge_point(1, ' #19 FOR_ITER') ++346: i46 = force_token() ++353: p48 = new_with_vtable(20801800) ++430: setfield_gc(p48, i21, descr=) +setfield_gc(p19, p48, descr=) ++481: setfield_gc(p1, i46, descr=) ++492: p50 = new_with_vtable(20869528) ++565: setfield_gc(p50, ConstPtr(ptr15), descr=) ++579: setfield_gc(p50, ConstPtr(ptr51), descr=) ++593: setfield_gc(p50, 2, descr=) ++601: p54 = new_array(5, descr=) ++679: p56 = new_with_vtable(ConstClass(W_IntObject)) ++749: setfield_gc(p56, 1, descr=) +setarrayitem_gc(p54, 0, p56, descr=) ++797: p60 = new_with_vtable(ConstClass(W_IntObject)) +setarrayitem_gc(p54, 1, p60, descr=) ++907: p63 = new_with_vtable(20808496) ++977: p65 = new_with_vtable(20810448) ++1047: setfield_gc(p65, 1, descr=) ++1055: setfield_gc(p65, 3, descr=) +setfield_gc(p63, p65, descr=) ++1103: setfield_gc(p63, 1, descr=) +setarrayitem_gc(p54, 2, p63, descr=) +setfield_gc(p50, p54, descr=) ++1194: setfield_gc(p50, 19, descr=) ++1202: setfield_gc(p50, 3, descr=) +setfield_gc(p50, p20, descr=) ++1248: setfield_gc(p50, 21, descr=) +setfield_gc(p50, ConstPtr(ptr25), descr=) ++1314: p77 = call_assembler(p50, p19, ConstPtr(ptr73), ConstPtr(ptr15), 0, ConstPtr(ptr51), 3, 19, p56, p60, p63, ConstPtr(ptr75), ConstPtr(ptr76), descr=) +guard_not_forced(, descr=) [p0, p1, p19, p50, p77, p48, p2, p3, p12, i6, i5] ++1555: guard_no_exception(, descr=) [p0, p1, p19, p50, p77, p48, p2, p3, p12, i6, i5] ++1570: p78 = getfield_gc(p19, descr=) ++1581: guard_isnull(p78, descr=) [p0, p1, p19, p77, p50, p78, p48, p2, p3, p12, i6, i5] ++1590: i79 = ptr_eq(p50, p1) +guard_false(i79, descr=) [p0, p1, p19, p77, p50, p48, p2, p3, p12, i6, i5] ++1610: i80 = getfield_gc(p19, descr=) ++1614: setfield_gc(p50, ConstPtr(ptr81), descr=) ++1622: i82 = int_is_true(i80) +guard_false(i82, descr=) [p0, p1, p77, p50, p19, p48, p2, p3, p12, i6, i5] ++1632: p83 = getfield_gc(p19, descr=) ++1636: p84 = getfield_gc(p50, descr=) ++1640: i85 = getfield_gc(p50, descr=) +setfield_gc(p19, p84, descr=) ++1685: guard_false(i85, descr=) [p0, p1, p77, p83, p50, p19, p48, p2, p3, p12, i6, i5] +debug_merge_point(0, ' #46 INPLACE_ADD') ++1694: setfield_gc(p48, -3, descr=) ++1710: guard_class(p77, ConstClass(W_IntObject), descr=) [p0, p1, p77, p2, p3, i6, i5] ++1722: i88 = getfield_gc_pure(p77, descr=) ++1726: i89 = int_add_ovf(i6, i88) +guard_no_overflow(, descr=) [p0, p1, p77, i89, p2, p3, i6, i5] +debug_merge_point(0, ' #47 STORE_FAST') +debug_merge_point(0, ' #50 JUMP_FORWARD') +debug_merge_point(0, ' #63 LOAD_FAST') +debug_merge_point(0, ' #66 LOAD_CONST') +debug_merge_point(0, ' #69 INPLACE_ADD') ++1742: i91 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i91, p2, p3, i89, None, i5] +debug_merge_point(0, ' #70 STORE_FAST') +debug_merge_point(0, ' #73 JUMP_ABSOLUTE') ++1759: i93 = getfield_raw(40588192, descr=) ++1767: i95 = int_sub(i93, 26) ++1771: setfield_raw(40588192, i95, descr=) ++1779: i97 = int_lt(i95, 0) +guard_false(i97, descr=) [p0, p1, p2, p3, i91, i89, None, None] +debug_merge_point(0, ' #15 LOAD_FAST') ++1789: p99 = new_with_vtable(ConstClass(W_IntObject)) ++1859: setfield_gc(p99, i89, descr=) ++1863: p101 = new_with_vtable(ConstClass(W_IntObject)) ++1933: setfield_gc(p101, i91, descr=) ++1944: jump(p1, p0, p2, ConstPtr(ptr102), 0, p3, 2, 15, p99, p101, ConstPtr(ptr106), ConstPtr(ptr107), descr=) ++2054: --end of the loop-- +[4caca4492641] jit-log-opt-bridge} +[4caca6b867f7] {jit-backend +[4caca6be469f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bae6a +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B01488B0425B8C2540148C70425B8C254010000000048898550FFFFFF488B0425C0C2540148C70425C0C254010000000048898548FFFFFF488B0425C8C2540148C70425C8C254010000000048898540FFFFFF488B0425D0C2540148C70425D0C254010000000048898538FFFFFF488B0425D8C2540148C70425D8C254010000000048898530FFFFFF4C8B3425004E5B01488B0425084E5B0148898528FFFFFF488B0425F0C2540148C70425F0C254010000000048898520FFFFFF488B0425184E5B0148898518FFFFFF488B0425204E5B0148898510FFFFFF488B042508C3540148C7042508C354010000000048898508FFFFFF488B042510C3540148C7042510C354010000000048898500FFFFFF49BB60A0CFB8A07F00004D8B2B4983C50149BB60A0CFB8A07F00004D892B4C3BB528FFFFFF0F8D000000004D89F74C0FAFB518FFFFFF4C8BAD10FFFFFF4D01F54983C7014C8BB538FFFFFF4D897E084C89EF49C7C31061B70041FFD34C8BA500FFFFFF4D8B5424084D89D14983C201488985F8FEFFFF4C898DF0FEFFFF4C89E74C89D649C7C3C07FB50041FFD348833C2550546B02000F85000000004D8B5424104C8995E8FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700D004000048891425704F3D014C8B95F8FEFFFF4C8950084C8B95E8FEFFFF4C8B8DF0FEFFFF41F6420401741D41524151504C89D74C89CE4889C249C7C380DEB20041FFD3584159415A4B8944CA10488B0425A0536B024883E80448890425A0536B024883F8000F8C000000004C89B538FFFFFF4D89FE4C89A500FFFFFF4D89EFE9A0FEFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA560FEFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C74C898D50FFFFFF4C8B5D104C899D48FFFFFF4C8B5D184C899D40FFFFFF4C8B5D204C899D38FFFFFF4C8B5D284C899D30FFFFFF4C8B5D304D89DE4C8B5D384C899D28FFFFFF4C8B5D404C899D20FFFFFF4C8B5D484C899D18FFFFFF4C8B5D504C899D10FFFFFF4C8B5D584C899D08FFFFFF4C8B5D604C899D00FFFFFFE9CAFDFFFF49BB00905BB6A07F000041FFD344405C3968484C505458603D033C00000049BB00905BB6A07F000041FFD3444074484C50545838603507033D00000049BB45905BB6A07F000041FFD34440810130484C50545838607C3507033E00000049BB00905BB6A07F000041FFD34440484C505458386035033F000000 +[4caca6bf7b89] jit-backend-dump} +[4caca6bf857d] {jit-backend-addr +Loop #4 ( #13 FOR_ITER) has address 7fa0b65bafff to 7fa0b65bb15f (bootstrap 7fa0b65bae6a) +[4caca6bf97cf] jit-backend-addr} +[4caca6bfa0ad] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bae7a +0 60FEFFFF +[4caca6bfad9b] jit-backend-dump} +[4caca6bfb47b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb026 +0 0B020000 +[4caca6bfbdd5] jit-backend-dump} +[4caca6bfc367] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb097 +0 D6010000 +[4caca6bfcc49] jit-backend-dump} +[4caca6bfd1b9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb142 +0 4C010000 +[4caca6bfdc6b] jit-backend-dump} +[4caca6bfe3b7] jit-backend} +[4caca6bff1d3] {jit-log-opt-loop +# Loop 4 : loop with 30 ops +[p0, p1, p2, p3, i4, p5, p6, p7, p8, p9, i10, i11, p12, i13, i14, p15, p16] +debug_merge_point(0, ' #13 FOR_ITER') +435: i17 = int_ge(i10, i11) -guard_false(i17, descr=) [p1, p0, p5, i10, p12, p2, p3, p4, p6, p8, p9, i7] +guard_false(i17, descr=) [p1, p0, p8, i10, p12, p2, p3, p5, p6, p7, p9, i4] +448: i18 = int_mul(i10, i13) +459: i19 = int_add(i14, i18) +469: i21 = int_add(i10, 1) -debug_merge_point(0, ' #16 STORE_FAST') -debug_merge_point(0, ' #19 LOAD_GLOBAL') -debug_merge_point(0, ' #22 LOAD_FAST') -debug_merge_point(0, ' #25 CALL_FUNCTION') -+473: setfield_gc(p5, i21, descr=) -+484: guard_not_invalidated(, descr=) [p1, p0, p15, p2, p3, p4, p5, p6, p8, p9, i19, None] +debug_merge_point(0, ' #16 STORE_FAST') +debug_merge_point(0, ' #19 LOAD_GLOBAL') +debug_merge_point(0, ' #22 LOAD_FAST') +debug_merge_point(0, ' #25 CALL_FUNCTION') ++473: setfield_gc(p8, i21, descr=) ++484: guard_not_invalidated(, descr=) [p1, p0, p15, p2, p3, p5, p6, p7, p8, p9, i19, None] +484: p24 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i19, descr=) -debug_merge_point(0, ' #28 LIST_APPEND') +debug_merge_point(0, ' #28 LIST_APPEND') +497: i25 = getfield_gc(p16, descr=) +509: i27 = int_add(i25, 1) +516: call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p16, i27, descr=) -+546: guard_no_exception(, descr=) [p1, p0, i25, p16, p2, p3, p4, p5, p6, p8, p9, p24, i19, None] ++546: guard_no_exception(, descr=) [p1, p0, i25, p16, p2, p3, p5, p6, p7, p8, p9, p24, i19, None] +561: p29 = getfield_gc(p16, descr=) +566: p31 = new_with_vtable(ConstClass(W_StringObject)) +636: setfield_gc(p31, p24, descr=) setarrayitem_gc(p29, i25, p31, descr=) -debug_merge_point(0, ' #31 JUMP_ABSOLUTE') -+702: i33 = getfield_raw(40681184, descr=) +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++702: i33 = getfield_raw(40588192, descr=) +710: i35 = int_sub(i33, 4) -+714: setfield_raw(40681184, i35, descr=) ++714: setfield_raw(40588192, i35, descr=) +722: i37 = int_lt(i35, 0) -guard_false(i37, descr=) [p1, p0, p2, p3, p4, p5, p6, p8, p9, i19] -debug_merge_point(0, ' #13 FOR_ITER') -+732: jump(p0, p1, p2, p3, p4, p5, p6, i19, p8, p9, i21, i11, p12, i13, i14, p15, p16, descr=) +guard_false(i37, descr=) [p1, p0, p2, p3, p5, p6, p7, p8, p9, i19] +debug_merge_point(0, ' #13 FOR_ITER') ++732: jump(p0, p1, p2, p3, i19, p5, p6, p7, p8, p9, i21, i11, p12, i13, i14, p15, p16, descr=) +757: --end of the loop-- -[1af179c9ab950] jit-log-opt-loop} -[1af179cc419a7] {jit-log-opt-loop -# Loop 4 : entry bridge with 56 ops +[4caca6c22a91] jit-log-opt-loop} +[4caca6c25811] {jit-backend +[4caca6e7f105] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb30f +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C2540100000000488B0C25E8C2540148C70425E8C2540100000000488B0425F0C2540148C70425F0C254010000000048898570FFFFFF488B0425F8C2540148C70425F8C254010000000048898568FFFFFF488B042500C3540148C7042500C354010000000048898560FFFFFF488B042508C3540148C7042508C354010000000048898558FFFFFF49BB68A0CFB8A07F0000498B034883C00149BB68A0CFB8A07F00004989034983F8050F8500000000488BBD70FFFFFF813FD03000000F85000000004C8B47104D85C00F8400000000488B47084C89BD50FFFFFF4D8B78204D85FF0F85000000004D8B78084C39F80F8D0000000048899D48FFFFFF498B581048899D40FFFFFF498B581848898538FFFFFF480FAFC348899D30FFFFFF488B9D40FFFFFF4801C3488B8538FFFFFF4883C001488947084983FA000F850000000049BBF8F477B6A07F00004D39DC0F85000000004C8BA550FFFFFF498B74240849BBA0217CB6A07F00004C39DE0F85000000004C8B56104981FAC07446010F850000000049BBF85371B6A07F0000498B334885F60F8500000000488B342508DF45014881FE706A49010F85000000004C8B56104981FAC07446010F8500000000488B3425B8B55D014881FE007D44010F8500000000488B342548A85A0148898D28FFFFFF48899520FFFFFF48898518FFFFFF4C898510FFFFFF4C898D08FFFFFF4889B500FFFFFF4889DF49C7C31061B70041FFD3488BB528FFFFFF4C8B4E084D8B41084C89C74983C001488985F8FEFFFF4889BDF0FEFFFF4C898DE8FEFFFF4C89CF4C89C649C7C3C07FB50041FFD348833C2550546B02000F85000000004C8B85E8FEFFFF4D8B48104C898DE0FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700D004000048891425704F3D014C8B95F8FEFFFF4C8950084C8B95E0FEFFFF4C8B8DF0FEFFFF41F6420401741D41514152504C89D74C89CE4889C249C7C380DEB20041FFD358415A41594B8944CA10488B0425A0536B024883E80448890425A0536B024883F8000F8C000000004C89B568FFFFFF4C89AD60FFFFFF488B8548FFFFFF48898550FFFFFF488B8520FFFFFF48898548FFFFFF488B8570FFFFFF48898538FFFFFF4C8BB518FFFFFF488B8510FFFFFF48898520FFFFFF488B8530FFFFFF48898518FFFFFF488B8540FFFFFF48898510FFFFFF4C89A570FFFFFF488B8528FFFFFF48898540FFFFFF488B8558FFFFFF48898530FFFFFF4C89BD28FFFFFF488B8508FFFFFF48898558FFFFFF4989DF488B8500FFFFFF48898508FFFFFF488B85E8FEFFFF48898500FFFFFF49BBFFAF5BB6A07F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA550FEFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D94C8B5D404C899D70FFFFFF4C8B5D484C899D68FFFFFF4C8B5D504C899D60FFFFFF4C8B5D584C899D58FFFFFFE90DFCFFFF49BB00905BB6A07F000041FFD321383C343029241D180C08044044484C034000000049BB00905BB6A07F000041FFD3383C1C34302924180C080444484C034100000049BB00905BB6A07F000041FFD3383C1C2034302924180C080444484C034200000049BB00905BB6A07F000041FFD338501C01203C34302924180C080444484C034300000049BB00905BB6A07F000041FFD338501C012034302924180C080444484C034400000049BB00905BB6A07F000041FFD3293850343024185408041C484C0D034500000049BB00905BB6A07F000041FFD338503034245408041C484C0D034600000049BB00905BB6A07F000041FFD338301834245408041C484C0D034700000049BB00905BB6A07F000041FFD33830281834245408041C484C0D034800000049BB00905BB6A07F000041FFD338301834245408041C484C0D034900000049BB00905BB6A07F000041FFD338301834245408041C484C0D034A00000049BB00905BB6A07F000041FFD33830281834245408041C484C0D034B00000049BB00905BB6A07F000041FFD338301834245408041C484C0D034C00000049BB00905BB6A07F000041FFD338301834245408041C4C0D034D00000049BB45905BB6A07F000041FFD33830810184013474546864404C7C0D034E00000049BB00905BB6A07F000041FFD338303474546864404C0D034F000000 +[4caca6e926f2] jit-backend-dump} +[4caca6e930e2] {jit-backend-addr +Loop #5 ( #13 FOR_ITER) has address 7fa0b65bb45b to 7fa0b65bb7ae (bootstrap 7fa0b65bb30f) +[4caca6e94267] jit-backend-addr} +[4caca6e94a6e] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb31f +0 50FEFFFF +[4caca6e95923] jit-backend-dump} +[4caca6e96085] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb47f +0 CB030000 +[4caca6e96c46] jit-backend-dump} +[4caca6e97240] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb492 +0 DA030000 +[4caca6e97cfc] jit-backend-dump} +[4caca6e981a9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb49f +0 ED030000 +[4caca6e98be1] jit-backend-dump} +[4caca6e9906d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb4b7 +0 F6030000 +[4caca6e999f7] jit-backend-dump} +[4caca6e99f88] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb4c4 +0 0C040000 +[4caca6e9aaa1] jit-backend-dump} +[4caca6e9afd8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb50f +0 E3030000 +[4caca6e9bb90] jit-backend-dump} +[4caca6e9c025] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb522 +0 F0030000 +[4caca6e9c9ac] jit-backend-dump} +[4caca6e9ce29] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb541 +0 EF030000 +[4caca6e9d7b0] jit-backend-dump} +[4caca6e9dc45] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb552 +0 FC030000 +[4caca6e9e848] jit-backend-dump} +[4caca6e9edeb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb568 +0 05040000 +[4caca6e9f91f] jit-backend-dump} +[4caca6e9fd9c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb57d +0 0E040000 +[4caca6ea0723] jit-backend-dump} +[4caca6ea0b9d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb58e +0 1B040000 +[4caca6ea1524] jit-backend-dump} +[4caca6ea19b6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb5a3 +0 25040000 +[4caca6ea233d] jit-backend-dump} +[4caca6ea29f4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb62c +0 D7030000 +[4caca6ea34fe] jit-backend-dump} +[4caca6ea53b3] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bb6dd +0 47030000 +[4caca6ea5e3b] jit-backend-dump} +[4caca6ea646b] jit-backend} +[4caca6ea7139] {jit-log-opt-loop +# Loop 5 : entry bridge with 56 ops [p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11, p12, p13, p14, p15] -debug_merge_point(0, ' #13 FOR_ITER') -+362: guard_value(i6, 2, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] -+372: guard_class(p9, 21012688, descr=) [p1, p0, p9, p2, p3, i4, p5, p8, p10, p11, p12, p13, p14, p15] -+384: p18 = getfield_gc(p9, descr=) -+388: guard_nonnull(p18, descr=) [p1, p0, p9, p18, p2, p3, i4, p5, p8, p10, p11, p12, p13, p14, p15] -+397: i19 = getfield_gc(p9, descr=) -+401: p20 = getfield_gc(p18, descr=) -+405: guard_isnull(p20, descr=) [p1, p0, p9, i19, p18, p20, p2, p3, i4, p5, p8, p10, p11, p12, p13, p14, p15] -+414: i21 = getfield_gc(p18, descr=) -+418: i22 = int_ge(i19, i21) -guard_false(i22, descr=) [p1, p0, p9, i19, p18, p2, p3, i4, p5, p8, p10, p11, p12, p13, p14, p15] -+427: i23 = getfield_gc(p18, descr=) -+431: i24 = getfield_gc(p18, descr=) -+442: i25 = int_mul(i19, i24) -+453: i26 = int_add(i23, i25) -+463: i28 = int_add(i19, 1) -+474: setfield_gc(p9, i28, descr=) -+478: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p11, p12, p13, p14, p15, i26] -debug_merge_point(0, ' #16 STORE_FAST') -debug_merge_point(0, ' #19 LOAD_GLOBAL') -+488: guard_value(p3, ConstPtr(ptr30), descr=) [p1, p0, p3, p2, p5, p8, p9, p11, p12, p14, p15, i26] -+507: p31 = getfield_gc(p0, descr=) -+519: guard_value(p31, ConstPtr(ptr32), descr=) [p1, p0, p31, p2, p5, p8, p9, p11, p12, p14, p15, i26] -+538: p33 = getfield_gc(p31, descr=) -+549: guard_isnull(p33, descr=) [p1, p0, p33, p31, p2, p5, p8, p9, p11, p12, p14, p15, i26] -+558: p35 = getfield_gc(ConstPtr(ptr34), descr=) -+571: guard_isnull(p35, descr=) [p1, p0, p35, p2, p5, p8, p9, p11, p12, p14, p15, i26] -+580: p37 = getfield_gc(ConstPtr(ptr36), descr=) -+588: guard_value(p37, ConstPtr(ptr38), descr=) [p1, p0, p37, p2, p5, p8, p9, p11, p12, p14, p15, i26] -+601: p39 = getfield_gc(p37, descr=) -+605: guard_isnull(p39, descr=) [p1, p0, p39, p37, p2, p5, p8, p9, p11, p12, p14, p15, i26] -+614: p41 = getfield_gc(ConstPtr(ptr40), descr=) -+622: guard_value(p41, ConstPtr(ptr42), descr=) [p1, p0, p41, p2, p5, p8, p9, p11, p12, p14, p15, i26] -debug_merge_point(0, ' #22 LOAD_FAST') -debug_merge_point(0, ' #25 CALL_FUNCTION') -+635: p44 = getfield_gc(ConstPtr(ptr43), descr=) -+643: guard_not_invalidated(, descr=) [p1, p0, p44, p2, p5, p8, p9, p12, p14, p15, i26] -+643: p46 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i26, descr=) -debug_merge_point(0, ' #28 LIST_APPEND') -+705: p47 = getfield_gc(p8, descr=) -+716: i48 = getfield_gc(p47, descr=) -+720: i50 = int_add(i48, 1) -+727: call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p47, i50, descr=) -+764: guard_no_exception(, descr=) [p1, p0, i48, p47, p2, p5, p8, p9, p12, p14, p15, p46, i26] -+779: p52 = getfield_gc(p47, descr=) -+790: p54 = new_with_vtable(ConstClass(W_StringObject)) -+860: setfield_gc(p54, p46, descr=) -setarrayitem_gc(p52, i48, p54, descr=) -debug_merge_point(0, ' #31 JUMP_ABSOLUTE') -+926: i56 = getfield_raw(40681184, descr=) -+934: i58 = int_sub(i56, 4) -+938: setfield_raw(40681184, i58, descr=) -+946: i60 = int_lt(i58, 0) -guard_false(i60, descr=) [p1, p0, p2, p5, p8, p9, p12, p14, p15, i26] -debug_merge_point(0, ' #13 FOR_ITER') -+956: jump(p0, p1, p2, p5, p8, p9, p12, i26, p14, p15, i28, i21, p18, i24, i23, p44, p47, descr=) -+1149: --end of the loop-- -[1af179cc8cec7] jit-log-opt-loop} -[1af179d0cacd1] {jit-log-opt-loop -# Loop 5 : entry bridge with 10 ops +debug_merge_point(0, ' #13 FOR_ITER') ++362: guard_value(i6, 5, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] ++372: guard_class(p12, 20808496, descr=) [p1, p0, p12, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] ++391: p18 = getfield_gc(p12, descr=) ++395: guard_nonnull(p18, descr=) [p1, p0, p12, p18, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] ++404: i19 = getfield_gc(p12, descr=) ++408: p20 = getfield_gc(p18, descr=) ++419: guard_isnull(p20, descr=) [p1, p0, p12, i19, p18, p20, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] ++428: i21 = getfield_gc(p18, descr=) ++432: i22 = int_ge(i19, i21) +guard_false(i22, descr=) [p1, p0, p12, i19, p18, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] ++441: i23 = getfield_gc(p18, descr=) ++452: i24 = getfield_gc(p18, descr=) ++463: i25 = int_mul(i19, i24) ++474: i26 = int_add(i23, i25) ++491: i28 = int_add(i19, 1) ++502: setfield_gc(p12, i28, descr=) ++506: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p10, p11, p12, p14, p15, i26] +debug_merge_point(0, ' #16 STORE_FAST') +debug_merge_point(0, ' #19 LOAD_GLOBAL') ++516: guard_value(p3, ConstPtr(ptr30), descr=) [p1, p0, p3, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++535: p31 = getfield_gc(p0, descr=) ++547: guard_value(p31, ConstPtr(ptr32), descr=) [p1, p0, p31, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++566: p33 = getfield_gc(p31, descr=) ++570: guard_value(p33, ConstPtr(ptr34), descr=) [p1, p0, p33, p31, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++583: p36 = getfield_gc(ConstPtr(ptr35), descr=) ++596: guard_isnull(p36, descr=) [p1, p0, p36, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++605: p38 = getfield_gc(ConstPtr(ptr37), descr=) ++613: guard_value(p38, ConstPtr(ptr39), descr=) [p1, p0, p38, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++626: p40 = getfield_gc(p38, descr=) ++630: guard_value(p40, ConstPtr(ptr41), descr=) [p1, p0, p40, p38, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++643: p43 = getfield_gc(ConstPtr(ptr42), descr=) ++651: guard_value(p43, ConstPtr(ptr44), descr=) [p1, p0, p43, p2, p5, p9, p10, p11, p12, p14, p15, i26] +debug_merge_point(0, ' #22 LOAD_FAST') +debug_merge_point(0, ' #25 CALL_FUNCTION') ++664: p46 = getfield_gc(ConstPtr(ptr45), descr=) ++672: guard_not_invalidated(, descr=) [p1, p0, p46, p2, p5, p9, p10, p11, p12, p15, i26] ++672: p48 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i26, descr=) +debug_merge_point(0, ' #28 LIST_APPEND') ++727: p49 = getfield_gc(p11, descr=) ++738: i50 = getfield_gc(p49, descr=) ++742: i52 = int_add(i50, 1) ++749: call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p49, i52, descr=) ++786: guard_no_exception(, descr=) [p1, p0, i50, p49, p2, p5, p9, p10, p11, p12, p15, p48, i26] ++801: p54 = getfield_gc(p49, descr=) ++812: p56 = new_with_vtable(ConstClass(W_StringObject)) ++882: setfield_gc(p56, p48, descr=) +setarrayitem_gc(p54, i50, p56, descr=) +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++948: i58 = getfield_raw(40588192, descr=) ++956: i60 = int_sub(i58, 4) ++960: setfield_raw(40588192, i60, descr=) ++968: i62 = int_lt(i60, 0) +guard_false(i62, descr=) [p1, p0, p2, p5, p9, p10, p11, p12, p15, i26] +debug_merge_point(0, ' #13 FOR_ITER') ++978: jump(p0, p1, p2, p5, i26, p9, p10, p11, p12, p15, i28, i21, p18, i24, i23, p46, p49, descr=) ++1183: --end of the loop-- +[4caca6ee826b] jit-log-opt-loop} +[4caca7252489] {jit-backend +[4caca726cc63] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bba44 +0 554889E5534154415541564157488DA5000000004C8B3C25B04D5B014C8B342598C2540148C7042598C254010000000049BB70A0CFB8A07F00004D8B2B4983C50149BB70A0CFB8A07F00004D892B4D8B6E404F0FB66C3D184983FD330F85000000004D89FD4983C7014D897E1849C74620000000004D896E2848C7C00100000048890425B04D5B0149C7C340BC920041FFD348C7C001000000488D65D8415F415E415D415C5B5DC3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA570FFFFFF4989FF4989F6E947FFFFFF49BB00905BB6A07F000041FFD33D380350000000 +[4caca727040f] jit-backend-dump} +[4caca7270a0d] {jit-backend-addr +Loop #6 (StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]) has address 7fa0b65bba74 to 7fa0b65bbaec (bootstrap 7fa0b65bba44) +[4caca72717af] jit-backend-addr} +[4caca7271eeb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bba54 +0 70FFFFFF +[4caca7273019] jit-backend-dump} +[4caca72738af] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbaa2 +0 87000000 +[4caca72746b5] jit-backend-dump} +[4caca7274fab] jit-backend} +[4caca7275aaf] {jit-log-opt-loop +# Loop 6 : entry bridge with 10 ops [i0, p1] debug_merge_point(0, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') +78: p2 = getfield_gc(p1, descr=) +82: i3 = strgetitem(p2, i0) +88: i5 = int_eq(i3, 51) -guard_true(i5, descr=) [i0, p1] +guard_true(i5, descr=) [i0, p1] +98: i7 = int_add(i0, 1) +105: setfield_gc(p1, i7, descr=) +109: setfield_gc(p1, ConstPtr(ptr8), descr=) +117: setfield_gc(p1, i0, descr=) -+121: finish(1, descr=) ++121: finish(1, descr=) +168: --end of the loop-- -[1af179d0da7b8] jit-log-opt-loop} -[1af179d281c59] {jit-log-opt-bridge -# bridge out of Guard 44 with 6 ops +[4caca72833af] jit-log-opt-loop} +[4caca73ec6b9] {jit-backend +[4caca73feba1] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbb41 +0 488DA50000000049BB78A0CFB8A07F00004D8B2B4983C50149BB78A0CFB8A07F00004D892B4983C7014D8B6E084D39EF0F8D0000000049BB74BA5BB6A07F000041FFE349BB00905BB6A07F000041FFD33D380351000000 +[4caca7401165] jit-backend-dump} +[4caca74017bb] {jit-backend-addr +Bridge out of guard 80 has address 7fa0b65bbb41 to 7fa0b65bbb84 +[4caca7402331] jit-backend-addr} +[4caca740291b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbb44 +0 70FFFFFF +[4caca7403451] jit-backend-dump} +[4caca7403a29] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbb73 +0 0D000000 +[4caca740430b] jit-backend-dump} +[4caca7404bf1] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbaa2 +0 9B000000 +[4caca74054b5] jit-backend-dump} +[4caca7405a91] jit-backend} +[4caca7406281] {jit-log-opt-bridge +# bridge out of Guard 80 with 6 ops [i0, p1] +37: i3 = int_add(i0, 1) +41: i4 = getfield_gc_pure(p1, descr=) +45: i5 = int_lt(i3, i4) -guard_true(i5, descr=) [i3, p1] +guard_true(i5, descr=) [i3, p1] debug_merge_point(0, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') -+54: jump(i3, p1, descr=) ++54: jump(i3, p1, descr=) +67: --end of the loop-- -[1af179d28ad65] jit-log-opt-bridge} -[1af179d501794] {jit-log-opt-bridge -# bridge out of Guard 45 with 1 ops +[4caca740c999] jit-log-opt-bridge} +[4caca77f59c2] {jit-backend +[4caca780f57c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbb98 +0 488DA50000000049BB80A0CFB8A07F00004D8B334983C60149BB80A0CFB8A07F00004D893348C7C00000000048890425B04D5B0149C7C340BC920041FFD348C7C001000000488D65D8415F415E415D415C5B5DC3 +[4caca782495a] jit-backend-dump} +[4caca7826082] {jit-backend-addr +Bridge out of guard 81 has address 7fa0b65bbb98 to 7fa0b65bbbec +[4caca7827f7e] jit-backend-addr} +[4caca7829178] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbb9b +0 70FFFFFF +[4caca782b236] jit-backend-dump} +[4caca782c3c4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbb73 +0 21000000 +[4caca782e12e] jit-backend-dump} +[4caca782efb6] jit-backend} +[4caca78304da] {jit-log-opt-bridge +# bridge out of Guard 81 with 1 ops [i0, p1] -+37: finish(0, descr=) ++37: finish(0, descr=) +84: --end of the loop-- -[1af179d5051db] jit-log-opt-bridge} -[1af179fc93628] {jit-log-opt-loop -# Loop 6 : loop with 201 ops +[4caca78370ec] jit-log-opt-bridge} +[4cacad3efadb] {jit-backend +[4cacad6472d9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbd77 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF488B0425B0C2540148C70425B0C254010000000048898550FFFFFF488B0425B8C2540148C70425B8C254010000000048898548FFFFFF4C8B3C25C0C2540148C70425C0C2540100000000488B0425C8C2540148C70425C8C254010000000048898540FFFFFF4C8B3425F04D5B01488B0425D8C2540148C70425D8C254010000000048898538FFFFFF488B0425E0C2540148C70425E0C254010000000048898530FFFFFF49BB88A0CFB8A07F00004D8B2B4983C50149BB88A0CFB8A07F00004D892B4C8BAD40FFFFFF4D8B65184D85E40F84000000004D8B55084D8B4C24084D39CA0F8D000000004D8B6424104F8B64D4104983C2014C8BBD70FFFFFF4D8B4F084D89550849BBA0217CB6A07F00004D39D90F85000000004D8B51104981FAC07446010F850000000049BB683A79B6A07F00004D8B0B4983F9017207418139C84000000F85000000004D8B510849BB904279B6A07F00004D39DA0F85000000004D8B42104981F8C07446010F850000000049BB883D79B6A07F00004D8B134983FA01720741813A082601000F85000000004983FC01720841813C24D00400000F85000000004D8B4A1849BB20F777B6A07F00004D39D90F85000000004D8B4A204D8B410848C7C7030000004C29C74883FF020F8F00000000498B7A404C89C64983E8014939F00F8D000000004F8B44C1104C8D8D78FFFFFF4983FE000F850000000049BB904279B6A07F00004C39DF0F85000000004C8B77104981FEC07446010F850000000049BB583C79B6A07F0000498B3B4883FF017206813F082601000F85000000004D85C00F84000000004C8B771849BB68F679B6A07F00004D39DE0F85000000004C8B7740488DB578FFFFFF49BB904279B6A07F00004D39DE0F8500000000498B5E104881FBC07446010F850000000049BBF877CEB8A07F00004D8B334D85F60F85000000004C8B342508DF45014981FE706A49010F8500000000498B5E104881FBC07446010F85000000004C8B3425E8B35D014981FE400244010F850000000049BB683B79B6A07F00004D8B334983FE01720741813E501800000F8500000000488B1C2568915201498B5E10813BE08701000F8500000000498B5E08488D9578FFFFFF48899528FFFFFF4889B520FFFFFF4889BD18FFFFFF4C898510FFFFFF4C898D08FFFFFF4C899500FFFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B9520FFFFFF4C8950084C8B9538FFFFFF41F642040174165041524C89D74889C649C7C310734D0041FFD3415A58498942384C8B8D28FFFFFF4D894F18488985F8FEFFFF488B0425704F3D01488D5028483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7008800000048891425704F3D0148C740080300000048C74010007D440149BB303879B6A07F00004C8958184C8B9510FFFFFF4C89502048899DF0FEFFFF488985E8FEFFFF4C89B5E0FEFFFF4C89A5D8FEFFFF48C78578FFFFFF520000004889C749C7C300B2660041FFD34883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004C8DA578FFFFFF4C8BBD70FFFFFF4D896718488985D0FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700F016000048891425704F3D014C8B95E8FEFFFF4C895008488985C8FEFFFF48C78578FFFFFF53000000488BBDF0FEFFFF4889C6488B95D0FEFFFF49C7C3A0EE660041FFD34883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004989C749BB00000000000000804C21D84883F8000F8500000000488BBDF0FEFFFF4C89FE49C7C370DFB40041FFD348833C2550546B02000F85000000004883F80172068138D03903000F85000000004881F850EB44010F84000000004C8BBD38FFFFFF4D8B57484D85D20F85000000004D8B57284983FA000F85000000004C8B1425E8546D014C8B8DF8FEFFFF49C74108FDFFFFFF4C8B95D8FEFFFF4D8B4A084D8B411049BBFFFFFFFFFFFFFF7F4D39D80F8D00000000488B7810488B7018488B57104883FA110F8500000000488B57204889D14883E2014883FA000F8400000000488B4F384883F9010F8F00000000488B4F184883C101488B54CF104883FA130F85000000004889CA4883C101488B4CCF104883C2024983F8000F8E000000004883FA0B0F85000000004883F9330F850000000049BB2020C8B8A07F00004C39DF0F8500000000488DBD78FFFFFF488985C0FEFFFF4889B5B8FEFFFF4889BDB0FEFFFF4C8985A8FEFFFF4C898DA0FEFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B9508FFFFFF4C89500841F64704017412504C89FF4889C649C7C310734D0041FFD358498947384C8B9570FFFFFF4C8B8DB0FEFFFF4D894A1848898598FEFFFF488B0425704F3D01488D5048483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700685D000048891425704F3D014C8B95A8FEFFFF4C8950084C8B95B8FEFFFF4C8950104C8B95A0FEFFFF4C89504049BB2020C8B8A07F00004C89583848898590FEFFFF48C78578FFFFFF5400000048C7C7000000004889C649BBECBA5BB6A07F000041FFD34883F80174164889C748C7C60000000049C7C3709CBD0041FFD3EB08488B0425B04D5B014883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004885C00F8400000000488B8538FFFFFF4C8B78484D85FF0F85000000004C8B78284983FF000F85000000004C8B1425A0536B024983EA3E4C891425A0536B024C8B8D30FFFFFFF6400401741A41514152504889C74C89CE49C7C310734D0041FFD358415A41594C8948384C8B8598FEFFFF49C74008FDFFFFFF4983FA000F8C000000004D89FE4C898D30FFFFFF4C8BBDD8FEFFFFE905F8FFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA500FEFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4C898550FFFFFF4C898D48FFFFFF4C8B5D104D89DF4C8B5D184C899D40FFFFFF4C8B5D204D89DE4C8B5D284C899D38FFFFFF4C8B5D304C899D30FFFFFFE971F7FFFF49BB00905BB6A07F000041FFD344403430484C50543C035500000049BB00905BB6A07F000041FFD34440342930484C50543C035600000049BB00905BB6A07F000041FFD3443C24484C50543034035700000049BB00905BB6A07F000041FFD3443C2824484C50543034035800000049BB00905BB6A07F000041FFD3443C24484C50543034035900000049BB00905BB6A07F000041FFD3443C2428484C50543034035A00000049BB00905BB6A07F000041FFD3443C242028484C50543034035B00000049BB00905BB6A07F000041FFD3443C2824484C50543034035C00000049BB00905BB6A07F000041FFD3443C30484C50543428035D00000049BB00905BB6A07F000041FFD3443C2428484C50543034035E00000049BB00905BB6A07F000041FFD3443C28484C50543034035F00000049BB00905BB6A07F000041FFD3443C192128484C505430341C036000000049BB00905BB6A07F000041FFD3443C5C484C50543034286020251C036100000049BB00905BB6A07F000041FFD3443C5C1C484C505430342860202507036200000049BB00905BB6A07F000041FFD3443C5C381C484C505430342860202507036300000049BB00905BB6A07F000041FFD3443C5C1C484C505430342860202507036400000049BB00905BB6A07F000041FFD3443C5C20484C50543034281C60072507036500000049BB00905BB6A07F000041FFD3443C5C381C484C50543034280760202507036600000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036700000049BB00905BB6A07F000041FFD3443C5C0C38484C5054303428191C60202507036800000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036900000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036A00000049BB00905BB6A07F000041FFD3443C5C0C38484C5054303428191C60202507036B00000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036C00000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036D00000049BB00905BB6A07F000041FFD3443C5C0C484C505430342838191C60202507036E00000049BB00905BB6A07F000041FFD3443C5C380C484C505430342807191C60202507036F00000049BB45905BB6A07F000041FFD344405C88018001017C484C50548C01587860840170756C035200000049BB45905BB6A07F000041FFD344405C88018001017C484C50548C01587860840170756C037000000049BB45905BB6A07F000041FFD344405C940188010180017C484C50548C01587860706C75035300000049BB45905BB6A07F000041FFD344405C940188010180017C484C50548C01587860706C75037100000049BB00905BB6A07F000041FFD344405C940188013D80017C484C50548C01587860706C75037200000049BB45905BB6A07F000041FFD344405C94018801007C484C50548C01587860706C75037300000049BB00905BB6A07F000041FFD344405C94018801007C484C50548C01587860706C75037400000049BB00905BB6A07F000041FFD344405C7C484C50548C01587894010060706C75037500000049BB00905BB6A07F000041FFD344403C00287C484C50548C01587894010760706C75037600000049BB00905BB6A07F000041FFD344403C007C484C50548C01587894010760706C75037700000049BB00905BB6A07F000041FFD344403C28484C50548C015878070060700775037800000049BB00905BB6A07F000041FFD344403C0024484C5054285878070760700775037900000049BB00905BB6A07F000041FFD344403C00484C5054285878211C1924070760700775037A00000049BB00905BB6A07F000041FFD344403C0005484C5054285878211C1924070760700775037B00000049BB00905BB6A07F000041FFD344403C00484C5054285878211C1924070760700775037C00000049BB00905BB6A07F000041FFD344403C0005484C5054285878211C1924070760700775037D00000049BB00905BB6A07F000041FFD344403C000509484C5054285878211C1924070760700775037E00000049BB00905BB6A07F000041FFD344403C0005091C484C505428587821071924070760700775037F00000049BB00905BB6A07F000041FFD344403C00051C484C505428587821071924070760700775038000000049BB00905BB6A07F000041FFD344403C001C484C505428587821071924070760700775038100000049BB45905BB6A07F000041FFD344405C9801B00101AC01484C50548C0158786070035400000049BB45905BB6A07F000041FFD344405C9801B00101AC01484C50548C0158786070038200000049BB00905BB6A07F000041FFD344405C9801B001AC01484C50548C0158786070038300000049BB00905BB6A07F000041FFD34440003CAC01484C50548C0158789801B0016070038400000049BB00905BB6A07F000041FFD3444000AC01484C50548C0158789801B0016070038500000049BB00905BB6A07F000041FFD34440484C50548C0158070707070386000000 +[4cacad697d75] jit-backend-dump} +[4cacad699617] {jit-backend-addr +Loop #7 ( #44 FOR_ITER) has address 7fa0b65bbe9a to 7fa0b65bc695 (bootstrap 7fa0b65bbd77) +[4cacad69bef7] jit-backend-addr} +[4cacad69d3df] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbd87 +0 00FEFFFF +[4cacad69f335] jit-backend-dump} +[4cacad6a04db] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbec8 +0 5D080000 +[4cacad6a1abf] jit-backend-dump} +[4cacad6a253f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbeda +0 66080000 +[4cacad6a3a21] jit-backend-dump} +[4cacad6a43ff] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbf0a +0 52080000 +[4cacad6a583f] jit-backend-dump} +[4cacad6a6397] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbf1b +0 5C080000 +[4cacad6a78f1] jit-backend-dump} +[4cacad6a840d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbf3b +0 58080000 +[4cacad6a997f] jit-backend-dump} +[4cacad6aa327] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbf52 +0 5C080000 +[4cacad6ab73d] jit-backend-dump} +[4cacad6ac0d9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbf63 +0 67080000 +[4cacad6ad4ef] jit-backend-dump} +[4cacad6ade9d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbf83 +0 64080000 +[4cacad6af3d3] jit-backend-dump} +[4cacad6afe83] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbf97 +0 6C080000 +[4cacad6b14c7] jit-backend-dump} +[4cacad6b1e63] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbfae +0 70080000 +[4cacad6b3285] jit-backend-dump} +[4cacad6b3c1b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbfca +0 70080000 +[4cacad6b502b] jit-backend-dump} +[4cacad6b59e5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbfde +0 77080000 +[4cacad6b6df5] jit-backend-dump} +[4cacad6b78d5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bbff4 +0 7F080000 +[4cacad6b8e65] jit-backend-dump} +[4cacad6b9933] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc007 +0 8C080000 +[4cacad6bae2d] jit-backend-dump} +[4cacad6bb7e7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc018 +0 9C080000 +[4cacad6bcbf7] jit-backend-dump} +[4cacad6bd58d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc037 +0 9F080000 +[4cacad6be9a9] jit-backend-dump} +[4cacad6bf345] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc040 +0 B7080000 +[4cacad6c6e0f] jit-backend-dump} +[4cacad6c7d0f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc057 +0 C2080000 +[4cacad6c9485] jit-backend-dump} +[4cacad6c9fe9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc075 +0 C7080000 +[4cacad6cb4bf] jit-backend-dump} +[4cacad6cbebb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc086 +0 D9080000 +[4cacad6cd319] jit-backend-dump} +[4cacad6cdcd3] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc09c +0 E7080000 +[4cacad6cf10d] jit-backend-dump} +[4cacad6cfaf7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc0b1 +0 F5080000 +[4cacad6d1177] jit-backend-dump} +[4cacad6d1c81] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc0c2 +0 07090000 +[4cacad6d31bd] jit-backend-dump} +[4cacad6d3b8f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc0d7 +0 16090000 +[4cacad6d4fc9] jit-backend-dump} +[4cacad6d5971] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc0f7 +0 19090000 +[4cacad6d6dab] jit-backend-dump} +[4cacad6d7aa1] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc10f +0 48090000 +[4cacad6d90df] jit-backend-dump} +[4cacad6d9bb9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc272 +0 0A080000 +[4cacad6db179] jit-backend-dump} +[4cacad6dbcfb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc281 +0 24080000 +[4cacad6dd18f] jit-backend-dump} +[4cacad6ddc2d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc31f +0 AF070000 +[4cacad6df061] jit-backend-dump} +[4cacad6dfa27] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc32e +0 C9070000 +[4cacad6e0e67] jit-backend-dump} +[4cacad6e1959] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc348 +0 D8070000 +[4cacad6e2f85] jit-backend-dump} +[4cacad6e3abf] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc36b +0 DE070000 +[4cacad6e4fdd] jit-backend-dump} +[4cacad6e59c7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc37d +0 F3070000 +[4cacad6e6e07] jit-backend-dump} +[4cacad6e77cd] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc38a +0 0D080000 +[4cacad6e8c19] jit-backend-dump} +[4cacad6e95f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc39e +0 1E080000 +[4cacad6eac77] jit-backend-dump} +[4cacad6eb75d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc3ac +0 37080000 +[4cacad6ecc9f] jit-backend-dump} +[4cacad6ed74f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc3e5 +0 48080000 +[4cacad6eeb95] jit-backend-dump} +[4cacad6ef54f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc3fb +0 56080000 +[4cacad6f0989] jit-backend-dump} +[4cacad6f1355] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc410 +0 68080000 +[4cacad6f290f] jit-backend-dump} +[4cacad6f3431] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc41e +0 82080000 +[4cacad6f4985] jit-backend-dump} +[4cacad6f5507] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc435 +0 92080000 +[4cacad6f6941] jit-backend-dump} +[4cacad6f72f5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc44f +0 A0080000 +[4cacad6f8735] jit-backend-dump} +[4cacad6f90f5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc459 +0 BF080000 +[4cacad6fa529] jit-backend-dump} +[4cacad6fb07b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc463 +0 DF080000 +[4cacad6fc6c5] jit-backend-dump} +[4cacad6fd175] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc476 +0 F5080000 +[4cacad6fe6e1] jit-backend-dump} +[4cacad6ff0a1] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc5e9 +0 AA070000 +[4cacad7004db] jit-backend-dump} +[4cacad704bfd] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc5f8 +0 C1070000 +[4cacad706457] jit-backend-dump} +[4cacad706fd9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc601 +0 DE070000 +[4cacad708581] jit-backend-dump} +[4cacad709097] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc615 +0 EF070000 +[4cacad70a645] jit-backend-dump} +[4cacad70b113] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc623 +0 07080000 +[4cacad70c59b] jit-backend-dump} +[4cacad70cf55] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bc67b +0 D4070000 +[4cacad70e311] jit-backend-dump} +[4cacad70f2dd] jit-backend} +[4cacad71126f] {jit-log-opt-loop +# Loop 7 : loop with 202 ops [p0, p1, p2, p3, p4, p5, p6, p7, i8, p9, p10] -debug_merge_point(0, ' #44 FOR_ITER') -+321: p11 = getfield_gc(p4, descr=) -+332: guard_nonnull(p11, descr=) [p1, p0, p4, p11, p2, p3, p5, p6, p7] -+341: i12 = getfield_gc(p4, descr=) +debug_merge_point(0, ' #44 FOR_ITER') ++321: p11 = getfield_gc(p7, descr=) ++332: guard_nonnull(p11, descr=) [p1, p0, p7, p11, p2, p3, p4, p5, p6] ++341: i12 = getfield_gc(p7, descr=) +345: i13 = getfield_gc(p11, descr=) +350: i14 = int_ge(i12, i13) -guard_false(i14, descr=) [p1, p0, p4, i12, p11, p2, p3, p5, p6, p7] +guard_false(i14, descr=) [p1, p0, p7, i12, p11, p2, p3, p4, p5, p6] +359: p15 = getfield_gc(p11, descr=) +364: p16 = getarrayitem_gc(p15, i12, descr=) +369: i18 = int_add(i12, 1) -debug_merge_point(0, ' #47 STORE_FAST') -debug_merge_point(0, ' #50 LOAD_GLOBAL') +debug_merge_point(0, ' #47 STORE_FAST') +debug_merge_point(0, ' #50 LOAD_GLOBAL') +373: p19 = getfield_gc(p0, descr=) -+384: setfield_gc(p4, i18, descr=) -+388: guard_value(p19, ConstPtr(ptr20), descr=) [p1, p0, p19, p2, p3, p4, p5, p6, p16] -+407: p21 = getfield_gc(p19, descr=) -+411: guard_isnull(p21, descr=) [p1, p0, p21, p19, p2, p3, p4, p5, p6, p16] -+420: p23 = getfield_gc(ConstPtr(ptr22), descr=) -+433: guard_nonnull_class(p23, 21015776, descr=) [p1, p0, p23, p2, p3, p4, p5, p6, p16] -debug_merge_point(0, ' #53 LOOKUP_METHOD') -+452: p25 = getfield_gc(p23, descr=) -+456: guard_value(p25, ConstPtr(ptr26), descr=) [p1, p0, p23, p25, p2, p3, p4, p5, p6, p16] -+475: p27 = getfield_gc(p25, descr=) -+479: guard_isnull(p27, descr=) [p1, p0, p23, p27, p25, p2, p3, p4, p5, p6, p16] -+488: p29 = getfield_gc(ConstPtr(ptr28), descr=) -+501: guard_nonnull_class(p29, ConstClass(Function), descr=) [p1, p0, p29, p23, p2, p3, p4, p5, p6, p16] -debug_merge_point(0, ' #56 LOAD_CONST') -debug_merge_point(0, ' #59 LOAD_FAST') -+520: guard_nonnull_class(p16, ConstClass(W_StringObject), descr=) [p1, p0, p16, p2, p3, p4, p29, p5, p6] -debug_merge_point(0, ' #62 CALL_METHOD') -+540: p32 = getfield_gc(p29, descr=) -+544: guard_value(p32, ConstPtr(ptr33), descr=) [p1, p0, p32, p29, p2, p3, p4, p16, p5, p6] -+563: p34 = getfield_gc(p29, descr=) -+567: i35 = arraylen_gc(p34, descr=) -+571: i37 = int_sub(3, i35) -+581: i39 = int_ge(2, i37) -guard_true(i39, descr=) [p1, p0, p29, p2, p3, p4, p16, p5, p6] -+591: p40 = getfield_gc(p29, descr=) -+595: p41 = getfield_gc(p29, descr=) -+595: i43 = int_sub(i35, 1) -+602: i44 = int_ge(i43, i35) -guard_false(i44, descr=) [p1, p0, i35, i43, p29, p2, p3, p4, p16, p5, p6, p40] -+611: p45 = getarrayitem_gc_pure(p34, i43, descr=) -+616: i46 = force_token() -+623: i47 = int_is_zero(i8) -guard_true(i47, descr=) [p1, p0, p9, p2, p3, p4, p29, p16, p5, p6, p45, p10, i46, p40] -debug_merge_point(1, ' #0 LOAD_GLOBAL') -+633: guard_value(p40, ConstPtr(ptr48), descr=) [p1, p0, p9, p40, p2, p3, p4, p29, p16, p5, p6, p45, p10, i46, None] -+652: p50 = getfield_gc(p40, descr=) -+656: guard_isnull(p50, descr=) [p1, p0, p9, p50, p40, p2, p3, p4, p29, p16, p5, p6, p45, p10, i46, None] -+665: p52 = getfield_gc(ConstPtr(ptr51), descr=) -+678: guard_nonnull_class(p52, ConstClass(Function), descr=) [p1, p0, p9, p52, p2, p3, p4, p29, p16, p5, p6, p45, p10, i46, None] -debug_merge_point(1, ' #3 LOAD_FAST') -debug_merge_point(1, ' #6 LOAD_FAST') -+696: guard_nonnull(p45, descr=) [p1, p0, p9, p45, p2, p3, p4, p29, p16, p5, p6, p52, None, p10, i46, None] -debug_merge_point(1, ' #9 CALL_FUNCTION') -+705: p54 = getfield_gc(p52, descr=) -+709: guard_value(p54, ConstPtr(ptr55), descr=) [p1, p0, p9, p54, p52, p2, p3, p4, p29, p16, p5, p6, None, p45, p10, i46, None] -+728: p56 = getfield_gc(p52, descr=) -+732: p57 = getfield_gc(p52, descr=) -+732: p58 = getfield_gc(p52, descr=) -+732: p59 = getfield_gc(p52, descr=) -+732: i60 = force_token() -debug_merge_point(2, ' #0 LOAD_GLOBAL') -+739: guard_value(p56, ConstPtr(ptr61), descr=) [p1, p0, p9, p56, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] -+758: p62 = getfield_gc(p56, descr=) -+762: guard_isnull(p62, descr=) [p1, p0, p9, p62, p56, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] -+771: p64 = getfield_gc(ConstPtr(ptr63), descr=) -+784: guard_isnull(p64, descr=) [p1, p0, p9, p64, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] -+793: p66 = getfield_gc(ConstPtr(ptr65), descr=) -+801: guard_value(p66, ConstPtr(ptr67), descr=) [p1, p0, p9, p66, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] -+814: p68 = getfield_gc(p66, descr=) -+818: guard_isnull(p68, descr=) [p1, p0, p9, p68, p66, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] -+827: p70 = getfield_gc(ConstPtr(ptr69), descr=) -+835: guard_value(p70, ConstPtr(ptr71), descr=) [p1, p0, p9, p70, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] -debug_merge_point(2, ' #3 LOAD_FAST') -debug_merge_point(2, ' #6 LOAD_CONST') -debug_merge_point(2, ' #9 BINARY_SUBSCR') -debug_merge_point(2, ' #10 CALL_FUNCTION') -debug_merge_point(2, ' #13 BUILD_TUPLE') -debug_merge_point(2, ' #16 LOAD_FAST') -debug_merge_point(2, ' #19 BINARY_ADD') -debug_merge_point(2, ' #20 STORE_FAST') -debug_merge_point(2, ' #23 LOAD_GLOBAL') -+848: p73 = getfield_gc(ConstPtr(ptr72), descr=) -+861: guard_nonnull_class(p73, 21003520, descr=) [p1, p0, p9, p73, p2, p3, p4, p29, p16, p5, p6, i60, p52, p45, p10, i46, None] -debug_merge_point(2, ' #26 LOOKUP_METHOD') -debug_merge_point(2, ' #29 LOAD_FAST') -debug_merge_point(2, ' #32 CALL_METHOD') -+880: p76 = getfield_gc(ConstPtr(ptr75), descr=) -+888: guard_not_invalidated(, descr=) [p1, p0, p9, p76, p2, p3, p4, p29, p16, p5, p6, p73, i60, p52, p45, p10, i46, None] -+888: p77 = getfield_gc(p73, descr=) -+892: guard_nonnull(p77, descr=) [p1, p0, p9, p73, p77, p2, p3, p4, p29, p16, p5, p6, None, i60, p52, p45, p10, i46, None] -+901: i78 = force_token() -+908: p80 = new_with_vtable(21002328) -+1013: setfield_gc(p80, i60, descr=) -setfield_gc(p9, p80, descr=) -+1064: setfield_gc(p0, i78, descr=) -+1075: p82 = new_array(3, descr=) -+1153: setarrayitem_gc(p82, 0, ConstPtr(ptr84), descr=) -+1161: setarrayitem_gc(p82, 1, ConstPtr(ptr86), descr=) -+1175: setarrayitem_gc(p82, 2, p45, descr=) -+1186: i89 = call_may_force(ConstClass(hash_tuple), p82, descr=) -guard_not_forced(, descr=) [p1, p0, p9, p73, p77, i89, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p82, p10] -+1252: guard_no_exception(, descr=) [p1, p0, p9, p73, p77, i89, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p82, p10] -+1267: i90 = force_token() -+1274: setfield_gc(p0, i90, descr=) -+1285: p92 = new_with_vtable(21002400) -+1355: setfield_gc(p92, p82, descr=) -+1366: i94 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p77, p92, i89, descr=) -guard_not_forced(, descr=) [p1, p0, p9, p92, p73, i94, p77, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] -+1425: guard_no_exception(, descr=) [p1, p0, p9, p92, p73, i94, p77, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] -+1440: i96 = int_and(i94, -9223372036854775808) -+1456: i97 = int_is_true(i96) -guard_false(i97, descr=) [p1, p0, p9, p92, p73, i94, p77, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] -+1466: p99 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p77, i94, descr=) -+1486: guard_no_exception(, descr=) [p1, p0, p9, p92, p73, p99, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] -+1501: guard_nonnull_class(p99, 21206408, descr=) [p1, p0, p9, p92, p73, p99, p80, p2, p3, p4, p29, p16, p5, p6, p52, i46, p45, p10] -debug_merge_point(2, ' #35 STORE_FAST') -debug_merge_point(2, ' #38 LOAD_FAST') -debug_merge_point(2, ' #41 LOAD_CONST') -debug_merge_point(2, ' #44 COMPARE_OP') -+1519: i102 = ptr_eq(p99, ConstPtr(ptr101)) -guard_false(i102, descr=) [p1, p0, p9, p80, p2, p3, p4, p29, p16, p5, p6, p92, p99, p52, i46, p45, p10] -debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') -debug_merge_point(2, ' #50 LOAD_FAST') -debug_merge_point(2, ' #53 RETURN_VALUE') -+1532: p103 = getfield_gc(p9, descr=) -+1543: guard_isnull(p103, descr=) [p1, p0, p9, p99, p103, p80, p2, p3, p4, p29, p16, p5, p6, p92, None, p52, i46, p45, p10] -+1552: i104 = getfield_gc(p9, descr=) -+1556: i105 = int_is_true(i104) -guard_false(i105, descr=) [p1, p0, p9, p99, p80, p2, p3, p4, p29, p16, p5, p6, p92, None, p52, i46, p45, p10] -+1566: p106 = getfield_gc(p9, descr=) -debug_merge_point(1, ' #12 LOOKUP_METHOD') -debug_merge_point(1, ' #15 LOAD_FAST') -debug_merge_point(1, ' #18 CALL_METHOD') -+1566: p108 = getfield_gc(ConstPtr(ptr107), descr=) -+1574: setfield_gc(p80, -3, descr=) -+1589: guard_not_invalidated(, descr=) [p1, p0, p9, p108, p2, p3, p4, p29, p16, p5, p6, None, p99, None, i46, p45, p10] -+1589: p110 = getfield_gc_pure(p16, descr=) -+1600: i111 = strlen(p110) -+1604: i113 = int_gt(9223372036854775807, i111) -guard_true(i113, descr=) [p1, p0, p9, p99, p110, p2, p3, p4, p29, p16, p5, p6, None, None, None, i46, p45, p10] -+1623: p114 = getfield_gc(p99, descr=) -+1627: i115 = getfield_gc(p99, descr=) -+1631: i117 = getarrayitem_gc_pure(p114, 0, descr=) -+1635: i119 = int_eq(i117, 17) -guard_true(i119, descr=) [p1, p0, p9, p99, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] -+1645: i121 = getarrayitem_gc_pure(p114, 2, descr=) -+1649: i123 = int_and(i121, 1) -+1656: i124 = int_is_true(i123) -guard_true(i124, descr=) [p1, p0, p9, p99, i121, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] -+1666: i126 = getarrayitem_gc_pure(p114, 5, descr=) -+1670: i128 = int_gt(i126, 1) -guard_false(i128, descr=) [p1, p0, p9, p99, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] -+1680: i130 = getarrayitem_gc_pure(p114, 1, descr=) -+1684: i132 = int_add(i130, 1) -+1688: i133 = getarrayitem_gc_pure(p114, i132, descr=) -+1693: i135 = int_eq(i133, 19) -guard_true(i135, descr=) [p1, p0, p9, p99, i132, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] -+1703: i137 = int_add(i132, 1) -+1710: i138 = getarrayitem_gc_pure(p114, i137, descr=) -+1715: i140 = int_add(i132, 2) -+1719: i142 = int_lt(0, i111) -guard_true(i142, descr=) [p1, p0, p9, p99, i138, i140, p2, p3, p4, p29, p16, p5, p6, p114, i111, p110, i115, None, None, None, i46, p45, p10] -+1729: guard_value(i140, 11, descr=) [p1, p0, p9, p99, i138, i140, p114, p2, p3, p4, p29, p16, p5, p6, None, i111, p110, i115, None, None, None, i46, p45, p10] -+1739: guard_value(i138, 51, descr=) [p1, p0, p9, p99, i138, p114, p2, p3, p4, p29, p16, p5, p6, None, i111, p110, i115, None, None, None, i46, p45, p10] -+1749: guard_value(p114, ConstPtr(ptr145), descr=) [p1, p0, p9, p99, p114, p2, p3, p4, p29, p16, p5, p6, None, i111, p110, i115, None, None, None, i46, p45, p10] ++384: setfield_gc(p7, i18, descr=) ++388: guard_value(p19, ConstPtr(ptr20), descr=) [p1, p0, p19, p2, p3, p4, p5, p16, p7] ++407: p21 = getfield_gc(p19, descr=) ++411: guard_value(p21, ConstPtr(ptr22), descr=) [p1, p0, p21, p19, p2, p3, p4, p5, p16, p7] ++424: p24 = getfield_gc(ConstPtr(ptr23), descr=) ++437: guard_nonnull_class(p24, 20812584, descr=) [p1, p0, p24, p2, p3, p4, p5, p16, p7] +debug_merge_point(0, ' #53 LOOKUP_METHOD') ++456: p26 = getfield_gc(p24, descr=) ++460: guard_value(p26, ConstPtr(ptr27), descr=) [p1, p0, p24, p26, p2, p3, p4, p5, p16, p7] ++479: p28 = getfield_gc(p26, descr=) ++483: guard_value(p28, ConstPtr(ptr29), descr=) [p1, p0, p24, p28, p26, p2, p3, p4, p5, p16, p7] ++496: p31 = getfield_gc(ConstPtr(ptr30), descr=) ++509: guard_nonnull_class(p31, ConstClass(Function), descr=) [p1, p0, p31, p24, p2, p3, p4, p5, p16, p7] +debug_merge_point(0, ' #56 LOAD_CONST') +debug_merge_point(0, ' #59 LOAD_FAST') ++528: guard_nonnull_class(p16, ConstClass(W_StringObject), descr=) [p1, p0, p16, p2, p3, p4, p5, p7, p31] +debug_merge_point(0, ' #62 CALL_METHOD') ++548: p34 = getfield_gc(p31, descr=) ++552: guard_value(p34, ConstPtr(ptr35), descr=) [p1, p0, p34, p31, p2, p3, p4, p5, p16, p7] ++571: p36 = getfield_gc(p31, descr=) ++575: i37 = arraylen_gc(p36, descr=) ++579: i39 = int_sub(3, i37) ++589: i41 = int_ge(2, i39) +guard_true(i41, descr=) [p1, p0, p31, p2, p3, p4, p5, p16, p7] ++599: p42 = getfield_gc(p31, descr=) ++603: p43 = getfield_gc(p31, descr=) ++603: i45 = int_sub(i37, 1) ++610: i46 = int_ge(i45, i37) +guard_false(i46, descr=) [p1, p0, i37, i45, p31, p2, p3, p4, p5, p16, p7, p42] ++619: p47 = getarrayitem_gc_pure(p36, i45, descr=) ++624: i48 = force_token() ++631: i49 = int_is_zero(i8) +guard_true(i49, descr=) [p1, p0, p9, p2, p3, p4, p5, p16, p7, p31, p10, p47, i48, p42] +debug_merge_point(1, ' #0 LOAD_GLOBAL') ++641: guard_value(p42, ConstPtr(ptr50), descr=) [p1, p0, p9, p42, p2, p3, p4, p5, p16, p7, p31, p10, p47, i48, None] ++660: p52 = getfield_gc(p42, descr=) ++664: guard_value(p52, ConstPtr(ptr53), descr=) [p1, p0, p9, p52, p42, p2, p3, p4, p5, p16, p7, p31, p10, p47, i48, None] ++677: p55 = getfield_gc(ConstPtr(ptr54), descr=) ++690: guard_nonnull_class(p55, ConstClass(Function), descr=) [p1, p0, p9, p55, p2, p3, p4, p5, p16, p7, p31, p10, p47, i48, None] +debug_merge_point(1, ' #3 LOAD_FAST') +debug_merge_point(1, ' #6 LOAD_FAST') ++708: guard_nonnull(p47, descr=) [p1, p0, p9, p47, p2, p3, p4, p5, p16, p7, p31, p55, p10, None, i48, None] +debug_merge_point(1, ' #9 CALL_FUNCTION') ++717: p57 = getfield_gc(p55, descr=) ++721: guard_value(p57, ConstPtr(ptr58), descr=) [p1, p0, p9, p57, p55, p2, p3, p4, p5, p16, p7, p31, None, p10, p47, i48, None] ++740: p59 = getfield_gc(p55, descr=) ++744: p60 = getfield_gc(p55, descr=) ++744: p61 = getfield_gc(p55, descr=) ++744: p62 = getfield_gc(p55, descr=) ++744: i63 = force_token() +debug_merge_point(2, ' #0 LOAD_GLOBAL') ++751: guard_value(p59, ConstPtr(ptr64), descr=) [p1, p0, p9, p59, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] ++770: p65 = getfield_gc(p59, descr=) ++774: guard_value(p65, ConstPtr(ptr66), descr=) [p1, p0, p9, p65, p59, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] ++787: p68 = getfield_gc(ConstPtr(ptr67), descr=) ++800: guard_isnull(p68, descr=) [p1, p0, p9, p68, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] ++809: p70 = getfield_gc(ConstPtr(ptr69), descr=) ++817: guard_value(p70, ConstPtr(ptr71), descr=) [p1, p0, p9, p70, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] ++830: p72 = getfield_gc(p70, descr=) ++834: guard_value(p72, ConstPtr(ptr73), descr=) [p1, p0, p9, p72, p70, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] ++847: p75 = getfield_gc(ConstPtr(ptr74), descr=) ++855: guard_value(p75, ConstPtr(ptr76), descr=) [p1, p0, p9, p75, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] +debug_merge_point(2, ' #3 LOAD_FAST') +debug_merge_point(2, ' #6 LOAD_CONST') +debug_merge_point(2, ' #9 BINARY_SUBSCR') +debug_merge_point(2, ' #10 CALL_FUNCTION') +debug_merge_point(2, ' #13 BUILD_TUPLE') +debug_merge_point(2, ' #16 LOAD_FAST') +debug_merge_point(2, ' #19 BINARY_ADD') +debug_merge_point(2, ' #20 STORE_FAST') +debug_merge_point(2, ' #23 LOAD_GLOBAL') ++868: p78 = getfield_gc(ConstPtr(ptr77), descr=) ++881: guard_nonnull_class(p78, 20802224, descr=) [p1, p0, p9, p78, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] +debug_merge_point(2, ' #26 LOOKUP_METHOD') +debug_merge_point(2, ' #29 LOAD_FAST') +debug_merge_point(2, ' #32 CALL_METHOD') ++900: p81 = getfield_gc(ConstPtr(ptr80), descr=) ++908: guard_not_invalidated(, descr=) [p1, p0, p9, p81, p2, p3, p4, p5, p16, p7, p31, p78, i63, p55, p10, p47, i48, None] ++908: p82 = getfield_gc(p78, descr=) ++912: guard_class(p82, ConstClass(ObjectDictStrategy), descr=) [p1, p0, p9, p78, p82, p2, p3, p4, p5, p16, p7, p31, None, i63, p55, p10, p47, i48, None] ++924: p84 = getfield_gc(p78, descr=) ++928: i85 = force_token() ++935: p87 = new_with_vtable(20801800) ++1040: setfield_gc(p87, i63, descr=) +setfield_gc(p9, p87, descr=) ++1091: setfield_gc(p0, i85, descr=) ++1102: p89 = new_array(3, descr=) ++1180: setarrayitem_gc(p89, 0, ConstPtr(ptr91), descr=) ++1188: setarrayitem_gc(p89, 1, ConstPtr(ptr93), descr=) ++1202: setarrayitem_gc(p89, 2, p47, descr=) ++1213: i96 = call_may_force(ConstClass(hash_tuple), p89, descr=) +guard_not_forced(, descr=) [p1, p0, p9, p78, p84, i96, p87, p2, p3, p4, p5, p16, p7, p31, p10, p89, p47, i48, p55] ++1279: guard_no_exception(, descr=) [p1, p0, p9, p78, p84, i96, p87, p2, p3, p4, p5, p16, p7, p31, p10, p89, p47, i48, p55] ++1294: i97 = force_token() ++1301: setfield_gc(p0, i97, descr=) ++1312: p99 = new_with_vtable(20801872) ++1382: setfield_gc(p99, p89, descr=) ++1393: i101 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p84, p99, i96, descr=) +guard_not_forced(, descr=) [p1, p0, p9, p99, p78, i101, p84, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] ++1452: guard_no_exception(, descr=) [p1, p0, p9, p99, p78, i101, p84, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] ++1467: i103 = int_and(i101, -9223372036854775808) ++1483: i104 = int_is_true(i103) +guard_false(i104, descr=) [p1, p0, p9, p99, p78, i101, p84, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] ++1493: p106 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p84, i101, descr=) ++1513: guard_no_exception(, descr=) [p1, p0, p9, p99, p78, p106, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] ++1528: guard_nonnull_class(p106, 21007408, descr=) [p1, p0, p9, p99, p78, p106, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] +debug_merge_point(2, ' #35 STORE_FAST') +debug_merge_point(2, ' #38 LOAD_FAST') +debug_merge_point(2, ' #41 LOAD_CONST') +debug_merge_point(2, ' #44 COMPARE_OP') ++1546: i109 = ptr_eq(p106, ConstPtr(ptr108)) +guard_false(i109, descr=) [p1, p0, p9, p87, p2, p3, p4, p5, p16, p7, p31, p99, p106, p10, p47, p55, i48] +debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') +debug_merge_point(2, ' #50 LOAD_FAST') +debug_merge_point(2, ' #53 RETURN_VALUE') ++1559: p110 = getfield_gc(p9, descr=) ++1570: guard_isnull(p110, descr=) [p1, p0, p9, p106, p110, p87, p2, p3, p4, p5, p16, p7, p31, p99, None, p10, p47, p55, i48] ++1579: i111 = getfield_gc(p9, descr=) ++1583: i112 = int_is_true(i111) +guard_false(i112, descr=) [p1, p0, p9, p106, p87, p2, p3, p4, p5, p16, p7, p31, p99, None, p10, p47, p55, i48] ++1593: p113 = getfield_gc(p9, descr=) +debug_merge_point(1, ' #12 LOOKUP_METHOD') +debug_merge_point(1, ' #15 LOAD_FAST') +debug_merge_point(1, ' #18 CALL_METHOD') ++1593: p115 = getfield_gc(ConstPtr(ptr114), descr=) ++1601: setfield_gc(p87, -3, descr=) ++1616: guard_not_invalidated(, descr=) [p1, p0, p9, p115, p2, p3, p4, p5, p16, p7, p31, None, p106, p10, p47, None, i48] ++1616: p117 = getfield_gc_pure(p16, descr=) ++1627: i118 = strlen(p117) ++1631: i120 = int_gt(9223372036854775807, i118) +guard_true(i120, descr=) [p1, p0, p9, p106, p117, p2, p3, p4, p5, p16, p7, p31, None, None, p10, p47, None, i48] ++1650: p121 = getfield_gc(p106, descr=) ++1654: i122 = getfield_gc(p106, descr=) ++1658: i124 = getarrayitem_gc_pure(p121, 0, descr=) ++1662: i126 = int_eq(i124, 17) +guard_true(i126, descr=) [p1, p0, p9, p106, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] ++1672: i128 = getarrayitem_gc_pure(p121, 2, descr=) ++1676: i130 = int_and(i128, 1) ++1683: i131 = int_is_true(i130) +guard_true(i131, descr=) [p1, p0, p9, p106, i128, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] ++1693: i133 = getarrayitem_gc_pure(p121, 5, descr=) ++1697: i135 = int_gt(i133, 1) +guard_false(i135, descr=) [p1, p0, p9, p106, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] ++1707: i137 = getarrayitem_gc_pure(p121, 1, descr=) ++1711: i139 = int_add(i137, 1) ++1715: i140 = getarrayitem_gc_pure(p121, i139, descr=) ++1720: i142 = int_eq(i140, 19) +guard_true(i142, descr=) [p1, p0, p9, p106, i139, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] ++1730: i144 = int_add(i139, 1) ++1737: i145 = getarrayitem_gc_pure(p121, i144, descr=) ++1742: i147 = int_add(i139, 2) ++1746: i149 = int_lt(0, i118) +guard_true(i149, descr=) [p1, p0, p9, p106, i145, i147, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] ++1756: guard_value(i147, 11, descr=) [p1, p0, p9, p106, i145, i147, p121, p2, p3, p4, p5, p16, p7, p31, i118, None, i122, p117, None, None, p10, p47, None, i48] ++1766: guard_value(i145, 51, descr=) [p1, p0, p9, p106, i145, p121, p2, p3, p4, p5, p16, p7, p31, i118, None, i122, p117, None, None, p10, p47, None, i48] ++1776: guard_value(p121, ConstPtr(ptr152), descr=) [p1, p0, p9, p106, p121, p2, p3, p4, p5, p16, p7, p31, i118, None, i122, p117, None, None, p10, p47, None, i48] debug_merge_point(2, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') -+1768: i146 = force_token() -+1775: p147 = new_with_vtable(21002328) -+1873: setfield_gc(p147, i46, descr=) -setfield_gc(p9, p147, descr=) -+1913: setfield_gc(p0, i146, descr=) -+1931: p149 = new_with_vtable(21022112) -+2001: setfield_gc(p149, ConstPtr(ptr145), descr=) -+2015: setfield_gc(p149, i115, descr=) -+2026: setfield_gc(p149, p110, descr=) -+2037: setfield_gc(p149, i111, descr=) -+2048: i150 = call_assembler(0, p149, descr=) -guard_not_forced(, descr=) [p1, p0, p9, p99, p149, i150, p147, p2, p3, p4, p29, p16, p5, p6, p45, p10] -+2139: guard_no_exception(, descr=) [p1, p0, p9, p99, p149, i150, p147, p2, p3, p4, p29, p16, p5, p6, p45, p10] -+2154: guard_true(i150, descr=) [p1, p0, p9, p99, p149, p147, p2, p3, p4, p29, p16, p5, p6, p45, p10] -debug_merge_point(1, ' #21 RETURN_VALUE') -+2163: p151 = getfield_gc(p9, descr=) -+2174: guard_isnull(p151, descr=) [p1, p0, p9, p151, p147, p2, p3, p4, p29, p16, p5, p6, p99, p149, p45, p10] -+2183: i152 = getfield_gc(p9, descr=) -+2187: i153 = int_is_true(i152) -guard_false(i153, descr=) [p1, p0, p9, p147, p2, p3, p4, p29, p16, p5, p6, p99, p149, p45, p10] -+2197: p154 = getfield_gc(p9, descr=) -debug_merge_point(0, ' #65 POP_TOP') -debug_merge_point(0, ' #66 JUMP_ABSOLUTE') -+2197: i156 = getfield_raw(40681184, descr=) -+2205: i158 = int_sub(i156, 62) -+2209: setfield_raw(40681184, i158, descr=) ++1795: i153 = force_token() ++1802: p154 = new_with_vtable(20801800) ++1900: setfield_gc(p154, i48, descr=) +setfield_gc(p9, p154, descr=) ++1940: setfield_gc(p0, i153, descr=) ++1958: p156 = new_with_vtable(20819912) ++2028: setfield_gc(p156, i118, descr=) ++2039: setfield_gc(p156, i122, descr=) ++2050: setfield_gc(p156, p117, descr=) ++2061: setfield_gc(p156, ConstPtr(ptr152), descr=) ++2075: i157 = call_assembler(0, p156, descr=) +guard_not_forced(, descr=) [p1, p0, p9, p106, p156, i157, p154, p2, p3, p4, p5, p16, p7, p31, p10, p47] ++2166: guard_no_exception(, descr=) [p1, p0, p9, p106, p156, i157, p154, p2, p3, p4, p5, p16, p7, p31, p10, p47] ++2181: guard_true(i157, descr=) [p1, p0, p9, p106, p156, p154, p2, p3, p4, p5, p16, p7, p31, p10, p47] +debug_merge_point(1, ' #21 RETURN_VALUE') ++2190: p158 = getfield_gc(p9, descr=) ++2201: guard_isnull(p158, descr=) [p1, p0, p9, p158, p154, p2, p3, p4, p5, p16, p7, p31, p106, p156, p10, p47] ++2210: i159 = getfield_gc(p9, descr=) ++2214: i160 = int_is_true(i159) +guard_false(i160, descr=) [p1, p0, p9, p154, p2, p3, p4, p5, p16, p7, p31, p106, p156, p10, p47] ++2224: p161 = getfield_gc(p9, descr=) +debug_merge_point(0, ' #65 POP_TOP') +debug_merge_point(0, ' #66 JUMP_ABSOLUTE') ++2224: i163 = getfield_raw(40588192, descr=) ++2232: i165 = int_sub(i163, 62) ++2236: setfield_raw(40588192, i165, descr=) setfield_gc(p9, p10, descr=) -+2260: setfield_gc(p147, -3, descr=) -+2275: i161 = int_lt(i158, 0) -guard_false(i161, descr=) [p1, p0, p2, p3, p4, p5, p6, p16, None, None, None, None] -debug_merge_point(0, ' #44 FOR_ITER') -+2285: jump(p0, p1, p2, p3, p4, p5, p6, p16, i152, p9, p10, descr=) -+2304: --end of the loop-- -[1af179fd9d3c7] jit-log-opt-loop} -[1af17a03f77a7] {jit-log-opt-loop -# Loop 7 : entry bridge with 211 ops ++2287: setfield_gc(p154, -3, descr=) ++2302: i168 = int_lt(i165, 0) +guard_false(i168, descr=) [p1, p0, p2, p3, p4, p5, p16, p7, None, None, None, None] +debug_merge_point(0, ' #44 FOR_ITER') ++2312: jump(p0, p1, p2, p3, p4, p5, p16, p7, i159, p9, p10, descr=) ++2334: --end of the loop-- +[4cacad8c060f] jit-log-opt-loop} +[4cacad8cacbf] {jit-backend +[4cacae25aaeb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd011 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C2540100000000488B0C25E8C2540148C70425E8C2540100000000488B0425F0C2540148C70425F0C254010000000048898570FFFFFF488B0425F8C2540148C70425F8C254010000000048898568FFFFFF488B042500C3540148C7042500C354010000000048898560FFFFFF488B042508C3540148C7042508C354010000000048898558FFFFFF49BB90A0CFB8A07F0000498B034883C00149BB90A0CFB8A07F00004989034983F8040F85000000008139B82F00000F8500000000488B79184885FF0F84000000004C8B4108488B47084939C00F8D00000000488B7F104A8B7CC7104983C0014C8941084983FA000F850000000049BBF8F477B6A07F00004D39DC0F85000000004D8B670849BBA0217CB6A07F00004D39DC0F8500000000498B5424104881FAC07446010F850000000049BB683A79B6A07F00004D8B234983FC01720841813C24C84000000F8500000000498B54240849BB904279B6A07F00004C39DA0F85000000004C8B52104981FAC07446010F850000000049BB883D79B6A07F0000498B134883FA017206813A082601000F85000000004883FF017206813FD00400000F85000000004C8B621849BB20F777B6A07F00004D39DC0F85000000004C8B62204D8B54240849C7C0030000004D29D04983F8020F8F000000004C8B42404C89D04983EA014939C20F8D000000004F8B54D4104889BD50FFFFFF48899548FFFFFF4C898540FFFFFF48898D38FFFFFF4C898D30FFFFFF4C899528FFFFFF4889B520FFFFFF49C7C3B0A0500041FFD3488B70384C8D9578FFFFFF4C8B48484D85C90F85000000004C8B48284983F9000F85000000004C8B8D40FFFFFF49BB904279B6A07F00004D39D90F8500000000498B49104881F9C07446010F850000000049BB583C79B6A07F00004D8B0B4983F9017207418139082601000F8500000000488B8D28FFFFFF4885C90F84000000004D8B411849BB68F679B6A07F00004D39D80F85000000004D8B4140498B5128498B792048833C2550546B02000F8500000000488DBD78FFFFFF49BB904279B6A07F00004D39D80F8500000000498B50104881FAC07446010F850000000049BBF877CEB8A07F00004D8B034D85C00F85000000004C8B042508DF45014981F8706A49010F8500000000498B50104881FAC07446010F85000000004C8B0425E8B35D014981F8400244010F850000000049BB683B79B6A07F00004D8B034983F8017207418138501800000F8500000000488B142568915201498B5010813AE08701000F8500000000498B50084C8DA578FFFFFF48898518FFFFFF48899510FFFFFF4889B508FFFFFF4889BD00FFFFFF4C8985F8FEFFFF4C898DF0FEFFFF4C8995E8FEFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B9500FFFFFF4C8950084C8B9518FFFFFF41F642040174165041524C89D74889C649C7C310734D0041FFD3415A58498942384D896718488985E0FEFFFF488B0425704F3D01488D5028483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7008800000048891425704F3D0148C740080300000048C74010007D440149BB303879B6A07F00004C8958184C8B9528FFFFFF4C8950204C89BDD8FEFFFF488985D0FEFFFF48899DC8FEFFFF4C89B5C0FEFFFF4C89ADB8FEFFFF48C78578FFFFFF870000004889C749C7C300B2660041FFD34883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004C8DAD78FFFFFF4C8BB5D8FEFFFF4D896E18488985B0FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700F016000048891425704F3D014C8B95D0FEFFFF4C895008488985A8FEFFFF48C78578FFFFFF88000000488BBD10FFFFFF4889C6488B95B0FEFFFF49C7C3A0EE660041FFD34883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004989C649BB00000000000000804C21D84883F8000F8500000000488BBD10FFFFFF4C89F649C7C370DFB40041FFD348833C2550546B02000F85000000004883F80172068138D03903000F85000000004881F850EB44010F84000000004C8BB518FFFFFF4D8B56484D85D20F85000000004D8B56284983FA000F85000000004C8B1425E8546D014C8B8DE0FEFFFF49C74108FDFFFFFF4C8B9550FFFFFF4D8B4A084D8B411049BBFFFFFFFFFFFFFF7F4D39D80F8D00000000488B7810488B7018488B57104883FA110F8500000000488B57204889D14883E2014883FA000F8400000000488B4F384883F9010F8F00000000488B4F184883C101488B54CF104883FA130F85000000004889CA4883C101488B4CCF104883C2024983F8000F8E000000004883FA0B0F85000000004883F9330F850000000049BB2020C8B8A07F00004C39DF0F8500000000488DBD78FFFFFF488985A0FEFFFF4889B598FEFFFF4889BD90FEFFFF4C898588FEFFFF4C898D80FEFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B95E8FEFFFF4C89500841F64604017412504C89F74889C649C7C310734D0041FFD358498946384C8B95D8FEFFFF4C8B8D90FEFFFF4D894A1848898578FEFFFF488B0425704F3D01488D5048483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700685D000048891425704F3D014C8B9588FEFFFF4C8950084C8B9598FEFFFF4C8950104C8B9580FEFFFF4C89504049BB2020C8B8A07F00004C89583848898570FEFFFF48C78578FFFFFF8900000048C7C7000000004889C649BBECBA5BB6A07F000041FFD34883F80174164889C748C7C60000000049C7C3709CBD0041FFD3EB08488B0425B04D5B014883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004885C00F8400000000488B8518FFFFFF4C8B70484D85F60F85000000004C8B70284983FE000F85000000004C8B1425A0536B024983EA3E4C891425A0536B024C8B8D08FFFFFFF6400401741A41524151504889C74C89CE49C7C310734D0041FFD3584159415A4C8948384C8B8578FEFFFF49C74008FDFFFFFF4983FA000F8C00000000488B85D8FEFFFF48898570FFFFFF488B85C0FEFFFF48898568FFFFFF488B85B8FEFFFF48898560FFFFFF488B8530FFFFFF48898558FFFFFF488B85C8FEFFFF48898548FFFFFF4C8BBD50FFFFFF488B8538FFFFFF48898540FFFFFF488B8518FFFFFF48898538FFFFFF4C898D30FFFFFF488B8520FFFFFF48898550FFFFFF49BB9ABE5BB6A07F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA5E0FDFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D94C8B5D404C899D70FFFFFF4C8B5D484C899D68FFFFFF4C8B5D504C899D60FFFFFF4C8B5D584C899D58FFFFFFE94FF6FFFF49BB00905BB6A07F000041FFD321383C343029241D180C08044044484C038A00000049BB00905BB6A07F000041FFD3383C0434302924180C084044484C038B00000049BB00905BB6A07F000041FFD3383C041C34302924180C084044484C038C00000049BB00905BB6A07F000041FFD3383C04211C34302924180C084044484C038D00000049BB00905BB6A07F000041FFD329383C343024180C08041C44484C038E00000049BB00905BB6A07F000041FFD3383C303424180C1C0444484C038F00000049BB00905BB6A07F000041FFD3383C303424180C1C0444484C039000000049BB00905BB6A07F000041FFD3383C08303424180C1C0444484C039100000049BB00905BB6A07F000041FFD3383C303424180C1C0444484C039200000049BB00905BB6A07F000041FFD3383C30083424180C1C0444484C039300000049BB00905BB6A07F000041FFD3383C3028083424180C1C0444484C039400000049BB00905BB6A07F000041FFD3383C08303424180C1C0444484C039500000049BB00905BB6A07F000041FFD3383C1C3424180C04084C039600000049BB00905BB6A07F000041FFD3383C30083424180C1C04039700000049BB00905BB6A07F000041FFD3383C083424180C1C04039800000049BB00905BB6A07F000041FFD3383C0129083424180C1C0420039900000049BB00905BB6A07F000041FFD3383C00243460680C505C5464182958039A00000049BB00905BB6A07F000041FFD3383C003460680C505C5464182958039B00000049BB00905BB6A07F000041FFD3383C00243460680C505C5464182907039C00000049BB00905BB6A07F000041FFD3383C0004243460680C505C5464182907039D00000049BB00905BB6A07F000041FFD3383C00243460680C505C5464182907039E00000049BB00905BB6A07F000041FFD3383C00043460680C505C542407182907039F00000049BB00905BB6A07F000041FFD3383C0020243460680C505C54070418290703A000000049BB45905BB6A07F000041FFD3383C00081C3460680C505C5420240418290703A100000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A200000049BB00905BB6A07F000041FFD3383C0008203460680C505C541D07240418290703A300000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A400000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A500000049BB00905BB6A07F000041FFD3383C0008203460680C505C541D07240418290703A600000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A700000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A800000049BB00905BB6A07F000041FFD3383C00083460680C505C54201D07240418290703A900000049BB00905BB6A07F000041FFD3383C0020083460680C505C54071D07240418290703AA00000049BB45905BB6A07F000041FFD398018C016C7C700188019C0160689401505C546474800185019001038700000049BB45905BB6A07F000041FFD398018C016C7C700188019C0160689401505C54647480018501900103AB00000049BB45905BB6A07F000041FFD398018C016CA4017C017088019C0160689401505C54800164748501038800000049BB45905BB6A07F000041FFD398018C016CA4017C017088019C0160689401505C5480016474850103AC00000049BB00905BB6A07F000041FFD398018C016CA4017C397088019C0160689401505C5480016474850103AD00000049BB45905BB6A07F000041FFD398018C016CA4017C0088019C0160689401505C5480016474850103AE00000049BB00905BB6A07F000041FFD398018C016CA4017C0088019C0160689401505C5480016474850103AF00000049BB00905BB6A07F000041FFD398018C016C88019C0160689401505C5400A40180016474850103B000000049BB00905BB6A07F000041FFD398018C0138002888019C0160689401505C5407A40180016474850103B100000049BB00905BB6A07F000041FFD398018C01380088019C0160689401505C5407A40180016474850103B200000049BB00905BB6A07F000041FFD398018C0138289C0160689401505C540007076474850103B300000049BB00905BB6A07F000041FFD398018C013800249C0160689401285C540707076474850103B400000049BB00905BB6A07F000041FFD398018C0138009C0160689401285C541924211C0707076474850103B500000049BB00905BB6A07F000041FFD398018C013800059C0160689401285C541924211C0707076474850103B600000049BB00905BB6A07F000041FFD398018C0138009C0160689401285C541924211C0707076474850103B700000049BB00905BB6A07F000041FFD398018C013800059C0160689401285C541924211C0707076474850103B800000049BB00905BB6A07F000041FFD398018C01380005099C0160689401285C541924211C0707076474850103B900000049BB00905BB6A07F000041FFD398018C01380005091C9C0160689401285C54192421070707076474850103BA00000049BB00905BB6A07F000041FFD398018C013800051C9C0160689401285C54192421070707076474850103BB00000049BB00905BB6A07F000041FFD398018C0138001C9C0160689401285C54192421070707076474850103BC00000049BB45905BB6A07F000041FFD398018C016CA801C00101BC019C0160689401505C546474038900000049BB45905BB6A07F000041FFD398018C016CA801C00101BC019C0160689401505C54647403BD00000049BB00905BB6A07F000041FFD398018C016CA801C001BC019C0160689401505C54647403BE00000049BB00905BB6A07F000041FFD398018C010038BC019C0160689401505C54A801C001647403BF00000049BB00905BB6A07F000041FFD398018C0100BC019C0160689401505C54A801C001647403C000000049BB00905BB6A07F000041FFD398018C019C0160689401505C0707070703C1000000 +[4cacae2c324b] jit-backend-dump} +[4cacae2c5693] {jit-backend-addr +Loop #8 ( #44 FOR_ITER) has address 7fa0b65bd15d to 7fa0b65bda6e (bootstrap 7fa0b65bd011) +[4cacae2c8c1b] jit-backend-addr} +[4cacae2c9d55] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd021 +0 E0FDFFFF +[4cacae2cbda1] jit-backend-dump} +[4cacae2ccecf] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd181 +0 89090000 +[4cacae2ce4ef] jit-backend-dump} +[4cacae2cef93] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd18d +0 9F090000 +[4cacae2d0439] jit-backend-dump} +[4cacae2d0e83] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd19a +0 B2090000 +[4cacae2d239b] jit-backend-dump} +[4cacae2d2e87] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd1ab +0 C2090000 +[4cacae2d4399] jit-backend-dump} +[4cacae2d4e79] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd1c6 +0 C9090000 +[4cacae2d624d] jit-backend-dump} +[4cacae2d6bfb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd1d9 +0 D6090000 +[4cacae2d7fd5] jit-backend-dump} +[4cacae2d898f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd1f0 +0 DD090000 +[4cacae2d9d6f] jit-backend-dump} +[4cacae2da8b5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd202 +0 E9090000 +[4cacae2dbe15] jit-backend-dump} +[4cacae2dc8e3] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd223 +0 E7090000 +[4cacae2dddb3] jit-backend-dump} +[4cacae2ea8f3] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd23b +0 ED090000 +[4cacae2ecff3] jit-backend-dump} +[4cacae2edd07] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd24c +0 FB090000 +[4cacae2efaef] jit-backend-dump} +[4cacae2f0ba5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd26b +0 FC090000 +[4cacae2f2615] jit-backend-dump} +[4cacae2f330b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd27d +0 090A0000 +[4cacae2f4d57] jit-backend-dump} +[4cacae2f5957] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd294 +0 0E0A0000 +[4cacae2f7499] jit-backend-dump} +[4cacae2f810b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd2b1 +0 0D0A0000 +[4cacae2f9bcf] jit-backend-dump} +[4cacae2fa9eb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd2c5 +0 140A0000 +[4cacae2fc449] jit-backend-dump} +[4cacae2fd0c7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd31d +0 DA090000 +[4cacae2fecf3] jit-backend-dump} +[4cacae2ffc4d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd32b +0 ED090000 +[4cacae301b73] jit-backend-dump} +[4cacae30284b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd345 +0 F3090000 +[4cacae304585] jit-backend-dump} +[4cacae305743] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd356 +0 030A0000 +[4cacae307981] jit-backend-dump} +[4cacae308a25] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd376 +0 050A0000 +[4cacae30ac27] jit-backend-dump} +[4cacae30be7b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd386 +0 160A0000 +[4cacae30e3f5] jit-backend-dump} +[4cacae30f16f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd39d +0 210A0000 +[4cacae3105e5] jit-backend-dump} +[4cacae311071] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd3b8 +0 290A0000 +[4cacae3124e7] jit-backend-dump} +[4cacae312ed7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd3d2 +0 330A0000 +[4cacae3142bd] jit-backend-dump} +[4cacae314e87] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd3e3 +0 460A0000 +[4cacae31633f] jit-backend-dump} +[4cacae316ef1] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd3f9 +0 550A0000 +[4cacae318433] jit-backend-dump} +[4cacae318f25] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd40e +0 640A0000 +[4cacae31a3ad] jit-backend-dump} +[4cacae31ada3] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd41f +0 770A0000 +[4cacae31c177] jit-backend-dump} +[4cacae31cb4f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd434 +0 870A0000 +[4cacae31e151] jit-backend-dump} +[4cacae31ec5b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd454 +0 8B0A0000 +[4cacae320119] jit-backend-dump} +[4cacae321109] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd46c +0 BC0A0000 +[4cacae322585] jit-backend-dump} +[4cacae3230ad] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd5d6 +0 78090000 +[4cacae324487] jit-backend-dump} +[4cacae324e6b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd5e5 +0 96090000 +[4cacae32623f] jit-backend-dump} +[4cacae326d6d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd683 +0 25090000 +[4cacae3282a9] jit-backend-dump} +[4cacae328dbf] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd692 +0 43090000 +[4cacae32a199] jit-backend-dump} +[4cacae32ab7d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd6ac +0 56090000 +[4cacae32bf57] jit-backend-dump} +[4cacae32c977] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd6cf +0 60090000 +[4cacae32dd57] jit-backend-dump} +[4cacae32e73b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd6e1 +0 7A090000 +[4cacae336637] jit-backend-dump} +[4cacae3375d3] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd6ee +0 99090000 +[4cacae338b81] jit-backend-dump} +[4cacae33974b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd702 +0 B0090000 +[4cacae33abf1] jit-backend-dump} +[4cacae33b58d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd710 +0 CF090000 +[4cacae33c967] jit-backend-dump} +[4cacae33d4bf] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd749 +0 EA090000 +[4cacae33e8a5] jit-backend-dump} +[4cacae33f397] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd75f +0 FD090000 +[4cacae3408df] jit-backend-dump} +[4cacae3413b3] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd774 +0 140A0000 +[4cacae342787] jit-backend-dump} +[4cacae34313b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd782 +0 330A0000 +[4cacae34451b] jit-backend-dump} +[4cacae344ea5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd799 +0 480A0000 +[4cacae34627f] jit-backend-dump} +[4cacae346ccf] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd7b3 +0 5B0A0000 +[4cacae348217] jit-backend-dump} +[4cacae348ddb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd7bd +0 7F0A0000 +[4cacae34a2b1] jit-backend-dump} +[4cacae34ac95] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd7c7 +0 A40A0000 +[4cacae34c07b] jit-backend-dump} +[4cacae34ca23] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd7da +0 BF0A0000 +[4cacae34de09] jit-backend-dump} +[4cacae34e79f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd94d +0 79090000 +[4cacae34fc27] jit-backend-dump} +[4cacae3506d1] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd95c +0 93090000 +[4cacae351b83] jit-backend-dump} +[4cacae352513] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd965 +0 B3090000 +[4cacae3538ed] jit-backend-dump} +[4cacae3542cb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd979 +0 C7090000 +[4cacae3556ab] jit-backend-dump} +[4cacae35602f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd987 +0 E2090000 +[4cacae35740f] jit-backend-dump} +[4cacae357f13] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd9df +0 B2090000 +[4cacae359509] jit-backend-dump} +[4cacae35a5a1] jit-backend} +[4cacae35c0dd] {jit-log-opt-loop +# Loop 8 : entry bridge with 212 ops [p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11, p12, p13, p14, p15] -debug_merge_point(0, ' #44 FOR_ITER') -+362: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] -+372: guard_class(p8, 21011168, descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10, p11, p12, p13, p14, p15] -+384: p18 = getfield_gc(p8, descr=) -+388: guard_nonnull(p18, descr=) [p1, p0, p8, p18, p2, p3, i4, p5, p9, p10, p11, p12, p13, p14, p15] -+397: i19 = getfield_gc(p8, descr=) +debug_merge_point(0, ' #44 FOR_ITER') ++362: guard_value(i6, 4, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] ++372: guard_class(p11, 20808216, descr=) [p1, p0, p11, p2, p3, i4, p5, p8, p9, p10, p12, p13, p14, p15] ++384: p18 = getfield_gc(p11, descr=) ++388: guard_nonnull(p18, descr=) [p1, p0, p11, p18, p2, p3, i4, p5, p8, p9, p10, p12, p13, p14, p15] ++397: i19 = getfield_gc(p11, descr=) +401: i20 = getfield_gc(p18, descr=) +405: i21 = int_ge(i19, i20) -guard_false(i21, descr=) [p1, p0, p8, i19, p18, p2, p3, i4, p5, p9, p10, p11, p12, p13, p14, p15] +guard_false(i21, descr=) [p1, p0, p11, i19, p18, p2, p3, i4, p5, p8, p9, p10, p12, p13, p14, p15] +414: p22 = getfield_gc(p18, descr=) +418: p23 = getarrayitem_gc(p22, i19, descr=) +423: i25 = int_add(i19, 1) -+427: setfield_gc(p8, i25, descr=) -+431: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p23, p10, p11, p12, p13, p14, p15] -debug_merge_point(0, ' #47 STORE_FAST') -debug_merge_point(0, ' #50 LOAD_GLOBAL') -+441: guard_value(p3, ConstPtr(ptr27), descr=) [p1, p0, p3, p2, p5, p8, p10, p11, p12, p13, p14, p23] ++427: setfield_gc(p11, i25, descr=) ++431: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p10, p11, p23, p13, p14, p15] +debug_merge_point(0, ' #47 STORE_FAST') +debug_merge_point(0, ' #50 LOAD_GLOBAL') ++441: guard_value(p3, ConstPtr(ptr27), descr=) [p1, p0, p3, p2, p5, p8, p9, p23, p11, p13, p14, p15] +460: p28 = getfield_gc(p0, descr=) -+464: guard_value(p28, ConstPtr(ptr29), descr=) [p1, p0, p28, p2, p5, p8, p10, p11, p12, p13, p14, p23] -+483: p30 = getfield_gc(p28, descr=) -+488: guard_isnull(p30, descr=) [p1, p0, p30, p28, p2, p5, p8, p10, p11, p12, p13, p14, p23] -+497: p32 = getfield_gc(ConstPtr(ptr31), descr=) -+510: guard_nonnull_class(p32, 21015776, descr=) [p1, p0, p32, p2, p5, p8, p10, p11, p12, p13, p14, p23] -debug_merge_point(0, ' #53 LOOKUP_METHOD') -+530: p34 = getfield_gc(p32, descr=) -+535: guard_value(p34, ConstPtr(ptr35), descr=) [p1, p0, p32, p34, p2, p5, p8, p10, p11, p12, p13, p14, p23] -+554: p36 = getfield_gc(p34, descr=) -+558: guard_isnull(p36, descr=) [p1, p0, p32, p36, p34, p2, p5, p8, p10, p11, p12, p13, p14, p23] -+567: p38 = getfield_gc(ConstPtr(ptr37), descr=) -+580: guard_nonnull_class(p38, ConstClass(Function), descr=) [p1, p0, p38, p32, p2, p5, p8, p10, p11, p12, p13, p14, p23] -debug_merge_point(0, ' #56 LOAD_CONST') -debug_merge_point(0, ' #59 LOAD_FAST') -+599: guard_nonnull_class(p23, ConstClass(W_StringObject), descr=) [p1, p0, p23, p2, p5, p8, p38, p12, p13, p14] -debug_merge_point(0, ' #62 CALL_METHOD') -+617: p41 = getfield_gc(p38, descr=) -+621: guard_value(p41, ConstPtr(ptr42), descr=) [p1, p0, p41, p38, p2, p5, p8, p23, p13, p14] -+640: p43 = getfield_gc(p38, descr=) -+644: i44 = arraylen_gc(p43, descr=) -+648: i46 = int_sub(3, i44) -+658: i48 = int_ge(2, i46) -guard_true(i48, descr=) [p1, p0, p38, p2, p5, p8, p23, p13, p14] -+668: p49 = getfield_gc(p38, descr=) -+672: p50 = getfield_gc(p38, descr=) -+672: i52 = int_sub(i44, 1) -+679: i53 = int_ge(i52, i44) -guard_false(i53, descr=) [p1, p0, i44, i52, p38, p2, p5, p8, p23, p13, p14, p49] -+688: p54 = getarrayitem_gc_pure(p43, i52, descr=) -+693: p56 = call(ConstClass(getexecutioncontext), descr=) -+738: p57 = getfield_gc(p56, descr=) -+742: i58 = force_token() -+749: p59 = getfield_gc(p56, descr=) -+753: guard_isnull(p59, descr=) [p1, p0, p56, p59, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, p49] -+762: i60 = getfield_gc(p56, descr=) -+766: i61 = int_is_zero(i60) -guard_true(i61, descr=) [p1, p0, p56, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, p49] -debug_merge_point(1, ' #0 LOAD_GLOBAL') -+776: guard_value(p49, ConstPtr(ptr62), descr=) [p1, p0, p56, p49, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, None] -+795: p64 = getfield_gc(p49, descr=) -+800: guard_isnull(p64, descr=) [p1, p0, p56, p64, p49, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, None] -+809: p66 = getfield_gc(ConstPtr(ptr65), descr=) -+822: guard_nonnull_class(p66, ConstClass(Function), descr=) [p1, p0, p56, p66, p2, p5, p8, p38, p23, p13, p14, p54, i58, p57, None] -debug_merge_point(1, ' #3 LOAD_FAST') -debug_merge_point(1, ' #6 LOAD_FAST') -+842: guard_nonnull(p54, descr=) [p1, p0, p56, p54, p2, p5, p8, p38, p23, p13, p14, p66, None, i58, p57, None] -debug_merge_point(1, ' #9 CALL_FUNCTION') -+858: p68 = getfield_gc(p66, descr=) -+863: guard_value(p68, ConstPtr(ptr69), descr=) [p1, p0, p56, p68, p66, p2, p5, p8, p38, p23, p13, p14, None, p54, i58, p57, None] -+882: p70 = getfield_gc(p66, descr=) -+887: p71 = getfield_gc(p66, descr=) -+887: p72 = getfield_gc(p66, descr=) -+892: p73 = getfield_gc(p66, descr=) -+897: guard_no_exception(, descr=) [p1, p0, p56, p72, p73, p2, p5, p8, p38, p23, p13, p14, p70, p66, p54, i58, p57, None] -+912: i74 = force_token() -debug_merge_point(2, ' #0 LOAD_GLOBAL') -+919: guard_value(p70, ConstPtr(ptr75), descr=) [p1, p0, p56, p70, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] -+938: p76 = getfield_gc(p70, descr=) -+942: guard_isnull(p76, descr=) [p1, p0, p56, p76, p70, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] -+951: p78 = getfield_gc(ConstPtr(ptr77), descr=) -+964: guard_isnull(p78, descr=) [p1, p0, p56, p78, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] -+973: p80 = getfield_gc(ConstPtr(ptr79), descr=) -+981: guard_value(p80, ConstPtr(ptr81), descr=) [p1, p0, p56, p80, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] -+994: p82 = getfield_gc(p80, descr=) -+998: guard_isnull(p82, descr=) [p1, p0, p56, p82, p80, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] -+1007: p84 = getfield_gc(ConstPtr(ptr83), descr=) -+1015: guard_value(p84, ConstPtr(ptr85), descr=) [p1, p0, p56, p84, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] -debug_merge_point(2, ' #3 LOAD_FAST') -debug_merge_point(2, ' #6 LOAD_CONST') -debug_merge_point(2, ' #9 BINARY_SUBSCR') -debug_merge_point(2, ' #10 CALL_FUNCTION') -debug_merge_point(2, ' #13 BUILD_TUPLE') -debug_merge_point(2, ' #16 LOAD_FAST') -debug_merge_point(2, ' #19 BINARY_ADD') -debug_merge_point(2, ' #20 STORE_FAST') -debug_merge_point(2, ' #23 LOAD_GLOBAL') -+1028: p87 = getfield_gc(ConstPtr(ptr86), descr=) -+1041: guard_nonnull_class(p87, 21003520, descr=) [p1, p0, p56, p87, p2, p5, p8, p38, p23, p13, p14, i74, None, p66, p54, i58, p57, None] -debug_merge_point(2, ' #26 LOOKUP_METHOD') -debug_merge_point(2, ' #29 LOAD_FAST') -debug_merge_point(2, ' #32 CALL_METHOD') -+1059: p90 = getfield_gc(ConstPtr(ptr89), descr=) -+1067: guard_not_invalidated(, descr=) [p1, p0, p56, p90, p2, p5, p8, p38, p23, p13, p14, p87, i74, None, p66, p54, i58, p57, None] -+1067: p91 = getfield_gc(p87, descr=) -+1071: guard_nonnull(p91, descr=) [p1, p0, p56, p87, p91, p2, p5, p8, p38, p23, p13, p14, None, i74, None, p66, p54, i58, p57, None] -+1080: i92 = force_token() -+1087: p94 = new_with_vtable(21002328) -+1199: setfield_gc(p94, i74, descr=) -setfield_gc(p56, p94, descr=) -+1250: setfield_gc(p0, i92, descr=) -+1261: p96 = new_array(3, descr=) -+1339: setarrayitem_gc(p96, 0, ConstPtr(ptr98), descr=) -+1347: setarrayitem_gc(p96, 1, ConstPtr(ptr100), descr=) -+1361: setarrayitem_gc(p96, 2, p54, descr=) -+1372: i103 = call_may_force(ConstClass(hash_tuple), p96, descr=) -guard_not_forced(, descr=) [p1, p0, p56, p87, p91, i103, p94, p2, p5, p8, p38, p23, p13, p14, p96, p54, i58, p66, p57] -+1445: guard_no_exception(, descr=) [p1, p0, p56, p87, p91, i103, p94, p2, p5, p8, p38, p23, p13, p14, p96, p54, i58, p66, p57] -+1460: i104 = force_token() -+1467: setfield_gc(p0, i104, descr=) -+1479: p106 = new_with_vtable(21002400) -+1549: setfield_gc(p106, p96, descr=) -+1560: i108 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p91, p106, i103, descr=) -guard_not_forced(, descr=) [p1, p0, p56, p106, p87, i108, p91, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] -+1619: guard_no_exception(, descr=) [p1, p0, p56, p106, p87, i108, p91, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] -+1634: i110 = int_and(i108, -9223372036854775808) -+1650: i111 = int_is_true(i110) -guard_false(i111, descr=) [p1, p0, p56, p106, p87, i108, p91, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] -+1660: p113 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p91, i108, descr=) -+1680: guard_no_exception(, descr=) [p1, p0, p56, p106, p87, p113, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] -+1695: guard_nonnull_class(p113, 21206408, descr=) [p1, p0, p56, p106, p87, p113, p94, p2, p5, p8, p38, p23, p13, p14, p54, i58, p66, p57] -debug_merge_point(2, ' #35 STORE_FAST') -debug_merge_point(2, ' #38 LOAD_FAST') -debug_merge_point(2, ' #41 LOAD_CONST') -debug_merge_point(2, ' #44 COMPARE_OP') -+1713: i116 = ptr_eq(p113, ConstPtr(ptr115)) -guard_false(i116, descr=) [p1, p0, p56, p94, p2, p5, p8, p38, p23, p13, p14, p113, p106, p54, i58, p66, p57] -debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') -debug_merge_point(2, ' #50 LOAD_FAST') -debug_merge_point(2, ' #53 RETURN_VALUE') -+1726: p117 = getfield_gc(p56, descr=) -+1738: guard_isnull(p117, descr=) [p1, p0, p56, p113, p117, p94, p2, p5, p8, p38, p23, p13, p14, None, p106, p54, i58, p66, p57] -+1747: i118 = getfield_gc(p56, descr=) -+1752: i119 = int_is_true(i118) -guard_false(i119, descr=) [p1, p0, p56, p113, p94, p2, p5, p8, p38, p23, p13, p14, None, p106, p54, i58, p66, p57] -+1762: p120 = getfield_gc(p56, descr=) -debug_merge_point(1, ' #12 LOOKUP_METHOD') -debug_merge_point(1, ' #15 LOAD_FAST') -debug_merge_point(1, ' #18 CALL_METHOD') -+1762: p122 = getfield_gc(ConstPtr(ptr121), descr=) -+1770: setfield_gc(p94, -3, descr=) -+1785: guard_not_invalidated(, descr=) [p1, p0, p56, p122, p2, p5, p8, p38, p23, p13, p14, p113, None, p54, i58, None, p57] -+1785: p124 = getfield_gc_pure(p23, descr=) -+1796: i125 = strlen(p124) -+1800: i127 = int_gt(9223372036854775807, i125) -guard_true(i127, descr=) [p1, p0, p56, p113, p124, p2, p5, p8, p38, p23, p13, p14, None, None, p54, i58, None, p57] -+1819: p128 = getfield_gc(p113, descr=) -+1823: i129 = getfield_gc(p113, descr=) -+1827: i131 = getarrayitem_gc_pure(p128, 0, descr=) -+1831: i133 = int_eq(i131, 17) -guard_true(i133, descr=) [p1, p0, p56, p113, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] -+1841: i135 = getarrayitem_gc_pure(p128, 2, descr=) -+1845: i137 = int_and(i135, 1) -+1852: i138 = int_is_true(i137) -guard_true(i138, descr=) [p1, p0, p56, p113, i135, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] -+1862: i140 = getarrayitem_gc_pure(p128, 5, descr=) -+1866: i142 = int_gt(i140, 1) -guard_false(i142, descr=) [p1, p0, p56, p113, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] -+1876: i144 = getarrayitem_gc_pure(p128, 1, descr=) -+1880: i146 = int_add(i144, 1) -+1884: i147 = getarrayitem_gc_pure(p128, i146, descr=) -+1889: i149 = int_eq(i147, 19) -guard_true(i149, descr=) [p1, p0, p56, p113, i146, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] -+1899: i151 = int_add(i146, 1) -+1906: i152 = getarrayitem_gc_pure(p128, i151, descr=) -+1911: i154 = int_add(i146, 2) -+1915: i156 = int_lt(0, i125) -guard_true(i156, descr=) [p1, p0, p56, p113, i152, i154, p2, p5, p8, p38, p23, p13, p14, i129, p124, p128, i125, None, None, p54, i58, None, p57] -+1925: guard_value(i154, 11, descr=) [p1, p0, p56, p113, i152, i154, p128, p2, p5, p8, p38, p23, p13, p14, i129, p124, None, i125, None, None, p54, i58, None, p57] -+1935: guard_value(i152, 51, descr=) [p1, p0, p56, p113, i152, p128, p2, p5, p8, p38, p23, p13, p14, i129, p124, None, i125, None, None, p54, i58, None, p57] -+1945: guard_value(p128, ConstPtr(ptr159), descr=) [p1, p0, p56, p113, p128, p2, p5, p8, p38, p23, p13, p14, i129, p124, None, i125, None, None, p54, i58, None, p57] ++464: guard_value(p28, ConstPtr(ptr29), descr=) [p1, p0, p28, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++483: p30 = getfield_gc(p28, descr=) ++488: guard_value(p30, ConstPtr(ptr31), descr=) [p1, p0, p30, p28, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++501: p33 = getfield_gc(ConstPtr(ptr32), descr=) ++514: guard_nonnull_class(p33, 20812584, descr=) [p1, p0, p33, p2, p5, p8, p9, p23, p11, p13, p14, p15] +debug_merge_point(0, ' #53 LOOKUP_METHOD') ++534: p35 = getfield_gc(p33, descr=) ++539: guard_value(p35, ConstPtr(ptr36), descr=) [p1, p0, p33, p35, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++558: p37 = getfield_gc(p35, descr=) ++562: guard_value(p37, ConstPtr(ptr38), descr=) [p1, p0, p33, p37, p35, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++575: p40 = getfield_gc(ConstPtr(ptr39), descr=) ++588: guard_nonnull_class(p40, ConstClass(Function), descr=) [p1, p0, p40, p33, p2, p5, p8, p9, p23, p11, p13, p14, p15] +debug_merge_point(0, ' #56 LOAD_CONST') +debug_merge_point(0, ' #59 LOAD_FAST') ++606: guard_nonnull_class(p23, ConstClass(W_StringObject), descr=) [p1, p0, p23, p2, p5, p8, p9, p11, p40, p15] +debug_merge_point(0, ' #62 CALL_METHOD') ++624: p43 = getfield_gc(p40, descr=) ++628: guard_value(p43, ConstPtr(ptr44), descr=) [p1, p0, p43, p40, p2, p5, p8, p9, p23, p11] ++647: p45 = getfield_gc(p40, descr=) ++651: i46 = arraylen_gc(p45, descr=) ++656: i48 = int_sub(3, i46) ++666: i50 = int_ge(2, i48) +guard_true(i50, descr=) [p1, p0, p40, p2, p5, p8, p9, p23, p11] ++676: p51 = getfield_gc(p40, descr=) ++680: p52 = getfield_gc(p40, descr=) ++680: i54 = int_sub(i46, 1) ++687: i55 = int_ge(i54, i46) +guard_false(i55, descr=) [p1, p0, i46, i54, p40, p2, p5, p8, p9, p23, p11, p51] ++696: p56 = getarrayitem_gc_pure(p45, i54, descr=) ++701: p58 = call(ConstClass(getexecutioncontext), descr=) ++760: p59 = getfield_gc(p58, descr=) ++764: i60 = force_token() ++771: p61 = getfield_gc(p58, descr=) ++775: guard_isnull(p61, descr=) [p1, p0, p58, p61, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, p51] ++784: i62 = getfield_gc(p58, descr=) ++788: i63 = int_is_zero(i62) +guard_true(i63, descr=) [p1, p0, p58, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, p51] +debug_merge_point(1, ' #0 LOAD_GLOBAL') ++798: guard_value(p51, ConstPtr(ptr64), descr=) [p1, p0, p58, p51, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, None] ++824: p66 = getfield_gc(p51, descr=) ++828: guard_value(p66, ConstPtr(ptr67), descr=) [p1, p0, p58, p66, p51, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, None] ++841: p69 = getfield_gc(ConstPtr(ptr68), descr=) ++854: guard_nonnull_class(p69, ConstClass(Function), descr=) [p1, p0, p58, p69, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, None] +debug_merge_point(1, ' #3 LOAD_FAST') +debug_merge_point(1, ' #6 LOAD_FAST') ++873: guard_nonnull(p56, descr=) [p1, p0, p58, p56, p2, p5, p8, p9, p23, p11, p40, p69, None, p59, i60, None] +debug_merge_point(1, ' #9 CALL_FUNCTION') ++889: p71 = getfield_gc(p69, descr=) ++893: guard_value(p71, ConstPtr(ptr72), descr=) [p1, p0, p58, p71, p69, p2, p5, p8, p9, p23, p11, p40, None, p56, p59, i60, None] ++912: p73 = getfield_gc(p69, descr=) ++916: p74 = getfield_gc(p69, descr=) ++916: p75 = getfield_gc(p69, descr=) ++920: p76 = getfield_gc(p69, descr=) ++924: guard_no_exception(, descr=) [p1, p0, p58, p75, p76, p2, p5, p8, p9, p23, p11, p40, p73, p69, p56, p59, i60, None] ++939: i77 = force_token() +debug_merge_point(2, ' #0 LOAD_GLOBAL') ++946: guard_value(p73, ConstPtr(ptr78), descr=) [p1, p0, p58, p73, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] ++965: p79 = getfield_gc(p73, descr=) ++969: guard_value(p79, ConstPtr(ptr80), descr=) [p1, p0, p58, p79, p73, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] ++982: p82 = getfield_gc(ConstPtr(ptr81), descr=) ++995: guard_isnull(p82, descr=) [p1, p0, p58, p82, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] ++1004: p84 = getfield_gc(ConstPtr(ptr83), descr=) ++1012: guard_value(p84, ConstPtr(ptr85), descr=) [p1, p0, p58, p84, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] ++1025: p86 = getfield_gc(p84, descr=) ++1029: guard_value(p86, ConstPtr(ptr87), descr=) [p1, p0, p58, p86, p84, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] ++1042: p89 = getfield_gc(ConstPtr(ptr88), descr=) ++1050: guard_value(p89, ConstPtr(ptr90), descr=) [p1, p0, p58, p89, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] +debug_merge_point(2, ' #3 LOAD_FAST') +debug_merge_point(2, ' #6 LOAD_CONST') +debug_merge_point(2, ' #9 BINARY_SUBSCR') +debug_merge_point(2, ' #10 CALL_FUNCTION') +debug_merge_point(2, ' #13 BUILD_TUPLE') +debug_merge_point(2, ' #16 LOAD_FAST') +debug_merge_point(2, ' #19 BINARY_ADD') +debug_merge_point(2, ' #20 STORE_FAST') +debug_merge_point(2, ' #23 LOAD_GLOBAL') ++1063: p92 = getfield_gc(ConstPtr(ptr91), descr=) ++1076: guard_nonnull_class(p92, 20802224, descr=) [p1, p0, p58, p92, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] +debug_merge_point(2, ' #26 LOOKUP_METHOD') +debug_merge_point(2, ' #29 LOAD_FAST') +debug_merge_point(2, ' #32 CALL_METHOD') ++1095: p95 = getfield_gc(ConstPtr(ptr94), descr=) ++1103: guard_not_invalidated(, descr=) [p1, p0, p58, p95, p2, p5, p8, p9, p23, p11, p40, p92, i77, None, p69, p56, p59, i60, None] ++1103: p96 = getfield_gc(p92, descr=) ++1107: guard_class(p96, ConstClass(ObjectDictStrategy), descr=) [p1, p0, p58, p92, p96, p2, p5, p8, p9, p23, p11, p40, None, i77, None, p69, p56, p59, i60, None] ++1119: p98 = getfield_gc(p92, descr=) ++1123: i99 = force_token() ++1130: p101 = new_with_vtable(20801800) ++1242: setfield_gc(p101, i77, descr=) +setfield_gc(p58, p101, descr=) ++1293: setfield_gc(p0, i99, descr=) ++1297: p103 = new_array(3, descr=) ++1375: setarrayitem_gc(p103, 0, ConstPtr(ptr105), descr=) ++1383: setarrayitem_gc(p103, 1, ConstPtr(ptr107), descr=) ++1397: setarrayitem_gc(p103, 2, p56, descr=) ++1408: i110 = call_may_force(ConstClass(hash_tuple), p103, descr=) +guard_not_forced(, descr=) [p1, p0, p58, p92, p98, i110, p101, p2, p5, p8, p9, p23, p11, p40, p56, p59, p69, i60, p103] ++1481: guard_no_exception(, descr=) [p1, p0, p58, p92, p98, i110, p101, p2, p5, p8, p9, p23, p11, p40, p56, p59, p69, i60, p103] ++1496: i111 = force_token() ++1503: setfield_gc(p0, i111, descr=) ++1514: p113 = new_with_vtable(20801872) ++1584: setfield_gc(p113, p103, descr=) ++1595: i115 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p98, p113, i110, descr=) +guard_not_forced(, descr=) [p1, p0, p58, p113, p92, i115, p98, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] ++1654: guard_no_exception(, descr=) [p1, p0, p58, p113, p92, i115, p98, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] ++1669: i117 = int_and(i115, -9223372036854775808) ++1685: i118 = int_is_true(i117) +guard_false(i118, descr=) [p1, p0, p58, p113, p92, i115, p98, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] ++1695: p120 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p98, i115, descr=) ++1715: guard_no_exception(, descr=) [p1, p0, p58, p113, p92, p120, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] ++1730: guard_nonnull_class(p120, 21007408, descr=) [p1, p0, p58, p113, p92, p120, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] +debug_merge_point(2, ' #35 STORE_FAST') +debug_merge_point(2, ' #38 LOAD_FAST') +debug_merge_point(2, ' #41 LOAD_CONST') +debug_merge_point(2, ' #44 COMPARE_OP') ++1748: i123 = ptr_eq(p120, ConstPtr(ptr122)) +guard_false(i123, descr=) [p1, p0, p58, p101, p2, p5, p8, p9, p23, p11, p40, p120, p113, p69, p56, p59, i60] +debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') +debug_merge_point(2, ' #50 LOAD_FAST') +debug_merge_point(2, ' #53 RETURN_VALUE') ++1761: p124 = getfield_gc(p58, descr=) ++1772: guard_isnull(p124, descr=) [p1, p0, p58, p120, p124, p101, p2, p5, p8, p9, p23, p11, p40, None, p113, p69, p56, p59, i60] ++1781: i125 = getfield_gc(p58, descr=) ++1785: i126 = int_is_true(i125) +guard_false(i126, descr=) [p1, p0, p58, p120, p101, p2, p5, p8, p9, p23, p11, p40, None, p113, p69, p56, p59, i60] ++1795: p127 = getfield_gc(p58, descr=) +debug_merge_point(1, ' #12 LOOKUP_METHOD') +debug_merge_point(1, ' #15 LOAD_FAST') +debug_merge_point(1, ' #18 CALL_METHOD') ++1795: p129 = getfield_gc(ConstPtr(ptr128), descr=) ++1803: setfield_gc(p101, -3, descr=) ++1818: guard_not_invalidated(, descr=) [p1, p0, p58, p129, p2, p5, p8, p9, p23, p11, p40, p120, None, None, p56, p59, i60] ++1818: p131 = getfield_gc_pure(p23, descr=) ++1829: i132 = strlen(p131) ++1833: i134 = int_gt(9223372036854775807, i132) +guard_true(i134, descr=) [p1, p0, p58, p120, p131, p2, p5, p8, p9, p23, p11, p40, None, None, None, p56, p59, i60] ++1852: p135 = getfield_gc(p120, descr=) ++1856: i136 = getfield_gc(p120, descr=) ++1860: i138 = getarrayitem_gc_pure(p135, 0, descr=) ++1864: i140 = int_eq(i138, 17) +guard_true(i140, descr=) [p1, p0, p58, p120, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] ++1874: i142 = getarrayitem_gc_pure(p135, 2, descr=) ++1878: i144 = int_and(i142, 1) ++1885: i145 = int_is_true(i144) +guard_true(i145, descr=) [p1, p0, p58, p120, i142, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] ++1895: i147 = getarrayitem_gc_pure(p135, 5, descr=) ++1899: i149 = int_gt(i147, 1) +guard_false(i149, descr=) [p1, p0, p58, p120, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] ++1909: i151 = getarrayitem_gc_pure(p135, 1, descr=) ++1913: i153 = int_add(i151, 1) ++1917: i154 = getarrayitem_gc_pure(p135, i153, descr=) ++1922: i156 = int_eq(i154, 19) +guard_true(i156, descr=) [p1, p0, p58, p120, i153, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] ++1932: i158 = int_add(i153, 1) ++1939: i159 = getarrayitem_gc_pure(p135, i158, descr=) ++1944: i161 = int_add(i153, 2) ++1948: i163 = int_lt(0, i132) +guard_true(i163, descr=) [p1, p0, p58, p120, i159, i161, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] ++1958: guard_value(i161, 11, descr=) [p1, p0, p58, p120, i159, i161, p135, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, None, None, None, None, p56, p59, i60] ++1968: guard_value(i159, 51, descr=) [p1, p0, p58, p120, i159, p135, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, None, None, None, None, p56, p59, i60] ++1978: guard_value(p135, ConstPtr(ptr166), descr=) [p1, p0, p58, p120, p135, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, None, None, None, None, p56, p59, i60] debug_merge_point(2, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') -+1964: i160 = force_token() -+1971: p161 = new_with_vtable(21002328) -+2069: setfield_gc(p161, i58, descr=) -setfield_gc(p56, p161, descr=) -+2111: setfield_gc(p0, i160, descr=) -+2129: p163 = new_with_vtable(21022112) -+2199: setfield_gc(p163, ConstPtr(ptr159), descr=) -+2213: setfield_gc(p163, i129, descr=) -+2224: setfield_gc(p163, p124, descr=) -+2235: setfield_gc(p163, i125, descr=) -+2246: i164 = call_assembler(0, p163, descr=) -guard_not_forced(, descr=) [p1, p0, p56, p113, p163, i164, p161, p2, p5, p8, p38, p23, p13, p14, p57, p54] -+2337: guard_no_exception(, descr=) [p1, p0, p56, p113, p163, i164, p161, p2, p5, p8, p38, p23, p13, p14, p57, p54] -+2352: guard_true(i164, descr=) [p1, p0, p56, p113, p163, p161, p2, p5, p8, p38, p23, p13, p14, p57, p54] -debug_merge_point(1, ' #21 RETURN_VALUE') -+2361: p165 = getfield_gc(p56, descr=) -+2372: guard_isnull(p165, descr=) [p1, p0, p56, p165, p161, p2, p5, p8, p38, p23, p13, p14, p113, p163, p57, p54] -+2381: i166 = getfield_gc(p56, descr=) -+2385: i167 = int_is_true(i166) -guard_false(i167, descr=) [p1, p0, p56, p161, p2, p5, p8, p38, p23, p13, p14, p113, p163, p57, p54] -+2395: p168 = getfield_gc(p56, descr=) -debug_merge_point(0, ' #65 POP_TOP') -debug_merge_point(0, ' #66 JUMP_ABSOLUTE') -+2395: i170 = getfield_raw(40681184, descr=) -+2403: i172 = int_sub(i170, 62) -+2407: setfield_raw(40681184, i172, descr=) -setfield_gc(p56, p57, descr=) -+2458: setfield_gc(p161, -3, descr=) -+2473: i175 = int_lt(i172, 0) -guard_false(i175, descr=) [p1, p0, p2, p5, p8, p13, p14, p23, None, None, None, None] -debug_merge_point(0, ' #44 FOR_ITER') -+2483: jump(p0, p1, p2, p5, p8, p13, p14, p23, i166, p56, p57, descr=) -+2625: --end of the loop-- -[1af17a04f8f24] jit-log-opt-loop} -[1af17a0a31f25] {jit-log-opt-bridge -# bridge out of Guard 154 with 18 ops ++1997: i167 = force_token() ++2004: p168 = new_with_vtable(20801800) ++2102: setfield_gc(p168, i60, descr=) +setfield_gc(p58, p168, descr=) ++2142: setfield_gc(p0, i167, descr=) ++2160: p170 = new_with_vtable(20819912) ++2230: setfield_gc(p170, i132, descr=) ++2241: setfield_gc(p170, i136, descr=) ++2252: setfield_gc(p170, p131, descr=) ++2263: setfield_gc(p170, ConstPtr(ptr166), descr=) ++2277: i171 = call_assembler(0, p170, descr=) +guard_not_forced(, descr=) [p1, p0, p58, p120, p170, i171, p168, p2, p5, p8, p9, p23, p11, p40, p56, p59] ++2368: guard_no_exception(, descr=) [p1, p0, p58, p120, p170, i171, p168, p2, p5, p8, p9, p23, p11, p40, p56, p59] ++2383: guard_true(i171, descr=) [p1, p0, p58, p120, p170, p168, p2, p5, p8, p9, p23, p11, p40, p56, p59] +debug_merge_point(1, ' #21 RETURN_VALUE') ++2392: p172 = getfield_gc(p58, descr=) ++2403: guard_isnull(p172, descr=) [p1, p0, p58, p172, p168, p2, p5, p8, p9, p23, p11, p40, p120, p170, p56, p59] ++2412: i173 = getfield_gc(p58, descr=) ++2416: i174 = int_is_true(i173) +guard_false(i174, descr=) [p1, p0, p58, p168, p2, p5, p8, p9, p23, p11, p40, p120, p170, p56, p59] ++2426: p175 = getfield_gc(p58, descr=) +debug_merge_point(0, ' #65 POP_TOP') +debug_merge_point(0, ' #66 JUMP_ABSOLUTE') ++2426: i177 = getfield_raw(40588192, descr=) ++2434: i179 = int_sub(i177, 62) ++2438: setfield_raw(40588192, i179, descr=) +setfield_gc(p58, p59, descr=) ++2489: setfield_gc(p168, -3, descr=) ++2504: i182 = int_lt(i179, 0) +guard_false(i182, descr=) [p1, p0, p2, p5, p8, p9, p23, p11, None, None, None, None] +debug_merge_point(0, ' #44 FOR_ITER') ++2514: jump(p0, p1, p2, p5, p8, p9, p23, p11, i173, p58, p59, descr=) ++2653: --end of the loop-- +[4cacae517669] jit-log-opt-loop} +[4cacaee48ccb] {jit-backend +[4cacaeea1c45] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65be3b7 +0 488DA50000000049BB98A0CFB8A07F00004D8B3B4983C70149BB98A0CFB8A07F00004D893B4C8BBD18FFFFFF4D8B77484D85F60F85000000004D8B77284983FE000F85000000004C8B3425A0536B024983EE054C893425A0536B024C8BAD08FFFFFF41F647040174104C89FF4C89EE49C7C310734D0041FFD34D896F384C8BAD78FEFFFF49C74508FDFFFFFF4983FE000F8C000000004C8BBDD8FEFFFF4C8BB5C0FEFFFF4C8BADB8FEFFFF49BBF8F477B6A07F00004D89DC49C7C2000000004C8B8D30FFFFFF49C7C00400000048C7C72C000000488BB520FFFFFF488B9DC8FEFFFF488B9550FFFFFF488B8D38FFFFFF48C78570FFFFFF0000000048C78568FFFFFF0000000048C78560FFFFFF0000000048C78558FFFFFF0000000049BB5DD15BB6A07F000041FFE349BB00905BB6A07F000041FFD398018C013C38BC019C0160689401505C54647403C200000049BB00905BB6A07F000041FFD398018C013CBC019C0160689401505C54647403C300000049BB00905BB6A07F000041FFD398018C019C0160689401505C070703C4000000 +[4cacaeeb8a21] jit-backend-dump} +[4cacaeeb9cbd] {jit-backend-addr +Bridge out of guard 190 has address 7fa0b65be3b7 to 7fa0b65be4e0 +[4cacaeebba0f] jit-backend-addr} +[4cacaeebca47] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65be3ba +0 E0FDFFFF +[4cacaeebe559] jit-backend-dump} +[4cacaeebf303] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65be3ec +0 F0000000 +[4cacaeec0929] jit-backend-dump} +[4cacaeec134f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65be3fa +0 07010000 +[4cacaeec278f] jit-backend-dump} +[4cacaeec3179] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65be449 +0 DC000000 +[4cacaeec45f5] jit-backend-dump} +[4cacaeec564b] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7fa0b65bd965 +0 4E0A0000 +[4cacaeec6b21] jit-backend-dump} +[4cacaeec7715] jit-backend} +[4cacaeec8bc1] {jit-log-opt-bridge +# bridge out of Guard 190 with 18 ops [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] -debug_merge_point(1, ' #21 RETURN_VALUE') +debug_merge_point(1, ' #21 RETURN_VALUE') +37: p15 = getfield_gc(p2, descr=) -+48: guard_isnull(p15, descr=) [p0, p1, p2, p15, p5, p6, p7, p8, p9, p10, p11, p12, p14, p13] ++48: guard_isnull(p15, descr=) [p0, p1, p2, p15, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] +57: i16 = getfield_gc(p2, descr=) +61: i17 = int_is_true(i16) -guard_false(i17, descr=) [p0, p1, p2, p5, p6, p7, p8, p9, p10, p11, p12, p14, p13] +guard_false(i17, descr=) [p0, p1, p2, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] +71: p18 = getfield_gc(p2, descr=) -debug_merge_point(0, ' #65 POP_TOP') -debug_merge_point(0, ' #66 JUMP_ABSOLUTE') -+71: i20 = getfield_raw(40681184, descr=) +debug_merge_point(0, ' #65 POP_TOP') +debug_merge_point(0, ' #66 JUMP_ABSOLUTE') ++71: i20 = getfield_raw(40588192, descr=) +79: i22 = int_sub(i20, 5) -+83: setfield_raw(40681184, i22, descr=) -setfield_gc(p2, p13, descr=) ++83: setfield_raw(40588192, i22, descr=) +setfield_gc(p2, p14, descr=) +125: setfield_gc(p5, -3, descr=) +140: i25 = int_lt(i22, 0) -guard_false(i25, descr=) [p0, p1, p6, p7, p8, p11, p12, p10, None, None] -debug_merge_point(0, ' #44 FOR_ITER') -+150: jump(p1, p0, p6, ConstPtr(ptr27), 0, p7, 1, 44, p8, ConstPtr(ptr31), ConstPtr(ptr32), ConstPtr(ptr33), ConstPtr(ptr34), p11, p12, p10, descr=) -+278: --end of the loop-- -[1af17a0a4ca6a] jit-log-opt-bridge} -[1af17a0db52b7] {jit-backend-counts -0:4481 -1:4485 -2:0 -3:4281 -4:1965 -5:2 -6:9210 -7:8304 -8:1686 -9:532 -10:1433 -11:1052 -[1af17a0db9523] jit-backend-counts} +guard_false(i25, descr=) [p0, p1, p6, p7, p8, p9, p10, p11, None, None] +debug_merge_point(0, ' #44 FOR_ITER') ++150: jump(p1, p0, p6, ConstPtr(ptr27), 0, p7, 4, 44, p8, p9, p10, p11, ConstPtr(ptr31), ConstPtr(ptr32), ConstPtr(ptr33), ConstPtr(ptr34), descr=) ++297: --end of the loop-- +[4cacaeef6f29] jit-log-opt-bridge} +[4cacaf781b8d] {jit-backend-counts +0:13968 +1:9112 +2:4445 +3:4485 +4:0 +5:4245 +6:1965 +7:2 +8:9210 +9:8304 +10:1686 +11:528 +12:1435 +13:1052 +[4cacaf788a8d] jit-backend-counts} diff --git a/source.py b/source.py --- a/source.py +++ b/source.py @@ -18,14 +18,20 @@ inlined_call() +def uninlined_call(): + s = 0 + for i in range(3): + s += 1 + return s + def bridge(): s = 0 i = 0 while i < 10000: if i % 2: + s += uninlined_call() + else: s += 1 - else: - s += 2 i += 1 return s From noreply at buildbot.pypy.org Fri Jul 22 11:36:52 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 11:36:52 +0200 (CEST) Subject: [pypy-commit] jitviewer default: merge Message-ID: <20110722093652.A157382961@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r154:f41ef1a56836 Date: 2011-07-22 11:36 +0200 http://bitbucket.org/pypy/jitviewer/changeset/f41ef1a56836/ Log: merge diff --git a/_jitviewer/static/script.js b/_jitviewer/static/script.js --- a/_jitviewer/static/script.js +++ b/_jitviewer/static/script.js @@ -38,7 +38,14 @@ $("#inp-bar").focus(); $("#inp-bar").bind("click keyup", function() { var value = $("#inp-bar")[0].value; - + $(".loopitem").each(function (i, l) { + glob = l; + if (l.getAttribute('name').search(value) != -1) { + $(l).show(); + } else { + $(l).hide(); + } + }); }); } diff --git a/_jitviewer/templates/index.html b/_jitviewer/templates/index.html --- a/_jitviewer/templates/index.html +++ b/_jitviewer/templates/index.html @@ -29,9 +29,9 @@
        {% for is_entry_bridge, index, item in loops %} {% if is_entry_bridge %} -
      • Entry bridge: {{item.repr()}} run {{item.count}} times
      • +
      • Entry bridge: {{item.repr()}} run {{item.count}} times
      • {% else %} -
      • {{item.repr()}} run {{item.count}} times
      • +
      • {{item.repr()}} run {{item.count}} times
      • {% endif %} {% endfor %}
      From noreply at buildbot.pypy.org Fri Jul 22 11:39:22 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 11:39:22 +0200 (CEST) Subject: [pypy-commit] jitviewer default: make call_assembler clickable Message-ID: <20110722093922.3F61882961@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r155:41244cedfca0 Date: 2011-07-22 11:39 +0200 http://bitbucket.org/pypy/jitviewer/changeset/41244cedfca0/ Log: make call_assembler clickable diff --git a/_jitviewer/parser.py b/_jitviewer/parser.py --- a/_jitviewer/parser.py +++ b/_jitviewer/parser.py @@ -113,6 +113,8 @@ return ("" % no + self.repr() + "") + repr_call_assembler = repr_jump + def getdescr(self): return cgi.escape(self.descr) From noreply at buildbot.pypy.org Fri Jul 22 11:51:00 2011 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 22 Jul 2011 11:51:00 +0200 (CEST) Subject: [pypy-commit] jitviewer default: minor things - show selected loop Message-ID: <20110722095100.2F79582961@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r156:fd367a7f871d Date: 2011-07-22 11:48 +0200 http://bitbucket.org/pypy/jitviewer/changeset/fd367a7f871d/ Log: minor things - show selected loop diff --git a/_jitviewer/static/script.js b/_jitviewer/static/script.js --- a/_jitviewer/static/script.js +++ b/_jitviewer/static/script.js @@ -3,12 +3,14 @@ function show_loop(no, path) { + $("#loop-" + glob_bridge_state.no).removeClass("selected"); glob_bridge_state.no = no; if (path) { glob_bridge_state.path = path; } else { delete glob_bridge_state.path; } + $("#loop-" + no).addClass("selected"); $.getJSON('/loop', glob_bridge_state, function(arg) { $('#main').html(arg.html).ready(function() { $.scrollTo($('#line-' + arg.scrollto), 200, {axis:'y'}); diff --git a/_jitviewer/static/style.css b/_jitviewer/static/style.css --- a/_jitviewer/static/style.css +++ b/_jitviewer/static/style.css @@ -198,6 +198,16 @@ color: #00A; } +.selected { + background-color: #aa6; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + -moz-box-shadow: 0px 0px 7px #cacaca; + -webkit-box-shadow: 0px 0px 7px #cacaca; + box-shadow: 0px 0px 7px #cacaca; +} + /* End of Formatting -----------------------------------------*/ From noreply at buildbot.pypy.org Fri Jul 22 13:23:59 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:23:59 +0200 (CEST) Subject: [pypy-commit] pypy default: Update this piece of doc. Message-ID: <20110722112359.88C5582961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45867:6d9fbc591141 Date: 2011-07-21 17:08 +0200 http://bitbucket.org/pypy/pypy/changeset/6d9fbc591141/ Log: Update this piece of doc. diff --git a/pypy/doc/config/translation.gc.txt b/pypy/doc/config/translation.gc.txt --- a/pypy/doc/config/translation.gc.txt +++ b/pypy/doc/config/translation.gc.txt @@ -1,4 +1,6 @@ -Choose the Garbage Collector used by the translated program: +Choose the Garbage Collector used by the translated program. +The good performing collectors are "hybrid" and "minimark". +The default is "minimark". - "ref": reference counting. Takes very long to translate and the result is slow. @@ -11,3 +13,12 @@ older generation. - "boehm": use the Boehm conservative GC. + + - "hybrid": a hybrid collector of "generation" together with a + mark-n-sweep old space + + - "markcompact": a slow, but memory-efficient collector, + influenced e.g. by Smalltalk systems. + + - "minimark": a generational mark-n-speed collector with good + performance. Includes page marking for large arrays. From noreply at buildbot.pypy.org Fri Jul 22 13:24:00 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:24:00 +0200 (CEST) Subject: [pypy-commit] pypy custom-trace: Step 1 (not translated so far) to add custom tracers. Message-ID: <20110722112400.D4BA0829B8@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: custom-trace Changeset: r45868:775391fe3185 Date: 2011-07-21 21:13 +0200 http://bitbucket.org/pypy/pypy/changeset/775391fe3185/ Log: Step 1 (not translated so far) to add custom tracers. diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -362,7 +362,8 @@ about=self)._obj Struct._install_extras(self, **kwds) - def _attach_runtime_type_info_funcptr(self, funcptr, destrptr): + def _attach_runtime_type_info_funcptr(self, funcptr, destrptr, + customtraceptr): if self._runtime_type_info is None: raise TypeError("attachRuntimeTypeInfo: %r must have been built " "with the rtti=True argument" % (self,)) @@ -376,7 +377,7 @@ raise TypeError("expected a runtime type info function " "implementation, got: %s" % funcptr) self._runtime_type_info.query_funcptr = funcptr - if destrptr is not None : + if destrptr is not None: T = typeOf(destrptr) if (not isinstance(T, Ptr) or not isinstance(T.TO, FuncType) or @@ -386,6 +387,18 @@ raise TypeError("expected a destructor function " "implementation, got: %s" % destrptr) self._runtime_type_info.destructor_funcptr = destrptr + if customtraceptr is not None: + from pypy.rpython.lltypesystem import llmemory + T = typeOf(customtraceptr) + if (not isinstance(T, Ptr) or + not isinstance(T.TO, FuncType) or + len(T.TO.ARGS) != 2 or + T.TO.RESULT != llmemory.Address or + T.TO.ARGS[0] != llmemory.Address or + T.TO.ARGS[1] != llmemory.Address): + raise TypeError("expected a custom trace function " + "implementation, got: %s" % customtraceptr) + self._runtime_type_info.custom_trace_funcptr = customtraceptr class GcStruct(RttiStruct): _gckind = 'gc' @@ -2039,10 +2052,12 @@ raise ValueError("only odd integers can be cast back to ptr") return _ptr(PTRTYPE, oddint, solid=True) -def attachRuntimeTypeInfo(GCSTRUCT, funcptr=None, destrptr=None): +def attachRuntimeTypeInfo(GCSTRUCT, funcptr=None, destrptr=None, + customtraceptr=None): if not isinstance(GCSTRUCT, RttiStruct): raise TypeError, "expected a RttiStruct: %s" % GCSTRUCT - GCSTRUCT._attach_runtime_type_info_funcptr(funcptr, destrptr) + GCSTRUCT._attach_runtime_type_info_funcptr(funcptr, destrptr, + customtraceptr) return _ptr(Ptr(RuntimeTypeInfo), GCSTRUCT._runtime_type_info) def getRuntimeTypeInfo(GCSTRUCT): diff --git a/pypy/rpython/memory/gc/base.py b/pypy/rpython/memory/gc/base.py --- a/pypy/rpython/memory/gc/base.py +++ b/pypy/rpython/memory/gc/base.py @@ -69,7 +69,10 @@ varsize_offsets_to_gcpointers_in_var_part, weakpointer_offset, member_index, - is_rpython_class): + is_rpython_class, + has_custom_trace, + get_custom_trace, + fast_path_tracing): self.getfinalizer = getfinalizer self.is_varsize = is_varsize self.has_gcptr_in_varsize = has_gcptr_in_varsize @@ -83,6 +86,9 @@ self.weakpointer_offset = weakpointer_offset self.member_index = member_index self.is_rpython_class = is_rpython_class + self.has_custom_trace = has_custom_trace + self.get_custom_trace = get_custom_trace + self.fast_path_tracing = fast_path_tracing def get_member_index(self, type_id): return self.member_index(type_id) @@ -181,8 +187,14 @@ Typically, 'callback' is a bound method and 'arg' can be None. """ typeid = self.get_type_id(obj) + # + # First, look if we need more than the simple fixed-size tracing + if not self.fast_path_tracing(typeid): + # + # Yes. Two cases: either we are just a GcArray(gcptr), for + # which we have a special case for performance, or we call + # the slow path version. if self.is_gcarrayofgcptr(typeid): - # a performance shortcut for GcArray(gcptr) length = (obj + llmemory.gcarrayofptr_lengthoffset).signed[0] item = obj + llmemory.gcarrayofptr_itemsoffset while length > 0: @@ -191,6 +203,9 @@ item += llmemory.gcarrayofptr_singleitemoffset length -= 1 return + self._trace_slow_path(obj, callback, arg) + # + # Do the tracing on the fixed-size part of the object. offsets = self.offsets_to_gc_pointers(typeid) i = 0 while i < len(offsets): @@ -198,6 +213,10 @@ if self.points_to_valid_gc_object(item): callback(item, arg) i += 1 + trace._annspecialcase_ = 'specialize:arg(2)' + + def _trace_slow_path(self, obj, callback, arg): + typeid = self.get_type_id(obj) if self.has_gcptr_in_varsize(typeid): item = obj + self.varsize_offset_to_variable_part(typeid) length = (obj + self.varsize_offset_to_length(typeid)).signed[0] @@ -212,7 +231,16 @@ j += 1 item += itemlength length -= 1 - trace._annspecialcase_ = 'specialize:arg(2)' + if self.has_custom_trace(typeid): + generator = self.get_custom_trace(typeid) + item = llmemory.NULL + while True: + item = generator(obj, item) + if not item: + break + if self.points_to_valid_gc_object(item): + callback(item, arg) + _trace_slow_path._annspecialcase_ = 'specialize:arg(2)' def trace_partial(self, obj, start, stop, callback, arg): """Like trace(), but only walk the array part, for indices in @@ -317,7 +345,7 @@ break obj = self.run_finalizers.popleft() finalizer = self.getfinalizer(self.get_type_id(obj)) - finalizer(obj) + finalizer(obj, llmemory.NULL) finally: self.finalizer_lock_count -= 1 diff --git a/pypy/rpython/memory/gc/markcompact.py b/pypy/rpython/memory/gc/markcompact.py --- a/pypy/rpython/memory/gc/markcompact.py +++ b/pypy/rpython/memory/gc/markcompact.py @@ -88,6 +88,9 @@ def __init__(self, config, space_size=4096, min_next_collect_after=128, **kwds): + import py + py.test.skip("the 'markcompact' gc needs fixing for custom tracers") + # MovingGCBase.__init__(self, config, **kwds) self.space_size = space_size self.min_next_collect_after = min_next_collect_after diff --git a/pypy/rpython/memory/gc/marksweep.py b/pypy/rpython/memory/gc/marksweep.py --- a/pypy/rpython/memory/gc/marksweep.py +++ b/pypy/rpython/memory/gc/marksweep.py @@ -450,7 +450,7 @@ hdr.next = self.malloced_objects self.malloced_objects = hdr #llop.debug_view(lltype.Void, self.malloced_objects, self.malloced_objects_with_finalizer, size_gc_header) - finalizer(obj) + finalizer(obj, llmemory.NULL) if not self.collect_in_progress: # another collection was caused? debug_print("outer collect interrupted " "by recursive collect") diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1247,15 +1247,15 @@ assert not type_contains_pyobjs(TYPE), "not implemented" if destrptr: typename = TYPE.__name__ - def ll_finalizer(addr): + def ll_finalizer(addr, ignored): v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) ll_call_destructor(destrptr, v, typename) + return llmemory.NULL fptr = self.transformer.annotate_finalizer(ll_finalizer, - [llmemory.Address], - lltype.Void) + [llmemory.Address, llmemory.Address], llmemory.Address) + return fptr else: - fptr = lltype.nullptr(gctypelayout.GCData.FINALIZERTYPE.TO) - return fptr + return None def gen_zero_gc_pointers(TYPE, v, llops, previous_steps=None): diff --git a/pypy/rpython/memory/gctypelayout.py b/pypy/rpython/memory/gctypelayout.py --- a/pypy/rpython/memory/gctypelayout.py +++ b/pypy/rpython/memory/gctypelayout.py @@ -17,13 +17,21 @@ _alloc_flavor_ = 'raw' OFFSETS_TO_GC_PTR = lltype.Array(lltype.Signed) - ADDRESS_VOID_FUNC = lltype.FuncType([llmemory.Address], lltype.Void) - FINALIZERTYPE = lltype.Ptr(ADDRESS_VOID_FUNC) + + # When used as a finalizer, the following functions only take one + # address and ignore the second, and return NULL. When used as a + # custom tracer (CT), it enumerates the addresses that contain GCREFs. + # It is called with the object as first argument, and the previous + # returned address (or NULL the first time) as the second argument. + FINALIZER_OR_CT_FUNC = lltype.FuncType([llmemory.Address, + llmemory.Address], + llmemory.Address) + FINALIZER_OR_CT = lltype.Ptr(FINALIZER_OR_CT_FUNC) # structure describing the layout of a typeid TYPE_INFO = lltype.Struct("type_info", ("infobits", lltype.Signed), # combination of the T_xxx consts - ("finalizer", FINALIZERTYPE), + ("finalizer_or_customtrace", FINALIZER_OR_CT), ("fixedsize", lltype.Signed), ("ofstoptrs", lltype.Ptr(OFFSETS_TO_GC_PTR)), hints={'immutable': True}, @@ -71,7 +79,11 @@ return (infobits & T_IS_GCARRAY_OF_GCPTR) != 0 def q_finalizer(self, typeid): - return self.get(typeid).finalizer + typeinfo = self.get(typeid) + if typeinfo.infobits & T_HAS_FINALIZER: + return typeinfo.finalizer_or_customtrace + else: + return lltype.nullptr(GCData.FINALIZER_OR_CT_FUNC) def q_offsets_to_gc_pointers(self, typeid): return self.get(typeid).ofstoptrs @@ -105,6 +117,25 @@ infobits = self.get(typeid).infobits return infobits & T_IS_RPYTHON_INSTANCE != 0 + def q_has_custom_trace(self, typeid): + infobits = self.get(typeid).infobits + return infobits & T_HAS_CUSTOM_TRACE != 0 + + def q_get_custom_trace(self, typeid): + ll_assert(self.q_has_custom_trace(typeid), + "T_HAS_CUSTOM_TRACE missing") + typeinfo = self.get(typeid) + return typeinfo.finalizer_or_customtrace + + def q_fast_path_tracing(self, typeid): + # return True if none of the flags T_HAS_GCPTR_IN_VARSIZE, + # T_IS_GCARRAY_OF_GCPTR or T_HAS_CUSTOM_TRACE is set + T_ANY_SLOW_FLAG = (T_HAS_GCPTR_IN_VARSIZE | + T_IS_GCARRAY_OF_GCPTR | + T_HAS_CUSTOM_TRACE) + infobits = self.get(typeid).infobits + return infobits & T_ANY_SLOW_FLAG == 0 + def set_query_functions(self, gc): gc.set_query_functions( self.q_is_varsize, @@ -119,18 +150,23 @@ self.q_varsize_offsets_to_gcpointers_in_var_part, self.q_weakpointer_offset, self.q_member_index, - self.q_is_rpython_class) + self.q_is_rpython_class, + self.q_has_custom_trace, + self.q_get_custom_trace, + self.q_fast_path_tracing) # the lowest 16bits are used to store group member index T_MEMBER_INDEX = 0xffff -T_IS_VARSIZE = 0x10000 -T_HAS_GCPTR_IN_VARSIZE = 0x20000 -T_IS_GCARRAY_OF_GCPTR = 0x40000 -T_IS_WEAKREF = 0x80000 +T_IS_VARSIZE = 0x010000 +T_HAS_GCPTR_IN_VARSIZE = 0x020000 +T_IS_GCARRAY_OF_GCPTR = 0x040000 +T_IS_WEAKREF = 0x080000 T_IS_RPYTHON_INSTANCE = 0x100000 # the type is a subclass of OBJECT +T_HAS_FINALIZER = 0x200000 +T_HAS_CUSTOM_TRACE = 0x400000 T_KEY_MASK = intmask(0xFF000000) -T_KEY_VALUE = intmask(0x7A000000) # bug detection only +T_KEY_VALUE = intmask(0x5A000000) # bug detection only def _check_valid_type_info(p): ll_assert(p.infobits & T_KEY_MASK == T_KEY_VALUE, "invalid type_id") @@ -151,7 +187,18 @@ offsets = offsets_to_gc_pointers(TYPE) infobits = index info.ofstoptrs = builder.offsets2table(offsets, TYPE) - info.finalizer = builder.make_finalizer_funcptr_for_type(TYPE) + # + kind_and_fptr = builder.finalizer_funcptr_for_type(TYPE) + if kind_and_fptr is not None: + kind, fptr = kind_and_fptr + info.finalizer_or_customtrace = fptr + if kind == "finalizer": + infobits |= T_HAS_FINALIZER + elif kind == "custom_trace": + infobits |= T_HAS_CUSTOM_TRACE + else: + assert 0, kind + # if not TYPE._is_varsize(): info.fixedsize = llarena.round_up_for_allocation( llmemory.sizeof(TYPE), builder.GCClass.object_minimal_size) @@ -216,7 +263,7 @@ # for debugging, the following list collects all the prebuilt # GcStructs and GcArrays self.all_prebuilt_gc = [] - self.finalizer_funcptrs = {} + self._finalizer_funcptrs = {} self.offsettable_cache = {} def make_type_info_group(self): @@ -318,15 +365,28 @@ return self.type_info_group def finalizer_funcptr_for_type(self, TYPE): - if TYPE in self.finalizer_funcptrs: - return self.finalizer_funcptrs[TYPE] - fptr = self.make_finalizer_funcptr_for_type(TYPE) - self.finalizer_funcptrs[TYPE] = fptr - return fptr + if TYPE in self._finalizer_funcptrs: + return self._finalizer_funcptrs[TYPE] + fptr1 = self.make_finalizer_funcptr_for_type(TYPE) + fptr2 = self.make_custom_trace_funcptr_for_type(TYPE) + assert not (fptr1 and fptr2), ( + "type %r needs both a finalizer and a custom tracer" % (TYPE,)) + if fptr1: + kind_and_fptr = "finalizer", fptr1 + elif fptr2: + kind_and_fptr = "custom_trace", fptr2 + else: + kind_and_fptr = None + self._finalizer_funcptrs[TYPE] = kind_and_fptr + return kind_and_fptr def make_finalizer_funcptr_for_type(self, TYPE): # must be overridden for proper finalizer support - return lltype.nullptr(GCData.ADDRESS_VOID_FUNC) + return None + + def make_custom_trace_funcptr_for_type(self, TYPE): + # must be overridden for proper custom tracer support + return None def initialize_gc_query_function(self, gc): return GCData(self.type_info_group).set_query_functions(gc) diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -196,17 +196,28 @@ DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] destrgraph = destrptr._obj.graph else: - return lltype.nullptr(gctypelayout.GCData.FINALIZERTYPE.TO) + return None assert not type_contains_pyobjs(TYPE), "not implemented" - def ll_finalizer(addr): + def ll_finalizer(addr, dummy): + assert dummy == llmemory.NULL try: v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) self.llinterp.eval_graph(destrgraph, [v], recursive=True) except llinterp.LLException: raise RuntimeError( "a finalizer raised an exception, shouldn't happen") - return llhelper(gctypelayout.GCData.FINALIZERTYPE, ll_finalizer) + return llmemory.NULL + return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer) + + def make_custom_trace_funcptr_for_type(self, TYPE): + from pypy.rpython.memory.gctransform.support import get_rtti, \ + type_contains_pyobjs + rtti = get_rtti(TYPE) + if rtti is not None and hasattr(rtti._obj, 'custom_trace_funcptr'): + return rtti._obj.custom_trace_funcptr + else: + return None def collect_constants(graphs): diff --git a/pypy/rpython/memory/test/test_gc.py b/pypy/rpython/memory/test/test_gc.py --- a/pypy/rpython/memory/test/test_gc.py +++ b/pypy/rpython/memory/test/test_gc.py @@ -237,6 +237,46 @@ res = self.interpret(f, [5]) assert 160 <= res <= 165 + def test_custom_trace(self): + from pypy.rpython.annlowlevel import llhelper + from pypy.rpython.lltypesystem import llmemory + from pypy.rpython.lltypesystem.llarena import ArenaError + # + S = lltype.GcStruct('S', ('x', llmemory.Address), + ('y', llmemory.Address), rtti=True) + T = lltype.GcStruct('T', ('z', lltype.Signed)) + offset_of_x = llmemory.offsetof(S, 'x') + def customtrace(obj, prev): + if not prev: + return obj + offset_of_x + else: + return llmemory.NULL + CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], + llmemory.Address) + customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) + lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr) + # + for attrname in ['x', 'y']: + def setup(): + s1 = lltype.malloc(S) + tx = lltype.malloc(T) + tx.z = 42 + ty = lltype.malloc(T) + s1.x = llmemory.cast_ptr_to_adr(tx) + s1.y = llmemory.cast_ptr_to_adr(ty) + return s1 + def f(): + s1 = setup() + llop.gc__collect(lltype.Void) + return llmemory.cast_adr_to_ptr(getattr(s1, attrname), + lltype.Ptr(T)) + if attrname == 'x': + res = self.interpret(f, []) + assert res.z == 42 + else: + py.test.raises((RuntimeError, ArenaError), + self.interpret, f, []) + def test_weakref(self): import weakref, gc class A(object): From noreply at buildbot.pypy.org Fri Jul 22 13:24:02 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:24:02 +0200 (CEST) Subject: [pypy-commit] pypy custom-trace: test_transformed_gc for custom tracers. Message-ID: <20110722112402.2353282961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: custom-trace Changeset: r45869:7467e121d4ac Date: 2011-07-21 21:28 +0200 http://bitbucket.org/pypy/pypy/changeset/7467e121d4ac/ Log: test_transformed_gc for custom tracers. diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -534,8 +534,8 @@ # this method is attached to the instance and redirects to # layoutbuilder.get_type_id(). - def finalizer_funcptr_for_type(self, TYPE): - return self.layoutbuilder.finalizer_funcptr_for_type(TYPE) + def special_funcptr_for_type(self, TYPE): + return self.layoutbuilder.special_funcptr_for_type(TYPE) def gc_header_for(self, obj, needs_hash=False): hdr = self.gcdata.gc.gcheaderbuilder.header_of_object(obj) @@ -678,7 +678,9 @@ c_type_id = rmodel.inputconst(TYPE_ID, type_id) info = self.layoutbuilder.get_info(type_id) c_size = rmodel.inputconst(lltype.Signed, info.fixedsize) - has_finalizer = bool(self.finalizer_funcptr_for_type(TYPE)) + kind_and_fptr = self.special_funcptr_for_type(TYPE) + has_finalizer = (kind_and_fptr is not None and + kind_and_fptr[0] == "finalizer") c_has_finalizer = rmodel.inputconst(lltype.Bool, has_finalizer) if not op.opname.endswith('_varsize') and not flags.get('varsize'): @@ -1233,19 +1235,21 @@ def has_finalizer(self, TYPE): rtti = get_rtti(TYPE) - return rtti is not None and hasattr(rtti._obj, 'destructor_funcptr') + return rtti is not None and getattr(rtti._obj, 'destructor_funcptr', + None) + + def has_custom_trace(self, TYPE): + rtti = get_rtti(TYPE) + return rtti is not None and getattr(rtti._obj, 'custom_trace_funcptr', + None) def make_finalizer_funcptr_for_type(self, TYPE): - if self.has_finalizer(TYPE): + if not self.has_finalizer(TYPE): + return None rtti = get_rtti(TYPE) destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] - else: - destrptr = None - DESTR_ARG = None - assert not type_contains_pyobjs(TYPE), "not implemented" - if destrptr: typename = TYPE.__name__ def ll_finalizer(addr, ignored): v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) @@ -1254,8 +1258,17 @@ fptr = self.transformer.annotate_finalizer(ll_finalizer, [llmemory.Address, llmemory.Address], llmemory.Address) return fptr - else: + + def make_custom_trace_funcptr_for_type(self, TYPE): + if not self.has_custom_trace(TYPE): return None + rtti = get_rtti(TYPE) + fptr = rtti._obj.custom_trace_funcptr + if not hasattr(fptr._obj, 'graph'): + ll_func = fptr._obj._callable + fptr = self.transformer.annotate_finalizer(ll_func, + [llmemory.Address, llmemory.Address], llmemory.Address) + return fptr def gen_zero_gc_pointers(TYPE, v, llops, previous_steps=None): diff --git a/pypy/rpython/memory/gctypelayout.py b/pypy/rpython/memory/gctypelayout.py --- a/pypy/rpython/memory/gctypelayout.py +++ b/pypy/rpython/memory/gctypelayout.py @@ -188,7 +188,7 @@ infobits = index info.ofstoptrs = builder.offsets2table(offsets, TYPE) # - kind_and_fptr = builder.finalizer_funcptr_for_type(TYPE) + kind_and_fptr = builder.special_funcptr_for_type(TYPE) if kind_and_fptr is not None: kind, fptr = kind_and_fptr info.finalizer_or_customtrace = fptr @@ -263,7 +263,7 @@ # for debugging, the following list collects all the prebuilt # GcStructs and GcArrays self.all_prebuilt_gc = [] - self._finalizer_funcptrs = {} + self._special_funcptrs = {} self.offsettable_cache = {} def make_type_info_group(self): @@ -364,9 +364,9 @@ self.offsettable_cache = None return self.type_info_group - def finalizer_funcptr_for_type(self, TYPE): - if TYPE in self._finalizer_funcptrs: - return self._finalizer_funcptrs[TYPE] + def special_funcptr_for_type(self, TYPE): + if TYPE in self._special_funcptrs: + return self._special_funcptrs[TYPE] fptr1 = self.make_finalizer_funcptr_for_type(TYPE) fptr2 = self.make_custom_trace_funcptr_for_type(TYPE) assert not (fptr1 and fptr2), ( @@ -377,7 +377,7 @@ kind_and_fptr = "custom_trace", fptr2 else: kind_and_fptr = None - self._finalizer_funcptrs[TYPE] = kind_and_fptr + self._special_funcptrs[TYPE] = kind_and_fptr return kind_and_fptr def make_finalizer_funcptr_for_type(self, TYPE): diff --git a/pypy/rpython/memory/test/test_transformed_gc.py b/pypy/rpython/memory/test/test_transformed_gc.py --- a/pypy/rpython/memory/test/test_transformed_gc.py +++ b/pypy/rpython/memory/test/test_transformed_gc.py @@ -410,6 +410,40 @@ res = run([5, 42]) #XXX pure lazyness here too assert 160 <= res <= 165 + def define_custom_trace(cls): + from pypy.rpython.annlowlevel import llhelper + from pypy.rpython.lltypesystem import llmemory + # + S = lltype.GcStruct('S', ('x', llmemory.Address), rtti=True) + T = lltype.GcStruct('T', ('z', lltype.Signed)) + offset_of_x = llmemory.offsetof(S, 'x') + def customtrace(obj, prev): + if not prev: + return obj + offset_of_x + else: + return llmemory.NULL + CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], + llmemory.Address) + customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) + lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr) + # + def setup(): + s1 = lltype.malloc(S) + tx = lltype.malloc(T) + tx.z = 4243 + s1.x = llmemory.cast_ptr_to_adr(tx) + return s1 + def f(): + s1 = setup() + llop.gc__collect(lltype.Void) + return llmemory.cast_adr_to_ptr(s1.x, lltype.Ptr(T)).z + return f + + def test_custom_trace(self): + run = self.runner("custom_trace") + res = run([]) + assert res == 4243 + def define_weakref(cls): import weakref, gc class A(object): diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -320,8 +320,10 @@ # still important to see it so that it can be followed as soon as # the mixlevelannotator resolves it. gctransf = self.db.gctransformer - fptr = gctransf.finalizer_funcptr_for_type(structdefnode.STRUCT) - self.db.get(fptr) + TYPE = structdefnode.STRUCT + kind_and_fptr = gctransf.special_funcptr_for_type(TYPE) + if kind_and_fptr: + self.db.get(kind_and_fptr[1]) def array_setup(self, arraydefnode): pass From noreply at buildbot.pypy.org Fri Jul 22 13:24:03 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:24:03 +0200 (CEST) Subject: [pypy-commit] pypy custom-trace: A test in test_newgc too. Message-ID: <20110722112403.52B0882961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: custom-trace Changeset: r45870:8d3a4293d164 Date: 2011-07-21 21:35 +0200 http://bitbucket.org/pypy/pypy/changeset/8d3a4293d164/ Log: A test in test_newgc too. diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -441,6 +441,45 @@ def test_del_raises(self): self.run('del_raises') # does not raise + def define_custom_trace(cls): + from pypy.rpython.annlowlevel import llhelper + from pypy.rpython.lltypesystem import llmemory + # + S = lltype.GcStruct('S', ('x', llmemory.Address), rtti=True) + offset_of_x = llmemory.offsetof(S, 'x') + def customtrace(obj, prev): + if not prev: + return obj + offset_of_x + else: + return llmemory.NULL + CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], + llmemory.Address) + customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) + lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr) + # + def setup(): + s = lltype.nullptr(S) + for i in range(10000): + t = lltype.malloc(S) + t.x = llmemory.cast_ptr_to_adr(s) + s = t + return s + def measure_length(s): + res = 0 + while s: + res += 1 + s = llmemory.cast_adr_to_ptr(s.x, lltype.Ptr(S)) + return res + def f(n): + s1 = setup() + llop.gc__collect(lltype.Void) + return measure_length(s1) + return f + + def test_custom_trace(self): + res = self.run('custom_trace', 0) + assert res == 10000 + def define_weakref(cls): import weakref From noreply at buildbot.pypy.org Fri Jul 22 13:24:04 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:24:04 +0200 (CEST) Subject: [pypy-commit] pypy custom-trace: typo Message-ID: <20110722112404.8639882961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: custom-trace Changeset: r45871:bba99b2fc522 Date: 2011-07-22 09:16 +0200 http://bitbucket.org/pypy/pypy/changeset/bba99b2fc522/ Log: typo diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -1668,7 +1668,7 @@ None) # we don't need the static in all prebuilt gc objects # # If we are in an inner collection caused by a call to a finalizer, - # the 'run_finalizers' objects also need to kept alive. + # the 'run_finalizers' objects also need to be kept alive. self.run_finalizers.foreach(self._collect_obj, self.objects_to_trace) From noreply at buildbot.pypy.org Fri Jul 22 13:24:05 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:24:05 +0200 (CEST) Subject: [pypy-commit] pypy custom-trace: Move the ShadowStackRootWalker in its own file. No other change. Message-ID: <20110722112405.BBB7982961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: custom-trace Changeset: r45872:688b0606d3d8 Date: 2011-07-22 09:22 +0200 http://bitbucket.org/pypy/pypy/changeset/688b0606d3d8/ Log: Move the ShadowStackRootWalker in its own file. No other change. diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -525,7 +525,8 @@ self.c_vtinfo_skip_offset = rmodel.inputconst(lltype.typeOf(sko), sko) def build_root_walker(self): - return ShadowStackRootWalker(self) + from pypy.rpython.memory.gctransform import shadowstack + return shadowstack.ShadowStackRootWalker(self) def consider_constant(self, TYPE, value): self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc) @@ -1336,217 +1337,3 @@ def need_thread_support(self, gctransformer, getfn): raise Exception("%s does not support threads" % ( self.__class__.__name__,)) - - -class ShadowStackRootWalker(BaseRootWalker): - need_root_stack = True - collect_stacks_from_other_threads = None - - def __init__(self, gctransformer): - BaseRootWalker.__init__(self, gctransformer) - self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth - # NB. 'self' is frozen, but we can use self.gcdata to store state - gcdata = self.gcdata - - def incr_stack(n): - top = gcdata.root_stack_top - gcdata.root_stack_top = top + n*sizeofaddr - return top - self.incr_stack = incr_stack - - def decr_stack(n): - top = gcdata.root_stack_top - n*sizeofaddr - gcdata.root_stack_top = top - return top - self.decr_stack = decr_stack - - self.rootstackhook = gctransformer.root_stack_jit_hook - if self.rootstackhook is None: - def collect_stack_root(callback, gc, addr): - if gc.points_to_valid_gc_object(addr): - callback(gc, addr) - return sizeofaddr - self.rootstackhook = collect_stack_root - - def push_stack(self, addr): - top = self.incr_stack(1) - top.address[0] = addr - - def pop_stack(self): - top = self.decr_stack(1) - return top.address[0] - - def allocate_stack(self): - return llmemory.raw_malloc(self.rootstacksize) - - def setup_root_walker(self): - stackbase = self.allocate_stack() - ll_assert(bool(stackbase), "could not allocate root stack") - self.gcdata.root_stack_top = stackbase - self.gcdata.root_stack_base = stackbase - BaseRootWalker.setup_root_walker(self) - - def walk_stack_roots(self, collect_stack_root): - gcdata = self.gcdata - gc = self.gc - rootstackhook = self.rootstackhook - addr = gcdata.root_stack_base - end = gcdata.root_stack_top - while addr != end: - addr += rootstackhook(collect_stack_root, gc, addr) - if self.collect_stacks_from_other_threads is not None: - self.collect_stacks_from_other_threads(collect_stack_root) - - def need_thread_support(self, gctransformer, getfn): - from pypy.module.thread import ll_thread # xxx fish - from pypy.rpython.memory.support import AddressDict - from pypy.rpython.memory.support import copy_without_null_values - gcdata = self.gcdata - # the interfacing between the threads and the GC is done via - # three completely ad-hoc operations at the moment: - # gc_thread_prepare, gc_thread_run, gc_thread_die. - # See docstrings below. - - def get_aid(): - """Return the thread identifier, cast to an (opaque) address.""" - return llmemory.cast_int_to_adr(ll_thread.get_ident()) - - def thread_setup(): - """Called once when the program starts.""" - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} - gcdata._fresh_rootstack = llmemory.NULL - gcdata.dead_threads_count = 0 - - def thread_prepare(): - """Called just before thread.start_new_thread(). This - allocates a new shadow stack to be used by the future - thread. If memory runs out, this raises a MemoryError - (which can be handled by the caller instead of just getting - ignored if it was raised in the newly starting thread). - """ - if not gcdata._fresh_rootstack: - gcdata._fresh_rootstack = self.allocate_stack() - if not gcdata._fresh_rootstack: - raise MemoryError - - def thread_run(): - """Called whenever the current thread (re-)acquired the GIL. - This should ensure that the shadow stack installed in - gcdata.root_stack_top/root_stack_base is the one corresponding - to the current thread. - """ - aid = get_aid() - if gcdata.active_thread != aid: - switch_shadow_stacks(aid) - - def thread_die(): - """Called just before the final GIL release done by a dying - thread. After a thread_die(), no more gc operation should - occur in this thread. - """ - aid = get_aid() - if aid == gcdata.main_thread: - return # ignore calls to thread_die() in the main thread - # (which can occur after a fork()). - gcdata.thread_stacks.setitem(aid, llmemory.NULL) - old = gcdata.root_stack_base - if gcdata._fresh_rootstack == llmemory.NULL: - gcdata._fresh_rootstack = old - else: - llmemory.raw_free(old) - install_new_stack(gcdata.main_thread) - # from time to time, rehash the dictionary to remove - # old NULL entries - gcdata.dead_threads_count += 1 - if (gcdata.dead_threads_count & 511) == 0: - copy = copy_without_null_values(gcdata.thread_stacks) - gcdata.thread_stacks.delete() - gcdata.thread_stacks = copy - - def switch_shadow_stacks(new_aid): - save_away_current_stack() - install_new_stack(new_aid) - switch_shadow_stacks._dont_inline_ = True - - def save_away_current_stack(): - old_aid = gcdata.active_thread - # save root_stack_base on the top of the stack - self.push_stack(gcdata.root_stack_base) - # store root_stack_top into the dictionary - gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) - - def install_new_stack(new_aid): - # look for the new stack top - top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) - if top == llmemory.NULL: - # first time we see this thread. It is an error if no - # fresh new stack is waiting. - base = gcdata._fresh_rootstack - gcdata._fresh_rootstack = llmemory.NULL - ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") - gcdata.root_stack_top = base - gcdata.root_stack_base = base - else: - # restore the root_stack_base from the top of the stack - gcdata.root_stack_top = top - gcdata.root_stack_base = self.pop_stack() - # done - gcdata.active_thread = new_aid - - def collect_stack(aid, stacktop, callback): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - # collect all valid stacks from the dict (the entry - # corresponding to the current thread is not valid) - gc = self.gc - rootstackhook = self.rootstackhook - end = stacktop - sizeofaddr - addr = end.address[0] - while addr != end: - addr += rootstackhook(callback, gc, addr) - - def collect_more_stacks(callback): - ll_assert(get_aid() == gcdata.active_thread, - "collect_more_stacks(): invalid active_thread") - gcdata.thread_stacks.foreach(collect_stack, callback) - - def _free_if_not_current(aid, stacktop, _): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - end = stacktop - sizeofaddr - base = end.address[0] - llmemory.raw_free(base) - - def thread_after_fork(result_of_fork, opaqueaddr): - # we don't need a thread_before_fork in this case, so - # opaqueaddr == NULL. This is called after fork(). - if result_of_fork == 0: - # We are in the child process. Assumes that only the - # current thread survived, so frees the shadow stacks - # of all the other ones. - gcdata.thread_stacks.foreach(_free_if_not_current, None) - # Clears the dict (including the current thread, which - # was an invalid entry anyway and will be recreated by - # the next call to save_away_current_stack()). - gcdata.thread_stacks.clear() - # Finally, reset the stored thread IDs, in case it - # changed because of fork(). Also change the main - # thread to the current one (because there is not any - # other left). - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - - self.thread_setup = thread_setup - self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) - self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, - inline=True) - # no thread_start_ptr here - self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) - # no thread_before_fork_ptr here - self.thread_after_fork_ptr = getfn(thread_after_fork, - [annmodel.SomeInteger(), - annmodel.SomeAddress()], - annmodel.s_None) - self.collect_stacks_from_other_threads = collect_more_stacks diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py new file mode 100644 --- /dev/null +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -0,0 +1,218 @@ +from pypy.rpython.memory.gctransform.framework import BaseRootWalker +from pypy.rpython.memory.gctransform.framework import sizeofaddr +from pypy.rlib.debug import ll_assert +from pypy.rpython.lltypesystem import llmemory + + +class ShadowStackRootWalker(BaseRootWalker): + need_root_stack = True + collect_stacks_from_other_threads = None + + def __init__(self, gctransformer): + BaseRootWalker.__init__(self, gctransformer) + self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth + # NB. 'self' is frozen, but we can use self.gcdata to store state + gcdata = self.gcdata + + def incr_stack(n): + top = gcdata.root_stack_top + gcdata.root_stack_top = top + n*sizeofaddr + return top + self.incr_stack = incr_stack + + def decr_stack(n): + top = gcdata.root_stack_top - n*sizeofaddr + gcdata.root_stack_top = top + return top + self.decr_stack = decr_stack + + self.rootstackhook = gctransformer.root_stack_jit_hook + if self.rootstackhook is None: + def collect_stack_root(callback, gc, addr): + if gc.points_to_valid_gc_object(addr): + callback(gc, addr) + return sizeofaddr + self.rootstackhook = collect_stack_root + + def push_stack(self, addr): + top = self.incr_stack(1) + top.address[0] = addr + + def pop_stack(self): + top = self.decr_stack(1) + return top.address[0] + + def allocate_stack(self): + return llmemory.raw_malloc(self.rootstacksize) + + def setup_root_walker(self): + stackbase = self.allocate_stack() + ll_assert(bool(stackbase), "could not allocate root stack") + self.gcdata.root_stack_top = stackbase + self.gcdata.root_stack_base = stackbase + BaseRootWalker.setup_root_walker(self) + + def walk_stack_roots(self, collect_stack_root): + gcdata = self.gcdata + gc = self.gc + rootstackhook = self.rootstackhook + addr = gcdata.root_stack_base + end = gcdata.root_stack_top + while addr != end: + addr += rootstackhook(collect_stack_root, gc, addr) + if self.collect_stacks_from_other_threads is not None: + self.collect_stacks_from_other_threads(collect_stack_root) + + def need_thread_support(self, gctransformer, getfn): + from pypy.module.thread import ll_thread # xxx fish + from pypy.rpython.memory.support import AddressDict + from pypy.rpython.memory.support import copy_without_null_values + gcdata = self.gcdata + # the interfacing between the threads and the GC is done via + # three completely ad-hoc operations at the moment: + # gc_thread_prepare, gc_thread_run, gc_thread_die. + # See docstrings below. + + def get_aid(): + """Return the thread identifier, cast to an (opaque) address.""" + return llmemory.cast_int_to_adr(ll_thread.get_ident()) + + def thread_setup(): + """Called once when the program starts.""" + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} + gcdata._fresh_rootstack = llmemory.NULL + gcdata.dead_threads_count = 0 + + def thread_prepare(): + """Called just before thread.start_new_thread(). This + allocates a new shadow stack to be used by the future + thread. If memory runs out, this raises a MemoryError + (which can be handled by the caller instead of just getting + ignored if it was raised in the newly starting thread). + """ + if not gcdata._fresh_rootstack: + gcdata._fresh_rootstack = self.allocate_stack() + if not gcdata._fresh_rootstack: + raise MemoryError + + def thread_run(): + """Called whenever the current thread (re-)acquired the GIL. + This should ensure that the shadow stack installed in + gcdata.root_stack_top/root_stack_base is the one corresponding + to the current thread. + """ + aid = get_aid() + if gcdata.active_thread != aid: + switch_shadow_stacks(aid) + + def thread_die(): + """Called just before the final GIL release done by a dying + thread. After a thread_die(), no more gc operation should + occur in this thread. + """ + aid = get_aid() + if aid == gcdata.main_thread: + return # ignore calls to thread_die() in the main thread + # (which can occur after a fork()). + gcdata.thread_stacks.setitem(aid, llmemory.NULL) + old = gcdata.root_stack_base + if gcdata._fresh_rootstack == llmemory.NULL: + gcdata._fresh_rootstack = old + else: + llmemory.raw_free(old) + install_new_stack(gcdata.main_thread) + # from time to time, rehash the dictionary to remove + # old NULL entries + gcdata.dead_threads_count += 1 + if (gcdata.dead_threads_count & 511) == 0: + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy + + def switch_shadow_stacks(new_aid): + save_away_current_stack() + install_new_stack(new_aid) + switch_shadow_stacks._dont_inline_ = True + + def save_away_current_stack(): + old_aid = gcdata.active_thread + # save root_stack_base on the top of the stack + self.push_stack(gcdata.root_stack_base) + # store root_stack_top into the dictionary + gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) + + def install_new_stack(new_aid): + # look for the new stack top + top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) + if top == llmemory.NULL: + # first time we see this thread. It is an error if no + # fresh new stack is waiting. + base = gcdata._fresh_rootstack + gcdata._fresh_rootstack = llmemory.NULL + ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") + gcdata.root_stack_top = base + gcdata.root_stack_base = base + else: + # restore the root_stack_base from the top of the stack + gcdata.root_stack_top = top + gcdata.root_stack_base = self.pop_stack() + # done + gcdata.active_thread = new_aid + + def collect_stack(aid, stacktop, callback): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + # collect all valid stacks from the dict (the entry + # corresponding to the current thread is not valid) + gc = self.gc + rootstackhook = self.rootstackhook + end = stacktop - sizeofaddr + addr = end.address[0] + while addr != end: + addr += rootstackhook(callback, gc, addr) + + def collect_more_stacks(callback): + ll_assert(get_aid() == gcdata.active_thread, + "collect_more_stacks(): invalid active_thread") + gcdata.thread_stacks.foreach(collect_stack, callback) + + def _free_if_not_current(aid, stacktop, _): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + end = stacktop - sizeofaddr + base = end.address[0] + llmemory.raw_free(base) + + def thread_after_fork(result_of_fork, opaqueaddr): + # we don't need a thread_before_fork in this case, so + # opaqueaddr == NULL. This is called after fork(). + if result_of_fork == 0: + # We are in the child process. Assumes that only the + # current thread survived, so frees the shadow stacks + # of all the other ones. + gcdata.thread_stacks.foreach(_free_if_not_current, None) + # Clears the dict (including the current thread, which + # was an invalid entry anyway and will be recreated by + # the next call to save_away_current_stack()). + gcdata.thread_stacks.clear() + # Finally, reset the stored thread IDs, in case it + # changed because of fork(). Also change the main + # thread to the current one (because there is not any + # other left). + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + + self.thread_setup = thread_setup + self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) + self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, + inline=True) + # no thread_start_ptr here + self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) + # no thread_before_fork_ptr here + self.thread_after_fork_ptr = getfn(thread_after_fork, + [annmodel.SomeInteger(), + annmodel.SomeAddress()], + annmodel.s_None) + self.collect_stacks_from_other_threads = collect_more_stacks From noreply at buildbot.pypy.org Fri Jul 22 13:24:07 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:24:07 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110722112407.1E25F82961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45873:63a68e798693 Date: 2011-07-22 13:24 +0200 http://bitbucket.org/pypy/pypy/changeset/63a68e798693/ Log: merge heads diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,6 +116,12 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + if "CFLAGS" in os.environ: + cflags = os.environ["CFLAGS"] + compiler.compiler.append(cflags) + compiler.compiler_so.append(cflags) + compiler.linker_so.append(cflags) + from sysconfig_cpython import ( parse_makefile, _variable_rx, expand_makefile_vars) diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -929,6 +929,19 @@ located in the ``py/bin/`` directory. For switches to modify test execution pass the ``-h`` option. +Coverage reports +---------------- + +In order to get coverage reports the `pytest-cov`_ plugin is included. +it adds some extra requirements ( coverage_ and `cov-core`_ ) +and can once they are installed coverage testing can be invoked via:: + + python test_all.py --cov file_or_direcory_to_cover file_or_directory + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov +.. _`coverage`: http://pypi.python.org/pypi/coverage +.. _`cov-core`: http://pypi.python.org/pypi/cov-core + Test conventions ---------------- diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -32,6 +32,15 @@ modules that relies on third-party libraries. See below how to get and build them. +Preping Windows for the Large Build +----------------------------------- + +Follow http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 to allow Windows up to 3GB for 32bit applications if you are on a 32bit version of windows. If you are using Visual C++ 2008 (untested with 2005), then you will have a utility called editbin.exe within Visual Studio 9.0\VC\bin. You will need to execute:: + + editbin /largeaddressaware pypy.exe + +on the pypy.exe or python.exe you are using to buld the new pypy. Reboot now if you followed the 3G instructions for 32bit windows. + Installing external packages ---------------------------- diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2820,11 +2820,11 @@ def test_residual_call_invalidate_some_arrays(self): ops = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) - p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p2, 0, descr=arraydescr2) p6 = getarrayitem_gc(p2, 1, descr=arraydescr2) i4 = getarrayitem_gc(p1, 1, descr=arraydescr) escape(p3) @@ -2837,7 +2837,7 @@ """ expected = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2586,7 +2586,23 @@ return n res = self.meta_interp(f, [10, 1]) self.check_loops(getfield_gc=2) + assert res == f(10, 1) + def test_jit_merge_point_with_raw_pointer(self): + driver = JitDriver(greens = [], reds = ['n', 'x']) + + TP = lltype.Array(lltype.Signed, hints={'nolength': True}) + + def f(n): + x = lltype.malloc(TP, 10, flavor='raw') + x[0] = 1 + while n > 0: + driver.jit_merge_point(n=n, x=x) + n -= x[0] + lltype.free(x, flavor='raw') + return n + + self.meta_interp(f, [10], repeat=3) class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -138,6 +138,9 @@ refvalue = cpu.ts.cast_to_ref(value) cpu.set_future_value_ref(j, refvalue) elif typecode == 'int': + if isinstance(lltype.typeOf(value), lltype.Ptr): + intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value)) + else: intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) elif typecode == 'float': diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -11,29 +11,15 @@ from pypy.tool.sourcetools import func_with_new_name import math -def dummy1(v): - assert isinstance(v, float) - return v - -def dummy2(v): - assert isinstance(v, float) - return v - TP = lltype.Array(lltype.Float, hints={'nolength': True}) numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) -slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) -slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'storage', 'arr']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) -def pos(v): - return v -def neg(v): - return -v -def absolute(v): - return abs(v) def add(v1, v2): return v1 + v2 def mul(v1, v2): @@ -59,21 +45,14 @@ arr.force_if_needed() del self.invalidates[:] - def _unop_impl(function): - signature = Signature() + def _unaryop_impl(w_ufunc): def impl(self, space): - new_sig = self.signature.transition(signature) - res = Call1( - function, - self, - new_sig) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + return w_ufunc(space, self) + return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__) - descr_pos = _unop_impl(pos) - descr_neg = _unop_impl(neg) - descr_abs = _unop_impl(absolute) + descr_pos = _unaryop_impl(interp_ufuncs.positive) + descr_neg = _unaryop_impl(interp_ufuncs.negative) + descr_abs = _unaryop_impl(interp_ufuncs.absolute) def _binop_impl(w_ufunc): def impl(self, space, w_other): @@ -268,23 +247,25 @@ def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) - def _sliceloop1(self, start, stop, step, arr, storage): + def _sliceloop1(self, start, stop, step, source, dest): i = start j = 0 while i < stop: - slice_driver1.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) - storage[i] = arr.eval(j) + slice_driver1.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) j += 1 i += step - def _sliceloop2(self, start, stop, step, arr, storage): + def _sliceloop2(self, start, stop, step, source, dest): i = start j = 0 while i > stop: - slice_driver2.jit_merge_point(signature=arr.signature, - step=step, stop=stop, i=i, j=j, arr=arr, storage=storage) - storage[i] = arr.eval(j) + slice_driver2.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) j += 1 i += step @@ -469,9 +450,9 @@ stop = self.calc_index(stop) step = self.step * step if step > 0: - self._sliceloop1(start, stop, step, arr, self.parent.storage) + self._sliceloop1(start, stop, step, arr, self.parent) else: - self._sliceloop2(start, stop, step, arr, self.parent.storage) + self._sliceloop2(start, stop, step, arr, self.parent) def calc_index(self, item): return (self.start + item * self.step) @@ -510,9 +491,9 @@ if not isinstance(arr, BaseArray): arr = convert_to_array(space, arr) if step > 0: - self._sliceloop1(start, stop, step, arr, self.storage) + self._sliceloop1(start, stop, step, arr, self) else: - self._sliceloop2(start, stop, step, arr, self.storage) + self._sliceloop2(start, stop, step, arr, self) def __del__(self): lltype.free(self.storage, flavor='raw') diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -72,6 +72,11 @@ def multiply(lvalue, rvalue): return lvalue * rvalue +# Used by numarray for __pos__. Not visible from numpy application space. + at ufunc +def positive(value): + return value + @ufunc def negative(value): return -value @@ -114,4 +119,4 @@ @ufunc2 def mod(lvalue, rvalue): - return math.fmod(lvalue, rvalue) \ No newline at end of file + return math.fmod(lvalue, rvalue) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -171,6 +171,12 @@ for i in range(5): assert b[i] == i + 5 + def test_radd(self): + from numpy import array + r = 3 + array(range(3)) + for i in range(3): + assert r[i] == i + 3 + def test_add_list(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) + FloatWrapper, Call2, SingleDimSlice, add, mul, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize @@ -48,19 +48,6 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_neg(self): - def f(i): - ar = SingleDimArray(i) - v = Call1(neg, ar, Signature()) - return v.get_concrete().storage[3] - - result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, - "setarrayitem_raw": 1, "int_add": 1, - "int_lt": 1, "guard_true": 1, "jump": 1}) - - assert result == f(5) - def test_sum(self): space = self.space diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -92,10 +92,10 @@ p51 = new_with_vtable(21136408) setfield_gc(p51, p28, descr=) setfield_gc(p51, ConstPtr(ptr51), descr=) - setfield_gc(p51, i29, descr=) setfield_gc(p51, 1, descr=) setfield_gc(p51, 16, descr=) setfield_gc(p51, p28, descr=) + setfield_gc(p51, i29, descr=) p55 = call(ConstClass(parse_digit_string), p51, descr=) guard_no_exception(descr=...) i57 = call(ConstClass(rbigint.toint), p55, descr=) @@ -104,4 +104,4 @@ guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) - """) \ No newline at end of file + """) diff --git a/pypy/module/select/test/test_epoll.py b/pypy/module/select/test/test_epoll.py --- a/pypy/module/select/test/test_epoll.py +++ b/pypy/module/select/test/test_epoll.py @@ -138,7 +138,7 @@ expected.sort() assert events == expected - assert then - now < 0.01 + assert then - now < 0.02 now = time.time() events = ep.poll(timeout=2.1, maxevents=4) @@ -151,7 +151,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 events.sort() expected = [ @@ -168,7 +168,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 expected = [(server.fileno(), select.EPOLLOUT)] assert events == expected @@ -192,7 +192,7 @@ now = time.time() ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 server.close() ep.unregister(fd) diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -86,7 +86,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated() + self.unerase(w_dict.dstorage).mutated(None) class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py --- a/pypy/objspace/std/test/test_identitydict.py +++ b/pypy/objspace/std/test/test_identitydict.py @@ -1,3 +1,4 @@ +import py from pypy.interpreter.gateway import interp2app from pypy.conftest import gettestobjspace from pypy.conftest import option @@ -8,6 +9,8 @@ from pypy.objspace.std import identitydict cls.space = gettestobjspace( **{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("interp2app doesn't work on appdirect") def compares_by_identity(space, w_cls): return space.wrap(w_cls.compares_by_identity()) @@ -49,7 +52,7 @@ def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) if option.runappdirect: - py.test.skip("__repr__ doesn't work on appdirect") + py.test.skip("interp2app doesn't work on appdirect") def w_uses_identity_strategy(self, obj): import __pypy__ diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -875,28 +875,32 @@ if bufsize == -1: # Get default from the class bufsize = self.bufsize self.bufsize = bufsize # buffer size (hint only) - self.buf = "" + self.buf = [] + self.buflen = 0 def flush_buffers(self): if self.buf: - self.do_write(self.buf) - self.buf = "" + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 def tell(self): - return self.do_tell() + len(self.buf) + return self.do_tell() + self.buflen def write(self, data): - buflen = len(self.buf) + buflen = self.buflen datalen = len(data) if datalen + buflen < self.bufsize: - self.buf += data + self.buf.append(data) + self.buflen += datalen elif buflen: - slice = self.bufsize - buflen - assert slice >= 0 - self.buf += data[:slice] - self.do_write(self.buf) - self.buf = "" - self.write(data[slice:]) + i = self.bufsize - buflen + assert i >= 0 + self.buf.append(data[:i]) + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 + self.write(data[i:]) else: self.do_write(data) @@ -922,11 +926,27 @@ """ def write(self, data): - BufferingOutputStream.write(self, data) - p = self.buf.rfind('\n') + 1 - if p >= 0: - self.do_write(self.buf[:p]) - self.buf = self.buf[p:] + p = data.rfind('\n') + 1 + assert p >= 0 + if self.buflen + len(data) < self.bufsize: + if p == 0: + self.buf.append(data) + self.buflen += len(data) + else: + if self.buflen: + self.do_write(''.join(self.buf)) + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) + else: + if self.buflen + p < self.bufsize: + p = self.bufsize - self.buflen + if self.buflen: + self.do_write(''.join(self.buf)) + assert p >= 0 + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) # ____________________________________________________________ diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -18,4 +18,5 @@ if __name__ == '__main__': import tool.autopath import pytest - sys.exit(pytest.main()) + import pytest_cov + sys.exit(pytest.main(plugins=[pytest_cov])) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -30,6 +30,9 @@ def getres(self): return self._getvar(self.res) + def getdescr(self): + return self.descr + def _getvar(self, v): return v @@ -37,9 +40,9 @@ return self._is_guard def repr(self): - args = self.args + args = self.getargs() if self.descr is not None: - args.append('descr=%s' % self.descr) + args.append('descr=%s' % self.getdescr()) arglist = ', '.join(args) if self.res is not None: return '%s = %s(%s)' % (self.getres(), self.name, arglist) diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,6 +1,6 @@ from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, Function, adjust_bridges, - import_log) + import_log, Op) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys @@ -225,3 +225,9 @@ assert 'cmp' in loops[1].operations[1].asm # bridge assert 'jo' in loops[3].operations[3].asm + +def test_Op_repr_is_pure(): + op = Op('foobar', ['a', 'b'], 'c', 'mydescr') + myrepr = 'c = foobar(a, b, descr=mydescr)' + assert op.repr() == myrepr + assert op.repr() == myrepr # do it twice diff --git a/pypy/tool/release/win32build.py b/pypy/tool/release/win32build.py --- a/pypy/tool/release/win32build.py +++ b/pypy/tool/release/win32build.py @@ -24,6 +24,6 @@ shutil.copy(str(pypydir.join('..', '..', 'expat-2.0.1', 'win32', 'bin', 'release', 'libexpat.dll')), str(builddir)) make_pypy('', ['-Ojit']) -make_pypy('-nojit', []) +make_pypy('-nojit', ['-O2']) #make_pypy('-stackless', [--stackless]) #make_pypy('-sandbox', [--sandbox]) diff --git a/pytest.py b/pytest.py --- a/pytest.py +++ b/pytest.py @@ -9,6 +9,8 @@ from _pytest import __version__ if __name__ == '__main__': # if run as a script or by 'python -m pytest' - raise SystemExit(main()) + #XXX: sync to upstream later + import pytest_cov + raise SystemExit(main(plugins=[pytest_cov])) else: _preloadplugins() # to populate pytest.* namespace so help(pytest) works diff --git a/pytest_cov.py b/pytest_cov.py new file mode 100644 --- /dev/null +++ b/pytest_cov.py @@ -0,0 +1,353 @@ +"""produce code coverage reports using the 'coverage' package, including support for distributed testing. + +This plugin produces coverage reports. It supports centralised testing and distributed testing in +both load and each modes. It also supports coverage of subprocesses. + +All features offered by the coverage package should be available, either through pytest-cov or +through coverage's config file. + + +Installation +------------ + +The `pytest-cov`_ package may be installed with pip or easy_install:: + + pip install pytest-cov + easy_install pytest-cov + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov/ + + +Uninstallation +-------------- + +Uninstalling packages is supported by pip:: + + pip uninstall pytest-cov + +However easy_install does not provide an uninstall facility. + +.. IMPORTANT:: + + Ensure that you manually delete the init_cov_core.pth file in your site-packages directory. + + This file starts coverage collection of subprocesses if appropriate during site initialisation + at python startup. + + +Usage +----- + +Centralised Testing +~~~~~~~~~~~~~~~~~~~ + +Centralised testing will report on the combined coverage of the main process and all of it's +subprocesses. + +Running centralised testing:: + + py.test --cov myproj tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Load +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to load will report on the combined coverage of all slaves. +The slaves may be spread out over any number of hosts and each slave may be located anywhere on the +file system. Each slave will have it's subprocesses measured. + +Running distributed testing with dist mode set to load:: + + py.test --cov myproj -n 2 tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Again but spread over different hosts and different directories:: + + py.test --cov myproj --dist load + --tx ssh=memedough at host1//chdir=testenv1 + --tx ssh=memedough at host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Each +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to each will report on the combined coverage of all slaves. +Since each slave is running all tests this allows generating a combined coverage report for multiple +environments. + +Running distributed testing with dist mode set to each:: + + py.test --cov myproj --dist each + --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python + --tx ssh=memedough at host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + ---------------------------------------- coverage ---------------------------------------- + platform linux2, python 2.6.5-final-0 + platform linux2, python 2.7.0-final-0 + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Reporting +--------- + +It is possible to generate any combination of the reports for a single test run. + +The available reports are terminal (with or without missing line numbers shown), HTML, XML and +annotated source code. + +The terminal report without line numbers (default):: + + py.test --cov-report term --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +The terminal report with line numbers:: + + py.test --cov-report term-missing --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover Missing + -------------------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% 24-26, 99, 149, 233-236, 297-298, 369-370 + myproj/feature4286 94 7 92% 183-188, 197 + -------------------------------------------------- + TOTAL 353 20 94% + + +The remaining three reports output to files without showing anything on the terminal (useful for +when the output is going to a continuous integration server):: + + py.test --cov-report html + --cov-report xml + --cov-report annotate + --cov myproj tests/ + + +Coverage Data File +------------------ + +The data file is erased at the beginning of testing to ensure clean data for each test run. + +The data file is left at the end of testing so that it is possible to use normal coverage tools to +examine it. + + +Coverage Config File +-------------------- + +This plugin provides a clean minimal set of command line options that are added to pytest. For +further control of coverage use a coverage config file. + +For example if tests are contained within the directory tree being measured the tests may be +excluded if desired by using a .coveragerc file with the omit option set:: + + py.test --cov-config .coveragerc + --cov myproj + myproj/tests/ + +Where the .coveragerc file contains file globs:: + + [run] + omit = tests/* + +For full details refer to the `coverage config file`_ documentation. + +.. _`coverage config file`: http://nedbatchelder.com/code/coverage/config.html + +Note that this plugin controls some options and setting the option in the config file will have no +effect. These include specifying source to be measured (source option) and all data file handling +(data_file and parallel options). + + +Limitations +----------- + +For distributed testing the slaves must have the pytest-cov package installed. This is needed since +the plugin must be registered through setuptools / distribute for pytest to start the plugin on the +slave. + +For subprocess measurement environment variables must make it from the main process to the +subprocess. The python used by the subprocess must have pytest-cov installed. The subprocess must +do normal site initialisation so that the environment variables can be detected and coverage +started. + + +Acknowledgements +---------------- + +Whilst this plugin has been built fresh from the ground up it has been influenced by the work done +on pytest-coverage (Ross Lawley, James Mills, Holger Krekel) and nose-cover (Jason Pellerin) which are +other coverage plugins. + +Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs. + +Holger Krekel for pytest with its distributed testing support. + +Jason Pellerin for nose. + +Michael Foord for unittest2. + +No doubt others have contributed to these tools as well. +""" + + +def pytest_addoption(parser): + """Add options to control coverage.""" + + group = parser.getgroup('coverage reporting with distributed testing support') + group.addoption('--cov', action='append', default=[], metavar='path', + dest='cov_source', + help='measure coverage for filesystem path (multi-allowed)') + group.addoption('--cov-report', action='append', default=[], metavar='type', + choices=['term', 'term-missing', 'annotate', 'html', 'xml'], + dest='cov_report', + help='type of report to generate: term, term-missing, annotate, html, xml (multi-allowed)') + group.addoption('--cov-config', action='store', default='.coveragerc', metavar='path', + dest='cov_config', + help='config file for coverage, default: .coveragerc') + + +def pytest_configure(config): + """Activate coverage plugin if appropriate.""" + + if config.getvalue('cov_source'): + config.pluginmanager.register(CovPlugin(), '_cov') + + +class CovPlugin(object): + """Use coverage package to produce code coverage reports. + + Delegates all work to a particular implementation based on whether + this test process is centralised, a distributed master or a + distributed slave. + """ + + def __init__(self): + """Creates a coverage pytest plugin. + + We read the rc file that coverage uses to get the data file + name. This is needed since we give coverage through it's API + the data file name. + """ + + # Our implementation is unknown at this time. + self.cov_controller = None + + def pytest_sessionstart(self, session): + """At session start determine our implementation and delegate to it.""" + + import cov_core + + cov_source = session.config.getvalue('cov_source') + cov_report = session.config.getvalue('cov_report') or ['term'] + cov_config = session.config.getvalue('cov_config') + + session_name = session.__class__.__name__ + is_master = (session.config.pluginmanager.hasplugin('dsession') or + session_name == 'DSession') + is_slave = (hasattr(session.config, 'slaveinput') or + session_name == 'SlaveSession') + nodeid = None + + if is_master: + controller_cls = cov_core.DistMaster + elif is_slave: + controller_cls = cov_core.DistSlave + nodeid = session.config.slaveinput.get('slaveid', getattr(session, 'nodeid')) + else: + controller_cls = cov_core.Central + + self.cov_controller = controller_cls(cov_source, + cov_report, + cov_config, + session.config, + nodeid) + + self.cov_controller.start() + + def pytest_configure_node(self, node): + """Delegate to our implementation.""" + + self.cov_controller.configure_node(node) + pytest_configure_node.optionalhook = True + + def pytest_testnodedown(self, node, error): + """Delegate to our implementation.""" + + self.cov_controller.testnodedown(node, error) + pytest_testnodedown.optionalhook = True + + def pytest_sessionfinish(self, session, exitstatus): + """Delegate to our implementation.""" + + self.cov_controller.finish() + + def pytest_terminal_summary(self, terminalreporter): + """Delegate to our implementation.""" + + self.cov_controller.summary(terminalreporter._tw) + + +def pytest_funcarg__cov(request): + """A pytest funcarg that provides access to the underlying coverage object.""" + + # Check with hasplugin to avoid getplugin exception in older pytest. + if request.config.pluginmanager.hasplugin('_cov'): + plugin = request.config.pluginmanager.getplugin('_cov') + if plugin.cov_controller: + return plugin.cov_controller.cov + return None From noreply at buildbot.pypy.org Fri Jul 22 13:26:18 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:26:18 +0200 (CEST) Subject: [pypy-commit] pypy default: Typo. Thanks anto :-) Message-ID: <20110722112618.67ADB82961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45874:4c725eb2f10f Date: 2011-07-22 13:26 +0200 http://bitbucket.org/pypy/pypy/changeset/4c725eb2f10f/ Log: Typo. Thanks anto :-) diff --git a/pypy/doc/config/translation.gc.txt b/pypy/doc/config/translation.gc.txt --- a/pypy/doc/config/translation.gc.txt +++ b/pypy/doc/config/translation.gc.txt @@ -20,5 +20,5 @@ - "markcompact": a slow, but memory-efficient collector, influenced e.g. by Smalltalk systems. - - "minimark": a generational mark-n-speed collector with good + - "minimark": a generational mark-n-sweep collector with good performance. Includes page marking for large arrays. From noreply at buildbot.pypy.org Fri Jul 22 13:42:24 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:42:24 +0200 (CEST) Subject: [pypy-commit] pypy tealet: hg merge default Message-ID: <20110722114224.B6B3582961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45875:e63fcce8c423 Date: 2011-07-15 09:09 +0200 http://bitbucket.org/pypy/pypy/changeset/e63fcce8c423/ Log: hg merge default diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -48,7 +48,8 @@ return self.from_param(as_parameter) def get_ffi_param(self, value): - return self.from_param(value)._to_ffi_param() + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() def get_ffi_argtype(self): if self._ffiargtype: diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -328,12 +328,14 @@ "native COM method call without 'this' parameter" ) thisarg = cast(args[0], POINTER(POINTER(c_void_p))) - newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) newargs.insert(0, args[0].value) argtypes.insert(0, c_void_p) else: thisarg = None - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -437,16 +439,15 @@ @classmethod def _conv_param(cls, argtype, arg): if isinstance(argtype, _CDataMeta): - #arg = argtype.from_param(arg) - arg = argtype.get_ffi_param(arg) - return arg, argtype + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - return arg._to_ffi_param(), type(arg) + return arg, arg._to_ffi_param(), type(arg) # # non-usual case: we do the import here to save a lot of code in the # jit trace of the normal case @@ -463,11 +464,12 @@ else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj._to_ffi_param(), type(cobj) + return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] + keepalives = [] newargtypes = [] total = len(args) paramflags = self._paramflags @@ -495,7 +497,8 @@ val = defval if val is marker: val = 0 - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): @@ -511,28 +514,32 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - newarg, newargtype = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) + keepalive = None newarg = ctypes.byref(val) newargtype = type(newarg) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - newarg, newargtype = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) inargs_idx += 1 @@ -541,12 +548,13 @@ extra = args[len(newargs):] for i, arg in enumerate(extra): try: - newarg, newargtype = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) - return newargs, newargtypes, outargs + return keepalives, newargs, newargtypes, outargs def _wrap_result(self, restype, result): diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -29,7 +29,7 @@ PythonPickler.__init__(self, *args, **kw) def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -263,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -27,9 +27,10 @@ _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset) -def parse_future(tree): +def parse_future(tree, feature_flags): future_lineno = 0 future_column = 0 + flags = 0 have_docstring = False body = None if isinstance(tree, ast.Module): @@ -37,7 +38,7 @@ elif isinstance(tree, ast.Interactive): body = tree.body if body is None: - return 0, 0 + return 0, 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): if have_docstring: @@ -48,11 +49,16 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset + for alias in stmt.names: + assert isinstance(alias, ast.alias) + # If this is an invalid flag, it will be caught later in + # codegen.py. + flags |= feature_flags.get(alias.name, 0) else: break else: break - return future_lineno, future_column + return flags, future_lineno, future_column class ForbiddenNameAssignment(Exception): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): @@ -925,6 +927,9 @@ return self.w_True return self.w_False + def issequence_w(self, w_obj): + return (self.findattr(w_obj, self.wrap("__getitem__")) is not None) + def isinstance_w(self, w_obj, w_type): return self.is_true(self.isinstance(w_obj, w_type)) diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -396,11 +396,14 @@ fastfunc = func else: # try to avoid excessive bloat - if func.__module__ == 'pypy.interpreter.astcompiler.ast': + mod = func.__module__ + if mod is None: + mod = "" + if mod == 'pypy.interpreter.astcompiler.ast': raise FastFuncNotSupported - if (not func.__module__.startswith('pypy.module.__builtin__') and - not func.__module__.startswith('pypy.module.sys') and - not func.__module__.startswith('pypy.module.math')): + if (not mod.startswith('pypy.module.__builtin__') and + not mod.startswith('pypy.module.sys') and + not mod.startswith('pypy.module.math')): if not func.__name__.startswith('descr'): raise FastFuncNotSupported d = {} diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,10 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - future_pos = misc.parse_future(node) + fut = misc.parse_future(node, self.future_flags.compiler_features) + f_flags, f_lineno, f_col = fut + future_pos = f_lineno, f_col + flags |= f_flags info = pyparse.CompileInfo(filename, mode, flags, future_pos) return self._compile_ast(node, info) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -858,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -416,10 +416,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -478,9 +481,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d has address %x to %x" % + debug_start("jit-backend-addr") + debug_print("bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -464,7 +464,7 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ @@ -632,16 +632,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): @@ -44,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -58,10 +63,15 @@ expected = "\xE8" + struct.pack(' movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -765,13 +765,65 @@ raise NotImplementedError("cast_ptr_to_int") def rewrite_op_force_cast(self, op): - from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof + assert not self._is_gc(op.args[0]) + fromll = longlong.is_longlong(op.args[0].concretetype) + toll = longlong.is_longlong(op.result.concretetype) + if fromll and toll: + return + if fromll: + args = op.args + opname = 'truncate_longlong_to_int' + RESULT = lltype.Signed + v = varoftype(RESULT) + op1 = SpaceOperation(opname, args, v) + op2 = self.rewrite_operation(op1) + oplist = self.force_cast_without_longlong(op2.result, op.result) + if oplist: + return [op2] + oplist + # + # force a renaming to put the correct result in place, even though + # it might be slightly mistyped (e.g. Signed versus Unsigned) + assert op2.result is v + op2.result = op.result + return op2 + elif toll: + from pypy.rpython.lltypesystem import rffi + size, unsigned = rffi.size_and_sign(op.args[0].concretetype) + if unsigned: + INTERMEDIATE = lltype.Unsigned + else: + INTERMEDIATE = lltype.Signed + v = varoftype(INTERMEDIATE) + oplist = self.force_cast_without_longlong(op.args[0], v) + if not oplist: + v = op.args[0] + oplist = [] + if unsigned: + opname = 'cast_uint_to_longlong' + else: + opname = 'cast_int_to_longlong' + op1 = SpaceOperation(opname, [v], op.result) + op2 = self.rewrite_operation(op1) + return oplist + [op2] + else: + return self.force_cast_without_longlong(op.args[0], op.result) + + def force_cast_without_longlong(self, v_arg, v_result): + from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT from pypy.rlib.rarithmetic import intmask - assert not self._is_gc(op.args[0]) - size2, unsigned2 = size_and_sign(op.result.concretetype) - if size2 >= sizeof(lltype.Signed): + # + if (v_result.concretetype in (FLOAT, lltype.Float) or + v_arg.concretetype in (FLOAT, lltype.Float)): + assert (v_result.concretetype == lltype.Float and + v_arg.concretetype == lltype.Float), "xxx unsupported cast" + return + # + size2, unsigned2 = size_and_sign(v_result.concretetype) + assert size2 <= sizeof(lltype.Signed) + if size2 == sizeof(lltype.Signed): return # the target type is LONG or ULONG - size1, unsigned1 = size_and_sign(op.args[0].concretetype) + size1, unsigned1 = size_and_sign(v_arg.concretetype) + assert size1 <= sizeof(lltype.Signed) # def bounds(size, unsigned): if unsigned: @@ -784,22 +836,28 @@ return # the target type includes the source range # result = [] - v1 = op.args[0] if min2: c_min2 = Constant(min2, lltype.Signed) - v2 = Variable(); v2.concretetype = lltype.Signed - result.append(SpaceOperation('int_sub', [v1, c_min2], v2)) + v2 = varoftype(lltype.Signed) + result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2)) else: - v2 = v1 + v2 = v_arg c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed) - v3 = Variable(); v3.concretetype = lltype.Signed + v3 = varoftype(lltype.Signed) result.append(SpaceOperation('int_and', [v2, c_mask], v3)) if min2: - result.append(SpaceOperation('int_add', [v3, c_min2], op.result)) + result.append(SpaceOperation('int_add', [v3, c_min2], v_result)) else: - result[-1].result = op.result + result[-1].result = v_result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from @@ -883,30 +941,7 @@ rewrite_op_ullong_is_true = rewrite_op_llong_is_true def rewrite_op_cast_primitive(self, op): - fromll = longlong.is_longlong(op.args[0].concretetype) - toll = longlong.is_longlong(op.result.concretetype) - if fromll != toll: - args = op.args - if fromll: - opname = 'truncate_longlong_to_int' - RESULT = lltype.Signed - else: - from pypy.rpython.lltypesystem import rffi - if rffi.cast(op.args[0].concretetype, -1) < 0: - opname = 'cast_int_to_longlong' - else: - opname = 'cast_uint_to_longlong' - RESULT = lltype.SignedLongLong - v = varoftype(RESULT) - op1 = SpaceOperation(opname, args, v) - op2 = self.rewrite_operation(op1) - # - # force a renaming to put the correct result in place, even though - # it might be slightly mistyped (e.g. Signed versus Unsigned) - assert op2.result is v - op2.result = op.result - # - return op2 + return self.rewrite_op_force_cast(op) # ---------- # Renames, from the _old opname to the _new one. @@ -1240,7 +1275,7 @@ calldescr = self.callcontrol.getcalldescr(op, oopspecindex, extraeffect) if extraeffect is not None: - assert (type(calldescr) is str # for tests + assert (is_test_calldescr(calldescr) # for tests or calldescr.get_extra_info().extraeffect == extraeffect) if isinstance(op.args[0].value, str): pass # for tests only @@ -1401,6 +1436,9 @@ return "using virtualizable array in illegal way in %r" % ( self.args[0],) +def is_test_calldescr(calldescr): + return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False) + def _with_prefix(prefix): result = {} for name in dir(Transformer): diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -96,6 +96,7 @@ def _try_coalesce(self, v, w): if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: + assert getkind(w.concretetype) == self.kind dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -3,6 +3,7 @@ from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register from pypy.jit.codewriter.format import assert_format +from pypy.jit.codewriter import longlong from pypy.jit.metainterp.history import AbstractDescr from pypy.rpython.lltypesystem import lltype, rclass, rstr from pypy.objspace.flow.model import SpaceOperation, Variable, Constant @@ -30,6 +31,9 @@ 'float': FakeRegAlloc()} class FakeDescr(AbstractDescr): + _for_tests_only = True + def __init__(self, oopspecindex=None): + self.oopspecindex = oopspecindex def __repr__(self): return '' def as_vtable_size_descr(self): @@ -55,19 +59,24 @@ def arraydescrof(self, ARRAY): return FakeDescr() +class FakeCallInfoCollection: + def add(self, *args): + pass + class FakeCallControl: _descr_cannot_raise = FakeDescr() + callinfocollection = FakeCallInfoCollection() def guess_call_kind(self, op): return 'residual' - def getcalldescr(self, op): + def getcalldescr(self, op, oopspecindex=None, extraeffect=None): try: if 'cannot_raise' in op.args[0].value._obj.graph.name: return self._descr_cannot_raise except AttributeError: pass - return FakeDescr() + return FakeDescr(oopspecindex) def calldescr_canraise(self, calldescr): - return calldescr is not self._descr_cannot_raise + return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None def get_vinfo(self, VTYPEPTR): return None @@ -734,7 +743,9 @@ def test_force_cast(self): from pypy.rpython.lltypesystem import rffi - + # NB: we don't need to test for INT here, the logic in jtransform is + # general enough so that if we have the below cases it should + # generalize also to INT for FROM, TO, expected in [ (rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""), (rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"), @@ -797,12 +808,42 @@ expected = [s.strip() for s in expected.splitlines()] check_force_cast(FROM, TO, expected, 42) check_force_cast(FROM, TO, expected, -42) - expected.append('int_return %i' + str(len(expected))) - expected = '\n'.join(expected) + returnvar = "%i" + str(len(expected)) + expected.append('int_return ' + returnvar) + expectedstr = '\n'.join(expected) # def f(n): return rffi.cast(TO, n) - self.encoding_test(f, [rffi.cast(FROM, 42)], expected, + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + + if not longlong.is_64_bit: + if FROM in (rffi.LONG, rffi.ULONG): + if FROM == rffi.LONG: + FROM = rffi.LONGLONG + else: + FROM = rffi.ULONGLONG + expected.insert(0, + "residual_call_irf_i $<* fn llong_to_int>, , I[], R[], F[%f0] -> %i0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + elif TO in (rffi.LONG, rffi.ULONG): + if TO == rffi.LONG: + TO = rffi.LONGLONG + else: + TO = rffi.ULONGLONG + if rffi.cast(FROM, -1) < 0: + fnname = "llong_from_int" + else: + fnname = "llong_from_uint" + expected.pop() # remove int_return + expected.append( + "residual_call_irf_f $<* fn %s>, , I[%s], R[], F[] -> %%f0" + % (fnname, returnvar)) + expected.append("float_return %f0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, transform=True) def test_force_cast_pointer(self): @@ -813,6 +854,23 @@ int_return %i0 """, transform=True) + def test_force_cast_float(self): + from pypy.rpython.lltypesystem import rffi + def f(n): + return rffi.cast(lltype.Float, n) + self.encoding_test(f, [12.456], """ + float_return %f0 + """, transform=True) + + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py --- a/pypy/jit/codewriter/test/test_longlong.py +++ b/pypy/jit/codewriter/test/test_longlong.py @@ -37,7 +37,7 @@ class TestLongLong: def setup_class(cls): - if sys.maxint > 2147483647: + if longlong.is_64_bit: py.test.skip("only for 32-bit platforms") def do_check(self, opname, oopspecindex, ARGS, RESULT): @@ -46,6 +46,8 @@ op = SpaceOperation(opname, vlist, v_result) tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) op1 = tr.rewrite_operation(op) + if isinstance(op1, list): + [op1] = op1 # def is_llf(TYPE): return (TYPE == lltype.SignedLongLong or @@ -196,6 +198,23 @@ for T2 in [lltype.Signed, lltype.Unsigned]: self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT, [T1], T2) + self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT, + [T1], T2) + if T2 == lltype.Signed: + expected = EffectInfo.OS_LLONG_FROM_INT + else: + expected = EffectInfo.OS_LLONG_FROM_UINT + self.do_check('cast_primitive', expected, [T2], T1) + self.do_check('force_cast', expected, [T2], T1) + # + for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + vlist = [varoftype(T1)] + v_result = varoftype(T2) + op = SpaceOperation('force_cast', vlist, v_result) + tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) + op1 = tr.rewrite_operation(op) + assert op1 is None def test_constants(self): for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]: diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -3916,11 +3916,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3941,9 +3938,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3962,10 +3957,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -3987,14 +3981,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -4010,10 +3999,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4131,9 +4118,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -4178,11 +4163,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4374,11 +4356,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -4532,6 +4511,25 @@ """ self.optimize_loop(ops, expected) + def test_strslice_with_other_stuff(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5082,11 +5082,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5107,9 +5104,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5128,10 +5123,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5153,14 +5147,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -5176,10 +5165,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5303,9 +5290,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -5411,11 +5396,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5609,11 +5591,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -21,7 +21,7 @@ continue if hasattr(Class, name_prefix + name): opclass = resoperation.opclasses[getattr(rop, name)] - print value, name, opclass + assert name in opclass.__name__ result.append((value, opclass, getattr(Class, name_prefix + name))) return unrolling_iterable(result) diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -61,7 +61,7 @@ self.ensure_nonnull() box = self.force_box() lengthbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) + optimization.optimize_default(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -72,13 +72,13 @@ else: return None - def string_copy_parts(self, optimization, targetbox, offsetbox, mode): + def string_copy_parts(self, optimizer, targetbox, offsetbox, mode): # Copies the pointer-to-string 'self' into the target string # given by 'targetbox', at the specified offset. Returns the offset # at the end of the copy. - lengthbox = self.getstrlen(optimization, mode) + lengthbox = self.getstrlen(optimizer, mode) srcbox = self.force_box() - return copy_str_content(optimization, srcbox, targetbox, + return copy_str_content(optimizer, srcbox, targetbox, CONST_0, offsetbox, lengthbox, mode) @@ -335,7 +335,7 @@ if optimizer is None: return None resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_ADD, [box1, box2], resbox)) return resbox def _int_sub(optimizer, box1, box2): @@ -345,10 +345,10 @@ if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimization, strbox, indexbox, mode): +def _strgetitem(optimizer, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimizer.optimize_default(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,7 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) + resbox = _strgetitem(self.optimizer, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): @@ -450,7 +450,7 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode) + lengthbox = value.getstrlen(self.optimizer, mode) self.make_equal_to(op.result, self.getvalue(lengthbox)) def optimize_CALL(self, op): diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -310,26 +310,27 @@ self.opimpl_goto_if_not(condbox, target) ''' % (_opimpl, _opimpl.upper())).compile() + + def _establish_nullity(self, box, orgpc): + value = box.nonnull() + if value: + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc) + else: + if not isinstance(box, Const): + self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + promoted_box = box.constbox() + self.metainterp.replace_box(box, promoted_box) + return value + @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_nonzero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if not value: + if not self._establish_nullity(box, orgpc): self.pc = target @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_iszero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if value: + if self._establish_nullity(box, orgpc): self.pc = target @arguments("box", "box", "box") @@ -364,7 +365,9 @@ def opimpl_new_with_vtable(self, sizedescr): cpu = self.metainterp.cpu cls = heaptracker.descr2vtable(cpu, sizedescr) - return self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + resbox = self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + self.metainterp.known_class_boxes[resbox] = None + return resbox ## @FixME #arguments("box") ## def opimpl_runtimenew(self, classbox): @@ -845,7 +848,9 @@ @arguments("orgpc", "box") def opimpl_guard_class(self, orgpc, box): clsbox = self.cls_of_box(box) + if box not in self.metainterp.known_class_boxes: self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + self.metainterp.known_class_boxes[box] = None return clsbox @arguments("int", "orgpc") @@ -1449,6 +1454,8 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1789,6 +1796,8 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -281,9 +281,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -984,11 +984,14 @@ pass class B(A): pass + @dont_look_inside + def extern(n): + if n: + return A() + else: + return B() def fn(n): - if n: - obj = A() - else: - obj = B() + obj = extern(n) return isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res @@ -1021,6 +1024,70 @@ res = self.meta_interp(main, []) assert res == 55 + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + def test_assert_isinstance(self): class A: pass diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -337,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -186,6 +186,11 @@ mod = self.get_ast("from __future__ import with_statement; import y; " \ "from __future__ import nested_scopes") raises(SyntaxError, compile, mod, "", "exec") + mod = self.get_ast("from __future__ import division\nx = 1/2") + co = compile(mod, "", "exec") + ns = {} + exec co in ns + assert ns["x"] == .5 def test_field_attr_writable(self): import _ast as ast diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -149,6 +149,12 @@ raise OperationError(space.w_TypeError, space.wrap(msg)) return res +def unwrap_truncate_int(TP, space, w_arg): + if space.is_true(space.isinstance(w_arg, space.w_int)): + return rffi.cast(TP, space.int_w(w_arg)) + else: + return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask()) +unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)' # ======================================================================== @@ -181,15 +187,14 @@ # note that we must check for longlong first, because either # is_signed or is_unsigned returns true anyway assert libffi.IS_32_BIT - kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind - self.arg_longlong(space, argchain, kind, w_arg) + self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): - argchain.arg(space.int_w(w_arg)) + argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) elif w_argtype.is_unsigned(): - argchain.arg(intmask(space.uint_w(w_arg))) + argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg)) elif w_argtype.is_char(): w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) @@ -220,15 +225,10 @@ return w_arg @jit.dont_look_inside - def arg_longlong(self, space, argchain, kind, w_arg): + def arg_longlong(self, space, argchain, w_arg): bigarg = space.bigint_w(w_arg) - if kind == 'I': - llval = bigarg.tolonglong() - elif kind == 'U': - ullval = bigarg.toulonglong() + ullval = bigarg.ulonglongmask() llval = rffi.cast(rffi.LONGLONG, ullval) - else: - assert False # this is a hack: we store the 64 bits of the long long into the # 64 bits of a float (i.e., a C double) floatval = libffi.longlong2float(llval) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -111,7 +111,6 @@ types.double) assert pow(2, 3) == 8 - def test_int_args(self): """ DLLEXPORT int sum_xy(int x, int y) @@ -119,10 +118,12 @@ return x+y; } """ + import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint) assert sum_xy(30, 12) == 42 + assert sum_xy(sys.maxint*2, 0) == -2 def test_void_result(self): """ @@ -247,6 +248,9 @@ types.ulong) assert sum_xy(sys.maxint, 12) == sys.maxint+12 assert sum_xy(sys.maxint+1, 12) == sys.maxint+13 + # + res = sum_xy(sys.maxint*2+3, 0) + assert res == 1 def test_unsigned_short_args(self): """ @@ -375,6 +379,9 @@ res = sum_xy(x, y) expected = maxint64 + 3 assert res == expected + # + res = sum_xy(maxint64*2+3, 0) + assert res == 1 def test_byval_argument(self): """ diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -43,11 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -57,6 +57,11 @@ def __del__(self): self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + + def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -10,7 +10,7 @@ class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 @@ -23,8 +23,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,11 +120,8 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: + assert isinstance(w_self, W_WeakrefBase) w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) def descr__repr__(self, space): w_obj = self.dereference() diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -572,10 +572,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -22,7 +22,7 @@ def PySequence_Check(space, w_obj): """Return 1 if the object provides sequence protocol, and 0 otherwise. This function always succeeds.""" - return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None) + return int(space.issequence_w(w_obj)) @cpython_api([PyObject], Py_ssize_t, error=-1) def PySequence_Size(space, w_obj): diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -10,6 +10,7 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + 'fromstring': 'interp_support.fromstring', # ufuncs 'abs': 'interp_ufuncs.absolute', diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib import jit @@ -7,7 +7,6 @@ from pypy.tool.sourcetools import func_with_new_name import math - def dummy1(v): assert isinstance(v, float) return v @@ -20,6 +19,8 @@ numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) +all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) class Signature(object): def __init__(self): @@ -45,10 +46,14 @@ return v1 * v2 def div(v1, v2): return v1 / v2 -def pow(v1, v2): +def power(v1, v2): return math.pow(v1, v2) def mod(v1, v2): return math.fmod(v1, v2) +def maximum(v1, v2): + return max(v1, v2) +def minimum(v1, v2): + return min(v1, v2) class BaseArray(Wrappable): def __init__(self): @@ -82,8 +87,8 @@ def _binop_impl(function): signature = Signature() def impl(self, space, w_other): + w_other = convert_to_array(space, w_other) new_sig = self.signature.transition(signature) - if isinstance(w_other, BaseArray): res = Call2( function, self, @@ -91,14 +96,6 @@ new_sig.transition(w_other.signature) ) w_other.invalidates.append(res) - else: - w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) self.invalidates.append(res) return space.wrap(res) return func_with_new_name(impl, "binop_%s_impl" % function.__name__) @@ -107,9 +104,137 @@ descr_sub = _binop_impl(sub) descr_mul = _binop_impl(mul) descr_div = _binop_impl(div) - descr_pow = _binop_impl(pow) + descr_pow = _binop_impl(power) descr_mod = _binop_impl(mod) + def _binop_right_impl(function): + signature = Signature() + def impl(self, space, w_other): + new_sig = self.signature.transition(signature) + w_other = FloatWrapper(space.float_w(w_other)) + res = Call2( + function, + w_other, + self, + new_sig.transition(w_other.signature) + ) + self.invalidates.append(res) + return space.wrap(res) + return func_with_new_name(impl, + "binop_right_%s_impl" % function.__name__) + + descr_radd = _binop_right_impl(add) + descr_rsub = _binop_right_impl(sub) + descr_rmul = _binop_right_impl(mul) + descr_rdiv = _binop_right_impl(div) + descr_rpow = _binop_right_impl(power) + descr_rmod = _binop_right_impl(mod) + + def _reduce_sum_prod_impl(function, init): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + return space.wrap(loop(self, init, self.find_size())) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_max_min_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, result, size): + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, self.eval(0), size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_argmax_argmin_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self', 'cur_best']) + def loop(self, size): + result = 0 + cur_best = self.eval(0) + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result, cur_best=cur_best) + new_best = function(cur_best, self.eval(i)) + if new_best != cur_best: + result = i + cur_best = new_best + i += 1 + return result + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, size)) + return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) + + def _all(self): + size = self.find_size() + i = 0 + while i < size: + all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if not self.eval(i): + return False + i += 1 + return True + def descr_all(self, space): + return space.wrap(self._all()) + + def _any(self): + size = self.find_size() + i = 0 + while i < size: + any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if self.eval(i): + return True + i += 1 + return False + def descr_any(self, space): + return space.wrap(self._any()) + + descr_sum = _reduce_sum_prod_impl(add, 0.0) + descr_prod = _reduce_sum_prod_impl(mul, 1.0) + descr_max = _reduce_max_min_impl(maximum) + descr_min = _reduce_max_min_impl(minimum) + descr_argmax = _reduce_argmax_argmin_impl(maximum) + descr_argmin = _reduce_argmax_argmin_impl(minimum) + + def descr_dot(self, space, w_other): + if isinstance(w_other, BaseArray): + w_res = self.descr_mul(space, w_other) + assert isinstance(w_res, BaseArray) + return w_res.descr_sum(space) + else: + return self.descr_mul(space, w_other) + def get_concrete(self): raise NotImplementedError @@ -136,13 +261,17 @@ return self.get_concrete().descr_setitem(space, item, value) def descr_mean(self, space): - s = 0 - concrete = self.get_concrete() - size = concrete.find_size() - for i in xrange(size): - s += concrete.getitem(i) - return space.wrap(s / size) + return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) +def convert_to_array (space, w_obj): + if isinstance(w_obj, BaseArray): + return w_obj + elif space.issequence_w(w_obj): + # Convert to array. + return new_numarray(space, w_obj) + else: + # If it's a scalar + return FloatWrapper(space.float_w(w_obj)) class FloatWrapper(BaseArray): """ @@ -350,14 +479,17 @@ def __del__(self): lltype.free(self.storage, flavor='raw') -def descr_new_numarray(space, w_type, w_size_or_iterable): +def new_numarray(space, w_size_or_iterable): l = space.listview(w_size_or_iterable) arr = SingleDimArray(len(l)) i = 0 for w_elem in l: arr.storage[i] = space.float_w(space.float(w_elem)) i += 1 - return space.wrap(arr) + return arr + +def descr_new_numarray(space, w_type, w_size_or_iterable): + return space.wrap(new_numarray(space, w_size_or_iterable)) @unwrap_spec(size=int) def zeros(space, size): @@ -389,6 +521,21 @@ __div__ = interp2app(BaseArray.descr_div), __pow__ = interp2app(BaseArray.descr_pow), __mod__ = interp2app(BaseArray.descr_mod), + __radd__ = interp2app(BaseArray.descr_radd), + __rsub__ = interp2app(BaseArray.descr_rsub), + __rmul__ = interp2app(BaseArray.descr_rmul), + __rdiv__ = interp2app(BaseArray.descr_rdiv), + __rpow__ = interp2app(BaseArray.descr_rpow), + __rmod__ = interp2app(BaseArray.descr_rmod), mean = interp2app(BaseArray.descr_mean), + sum = interp2app(BaseArray.descr_sum), + prod = interp2app(BaseArray.descr_prod), + max = interp2app(BaseArray.descr_max), + min = interp2app(BaseArray.descr_min), + argmax = interp2app(BaseArray.descr_argmax), + argmin = interp2app(BaseArray.descr_argmin), + all = interp2app(BaseArray.descr_all), + any = interp2app(BaseArray.descr_any), + dot = interp2app(BaseArray.descr_dot), ) diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_support.py @@ -0,0 +1,32 @@ + +from pypy.rlib.rstruct.runpack import runpack +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.error import OperationError +from pypy.module.micronumpy.interp_numarray import SingleDimArray + +FLOAT_SIZE = rffi.sizeof(lltype.Float) + + at unwrap_spec(s=str) +def fromstring(space, s): + length = len(s) + + if length % FLOAT_SIZE == 0: + number = length/FLOAT_SIZE + else: + raise OperationError(space.w_ValueError, space.wrap( + "string length %d not divisable by %d" % (length, FLOAT_SIZE))) + + a = SingleDimArray(number) + + start = 0 + end = FLOAT_SIZE + i = 0 + while i < number: + part = s[start:end] + a.storage[i] = runpack('d', part) + i += 1 + start += FLOAT_SIZE + end += FLOAT_SIZE + + return space.wrap(a) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,30 +1,34 @@ import math from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature +from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name - def ufunc(func): signature = Signature() def impl(space, w_obj): - if isinstance(w_obj, BaseArray): - w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) - w_obj.invalidates.append(w_res) + if space.issequence_w(w_obj): + w_obj_arr = convert_to_array(space, w_obj) + w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) + w_obj_arr.invalidates.append(w_res) return w_res + else: return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): - if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): - new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) - w_res = Call2(func, w_lhs, w_rhs, new_sig) - w_lhs.invalidates.append(w_res) - w_rhs.invalidates.append(w_res) + if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): + w_lhs_arr = convert_to_array(space, w_lhs) + w_rhs_arr = convert_to_array(space, w_rhs) + new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature) + w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig) + w_lhs_arr.invalidates.append(w_res) + w_rhs_arr.invalidates.append(w_res) return w_res + else: return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -1,12 +1,10 @@ from pypy.conftest import gettestobjspace from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper - class BaseNumpyAppTest(object): def setup_class(cls): cls.space = gettestobjspace(usemodules=('micronumpy',)) - class TestSignature(object): def test_binop_signature(self, space): ar = SingleDimArray(10) @@ -26,4 +24,4 @@ v3 = ar.descr_add(space, v1) v4 = ar.descr_add(space, v2) - assert v3.signature is v4.signature \ No newline at end of file + assert v3.signature is v4.signature diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1,6 +1,7 @@ import py from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest +from pypy.conftest import gettestobjspace class AppTestNumArray(BaseNumpyAppTest): @@ -96,6 +97,15 @@ for i in range(5): assert b[i] == i + 5 + def test_add_list(self): + from numpy import array + a = array(range(5)) + b = list(reversed(range(5))) + c = a + b + assert isinstance(c, array) + for i in range(5): + assert c[i] == 4 + def test_subtract(self): from numpy import array a = array(range(5)) @@ -276,7 +286,97 @@ assert d[1] == 12 def test_mean(self): - from numpy import array, mean + from numpy import array a = array(range(5)) assert a.mean() == 2.0 assert a[:4].mean() == 1.5 + + def test_sum(self): + from numpy import array + a = array(range(5)) + assert a.sum() == 10.0 + assert a[:4].sum() == 6.0 + + def test_prod(self): + from numpy import array + a = array(range(1,6)) + assert a.prod() == 120.0 + assert a[:4].prod() == 24.0 + + def test_max(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.max() == 5.7 + b = array([]) + raises(ValueError, "b.max()") + + def test_max_add(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert (a+a).max() == 11.4 + + def test_min(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.min() == -3.0 + b = array([]) + raises(ValueError, "b.min()") + + def test_argmax(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmax() == 2 + b = array([]) + raises(ValueError, "b.argmax()") + + def test_argmin(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmin() == 3 + b = array([]) + raises(ValueError, "b.argmin()") + + def test_all(self): + from numpy import array + a = array(range(5)) + assert a.all() == False + a[0] = 3.0 + assert a.all() == True + b = array([]) + assert b.all() == True + + def test_any(self): + from numpy import array, zeros + a = array(range(5)) + assert a.any() == True + b = zeros(5) + assert b.any() == False + c = array([]) + assert c.any() == False + + def test_dot(self): + from numpy import array + a = array(range(5)) + assert a.dot(a) == 30.0 + + def test_dot_constant(self): + from numpy import array + a = array(range(5)) + b = a.dot(2.5) + for i in xrange(5): + assert b[i] == 2.5*a[i] + + +class AppTestSupport(object): + def setup_class(cls): + import struct + cls.space = gettestobjspace(usemodules=('micronumpy',)) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + + def test_fromstring(self): + from numpy import fromstring + a = fromstring(self.data) + for i in range(4): + assert a[i] == i + 1 + raises(ValueError, fromstring, "abc") + diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -10,6 +10,40 @@ assert sign(-0.0) == 0.0 assert minimum(2.0, 3.0) == 2.0 + def test_sequence(self): + from numpy import array, negative, minimum + a = array(range(3)) + b = [2.0, 1.0, 0.0] + c = 1.0 + b_neg = negative(b) + assert isinstance(b_neg, array) + for i in range(3): + assert b_neg[i] == -b[i] + min_a_b = minimum(a, b) + assert isinstance(min_a_b, array) + for i in range(3): + assert min_a_b[i] == min(a[i], b[i]) + min_b_a = minimum(b, a) + assert isinstance(min_b_a, array) + for i in range(3): + assert min_b_a[i] == min(a[i], b[i]) + min_a_c = minimum(a, c) + assert isinstance(min_a_c, array) + for i in range(3): + assert min_a_c[i] == min(a[i], c) + min_c_a = minimum(c, a) + assert isinstance(min_c_a, array) + for i in range(3): + assert min_c_a[i] == min(a[i], c) + min_b_c = minimum(b, c) + assert isinstance(min_b_c, array) + for i in range(3): + assert min_b_c[i] == min(b[i], c) + min_c_b = minimum(c, b) + assert isinstance(min_c_b, array) + for i in range(3): + assert min_c_b[i] == min(b[i], c) + def test_negative(self): from numpy import array, negative diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -4,9 +4,20 @@ FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile +from pypy.rlib.objectmodel import specialize class FakeSpace(object): - pass + w_ValueError = None + + def issequence_w(self, w_obj): + return True + + @specialize.argtype(1) + def wrap(self, w_obj): + return w_obj + + def float_w(self, w_obj): + return float(w_obj) class TestNumpyJIt(LLJitMixin): def setup_class(cls): @@ -51,6 +62,110 @@ assert result == f(5) + def test_sum(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_sum(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 2, + "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_prod(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_prod(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_max(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_max(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_gt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, + "guard_false": 1, "jump": 1}) + + def test_min(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_min(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_argmin(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_argmin(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + + def test_all(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = 1.0 + j += 1 + return ar.descr_add(space, ar).descr_all(space) + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, + "int_lt": 1, "guard_true": 2, "jump": 1}) + + def test_any(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_any(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, "guard_false": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + def test_already_forecd(self): def f(i): ar = SingleDimArray(i) diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -19,7 +19,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) + guard_true(i7, descr=...) i9 = int_add(i5, 1) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) @@ -39,11 +39,12 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated(descr=...) i13 = int_lt(i7, i9) - guard_true(i13, descr=) + guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = int_add(i7, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) @@ -68,16 +69,17 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i13 = int_lt(i8, 307200) - guard_true(i13, descr=) + guard_true(i13, descr=...) + guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) # on 64bit, there is a guard checking that i19 actually fits into 32bit ... setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -80,19 +80,19 @@ # assert entry_bridge.match_by_id('call', """ p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) + guard_nonnull_class(p29, ConstClass(Function), descr=...) p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) + guard_value(p33, ConstPtr(ptr34), descr=...) p35 = getfield_gc(p29, descr=) p36 = getfield_gc(p29, descr=) p38 = call(ConstClass(getexecutioncontext), descr=) p39 = getfield_gc(p38, descr=) i40 = force_token() p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) + guard_isnull(p41, descr=...) i42 = getfield_gc(p38, descr=) i43 = int_is_zero(i42) - guard_true(i43, descr=) + guard_true(i43, descr=...) i50 = force_token() """) # @@ -101,16 +101,16 @@ loop, = log.loops_by_id('call') assert loop.match(""" i12 = int_lt(i5, i6) - guard_true(i12, descr=) + guard_true(i12, descr=...) i13 = force_token() i15 = int_add(i5, 1) i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) """) @@ -146,14 +146,14 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i15 = int_lt(i6, i9) - guard_true(i15, descr=) - guard_not_invalidated(descr=) + guard_true(i15, descr=...) + guard_not_invalidated(descr=...) i16 = force_token() i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) """) @@ -180,11 +180,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) - guard_not_invalidated(descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = force_token() i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() --TICK-- jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) @@ -281,25 +281,23 @@ loop0, = log.loops_by_id('g1') assert loop0.match_by_id('g1', """ i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('h1', """ i20 = force_token() i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('g2', """ i27 = force_token() i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) # loop1, = log.loops_by_id('g3') assert loop1.match_by_id('g3', """ i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) guard_no_overflow(descr=...) """) @@ -352,7 +350,7 @@ i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) p17 = getfield_gc(p8, descr=) p19 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p19, i12, descr=) @@ -404,9 +402,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i10 = int_lt(i5, i6) - guard_true(i10, descr=) + guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i120 = int_add(i5, 1) - guard_not_invalidated(descr=) --TICK-- jump(..., descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py --- a/pypy/module/pypyjit/test_pypy_c/test_exception.py +++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py @@ -36,11 +36,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i5 = int_is_true(i3) - guard_true(i5, descr=) - guard_not_invalidated(descr=) + guard_true(i5, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -84,8 +84,8 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i4, i5) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i14 = int_add(i4, 1) --TICK-- diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -0,0 +1,30 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGlobals(BaseTestPyPyC): + def test_load_builtin(self): + def main(n): + import pypyjit + + i = 0 + while i < n: + l = len # ID: loadglobal + i += pypyjit.residual_call(l, "a") + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("loadglobal", """ + p10 = getfield_gc(p0, descr=) + guard_value(p10, ConstPtr(ptr11), descr=...) + p12 = getfield_gc(p10, descr=) + guard_value(p12, ConstPtr(ptr13), descr=...) + p15 = getfield_gc(ConstPtr(ptr14), descr=) + guard_isnull(p15, descr=...) + guard_not_invalidated(descr=...) + p19 = getfield_gc(ConstPtr(p17), descr=) + guard_value(p19, ConstPtr(ptr20), descr=...) + p22 = getfield_gc(ConstPtr(ptr21), descr=) + guard_nonnull(p22, descr=...) + """) \ No newline at end of file diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py --- a/pypy/module/pypyjit/test_pypy_c/test_import.py +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -15,13 +15,13 @@ assert log.result == 500 loop, = log.loops_by_id('import') assert loop.match_by_id('import', """ + guard_not_invalidated(descr=...) p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) + guard_value(p11, ConstPtr(ptr12), descr=...) p14 = getfield_gc(ConstPtr(ptr13), descr=) p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) + guard_value(p14, ConstPtr(ptr17), descr=...) + guard_isnull(p16, descr=...) """) def test_import_fast_path(self, tmpdir): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -22,10 +22,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) """) @@ -47,10 +47,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = int_lt(i5, i6) - guard_true(i9, descr=) - guard_not_invalidated(descr=) + guard_true(i9, descr=...) + guard_not_invalidated(descr=...) i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -17,6 +17,7 @@ assert loop.match(""" i7 = int_lt(i4, 300) guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 3000) guard_no_overflow(descr=...) i11 = int_add(i4, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -84,7 +84,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = float_lt(f5, f7) - guard_true(i9, descr=) + guard_true(i9, descr=...) f10 = float_add(f8, f5) --TICK-- jump(p0, p1, p2, p3, p4, f10, p6, f7, f8, descr=) @@ -107,19 +107,19 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i11, i12) - guard_false(i16, descr=) + guard_false(i16, descr=...) i17 = int_mul(i11, i14) i18 = int_add(i15, i17) i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=) + guard_not_invalidated(descr=...) i23 = int_lt(i18, 0) - guard_false(i23, descr=) + guard_false(i23, descr=...) i25 = int_ge(i18, i9) - guard_false(i25, descr=) + guard_false(i25, descr=...) i27 = int_add_ovf(i7, i18) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -164,20 +164,20 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i12, i13) - guard_false(i16, descr=) + guard_false(i16, descr=...) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) - guard_nonnull_class(p17, 146982464, descr=) + guard_nonnull_class(p17, 146982464, descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) - guard_true(i23, descr=) + guard_true(i23, descr=...) i24 = getfield_gc(p17, descr=) i25 = getarrayitem_raw(i24, 0, descr=<.*>) i27 = int_lt(1, i21) - guard_false(i27, descr=) + guard_false(i27, descr=...) i28 = int_add_ovf(i10, i25) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) @@ -201,9 +201,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i11 = int_lt(i7, 300) - guard_true(i11, descr=) + guard_true(i11, descr=...) i12 = int_add_ovf(i8, i9) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i14 = int_add(i7, 1) --TICK-- jump(..., descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -16,27 +16,92 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = int_mod(i6, i10) i17 = int_rshift(i15, 63) i18 = int_and(i10, i17) i19 = int_add(i15, i18) i21 = int_lt(i19, 0) - guard_false(i21, descr=) + guard_false(i21, descr=...) i22 = int_ge(i19, i10) - guard_false(i22, descr=) + guard_false(i22, descr=...) i23 = strgetitem(p11, i19) i24 = int_ge(i19, i12) - guard_false(i24, descr=) + guard_false(i24, descr=...) i25 = unicodegetitem(p13, i19) - guard_not_invalidated(descr=) p27 = newstr(1) strsetitem(p27, 0, i23) p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) - guard_true(i32, descr=) + guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) + """) + + def test_long(self): + def main(n): + import string + i = 1 + while i < n: + i += int(long(string.digits[i % len(string.digits)], 16)) + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i13 = int_eq(i6, -9223372036854775808) + guard_false(i13, descr=...) + i15 = int_mod(i6, i8) + i17 = int_rshift(i15, 63) + i18 = int_and(i8, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i8) + guard_false(i22, descr=...) + i23 = strgetitem(p10, i19) + p25 = newstr(1) + strsetitem(p25, 0, i23) + p28 = call(ConstClass(strip_spaces), p25, descr=) + guard_no_exception(descr=...) + i29 = strlen(p28) + i30 = int_is_true(i29) + guard_true(i30, descr=...) + i32 = int_sub(i29, 1) + i33 = strgetitem(p28, i32) + i35 = int_eq(i33, 108) + guard_false(i35, descr=...) + i37 = int_eq(i33, 76) + guard_false(i37, descr=...) + i39 = strgetitem(p28, 0) + i41 = int_eq(i39, 45) + guard_false(i41, descr=...) + i43 = int_eq(i39, 43) + guard_false(i43, descr=...) + i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=) + guard_false(i43, descr=...) + i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=) + guard_false(i46, descr=...) + p51 = new_with_vtable(21136408) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, i29, descr=) + setfield_gc(p51, 1, descr=) + setfield_gc(p51, 16, descr=) + setfield_gc(p51, p28, descr=) + p55 = call(ConstClass(parse_digit_string), p51, descr=) + guard_no_exception(descr=...) + i57 = call(ConstClass(rbigint.toint), p55, descr=) + guard_no_exception(descr=...) + i58 = int_add_ovf(i6, i57) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) """) \ No newline at end of file diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ CPYTHON_VERSION = (2, 7, 1, "final", 42) #XXX # sync patchlevel.h CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (1, 5, 0, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (1, 6, 0, "dev", 1) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -132,6 +132,16 @@ # You cannot assing character format codes as restype any longer raises(TypeError, setattr, f, "restype", "i") + + def test_truncate_python_longs(self): + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_int + x = sys.maxint * 2 + result = f(x, x, x, x, 0, 0) + assert result == -8 + + def test_floatresult(self): f = dll._testfunc_f_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] @@ -411,6 +421,23 @@ result = f("abcd", ord("b")) assert result == "bcd" + def test_keepalive_buffers(self, monkeypatch): + import gc + f = dll.my_strchr + f.argtypes = [c_char_p] + f.restype = c_char_p + # + orig__call_funcptr = f._call_funcptr + def _call_funcptr(funcptr, *newargs): + gc.collect() + gc.collect() + gc.collect() + return orig__call_funcptr(funcptr, *newargs) + monkeypatch.setattr(f, '_call_funcptr', _call_funcptr) + # + result = f("abcd", ord("b")) + assert result == "bcd" + def test_caching_bug_1(self): # the same test as test_call_some_args, with two extra lines # in the middle that trigger caching in f._ptr, which then diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py @@ -12,7 +12,7 @@ from _ctypes.function import CFuncPtr def guess(value): - cobj, ctype = CFuncPtr._conv_param(None, value) + _, cobj, ctype = CFuncPtr._conv_param(None, value) return ctype ## cobj = CFuncPtr._conv_param(None, value) ## return type(cobj) diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -21,6 +21,7 @@ 'RPyThreadAcquireLock', 'RPyThreadReleaseLock', 'RPyThreadYield', 'RPyThreadGetStackSize', 'RPyThreadSetStackSize', + 'RPyOpaqueDealloc_ThreadLock', 'RPyThreadAfterFork'] ) @@ -52,6 +53,9 @@ c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], rffi.INT, threadsafe=False) # may add in a global list +c_thread_lock_dealloc = llexternal('RPyOpaqueDealloc_ThreadLock', [TLOCKP], + lltype.Void, + threadsafe=True) c_thread_acquirelock = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT], rffi.INT, threadsafe=True) # release the GIL @@ -156,6 +160,9 @@ return ll_lock def free_ll_lock(ll_lock): + c_thread_acquirelock(ll_lock, 0) + c_thread_releaselock(ll_lock) + c_thread_lock_dealloc(ll_lock) lltype.free(ll_lock, flavor='raw', track_allocation=False) def acquire_NOAUTO(ll_lock, flag): diff --git a/pypy/module/thread/test/test_import_lock.py b/pypy/module/thread/test/test_import_lock.py --- a/pypy/module/thread/test/test_import_lock.py +++ b/pypy/module/thread/test/test_import_lock.py @@ -66,6 +66,9 @@ def test_lock(self, space, monkeypatch): from pypy.module.imp.importing import getimportlock, importhook + # Force importing the module _file now + space.builtin.get('file') + # Monkeypatch the import lock and add a counter importlock = getimportlock(space) original_acquire = importlock.acquire_lock diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -736,6 +736,8 @@ class W_DictMultiIterObject(W_Object): from pypy.objspace.std.dicttype import dictiter_typedef as typedef + _immutable_fields_ = ["iteratorimplementation", "itertype"] + def __init__(w_self, space, iteratorimplementation, itertype): w_self.space = space w_self.iteratorimplementation = iteratorimplementation diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -431,12 +431,17 @@ return None assert isinstance(lifeline, WeakrefLifeline) return lifeline + getweakref._cannot_really_call_random_things_ = True def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline - assert (isinstance(weakreflifeline, WeakrefLifeline) or - weakreflifeline is None) + assert isinstance(weakreflifeline, WeakrefLifeline) self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + setweakref._cannot_really_call_random_things_ = True + + def delweakref(self): + self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + delweakref._cannot_really_call_random_things_ = True class ObjectMixin(object): _mixin_ = True diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -36,6 +36,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None class W_SetObject(W_BaseSetObject): from pypy.objspace.std.settype import set_typedef as typedef diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -171,7 +171,7 @@ obj = c.instantiate() assert obj.getweakref() is None obj.setweakref(space, lifeline1) - obj.setweakref(space, None) + obj.delweakref() diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -532,6 +532,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None # ____________________________________________________________ # Initialization of type objects diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -482,6 +482,13 @@ key[2:]) cache[key] = s_value + # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass) + try: + graph = self.bookkeeper.position_key[0] + graph.func._dont_reach_me_in_del_ = True + except (TypeError, AttributeError): + pass + return annmodel.s_None def annotate_hooks(self, **kwds_s): diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -83,6 +83,9 @@ t, rtyper, fngraph = self.gengraph(fn, [int]) + # added by compute_result_annotation() + assert fn._dont_reach_me_in_del_ == True + def getargs(func): for graph in t.graphs: if getattr(graph, 'func', None) is func: diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -172,17 +172,6 @@ assert max_n >= 0 ITEM = A.OF ctypes_item = get_ctypes_type(ITEM, delayed_builders) - # Python 2.5 ctypes can raise OverflowError on 64-bit builds - for n in [sys.maxint, 2**31]: - MAX_SIZE = n/64 - try: - PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item) - except OverflowError, e: - pass - else: - break - else: - raise e class CArray(ctypes.Structure): if not A._hints.get('nolength'): @@ -191,6 +180,7 @@ else: _fields_ = [('items', max_n * ctypes_item)] + @classmethod def _malloc(cls, n=None): if not isinstance(n, int): raise TypeError, "array length must be an int" @@ -199,10 +189,29 @@ if hasattr(bigarray, 'length'): bigarray.length = n return bigarray - _malloc = classmethod(_malloc) + + _ptrtype = None + + @classmethod + def _get_ptrtype(cls): + if cls._ptrtype: + return cls._ptrtype + # ctypes can raise OverflowError on 64-bit builds + for n in [sys.maxint, 2**31]: + cls.MAX_SIZE = n/64 + try: + cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item) + except OverflowError, e: + pass + else: + break + else: + raise e + return cls._ptrtype def _indexable(self, index): - assert index + 1 < MAX_SIZE + PtrType = self._get_ptrtype() + assert index + 1 < self.MAX_SIZE p = ctypes.cast(ctypes.pointer(self.items), PtrType) return p.contents diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py --- a/pypy/rpython/lltypesystem/rclass.py +++ b/pypy/rpython/lltypesystem/rclass.py @@ -400,6 +400,7 @@ assert len(s_func.descriptions) == 1 funcdesc, = s_func.descriptions graph = funcdesc.getuniquegraph() + self.check_graph_of_del_does_not_call_too_much(graph) FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void) destrptr = functionptr(FUNCTYPE, graph.name, graph=graph, diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -486,6 +486,11 @@ return True + def ll_startswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[0] == ch + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) @@ -503,6 +508,11 @@ return True + def ll_endswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[len(s.chars) - 1] == ch + @elidable def ll_find_char(s, ch, start, end): i = start diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -671,7 +671,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_arrayofstruct(self): - S1 = lltype.Struct('S1', ('x', lltype.Signed)) + S1 = lltype.Struct('S2', ('x', lltype.Signed)) A = lltype.Array(S1, hints={'nolength': True}) a = lltype.malloc(A, 5, flavor='raw') a[0].x = 100 diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -256,10 +256,6 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - class Cls(self.AddressStack): - def append(self2, addr): - assert addr not in self2.tolist() - self.AddressStack.append(self2, addr) self.objects_pointing_to_young = self.AddressStack() # # Similar to 'objects_pointing_to_young', but lists objects diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -525,6 +525,7 @@ def test_writebarrier_before_copy(self): from pypy.rpython.memory.gc import minimark largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 p_src = self.malloc(VAR, largeobj_size) p_dst = self.malloc(VAR, largeobj_size) # make them old @@ -564,6 +565,7 @@ from pypy.rpython.memory.gc import minimark tid = self.get_type_id(VAR) largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 addr_src = self.gc.external_malloc(tid, largeobj_size) addr_dst = self.gc.external_malloc(tid, largeobj_size) hdr_src = self.gc.header(addr_src) diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -433,7 +433,9 @@ "ll_streq": Meth([self.SELFTYPE_T], Bool), "ll_strcmp": Meth([self.SELFTYPE_T], Signed), "ll_startswith": Meth([self.SELFTYPE_T], Bool), + "ll_startswith_char": Meth([self.CHAR], Bool), "ll_endswith": Meth([self.SELFTYPE_T], Bool), + "ll_endswith_char": Meth([self.CHAR], Bool), "ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed), @@ -1429,10 +1431,18 @@ # NOT_RPYTHON return self._str.startswith(s._str) + def ll_startswith_char(self, s): + # NOT_RPYTHON + return self._str.startswith(s) + def ll_endswith(self, s): # NOT_RPYTHON return self._str.endswith(s._str) + def ll_endswith_char(self, s): + # NOT_RPYTHON + return self._str.endswith(s) + def ll_find(self, s, start, end): # NOT_RPYTHON if start > len(self._str): # workaround to cope with corner case diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -374,6 +374,43 @@ def can_ll_be_null(self, s_value): return s_value.can_be_none() + def check_graph_of_del_does_not_call_too_much(self, graph): + # RPython-level __del__() methods should not do "too much". + # In the PyPy Python interpreter, they usually do simple things + # like file.__del__() closing the file descriptor; or if they + # want to do more like call an app-level __del__() method, they + # enqueue the object instead, and the actual call is done later. + # + # Here, as a quick way to check "not doing too much", we check + # that from no RPython-level __del__() method we can reach a + # JitDriver. + # + # XXX wrong complexity, but good enough because the set of + # reachable graphs should be small + callgraph = self.rtyper.annotator.translator.callgraph.values() + seen = {graph: None} + while True: + oldlength = len(seen) + for caller, callee in callgraph: + if caller in seen and callee not in seen: + func = getattr(callee, 'func', None) + if getattr(func, '_dont_reach_me_in_del_', False): + lst = [str(callee)] + g = caller + while g: + lst.append(str(g)) + g = seen.get(g) + lst.append('') + raise TyperError("the RPython-level __del__() method " + "in %r calls:%s" % ( + graph, '\n\t'.join(lst[::-1]))) + if getattr(func, '_cannot_really_call_random_things_', + False): + continue + seen[callee] = caller + if len(seen) == oldlength: + break + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops, classcallhop=None): diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -667,7 +667,6 @@ res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res -ll_pop.oopspec = 'list.pop(l, index)' def ll_reverse(l): length = l.ll_length() diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py --- a/pypy/rpython/rstr.py +++ b/pypy/rpython/rstr.py @@ -81,16 +81,30 @@ return super(AbstractStringRepr, self).rtype_is_true(hop) def rtype_method_startswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_startswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_startswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_endswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_endswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_endswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_find(self, hop, reverse=False): # XXX binaryop diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -7,6 +7,7 @@ from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.rpython.error import TyperError from pypy.objspace.flow.model import summary class EmptyBase(object): @@ -1022,6 +1023,24 @@ assert destrptra is not None assert destrptrb is not None + def test_del_forbidden(self): + class A(object): + def __del__(self): + self.foo() + def foo(self): + self.bar() + def bar(self): + pass + bar._dont_reach_me_in_del_ = True + def f(): + a = A() + a.foo() + a.bar() + t = TranslationContext() + t.buildannotator().build_types(f, []) + e = py.test.raises(TyperError, t.buildrtyper().specialize) + print e.value + def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int class FooBar(object): diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -227,6 +227,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_startswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].startswith(const('o')) + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_endswith(self): const = self.const def fn(i, j): @@ -238,6 +247,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_endswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].endswith(const('e')) + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_find(self): const = self.const def fn(i, j): diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -1,10 +1,13 @@ import re, sys -from pypy.jit.metainterp.resoperation import rop, opname +from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser +from pypy.tool.logparser import parse_log_file, extract_category class Op(object): bridge = None + offset = None + asm = None def __init__(self, name, args, res, descr): self.name = name @@ -54,10 +57,53 @@ Op = Op use_mock_model = True + def postprocess(self, loop, backend_dump=None, backend_tp=None, + dump_start=0): + if backend_dump is not None: + raw_asm = self._asm_disassemble(backend_dump.decode('hex'), + backend_tp, dump_start) + asm = [] + start = 0 + for elem in raw_asm: + if len(elem.split("\t")) != 3: + continue + adr, _, v = elem.split("\t") + if not start: + start = int(adr.strip(":"), 16) + ofs = int(adr.strip(":"), 16) - start + if ofs >= 0: + asm.append((ofs, v.strip("\n"))) + asm_index = 0 + for i, op in enumerate(loop.operations): + end = 0 + j = i + 1 + while end == 0: + if j == len(loop.operations): + end = loop.last_offset + break + if loop.operations[j].offset is None: + j += 1 + else: + end = loop.operations[j].offset + if op.offset is not None: + while asm[asm_index][0] < op.offset: + asm_index += 1 + end_index = asm_index + while asm[end_index][0] < end: + end_index += 1 + op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) + return loop + + def _asm_disassemble(self, d, origin_addr, tp): + from pypy.jit.backend.x86.tool.viewcode import machine_code_dump + return list(machine_code_dump(d, tp, origin_addr)) + @classmethod - def parse_from_input(cls, input): - return cls(input, None, {}, 'lltype', None, - nonstrict=True).parse() + def parse_from_input(cls, input, **kwds): + parser = cls(input, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + return parser.postprocess(loop, **kwds) def parse_args(self, opname, argspec): if not argspec.strip(): @@ -284,3 +330,46 @@ res.append(op) i += 1 return res + + +def import_log(logname, ParserCls=SimpleParser): + log = parse_log_file(logname) + addrs = {} + for entry in extract_category(log, 'jit-backend-addr'): + m = re.search('bootstrap ([\da-f]+)', entry) + if not m: + # a bridge + m = re.search('has address ([\da-f]+)', entry) + addr = int(m.group(1), 16) + entry = entry.lower() + m = re.search('guard \d+', entry) + addrs[addr] = m.group(0) + else: + name = entry[:entry.find('(') - 1].lower() + addrs[int(m.group(1), 16)] = name + dumps = {} + for entry in extract_category(log, 'jit-backend-dump'): + backend, _, dump, _ = entry.split("\n") + _, addr, _, data = re.split(" +", dump) + backend_name = backend.split(" ")[1] + addr = int(addr[1:], 16) + if addr in addrs: + dumps[addrs[addr]] = (backend_name, addr, data) + loops = [] + for entry in extract_category(log, 'jit-log-opt'): + parser = ParserCls(entry, None, {}, 'lltype', None, + nonstrict=True) + loop = parser.parse() + comm = loop.comment + comm = comm.lower() + if comm.startswith('# bridge'): + m = re.search('guard \d+', comm) + name = m.group(0) + else: + name = comm[2:comm.find(':')-1] + if name in dumps: + bname, start_ofs, dump = dumps[name] + parser.postprocess(loop, backend_tp=bname, backend_dump=dump, + dump_start=start_ofs) + loops.append(loop) + return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest.log b/pypy/tool/jitlogparser/test/logtest.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest.log @@ -0,0 +1,38 @@ +[11f210b47027] {jit-backend +[11f210b900f7] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f3b0b2e63d5 +0 554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB3050920D3B7F00004D8B334983C60149BB3050920D3B7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05632E0B3B7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00602E0B3B7F000041FFD34440484C3D030300000049BB00602E0B3B7F000041FFD34440484C3D070304000000 +[11f210b949b3] jit-backend-dump} +[11f210b949b4] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f3b0b2e645d to 7f3b0b2e64af (bootstrap 7f3b0b2e63d5) +[11f210bab188] jit-backend-addr} +[11f210bab189] jit-backend} +[11f210bacbb7] {jit-log-opt-loop +# Loop 0 : loop with 19 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 INPLACE_ADD') ++179: i8 = int_add(i4, 1) +debug_merge_point(0, ' #28 STORE_FAST') +debug_merge_point(0, ' #31 JUMP_ABSOLUTE') ++183: i10 = getfield_raw(40564608, descr=) ++191: i12 = int_sub(i10, 1) ++195: setfield_raw(40564608, i12, descr=) ++203: i14 = int_lt(i12, 0) +guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++213: jump(p0, p1, p2, p3, i8, descr=) ++218: --end of the loop-- +[11f210c17981] jit-log-opt-loop} +[11f210fb1d21] {jit-backend-counts +0:8965 +1:2 +[11f210fb381b] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,12 +1,11 @@ -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, Const -from pypy.tool.jitlogparser.parser import SimpleParser, TraceForOpcode, Function,\ - adjust_bridges +from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, + Function, adjust_bridges, + import_log) from pypy.tool.jitlogparser.storage import LoopStorage -import py +import py, sys -def parse(input): - return SimpleParser.parse_from_input(input) +def parse(input, **kwds): + return SimpleParser.parse_from_input(input, **kwds) def test_parse(): @@ -111,6 +110,8 @@ assert res.chunks[1].lineno == 3 def test_linerange(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(''' [i0, i1] @@ -125,6 +126,8 @@ assert res.lineset == set([7, 8, 9]) def test_linerange_notstarts(): + if sys.version_info > (2, 6): + py.test.skip("unportable test") fname = str(py.path.local(__file__).join('..', 'x.py')) ops = parse(""" [p6, p1] @@ -179,3 +182,42 @@ ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] assert chunk.bytecode_name == 'StrLiteralSearch' + +def test_parsing_assembler(): + backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" + dump_start = 0x7f3b0b2e63d5 + loop = parse(""" + # Loop 0 : loop with 19 ops + [p0, p1, p2, p3, i4] + debug_merge_point(0, ' #15 COMPARE_OP') + +166: i6 = int_lt(i4, 10000) + guard_true(i6, descr=) [p1, p0, p2, p3, i4] + debug_merge_point(0, ' #27 INPLACE_ADD') + +179: i8 = int_add(i4, 1) + debug_merge_point(0, ' #31 JUMP_ABSOLUTE') + +183: i10 = getfield_raw(40564608, descr=) + +191: i12 = int_sub(i10, 1) + +195: setfield_raw(40564608, i12, descr=) + +203: i14 = int_lt(i12, 0) + guard_false(i14, descr=) [p1, p0, p2, p3, i8, None] + debug_merge_point(0, ' #9 LOAD_FAST') + +213: jump(p0, p1, p2, p3, i8, descr=) + +218: --end of the loop--""", backend_dump=backend_dump, + dump_start=dump_start, + backend_tp='x86_64') + cmp = loop.operations[1] + assert 'jge' in cmp.asm + assert '0x2710' in cmp.asm + assert 'jmp' in loop.operations[-1].asm + +def test_import_log(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest.log'))) + assert 'jge' in loops[0].operations[3].asm + +def test_import_log_2(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest2.log'))) + assert 'cmp' in loops[1].operations[1].asm + # bridge + assert 'cmp' in loops[3].operations[1].asm diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -688,11 +688,37 @@ def getothernodes(self): return self.othernodes[:] + def getbasecfilefornode(self, node, basecname): + # For FuncNode instances, use the python source filename (relative to + # the top directory): + if hasattr(node.obj, 'graph'): + g = node.obj.graph + # Lookup the filename from the function. + # However, not all FunctionGraph objs actually have a "func": + if hasattr(g, 'func'): + if g.filename.endswith('.py'): + localpath = py.path.local(g.filename) + pypkgpath = localpath.pypkgpath() + if pypkgpath: + relpypath = localpath.relto(pypkgpath) + return relpypath.replace('.py', '.c') + return basecname + def splitnodesimpl(self, basecname, nodes, nextra, nbetween, split_criteria=SPLIT_CRITERIA): + # Gather nodes by some criteria: + nodes_by_base_cfile = {} + for node in nodes: + c_filename = self.getbasecfilefornode(node, basecname) + if c_filename in nodes_by_base_cfile: + nodes_by_base_cfile[c_filename].append(node) + else: + nodes_by_base_cfile[c_filename] = [node] + # produce a sequence of nodes, grouped into files # which have no more than SPLIT_CRITERIA lines - iternodes = iter(nodes) + for basecname in nodes_by_base_cfile: + iternodes = iter(nodes_by_base_cfile[basecname]) done = [False] def subiter(): used = nextra diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -55,6 +55,13 @@ data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + # Verify that the generated C files have sane names: + gen_c_files = [str(f) for f in cbuilder.extrafiles] + for expfile in ('rlib_rposix.c', + 'rpython_lltypesystem_rstr.c', + 'translator_c_test_test_standalone.c'): + assert cbuilder.targetdir.join(expfile) in gen_c_files + def test_print(self): def entry_point(argv): print "hello simpler world" diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs --- a/pypy/translator/cli/src/pypylib.cs +++ b/pypy/translator/cli/src/pypylib.cs @@ -615,11 +615,29 @@ return s1.StartsWith(s2); } + public static bool ll_startswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[0] == c; + } + public static bool ll_endswith(string s1, string s2) { return s1.EndsWith(s2); } + public static bool ll_endswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[s.Length - 1] == c; + } + public static int ll_find(string s1, string s2, int start, int stop) { if (stop > s1.Length) diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -791,6 +791,20 @@ return str.substring(start,start+cnt); } + public static boolean ll_startswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(0) == c; + } + + public static boolean ll_endswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(str.length() - 1) == c; + } + // ---------------------------------------------------------------------- // StringBuffer From noreply at buildbot.pypy.org Fri Jul 22 13:42:25 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:42:25 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Support tealets on asmgcc too. It's actually easy, unless I'm Message-ID: <20110722114225.EFCEC82961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45876:d6075e673700 Date: 2011-07-15 09:38 +0200 http://bitbucket.org/pypy/pypy/changeset/d6075e673700/ Log: Support tealets on asmgcc too. It's actually easy, unless I'm missing something. diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -31,8 +31,7 @@ BoolOption("tealet", "enable stackless features via tealets", default=False, cmdline="--tealet", requires=[("translation.type_system", "lltype"), - ("translation.gctransformer", "framework"), - ("translation.gcrootfinder", "shadowstack")]), + ("translation.gctransformer", "framework")]), ChoiceOption("type_system", "Type system to use when RTyping", ["lltype", "ootype"], cmdline=None, default="lltype", requires={ diff --git a/pypy/rlib/test/test_rtealet.py b/pypy/rlib/test/test_rtealet.py --- a/pypy/rlib/test/test_rtealet.py +++ b/pypy/rlib/test/test_rtealet.py @@ -29,5 +29,3 @@ class TestTealetAsmgcc(BaseTestTealet): gcrootfinder = "asmgcc" - def setup_class(cls): - py.test.skip("XXX in-progress") diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -483,8 +483,8 @@ 'gc_dump_rpy_heap' : LLOp(), 'gc_typeids_z' : LLOp(), - 'gc_save_stack_roots' : LLOp(), # for tealet support - 'gc_restore_stack_roots': LLOp(), # for tealet support + 'gc_save_stack_roots' : LLOp(canunwindgc=True), # for tealet support + 'gc_restore_stack_roots': LLOp(canunwindgc=True), # for tealet support # ------- JIT & GC interaction, only for some GCs ---------- diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py --- a/pypy/rpython/memory/gctransform/asmgcroot.py +++ b/pypy/rpython/memory/gctransform/asmgcroot.py @@ -1,3 +1,4 @@ +from pypy.annotation import model as annmodel from pypy.rpython.memory.gctransform.framework import FrameworkGCTransformer from pypy.rpython.memory.gctransform.framework import BaseRootWalker from pypy.rpython.lltypesystem import lltype, llmemory, rffi @@ -147,6 +148,54 @@ self._extra_gcmapend = lambda: llmemory.NULL self._extra_mark_sorted = lambda: True + def need_tealet_support(self, gctransformer, getfn): + # tealet support: hooks to save and restore the GC pointers + # from the stack before it is whisked away by "tealet.c". + GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF)) + SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed)) + WALKER_PTR = lltype.Ptr(lltype.Struct('walker', + ('gcptr_array', GCPTR_ARRAY), + ('signed_array', SIGNED_ARRAY))) + gcdata = self.gcdata + # + def ll_count_locations(gc, addr): + gcdata._gc_tealet_count += 1 + # + def ll_save_locations(gc, addr): + gcref = llmemory.cast_adr_to_ptr(addr.address[0], llmemory.GCREF) + gcdata._gc_tealet_array[gcdata._gc_tealet_count] = gcref + gcdata._gc_tealet_count += 1 + # + def ll_restore_locations(gc, addr): + gcref = gcdata._gc_tealet_array[gcdata._gc_tealet_count] + gcdata._gc_tealet_count += 1 + addr.address[0] = llmemory.cast_ptr_to_adr(gcref) + # + def ll_save_stack_roots(walker): + gcdata._gc_tealet_count = 0 + self.walk_stack_roots(ll_count_locations) + count = gcdata._gc_tealet_count + gcdata._gc_tealet_count = 0 + gcdata._gc_tealet_array = lltype.malloc(GCPTR_ARRAY.TO, count) + self.walk_stack_roots(ll_save_locations) + walker.gcptr_array = gcdata._gc_tealet_array + gcdata._gc_tealet_array = lltype.nullptr(GCPTR_ARRAY.TO) + # + def ll_restore_stack_roots(walker): + gcdata._gc_tealet_array = walker.gcptr_array + gcdata._gc_tealet_count = 0 + self.walk_stack_roots(ll_restore_locations) + gcdata._gc_tealet_array = lltype.nullptr(GCPTR_ARRAY.TO) + # + self.ll_save_stack_roots_ptr = getfn(ll_save_stack_roots, + [annmodel.SomePtr(WALKER_PTR)], + annmodel.s_None, + minimal_transform=False) + self.ll_restore_stack_roots_ptr = getfn(ll_restore_stack_roots, + [annmodel.SomePtr(WALKER_PTR)], + annmodel.s_None, + minimal_transform=False) + def need_thread_support(self, gctransformer, getfn): # Threads supported "out of the box" by the rest of the code. # The whole code in this function is only there to support From noreply at buildbot.pypy.org Fri Jul 22 13:42:28 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:42:28 +0200 (CEST) Subject: [pypy-commit] pypy tealet: hg merge default Message-ID: <20110722114228.A655C82961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45877:daea6a23c7ab Date: 2011-07-20 18:15 +0200 http://bitbucket.org/pypy/pypy/changeset/daea6a23c7ab/ Log: hg merge default diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -185,6 +185,7 @@ Jim Baker Philip Jenvey Rodrigo Araújo + Brett Cannon Heinrich-Heine University, Germany Open End AB (formerly AB Strakt), Sweden diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -19,12 +19,12 @@ section * Write them in pure python and use direct libffi low-level bindings, See - \_rawffi_ module description. + \_ffi_ module description. * Write them in RPython as mixedmodule_, using *rffi* as bindings. .. _ctypes: #CTypes -.. _\_rawffi: #LibFFI +.. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules CTypes @@ -42,41 +42,50 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. +ctypes call are optimized by the JIT and the resulting machine code contains a +direct call to the target C function. However, due to the very dynamic nature +of ctypes, some overhead over a bare C call is still present, in particular to +check/convert the types of the parameters. Moreover, even if most calls are +optimized, some cannot and thus need to follow the slow path, not optimized by +the JIT. + .. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure +.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html Pros ---- -Stable, CPython-compatible API +Stable, CPython-compatible API. Most calls are fast, optimized by JIT. Cons ---- -Only pure-python code (slow), problems with platform-dependency (although -we partially solve those). PyPy implementation is now very slow. +Problems with platform-dependency (although we partially solve +those). Although the JIT optimizes ctypes calls, some overhead is still +present. The slow-path is very slow. -_`CPython ctypes`: http://python.net/crew/theller/ctypes/ LibFFI ====== Mostly in order to be able to write a ctypes module, we developed a very -low-level libffi bindings. (libffi is a C-level library for dynamic calling, +low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling, which is used by CPython ctypes). This library provides stable and usable API, although it's API is a very low-level one. It does not contain any -magic. +magic. It is also optimized by the JIT, but has much less overhead than ctypes. Pros ---- -Works. Combines disadvantages of using ctypes with disadvantages of -using mixed modules. Probably more suitable for a delicate code -where ctypes magic goes in a way. +It Works. Probably more suitable for a delicate code where ctypes magic goes +in a way. All calls are optimized by the JIT, there is no slow path as in +ctypes. Cons ---- -Slow. CPython-incompatible API, very rough and low-level +It combines disadvantages of using ctypes with disadvantages of using mixed +modules. CPython-incompatible API, very rough and low-level. Mixed Modules ============= @@ -87,15 +96,15 @@ * a mixed module needs to be written in RPython, which is far more complicated than Python (XXX link) -* due to lack of separate compilation (as of April 2008), each +* due to lack of separate compilation (as of July 2011), each compilation-check requires to recompile whole PyPy python interpreter, which takes 0.5-1h. We plan to solve this at some point in near future. * although rpython is a garbage-collected language, the border between C and RPython needs to be managed by hand (each object that goes into the - C level must be explicitly freed) XXX we try to solve this + C level must be explicitly freed). -Some document is available `here`_ +Some documentation is available `here`_ .. _`here`: rffi.html diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -145,11 +145,11 @@ def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - self.clear_all_weakrefs() self.enqueue_for_destruction(self.space, GeneratorIterator.descr_close, "interrupting generator of ") diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -1118,6 +1118,9 @@ return meth(op, args, *descrs) def _get_list_nonneg_canraise_flags(self, op): + # XXX as far as I can see, this function will always return True + # because functions that are neither nonneg nor fast don't have an + # oopspec any more # xxx break of abstraction: func = get_funcobj(op.args[0].value)._callable # base hints on the name of the ll function, which is a bit xxx-ish diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -73,7 +73,7 @@ assert self._lazy_setfield is None self._cached_fields[structvalue] = fieldvalue - def force_lazy_setfield(self, optheap): + def force_lazy_setfield(self, optheap, can_cache=True): op = self._lazy_setfield if op is not None: # This is the way _lazy_setfield is usually reset to None. @@ -83,12 +83,16 @@ self._cached_fields.clear() self._lazy_setfield = None optheap.next_optimization.propagate_forward(op) + if not can_cache: + return # Once it is done, we can put at least one piece of information # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) + elif not can_cache: + self._cached_fields.clear() def get_reconstructed(self, optimizer, valuemap): assert self._lazy_setfield is None @@ -202,20 +206,9 @@ for arraydescr in effectinfo.readonly_descrs_arrays: self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: - self.force_lazy_setfield(fielddescr) - try: - cf = self.cached_fields[fielddescr] - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setfield(fielddescr, can_cache=False) for arraydescr in effectinfo.write_descrs_arrays: - self.force_lazy_setarrayitem(arraydescr) - try: - submap = self.cached_arrayitems[arraydescr] - for cf in submap.itervalues(): - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setarrayitem(arraydescr, can_cache=False) if effectinfo.check_forces_virtual_or_virtualizable(): vrefinfo = self.optimizer.metainterp_sd.virtualref_info self.force_lazy_setfield(vrefinfo.descr_forced) @@ -238,20 +231,20 @@ if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] - def force_lazy_setfield(self, descr): + def force_lazy_setfield(self, descr, can_cache=True): try: cf = self.cached_fields[descr] except KeyError: return - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) - def force_lazy_setarrayitem(self, arraydescr): + def force_lazy_setarrayitem(self, arraydescr, can_cache=True): try: submap = self.cached_arrayitems[arraydescr] except KeyError: return for cf in submap.values(): - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes @@ -387,7 +380,7 @@ cf.do_setfield(self, op) else: # variable index, so make sure the lazy setarrayitems are done - self.force_lazy_setarrayitem(op.getdescr()) + self.force_lazy_setarrayitem(op.getdescr(), can_cache=False) # and then emit the operation self.emit_operation(op) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -199,6 +199,7 @@ )) return self.emit_operation(op) + self.pure(rop.FLOAT_MUL, [arg2, arg1], op.result) def optimize_FLOAT_NEG(self, op): v1 = op.getarg(0) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1755,6 +1755,48 @@ """ self.optimize_loop(ops, expected) + def test_duplicate_getarrayitem_after_setarrayitem_bug(self): + ops = """ + [p0, i0, i1] + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i6 = int_add(i0, 1) + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + + def test_duplicate_getarrayitem_after_setarrayitem_bug2(self): + ops = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + def test_bug_1(self): ops = """ [i0, p1] @@ -4511,7 +4553,7 @@ """ self.optimize_loop(ops, expected) - def test_strslice_with_other_stuff(self): + def test_strslice_subtraction_folds(self): ops = """ [p0, i0] i1 = int_add(i0, 1) @@ -4530,6 +4572,20 @@ """ self.optimize_strunicode_loop(ops, expected) + def test_float_mul_reversed(self): + ops = """ + [f0, f1] + f2 = float_mul(f0, f1) + f3 = float_mul(f1, f0) + jump(f2, f3) + """ + expected = """ + [f0, f1] + f2 = float_mul(f0, f1) + jump(f2, f2) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -596,12 +596,16 @@ standard_box = self.metainterp.virtualizable_boxes[-1] if standard_box is box: return False + if box in self.metainterp.nonstandard_virtualizables: + return True eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None, box, standard_box) eqbox = self.implement_guard_value(pc, eqbox) isstandard = eqbox.getint() if isstandard: self.metainterp.replace_box(box, standard_box) + else: + self.metainterp.nonstandard_virtualizables[box] = None return not isstandard def _get_virtualizable_field_index(self, fielddescr): @@ -1456,6 +1460,8 @@ self.call_pure_results = args_dict_box() # contains boxes where the class is already known self.known_class_boxes = {} + # contains frame boxes that are not virtualizables + self.nonstandard_virtualizables = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1797,6 +1803,7 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} + self.nonstandard_virtualizables = {} # XXX maybe not needed? duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2381,7 +2381,7 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? - def test_retrace_ending_up_retrazing_another_loop(self): + def test_retrace_ending_up_retracing_another_loop(self): myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) bytecode = "0+sI0+SI" diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -1133,6 +1133,7 @@ res = self.meta_interp(f, [10]) assert res == 55 self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True) + self.check_history(ptr_eq=2) def test_virtual_child_frame_with_arrays(self): myjitdriver = JitDriver(greens = [], reds = ['frame'], diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py --- a/pypy/module/__builtin__/compiling.py +++ b/pypy/module/__builtin__/compiling.py @@ -5,7 +5,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError from pypy.interpreter.astcompiler import consts, ast -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec @unwrap_spec(filename=str, mode=str, flags=int, dont_inherit=int) def compile(space, w_source, filename, mode, flags=0, dont_inherit=0): diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py --- a/pypy/module/__builtin__/descriptor.py +++ b/pypy/module/__builtin__/descriptor.py @@ -1,12 +1,10 @@ - -from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.function import StaticMethod, ClassMethod from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.descroperation import object_getattribute, object_setattr -from pypy.interpreter.function import StaticMethod, ClassMethod -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \ - descr_set_dict, interp_attrproperty_w, generic_new_descr +from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w, + generic_new_descr) +from pypy.objspace.descroperation import object_getattribute class W_Super(Wrappable): def __init__(self, space, w_starttype, w_objtype, w_self): diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -4,13 +4,12 @@ """ from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import NoneNotWrapped, applevel +from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.objectmodel import specialize -from inspect import getsource, getfile from pypy.rlib.rbigint import rbigint @@ -662,7 +661,6 @@ def descr_reduce(self): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns space = self.space w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -1,11 +1,9 @@ import new from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import NoneNotWrapped, applevel, interp2app +from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict -from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, descr_set_dict from pypy.rlib.objectmodel import compute_identity_hash from pypy.rlib.debug import make_sure_not_resized from pypy.rlib import jit diff --git a/pypy/module/__builtin__/interp_memoryview.py b/pypy/module/__builtin__/interp_memoryview.py --- a/pypy/module/__builtin__/interp_memoryview.py +++ b/pypy/module/__builtin__/interp_memoryview.py @@ -2,7 +2,7 @@ Implementation of the 'buffer' and 'memoryview' types. """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter import gateway, buffer +from pypy.interpreter import buffer from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -4,12 +4,10 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.runicode import UNICHR from pypy.rlib.rfloat import isnan, isinf, round_double from pypy.rlib import rfloat -import math import __builtin__ NoneNotWrapped = gateway.NoneNotWrapped diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,5 +1,4 @@ -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib import debug, jit diff --git a/pypy/module/__pypy__/interp_identitydict.py b/pypy/module/__pypy__/interp_identitydict.py --- a/pypy/module/__pypy__/interp_identitydict.py +++ b/pypy/module/__pypy__/interp_identitydict.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app from pypy.interpreter.baseobjspace import Wrappable class W_IdentityDict(Wrappable): diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.objectmodel import we_are_translated class CodecState(object): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -1,9 +1,8 @@ -import sys -from pypy.interpreter.baseobjspace import Wrappable, Arguments +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, \ operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi @@ -83,7 +82,6 @@ def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P types = [ # note: most of the type name directly come from the C equivalent, # with the exception of bytes: in C, ubyte and char are equivalent, diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,12 +3,10 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.gateway import ObjSpace -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -import os def wrap_streamerror(space, e, w_filename=None): if isinstance(e, streamio.StreamError): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -4,7 +4,6 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.buffer import RWBuffer -from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstring import StringBuilder from pypy.rlib.rarithmetic import r_longlong, intmask from pypy.tool.sourcetools import func_renamer diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py --- a/pypy/module/_io/interp_fileio.py +++ b/pypy/module/_io/interp_fileio.py @@ -1,5 +1,4 @@ -from pypy.interpreter.typedef import ( - TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty) +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 from pypy.rlib.rarithmetic import r_longlong diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -6,7 +6,6 @@ TypeDef, interp_attrproperty, generic_new_descr) from pypy.module.exceptions.interp_exceptions import W_IOError from pypy.module._io.interp_fileio import W_FileIO -from pypy.module._io.interp_iobase import W_IOBase from pypy.module._io.interp_textio import W_TextIOWrapper from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -4,7 +4,7 @@ generic_new_descr) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint from pypy.rlib.rbigint import rbigint from pypy.rlib.rstring import UnicodeBuilder diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py --- a/pypy/module/_locale/interp_locale.py +++ b/pypy/module/_locale/interp_locale.py @@ -1,4 +1,3 @@ -from pypy.rpython.tool import rffi_platform as platform from pypy.rlib import rposix from pypy.rlib.rarithmetic import intmask diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -2,12 +2,10 @@ """ The ffi for rpython, need to be imported for side effects """ -import sys from pypy.rpython.lltypesystem import rffi from pypy.rpython.lltypesystem import lltype from pypy.rpython.tool import rffi_platform from pypy.rpython.extfunc import register_external -from pypy.rpython.extregistry import ExtRegistryEntry from pypy.module._minimal_curses import interp_curses from pypy.translator.tool.cbuild import ExternalCompilationInfo diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -1,4 +1,4 @@ -import py, sys +import py from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -4,7 +4,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import ( OperationError, wrap_oserror, operationerrfmt) -from pypy.rpython.lltypesystem import rffi, lltype, llmemory +from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll import sys diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -15,7 +15,6 @@ if sys.platform == 'win32': from pypy.rlib import rwin32 - from pypy.interpreter.error import wrap_windowserror from pypy.module._multiprocessing.interp_win32 import ( handle_w, _GetTickCount) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -8,7 +8,6 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec -from pypy.objspace.std.dicttype import dictiter_typedef from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,10 +2,10 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rpython.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import get_elem, push_elem +from pypy.module._rawffi.array import push_elem from pypy.module._rawffi.structure import W_Structure -from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \ - wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes +from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, + unwrap_value, unpack_argshapes) from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL from pypy.rlib.clibffi import ffi_type_void from pypy.rlib import rweakref diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -1,7 +1,6 @@ -import sys from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib.clibffi import * @@ -15,7 +14,7 @@ from pypy.rlib import rwin32 from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.tracker import tracker TYPEMAP = { diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py --- a/pypy/module/_socket/interp_func.py +++ b/pypy/module/_socket/interp_func.py @@ -1,9 +1,8 @@ -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._socket.interp_socket import converted_error, W_RSocket from pypy.rlib import rsocket from pypy.rlib.rsocket import SocketError -from pypy.rlib.rarithmetic import r_uint -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError def gethostname(space): """gethostname() -> string diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,7 +1,7 @@ from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError -from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -11,7 +11,6 @@ from pypy.module._socket import interp_socket -import sys ## user defined constants X509_NAME_MAXLEN = 256 diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -15,13 +15,10 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import StaticMethod from pypy.module._stackless.stackless_flags import StacklessFlags from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py --- a/pypy/module/_stackless/interp_stackless.py +++ b/pypy/module/_stackless/interp_stackless.py @@ -1,9 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError -from pypy.rlib.rarithmetic import intmask import os diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py --- a/pypy/module/_stackless/rclonable.py +++ b/pypy/module/_stackless/rclonable.py @@ -1,7 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.rlib.objectmodel import we_are_translated -from pypy.interpreter.error import OperationError class InterpClonableMixin: diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,9 +1,8 @@ import py -from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.interpreter.typedef import GetSetProperty, TypeDef +from pypy.interpreter.typedef import TypeDef from pypy.rlib import jit import weakref diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -1,6 +1,5 @@ from __future__ import with_statement from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError, wrap_windowserror diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,10 +1,9 @@ from __future__ import with_statement -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object from pypy.objspace.std.multimethod import FailedToImplement diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -4,9 +4,8 @@ from pypy.rpython.lltypesystem import lltype from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.rlib.streamio import Stream from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform as compiler diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -133,6 +133,7 @@ bz2f.seek(0) assert bz2f.tell() == 0 + del bz2f # delete from this frame, which is captured in the traceback def test_open_close_del(self): from bz2 import BZ2File @@ -246,11 +247,18 @@ assert text_read == self.TEXT bz2f.close() + def test_silently_closes(self): + from bz2 import BZ2File + self.create_broken_temp_file() + BZ2File(self.temppath) + # check that no C-level malloc is left behind + def test_read_broken_file(self): from bz2 import BZ2File self.create_broken_temp_file() bz2f = BZ2File(self.temppath) raises(EOFError, bz2f.read) + del bz2f # delete from this frame, which is captured in the traceback def test_subsequent_read_broken_file(self): from bz2 import BZ2File @@ -264,6 +272,7 @@ raise Exception("should generate EOFError earlier") except EOFError: pass + del bz2f # delete from this frame, which is captured in the traceback def test_read_chunk10(self): from bz2 import BZ2File @@ -416,6 +425,7 @@ bz2f.close() bz2f = BZ2File(self.temppath, 'r') assert bz2f.read() == self.random_data + del bz2f # delete from this frame, which is captured in the traceback def test_context_manager(self): from bz2 import BZ2File diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -1,4 +1,3 @@ -import sys from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py --- a/pypy/module/cmath/interp_cmath.py +++ b/pypy/module/cmath/interp_cmath.py @@ -5,7 +5,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import NoneNotWrapped -from pypy.module.cmath import Module, names_and_docstrings +from pypy.module.cmath import names_and_docstrings from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG from pypy.module.cmath.constant import M_LN2, M_LN10 diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py --- a/pypy/module/cpyext/cdatetime.py +++ b/pypy/module/cpyext/cdatetime.py @@ -1,8 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib.objectmodel import we_are_translated -from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef -from pypy.module.cpyext.api import ( - cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields) +from pypy.module.cpyext.pyobject import PyObject, make_ref +from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct, + PyObjectFields) from pypy.module.cpyext.import_ import PyImport_Import from pypy.module.cpyext.typeobject import PyTypeObjectPtr from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py --- a/pypy/module/cpyext/complexobject.py +++ b/pypy/module/cpyext/complexobject.py @@ -1,7 +1,6 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.module.cpyext.api import ( cpython_api, cpython_struct, PyObject, build_type_checkers) -from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.floatobject import PyFloat_AsDouble from pypy.objspace.std.complexobject import W_ComplexObject from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.1" /* PyPy version as a string */ -#define PYPY_VERSION "1.5.0" +#define PYPY_VERSION "1.6.0" /* Subversion Revision number of this file (not of the repository) */ #define PY_PATCHLEVEL_REVISION "$Revision: 77872 $" diff --git a/pypy/module/crypt/interp_crypt.py b/pypy/module/crypt/interp_crypt.py --- a/pypy/module/crypt/interp_crypt.py +++ b/pypy/module/crypt/interp_crypt.py @@ -1,6 +1,5 @@ -from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.rpython.lltypesystem import rffi, lltype +from pypy.rpython.lltypesystem import rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo import sys diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -73,9 +73,8 @@ """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w,\ - GetSetProperty, interp_attrproperty, descr_get_dict, descr_set_dict,\ - descr_del_dict +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict, + descr_set_dict, descr_del_dict) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError from pypy.rlib import rwin32 diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -11,9 +11,8 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.eval import Code from pypy.interpreter.pycode import PyCode -from pypy.rlib import streamio, jit, rposix +from pypy.rlib import streamio, jit from pypy.rlib.streamio import StreamErrors -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -3,9 +3,9 @@ from pypy.rlib import streamio from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.module import Module -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import struct + def get_suffixes(space): w = space.wrap diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,7 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.rarithmetic import ovfcheck class W_Count(Wrappable): diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -1,10 +1,8 @@ -from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask from pypy.rlib import rstackovf from pypy.module._file.interp_file import W_File -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import sys + Py_MARSHAL_VERSION = 2 diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,4 +1,4 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty @@ -244,6 +244,12 @@ def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_repr(self, space): + return self.get_concrete()._repr(space) + + def descr_str(self, space): + return self.get_concrete()._str(space) + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -433,6 +439,26 @@ def calc_index(self, item): return (self.start + item * self.step) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + class SingleDimArray(BaseArray): signature = Signature() @@ -470,6 +496,26 @@ def getitem(self, item): return self.storage[item] + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [str(self.getitem(index)) for index \ + in range(3)] + nums.append("..." + "," * comma) + nums.extend([str(self.getitem(index)) for index \ + in range(self.find_size() - 3, self.find_size())]) + else: + nums = [str(self.getitem(index)) for index \ + in range(self.find_size())] + return nums + + def _repr(self, space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") + + def _str(self,space): + # Simple implementation so that we can see the array. Needs work. + return space.wrap("[" + " ".join(self._getnums(True)) + "]") + @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) @@ -527,6 +573,8 @@ __rdiv__ = interp2app(BaseArray.descr_rdiv), __rpow__ = interp2app(BaseArray.descr_rpow), __rmod__ = interp2app(BaseArray.descr_rmod), + __repr__ = interp2app(BaseArray.descr_repr), + __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), sum = interp2app(BaseArray.descr_sum), diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,7 +1,7 @@ import math -from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array +from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, + convert_to_array) from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -43,6 +43,38 @@ a = array(range(5)) assert a[3] == 3 + def test_repr(self): + from numpy import array, zeros + a = array(range(5)) + assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" + a = zeros(1001) + assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_repr_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert repr(b) == "array([1.0, 3.0])" + a = zeros(2002) + b = a[::2] + assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_str(self): + from numpy import array, zeros + a = array(range(5)) + assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + a = zeros(1001) + assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + + def test_str_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert str(b) == "[1.0 3.0]" + a = zeros(2002) + b = a[::2] + assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_getitem(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py --- a/pypy/module/mmap/interp_mmap.py +++ b/pypy/module/mmap/interp_mmap.py @@ -1,15 +1,10 @@ -from pypy.rpython.tool import rffi_platform -from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped from pypy.rlib import rmmap from pypy.rlib.rmmap import RValueError, RTypeError, ROverflowError -import sys -import os -import platform -import stat + class W_MMap(Wrappable): def __init__(self, space, mmap_obj): diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -15,7 +15,6 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap -from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant from pypy.jit.metainterp.resoperation import rop from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -1,9 +1,9 @@ from pypy.interpreter.typedef import TypeDef, interp_attrproperty -from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import unwrap_spec, interp2app from pypy.interpreter.pycode import PyCode -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.lltypesystem.rclass import OBJECT diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -0,0 +1,32 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestMath(BaseTestPyPyC): + def test_log(self): + def main(n): + import math + + i = 1 + s = 0.0 + while i < n: + s += math.log(i) - math.log10(i) + i += 1 + return s + log = self.run(main, [500]) + assert round(log.result, 6) == round(main(500), 6) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i2 = int_lt(i0, i1) + guard_true(i2, descr=...) + guard_not_invalidated(descr=...) + f1 = cast_int_to_float(i0) + i3 = float_le(f1, 0) + guard_false(i3, descr=...) + f2 = call(ConstClass(log), f1, descr=) + f3 = call(ConstClass(log10), f1, descr=) + f4 = float_sub(f2, f3) + f5 = float_add(f0, f4) + i4 = int_add(i0, 1) + --TICK-- + jump(..., descr=) + """) diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py --- a/pypy/module/rctime/interp_time.py +++ b/pypy/module/rctime/interp_time.py @@ -6,7 +6,6 @@ from pypy.rlib.rarithmetic import ovfcheck_float_to_int from pypy.rlib import rposix from pypy.translator.tool.cbuild import ExternalCompilationInfo -import math import os import sys import time as pytime diff --git a/pypy/module/select/interp_select.py b/pypy/module/select/interp_select.py --- a/pypy/module/select/interp_select.py +++ b/pypy/module/select/interp_select.py @@ -1,9 +1,7 @@ -import math from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import ( - OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.rlib import rpoll import errno diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py --- a/pypy/module/struct/formatiterator.py +++ b/pypy/module/struct/formatiterator.py @@ -1,11 +1,10 @@ - from pypy.interpreter.error import OperationError from pypy.rlib.objectmodel import specialize from pypy.rlib.rstruct.error import StructError from pypy.rlib.rstruct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT -from pypy.rlib.rstruct.formatiterator import (FormatIterator, - CalcSizeFormatIterator) +from pypy.rlib.rstruct.formatiterator import FormatIterator + class PackFormatIterator(FormatIterator): diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py --- a/pypy/module/struct/interp_struct.py +++ b/pypy/module/struct/interp_struct.py @@ -1,10 +1,7 @@ from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.module.struct.formatiterator import PackFormatIterator, UnpackFormatIterator from pypy.rlib.rstruct.error import StructError -from pypy.module.struct.formatiterator import CalcSizeFormatIterator -from pypy.module.struct.formatiterator import PackFormatIterator -from pypy.module.struct.formatiterator import UnpackFormatIterator - +from pypy.rlib.rstruct.formatiterator import CalcSizeFormatIterator @unwrap_spec(format=str) def calcsize(space, format): diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py --- a/pypy/module/sys/test/test_sysmodule.py +++ b/pypy/module/sys/test/test_sysmodule.py @@ -476,7 +476,7 @@ assert isinstance(vi[0], int) assert isinstance(vi[1], int) assert isinstance(vi[2], int) - assert vi[3] in ("alpha", "beta", "candidate", "final") + assert vi[3] in ("alpha", "beta", "candidate", "dev", "final") assert isinstance(vi[4], int) def test_allattributes(self): @@ -523,4 +523,4 @@ # If this ever actually becomes a compilation option this test should # be changed. - assert sys.float_repr_style == "short" \ No newline at end of file + assert sys.float_repr_style == "short" diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -1,9 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype, llmemory -from pypy.rpython.tool import rffi_platform as platform from pypy.translator.tool.cbuild import ExternalCompilationInfo -import py, os -from pypy.rpython.extregistry import ExtRegistryEntry +import py from pypy.rlib import jit from pypy.rlib.debug import ll_assert from pypy.rlib.objectmodel import we_are_translated diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py --- a/pypy/module/thread/os_local.py +++ b/pypy/module/thread/os_local.py @@ -1,9 +1,7 @@ from pypy.module.thread import ll_thread as thread -from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp2app -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict +from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty, + descr_get_dict) class Local(Wrappable): diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py --- a/pypy/module/thread/os_thread.py +++ b/pypy/module/thread/os_thread.py @@ -6,7 +6,6 @@ from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import unwrap_spec, NoneNotWrapped, Arguments -from pypy.rlib.objectmodel import free_non_gc_object # Here are the steps performed to start a new thread: # diff --git a/pypy/module/unicodedata/generate_unicodedb.py b/pypy/module/unicodedata/generate_unicodedb.py --- a/pypy/module/unicodedata/generate_unicodedb.py +++ b/pypy/module/unicodedata/generate_unicodedb.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -import pprint - MAXUNICODE = 0x10FFFF # the value of sys.maxunicode of wide Python builds MANDATORY_LINE_BREAKS = ["BK", "CR", "LF", "NL"] # line break categories @@ -662,7 +660,7 @@ ''' def main(): - import re, sys + import sys from optparse import OptionParser infile = None outfile = sys.stdout diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py --- a/pypy/rpython/extfuncregistry.py +++ b/pypy/rpython/extfuncregistry.py @@ -1,6 +1,6 @@ # this registry uses the new interface for external functions -from extfunc import register_external +from pypy.rpython.extfunc import register_external # ___________________________ # math functions @@ -30,24 +30,28 @@ export_name="ll_math.ll_math_%s" % name, sandboxsafe=True, llimpl=llimpl) -register_external(rfloat.isinf, [float], bool, - export_name="ll_math.ll_math_isinf", sandboxsafe=True, - llimpl=ll_math.ll_math_isinf) -register_external(rfloat.isnan, [float], bool, - export_name="ll_math.ll_math_isnan", sandboxsafe=True, - llimpl=ll_math.ll_math_isnan) -register_external(rfloat.isfinite, [float], bool, - export_name="ll_math.ll_math_isfinite", sandboxsafe=True, - llimpl=ll_math.ll_math_isfinite) -register_external(rfloat.copysign, [float, float], float, - export_name="ll_math.ll_math_copysign", sandboxsafe=True, - llimpl=ll_math.ll_math_copysign) -register_external(math.floor, [float], float, - export_name="ll_math.ll_math_floor", sandboxsafe=True, - llimpl=ll_math.ll_math_floor) -register_external(math.sqrt, [float], float, - export_name="ll_math.ll_math_sqrt", sandboxsafe=True, - llimpl=ll_math.ll_math_sqrt) +_register = [ # (module, [(method name, arg types, return type), ...], ...) + (rfloat, [ + ('isinf', [float], bool), + ('isnan', [float], bool), + ('isfinite', [float], bool), + ('copysign', [float, float], float), + ]), + (math, [ + ('floor', [float], float), + ('sqrt', [float], float), + ('log', [float], float), + ('log10', [float], float), + ]), +] +for module, methods in _register: + for name, arg_types, return_type in methods: + method_name = 'll_math_%s' % name + register_external(getattr(module, name), arg_types, return_type, + export_name='ll_math.%s' % method_name, + sandboxsafe=True, + llimpl=getattr(ll_math, method_name)) + complex_math_functions = [ ('frexp', [float], (float, int)), diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -68,8 +68,9 @@ math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) - math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) +math_log = llexternal('log', [rffi.DOUBLE], rffi.DOUBLE) +math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -335,6 +336,16 @@ return x # +inf or nan +def ll_math_log(x): + if x <= 0: + raise ValueError("math domain error") + return math_log(x) + +def ll_math_log10(x): + if x <= 0: + raise ValueError("math domain error") + return math_log10(x) + # ____________________________________________________________ # # Default implementations @@ -373,7 +384,7 @@ unary_math_functions = [ 'acos', 'asin', 'atan', 'ceil', 'cos', 'cosh', 'exp', 'fabs', - 'sin', 'sinh', 'tan', 'tanh', 'log', 'log10', + 'sin', 'sinh', 'tan', 'tanh', 'acosh', 'asinh', 'atanh', 'log1p', 'expm1', ] unary_math_functions_can_overflow = [ diff --git a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py --- a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py +++ b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py @@ -1,6 +1,4 @@ - -""" Just another bunch of tests for llmath, run on top of llinterp -""" +"""Just another bunch of tests for llmath, run on top of llinterp.""" from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin from pypy.rpython.lltypesystem.module import ll_math @@ -39,7 +37,7 @@ assert self.interpret(f, [0.3, 0.4]) == f(0.3, 0.4) return next_test - for name in ll_math.unary_math_functions: + for name in ll_math.unary_math_functions + ['log', 'log10', 'sqrt']: func_name = 'test_%s' % (name,) next_test = new_unary_test(name) next_test.func_name = func_name diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,6 +34,13 @@ the GC in very small programs. Defaults to 8 times the nursery. + PYPY_GC_LOSTCARD If between two minor collections we see more than + 'PYPY_GC_LOSTCARD * length' writes to the same array, + then give up card marking and use the fast write + barrier instead. Defaults to 0.3333 for now. + Avoid values lower than 0.125: it is the growth + factor of list.append(). + PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -198,6 +205,9 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, + # See PYPY_GC_LOSTCARD. + "lost_card": 1.0 / 3.0, + # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -214,6 +224,7 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, + lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -235,6 +246,7 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 + self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -355,6 +367,10 @@ else: self.max_delta = 0.125 * env.get_total_memory() # + lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') + if lost_card > 0.0: + self.lost_card = lost_card + # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -649,7 +665,7 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only @@ -675,11 +691,15 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # (the loop is empty in C). + # followed by a Signed (the loop is empty in C). + if cardheadersize > 0: i = 0 - while i < cardheadersize: - llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) + while i < cardheadersize - WORD: + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Char)) i += 1 + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -903,14 +923,11 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # - size_gc_header = self.gcheaderbuilder.size_gc_header - p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: - p -= 1 - ll_assert(p.char[0] == '\x00', + i -= 1 + ll_assert(self.get_card(obj, i).char[0] == '\x00', "the card marker bits are not cleared") - i -= 1 # ---------- # Write barrier @@ -1008,6 +1025,8 @@ self.prebuilt_root_objects.append(addr_array) return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1025,10 +1044,6 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1057,6 +1072,8 @@ if not self.appears_to_be_young(newvalue): return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1069,10 +1086,6 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1090,11 +1103,36 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card(self, obj, byteindex): + def get_card_counter_addr(self, obj): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + return llarena.getfakearenaaddress(addr_byte) - WORD + def get_card(self, obj, byteindex): + return self.get_card_counter_addr(obj) + (~byteindex) + + def set_cards_flag(self, obj): + hdr = self.header(obj) + if hdr.tid & GCFLAG_CARDS_SET == 0: + # + # first time we set a card bit in this object + self.header(obj).tid |= GCFLAG_CARDS_SET + self.objects_with_cards_set.append(obj) + # + # initialize the counter with the array length and self.lost_card + typeid = self.get_type_id(obj) + offset_to_length = self.varsize_offset_to_length(typeid) + length = (obj + offset_to_length).signed[0] + counter = int(length * self.lost_card) + self.get_card_counter_addr(obj).signed[0] = counter + else: + # decrement the counter and if zero is reached, give up on + # card marking (up to the next collection). + addr = self.get_card_counter_addr(obj) + addr.signed[0] -= 1 + if addr.signed[0] < 0: + self.objects_pointing_to_young.append(obj) + hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1167,10 +1205,7 @@ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(dest_addr) - dest_hdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(dest_addr) # ---------- # Nursery collection @@ -1264,6 +1299,7 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) + p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1602,7 +1638,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 arena -= extra_words * WORD allocsize += extra_words * WORD # diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -89,7 +89,7 @@ while asm[asm_index][0] < op.offset: asm_index += 1 end_index = asm_index - while asm[end_index][0] < end: + while asm[end_index][0] < end and end_index < len(asm) - 1: end_index += 1 op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) return loop @@ -336,25 +336,27 @@ log = parse_log_file(logname) addrs = {} for entry in extract_category(log, 'jit-backend-addr'): - m = re.search('bootstrap ([\da-f]+)', entry) + m = re.search('bootstrap ([-\da-f]+)', entry) if not m: # a bridge - m = re.search('has address ([\da-f]+)', entry) + m = re.search('has address ([-\da-f]+)', entry) addr = int(m.group(1), 16) entry = entry.lower() m = re.search('guard \d+', entry) - addrs[addr] = m.group(0) + name = m.group(0) else: name = entry[:entry.find('(') - 1].lower() - addrs[int(m.group(1), 16)] = name + addr = int(m.group(1), 16) + addrs.setdefault(addr, []).append(name) dumps = {} for entry in extract_category(log, 'jit-backend-dump'): backend, _, dump, _ = entry.split("\n") _, addr, _, data = re.split(" +", dump) backend_name = backend.split(" ")[1] addr = int(addr[1:], 16) - if addr in addrs: - dumps[addrs[addr]] = (backend_name, addr, data) + if addr in addrs and addrs[addr]: + name = addrs[addr].pop(0) # they should come in order + dumps[name] = (backend_name, addr, data) loops = [] for entry in extract_category(log, 'jit-log-opt'): parser = ParserCls(entry, None, {}, 'lltype', None, @@ -369,7 +371,10 @@ name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] - parser.postprocess(loop, backend_tp=bname, backend_dump=dump, - dump_start=start_ofs) + loop.force_asm = (lambda dump=dump, start_ofs=start_ofs, + bname=bname, loop=loop: + parser.postprocess(loop, backend_tp=bname, + backend_dump=dump, + dump_start=start_ofs)) loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest2.log @@ -0,0 +1,301 @@ +[1f5e7f69779] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f7fe75] jit-backend-dump} +[1f5e7f84fc4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f87ac1] jit-backend-dump} +[1f5e7f8a0b4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b08a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f8da6b] jit-backend-dump} +[1f5e7f8f4f6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b13d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f92b83] jit-backend-dump} +[1f5e7f95b99] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 +[1f5e7f988d0] jit-backend-dump} +[1f5e7fa16fb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b28e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 +[1f5e7fa47ac] jit-backend-dump} +[1f5e7fab3a4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 +[1f5e7faf1ca] jit-backend-dump} +[1f5e7fb0813] {jit-backend-counts +[1f5e7fb0f61] jit-backend-counts} +[1f5fd38be3e] {jit-backend +[1f5fe729336] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB30B00C0A897F00004D8B334983C60149BB30B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030300000049BB00B0A007897F000041FFD34440484C3D39030400000049BB00B0A007897F000041FFD34440484C3907070305000000 +[1f5fe73276a] jit-backend-dump} +[1f5fe73438f] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f8907a0b45d to 7f8907a0b4c3 (bootstrap 7f8907a0b3d5) +[1f5fe7369af] jit-backend-addr} +[1f5fe737940] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3e5 +0 50FFFFFF +[1f5fe74b40e] jit-backend-dump} +[1f5fe74c63d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b484 +0 95000000 +[1f5fe74da6a] jit-backend-dump} +[1f5fe74e438] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 9B000000 +[1f5fe74f513] jit-backend-dump} +[1f5fe74fd2e] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b4b7 +0 91000000 +[1f5fe750d8c] jit-backend-dump} +[1f5fe75373f] jit-backend} +[1f5fe755abc] {jit-log-opt-loop +# Loop 0 : loop with 26 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 1) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f5fe92b8af] jit-log-opt-loop} +[1f5fe944ae5] {jit-backend +[1f5fee20651] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b565 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C254010000000049BB38B00C0A897F0000498B0B4883C10149BB38B00C0A897F000049890B4983F8010F85000000004883FE017206813E980700000F85000000004983FA000F850000000049BBA8F0B407897F00004D39DC0F8500000000488B56084881FA102700000F8D000000004989D44883E2024883FA000F85000000004983C403488B1425A0536B024883EA0148891425A0536B024883FA000F8C000000004C89BD70FFFFFF4C89B568FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4D89E749BB5DB4A007897F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DAE9CCFEFFFF49BB00B0A007897F000041FFD321383C343029241D180C08030600000049BB00B0A007897F000041FFD3383C18343029240C08030700000049BB00B0A007897F000041FFD329383C3430241808030800000049BB00B0A007897F000041FFD3383C3034241808030900000049BB00B0A007897F000041FFD3383C183424030A00000049BB00B0A007897F000041FFD3383C34241809030B00000049BB00B0A007897F000041FFD3383C34243107030C000000 +[1f5fee2e673] jit-backend-dump} +[1f5fee2f38d] {jit-backend-addr +Loop 1 ( #9 LOAD_FAST) has address 7f8907a0b631 to 7f8907a0b6f8 (bootstrap 7f8907a0b565) +[1f5fee312e3] jit-backend-addr} +[1f5fee320ed] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b575 +0 50FFFFFF +[1f5fee3e903] jit-backend-dump} +[1f5fee3fbff] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b655 +0 0C010000 +[1f5fee41579] jit-backend-dump} +[1f5fee421af] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b667 +0 17010000 +[1f5fee43835] jit-backend-dump} +[1f5fee44261] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b671 +0 28010000 +[1f5fee457c1] jit-backend-dump} +[1f5fee461a5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b684 +0 2F010000 +[1f5fee475d3] jit-backend-dump} +[1f5fee47f57] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b695 +0 37010000 +[1f5fee4933d] jit-backend-dump} +[1f5fee49cd9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6a6 +0 3D010000 +[1f5fee4b0ad] jit-backend-dump} +[1f5fee4ba4f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6c8 +0 33010000 +[1f5fee4cf61] jit-backend-dump} +[1f5fee4dc45] jit-backend} +[1f5fee4f3a9] {jit-log-opt-loop +# Loop 1 : entry bridge with 31 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10] +debug_merge_point(0, ' #9 LOAD_FAST') ++234: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10] ++244: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10] ++262: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p10] +debug_merge_point(0, ' #12 LOAD_CONST') ++272: guard_value(p3, ConstPtr(ptr14), descr=) [p1, p0, p3, p2, p5, p8, p10] +debug_merge_point(0, ' #15 COMPARE_OP') ++291: i15 = getfield_gc_pure(p8, descr=) ++295: i17 = int_lt(i15, 10000) +guard_true(i17, descr=) [p1, p0, p8, p2, p5] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++308: i19 = int_and(i15, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++315: i20 = int_is_true(i19) +guard_false(i20, descr=) [p1, p0, p2, p5, p8, i19] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++325: i22 = int_add(i15, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++329: i24 = getfield_raw(40588192, descr=) ++337: i26 = int_sub(i24, 1) ++341: setfield_raw(40588192, i26, descr=) ++349: i28 = int_lt(i26, 0) +guard_false(i28, descr=) [p1, p0, p2, p5, i22, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++359: jump(p0, p1, p2, p5, i22, descr=) ++403: --end of the loop-- +[1f60036d952] jit-log-opt-loop} +[1f600719a74] {jit-backend +[1f600759dac] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b817 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB40B00C0A897F00004D8B334983C60149BB40B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF024C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030D00000049BB00B0A007897F000041FFD34440484C3D39030E00000049BB00B0A007897F000041FFD34440484C390707030F000000 +[1f60076fd90] jit-backend-dump} +[1f600770f30] {jit-backend-addr +Loop 2 ( #9 LOAD_FAST) has address 7f8907a0b89f to 7f8907a0b905 (bootstrap 7f8907a0b817) +[1f6007730fc] jit-backend-addr} +[1f600773fde] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b827 +0 50FFFFFF +[1f600775c76] jit-backend-dump} +[1f600776a38] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8c6 +0 95000000 +[1f600778112] jit-backend-dump} +[1f600778b8c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8d7 +0 9B000000 +[1f60077a04a] jit-backend-dump} +[1f60077aa6a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8f9 +0 91000000 +[1f60077bf10] jit-backend-dump} +[1f60077cc24] jit-backend} +[1f60077e094] {jit-log-opt-loop +# Loop 2 : loop with 25 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 2) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f6007a567c] jit-log-opt-loop} +[1f600802cd6] {jit-backend +[1f600862dd8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9b7 +0 488DA50000000049BB48B00C0A897F00004D8B3B4983C70149BB48B00C0A897F00004D893B4D89F74983C6010F80000000004C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C00000000488B0425704F3D01488D5010483B1425784F3D01761A49BB10B2A007897F000041FFD349BB8EB2A007897F000041FFD348C7009807000048891425704F3D014C89700848898550FFFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBA8F0B407897F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00100000048C7C709000000488BB550FFFFFF48C7C30000000048C7C20000000049BB31B6A007897F000041FFE349BB00B0A007897F000041FFD3444039484C3D031000000049BB00B0A007897F000041FFD34440484C39070311000000 +[1f60086ba5a] jit-backend-dump} +[1f60086d36e] {jit-backend-addr +Bridge out of guard 4 has address 7f8907a0b9b7 to 7f8907a0bab1 +[1f60086ffd2] jit-backend-addr} +[1f600870dca] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9ba +0 C0FEFFFF +[1f60087281c] jit-backend-dump} +[1f600873506] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 C8000000 +[1f600874b44] jit-backend-dump} +[1f6008754d4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0ba03 +0 C2000000 +[1f600876956] jit-backend-dump} +[1f600877b1a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 1E050000 +[1f600878f4e] jit-backend-dump} +[1f600884c12] jit-backend} +[1f60088780a] {jit-log-opt-bridge +# bridge out of Guard 4 with 16 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #31 LOAD_FAST') +debug_merge_point(0, ' #34 LOAD_CONST') +debug_merge_point(0, ' #37 INPLACE_ADD') ++37: i7 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i7, p2, p3, i5] +debug_merge_point(0, ' #38 STORE_FAST') +debug_merge_point(0, ' #41 JUMP_ABSOLUTE') ++50: i9 = getfield_raw(40588192, descr=) ++58: i11 = int_sub(i9, 1) ++62: setfield_raw(40588192, i11, descr=) ++70: i13 = int_lt(i11, 0) +guard_false(i13, descr=) [p0, p1, p2, p3, i7, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++80: p16 = new_with_vtable(ConstClass(W_IntObject)) ++143: setfield_gc(p16, i7, descr=) ++147: jump(p1, p0, p2, ConstPtr(ptr17), 0, p3, 1, 9, p16, ConstPtr(ptr21), ConstPtr(ptr22), descr=) ++250: --end of the loop-- +[1f6008aa976] jit-log-opt-bridge} +[1f600912c98] {jit-backend-counts +0:1982 +1:1985 +2:0 +3:1782 +[1f600916544] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -213,11 +213,15 @@ def test_import_log(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) + for loop in loops: + loop.force_asm() assert 'jge' in loops[0].operations[3].asm def test_import_log_2(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest2.log'))) + for loop in loops: + loop.force_asm() assert 'cmp' in loops[1].operations[1].asm # bridge - assert 'cmp' in loops[3].operations[1].asm + assert 'jo' in loops[3].operations[3].asm diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1824,6 +1824,11 @@ __gccallshapes: """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) + print >> output, """\ + #if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits + #endif + """ def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) From noreply at buildbot.pypy.org Fri Jul 22 13:42:30 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:42:30 +0200 (CEST) Subject: [pypy-commit] pypy tealet: hg merge bba99b2fc522 (from branch custom-trace) Message-ID: <20110722114230.959A082961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45878:70a2ce79f28d Date: 2011-07-22 13:35 +0200 http://bitbucket.org/pypy/pypy/changeset/70a2ce79f28d/ Log: hg merge bba99b2fc522 (from branch custom-trace) diff --git a/pypy/config/config.py b/pypy/config/config.py --- a/pypy/config/config.py +++ b/pypy/config/config.py @@ -81,6 +81,12 @@ (self.__class__, name)) return self._cfgimpl_values[name] + def __dir__(self): + from_type = dir(type(self)) + from_dict = list(self.__dict__) + extras = list(self._cfgimpl_values) + return sorted(set(extras + from_type + from_dict)) + def __delattr__(self, name): # XXX if you use delattr you are responsible for all bad things # happening diff --git a/pypy/config/test/test_config.py b/pypy/config/test/test_config.py --- a/pypy/config/test/test_config.py +++ b/pypy/config/test/test_config.py @@ -63,6 +63,20 @@ py.test.raises(ConfigError, 'config.gc.name = "ref"') config.gc.name = "framework" +def test___dir__(): + descr = make_description() + config = Config(descr, bool=False) + attrs = dir(config) + assert '__repr__' in attrs # from the type + assert '_cfgimpl_values' in attrs # from self + assert 'gc' in attrs # custom attribute + assert 'objspace' in attrs # custom attribute + # + attrs = dir(config.gc) + assert 'name' in attrs + assert 'dummy' in attrs + assert 'float' in attrs + def test_arbitrary_option(): descr = OptionDescription("top", "", [ ArbitraryOption("a", "no help", default=None) diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -144,7 +144,10 @@ ["annotate", "rtype", "backendopt", "database", "source", "pyjitpl"], default=None, cmdline="--fork-before"), - + BoolOption("dont_write_c_files", + "Make the C backend write everyting to /dev/null. " + + "Useful for benchmarking, so you don't actually involve the disk", + default=False, cmdline="--dont-write-c-files"), ArbitraryOption("instrumentctl", "internal", default=None), StrOption("output", "Output file name", cmdline="--output"), diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -31,7 +31,8 @@ _immutable_fields_ = ['code?', 'w_func_globals?', 'closure?', - 'defs_w?[*]'] + 'defs_w?[*]', + 'name?'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -5,10 +5,9 @@ from pypy.jit.codewriter import support from pypy.jit.codewriter.jitcode import JitCode -from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer -from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer -from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze -from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection +from pypy.jit.codewriter.effectinfo import (VirtualizableAnalyzer, + QuasiImmutAnalyzer, CanReleaseGILAnalyzer, effectinfo_from_writeanalyze, + EffectInfo, CallInfoCollection) from pypy.translator.simplify import get_funcobj, get_functype from pypy.rpython.lltypesystem import lltype, llmemory from pypy.translator.backendopt.canraise import RaiseAnalyzer @@ -32,6 +31,7 @@ self.readwrite_analyzer = ReadWriteAnalyzer(translator) self.virtualizable_analyzer = VirtualizableAnalyzer(translator) self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator) + self.canreleasegil_analyzer = CanReleaseGILAnalyzer(translator) # for index, jd in enumerate(jitdrivers_sd): jd.index = index @@ -219,7 +219,9 @@ assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect - can_invalidate = self.quasiimmut_analyzer.analyze(op) + can_release_gil = self.canreleasegil_analyzer.analyze(op) + # can_release_gil implies can_invalidate + can_invalidate = can_release_gil or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE @@ -235,7 +237,7 @@ # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, - oopspecindex, can_invalidate) + oopspecindex, can_invalidate, can_release_gil) # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -79,13 +79,15 @@ write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, - can_invalidate=False): + can_invalidate=False, can_release_gil=False): key = (frozenset(readonly_descrs_fields), frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, - oopspecindex) + oopspecindex, + can_invalidate, + can_release_gil) if key in cls._cache: return cls._cache[key] result = object.__new__(cls) @@ -100,6 +102,7 @@ result.write_descrs_arrays = write_descrs_arrays result.extraeffect = extraeffect result.can_invalidate = can_invalidate + result.can_release_gil = can_release_gil result.oopspecindex = oopspecindex cls._cache[key] = result return result @@ -111,12 +114,13 @@ return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE def has_random_effects(self): - return self.oopspecindex == self.OS_LIBFFI_CALL + return self.oopspecindex == self.OS_LIBFFI_CALL or self.can_release_gil def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, - can_invalidate=False): + can_invalidate=False, + can_release_gil=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: return None @@ -158,7 +162,8 @@ write_descrs_arrays, extraeffect, oopspecindex, - can_invalidate) + can_invalidate, + can_release_gil) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: @@ -194,6 +199,16 @@ def analyze_simple_operation(self, op, graphinfo): return op.opname == 'jit_force_quasi_immutable' +class CanReleaseGILAnalyzer(BoolGraphAnalyzer): + def analyze_direct_call(self, graph, seen=None): + releases_gil = False + if hasattr(graph, "func") and hasattr(graph.func, "_ptr"): + releases_gil = graph.func._ptr._obj.releases_gil + return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen) + + def analyze_simple_operation(self, op, graphinfo): + return False + # ____________________________________________________________ class CallInfoCollection(object): diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -395,7 +395,7 @@ ('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed), ('int_abs', [lltype.Signed], lltype.Signed), ('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float), - ] +] class LLtypeHelpers: diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py --- a/pypy/jit/codewriter/test/test_call.py +++ b/pypy/jit/codewriter/test/test_call.py @@ -1,6 +1,6 @@ import py from pypy.objspace.flow.model import SpaceOperation, Constant, Variable -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.unsimplify import varoftype from pypy.rlib import jit from pypy.jit.codewriter.call import CallControl @@ -171,3 +171,24 @@ def test_jit_force_virtualizable_effectinfo(): py.test.skip("XXX add a test for CallControl.getcalldescr() -> EF_xxx") + +def test_releases_gil_analyzer(): + from pypy.jit.backend.llgraph.runner import LLtypeCPU + + T = rffi.CArrayPtr(rffi.TIME_T) + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + + @jit.dont_look_inside + def f(): + return external(lltype.nullptr(T.TO)) + + rtyper = support.annotate(f, []) + jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) + cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) + res = cc.find_all_graphs(FakePolicy()) + + [f_graph] = [x for x in res if x.func is f] + [block, _] = list(f_graph.iterblocks()) + [op] = block.operations + call_descr = cc.getcalldescr(op) + assert call_descr.extrainfo.can_release_gil \ No newline at end of file diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -61,7 +61,6 @@ optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble, retraced) - if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -390,8 +390,21 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): - return self.execute_with_descr(rop.GETARRAYITEM_GC, + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache and isinstance(indexbox, ConstInt): + index = indexbox.getint() + frombox, tobox = cache.get(index, (None, None)) + if frombox is arraybox: + return tobox + resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) + if isinstance(indexbox, ConstInt): + if not cache: + cache = self.metainterp.heap_array_cache[arraydescr] = {} + index = indexbox.getint() + cache[index] = arraybox, resbox + return resbox + opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any @@ -419,6 +432,13 @@ indexbox, itembox): self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, itembox) + if isinstance(indexbox, ConstInt): + cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {}) + cache[indexbox.getint()] = arraybox, itembox + else: + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache: + cache.clear() opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any @@ -454,21 +474,17 @@ def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, - sbox, sizebox) + self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox) abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, sizebox) - self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, - sbox, abox) + self._opimpl_setfield_gc_any(sbox, itemsdescr, abox) return sbox @arguments("box", "descr", "descr", "box") def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox) opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any @@ -477,10 +493,9 @@ @arguments("box", "descr", "descr", "box", "box") def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, - indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox, + valuebox) opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any @@ -502,18 +517,29 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC, box, fielddescr) opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @arguments("box", "descr") def _opimpl_getfield_gc_pure_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_PURE, box, fielddescr) opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any + @specialize.arg(1) + def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(opnum, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox + @arguments("orgpc", "box", "descr") def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr): ginfo = self.metainterp.jitdriver_sd.greenfield_info @@ -532,7 +558,11 @@ @arguments("box", "descr", "box") def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box and tobox is valuebox: + return self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + self.metainterp.heap_cache[fielddescr] = (box, valuebox) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any @@ -617,7 +647,7 @@ @arguments("orgpc", "box", "descr") def _opimpl_getfield_vable(self, pc, box, fielddescr): if self._nonstandard_virtualizable(pc, box): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any(box, fielddescr) self.metainterp.check_synchronized_virtualizable() index = self._get_virtualizable_field_index(fielddescr) return self.metainterp.virtualizable_boxes[index] @@ -629,8 +659,7 @@ @arguments("orgpc", "box", "descr", "box") def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox): if self._nonstandard_virtualizable(pc, box): - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) - return + return self._opimpl_setfield_gc_any(box, fielddescr, valuebox) index = self._get_virtualizable_field_index(fielddescr) self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -660,10 +689,8 @@ @arguments("orgpc", "box", "descr", "descr", "box") def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr, - arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox) self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) return self.metainterp.virtualizable_boxes[index] @@ -676,10 +703,9 @@ def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox, valuebox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - self.execute_with_descr(rop.SETARRAYITEM_GC, adescr, - arraybox, indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + self._opimpl_setarrayitem_gc_any(arraybox, adescr, + indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -693,8 +719,7 @@ @arguments("orgpc", "box", "descr", "descr") def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -1462,6 +1487,12 @@ self.known_class_boxes = {} # contains frame boxes that are not virtualizables self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1637,10 +1668,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1804,6 +1852,8 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} + self.heap_array_cache = {} duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), @@ -2311,6 +2361,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -11,7 +11,7 @@ from pypy import conftest from pypy.rlib.rarithmetic import ovfcheck from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -1024,69 +1024,6 @@ res = self.meta_interp(main, []) assert res == 55 - def test_dont_record_repeated_guard_class(self): - class A: - pass - class B(A): - pass - @dont_look_inside - def extern(n): - if n == -7: - return None - elif n: - return A() - else: - return B() - def fn(n): - obj = extern(n) - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=1, guard_nonnull=1) - res = self.interp_operations(fn, [1]) - assert not res - - def test_dont_record_guard_class_after_new(self): - class A: - pass - class B(A): - pass - def fn(n): - if n == -7: - obj = None - elif n: - obj = A() - else: - obj = B() - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=0, guard_nonnull=0) - res = self.interp_operations(fn, [1]) - assert not res - - def test_guard_isnull_nullifies(self): - class A: - pass - a = A() - a.x = None - def fn(n): - if n == -7: - a.x = "" - obj = a.x - res = 0 - if not obj: - res += 1 - if obj: - res += 1 - if obj is None: - res += 1 - if obj is not None: - res += 1 - return res - res = self.interp_operations(fn, [0]) - assert res == 2 - self.check_operations_history(guard_isnull=1) def test_assert_isinstance(self): class A: @@ -1248,7 +1185,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: @@ -1616,8 +1553,6 @@ assert res == 1 def test_raw_malloc_and_access(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Signed) def f(n): @@ -1631,8 +1566,6 @@ assert res == 10 def test_raw_malloc_and_access_float(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Float) def f(n, f): @@ -2619,5 +2552,41 @@ self.meta_interp(f, [], enable_opts='') self.check_loops(new_with_vtable=1) + def test_release_gil_flush_heap_cache(self): + T = rffi.CArrayPtr(rffi.TIME_T) + + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + # Not a real lock, has all the same properties with respect to GIL + # release though, so good for this test. + class Lock(object): + @dont_look_inside + def acquire(self): + external(lltype.nullptr(T.TO)) + @dont_look_inside + def release(self): + external(lltype.nullptr(T.TO)) + class X(object): + def __init__(self, idx): + self.field = idx + @dont_look_inside + def get_obj(z): + return X(z) + myjitdriver = JitDriver(greens=[], reds=["n", "l", "z", "lock"]) + def f(n, z): + lock = Lock() + l = 0 + while n > 0: + myjitdriver.jit_merge_point(lock=lock, l=l, n=n, z=z) + x = get_obj(z) + l += x.field + lock.acquire() + # This must not reuse the previous one. + n -= x.field + lock.release() + return n + res = self.meta_interp(f, [10, 1]) + self.check_loops(getfield_gc=2) + + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,407 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + l = [1] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * (4 + a) + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + len(frame.l) + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -268,3 +268,7 @@ if errors: w_errors = space.wrap(rffi.charp2str(errors)) return space.call_method(w_str, 'encode', w_encoding, w_errors) + + at cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -287,3 +287,9 @@ def test_eq(self, space, api): assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'ab' diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -23,6 +23,9 @@ 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'sin': 'interp_ufuncs.sin', + 'cos': 'interp_ufuncs.cos', + 'tan': 'interp_ufuncs.tan', } appleveldefs = { diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,7 +2,9 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit +from pypy.rlib.rfloat import DTSF_STR_PRECISION from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name import math @@ -55,6 +57,9 @@ def minimum(v1, v2): return min(v1, v2) +def float2string(x): + return float2string_orig(x, 'g', DTSF_STR_PRECISION) + class BaseArray(Wrappable): def __init__(self): self.invalidates = [] @@ -235,6 +240,24 @@ else: return self.descr_mul(space, w_other) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] + nums.append("..." + "," * comma) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) + else: + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] + return nums + def get_concrete(self): raise NotImplementedError @@ -245,10 +268,14 @@ return self.get_concrete().descr_len(space) def descr_repr(self, space): - return self.get_concrete()._repr(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])") def descr_str(self, space): - return self.get_concrete()._str(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("[" + " ".join(concrete._getnums(True)) + "]") def descr_getitem(self, space, w_idx): # TODO: indexing by tuples @@ -439,26 +466,6 @@ def calc_index(self, item): return (self.start + item * self.step) - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - class SingleDimArray(BaseArray): signature = Signature() @@ -496,26 +503,6 @@ def getitem(self, item): return self.storage[item] - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - @unwrap_spec(item=int, value=float) def descr_setitem(self, space, item, value): item = self.getindex(space, item) diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -74,3 +74,15 @@ if value == 0.0: return 0.0 return rfloat.copysign(1.0, value) + + at ufunc +def sin(value): + return math.sin(value) + + at ufunc +def cos(value): + return math.cos(value) + + at ufunc +def tan(value): + return math.tan(value) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -133,3 +133,30 @@ except OverflowError: res = float('inf') assert b[i] == res + + def test_sin(self): + import math + from numpy import array, sin + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = sin(a) + for i in range(len(a)): + assert b[i] == math.sin(a[i]) + + def test_cos(self): + import math + from numpy import array, cos + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = cos(a) + for i in range(len(a)): + assert b[i] == math.cos(a[i]) + + def test_tan(self): + import math + from numpy import array, tan + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = tan(a) + for i in range(len(a)): + assert b[i] == math.tan(a[i]) diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -133,8 +133,7 @@ else: return space.wrap("0x%sp%s%d" % (s, sign, exp)) -def float2string(space, w_float, code, precision): - x = w_float.floatval +def float2string(x, code, precision): # we special-case explicitly inf and nan here if isfinite(x): s = formatd(x, code, precision, DTSF_ADD_DOT_0) @@ -145,13 +144,13 @@ s = "-inf" else: # isnan(x): s = "nan" - return space.wrap(s) + return s def repr__Float(space, w_float): - return float2string(space, w_float, 'r', 0) + return space.wrap(float2string(w_float.floatval, 'r', 0)) def str__Float(space, w_float): - return float2string(space, w_float, 'g', DTSF_STR_PRECISION) + return space.wrap(float2string(w_float.floatval, 'g', DTSF_STR_PRECISION)) def format__Float_ANY(space, w_float, w_spec): return newformat.run_formatter(space, w_spec, "format_float", w_float) diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -362,7 +362,8 @@ about=self)._obj Struct._install_extras(self, **kwds) - def _attach_runtime_type_info_funcptr(self, funcptr, destrptr): + def _attach_runtime_type_info_funcptr(self, funcptr, destrptr, + customtraceptr): if self._runtime_type_info is None: raise TypeError("attachRuntimeTypeInfo: %r must have been built " "with the rtti=True argument" % (self,)) @@ -376,7 +377,7 @@ raise TypeError("expected a runtime type info function " "implementation, got: %s" % funcptr) self._runtime_type_info.query_funcptr = funcptr - if destrptr is not None : + if destrptr is not None: T = typeOf(destrptr) if (not isinstance(T, Ptr) or not isinstance(T.TO, FuncType) or @@ -386,6 +387,18 @@ raise TypeError("expected a destructor function " "implementation, got: %s" % destrptr) self._runtime_type_info.destructor_funcptr = destrptr + if customtraceptr is not None: + from pypy.rpython.lltypesystem import llmemory + T = typeOf(customtraceptr) + if (not isinstance(T, Ptr) or + not isinstance(T.TO, FuncType) or + len(T.TO.ARGS) != 2 or + T.TO.RESULT != llmemory.Address or + T.TO.ARGS[0] != llmemory.Address or + T.TO.ARGS[1] != llmemory.Address): + raise TypeError("expected a custom trace function " + "implementation, got: %s" % customtraceptr) + self._runtime_type_info.custom_trace_funcptr = customtraceptr class GcStruct(RttiStruct): _gckind = 'gc' @@ -2039,10 +2052,12 @@ raise ValueError("only odd integers can be cast back to ptr") return _ptr(PTRTYPE, oddint, solid=True) -def attachRuntimeTypeInfo(GCSTRUCT, funcptr=None, destrptr=None): +def attachRuntimeTypeInfo(GCSTRUCT, funcptr=None, destrptr=None, + customtraceptr=None): if not isinstance(GCSTRUCT, RttiStruct): raise TypeError, "expected a RttiStruct: %s" % GCSTRUCT - GCSTRUCT._attach_runtime_type_info_funcptr(funcptr, destrptr) + GCSTRUCT._attach_runtime_type_info_funcptr(funcptr, destrptr, + customtraceptr) return _ptr(Ptr(RuntimeTypeInfo), GCSTRUCT._runtime_type_info) def getRuntimeTypeInfo(GCSTRUCT): diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -69,8 +69,6 @@ [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) -math_log = llexternal('log', [rffi.DOUBLE], rffi.DOUBLE) -math_log10 = llexternal('log10', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -222,10 +220,6 @@ return (fracpart, intpart) -def ll_math_copysign(x, y): - return math_copysign(x, y) # no error checking needed - - def ll_math_fmod(x, y): if isinf(y): if isinf(x): diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -102,19 +102,6 @@ else: callbackholder = None - funcptr = lltype.functionptr(ext_type, name, external='C', - compilation_info=compilation_info, - _callable=_callable, - _safe_not_sandboxed=sandboxsafe, - _debugexc=True, # on top of llinterp - canraise=False, - **kwds) - if isinstance(_callable, ll2ctypes.LL2CtypesCallable): - _callable.funcptr = funcptr - - if _nowrapper: - return funcptr - if threadsafe in (False, True): # invoke the around-handlers, which release the GIL, if and only if # the C function is thread-safe. @@ -125,6 +112,21 @@ # sandboxsafe is a hint for "too-small-ness" (e.g. math functions). invoke_around_handlers = not sandboxsafe + funcptr = lltype.functionptr(ext_type, name, external='C', + compilation_info=compilation_info, + _callable=_callable, + _safe_not_sandboxed=sandboxsafe, + _debugexc=True, # on top of llinterp + canraise=False, + releases_gil=invoke_around_handlers, + **kwds) + if isinstance(_callable, ll2ctypes.LL2CtypesCallable): + _callable.funcptr = funcptr + + if _nowrapper: + return funcptr + + if invoke_around_handlers: # The around-handlers are releasing the GIL in a threaded pypy. # We need tons of care to ensure that no GC operation and no diff --git a/pypy/rpython/memory/gc/base.py b/pypy/rpython/memory/gc/base.py --- a/pypy/rpython/memory/gc/base.py +++ b/pypy/rpython/memory/gc/base.py @@ -69,7 +69,10 @@ varsize_offsets_to_gcpointers_in_var_part, weakpointer_offset, member_index, - is_rpython_class): + is_rpython_class, + has_custom_trace, + get_custom_trace, + fast_path_tracing): self.getfinalizer = getfinalizer self.is_varsize = is_varsize self.has_gcptr_in_varsize = has_gcptr_in_varsize @@ -83,6 +86,9 @@ self.weakpointer_offset = weakpointer_offset self.member_index = member_index self.is_rpython_class = is_rpython_class + self.has_custom_trace = has_custom_trace + self.get_custom_trace = get_custom_trace + self.fast_path_tracing = fast_path_tracing def get_member_index(self, type_id): return self.member_index(type_id) @@ -181,8 +187,14 @@ Typically, 'callback' is a bound method and 'arg' can be None. """ typeid = self.get_type_id(obj) + # + # First, look if we need more than the simple fixed-size tracing + if not self.fast_path_tracing(typeid): + # + # Yes. Two cases: either we are just a GcArray(gcptr), for + # which we have a special case for performance, or we call + # the slow path version. if self.is_gcarrayofgcptr(typeid): - # a performance shortcut for GcArray(gcptr) length = (obj + llmemory.gcarrayofptr_lengthoffset).signed[0] item = obj + llmemory.gcarrayofptr_itemsoffset while length > 0: @@ -191,6 +203,9 @@ item += llmemory.gcarrayofptr_singleitemoffset length -= 1 return + self._trace_slow_path(obj, callback, arg) + # + # Do the tracing on the fixed-size part of the object. offsets = self.offsets_to_gc_pointers(typeid) i = 0 while i < len(offsets): @@ -198,6 +213,10 @@ if self.points_to_valid_gc_object(item): callback(item, arg) i += 1 + trace._annspecialcase_ = 'specialize:arg(2)' + + def _trace_slow_path(self, obj, callback, arg): + typeid = self.get_type_id(obj) if self.has_gcptr_in_varsize(typeid): item = obj + self.varsize_offset_to_variable_part(typeid) length = (obj + self.varsize_offset_to_length(typeid)).signed[0] @@ -212,7 +231,16 @@ j += 1 item += itemlength length -= 1 - trace._annspecialcase_ = 'specialize:arg(2)' + if self.has_custom_trace(typeid): + generator = self.get_custom_trace(typeid) + item = llmemory.NULL + while True: + item = generator(obj, item) + if not item: + break + if self.points_to_valid_gc_object(item): + callback(item, arg) + _trace_slow_path._annspecialcase_ = 'specialize:arg(2)' def trace_partial(self, obj, start, stop, callback, arg): """Like trace(), but only walk the array part, for indices in @@ -317,7 +345,7 @@ break obj = self.run_finalizers.popleft() finalizer = self.getfinalizer(self.get_type_id(obj)) - finalizer(obj) + finalizer(obj, llmemory.NULL) finally: self.finalizer_lock_count -= 1 diff --git a/pypy/rpython/memory/gc/markcompact.py b/pypy/rpython/memory/gc/markcompact.py --- a/pypy/rpython/memory/gc/markcompact.py +++ b/pypy/rpython/memory/gc/markcompact.py @@ -88,6 +88,9 @@ def __init__(self, config, space_size=4096, min_next_collect_after=128, **kwds): + import py + py.test.skip("the 'markcompact' gc needs fixing for custom tracers") + # MovingGCBase.__init__(self, config, **kwds) self.space_size = space_size self.min_next_collect_after = min_next_collect_after diff --git a/pypy/rpython/memory/gc/marksweep.py b/pypy/rpython/memory/gc/marksweep.py --- a/pypy/rpython/memory/gc/marksweep.py +++ b/pypy/rpython/memory/gc/marksweep.py @@ -450,7 +450,7 @@ hdr.next = self.malloced_objects self.malloced_objects = hdr #llop.debug_view(lltype.Void, self.malloced_objects, self.malloced_objects_with_finalizer, size_gc_header) - finalizer(obj) + finalizer(obj, llmemory.NULL) if not self.collect_in_progress: # another collection was caused? debug_print("outer collect interrupted " "by recursive collect") diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -1668,7 +1668,7 @@ None) # we don't need the static in all prebuilt gc objects # # If we are in an inner collection caused by a call to a finalizer, - # the 'run_finalizers' objects also need to kept alive. + # the 'run_finalizers' objects also need to be kept alive. self.run_finalizers.foreach(self._collect_obj, self.objects_to_trace) diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py --- a/pypy/rpython/memory/gctransform/asmgcroot.py +++ b/pypy/rpython/memory/gctransform/asmgcroot.py @@ -233,7 +233,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.aid2stack = copy_without_null_values(gcdata.aid2stack) + copy = copy_without_null_values(gcdata.aid2stack) + gcdata.aid2stack.delete() + gcdata.aid2stack = copy def belongs_to_current_thread(framedata): # xxx obscure: the answer is Yes if, as a pointer, framedata diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -531,8 +531,8 @@ # this method is attached to the instance and redirects to # layoutbuilder.get_type_id(). - def finalizer_funcptr_for_type(self, TYPE): - return self.layoutbuilder.finalizer_funcptr_for_type(TYPE) + def special_funcptr_for_type(self, TYPE): + return self.layoutbuilder.special_funcptr_for_type(TYPE) def gc_header_for(self, obj, needs_hash=False): hdr = self.gcdata.gc.gcheaderbuilder.header_of_object(obj) @@ -675,7 +675,9 @@ c_type_id = rmodel.inputconst(TYPE_ID, type_id) info = self.layoutbuilder.get_info(type_id) c_size = rmodel.inputconst(lltype.Signed, info.fixedsize) - has_finalizer = bool(self.finalizer_funcptr_for_type(TYPE)) + kind_and_fptr = self.special_funcptr_for_type(TYPE) + has_finalizer = (kind_and_fptr is not None and + kind_and_fptr[0] == "finalizer") c_has_finalizer = rmodel.inputconst(lltype.Bool, has_finalizer) if not op.opname.endswith('_varsize') and not flags.get('varsize'): @@ -1251,28 +1253,39 @@ def has_finalizer(self, TYPE): rtti = get_rtti(TYPE) - return rtti is not None and hasattr(rtti._obj, 'destructor_funcptr') + return rtti is not None and getattr(rtti._obj, 'destructor_funcptr', + None) + + def has_custom_trace(self, TYPE): + rtti = get_rtti(TYPE) + return rtti is not None and getattr(rtti._obj, 'custom_trace_funcptr', + None) def make_finalizer_funcptr_for_type(self, TYPE): - if self.has_finalizer(TYPE): + if not self.has_finalizer(TYPE): + return None rtti = get_rtti(TYPE) destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] - else: - destrptr = None - DESTR_ARG = None - assert not type_contains_pyobjs(TYPE), "not implemented" - if destrptr: typename = TYPE.__name__ - def ll_finalizer(addr): + def ll_finalizer(addr, ignored): v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) ll_call_destructor(destrptr, v, typename) + return llmemory.NULL fptr = self.transformer.annotate_finalizer(ll_finalizer, - [llmemory.Address], - lltype.Void) - else: - fptr = lltype.nullptr(gctypelayout.GCData.FINALIZERTYPE.TO) + [llmemory.Address, llmemory.Address], llmemory.Address) + return fptr + + def make_custom_trace_funcptr_for_type(self, TYPE): + if not self.has_custom_trace(TYPE): + return None + rtti = get_rtti(TYPE) + fptr = rtti._obj.custom_trace_funcptr + if not hasattr(fptr._obj, 'graph'): + ll_func = fptr._obj._callable + fptr = self.transformer.annotate_finalizer(ll_func, + [llmemory.Address, llmemory.Address], llmemory.Address) return fptr @@ -1519,8 +1532,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.thread_stacks = copy_without_null_values( - gcdata.thread_stacks) + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy def switch_shadow_stacks(new_aid): save_away_current_stack() diff --git a/pypy/rpython/memory/gctypelayout.py b/pypy/rpython/memory/gctypelayout.py --- a/pypy/rpython/memory/gctypelayout.py +++ b/pypy/rpython/memory/gctypelayout.py @@ -17,13 +17,21 @@ _alloc_flavor_ = 'raw' OFFSETS_TO_GC_PTR = lltype.Array(lltype.Signed) - ADDRESS_VOID_FUNC = lltype.FuncType([llmemory.Address], lltype.Void) - FINALIZERTYPE = lltype.Ptr(ADDRESS_VOID_FUNC) + + # When used as a finalizer, the following functions only take one + # address and ignore the second, and return NULL. When used as a + # custom tracer (CT), it enumerates the addresses that contain GCREFs. + # It is called with the object as first argument, and the previous + # returned address (or NULL the first time) as the second argument. + FINALIZER_OR_CT_FUNC = lltype.FuncType([llmemory.Address, + llmemory.Address], + llmemory.Address) + FINALIZER_OR_CT = lltype.Ptr(FINALIZER_OR_CT_FUNC) # structure describing the layout of a typeid TYPE_INFO = lltype.Struct("type_info", ("infobits", lltype.Signed), # combination of the T_xxx consts - ("finalizer", FINALIZERTYPE), + ("finalizer_or_customtrace", FINALIZER_OR_CT), ("fixedsize", lltype.Signed), ("ofstoptrs", lltype.Ptr(OFFSETS_TO_GC_PTR)), hints={'immutable': True}, @@ -71,7 +79,11 @@ return (infobits & T_IS_GCARRAY_OF_GCPTR) != 0 def q_finalizer(self, typeid): - return self.get(typeid).finalizer + typeinfo = self.get(typeid) + if typeinfo.infobits & T_HAS_FINALIZER: + return typeinfo.finalizer_or_customtrace + else: + return lltype.nullptr(GCData.FINALIZER_OR_CT_FUNC) def q_offsets_to_gc_pointers(self, typeid): return self.get(typeid).ofstoptrs @@ -105,6 +117,25 @@ infobits = self.get(typeid).infobits return infobits & T_IS_RPYTHON_INSTANCE != 0 + def q_has_custom_trace(self, typeid): + infobits = self.get(typeid).infobits + return infobits & T_HAS_CUSTOM_TRACE != 0 + + def q_get_custom_trace(self, typeid): + ll_assert(self.q_has_custom_trace(typeid), + "T_HAS_CUSTOM_TRACE missing") + typeinfo = self.get(typeid) + return typeinfo.finalizer_or_customtrace + + def q_fast_path_tracing(self, typeid): + # return True if none of the flags T_HAS_GCPTR_IN_VARSIZE, + # T_IS_GCARRAY_OF_GCPTR or T_HAS_CUSTOM_TRACE is set + T_ANY_SLOW_FLAG = (T_HAS_GCPTR_IN_VARSIZE | + T_IS_GCARRAY_OF_GCPTR | + T_HAS_CUSTOM_TRACE) + infobits = self.get(typeid).infobits + return infobits & T_ANY_SLOW_FLAG == 0 + def set_query_functions(self, gc): gc.set_query_functions( self.q_is_varsize, @@ -119,18 +150,23 @@ self.q_varsize_offsets_to_gcpointers_in_var_part, self.q_weakpointer_offset, self.q_member_index, - self.q_is_rpython_class) + self.q_is_rpython_class, + self.q_has_custom_trace, + self.q_get_custom_trace, + self.q_fast_path_tracing) # the lowest 16bits are used to store group member index T_MEMBER_INDEX = 0xffff -T_IS_VARSIZE = 0x10000 -T_HAS_GCPTR_IN_VARSIZE = 0x20000 -T_IS_GCARRAY_OF_GCPTR = 0x40000 -T_IS_WEAKREF = 0x80000 +T_IS_VARSIZE = 0x010000 +T_HAS_GCPTR_IN_VARSIZE = 0x020000 +T_IS_GCARRAY_OF_GCPTR = 0x040000 +T_IS_WEAKREF = 0x080000 T_IS_RPYTHON_INSTANCE = 0x100000 # the type is a subclass of OBJECT +T_HAS_FINALIZER = 0x200000 +T_HAS_CUSTOM_TRACE = 0x400000 T_KEY_MASK = intmask(0xFF000000) -T_KEY_VALUE = intmask(0x7A000000) # bug detection only +T_KEY_VALUE = intmask(0x5A000000) # bug detection only def _check_valid_type_info(p): ll_assert(p.infobits & T_KEY_MASK == T_KEY_VALUE, "invalid type_id") @@ -151,7 +187,18 @@ offsets = offsets_to_gc_pointers(TYPE) infobits = index info.ofstoptrs = builder.offsets2table(offsets, TYPE) - info.finalizer = builder.make_finalizer_funcptr_for_type(TYPE) + # + kind_and_fptr = builder.special_funcptr_for_type(TYPE) + if kind_and_fptr is not None: + kind, fptr = kind_and_fptr + info.finalizer_or_customtrace = fptr + if kind == "finalizer": + infobits |= T_HAS_FINALIZER + elif kind == "custom_trace": + infobits |= T_HAS_CUSTOM_TRACE + else: + assert 0, kind + # if not TYPE._is_varsize(): info.fixedsize = llarena.round_up_for_allocation( llmemory.sizeof(TYPE), builder.GCClass.object_minimal_size) @@ -216,7 +263,7 @@ # for debugging, the following list collects all the prebuilt # GcStructs and GcArrays self.all_prebuilt_gc = [] - self.finalizer_funcptrs = {} + self._special_funcptrs = {} self.offsettable_cache = {} def make_type_info_group(self): @@ -317,16 +364,29 @@ self.offsettable_cache = None return self.type_info_group - def finalizer_funcptr_for_type(self, TYPE): - if TYPE in self.finalizer_funcptrs: - return self.finalizer_funcptrs[TYPE] - fptr = self.make_finalizer_funcptr_for_type(TYPE) - self.finalizer_funcptrs[TYPE] = fptr - return fptr + def special_funcptr_for_type(self, TYPE): + if TYPE in self._special_funcptrs: + return self._special_funcptrs[TYPE] + fptr1 = self.make_finalizer_funcptr_for_type(TYPE) + fptr2 = self.make_custom_trace_funcptr_for_type(TYPE) + assert not (fptr1 and fptr2), ( + "type %r needs both a finalizer and a custom tracer" % (TYPE,)) + if fptr1: + kind_and_fptr = "finalizer", fptr1 + elif fptr2: + kind_and_fptr = "custom_trace", fptr2 + else: + kind_and_fptr = None + self._special_funcptrs[TYPE] = kind_and_fptr + return kind_and_fptr def make_finalizer_funcptr_for_type(self, TYPE): # must be overridden for proper finalizer support - return lltype.nullptr(GCData.ADDRESS_VOID_FUNC) + return None + + def make_custom_trace_funcptr_for_type(self, TYPE): + # must be overridden for proper custom tracer support + return None def initialize_gc_query_function(self, gc): return GCData(self.type_info_group).set_query_functions(gc) diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py --- a/pypy/rpython/memory/gcwrapper.py +++ b/pypy/rpython/memory/gcwrapper.py @@ -196,17 +196,28 @@ DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] destrgraph = destrptr._obj.graph else: - return lltype.nullptr(gctypelayout.GCData.FINALIZERTYPE.TO) + return None assert not type_contains_pyobjs(TYPE), "not implemented" - def ll_finalizer(addr): + def ll_finalizer(addr, dummy): + assert dummy == llmemory.NULL try: v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) self.llinterp.eval_graph(destrgraph, [v], recursive=True) except llinterp.LLException: raise RuntimeError( "a finalizer raised an exception, shouldn't happen") - return llhelper(gctypelayout.GCData.FINALIZERTYPE, ll_finalizer) + return llmemory.NULL + return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer) + + def make_custom_trace_funcptr_for_type(self, TYPE): + from pypy.rpython.memory.gctransform.support import get_rtti, \ + type_contains_pyobjs + rtti = get_rtti(TYPE) + if rtti is not None and hasattr(rtti._obj, 'custom_trace_funcptr'): + return rtti._obj.custom_trace_funcptr + else: + return None def collect_constants(graphs): diff --git a/pypy/rpython/memory/test/test_gc.py b/pypy/rpython/memory/test/test_gc.py --- a/pypy/rpython/memory/test/test_gc.py +++ b/pypy/rpython/memory/test/test_gc.py @@ -237,6 +237,46 @@ res = self.interpret(f, [5]) assert 160 <= res <= 165 + def test_custom_trace(self): + from pypy.rpython.annlowlevel import llhelper + from pypy.rpython.lltypesystem import llmemory + from pypy.rpython.lltypesystem.llarena import ArenaError + # + S = lltype.GcStruct('S', ('x', llmemory.Address), + ('y', llmemory.Address), rtti=True) + T = lltype.GcStruct('T', ('z', lltype.Signed)) + offset_of_x = llmemory.offsetof(S, 'x') + def customtrace(obj, prev): + if not prev: + return obj + offset_of_x + else: + return llmemory.NULL + CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], + llmemory.Address) + customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) + lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr) + # + for attrname in ['x', 'y']: + def setup(): + s1 = lltype.malloc(S) + tx = lltype.malloc(T) + tx.z = 42 + ty = lltype.malloc(T) + s1.x = llmemory.cast_ptr_to_adr(tx) + s1.y = llmemory.cast_ptr_to_adr(ty) + return s1 + def f(): + s1 = setup() + llop.gc__collect(lltype.Void) + return llmemory.cast_adr_to_ptr(getattr(s1, attrname), + lltype.Ptr(T)) + if attrname == 'x': + res = self.interpret(f, []) + assert res.z == 42 + else: + py.test.raises((RuntimeError, ArenaError), + self.interpret, f, []) + def test_weakref(self): import weakref, gc class A(object): diff --git a/pypy/rpython/memory/test/test_transformed_gc.py b/pypy/rpython/memory/test/test_transformed_gc.py --- a/pypy/rpython/memory/test/test_transformed_gc.py +++ b/pypy/rpython/memory/test/test_transformed_gc.py @@ -410,6 +410,40 @@ res = run([5, 42]) #XXX pure lazyness here too assert 160 <= res <= 165 + def define_custom_trace(cls): + from pypy.rpython.annlowlevel import llhelper + from pypy.rpython.lltypesystem import llmemory + # + S = lltype.GcStruct('S', ('x', llmemory.Address), rtti=True) + T = lltype.GcStruct('T', ('z', lltype.Signed)) + offset_of_x = llmemory.offsetof(S, 'x') + def customtrace(obj, prev): + if not prev: + return obj + offset_of_x + else: + return llmemory.NULL + CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], + llmemory.Address) + customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) + lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr) + # + def setup(): + s1 = lltype.malloc(S) + tx = lltype.malloc(T) + tx.z = 4243 + s1.x = llmemory.cast_ptr_to_adr(tx) + return s1 + def f(): + s1 = setup() + llop.gc__collect(lltype.Void) + return llmemory.cast_adr_to_ptr(s1.x, lltype.Ptr(T)).z + return f + + def test_custom_trace(self): + run = self.runner("custom_trace") + res = run([]) + assert res == 4243 + def define_weakref(cls): import weakref, gc class A(object): diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -148,7 +148,7 @@ operations[0].getarg(1)) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) diff --git a/pypy/tool/nullpath.py b/pypy/tool/nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/nullpath.py @@ -0,0 +1,12 @@ +import py + +class NullPyPathLocal(py.path.local): + + def join(self, *args): + return self.__class__(py.path.local.join(self, *args)) + + def open(self, mode): + return open('/dev/null', mode) + + def __repr__(self): + return py.path.local.__repr__(self) + ' [fake]' diff --git a/pypy/tool/test/test_nullpath.py b/pypy/tool/test/test_nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/test/test_nullpath.py @@ -0,0 +1,16 @@ +import sys +import py +from pypy.tool.nullpath import NullPyPathLocal + +def setup_module(): + if 'posix' not in sys.builtin_module_names: + py.test.skip('posix only') + +def test_nullpath(tmpdir): + path = NullPyPathLocal(tmpdir) + assert repr(path).endswith('[fake]') + foo_txt = path.join('foo.txt') + assert isinstance(foo_txt, NullPyPathLocal) + # + f = foo_txt.open('w') + assert f.name == '/dev/null' diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -320,8 +320,10 @@ # still important to see it so that it can be followed as soon as # the mixlevelannotator resolves it. gctransf = self.db.gctransformer - fptr = gctransf.finalizer_funcptr_for_type(structdefnode.STRUCT) - self.db.get(fptr) + TYPE = structdefnode.STRUCT + kind_and_fptr = gctransf.special_funcptr_for_type(TYPE) + if kind_and_fptr: + self.db.get(kind_and_fptr[1]) def array_setup(self, arraydefnode): pass diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -13,6 +13,7 @@ from pypy.rpython.typesystem import getfunctionptr from pypy.translator.c import gc from pypy.rlib import exports +from pypy.tool.nullpath import NullPyPathLocal def import_module_from_directory(dir, modname): file, pathname, description = imp.find_module(modname, [str(dir)]) @@ -237,6 +238,8 @@ self.modulename = uniquemodulename('testing') modulename = self.modulename targetdir = udir.ensure(modulename, dir=1) + if self.config.translation.dont_write_c_files: + targetdir = NullPyPathLocal(targetdir) self.targetdir = targetdir defines = defines.copy() @@ -248,12 +251,8 @@ CBuilder.have___thread = self.translator.platform.check___thread() if not self.standalone: assert not self.config.translation.instrument - self.eci, cfile, extra = gen_source(db, modulename, targetdir, - self.eci, - defines = defines, - split=self.split) else: - pfname = db.get(pf) + defines['PYPY_STANDALONE'] = db.get(pf) if self.config.translation.instrument: defines['INSTRUMENT'] = 1 if CBuilder.have___thread: @@ -263,11 +262,9 @@ defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( export_symbols=["pypy_main_startup"])) - self.eci, cfile, extra = gen_source_standalone(db, modulename, - targetdir, - self.eci, - entrypointname = pfname, - defines = defines) + self.eci, cfile, extra = gen_source(db, modulename, targetdir, + self.eci, defines=defines, + split=self.split) self.c_source_filename = py.path.local(cfile) self.extrafiles = self.eventually_copy(extra) self.gen_makefile(targetdir, exe_name=exe_name) @@ -432,6 +429,7 @@ class CStandaloneBuilder(CBuilder): standalone = True + split = True executable_name = None shared_library_name = None @@ -944,64 +942,12 @@ ] return eci.merge(ExternalCompilationInfo(separate_module_files=files)) -def gen_source_standalone(database, modulename, targetdir, eci, - entrypointname, defines={}): - assert database.standalone + +def gen_source(database, modulename, targetdir, + eci, defines={}, split=False): if isinstance(targetdir, str): targetdir = py.path.local(targetdir) - filename = targetdir.join(modulename + '.c') - f = filename.open('w') - incfilename = targetdir.join('common_header.h') - fi = incfilename.open('w') - # - # Header - # - print >> f, '#include "common_header.h"' - print >> f - commondefs(defines) - defines['PYPY_STANDALONE'] = entrypointname - for key, value in defines.items(): - print >> fi, '#define %s %s' % (key, value) - - eci.write_c_header(fi) - print >> fi, '#include "src/g_prerequisite.h"' - - fi.close() - - preimplementationlines = list( - pre_include_code_lines(database, database.translator.rtyper)) - - # - # 1) All declarations - # 2) Implementation of functions and global structures and arrays - # - sg = SourceGenerator(database, preimplementationlines) - sg.set_strategy(targetdir) - database.prepare_inline_helpers() - sg.gen_readable_parts_of_source(f) - - # 3) start-up code - print >> f - gen_startupcode(f, database) - - f.close() - - if 'INSTRUMENT' in defines: - fi = incfilename.open('a') - n = database.instrument_ncounter - print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n - fi.close() - - eci = add_extra_files(eci) - eci = eci.convert_sources_to_files(being_main=True) - files, eci = eci.get_module_files() - return eci, filename, sg.getextrafiles() + list(files) - -def gen_source(database, modulename, targetdir, eci, defines={}, split=False): - assert not database.standalone - if isinstance(targetdir, str): - targetdir = py.path.local(targetdir) filename = targetdir.join(modulename + '.c') f = filename.open('w') incfilename = targetdir.join('common_header.h') @@ -1040,6 +986,12 @@ gen_startupcode(f, database) f.close() + if 'INSTRUMENT' in defines: + fi = incfilename.open('a') + n = database.instrument_ncounter + print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n + fi.close() + eci = add_extra_files(eci) eci = eci.convert_sources_to_files(being_main=True) files, eci = eci.get_module_files() diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py --- a/pypy/translator/c/test/test_genc.py +++ b/pypy/translator/c/test/test_genc.py @@ -4,7 +4,6 @@ from pypy.translator.translator import TranslationContext from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c import genc -from pypy.translator.c.genc import gen_source from pypy.translator.c.gc import NoneGcPolicy from pypy.objspace.flow.model import Constant, Variable, SpaceOperation from pypy.objspace.flow.model import Block, Link, FunctionGraph @@ -13,6 +12,7 @@ from pypy.translator.backendopt.all import backend_optimizations from pypy.translator.interactive import Translation from pypy.rlib.entrypoint import entrypoint +from pypy.tool.nullpath import NullPyPathLocal def compile(fn, argtypes, view=False, gcpolicy="ref", backendopt=True, annotatorpolicy=None): @@ -63,6 +63,22 @@ py.test.raises(Exception, f1, "world") # check that it's really typed + +def test_dont_write_source_files(): + def f(x): + return x*2 + t = TranslationContext() + t.buildannotator().build_types(f, [int]) + t.buildrtyper().specialize() + + t.config.translation.countmallocs = True + t.config.translation.dont_write_c_files = True + builder = genc.CExtModuleBuilder(t, f, config=t.config) + builder.generate_source() + assert isinstance(builder.targetdir, NullPyPathLocal) + assert builder.targetdir.listdir() == [] + + def test_simple_lambda(): f = lambda x: x*2 t = TranslationContext() diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -441,6 +441,45 @@ def test_del_raises(self): self.run('del_raises') # does not raise + def define_custom_trace(cls): + from pypy.rpython.annlowlevel import llhelper + from pypy.rpython.lltypesystem import llmemory + # + S = lltype.GcStruct('S', ('x', llmemory.Address), rtti=True) + offset_of_x = llmemory.offsetof(S, 'x') + def customtrace(obj, prev): + if not prev: + return obj + offset_of_x + else: + return llmemory.NULL + CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], + llmemory.Address) + customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) + lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr) + # + def setup(): + s = lltype.nullptr(S) + for i in range(10000): + t = lltype.malloc(S) + t.x = llmemory.cast_ptr_to_adr(s) + s = t + return s + def measure_length(s): + res = 0 + while s: + res += 1 + s = llmemory.cast_adr_to_ptr(s.x, lltype.Ptr(S)) + return res + def f(n): + s1 = setup() + llop.gc__collect(lltype.Void) + return measure_length(s1) + return f + + def test_custom_trace(self): + res = self.run('custom_trace', 0) + assert res == 10000 + def define_weakref(cls): import weakref From noreply at buildbot.pypy.org Fri Jul 22 13:42:31 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 13:42:31 +0200 (CEST) Subject: [pypy-commit] pypy tealet: hg merge custom-trace Message-ID: <20110722114231.D22E482961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45879:9b46053cc47d Date: 2011-07-22 13:41 +0200 http://bitbucket.org/pypy/pypy/changeset/9b46053cc47d/ Log: hg merge custom-trace diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -522,7 +522,8 @@ self.c_vtinfo_skip_offset = rmodel.inputconst(lltype.typeOf(sko), sko) def build_root_walker(self): - return ShadowStackRootWalker(self) + from pypy.rpython.memory.gctransform import shadowstack + return shadowstack.ShadowStackRootWalker(self) def consider_constant(self, TYPE, value): self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc) @@ -1354,269 +1355,3 @@ def need_thread_support(self, gctransformer, getfn): raise Exception("%s does not support threads" % ( self.__class__.__name__,)) - - def need_tealet_support(self, gctransformer, getfn): - raise Exception("%s does not support tealets" % ( - self.__class__.__name__,)) - - -class ShadowStackRootWalker(BaseRootWalker): - need_root_stack = True - collect_stacks_from_other_threads = None - - def __init__(self, gctransformer): - BaseRootWalker.__init__(self, gctransformer) - self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth - # NB. 'self' is frozen, but we can use self.gcdata to store state - gcdata = self.gcdata - - def incr_stack(n): - top = gcdata.root_stack_top - gcdata.root_stack_top = top + n*sizeofaddr - return top - self.incr_stack = incr_stack - - def decr_stack(n): - top = gcdata.root_stack_top - n*sizeofaddr - gcdata.root_stack_top = top - return top - self.decr_stack = decr_stack - - self.jit2gc = getattr(gctransformer.translator, '_jit2gc', {}) - try: - self.rootstackhook = self.jit2gc['rootstackhook'] - except KeyError: - def collect_stack_root(callback, gc, addr): - if gc.points_to_valid_gc_object(addr): - callback(gc, addr) - return sizeofaddr - self.rootstackhook = collect_stack_root - - def push_stack(self, addr): - top = self.incr_stack(1) - top.address[0] = addr - - def pop_stack(self): - top = self.decr_stack(1) - return top.address[0] - - def allocate_stack(self): - return llmemory.raw_malloc(self.rootstacksize) - - def setup_root_walker(self): - stackbase = self.allocate_stack() - ll_assert(bool(stackbase), "could not allocate root stack") - self.gcdata.root_stack_top = stackbase - self.gcdata.root_stack_base = stackbase - BaseRootWalker.setup_root_walker(self) - - def walk_stack_roots(self, collect_stack_root): - gcdata = self.gcdata - gc = self.gc - rootstackhook = self.rootstackhook - addr = gcdata.root_stack_base - end = gcdata.root_stack_top - while addr != end: - addr += rootstackhook(collect_stack_root, gc, addr) - if self.collect_stacks_from_other_threads is not None: - self.collect_stacks_from_other_threads(collect_stack_root) - - def need_tealet_support(self, gctransformer, getfn): - GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF)) - SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed)) - WALKER_PTR = lltype.Ptr(lltype.Struct('walker', - ('gcptr_array', GCPTR_ARRAY), - ('signed_array', SIGNED_ARRAY))) - gcdata = self.gcdata - jit_save_stack_roots = self.jit2gc.get('savestackhook') - jit_restore_stack_roots = self.jit2gc.get('restorestackhook') - # - def ll_save_stack_roots(walker): - if jit_save_stack_roots is not None: - jit_save_stack_roots(walker, gcdata) - else: - addr = gcdata.root_stack_base - end = gcdata.root_stack_top - count = (end - addr) // sizeofaddr - walker.gcptr_array = array = lltype.malloc(GCPTR_ARRAY.TO,count) - n = 0 - while n < len(array): - array[n] = llmemory.cast_adr_to_ptr(addr.address[n], - llmemory.GCREF) - n += 1 - gcdata.root_stack_top = gcdata.root_stack_base # make it empty - # - def ll_restore_stack_roots(walker): - if jit_restore_stack_roots is not None: - jit_restore_stack_roots(walker, gcdata) - return - array = walker.gcptr_array - addr = gcdata.root_stack_base - gcdata.root_stack_top = addr + len(array) * sizeofaddr - n = 0 - while n < len(array): - addr.address[n] = llmemory.cast_ptr_to_adr(array[n]) - n += 1 - # - self.ll_save_stack_roots_ptr = getfn(ll_save_stack_roots, - [annmodel.SomePtr(WALKER_PTR)], - annmodel.s_None, - minimal_transform=False) - self.ll_restore_stack_roots_ptr = getfn(ll_restore_stack_roots, - [annmodel.SomePtr(WALKER_PTR)], - annmodel.s_None, - minimal_transform=False) - - def need_thread_support(self, gctransformer, getfn): - from pypy.module.thread import ll_thread # xxx fish - from pypy.rpython.memory.support import AddressDict - from pypy.rpython.memory.support import copy_without_null_values - gcdata = self.gcdata - # the interfacing between the threads and the GC is done via - # three completely ad-hoc operations at the moment: - # gc_thread_prepare, gc_thread_run, gc_thread_die. - # See docstrings below. - - def get_aid(): - """Return the thread identifier, cast to an (opaque) address.""" - return llmemory.cast_int_to_adr(ll_thread.get_ident()) - - def thread_setup(): - """Called once when the program starts.""" - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} - gcdata._fresh_rootstack = llmemory.NULL - gcdata.dead_threads_count = 0 - - def thread_prepare(): - """Called just before thread.start_new_thread(). This - allocates a new shadow stack to be used by the future - thread. If memory runs out, this raises a MemoryError - (which can be handled by the caller instead of just getting - ignored if it was raised in the newly starting thread). - """ - if not gcdata._fresh_rootstack: - gcdata._fresh_rootstack = self.allocate_stack() - if not gcdata._fresh_rootstack: - raise MemoryError - - def thread_run(): - """Called whenever the current thread (re-)acquired the GIL. - This should ensure that the shadow stack installed in - gcdata.root_stack_top/root_stack_base is the one corresponding - to the current thread. - """ - aid = get_aid() - if gcdata.active_thread != aid: - switch_shadow_stacks(aid) - - def thread_die(): - """Called just before the final GIL release done by a dying - thread. After a thread_die(), no more gc operation should - occur in this thread. - """ - aid = get_aid() - if aid == gcdata.main_thread: - return # ignore calls to thread_die() in the main thread - # (which can occur after a fork()). - gcdata.thread_stacks.setitem(aid, llmemory.NULL) - old = gcdata.root_stack_base - if gcdata._fresh_rootstack == llmemory.NULL: - gcdata._fresh_rootstack = old - else: - llmemory.raw_free(old) - install_new_stack(gcdata.main_thread) - # from time to time, rehash the dictionary to remove - # old NULL entries - gcdata.dead_threads_count += 1 - if (gcdata.dead_threads_count & 511) == 0: - copy = copy_without_null_values(gcdata.thread_stacks) - gcdata.thread_stacks.delete() - gcdata.thread_stacks = copy - - def switch_shadow_stacks(new_aid): - save_away_current_stack() - install_new_stack(new_aid) - switch_shadow_stacks._dont_inline_ = True - - def save_away_current_stack(): - old_aid = gcdata.active_thread - # save root_stack_base on the top of the stack - self.push_stack(gcdata.root_stack_base) - # store root_stack_top into the dictionary - gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) - - def install_new_stack(new_aid): - # look for the new stack top - top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) - if top == llmemory.NULL: - # first time we see this thread. It is an error if no - # fresh new stack is waiting. - base = gcdata._fresh_rootstack - gcdata._fresh_rootstack = llmemory.NULL - ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") - gcdata.root_stack_top = base - gcdata.root_stack_base = base - else: - # restore the root_stack_base from the top of the stack - gcdata.root_stack_top = top - gcdata.root_stack_base = self.pop_stack() - # done - gcdata.active_thread = new_aid - - def collect_stack(aid, stacktop, callback): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - # collect all valid stacks from the dict (the entry - # corresponding to the current thread is not valid) - gc = self.gc - rootstackhook = self.rootstackhook - end = stacktop - sizeofaddr - addr = end.address[0] - while addr != end: - addr += rootstackhook(callback, gc, addr) - - def collect_more_stacks(callback): - ll_assert(get_aid() == gcdata.active_thread, - "collect_more_stacks(): invalid active_thread") - gcdata.thread_stacks.foreach(collect_stack, callback) - - def _free_if_not_current(aid, stacktop, _): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - end = stacktop - sizeofaddr - base = end.address[0] - llmemory.raw_free(base) - - def thread_after_fork(result_of_fork, opaqueaddr): - # we don't need a thread_before_fork in this case, so - # opaqueaddr == NULL. This is called after fork(). - if result_of_fork == 0: - # We are in the child process. Assumes that only the - # current thread survived, so frees the shadow stacks - # of all the other ones. - gcdata.thread_stacks.foreach(_free_if_not_current, None) - # Clears the dict (including the current thread, which - # was an invalid entry anyway and will be recreated by - # the next call to save_away_current_stack()). - gcdata.thread_stacks.clear() - # Finally, reset the stored thread IDs, in case it - # changed because of fork(). Also change the main - # thread to the current one (because there is not any - # other left). - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - - self.thread_setup = thread_setup - self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) - self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, - inline=True) - # no thread_start_ptr here - self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) - # no thread_before_fork_ptr here - self.thread_after_fork_ptr = getfn(thread_after_fork, - [annmodel.SomeInteger(), - annmodel.SomeAddress()], - annmodel.s_None) - self.collect_stacks_from_other_threads = collect_more_stacks diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py new file mode 100644 --- /dev/null +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -0,0 +1,266 @@ +from pypy.rpython.memory.gctransform.framework import BaseRootWalker +from pypy.rpython.memory.gctransform.framework import sizeofaddr +from pypy.rlib.debug import ll_assert +from pypy.rpython.lltypesystem import llmemory + + +class ShadowStackRootWalker(BaseRootWalker): + need_root_stack = True + collect_stacks_from_other_threads = None + + def __init__(self, gctransformer): + BaseRootWalker.__init__(self, gctransformer) + self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth + # NB. 'self' is frozen, but we can use self.gcdata to store state + gcdata = self.gcdata + + def incr_stack(n): + top = gcdata.root_stack_top + gcdata.root_stack_top = top + n*sizeofaddr + return top + self.incr_stack = incr_stack + + def decr_stack(n): + top = gcdata.root_stack_top - n*sizeofaddr + gcdata.root_stack_top = top + return top + self.decr_stack = decr_stack + + self.jit2gc = getattr(gctransformer.translator, '_jit2gc', {}) + try: + self.rootstackhook = self.jit2gc['rootstackhook'] + except KeyError: + def collect_stack_root(callback, gc, addr): + if gc.points_to_valid_gc_object(addr): + callback(gc, addr) + return sizeofaddr + self.rootstackhook = collect_stack_root + + def push_stack(self, addr): + top = self.incr_stack(1) + top.address[0] = addr + + def pop_stack(self): + top = self.decr_stack(1) + return top.address[0] + + def allocate_stack(self): + return llmemory.raw_malloc(self.rootstacksize) + + def setup_root_walker(self): + stackbase = self.allocate_stack() + ll_assert(bool(stackbase), "could not allocate root stack") + self.gcdata.root_stack_top = stackbase + self.gcdata.root_stack_base = stackbase + BaseRootWalker.setup_root_walker(self) + + def walk_stack_roots(self, collect_stack_root): + gcdata = self.gcdata + gc = self.gc + rootstackhook = self.rootstackhook + addr = gcdata.root_stack_base + end = gcdata.root_stack_top + while addr != end: + addr += rootstackhook(collect_stack_root, gc, addr) + if self.collect_stacks_from_other_threads is not None: + self.collect_stacks_from_other_threads(collect_stack_root) + + def need_tealet_support(self, gctransformer, getfn): + GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF)) + SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed)) + WALKER_PTR = lltype.Ptr(lltype.Struct('walker', + ('gcptr_array', GCPTR_ARRAY), + ('signed_array', SIGNED_ARRAY))) + gcdata = self.gcdata + jit_save_stack_roots = self.jit2gc.get('savestackhook') + jit_restore_stack_roots = self.jit2gc.get('restorestackhook') + # + def ll_save_stack_roots(walker): + if jit_save_stack_roots is not None: + jit_save_stack_roots(walker, gcdata) + else: + addr = gcdata.root_stack_base + end = gcdata.root_stack_top + count = (end - addr) // sizeofaddr + walker.gcptr_array = array = lltype.malloc(GCPTR_ARRAY.TO,count) + n = 0 + while n < len(array): + array[n] = llmemory.cast_adr_to_ptr(addr.address[n], + llmemory.GCREF) + n += 1 + gcdata.root_stack_top = gcdata.root_stack_base # make it empty + # + def ll_restore_stack_roots(walker): + if jit_restore_stack_roots is not None: + jit_restore_stack_roots(walker, gcdata) + return + array = walker.gcptr_array + addr = gcdata.root_stack_base + gcdata.root_stack_top = addr + len(array) * sizeofaddr + n = 0 + while n < len(array): + addr.address[n] = llmemory.cast_ptr_to_adr(array[n]) + n += 1 + # + self.ll_save_stack_roots_ptr = getfn(ll_save_stack_roots, + [annmodel.SomePtr(WALKER_PTR)], + annmodel.s_None, + minimal_transform=False) + self.ll_restore_stack_roots_ptr = getfn(ll_restore_stack_roots, + [annmodel.SomePtr(WALKER_PTR)], + annmodel.s_None, + minimal_transform=False) + + def need_thread_support(self, gctransformer, getfn): + from pypy.module.thread import ll_thread # xxx fish + from pypy.rpython.memory.support import AddressDict + from pypy.rpython.memory.support import copy_without_null_values + gcdata = self.gcdata + # the interfacing between the threads and the GC is done via + # three completely ad-hoc operations at the moment: + # gc_thread_prepare, gc_thread_run, gc_thread_die. + # See docstrings below. + + def get_aid(): + """Return the thread identifier, cast to an (opaque) address.""" + return llmemory.cast_int_to_adr(ll_thread.get_ident()) + + def thread_setup(): + """Called once when the program starts.""" + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} + gcdata._fresh_rootstack = llmemory.NULL + gcdata.dead_threads_count = 0 + + def thread_prepare(): + """Called just before thread.start_new_thread(). This + allocates a new shadow stack to be used by the future + thread. If memory runs out, this raises a MemoryError + (which can be handled by the caller instead of just getting + ignored if it was raised in the newly starting thread). + """ + if not gcdata._fresh_rootstack: + gcdata._fresh_rootstack = self.allocate_stack() + if not gcdata._fresh_rootstack: + raise MemoryError + + def thread_run(): + """Called whenever the current thread (re-)acquired the GIL. + This should ensure that the shadow stack installed in + gcdata.root_stack_top/root_stack_base is the one corresponding + to the current thread. + """ + aid = get_aid() + if gcdata.active_thread != aid: + switch_shadow_stacks(aid) + + def thread_die(): + """Called just before the final GIL release done by a dying + thread. After a thread_die(), no more gc operation should + occur in this thread. + """ + aid = get_aid() + if aid == gcdata.main_thread: + return # ignore calls to thread_die() in the main thread + # (which can occur after a fork()). + gcdata.thread_stacks.setitem(aid, llmemory.NULL) + old = gcdata.root_stack_base + if gcdata._fresh_rootstack == llmemory.NULL: + gcdata._fresh_rootstack = old + else: + llmemory.raw_free(old) + install_new_stack(gcdata.main_thread) + # from time to time, rehash the dictionary to remove + # old NULL entries + gcdata.dead_threads_count += 1 + if (gcdata.dead_threads_count & 511) == 0: + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy + + def switch_shadow_stacks(new_aid): + save_away_current_stack() + install_new_stack(new_aid) + switch_shadow_stacks._dont_inline_ = True + + def save_away_current_stack(): + old_aid = gcdata.active_thread + # save root_stack_base on the top of the stack + self.push_stack(gcdata.root_stack_base) + # store root_stack_top into the dictionary + gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) + + def install_new_stack(new_aid): + # look for the new stack top + top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) + if top == llmemory.NULL: + # first time we see this thread. It is an error if no + # fresh new stack is waiting. + base = gcdata._fresh_rootstack + gcdata._fresh_rootstack = llmemory.NULL + ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") + gcdata.root_stack_top = base + gcdata.root_stack_base = base + else: + # restore the root_stack_base from the top of the stack + gcdata.root_stack_top = top + gcdata.root_stack_base = self.pop_stack() + # done + gcdata.active_thread = new_aid + + def collect_stack(aid, stacktop, callback): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + # collect all valid stacks from the dict (the entry + # corresponding to the current thread is not valid) + gc = self.gc + rootstackhook = self.rootstackhook + end = stacktop - sizeofaddr + addr = end.address[0] + while addr != end: + addr += rootstackhook(callback, gc, addr) + + def collect_more_stacks(callback): + ll_assert(get_aid() == gcdata.active_thread, + "collect_more_stacks(): invalid active_thread") + gcdata.thread_stacks.foreach(collect_stack, callback) + + def _free_if_not_current(aid, stacktop, _): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + end = stacktop - sizeofaddr + base = end.address[0] + llmemory.raw_free(base) + + def thread_after_fork(result_of_fork, opaqueaddr): + # we don't need a thread_before_fork in this case, so + # opaqueaddr == NULL. This is called after fork(). + if result_of_fork == 0: + # We are in the child process. Assumes that only the + # current thread survived, so frees the shadow stacks + # of all the other ones. + gcdata.thread_stacks.foreach(_free_if_not_current, None) + # Clears the dict (including the current thread, which + # was an invalid entry anyway and will be recreated by + # the next call to save_away_current_stack()). + gcdata.thread_stacks.clear() + # Finally, reset the stored thread IDs, in case it + # changed because of fork(). Also change the main + # thread to the current one (because there is not any + # other left). + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + + self.thread_setup = thread_setup + self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) + self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, + inline=True) + # no thread_start_ptr here + self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) + # no thread_before_fork_ptr here + self.thread_after_fork_ptr = getfn(thread_after_fork, + [annmodel.SomeInteger(), + annmodel.SomeAddress()], + annmodel.s_None) + self.collect_stacks_from_other_threads = collect_more_stacks From noreply at buildbot.pypy.org Fri Jul 22 14:57:53 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 22 Jul 2011 14:57:53 +0200 (CEST) Subject: [pypy-commit] jitviewer default: make it clearer that these ops are guards; also, use == insteaf of 'is' for guard_value, because it's more correct in case of eg guard(i4 == 0) vs guard(i4 is 0) Message-ID: <20110722125753.767A782961@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r157:a6e6c83ade89 Date: 2011-07-22 12:12 +0200 http://bitbucket.org/pypy/jitviewer/changeset/a6e6c83ade89/ Log: make it clearer that these ops are guards; also, use == insteaf of 'is' for guard_value, because it's more correct in case of eg guard(i4 == 0) vs guard(i4 is 0) diff --git a/_jitviewer/parser.py b/_jitviewer/parser.py --- a/_jitviewer/parser.py +++ b/_jitviewer/parser.py @@ -67,16 +67,16 @@ locals()['repr_' + name] = _new_binop(bin_op) def repr_guard_true(self): - return '%s is true' % self.getarg(0) + return 'guard(%s is true)' % self.getarg(0) def repr_guard_false(self): - return '%s is false' % self.getarg(0) + return 'guard(%s is false)' % self.getarg(0) def repr_guard_value(self): - return '%s is %s' % (self.getarg(0), self.getarg(1)) + return 'guard(%s == %s)' % (self.getarg(0), self.getarg(1)) def repr_guard_isnull(self): - return '%s is null' % self.getarg(0) + return 'guard(%s is null)' % self.getarg(0) def repr_getfield_raw(self): name, field = self.descr.split(' ')[1].rsplit('.', 1) From noreply at buildbot.pypy.org Fri Jul 22 14:57:54 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 22 Jul 2011 14:57:54 +0200 (CEST) Subject: [pypy-commit] jitviewer default: use a nicer color (light gray) to highlight the selected loop Message-ID: <20110722125754.849FF82961@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r158:0d2e083b7862 Date: 2011-07-22 14:57 +0200 http://bitbucket.org/pypy/jitviewer/changeset/0d2e083b7862/ Log: use a nicer color (light gray) to highlight the selected loop diff --git a/_jitviewer/static/style.css b/_jitviewer/static/style.css --- a/_jitviewer/static/style.css +++ b/_jitviewer/static/style.css @@ -199,7 +199,7 @@ } .selected { - background-color: #aa6; + background-color: #ddd; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; From noreply at buildbot.pypy.org Fri Jul 22 16:01:20 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 22 Jul 2011 16:01:20 +0200 (CEST) Subject: [pypy-commit] pypy default: Missing calls to close(). This really creates rare crashes, because of Message-ID: <20110722140120.8282382961@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45880:349b4b7df46e Date: 2011-07-22 16:01 +0200 http://bitbucket.org/pypy/pypy/changeset/349b4b7df46e/ Log: Missing calls to close(). This really creates rare crashes, because of an opened, non-flushed write file is left behind by a test, and a following test opens the same file name. diff --git a/lib-python/2.7/test/test_tarfile.py b/lib-python/modified-2.7/test/test_tarfile.py copy from lib-python/2.7/test/test_tarfile.py copy to lib-python/modified-2.7/test/test_tarfile.py --- a/lib-python/2.7/test/test_tarfile.py +++ b/lib-python/modified-2.7/test/test_tarfile.py @@ -169,6 +169,7 @@ except tarfile.ReadError: self.fail("tarfile.open() failed on empty archive") self.assertListEqual(tar.getmembers(), []) + tar.close() def test_null_tarfile(self): # Test for issue6123: Allow opening empty archives. @@ -207,16 +208,21 @@ fobj = open(self.tarname, "rb") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, os.path.abspath(fobj.name)) + tar.close() def test_no_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) self.assertRaises(AttributeError, getattr, fobj, "name") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, None) def test_empty_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) fobj.name = "" tar = tarfile.open(fileobj=fobj, mode=self.mode) @@ -515,6 +521,7 @@ self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1") tarinfo = self.tar.getmember("pax/umlauts-�������") self._test_member(tarinfo, size=7011, chksum=md5_regtype) + self.tar.close() class LongnameTest(ReadTest): @@ -675,6 +682,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.rmdir(path) @@ -692,6 +700,7 @@ tar.gettarinfo(target) tarinfo = tar.gettarinfo(link) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(target) os.remove(link) @@ -704,6 +713,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(path) @@ -722,6 +732,7 @@ tar.add(dstname) os.chdir(cwd) self.assertTrue(tar.getnames() == [], "added the archive to itself") + tar.close() def test_exclude(self): tempdir = os.path.join(TEMPDIR, "exclude") @@ -742,6 +753,7 @@ tar = tarfile.open(tmpname, "r") self.assertEqual(len(tar.getmembers()), 1) self.assertEqual(tar.getnames()[0], "empty_dir") + tar.close() finally: shutil.rmtree(tempdir) @@ -859,7 +871,9 @@ fobj.close() elif self.mode.endswith("bz2"): dec = bz2.BZ2Decompressor() - data = open(tmpname, "rb").read() + f = open(tmpname, "rb") + data = f.read() + f.close() data = dec.decompress(data) self.assertTrue(len(dec.unused_data) == 0, "found trailing data") @@ -938,6 +952,7 @@ "unable to read longname member") self.assertEqual(tarinfo.linkname, member.linkname, "unable to read longname member") + tar.close() def test_longname_1023(self): self._test(("longnam/" * 127) + "longnam") @@ -1030,6 +1045,7 @@ else: n = tar.getmembers()[0].name self.assertTrue(name == n, "PAX longname creation failed") + tar.close() def test_pax_global_header(self): pax_headers = { @@ -1058,6 +1074,7 @@ tarfile.PAX_NUMBER_FIELDS[key](val) except (TypeError, ValueError): self.fail("unable to convert pax header field") + tar.close() def test_pax_extended_header(self): # The fields from the pax header have priority over the @@ -1077,6 +1094,7 @@ self.assertEqual(t.pax_headers, pax_headers) self.assertEqual(t.name, "foo") self.assertEqual(t.uid, 123) + tar.close() class UstarUnicodeTest(unittest.TestCase): @@ -1120,6 +1138,7 @@ tarinfo.name = "foo" tarinfo.uname = u"���" self.assertRaises(UnicodeError, tar.addfile, tarinfo) + tar.close() def test_unicode_argument(self): tar = tarfile.open(tarname, "r", encoding="iso8859-1", errors="strict") @@ -1174,6 +1193,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="ascii", errors=handler) self.assertEqual(tar.getnames()[0], name) + tar.close() self.assertRaises(UnicodeError, tarfile.open, tmpname, encoding="ascii", errors="strict") @@ -1186,6 +1206,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="iso8859-1", errors="utf-8") self.assertEqual(tar.getnames()[0], "���/" + u"�".encode("utf8")) + tar.close() class AppendTest(unittest.TestCase): @@ -1213,6 +1234,7 @@ def _test(self, names=["bar"], fileobj=None): tar = tarfile.open(self.tarname, fileobj=fileobj) self.assertEqual(tar.getnames(), names) + tar.close() def test_non_existing(self): self._add_testfile() @@ -1231,7 +1253,9 @@ def test_fileobj(self): self._create_testtar() - data = open(self.tarname).read() + f = open(self.tarname) + data = f.read() + f.close() fobj = StringIO.StringIO(data) self._add_testfile(fobj) fobj.seek(0) @@ -1257,7 +1281,9 @@ # Append mode is supposed to fail if the tarfile to append to # does not end with a zero block. def _test_error(self, data): - open(self.tarname, "wb").write(data) + f = open(self.tarname, "wb") + f.write(data) + f.close() self.assertRaises(tarfile.ReadError, self._add_testfile) def test_null(self): From noreply at buildbot.pypy.org Fri Jul 22 16:57:28 2011 From: noreply at buildbot.pypy.org (hager) Date: Fri, 22 Jul 2011 16:57:28 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Removed parameter change of --architecture flag in objdump call. Message-ID: <20110722145728.41DBA82961@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45881:1a88619622ec Date: 2011-07-19 11:54 +0200 http://bitbucket.org/pypy/pypy/changeset/1a88619622ec/ Log: Removed parameter change of --architecture flag in objdump call. diff --git a/pypy/jit/backend/arm/tool/objdump.py b/pypy/jit/backend/arm/tool/objdump.py --- a/pypy/jit/backend/arm/tool/objdump.py +++ b/pypy/jit/backend/arm/tool/objdump.py @@ -7,7 +7,7 @@ import os, sys, py def objdump(input): - os.system('objdump -D --architecture=powerpc:common64 --target=binary %s' % input) + os.system('objdump -D --architecture=arm --target=binary %s' % input) def get_tmp_file(): From noreply at buildbot.pypy.org Fri Jul 22 16:57:29 2011 From: noreply at buildbot.pypy.org (hager) Date: Fri, 22 Jul 2011 16:57:29 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Added test_runner.py and removed x86 stuff from runner.py . Message-ID: <20110722145729.6EB8482961@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45882:945ddbb14fe5 Date: 2011-07-19 17:13 +0200 http://bitbucket.org/pypy/pypy/changeset/945ddbb14fe5/ Log: Added test_runner.py and removed x86 stuff from runner.py . diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_runner.py b/pypy/jit/backend/ppc/ppcgen/test/test_runner.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/ppc/ppcgen/test/test_runner.py @@ -0,0 +1,11 @@ +from pypy.jit.backend.test.runner_test import LLtypeBackendTest +from pypy.jit.backend.ppc.runner import PPC_64_CPU + +class FakeStats(object): + pass + +class TestPPC(LLtypeBackendTest): + + def setup_method(self, method): + self.cpu = PPC_64_CPU(rtyper=None, stats=FakeStats()) + self.cpu.setup_once() diff --git a/pypy/jit/backend/ppc/runner.py b/pypy/jit/backend/ppc/runner.py --- a/pypy/jit/backend/ppc/runner.py +++ b/pypy/jit/backend/ppc/runner.py @@ -17,11 +17,6 @@ class PPC_64_CPU(AbstractLLCPU): - debug = True - supports_floats = False - - BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) - dont_keepalive_stuff = False # for tests def __init__(self, rtyper, stats, opts=None, translate_support_code=False, gcdescr=None): @@ -30,123 +25,5 @@ AbstractLLCPU.__init__(self, rtyper, stats, opts, translate_support_code, gcdescr) - def setup(self): - if self.opts is not None: - failargs_limit = self.opts.failargs_limit - else: - failargs_limit = 1000 - self.assembler = Assembler386(self, self.translate_support_code, - failargs_limit) - - def get_on_leave_jitted_hook(self): - return self.assembler.leave_jitted_hook - - def setup_once(self): - self.assembler.setup_once() - - def finish_once(self): - self.assembler.finish_once() - def compile_loop(self, inputargs, operations, looptoken, log=True): - return self.assembler.assemble_loop(inputargs, operations, looptoken, - log=log) - - def compile_bridge(self, faildescr, inputargs, operations, - original_loop_token, log=True): - clt = original_loop_token.compiled_loop_token - clt.compiling_a_bridge() - return self.assembler.assemble_bridge(faildescr, inputargs, operations, - original_loop_token, log=log) - - def set_future_value_int(self, index, intvalue): - self.assembler.fail_boxes_int.setitem(index, intvalue) - - def set_future_value_float(self, index, floatvalue): - self.assembler.fail_boxes_float.setitem(index, floatvalue) - - def set_future_value_ref(self, index, ptrvalue): - self.assembler.fail_boxes_ptr.setitem(index, ptrvalue) - - def get_latest_value_int(self, index): - return self.assembler.fail_boxes_int.getitem(index) - - def get_latest_value_float(self, index): - return self.assembler.fail_boxes_float.getitem(index) - - def get_latest_value_ref(self, index): - return self.assembler.fail_boxes_ptr.getitem(index) - - def get_latest_value_count(self): - return self.assembler.fail_boxes_count - - def clear_latest_values(self, count): - setitem = self.assembler.fail_boxes_ptr.setitem - null = lltype.nullptr(llmemory.GCREF.TO) - for index in range(count): - setitem(index, null) - - def get_latest_force_token(self): - return self.assembler.fail_ebp + FORCE_INDEX_OFS - - def execute_token(self, executable_token): - addr = executable_token._x86_bootstrap_code - #llop.debug_print(lltype.Void, ">>>> Entering", addr) - func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr) - #llop.debug_print(lltype.Void, "<<<< Back") - fail_index = self._execute_call(func) - return self.get_fail_descr_from_number(fail_index) - - def _execute_call(self, func): - # help flow objspace - prev_interpreter = None - if not self.translate_support_code: - prev_interpreter = LLInterpreter.current_interpreter - LLInterpreter.current_interpreter = self.debug_ll_interpreter - res = 0 - try: - res = func() - finally: - if not self.translate_support_code: - LLInterpreter.current_interpreter = prev_interpreter - return res - - @staticmethod - def cast_ptr_to_int(x): - adr = llmemory.cast_ptr_to_adr(x) - return CPU386.cast_adr_to_int(adr) - - all_null_registers = lltype.malloc(rffi.LONGP.TO, 24, - flavor='raw', zero=True, - immortal=True) - - def force(self, addr_of_force_index): - TP = rffi.CArrayPtr(lltype.Signed) - fail_index = rffi.cast(TP, addr_of_force_index)[0] - assert fail_index >= 0, "already forced!" - faildescr = self.get_fail_descr_from_number(fail_index) - rffi.cast(TP, addr_of_force_index)[0] = ~fail_index - frb = self.assembler._find_failure_recovery_bytecode(faildescr) - bytecode = rffi.cast(rffi.UCHARP, frb) - # start of "no gc operation!" block - fail_index_2 = self.assembler.grab_frame_values( - bytecode, - addr_of_force_index - FORCE_INDEX_OFS, - self.all_null_registers) - self.assembler.leave_jitted_hook() - # end of "no gc operation!" block - assert fail_index == fail_index_2 - return faildescr - - def redirect_call_assembler(self, oldlooptoken, newlooptoken): - self.assembler.redirect_call_assembler(oldlooptoken, newlooptoken) - - def invalidate_loop(self, looptoken): - from pypy.jit.backend.x86 import codebuf - - for addr, tgt in looptoken.compiled_loop_token.invalidate_positions: - mc = codebuf.MachineCodeBlockWrapper() - mc.JMP_l(tgt) - assert mc.get_relative_pos() == 5 # [JMP] [tgt 4 bytes] - mc.copy_to_raw_memory(addr - 1) - # positions invalidated - looptoken.compiled_loop_token.invalidate_positions = [] + pass From noreply at buildbot.pypy.org Fri Jul 22 16:57:30 2011 From: noreply at buildbot.pypy.org (hager) Date: Fri, 22 Jul 2011 16:57:30 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Execute floating point related test only if floating point ops are supported. Message-ID: <20110722145730.A467482961@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45883:0423752b019b Date: 2011-07-22 16:47 +0200 http://bitbucket.org/pypy/pypy/changeset/0423752b019b/ Log: Execute floating point related test only if floating point ops are supported. diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -114,6 +114,8 @@ assert fail.identifier == 1 def test_compile_linear_float_loop(self): + if not self.cpu.supports_floats: + py.test.skip("floats not supported") i0 = BoxFloat() i1 = BoxFloat() operations = [ From noreply at buildbot.pypy.org Fri Jul 22 16:57:31 2011 From: noreply at buildbot.pypy.org (hager) Date: Fri, 22 Jul 2011 16:57:31 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Renamed class MyPPCAssembler to PPCBuilder, added some methods for code generation. Message-ID: <20110722145731.D3C4E82961@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45884:762f25673182 Date: 2011-07-22 16:54 +0200 http://bitbucket.org/pypy/pypy/changeset/762f25673182/ Log: Renamed class MyPPCAssembler to PPCBuilder, added some methods for code generation. diff --git a/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py b/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py --- a/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py +++ b/pypy/jit/backend/ppc/ppcgen/ppc_assembler.py @@ -7,6 +7,7 @@ from pypy.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager from pypy.rpython.lltypesystem import lltype, rffi +from pypy.jit.metainterp.resoperation import rop A = Form("frD", "frA", "frB", "XO3", "Rc") A1 = Form("frD", "frB", "XO3", "Rc") @@ -802,7 +803,7 @@ return -((v ^ 0xFFFF) + 1) # "sign extend" to 32 bits return v -class MyPPCAssembler(PPCAssembler): +class PPCBuilder(PPCAssembler): def __init__(self): PPCAssembler.__init__(self) self.init_block_builder() @@ -816,40 +817,39 @@ self.addis(rD, 0, ha(addr)) self.lwz(rD, rD, la(addr)) + def store_reg(self, source_reg, addr): + self.load_word(10, addr) + self.stw(source_reg, 10, 0) + def nop(self): self.ori(0, 0, 0) - #def bl(self, addr): - # offset = 4 * len(self.insts) - # self.nop() - # self.patch_list.append((offset, addr)) + # translate a trace operation to corresponding machine code + def build_op(self, trace_op, cpu): + opnum = trace_op.getopnum() + if opnum == rop.INT_ADD: + self.emit_int_add(trace_op, cpu) + elif opnum == rop.FINISH: + self.emit_finish(cpu) - #def assemble(self, dump=os.environ.has_key('PYPY_DEBUG')): - # insns = self.assemble0(dump) - # for i in insns: - # self.emit(i) - # i = self.materialize(AsmMemoryManager(), []) - # t = lltype.FuncType([], lltype.Signed) - # self.patch_jumps(i) - # return rffi.cast(lltype.Ptr(t), i) - # - #def patch_jumps(self, rawstart): - # #import pdb; pdb.set_trace() + # --------------------------------------- # + # CODE GENERATION # + # --------------------------------------- # - # for offset, addr in self.patch_list: - # #delta = (rawstart + offset) - addr - # delta = addr - (rawstart + offset) - # delta >>= 2 - # print "delta =", delta - # #assert (delta >> 24) == -1 + def emit_int_add(self, op, cpu): + arg0 = op.getarg(0) + arg1 = op.getarg(1) - # updater = BranchUpdater() - # #updater.bl(delta) - # self.load_word(reg, h) + arg0_index = cpu.get_box_index(arg0) + addr_box_0 = cpu.fail_boxes_int.get_addr_for_num(arg0_index) + self.load_from(3, addr_box_0) + self.addi(3, 3, arg1.value) + self.store_reg(3, addr_box_0) - # updater.bctrl() - # updater.write_to_mem(rawstart + offset) + def emit_finish(self, cpu): + self.load_word(3, 0) + self.blr() class BranchUpdater(PPCAssembler): def __init__(self): diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py --- a/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py +++ b/pypy/jit/backend/ppc/ppcgen/test/test_ppc.py @@ -1,7 +1,7 @@ import py import random, sys, os -from pypy.jit.backend.ppc.ppcgen.ppc_assembler import BasicPPCAssembler, MyPPCAssembler +from pypy.jit.backend.ppc.ppcgen.ppc_assembler import BasicPPCAssembler, PPCBuilder from pypy.jit.backend.ppc.ppcgen.symbol_lookup import lookup from pypy.jit.backend.ppc.ppcgen.regname import * from pypy.jit.backend.ppc.ppcgen import form, pystructs @@ -21,7 +21,7 @@ """ Creates the boilerplate code for the tests. -- Make an MyPPCAssembler object +- Make an PPCBuilder object - Let the given test create the machine code - Create a function and call it - Compare the return value with the expected result @@ -29,7 +29,7 @@ def asmtest(expected=-1): def testmaker(test): def newtest(self): - a = MyPPCAssembler() + a = PPCBuilder() test(self, a) f = a.assemble() assert f() == expected @@ -173,7 +173,7 @@ def test_call_function(self): functype = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) call_addr = rffi.cast(lltype.Signed, llhelper(functype, func)) - a = MyPPCAssembler() + a = PPCBuilder() # NOW EXPLICITLY: # @@ -245,7 +245,7 @@ a.blr() def test_neg(self): - a = MyPPCAssembler() + a = PPCBuilder() a.load_word(10, 0x0000F0F0) a.neg(3, 10) a.blr() @@ -253,7 +253,7 @@ assert f() == hex_to_signed_int("FFFF0F10") def test_load_and_store(self): - a = MyPPCAssembler() + a = PPCBuilder() word1 = 1000 word2 = 2000 a.load_word(10, word1) From noreply at buildbot.pypy.org Fri Jul 22 16:57:33 2011 From: noreply at buildbot.pypy.org (hager) Date: Fri, 22 Jul 2011 16:57:33 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Skip floating point tests for now. Message-ID: <20110722145733.0A77082961@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45885:a6907c4a6995 Date: 2011-07-22 16:55 +0200 http://bitbucket.org/pypy/pypy/changeset/a6907c4a6995/ Log: Skip floating point tests for now. diff --git a/pypy/jit/backend/ppc/ppcgen/test/test_runner.py b/pypy/jit/backend/ppc/ppcgen/test/test_runner.py --- a/pypy/jit/backend/ppc/ppcgen/test/test_runner.py +++ b/pypy/jit/backend/ppc/ppcgen/test/test_runner.py @@ -4,8 +4,14 @@ class FakeStats(object): pass +#def skip(self): +# py.test.skip("not done") + class TestPPC(LLtypeBackendTest): + test_float_operations = skip + def setup_method(self, method): self.cpu = PPC_64_CPU(rtyper=None, stats=FakeStats()) self.cpu.setup_once() + From noreply at buildbot.pypy.org Fri Jul 22 16:57:34 2011 From: noreply at buildbot.pypy.org (hager) Date: Fri, 22 Jul 2011 16:57:34 +0200 (CEST) Subject: [pypy-commit] pypy ppc-jit-backend: Started implementing the PPC_64_CPU class. Message-ID: <20110722145734.401CA82961@wyvern.cs.uni-duesseldorf.de> Author: hager Branch: ppc-jit-backend Changeset: r45886:e24c11f9222b Date: 2011-07-22 16:57 +0200 http://bitbucket.org/pypy/pypy/changeset/e24c11f9222b/ Log: Started implementing the PPC_64_CPU class. diff --git a/pypy/jit/backend/ppc/runner.py b/pypy/jit/backend/ppc/runner.py --- a/pypy/jit/backend/ppc/runner.py +++ b/pypy/jit/backend/ppc/runner.py @@ -9,6 +9,8 @@ from pypy.jit.backend.x86.profagent import ProfileAgent from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU from pypy.jit.backend.x86 import regloc +from pypy.jit.backend.x86.support import values_array +from pypy.jit.backend.ppc.ppcgen.ppc_assembler import PPCBuilder import sys from pypy.tool.ansi_print import ansi_log @@ -25,5 +27,45 @@ AbstractLLCPU.__init__(self, rtyper, stats, opts, translate_support_code, gcdescr) + # pointer to an array of ints + # XXX length of the integer array is 1000 for now + self.arg_to_box = {} + self.fail_boxes_int = values_array(lltype.Signed, 1000) + self.saved_descr = {} + + # floats are not supported yet + self.supports_floats = False + + # compile a given trace def compile_loop(self, inputargs, operations, looptoken, log=True): - pass + codebuilder = PPCBuilder() + self.saved_descr[len(self.saved_descr)] = operations[-1].getdescr() + + for index, arg in enumerate(inputargs): + self.arg_to_box[arg] = index + + self._walk_trace_ops(codebuilder, operations) + + f = codebuilder.assemble() + looptoken.ppc_code = f + + def set_future_value_int(self, index, value_int): + self.fail_boxes_int.setitem(index, value_int) + + # executes the stored machine code in the token + def execute_token(self, looptoken): + descr_index = looptoken.ppc_code() + return self.saved_descr[descr_index] + + # fetch the result of the computation and return it + def get_latest_value_int(self, index): + value = self.fail_boxes_int.getitem(index) + return value + + # walk through the given trace and generate machine code + def _walk_trace_ops(self, codebuilder, operations): + for op in operations: + codebuilder.build_op(op, self) + + def get_box_index(self, box): + return self.arg_to_box[box] From noreply at buildbot.pypy.org Fri Jul 22 22:35:40 2011 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 22 Jul 2011 22:35:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Wrap text. No other change. Message-ID: <20110722203541.003E082961@wyvern.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r45887:554404f0776e Date: 2011-07-22 22:15 +0200 http://bitbucket.org/pypy/pypy/changeset/554404f0776e/ Log: Wrap text. No other change. diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -35,11 +35,17 @@ Preping Windows for the Large Build ----------------------------------- -Follow http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 to allow Windows up to 3GB for 32bit applications if you are on a 32bit version of windows. If you are using Visual C++ 2008 (untested with 2005), then you will have a utility called editbin.exe within Visual Studio 9.0\VC\bin. You will need to execute:: +Follow http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 +to allow Windows up to 3GB for 32bit applications if you are on a +32bit version of windows. If you are using Visual C++ 2008 (untested +with 2005), then you will have a utility called editbin.exe within +Visual Studio 9.0\VC\bin. You will need to execute:: editbin /largeaddressaware pypy.exe -on the pypy.exe or python.exe you are using to buld the new pypy. Reboot now if you followed the 3G instructions for 32bit windows. +on the pypy.exe or python.exe you are using to buld the new +pypy. Reboot now if you followed the 3G instructions for 32bit +windows. Installing external packages ---------------------------- From noreply at buildbot.pypy.org Fri Jul 22 22:35:42 2011 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 22 Jul 2011 22:35:42 +0200 (CEST) Subject: [pypy-commit] pypy default: Expand /3GB stuff a bit Message-ID: <20110722203542.2D71782961@wyvern.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r45888:3540a8fca517 Date: 2011-07-22 22:29 +0200 http://bitbucket.org/pypy/pypy/changeset/3540a8fca517/ Log: Expand /3GB stuff a bit diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -35,17 +35,20 @@ Preping Windows for the Large Build ----------------------------------- -Follow http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 -to allow Windows up to 3GB for 32bit applications if you are on a -32bit version of windows. If you are using Visual C++ 2008 (untested -with 2005), then you will have a utility called editbin.exe within -Visual Studio 9.0\VC\bin. You will need to execute:: +Normally 32bit programs are limited to 2GB of memory on Windows. It is +possible to raise this limit, to 3GB on Windows 32bit, and almost 4GB +on Windows 64bit. + +On Windows 32bit, it is necessary to modify the system: follow +http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 +to enable the "3GB" feature, and reboot. This step is not necessary on +Windows 64bit. + +Then you need to execute:: editbin /largeaddressaware pypy.exe -on the pypy.exe or python.exe you are using to buld the new -pypy. Reboot now if you followed the 3G instructions for 32bit -windows. +on the pypy.exe file you compiled. Installing external packages ---------------------------- From noreply at buildbot.pypy.org Fri Jul 22 23:29:20 2011 From: noreply at buildbot.pypy.org (ademan) Date: Fri, 22 Jul 2011 23:29:20 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Implementation of oo{, un}box_int for CLI. Message-ID: <20110722212920.7C86F82961@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45889:96a48cd97218 Date: 2011-07-22 14:29 -0700 http://bitbucket.org/pypy/pypy/changeset/96a48cd97218/ Log: Implementation of oo{,un}box_int for CLI. diff --git a/pypy/translator/cli/metavm.py b/pypy/translator/cli/metavm.py --- a/pypy/translator/cli/metavm.py +++ b/pypy/translator/cli/metavm.py @@ -1,6 +1,6 @@ from pypy.translator.cli import oopspec from pypy.rpython.ootypesystem import ootype -from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.oosupport.metavm import Generator, InstructionList, MicroInstruction,\ PushAllArgs, StoreResult, GetField, SetField, DownCast from pypy.translator.oosupport.metavm import _Call as _OOCall @@ -173,6 +173,17 @@ generator.load(v_obj) generator.ilasm.opcode('unbox.any', boxtype) +class _UnboxType(MicroInstruction): + def __init__(self, TO): + self.TO = TO + super(_UnboxType, self).__init__() + + def render(self, generator, op): + v_obj, = op.args + boxtype = generator.cts.lltype_to_cts(self.TO) + generator.load(v_obj) + generator.ilasm.opcode('unbox.any', boxtype) + class _NewArray(MicroInstruction): def render(self, generator, op): v_type, v_length = op.args @@ -312,6 +323,7 @@ #CastWeakAdrToPtr = _CastWeakAdrToPtr() Box = _Box() Unbox = _Unbox() +UnboxInt = _UnboxType(lltype.Signed) NewArray = _NewArray() GetArrayElem = _GetArrayElem() SetArrayElem = _SetArrayElem() diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py --- a/pypy/translator/cli/opcodes.py +++ b/pypy/translator/cli/opcodes.py @@ -2,7 +2,7 @@ IndirectCall, GetField, SetField, DownCast, NewCustomDict,\ MapException, Box, Unbox, NewArray, GetArrayElem, SetArrayElem,\ TypeOf, CastPrimitive, EventHandler, GetStaticField, SetStaticField, \ - DebugPrint + DebugPrint, UnboxInt from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult, InstructionList,\ New, RuntimeNew, CastTo, PushPrimitive, OOString, OOUnicode, OONewArray from pypy.translator.cli.cts import WEAKREF @@ -48,6 +48,8 @@ 'cast_from_object': [DownCast], 'clibox': [Box], 'cliunbox': [Unbox], + 'oobox_int': [Box], + 'oounbox_int': [UnboxInt], 'cli_newarray': [NewArray], 'cli_getelem': [GetArrayElem], 'cli_setelem': [SetArrayElem], From noreply at buildbot.pypy.org Sat Jul 23 02:10:06 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Sat, 23 Jul 2011 02:10:06 +0200 (CEST) Subject: [pypy-commit] pypy default: numpy: added copy and made set slice work when setting to part of the same array Message-ID: <20110723001006.81FE582961@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r45890:0055fef080ed Date: 2011-07-22 18:10 -0600 http://bitbucket.org/pypy/pypy/changeset/0055fef080ed/ Log: numpy: added copy and made set slice work when setting to part of the same array diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -205,6 +205,9 @@ def get_concrete(self): raise NotImplementedError + def descr_copy(self, space): + return new_numarray(space, self) + def descr_get_shape(self, space): return space.newtuple([self.descr_len(space)]) @@ -241,7 +244,16 @@ # Single index self.get_concrete().setitem(start, space.float_w(w_value)) else: - self.get_concrete().setslice(space, start, stop, step, + concrete = self.get_concrete() + if isinstance(w_value, BaseArray): + # for now we just copy if setting part of an array from + # part of itself. can be improved. + if concrete.get_root_storage() is \ + w_value.get_concrete().get_root_storage(): + w_value = new_numarray(space, w_value) + else: + w_value = convert_to_array(space, w_value) + concrete.setslice(space, start, stop, step, slice_length, w_value) def descr_mean(self, space): @@ -440,11 +452,13 @@ self.parent = parent self.size = slice_length + def get_root_storage(self): + self.parent.storage + def find_size(self): return self.size def setslice(self, space, start, stop, step, slice_length, arr): - arr = convert_to_array(space, arr) start = self.calc_index(start) if stop != -1: stop = self.calc_index(stop) @@ -471,6 +485,9 @@ def get_concrete(self): return self + def get_root_storage(self): + return self.storage + def find_size(self): return self.size @@ -488,8 +505,6 @@ self.storage[item] = value def setslice(self, space, start, stop, step, slice_length, arr): - if not isinstance(arr, BaseArray): - arr = convert_to_array(space, arr) if step > 0: self._sliceloop1(start, stop, step, arr, self) else: @@ -525,6 +540,7 @@ 'numarray', __new__ = interp2app(descr_new_numarray), + copy = interp2app(BaseArray.descr_copy), shape = GetSetProperty(BaseArray.descr_get_shape), __len__ = interp2app(BaseArray.descr_len), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -38,6 +38,13 @@ a[2] = 4 assert a[2] == 4 + def test_copy(self): + from numpy import array + a = array(range(5)) + b = a.copy() + for i in xrange(5): + assert b[i] == a[i] + def test_iterator_init(self): from numpy import array a = array(range(5)) @@ -99,6 +106,9 @@ a[1:4:2] = b assert a[1] == 0. assert a[3] == 1. + b[::-1] = b + assert b[0] == 1. + assert b[1] == 0. def test_setslice_of_slice_array(self): from numpy import array, zeros From noreply at buildbot.pypy.org Sat Jul 23 02:47:34 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sat, 23 Jul 2011 02:47:34 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Ignore jit_force_quasi_immutable on CLI Message-ID: <20110723004734.36A1882961@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45891:655cd69271e7 Date: 2011-07-22 17:47 -0700 http://bitbucket.org/pypy/pypy/changeset/655cd69271e7/ Log: Ignore jit_force_quasi_immutable on CLI diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py --- a/pypy/translator/cli/opcodes.py +++ b/pypy/translator/cli/opcodes.py @@ -94,6 +94,7 @@ 'debug_fatalerror': [PushAllArgs, 'call void [pypylib]pypy.runtime.Debug::DEBUG_FATALERROR(string)'], 'keepalive': Ignore, 'jit_marker': Ignore, + 'jit_force_quasi_immutable':Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, } From noreply at buildbot.pypy.org Sat Jul 23 03:38:43 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sat, 23 Jul 2011 03:38:43 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Test for oo{, un}box_int llinterp implementation. Message-ID: <20110723013843.3F5D182961@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45892:90c81e2af0f1 Date: 2011-07-22 18:38 -0700 http://bitbucket.org/pypy/pypy/changeset/90c81e2af0f1/ Log: Test for oo{,un}box_int llinterp implementation. diff --git a/pypy/rpython/test/test_rint.py b/pypy/rpython/test/test_rint.py --- a/pypy/rpython/test/test_rint.py +++ b/pypy/rpython/test/test_rint.py @@ -8,6 +8,9 @@ from pypy.rlib import objectmodel from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem.lloperation import llop class TestSnippet(object): @@ -412,4 +415,8 @@ pass class TestOOtype(BaseTestRint, OORtypeMixin): - pass + def test_oobox_int(self): + def f(): + x = llop.oobox_int(ootype.Object, 42) + return llop.oounbox_int(lltype.Signed, x) + assert self.interpret(f, []) == 42 From noreply at buildbot.pypy.org Sat Jul 23 10:11:29 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sat, 23 Jul 2011 10:11:29 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Merge default. Message-ID: <20110723081129.3196B829BA@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45893:4973b936e5da Date: 2011-07-23 01:09 -0700 http://bitbucket.org/pypy/pypy/changeset/4973b936e5da/ Log: Merge default. diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,6 +116,12 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + if "CFLAGS" in os.environ: + cflags = os.environ["CFLAGS"] + compiler.compiler.append(cflags) + compiler.compiler_so.append(cflags) + compiler.linker_so.append(cflags) + from sysconfig_cpython import ( parse_makefile, _variable_rx, expand_makefile_vars) diff --git a/lib-python/2.7/test/test_tarfile.py b/lib-python/modified-2.7/test/test_tarfile.py copy from lib-python/2.7/test/test_tarfile.py copy to lib-python/modified-2.7/test/test_tarfile.py --- a/lib-python/2.7/test/test_tarfile.py +++ b/lib-python/modified-2.7/test/test_tarfile.py @@ -169,6 +169,7 @@ except tarfile.ReadError: self.fail("tarfile.open() failed on empty archive") self.assertListEqual(tar.getmembers(), []) + tar.close() def test_null_tarfile(self): # Test for issue6123: Allow opening empty archives. @@ -207,16 +208,21 @@ fobj = open(self.tarname, "rb") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, os.path.abspath(fobj.name)) + tar.close() def test_no_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) self.assertRaises(AttributeError, getattr, fobj, "name") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, None) def test_empty_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) fobj.name = "" tar = tarfile.open(fileobj=fobj, mode=self.mode) @@ -515,6 +521,7 @@ self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1") tarinfo = self.tar.getmember("pax/umlauts-�������") self._test_member(tarinfo, size=7011, chksum=md5_regtype) + self.tar.close() class LongnameTest(ReadTest): @@ -675,6 +682,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.rmdir(path) @@ -692,6 +700,7 @@ tar.gettarinfo(target) tarinfo = tar.gettarinfo(link) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(target) os.remove(link) @@ -704,6 +713,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(path) @@ -722,6 +732,7 @@ tar.add(dstname) os.chdir(cwd) self.assertTrue(tar.getnames() == [], "added the archive to itself") + tar.close() def test_exclude(self): tempdir = os.path.join(TEMPDIR, "exclude") @@ -742,6 +753,7 @@ tar = tarfile.open(tmpname, "r") self.assertEqual(len(tar.getmembers()), 1) self.assertEqual(tar.getnames()[0], "empty_dir") + tar.close() finally: shutil.rmtree(tempdir) @@ -859,7 +871,9 @@ fobj.close() elif self.mode.endswith("bz2"): dec = bz2.BZ2Decompressor() - data = open(tmpname, "rb").read() + f = open(tmpname, "rb") + data = f.read() + f.close() data = dec.decompress(data) self.assertTrue(len(dec.unused_data) == 0, "found trailing data") @@ -938,6 +952,7 @@ "unable to read longname member") self.assertEqual(tarinfo.linkname, member.linkname, "unable to read longname member") + tar.close() def test_longname_1023(self): self._test(("longnam/" * 127) + "longnam") @@ -1030,6 +1045,7 @@ else: n = tar.getmembers()[0].name self.assertTrue(name == n, "PAX longname creation failed") + tar.close() def test_pax_global_header(self): pax_headers = { @@ -1058,6 +1074,7 @@ tarfile.PAX_NUMBER_FIELDS[key](val) except (TypeError, ValueError): self.fail("unable to convert pax header field") + tar.close() def test_pax_extended_header(self): # The fields from the pax header have priority over the @@ -1077,6 +1094,7 @@ self.assertEqual(t.pax_headers, pax_headers) self.assertEqual(t.name, "foo") self.assertEqual(t.uid, 123) + tar.close() class UstarUnicodeTest(unittest.TestCase): @@ -1120,6 +1138,7 @@ tarinfo.name = "foo" tarinfo.uname = u"���" self.assertRaises(UnicodeError, tar.addfile, tarinfo) + tar.close() def test_unicode_argument(self): tar = tarfile.open(tarname, "r", encoding="iso8859-1", errors="strict") @@ -1174,6 +1193,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="ascii", errors=handler) self.assertEqual(tar.getnames()[0], name) + tar.close() self.assertRaises(UnicodeError, tarfile.open, tmpname, encoding="ascii", errors="strict") @@ -1186,6 +1206,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="iso8859-1", errors="utf-8") self.assertEqual(tar.getnames()[0], "���/" + u"�".encode("utf8")) + tar.close() class AppendTest(unittest.TestCase): @@ -1213,6 +1234,7 @@ def _test(self, names=["bar"], fileobj=None): tar = tarfile.open(self.tarname, fileobj=fileobj) self.assertEqual(tar.getnames(), names) + tar.close() def test_non_existing(self): self._add_testfile() @@ -1231,7 +1253,9 @@ def test_fileobj(self): self._create_testtar() - data = open(self.tarname).read() + f = open(self.tarname) + data = f.read() + f.close() fobj = StringIO.StringIO(data) self._add_testfile(fobj) fobj.seek(0) @@ -1257,7 +1281,9 @@ # Append mode is supposed to fail if the tarfile to append to # does not end with a zero block. def _test_error(self, data): - open(self.tarname, "wb").write(data) + f = open(self.tarname, "wb") + f.write(data) + f.close() self.assertRaises(tarfile.ReadError, self._add_testfile) def test_null(self): diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -327,6 +327,9 @@ BoolOption("mutable_builtintypes", "Allow the changing of builtin types", default=False, requires=[("objspace.std.builtinshortcut", True)]), + BoolOption("withidentitydict", + "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not", + default=True), ]), ]) diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -929,6 +929,19 @@ located in the ``py/bin/`` directory. For switches to modify test execution pass the ``-h`` option. +Coverage reports +---------------- + +In order to get coverage reports the `pytest-cov`_ plugin is included. +it adds some extra requirements ( coverage_ and `cov-core`_ ) +and can once they are installed coverage testing can be invoked via:: + + python test_all.py --cov file_or_direcory_to_cover file_or_directory + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov +.. _`coverage`: http://pypi.python.org/pypi/coverage +.. _`cov-core`: http://pypi.python.org/pypi/cov-core + Test conventions ---------------- diff --git a/pypy/doc/config/objspace.std.withidentitydict.txt b/pypy/doc/config/objspace.std.withidentitydict.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withidentitydict.txt @@ -0,0 +1,21 @@ +============================= +objspace.std.withidentitydict +============================= + +* **name:** withidentitydict + +* **description:** enable a dictionary strategy for "by identity" comparisons + +* **command-line:** --objspace-std-withidentitydict + +* **command-line for negation:** --no-objspace-std-withidentitydict + +* **option type:** boolean option + +* **default:** True + + +Enable a dictionary strategy specialized for instances of classes which +compares "by identity", which is the default unless you override ``__hash__``, +``__eq__`` or ``__cmp__``. This strategy will be used only with new-style +classes. diff --git a/pypy/doc/config/translation.dont_write_c_files.txt b/pypy/doc/config/translation.dont_write_c_files.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/translation.dont_write_c_files.txt @@ -0,0 +1,4 @@ +write the generated C files to ``/dev/null`` instead of to the disk. Useful if +you want to use translate.py as a benchmark and don't want to access the disk. + +.. _`translation documentation`: ../translation.html diff --git a/pypy/doc/config/translation.gc.txt b/pypy/doc/config/translation.gc.txt --- a/pypy/doc/config/translation.gc.txt +++ b/pypy/doc/config/translation.gc.txt @@ -1,4 +1,6 @@ -Choose the Garbage Collector used by the translated program: +Choose the Garbage Collector used by the translated program. +The good performing collectors are "hybrid" and "minimark". +The default is "minimark". - "ref": reference counting. Takes very long to translate and the result is slow. @@ -11,3 +13,12 @@ older generation. - "boehm": use the Boehm conservative GC. + + - "hybrid": a hybrid collector of "generation" together with a + mark-n-sweep old space + + - "markcompact": a slow, but memory-efficient collector, + influenced e.g. by Smalltalk systems. + + - "minimark": a generational mark-n-sweep collector with good + performance. Includes page marking for large arrays. diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -211,6 +211,38 @@ >>>> print d1['a'] 42 +Mutating classes of objects which are already used as dictionary keys +--------------------------------------------------------------------- + +Consider the following snippet of code:: + + class X(object): + pass + + def __evil_eq__(self, other): + print 'hello world' + return False + + def evil(y): + d = {x(): 1} + X.__eq__ = __evil_eq__ + d[y] # might trigger a call to __eq__? + +In CPython, __evil_eq__ **might** be called, although there is no way to write +a test which reliably calls it. It happens if ``y is not x`` and ``hash(y) == +hash(x)``, where ``hash(x)`` is computed when ``x`` is inserted into the +dictionary. If **by chance** the condition is satisfied, then ``__evil_eq__`` +is called. + +PyPy uses a special strategy to optimize dictionaries whose keys are instances +of user-defined classes which do not override the default ``__hash__``, +``__eq__`` and ``__cmp__``: when using this strategy, ``__eq__`` and +``__cmp__`` are never called, but instead the lookup is done by identity, so +in the case above it is guaranteed that ``__eq__`` won't be called. + +Note that in all other cases (e.g., if you have a custom ``__hash__`` and +``__eq__`` in ``y``) the behavior is exactly the same as CPython. + Ignored exceptions ----------------------- diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -32,6 +32,24 @@ modules that relies on third-party libraries. See below how to get and build them. +Preping Windows for the Large Build +----------------------------------- + +Normally 32bit programs are limited to 2GB of memory on Windows. It is +possible to raise this limit, to 3GB on Windows 32bit, and almost 4GB +on Windows 64bit. + +On Windows 32bit, it is necessary to modify the system: follow +http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 +to enable the "3GB" feature, and reboot. This step is not necessary on +Windows 64bit. + +Then you need to execute:: + + editbin /largeaddressaware pypy.exe + +on the pypy.exe file you compiled. + Installing external packages ---------------------------- diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -31,7 +31,8 @@ _immutable_fields_ = ['code?', 'w_func_globals?', 'closure?', - 'defs_w?[*]'] + 'defs_w?[*]', + 'name?'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2820,11 +2820,11 @@ def test_residual_call_invalidate_some_arrays(self): ops = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) - p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p2, 0, descr=arraydescr2) p6 = getarrayitem_gc(p2, 1, descr=arraydescr2) i4 = getarrayitem_gc(p1, 1, descr=arraydescr) escape(p3) @@ -2837,7 +2837,7 @@ """ expected = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -390,8 +390,21 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): - return self.execute_with_descr(rop.GETARRAYITEM_GC, + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache and isinstance(indexbox, ConstInt): + index = indexbox.getint() + frombox, tobox = cache.get(index, (None, None)) + if frombox is arraybox: + return tobox + resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) + if isinstance(indexbox, ConstInt): + if not cache: + cache = self.metainterp.heap_array_cache[arraydescr] = {} + index = indexbox.getint() + cache[index] = arraybox, resbox + return resbox + opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any @@ -419,6 +432,13 @@ indexbox, itembox): self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, itembox) + if isinstance(indexbox, ConstInt): + cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {}) + cache[indexbox.getint()] = arraybox, itembox + else: + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache: + cache.clear() opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any @@ -454,21 +474,17 @@ def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, - sbox, sizebox) + self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox) abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, sizebox) - self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, - sbox, abox) + self._opimpl_setfield_gc_any(sbox, itemsdescr, abox) return sbox @arguments("box", "descr", "descr", "box") def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox) opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any @@ -477,10 +493,9 @@ @arguments("box", "descr", "descr", "box", "box") def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, - indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox, + valuebox) opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any @@ -502,18 +517,29 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC, box, fielddescr) opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @arguments("box", "descr") def _opimpl_getfield_gc_pure_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_PURE, box, fielddescr) opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any + @specialize.arg(1) + def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(opnum, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox + @arguments("orgpc", "box", "descr") def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr): ginfo = self.metainterp.jitdriver_sd.greenfield_info @@ -532,7 +558,11 @@ @arguments("box", "descr", "box") def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box and tobox is valuebox: + return self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + self.metainterp.heap_cache[fielddescr] = (box, valuebox) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any @@ -617,7 +647,7 @@ @arguments("orgpc", "box", "descr") def _opimpl_getfield_vable(self, pc, box, fielddescr): if self._nonstandard_virtualizable(pc, box): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any(box, fielddescr) self.metainterp.check_synchronized_virtualizable() index = self._get_virtualizable_field_index(fielddescr) return self.metainterp.virtualizable_boxes[index] @@ -629,8 +659,7 @@ @arguments("orgpc", "box", "descr", "box") def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox): if self._nonstandard_virtualizable(pc, box): - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) - return + return self._opimpl_setfield_gc_any(box, fielddescr, valuebox) index = self._get_virtualizable_field_index(fielddescr) self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -660,10 +689,8 @@ @arguments("orgpc", "box", "descr", "descr", "box") def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr, - arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox) self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) return self.metainterp.virtualizable_boxes[index] @@ -676,10 +703,9 @@ def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox, valuebox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - self.execute_with_descr(rop.SETARRAYITEM_GC, adescr, - arraybox, indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + self._opimpl_setarrayitem_gc_any(arraybox, adescr, + indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -693,8 +719,7 @@ @arguments("orgpc", "box", "descr", "descr") def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -1462,6 +1487,12 @@ self.known_class_boxes = {} # contains frame boxes that are not virtualizables self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1637,10 +1668,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1804,6 +1852,8 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} + self.heap_array_cache = {} duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), @@ -2311,6 +2361,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1024,69 +1024,6 @@ res = self.meta_interp(main, []) assert res == 55 - def test_dont_record_repeated_guard_class(self): - class A: - pass - class B(A): - pass - @dont_look_inside - def extern(n): - if n == -7: - return None - elif n: - return A() - else: - return B() - def fn(n): - obj = extern(n) - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=1, guard_nonnull=1) - res = self.interp_operations(fn, [1]) - assert not res - - def test_dont_record_guard_class_after_new(self): - class A: - pass - class B(A): - pass - def fn(n): - if n == -7: - obj = None - elif n: - obj = A() - else: - obj = B() - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=0, guard_nonnull=0) - res = self.interp_operations(fn, [1]) - assert not res - - def test_guard_isnull_nullifies(self): - class A: - pass - a = A() - a.x = None - def fn(n): - if n == -7: - a.x = "" - obj = a.x - res = 0 - if not obj: - res += 1 - if obj: - res += 1 - if obj is None: - res += 1 - if obj is not None: - res += 1 - return res - res = self.interp_operations(fn, [0]) - assert res == 2 - self.check_operations_history(guard_isnull=1) def test_assert_isinstance(self): class A: @@ -1248,7 +1185,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: @@ -2649,7 +2586,23 @@ return n res = self.meta_interp(f, [10, 1]) self.check_loops(getfield_gc=2) + assert res == f(10, 1) + def test_jit_merge_point_with_raw_pointer(self): + driver = JitDriver(greens = [], reds = ['n', 'x']) + + TP = lltype.Array(lltype.Signed, hints={'nolength': True}) + + def f(n): + x = lltype.malloc(TP, 10, flavor='raw') + x[0] = 1 + while n > 0: + driver.jit_merge_point(n=n, x=x) + n -= x[0] + lltype.free(x, flavor='raw') + return n + + self.meta_interp(f, [10], repeat=3) class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,407 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + l = [1] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * (4 + a) + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + len(frame.l) + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -138,6 +138,9 @@ refvalue = cpu.ts.cast_to_ref(value) cpu.set_future_value_ref(j, refvalue) elif typecode == 'int': + if isinstance(lltype.typeOf(value), lltype.Ptr): + intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value)) + else: intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) elif typecode == 'float': diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -25,6 +25,7 @@ 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', 'lookup_special' : 'interp_magic.lookup_special', + 'do_what_I_mean' : 'interp_magic.do_what_I_mean', } submodules = { diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -70,3 +70,6 @@ if w_descr is None: return space.w_None return space.get(w_descr, w_obj) + +def do_what_I_mean(space): + return space.wrap(42) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -49,3 +49,8 @@ class X: pass raises(TypeError, lookup_special, X(), "foo") + + def test_do_what_I_mean(self): + from __pypy__ import do_what_I_mean + x = do_what_I_mean() + assert x == 42 diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -268,3 +268,7 @@ if errors: w_errors = space.wrap(rffi.charp2str(errors)) return space.call_method(w_str, 'encode', w_encoding, w_errors) + + at cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -287,3 +287,9 @@ def test_eq(self, space, api): assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'ab' diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -15,14 +15,22 @@ # ufuncs 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', + 'add': 'interp_ufuncs.add', 'copysign': 'interp_ufuncs.copysign', + 'divide': 'interp_ufuncs.divide', 'exp': 'interp_ufuncs.exp', + 'fabs': 'interp_ufuncs.fabs', 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', + 'multiply': 'interp_ufuncs.multiply', 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'subtract': 'interp_ufuncs.subtract', + 'sin': 'interp_ufuncs.sin', + 'cos': 'interp_ufuncs.cos', + 'tan': 'interp_ufuncs.tan', } appleveldefs = { diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -3,7 +3,7 @@ It should not be imported by the module itself """ -from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray class BogusBytecode(Exception): pass @@ -18,6 +18,14 @@ def wrap(self, x): return x + def issequence_w(self, w_obj): + # Completley wrong in the general case, but good enough for this. + return isinstance(w_obj, BaseArray) + + def float_w(self, w_obj): + assert isinstance(w_obj, float) + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() stack = [] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,59 +2,36 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy.interp_support import Signature +from pypy.module.micronumpy import interp_ufuncs +from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit +from pypy.rlib.rfloat import DTSF_STR_PRECISION from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name import math -def dummy1(v): - assert isinstance(v, float) - return v - -def dummy2(v): - assert isinstance(v, float) - return v - TP = lltype.Array(lltype.Float, hints={'nolength': True}) numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) -class Signature(object): - def __init__(self): - self.transitions = {} - - def transition(self, target): - if target in self.transitions: - return self.transitions[target] - self.transitions[target] = new = Signature() - return new - -def pos(v): - return v -def neg(v): - return -v -def absolute(v): - return abs(v) def add(v1, v2): return v1 + v2 -def sub(v1, v2): - return v1 - v2 def mul(v1, v2): return v1 * v2 -def div(v1, v2): - return v1 / v2 -def power(v1, v2): - return math.pow(v1, v2) -def mod(v1, v2): - return math.fmod(v1, v2) def maximum(v1, v2): return max(v1, v2) def minimum(v1, v2): return min(v1, v2) +def float2string(x): + return float2string_orig(x, 'g', DTSF_STR_PRECISION) + class BaseArray(Wrappable): def __init__(self): self.invalidates = [] @@ -68,67 +45,39 @@ arr.force_if_needed() del self.invalidates[:] - def _unop_impl(function): - signature = Signature() + def _unaryop_impl(w_ufunc): def impl(self, space): - new_sig = self.signature.transition(signature) - res = Call1( - function, - self, - new_sig) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + return w_ufunc(space, self) + return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__) - descr_pos = _unop_impl(pos) - descr_neg = _unop_impl(neg) - descr_abs = _unop_impl(absolute) + descr_pos = _unaryop_impl(interp_ufuncs.positive) + descr_neg = _unaryop_impl(interp_ufuncs.negative) + descr_abs = _unaryop_impl(interp_ufuncs.absolute) - def _binop_impl(function): - signature = Signature() + def _binop_impl(w_ufunc): def impl(self, space, w_other): - w_other = convert_to_array(space, w_other) - new_sig = self.signature.transition(signature) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + return w_ufunc(space, self, w_other) + return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__) - descr_add = _binop_impl(add) - descr_sub = _binop_impl(sub) - descr_mul = _binop_impl(mul) - descr_div = _binop_impl(div) - descr_pow = _binop_impl(power) - descr_mod = _binop_impl(mod) + descr_add = _binop_impl(interp_ufuncs.add) + descr_sub = _binop_impl(interp_ufuncs.subtract) + descr_mul = _binop_impl(interp_ufuncs.multiply) + descr_div = _binop_impl(interp_ufuncs.divide) + descr_pow = _binop_impl(interp_ufuncs.power) + descr_mod = _binop_impl(interp_ufuncs.mod) - def _binop_right_impl(function): - signature = Signature() + def _binop_right_impl(w_ufunc): def impl(self, space, w_other): - new_sig = self.signature.transition(signature) w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - w_other, - self, - new_sig.transition(w_other.signature) - ) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, - "binop_right_%s_impl" % function.__name__) + return w_ufunc(space, w_other, self) + return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__) - descr_radd = _binop_right_impl(add) - descr_rsub = _binop_right_impl(sub) - descr_rmul = _binop_right_impl(mul) - descr_rdiv = _binop_right_impl(div) - descr_rpow = _binop_right_impl(power) - descr_rmod = _binop_right_impl(mod) + descr_radd = _binop_right_impl(interp_ufuncs.add) + descr_rsub = _binop_right_impl(interp_ufuncs.subtract) + descr_rmul = _binop_right_impl(interp_ufuncs.multiply) + descr_rdiv = _binop_right_impl(interp_ufuncs.divide) + descr_rpow = _binop_right_impl(interp_ufuncs.power) + descr_rmod = _binop_right_impl(interp_ufuncs.mod) def _reduce_sum_prod_impl(function, init): reduce_driver = jit.JitDriver(greens=['signature'], @@ -235,9 +184,30 @@ else: return self.descr_mul(space, w_other) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] + nums.append("..." + "," * comma) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) + else: + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] + return nums + def get_concrete(self): raise NotImplementedError + def descr_copy(self, space): + return new_numarray(space, self) + def descr_get_shape(self, space): return space.newtuple([self.descr_len(space)]) @@ -245,10 +215,14 @@ return self.get_concrete().descr_len(space) def descr_repr(self, space): - return self.get_concrete()._repr(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])") def descr_str(self, space): - return self.get_concrete()._str(space) + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("[" + " ".join(concrete._getnums(True)) + "]") def descr_getitem(self, space, w_idx): # TODO: indexing by tuples @@ -261,14 +235,52 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().setitem(start, space.float_w(w_value)) + else: + concrete = self.get_concrete() + if isinstance(w_value, BaseArray): + # for now we just copy if setting part of an array from + # part of itself. can be improved. + if concrete.get_root_storage() is \ + w_value.get_concrete().get_root_storage(): + w_value = new_numarray(space, w_value) + else: + w_value = convert_to_array(space, w_value) + concrete.setslice(space, start, stop, step, + slice_length, w_value) def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) + def _sliceloop1(self, start, stop, step, source, dest): + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, source, dest): + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + def convert_to_array (space, w_obj): if isinstance(w_obj, BaseArray): return w_obj @@ -413,8 +425,8 @@ return self.parent.getitem(self.calc_index(item)) @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - return self.parent.descr_setitem(space, self.calc_index(item), value) + def setitem(self, item, value): + return self.parent.setitem(self.calc_index(item), value) def descr_len(self, space): return space.wrap(self.find_size()) @@ -428,37 +440,37 @@ def __init__(self, start, stop, step, slice_length, parent, signature): ViewArray.__init__(self, parent, signature) + if isinstance(parent, SingleDimSlice): + self.start = parent.calc_index(start) + self.stop = parent.calc_index(stop) + self.step = parent.step * step + self.parent = parent.parent + else: self.start = start self.stop = stop self.step = step + self.parent = parent self.size = slice_length + def get_root_storage(self): + self.parent.storage + def find_size(self): return self.size + def setslice(self, space, start, stop, step, slice_length, arr): + start = self.calc_index(start) + if stop != -1: + stop = self.calc_index(stop) + step = self.step * step + if step > 0: + self._sliceloop1(start, stop, step, arr, self.parent) + else: + self._sliceloop2(start, stop, step, arr, self.parent) + def calc_index(self, item): return (self.start + item * self.step) - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - class SingleDimArray(BaseArray): signature = Signature() @@ -473,55 +485,31 @@ def get_concrete(self): return self + def get_root_storage(self): + return self.storage + def find_size(self): return self.size def eval(self, i): return self.storage[i] - def getindex(self, space, item): - if item >= self.size: - raise operationerrfmt(space.w_IndexError, - '%d above array size', item) - if item < 0: - item += self.size - if item < 0: - raise operationerrfmt(space.w_IndexError, - '%d below zero', item) - return item - def descr_len(self, space): return space.wrap(self.size) def getitem(self, item): return self.storage[item] - def _getnums(self, comma): - if self.find_size() > 1000: - nums = [str(self.getitem(index)) for index \ - in range(3)] - nums.append("..." + "," * comma) - nums.extend([str(self.getitem(index)) for index \ - in range(self.find_size() - 3, self.find_size())]) - else: - nums = [str(self.getitem(index)) for index \ - in range(self.find_size())] - return nums - - def _repr(self, space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("array([" + ", ".join(self._getnums(False)) + "])") - - def _str(self,space): - # Simple implementation so that we can see the array. Needs work. - return space.wrap("[" + " ".join(self._getnums(True)) + "]") - - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - item = self.getindex(space, item) + def setitem(self, item, value): self.invalidated() self.storage[item] = value + def setslice(self, space, start, stop, step, slice_length, arr): + if step > 0: + self._sliceloop1(start, stop, step, arr, self) + else: + self._sliceloop2(start, stop, step, arr, self) + def __del__(self): lltype.free(self.storage, flavor='raw') @@ -552,6 +540,7 @@ 'numarray', __new__ = interp2app(descr_new_numarray), + copy = interp2app(BaseArray.descr_copy), shape = GetSetProperty(BaseArray.descr_get_shape), __len__ = interp2app(BaseArray.descr_len), diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py --- a/pypy/module/micronumpy/interp_support.py +++ b/pypy/module/micronumpy/interp_support.py @@ -1,14 +1,14 @@ - from pypy.rlib.rstruct.runpack import runpack from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.interp_numarray import SingleDimArray + FLOAT_SIZE = rffi.sizeof(lltype.Float) @unwrap_spec(s=str) def fromstring(space, s): + from pypy.module.micronumpy.interp_numarray import SingleDimArray length = len(s) if length % FLOAT_SIZE == 0: @@ -30,3 +30,13 @@ end += FLOAT_SIZE return space.wrap(a) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,13 +1,13 @@ import math -from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, - convert_to_array) +from pypy.module.micronumpy.interp_support import Signature from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name def ufunc(func): signature = Signature() def impl(space, w_obj): + from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array if space.issequence_w(w_obj): w_obj_arr = convert_to_array(space, w_obj) w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) @@ -20,6 +20,7 @@ def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): + from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): w_lhs_arr = convert_to_array(space, w_lhs) w_rhs_arr = convert_to_array(space, w_rhs) @@ -37,9 +38,17 @@ return abs(value) @ufunc2 +def add(lvalue, rvalue): + return lvalue + rvalue + + at ufunc2 def copysign(lvalue, rvalue): return rfloat.copysign(lvalue, rvalue) + at ufunc2 +def divide(lvalue, rvalue): + return lvalue / rvalue + @ufunc def exp(value): try: @@ -47,6 +56,10 @@ except OverflowError: return rfloat.INFINITY + at ufunc +def fabs(value): + return math.fabs(value) + @ufunc2 def maximum(lvalue, rvalue): return max(lvalue, rvalue) @@ -55,6 +68,15 @@ def minimum(lvalue, rvalue): return min(lvalue, rvalue) + at ufunc2 +def multiply(lvalue, rvalue): + return lvalue * rvalue + +# Used by numarray for __pos__. Not visible from numpy application space. + at ufunc +def positive(value): + return value + @ufunc def negative(value): return -value @@ -65,6 +87,10 @@ return rfloat.copysign(rfloat.INFINITY, value) return 1.0 / value + at ufunc2 +def subtract(lvalue, rvalue): + return lvalue - rvalue + @ufunc def floor(value): return math.floor(value) @@ -74,3 +100,23 @@ if value == 0.0: return 0.0 return rfloat.copysign(1.0, value) + + at ufunc +def sin(value): + return math.sin(value) + + at ufunc +def cos(value): + return math.cos(value) + + at ufunc +def tan(value): + return math.tan(value) + + at ufunc2 +def power(lvalue, rvalue): + return math.pow(lvalue, rvalue) + + at ufunc2 +def mod(lvalue, rvalue): + return math.fmod(lvalue, rvalue) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -38,6 +38,13 @@ a[2] = 4 assert a[2] == 4 + def test_copy(self): + from numpy import array + a = array(range(5)) + b = a.copy() + for i in xrange(5): + assert b[i] == a[i] + def test_iterator_init(self): from numpy import array a = array(range(5)) @@ -92,6 +99,51 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + b[::-1] = b + assert b[0] == 1. + assert b[1] == 0. + + def test_setslice_of_slice_array(self): + from numpy import array, zeros + a = zeros(5) + a[::2] = array([9., 10., 11.]) + assert a[0] == 9. + assert a[2] == 10. + assert a[4] == 11. + a[1:4:2][::-1] = array([1., 2.]) + assert a[0] == 9. + assert a[1] == 2. + assert a[2] == 10. + assert a[3] == 1. + assert a[4] == 11. + a = zeros(10) + a[::2][::-1][::2] = array(range(1,4)) + assert a[8] == 1. + assert a[4] == 2. + assert a[0] == 3. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) @@ -129,6 +181,12 @@ for i in range(5): assert b[i] == i + 5 + def test_radd(self): + from numpy import array + r = 3 + array(range(3)) + for i in range(3): + assert r[i] == i + 3 + def test_add_list(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -65,6 +65,33 @@ for i in range(3): assert b[i] == abs(a[i]) + def test_add(self): + from numpy import array, add + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = add(a, b) + for i in range(3): + assert c[i] == a[i] + b[i] + + def test_divide(self): + from numpy import array, divide + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = divide(a, b) + for i in range(3): + assert c[i] == a[i] / b[i] + + def test_fabs(self): + from numpy import array, fabs + from math import fabs as math_fabs + + a = array([-5.0, -0.0, 1.0]) + b = fabs(a) + for i in range(3): + assert b[i] == math_fabs(a[i]) + def test_minimum(self): from numpy import array, minimum @@ -83,6 +110,15 @@ for i in range(3): assert c[i] == max(a[i], b[i]) + def test_multiply(self): + from numpy import array, multiply + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = multiply(a, b) + for i in range(3): + assert c[i] == a[i] * b[i] + def test_sign(self): from numpy import array, sign @@ -101,6 +137,15 @@ for i in range(4): assert b[i] == reference[i] + def test_subtract(self): + from numpy import array, subtract + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = subtract(a, b) + for i in range(3): + assert c[i] == a[i] - b[i] + def test_floor(self): from numpy import array, floor @@ -133,3 +178,30 @@ except OverflowError: res = float('inf') assert b[i] == res + + def test_sin(self): + import math + from numpy import array, sin + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = sin(a) + for i in range(len(a)): + assert b[i] == math.sin(a[i]) + + def test_cos(self): + import math + from numpy import array, cos + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = cos(a) + for i in range(len(a)): + assert b[i] == math.cos(a[i]) + + def test_tan(self): + import math + from numpy import array, tan + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = tan(a) + for i in range(len(a)): + assert b[i] == math.tan(a[i]) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,10 +1,11 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) + FloatWrapper, Call2, SingleDimSlice, add, mul, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): w_ValueError = None @@ -47,21 +48,6 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_neg(self): - space = self.space - - def f(i): - ar = SingleDimArray(i) - v = Call1(neg, ar, Signature()) - return v.get_concrete().storage[3] - - result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, - "setarrayitem_raw": 1, "int_add": 1, - "int_lt": 1, "guard_true": 1, "jump": 1}) - - assert result == f(5) - def test_sum(self): space = self.space @@ -104,6 +90,7 @@ "float_gt": 1, "int_add": 1, "int_lt": 1, "guard_true": 1, "guard_false": 1, "jump": 1}) + assert result == f(5) def test_min(self): space = self.space @@ -121,6 +108,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_argmin(self): space = self.space @@ -138,6 +126,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_all(self): space = self.space @@ -153,6 +142,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_any(self): space = self.space @@ -165,6 +155,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "guard_false": 1, "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) def test_already_forecd(self): def f(i): @@ -248,6 +239,28 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar2.storage[1] = 5.5 + if NonConstant(False): + arg = ar2 + else: + arg = ar2.descr_add(space, ar2) + ar.setslice(space, 0, step*i, step, i, arg) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 2, + 'float_add' : 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == 11.0 + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -30,7 +30,6 @@ assert res == 8.0 * 300 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('fficall', """ - p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>) guard_not_invalidated(descr=...) i17 = force_token() setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -23,3 +23,29 @@ ops = loop.ops_by_id('look') assert log.opnames(ops) == ['setfield_gc', 'guard_not_invalidated'] + + def test_identitydict(self): + def fn(n): + class X(object): + pass + x = X() + d = {} + d[x] = 1 + res = 0 + for i in range(300): + value = d[x] # ID: getitem + res += value + return res + # + log = self.run(fn, [1000]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # check that the call to ll_dict_lookup is not a call_may_force + assert loop.match_by_id("getitem", """ + i25 = call(ConstClass(_ll_1_gc_identityhash__objectPtr), p6, descr=...) + ... + i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...) + ... + p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -92,10 +92,10 @@ p51 = new_with_vtable(21136408) setfield_gc(p51, p28, descr=) setfield_gc(p51, ConstPtr(ptr51), descr=) - setfield_gc(p51, i29, descr=) setfield_gc(p51, 1, descr=) setfield_gc(p51, 16, descr=) setfield_gc(p51, p28, descr=) + setfield_gc(p51, i29, descr=) p55 = call(ConstClass(parse_digit_string), p51, descr=) guard_no_exception(descr=...) i57 = call(ConstClass(rbigint.toint), p55, descr=) @@ -104,4 +104,4 @@ guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) - """) \ No newline at end of file + """) diff --git a/pypy/module/select/test/test_epoll.py b/pypy/module/select/test/test_epoll.py --- a/pypy/module/select/test/test_epoll.py +++ b/pypy/module/select/test/test_epoll.py @@ -138,7 +138,7 @@ expected.sort() assert events == expected - assert then - now < 0.01 + assert then - now < 0.02 now = time.time() events = ep.poll(timeout=2.1, maxevents=4) @@ -151,7 +151,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 events.sort() expected = [ @@ -168,7 +168,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 expected = [(server.fileno(), select.EPOLLOUT)] assert events == expected @@ -192,7 +192,7 @@ now = time.time() ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 server.close() ep.unregister(fd) diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -28,6 +28,13 @@ return w_delattr object_delattr._annspecialcase_ = 'specialize:memo' +def object_hash(space): + "Utility that returns the app-level descriptor object.__hash__." + w_src, w_hash = space.lookup_in_type_where(space.w_object, + '__hash__') + return w_hash +object_hash._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): w_type = space.type(w_obj) typename = w_type.getname(space) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -157,11 +157,15 @@ return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): - #XXX implement other strategies later + withidentitydict = self.space.config.objspace.std.withidentitydict if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) - elif self.space.is_w(self.space.type(w_key), self.space.w_int): + return + w_type = self.space.type(w_key) + if self.space.is_w(w_type, self.space.w_int): self.switch_to_int_strategy(w_dict) + elif withidentitydict and w_type.compares_by_identity(): + self.switch_to_identity_strategy(w_dict) else: self.switch_to_object_strategy(w_dict) @@ -177,6 +181,13 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_identity_strategy(self, w_dict): + from pypy.objspace.std.identitydict import IdentityDictStrategy + strategy = self.space.fromcache(IdentityDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): strategy = self.space.fromcache(ObjectDictStrategy) storage = strategy.get_empty_storage() @@ -338,7 +349,6 @@ def getitem(self, w_dict, w_key): space = self.space - if self.is_correct_type(w_key): return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) elif self._never_equal_to(space.type(w_key)): @@ -404,6 +414,7 @@ def keys(self, w_dict): return self.unerase(w_dict.dstorage).keys() + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") @@ -448,7 +459,9 @@ return StrIteratorImplementation(self.space, self, w_dict) -class StrIteratorImplementation(IteratorImplementation): +class _WrappedIteratorMixin(object): + _mixin_ = True + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() @@ -460,6 +473,23 @@ else: return None, None +class _UnwrappedIteratorMixin: + _mixin_ = True + + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value + else: + return None, None + + +class StrIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass class IntDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("int") @@ -490,31 +520,11 @@ def iter(self, w_dict): return IntIteratorImplementation(self.space, self, w_dict) -class IntIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() +class IntIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass - def next_entry(self): - # note that this 'for' loop only runs once, at most - for key, w_value in self.iterator: - return self.space.wrap(key), w_value - else: - return None, None - - -class ObjectIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() - - def next_entry(self): - # note that this 'for' loop only runs once, at most - for w_key, w_value in self.iterator: - return w_key, w_value - else: - return None, None - +class ObjectIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass init_signature = Signature(['seq_or_map'], None, 'kwargs') init_defaults = [None] diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -86,7 +86,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated() + self.unerase(w_dict.dstorage).mutated(None) class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -133,8 +133,7 @@ else: return space.wrap("0x%sp%s%d" % (s, sign, exp)) -def float2string(space, w_float, code, precision): - x = w_float.floatval +def float2string(x, code, precision): # we special-case explicitly inf and nan here if isfinite(x): s = formatd(x, code, precision, DTSF_ADD_DOT_0) @@ -145,13 +144,13 @@ s = "-inf" else: # isnan(x): s = "nan" - return space.wrap(s) + return s def repr__Float(space, w_float): - return float2string(space, w_float, 'r', 0) + return space.wrap(float2string(w_float.floatval, 'r', 0)) def str__Float(space, w_float): - return float2string(space, w_float, 'g', DTSF_STR_PRECISION) + return space.wrap(float2string(w_float.floatval, 'g', DTSF_STR_PRECISION)) def format__Float_ANY(space, w_float, w_spec): return newformat.run_formatter(space, w_spec, "format_float", w_float) diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/identitydict.py @@ -0,0 +1,85 @@ +## ---------------------------------------------------------------------------- +## dict strategy (see dict_multiobject.py) + +from pypy.rlib import rerased +from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, + DictStrategy, + IteratorImplementation, + _UnwrappedIteratorMixin) + + +# this strategy is selected by EmptyDictStrategy.switch_to_correct_strategy +class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): + """ + Strategy for custom instances which compares by identity (i.e., the + default unless you override __hash__, __eq__ or __cmp__). The storage is + just a normal RPython dict, which has already the correct by-identity + semantics. + + Note that at a first sight, you might have problems if you mutate the + class of an object which is already inside an identitydict. Consider this + example:: + + class X(object): + pass + d = {x(): 1} + X.__eq__ = ... + d[y] # might trigger a call to __eq__? + + We want to be sure that x.__eq__ is called in the same cases as in + CPython. However, as long as the strategy is IdentityDictStrategy, the + __eq__ will never be called. + + It turns out that it's not a problem. In CPython (and in PyPy without + this strategy), the __eq__ is called if ``hash(y) == hash(x)`` and ``x is + not y``. Note that hash(x) is computed at the time when we insert x in + the dict, not at the time we lookup y. + + Now, how can hash(y) == hash(x)? There are two possibilities: + + 1. we write a custom __hash__ for the class of y, thus making it a not + "compares by reference" type + + 2. the class of y is "compares by reference" type, and by chance the + hash is the same as x + + In the first case, the getitem immediately notice that y is not of the + right type, and switches the strategy to ObjectDictStrategy, then the + lookup works as usual. + + The second case is completely non-deterministic, even in CPython. + Depending on the phase of the moon, you might call the __eq__ or not, so + it is perfectly fine to *never* call it. Morever, in practice with the + minimar GC we never have two live objects with the same hash, so it would + never happen anyway. + """ + + erase, unerase = rerased.new_erasing_pair("identitydict") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): + w_type = self.space.type(w_obj) + return w_type.compares_by_identity() + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return IdentityDictIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + + +class IdentityDictIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -6,7 +6,7 @@ from pypy.objspace.descroperation import Object from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.register_all import register_all - +from pypy.objspace.std import identitydict def descr__repr__(space, w_obj): w = space.wrap diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -39,7 +39,6 @@ from pypy.objspace.std.stringtype import wrapstr from pypy.objspace.std.unicodetype import wrapunicode - class StdObjSpace(ObjSpace, DescrOperation): """The standard object space, implementing a general-purpose object library in Restricted Python.""" diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -898,6 +898,7 @@ withsmalldicts = False withcelldict = False withmethodcache = False + withidentitydict = False FakeSpace.config = Config() @@ -1105,3 +1106,4 @@ fakespace = FakeSpace() d = fakespace.newdict(module=True) assert type(d.strategy) is StringDictStrategy + diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_identitydict.py @@ -0,0 +1,138 @@ +import py +from pypy.interpreter.gateway import interp2app +from pypy.conftest import gettestobjspace +from pypy.conftest import option + +class AppTestComparesByIdentity: + + def setup_class(cls): + from pypy.objspace.std import identitydict + cls.space = gettestobjspace( + **{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("interp2app doesn't work on appdirect") + + def compares_by_identity(space, w_cls): + return space.wrap(w_cls.compares_by_identity()) + cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) + + def test_compares_by_identity(self): + class Plain(object): + pass + + class CustomEq(object): + def __eq__(self, other): + return True + + class CustomCmp (object): + def __cmp__(self, other): + return 0 + + class CustomHash(object): + def __hash__(self): + return 0 + + assert self.compares_by_identity(Plain) + assert not self.compares_by_identity(CustomEq) + assert not self.compares_by_identity(CustomCmp) + assert not self.compares_by_identity(CustomHash) + + def test_modify_class(self): + class X(object): + pass + + assert self.compares_by_identity(X) + X.__eq__ = lambda x: None + assert not self.compares_by_identity(X) + del X.__eq__ + assert self.compares_by_identity(X) + + +class AppTestIdentityDict(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("interp2app doesn't work on appdirect") + + def w_uses_identity_strategy(self, obj): + import __pypy__ + return "IdentityDictStrategy" in __pypy__.internal_repr(obj) + + def test_use_strategy(self): + class X(object): + pass + d = {} + x = X() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[x] == 1 + + def test_bad_item(self): + class X(object): + pass + class Y(object): + def __hash__(self): + return 32 + + d = {} + x = X() + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + d[y] = 2 + assert not self.uses_identity_strategy(d) + assert d[x] == 1 + assert d[y] == 2 + + def test_bad_key(self): + class X(object): + pass + d = {} + x = X() + + class Y(object): + def __hash__(self): + return hash(x) # to make sure we do x == y + + def __eq__(self, other): + return True + + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[y] == 1 + assert not self.uses_identity_strategy(d) + + def test_iter(self): + class X(object): + pass + x = X() + d = {x: 1} + assert self.uses_identity_strategy(d) + assert list(iter(d)) == [x] + + def test_mutate_class_and_then_compare(self): + class X(object): + pass + class Y(object): + pass + + x = X() + y = Y() + d1 = {x: 1} + d2 = {y: 1} + assert self.uses_identity_strategy(d1) + assert self.uses_identity_strategy(d2) + # + X.__hash__ = lambda self: hash(y) + X.__eq__ = lambda self, other: True + # + assert d1 == d2 + assert self.uses_identity_strategy(d1) + assert not self.uses_identity_strategy(d2) + + def test_old_style_classes(self): + class X: + pass + d = {X(): 1} + assert not self.uses_identity_strategy(d) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -7,6 +7,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member from pypy.objspace.std.objecttype import object_typedef +from pypy.objspace.std import identitydict from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash from pypy.rlib.jit import promote, elidable_promote, we_are_jitted @@ -76,6 +77,10 @@ for i in range(len(self.lookup_where)): self.lookup_where[i] = None_None +# possible values of compares_by_identity_status +UNKNOWN = 0 +COMPARES_BY_IDENTITY = 1 +OVERRIDES_EQ_CMP_OR_HASH = 2 class W_TypeObject(W_Object): from pypy.objspace.std.typetype import type_typedef as typedef @@ -102,6 +107,9 @@ # (False is a conservative default, fixed during real usage) uses_object_getattribute = False + # for config.objspace.std.withidentitydict + compares_by_identity_status = UNKNOWN + # used to cache the type __new__ function if it comes from a builtin type # != 'type', in that case call__Type will also assumes the result # of the __new__ is an instance of the type @@ -146,11 +154,17 @@ else: w_self.terminator = NoDictTerminator(space, w_self) - def mutated(w_self): + def mutated(w_self, key): + """ + The type is being mutated. key is either the string containing the + specific attribute which is being deleted/set or None to indicate a + generic mutation. + """ space = w_self.space assert w_self.is_heaptype() or space.config.objspace.std.mutable_builtintypes if (not space.config.objspace.std.withtypeversion and not space.config.objspace.std.getattributeshortcut and + not space.config.objspace.std.withidentitydict and not space.config.objspace.std.newshortcut): return @@ -158,6 +172,13 @@ w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage + if space.config.objspace.std.withidentitydict: + did_compare_by_identity = ( + w_self.compares_by_identity_status == COMPARES_BY_IDENTITY) + if (key is None or key == '__eq__' or + key == '__cmp__' or key == '__hash__'): + w_self.compares_by_identity_status = UNKNOWN + if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None @@ -168,7 +189,7 @@ subclasses_w = w_self.get_subclasses() for w_subclass in subclasses_w: assert isinstance(w_subclass, W_TypeObject) - w_subclass.mutated() + w_subclass.mutated(key) def version_tag(w_self): if (not we_are_jitted() or w_self.is_heaptype() or @@ -207,6 +228,25 @@ def has_object_getattribute(w_self): return w_self.getattribute_if_not_from_object() is None + def compares_by_identity(w_self): + from pypy.objspace.descroperation import object_hash + if not w_self.space.config.objspace.std.withidentitydict: + return False # conservative + # + if w_self.compares_by_identity_status != UNKNOWN: + # fast path + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + # + default_hash = object_hash(w_self.space) + overrides_eq_cmp_or_hash = (w_self.lookup('__eq__') or + w_self.lookup('__cmp__') or + w_self.lookup('__hash__') is not default_hash) + if overrides_eq_cmp_or_hash: + w_self.compares_by_identity_status = OVERRIDES_EQ_CMP_OR_HASH + else: + w_self.compares_by_identity_status = COMPARES_BY_IDENTITY + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + def ready(w_self): for w_base in w_self.bases_w: if not isinstance(w_base, W_TypeObject): @@ -269,7 +309,7 @@ w_curr.w_value = w_value return True w_value = TypeCell(w_value) - w_self.mutated() + w_self.mutated(name) w_self.dict_w[name] = w_value return True @@ -286,7 +326,7 @@ except KeyError: return False else: - w_self.mutated() + w_self.mutated(key) return True def lookup(w_self, name): diff --git a/pypy/objspace/std/typetype.py b/pypy/objspace/std/typetype.py --- a/pypy/objspace/std/typetype.py +++ b/pypy/objspace/std/typetype.py @@ -141,7 +141,7 @@ w_oldbestbase.getname(space)) # invalidate the version_tag of all the current subclasses - w_type.mutated() + w_type.mutated(None) # now we can go ahead and change 'w_type.bases_w' saved_bases_w = w_type.bases_w diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -875,28 +875,32 @@ if bufsize == -1: # Get default from the class bufsize = self.bufsize self.bufsize = bufsize # buffer size (hint only) - self.buf = "" + self.buf = [] + self.buflen = 0 def flush_buffers(self): if self.buf: - self.do_write(self.buf) - self.buf = "" + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 def tell(self): - return self.do_tell() + len(self.buf) + return self.do_tell() + self.buflen def write(self, data): - buflen = len(self.buf) + buflen = self.buflen datalen = len(data) if datalen + buflen < self.bufsize: - self.buf += data + self.buf.append(data) + self.buflen += datalen elif buflen: - slice = self.bufsize - buflen - assert slice >= 0 - self.buf += data[:slice] - self.do_write(self.buf) - self.buf = "" - self.write(data[slice:]) + i = self.bufsize - buflen + assert i >= 0 + self.buf.append(data[:i]) + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 + self.write(data[i:]) else: self.do_write(data) @@ -922,11 +926,27 @@ """ def write(self, data): - BufferingOutputStream.write(self, data) - p = self.buf.rfind('\n') + 1 - if p >= 0: - self.do_write(self.buf[:p]) - self.buf = self.buf[p:] + p = data.rfind('\n') + 1 + assert p >= 0 + if self.buflen + len(data) < self.bufsize: + if p == 0: + self.buf.append(data) + self.buflen += len(data) + else: + if self.buflen: + self.do_write(''.join(self.buf)) + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) + else: + if self.buflen + p < self.bufsize: + p = self.bufsize - self.buflen + if self.buflen: + self.do_write(''.join(self.buf)) + assert p >= 0 + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) # ____________________________________________________________ diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py --- a/pypy/rpython/memory/gctransform/asmgcroot.py +++ b/pypy/rpython/memory/gctransform/asmgcroot.py @@ -184,7 +184,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.aid2stack = copy_without_null_values(gcdata.aid2stack) + copy = copy_without_null_values(gcdata.aid2stack) + gcdata.aid2stack.delete() + gcdata.aid2stack = copy def belongs_to_current_thread(framedata): # xxx obscure: the answer is Yes if, as a pointer, framedata diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1449,8 +1449,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.thread_stacks = copy_without_null_values( - gcdata.thread_stacks) + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy def switch_shadow_stacks(new_aid): save_away_current_stack() diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -18,4 +18,5 @@ if __name__ == '__main__': import tool.autopath import pytest - sys.exit(pytest.main()) + import pytest_cov + sys.exit(pytest.main(plugins=[pytest_cov])) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -30,6 +30,9 @@ def getres(self): return self._getvar(self.res) + def getdescr(self): + return self.descr + def _getvar(self, v): return v @@ -39,7 +42,7 @@ def repr(self): args = self.getargs() if self.descr is not None: - args.append('descr=%s' % self.descr) + args.append('descr=%s' % self.getdescr()) arglist = ', '.join(args) if self.res is not None: return '%s = %s(%s)' % (self.getres(), self.name, arglist) @@ -145,10 +148,10 @@ if operations[0].name == 'debug_merge_point': self.inline_level = int(operations[0].args[0]) m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', - operations[0].getarg(1)) + operations[0].args[1]) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1][1:-1] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,6 +1,6 @@ from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, Function, adjust_bridges, - import_log) + import_log, Op) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys @@ -181,7 +181,7 @@ """) ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] - assert chunk.bytecode_name == 'StrLiteralSearch' + assert chunk.bytecode_name.startswith('StrLiteralSearch') def test_parsing_assembler(): backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" @@ -225,3 +225,9 @@ assert 'cmp' in loops[1].operations[1].asm # bridge assert 'jo' in loops[3].operations[3].asm + +def test_Op_repr_is_pure(): + op = Op('foobar', ['a', 'b'], 'c', 'mydescr') + myrepr = 'c = foobar(a, b, descr=mydescr)' + assert op.repr() == myrepr + assert op.repr() == myrepr # do it twice diff --git a/pypy/tool/release/win32build.py b/pypy/tool/release/win32build.py --- a/pypy/tool/release/win32build.py +++ b/pypy/tool/release/win32build.py @@ -24,6 +24,6 @@ shutil.copy(str(pypydir.join('..', '..', 'expat-2.0.1', 'win32', 'bin', 'release', 'libexpat.dll')), str(builddir)) make_pypy('', ['-Ojit']) -make_pypy('-nojit', []) +make_pypy('-nojit', ['-O2']) #make_pypy('-stackless', [--stackless]) #make_pypy('-sandbox', [--sandbox]) diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -251,12 +251,8 @@ CBuilder.have___thread = self.translator.platform.check___thread() if not self.standalone: assert not self.config.translation.instrument - self.eci, cfile, extra = gen_source(db, modulename, targetdir, - self.eci, - defines = defines, - split=self.split) else: - pfname = db.get(pf) + defines['PYPY_STANDALONE'] = db.get(pf) if self.config.translation.instrument: defines['INSTRUMENT'] = 1 if CBuilder.have___thread: @@ -266,11 +262,9 @@ defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( export_symbols=["pypy_main_startup"])) - self.eci, cfile, extra = gen_source_standalone(db, modulename, - targetdir, - self.eci, - entrypointname = pfname, - defines = defines) + self.eci, cfile, extra = gen_source(db, modulename, targetdir, + self.eci, defines=defines, + split=self.split) self.c_source_filename = py.path.local(cfile) self.extrafiles = self.eventually_copy(extra) self.gen_makefile(targetdir, exe_name=exe_name) @@ -435,6 +429,7 @@ class CStandaloneBuilder(CBuilder): standalone = True + split = True executable_name = None shared_library_name = None @@ -948,63 +943,8 @@ return eci.merge(ExternalCompilationInfo(separate_module_files=files)) -def gen_source_standalone(database, modulename, targetdir, eci, - entrypointname, defines={}): - assert database.standalone - if isinstance(targetdir, str): - targetdir = py.path.local(targetdir) - - filename = targetdir.join(modulename + '.c') - f = filename.open('w') - incfilename = targetdir.join('common_header.h') - fi = incfilename.open('w') - - # - # Header - # - print >> f, '#include "common_header.h"' - print >> f - commondefs(defines) - defines['PYPY_STANDALONE'] = entrypointname - for key, value in defines.items(): - print >> fi, '#define %s %s' % (key, value) - - eci.write_c_header(fi) - print >> fi, '#include "src/g_prerequisite.h"' - - fi.close() - - preimplementationlines = list( - pre_include_code_lines(database, database.translator.rtyper)) - - # - # 1) All declarations - # 2) Implementation of functions and global structures and arrays - # - sg = SourceGenerator(database, preimplementationlines) - sg.set_strategy(targetdir) - database.prepare_inline_helpers() - sg.gen_readable_parts_of_source(f) - - # 3) start-up code - print >> f - gen_startupcode(f, database) - - f.close() - - if 'INSTRUMENT' in defines: - fi = incfilename.open('a') - n = database.instrument_ncounter - print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n - fi.close() - - eci = add_extra_files(eci) - eci = eci.convert_sources_to_files(being_main=True) - files, eci = eci.get_module_files() - return eci, filename, sg.getextrafiles() + list(files) - -def gen_source(database, modulename, targetdir, eci, defines={}, split=False): - assert not database.standalone +def gen_source(database, modulename, targetdir, + eci, defines={}, split=False): if isinstance(targetdir, str): targetdir = py.path.local(targetdir) @@ -1046,6 +986,12 @@ gen_startupcode(f, database) f.close() + if 'INSTRUMENT' in defines: + fi = incfilename.open('a') + n = database.instrument_ncounter + print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n + fi.close() + eci = add_extra_files(eci) eci = eci.convert_sources_to_files(being_main=True) files, eci = eci.get_module_files() diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py --- a/pypy/translator/c/test/test_genc.py +++ b/pypy/translator/c/test/test_genc.py @@ -4,7 +4,6 @@ from pypy.translator.translator import TranslationContext from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c import genc -from pypy.translator.c.genc import gen_source from pypy.translator.c.gc import NoneGcPolicy from pypy.objspace.flow.model import Constant, Variable, SpaceOperation from pypy.objspace.flow.model import Block, Link, FunctionGraph diff --git a/pytest.py b/pytest.py --- a/pytest.py +++ b/pytest.py @@ -9,6 +9,8 @@ from _pytest import __version__ if __name__ == '__main__': # if run as a script or by 'python -m pytest' - raise SystemExit(main()) + #XXX: sync to upstream later + import pytest_cov + raise SystemExit(main(plugins=[pytest_cov])) else: _preloadplugins() # to populate pytest.* namespace so help(pytest) works diff --git a/pytest_cov.py b/pytest_cov.py new file mode 100644 --- /dev/null +++ b/pytest_cov.py @@ -0,0 +1,353 @@ +"""produce code coverage reports using the 'coverage' package, including support for distributed testing. + +This plugin produces coverage reports. It supports centralised testing and distributed testing in +both load and each modes. It also supports coverage of subprocesses. + +All features offered by the coverage package should be available, either through pytest-cov or +through coverage's config file. + + +Installation +------------ + +The `pytest-cov`_ package may be installed with pip or easy_install:: + + pip install pytest-cov + easy_install pytest-cov + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov/ + + +Uninstallation +-------------- + +Uninstalling packages is supported by pip:: + + pip uninstall pytest-cov + +However easy_install does not provide an uninstall facility. + +.. IMPORTANT:: + + Ensure that you manually delete the init_cov_core.pth file in your site-packages directory. + + This file starts coverage collection of subprocesses if appropriate during site initialisation + at python startup. + + +Usage +----- + +Centralised Testing +~~~~~~~~~~~~~~~~~~~ + +Centralised testing will report on the combined coverage of the main process and all of it's +subprocesses. + +Running centralised testing:: + + py.test --cov myproj tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Load +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to load will report on the combined coverage of all slaves. +The slaves may be spread out over any number of hosts and each slave may be located anywhere on the +file system. Each slave will have it's subprocesses measured. + +Running distributed testing with dist mode set to load:: + + py.test --cov myproj -n 2 tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Again but spread over different hosts and different directories:: + + py.test --cov myproj --dist load + --tx ssh=memedough at host1//chdir=testenv1 + --tx ssh=memedough at host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Each +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to each will report on the combined coverage of all slaves. +Since each slave is running all tests this allows generating a combined coverage report for multiple +environments. + +Running distributed testing with dist mode set to each:: + + py.test --cov myproj --dist each + --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python + --tx ssh=memedough at host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + ---------------------------------------- coverage ---------------------------------------- + platform linux2, python 2.6.5-final-0 + platform linux2, python 2.7.0-final-0 + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Reporting +--------- + +It is possible to generate any combination of the reports for a single test run. + +The available reports are terminal (with or without missing line numbers shown), HTML, XML and +annotated source code. + +The terminal report without line numbers (default):: + + py.test --cov-report term --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +The terminal report with line numbers:: + + py.test --cov-report term-missing --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover Missing + -------------------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% 24-26, 99, 149, 233-236, 297-298, 369-370 + myproj/feature4286 94 7 92% 183-188, 197 + -------------------------------------------------- + TOTAL 353 20 94% + + +The remaining three reports output to files without showing anything on the terminal (useful for +when the output is going to a continuous integration server):: + + py.test --cov-report html + --cov-report xml + --cov-report annotate + --cov myproj tests/ + + +Coverage Data File +------------------ + +The data file is erased at the beginning of testing to ensure clean data for each test run. + +The data file is left at the end of testing so that it is possible to use normal coverage tools to +examine it. + + +Coverage Config File +-------------------- + +This plugin provides a clean minimal set of command line options that are added to pytest. For +further control of coverage use a coverage config file. + +For example if tests are contained within the directory tree being measured the tests may be +excluded if desired by using a .coveragerc file with the omit option set:: + + py.test --cov-config .coveragerc + --cov myproj + myproj/tests/ + +Where the .coveragerc file contains file globs:: + + [run] + omit = tests/* + +For full details refer to the `coverage config file`_ documentation. + +.. _`coverage config file`: http://nedbatchelder.com/code/coverage/config.html + +Note that this plugin controls some options and setting the option in the config file will have no +effect. These include specifying source to be measured (source option) and all data file handling +(data_file and parallel options). + + +Limitations +----------- + +For distributed testing the slaves must have the pytest-cov package installed. This is needed since +the plugin must be registered through setuptools / distribute for pytest to start the plugin on the +slave. + +For subprocess measurement environment variables must make it from the main process to the +subprocess. The python used by the subprocess must have pytest-cov installed. The subprocess must +do normal site initialisation so that the environment variables can be detected and coverage +started. + + +Acknowledgements +---------------- + +Whilst this plugin has been built fresh from the ground up it has been influenced by the work done +on pytest-coverage (Ross Lawley, James Mills, Holger Krekel) and nose-cover (Jason Pellerin) which are +other coverage plugins. + +Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs. + +Holger Krekel for pytest with its distributed testing support. + +Jason Pellerin for nose. + +Michael Foord for unittest2. + +No doubt others have contributed to these tools as well. +""" + + +def pytest_addoption(parser): + """Add options to control coverage.""" + + group = parser.getgroup('coverage reporting with distributed testing support') + group.addoption('--cov', action='append', default=[], metavar='path', + dest='cov_source', + help='measure coverage for filesystem path (multi-allowed)') + group.addoption('--cov-report', action='append', default=[], metavar='type', + choices=['term', 'term-missing', 'annotate', 'html', 'xml'], + dest='cov_report', + help='type of report to generate: term, term-missing, annotate, html, xml (multi-allowed)') + group.addoption('--cov-config', action='store', default='.coveragerc', metavar='path', + dest='cov_config', + help='config file for coverage, default: .coveragerc') + + +def pytest_configure(config): + """Activate coverage plugin if appropriate.""" + + if config.getvalue('cov_source'): + config.pluginmanager.register(CovPlugin(), '_cov') + + +class CovPlugin(object): + """Use coverage package to produce code coverage reports. + + Delegates all work to a particular implementation based on whether + this test process is centralised, a distributed master or a + distributed slave. + """ + + def __init__(self): + """Creates a coverage pytest plugin. + + We read the rc file that coverage uses to get the data file + name. This is needed since we give coverage through it's API + the data file name. + """ + + # Our implementation is unknown at this time. + self.cov_controller = None + + def pytest_sessionstart(self, session): + """At session start determine our implementation and delegate to it.""" + + import cov_core + + cov_source = session.config.getvalue('cov_source') + cov_report = session.config.getvalue('cov_report') or ['term'] + cov_config = session.config.getvalue('cov_config') + + session_name = session.__class__.__name__ + is_master = (session.config.pluginmanager.hasplugin('dsession') or + session_name == 'DSession') + is_slave = (hasattr(session.config, 'slaveinput') or + session_name == 'SlaveSession') + nodeid = None + + if is_master: + controller_cls = cov_core.DistMaster + elif is_slave: + controller_cls = cov_core.DistSlave + nodeid = session.config.slaveinput.get('slaveid', getattr(session, 'nodeid')) + else: + controller_cls = cov_core.Central + + self.cov_controller = controller_cls(cov_source, + cov_report, + cov_config, + session.config, + nodeid) + + self.cov_controller.start() + + def pytest_configure_node(self, node): + """Delegate to our implementation.""" + + self.cov_controller.configure_node(node) + pytest_configure_node.optionalhook = True + + def pytest_testnodedown(self, node, error): + """Delegate to our implementation.""" + + self.cov_controller.testnodedown(node, error) + pytest_testnodedown.optionalhook = True + + def pytest_sessionfinish(self, session, exitstatus): + """Delegate to our implementation.""" + + self.cov_controller.finish() + + def pytest_terminal_summary(self, terminalreporter): + """Delegate to our implementation.""" + + self.cov_controller.summary(terminalreporter._tw) + + +def pytest_funcarg__cov(request): + """A pytest funcarg that provides access to the underlying coverage object.""" + + # Check with hasplugin to avoid getplugin exception in older pytest. + if request.config.pluginmanager.hasplugin('_cov'): + plugin = request.config.pluginmanager.getplugin('_cov') + if plugin.cov_controller: + return plugin.cov_controller.cov + return None From noreply at buildbot.pypy.org Sat Jul 23 11:00:28 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 11:00:28 +0200 (CEST) Subject: [pypy-commit] pypy default: On CPython, some functions accept integers of any size and Message-ID: <20110723090028.60050829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45894:48020b9e373b Date: 2011-07-23 11:00 +0200 http://bitbucket.org/pypy/pypy/changeset/48020b9e373b/ Log: On CPython, some functions accept integers of any size and truncate. This seems to be important at least for crc32() and adler32(), so fix it for them. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -1284,6 +1284,17 @@ self.wrap("expected a 32-bit integer")) return value + def truncatedint(self, w_obj): + # Like space.gateway_int_w(), but return the integer truncated + # instead of raising OverflowError. For obscure cases only. + try: + return self.int_w(w_obj) + except OperationError, e: + if not e.match(self, self.w_OverflowError): + raise + from pypy.rlib.rarithmetic import intmask + return intmask(self.bigint_w(w_obj).uintmask()) + def c_filedescriptor_w(self, w_fd): # This is only used sometimes in CPython, e.g. for os.fsync() but # not os.close(). It's likely designed for 'select'. It's irregular diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -140,6 +140,9 @@ def visit_c_nonnegint(self, el, app_sig): self.checked_space_method(el, app_sig) + def visit_truncatedint(self, el, app_sig): + self.checked_space_method(el, app_sig) + def visit__Wrappable(self, el, app_sig): name = el.__name__ argname = self.orig_arg() @@ -257,6 +260,9 @@ def visit_c_nonnegint(self, typ): self.run_args.append("space.c_nonnegint_w(%s)" % (self.scopenext(),)) + def visit_truncatedint(self, typ): + self.run_args.append("space.truncatedint(%s)" % (self.scopenext(),)) + def _make_unwrap_activation_class(self, unwrap_spec, cache={}): try: key = tuple(unwrap_spec) @@ -387,6 +393,9 @@ def visit_c_nonnegint(self, typ): self.unwrap.append("space.c_nonnegint_w(%s)" % (self.nextarg(),)) + def visit_truncatedint(self, typ): + self.unwrap.append("space.truncatedint(%s)" % (self.nextarg(),)) + def make_fastfunc(unwrap_spec, func): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) diff --git a/pypy/module/binascii/interp_crc32.py b/pypy/module/binascii/interp_crc32.py --- a/pypy/module/binascii/interp_crc32.py +++ b/pypy/module/binascii/interp_crc32.py @@ -61,7 +61,7 @@ crc_32_tab = map(r_uint, crc_32_tab) - at unwrap_spec(data='bufferstr', oldcrc='c_int') + at unwrap_spec(data='bufferstr', oldcrc='truncatedint') def crc32(space, data, oldcrc=0): "Compute the CRC-32 incrementally." diff --git a/pypy/module/binascii/test/test_binascii.py b/pypy/module/binascii/test/test_binascii.py --- a/pypy/module/binascii/test/test_binascii.py +++ b/pypy/module/binascii/test/test_binascii.py @@ -374,6 +374,8 @@ ('x', 10000, -1855256896), ('y', 10000, -429115818), ('z', 10000, 2137352172), + ('foo', 99999999999999999999999999, -1932704816), + ('bar', -99999999999999999999999999, 2000545409), ]: assert self.binascii.crc32(input, initial) == expected diff --git a/pypy/module/zlib/interp_zlib.py b/pypy/module/zlib/interp_zlib.py --- a/pypy/module/zlib/interp_zlib.py +++ b/pypy/module/zlib/interp_zlib.py @@ -20,25 +20,15 @@ return intmask((x ^ SIGN_EXTEND2) - SIGN_EXTEND2) - at unwrap_spec(string='bufferstr') -def crc32(space, string, w_start = rzlib.CRC32_DEFAULT_START): + at unwrap_spec(string='bufferstr', start='truncatedint') +def crc32(space, string, start = rzlib.CRC32_DEFAULT_START): """ crc32(string[, start]) -- Compute a CRC-32 checksum of string. An optional starting value can be specified. The returned checksum is an integer. """ - if space.is_true(space.isinstance(w_start, space.w_long)): - num = space.bigint_w(w_start) - ustart = num.uintmask() - elif space.is_true(space.isinstance(w_start, space.w_int)): - start = space.int_w(w_start) ustart = r_uint(start) - else: - raise OperationError(space.w_TypeError, - space.wrap("crc32() argument 2 must " - "be integer, not str")) - checksum = rzlib.crc32(string, ustart) # This is, perhaps, a little stupid. zlib returns the checksum unsigned. @@ -51,7 +41,7 @@ return space.wrap(checksum) - at unwrap_spec(string='bufferstr', start=r_uint) + at unwrap_spec(string='bufferstr', start='truncatedint') def adler32(space, string, start=rzlib.ADLER32_DEFAULT_START): """ adler32(string[, start]) -- Compute an Adler-32 checksum of string. @@ -59,7 +49,8 @@ An optional starting value can be specified. The returned checksum is an integer. """ - checksum = rzlib.adler32(string, start) + ustart = r_uint(start) + checksum = rzlib.adler32(string, ustart) # See comments in crc32() for the following line checksum = unsigned_to_signed_32bit(checksum) diff --git a/pypy/module/zlib/test/test_zlib.py b/pypy/module/zlib/test/test_zlib.py --- a/pypy/module/zlib/test/test_zlib.py +++ b/pypy/module/zlib/test/test_zlib.py @@ -78,15 +78,17 @@ def test_crc32_negative_long_start(self): v = self.zlib.crc32('', -1L) assert v == -1 + assert self.zlib.crc32('foo', -99999999999999999999999) == 1611238463 def test_crc32_long_start(self): import sys v = self.zlib.crc32('', sys.maxint*2) assert v == -2 + assert self.zlib.crc32('foo', 99999999999999999999999) == 1635107045 def test_adler32(self): """ - When called with a string, zlib.crc32 should compute its adler 32 + When called with a string, zlib.adler32() should compute its adler 32 checksum and return it as a signed 32 bit integer. On 64-bit machines too (it is a bug in CPython < 2.6 to return unsigned values in this case). @@ -113,6 +115,9 @@ helloworldsum = self.zlib.adler32(world, hellosum) assert helloworldsum == self.zlib.adler32(hello + world) + assert self.zlib.adler32('foo', -1) == 45547858 + assert self.zlib.adler32('foo', 99999999999999999999999) == -114818734 + def test_invalidLevel(self): """ From noreply at buildbot.pypy.org Sat Jul 23 11:02:51 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sat, 23 Jul 2011 11:02:51 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Calling super(...).__init__() wasn't necessary here. Message-ID: <20110723090251.0361C829BA@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45895:3589c6241735 Date: 2011-07-23 02:02 -0700 http://bitbucket.org/pypy/pypy/changeset/3589c6241735/ Log: Calling super(...).__init__() wasn't necessary here. diff --git a/pypy/translator/cli/metavm.py b/pypy/translator/cli/metavm.py --- a/pypy/translator/cli/metavm.py +++ b/pypy/translator/cli/metavm.py @@ -176,7 +176,6 @@ class _UnboxType(MicroInstruction): def __init__(self, TO): self.TO = TO - super(_UnboxType, self).__init__() def render(self, generator, op): v_obj, = op.args From noreply at buildbot.pypy.org Sat Jul 23 12:01:47 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 12:01:47 +0200 (CEST) Subject: [pypy-commit] pypy default: fix and don"t compare pointers by is Message-ID: <20110723100147.3B663829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45896:8c9bfd29cb30 Date: 2011-07-23 12:01 +0200 http://bitbucket.org/pypy/pypy/changeset/8c9bfd29cb30/ Log: fix and don"t compare pointers by is diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -248,8 +248,8 @@ if isinstance(w_value, BaseArray): # for now we just copy if setting part of an array from # part of itself. can be improved. - if concrete.get_root_storage() is \ - w_value.get_concrete().get_root_storage(): + if (concrete.get_root_storage() == + w_value.get_concrete().get_root_storage()): w_value = new_numarray(space, w_value) else: w_value = convert_to_array(space, w_value) @@ -453,7 +453,7 @@ self.size = slice_length def get_root_storage(self): - self.parent.storage + return self.parent.storage def find_size(self): return self.size From noreply at buildbot.pypy.org Sat Jul 23 12:02:42 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sat, 23 Jul 2011 12:02:42 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Merge default. Message-ID: <20110723100242.43E53829BA@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45897:dd27ac5f6592 Date: 2011-07-23 03:02 -0700 http://bitbucket.org/pypy/pypy/changeset/dd27ac5f6592/ Log: Merge default. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -1284,6 +1284,17 @@ self.wrap("expected a 32-bit integer")) return value + def truncatedint(self, w_obj): + # Like space.gateway_int_w(), but return the integer truncated + # instead of raising OverflowError. For obscure cases only. + try: + return self.int_w(w_obj) + except OperationError, e: + if not e.match(self, self.w_OverflowError): + raise + from pypy.rlib.rarithmetic import intmask + return intmask(self.bigint_w(w_obj).uintmask()) + def c_filedescriptor_w(self, w_fd): # This is only used sometimes in CPython, e.g. for os.fsync() but # not os.close(). It's likely designed for 'select'. It's irregular diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -140,6 +140,9 @@ def visit_c_nonnegint(self, el, app_sig): self.checked_space_method(el, app_sig) + def visit_truncatedint(self, el, app_sig): + self.checked_space_method(el, app_sig) + def visit__Wrappable(self, el, app_sig): name = el.__name__ argname = self.orig_arg() @@ -257,6 +260,9 @@ def visit_c_nonnegint(self, typ): self.run_args.append("space.c_nonnegint_w(%s)" % (self.scopenext(),)) + def visit_truncatedint(self, typ): + self.run_args.append("space.truncatedint(%s)" % (self.scopenext(),)) + def _make_unwrap_activation_class(self, unwrap_spec, cache={}): try: key = tuple(unwrap_spec) @@ -387,6 +393,9 @@ def visit_c_nonnegint(self, typ): self.unwrap.append("space.c_nonnegint_w(%s)" % (self.nextarg(),)) + def visit_truncatedint(self, typ): + self.unwrap.append("space.truncatedint(%s)" % (self.nextarg(),)) + def make_fastfunc(unwrap_spec, func): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) diff --git a/pypy/module/binascii/interp_crc32.py b/pypy/module/binascii/interp_crc32.py --- a/pypy/module/binascii/interp_crc32.py +++ b/pypy/module/binascii/interp_crc32.py @@ -61,7 +61,7 @@ crc_32_tab = map(r_uint, crc_32_tab) - at unwrap_spec(data='bufferstr', oldcrc='c_int') + at unwrap_spec(data='bufferstr', oldcrc='truncatedint') def crc32(space, data, oldcrc=0): "Compute the CRC-32 incrementally." diff --git a/pypy/module/binascii/test/test_binascii.py b/pypy/module/binascii/test/test_binascii.py --- a/pypy/module/binascii/test/test_binascii.py +++ b/pypy/module/binascii/test/test_binascii.py @@ -374,6 +374,8 @@ ('x', 10000, -1855256896), ('y', 10000, -429115818), ('z', 10000, 2137352172), + ('foo', 99999999999999999999999999, -1932704816), + ('bar', -99999999999999999999999999, 2000545409), ]: assert self.binascii.crc32(input, initial) == expected diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -248,8 +248,8 @@ if isinstance(w_value, BaseArray): # for now we just copy if setting part of an array from # part of itself. can be improved. - if concrete.get_root_storage() is \ - w_value.get_concrete().get_root_storage(): + if (concrete.get_root_storage() == + w_value.get_concrete().get_root_storage()): w_value = new_numarray(space, w_value) else: w_value = convert_to_array(space, w_value) @@ -453,7 +453,7 @@ self.size = slice_length def get_root_storage(self): - self.parent.storage + return self.parent.storage def find_size(self): return self.size diff --git a/pypy/module/zlib/interp_zlib.py b/pypy/module/zlib/interp_zlib.py --- a/pypy/module/zlib/interp_zlib.py +++ b/pypy/module/zlib/interp_zlib.py @@ -20,25 +20,15 @@ return intmask((x ^ SIGN_EXTEND2) - SIGN_EXTEND2) - at unwrap_spec(string='bufferstr') -def crc32(space, string, w_start = rzlib.CRC32_DEFAULT_START): + at unwrap_spec(string='bufferstr', start='truncatedint') +def crc32(space, string, start = rzlib.CRC32_DEFAULT_START): """ crc32(string[, start]) -- Compute a CRC-32 checksum of string. An optional starting value can be specified. The returned checksum is an integer. """ - if space.is_true(space.isinstance(w_start, space.w_long)): - num = space.bigint_w(w_start) - ustart = num.uintmask() - elif space.is_true(space.isinstance(w_start, space.w_int)): - start = space.int_w(w_start) ustart = r_uint(start) - else: - raise OperationError(space.w_TypeError, - space.wrap("crc32() argument 2 must " - "be integer, not str")) - checksum = rzlib.crc32(string, ustart) # This is, perhaps, a little stupid. zlib returns the checksum unsigned. @@ -51,7 +41,7 @@ return space.wrap(checksum) - at unwrap_spec(string='bufferstr', start=r_uint) + at unwrap_spec(string='bufferstr', start='truncatedint') def adler32(space, string, start=rzlib.ADLER32_DEFAULT_START): """ adler32(string[, start]) -- Compute an Adler-32 checksum of string. @@ -59,7 +49,8 @@ An optional starting value can be specified. The returned checksum is an integer. """ - checksum = rzlib.adler32(string, start) + ustart = r_uint(start) + checksum = rzlib.adler32(string, ustart) # See comments in crc32() for the following line checksum = unsigned_to_signed_32bit(checksum) diff --git a/pypy/module/zlib/test/test_zlib.py b/pypy/module/zlib/test/test_zlib.py --- a/pypy/module/zlib/test/test_zlib.py +++ b/pypy/module/zlib/test/test_zlib.py @@ -78,15 +78,17 @@ def test_crc32_negative_long_start(self): v = self.zlib.crc32('', -1L) assert v == -1 + assert self.zlib.crc32('foo', -99999999999999999999999) == 1611238463 def test_crc32_long_start(self): import sys v = self.zlib.crc32('', sys.maxint*2) assert v == -2 + assert self.zlib.crc32('foo', 99999999999999999999999) == 1635107045 def test_adler32(self): """ - When called with a string, zlib.crc32 should compute its adler 32 + When called with a string, zlib.adler32() should compute its adler 32 checksum and return it as a signed 32 bit integer. On 64-bit machines too (it is a bug in CPython < 2.6 to return unsigned values in this case). @@ -113,6 +115,9 @@ helloworldsum = self.zlib.adler32(world, hellosum) assert helloworldsum == self.zlib.adler32(hello + world) + assert self.zlib.adler32('foo', -1) == 45547858 + assert self.zlib.adler32('foo', 99999999999999999999999) == -114818734 + def test_invalidLevel(self): """ From noreply at buildbot.pypy.org Sat Jul 23 13:21:30 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sat, 23 Jul 2011 13:21:30 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Fix tests to remove redundancy. Message-ID: <20110723112130.AAD9B829BA@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45898:864d55a90e7e Date: 2011-07-23 04:21 -0700 http://bitbucket.org/pypy/pypy/changeset/864d55a90e7e/ Log: Fix tests to remove redundancy. diff --git a/pypy/translator/cli/test/test_int.py b/pypy/translator/cli/test/test_int.py --- a/pypy/translator/cli/test/test_int.py +++ b/pypy/translator/cli/test/test_int.py @@ -1,8 +1,8 @@ import py from pypy.translator.cli.test.runtest import CliTest -from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test -class TestCliInt(CliTest, BaseTestRint): +class TestCliInt(CliTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/jvm/test/test_int.py b/pypy/translator/jvm/test/test_int.py --- a/pypy/translator/jvm/test/test_int.py +++ b/pypy/translator/jvm/test/test_int.py @@ -1,10 +1,11 @@ import py from pypy.translator.jvm.test.runtest import JvmTest from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test # ====> ../../../rpython/test/test_rint.py -class TestJvmInt(JvmTest, BaseTestRint): +class TestJvmInt(JvmTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py --- a/pypy/translator/oosupport/test_template/operations.py +++ b/pypy/translator/oosupport/test_template/operations.py @@ -207,13 +207,6 @@ return bool(x) self._check_all(fn) - def test_box(self): - def f(): - x = 42 - y = llop.oobox_int(ootype.Object, x) - return llop.oounbox_int(lltype.Signed, y) - assert self.interpret(f, []) == 42 - def test_ullong_rshift(self): def f(x): return x >> 1 From noreply at buildbot.pypy.org Sat Jul 23 17:02:02 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 17:02:02 +0200 (CEST) Subject: [pypy-commit] pypy default: Tentative: set acceptable_as_base_class to False by default Message-ID: <20110723150202.C2640829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45899:02cebf6df7a0 Date: 2011-07-23 17:00 +0200 http://bitbucket.org/pypy/pypy/changeset/02cebf6df7a0/ Log: Tentative: set acceptable_as_base_class to False by default on TypeDefs that don't define a custom __new__. CPython tests appear to pass. diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -23,7 +23,7 @@ self.hasdict |= __base.hasdict self.weakrefable |= __base.weakrefable self.rawdict = {} - self.acceptable_as_base_class = True + self.acceptable_as_base_class = '__new__' in rawdict self.applevel_subclasses_base = None # xxx used by faking self.fakedcpytype = None From noreply at buildbot.pypy.org Sat Jul 23 17:26:18 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 17:26:18 +0200 (CEST) Subject: [pypy-commit] jitviewer default: slightly different approach to displaying where we are Message-ID: <20110723152618.E3F54829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r159:bc0e2179c8c4 Date: 2011-07-23 17:22 +0200 http://bitbucket.org/pypy/jitviewer/changeset/bc0e2179c8c4/ Log: slightly different approach to displaying where we are diff --git a/_jitviewer/static/script.js b/_jitviewer/static/script.js --- a/_jitviewer/static/script.js +++ b/_jitviewer/static/script.js @@ -3,17 +3,23 @@ function show_loop(no, path) { - $("#loop-" + glob_bridge_state.no).removeClass("selected"); + $("#title-text").html($("#loop-" + no).attr('name')); + $("#title").show(); glob_bridge_state.no = no; if (path) { glob_bridge_state.path = path; } else { delete glob_bridge_state.path; } - $("#loop-" + no).addClass("selected"); $.getJSON('/loop', glob_bridge_state, function(arg) { $('#main').html(arg.html).ready(function() { - $.scrollTo($('#line-' + arg.scrollto), 200, {axis:'y'}); + var scrollto; + if (arg.scrollto == 0) { + scrollto = 0; + } else { + scrollto = arg.scrollto - 1; + } + $.scrollTo($('#line-' + scrollto), 200, {axis:'y'}); }); $('#callstack').html('') for (var index in arg.callstack) { diff --git a/_jitviewer/static/style.css b/_jitviewer/static/style.css --- a/_jitviewer/static/style.css +++ b/_jitviewer/static/style.css @@ -17,7 +17,7 @@ font-size: 13px; line-height: 22px; - margin-left: 30px; + margin-left: 0px; margin-top: 60px; } #single_loop { @@ -30,6 +30,9 @@ /* End of General Layout & Typography -----------------------------------------*/ +#filter { + margin-left: 15px; +} /* Floating Side-Menu @@ -37,6 +40,7 @@ #loops ul li span { display: block; width: 100%; + margin-left: 30px; padding-left: 5px; -moz-box-sizing: border-box; @@ -45,8 +49,8 @@ border-bottom: solid 1px rgba(121, 139, 162, 0.3); } -#loops ul li:first-child a:hover {border-top: solid 1px rgba(121, 139, 162, 0.3); margin-top: -1px;} -#loops ul li a:hover { +a:hover {border-top: solid 1px rgba(121, 139, 162, 0.3); margin-top: -1px;} +a:hover { background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.10)); background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0, rgba(0, 0, 0, 0.07)),color-stop(1, rgba(0, 0, 0, 0.10))); color: rgba(0, 0, 0, 1); @@ -65,13 +69,14 @@ display: block; float: left; width: 800px; + margin-left: 30px; } header { display: block; width: 360px; position: fixed; - top: 20px; + top: 30px; left: 920px; padding: 5px; @@ -208,6 +213,17 @@ box-shadow: 0px 0px 7px #cacaca; } +#title { + position: fixed; + text-align: center; + top: 0; + width: 100%; + z-index: 100; + background-color: #164464; + color: #FFF; + display: none; +} + /* End of Formatting -----------------------------------------*/ @@ -222,6 +238,3 @@ - - - diff --git a/_jitviewer/templates/index.html b/_jitviewer/templates/index.html --- a/_jitviewer/templates/index.html +++ b/_jitviewer/templates/index.html @@ -22,7 +22,10 @@
      -
      +
      + Main title +
      +
      Filter:
      From noreply at buildbot.pypy.org Sat Jul 23 17:40:40 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 17:40:40 +0200 (CEST) Subject: [pypy-commit] jitviewer default: log created with a newer pypy, for demos Message-ID: <20110723154040.22A49829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r160:7e05f3008111 Date: 2011-07-23 17:40 +0200 http://bitbucket.org/pypy/jitviewer/changeset/7e05f3008111/ Log: log created with a newer pypy, for demos diff --git a/log b/log --- a/log +++ b/log @@ -1,193 +1,193 @@ -[4cac93478f8a] {jit-backend-dump +[57f8441b33f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 -[4cac9348d29a] jit-backend-dump} -[4cac93490d4d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60000 +0 4157415641554154415341524151415057565554535251504889E341BBD01AEA0041FFD34889DF4883E4F041BB7030D50041FFD3488D65D8415F415E415D415C5B5DC3 +[57f8442ed33] jit-backend-dump} +[57f84430867] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 -[4cac93492757] jit-backend-dump} -[4cac934942ae] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60043 +0 4157415641554154415341524151415057565554535251504889E341BBE01AEA0041FFD34889DF4883E4F041BB7030D50041FFD3488D65D8415F415E415D415C5B5DC3 +[57f844326cf] jit-backend-dump} +[57f84435cef] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b908a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 -[4cac93496777] jit-backend-dump} -[4cac934976da] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60086 +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247841BBD01AEA0041FFD34889DF4883E4F041BB7030D50041FFD3488D65D8415F415E415D415C5B5DC3 +[57f84438893] jit-backend-dump} +[57f84439bd7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b913d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 -[4cac93499888] jit-backend-dump} -[4cac9349bec2] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60137 +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247841BBE01AEA0041FFD34889DF4883E4F041BB7030D50041FFD3488D65D8415F415E415D415C5B5DC3 +[57f8443c2ab] jit-backend-dump} +[57f8443fd67] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 -[4cac9349dd04] jit-backend-dump} -[4cac934a41de] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D741BB10C2D00041FFE3 +[57f84441ed7] jit-backend-dump} +[57f8444998b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b928e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 -[4cac934a5e7f] jit-backend-dump} -[4cac934aad48] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6028d +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425709F4401C3 +[57f8444ba3b] jit-backend-dump} +[57f84452053] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 -[4cac934ad355] jit-backend-dump} -[4cac934ae420] {jit-backend-counts -[4cac934ae846] jit-backend-counts} -[4cac9a58f8bb] {jit-backend -[4cac9a6633f5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60304 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1041BBF0F2AA0041FFD3488B0425D07E75024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B0425D87E750248C70425D07E75020000000048C70425D87E75020000000048890425D0295C0141BBD01AEA0041FFD3B8030000004883C478C3 +[57f84454ebf] jit-backend-dump} +[57f84455fa3] {jit-backend-counts +[57f844564bf] jit-backend-counts} +[57f849252ef] {jit-backend +[57f849d70ef] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b93d5 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C2540100000000488B0C25E8C2540148C70425E8C2540100000000488B0425F0C2540148C70425F0C254010000000048898570FFFFFF49BB30A0CFB8A07F0000498B034883C00149BB30A0CFB8A07F00004989034983F8030F8500000000813AD03000000F8500000000488B7A104885FF0F84000000004C8B4208488B47204885C00F8500000000488B47084939C00F8C0000000048C74210000000004983FA000F85000000004D8B5110418139302301000F85000000004D8B49184983F9020F85000000004885F60F84000000004D85D20F85000000004D8B576841C687950000000141F64704017418515641524C89FF4C89EE49C7C310734D0041FFD3415A5E594D896F5041F64704017418515641524C89FF4C89E649C7C310734D0041FFD3415A5E594D89677841C687960000000049C747600000000049C787800000000200000049C747582A00000041F6420401741F515641524C89D74889F248C7C60000000049C7C380DEB20041FFD3415A5E594989721041F6420401741F515641524C89D748C7C6010000004889DA49C7C380DEB20041FFD3415A5E5949895A1849C742200000000041F6420401741F515641524C89D748C7C6030000004889CA49C7C380DEB20041FFD3415A5E5949894A28488B8D70FFFFFF41F6420401741F515641524C89D748C7C6040000004889CA49C7C380DEB20041FFD3415A5E5949894A304889342590C2540149C7C340BC920041FFD348C7C000000000488D65D8415F415E415D415C5B5DC3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA570FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D94C8B5D404C899D70FFFFFFE98BFDFFFF49BB00905BB6A07F000041FFD321383C343029241D180C080440030300000049BB00905BB6A07F000041FFD3383C0834302924180C0440030400000049BB00905BB6A07F000041FFD3383C081C34302924180C0440030500000049BB00905BB6A07F000041FFD3383C08211C0034302924180C0440030600000049BB00905BB6A07F000041FFD3383C08211C34302924180C0440030700000049BB00905BB6A07F000041FFD329383C343024180C0440030800000049BB00905BB6A07F000041FFD3383C24343028180C0440030900000049BB00905BB6A07F000041FFD3383C25343028180C0440030A00000049BB00905BB6A07F000041FFD3383C183430280C0440030B00000049BB00905BB6A07F000041FFD3383C182834300C0440030C000000 -[4cac9a688c4a] jit-backend-dump} -[4cac9a68ad9c] {jit-backend-addr -Loop #0 ( #19 FOR_ITER) has address 7fa0b65b94d0 to 7fa0b65b96c6 (bootstrap 7fa0b65b93d5) -[4cac9a68d731] jit-backend-addr} -[4cac9a68e7e9] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e603d0 +0 554889E5534154415541564157488DA5000000004C8B3C25D0295C0148C70425D0295C01000000004C8B3425D8295C0148C70425D8295C01000000004C8B2C25E0295C0148C70425E0295C01000000004C8B2425E8295C0148C70425E8295C01000000004C8B1425B0B962014C8B0C25F8295C0148C70425F8295C01000000004C8B0425C0B96201488B3C25C8B96201488B3425102A5C0148C70425102A5C0100000000488B1C25182A5C0148C70425182A5C0100000000488B1425202A5C0148C70425202A5C0100000000488B0C25282A5C0148C70425282A5C0100000000488B0425302A5C0148C70425302A5C010000000048898570FFFFFF49BB30F049D6C97F0000498B034883C00149BB30F049D6C97F00004989034983F8030F8500000000813A582C00000F8500000000488B7A104885FF0F84000000004C8B4208488B47204885C00F8500000000488B47084939C00F8C0000000048C74210000000004983FA000F85000000004D8B5110418139302301000F85000000004D8B49184983F9020F85000000004885F60F84000000004D85D20F85000000004D8B576841C687950000000141F64704017417515641524C89FF4C89EE41BB30BCC70041FFD3415A5E594D896F5041F64704017417515641524C89FF4C89E641BB30BCC70041FFD3415A5E594D89677841C687960000000049C747600000000049C787800000000200000049C747582A00000041F6420401741C515641524C89D74889F2BE0000000041BB9018C80041FFD3415A5E594989721041F6420401741C515641524C89D7BE010000004889DA41BB9018C80041FFD3415A5E5949895A1849C742200000000041F6420401741C515641524C89D7BE030000004889CA41BB9018C80041FFD3415A5E5949894A28488B8D70FFFFFF41F6420401741C515641524C89D7BE040000004889CA41BB9018C80041FFD3415A5E5949894A3048893425D0295C0141BBD01AEA0041FFD3B800000000488D65D8415F415E415D415C5B5DC3488B0425207E75024829E0483B0425802C4401760D49BB0403E6D3C97F000041FFD3554889E5534154415541564157488DA570FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D94C8B5D404C899D70FFFFFFE99CFDFFFF49BB0000E6D3C97F000041FFD321383C343029241D180C080440030400000049BB0000E6D3C97F000041FFD3383C0834302924180C0440030500000049BB0000E6D3C97F000041FFD3383C081C34302924180C0440030600000049BB0000E6D3C97F000041FFD3383C08211C0034302924180C0440030700000049BB0000E6D3C97F000041FFD3383C08211C34302924180C0440030800000049BB0000E6D3C97F000041FFD329383C343024180C0440030900000049BB0000E6D3C97F000041FFD3383C24343028180C0440030A00000049BB0000E6D3C97F000041FFD3383C25343028180C0440030B00000049BB0000E6D3C97F000041FFD3383C183430280C0440030C00000049BB0000E6D3C97F000041FFD3383C182834300C0440030D000000 +[57f849f04c7] jit-backend-dump} +[57f849f11bb] {jit-backend-addr +Loop 0 ( #19 FOR_ITER) has address 7fc9d3e604cb to 7fc9d3e606b0 (bootstrap 7fc9d3e603d0) +[57f849f27fb] jit-backend-addr} +[57f849f3723] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b93e5 +0 70FFFFFF -[4cac9a690058] jit-backend-dump} -[4cac9a691034] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e603e0 +0 70FFFFFF +[57f849f4a2b] jit-backend-dump} +[57f849f572f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b94f4 +0 4D020000 -[4cac9a6922d1] jit-backend-dump} -[4cac9a692c27] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e604ef +0 3C020000 +[57f849f665b] jit-backend-dump} +[57f849f6cef] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9500 +0 60020000 -[4cac9a693cd5] jit-backend-dump} -[4cac9a6944c3] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e604fb +0 4F020000 +[57f849f7b8f] jit-backend-dump} +[57f849f83bb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b950d +0 70020000 -[4cac9a695535] jit-backend-dump} -[4cac9a695d05] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60508 +0 5F020000 +[57f849f9263] jit-backend-dump} +[57f849f9963] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b951e +0 7D020000 -[4cac9a696d8b] jit-backend-dump} -[4cac9a697597] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60519 +0 6C020000 +[57f849fa67f] jit-backend-dump} +[57f849fac83] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b952b +0 90020000 -[4cac9a698893] jit-backend-dump} -[4cac9a69918f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60526 +0 7F020000 +[57f849fb91b] jit-backend-dump} +[57f849fbf23] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b953d +0 9D020000 -[4cac9a69a2ce] jit-backend-dump} -[4cac9a69aac6] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60538 +0 8C020000 +[57f849fcc67] jit-backend-dump} +[57f849fd38f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b954e +0 A8020000 -[4cac9a69bb3d] jit-backend-dump} -[4cac9a69c32b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60549 +0 97020000 +[57f849fe10f] jit-backend-dump} +[57f849fe843] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b955c +0 B6020000 -[4cac9a69d3ac] jit-backend-dump} -[4cac9a69db90] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60557 +0 A5020000 +[57f849ff4fb] jit-backend-dump} +[57f849ffadb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9565 +0 C9020000 -[4cac9a69ec11] jit-backend-dump} -[4cac9a69f517] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60560 +0 B8020000 +[57f84a0076f] jit-backend-dump} +[57f84a00d5b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b956e +0 DB020000 -[4cac9a6a0719] jit-backend-dump} -[4cac9a6a3351] jit-backend} -[4cac9a6a4959] {jit-log-opt-loop +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60569 +0 CA020000 +[57f84a019ef] jit-backend-dump} +[57f84a05713] jit-backend} +[57f84a0799b] {jit-log-opt-loop # Loop 0 : entry bridge with 36 ops [p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11, p12] debug_merge_point(0, ' #19 FOR_ITER') -+281: guard_value(i6, 3, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12] -+291: guard_class(p10, 20808496, descr=) [p1, p0, p10, p2, p3, i4, p5, p8, p9, p11, p12] ++281: guard_value(i6, 3, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12] ++291: guard_class(p10, 21286584, descr=) [p1, p0, p10, p2, p3, i4, p5, p8, p9, p11, p12] +303: p15 = getfield_gc(p10, descr=) -+307: guard_nonnull(p15, descr=) [p1, p0, p10, p15, p2, p3, i4, p5, p8, p9, p11, p12] ++307: guard_nonnull(p15, descr=) [p1, p0, p10, p15, p2, p3, i4, p5, p8, p9, p11, p12] +316: i16 = getfield_gc(p10, descr=) +320: p17 = getfield_gc(p15, descr=) -+324: guard_isnull(p17, descr=) [p1, p0, p10, i16, p15, p17, p2, p3, i4, p5, p8, p9, p11, p12] ++324: guard_isnull(p17, descr=) [p1, p0, p10, i16, p15, p17, p2, p3, i4, p5, p8, p9, p11, p12] +333: i18 = getfield_gc(p15, descr=) +337: i19 = int_ge(i16, i18) -guard_true(i19, descr=) [p1, p0, p10, i16, p15, p2, p3, i4, p5, p8, p9, p11, p12] +guard_true(i19, descr=) [p1, p0, p10, i16, p15, p2, p3, i4, p5, p8, p9, p11, p12] +346: setfield_gc(p10, ConstPtr(ptr20), descr=) -+354: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p11, p12] ++354: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p11, p12] debug_merge_point(0, ' #38 POP_BLOCK') +364: p22 = getfield_gc_pure(p5, descr=) -+368: guard_class(p5, 20870544, descr=) [p1, p0, p5, p2, p3, p22, p8, p9, p11, p12] ++368: guard_class(p5, 21349776, descr=) [p1, p0, p5, p2, p3, p22, p8, p9, p11, p12] +381: i24 = getfield_gc_pure(p5, descr=) -+385: guard_value(i24, 2, descr=) [p1, p0, i24, p2, p3, p22, p8, p9, p11, p12] ++385: guard_value(i24, 2, descr=) [p1, p0, i24, p2, p3, p22, p8, p9, p11, p12] debug_merge_point(0, ' #39 LOAD_FAST') -+395: guard_nonnull(p8, descr=) [p1, p0, p8, p2, p3, p22, p9, p11, p12] ++395: guard_nonnull(p8, descr=) [p1, p0, p8, p2, p3, p22, p9, p11, p12] debug_merge_point(0, ' #42 RETURN_VALUE') -+404: guard_isnull(p22, descr=) [p1, p0, p8, p22, p2, p3, p9, p11, p12] ++404: guard_isnull(p22, descr=) [p1, p0, p8, p22, p2, p3, p9, p11, p12] +413: p26 = getfield_gc(p0, descr=) +417: setfield_gc(p0, 1, descr=) setfield_gc(p0, p2, descr=) setfield_gc(p0, p3, descr=) -+495: setfield_gc(p0, 0, descr=) -+503: setfield_gc(p0, ConstPtr(ptr28), descr=) -+511: setfield_gc(p0, 2, descr=) -+522: setfield_gc(p0, 42, descr=) ++493: setfield_gc(p0, 0, descr=) ++501: setfield_gc(p0, ConstPtr(ptr28), descr=) ++509: setfield_gc(p0, 2, descr=) ++520: setfield_gc(p0, 42, descr=) setarrayitem_gc(p26, 0, p8, descr=) setarrayitem_gc(p26, 1, p9, descr=) -+614: setarrayitem_gc(p26, 2, ConstPtr(ptr34), descr=) ++606: setarrayitem_gc(p26, 2, ConstPtr(ptr34), descr=) setarrayitem_gc(p26, 3, p11, descr=) setarrayitem_gc(p26, 4, p12, descr=) -+713: finish(p8, descr=) -+753: --end of the loop-- -[4cac9a791478] jit-log-opt-loop} -[4cac9adac196] {jit-backend -[4cac9ae4da16] {jit-backend-dump ++699: finish(p8, descr=) ++736: --end of the loop-- +[57f84aa6d2b] jit-log-opt-loop} +[57f84d51227] {jit-backend +[57f84db3b1b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9888 +0 488DA50000000049BB38A0CFB8A07F0000498B0B4883C10149BB38A0CFB8A07F000049890B488B4F10488B7F184C89C04C0FAFC74C01C14883C001488942084983FA000F85000000004883FE017206813E980700000F850000000049BB88F377B6A07F00004D39DC0F85000000004C8B66084983C4010F8000000000488B3425A0536B024883EE0148893425A0536B024883FE000F8C0000000048898D68FFFFFF48899560FFFFFF4C898D58FFFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C89600848898550FFFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C8B9568FFFFFF4C89500848898548FFFFFF49BB88F377B6A07F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00300000048C7C713000000488BB550FFFFFF488B9D48FFFFFF488B9560FFFFFF48C7C10000000048C78570FFFFFF0000000049BBD0945BB6A07F000041FFE349BB00905BB6A07F000041FFD329383C343024180C084005030D00000049BB00905BB6A07F000041FFD3383C18343024084005030E00000049BB00905BB6A07F000041FFD3383C30342418084005030F00000049BB00905BB6A07F000041FFD3383C183134240805031000000049BB00905BB6A07F000041FFD3383C34240831050311000000 -[4cac9ae59dbe] jit-backend-dump} -[4cac9ae5b714] {jit-backend-addr -Bridge out of guard 7 has address 7fa0b65b9888 to 7fa0b65b9a2f -[4cac9ae5e1a4] jit-backend-addr} -[4cac9ae5f098] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60872 +0 488DA50000000049BB38F049D6C97F0000498B0B4883C10149BB38F049D6C97F000049890B488B4F10488B7F184C89C04C0FAFC74C01C14883C001488942084983FA000F85000000004883FE017206813EF80700000F850000000049BB20A0F6D3C97F00004D39DC0F85000000004C8B66084983C4010F8000000000488B3425287E75024883EE0148893425287E75024883FE000F8C0000000048898D68FFFFFF48899560FFFFFF4C898D58FFFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700F807000048891425709F44014C89600848898550FFFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700F807000048891425709F44014C8B9568FFFFFF4C89500848898548FFFFFF49BB20A0F6D3C97F00004D89DC41BA000000004C8B8D58FFFFFF41B803000000BF13000000488BB550FFFFFF488B9D48FFFFFF488B9560FFFFFFB90000000048C78570FFFFFF0000000049BBCB04E6D3C97F000041FFE349BB0000E6D3C97F000041FFD329383C343024180C084005030E00000049BB0000E6D3C97F000041FFD3383C18343024084005030F00000049BB0000E6D3C97F000041FFD3383C30342418084005031000000049BB0000E6D3C97F000041FFD3383C183134240805031100000049BB0000E6D3C97F000041FFD3383C34240831050312000000 +[57f84dc2193] jit-backend-dump} +[57f84dc3793] {jit-backend-addr +bridge out of Guard 8 has address 7fc9d3e60872 to 7fc9d3e60a13 +[57f84dc479f] jit-backend-addr} +[57f84dc4fb7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b988b +0 C0FEFFFF -[4cac9ae60d9c] jit-backend-dump} -[4cac9ae61ca2] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60875 +0 C0FEFFFF +[57f84dc6163] jit-backend-dump} +[57f84dc6997] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b98cd +0 5E010000 -[4cac9ae6dd50] jit-backend-dump} -[4cac9ae6ec8c] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e608b7 +0 58010000 +[57f84dc7a93] jit-backend-dump} +[57f84dc81db] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b98df +0 69010000 -[4cac9ae702fa] jit-backend-dump} -[4cac9ae70daa] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e608c9 +0 63010000 +[57f84dc8f4b] jit-backend-dump} +[57f84dc964b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b98f2 +0 71010000 -[4cac9ae72460] jit-backend-dump} -[4cac9ae72f28] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e608dc +0 6B010000 +[57f84dca307] jit-backend-dump} +[57f84dcaa23] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9900 +0 7E010000 -[4cac9ae74362] jit-backend-dump} -[4cac9ae74cf8] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e608ea +0 78010000 +[57f84dcb6c7] jit-backend-dump} +[57f84dcbc9b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b991e +0 7A010000 -[4cac9ae76156] jit-backend-dump} -[4cac9ae77284] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60908 +0 74010000 +[57f84dcc93f] jit-backend-dump} +[57f84dcd203] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b952b +0 59030000 -[4cac9ae786dc] jit-backend-dump} -[4cac9ae792a6] jit-backend} -[4cac9ae7c63c] {jit-log-opt-bridge -# bridge out of Guard 7 with 29 ops +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60526 +0 48030000 +[57f84dce083] jit-backend-dump} +[57f84dce85b] jit-backend} +[57f84dcf6fb] {jit-log-opt-bridge +# bridge out of Guard 8 with 29 ops [p0, p1, p2, i3, p4, p5, p6, i7, p8, p9, p10, p11, p12] +37: i13 = getfield_gc(p4, descr=) +41: i14 = getfield_gc(p4, descr=) @@ -195,472 +195,459 @@ +52: i16 = int_add(i13, i15) +55: i18 = int_add(i3, 1) +59: setfield_gc(p2, i18, descr=) -+63: guard_value(i7, 0, descr=) [i7, p0, p1, p5, p6, p8, p9, p10, p2, p12, i16] ++63: guard_value(i7, 0, descr=) [i7, p0, p1, p5, p6, p8, p9, p10, p2, p12, i16] debug_merge_point(0, ' #22 STORE_FAST') debug_merge_point(0, ' #25 LOAD_FAST') -+73: guard_nonnull_class(p9, ConstClass(W_IntObject), descr=) [p0, p1, p9, p5, p6, p8, p2, p12, i16] ++73: guard_nonnull_class(p9, ConstClass(W_IntObject), descr=) [p0, p1, p9, p5, p6, p8, p2, p12, i16] debug_merge_point(0, ' #28 LOAD_CONST') -+91: guard_value(p6, ConstPtr(ptr21), descr=) [p0, p1, p6, p5, p8, p9, p2, p12, i16] ++91: guard_value(p6, ConstPtr(ptr21), descr=) [p0, p1, p6, p5, p8, p9, p2, p12, i16] debug_merge_point(0, ' #31 INPLACE_ADD') +110: i22 = getfield_gc_pure(p9, descr=) +114: i24 = int_add_ovf(i22, 1) -guard_no_overflow(, descr=) [p0, p1, p9, i24, p5, p8, p2, i16] +guard_no_overflow(, descr=) [p0, p1, p9, i24, p5, p8, p2, i16] debug_merge_point(0, ' #32 STORE_FAST') debug_merge_point(0, ' #35 JUMP_ABSOLUTE') -+124: i26 = getfield_raw(40588192, descr=) ++124: i26 = getfield_raw(41254440, descr=) +132: i28 = int_sub(i26, 1) -+136: setfield_raw(40588192, i28, descr=) ++136: setfield_raw(41254440, i28, descr=) +144: i30 = int_lt(i28, 0) -guard_false(i30, descr=) [p0, p1, p5, p8, p2, i24, i16] +guard_false(i30, descr=) [p0, p1, p5, p8, p2, i24, i16] debug_merge_point(0, ' #19 FOR_ITER') +154: p32 = new_with_vtable(ConstClass(W_IntObject)) +238: setfield_gc(p32, i24, descr=) +242: p34 = new_with_vtable(ConstClass(W_IntObject)) +312: setfield_gc(p34, i16, descr=) +323: jump(p1, p0, p5, ConstPtr(ptr35), 0, p8, 3, 19, p32, p34, p2, ConstPtr(ptr39), ConstPtr(ptr40), descr=) -+423: --end of the loop-- -[4cac9aebd2aa] jit-log-opt-bridge} -[4cac9b1ed9a0] {jit-backend -[4cac9b2540ba] {jit-backend-dump ++417: --end of the loop-- +[57f84dfc42f] jit-log-opt-bridge} +[57f84ffed2b] {jit-backend +[57f85039c37] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9ab5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B014C8B3425D84D5B0149BB40A0CFB8A07F00004D8B2B4983C50149BB40A0CFB8A07F00004D892B4981FE102700000F8D000000004C89F048C7C10200000048898550FFFFFF489948F7F94889D048C1FA3F49C7C6020000004921D64C01F04883F8000F85000000004C89F84983C7010F8000000000488B8550FFFFFF4883C0014C8B3425A0536B024983EE014C893425A0536B024983FE000F8C0000000048898548FFFFFF4C8BB548FFFFFFE958FFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA540FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C74D89CEE9FBFEFFFF49BB00905BB6A07F000041FFD34440484C393D031200000049BB00905BB6A07F000041FFD34440484C01513D031300000049BB00905BB6A07F000041FFD344403D484C075101031400000049BB00905BB6A07F000041FFD34440484C013D0707070315000000 -[4cac9b26ab54] jit-backend-dump} -[4cac9b26bd8a] {jit-backend-addr -Loop #1 ( #15 LOAD_FAST) has address 7fa0b65b9b45 to 7fa0b65b9bed (bootstrap 7fa0b65b9ab5) -[4cac9b26e0d0] jit-backend-addr} -[4cac9b26f1e6] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60a99 +0 554889E5534154415541564157488DA500000000488B0425D0295C0148C70425D0295C010000000048898570FFFFFF488B0425D8295C0148C70425D8295C010000000048898568FFFFFF488B0425E0295C0148C70425E0295C010000000048898560FFFFFF488B0425E8295C0148C70425E8295C010000000048898558FFFFFF4C8B3C25B0B962014C8B3425B8B9620149BB40F049D6C97F00004D8B2B4983C50149BB40F049D6C97F00004D892B4981FE102700000F8D000000004C89F0B90200000048898550FFFFFF489948F7F94889D048C1FA3F41BE020000004921D64C01F04883F8000F85000000004C89F84983C7010F8000000000488B8550FFFFFF4883C0014C8B3425287E75024983EE014C893425287E75024983FE000F8C0000000048898548FFFFFF4C8BB548FFFFFFE95BFFFFFF488B0425207E75024829E0483B0425802C4401760D49BB0403E6D3C97F000041FFD3554889E5534154415541564157488DA540FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C74D89CEE9FEFEFFFF49BB0000E6D3C97F000041FFD34440484C393D031300000049BB0000E6D3C97F000041FFD34440484C01513D031400000049BB0000E6D3C97F000041FFD344403D484C075101031500000049BB0000E6D3C97F000041FFD34440484C013D0707070316000000 +[57f8504104b] jit-backend-dump} +[57f85041863] {jit-backend-addr +Loop 1 ( #15 LOAD_FAST) has address 7fc9d3e60b29 to 7fc9d3e60bce (bootstrap 7fc9d3e60a99) +[57f8504297f] jit-backend-addr} +[57f850431e3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9ac5 +0 40FFFFFF -[4cac9b270e96] jit-backend-dump} -[4cac9b271d42] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60aa9 +0 40FFFFFF +[57f85044587] jit-backend-dump} +[57f85044d67] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9b6c +0 DA000000 -[4cac9b2734ac] jit-backend-dump} -[4cac9b273ff2] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60b50 +0 D7000000 +[57f85045beb] jit-backend-dump} +[57f85046253] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9ba0 +0 BE000000 -[4cac9b2754e0] jit-backend-dump} -[4cac9b275efa] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60b81 +0 BE000000 +[57f85046f0b] jit-backend-dump} +[57f850474d3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9bad +0 CA000000 -[4cac9b277334] jit-backend-dump} -[4cac9b277cd0] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60b8e +0 CA000000 +[57f8504814b] jit-backend-dump} +[57f8504871f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9bd6 +0 BB000000 -[4cac9b2790ec] jit-backend-dump} -[4cac9b279f2c] jit-backend} -[4cac9b27b3fc] {jit-log-opt-loop +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60bb7 +0 BB000000 +[57f85049547] jit-backend-dump} +[57f85049cf3] jit-backend} +[57f8504bc77] {jit-log-opt-loop # Loop 1 : loop with 35 ops [p0, p1, p2, p3, i4, i5] debug_merge_point(0, ' #15 LOAD_FAST') debug_merge_point(0, ' #18 LOAD_CONST') debug_merge_point(0, ' #21 COMPARE_OP') +174: i7 = int_lt(i5, 10000) -guard_true(i7, descr=) [p1, p0, p2, p3, i5, i4] +guard_true(i7, descr=) [p1, p0, p2, p3, i5, i4] debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') debug_merge_point(0, ' #27 LOAD_FAST') debug_merge_point(0, ' #30 LOAD_CONST') debug_merge_point(0, ' #33 BINARY_MODULO') +187: i9 = int_mod(i5, 2) -+209: i11 = int_rshift(i9, 63) -+216: i12 = int_and(2, i11) -+226: i13 = int_add(i9, i12) ++207: i11 = int_rshift(i9, 63) ++214: i12 = int_and(2, i11) ++223: i13 = int_add(i9, i12) debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') -+229: i14 = int_is_true(i13) -guard_false(i14, descr=) [p1, p0, p2, p3, i13, i5, i4] ++226: i14 = int_is_true(i13) +guard_false(i14, descr=) [p1, p0, p2, p3, i13, i5, i4] debug_merge_point(0, ' #53 LOAD_FAST') debug_merge_point(0, ' #56 LOAD_CONST') debug_merge_point(0, ' #59 INPLACE_ADD') -+239: i16 = int_add_ovf(i4, 1) -guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i5, i4] ++236: i16 = int_add_ovf(i4, 1) +guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i5, i4] debug_merge_point(0, ' #60 STORE_FAST') debug_merge_point(0, ' #63 LOAD_FAST') debug_merge_point(0, ' #66 LOAD_CONST') debug_merge_point(0, ' #69 INPLACE_ADD') -+252: i19 = int_add(i5, 1) ++249: i19 = int_add(i5, 1) debug_merge_point(0, ' #70 STORE_FAST') debug_merge_point(0, ' #73 JUMP_ABSOLUTE') -+263: i21 = getfield_raw(40588192, descr=) -+271: i23 = int_sub(i21, 1) -+275: setfield_raw(40588192, i23, descr=) -+283: i25 = int_lt(i23, 0) -guard_false(i25, descr=) [p1, p0, p2, p3, i19, i16, None, None, None] ++260: i21 = getfield_raw(41254440, descr=) ++268: i23 = int_sub(i21, 1) ++272: setfield_raw(41254440, i23, descr=) ++280: i25 = int_lt(i23, 0) +guard_false(i25, descr=) [p1, p0, p2, p3, i19, i16, None, None, None] debug_merge_point(0, ' #15 LOAD_FAST') -+293: jump(p0, p1, p2, p3, i16, i19, descr=) -+312: --end of the loop-- -[4cac9b2b109c] jit-log-opt-loop} -[4cac9b2b409c] {jit-backend -[4cac9b78442f] {jit-backend-dump ++290: jump(p0, p1, p2, p3, i16, i19, descr=) ++309: --end of the loop-- +[57f85073ed7] jit-log-opt-loop} +[57f85076157] {jit-backend +[57f850c2f3f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9cb0 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C2540100000000488B0C25E8C2540148C70425E8C254010000000049BB48A0CFB8A07F0000498B034883C00149BB48A0CFB8A07F00004989034983F8020F85000000004883FB017206813B980700000F85000000004983FA000F850000000049BB40F477B6A07F00004D39DC0F8500000000488B4B084881F9102700000F8D0000000049BB00000000000000804C39D90F84000000004889C848C7C10200000048898570FFFFFF489948F7F94889D048C1FA3F48C7C1020000004821D14801C84883F8000F85000000004883FE017206813E980700000F8500000000488B46084883C0010F8000000000488B9D70FFFFFF4883C301488B3425A0536B024883EE0148893425A0536B024883FE000F8C0000000048898568FFFFFF4C89BD70FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4C8BBD68FFFFFF4C89B568FFFFFF4989DE49BB459B5BB6A07F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA540FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D9E95AFEFFFF49BB00905BB6A07F000041FFD321383C343029241D180C0804031600000049BB00905BB6A07F000041FFD3383C0C34302924180804031700000049BB00905BB6A07F000041FFD329383C343024180C04031800000049BB00905BB6A07F000041FFD3383C303424180C04031900000049BB00905BB6A07F000041FFD3383C0C342418031A00000049BB00905BB6A07F000041FFD3383C0C05342418031B00000049BB00905BB6A07F000041FFD3383C3424180C01031C00000049BB00905BB6A07F000041FFD3383C1834240C07031D00000049BB00905BB6A07F000041FFD3383C180134240C07031E00000049BB00905BB6A07F000041FFD3383C3424010D07031F000000 -[4cac9b794481] jit-backend-dump} -[4cac9b794cf3] {jit-backend-addr -Loop #2 ( #15 LOAD_FAST) has address 7fa0b65b9d90 to 7fa0b65b9ec2 (bootstrap 7fa0b65b9cb0) -[4cac9b795ba9] jit-backend-addr} -[4cac9b79637b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60c91 +0 554889E5534154415541564157488DA5000000004C8B3C25D0295C0148C70425D0295C01000000004C8B3425D8295C0148C70425D8295C01000000004C8B2C25E0295C0148C70425E0295C01000000004C8B2425E8295C0148C70425E8295C01000000004C8B1425B0B962014C8B0C25F8295C0148C70425F8295C01000000004C8B0425C0B96201488B3C25C8B96201488B3425102A5C0148C70425102A5C0100000000488B1C25182A5C0148C70425182A5C0100000000488B1425202A5C0148C70425202A5C0100000000488B0C25282A5C0148C70425282A5C010000000049BB48F049D6C97F0000498B034883C00149BB48F049D6C97F00004989034983F8020F85000000004883FB017206813BF80700000F85000000004983FA000F850000000049BBD8A0F6D3C97F00004D39DC0F8500000000488B4B084881F9102700000F8D0000000049BB00000000000000804C39D90F84000000004889C8B90200000048898570FFFFFF489948F7F94889D048C1FA3FB9020000004821D14801C84883F8000F85000000004883FE017206813EF80700000F8500000000488B46084883C0010F8000000000488B9D70FFFFFF4883C301488B3425287E75024883EE0148893425287E75024883FE000F8C0000000048898568FFFFFF4C89BD70FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4C8BBD68FFFFFF4C89B568FFFFFF4989DE49BB290BE6D3C97F000041FFE3488B0425207E75024829E0483B0425802C4401760D49BB0403E6D3C97F000041FFD3554889E5534154415541564157488DA540FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D9E95EFEFFFF49BB0000E6D3C97F000041FFD321383C343029241D180C0804031700000049BB0000E6D3C97F000041FFD3383C0C34302924180804031800000049BB0000E6D3C97F000041FFD329383C343024180C04031900000049BB0000E6D3C97F000041FFD3383C303424180C04031A00000049BB0000E6D3C97F000041FFD3383C0C342418031B00000049BB0000E6D3C97F000041FFD3383C0C05342418031C00000049BB0000E6D3C97F000041FFD3383C3424180C01031D00000049BB0000E6D3C97F000041FFD3383C1834240C07031E00000049BB0000E6D3C97F000041FFD3383C180134240C07031F00000049BB0000E6D3C97F000041FFD3383C34240D01070320000000 +[57f850ccf4b] jit-backend-dump} +[57f850cd723] {jit-backend-addr +Loop 2 ( #15 LOAD_FAST) has address 7fc9d3e60d71 to 7fc9d3e60e9f (bootstrap 7fc9d3e60c91) +[57f850ce75b] jit-backend-addr} +[57f850cef77] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9cc0 +0 40FFFFFF -[4cac9b796ff1] jit-backend-dump} -[4cac9b7975e7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60ca1 +0 40FFFFFF +[57f850d01c7] jit-backend-dump} +[57f850d6433] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9db4 +0 7E010000 -[4cac9b79807f] jit-backend-dump} -[4cac9b798617] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60d95 +0 7A010000 +[57f850d760f] jit-backend-dump} +[57f850d7ee3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9dc6 +0 8A010000 -[4cac9b79903b] jit-backend-dump} -[4cac9b79951f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60da7 +0 86010000 +[57f850d8c2f] jit-backend-dump} +[57f850d9257] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9dd0 +0 9C010000 -[4cac9b799e89] jit-backend-dump} -[4cac9b79a2c7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60db1 +0 98010000 +[57f850d9f0f] jit-backend-dump} +[57f850da4df] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9de3 +0 A4010000 -[4cac9b79ab5d] jit-backend-dump} -[4cac9b79af97] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60dc4 +0 A0010000 +[57f850db16f] jit-backend-dump} +[57f850db877] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9df4 +0 AD010000 -[4cac9b79b911] jit-backend-dump} -[4cac9b79be79] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60dd5 +0 A9010000 +[57f850dc73f] jit-backend-dump} +[57f850dce3f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9e07 +0 B2010000 -[4cac9b79cb47] jit-backend-dump} -[4cac9b79d0d7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60de8 +0 AE010000 +[57f850ddcb7] jit-backend-dump} +[57f850de2fb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9e3b +0 97010000 -[4cac9b79da99] jit-backend-dump} -[4cac9b79dee5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60e18 +0 97010000 +[57f850defbb] jit-backend-dump} +[57f850df5bb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9e4d +0 9E010000 -[4cac9b79e769] jit-backend-dump} -[4cac9b79ebb5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60e2a +0 9E010000 +[57f850e024b] jit-backend-dump} +[57f850e0833] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9e5b +0 A9010000 -[4cac9b79f44b] jit-backend-dump} -[4cac9b79f9d9] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60e38 +0 A9010000 +[57f850e1743] jit-backend-dump} +[57f850e1e83] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9e84 +0 9A010000 -[4cac9b7a0481] jit-backend-dump} -[4cac9b7a0ad7] jit-backend} -[4cac9b7a16cd] {jit-log-opt-loop +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60e61 +0 9A010000 +[57f850e2c03] jit-backend-dump} +[57f850e33f7] jit-backend} +[57f850e410b] {jit-log-opt-loop # Loop 2 : entry bridge with 44 ops [p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11] debug_merge_point(0, ' #15 LOAD_FAST') -+254: guard_value(i6, 2, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11] -+264: guard_nonnull_class(p9, ConstClass(W_IntObject), descr=) [p1, p0, p9, p2, p3, i4, p5, p8, p10, p11] -+282: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p11] ++254: guard_value(i6, 2, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11] ++264: guard_nonnull_class(p9, ConstClass(W_IntObject), descr=) [p1, p0, p9, p2, p3, i4, p5, p8, p10, p11] ++282: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p11] debug_merge_point(0, ' #18 LOAD_CONST') -+292: guard_value(p3, ConstPtr(ptr15), descr=) [p1, p0, p3, p2, p5, p8, p9, p11] ++292: guard_value(p3, ConstPtr(ptr15), descr=) [p1, p0, p3, p2, p5, p8, p9, p11] debug_merge_point(0, ' #21 COMPARE_OP') +311: i16 = getfield_gc_pure(p9, descr=) +315: i18 = int_lt(i16, 10000) -guard_true(i18, descr=) [p1, p0, p9, p2, p5, p8] +guard_true(i18, descr=) [p1, p0, p9, p2, p5, p8] debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') debug_merge_point(0, ' #27 LOAD_FAST') debug_merge_point(0, ' #30 LOAD_CONST') debug_merge_point(0, ' #33 BINARY_MODULO') +328: i20 = int_eq(i16, -9223372036854775808) -guard_false(i20, descr=) [p1, p0, p9, i16, p2, p5, p8] +guard_false(i20, descr=) [p1, p0, p9, i16, p2, p5, p8] +347: i22 = int_mod(i16, 2) -+369: i24 = int_rshift(i22, 63) -+376: i25 = int_and(2, i24) -+386: i26 = int_add(i22, i25) ++367: i24 = int_rshift(i22, 63) ++374: i25 = int_and(2, i24) ++382: i26 = int_add(i22, i25) debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') -+389: i27 = int_is_true(i26) -guard_false(i27, descr=) [p1, p0, p2, p5, p8, p9, i26] ++385: i27 = int_is_true(i26) +guard_false(i27, descr=) [p1, p0, p2, p5, p8, p9, i26] debug_merge_point(0, ' #53 LOAD_FAST') -+399: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p5, p9, None] ++395: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p5, p9, None] debug_merge_point(0, ' #56 LOAD_CONST') debug_merge_point(0, ' #59 INPLACE_ADD') -+417: i30 = getfield_gc_pure(p8, descr=) -+421: i32 = int_add_ovf(i30, 1) -guard_no_overflow(, descr=) [p1, p0, p8, i32, p2, p5, p9, None] ++413: i30 = getfield_gc_pure(p8, descr=) ++417: i32 = int_add_ovf(i30, 1) +guard_no_overflow(, descr=) [p1, p0, p8, i32, p2, p5, p9, None] debug_merge_point(0, ' #60 STORE_FAST') debug_merge_point(0, ' #63 LOAD_FAST') debug_merge_point(0, ' #66 LOAD_CONST') debug_merge_point(0, ' #69 INPLACE_ADD') -+431: i34 = int_add(i16, 1) ++427: i34 = int_add(i16, 1) debug_merge_point(0, ' #70 STORE_FAST') debug_merge_point(0, ' #73 JUMP_ABSOLUTE') -+442: i36 = getfield_raw(40588192, descr=) -+450: i38 = int_sub(i36, 1) -+454: setfield_raw(40588192, i38, descr=) -+462: i40 = int_lt(i38, 0) -guard_false(i40, descr=) [p1, p0, p2, p5, i32, i34, None] ++438: i36 = getfield_raw(41254440, descr=) ++446: i38 = int_sub(i36, 1) ++450: setfield_raw(41254440, i38, descr=) ++458: i40 = int_lt(i38, 0) +guard_false(i40, descr=) [p1, p0, p2, p5, i34, i32, None] debug_merge_point(0, ' #15 LOAD_FAST') -+472: jump(p0, p1, p2, p5, i32, i34, descr=) -+530: --end of the loop-- -[4cac9b7c5c13] jit-log-opt-loop} -[4caca24c49a7] {jit-backend -[4caca25290e7] {jit-backend-dump ++468: jump(p0, p1, p2, p5, i32, i34, descr=) ++526: --end of the loop-- +[57f85116a67] jit-log-opt-loop} +[57f85b7f3e3] {jit-backend +[57f85bc77e7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba03b +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B014C8B3425D84D5B0149BB50A0CFB8A07F00004D8B2B4983C50149BB50A0CFB8A07F00004D892B4981FE102700000F8D000000004C89F048C7C10200000048898550FFFFFF489948F7F94889D048C1FA3F49C7C6020000004921D64C01F04883F8000F85000000004C89F84983C7010F8000000000488B8550FFFFFF4883C0014C8B3425A0536B024983EE1C4C893425A0536B024983FE000F8C0000000048898548FFFFFF4C8BB548FFFFFFE958FFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA540FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C74D89CEE9FBFEFFFF49BB00905BB6A07F000041FFD34440484C3D39032000000049BB00905BB6A07F000041FFD34440484C013D51032100000049BB00905BB6A07F000041FFD344403D484C070151032200000049BB00905BB6A07F000041FFD34440484C013D0707070323000000 -[4caca2535c6f] jit-backend-dump} -[4caca2536b09] {jit-backend-addr -Loop #3 ( #15 LOAD_FAST) has address 7fa0b65ba0cb to 7fa0b65ba173 (bootstrap 7fa0b65ba03b) -[4caca25499b5] jit-backend-addr} -[4caca254ae61] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61018 +0 554889E5534154415541564157488DA500000000488B0425D0295C0148C70425D0295C010000000048898570FFFFFF488B0425D8295C0148C70425D8295C010000000048898568FFFFFF488B0425E0295C0148C70425E0295C010000000048898560FFFFFF488B0425E8295C0148C70425E8295C010000000048898558FFFFFF4C8B3C25B0B962014C8B3425B8B9620149BB50F049D6C97F00004D8B2B4983C50149BB50F049D6C97F00004D892B4981FE102700000F8D000000004C89F0B90200000048898550FFFFFF489948F7F94889D048C1FA3F41BE020000004921D64C01F04883F8000F85000000004C89F84983C7010F8000000000488B8550FFFFFF4883C0014C8B3425287E75024983EE0D4C893425287E75024983FE000F8C0000000048898548FFFFFF4C8BB548FFFFFFE95BFFFFFF488B0425207E75024829E0483B0425802C4401760D49BB0403E6D3C97F000041FFD3554889E5534154415541564157488DA540FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C74D89CEE9FEFEFFFF49BB0000E6D3C97F000041FFD34440484C393D032100000049BB0000E6D3C97F000041FFD34440484C01513D032200000049BB0000E6D3C97F000041FFD344403D484C075101032300000049BB0000E6D3C97F000041FFD34440484C3D010707070324000000 +[57f85bcf977] jit-backend-dump} +[57f85bd02b7] {jit-backend-addr +Loop 3 ( #15 LOAD_FAST) has address 7fc9d3e610a8 to 7fc9d3e6114d (bootstrap 7fc9d3e61018) +[57f85bd15a3] jit-backend-addr} +[57f85bd21ab] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba04b +0 40FFFFFF -[4caca254cf85] jit-backend-dump} -[4caca254e18b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61028 +0 40FFFFFF +[57f85bd35a3] jit-backend-dump} +[57f85bd4293] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba0f2 +0 DA000000 -[4caca254f985] jit-backend-dump} -[4caca255041d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e610cf +0 D7000000 +[57f85bd523f] jit-backend-dump} +[57f85bd58a3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba126 +0 BE000000 -[4caca2551995] jit-backend-dump} -[4caca2552337] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61100 +0 BE000000 +[57f85bd65c3] jit-backend-dump} +[57f85bd6c0b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba133 +0 CA000000 -[4caca25538d3] jit-backend-dump} -[4caca2554317] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6110d +0 CA000000 +[57f85bd7947] jit-backend-dump} +[57f85bd7f5f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba15c +0 BB000000 -[4caca25558ad] jit-backend-dump} -[4caca255673b] jit-backend} -[4caca2557d67] {jit-log-opt-loop +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61136 +0 BB000000 +[57f85bd8ed7] jit-backend-dump} +[57f85bd9777] jit-backend} +[57f85bda9ef] {jit-log-opt-loop # Loop 3 : loop with 34 ops [p0, p1, p2, p3, i4, i5] debug_merge_point(0, ' #18 LOAD_CONST') debug_merge_point(0, ' #21 COMPARE_OP') +174: i7 = int_lt(i5, 10000) -guard_true(i7, descr=) [p1, p0, p2, p3, i4, i5] +guard_true(i7, descr=) [p1, p0, p2, p3, i5, i4] debug_merge_point(0, ' #24 POP_JUMP_IF_FALSE') debug_merge_point(0, ' #27 LOAD_FAST') debug_merge_point(0, ' #30 LOAD_CONST') debug_merge_point(0, ' #33 BINARY_MODULO') +187: i9 = int_mod(i5, 2) -+209: i11 = int_rshift(i9, 63) -+216: i12 = int_and(2, i11) -+226: i13 = int_add(i9, i12) ++207: i11 = int_rshift(i9, 63) ++214: i12 = int_and(2, i11) ++223: i13 = int_add(i9, i12) debug_merge_point(0, ' #34 POP_JUMP_IF_FALSE') -+229: i14 = int_is_true(i13) -guard_false(i14, descr=) [p1, p0, p2, p3, i13, i4, i5] ++226: i14 = int_is_true(i13) +guard_false(i14, descr=) [p1, p0, p2, p3, i13, i5, i4] debug_merge_point(0, ' #53 LOAD_FAST') debug_merge_point(0, ' #56 LOAD_CONST') debug_merge_point(0, ' #59 INPLACE_ADD') -+239: i16 = int_add_ovf(i4, 1) -guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i4, i5] ++236: i16 = int_add_ovf(i4, 1) +guard_no_overflow(, descr=) [p1, p0, i16, p2, p3, None, i5, i4] debug_merge_point(0, ' #60 STORE_FAST') debug_merge_point(0, ' #63 LOAD_FAST') debug_merge_point(0, ' #66 LOAD_CONST') debug_merge_point(0, ' #69 INPLACE_ADD') -+252: i19 = int_add(i5, 1) ++249: i19 = int_add(i5, 1) debug_merge_point(0, ' #70 STORE_FAST') debug_merge_point(0, ' #73 JUMP_ABSOLUTE') -+263: i21 = getfield_raw(40588192, descr=) -+271: i23 = int_sub(i21, 28) -+275: setfield_raw(40588192, i23, descr=) -+283: i25 = int_lt(i23, 0) -guard_false(i25, descr=) [p1, p0, p2, p3, i19, i16, None, None, None] ++260: i21 = getfield_raw(41254440, descr=) ++268: i23 = int_sub(i21, 13) ++272: setfield_raw(41254440, i23, descr=) ++280: i25 = int_lt(i23, 0) +guard_false(i25, descr=) [p1, p0, p2, p3, i16, i19, None, None, None] debug_merge_point(0, ' #15 LOAD_FAST') -+293: jump(p0, p1, p2, p3, i16, i19, descr=) -+312: --end of the loop-- -[4caca258fbfd] jit-log-opt-loop} -[4caca2e41c45] {jit-backend -[4caca43342ad] {jit-backend-dump ++290: jump(p0, p1, p2, p3, i16, i19, descr=) ++309: --end of the loop-- +[57f85c0daa3] jit-log-opt-loop} +[57f85e4c2cb] {jit-backend +[57f861f68eb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba350 +0 488DA50000000049BB58A0CFB8A07F0000498B034883C00149BB58A0CFB8A07F0000498903488B8570FFFFFF4C8B700849BBA0217CB6A07F00004D39DE0F85000000004D8B6E104981FDC07446010F850000000049BB58026CB6A07F00004D8B334983FE01720741813E082601000F85000000004D8B6E1849BB88F377B6A07F00004D39DD0F85000000004D8B6E4049C7C3B0A0500041FFD34C8B60384C8D9578FFFFFF4C8B48484D85C90F85000000004C8B48284983F9000F850000000049BBA0217CB6A07F00004D39DD0F85000000004D8B4D104981F9C07446010F850000000049BBF80F6CB6A07F00004D8B2B4D85ED0F85000000004C8B2C2508DF45014981FD706A49010F85000000004D8B4D104981F9C07446010F85000000004C8B2C2508B65D014981FD603B62010F85000000004C8B2C25883B62014C8B2C25A0536B024983ED174C892C25A0536B024983FD000F8C000000004C8DAD78FFFFFF48898548FFFFFF4C899540FFFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B9540FFFFFF4C8950084C8B9548FFFFFF41F642040174164152504C89D74889C649C7C310734D0041FFD358415A498942384C8B8D70FFFFFF4D89691848898538FFFFFF488B0425704F3D01488D9098000000483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700381F010048891425704F3D0149BB88F377B6A07F00004C89587849BBA00171B6A07F00004C89586048C740700200000048898530FFFFFF488B0425704F3D01488D5038483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7008800000048891425704F3D0148C740080500000048898528FFFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D0148C74008010000004C8B9528FFFFFF41F642040174164152504C89D74889C649C7C310734D0041FFD358415A4989421048898520FFFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C8B9528FFFFFF41F642040174165041524C89D74889C649C7C310734D0041FFD3415A584989421848898518FFFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700D030000048891425704F3D0148898510FFFFFF488B0425704F3D01488D5028483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7007038000048891425704F3D0148C740180100000048C74008030000004C8B9510FFFFFF41F642040174165041524C89D74889C649C7C310734D0041FFD3415A584989421049C7420801000000488B8528FFFFFFF640040174165041524889C74C89D649C7C310734D0041FFD3415A584C8950204C8B8D30FFFFFF41F6410401741A50415241514C89CF4889C649C7C310734D0041FFD34159415A584989416849C741581300000049C781800000000300000041F64104017418415241514C89CF4C89E649C7C310734D0041FFD34159415A4D89613041C781900000001500000041F64104017422415241514C89CF49BBA0217CB6A07F00004C89DE49C7C310734D0041FFD34159415A49BBA0217CB6A07F00004D8959084C89BD08FFFFFF4C89B500FFFFFF48C78578FFFFFF2400000049C7C3030000004C891C2449C7C3130000004C895C24084C8B9D20FFFFFF4C895C24104C8B9D18FFFFFF4C895C24184C8954242049C7C3000000004C895C242849C7C3000000004C895C24304C89CF488BB548FFFFFF48C7C20000000049BB88F377B6A07F00004C89D949C7C00000000049BBA00171B6A07F00004D89D949BBC6965BB6A07F000041FFD34883F80074164889C7488BB530FFFFFF49C7C3D0D88C0041FFD3EB23488B8530FFFFFF48C7401800000000488B042590C2540148C7042590C25401000000004883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004C8BB548FFFFFF4D8B56484D85D20F85000000004C8B9530FFFFFF4C3B9570FFFFFF0F84000000004D8B4E2849C74250000000004983F9000F85000000004D8B4E384D8B7A304D0FB6A29400000041F6460401741A41514152504C89F74C89FE49C7C310734D0041FFD358415A41594D897E384D85E40F85000000004C8BA538FFFFFF49C7442408FDFFFFFF8138980700000F85000000004C8B60084C8BB508FFFFFF4D01E60F8000000000488B8550FFFFFF4883C0010F80000000004C8B2425A0536B024983EC1A4C892425A0536B024983FC000F8C00000000488985F8FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C897008488985F0FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7009807000048891425704F3D014C8B95F8FEFFFF4C895008488985E8FEFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BB40F477B6A07F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00200000048C7C70F000000488BB5F0FEFFFF488B9DE8FEFFFF48C7C20000000048C7C10000000049BB909D5BB6A07F000041FFE349BB00905BB6A07F000041FFD3440038484C3D51032500000049BB00905BB6A07F000041FFD344003438484C3D51032600000049BB00905BB6A07F000041FFD3440038484C3D51032700000049BB00905BB6A07F000041FFD344003438484C3D51032800000049BB00905BB6A07F000041FFD344400024484C382930343D51032900000049BB00905BB6A07F000041FFD3444000484C382930343D51032A00000049BB00905BB6A07F000041FFD344400034484C382930073D51032B00000049BB00905BB6A07F000041FFD34440002434484C382930073D51032C00000049BB00905BB6A07F000041FFD344400034484C382930073D51032D00000049BB00905BB6A07F000041FFD344400034484C382930073D51032E00000049BB00905BB6A07F000041FFD34440002434484C382930073D51032F00000049BB00905BB6A07F000041FFD344400034484C382930073D51033000000049BB00905BB6A07F000041FFD344400034484C382930073D51033100000049BB00905BB6A07F000041FFD3444000484C382930073D51033200000049BB45905BB6A07F000041FFD344405460005C484C787551032400000049BB45905BB6A07F000041FFD344405460005C484C787551033300000049BB00905BB6A07F000041FFD34440380060285C484C787551033400000049BB00905BB6A07F000041FFD344403800285C484C787551033500000049BB00905BB6A07F000041FFD344400028385C484C787551033600000049BB00905BB6A07F000041FFD34440002428385C484C787551033700000049BB00905BB6A07F000041FFD3444000484C7551033800000049BB00905BB6A07F000041FFD344400039484C7551033900000049BB00905BB6A07F000041FFD3444001484C390751033A00000049BB00905BB6A07F000041FFD34440484C01390707033B000000 -[4caca436d577] jit-backend-dump} -[4caca436ec69] {jit-backend-addr -Bridge out of guard 19 has address 7fa0b65ba350 to 7fa0b65bab56 -[4caca4370ee3] jit-backend-addr} -[4caca43720d1] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6132a +0 488DA50000000049BB58F049D6C97F0000498B034883C00149BB58F049D6C97F0000498903488B8570FFFFFF4C8B700849BB2060F7D3C97F00004D39DE0F85000000004D8B6E104981FD60C84D010F850000000049BBB821F6D3C97F00004D8B334983FE01720741813E082601000F85000000004D8B6E1849BB20A0F6D3C97F00004D39DD0F85000000004D8B6E4041BBD07D890041FFD34C8B60384C8D9578FFFFFF4C8B48484D85C90F85000000004C8B48284983F9000F850000000049BB2060F7D3C97F00004D39DD0F85000000004D8B4D104981F960C84D010F850000000049BB38DAFCD3C97F00004D8B2B4D85ED0F85000000004C8B2C2520C350014981FD60C84D010F85000000004C8B2C25C82065014981FDA0AA69010F85000000004C8B2C25287E75024983ED084C892C25287E75024983FD000F8C000000004C8DAD78FFFFFF48898548FFFFFF4C899540FFFFFF488B0425709F4401488D5018483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700401D000048891425709F44014C8B9540FFFFFF4C8950084C8B9548FFFFFF41F642040174154152504C89D74889C641BB30BCC70041FFD358415A498942384C8B8D70FFFFFF4D89691848898538FFFFFF488B0425709F4401488D9098000000483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700381F010048891425709F4401C780900000001500000048C780800000000300000049BB2060F7D3C97F00004C89580848898530FFFFFF488B0425709F4401488D5038483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C7008800000048891425709F440148C740080500000048898528FFFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700F807000048891425709F440148C74008010000004C8B9528FFFFFF41F642040174154152504C89D74889C641BB30BCC70041FFD358415A4989421048898520FFFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700F807000048891425709F44014C8B9528FFFFFF41F642040174154152504C89D74889C641BB30BCC70041FFD358415A4989421848898518FFFFFF488B0425709F4401488D5018483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700582C000048891425709F440148898510FFFFFF488B0425709F4401488D5028483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700D838000048891425709F440148C740180100000048C74008030000004C8B9510FFFFFF41F642040174155041524C89D74889C641BB30BCC70041FFD3415A584989421049C7420801000000488B8528FFFFFFF640040174155041524889C74C89D641BB30BCC70041FFD3415A584C8950204C8B8D30FFFFFF41F6410401741941515041524C89CF4889C641BB30BCC70041FFD3415A5841594989416841F64104017421415141524C89CF49BB20A0F6D3C97F00004C89DE41BB30BCC70041FFD3415A415949BB20A0F6D3C97F00004D89597849C741700200000041F64104017421415141524C89CF49BBA083FDD3C97F00004C89DE41BB30BCC70041FFD3415A415949BBA083FDD3C97F00004D89596041F64104017417415141524C89CF4C89E641BB30BCC70041FFD3415A41594D89613049C74158130000004C89BD08FFFFFF4C89B500FFFFFF48C78578FFFFFF2500000041BB030000004C891C2441BB130000004C895C24084C8B9D20FFFFFF4C895C24104C8B9D18FFFFFF4C895C24184C8954242041BB000000004C895C242841BB000000004C895C24304C89CF488BB548FFFFFFBA0000000049BB20A0F6D3C97F00004C89D941B80000000049BBA083FDD3C97F00004D89D949BBB006E6D3C97F000041FFD34883F80074154889C7488BB530FFFFFF41BB90AF970041FFD3EB23488B8530FFFFFF48C7401800000000488B0425D0295C0148C70425D0295C01000000004883BD78FFFFFF000F8C0000000048833C25D07E7502000F85000000004C8B8D48FFFFFF4D8B51484D85D20F85000000004D8B51284C8BB530FFFFFF49C74650000000004983FA000F85000000004D8B51384D8B7E304D0FB6A69400000041F6410401741941524151504C89CF4C89FE41BB30BCC70041FFD3584159415A4D8979384D85E40F85000000004C8BA538FFFFFF49C7442408FDFFFFFF8138F80700000F85000000004C8B60084C8B8D08FFFFFF4D01E10F8000000000488B8550FFFFFF4883C0010F80000000004C8B2425287E75024983EC0B4C892425287E75024983FC000F8C00000000488985F8FEFFFF4C898DF0FEFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700F807000048891425709F44014C8B95F0FEFFFF4C895008488985E8FEFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700F807000048891425709F44014C8B95F8FEFFFF4C895008488985E0FEFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBD8A0F6D3C97F00004D89DC41BA000000004C8B8D58FFFFFF41B802000000BF0F000000488BB5E8FEFFFF488B9DE0FEFFFFBA00000000B90000000049BB710DE6D3C97F000041FFE349BB0000E6D3C97F000041FFD3440038484C3D51032600000049BB0000E6D3C97F000041FFD344003438484C3D51032700000049BB0000E6D3C97F000041FFD3440038484C3D51032800000049BB0000E6D3C97F000041FFD344003438484C3D51032900000049BB0000E6D3C97F000041FFD344400024484C382930343D51032A00000049BB0000E6D3C97F000041FFD3444000484C382930343D51032B00000049BB0000E6D3C97F000041FFD344400034484C382930073D51032C00000049BB0000E6D3C97F000041FFD34440002434484C382930073D51032D00000049BB0000E6D3C97F000041FFD344400034484C382930073D51032E00000049BB0000E6D3C97F000041FFD3444000484C382930073D51032F00000049BB0000E6D3C97F000041FFD344400034484C382930073D51033000000049BB0000E6D3C97F000041FFD344400034484C382930073D51033100000049BB0000E6D3C97F000041FFD3444000484C382930073D51033200000049BB4300E6D3C97F000041FFD344405460005C484C787551032500000049BB4300E6D3C97F000041FFD344405460005C484C787551033300000049BB0000E6D3C97F000041FFD34440240060285C484C787551033400000049BB0000E6D3C97F000041FFD344400038245C484C787551033500000049BB0000E6D3C97F000041FFD34440002838245C484C787551033600000049BB0000E6D3C97F000041FFD3444000484C7551033700000049BB0000E6D3C97F000041FFD344400025484C7551033800000049BB0000E6D3C97F000041FFD3444001484C250751033900000049BB0000E6D3C97F000041FFD34440484C01250707033A000000 +[57f86228c9f] jit-backend-dump} +[57f86229f5b] {jit-backend-addr +bridge out of Guard 20 has address 7fc9d3e6132a to 7fc9d3e61b25 +[57f8622b41f] jit-backend-addr} +[57f8622bd97] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba353 +0 60FEFFFF -[4caca4373f79] jit-backend-dump} -[4caca43750e9] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6132d +0 50FEFFFF +[57f8622d087] jit-backend-dump} +[57f8622d97b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba38f +0 C3070000 -[4caca43766bb] jit-backend-dump} -[4caca4377105] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61369 +0 B8070000 +[57f8622e8cb] jit-backend-dump} +[57f8622f017] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba3a0 +0 CB070000 -[4caca43785f9] jit-backend-dump} -[4caca4379169] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6137a +0 C0070000 +[57f86232fe7] jit-backend-dump} +[57f862337ef] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba3c0 +0 C5070000 -[4caca437a6e1] jit-backend-dump} -[4caca437b233] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6139a +0 BA070000 +[57f862349ab] jit-backend-dump} +[57f862353c3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba3d7 +0 C7070000 -[4caca437cb5f] jit-backend-dump} -[4caca437d4dd] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e613b1 +0 BC070000 +[57f862476fb] jit-backend-dump} +[57f8624821f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba3fd +0 BB070000 -[4caca437e905] jit-backend-dump} -[4caca437f28f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e613d6 +0 B1070000 +[57f8624bbb3] jit-backend-dump} +[57f8624c50b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba40b +0 CB070000 -[4caca43806b1] jit-backend-dump} -[4caca4381071] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e613e4 +0 C1070000 +[57f8624d957] jit-backend-dump} +[57f8624e2d3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba41e +0 D5070000 -[4caca4382739] jit-backend-dump} -[4caca4383237] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e613f7 +0 CB070000 +[57f8624f807] jit-backend-dump} +[57f862502a3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba42f +0 E2070000 -[4caca43847d9] jit-backend-dump} -[4caca4385175] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61408 +0 D8070000 +[57f86251373] jit-backend-dump} +[57f86251a97] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba445 +0 EB070000 -[4caca438659d] jit-backend-dump} -[4caca4386f1b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6141e +0 E1070000 +[57f86252797] jit-backend-dump} +[57f86253347] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba45a +0 F4070000 -[4caca4388331] jit-backend-dump} -[4caca4388cf1] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61433 +0 07080000 +[57f8625419b] jit-backend-dump} +[57f86254793] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba46b +0 01080000 -[4caca438a101] jit-backend-dump} -[4caca438abe7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61448 +0 10080000 +[57f8625541b] jit-backend-dump} +[57f86255a03] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba480 +0 0B080000 -[4caca438c219] jit-backend-dump} -[4caca438d161] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61466 +0 10080000 +[57f8625668b] jit-backend-dump} +[57f86256ccf] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba4a6 +0 21080000 -[4caca438e673] jit-backend-dump} -[4caca438f04b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61936 +0 5D030000 +[57f86257957] jit-backend-dump} +[57f86258077] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba95f +0 85030000 -[4caca4390461] jit-backend-dump} -[4caca4390e21] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61945 +0 6B030000 +[57f86258e03] jit-backend-dump} +[57f862595d3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba96e +0 93030000 -[4caca439222b] jit-backend-dump} -[4caca4392bdf] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61959 +0 74030000 +[57f8625a3cb] jit-backend-dump} +[57f8625a9eb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba982 +0 9C030000 -[4caca4394217] jit-backend-dump} -[4caca4394d15] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61976 +0 75030000 +[57f8625b673] jit-backend-dump} +[57f8625bc83] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba996 +0 A6030000 -[4caca43962f3] jit-backend-dump} -[4caca4396c8f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e619b3 +0 55030000 +[57f8625c90b] jit-backend-dump} +[57f8625cf27] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba9ac +0 AD030000 -[4caca43980b7] jit-backend-dump} -[4caca4398a89] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e619cf +0 57030000 +[57f8625ddaf] jit-backend-dump} +[57f8625e4ff] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65ba9ea +0 8C030000 -[4caca4399e99] jit-backend-dump} -[4caca439a85f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e619e3 +0 5C030000 +[57f8625f217] jit-backend-dump} +[57f8625f82f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65baa06 +0 8E030000 -[4caca439bca5] jit-backend-dump} -[4caca439c731] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e619f4 +0 65030000 +[57f862604b7] jit-backend-dump} +[57f86260aa7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65baa1a +0 93030000 -[4caca439dd99] jit-backend-dump} -[4caca439e807] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61a12 +0 61030000 +[57f8626172f] jit-backend-dump} +[57f862620bb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65baa2b +0 9C030000 -[4caca439fd13] jit-backend-dump} -[4caca43a06f7] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65baa49 +0 98030000 -[4caca43a6019] jit-backend-dump} -[4caca43a771d] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65b9ba0 +0 AC070000 -[4caca43a8cb9] jit-backend-dump} -[4caca43a9949] jit-backend} -[4caca43ab1c1] {jit-log-opt-bridge -# bridge out of Guard 19 with 124 ops +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e60b81 +0 A5070000 +[57f86266787] jit-backend-dump} +[57f86267197] jit-backend} +[57f86268423] {jit-log-opt-bridge +# bridge out of Guard 20 with 119 ops [p0, p1, p2, p3, i4, i5, i6] debug_merge_point(0, ' #37 LOAD_FAST') debug_merge_point(0, ' #40 LOAD_GLOBAL') +37: p7 = getfield_gc(p1, descr=) -+48: guard_value(p7, ConstPtr(ptr8), descr=) [p0, p1, p7, p2, p3, i6, i5] ++48: guard_value(p7, ConstPtr(ptr8), descr=) [p0, p1, p7, p2, p3, i6, i5] +67: p9 = getfield_gc(p7, descr=) -+71: guard_value(p9, ConstPtr(ptr10), descr=) [p0, p1, p9, p7, p2, p3, i6, i5] ++71: guard_value(p9, ConstPtr(ptr10), descr=) [p0, p1, p9, p7, p2, p3, i6, i5] +84: p12 = getfield_gc(ConstPtr(ptr11), descr=) -+97: guard_nonnull_class(p12, ConstClass(Function), descr=) [p0, p1, p12, p2, p3, i6, i5] ++97: guard_nonnull_class(p12, ConstClass(Function), descr=) [p0, p1, p12, p2, p3, i6, i5] debug_merge_point(0, ' #43 CALL_FUNCTION') +116: p14 = getfield_gc(p12, descr=) -+120: guard_value(p14, ConstPtr(ptr15), descr=) [p0, p1, p14, p12, p2, p3, i6, i5] ++120: guard_value(p14, ConstPtr(ptr15), descr=) [p0, p1, p14, p12, p2, p3, i6, i5] +139: p16 = getfield_gc(p12, descr=) +143: p17 = getfield_gc(p12, descr=) +143: p19 = call(ConstClass(getexecutioncontext), descr=) -+153: p20 = getfield_gc(p19, descr=) -+157: i21 = force_token() -+164: p22 = getfield_gc(p19, descr=) -+168: guard_isnull(p22, descr=) [p0, p1, p19, p22, p2, p3, p12, i21, p20, p16, i6, i5] -+177: i23 = getfield_gc(p19, descr=) -+181: i24 = int_is_zero(i23) -guard_true(i24, descr=) [p0, p1, p19, p2, p3, p12, i21, p20, p16, i6, i5] ++152: p20 = getfield_gc(p19, descr=) ++156: i21 = force_token() ++163: p22 = getfield_gc(p19, descr=) ++167: guard_isnull(p22, descr=) [p0, p1, p19, p22, p2, p3, p12, i21, p20, p16, i6, i5] ++176: i23 = getfield_gc(p19, descr=) ++180: i24 = int_is_zero(i23) +guard_true(i24, descr=) [p0, p1, p19, p2, p3, p12, i21, p20, p16, i6, i5] debug_merge_point(1, ' #0 LOAD_CONST') debug_merge_point(1, ' #3 STORE_FAST') debug_merge_point(1, ' #6 SETUP_LOOP') debug_merge_point(1, ' #9 LOAD_GLOBAL') -+191: guard_value(p16, ConstPtr(ptr25), descr=) [p0, p1, p19, p16, p2, p3, p12, i21, p20, None, i6, i5] -+210: p27 = getfield_gc(p16, descr=) -+214: guard_value(p27, ConstPtr(ptr28), descr=) [p0, p1, p19, p27, p16, p2, p3, p12, i21, p20, None, i6, i5] -+227: p30 = getfield_gc(ConstPtr(ptr29), descr=) -+240: guard_isnull(p30, descr=) [p0, p1, p19, p30, p2, p3, p12, i21, p20, None, i6, i5] -+249: p32 = getfield_gc(ConstPtr(ptr31), descr=) -+257: guard_value(p32, ConstPtr(ptr33), descr=) [p0, p1, p19, p32, p2, p3, p12, i21, p20, None, i6, i5] -+270: p34 = getfield_gc(p32, descr=) -+274: guard_value(p34, ConstPtr(ptr35), descr=) [p0, p1, p19, p34, p32, p2, p3, p12, i21, p20, None, i6, i5] -+287: p37 = getfield_gc(ConstPtr(ptr36), descr=) -+295: guard_value(p37, ConstPtr(ptr38), descr=) [p0, p1, p19, p37, p2, p3, p12, i21, p20, None, i6, i5] ++190: guard_value(p16, ConstPtr(ptr25), descr=) [p0, p1, p19, p16, p2, p3, p12, i21, p20, None, i6, i5] ++209: p27 = getfield_gc(p16, descr=) ++213: guard_value(p27, ConstPtr(ptr28), descr=) [p0, p1, p19, p27, p16, p2, p3, p12, i21, p20, None, i6, i5] ++226: p30 = getfield_gc(ConstPtr(ptr29), descr=) ++239: guard_isnull(p30, descr=) [p0, p1, p19, p30, p2, p3, p12, i21, p20, None, i6, i5] ++248: guard_not_invalidated(, descr=) [p0, p1, p19, p2, p3, p12, i21, p20, None, i6, i5] ++248: p32 = getfield_gc(ConstPtr(ptr31), descr=) ++256: guard_value(p32, ConstPtr(ptr33), descr=) [p0, p1, p19, p32, p2, p3, p12, i21, p20, None, i6, i5] ++269: p35 = getfield_gc(ConstPtr(ptr34), descr=) ++277: guard_value(p35, ConstPtr(ptr36), descr=) [p0, p1, p19, p35, p2, p3, p12, i21, p20, None, i6, i5] debug_merge_point(1, ' #12 LOAD_CONST') debug_merge_point(1, ' #15 CALL_FUNCTION') -+308: p39 = getfield_gc(ConstPtr(ptr38), descr=) -+316: guard_not_invalidated(, descr=) [p0, p1, p19, p39, p2, p3, p12, i21, p20, None, i6, i5] debug_merge_point(1, ' #18 GET_ITER') debug_merge_point(1, ' #19 FOR_ITER') debug_merge_point(1, ' #22 STORE_FAST') @@ -669,677 +656,662 @@ debug_merge_point(1, ' #31 INPLACE_ADD') debug_merge_point(1, ' #32 STORE_FAST') debug_merge_point(1, ' #35 JUMP_ABSOLUTE') -+316: i41 = getfield_raw(40588192, descr=) -+324: i43 = int_sub(i41, 23) -+328: setfield_raw(40588192, i43, descr=) -+336: i45 = int_lt(i43, 0) -guard_false(i45, descr=) [p0, p1, p19, p2, p3, p12, i21, p20, None, i6, i5] ++290: i38 = getfield_raw(41254440, descr=) ++298: i40 = int_sub(i38, 8) ++302: setfield_raw(41254440, i40, descr=) ++310: i42 = int_lt(i40, 0) +guard_false(i42, descr=) [p0, p1, p19, p2, p3, p12, i21, p20, None, i6, i5] debug_merge_point(1, ' #19 FOR_ITER') -+346: i46 = force_token() -+353: p48 = new_with_vtable(20801800) -+430: setfield_gc(p48, i21, descr=) -setfield_gc(p19, p48, descr=) -+481: setfield_gc(p1, i46, descr=) -+492: p50 = new_with_vtable(20869528) -+565: setfield_gc(p50, ConstPtr(ptr15), descr=) -+579: setfield_gc(p50, ConstPtr(ptr51), descr=) -+593: setfield_gc(p50, 2, descr=) -+601: p54 = new_array(5, descr=) -+679: p56 = new_with_vtable(ConstClass(W_IntObject)) -+749: setfield_gc(p56, 1, descr=) -setarrayitem_gc(p54, 0, p56, descr=) -+797: p60 = new_with_vtable(ConstClass(W_IntObject)) -setarrayitem_gc(p54, 1, p60, descr=) -+907: p63 = new_with_vtable(20808496) -+977: p65 = new_with_vtable(20810448) -+1047: setfield_gc(p65, 1, descr=) -+1055: setfield_gc(p65, 3, descr=) -setfield_gc(p63, p65, descr=) -+1103: setfield_gc(p63, 1, descr=) -setarrayitem_gc(p54, 2, p63, descr=) -setfield_gc(p50, p54, descr=) -+1194: setfield_gc(p50, 19, descr=) -+1202: setfield_gc(p50, 3, descr=) -setfield_gc(p50, p20, descr=) -+1248: setfield_gc(p50, 21, descr=) -setfield_gc(p50, ConstPtr(ptr25), descr=) -+1314: p77 = call_assembler(p50, p19, ConstPtr(ptr73), ConstPtr(ptr15), 0, ConstPtr(ptr51), 3, 19, p56, p60, p63, ConstPtr(ptr75), ConstPtr(ptr76), descr=) -guard_not_forced(, descr=) [p0, p1, p19, p50, p77, p48, p2, p3, p12, i6, i5] -+1555: guard_no_exception(, descr=) [p0, p1, p19, p50, p77, p48, p2, p3, p12, i6, i5] -+1570: p78 = getfield_gc(p19, descr=) -+1581: guard_isnull(p78, descr=) [p0, p1, p19, p77, p50, p78, p48, p2, p3, p12, i6, i5] -+1590: i79 = ptr_eq(p50, p1) -guard_false(i79, descr=) [p0, p1, p19, p77, p50, p48, p2, p3, p12, i6, i5] -+1610: i80 = getfield_gc(p19, descr=) -+1614: setfield_gc(p50, ConstPtr(ptr81), descr=) -+1622: i82 = int_is_true(i80) -guard_false(i82, descr=) [p0, p1, p77, p50, p19, p48, p2, p3, p12, i6, i5] -+1632: p83 = getfield_gc(p19, descr=) -+1636: p84 = getfield_gc(p50, descr=) -+1640: i85 = getfield_gc(p50, descr=) -setfield_gc(p19, p84, descr=) -+1685: guard_false(i85, descr=) [p0, p1, p77, p83, p50, p19, p48, p2, p3, p12, i6, i5] ++320: i43 = force_token() ++327: p45 = new_with_vtable(21282720) ++404: setfield_gc(p45, i21, descr=) +setfield_gc(p19, p45, descr=) ++454: setfield_gc(p1, i43, descr=) ++465: p47 = new_with_vtable(21348760) ++538: setfield_gc(p47, 21, descr=) ++548: setfield_gc(p47, 3, descr=) ++559: setfield_gc(p47, ConstPtr(ptr25), descr=) ++573: p51 = new_array(5, descr=) ++651: p53 = new_with_vtable(ConstClass(W_IntObject)) ++721: setfield_gc(p53, 1, descr=) +setarrayitem_gc(p51, 0, p53, descr=) ++768: p57 = new_with_vtable(ConstClass(W_IntObject)) +setarrayitem_gc(p51, 1, p57, descr=) ++877: p60 = new_with_vtable(21286584) ++947: p62 = new_with_vtable(21289784) ++1017: setfield_gc(p62, 1, descr=) ++1025: setfield_gc(p62, 3, descr=) +setfield_gc(p60, p62, descr=) ++1072: setfield_gc(p60, 1, descr=) +setarrayitem_gc(p51, 2, p60, descr=) +setfield_gc(p47, p51, descr=) +setfield_gc(p47, ConstPtr(ptr15), descr=) ++1215: setfield_gc(p47, 2, descr=) +setfield_gc(p47, ConstPtr(ptr68), descr=) +setfield_gc(p47, p20, descr=) ++1311: setfield_gc(p47, 19, descr=) ++1319: p74 = call_assembler(p47, p19, ConstPtr(ptr70), ConstPtr(ptr15), 0, ConstPtr(ptr68), 3, 19, p53, p57, p60, ConstPtr(ptr72), ConstPtr(ptr73), descr=) +guard_not_forced(, descr=) [p0, p1, p19, p47, p74, p45, p2, p3, p12, i6, i5] ++1552: guard_no_exception(, descr=) [p0, p1, p19, p47, p74, p45, p2, p3, p12, i6, i5] ++1567: p75 = getfield_gc(p19, descr=) ++1578: guard_isnull(p75, descr=) [p0, p1, p19, p74, p47, p75, p45, p2, p3, p12, i6, i5] ++1587: i76 = getfield_gc(p19, descr=) ++1591: setfield_gc(p47, ConstPtr(ptr77), descr=) ++1606: i78 = int_is_true(i76) +guard_false(i78, descr=) [p0, p1, p74, p47, p19, p45, p2, p3, p12, i6, i5] ++1616: p79 = getfield_gc(p19, descr=) ++1620: p80 = getfield_gc(p47, descr=) ++1624: i81 = getfield_gc(p47, descr=) +setfield_gc(p19, p80, descr=) ++1668: guard_false(i81, descr=) [p0, p1, p74, p79, p47, p19, p45, p2, p3, p12, i6, i5] debug_merge_point(0, ' #46 INPLACE_ADD') -+1694: setfield_gc(p48, -3, descr=) -+1710: guard_class(p77, ConstClass(W_IntObject), descr=) [p0, p1, p77, p2, p3, i6, i5] -+1722: i88 = getfield_gc_pure(p77, descr=) -+1726: i89 = int_add_ovf(i6, i88) -guard_no_overflow(, descr=) [p0, p1, p77, i89, p2, p3, i6, i5] ++1677: setfield_gc(p45, -3, descr=) ++1693: guard_class(p74, ConstClass(W_IntObject), descr=) [p0, p1, p74, p2, p3, i6, i5] ++1705: i84 = getfield_gc_pure(p74, descr=) ++1709: i85 = int_add_ovf(i6, i84) +guard_no_overflow(, descr=) [p0, p1, p74, i85, p2, p3, i6, i5] debug_merge_point(0, ' #47 STORE_FAST') debug_merge_point(0, ' #50 JUMP_FORWARD') debug_merge_point(0, ' #63 LOAD_FAST') debug_merge_point(0, ' #66 LOAD_CONST') debug_merge_point(0, ' #69 INPLACE_ADD') -+1742: i91 = int_add_ovf(i5, 1) -guard_no_overflow(, descr=) [p0, p1, i91, p2, p3, i89, None, i5] ++1725: i87 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i87, p2, p3, i85, None, i5] debug_merge_point(0, ' #70 STORE_FAST') debug_merge_point(0, ' #73 JUMP_ABSOLUTE') -+1759: i93 = getfield_raw(40588192, descr=) -+1767: i95 = int_sub(i93, 26) -+1771: setfield_raw(40588192, i95, descr=) -+1779: i97 = int_lt(i95, 0) -guard_false(i97, descr=) [p0, p1, p2, p3, i91, i89, None, None] ++1742: i89 = getfield_raw(41254440, descr=) ++1750: i91 = int_sub(i89, 11) ++1754: setfield_raw(41254440, i91, descr=) ++1762: i93 = int_lt(i91, 0) +guard_false(i93, descr=) [p0, p1, p2, p3, i87, i85, None, None] debug_merge_point(0, ' #15 LOAD_FAST') -+1789: p99 = new_with_vtable(ConstClass(W_IntObject)) -+1859: setfield_gc(p99, i89, descr=) -+1863: p101 = new_with_vtable(ConstClass(W_IntObject)) -+1933: setfield_gc(p101, i91, descr=) -+1944: jump(p1, p0, p2, ConstPtr(ptr102), 0, p3, 2, 15, p99, p101, ConstPtr(ptr106), ConstPtr(ptr107), descr=) -+2054: --end of the loop-- -[4caca4492641] jit-log-opt-bridge} -[4caca6b867f7] {jit-backend -[4caca6be469f] {jit-backend-dump ++1772: p95 = new_with_vtable(ConstClass(W_IntObject)) ++1849: setfield_gc(p95, i85, descr=) ++1860: p97 = new_with_vtable(ConstClass(W_IntObject)) ++1930: setfield_gc(p97, i87, descr=) ++1941: jump(p1, p0, p2, ConstPtr(ptr98), 0, p3, 2, 15, p95, p97, ConstPtr(ptr102), ConstPtr(ptr103), descr=) ++2043: --end of the loop-- +[57f8632120b] jit-log-opt-bridge} +[57f8713d317] {jit-backend +[57f87216ddb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bae6a +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B01488B0425B8C2540148C70425B8C254010000000048898550FFFFFF488B0425C0C2540148C70425C0C254010000000048898548FFFFFF488B0425C8C2540148C70425C8C254010000000048898540FFFFFF488B0425D0C2540148C70425D0C254010000000048898538FFFFFF488B0425D8C2540148C70425D8C254010000000048898530FFFFFF4C8B3425004E5B01488B0425084E5B0148898528FFFFFF488B0425F0C2540148C70425F0C254010000000048898520FFFFFF488B0425184E5B0148898518FFFFFF488B0425204E5B0148898510FFFFFF488B042508C3540148C7042508C354010000000048898508FFFFFF488B042510C3540148C7042510C354010000000048898500FFFFFF49BB60A0CFB8A07F00004D8B2B4983C50149BB60A0CFB8A07F00004D892B4C3BB528FFFFFF0F8D000000004D89F74C0FAFB518FFFFFF4C8BAD10FFFFFF4D01F54983C7014C8BB538FFFFFF4D897E084C89EF49C7C31061B70041FFD34C8BA500FFFFFF4D8B5424084D89D14983C201488985F8FEFFFF4C898DF0FEFFFF4C89E74C89D649C7C3C07FB50041FFD348833C2550546B02000F85000000004D8B5424104C8995E8FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700D004000048891425704F3D014C8B95F8FEFFFF4C8950084C8B95E8FEFFFF4C8B8DF0FEFFFF41F6420401741D41524151504C89D74C89CE4889C249C7C380DEB20041FFD3584159415A4B8944CA10488B0425A0536B024883E80448890425A0536B024883F8000F8C000000004C89B538FFFFFF4D89FE4C89A500FFFFFF4D89EFE9A0FEFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA560FEFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C74C898D50FFFFFF4C8B5D104C899D48FFFFFF4C8B5D184C899D40FFFFFF4C8B5D204C899D38FFFFFF4C8B5D284C899D30FFFFFF4C8B5D304D89DE4C8B5D384C899D28FFFFFF4C8B5D404C899D20FFFFFF4C8B5D484C899D18FFFFFF4C8B5D504C899D10FFFFFF4C8B5D584C899D08FFFFFF4C8B5D604C899D00FFFFFFE9CAFDFFFF49BB00905BB6A07F000041FFD344405C3968484C505458603D033C00000049BB00905BB6A07F000041FFD3444074484C50545838603507033D00000049BB45905BB6A07F000041FFD34440810130484C50545838607C3507033E00000049BB00905BB6A07F000041FFD34440484C505458386035033F000000 -[4caca6bf7b89] jit-backend-dump} -[4caca6bf857d] {jit-backend-addr -Loop #4 ( #13 FOR_ITER) has address 7fa0b65bafff to 7fa0b65bb15f (bootstrap 7fa0b65bae6a) -[4caca6bf97cf] jit-backend-addr} -[4caca6bfa0ad] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61df6 +0 554889E5534154415541564157488DA500000000488B0425D0295C0148C70425D0295C010000000048898570FFFFFF488B0425D8295C0148C70425D8295C010000000048898568FFFFFF488B0425E0295C0148C70425E0295C010000000048898560FFFFFF488B0425E8295C0148C70425E8295C010000000048898558FFFFFF4C8B3C25B0B96201488B0425F8295C0148C70425F8295C010000000048898550FFFFFF488B0425002A5C0148C70425002A5C010000000048898548FFFFFF488B0425082A5C0148C70425082A5C010000000048898540FFFFFF488B0425102A5C0148C70425102A5C010000000048898538FFFFFF488B0425182A5C0148C70425182A5C010000000048898530FFFFFF4C8B3425E0B96201488B0425E8B9620148898528FFFFFF488B0425302A5C0148C70425302A5C010000000048898520FFFFFF488B0425F8B9620148898518FFFFFF488B042500BA620148898510FFFFFF488B0425482A5C0148C70425482A5C010000000048898508FFFFFF49BB60F049D6C97F00004D8B2B4983C50149BB60F049D6C97F00004D892B4C3BB528FFFFFF0F8D000000004D89F74C0FAFB518FFFFFF4C8BAD10FFFFFF4D01F54983C7014C8BB538FFFFFF4D897E084C89EF41BB80A9D10041FFD34C8BA508FFFFFF4D8B5424084D89D14983C20148898500FFFFFF4C898DF8FEFFFF4C89E74C89D641BBC0707E0041FFD348833C25D07E7502000F85000000004D8B5424104C8995F0FEFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700D004000048891425709F44014C8B9500FFFFFF4C8950084C8B95F0FEFFFF4C8B8DF8FEFFFF41F6420401741C41525041514C89D74C89CE4889C241BB9018C80041FFD3415958415A4B8944CA10488B0425287E75024883E80348890425287E75024883F8000F8C000000004C89B538FFFFFF4D89FE4C89A508FFFFFF4D89EFE9A3FEFFFF488B0425207E75024829E0483B0425802C4401760D49BB0403E6D3C97F000041FFD3554889E5534154415541564157488DA560FEFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C74C898D50FFFFFF4C8B5D104C899D48FFFFFF4C8B5D184C899D40FFFFFF4C8B5D204C899D38FFFFFF4C8B5D284C899D30FFFFFF4C8B5D304D89DE4C8B5D384C899D28FFFFFF4C8B5D404C899D20FFFFFF4C8B5D484C899D18FFFFFF4C8B5D504C899D10FFFFFF4C8B5D584C899D08FFFFFFE9D8FDFFFF49BB0000E6D3C97F000041FFD344405C3968484C505458603D033B00000049BB0000E6D3C97F000041FFD34440484C50545838603507033C00000049BB4300E6D3C97F000041FFD344407D30484C5054583860783507033D00000049BB0000E6D3C97F000041FFD34440484C505458386035033E000000 +[57f8723a1ef] jit-backend-dump} +[57f8723b47b] {jit-backend-addr +Loop 4 ( #13 FOR_ITER) has address 7fc9d3e61f70 to 7fc9d3e620cd (bootstrap 7fc9d3e61df6) +[57f8723d337] jit-backend-addr} +[57f8723e3a7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bae7a +0 60FEFFFF -[4caca6bfad9b] jit-backend-dump} -[4caca6bfb47b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61e06 +0 60FEFFFF +[57f8723fbef] jit-backend-dump} +[57f87240b63] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb026 +0 0B020000 -[4caca6bfbdd5] jit-backend-dump} -[4caca6bfc367] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e61f97 +0 FD010000 +[57f87241f27] jit-backend-dump} +[57f872429ff] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb097 +0 D6010000 -[4caca6bfcc49] jit-backend-dump} -[4caca6bfd1b9] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62006 +0 C9010000 +[57f87243d63] jit-backend-dump} +[57f872446c3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb142 +0 4C010000 -[4caca6bfdc6b] jit-backend-dump} -[4caca6bfe3b7] jit-backend} -[4caca6bff1d3] {jit-log-opt-loop +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e620b0 +0 3F010000 +[57f8724593b] jit-backend-dump} +[57f872463f3] jit-backend} +[57f87247a07] {jit-log-opt-loop # Loop 4 : loop with 30 ops -[p0, p1, p2, p3, i4, p5, p6, p7, p8, p9, i10, i11, p12, i13, i14, p15, p16] +[p0, p1, p2, p3, i4, p5, p6, p7, p8, p9, i10, i11, p12, i13, i14, p15] debug_merge_point(0, ' #13 FOR_ITER') -+435: i17 = int_ge(i10, i11) -guard_false(i17, descr=) [p1, p0, p8, i10, p12, p2, p3, p5, p6, p7, p9, i4] -+448: i18 = int_mul(i10, i13) -+459: i19 = int_add(i14, i18) -+469: i21 = int_add(i10, 1) ++408: i16 = int_ge(i10, i11) +guard_false(i16, descr=) [p1, p0, p8, i10, p12, p2, p3, p5, p6, p7, p9, i4] ++421: i17 = int_mul(i10, i13) ++432: i18 = int_add(i14, i17) ++442: i20 = int_add(i10, 1) debug_merge_point(0, ' #16 STORE_FAST') debug_merge_point(0, ' #19 LOAD_GLOBAL') ++446: setfield_gc(p8, i20, descr=) ++457: guard_not_invalidated(, descr=) [p1, p0, p2, p3, p5, p6, p7, p8, p9, i18, None] debug_merge_point(0, ' #22 LOAD_FAST') debug_merge_point(0, ' #25 CALL_FUNCTION') -+473: setfield_gc(p8, i21, descr=) -+484: guard_not_invalidated(, descr=) [p1, p0, p15, p2, p3, p5, p6, p7, p8, p9, i19, None] -+484: p24 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i19, descr=) ++457: p23 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i18, descr=) debug_merge_point(0, ' #28 LIST_APPEND') -+497: i25 = getfield_gc(p16, descr=) -+509: i27 = int_add(i25, 1) -+516: call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p16, i27, descr=) -+546: guard_no_exception(, descr=) [p1, p0, i25, p16, p2, p3, p5, p6, p7, p8, p9, p24, i19, None] -+561: p29 = getfield_gc(p16, descr=) -+566: p31 = new_with_vtable(ConstClass(W_StringObject)) -+636: setfield_gc(p31, p24, descr=) -setarrayitem_gc(p29, i25, p31, descr=) ++469: i24 = getfield_gc(p15, descr=) ++481: i26 = int_add(i24, 1) ++488: call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p15, i26, descr=) ++517: guard_no_exception(, descr=) [p1, p0, i24, p15, p2, p3, p5, p6, p7, p8, p9, p23, i18, None] ++532: p28 = getfield_gc(p15, descr=) ++537: p30 = new_with_vtable(ConstClass(W_StringObject)) ++607: setfield_gc(p30, p23, descr=) +setarrayitem_gc(p28, i24, p30, descr=) debug_merge_point(0, ' #31 JUMP_ABSOLUTE') -+702: i33 = getfield_raw(40588192, descr=) -+710: i35 = int_sub(i33, 4) -+714: setfield_raw(40588192, i35, descr=) -+722: i37 = int_lt(i35, 0) -guard_false(i37, descr=) [p1, p0, p2, p3, p5, p6, p7, p8, p9, i19] ++672: i32 = getfield_raw(41254440, descr=) ++680: i34 = int_sub(i32, 3) ++684: setfield_raw(41254440, i34, descr=) ++692: i36 = int_lt(i34, 0) +guard_false(i36, descr=) [p1, p0, p2, p3, p5, p6, p7, p8, p9, i18] debug_merge_point(0, ' #13 FOR_ITER') -+732: jump(p0, p1, p2, p3, i19, p5, p6, p7, p8, p9, i21, i11, p12, i13, i14, p15, p16, descr=) -+757: --end of the loop-- -[4caca6c22a91] jit-log-opt-loop} -[4caca6c25811] {jit-backend -[4caca6e7f105] {jit-backend-dump ++702: jump(p0, p1, p2, p3, i18, p5, p6, p7, p8, p9, i20, i11, p12, i13, i14, p15, descr=) ++727: --end of the loop-- +[57f8728edc3] jit-log-opt-loop} +[57f872942fb] {jit-backend +[57f8765e77b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb30f +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C2540100000000488B0C25E8C2540148C70425E8C2540100000000488B0425F0C2540148C70425F0C254010000000048898570FFFFFF488B0425F8C2540148C70425F8C254010000000048898568FFFFFF488B042500C3540148C7042500C354010000000048898560FFFFFF488B042508C3540148C7042508C354010000000048898558FFFFFF49BB68A0CFB8A07F0000498B034883C00149BB68A0CFB8A07F00004989034983F8050F8500000000488BBD70FFFFFF813FD03000000F85000000004C8B47104D85C00F8400000000488B47084C89BD50FFFFFF4D8B78204D85FF0F85000000004D8B78084C39F80F8D0000000048899D48FFFFFF498B581048899D40FFFFFF498B581848898538FFFFFF480FAFC348899D30FFFFFF488B9D40FFFFFF4801C3488B8538FFFFFF4883C001488947084983FA000F850000000049BBF8F477B6A07F00004D39DC0F85000000004C8BA550FFFFFF498B74240849BBA0217CB6A07F00004C39DE0F85000000004C8B56104981FAC07446010F850000000049BBF85371B6A07F0000498B334885F60F8500000000488B342508DF45014881FE706A49010F85000000004C8B56104981FAC07446010F8500000000488B3425B8B55D014881FE007D44010F8500000000488B342548A85A0148898D28FFFFFF48899520FFFFFF48898518FFFFFF4C898510FFFFFF4C898D08FFFFFF4889B500FFFFFF4889DF49C7C31061B70041FFD3488BB528FFFFFF4C8B4E084D8B41084C89C74983C001488985F8FEFFFF4889BDF0FEFFFF4C898DE8FEFFFF4C89CF4C89C649C7C3C07FB50041FFD348833C2550546B02000F85000000004C8B85E8FEFFFF4D8B48104C898DE0FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700D004000048891425704F3D014C8B95F8FEFFFF4C8950084C8B95E0FEFFFF4C8B8DF0FEFFFF41F6420401741D41514152504C89D74C89CE4889C249C7C380DEB20041FFD358415A41594B8944CA10488B0425A0536B024883E80448890425A0536B024883F8000F8C000000004C89B568FFFFFF4C89AD60FFFFFF488B8548FFFFFF48898550FFFFFF488B8520FFFFFF48898548FFFFFF488B8570FFFFFF48898538FFFFFF4C8BB518FFFFFF488B8510FFFFFF48898520FFFFFF488B8530FFFFFF48898518FFFFFF488B8540FFFFFF48898510FFFFFF4C89A570FFFFFF488B8528FFFFFF48898540FFFFFF488B8558FFFFFF48898530FFFFFF4C89BD28FFFFFF488B8508FFFFFF48898558FFFFFF4989DF488B8500FFFFFF48898508FFFFFF488B85E8FEFFFF48898500FFFFFF49BBFFAF5BB6A07F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA550FEFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D94C8B5D404C899D70FFFFFF4C8B5D484C899D68FFFFFF4C8B5D504C899D60FFFFFF4C8B5D584C899D58FFFFFFE90DFCFFFF49BB00905BB6A07F000041FFD321383C343029241D180C08044044484C034000000049BB00905BB6A07F000041FFD3383C1C34302924180C080444484C034100000049BB00905BB6A07F000041FFD3383C1C2034302924180C080444484C034200000049BB00905BB6A07F000041FFD338501C01203C34302924180C080444484C034300000049BB00905BB6A07F000041FFD338501C012034302924180C080444484C034400000049BB00905BB6A07F000041FFD3293850343024185408041C484C0D034500000049BB00905BB6A07F000041FFD338503034245408041C484C0D034600000049BB00905BB6A07F000041FFD338301834245408041C484C0D034700000049BB00905BB6A07F000041FFD33830281834245408041C484C0D034800000049BB00905BB6A07F000041FFD338301834245408041C484C0D034900000049BB00905BB6A07F000041FFD338301834245408041C484C0D034A00000049BB00905BB6A07F000041FFD33830281834245408041C484C0D034B00000049BB00905BB6A07F000041FFD338301834245408041C484C0D034C00000049BB00905BB6A07F000041FFD338301834245408041C4C0D034D00000049BB45905BB6A07F000041FFD33830810184013474546864404C7C0D034E00000049BB00905BB6A07F000041FFD338303474546864404C0D034F000000 -[4caca6e926f2] jit-backend-dump} -[4caca6e930e2] {jit-backend-addr -Loop #5 ( #13 FOR_ITER) has address 7fa0b65bb45b to 7fa0b65bb7ae (bootstrap 7fa0b65bb30f) -[4caca6e94267] jit-backend-addr} -[4caca6e94a6e] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6226a +0 554889E5534154415541564157488DA5000000004C8B3C25D0295C0148C70425D0295C01000000004C8B3425D8295C0148C70425D8295C01000000004C8B2C25E0295C0148C70425E0295C01000000004C8B2425E8295C0148C70425E8295C01000000004C8B1425B0B962014C8B0C25F8295C0148C70425F8295C01000000004C8B0425C0B96201488B3C25C8B96201488B3425102A5C0148C70425102A5C0100000000488B1C25182A5C0148C70425182A5C0100000000488B1425202A5C0148C70425202A5C0100000000488B0C25282A5C0148C70425282A5C0100000000488B0425302A5C0148C70425302A5C010000000048898570FFFFFF488B0425382A5C0148C70425382A5C010000000048898568FFFFFF488B0425402A5C0148C70425402A5C010000000048898560FFFFFF488B0425482A5C0148C70425482A5C010000000048898558FFFFFF49BB68F049D6C97F0000498B034883C00149BB68F049D6C97F00004989034983F8050F8500000000488BBD70FFFFFF813F582C00000F85000000004C8B47104D85C00F8400000000488B47084C89BD50FFFFFF4D8B78204D85FF0F85000000004D8B78084C39F80F8D000000004C898D48FFFFFF4D8B48104C89AD40FFFFFF4D8B681848898538FFFFFF490FAFC54C898D30FFFFFF4901C1488B8538FFFFFF4883C001488947084983FA000F850000000049BB287CFAD3C97F00004D39DC0F85000000004C8BA550FFFFFF498B74240849BB2060F7D3C97F00004C39DE0F85000000004C8B56104981FA60C84D010F850000000049BBD85342D6C97F0000498B334885F60F8500000000488B342520C350014881FE60C84D010F8500000000488B3425782065014881FE20D24B010F850000000048898D28FFFFFF48899520FFFFFF4C898D18FFFFFF4C898510FFFFFF48898508FFFFFF4C89CF41BB80A9D10041FFD34C8B8528FFFFFF4D8B4808498B79084889FA4883C70148899500FFFFFF4C898DF8FEFFFF488985F0FEFFFF4889FE4C89CF41BBC0707E0041FFD348833C25D07E7502000F8500000000488B85F8FEFFFF4C8B48104C898DE8FEFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700D004000048891425709F44014C8B95F0FEFFFF4C8950084C8B95E8FEFFFF4C8B8D00FFFFFF41F6420401741C41525041514C89D74C89CE4889C241BB9018C80041FFD3415958415A4B8944CA10488B0425287E75024883E80348890425287E75024883F8000F8C000000004C89B568FFFFFF488B8540FFFFFF48898560FFFFFF48899D50FFFFFF488B8528FFFFFF48898540FFFFFF488B8570FFFFFF48898538FFFFFF4C8BB508FFFFFF4C89BD28FFFFFF488B85F8FEFFFF48898508FFFFFF4C89A570FFFFFF4C8BBD18FFFFFF4C89AD18FFFFFFFFB558FFFFFF488B8548FFFFFF48898558FFFFFF488B8520FFFFFF48898548FFFFFF488B8510FFFFFF48898520FFFFFF488B8530FFFFFF48898510FFFFFF8F8530FFFFFF49BB701FE6D3C97F000041FFE3488B0425207E75024829E0483B0425802C4401760D49BB0403E6D3C97F000041FFD3554889E5534154415541564157488DA560FEFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D94C8B5D404C899D70FFFFFF4C8B5D484C899D68FFFFFF4C8B5D504C899D60FFFFFF4C8B5D584C899D58FFFFFFE94AFCFFFF49BB0000E6D3C97F000041FFD321383C343029241D180C08044044484C033F00000049BB0000E6D3C97F000041FFD3383C1C34302924180C080444484C034000000049BB0000E6D3C97F000041FFD3383C1C2034302924180C080444484C034100000049BB0000E6D3C97F000041FFD338501C01203C34302924180C080444484C034200000049BB0000E6D3C97F000041FFD338501C012034302924180C080444484C034300000049BB0000E6D3C97F000041FFD3293850583054180C08041C484C25034400000049BB0000E6D3C97F000041FFD338503058540C08041C484C25034500000049BB0000E6D3C97F000041FFD338301858540C08041C484C25034600000049BB0000E6D3C97F000041FFD33830281858540C08041C484C25034700000049BB0000E6D3C97F000041FFD338301858540C08041C484C25034800000049BB0000E6D3C97F000041FFD3383058540C08041C484C25034900000049BB0000E6D3C97F000041FFD338301858540C08041C484C25034A00000049BB0000E6D3C97F000041FFD338301858540C08041C484C25034B00000049BB4300E6D3C97F000041FFD33830797C58540C6864404C80016D034C00000049BB0000E6D3C97F000041FFD3383058540C6864404C6D034D000000 +[57f8767cecb] jit-backend-dump} +[57f8767df6f] {jit-backend-addr +Loop 5 ( #13 FOR_ITER) has address 7fc9d3e623b6 to 7fc9d3e626cc (bootstrap 7fc9d3e6226a) +[57f8767fd77] jit-backend-addr} +[57f876809fb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb31f +0 50FEFFFF -[4caca6e95923] jit-backend-dump} -[4caca6e96085] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6227a +0 60FEFFFF +[57f8768289b] jit-backend-dump} +[57f876836fb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb47f +0 CB030000 -[4caca6e96c46] jit-backend-dump} -[4caca6e97240] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e623da +0 8E030000 +[57f87684d57] jit-backend-dump} +[57f87685833] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb492 +0 DA030000 -[4caca6e97cfc] jit-backend-dump} -[4caca6e981a9] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e623ed +0 9D030000 +[57f87686da7] jit-backend-dump} +[57f8768779b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb49f +0 ED030000 -[4caca6e98be1] jit-backend-dump} -[4caca6e9906d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e623fa +0 B0030000 +[57f87688c3f] jit-backend-dump} +[57f876896b3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb4b7 +0 F6030000 -[4caca6e999f7] jit-backend-dump} -[4caca6e99f88] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62412 +0 B9030000 +[57f8768aab7] jit-backend-dump} +[57f8768b45b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb4c4 +0 0C040000 -[4caca6e9aaa1] jit-backend-dump} -[4caca6e9afd8] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6241f +0 CF030000 +[57f8768c8a7] jit-backend-dump} +[57f8768d113] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb50f +0 E3030000 -[4caca6e9bb90] jit-backend-dump} -[4caca6e9c025] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62463 +0 AD030000 +[57f8768e45b] jit-backend-dump} +[57f8768ee7b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb522 +0 F0030000 -[4caca6e9c9ac] jit-backend-dump} -[4caca6e9ce29] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62476 +0 BA030000 +[57f8769033f] jit-backend-dump} +[57f87690c0f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb541 +0 EF030000 -[4caca6e9d7b0] jit-backend-dump} -[4caca6e9dc45] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62495 +0 B9030000 +[57f876920a7] jit-backend-dump} +[57f87692b07] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb552 +0 FC030000 -[4caca6e9e848] jit-backend-dump} -[4caca6e9edeb] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e624a6 +0 C6030000 +[57f87693df3] jit-backend-dump} +[57f876948ab] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb568 +0 05040000 -[4caca6e9f91f] jit-backend-dump} -[4caca6e9fd9c] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e624bc +0 CF030000 +[57f87695ac3] jit-backend-dump} +[57f876964c3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb57d +0 0E040000 -[4caca6ea0723] jit-backend-dump} -[4caca6ea0b9d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e624d1 +0 F5030000 +[57f87697493] jit-backend-dump} +[57f87697bc3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb58e +0 1B040000 -[4caca6ea1524] jit-backend-dump} -[4caca6ea19b6] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e624e6 +0 FE030000 +[57f87698aa7] jit-backend-dump} +[57f87699397] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb5a3 +0 25040000 -[4caca6ea233d] jit-backend-dump} -[4caca6ea29f4] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6255e +0 A4030000 +[57f8769a3b3] jit-backend-dump} +[57f8769ab4f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb62c +0 D7030000 -[4caca6ea34fe] jit-backend-dump} -[4caca6ea53b3] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bb6dd +0 47030000 -[4caca6ea5e3b] jit-backend-dump} -[4caca6ea646b] jit-backend} -[4caca6ea7139] {jit-log-opt-loop -# Loop 5 : entry bridge with 56 ops +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6260e +0 14030000 +[57f8769c163] jit-backend-dump} +[57f8769cda7] jit-backend} +[57f8769e407] {jit-log-opt-loop +# Loop 5 : entry bridge with 53 ops [p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11, p12, p13, p14, p15] debug_merge_point(0, ' #13 FOR_ITER') -+362: guard_value(i6, 5, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] -+372: guard_class(p12, 20808496, descr=) [p1, p0, p12, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] ++362: guard_value(i6, 5, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] ++372: guard_class(p12, 21286584, descr=) [p1, p0, p12, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] +391: p18 = getfield_gc(p12, descr=) -+395: guard_nonnull(p18, descr=) [p1, p0, p12, p18, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] ++395: guard_nonnull(p18, descr=) [p1, p0, p12, p18, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] +404: i19 = getfield_gc(p12, descr=) +408: p20 = getfield_gc(p18, descr=) -+419: guard_isnull(p20, descr=) [p1, p0, p12, i19, p18, p20, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] ++419: guard_isnull(p20, descr=) [p1, p0, p12, i19, p18, p20, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] +428: i21 = getfield_gc(p18, descr=) +432: i22 = int_ge(i19, i21) -guard_false(i22, descr=) [p1, p0, p12, i19, p18, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] +guard_false(i22, descr=) [p1, p0, p12, i19, p18, p2, p3, i4, p5, p8, p9, p10, p11, p13, p14, p15] +441: i23 = getfield_gc(p18, descr=) +452: i24 = getfield_gc(p18, descr=) +463: i25 = int_mul(i19, i24) +474: i26 = int_add(i23, i25) -+491: i28 = int_add(i19, 1) -+502: setfield_gc(p12, i28, descr=) -+506: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p10, p11, p12, p14, p15, i26] ++484: i28 = int_add(i19, 1) ++495: setfield_gc(p12, i28, descr=) ++499: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p10, p11, p12, p14, p15, i26] debug_merge_point(0, ' #16 STORE_FAST') debug_merge_point(0, ' #19 LOAD_GLOBAL') -+516: guard_value(p3, ConstPtr(ptr30), descr=) [p1, p0, p3, p2, p5, p9, p10, p11, p12, p14, p15, i26] -+535: p31 = getfield_gc(p0, descr=) -+547: guard_value(p31, ConstPtr(ptr32), descr=) [p1, p0, p31, p2, p5, p9, p10, p11, p12, p14, p15, i26] -+566: p33 = getfield_gc(p31, descr=) -+570: guard_value(p33, ConstPtr(ptr34), descr=) [p1, p0, p33, p31, p2, p5, p9, p10, p11, p12, p14, p15, i26] -+583: p36 = getfield_gc(ConstPtr(ptr35), descr=) -+596: guard_isnull(p36, descr=) [p1, p0, p36, p2, p5, p9, p10, p11, p12, p14, p15, i26] -+605: p38 = getfield_gc(ConstPtr(ptr37), descr=) -+613: guard_value(p38, ConstPtr(ptr39), descr=) [p1, p0, p38, p2, p5, p9, p10, p11, p12, p14, p15, i26] -+626: p40 = getfield_gc(p38, descr=) -+630: guard_value(p40, ConstPtr(ptr41), descr=) [p1, p0, p40, p38, p2, p5, p9, p10, p11, p12, p14, p15, i26] -+643: p43 = getfield_gc(ConstPtr(ptr42), descr=) -+651: guard_value(p43, ConstPtr(ptr44), descr=) [p1, p0, p43, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++509: guard_value(p3, ConstPtr(ptr30), descr=) [p1, p0, p3, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++528: p31 = getfield_gc(p0, descr=) ++540: guard_value(p31, ConstPtr(ptr32), descr=) [p1, p0, p31, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++559: p33 = getfield_gc(p31, descr=) ++563: guard_value(p33, ConstPtr(ptr34), descr=) [p1, p0, p33, p31, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++576: p36 = getfield_gc(ConstPtr(ptr35), descr=) ++589: guard_isnull(p36, descr=) [p1, p0, p36, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++598: guard_not_invalidated(, descr=) [p1, p0, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++598: p38 = getfield_gc(ConstPtr(ptr37), descr=) ++606: guard_value(p38, ConstPtr(ptr39), descr=) [p1, p0, p38, p2, p5, p9, p10, p11, p12, p14, p15, i26] ++619: p41 = getfield_gc(ConstPtr(ptr40), descr=) ++627: guard_value(p41, ConstPtr(ptr42), descr=) [p1, p0, p41, p2, p5, p9, p10, p11, p12, p14, p15, i26] debug_merge_point(0, ' #22 LOAD_FAST') debug_merge_point(0, ' #25 CALL_FUNCTION') -+664: p46 = getfield_gc(ConstPtr(ptr45), descr=) -+672: guard_not_invalidated(, descr=) [p1, p0, p46, p2, p5, p9, p10, p11, p12, p15, i26] -+672: p48 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i26, descr=) ++640: p44 = call(ConstClass(ll_int_str__IntegerR_SignedConst_Signed), i26, descr=) debug_merge_point(0, ' #28 LIST_APPEND') -+727: p49 = getfield_gc(p11, descr=) -+738: i50 = getfield_gc(p49, descr=) -+742: i52 = int_add(i50, 1) -+749: call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p49, i52, descr=) -+786: guard_no_exception(, descr=) [p1, p0, i50, p49, p2, p5, p9, p10, p11, p12, p15, p48, i26] -+801: p54 = getfield_gc(p49, descr=) -+812: p56 = new_with_vtable(ConstClass(W_StringObject)) -+882: setfield_gc(p56, p48, descr=) -setarrayitem_gc(p54, i50, p56, descr=) ++687: p45 = getfield_gc(p11, descr=) ++698: i46 = getfield_gc(p45, descr=) ++702: i48 = int_add(i46, 1) ++709: call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p45, i48, descr=) ++745: guard_no_exception(, descr=) [p1, p0, i46, p45, p2, p5, p9, p10, p11, p12, p15, p44, i26] ++760: p50 = getfield_gc(p45, descr=) ++771: p52 = new_with_vtable(ConstClass(W_StringObject)) ++841: setfield_gc(p52, p44, descr=) +setarrayitem_gc(p50, i46, p52, descr=) debug_merge_point(0, ' #31 JUMP_ABSOLUTE') -+948: i58 = getfield_raw(40588192, descr=) -+956: i60 = int_sub(i58, 4) -+960: setfield_raw(40588192, i60, descr=) -+968: i62 = int_lt(i60, 0) -guard_false(i62, descr=) [p1, p0, p2, p5, p9, p10, p11, p12, p15, i26] ++906: i54 = getfield_raw(41254440, descr=) ++914: i56 = int_sub(i54, 3) ++918: setfield_raw(41254440, i56, descr=) ++926: i58 = int_lt(i56, 0) +guard_false(i58, descr=) [p1, p0, p2, p5, p9, p10, p11, p12, p15, i26] debug_merge_point(0, ' #13 FOR_ITER') -+978: jump(p0, p1, p2, p5, i26, p9, p10, p11, p12, p15, i28, i21, p18, i24, i23, p46, p49, descr=) -+1183: --end of the loop-- -[4caca6ee826b] jit-log-opt-loop} -[4caca7252489] {jit-backend -[4caca726cc63] {jit-backend-dump ++936: jump(p0, p1, p2, p5, i26, p9, p10, p11, p12, p15, i28, i21, p18, i24, i23, p45, descr=) ++1122: --end of the loop-- +[57f877459f3] jit-log-opt-loop} +[57f87db5043] {jit-backend +[57f87dda1cb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bba44 +0 554889E5534154415541564157488DA5000000004C8B3C25B04D5B014C8B342598C2540148C7042598C254010000000049BB70A0CFB8A07F00004D8B2B4983C50149BB70A0CFB8A07F00004D892B4D8B6E404F0FB66C3D184983FD330F85000000004D89FD4983C7014D897E1849C74620000000004D896E2848C7C00100000048890425B04D5B0149C7C340BC920041FFD348C7C001000000488D65D8415F415E415D415C5B5DC3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA570FFFFFF4989FF4989F6E947FFFFFF49BB00905BB6A07F000041FFD33D380350000000 -[4caca727040f] jit-backend-dump} -[4caca7270a0d] {jit-backend-addr -Loop #6 (StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]) has address 7fa0b65bba74 to 7fa0b65bbaec (bootstrap 7fa0b65bba44) -[4caca72717af] jit-backend-addr} -[4caca7271eeb] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62942 +0 554889E5534154415541564157488DA5000000004C8B3C2590B962014C8B3425D8295C0148C70425D8295C010000000049BB70F049D6C97F00004D8B2B4983C50149BB70F049D6C97F00004D892B4D8B6E404F0FB66C3D184983FD330F85000000004D89FD4983C7014D897E1849C74620000000004D896E28B8010000004889042590B9620141BBD01AEA0041FFD3B801000000488D65D8415F415E415D415C5B5DC3488B0425207E75024829E0483B0425802C4401760D49BB0403E6D3C97F000041FFD3554889E5534154415541564157488DA570FFFFFF4989FF4989F6E94CFFFFFF49BB0000E6D3C97F000041FFD33D38034E000000 +[57f87ddf053] jit-backend-dump} +[57f87ddf887] {jit-backend-addr +Loop 6 (StrLiteralSearch at 11/51 [17, 8, 3, 1, 1, 1, 1, 51, 0, 19, 51, 1]) has address 7fc9d3e62972 to 7fc9d3e629e5 (bootstrap 7fc9d3e62942) +[57f87de0a03] jit-backend-addr} +[57f87de131f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bba54 +0 70FFFFFF -[4caca7273019] jit-backend-dump} -[4caca72738af] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62952 +0 70FFFFFF +[57f87de25bb] jit-backend-dump} +[57f87de30eb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbaa2 +0 87000000 -[4caca72746b5] jit-backend-dump} -[4caca7274fab] jit-backend} -[4caca7275aaf] {jit-log-opt-loop +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e629a0 +0 82000000 +[57f87de407f] jit-backend-dump} +[57f87de48eb] jit-backend} +[57f87de5503] {jit-log-opt-loop # Loop 6 : entry bridge with 10 ops [i0, p1] debug_merge_point(0, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') +78: p2 = getfield_gc(p1, descr=) +82: i3 = strgetitem(p2, i0) +88: i5 = int_eq(i3, 51) -guard_true(i5, descr=) [i0, p1] +guard_true(i5, descr=) [i0, p1] +98: i7 = int_add(i0, 1) +105: setfield_gc(p1, i7, descr=) +109: setfield_gc(p1, ConstPtr(ptr8), descr=) +117: setfield_gc(p1, i0, descr=) -+121: finish(1, descr=) -+168: --end of the loop-- -[4caca72833af] jit-log-opt-loop} -[4caca73ec6b9] {jit-backend -[4caca73feba1] {jit-backend-dump ++121: finish(1, descr=) ++163: --end of the loop-- +[57f87df5033] jit-log-opt-loop} +[57f880d8517] {jit-backend +[57f880f4b7b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbb41 +0 488DA50000000049BB78A0CFB8A07F00004D8B2B4983C50149BB78A0CFB8A07F00004D892B4983C7014D8B6E084D39EF0F8D0000000049BB74BA5BB6A07F000041FFE349BB00905BB6A07F000041FFD33D380351000000 -[4caca7401165] jit-backend-dump} -[4caca74017bb] {jit-backend-addr -Bridge out of guard 80 has address 7fa0b65bbb41 to 7fa0b65bbb84 -[4caca7402331] jit-backend-addr} -[4caca740291b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62a3a +0 488DA50000000049BB78F049D6C97F00004D8B2B4983C50149BB78F049D6C97F00004D892B4983C7014D8B6E084D39EF0F8D0000000049BB7229E6D3C97F000041FFE349BB0000E6D3C97F000041FFD33D38034F000000 +[57f880f8273] jit-backend-dump} +[57f880f8b83] {jit-backend-addr +bridge out of Guard 78 has address 7fc9d3e62a3a to 7fc9d3e62a7d +[57f880f99d3] jit-backend-addr} +[57f880fa11f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbb44 +0 70FFFFFF -[4caca7403451] jit-backend-dump} -[4caca7403a29] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62a3d +0 70FFFFFF +[57f880fb26f] jit-backend-dump} +[57f880fbc63] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbb73 +0 0D000000 -[4caca740430b] jit-backend-dump} -[4caca7404bf1] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62a6c +0 0D000000 +[57f880fca0b] jit-backend-dump} +[57f880fd3ab] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbaa2 +0 9B000000 -[4caca74054b5] jit-backend-dump} -[4caca7405a91] jit-backend} -[4caca7406281] {jit-log-opt-bridge -# bridge out of Guard 80 with 6 ops +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e629a0 +0 96000000 +[57f880fe0c3] jit-backend-dump} +[57f880fe817] jit-backend} +[57f880ff50f] {jit-log-opt-bridge +# bridge out of Guard 78 with 6 ops [i0, p1] +37: i3 = int_add(i0, 1) +41: i4 = getfield_gc_pure(p1, descr=) +45: i5 = int_lt(i3, i4) -guard_true(i5, descr=) [i3, p1] +guard_true(i5, descr=) [i3, p1] debug_merge_point(0, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') +54: jump(i3, p1, descr=) +67: --end of the loop-- -[4caca740c999] jit-log-opt-bridge} -[4caca77f59c2] {jit-backend -[4caca780f57c] {jit-backend-dump +[57f88113d8f] jit-log-opt-bridge} +[57f8843073f] {jit-backend +[57f8843d8cb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbb98 +0 488DA50000000049BB80A0CFB8A07F00004D8B334983C60149BB80A0CFB8A07F00004D893348C7C00000000048890425B04D5B0149C7C340BC920041FFD348C7C001000000488D65D8415F415E415D415C5B5DC3 -[4caca782495a] jit-backend-dump} -[4caca7826082] {jit-backend-addr -Bridge out of guard 81 has address 7fa0b65bbb98 to 7fa0b65bbbec -[4caca7827f7e] jit-backend-addr} -[4caca7829178] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62a91 +0 488DA50000000049BB80F049D6C97F00004D8B334983C60149BB80F049D6C97F00004D8933B8000000004889042590B9620141BBD01AEA0041FFD3B801000000488D65D8415F415E415D415C5B5DC3 +[57f88440a07] jit-backend-dump} +[57f8844108b] {jit-backend-addr +bridge out of Guard 79 has address 7fc9d3e62a91 to 7fc9d3e62ae0 +[57f88441c47] jit-backend-addr} +[57f88442393] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbb9b +0 70FFFFFF -[4caca782b236] jit-backend-dump} -[4caca782c3c4] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62a94 +0 70FFFFFF +[57f8844324b] jit-backend-dump} +[57f88443c17] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbb73 +0 21000000 -[4caca782e12e] jit-backend-dump} -[4caca782efb6] jit-backend} -[4caca78304da] {jit-log-opt-bridge -# bridge out of Guard 81 with 1 ops +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62a6c +0 21000000 +[57f88444a53] jit-backend-dump} +[57f884450cb] jit-backend} +[57f88445a13] {jit-log-opt-bridge +# bridge out of Guard 79 with 1 ops [i0, p1] -+37: finish(0, descr=) -+84: --end of the loop-- -[4caca78370ec] jit-log-opt-bridge} -[4cacad3efadb] {jit-backend -[4cacad6472d9] {jit-backend-dump ++37: finish(0, descr=) ++79: --end of the loop-- +[57f88448eaf] jit-log-opt-bridge} +[57f89c2d9a3] {jit-backend +[57f89dce1f7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbd77 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF488B0425B0C2540148C70425B0C254010000000048898550FFFFFF488B0425B8C2540148C70425B8C254010000000048898548FFFFFF4C8B3C25C0C2540148C70425C0C2540100000000488B0425C8C2540148C70425C8C254010000000048898540FFFFFF4C8B3425F04D5B01488B0425D8C2540148C70425D8C254010000000048898538FFFFFF488B0425E0C2540148C70425E0C254010000000048898530FFFFFF49BB88A0CFB8A07F00004D8B2B4983C50149BB88A0CFB8A07F00004D892B4C8BAD40FFFFFF4D8B65184D85E40F84000000004D8B55084D8B4C24084D39CA0F8D000000004D8B6424104F8B64D4104983C2014C8BBD70FFFFFF4D8B4F084D89550849BBA0217CB6A07F00004D39D90F85000000004D8B51104981FAC07446010F850000000049BB683A79B6A07F00004D8B0B4983F9017207418139C84000000F85000000004D8B510849BB904279B6A07F00004D39DA0F85000000004D8B42104981F8C07446010F850000000049BB883D79B6A07F00004D8B134983FA01720741813A082601000F85000000004983FC01720841813C24D00400000F85000000004D8B4A1849BB20F777B6A07F00004D39D90F85000000004D8B4A204D8B410848C7C7030000004C29C74883FF020F8F00000000498B7A404C89C64983E8014939F00F8D000000004F8B44C1104C8D8D78FFFFFF4983FE000F850000000049BB904279B6A07F00004C39DF0F85000000004C8B77104981FEC07446010F850000000049BB583C79B6A07F0000498B3B4883FF017206813F082601000F85000000004D85C00F84000000004C8B771849BB68F679B6A07F00004D39DE0F85000000004C8B7740488DB578FFFFFF49BB904279B6A07F00004D39DE0F8500000000498B5E104881FBC07446010F850000000049BBF877CEB8A07F00004D8B334D85F60F85000000004C8B342508DF45014981FE706A49010F8500000000498B5E104881FBC07446010F85000000004C8B3425E8B35D014981FE400244010F850000000049BB683B79B6A07F00004D8B334983FE01720741813E501800000F8500000000488B1C2568915201498B5E10813BE08701000F8500000000498B5E08488D9578FFFFFF48899528FFFFFF4889B520FFFFFF4889BD18FFFFFF4C898510FFFFFF4C898D08FFFFFF4C899500FFFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B9520FFFFFF4C8950084C8B9538FFFFFF41F642040174165041524C89D74889C649C7C310734D0041FFD3415A58498942384C8B8D28FFFFFF4D894F18488985F8FEFFFF488B0425704F3D01488D5028483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7008800000048891425704F3D0148C740080300000048C74010007D440149BB303879B6A07F00004C8958184C8B9510FFFFFF4C89502048899DF0FEFFFF488985E8FEFFFF4C89B5E0FEFFFF4C89A5D8FEFFFF48C78578FFFFFF520000004889C749C7C300B2660041FFD34883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004C8DA578FFFFFF4C8BBD70FFFFFF4D896718488985D0FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700F016000048891425704F3D014C8B95E8FEFFFF4C895008488985C8FEFFFF48C78578FFFFFF53000000488BBDF0FEFFFF4889C6488B95D0FEFFFF49C7C3A0EE660041FFD34883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004989C749BB00000000000000804C21D84883F8000F8500000000488BBDF0FEFFFF4C89FE49C7C370DFB40041FFD348833C2550546B02000F85000000004883F80172068138D03903000F85000000004881F850EB44010F84000000004C8BBD38FFFFFF4D8B57484D85D20F85000000004D8B57284983FA000F85000000004C8B1425E8546D014C8B8DF8FEFFFF49C74108FDFFFFFF4C8B95D8FEFFFF4D8B4A084D8B411049BBFFFFFFFFFFFFFF7F4D39D80F8D00000000488B7810488B7018488B57104883FA110F8500000000488B57204889D14883E2014883FA000F8400000000488B4F384883F9010F8F00000000488B4F184883C101488B54CF104883FA130F85000000004889CA4883C101488B4CCF104883C2024983F8000F8E000000004883FA0B0F85000000004883F9330F850000000049BB2020C8B8A07F00004C39DF0F8500000000488DBD78FFFFFF488985C0FEFFFF4889B5B8FEFFFF4889BDB0FEFFFF4C8985A8FEFFFF4C898DA0FEFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B9508FFFFFF4C89500841F64704017412504C89FF4889C649C7C310734D0041FFD358498947384C8B9570FFFFFF4C8B8DB0FEFFFF4D894A1848898598FEFFFF488B0425704F3D01488D5048483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700685D000048891425704F3D014C8B95A8FEFFFF4C8950084C8B95B8FEFFFF4C8950104C8B95A0FEFFFF4C89504049BB2020C8B8A07F00004C89583848898590FEFFFF48C78578FFFFFF5400000048C7C7000000004889C649BBECBA5BB6A07F000041FFD34883F80174164889C748C7C60000000049C7C3709CBD0041FFD3EB08488B0425B04D5B014883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004885C00F8400000000488B8538FFFFFF4C8B78484D85FF0F85000000004C8B78284983FF000F85000000004C8B1425A0536B024983EA3E4C891425A0536B024C8B8D30FFFFFFF6400401741A41514152504889C74C89CE49C7C310734D0041FFD358415A41594C8948384C8B8598FEFFFF49C74008FDFFFFFF4983FA000F8C000000004D89FE4C898D30FFFFFF4C8BBDD8FEFFFFE905F8FFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA500FEFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4C898550FFFFFF4C898D48FFFFFF4C8B5D104D89DF4C8B5D184C899D40FFFFFF4C8B5D204D89DE4C8B5D284C899D38FFFFFF4C8B5D304C899D30FFFFFFE971F7FFFF49BB00905BB6A07F000041FFD344403430484C50543C035500000049BB00905BB6A07F000041FFD34440342930484C50543C035600000049BB00905BB6A07F000041FFD3443C24484C50543034035700000049BB00905BB6A07F000041FFD3443C2824484C50543034035800000049BB00905BB6A07F000041FFD3443C24484C50543034035900000049BB00905BB6A07F000041FFD3443C2428484C50543034035A00000049BB00905BB6A07F000041FFD3443C242028484C50543034035B00000049BB00905BB6A07F000041FFD3443C2824484C50543034035C00000049BB00905BB6A07F000041FFD3443C30484C50543428035D00000049BB00905BB6A07F000041FFD3443C2428484C50543034035E00000049BB00905BB6A07F000041FFD3443C28484C50543034035F00000049BB00905BB6A07F000041FFD3443C192128484C505430341C036000000049BB00905BB6A07F000041FFD3443C5C484C50543034286020251C036100000049BB00905BB6A07F000041FFD3443C5C1C484C505430342860202507036200000049BB00905BB6A07F000041FFD3443C5C381C484C505430342860202507036300000049BB00905BB6A07F000041FFD3443C5C1C484C505430342860202507036400000049BB00905BB6A07F000041FFD3443C5C20484C50543034281C60072507036500000049BB00905BB6A07F000041FFD3443C5C381C484C50543034280760202507036600000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036700000049BB00905BB6A07F000041FFD3443C5C0C38484C5054303428191C60202507036800000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036900000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036A00000049BB00905BB6A07F000041FFD3443C5C0C38484C5054303428191C60202507036B00000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036C00000049BB00905BB6A07F000041FFD3443C5C38484C5054303428191C60202507036D00000049BB00905BB6A07F000041FFD3443C5C0C484C505430342838191C60202507036E00000049BB00905BB6A07F000041FFD3443C5C380C484C505430342807191C60202507036F00000049BB45905BB6A07F000041FFD344405C88018001017C484C50548C01587860840170756C035200000049BB45905BB6A07F000041FFD344405C88018001017C484C50548C01587860840170756C037000000049BB45905BB6A07F000041FFD344405C940188010180017C484C50548C01587860706C75035300000049BB45905BB6A07F000041FFD344405C940188010180017C484C50548C01587860706C75037100000049BB00905BB6A07F000041FFD344405C940188013D80017C484C50548C01587860706C75037200000049BB45905BB6A07F000041FFD344405C94018801007C484C50548C01587860706C75037300000049BB00905BB6A07F000041FFD344405C94018801007C484C50548C01587860706C75037400000049BB00905BB6A07F000041FFD344405C7C484C50548C01587894010060706C75037500000049BB00905BB6A07F000041FFD344403C00287C484C50548C01587894010760706C75037600000049BB00905BB6A07F000041FFD344403C007C484C50548C01587894010760706C75037700000049BB00905BB6A07F000041FFD344403C28484C50548C015878070060700775037800000049BB00905BB6A07F000041FFD344403C0024484C5054285878070760700775037900000049BB00905BB6A07F000041FFD344403C00484C5054285878211C1924070760700775037A00000049BB00905BB6A07F000041FFD344403C0005484C5054285878211C1924070760700775037B00000049BB00905BB6A07F000041FFD344403C00484C5054285878211C1924070760700775037C00000049BB00905BB6A07F000041FFD344403C0005484C5054285878211C1924070760700775037D00000049BB00905BB6A07F000041FFD344403C000509484C5054285878211C1924070760700775037E00000049BB00905BB6A07F000041FFD344403C0005091C484C505428587821071924070760700775037F00000049BB00905BB6A07F000041FFD344403C00051C484C505428587821071924070760700775038000000049BB00905BB6A07F000041FFD344403C001C484C505428587821071924070760700775038100000049BB45905BB6A07F000041FFD344405C9801B00101AC01484C50548C0158786070035400000049BB45905BB6A07F000041FFD344405C9801B00101AC01484C50548C0158786070038200000049BB00905BB6A07F000041FFD344405C9801B001AC01484C50548C0158786070038300000049BB00905BB6A07F000041FFD34440003CAC01484C50548C0158789801B0016070038400000049BB00905BB6A07F000041FFD3444000AC01484C50548C0158789801B0016070038500000049BB00905BB6A07F000041FFD34440484C50548C0158070707070386000000 -[4cacad697d75] jit-backend-dump} -[4cacad699617] {jit-backend-addr -Loop #7 ( #44 FOR_ITER) has address 7fa0b65bbe9a to 7fa0b65bc695 (bootstrap 7fa0b65bbd77) -[4cacad69bef7] jit-backend-addr} -[4cacad69d3df] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62c6b +0 554889E5534154415541564157488DA500000000488B0425D0295C0148C70425D0295C010000000048898570FFFFFF488B0425D8295C0148C70425D8295C010000000048898568FFFFFF488B0425E0295C0148C70425E0295C010000000048898560FFFFFF488B0425E8295C0148C70425E8295C010000000048898558FFFFFF488B0425F0295C0148C70425F0295C010000000048898550FFFFFF488B0425F8295C0148C70425F8295C010000000048898548FFFFFF4C8B3C25002A5C0148C70425002A5C0100000000488B0425082A5C0148C70425082A5C010000000048898540FFFFFF4C8B3425D0B96201488B0425182A5C0148C70425182A5C010000000048898538FFFFFF488B0425202A5C0148C70425202A5C010000000048898530FFFFFF49BB88F049D6C97F00004D8B2B4983C50149BB88F049D6C97F00004D892B4C8BAD40FFFFFF4D8B65184D85E40F84000000004D8B55084D8B4C24084D39CA0F8D000000004D8B6424104F8B64D4104983C2014C8BBD70FFFFFF4D8B4F084D89550849BB2060F7D3C97F00004D39D90F85000000004D8B51104981FA60C84D010F850000000049BBE821F6D3C97F00004D8B0B4983F9017207418139184600000F85000000004D8B510849BB2861F7D3C97F00004D39DA0F85000000004D8B42104981F860C84D010F850000000049BB2825F6D3C97F00004D8B134983FA01720741813A082601000F85000000004983FC01720841813C24D00400000F85000000004D8B4A1849BB70A4F6D3C97F00004D39D90F85000000004D8B4A204D8B4108BF030000004C29C74883FF020F8F00000000498B7A404C89C64983E8014939F00F8D000000004F8B44C1104C8D8D78FFFFFF4983FE000F850000000049BB2861F7D3C97F00004C39DF0F85000000004C8B77104981FE60C84D010F850000000049BBF823F6D3C97F0000498B3B4883FF017206813F082601000F85000000004D85C00F84000000004C8B771849BBB863FAD3C97F00004D39DE0F85000000004C8B7740488DB578FFFFFF49BB2861F7D3C97F00004D39DE0F8500000000498B5E104881FB60C84D010F850000000049BBE8E245D6C97F00004D8B334D85F60F85000000004C8B342520C350014981FE60C84D010F85000000004C8B3425A81E65014981FEA0554B010F850000000049BB0823F6D3C97F00004D8B334983FE01720741813E780D00000F8500000000498B5E10813B588901000F8500000000498B5E08488D9578FFFFFF48899528FFFFFF4889B520FFFFFF4889BD18FFFFFF4C898510FFFFFF4C898D08FFFFFF4C899500FFFFFF488B0425709F4401488D5018483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700401D000048891425709F44014C8B9520FFFFFF4C8950084C8B9538FFFFFF41F642040174154152504C89D74889C641BB30BCC70041FFD358415A498942384C8B8D28FFFFFF4D894F18488985F8FEFFFF488B0425709F4401488D5028483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C7008800000048891425709F440148C740080300000048C7401020D24B0149BB8012FBD3C97F00004C8958184C8B9510FFFFFF4C895020488985F0FEFFFF4C89A5E8FEFFFF4C89B5E0FEFFFF48899DD8FEFFFF48C78578FFFFFF500000004889C741BBD0C4950041FFD34883BD78FFFFFF000F8C0000000048833C25D07E7502000F85000000004C8DBD78FFFFFF488B9D70FFFFFF4C897B18488985D0FEFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700880A000048891425709F44014C8B95F0FEFFFF4C895008488985C8FEFFFF48C78578FFFFFF51000000488BBDD8FEFFFF4889C6488B95D0FEFFFF41BBC0F5BD0041FFD34883BD78FFFFFF000F8C0000000048833C25D07E7502000F85000000004889C349BB00000000000000804C21D84883F8000F8500000000488BBDD8FEFFFF4889DE41BBD0E5BC0041FFD348833C25D07E7502000F85000000004883F80172068138383E03000F85000000004881F8303D4C010F8400000000488B9D38FFFFFF4C8B53484D85D20F85000000004C8B53284983FA000F85000000004C8B95F8FEFFFF49C74208FDFFFFFF4C8B95E8FEFFFF4D8B4A084D8B411049BBFFFFFFFFFFFFFF7F4D39D80F8D00000000488B7810488B7018488B57104883FA110F8500000000488B57204889D14883E2014883FA000F8400000000488B4F384883F9010F8F00000000488B4F184883C101488B54CF104883FA130F85000000004889CA4883C101488B4CCF104883C2024983F8000F8E000000004883FA0B0F85000000004883F9330F850000000049BB0036F7D3C97F00004C39DF0F8500000000488DBD78FFFFFF488985C0FEFFFF4889B5B8FEFFFF4889BDB0FEFFFF4C8985A8FEFFFF4C898DA0FEFFFF488B0425709F4401488D5018483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700401D000048891425709F44014C8B9508FFFFFF4C895008F64304017411504889DF4889C641BB30BCC70041FFD358488943384C8B9570FFFFFF4C8B8DB0FEFFFF4D894A1848898598FEFFFF488B0425709F4401488D5048483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C70040B0000048891425709F44014C8B95A8FEFFFF4C89500849BB0036F7D3C97F00004C8958384C8B95A0FEFFFF4C8950404C8B95B8FEFFFF4C89501048898590FEFFFF48C78578FFFFFF52000000BF000000004889C649BBE529E6D3C97F000041FFD34883F80174134889C7BE0000000041BBE049980041FFD3EB08488B042590B962014883BD78FFFFFF000F8C0000000048833C25D07E7502000F85000000004885C00F8400000000488B8538FFFFFF488B58484885DB0F8500000000488B58284883FB000F85000000004C8B1425287E75024983EA194C891425287E75024C8B8D30FFFFFFF6400401741941524151504889C74C89CE41BB30BCC70041FFD3584159415A4C8948384C8B8598FEFFFF49C74008FDFFFFFF4983FA000F8C000000004C8BBDE8FEFFFF4989DE4C898D30FFFFFFE934F8FFFF488B0425207E75024829E0483B0425802C4401760D49BB0403E6D3C97F000041FFD3554889E5534154415541564157488DA500FEFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4C898550FFFFFF4C898D48FFFFFF4C8B5D104D89DF4C8B5D184C899D40FFFFFF4C8B5D204D89DE4C8B5D284C899D38FFFFFF4C8B5D304C899D30FFFFFFE9A0F7FFFF49BB0000E6D3C97F000041FFD344403430484C50543C035300000049BB0000E6D3C97F000041FFD34440342930484C50543C035400000049BB0000E6D3C97F000041FFD3443C24484C50543034035500000049BB0000E6D3C97F000041FFD3443C2824484C50543034035600000049BB0000E6D3C97F000041FFD3443C24484C50543034035700000049BB0000E6D3C97F000041FFD3443C2428484C50543034035800000049BB0000E6D3C97F000041FFD3443C242028484C50543034035900000049BB0000E6D3C97F000041FFD3443C2824484C50543034035A00000049BB0000E6D3C97F000041FFD3443C30484C50543428035B00000049BB0000E6D3C97F000041FFD3443C2428484C50543034035C00000049BB0000E6D3C97F000041FFD3443C28484C50543034035D00000049BB0000E6D3C97F000041FFD3443C192128484C505430341C035E00000049BB0000E6D3C97F000041FFD3443C5C484C50543034286025201C035F00000049BB0000E6D3C97F000041FFD3443C5C1C484C505430342860252007036000000049BB0000E6D3C97F000041FFD3443C5C381C484C505430342860252007036100000049BB0000E6D3C97F000041FFD3443C5C1C484C505430342860252007036200000049BB0000E6D3C97F000041FFD3443C5C20484C50543034281C60250707036300000049BB0000E6D3C97F000041FFD3443C5C381C484C50543034280760252007036400000049BB0000E6D3C97F000041FFD3443C5C38484C5054303428191C60252007036500000049BB0000E6D3C97F000041FFD3443C5C0C38484C5054303428191C60252007036600000049BB0000E6D3C97F000041FFD3443C5C38484C5054303428191C60252007036700000049BB0000E6D3C97F000041FFD3443C5C484C5054303428191C60252007036800000049BB0000E6D3C97F000041FFD3443C5C38484C5054303428191C60252007036900000049BB0000E6D3C97F000041FFD3443C5C38484C5054303428191C60252007036A00000049BB0000E6D3C97F000041FFD3443C5C38484C5054303428191C60252007036B00000049BB0000E6D3C97F000041FFD3443C5C380C484C5054303428191C60252007036C00000049BB4300E6D3C97F000041FFD344405C88018C01017C484C505484015878756C60708001035000000049BB4300E6D3C97F000041FFD344405C88018C01017C484C505484015878756C60708001036D00000049BB4300E6D3C97F000041FFD344405C94018801018C017C484C5054840158786C607570035100000049BB4300E6D3C97F000041FFD344405C94018801018C017C484C5054840158786C607570036E00000049BB0000E6D3C97F000041FFD344405C940188010D8C017C484C5054840158786C607570036F00000049BB4300E6D3C97F000041FFD344405C94018801007C484C5054840158786C607570037000000049BB0000E6D3C97F000041FFD344405C94018801007C484C5054840158786C607570037100000049BB0000E6D3C97F000041FFD344405C7C484C5054840158789401006C607570037200000049BB0000E6D3C97F000041FFD344400C00287C484C5054840158789401076C607570037300000049BB0000E6D3C97F000041FFD344400C007C484C5054840158789401076C607570037400000049BB0000E6D3C97F000041FFD344400C484C505484015878070007607570037500000049BB0000E6D3C97F000041FFD344400C0024484C5054285878070707607570037600000049BB0000E6D3C97F000041FFD344400C00484C50542858781C212419070707607570037700000049BB0000E6D3C97F000041FFD344400C0005484C50542858781C212419070707607570037800000049BB0000E6D3C97F000041FFD344400C00484C50542858781C212419070707607570037900000049BB0000E6D3C97F000041FFD344400C0005484C50542858781C212419070707607570037A00000049BB0000E6D3C97F000041FFD344400C000509484C50542858781C212419070707607570037B00000049BB0000E6D3C97F000041FFD344400C0005091C484C505428587807212419070707607570037C00000049BB0000E6D3C97F000041FFD344400C00051C484C505428587807212419070707607570037D00000049BB0000E6D3C97F000041FFD344400C001C484C505428587807212419070707607570037E00000049BB4300E6D3C97F000041FFD344405C9801B00101AC01484C5054840158787060035200000049BB4300E6D3C97F000041FFD344405C9801B00101AC01484C5054840158787060037F00000049BB0000E6D3C97F000041FFD344405C9801B001AC01484C5054840158787060038000000049BB0000E6D3C97F000041FFD34440000CAC01484C505484015878B00198017060038100000049BB0000E6D3C97F000041FFD3444000AC01484C505484015878B00198017060038200000049BB0000E6D3C97F000041FFD34440484C5054840158070707070383000000 +[57f89e03a13] jit-backend-dump} +[57f89e048b3] {jit-backend-addr +Loop 7 ( #44 FOR_ITER) has address 7fc9d3e62d8e to 7fc9d3e6355a (bootstrap 7fc9d3e62c6b) +[57f89e0624f] jit-backend-addr} +[57f89e0705b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbd87 +0 00FEFFFF -[4cacad69f335] jit-backend-dump} -[4cacad6a04db] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62c7b +0 00FEFFFF +[57f89e084c3] jit-backend-dump} +[57f89e091cf] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbec8 +0 5D080000 -[4cacad6a1abf] jit-backend-dump} -[4cacad6a253f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62dbc +0 2E080000 +[57f89e0a07f] jit-backend-dump} +[57f89e0a73b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbeda +0 66080000 -[4cacad6a3a21] jit-backend-dump} -[4cacad6a43ff] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62dce +0 37080000 +[57f89e0b483] jit-backend-dump} +[57f89e0bafb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbf0a +0 52080000 -[4cacad6a583f] jit-backend-dump} -[4cacad6a6397] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62dfe +0 23080000 +[57f89e0c977] jit-backend-dump} +[57f89e0d093] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbf1b +0 5C080000 -[4cacad6a78f1] jit-backend-dump} -[4cacad6a840d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62e0f +0 2D080000 +[57f89e0deb3] jit-backend-dump} +[57f89e0e5b3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbf3b +0 58080000 -[4cacad6a997f] jit-backend-dump} -[4cacad6aa327] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62e2f +0 29080000 +[57f89e0f2f7] jit-backend-dump} +[57f89e0f91f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbf52 +0 5C080000 -[4cacad6ab73d] jit-backend-dump} -[4cacad6ac0d9] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62e46 +0 2D080000 +[57f89e105e7] jit-backend-dump} +[57f89e10c07] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbf63 +0 67080000 -[4cacad6ad4ef] jit-backend-dump} -[4cacad6ade9d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62e57 +0 38080000 +[57f89e11987] jit-backend-dump} +[57f89e121ab] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbf83 +0 64080000 -[4cacad6af3d3] jit-backend-dump} -[4cacad6afe83] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62e77 +0 35080000 +[57f89e12f43] jit-backend-dump} +[57f89e1369b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbf97 +0 6C080000 -[4cacad6b14c7] jit-backend-dump} -[4cacad6b1e63] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62e8b +0 3D080000 +[57f89e14417] jit-backend-dump} +[57f89e14a1f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbfae +0 70080000 -[4cacad6b3285] jit-backend-dump} -[4cacad6b3c1b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62ea2 +0 41080000 +[57f89e1825b] jit-backend-dump} +[57f89e18a9f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbfca +0 70080000 -[4cacad6b502b] jit-backend-dump} -[4cacad6b59e5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62ebc +0 43080000 +[57f89e198ff] jit-backend-dump} +[57f89e1a037] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbfde +0 77080000 -[4cacad6b6df5] jit-backend-dump} -[4cacad6b78d5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62ed0 +0 4A080000 +[57f89e1aeef] jit-backend-dump} +[57f89e1b5cb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bbff4 +0 7F080000 -[4cacad6b8e65] jit-backend-dump} -[4cacad6b9933] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62ee6 +0 52080000 +[57f89e1c2e7] jit-backend-dump} +[57f89e1c9f7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc007 +0 8C080000 -[4cacad6bae2d] jit-backend-dump} -[4cacad6bb7e7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62ef9 +0 5F080000 +[57f89e1d6bb] jit-backend-dump} +[57f89e1dcbf] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc018 +0 9C080000 -[4cacad6bcbf7] jit-backend-dump} -[4cacad6bd58d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62f0a +0 6F080000 +[57f89e1e95b] jit-backend-dump} +[57f89e1ef4b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc037 +0 9F080000 -[4cacad6be9a9] jit-backend-dump} -[4cacad6bf345] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62f29 +0 72080000 +[57f89e1fd6b] jit-backend-dump} +[57f89e20497] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc040 +0 B7080000 -[4cacad6c6e0f] jit-backend-dump} -[4cacad6c7d0f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62f32 +0 8A080000 +[57f89e21283] jit-backend-dump} +[57f89e218bf] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc057 +0 C2080000 -[4cacad6c9485] jit-backend-dump} -[4cacad6c9fe9] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62f49 +0 95080000 +[57f89e22583] jit-backend-dump} +[57f89e22b87] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc075 +0 C7080000 -[4cacad6cb4bf] jit-backend-dump} -[4cacad6cbebb] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62f67 +0 9A080000 +[57f89e23823] jit-backend-dump} +[57f89e23e27] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc086 +0 D9080000 -[4cacad6cd319] jit-backend-dump} -[4cacad6cdcd3] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62f78 +0 AC080000 +[57f89e24abf] jit-backend-dump} +[57f89e251cf] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc09c +0 E7080000 -[4cacad6cf10d] jit-backend-dump} -[4cacad6cfaf7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62f8e +0 BA080000 +[57f89e25f67] jit-backend-dump} +[57f89e26973] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc0b1 +0 F5080000 -[4cacad6d1177] jit-backend-dump} -[4cacad6d1c81] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62fa3 +0 EA080000 +[57f89e277d7] jit-backend-dump} +[57f89e27e17] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc0c2 +0 07090000 -[4cacad6d31bd] jit-backend-dump} -[4cacad6d3b8f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62fb8 +0 F8080000 +[57f89e28ab3] jit-backend-dump} +[57f89e290c7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc0d7 +0 16090000 -[4cacad6d4fc9] jit-backend-dump} -[4cacad6d5971] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62fd8 +0 FB080000 +[57f89e29d5f] jit-backend-dump} +[57f89e2a36b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc0f7 +0 19090000 -[4cacad6d6dab] jit-backend-dump} -[4cacad6d7aa1] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e62fe8 +0 0E090000 +[57f89e2b257] jit-backend-dump} +[57f89e2ba03] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc10f +0 48090000 -[4cacad6d90df] jit-backend-dump} -[4cacad6d9bb9] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63149 +0 D1070000 +[57f89e2c84b] jit-backend-dump} +[57f89e2ce7b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc272 +0 0A080000 -[4cacad6db179] jit-backend-dump} -[4cacad6dbcfb] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63158 +0 EB070000 +[57f89e2db17] jit-backend-dump} +[57f89e2e11b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc281 +0 24080000 -[4cacad6dd18f] jit-backend-dump} -[4cacad6ddc2d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e631f5 +0 77070000 +[57f89e2edaf] jit-backend-dump} +[57f89e2f393] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc31f +0 AF070000 -[4cacad6df061] jit-backend-dump} -[4cacad6dfa27] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63204 +0 91070000 +[57f89e30023] jit-backend-dump} +[57f89e30767] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc32e +0 C9070000 -[4cacad6e0e67] jit-backend-dump} -[4cacad6e1959] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6321e +0 A0070000 +[57f89e31617] jit-backend-dump} +[57f89e31d5b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc348 +0 D8070000 -[4cacad6e2f85] jit-backend-dump} -[4cacad6e3abf] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63240 +0 A7070000 +[57f89e35447] jit-backend-dump} +[57f89e35c47] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc36b +0 DE070000 -[4cacad6e4fdd] jit-backend-dump} -[4cacad6e59c7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63252 +0 BC070000 +[57f89e36a6b] jit-backend-dump} +[57f89e37177] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc37d +0 F3070000 -[4cacad6e6e07] jit-backend-dump} -[4cacad6e77cd] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6325f +0 D6070000 +[57f89e37e8b] jit-backend-dump} +[57f89e3849b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc38a +0 0D080000 -[4cacad6e8c19] jit-backend-dump} -[4cacad6e95f7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63273 +0 E7070000 +[57f89e392a3] jit-backend-dump} +[57f89e39abb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc39e +0 1E080000 -[4cacad6eac77] jit-backend-dump} -[4cacad6eb75d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63281 +0 00080000 +[57f89e3a8b7] jit-backend-dump} +[57f89e3b08b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc3ac +0 37080000 -[4cacad6ecc9f] jit-backend-dump} -[4cacad6ed74f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e632b2 +0 18080000 +[57f89e3bd57] jit-backend-dump} +[57f89e3c373] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc3e5 +0 48080000 -[4cacad6eeb95] jit-backend-dump} -[4cacad6ef54f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e632c8 +0 26080000 +[57f89e3d00f] jit-backend-dump} +[57f89e3d5eb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc3fb +0 56080000 -[4cacad6f0989] jit-backend-dump} -[4cacad6f1355] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e632dd +0 38080000 +[57f89e3e293] jit-backend-dump} +[57f89e3e9ab] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc410 +0 68080000 -[4cacad6f290f] jit-backend-dump} -[4cacad6f3431] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e632eb +0 52080000 +[57f89e3f823] jit-backend-dump} +[57f89e3ff53] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc41e +0 82080000 -[4cacad6f4985] jit-backend-dump} -[4cacad6f5507] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63302 +0 62080000 +[57f89e40ceb] jit-backend-dump} +[57f89e412e3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc435 +0 92080000 -[4cacad6f6941] jit-backend-dump} -[4cacad6f72f5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6331c +0 70080000 +[57f89e41f7f] jit-backend-dump} +[57f89e4257b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc44f +0 A0080000 -[4cacad6f8735] jit-backend-dump} -[4cacad6f90f5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63326 +0 8F080000 +[57f89e4320f] jit-backend-dump} +[57f89e438db] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc459 +0 BF080000 -[4cacad6fa529] jit-backend-dump} -[4cacad6fb07b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63330 +0 AF080000 +[57f89e445ff] jit-backend-dump} +[57f89e44d1b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc463 +0 DF080000 -[4cacad6fc6c5] jit-backend-dump} -[4cacad6fd175] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63343 +0 C5080000 +[57f89e45a87] jit-backend-dump} +[57f89e4607f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc476 +0 F5080000 -[4cacad6fe6e1] jit-backend-dump} -[4cacad6ff0a1] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e634af +0 81070000 +[57f89e46d1b] jit-backend-dump} +[57f89e4731f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc5e9 +0 AA070000 -[4cacad7004db] jit-backend-dump} -[4cacad704bfd] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e634be +0 98070000 +[57f89e47fb3] jit-backend-dump} +[57f89e487fb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc5f8 +0 C1070000 -[4cacad706457] jit-backend-dump} -[4cacad706fd9] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e634c7 +0 B5070000 +[57f89e49b37] jit-backend-dump} +[57f89e4a3a7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc601 +0 DE070000 -[4cacad708581] jit-backend-dump} -[4cacad709097] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e634db +0 C6070000 +[57f89e4b6db] jit-backend-dump} +[57f89e4bfdf] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc615 +0 EF070000 -[4cacad70a645] jit-backend-dump} -[4cacad70b113] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e634e9 +0 DE070000 +[57f89e4d377] jit-backend-dump} +[57f89e4dd33] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc623 +0 07080000 -[4cacad70c59b] jit-backend-dump} -[4cacad70cf55] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bc67b +0 D4070000 -[4cacad70e311] jit-backend-dump} -[4cacad70f2dd] jit-backend} -[4cacad71126f] {jit-log-opt-loop -# Loop 7 : loop with 202 ops +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63540 +0 AC070000 +[57f89e4f1cf] jit-backend-dump} +[57f89e4feaf] jit-backend} +[57f89e5168b] {jit-log-opt-loop +# Loop 7 : loop with 198 ops [p0, p1, p2, p3, p4, p5, p6, p7, i8, p9, p10] debug_merge_point(0, ' #44 FOR_ITER') +321: p11 = getfield_gc(p7, descr=) -+332: guard_nonnull(p11, descr=) [p1, p0, p7, p11, p2, p3, p4, p5, p6] ++332: guard_nonnull(p11, descr=) [p1, p0, p7, p11, p2, p3, p4, p5, p6] +341: i12 = getfield_gc(p7, descr=) +345: i13 = getfield_gc(p11, descr=) +350: i14 = int_ge(i12, i13) -guard_false(i14, descr=) [p1, p0, p7, i12, p11, p2, p3, p4, p5, p6] +guard_false(i14, descr=) [p1, p0, p7, i12, p11, p2, p3, p4, p5, p6] +359: p15 = getfield_gc(p11, descr=) +364: p16 = getarrayitem_gc(p15, i12, descr=) +369: i18 = int_add(i12, 1) @@ -1347,784 +1319,771 @@ debug_merge_point(0, ' #50 LOAD_GLOBAL') +373: p19 = getfield_gc(p0, descr=) +384: setfield_gc(p7, i18, descr=) -+388: guard_value(p19, ConstPtr(ptr20), descr=) [p1, p0, p19, p2, p3, p4, p5, p16, p7] ++388: guard_value(p19, ConstPtr(ptr20), descr=) [p1, p0, p19, p2, p3, p4, p5, p16, p7] +407: p21 = getfield_gc(p19, descr=) -+411: guard_value(p21, ConstPtr(ptr22), descr=) [p1, p0, p21, p19, p2, p3, p4, p5, p16, p7] ++411: guard_value(p21, ConstPtr(ptr22), descr=) [p1, p0, p21, p19, p2, p3, p4, p5, p16, p7] +424: p24 = getfield_gc(ConstPtr(ptr23), descr=) -+437: guard_nonnull_class(p24, 20812584, descr=) [p1, p0, p24, p2, p3, p4, p5, p16, p7] ++437: guard_nonnull_class(p24, 21293176, descr=) [p1, p0, p24, p2, p3, p4, p5, p16, p7] debug_merge_point(0, ' #53 LOOKUP_METHOD') +456: p26 = getfield_gc(p24, descr=) -+460: guard_value(p26, ConstPtr(ptr27), descr=) [p1, p0, p24, p26, p2, p3, p4, p5, p16, p7] ++460: guard_value(p26, ConstPtr(ptr27), descr=) [p1, p0, p24, p26, p2, p3, p4, p5, p16, p7] +479: p28 = getfield_gc(p26, descr=) -+483: guard_value(p28, ConstPtr(ptr29), descr=) [p1, p0, p24, p28, p26, p2, p3, p4, p5, p16, p7] ++483: guard_value(p28, ConstPtr(ptr29), descr=) [p1, p0, p24, p28, p26, p2, p3, p4, p5, p16, p7] +496: p31 = getfield_gc(ConstPtr(ptr30), descr=) -+509: guard_nonnull_class(p31, ConstClass(Function), descr=) [p1, p0, p31, p24, p2, p3, p4, p5, p16, p7] ++509: guard_nonnull_class(p31, ConstClass(Function), descr=) [p1, p0, p31, p24, p2, p3, p4, p5, p16, p7] debug_merge_point(0, ' #56 LOAD_CONST') debug_merge_point(0, ' #59 LOAD_FAST') -+528: guard_nonnull_class(p16, ConstClass(W_StringObject), descr=) [p1, p0, p16, p2, p3, p4, p5, p7, p31] ++528: guard_nonnull_class(p16, ConstClass(W_StringObject), descr=) [p1, p0, p16, p2, p3, p4, p5, p7, p31] debug_merge_point(0, ' #62 CALL_METHOD') +548: p34 = getfield_gc(p31, descr=) -+552: guard_value(p34, ConstPtr(ptr35), descr=) [p1, p0, p34, p31, p2, p3, p4, p5, p16, p7] ++552: guard_value(p34, ConstPtr(ptr35), descr=) [p1, p0, p34, p31, p2, p3, p4, p5, p16, p7] +571: p36 = getfield_gc(p31, descr=) +575: i37 = arraylen_gc(p36, descr=) +579: i39 = int_sub(3, i37) -+589: i41 = int_ge(2, i39) -guard_true(i41, descr=) [p1, p0, p31, p2, p3, p4, p5, p16, p7] -+599: p42 = getfield_gc(p31, descr=) -+603: p43 = getfield_gc(p31, descr=) -+603: i45 = int_sub(i37, 1) -+610: i46 = int_ge(i45, i37) -guard_false(i46, descr=) [p1, p0, i37, i45, p31, p2, p3, p4, p5, p16, p7, p42] -+619: p47 = getarrayitem_gc_pure(p36, i45, descr=) -+624: i48 = force_token() -+631: i49 = int_is_zero(i8) -guard_true(i49, descr=) [p1, p0, p9, p2, p3, p4, p5, p16, p7, p31, p10, p47, i48, p42] -debug_merge_point(1, ' #0 LOAD_GLOBAL') -+641: guard_value(p42, ConstPtr(ptr50), descr=) [p1, p0, p9, p42, p2, p3, p4, p5, p16, p7, p31, p10, p47, i48, None] -+660: p52 = getfield_gc(p42, descr=) -+664: guard_value(p52, ConstPtr(ptr53), descr=) [p1, p0, p9, p52, p42, p2, p3, p4, p5, p16, p7, p31, p10, p47, i48, None] -+677: p55 = getfield_gc(ConstPtr(ptr54), descr=) -+690: guard_nonnull_class(p55, ConstClass(Function), descr=) [p1, p0, p9, p55, p2, p3, p4, p5, p16, p7, p31, p10, p47, i48, None] -debug_merge_point(1, ' #3 LOAD_FAST') -debug_merge_point(1, ' #6 LOAD_FAST') -+708: guard_nonnull(p47, descr=) [p1, p0, p9, p47, p2, p3, p4, p5, p16, p7, p31, p55, p10, None, i48, None] -debug_merge_point(1, ' #9 CALL_FUNCTION') -+717: p57 = getfield_gc(p55, descr=) -+721: guard_value(p57, ConstPtr(ptr58), descr=) [p1, p0, p9, p57, p55, p2, p3, p4, p5, p16, p7, p31, None, p10, p47, i48, None] -+740: p59 = getfield_gc(p55, descr=) -+744: p60 = getfield_gc(p55, descr=) -+744: p61 = getfield_gc(p55, descr=) -+744: p62 = getfield_gc(p55, descr=) -+744: i63 = force_token() -debug_merge_point(2, ' #0 LOAD_GLOBAL') -+751: guard_value(p59, ConstPtr(ptr64), descr=) [p1, p0, p9, p59, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] -+770: p65 = getfield_gc(p59, descr=) -+774: guard_value(p65, ConstPtr(ptr66), descr=) [p1, p0, p9, p65, p59, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] -+787: p68 = getfield_gc(ConstPtr(ptr67), descr=) -+800: guard_isnull(p68, descr=) [p1, p0, p9, p68, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] -+809: p70 = getfield_gc(ConstPtr(ptr69), descr=) -+817: guard_value(p70, ConstPtr(ptr71), descr=) [p1, p0, p9, p70, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] -+830: p72 = getfield_gc(p70, descr=) -+834: guard_value(p72, ConstPtr(ptr73), descr=) [p1, p0, p9, p72, p70, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] -+847: p75 = getfield_gc(ConstPtr(ptr74), descr=) -+855: guard_value(p75, ConstPtr(ptr76), descr=) [p1, p0, p9, p75, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] -debug_merge_point(2, ' #3 LOAD_FAST') -debug_merge_point(2, ' #6 LOAD_CONST') -debug_merge_point(2, ' #9 BINARY_SUBSCR') -debug_merge_point(2, ' #10 CALL_FUNCTION') -debug_merge_point(2, ' #13 BUILD_TUPLE') -debug_merge_point(2, ' #16 LOAD_FAST') -debug_merge_point(2, ' #19 BINARY_ADD') -debug_merge_point(2, ' #20 STORE_FAST') -debug_merge_point(2, ' #23 LOAD_GLOBAL') -+868: p78 = getfield_gc(ConstPtr(ptr77), descr=) -+881: guard_nonnull_class(p78, 20802224, descr=) [p1, p0, p9, p78, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, p47, i48, None] -debug_merge_point(2, ' #26 LOOKUP_METHOD') -debug_merge_point(2, ' #29 LOAD_FAST') -debug_merge_point(2, ' #32 CALL_METHOD') -+900: p81 = getfield_gc(ConstPtr(ptr80), descr=) -+908: guard_not_invalidated(, descr=) [p1, p0, p9, p81, p2, p3, p4, p5, p16, p7, p31, p78, i63, p55, p10, p47, i48, None] -+908: p82 = getfield_gc(p78, descr=) -+912: guard_class(p82, ConstClass(ObjectDictStrategy), descr=) [p1, p0, p9, p78, p82, p2, p3, p4, p5, p16, p7, p31, None, i63, p55, p10, p47, i48, None] -+924: p84 = getfield_gc(p78, descr=) -+928: i85 = force_token() -+935: p87 = new_with_vtable(20801800) -+1040: setfield_gc(p87, i63, descr=) -setfield_gc(p9, p87, descr=) -+1091: setfield_gc(p0, i85, descr=) -+1102: p89 = new_array(3, descr=) -+1180: setarrayitem_gc(p89, 0, ConstPtr(ptr91), descr=) -+1188: setarrayitem_gc(p89, 1, ConstPtr(ptr93), descr=) -+1202: setarrayitem_gc(p89, 2, p47, descr=) -+1213: i96 = call_may_force(ConstClass(hash_tuple), p89, descr=) -guard_not_forced(, descr=) [p1, p0, p9, p78, p84, i96, p87, p2, p3, p4, p5, p16, p7, p31, p10, p89, p47, i48, p55] -+1279: guard_no_exception(, descr=) [p1, p0, p9, p78, p84, i96, p87, p2, p3, p4, p5, p16, p7, p31, p10, p89, p47, i48, p55] -+1294: i97 = force_token() -+1301: setfield_gc(p0, i97, descr=) -+1312: p99 = new_with_vtable(20801872) -+1382: setfield_gc(p99, p89, descr=) -+1393: i101 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p84, p99, i96, descr=) -guard_not_forced(, descr=) [p1, p0, p9, p99, p78, i101, p84, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] -+1452: guard_no_exception(, descr=) [p1, p0, p9, p99, p78, i101, p84, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] -+1467: i103 = int_and(i101, -9223372036854775808) -+1483: i104 = int_is_true(i103) -guard_false(i104, descr=) [p1, p0, p9, p99, p78, i101, p84, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] -+1493: p106 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p84, i101, descr=) -+1513: guard_no_exception(, descr=) [p1, p0, p9, p99, p78, p106, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] -+1528: guard_nonnull_class(p106, 21007408, descr=) [p1, p0, p9, p99, p78, p106, p87, p2, p3, p4, p5, p16, p7, p31, p10, p47, p55, i48] -debug_merge_point(2, ' #35 STORE_FAST') -debug_merge_point(2, ' #38 LOAD_FAST') -debug_merge_point(2, ' #41 LOAD_CONST') -debug_merge_point(2, ' #44 COMPARE_OP') -+1546: i109 = ptr_eq(p106, ConstPtr(ptr108)) -guard_false(i109, descr=) [p1, p0, p9, p87, p2, p3, p4, p5, p16, p7, p31, p99, p106, p10, p47, p55, i48] -debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') -debug_merge_point(2, ' #50 LOAD_FAST') -debug_merge_point(2, ' #53 RETURN_VALUE') -+1559: p110 = getfield_gc(p9, descr=) -+1570: guard_isnull(p110, descr=) [p1, p0, p9, p106, p110, p87, p2, p3, p4, p5, p16, p7, p31, p99, None, p10, p47, p55, i48] -+1579: i111 = getfield_gc(p9, descr=) -+1583: i112 = int_is_true(i111) -guard_false(i112, descr=) [p1, p0, p9, p106, p87, p2, p3, p4, p5, p16, p7, p31, p99, None, p10, p47, p55, i48] -+1593: p113 = getfield_gc(p9, descr=) -debug_merge_point(1, ' #12 LOOKUP_METHOD') -debug_merge_point(1, ' #15 LOAD_FAST') -debug_merge_point(1, ' #18 CALL_METHOD') -+1593: p115 = getfield_gc(ConstPtr(ptr114), descr=) -+1601: setfield_gc(p87, -3, descr=) -+1616: guard_not_invalidated(, descr=) [p1, p0, p9, p115, p2, p3, p4, p5, p16, p7, p31, None, p106, p10, p47, None, i48] -+1616: p117 = getfield_gc_pure(p16, descr=) -+1627: i118 = strlen(p117) -+1631: i120 = int_gt(9223372036854775807, i118) -guard_true(i120, descr=) [p1, p0, p9, p106, p117, p2, p3, p4, p5, p16, p7, p31, None, None, p10, p47, None, i48] -+1650: p121 = getfield_gc(p106, descr=) -+1654: i122 = getfield_gc(p106, descr=) -+1658: i124 = getarrayitem_gc_pure(p121, 0, descr=) -+1662: i126 = int_eq(i124, 17) -guard_true(i126, descr=) [p1, p0, p9, p106, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] -+1672: i128 = getarrayitem_gc_pure(p121, 2, descr=) -+1676: i130 = int_and(i128, 1) -+1683: i131 = int_is_true(i130) -guard_true(i131, descr=) [p1, p0, p9, p106, i128, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] -+1693: i133 = getarrayitem_gc_pure(p121, 5, descr=) -+1697: i135 = int_gt(i133, 1) -guard_false(i135, descr=) [p1, p0, p9, p106, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] -+1707: i137 = getarrayitem_gc_pure(p121, 1, descr=) -+1711: i139 = int_add(i137, 1) -+1715: i140 = getarrayitem_gc_pure(p121, i139, descr=) -+1720: i142 = int_eq(i140, 19) -guard_true(i142, descr=) [p1, p0, p9, p106, i139, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] -+1730: i144 = int_add(i139, 1) -+1737: i145 = getarrayitem_gc_pure(p121, i144, descr=) -+1742: i147 = int_add(i139, 2) -+1746: i149 = int_lt(0, i118) -guard_true(i149, descr=) [p1, p0, p9, p106, i145, i147, p2, p3, p4, p5, p16, p7, p31, i118, p121, i122, p117, None, None, p10, p47, None, i48] -+1756: guard_value(i147, 11, descr=) [p1, p0, p9, p106, i145, i147, p121, p2, p3, p4, p5, p16, p7, p31, i118, None, i122, p117, None, None, p10, p47, None, i48] -+1766: guard_value(i145, 51, descr=) [p1, p0, p9, p106, i145, p121, p2, p3, p4, p5, p16, p7, p31, i118, None, i122, p117, None, None, p10, p47, None, i48] -+1776: guard_value(p121, ConstPtr(ptr152), descr=) [p1, p0, p9, p106, p121, p2, p3, p4, p5, p16, p7, p31, i118, None, i122, p117, None, None, p10, p47, None, i48] ++587: i41 = int_ge(2, i39) +guard_true(i41, descr=) [p1, p0, p31, p2, p3, p4, p5, p16, p7] ++597: p42 = getfield_gc(p31, descr=) ++601: p43 = getfield_gc(p31, descr=) ++601: i45 = int_sub(i37, 1) ++608: i46 = int_ge(i45, i37) +guard_false(i46, descr=) [p1, p0, i37, i45, p31, p2, p3, p4, p5, p16, p7, p42] ++617: p47 = getarrayitem_gc_pure(p36, i45, descr=) ++622: i48 = force_token() ++629: i49 = int_is_zero(i8) +guard_true(i49, descr=) [p1, p0, p9, p2, p3, p4, p5, p16, p7, p31, p10, i48, p47, p42] +debug_merge_point(1, ' #0 LOAD_GLOBAL') ++639: guard_value(p42, ConstPtr(ptr50), descr=) [p1, p0, p9, p42, p2, p3, p4, p5, p16, p7, p31, p10, i48, p47, None] ++658: p52 = getfield_gc(p42, descr=) ++662: guard_value(p52, ConstPtr(ptr53), descr=) [p1, p0, p9, p52, p42, p2, p3, p4, p5, p16, p7, p31, p10, i48, p47, None] ++675: p55 = getfield_gc(ConstPtr(ptr54), descr=) ++688: guard_nonnull_class(p55, ConstClass(Function), descr=) [p1, p0, p9, p55, p2, p3, p4, p5, p16, p7, p31, p10, i48, p47, None] +debug_merge_point(1, ' #3 LOAD_FAST') +debug_merge_point(1, ' #6 LOAD_FAST') ++706: guard_nonnull(p47, descr=) [p1, p0, p9, p47, p2, p3, p4, p5, p16, p7, p31, p55, p10, i48, None, None] +debug_merge_point(1, ' #9 CALL_FUNCTION') ++715: p57 = getfield_gc(p55, descr=) ++719: guard_value(p57, ConstPtr(ptr58), descr=) [p1, p0, p9, p57, p55, p2, p3, p4, p5, p16, p7, p31, None, p10, i48, p47, None] ++738: p59 = getfield_gc(p55, descr=) ++742: p60 = getfield_gc(p55, descr=) ++742: p61 = getfield_gc(p55, descr=) ++742: p62 = getfield_gc(p55, descr=) ++742: i63 = force_token() +debug_merge_point(2, ' #0 LOAD_GLOBAL') ++749: guard_value(p59, ConstPtr(ptr64), descr=) [p1, p0, p9, p59, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, i48, p47, None] ++768: p65 = getfield_gc(p59, descr=) ++772: guard_value(p65, ConstPtr(ptr66), descr=) [p1, p0, p9, p65, p59, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, i48, p47, None] ++785: p68 = getfield_gc(ConstPtr(ptr67), descr=) ++798: guard_isnull(p68, descr=) [p1, p0, p9, p68, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, i48, p47, None] ++807: guard_not_invalidated(, descr=) [p1, p0, p9, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, i48, p47, None] ++807: p70 = getfield_gc(ConstPtr(ptr69), descr=) ++815: guard_value(p70, ConstPtr(ptr71), descr=) [p1, p0, p9, p70, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, i48, p47, None] ++828: p73 = getfield_gc(ConstPtr(ptr72), descr=) ++836: guard_value(p73, ConstPtr(ptr74), descr=) [p1, p0, p9, p73, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, i48, p47, None] +debug_merge_point(2, ' #3 LOAD_FAST') +debug_merge_point(2, ' #6 LOAD_CONST') +debug_merge_point(2, ' #9 BINARY_SUBSCR') +debug_merge_point(2, ' #10 CALL_FUNCTION') +debug_merge_point(2, ' #13 BUILD_TUPLE') +debug_merge_point(2, ' #16 LOAD_FAST') +debug_merge_point(2, ' #19 BINARY_ADD') +debug_merge_point(2, ' #20 STORE_FAST') +debug_merge_point(2, ' #23 LOAD_GLOBAL') ++849: p76 = getfield_gc(ConstPtr(ptr75), descr=) ++862: guard_nonnull_class(p76, 21278680, descr=) [p1, p0, p9, p76, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, i48, p47, None] +debug_merge_point(2, ' #26 LOOKUP_METHOD') +debug_merge_point(2, ' #29 LOAD_FAST') +debug_merge_point(2, ' #32 CALL_METHOD') ++881: p78 = getfield_gc(p76, descr=) ++885: guard_class(p78, ConstClass(ObjectDictStrategy), descr=) [p1, p0, p9, p76, p78, p2, p3, p4, p5, p16, p7, p31, i63, p55, p10, i48, p47, None] ++897: p80 = getfield_gc(p76, descr=) ++901: i81 = force_token() ++908: p83 = new_with_vtable(21282720) ++1013: setfield_gc(p83, i63, descr=) +setfield_gc(p9, p83, descr=) ++1063: setfield_gc(p0, i81, descr=) ++1074: p85 = new_array(3, descr=) ++1152: setarrayitem_gc(p85, 0, ConstPtr(ptr87), descr=) ++1160: setarrayitem_gc(p85, 1, ConstPtr(ptr89), descr=) ++1174: setarrayitem_gc(p85, 2, p47, descr=) ++1185: i92 = call_may_force(ConstClass(hash_tuple), p85, descr=) +guard_not_forced(, descr=) [p1, p0, p9, p76, p80, i92, p83, p2, p3, p4, p5, p16, p7, p31, i48, p55, p10, p47, p85] ++1250: guard_no_exception(, descr=) [p1, p0, p9, p76, p80, i92, p83, p2, p3, p4, p5, p16, p7, p31, i48, p55, p10, p47, p85] ++1265: i93 = force_token() ++1272: setfield_gc(p0, i93, descr=) ++1283: p95 = new_with_vtable(21277928) ++1353: setfield_gc(p95, p85, descr=) ++1364: i97 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p80, p95, i92, descr=) +guard_not_forced(, descr=) [p1, p0, p9, p95, p76, i97, p80, p83, p2, p3, p4, p5, p16, p7, p31, p55, p10, i48, p47] ++1422: guard_no_exception(, descr=) [p1, p0, p9, p95, p76, i97, p80, p83, p2, p3, p4, p5, p16, p7, p31, p55, p10, i48, p47] ++1437: i99 = int_and(i97, -9223372036854775808) ++1453: i100 = int_is_true(i99) +guard_false(i100, descr=) [p1, p0, p9, p95, p76, i97, p80, p83, p2, p3, p4, p5, p16, p7, p31, p55, p10, i48, p47] ++1463: p102 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p80, i97, descr=) ++1482: guard_no_exception(, descr=) [p1, p0, p9, p95, p76, p102, p83, p2, p3, p4, p5, p16, p7, p31, p55, p10, i48, p47] ++1497: guard_nonnull_class(p102, 21487768, descr=) [p1, p0, p9, p95, p76, p102, p83, p2, p3, p4, p5, p16, p7, p31, p55, p10, i48, p47] +debug_merge_point(2, ' #35 STORE_FAST') +debug_merge_point(2, ' #38 LOAD_FAST') +debug_merge_point(2, ' #41 LOAD_CONST') +debug_merge_point(2, ' #44 COMPARE_OP') ++1515: i105 = ptr_eq(p102, ConstPtr(ptr104)) +guard_false(i105, descr=) [p1, p0, p9, p83, p2, p3, p4, p5, p16, p7, p31, p95, p102, p55, p10, i48, p47] +debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') +debug_merge_point(2, ' #50 LOAD_FAST') +debug_merge_point(2, ' #53 RETURN_VALUE') ++1528: p106 = getfield_gc(p9, descr=) ++1539: guard_isnull(p106, descr=) [p1, p0, p9, p102, p106, p83, p2, p3, p4, p5, p16, p7, p31, p95, None, p55, p10, i48, p47] ++1548: i107 = getfield_gc(p9, descr=) ++1552: i108 = int_is_true(i107) +guard_false(i108, descr=) [p1, p0, p9, p102, p83, p2, p3, p4, p5, p16, p7, p31, p95, None, p55, p10, i48, p47] ++1562: p109 = getfield_gc(p9, descr=) +debug_merge_point(1, ' #12 LOOKUP_METHOD') +debug_merge_point(1, ' #15 LOAD_FAST') +debug_merge_point(1, ' #18 CALL_METHOD') ++1562: setfield_gc(p83, -3, descr=) ++1577: guard_not_invalidated(, descr=) [p1, p0, p9, p2, p3, p4, p5, p16, p7, p31, None, p102, None, p10, i48, p47] ++1577: p111 = getfield_gc_pure(p16, descr=) ++1588: i112 = strlen(p111) ++1592: i114 = int_gt(9223372036854775807, i112) +guard_true(i114, descr=) [p1, p0, p9, p102, p111, p2, p3, p4, p5, p16, p7, p31, None, None, None, p10, i48, p47] ++1611: p115 = getfield_gc(p102, descr=) ++1615: i116 = getfield_gc(p102, descr=) ++1619: i118 = getarrayitem_gc_pure(p115, 0, descr=) ++1623: i120 = int_eq(i118, 17) +guard_true(i120, descr=) [p1, p0, p9, p102, p2, p3, p4, p5, p16, p7, p31, p115, i112, p111, i116, None, None, None, p10, i48, p47] ++1633: i122 = getarrayitem_gc_pure(p115, 2, descr=) ++1637: i124 = int_and(i122, 1) ++1644: i125 = int_is_true(i124) +guard_true(i125, descr=) [p1, p0, p9, p102, i122, p2, p3, p4, p5, p16, p7, p31, p115, i112, p111, i116, None, None, None, p10, i48, p47] ++1654: i127 = getarrayitem_gc_pure(p115, 5, descr=) ++1658: i129 = int_gt(i127, 1) +guard_false(i129, descr=) [p1, p0, p9, p102, p2, p3, p4, p5, p16, p7, p31, p115, i112, p111, i116, None, None, None, p10, i48, p47] ++1668: i131 = getarrayitem_gc_pure(p115, 1, descr=) ++1672: i133 = int_add(i131, 1) ++1676: i134 = getarrayitem_gc_pure(p115, i133, descr=) ++1681: i136 = int_eq(i134, 19) +guard_true(i136, descr=) [p1, p0, p9, p102, i133, p2, p3, p4, p5, p16, p7, p31, p115, i112, p111, i116, None, None, None, p10, i48, p47] ++1691: i138 = int_add(i133, 1) ++1698: i139 = getarrayitem_gc_pure(p115, i138, descr=) ++1703: i141 = int_add(i133, 2) ++1707: i143 = int_lt(0, i112) +guard_true(i143, descr=) [p1, p0, p9, p102, i139, i141, p2, p3, p4, p5, p16, p7, p31, p115, i112, p111, i116, None, None, None, p10, i48, p47] ++1717: guard_value(i141, 11, descr=) [p1, p0, p9, p102, i139, i141, p115, p2, p3, p4, p5, p16, p7, p31, None, i112, p111, i116, None, None, None, p10, i48, p47] ++1727: guard_value(i139, 51, descr=) [p1, p0, p9, p102, i139, p115, p2, p3, p4, p5, p16, p7, p31, None, i112, p111, i116, None, None, None, p10, i48, p47] ++1737: guard_value(p115, ConstPtr(ptr146), descr=) [p1, p0, p9, p102, p115, p2, p3, p4, p5, p16, p7, p31, None, i112, p111, i116, None, None, None, p10, i48, p47] debug_merge_point(2, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') -+1795: i153 = force_token() -+1802: p154 = new_with_vtable(20801800) -+1900: setfield_gc(p154, i48, descr=) -setfield_gc(p9, p154, descr=) -+1940: setfield_gc(p0, i153, descr=) -+1958: p156 = new_with_vtable(20819912) -+2028: setfield_gc(p156, i118, descr=) -+2039: setfield_gc(p156, i122, descr=) -+2050: setfield_gc(p156, p117, descr=) -+2061: setfield_gc(p156, ConstPtr(ptr152), descr=) -+2075: i157 = call_assembler(0, p156, descr=) -guard_not_forced(, descr=) [p1, p0, p9, p106, p156, i157, p154, p2, p3, p4, p5, p16, p7, p31, p10, p47] -+2166: guard_no_exception(, descr=) [p1, p0, p9, p106, p156, i157, p154, p2, p3, p4, p5, p16, p7, p31, p10, p47] -+2181: guard_true(i157, descr=) [p1, p0, p9, p106, p156, p154, p2, p3, p4, p5, p16, p7, p31, p10, p47] -debug_merge_point(1, ' #21 RETURN_VALUE') -+2190: p158 = getfield_gc(p9, descr=) -+2201: guard_isnull(p158, descr=) [p1, p0, p9, p158, p154, p2, p3, p4, p5, p16, p7, p31, p106, p156, p10, p47] -+2210: i159 = getfield_gc(p9, descr=) -+2214: i160 = int_is_true(i159) -guard_false(i160, descr=) [p1, p0, p9, p154, p2, p3, p4, p5, p16, p7, p31, p106, p156, p10, p47] -+2224: p161 = getfield_gc(p9, descr=) ++1756: i147 = force_token() ++1763: p148 = new_with_vtable(21282720) ++1861: setfield_gc(p148, i48, descr=) +setfield_gc(p9, p148, descr=) ++1899: setfield_gc(p0, i147, descr=) ++1917: p150 = new_with_vtable(21320352) ++1987: setfield_gc(p150, i112, descr=) ++1998: setfield_gc(p150, ConstPtr(ptr146), descr=) ++2012: setfield_gc(p150, p111, descr=) ++2023: setfield_gc(p150, i116, descr=) ++2034: i151 = call_assembler(0, p150, descr=) +guard_not_forced(, descr=) [p1, p0, p9, p102, p150, i151, p148, p2, p3, p4, p5, p16, p7, p31, p47, p10] ++2120: guard_no_exception(, descr=) [p1, p0, p9, p102, p150, i151, p148, p2, p3, p4, p5, p16, p7, p31, p47, p10] ++2135: guard_true(i151, descr=) [p1, p0, p9, p102, p150, p148, p2, p3, p4, p5, p16, p7, p31, p47, p10] +debug_merge_point(1, ' #21 RETURN_VALUE') ++2144: p152 = getfield_gc(p9, descr=) ++2155: guard_isnull(p152, descr=) [p1, p0, p9, p152, p148, p2, p3, p4, p5, p16, p7, p31, p150, p102, p47, p10] ++2164: i153 = getfield_gc(p9, descr=) ++2168: i154 = int_is_true(i153) +guard_false(i154, descr=) [p1, p0, p9, p148, p2, p3, p4, p5, p16, p7, p31, p150, p102, p47, p10] ++2178: p155 = getfield_gc(p9, descr=) debug_merge_point(0, ' #65 POP_TOP') debug_merge_point(0, ' #66 JUMP_ABSOLUTE') -+2224: i163 = getfield_raw(40588192, descr=) -+2232: i165 = int_sub(i163, 62) -+2236: setfield_raw(40588192, i165, descr=) ++2178: i157 = getfield_raw(41254440, descr=) ++2186: i159 = int_sub(i157, 25) ++2190: setfield_raw(41254440, i159, descr=) setfield_gc(p9, p10, descr=) -+2287: setfield_gc(p154, -3, descr=) -+2302: i168 = int_lt(i165, 0) -guard_false(i168, descr=) [p1, p0, p2, p3, p4, p5, p16, p7, None, None, None, None] ++2240: setfield_gc(p148, -3, descr=) ++2255: i162 = int_lt(i159, 0) +guard_false(i162, descr=) [p1, p0, p2, p3, p4, p5, p16, p7, None, None, None, None] debug_merge_point(0, ' #44 FOR_ITER') -+2312: jump(p0, p1, p2, p3, p4, p5, p16, p7, i159, p9, p10, descr=) -+2334: --end of the loop-- -[4cacad8c060f] jit-log-opt-loop} -[4cacad8cacbf] {jit-backend -[4cacae25aaeb] {jit-backend-dump ++2265: jump(p0, p1, p2, p3, p4, p5, p16, p7, i153, p9, p10, descr=) ++2287: --end of the loop-- +[57f89f76b07] jit-log-opt-loop} +[57f89f7da73] {jit-backend +[57f8a0ec83b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd011 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C2540100000000488B0C25E8C2540148C70425E8C2540100000000488B0425F0C2540148C70425F0C254010000000048898570FFFFFF488B0425F8C2540148C70425F8C254010000000048898568FFFFFF488B042500C3540148C7042500C354010000000048898560FFFFFF488B042508C3540148C7042508C354010000000048898558FFFFFF49BB90A0CFB8A07F0000498B034883C00149BB90A0CFB8A07F00004989034983F8040F85000000008139B82F00000F8500000000488B79184885FF0F84000000004C8B4108488B47084939C00F8D00000000488B7F104A8B7CC7104983C0014C8941084983FA000F850000000049BBF8F477B6A07F00004D39DC0F85000000004D8B670849BBA0217CB6A07F00004D39DC0F8500000000498B5424104881FAC07446010F850000000049BB683A79B6A07F00004D8B234983FC01720841813C24C84000000F8500000000498B54240849BB904279B6A07F00004C39DA0F85000000004C8B52104981FAC07446010F850000000049BB883D79B6A07F0000498B134883FA017206813A082601000F85000000004883FF017206813FD00400000F85000000004C8B621849BB20F777B6A07F00004D39DC0F85000000004C8B62204D8B54240849C7C0030000004D29D04983F8020F8F000000004C8B42404C89D04983EA014939C20F8D000000004F8B54D4104889BD50FFFFFF48899548FFFFFF4C898540FFFFFF48898D38FFFFFF4C898D30FFFFFF4C899528FFFFFF4889B520FFFFFF49C7C3B0A0500041FFD3488B70384C8D9578FFFFFF4C8B48484D85C90F85000000004C8B48284983F9000F85000000004C8B8D40FFFFFF49BB904279B6A07F00004D39D90F8500000000498B49104881F9C07446010F850000000049BB583C79B6A07F00004D8B0B4983F9017207418139082601000F8500000000488B8D28FFFFFF4885C90F84000000004D8B411849BB68F679B6A07F00004D39D80F85000000004D8B4140498B5128498B792048833C2550546B02000F8500000000488DBD78FFFFFF49BB904279B6A07F00004D39D80F8500000000498B50104881FAC07446010F850000000049BBF877CEB8A07F00004D8B034D85C00F85000000004C8B042508DF45014981F8706A49010F8500000000498B50104881FAC07446010F85000000004C8B0425E8B35D014981F8400244010F850000000049BB683B79B6A07F00004D8B034983F8017207418138501800000F8500000000488B142568915201498B5010813AE08701000F8500000000498B50084C8DA578FFFFFF48898518FFFFFF48899510FFFFFF4889B508FFFFFF4889BD00FFFFFF4C8985F8FEFFFF4C898DF0FEFFFF4C8995E8FEFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B9500FFFFFF4C8950084C8B9518FFFFFF41F642040174165041524C89D74889C649C7C310734D0041FFD3415A58498942384D896718488985E0FEFFFF488B0425704F3D01488D5028483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C7008800000048891425704F3D0148C740080300000048C74010007D440149BB303879B6A07F00004C8958184C8B9528FFFFFF4C8950204C89BDD8FEFFFF488985D0FEFFFF48899DC8FEFFFF4C89B5C0FEFFFF4C89ADB8FEFFFF48C78578FFFFFF870000004889C749C7C300B2660041FFD34883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004C8DAD78FFFFFF4C8BB5D8FEFFFF4D896E18488985B0FEFFFF488B0425704F3D01488D5010483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700F016000048891425704F3D014C8B95D0FEFFFF4C895008488985A8FEFFFF48C78578FFFFFF88000000488BBD10FFFFFF4889C6488B95B0FEFFFF49C7C3A0EE660041FFD34883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004989C649BB00000000000000804C21D84883F8000F8500000000488BBD10FFFFFF4C89F649C7C370DFB40041FFD348833C2550546B02000F85000000004883F80172068138D03903000F85000000004881F850EB44010F84000000004C8BB518FFFFFF4D8B56484D85D20F85000000004D8B56284983FA000F85000000004C8B1425E8546D014C8B8DE0FEFFFF49C74108FDFFFFFF4C8B9550FFFFFF4D8B4A084D8B411049BBFFFFFFFFFFFFFF7F4D39D80F8D00000000488B7810488B7018488B57104883FA110F8500000000488B57204889D14883E2014883FA000F8400000000488B4F384883F9010F8F00000000488B4F184883C101488B54CF104883FA130F85000000004889CA4883C101488B4CCF104883C2024983F8000F8E000000004883FA0B0F85000000004883F9330F850000000049BB2020C8B8A07F00004C39DF0F8500000000488DBD78FFFFFF488985A0FEFFFF4889B598FEFFFF4889BD90FEFFFF4C898588FEFFFF4C898D80FEFFFF488B0425704F3D01488D5018483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700A816000048891425704F3D014C8B95E8FEFFFF4C89500841F64604017412504C89F74889C649C7C310734D0041FFD358498946384C8B95D8FEFFFF4C8B8D90FEFFFF4D894A1848898578FEFFFF488B0425704F3D01488D5048483B1425784F3D01761A49BB10925BB6A07F000041FFD349BB8E925BB6A07F000041FFD348C700685D000048891425704F3D014C8B9588FEFFFF4C8950084C8B9598FEFFFF4C8950104C8B9580FEFFFF4C89504049BB2020C8B8A07F00004C89583848898570FEFFFF48C78578FFFFFF8900000048C7C7000000004889C649BBECBA5BB6A07F000041FFD34883F80174164889C748C7C60000000049C7C3709CBD0041FFD3EB08488B0425B04D5B014883BD78FFFFFF000F8C0000000048833C2550546B02000F85000000004885C00F8400000000488B8518FFFFFF4C8B70484D85F60F85000000004C8B70284983FE000F85000000004C8B1425A0536B024983EA3E4C891425A0536B024C8B8D08FFFFFFF6400401741A41524151504889C74C89CE49C7C310734D0041FFD3584159415A4C8948384C8B8578FEFFFF49C74008FDFFFFFF4983FA000F8C00000000488B85D8FEFFFF48898570FFFFFF488B85C0FEFFFF48898568FFFFFF488B85B8FEFFFF48898560FFFFFF488B8530FFFFFF48898558FFFFFF488B85C8FEFFFF48898548FFFFFF4C8BBD50FFFFFF488B8538FFFFFF48898540FFFFFF488B8518FFFFFF48898538FFFFFF4C898D30FFFFFF488B8520FFFFFF48898550FFFFFF49BB9ABE5BB6A07F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05935BB6A07F000041FFD3554889E5534154415541564157488DA5E0FDFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D94C8B5D404C899D70FFFFFF4C8B5D484C899D68FFFFFF4C8B5D504C899D60FFFFFF4C8B5D584C899D58FFFFFFE94FF6FFFF49BB00905BB6A07F000041FFD321383C343029241D180C08044044484C038A00000049BB00905BB6A07F000041FFD3383C0434302924180C084044484C038B00000049BB00905BB6A07F000041FFD3383C041C34302924180C084044484C038C00000049BB00905BB6A07F000041FFD3383C04211C34302924180C084044484C038D00000049BB00905BB6A07F000041FFD329383C343024180C08041C44484C038E00000049BB00905BB6A07F000041FFD3383C303424180C1C0444484C038F00000049BB00905BB6A07F000041FFD3383C303424180C1C0444484C039000000049BB00905BB6A07F000041FFD3383C08303424180C1C0444484C039100000049BB00905BB6A07F000041FFD3383C303424180C1C0444484C039200000049BB00905BB6A07F000041FFD3383C30083424180C1C0444484C039300000049BB00905BB6A07F000041FFD3383C3028083424180C1C0444484C039400000049BB00905BB6A07F000041FFD3383C08303424180C1C0444484C039500000049BB00905BB6A07F000041FFD3383C1C3424180C04084C039600000049BB00905BB6A07F000041FFD3383C30083424180C1C04039700000049BB00905BB6A07F000041FFD3383C083424180C1C04039800000049BB00905BB6A07F000041FFD3383C0129083424180C1C0420039900000049BB00905BB6A07F000041FFD3383C00243460680C505C5464182958039A00000049BB00905BB6A07F000041FFD3383C003460680C505C5464182958039B00000049BB00905BB6A07F000041FFD3383C00243460680C505C5464182907039C00000049BB00905BB6A07F000041FFD3383C0004243460680C505C5464182907039D00000049BB00905BB6A07F000041FFD3383C00243460680C505C5464182907039E00000049BB00905BB6A07F000041FFD3383C00043460680C505C542407182907039F00000049BB00905BB6A07F000041FFD3383C0020243460680C505C54070418290703A000000049BB45905BB6A07F000041FFD3383C00081C3460680C505C5420240418290703A100000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A200000049BB00905BB6A07F000041FFD3383C0008203460680C505C541D07240418290703A300000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A400000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A500000049BB00905BB6A07F000041FFD3383C0008203460680C505C541D07240418290703A600000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A700000049BB00905BB6A07F000041FFD3383C00203460680C505C541D07240418290703A800000049BB00905BB6A07F000041FFD3383C00083460680C505C54201D07240418290703A900000049BB00905BB6A07F000041FFD3383C0020083460680C505C54071D07240418290703AA00000049BB45905BB6A07F000041FFD398018C016C7C700188019C0160689401505C546474800185019001038700000049BB45905BB6A07F000041FFD398018C016C7C700188019C0160689401505C54647480018501900103AB00000049BB45905BB6A07F000041FFD398018C016CA4017C017088019C0160689401505C54800164748501038800000049BB45905BB6A07F000041FFD398018C016CA4017C017088019C0160689401505C5480016474850103AC00000049BB00905BB6A07F000041FFD398018C016CA4017C397088019C0160689401505C5480016474850103AD00000049BB45905BB6A07F000041FFD398018C016CA4017C0088019C0160689401505C5480016474850103AE00000049BB00905BB6A07F000041FFD398018C016CA4017C0088019C0160689401505C5480016474850103AF00000049BB00905BB6A07F000041FFD398018C016C88019C0160689401505C5400A40180016474850103B000000049BB00905BB6A07F000041FFD398018C0138002888019C0160689401505C5407A40180016474850103B100000049BB00905BB6A07F000041FFD398018C01380088019C0160689401505C5407A40180016474850103B200000049BB00905BB6A07F000041FFD398018C0138289C0160689401505C540007076474850103B300000049BB00905BB6A07F000041FFD398018C013800249C0160689401285C540707076474850103B400000049BB00905BB6A07F000041FFD398018C0138009C0160689401285C541924211C0707076474850103B500000049BB00905BB6A07F000041FFD398018C013800059C0160689401285C541924211C0707076474850103B600000049BB00905BB6A07F000041FFD398018C0138009C0160689401285C541924211C0707076474850103B700000049BB00905BB6A07F000041FFD398018C013800059C0160689401285C541924211C0707076474850103B800000049BB00905BB6A07F000041FFD398018C01380005099C0160689401285C541924211C0707076474850103B900000049BB00905BB6A07F000041FFD398018C01380005091C9C0160689401285C54192421070707076474850103BA00000049BB00905BB6A07F000041FFD398018C013800051C9C0160689401285C54192421070707076474850103BB00000049BB00905BB6A07F000041FFD398018C0138001C9C0160689401285C54192421070707076474850103BC00000049BB45905BB6A07F000041FFD398018C016CA801C00101BC019C0160689401505C546474038900000049BB45905BB6A07F000041FFD398018C016CA801C00101BC019C0160689401505C54647403BD00000049BB00905BB6A07F000041FFD398018C016CA801C001BC019C0160689401505C54647403BE00000049BB00905BB6A07F000041FFD398018C010038BC019C0160689401505C54A801C001647403BF00000049BB00905BB6A07F000041FFD398018C0100BC019C0160689401505C54A801C001647403C000000049BB00905BB6A07F000041FFD398018C019C0160689401505C0707070703C1000000 -[4cacae2c324b] jit-backend-dump} -[4cacae2c5693] {jit-backend-addr -Loop #8 ( #44 FOR_ITER) has address 7fa0b65bd15d to 7fa0b65bda6e (bootstrap 7fa0b65bd011) -[4cacae2c8c1b] jit-backend-addr} -[4cacae2c9d55] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63eae +0 554889E5534154415541564157488DA5000000004C8B3C25D0295C0148C70425D0295C01000000004C8B3425D8295C0148C70425D8295C01000000004C8B2C25E0295C0148C70425E0295C01000000004C8B2425E8295C0148C70425E8295C01000000004C8B1425B0B962014C8B0C25F8295C0148C70425F8295C01000000004C8B0425C0B96201488B3C25C8B96201488B3425102A5C0148C70425102A5C0100000000488B1C25182A5C0148C70425182A5C0100000000488B1425202A5C0148C70425202A5C0100000000488B0C25282A5C0148C70425282A5C0100000000488B0425302A5C0148C70425302A5C010000000048898570FFFFFF488B0425382A5C0148C70425382A5C010000000048898568FFFFFF488B0425402A5C0148C70425402A5C010000000048898560FFFFFF488B0425482A5C0148C70425482A5C010000000048898558FFFFFF49BB90F049D6C97F0000498B034883C00149BB90F049D6C97F00004989034983F8040F85000000008139083200000F8500000000488B79184885FF0F84000000004C8B4108488B47084939C00F8D00000000488B7F104A8B7CC7104983C0014C8941084983FA000F850000000049BB287CFAD3C97F00004D39DC0F85000000004D8B670849BB2060F7D3C97F00004D39DC0F8500000000498B5424104881FA60C84D010F850000000049BBE821F6D3C97F00004D8B234983FC01720841813C24184600000F8500000000498B54240849BB2861F7D3C97F00004C39DA0F85000000004C8B52104981FA60C84D010F850000000049BB2825F6D3C97F0000498B134883FA017206813A082601000F85000000004883FF017206813FD00400000F85000000004C8B621849BB70A4F6D3C97F00004D39DC0F85000000004C8B62204D8B54240841B8030000004D29D04983F8020F8F000000004C8B42404C89D04983EA014939C20F8D000000004F8B54D4104889BD50FFFFFF4C898548FFFFFF48898D40FFFFFF4C899538FFFFFF48899530FFFFFF4889B528FFFFFF4C898D20FFFFFF41BBD07D890041FFD34C8B4838488DB578FFFFFF488B50484885D20F8500000000488B50284883FA000F8500000000488B9548FFFFFF49BB2861F7D3C97F00004C39DA0F85000000004C8B52104981FA60C84D010F850000000049BBF823F6D3C97F0000498B134883FA017206813A082601000F85000000004C8B9538FFFFFF4D85D20F8400000000488B4A1849BBB863FAD3C97F00004C39D90F8500000000488B4A404C8B4228488B7A2048833C25D07E7502000F8500000000488DBD78FFFFFF49BB2861F7D3C97F00004C39D90F85000000004C8B41104981F860C84D010F850000000049BBE8E245D6C97F0000498B0B4885C90F8500000000488B0C2520C350014881F960C84D010F8500000000488B0C25A81E65014881F9A0554B010F850000000049BB0823F6D3C97F0000498B0B4883F90172068139780D00000F85000000004C8B4110418138588901000F85000000004C8B41084C8DA578FFFFFF48898518FFFFFF48898D10FFFFFF48899508FFFFFF4889B500FFFFFF4889BDF8FEFFFF4C8985F0FEFFFF4C898DE8FEFFFF488B0425709F4401488D5018483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700401D000048891425709F44014C8B95F8FEFFFF4C8950084C8B9518FFFFFF41F642040174154152504C89D74889C641BB30BCC70041FFD358415A498942384D896718488985E0FEFFFF488B0425709F4401488D5028483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C7008800000048891425709F440148C740080300000048C7401020D24B0149BB8012FBD3C97F00004C8958184C8B9538FFFFFF4C8950204C89BDD8FEFFFF488985D0FEFFFF48899DC8FEFFFF4C89B5C0FEFFFF4C89ADB8FEFFFF48C78578FFFFFF840000004889C741BBD0C4950041FFD34883BD78FFFFFF000F8C0000000048833C25D07E7502000F85000000004C8DAD78FFFFFF4C8BB5D8FEFFFF4D896E18488985B0FEFFFF488B0425709F4401488D5010483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700880A000048891425709F44014C8B95D0FEFFFF4C895008488985A8FEFFFF48C78578FFFFFF85000000488BBDF0FEFFFF4889C6488B95B0FEFFFF41BBC0F5BD0041FFD34883BD78FFFFFF000F8C0000000048833C25D07E7502000F85000000004989C649BB00000000000000804C21D84883F8000F8500000000488BBDF0FEFFFF4C89F641BBD0E5BC0041FFD348833C25D07E7502000F85000000004883F80172068138383E03000F85000000004881F8303D4C010F84000000004C8BB518FFFFFF4D8B56484D85D20F85000000004D8B56284983FA000F85000000004C8B95E0FEFFFF49C74208FDFFFFFF4C8B9550FFFFFF4D8B4A084D8B411049BBFFFFFFFFFFFFFF7F4D39D80F8D00000000488B7810488B7018488B57104883FA110F8500000000488B57204889D14883E2014883FA000F8400000000488B4F384883F9010F8F00000000488B4F184883C101488B54CF104883FA130F85000000004889CA4883C101488B4CCF104883C2024983F8000F8E000000004883FA0B0F85000000004883F9330F850000000049BB0036F7D3C97F00004C39DF0F8500000000488DBD78FFFFFF488985A0FEFFFF4889B598FEFFFF4889BD90FEFFFF4C898588FEFFFF4C898D80FEFFFF488B0425709F4401488D5018483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C700401D000048891425709F44014C8B9500FFFFFF4C89500841F64604017411504C89F74889C641BB30BCC70041FFD358498946384C8B95D8FEFFFF4C8B8D90FEFFFF4D894A1848898578FEFFFF488B0425709F4401488D5048483B1425789F4401761A49BB1002E6D3C97F000041FFD349BB8D02E6D3C97F000041FFD348C70040B0000048891425709F44014C8B9588FEFFFF4C89500849BB0036F7D3C97F00004C8958384C8B9580FEFFFF4C8950404C8B9598FEFFFF4C89501048898570FEFFFF48C78578FFFFFF86000000BF000000004889C649BBE529E6D3C97F000041FFD34883F80174134889C7BE0000000041BBE049980041FFD3EB08488B042590B962014883BD78FFFFFF000F8C0000000048833C25D07E7502000F85000000004885C00F8400000000488B8518FFFFFF4C8B70484D85F60F85000000004C8B70284983FE000F85000000004C8B1425287E75024983EA194C891425287E75024C8B8DE8FEFFFFF6400401741941514152504889C74C89CE41BB30BCC70041FFD358415A41594C8948384C8B8578FEFFFF49C74008FDFFFFFF4983FA000F8C00000000488B85D8FEFFFF48898570FFFFFF488B85C0FEFFFF48898568FFFFFF488B85B8FEFFFF48898560FFFFFF488B8520FFFFFF48898558FFFFFF488B85C8FEFFFF48898548FFFFFF4C8BBD50FFFFFF488B8518FFFFFF48898538FFFFFF4C898D30FFFFFF488B8528FFFFFF48898550FFFFFF49BB8E2DE6D3C97F000041FFE3488B0425207E75024829E0483B0425802C4401760D49BB0403E6D3C97F000041FFD3554889E5534154415541564157488DA5E0FDFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DA4C8B5D384C89D94C8B5D404C899D70FFFFFF4C8B5D484C899D68FFFFFF4C8B5D504C899D60FFFFFF4C8B5D584C899D58FFFFFFE98CF6FFFF49BB0000E6D3C97F000041FFD321383C343029241D180C08044044484C038700000049BB0000E6D3C97F000041FFD3383C0434302924180C084044484C038800000049BB0000E6D3C97F000041FFD3383C041C34302924180C084044484C038900000049BB0000E6D3C97F000041FFD3383C04211C34302924180C084044484C038A00000049BB0000E6D3C97F000041FFD329383C343024180C08041C44484C038B00000049BB0000E6D3C97F000041FFD3383C303424180C1C0444484C038C00000049BB0000E6D3C97F000041FFD3383C303424180C1C0444484C038D00000049BB0000E6D3C97F000041FFD3383C08303424180C1C0444484C038E00000049BB0000E6D3C97F000041FFD3383C303424180C1C0444484C038F00000049BB0000E6D3C97F000041FFD3383C30083424180C1C0444484C039000000049BB0000E6D3C97F000041FFD3383C3028083424180C1C0444484C039100000049BB0000E6D3C97F000041FFD3383C08303424180C1C0444484C039200000049BB0000E6D3C97F000041FFD3383C1C3424180C04084C039300000049BB0000E6D3C97F000041FFD3383C30083424180C1C04039400000049BB0000E6D3C97F000041FFD3383C083424180C1C04039500000049BB0000E6D3C97F000041FFD3383C0129083424180C1C0420039600000049BB0000E6D3C97F000041FFD3383C00083468640C50586019245C54039700000049BB0000E6D3C97F000041FFD3383C003468640C50586019245C54039800000049BB0000E6D3C97F000041FFD3383C00083468640C50586019245C07039900000049BB0000E6D3C97F000041FFD3383C0028083468640C50586019245C07039A00000049BB0000E6D3C97F000041FFD3383C00083468640C50586019245C07039B00000049BB0000E6D3C97F000041FFD3383C00283468640C5058600819240707039C00000049BB0000E6D3C97F000041FFD3383C0004083468640C5058600719242807039D00000049BB4300E6D3C97F000041FFD3383C00201C3468640C505860040819242807039E00000049BB0000E6D3C97F000041FFD3383C00043468640C5058601D070819242807039F00000049BB0000E6D3C97F000041FFD3383C0020043468640C5058601D07081924280703A000000049BB0000E6D3C97F000041FFD3383C00043468640C5058601D07081924280703A100000049BB0000E6D3C97F000041FFD3383C003468640C5058601D07081924280703A200000049BB0000E6D3C97F000041FFD3383C00043468640C5058601D07081924280703A300000049BB0000E6D3C97F000041FFD3383C00043468640C5058601D07081924280703A400000049BB0000E6D3C97F000041FFD3383C00043468640C5058601D07081924280703A500000049BB0000E6D3C97F000041FFD3383C0004203468640C5058601D07081924280703A600000049BB4300E6D3C97F000041FFD398018C016C7080010188019C0168649401505860795C9001840174038400000049BB4300E6D3C97F000041FFD398018C016C7080010188019C0168649401505860795C900184017403A700000049BB4300E6D3C97F000041FFD398018C016CA4017001800188019C0168649401505860795C840174038500000049BB4300E6D3C97F000041FFD398018C016CA4017001800188019C0168649401505860795C84017403A800000049BB0000E6D3C97F000041FFD398018C016CA4017039800188019C0168649401505860795C84017403A900000049BB4300E6D3C97F000041FFD398018C016CA401700088019C0168649401505860795C84017403AA00000049BB0000E6D3C97F000041FFD398018C016CA401700088019C0168649401505860795C84017403AB00000049BB0000E6D3C97F000041FFD398018C016C88019C0168649401505860A40100795C84017403AC00000049BB0000E6D3C97F000041FFD398018C0138002888019C0168649401505860A40107795C84017403AD00000049BB0000E6D3C97F000041FFD398018C01380088019C0168649401505860A40107795C84017403AE00000049BB0000E6D3C97F000041FFD398018C01389C01686494015058600700795C84010703AF00000049BB0000E6D3C97F000041FFD398018C013800249C01686494012858600707795C84010703B000000049BB0000E6D3C97F000041FFD398018C0138009C016864940128586024211C190707795C84010703B100000049BB0000E6D3C97F000041FFD398018C013800059C016864940128586024211C190707795C84010703B200000049BB0000E6D3C97F000041FFD398018C0138009C016864940128586024211C190707795C84010703B300000049BB0000E6D3C97F000041FFD398018C013800059C016864940128586024211C190707795C84010703B400000049BB0000E6D3C97F000041FFD398018C01380005099C016864940128586024211C190707795C84010703B500000049BB0000E6D3C97F000041FFD398018C01380005091C9C0168649401285860242107190707795C84010703B600000049BB0000E6D3C97F000041FFD398018C013800051C9C0168649401285860242107190707795C84010703B700000049BB0000E6D3C97F000041FFD398018C0138001C9C0168649401285860242107190707795C84010703B800000049BB4300E6D3C97F000041FFD398018C016CA801C00101BC019C01686494015058605C8401038600000049BB4300E6D3C97F000041FFD398018C016CA801C00101BC019C01686494015058605C840103B900000049BB0000E6D3C97F000041FFD398018C016CA801C001BC019C01686494015058605C840103BA00000049BB0000E6D3C97F000041FFD398018C010038BC019C0168649401505860A801C0015C840103BB00000049BB0000E6D3C97F000041FFD398018C0100BC019C0168649401505860A801C0015C840103BC00000049BB0000E6D3C97F000041FFD398018C019C016864940150580707070703BD000000 +[57f8a11b2af] jit-backend-dump} +[57f8a11c06b] {jit-backend-addr +Loop 8 ( #44 FOR_ITER) has address 7fc9d3e63ffa to 7fc9d3e648ce (bootstrap 7fc9d3e63eae) +[57f8a11d3e7] jit-backend-addr} +[57f8a11dc9b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd021 +0 E0FDFFFF -[4cacae2cbda1] jit-backend-dump} -[4cacae2ccecf] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e63ebe +0 E0FDFFFF +[57f8a11ef3f] jit-backend-dump} +[57f8a11f7a7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd181 +0 89090000 -[4cacae2ce4ef] jit-backend-dump} -[4cacae2cef93] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6401e +0 4C090000 +[57f8a120747] jit-backend-dump} +[57f8a120ed3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd18d +0 9F090000 -[4cacae2d0439] jit-backend-dump} -[4cacae2d0e83] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6402a +0 62090000 +[57f8a121d0b] jit-backend-dump} +[57f8a122523] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd19a +0 B2090000 -[4cacae2d239b] jit-backend-dump} -[4cacae2d2e87] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64037 +0 75090000 +[57f8a1232a3] jit-backend-dump} +[57f8a1238ab] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd1ab +0 C2090000 -[4cacae2d4399] jit-backend-dump} -[4cacae2d4e79] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64048 +0 85090000 +[57f8a124583] jit-backend-dump} +[57f8a124bc7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd1c6 +0 C9090000 -[4cacae2d624d] jit-backend-dump} -[4cacae2d6bfb] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64063 +0 8C090000 +[57f8a12585f] jit-backend-dump} +[57f8a125e7f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd1d9 +0 D6090000 -[4cacae2d7fd5] jit-backend-dump} -[4cacae2d898f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64076 +0 99090000 +[57f8a126d7b] jit-backend-dump} +[57f8a12749b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd1f0 +0 DD090000 -[4cacae2d9d6f] jit-backend-dump} -[4cacae2da8b5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6408d +0 A0090000 +[57f8a1281d3] jit-backend-dump} +[57f8a1287f3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd202 +0 E9090000 -[4cacae2dbe15] jit-backend-dump} -[4cacae2dc8e3] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6409f +0 AC090000 +[57f8a12948f] jit-backend-dump} +[57f8a129a6f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd223 +0 E7090000 -[4cacae2dddb3] jit-backend-dump} -[4cacae2ea8f3] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e640c0 +0 AA090000 +[57f8a12dc37] jit-backend-dump} +[57f8a12e4a7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd23b +0 ED090000 -[4cacae2ecff3] jit-backend-dump} -[4cacae2edd07] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e640d8 +0 B0090000 +[57f8a12f2bf] jit-backend-dump} +[57f8a12faef] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd24c +0 FB090000 -[4cacae2efaef] jit-backend-dump} -[4cacae2f0ba5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e640e9 +0 BE090000 +[57f8a1309ab] jit-backend-dump} +[57f8a131097] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd26b +0 FC090000 -[4cacae2f2615] jit-backend-dump} -[4cacae2f330b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64108 +0 BF090000 +[57f8a131d47] jit-backend-dump} +[57f8a13236b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd27d +0 090A0000 -[4cacae2f4d57] jit-backend-dump} -[4cacae2f5957] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6411a +0 CC090000 +[57f8a13300f] jit-backend-dump} +[57f8a133617] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd294 +0 0E0A0000 -[4cacae2f7499] jit-backend-dump} -[4cacae2f810b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64131 +0 D1090000 +[57f8a1342bb] jit-backend-dump} +[57f8a1348e7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd2b1 +0 0D0A0000 -[4cacae2f9bcf] jit-backend-dump} -[4cacae2fa9eb] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6414d +0 D1090000 +[57f8a1356bb] jit-backend-dump} +[57f8a135deb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd2c5 +0 140A0000 -[4cacae2fc449] jit-backend-dump} -[4cacae2fd0c7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64161 +0 D8090000 +[57f8a136bb3] jit-backend-dump} +[57f8a13728b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd31d +0 DA090000 -[4cacae2fecf3] jit-backend-dump} -[4cacae2ffc4d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e641b8 +0 9F090000 +[57f8a137fe3] jit-backend-dump} +[57f8a1385cb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd32b +0 ED090000 -[4cacae301b73] jit-backend-dump} -[4cacae30284b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e641c6 +0 B2090000 +[57f8a139267] jit-backend-dump} +[57f8a13987f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd345 +0 F3090000 -[4cacae304585] jit-backend-dump} -[4cacae305743] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e641e0 +0 B8090000 +[57f8a13a60f] jit-backend-dump} +[57f8a13acfb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd356 +0 030A0000 -[4cacae307981] jit-backend-dump} -[4cacae308a25] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e641f1 +0 C8090000 +[57f8a13ba2b] jit-backend-dump} +[57f8a13c1ab] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd376 +0 050A0000 -[4cacae30ac27] jit-backend-dump} -[4cacae30be7b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64210 +0 CB090000 +[57f8a13ce4b] jit-backend-dump} +[57f8a13d453] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd386 +0 160A0000 -[4cacae30e3f5] jit-backend-dump} -[4cacae30f16f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64220 +0 DC090000 +[57f8a13e0eb] jit-backend-dump} +[57f8a13e757] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd39d +0 210A0000 -[4cacae3105e5] jit-backend-dump} -[4cacae311071] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64237 +0 E7090000 +[57f8a13f423] jit-backend-dump} +[57f8a13fb4f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd3b8 +0 290A0000 -[4cacae3124e7] jit-backend-dump} -[4cacae312ed7] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64252 +0 EF090000 +[57f8a1409d7] jit-backend-dump} +[57f8a1410d7] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd3d2 +0 330A0000 -[4cacae3142bd] jit-backend-dump} -[4cacae314e87] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6426c +0 F9090000 +[57f8a141e5b] jit-backend-dump} +[57f8a142493] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd3e3 +0 460A0000 -[4cacae31633f] jit-backend-dump} -[4cacae316ef1] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6427d +0 0C0A0000 +[57f8a14312f] jit-backend-dump} +[57f8a143737] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd3f9 +0 550A0000 -[4cacae318433] jit-backend-dump} -[4cacae318f25] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64293 +0 1B0A0000 +[57f8a144403] jit-backend-dump} +[57f8a144bbb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd40e +0 640A0000 -[4cacae31a3ad] jit-backend-dump} -[4cacae31ada3] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e642a8 +0 4D0A0000 +[57f8a1458fb] jit-backend-dump} +[57f8a146037] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd41f +0 770A0000 -[4cacae31c177] jit-backend-dump} -[4cacae31cb4f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e642bd +0 5C0A0000 +[57f8a146df3] jit-backend-dump} +[57f8a149cd3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd434 +0 870A0000 -[4cacae31e151] jit-backend-dump} -[4cacae31ec5b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e642dc +0 610A0000 +[57f8a14ad13] jit-backend-dump} +[57f8a14b437] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd454 +0 8B0A0000 -[4cacae320119] jit-backend-dump} -[4cacae321109] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e642ed +0 740A0000 +[57f8a14c187] jit-backend-dump} +[57f8a14c84b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd46c +0 BC0A0000 -[4cacae322585] jit-backend-dump} -[4cacae3230ad] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64455 +0 31090000 +[57f8a14d4df] jit-backend-dump} +[57f8a14dbe3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd5d6 +0 78090000 -[4cacae324487] jit-backend-dump} -[4cacae324e6b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64464 +0 4F090000 +[57f8a14e8f7] jit-backend-dump} +[57f8a14f023] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd5e5 +0 96090000 -[4cacae32623f] jit-backend-dump} -[4cacae326d6d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64501 +0 DF080000 +[57f8a14fd37] jit-backend-dump} +[57f8a150377] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd683 +0 25090000 -[4cacae3282a9] jit-backend-dump} -[4cacae328dbf] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64510 +0 FD080000 +[57f8a15102f] jit-backend-dump} +[57f8a15164f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd692 +0 43090000 -[4cacae32a199] jit-backend-dump} -[4cacae32ab7d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6452a +0 10090000 +[57f8a1522df] jit-backend-dump} +[57f8a1528df] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd6ac +0 56090000 -[4cacae32bf57] jit-backend-dump} -[4cacae32c977] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6454c +0 1B090000 +[57f8a1537eb] jit-backend-dump} +[57f8a153f0f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd6cf +0 60090000 -[4cacae32dd57] jit-backend-dump} -[4cacae32e73b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6455e +0 34090000 +[57f8a154d17] jit-backend-dump} +[57f8a155333] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd6e1 +0 7A090000 -[4cacae336637] jit-backend-dump} -[4cacae3375d3] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6456b +0 52090000 +[57f8a15605b] jit-backend-dump} +[57f8a15667b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd6ee +0 99090000 -[4cacae338b81] jit-backend-dump} -[4cacae33974b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6457f +0 68090000 +[57f8a15730f] jit-backend-dump} +[57f8a157917] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd702 +0 B0090000 -[4cacae33abf1] jit-backend-dump} -[4cacae33b58d] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6458d +0 86090000 +[57f8a1585a3] jit-backend-dump} +[57f8a158d4f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd710 +0 CF090000 -[4cacae33c967] jit-backend-dump} -[4cacae33d4bf] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e645be +0 A7090000 +[57f8a159bc7] jit-backend-dump} +[57f8a15a323] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd749 +0 EA090000 -[4cacae33e8a5] jit-backend-dump} -[4cacae33f397] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e645d4 +0 BA090000 +[57f8a15b067] jit-backend-dump} +[57f8a15b64b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd75f +0 FD090000 -[4cacae3408df] jit-backend-dump} -[4cacae3413b3] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e645e9 +0 D1090000 +[57f8a15c2db] jit-backend-dump} +[57f8a15c8ab] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd774 +0 140A0000 -[4cacae342787] jit-backend-dump} -[4cacae34313b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e645f7 +0 F0090000 +[57f8a15d533] jit-backend-dump} +[57f8a15db23] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd782 +0 330A0000 -[4cacae34451b] jit-backend-dump} -[4cacae344ea5] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6460e +0 050A0000 +[57f8a15e927] jit-backend-dump} +[57f8a15f3bb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd799 +0 480A0000 -[4cacae34627f] jit-backend-dump} -[4cacae346ccf] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64628 +0 180A0000 +[57f8a1601d3] jit-backend-dump} +[57f8a1607eb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd7b3 +0 5B0A0000 -[4cacae348217] jit-backend-dump} -[4cacae348ddb] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e64632 +0 3C0A0000 +[57f8a16147b] jit-backend-dump} +[57f8a161a5b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd7bd +0 7F0A0000 -[4cacae34a2b1] jit-backend-dump} -[4cacae34ac95] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6463c +0 610A0000 +[57f8a1626e7] jit-backend-dump} +[57f8a162cd3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd7c7 +0 A40A0000 -[4cacae34c07b] jit-backend-dump} -[4cacae34ca23] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6464f +0 7C0A0000 +[57f8a1661e7] jit-backend-dump} +[57f8a1669cb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd7da +0 BF0A0000 -[4cacae34de09] jit-backend-dump} -[4cacae34e79f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e647bc +0 3C090000 +[57f8a167737] jit-backend-dump} +[57f8a167e0f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd94d +0 79090000 -[4cacae34fc27] jit-backend-dump} -[4cacae3506d1] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e647cb +0 57090000 +[57f8a168b57] jit-backend-dump} +[57f8a16913f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd95c +0 93090000 -[4cacae351b83] jit-backend-dump} -[4cacae352513] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e647d4 +0 78090000 +[57f8a169dc7] jit-backend-dump} +[57f8a16a3ab] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd965 +0 B3090000 -[4cacae3538ed] jit-backend-dump} -[4cacae3542cb] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e647e8 +0 8D090000 +[57f8a16b033] jit-backend-dump} +[57f8a16b67f] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd979 +0 C7090000 -[4cacae3556ab] jit-backend-dump} -[4cacae35602f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e647f6 +0 A9090000 +[57f8a16c517] jit-backend-dump} +[57f8a16cc23] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd987 +0 E2090000 -[4cacae35740f] jit-backend-dump} -[4cacae357f13] {jit-backend-dump -BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd9df +0 B2090000 -[4cacae359509] jit-backend-dump} -[4cacae35a5a1] jit-backend} -[4cacae35c0dd] {jit-log-opt-loop -# Loop 8 : entry bridge with 212 ops +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6484d +0 7B090000 +[57f8a16d98b] jit-backend-dump} +[57f8a16e1e7] jit-backend} +[57f8a16f15f] {jit-log-opt-loop +# Loop 8 : entry bridge with 208 ops [p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11, p12, p13, p14, p15] debug_merge_point(0, ' #44 FOR_ITER') -+362: guard_value(i6, 4, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] -+372: guard_class(p11, 20808216, descr=) [p1, p0, p11, p2, p3, i4, p5, p8, p9, p10, p12, p13, p14, p15] ++362: guard_value(i6, 4, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10, p11, p12, p13, p14, p15] ++372: guard_class(p11, 21288040, descr=) [p1, p0, p11, p2, p3, i4, p5, p8, p9, p10, p12, p13, p14, p15] +384: p18 = getfield_gc(p11, descr=) -+388: guard_nonnull(p18, descr=) [p1, p0, p11, p18, p2, p3, i4, p5, p8, p9, p10, p12, p13, p14, p15] ++388: guard_nonnull(p18, descr=) [p1, p0, p11, p18, p2, p3, i4, p5, p8, p9, p10, p12, p13, p14, p15] +397: i19 = getfield_gc(p11, descr=) +401: i20 = getfield_gc(p18, descr=) +405: i21 = int_ge(i19, i20) -guard_false(i21, descr=) [p1, p0, p11, i19, p18, p2, p3, i4, p5, p8, p9, p10, p12, p13, p14, p15] +guard_false(i21, descr=) [p1, p0, p11, i19, p18, p2, p3, i4, p5, p8, p9, p10, p12, p13, p14, p15] +414: p22 = getfield_gc(p18, descr=) +418: p23 = getarrayitem_gc(p22, i19, descr=) +423: i25 = int_add(i19, 1) +427: setfield_gc(p11, i25, descr=) -+431: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p10, p11, p23, p13, p14, p15] ++431: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p9, p10, p11, p23, p13, p14, p15] debug_merge_point(0, ' #47 STORE_FAST') debug_merge_point(0, ' #50 LOAD_GLOBAL') -+441: guard_value(p3, ConstPtr(ptr27), descr=) [p1, p0, p3, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++441: guard_value(p3, ConstPtr(ptr27), descr=) [p1, p0, p3, p2, p5, p8, p9, p23, p11, p13, p14, p15] +460: p28 = getfield_gc(p0, descr=) -+464: guard_value(p28, ConstPtr(ptr29), descr=) [p1, p0, p28, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++464: guard_value(p28, ConstPtr(ptr29), descr=) [p1, p0, p28, p2, p5, p8, p9, p23, p11, p13, p14, p15] +483: p30 = getfield_gc(p28, descr=) -+488: guard_value(p30, ConstPtr(ptr31), descr=) [p1, p0, p30, p28, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++488: guard_value(p30, ConstPtr(ptr31), descr=) [p1, p0, p30, p28, p2, p5, p8, p9, p23, p11, p13, p14, p15] +501: p33 = getfield_gc(ConstPtr(ptr32), descr=) -+514: guard_nonnull_class(p33, 20812584, descr=) [p1, p0, p33, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++514: guard_nonnull_class(p33, 21293176, descr=) [p1, p0, p33, p2, p5, p8, p9, p23, p11, p13, p14, p15] debug_merge_point(0, ' #53 LOOKUP_METHOD') +534: p35 = getfield_gc(p33, descr=) -+539: guard_value(p35, ConstPtr(ptr36), descr=) [p1, p0, p33, p35, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++539: guard_value(p35, ConstPtr(ptr36), descr=) [p1, p0, p33, p35, p2, p5, p8, p9, p23, p11, p13, p14, p15] +558: p37 = getfield_gc(p35, descr=) -+562: guard_value(p37, ConstPtr(ptr38), descr=) [p1, p0, p33, p37, p35, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++562: guard_value(p37, ConstPtr(ptr38), descr=) [p1, p0, p33, p37, p35, p2, p5, p8, p9, p23, p11, p13, p14, p15] +575: p40 = getfield_gc(ConstPtr(ptr39), descr=) -+588: guard_nonnull_class(p40, ConstClass(Function), descr=) [p1, p0, p40, p33, p2, p5, p8, p9, p23, p11, p13, p14, p15] ++588: guard_nonnull_class(p40, ConstClass(Function), descr=) [p1, p0, p40, p33, p2, p5, p8, p9, p23, p11, p13, p14, p15] debug_merge_point(0, ' #56 LOAD_CONST') debug_merge_point(0, ' #59 LOAD_FAST') -+606: guard_nonnull_class(p23, ConstClass(W_StringObject), descr=) [p1, p0, p23, p2, p5, p8, p9, p11, p40, p15] ++606: guard_nonnull_class(p23, ConstClass(W_StringObject), descr=) [p1, p0, p23, p2, p5, p8, p9, p11, p40, p15] debug_merge_point(0, ' #62 CALL_METHOD') +624: p43 = getfield_gc(p40, descr=) -+628: guard_value(p43, ConstPtr(ptr44), descr=) [p1, p0, p43, p40, p2, p5, p8, p9, p23, p11] ++628: guard_value(p43, ConstPtr(ptr44), descr=) [p1, p0, p43, p40, p2, p5, p8, p9, p23, p11] +647: p45 = getfield_gc(p40, descr=) +651: i46 = arraylen_gc(p45, descr=) +656: i48 = int_sub(3, i46) -+666: i50 = int_ge(2, i48) -guard_true(i50, descr=) [p1, p0, p40, p2, p5, p8, p9, p23, p11] -+676: p51 = getfield_gc(p40, descr=) -+680: p52 = getfield_gc(p40, descr=) -+680: i54 = int_sub(i46, 1) -+687: i55 = int_ge(i54, i46) -guard_false(i55, descr=) [p1, p0, i46, i54, p40, p2, p5, p8, p9, p23, p11, p51] -+696: p56 = getarrayitem_gc_pure(p45, i54, descr=) -+701: p58 = call(ConstClass(getexecutioncontext), descr=) -+760: p59 = getfield_gc(p58, descr=) -+764: i60 = force_token() -+771: p61 = getfield_gc(p58, descr=) -+775: guard_isnull(p61, descr=) [p1, p0, p58, p61, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, p51] -+784: i62 = getfield_gc(p58, descr=) -+788: i63 = int_is_zero(i62) -guard_true(i63, descr=) [p1, p0, p58, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, p51] -debug_merge_point(1, ' #0 LOAD_GLOBAL') -+798: guard_value(p51, ConstPtr(ptr64), descr=) [p1, p0, p58, p51, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, None] -+824: p66 = getfield_gc(p51, descr=) -+828: guard_value(p66, ConstPtr(ptr67), descr=) [p1, p0, p58, p66, p51, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, None] -+841: p69 = getfield_gc(ConstPtr(ptr68), descr=) -+854: guard_nonnull_class(p69, ConstClass(Function), descr=) [p1, p0, p58, p69, p2, p5, p8, p9, p23, p11, p40, p56, p59, i60, None] -debug_merge_point(1, ' #3 LOAD_FAST') -debug_merge_point(1, ' #6 LOAD_FAST') -+873: guard_nonnull(p56, descr=) [p1, p0, p58, p56, p2, p5, p8, p9, p23, p11, p40, p69, None, p59, i60, None] -debug_merge_point(1, ' #9 CALL_FUNCTION') -+889: p71 = getfield_gc(p69, descr=) -+893: guard_value(p71, ConstPtr(ptr72), descr=) [p1, p0, p58, p71, p69, p2, p5, p8, p9, p23, p11, p40, None, p56, p59, i60, None] -+912: p73 = getfield_gc(p69, descr=) -+916: p74 = getfield_gc(p69, descr=) -+916: p75 = getfield_gc(p69, descr=) -+920: p76 = getfield_gc(p69, descr=) -+924: guard_no_exception(, descr=) [p1, p0, p58, p75, p76, p2, p5, p8, p9, p23, p11, p40, p73, p69, p56, p59, i60, None] -+939: i77 = force_token() -debug_merge_point(2, ' #0 LOAD_GLOBAL') -+946: guard_value(p73, ConstPtr(ptr78), descr=) [p1, p0, p58, p73, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] -+965: p79 = getfield_gc(p73, descr=) -+969: guard_value(p79, ConstPtr(ptr80), descr=) [p1, p0, p58, p79, p73, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] -+982: p82 = getfield_gc(ConstPtr(ptr81), descr=) -+995: guard_isnull(p82, descr=) [p1, p0, p58, p82, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] -+1004: p84 = getfield_gc(ConstPtr(ptr83), descr=) -+1012: guard_value(p84, ConstPtr(ptr85), descr=) [p1, p0, p58, p84, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] -+1025: p86 = getfield_gc(p84, descr=) -+1029: guard_value(p86, ConstPtr(ptr87), descr=) [p1, p0, p58, p86, p84, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] -+1042: p89 = getfield_gc(ConstPtr(ptr88), descr=) -+1050: guard_value(p89, ConstPtr(ptr90), descr=) [p1, p0, p58, p89, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] -debug_merge_point(2, ' #3 LOAD_FAST') -debug_merge_point(2, ' #6 LOAD_CONST') -debug_merge_point(2, ' #9 BINARY_SUBSCR') -debug_merge_point(2, ' #10 CALL_FUNCTION') -debug_merge_point(2, ' #13 BUILD_TUPLE') -debug_merge_point(2, ' #16 LOAD_FAST') -debug_merge_point(2, ' #19 BINARY_ADD') -debug_merge_point(2, ' #20 STORE_FAST') -debug_merge_point(2, ' #23 LOAD_GLOBAL') -+1063: p92 = getfield_gc(ConstPtr(ptr91), descr=) -+1076: guard_nonnull_class(p92, 20802224, descr=) [p1, p0, p58, p92, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, p56, p59, i60, None] -debug_merge_point(2, ' #26 LOOKUP_METHOD') -debug_merge_point(2, ' #29 LOAD_FAST') -debug_merge_point(2, ' #32 CALL_METHOD') -+1095: p95 = getfield_gc(ConstPtr(ptr94), descr=) -+1103: guard_not_invalidated(, descr=) [p1, p0, p58, p95, p2, p5, p8, p9, p23, p11, p40, p92, i77, None, p69, p56, p59, i60, None] -+1103: p96 = getfield_gc(p92, descr=) -+1107: guard_class(p96, ConstClass(ObjectDictStrategy), descr=) [p1, p0, p58, p92, p96, p2, p5, p8, p9, p23, p11, p40, None, i77, None, p69, p56, p59, i60, None] -+1119: p98 = getfield_gc(p92, descr=) -+1123: i99 = force_token() -+1130: p101 = new_with_vtable(20801800) -+1242: setfield_gc(p101, i77, descr=) -setfield_gc(p58, p101, descr=) -+1293: setfield_gc(p0, i99, descr=) -+1297: p103 = new_array(3, descr=) -+1375: setarrayitem_gc(p103, 0, ConstPtr(ptr105), descr=) -+1383: setarrayitem_gc(p103, 1, ConstPtr(ptr107), descr=) -+1397: setarrayitem_gc(p103, 2, p56, descr=) -+1408: i110 = call_may_force(ConstClass(hash_tuple), p103, descr=) -guard_not_forced(, descr=) [p1, p0, p58, p92, p98, i110, p101, p2, p5, p8, p9, p23, p11, p40, p56, p59, p69, i60, p103] -+1481: guard_no_exception(, descr=) [p1, p0, p58, p92, p98, i110, p101, p2, p5, p8, p9, p23, p11, p40, p56, p59, p69, i60, p103] -+1496: i111 = force_token() -+1503: setfield_gc(p0, i111, descr=) -+1514: p113 = new_with_vtable(20801872) -+1584: setfield_gc(p113, p103, descr=) -+1595: i115 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p98, p113, i110, descr=) -guard_not_forced(, descr=) [p1, p0, p58, p113, p92, i115, p98, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] -+1654: guard_no_exception(, descr=) [p1, p0, p58, p113, p92, i115, p98, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] -+1669: i117 = int_and(i115, -9223372036854775808) -+1685: i118 = int_is_true(i117) -guard_false(i118, descr=) [p1, p0, p58, p113, p92, i115, p98, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] -+1695: p120 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p98, i115, descr=) -+1715: guard_no_exception(, descr=) [p1, p0, p58, p113, p92, p120, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] -+1730: guard_nonnull_class(p120, 21007408, descr=) [p1, p0, p58, p113, p92, p120, p101, p2, p5, p8, p9, p23, p11, p40, p69, p56, p59, i60] -debug_merge_point(2, ' #35 STORE_FAST') -debug_merge_point(2, ' #38 LOAD_FAST') -debug_merge_point(2, ' #41 LOAD_CONST') -debug_merge_point(2, ' #44 COMPARE_OP') -+1748: i123 = ptr_eq(p120, ConstPtr(ptr122)) -guard_false(i123, descr=) [p1, p0, p58, p101, p2, p5, p8, p9, p23, p11, p40, p120, p113, p69, p56, p59, i60] -debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') -debug_merge_point(2, ' #50 LOAD_FAST') -debug_merge_point(2, ' #53 RETURN_VALUE') -+1761: p124 = getfield_gc(p58, descr=) -+1772: guard_isnull(p124, descr=) [p1, p0, p58, p120, p124, p101, p2, p5, p8, p9, p23, p11, p40, None, p113, p69, p56, p59, i60] -+1781: i125 = getfield_gc(p58, descr=) -+1785: i126 = int_is_true(i125) -guard_false(i126, descr=) [p1, p0, p58, p120, p101, p2, p5, p8, p9, p23, p11, p40, None, p113, p69, p56, p59, i60] -+1795: p127 = getfield_gc(p58, descr=) -debug_merge_point(1, ' #12 LOOKUP_METHOD') -debug_merge_point(1, ' #15 LOAD_FAST') -debug_merge_point(1, ' #18 CALL_METHOD') -+1795: p129 = getfield_gc(ConstPtr(ptr128), descr=) -+1803: setfield_gc(p101, -3, descr=) -+1818: guard_not_invalidated(, descr=) [p1, p0, p58, p129, p2, p5, p8, p9, p23, p11, p40, p120, None, None, p56, p59, i60] -+1818: p131 = getfield_gc_pure(p23, descr=) -+1829: i132 = strlen(p131) -+1833: i134 = int_gt(9223372036854775807, i132) -guard_true(i134, descr=) [p1, p0, p58, p120, p131, p2, p5, p8, p9, p23, p11, p40, None, None, None, p56, p59, i60] -+1852: p135 = getfield_gc(p120, descr=) -+1856: i136 = getfield_gc(p120, descr=) -+1860: i138 = getarrayitem_gc_pure(p135, 0, descr=) -+1864: i140 = int_eq(i138, 17) -guard_true(i140, descr=) [p1, p0, p58, p120, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] -+1874: i142 = getarrayitem_gc_pure(p135, 2, descr=) -+1878: i144 = int_and(i142, 1) -+1885: i145 = int_is_true(i144) -guard_true(i145, descr=) [p1, p0, p58, p120, i142, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] -+1895: i147 = getarrayitem_gc_pure(p135, 5, descr=) -+1899: i149 = int_gt(i147, 1) -guard_false(i149, descr=) [p1, p0, p58, p120, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] -+1909: i151 = getarrayitem_gc_pure(p135, 1, descr=) -+1913: i153 = int_add(i151, 1) -+1917: i154 = getarrayitem_gc_pure(p135, i153, descr=) -+1922: i156 = int_eq(i154, 19) -guard_true(i156, descr=) [p1, p0, p58, p120, i153, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] -+1932: i158 = int_add(i153, 1) -+1939: i159 = getarrayitem_gc_pure(p135, i158, descr=) -+1944: i161 = int_add(i153, 2) -+1948: i163 = int_lt(0, i132) -guard_true(i163, descr=) [p1, p0, p58, p120, i159, i161, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, p135, None, None, None, p56, p59, i60] -+1958: guard_value(i161, 11, descr=) [p1, p0, p58, p120, i159, i161, p135, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, None, None, None, None, p56, p59, i60] -+1968: guard_value(i159, 51, descr=) [p1, p0, p58, p120, i159, p135, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, None, None, None, None, p56, p59, i60] -+1978: guard_value(p135, ConstPtr(ptr166), descr=) [p1, p0, p58, p120, p135, p2, p5, p8, p9, p23, p11, p40, i136, p131, i132, None, None, None, None, p56, p59, i60] ++665: i50 = int_ge(2, i48) +guard_true(i50, descr=) [p1, p0, p40, p2, p5, p8, p9, p23, p11] ++675: p51 = getfield_gc(p40, descr=) ++679: p52 = getfield_gc(p40, descr=) ++679: i54 = int_sub(i46, 1) ++686: i55 = int_ge(i54, i46) +guard_false(i55, descr=) [p1, p0, i46, i54, p40, p2, p5, p8, p9, p23, p11, p51] ++695: p56 = getarrayitem_gc_pure(p45, i54, descr=) ++700: p58 = call(ConstClass(getexecutioncontext), descr=) ++758: p59 = getfield_gc(p58, descr=) ++762: i60 = force_token() ++769: p61 = getfield_gc(p58, descr=) ++773: guard_isnull(p61, descr=) [p1, p0, p58, p61, p2, p5, p8, p9, p23, p11, p40, i60, p59, p56, p51] ++782: i62 = getfield_gc(p58, descr=) ++786: i63 = int_is_zero(i62) +guard_true(i63, descr=) [p1, p0, p58, p2, p5, p8, p9, p23, p11, p40, i60, p59, p56, p51] +debug_merge_point(1, ' #0 LOAD_GLOBAL') ++796: guard_value(p51, ConstPtr(ptr64), descr=) [p1, p0, p58, p51, p2, p5, p8, p9, p23, p11, p40, i60, p59, p56, None] ++822: p66 = getfield_gc(p51, descr=) ++826: guard_value(p66, ConstPtr(ptr67), descr=) [p1, p0, p58, p66, p51, p2, p5, p8, p9, p23, p11, p40, i60, p59, p56, None] ++839: p69 = getfield_gc(ConstPtr(ptr68), descr=) ++852: guard_nonnull_class(p69, ConstClass(Function), descr=) [p1, p0, p58, p69, p2, p5, p8, p9, p23, p11, p40, i60, p59, p56, None] +debug_merge_point(1, ' #3 LOAD_FAST') +debug_merge_point(1, ' #6 LOAD_FAST') ++870: guard_nonnull(p56, descr=) [p1, p0, p58, p56, p2, p5, p8, p9, p23, p11, p40, p69, i60, p59, None, None] +debug_merge_point(1, ' #9 CALL_FUNCTION') ++886: p71 = getfield_gc(p69, descr=) ++890: guard_value(p71, ConstPtr(ptr72), descr=) [p1, p0, p58, p71, p69, p2, p5, p8, p9, p23, p11, p40, None, i60, p59, p56, None] ++909: p73 = getfield_gc(p69, descr=) ++913: p74 = getfield_gc(p69, descr=) ++913: p75 = getfield_gc(p69, descr=) ++917: p76 = getfield_gc(p69, descr=) ++921: guard_no_exception(, descr=) [p1, p0, p58, p75, p76, p2, p5, p8, p9, p23, p11, p40, p73, p69, i60, p59, p56, None] ++936: i77 = force_token() +debug_merge_point(2, ' #0 LOAD_GLOBAL') ++943: guard_value(p73, ConstPtr(ptr78), descr=) [p1, p0, p58, p73, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, i60, p59, p56, None] ++962: p79 = getfield_gc(p73, descr=) ++966: guard_value(p79, ConstPtr(ptr80), descr=) [p1, p0, p58, p79, p73, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, i60, p59, p56, None] ++979: p82 = getfield_gc(ConstPtr(ptr81), descr=) ++992: guard_isnull(p82, descr=) [p1, p0, p58, p82, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, i60, p59, p56, None] ++1001: guard_not_invalidated(, descr=) [p1, p0, p58, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, i60, p59, p56, None] ++1001: p84 = getfield_gc(ConstPtr(ptr83), descr=) ++1009: guard_value(p84, ConstPtr(ptr85), descr=) [p1, p0, p58, p84, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, i60, p59, p56, None] ++1022: p87 = getfield_gc(ConstPtr(ptr86), descr=) ++1030: guard_value(p87, ConstPtr(ptr88), descr=) [p1, p0, p58, p87, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, i60, p59, p56, None] +debug_merge_point(2, ' #3 LOAD_FAST') +debug_merge_point(2, ' #6 LOAD_CONST') +debug_merge_point(2, ' #9 BINARY_SUBSCR') +debug_merge_point(2, ' #10 CALL_FUNCTION') +debug_merge_point(2, ' #13 BUILD_TUPLE') +debug_merge_point(2, ' #16 LOAD_FAST') +debug_merge_point(2, ' #19 BINARY_ADD') +debug_merge_point(2, ' #20 STORE_FAST') +debug_merge_point(2, ' #23 LOAD_GLOBAL') ++1043: p90 = getfield_gc(ConstPtr(ptr89), descr=) ++1056: guard_nonnull_class(p90, 21278680, descr=) [p1, p0, p58, p90, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, i60, p59, p56, None] +debug_merge_point(2, ' #26 LOOKUP_METHOD') +debug_merge_point(2, ' #29 LOAD_FAST') +debug_merge_point(2, ' #32 CALL_METHOD') ++1074: p92 = getfield_gc(p90, descr=) ++1078: guard_class(p92, ConstClass(ObjectDictStrategy), descr=) [p1, p0, p58, p90, p92, p2, p5, p8, p9, p23, p11, p40, i77, None, p69, i60, p59, p56, None] ++1091: p94 = getfield_gc(p90, descr=) ++1095: i95 = force_token() ++1102: p97 = new_with_vtable(21282720) ++1214: setfield_gc(p97, i77, descr=) +setfield_gc(p58, p97, descr=) ++1264: setfield_gc(p0, i95, descr=) ++1268: p99 = new_array(3, descr=) ++1346: setarrayitem_gc(p99, 0, ConstPtr(ptr101), descr=) ++1354: setarrayitem_gc(p99, 1, ConstPtr(ptr103), descr=) ++1368: setarrayitem_gc(p99, 2, p56, descr=) ++1379: i106 = call_may_force(ConstClass(hash_tuple), p99, descr=) +guard_not_forced(, descr=) [p1, p0, p58, p90, p94, i106, p97, p2, p5, p8, p9, p23, p11, p40, i60, p56, p99, p59, p69] ++1451: guard_no_exception(, descr=) [p1, p0, p58, p90, p94, i106, p97, p2, p5, p8, p9, p23, p11, p40, i60, p56, p99, p59, p69] ++1466: i107 = force_token() ++1473: setfield_gc(p0, i107, descr=) ++1484: p109 = new_with_vtable(21277928) ++1554: setfield_gc(p109, p99, descr=) ++1565: i111 = call_may_force(ConstClass(ll_dict_lookup__dicttablePtr_pypy_interpreter_baseobjspace_W_RootPtr_Signed), p94, p109, i106, descr=) +guard_not_forced(, descr=) [p1, p0, p58, p109, p90, i111, p94, p97, p2, p5, p8, p9, p23, p11, p40, i60, p56, p59, p69] ++1623: guard_no_exception(, descr=) [p1, p0, p58, p109, p90, i111, p94, p97, p2, p5, p8, p9, p23, p11, p40, i60, p56, p59, p69] ++1638: i113 = int_and(i111, -9223372036854775808) ++1654: i114 = int_is_true(i113) +guard_false(i114, descr=) [p1, p0, p58, p109, p90, i111, p94, p97, p2, p5, p8, p9, p23, p11, p40, i60, p56, p59, p69] ++1664: p116 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p94, i111, descr=) ++1683: guard_no_exception(, descr=) [p1, p0, p58, p109, p90, p116, p97, p2, p5, p8, p9, p23, p11, p40, i60, p56, p59, p69] ++1698: guard_nonnull_class(p116, 21487768, descr=) [p1, p0, p58, p109, p90, p116, p97, p2, p5, p8, p9, p23, p11, p40, i60, p56, p59, p69] +debug_merge_point(2, ' #35 STORE_FAST') +debug_merge_point(2, ' #38 LOAD_FAST') +debug_merge_point(2, ' #41 LOAD_CONST') +debug_merge_point(2, ' #44 COMPARE_OP') ++1716: i119 = ptr_eq(p116, ConstPtr(ptr118)) +guard_false(i119, descr=) [p1, p0, p58, p97, p2, p5, p8, p9, p23, p11, p40, p109, p116, i60, p56, p59, p69] +debug_merge_point(2, ' #47 POP_JUMP_IF_FALSE') +debug_merge_point(2, ' #50 LOAD_FAST') +debug_merge_point(2, ' #53 RETURN_VALUE') ++1729: p120 = getfield_gc(p58, descr=) ++1740: guard_isnull(p120, descr=) [p1, p0, p58, p116, p120, p97, p2, p5, p8, p9, p23, p11, p40, p109, None, i60, p56, p59, p69] ++1749: i121 = getfield_gc(p58, descr=) ++1753: i122 = int_is_true(i121) +guard_false(i122, descr=) [p1, p0, p58, p116, p97, p2, p5, p8, p9, p23, p11, p40, p109, None, i60, p56, p59, p69] ++1763: p123 = getfield_gc(p58, descr=) +debug_merge_point(1, ' #12 LOOKUP_METHOD') +debug_merge_point(1, ' #15 LOAD_FAST') +debug_merge_point(1, ' #18 CALL_METHOD') ++1763: setfield_gc(p97, -3, descr=) ++1778: guard_not_invalidated(, descr=) [p1, p0, p58, p2, p5, p8, p9, p23, p11, p40, None, p116, i60, p56, p59, None] ++1778: p125 = getfield_gc_pure(p23, descr=) ++1789: i126 = strlen(p125) ++1793: i128 = int_gt(9223372036854775807, i126) +guard_true(i128, descr=) [p1, p0, p58, p116, p125, p2, p5, p8, p9, p23, p11, p40, None, None, i60, p56, p59, None] ++1812: p129 = getfield_gc(p116, descr=) ++1816: i130 = getfield_gc(p116, descr=) ++1820: i132 = getarrayitem_gc_pure(p129, 0, descr=) ++1824: i134 = int_eq(i132, 17) +guard_true(i134, descr=) [p1, p0, p58, p116, p2, p5, p8, p9, p23, p11, p40, p125, i126, p129, i130, None, None, i60, p56, p59, None] ++1834: i136 = getarrayitem_gc_pure(p129, 2, descr=) ++1838: i138 = int_and(i136, 1) ++1845: i139 = int_is_true(i138) +guard_true(i139, descr=) [p1, p0, p58, p116, i136, p2, p5, p8, p9, p23, p11, p40, p125, i126, p129, i130, None, None, i60, p56, p59, None] ++1855: i141 = getarrayitem_gc_pure(p129, 5, descr=) ++1859: i143 = int_gt(i141, 1) +guard_false(i143, descr=) [p1, p0, p58, p116, p2, p5, p8, p9, p23, p11, p40, p125, i126, p129, i130, None, None, i60, p56, p59, None] ++1869: i145 = getarrayitem_gc_pure(p129, 1, descr=) ++1873: i147 = int_add(i145, 1) ++1877: i148 = getarrayitem_gc_pure(p129, i147, descr=) ++1882: i150 = int_eq(i148, 19) +guard_true(i150, descr=) [p1, p0, p58, p116, i147, p2, p5, p8, p9, p23, p11, p40, p125, i126, p129, i130, None, None, i60, p56, p59, None] ++1892: i152 = int_add(i147, 1) ++1899: i153 = getarrayitem_gc_pure(p129, i152, descr=) ++1904: i155 = int_add(i147, 2) ++1908: i157 = int_lt(0, i126) +guard_true(i157, descr=) [p1, p0, p58, p116, i153, i155, p2, p5, p8, p9, p23, p11, p40, p125, i126, p129, i130, None, None, i60, p56, p59, None] ++1918: guard_value(i155, 11, descr=) [p1, p0, p58, p116, i153, i155, p129, p2, p5, p8, p9, p23, p11, p40, p125, i126, None, i130, None, None, i60, p56, p59, None] ++1928: guard_value(i153, 51, descr=) [p1, p0, p58, p116, i153, p129, p2, p5, p8, p9, p23, p11, p40, p125, i126, None, i130, None, None, i60, p56, p59, None] ++1938: guard_value(p129, ConstPtr(ptr160), descr=) [p1, p0, p58, p116, p129, p2, p5, p8, p9, p23, p11, p40, p125, i126, None, i130, None, None, i60, p56, p59, None] debug_merge_point(2, 'StrLiteralSearch at 11/51 [17. 8. 3. 1. 1. 1. 1. 51. 0. 19. 51. 1]') -+1997: i167 = force_token() -+2004: p168 = new_with_vtable(20801800) -+2102: setfield_gc(p168, i60, descr=) -setfield_gc(p58, p168, descr=) -+2142: setfield_gc(p0, i167, descr=) -+2160: p170 = new_with_vtable(20819912) -+2230: setfield_gc(p170, i132, descr=) -+2241: setfield_gc(p170, i136, descr=) -+2252: setfield_gc(p170, p131, descr=) -+2263: setfield_gc(p170, ConstPtr(ptr166), descr=) -+2277: i171 = call_assembler(0, p170, descr=) -guard_not_forced(, descr=) [p1, p0, p58, p120, p170, i171, p168, p2, p5, p8, p9, p23, p11, p40, p56, p59] -+2368: guard_no_exception(, descr=) [p1, p0, p58, p120, p170, i171, p168, p2, p5, p8, p9, p23, p11, p40, p56, p59] -+2383: guard_true(i171, descr=) [p1, p0, p58, p120, p170, p168, p2, p5, p8, p9, p23, p11, p40, p56, p59] -debug_merge_point(1, ' #21 RETURN_VALUE') -+2392: p172 = getfield_gc(p58, descr=) -+2403: guard_isnull(p172, descr=) [p1, p0, p58, p172, p168, p2, p5, p8, p9, p23, p11, p40, p120, p170, p56, p59] -+2412: i173 = getfield_gc(p58, descr=) -+2416: i174 = int_is_true(i173) -guard_false(i174, descr=) [p1, p0, p58, p168, p2, p5, p8, p9, p23, p11, p40, p120, p170, p56, p59] -+2426: p175 = getfield_gc(p58, descr=) ++1957: i161 = force_token() ++1964: p162 = new_with_vtable(21282720) ++2062: setfield_gc(p162, i60, descr=) +setfield_gc(p58, p162, descr=) ++2101: setfield_gc(p0, i161, descr=) ++2119: p164 = new_with_vtable(21320352) ++2189: setfield_gc(p164, i126, descr=) ++2200: setfield_gc(p164, ConstPtr(ptr160), descr=) ++2214: setfield_gc(p164, p125, descr=) ++2225: setfield_gc(p164, i130, descr=) ++2236: i165 = call_assembler(0, p164, descr=) +guard_not_forced(, descr=) [p1, p0, p58, p116, p164, i165, p162, p2, p5, p8, p9, p23, p11, p40, p56, p59] ++2322: guard_no_exception(, descr=) [p1, p0, p58, p116, p164, i165, p162, p2, p5, p8, p9, p23, p11, p40, p56, p59] ++2337: guard_true(i165, descr=) [p1, p0, p58, p116, p164, p162, p2, p5, p8, p9, p23, p11, p40, p56, p59] +debug_merge_point(1, ' #21 RETURN_VALUE') ++2346: p166 = getfield_gc(p58, descr=) ++2357: guard_isnull(p166, descr=) [p1, p0, p58, p166, p162, p2, p5, p8, p9, p23, p11, p40, p116, p164, p56, p59] ++2366: i167 = getfield_gc(p58, descr=) ++2370: i168 = int_is_true(i167) +guard_false(i168, descr=) [p1, p0, p58, p162, p2, p5, p8, p9, p23, p11, p40, p116, p164, p56, p59] ++2380: p169 = getfield_gc(p58, descr=) debug_merge_point(0, ' #65 POP_TOP') debug_merge_point(0, ' #66 JUMP_ABSOLUTE') -+2426: i177 = getfield_raw(40588192, descr=) -+2434: i179 = int_sub(i177, 62) -+2438: setfield_raw(40588192, i179, descr=) ++2380: i171 = getfield_raw(41254440, descr=) ++2388: i173 = int_sub(i171, 25) ++2392: setfield_raw(41254440, i173, descr=) setfield_gc(p58, p59, descr=) -+2489: setfield_gc(p168, -3, descr=) -+2504: i182 = int_lt(i179, 0) -guard_false(i182, descr=) [p1, p0, p2, p5, p8, p9, p23, p11, None, None, None, None] ++2442: setfield_gc(p162, -3, descr=) ++2457: i176 = int_lt(i173, 0) +guard_false(i176, descr=) [p1, p0, p2, p5, p8, p9, p23, p11, None, None, None, None] debug_merge_point(0, ' #44 FOR_ITER') -+2514: jump(p0, p1, p2, p5, p8, p9, p23, p11, i173, p58, p59, descr=) -+2653: --end of the loop-- -[4cacae517669] jit-log-opt-loop} -[4cacaee48ccb] {jit-backend -[4cacaeea1c45] {jit-backend-dump ++2467: jump(p0, p1, p2, p5, p8, p9, p23, p11, i167, p58, p59, descr=) ++2592: --end of the loop-- +[57f8a5b01d3] jit-log-opt-loop} +[57f8aae4d63] {jit-backend +[57f8ab1803b] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65be3b7 +0 488DA50000000049BB98A0CFB8A07F00004D8B3B4983C70149BB98A0CFB8A07F00004D893B4C8BBD18FFFFFF4D8B77484D85F60F85000000004D8B77284983FE000F85000000004C8B3425A0536B024983EE054C893425A0536B024C8BAD08FFFFFF41F647040174104C89FF4C89EE49C7C310734D0041FFD34D896F384C8BAD78FEFFFF49C74508FDFFFFFF4983FE000F8C000000004C8BBDD8FEFFFF4C8BB5C0FEFFFF4C8BADB8FEFFFF49BBF8F477B6A07F00004D89DC49C7C2000000004C8B8D30FFFFFF49C7C00400000048C7C72C000000488BB520FFFFFF488B9DC8FEFFFF488B9550FFFFFF488B8D38FFFFFF48C78570FFFFFF0000000048C78568FFFFFF0000000048C78560FFFFFF0000000048C78558FFFFFF0000000049BB5DD15BB6A07F000041FFE349BB00905BB6A07F000041FFD398018C013C38BC019C0160689401505C54647403C200000049BB00905BB6A07F000041FFD398018C013CBC019C0160689401505C54647403C300000049BB00905BB6A07F000041FFD398018C019C0160689401505C070703C4000000 -[4cacaeeb8a21] jit-backend-dump} -[4cacaeeb9cbd] {jit-backend-addr -Bridge out of guard 190 has address 7fa0b65be3b7 to 7fa0b65be4e0 -[4cacaeebba0f] jit-backend-addr} -[4cacaeebca47] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e651ee +0 488DA50000000049BB98F049D6C97F00004D8B3B4983C70149BB98F049D6C97F00004D893B4C8BBD18FFFFFF4D8B77484D85F60F85000000004D8B77284983FE000F85000000004C8B3425287E75024983EE024C893425287E75024C8BADE8FEFFFF41F6470401740F4C89FF4C89EE41BB30BCC70041FFD34D896F384C8BAD78FEFFFF49C74508FDFFFFFF4983FE000F8C000000004C8BBDD8FEFFFF4C8BB5C0FEFFFF4C8BADB8FEFFFF49BB287CFAD3C97F00004D89DC41BA000000004C8B8D20FFFFFF41B804000000BF2C000000488BB528FFFFFF488B9DC8FEFFFF488B9550FFFFFF488B8D40FFFFFF48C78570FFFFFF0000000048C78568FFFFFF0000000048C78560FFFFFF0000000048C78558FFFFFF0000000049BBFA3FE6D3C97F000041FFE349BB0000E6D3C97F000041FFD398018C013C38BC019C01686494015058605C840103BE00000049BB0000E6D3C97F000041FFD398018C013CBC019C01686494015058605C840103BF00000049BB0000E6D3C97F000041FFD398018C019C01686494015058070703C0000000 +[57f8ab25b3f] jit-backend-dump} +[57f8ab26767] {jit-backend-addr +bridge out of Guard 186 has address 7fc9d3e651ee to 7fc9d3e65312 +[57f8ab2785f] jit-backend-addr} +[57f8ab282f3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65be3ba +0 E0FDFFFF -[4cacaeebe559] jit-backend-dump} -[4cacaeebf303] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e651f1 +0 E0FDFFFF +[57f8ab29587] jit-backend-dump} +[57f8ab2a157] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65be3ec +0 F0000000 -[4cacaeec0929] jit-backend-dump} -[4cacaeec134f] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e65223 +0 EB000000 +[57f8ab2af7b] jit-backend-dump} +[57f8ab2b5d3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65be3fa +0 07010000 -[4cacaeec278f] jit-backend-dump} -[4cacaeec3179] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e65231 +0 03010000 +[57f8ab2c2bb] jit-backend-dump} +[57f8ab2c8c3] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65be449 +0 DC000000 -[4cacaeec45f5] jit-backend-dump} -[4cacaeec564b] {jit-backend-dump +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e6527f +0 DA000000 +[57f8ab2d70f] jit-backend-dump} +[57f8ab2e0cb] {jit-backend-dump BACKEND x86_64 -SYS_EXECUTABLE python -CODE_DUMP @7fa0b65bd965 +0 4E0A0000 -[4cacaeec6b21] jit-backend-dump} -[4cacaeec7715] jit-backend} -[4cacaeec8bc1] {jit-log-opt-bridge -# bridge out of Guard 190 with 18 ops +SYS_EXECUTABLE /home/fijal/Downloads/pypy-c-jit-45787-e4eef33f1a65-linux64/bin/pypy +CODE_DUMP @7fc9d3e647d4 +0 160A0000 +[57f8ab2ee6b] jit-backend-dump} +[57f8ab2f627] jit-backend} +[57f8ab301b3] {jit-log-opt-bridge +# bridge out of Guard 186 with 18 ops [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] -debug_merge_point(1, ' #21 RETURN_VALUE') +debug_merge_point(1, ' #21 RETURN_VALUE') +37: p15 = getfield_gc(p2, descr=) -+48: guard_isnull(p15, descr=) [p0, p1, p2, p15, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] ++48: guard_isnull(p15, descr=) [p0, p1, p2, p15, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] +57: i16 = getfield_gc(p2, descr=) +61: i17 = int_is_true(i16) -guard_false(i17, descr=) [p0, p1, p2, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] +guard_false(i17, descr=) [p0, p1, p2, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14] +71: p18 = getfield_gc(p2, descr=) debug_merge_point(0, ' #65 POP_TOP') debug_merge_point(0, ' #66 JUMP_ABSOLUTE') -+71: i20 = getfield_raw(40588192, descr=) -+79: i22 = int_sub(i20, 5) -+83: setfield_raw(40588192, i22, descr=) ++71: i20 = getfield_raw(41254440, descr=) ++79: i22 = int_sub(i20, 2) ++83: setfield_raw(41254440, i22, descr=) setfield_gc(p2, p14, descr=) -+125: setfield_gc(p5, -3, descr=) -+140: i25 = int_lt(i22, 0) -guard_false(i25, descr=) [p0, p1, p6, p7, p8, p9, p10, p11, None, None] ++124: setfield_gc(p5, -3, descr=) ++139: i25 = int_lt(i22, 0) +guard_false(i25, descr=) [p0, p1, p6, p7, p8, p9, p10, p11, None, None] debug_merge_point(0, ' #44 FOR_ITER') -+150: jump(p1, p0, p6, ConstPtr(ptr27), 0, p7, 4, 44, p8, p9, p10, p11, ConstPtr(ptr31), ConstPtr(ptr32), ConstPtr(ptr33), ConstPtr(ptr34), descr=) -+297: --end of the loop-- -[4cacaeef6f29] jit-log-opt-bridge} -[4cacaf781b8d] {jit-backend-counts ++149: jump(p1, p0, p6, ConstPtr(ptr27), 0, p7, 4, 44, p8, p9, p10, p11, ConstPtr(ptr31), ConstPtr(ptr32), ConstPtr(ptr33), ConstPtr(ptr34), descr=) ++292: --end of the loop-- +[57f8ab5379b] jit-log-opt-bridge} +[57f8af5d3af] {jit-backend-counts 0:13968 1:9112 -2:4445 +2:4482 3:4485 4:0 -5:4245 -6:1965 -7:2 +5:4282 +6:1967 +7:1 8:9210 9:8304 10:1686 -11:528 -12:1435 +11:534 +12:1433 13:1052 -[4cacaf788a8d] jit-backend-counts} +[57f8af61e1f] jit-backend-counts} From noreply at buildbot.pypy.org Sat Jul 23 18:02:26 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 18:02:26 +0200 (CEST) Subject: [pypy-commit] pypy default: Tentatively let StackOverflow and MemoryError exit the JIT tracing Message-ID: <20110723160226.C453F829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45900:2413c8ed9933 Date: 2011-07-23 18:02 +0200 http://bitbucket.org/pypy/pypy/changeset/2413c8ed9933/ Log: Tentatively let StackOverflow and MemoryError exit the JIT tracing and be propagated outside. diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -10,6 +10,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import fatalerror +from pypy.rlib.rstackovf import StackOverflow from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function @@ -408,6 +409,15 @@ jd.warmstate = state def crash_in_jit(e): + try: + raise e + except JitException: + raise # go through + except MemoryError: + raise # go through + except StackOverflow: + raise # go through + except Exception, e: if not we_are_translated(): print "~~~ Crash in JIT!" print '~~~ %s: %s' % (e.__class__, e) @@ -421,8 +431,6 @@ def maybe_enter_jit(*args): try: maybe_compile_and_run(state.increment_threshold, *args) - except JitException: - raise # go through except Exception, e: crash_in_jit(e) maybe_enter_jit._always_inline_ = True From noreply at buildbot.pypy.org Sat Jul 23 18:18:49 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 18:18:49 +0200 (CEST) Subject: [pypy-commit] jitviewer default: also highlight the line Message-ID: <20110723161849.C8726829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r161:9cc45021ed0d Date: 2011-07-23 18:16 +0200 http://bitbucket.org/pypy/jitviewer/changeset/9cc45021ed0d/ Log: also highlight the line diff --git a/_jitviewer/static/script.js b/_jitviewer/static/script.js --- a/_jitviewer/static/script.js +++ b/_jitviewer/static/script.js @@ -3,6 +3,8 @@ function show_loop(no, path) { + $("#loop-" + glob_bridge_state.no).removeClass("selected"); + $("#loop-" + no).addClass("selected"); $("#title-text").html($("#loop-" + no).attr('name')); $("#title").show(); glob_bridge_state.no = no; From noreply at buildbot.pypy.org Sat Jul 23 19:10:15 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 19:10:15 +0200 (CEST) Subject: [pypy-commit] pypy range-immutable: close this branch for the forseeable future. ranges are rarely constants Message-ID: <20110723171015.2CD11829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: range-immutable Changeset: r45901:2980b2bf826d Date: 2011-07-23 19:08 +0200 http://bitbucket.org/pypy/pypy/changeset/2980b2bf826d/ Log: close this branch for the forseeable future. ranges are rarely constants From noreply at buildbot.pypy.org Sat Jul 23 19:50:34 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 19:50:34 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: improve tests Message-ID: <20110723175034.4AFF1829BB@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45903:d0af6a58e1b1 Date: 2011-07-23 19:34 +0200 http://bitbucket.org/pypy/pypy/changeset/d0af6a58e1b1/ Log: improve tests diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -883,12 +883,12 @@ self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), BoxFloat(1.5)], 'void', descr=kdescr) - #f = self.cpu.bh_getinteriorfield_gc_f(a_box.getref_base(), 3, kdescr) - #assert f == 1.5 - #self.cpu.bh_setinteriorfield_gc_f(a_box.getref_base(), 3, kdescr, 2.5) + f = self.cpu.bh_getinteriorfield_gc_f(a_box.getref_base(), 3, kdescr) + assert f == 1.5 + self.cpu.bh_setinteriorfield_gc_f(a_box.getref_base(), 3, kdescr, 2.5) r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)], 'float', descr=kdescr) - assert r.getfloat() == 1.5 + assert r.getfloat() == 2.5 self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), BoxInt(15)], 'void', descr=vdescr) @@ -898,9 +898,13 @@ r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)], 'int', descr=vdescr) assert r.getint() == 25 - self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3), + self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(4), s_box], 'void', descr=pdescr) + r = self.cpu.bh_getinteriorfield_gc_r(a_box.getref_base(), 4, pdescr) + assert r == s_box.getref_base() + self.cpu.bh_setinteriorfield_gc_r(a_box.getref_base(), 3, pdescr, + s_box.getref_base()) r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)], 'ref', descr=pdescr) assert r.getref_base() == s_box.getref_base() From noreply at buildbot.pypy.org Sat Jul 23 19:50:33 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 19:50:33 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: merge default Message-ID: <20110723175033.0CF99829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45902:fd39e9d2bdcf Date: 2011-07-23 19:14 +0200 http://bitbucket.org/pypy/pypy/changeset/fd39e9d2bdcf/ Log: merge default diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -185,6 +185,7 @@ Jim Baker Philip Jenvey Rodrigo Araújo + Brett Cannon Heinrich-Heine University, Germany Open End AB (formerly AB Strakt), Sweden diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,6 +116,12 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + if "CFLAGS" in os.environ: + cflags = os.environ["CFLAGS"] + compiler.compiler.append(cflags) + compiler.compiler_so.append(cflags) + compiler.linker_so.append(cflags) + from sysconfig_cpython import ( parse_makefile, _variable_rx, expand_makefile_vars) diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. diff --git a/lib-python/2.7/test/test_tarfile.py b/lib-python/modified-2.7/test/test_tarfile.py copy from lib-python/2.7/test/test_tarfile.py copy to lib-python/modified-2.7/test/test_tarfile.py --- a/lib-python/2.7/test/test_tarfile.py +++ b/lib-python/modified-2.7/test/test_tarfile.py @@ -169,6 +169,7 @@ except tarfile.ReadError: self.fail("tarfile.open() failed on empty archive") self.assertListEqual(tar.getmembers(), []) + tar.close() def test_null_tarfile(self): # Test for issue6123: Allow opening empty archives. @@ -207,16 +208,21 @@ fobj = open(self.tarname, "rb") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, os.path.abspath(fobj.name)) + tar.close() def test_no_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) self.assertRaises(AttributeError, getattr, fobj, "name") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, None) def test_empty_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) fobj.name = "" tar = tarfile.open(fileobj=fobj, mode=self.mode) @@ -515,6 +521,7 @@ self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1") tarinfo = self.tar.getmember("pax/umlauts-�������") self._test_member(tarinfo, size=7011, chksum=md5_regtype) + self.tar.close() class LongnameTest(ReadTest): @@ -675,6 +682,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.rmdir(path) @@ -692,6 +700,7 @@ tar.gettarinfo(target) tarinfo = tar.gettarinfo(link) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(target) os.remove(link) @@ -704,6 +713,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(path) @@ -722,6 +732,7 @@ tar.add(dstname) os.chdir(cwd) self.assertTrue(tar.getnames() == [], "added the archive to itself") + tar.close() def test_exclude(self): tempdir = os.path.join(TEMPDIR, "exclude") @@ -742,6 +753,7 @@ tar = tarfile.open(tmpname, "r") self.assertEqual(len(tar.getmembers()), 1) self.assertEqual(tar.getnames()[0], "empty_dir") + tar.close() finally: shutil.rmtree(tempdir) @@ -859,7 +871,9 @@ fobj.close() elif self.mode.endswith("bz2"): dec = bz2.BZ2Decompressor() - data = open(tmpname, "rb").read() + f = open(tmpname, "rb") + data = f.read() + f.close() data = dec.decompress(data) self.assertTrue(len(dec.unused_data) == 0, "found trailing data") @@ -938,6 +952,7 @@ "unable to read longname member") self.assertEqual(tarinfo.linkname, member.linkname, "unable to read longname member") + tar.close() def test_longname_1023(self): self._test(("longnam/" * 127) + "longnam") @@ -1030,6 +1045,7 @@ else: n = tar.getmembers()[0].name self.assertTrue(name == n, "PAX longname creation failed") + tar.close() def test_pax_global_header(self): pax_headers = { @@ -1058,6 +1074,7 @@ tarfile.PAX_NUMBER_FIELDS[key](val) except (TypeError, ValueError): self.fail("unable to convert pax header field") + tar.close() def test_pax_extended_header(self): # The fields from the pax header have priority over the @@ -1077,6 +1094,7 @@ self.assertEqual(t.pax_headers, pax_headers) self.assertEqual(t.name, "foo") self.assertEqual(t.uid, 123) + tar.close() class UstarUnicodeTest(unittest.TestCase): @@ -1120,6 +1138,7 @@ tarinfo.name = "foo" tarinfo.uname = u"���" self.assertRaises(UnicodeError, tar.addfile, tarinfo) + tar.close() def test_unicode_argument(self): tar = tarfile.open(tarname, "r", encoding="iso8859-1", errors="strict") @@ -1174,6 +1193,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="ascii", errors=handler) self.assertEqual(tar.getnames()[0], name) + tar.close() self.assertRaises(UnicodeError, tarfile.open, tmpname, encoding="ascii", errors="strict") @@ -1186,6 +1206,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="iso8859-1", errors="utf-8") self.assertEqual(tar.getnames()[0], "���/" + u"�".encode("utf8")) + tar.close() class AppendTest(unittest.TestCase): @@ -1213,6 +1234,7 @@ def _test(self, names=["bar"], fileobj=None): tar = tarfile.open(self.tarname, fileobj=fileobj) self.assertEqual(tar.getnames(), names) + tar.close() def test_non_existing(self): self._add_testfile() @@ -1231,7 +1253,9 @@ def test_fileobj(self): self._create_testtar() - data = open(self.tarname).read() + f = open(self.tarname) + data = f.read() + f.close() fobj = StringIO.StringIO(data) self._add_testfile(fobj) fobj.seek(0) @@ -1257,7 +1281,9 @@ # Append mode is supposed to fail if the tarfile to append to # does not end with a zero block. def _test_error(self, data): - open(self.tarname, "wb").write(data) + f = open(self.tarname, "wb") + f.write(data) + f.close() self.assertRaises(tarfile.ReadError, self._add_testfile) def test_null(self): diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -48,7 +48,8 @@ return self.from_param(as_parameter) def get_ffi_param(self, value): - return self.from_param(value)._to_ffi_param() + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() def get_ffi_argtype(self): if self._ffiargtype: diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -328,12 +328,14 @@ "native COM method call without 'this' parameter" ) thisarg = cast(args[0], POINTER(POINTER(c_void_p))) - newargs, argtypes, outargs = self._convert_args(argtypes, args[1:], kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) newargs.insert(0, args[0].value) argtypes.insert(0, c_void_p) else: thisarg = None - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -437,16 +439,15 @@ @classmethod def _conv_param(cls, argtype, arg): if isinstance(argtype, _CDataMeta): - #arg = argtype.from_param(arg) - arg = argtype.get_ffi_param(arg) - return arg, argtype + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - return arg._to_ffi_param(), type(arg) + return arg, arg._to_ffi_param(), type(arg) # # non-usual case: we do the import here to save a lot of code in the # jit trace of the normal case @@ -463,11 +464,12 @@ else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj._to_ffi_param(), type(cobj) + return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] + keepalives = [] newargtypes = [] total = len(args) paramflags = self._paramflags @@ -495,7 +497,8 @@ val = defval if val is marker: val = 0 - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): @@ -511,28 +514,32 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - newarg, newargtype = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) + keepalive = None newarg = ctypes.byref(val) newargtype = type(newarg) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - newarg, newargtype = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) inargs_idx += 1 @@ -541,12 +548,13 @@ extra = args[len(newargs):] for i, arg in enumerate(extra): try: - newarg, newargtype = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) - return newargs, newargtypes, outargs + return keepalives, newargs, newargtypes, outargs def _wrap_result(self, restype, result): diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -29,7 +29,7 @@ PythonPickler.__init__(self, *args, **kw) def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): diff --git a/pypy/config/config.py b/pypy/config/config.py --- a/pypy/config/config.py +++ b/pypy/config/config.py @@ -81,6 +81,12 @@ (self.__class__, name)) return self._cfgimpl_values[name] + def __dir__(self): + from_type = dir(type(self)) + from_dict = list(self.__dict__) + extras = list(self._cfgimpl_values) + return sorted(set(extras + from_type + from_dict)) + def __delattr__(self, name): # XXX if you use delattr you are responsible for all bad things # happening diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -327,6 +327,9 @@ BoolOption("mutable_builtintypes", "Allow the changing of builtin types", default=False, requires=[("objspace.std.builtinshortcut", True)]), + BoolOption("withidentitydict", + "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not", + default=True), ]), ]) diff --git a/pypy/config/test/test_config.py b/pypy/config/test/test_config.py --- a/pypy/config/test/test_config.py +++ b/pypy/config/test/test_config.py @@ -63,6 +63,20 @@ py.test.raises(ConfigError, 'config.gc.name = "ref"') config.gc.name = "framework" +def test___dir__(): + descr = make_description() + config = Config(descr, bool=False) + attrs = dir(config) + assert '__repr__' in attrs # from the type + assert '_cfgimpl_values' in attrs # from self + assert 'gc' in attrs # custom attribute + assert 'objspace' in attrs # custom attribute + # + attrs = dir(config.gc) + assert 'name' in attrs + assert 'dummy' in attrs + assert 'float' in attrs + def test_arbitrary_option(): descr = OptionDescription("top", "", [ ArbitraryOption("a", "no help", default=None) diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -140,7 +140,10 @@ ["annotate", "rtype", "backendopt", "database", "source", "pyjitpl"], default=None, cmdline="--fork-before"), - + BoolOption("dont_write_c_files", + "Make the C backend write everyting to /dev/null. " + + "Useful for benchmarking, so you don't actually involve the disk", + default=False, cmdline="--dont-write-c-files"), ArbitraryOption("instrumentctl", "internal", default=None), StrOption("output", "Output file name", cmdline="--output"), diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -929,6 +929,19 @@ located in the ``py/bin/`` directory. For switches to modify test execution pass the ``-h`` option. +Coverage reports +---------------- + +In order to get coverage reports the `pytest-cov`_ plugin is included. +it adds some extra requirements ( coverage_ and `cov-core`_ ) +and can once they are installed coverage testing can be invoked via:: + + python test_all.py --cov file_or_direcory_to_cover file_or_directory + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov +.. _`coverage`: http://pypi.python.org/pypi/coverage +.. _`cov-core`: http://pypi.python.org/pypi/cov-core + Test conventions ---------------- diff --git a/pypy/doc/config/objspace.std.withidentitydict.txt b/pypy/doc/config/objspace.std.withidentitydict.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withidentitydict.txt @@ -0,0 +1,21 @@ +============================= +objspace.std.withidentitydict +============================= + +* **name:** withidentitydict + +* **description:** enable a dictionary strategy for "by identity" comparisons + +* **command-line:** --objspace-std-withidentitydict + +* **command-line for negation:** --no-objspace-std-withidentitydict + +* **option type:** boolean option + +* **default:** True + + +Enable a dictionary strategy specialized for instances of classes which +compares "by identity", which is the default unless you override ``__hash__``, +``__eq__`` or ``__cmp__``. This strategy will be used only with new-style +classes. diff --git a/pypy/doc/config/translation.dont_write_c_files.txt b/pypy/doc/config/translation.dont_write_c_files.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/translation.dont_write_c_files.txt @@ -0,0 +1,4 @@ +write the generated C files to ``/dev/null`` instead of to the disk. Useful if +you want to use translate.py as a benchmark and don't want to access the disk. + +.. _`translation documentation`: ../translation.html diff --git a/pypy/doc/config/translation.gc.txt b/pypy/doc/config/translation.gc.txt --- a/pypy/doc/config/translation.gc.txt +++ b/pypy/doc/config/translation.gc.txt @@ -1,4 +1,6 @@ -Choose the Garbage Collector used by the translated program: +Choose the Garbage Collector used by the translated program. +The good performing collectors are "hybrid" and "minimark". +The default is "minimark". - "ref": reference counting. Takes very long to translate and the result is slow. @@ -11,3 +13,12 @@ older generation. - "boehm": use the Boehm conservative GC. + + - "hybrid": a hybrid collector of "generation" together with a + mark-n-sweep old space + + - "markcompact": a slow, but memory-efficient collector, + influenced e.g. by Smalltalk systems. + + - "minimark": a generational mark-n-sweep collector with good + performance. Includes page marking for large arrays. diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -211,6 +211,38 @@ >>>> print d1['a'] 42 +Mutating classes of objects which are already used as dictionary keys +--------------------------------------------------------------------- + +Consider the following snippet of code:: + + class X(object): + pass + + def __evil_eq__(self, other): + print 'hello world' + return False + + def evil(y): + d = {x(): 1} + X.__eq__ = __evil_eq__ + d[y] # might trigger a call to __eq__? + +In CPython, __evil_eq__ **might** be called, although there is no way to write +a test which reliably calls it. It happens if ``y is not x`` and ``hash(y) == +hash(x)``, where ``hash(x)`` is computed when ``x`` is inserted into the +dictionary. If **by chance** the condition is satisfied, then ``__evil_eq__`` +is called. + +PyPy uses a special strategy to optimize dictionaries whose keys are instances +of user-defined classes which do not override the default ``__hash__``, +``__eq__`` and ``__cmp__``: when using this strategy, ``__eq__`` and +``__cmp__`` are never called, but instead the lookup is done by identity, so +in the case above it is guaranteed that ``__eq__`` won't be called. + +Note that in all other cases (e.g., if you have a custom ``__hash__`` and +``__eq__`` in ``y``) the behavior is exactly the same as CPython. + Ignored exceptions ----------------------- diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -19,12 +19,12 @@ section * Write them in pure python and use direct libffi low-level bindings, See - \_rawffi_ module description. + \_ffi_ module description. * Write them in RPython as mixedmodule_, using *rffi* as bindings. .. _ctypes: #CTypes -.. _\_rawffi: #LibFFI +.. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules CTypes @@ -42,41 +42,50 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. +ctypes call are optimized by the JIT and the resulting machine code contains a +direct call to the target C function. However, due to the very dynamic nature +of ctypes, some overhead over a bare C call is still present, in particular to +check/convert the types of the parameters. Moreover, even if most calls are +optimized, some cannot and thus need to follow the slow path, not optimized by +the JIT. + .. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure +.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html Pros ---- -Stable, CPython-compatible API +Stable, CPython-compatible API. Most calls are fast, optimized by JIT. Cons ---- -Only pure-python code (slow), problems with platform-dependency (although -we partially solve those). PyPy implementation is now very slow. +Problems with platform-dependency (although we partially solve +those). Although the JIT optimizes ctypes calls, some overhead is still +present. The slow-path is very slow. -_`CPython ctypes`: http://python.net/crew/theller/ctypes/ LibFFI ====== Mostly in order to be able to write a ctypes module, we developed a very -low-level libffi bindings. (libffi is a C-level library for dynamic calling, +low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling, which is used by CPython ctypes). This library provides stable and usable API, although it's API is a very low-level one. It does not contain any -magic. +magic. It is also optimized by the JIT, but has much less overhead than ctypes. Pros ---- -Works. Combines disadvantages of using ctypes with disadvantages of -using mixed modules. Probably more suitable for a delicate code -where ctypes magic goes in a way. +It Works. Probably more suitable for a delicate code where ctypes magic goes +in a way. All calls are optimized by the JIT, there is no slow path as in +ctypes. Cons ---- -Slow. CPython-incompatible API, very rough and low-level +It combines disadvantages of using ctypes with disadvantages of using mixed +modules. CPython-incompatible API, very rough and low-level. Mixed Modules ============= @@ -87,15 +96,15 @@ * a mixed module needs to be written in RPython, which is far more complicated than Python (XXX link) -* due to lack of separate compilation (as of April 2008), each +* due to lack of separate compilation (as of July 2011), each compilation-check requires to recompile whole PyPy python interpreter, which takes 0.5-1h. We plan to solve this at some point in near future. * although rpython is a garbage-collected language, the border between C and RPython needs to be managed by hand (each object that goes into the - C level must be explicitly freed) XXX we try to solve this + C level must be explicitly freed). -Some document is available `here`_ +Some documentation is available `here`_ .. _`here`: rffi.html diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -32,6 +32,24 @@ modules that relies on third-party libraries. See below how to get and build them. +Preping Windows for the Large Build +----------------------------------- + +Normally 32bit programs are limited to 2GB of memory on Windows. It is +possible to raise this limit, to 3GB on Windows 32bit, and almost 4GB +on Windows 64bit. + +On Windows 32bit, it is necessary to modify the system: follow +http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 +to enable the "3GB" feature, and reboot. This step is not necessary on +Windows 64bit. + +Then you need to execute:: + + editbin /largeaddressaware pypy.exe + +on the pypy.exe file you compiled. + Installing external packages ---------------------------- diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -27,9 +27,10 @@ _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset) -def parse_future(tree): +def parse_future(tree, feature_flags): future_lineno = 0 future_column = 0 + flags = 0 have_docstring = False body = None if isinstance(tree, ast.Module): @@ -37,7 +38,7 @@ elif isinstance(tree, ast.Interactive): body = tree.body if body is None: - return 0, 0 + return 0, 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): if have_docstring: @@ -48,11 +49,16 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset + for alias in stmt.names: + assert isinstance(alias, ast.alias) + # If this is an invalid flag, it will be caught later in + # codegen.py. + flags |= feature_flags.get(alias.name, 0) else: break else: break - return future_lineno, future_column + return flags, future_lineno, future_column class ForbiddenNameAssignment(Exception): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): @@ -925,6 +927,9 @@ return self.w_True return self.w_False + def issequence_w(self, w_obj): + return (self.findattr(w_obj, self.wrap("__getitem__")) is not None) + def isinstance_w(self, w_obj, w_type): return self.is_true(self.isinstance(w_obj, w_type)) @@ -1279,6 +1284,17 @@ self.wrap("expected a 32-bit integer")) return value + def truncatedint(self, w_obj): + # Like space.gateway_int_w(), but return the integer truncated + # instead of raising OverflowError. For obscure cases only. + try: + return self.int_w(w_obj) + except OperationError, e: + if not e.match(self, self.w_OverflowError): + raise + from pypy.rlib.rarithmetic import intmask + return intmask(self.bigint_w(w_obj).uintmask()) + def c_filedescriptor_w(self, w_fd): # This is only used sometimes in CPython, e.g. for os.fsync() but # not os.close(). It's likely designed for 'select'. It's irregular diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -31,7 +31,8 @@ _immutable_fields_ = ['code?', 'w_func_globals?', 'closure?', - 'defs_w?[*]'] + 'defs_w?[*]', + 'name?'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -140,6 +140,9 @@ def visit_c_nonnegint(self, el, app_sig): self.checked_space_method(el, app_sig) + def visit_truncatedint(self, el, app_sig): + self.checked_space_method(el, app_sig) + def visit__Wrappable(self, el, app_sig): name = el.__name__ argname = self.orig_arg() @@ -257,6 +260,9 @@ def visit_c_nonnegint(self, typ): self.run_args.append("space.c_nonnegint_w(%s)" % (self.scopenext(),)) + def visit_truncatedint(self, typ): + self.run_args.append("space.truncatedint(%s)" % (self.scopenext(),)) + def _make_unwrap_activation_class(self, unwrap_spec, cache={}): try: key = tuple(unwrap_spec) @@ -387,6 +393,9 @@ def visit_c_nonnegint(self, typ): self.unwrap.append("space.c_nonnegint_w(%s)" % (self.nextarg(),)) + def visit_truncatedint(self, typ): + self.unwrap.append("space.truncatedint(%s)" % (self.nextarg(),)) + def make_fastfunc(unwrap_spec, func): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) @@ -396,11 +405,14 @@ fastfunc = func else: # try to avoid excessive bloat - if func.__module__ == 'pypy.interpreter.astcompiler.ast': + mod = func.__module__ + if mod is None: + mod = "" + if mod == 'pypy.interpreter.astcompiler.ast': raise FastFuncNotSupported - if (not func.__module__.startswith('pypy.module.__builtin__') and - not func.__module__.startswith('pypy.module.sys') and - not func.__module__.startswith('pypy.module.math')): + if (not mod.startswith('pypy.module.__builtin__') and + not mod.startswith('pypy.module.sys') and + not mod.startswith('pypy.module.math')): if not func.__name__.startswith('descr'): raise FastFuncNotSupported d = {} diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,10 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - future_pos = misc.parse_future(node) + fut = misc.parse_future(node, self.future_flags.compiler_features) + f_flags, f_lineno, f_col = fut + future_pos = f_lineno, f_col + flags |= f_flags info = pyparse.CompileInfo(filename, mode, flags, future_pos) return self._compile_ast(node, info) diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -23,7 +23,7 @@ self.hasdict |= __base.hasdict self.weakrefable |= __base.weakrefable self.rawdict = {} - self.acceptable_as_base_class = True + self.acceptable_as_base_class = '__new__' in rawdict self.applevel_subclasses_base = None # xxx used by faking self.fakedcpytype = None @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -858,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -481,7 +481,7 @@ # rawstart = self.materialize_loop(original_loop_token) debug_start("jit-backend-addr") - debug_print("Bridge out of Guard %d has address %x to %x" % + debug_print("bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -464,7 +464,7 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ @@ -632,16 +632,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): @@ -44,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -58,10 +63,15 @@ expected = "\xE8" + struct.pack(' movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -5,10 +5,9 @@ from pypy.jit.codewriter import support from pypy.jit.codewriter.jitcode import JitCode -from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer -from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer -from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze -from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection +from pypy.jit.codewriter.effectinfo import (VirtualizableAnalyzer, + QuasiImmutAnalyzer, CanReleaseGILAnalyzer, effectinfo_from_writeanalyze, + EffectInfo, CallInfoCollection) from pypy.translator.simplify import get_funcobj, get_functype from pypy.rpython.lltypesystem import lltype, llmemory from pypy.translator.backendopt.canraise import RaiseAnalyzer @@ -32,6 +31,7 @@ self.readwrite_analyzer = ReadWriteAnalyzer(translator) self.virtualizable_analyzer = VirtualizableAnalyzer(translator) self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator) + self.canreleasegil_analyzer = CanReleaseGILAnalyzer(translator) # for index, jd in enumerate(jitdrivers_sd): jd.index = index @@ -219,7 +219,9 @@ assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect - can_invalidate = self.quasiimmut_analyzer.analyze(op) + can_release_gil = self.canreleasegil_analyzer.analyze(op) + # can_release_gil implies can_invalidate + can_invalidate = can_release_gil or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE @@ -235,7 +237,7 @@ # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, - oopspecindex, can_invalidate) + oopspecindex, can_invalidate, can_release_gil) # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -79,13 +79,15 @@ write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, - can_invalidate=False): + can_invalidate=False, can_release_gil=False): key = (frozenset(readonly_descrs_fields), frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, - oopspecindex) + oopspecindex, + can_invalidate, + can_release_gil) if key in cls._cache: return cls._cache[key] result = object.__new__(cls) @@ -100,6 +102,7 @@ result.write_descrs_arrays = write_descrs_arrays result.extraeffect = extraeffect result.can_invalidate = can_invalidate + result.can_release_gil = can_release_gil result.oopspecindex = oopspecindex cls._cache[key] = result return result @@ -111,12 +114,13 @@ return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE def has_random_effects(self): - return self.oopspecindex == self.OS_LIBFFI_CALL + return self.oopspecindex == self.OS_LIBFFI_CALL or self.can_release_gil def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, - can_invalidate=False): + can_invalidate=False, + can_release_gil=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: return None @@ -158,7 +162,8 @@ write_descrs_arrays, extraeffect, oopspecindex, - can_invalidate) + can_invalidate, + can_release_gil) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: @@ -194,6 +199,16 @@ def analyze_simple_operation(self, op, graphinfo): return op.opname == 'jit_force_quasi_immutable' +class CanReleaseGILAnalyzer(BoolGraphAnalyzer): + def analyze_direct_call(self, graph, seen=None): + releases_gil = False + if hasattr(graph, "func") and hasattr(graph.func, "_ptr"): + releases_gil = graph.func._ptr._obj.releases_gil + return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen) + + def analyze_simple_operation(self, op, graphinfo): + return False + # ____________________________________________________________ class CallInfoCollection(object): diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -788,13 +788,65 @@ raise NotImplementedError("cast_ptr_to_int") def rewrite_op_force_cast(self, op): - from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof + assert not self._is_gc(op.args[0]) + fromll = longlong.is_longlong(op.args[0].concretetype) + toll = longlong.is_longlong(op.result.concretetype) + if fromll and toll: + return + if fromll: + args = op.args + opname = 'truncate_longlong_to_int' + RESULT = lltype.Signed + v = varoftype(RESULT) + op1 = SpaceOperation(opname, args, v) + op2 = self.rewrite_operation(op1) + oplist = self.force_cast_without_longlong(op2.result, op.result) + if oplist: + return [op2] + oplist + # + # force a renaming to put the correct result in place, even though + # it might be slightly mistyped (e.g. Signed versus Unsigned) + assert op2.result is v + op2.result = op.result + return op2 + elif toll: + from pypy.rpython.lltypesystem import rffi + size, unsigned = rffi.size_and_sign(op.args[0].concretetype) + if unsigned: + INTERMEDIATE = lltype.Unsigned + else: + INTERMEDIATE = lltype.Signed + v = varoftype(INTERMEDIATE) + oplist = self.force_cast_without_longlong(op.args[0], v) + if not oplist: + v = op.args[0] + oplist = [] + if unsigned: + opname = 'cast_uint_to_longlong' + else: + opname = 'cast_int_to_longlong' + op1 = SpaceOperation(opname, [v], op.result) + op2 = self.rewrite_operation(op1) + return oplist + [op2] + else: + return self.force_cast_without_longlong(op.args[0], op.result) + + def force_cast_without_longlong(self, v_arg, v_result): + from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT from pypy.rlib.rarithmetic import intmask - assert not self._is_gc(op.args[0]) - size2, unsigned2 = size_and_sign(op.result.concretetype) - if size2 >= sizeof(lltype.Signed): + # + if (v_result.concretetype in (FLOAT, lltype.Float) or + v_arg.concretetype in (FLOAT, lltype.Float)): + assert (v_result.concretetype == lltype.Float and + v_arg.concretetype == lltype.Float), "xxx unsupported cast" + return + # + size2, unsigned2 = size_and_sign(v_result.concretetype) + assert size2 <= sizeof(lltype.Signed) + if size2 == sizeof(lltype.Signed): return # the target type is LONG or ULONG - size1, unsigned1 = size_and_sign(op.args[0].concretetype) + size1, unsigned1 = size_and_sign(v_arg.concretetype) + assert size1 <= sizeof(lltype.Signed) # def bounds(size, unsigned): if unsigned: @@ -807,22 +859,28 @@ return # the target type includes the source range # result = [] - v1 = op.args[0] if min2: c_min2 = Constant(min2, lltype.Signed) - v2 = Variable(); v2.concretetype = lltype.Signed - result.append(SpaceOperation('int_sub', [v1, c_min2], v2)) + v2 = varoftype(lltype.Signed) + result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2)) else: - v2 = v1 + v2 = v_arg c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed) - v3 = Variable(); v3.concretetype = lltype.Signed + v3 = varoftype(lltype.Signed) result.append(SpaceOperation('int_and', [v2, c_mask], v3)) if min2: - result.append(SpaceOperation('int_add', [v3, c_min2], op.result)) + result.append(SpaceOperation('int_add', [v3, c_min2], v_result)) else: - result[-1].result = op.result + result[-1].result = v_result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from @@ -906,30 +964,7 @@ rewrite_op_ullong_is_true = rewrite_op_llong_is_true def rewrite_op_cast_primitive(self, op): - fromll = longlong.is_longlong(op.args[0].concretetype) - toll = longlong.is_longlong(op.result.concretetype) - if fromll != toll: - args = op.args - if fromll: - opname = 'truncate_longlong_to_int' - RESULT = lltype.Signed - else: - from pypy.rpython.lltypesystem import rffi - if rffi.cast(op.args[0].concretetype, -1) < 0: - opname = 'cast_int_to_longlong' - else: - opname = 'cast_uint_to_longlong' - RESULT = lltype.SignedLongLong - v = varoftype(RESULT) - op1 = SpaceOperation(opname, args, v) - op2 = self.rewrite_operation(op1) - # - # force a renaming to put the correct result in place, even though - # it might be slightly mistyped (e.g. Signed versus Unsigned) - assert op2.result is v - op2.result = op.result - # - return op2 + return self.rewrite_op_force_cast(op) # ---------- # Renames, from the _old opname to the _new one. @@ -1106,6 +1141,9 @@ return meth(op, args, *descrs) def _get_list_nonneg_canraise_flags(self, op): + # XXX as far as I can see, this function will always return True + # because functions that are neither nonneg nor fast don't have an + # oopspec any more # xxx break of abstraction: func = get_funcobj(op.args[0].value)._callable # base hints on the name of the ll function, which is a bit xxx-ish @@ -1263,7 +1301,7 @@ calldescr = self.callcontrol.getcalldescr(op, oopspecindex, extraeffect) if extraeffect is not None: - assert (type(calldescr) is str # for tests + assert (is_test_calldescr(calldescr) # for tests or calldescr.get_extra_info().extraeffect == extraeffect) if isinstance(op.args[0].value, str): pass # for tests only @@ -1424,6 +1462,9 @@ return "using virtualizable array in illegal way in %r" % ( self.args[0],) +def is_test_calldescr(calldescr): + return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False) + def _with_prefix(prefix): result = {} for name in dir(Transformer): diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -96,6 +96,7 @@ def _try_coalesce(self, v, w): if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: + assert getkind(w.concretetype) == self.kind dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -390,7 +390,7 @@ ('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed), ('int_abs', [lltype.Signed], lltype.Signed), ('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float), - ] +] class LLtypeHelpers: diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py --- a/pypy/jit/codewriter/test/test_call.py +++ b/pypy/jit/codewriter/test/test_call.py @@ -1,6 +1,6 @@ import py from pypy.objspace.flow.model import SpaceOperation, Constant, Variable -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.unsimplify import varoftype from pypy.rlib import jit from pypy.jit.codewriter.call import CallControl @@ -171,3 +171,24 @@ def test_jit_force_virtualizable_effectinfo(): py.test.skip("XXX add a test for CallControl.getcalldescr() -> EF_xxx") + +def test_releases_gil_analyzer(): + from pypy.jit.backend.llgraph.runner import LLtypeCPU + + T = rffi.CArrayPtr(rffi.TIME_T) + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + + @jit.dont_look_inside + def f(): + return external(lltype.nullptr(T.TO)) + + rtyper = support.annotate(f, []) + jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) + cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) + res = cc.find_all_graphs(FakePolicy()) + + [f_graph] = [x for x in res if x.func is f] + [block, _] = list(f_graph.iterblocks()) + [op] = block.operations + call_descr = cc.getcalldescr(op) + assert call_descr.extrainfo.can_release_gil \ No newline at end of file diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -3,6 +3,7 @@ from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register from pypy.jit.codewriter.format import assert_format +from pypy.jit.codewriter import longlong from pypy.jit.metainterp.history import AbstractDescr from pypy.rpython.lltypesystem import lltype, rclass, rstr from pypy.objspace.flow.model import SpaceOperation, Variable, Constant @@ -30,6 +31,9 @@ 'float': FakeRegAlloc()} class FakeDescr(AbstractDescr): + _for_tests_only = True + def __init__(self, oopspecindex=None): + self.oopspecindex = oopspecindex def __repr__(self): return '' def as_vtable_size_descr(self): @@ -55,19 +59,24 @@ def arraydescrof(self, ARRAY): return FakeDescr() +class FakeCallInfoCollection: + def add(self, *args): + pass + class FakeCallControl: _descr_cannot_raise = FakeDescr() + callinfocollection = FakeCallInfoCollection() def guess_call_kind(self, op): return 'residual' - def getcalldescr(self, op): + def getcalldescr(self, op, oopspecindex=None, extraeffect=None): try: if 'cannot_raise' in op.args[0].value._obj.graph.name: return self._descr_cannot_raise except AttributeError: pass - return FakeDescr() + return FakeDescr(oopspecindex) def calldescr_canraise(self, calldescr): - return calldescr is not self._descr_cannot_raise + return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None def get_vinfo(self, VTYPEPTR): return None @@ -734,7 +743,9 @@ def test_force_cast(self): from pypy.rpython.lltypesystem import rffi - + # NB: we don't need to test for INT here, the logic in jtransform is + # general enough so that if we have the below cases it should + # generalize also to INT for FROM, TO, expected in [ (rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""), (rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"), @@ -797,12 +808,42 @@ expected = [s.strip() for s in expected.splitlines()] check_force_cast(FROM, TO, expected, 42) check_force_cast(FROM, TO, expected, -42) - expected.append('int_return %i' + str(len(expected))) - expected = '\n'.join(expected) + returnvar = "%i" + str(len(expected)) + expected.append('int_return ' + returnvar) + expectedstr = '\n'.join(expected) # def f(n): return rffi.cast(TO, n) - self.encoding_test(f, [rffi.cast(FROM, 42)], expected, + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + + if not longlong.is_64_bit: + if FROM in (rffi.LONG, rffi.ULONG): + if FROM == rffi.LONG: + FROM = rffi.LONGLONG + else: + FROM = rffi.ULONGLONG + expected.insert(0, + "residual_call_irf_i $<* fn llong_to_int>, , I[], R[], F[%f0] -> %i0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + elif TO in (rffi.LONG, rffi.ULONG): + if TO == rffi.LONG: + TO = rffi.LONGLONG + else: + TO = rffi.ULONGLONG + if rffi.cast(FROM, -1) < 0: + fnname = "llong_from_int" + else: + fnname = "llong_from_uint" + expected.pop() # remove int_return + expected.append( + "residual_call_irf_f $<* fn %s>, , I[%s], R[], F[] -> %%f0" + % (fnname, returnvar)) + expected.append("float_return %f0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, transform=True) def test_force_cast_pointer(self): @@ -813,6 +854,23 @@ int_return %i0 """, transform=True) + def test_force_cast_float(self): + from pypy.rpython.lltypesystem import rffi + def f(n): + return rffi.cast(lltype.Float, n) + self.encoding_test(f, [12.456], """ + float_return %f0 + """, transform=True) + + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py --- a/pypy/jit/codewriter/test/test_longlong.py +++ b/pypy/jit/codewriter/test/test_longlong.py @@ -37,7 +37,7 @@ class TestLongLong: def setup_class(cls): - if sys.maxint > 2147483647: + if longlong.is_64_bit: py.test.skip("only for 32-bit platforms") def do_check(self, opname, oopspecindex, ARGS, RESULT): @@ -46,6 +46,8 @@ op = SpaceOperation(opname, vlist, v_result) tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) op1 = tr.rewrite_operation(op) + if isinstance(op1, list): + [op1] = op1 # def is_llf(TYPE): return (TYPE == lltype.SignedLongLong or @@ -196,6 +198,23 @@ for T2 in [lltype.Signed, lltype.Unsigned]: self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT, [T1], T2) + self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT, + [T1], T2) + if T2 == lltype.Signed: + expected = EffectInfo.OS_LLONG_FROM_INT + else: + expected = EffectInfo.OS_LLONG_FROM_UINT + self.do_check('cast_primitive', expected, [T2], T1) + self.do_check('force_cast', expected, [T2], T1) + # + for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + vlist = [varoftype(T1)] + v_result = varoftype(T2) + op = SpaceOperation('force_cast', vlist, v_result) + tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) + op1 = tr.rewrite_operation(op) + assert op1 is None def test_constants(self): for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]: diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -61,7 +61,6 @@ optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble, retraced) - if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -73,7 +73,7 @@ assert self._lazy_setfield is None self._cached_fields[structvalue] = fieldvalue - def force_lazy_setfield(self, optheap): + def force_lazy_setfield(self, optheap, can_cache=True): op = self._lazy_setfield if op is not None: # This is the way _lazy_setfield is usually reset to None. @@ -83,12 +83,16 @@ self._cached_fields.clear() self._lazy_setfield = None optheap.next_optimization.propagate_forward(op) + if not can_cache: + return # Once it is done, we can put at least one piece of information # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) + elif not can_cache: + self._cached_fields.clear() def get_reconstructed(self, optimizer, valuemap): assert self._lazy_setfield is None @@ -202,20 +206,9 @@ for arraydescr in effectinfo.readonly_descrs_arrays: self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: - self.force_lazy_setfield(fielddescr) - try: - cf = self.cached_fields[fielddescr] - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setfield(fielddescr, can_cache=False) for arraydescr in effectinfo.write_descrs_arrays: - self.force_lazy_setarrayitem(arraydescr) - try: - submap = self.cached_arrayitems[arraydescr] - for cf in submap.itervalues(): - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setarrayitem(arraydescr, can_cache=False) if effectinfo.check_forces_virtual_or_virtualizable(): vrefinfo = self.optimizer.metainterp_sd.virtualref_info self.force_lazy_setfield(vrefinfo.descr_forced) @@ -238,20 +231,20 @@ if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] - def force_lazy_setfield(self, descr): + def force_lazy_setfield(self, descr, can_cache=True): try: cf = self.cached_fields[descr] except KeyError: return - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) - def force_lazy_setarrayitem(self, arraydescr): + def force_lazy_setarrayitem(self, arraydescr, can_cache=True): try: submap = self.cached_arrayitems[arraydescr] except KeyError: return for cf in submap.values(): - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes @@ -387,7 +380,7 @@ cf.do_setfield(self, op) else: # variable index, so make sure the lazy setarrayitems are done - self.force_lazy_setarrayitem(op.getdescr()) + self.force_lazy_setarrayitem(op.getdescr(), can_cache=False) # and then emit the operation self.emit_operation(op) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -199,6 +199,7 @@ )) return self.emit_operation(op) + self.pure(rop.FLOAT_MUL, [arg2, arg1], op.result) def optimize_FLOAT_NEG(self, op): v1 = op.getarg(0) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1755,6 +1755,48 @@ """ self.optimize_loop(ops, expected) + def test_duplicate_getarrayitem_after_setarrayitem_bug(self): + ops = """ + [p0, i0, i1] + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i6 = int_add(i0, 1) + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + + def test_duplicate_getarrayitem_after_setarrayitem_bug2(self): + ops = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + def test_bug_1(self): ops = """ [i0, p1] @@ -3916,11 +3958,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3941,9 +3980,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3962,10 +3999,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -3987,14 +4023,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -4010,10 +4041,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4131,9 +4160,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -4178,11 +4205,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4374,11 +4398,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -4532,6 +4553,39 @@ """ self.optimize_loop(ops, expected) + def test_strslice_subtraction_folds(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + + def test_float_mul_reversed(self): + ops = """ + [f0, f1] + f2 = float_mul(f0, f1) + f3 = float_mul(f1, f0) + jump(f2, f3) + """ + expected = """ + [f0, f1] + f2 = float_mul(f0, f1) + jump(f2, f2) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2820,11 +2820,11 @@ def test_residual_call_invalidate_some_arrays(self): ops = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) - p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p2, 0, descr=arraydescr2) p6 = getarrayitem_gc(p2, 1, descr=arraydescr2) i4 = getarrayitem_gc(p1, 1, descr=arraydescr) escape(p3) @@ -2837,7 +2837,7 @@ """ expected = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) @@ -5082,11 +5082,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5107,9 +5104,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5128,10 +5123,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5153,14 +5147,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -5176,10 +5165,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5303,9 +5290,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -5411,11 +5396,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5609,11 +5591,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -21,6 +21,7 @@ continue if hasattr(Class, name_prefix + name): opclass = resoperation.opclasses[getattr(rop, name)] + assert name in opclass.__name__ result.append((value, opclass, getattr(Class, name_prefix + name))) return unrolling_iterable(result) diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -61,7 +61,7 @@ self.ensure_nonnull() box = self.force_box() lengthbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) + optimization.optimize_default(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -72,13 +72,13 @@ else: return None - def string_copy_parts(self, optimization, targetbox, offsetbox, mode): + def string_copy_parts(self, optimizer, targetbox, offsetbox, mode): # Copies the pointer-to-string 'self' into the target string # given by 'targetbox', at the specified offset. Returns the offset # at the end of the copy. - lengthbox = self.getstrlen(optimization, mode) + lengthbox = self.getstrlen(optimizer, mode) srcbox = self.force_box() - return copy_str_content(optimization, srcbox, targetbox, + return copy_str_content(optimizer, srcbox, targetbox, CONST_0, offsetbox, lengthbox, mode) @@ -335,7 +335,7 @@ if optimizer is None: return None resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_ADD, [box1, box2], resbox)) return resbox def _int_sub(optimizer, box1, box2): @@ -345,10 +345,10 @@ if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimization, strbox, indexbox, mode): +def _strgetitem(optimizer, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimizer.optimize_default(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -440,7 +440,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) + resbox = _strgetitem(self.optimizer, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): @@ -450,7 +450,7 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode) + lengthbox = value.getstrlen(self.optimizer, mode) self.make_equal_to(op.result, self.getvalue(lengthbox)) def optimize_CALL(self, op): diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -391,8 +391,21 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): - return self.execute_with_descr(rop.GETARRAYITEM_GC, + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache and isinstance(indexbox, ConstInt): + index = indexbox.getint() + frombox, tobox = cache.get(index, (None, None)) + if frombox is arraybox: + return tobox + resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) + if isinstance(indexbox, ConstInt): + if not cache: + cache = self.metainterp.heap_array_cache[arraydescr] = {} + index = indexbox.getint() + cache[index] = arraybox, resbox + return resbox + opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any @@ -420,6 +433,13 @@ indexbox, itembox): self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, itembox) + if isinstance(indexbox, ConstInt): + cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {}) + cache[indexbox.getint()] = arraybox, itembox + else: + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache: + cache.clear() opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any @@ -455,21 +475,17 @@ def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, - sbox, sizebox) + self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox) abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, sizebox) - self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, - sbox, abox) + self._opimpl_setfield_gc_any(sbox, itemsdescr, abox) return sbox @arguments("box", "descr", "descr", "box") def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox) opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any @@ -478,10 +494,9 @@ @arguments("box", "descr", "descr", "box", "box") def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, - indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox, + valuebox) opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any @@ -503,14 +518,16 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC, box, fielddescr) opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @arguments("box", "descr") def _opimpl_getfield_gc_pure_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_PURE, box, fielddescr) opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any @@ -523,6 +540,15 @@ opimpl_getinteriorfield_gc_f = _opimpl_getinteriorfield_gc_any opimpl_getinteriorfield_gc_r = _opimpl_getinteriorfield_gc_any + @specialize.arg(1) + def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(opnum, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox + @arguments("orgpc", "box", "descr") def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr): ginfo = self.metainterp.jitdriver_sd.greenfield_info @@ -541,7 +567,11 @@ @arguments("box", "descr", "box") def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box and tobox is valuebox: + return self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + self.metainterp.heap_cache[fielddescr] = (box, valuebox) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any @@ -614,12 +644,16 @@ standard_box = self.metainterp.virtualizable_boxes[-1] if standard_box is box: return False + if box in self.metainterp.nonstandard_virtualizables: + return True eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None, box, standard_box) eqbox = self.implement_guard_value(pc, eqbox) isstandard = eqbox.getint() if isstandard: self.metainterp.replace_box(box, standard_box) + else: + self.metainterp.nonstandard_virtualizables[box] = None return not isstandard def _get_virtualizable_field_index(self, fielddescr): @@ -631,7 +665,7 @@ @arguments("orgpc", "box", "descr") def _opimpl_getfield_vable(self, pc, box, fielddescr): if self._nonstandard_virtualizable(pc, box): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any(box, fielddescr) self.metainterp.check_synchronized_virtualizable() index = self._get_virtualizable_field_index(fielddescr) return self.metainterp.virtualizable_boxes[index] @@ -643,8 +677,7 @@ @arguments("orgpc", "box", "descr", "box") def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox): if self._nonstandard_virtualizable(pc, box): - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) - return + return self._opimpl_setfield_gc_any(box, fielddescr, valuebox) index = self._get_virtualizable_field_index(fielddescr) self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -674,10 +707,8 @@ @arguments("orgpc", "box", "descr", "descr", "box") def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr, - arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox) self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) return self.metainterp.virtualizable_boxes[index] @@ -690,10 +721,9 @@ def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox, valuebox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - self.execute_with_descr(rop.SETARRAYITEM_GC, adescr, - arraybox, indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + self._opimpl_setarrayitem_gc_any(arraybox, adescr, + indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -707,8 +737,7 @@ @arguments("orgpc", "box", "descr", "descr") def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -1474,6 +1503,14 @@ self.call_pure_results = args_dict_box() # contains boxes where the class is already known self.known_class_boxes = {} + # contains frame boxes that are not virtualizables + self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1649,10 +1686,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1815,6 +1869,9 @@ def reached_loop_header(self, greenboxes, redboxes, resumedescr): self.known_class_boxes = {} + self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} + self.heap_array_cache = {} duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), @@ -2322,6 +2379,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -11,7 +11,7 @@ from pypy import conftest from pypy.rlib.rarithmetic import ovfcheck from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -984,11 +984,14 @@ pass class B(A): pass + @dont_look_inside + def extern(n): + if n: + return A() + else: + return B() def fn(n): - if n: - obj = A() - else: - obj = B() + obj = extern(n) return isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res @@ -1021,68 +1024,6 @@ res = self.meta_interp(main, []) assert res == 55 - def test_dont_record_repeated_guard_class(self): - class A: - pass - class B(A): - pass - a = A() - b = B() - def fn(n): - if n == -7: - obj = None - elif n: - obj = a - else: - obj = b - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=1, guard_nonnull=1) - res = self.interp_operations(fn, [1]) - assert not res - - def test_dont_record_guard_class_after_new(self): - class A: - pass - class B(A): - pass - def fn(n): - if n == -7: - obj = None - elif n: - obj = A() - else: - obj = B() - return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) - res = self.interp_operations(fn, [0]) - assert res == 4 - self.check_operations_history(guard_class=0, guard_nonnull=0) - res = self.interp_operations(fn, [1]) - assert not res - - def test_guard_isnull_nullifies(self): - class A: - pass - a = A() - a.x = None - def fn(n): - if n == -7: - a.x = "" - obj = a.x - res = 0 - if not obj: - res += 1 - if obj: - res += 1 - if obj is None: - res += 1 - if obj is not None: - res += 1 - return res - res = self.interp_operations(fn, [0]) - assert res == 2 - self.check_operations_history(guard_isnull=1) def test_assert_isinstance(self): class A: @@ -1244,7 +1185,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: @@ -1612,8 +1553,6 @@ assert res == 1 def test_raw_malloc_and_access(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Signed) def f(n): @@ -1627,8 +1566,6 @@ assert res == 10 def test_raw_malloc_and_access_float(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Float) def f(n, f): @@ -2377,7 +2314,7 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? - def test_retrace_ending_up_retrazing_another_loop(self): + def test_retrace_ending_up_retracing_another_loop(self): myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) bytecode = "0+sI0+SI" @@ -2615,5 +2552,57 @@ self.meta_interp(f, [], enable_opts='') self.check_loops(new_with_vtable=1) + def test_release_gil_flush_heap_cache(self): + T = rffi.CArrayPtr(rffi.TIME_T) + + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + # Not a real lock, has all the same properties with respect to GIL + # release though, so good for this test. + class Lock(object): + @dont_look_inside + def acquire(self): + external(lltype.nullptr(T.TO)) + @dont_look_inside + def release(self): + external(lltype.nullptr(T.TO)) + class X(object): + def __init__(self, idx): + self.field = idx + @dont_look_inside + def get_obj(z): + return X(z) + myjitdriver = JitDriver(greens=[], reds=["n", "l", "z", "lock"]) + def f(n, z): + lock = Lock() + l = 0 + while n > 0: + myjitdriver.jit_merge_point(lock=lock, l=l, n=n, z=z) + x = get_obj(z) + l += x.field + lock.acquire() + # This must not reuse the previous one. + n -= x.field + lock.release() + return n + res = self.meta_interp(f, [10, 1]) + self.check_loops(getfield_gc=2) + assert res == f(10, 1) + + def test_jit_merge_point_with_raw_pointer(self): + driver = JitDriver(greens = [], reds = ['n', 'x']) + + TP = lltype.Array(lltype.Signed, hints={'nolength': True}) + + def f(n): + x = lltype.malloc(TP, 10, flavor='raw') + x[0] = 1 + while n > 0: + driver.jit_merge_point(n=n, x=x) + n -= x[0] + lltype.free(x, flavor='raw') + return n + + self.meta_interp(f, [10], repeat=3) + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,407 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + l = [1] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * (4 + a) + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + len(frame.l) + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ @@ -1133,6 +1133,7 @@ res = self.meta_interp(f, [10]) assert res == 55 self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True) + self.check_history(ptr_eq=2) def test_virtual_child_frame_with_arrays(self): myjitdriver = JitDriver(greens = [], reds = ['frame'], diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -10,6 +10,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import fatalerror +from pypy.rlib.rstackovf import StackOverflow from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function @@ -408,6 +409,15 @@ jd.warmstate = state def crash_in_jit(e): + try: + raise e + except JitException: + raise # go through + except MemoryError: + raise # go through + except StackOverflow: + raise # go through + except Exception, e: if not we_are_translated(): print "~~~ Crash in JIT!" print '~~~ %s: %s' % (e.__class__, e) @@ -421,8 +431,6 @@ def maybe_enter_jit(*args): try: maybe_compile_and_run(state.increment_threshold, *args) - except JitException: - raise # go through except Exception, e: crash_in_jit(e) maybe_enter_jit._always_inline_ = True diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -138,6 +138,9 @@ refvalue = cpu.ts.cast_to_ref(value) cpu.set_future_value_ref(j, refvalue) elif typecode == 'int': + if isinstance(lltype.typeOf(value), lltype.Ptr): + intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value)) + else: intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) elif typecode == 'float': diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py --- a/pypy/module/__builtin__/compiling.py +++ b/pypy/module/__builtin__/compiling.py @@ -5,7 +5,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError from pypy.interpreter.astcompiler import consts, ast -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec @unwrap_spec(filename=str, mode=str, flags=int, dont_inherit=int) def compile(space, w_source, filename, mode, flags=0, dont_inherit=0): diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py --- a/pypy/module/__builtin__/descriptor.py +++ b/pypy/module/__builtin__/descriptor.py @@ -1,12 +1,10 @@ - -from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.function import StaticMethod, ClassMethod from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.descroperation import object_getattribute, object_setattr -from pypy.interpreter.function import StaticMethod, ClassMethod -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \ - descr_set_dict, interp_attrproperty_w, generic_new_descr +from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w, + generic_new_descr) +from pypy.objspace.descroperation import object_getattribute class W_Super(Wrappable): def __init__(self, space, w_starttype, w_objtype, w_self): diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -4,13 +4,12 @@ """ from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import NoneNotWrapped, applevel +from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.objectmodel import specialize -from inspect import getsource, getfile from pypy.rlib.rbigint import rbigint @@ -662,7 +661,6 @@ def descr_reduce(self): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns space = self.space w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -1,11 +1,9 @@ import new from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import NoneNotWrapped, applevel, interp2app +from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict -from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, descr_set_dict from pypy.rlib.objectmodel import compute_identity_hash from pypy.rlib.debug import make_sure_not_resized from pypy.rlib import jit diff --git a/pypy/module/__builtin__/interp_memoryview.py b/pypy/module/__builtin__/interp_memoryview.py --- a/pypy/module/__builtin__/interp_memoryview.py +++ b/pypy/module/__builtin__/interp_memoryview.py @@ -2,7 +2,7 @@ Implementation of the 'buffer' and 'memoryview' types. """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter import gateway, buffer +from pypy.interpreter import buffer from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -4,12 +4,10 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.runicode import UNICHR from pypy.rlib.rfloat import isnan, isinf, round_double from pypy.rlib import rfloat -import math import __builtin__ NoneNotWrapped = gateway.NoneNotWrapped diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -25,6 +25,7 @@ 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', 'lookup_special' : 'interp_magic.lookup_special', + 'do_what_I_mean' : 'interp_magic.do_what_I_mean', } submodules = { diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,5 +1,4 @@ -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib import debug, jit diff --git a/pypy/module/__pypy__/interp_identitydict.py b/pypy/module/__pypy__/interp_identitydict.py --- a/pypy/module/__pypy__/interp_identitydict.py +++ b/pypy/module/__pypy__/interp_identitydict.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app from pypy.interpreter.baseobjspace import Wrappable class W_IdentityDict(Wrappable): diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -70,3 +70,6 @@ if w_descr is None: return space.w_None return space.get(w_descr, w_obj) + +def do_what_I_mean(space): + return space.wrap(42) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -49,3 +49,8 @@ class X: pass raises(TypeError, lookup_special, X(), "foo") + + def test_do_what_I_mean(self): + from __pypy__ import do_what_I_mean + x = do_what_I_mean() + assert x == 42 diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -186,6 +186,11 @@ mod = self.get_ast("from __future__ import with_statement; import y; " \ "from __future__ import nested_scopes") raises(SyntaxError, compile, mod, "", "exec") + mod = self.get_ast("from __future__ import division\nx = 1/2") + co = compile(mod, "", "exec") + ns = {} + exec co in ns + assert ns["x"] == .5 def test_field_attr_writable(self): import _ast as ast diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.objectmodel import we_are_translated class CodecState(object): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -1,9 +1,8 @@ -import sys -from pypy.interpreter.baseobjspace import Wrappable, Arguments +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, \ operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi @@ -83,7 +82,6 @@ def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P types = [ # note: most of the type name directly come from the C equivalent, # with the exception of bytes: in C, ubyte and char are equivalent, @@ -149,6 +147,12 @@ raise OperationError(space.w_TypeError, space.wrap(msg)) return res +def unwrap_truncate_int(TP, space, w_arg): + if space.is_true(space.isinstance(w_arg, space.w_int)): + return rffi.cast(TP, space.int_w(w_arg)) + else: + return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask()) +unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)' # ======================================================================== @@ -181,15 +185,14 @@ # note that we must check for longlong first, because either # is_signed or is_unsigned returns true anyway assert libffi.IS_32_BIT - kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind - self.arg_longlong(space, argchain, kind, w_arg) + self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): - argchain.arg(space.int_w(w_arg)) + argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) elif w_argtype.is_unsigned(): - argchain.arg(intmask(space.uint_w(w_arg))) + argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg)) elif w_argtype.is_char(): w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) @@ -220,15 +223,10 @@ return w_arg @jit.dont_look_inside - def arg_longlong(self, space, argchain, kind, w_arg): + def arg_longlong(self, space, argchain, w_arg): bigarg = space.bigint_w(w_arg) - if kind == 'I': - llval = bigarg.tolonglong() - elif kind == 'U': - ullval = bigarg.toulonglong() + ullval = bigarg.ulonglongmask() llval = rffi.cast(rffi.LONGLONG, ullval) - else: - assert False # this is a hack: we store the 64 bits of the long long into the # 64 bits of a float (i.e., a C double) floatval = libffi.longlong2float(llval) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -111,7 +111,6 @@ types.double) assert pow(2, 3) == 8 - def test_int_args(self): """ DLLEXPORT int sum_xy(int x, int y) @@ -119,10 +118,12 @@ return x+y; } """ + import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint) assert sum_xy(30, 12) == 42 + assert sum_xy(sys.maxint*2, 0) == -2 def test_void_result(self): """ @@ -247,6 +248,9 @@ types.ulong) assert sum_xy(sys.maxint, 12) == sys.maxint+12 assert sum_xy(sys.maxint+1, 12) == sys.maxint+13 + # + res = sum_xy(sys.maxint*2+3, 0) + assert res == 1 def test_unsigned_short_args(self): """ @@ -375,6 +379,9 @@ res = sum_xy(x, y) expected = maxint64 + 3 assert res == expected + # + res = sum_xy(maxint64*2+3, 0) + assert res == 1 def test_byval_argument(self): """ diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -43,11 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,12 +3,10 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.gateway import ObjSpace -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -import os def wrap_streamerror(space, e, w_filename=None): if isinstance(e, streamio.StreamError): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -4,7 +4,6 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.buffer import RWBuffer -from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstring import StringBuilder from pypy.rlib.rarithmetic import r_longlong, intmask from pypy.tool.sourcetools import func_renamer diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py --- a/pypy/module/_io/interp_fileio.py +++ b/pypy/module/_io/interp_fileio.py @@ -1,5 +1,4 @@ -from pypy.interpreter.typedef import ( - TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty) +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 from pypy.rlib.rarithmetic import r_longlong diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -6,7 +6,6 @@ TypeDef, interp_attrproperty, generic_new_descr) from pypy.module.exceptions.interp_exceptions import W_IOError from pypy.module._io.interp_fileio import W_FileIO -from pypy.module._io.interp_iobase import W_IOBase from pypy.module._io.interp_textio import W_TextIOWrapper from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -57,6 +57,11 @@ def __del__(self): self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + + def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -4,7 +4,7 @@ generic_new_descr) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint from pypy.rlib.rbigint import rbigint from pypy.rlib.rstring import UnicodeBuilder diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py --- a/pypy/module/_locale/interp_locale.py +++ b/pypy/module/_locale/interp_locale.py @@ -1,4 +1,3 @@ -from pypy.rpython.tool import rffi_platform as platform from pypy.rlib import rposix from pypy.rlib.rarithmetic import intmask diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -2,12 +2,10 @@ """ The ffi for rpython, need to be imported for side effects """ -import sys from pypy.rpython.lltypesystem import rffi from pypy.rpython.lltypesystem import lltype from pypy.rpython.tool import rffi_platform from pypy.rpython.extfunc import register_external -from pypy.rpython.extregistry import ExtRegistryEntry from pypy.module._minimal_curses import interp_curses from pypy.translator.tool.cbuild import ExternalCompilationInfo diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -1,4 +1,4 @@ -import py, sys +import py from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -4,7 +4,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import ( OperationError, wrap_oserror, operationerrfmt) -from pypy.rpython.lltypesystem import rffi, lltype, llmemory +from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll import sys diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -15,7 +15,6 @@ if sys.platform == 'win32': from pypy.rlib import rwin32 - from pypy.interpreter.error import wrap_windowserror from pypy.module._multiprocessing.interp_win32 import ( handle_w, _GetTickCount) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -8,7 +8,6 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec -from pypy.objspace.std.dicttype import dictiter_typedef from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,10 +2,10 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rpython.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import get_elem, push_elem +from pypy.module._rawffi.array import push_elem from pypy.module._rawffi.structure import W_Structure -from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \ - wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes +from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, + unwrap_value, unpack_argshapes) from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL from pypy.rlib.clibffi import ffi_type_void from pypy.rlib import rweakref diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -1,7 +1,6 @@ -import sys from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib.clibffi import * @@ -15,7 +14,7 @@ from pypy.rlib import rwin32 from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.tracker import tracker TYPEMAP = { diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py --- a/pypy/module/_socket/interp_func.py +++ b/pypy/module/_socket/interp_func.py @@ -1,9 +1,8 @@ -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._socket.interp_socket import converted_error, W_RSocket from pypy.rlib import rsocket from pypy.rlib.rsocket import SocketError -from pypy.rlib.rarithmetic import r_uint -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError def gethostname(space): """gethostname() -> string diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,7 +1,7 @@ from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError -from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -11,7 +11,6 @@ from pypy.module._socket import interp_socket -import sys ## user defined constants X509_NAME_MAXLEN = 256 diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -15,13 +15,10 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import StaticMethod from pypy.module._stackless.stackless_flags import StacklessFlags from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py --- a/pypy/module/_stackless/interp_stackless.py +++ b/pypy/module/_stackless/interp_stackless.py @@ -1,9 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError -from pypy.rlib.rarithmetic import intmask import os diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py --- a/pypy/module/_stackless/rclonable.py +++ b/pypy/module/_stackless/rclonable.py @@ -1,7 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.rlib.objectmodel import we_are_translated -from pypy.interpreter.error import OperationError class InterpClonableMixin: diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,16 +1,15 @@ import py -from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.interpreter.typedef import GetSetProperty, TypeDef +from pypy.interpreter.typedef import TypeDef from pypy.rlib import jit import weakref class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 @@ -23,8 +22,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,11 +119,8 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: + assert isinstance(w_self, W_WeakrefBase) w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) def descr__repr__(self, space): w_obj = self.dereference() diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -1,6 +1,5 @@ from __future__ import with_statement from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError, wrap_windowserror diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,10 +1,9 @@ from __future__ import with_statement -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object from pypy.objspace.std.multimethod import FailedToImplement @@ -572,10 +571,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): diff --git a/pypy/module/binascii/interp_crc32.py b/pypy/module/binascii/interp_crc32.py --- a/pypy/module/binascii/interp_crc32.py +++ b/pypy/module/binascii/interp_crc32.py @@ -61,7 +61,7 @@ crc_32_tab = map(r_uint, crc_32_tab) - at unwrap_spec(data='bufferstr', oldcrc='c_int') + at unwrap_spec(data='bufferstr', oldcrc='truncatedint') def crc32(space, data, oldcrc=0): "Compute the CRC-32 incrementally." diff --git a/pypy/module/binascii/test/test_binascii.py b/pypy/module/binascii/test/test_binascii.py --- a/pypy/module/binascii/test/test_binascii.py +++ b/pypy/module/binascii/test/test_binascii.py @@ -374,6 +374,8 @@ ('x', 10000, -1855256896), ('y', 10000, -429115818), ('z', 10000, 2137352172), + ('foo', 99999999999999999999999999, -1932704816), + ('bar', -99999999999999999999999999, 2000545409), ]: assert self.binascii.crc32(input, initial) == expected diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -4,9 +4,8 @@ from pypy.rpython.lltypesystem import lltype from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.rlib.streamio import Stream from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform as compiler diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -133,6 +133,7 @@ bz2f.seek(0) assert bz2f.tell() == 0 + del bz2f # delete from this frame, which is captured in the traceback def test_open_close_del(self): from bz2 import BZ2File @@ -246,11 +247,18 @@ assert text_read == self.TEXT bz2f.close() + def test_silently_closes(self): + from bz2 import BZ2File + self.create_broken_temp_file() + BZ2File(self.temppath) + # check that no C-level malloc is left behind + def test_read_broken_file(self): from bz2 import BZ2File self.create_broken_temp_file() bz2f = BZ2File(self.temppath) raises(EOFError, bz2f.read) + del bz2f # delete from this frame, which is captured in the traceback def test_subsequent_read_broken_file(self): from bz2 import BZ2File @@ -264,6 +272,7 @@ raise Exception("should generate EOFError earlier") except EOFError: pass + del bz2f # delete from this frame, which is captured in the traceback def test_read_chunk10(self): from bz2 import BZ2File @@ -416,6 +425,7 @@ bz2f.close() bz2f = BZ2File(self.temppath, 'r') assert bz2f.read() == self.random_data + del bz2f # delete from this frame, which is captured in the traceback def test_context_manager(self): from bz2 import BZ2File diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -1,4 +1,3 @@ -import sys from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py --- a/pypy/module/cmath/interp_cmath.py +++ b/pypy/module/cmath/interp_cmath.py @@ -5,7 +5,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import NoneNotWrapped -from pypy.module.cmath import Module, names_and_docstrings +from pypy.module.cmath import names_and_docstrings from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG from pypy.module.cmath.constant import M_LN2, M_LN10 diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py --- a/pypy/module/cpyext/cdatetime.py +++ b/pypy/module/cpyext/cdatetime.py @@ -1,8 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib.objectmodel import we_are_translated -from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef -from pypy.module.cpyext.api import ( - cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields) +from pypy.module.cpyext.pyobject import PyObject, make_ref +from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct, + PyObjectFields) from pypy.module.cpyext.import_ import PyImport_Import from pypy.module.cpyext.typeobject import PyTypeObjectPtr from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py --- a/pypy/module/cpyext/complexobject.py +++ b/pypy/module/cpyext/complexobject.py @@ -1,7 +1,6 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.module.cpyext.api import ( cpython_api, cpython_struct, PyObject, build_type_checkers) -from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.floatobject import PyFloat_AsDouble from pypy.objspace.std.complexobject import W_ComplexObject from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.1" /* PyPy version as a string */ -#define PYPY_VERSION "1.5.0" +#define PYPY_VERSION "1.6.0" /* Subversion Revision number of this file (not of the repository) */ #define PY_PATCHLEVEL_REVISION "$Revision: 77872 $" diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -22,7 +22,7 @@ def PySequence_Check(space, w_obj): """Return 1 if the object provides sequence protocol, and 0 otherwise. This function always succeeds.""" - return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None) + return int(space.issequence_w(w_obj)) @cpython_api([PyObject], Py_ssize_t, error=-1) def PySequence_Size(space, w_obj): diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -268,3 +268,7 @@ if errors: w_errors = space.wrap(rffi.charp2str(errors)) return space.call_method(w_str, 'encode', w_encoding, w_errors) + + at cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -287,3 +287,9 @@ def test_eq(self, space, api): assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'ab' diff --git a/pypy/module/crypt/interp_crypt.py b/pypy/module/crypt/interp_crypt.py --- a/pypy/module/crypt/interp_crypt.py +++ b/pypy/module/crypt/interp_crypt.py @@ -1,6 +1,5 @@ -from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.rpython.lltypesystem import rffi, lltype +from pypy.rpython.lltypesystem import rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo import sys diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -73,9 +73,8 @@ """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w,\ - GetSetProperty, interp_attrproperty, descr_get_dict, descr_set_dict,\ - descr_del_dict +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict, + descr_set_dict, descr_del_dict) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError from pypy.rlib import rwin32 diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -11,9 +11,8 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.eval import Code from pypy.interpreter.pycode import PyCode -from pypy.rlib import streamio, jit, rposix +from pypy.rlib import streamio, jit from pypy.rlib.streamio import StreamErrors -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -3,9 +3,9 @@ from pypy.rlib import streamio from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.module import Module -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import struct + def get_suffixes(space): w = space.wrap diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,7 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.rarithmetic import ovfcheck class W_Count(Wrappable): diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -1,10 +1,8 @@ -from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask from pypy.rlib import rstackovf from pypy.module._file.interp_file import W_File -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import sys + Py_MARSHAL_VERSION = 2 diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -15,14 +15,22 @@ # ufuncs 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', + 'add': 'interp_ufuncs.add', 'copysign': 'interp_ufuncs.copysign', + 'divide': 'interp_ufuncs.divide', 'exp': 'interp_ufuncs.exp', + 'fabs': 'interp_ufuncs.fabs', 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', + 'multiply': 'interp_ufuncs.multiply', 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'subtract': 'interp_ufuncs.subtract', + 'sin': 'interp_ufuncs.sin', + 'cos': 'interp_ufuncs.cos', + 'tan': 'interp_ufuncs.tan', } appleveldefs = { diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -3,7 +3,7 @@ It should not be imported by the module itself """ -from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray class BogusBytecode(Exception): pass @@ -18,6 +18,14 @@ def wrap(self, x): return x + def issequence_w(self, w_obj): + # Completley wrong in the general case, but good enough for this. + return isinstance(w_obj, BaseArray) + + def float_w(self, w_obj): + assert isinstance(w_obj, float) + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() stack = [] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,54 +1,36 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy.interp_support import Signature +from pypy.module.micronumpy import interp_ufuncs +from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit +from pypy.rlib.rfloat import DTSF_STR_PRECISION from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name import math - -def dummy1(v): - assert isinstance(v, float) - return v - -def dummy2(v): - assert isinstance(v, float) - return v - TP = lltype.Array(lltype.Float, hints={'nolength': True}) numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) +all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) -class Signature(object): - def __init__(self): - self.transitions = {} - - def transition(self, target): - if target in self.transitions: - return self.transitions[target] - self.transitions[target] = new = Signature() - return new - -def pos(v): - return v -def neg(v): - return -v -def absolute(v): - return abs(v) def add(v1, v2): return v1 + v2 -def sub(v1, v2): - return v1 - v2 def mul(v1, v2): return v1 * v2 -def div(v1, v2): - return v1 / v2 -def pow(v1, v2): - return math.pow(v1, v2) -def mod(v1, v2): - return math.fmod(v1, v2) +def maximum(v1, v2): + return max(v1, v2) +def minimum(v1, v2): + return min(v1, v2) + +def float2string(x): + return float2string_orig(x, 'g', DTSF_STR_PRECISION) class BaseArray(Wrappable): def __init__(self): @@ -63,62 +45,185 @@ arr.force_if_needed() del self.invalidates[:] - def _unop_impl(function): - signature = Signature() + def _unaryop_impl(w_ufunc): def impl(self, space): - new_sig = self.signature.transition(signature) - res = Call1( - function, - self, - new_sig) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + return w_ufunc(space, self) + return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__) - descr_pos = _unop_impl(pos) - descr_neg = _unop_impl(neg) - descr_abs = _unop_impl(absolute) + descr_pos = _unaryop_impl(interp_ufuncs.positive) + descr_neg = _unaryop_impl(interp_ufuncs.negative) + descr_abs = _unaryop_impl(interp_ufuncs.absolute) - def _binop_impl(function): - signature = Signature() + def _binop_impl(w_ufunc): def impl(self, space, w_other): - new_sig = self.signature.transition(signature) + return w_ufunc(space, self, w_other) + return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__) + + descr_add = _binop_impl(interp_ufuncs.add) + descr_sub = _binop_impl(interp_ufuncs.subtract) + descr_mul = _binop_impl(interp_ufuncs.multiply) + descr_div = _binop_impl(interp_ufuncs.divide) + descr_pow = _binop_impl(interp_ufuncs.power) + descr_mod = _binop_impl(interp_ufuncs.mod) + + def _binop_right_impl(w_ufunc): + def impl(self, space, w_other): + w_other = FloatWrapper(space.float_w(w_other)) + return w_ufunc(space, w_other, self) + return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__) + + descr_radd = _binop_right_impl(interp_ufuncs.add) + descr_rsub = _binop_right_impl(interp_ufuncs.subtract) + descr_rmul = _binop_right_impl(interp_ufuncs.multiply) + descr_rdiv = _binop_right_impl(interp_ufuncs.divide) + descr_rpow = _binop_right_impl(interp_ufuncs.power) + descr_rmod = _binop_right_impl(interp_ufuncs.mod) + + def _reduce_sum_prod_impl(function, init): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + return space.wrap(loop(self, init, self.find_size())) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_max_min_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, result, size): + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, self.eval(0), size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_argmax_argmin_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self', 'cur_best']) + def loop(self, size): + result = 0 + cur_best = self.eval(0) + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result, cur_best=cur_best) + new_best = function(cur_best, self.eval(i)) + if new_best != cur_best: + result = i + cur_best = new_best + i += 1 + return result + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, size)) + return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) + + def _all(self): + size = self.find_size() + i = 0 + while i < size: + all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if not self.eval(i): + return False + i += 1 + return True + def descr_all(self, space): + return space.wrap(self._all()) + + def _any(self): + size = self.find_size() + i = 0 + while i < size: + any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if self.eval(i): + return True + i += 1 + return False + def descr_any(self, space): + return space.wrap(self._any()) + + descr_sum = _reduce_sum_prod_impl(add, 0.0) + descr_prod = _reduce_sum_prod_impl(mul, 1.0) + descr_max = _reduce_max_min_impl(maximum) + descr_min = _reduce_max_min_impl(minimum) + descr_argmax = _reduce_argmax_argmin_impl(maximum) + descr_argmin = _reduce_argmax_argmin_impl(minimum) + + def descr_dot(self, space, w_other): if isinstance(w_other, BaseArray): - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) + w_res = self.descr_mul(space, w_other) + assert isinstance(w_res, BaseArray) + return w_res.descr_sum(space) else: - w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + return self.descr_mul(space, w_other) - descr_add = _binop_impl(add) - descr_sub = _binop_impl(sub) - descr_mul = _binop_impl(mul) - descr_div = _binop_impl(div) - descr_pow = _binop_impl(pow) - descr_mod = _binop_impl(mod) + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] + nums.append("..." + "," * comma) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) + else: + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] + return nums def get_concrete(self): raise NotImplementedError + def descr_copy(self, space): + return new_numarray(space, self) + def descr_get_shape(self, space): return space.newtuple([self.descr_len(space)]) def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_repr(self, space): + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])") + + def descr_str(self, space): + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("[" + " ".join(concrete._getnums(True)) + "]") + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -130,19 +235,61 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().setitem(start, space.float_w(w_value)) + else: + concrete = self.get_concrete() + if isinstance(w_value, BaseArray): + # for now we just copy if setting part of an array from + # part of itself. can be improved. + if (concrete.get_root_storage() == + w_value.get_concrete().get_root_storage()): + w_value = new_numarray(space, w_value) + else: + w_value = convert_to_array(space, w_value) + concrete.setslice(space, start, stop, step, + slice_length, w_value) def descr_mean(self, space): - s = 0 - concrete = self.get_concrete() - size = concrete.find_size() - for i in xrange(size): - s += concrete.getitem(i) - return space.wrap(s / size) + return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) + def _sliceloop1(self, start, stop, step, source, dest): + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, source, dest): + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + +def convert_to_array (space, w_obj): + if isinstance(w_obj, BaseArray): + return w_obj + elif space.issequence_w(w_obj): + # Convert to array. + return new_numarray(space, w_obj) + else: + # If it's a scalar + return FloatWrapper(space.float_w(w_obj)) class FloatWrapper(BaseArray): """ @@ -278,8 +425,8 @@ return self.parent.getitem(self.calc_index(item)) @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - return self.parent.descr_setitem(space, self.calc_index(item), value) + def setitem(self, item, value): + return self.parent.setitem(self.calc_index(item), value) def descr_len(self, space): return space.wrap(self.find_size()) @@ -293,14 +440,34 @@ def __init__(self, start, stop, step, slice_length, parent, signature): ViewArray.__init__(self, parent, signature) + if isinstance(parent, SingleDimSlice): + self.start = parent.calc_index(start) + self.stop = parent.calc_index(stop) + self.step = parent.step * step + self.parent = parent.parent + else: self.start = start self.stop = stop self.step = step + self.parent = parent self.size = slice_length + def get_root_storage(self): + return self.parent.storage + def find_size(self): return self.size + def setslice(self, space, start, stop, step, slice_length, arr): + start = self.calc_index(start) + if stop != -1: + stop = self.calc_index(stop) + step = self.step * step + if step > 0: + self._sliceloop1(start, stop, step, arr, self.parent) + else: + self._sliceloop2(start, stop, step, arr, self.parent) + def calc_index(self, item): return (self.start + item * self.step) @@ -318,46 +485,45 @@ def get_concrete(self): return self + def get_root_storage(self): + return self.storage + def find_size(self): return self.size def eval(self, i): return self.storage[i] - def getindex(self, space, item): - if item >= self.size: - raise operationerrfmt(space.w_IndexError, - '%d above array size', item) - if item < 0: - item += self.size - if item < 0: - raise operationerrfmt(space.w_IndexError, - '%d below zero', item) - return item - def descr_len(self, space): return space.wrap(self.size) def getitem(self, item): return self.storage[item] - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - item = self.getindex(space, item) + def setitem(self, item, value): self.invalidated() self.storage[item] = value + def setslice(self, space, start, stop, step, slice_length, arr): + if step > 0: + self._sliceloop1(start, stop, step, arr, self) + else: + self._sliceloop2(start, stop, step, arr, self) + def __del__(self): lltype.free(self.storage, flavor='raw') -def descr_new_numarray(space, w_type, w_size_or_iterable): +def new_numarray(space, w_size_or_iterable): l = space.listview(w_size_or_iterable) arr = SingleDimArray(len(l)) i = 0 for w_elem in l: arr.storage[i] = space.float_w(space.float(w_elem)) i += 1 - return space.wrap(arr) + return arr + +def descr_new_numarray(space, w_type, w_size_or_iterable): + return space.wrap(new_numarray(space, w_size_or_iterable)) @unwrap_spec(size=int) def zeros(space, size): @@ -374,6 +540,7 @@ 'numarray', __new__ = interp2app(descr_new_numarray), + copy = interp2app(BaseArray.descr_copy), shape = GetSetProperty(BaseArray.descr_get_shape), __len__ = interp2app(BaseArray.descr_len), @@ -389,6 +556,23 @@ __div__ = interp2app(BaseArray.descr_div), __pow__ = interp2app(BaseArray.descr_pow), __mod__ = interp2app(BaseArray.descr_mod), + __radd__ = interp2app(BaseArray.descr_radd), + __rsub__ = interp2app(BaseArray.descr_rsub), + __rmul__ = interp2app(BaseArray.descr_rmul), + __rdiv__ = interp2app(BaseArray.descr_rdiv), + __rpow__ = interp2app(BaseArray.descr_rpow), + __rmod__ = interp2app(BaseArray.descr_rmod), + __repr__ = interp2app(BaseArray.descr_repr), + __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), + sum = interp2app(BaseArray.descr_sum), + prod = interp2app(BaseArray.descr_prod), + max = interp2app(BaseArray.descr_max), + min = interp2app(BaseArray.descr_min), + argmax = interp2app(BaseArray.descr_argmax), + argmin = interp2app(BaseArray.descr_argmin), + all = interp2app(BaseArray.descr_all), + any = interp2app(BaseArray.descr_any), + dot = interp2app(BaseArray.descr_dot), ) diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py --- a/pypy/module/micronumpy/interp_support.py +++ b/pypy/module/micronumpy/interp_support.py @@ -1,14 +1,14 @@ - from pypy.rlib.rstruct.runpack import runpack from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.interp_numarray import SingleDimArray + FLOAT_SIZE = rffi.sizeof(lltype.Float) @unwrap_spec(s=str) def fromstring(space, s): + from pypy.module.micronumpy.interp_numarray import SingleDimArray length = len(s) if length % FLOAT_SIZE == 0: @@ -30,3 +30,13 @@ end += FLOAT_SIZE return space.wrap(a) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,30 +1,35 @@ import math -from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature +from pypy.module.micronumpy.interp_support import Signature from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name - def ufunc(func): signature = Signature() def impl(space, w_obj): - if isinstance(w_obj, BaseArray): - w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) - w_obj.invalidates.append(w_res) + from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array + if space.issequence_w(w_obj): + w_obj_arr = convert_to_array(space, w_obj) + w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) + w_obj_arr.invalidates.append(w_res) return w_res + else: return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): - if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): - new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) - w_res = Call2(func, w_lhs, w_rhs, new_sig) - w_lhs.invalidates.append(w_res) - w_rhs.invalidates.append(w_res) + from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array + if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): + w_lhs_arr = convert_to_array(space, w_lhs) + w_rhs_arr = convert_to_array(space, w_rhs) + new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature) + w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig) + w_lhs_arr.invalidates.append(w_res) + w_rhs_arr.invalidates.append(w_res) return w_res + else: return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @@ -33,9 +38,17 @@ return abs(value) @ufunc2 +def add(lvalue, rvalue): + return lvalue + rvalue + + at ufunc2 def copysign(lvalue, rvalue): return rfloat.copysign(lvalue, rvalue) + at ufunc2 +def divide(lvalue, rvalue): + return lvalue / rvalue + @ufunc def exp(value): try: @@ -43,6 +56,10 @@ except OverflowError: return rfloat.INFINITY + at ufunc +def fabs(value): + return math.fabs(value) + @ufunc2 def maximum(lvalue, rvalue): return max(lvalue, rvalue) @@ -51,6 +68,15 @@ def minimum(lvalue, rvalue): return min(lvalue, rvalue) + at ufunc2 +def multiply(lvalue, rvalue): + return lvalue * rvalue + +# Used by numarray for __pos__. Not visible from numpy application space. + at ufunc +def positive(value): + return value + @ufunc def negative(value): return -value @@ -61,6 +87,10 @@ return rfloat.copysign(rfloat.INFINITY, value) return 1.0 / value + at ufunc2 +def subtract(lvalue, rvalue): + return lvalue - rvalue + @ufunc def floor(value): return math.floor(value) @@ -70,3 +100,23 @@ if value == 0.0: return 0.0 return rfloat.copysign(1.0, value) + + at ufunc +def sin(value): + return math.sin(value) + + at ufunc +def cos(value): + return math.cos(value) + + at ufunc +def tan(value): + return math.tan(value) + + at ufunc2 +def power(lvalue, rvalue): + return math.pow(lvalue, rvalue) + + at ufunc2 +def mod(lvalue, rvalue): + return math.fmod(lvalue, rvalue) diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -1,12 +1,10 @@ from pypy.conftest import gettestobjspace from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper - class BaseNumpyAppTest(object): def setup_class(cls): cls.space = gettestobjspace(usemodules=('micronumpy',)) - class TestSignature(object): def test_binop_signature(self, space): ar = SingleDimArray(10) @@ -26,4 +24,4 @@ v3 = ar.descr_add(space, v1) v4 = ar.descr_add(space, v2) - assert v3.signature is v4.signature \ No newline at end of file + assert v3.signature is v4.signature diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -38,11 +38,50 @@ a[2] = 4 assert a[2] == 4 + def test_copy(self): + from numpy import array + a = array(range(5)) + b = a.copy() + for i in xrange(5): + assert b[i] == a[i] + def test_iterator_init(self): from numpy import array a = array(range(5)) assert a[3] == 3 + def test_repr(self): + from numpy import array, zeros + a = array(range(5)) + assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" + a = zeros(1001) + assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_repr_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert repr(b) == "array([1.0, 3.0])" + a = zeros(2002) + b = a[::2] + assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_str(self): + from numpy import array, zeros + a = array(range(5)) + assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + a = zeros(1001) + assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + + def test_str_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert str(b) == "[1.0 3.0]" + a = zeros(2002) + b = a[::2] + assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_getitem(self): from numpy import array a = array(range(5)) @@ -60,6 +99,51 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + b[::-1] = b + assert b[0] == 1. + assert b[1] == 0. + + def test_setslice_of_slice_array(self): + from numpy import array, zeros + a = zeros(5) + a[::2] = array([9., 10., 11.]) + assert a[0] == 9. + assert a[2] == 10. + assert a[4] == 11. + a[1:4:2][::-1] = array([1., 2.]) + assert a[0] == 9. + assert a[1] == 2. + assert a[2] == 10. + assert a[3] == 1. + assert a[4] == 11. + a = zeros(10) + a[::2][::-1][::2] = array(range(1,4)) + assert a[8] == 1. + assert a[4] == 2. + assert a[0] == 3. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) @@ -97,6 +181,21 @@ for i in range(5): assert b[i] == i + 5 + def test_radd(self): + from numpy import array + r = 3 + array(range(3)) + for i in range(3): + assert r[i] == i + 3 + + def test_add_list(self): + from numpy import array + a = array(range(5)) + b = list(reversed(range(5))) + c = a + b + assert isinstance(c, array) + for i in range(5): + assert c[i] == 4 + def test_subtract(self): from numpy import array a = array(range(5)) @@ -282,6 +381,82 @@ assert a.mean() == 2.0 assert a[:4].mean() == 1.5 + def test_sum(self): + from numpy import array + a = array(range(5)) + assert a.sum() == 10.0 + assert a[:4].sum() == 6.0 + + def test_prod(self): + from numpy import array + a = array(range(1,6)) + assert a.prod() == 120.0 + assert a[:4].prod() == 24.0 + + def test_max(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.max() == 5.7 + b = array([]) + raises(ValueError, "b.max()") + + def test_max_add(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert (a+a).max() == 11.4 + + def test_min(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.min() == -3.0 + b = array([]) + raises(ValueError, "b.min()") + + def test_argmax(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmax() == 2 + b = array([]) + raises(ValueError, "b.argmax()") + + def test_argmin(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmin() == 3 + b = array([]) + raises(ValueError, "b.argmin()") + + def test_all(self): + from numpy import array + a = array(range(5)) + assert a.all() == False + a[0] = 3.0 + assert a.all() == True + b = array([]) + assert b.all() == True + + def test_any(self): + from numpy import array, zeros + a = array(range(5)) + assert a.any() == True + b = zeros(5) + assert b.any() == False + c = array([]) + assert c.any() == False + + def test_dot(self): + from numpy import array + a = array(range(5)) + assert a.dot(a) == 30.0 + + def test_dot_constant(self): + from numpy import array + a = array(range(5)) + b = a.dot(2.5) + for i in xrange(5): + assert b[i] == 2.5*a[i] + + class AppTestSupport(object): def setup_class(cls): import struct diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -10,6 +10,40 @@ assert sign(-0.0) == 0.0 assert minimum(2.0, 3.0) == 2.0 + def test_sequence(self): + from numpy import array, negative, minimum + a = array(range(3)) + b = [2.0, 1.0, 0.0] + c = 1.0 + b_neg = negative(b) + assert isinstance(b_neg, array) + for i in range(3): + assert b_neg[i] == -b[i] + min_a_b = minimum(a, b) + assert isinstance(min_a_b, array) + for i in range(3): + assert min_a_b[i] == min(a[i], b[i]) + min_b_a = minimum(b, a) + assert isinstance(min_b_a, array) + for i in range(3): + assert min_b_a[i] == min(a[i], b[i]) + min_a_c = minimum(a, c) + assert isinstance(min_a_c, array) + for i in range(3): + assert min_a_c[i] == min(a[i], c) + min_c_a = minimum(c, a) + assert isinstance(min_c_a, array) + for i in range(3): + assert min_c_a[i] == min(a[i], c) + min_b_c = minimum(b, c) + assert isinstance(min_b_c, array) + for i in range(3): + assert min_b_c[i] == min(b[i], c) + min_c_b = minimum(c, b) + assert isinstance(min_c_b, array) + for i in range(3): + assert min_c_b[i] == min(b[i], c) + def test_negative(self): from numpy import array, negative @@ -31,6 +65,33 @@ for i in range(3): assert b[i] == abs(a[i]) + def test_add(self): + from numpy import array, add + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = add(a, b) + for i in range(3): + assert c[i] == a[i] + b[i] + + def test_divide(self): + from numpy import array, divide + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = divide(a, b) + for i in range(3): + assert c[i] == a[i] / b[i] + + def test_fabs(self): + from numpy import array, fabs + from math import fabs as math_fabs + + a = array([-5.0, -0.0, 1.0]) + b = fabs(a) + for i in range(3): + assert b[i] == math_fabs(a[i]) + def test_minimum(self): from numpy import array, minimum @@ -49,6 +110,15 @@ for i in range(3): assert c[i] == max(a[i], b[i]) + def test_multiply(self): + from numpy import array, multiply + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = multiply(a, b) + for i in range(3): + assert c[i] == a[i] * b[i] + def test_sign(self): from numpy import array, sign @@ -67,6 +137,15 @@ for i in range(4): assert b[i] == reference[i] + def test_subtract(self): + from numpy import array, subtract + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = subtract(a, b) + for i in range(3): + assert c[i] == a[i] - b[i] + def test_floor(self): from numpy import array, floor @@ -99,3 +178,30 @@ except OverflowError: res = float('inf') assert b[i] == res + + def test_sin(self): + import math + from numpy import array, sin + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = sin(a) + for i in range(len(a)): + assert b[i] == math.sin(a[i]) + + def test_cos(self): + import math + from numpy import array, cos + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = cos(a) + for i in range(len(a)): + assert b[i] == math.cos(a[i]) + + def test_tan(self): + import math + from numpy import array, tan + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = tan(a) + for i in range(len(a)): + assert b[i] == math.tan(a[i]) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,12 +1,24 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) + FloatWrapper, Call2, SingleDimSlice, add, mul, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile +from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): - pass + w_ValueError = None + + def issequence_w(self, w_obj): + return True + + @specialize.argtype(1) + def wrap(self, w_obj): + return w_obj + + def float_w(self, w_obj): + return float(w_obj) class TestNumpyJIt(LLJitMixin): def setup_class(cls): @@ -36,19 +48,113 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_neg(self): + def test_sum(self): space = self.space def f(i): ar = SingleDimArray(i) - v = Call1(neg, ar, Signature()) - return v.get_concrete().storage[3] + return ar.descr_add(space, ar).descr_sum(space) result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, - "setarrayitem_raw": 1, "int_add": 1, + self.check_loops({"getarrayitem_raw": 2, "float_add": 2, + "int_add": 1, "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + def test_prod(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_prod(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_max(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_max(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_gt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, + "guard_false": 1, "jump": 1}) + assert result == f(5) + + def test_min(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_min(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + assert result == f(5) + + def test_argmin(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_argmin(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + assert result == f(5) + + def test_all(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = 1.0 + j += 1 + return ar.descr_add(space, ar).descr_all(space) + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, + "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) + + def test_any(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_any(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, "guard_false": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) def test_already_forecd(self): @@ -133,6 +239,28 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar2.storage[1] = 5.5 + if NonConstant(False): + arg = ar2 + else: + arg = ar2.descr_add(space, ar2) + ar.setslice(space, 0, step*i, step, i, arg) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 2, + 'float_add' : 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == 11.0 + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py --- a/pypy/module/mmap/interp_mmap.py +++ b/pypy/module/mmap/interp_mmap.py @@ -1,15 +1,10 @@ -from pypy.rpython.tool import rffi_platform -from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped from pypy.rlib import rmmap from pypy.rlib.rmmap import RValueError, RTypeError, ROverflowError -import sys -import os -import platform -import stat + class W_MMap(Wrappable): def __init__(self, space, mmap_obj): diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -15,7 +15,6 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap -from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant from pypy.jit.metainterp.resoperation import rop from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -1,9 +1,9 @@ from pypy.interpreter.typedef import TypeDef, interp_attrproperty -from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import unwrap_spec, interp2app from pypy.interpreter.pycode import PyCode -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.lltypesystem.rclass import OBJECT diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -30,7 +30,6 @@ assert res == 8.0 * 300 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('fficall', """ - p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>) guard_not_invalidated(descr=...) i17 = force_token() setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -19,7 +19,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) + guard_true(i7, descr=...) i9 = int_add(i5, 1) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) @@ -39,11 +39,12 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated(descr=...) i13 = int_lt(i7, i9) - guard_true(i13, descr=) + guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = int_add(i7, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) @@ -68,16 +69,17 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i13 = int_lt(i8, 307200) - guard_true(i13, descr=) + guard_true(i13, descr=...) + guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) # on 64bit, there is a guard checking that i19 actually fits into 32bit ... setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -80,19 +80,19 @@ # assert entry_bridge.match_by_id('call', """ p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) + guard_nonnull_class(p29, ConstClass(Function), descr=...) p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) + guard_value(p33, ConstPtr(ptr34), descr=...) p35 = getfield_gc(p29, descr=) p36 = getfield_gc(p29, descr=) p38 = call(ConstClass(getexecutioncontext), descr=) p39 = getfield_gc(p38, descr=) i40 = force_token() p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) + guard_isnull(p41, descr=...) i42 = getfield_gc(p38, descr=) i43 = int_is_zero(i42) - guard_true(i43, descr=) + guard_true(i43, descr=...) i50 = force_token() """) # @@ -101,16 +101,16 @@ loop, = log.loops_by_id('call') assert loop.match(""" i12 = int_lt(i5, i6) - guard_true(i12, descr=) + guard_true(i12, descr=...) i13 = force_token() i15 = int_add(i5, 1) i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) """) @@ -146,14 +146,14 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i15 = int_lt(i6, i9) - guard_true(i15, descr=) - guard_not_invalidated(descr=) + guard_true(i15, descr=...) + guard_not_invalidated(descr=...) i16 = force_token() i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) """) @@ -180,11 +180,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) - guard_not_invalidated(descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = force_token() i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() --TICK-- jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) @@ -281,25 +281,23 @@ loop0, = log.loops_by_id('g1') assert loop0.match_by_id('g1', """ i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('h1', """ i20 = force_token() i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('g2', """ i27 = force_token() i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) # loop1, = log.loops_by_id('g3') assert loop1.match_by_id('g3', """ i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) guard_no_overflow(descr=...) """) @@ -352,7 +350,7 @@ i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) p17 = getfield_gc(p8, descr=) p19 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p19, i12, descr=) @@ -404,9 +402,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i10 = int_lt(i5, i6) - guard_true(i10, descr=) + guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i120 = int_add(i5, 1) - guard_not_invalidated(descr=) --TICK-- jump(..., descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -23,3 +23,29 @@ ops = loop.ops_by_id('look') assert log.opnames(ops) == ['setfield_gc', 'guard_not_invalidated'] + + def test_identitydict(self): + def fn(n): + class X(object): + pass + x = X() + d = {} + d[x] = 1 + res = 0 + for i in range(300): + value = d[x] # ID: getitem + res += value + return res + # + log = self.run(fn, [1000]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # check that the call to ll_dict_lookup is not a call_may_force + assert loop.match_by_id("getitem", """ + i25 = call(ConstClass(_ll_1_gc_identityhash__objectPtr), p6, descr=...) + ... + i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...) + ... + p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py --- a/pypy/module/pypyjit/test_pypy_c/test_exception.py +++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py @@ -36,11 +36,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i5 = int_is_true(i3) - guard_true(i5, descr=) - guard_not_invalidated(descr=) + guard_true(i5, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -84,8 +84,8 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i4, i5) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i14 = int_add(i4, 1) --TICK-- diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -0,0 +1,30 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGlobals(BaseTestPyPyC): + def test_load_builtin(self): + def main(n): + import pypyjit + + i = 0 + while i < n: + l = len # ID: loadglobal + i += pypyjit.residual_call(l, "a") + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("loadglobal", """ + p10 = getfield_gc(p0, descr=) + guard_value(p10, ConstPtr(ptr11), descr=...) + p12 = getfield_gc(p10, descr=) + guard_value(p12, ConstPtr(ptr13), descr=...) + p15 = getfield_gc(ConstPtr(ptr14), descr=) + guard_isnull(p15, descr=...) + guard_not_invalidated(descr=...) + p19 = getfield_gc(ConstPtr(p17), descr=) + guard_value(p19, ConstPtr(ptr20), descr=...) + p22 = getfield_gc(ConstPtr(ptr21), descr=) + guard_nonnull(p22, descr=...) + """) \ No newline at end of file diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py --- a/pypy/module/pypyjit/test_pypy_c/test_import.py +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -15,13 +15,13 @@ assert log.result == 500 loop, = log.loops_by_id('import') assert loop.match_by_id('import', """ + guard_not_invalidated(descr=...) p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) + guard_value(p11, ConstPtr(ptr12), descr=...) p14 = getfield_gc(ConstPtr(ptr13), descr=) p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) + guard_value(p14, ConstPtr(ptr17), descr=...) + guard_isnull(p16, descr=...) """) def test_import_fast_path(self, tmpdir): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -22,10 +22,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) """) @@ -47,10 +47,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = int_lt(i5, i6) - guard_true(i9, descr=) - guard_not_invalidated(descr=) + guard_true(i9, descr=...) + guard_not_invalidated(descr=...) i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -0,0 +1,32 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestMath(BaseTestPyPyC): + def test_log(self): + def main(n): + import math + + i = 1 + s = 0.0 + while i < n: + s += math.log(i) - math.log10(i) + i += 1 + return s + log = self.run(main, [500]) + assert round(log.result, 6) == round(main(500), 6) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i2 = int_lt(i0, i1) + guard_true(i2, descr=...) + guard_not_invalidated(descr=...) + f1 = cast_int_to_float(i0) + i3 = float_le(f1, 0) + guard_false(i3, descr=...) + f2 = call(ConstClass(log), f1, descr=) + f3 = call(ConstClass(log10), f1, descr=) + f4 = float_sub(f2, f3) + f5 = float_add(f0, f4) + i4 = int_add(i0, 1) + --TICK-- + jump(..., descr=) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -17,6 +17,7 @@ assert loop.match(""" i7 = int_lt(i4, 300) guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 3000) guard_no_overflow(descr=...) i11 = int_add(i4, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -84,7 +84,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = float_lt(f5, f7) - guard_true(i9, descr=) + guard_true(i9, descr=...) f10 = float_add(f8, f5) --TICK-- jump(p0, p1, p2, p3, p4, f10, p6, f7, f8, descr=) @@ -107,19 +107,19 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i11, i12) - guard_false(i16, descr=) + guard_false(i16, descr=...) i17 = int_mul(i11, i14) i18 = int_add(i15, i17) i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=) + guard_not_invalidated(descr=...) i23 = int_lt(i18, 0) - guard_false(i23, descr=) + guard_false(i23, descr=...) i25 = int_ge(i18, i9) - guard_false(i25, descr=) + guard_false(i25, descr=...) i27 = int_add_ovf(i7, i18) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -164,20 +164,20 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i16 = int_ge(i12, i13) - guard_false(i16, descr=) + guard_false(i16, descr=...) p17 = getarrayitem_gc(p15, i12, descr=) i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) - guard_nonnull_class(p17, 146982464, descr=) + guard_nonnull_class(p17, 146982464, descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) - guard_true(i23, descr=) + guard_true(i23, descr=...) i24 = getfield_gc(p17, descr=) i25 = getarrayitem_raw(i24, 0, descr=<.*>) i27 = int_lt(1, i21) - guard_false(i27, descr=) + guard_false(i27, descr=...) i28 = int_add_ovf(i10, i25) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=) """) @@ -201,9 +201,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i11 = int_lt(i7, 300) - guard_true(i11, descr=) + guard_true(i11, descr=...) i12 = int_add_ovf(i8, i9) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i14 = int_add(i7, 1) --TICK-- jump(..., descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -16,27 +16,92 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = int_mod(i6, i10) i17 = int_rshift(i15, 63) i18 = int_and(i10, i17) i19 = int_add(i15, i18) i21 = int_lt(i19, 0) - guard_false(i21, descr=) + guard_false(i21, descr=...) i22 = int_ge(i19, i10) - guard_false(i22, descr=) + guard_false(i22, descr=...) i23 = strgetitem(p11, i19) i24 = int_ge(i19, i12) - guard_false(i24, descr=) + guard_false(i24, descr=...) i25 = unicodegetitem(p13, i19) - guard_not_invalidated(descr=) p27 = newstr(1) strsetitem(p27, 0, i23) p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=) - guard_true(i32, descr=) + guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=) - """) \ No newline at end of file + """) + + def test_long(self): + def main(n): + import string + i = 1 + while i < n: + i += int(long(string.digits[i % len(string.digits)], 16)) + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i13 = int_eq(i6, -9223372036854775808) + guard_false(i13, descr=...) + i15 = int_mod(i6, i8) + i17 = int_rshift(i15, 63) + i18 = int_and(i8, i17) + i19 = int_add(i15, i18) + i21 = int_lt(i19, 0) + guard_false(i21, descr=...) + i22 = int_ge(i19, i8) + guard_false(i22, descr=...) + i23 = strgetitem(p10, i19) + p25 = newstr(1) + strsetitem(p25, 0, i23) + p28 = call(ConstClass(strip_spaces), p25, descr=) + guard_no_exception(descr=...) + i29 = strlen(p28) + i30 = int_is_true(i29) + guard_true(i30, descr=...) + i32 = int_sub(i29, 1) + i33 = strgetitem(p28, i32) + i35 = int_eq(i33, 108) + guard_false(i35, descr=...) + i37 = int_eq(i33, 76) + guard_false(i37, descr=...) + i39 = strgetitem(p28, 0) + i41 = int_eq(i39, 45) + guard_false(i41, descr=...) + i43 = int_eq(i39, 43) + guard_false(i43, descr=...) + i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=) + guard_false(i43, descr=...) + i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=) + guard_false(i46, descr=...) + p51 = new_with_vtable(21136408) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, ConstPtr(ptr51), descr=) + setfield_gc(p51, 1, descr=) + setfield_gc(p51, 16, descr=) + setfield_gc(p51, p28, descr=) + setfield_gc(p51, i29, descr=) + p55 = call(ConstClass(parse_digit_string), p51, descr=) + guard_no_exception(descr=...) + i57 = call(ConstClass(rbigint.toint), p55, descr=) + guard_no_exception(descr=...) + i58 = int_add_ovf(i6, i57) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) + """) diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py --- a/pypy/module/rctime/interp_time.py +++ b/pypy/module/rctime/interp_time.py @@ -6,7 +6,6 @@ from pypy.rlib.rarithmetic import ovfcheck_float_to_int from pypy.rlib import rposix from pypy.translator.tool.cbuild import ExternalCompilationInfo -import math import os import sys import time as pytime diff --git a/pypy/module/select/interp_select.py b/pypy/module/select/interp_select.py --- a/pypy/module/select/interp_select.py +++ b/pypy/module/select/interp_select.py @@ -1,9 +1,7 @@ -import math from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import ( - OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.rlib import rpoll import errno diff --git a/pypy/module/select/test/test_epoll.py b/pypy/module/select/test/test_epoll.py --- a/pypy/module/select/test/test_epoll.py +++ b/pypy/module/select/test/test_epoll.py @@ -138,7 +138,7 @@ expected.sort() assert events == expected - assert then - now < 0.01 + assert then - now < 0.02 now = time.time() events = ep.poll(timeout=2.1, maxevents=4) @@ -151,7 +151,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 events.sort() expected = [ @@ -168,7 +168,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 expected = [(server.fileno(), select.EPOLLOUT)] assert events == expected @@ -192,7 +192,7 @@ now = time.time() ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 server.close() ep.unregister(fd) diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py --- a/pypy/module/struct/formatiterator.py +++ b/pypy/module/struct/formatiterator.py @@ -1,11 +1,10 @@ - from pypy.interpreter.error import OperationError from pypy.rlib.objectmodel import specialize from pypy.rlib.rstruct.error import StructError from pypy.rlib.rstruct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT -from pypy.rlib.rstruct.formatiterator import (FormatIterator, - CalcSizeFormatIterator) +from pypy.rlib.rstruct.formatiterator import FormatIterator + class PackFormatIterator(FormatIterator): diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py --- a/pypy/module/struct/interp_struct.py +++ b/pypy/module/struct/interp_struct.py @@ -1,10 +1,7 @@ from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.module.struct.formatiterator import PackFormatIterator, UnpackFormatIterator from pypy.rlib.rstruct.error import StructError -from pypy.module.struct.formatiterator import CalcSizeFormatIterator -from pypy.module.struct.formatiterator import PackFormatIterator -from pypy.module.struct.formatiterator import UnpackFormatIterator - +from pypy.rlib.rstruct.formatiterator import CalcSizeFormatIterator @unwrap_spec(format=str) def calcsize(space, format): diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py --- a/pypy/module/sys/test/test_sysmodule.py +++ b/pypy/module/sys/test/test_sysmodule.py @@ -476,7 +476,7 @@ assert isinstance(vi[0], int) assert isinstance(vi[1], int) assert isinstance(vi[2], int) - assert vi[3] in ("alpha", "beta", "candidate", "final") + assert vi[3] in ("alpha", "beta", "candidate", "dev", "final") assert isinstance(vi[4], int) def test_allattributes(self): @@ -523,4 +523,4 @@ # If this ever actually becomes a compilation option this test should # be changed. - assert sys.float_repr_style == "short" \ No newline at end of file + assert sys.float_repr_style == "short" diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ CPYTHON_VERSION = (2, 7, 1, "final", 42) #XXX # sync patchlevel.h CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (1, 5, 0, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (1, 6, 0, "dev", 1) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -132,6 +132,16 @@ # You cannot assing character format codes as restype any longer raises(TypeError, setattr, f, "restype", "i") + + def test_truncate_python_longs(self): + f = dll._testfunc_i_bhilfd + f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] + f.restype = c_int + x = sys.maxint * 2 + result = f(x, x, x, x, 0, 0) + assert result == -8 + + def test_floatresult(self): f = dll._testfunc_f_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] @@ -411,6 +421,23 @@ result = f("abcd", ord("b")) assert result == "bcd" + def test_keepalive_buffers(self, monkeypatch): + import gc + f = dll.my_strchr + f.argtypes = [c_char_p] + f.restype = c_char_p + # + orig__call_funcptr = f._call_funcptr + def _call_funcptr(funcptr, *newargs): + gc.collect() + gc.collect() + gc.collect() + return orig__call_funcptr(funcptr, *newargs) + monkeypatch.setattr(f, '_call_funcptr', _call_funcptr) + # + result = f("abcd", ord("b")) + assert result == "bcd" + def test_caching_bug_1(self): # the same test as test_call_some_args, with two extra lines # in the middle that trigger caching in f._ptr, which then diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py @@ -12,7 +12,7 @@ from _ctypes.function import CFuncPtr def guess(value): - cobj, ctype = CFuncPtr._conv_param(None, value) + _, cobj, ctype = CFuncPtr._conv_param(None, value) return ctype ## cobj = CFuncPtr._conv_param(None, value) ## return type(cobj) diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py --- a/pypy/module/thread/ll_thread.py +++ b/pypy/module/thread/ll_thread.py @@ -1,9 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype, llmemory -from pypy.rpython.tool import rffi_platform as platform from pypy.translator.tool.cbuild import ExternalCompilationInfo -import py, os -from pypy.rpython.extregistry import ExtRegistryEntry +import py from pypy.rlib import jit from pypy.rlib.debug import ll_assert from pypy.rlib.objectmodel import we_are_translated @@ -21,6 +19,7 @@ 'RPyThreadAcquireLock', 'RPyThreadReleaseLock', 'RPyThreadYield', 'RPyThreadGetStackSize', 'RPyThreadSetStackSize', + 'RPyOpaqueDealloc_ThreadLock', 'RPyThreadAfterFork'] ) @@ -52,6 +51,9 @@ c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], rffi.INT, threadsafe=False) # may add in a global list +c_thread_lock_dealloc = llexternal('RPyOpaqueDealloc_ThreadLock', [TLOCKP], + lltype.Void, + threadsafe=True) c_thread_acquirelock = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT], rffi.INT, threadsafe=True) # release the GIL @@ -156,6 +158,9 @@ return ll_lock def free_ll_lock(ll_lock): + c_thread_acquirelock(ll_lock, 0) + c_thread_releaselock(ll_lock) + c_thread_lock_dealloc(ll_lock) lltype.free(ll_lock, flavor='raw', track_allocation=False) def acquire_NOAUTO(ll_lock, flag): diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py --- a/pypy/module/thread/os_local.py +++ b/pypy/module/thread/os_local.py @@ -1,9 +1,7 @@ from pypy.module.thread import ll_thread as thread -from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp2app -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict +from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty, + descr_get_dict) class Local(Wrappable): diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py --- a/pypy/module/thread/os_thread.py +++ b/pypy/module/thread/os_thread.py @@ -6,7 +6,6 @@ from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import unwrap_spec, NoneNotWrapped, Arguments -from pypy.rlib.objectmodel import free_non_gc_object # Here are the steps performed to start a new thread: # diff --git a/pypy/module/thread/test/test_import_lock.py b/pypy/module/thread/test/test_import_lock.py --- a/pypy/module/thread/test/test_import_lock.py +++ b/pypy/module/thread/test/test_import_lock.py @@ -66,6 +66,9 @@ def test_lock(self, space, monkeypatch): from pypy.module.imp.importing import getimportlock, importhook + # Force importing the module _file now + space.builtin.get('file') + # Monkeypatch the import lock and add a counter importlock = getimportlock(space) original_acquire = importlock.acquire_lock diff --git a/pypy/module/unicodedata/generate_unicodedb.py b/pypy/module/unicodedata/generate_unicodedb.py --- a/pypy/module/unicodedata/generate_unicodedb.py +++ b/pypy/module/unicodedata/generate_unicodedb.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -import pprint - MAXUNICODE = 0x10FFFF # the value of sys.maxunicode of wide Python builds MANDATORY_LINE_BREAKS = ["BK", "CR", "LF", "NL"] # line break categories @@ -662,7 +660,7 @@ ''' def main(): - import re, sys + import sys from optparse import OptionParser infile = None outfile = sys.stdout diff --git a/pypy/module/zlib/interp_zlib.py b/pypy/module/zlib/interp_zlib.py --- a/pypy/module/zlib/interp_zlib.py +++ b/pypy/module/zlib/interp_zlib.py @@ -20,25 +20,15 @@ return intmask((x ^ SIGN_EXTEND2) - SIGN_EXTEND2) - at unwrap_spec(string='bufferstr') -def crc32(space, string, w_start = rzlib.CRC32_DEFAULT_START): + at unwrap_spec(string='bufferstr', start='truncatedint') +def crc32(space, string, start = rzlib.CRC32_DEFAULT_START): """ crc32(string[, start]) -- Compute a CRC-32 checksum of string. An optional starting value can be specified. The returned checksum is an integer. """ - if space.is_true(space.isinstance(w_start, space.w_long)): - num = space.bigint_w(w_start) - ustart = num.uintmask() - elif space.is_true(space.isinstance(w_start, space.w_int)): - start = space.int_w(w_start) ustart = r_uint(start) - else: - raise OperationError(space.w_TypeError, - space.wrap("crc32() argument 2 must " - "be integer, not str")) - checksum = rzlib.crc32(string, ustart) # This is, perhaps, a little stupid. zlib returns the checksum unsigned. @@ -51,7 +41,7 @@ return space.wrap(checksum) - at unwrap_spec(string='bufferstr', start=r_uint) + at unwrap_spec(string='bufferstr', start='truncatedint') def adler32(space, string, start=rzlib.ADLER32_DEFAULT_START): """ adler32(string[, start]) -- Compute an Adler-32 checksum of string. @@ -59,7 +49,8 @@ An optional starting value can be specified. The returned checksum is an integer. """ - checksum = rzlib.adler32(string, start) + ustart = r_uint(start) + checksum = rzlib.adler32(string, ustart) # See comments in crc32() for the following line checksum = unsigned_to_signed_32bit(checksum) diff --git a/pypy/module/zlib/test/test_zlib.py b/pypy/module/zlib/test/test_zlib.py --- a/pypy/module/zlib/test/test_zlib.py +++ b/pypy/module/zlib/test/test_zlib.py @@ -78,15 +78,17 @@ def test_crc32_negative_long_start(self): v = self.zlib.crc32('', -1L) assert v == -1 + assert self.zlib.crc32('foo', -99999999999999999999999) == 1611238463 def test_crc32_long_start(self): import sys v = self.zlib.crc32('', sys.maxint*2) assert v == -2 + assert self.zlib.crc32('foo', 99999999999999999999999) == 1635107045 def test_adler32(self): """ - When called with a string, zlib.crc32 should compute its adler 32 + When called with a string, zlib.adler32() should compute its adler 32 checksum and return it as a signed 32 bit integer. On 64-bit machines too (it is a bug in CPython < 2.6 to return unsigned values in this case). @@ -113,6 +115,9 @@ helloworldsum = self.zlib.adler32(world, hellosum) assert helloworldsum == self.zlib.adler32(hello + world) + assert self.zlib.adler32('foo', -1) == 45547858 + assert self.zlib.adler32('foo', 99999999999999999999999) == -114818734 + def test_invalidLevel(self): """ diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -28,6 +28,13 @@ return w_delattr object_delattr._annspecialcase_ = 'specialize:memo' +def object_hash(space): + "Utility that returns the app-level descriptor object.__hash__." + w_src, w_hash = space.lookup_in_type_where(space.w_object, + '__hash__') + return w_hash +object_hash._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): w_type = space.type(w_obj) typename = w_type.getname(space) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -157,11 +157,15 @@ return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): - #XXX implement other strategies later + withidentitydict = self.space.config.objspace.std.withidentitydict if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) - elif self.space.is_w(self.space.type(w_key), self.space.w_int): + return + w_type = self.space.type(w_key) + if self.space.is_w(w_type, self.space.w_int): self.switch_to_int_strategy(w_dict) + elif withidentitydict and w_type.compares_by_identity(): + self.switch_to_identity_strategy(w_dict) else: self.switch_to_object_strategy(w_dict) @@ -177,6 +181,13 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_identity_strategy(self, w_dict): + from pypy.objspace.std.identitydict import IdentityDictStrategy + strategy = self.space.fromcache(IdentityDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): strategy = self.space.fromcache(ObjectDictStrategy) storage = strategy.get_empty_storage() @@ -338,7 +349,6 @@ def getitem(self, w_dict, w_key): space = self.space - if self.is_correct_type(w_key): return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) elif self._never_equal_to(space.type(w_key)): @@ -404,6 +414,7 @@ def keys(self, w_dict): return self.unerase(w_dict.dstorage).keys() + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") @@ -448,7 +459,9 @@ return StrIteratorImplementation(self.space, self, w_dict) -class StrIteratorImplementation(IteratorImplementation): +class _WrappedIteratorMixin(object): + _mixin_ = True + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() @@ -460,6 +473,23 @@ else: return None, None +class _UnwrappedIteratorMixin: + _mixin_ = True + + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value + else: + return None, None + + +class StrIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass class IntDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("int") @@ -490,31 +520,11 @@ def iter(self, w_dict): return IntIteratorImplementation(self.space, self, w_dict) -class IntIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() +class IntIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass - def next_entry(self): - # note that this 'for' loop only runs once, at most - for key, w_value in self.iterator: - return self.space.wrap(key), w_value - else: - return None, None - - -class ObjectIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() - - def next_entry(self): - # note that this 'for' loop only runs once, at most - for w_key, w_value in self.iterator: - return w_key, w_value - else: - return None, None - +class ObjectIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass init_signature = Signature(['seq_or_map'], None, 'kwargs') init_defaults = [None] @@ -736,6 +746,8 @@ class W_DictMultiIterObject(W_Object): from pypy.objspace.std.dicttype import dictiter_typedef as typedef + _immutable_fields_ = ["iteratorimplementation", "itertype"] + def __init__(w_self, space, iteratorimplementation, itertype): w_self.space = space w_self.iteratorimplementation = iteratorimplementation diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -86,7 +86,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated() + self.unerase(w_dict.dstorage).mutated(None) class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -133,8 +133,7 @@ else: return space.wrap("0x%sp%s%d" % (s, sign, exp)) -def float2string(space, w_float, code, precision): - x = w_float.floatval +def float2string(x, code, precision): # we special-case explicitly inf and nan here if isfinite(x): s = formatd(x, code, precision, DTSF_ADD_DOT_0) @@ -145,13 +144,13 @@ s = "-inf" else: # isnan(x): s = "nan" - return space.wrap(s) + return s def repr__Float(space, w_float): - return float2string(space, w_float, 'r', 0) + return space.wrap(float2string(w_float.floatval, 'r', 0)) def str__Float(space, w_float): - return float2string(space, w_float, 'g', DTSF_STR_PRECISION) + return space.wrap(float2string(w_float.floatval, 'g', DTSF_STR_PRECISION)) def format__Float_ANY(space, w_float, w_spec): return newformat.run_formatter(space, w_spec, "format_float", w_float) diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/identitydict.py @@ -0,0 +1,85 @@ +## ---------------------------------------------------------------------------- +## dict strategy (see dict_multiobject.py) + +from pypy.rlib import rerased +from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, + DictStrategy, + IteratorImplementation, + _UnwrappedIteratorMixin) + + +# this strategy is selected by EmptyDictStrategy.switch_to_correct_strategy +class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): + """ + Strategy for custom instances which compares by identity (i.e., the + default unless you override __hash__, __eq__ or __cmp__). The storage is + just a normal RPython dict, which has already the correct by-identity + semantics. + + Note that at a first sight, you might have problems if you mutate the + class of an object which is already inside an identitydict. Consider this + example:: + + class X(object): + pass + d = {x(): 1} + X.__eq__ = ... + d[y] # might trigger a call to __eq__? + + We want to be sure that x.__eq__ is called in the same cases as in + CPython. However, as long as the strategy is IdentityDictStrategy, the + __eq__ will never be called. + + It turns out that it's not a problem. In CPython (and in PyPy without + this strategy), the __eq__ is called if ``hash(y) == hash(x)`` and ``x is + not y``. Note that hash(x) is computed at the time when we insert x in + the dict, not at the time we lookup y. + + Now, how can hash(y) == hash(x)? There are two possibilities: + + 1. we write a custom __hash__ for the class of y, thus making it a not + "compares by reference" type + + 2. the class of y is "compares by reference" type, and by chance the + hash is the same as x + + In the first case, the getitem immediately notice that y is not of the + right type, and switches the strategy to ObjectDictStrategy, then the + lookup works as usual. + + The second case is completely non-deterministic, even in CPython. + Depending on the phase of the moon, you might call the __eq__ or not, so + it is perfectly fine to *never* call it. Morever, in practice with the + minimar GC we never have two live objects with the same hash, so it would + never happen anyway. + """ + + erase, unerase = rerased.new_erasing_pair("identitydict") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def get_empty_storage(self): + return self.erase({}) + + def is_correct_type(self, w_obj): + w_type = self.space.type(w_obj) + return w_type.compares_by_identity() + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return IdentityDictIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + + +class IdentityDictIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -431,12 +431,17 @@ return None assert isinstance(lifeline, WeakrefLifeline) return lifeline + getweakref._cannot_really_call_random_things_ = True def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline - assert (isinstance(weakreflifeline, WeakrefLifeline) or - weakreflifeline is None) + assert isinstance(weakreflifeline, WeakrefLifeline) self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + setweakref._cannot_really_call_random_things_ = True + + def delweakref(self): + self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + delweakref._cannot_really_call_random_things_ = True class ObjectMixin(object): _mixin_ = True diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -6,7 +6,7 @@ from pypy.objspace.descroperation import Object from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.register_all import register_all - +from pypy.objspace.std import identitydict def descr__repr__(space, w_obj): w = space.wrap diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -39,7 +39,6 @@ from pypy.objspace.std.stringtype import wrapstr from pypy.objspace.std.unicodetype import wrapunicode - class StdObjSpace(ObjSpace, DescrOperation): """The standard object space, implementing a general-purpose object library in Restricted Python.""" diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -36,6 +36,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None class W_SetObject(W_BaseSetObject): from pypy.objspace.std.settype import set_typedef as typedef diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -898,6 +898,7 @@ withsmalldicts = False withcelldict = False withmethodcache = False + withidentitydict = False FakeSpace.config = Config() @@ -1105,3 +1106,4 @@ fakespace = FakeSpace() d = fakespace.newdict(module=True) assert type(d.strategy) is StringDictStrategy + diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_identitydict.py @@ -0,0 +1,138 @@ +import py +from pypy.interpreter.gateway import interp2app +from pypy.conftest import gettestobjspace +from pypy.conftest import option + +class AppTestComparesByIdentity: + + def setup_class(cls): + from pypy.objspace.std import identitydict + cls.space = gettestobjspace( + **{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("interp2app doesn't work on appdirect") + + def compares_by_identity(space, w_cls): + return space.wrap(w_cls.compares_by_identity()) + cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) + + def test_compares_by_identity(self): + class Plain(object): + pass + + class CustomEq(object): + def __eq__(self, other): + return True + + class CustomCmp (object): + def __cmp__(self, other): + return 0 + + class CustomHash(object): + def __hash__(self): + return 0 + + assert self.compares_by_identity(Plain) + assert not self.compares_by_identity(CustomEq) + assert not self.compares_by_identity(CustomCmp) + assert not self.compares_by_identity(CustomHash) + + def test_modify_class(self): + class X(object): + pass + + assert self.compares_by_identity(X) + X.__eq__ = lambda x: None + assert not self.compares_by_identity(X) + del X.__eq__ + assert self.compares_by_identity(X) + + +class AppTestIdentityDict(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("interp2app doesn't work on appdirect") + + def w_uses_identity_strategy(self, obj): + import __pypy__ + return "IdentityDictStrategy" in __pypy__.internal_repr(obj) + + def test_use_strategy(self): + class X(object): + pass + d = {} + x = X() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[x] == 1 + + def test_bad_item(self): + class X(object): + pass + class Y(object): + def __hash__(self): + return 32 + + d = {} + x = X() + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + d[y] = 2 + assert not self.uses_identity_strategy(d) + assert d[x] == 1 + assert d[y] == 2 + + def test_bad_key(self): + class X(object): + pass + d = {} + x = X() + + class Y(object): + def __hash__(self): + return hash(x) # to make sure we do x == y + + def __eq__(self, other): + return True + + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[y] == 1 + assert not self.uses_identity_strategy(d) + + def test_iter(self): + class X(object): + pass + x = X() + d = {x: 1} + assert self.uses_identity_strategy(d) + assert list(iter(d)) == [x] + + def test_mutate_class_and_then_compare(self): + class X(object): + pass + class Y(object): + pass + + x = X() + y = Y() + d1 = {x: 1} + d2 = {y: 1} + assert self.uses_identity_strategy(d1) + assert self.uses_identity_strategy(d2) + # + X.__hash__ = lambda self: hash(y) + X.__eq__ = lambda self, other: True + # + assert d1 == d2 + assert self.uses_identity_strategy(d1) + assert not self.uses_identity_strategy(d2) + + def test_old_style_classes(self): + class X: + pass + d = {X(): 1} + assert not self.uses_identity_strategy(d) diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -171,7 +171,7 @@ obj = c.instantiate() assert obj.getweakref() is None obj.setweakref(space, lifeline1) - obj.setweakref(space, None) + obj.delweakref() diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -7,6 +7,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member from pypy.objspace.std.objecttype import object_typedef +from pypy.objspace.std import identitydict from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash from pypy.rlib.jit import promote, elidable_promote, we_are_jitted @@ -76,6 +77,10 @@ for i in range(len(self.lookup_where)): self.lookup_where[i] = None_None +# possible values of compares_by_identity_status +UNKNOWN = 0 +COMPARES_BY_IDENTITY = 1 +OVERRIDES_EQ_CMP_OR_HASH = 2 class W_TypeObject(W_Object): from pypy.objspace.std.typetype import type_typedef as typedef @@ -102,6 +107,9 @@ # (False is a conservative default, fixed during real usage) uses_object_getattribute = False + # for config.objspace.std.withidentitydict + compares_by_identity_status = UNKNOWN + # used to cache the type __new__ function if it comes from a builtin type # != 'type', in that case call__Type will also assumes the result # of the __new__ is an instance of the type @@ -146,11 +154,17 @@ else: w_self.terminator = NoDictTerminator(space, w_self) - def mutated(w_self): + def mutated(w_self, key): + """ + The type is being mutated. key is either the string containing the + specific attribute which is being deleted/set or None to indicate a + generic mutation. + """ space = w_self.space assert w_self.is_heaptype() or space.config.objspace.std.mutable_builtintypes if (not space.config.objspace.std.withtypeversion and not space.config.objspace.std.getattributeshortcut and + not space.config.objspace.std.withidentitydict and not space.config.objspace.std.newshortcut): return @@ -158,6 +172,13 @@ w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage + if space.config.objspace.std.withidentitydict: + did_compare_by_identity = ( + w_self.compares_by_identity_status == COMPARES_BY_IDENTITY) + if (key is None or key == '__eq__' or + key == '__cmp__' or key == '__hash__'): + w_self.compares_by_identity_status = UNKNOWN + if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None @@ -168,7 +189,7 @@ subclasses_w = w_self.get_subclasses() for w_subclass in subclasses_w: assert isinstance(w_subclass, W_TypeObject) - w_subclass.mutated() + w_subclass.mutated(key) def version_tag(w_self): if (not we_are_jitted() or w_self.is_heaptype() or @@ -207,6 +228,25 @@ def has_object_getattribute(w_self): return w_self.getattribute_if_not_from_object() is None + def compares_by_identity(w_self): + from pypy.objspace.descroperation import object_hash + if not w_self.space.config.objspace.std.withidentitydict: + return False # conservative + # + if w_self.compares_by_identity_status != UNKNOWN: + # fast path + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + # + default_hash = object_hash(w_self.space) + overrides_eq_cmp_or_hash = (w_self.lookup('__eq__') or + w_self.lookup('__cmp__') or + w_self.lookup('__hash__') is not default_hash) + if overrides_eq_cmp_or_hash: + w_self.compares_by_identity_status = OVERRIDES_EQ_CMP_OR_HASH + else: + w_self.compares_by_identity_status = COMPARES_BY_IDENTITY + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + def ready(w_self): for w_base in w_self.bases_w: if not isinstance(w_base, W_TypeObject): @@ -269,7 +309,7 @@ w_curr.w_value = w_value return True w_value = TypeCell(w_value) - w_self.mutated() + w_self.mutated(name) w_self.dict_w[name] = w_value return True @@ -286,7 +326,7 @@ except KeyError: return False else: - w_self.mutated() + w_self.mutated(key) return True def lookup(w_self, name): @@ -532,6 +572,8 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None # ____________________________________________________________ # Initialization of type objects diff --git a/pypy/objspace/std/typetype.py b/pypy/objspace/std/typetype.py --- a/pypy/objspace/std/typetype.py +++ b/pypy/objspace/std/typetype.py @@ -141,7 +141,7 @@ w_oldbestbase.getname(space)) # invalidate the version_tag of all the current subclasses - w_type.mutated() + w_type.mutated(None) # now we can go ahead and change 'w_type.bases_w' saved_bases_w = w_type.bases_w diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -482,6 +482,13 @@ key[2:]) cache[key] = s_value + # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass) + try: + graph = self.bookkeeper.position_key[0] + graph.func._dont_reach_me_in_del_ = True + except (TypeError, AttributeError): + pass + return annmodel.s_None def annotate_hooks(self, **kwds_s): diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -875,28 +875,32 @@ if bufsize == -1: # Get default from the class bufsize = self.bufsize self.bufsize = bufsize # buffer size (hint only) - self.buf = "" + self.buf = [] + self.buflen = 0 def flush_buffers(self): if self.buf: - self.do_write(self.buf) - self.buf = "" + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 def tell(self): - return self.do_tell() + len(self.buf) + return self.do_tell() + self.buflen def write(self, data): - buflen = len(self.buf) + buflen = self.buflen datalen = len(data) if datalen + buflen < self.bufsize: - self.buf += data + self.buf.append(data) + self.buflen += datalen elif buflen: - slice = self.bufsize - buflen - assert slice >= 0 - self.buf += data[:slice] - self.do_write(self.buf) - self.buf = "" - self.write(data[slice:]) + i = self.bufsize - buflen + assert i >= 0 + self.buf.append(data[:i]) + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 + self.write(data[i:]) else: self.do_write(data) @@ -922,11 +926,27 @@ """ def write(self, data): - BufferingOutputStream.write(self, data) - p = self.buf.rfind('\n') + 1 - if p >= 0: - self.do_write(self.buf[:p]) - self.buf = self.buf[p:] + p = data.rfind('\n') + 1 + assert p >= 0 + if self.buflen + len(data) < self.bufsize: + if p == 0: + self.buf.append(data) + self.buflen += len(data) + else: + if self.buflen: + self.do_write(''.join(self.buf)) + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) + else: + if self.buflen + p < self.bufsize: + p = self.bufsize - self.buflen + if self.buflen: + self.do_write(''.join(self.buf)) + assert p >= 0 + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) # ____________________________________________________________ diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py --- a/pypy/rlib/test/test_jit.py +++ b/pypy/rlib/test/test_jit.py @@ -83,6 +83,9 @@ t, rtyper, fngraph = self.gengraph(fn, [int]) + # added by compute_result_annotation() + assert fn._dont_reach_me_in_del_ == True + def getargs(func): for graph in t.graphs: if getattr(graph, 'func', None) is func: diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py --- a/pypy/rpython/extfuncregistry.py +++ b/pypy/rpython/extfuncregistry.py @@ -1,6 +1,6 @@ # this registry uses the new interface for external functions -from extfunc import register_external +from pypy.rpython.extfunc import register_external # ___________________________ # math functions @@ -30,24 +30,28 @@ export_name="ll_math.ll_math_%s" % name, sandboxsafe=True, llimpl=llimpl) -register_external(rfloat.isinf, [float], bool, - export_name="ll_math.ll_math_isinf", sandboxsafe=True, - llimpl=ll_math.ll_math_isinf) -register_external(rfloat.isnan, [float], bool, - export_name="ll_math.ll_math_isnan", sandboxsafe=True, - llimpl=ll_math.ll_math_isnan) -register_external(rfloat.isfinite, [float], bool, - export_name="ll_math.ll_math_isfinite", sandboxsafe=True, - llimpl=ll_math.ll_math_isfinite) -register_external(rfloat.copysign, [float, float], float, - export_name="ll_math.ll_math_copysign", sandboxsafe=True, - llimpl=ll_math.ll_math_copysign) -register_external(math.floor, [float], float, - export_name="ll_math.ll_math_floor", sandboxsafe=True, - llimpl=ll_math.ll_math_floor) -register_external(math.sqrt, [float], float, - export_name="ll_math.ll_math_sqrt", sandboxsafe=True, - llimpl=ll_math.ll_math_sqrt) +_register = [ # (module, [(method name, arg types, return type), ...], ...) + (rfloat, [ + ('isinf', [float], bool), + ('isnan', [float], bool), + ('isfinite', [float], bool), + ('copysign', [float, float], float), + ]), + (math, [ + ('floor', [float], float), + ('sqrt', [float], float), + ('log', [float], float), + ('log10', [float], float), + ]), +] +for module, methods in _register: + for name, arg_types, return_type in methods: + method_name = 'll_math_%s' % name + register_external(getattr(module, name), arg_types, return_type, + export_name='ll_math.%s' % method_name, + sandboxsafe=True, + llimpl=getattr(ll_math, method_name)) + complex_math_functions = [ ('frexp', [float], (float, int)), diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -171,17 +171,6 @@ assert max_n >= 0 ITEM = A.OF ctypes_item = get_ctypes_type(ITEM, delayed_builders) - # Python 2.5 ctypes can raise OverflowError on 64-bit builds - for n in [sys.maxint, 2**31]: - MAX_SIZE = n/64 - try: - PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item) - except OverflowError, e: - pass - else: - break - else: - raise e class CArray(ctypes.Structure): if not A._hints.get('nolength'): @@ -190,6 +179,7 @@ else: _fields_ = [('items', max_n * ctypes_item)] + @classmethod def _malloc(cls, n=None): if not isinstance(n, int): raise TypeError, "array length must be an int" @@ -198,10 +188,29 @@ if hasattr(bigarray, 'length'): bigarray.length = n return bigarray - _malloc = classmethod(_malloc) + + _ptrtype = None + + @classmethod + def _get_ptrtype(cls): + if cls._ptrtype: + return cls._ptrtype + # ctypes can raise OverflowError on 64-bit builds + for n in [sys.maxint, 2**31]: + cls.MAX_SIZE = n/64 + try: + cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item) + except OverflowError, e: + pass + else: + break + else: + raise e + return cls._ptrtype def _indexable(self, index): - assert index + 1 < MAX_SIZE + PtrType = self._get_ptrtype() + assert index + 1 < self.MAX_SIZE p = ctypes.cast(ctypes.pointer(self.items), PtrType) return p.contents diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -68,7 +68,6 @@ math_hypot = llexternal(underscore + 'hypot', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) - math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable @@ -221,10 +220,6 @@ return (fracpart, intpart) -def ll_math_copysign(x, y): - return math_copysign(x, y) # no error checking needed - - def ll_math_fmod(x, y): if isinf(y): if isinf(x): @@ -335,6 +330,16 @@ return x # +inf or nan +def ll_math_log(x): + if x <= 0: + raise ValueError("math domain error") + return math_log(x) + +def ll_math_log10(x): + if x <= 0: + raise ValueError("math domain error") + return math_log10(x) + # ____________________________________________________________ # # Default implementations @@ -373,7 +378,7 @@ unary_math_functions = [ 'acos', 'asin', 'atan', 'ceil', 'cos', 'cosh', 'exp', 'fabs', - 'sin', 'sinh', 'tan', 'tanh', 'log', 'log10', + 'sin', 'sinh', 'tan', 'tanh', 'acosh', 'asinh', 'atanh', 'log1p', 'expm1', ] unary_math_functions_can_overflow = [ diff --git a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py --- a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py +++ b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py @@ -1,6 +1,4 @@ - -""" Just another bunch of tests for llmath, run on top of llinterp -""" +"""Just another bunch of tests for llmath, run on top of llinterp.""" from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin from pypy.rpython.lltypesystem.module import ll_math @@ -39,7 +37,7 @@ assert self.interpret(f, [0.3, 0.4]) == f(0.3, 0.4) return next_test - for name in ll_math.unary_math_functions: + for name in ll_math.unary_math_functions + ['log', 'log10', 'sqrt']: func_name = 'test_%s' % (name,) next_test = new_unary_test(name) next_test.func_name = func_name diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py --- a/pypy/rpython/lltypesystem/rclass.py +++ b/pypy/rpython/lltypesystem/rclass.py @@ -400,6 +400,7 @@ assert len(s_func.descriptions) == 1 funcdesc, = s_func.descriptions graph = funcdesc.getuniquegraph() + self.check_graph_of_del_does_not_call_too_much(graph) FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void) destrptr = functionptr(FUNCTYPE, graph.name, graph=graph, diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -102,19 +102,6 @@ else: callbackholder = None - funcptr = lltype.functionptr(ext_type, name, external='C', - compilation_info=compilation_info, - _callable=_callable, - _safe_not_sandboxed=sandboxsafe, - _debugexc=True, # on top of llinterp - canraise=False, - **kwds) - if isinstance(_callable, ll2ctypes.LL2CtypesCallable): - _callable.funcptr = funcptr - - if _nowrapper: - return funcptr - if threadsafe in (False, True): # invoke the around-handlers, which release the GIL, if and only if # the C function is thread-safe. @@ -125,6 +112,21 @@ # sandboxsafe is a hint for "too-small-ness" (e.g. math functions). invoke_around_handlers = not sandboxsafe + funcptr = lltype.functionptr(ext_type, name, external='C', + compilation_info=compilation_info, + _callable=_callable, + _safe_not_sandboxed=sandboxsafe, + _debugexc=True, # on top of llinterp + canraise=False, + releases_gil=invoke_around_handlers, + **kwds) + if isinstance(_callable, ll2ctypes.LL2CtypesCallable): + _callable.funcptr = funcptr + + if _nowrapper: + return funcptr + + if invoke_around_handlers: # The around-handlers are releasing the GIL in a threaded pypy. # We need tons of care to ensure that no GC operation and no diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -486,6 +486,11 @@ return True + def ll_startswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[0] == ch + @elidable def ll_endswith(s1, s2): len1 = len(s1.chars) @@ -503,6 +508,11 @@ return True + def ll_endswith_char(s, ch): + if not len(s.chars): + return False + return s.chars[len(s.chars) - 1] == ch + @elidable def ll_find_char(s, ch, start, end): i = start diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -671,7 +671,7 @@ assert not ALLOCATED # detects memory leaks in the test def test_arrayofstruct(self): - S1 = lltype.Struct('S1', ('x', lltype.Signed)) + S1 = lltype.Struct('S2', ('x', lltype.Signed)) A = lltype.Array(S1, hints={'nolength': True}) a = lltype.malloc(A, 5, flavor='raw') a[0].x = 100 diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,6 +34,13 @@ the GC in very small programs. Defaults to 8 times the nursery. + PYPY_GC_LOSTCARD If between two minor collections we see more than + 'PYPY_GC_LOSTCARD * length' writes to the same array, + then give up card marking and use the fast write + barrier instead. Defaults to 0.3333 for now. + Avoid values lower than 0.125: it is the growth + factor of list.append(). + PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -198,6 +205,9 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, + # See PYPY_GC_LOSTCARD. + "lost_card": 1.0 / 3.0, + # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -214,6 +224,7 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, + lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -235,6 +246,7 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 + self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -355,6 +367,10 @@ else: self.max_delta = 0.125 * env.get_total_memory() # + lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') + if lost_card > 0.0: + self.lost_card = lost_card + # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -649,7 +665,7 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only @@ -675,11 +691,15 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # (the loop is empty in C). + # followed by a Signed (the loop is empty in C). + if cardheadersize > 0: i = 0 - while i < cardheadersize: - llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) + while i < cardheadersize - WORD: + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Char)) i += 1 + llarena.arena_reserve(arena + i, + llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -903,14 +923,11 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # - size_gc_header = self.gcheaderbuilder.size_gc_header - p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: - p -= 1 - ll_assert(p.char[0] == '\x00', + i -= 1 + ll_assert(self.get_card(obj, i).char[0] == '\x00', "the card marker bits are not cleared") - i -= 1 # ---------- # Write barrier @@ -1008,6 +1025,8 @@ self.prebuilt_root_objects.append(addr_array) return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1025,10 +1044,6 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1057,6 +1072,8 @@ if not self.appears_to_be_young(newvalue): return # + self.set_cards_flag(addr_array) + # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1069,10 +1086,6 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) - # - if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) - objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1090,11 +1103,36 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card(self, obj, byteindex): + def get_card_counter_addr(self, obj): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) + (~byteindex) + return llarena.getfakearenaaddress(addr_byte) - WORD + def get_card(self, obj, byteindex): + return self.get_card_counter_addr(obj) + (~byteindex) + + def set_cards_flag(self, obj): + hdr = self.header(obj) + if hdr.tid & GCFLAG_CARDS_SET == 0: + # + # first time we set a card bit in this object + self.header(obj).tid |= GCFLAG_CARDS_SET + self.objects_with_cards_set.append(obj) + # + # initialize the counter with the array length and self.lost_card + typeid = self.get_type_id(obj) + offset_to_length = self.varsize_offset_to_length(typeid) + length = (obj + offset_to_length).signed[0] + counter = int(length * self.lost_card) + self.get_card_counter_addr(obj).signed[0] = counter + else: + # decrement the counter and if zero is reached, give up on + # card marking (up to the next collection). + addr = self.get_card_counter_addr(obj) + addr.signed[0] -= 1 + if addr.signed[0] < 0: + self.objects_pointing_to_young.append(obj) + hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1167,10 +1205,7 @@ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - dest_hdr = self.header(dest_addr) - if dest_hdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(dest_addr) - dest_hdr.tid |= GCFLAG_CARDS_SET + self.set_cards_flag(dest_addr) # ---------- # Nursery collection @@ -1264,6 +1299,7 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) + p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1602,7 +1638,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + extra_words = self.card_marking_words_for_length(length) + 1 arena -= extra_words * WORD allocsize += extra_words * WORD # diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py --- a/pypy/rpython/memory/gc/test/test_direct.py +++ b/pypy/rpython/memory/gc/test/test_direct.py @@ -525,6 +525,7 @@ def test_writebarrier_before_copy(self): from pypy.rpython.memory.gc import minimark largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 p_src = self.malloc(VAR, largeobj_size) p_dst = self.malloc(VAR, largeobj_size) # make them old @@ -564,6 +565,7 @@ from pypy.rpython.memory.gc import minimark tid = self.get_type_id(VAR) largeobj_size = self.gc.nonlarge_max + 1 + self.gc.next_major_collection_threshold = 99999.0 addr_src = self.gc.external_malloc(tid, largeobj_size) addr_dst = self.gc.external_malloc(tid, largeobj_size) hdr_src = self.gc.header(addr_src) diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py --- a/pypy/rpython/memory/gctransform/asmgcroot.py +++ b/pypy/rpython/memory/gctransform/asmgcroot.py @@ -184,7 +184,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.aid2stack = copy_without_null_values(gcdata.aid2stack) + copy = copy_without_null_values(gcdata.aid2stack) + gcdata.aid2stack.delete() + gcdata.aid2stack = copy def belongs_to_current_thread(framedata): # xxx obscure: the answer is Yes if, as a pointer, framedata diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -1449,8 +1449,9 @@ # old NULL entries gcdata.dead_threads_count += 1 if (gcdata.dead_threads_count & 511) == 0: - gcdata.thread_stacks = copy_without_null_values( - gcdata.thread_stacks) + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy def switch_shadow_stacks(new_aid): save_away_current_stack() diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -433,7 +433,9 @@ "ll_streq": Meth([self.SELFTYPE_T], Bool), "ll_strcmp": Meth([self.SELFTYPE_T], Signed), "ll_startswith": Meth([self.SELFTYPE_T], Bool), + "ll_startswith_char": Meth([self.CHAR], Bool), "ll_endswith": Meth([self.SELFTYPE_T], Bool), + "ll_endswith_char": Meth([self.CHAR], Bool), "ll_find": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_rfind": Meth([self.SELFTYPE_T, Signed, Signed], Signed), "ll_count": Meth([self.SELFTYPE_T, Signed, Signed], Signed), @@ -1429,10 +1431,18 @@ # NOT_RPYTHON return self._str.startswith(s._str) + def ll_startswith_char(self, s): + # NOT_RPYTHON + return self._str.startswith(s) + def ll_endswith(self, s): # NOT_RPYTHON return self._str.endswith(s._str) + def ll_endswith_char(self, s): + # NOT_RPYTHON + return self._str.endswith(s) + def ll_find(self, s, start, end): # NOT_RPYTHON if start > len(self._str): # workaround to cope with corner case diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py --- a/pypy/rpython/rclass.py +++ b/pypy/rpython/rclass.py @@ -374,6 +374,43 @@ def can_ll_be_null(self, s_value): return s_value.can_be_none() + def check_graph_of_del_does_not_call_too_much(self, graph): + # RPython-level __del__() methods should not do "too much". + # In the PyPy Python interpreter, they usually do simple things + # like file.__del__() closing the file descriptor; or if they + # want to do more like call an app-level __del__() method, they + # enqueue the object instead, and the actual call is done later. + # + # Here, as a quick way to check "not doing too much", we check + # that from no RPython-level __del__() method we can reach a + # JitDriver. + # + # XXX wrong complexity, but good enough because the set of + # reachable graphs should be small + callgraph = self.rtyper.annotator.translator.callgraph.values() + seen = {graph: None} + while True: + oldlength = len(seen) + for caller, callee in callgraph: + if caller in seen and callee not in seen: + func = getattr(callee, 'func', None) + if getattr(func, '_dont_reach_me_in_del_', False): + lst = [str(callee)] + g = caller + while g: + lst.append(str(g)) + g = seen.get(g) + lst.append('') + raise TyperError("the RPython-level __del__() method " + "in %r calls:%s" % ( + graph, '\n\t'.join(lst[::-1]))) + if getattr(func, '_cannot_really_call_random_things_', + False): + continue + seen[callee] = caller + if len(seen) == oldlength: + break + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops, classcallhop=None): diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py --- a/pypy/rpython/rlist.py +++ b/pypy/rpython/rlist.py @@ -667,7 +667,6 @@ res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res -ll_pop.oopspec = 'list.pop(l, index)' def ll_reverse(l): length = l.ll_length() diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py --- a/pypy/rpython/rstr.py +++ b/pypy/rpython/rstr.py @@ -81,16 +81,30 @@ return super(AbstractStringRepr, self).rtype_is_true(hop) def rtype_method_startswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_startswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_startswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_startswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_endswith(self, hop): - str1_repr, str2_repr = self._str_reprs(hop) - v_str, v_value = hop.inputargs(str1_repr, str2_repr) + str1_repr = hop.args_r[0].repr + str2_repr = hop.args_r[1] + v_str = hop.inputarg(str1_repr, arg=0) + if str2_repr == str2_repr.char_repr: + v_value = hop.inputarg(str2_repr.char_repr, arg=1) + fn = self.ll.ll_endswith_char + else: + v_value = hop.inputarg(str2_repr, arg=1) + fn = self.ll.ll_endswith hop.exception_cannot_occur() - return hop.gendirectcall(self.ll.ll_endswith, v_str, v_value) + return hop.gendirectcall(fn, v_str, v_value) def rtype_method_find(self, hop, reverse=False): # XXX binaryop diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py --- a/pypy/rpython/test/test_rclass.py +++ b/pypy/rpython/test/test_rclass.py @@ -7,6 +7,7 @@ from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.rpython.error import TyperError from pypy.objspace.flow.model import summary class EmptyBase(object): @@ -1022,6 +1023,24 @@ assert destrptra is not None assert destrptrb is not None + def test_del_forbidden(self): + class A(object): + def __del__(self): + self.foo() + def foo(self): + self.bar() + def bar(self): + pass + bar._dont_reach_me_in_del_ = True + def f(): + a = A() + a.foo() + a.bar() + t = TranslationContext() + t.buildannotator().build_types(f, []) + e = py.test.raises(TyperError, t.buildrtyper().specialize) + print e.value + def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int class FooBar(object): diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -227,6 +227,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_startswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].startswith(const('o')) + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_endswith(self): const = self.const def fn(i, j): @@ -238,6 +247,15 @@ res = self.interpret(fn, [i,j]) assert res is fn(i, j) + def test_endswith_char(self): + const = self.const + def fn(i): + s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')] + return s[i].endswith(const('e')) + for i in range(10): + res = self.interpret(fn, [i]) + assert res == fn(i) + def test_find(self): const = self.const def fn(i, j): diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -18,4 +18,5 @@ if __name__ == '__main__': import tool.autopath import pytest - sys.exit(pytest.main()) + import pytest_cov + sys.exit(pytest.main(plugins=[pytest_cov])) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -30,6 +30,9 @@ def getres(self): return self._getvar(self.res) + def getdescr(self): + return self.descr + def _getvar(self, v): return v @@ -39,7 +42,7 @@ def repr(self): args = self.getargs() if self.descr is not None: - args.append('descr=%s' % self.descr) + args.append('descr=%s' % self.getdescr()) arglist = ', '.join(args) if self.res is not None: return '%s = %s(%s)' % (self.getres(), self.name, arglist) @@ -89,7 +92,7 @@ while asm[asm_index][0] < op.offset: asm_index += 1 end_index = asm_index - while asm[end_index][0] < end: + while asm[end_index][0] < end and end_index < len(asm) - 1: end_index += 1 op.asm = '\n'.join([asm[i][1] for i in range(asm_index, end_index)]) return loop @@ -145,10 +148,10 @@ if operations[0].name == 'debug_merge_point': self.inline_level = int(operations[0].args[0]) m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', - operations[0].getarg(1)) + operations[0].args[1]) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1].split(" ")[0][1:] + self.bytecode_name = operations[0].args[1][1:-1] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) @@ -336,27 +339,45 @@ log = parse_log_file(logname) addrs = {} for entry in extract_category(log, 'jit-backend-addr'): - m = re.search('bootstrap ([\da-f]+)', entry) - name = entry[:entry.find('(') - 1] - addrs[int(m.group(1), 16)] = name + m = re.search('bootstrap ([-\da-f]+)', entry) + if not m: + # a bridge + m = re.search('has address ([-\da-f]+)', entry) + addr = int(m.group(1), 16) + entry = entry.lower() + m = re.search('guard \d+', entry) + name = m.group(0) + else: + name = entry[:entry.find('(') - 1].lower() + addr = int(m.group(1), 16) + addrs.setdefault(addr, []).append(name) dumps = {} for entry in extract_category(log, 'jit-backend-dump'): backend, _, dump, _ = entry.split("\n") _, addr, _, data = re.split(" +", dump) backend_name = backend.split(" ")[1] addr = int(addr[1:], 16) - if addr in addrs: - dumps[addrs[addr]] = (backend_name, addr, data) + if addr in addrs and addrs[addr]: + name = addrs[addr].pop(0) # they should come in order + dumps[name] = (backend_name, addr, data) loops = [] for entry in extract_category(log, 'jit-log-opt'): parser = ParserCls(entry, None, {}, 'lltype', None, nonstrict=True) loop = parser.parse() comm = loop.comment + comm = comm.lower() + if comm.startswith('# bridge'): + m = re.search('guard \d+', comm) + name = m.group(0) + else: name = comm[2:comm.find(':')-1] if name in dumps: bname, start_ofs, dump = dumps[name] - parser.postprocess(loop, backend_tp=bname, backend_dump=dump, - dump_start=start_ofs) + loop.force_asm = (lambda dump=dump, start_ofs=start_ofs, + bname=bname, loop=loop: + parser.postprocess(loop, backend_tp=bname, + backend_dump=dump, + dump_start=start_ofs)) loops.append(loop) return log, loops diff --git a/pypy/tool/jitlogparser/test/logtest2.log b/pypy/tool/jitlogparser/test/logtest2.log new file mode 100644 --- /dev/null +++ b/pypy/tool/jitlogparser/test/logtest2.log @@ -0,0 +1,301 @@ +[1f5e7f69779] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b000 +0 4157415641554154415341524151415057565554535251504889E349C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f7fe75] jit-backend-dump} +[1f5e7f84fc4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b045 +0 4157415641554154415341524151415057565554535251504889E349C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f87ac1] jit-backend-dump} +[1f5e7f8a0b4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b08a +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C340BC920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f8da6b] jit-backend-dump} +[1f5e7f8f4f6] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b13d +0 4157415641554154415341524151415057565554535251504889E34881EC80000000F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438F2440F11442440F2440F114C2448F2440F11542450F2440F115C2458F2440F11642460F2440F116C2468F2440F11742470F2440F117C247849C7C3F0BB920041FFD34889DF4883E4F049C7C350BC920041FFD3488D65D8415F415E415D415C5B5DC3 +[1f5e7f92b83] jit-backend-dump} +[1f5e7f95b99] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b210 +0 F20F11442410F20F114C2418F20F11542420F20F115C2428F20F11642430F20F116C2438F20F11742440F20F117C2448F2440F11442450F2440F114C2458F2440F11542460F2440F115C2468F2440F11642470F2440F116C2478F2440F11B42480000000F2440F11BC24880000004829C24889D749C7C350A8920041FFE3 +[1f5e7f988d0] jit-backend-dump} +[1f5e7fa16fb] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b28e +0 F20F10442410F20F104C2418F20F10542420F20F105C2428F20F10642430F20F106C2438F20F10742440F20F107C2448F2440F10442450F2440F104C2458F2440F10542460F2440F105C2468F2440F10642470F2440F106C2478F2440F10B42480000000F2440F10BC2488000000488B1425704F3D01C3 +[1f5e7fa47ac] jit-backend-dump} +[1f5e7fab3a4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b305 +0 57565251415041514883EC40F20F110424F20F114C2408F20F11542410F20F115C2418F20F11642420F20F116C2428F20F11742430F20F117C2438488D7D1049C7C340BA520041FFD3488B042550546B024885C0753CF20F107C2438F20F10742430F20F106C2428F20F10642420F20F105C2418F20F10542410F20F104C2408F20F1004244883C44041594158595A5E5FC3488B042558546B0248C7042550546B020000000048C7042558546B02000000004889042590C2540149C7C340BC920041FFD348C7C0020000004883C478C3 +[1f5e7faf1ca] jit-backend-dump} +[1f5e7fb0813] {jit-backend-counts +[1f5e7fb0f61] jit-backend-counts} +[1f5fd38be3e] {jit-backend +[1f5fe729336] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB30B00C0A897F00004D8B334983C60149BB30B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030300000049BB00B0A007897F000041FFD34440484C3D39030400000049BB00B0A007897F000041FFD34440484C3907070305000000 +[1f5fe73276a] jit-backend-dump} +[1f5fe73438f] {jit-backend-addr +Loop 0 ( #9 LOAD_FAST) has address 7f8907a0b45d to 7f8907a0b4c3 (bootstrap 7f8907a0b3d5) +[1f5fe7369af] jit-backend-addr} +[1f5fe737940] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3e5 +0 50FFFFFF +[1f5fe74b40e] jit-backend-dump} +[1f5fe74c63d] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b484 +0 95000000 +[1f5fe74da6a] jit-backend-dump} +[1f5fe74e438] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 9B000000 +[1f5fe74f513] jit-backend-dump} +[1f5fe74fd2e] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b4b7 +0 91000000 +[1f5fe750d8c] jit-backend-dump} +[1f5fe75373f] jit-backend} +[1f5fe755abc] {jit-log-opt-loop +# Loop 0 : loop with 26 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #9 LOAD_FAST') +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 1) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f5fe92b8af] jit-log-opt-loop} +[1f5fe944ae5] {jit-backend +[1f5fee20651] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b565 +0 554889E5534154415541564157488DA5000000004C8B3C2590C2540148C7042590C25401000000004C8B342598C2540148C7042598C25401000000004C8B2C25A0C2540148C70425A0C25401000000004C8B2425A8C2540148C70425A8C25401000000004C8B1425D04D5B014C8B0C25B8C2540148C70425B8C25401000000004C8B0425E04D5B01488B3C25E84D5B01488B3425D0C2540148C70425D0C2540100000000488B1C25D8C2540148C70425D8C2540100000000488B1425E0C2540148C70425E0C254010000000049BB38B00C0A897F0000498B0B4883C10149BB38B00C0A897F000049890B4983F8010F85000000004883FE017206813E980700000F85000000004983FA000F850000000049BBA8F0B407897F00004D39DC0F8500000000488B56084881FA102700000F8D000000004989D44883E2024883FA000F85000000004983C403488B1425A0536B024883EA0148891425A0536B024883FA000F8C000000004C89BD70FFFFFF4C89B568FFFFFF4C89AD60FFFFFF4C898D58FFFFFF4D89E749BB5DB4A007897F000041FFE3488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4989FF4989F64989D54989CC4D89C24C8B5D104D89D84C8B5D184C89DF4C8B5D204C89DE4C8B5D284C89DB4C8B5D304C89DAE9CCFEFFFF49BB00B0A007897F000041FFD321383C343029241D180C08030600000049BB00B0A007897F000041FFD3383C18343029240C08030700000049BB00B0A007897F000041FFD329383C3430241808030800000049BB00B0A007897F000041FFD3383C3034241808030900000049BB00B0A007897F000041FFD3383C183424030A00000049BB00B0A007897F000041FFD3383C34241809030B00000049BB00B0A007897F000041FFD3383C34243107030C000000 +[1f5fee2e673] jit-backend-dump} +[1f5fee2f38d] {jit-backend-addr +Loop 1 ( #9 LOAD_FAST) has address 7f8907a0b631 to 7f8907a0b6f8 (bootstrap 7f8907a0b565) +[1f5fee312e3] jit-backend-addr} +[1f5fee320ed] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b575 +0 50FFFFFF +[1f5fee3e903] jit-backend-dump} +[1f5fee3fbff] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b655 +0 0C010000 +[1f5fee41579] jit-backend-dump} +[1f5fee421af] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b667 +0 17010000 +[1f5fee43835] jit-backend-dump} +[1f5fee44261] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b671 +0 28010000 +[1f5fee457c1] jit-backend-dump} +[1f5fee461a5] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b684 +0 2F010000 +[1f5fee475d3] jit-backend-dump} +[1f5fee47f57] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b695 +0 37010000 +[1f5fee4933d] jit-backend-dump} +[1f5fee49cd9] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6a6 +0 3D010000 +[1f5fee4b0ad] jit-backend-dump} +[1f5fee4ba4f] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b6c8 +0 33010000 +[1f5fee4cf61] jit-backend-dump} +[1f5fee4dc45] jit-backend} +[1f5fee4f3a9] {jit-log-opt-loop +# Loop 1 : entry bridge with 31 ops +[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10] +debug_merge_point(0, ' #9 LOAD_FAST') ++234: guard_value(i6, 1, descr=) [i6, p1, p0, p2, p3, i4, p5, i7, p8, p9, p10] ++244: guard_nonnull_class(p8, ConstClass(W_IntObject), descr=) [p1, p0, p8, p2, p3, i4, p5, p9, p10] ++262: guard_value(i4, 0, descr=) [i4, p1, p0, p2, p3, p5, p8, p10] +debug_merge_point(0, ' #12 LOAD_CONST') ++272: guard_value(p3, ConstPtr(ptr14), descr=) [p1, p0, p3, p2, p5, p8, p10] +debug_merge_point(0, ' #15 COMPARE_OP') ++291: i15 = getfield_gc_pure(p8, descr=) ++295: i17 = int_lt(i15, 10000) +guard_true(i17, descr=) [p1, p0, p8, p2, p5] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++308: i19 = int_and(i15, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++315: i20 = int_is_true(i19) +guard_false(i20, descr=) [p1, p0, p2, p5, p8, i19] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++325: i22 = int_add(i15, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++329: i24 = getfield_raw(40588192, descr=) ++337: i26 = int_sub(i24, 1) ++341: setfield_raw(40588192, i26, descr=) ++349: i28 = int_lt(i26, 0) +guard_false(i28, descr=) [p1, p0, p2, p5, i22, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++359: jump(p0, p1, p2, p5, i22, descr=) ++403: --end of the loop-- +[1f60036d952] jit-log-opt-loop} +[1f600719a74] {jit-backend +[1f600759dac] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b817 +0 554889E5534154415541564157488DA500000000488B042590C2540148C7042590C254010000000048898570FFFFFF488B042598C2540148C7042598C254010000000048898568FFFFFF488B0425A0C2540148C70425A0C254010000000048898560FFFFFF488B0425A8C2540148C70425A8C254010000000048898558FFFFFF4C8B3C25D04D5B0149BB40B00C0A897F00004D8B334983C60149BB40B00C0A897F00004D89334981FF102700000F8D000000004D89FE4983E7024983FF000F85000000004983C6034C8B3C25A0536B024983EF024C893C25A0536B024983FF000F8C000000004D89F7E99AFFFFFF488B0425A8536B024829E0483B042580DC3C01760D49BB05B3A007897F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E940FFFFFF49BB00B0A007897F000041FFD34440484C3D030D00000049BB00B0A007897F000041FFD34440484C3D39030E00000049BB00B0A007897F000041FFD34440484C390707030F000000 +[1f60076fd90] jit-backend-dump} +[1f600770f30] {jit-backend-addr +Loop 2 ( #9 LOAD_FAST) has address 7f8907a0b89f to 7f8907a0b905 (bootstrap 7f8907a0b817) +[1f6007730fc] jit-backend-addr} +[1f600773fde] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b827 +0 50FFFFFF +[1f600775c76] jit-backend-dump} +[1f600776a38] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8c6 +0 95000000 +[1f600778112] jit-backend-dump} +[1f600778b8c] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8d7 +0 9B000000 +[1f60077a04a] jit-backend-dump} +[1f60077aa6a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b8f9 +0 91000000 +[1f60077bf10] jit-backend-dump} +[1f60077cc24] jit-backend} +[1f60077e094] {jit-log-opt-loop +# Loop 2 : loop with 25 ops +[p0, p1, p2, p3, i4] +debug_merge_point(0, ' #12 LOAD_CONST') +debug_merge_point(0, ' #15 COMPARE_OP') ++166: i6 = int_lt(i4, 10000) +guard_true(i6, descr=) [p1, p0, p2, p3, i4] +debug_merge_point(0, ' #18 POP_JUMP_IF_FALSE') +debug_merge_point(0, ' #21 LOAD_FAST') +debug_merge_point(0, ' #24 LOAD_CONST') +debug_merge_point(0, ' #27 BINARY_AND') ++179: i8 = int_and(i4, 2) +debug_merge_point(0, ' #28 POP_JUMP_IF_FALSE') ++186: i9 = int_is_true(i8) +guard_false(i9, descr=) [p1, p0, p2, p3, i8, i4] +debug_merge_point(0, ' #44 LOAD_FAST') +debug_merge_point(0, ' #47 LOAD_CONST') +debug_merge_point(0, ' #50 INPLACE_ADD') ++196: i11 = int_add(i4, 3) +debug_merge_point(0, ' #51 STORE_FAST') +debug_merge_point(0, ' #54 JUMP_ABSOLUTE') ++200: i13 = getfield_raw(40588192, descr=) ++208: i15 = int_sub(i13, 2) ++212: setfield_raw(40588192, i15, descr=) ++220: i17 = int_lt(i15, 0) +guard_false(i17, descr=) [p1, p0, p2, p3, i11, None, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++230: jump(p0, p1, p2, p3, i11, descr=) ++238: --end of the loop-- +[1f6007a567c] jit-log-opt-loop} +[1f600802cd6] {jit-backend +[1f600862dd8] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9b7 +0 488DA50000000049BB48B00C0A897F00004D8B3B4983C70149BB48B00C0A897F00004D893B4D89F74983C6010F80000000004C8B3C25A0536B024983EF014C893C25A0536B024983FF000F8C00000000488B0425704F3D01488D5010483B1425784F3D01761A49BB10B2A007897F000041FFD349BB8EB2A007897F000041FFD348C7009807000048891425704F3D014C89700848898550FFFFFF4C8BBD70FFFFFF4C8BB568FFFFFF4C8BAD60FFFFFF49BBA8F0B407897F00004D89DC49C7C2000000004C8B8D58FFFFFF49C7C00100000048C7C709000000488BB550FFFFFF48C7C30000000048C7C20000000049BB31B6A007897F000041FFE349BB00B0A007897F000041FFD3444039484C3D031000000049BB00B0A007897F000041FFD34440484C39070311000000 +[1f60086ba5a] jit-backend-dump} +[1f60086d36e] {jit-backend-addr +Bridge out of guard 4 has address 7f8907a0b9b7 to 7f8907a0bab1 +[1f60086ffd2] jit-backend-addr} +[1f600870dca] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b9ba +0 C0FEFFFF +[1f60087281c] jit-backend-dump} +[1f600873506] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b3d5 +0 C8000000 +[1f600874b44] jit-backend-dump} +[1f6008754d4] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0ba03 +0 C2000000 +[1f600876956] jit-backend-dump} +[1f600877b1a] {jit-backend-dump +BACKEND x86_64 +SYS_EXECUTABLE python +CODE_DUMP @7f8907a0b495 +0 1E050000 +[1f600878f4e] jit-backend-dump} +[1f600884c12] jit-backend} +[1f60088780a] {jit-log-opt-bridge +# bridge out of Guard 4 with 16 ops +[p0, p1, p2, p3, i4, i5] +debug_merge_point(0, ' #31 LOAD_FAST') +debug_merge_point(0, ' #34 LOAD_CONST') +debug_merge_point(0, ' #37 INPLACE_ADD') ++37: i7 = int_add_ovf(i5, 1) +guard_no_overflow(, descr=) [p0, p1, i7, p2, p3, i5] +debug_merge_point(0, ' #38 STORE_FAST') +debug_merge_point(0, ' #41 JUMP_ABSOLUTE') ++50: i9 = getfield_raw(40588192, descr=) ++58: i11 = int_sub(i9, 1) ++62: setfield_raw(40588192, i11, descr=) ++70: i13 = int_lt(i11, 0) +guard_false(i13, descr=) [p0, p1, p2, p3, i7, None] +debug_merge_point(0, ' #9 LOAD_FAST') ++80: p16 = new_with_vtable(ConstClass(W_IntObject)) ++143: setfield_gc(p16, i7, descr=) ++147: jump(p1, p0, p2, ConstPtr(ptr17), 0, p3, 1, 9, p16, ConstPtr(ptr21), ConstPtr(ptr22), descr=) ++250: --end of the loop-- +[1f6008aa976] jit-log-opt-bridge} +[1f600912c98] {jit-backend-counts +0:1982 +1:1985 +2:0 +3:1782 +[1f600916544] jit-backend-counts} diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,6 +1,6 @@ from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, Function, adjust_bridges, - import_log) + import_log, Op) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys @@ -181,7 +181,7 @@ """) ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] - assert chunk.bytecode_name == 'StrLiteralSearch' + assert chunk.bytecode_name.startswith('StrLiteralSearch') def test_parsing_assembler(): backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" @@ -213,4 +213,21 @@ def test_import_log(): _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) + for loop in loops: + loop.force_asm() assert 'jge' in loops[0].operations[3].asm + +def test_import_log_2(): + _, loops = import_log(str(py.path.local(__file__).join('..', + 'logtest2.log'))) + for loop in loops: + loop.force_asm() + assert 'cmp' in loops[1].operations[1].asm + # bridge + assert 'jo' in loops[3].operations[3].asm + +def test_Op_repr_is_pure(): + op = Op('foobar', ['a', 'b'], 'c', 'mydescr') + myrepr = 'c = foobar(a, b, descr=mydescr)' + assert op.repr() == myrepr + assert op.repr() == myrepr # do it twice diff --git a/pypy/tool/nullpath.py b/pypy/tool/nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/nullpath.py @@ -0,0 +1,12 @@ +import py + +class NullPyPathLocal(py.path.local): + + def join(self, *args): + return self.__class__(py.path.local.join(self, *args)) + + def open(self, mode): + return open('/dev/null', mode) + + def __repr__(self): + return py.path.local.__repr__(self) + ' [fake]' diff --git a/pypy/tool/release/win32build.py b/pypy/tool/release/win32build.py --- a/pypy/tool/release/win32build.py +++ b/pypy/tool/release/win32build.py @@ -24,6 +24,6 @@ shutil.copy(str(pypydir.join('..', '..', 'expat-2.0.1', 'win32', 'bin', 'release', 'libexpat.dll')), str(builddir)) make_pypy('', ['-Ojit']) -make_pypy('-nojit', []) +make_pypy('-nojit', ['-O2']) #make_pypy('-stackless', [--stackless]) #make_pypy('-sandbox', [--sandbox]) diff --git a/pypy/tool/test/test_nullpath.py b/pypy/tool/test/test_nullpath.py new file mode 100644 --- /dev/null +++ b/pypy/tool/test/test_nullpath.py @@ -0,0 +1,16 @@ +import sys +import py +from pypy.tool.nullpath import NullPyPathLocal + +def setup_module(): + if 'posix' not in sys.builtin_module_names: + py.test.skip('posix only') + +def test_nullpath(tmpdir): + path = NullPyPathLocal(tmpdir) + assert repr(path).endswith('[fake]') + foo_txt = path.join('foo.txt') + assert isinstance(foo_txt, NullPyPathLocal) + # + f = foo_txt.open('w') + assert f.name == '/dev/null' diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1824,6 +1824,11 @@ __gccallshapes: """.replace("__gccallshapes", _globalname("__gccallshapes")) output.writelines(shapelines) + print >> output, """\ + #if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits + #endif + """ def process(self, iterlines, newfile, filename='?'): parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle) diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py --- a/pypy/translator/c/genc.py +++ b/pypy/translator/c/genc.py @@ -13,6 +13,7 @@ from pypy.rpython.typesystem import getfunctionptr from pypy.translator.c import gc from pypy.rlib import exports +from pypy.tool.nullpath import NullPyPathLocal def import_module_from_directory(dir, modname): file, pathname, description = imp.find_module(modname, [str(dir)]) @@ -237,6 +238,8 @@ self.modulename = uniquemodulename('testing') modulename = self.modulename targetdir = udir.ensure(modulename, dir=1) + if self.config.translation.dont_write_c_files: + targetdir = NullPyPathLocal(targetdir) self.targetdir = targetdir defines = defines.copy() @@ -248,12 +251,8 @@ CBuilder.have___thread = self.translator.platform.check___thread() if not self.standalone: assert not self.config.translation.instrument - self.eci, cfile, extra = gen_source(db, modulename, targetdir, - self.eci, - defines = defines, - split=self.split) else: - pfname = db.get(pf) + defines['PYPY_STANDALONE'] = db.get(pf) if self.config.translation.instrument: defines['INSTRUMENT'] = 1 if CBuilder.have___thread: @@ -263,11 +262,9 @@ defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( export_symbols=["pypy_main_startup"])) - self.eci, cfile, extra = gen_source_standalone(db, modulename, - targetdir, - self.eci, - entrypointname = pfname, - defines = defines) + self.eci, cfile, extra = gen_source(db, modulename, targetdir, + self.eci, defines=defines, + split=self.split) self.c_source_filename = py.path.local(cfile) self.extrafiles = self.eventually_copy(extra) self.gen_makefile(targetdir, exe_name=exe_name) @@ -432,6 +429,7 @@ class CStandaloneBuilder(CBuilder): standalone = True + split = True executable_name = None shared_library_name = None @@ -688,11 +686,37 @@ def getothernodes(self): return self.othernodes[:] + def getbasecfilefornode(self, node, basecname): + # For FuncNode instances, use the python source filename (relative to + # the top directory): + if hasattr(node.obj, 'graph'): + g = node.obj.graph + # Lookup the filename from the function. + # However, not all FunctionGraph objs actually have a "func": + if hasattr(g, 'func'): + if g.filename.endswith('.py'): + localpath = py.path.local(g.filename) + pypkgpath = localpath.pypkgpath() + if pypkgpath: + relpypath = localpath.relto(pypkgpath) + return relpypath.replace('.py', '.c') + return basecname + def splitnodesimpl(self, basecname, nodes, nextra, nbetween, split_criteria=SPLIT_CRITERIA): + # Gather nodes by some criteria: + nodes_by_base_cfile = {} + for node in nodes: + c_filename = self.getbasecfilefornode(node, basecname) + if c_filename in nodes_by_base_cfile: + nodes_by_base_cfile[c_filename].append(node) + else: + nodes_by_base_cfile[c_filename] = [node] + # produce a sequence of nodes, grouped into files # which have no more than SPLIT_CRITERIA lines - iternodes = iter(nodes) + for basecname in nodes_by_base_cfile: + iternodes = iter(nodes_by_base_cfile[basecname]) done = [False] def subiter(): used = nextra @@ -918,64 +942,12 @@ ] return eci.merge(ExternalCompilationInfo(separate_module_files=files)) -def gen_source_standalone(database, modulename, targetdir, eci, - entrypointname, defines={}): - assert database.standalone + +def gen_source(database, modulename, targetdir, + eci, defines={}, split=False): if isinstance(targetdir, str): targetdir = py.path.local(targetdir) - filename = targetdir.join(modulename + '.c') - f = filename.open('w') - incfilename = targetdir.join('common_header.h') - fi = incfilename.open('w') - # - # Header - # - print >> f, '#include "common_header.h"' - print >> f - commondefs(defines) - defines['PYPY_STANDALONE'] = entrypointname - for key, value in defines.items(): - print >> fi, '#define %s %s' % (key, value) - - eci.write_c_header(fi) - print >> fi, '#include "src/g_prerequisite.h"' - - fi.close() - - preimplementationlines = list( - pre_include_code_lines(database, database.translator.rtyper)) - - # - # 1) All declarations - # 2) Implementation of functions and global structures and arrays - # - sg = SourceGenerator(database, preimplementationlines) - sg.set_strategy(targetdir) - database.prepare_inline_helpers() - sg.gen_readable_parts_of_source(f) - - # 3) start-up code - print >> f - gen_startupcode(f, database) - - f.close() - - if 'INSTRUMENT' in defines: - fi = incfilename.open('a') - n = database.instrument_ncounter - print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n - fi.close() - - eci = add_extra_files(eci) - eci = eci.convert_sources_to_files(being_main=True) - files, eci = eci.get_module_files() - return eci, filename, sg.getextrafiles() + list(files) - -def gen_source(database, modulename, targetdir, eci, defines={}, split=False): - assert not database.standalone - if isinstance(targetdir, str): - targetdir = py.path.local(targetdir) filename = targetdir.join(modulename + '.c') f = filename.open('w') incfilename = targetdir.join('common_header.h') @@ -1014,6 +986,12 @@ gen_startupcode(f, database) f.close() + if 'INSTRUMENT' in defines: + fi = incfilename.open('a') + n = database.instrument_ncounter + print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n + fi.close() + eci = add_extra_files(eci) eci = eci.convert_sources_to_files(being_main=True) files, eci = eci.get_module_files() diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py --- a/pypy/translator/c/test/test_genc.py +++ b/pypy/translator/c/test/test_genc.py @@ -4,7 +4,6 @@ from pypy.translator.translator import TranslationContext from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c import genc -from pypy.translator.c.genc import gen_source from pypy.translator.c.gc import NoneGcPolicy from pypy.objspace.flow.model import Constant, Variable, SpaceOperation from pypy.objspace.flow.model import Block, Link, FunctionGraph @@ -13,6 +12,7 @@ from pypy.translator.backendopt.all import backend_optimizations from pypy.translator.interactive import Translation from pypy.rlib.entrypoint import entrypoint +from pypy.tool.nullpath import NullPyPathLocal def compile(fn, argtypes, view=False, gcpolicy="ref", backendopt=True, annotatorpolicy=None): @@ -63,6 +63,22 @@ py.test.raises(Exception, f1, "world") # check that it's really typed + +def test_dont_write_source_files(): + def f(x): + return x*2 + t = TranslationContext() + t.buildannotator().build_types(f, [int]) + t.buildrtyper().specialize() + + t.config.translation.countmallocs = True + t.config.translation.dont_write_c_files = True + builder = genc.CExtModuleBuilder(t, f, config=t.config) + builder.generate_source() + assert isinstance(builder.targetdir, NullPyPathLocal) + assert builder.targetdir.listdir() == [] + + def test_simple_lambda(): f = lambda x: x*2 t = TranslationContext() diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -55,6 +55,13 @@ data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + # Verify that the generated C files have sane names: + gen_c_files = [str(f) for f in cbuilder.extrafiles] + for expfile in ('rlib_rposix.c', + 'rpython_lltypesystem_rstr.c', + 'translator_c_test_test_standalone.c'): + assert cbuilder.targetdir.join(expfile) in gen_c_files + def test_print(self): def entry_point(argv): print "hello simpler world" diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs --- a/pypy/translator/cli/src/pypylib.cs +++ b/pypy/translator/cli/src/pypylib.cs @@ -615,11 +615,29 @@ return s1.StartsWith(s2); } + public static bool ll_startswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[0] == c; + } + public static bool ll_endswith(string s1, string s2) { return s1.EndsWith(s2); } + public static bool ll_endswith_char(string s, char c) + { + if (s.Length == 0) + { + return false; + } + return s[s.Length - 1] == c; + } + public static int ll_find(string s1, string s2, int start, int stop) { if (stop > s1.Length) diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -791,6 +791,20 @@ return str.substring(start,start+cnt); } + public static boolean ll_startswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(0) == c; + } + + public static boolean ll_endswith_char(String str, char c) { + if (str.length() == 0) { + return false; + } + return str.charAt(str.length() - 1) == c; + } + // ---------------------------------------------------------------------- // StringBuffer diff --git a/pytest.py b/pytest.py --- a/pytest.py +++ b/pytest.py @@ -9,6 +9,8 @@ from _pytest import __version__ if __name__ == '__main__': # if run as a script or by 'python -m pytest' - raise SystemExit(main()) + #XXX: sync to upstream later + import pytest_cov + raise SystemExit(main(plugins=[pytest_cov])) else: _preloadplugins() # to populate pytest.* namespace so help(pytest) works diff --git a/pytest_cov.py b/pytest_cov.py new file mode 100644 --- /dev/null +++ b/pytest_cov.py @@ -0,0 +1,353 @@ +"""produce code coverage reports using the 'coverage' package, including support for distributed testing. + +This plugin produces coverage reports. It supports centralised testing and distributed testing in +both load and each modes. It also supports coverage of subprocesses. + +All features offered by the coverage package should be available, either through pytest-cov or +through coverage's config file. + + +Installation +------------ + +The `pytest-cov`_ package may be installed with pip or easy_install:: + + pip install pytest-cov + easy_install pytest-cov + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov/ + + +Uninstallation +-------------- + +Uninstalling packages is supported by pip:: + + pip uninstall pytest-cov + +However easy_install does not provide an uninstall facility. + +.. IMPORTANT:: + + Ensure that you manually delete the init_cov_core.pth file in your site-packages directory. + + This file starts coverage collection of subprocesses if appropriate during site initialisation + at python startup. + + +Usage +----- + +Centralised Testing +~~~~~~~~~~~~~~~~~~~ + +Centralised testing will report on the combined coverage of the main process and all of it's +subprocesses. + +Running centralised testing:: + + py.test --cov myproj tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Load +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to load will report on the combined coverage of all slaves. +The slaves may be spread out over any number of hosts and each slave may be located anywhere on the +file system. Each slave will have it's subprocesses measured. + +Running distributed testing with dist mode set to load:: + + py.test --cov myproj -n 2 tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Again but spread over different hosts and different directories:: + + py.test --cov myproj --dist load + --tx ssh=memedough at host1//chdir=testenv1 + --tx ssh=memedough at host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Each +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to each will report on the combined coverage of all slaves. +Since each slave is running all tests this allows generating a combined coverage report for multiple +environments. + +Running distributed testing with dist mode set to each:: + + py.test --cov myproj --dist each + --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python + --tx ssh=memedough at host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + ---------------------------------------- coverage ---------------------------------------- + platform linux2, python 2.6.5-final-0 + platform linux2, python 2.7.0-final-0 + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Reporting +--------- + +It is possible to generate any combination of the reports for a single test run. + +The available reports are terminal (with or without missing line numbers shown), HTML, XML and +annotated source code. + +The terminal report without line numbers (default):: + + py.test --cov-report term --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +The terminal report with line numbers:: + + py.test --cov-report term-missing --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover Missing + -------------------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% 24-26, 99, 149, 233-236, 297-298, 369-370 + myproj/feature4286 94 7 92% 183-188, 197 + -------------------------------------------------- + TOTAL 353 20 94% + + +The remaining three reports output to files without showing anything on the terminal (useful for +when the output is going to a continuous integration server):: + + py.test --cov-report html + --cov-report xml + --cov-report annotate + --cov myproj tests/ + + +Coverage Data File +------------------ + +The data file is erased at the beginning of testing to ensure clean data for each test run. + +The data file is left at the end of testing so that it is possible to use normal coverage tools to +examine it. + + +Coverage Config File +-------------------- + +This plugin provides a clean minimal set of command line options that are added to pytest. For +further control of coverage use a coverage config file. + +For example if tests are contained within the directory tree being measured the tests may be +excluded if desired by using a .coveragerc file with the omit option set:: + + py.test --cov-config .coveragerc + --cov myproj + myproj/tests/ + +Where the .coveragerc file contains file globs:: + + [run] + omit = tests/* + +For full details refer to the `coverage config file`_ documentation. + +.. _`coverage config file`: http://nedbatchelder.com/code/coverage/config.html + +Note that this plugin controls some options and setting the option in the config file will have no +effect. These include specifying source to be measured (source option) and all data file handling +(data_file and parallel options). + + +Limitations +----------- + +For distributed testing the slaves must have the pytest-cov package installed. This is needed since +the plugin must be registered through setuptools / distribute for pytest to start the plugin on the +slave. + +For subprocess measurement environment variables must make it from the main process to the +subprocess. The python used by the subprocess must have pytest-cov installed. The subprocess must +do normal site initialisation so that the environment variables can be detected and coverage +started. + + +Acknowledgements +---------------- + +Whilst this plugin has been built fresh from the ground up it has been influenced by the work done +on pytest-coverage (Ross Lawley, James Mills, Holger Krekel) and nose-cover (Jason Pellerin) which are +other coverage plugins. + +Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs. + +Holger Krekel for pytest with its distributed testing support. + +Jason Pellerin for nose. + +Michael Foord for unittest2. + +No doubt others have contributed to these tools as well. +""" + + +def pytest_addoption(parser): + """Add options to control coverage.""" + + group = parser.getgroup('coverage reporting with distributed testing support') + group.addoption('--cov', action='append', default=[], metavar='path', + dest='cov_source', + help='measure coverage for filesystem path (multi-allowed)') + group.addoption('--cov-report', action='append', default=[], metavar='type', + choices=['term', 'term-missing', 'annotate', 'html', 'xml'], + dest='cov_report', + help='type of report to generate: term, term-missing, annotate, html, xml (multi-allowed)') + group.addoption('--cov-config', action='store', default='.coveragerc', metavar='path', + dest='cov_config', + help='config file for coverage, default: .coveragerc') + + +def pytest_configure(config): + """Activate coverage plugin if appropriate.""" + + if config.getvalue('cov_source'): + config.pluginmanager.register(CovPlugin(), '_cov') + + +class CovPlugin(object): + """Use coverage package to produce code coverage reports. + + Delegates all work to a particular implementation based on whether + this test process is centralised, a distributed master or a + distributed slave. + """ + + def __init__(self): + """Creates a coverage pytest plugin. + + We read the rc file that coverage uses to get the data file + name. This is needed since we give coverage through it's API + the data file name. + """ + + # Our implementation is unknown at this time. + self.cov_controller = None + + def pytest_sessionstart(self, session): + """At session start determine our implementation and delegate to it.""" + + import cov_core + + cov_source = session.config.getvalue('cov_source') + cov_report = session.config.getvalue('cov_report') or ['term'] + cov_config = session.config.getvalue('cov_config') + + session_name = session.__class__.__name__ + is_master = (session.config.pluginmanager.hasplugin('dsession') or + session_name == 'DSession') + is_slave = (hasattr(session.config, 'slaveinput') or + session_name == 'SlaveSession') + nodeid = None + + if is_master: + controller_cls = cov_core.DistMaster + elif is_slave: + controller_cls = cov_core.DistSlave + nodeid = session.config.slaveinput.get('slaveid', getattr(session, 'nodeid')) + else: + controller_cls = cov_core.Central + + self.cov_controller = controller_cls(cov_source, + cov_report, + cov_config, + session.config, + nodeid) + + self.cov_controller.start() + + def pytest_configure_node(self, node): + """Delegate to our implementation.""" + + self.cov_controller.configure_node(node) + pytest_configure_node.optionalhook = True + + def pytest_testnodedown(self, node, error): + """Delegate to our implementation.""" + + self.cov_controller.testnodedown(node, error) + pytest_testnodedown.optionalhook = True + + def pytest_sessionfinish(self, session, exitstatus): + """Delegate to our implementation.""" + + self.cov_controller.finish() + + def pytest_terminal_summary(self, terminalreporter): + """Delegate to our implementation.""" + + self.cov_controller.summary(terminalreporter._tw) + + +def pytest_funcarg__cov(request): + """A pytest funcarg that provides access to the underlying coverage object.""" + + # Check with hasplugin to avoid getplugin exception in older pytest. + if request.config.pluginmanager.hasplugin('_cov'): + plugin = request.config.pluginmanager.getplugin('_cov') + if plugin.cov_controller: + return plugin.cov_controller.cov + return None From noreply at buildbot.pypy.org Sat Jul 23 19:50:35 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 19:50:35 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: bh_getinteriorfield_gc_r Message-ID: <20110723175035.78A87829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45904:d6053cf6b6d9 Date: 2011-07-23 19:35 +0200 http://bitbucket.org/pypy/pypy/changeset/d6053cf6b6d9/ Log: bh_getinteriorfield_gc_r diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -328,6 +328,18 @@ # --- end of GC unsafe code --- return pval + def bh_getinteriorfield_gc_r(self, gcref, itemindex, descr): + arraydescr = descr.arraydescr + ofs, size, _ = self.unpack_arraydescr_size(arraydescr) + ofs += descr.fielddescr.offset + # --- start of GC unsafe code (no GC operation!) --- + items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs + + size * itemindex) + items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items) + pval = self._cast_int_to_gcref(items[0]) + # --- end of GC unsafe code --- + return pval + @specialize.argtype(2) def bh_getarrayitem_gc_f(self, arraydescr, gcref, itemindex): ofs = self.unpack_arraydescr(arraydescr) From noreply at buildbot.pypy.org Sat Jul 23 19:50:36 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 19:50:36 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: fix bh methods; Message-ID: <20110723175036.A7C42829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45905:234b2589b175 Date: 2011-07-23 19:41 +0200 http://bitbucket.org/pypy/pypy/changeset/234b2589b175/ Log: fix bh methods; diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -300,25 +300,6 @@ else: raise NotImplementedError("size = %d" % size) - def bh_getinteriorfield_gc_i(self, gcref, itemindex, descr): - arraydescr = descr.arraydescr - ofs, size, _ = self.unpack_arraydescr_size(arraydescr) - ofs += descr.fielddescr.offset - fieldsize = descr.fielddescr.get_field_size(self.translate_support_code) - fullofs = itemindex * size + ofs - # --- start of GC unsafe code (no GC operation!) --- - items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), fullofs) - for STYPE, UTYPE, itemsize in unroll_basic_sizes: - if fieldsize == itemsize: - # XXX signedness - item = rffi.cast(rffi.CArrayPtr(STYPE), items) - val = item[0] - val = rffi.cast(lltype.Signed, val) - # --- end of GC unsafe code --- - return val - else: - raise NotImplementedError("size = %d" % fieldsize) - def bh_getarrayitem_gc_r(self, arraydescr, gcref, itemindex): ofs = self.unpack_arraydescr(arraydescr) # --- start of GC unsafe code (no GC operation!) --- @@ -328,18 +309,6 @@ # --- end of GC unsafe code --- return pval - def bh_getinteriorfield_gc_r(self, gcref, itemindex, descr): - arraydescr = descr.arraydescr - ofs, size, _ = self.unpack_arraydescr_size(arraydescr) - ofs += descr.fielddescr.offset - # --- start of GC unsafe code (no GC operation!) --- - items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs + - size * itemindex) - items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items) - pval = self._cast_int_to_gcref(items[0]) - # --- end of GC unsafe code --- - return pval - @specialize.argtype(2) def bh_getarrayitem_gc_f(self, arraydescr, gcref, itemindex): ofs = self.unpack_arraydescr(arraydescr) @@ -388,6 +357,49 @@ bh_getarrayitem_raw_i = bh_getarrayitem_gc_i bh_getarrayitem_raw_f = bh_getarrayitem_gc_f + def bh_getinteriorfield_gc_i(self, gcref, itemindex, descr): + arraydescr = descr.arraydescr + ofs, size, _ = self.unpack_arraydescr_size(arraydescr) + ofs += descr.fielddescr.offset + fieldsize = descr.fielddescr.get_field_size(self.translate_support_code) + fullofs = itemindex * size + ofs + # --- start of GC unsafe code (no GC operation!) --- + items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), fullofs) + for STYPE, UTYPE, itemsize in unroll_basic_sizes: + if fieldsize == itemsize: + # XXX signedness + item = rffi.cast(rffi.CArrayPtr(STYPE), items) + val = item[0] + val = rffi.cast(lltype.Signed, val) + # --- end of GC unsafe code --- + return val + else: + raise NotImplementedError("size = %d" % fieldsize) + + def bh_getinteriorfield_gc_r(self, gcref, itemindex, descr): + arraydescr = descr.arraydescr + ofs, size, _ = self.unpack_arraydescr_size(arraydescr) + ofs += descr.fielddescr.offset + # --- start of GC unsafe code (no GC operation!) --- + items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs + + size * itemindex) + items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items) + pval = self._cast_int_to_gcref(items[0]) + # --- end of GC unsafe code --- + return pval + + def bh_getinteriorfield_gc_f(self, gcref, itemindex, descr): + arraydescr = descr.arraydescr + ofs, size, _ = self.unpack_arraydescr_size(arraydescr) + ofs += descr.fielddescr.offset + # --- start of GC unsafe code (no GC operation!) --- + items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs + + size * itemindex) + items = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), items) + fval = items[0] + # --- end of GC unsafe code --- + return fval + def bh_setinteriorfield_gc_i(self, gcref, itemindex, descr, value): arraydescr = descr.arraydescr ofs, size, _ = self.unpack_arraydescr_size(arraydescr) @@ -405,6 +417,30 @@ else: raise NotImplementedError("size = %d" % fieldsize) + def bh_setinteriorfield_gc_r(self, gcref, itemindex, descr, newvalue): + arraydescr = descr.arraydescr + ofs, size, _ = self.unpack_arraydescr_size(arraydescr) + ofs += descr.fielddescr.offset + self.gc_ll_descr.do_write_barrier(gcref, newvalue) + # --- start of GC unsafe code (no GC operation!) --- + items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), + ofs + size * itemindex) + items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items) + items[0] = self.cast_gcref_to_int(newvalue) + # --- end of GC unsafe code --- + + def bh_setinteriorfield_gc_f(self, gcref, itemindex, descr, newvalue): + arraydescr = descr.arraydescr + ofs, size, _ = self.unpack_arraydescr_size(arraydescr) + ofs += descr.fielddescr.offset + self.gc_ll_descr.do_write_barrier(gcref, newvalue) + # --- start of GC unsafe code (no GC operation!) --- + items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), + ofs + size * itemindex) + items = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), items) + items[0] = newvalue + # --- end of GC unsafe code --- + def bh_strlen(self, string): s = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), string) return len(s.chars) From noreply at buildbot.pypy.org Sat Jul 23 19:50:37 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 19:50:37 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: a test and a fix Message-ID: <20110723175037.DD5A3829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45906:464e597e2cfd Date: 2011-07-23 19:50 +0200 http://bitbucket.org/pypy/pypy/changeset/464e597e2cfd/ Log: a test and a fix diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -1237,6 +1237,8 @@ self.intval = intmask(void_p.value) def __eq__(self, other): + if not other: + return self.intval == 0 if isinstance(other, _llgcopaque): return self.intval == other.intval storage = object() diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -8,6 +8,7 @@ from pypy.rpython.lltypesystem.ll2ctypes import uninitialized2ctypes from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED, force_cast from pypy.rpython.lltypesystem.ll2ctypes import cast_adr_to_int, get_ctypes_type +from pypy.rpython.lltypesystem.ll2ctypes import _llgcopaque from pypy.rpython.annlowlevel import llhelper from pypy.rlib import rposix from pypy.translator.tool.cbuild import ExternalCompilationInfo @@ -1373,3 +1374,7 @@ f = rffi.llexternal('f', [rffi.INT, rffi.INT], rffi.INT, compilation_info=eci) assert f(3, 4) == 7 + + def test_llgcopaque_eq(self): + assert _llgcopaque(1) != None + assert _llgcopaque(0) == None From noreply at buildbot.pypy.org Sat Jul 23 19:56:29 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 23 Jul 2011 19:56:29 +0200 (CEST) Subject: [pypy-commit] pypy default: Change a bunch of sys.platform == 'linux2' to be sys.platform.startswith('linux') to be ready for linux3. Message-ID: <20110723175629.6FA6A829BA@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45907:c1f79d724bc0 Date: 2011-07-23 10:54 -0700 http://bitbucket.org/pypy/pypy/changeset/c1f79d724bc0/ Log: Change a bunch of sys.platform == 'linux2' to be sys.platform.startswith('linux') to be ready for linux3. diff --git a/pypy/config/support.py b/pypy/config/support.py --- a/pypy/config/support.py +++ b/pypy/config/support.py @@ -9,7 +9,7 @@ return 1 # don't override MAKEFLAGS. This will call 'make' without any '-j' option if sys.platform == 'darwin': return darwin_get_cpu_count() - elif sys.platform != 'linux2': + elif not sys.platform.startswith('linux'): return 1 # implement me try: if isinstance(filename_or_file, str): diff --git a/pypy/config/test/test_support.py b/pypy/config/test/test_support.py --- a/pypy/config/test/test_support.py +++ b/pypy/config/test/test_support.py @@ -40,7 +40,7 @@ return self._value def test_cpuinfo_linux(): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("linux only") saved = os.environ try: diff --git a/pypy/jit/backend/llvm/llvm_rffi.py b/pypy/jit/backend/llvm/llvm_rffi.py --- a/pypy/jit/backend/llvm/llvm_rffi.py +++ b/pypy/jit/backend/llvm/llvm_rffi.py @@ -3,7 +3,7 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo, log -if sys.platform != 'linux2': +if not sys.platform.startswith('linux'): py.test.skip("Linux only for now") # ____________________________________________________________ diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -852,7 +852,7 @@ # Sometimes the library is wrapped into another DLL, ensure that # the correct bootstrap code is installed kwds["link_extra"] = ["msvcrt.lib"] - elif sys.platform == 'linux2': + elif sys.platform.startswith('linux'): compile_extra.append("-Werror=implicit-function-declaration") export_symbols_eci.append('pypyAPI') else: diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -188,7 +188,7 @@ kwds["compile_extra"] = ["/we4013"] else: kwds["link_files"] = [str(api_library + '.so')] - if sys.platform == 'linux2': + if sys.platform.startswith('linux'): kwds["compile_extra"]=["-Werror=implicit-function-declaration"] return compile_module(self.space, name, **kwds) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -85,7 +85,7 @@ return SEARCH_ERROR, None, None -if sys.platform == 'linux2' or 'freebsd' in sys.platform: +if sys.platform.startswith('linux') or 'freebsd' in sys.platform: def case_ok(filename): return True else: diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -125,13 +125,13 @@ assert st.st_size == 14 assert st.st_nlink == 1 - #if sys.platform.startswith('linux2'): + #if sys.platform.startswith('linux'): # # expects non-integer timestamps - it's unlikely that they are # # all three integers # assert ((st.st_atime, st.st_mtime, st.st_ctime) != # (st[7], st[8], st[9])) # assert st.st_blksize * st.st_blocks >= st.st_size - if sys.platform.startswith('linux2'): + if sys.platform.startswith('linux'): assert hasattr(st, 'st_rdev') def test_stat_float_times(self): diff --git a/pypy/rlib/test/test_rlocale.py b/pypy/rlib/test/test_rlocale.py --- a/pypy/rlib/test/test_rlocale.py +++ b/pypy/rlib/test/test_rlocale.py @@ -37,7 +37,7 @@ assert isinstance(grouping, str) def test_libintl(): - if sys.platform not in ("linux2", "darwin"): + if sys.platform != "darwin" or not sys.platform.startswith("linux"): py.test.skip("there is (maybe) no libintl here") _gettext = external('gettext', [rffi.CCHARP], rffi.CCHARP) res = _gettext("1234") diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -1331,7 +1331,7 @@ def _where_is_errno(): return standard_c_lib._errno() - elif sys.platform in ('linux2', 'freebsd6'): + elif sys.platform.startswith('linux') or sys.platform == 'freebsd6': standard_c_lib.__errno_location.restype = ctypes.POINTER(ctypes.c_int) def _where_is_errno(): return standard_c_lib.__errno_location() diff --git a/pypy/rpython/lltypesystem/llarena.py b/pypy/rpython/lltypesystem/llarena.py --- a/pypy/rpython/lltypesystem/llarena.py +++ b/pypy/rpython/lltypesystem/llarena.py @@ -404,7 +404,7 @@ from pypy.rpython.extfunc import register_external from pypy.rlib.objectmodel import CDefinedIntSymbolic -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): # This only works with linux's madvise(), which is really not a memory # usage hint but a real command. It guarantees that after MADV_DONTNEED # the pages are cleared again. diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -1348,7 +1348,7 @@ def test_prefix(self): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("Not supported") from pypy.translator.platform import platform diff --git a/pypy/rpython/memory/gc/env.py b/pypy/rpython/memory/gc/env.py --- a/pypy/rpython/memory/gc/env.py +++ b/pypy/rpython/memory/gc/env.py @@ -55,7 +55,7 @@ # will be huge on 64-bit systems. if sys.maxint == 2147483647: # 32-bit - if sys.platform == 'linux2': + if sys.platform.startswith('linux'): addressable_size = float(2**32) # 4GB elif sys.platform == 'win32': addressable_size = float(2**31) # 2GB @@ -65,7 +65,7 @@ addressable_size = float(2**63) # 64-bit -def get_total_memory_linux2(filename): +def get_total_memory_linux(filename): debug_start("gc-hardware") result = -1.0 try: @@ -93,7 +93,7 @@ result = addressable_size debug_stop("gc-hardware") return result - +get_total_memory_linux2 = get_total_memory_linux3 = get_total_memory_linux def get_total_memory_darwin(result): debug_start("gc-hardware") @@ -108,7 +108,7 @@ return result -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): def get_total_memory(): return get_total_memory_linux2('/proc/meminfo') diff --git a/pypy/rpython/module/ll_os_stat.py b/pypy/rpython/module/ll_os_stat.py --- a/pypy/rpython/module/ll_os_stat.py +++ b/pypy/rpython/module/ll_os_stat.py @@ -21,7 +21,7 @@ # sub-second timestamps. # - TIMESPEC is defined when the "struct stat" contains st_atim field. -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): TIMESPEC = platform.Struct('struct timespec', [('tv_sec', rffi.TIME_T), ('tv_nsec', rffi.LONG)]) diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -226,7 +226,7 @@ eci = eci.merge(configure_boehm()) pre_include_bits = [] - if sys.platform == "linux2": + if sys.platform.startswith('linux'): pre_include_bits += ["#define _REENTRANT 1", "#define GC_LINUX_THREADS 1"] if sys.platform != "win32": diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py --- a/pypy/translator/platform/__init__.py +++ b/pypy/translator/platform/__init__.py @@ -230,7 +230,7 @@ return True -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): from pypy.translator.platform.linux import Linux, Linux64 import platform if platform.architecture()[0] == '32bit': diff --git a/pypy/translator/sandbox/sandlib.py b/pypy/translator/sandbox/sandlib.py --- a/pypy/translator/sandbox/sandlib.py +++ b/pypy/translator/sandbox/sandlib.py @@ -209,7 +209,7 @@ def handle_until_return(self): child_stdin = self.popen.stdin child_stdout = self.popen.stdout - if self.os_level_sandboxing and sys.platform.startswith('linux2'): + if self.os_level_sandboxing and sys.platform.startswith('linux'): # rationale: we wait until the child process started completely, # letting the C library do any system calls it wants for # initialization. When the RPython code starts up, it quickly diff --git a/pypy/translator/sandbox/test/test_sandbox.py b/pypy/translator/sandbox/test/test_sandbox.py --- a/pypy/translator/sandbox/test/test_sandbox.py +++ b/pypy/translator/sandbox/test/test_sandbox.py @@ -145,7 +145,7 @@ g = pipe.stdin f = pipe.stdout expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GENERATIONGC_NURSERY",), None) - if sys.platform == 'linux2': # on Mac, uses another (sandboxsafe) approach + if sys.platform.startswith('linux'): # on Mac, uses another (sandboxsafe) approach expect(f, g, "ll_os.ll_os_open", ("/proc/cpuinfo", 0, 420), OSError(5232, "xyz")) expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GC_DEBUG",), None) From noreply at buildbot.pypy.org Sat Jul 23 19:56:30 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 23 Jul 2011 19:56:30 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20110723175630.A5415829BA@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45908:1176c7a15532 Date: 2011-07-23 10:56 -0700 http://bitbucket.org/pypy/pypy/changeset/1176c7a15532/ Log: merged upstream diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -23,7 +23,7 @@ self.hasdict |= __base.hasdict self.weakrefable |= __base.weakrefable self.rawdict = {} - self.acceptable_as_base_class = True + self.acceptable_as_base_class = '__new__' in rawdict self.applevel_subclasses_base = None # xxx used by faking self.fakedcpytype = None diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -10,6 +10,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import fatalerror +from pypy.rlib.rstackovf import StackOverflow from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function @@ -408,6 +409,15 @@ jd.warmstate = state def crash_in_jit(e): + try: + raise e + except JitException: + raise # go through + except MemoryError: + raise # go through + except StackOverflow: + raise # go through + except Exception, e: if not we_are_translated(): print "~~~ Crash in JIT!" print '~~~ %s: %s' % (e.__class__, e) @@ -421,8 +431,6 @@ def maybe_enter_jit(*args): try: maybe_compile_and_run(state.increment_threshold, *args) - except JitException: - raise # go through except Exception, e: crash_in_jit(e) maybe_enter_jit._always_inline_ = True From noreply at buildbot.pypy.org Sat Jul 23 20:21:16 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 20:21:16 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: tests and fixes for void args Message-ID: <20110723182116.6A461829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45909:725eba4ec8b0 Date: 2011-07-23 20:20 +0200 http://bitbucket.org/pypy/pypy/changeset/725eba4ec8b0/ Log: tests and fixes for void args diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -695,7 +695,6 @@ return SpaceOperation(opname, [op.args[0]], op.result) def rewrite_op_getinteriorfield(self, op): - # only supports strings and unicodes assert len(op.args) == 3 if isinstance(op.args[1], Constant) and op.args[1].value == 'chars': optype = op.args[0].concretetype @@ -707,6 +706,8 @@ return SpaceOperation(opname, [op.args[0], op.args[2]], op.result) else: v_inst, v_index, c_field = op.args + if op.result.concretetype is lltype.Void: + return # only GcArray of Struct supported assert isinstance(v_inst.concretetype.TO, lltype.GcArray) STRUCT = v_inst.concretetype.TO.OF @@ -719,7 +720,6 @@ op.result) def rewrite_op_setinteriorfield(self, op): - # only supports strings and unicodes assert len(op.args) == 4 if isinstance(op.args[1], Constant) and op.args[1].value == 'chars': optype = op.args[0].concretetype @@ -732,6 +732,8 @@ op.result) else: v_inst, v_index, c_field, v_value = op.args + if v_value.concretetype is lltype.Void: + return # only GcArray of Struct supported assert isinstance(v_inst.concretetype.TO, lltype.GcArray) STRUCT = v_inst.concretetype.TO.OF diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -658,6 +658,10 @@ op1 = Transformer(FakeCPU()).rewrite_operation(op) assert op1.opname == 'getinteriorfield_gc_i' assert op1.args == [v, i, ('interiorfielddescr', DICT, 'v')] + op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)], + Constant(None, lltype.Void)) + op1 = Transformer(FakeCPU()).rewrite_operation(op) + assert not op1 def test_str_setinteriorfield(): v = varoftype(lltype.Ptr(rstr.STR)) @@ -697,6 +701,10 @@ op1 = Transformer(FakeCPU()).rewrite_operation(op) assert op1.opname == 'setinteriorfield_gc_i' assert op1.args == [v, i, i, ('interiorfielddescr', DICT, 'v')] + op = SpaceOperation('setinteriorfield', [v, i, Constant('v', lltype.Void), + v_void], v_void) + op1 = Transformer(FakeCPU()).rewrite_operation(op) + assert not op1 def test_promote_1(): v1 = varoftype(lltype.Signed) diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -6,7 +6,6 @@ class DictTests: def test_dict_set_none(self): - py.test.skip("annoying") def fn(n): d = {} d[0] = None From noreply at buildbot.pypy.org Sat Jul 23 20:40:53 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 23 Jul 2011 20:40:53 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: (fijal, arigo) a test and a fix Message-ID: <20110723184053.548B7829BA@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45910:f46f701cd3b8 Date: 2011-07-23 20:40 +0200 http://bitbucket.org/pypy/pypy/changeset/f46f701cd3b8/ Log: (fijal, arigo) a test and a fix diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -707,7 +707,7 @@ else: v_inst, v_index, c_field = op.args if op.result.concretetype is lltype.Void: - return + return Constant(None, lltype.Void) # only GcArray of Struct supported assert isinstance(v_inst.concretetype.TO, lltype.GcArray) STRUCT = v_inst.concretetype.TO.OF diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -661,7 +661,7 @@ op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)], Constant(None, lltype.Void)) op1 = Transformer(FakeCPU()).rewrite_operation(op) - assert not op1 + assert op1 == Constant(None, lltype.Void) def test_str_setinteriorfield(): v = varoftype(lltype.Ptr(rstr.STR)) From noreply at buildbot.pypy.org Sat Jul 23 20:43:49 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 20:43:49 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: A different fix. Message-ID: <20110723184349.C6CD0829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: inline-dict-ops Changeset: r45911:d6719614d202 Date: 2011-07-23 20:43 +0200 http://bitbucket.org/pypy/pypy/changeset/d6719614d202/ Log: A different fix. diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -47,9 +47,11 @@ newoperations = [] # def do_rename(var, var_or_const): + if var.concretetype is lltype.Void: + renamings[var] = Constant(None, lltype.Void) + return renamings[var] = var_or_const - if (isinstance(var_or_const, Constant) - and var.concretetype != lltype.Void): + if isinstance(var_or_const, Constant): value = var_or_const.value value = lltype._cast_whatever(var.concretetype, value) renamings_constants[var] = Constant(value, var.concretetype) From noreply at buildbot.pypy.org Sat Jul 23 20:43:51 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 20:43:51 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: merge heads Message-ID: <20110723184351.08DCF829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: inline-dict-ops Changeset: r45912:d52c8358f541 Date: 2011-07-23 20:43 +0200 http://bitbucket.org/pypy/pypy/changeset/d52c8358f541/ Log: merge heads diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -709,7 +709,7 @@ else: v_inst, v_index, c_field = op.args if op.result.concretetype is lltype.Void: - return + return Constant(None, lltype.Void) # only GcArray of Struct supported assert isinstance(v_inst.concretetype.TO, lltype.GcArray) STRUCT = v_inst.concretetype.TO.OF diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -661,7 +661,7 @@ op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)], Constant(None, lltype.Void)) op1 = Transformer(FakeCPU()).rewrite_operation(op) - assert not op1 + assert op1 == Constant(None, lltype.Void) def test_str_setinteriorfield(): v = varoftype(lltype.Ptr(rstr.STR)) From noreply at buildbot.pypy.org Sat Jul 23 20:46:04 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 20:46:04 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: Fix broken test, sorry. Message-ID: <20110723184604.5FB17829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: inline-dict-ops Changeset: r45913:e2b65a520ac8 Date: 2011-07-23 20:46 +0200 http://bitbucket.org/pypy/pypy/changeset/e2b65a520ac8/ Log: Fix broken test, sorry. diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -510,7 +510,7 @@ def test_rename_on_links(): v1 = Variable() - v2 = Variable() + v2 = Variable(); v2.concretetype = llmemory.Address v3 = Variable() block = Block([v1]) block.operations = [SpaceOperation('cast_pointer', [v1], v2)] From noreply at buildbot.pypy.org Sat Jul 23 20:47:47 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 20:47:47 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: Re-simplify this code. Message-ID: <20110723184747.895BF829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: inline-dict-ops Changeset: r45914:e6c306ce9172 Date: 2011-07-23 20:47 +0200 http://bitbucket.org/pypy/pypy/changeset/e6c306ce9172/ Log: Re-simplify this code. diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -709,7 +709,7 @@ else: v_inst, v_index, c_field = op.args if op.result.concretetype is lltype.Void: - return Constant(None, lltype.Void) + return # only GcArray of Struct supported assert isinstance(v_inst.concretetype.TO, lltype.GcArray) STRUCT = v_inst.concretetype.TO.OF diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -661,7 +661,7 @@ op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)], Constant(None, lltype.Void)) op1 = Transformer(FakeCPU()).rewrite_operation(op) - assert op1 == Constant(None, lltype.Void) + assert op1 is None def test_str_setinteriorfield(): v = varoftype(lltype.Ptr(rstr.STR)) From noreply at buildbot.pypy.org Sat Jul 23 22:32:51 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 22:32:51 +0200 (CEST) Subject: [pypy-commit] pypy default: Backout 4543677d758a and abc993e8d795, removing PYPY_GC_LOSTCARD Message-ID: <20110723203251.45A00829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45915:8fb98ebfdeb3 Date: 2011-07-23 16:19 +0200 http://bitbucket.org/pypy/pypy/changeset/8fb98ebfdeb3/ Log: Backout 4543677d758a and abc993e8d795, removing PYPY_GC_LOSTCARD again. Will try another approach: inlining the write barrier logic for GCFLAG_HAS_CARDS in the jit backend code. diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,13 +34,6 @@ the GC in very small programs. Defaults to 8 times the nursery. - PYPY_GC_LOSTCARD If between two minor collections we see more than - 'PYPY_GC_LOSTCARD * length' writes to the same array, - then give up card marking and use the fast write - barrier instead. Defaults to 0.3333 for now. - Avoid values lower than 0.125: it is the growth - factor of list.append(). - PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -205,9 +198,6 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, - # See PYPY_GC_LOSTCARD. - "lost_card": 1.0 / 3.0, - # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -224,7 +214,6 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, - lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -246,7 +235,6 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 - self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -367,10 +355,6 @@ else: self.max_delta = 0.125 * env.get_total_memory() # - lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') - if lost_card > 0.0: - self.lost_card = lost_card - # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -665,7 +649,7 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + 1 + extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS # note that if 'can_make_young', then card marking will only @@ -691,15 +675,11 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # followed by a Signed (the loop is empty in C). - if cardheadersize > 0: + # (the loop is empty in C). i = 0 - while i < cardheadersize - WORD: - llarena.arena_reserve(arena + i, - llmemory.sizeof(lltype.Char)) + while i < cardheadersize: + llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) i += 1 - llarena.arena_reserve(arena + i, - llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -923,11 +903,14 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # + size_gc_header = self.gcheaderbuilder.size_gc_header + p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: + p -= 1 + ll_assert(p.char[0] == '\x00', + "the card marker bits are not cleared") i -= 1 - ll_assert(self.get_card(obj, i).char[0] == '\x00', - "the card marker bits are not cleared") # ---------- # Write barrier @@ -1025,8 +1008,6 @@ self.prebuilt_root_objects.append(addr_array) return # - self.set_cards_flag(addr_array) - # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1044,6 +1025,10 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1072,8 +1057,6 @@ if not self.appears_to_be_young(newvalue): return # - self.set_cards_flag(addr_array) - # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1086,6 +1069,10 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1103,36 +1090,11 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card_counter_addr(self, obj): + def get_card(self, obj, byteindex): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) - WORD + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) - def get_card(self, obj, byteindex): - return self.get_card_counter_addr(obj) + (~byteindex) - - def set_cards_flag(self, obj): - hdr = self.header(obj) - if hdr.tid & GCFLAG_CARDS_SET == 0: - # - # first time we set a card bit in this object - self.header(obj).tid |= GCFLAG_CARDS_SET - self.objects_with_cards_set.append(obj) - # - # initialize the counter with the array length and self.lost_card - typeid = self.get_type_id(obj) - offset_to_length = self.varsize_offset_to_length(typeid) - length = (obj + offset_to_length).signed[0] - counter = int(length * self.lost_card) - self.get_card_counter_addr(obj).signed[0] = counter - else: - # decrement the counter and if zero is reached, give up on - # card marking (up to the next collection). - addr = self.get_card_counter_addr(obj) - addr.signed[0] -= 1 - if addr.signed[0] < 0: - self.objects_pointing_to_young.append(obj) - hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1205,7 +1167,10 @@ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - self.set_cards_flag(dest_addr) + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1299,7 +1264,6 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) - p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1638,7 +1602,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + 1 + extra_words = self.card_marking_words_for_length(length) arena -= extra_words * WORD allocsize += extra_words * WORD # From noreply at buildbot.pypy.org Sat Jul 23 22:32:52 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 22:32:52 +0200 (CEST) Subject: [pypy-commit] pypy default: Oooops. Found and fixed a subtle bug: young arrays that use card Message-ID: <20110723203252.7AB95829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45916:82e5051d55c3 Date: 2011-07-23 22:31 +0200 http://bitbucket.org/pypy/pypy/changeset/82e5051d55c3/ Log: Oooops. Found and fixed a subtle bug: young arrays that use card marking but die young would still be scanned for objects. That's wrooong as it means that a lot more objects stay alive. diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -263,8 +263,8 @@ # that it is possible for an object to be listed both in here # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - # Note also that young array objects may be added to this list. - self.objects_with_cards_set = self.AddressStack() + # Note also that young array objects are never listed here. + self.old_objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -652,8 +652,12 @@ extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS - # note that if 'can_make_young', then card marking will only - # be used later, after (and if) the object becomes old + # if 'can_make_young', then we also immediately set + # GCFLAG_CARDS_SET, but without adding the object to + # 'old_objects_with_cards_set'. In this way it should + # never be added to that list as long as it is young. + if can_make_young: + extra_flags |= GCFLAG_CARDS_SET # # Detect very rare cases of overflows if raw_malloc_usage(totalsize) > (sys.maxint - (WORD-1) @@ -1027,7 +1031,7 @@ addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) + self.old_objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True @@ -1071,7 +1075,7 @@ addr_byte.char[0] = chr(byte | bitmask) # if objhdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(addr_array) + self.old_objects_with_cards_set.append(addr_array) objhdr.tid |= GCFLAG_CARDS_SET return # @@ -1159,17 +1163,20 @@ # manually copy the individual card marks from source to dest bytes = self.card_marking_bytes_for_length(length) # + anybyte = 0 i = 0 while i < bytes: addr_srcbyte = self.get_card(source_addr, i) addr_dstbyte = self.get_card(dest_addr, i) byte = ord(addr_srcbyte.char[0]) + anybyte |= byte addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # + if anybyte: dest_hdr = self.header(dest_addr) if dest_hdr.tid & GCFLAG_CARDS_SET == 0: - self.objects_with_cards_set.append(dest_addr) + self.old_objects_with_cards_set.append(dest_addr) dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- @@ -1204,9 +1211,9 @@ self.collect_oldrefs_to_nursery() # # We have to loop back if collect_oldrefs_to_nursery caused - # new objects to show up in objects_with_cards_set + # new objects to show up in old_objects_with_cards_set if self.card_page_indices > 0: - if self.objects_with_cards_set.non_empty(): + if self.old_objects_with_cards_set.non_empty(): continue break # @@ -1249,7 +1256,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.objects_with_cards_set + oldlist = self.old_objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1364,22 +1371,7 @@ # arrive here. if (bool(self.young_rawmalloced_objects) and self.young_rawmalloced_objects.contains(obj)): - # 'obj' points to a young, raw-malloced object - if (self.header(obj).tid & GCFLAG_VISITED) == 0: - self.header(obj).tid |= GCFLAG_VISITED - # - # we just made 'obj' old, so we may need to add it - # in the correct list: - if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: - # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so - # the object may contain young pointers anywhere - self.objects_pointing_to_young.append(obj) - else: - # large array case: the object contains card marks - # that tell us where young pointers are, and it - # is already in objects_with_cards_set. - ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, - "neither YOUNG_PTRS nor HAS_CARDS??") + self._visit_young_rawmalloced_object(obj) return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1432,6 +1424,47 @@ # objects when we walk 'objects_pointing_to_young'. self.objects_pointing_to_young.append(newobj) + def _visit_young_rawmalloced_object(self, obj): + # 'obj' points to a young, raw-malloced object. + # Any young rawmalloced object never seen by the code here + # will end up without GCFLAG_VISITED, and be freed at the + # end of the current minor collection. Note that there was + # a bug in which dying young arrays with card marks would + # still be scanned before being freed, keeping a lot of + # objects unnecessarily alive. + hdr = self.header(obj) + if hdr.tid & GCFLAG_VISITED: + return + hdr.tid |= GCFLAG_VISITED + # + # we just made 'obj' old, so we need to add it to the correct + # lists. (Note that another point of view on the longish + # comments below is that we are not changing any flags in 'hdr', + # but just restoring invariants: the object may be missing from + # these lists as long as it is a young array, but not when it + # grows old.) + anywhere = False + # + if hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + anywhere = True + # + if hdr.tid & GCFLAG_HAS_CARDS != 0: + # large array case: the object contains card marks + # that tell us where young pointers are, and it must + # be added to 'old_objects_with_cards_set'. Note that + # we must add it even if we also added it just above to + # 'objects_pointing_to_young', because the object header + # needs to be cleaned up. + ll_assert(hdr.tid & GCFLAG_CARDS_SET != 0, + "young array: GCFLAG_HAS_CARDS without GCFLAG_CARDS_SET") + self.old_objects_with_cards_set.append(obj) + anywhere = True + # + ll_assert(anywhere, "wrong flag combination on young array") + def _malloc_out_of_nursery(self, totalsize): """Allocate non-movable memory for an object of the given From noreply at buildbot.pypy.org Sat Jul 23 22:32:53 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 22:32:53 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110723203253.D34CC829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45917:2051f1bfa5fc Date: 2011-07-23 22:32 +0200 http://bitbucket.org/pypy/pypy/changeset/2051f1bfa5fc/ Log: merge heads diff --git a/pypy/config/support.py b/pypy/config/support.py --- a/pypy/config/support.py +++ b/pypy/config/support.py @@ -9,7 +9,7 @@ return 1 # don't override MAKEFLAGS. This will call 'make' without any '-j' option if sys.platform == 'darwin': return darwin_get_cpu_count() - elif sys.platform != 'linux2': + elif not sys.platform.startswith('linux'): return 1 # implement me try: if isinstance(filename_or_file, str): diff --git a/pypy/config/test/test_support.py b/pypy/config/test/test_support.py --- a/pypy/config/test/test_support.py +++ b/pypy/config/test/test_support.py @@ -40,7 +40,7 @@ return self._value def test_cpuinfo_linux(): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("linux only") saved = os.environ try: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -23,7 +23,7 @@ self.hasdict |= __base.hasdict self.weakrefable |= __base.weakrefable self.rawdict = {} - self.acceptable_as_base_class = True + self.acceptable_as_base_class = '__new__' in rawdict self.applevel_subclasses_base = None # xxx used by faking self.fakedcpytype = None diff --git a/pypy/jit/backend/llvm/llvm_rffi.py b/pypy/jit/backend/llvm/llvm_rffi.py --- a/pypy/jit/backend/llvm/llvm_rffi.py +++ b/pypy/jit/backend/llvm/llvm_rffi.py @@ -3,7 +3,7 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo, log -if sys.platform != 'linux2': +if not sys.platform.startswith('linux'): py.test.skip("Linux only for now") # ____________________________________________________________ diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -10,6 +10,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import fatalerror +from pypy.rlib.rstackovf import StackOverflow from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function @@ -408,6 +409,15 @@ jd.warmstate = state def crash_in_jit(e): + try: + raise e + except JitException: + raise # go through + except MemoryError: + raise # go through + except StackOverflow: + raise # go through + except Exception, e: if not we_are_translated(): print "~~~ Crash in JIT!" print '~~~ %s: %s' % (e.__class__, e) @@ -421,8 +431,6 @@ def maybe_enter_jit(*args): try: maybe_compile_and_run(state.increment_threshold, *args) - except JitException: - raise # go through except Exception, e: crash_in_jit(e) maybe_enter_jit._always_inline_ = True diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -852,7 +852,7 @@ # Sometimes the library is wrapped into another DLL, ensure that # the correct bootstrap code is installed kwds["link_extra"] = ["msvcrt.lib"] - elif sys.platform == 'linux2': + elif sys.platform.startswith('linux'): compile_extra.append("-Werror=implicit-function-declaration") export_symbols_eci.append('pypyAPI') else: diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -188,7 +188,7 @@ kwds["compile_extra"] = ["/we4013"] else: kwds["link_files"] = [str(api_library + '.so')] - if sys.platform == 'linux2': + if sys.platform.startswith('linux'): kwds["compile_extra"]=["-Werror=implicit-function-declaration"] return compile_module(self.space, name, **kwds) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -85,7 +85,7 @@ return SEARCH_ERROR, None, None -if sys.platform == 'linux2' or 'freebsd' in sys.platform: +if sys.platform.startswith('linux') or 'freebsd' in sys.platform: def case_ok(filename): return True else: diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -125,13 +125,13 @@ assert st.st_size == 14 assert st.st_nlink == 1 - #if sys.platform.startswith('linux2'): + #if sys.platform.startswith('linux'): # # expects non-integer timestamps - it's unlikely that they are # # all three integers # assert ((st.st_atime, st.st_mtime, st.st_ctime) != # (st[7], st[8], st[9])) # assert st.st_blksize * st.st_blocks >= st.st_size - if sys.platform.startswith('linux2'): + if sys.platform.startswith('linux'): assert hasattr(st, 'st_rdev') def test_stat_float_times(self): diff --git a/pypy/rlib/test/test_rlocale.py b/pypy/rlib/test/test_rlocale.py --- a/pypy/rlib/test/test_rlocale.py +++ b/pypy/rlib/test/test_rlocale.py @@ -37,7 +37,7 @@ assert isinstance(grouping, str) def test_libintl(): - if sys.platform not in ("linux2", "darwin"): + if sys.platform != "darwin" or not sys.platform.startswith("linux"): py.test.skip("there is (maybe) no libintl here") _gettext = external('gettext', [rffi.CCHARP], rffi.CCHARP) res = _gettext("1234") diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -1331,7 +1331,7 @@ def _where_is_errno(): return standard_c_lib._errno() - elif sys.platform in ('linux2', 'freebsd6'): + elif sys.platform.startswith('linux') or sys.platform == 'freebsd6': standard_c_lib.__errno_location.restype = ctypes.POINTER(ctypes.c_int) def _where_is_errno(): return standard_c_lib.__errno_location() diff --git a/pypy/rpython/lltypesystem/llarena.py b/pypy/rpython/lltypesystem/llarena.py --- a/pypy/rpython/lltypesystem/llarena.py +++ b/pypy/rpython/lltypesystem/llarena.py @@ -404,7 +404,7 @@ from pypy.rpython.extfunc import register_external from pypy.rlib.objectmodel import CDefinedIntSymbolic -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): # This only works with linux's madvise(), which is really not a memory # usage hint but a real command. It guarantees that after MADV_DONTNEED # the pages are cleared again. diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -1348,7 +1348,7 @@ def test_prefix(self): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("Not supported") from pypy.translator.platform import platform diff --git a/pypy/rpython/memory/gc/env.py b/pypy/rpython/memory/gc/env.py --- a/pypy/rpython/memory/gc/env.py +++ b/pypy/rpython/memory/gc/env.py @@ -55,7 +55,7 @@ # will be huge on 64-bit systems. if sys.maxint == 2147483647: # 32-bit - if sys.platform == 'linux2': + if sys.platform.startswith('linux'): addressable_size = float(2**32) # 4GB elif sys.platform == 'win32': addressable_size = float(2**31) # 2GB @@ -65,7 +65,7 @@ addressable_size = float(2**63) # 64-bit -def get_total_memory_linux2(filename): +def get_total_memory_linux(filename): debug_start("gc-hardware") result = -1.0 try: @@ -93,7 +93,7 @@ result = addressable_size debug_stop("gc-hardware") return result - +get_total_memory_linux2 = get_total_memory_linux3 = get_total_memory_linux def get_total_memory_darwin(result): debug_start("gc-hardware") @@ -108,7 +108,7 @@ return result -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): def get_total_memory(): return get_total_memory_linux2('/proc/meminfo') diff --git a/pypy/rpython/module/ll_os_stat.py b/pypy/rpython/module/ll_os_stat.py --- a/pypy/rpython/module/ll_os_stat.py +++ b/pypy/rpython/module/ll_os_stat.py @@ -21,7 +21,7 @@ # sub-second timestamps. # - TIMESPEC is defined when the "struct stat" contains st_atim field. -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): TIMESPEC = platform.Struct('struct timespec', [('tv_sec', rffi.TIME_T), ('tv_nsec', rffi.LONG)]) diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -226,7 +226,7 @@ eci = eci.merge(configure_boehm()) pre_include_bits = [] - if sys.platform == "linux2": + if sys.platform.startswith('linux'): pre_include_bits += ["#define _REENTRANT 1", "#define GC_LINUX_THREADS 1"] if sys.platform != "win32": diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py --- a/pypy/translator/platform/__init__.py +++ b/pypy/translator/platform/__init__.py @@ -230,7 +230,7 @@ return True -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): from pypy.translator.platform.linux import Linux, Linux64 import platform if platform.architecture()[0] == '32bit': diff --git a/pypy/translator/sandbox/sandlib.py b/pypy/translator/sandbox/sandlib.py --- a/pypy/translator/sandbox/sandlib.py +++ b/pypy/translator/sandbox/sandlib.py @@ -209,7 +209,7 @@ def handle_until_return(self): child_stdin = self.popen.stdin child_stdout = self.popen.stdout - if self.os_level_sandboxing and sys.platform.startswith('linux2'): + if self.os_level_sandboxing and sys.platform.startswith('linux'): # rationale: we wait until the child process started completely, # letting the C library do any system calls it wants for # initialization. When the RPython code starts up, it quickly diff --git a/pypy/translator/sandbox/test/test_sandbox.py b/pypy/translator/sandbox/test/test_sandbox.py --- a/pypy/translator/sandbox/test/test_sandbox.py +++ b/pypy/translator/sandbox/test/test_sandbox.py @@ -145,7 +145,7 @@ g = pipe.stdin f = pipe.stdout expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GENERATIONGC_NURSERY",), None) - if sys.platform == 'linux2': # on Mac, uses another (sandboxsafe) approach + if sys.platform.startswith('linux'): # on Mac, uses another (sandboxsafe) approach expect(f, g, "ll_os.ll_os_open", ("/proc/cpuinfo", 0, 420), OSError(5232, "xyz")) expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GC_DEBUG",), None) From noreply at buildbot.pypy.org Sat Jul 23 23:12:10 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Sat, 23 Jul 2011 23:12:10 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: first draft of the talk Message-ID: <20110723211210.BB20E829BA@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: extradoc Changeset: r3838:698e19195980 Date: 2011-07-23 23:11 +0200 http://bitbucket.org/pypy/extradoc/changeset/698e19195980/ Log: first draft of the talk diff --git a/talk/icooolps2011/talk/figures/bench.pdf b/talk/icooolps2011/talk/figures/bench.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0def86736f36c863a02694883f29401e911f9c25 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/map.svg b/talk/icooolps2011/talk/figures/map.svg new file mode 100644 --- /dev/null +++ b/talk/icooolps2011/talk/figures/map.svg @@ -0,0 +1,327 @@ + + + +image/svg+xmlmap +map +"a": 0 +add "a" +map +"a": 0 +"b": 1 +add "b" +map +"c": 0 +add "c" +instance +map +storage +array +4 +6 + \ No newline at end of file diff --git a/talk/icooolps2011/talk/figures/map01.pdf b/talk/icooolps2011/talk/figures/map01.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d957a75d52a1e205b35f2139afe40e260bcaa5f7 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/map02.pdf b/talk/icooolps2011/talk/figures/map02.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c8f07cffbd5017707537c5fb18bf7a822384016f GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/metatrace01.pdf b/talk/icooolps2011/talk/figures/metatrace01.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0b7181b5a476093c16ff1233f37535378ef7bf8a GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace-levels-metatracing.svg b/talk/icooolps2011/talk/figures/trace-levels-metatracing.svg new file mode 100644 --- /dev/null +++ b/talk/icooolps2011/talk/figures/trace-levels-metatracing.svg @@ -0,0 +1,833 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + CPU + + Interpreter + + User Program + + + f1 + + + + + f2 + + + + + main_loop + + + + + + BINARY_ADD + + + + JUMP_IF_FALSE + + + + + + + ... + ... + + + + + + + + + + Trace for f1 + + ops frommain_loop...ops fromBINARY_ADD...more ops frommain_loop...ops_fromJUMP_IF_FALSEguard(...)jump to start + + + Tracer + + + CPU + + + diff --git a/talk/icooolps2011/talk/figures/trace-levels-tracing.svg b/talk/icooolps2011/talk/figures/trace-levels-tracing.svg new file mode 100644 --- /dev/null +++ b/talk/icooolps2011/talk/figures/trace-levels-tracing.svg @@ -0,0 +1,991 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + CPU + + Interpreter + + + + + main_loop + + + + + + BINARY_ADD + + + + JUMP_IF_FALSE + + + + + + + ... + ... + + + + + + Tracer + + + CPU + + + + + + + CPU + User Program + + + f1 + + + + + f2 + + + + diff --git a/talk/icooolps2011/talk/figures/trace01.pdf b/talk/icooolps2011/talk/figures/trace01.pdf new file mode 100644 index 0000000000000000000000000000000000000000..252b5089e72d3626e636cd02397204a464c7ca22 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace02.pdf b/talk/icooolps2011/talk/figures/trace02.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ece12fe0c3f96856afea26c49d92ade630db9328 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace03.pdf b/talk/icooolps2011/talk/figures/trace03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..04b38b8996eb2c297214c017bbe1cce1f8f64bdb GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace04.pdf b/talk/icooolps2011/talk/figures/trace04.pdf new file mode 100644 index 0000000000000000000000000000000000000000..472b798aeae005652fc0d749ed6571117c5819d9 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace05.pdf b/talk/icooolps2011/talk/figures/trace05.pdf new file mode 100644 index 0000000000000000000000000000000000000000..977e3bbda8d4d349f27f06fcdaa3bd100e95e1a7 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/talk.tex b/talk/icooolps2011/talk/talk.tex new file mode 100644 --- /dev/null +++ b/talk/icooolps2011/talk/talk.tex @@ -0,0 +1,577 @@ +\documentclass[utf8x]{beamer} + +% This file is a solution template for: + +% - Talk at a conference/colloquium. +% - Talk length is about 20min. +% - Style is ornate. + +\mode +{ + \usetheme{Warsaw} + % or ... + + %\setbeamercovered{transparent} + % or whatever (possibly just delete it) +} + + +\usepackage[english]{babel} +\usepackage{listings} +\usepackage{fancyvrb} +\usepackage{ulem} +\usepackage{color} +\usepackage{alltt} + +\usepackage[utf8x]{inputenc} + +\input{pygments} + +\newcommand\redsout[1]{{\color{red}\sout{\hbox{\color{black}{#1}}}}} +\newcommand{\noop}{} + +% or whatever + +% Or whatever. Note that the encoding and the font should match. If T1 +% does not look nice, try deleting the line with the fontenc. + + +\title[Runtime Feedback in a Meta-Tracing JIT]{Runtime Feedback in a Meta-Tracing JIT for Efficient Dynamic Languages} + +\author[Carl Friedrich Bolz et. al.]{\emph{Carl Friedrich Bolz}\inst{1} \and Antonio Cuni\inst{3} \and Maciej Fijałkowski\inst{2} \and Michael Leuschel\inst{1} \and Samuele Pedroni\inst{3} \and Armin Rigo\inst{1}} +% - Give the names in the same order as the appear in the paper. +% - Use the \inst{?} command only if the authors have different +% affiliation. + +\institute[Heinrich-Heine-Universität Düsseldorf] +{$^1$Heinrich-Heine-Universität Düsseldorf, STUPS Group, Germany \and + + $^2$merlinux GmbH, Hildesheim, Germany \and + + $^3$Open End, Göteborg, Sweden \and +} + +\date{ICOOOLPS 2011, July 26, 2011} +% - Either use conference name or its abbreviation. +% - Not really informative to the audience, more for people (including +% yourself) who are reading the slides online + + +% If you have a file called "university-logo-filename.xxx", where xxx +% is a graphic format that can be processed by latex or pdflatex, +% resp., then you can add a logo as follows: + + + + +% Delete this, if you do not want the table of contents to pop up at +% the beginning of each subsection: +%\AtBeginSubsection[] +%{ +% \begin{frame} +% \frametitle{Outline} +% \tableofcontents[currentsection,currentsubsection] +% \end{frame} +%} + + +% If you wish to uncover everything in a step-wise fashion, uncomment +% the following command: + +%\beamerdefaultoverlayspecification{<+->} + + +\begin{document} + +\begin{frame} + \titlepage +\end{frame} + +\begin{frame} + \frametitle{Good JIT Compilers for Dynamic Languages are Hard} + \begin{itemize} + \item implementing the object model well is crucial + \item recent languages like Python, Ruby, JS have complex core semantics + \item many corner cases, even hard to interpret correctly + \pause + \item to get efficiency, the correct fast path through the tree of implementations must be generated XXX + \item feedback of runtime information to the compiler is necessary + \item correct exploitation of this information in the compiler + \end{itemize} + \pause + \begin{block}{Problems} + \begin{enumerate} + \item implement all corner-cases of semantics correctly + \item ... and the common cases efficiently + \item feed back and exploit runtime information + \end{enumerate} + \end{block} +\end{frame} + +\begin{frame} + \frametitle{A Tracing JIT} + \includegraphics[scale=0.5]{figures/trace01.pdf} +\end{frame} + +\begin{frame} + \frametitle{A Tracing JIT} + \includegraphics[scale=0.5]{figures/trace02.pdf} +\end{frame} + +\begin{frame} + \frametitle{A Tracing JIT} + \includegraphics[scale=0.5]{figures/trace03.pdf} +\end{frame} + +\begin{frame} + \frametitle{A Tracing JIT} + \includegraphics[scale=0.5]{figures/trace04.pdf} +\end{frame} + +\begin{frame} + \frametitle{Tracing JITs} + Advantages: + \begin{itemize} + \item can be added to existing VM + \item interpreter does a lot of work + \item can fall back to interpreter for uncommon paths + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Granularity Problems} + \begin{itemize} + \item if the tracer records bytecode, not enough information is there + \item many dynamic languages have bytecodes that contain complex logic + \item need to expand the bytecode in the trace into something more explicit + \item this duplicates the lanuage semantics in the tracer/optimizer + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Example: Attribute Reads in Python} + What happens when an attribute \texttt{x.m} is read? (simplified) + \begin{itemize} + \item check for \texttt{x.\_\_getattribute\_\_}, if there, call it + \pause + \item look for the attribute in the object's dictionary, if it's there, return it + \pause + \item walk up the MRO and look in each class' dictionary for the attribute + \pause + \item if the attribute is found, call its \texttt{\_\_get\_\_} attribute and return the result + \pause + \item if the attribute is not found, look for \texttt{x.\_\_getattr\_\_}, if there, call it + \pause + \item raise an \texttt{AttributeError} + \end{itemize} + \pause + all this is one bytecode +\end{frame} + +\begin{frame} + \frametitle{Idea of Meta-Tracing} + \includegraphics[scale=0.5]{figures/trace05.pdf} +\end{frame} + +\begin{frame} + \frametitle{Meta-Tracing} + \includegraphics[scale=0.5]{figures/metatrace01.pdf} +\end{frame} + +\begin{frame} + \frametitle{Meta-Tracing JITs} + \begin{block}{Advantages:} + \begin{itemize} + \item semantics is always like that of the interpreter + \item trace fully contains language semantics + \item meta-tracers can be reused for various interpreters + \end{itemize} + \end{block} + \pause + a few meta-tracing systems have been built: + \begin{itemize} + \item Sullivan et.al. describe a meta-tracer using the Dynamo RIO system + \item Yermolovich et.al. run a Lua implementation on top of a tracing JS implementation + \item SPUR is a tracing JIT for CLR bytecodes, which is used to speed up a JS implementation in C\# + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{PyPy} + A general environment for implementing dynamic languages + \pause + \begin{block}{Approach} + \begin{itemize} + \item write an interpreter for the language in RPython + \item compilable to an efficient C-based VM + \pause + \item (RPython is a restricted subset of Python) + \end{itemize} + \end{block} + \pause + \begin{block}{PyPy's Meta-Tracing JIT} + \begin{itemize} + \item PyPy contains a meta-tracing JIT for interpreters in RPython + \item needs a few source-code hints (or annotations) in the interpreter + \item powerful general optimizations + \end{itemize} + \end{block} +\end{frame} + +\begin{frame} + \frametitle{Runtime Feedback} + Problems of Naive Meta-Tracing: + \begin{itemize} + \item no runtime feedback of user-level types + \item tracer does not know about invariants in the interpreter + \end{itemize} + \pause + \begin{block}{Proposed Solutions} + \begin{itemize} + \item introduce \textit{hints} that the interpreter-author can use + \item hints are annotation in the interpreter + \item they give information to the meta-tracer + \pause + \item two hints presented here + \item one to induce runtime feedback of arbitrary information + \item the second one to influence constant folding + \end{itemize} + \end{block} +\end{frame} + + +\begin{frame} + \frametitle{Example: Instances with Maps} + \includegraphics[scale=0.5]{figures/map01.pdf} +\end{frame} + +\begin{frame} + \frametitle{Example: Instances with Maps} + \includegraphics[scale=0.5]{figures/map02.pdf} +\end{frame} + +\begin{frame}[containsverbatim] +\frametitle{Map Implementation} + +\begin{Verbatim}[commandchars=\\\{\}] +\PY{k}{class} \PY{n+nc}{Map}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} + \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{indexes}\PY{p}{)}\PY{p}{:} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes} \PY{o}{=} \PY{n}{indexes} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{other\PYZus{}maps} \PY{o}{=} \PY{p}{\PYZob{}}\PY{p}{\PYZcb{}} + + \PY{k}{def} \PY{n+nf}{getindex}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{,} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)} + + \PY{k}{def} \PY{n+nf}{add\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{o}{.}\PY{o}{.}\PY{o}{.} + +\PY{n}{EMPTY\PYZus{}MAP} \PY{o}{=} \PY{n}{Map}\PY{p}{(}\PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}\PY{p}{)} +\end{Verbatim} +\end{frame} + +\begin{frame}[plain,containsverbatim] +\begin{Verbatim}[commandchars=\\\{\}] +\PY{k}{class} \PY{n+nc}{Instance}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} + \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{)}\PY{p}{:} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map} \PY{o}{=} \PY{n}{EMPTY\PYZus{}MAP} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{storage} \PY{o}{=} \PY{p}{[}\PY{p}{]} + + \PY{k}{def} \PY{n+nf}{getfield}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{n}{index} \PY{o}{=} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{name}\PY{p}{)} + \PY{k}{if} \PY{n}{index} \PY{o}{!=} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{:} + \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{storage}\PY{p}{[}\PY{n}{index}\PY{p}{]} + \PY{k}{return} \PY{n+nb+bp}{None} + + \PY{k}{def} \PY{n+nf}{write\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{value}\PY{p}{)}\PY{p}{:} + \PY{o}{.}\PY{o}{.}\PY{o}{.} +\end{Verbatim} +\end{frame} + +\begin{frame}[plain,containsverbatim] +\frametitle{Trace for code \texttt{inst.a + inst.b}} +\begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] +# $inst_1$.getattr("a") +$map_1$ = $inst_1$.map +$index_1$ = Map.getindex($map_1$, "a") +guard($index_1$ != -1) +$storage_1$ = $inst_1$.storage +$result_1$ = $storage_1$[$index_1$] +|\pause| +# $inst_1$.getattr("b") +$map_2$ = $inst_1$.map +$index_2$ = Map.getindex($map_2$, "b") +guard($index_2$ != -1) +$storage_2$ = $inst_1$.storage +$result_2$ = $storage_2$[$index_2$] + +$v_1$ = $result_1$ + $result_2$ +return($v_1$) +\end{lstlisting} +\end{frame} + +\begin{frame}[plain,containsverbatim] +\frametitle{Trace for code \texttt{inst.a + inst.b}} +\begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] +# $inst_1$.getattr("a") +$map_1$ = $inst_1$.map +$index_1$ = Map.getindex($map_1$, "a") +guard($index_1$ != -1) +$storage_1$ = $inst_1$.storage +$result_1$ = $storage_1$[$index_1$] + +# $inst_1$.getattr("b") +$map_2$ = $inst_1$.map +$index_2$ = Map.getindex($map_2$, "b") +guard($index_2$ != -1) +$storage_2$ = $inst_1$.storage +$result_2$ = $storage_2$[$index_2$] + +$v_1$ = $result_1$ + $result_2$ +return($v_1$) +\end{lstlisting} +\end{frame} + +\begin{frame}[containsverbatim] + \frametitle{Runtime Feedback Controlled by the Interpreter Author} + \begin{itemize} + \item give the interpreter author a way to feed back runtime values into the trace + \item written as \texttt{promote(x)} + \item captures the argument's runtime value during tracing + \item should be used only for variables that take few values + \end{itemize} + \pause + + \begin{minipage}[b]{6cm} + \centering + {\noop + \begin{lstlisting}[mathescape,basicstyle=\ttfamily] +def f1(x, y): + promote(x) + z = x * 2 + 1 + return z + y + \end{lstlisting} + } + \end{minipage} + \vline + \hspace{0.5cm} + \begin{minipage}[b]{4cm} + {\noop + \begin{lstlisting}[mathescape,basicstyle=\ttfamily] +guard($x_1$ == 4) +$v_1$ = $x_1$ * 2 +$z_1$ = $v_1$ + 1 +$v_2$ = $z_1$ + $y_1$ +return($v_2$) + \end{lstlisting} + } + \end{minipage} +\end{frame} + +\begin{frame}[containsverbatim] + \frametitle{Runtime Feedback Controlled by the Interpreter Author} + \begin{itemize} + \item give the interpreter author a way to feed back runtime values into the trace + \item written as \texttt{promote(x)} + \item captures the argument's runtime value during tracing + \item should be used only for variables that take few values + \end{itemize} + + \begin{minipage}[b]{6cm} + \centering + {\noop + \begin{lstlisting}[mathescape,basicstyle=\ttfamily] +def f1(x, y): + promote(x) + z = x * 2 + 1 + return z + y + + + \end{lstlisting} + } + \end{minipage} +\end{frame} + +\begin{frame}[containsverbatim] + \frametitle{Runtime Feedback Controlled by the Interpreter Author} + \begin{itemize} + \item give the interpreter author a way to feed back runtime values into the trace + \item written as \texttt{promote(x)} + \item captures the argument's runtime value during tracing + \item should be used only for variables that take few values + \end{itemize} + + \begin{minipage}[b]{6cm} + \centering + {\noop + \begin{lstlisting}[mathescape,basicstyle=\ttfamily] +def f1(x, y): + promote(x) + z = x * 2 + 1 + return z + y + + + \end{lstlisting} + } + \end{minipage} + \vline + \hspace{0.5cm} + \begin{minipage}[b]{4cm} + {\noop + \begin{lstlisting}[mathescape,basicstyle=\ttfamily] +guard($x_1$ == 4) +$v_1$ = $x_1$ * 2 +$z_1$ = $v_1$ + 1 +$v_2$ = $z_1$ + $y_1$ +return($v_2$) + \end{lstlisting} + } + \end{minipage} +\end{frame} + +\begin{frame} + \frametitle{Foldable Operations Defined by the Interpreter Author} + \begin{itemize} + \item let the interpreter author define foldable functions + \item those functions typically don't look foldable + \item otherwise there is no need for an annotation + \item done via a function decorator \texttt{@elidable} + \pause + \item decorated functions should be pure + \item or have idempotent side effects (such as a function that memoizes) + \item trace optimizer will remove calls to such functions with constant arguments + \end{itemize} +\end{frame} + +\begin{frame}[containsverbatim] +\frametitle{Adding Hints to Maps} + +\begin{Verbatim}[commandchars=\\\{\}] +\PY{k}{class} \PY{n+nc}{Map}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} + \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{indexes}\PY{p}{)}\PY{p}{:} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes} \PY{o}{=} \PY{n}{indexes} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{other\PYZus{}maps} \PY{o}{=} \PY{p}{\PYZob{}}\PY{p}{\PYZcb{}} + + \PY{n+nd}{@elidable} + \PY{k}{def} \PY{n+nf}{getindex}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{,} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)} + + \PY{n+nd}{@elidable} + \PY{k}{def} \PY{n+nf}{add\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{o}{.}\PY{o}{.}\PY{o}{.} + +\PY{n}{EMPTY\PYZus{}MAP} \PY{o}{=} \PY{n}{Map}\PY{p}{(}\PY{p}{)} +\end{Verbatim} +\end{frame} + +\begin{frame}[containsverbatim] +\frametitle{Adding Hints to Maps} + +\begin{Verbatim}[commandchars=\\\{\}] +\PY{n}{EMPTY\PYZus{}MAP} \PY{o}{=} \PY{n}{Map}\PY{p}{(}\PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}\PY{p}{)} + +\PY{k}{class} \PY{n+nc}{Instance}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} + \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{)}\PY{p}{:} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map} \PY{o}{=} \PY{n}{EMPTY\PYZus{}MAP} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{storage} \PY{o}{=} \PY{p}{[}\PY{p}{]} + + \PY{k}{def} \PY{n+nf}{getfield}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{n}{promote}\PY{p}{(}\PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map}\PY{p}{)} + \PY{n}{index} \PY{o}{=} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{name}\PY{p}{)} + \PY{k}{if} \PY{n}{index} \PY{o}{!=} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{:} + \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{storage}\PY{p}{[}\PY{n}{index}\PY{p}{]} + \PY{k}{return} \PY{n+nb+bp}{None} + + \PY{k}{def} \PY{n+nf}{write\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{value}\PY{p}{)}\PY{p}{:} + \PY{o}{.}\PY{o}{.}\PY{o}{.} +\end{Verbatim} +\end{frame} + + +\begin{frame}[containsverbatim,plain] + \frametitle{Trace with Hints} +\begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] +# $inst_1$.getattr("a") +$map_1$ = $inst_1$.map +guard($map_1$ == 0xb74af4a8) +|{\color{gray}$index_1$ = Map.getindex($map_1$, "a")| +|{\color{gray}guard($index_1$ != -1)| +$storage_1$ = $inst_1$.storage +$result_1$ = $storage_1$[$index_1$] + +# $inst_1$.getattr("b") +|{\color{gray}$map_2$ = $inst_1$.map| +|{\color{gray}guard($map_2$ == 0xb74af4a8)| +|{\color{gray}$index_2$ = Map.getindex($map_2$, "b")| +|{\color{gray}guard($index_2$ != -1)| +|{\color{gray}$storage_2$ = $inst_1$.storage| +$result_2$ = $storage_2$[$index_2$] + +$v_1$ = $result_1$ + $result_2$ +return($v_1$) +\end{lstlisting} +\end{frame} + +\begin{frame}[containsverbatim,plain] + \frametitle{Final Trace} +\begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] +# $inst_1$.getattr("a") +$map_1$ = $inst_1$.map +guard($map_1$ == 0xb74af4a8) +$storage_1$ = $inst_1$.storage +$result_1$ = $storage_1$[$0$] +$result_2$ = $storage_2$[$1$] +$v_1$ = $result_1$ + $result_2$ +return($v_1$) +\end{lstlisting} +\end{frame} + + +\begin{frame} + \frametitle{Uses of These Hints} + \begin{block}{\texttt{promote} lets one specialize on various things:} + \begin{itemize} + \item user-level types + \item shapes of instances + \item the current state of a classes' methods + \item ... + \end{itemize} + \end{block} + \pause + \begin{block}{uses of \texttt{@elidable}} + \begin{itemize} + \item define immutable fields by decorating a getter + \item declare arbitrary invariants + \end{itemize} + + \end{block} +\end{frame} + +\begin{frame} + \frametitle{Some Benchmarks} + \begin{itemize} + \item benchmarks done using PyPy's Python interpreter + \item about 30'000 lines of code + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Some Benchmarks} + \includegraphics[scale=0.5]{figures/bench.pdf} +\end{frame} + +\begin{frame} + \frametitle{Conclusion} + \begin{itemize} + \item meta-tracing can make the efficient implementation of complex dynamic languaes easier + \item two kinds of hints to be added by the interpreter author allows arbitrary runtime feedback + \item the hints are expressive enough to re-implement classical optimizations such as maps + \item usage of the hints leads to good speedups for object-oriented code in PyPy's Python interpreter + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Bonus: Comparison with Partial Evaluation} +\end{frame} + + +\end{document} From noreply at buildbot.pypy.org Sat Jul 23 23:24:34 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 23:24:34 +0200 (CEST) Subject: [pypy-commit] pypy default: Add the encoding for the instruction BTS. Message-ID: <20110723212434.EA8E0829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45918:6d1d40c49f22 Date: 2011-07-23 18:41 +0200 http://bitbucket.org/pypy/pypy/changeset/6d1d40c49f22/ Log: Add the encoding for the instruction BTS. diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -483,6 +483,7 @@ SAR = _binaryop('SAR') TEST = _binaryop('TEST') TEST8 = _binaryop('TEST8') + BTS = _binaryop('BTS') ADD = _binaryop('ADD') SUB = _binaryop('SUB') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -565,6 +565,9 @@ TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_, immediate(1), immediate(2, 'b')) TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0') + BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1)) + BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_, immediate(1)) + # x87 instructions FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) From noreply at buildbot.pypy.org Sat Jul 23 23:24:36 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 23:24:36 +0200 (CEST) Subject: [pypy-commit] pypy default: Add some encodings for the 8-bit instruction OR. Message-ID: <20110723212436.28937829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45919:062dd0bd8fb4 Date: 2011-07-23 19:38 +0200 http://bitbucket.org/pypy/pypy/changeset/062dd0bd8fb4/ Log: Add some encodings for the 8-bit instruction OR. diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -476,6 +476,7 @@ AND = _binaryop('AND') OR = _binaryop('OR') + OR8 = _binaryop('OR8') XOR = _binaryop('XOR') NOT = _unaryop('NOT') SHL = _binaryop('SHL') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -496,6 +496,10 @@ AND8_rr = insn(rex_fw, '\x20', byte_register(1), byte_register(2,8), '\xC0') OR8_rr = insn(rex_fw, '\x08', byte_register(1), byte_register(2,8), '\xC0') + OR8_mi = insn(rex_fw, '\x80', orbyte(1<<3), mem_reg_plus_const(1), + immediate(2, 'b')) + OR8_ji = insn(rex_fw, '\x80', orbyte(1<<3), abs_, immediate(1), + immediate(2, 'b')) NEG_r = insn(rex_w, '\xF7', register(1), '\xD8') From noreply at buildbot.pypy.org Sat Jul 23 23:24:37 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 23:24:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Support writing inline code in the write barrier for large arrays, Message-ID: <20110723212437.771B9829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45920:4c0d2555caa8 Date: 2011-07-23 19:55 +0200 http://bitbucket.org/pypy/pypy/changeset/4c0d2555caa8/ Log: Support writing inline code in the write barrier for large arrays, for the simple case where calling it would just set a flag just before the object. diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -453,21 +453,33 @@ class WriteBarrierDescr(AbstractDescr): def __init__(self, gc_ll_descr): + GCClass = gc_ll_descr.GCClass self.llop1 = gc_ll_descr.llop1 self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR - self.fielddescr_tid = get_field_descr(gc_ll_descr, - gc_ll_descr.GCClass.HDR, 'tid') - self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG - # if convenient for the backend, we also compute the info about + self.fielddescr_tid = get_field_descr(gc_ll_descr, GCClass.HDR, 'tid') + # + self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG + self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = ( + self.extract_flag_byte(self.jit_wb_if_flag)) + # + if hasattr(GCClass, 'JIT_WB_CARDS_SET'): + self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET + self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT + self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = ( + self.extract_flag_byte(self.jit_wb_cards_set)) + else: + self.jit_wb_cards_set = 0 + + def extract_flag_byte(self, flag_word): + # if convenient for the backend, we compute the info about # the flag as (byte-offset, single-byte-flag). import struct - value = struct.pack("l", self.jit_wb_if_flag) + value = struct.pack("l", flag_word) assert value.count('\x00') == len(value) - 1 # only one byte is != 0 i = 0 while value[i] == '\x00': i += 1 - self.jit_wb_if_flag_byteofs = i - self.jit_wb_if_flag_singlebyte = struct.unpack('b', value[i])[0] + return (i, struct.unpack('b', value[i])[0]) def get_write_barrier_fn(self, cpu): llop1 = self.llop1 diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -1707,6 +1707,7 @@ jit_wb_if_flag = 4096 jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 0 def get_write_barrier_from_array_fn(self, cpu): return funcbox.getint() # @@ -1728,6 +1729,72 @@ else: assert record == [] + def test_cond_call_gc_wb_array_card_marking_fast_path(self): + def func_void(a, b, c): + record.append((a, b, c)) + record = [] + # + S = lltype.Struct('S', ('tid', lltype.Signed)) + S_WITH_CARDS = lltype.Struct('S_WITH_CARDS', + ('card0', lltype.Char), + ('card1', lltype.Char), + ('card2', lltype.Char), + ('card3', lltype.Char), + ('card4', lltype.Char), + ('card5', lltype.Char), + ('card6', lltype.Char), + ('card7', lltype.Char), + ('data', S)) + FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)], + lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + funcbox = self.get_funcbox(self.cpu, func_ptr) + class WriteBarrierDescr(AbstractDescr): + jit_wb_if_flag = 4096 + jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') + jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 8192 + jit_wb_cards_set_byteofs = struct.pack("i", 8192).index('\x20') + jit_wb_cards_set_singlebyte = 0x20 + jit_wb_card_page_shift = 7 + def get_write_barrier_from_array_fn(self, cpu): + return funcbox.getint() + # + for BoxIndexCls in [BoxInt, ConstInt]: + for cond in [False, True]: + print + print '_'*79 + print 'BoxIndexCls =', BoxIndexCls + print 'JIT_WB_CARDS_SET =', cond + print + value = random.randrange(-sys.maxint, sys.maxint) + value |= 4096 + if cond: + value |= 8192 + else: + value &= ~8192 + s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True) + s.data.tid = value + sgcref = rffi.cast(llmemory.GCREF, s.data) + del record[:] + box_index = BoxIndexCls((9<<7) + 17) + self.execute_operation(rop.COND_CALL_GC_WB_ARRAY, + [BoxPtr(sgcref), box_index, BoxPtr(sgcref)], + 'void', descr=WriteBarrierDescr()) + if cond: + assert record == [] + assert s.card6 == '\x02' + else: + assert record == [(s.data, (9<<7) + 17, s.data)] + assert s.card6 == '\x00' + assert s.card0 == '\x00' + assert s.card1 == '\x00' + assert s.card2 == '\x00' + assert s.card3 == '\x00' + assert s.card4 == '\x00' + assert s.card5 == '\x00' + assert s.card7 == '\x00' + def test_force_operations_returning_void(self): values = [] def maybe_force(token, flag): diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -2246,10 +2246,12 @@ if opnum == rop.COND_CALL_GC_WB: N = 2 func = descr.get_write_barrier_fn(self.cpu) + card_marking = False elif opnum == rop.COND_CALL_GC_WB_ARRAY: N = 3 func = descr.get_write_barrier_from_array_fn(self.cpu) assert func != 0 + card_marking = descr.jit_wb_cards_set != 0 else: raise AssertionError(opnum) # @@ -2258,6 +2260,18 @@ imm(descr.jit_wb_if_flag_singlebyte)) self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later jz_location = self.mc.get_relative_pos() + + # for cond_call_gc_wb_array, also add another fast path: + # if GCFLAG_CARDS_SET, then we can just set one bit and be done + if card_marking: + self.mc.TEST8(addr_add_const(loc_base, + descr.jit_wb_cards_set_byteofs), + imm(descr.jit_wb_cards_set_singlebyte)) + self.mc.J_il8(rx86.Conditions['NZ'], 0) # patched later + jnz_location = self.mc.get_relative_pos() + else: + jnz_location = 0 + # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. if IS_X86_32: @@ -2297,6 +2311,43 @@ loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) + + # if GCFLAG_CARDS_SET, then we can do the whole thing that would + # be done in the CALL above with just four instructions, so here + # is an inline copy of them + if card_marking: + self.mc.JMP_l8(0) # jump to the exit, patched later + jmp_location = self.mc.get_relative_pos() + # patch the JNZ above + offset = self.mc.get_relative_pos() - jnz_location + assert 0 < offset <= 127 + self.mc.overwrite(jnz_location-1, chr(offset)) + # + loc_index = arglocs[1] + if isinstance(loc_index, RegLoc): + # choose a scratch register + tmp1 = loc_index + self.mc.PUSH_r(tmp1.value) + # SHR tmp, card_page_shift + self.mc.SHR_ri(tmp1.value, descr.jit_wb_card_page_shift) + # XOR tmp, -8 + self.mc.XOR_ri(tmp1.value, -8) + # BTS [loc_base], tmp + self.mc.BTS(addr_add_const(loc_base, 0), tmp1) + # done + self.mc.POP_r(tmp1.value) + elif isinstance(loc_index, ImmedLoc): + byte_index = loc_index.value >> descr.jit_wb_card_page_shift + byte_ofs = ~(byte_index >> 3) + byte_val = 1 << (byte_index & 7) + self.mc.OR8(addr_add_const(loc_base, byte_ofs), imm(byte_val)) + else: + raise AssertionError("index is neither RegLoc nor ImmedLoc") + # patch the JMP above + offset = self.mc.get_relative_pos() - jmp_location + assert 0 < offset <= 127 + self.mc.overwrite(jmp_location-1, chr(offset)) + # # patch the JZ above offset = self.mc.get_relative_pos() - jz_location assert 0 < offset <= 127 diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -524,6 +524,76 @@ def test_compile_framework_8(self): self.run('compile_framework_8') + def define_compile_framework_9(cls): + # Like compile_framework_8, but with variable indexes and large + # arrays, testing the card_marking case + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + num = 512 + (n & 7) + l = [None] * num + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[num-8] = X(n+70) + l[num-9] = X(n+80) + l[num-10] = X(n+90) + l[num-11] = X(n+100) + l[-12] = X(n+110) + l[-13] = X(n+120) + l[-14] = X(n+130) + l[-15] = X(n+140) + if n < 1800: + num = 512 + (n & 7) + check(len(l) == num) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[num-8].x == n+70) + check(l[num-9].x == n+80) + check(l[num-10].x == n+90) + check(l[num-11].x == n+100) + check(l[-12].x == n+110) + check(l[-13].x == n+120) + check(l[-14].x == n+130) + check(l[-15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 512) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[-8].x == 72) + check(l[-9].x == 82) + check(l[-10].x == 92) + check(l[-11].x == 102) + check(l[-12].x == 112) + check(l[-13].x == 122) + check(l[-14].x == 132) + check(l[-15].x == 142) + return before, f, after + + def test_compile_framework_9(self): + self.run('compile_framework_9') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -920,6 +920,20 @@ # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS + # for the JIT to generate custom code corresponding to the array + # write barrier for the simplest case of cards. If JIT_CARDS_SET + # is already set on an object, it will execute code like this: + # MOV eax, index + # SHR eax, JIT_WB_CARD_PAGE_SHIFT + # XOR eax, -8 + # BTS [object], eax + if TRANSLATION_PARAMS['card_page_indices'] > 0: + JIT_WB_CARDS_SET = GCFLAG_CARDS_SET + JIT_WB_CARD_PAGE_SHIFT = 1 + while ((1 << JIT_WB_CARD_PAGE_SHIFT) != + TRANSLATION_PARAMS['card_page_indices']): + JIT_WB_CARD_PAGE_SHIFT += 1 + @classmethod def JIT_max_size_of_young_obj(cls): return cls.TRANSLATION_PARAMS['large_object'] From noreply at buildbot.pypy.org Sat Jul 23 23:24:38 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 23 Jul 2011 23:24:38 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110723212438.D9038829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45921:b3db617a2463 Date: 2011-07-23 22:34 +0200 http://bitbucket.org/pypy/pypy/changeset/b3db617a2463/ Log: merge heads diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -453,21 +453,33 @@ class WriteBarrierDescr(AbstractDescr): def __init__(self, gc_ll_descr): + GCClass = gc_ll_descr.GCClass self.llop1 = gc_ll_descr.llop1 self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR - self.fielddescr_tid = get_field_descr(gc_ll_descr, - gc_ll_descr.GCClass.HDR, 'tid') - self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG - # if convenient for the backend, we also compute the info about + self.fielddescr_tid = get_field_descr(gc_ll_descr, GCClass.HDR, 'tid') + # + self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG + self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = ( + self.extract_flag_byte(self.jit_wb_if_flag)) + # + if hasattr(GCClass, 'JIT_WB_CARDS_SET'): + self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET + self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT + self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = ( + self.extract_flag_byte(self.jit_wb_cards_set)) + else: + self.jit_wb_cards_set = 0 + + def extract_flag_byte(self, flag_word): + # if convenient for the backend, we compute the info about # the flag as (byte-offset, single-byte-flag). import struct - value = struct.pack("l", self.jit_wb_if_flag) + value = struct.pack("l", flag_word) assert value.count('\x00') == len(value) - 1 # only one byte is != 0 i = 0 while value[i] == '\x00': i += 1 - self.jit_wb_if_flag_byteofs = i - self.jit_wb_if_flag_singlebyte = struct.unpack('b', value[i])[0] + return (i, struct.unpack('b', value[i])[0]) def get_write_barrier_fn(self, cpu): llop1 = self.llop1 diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -1707,6 +1707,7 @@ jit_wb_if_flag = 4096 jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 0 def get_write_barrier_from_array_fn(self, cpu): return funcbox.getint() # @@ -1728,6 +1729,72 @@ else: assert record == [] + def test_cond_call_gc_wb_array_card_marking_fast_path(self): + def func_void(a, b, c): + record.append((a, b, c)) + record = [] + # + S = lltype.Struct('S', ('tid', lltype.Signed)) + S_WITH_CARDS = lltype.Struct('S_WITH_CARDS', + ('card0', lltype.Char), + ('card1', lltype.Char), + ('card2', lltype.Char), + ('card3', lltype.Char), + ('card4', lltype.Char), + ('card5', lltype.Char), + ('card6', lltype.Char), + ('card7', lltype.Char), + ('data', S)) + FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)], + lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + funcbox = self.get_funcbox(self.cpu, func_ptr) + class WriteBarrierDescr(AbstractDescr): + jit_wb_if_flag = 4096 + jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') + jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 8192 + jit_wb_cards_set_byteofs = struct.pack("i", 8192).index('\x20') + jit_wb_cards_set_singlebyte = 0x20 + jit_wb_card_page_shift = 7 + def get_write_barrier_from_array_fn(self, cpu): + return funcbox.getint() + # + for BoxIndexCls in [BoxInt, ConstInt]: + for cond in [False, True]: + print + print '_'*79 + print 'BoxIndexCls =', BoxIndexCls + print 'JIT_WB_CARDS_SET =', cond + print + value = random.randrange(-sys.maxint, sys.maxint) + value |= 4096 + if cond: + value |= 8192 + else: + value &= ~8192 + s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True) + s.data.tid = value + sgcref = rffi.cast(llmemory.GCREF, s.data) + del record[:] + box_index = BoxIndexCls((9<<7) + 17) + self.execute_operation(rop.COND_CALL_GC_WB_ARRAY, + [BoxPtr(sgcref), box_index, BoxPtr(sgcref)], + 'void', descr=WriteBarrierDescr()) + if cond: + assert record == [] + assert s.card6 == '\x02' + else: + assert record == [(s.data, (9<<7) + 17, s.data)] + assert s.card6 == '\x00' + assert s.card0 == '\x00' + assert s.card1 == '\x00' + assert s.card2 == '\x00' + assert s.card3 == '\x00' + assert s.card4 == '\x00' + assert s.card5 == '\x00' + assert s.card7 == '\x00' + def test_force_operations_returning_void(self): values = [] def maybe_force(token, flag): diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -2246,10 +2246,12 @@ if opnum == rop.COND_CALL_GC_WB: N = 2 func = descr.get_write_barrier_fn(self.cpu) + card_marking = False elif opnum == rop.COND_CALL_GC_WB_ARRAY: N = 3 func = descr.get_write_barrier_from_array_fn(self.cpu) assert func != 0 + card_marking = descr.jit_wb_cards_set != 0 else: raise AssertionError(opnum) # @@ -2258,6 +2260,18 @@ imm(descr.jit_wb_if_flag_singlebyte)) self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later jz_location = self.mc.get_relative_pos() + + # for cond_call_gc_wb_array, also add another fast path: + # if GCFLAG_CARDS_SET, then we can just set one bit and be done + if card_marking: + self.mc.TEST8(addr_add_const(loc_base, + descr.jit_wb_cards_set_byteofs), + imm(descr.jit_wb_cards_set_singlebyte)) + self.mc.J_il8(rx86.Conditions['NZ'], 0) # patched later + jnz_location = self.mc.get_relative_pos() + else: + jnz_location = 0 + # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. if IS_X86_32: @@ -2297,6 +2311,43 @@ loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) + + # if GCFLAG_CARDS_SET, then we can do the whole thing that would + # be done in the CALL above with just four instructions, so here + # is an inline copy of them + if card_marking: + self.mc.JMP_l8(0) # jump to the exit, patched later + jmp_location = self.mc.get_relative_pos() + # patch the JNZ above + offset = self.mc.get_relative_pos() - jnz_location + assert 0 < offset <= 127 + self.mc.overwrite(jnz_location-1, chr(offset)) + # + loc_index = arglocs[1] + if isinstance(loc_index, RegLoc): + # choose a scratch register + tmp1 = loc_index + self.mc.PUSH_r(tmp1.value) + # SHR tmp, card_page_shift + self.mc.SHR_ri(tmp1.value, descr.jit_wb_card_page_shift) + # XOR tmp, -8 + self.mc.XOR_ri(tmp1.value, -8) + # BTS [loc_base], tmp + self.mc.BTS(addr_add_const(loc_base, 0), tmp1) + # done + self.mc.POP_r(tmp1.value) + elif isinstance(loc_index, ImmedLoc): + byte_index = loc_index.value >> descr.jit_wb_card_page_shift + byte_ofs = ~(byte_index >> 3) + byte_val = 1 << (byte_index & 7) + self.mc.OR8(addr_add_const(loc_base, byte_ofs), imm(byte_val)) + else: + raise AssertionError("index is neither RegLoc nor ImmedLoc") + # patch the JMP above + offset = self.mc.get_relative_pos() - jmp_location + assert 0 < offset <= 127 + self.mc.overwrite(jmp_location-1, chr(offset)) + # # patch the JZ above offset = self.mc.get_relative_pos() - jz_location assert 0 < offset <= 127 diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -476,6 +476,7 @@ AND = _binaryop('AND') OR = _binaryop('OR') + OR8 = _binaryop('OR8') XOR = _binaryop('XOR') NOT = _unaryop('NOT') SHL = _binaryop('SHL') @@ -483,6 +484,7 @@ SAR = _binaryop('SAR') TEST = _binaryop('TEST') TEST8 = _binaryop('TEST8') + BTS = _binaryop('BTS') ADD = _binaryop('ADD') SUB = _binaryop('SUB') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -496,6 +496,10 @@ AND8_rr = insn(rex_fw, '\x20', byte_register(1), byte_register(2,8), '\xC0') OR8_rr = insn(rex_fw, '\x08', byte_register(1), byte_register(2,8), '\xC0') + OR8_mi = insn(rex_fw, '\x80', orbyte(1<<3), mem_reg_plus_const(1), + immediate(2, 'b')) + OR8_ji = insn(rex_fw, '\x80', orbyte(1<<3), abs_, immediate(1), + immediate(2, 'b')) NEG_r = insn(rex_w, '\xF7', register(1), '\xD8') @@ -565,6 +569,9 @@ TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_, immediate(1), immediate(2, 'b')) TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0') + BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1)) + BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_, immediate(1)) + # x87 instructions FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -524,6 +524,76 @@ def test_compile_framework_8(self): self.run('compile_framework_8') + def define_compile_framework_9(cls): + # Like compile_framework_8, but with variable indexes and large + # arrays, testing the card_marking case + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + num = 512 + (n & 7) + l = [None] * num + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[num-8] = X(n+70) + l[num-9] = X(n+80) + l[num-10] = X(n+90) + l[num-11] = X(n+100) + l[-12] = X(n+110) + l[-13] = X(n+120) + l[-14] = X(n+130) + l[-15] = X(n+140) + if n < 1800: + num = 512 + (n & 7) + check(len(l) == num) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[num-8].x == n+70) + check(l[num-9].x == n+80) + check(l[num-10].x == n+90) + check(l[num-11].x == n+100) + check(l[-12].x == n+110) + check(l[-13].x == n+120) + check(l[-14].x == n+130) + check(l[-15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 512) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[-8].x == 72) + check(l[-9].x == 82) + check(l[-10].x == 92) + check(l[-11].x == 102) + check(l[-12].x == 112) + check(l[-13].x == 122) + check(l[-14].x == 132) + check(l[-15].x == 142) + return before, f, after + + def test_compile_framework_9(self): + self.run('compile_framework_9') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -924,6 +924,20 @@ # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS + # for the JIT to generate custom code corresponding to the array + # write barrier for the simplest case of cards. If JIT_CARDS_SET + # is already set on an object, it will execute code like this: + # MOV eax, index + # SHR eax, JIT_WB_CARD_PAGE_SHIFT + # XOR eax, -8 + # BTS [object], eax + if TRANSLATION_PARAMS['card_page_indices'] > 0: + JIT_WB_CARDS_SET = GCFLAG_CARDS_SET + JIT_WB_CARD_PAGE_SHIFT = 1 + while ((1 << JIT_WB_CARD_PAGE_SHIFT) != + TRANSLATION_PARAMS['card_page_indices']): + JIT_WB_CARD_PAGE_SHIFT += 1 + @classmethod def JIT_max_size_of_young_obj(cls): return cls.TRANSLATION_PARAMS['large_object'] From noreply at buildbot.pypy.org Sun Jul 24 00:16:31 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 00:16:31 +0200 (CEST) Subject: [pypy-commit] pypy default: Moving code around. The goal is to reduce the cost of Message-ID: <20110723221631.08E51829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45922:70abd7de1363 Date: 2011-07-24 00:16 +0200 http://bitbucket.org/pypy/pypy/changeset/70abd7de1363/ Log: Moving code around. The goal is to reduce the cost of space.isinstance(), probably by a large factor: according to valgrind, for every second we spend running W_TypeObject.issubtype(), we spend almost 4 extra seconds in the rest of space.isinstance(), because of the levels and levels of indirections. diff --git a/pypy/module/__builtin__/abstractinst.py b/pypy/module/__builtin__/abstractinst.py --- a/pypy/module/__builtin__/abstractinst.py +++ b/pypy/module/__builtin__/abstractinst.py @@ -58,7 +58,10 @@ # -- case (anything, type) try: - w_result = space.isinstance(w_obj, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.isinstance_allow_override(w_obj, w_klass_or_tuple) + else: + w_result = space.isinstance(w_obj, w_klass_or_tuple) except OperationError, e: # if w_klass_or_tuple was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors @@ -72,8 +75,11 @@ w_pretendtype = space.getattr(w_obj, space.wrap('__class__')) if space.is_w(w_pretendtype, space.type(w_obj)): return False # common case: obj.__class__ is type(obj) - w_result = space.issubtype(w_pretendtype, w_klass_or_tuple, - allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_pretendtype, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_pretendtype, w_klass_or_tuple) except OperationError, e: if e.async(space): raise @@ -134,7 +140,11 @@ # -- case (type, type) try: - w_result = space.issubtype(w_derived, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_derived, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_derived, w_klass_or_tuple) except OperationError, e: # if one of the args was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -497,22 +497,25 @@ space.wrap("coercion should return None or 2-tuple")) return w_res - def issubtype(space, w_sub, w_type, allow_override=False): - if allow_override: + def issubtype(space, w_sub, w_type): + return space._type_issubtype(w_sub, w_type) + + def isinstance(space, w_inst, w_type): + return space._type_isinstance(w_inst, w_type) + + def issubtype_allow_override(space, w_sub, w_type): w_check = space.lookup(w_type, "__subclasscheck__") if w_check is None: raise OperationError(space.w_TypeError, space.wrap("issubclass not supported here")) return space.get_and_call_function(w_check, w_type, w_sub) - return space._type_issubtype(w_sub, w_type) - def isinstance(space, w_inst, w_type, allow_override=False): - if allow_override: + def isinstance_allow_override(space, w_inst, w_type): w_check = space.lookup(w_type, "__instancecheck__") if w_check is not None: return space.get_and_call_function(w_check, w_type, w_inst) - return space.issubtype(space.type(w_inst), w_type, allow_override) - + else: + return space.isinstance(w_inst, w_type) # helpers diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -568,3 +568,8 @@ if isinstance(w_sub, W_TypeObject) and isinstance(w_type, W_TypeObject): return self.wrap(w_sub.issubtype(w_type)) raise OperationError(self.w_TypeError, self.wrap("need type objects")) + + def _type_isinstance(self, w_inst, w_type): + if isinstance(w_type, W_TypeObject): + return self.wrap(self.type(w_inst).issubtype(w_type)) + raise OperationError(self.w_TypeError, self.wrap("need type object")) From noreply at buildbot.pypy.org Sun Jul 24 00:29:37 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sun, 24 Jul 2011 00:29:37 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: xfail prebuilt int unboxing on ootype for now. Message-ID: <20110723222937.584B7829BA@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45923:4587e282fee5 Date: 2011-07-23 15:29 -0700 http://bitbucket.org/pypy/pypy/changeset/4587e282fee5/ Log: xfail prebuilt int unboxing on ootype for now. diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py --- a/pypy/rlib/test/test_rerased.py +++ b/pypy/rlib/test/test_rerased.py @@ -290,6 +290,9 @@ UNERASED_TYPE = OBJECT def castable(self, TO, var): return ootype.isSubclass(lltype.typeOf(var), TO) + @py.test.mark.xfail + def test_prebuilt_erased(self): + super(TestOOtype, self).test_prebuilt_erased() def test_union(): s_e1 = SomeErased() From noreply at buildbot.pypy.org Sun Jul 24 03:57:51 2011 From: noreply at buildbot.pypy.org (ademan) Date: Sun, 24 Jul 2011 03:57:51 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Merge default. Message-ID: <20110724015751.747BA829BA@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45924:ffc2e849fd16 Date: 2011-07-23 18:57 -0700 http://bitbucket.org/pypy/pypy/changeset/ffc2e849fd16/ Log: Merge default. diff --git a/pypy/config/support.py b/pypy/config/support.py --- a/pypy/config/support.py +++ b/pypy/config/support.py @@ -9,7 +9,7 @@ return 1 # don't override MAKEFLAGS. This will call 'make' without any '-j' option if sys.platform == 'darwin': return darwin_get_cpu_count() - elif sys.platform != 'linux2': + elif not sys.platform.startswith('linux'): return 1 # implement me try: if isinstance(filename_or_file, str): diff --git a/pypy/config/test/test_support.py b/pypy/config/test/test_support.py --- a/pypy/config/test/test_support.py +++ b/pypy/config/test/test_support.py @@ -40,7 +40,7 @@ return self._value def test_cpuinfo_linux(): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("linux only") saved = os.environ try: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -23,7 +23,7 @@ self.hasdict |= __base.hasdict self.weakrefable |= __base.weakrefable self.rawdict = {} - self.acceptable_as_base_class = True + self.acceptable_as_base_class = '__new__' in rawdict self.applevel_subclasses_base = None # xxx used by faking self.fakedcpytype = None diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -453,21 +453,33 @@ class WriteBarrierDescr(AbstractDescr): def __init__(self, gc_ll_descr): + GCClass = gc_ll_descr.GCClass self.llop1 = gc_ll_descr.llop1 self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR - self.fielddescr_tid = get_field_descr(gc_ll_descr, - gc_ll_descr.GCClass.HDR, 'tid') - self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG - # if convenient for the backend, we also compute the info about + self.fielddescr_tid = get_field_descr(gc_ll_descr, GCClass.HDR, 'tid') + # + self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG + self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = ( + self.extract_flag_byte(self.jit_wb_if_flag)) + # + if hasattr(GCClass, 'JIT_WB_CARDS_SET'): + self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET + self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT + self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = ( + self.extract_flag_byte(self.jit_wb_cards_set)) + else: + self.jit_wb_cards_set = 0 + + def extract_flag_byte(self, flag_word): + # if convenient for the backend, we compute the info about # the flag as (byte-offset, single-byte-flag). import struct - value = struct.pack("l", self.jit_wb_if_flag) + value = struct.pack("l", flag_word) assert value.count('\x00') == len(value) - 1 # only one byte is != 0 i = 0 while value[i] == '\x00': i += 1 - self.jit_wb_if_flag_byteofs = i - self.jit_wb_if_flag_singlebyte = struct.unpack('b', value[i])[0] + return (i, struct.unpack('b', value[i])[0]) def get_write_barrier_fn(self, cpu): llop1 = self.llop1 diff --git a/pypy/jit/backend/llvm/llvm_rffi.py b/pypy/jit/backend/llvm/llvm_rffi.py --- a/pypy/jit/backend/llvm/llvm_rffi.py +++ b/pypy/jit/backend/llvm/llvm_rffi.py @@ -3,7 +3,7 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo, log -if sys.platform != 'linux2': +if not sys.platform.startswith('linux'): py.test.skip("Linux only for now") # ____________________________________________________________ diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -1707,6 +1707,7 @@ jit_wb_if_flag = 4096 jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 0 def get_write_barrier_from_array_fn(self, cpu): return funcbox.getint() # @@ -1728,6 +1729,72 @@ else: assert record == [] + def test_cond_call_gc_wb_array_card_marking_fast_path(self): + def func_void(a, b, c): + record.append((a, b, c)) + record = [] + # + S = lltype.Struct('S', ('tid', lltype.Signed)) + S_WITH_CARDS = lltype.Struct('S_WITH_CARDS', + ('card0', lltype.Char), + ('card1', lltype.Char), + ('card2', lltype.Char), + ('card3', lltype.Char), + ('card4', lltype.Char), + ('card5', lltype.Char), + ('card6', lltype.Char), + ('card7', lltype.Char), + ('data', S)) + FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)], + lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + funcbox = self.get_funcbox(self.cpu, func_ptr) + class WriteBarrierDescr(AbstractDescr): + jit_wb_if_flag = 4096 + jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') + jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 8192 + jit_wb_cards_set_byteofs = struct.pack("i", 8192).index('\x20') + jit_wb_cards_set_singlebyte = 0x20 + jit_wb_card_page_shift = 7 + def get_write_barrier_from_array_fn(self, cpu): + return funcbox.getint() + # + for BoxIndexCls in [BoxInt, ConstInt]: + for cond in [False, True]: + print + print '_'*79 + print 'BoxIndexCls =', BoxIndexCls + print 'JIT_WB_CARDS_SET =', cond + print + value = random.randrange(-sys.maxint, sys.maxint) + value |= 4096 + if cond: + value |= 8192 + else: + value &= ~8192 + s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True) + s.data.tid = value + sgcref = rffi.cast(llmemory.GCREF, s.data) + del record[:] + box_index = BoxIndexCls((9<<7) + 17) + self.execute_operation(rop.COND_CALL_GC_WB_ARRAY, + [BoxPtr(sgcref), box_index, BoxPtr(sgcref)], + 'void', descr=WriteBarrierDescr()) + if cond: + assert record == [] + assert s.card6 == '\x02' + else: + assert record == [(s.data, (9<<7) + 17, s.data)] + assert s.card6 == '\x00' + assert s.card0 == '\x00' + assert s.card1 == '\x00' + assert s.card2 == '\x00' + assert s.card3 == '\x00' + assert s.card4 == '\x00' + assert s.card5 == '\x00' + assert s.card7 == '\x00' + def test_force_operations_returning_void(self): values = [] def maybe_force(token, flag): diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -2246,10 +2246,12 @@ if opnum == rop.COND_CALL_GC_WB: N = 2 func = descr.get_write_barrier_fn(self.cpu) + card_marking = False elif opnum == rop.COND_CALL_GC_WB_ARRAY: N = 3 func = descr.get_write_barrier_from_array_fn(self.cpu) assert func != 0 + card_marking = descr.jit_wb_cards_set != 0 else: raise AssertionError(opnum) # @@ -2258,6 +2260,18 @@ imm(descr.jit_wb_if_flag_singlebyte)) self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later jz_location = self.mc.get_relative_pos() + + # for cond_call_gc_wb_array, also add another fast path: + # if GCFLAG_CARDS_SET, then we can just set one bit and be done + if card_marking: + self.mc.TEST8(addr_add_const(loc_base, + descr.jit_wb_cards_set_byteofs), + imm(descr.jit_wb_cards_set_singlebyte)) + self.mc.J_il8(rx86.Conditions['NZ'], 0) # patched later + jnz_location = self.mc.get_relative_pos() + else: + jnz_location = 0 + # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. if IS_X86_32: @@ -2297,6 +2311,43 @@ loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) + + # if GCFLAG_CARDS_SET, then we can do the whole thing that would + # be done in the CALL above with just four instructions, so here + # is an inline copy of them + if card_marking: + self.mc.JMP_l8(0) # jump to the exit, patched later + jmp_location = self.mc.get_relative_pos() + # patch the JNZ above + offset = self.mc.get_relative_pos() - jnz_location + assert 0 < offset <= 127 + self.mc.overwrite(jnz_location-1, chr(offset)) + # + loc_index = arglocs[1] + if isinstance(loc_index, RegLoc): + # choose a scratch register + tmp1 = loc_index + self.mc.PUSH_r(tmp1.value) + # SHR tmp, card_page_shift + self.mc.SHR_ri(tmp1.value, descr.jit_wb_card_page_shift) + # XOR tmp, -8 + self.mc.XOR_ri(tmp1.value, -8) + # BTS [loc_base], tmp + self.mc.BTS(addr_add_const(loc_base, 0), tmp1) + # done + self.mc.POP_r(tmp1.value) + elif isinstance(loc_index, ImmedLoc): + byte_index = loc_index.value >> descr.jit_wb_card_page_shift + byte_ofs = ~(byte_index >> 3) + byte_val = 1 << (byte_index & 7) + self.mc.OR8(addr_add_const(loc_base, byte_ofs), imm(byte_val)) + else: + raise AssertionError("index is neither RegLoc nor ImmedLoc") + # patch the JMP above + offset = self.mc.get_relative_pos() - jmp_location + assert 0 < offset <= 127 + self.mc.overwrite(jmp_location-1, chr(offset)) + # # patch the JZ above offset = self.mc.get_relative_pos() - jz_location assert 0 < offset <= 127 diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -476,6 +476,7 @@ AND = _binaryop('AND') OR = _binaryop('OR') + OR8 = _binaryop('OR8') XOR = _binaryop('XOR') NOT = _unaryop('NOT') SHL = _binaryop('SHL') @@ -483,6 +484,7 @@ SAR = _binaryop('SAR') TEST = _binaryop('TEST') TEST8 = _binaryop('TEST8') + BTS = _binaryop('BTS') ADD = _binaryop('ADD') SUB = _binaryop('SUB') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -496,6 +496,10 @@ AND8_rr = insn(rex_fw, '\x20', byte_register(1), byte_register(2,8), '\xC0') OR8_rr = insn(rex_fw, '\x08', byte_register(1), byte_register(2,8), '\xC0') + OR8_mi = insn(rex_fw, '\x80', orbyte(1<<3), mem_reg_plus_const(1), + immediate(2, 'b')) + OR8_ji = insn(rex_fw, '\x80', orbyte(1<<3), abs_, immediate(1), + immediate(2, 'b')) NEG_r = insn(rex_w, '\xF7', register(1), '\xD8') @@ -565,6 +569,9 @@ TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_, immediate(1), immediate(2, 'b')) TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0') + BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1)) + BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_, immediate(1)) + # x87 instructions FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -524,6 +524,76 @@ def test_compile_framework_8(self): self.run('compile_framework_8') + def define_compile_framework_9(cls): + # Like compile_framework_8, but with variable indexes and large + # arrays, testing the card_marking case + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + num = 512 + (n & 7) + l = [None] * num + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[num-8] = X(n+70) + l[num-9] = X(n+80) + l[num-10] = X(n+90) + l[num-11] = X(n+100) + l[-12] = X(n+110) + l[-13] = X(n+120) + l[-14] = X(n+130) + l[-15] = X(n+140) + if n < 1800: + num = 512 + (n & 7) + check(len(l) == num) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[num-8].x == n+70) + check(l[num-9].x == n+80) + check(l[num-10].x == n+90) + check(l[num-11].x == n+100) + check(l[-12].x == n+110) + check(l[-13].x == n+120) + check(l[-14].x == n+130) + check(l[-15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 512) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[-8].x == 72) + check(l[-9].x == 82) + check(l[-10].x == 92) + check(l[-11].x == 102) + check(l[-12].x == 112) + check(l[-13].x == 122) + check(l[-14].x == 132) + check(l[-15].x == 142) + return before, f, after + + def test_compile_framework_9(self): + self.run('compile_framework_9') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -10,6 +10,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import fatalerror +from pypy.rlib.rstackovf import StackOverflow from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function @@ -408,6 +409,15 @@ jd.warmstate = state def crash_in_jit(e): + try: + raise e + except JitException: + raise # go through + except MemoryError: + raise # go through + except StackOverflow: + raise # go through + except Exception, e: if not we_are_translated(): print "~~~ Crash in JIT!" print '~~~ %s: %s' % (e.__class__, e) @@ -421,8 +431,6 @@ def maybe_enter_jit(*args): try: maybe_compile_and_run(state.increment_threshold, *args) - except JitException: - raise # go through except Exception, e: crash_in_jit(e) maybe_enter_jit._always_inline_ = True diff --git a/pypy/module/__builtin__/abstractinst.py b/pypy/module/__builtin__/abstractinst.py --- a/pypy/module/__builtin__/abstractinst.py +++ b/pypy/module/__builtin__/abstractinst.py @@ -58,7 +58,10 @@ # -- case (anything, type) try: - w_result = space.isinstance(w_obj, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.isinstance_allow_override(w_obj, w_klass_or_tuple) + else: + w_result = space.isinstance(w_obj, w_klass_or_tuple) except OperationError, e: # if w_klass_or_tuple was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors @@ -72,8 +75,11 @@ w_pretendtype = space.getattr(w_obj, space.wrap('__class__')) if space.is_w(w_pretendtype, space.type(w_obj)): return False # common case: obj.__class__ is type(obj) - w_result = space.issubtype(w_pretendtype, w_klass_or_tuple, - allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_pretendtype, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_pretendtype, w_klass_or_tuple) except OperationError, e: if e.async(space): raise @@ -134,7 +140,11 @@ # -- case (type, type) try: - w_result = space.issubtype(w_derived, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_derived, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_derived, w_klass_or_tuple) except OperationError, e: # if one of the args was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -852,7 +852,7 @@ # Sometimes the library is wrapped into another DLL, ensure that # the correct bootstrap code is installed kwds["link_extra"] = ["msvcrt.lib"] - elif sys.platform == 'linux2': + elif sys.platform.startswith('linux'): compile_extra.append("-Werror=implicit-function-declaration") export_symbols_eci.append('pypyAPI') else: diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -188,7 +188,7 @@ kwds["compile_extra"] = ["/we4013"] else: kwds["link_files"] = [str(api_library + '.so')] - if sys.platform == 'linux2': + if sys.platform.startswith('linux'): kwds["compile_extra"]=["-Werror=implicit-function-declaration"] return compile_module(self.space, name, **kwds) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -85,7 +85,7 @@ return SEARCH_ERROR, None, None -if sys.platform == 'linux2' or 'freebsd' in sys.platform: +if sys.platform.startswith('linux') or 'freebsd' in sys.platform: def case_ok(filename): return True else: diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -125,13 +125,13 @@ assert st.st_size == 14 assert st.st_nlink == 1 - #if sys.platform.startswith('linux2'): + #if sys.platform.startswith('linux'): # # expects non-integer timestamps - it's unlikely that they are # # all three integers # assert ((st.st_atime, st.st_mtime, st.st_ctime) != # (st[7], st[8], st[9])) # assert st.st_blksize * st.st_blocks >= st.st_size - if sys.platform.startswith('linux2'): + if sys.platform.startswith('linux'): assert hasattr(st, 'st_rdev') def test_stat_float_times(self): diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -497,22 +497,25 @@ space.wrap("coercion should return None or 2-tuple")) return w_res - def issubtype(space, w_sub, w_type, allow_override=False): - if allow_override: + def issubtype(space, w_sub, w_type): + return space._type_issubtype(w_sub, w_type) + + def isinstance(space, w_inst, w_type): + return space._type_isinstance(w_inst, w_type) + + def issubtype_allow_override(space, w_sub, w_type): w_check = space.lookup(w_type, "__subclasscheck__") if w_check is None: raise OperationError(space.w_TypeError, space.wrap("issubclass not supported here")) return space.get_and_call_function(w_check, w_type, w_sub) - return space._type_issubtype(w_sub, w_type) - def isinstance(space, w_inst, w_type, allow_override=False): - if allow_override: + def isinstance_allow_override(space, w_inst, w_type): w_check = space.lookup(w_type, "__instancecheck__") if w_check is not None: return space.get_and_call_function(w_check, w_type, w_inst) - return space.issubtype(space.type(w_inst), w_type, allow_override) - + else: + return space.isinstance(w_inst, w_type) # helpers diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -568,3 +568,8 @@ if isinstance(w_sub, W_TypeObject) and isinstance(w_type, W_TypeObject): return self.wrap(w_sub.issubtype(w_type)) raise OperationError(self.w_TypeError, self.wrap("need type objects")) + + def _type_isinstance(self, w_inst, w_type): + if isinstance(w_type, W_TypeObject): + return self.wrap(self.type(w_inst).issubtype(w_type)) + raise OperationError(self.w_TypeError, self.wrap("need type object")) diff --git a/pypy/rlib/test/test_rlocale.py b/pypy/rlib/test/test_rlocale.py --- a/pypy/rlib/test/test_rlocale.py +++ b/pypy/rlib/test/test_rlocale.py @@ -37,7 +37,7 @@ assert isinstance(grouping, str) def test_libintl(): - if sys.platform not in ("linux2", "darwin"): + if sys.platform != "darwin" or not sys.platform.startswith("linux"): py.test.skip("there is (maybe) no libintl here") _gettext = external('gettext', [rffi.CCHARP], rffi.CCHARP) res = _gettext("1234") diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -1331,7 +1331,7 @@ def _where_is_errno(): return standard_c_lib._errno() - elif sys.platform in ('linux2', 'freebsd6'): + elif sys.platform.startswith('linux') or sys.platform == 'freebsd6': standard_c_lib.__errno_location.restype = ctypes.POINTER(ctypes.c_int) def _where_is_errno(): return standard_c_lib.__errno_location() diff --git a/pypy/rpython/lltypesystem/llarena.py b/pypy/rpython/lltypesystem/llarena.py --- a/pypy/rpython/lltypesystem/llarena.py +++ b/pypy/rpython/lltypesystem/llarena.py @@ -404,7 +404,7 @@ from pypy.rpython.extfunc import register_external from pypy.rlib.objectmodel import CDefinedIntSymbolic -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): # This only works with linux's madvise(), which is really not a memory # usage hint but a real command. It guarantees that after MADV_DONTNEED # the pages are cleared again. diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -1348,7 +1348,7 @@ def test_prefix(self): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("Not supported") from pypy.translator.platform import platform diff --git a/pypy/rpython/memory/gc/env.py b/pypy/rpython/memory/gc/env.py --- a/pypy/rpython/memory/gc/env.py +++ b/pypy/rpython/memory/gc/env.py @@ -55,7 +55,7 @@ # will be huge on 64-bit systems. if sys.maxint == 2147483647: # 32-bit - if sys.platform == 'linux2': + if sys.platform.startswith('linux'): addressable_size = float(2**32) # 4GB elif sys.platform == 'win32': addressable_size = float(2**31) # 2GB @@ -65,7 +65,7 @@ addressable_size = float(2**63) # 64-bit -def get_total_memory_linux2(filename): +def get_total_memory_linux(filename): debug_start("gc-hardware") result = -1.0 try: @@ -93,7 +93,7 @@ result = addressable_size debug_stop("gc-hardware") return result - +get_total_memory_linux2 = get_total_memory_linux3 = get_total_memory_linux def get_total_memory_darwin(result): debug_start("gc-hardware") @@ -108,7 +108,7 @@ return result -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): def get_total_memory(): return get_total_memory_linux2('/proc/meminfo') diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,13 +34,6 @@ the GC in very small programs. Defaults to 8 times the nursery. - PYPY_GC_LOSTCARD If between two minor collections we see more than - 'PYPY_GC_LOSTCARD * length' writes to the same array, - then give up card marking and use the fast write - barrier instead. Defaults to 0.3333 for now. - Avoid values lower than 0.125: it is the growth - factor of list.append(). - PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -205,9 +198,6 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, - # See PYPY_GC_LOSTCARD. - "lost_card": 1.0 / 3.0, - # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -224,7 +214,6 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, - lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -246,7 +235,6 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 - self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -275,8 +263,8 @@ # that it is possible for an object to be listed both in here # and in 'objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - # Note also that young array objects may be added to this list. - self.objects_with_cards_set = self.AddressStack() + # Note also that young array objects are never listed here. + self.old_objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -367,10 +355,6 @@ else: self.max_delta = 0.125 * env.get_total_memory() # - lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') - if lost_card > 0.0: - self.lost_card = lost_card - # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -665,11 +649,15 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + 1 + extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS - # note that if 'can_make_young', then card marking will only - # be used later, after (and if) the object becomes old + # if 'can_make_young', then we also immediately set + # GCFLAG_CARDS_SET, but without adding the object to + # 'old_objects_with_cards_set'. In this way it should + # never be added to that list as long as it is young. + if can_make_young: + extra_flags |= GCFLAG_CARDS_SET # # Detect very rare cases of overflows if raw_malloc_usage(totalsize) > (sys.maxint - (WORD-1) @@ -691,15 +679,11 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # followed by a Signed (the loop is empty in C). - if cardheadersize > 0: + # (the loop is empty in C). i = 0 - while i < cardheadersize - WORD: - llarena.arena_reserve(arena + i, - llmemory.sizeof(lltype.Char)) + while i < cardheadersize: + llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) i += 1 - llarena.arena_reserve(arena + i, - llmemory.sizeof(lltype.Signed)) # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -923,11 +907,14 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # + size_gc_header = self.gcheaderbuilder.size_gc_header + p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: + p -= 1 + ll_assert(p.char[0] == '\x00', + "the card marker bits are not cleared") i -= 1 - ll_assert(self.get_card(obj, i).char[0] == '\x00', - "the card marker bits are not cleared") # ---------- # Write barrier @@ -937,6 +924,20 @@ # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS + # for the JIT to generate custom code corresponding to the array + # write barrier for the simplest case of cards. If JIT_CARDS_SET + # is already set on an object, it will execute code like this: + # MOV eax, index + # SHR eax, JIT_WB_CARD_PAGE_SHIFT + # XOR eax, -8 + # BTS [object], eax + if TRANSLATION_PARAMS['card_page_indices'] > 0: + JIT_WB_CARDS_SET = GCFLAG_CARDS_SET + JIT_WB_CARD_PAGE_SHIFT = 1 + while ((1 << JIT_WB_CARD_PAGE_SHIFT) != + TRANSLATION_PARAMS['card_page_indices']): + JIT_WB_CARD_PAGE_SHIFT += 1 + @classmethod def JIT_max_size_of_young_obj(cls): return cls.TRANSLATION_PARAMS['large_object'] @@ -1025,8 +1026,6 @@ self.prebuilt_root_objects.append(addr_array) return # - self.set_cards_flag(addr_array) - # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1044,6 +1043,10 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.old_objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1072,8 +1075,6 @@ if not self.appears_to_be_young(newvalue): return # - self.set_cards_flag(addr_array) - # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1086,6 +1087,10 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.old_objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1103,36 +1108,11 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card_counter_addr(self, obj): + def get_card(self, obj, byteindex): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) - WORD + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) - def get_card(self, obj, byteindex): - return self.get_card_counter_addr(obj) + (~byteindex) - - def set_cards_flag(self, obj): - hdr = self.header(obj) - if hdr.tid & GCFLAG_CARDS_SET == 0: - # - # first time we set a card bit in this object - self.header(obj).tid |= GCFLAG_CARDS_SET - self.objects_with_cards_set.append(obj) - # - # initialize the counter with the array length and self.lost_card - typeid = self.get_type_id(obj) - offset_to_length = self.varsize_offset_to_length(typeid) - length = (obj + offset_to_length).signed[0] - counter = int(length * self.lost_card) - self.get_card_counter_addr(obj).signed[0] = counter - else: - # decrement the counter and if zero is reached, give up on - # card marking (up to the next collection). - addr = self.get_card_counter_addr(obj) - addr.signed[0] -= 1 - if addr.signed[0] < 0: - self.objects_pointing_to_young.append(obj) - hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1197,15 +1177,21 @@ # manually copy the individual card marks from source to dest bytes = self.card_marking_bytes_for_length(length) # + anybyte = 0 i = 0 while i < bytes: addr_srcbyte = self.get_card(source_addr, i) addr_dstbyte = self.get_card(dest_addr, i) byte = ord(addr_srcbyte.char[0]) + anybyte |= byte addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - self.set_cards_flag(dest_addr) + if anybyte: + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.old_objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1239,9 +1225,9 @@ self.collect_oldrefs_to_nursery() # # We have to loop back if collect_oldrefs_to_nursery caused - # new objects to show up in objects_with_cards_set + # new objects to show up in old_objects_with_cards_set if self.card_page_indices > 0: - if self.objects_with_cards_set.non_empty(): + if self.old_objects_with_cards_set.non_empty(): continue break # @@ -1284,7 +1270,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.objects_with_cards_set + oldlist = self.old_objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1299,7 +1285,6 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) - p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it # means that it is in 'objects_pointing_to_young' and @@ -1400,22 +1385,7 @@ # arrive here. if (bool(self.young_rawmalloced_objects) and self.young_rawmalloced_objects.contains(obj)): - # 'obj' points to a young, raw-malloced object - if (self.header(obj).tid & GCFLAG_VISITED) == 0: - self.header(obj).tid |= GCFLAG_VISITED - # - # we just made 'obj' old, so we may need to add it - # in the correct list: - if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: - # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so - # the object may contain young pointers anywhere - self.objects_pointing_to_young.append(obj) - else: - # large array case: the object contains card marks - # that tell us where young pointers are, and it - # is already in objects_with_cards_set. - ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, - "neither YOUNG_PTRS nor HAS_CARDS??") + self._visit_young_rawmalloced_object(obj) return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1468,6 +1438,47 @@ # objects when we walk 'objects_pointing_to_young'. self.objects_pointing_to_young.append(newobj) + def _visit_young_rawmalloced_object(self, obj): + # 'obj' points to a young, raw-malloced object. + # Any young rawmalloced object never seen by the code here + # will end up without GCFLAG_VISITED, and be freed at the + # end of the current minor collection. Note that there was + # a bug in which dying young arrays with card marks would + # still be scanned before being freed, keeping a lot of + # objects unnecessarily alive. + hdr = self.header(obj) + if hdr.tid & GCFLAG_VISITED: + return + hdr.tid |= GCFLAG_VISITED + # + # we just made 'obj' old, so we need to add it to the correct + # lists. (Note that another point of view on the longish + # comments below is that we are not changing any flags in 'hdr', + # but just restoring invariants: the object may be missing from + # these lists as long as it is a young array, but not when it + # grows old.) + anywhere = False + # + if hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so + # the object may contain young pointers anywhere + self.objects_pointing_to_young.append(obj) + anywhere = True + # + if hdr.tid & GCFLAG_HAS_CARDS != 0: + # large array case: the object contains card marks + # that tell us where young pointers are, and it must + # be added to 'old_objects_with_cards_set'. Note that + # we must add it even if we also added it just above to + # 'objects_pointing_to_young', because the object header + # needs to be cleaned up. + ll_assert(hdr.tid & GCFLAG_CARDS_SET != 0, + "young array: GCFLAG_HAS_CARDS without GCFLAG_CARDS_SET") + self.old_objects_with_cards_set.append(obj) + anywhere = True + # + ll_assert(anywhere, "wrong flag combination on young array") + def _malloc_out_of_nursery(self, totalsize): """Allocate non-movable memory for an object of the given @@ -1638,7 +1649,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + 1 + extra_words = self.card_marking_words_for_length(length) arena -= extra_words * WORD allocsize += extra_words * WORD # diff --git a/pypy/rpython/module/ll_os_stat.py b/pypy/rpython/module/ll_os_stat.py --- a/pypy/rpython/module/ll_os_stat.py +++ b/pypy/rpython/module/ll_os_stat.py @@ -21,7 +21,7 @@ # sub-second timestamps. # - TIMESPEC is defined when the "struct stat" contains st_atim field. -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): TIMESPEC = platform.Struct('struct timespec', [('tv_sec', rffi.TIME_T), ('tv_nsec', rffi.LONG)]) diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -226,7 +226,7 @@ eci = eci.merge(configure_boehm()) pre_include_bits = [] - if sys.platform == "linux2": + if sys.platform.startswith('linux'): pre_include_bits += ["#define _REENTRANT 1", "#define GC_LINUX_THREADS 1"] if sys.platform != "win32": diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py --- a/pypy/translator/platform/__init__.py +++ b/pypy/translator/platform/__init__.py @@ -230,7 +230,7 @@ return True -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): from pypy.translator.platform.linux import Linux, Linux64 import platform if platform.architecture()[0] == '32bit': diff --git a/pypy/translator/sandbox/sandlib.py b/pypy/translator/sandbox/sandlib.py --- a/pypy/translator/sandbox/sandlib.py +++ b/pypy/translator/sandbox/sandlib.py @@ -209,7 +209,7 @@ def handle_until_return(self): child_stdin = self.popen.stdin child_stdout = self.popen.stdout - if self.os_level_sandboxing and sys.platform.startswith('linux2'): + if self.os_level_sandboxing and sys.platform.startswith('linux'): # rationale: we wait until the child process started completely, # letting the C library do any system calls it wants for # initialization. When the RPython code starts up, it quickly diff --git a/pypy/translator/sandbox/test/test_sandbox.py b/pypy/translator/sandbox/test/test_sandbox.py --- a/pypy/translator/sandbox/test/test_sandbox.py +++ b/pypy/translator/sandbox/test/test_sandbox.py @@ -145,7 +145,7 @@ g = pipe.stdin f = pipe.stdout expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GENERATIONGC_NURSERY",), None) - if sys.platform == 'linux2': # on Mac, uses another (sandboxsafe) approach + if sys.platform.startswith('linux'): # on Mac, uses another (sandboxsafe) approach expect(f, g, "ll_os.ll_os_open", ("/proc/cpuinfo", 0, 420), OSError(5232, "xyz")) expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GC_DEBUG",), None) From noreply at buildbot.pypy.org Sun Jul 24 06:56:33 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 06:56:33 +0200 (CEST) Subject: [pypy-commit] pypy default: There is another case that is similarly buggy (it traces too much)... Message-ID: <20110724045633.C67548208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45925:4e68774de7bd Date: 2011-07-24 06:56 +0200 http://bitbucket.org/pypy/pypy/changeset/4e68774de7bd/ Log: There is another case that is similarly buggy (it traces too much)... diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -1342,6 +1342,8 @@ "objects_pointing_to_young contains obj with " "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") continue + # XXX FIXME: 'obj' might be a never-visited young array, in this + # case it should **not** be collected here!!!!!!!!! # # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should # have this flag set after a nursery collection. From noreply at buildbot.pypy.org Sun Jul 24 08:18:32 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 08:18:32 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix for the previous bug: declare that the list should be really Message-ID: <20110724061832.A1EAB8208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45926:6b4eb34c6091 Date: 2011-07-24 07:27 +0200 http://bitbucket.org/pypy/pypy/changeset/6b4eb34c6091/ Log: Fix for the previous bug: declare that the list should be really 'old_objects_pointing_to_young', i.e. only contain old objects. This is a bit costly to ensure in the write barrier, so between collections, we let young arrays be added to it "by mistake" and then clean it up at the start of the next minor collection. diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -256,12 +256,15 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - self.objects_pointing_to_young = self.AddressStack() + # Note that young array objects may (by temporary "mistake") be added + # to this list, but will be removed again at the start of the next + # minor collection. + self.old_objects_pointing_to_young = self.AddressStack() # - # Similar to 'objects_pointing_to_young', but lists objects + # Similar to 'old_objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'objects_pointing_to_young', in which case we + # and in 'old_objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. # Note also that young array objects are never listed here. self.old_objects_with_cards_set = self.AddressStack() @@ -979,12 +982,12 @@ # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object - # to the list 'objects_pointing_to_young'. We know that + # to the list 'old_objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.objects_pointing_to_young.append(addr_struct) + self.old_objects_pointing_to_young.append(addr_struct) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC @@ -1019,7 +1022,7 @@ "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") # # no cards, use default logic. Mostly copied from above. - self.objects_pointing_to_young.append(addr_array) + self.old_objects_pointing_to_young.append(addr_array) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS @@ -1100,7 +1103,7 @@ "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") # if self.appears_to_be_young(newvalue): - self.objects_pointing_to_young.append(addr_array) + self.old_objects_pointing_to_young.append(addr_array) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True @@ -1120,7 +1123,7 @@ """ objhdr = self.header(addr_struct) if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: - self.objects_pointing_to_young.append(addr_struct) + self.old_objects_pointing_to_young.append(addr_struct) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: @@ -1164,7 +1167,7 @@ # if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.objects_pointing_to_young.append(dest_addr) + self.old_objects_pointing_to_young.append(dest_addr) dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: @@ -1202,13 +1205,18 @@ # debug_start("gc-minor") # + # Before everything else, remove from 'old_objects_pointing_to_young' + # the young arrays. + if self.young_rawmalloced_objects: + self.remove_young_arrays_from_old_objects_pointing_to_young() + # # First, find the roots that point to young objects. All nursery # objects found are copied out of the nursery, and the occasional # young raw-malloced object is flagged with GCFLAG_VISITED. # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'objects_pointing_to_young'. + # 'old_objects_pointing_to_young'. self.collect_roots_in_nursery() # while True: @@ -1217,11 +1225,11 @@ if self.card_page_indices > 0: self.collect_cardrefs_to_nursery() # - # Now trace objects from 'objects_pointing_to_young'. + # Now trace objects from 'old_objects_pointing_to_young'. # All nursery objects they reference are copied out of the - # nursery, and again added to 'objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'objects_pointing_to_young' is empty. + # nursery, and again added to 'old_objects_pointing_to_young'. + # All young raw-malloced object found are flagged GCFLAG_VISITED. + # We proceed until 'old_objects_pointing_to_young' is empty. self.collect_oldrefs_to_nursery() # # We have to loop back if collect_oldrefs_to_nursery caused @@ -1262,7 +1270,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.objects_pointing_to_young. + # GcStruct is in the list self.old_objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1287,7 +1295,7 @@ p = llarena.getfakearenaaddress(obj - size_gc_header) # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it - # means that it is in 'objects_pointing_to_young' and + # means that it is in 'old_objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: @@ -1326,24 +1334,17 @@ def collect_oldrefs_to_nursery(self): - # Follow the objects_pointing_to_young list and move the + # Follow the old_objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.objects_pointing_to_young + oldlist = self.old_objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Check (somehow) that the flags are correct: we must not have - # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's - # possible that the same obj is appended twice to the list - # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out - # here. - if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: - ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, - "objects_pointing_to_young contains obj with " - "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") - continue - # XXX FIXME: 'obj' might be a never-visited young array, in this - # case it should **not** be collected here!!!!!!!!! + # Check that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0, + "old_objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS") # # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should # have this flag set after a nursery collection. @@ -1351,7 +1352,7 @@ # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'objects_pointing_to_young' as well. + # and adding them to 'old_objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1434,11 +1435,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'objects_pointing_to_young', + # Add the newobj to the list 'old_objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'objects_pointing_to_young'. - self.objects_pointing_to_young.append(newobj) + # objects when we walk 'old_objects_pointing_to_young'. + self.old_objects_pointing_to_young.append(newobj) def _visit_young_rawmalloced_object(self, obj): # 'obj' points to a young, raw-malloced object. @@ -1453,33 +1454,20 @@ return hdr.tid |= GCFLAG_VISITED # - # we just made 'obj' old, so we need to add it to the correct - # lists. (Note that another point of view on the longish - # comments below is that we are not changing any flags in 'hdr', - # but just restoring invariants: the object may be missing from - # these lists as long as it is a young array, but not when it - # grows old.) - anywhere = False + # we just made 'obj' old, so we need to add it to the correct lists + added_somewhere = False # if hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: - # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so - # the object may contain young pointers anywhere - self.objects_pointing_to_young.append(obj) - anywhere = True + self.old_objects_pointing_to_young.append(obj) + added_somewhere = True # if hdr.tid & GCFLAG_HAS_CARDS != 0: - # large array case: the object contains card marks - # that tell us where young pointers are, and it must - # be added to 'old_objects_with_cards_set'. Note that - # we must add it even if we also added it just above to - # 'objects_pointing_to_young', because the object header - # needs to be cleaned up. ll_assert(hdr.tid & GCFLAG_CARDS_SET != 0, "young array: GCFLAG_HAS_CARDS without GCFLAG_CARDS_SET") self.old_objects_with_cards_set.append(obj) - anywhere = True + added_somewhere = True # - ll_assert(anywhere, "wrong flag combination on young array") + ll_assert(added_somewhere, "wrong flag combination on young array") def _malloc_out_of_nursery(self, totalsize): @@ -1519,6 +1507,18 @@ # and survives. Otherwise, it dies. self.free_rawmalloced_object_if_unvisited(obj) + def remove_young_arrays_from_old_objects_pointing_to_young(self): + old = self.old_objects_pointing_to_young + new = self.AddressStack() + while old.non_empty(): + obj = old.pop() + if not self.young_rawmalloced_objects.contains(obj): + new.append(obj) + # an extra copy, to avoid assignments to + # 'self.old_objects_pointing_to_young' + while new.non_empty(): + old.append(new.pop()) + new.delete() # ---------- # Full collection From noreply at buildbot.pypy.org Sun Jul 24 11:39:48 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 11:39:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove a needless try:finally: that goes in the way of printing Message-ID: <20110724093948.58BF88208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45927:8a99e7cc1a06 Date: 2011-07-24 11:39 +0200 http://bitbucket.org/pypy/pypy/changeset/8a99e7cc1a06/ Log: Remove a needless try:finally: that goes in the way of printing RPython tracebacks. diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1162,12 +1162,10 @@ metainterp.jitdriver_sd.greenfield_info is not None): virtualizable_boxes = metainterp.virtualizable_boxes saved_pc = self.pc - try: if resumepc >= 0: self.pc = resumepc resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, metainterp.virtualref_boxes, resumedescr) - finally: self.pc = saved_pc def implement_guard_value(self, orgpc, box): From noreply at buildbot.pypy.org Sun Jul 24 12:12:39 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 12:12:39 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix for issue #806. Message-ID: <20110724101239.BAAAD8208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45928:c525a219909f Date: 2011-07-24 12:12 +0200 http://bitbucket.org/pypy/pypy/changeset/c525a219909f/ Log: Fix for issue #806. diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -1251,7 +1251,10 @@ def _compile(self, func): assert isinstance(func, ast.FunctionDef) # If there's a docstring, store it as the first constant. + if func.body: doc_expr = self.possible_docstring(func.body[0]) + else: + doc_expr = None if doc_expr is not None: self.add_const(doc_expr.s) start = 1 @@ -1263,6 +1266,7 @@ if args.args: self._handle_nested_args(args.args) self.argcount = len(args.args) + if func.body: for i in range(start, len(func.body)): func.body[i].walkabout(self) diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py --- a/pypy/interpreter/astcompiler/symtable.py +++ b/pypy/interpreter/astcompiler/symtable.py @@ -363,6 +363,9 @@ new_scope = FunctionScope(func.name, func.lineno, func.col_offset) self.push_scope(new_scope, func) func.args.walkabout(self) + # func.body should never be empty (or else it contains one Pass) + # but it can be if we make an ast.FunctionDef() from app-level. + if func.body: self.visit_sequence(func.body) self.pop_scope() diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -250,3 +250,19 @@ assert x.left == n1 assert x.op == addop assert x.right == n3 + + def test_functiondef(self): + import _ast as ast + fAst = ast.FunctionDef( + name="foo", + args=ast.arguments( + args=[], vararg=None, kwarg=None, defaults=[], + kwonlyargs=[], kw_defaults=[]), + body=[], decorator_list=[], lineno=5, col_offset=0) + exprAst = ast.Interactive(body=[fAst]) + compiled = compile(exprAst, "", "single") + # + d = {} + eval(compiled, d, d) + assert type(d['foo']) is type(lambda: 42) + assert d['foo']() is None From noreply at buildbot.pypy.org Sun Jul 24 12:42:48 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 12:42:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Tests prompted by issue #801 (thanks justinpeel). Message-ID: <20110724104248.92F2A8208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45929:f523aecab18f Date: 2011-07-24 12:30 +0200 http://bitbucket.org/pypy/pypy/changeset/f523aecab18f/ Log: Tests prompted by issue #801 (thanks justinpeel). diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -227,6 +227,45 @@ assert list(itertools.islice(xrange(10), None,None)) == range(10) assert list(itertools.islice(xrange(10), None,None,None)) == range(10) + def test_islice_dropitems_exact(self): + import itertools + + it = iter("abcdefghij") + itertools.islice(it, 2, 2) # doesn't eagerly drop anything + assert it.next() == "a" + itertools.islice(it, 3, 8, 2) # doesn't eagerly drop anything + assert it.next() == "b" + assert it.next() == "c" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 2, 3), None) # drops 2 items + assert x == "c" + assert it.next() == "d" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 3, 8, 2), None) # drops 3 items + assert x == "d" + assert it.next() == "e" + + it = iter("abcdefghij") + x = next(itertools.islice(it, None, 8), None) # drops 0 items + assert x == "a" + assert it.next() == "b" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 3, 2), None) # drops 3 items + assert x is None + assert it.next() == "d" + + it = iter("abcdefghij") + islc = itertools.islice(it, 3, 7, 2) + assert islc.next() == "d" # drops 0, 1, 2, returns item #3 + assert it.next() == "e" + assert islc.next() == "g" # drops the 4th and return item #5 + assert it.next() == "h" + raises(StopIteration, islc.next) # drops the 6th and raise + assert it.next() == "j" + def test_islice_overflow(self): import itertools import sys From noreply at buildbot.pypy.org Sun Jul 24 12:42:49 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 12:42:49 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix for f523aecab18f, and rewrite to move the loop in a subfunction Message-ID: <20110724104249.C9CAA8208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45930:b06b8d4e38c5 Date: 2011-07-24 12:42 +0200 http://bitbucket.org/pypy/pypy/changeset/b06b8d4e38c5/ Log: Fix for f523aecab18f, and rewrite to move the loop in a subfunction that is not called at all if step==1. diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -379,16 +379,23 @@ self.start = -1 else: # all following calls consume = self.step + if consume > 1: + self._ignore_items(consume-1) if self.stop >= 0: if self.stop < consume: + self.stop = 0 # reset the state so that a following next_w() + self.step = 1 # has no effect any more raise OperationError(self.space.w_StopIteration, self.space.w_None) self.stop -= consume + return self.space.next(self.iterable) + + def _ignore_items(self, num): while True: - w_obj = self.space.next(self.iterable) - consume -= 1 - if consume <= 0: - return w_obj + self.space.next(self.iterable) + num -= 1 + if num <= 0: + break def W_ISlice___new__(space, w_subtype, w_iterable, w_startstop, args_w): r = space.allocate_instance(W_ISlice, w_subtype) From noreply at buildbot.pypy.org Sun Jul 24 13:02:59 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 13:02:59 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and fix. Thanks Trundle for the test. The fix is done in Message-ID: <20110724110259.9D5A48208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45931:97ce6ad3bd73 Date: 2011-07-24 13:03 +0200 http://bitbucket.org/pypy/pypy/changeset/97ce6ad3bd73/ Log: Test and fix. Thanks Trundle for the test. The fix is done in error.py instead, by calling exception_is_valid_class_w() after calling exception_getclass(), as was already done in one place. diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -189,7 +189,7 @@ if space.is_w(w_value, space.w_None): # raise Type: we assume we have to instantiate Type w_value = space.call_function(w_type) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: w_valuetype = space.exception_getclass(w_value) if space.exception_issubclass_w(w_valuetype, w_type): @@ -204,18 +204,12 @@ else: # raise Type, X: assume X is the constructor argument w_value = space.call_function(w_type, w_value) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: # the only case left here is (inst, None), from a 'raise inst'. w_inst = w_type - w_instclass = space.exception_getclass(w_inst) - if not space.exception_is_valid_class_w(w_instclass): - instclassname = w_instclass.getname(space) - msg = ("exceptions must be old-style classes or derived " - "from BaseException, not %s") - raise operationerrfmt(space.w_TypeError, msg, instclassname) - + w_instclass = self._exception_getclass(space, w_inst) if not space.is_w(w_value, space.w_None): raise OperationError(space.w_TypeError, space.wrap("instance exception may not " @@ -226,6 +220,15 @@ self.w_type = w_type self._w_value = w_value + def _exception_getclass(self, space, w_inst): + w_type = space.exception_getclass(w_inst) + if not space.exception_is_valid_class_w(w_type): + typename = w_type.getname(space) + msg = ("exceptions must be old-style classes or derived " + "from BaseException, not %s") + raise operationerrfmt(space.w_TypeError, msg, typename) + return w_type + def write_unraisable(self, space, where, w_object=None): if w_object is None: objrepr = '' diff --git a/pypy/interpreter/test/test_raise.py b/pypy/interpreter/test/test_raise.py --- a/pypy/interpreter/test/test_raise.py +++ b/pypy/interpreter/test/test_raise.py @@ -274,3 +274,9 @@ pass except A: pass + + def test_new_returns_bad_instance(self): + class MyException(Exception): + def __new__(cls, *args): + return object() + raises(TypeError, "raise MyException") From noreply at buildbot.pypy.org Sun Jul 24 13:39:38 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 13:39:38 +0200 (CEST) Subject: [pypy-commit] pypy default: Change the interface of deldictvalue() to take an unwrapped Message-ID: <20110724113938.E6F8D8208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45932:24ff93f071a4 Date: 2011-07-24 13:26 +0200 http://bitbucket.org/pypy/pypy/changeset/24ff93f071a4/ Log: Change the interface of deldictvalue() to take an unwrapped attribute name, like getdictvalue() and setdictvalue(). Just for unification purposes. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -44,11 +44,11 @@ return True return False - def deldictvalue(self, space, w_name): + def deldictvalue(self, space, attr): w_dict = self.getdict(space) if w_dict is not None: try: - space.delitem(w_dict, w_name) + space.delitem(w_dict, space.wrap(attr)) return True except OperationError, ex: if not ex.match(space, space.w_KeyError): diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -418,7 +418,7 @@ if w_meth is not None: space.call_function(w_meth, w_name) else: - if not self.deldictvalue(space, w_name): + if not self.deldictvalue(space, name): raise operationerrfmt( space.w_AttributeError, "%s instance has no attribute '%s'", diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -96,7 +96,7 @@ if space.is_data_descr(w_descr): space.delete(w_descr, w_obj) return - if w_obj.deldictvalue(space, w_name): + if w_obj.deldictvalue(space, name): return raiseattrerror(space, w_obj, name, w_descr) diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -61,7 +61,8 @@ space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): + key = self.space.str_w(w_key) + if not self.unerase(w_dict.dstorage).deldictvalue(space, key): raise KeyError else: raise KeyError diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -369,8 +369,7 @@ def setdictvalue(self, space, attrname, w_value): return self._get_mapdict_map().write(self, (attrname, DICT), w_value) - def deldictvalue(self, space, w_name): - attrname = space.str_w(w_name) + def deldictvalue(self, space, attrname): new_obj = self._get_mapdict_map().delete(self, (attrname, DICT)) if new_obj is None: return False @@ -647,7 +646,8 @@ w_key_type = space.type(w_key) w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = w_obj.deldictvalue(space, w_key) + key = self.space.str_w(w_key) + flag = w_obj.deldictvalue(space, key) if not flag: raise KeyError elif _never_equal_to_string(space, w_key_type): diff --git a/pypy/objspace/std/proxyobject.py b/pypy/objspace/std/proxyobject.py --- a/pypy/objspace/std/proxyobject.py +++ b/pypy/objspace/std/proxyobject.py @@ -52,10 +52,10 @@ raise return False - def deldictvalue(self, space, w_attr): + def deldictvalue(self, space, attr): try: space.call_function(self.w_controller, space.wrap('__delattr__'), - w_attr) + space.wrap(attr)) return True except OperationError, e: if not e.match(space, space.w_AttributeError): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -313,10 +313,9 @@ w_self.dict_w[name] = w_value return True - def deldictvalue(w_self, space, w_key): + def deldictvalue(w_self, space, key): if w_self.lazyloaders: w_self._freeze_() # force un-lazification - key = space.str_w(w_key) if (not space.config.objspace.std.mutable_builtintypes and not w_self.is_heaptype()): msg = "can't delete attributes on type object '%s'" diff --git a/pypy/objspace/std/typetype.py b/pypy/objspace/std/typetype.py --- a/pypy/objspace/std/typetype.py +++ b/pypy/objspace/std/typetype.py @@ -226,7 +226,7 @@ def descr_del___abstractmethods__(space, w_type): w_type = _check(space, w_type) - if not w_type.deldictvalue(space, space.wrap("__abstractmethods__")): + if not w_type.deldictvalue(space, "__abstractmethods__"): raise OperationError(space.w_AttributeError, space.wrap("__abstractmethods__")) w_type.set_abstract(False) From noreply at buildbot.pypy.org Sun Jul 24 13:39:40 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 13:39:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and fix for issue #804 (thanks albert). Message-ID: <20110724113940.40BF4829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45933:e6712f5d73d8 Date: 2011-07-24 13:39 +0200 http://bitbucket.org/pypy/pypy/changeset/e6712f5d73d8/ Log: Test and fix for issue #804 (thanks albert). Regenerated ast.py. diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -3069,6 +3069,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 _Expression_field_unroller = unrolling_iterable(['body']) @@ -3157,6 +3158,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def stmt_get_col_offset(space, w_self): @@ -3178,6 +3180,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask stmt.typedef = typedef.TypeDef("stmt", @@ -3208,6 +3211,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def FunctionDef_get_args(space, w_self): @@ -3229,6 +3233,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 2 def FunctionDef_get_body(space, w_self): @@ -3315,6 +3320,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def ClassDef_get_bases(space, w_self): @@ -3420,6 +3426,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Return_field_unroller = unrolling_iterable(['value']) @@ -3526,6 +3533,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _Assign_field_unroller = unrolling_iterable(['targets', 'value']) @@ -3573,6 +3581,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def AugAssign_get_op(space, w_self): @@ -3590,13 +3599,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def AugAssign_get_value(space, w_self): @@ -3618,6 +3627,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 4 _AugAssign_field_unroller = unrolling_iterable(['target', 'op', 'value']) @@ -3665,6 +3675,7 @@ raise w_self.setdictvalue(space, 'dest', w_new_value) return + w_self.deldictvalue(space, 'dest') w_self.initialization_state |= 1 def Print_get_values(space, w_self): @@ -3704,6 +3715,7 @@ raise w_self.setdictvalue(space, 'nl', w_new_value) return + w_self.deldictvalue(space, 'nl') w_self.initialization_state |= 4 _Print_field_unroller = unrolling_iterable(['dest', 'values', 'nl']) @@ -3752,6 +3764,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def For_get_iter(space, w_self): @@ -3773,6 +3786,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def For_get_body(space, w_self): @@ -3859,6 +3873,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def While_get_body(space, w_self): @@ -3944,6 +3959,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def If_get_body(space, w_self): @@ -4029,6 +4045,7 @@ raise w_self.setdictvalue(space, 'context_expr', w_new_value) return + w_self.deldictvalue(space, 'context_expr') w_self.initialization_state |= 1 def With_get_optional_vars(space, w_self): @@ -4050,6 +4067,7 @@ raise w_self.setdictvalue(space, 'optional_vars', w_new_value) return + w_self.deldictvalue(space, 'optional_vars') w_self.initialization_state |= 2 def With_get_body(space, w_self): @@ -4116,6 +4134,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def Raise_get_inst(space, w_self): @@ -4137,6 +4156,7 @@ raise w_self.setdictvalue(space, 'inst', w_new_value) return + w_self.deldictvalue(space, 'inst') w_self.initialization_state |= 2 def Raise_get_tback(space, w_self): @@ -4158,6 +4178,7 @@ raise w_self.setdictvalue(space, 'tback', w_new_value) return + w_self.deldictvalue(space, 'tback') w_self.initialization_state |= 4 _Raise_field_unroller = unrolling_iterable(['type', 'inst', 'tback']) @@ -4351,6 +4372,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def Assert_get_msg(space, w_self): @@ -4372,6 +4394,7 @@ raise w_self.setdictvalue(space, 'msg', w_new_value) return + w_self.deldictvalue(space, 'msg') w_self.initialization_state |= 2 _Assert_field_unroller = unrolling_iterable(['test', 'msg']) @@ -4464,6 +4487,7 @@ raise w_self.setdictvalue(space, 'module', w_new_value) return + w_self.deldictvalue(space, 'module') w_self.initialization_state |= 1 def ImportFrom_get_names(space, w_self): @@ -4503,6 +4527,7 @@ raise w_self.setdictvalue(space, 'level', w_new_value) return + w_self.deldictvalue(space, 'level') w_self.initialization_state |= 4 _ImportFrom_field_unroller = unrolling_iterable(['module', 'names', 'level']) @@ -4551,6 +4576,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 def Exec_get_globals(space, w_self): @@ -4572,6 +4598,7 @@ raise w_self.setdictvalue(space, 'globals', w_new_value) return + w_self.deldictvalue(space, 'globals') w_self.initialization_state |= 2 def Exec_get_locals(space, w_self): @@ -4593,6 +4620,7 @@ raise w_self.setdictvalue(space, 'locals', w_new_value) return + w_self.deldictvalue(space, 'locals') w_self.initialization_state |= 4 _Exec_field_unroller = unrolling_iterable(['body', 'globals', 'locals']) @@ -4683,6 +4711,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Expr_field_unroller = unrolling_iterable(['value']) @@ -4779,6 +4808,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def expr_get_col_offset(space, w_self): @@ -4800,6 +4830,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask expr.typedef = typedef.TypeDef("expr", @@ -4826,13 +4857,13 @@ try: obj = space.interp_w(boolop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def BoolOp_get_values(space, w_self): @@ -4898,6 +4929,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def BinOp_get_op(space, w_self): @@ -4915,13 +4947,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def BinOp_get_right(space, w_self): @@ -4943,6 +4975,7 @@ raise w_self.setdictvalue(space, 'right', w_new_value) return + w_self.deldictvalue(space, 'right') w_self.initialization_state |= 4 _BinOp_field_unroller = unrolling_iterable(['left', 'op', 'right']) @@ -4986,13 +5019,13 @@ try: obj = space.interp_w(unaryop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def UnaryOp_get_operand(space, w_self): @@ -5014,6 +5047,7 @@ raise w_self.setdictvalue(space, 'operand', w_new_value) return + w_self.deldictvalue(space, 'operand') w_self.initialization_state |= 2 _UnaryOp_field_unroller = unrolling_iterable(['op', 'operand']) @@ -5060,6 +5094,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 1 def Lambda_get_body(space, w_self): @@ -5081,6 +5116,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 _Lambda_field_unroller = unrolling_iterable(['args', 'body']) @@ -5127,6 +5163,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def IfExp_get_body(space, w_self): @@ -5148,6 +5185,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 def IfExp_get_orelse(space, w_self): @@ -5169,6 +5207,7 @@ raise w_self.setdictvalue(space, 'orelse', w_new_value) return + w_self.deldictvalue(space, 'orelse') w_self.initialization_state |= 4 _IfExp_field_unroller = unrolling_iterable(['test', 'body', 'orelse']) @@ -5322,6 +5361,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def ListComp_get_generators(space, w_self): @@ -5387,6 +5427,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def SetComp_get_generators(space, w_self): @@ -5452,6 +5493,7 @@ raise w_self.setdictvalue(space, 'key', w_new_value) return + w_self.deldictvalue(space, 'key') w_self.initialization_state |= 1 def DictComp_get_value(space, w_self): @@ -5473,6 +5515,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 def DictComp_get_generators(space, w_self): @@ -5539,6 +5582,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def GeneratorExp_get_generators(space, w_self): @@ -5604,6 +5648,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Yield_field_unroller = unrolling_iterable(['value']) @@ -5649,6 +5694,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def Compare_get_ops(space, w_self): @@ -5734,6 +5780,7 @@ raise w_self.setdictvalue(space, 'func', w_new_value) return + w_self.deldictvalue(space, 'func') w_self.initialization_state |= 1 def Call_get_args(space, w_self): @@ -5791,6 +5838,7 @@ raise w_self.setdictvalue(space, 'starargs', w_new_value) return + w_self.deldictvalue(space, 'starargs') w_self.initialization_state |= 8 def Call_get_kwargs(space, w_self): @@ -5812,6 +5860,7 @@ raise w_self.setdictvalue(space, 'kwargs', w_new_value) return + w_self.deldictvalue(space, 'kwargs') w_self.initialization_state |= 16 _Call_field_unroller = unrolling_iterable(['func', 'args', 'keywords', 'starargs', 'kwargs']) @@ -5863,6 +5912,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Repr_field_unroller = unrolling_iterable(['value']) @@ -5908,6 +5958,7 @@ raise w_self.setdictvalue(space, 'n', w_new_value) return + w_self.deldictvalue(space, 'n') w_self.initialization_state |= 1 _Num_field_unroller = unrolling_iterable(['n']) @@ -5953,6 +6004,7 @@ raise w_self.setdictvalue(space, 's', w_new_value) return + w_self.deldictvalue(space, 's') w_self.initialization_state |= 1 _Str_field_unroller = unrolling_iterable(['s']) @@ -5998,6 +6050,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Attribute_get_attr(space, w_self): @@ -6019,6 +6072,7 @@ raise w_self.setdictvalue(space, 'attr', w_new_value) return + w_self.deldictvalue(space, 'attr') w_self.initialization_state |= 2 def Attribute_get_ctx(space, w_self): @@ -6036,13 +6090,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Attribute_field_unroller = unrolling_iterable(['value', 'attr', 'ctx']) @@ -6090,6 +6144,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Subscript_get_slice(space, w_self): @@ -6111,6 +6166,7 @@ raise w_self.setdictvalue(space, 'slice', w_new_value) return + w_self.deldictvalue(space, 'slice') w_self.initialization_state |= 2 def Subscript_get_ctx(space, w_self): @@ -6128,13 +6184,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Subscript_field_unroller = unrolling_iterable(['value', 'slice', 'ctx']) @@ -6182,6 +6238,7 @@ raise w_self.setdictvalue(space, 'id', w_new_value) return + w_self.deldictvalue(space, 'id') w_self.initialization_state |= 1 def Name_get_ctx(space, w_self): @@ -6199,13 +6256,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Name_field_unroller = unrolling_iterable(['id', 'ctx']) @@ -6266,13 +6323,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _List_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6334,13 +6391,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Tuple_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6388,6 +6445,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Const_field_unroller = unrolling_iterable(['value']) @@ -6506,6 +6564,7 @@ raise w_self.setdictvalue(space, 'lower', w_new_value) return + w_self.deldictvalue(space, 'lower') w_self.initialization_state |= 1 def Slice_get_upper(space, w_self): @@ -6527,6 +6586,7 @@ raise w_self.setdictvalue(space, 'upper', w_new_value) return + w_self.deldictvalue(space, 'upper') w_self.initialization_state |= 2 def Slice_get_step(space, w_self): @@ -6548,6 +6608,7 @@ raise w_self.setdictvalue(space, 'step', w_new_value) return + w_self.deldictvalue(space, 'step') w_self.initialization_state |= 4 _Slice_field_unroller = unrolling_iterable(['lower', 'upper', 'step']) @@ -6638,6 +6699,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Index_field_unroller = unrolling_iterable(['value']) @@ -6907,6 +6969,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def comprehension_get_iter(space, w_self): @@ -6928,6 +6991,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def comprehension_get_ifs(space, w_self): @@ -6994,6 +7058,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def excepthandler_get_col_offset(space, w_self): @@ -7015,6 +7080,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask excepthandler.typedef = typedef.TypeDef("excepthandler", @@ -7045,6 +7111,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def ExceptHandler_get_name(space, w_self): @@ -7066,6 +7133,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 2 def ExceptHandler_get_body(space, w_self): @@ -7153,6 +7221,7 @@ raise w_self.setdictvalue(space, 'vararg', w_new_value) return + w_self.deldictvalue(space, 'vararg') w_self.initialization_state |= 2 def arguments_get_kwarg(space, w_self): @@ -7177,6 +7246,7 @@ raise w_self.setdictvalue(space, 'kwarg', w_new_value) return + w_self.deldictvalue(space, 'kwarg') w_self.initialization_state |= 4 def arguments_get_defaults(space, w_self): @@ -7245,6 +7315,7 @@ raise w_self.setdictvalue(space, 'arg', w_new_value) return + w_self.deldictvalue(space, 'arg') w_self.initialization_state |= 1 def keyword_get_value(space, w_self): @@ -7266,6 +7337,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _keyword_field_unroller = unrolling_iterable(['arg', 'value']) @@ -7312,6 +7384,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def alias_get_asname(space, w_self): @@ -7336,6 +7409,7 @@ raise w_self.setdictvalue(space, 'asname', w_new_value) return + w_self.deldictvalue(space, 'asname') w_self.initialization_state |= 2 _alias_field_unroller = unrolling_iterable(['name', 'asname']) diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -446,6 +446,7 @@ if field.seq: self.emit("w_self.w_%s = w_new_value" % (field.name,), 1) else: + save_original_object = False self.emit("try:", 1) if field.type.value not in asdl.builtin_types: # These are always other AST nodes. @@ -454,9 +455,7 @@ (field.type,), 2) self.emit("w_self.%s = obj.to_simple_int(space)" % (field.name,), 2) - self.emit("# need to save the original object too", 2) - self.emit("w_self.setdictvalue(space, '%s', w_new_value)" - % (field.name,), 2) + save_original_object = True else: config = (field.name, field.type, repr(field.opt)) self.emit("w_self.%s = space.interp_w(%s, w_new_value, %s)" % @@ -480,6 +479,12 @@ self.emit(" w_self.setdictvalue(space, '%s', w_new_value)" % (field.name,), 1) self.emit(" return", 1) + if save_original_object: + self.emit("# need to save the original object too", 1) + self.emit("w_self.setdictvalue(space, '%s', w_new_value)" + % (field.name,), 1) + else: + self.emit("w_self.deldictvalue(space, '%s')" %(field.name,), 1) self.emit("w_self.initialization_state |= %s" % (flag,), 1) self.emit("") diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -266,3 +266,11 @@ eval(compiled, d, d) assert type(d['foo']) is type(lambda: 42) assert d['foo']() is None + + def test_missing_name(self): + import _ast as ast + n = ast.FunctionDef(name=None) + n.name = "foo" + n.name = "foo" + n.name = "foo" + assert n.name == "foo" From noreply at buildbot.pypy.org Sun Jul 24 13:56:02 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 13:56:02 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix issue 793 (thanks mistuhiko). Generally allow visit_sequence() Message-ID: <20110724115602.508BC8208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45934:4d416d3a6e38 Date: 2011-07-24 13:56 +0200 http://bitbucket.org/pypy/pypy/changeset/4d416d3a6e38/ Log: Fix issue 793 (thanks mistuhiko). Generally allow visit_sequence() to be called on None. diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -2541,6 +2541,7 @@ class ASTVisitor(object): def visit_sequence(self, seq): + if seq is not None: for node in seq: node.walkabout(self) @@ -2673,33 +2674,25 @@ class GenericASTVisitor(ASTVisitor): def visit_Module(self, node): - if node.body: self.visit_sequence(node.body) def visit_Interactive(self, node): - if node.body: self.visit_sequence(node.body) def visit_Expression(self, node): node.body.walkabout(self) def visit_Suite(self, node): - if node.body: self.visit_sequence(node.body) def visit_FunctionDef(self, node): node.args.walkabout(self) - if node.body: self.visit_sequence(node.body) - if node.decorator_list: self.visit_sequence(node.decorator_list) def visit_ClassDef(self, node): - if node.bases: self.visit_sequence(node.bases) - if node.body: self.visit_sequence(node.body) - if node.decorator_list: self.visit_sequence(node.decorator_list) def visit_Return(self, node): @@ -2707,11 +2700,9 @@ node.value.walkabout(self) def visit_Delete(self, node): - if node.targets: self.visit_sequence(node.targets) def visit_Assign(self, node): - if node.targets: self.visit_sequence(node.targets) node.value.walkabout(self) @@ -2722,36 +2713,28 @@ def visit_Print(self, node): if node.dest: node.dest.walkabout(self) - if node.values: self.visit_sequence(node.values) def visit_For(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.body: self.visit_sequence(node.body) - if node.orelse: self.visit_sequence(node.orelse) def visit_While(self, node): node.test.walkabout(self) - if node.body: self.visit_sequence(node.body) - if node.orelse: self.visit_sequence(node.orelse) def visit_If(self, node): node.test.walkabout(self) - if node.body: self.visit_sequence(node.body) - if node.orelse: self.visit_sequence(node.orelse) def visit_With(self, node): node.context_expr.walkabout(self) if node.optional_vars: node.optional_vars.walkabout(self) - if node.body: self.visit_sequence(node.body) def visit_Raise(self, node): @@ -2763,17 +2746,12 @@ node.tback.walkabout(self) def visit_TryExcept(self, node): - if node.body: self.visit_sequence(node.body) - if node.handlers: self.visit_sequence(node.handlers) - if node.orelse: self.visit_sequence(node.orelse) def visit_TryFinally(self, node): - if node.body: self.visit_sequence(node.body) - if node.finalbody: self.visit_sequence(node.finalbody) def visit_Assert(self, node): @@ -2782,11 +2760,9 @@ node.msg.walkabout(self) def visit_Import(self, node): - if node.names: self.visit_sequence(node.names) def visit_ImportFrom(self, node): - if node.names: self.visit_sequence(node.names) def visit_Exec(self, node): @@ -2812,7 +2788,6 @@ pass def visit_BoolOp(self, node): - if node.values: self.visit_sequence(node.values) def visit_BinOp(self, node): @@ -2832,34 +2807,27 @@ node.orelse.walkabout(self) def visit_Dict(self, node): - if node.keys: self.visit_sequence(node.keys) - if node.values: self.visit_sequence(node.values) def visit_Set(self, node): - if node.elts: self.visit_sequence(node.elts) def visit_ListComp(self, node): node.elt.walkabout(self) - if node.generators: self.visit_sequence(node.generators) def visit_SetComp(self, node): node.elt.walkabout(self) - if node.generators: self.visit_sequence(node.generators) def visit_DictComp(self, node): node.key.walkabout(self) node.value.walkabout(self) - if node.generators: self.visit_sequence(node.generators) def visit_GeneratorExp(self, node): node.elt.walkabout(self) - if node.generators: self.visit_sequence(node.generators) def visit_Yield(self, node): @@ -2868,14 +2836,11 @@ def visit_Compare(self, node): node.left.walkabout(self) - if node.comparators: self.visit_sequence(node.comparators) def visit_Call(self, node): node.func.walkabout(self) - if node.args: self.visit_sequence(node.args) - if node.keywords: self.visit_sequence(node.keywords) if node.starargs: node.starargs.walkabout(self) @@ -2902,11 +2867,9 @@ pass def visit_List(self, node): - if node.elts: self.visit_sequence(node.elts) def visit_Tuple(self, node): - if node.elts: self.visit_sequence(node.elts) def visit_Const(self, node): @@ -2924,7 +2887,6 @@ node.step.walkabout(self) def visit_ExtSlice(self, node): - if node.dims: self.visit_sequence(node.dims) def visit_Index(self, node): @@ -2933,7 +2895,6 @@ def visit_comprehension(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.ifs: self.visit_sequence(node.ifs) def visit_ExceptHandler(self, node): @@ -2941,13 +2902,10 @@ node.type.walkabout(self) if node.name: node.name.walkabout(self) - if node.body: self.visit_sequence(node.body) def visit_arguments(self, node): - if node.args: self.visit_sequence(node.args) - if node.defaults: self.visit_sequence(node.defaults) def visit_keyword(self, node): diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -295,15 +295,11 @@ def visit_FunctionDef(self, func): self.update_position(func.lineno, True) # Load decorators first, but apply them after the function is created. - if func.decorator_list: self.visit_sequence(func.decorator_list) args = func.args assert isinstance(args, ast.arguments) - if args.defaults: self.visit_sequence(args.defaults) - num_defaults = len(args.defaults) - else: - num_defaults = 0 + num_defaults = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(FunctionCodeGenerator, func.name, func, func.lineno) self._make_function(code, num_defaults) @@ -317,24 +313,17 @@ self.update_position(lam.lineno) args = lam.args assert isinstance(args, ast.arguments) - if args.defaults: self.visit_sequence(args.defaults) - default_count = len(args.defaults) - else: - default_count = 0 + default_count = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(LambdaCodeGenerator, "", lam, lam.lineno) self._make_function(code, default_count) def visit_ClassDef(self, cls): self.update_position(cls.lineno, True) - if cls.decorator_list: self.visit_sequence(cls.decorator_list) self.load_const(self.space.wrap(cls.name)) - if cls.bases: - bases_count = len(cls.bases) self.visit_sequence(cls.bases) - else: - bases_count = 0 + bases_count = len(cls.bases) if cls.bases is not None else 0 self.emit_op_arg(ops.BUILD_TUPLE, bases_count) code = self.sub_scope(ClassCodeGenerator, cls.name, cls, cls.lineno) self._make_function(code, 0) @@ -446,7 +435,6 @@ end = self.new_block() test_constant = if_.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if if_.orelse: self.visit_sequence(if_.orelse) elif test_constant == optimize.CONST_TRUE: self.visit_sequence(if_.body) @@ -515,7 +503,6 @@ self.use_next_block(cleanup) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, start) - if fr.orelse: self.visit_sequence(fr.orelse) self.use_next_block(end) @@ -523,7 +510,6 @@ self.update_position(wh.lineno, True) test_constant = wh.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if wh.orelse: self.visit_sequence(wh.orelse) else: end = self.new_block() @@ -544,7 +530,6 @@ self.use_next_block(anchor) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, loop) - if wh.orelse: self.visit_sequence(wh.orelse) self.use_next_block(end) @@ -581,7 +566,6 @@ self.use_next_block(next_except) self.emit_op(ops.END_FINALLY) self.use_next_block(otherwise) - if te.orelse: self.visit_sequence(te.orelse) self.use_next_block(end) @@ -893,26 +877,18 @@ def visit_Tuple(self, tup): self.update_position(tup.lineno) - if tup.elts: - elt_count = len(tup.elts) - else: - elt_count = 0 + elt_count = len(tup.elts) if tup.elts is not None else 0 if tup.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: self.visit_sequence(tup.elts) if tup.ctx == ast.Load: self.emit_op_arg(ops.BUILD_TUPLE, elt_count) def visit_List(self, l): self.update_position(l.lineno) - if l.elts: - elt_count = len(l.elts) - else: - elt_count = 0 + elt_count = len(l.elts) if l.elts is not None else 0 if l.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: self.visit_sequence(l.elts) if l.ctx == ast.Load: self.emit_op_arg(ops.BUILD_LIST, elt_count) @@ -944,10 +920,8 @@ if self._optimize_method_call(call): return call.func.walkabout(self) - arg = 0 + arg = len(call.args) if call.args is not None else 0 call_type = 0 - if call.args: - arg = len(call.args) self.visit_sequence(call.args) if call.keywords: self.visit_sequence(call.keywords) @@ -984,16 +958,10 @@ assert isinstance(attr_lookup, ast.Attribute) attr_lookup.value.walkabout(self) self.emit_op_name(ops.LOOKUP_METHOD, self.names, attr_lookup.attr) - if call.args: self.visit_sequence(call.args) - arg_count = len(call.args) - else: - arg_count = 0 - if call.keywords: + arg_count = len(call.args) if call.args is not None else 0 self.visit_sequence(call.keywords) - kwarg_count = len(call.keywords) - else: - kwarg_count = 0 + kwarg_count = len(call.keywords) if call.keywords is not None else 0 self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) | arg_count) return True diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py --- a/pypy/interpreter/astcompiler/symtable.py +++ b/pypy/interpreter/astcompiler/symtable.py @@ -356,16 +356,11 @@ # Function defaults and decorators happen in the outer scope. args = func.args assert isinstance(args, ast.arguments) - if args.defaults: self.visit_sequence(args.defaults) - if func.decorator_list: self.visit_sequence(func.decorator_list) new_scope = FunctionScope(func.name, func.lineno, func.col_offset) self.push_scope(new_scope, func) func.args.walkabout(self) - # func.body should never be empty (or else it contains one Pass) - # but it can be if we make an ast.FunctionDef() from app-level. - if func.body: self.visit_sequence(func.body) self.pop_scope() @@ -375,9 +370,7 @@ def visit_ClassDef(self, clsdef): self.note_symbol(clsdef.name, SYM_ASSIGNED) - if clsdef.bases: self.visit_sequence(clsdef.bases) - if clsdef.decorator_list: self.visit_sequence(clsdef.decorator_list) self.push_scope(ClassScope(clsdef), clsdef) self.visit_sequence(clsdef.body) @@ -434,7 +427,6 @@ def visit_Lambda(self, lamb): args = lamb.args assert isinstance(args, ast.arguments) - if args.defaults: self.visit_sequence(args.defaults) new_scope = FunctionScope("lambda", lamb.lineno, lamb.col_offset) self.push_scope(new_scope, lamb) @@ -450,7 +442,6 @@ self.push_scope(new_scope, node) self.implicit_arg(0) outer.target.walkabout(self) - if outer.ifs: self.visit_sequence(outer.ifs) self.visit_sequence(comps[1:]) for item in list(consider): diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -221,8 +221,9 @@ self.emit("class ASTVisitor(object):") self.emit("") self.emit("def visit_sequence(self, seq):", 1) - self.emit("for node in seq:", 2) - self.emit("node.walkabout(self)", 3) + self.emit("if seq is not None:", 2) + self.emit("for node in seq:", 3) + self.emit("node.walkabout(self)", 4) self.emit("") self.emit("def default_visitor(self, node):", 1) self.emit("raise NodeVisitorNotImplemented", 2) @@ -280,15 +281,13 @@ def visitField(self, field): if field.type.value not in asdl.builtin_types and \ field.type.value not in self.data.simple_types: - if field.seq or field.opt: + level = 2 + template = "node.%s.walkabout(self)" + if field.seq: + template = "self.visit_sequence(node.%s)" + elif field.opt: self.emit("if node.%s:" % (field.name,), 2) level = 3 - else: - level = 2 - if field.seq: - template = "self.visit_sequence(node.%s)" - else: - template = "node.%s.walkabout(self)" self.emit(template % (field.name,), level) return True return False diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -274,3 +274,14 @@ n.name = "foo" n.name = "foo" assert n.name == "foo" + + def test_issue793(self): + import _ast as ast + body = ast.Module([ + ast.TryExcept([ast.Pass(lineno=2, col_offset=4)], + [ast.ExceptHandler(ast.Name('Exception', ast.Load(), + lineno=3, col_offset=0), + None, [], lineno=4, col_offset=0)], + [], lineno=1, col_offset=0) + ]) + exec compile(body, '', 'exec') From noreply at buildbot.pypy.org Sun Jul 24 14:24:12 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 14:24:12 +0200 (CEST) Subject: [pypy-commit] pypy default: Issue #781: improve the error message. Message-ID: <20110724122412.E06548208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45935:ea1d8b0f01bd Date: 2011-07-24 14:23 +0200 http://bitbucket.org/pypy/pypy/changeset/ea1d8b0f01bd/ Log: Issue #781: improve the error message. diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -905,16 +905,15 @@ def SETUP_WITH(self, offsettoend, next_instr): w_manager = self.peekvalue() + w_enter = self.space.lookup(w_manager, "__enter__") w_descr = self.space.lookup(w_manager, "__exit__") - if w_descr is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__exit__")) + if w_enter is None or w_descr is None: + typename = self.space.type(w_manager).getname(self.space) + raise operationerrfmt(self.space.w_AttributeError, + "'%s' object is not a context manager" + " (no __enter__/__exit__ method)", typename) w_exit = self.space.get(w_descr, w_manager) self.settopvalue(w_exit) - w_enter = self.space.lookup(w_manager, "__enter__") - if w_enter is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__enter__")) w_result = self.space.get_and_call_function(w_enter, w_manager) block = WithBlock(self, next_instr + offsettoend) self.append_block(block) From notifications-noreply at bitbucket.org Sun Jul 24 15:04:37 2011 From: notifications-noreply at bitbucket.org (Bitbucket) Date: Sun, 24 Jul 2011 13:04:37 -0000 Subject: [pypy-commit] Notification: pypy Message-ID: <20110724130437.15757.26023@bitbucket03.managed.contegix.com> You have received a notification from cgerum. Hi, I forked pypy. My fork is at https://bitbucket.org/cgerum/pypy. -- Change your notification settings at https://bitbucket.org/account/notifications/ From noreply at buildbot.pypy.org Sun Jul 24 15:58:36 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 15:58:36 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: Update jit.txt. Message-ID: <20110724135836.E27C98208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r3839:9260da9d884b Date: 2011-07-24 15:58 +0200 http://bitbucket.org/pypy/extradoc/changeset/9260da9d884b/ Log: Update jit.txt. diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -1,3 +1,5 @@ +tasks with "(( ))" around them are unlikely. + BUGS ---- @@ -8,18 +10,15 @@ [arigo] - cpython has sys._current_frames(), but not pypy; however relying on this looks like it's not the job of the jit +* fix the cases of MemoryError during the execution of machine code + (they are now a fatal RPython error) + + NEW TASKS --------- -- think about whether W_TypeObject._pure_lookup_where_with_method_cache needs a - different decorator, because it cannot be moved around arbitrarily. - - have benchmarks for jit compile time and jit memory usage -- kill GUARD_(NO)_EXCEPTION; replace that by LAST_EXC_VALUE to load the - current exception from the struct in memory, followed by a regular - GUARD_CLASS. (Armin: Look like a simplification, but it's a bit messy too) - - maybe refactor a bit the x86 backend, particularly the register allocation @@ -27,17 +26,8 @@ is a compile time constant (and call unrolled version of string formatting loop in this case). -- generators?? - - consider how much old style classes in stdlib hurt us. -- support raw mallocs - -- support casting from Signed to an opaque pointer - -- local imports should be jitted more efficiently, right now they produce a - long trace and they are rather common (e.g. in translate.py) - - the integer range analysis cannot deal with int_between, because it is lowered to uint arithmetic too early @@ -47,7 +37,7 @@ re.search("(ab)+", "a" * 1000 + "b") almost doesn't get compiled and gets very modest speedups with the JIT on (10-20%) -- consider an automated way to take a function with a loop and generate a +- consider an automated way in RPython: a function with a loop and generate a JITable preamble and postamble with a call to the loop in the middle. - implement small tuples, there are a lot of places where they are hashed and @@ -58,12 +48,6 @@ Things we can do mostly by editing optimizeopt/: -- getfields which result is never used never get removed (probable cause - - they used to be as livevars in removed guards). also getfields which result - is only used as a livevar in a guard should be removed and encoded in - the guard recovert code (only if we are sure that the stored field cannot - change) - - if we move a promotion up the chain, some arguments don't get replaced with constants (those between current and previous locations). So we get like @@ -95,36 +79,17 @@ Extracted from some real-life Python programs, examples that don't give nice code at all so far: -- string manipulation: s[n], s[-n], s[i:j], most operations on single - chars, building a big string with repeated "s += t", "a,b=s.split()", - etc. PARTIALLY DONE with virtual strings - -- http://paste.pocoo.org/show/188520/ - this will compile new assembler path for each new type, even though that's - overspecialization since in this particular case it's not relevant. - This is treated as a megamorphic call (promotion of w_self in typeobject.py) - while in fact it is not. - -- guard_true(frame.is_being_profiled) all over the place - -- cProfile should be supported (right now it prevents JITting completely): - the calls to get the time should be done with the single assembler - instruction "read high-perf time stamp". The dict lookups done by - cProfile should be folded away. IN PROGRESS - - let super() work with the method cache. -- turn max(x, y)/min(x, y) into MAXSD, MINSD instructions when x and y are - floats. - -- xxx (find more examples :-) +- ((turn max(x, y)/min(x, y) into MAXSD, MINSD instructions when x and y are + floats.)) BACKEND TASKS ------------- -Look into avoiding double load of memory into register on 64bit. +Look into avoiding double load of constant into register on 64bit. In case we want to first read a value, increment it and store (for example), -we end up with double load of memory into register. Like: +we end up with double load of constant into register. Like: movabs 0xsomemem,r11 mov (r11), r10 @@ -139,14 +104,12 @@ - think out looking into functions or not, based on arguments, for example contains__Tuple should be unrolled if tuple is of constant - length. HARD, blocked by the fact that we don't know constants soon enough + length. This should be possible now that we do some heap opt during + tracing. Also, an unrolled loop means several copies of the guards, which may fail independently, leading to an exponential number of bridges -- out-of-line guards (when an external change would invalidate existing - pieces of assembler) - -- merge tails of loops-and-bridges? +- ((merge tails of loops-and-bridges?)) UNROLLING --------- From noreply at buildbot.pypy.org Sun Jul 24 16:03:44 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 24 Jul 2011 16:03:44 +0200 (CEST) Subject: [pypy-commit] pypy inline-dict-ops: kill the old nonsense Message-ID: <20110724140344.1688A8208C@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-dict-ops Changeset: r45938:99e88cd8c32c Date: 2011-07-24 16:02 +0200 http://bitbucket.org/pypy/pypy/changeset/99e88cd8c32c/ Log: kill the old nonsense diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -497,11 +497,6 @@ ENTRY = ENTRIES.OF entry = d.entries[i] if ENTRIES.must_clear_key: - key = entry.key # careful about destructor side effects: - # keep key alive until entry.value has also - # been zeroed (if it must be) - # XXX is this *actually* keeping stuff alive without - # keepalive_until_here? entry.key = lltype.nullptr(ENTRY.key.TO) if ENTRIES.must_clear_value: entry.value = lltype.nullptr(ENTRY.value.TO) From noreply at buildbot.pypy.org Sun Jul 24 16:03:45 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 24 Jul 2011 16:03:45 +0200 (CEST) Subject: [pypy-commit] pypy default: fix the nonsense on trunk as well Message-ID: <20110724140345.4A2388208C@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45939:d0b8d070eeec Date: 2011-07-24 16:03 +0200 http://bitbucket.org/pypy/pypy/changeset/d0b8d070eeec/ Log: fix the nonsense on trunk as well diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -501,9 +501,6 @@ ENTRY = ENTRIES.OF entry = d.entries[i] if ENTRIES.must_clear_key: - key = entry.key # careful about destructor side effects: - # keep key alive until entry.value has also - # been zeroed (if it must be) entry.key = lltype.nullptr(ENTRY.key.TO) if ENTRIES.must_clear_value: entry.value = lltype.nullptr(ENTRY.value.TO) From noreply at buildbot.pypy.org Sun Jul 24 16:25:24 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 24 Jul 2011 16:25:24 +0200 (CEST) Subject: [pypy-commit] jitviewer default: s/pypy-c/pypy/; Message-ID: <20110724142524.E04D88208C@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r162:b91ae3cae879 Date: 2011-07-24 16:24 +0200 http://bitbucket.org/pypy/jitviewer/changeset/b91ae3cae879/ Log: s/pypy-c/pypy/; diff --git a/README b/README --- a/README +++ b/README @@ -2,7 +2,7 @@ (1.6.1 or newer), virtualenvwrapper, and a recent PyPy (1.5 or trunk) to create a virtualenv: - mkvirtualenv --python=/path/to/pypy-c pypy-viewer + mkvirtualenv --python=/path/to/pypy pypy-viewer Now install the dependencies: @@ -20,5 +20,5 @@ jitviewer.py log where log is a logfile generated by -PYPYLOG=jit-log-opt,jit-backend:log pypy-c . +PYPYLOG=jit-log-opt,jit-backend:log pypy . An example log file comes with a checkout. diff --git a/bin/jitviewer.py b/bin/jitviewer.py --- a/bin/jitviewer.py +++ b/bin/jitviewer.py @@ -15,7 +15,7 @@ To produce the logfile for your program, run: - PYPYLOG=jit-log-opt,jit-backend-counts:mylogfile.log pypy-c myapp.py + PYPYLOG=jit-log-opt,jit-backend-counts:mylogfile.log pypy myapp.py """ import sys From noreply at buildbot.pypy.org Sun Jul 24 17:23:02 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sun, 24 Jul 2011 17:23:02 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: dont generalize constants Message-ID: <20110724152302.3D98A8208C@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45940:1782e7a6c50a Date: 2011-07-22 14:41 +0200 http://bitbucket.org/pypy/pypy/changeset/1782e7a6c50a/ Log: dont generalize constants diff --git a/pypy/jit/metainterp/optimizeopt/generalize.py b/pypy/jit/metainterp/optimizeopt/generalize.py --- a/pypy/jit/metainterp/optimizeopt/generalize.py +++ b/pypy/jit/metainterp/optimizeopt/generalize.py @@ -10,6 +10,8 @@ class KillHugeIntBounds(GeneralizationStrategy): def apply(self): for v in self.optimizer.values.values(): + if v.is_constant(): + continue if v.intbound.lower < MININT/2: v.intbound.lower = MININT if v.intbound.upper > MAXINT/2: diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -155,6 +155,7 @@ assert isinstance(constbox, Const) self.box = constbox self.level = LEVEL_CONSTANT + if isinstance(constbox, ConstInt): val = constbox.getint() self.intbound = IntBound(val, val) From noreply at buildbot.pypy.org Sun Jul 24 17:23:03 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Sun, 24 Jul 2011 17:23:03 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: hack to prevet the generated value guards from updating pure_operations Message-ID: <20110724152303.6FB3D8208C@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45941:77e23f604a98 Date: 2011-07-24 12:01 +0200 http://bitbucket.org/pypy/pypy/changeset/77e23f604a98/ Log: hack to prevet the generated value guards from updating pure_operations diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -237,6 +237,8 @@ self.optimizer.emitting_dissabled = True for op in inputarg_setup_ops: self.optimizer.send_extra_operation(op) + # XXX Hack to prevent previos loop from updateing pure_operations + self.optimizer.pure_operations = args_dict() seen = {} for op in self.short_boxes.operations(): self.ensure_short_op_emitted(op, self.optimizer, seen) From noreply at buildbot.pypy.org Sun Jul 24 17:58:50 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 17:58:50 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: Add a task Message-ID: <20110724155850.E44F48208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r3840:3ab2effafd3d Date: 2011-07-24 17:59 +0200 http://bitbucket.org/pypy/extradoc/changeset/3ab2effafd3d/ Log: Add a task diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -43,6 +43,8 @@ - implement small tuples, there are a lot of places where they are hashed and compared +- support single floats in the JIT + OPTIMIZATIONS ------------- From noreply at buildbot.pypy.org Sun Jul 24 18:16:18 2011 From: noreply at buildbot.pypy.org (hodgestar) Date: Sun, 24 Jul 2011 18:16:18 +0200 (CEST) Subject: [pypy-commit] pypy inline-simple-generators: (fijal, hodgestar) Start adding should_unroll_one_iteration. Message-ID: <20110724161618.9430A8208C@wyvern.cs.uni-duesseldorf.de> Author: Simon Cross Branch: inline-simple-generators Changeset: r45942:2e3ca4c4b315 Date: 2011-07-24 18:04 +0200 http://bitbucket.org/pypy/pypy/changeset/2e3ca4c4b315/ Log: (fijal, hodgestar) Start adding should_unroll_one_iteration. diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -901,6 +901,7 @@ any_operation = len(self.metainterp.history.operations) > 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) + import pdb; pdb.set_trace() self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -508,6 +508,23 @@ assert res == 84 - 61 - 62 self.check_history(call=1) # because the trace starts immediately + def test_unroll_one_loop(self): + def unroll(x): + return x == 0 + myjitdriver = JitDriver(greens = ['x'], reds = ['y'], should_unroll_one_iteration=unroll) + + def f(x, y): + while y > 0: + myjitdriver.jit_merge_point(x=x, y=y) + if x == 0: + return y + f(0, 4) + y -= 1 + return 0 + + res = self.meta_interp(f, [1, 4], enable_opts="", inline=True) + self.check_history(call_assembler=0) + def test_format(self): def f(n): return len("<%d>" % n) diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -468,6 +468,9 @@ onlygreens=False) jd._can_never_inline_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool) + jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd, + annhelper, jd.jitdriver.should_unroll_one_iteration, + annmodel.s_Bool) annhelper.finish() def _make_hook_graph(self, jitdriver_sd, annhelper, func, diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -44,8 +44,8 @@ ec.w_tracefunc is None) def can_never_inline(next_instr, is_being_profiled, bytecode): - return (bytecode.co_flags & CO_GENERATOR) != 0 - + #return (bytecode.co_flags & CO_GENERATOR) != 0 + return False def wrap_oplist(space, logops, operations): list_w = [] diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -315,7 +315,7 @@ def __init__(self, greens=None, reds=None, virtualizables=None, get_jitcell_at=None, set_jitcell_at=None, get_printable_location=None, confirm_enter_jit=None, - can_never_inline=None): + can_never_inline=None, should_unroll_one_iteration=None): if greens is not None: self.greens = greens if reds is not None: @@ -334,6 +334,7 @@ self.get_printable_location = get_printable_location self.confirm_enter_jit = confirm_enter_jit self.can_never_inline = can_never_inline + self.should_unroll_one_iteration = should_unroll_one_iteration def _freeze_(self): return True From noreply at buildbot.pypy.org Sun Jul 24 18:47:07 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 18:47:07 +0200 (CEST) Subject: [pypy-commit] pypy default: signal.signal() crashes with ValueError when called from a Message-ID: <20110724164707.DB19A8208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45943:824b72bb6b45 Date: 2011-07-24 17:25 +0200 http://bitbucket.org/pypy/pypy/changeset/824b72bb6b45/ Log: signal.signal() crashes with ValueError when called from a non-main thread...? diff --git a/lib_pypy/pyrepl/unix_console.py b/lib_pypy/pyrepl/unix_console.py --- a/lib_pypy/pyrepl/unix_console.py +++ b/lib_pypy/pyrepl/unix_console.py @@ -384,14 +384,18 @@ self.__maybe_write_code(self._smkx) + try: self.old_sigwinch = signal.signal( signal.SIGWINCH, self.__sigwinch) + except ValueError: + pass def restore(self): self.__maybe_write_code(self._rmkx) self.flushoutput() tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate) + if hasattr(self, 'old_sigwinch'): signal.signal(signal.SIGWINCH, self.old_sigwinch) def __sigwinch(self, signum, frame): From noreply at buildbot.pypy.org Sun Jul 24 18:47:09 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 18:47:09 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and -er- fix, by commenting out the buggy code. Message-ID: <20110724164709.239C9829BA@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45944:70d00af8294e Date: 2011-07-24 18:46 +0200 http://bitbucket.org/pypy/pypy/changeset/70d00af8294e/ Log: Test and -er- fix, by commenting out the buggy code. diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -40,7 +40,7 @@ # In that case, do 5 bits at a time. The potential drawback is that # a table of 2**5 intermediate results is computed. -FIVEARY_CUTOFF = 8 +## FIVEARY_CUTOFF = 8 disabled for now def _mask_digit(x): @@ -456,7 +456,7 @@ # python adaptation: moved macros REDUCE(X) and MULT(X, Y, result) # into helper function result = _help_mult(x, y, c) - if b.numdigits() <= FIVEARY_CUTOFF: + if 1: ## b.numdigits() <= FIVEARY_CUTOFF: # Left-to-right binary exponentiation (HAC Algorithm 14.79) # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf i = b.numdigits() - 1 @@ -469,26 +469,30 @@ z = _help_mult(z, a, c) j >>= 1 i -= 1 - else: - # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) - # This is only useful in the case where c != None. - # z still holds 1L - table = [z] * 32 - table[0] = z - for i in range(1, 32): - table[i] = _help_mult(table[i-1], a, c) - i = b.numdigits() - 1 - while i >= 0: - bi = b.digit(i) - j = SHIFT - 5 - while j >= 0: - index = (bi >> j) & 0x1f - for k in range(5): - z = _help_mult(z, z, c) - if index: - z = _help_mult(z, table[index], c) - j -= 5 - i -= 1 +## else: +## This code is disabled for now, because it assumes that +## SHIFT is a multiple of 5. It could be fixed but it looks +## like it's more troubles than benefits... +## +## # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) +## # This is only useful in the case where c != None. +## # z still holds 1L +## table = [z] * 32 +## table[0] = z +## for i in range(1, 32): +## table[i] = _help_mult(table[i-1], a, c) +## i = b.numdigits() - 1 +## while i >= 0: +## bi = b.digit(i) +## j = SHIFT - 5 +## while j >= 0: +## index = (bi >> j) & 0x1f +## for k in range(5): +## z = _help_mult(z, z, c) +## if index: +## z = _help_mult(z, table[index], c) +## j -= 5 +## i -= 1 if negativeOutput and z.sign != 0: z = z.sub(c) diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py --- a/pypy/rlib/test/test_rbigint.py +++ b/pypy/rlib/test/test_rbigint.py @@ -373,6 +373,13 @@ print '--->', v assert v.tolong() == pow(x, y, z) + def test_pow_lll_bug(self): + two = rbigint.fromint(2) + t = rbigint.fromlong(2655689964083835493447941032762343136647965588635159615997220691002017799304) + for n, expected in [(37, 9), (1291, 931), (67889, 39464)]: + v = two.pow(t, rbigint.fromint(n)) + assert v.toint() == expected + def test_pow_lln(self): x = 10L y = 2L From noreply at buildbot.pypy.org Sun Jul 24 18:47:10 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 24 Jul 2011 18:47:10 +0200 (CEST) Subject: [pypy-commit] pypy default: merge default Message-ID: <20110724164710.5939D8208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45945:70435a5564da Date: 2011-07-24 18:46 +0200 http://bitbucket.org/pypy/pypy/changeset/70435a5564da/ Log: merge default diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -501,9 +501,6 @@ ENTRY = ENTRIES.OF entry = d.entries[i] if ENTRIES.must_clear_key: - key = entry.key # careful about destructor side effects: - # keep key alive until entry.value has also - # been zeroed (if it must be) entry.key = lltype.nullptr(ENTRY.key.TO) if ENTRIES.must_clear_value: entry.value = lltype.nullptr(ENTRY.value.TO) From noreply at buildbot.pypy.org Sun Jul 24 19:14:17 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 24 Jul 2011 19:14:17 +0200 (CEST) Subject: [pypy-commit] pypy inline-simple-generators: (fijal, hodgestar) make the test pass Message-ID: <20110724171417.9066D8208C@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-simple-generators Changeset: r45946:637652763be4 Date: 2011-07-24 19:12 +0200 http://bitbucket.org/pypy/pypy/changeset/637652763be4/ Log: (fijal, hodgestar) make the test pass diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -901,7 +901,6 @@ any_operation = len(self.metainterp.history.operations) > 0 jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex] self.verify_green_args(jitdriver_sd, greenboxes) - import pdb; pdb.set_trace() self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion, greenboxes) @@ -931,6 +930,8 @@ # close the loop. We have to put the possibly-modified list # 'redboxes' back into the registers where it comes from. put_back_list_of_boxes3(self, jcposition, redboxes) + elif jitdriver_sd.warmstate.should_unroll_one_iteration(greenboxes): + return else: # warning! careful here. We have to return from the current # frame containing the jit_merge_point, and then use diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -508,7 +508,7 @@ assert res == 84 - 61 - 62 self.check_history(call=1) # because the trace starts immediately - def test_unroll_one_loop(self): + def test_unroll_one_loop_iteration(self): def unroll(x): return x == 0 myjitdriver = JitDriver(greens = ['x'], reds = ['y'], should_unroll_one_iteration=unroll) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -572,6 +572,19 @@ return can_inline_greenargs(*greenargs) self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + + if jd._should_unroll_one_iteration_ptr is None: + def should_unroll_one_iteration(greenkey): + return False + else: + rtyper = self.warmrunnerdesc.rtyper + inline_ptr = jd._should_unroll_one_iteration_ptr + def should_unroll_one_iteration(greenkey): + greenargs = unwrap_greenkey(greenkey) + fn = support.maybe_on_top_of_llinterp(rtyper, inline_ptr) + return fn(*greenargs) + self.should_unroll_one_iteration = should_unroll_one_iteration + if hasattr(jd.jitdriver, 'on_compile'): def on_compile(logger, token, operations, type, greenkey): greenargs = unwrap_greenkey(greenkey) From noreply at buildbot.pypy.org Sun Jul 24 19:40:28 2011 From: noreply at buildbot.pypy.org (hodgestar) Date: Sun, 24 Jul 2011 19:40:28 +0200 (CEST) Subject: [pypy-commit] pypy inline-simple-generators: (fijal, hodgestar) Unroll only one iteration of the loop. Message-ID: <20110724174028.D4C278208C@wyvern.cs.uni-duesseldorf.de> Author: Simon Cross Branch: inline-simple-generators Changeset: r45947:ade9aa80fb50 Date: 2011-07-24 19:40 +0200 http://bitbucket.org/pypy/pypy/changeset/ade9aa80fb50/ Log: (fijal, hodgestar) Unroll only one iteration of the loop. diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -56,6 +56,8 @@ # for resume.py operation self.parent_resumedata_snapshot = None self.parent_resumedata_frame_info_list = None + # counter for unrolling inlined loops + self.unroll_iterations = 1 @specialize.arg(3) def copy_constants(self, registers, constants, ConstClass): @@ -930,9 +932,11 @@ # close the loop. We have to put the possibly-modified list # 'redboxes' back into the registers where it comes from. put_back_list_of_boxes3(self, jcposition, redboxes) - elif jitdriver_sd.warmstate.should_unroll_one_iteration(greenboxes): + else: + if jitdriver_sd.warmstate.should_unroll_one_iteration(greenboxes): + if self.unroll_iterations > 0: + self.unroll_iterations -= 1 return - else: # warning! careful here. We have to return from the current # frame containing the jit_merge_point, and then use # do_recursive_call() to follow the recursive call. This is diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -511,20 +511,29 @@ def test_unroll_one_loop_iteration(self): def unroll(x): return x == 0 - myjitdriver = JitDriver(greens = ['x'], reds = ['y'], should_unroll_one_iteration=unroll) + myjitdriver = JitDriver(greens = ['code'], + reds = ['loops', 'inner_loops', 's'], + should_unroll_one_iteration=unroll) - def f(x, y): - while y > 0: - myjitdriver.jit_merge_point(x=x, y=y) - if x == 0: - return y - f(0, 4) - y -= 1 - return 0 + def f(code, loops, inner_loops): + s = 0 + while loops > 0: + myjitdriver.jit_merge_point(code=code, loops=loops, + inner_loops=inner_loops, s=s) + if code == 1: + s += f(0, inner_loops, 0) + loops -= 1 + s += 1 + return s - res = self.meta_interp(f, [1, 4], enable_opts="", inline=True) + res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True) + assert res == f(1, 4, 1) self.check_history(call_assembler=0) + res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True) + assert res == f(1, 4, 2) + self.check_history(call_assembler=1) + def test_format(self): def f(n): return len("<%d>" % n) From noreply at buildbot.pypy.org Sun Jul 24 19:42:38 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 24 Jul 2011 19:42:38 +0200 (CEST) Subject: [pypy-commit] pypy inline-simple-generators: (fijal, hodgestar) unroll one iteration of generators Message-ID: <20110724174238.DE9AC8208C@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-simple-generators Changeset: r45948:b0e02ce2abbb Date: 2011-07-24 19:42 +0200 http://bitbucket.org/pypy/pypy/changeset/b0e02ce2abbb/ Log: (fijal, hodgestar) unroll one iteration of generators diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -44,9 +44,11 @@ ec.w_tracefunc is None) def can_never_inline(next_instr, is_being_profiled, bytecode): - #return (bytecode.co_flags & CO_GENERATOR) != 0 return False +def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode): + return (bytecode.co_flags & CO_GENERATOR) != 0 + def wrap_oplist(space, logops, operations): list_w = [] for op in operations: @@ -110,7 +112,9 @@ get_jitcell_at = get_jitcell_at, set_jitcell_at = set_jitcell_at, confirm_enter_jit = confirm_enter_jit, - can_never_inline = can_never_inline) + can_never_inline = can_never_inline, + should_unroll_one_iteration = + should_unroll_one_iteration) class __extend__(PyFrame): From noreply at buildbot.pypy.org Sun Jul 24 20:18:37 2011 From: noreply at buildbot.pypy.org (hodgestar) Date: Sun, 24 Jul 2011 20:18:37 +0200 (CEST) Subject: [pypy-commit] pypy inline-simple-generators: (antocuni, hodgestar) Rename unroll argument in test to make test more understandable. Message-ID: <20110724181837.A17A18208C@wyvern.cs.uni-duesseldorf.de> Author: Simon Cross Branch: inline-simple-generators Changeset: r45949:1c03240c7ac2 Date: 2011-07-24 20:18 +0200 http://bitbucket.org/pypy/pypy/changeset/1c03240c7ac2/ Log: (antocuni, hodgestar) Rename unroll argument in test to make test more understandable. diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -509,8 +509,8 @@ self.check_history(call=1) # because the trace starts immediately def test_unroll_one_loop_iteration(self): - def unroll(x): - return x == 0 + def unroll(code): + return code == 0 myjitdriver = JitDriver(greens = ['code'], reds = ['loops', 'inner_loops', 's'], should_unroll_one_iteration=unroll) From noreply at buildbot.pypy.org Sun Jul 24 21:44:14 2011 From: noreply at buildbot.pypy.org (hodgestar) Date: Sun, 24 Jul 2011 21:44:14 +0200 (CEST) Subject: [pypy-commit] pypy inline-simple-generators: (fijal, hodgestar) Add test_pypy_c for generators. Message-ID: <20110724194414.98AD08208C@wyvern.cs.uni-duesseldorf.de> Author: Simon Cross Branch: inline-simple-generators Changeset: r45950:f8569277fc1f Date: 2011-07-24 21:44 +0200 http://bitbucket.org/pypy/pypy/changeset/f8569277fc1f/ Log: (fijal, hodgestar) Add test_pypy_c for generators. diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py @@ -0,0 +1,25 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGenerators(BaseTestPyPyC): + def test_simple_generator(self): + def main(n): + def f(): + for i in range(10000): + yield i + + def g(): + for i in f(): # ID: generator + pass + + g() + + log = self.run(main, [500]) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("generator", """ + i16 = force_token() + p45 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p45, i29, descr=) + setarrayitem_gc(p8, 0, p45, descr=) + jump(..., descr=...) + """) From noreply at buildbot.pypy.org Sun Jul 24 21:47:08 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 24 Jul 2011 21:47:08 +0200 (CEST) Subject: [pypy-commit] pypy default: (fijal, hodgestar) merge inline-simple-generators. that branch peels one loop iteration out of generators and inlines this into outer loop Message-ID: <20110724194708.472E38208C@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r45951:c8bb44739101 Date: 2011-07-24 21:47 +0200 http://bitbucket.org/pypy/pypy/changeset/c8bb44739101/ Log: (fijal, hodgestar) merge inline-simple-generators. that branch peels one loop iteration out of generators and inlines this into outer loop diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -56,6 +56,8 @@ # for resume.py operation self.parent_resumedata_snapshot = None self.parent_resumedata_frame_info_list = None + # counter for unrolling inlined loops + self.unroll_iterations = 1 @specialize.arg(3) def copy_constants(self, registers, constants, ConstClass): @@ -931,6 +933,10 @@ # 'redboxes' back into the registers where it comes from. put_back_list_of_boxes3(self, jcposition, redboxes) else: + if jitdriver_sd.warmstate.should_unroll_one_iteration(greenboxes): + if self.unroll_iterations > 0: + self.unroll_iterations -= 1 + return # warning! careful here. We have to return from the current # frame containing the jit_merge_point, and then use # do_recursive_call() to follow the recursive call. This is diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -508,6 +508,32 @@ assert res == 84 - 61 - 62 self.check_history(call=1) # because the trace starts immediately + def test_unroll_one_loop_iteration(self): + def unroll(code): + return code == 0 + myjitdriver = JitDriver(greens = ['code'], + reds = ['loops', 'inner_loops', 's'], + should_unroll_one_iteration=unroll) + + def f(code, loops, inner_loops): + s = 0 + while loops > 0: + myjitdriver.jit_merge_point(code=code, loops=loops, + inner_loops=inner_loops, s=s) + if code == 1: + s += f(0, inner_loops, 0) + loops -= 1 + s += 1 + return s + + res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True) + assert res == f(1, 4, 1) + self.check_history(call_assembler=0) + + res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True) + assert res == f(1, 4, 2) + self.check_history(call_assembler=1) + def test_format(self): def f(n): return len("<%d>" % n) diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -468,6 +468,9 @@ onlygreens=False) jd._can_never_inline_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool) + jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd, + annhelper, jd.jitdriver.should_unroll_one_iteration, + annmodel.s_Bool) annhelper.finish() def _make_hook_graph(self, jitdriver_sd, annhelper, func, diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -572,6 +572,19 @@ return can_inline_greenargs(*greenargs) self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + + if jd._should_unroll_one_iteration_ptr is None: + def should_unroll_one_iteration(greenkey): + return False + else: + rtyper = self.warmrunnerdesc.rtyper + inline_ptr = jd._should_unroll_one_iteration_ptr + def should_unroll_one_iteration(greenkey): + greenargs = unwrap_greenkey(greenkey) + fn = support.maybe_on_top_of_llinterp(rtyper, inline_ptr) + return fn(*greenargs) + self.should_unroll_one_iteration = should_unroll_one_iteration + if hasattr(jd.jitdriver, 'on_compile'): def on_compile(logger, token, operations, type, greenkey): greenargs = unwrap_greenkey(greenkey) diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -44,9 +44,11 @@ ec.w_tracefunc is None) def can_never_inline(next_instr, is_being_profiled, bytecode): + return False + +def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode): return (bytecode.co_flags & CO_GENERATOR) != 0 - def wrap_oplist(space, logops, operations): list_w = [] for op in operations: @@ -110,7 +112,9 @@ get_jitcell_at = get_jitcell_at, set_jitcell_at = set_jitcell_at, confirm_enter_jit = confirm_enter_jit, - can_never_inline = can_never_inline) + can_never_inline = can_never_inline, + should_unroll_one_iteration = + should_unroll_one_iteration) class __extend__(PyFrame): diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py @@ -0,0 +1,25 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGenerators(BaseTestPyPyC): + def test_simple_generator(self): + def main(n): + def f(): + for i in range(10000): + yield i + + def g(): + for i in f(): # ID: generator + pass + + g() + + log = self.run(main, [500]) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("generator", """ + i16 = force_token() + p45 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p45, i29, descr=) + setarrayitem_gc(p8, 0, p45, descr=) + jump(..., descr=...) + """) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -315,7 +315,7 @@ def __init__(self, greens=None, reds=None, virtualizables=None, get_jitcell_at=None, set_jitcell_at=None, get_printable_location=None, confirm_enter_jit=None, - can_never_inline=None): + can_never_inline=None, should_unroll_one_iteration=None): if greens is not None: self.greens = greens if reds is not None: @@ -334,6 +334,7 @@ self.get_printable_location = get_printable_location self.confirm_enter_jit = confirm_enter_jit self.can_never_inline = can_never_inline + self.should_unroll_one_iteration = should_unroll_one_iteration def _freeze_(self): return True From noreply at buildbot.pypy.org Sun Jul 24 21:54:04 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 24 Jul 2011 21:54:04 +0200 (CEST) Subject: [pypy-commit] pypy inline-simple-generators: close merged branch Message-ID: <20110724195404.6B1CE8208C@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: inline-simple-generators Changeset: r45952:cf2759cf9b0a Date: 2011-07-24 21:54 +0200 http://bitbucket.org/pypy/pypy/changeset/cf2759cf9b0a/ Log: close merged branch From noreply at buildbot.pypy.org Sun Jul 24 22:38:41 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 24 Jul 2011 22:38:41 +0200 (CEST) Subject: [pypy-commit] jitviewer default: a silly workaround for module-global code Message-ID: <20110724203841.E63A08208C@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r163:a243fd3d0a1e Date: 2011-07-24 22:38 +0200 http://bitbucket.org/pypy/jitviewer/changeset/a243fd3d0a1e/ Log: a silly workaround for module-global code diff --git a/bin/jitviewer.py b/bin/jitviewer.py --- a/bin/jitviewer.py +++ b/bin/jitviewer.py @@ -130,6 +130,13 @@ startline, endline = loop.linerange code = self.storage.load_code(loop.filename)[(loop.startlineno, loop.name)] + if code.co_name == '' and code.co_firstlineno == 1: + try: + with open(code.co_filename) as f: + source = CodeRepr(f.read(), code, loop) + except (IOError, OSError): + source = CodeReprNoFile(loop) + else: source = CodeRepr(inspect.getsource(code), code, loop) d = {'html': flask.render_template('loop.html', source=source, From noreply at buildbot.pypy.org Mon Jul 25 00:43:52 2011 From: noreply at buildbot.pypy.org (hodgestar) Date: Mon, 25 Jul 2011 00:43:52 +0200 (CEST) Subject: [pypy-commit] jitviewer default: (hodgestar, fijal) Jitviewer requires Jinja2 >= 2.6 Message-ID: <20110724224352.6F3EC8208C@wyvern.cs.uni-duesseldorf.de> Author: Simon Cross Branch: Changeset: r164:993de13e3b77 Date: 2011-07-25 00:43 +0200 http://bitbucket.org/pypy/jitviewer/changeset/993de13e3b77/ Log: (hodgestar, fijal) Jitviewer requires Jinja2 >= 2.6 diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ url='http://pypy.org', packages=['_jitviewer'], scripts=['bin/jitviewer.py', 'bin/qwebview.py'], - install_requires=['flask', 'pygments', 'simplejson'], + install_requires=['flask', 'pygments', 'simplejson', 'Jinja2>=2.6'], include_package_data=True, package_data={'': ['templates/*.html', 'static/*']}, zip_safe=False) From noreply at buildbot.pypy.org Mon Jul 25 01:10:26 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 01:10:26 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: work in progress Message-ID: <20110724231026.56ED98208C@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45953:b3e72b286556 Date: 2011-07-25 01:08 +0200 http://bitbucket.org/pypy/pypy/changeset/b3e72b286556/ Log: work in progress diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -137,6 +137,9 @@ if (hasattr(targetgraph, 'func') and hasattr(targetgraph.func, 'oopspec')): return 'builtin' + if (hasattr(targetgraph, 'func') and + hasattr(targetgraph.func, '_jit_unroll_if_const_')): + return 'regularifconst' elif op.opname == 'oosend': SELFTYPE, methname, opargs = support.decompose_oosend(op) if SELFTYPE.oopspec_name is not None: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -337,6 +337,15 @@ op1 = SpaceOperation('-live-', [], None) return [op0, op1] + def handle_regularifconst_call(self, op): + """ A direct call that turns into inline_ifconst_call_xxx. The first + argument is jitcode, then number of const arg then calldescr and + finally all other args + """ + import pdb + pdb.set_trace() + [targetgraph] = self.callcontrol.graphs_from(op) + def handle_builtin_call(self, op): oopspec_name, args = support.decode_builtin_call(op) # dispatch to various implementations depending on the oopspec_name diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -58,6 +58,8 @@ self._reject_function(func)) contains_loop = contains_loop and not getattr( func, '_jit_unroll_safe_', False) + contains_loop = contains_loop and not getattr( + func, '_jit_unroll_if_const_', False) unsupported = contains_unsupported_variable_type(graph, self.supports_floats, diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -3,7 +3,7 @@ from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed -from pypy.rlib.jit import unroll_safe, current_trace_length +from pypy.rlib.jit import unroll_safe, current_trace_length, unroll_if_const from pypy.jit.metainterp import pyjitpl, history from pypy.jit.metainterp.warmstate import set_future_value from pypy.jit.metainterp.warmspot import get_stats @@ -2400,6 +2400,34 @@ # 1 preamble and 6 speciealized versions of each loop self.check_tree_loop_count(2*(1 + 6)) + def test_unroll_if_const(self): + @unroll_if_const(0) + def f(arg): + s = 0 + while arg > 0: + s += arg + arg -= 1 + return s + + driver = JitDriver(greens = ['code'], reds = ['n', 'arg', 's']) + + def main(code, n, arg): + s = 0 + while n > 0: + driver.jit_merge_point(code=code, n=n, arg=arg, s=s) + if code == 0: + s += f(arg) + else: + s += f(1) + n -= 1 + return s + + res = self.meta_interp(main, [0, 10, 2], enable_opts='') + assert res == main(0, 10, 2) + self.check_loops(call=1) + res = self.meta_interp(main, [1, 10, 2], enable_opts='') + assert res == main(0, 10, 2) + self.check_loops(call=0) class TestOOtype(BasicTests, OOJitMixin): diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -41,6 +41,14 @@ """ return x +def unroll_if_const(argno): + """ Mark function as loop unrollable if arg number argno is a constant + """ + def decorator(f): + f._jit_unroll_if_const_ = (argno,) + return f + return decorator + @specialize.argtype(0) def promote(x): return hint(x, promote=True) From noreply at buildbot.pypy.org Mon Jul 25 02:09:51 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 25 Jul 2011 02:09:51 +0200 (CEST) Subject: [pypy-commit] pypy default: Merging ootype-rerased Message-ID: <20110725000951.2BDC08208C@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: Changeset: r45954:d4d712e9bd58 Date: 2011-07-24 17:09 -0700 http://bitbucket.org/pypy/pypy/changeset/d4d712e9bd58/ Log: Merging ootype-rerased diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py --- a/pypy/rlib/rerased.py +++ b/pypy/rlib/rerased.py @@ -113,7 +113,7 @@ if hop.r_result.lowleveltype is lltype.Void: return hop.inputconst(lltype.Void, None) [v] = hop.inputargs(hop.args_r[0]) - return hop.genop('cast_opaque_ptr', [v], resulttype = hop.r_result) + return hop.args_r[0].rtype_unerase(hop, v) return erase, unerase @@ -147,7 +147,7 @@ def specialize_call(self, hop): [v] = hop.inputargs(hop.args_r[0]) assert isinstance(hop.s_result, annmodel.SomeInteger) - return hop.gendirectcall(ll_unerase_int, v) + return hop.args_r[0].rtype_unerase_int(hop, v) def ll_unerase_int(gcref): from pypy.rpython.lltypesystem.lloperation import llop @@ -174,7 +174,10 @@ return False # cannot be None, but can contain a None def rtyper_makerepr(self, rtyper): + if rtyper.type_system.name == 'lltypesystem': return ErasedRepr(rtyper) + elif rtyper.type_system.name == 'ootypesystem': + return OOErasedRepr(rtyper) def rtyper_makekey(self): return self.__class__, @@ -200,6 +203,13 @@ return hop.genop('cast_opaque_ptr', [v_obj], resulttype=self.lowleveltype) + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_opaque_ptr', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + return hop.gendirectcall(ll_unerase_int, v) + def rtype_erase_int(self, hop): [v_value] = hop.inputargs(lltype.Signed) c_one = hop.inputconst(lltype.Signed, 1) @@ -224,3 +234,50 @@ return lltype.nullptr(self.lowleveltype.TO) v = r_obj.convert_const(value._x) return lltype.cast_opaque_ptr(self.lowleveltype, v) + +from pypy.rpython.ootypesystem import ootype + +class OOErasedRepr(Repr): + lowleveltype = ootype.Object + def __init__(self, rtyper): + self.rtyper = rtyper + + def rtype_erase(self, hop, s_obj): + hop.exception_cannot_occur() + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return hop.inputconst(self.lowleveltype, + ootype.NULL) + [v_obj] = hop.inputargs(r_obj) + return hop.genop('cast_to_object', [v_obj], + resulttype=self.lowleveltype) + + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_from_object', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('oounbox_int', [v], resulttype=hop.r_result) + return hop.genop('int_rshift', [v2, c_one], resulttype=lltype.Signed) + + def rtype_erase_int(self, hop): + hop.exception_is_here() + [v_value] = hop.inputargs(lltype.Signed) + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('int_lshift_ovf', [v_value, c_one], + resulttype = lltype.Signed) + v2p1 = hop.genop('int_add', [v2, c_one], + resulttype = lltype.Signed) + return hop.genop('oobox_int', [v2p1], resulttype=hop.r_result) + + def convert_const(self, value): + if value._identity is _identity_for_ints: + return value._x # FIXME: what should we do here? + bk = self.rtyper.annotator.bookkeeper + s_obj = value._identity.get_input_annotation(bk) + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return ootype.NULL + v = r_obj.convert_const(value._x) + return ootype.cast_to_object(v) diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py --- a/pypy/rlib/test/test_rerased.py +++ b/pypy/rlib/test/test_rerased.py @@ -5,8 +5,10 @@ from pypy.annotation.annrpython import RPythonAnnotator from pypy.rpython.test.test_llinterp import interpret from pypy.rpython.lltypesystem.rclass import OBJECTPTR +from pypy.rpython.ootypesystem.rclass import OBJECT from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin class X(object): pass @@ -79,136 +81,6 @@ s = a.build_types(f, []) assert isinstance(s, annmodel.SomeInteger) -def test_rtype_1(): - def f(): - return eraseX(X()) - x = interpret(f, []) - assert lltype.typeOf(x) == llmemory.GCREF - -def test_rtype_2(): - def f(): - x1 = X() - e = eraseX(x1) - #assert not is_integer(e) - x2 = uneraseX(e) - return x2 - x = interpret(f, []) - assert lltype.castable(OBJECTPTR, lltype.typeOf(x)) > 0 - -def test_rtype_3(): - def f(): - e = erase_int(16) - #assert is_integer(e) - x2 = unerase_int(e) - return x2 - x = interpret(f, []) - assert x == 16 - - -def test_prebuilt_erased(): - e1 = erase_int(16) - x1 = X() - x1.foobar = 42 - e2 = eraseX(x1) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = unerase_int(e1) + uneraseX(e2).foobar - return x2 - x = interpret(f, []) - assert x == 16 + 42 + 1 - -def test_prebuilt_erased_in_instance(): - erase_empty, unerase_empty = new_erasing_pair("empty") - class FakeList(object): - pass - - x1 = X() - x1.foobar = 42 - l1 = FakeList() - l1.storage = eraseX(x1) - l2 = FakeList() - l2.storage = erase_empty(None) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) - return x2 - x = interpret(f, []) - assert x == 43 + True - - -def test_overflow(): - def f(i): - try: - e = erase_int(i) - except OverflowError: - return -1 - #assert is_integer(e) - return unerase_int(e) - x = interpret(f, [16]) - assert x == 16 - x = interpret(f, [sys.maxint]) - assert x == -1 - -def test_none(): - def foo(): - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - # - def foo(): - eraseX(X()) - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - -def test_union(): - s_e1 = SomeErased() - s_e1.const = 1 - s_e2 = SomeErased() - s_e2.const = 3 - assert not annmodel.pair(s_e1, s_e2).union().is_constant() - - -def test_rtype_list(): - prebuilt_l = [X()] - prebuilt_e = erase_list_X(prebuilt_l) - def l(flag): - if flag == 1: - l = [X()] - e = erase_list_X(l) - elif flag == 2: - l = prebuilt_l - e = erase_list_X(l) - else: - l = prebuilt_l - e = prebuilt_e - #assert is_integer(e) is False - assert unerase_list_X(e) is l - interpret(l, [0]) - interpret(l, [1]) - interpret(l, [2]) - -# ____________________________________________________________ - -def test_erasing_pair(): - erase, unerase = new_erasing_pair("test1") - class X: - pass - x = X() - erased = erase(x) - assert unerase(erased) is x - # - erase2, unerase2 = new_erasing_pair("test2") - py.test.raises(AssertionError, unerase2, erased) - def test_annotate_erasing_pair(): erase, unerase = new_erasing_pair("test1") erase2, unerase2 = new_erasing_pair("test2") @@ -296,3 +168,148 @@ a = RPythonAnnotator() s = a.build_types(f, [int]) assert isinstance(s, annmodel.SomeInteger) + +class BaseTestRErased(BaseRtypingTest): + def test_rtype_1(self): + def f(): + return eraseX(X()) + x = self.interpret(f, []) + assert lltype.typeOf(x) == self.ERASED_TYPE + + def test_rtype_2(self): + def f(): + x1 = X() + e = eraseX(x1) + #assert not is_integer(e) + x2 = uneraseX(e) + return x2 + x = self.interpret(f, []) + assert self.castable(self.UNERASED_TYPE, x) + + def test_rtype_3(self): + def f(): + e = erase_int(16) + #assert is_integer(e) + x2 = unerase_int(e) + return x2 + x = self.interpret(f, []) + assert x == 16 + + def test_prebuilt_erased(self): + e1 = erase_int(16) + x1 = X() + x1.foobar = 42 + e2 = eraseX(x1) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = unerase_int(e1) + uneraseX(e2).foobar + return x2 + x = self.interpret(f, []) + assert x == 16 + 42 + 1 + + def test_prebuilt_erased_in_instance(self): + erase_empty, unerase_empty = new_erasing_pair("empty") + class FakeList(object): + pass + + x1 = X() + x1.foobar = 42 + l1 = FakeList() + l1.storage = eraseX(x1) + l2 = FakeList() + l2.storage = erase_empty(None) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) + return x2 + x = self.interpret(f, []) + assert x == 43 + True + + def test_overflow(self): + def f(i): + try: + e = erase_int(i) + except OverflowError: + return -1 + #assert is_integer(e) + return unerase_int(e) + x = self.interpret(f, [16]) + assert x == 16 + x = self.interpret(f, [sys.maxint]) + assert x == -1 + + def test_none(self): + def foo(): + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + # + def foo(): + eraseX(X()) + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + + def test_rtype_list(self): + prebuilt_l = [X()] + prebuilt_e = erase_list_X(prebuilt_l) + def l(flag): + if flag == 1: + l = [X()] + e = erase_list_X(l) + elif flag == 2: + l = prebuilt_l + e = erase_list_X(l) + else: + l = prebuilt_l + e = prebuilt_e + #assert is_integer(e) is False + assert unerase_list_X(e) is l + self.interpret(l, [0]) + self.interpret(l, [1]) + self.interpret(l, [2]) + +class TestLLtype(BaseTestRErased, LLRtypeMixin): + ERASED_TYPE = llmemory.GCREF + UNERASED_TYPE = OBJECTPTR + def castable(self, TO, var): + return lltype.castable(TO, lltype.typeOf(var)) > 0 + +from pypy.rpython.ootypesystem.ootype import Object + +class TestOOtype(BaseTestRErased, OORtypeMixin): + ERASED_TYPE = Object + UNERASED_TYPE = OBJECT + def castable(self, TO, var): + return ootype.isSubclass(lltype.typeOf(var), TO) + @py.test.mark.xfail + def test_prebuilt_erased(self): + super(TestOOtype, self).test_prebuilt_erased() + +def test_union(): + s_e1 = SomeErased() + s_e1.const = 1 + s_e2 = SomeErased() + s_e2.const = 3 + assert not annmodel.pair(s_e1, s_e2).union().is_constant() + +# ____________________________________________________________ + +def test_erasing_pair(): + erase, unerase = new_erasing_pair("test1") + class X: + pass + x = X() + erased = erase(x) + assert unerase(erased) is x + # + erase2, unerase2 = new_erasing_pair("test2") + py.test.raises(AssertionError, unerase2, erased) diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -1225,6 +1225,12 @@ except ValueError: self.make_llexception() + def op_oobox_int(self, i): + return ootype.oobox_int(i) + + def op_oounbox_int(self, x): + return ootype.oounbox_int(x) + class Tracer(object): Counter = 0 file = None diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -585,6 +585,8 @@ 'classof': LLOp(oo=True, canfold=True), 'subclassof': LLOp(oo=True, canfold=True), 'oostring': LLOp(oo=True, sideeffects=False), + 'oobox_int': LLOp(oo=True, sideeffects=False), + 'oounbox_int': LLOp(oo=True, sideeffects=False), 'ooparse_int': LLOp(oo=True, canraise=(ValueError,)), 'ooparse_float': LLOp(oo=True, canraise=(ValueError,)), 'oounicode': LLOp(oo=True, canraise=(UnicodeDecodeError,)), diff --git a/pypy/rpython/ootypesystem/ooopimpl.py b/pypy/rpython/ootypesystem/ooopimpl.py --- a/pypy/rpython/ootypesystem/ooopimpl.py +++ b/pypy/rpython/ootypesystem/ooopimpl.py @@ -3,7 +3,6 @@ # ____________________________________________________________ # Implementation of the 'canfold' oo operations - def op_ooupcast(INST, inst): return ootype.ooupcast(INST, inst) op_ooupcast.need_result_type = True diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -1938,6 +1938,17 @@ assert typeOf(obj) is Object return obj._cast_to(EXPECTED_TYPE) +class Box(_object): + def __init__(self, i): + self._TYPE = Object + self.i = i + +def oobox_int(i): + return Box(i) + +def oounbox_int(x): + return x.i + def oostring(obj, base): """ Convert char, int, float, instances and str to str. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -255,7 +255,7 @@ methodname = None return fn, v_obj, methodname -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): from pypy.rlib import jit r_dict = hop.r_result diff --git a/pypy/rpython/test/test_rint.py b/pypy/rpython/test/test_rint.py --- a/pypy/rpython/test/test_rint.py +++ b/pypy/rpython/test/test_rint.py @@ -8,6 +8,9 @@ from pypy.rlib import objectmodel from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem.lloperation import llop class TestSnippet(object): @@ -412,4 +415,8 @@ pass class TestOOtype(BaseTestRint, OORtypeMixin): - pass + def test_oobox_int(self): + def f(): + x = llop.oobox_int(ootype.Object, 42) + return llop.oounbox_int(lltype.Signed, x) + assert self.interpret(f, []) == 42 diff --git a/pypy/translator/cli/metavm.py b/pypy/translator/cli/metavm.py --- a/pypy/translator/cli/metavm.py +++ b/pypy/translator/cli/metavm.py @@ -1,6 +1,6 @@ from pypy.translator.cli import oopspec from pypy.rpython.ootypesystem import ootype -from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.oosupport.metavm import Generator, InstructionList, MicroInstruction,\ PushAllArgs, StoreResult, GetField, SetField, DownCast from pypy.translator.oosupport.metavm import _Call as _OOCall @@ -173,6 +173,16 @@ generator.load(v_obj) generator.ilasm.opcode('unbox.any', boxtype) +class _UnboxType(MicroInstruction): + def __init__(self, TO): + self.TO = TO + + def render(self, generator, op): + v_obj, = op.args + boxtype = generator.cts.lltype_to_cts(self.TO) + generator.load(v_obj) + generator.ilasm.opcode('unbox.any', boxtype) + class _NewArray(MicroInstruction): def render(self, generator, op): v_type, v_length = op.args @@ -312,6 +322,7 @@ #CastWeakAdrToPtr = _CastWeakAdrToPtr() Box = _Box() Unbox = _Unbox() +UnboxInt = _UnboxType(lltype.Signed) NewArray = _NewArray() GetArrayElem = _GetArrayElem() SetArrayElem = _SetArrayElem() diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py --- a/pypy/translator/cli/opcodes.py +++ b/pypy/translator/cli/opcodes.py @@ -2,7 +2,7 @@ IndirectCall, GetField, SetField, DownCast, NewCustomDict,\ MapException, Box, Unbox, NewArray, GetArrayElem, SetArrayElem,\ TypeOf, CastPrimitive, EventHandler, GetStaticField, SetStaticField, \ - DebugPrint + DebugPrint, UnboxInt from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult, InstructionList,\ New, RuntimeNew, CastTo, PushPrimitive, OOString, OOUnicode, OONewArray from pypy.translator.cli.cts import WEAKREF @@ -48,6 +48,8 @@ 'cast_from_object': [DownCast], 'clibox': [Box], 'cliunbox': [Unbox], + 'oobox_int': [Box], + 'oounbox_int': [UnboxInt], 'cli_newarray': [NewArray], 'cli_getelem': [GetArrayElem], 'cli_setelem': [SetArrayElem], @@ -92,6 +94,7 @@ 'debug_fatalerror': [PushAllArgs, 'call void [pypylib]pypy.runtime.Debug::DEBUG_FATALERROR(string)'], 'keepalive': Ignore, 'jit_marker': Ignore, + 'jit_force_quasi_immutable':Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, } diff --git a/pypy/translator/cli/test/test_int.py b/pypy/translator/cli/test/test_int.py --- a/pypy/translator/cli/test/test_int.py +++ b/pypy/translator/cli/test/test_int.py @@ -1,8 +1,8 @@ import py from pypy.translator.cli.test.runtest import CliTest -from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test -class TestCliInt(CliTest, BaseTestRint): +class TestCliInt(CliTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -77,6 +77,8 @@ 'oosend': [JvmCallMethod, StoreResult], 'ooupcast': DoNothing, 'oodowncast': [DownCast, StoreResult], + 'oobox_int': jvm.PYPYBOXINT, + 'oounbox_int': jvm.PYPYUNBOXINT, 'cast_to_object': DoNothing, 'cast_from_object': [DownCast, StoreResult], 'instanceof': [CastTo, StoreResult], diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -307,6 +307,14 @@ return result; } + public static Object box_integer(int x) { + return new Integer(x); + } + + public static int unbox_integer(Object o) { + Integer x = (Integer)o; + return x.intValue(); + } // Used in testing the JVM backend: // // A series of methods which serve a similar purpose to repr() in Python: diff --git a/pypy/translator/jvm/test/test_int.py b/pypy/translator/jvm/test/test_int.py --- a/pypy/translator/jvm/test/test_int.py +++ b/pypy/translator/jvm/test/test_int.py @@ -1,10 +1,11 @@ import py from pypy.translator.jvm.test.runtest import JvmTest from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test # ====> ../../../rpython/test/test_rint.py -class TestJvmInt(JvmTest, BaseTestRint): +class TestJvmInt(JvmTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/jvm/typesystem.py b/pypy/translator/jvm/typesystem.py --- a/pypy/translator/jvm/typesystem.py +++ b/pypy/translator/jvm/typesystem.py @@ -963,6 +963,8 @@ PYPYRUNTIMENEW = Method.s(jPyPy, 'RuntimeNew', (jClass,), jObject) PYPYSTRING2BYTES = Method.s(jPyPy, 'string2bytes', (jString,), jByteArray) PYPYARRAYTOLIST = Method.s(jPyPy, 'array_to_list', (jObjectArray,), jArrayList) +PYPYBOXINT = Method.s(jPyPy, 'box_integer', (jInt,), jObject) +PYPYUNBOXINT = Method.s(jPyPy, 'unbox_integer', (jObject,), jInt) PYPYOOPARSEFLOAT = Method.v(jPyPy, 'ooparse_float', (jString,), jDouble) OBJECTGETCLASS = Method.v(jObject, 'getClass', (), jClass) CLASSGETNAME = Method.v(jClass, 'getName', (), jString) diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py --- a/pypy/translator/oosupport/test_template/operations.py +++ b/pypy/translator/oosupport/test_template/operations.py @@ -1,3 +1,6 @@ +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype from pypy.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, ovfcheck from pypy.rlib import rstack from pypy.annotation import model as annmodel From noreply at buildbot.pypy.org Mon Jul 25 02:15:04 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 25 Jul 2011 02:15:04 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Merge default. Message-ID: <20110725001504.513958208C@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45955:7f3d2d819c7d Date: 2011-07-24 16:57 -0700 http://bitbucket.org/pypy/pypy/changeset/7f3d2d819c7d/ Log: Merge default. diff --git a/lib_pypy/pyrepl/unix_console.py b/lib_pypy/pyrepl/unix_console.py --- a/lib_pypy/pyrepl/unix_console.py +++ b/lib_pypy/pyrepl/unix_console.py @@ -384,14 +384,18 @@ self.__maybe_write_code(self._smkx) + try: self.old_sigwinch = signal.signal( signal.SIGWINCH, self.__sigwinch) + except ValueError: + pass def restore(self): self.__maybe_write_code(self._rmkx) self.flushoutput() tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate) + if hasattr(self, 'old_sigwinch'): signal.signal(signal.SIGWINCH, self.old_sigwinch) def __sigwinch(self, signum, frame): diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -2541,6 +2541,7 @@ class ASTVisitor(object): def visit_sequence(self, seq): + if seq is not None: for node in seq: node.walkabout(self) @@ -2673,33 +2674,25 @@ class GenericASTVisitor(ASTVisitor): def visit_Module(self, node): - if node.body: self.visit_sequence(node.body) def visit_Interactive(self, node): - if node.body: self.visit_sequence(node.body) def visit_Expression(self, node): node.body.walkabout(self) def visit_Suite(self, node): - if node.body: self.visit_sequence(node.body) def visit_FunctionDef(self, node): node.args.walkabout(self) - if node.body: self.visit_sequence(node.body) - if node.decorator_list: self.visit_sequence(node.decorator_list) def visit_ClassDef(self, node): - if node.bases: self.visit_sequence(node.bases) - if node.body: self.visit_sequence(node.body) - if node.decorator_list: self.visit_sequence(node.decorator_list) def visit_Return(self, node): @@ -2707,11 +2700,9 @@ node.value.walkabout(self) def visit_Delete(self, node): - if node.targets: self.visit_sequence(node.targets) def visit_Assign(self, node): - if node.targets: self.visit_sequence(node.targets) node.value.walkabout(self) @@ -2722,36 +2713,28 @@ def visit_Print(self, node): if node.dest: node.dest.walkabout(self) - if node.values: self.visit_sequence(node.values) def visit_For(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.body: self.visit_sequence(node.body) - if node.orelse: self.visit_sequence(node.orelse) def visit_While(self, node): node.test.walkabout(self) - if node.body: self.visit_sequence(node.body) - if node.orelse: self.visit_sequence(node.orelse) def visit_If(self, node): node.test.walkabout(self) - if node.body: self.visit_sequence(node.body) - if node.orelse: self.visit_sequence(node.orelse) def visit_With(self, node): node.context_expr.walkabout(self) if node.optional_vars: node.optional_vars.walkabout(self) - if node.body: self.visit_sequence(node.body) def visit_Raise(self, node): @@ -2763,17 +2746,12 @@ node.tback.walkabout(self) def visit_TryExcept(self, node): - if node.body: self.visit_sequence(node.body) - if node.handlers: self.visit_sequence(node.handlers) - if node.orelse: self.visit_sequence(node.orelse) def visit_TryFinally(self, node): - if node.body: self.visit_sequence(node.body) - if node.finalbody: self.visit_sequence(node.finalbody) def visit_Assert(self, node): @@ -2782,11 +2760,9 @@ node.msg.walkabout(self) def visit_Import(self, node): - if node.names: self.visit_sequence(node.names) def visit_ImportFrom(self, node): - if node.names: self.visit_sequence(node.names) def visit_Exec(self, node): @@ -2812,7 +2788,6 @@ pass def visit_BoolOp(self, node): - if node.values: self.visit_sequence(node.values) def visit_BinOp(self, node): @@ -2832,34 +2807,27 @@ node.orelse.walkabout(self) def visit_Dict(self, node): - if node.keys: self.visit_sequence(node.keys) - if node.values: self.visit_sequence(node.values) def visit_Set(self, node): - if node.elts: self.visit_sequence(node.elts) def visit_ListComp(self, node): node.elt.walkabout(self) - if node.generators: self.visit_sequence(node.generators) def visit_SetComp(self, node): node.elt.walkabout(self) - if node.generators: self.visit_sequence(node.generators) def visit_DictComp(self, node): node.key.walkabout(self) node.value.walkabout(self) - if node.generators: self.visit_sequence(node.generators) def visit_GeneratorExp(self, node): node.elt.walkabout(self) - if node.generators: self.visit_sequence(node.generators) def visit_Yield(self, node): @@ -2868,14 +2836,11 @@ def visit_Compare(self, node): node.left.walkabout(self) - if node.comparators: self.visit_sequence(node.comparators) def visit_Call(self, node): node.func.walkabout(self) - if node.args: self.visit_sequence(node.args) - if node.keywords: self.visit_sequence(node.keywords) if node.starargs: node.starargs.walkabout(self) @@ -2902,11 +2867,9 @@ pass def visit_List(self, node): - if node.elts: self.visit_sequence(node.elts) def visit_Tuple(self, node): - if node.elts: self.visit_sequence(node.elts) def visit_Const(self, node): @@ -2924,7 +2887,6 @@ node.step.walkabout(self) def visit_ExtSlice(self, node): - if node.dims: self.visit_sequence(node.dims) def visit_Index(self, node): @@ -2933,7 +2895,6 @@ def visit_comprehension(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.ifs: self.visit_sequence(node.ifs) def visit_ExceptHandler(self, node): @@ -2941,13 +2902,10 @@ node.type.walkabout(self) if node.name: node.name.walkabout(self) - if node.body: self.visit_sequence(node.body) def visit_arguments(self, node): - if node.args: self.visit_sequence(node.args) - if node.defaults: self.visit_sequence(node.defaults) def visit_keyword(self, node): @@ -3069,6 +3027,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 _Expression_field_unroller = unrolling_iterable(['body']) @@ -3157,6 +3116,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def stmt_get_col_offset(space, w_self): @@ -3178,6 +3138,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask stmt.typedef = typedef.TypeDef("stmt", @@ -3208,6 +3169,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def FunctionDef_get_args(space, w_self): @@ -3229,6 +3191,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 2 def FunctionDef_get_body(space, w_self): @@ -3315,6 +3278,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def ClassDef_get_bases(space, w_self): @@ -3420,6 +3384,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Return_field_unroller = unrolling_iterable(['value']) @@ -3526,6 +3491,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _Assign_field_unroller = unrolling_iterable(['targets', 'value']) @@ -3573,6 +3539,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def AugAssign_get_op(space, w_self): @@ -3590,13 +3557,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def AugAssign_get_value(space, w_self): @@ -3618,6 +3585,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 4 _AugAssign_field_unroller = unrolling_iterable(['target', 'op', 'value']) @@ -3665,6 +3633,7 @@ raise w_self.setdictvalue(space, 'dest', w_new_value) return + w_self.deldictvalue(space, 'dest') w_self.initialization_state |= 1 def Print_get_values(space, w_self): @@ -3704,6 +3673,7 @@ raise w_self.setdictvalue(space, 'nl', w_new_value) return + w_self.deldictvalue(space, 'nl') w_self.initialization_state |= 4 _Print_field_unroller = unrolling_iterable(['dest', 'values', 'nl']) @@ -3752,6 +3722,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def For_get_iter(space, w_self): @@ -3773,6 +3744,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def For_get_body(space, w_self): @@ -3859,6 +3831,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def While_get_body(space, w_self): @@ -3944,6 +3917,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def If_get_body(space, w_self): @@ -4029,6 +4003,7 @@ raise w_self.setdictvalue(space, 'context_expr', w_new_value) return + w_self.deldictvalue(space, 'context_expr') w_self.initialization_state |= 1 def With_get_optional_vars(space, w_self): @@ -4050,6 +4025,7 @@ raise w_self.setdictvalue(space, 'optional_vars', w_new_value) return + w_self.deldictvalue(space, 'optional_vars') w_self.initialization_state |= 2 def With_get_body(space, w_self): @@ -4116,6 +4092,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def Raise_get_inst(space, w_self): @@ -4137,6 +4114,7 @@ raise w_self.setdictvalue(space, 'inst', w_new_value) return + w_self.deldictvalue(space, 'inst') w_self.initialization_state |= 2 def Raise_get_tback(space, w_self): @@ -4158,6 +4136,7 @@ raise w_self.setdictvalue(space, 'tback', w_new_value) return + w_self.deldictvalue(space, 'tback') w_self.initialization_state |= 4 _Raise_field_unroller = unrolling_iterable(['type', 'inst', 'tback']) @@ -4351,6 +4330,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def Assert_get_msg(space, w_self): @@ -4372,6 +4352,7 @@ raise w_self.setdictvalue(space, 'msg', w_new_value) return + w_self.deldictvalue(space, 'msg') w_self.initialization_state |= 2 _Assert_field_unroller = unrolling_iterable(['test', 'msg']) @@ -4464,6 +4445,7 @@ raise w_self.setdictvalue(space, 'module', w_new_value) return + w_self.deldictvalue(space, 'module') w_self.initialization_state |= 1 def ImportFrom_get_names(space, w_self): @@ -4503,6 +4485,7 @@ raise w_self.setdictvalue(space, 'level', w_new_value) return + w_self.deldictvalue(space, 'level') w_self.initialization_state |= 4 _ImportFrom_field_unroller = unrolling_iterable(['module', 'names', 'level']) @@ -4551,6 +4534,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 def Exec_get_globals(space, w_self): @@ -4572,6 +4556,7 @@ raise w_self.setdictvalue(space, 'globals', w_new_value) return + w_self.deldictvalue(space, 'globals') w_self.initialization_state |= 2 def Exec_get_locals(space, w_self): @@ -4593,6 +4578,7 @@ raise w_self.setdictvalue(space, 'locals', w_new_value) return + w_self.deldictvalue(space, 'locals') w_self.initialization_state |= 4 _Exec_field_unroller = unrolling_iterable(['body', 'globals', 'locals']) @@ -4683,6 +4669,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Expr_field_unroller = unrolling_iterable(['value']) @@ -4779,6 +4766,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def expr_get_col_offset(space, w_self): @@ -4800,6 +4788,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask expr.typedef = typedef.TypeDef("expr", @@ -4826,13 +4815,13 @@ try: obj = space.interp_w(boolop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def BoolOp_get_values(space, w_self): @@ -4898,6 +4887,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def BinOp_get_op(space, w_self): @@ -4915,13 +4905,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def BinOp_get_right(space, w_self): @@ -4943,6 +4933,7 @@ raise w_self.setdictvalue(space, 'right', w_new_value) return + w_self.deldictvalue(space, 'right') w_self.initialization_state |= 4 _BinOp_field_unroller = unrolling_iterable(['left', 'op', 'right']) @@ -4986,13 +4977,13 @@ try: obj = space.interp_w(unaryop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def UnaryOp_get_operand(space, w_self): @@ -5014,6 +5005,7 @@ raise w_self.setdictvalue(space, 'operand', w_new_value) return + w_self.deldictvalue(space, 'operand') w_self.initialization_state |= 2 _UnaryOp_field_unroller = unrolling_iterable(['op', 'operand']) @@ -5060,6 +5052,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 1 def Lambda_get_body(space, w_self): @@ -5081,6 +5074,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 _Lambda_field_unroller = unrolling_iterable(['args', 'body']) @@ -5127,6 +5121,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def IfExp_get_body(space, w_self): @@ -5148,6 +5143,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 def IfExp_get_orelse(space, w_self): @@ -5169,6 +5165,7 @@ raise w_self.setdictvalue(space, 'orelse', w_new_value) return + w_self.deldictvalue(space, 'orelse') w_self.initialization_state |= 4 _IfExp_field_unroller = unrolling_iterable(['test', 'body', 'orelse']) @@ -5322,6 +5319,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def ListComp_get_generators(space, w_self): @@ -5387,6 +5385,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def SetComp_get_generators(space, w_self): @@ -5452,6 +5451,7 @@ raise w_self.setdictvalue(space, 'key', w_new_value) return + w_self.deldictvalue(space, 'key') w_self.initialization_state |= 1 def DictComp_get_value(space, w_self): @@ -5473,6 +5473,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 def DictComp_get_generators(space, w_self): @@ -5539,6 +5540,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def GeneratorExp_get_generators(space, w_self): @@ -5604,6 +5606,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Yield_field_unroller = unrolling_iterable(['value']) @@ -5649,6 +5652,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def Compare_get_ops(space, w_self): @@ -5734,6 +5738,7 @@ raise w_self.setdictvalue(space, 'func', w_new_value) return + w_self.deldictvalue(space, 'func') w_self.initialization_state |= 1 def Call_get_args(space, w_self): @@ -5791,6 +5796,7 @@ raise w_self.setdictvalue(space, 'starargs', w_new_value) return + w_self.deldictvalue(space, 'starargs') w_self.initialization_state |= 8 def Call_get_kwargs(space, w_self): @@ -5812,6 +5818,7 @@ raise w_self.setdictvalue(space, 'kwargs', w_new_value) return + w_self.deldictvalue(space, 'kwargs') w_self.initialization_state |= 16 _Call_field_unroller = unrolling_iterable(['func', 'args', 'keywords', 'starargs', 'kwargs']) @@ -5863,6 +5870,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Repr_field_unroller = unrolling_iterable(['value']) @@ -5908,6 +5916,7 @@ raise w_self.setdictvalue(space, 'n', w_new_value) return + w_self.deldictvalue(space, 'n') w_self.initialization_state |= 1 _Num_field_unroller = unrolling_iterable(['n']) @@ -5953,6 +5962,7 @@ raise w_self.setdictvalue(space, 's', w_new_value) return + w_self.deldictvalue(space, 's') w_self.initialization_state |= 1 _Str_field_unroller = unrolling_iterable(['s']) @@ -5998,6 +6008,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Attribute_get_attr(space, w_self): @@ -6019,6 +6030,7 @@ raise w_self.setdictvalue(space, 'attr', w_new_value) return + w_self.deldictvalue(space, 'attr') w_self.initialization_state |= 2 def Attribute_get_ctx(space, w_self): @@ -6036,13 +6048,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Attribute_field_unroller = unrolling_iterable(['value', 'attr', 'ctx']) @@ -6090,6 +6102,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Subscript_get_slice(space, w_self): @@ -6111,6 +6124,7 @@ raise w_self.setdictvalue(space, 'slice', w_new_value) return + w_self.deldictvalue(space, 'slice') w_self.initialization_state |= 2 def Subscript_get_ctx(space, w_self): @@ -6128,13 +6142,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Subscript_field_unroller = unrolling_iterable(['value', 'slice', 'ctx']) @@ -6182,6 +6196,7 @@ raise w_self.setdictvalue(space, 'id', w_new_value) return + w_self.deldictvalue(space, 'id') w_self.initialization_state |= 1 def Name_get_ctx(space, w_self): @@ -6199,13 +6214,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Name_field_unroller = unrolling_iterable(['id', 'ctx']) @@ -6266,13 +6281,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _List_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6334,13 +6349,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Tuple_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6388,6 +6403,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Const_field_unroller = unrolling_iterable(['value']) @@ -6506,6 +6522,7 @@ raise w_self.setdictvalue(space, 'lower', w_new_value) return + w_self.deldictvalue(space, 'lower') w_self.initialization_state |= 1 def Slice_get_upper(space, w_self): @@ -6527,6 +6544,7 @@ raise w_self.setdictvalue(space, 'upper', w_new_value) return + w_self.deldictvalue(space, 'upper') w_self.initialization_state |= 2 def Slice_get_step(space, w_self): @@ -6548,6 +6566,7 @@ raise w_self.setdictvalue(space, 'step', w_new_value) return + w_self.deldictvalue(space, 'step') w_self.initialization_state |= 4 _Slice_field_unroller = unrolling_iterable(['lower', 'upper', 'step']) @@ -6638,6 +6657,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Index_field_unroller = unrolling_iterable(['value']) @@ -6907,6 +6927,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def comprehension_get_iter(space, w_self): @@ -6928,6 +6949,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def comprehension_get_ifs(space, w_self): @@ -6994,6 +7016,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def excepthandler_get_col_offset(space, w_self): @@ -7015,6 +7038,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask excepthandler.typedef = typedef.TypeDef("excepthandler", @@ -7045,6 +7069,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def ExceptHandler_get_name(space, w_self): @@ -7066,6 +7091,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 2 def ExceptHandler_get_body(space, w_self): @@ -7153,6 +7179,7 @@ raise w_self.setdictvalue(space, 'vararg', w_new_value) return + w_self.deldictvalue(space, 'vararg') w_self.initialization_state |= 2 def arguments_get_kwarg(space, w_self): @@ -7177,6 +7204,7 @@ raise w_self.setdictvalue(space, 'kwarg', w_new_value) return + w_self.deldictvalue(space, 'kwarg') w_self.initialization_state |= 4 def arguments_get_defaults(space, w_self): @@ -7245,6 +7273,7 @@ raise w_self.setdictvalue(space, 'arg', w_new_value) return + w_self.deldictvalue(space, 'arg') w_self.initialization_state |= 1 def keyword_get_value(space, w_self): @@ -7266,6 +7295,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _keyword_field_unroller = unrolling_iterable(['arg', 'value']) @@ -7312,6 +7342,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def alias_get_asname(space, w_self): @@ -7336,6 +7367,7 @@ raise w_self.setdictvalue(space, 'asname', w_new_value) return + w_self.deldictvalue(space, 'asname') w_self.initialization_state |= 2 _alias_field_unroller = unrolling_iterable(['name', 'asname']) diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -295,15 +295,11 @@ def visit_FunctionDef(self, func): self.update_position(func.lineno, True) # Load decorators first, but apply them after the function is created. - if func.decorator_list: self.visit_sequence(func.decorator_list) args = func.args assert isinstance(args, ast.arguments) - if args.defaults: self.visit_sequence(args.defaults) - num_defaults = len(args.defaults) - else: - num_defaults = 0 + num_defaults = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(FunctionCodeGenerator, func.name, func, func.lineno) self._make_function(code, num_defaults) @@ -317,24 +313,17 @@ self.update_position(lam.lineno) args = lam.args assert isinstance(args, ast.arguments) - if args.defaults: self.visit_sequence(args.defaults) - default_count = len(args.defaults) - else: - default_count = 0 + default_count = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(LambdaCodeGenerator, "", lam, lam.lineno) self._make_function(code, default_count) def visit_ClassDef(self, cls): self.update_position(cls.lineno, True) - if cls.decorator_list: self.visit_sequence(cls.decorator_list) self.load_const(self.space.wrap(cls.name)) - if cls.bases: - bases_count = len(cls.bases) self.visit_sequence(cls.bases) - else: - bases_count = 0 + bases_count = len(cls.bases) if cls.bases is not None else 0 self.emit_op_arg(ops.BUILD_TUPLE, bases_count) code = self.sub_scope(ClassCodeGenerator, cls.name, cls, cls.lineno) self._make_function(code, 0) @@ -446,7 +435,6 @@ end = self.new_block() test_constant = if_.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if if_.orelse: self.visit_sequence(if_.orelse) elif test_constant == optimize.CONST_TRUE: self.visit_sequence(if_.body) @@ -515,7 +503,6 @@ self.use_next_block(cleanup) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, start) - if fr.orelse: self.visit_sequence(fr.orelse) self.use_next_block(end) @@ -523,7 +510,6 @@ self.update_position(wh.lineno, True) test_constant = wh.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if wh.orelse: self.visit_sequence(wh.orelse) else: end = self.new_block() @@ -544,7 +530,6 @@ self.use_next_block(anchor) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, loop) - if wh.orelse: self.visit_sequence(wh.orelse) self.use_next_block(end) @@ -581,7 +566,6 @@ self.use_next_block(next_except) self.emit_op(ops.END_FINALLY) self.use_next_block(otherwise) - if te.orelse: self.visit_sequence(te.orelse) self.use_next_block(end) @@ -893,26 +877,18 @@ def visit_Tuple(self, tup): self.update_position(tup.lineno) - if tup.elts: - elt_count = len(tup.elts) - else: - elt_count = 0 + elt_count = len(tup.elts) if tup.elts is not None else 0 if tup.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: self.visit_sequence(tup.elts) if tup.ctx == ast.Load: self.emit_op_arg(ops.BUILD_TUPLE, elt_count) def visit_List(self, l): self.update_position(l.lineno) - if l.elts: - elt_count = len(l.elts) - else: - elt_count = 0 + elt_count = len(l.elts) if l.elts is not None else 0 if l.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: self.visit_sequence(l.elts) if l.ctx == ast.Load: self.emit_op_arg(ops.BUILD_LIST, elt_count) @@ -944,10 +920,8 @@ if self._optimize_method_call(call): return call.func.walkabout(self) - arg = 0 + arg = len(call.args) if call.args is not None else 0 call_type = 0 - if call.args: - arg = len(call.args) self.visit_sequence(call.args) if call.keywords: self.visit_sequence(call.keywords) @@ -984,16 +958,10 @@ assert isinstance(attr_lookup, ast.Attribute) attr_lookup.value.walkabout(self) self.emit_op_name(ops.LOOKUP_METHOD, self.names, attr_lookup.attr) - if call.args: self.visit_sequence(call.args) - arg_count = len(call.args) - else: - arg_count = 0 - if call.keywords: + arg_count = len(call.args) if call.args is not None else 0 self.visit_sequence(call.keywords) - kwarg_count = len(call.keywords) - else: - kwarg_count = 0 + kwarg_count = len(call.keywords) if call.keywords is not None else 0 self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) | arg_count) return True @@ -1251,7 +1219,10 @@ def _compile(self, func): assert isinstance(func, ast.FunctionDef) # If there's a docstring, store it as the first constant. + if func.body: doc_expr = self.possible_docstring(func.body[0]) + else: + doc_expr = None if doc_expr is not None: self.add_const(doc_expr.s) start = 1 @@ -1263,6 +1234,7 @@ if args.args: self._handle_nested_args(args.args) self.argcount = len(args.args) + if func.body: for i in range(start, len(func.body)): func.body[i].walkabout(self) diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py --- a/pypy/interpreter/astcompiler/symtable.py +++ b/pypy/interpreter/astcompiler/symtable.py @@ -356,9 +356,7 @@ # Function defaults and decorators happen in the outer scope. args = func.args assert isinstance(args, ast.arguments) - if args.defaults: self.visit_sequence(args.defaults) - if func.decorator_list: self.visit_sequence(func.decorator_list) new_scope = FunctionScope(func.name, func.lineno, func.col_offset) self.push_scope(new_scope, func) @@ -372,9 +370,7 @@ def visit_ClassDef(self, clsdef): self.note_symbol(clsdef.name, SYM_ASSIGNED) - if clsdef.bases: self.visit_sequence(clsdef.bases) - if clsdef.decorator_list: self.visit_sequence(clsdef.decorator_list) self.push_scope(ClassScope(clsdef), clsdef) self.visit_sequence(clsdef.body) @@ -431,7 +427,6 @@ def visit_Lambda(self, lamb): args = lamb.args assert isinstance(args, ast.arguments) - if args.defaults: self.visit_sequence(args.defaults) new_scope = FunctionScope("lambda", lamb.lineno, lamb.col_offset) self.push_scope(new_scope, lamb) @@ -447,7 +442,6 @@ self.push_scope(new_scope, node) self.implicit_arg(0) outer.target.walkabout(self) - if outer.ifs: self.visit_sequence(outer.ifs) self.visit_sequence(comps[1:]) for item in list(consider): diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -221,8 +221,9 @@ self.emit("class ASTVisitor(object):") self.emit("") self.emit("def visit_sequence(self, seq):", 1) - self.emit("for node in seq:", 2) - self.emit("node.walkabout(self)", 3) + self.emit("if seq is not None:", 2) + self.emit("for node in seq:", 3) + self.emit("node.walkabout(self)", 4) self.emit("") self.emit("def default_visitor(self, node):", 1) self.emit("raise NodeVisitorNotImplemented", 2) @@ -280,15 +281,13 @@ def visitField(self, field): if field.type.value not in asdl.builtin_types and \ field.type.value not in self.data.simple_types: - if field.seq or field.opt: + level = 2 + template = "node.%s.walkabout(self)" + if field.seq: + template = "self.visit_sequence(node.%s)" + elif field.opt: self.emit("if node.%s:" % (field.name,), 2) level = 3 - else: - level = 2 - if field.seq: - template = "self.visit_sequence(node.%s)" - else: - template = "node.%s.walkabout(self)" self.emit(template % (field.name,), level) return True return False @@ -446,6 +445,7 @@ if field.seq: self.emit("w_self.w_%s = w_new_value" % (field.name,), 1) else: + save_original_object = False self.emit("try:", 1) if field.type.value not in asdl.builtin_types: # These are always other AST nodes. @@ -454,9 +454,7 @@ (field.type,), 2) self.emit("w_self.%s = obj.to_simple_int(space)" % (field.name,), 2) - self.emit("# need to save the original object too", 2) - self.emit("w_self.setdictvalue(space, '%s', w_new_value)" - % (field.name,), 2) + save_original_object = True else: config = (field.name, field.type, repr(field.opt)) self.emit("w_self.%s = space.interp_w(%s, w_new_value, %s)" % @@ -480,6 +478,12 @@ self.emit(" w_self.setdictvalue(space, '%s', w_new_value)" % (field.name,), 1) self.emit(" return", 1) + if save_original_object: + self.emit("# need to save the original object too", 1) + self.emit("w_self.setdictvalue(space, '%s', w_new_value)" + % (field.name,), 1) + else: + self.emit("w_self.deldictvalue(space, '%s')" %(field.name,), 1) self.emit("w_self.initialization_state |= %s" % (flag,), 1) self.emit("") diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -44,11 +44,11 @@ return True return False - def deldictvalue(self, space, w_name): + def deldictvalue(self, space, attr): w_dict = self.getdict(space) if w_dict is not None: try: - space.delitem(w_dict, w_name) + space.delitem(w_dict, space.wrap(attr)) return True except OperationError, ex: if not ex.match(space, space.w_KeyError): diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -189,7 +189,7 @@ if space.is_w(w_value, space.w_None): # raise Type: we assume we have to instantiate Type w_value = space.call_function(w_type) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: w_valuetype = space.exception_getclass(w_value) if space.exception_issubclass_w(w_valuetype, w_type): @@ -204,18 +204,12 @@ else: # raise Type, X: assume X is the constructor argument w_value = space.call_function(w_type, w_value) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: # the only case left here is (inst, None), from a 'raise inst'. w_inst = w_type - w_instclass = space.exception_getclass(w_inst) - if not space.exception_is_valid_class_w(w_instclass): - instclassname = w_instclass.getname(space) - msg = ("exceptions must be old-style classes or derived " - "from BaseException, not %s") - raise operationerrfmt(space.w_TypeError, msg, instclassname) - + w_instclass = self._exception_getclass(space, w_inst) if not space.is_w(w_value, space.w_None): raise OperationError(space.w_TypeError, space.wrap("instance exception may not " @@ -226,6 +220,15 @@ self.w_type = w_type self._w_value = w_value + def _exception_getclass(self, space, w_inst): + w_type = space.exception_getclass(w_inst) + if not space.exception_is_valid_class_w(w_type): + typename = w_type.getname(space) + msg = ("exceptions must be old-style classes or derived " + "from BaseException, not %s") + raise operationerrfmt(space.w_TypeError, msg, typename) + return w_type + def write_unraisable(self, space, where, w_object=None): if w_object is None: objrepr = '' diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -905,16 +905,15 @@ def SETUP_WITH(self, offsettoend, next_instr): w_manager = self.peekvalue() + w_enter = self.space.lookup(w_manager, "__enter__") w_descr = self.space.lookup(w_manager, "__exit__") - if w_descr is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__exit__")) + if w_enter is None or w_descr is None: + typename = self.space.type(w_manager).getname(self.space) + raise operationerrfmt(self.space.w_AttributeError, + "'%s' object is not a context manager" + " (no __enter__/__exit__ method)", typename) w_exit = self.space.get(w_descr, w_manager) self.settopvalue(w_exit) - w_enter = self.space.lookup(w_manager, "__enter__") - if w_enter is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__enter__")) w_result = self.space.get_and_call_function(w_enter, w_manager) block = WithBlock(self, next_instr + offsettoend) self.append_block(block) diff --git a/pypy/interpreter/test/test_raise.py b/pypy/interpreter/test/test_raise.py --- a/pypy/interpreter/test/test_raise.py +++ b/pypy/interpreter/test/test_raise.py @@ -274,3 +274,9 @@ pass except A: pass + + def test_new_returns_bad_instance(self): + class MyException(Exception): + def __new__(cls, *args): + return object() + raises(TypeError, "raise MyException") diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -56,6 +56,8 @@ # for resume.py operation self.parent_resumedata_snapshot = None self.parent_resumedata_frame_info_list = None + # counter for unrolling inlined loops + self.unroll_iterations = 1 @specialize.arg(3) def copy_constants(self, registers, constants, ConstClass): @@ -931,6 +933,10 @@ # 'redboxes' back into the registers where it comes from. put_back_list_of_boxes3(self, jcposition, redboxes) else: + if jitdriver_sd.warmstate.should_unroll_one_iteration(greenboxes): + if self.unroll_iterations > 0: + self.unroll_iterations -= 1 + return # warning! careful here. We have to return from the current # frame containing the jit_merge_point, and then use # do_recursive_call() to follow the recursive call. This is @@ -1162,12 +1168,10 @@ metainterp.jitdriver_sd.greenfield_info is not None): virtualizable_boxes = metainterp.virtualizable_boxes saved_pc = self.pc - try: if resumepc >= 0: self.pc = resumepc resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, metainterp.virtualref_boxes, resumedescr) - finally: self.pc = saved_pc def implement_guard_value(self, orgpc, box): diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -508,6 +508,32 @@ assert res == 84 - 61 - 62 self.check_history(call=1) # because the trace starts immediately + def test_unroll_one_loop_iteration(self): + def unroll(code): + return code == 0 + myjitdriver = JitDriver(greens = ['code'], + reds = ['loops', 'inner_loops', 's'], + should_unroll_one_iteration=unroll) + + def f(code, loops, inner_loops): + s = 0 + while loops > 0: + myjitdriver.jit_merge_point(code=code, loops=loops, + inner_loops=inner_loops, s=s) + if code == 1: + s += f(0, inner_loops, 0) + loops -= 1 + s += 1 + return s + + res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True) + assert res == f(1, 4, 1) + self.check_history(call_assembler=0) + + res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True) + assert res == f(1, 4, 2) + self.check_history(call_assembler=1) + def test_format(self): def f(n): return len("<%d>" % n) diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -468,6 +468,9 @@ onlygreens=False) jd._can_never_inline_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool) + jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd, + annhelper, jd.jitdriver.should_unroll_one_iteration, + annmodel.s_Bool) annhelper.finish() def _make_hook_graph(self, jitdriver_sd, annhelper, func, diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -572,6 +572,19 @@ return can_inline_greenargs(*greenargs) self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + + if jd._should_unroll_one_iteration_ptr is None: + def should_unroll_one_iteration(greenkey): + return False + else: + rtyper = self.warmrunnerdesc.rtyper + inline_ptr = jd._should_unroll_one_iteration_ptr + def should_unroll_one_iteration(greenkey): + greenargs = unwrap_greenkey(greenkey) + fn = support.maybe_on_top_of_llinterp(rtyper, inline_ptr) + return fn(*greenargs) + self.should_unroll_one_iteration = should_unroll_one_iteration + if hasattr(jd.jitdriver, 'on_compile'): def on_compile(logger, token, operations, type, greenkey): greenargs = unwrap_greenkey(greenkey) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -418,7 +418,7 @@ if w_meth is not None: space.call_function(w_meth, w_name) else: - if not self.deldictvalue(space, w_name): + if not self.deldictvalue(space, name): raise operationerrfmt( space.w_AttributeError, "%s instance has no attribute '%s'", diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -250,3 +250,38 @@ assert x.left == n1 assert x.op == addop assert x.right == n3 + + def test_functiondef(self): + import _ast as ast + fAst = ast.FunctionDef( + name="foo", + args=ast.arguments( + args=[], vararg=None, kwarg=None, defaults=[], + kwonlyargs=[], kw_defaults=[]), + body=[], decorator_list=[], lineno=5, col_offset=0) + exprAst = ast.Interactive(body=[fAst]) + compiled = compile(exprAst, "", "single") + # + d = {} + eval(compiled, d, d) + assert type(d['foo']) is type(lambda: 42) + assert d['foo']() is None + + def test_missing_name(self): + import _ast as ast + n = ast.FunctionDef(name=None) + n.name = "foo" + n.name = "foo" + n.name = "foo" + assert n.name == "foo" + + def test_issue793(self): + import _ast as ast + body = ast.Module([ + ast.TryExcept([ast.Pass(lineno=2, col_offset=4)], + [ast.ExceptHandler(ast.Name('Exception', ast.Load(), + lineno=3, col_offset=0), + None, [], lineno=4, col_offset=0)], + [], lineno=1, col_offset=0) + ]) + exec compile(body, '', 'exec') diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -379,16 +379,23 @@ self.start = -1 else: # all following calls consume = self.step + if consume > 1: + self._ignore_items(consume-1) if self.stop >= 0: if self.stop < consume: + self.stop = 0 # reset the state so that a following next_w() + self.step = 1 # has no effect any more raise OperationError(self.space.w_StopIteration, self.space.w_None) self.stop -= consume + return self.space.next(self.iterable) + + def _ignore_items(self, num): while True: - w_obj = self.space.next(self.iterable) - consume -= 1 - if consume <= 0: - return w_obj + self.space.next(self.iterable) + num -= 1 + if num <= 0: + break def W_ISlice___new__(space, w_subtype, w_iterable, w_startstop, args_w): r = space.allocate_instance(W_ISlice, w_subtype) diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -227,6 +227,45 @@ assert list(itertools.islice(xrange(10), None,None)) == range(10) assert list(itertools.islice(xrange(10), None,None,None)) == range(10) + def test_islice_dropitems_exact(self): + import itertools + + it = iter("abcdefghij") + itertools.islice(it, 2, 2) # doesn't eagerly drop anything + assert it.next() == "a" + itertools.islice(it, 3, 8, 2) # doesn't eagerly drop anything + assert it.next() == "b" + assert it.next() == "c" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 2, 3), None) # drops 2 items + assert x == "c" + assert it.next() == "d" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 3, 8, 2), None) # drops 3 items + assert x == "d" + assert it.next() == "e" + + it = iter("abcdefghij") + x = next(itertools.islice(it, None, 8), None) # drops 0 items + assert x == "a" + assert it.next() == "b" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 3, 2), None) # drops 3 items + assert x is None + assert it.next() == "d" + + it = iter("abcdefghij") + islc = itertools.islice(it, 3, 7, 2) + assert islc.next() == "d" # drops 0, 1, 2, returns item #3 + assert it.next() == "e" + assert islc.next() == "g" # drops the 4th and return item #5 + assert it.next() == "h" + raises(StopIteration, islc.next) # drops the 6th and raise + assert it.next() == "j" + def test_islice_overflow(self): import itertools import sys diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -44,9 +44,11 @@ ec.w_tracefunc is None) def can_never_inline(next_instr, is_being_profiled, bytecode): + return False + +def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode): return (bytecode.co_flags & CO_GENERATOR) != 0 - def wrap_oplist(space, logops, operations): list_w = [] for op in operations: @@ -110,7 +112,9 @@ get_jitcell_at = get_jitcell_at, set_jitcell_at = set_jitcell_at, confirm_enter_jit = confirm_enter_jit, - can_never_inline = can_never_inline) + can_never_inline = can_never_inline, + should_unroll_one_iteration = + should_unroll_one_iteration) class __extend__(PyFrame): diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py @@ -0,0 +1,25 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGenerators(BaseTestPyPyC): + def test_simple_generator(self): + def main(n): + def f(): + for i in range(10000): + yield i + + def g(): + for i in f(): # ID: generator + pass + + g() + + log = self.run(main, [500]) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("generator", """ + i16 = force_token() + p45 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p45, i29, descr=) + setarrayitem_gc(p8, 0, p45, descr=) + jump(..., descr=...) + """) diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -96,7 +96,7 @@ if space.is_data_descr(w_descr): space.delete(w_descr, w_obj) return - if w_obj.deldictvalue(space, w_name): + if w_obj.deldictvalue(space, name): return raiseattrerror(space, w_obj, name, w_descr) diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -61,7 +61,8 @@ space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): + key = self.space.str_w(w_key) + if not self.unerase(w_dict.dstorage).deldictvalue(space, key): raise KeyError else: raise KeyError diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -369,8 +369,7 @@ def setdictvalue(self, space, attrname, w_value): return self._get_mapdict_map().write(self, (attrname, DICT), w_value) - def deldictvalue(self, space, w_name): - attrname = space.str_w(w_name) + def deldictvalue(self, space, attrname): new_obj = self._get_mapdict_map().delete(self, (attrname, DICT)) if new_obj is None: return False @@ -647,7 +646,8 @@ w_key_type = space.type(w_key) w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = w_obj.deldictvalue(space, w_key) + key = self.space.str_w(w_key) + flag = w_obj.deldictvalue(space, key) if not flag: raise KeyError elif _never_equal_to_string(space, w_key_type): diff --git a/pypy/objspace/std/proxyobject.py b/pypy/objspace/std/proxyobject.py --- a/pypy/objspace/std/proxyobject.py +++ b/pypy/objspace/std/proxyobject.py @@ -52,10 +52,10 @@ raise return False - def deldictvalue(self, space, w_attr): + def deldictvalue(self, space, attr): try: space.call_function(self.w_controller, space.wrap('__delattr__'), - w_attr) + space.wrap(attr)) return True except OperationError, e: if not e.match(space, space.w_AttributeError): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -313,10 +313,9 @@ w_self.dict_w[name] = w_value return True - def deldictvalue(w_self, space, w_key): + def deldictvalue(w_self, space, key): if w_self.lazyloaders: w_self._freeze_() # force un-lazification - key = space.str_w(w_key) if (not space.config.objspace.std.mutable_builtintypes and not w_self.is_heaptype()): msg = "can't delete attributes on type object '%s'" diff --git a/pypy/objspace/std/typetype.py b/pypy/objspace/std/typetype.py --- a/pypy/objspace/std/typetype.py +++ b/pypy/objspace/std/typetype.py @@ -226,7 +226,7 @@ def descr_del___abstractmethods__(space, w_type): w_type = _check(space, w_type) - if not w_type.deldictvalue(space, space.wrap("__abstractmethods__")): + if not w_type.deldictvalue(space, "__abstractmethods__"): raise OperationError(space.w_AttributeError, space.wrap("__abstractmethods__")) w_type.set_abstract(False) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -315,7 +315,7 @@ def __init__(self, greens=None, reds=None, virtualizables=None, get_jitcell_at=None, set_jitcell_at=None, get_printable_location=None, confirm_enter_jit=None, - can_never_inline=None): + can_never_inline=None, should_unroll_one_iteration=None): if greens is not None: self.greens = greens if reds is not None: @@ -334,6 +334,7 @@ self.get_printable_location = get_printable_location self.confirm_enter_jit = confirm_enter_jit self.can_never_inline = can_never_inline + self.should_unroll_one_iteration = should_unroll_one_iteration def _freeze_(self): return True diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -40,7 +40,7 @@ # In that case, do 5 bits at a time. The potential drawback is that # a table of 2**5 intermediate results is computed. -FIVEARY_CUTOFF = 8 +## FIVEARY_CUTOFF = 8 disabled for now def _mask_digit(x): @@ -456,7 +456,7 @@ # python adaptation: moved macros REDUCE(X) and MULT(X, Y, result) # into helper function result = _help_mult(x, y, c) - if b.numdigits() <= FIVEARY_CUTOFF: + if 1: ## b.numdigits() <= FIVEARY_CUTOFF: # Left-to-right binary exponentiation (HAC Algorithm 14.79) # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf i = b.numdigits() - 1 @@ -469,26 +469,30 @@ z = _help_mult(z, a, c) j >>= 1 i -= 1 - else: - # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) - # This is only useful in the case where c != None. - # z still holds 1L - table = [z] * 32 - table[0] = z - for i in range(1, 32): - table[i] = _help_mult(table[i-1], a, c) - i = b.numdigits() - 1 - while i >= 0: - bi = b.digit(i) - j = SHIFT - 5 - while j >= 0: - index = (bi >> j) & 0x1f - for k in range(5): - z = _help_mult(z, z, c) - if index: - z = _help_mult(z, table[index], c) - j -= 5 - i -= 1 +## else: +## This code is disabled for now, because it assumes that +## SHIFT is a multiple of 5. It could be fixed but it looks +## like it's more troubles than benefits... +## +## # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) +## # This is only useful in the case where c != None. +## # z still holds 1L +## table = [z] * 32 +## table[0] = z +## for i in range(1, 32): +## table[i] = _help_mult(table[i-1], a, c) +## i = b.numdigits() - 1 +## while i >= 0: +## bi = b.digit(i) +## j = SHIFT - 5 +## while j >= 0: +## index = (bi >> j) & 0x1f +## for k in range(5): +## z = _help_mult(z, z, c) +## if index: +## z = _help_mult(z, table[index], c) +## j -= 5 +## i -= 1 if negativeOutput and z.sign != 0: z = z.sub(c) diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py --- a/pypy/rlib/test/test_rbigint.py +++ b/pypy/rlib/test/test_rbigint.py @@ -373,6 +373,13 @@ print '--->', v assert v.tolong() == pow(x, y, z) + def test_pow_lll_bug(self): + two = rbigint.fromint(2) + t = rbigint.fromlong(2655689964083835493447941032762343136647965588635159615997220691002017799304) + for n, expected in [(37, 9), (1291, 931), (67889, 39464)]: + v = two.pow(t, rbigint.fromint(n)) + assert v.toint() == expected + def test_pow_lln(self): x = 10L y = 2L diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -501,9 +501,6 @@ ENTRY = ENTRIES.OF entry = d.entries[i] if ENTRIES.must_clear_key: - key = entry.key # careful about destructor side effects: - # keep key alive until entry.value has also - # been zeroed (if it must be) entry.key = lltype.nullptr(ENTRY.key.TO) if ENTRIES.must_clear_value: entry.value = lltype.nullptr(ENTRY.value.TO) diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -256,12 +256,15 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - self.objects_pointing_to_young = self.AddressStack() + # Note that young array objects may (by temporary "mistake") be added + # to this list, but will be removed again at the start of the next + # minor collection. + self.old_objects_pointing_to_young = self.AddressStack() # - # Similar to 'objects_pointing_to_young', but lists objects + # Similar to 'old_objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'objects_pointing_to_young', in which case we + # and in 'old_objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. # Note also that young array objects are never listed here. self.old_objects_with_cards_set = self.AddressStack() @@ -979,12 +982,12 @@ # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object - # to the list 'objects_pointing_to_young'. We know that + # to the list 'old_objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.objects_pointing_to_young.append(addr_struct) + self.old_objects_pointing_to_young.append(addr_struct) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC @@ -1019,7 +1022,7 @@ "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") # # no cards, use default logic. Mostly copied from above. - self.objects_pointing_to_young.append(addr_array) + self.old_objects_pointing_to_young.append(addr_array) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS @@ -1100,7 +1103,7 @@ "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") # if self.appears_to_be_young(newvalue): - self.objects_pointing_to_young.append(addr_array) + self.old_objects_pointing_to_young.append(addr_array) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True @@ -1120,7 +1123,7 @@ """ objhdr = self.header(addr_struct) if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: - self.objects_pointing_to_young.append(addr_struct) + self.old_objects_pointing_to_young.append(addr_struct) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: @@ -1164,7 +1167,7 @@ # if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.objects_pointing_to_young.append(dest_addr) + self.old_objects_pointing_to_young.append(dest_addr) dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: @@ -1202,13 +1205,18 @@ # debug_start("gc-minor") # + # Before everything else, remove from 'old_objects_pointing_to_young' + # the young arrays. + if self.young_rawmalloced_objects: + self.remove_young_arrays_from_old_objects_pointing_to_young() + # # First, find the roots that point to young objects. All nursery # objects found are copied out of the nursery, and the occasional # young raw-malloced object is flagged with GCFLAG_VISITED. # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'objects_pointing_to_young'. + # 'old_objects_pointing_to_young'. self.collect_roots_in_nursery() # while True: @@ -1217,11 +1225,11 @@ if self.card_page_indices > 0: self.collect_cardrefs_to_nursery() # - # Now trace objects from 'objects_pointing_to_young'. + # Now trace objects from 'old_objects_pointing_to_young'. # All nursery objects they reference are copied out of the - # nursery, and again added to 'objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'objects_pointing_to_young' is empty. + # nursery, and again added to 'old_objects_pointing_to_young'. + # All young raw-malloced object found are flagged GCFLAG_VISITED. + # We proceed until 'old_objects_pointing_to_young' is empty. self.collect_oldrefs_to_nursery() # # We have to loop back if collect_oldrefs_to_nursery caused @@ -1262,7 +1270,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.objects_pointing_to_young. + # GcStruct is in the list self.old_objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1287,7 +1295,7 @@ p = llarena.getfakearenaaddress(obj - size_gc_header) # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it - # means that it is in 'objects_pointing_to_young' and + # means that it is in 'old_objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: @@ -1326,22 +1334,17 @@ def collect_oldrefs_to_nursery(self): - # Follow the objects_pointing_to_young list and move the + # Follow the old_objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.objects_pointing_to_young + oldlist = self.old_objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Check (somehow) that the flags are correct: we must not have - # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's - # possible that the same obj is appended twice to the list - # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out - # here. - if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: - ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, - "objects_pointing_to_young contains obj with " - "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") - continue + # Check that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0, + "old_objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS") # # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should # have this flag set after a nursery collection. @@ -1349,7 +1352,7 @@ # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'objects_pointing_to_young' as well. + # and adding them to 'old_objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1432,11 +1435,11 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'objects_pointing_to_young', + # Add the newobj to the list 'old_objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'objects_pointing_to_young'. - self.objects_pointing_to_young.append(newobj) + # objects when we walk 'old_objects_pointing_to_young'. + self.old_objects_pointing_to_young.append(newobj) def _visit_young_rawmalloced_object(self, obj): # 'obj' points to a young, raw-malloced object. @@ -1451,33 +1454,20 @@ return hdr.tid |= GCFLAG_VISITED # - # we just made 'obj' old, so we need to add it to the correct - # lists. (Note that another point of view on the longish - # comments below is that we are not changing any flags in 'hdr', - # but just restoring invariants: the object may be missing from - # these lists as long as it is a young array, but not when it - # grows old.) - anywhere = False + # we just made 'obj' old, so we need to add it to the correct lists + added_somewhere = False # if hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: - # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so - # the object may contain young pointers anywhere - self.objects_pointing_to_young.append(obj) - anywhere = True + self.old_objects_pointing_to_young.append(obj) + added_somewhere = True # if hdr.tid & GCFLAG_HAS_CARDS != 0: - # large array case: the object contains card marks - # that tell us where young pointers are, and it must - # be added to 'old_objects_with_cards_set'. Note that - # we must add it even if we also added it just above to - # 'objects_pointing_to_young', because the object header - # needs to be cleaned up. ll_assert(hdr.tid & GCFLAG_CARDS_SET != 0, "young array: GCFLAG_HAS_CARDS without GCFLAG_CARDS_SET") self.old_objects_with_cards_set.append(obj) - anywhere = True + added_somewhere = True # - ll_assert(anywhere, "wrong flag combination on young array") + ll_assert(added_somewhere, "wrong flag combination on young array") def _malloc_out_of_nursery(self, totalsize): @@ -1517,6 +1507,18 @@ # and survives. Otherwise, it dies. self.free_rawmalloced_object_if_unvisited(obj) + def remove_young_arrays_from_old_objects_pointing_to_young(self): + old = self.old_objects_pointing_to_young + new = self.AddressStack() + while old.non_empty(): + obj = old.pop() + if not self.young_rawmalloced_objects.contains(obj): + new.append(obj) + # an extra copy, to avoid assignments to + # 'self.old_objects_pointing_to_young' + while new.non_empty(): + old.append(new.pop()) + new.delete() # ---------- # Full collection From noreply at buildbot.pypy.org Mon Jul 25 02:15:05 2011 From: noreply at buildbot.pypy.org (ademan) Date: Mon, 25 Jul 2011 02:15:05 +0200 (CEST) Subject: [pypy-commit] pypy ootype-rerased: Closing ootype-rerased Message-ID: <20110725001505.78F8D8208C@wyvern.cs.uni-duesseldorf.de> Author: Daniel Roberts Branch: ootype-rerased Changeset: r45956:b5bc2f812d76 Date: 2011-07-24 17:13 -0700 http://bitbucket.org/pypy/pypy/changeset/b5bc2f812d76/ Log: Closing ootype-rerased From noreply at buildbot.pypy.org Mon Jul 25 03:10:24 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 25 Jul 2011 03:10:24 +0200 (CEST) Subject: [pypy-commit] pypy default: typo in a docstring. Message-ID: <20110725011024.7E7988208C@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45957:f3f9ce087f0c Date: 2011-07-24 16:32 -0700 http://bitbucket.org/pypy/pypy/changeset/f3f9ce087f0c/ Log: typo in a docstring. diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py --- a/pypy/objspace/std/identitydict.py +++ b/pypy/objspace/std/identitydict.py @@ -50,7 +50,7 @@ The second case is completely non-deterministic, even in CPython. Depending on the phase of the moon, you might call the __eq__ or not, so it is perfectly fine to *never* call it. Morever, in practice with the - minimar GC we never have two live objects with the same hash, so it would + minimark GC we never have two live objects with the same hash, so it would never happen anyway. """ From noreply at buildbot.pypy.org Mon Jul 25 03:10:25 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 25 Jul 2011 03:10:25 +0200 (CEST) Subject: [pypy-commit] pypy default: Mark IdentityDict storage as being nonull. Message-ID: <20110725011025.AC2468208C@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45958:f1360c0d409b Date: 2011-07-24 16:34 -0700 http://bitbucket.org/pypy/pypy/changeset/f1360c0d409b/ Log: Mark IdentityDict storage as being nonull. diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py --- a/pypy/objspace/std/identitydict.py +++ b/pypy/objspace/std/identitydict.py @@ -2,6 +2,7 @@ ## dict strategy (see dict_multiobject.py) from pypy.rlib import rerased +from pypy.rlib.debug import mark_dict_non_null from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, DictStrategy, IteratorImplementation, @@ -65,7 +66,9 @@ return wrapped def get_empty_storage(self): - return self.erase({}) + d = {} + mark_dict_non_null(d) + return self.erase(d) def is_correct_type(self, w_obj): w_type = self.space.type(w_obj) From noreply at buildbot.pypy.org Mon Jul 25 03:10:26 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 25 Jul 2011 03:10:26 +0200 (CEST) Subject: [pypy-commit] pypy default: (zain, alex): specialize the error checking for math.{sin, cos} this way is much cleaner, plus the error checking is written in terms of the input, which means the JIT can often remove duplicate checks. Message-ID: <20110725011026.DB3A88208C@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45959:af99487db00f Date: 2011-07-24 18:10 -0700 http://bitbucket.org/pypy/pypy/changeset/af99487db00f/ Log: (zain, alex): specialize the error checking for math.{sin,cos} this way is much cleaner, plus the error checking is written in terms of the input, which means the JIT can often remove duplicate checks. diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py --- a/pypy/module/pypyjit/test_pypy_c/test_math.py +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -30,3 +30,34 @@ --TICK-- jump(..., descr=) """) + + def test_sin_cos(self): + def main(n): + import math + + i = 1 + s = 0.0 + while i < n: + s += math.sin(i) - math.cos(i) + i += 1 + return s + log = self.run(main, [500]) + assert round(log.result, 6) == round(main(500), 6) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i2 = int_lt(i0, i1) + guard_true(i2, descr=...) + f1 = cast_int_to_float(i0) + i3 = float_eq(f1, inf) + i4 = float_eq(f1, -inf) + i5 = int_or(i3, i4) + i6 = int_is_true(i5) + guard_false(i6, descr=...) + f2 = call(ConstClass(sin), f1, descr=) + f3 = call(ConstClass(cos), f1, descr=) + f4 = float_sub(f2, f3) + f5 = float_add(f0, f4) + i7 = int_add(i0, f1) + --TICK-- + jump(..., descr=) + """) \ No newline at end of file diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py --- a/pypy/rpython/extfuncregistry.py +++ b/pypy/rpython/extfuncregistry.py @@ -42,6 +42,8 @@ ('sqrt', [float], float), ('log', [float], float), ('log10', [float], float), + ('sin', [float], float), + ('cos', [float], float), ]), ] for module, methods in _register: diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -69,6 +69,8 @@ [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) +math_sin = llexternal('sin', [rffi.DOUBLE], rffi.DOUBLE) +math_cos = llexternal('cos', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -340,6 +342,16 @@ raise ValueError("math domain error") return math_log10(x) +def ll_math_sin(x): + if isinf(x): + raise ValueError("math domain error") + return math_sin(x) + +def ll_math_cos(x): + if isinf(x): + raise ValueError("math domain error") + return math_cos(x) + # ____________________________________________________________ # # Default implementations @@ -377,8 +389,8 @@ unary_math_functions = [ 'acos', 'asin', 'atan', - 'ceil', 'cos', 'cosh', 'exp', 'fabs', - 'sin', 'sinh', 'tan', 'tanh', + 'ceil', 'cosh', 'exp', 'fabs', + 'sinh', 'tan', 'tanh', 'acosh', 'asinh', 'atanh', 'log1p', 'expm1', ] unary_math_functions_can_overflow = [ diff --git a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py --- a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py +++ b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py @@ -37,7 +37,7 @@ assert self.interpret(f, [0.3, 0.4]) == f(0.3, 0.4) return next_test - for name in ll_math.unary_math_functions + ['log', 'log10', 'sqrt']: + for name in ll_math.unary_math_functions + ['log', 'log10', 'sin', 'cos', 'sqrt']: func_name = 'test_%s' % (name,) next_test = new_unary_test(name) next_test.func_name = func_name From noreply at buildbot.pypy.org Mon Jul 25 03:10:28 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 25 Jul 2011 03:10:28 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream. Message-ID: <20110725011028.36E618208C@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45960:c3cdcacec880 Date: 2011-07-24 18:10 -0700 http://bitbucket.org/pypy/pypy/changeset/c3cdcacec880/ Log: merged upstream. diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py --- a/pypy/rlib/rerased.py +++ b/pypy/rlib/rerased.py @@ -113,7 +113,7 @@ if hop.r_result.lowleveltype is lltype.Void: return hop.inputconst(lltype.Void, None) [v] = hop.inputargs(hop.args_r[0]) - return hop.genop('cast_opaque_ptr', [v], resulttype = hop.r_result) + return hop.args_r[0].rtype_unerase(hop, v) return erase, unerase @@ -147,7 +147,7 @@ def specialize_call(self, hop): [v] = hop.inputargs(hop.args_r[0]) assert isinstance(hop.s_result, annmodel.SomeInteger) - return hop.gendirectcall(ll_unerase_int, v) + return hop.args_r[0].rtype_unerase_int(hop, v) def ll_unerase_int(gcref): from pypy.rpython.lltypesystem.lloperation import llop @@ -174,7 +174,10 @@ return False # cannot be None, but can contain a None def rtyper_makerepr(self, rtyper): + if rtyper.type_system.name == 'lltypesystem': return ErasedRepr(rtyper) + elif rtyper.type_system.name == 'ootypesystem': + return OOErasedRepr(rtyper) def rtyper_makekey(self): return self.__class__, @@ -200,6 +203,13 @@ return hop.genop('cast_opaque_ptr', [v_obj], resulttype=self.lowleveltype) + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_opaque_ptr', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + return hop.gendirectcall(ll_unerase_int, v) + def rtype_erase_int(self, hop): [v_value] = hop.inputargs(lltype.Signed) c_one = hop.inputconst(lltype.Signed, 1) @@ -224,3 +234,50 @@ return lltype.nullptr(self.lowleveltype.TO) v = r_obj.convert_const(value._x) return lltype.cast_opaque_ptr(self.lowleveltype, v) + +from pypy.rpython.ootypesystem import ootype + +class OOErasedRepr(Repr): + lowleveltype = ootype.Object + def __init__(self, rtyper): + self.rtyper = rtyper + + def rtype_erase(self, hop, s_obj): + hop.exception_cannot_occur() + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return hop.inputconst(self.lowleveltype, + ootype.NULL) + [v_obj] = hop.inputargs(r_obj) + return hop.genop('cast_to_object', [v_obj], + resulttype=self.lowleveltype) + + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_from_object', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('oounbox_int', [v], resulttype=hop.r_result) + return hop.genop('int_rshift', [v2, c_one], resulttype=lltype.Signed) + + def rtype_erase_int(self, hop): + hop.exception_is_here() + [v_value] = hop.inputargs(lltype.Signed) + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('int_lshift_ovf', [v_value, c_one], + resulttype = lltype.Signed) + v2p1 = hop.genop('int_add', [v2, c_one], + resulttype = lltype.Signed) + return hop.genop('oobox_int', [v2p1], resulttype=hop.r_result) + + def convert_const(self, value): + if value._identity is _identity_for_ints: + return value._x # FIXME: what should we do here? + bk = self.rtyper.annotator.bookkeeper + s_obj = value._identity.get_input_annotation(bk) + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return ootype.NULL + v = r_obj.convert_const(value._x) + return ootype.cast_to_object(v) diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py --- a/pypy/rlib/test/test_rerased.py +++ b/pypy/rlib/test/test_rerased.py @@ -5,8 +5,10 @@ from pypy.annotation.annrpython import RPythonAnnotator from pypy.rpython.test.test_llinterp import interpret from pypy.rpython.lltypesystem.rclass import OBJECTPTR +from pypy.rpython.ootypesystem.rclass import OBJECT from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin class X(object): pass @@ -79,136 +81,6 @@ s = a.build_types(f, []) assert isinstance(s, annmodel.SomeInteger) -def test_rtype_1(): - def f(): - return eraseX(X()) - x = interpret(f, []) - assert lltype.typeOf(x) == llmemory.GCREF - -def test_rtype_2(): - def f(): - x1 = X() - e = eraseX(x1) - #assert not is_integer(e) - x2 = uneraseX(e) - return x2 - x = interpret(f, []) - assert lltype.castable(OBJECTPTR, lltype.typeOf(x)) > 0 - -def test_rtype_3(): - def f(): - e = erase_int(16) - #assert is_integer(e) - x2 = unerase_int(e) - return x2 - x = interpret(f, []) - assert x == 16 - - -def test_prebuilt_erased(): - e1 = erase_int(16) - x1 = X() - x1.foobar = 42 - e2 = eraseX(x1) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = unerase_int(e1) + uneraseX(e2).foobar - return x2 - x = interpret(f, []) - assert x == 16 + 42 + 1 - -def test_prebuilt_erased_in_instance(): - erase_empty, unerase_empty = new_erasing_pair("empty") - class FakeList(object): - pass - - x1 = X() - x1.foobar = 42 - l1 = FakeList() - l1.storage = eraseX(x1) - l2 = FakeList() - l2.storage = erase_empty(None) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) - return x2 - x = interpret(f, []) - assert x == 43 + True - - -def test_overflow(): - def f(i): - try: - e = erase_int(i) - except OverflowError: - return -1 - #assert is_integer(e) - return unerase_int(e) - x = interpret(f, [16]) - assert x == 16 - x = interpret(f, [sys.maxint]) - assert x == -1 - -def test_none(): - def foo(): - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - # - def foo(): - eraseX(X()) - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - -def test_union(): - s_e1 = SomeErased() - s_e1.const = 1 - s_e2 = SomeErased() - s_e2.const = 3 - assert not annmodel.pair(s_e1, s_e2).union().is_constant() - - -def test_rtype_list(): - prebuilt_l = [X()] - prebuilt_e = erase_list_X(prebuilt_l) - def l(flag): - if flag == 1: - l = [X()] - e = erase_list_X(l) - elif flag == 2: - l = prebuilt_l - e = erase_list_X(l) - else: - l = prebuilt_l - e = prebuilt_e - #assert is_integer(e) is False - assert unerase_list_X(e) is l - interpret(l, [0]) - interpret(l, [1]) - interpret(l, [2]) - -# ____________________________________________________________ - -def test_erasing_pair(): - erase, unerase = new_erasing_pair("test1") - class X: - pass - x = X() - erased = erase(x) - assert unerase(erased) is x - # - erase2, unerase2 = new_erasing_pair("test2") - py.test.raises(AssertionError, unerase2, erased) - def test_annotate_erasing_pair(): erase, unerase = new_erasing_pair("test1") erase2, unerase2 = new_erasing_pair("test2") @@ -296,3 +168,148 @@ a = RPythonAnnotator() s = a.build_types(f, [int]) assert isinstance(s, annmodel.SomeInteger) + +class BaseTestRErased(BaseRtypingTest): + def test_rtype_1(self): + def f(): + return eraseX(X()) + x = self.interpret(f, []) + assert lltype.typeOf(x) == self.ERASED_TYPE + + def test_rtype_2(self): + def f(): + x1 = X() + e = eraseX(x1) + #assert not is_integer(e) + x2 = uneraseX(e) + return x2 + x = self.interpret(f, []) + assert self.castable(self.UNERASED_TYPE, x) + + def test_rtype_3(self): + def f(): + e = erase_int(16) + #assert is_integer(e) + x2 = unerase_int(e) + return x2 + x = self.interpret(f, []) + assert x == 16 + + def test_prebuilt_erased(self): + e1 = erase_int(16) + x1 = X() + x1.foobar = 42 + e2 = eraseX(x1) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = unerase_int(e1) + uneraseX(e2).foobar + return x2 + x = self.interpret(f, []) + assert x == 16 + 42 + 1 + + def test_prebuilt_erased_in_instance(self): + erase_empty, unerase_empty = new_erasing_pair("empty") + class FakeList(object): + pass + + x1 = X() + x1.foobar = 42 + l1 = FakeList() + l1.storage = eraseX(x1) + l2 = FakeList() + l2.storage = erase_empty(None) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) + return x2 + x = self.interpret(f, []) + assert x == 43 + True + + def test_overflow(self): + def f(i): + try: + e = erase_int(i) + except OverflowError: + return -1 + #assert is_integer(e) + return unerase_int(e) + x = self.interpret(f, [16]) + assert x == 16 + x = self.interpret(f, [sys.maxint]) + assert x == -1 + + def test_none(self): + def foo(): + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + # + def foo(): + eraseX(X()) + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + + def test_rtype_list(self): + prebuilt_l = [X()] + prebuilt_e = erase_list_X(prebuilt_l) + def l(flag): + if flag == 1: + l = [X()] + e = erase_list_X(l) + elif flag == 2: + l = prebuilt_l + e = erase_list_X(l) + else: + l = prebuilt_l + e = prebuilt_e + #assert is_integer(e) is False + assert unerase_list_X(e) is l + self.interpret(l, [0]) + self.interpret(l, [1]) + self.interpret(l, [2]) + +class TestLLtype(BaseTestRErased, LLRtypeMixin): + ERASED_TYPE = llmemory.GCREF + UNERASED_TYPE = OBJECTPTR + def castable(self, TO, var): + return lltype.castable(TO, lltype.typeOf(var)) > 0 + +from pypy.rpython.ootypesystem.ootype import Object + +class TestOOtype(BaseTestRErased, OORtypeMixin): + ERASED_TYPE = Object + UNERASED_TYPE = OBJECT + def castable(self, TO, var): + return ootype.isSubclass(lltype.typeOf(var), TO) + @py.test.mark.xfail + def test_prebuilt_erased(self): + super(TestOOtype, self).test_prebuilt_erased() + +def test_union(): + s_e1 = SomeErased() + s_e1.const = 1 + s_e2 = SomeErased() + s_e2.const = 3 + assert not annmodel.pair(s_e1, s_e2).union().is_constant() + +# ____________________________________________________________ + +def test_erasing_pair(): + erase, unerase = new_erasing_pair("test1") + class X: + pass + x = X() + erased = erase(x) + assert unerase(erased) is x + # + erase2, unerase2 = new_erasing_pair("test2") + py.test.raises(AssertionError, unerase2, erased) diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -1225,6 +1225,12 @@ except ValueError: self.make_llexception() + def op_oobox_int(self, i): + return ootype.oobox_int(i) + + def op_oounbox_int(self, x): + return ootype.oounbox_int(x) + class Tracer(object): Counter = 0 file = None diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -585,6 +585,8 @@ 'classof': LLOp(oo=True, canfold=True), 'subclassof': LLOp(oo=True, canfold=True), 'oostring': LLOp(oo=True, sideeffects=False), + 'oobox_int': LLOp(oo=True, sideeffects=False), + 'oounbox_int': LLOp(oo=True, sideeffects=False), 'ooparse_int': LLOp(oo=True, canraise=(ValueError,)), 'ooparse_float': LLOp(oo=True, canraise=(ValueError,)), 'oounicode': LLOp(oo=True, canraise=(UnicodeDecodeError,)), diff --git a/pypy/rpython/ootypesystem/ooopimpl.py b/pypy/rpython/ootypesystem/ooopimpl.py --- a/pypy/rpython/ootypesystem/ooopimpl.py +++ b/pypy/rpython/ootypesystem/ooopimpl.py @@ -3,7 +3,6 @@ # ____________________________________________________________ # Implementation of the 'canfold' oo operations - def op_ooupcast(INST, inst): return ootype.ooupcast(INST, inst) op_ooupcast.need_result_type = True diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -1938,6 +1938,17 @@ assert typeOf(obj) is Object return obj._cast_to(EXPECTED_TYPE) +class Box(_object): + def __init__(self, i): + self._TYPE = Object + self.i = i + +def oobox_int(i): + return Box(i) + +def oounbox_int(x): + return x.i + def oostring(obj, base): """ Convert char, int, float, instances and str to str. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -255,7 +255,7 @@ methodname = None return fn, v_obj, methodname -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): from pypy.rlib import jit r_dict = hop.r_result diff --git a/pypy/rpython/test/test_rint.py b/pypy/rpython/test/test_rint.py --- a/pypy/rpython/test/test_rint.py +++ b/pypy/rpython/test/test_rint.py @@ -8,6 +8,9 @@ from pypy.rlib import objectmodel from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem.lloperation import llop class TestSnippet(object): @@ -412,4 +415,8 @@ pass class TestOOtype(BaseTestRint, OORtypeMixin): - pass + def test_oobox_int(self): + def f(): + x = llop.oobox_int(ootype.Object, 42) + return llop.oounbox_int(lltype.Signed, x) + assert self.interpret(f, []) == 42 diff --git a/pypy/translator/cli/metavm.py b/pypy/translator/cli/metavm.py --- a/pypy/translator/cli/metavm.py +++ b/pypy/translator/cli/metavm.py @@ -1,6 +1,6 @@ from pypy.translator.cli import oopspec from pypy.rpython.ootypesystem import ootype -from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.oosupport.metavm import Generator, InstructionList, MicroInstruction,\ PushAllArgs, StoreResult, GetField, SetField, DownCast from pypy.translator.oosupport.metavm import _Call as _OOCall @@ -173,6 +173,16 @@ generator.load(v_obj) generator.ilasm.opcode('unbox.any', boxtype) +class _UnboxType(MicroInstruction): + def __init__(self, TO): + self.TO = TO + + def render(self, generator, op): + v_obj, = op.args + boxtype = generator.cts.lltype_to_cts(self.TO) + generator.load(v_obj) + generator.ilasm.opcode('unbox.any', boxtype) + class _NewArray(MicroInstruction): def render(self, generator, op): v_type, v_length = op.args @@ -312,6 +322,7 @@ #CastWeakAdrToPtr = _CastWeakAdrToPtr() Box = _Box() Unbox = _Unbox() +UnboxInt = _UnboxType(lltype.Signed) NewArray = _NewArray() GetArrayElem = _GetArrayElem() SetArrayElem = _SetArrayElem() diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py --- a/pypy/translator/cli/opcodes.py +++ b/pypy/translator/cli/opcodes.py @@ -2,7 +2,7 @@ IndirectCall, GetField, SetField, DownCast, NewCustomDict,\ MapException, Box, Unbox, NewArray, GetArrayElem, SetArrayElem,\ TypeOf, CastPrimitive, EventHandler, GetStaticField, SetStaticField, \ - DebugPrint + DebugPrint, UnboxInt from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult, InstructionList,\ New, RuntimeNew, CastTo, PushPrimitive, OOString, OOUnicode, OONewArray from pypy.translator.cli.cts import WEAKREF @@ -48,6 +48,8 @@ 'cast_from_object': [DownCast], 'clibox': [Box], 'cliunbox': [Unbox], + 'oobox_int': [Box], + 'oounbox_int': [UnboxInt], 'cli_newarray': [NewArray], 'cli_getelem': [GetArrayElem], 'cli_setelem': [SetArrayElem], @@ -92,6 +94,7 @@ 'debug_fatalerror': [PushAllArgs, 'call void [pypylib]pypy.runtime.Debug::DEBUG_FATALERROR(string)'], 'keepalive': Ignore, 'jit_marker': Ignore, + 'jit_force_quasi_immutable':Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, } diff --git a/pypy/translator/cli/test/test_int.py b/pypy/translator/cli/test/test_int.py --- a/pypy/translator/cli/test/test_int.py +++ b/pypy/translator/cli/test/test_int.py @@ -1,8 +1,8 @@ import py from pypy.translator.cli.test.runtest import CliTest -from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test -class TestCliInt(CliTest, BaseTestRint): +class TestCliInt(CliTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -77,6 +77,8 @@ 'oosend': [JvmCallMethod, StoreResult], 'ooupcast': DoNothing, 'oodowncast': [DownCast, StoreResult], + 'oobox_int': jvm.PYPYBOXINT, + 'oounbox_int': jvm.PYPYUNBOXINT, 'cast_to_object': DoNothing, 'cast_from_object': [DownCast, StoreResult], 'instanceof': [CastTo, StoreResult], diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -307,6 +307,14 @@ return result; } + public static Object box_integer(int x) { + return new Integer(x); + } + + public static int unbox_integer(Object o) { + Integer x = (Integer)o; + return x.intValue(); + } // Used in testing the JVM backend: // // A series of methods which serve a similar purpose to repr() in Python: diff --git a/pypy/translator/jvm/test/test_int.py b/pypy/translator/jvm/test/test_int.py --- a/pypy/translator/jvm/test/test_int.py +++ b/pypy/translator/jvm/test/test_int.py @@ -1,10 +1,11 @@ import py from pypy.translator.jvm.test.runtest import JvmTest from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test # ====> ../../../rpython/test/test_rint.py -class TestJvmInt(JvmTest, BaseTestRint): +class TestJvmInt(JvmTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/jvm/typesystem.py b/pypy/translator/jvm/typesystem.py --- a/pypy/translator/jvm/typesystem.py +++ b/pypy/translator/jvm/typesystem.py @@ -963,6 +963,8 @@ PYPYRUNTIMENEW = Method.s(jPyPy, 'RuntimeNew', (jClass,), jObject) PYPYSTRING2BYTES = Method.s(jPyPy, 'string2bytes', (jString,), jByteArray) PYPYARRAYTOLIST = Method.s(jPyPy, 'array_to_list', (jObjectArray,), jArrayList) +PYPYBOXINT = Method.s(jPyPy, 'box_integer', (jInt,), jObject) +PYPYUNBOXINT = Method.s(jPyPy, 'unbox_integer', (jObject,), jInt) PYPYOOPARSEFLOAT = Method.v(jPyPy, 'ooparse_float', (jString,), jDouble) OBJECTGETCLASS = Method.v(jObject, 'getClass', (), jClass) CLASSGETNAME = Method.v(jClass, 'getName', (), jString) diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py --- a/pypy/translator/oosupport/test_template/operations.py +++ b/pypy/translator/oosupport/test_template/operations.py @@ -1,3 +1,6 @@ +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype from pypy.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, ovfcheck from pypy.rlib import rstack from pypy.annotation import model as annmodel From noreply at buildbot.pypy.org Mon Jul 25 05:42:30 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 25 Jul 2011 05:42:30 +0200 (CEST) Subject: [pypy-commit] pypy default: Clean up some silly oopspec stuff with dicts (how old was this code...) Message-ID: <20110725034230.11BED8208C@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45961:0b485b20b582 Date: 2011-07-24 20:42 -0700 http://bitbucket.org/pypy/pypy/changeset/0b485b20b582/ Log: Clean up some silly oopspec stuff with dicts (how old was this code...) diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -420,10 +420,6 @@ _ll_1_dict_values.need_result_type = True _ll_1_dict_items .need_result_type = True - def _ll_1_newdictiter(ITER, d): - return ll_rdict.ll_dictiter(lltype.Ptr(ITER), d) - _ll_1_newdictiter.need_result_type = True - _dictnext_keys = staticmethod(ll_rdict.ll_dictnext_group['keys']) _dictnext_values = staticmethod(ll_rdict.ll_dictnext_group['values']) _dictnext_items = staticmethod(ll_rdict.ll_dictnext_group['items']) @@ -574,10 +570,6 @@ _ll_1_dict_values.need_result_type = True _ll_1_dict_items .need_result_type = True - def _ll_1_newdictiter(ITER, d): - return oo_rdict.ll_dictiter(ITER, d) - _ll_1_newdictiter.need_result_type = True - _dictnext_keys = staticmethod(oo_rdict.ll_dictnext_group['keys']) _dictnext_values = staticmethod(oo_rdict.ll_dictnext_group['values']) _dictnext_items = staticmethod(oo_rdict.ll_dictnext_group['items']) diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -491,8 +491,8 @@ if i & HIGHEST_BIT: raise KeyError _ll_dict_del(d, i) -ll_dict_delitem.oopspec = 'dict.delitem(d, key)' + at jit.dont_look_inside def _ll_dict_del(d, i): d.entries.mark_deleted(i) d.num_items -= 1 @@ -687,7 +687,6 @@ iter.dict = d iter.index = 0 return iter -ll_dictiter.oopspec = 'newdictiter(d)' def _make_ll_dictnext(kind): # make three versions of the following function: keys, values, items From notifications-noreply at bitbucket.org Mon Jul 25 07:46:05 2011 From: notifications-noreply at bitbucket.org (Bitbucket) Date: Mon, 25 Jul 2011 05:46:05 -0000 Subject: [pypy-commit] Notification: pypy Message-ID: <20110725054605.8119.61118@bitbucket02.managed.contegix.com> You have received a notification from shomah4a. Hi, I forked pypy. My fork is at https://bitbucket.org/shomah4a/pypy. -- Change your notification settings at https://bitbucket.org/account/notifications/ From noreply at buildbot.pypy.org Mon Jul 25 10:42:24 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Mon, 25 Jul 2011 10:42:24 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: tweaks Message-ID: <20110725084224.EA5248208C@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: extradoc Changeset: r3841:425c42775168 Date: 2011-07-25 09:45 +0100 http://bitbucket.org/pypy/extradoc/changeset/425c42775168/ Log: tweaks diff --git a/talk/icooolps2011/talk/figures/map.svg b/talk/icooolps2011/talk/figures/map.svg --- a/talk/icooolps2011/talk/figures/map.svg +++ b/talk/icooolps2011/talk/figures/map.svg @@ -64,7 +64,7 @@ showgrid="false" inkscape:zoom="1.3953574" inkscape:cx="271.26815" - inkscape:cy="273.36393" + inkscape:cy="130.03147" inkscape:window-x="0" inkscape:window-y="24" inkscape:window-maximized="1" diff --git a/talk/icooolps2011/talk/talk.tex b/talk/icooolps2011/talk/talk.tex --- a/talk/icooolps2011/talk/talk.tex +++ b/talk/icooolps2011/talk/talk.tex @@ -90,11 +90,9 @@ \begin{frame} \frametitle{Good JIT Compilers for Dynamic Languages are Hard} \begin{itemize} - \item implementing the object model well is crucial \item recent languages like Python, Ruby, JS have complex core semantics \item many corner cases, even hard to interpret correctly \pause - \item to get efficiency, the correct fast path through the tree of implementations must be generated XXX \item feedback of runtime information to the compiler is necessary \item correct exploitation of this information in the compiler \end{itemize} @@ -114,7 +112,7 @@ \end{frame} \begin{frame} - \frametitle{A Tracing JIT} + \frametitle{An Interpreter} \includegraphics[scale=0.5]{figures/trace02.pdf} \end{frame} @@ -212,7 +210,7 @@ \begin{block}{PyPy's Meta-Tracing JIT} \begin{itemize} \item PyPy contains a meta-tracing JIT for interpreters in RPython - \item needs a few source-code hints (or annotations) in the interpreter + \item needs a few source-code hints (or annotations) \emph{in the interpreter} \item powerful general optimizations \end{itemize} \end{block} @@ -257,7 +255,7 @@ \PY{k}{class} \PY{n+nc}{Map}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{indexes}\PY{p}{)}\PY{p}{:} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes} \PY{o}{=} \PY{n}{indexes} - \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{other\PYZus{}maps} \PY{o}{=} \PY{p}{\PYZob{}}\PY{p}{\PYZcb{}} + \PY{o}{.}\PY{o}{.}\PY{o}{.} \PY{k}{def} \PY{n+nf}{getindex}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{,} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)} @@ -290,14 +288,14 @@ \begin{frame}[plain,containsverbatim] \frametitle{Trace for code \texttt{inst.a + inst.b}} \begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] -# $inst_1$.getattr("a") +# $inst_1$.getfield("a") $map_1$ = $inst_1$.map $index_1$ = Map.getindex($map_1$, "a") guard($index_1$ != -1) $storage_1$ = $inst_1$.storage $result_1$ = $storage_1$[$index_1$] |\pause| -# $inst_1$.getattr("b") +# $inst_1$.getfield("b") $map_2$ = $inst_1$.map $index_2$ = Map.getindex($map_2$, "b") guard($index_2$ != -1) @@ -305,21 +303,20 @@ $result_2$ = $storage_2$[$index_2$] $v_1$ = $result_1$ + $result_2$ -return($v_1$) \end{lstlisting} \end{frame} \begin{frame}[plain,containsverbatim] -\frametitle{Trace for code \texttt{inst.a + inst.b}} +\frametitle{Trace for Code \texttt{inst.a + inst.b}} \begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] -# $inst_1$.getattr("a") +# $inst_1$.getfield("a") $map_1$ = $inst_1$.map $index_1$ = Map.getindex($map_1$, "a") guard($index_1$ != -1) $storage_1$ = $inst_1$.storage $result_1$ = $storage_1$[$index_1$] -# $inst_1$.getattr("b") +# $inst_1$.getfield("b") $map_2$ = $inst_1$.map $index_2$ = Map.getindex($map_2$, "b") guard($index_2$ != -1) @@ -327,7 +324,6 @@ $result_2$ = $storage_2$[$index_2$] $v_1$ = $result_1$ + $result_2$ -return($v_1$) \end{lstlisting} \end{frame} @@ -340,7 +336,10 @@ \item should be used only for variables that take few values \end{itemize} \pause +\end{frame} +\begin{frame}[containsverbatim] + \frametitle{Tiny Example} \begin{minipage}[b]{6cm} \centering {\noop @@ -356,71 +355,10 @@ \hspace{0.5cm} \begin{minipage}[b]{4cm} {\noop - \begin{lstlisting}[mathescape,basicstyle=\ttfamily] + \begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily] guard($x_1$ == 4) -$v_1$ = $x_1$ * 2 -$z_1$ = $v_1$ + 1 -$v_2$ = $z_1$ + $y_1$ -return($v_2$) - \end{lstlisting} - } - \end{minipage} -\end{frame} - -\begin{frame}[containsverbatim] - \frametitle{Runtime Feedback Controlled by the Interpreter Author} - \begin{itemize} - \item give the interpreter author a way to feed back runtime values into the trace - \item written as \texttt{promote(x)} - \item captures the argument's runtime value during tracing - \item should be used only for variables that take few values - \end{itemize} - - \begin{minipage}[b]{6cm} - \centering - {\noop - \begin{lstlisting}[mathescape,basicstyle=\ttfamily] -def f1(x, y): - promote(x) - z = x * 2 + 1 - return z + y - - - \end{lstlisting} - } - \end{minipage} -\end{frame} - -\begin{frame}[containsverbatim] - \frametitle{Runtime Feedback Controlled by the Interpreter Author} - \begin{itemize} - \item give the interpreter author a way to feed back runtime values into the trace - \item written as \texttt{promote(x)} - \item captures the argument's runtime value during tracing - \item should be used only for variables that take few values - \end{itemize} - - \begin{minipage}[b]{6cm} - \centering - {\noop - \begin{lstlisting}[mathescape,basicstyle=\ttfamily] -def f1(x, y): - promote(x) - z = x * 2 + 1 - return z + y - - - \end{lstlisting} - } - \end{minipage} - \vline - \hspace{0.5cm} - \begin{minipage}[b]{4cm} - {\noop - \begin{lstlisting}[mathescape,basicstyle=\ttfamily] -guard($x_1$ == 4) -$v_1$ = $x_1$ * 2 -$z_1$ = $v_1$ + 1 +|{\color{gray}$v_1$ = $x_1$ * 2}| +|{\color{gray}$z_1$ = $v_1$ + 1}| $v_2$ = $z_1$ + $y_1$ return($v_2$) \end{lstlisting} @@ -449,7 +387,7 @@ \PY{k}{class} \PY{n+nc}{Map}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{indexes}\PY{p}{)}\PY{p}{:} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes} \PY{o}{=} \PY{n}{indexes} - \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{other\PYZus{}maps} \PY{o}{=} \PY{p}{\PYZob{}}\PY{p}{\PYZcb{}} + \PY{o}{.}\PY{o}{.}\PY{o}{.} \PY{n+nd}{@elidable} \PY{k}{def} \PY{n+nf}{getindex}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} @@ -459,7 +397,7 @@ \PY{k}{def} \PY{n+nf}{add\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} \PY{o}{.}\PY{o}{.}\PY{o}{.} -\PY{n}{EMPTY\PYZus{}MAP} \PY{o}{=} \PY{n}{Map}\PY{p}{(}\PY{p}{)} +\PY{n}{EMPTY\PYZus{}MAP} \PY{o}{=} \PY{n}{Map}\PY{p}{(}\PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}\PY{p}{)} \end{Verbatim} \end{frame} @@ -467,8 +405,6 @@ \frametitle{Adding Hints to Maps} \begin{Verbatim}[commandchars=\\\{\}] -\PY{n}{EMPTY\PYZus{}MAP} \PY{o}{=} \PY{n}{Map}\PY{p}{(}\PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}\PY{p}{)} - \PY{k}{class} \PY{n+nc}{Instance}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{)}\PY{p}{:} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map} \PY{o}{=} \PY{n}{EMPTY\PYZus{}MAP} @@ -488,40 +424,37 @@ \begin{frame}[containsverbatim,plain] - \frametitle{Trace with Hints} + \frametitle{Trace with Hints for Code \texttt{inst.a + inst.b}} \begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] -# $inst_1$.getattr("a") +# $inst_1$.getfield("a") $map_1$ = $inst_1$.map guard($map_1$ == 0xb74af4a8) -|{\color{gray}$index_1$ = Map.getindex($map_1$, "a")| -|{\color{gray}guard($index_1$ != -1)| +|{\color{gray}$index_1$ = Map.getindex($map_1$, "a")}| +|{\color{gray}guard($index_1$ != -1)}| $storage_1$ = $inst_1$.storage -$result_1$ = $storage_1$[$index_1$] +$result_1$ = $storage_1$[$index_1$}] -# $inst_1$.getattr("b") +# $inst_1$.getfield("b") |{\color{gray}$map_2$ = $inst_1$.map| -|{\color{gray}guard($map_2$ == 0xb74af4a8)| -|{\color{gray}$index_2$ = Map.getindex($map_2$, "b")| -|{\color{gray}guard($index_2$ != -1)| -|{\color{gray}$storage_2$ = $inst_1$.storage| +|{\color{gray}guard($map_2$ == 0xb74af4a8)}| +|{\color{gray}$index_2$ = Map.getindex($map_2$, "b")}| +|{\color{gray}guard($index_2$ != -1)}| +|{\color{gray}$storage_2$ = $inst_1$.storage}| $result_2$ = $storage_2$[$index_2$] $v_1$ = $result_1$ + $result_2$ -return($v_1$) \end{lstlisting} \end{frame} \begin{frame}[containsverbatim,plain] \frametitle{Final Trace} \begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] -# $inst_1$.getattr("a") $map_1$ = $inst_1$.map guard($map_1$ == 0xb74af4a8) $storage_1$ = $inst_1$.storage $result_1$ = $storage_1$[$0$] $result_2$ = $storage_2$[$1$] $v_1$ = $result_1$ + $result_2$ -return($v_1$) \end{lstlisting} \end{frame} @@ -551,6 +484,8 @@ \begin{itemize} \item benchmarks done using PyPy's Python interpreter \item about 30'000 lines of code + \item 20 calls to \texttt{promote} + \item 10 applications of \texttt{@elidable} \end{itemize} \end{frame} @@ -562,8 +497,9 @@ \begin{frame} \frametitle{Conclusion} \begin{itemize} - \item meta-tracing can make the efficient implementation of complex dynamic languaes easier - \item two kinds of hints to be added by the interpreter author allows arbitrary runtime feedback + \item meta-tracing can make the efficient implementation of complex dynamic languages easier + \item only requires to write a correct interpreter + \item two kinds of hints to be added by the interpreter author allow arbitrary runtime feedback and its exploitation \item the hints are expressive enough to re-implement classical optimizations such as maps \item usage of the hints leads to good speedups for object-oriented code in PyPy's Python interpreter \end{itemize} @@ -571,6 +507,19 @@ \begin{frame} \frametitle{Bonus: Comparison with Partial Evaluation} + \begin{itemize} + \pause + \item the only difference between meta-tracing and partial evaluation is that meta-tracing works + \pause + \item ... mostly kidding + \pause + \item very similar from the motivation and ideas + \item PE was never scaled up to perform well on large interpreters + \item classical PE mostly ahead of time + \item PE tried very carefully to select the right paths to inline and optimize + \item quite often this fails and inlines too much or too little + \item tracing is much more pragmatic: simply look what happens + \end{itemize} \end{frame} From noreply at buildbot.pypy.org Mon Jul 25 13:37:33 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 25 Jul 2011 13:37:33 +0200 (CEST) Subject: [pypy-commit] pyrepl default: Copy the changeset 824b72bb6b45 from pypy's main repo: Message-ID: <20110725113733.3E6F78208C@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r124:714bcbd37203 Date: 2011-07-25 13:36 +0200 http://bitbucket.org/pypy/pyrepl/changeset/714bcbd37203/ Log: Copy the changeset 824b72bb6b45 from pypy's main repo: on top of both CPython and PyPy, signal.signal() raises ValueError when called from a non-main thread. In this case just ignore setting up the signal handler, for now. diff --git a/pyrepl/unix_console.py b/pyrepl/unix_console.py --- a/pyrepl/unix_console.py +++ b/pyrepl/unix_console.py @@ -384,14 +384,18 @@ self.__maybe_write_code(self._smkx) + try: self.old_sigwinch = signal.signal( signal.SIGWINCH, self.__sigwinch) + except ValueError: + pass def restore(self): self.__maybe_write_code(self._rmkx) self.flushoutput() tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate) + if hasattr(self, 'old_sigwinch'): signal.signal(signal.SIGWINCH, self.old_sigwinch) def __sigwinch(self, signum, frame): From noreply at buildbot.pypy.org Mon Jul 25 13:46:34 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 25 Jul 2011 13:46:34 +0200 (CEST) Subject: [pypy-commit] pypy default: Added tag benchmarked for changeset b48df0bf4e75 Message-ID: <20110725114634.031FC8208C@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45964:b6be8465a274 Date: 2011-07-25 13:38 +0200 http://bitbucket.org/pypy/pypy/changeset/b6be8465a274/ Log: Added tag benchmarked for changeset b48df0bf4e75 diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -1,1 +1,2 @@ b590cf6de4190623aad9aa698694c22e614d67b9 release-1.5 +b48df0bf4e75b81d98f19ce89d4a7dc3e1dab5e5 benchmarked From noreply at buildbot.pypy.org Mon Jul 25 14:13:26 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 25 Jul 2011 14:13:26 +0200 (CEST) Subject: [pypy-commit] buildbot default: bah, typo Message-ID: <20110725121326.68AC68208C@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r537:79cc0b9cab89 Date: 2011-07-25 14:13 +0200 http://bitbucket.org/pypy/buildbot/changeset/79cc0b9cab89/ Log: bah, typo diff --git a/bbhook/scm.py b/bbhook/scm.py --- a/bbhook/scm.py +++ b/bbhook/scm.py @@ -22,7 +22,7 @@ def get_diff(local_repo, hgid): out = hg('-R', local_repo, 'diff', '-b', '--git', '-c', hgid) - out = out.splitlines(True) + lines = out.splitlines(True) return filter_diff(lines) def filter_diff(lines): From noreply at buildbot.pypy.org Mon Jul 25 14:24:13 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 25 Jul 2011 14:24:13 +0200 (CEST) Subject: [pypy-commit] benchmarks default: import the main pypy repo at revision b6be8465a274, tag 'benchmarked' Message-ID: <20110725122413.8A4E2829C2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r131:f3830896d637 Date: 2011-07-25 13:52 +0200 http://bitbucket.org/pypy/benchmarks/changeset/f3830896d637/ Log: import the main pypy repo at revision b6be8465a274, tag 'benchmarked' diff too long, truncating to 10000 out of 1743062 lines diff --git a/Notes.txt b/Notes.txt --- a/Notes.txt +++ b/Notes.txt @@ -1,6 +1,6 @@ Notes ====== -twisted can be updated by killing lib/twisted, then running:: +twisted can be updated by killing lib/twisted-trunk, then running:: svn export svn://svn.twistedmatrix.com/svn/Twisted/trunk lib/twisted-trunk -q diff --git a/lib/pypy/.gitignore b/lib/pypy/.gitignore new file mode 100644 --- /dev/null +++ b/lib/pypy/.gitignore @@ -0,0 +1,21 @@ +.hg +.svn + +*.pyc +*.pyo +*~ + +bin/pypy-c +include/*.h +lib_pypy/ctypes_config_cache/_[^_]*_*.py +pypy/_cache +pypy/doc/*.html +pypy/doc/config/*.html +pypy/doc/discussion/*.html +pypy/module/cpyext/src/*.o +pypy/module/cpyext/test/*.o +pypy/module/test_lib_pypy/ctypes_tests/*.o +pypy/translator/c/src/dtoa.o +pypy/translator/goal/pypy-c +pypy/translator/goal/target*-c +release/ \ No newline at end of file diff --git a/lib/pypy/.hg_archival.txt b/lib/pypy/.hg_archival.txt new file mode 100644 --- /dev/null +++ b/lib/pypy/.hg_archival.txt @@ -0,0 +1,4 @@ +repo: 45eff22199974f85fd96138d25510f4660aba5a1 +node: b48df0bf4e75b81d98f19ce89d4a7dc3e1dab5e5 +branch: default +tag: benchmarked diff --git a/lib/pypy/.hgignore b/lib/pypy/.hgignore new file mode 100644 --- /dev/null +++ b/lib/pypy/.hgignore @@ -0,0 +1,73 @@ +syntax: glob +*.py[co] +*~ +.*.swp + +syntax: regexp +^testresult$ +^site-packages$ +^site-packages/.*$ +^site-packages/.*$ +^bin$ +^pypy/bin/pypy-c +^pypy/module/cpyext/src/.+\.o$ +^pypy/module/cpyext/src/.+\.obj$ +^pypy/module/cpyext/test/.+\.errors$ +^pypy/module/cpyext/test/.+\.o$ +^pypy/module/cpyext/test/.+\.obj$ +^pypy/module/cpyext/test/.+\.manifest$ +^pypy/module/test_lib_pypy/ctypes_tests/.+\.o$ +^pypy/doc/.+\.html$ +^pypy/doc/config/.+\.rst$ +^pypy/doc/basicblock\.asc$ +^pypy/doc/.+\.svninfo$ +^pypy/translator/c/src/libffi_msvc/.+\.obj$ +^pypy/translator/c/src/libffi_msvc/.+\.dll$ +^pypy/translator/c/src/libffi_msvc/.+\.lib$ +^pypy/translator/c/src/libffi_msvc/.+\.exp$ +^pypy/translator/c/src/cjkcodecs/.+\.o$ +^pypy/translator/c/src/cjkcodecs/.+\.obj$ +^pypy/translator/jvm/\.project$ +^pypy/translator/jvm/\.classpath$ +^pypy/translator/jvm/eclipse-bin$ +^pypy/translator/jvm/src/pypy/.+\.class$ +^pypy/translator/benchmark/docutils$ +^pypy/translator/benchmark/templess$ +^pypy/translator/benchmark/gadfly$ +^pypy/translator/benchmark/mako$ +^pypy/translator/benchmark/bench-custom\.benchmark_result$ +^pypy/translator/benchmark/shootout_benchmarks$ +^pypy/translator/goal/pypy-translation-snapshot$ +^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar +^pypy/translator/goal/.+\.exe$ +^pypy/translator/goal/.+\.dll$ +^pypy/translator/goal/target.+-c$ +^pypy/_cache$ +^pypy/doc/statistic/.+\.html$ +^pypy/doc/statistic/.+\.eps$ +^pypy/doc/statistic/.+\.pdf$ +^pypy/translator/cli/src/pypylib\.dll$ +^pypy/translator/cli/src/query\.exe$ +^pypy/translator/cli/src/main\.exe$ +^lib_pypy/ctypes_config_cache/_.+_cache\.py$ +^lib_pypy/ctypes_config_cache/_.+_.+_\.py$ +^pypy/translator/cli/query-descriptions$ +^pypy/doc/discussion/.+\.html$ +^include/.+\.h$ +^include/.+\.inl$ +^pypy/doc/_build/.*$ +^pypy/doc/config/.+\.html$ +^pypy/doc/config/style\.css$ +^pypy/doc/jit/.+\.html$ +^pypy/doc/jit/style\.css$ +^pypy/doc/image/lattice1\.png$ +^pypy/doc/image/lattice2\.png$ +^pypy/doc/image/lattice3\.png$ +^pypy/doc/image/stackless_informal\.png$ +^pypy/doc/image/parsing_example.+\.png$ +^pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test\.o$ +^compiled +^.git/ +^release/ diff --git a/lib/pypy/.hgsubstate b/lib/pypy/.hgsubstate new file mode 100644 diff --git a/lib/pypy/.hgtags b/lib/pypy/.hgtags new file mode 100644 --- /dev/null +++ b/lib/pypy/.hgtags @@ -0,0 +1,1 @@ +b590cf6de4190623aad9aa698694c22e614d67b9 release-1.5 diff --git a/lib/pypy/LICENSE b/lib/pypy/LICENSE new file mode 100644 --- /dev/null +++ b/lib/pypy/LICENSE @@ -0,0 +1,249 @@ +License for files in the pypy/ directory +================================================== + +Except when otherwise stated (look for LICENSE files in directories or +information at the beginning of each file) all software and +documentation in the 'pypy' directories is licensed as follows: + + The MIT License + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + +PyPy Copyright holders 2003-2011 +----------------------------------- + +Except when otherwise stated (look for LICENSE files or information at +the beginning of each file) the files in the 'pypy' directory are each +copyrighted by one or more of the following people and organizations: + + Armin Rigo + Maciej Fijalkowski + Carl Friedrich Bolz + Amaury Forgeot d'Arc + Antonio Cuni + Samuele Pedroni + Michael Hudson + Holger Krekel + Christian Tismer + Benjamin Peterson + Eric van Riet Paap + Anders Chrigström + Håkan Ardö + Richard Emslie + Dan Villiom Podlaski Christiansen + Alexander Schremmer + Alex Gaynor + David Schneider + Aurelién Campeas + Anders Lehmann + Camillo Bruni + Niklaus Haldimann + Leonardo Santagada + Toon Verwaest + Seo Sanghyeon + Lawrence Oluyede + Bartosz Skowron + Jakub Gustak + Guido Wesdorp + Adrien Di Mascio + Laura Creighton + Ludovic Aubry + Niko Matsakis + Daniel Roberts + Jason Creighton + Jacob Hallén + Alex Martelli + Anders Hammarquist + Jan de Mooij + Stephan Diehl + Michael Foord + Stefan Schwarzer + Tomek Meka + Patrick Maupin + Bob Ippolito + Bruno Gola + Alexandre Fayolle + Marius Gedminas + Simon Burton + Jean-Paul Calderone + John Witulski + Wim Lavrijsen + Andreas Stührk + Jean-Philippe St. Pierre + Guido van Rossum + Pavel Vinogradov + Valentino Volonghi + Paul deGrandis + Adrian Kuhn + tav + Georg Brandl + Gerald Klix + Wanja Saatkamp + Boris Feigin + Oscar Nierstrasz + Dario Bertini + David Malcolm + Eugene Oden + Henry Mason + Lukas Renggli + Guenter Jantzen + Ronny Pfannschmidt + Bert Freudenberg + Amit Regmi + Ben Young + Nicolas Chauvat + Andrew Durdin + Michael Schneider + Nicholas Riley + Rocco Moretti + Gintautas Miliauskas + Michael Twomey + Igor Trindade Oliveira + Lucian Branescu Mihaila + Olivier Dormond + Jared Grubb + Karl Bartel + Gabriel Lavoie + Brian Dorsey + Victor Stinner + Stuart Williams + Toby Watson + Antoine Pitrou + Justas Sadzevicius + Neil Shepperd + Mikael Schönenberg + Gasper Zejn + Jonathan David Riehl + Elmo Mäntynen + Anders Qvist + Beatrice Düring + Alexander Sedov + Vincent Legoll + Alan McIntyre + Romain Guillebert + Alex Perry + Jens-Uwe Mager + Dan Stromberg + Lukas Diekmann + Carl Meyer + Pieter Zieschang + Alejandro J. Cura + Sylvain Thenault + Travis Francis Athougies + Henrik Vendelbo + Lutz Paelike + Jacob Oscarson + Martin Blais + Lucio Torre + Lene Wagner + Miguel de Val Borro + Ignas Mikalajunas + Artur Lisiecki + Joshua Gilbert + Godefroid Chappelle + Yusei Tahara + Christopher Armstrong + Stephan Busemann + Gustavo Niemeyer + William Leslie + Akira Li + Kristján Valur Jónsson + Bobby Impollonia + Andrew Thompson + Anders Sigfridsson + Jacek Generowicz + Dan Colish + Sven Hager + Zooko Wilcox-O Hearn + Anders Hammarquist + Dinu Gherman + Dan Colish + Daniel Neuhäuser + Michael Chermside + Konrad Delong + Anna Ravencroft + Greg Price + Armin Ronacher + Jim Baker + Philip Jenvey + Rodrigo Araújo + Brett Cannon + + Heinrich-Heine University, Germany + Open End AB (formerly AB Strakt), Sweden + merlinux GmbH, Germany + tismerysoft GmbH, Germany + Logilab Paris, France + DFKI GmbH, Germany + Impara, Germany + Change Maker, Sweden + +The PyPy Logo as used by http://speed.pypy.org and others was created +by Samuel Reis and is distributed on terms of Creative Commons Share Alike +License. + +License for 'lib-python/2.7.0' and 'lib-python/2.7.0-modified' +============================================================== + +Except when otherwise stated (look for LICENSE files or +copyright/license information at the beginning of each file) the files +in the 'lib-python/2.7.0' and 'lib-python/2.7.0-modified' directories +are all copyrighted by the Python Software Foundation and licensed under +the Python Software License of which you can find a copy here: +http://www.python.org/doc/Copyright.html + +License for 'pypy/translator/jvm/src/jna.jar' +============================================= + +The file 'pypy/translator/jvm/src/jna.jar' is licensed under the GNU +Lesser General Public License of which you can find a copy here: +http://www.gnu.org/licenses/lgpl.html + +License for 'pypy/translator/jvm/src/jasmin.jar' +================================================ + +The file 'pypy/translator/jvm/src/jasmin.jar' is copyright (c) 1996-2004 Jon Meyer +and distributed with permission. The use of Jasmin by PyPy does not imply +that PyPy is endorsed by Jon Meyer nor any of Jasmin's contributors. Furthermore, +the following disclaimer applies to Jasmin: + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License for 'pypy/module/unicodedata/' +====================================== + +The following files are from the website of The Unicode Consortium +at http://www.unicode.org/. For the terms of use of these files, see +http://www.unicode.org/terms_of_use.html . Or they are derived from +files from the above website, and the same terms of use apply. + + CompositionExclusions-*.txt + EastAsianWidth-*.txt + LineBreak-*.txt + UnicodeData-*.txt + UnihanNumeric-*.txt diff --git a/lib/pypy/README b/lib/pypy/README new file mode 100644 --- /dev/null +++ b/lib/pypy/README @@ -0,0 +1,24 @@ +===================================== +PyPy: Python in Python Implementation +===================================== + +Welcome to PyPy! + +PyPy is both an implementation of the Python programming language, and +an extensive compiler framework for dynamic language implementations. +You can build self-contained Python implementations which execute +independently from CPython. + +The home page is: + + http://pypy.org/ + +The getting-started document will help guide you: + + http://doc.pypy.org/en/latest/getting-started.html + +It will also point you to the rest of the documentation which is generated +from files in the pypy/doc directory within the source repositories. Enjoy +and send us feedback! + + the pypy-dev team diff --git a/lib/pypy/_pytest/__init__.py b/lib/pypy/_pytest/__init__.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/__init__.py @@ -0,0 +1,2 @@ +# +__version__ = '2.1.0.dev4' diff --git a/lib/pypy/_pytest/assertion/__init__.py b/lib/pypy/_pytest/assertion/__init__.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/assertion/__init__.py @@ -0,0 +1,128 @@ +""" +support for presenting detailed information in failing assertions. +""" +import py +import imp +import marshal +import struct +import sys +import pytest +from _pytest.monkeypatch import monkeypatch +from _pytest.assertion import reinterpret, util + +try: + from _pytest.assertion.rewrite import rewrite_asserts +except ImportError: + rewrite_asserts = None +else: + import ast + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption('--assertmode', action="store", dest="assertmode", + choices=("on", "old", "off", "default"), default="default", + metavar="on|old|off", + help="""control assertion debugging tools. +'off' performs no assertion debugging. +'old' reinterprets the expressions in asserts to glean information. +'on' (the default) rewrites the assert statements in test modules to provide +sub-expression results.""") + group.addoption('--no-assert', action="store_true", default=False, + dest="noassert", help="DEPRECATED equivalent to --assertmode=off") + group.addoption('--nomagic', action="store_true", default=False, + dest="nomagic", help="DEPRECATED equivalent to --assertmode=off") + +class AssertionState: + """State for the assertion plugin.""" + + def __init__(self, config, mode): + self.mode = mode + self.trace = config.trace.root.get("assertion") + +def pytest_configure(config): + warn_about_missing_assertion() + mode = config.getvalue("assertmode") + if config.getvalue("noassert") or config.getvalue("nomagic"): + if mode not in ("off", "default"): + raise pytest.UsageError("assertion options conflict") + mode = "off" + elif mode == "default": + mode = "on" + if mode != "off": + def callbinrepr(op, left, right): + hook_result = config.hook.pytest_assertrepr_compare( + config=config, op=op, left=left, right=right) + for new_expl in hook_result: + if new_expl: + return '\n~'.join(new_expl) + m = monkeypatch() + config._cleanup.append(m.undo) + m.setattr(py.builtin.builtins, 'AssertionError', + reinterpret.AssertionError) + m.setattr(util, '_reprcompare', callbinrepr) + if mode == "on" and rewrite_asserts is None: + mode = "old" + config._assertstate = AssertionState(config, mode) + config._assertstate.trace("configured with mode set to %r" % (mode,)) + +def _write_pyc(co, source_path): + if hasattr(imp, "cache_from_source"): + # Handle PEP 3147 pycs. + pyc = py.path.local(imp.cache_from_source(str(source_path))) + pyc.ensure() + else: + pyc = source_path + "c" + mtime = int(source_path.mtime()) + fp = pyc.open("wb") + try: + fp.write(imp.get_magic()) + fp.write(struct.pack(">", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + + +class DebugInterpreter(ast.NodeVisitor): + """Interpret AST nodes to gleam useful debugging information. """ + + def __init__(self, frame): + self.frame = frame + + def generic_visit(self, node): + # Fallback when we don't have a special implementation. + if _is_ast_expr(node): + mod = ast.Expression(node) + co = self._compile(mod) + try: + result = self.frame.eval(co) + except Exception: + raise Failure() + explanation = self.frame.repr(result) + return explanation, result + elif _is_ast_stmt(node): + mod = ast.Module([node]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co) + except Exception: + raise Failure() + return None, None + else: + raise AssertionError("can't handle %s" %(node,)) + + def _compile(self, source, mode="eval"): + return compile(source, "", mode) + + def visit_Expr(self, expr): + return self.visit(expr.value) + + def visit_Module(self, mod): + for stmt in mod.body: + self.visit(stmt) + + def visit_Name(self, name): + explanation, result = self.generic_visit(name) + # See if the name is local. + source = "%r in locals() is not globals()" % (name.id,) + co = self._compile(source) + try: + local = self.frame.eval(co) + except Exception: + # have to assume it isn't + local = None + if local is None or not self.frame.is_true(local): + return name.id, result + return explanation, result + + def visit_Compare(self, comp): + left = comp.left + left_explanation, left_result = self.visit(left) + for op, next_op in zip(comp.ops, comp.comparators): + next_explanation, next_result = self.visit(next_op) + op_symbol = operator_map[op.__class__] + explanation = "%s %s %s" % (left_explanation, op_symbol, + next_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=next_result) + except Exception: + raise Failure(explanation) + try: + if not self.frame.is_true(result): + break + except KeyboardInterrupt: + raise + except: + break + left_explanation, left_result = next_explanation, next_result + + if util._reprcompare is not None: + res = util._reprcompare(op_symbol, left_result, next_result) + if res: + explanation = res + return explanation, result + + def visit_BoolOp(self, boolop): + is_or = isinstance(boolop.op, ast.Or) + explanations = [] + for operand in boolop.values: + explanation, result = self.visit(operand) + explanations.append(explanation) + if result == is_or: + break + name = is_or and " or " or " and " + explanation = "(" + name.join(explanations) + ")" + return explanation, result + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_explanation, operand_result = self.visit(unary.operand) + explanation = pattern % (operand_explanation,) + co = self._compile(pattern % ("__exprinfo_expr",)) + try: + result = self.frame.eval(co, __exprinfo_expr=operand_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_BinOp(self, binop): + left_explanation, left_result = self.visit(binop.left) + right_explanation, right_result = self.visit(binop.right) + symbol = operator_map[binop.op.__class__] + explanation = "(%s %s %s)" % (left_explanation, symbol, + right_explanation) + source = "__exprinfo_left %s __exprinfo_right" % (symbol,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_left=left_result, + __exprinfo_right=right_result) + except Exception: + raise Failure(explanation) + return explanation, result + + def visit_Call(self, call): + func_explanation, func = self.visit(call.func) + arg_explanations = [] + ns = {"__exprinfo_func" : func} + arguments = [] + for arg in call.args: + arg_explanation, arg_result = self.visit(arg) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + arguments.append(arg_name) + arg_explanations.append(arg_explanation) + for keyword in call.keywords: + arg_explanation, arg_result = self.visit(keyword.value) + arg_name = "__exprinfo_%s" % (len(ns),) + ns[arg_name] = arg_result + keyword_source = "%s=%%s" % (keyword.arg) + arguments.append(keyword_source % (arg_name,)) + arg_explanations.append(keyword_source % (arg_explanation,)) + if call.starargs: + arg_explanation, arg_result = self.visit(call.starargs) + arg_name = "__exprinfo_star" + ns[arg_name] = arg_result + arguments.append("*%s" % (arg_name,)) + arg_explanations.append("*%s" % (arg_explanation,)) + if call.kwargs: + arg_explanation, arg_result = self.visit(call.kwargs) + arg_name = "__exprinfo_kwds" + ns[arg_name] = arg_result + arguments.append("**%s" % (arg_name,)) + arg_explanations.append("**%s" % (arg_explanation,)) + args_explained = ", ".join(arg_explanations) + explanation = "%s(%s)" % (func_explanation, args_explained) + args = ", ".join(arguments) + source = "__exprinfo_func(%s)" % (args,) + co = self._compile(source) + try: + result = self.frame.eval(co, **ns) + except Exception: + raise Failure(explanation) + pattern = "%s\n{%s = %s\n}" + rep = self.frame.repr(result) + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def _is_builtin_name(self, name): + pattern = "%r not in globals() and %r not in locals()" + source = pattern % (name.id, name.id) + co = self._compile(source) + try: + return self.frame.eval(co) + except Exception: + return False + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + source_explanation, source_result = self.visit(attr.value) + explanation = "%s.%s" % (source_explanation, attr.attr) + source = "__exprinfo_expr.%s" % (attr.attr,) + co = self._compile(source) + try: + result = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + raise Failure(explanation) + explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result), + self.frame.repr(result), + source_explanation, attr.attr) + # Check if the attr is from an instance. + source = "%r in getattr(__exprinfo_expr, '__dict__', {})" + source = source % (attr.attr,) + co = self._compile(source) + try: + from_instance = self.frame.eval(co, __exprinfo_expr=source_result) + except Exception: + from_instance = None + if from_instance is None or self.frame.is_true(from_instance): + rep = self.frame.repr(result) + pattern = "%s\n{%s = %s\n}" + explanation = pattern % (rep, rep, explanation) + return explanation, result + + def visit_Assert(self, assrt): + test_explanation, test_result = self.visit(assrt.test) + explanation = "assert %s" % (test_explanation,) + if not self.frame.is_true(test_result): + try: + raise BuiltinAssertionError + except Exception: + raise Failure(explanation) + return explanation, test_result + + def visit_Assign(self, assign): + value_explanation, value_result = self.visit(assign.value) + explanation = "... = %s" % (value_explanation,) + name = ast.Name("__exprinfo_expr", ast.Load(), + lineno=assign.value.lineno, + col_offset=assign.value.col_offset) + new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno, + col_offset=assign.col_offset) + mod = ast.Module([new_assign]) + co = self._compile(mod, "exec") + try: + self.frame.exec_(co, __exprinfo_expr=value_result) + except Exception: + raise Failure(explanation) + return explanation, value_result diff --git a/lib/pypy/_pytest/assertion/oldinterpret.py b/lib/pypy/_pytest/assertion/oldinterpret.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/assertion/oldinterpret.py @@ -0,0 +1,552 @@ +import py +import sys, inspect +from compiler import parse, ast, pycodegen +from _pytest.assertion.util import format_explanation +from _pytest.assertion.reinterpret import BuiltinAssertionError + +passthroughex = py.builtin._sysex + +class Failure: + def __init__(self, node): + self.exc, self.value, self.tb = sys.exc_info() + self.node = node + +class View(object): + """View base class. + + If C is a subclass of View, then C(x) creates a proxy object around + the object x. The actual class of the proxy is not C in general, + but a *subclass* of C determined by the rules below. To avoid confusion + we call view class the class of the proxy (a subclass of C, so of View) + and object class the class of x. + + Attributes and methods not found in the proxy are automatically read on x. + Other operations like setting attributes are performed on the proxy, as + determined by its view class. The object x is available from the proxy + as its __obj__ attribute. + + The view class selection is determined by the __view__ tuples and the + optional __viewkey__ method. By default, the selected view class is the + most specific subclass of C whose __view__ mentions the class of x. + If no such subclass is found, the search proceeds with the parent + object classes. For example, C(True) will first look for a subclass + of C with __view__ = (..., bool, ...) and only if it doesn't find any + look for one with __view__ = (..., int, ...), and then ..., object,... + If everything fails the class C itself is considered to be the default. + + Alternatively, the view class selection can be driven by another aspect + of the object x, instead of the class of x, by overriding __viewkey__. + See last example at the end of this module. + """ + + _viewcache = {} + __view__ = () + + def __new__(rootclass, obj, *args, **kwds): + self = object.__new__(rootclass) + self.__obj__ = obj + self.__rootclass__ = rootclass + key = self.__viewkey__() + try: + self.__class__ = self._viewcache[key] + except KeyError: + self.__class__ = self._selectsubclass(key) + return self + + def __getattr__(self, attr): + # attributes not found in the normal hierarchy rooted on View + # are looked up in the object's real class + return getattr(self.__obj__, attr) + + def __viewkey__(self): + return self.__obj__.__class__ + + def __matchkey__(self, key, subclasses): + if inspect.isclass(key): + keys = inspect.getmro(key) + else: + keys = [key] + for key in keys: + result = [C for C in subclasses if key in C.__view__] + if result: + return result + return [] + + def _selectsubclass(self, key): + subclasses = list(enumsubclasses(self.__rootclass__)) + for C in subclasses: + if not isinstance(C.__view__, tuple): + C.__view__ = (C.__view__,) + choices = self.__matchkey__(key, subclasses) + if not choices: + return self.__rootclass__ + elif len(choices) == 1: + return choices[0] + else: + # combine the multiple choices + return type('?', tuple(choices), {}) + + def __repr__(self): + return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) + + +def enumsubclasses(cls): + for subcls in cls.__subclasses__(): + for subsubclass in enumsubclasses(subcls): + yield subsubclass + yield cls + + +class Interpretable(View): + """A parse tree node with a few extra methods.""" + explanation = None + + def is_builtin(self, frame): + return False + + def eval(self, frame): + # fall-back for unknown expression nodes + try: + expr = ast.Expression(self.__obj__) + expr.filename = '' + self.__obj__.filename = '' + co = pycodegen.ExpressionCodeGenerator(expr).getCode() + result = frame.eval(co) + except passthroughex: + raise + except: + raise Failure(self) + self.result = result + self.explanation = self.explanation or frame.repr(self.result) + + def run(self, frame): + # fall-back for unknown statement nodes + try: + expr = ast.Module(None, ast.Stmt([self.__obj__])) + expr.filename = '' + co = pycodegen.ModuleCodeGenerator(expr).getCode() + frame.exec_(co) + except passthroughex: + raise + except: + raise Failure(self) + + def nice_explanation(self): + return format_explanation(self.explanation) + + +class Name(Interpretable): + __view__ = ast.Name + + def is_local(self, frame): + source = '%r in locals() is not globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_global(self, frame): + source = '%r in globals()' % self.name + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def is_builtin(self, frame): + source = '%r not in locals() and %r not in globals()' % ( + self.name, self.name) + try: + return frame.is_true(frame.eval(source)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + super(Name, self).eval(frame) + if not self.is_local(frame): + self.explanation = self.name + +class Compare(Interpretable): + __view__ = ast.Compare + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + for operation, expr2 in self.ops: + if hasattr(self, 'result'): + # shortcutting in chained expressions + if not frame.is_true(self.result): + break + expr2 = Interpretable(expr2) + expr2.eval(frame) + self.explanation = "%s %s %s" % ( + expr.explanation, operation, expr2.explanation) + source = "__exprinfo_left %s __exprinfo_right" % operation + try: + self.result = frame.eval(source, + __exprinfo_left=expr.result, + __exprinfo_right=expr2.result) + except passthroughex: + raise + except: + raise Failure(self) + expr = expr2 + +class And(Interpretable): + __view__ = ast.And + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if not frame.is_true(expr.result): + break + self.explanation = '(' + ' and '.join(explanations) + ')' + +class Or(Interpretable): + __view__ = ast.Or + + def eval(self, frame): + explanations = [] + for expr in self.nodes: + expr = Interpretable(expr) + expr.eval(frame) + explanations.append(expr.explanation) + self.result = expr.result + if frame.is_true(expr.result): + break + self.explanation = '(' + ' or '.join(explanations) + ')' + + +# == Unary operations == +keepalive = [] +for astclass, astpattern in { + ast.Not : 'not __exprinfo_expr', + ast.Invert : '(~__exprinfo_expr)', + }.items(): + + class UnaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + expr = Interpretable(self.expr) + expr.eval(frame) + self.explanation = astpattern.replace('__exprinfo_expr', + expr.explanation) + try: + self.result = frame.eval(astpattern, + __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(UnaryArith) + +# == Binary operations == +for astclass, astpattern in { + ast.Add : '(__exprinfo_left + __exprinfo_right)', + ast.Sub : '(__exprinfo_left - __exprinfo_right)', + ast.Mul : '(__exprinfo_left * __exprinfo_right)', + ast.Div : '(__exprinfo_left / __exprinfo_right)', + ast.Mod : '(__exprinfo_left % __exprinfo_right)', + ast.Power : '(__exprinfo_left ** __exprinfo_right)', + }.items(): + + class BinaryArith(Interpretable): + __view__ = astclass + + def eval(self, frame, astpattern=astpattern): + left = Interpretable(self.left) + left.eval(frame) + right = Interpretable(self.right) + right.eval(frame) + self.explanation = (astpattern + .replace('__exprinfo_left', left .explanation) + .replace('__exprinfo_right', right.explanation)) + try: + self.result = frame.eval(astpattern, + __exprinfo_left=left.result, + __exprinfo_right=right.result) + except passthroughex: + raise + except: + raise Failure(self) + + keepalive.append(BinaryArith) + + +class CallFunc(Interpretable): + __view__ = ast.CallFunc + + def is_bool(self, frame): + source = 'isinstance(__exprinfo_value, bool)' + try: + return frame.is_true(frame.eval(source, + __exprinfo_value=self.result)) + except passthroughex: + raise + except: + return False + + def eval(self, frame): + node = Interpretable(self.node) + node.eval(frame) + explanations = [] + vars = {'__exprinfo_fn': node.result} + source = '__exprinfo_fn(' + for a in self.args: + if isinstance(a, ast.Keyword): + keyword = a.name + a = a.expr + else: + keyword = None + a = Interpretable(a) + a.eval(frame) + argname = '__exprinfo_%d' % len(vars) + vars[argname] = a.result + if keyword is None: + source += argname + ',' + explanations.append(a.explanation) + else: + source += '%s=%s,' % (keyword, argname) + explanations.append('%s=%s' % (keyword, a.explanation)) + if self.star_args: + star_args = Interpretable(self.star_args) + star_args.eval(frame) + argname = '__exprinfo_star' + vars[argname] = star_args.result + source += '*' + argname + ',' + explanations.append('*' + star_args.explanation) + if self.dstar_args: + dstar_args = Interpretable(self.dstar_args) + dstar_args.eval(frame) + argname = '__exprinfo_kwds' + vars[argname] = dstar_args.result + source += '**' + argname + ',' + explanations.append('**' + dstar_args.explanation) + self.explanation = "%s(%s)" % ( + node.explanation, ', '.join(explanations)) + if source.endswith(','): + source = source[:-1] + source += ')' + try: + self.result = frame.eval(source, **vars) + except passthroughex: + raise + except: + raise Failure(self) + if not node.is_builtin(frame) or not self.is_bool(frame): + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +class Getattr(Interpretable): + __view__ = ast.Getattr + + def eval(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + source = '__exprinfo_expr.%s' % self.attrname + try: + self.result = frame.eval(source, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + self.explanation = '%s.%s' % (expr.explanation, self.attrname) + # if the attribute comes from the instance, its value is interesting + source = ('hasattr(__exprinfo_expr, "__dict__") and ' + '%r in __exprinfo_expr.__dict__' % self.attrname) + try: + from_instance = frame.is_true( + frame.eval(source, __exprinfo_expr=expr.result)) + except passthroughex: + raise + except: + from_instance = True + if from_instance: + r = frame.repr(self.result) + self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) + +# == Re-interpretation of full statements == + +class Assert(Interpretable): + __view__ = ast.Assert + + def run(self, frame): + test = Interpretable(self.test) + test.eval(frame) + # print the result as 'assert ' + self.result = test.result + self.explanation = 'assert ' + test.explanation + if not frame.is_true(test.result): + try: + raise BuiltinAssertionError + except passthroughex: + raise + except: + raise Failure(self) + +class Assign(Interpretable): + __view__ = ast.Assign + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = '... = ' + expr.explanation + # fall-back-run the rest of the assignment + ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr')) + mod = ast.Module(None, ast.Stmt([ass])) + mod.filename = '' + co = pycodegen.ModuleCodeGenerator(mod).getCode() + try: + frame.exec_(co, __exprinfo_expr=expr.result) + except passthroughex: + raise + except: + raise Failure(self) + +class Discard(Interpretable): + __view__ = ast.Discard + + def run(self, frame): + expr = Interpretable(self.expr) + expr.eval(frame) + self.result = expr.result + self.explanation = expr.explanation + +class Stmt(Interpretable): + __view__ = ast.Stmt + + def run(self, frame): + for stmt in self.nodes: + stmt = Interpretable(stmt) + stmt.run(frame) + + +def report_failure(e): + explanation = e.node.nice_explanation() + if explanation: + explanation = ", in: " + explanation + else: + explanation = "" + sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) + +def check(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + expr = parse(s, 'eval') + assert isinstance(expr, ast.Expression) + node = Interpretable(expr.node) + try: + node.eval(frame) + except passthroughex: + raise + except Failure: + e = sys.exc_info()[1] + report_failure(e) + else: + if not frame.is_true(node.result): + sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) + + +########################################################### +# API / Entry points +# ######################################################### + +def interpret(source, frame, should_fail=False): + module = Interpretable(parse(source, 'exec').node) + #print "got module", module + if isinstance(frame, py.std.types.FrameType): + frame = py.code.Frame(frame) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + return getfailure(e) + except passthroughex: + raise + except: + import traceback + traceback.print_exc() + if should_fail: + return ("(assertion failed, but when it was re-run for " + "printing intermediate values, it did not fail. Suggestions: " + "compute assert expression before the assert or use --nomagic)") + else: + return None + +def getmsg(excinfo): + if isinstance(excinfo, tuple): + excinfo = py.code.ExceptionInfo(excinfo) + #frame, line = gettbline(tb) + #frame = py.code.Frame(frame) + #return interpret(line, frame) + + tb = excinfo.traceback[-1] + source = str(tb.statement).strip() + x = interpret(source, tb.frame, should_fail=True) + if not isinstance(x, str): + raise TypeError("interpret returned non-string %r" % (x,)) + return x + +def getfailure(e): + explanation = e.node.nice_explanation() + if str(e.value): + lines = explanation.split('\n') + lines[0] += " << %s" % (e.value,) + explanation = '\n'.join(lines) + text = "%s: %s" % (e.exc.__name__, explanation) + if text.startswith('AssertionError: assert '): + text = text[16:] + return text + +def run(s, frame=None): + if frame is None: + frame = sys._getframe(1) + frame = py.code.Frame(frame) + module = Interpretable(parse(s, 'exec').node) + try: + module.run(frame) + except Failure: + e = sys.exc_info()[1] + report_failure(e) + + +if __name__ == '__main__': + # example: + def f(): + return 5 + def g(): + return 3 + def h(x): + return 'never' + check("f() * g() == 5") + check("not f()") + check("not (f() and g() or 0)") + check("f() == g()") + i = 4 + check("i == f()") + check("len(f()) == 0") + check("isinstance(2+3+4, float)") + + run("x = i") + check("x == 5") + + run("assert not f(), 'oops'") + run("a, b, c = 1, 2") + run("a, b, c = f()") + + check("max([f(),g()]) == 4") + check("'hello'[g()] == 'h'") + run("'guk%d' % h(f())") diff --git a/lib/pypy/_pytest/assertion/reinterpret.py b/lib/pypy/_pytest/assertion/reinterpret.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/assertion/reinterpret.py @@ -0,0 +1,48 @@ +import sys +import py + +BuiltinAssertionError = py.builtin.builtins.AssertionError + +class AssertionError(BuiltinAssertionError): + def __init__(self, *args): + BuiltinAssertionError.__init__(self, *args) + if args: + try: + self.msg = str(args[0]) + except py.builtin._sysex: + raise + except: + self.msg = "<[broken __repr__] %s at %0xd>" %( + args[0].__class__, id(args[0])) + else: + f = py.code.Frame(sys._getframe(1)) + try: + source = f.code.fullsource + if source is not None: + try: + source = source.getstatement(f.lineno, assertion=True) + except IndexError: + source = None + else: + source = str(source.deindent()).strip() + except py.error.ENOENT: + source = None + # this can also occur during reinterpretation, when the + # co_filename is set to "". + if source: + self.msg = reinterpret(source, f, should_fail=True) + else: + self.msg = "" + if not self.args: + self.args = (self.msg,) + +if sys.version_info > (3, 0): + AssertionError.__module__ = "builtins" + reinterpret_old = "old reinterpretation not available for py3" +else: + from _pytest.assertion.oldinterpret import interpret as reinterpret_old +if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): + from _pytest.assertion.newinterpret import interpret as reinterpret +else: + reinterpret = reinterpret_old + diff --git a/lib/pypy/_pytest/assertion/rewrite.py b/lib/pypy/_pytest/assertion/rewrite.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/assertion/rewrite.py @@ -0,0 +1,340 @@ +"""Rewrite assertion AST to produce nice error messages""" + +import ast +import collections +import itertools +import sys + +import py +from _pytest.assertion import util + + +def rewrite_asserts(mod): + """Rewrite the assert statements in mod.""" + AssertionRewriter().run(mod) + + +_saferepr = py.io.saferepr +from _pytest.assertion.util import format_explanation as _format_explanation + +def _format_boolop(operands, explanations, is_or): + show_explanations = [] + for operand, expl in zip(operands, explanations): + show_explanations.append(expl) + if operand == is_or: + break + return "(" + (is_or and " or " or " and ").join(show_explanations) + ")" + +def _call_reprcompare(ops, results, expls, each_obj): + for i, res, expl in zip(range(len(ops)), results, expls): + try: + done = not res + except Exception: + done = True + if done: + break + if util._reprcompare is not None: + custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1]) + if custom is not None: + return custom + return expl + + +unary_map = { + ast.Not : "not %s", + ast.Invert : "~%s", + ast.USub : "-%s", + ast.UAdd : "+%s" +} + +binop_map = { + ast.BitOr : "|", + ast.BitXor : "^", + ast.BitAnd : "&", + ast.LShift : "<<", + ast.RShift : ">>", + ast.Add : "+", + ast.Sub : "-", + ast.Mult : "*", + ast.Div : "/", + ast.FloorDiv : "//", + ast.Mod : "%", + ast.Eq : "==", + ast.NotEq : "!=", + ast.Lt : "<", + ast.LtE : "<=", + ast.Gt : ">", + ast.GtE : ">=", + ast.Pow : "**", + ast.Is : "is", + ast.IsNot : "is not", + ast.In : "in", + ast.NotIn : "not in" +} + + +def set_location(node, lineno, col_offset): + """Set node location information recursively.""" + def _fix(node, lineno, col_offset): + if "lineno" in node._attributes: + node.lineno = lineno + if "col_offset" in node._attributes: + node.col_offset = col_offset + for child in ast.iter_child_nodes(node): + _fix(child, lineno, col_offset) + _fix(node, lineno, col_offset) + return node + + +class AssertionRewriter(ast.NodeVisitor): + + def run(self, mod): + """Find all assert statements in *mod* and rewrite them.""" + if not mod.body: + # Nothing to do. + return + # Insert some special imports at the top of the module but after any + # docstrings and __future__ imports. + aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"), + ast.alias("_pytest.assertion.rewrite", "@pytest_ar")] + expect_docstring = True + pos = 0 + lineno = 0 + for item in mod.body: + if (expect_docstring and isinstance(item, ast.Expr) and + isinstance(item.value, ast.Str)): + doc = item.value.s + if "PYTEST_DONT_REWRITE" in doc: + # The module has disabled assertion rewriting. + return + lineno += len(doc) - 1 + expect_docstring = False + elif (not isinstance(item, ast.ImportFrom) or item.level > 0 and + item.identifier != "__future__"): + lineno = item.lineno + break + pos += 1 + imports = [ast.Import([alias], lineno=lineno, col_offset=0) + for alias in aliases] + mod.body[pos:pos] = imports + # Collect asserts. + nodes = collections.deque([mod]) + while nodes: + node = nodes.popleft() + for name, field in ast.iter_fields(node): + if isinstance(field, list): + new = [] + for i, child in enumerate(field): + if isinstance(child, ast.Assert): + # Transform assert. + new.extend(self.visit(child)) + else: + new.append(child) + if isinstance(child, ast.AST): + nodes.append(child) + setattr(node, name, new) + elif (isinstance(field, ast.AST) and + # Don't recurse into expressions as they can't contain + # asserts. + not isinstance(field, ast.expr)): + nodes.append(field) + + def variable(self): + """Get a new variable.""" + # Use a character invalid in python identifiers to avoid clashing. + name = "@py_assert" + str(next(self.variable_counter)) + self.variables.add(name) + return name + + def assign(self, expr): + """Give *expr* a name.""" + name = self.variable() + self.statements.append(ast.Assign([ast.Name(name, ast.Store())], expr)) + return ast.Name(name, ast.Load()) + + def display(self, expr): + """Call py.io.saferepr on the expression.""" + return self.helper("saferepr", expr) + + def helper(self, name, *args): + """Call a helper in this module.""" + py_name = ast.Name("@pytest_ar", ast.Load()) + attr = ast.Attribute(py_name, "_" + name, ast.Load()) + return ast.Call(attr, list(args), [], None, None) + + def builtin(self, name): + """Return the builtin called *name*.""" + builtin_name = ast.Name("@py_builtins", ast.Load()) + return ast.Attribute(builtin_name, name, ast.Load()) + + def explanation_param(self, expr): + specifier = "py" + str(next(self.variable_counter)) + self.explanation_specifiers[specifier] = expr + return "%(" + specifier + ")s" + + def push_format_context(self): + self.explanation_specifiers = {} + self.stack.append(self.explanation_specifiers) + + def pop_format_context(self, expl_expr): + current = self.stack.pop() + if self.stack: + self.explanation_specifiers = self.stack[-1] + keys = [ast.Str(key) for key in current.keys()] + format_dict = ast.Dict(keys, list(current.values())) + form = ast.BinOp(expl_expr, ast.Mod(), format_dict) + name = "@py_format" + str(next(self.variable_counter)) + self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form)) + return ast.Name(name, ast.Load()) + + def generic_visit(self, node): + """Handle expressions we don't have custom code for.""" + assert isinstance(node, ast.expr) + res = self.assign(node) + return res, self.explanation_param(self.display(res)) + + def visit_Assert(self, assert_): + if assert_.msg: + # There's already a message. Don't mess with it. + return [assert_] + self.statements = [] + self.variables = set() + self.variable_counter = itertools.count() + self.stack = [] + self.on_failure = [] + self.push_format_context() + # Rewrite assert into a bunch of statements. + top_condition, explanation = self.visit(assert_.test) + # Create failure message. + body = self.on_failure + negation = ast.UnaryOp(ast.Not(), top_condition) + self.statements.append(ast.If(negation, body, [])) + explanation = "assert " + explanation + template = ast.Str(explanation) + msg = self.pop_format_context(template) + fmt = self.helper("format_explanation", msg) + err_name = ast.Name("AssertionError", ast.Load()) + exc = ast.Call(err_name, [fmt], [], None, None) + if sys.version_info[0] >= 3: + raise_ = ast.Raise(exc, None) + else: + raise_ = ast.Raise(exc, None, None) + body.append(raise_) + # Delete temporary variables. + names = [ast.Name(name, ast.Del()) for name in self.variables] + if names: + delete = ast.Delete(names) + self.statements.append(delete) + # Fix line numbers. + for stmt in self.statements: + set_location(stmt, assert_.lineno, assert_.col_offset) + return self.statements + + def visit_Name(self, name): + # Check if the name is local or not. + locs = ast.Call(self.builtin("locals"), [], [], None, None) + globs = ast.Call(self.builtin("globals"), [], [], None, None) + ops = [ast.In(), ast.IsNot()] + test = ast.Compare(ast.Str(name.id), ops, [locs, globs]) + expr = ast.IfExp(test, self.display(name), ast.Str(name.id)) + return name, self.explanation_param(expr) + + def visit_BoolOp(self, boolop): + operands = [] + explanations = [] + self.push_format_context() + for operand in boolop.values: + res, explanation = self.visit(operand) + operands.append(res) + explanations.append(explanation) + expls = ast.Tuple([ast.Str(expl) for expl in explanations], ast.Load()) + is_or = ast.Num(isinstance(boolop.op, ast.Or)) + expl_template = self.helper("format_boolop", + ast.Tuple(operands, ast.Load()), expls, + is_or) + expl = self.pop_format_context(expl_template) + res = self.assign(ast.BoolOp(boolop.op, operands)) + return res, self.explanation_param(expl) + + def visit_UnaryOp(self, unary): + pattern = unary_map[unary.op.__class__] + operand_res, operand_expl = self.visit(unary.operand) + res = self.assign(ast.UnaryOp(unary.op, operand_res)) + return res, pattern % (operand_expl,) + + def visit_BinOp(self, binop): + symbol = binop_map[binop.op.__class__] + left_expr, left_expl = self.visit(binop.left) + right_expr, right_expl = self.visit(binop.right) + explanation = "(%s %s %s)" % (left_expl, symbol, right_expl) + res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) + return res, explanation + + def visit_Call(self, call): + new_func, func_expl = self.visit(call.func) + arg_expls = [] + new_args = [] + new_kwargs = [] + new_star = new_kwarg = None + for arg in call.args: + res, expl = self.visit(arg) + new_args.append(res) + arg_expls.append(expl) + for keyword in call.keywords: + res, expl = self.visit(keyword.value) + new_kwargs.append(ast.keyword(keyword.arg, res)) + arg_expls.append(keyword.arg + "=" + expl) + if call.starargs: + new_star, expl = self.visit(call.starargs) + arg_expls.append("*" + expl) + if call.kwargs: + new_kwarg, expl = self.visit(call.kwarg) + arg_expls.append("**" + expl) + expl = "%s(%s)" % (func_expl, ', '.join(arg_expls)) + new_call = ast.Call(new_func, new_args, new_kwargs, new_star, new_kwarg) + res = self.assign(new_call) + res_expl = self.explanation_param(self.display(res)) + outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl) + return res, outer_expl + + def visit_Attribute(self, attr): + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + value, value_expl = self.visit(attr.value) + res = self.assign(ast.Attribute(value, attr.attr, ast.Load())) + res_expl = self.explanation_param(self.display(res)) + pat = "%s\n{%s = %s.%s\n}" + expl = pat % (res_expl, res_expl, value_expl, attr.attr) + return res, expl + + def visit_Compare(self, comp): + self.push_format_context() + left_res, left_expl = self.visit(comp.left) + res_variables = [self.variable() for i in range(len(comp.ops))] + load_names = [ast.Name(v, ast.Load()) for v in res_variables] + store_names = [ast.Name(v, ast.Store()) for v in res_variables] + it = zip(range(len(comp.ops)), comp.ops, comp.comparators) + expls = [] + syms = [] + results = [left_res] + for i, op, next_operand in it: + next_res, next_expl = self.visit(next_operand) + results.append(next_res) + sym = binop_map[op.__class__] + syms.append(ast.Str(sym)) + expl = "%s %s %s" % (left_expl, sym, next_expl) + expls.append(ast.Str(expl)) + res_expr = ast.Compare(left_res, [op], [next_res]) + self.statements.append(ast.Assign([store_names[i]], res_expr)) + left_res, left_expl = next_res, next_expl + # Use py.code._reprcompare if that's available. + expl_call = self.helper("call_reprcompare", + ast.Tuple(syms, ast.Load()), + ast.Tuple(load_names, ast.Load()), + ast.Tuple(expls, ast.Load()), + ast.Tuple(results, ast.Load())) + if len(comp.ops) > 1: + res = ast.BoolOp(ast.And(), load_names) + else: + res = load_names[0] + return res, self.explanation_param(self.pop_format_context(expl_call)) diff --git a/lib/pypy/_pytest/assertion/util.py b/lib/pypy/_pytest/assertion/util.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/assertion/util.py @@ -0,0 +1,213 @@ +"""Utilities for assertion debugging""" + +import py + + +# The _reprcompare attribute on the util module is used by the new assertion +# interpretation code and assertion rewriter to detect this plugin was +# loaded and in turn call the hooks defined here as part of the +# DebugInterpreter. +_reprcompare = None + +def format_explanation(explanation): + """This formats an explanation + + Normally all embedded newlines are escaped, however there are + three exceptions: \n{, \n} and \n~. The first two are intended + cover nested explanations, see function and attribute explanations + for examples (.visit_Call(), visit_Attribute()). The last one is + for when one explanation needs to span multiple lines, e.g. when + displaying diffs. + """ + # simplify 'assert False where False = ...' + where = 0 + while True: + start = where = explanation.find("False\n{False = ", where) + if where == -1: + break + level = 0 + for i, c in enumerate(explanation[start:]): + if c == "{": + level += 1 + elif c == "}": + level -= 1 + if not level: + break + else: + raise AssertionError("unbalanced braces: %r" % (explanation,)) + end = start + i + where = end + if explanation[end - 1] == '\n': + explanation = (explanation[:start] + explanation[start+15:end-1] + + explanation[end+1:]) + where -= 17 + raw_lines = (explanation or '').split('\n') + # escape newlines not followed by {, } and ~ + lines = [raw_lines[0]] + for l in raw_lines[1:]: + if l.startswith('{') or l.startswith('}') or l.startswith('~'): + lines.append(l) + else: + lines[-1] += '\\n' + l + + result = lines[:1] + stack = [0] + stackcnt = [0] + for line in lines[1:]: + if line.startswith('{'): + if stackcnt[-1]: + s = 'and ' + else: + s = 'where ' + stack.append(len(result)) + stackcnt[-1] += 1 + stackcnt.append(0) + result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) + elif line.startswith('}'): + assert line.startswith('}') + stack.pop() + stackcnt.pop() + result[stack[-1]] += line[1:] + else: + assert line.startswith('~') + result.append(' '*len(stack) + line[1:]) + assert len(stack) == 1 + return '\n'.join(result) + + +# Provide basestring in python3 +try: + basestring = basestring +except NameError: + basestring = str + + +def assertrepr_compare(op, left, right): + """return specialised explanations for some operators/operands""" + width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op + left_repr = py.io.saferepr(left, maxsize=int(width/2)) + right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) + summary = '%s %s %s' % (left_repr, op, right_repr) + + issequence = lambda x: isinstance(x, (list, tuple)) + istext = lambda x: isinstance(x, basestring) + isdict = lambda x: isinstance(x, dict) + isset = lambda x: isinstance(x, set) + + explanation = None + try: + if op == '==': + if istext(left) and istext(right): + explanation = _diff_text(left, right) + elif issequence(left) and issequence(right): + explanation = _compare_eq_sequence(left, right) + elif isset(left) and isset(right): + explanation = _compare_eq_set(left, right) + elif isdict(left) and isdict(right): + explanation = _diff_text(py.std.pprint.pformat(left), + py.std.pprint.pformat(right)) + elif op == 'not in': + if istext(left) and istext(right): + explanation = _notin_text(left, right) + except py.builtin._sysex: + raise + except: + excinfo = py.code.ExceptionInfo() + explanation = ['(pytest_assertion plugin: representation of ' + 'details failed. Probably an object has a faulty __repr__.)', + str(excinfo) + ] + + + if not explanation: + return None + + # Don't include pageloads of data, should be configurable + if len(''.join(explanation)) > 80*8: + explanation = ['Detailed information too verbose, truncated'] + + return [summary] + explanation + + +def _diff_text(left, right): + """Return the explanation for the diff between text + + This will skip leading and trailing characters which are + identical to keep the diff minimal. + """ + explanation = [] + i = 0 # just in case left or right has zero length + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + break + if i > 42: + i -= 10 # Provide some context + explanation = ['Skipping %s identical ' + 'leading characters in diff' % i] + left = left[i:] + right = right[i:] + if len(left) == len(right): + for i in range(len(left)): + if left[-i] != right[-i]: + break + if i > 42: + i -= 10 # Provide some context + explanation += ['Skipping %s identical ' + 'trailing characters in diff' % i] + left = left[:-i] + right = right[:-i] + explanation += [line.strip('\n') + for line in py.std.difflib.ndiff(left.splitlines(), + right.splitlines())] + return explanation + + +def _compare_eq_sequence(left, right): + explanation = [] + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + explanation += ['At index %s diff: %r != %r' % + (i, left[i], right[i])] + break + if len(left) > len(right): + explanation += ['Left contains more items, ' + 'first extra item: %s' % py.io.saferepr(left[len(right)],)] + elif len(left) < len(right): + explanation += ['Right contains more items, ' + 'first extra item: %s' % py.io.saferepr(right[len(left)],)] + return explanation # + _diff_text(py.std.pprint.pformat(left), + # py.std.pprint.pformat(right)) + + +def _compare_eq_set(left, right): + explanation = [] + diff_left = left - right + diff_right = right - left + if diff_left: + explanation.append('Extra items in the left set:') + for item in diff_left: + explanation.append(py.io.saferepr(item)) + if diff_right: + explanation.append('Extra items in the right set:') + for item in diff_right: + explanation.append(py.io.saferepr(item)) + return explanation + + +def _notin_text(term, text): + index = text.find(term) + head = text[:index] + tail = text[index+len(term):] + correct_text = head + tail + diff = _diff_text(correct_text, text) + newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] + for line in diff: + if line.startswith('Skipping'): + continue + if line.startswith('- '): + continue + if line.startswith('+ '): + newdiff.append(' ' + line[2:]) + else: + newdiff.append(line) + return newdiff diff --git a/lib/pypy/_pytest/capture.py b/lib/pypy/_pytest/capture.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/capture.py @@ -0,0 +1,226 @@ +""" per-test stdout/stderr capturing mechanisms, ``capsys`` and ``capfd`` function arguments. """ + +import pytest, py +import os + +def pytest_addoption(parser): + group = parser.getgroup("general") + group._addoption('--capture', action="store", default=None, + metavar="method", type="choice", choices=['fd', 'sys', 'no'], + help="per-test capturing method: one of fd (default)|sys|no.") + group._addoption('-s', action="store_const", const="no", dest="capture", + help="shortcut for --capture=no.") + +def addouterr(rep, outerr): + repr = getattr(rep, 'longrepr', None) + if not hasattr(repr, 'addsection'): + return + for secname, content in zip(["out", "err"], outerr): + if content: + repr.addsection("Captured std%s" % secname, content.rstrip()) + +def pytest_unconfigure(config): + # registered in config.py during early conftest.py loading + capman = config.pluginmanager.getplugin('capturemanager') + while capman._method2capture: + name, cap = capman._method2capture.popitem() + # XXX logging module may wants to close it itself on process exit + # otherwise we could do finalization here and call "reset()". + cap.suspend() + +class NoCapture: + def startall(self): + pass + def resume(self): + pass + def reset(self): + pass + def suspend(self): + return "", "" + +class CaptureManager: + def __init__(self): + self._method2capture = {} + + def _maketempfile(self): + f = py.std.tempfile.TemporaryFile() + newf = py.io.dupfile(f, encoding="UTF-8") + f.close() + return newf + + def _makestringio(self): + return py.io.TextIO() + + def _getcapture(self, method): + if method == "fd": + return py.io.StdCaptureFD(now=False, + out=self._maketempfile(), err=self._maketempfile() + ) + elif method == "sys": + return py.io.StdCapture(now=False, + out=self._makestringio(), err=self._makestringio() + ) + elif method == "no": + return NoCapture() + else: + raise ValueError("unknown capturing method: %r" % method) + + def _getmethod_preoptionparse(self, args): + if '-s' in args or "--capture=no" in args: + return "no" + elif hasattr(os, 'dup') and '--capture=sys' not in args: + return "fd" + else: + return "sys" + + def _getmethod(self, config, fspath): + if config.option.capture: + method = config.option.capture + else: + try: + method = config._conftest.rget("option_capture", path=fspath) + except KeyError: + method = "fd" + if method == "fd" and not hasattr(os, 'dup'): # e.g. jython + method = "sys" + return method + + def resumecapture_item(self, item): + method = self._getmethod(item.config, item.fspath) + if not hasattr(item, 'outerr'): + item.outerr = ('', '') # we accumulate outerr on the item + return self.resumecapture(method) + + def resumecapture(self, method): + if hasattr(self, '_capturing'): + raise ValueError("cannot resume, already capturing with %r" % + (self._capturing,)) + cap = self._method2capture.get(method) + self._capturing = method + if cap is None: + self._method2capture[method] = cap = self._getcapture(method) + cap.startall() + else: + cap.resume() + + def suspendcapture(self, item=None): + self.deactivate_funcargs() + if hasattr(self, '_capturing'): + method = self._capturing + cap = self._method2capture.get(method) + if cap is not None: + outerr = cap.suspend() + del self._capturing + if item: + outerr = (item.outerr[0] + outerr[0], + item.outerr[1] + outerr[1]) + return outerr + if hasattr(item, 'outerr'): + return item.outerr + return "", "" + + def activate_funcargs(self, pyfuncitem): + if not hasattr(pyfuncitem, 'funcargs'): + return + assert not hasattr(self, '_capturing_funcargs') + self._capturing_funcargs = capturing_funcargs = [] + for name, capfuncarg in pyfuncitem.funcargs.items(): + if name in ('capsys', 'capfd'): + capturing_funcargs.append(capfuncarg) + capfuncarg._start() + + def deactivate_funcargs(self): + capturing_funcargs = getattr(self, '_capturing_funcargs', None) + if capturing_funcargs is not None: + while capturing_funcargs: + capfuncarg = capturing_funcargs.pop() + capfuncarg._finalize() + del self._capturing_funcargs + + def pytest_make_collect_report(self, __multicall__, collector): + method = self._getmethod(collector.config, collector.fspath) + try: + self.resumecapture(method) + except ValueError: + return # recursive collect, XXX refactor capturing + # to allow for more lightweight recursive capturing + try: + rep = __multicall__.execute() + finally: + outerr = self.suspendcapture() + addouterr(rep, outerr) + return rep + + @pytest.mark.tryfirst + def pytest_runtest_setup(self, item): + self.resumecapture_item(item) + + @pytest.mark.tryfirst + def pytest_runtest_call(self, item): + self.resumecapture_item(item) + self.activate_funcargs(item) + + @pytest.mark.tryfirst + def pytest_runtest_teardown(self, item): + self.resumecapture_item(item) + + def pytest__teardown_final(self, __multicall__, session): + method = self._getmethod(session.config, None) + self.resumecapture(method) + try: + rep = __multicall__.execute() + finally: + outerr = self.suspendcapture() + if rep: + addouterr(rep, outerr) + return rep + + def pytest_keyboard_interrupt(self, excinfo): + if hasattr(self, '_capturing'): + self.suspendcapture() + + @pytest.mark.tryfirst + def pytest_runtest_makereport(self, __multicall__, item, call): + self.deactivate_funcargs() + rep = __multicall__.execute() + outerr = self.suspendcapture(item) + if not rep.passed: + addouterr(rep, outerr) + if not rep.passed or rep.when == "teardown": + outerr = ('', '') + item.outerr = outerr + return rep + +def pytest_funcarg__capsys(request): + """enables capturing of writes to sys.stdout/sys.stderr and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. + """ + return CaptureFuncarg(py.io.StdCapture) + +def pytest_funcarg__capfd(request): + """enables capturing of writes to file descriptors 1 and 2 and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. + """ + if not hasattr(os, 'dup'): + py.test.skip("capfd funcarg needs os.dup") + return CaptureFuncarg(py.io.StdCaptureFD) + +class CaptureFuncarg: + def __init__(self, captureclass): + self.capture = captureclass(now=False) + + def _start(self): + self.capture.startall() + + def _finalize(self): + if hasattr(self, 'capture'): + self.capture.reset() + del self.capture + + def readouterr(self): + return self.capture.readouterr() + + def close(self): + self._finalize() diff --git a/lib/pypy/_pytest/config.py b/lib/pypy/_pytest/config.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/config.py @@ -0,0 +1,449 @@ +""" command line options, ini-file and conftest.py processing. """ + +import py +import sys, os +from _pytest.core import PluginManager +import pytest + +def pytest_cmdline_parse(pluginmanager, args): + config = Config(pluginmanager) + config.parse(args) + if config.option.debug: + config.trace.root.setwriter(sys.stderr.write) + return config + +def pytest_unconfigure(config): + for func in config._cleanup: + func() + +class Parser: + """ Parser for command line arguments. """ + + def __init__(self, usage=None, processopt=None): + self._anonymous = OptionGroup("custom options", parser=self) + self._groups = [] + self._processopt = processopt + self._usage = usage + self._inidict = {} + self._ininames = [] + self.hints = [] + + def processoption(self, option): + if self._processopt: + if option.dest: + self._processopt(option) + + def addnote(self, note): + self._notes.append(note) + + def getgroup(self, name, description="", after=None): + """ get (or create) a named option Group. + + :name: unique name of the option group. + :description: long description for --help output. + :after: name of other group, used for ordering --help output. + """ + for group in self._groups: + if group.name == name: + return group + group = OptionGroup(name, description, parser=self) + i = 0 + for i, grp in enumerate(self._groups): + if grp.name == after: + break + self._groups.insert(i+1, group) + return group + + def addoption(self, *opts, **attrs): + """ add an optparse-style option. """ + self._anonymous.addoption(*opts, **attrs) + + def parse(self, args): + self.optparser = optparser = MyOptionParser(self) + groups = self._groups + [self._anonymous] + for group in groups: + if group.options: + desc = group.description or group.name + optgroup = py.std.optparse.OptionGroup(optparser, desc) + optgroup.add_options(group.options) + optparser.add_option_group(optgroup) + return self.optparser.parse_args([str(x) for x in args]) + + def parse_setoption(self, args, option): + parsedoption, args = self.parse(args) + for name, value in parsedoption.__dict__.items(): + setattr(option, name, value) + return args + + def addini(self, name, help, type=None, default=None): + """ add an ini-file option with the given name and description. """ + assert type in (None, "pathlist", "args", "linelist") + self._inidict[name] = (help, type, default) + self._ininames.append(name) + +class OptionGroup: + def __init__(self, name, description="", parser=None): + self.name = name + self.description = description + self.options = [] + self.parser = parser + + def addoption(self, *optnames, **attrs): + """ add an option to this group. """ + option = py.std.optparse.Option(*optnames, **attrs) + self._addoption_instance(option, shortupper=False) + + def _addoption(self, *optnames, **attrs): + option = py.std.optparse.Option(*optnames, **attrs) + self._addoption_instance(option, shortupper=True) + + def _addoption_instance(self, option, shortupper=False): + if not shortupper: + for opt in option._short_opts: + if opt[0] == '-' and opt[1].islower(): + raise ValueError("lowercase shortoptions reserved") + if self.parser: + self.parser.processoption(option) + self.options.append(option) + + +class MyOptionParser(py.std.optparse.OptionParser): + def __init__(self, parser): + self._parser = parser + py.std.optparse.OptionParser.__init__(self, usage=parser._usage, + add_help_option=False) + def format_epilog(self, formatter): + hints = self._parser.hints + if hints: + s = "\n".join(["hint: " + x for x in hints]) + "\n" + s = "\n" + s + "\n" + return s + return "" + +class Conftest(object): + """ the single place for accessing values and interacting + towards conftest modules from py.test objects. + """ + def __init__(self, onimport=None, confcutdir=None): + self._path2confmods = {} + self._onimport = onimport + self._conftestpath2mod = {} + self._confcutdir = confcutdir + + def setinitial(self, args): + """ try to find a first anchor path for looking up global values + from conftests. This function is usually called _before_ + argument parsing. conftest files may add command line options + and we thus have no completely safe way of determining + which parts of the arguments are actually related to options + and which are file system paths. We just try here to get + bootstrapped ... + """ + current = py.path.local() + opt = '--confcutdir' + for i in range(len(args)): + opt1 = str(args[i]) + if opt1.startswith(opt): + if opt1 == opt: + if len(args) > i: + p = current.join(args[i+1], abs=True) + elif opt1.startswith(opt + "="): + p = current.join(opt1[len(opt)+1:], abs=1) + self._confcutdir = p + break + for arg in args + [current]: + if hasattr(arg, 'startswith') and arg.startswith("--"): + continue + anchor = current.join(arg, abs=1) + if anchor.check(): # we found some file object + self._path2confmods[None] = self.getconftestmodules(anchor) + # let's also consider test* dirs + if anchor.check(dir=1): + for x in anchor.listdir("test*"): + if x.check(dir=1): + self.getconftestmodules(x) + break + else: + assert 0, "no root of filesystem?" + + def getconftestmodules(self, path): + """ return a list of imported conftest modules for the given path. """ + try: + clist = self._path2confmods[path] + except KeyError: + if path is None: + raise ValueError("missing default confest.") + dp = path.dirpath() + clist = [] + if dp != path: + cutdir = self._confcutdir + if cutdir and path != cutdir and not path.relto(cutdir): + pass + else: + conftestpath = path.join("conftest.py") + if conftestpath.check(file=1): + clist.append(self.importconftest(conftestpath)) + clist[:0] = self.getconftestmodules(dp) + self._path2confmods[path] = clist + # be defensive: avoid changes from caller side to + # affect us by always returning a copy of the actual list + return clist[:] + + def rget(self, name, path=None): + mod, value = self.rget_with_confmod(name, path) + return value + + def rget_with_confmod(self, name, path=None): + modules = self.getconftestmodules(path) + modules.reverse() + for mod in modules: + try: + return mod, getattr(mod, name) + except AttributeError: + continue + raise KeyError(name) + + def importconftest(self, conftestpath): + assert conftestpath.check(), conftestpath + try: + return self._conftestpath2mod[conftestpath] + except KeyError: + pkgpath = conftestpath.pypkgpath() + if pkgpath is None: + _ensure_removed_sysmodule(conftestpath.purebasename) + self._conftestpath2mod[conftestpath] = mod = conftestpath.pyimport() + dirpath = conftestpath.dirpath() + if dirpath in self._path2confmods: + for path, mods in self._path2confmods.items(): + if path and path.relto(dirpath) or path == dirpath: + assert mod not in mods + mods.append(mod) + self._postimport(mod) + return mod + + def _postimport(self, mod): + if self._onimport: + self._onimport(mod) + return mod + +def _ensure_removed_sysmodule(modname): + try: + del sys.modules[modname] + except KeyError: + pass + +class CmdOptions(object): + """ holds cmdline options as attributes.""" + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + def __repr__(self): + return "" %(self.__dict__,) + +class Config(object): + """ access to configuration values, pluginmanager and plugin hooks. """ + def __init__(self, pluginmanager=None): + #: command line option values, usually added via parser.addoption(...) + #: or parser.getgroup(...).addoption(...) calls + self.option = CmdOptions() + self._parser = Parser( + usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]", + processopt=self._processopt, + ) + #: a pluginmanager instance + self.pluginmanager = pluginmanager or PluginManager(load=True) + self.trace = self.pluginmanager.trace.root.get("config") + self._conftest = Conftest(onimport=self._onimportconftest) + self.hook = self.pluginmanager.hook + self._inicache = {} + self._cleanup = [] + + @classmethod + def fromdictargs(cls, option_dict, args): + """ constructor useable for subprocesses. """ + config = cls() + config._preparse(args, addopts=False) + config.option.__dict__.update(option_dict) + for x in config.option.plugins: + config.pluginmanager.consider_pluginarg(x) + return config + + def _onimportconftest(self, conftestmodule): + self.trace("loaded conftestmodule %r" %(conftestmodule,)) + self.pluginmanager.consider_conftest(conftestmodule) + + def _processopt(self, opt): + if hasattr(opt, 'default') and opt.dest: + if not hasattr(self.option, opt.dest): + setattr(self.option, opt.dest, opt.default) + + def _getmatchingplugins(self, fspath): + allconftests = self._conftest._conftestpath2mod.values() + plugins = [x for x in self.pluginmanager.getplugins() + if x not in allconftests] + plugins += self._conftest.getconftestmodules(fspath) + return plugins + + def _setinitialconftest(self, args): + # capture output during conftest init (#issue93) + from _pytest.capture import CaptureManager + capman = CaptureManager() + self.pluginmanager.register(capman, 'capturemanager') + # will be unregistered in capture.py's unconfigure() + capman.resumecapture(capman._getmethod_preoptionparse(args)) + try: + try: + self._conftest.setinitial(args) + finally: + out, err = capman.suspendcapture() # logging might have got it + except: + sys.stdout.write(out) + sys.stderr.write(err) + raise + + def _initini(self, args): + self.inicfg = getcfg(args, ["pytest.ini", "tox.ini", "setup.cfg"]) + self._parser.addini('addopts', 'extra command line options', 'args') + self._parser.addini('minversion', 'minimally required pytest version') + + def _preparse(self, args, addopts=True): + self._initini(args) + if addopts: + args[:] = self.getini("addopts") + args + self._checkversion() + self.pluginmanager.consider_preparse(args) + self.pluginmanager.consider_setuptools_entrypoints() + self.pluginmanager.consider_env() + self._setinitialconftest(args) + self.pluginmanager.do_addoption(self._parser) + if addopts: + self.hook.pytest_cmdline_preparse(config=self, args=args) + + def _checkversion(self): + minver = self.inicfg.get('minversion', None) + if minver: + ver = minver.split(".") + myver = pytest.__version__.split(".") + if myver < ver: + raise pytest.UsageError( + "%s:%d: requires pytest-%s, actual pytest-%s'" %( + self.inicfg.config.path, self.inicfg.lineof('minversion'), + minver, pytest.__version__)) + + def parse(self, args): + # parse given cmdline arguments into this config object. + # Note that this can only be called once per testing process. + assert not hasattr(self, 'args'), ( + "can only parse cmdline args at most once per Config object") + self._preparse(args) + self._parser.hints.extend(self.pluginmanager._hints) + args = self._parser.parse_setoption(args, self.option) + if not args: + args.append(py.std.os.getcwd()) + self.args = args + + def getini(self, name): + """ return configuration value from an ini file. If the + specified name hasn't been registered through a prior ``parse.addini`` + call (usually from a plugin), a ValueError is raised. """ + try: + return self._inicache[name] + except KeyError: + self._inicache[name] = val = self._getini(name) + return val + + def _getini(self, name): + try: + description, type, default = self._parser._inidict[name] + except KeyError: + raise ValueError("unknown configuration value: %r" %(name,)) + try: + value = self.inicfg[name] + except KeyError: + if default is not None: + return default + if type is None: + return '' + return [] + if type == "pathlist": + dp = py.path.local(self.inicfg.config.path).dirpath() + l = [] + for relpath in py.std.shlex.split(value): + l.append(dp.join(relpath, abs=True)) + return l + elif type == "args": + return py.std.shlex.split(value) + elif type == "linelist": + return [t for t in map(lambda x: x.strip(), value.split("\n")) if t] + else: + assert type is None + return value + + def _getconftest_pathlist(self, name, path=None): + try: + mod, relroots = self._conftest.rget_with_confmod(name, path) + except KeyError: + return None + modpath = py.path.local(mod.__file__).dirpath() + l = [] + for relroot in relroots: + if not isinstance(relroot, py.path.local): + relroot = relroot.replace("/", py.path.local.sep) + relroot = modpath.join(relroot, abs=True) + l.append(relroot) + return l + + def _getconftest(self, name, path=None, check=False): + if check: + self._checkconftest(name) + return self._conftest.rget(name, path) + + def getvalue(self, name, path=None): + """ return ``name`` value looked set from command line options. + + (deprecated) if we can't find the option also lookup + the name in a matching conftest file. + """ + try: + return getattr(self.option, name) + except AttributeError: + return self._getconftest(name, path, check=False) + + def getvalueorskip(self, name, path=None): + """ (deprecated) return getvalue(name) or call + py.test.skip if no value exists. """ + __tracebackhide__ = True + try: + val = self.getvalue(name, path) + if val is None: + raise KeyError(name) + return val + except KeyError: + py.test.skip("no %r value found" %(name,)) + + +def getcfg(args, inibasenames): + args = [x for x in args if str(x)[0] != "-"] + if not args: + args = [py.path.local()] + for arg in args: + arg = py.path.local(arg) + for base in arg.parts(reverse=True): + for inibasename in inibasenames: + p = base.join(inibasename) + if p.check(): + iniconfig = py.iniconfig.IniConfig(p) + if 'pytest' in iniconfig.sections: + return iniconfig['pytest'] + return {} + +def findupwards(current, basename): + current = py.path.local(current) + while 1: + p = current.join(basename) + if p.check(): + return p + p = current.dirpath() + if p == current: + return + current = p + diff --git a/lib/pypy/_pytest/core.py b/lib/pypy/_pytest/core.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/core.py @@ -0,0 +1,467 @@ +""" +pytest PluginManager, basic initialization and tracing. +(c) Holger Krekel 2004-2010 +""" +import sys, os +import inspect +import py +from _pytest import hookspec # the extension point definitions + +assert py.__version__.split(".")[:2] >= ['1', '4'], ("installation problem: " + "%s is too old, remove or upgrade 'py'" % (py.__version__)) + +default_plugins = ( + "config mark main terminal runner python pdb unittest capture skipping " + "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript " + "junitxml resultlog doctest").split() + +class TagTracer: + def __init__(self, prefix="[pytest] "): + self._tag2proc = {} + self.writer = None + self.indent = 0 + self.prefix = prefix + + def get(self, name): + return TagTracerSub(self, (name,)) + + def processmessage(self, tags, args): + if self.writer is not None: + if args: + indent = " " * self.indent + content = " ".join(map(str, args)) + self.writer("%s%s%s\n" %(self.prefix, indent, content)) + try: + self._tag2proc[tags](tags, args) + except KeyError: + pass + + def setwriter(self, writer): + self.writer = writer + + def setprocessor(self, tags, processor): + if isinstance(tags, str): + tags = tuple(tags.split(":")) + else: + assert isinstance(tags, tuple) + self._tag2proc[tags] = processor + +class TagTracerSub: + def __init__(self, root, tags): + self.root = root + self.tags = tags + def __call__(self, *args): + self.root.processmessage(self.tags, args) + def setmyprocessor(self, processor): + self.root.setprocessor(self.tags, processor) + def get(self, name): + return self.__class__(self.root, self.tags + (name,)) + +class PluginManager(object): + def __init__(self, load=False): + self._name2plugin = {} + self._listattrcache = {} + self._plugins = [] + self._hints = [] + self.trace = TagTracer().get("pluginmanage") + self._plugin_distinfo = [] + if os.environ.get('PYTEST_DEBUG'): + err = sys.stderr + encoding = getattr(err, 'encoding', 'utf8') + try: + err = py.io.dupfile(err, encoding=encoding) + except Exception: + pass + self.trace.root.setwriter(err.write) + self.hook = HookRelay([hookspec], pm=self) + self.register(self) + if load: + for spec in default_plugins: + self.import_plugin(spec) + + def register(self, plugin, name=None, prepend=False): + assert not self.isregistered(plugin), plugin + name = name or getattr(plugin, '__name__', str(id(plugin))) + if name in self._name2plugin: + return False + #self.trace("registering", name, plugin) + self._name2plugin[name] = plugin + self.call_plugin(plugin, "pytest_addhooks", {'pluginmanager': self}) + self.hook.pytest_plugin_registered(manager=self, plugin=plugin) + if not prepend: + self._plugins.append(plugin) + else: + self._plugins.insert(0, plugin) + return True + + def unregister(self, plugin=None, name=None): + if plugin is None: + plugin = self.getplugin(name=name) + self._plugins.remove(plugin) + self.hook.pytest_plugin_unregistered(plugin=plugin) + for name, value in list(self._name2plugin.items()): + if value == plugin: + del self._name2plugin[name] + + def isregistered(self, plugin, name=None): + if self.getplugin(name) is not None: + return True + for val in self._name2plugin.values(): + if plugin == val: + return True + + def addhooks(self, spec): + self.hook._addhooks(spec, prefix="pytest_") + + def getplugins(self): + return list(self._plugins) + + def skipifmissing(self, name): + if not self.hasplugin(name): + py.test.skip("plugin %r is missing" % name) + + def hasplugin(self, name): + return bool(self.getplugin(name)) + + def getplugin(self, name): + if name is None: + return None + try: + return self._name2plugin[name] + except KeyError: + return self._name2plugin.get("_pytest." + name, None) + + # API for bootstrapping + # + def _envlist(self, varname): + val = py.std.os.environ.get(varname, None) + if val is not None: + return val.split(',') + return () + + def consider_env(self): + for spec in self._envlist("PYTEST_PLUGINS"): + self.import_plugin(spec) + + def consider_setuptools_entrypoints(self): + try: + from pkg_resources import iter_entry_points, DistributionNotFound + except ImportError: + return # XXX issue a warning + for ep in iter_entry_points('pytest11'): + name = ep.name + if name.startswith("pytest_"): + name = name[7:] + if ep.name in self._name2plugin or name in self._name2plugin: + continue + try: + plugin = ep.load() + except DistributionNotFound: + continue + self._plugin_distinfo.append((ep.dist, plugin)) + self.register(plugin, name=name) + + def consider_preparse(self, args): + for opt1,opt2 in zip(args, args[1:]): + if opt1 == "-p": + self.consider_pluginarg(opt2) + + def consider_pluginarg(self, arg): + if arg.startswith("no:"): + name = arg[3:] + if self.getplugin(name) is not None: + self.unregister(None, name=name) + self._name2plugin[name] = -1 + else: + if self.getplugin(arg) is None: + self.import_plugin(arg) + + def consider_conftest(self, conftestmodule): + if self.register(conftestmodule, name=conftestmodule.__file__): + self.consider_module(conftestmodule) + + def consider_module(self, mod): + attr = getattr(mod, "pytest_plugins", ()) + if attr: + if not isinstance(attr, (list, tuple)): + attr = (attr,) + for spec in attr: + self.import_plugin(spec) + + def import_plugin(self, modname): + assert isinstance(modname, str) + if self.getplugin(modname) is not None: + return + try: + #self.trace("importing", modname) + mod = importplugin(modname) + except KeyboardInterrupt: + raise + except ImportError: + if modname.startswith("pytest_"): + return self.import_plugin(modname[7:]) + raise + except: + e = py.std.sys.exc_info()[1] + if not hasattr(py.test, 'skip'): + raise + elif not isinstance(e, py.test.skip.Exception): + raise + self._hints.append("skipped plugin %r: %s" %((modname, e.msg))) + else: + self.register(mod, modname) + self.consider_module(mod) + + def pytest_plugin_registered(self, plugin): + import pytest + dic = self.call_plugin(plugin, "pytest_namespace", {}) or {} + if dic: + self._setns(pytest, dic) + if hasattr(self, '_config'): + self.call_plugin(plugin, "pytest_addoption", + {'parser': self._config._parser}) + self.call_plugin(plugin, "pytest_configure", + {'config': self._config}) + + def _setns(self, obj, dic): + import pytest + for name, value in dic.items(): + if isinstance(value, dict): + mod = getattr(obj, name, None) + if mod is None: + modname = "pytest.%s" % name + mod = py.std.types.ModuleType(modname) + sys.modules[modname] = mod + mod.__all__ = [] + setattr(obj, name, mod) + obj.__all__.append(name) + self._setns(mod, value) + else: + setattr(obj, name, value) + obj.__all__.append(name) + #if obj != pytest: + # pytest.__all__.append(name) + setattr(pytest, name, value) + + def pytest_terminal_summary(self, terminalreporter): + tw = terminalreporter._tw + if terminalreporter.config.option.traceconfig: + for hint in self._hints: + tw.line("hint: %s" % hint) + + def do_addoption(self, parser): + mname = "pytest_addoption" + methods = reversed(self.listattr(mname)) + MultiCall(methods, {'parser': parser}).execute() + + def do_configure(self, config): + assert not hasattr(self, '_config') + self._config = config + config.hook.pytest_configure(config=self._config) + + def do_unconfigure(self, config): + config = self._config + del self._config + config.hook.pytest_unconfigure(config=config) + config.pluginmanager.unregister(self) + + def notify_exception(self, excinfo, option=None): + if option and option.fulltrace: + style = "long" + else: + style = "native" + excrepr = excinfo.getrepr(funcargs=True, + showlocals=getattr(option, 'showlocals', False), + style=style, + ) + res = self.hook.pytest_internalerror(excrepr=excrepr) + if not py.builtin.any(res): + for line in str(excrepr).split("\n"): + sys.stderr.write("INTERNALERROR> %s\n" %line) + sys.stderr.flush() + + def listattr(self, attrname, plugins=None): + if plugins is None: + plugins = self._plugins + key = (attrname,) + tuple(plugins) + try: + return list(self._listattrcache[key]) + except KeyError: + pass + l = [] + last = [] + for plugin in plugins: + try: + meth = getattr(plugin, attrname) + if hasattr(meth, 'tryfirst'): + last.append(meth) + elif hasattr(meth, 'trylast'): + l.insert(0, meth) + else: + l.append(meth) + except AttributeError: + continue + l.extend(last) + self._listattrcache[key] = list(l) + return l + + def call_plugin(self, plugin, methname, kwargs): + return MultiCall(methods=self.listattr(methname, plugins=[plugin]), + kwargs=kwargs, firstresult=True).execute() + + +def importplugin(importspec): + name = importspec + try: + mod = "_pytest." + name + return __import__(mod, None, None, '__doc__') + except ImportError: + #e = py.std.sys.exc_info()[1] + #if str(e).find(name) == -1: + # raise + pass # + return __import__(importspec, None, None, '__doc__') + +class MultiCall: + """ execute a call into multiple python functions/methods. """ + def __init__(self, methods, kwargs, firstresult=False): + self.methods = list(methods) + self.kwargs = kwargs + self.results = [] + self.firstresult = firstresult + + def __repr__(self): + status = "%d results, %d meths" % (len(self.results), len(self.methods)) + return "" %(status, self.kwargs) + + def execute(self): + while self.methods: + method = self.methods.pop() + kwargs = self.getkwargs(method) + res = method(**kwargs) + if res is not None: + self.results.append(res) + if self.firstresult: + return res + if not self.firstresult: + return self.results + + def getkwargs(self, method): + kwargs = {} + for argname in varnames(method): + try: + kwargs[argname] = self.kwargs[argname] + except KeyError: + if argname == "__multicall__": + kwargs[argname] = self + return kwargs + +def varnames(func): + try: + return func._varnames + except AttributeError: + pass + if not inspect.isfunction(func) and not inspect.ismethod(func): + func = getattr(func, '__call__', func) + ismethod = inspect.ismethod(func) + rawcode = py.code.getrawcode(func) + try: + x = rawcode.co_varnames[ismethod:rawcode.co_argcount] + except AttributeError: + x = () + py.builtin._getfuncdict(func)['_varnames'] = x + return x + +class HookRelay: + def __init__(self, hookspecs, pm, prefix="pytest_"): + if not isinstance(hookspecs, list): + hookspecs = [hookspecs] + self._hookspecs = [] + self._pm = pm + self.trace = pm.trace.root.get("hook") + for hookspec in hookspecs: + self._addhooks(hookspec, prefix) + + def _addhooks(self, hookspecs, prefix): + self._hookspecs.append(hookspecs) + added = False + for name, method in vars(hookspecs).items(): + if name.startswith(prefix): + firstresult = getattr(method, 'firstresult', False) + hc = HookCaller(self, name, firstresult=firstresult) + setattr(self, name, hc) + added = True + #print ("setting new hook", name) + if not added: + raise ValueError("did not find new %r hooks in %r" %( + prefix, hookspecs,)) + + +class HookCaller: + def __init__(self, hookrelay, name, firstresult): + self.hookrelay = hookrelay + self.name = name + self.firstresult = firstresult + self.trace = self.hookrelay.trace + + def __repr__(self): + return "" %(self.name,) + + def __call__(self, **kwargs): + methods = self.hookrelay._pm.listattr(self.name) + return self._docall(methods, kwargs) + + def pcall(self, plugins, **kwargs): + methods = self.hookrelay._pm.listattr(self.name, plugins=plugins) + return self._docall(methods, kwargs) + + def _docall(self, methods, kwargs): + self.trace(self.name, kwargs) + self.trace.root.indent += 1 + mc = MultiCall(methods, kwargs, firstresult=self.firstresult) + try: + res = mc.execute() + if res: + self.trace("finish", self.name, "-->", res) + finally: + self.trace.root.indent -= 1 + return res + +_preinit = [] + +def _preloadplugins(): + _preinit.append(PluginManager(load=True)) + +def main(args=None, plugins=None): + """ returned exit code integer, after an in-process testing run + with the given command line arguments, preloading an optional list + of passed in plugin objects. """ + if args is None: + args = sys.argv[1:] + elif isinstance(args, py.path.local): + args = [str(args)] + elif not isinstance(args, (tuple, list)): + if not isinstance(args, str): + raise ValueError("not a string or argument list: %r" % (args,)) + args = py.std.shlex.split(args) + if _preinit: + _pluginmanager = _preinit.pop(0) + else: # subsequent calls to main will create a fresh instance + _pluginmanager = PluginManager(load=True) + hook = _pluginmanager.hook + try: + if plugins: + for plugin in plugins: + _pluginmanager.register(plugin) + config = hook.pytest_cmdline_parse( + pluginmanager=_pluginmanager, args=args) + exitstatus = hook.pytest_cmdline_main(config=config) + except UsageError: + e = sys.exc_info()[1] + sys.stderr.write("ERROR: %s\n" %(e.args[0],)) + exitstatus = 3 + return exitstatus + +class UsageError(Exception): + """ error in py.test usage or invocation""" + diff --git a/lib/pypy/_pytest/doctest.py b/lib/pypy/_pytest/doctest.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/doctest.py @@ -0,0 +1,87 @@ +""" discover and run doctests in modules and test files.""" + +import pytest, py +from py._code.code import TerminalRepr, ReprFileLocation + +def pytest_addoption(parser): + group = parser.getgroup("collect") + group.addoption("--doctest-modules", + action="store_true", default=False, + help="run doctests in all .py modules", + dest="doctestmodules") + group.addoption("--doctest-glob", + action="store", default="test*.txt", metavar="pat", + help="doctests file matching pattern, default: test*.txt", + dest="doctestglob") + +def pytest_collect_file(path, parent): + config = parent.config + if path.ext == ".py": + if config.option.doctestmodules: + return DoctestModule(path, parent) + elif (path.ext in ('.txt', '.rst') and parent.session.isinitpath(path)) or \ + path.check(fnmatch=config.getvalue("doctestglob")): + return DoctestTextfile(path, parent) + +class ReprFailDoctest(TerminalRepr): + def __init__(self, reprlocation, lines): + self.reprlocation = reprlocation + self.lines = lines + def toterminal(self, tw): + for line in self.lines: + tw.line(line) + self.reprlocation.toterminal(tw) + +class DoctestItem(pytest.Item): + def repr_failure(self, excinfo): + doctest = py.std.doctest + if excinfo.errisinstance((doctest.DocTestFailure, + doctest.UnexpectedException)): + doctestfailure = excinfo.value + example = doctestfailure.example + test = doctestfailure.test + filename = test.filename + lineno = test.lineno + example.lineno + 1 + message = excinfo.type.__name__ + reprlocation = ReprFileLocation(filename, lineno, message) + checker = py.std.doctest.OutputChecker() + REPORT_UDIFF = py.std.doctest.REPORT_UDIFF + filelines = py.path.local(filename).readlines(cr=0) + i = max(test.lineno, max(0, lineno - 10)) # XXX? + lines = [] + for line in filelines[i:lineno]: + lines.append("%03d %s" % (i+1, line)) + i += 1 + if excinfo.errisinstance(doctest.DocTestFailure): + lines += checker.output_difference(example, + doctestfailure.got, REPORT_UDIFF).split("\n") + else: + inner_excinfo = py.code.ExceptionInfo(excinfo.value.exc_info) + lines += ["UNEXPECTED EXCEPTION: %s" % + repr(inner_excinfo.value)] + lines += py.std.traceback.format_exception(*excinfo.value.exc_info) + return ReprFailDoctest(reprlocation, lines) + else: + return super(DoctestItem, self).repr_failure(excinfo) + + def reportinfo(self): + return self.fspath, None, "[doctest]" + +class DoctestTextfile(DoctestItem, pytest.File): + def runtest(self): + doctest = py.std.doctest + failed, tot = doctest.testfile( + str(self.fspath), module_relative=False, + optionflags=doctest.ELLIPSIS, + raise_on_error=True, verbose=0) + +class DoctestModule(DoctestItem, pytest.File): + def runtest(self): + doctest = py.std.doctest + if self.fspath.basename == "conftest.py": + module = self.config._conftest.importconftest(self.fspath) + else: + module = self.fspath.pyimport() + failed, tot = doctest.testmod( + module, raise_on_error=True, verbose=0, + optionflags=doctest.ELLIPSIS) diff --git a/lib/pypy/_pytest/genscript.py b/lib/pypy/_pytest/genscript.py new file mode 100755 --- /dev/null +++ b/lib/pypy/_pytest/genscript.py @@ -0,0 +1,69 @@ +""" generate a single-file self-contained version of py.test """ +import py + +def find_toplevel(name): + for syspath in py.std.sys.path: + base = py.path.local(syspath) + lib = base/name + if lib.check(dir=1): + return lib + mod = base.join("%s.py" % name) + if mod.check(file=1): + return mod + raise LookupError(name) + +def pkgname(toplevel, rootpath, path): + parts = path.parts()[len(rootpath.parts()):] + return '.'.join([toplevel] + [x.purebasename for x in parts]) + +def pkg_to_mapping(name): + toplevel = find_toplevel(name) + name2src = {} + if toplevel.check(file=1): # module + name2src[toplevel.purebasename] = toplevel.read() + else: # package + for pyfile in toplevel.visit('*.py'): + pkg = pkgname(name, toplevel, pyfile) + name2src[pkg] = pyfile.read() + return name2src + +def compress_mapping(mapping): + data = py.std.pickle.dumps(mapping, 2) + data = py.std.zlib.compress(data, 9) + data = py.std.base64.encodestring(data) + data = data.decode('ascii') + return data + + +def compress_packages(names): + mapping = {} + for name in names: + mapping.update(pkg_to_mapping(name)) + return compress_mapping(mapping) + +def generate_script(entry, packages): + data = compress_packages(packages) + tmpl = py.path.local(__file__).dirpath().join('standalonetemplate.py') + exe = tmpl.read() + exe = exe.replace('@SOURCES@', data) + exe = exe.replace('@ENTRY@', entry) + return exe + + +def pytest_addoption(parser): + group = parser.getgroup("debugconfig") + group.addoption("--genscript", action="store", default=None, + dest="genscript", metavar="path", + help="create standalone py.test script at given target path.") + +def pytest_cmdline_main(config): + genscript = config.getvalue("genscript") + if genscript: + script = generate_script( + 'import py; raise SystemExit(py.test.cmdline.main())', + ['py', '_pytest', 'pytest'], + ) + + genscript = py.path.local(genscript) + genscript.write(script) + return 0 diff --git a/lib/pypy/_pytest/helpconfig.py b/lib/pypy/_pytest/helpconfig.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/helpconfig.py @@ -0,0 +1,174 @@ +""" version info, help messages, tracing configuration. """ +import py +import pytest +import inspect, sys +from _pytest.core import varnames + +def pytest_addoption(parser): + group = parser.getgroup('debugconfig') + group.addoption('--version', action="store_true", + help="display pytest lib version and import information.") + group._addoption("-h", "--help", action="store_true", dest="help", + help="show help message and configuration info") + group._addoption('-p', action="append", dest="plugins", default = [], + metavar="name", + help="early-load given plugin (multi-allowed).") + group.addoption('--traceconfig', + action="store_true", dest="traceconfig", default=False, + help="trace considerations of conftest.py files."), + group.addoption('--debug', + action="store_true", dest="debug", default=False, + help="generate and show internal debugging information.") + + +def pytest_cmdline_main(config): + if config.option.version: + p = py.path.local(pytest.__file__) + sys.stderr.write("This is py.test version %s, imported from %s\n" % + (pytest.__version__, p)) + plugininfo = getpluginversioninfo(config) + if plugininfo: + for line in plugininfo: + sys.stderr.write(line + "\n") + return 0 + elif config.option.help: + config.pluginmanager.do_configure(config) + showhelp(config) + return 0 + +def showhelp(config): + tw = py.io.TerminalWriter() + tw.write(config._parser.optparser.format_help()) + tw.line() + tw.line() + #tw.sep( "=", "config file settings") + tw.line("[pytest] ini-options in the next " + "pytest.ini|tox.ini|setup.cfg file:") + tw.line() + + for name in config._parser._ininames: + help, type, default = config._parser._inidict[name] + if type is None: + type = "string" + spec = "%s (%s)" % (name, type) + line = " %-24s %s" %(spec, help) + tw.line(line[:tw.fullwidth]) + + tw.line() ; tw.line() + #tw.sep("=") + return + + tw.line("conftest.py options:") + tw.line() + conftestitems = sorted(config._parser._conftestdict.items()) + for name, help in conftest_options + conftestitems: + line = " %-15s %s" %(name, help) + tw.line(line[:tw.fullwidth]) + tw.line() + #tw.sep( "=") + +conftest_options = [ + ('pytest_plugins', 'list of plugin names to load'), +] + +def getpluginversioninfo(config): + lines = [] + plugininfo = config.pluginmanager._plugin_distinfo + if plugininfo: + lines.append("setuptools registered plugins:") + for dist, plugin in plugininfo: + loc = getattr(plugin, '__file__', repr(plugin)) + content = "%s-%s at %s" % (dist.project_name, dist.version, loc) + lines.append(" " + content) + return lines + +def pytest_report_header(config): + lines = [] + if config.option.debug or config.option.traceconfig: + lines.append("using: pytest-%s pylib-%s" % + (pytest.__version__,py.__version__)) + + verinfo = getpluginversioninfo(config) + if verinfo: + lines.extend(verinfo) + + if config.option.traceconfig: + lines.append("active plugins:") + plugins = [] + items = config.pluginmanager._name2plugin.items() + for name, plugin in items: + if hasattr(plugin, '__file__'): + r = plugin.__file__ + else: + r = repr(plugin) + lines.append(" %-20s: %s" %(name, r)) + return lines + + +# ===================================================== +# validate plugin syntax and hooks +# ===================================================== + +def pytest_plugin_registered(manager, plugin): + methods = collectattr(plugin) + hooks = {} + for hookspec in manager.hook._hookspecs: + hooks.update(collectattr(hookspec)) + + stringio = py.io.TextIO() + def Print(*args): + if args: + stringio.write(" ".join(map(str, args))) + stringio.write("\n") + + fail = False + while methods: + name, method = methods.popitem() + #print "checking", name + if isgenerichook(name): + continue + if name not in hooks: + if not getattr(method, 'optionalhook', False): + Print("found unknown hook:", name) + fail = True + else: + #print "checking", method + method_args = list(varnames(method)) + if '__multicall__' in method_args: + method_args.remove('__multicall__') + hook = hooks[name] + hookargs = varnames(hook) + for arg in method_args: + if arg not in hookargs: + Print("argument %r not available" %(arg, )) + Print("actual definition: %s" %(formatdef(method))) + Print("available hook arguments: %s" % + ", ".join(hookargs)) + fail = True + break + #if not fail: + # print "matching hook:", formatdef(method) + if fail: + name = getattr(plugin, '__name__', plugin) + raise PluginValidationError("%s:\n%s" % (name, stringio.getvalue())) + +class PluginValidationError(Exception): + """ plugin failed validation. """ + +def isgenerichook(name): + return name == "pytest_plugins" or \ + name.startswith("pytest_funcarg__") + +def collectattr(obj): + methods = {} + for apiname in dir(obj): + if apiname.startswith("pytest_"): + methods[apiname] = getattr(obj, apiname) + return methods + +def formatdef(func): + return "%s%s" % ( + func.__name__, + inspect.formatargspec(*inspect.getargspec(func)) + ) + diff --git a/lib/pypy/_pytest/hookspec.py b/lib/pypy/_pytest/hookspec.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/hookspec.py @@ -0,0 +1,222 @@ +""" hook specifications for pytest plugins, invoked from main.py and builtin plugins. """ + +# ------------------------------------------------------------------------- +# Initialization +# ------------------------------------------------------------------------- + +def pytest_addhooks(pluginmanager): + """called at plugin load time to allow adding new hooks via a call to + pluginmanager.registerhooks(module).""" + + +def pytest_namespace(): + """return dict of name->object to be made globally available in + the py.test/pytest namespace. This hook is called before command + line options are parsed. + """ + +def pytest_cmdline_parse(pluginmanager, args): + """return initialized config object, parsing the specified args. """ +pytest_cmdline_parse.firstresult = True + +def pytest_cmdline_preparse(config, args): + """modify command line arguments before option parsing. """ + +def pytest_addoption(parser): + """add optparse-style options and ini-style config values via calls + to ``parser.addoption`` and ``parser.addini(...)``. + """ + +def pytest_cmdline_main(config): + """ called for performing the main command line action. The default + implementation will invoke the configure hooks and runtest_mainloop. """ +pytest_cmdline_main.firstresult = True + +def pytest_configure(config): + """ called after command line options have been parsed. + and all plugins and initial conftest files been loaded. + """ + +def pytest_unconfigure(config): + """ called before test process is exited. """ + +def pytest_runtestloop(session): + """ called for performing the main runtest loop + (after collection finished). """ +pytest_runtestloop.firstresult = True + +# ------------------------------------------------------------------------- +# collection hooks +# ------------------------------------------------------------------------- + +def pytest_collection(session): + """ perform the collection protocol for the given session. """ +pytest_collection.firstresult = True + +def pytest_collection_modifyitems(session, config, items): + """ called after collection has been performed, may filter or re-order + the items in-place.""" + +def pytest_collection_finish(session): + """ called after collection has been performed and modified. """ + +def pytest_ignore_collect(path, config): + """ return True to prevent considering this path for collection. + This hook is consulted for all files and directories prior to calling + more specific hooks. + """ +pytest_ignore_collect.firstresult = True + +def pytest_collect_directory(path, parent): + """ called before traversing a directory for collection files. """ +pytest_collect_directory.firstresult = True + +def pytest_collect_file(path, parent): + """ return collection Node or None for the given path. Any new node + needs to have the specified ``parent`` as a parent.""" + +# logging hooks for collection +def pytest_collectstart(collector): + """ collector starts collecting. """ + +def pytest_itemcollected(item): + """ we just collected a test item. """ + +def pytest_collectreport(report): + """ collector finished collecting. """ + +def pytest_deselected(items): + """ called for test items deselected by keyword. """ + +def pytest_make_collect_report(collector): + """ perform ``collector.collect()`` and return a CollectReport. """ +pytest_make_collect_report.firstresult = True + +# ------------------------------------------------------------------------- +# Python test function related hooks +# ------------------------------------------------------------------------- + +def pytest_pycollect_makemodule(path, parent): + """ return a Module collector or None for the given path. + This hook will be called for each matching test module path. + The pytest_collect_file hook needs to be used if you want to + create test modules for files that do not match as a test module. + """ +pytest_pycollect_makemodule.firstresult = True + +def pytest_pycollect_makeitem(collector, name, obj): + """ return custom item/collector for a python object in a module, or None. """ +pytest_pycollect_makeitem.firstresult = True + +def pytest_pyfunc_call(pyfuncitem): + """ call underlying test function. """ +pytest_pyfunc_call.firstresult = True + +def pytest_generate_tests(metafunc): + """ generate (multiple) parametrized calls to a test function.""" + +# ------------------------------------------------------------------------- +# generic runtest related hooks +# ------------------------------------------------------------------------- +def pytest_itemstart(item, node=None): + """ (deprecated, use pytest_runtest_logstart). """ + +def pytest_runtest_protocol(item): + """ implements the standard runtest_setup/call/teardown protocol including + capturing exceptions and calling reporting hooks on the results accordingly. + + :return boolean: True if no further hook implementations should be invoked. + """ +pytest_runtest_protocol.firstresult = True + +def pytest_runtest_logstart(nodeid, location): + """ signal the start of a test run. """ + +def pytest_runtest_setup(item): + """ called before ``pytest_runtest_call(item)``. """ + +def pytest_runtest_call(item): + """ called to execute the test ``item``. """ + +def pytest_runtest_teardown(item): + """ called after ``pytest_runtest_call``. """ + +def pytest_runtest_makereport(item, call): + """ return a :py:class:`_pytest.runner.TestReport` object + for the given :py:class:`pytest.Item` and + :py:class:`_pytest.runner.CallInfo`. + """ +pytest_runtest_makereport.firstresult = True + +def pytest_runtest_logreport(report): + """ process item test report. """ + +# special handling for final teardown - somewhat internal for now +def pytest__teardown_final(session): + """ called before test session finishes. """ +pytest__teardown_final.firstresult = True + +def pytest__teardown_final_logerror(report, session): + """ called if runtest_teardown_final failed. """ + +# ------------------------------------------------------------------------- +# test session related hooks +# ------------------------------------------------------------------------- + +def pytest_sessionstart(session): + """ before session.main() is called. """ + +def pytest_sessionfinish(session, exitstatus): + """ whole test run finishes. """ + + +# ------------------------------------------------------------------------- +# hooks for customising the assert methods +# ------------------------------------------------------------------------- + +def pytest_assertrepr_compare(config, op, left, right): + """return explanation for comparisons in failing assert expressions. + + Return None for no custom explanation, otherwise return a list + of strings. The strings will be joined by newlines but any newlines + *in* a string will be escaped. Note that all but the first line will + be indented sligthly, the intention is for the first line to be a summary. + """ + +# ------------------------------------------------------------------------- +# hooks for influencing reporting (invoked from _pytest_terminal) +# ------------------------------------------------------------------------- + +def pytest_report_header(config): + """ return a string to be displayed as header info for terminal reporting.""" + +def pytest_report_teststatus(report): + """ return result-category, shortletter and verbose word for reporting.""" +pytest_report_teststatus.firstresult = True + +def pytest_terminal_summary(terminalreporter): + """ add additional section in terminal summary reporting. """ + +# ------------------------------------------------------------------------- +# doctest hooks +# ------------------------------------------------------------------------- + +def pytest_doctest_prepare_content(content): + """ return processed content for a given doctest""" +pytest_doctest_prepare_content.firstresult = True + +# ------------------------------------------------------------------------- +# error handling and internal debugging hooks +# ------------------------------------------------------------------------- + +def pytest_plugin_registered(plugin, manager): + """ a new py lib plugin got registered. """ + +def pytest_plugin_unregistered(plugin): + """ a py lib plugin got unregistered. """ + +def pytest_internalerror(excrepr): + """ called for internal errors. """ + +def pytest_keyboard_interrupt(excinfo): + """ called for keyboard interrupt. """ diff --git a/lib/pypy/_pytest/junitxml.py b/lib/pypy/_pytest/junitxml.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/junitxml.py @@ -0,0 +1,221 @@ +""" report test results in JUnit-XML format, for use with Hudson and build integration servers. + +Based on initial code from Ross Lawley. +""" + +import py +import os +import re +import sys +import time + + +# Python 2.X and 3.X compatibility +try: + unichr(65) +except NameError: + unichr = chr +try: + unicode('A') +except NameError: + unicode = str +try: + long(1) +except NameError: + long = int + + +# We need to get the subset of the invalid unicode ranges according to +# XML 1.0 which are valid in this python build. Hence we calculate +# this dynamically instead of hardcoding it. The spec range of valid +# chars is: Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] +# | [#x10000-#x10FFFF] +_illegal_unichrs = [(0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x19), + (0xD800, 0xDFFF), (0xFDD0, 0xFFFF)] +_illegal_ranges = [unicode("%s-%s") % (unichr(low), unichr(high)) + for (low, high) in _illegal_unichrs + if low < sys.maxunicode] +illegal_xml_re = re.compile(unicode('[%s]') % + unicode('').join(_illegal_ranges)) +del _illegal_unichrs +del _illegal_ranges + + +def pytest_addoption(parser): + group = parser.getgroup("terminal reporting") + group.addoption('--junitxml', action="store", dest="xmlpath", + metavar="path", default=None, + help="create junit-xml style report file at given path.") + group.addoption('--junitprefix', action="store", dest="junitprefix", + metavar="str", default=None, + help="prepend prefix to classnames in junit-xml output") + +def pytest_configure(config): + xmlpath = config.option.xmlpath + if xmlpath: + config._xml = LogXML(xmlpath, config.option.junitprefix) + config.pluginmanager.register(config._xml) + +def pytest_unconfigure(config): + xml = getattr(config, '_xml', None) + if xml: + del config._xml + config.pluginmanager.unregister(xml) + + +class LogXML(object): + def __init__(self, logfile, prefix): + logfile = os.path.expanduser(os.path.expandvars(logfile)) + self.logfile = os.path.normpath(logfile) + self.prefix = prefix + self.test_logs = [] + self.passed = self.skipped = 0 + self.failed = self.errors = 0 + self._durations = {} + + def _opentestcase(self, report): + names = report.nodeid.split("::") + names[0] = names[0].replace("/", '.') + names = tuple(names) + d = {'time': self._durations.pop(report.nodeid, "0")} + names = [x.replace(".py", "") for x in names if x != "()"] + classnames = names[:-1] + if self.prefix: + classnames.insert(0, self.prefix) + d['classname'] = ".".join(classnames) + d['name'] = py.xml.escape(names[-1]) + attrs = ['%s="%s"' % item for item in sorted(d.items())] + self.test_logs.append("\n" % " ".join(attrs)) + + def _closetestcase(self): + self.test_logs.append("") + + def appendlog(self, fmt, *args): + def repl(matchobj): + i = ord(matchobj.group()) + if i <= 0xFF: + return unicode('#x%02X') % i + else: + return unicode('#x%04X') % i + args = tuple([illegal_xml_re.sub(repl, py.xml.escape(arg)) + for arg in args]) + self.test_logs.append(fmt % args) + + def append_pass(self, report): + self.passed += 1 + self._opentestcase(report) + self._closetestcase() + + def append_failure(self, report): + self._opentestcase(report) + #msg = str(report.longrepr.reprtraceback.extraline) + if "xfail" in report.keywords: + self.appendlog( + '') + self.skipped += 1 + else: + self.appendlog('%s', + report.longrepr) + self.failed += 1 + self._closetestcase() + + def append_collect_failure(self, report): + self._opentestcase(report) + #msg = str(report.longrepr.reprtraceback.extraline) + self.appendlog('%s', + report.longrepr) + self._closetestcase() + self.errors += 1 + + def append_collect_skipped(self, report): + self._opentestcase(report) + #msg = str(report.longrepr.reprtraceback.extraline) + self.appendlog('%s', + report.longrepr) + self._closetestcase() + self.skipped += 1 + + def append_error(self, report): + self._opentestcase(report) + self.appendlog('%s', + report.longrepr) + self._closetestcase() + self.errors += 1 + + def append_skipped(self, report): + self._opentestcase(report) + if "xfail" in report.keywords: + self.appendlog( + '%s', + report.keywords['xfail']) + else: + filename, lineno, skipreason = report.longrepr + if skipreason.startswith("Skipped: "): + skipreason = skipreason[9:] + self.appendlog('%s', + skipreason, "%s:%s: %s" % report.longrepr, + ) + self._closetestcase() + self.skipped += 1 + + def pytest_runtest_logreport(self, report): + if report.passed: + self.append_pass(report) + elif report.failed: + if report.when != "call": + self.append_error(report) + else: + self.append_failure(report) + elif report.skipped: + self.append_skipped(report) + + def pytest_runtest_call(self, item, __multicall__): + start = time.time() + try: + return __multicall__.execute() + finally: + self._durations[item.nodeid] = time.time() - start + + def pytest_collectreport(self, report): + if not report.passed: + if report.failed: + self.append_collect_failure(report) + else: + self.append_collect_skipped(report) + + def pytest_internalerror(self, excrepr): + self.errors += 1 + data = py.xml.escape(excrepr) + self.test_logs.append( + '\n' + ' ' + '%s' % data) + + def pytest_sessionstart(self, session): + self.suite_start_time = time.time() + + def pytest_sessionfinish(self, session, exitstatus, __multicall__): + if py.std.sys.version_info[0] < 3: + logfile = py.std.codecs.open(self.logfile, 'w', encoding='utf-8') + else: + logfile = open(self.logfile, 'w', encoding='utf-8') + + suite_stop_time = time.time() + suite_time_delta = suite_stop_time - self.suite_start_time + numtests = self.passed + self.failed + logfile.write('') + logfile.write('') + logfile.writelines(self.test_logs) + logfile.write('') + logfile.close() + + def pytest_terminal_summary(self, terminalreporter): + terminalreporter.write_sep("-", "generated xml file: %s" % (self.logfile)) diff --git a/lib/pypy/_pytest/main.py b/lib/pypy/_pytest/main.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/main.py @@ -0,0 +1,552 @@ +""" core implementation of testing process: init, session, runtest loop. """ + +import py +import pytest, _pytest +import os, sys +tracebackcutdir = py.path.local(_pytest.__file__).dirpath() + +# exitcodes for the command line +EXIT_OK = 0 +EXIT_TESTSFAILED = 1 +EXIT_INTERRUPTED = 2 +EXIT_INTERNALERROR = 3 + +def pytest_addoption(parser): + parser.addini("norecursedirs", "directory patterns to avoid for recursion", + type="args", default=('.*', 'CVS', '_darcs', '{arch}')) + #parser.addini("dirpatterns", + # "patterns specifying possible locations of test files", + # type="linelist", default=["**/test_*.txt", + # "**/test_*.py", "**/*_test.py"] + #) + group = parser.getgroup("general", "running and selection options") + group._addoption('-x', '--exitfirst', action="store_true", default=False, + dest="exitfirst", + help="exit instantly on first error or failed test."), + group._addoption('--maxfail', metavar="num", + action="store", type="int", dest="maxfail", default=0, + help="exit after first num failures or errors.") + + group = parser.getgroup("collect", "collection") + group.addoption('--collectonly', + action="store_true", dest="collectonly", + help="only collect tests, don't execute them."), + group.addoption('--pyargs', action="store_true", + help="try to interpret all arguments as python packages.") + group.addoption("--ignore", action="append", metavar="path", + help="ignore path during collection (multi-allowed).") + group.addoption('--confcutdir', dest="confcutdir", default=None, + metavar="dir", + help="only load conftest.py's relative to specified dir.") + + group = parser.getgroup("debugconfig", + "test session debugging and configuration") + group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir", + help="base temporary directory for this test run.") + + +def pytest_namespace(): + collect = dict(Item=Item, Collector=Collector, File=File, Session=Session) + return dict(collect=collect) + +def pytest_configure(config): + py.test.config = config # compatibiltiy + if config.option.exitfirst: + config.option.maxfail = 1 + +def wrap_session(config, doit): + """Skeleton command line program""" + session = Session(config) + session.exitstatus = EXIT_OK + initstate = 0 + try: + config.pluginmanager.do_configure(config) + initstate = 1 + config.hook.pytest_sessionstart(session=session) + initstate = 2 + doit(config, session) + except pytest.UsageError: + raise + except KeyboardInterrupt: + excinfo = py.code.ExceptionInfo() + config.hook.pytest_keyboard_interrupt(excinfo=excinfo) + session.exitstatus = EXIT_INTERRUPTED + except: + excinfo = py.code.ExceptionInfo() + config.pluginmanager.notify_exception(excinfo, config.option) + session.exitstatus = EXIT_INTERNALERROR + if excinfo.errisinstance(SystemExit): + sys.stderr.write("mainloop: caught Spurious SystemExit!\n") + if not session.exitstatus and session._testsfailed: + session.exitstatus = EXIT_TESTSFAILED + if initstate >= 2: + config.hook.pytest_sessionfinish(session=session, + exitstatus=session.exitstatus) + if initstate >= 1: + config.pluginmanager.do_unconfigure(config) + return session.exitstatus + +def pytest_cmdline_main(config): + return wrap_session(config, _main) + +def _main(config, session): + """ default command line protocol for initialization, session, + running tests and reporting. """ + config.hook.pytest_collection(session=session) + config.hook.pytest_runtestloop(session=session) + +def pytest_collection(session): + return session.perform_collect() + +def pytest_runtestloop(session): + if session.config.option.collectonly: + return True + for item in session.session.items: + item.config.hook.pytest_runtest_protocol(item=item) + if session.shouldstop: + raise session.Interrupted(session.shouldstop) + return True + +def pytest_ignore_collect(path, config): + p = path.dirpath() + ignore_paths = config._getconftest_pathlist("collect_ignore", path=p) + ignore_paths = ignore_paths or [] + excludeopt = config.getvalue("ignore") + if excludeopt: + ignore_paths.extend([py.path.local(x) for x in excludeopt]) + return path in ignore_paths + +class HookProxy: + def __init__(self, fspath, config): + self.fspath = fspath + self.config = config + def __getattr__(self, name): + hookmethod = getattr(self.config.hook, name) + def call_matching_hooks(**kwargs): + plugins = self.config._getmatchingplugins(self.fspath) + return hookmethod.pcall(plugins, **kwargs) + return call_matching_hooks + +def compatproperty(name): + def fget(self): + return getattr(pytest, name) + return property(fget, None, None, + "deprecated attribute %r, use pytest.%s" % (name,name)) + +class Node(object): + """ base class for all Nodes in the collection tree. + Collector subclasses have children, Items are terminal nodes.""" + + def __init__(self, name, parent=None, config=None, session=None): + #: a unique name with the scope of the parent + self.name = name + + #: the parent collector node. + self.parent = parent + + #: the test config object + self.config = config or parent.config + + #: the collection this node is part of + self.session = session or parent.session + + #: filesystem path where this node was collected from + self.fspath = getattr(parent, 'fspath', None) + self.ihook = self.session.gethookproxy(self.fspath) + self.keywords = {self.name: True} + + Module = compatproperty("Module") + Class = compatproperty("Class") + Instance = compatproperty("Instance") + Function = compatproperty("Function") + File = compatproperty("File") + Item = compatproperty("Item") + + def _getcustomclass(self, name): + cls = getattr(self, name) + if cls != getattr(pytest, name): + py.log._apiwarn("2.0", "use of node.%s is deprecated, " + "use pytest_pycollect_makeitem(...) to create custom " + "collection nodes" % name) + return cls + + def __repr__(self): + return "<%s %r>" %(self.__class__.__name__, getattr(self, 'name', None)) + + # methods for ordering nodes + @property + def nodeid(self): + try: + return self._nodeid + except AttributeError: + self._nodeid = x = self._makeid() + return x + + def _makeid(self): + return self.parent.nodeid + "::" + self.name + + def __eq__(self, other): + if not isinstance(other, Node): + return False + return self.__class__ == other.__class__ and \ + self.name == other.name and self.parent == other.parent + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.name, self.parent)) + + def setup(self): + pass + + def teardown(self): + pass + + def _memoizedcall(self, attrname, function): + exattrname = "_ex_" + attrname + failure = getattr(self, exattrname, None) + if failure is not None: + py.builtin._reraise(failure[0], failure[1], failure[2]) + if hasattr(self, attrname): + return getattr(self, attrname) + try: + res = function() + except py.builtin._sysex: + raise + except: + failure = py.std.sys.exc_info() + setattr(self, exattrname, failure) + raise + setattr(self, attrname, res) + return res + + def listchain(self): + """ return list of all parent collectors up to self, + starting from root of collection tree. """ + l = [self] + while 1: + x = l[0] + if x.parent is not None: # and x.parent.parent is not None: + l.insert(0, x.parent) + else: + return l + + def listnames(self): + return [x.name for x in self.listchain()] + + def getplugins(self): + return self.config._getmatchingplugins(self.fspath) + + def getparent(self, cls): + current = self + while current and not isinstance(current, cls): + current = current.parent + return current + + def _prunetraceback(self, excinfo): + pass + + def _repr_failure_py(self, excinfo, style=None): + if self.config.option.fulltrace: + style="long" + else: + self._prunetraceback(excinfo) + # XXX should excinfo.getrepr record all data and toterminal() + # process it? + if style is None: + if self.config.option.tbstyle == "short": + style = "short" + else: + style = "long" + return excinfo.getrepr(funcargs=True, + showlocals=self.config.option.showlocals, + style=style) + + repr_failure = _repr_failure_py + +class Collector(Node): + """ Collector instances create children through collect() + and thus iteratively build a tree. + """ + class CollectError(Exception): + """ an error during collection, contains a custom message. """ + + def collect(self): + """ returns a list of children (items and collectors) + for this collection node. + """ + raise NotImplementedError("abstract") + + def repr_failure(self, excinfo): + """ represent a collection failure. """ + if excinfo.errisinstance(self.CollectError): + exc = excinfo.value + return str(exc.args[0]) + return self._repr_failure_py(excinfo, style="short") + + def _memocollect(self): + """ internal helper method to cache results of calling collect(). """ + return self._memoizedcall('_collected', lambda: list(self.collect())) + + def _prunetraceback(self, excinfo): + if hasattr(self, 'fspath'): + path = self.fspath + traceback = excinfo.traceback + ntraceback = traceback.cut(path=self.fspath) + if ntraceback == traceback: + ntraceback = ntraceback.cut(excludepath=tracebackcutdir) + excinfo.traceback = ntraceback.filter() + +class FSCollector(Collector): + def __init__(self, fspath, parent=None, config=None, session=None): + fspath = py.path.local(fspath) # xxx only for test_resultlog.py? + name = fspath.basename + if parent is not None: + rel = fspath.relto(parent.fspath) + if rel: + name = rel + name = name.replace(os.sep, "/") + super(FSCollector, self).__init__(name, parent, config, session) + self.fspath = fspath + + def _makeid(self): + if self == self.session: + return "." + relpath = self.session.fspath.bestrelpath(self.fspath) + if os.sep != "/": + relpath = relpath.replace(os.sep, "/") + return relpath + +class File(FSCollector): + """ base class for collecting tests from a file. """ + +class Item(Node): + """ a basic test invocation item. Note that for a single function + there might be multiple test invocation items. + """ + def reportinfo(self): + return self.fspath, None, "" + + @property + def location(self): + try: + return self._location + except AttributeError: + location = self.reportinfo() + # bestrelpath is a quite slow function + cache = self.config.__dict__.setdefault("_bestrelpathcache", {}) + try: + fspath = cache[location[0]] + except KeyError: + fspath = self.session.fspath.bestrelpath(location[0]) + cache[location[0]] = fspath + location = (fspath, location[1], str(location[2])) + self._location = location + return location + +class NoMatch(Exception): + """ raised if matching cannot locate a matching names. """ + +class Session(FSCollector): + class Interrupted(KeyboardInterrupt): + """ signals an interrupted test run. """ + __module__ = 'builtins' # for py3 + + def __init__(self, config): + super(Session, self).__init__(py.path.local(), parent=None, + config=config, session=self) + assert self.config.pluginmanager.register(self, name="session", prepend=True) + self._testsfailed = 0 + self.shouldstop = False + self.trace = config.trace.root.get("collection") + self._norecursepatterns = config.getini("norecursedirs") + + def pytest_collectstart(self): + if self.shouldstop: + raise self.Interrupted(self.shouldstop) + + def pytest_runtest_logreport(self, report): + if report.failed and 'xfail' not in getattr(report, 'keywords', []): + self._testsfailed += 1 + maxfail = self.config.getvalue("maxfail") + if maxfail and self._testsfailed >= maxfail: + self.shouldstop = "stopping after %d failures" % ( + self._testsfailed) + pytest_collectreport = pytest_runtest_logreport + + def isinitpath(self, path): + return path in self._initialpaths + + def gethookproxy(self, fspath): + return HookProxy(fspath, self.config) + + def perform_collect(self, args=None, genitems=True): + hook = self.config.hook + try: + items = self._perform_collect(args, genitems) + hook.pytest_collection_modifyitems(session=self, + config=self.config, items=items) + finally: + hook.pytest_collection_finish(session=self) + return items + + def _perform_collect(self, args, genitems): + if args is None: + args = self.config.args + self.trace("perform_collect", self, args) + self.trace.root.indent += 1 + self._notfound = [] + self._initialpaths = set() + self._initialparts = [] + for arg in args: + parts = self._parsearg(arg) + self._initialparts.append(parts) + self._initialpaths.add(parts[0]) + self.ihook.pytest_collectstart(collector=self) + rep = self.ihook.pytest_make_collect_report(collector=self) + self.ihook.pytest_collectreport(report=rep) + self.trace.root.indent -= 1 + if self._notfound: + for arg, exc in self._notfound: + line = "(no name %r in any of %r)" % (arg, exc.args[0]) + raise pytest.UsageError("not found: %s\n%s" %(arg, line)) + if not genitems: + return rep.result + else: + self.items = items = [] + if rep.passed: + for node in rep.result: + self.items.extend(self.genitems(node)) + return items + + def collect(self): + for parts in self._initialparts: + arg = "::".join(map(str, parts)) + self.trace("processing argument", arg) + self.trace.root.indent += 1 + try: + for x in self._collect(arg): + yield x + except NoMatch: + # we are inside a make_report hook so + # we cannot directly pass through the exception + self._notfound.append((arg, sys.exc_info()[1])) + self.trace.root.indent -= 1 + break + self.trace.root.indent -= 1 + + def _collect(self, arg): + names = self._parsearg(arg) + path = names.pop(0) + if path.check(dir=1): + assert not names, "invalid arg %r" %(arg,) + for path in path.visit(fil=lambda x: x.check(file=1), + rec=self._recurse, bf=True, sort=True): + for x in self._collectfile(path): + yield x + else: + assert path.check(file=1) + for x in self.matchnodes(self._collectfile(path), names): + yield x + + def _collectfile(self, path): + ihook = self.gethookproxy(path) + if not self.isinitpath(path): + if ihook.pytest_ignore_collect(path=path, config=self.config): + return () + return ihook.pytest_collect_file(path=path, parent=self) + + def _recurse(self, path): + ihook = self.gethookproxy(path.dirpath()) + if ihook.pytest_ignore_collect(path=path, config=self.config): + return + for pat in self._norecursepatterns: + if path.check(fnmatch=pat): + return False + ihook = self.gethookproxy(path) + ihook.pytest_collect_directory(path=path, parent=self) + return True + + def _tryconvertpyarg(self, x): + try: + mod = __import__(x, None, None, ['__doc__']) + except (ValueError, ImportError): + return x + p = py.path.local(mod.__file__) + if p.purebasename == "__init__": + p = p.dirpath() + else: + p = p.new(basename=p.purebasename+".py") + return str(p) + + def _parsearg(self, arg): + """ return (fspath, names) tuple after checking the file exists. """ + arg = str(arg) + if self.config.option.pyargs: + arg = self._tryconvertpyarg(arg) + parts = str(arg).split("::") + relpath = parts[0].replace("/", os.sep) + path = self.fspath.join(relpath, abs=True) + if not path.check(): + if self.config.option.pyargs: + msg = "file or package not found: " + else: + msg = "file not found: " + raise pytest.UsageError(msg + arg) + parts[0] = path + return parts + + def matchnodes(self, matching, names): + self.trace("matchnodes", matching, names) + self.trace.root.indent += 1 + nodes = self._matchnodes(matching, names) + num = len(nodes) + self.trace("matchnodes finished -> ", num, "nodes") + self.trace.root.indent -= 1 + if num == 0: + raise NoMatch(matching, names[:1]) + return nodes + + def _matchnodes(self, matching, names): + if not matching or not names: + return matching + name = names[0] + assert name + nextnames = names[1:] + resultnodes = [] + for node in matching: + if isinstance(node, pytest.Item): + if not names: + resultnodes.append(node) + continue + assert isinstance(node, pytest.Collector) + node.ihook.pytest_collectstart(collector=node) + rep = node.ihook.pytest_make_collect_report(collector=node) + if rep.passed: + has_matched = False + for x in rep.result: + if x.name == name: + resultnodes.extend(self.matchnodes([x], nextnames)) + has_matched = True + # XXX accept IDs that don't have "()" for class instances + if not has_matched and len(rep.result) == 1 and x.name == "()": + nextnames.insert(0, name) + resultnodes.extend(self.matchnodes([x], nextnames)) + node.ihook.pytest_collectreport(report=rep) + return resultnodes + + def genitems(self, node): + self.trace("genitems", node) + if isinstance(node, pytest.Item): + node.ihook.pytest_itemcollected(item=node) + yield node + else: + assert isinstance(node, pytest.Collector) + node.ihook.pytest_collectstart(collector=node) + rep = node.ihook.pytest_make_collect_report(collector=node) + if rep.passed: + for subnode in rep.result: + for x in self.genitems(subnode): + yield x + node.ihook.pytest_collectreport(report=rep) diff --git a/lib/pypy/_pytest/mark.py b/lib/pypy/_pytest/mark.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/mark.py @@ -0,0 +1,176 @@ +""" generic mechanism for marking and selecting python functions. """ +import pytest, py + +def pytest_namespace(): + return {'mark': MarkGenerator()} + +def pytest_addoption(parser): + group = parser.getgroup("general") + group._addoption('-k', + action="store", dest="keyword", default='', metavar="KEYWORDEXPR", + help="only run tests which match given keyword expression. " + "An expression consists of space-separated terms. " + "Each term must match. Precede a term with '-' to negate. " + "Terminate expression with ':' to make the first match match " + "all subsequent tests (usually file-order). ") + +def pytest_collection_modifyitems(items, config): + keywordexpr = config.option.keyword + if not keywordexpr: + return + selectuntil = False + if keywordexpr[-1] == ":": + selectuntil = True + keywordexpr = keywordexpr[:-1] + + remaining = [] + deselected = [] + for colitem in items: + if keywordexpr and skipbykeyword(colitem, keywordexpr): + deselected.append(colitem) + else: + remaining.append(colitem) + if selectuntil: + keywordexpr = None + + if deselected: + config.hook.pytest_deselected(items=deselected) + items[:] = remaining + +def skipbykeyword(colitem, keywordexpr): + """ return True if they given keyword expression means to + skip this collector/item. + """ + if not keywordexpr: + return + + itemkeywords = getkeywords(colitem) + for key in filter(None, keywordexpr.split()): + eor = key[:1] == '-' + if eor: + key = key[1:] + if not (eor ^ matchonekeyword(key, itemkeywords)): + return True + +def getkeywords(node): + keywords = {} + while node is not None: + keywords.update(node.keywords) + node = node.parent + return keywords + + +def matchonekeyword(key, itemkeywords): + for elem in key.split("."): + for kw in itemkeywords: + if elem in kw: + break + else: + return False + return True + +class MarkGenerator: + """ Factory for :class:`MarkDecorator` objects - exposed as + a ``py.test.mark`` singleton instance. Example:: + + import py + @py.test.mark.slowtest + def test_function(): + pass + + will set a 'slowtest' :class:`MarkInfo` object + on the ``test_function`` object. """ + + def __getattr__(self, name): + if name[0] == "_": + raise AttributeError(name) + return MarkDecorator(name) + +class MarkDecorator: + """ A decorator for test functions and test classes. When applied + it will create :class:`MarkInfo` objects which may be + :ref:`retrieved by hooks as item keywords `. + MarkDecorator instances are often created like this:: + + mark1 = py.test.mark.NAME # simple MarkDecorator + mark2 = py.test.mark.NAME(name1=value) # parametrized MarkDecorator + + and can then be applied as decorators to test functions:: + + @mark2 + def test_function(): + pass + """ + def __init__(self, name, args=None, kwargs=None): + self.markname = name + self.args = args or () + self.kwargs = kwargs or {} + + def __repr__(self): + d = self.__dict__.copy() + name = d.pop('markname') + return "" %(name, d) + + def __call__(self, *args, **kwargs): + """ if passed a single callable argument: decorate it with mark info. + otherwise add *args/**kwargs in-place to mark information. """ + if args: + func = args[0] + if len(args) == 1 and hasattr(func, '__call__') or \ + hasattr(func, '__bases__'): + if hasattr(func, '__bases__'): + if hasattr(func, 'pytestmark'): + l = func.pytestmark + if not isinstance(l, list): + func.pytestmark = [l, self] + else: + l.append(self) + else: + func.pytestmark = [self] + else: + holder = getattr(func, self.markname, None) + if holder is None: + holder = MarkInfo(self.markname, self.args, self.kwargs) + setattr(func, self.markname, holder) + else: + holder.kwargs.update(self.kwargs) + holder.args += self.args + return func + kw = self.kwargs.copy() + kw.update(kwargs) + args = self.args + args + return self.__class__(self.markname, args=args, kwargs=kw) + +class MarkInfo: + """ Marking object created by :class:`MarkDecorator` instances. """ + def __init__(self, name, args, kwargs): + #: name of attribute + self.name = name + #: positional argument list, empty if none specified + self.args = args + #: keyword argument dictionary, empty if nothing specified + self.kwargs = kwargs + + def __repr__(self): + return "" % ( + self.name, self.args, self.kwargs) + +def pytest_itemcollected(item): + if not isinstance(item, pytest.Function): + return + try: + func = item.obj.__func__ + except AttributeError: + func = getattr(item.obj, 'im_func', item.obj) + pyclasses = (pytest.Class, pytest.Module) + for node in item.listchain(): + if isinstance(node, pyclasses): + marker = getattr(node.obj, 'pytestmark', None) + if marker is not None: + if isinstance(marker, list): + for mark in marker: + mark(func) + else: + marker(func) + node = node.parent + item.keywords.update(py.builtin._getfuncdict(func)) diff --git a/lib/pypy/_pytest/monkeypatch.py b/lib/pypy/_pytest/monkeypatch.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/monkeypatch.py @@ -0,0 +1,103 @@ +""" monkeypatching and mocking functionality. """ + +import os, sys + +def pytest_funcarg__monkeypatch(request): + """The returned ``monkeypatch`` funcarg provides these + helper methods to modify objects, dictionaries or os.environ:: + + monkeypatch.setattr(obj, name, value, raising=True) + monkeypatch.delattr(obj, name, raising=True) + monkeypatch.setitem(mapping, name, value) + monkeypatch.delitem(obj, name, raising=True) + monkeypatch.setenv(name, value, prepend=False) + monkeypatch.delenv(name, value, raising=True) + monkeypatch.syspath_prepend(path) + + All modifications will be undone after the requesting + test function has finished. The ``raising`` + parameter determines if a KeyError or AttributeError + will be raised if the set/deletion operation has no target. + """ + mpatch = monkeypatch() + request.addfinalizer(mpatch.undo) + return mpatch + +notset = object() + +class monkeypatch: + """ object keeping a record of setattr/item/env/syspath changes. """ + def __init__(self): + self._setattr = [] + self._setitem = [] + + def setattr(self, obj, name, value, raising=True): + """ set attribute ``name`` on ``obj`` to ``value``, by default + raise AttributeEror if the attribute did not exist. """ + oldval = getattr(obj, name, notset) + if raising and oldval is notset: + raise AttributeError("%r has no attribute %r" %(obj, name)) + self._setattr.insert(0, (obj, name, oldval)) + setattr(obj, name, value) + + def delattr(self, obj, name, raising=True): + """ delete attribute ``name`` from ``obj``, by default raise + AttributeError it the attribute did not previously exist. """ + if not hasattr(obj, name): + if raising: + raise AttributeError(name) + else: + self._setattr.insert(0, (obj, name, getattr(obj, name, notset))) + delattr(obj, name) + + def setitem(self, dic, name, value): + """ set dictionary entry ``name`` to value. """ + self._setitem.insert(0, (dic, name, dic.get(name, notset))) + dic[name] = value + + def delitem(self, dic, name, raising=True): + """ delete ``name`` from dict, raise KeyError if it doesn't exist.""" + if name not in dic: + if raising: + raise KeyError(name) + else: + self._setitem.insert(0, (dic, name, dic.get(name, notset))) + del dic[name] + + def setenv(self, name, value, prepend=None): + """ set environment variable ``name`` to ``value``. if ``prepend`` + is a character, read the current environment variable value + and prepend the ``value`` adjoined with the ``prepend`` character.""" + value = str(value) + if prepend and name in os.environ: + value = value + prepend + os.environ[name] + self.setitem(os.environ, name, value) + + def delenv(self, name, raising=True): + """ delete ``name`` from environment, raise KeyError it not exists.""" + self.delitem(os.environ, name, raising=raising) + + def syspath_prepend(self, path): + """ prepend ``path`` to ``sys.path`` list of import locations. """ + if not hasattr(self, '_savesyspath'): + self._savesyspath = sys.path[:] + sys.path.insert(0, str(path)) + + def undo(self): + """ undo previous changes. This call consumes the + undo stack. Calling it a second time has no effect unless + you do more monkeypatching after the undo call.""" + for obj, name, value in self._setattr: + if value is not notset: + setattr(obj, name, value) + else: + delattr(obj, name) + self._setattr[:] = [] + for dictionary, name, value in self._setitem: + if value is notset: + del dictionary[name] + else: + dictionary[name] = value + self._setitem[:] = [] + if hasattr(self, '_savesyspath'): + sys.path[:] = self._savesyspath diff --git a/lib/pypy/_pytest/nose.py b/lib/pypy/_pytest/nose.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/nose.py @@ -0,0 +1,47 @@ +""" run test suites written for nose. """ + +import pytest, py +import inspect +import sys + +def pytest_runtest_makereport(__multicall__, item, call): + SkipTest = getattr(sys.modules.get('nose', None), 'SkipTest', None) + if SkipTest: + if call.excinfo and call.excinfo.errisinstance(SkipTest): + # let's substitute the excinfo with a py.test.skip one + call2 = call.__class__(lambda: py.test.skip(str(call.excinfo.value)), call.when) + call.excinfo = call2.excinfo + + +def pytest_runtest_setup(item): + if isinstance(item, (pytest.Function)): + if isinstance(item.parent, pytest.Generator): + gen = item.parent + if not hasattr(gen, '_nosegensetup'): + call_optional(gen.obj, 'setup') + if isinstance(gen.parent, pytest.Instance): + call_optional(gen.parent.obj, 'setup') + gen._nosegensetup = True + if not call_optional(item.obj, 'setup'): + # call module level setup if there is no object level one + call_optional(item.parent.obj, 'setup') + +def pytest_runtest_teardown(item): + if isinstance(item, pytest.Function): + if not call_optional(item.obj, 'teardown'): + call_optional(item.parent.obj, 'teardown') + #if hasattr(item.parent, '_nosegensetup'): + # #call_optional(item._nosegensetup, 'teardown') + # del item.parent._nosegensetup + +def pytest_make_collect_report(collector): + if isinstance(collector, pytest.Generator): + call_optional(collector.obj, 'setup') + +def call_optional(obj, name): + method = getattr(obj, name, None) + if method: + # If there's any problems allow the exception to raise rather than + # silently ignoring them + method() + return True diff --git a/lib/pypy/_pytest/pastebin.py b/lib/pypy/_pytest/pastebin.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/pastebin.py @@ -0,0 +1,63 @@ +""" submit failure or test session information to a pastebin service. """ +import py, sys + +class url: + base = "http://paste.pocoo.org" + xmlrpc = base + "/xmlrpc/" + show = base + "/show/" + +def pytest_addoption(parser): + group = parser.getgroup("terminal reporting") + group._addoption('--pastebin', metavar="mode", + action='store', dest="pastebin", default=None, + type="choice", choices=['failed', 'all'], + help="send failed|all info to Pocoo pastebin service.") + +def pytest_configure(__multicall__, config): + import tempfile + __multicall__.execute() + if config.option.pastebin == "all": + config._pastebinfile = tempfile.TemporaryFile('w+') + tr = config.pluginmanager.getplugin('terminalreporter') + oldwrite = tr._tw.write + def tee_write(s, **kwargs): + oldwrite(s, **kwargs) + config._pastebinfile.write(str(s)) + tr._tw.write = tee_write + +def pytest_unconfigure(config): + if hasattr(config, '_pastebinfile'): + config._pastebinfile.seek(0) + sessionlog = config._pastebinfile.read() + config._pastebinfile.close() + del config._pastebinfile + proxyid = getproxy().newPaste("python", sessionlog) + pastebinurl = "%s%s" % (url.show, proxyid) + sys.stderr.write("pastebin session-log: %s\n" % pastebinurl) + tr = config.pluginmanager.getplugin('terminalreporter') + del tr._tw.__dict__['write'] + +def getproxy(): + return py.std.xmlrpclib.ServerProxy(url.xmlrpc).pastes + +def pytest_terminal_summary(terminalreporter): + if terminalreporter.config.option.pastebin != "failed": + return + tr = terminalreporter + if 'failed' in tr.stats: + terminalreporter.write_sep("=", "Sending information to Paste Service") + if tr.config.option.debug: + terminalreporter.write_line("xmlrpcurl: %s" %(url.xmlrpc,)) + serverproxy = getproxy() + for rep in terminalreporter.stats.get('failed'): + try: + msg = rep.longrepr.reprtraceback.reprentries[-1].reprfileloc + except AttributeError: + msg = tr._getfailureheadline(rep) + tw = py.io.TerminalWriter(stringio=True) + rep.toterminal(tw) + s = tw.stringio.getvalue() + assert len(s) + proxyid = serverproxy.newPaste("python", s) + pastebinurl = "%s%s" % (url.show, proxyid) + tr.write_line("%s --> %s" %(msg, pastebinurl)) diff --git a/lib/pypy/_pytest/pdb.py b/lib/pypy/_pytest/pdb.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/pdb.py @@ -0,0 +1,79 @@ +""" interactive debugging with PDB, the Python Debugger. """ + +import pytest, py +import sys + +def pytest_addoption(parser): + group = parser.getgroup("general") + group._addoption('--pdb', + action="store_true", dest="usepdb", default=False, + help="start the interactive Python debugger on errors.") + +def pytest_namespace(): + return {'set_trace': pytestPDB().set_trace} + +def pytest_configure(config): + if config.getvalue("usepdb"): + config.pluginmanager.register(PdbInvoke(), 'pdbinvoke') + +class pytestPDB: + """ Pseudo PDB that defers to the real pdb. """ + item = None + + def set_trace(self): + """ invoke PDB set_trace debugging, dropping any IO capturing. """ + frame = sys._getframe().f_back + item = getattr(self, 'item', None) + if item is not None: + capman = item.config.pluginmanager.getplugin("capturemanager") + out, err = capman.suspendcapture() + if hasattr(item, 'outerr'): + item.outerr = (item.outerr[0] + out, item.outerr[1] + err) + tw = py.io.TerminalWriter() + tw.line() + tw.sep(">", "PDB set_trace (IO-capturing turned off)") + py.std.pdb.Pdb().set_trace(frame) + +def pdbitem(item): + pytestPDB.item = item +pytest_runtest_setup = pytest_runtest_call = pytest_runtest_teardown = pdbitem + +def pytest_runtest_makereport(): + pytestPDB.item = None + +class PdbInvoke: + @pytest.mark.tryfirst + def pytest_runtest_makereport(self, item, call, __multicall__): + rep = __multicall__.execute() + if not call.excinfo or \ + call.excinfo.errisinstance(pytest.skip.Exception) or \ + call.excinfo.errisinstance(py.std.bdb.BdbQuit): + return rep + if "xfail" in rep.keywords: + return rep + # we assume that the above execute() suspended capturing + # XXX we re-use the TerminalReporter's terminalwriter + # because this seems to avoid some encoding related troubles + # for not completely clear reasons. + tw = item.config.pluginmanager.getplugin("terminalreporter")._tw + tw.line() + tw.sep(">", "traceback") + rep.toterminal(tw) + tw.sep(">", "entering PDB") + post_mortem(call.excinfo._excinfo[2]) + rep._pdbshown = True + return rep + +def post_mortem(t): + pdb = py.std.pdb + class Pdb(pdb.Pdb): + def get_stack(self, f, t): + stack, i = pdb.Pdb.get_stack(self, f, t) + if f is None: + i = max(0, len(stack) - 1) + while i and stack[i][0].f_locals.get("__tracebackhide__", False): + i-=1 + return stack, i + p = Pdb() + p.reset() + p.interaction(None, t) diff --git a/lib/pypy/_pytest/pytester.py b/lib/pypy/_pytest/pytester.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/pytester.py @@ -0,0 +1,685 @@ +""" (disabled by default) support for testing py.test and py.test plugins. """ + +import py, pytest +import sys, os +import re +import inspect +import time +from fnmatch import fnmatch +from _pytest.main import Session, EXIT_OK +from py.builtin import print_ +from _pytest.core import HookRelay + +def pytest_addoption(parser): + group = parser.getgroup("pylib") + group.addoption('--no-tools-on-path', + action="store_true", dest="notoolsonpath", default=False, + help=("discover tools on PATH instead of going through py.cmdline.") + ) + +def pytest_configure(config): + # This might be called multiple times. Only take the first. + global _pytest_fullpath + import pytest + try: + _pytest_fullpath + except NameError: + _pytest_fullpath = os.path.abspath(pytest.__file__.rstrip("oc")) + +def pytest_funcarg___pytest(request): + return PytestArg(request) + +class PytestArg: + def __init__(self, request): + self.request = request + + def gethookrecorder(self, hook): + hookrecorder = HookRecorder(hook._pm) + hookrecorder.start_recording(hook._hookspecs) + self.request.addfinalizer(hookrecorder.finish_recording) + return hookrecorder + +class ParsedCall: + def __init__(self, name, locals): + assert '_name' not in locals + self.__dict__.update(locals) + self.__dict__.pop('self') + self._name = name + + def __repr__(self): + d = self.__dict__.copy() + del d['_name'] + return "" %(self._name, d) + +class HookRecorder: + def __init__(self, pluginmanager): + self._pluginmanager = pluginmanager + self.calls = [] + self._recorders = {} + + def start_recording(self, hookspecs): + if not isinstance(hookspecs, (list, tuple)): + hookspecs = [hookspecs] + for hookspec in hookspecs: + assert hookspec not in self._recorders + class RecordCalls: + _recorder = self + for name, method in vars(hookspec).items(): + if name[0] != "_": + setattr(RecordCalls, name, self._makecallparser(method)) + recorder = RecordCalls() + self._recorders[hookspec] = recorder + self._pluginmanager.register(recorder) + self.hook = HookRelay(hookspecs, pm=self._pluginmanager, + prefix="pytest_") + + def finish_recording(self): + for recorder in self._recorders.values(): + self._pluginmanager.unregister(recorder) + self._recorders.clear() + + def _makecallparser(self, method): + name = method.__name__ + args, varargs, varkw, default = py.std.inspect.getargspec(method) + if not args or args[0] != "self": + args.insert(0, 'self') + fspec = py.std.inspect.formatargspec(args, varargs, varkw, default) + # we use exec because we want to have early type + # errors on wrong input arguments, using + # *args/**kwargs delays this and gives errors + # elsewhere + exec (py.code.compile(""" + def %(name)s%(fspec)s: + self._recorder.calls.append( + ParsedCall(%(name)r, locals())) + """ % locals())) + return locals()[name] + + def getcalls(self, names): + if isinstance(names, str): + names = names.split() + for name in names: + for cls in self._recorders: + if name in vars(cls): + break + else: + raise ValueError("callname %r not found in %r" %( + name, self._recorders.keys())) + l = [] + for call in self.calls: + if call._name in names: + l.append(call) + return l + + def contains(self, entries): + __tracebackhide__ = True + from py.builtin import print_ + i = 0 + entries = list(entries) + backlocals = py.std.sys._getframe(1).f_locals + while entries: + name, check = entries.pop(0) + for ind, call in enumerate(self.calls[i:]): + if call._name == name: + print_("NAMEMATCH", name, call) + if eval(check, backlocals, call.__dict__): + print_("CHECKERMATCH", repr(check), "->", call) + else: + print_("NOCHECKERMATCH", repr(check), "-", call) + continue + i += ind + 1 + break + print_("NONAMEMATCH", name, "with", call) + else: + py.test.fail("could not find %r check %r" % (name, check)) + + def popcall(self, name): + __tracebackhide__ = True + for i, call in enumerate(self.calls): + if call._name == name: + del self.calls[i] + return call + lines = ["could not find call %r, in:" % (name,)] + lines.extend([" %s" % str(x) for x in self.calls]) + py.test.fail("\n".join(lines)) + + def getcall(self, name): + l = self.getcalls(name) + assert len(l) == 1, (name, l) + return l[0] + + +def pytest_funcarg__linecomp(request): + return LineComp() + +def pytest_funcarg__LineMatcher(request): + return LineMatcher + +def pytest_funcarg__testdir(request): + tmptestdir = TmpTestdir(request) + return tmptestdir + +rex_outcome = re.compile("(\d+) (\w+)") +class RunResult: + def __init__(self, ret, outlines, errlines, duration): + self.ret = ret + self.outlines = outlines + self.errlines = errlines + self.stdout = LineMatcher(outlines) + self.stderr = LineMatcher(errlines) + self.duration = duration + + def parseoutcomes(self): + for line in reversed(self.outlines): + if 'seconds' in line: + outcomes = rex_outcome.findall(line) + if outcomes: + d = {} + for num, cat in outcomes: + d[cat] = int(num) + return d + +class TmpTestdir: + def __init__(self, request): + self.request = request + self.Config = request.config.__class__ + self._pytest = request.getfuncargvalue("_pytest") + # XXX remove duplication with tmpdir plugin + basetmp = request.config._tmpdirhandler.ensuretemp("testdir") + name = request.function.__name__ + for i in range(100): + try: + tmpdir = basetmp.mkdir(name + str(i)) + except py.error.EEXIST: + continue + break + # we need to create another subdir + # because Directory.collect() currently loads + # conftest.py from sibling directories + self.tmpdir = tmpdir.mkdir(name) + self.plugins = [] + self._syspathremove = [] + self.chdir() # always chdir + self.request.addfinalizer(self.finalize) + + def __repr__(self): + return "" % (self.tmpdir,) + + def finalize(self): + for p in self._syspathremove: + py.std.sys.path.remove(p) + if hasattr(self, '_olddir'): + self._olddir.chdir() + # delete modules that have been loaded from tmpdir + for name, mod in list(sys.modules.items()): + if mod: + fn = getattr(mod, '__file__', None) + if fn and fn.startswith(str(self.tmpdir)): + del sys.modules[name] + + def getreportrecorder(self, obj): + if hasattr(obj, 'config'): + obj = obj.config + if hasattr(obj, 'hook'): + obj = obj.hook + assert hasattr(obj, '_hookspecs'), obj + reprec = ReportRecorder(obj) + reprec.hookrecorder = self._pytest.gethookrecorder(obj) + reprec.hook = reprec.hookrecorder.hook + return reprec + + def chdir(self): + old = self.tmpdir.chdir() + if not hasattr(self, '_olddir'): + self._olddir = old + + def _makefile(self, ext, args, kwargs): + items = list(kwargs.items()) + if args: + source = py.builtin._totext("\n").join( + map(py.builtin._totext, args)) + py.builtin._totext("\n") + basename = self.request.function.__name__ + items.insert(0, (basename, source)) + ret = None + for name, value in items: + p = self.tmpdir.join(name).new(ext=ext) + source = py.builtin._totext(py.code.Source(value)).lstrip() + p.write(source.encode("utf-8"), "wb") + if ret is None: + ret = p + return ret + + + def makefile(self, ext, *args, **kwargs): + return self._makefile(ext, args, kwargs) + + def makeini(self, source): + return self.makefile('cfg', setup=source) + + def makeconftest(self, source): + return self.makepyfile(conftest=source) + + def makeini(self, source): + return self.makefile('.ini', tox=source) + + def getinicfg(self, source): + p = self.makeini(source) + return py.iniconfig.IniConfig(p)['pytest'] + + def makepyfile(self, *args, **kwargs): + return self._makefile('.py', args, kwargs) + + def maketxtfile(self, *args, **kwargs): + return self._makefile('.txt', args, kwargs) + + def syspathinsert(self, path=None): + if path is None: + path = self.tmpdir + py.std.sys.path.insert(0, str(path)) + self._syspathremove.append(str(path)) + + def mkdir(self, name): + return self.tmpdir.mkdir(name) + + def mkpydir(self, name): + p = self.mkdir(name) + p.ensure("__init__.py") + return p + + Session = Session + def getnode(self, config, arg): + session = Session(config) + assert '::' not in str(arg) + p = py.path.local(arg) + x = session.fspath.bestrelpath(p) + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res + + def getpathnode(self, path): + config = self.parseconfigure(path) + session = Session(config) + x = session.fspath.bestrelpath(path) + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return res + + def genitems(self, colitems): + session = colitems[0].session + result = [] + for colitem in colitems: + result.extend(session.genitems(colitem)) + return result + + def inline_genitems(self, *args): + #config = self.parseconfig(*args) + config = self.parseconfigure(*args) + rec = self.getreportrecorder(config) + session = Session(config) + config.hook.pytest_sessionstart(session=session) + session.perform_collect() + config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) + return session.items, rec + + def runitem(self, source): + # used from runner functional tests + item = self.getitem(source) + # the test class where we are called from wants to provide the runner + testclassinstance = py.builtin._getimself(self.request.function) + runner = testclassinstance.getrunner() + return runner(item) + + def inline_runsource(self, source, *cmdlineargs): + p = self.makepyfile(source) + l = list(cmdlineargs) + [p] + return self.inline_run(*l) + + def inline_runsource1(self, *args): + args = list(args) + source = args.pop() + p = self.makepyfile(source) + l = list(args) + [p] + reprec = self.inline_run(*l) + reports = reprec.getreports("pytest_runtest_logreport") + assert len(reports) == 1, reports + return reports[0] + + def inline_run(self, *args): + args = ("-s", ) + args # otherwise FD leakage + config = self.parseconfig(*args) + reprec = self.getreportrecorder(config) + #config.pluginmanager.do_configure(config) + config.hook.pytest_cmdline_main(config=config) + #config.pluginmanager.do_unconfigure(config) + return reprec + + def config_preparse(self): + config = self.Config() + for plugin in self.plugins: + if isinstance(plugin, str): + config.pluginmanager.import_plugin(plugin) + else: + if isinstance(plugin, dict): + plugin = PseudoPlugin(plugin) + if not config.pluginmanager.isregistered(plugin): + config.pluginmanager.register(plugin) + return config + + def parseconfig(self, *args): + if not args: + args = (self.tmpdir,) + config = self.config_preparse() + args = list(args) + for x in args: + if str(x).startswith('--basetemp'): + break + else: + args.append("--basetemp=%s" % self.tmpdir.dirpath('basetemp')) + config.parse(args) + return config + + def reparseconfig(self, args=None): + """ this is used from tests that want to re-invoke parse(). """ + if not args: + args = [self.tmpdir] + oldconfig = getattr(py.test, 'config', None) + try: + c = py.test.config = self.Config() + c.basetemp = py.path.local.make_numbered_dir(prefix="reparse", + keep=0, rootdir=self.tmpdir, lock_timeout=None) + c.parse(args) + c.pluginmanager.do_configure(c) + self.request.addfinalizer(lambda: c.pluginmanager.do_unconfigure(c)) + return c + finally: + py.test.config = oldconfig + + def parseconfigure(self, *args): + config = self.parseconfig(*args) + config.pluginmanager.do_configure(config) + self.request.addfinalizer(lambda: + config.pluginmanager.do_unconfigure(config)) + return config + + def getitem(self, source, funcname="test_func"): + for item in self.getitems(source): + if item.name == funcname: + return item + assert 0, "%r item not found in module:\n%s" %(funcname, source) + + def getitems(self, source): + modcol = self.getmodulecol(source) + return self.genitems([modcol]) + + def getmodulecol(self, source, configargs=(), withinit=False): + kw = {self.request.function.__name__: py.code.Source(source).strip()} + path = self.makepyfile(**kw) + if withinit: + self.makepyfile(__init__ = "#") + self.config = config = self.parseconfigure(path, *configargs) + node = self.getnode(config, path) + #config.pluginmanager.do_unconfigure(config) + return node + + def collect_by_name(self, modcol, name): + for colitem in modcol._memocollect(): + if colitem.name == name: + return colitem + + def popen(self, cmdargs, stdout, stderr, **kw): + env = os.environ.copy() + env['PYTHONPATH'] = os.pathsep.join(filter(None, [ + str(os.getcwd()), env.get('PYTHONPATH', '')])) + kw['env'] = env + #print "env", env + return py.std.subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw) + + def pytestmain(self, *args, **kwargs): + ret = pytest.main(*args, **kwargs) + if ret == 2: + raise KeyboardInterrupt() + def run(self, *cmdargs): + return self._run(*cmdargs) + + def _run(self, *cmdargs): + cmdargs = [str(x) for x in cmdargs] + p1 = self.tmpdir.join("stdout") + p2 = self.tmpdir.join("stderr") + print_("running", cmdargs, "curdir=", py.path.local()) + f1 = p1.open("wb") + f2 = p2.open("wb") + now = time.time() + popen = self.popen(cmdargs, stdout=f1, stderr=f2, + close_fds=(sys.platform != "win32")) + ret = popen.wait() + f1.close() + f2.close() + out = p1.read("rb") + out = getdecoded(out).splitlines() + err = p2.read("rb") + err = getdecoded(err).splitlines() + def dump_lines(lines, fp): + try: + for line in lines: + py.builtin.print_(line, file=fp) + except UnicodeEncodeError: + print("couldn't print to %s because of encoding" % (fp,)) + dump_lines(out, sys.stdout) + dump_lines(err, sys.stderr) + return RunResult(ret, out, err, time.time()-now) + + def runpybin(self, scriptname, *args): + fullargs = self._getpybinargs(scriptname) + args + return self.run(*fullargs) + + def _getpybinargs(self, scriptname): + if not self.request.config.getvalue("notoolsonpath"): + # XXX we rely on script refering to the correct environment + # we cannot use "(py.std.sys.executable,script)" + # becaue on windows the script is e.g. a py.test.exe + return (py.std.sys.executable, _pytest_fullpath,) + else: + py.test.skip("cannot run %r with --no-tools-on-path" % scriptname) + + def runpython(self, script, prepend=True): + if prepend: + s = self._getsysprepend() + if s: + script.write(s + "\n" + script.read()) + return self.run(sys.executable, script) + + def _getsysprepend(self): + if self.request.config.getvalue("notoolsonpath"): + s = "import sys;sys.path.insert(0,%r);" % str(py._pydir.dirpath()) + else: + s = "" + return s + + def runpython_c(self, command): + command = self._getsysprepend() + command + return self.run(py.std.sys.executable, "-c", command) + + def runpytest(self, *args): + p = py.path.local.make_numbered_dir(prefix="runpytest-", + keep=None, rootdir=self.tmpdir) + args = ('--basetemp=%s' % p, ) + args + #for x in args: + # if '--confcutdir' in str(x): + # break + #else: + # pass + # args = ('--confcutdir=.',) + args + plugins = [x for x in self.plugins if isinstance(x, str)] + if plugins: + args = ('-p', plugins[0]) + args + return self.runpybin("py.test", *args) + + def spawn_pytest(self, string, expect_timeout=10.0): + if self.request.config.getvalue("notoolsonpath"): + py.test.skip("--no-tools-on-path prevents running pexpect-spawn tests") + basetemp = self.tmpdir.mkdir("pexpect") + invoke = " ".join(map(str, self._getpybinargs("py.test"))) + cmd = "%s --basetemp=%s %s" % (invoke, basetemp, string) + return self.spawn(cmd, expect_timeout=expect_timeout) + + def spawn(self, cmd, expect_timeout=10.0): + pexpect = py.test.importorskip("pexpect", "2.4") + if hasattr(sys, 'pypy_version_info') and '64' in py.std.platform.machine(): + pytest.skip("pypy-64 bit not supported") + logfile = self.tmpdir.join("spawn.out") + child = pexpect.spawn(cmd, logfile=logfile.open("w")) + child.timeout = expect_timeout + return child + +def getdecoded(out): + try: + return out.decode("utf-8") + except UnicodeDecodeError: + return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % ( + py.io.saferepr(out),) + +class PseudoPlugin: + def __init__(self, vars): + self.__dict__.update(vars) + +class ReportRecorder(object): + def __init__(self, hook): + self.hook = hook + self.pluginmanager = hook._pm + self.pluginmanager.register(self) + + def getcall(self, name): + return self.hookrecorder.getcall(name) + + def popcall(self, name): + return self.hookrecorder.popcall(name) + + def getcalls(self, names): + """ return list of ParsedCall instances matching the given eventname. """ + return self.hookrecorder.getcalls(names) + + # functionality for test reports + + def getreports(self, names="pytest_runtest_logreport pytest_collectreport"): + return [x.report for x in self.getcalls(names)] + + def matchreport(self, inamepart="", names="pytest_runtest_logreport pytest_collectreport", when=None): + """ return a testreport whose dotted import path matches """ + l = [] + for rep in self.getreports(names=names): + if when and getattr(rep, 'when', None) != when: + continue + if not inamepart or inamepart in rep.nodeid.split("::"): + l.append(rep) + if not l: + raise ValueError("could not find test report matching %r: no test reports at all!" % + (inamepart,)) + if len(l) > 1: + raise ValueError("found more than one testreport matching %r: %s" %( + inamepart, l)) + return l[0] + + def getfailures(self, names='pytest_runtest_logreport pytest_collectreport'): + return [rep for rep in self.getreports(names) if rep.failed] + + def getfailedcollections(self): + return self.getfailures('pytest_collectreport') + + def listoutcomes(self): + passed = [] + skipped = [] + failed = [] + for rep in self.getreports("pytest_runtest_logreport"): + if rep.passed: + if rep.when == "call": + passed.append(rep) + elif rep.skipped: + skipped.append(rep) + elif rep.failed: + failed.append(rep) + return passed, skipped, failed + + def countoutcomes(self): + return [len(x) for x in self.listoutcomes()] + + def assertoutcome(self, passed=0, skipped=0, failed=0): + realpassed, realskipped, realfailed = self.listoutcomes() + assert passed == len(realpassed) + assert skipped == len(realskipped) + assert failed == len(realfailed) + + def clear(self): + self.hookrecorder.calls[:] = [] + + def unregister(self): + self.pluginmanager.unregister(self) + self.hookrecorder.finish_recording() + +class LineComp: + def __init__(self): + self.stringio = py.io.TextIO() + + def assert_contains_lines(self, lines2): + """ assert that lines2 are contained (linearly) in lines1. + return a list of extralines found. + """ + __tracebackhide__ = True + val = self.stringio.getvalue() + self.stringio.truncate(0) + self.stringio.seek(0) + lines1 = val.split("\n") + return LineMatcher(lines1).fnmatch_lines(lines2) + +class LineMatcher: + def __init__(self, lines): + self.lines = lines + + def str(self): + return "\n".join(self.lines) + + def _getlines(self, lines2): + if isinstance(lines2, str): + lines2 = py.code.Source(lines2) + if isinstance(lines2, py.code.Source): + lines2 = lines2.strip().lines + return lines2 + + def fnmatch_lines_random(self, lines2): + lines2 = self._getlines(lines2) + for line in lines2: + for x in self.lines: + if line == x or fnmatch(x, line): + print_("matched: ", repr(line)) + break + else: + raise ValueError("line %r not found in output" % line) + + def fnmatch_lines(self, lines2): + def show(arg1, arg2): + py.builtin.print_(arg1, arg2, file=py.std.sys.stderr) + lines2 = self._getlines(lines2) + lines1 = self.lines[:] + nextline = None + extralines = [] + __tracebackhide__ = True + for line in lines2: + nomatchprinted = False + while lines1: + nextline = lines1.pop(0) + if line == nextline: + show("exact match:", repr(line)) + break + elif fnmatch(nextline, line): + show("fnmatch:", repr(line)) + show(" with:", repr(nextline)) + break + else: + if not nomatchprinted: + show("nomatch:", repr(line)) + nomatchprinted = True + show(" and:", repr(nextline)) + extralines.append(nextline) + else: + py.test.fail("remains unmatched: %r, see stderr" % (line,)) diff --git a/lib/pypy/_pytest/python.py b/lib/pypy/_pytest/python.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/python.py @@ -0,0 +1,871 @@ +""" Python test discovery, setup and run of test functions. """ +import py +import inspect +import sys +import pytest +from py._code.code import TerminalRepr + +import _pytest +cutdir = py.path.local(_pytest.__file__).dirpath() + +def pytest_addoption(parser): + group = parser.getgroup("general") + group.addoption('--funcargs', + action="store_true", dest="showfuncargs", default=False, + help="show available function arguments, sorted by plugin") + parser.addini("python_files", type="args", + default=('test_*.py', '*_test.py'), + help="glob-style file patterns for Python test module discovery") + parser.addini("python_classes", type="args", default=("Test",), + help="prefixes for Python test class discovery") + parser.addini("python_functions", type="args", default=("test",), + help="prefixes for Python test function and method discovery") + +def pytest_cmdline_main(config): + if config.option.showfuncargs: + showfuncargs(config) + return 0 + + at pytest.mark.trylast +def pytest_namespace(): + raises.Exception = pytest.fail.Exception + return { + 'raises' : raises, + 'collect': { + 'Module': Module, 'Class': Class, 'Instance': Instance, + 'Function': Function, 'Generator': Generator, + '_fillfuncargs': fillfuncargs} + } + +def pytest_funcarg__pytestconfig(request): + """ the pytest config object with access to command line opts.""" + return request.config + +def pytest_pyfunc_call(__multicall__, pyfuncitem): + if not __multicall__.execute(): + testfunction = pyfuncitem.obj + if pyfuncitem._isyieldedfunction(): + testfunction(*pyfuncitem._args) + else: + funcargs = pyfuncitem.funcargs + testfunction(**funcargs) + +def pytest_collect_file(path, parent): + ext = path.ext + pb = path.purebasename + if ext == ".py": + if not parent.session.isinitpath(path): + for pat in parent.config.getini('python_files'): + if path.fnmatch(pat): + break + else: + return + return parent.ihook.pytest_pycollect_makemodule( + path=path, parent=parent) + +def pytest_pycollect_makemodule(path, parent): + return Module(path, parent) + +def pytest_pycollect_makeitem(__multicall__, collector, name, obj): + res = __multicall__.execute() + if res is not None: + return res + if inspect.isclass(obj): + #if hasattr(collector.obj, 'unittest'): + # return # we assume it's a mixin class for a TestCase derived one + if collector.classnamefilter(name): + if not hasinit(obj): + Class = collector._getcustomclass("Class") + return Class(name, parent=collector) + elif collector.funcnamefilter(name) and hasattr(obj, '__call__'): + if is_generator(obj): + return Generator(name, parent=collector) + else: + return collector._genfunctions(name, obj) + +def is_generator(func): + try: + return py.code.getrawcode(func).co_flags & 32 # generator function + except AttributeError: # builtin functions have no bytecode + # assume them to not be generators + return False + +class PyobjMixin(object): + def obj(): + def fget(self): + try: + return self._obj + except AttributeError: + self._obj = obj = self._getobj() + return obj + def fset(self, value): + self._obj = value + return property(fget, fset, None, "underlying python object") + obj = obj() + + def _getobj(self): + return getattr(self.parent.obj, self.name) + + def getmodpath(self, stopatmodule=True, includemodule=False): + """ return python path relative to the containing module. """ + chain = self.listchain() + chain.reverse() + parts = [] + for node in chain: + if isinstance(node, Instance): + continue + name = node.name + if isinstance(node, Module): + assert name.endswith(".py") + name = name[:-3] + if stopatmodule: + if includemodule: + parts.append(name) + break + parts.append(name) + parts.reverse() + s = ".".join(parts) + return s.replace(".[", "[") + + def _getfslineno(self): + try: + return self._fslineno + except AttributeError: + pass + obj = self.obj + # xxx let decorators etc specify a sane ordering + if hasattr(obj, 'place_as'): + obj = obj.place_as + + self._fslineno = py.code.getfslineno(obj) + return self._fslineno + + def reportinfo(self): + # XXX caching? + obj = self.obj + if hasattr(obj, 'compat_co_firstlineno'): + # nose compatibility + fspath = sys.modules[obj.__module__].__file__ + if fspath.endswith(".pyc"): + fspath = fspath[:-1] + #assert 0 + #fn = inspect.getsourcefile(obj) or inspect.getfile(obj) + lineno = obj.compat_co_firstlineno + modpath = obj.__module__ + else: + fspath, lineno = self._getfslineno() + modpath = self.getmodpath() + return fspath, lineno, modpath + +class PyCollectorMixin(PyobjMixin, pytest.Collector): + + def funcnamefilter(self, name): + for prefix in self.config.getini("python_functions"): + if name.startswith(prefix): + return True + + def classnamefilter(self, name): + for prefix in self.config.getini("python_classes"): + if name.startswith(prefix): + return True + + def collect(self): + # NB. we avoid random getattrs and peek in the __dict__ instead + # (XXX originally introduced from a PyPy need, still true?) + dicts = [getattr(self.obj, '__dict__', {})] + for basecls in inspect.getmro(self.obj.__class__): + dicts.append(basecls.__dict__) + seen = {} + l = [] + for dic in dicts: + for name, obj in dic.items(): + if name in seen: + continue + seen[name] = True + if name[0] != "_": + res = self.makeitem(name, obj) + if res is None: + continue + if not isinstance(res, list): + res = [res] + l.extend(res) + l.sort(key=lambda item: item.reportinfo()[:2]) + return l + + def makeitem(self, name, obj): + return self.ihook.pytest_pycollect_makeitem( + collector=self, name=name, obj=obj) + + def _genfunctions(self, name, funcobj): + module = self.getparent(Module).obj + clscol = self.getparent(Class) + cls = clscol and clscol.obj or None + metafunc = Metafunc(funcobj, config=self.config, + cls=cls, module=module) + gentesthook = self.config.hook.pytest_generate_tests + extra = [module] + if cls is not None: + extra.append(cls()) + plugins = self.getplugins() + extra + gentesthook.pcall(plugins, metafunc=metafunc) + Function = self._getcustomclass("Function") + if not metafunc._calls: + return Function(name, parent=self) + l = [] + for callspec in metafunc._calls: + subname = "%s[%s]" %(name, callspec.id) + function = Function(name=subname, parent=self, + callspec=callspec, callobj=funcobj, keywords={callspec.id:True}) + l.append(function) + return l + + +class Module(pytest.File, PyCollectorMixin): + def _getobj(self): + return self._memoizedcall('_obj', self._importtestmodule) + + def _importtestmodule(self): + # we assume we are only called once per module + from _pytest import assertion + assertion.before_module_import(self) + try: + try: + mod = self.fspath.pyimport(ensuresyspath=True) + finally: + assertion.after_module_import(self) + except SyntaxError: + excinfo = py.code.ExceptionInfo() + raise self.CollectError(excinfo.getrepr(style="short")) + except self.fspath.ImportMismatchError: + e = sys.exc_info()[1] + raise self.CollectError( + "import file mismatch:\n" + "imported module %r has this __file__ attribute:\n" + " %s\n" + "which is not the same as the test file we want to collect:\n" + " %s\n" + "HINT: use a unique basename for your test file modules" + % e.args + ) + #print "imported test module", mod + self.config.pluginmanager.consider_module(mod) + return mod + + def setup(self): + if hasattr(self.obj, 'setup_module'): + #XXX: nose compat hack, move to nose plugin + # if it takes a positional arg, its probably a pytest style one + # so we pass the current module object + if inspect.getargspec(self.obj.setup_module)[0]: + self.obj.setup_module(self.obj) + else: + self.obj.setup_module() + + def teardown(self): + if hasattr(self.obj, 'teardown_module'): + #XXX: nose compat hack, move to nose plugin + # if it takes a positional arg, its probably a py.test style one + # so we pass the current module object + if inspect.getargspec(self.obj.teardown_module)[0]: + self.obj.teardown_module(self.obj) + else: + self.obj.teardown_module() + +class Class(PyCollectorMixin, pytest.Collector): + + def collect(self): + return [self._getcustomclass("Instance")(name="()", parent=self)] + + def setup(self): + setup_class = getattr(self.obj, 'setup_class', None) + if setup_class is not None: + setup_class = getattr(setup_class, 'im_func', setup_class) + setup_class(self.obj) + + def teardown(self): + teardown_class = getattr(self.obj, 'teardown_class', None) + if teardown_class is not None: + teardown_class = getattr(teardown_class, 'im_func', teardown_class) + teardown_class(self.obj) + +class Instance(PyCollectorMixin, pytest.Collector): + def _getobj(self): + return self.parent.obj() + + def newinstance(self): + self.obj = self._getobj() + return self.obj + +class FunctionMixin(PyobjMixin): + """ mixin for the code common to Function and Generator. + """ + def setup(self): + """ perform setup for this test function. """ + if hasattr(self, '_preservedparent'): + obj = self._preservedparent + elif isinstance(self.parent, Instance): + obj = self.parent.newinstance() + self.obj = self._getobj() + else: + obj = self.parent.obj + if inspect.ismethod(self.obj): + name = 'setup_method' + else: + name = 'setup_function' + setup_func_or_method = getattr(obj, name, None) + if setup_func_or_method is not None: + setup_func_or_method(self.obj) + + def teardown(self): + """ perform teardown for this test function. """ + if inspect.ismethod(self.obj): + name = 'teardown_method' + else: + name = 'teardown_function' + obj = self.parent.obj + teardown_func_or_meth = getattr(obj, name, None) + if teardown_func_or_meth is not None: + teardown_func_or_meth(self.obj) + + def _prunetraceback(self, excinfo): + if hasattr(self, '_obj') and not self.config.option.fulltrace: + code = py.code.Code(self.obj) + path, firstlineno = code.path, code.firstlineno + traceback = excinfo.traceback + ntraceback = traceback.cut(path=path, firstlineno=firstlineno) + if ntraceback == traceback: + ntraceback = ntraceback.cut(path=path) + if ntraceback == traceback: + ntraceback = ntraceback.cut(excludepath=cutdir) + excinfo.traceback = ntraceback.filter() + + def _repr_failure_py(self, excinfo, style="long"): + if excinfo.errisinstance(FuncargRequest.LookupError): + fspath, lineno, msg = self.reportinfo() + lines, _ = inspect.getsourcelines(self.obj) + for i, line in enumerate(lines): + if line.strip().startswith('def'): + return FuncargLookupErrorRepr(fspath, lineno, + lines[:i+1], str(excinfo.value)) + if excinfo.errisinstance(pytest.fail.Exception): + if not excinfo.value.pytrace: + return str(excinfo.value) + return super(FunctionMixin, self)._repr_failure_py(excinfo, + style=style) + + def repr_failure(self, excinfo, outerr=None): + assert outerr is None, "XXX outerr usage is deprecated" + return self._repr_failure_py(excinfo, + style=self.config.option.tbstyle) + +class FuncargLookupErrorRepr(TerminalRepr): + def __init__(self, filename, firstlineno, deflines, errorstring): + self.deflines = deflines + self.errorstring = errorstring + self.filename = filename + self.firstlineno = firstlineno + + def toterminal(self, tw): + tw.line() + for line in self.deflines: + tw.line(" " + line.strip()) + for line in self.errorstring.split("\n"): + tw.line(" " + line.strip(), red=True) + tw.line() + tw.line("%s:%d" % (self.filename, self.firstlineno+1)) + +class Generator(FunctionMixin, PyCollectorMixin, pytest.Collector): + def collect(self): + # test generators are seen as collectors but they also + # invoke setup/teardown on popular request + # (induced by the common "test_*" naming shared with normal tests) + self.session._setupstate.prepare(self) + # see FunctionMixin.setup and test_setupstate_is_preserved_134 + self._preservedparent = self.parent.obj + l = [] + seen = {} + for i, x in enumerate(self.obj()): + name, call, args = self.getcallargs(x) + if not py.builtin.callable(call): + raise TypeError("%r yielded non callable test %r" %(self.obj, call,)) + if name is None: + name = "[%d]" % i + else: + name = "['%s']" % name + if name in seen: + raise ValueError("%r generated tests with non-unique name %r" %(self, name)) + seen[name] = True + l.append(self.Function(name, self, args=args, callobj=call)) + return l + + def getcallargs(self, obj): + if not isinstance(obj, (tuple, list)): + obj = (obj,) + # explict naming + if isinstance(obj[0], py.builtin._basestring): + name = obj[0] + obj = obj[1:] + else: + name = None + call, args = obj[0], obj[1:] + return name, call, args + + +# +# Test Items +# +_dummy = object() +class Function(FunctionMixin, pytest.Item): + """ a Function Item is responsible for setting up + and executing a Python callable test object. + """ + _genid = None + def __init__(self, name, parent=None, args=None, config=None, + callspec=None, callobj=_dummy, keywords=None, session=None): + super(Function, self).__init__(name, parent, + config=config, session=session) + self._args = args + if self._isyieldedfunction(): + assert not callspec, ( + "yielded functions (deprecated) cannot have funcargs") + else: + if callspec is not None: + self.funcargs = callspec.funcargs or {} + self._genid = callspec.id + if hasattr(callspec, "param"): + self._requestparam = callspec.param + else: + self.funcargs = {} + if callobj is not _dummy: + self._obj = callobj + self.function = getattr(self.obj, 'im_func', self.obj) + self.keywords.update(py.builtin._getfuncdict(self.obj) or {}) + if keywords: + self.keywords.update(keywords) + + def _getobj(self): + name = self.name + i = name.find("[") # parametrization + if i != -1: + name = name[:i] + return getattr(self.parent.obj, name) + + def _isyieldedfunction(self): + return self._args is not None + + def runtest(self): + """ execute the underlying test function. """ + self.ihook.pytest_pyfunc_call(pyfuncitem=self) + + def setup(self): + super(Function, self).setup() + if hasattr(self, 'funcargs'): + fillfuncargs(self) + + def __eq__(self, other): + try: + return (self.name == other.name and + self._args == other._args and + self.parent == other.parent and + self.obj == other.obj and + getattr(self, '_genid', None) == + getattr(other, '_genid', None) + ) + except AttributeError: + pass + return False + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.parent, self.name)) + +def hasinit(obj): + init = getattr(obj, '__init__', None) + if init: + if init != object.__init__: + return True + + +def getfuncargnames(function, startindex=None): + # XXX merge with main.py's varnames + argnames = py.std.inspect.getargs(py.code.getrawcode(function))[0] + if startindex is None: + startindex = py.std.inspect.ismethod(function) and 1 or 0 + defaults = getattr(function, 'func_defaults', + getattr(function, '__defaults__', None)) or () + numdefaults = len(defaults) + if numdefaults: + return argnames[startindex:-numdefaults] + return argnames[startindex:] + +def fillfuncargs(function): + """ fill missing funcargs. """ + request = FuncargRequest(pyfuncitem=function) + request._fillfuncargs() + +_notexists = object() +class CallSpec: + def __init__(self, funcargs, id, param): + self.funcargs = funcargs + self.id = id + if param is not _notexists: + self.param = param + def __repr__(self): + return "" %( + self.id, getattr(self, 'param', '?'), self.funcargs) + +class Metafunc: + def __init__(self, function, config=None, cls=None, module=None): + self.config = config + self.module = module + self.function = function + self.funcargnames = getfuncargnames(function, + startindex=int(cls is not None)) + self.cls = cls + self.module = module + self._calls = [] + self._ids = py.builtin.set() + + def addcall(self, funcargs=None, id=_notexists, param=_notexists): + """ add a new call to the underlying test function during the + collection phase of a test run. Note that request.addcall() is + called during the test collection phase prior and independently + to actual test execution. Therefore you should perform setup + of resources in a funcarg factory which can be instrumented + with the ``param``. + + :arg funcargs: argument keyword dictionary used when invoking + the test function. + + :arg id: used for reporting and identification purposes. If you + don't supply an `id` the length of the currently + list of calls to the test function will be used. + + :arg param: will be exposed to a later funcarg factory invocation + through the ``request.param`` attribute. It allows to + defer test fixture setup activities to when an actual + test is run. + """ + assert funcargs is None or isinstance(funcargs, dict) + if funcargs is not None: + for name in funcargs: + if name not in self.funcargnames: + pytest.fail("funcarg %r not used in this function." % name) + if id is None: + raise ValueError("id=None not allowed") + if id is _notexists: + id = len(self._calls) + id = str(id) + if id in self._ids: + raise ValueError("duplicate id %r" % id) + self._ids.add(id) + self._calls.append(CallSpec(funcargs, id, param)) + +class FuncargRequest: + """ A request for function arguments from a test function. + + Note that there is an optional ``param`` attribute in case + there was an invocation to metafunc.addcall(param=...). + If no such call was done in a ``pytest_generate_tests`` + hook, the attribute will not be present. + """ + _argprefix = "pytest_funcarg__" + _argname = None + + class LookupError(LookupError): + """ error on performing funcarg request. """ + + def __init__(self, pyfuncitem): + self._pyfuncitem = pyfuncitem + if hasattr(pyfuncitem, '_requestparam'): + self.param = pyfuncitem._requestparam + extra = [obj for obj in (self.module, self.instance) if obj] + self._plugins = pyfuncitem.getplugins() + extra + self._funcargs = self._pyfuncitem.funcargs.copy() + self._name2factory = {} + self._currentarg = None + + @property + def function(self): + """ function object of the test invocation. """ + return self._pyfuncitem.obj + + @property + def keywords(self): + """ keywords of the test function item. + + .. versionadded:: 2.0 + """ + return self._pyfuncitem.keywords + + @property + def module(self): + """ module where the test function was collected. """ + return self._pyfuncitem.getparent(pytest.Module).obj + + @property + def cls(self): + """ class (can be None) where the test function was collected. """ + clscol = self._pyfuncitem.getparent(pytest.Class) + if clscol: + return clscol.obj + @property + def instance(self): + """ instance (can be None) on which test function was collected. """ + return py.builtin._getimself(self.function) + + @property + def config(self): + """ the pytest config object associated with this request. """ + return self._pyfuncitem.config + + @property + def fspath(self): + """ the file system path of the test module which collected this test. """ + return self._pyfuncitem.fspath + + def _fillfuncargs(self): + argnames = getfuncargnames(self.function) + if argnames: + assert not getattr(self._pyfuncitem, '_args', None), ( + "yielded functions cannot have funcargs") + for argname in argnames: + if argname not in self._pyfuncitem.funcargs: + self._pyfuncitem.funcargs[argname] = self.getfuncargvalue(argname) + + + def applymarker(self, marker): + """ apply a marker to a single test function invocation. + This method is useful if you don't want to have a keyword/marker + on all function invocations. + + :arg marker: a :py:class:`_pytest.mark.MarkDecorator` object + created by a call to ``py.test.mark.NAME(...)``. + """ + if not isinstance(marker, py.test.mark.XYZ.__class__): + raise ValueError("%r is not a py.test.mark.* object") + self._pyfuncitem.keywords[marker.markname] = marker + + def cached_setup(self, setup, teardown=None, scope="module", extrakey=None): + """ return a testing resource managed by ``setup`` & + ``teardown`` calls. ``scope`` and ``extrakey`` determine when the + ``teardown`` function will be called so that subsequent calls to + ``setup`` would recreate the resource. + + :arg teardown: function receiving a previously setup resource. + :arg setup: a no-argument function creating a resource. + :arg scope: a string value out of ``function``, ``class``, ``module`` + or ``session`` indicating the caching lifecycle of the resource. + :arg extrakey: added to internal caching key of (funcargname, scope). + """ + if not hasattr(self.config, '_setupcache'): + self.config._setupcache = {} # XXX weakref? + cachekey = (self._currentarg, self._getscopeitem(scope), extrakey) + cache = self.config._setupcache + try: + val = cache[cachekey] + except KeyError: + val = setup() + cache[cachekey] = val + if teardown is not None: + def finalizer(): + del cache[cachekey] + teardown(val) + self._addfinalizer(finalizer, scope=scope) + return val + + def getfuncargvalue(self, argname): + """ Retrieve a function argument by name for this test + function invocation. This allows one function argument factory + to call another function argument factory. If there are two + funcarg factories for the same test function argument the first + factory may use ``getfuncargvalue`` to call the second one and + do something additional with the resource. + """ + try: + return self._funcargs[argname] + except KeyError: + pass + if argname not in self._name2factory: + self._name2factory[argname] = self.config.pluginmanager.listattr( + plugins=self._plugins, + attrname=self._argprefix + str(argname) + ) + #else: we are called recursively + if not self._name2factory[argname]: + self._raiselookupfailed(argname) + funcargfactory = self._name2factory[argname].pop() + oldarg = self._currentarg + self._currentarg = argname + try: + self._funcargs[argname] = res = funcargfactory(request=self) + finally: + self._currentarg = oldarg + return res + + def _getscopeitem(self, scope): + if scope == "function": + return self._pyfuncitem + elif scope == "session": + return None + elif scope == "class": + x = self._pyfuncitem.getparent(pytest.Class) + if x is not None: + return x + scope = "module" + if scope == "module": + return self._pyfuncitem.getparent(pytest.Module) + raise ValueError("unknown finalization scope %r" %(scope,)) + + def addfinalizer(self, finalizer): + """add finalizer function to be called after test function + finished execution. """ + self._addfinalizer(finalizer, scope="function") + + def _addfinalizer(self, finalizer, scope): + colitem = self._getscopeitem(scope) + self._pyfuncitem.session._setupstate.addfinalizer( + finalizer=finalizer, colitem=colitem) + + def __repr__(self): + return "" %(self._pyfuncitem) + + def _raiselookupfailed(self, argname): + available = [] + for plugin in self._plugins: + for name in vars(plugin): + if name.startswith(self._argprefix): + name = name[len(self._argprefix):] + if name not in available: + available.append(name) + fspath, lineno, msg = self._pyfuncitem.reportinfo() + msg = "LookupError: no factory found for function argument %r" % (argname,) + msg += "\n available funcargs: %s" %(", ".join(available),) + msg += "\n use 'py.test --funcargs [testpath]' for help on them." + raise self.LookupError(msg) + +def showfuncargs(config): + from _pytest.main import wrap_session + return wrap_session(config, _showfuncargs_main) + +def _showfuncargs_main(config, session): + session.perform_collect() + if session.items: + plugins = session.items[0].getplugins() + else: + plugins = session.getplugins() + curdir = py.path.local() + tw = py.io.TerminalWriter() + verbose = config.getvalue("verbose") + for plugin in plugins: + available = [] + for name, factory in vars(plugin).items(): + if name.startswith(FuncargRequest._argprefix): + name = name[len(FuncargRequest._argprefix):] + if name not in available: + available.append([name, factory]) + if available: + pluginname = plugin.__name__ + for name, factory in available: + loc = getlocation(factory, curdir) + if verbose: + funcargspec = "%s -- %s" %(name, loc,) + else: + funcargspec = name + tw.line(funcargspec, green=True) + doc = factory.__doc__ or "" + if doc: + for line in doc.split("\n"): + tw.line(" " + line.strip()) + else: + tw.line(" %s: no docstring available" %(loc,), + red=True) + +def getlocation(function, curdir): + import inspect + fn = py.path.local(inspect.getfile(function)) + lineno = py.builtin._getcode(function).co_firstlineno + if fn.relto(curdir): + fn = fn.relto(curdir) + return "%s:%d" %(fn, lineno+1) + +# builtin pytest.raises helper + +def raises(ExpectedException, *args, **kwargs): + """ assert that a code block/function call raises @ExpectedException + and raise a failure exception otherwise. + + If using Python 2.5 or above, you may use this function as a + context manager:: + + >>> with raises(ZeroDivisionError): + ... 1/0 + + Or you can specify a callable by passing a to-be-called lambda:: + + >>> raises(ZeroDivisionError, lambda: 1/0) + + + or you can specify an arbitrary callable with arguments:: + + >>> def f(x): return 1/x + ... + >>> raises(ZeroDivisionError, f, 0) + + >>> raises(ZeroDivisionError, f, x=0) + + + A third possibility is to use a string which which will + be executed:: + + >>> raises(ZeroDivisionError, "f(0)") + + """ + __tracebackhide__ = True + + if not args: + return RaisesContext(ExpectedException) + elif isinstance(args[0], str): + code, = args + assert isinstance(code, str) + frame = sys._getframe(1) + loc = frame.f_locals.copy() + loc.update(kwargs) + #print "raises frame scope: %r" % frame.f_locals + try: + code = py.code.Source(code).compile() + py.builtin.exec_(code, frame.f_globals, loc) + # XXX didn'T mean f_globals == f_locals something special? + # this is destroyed here ... + except ExpectedException: + return py.code.ExceptionInfo() + else: + func = args[0] + try: + func(*args[1:], **kwargs) + except ExpectedException: + return py.code.ExceptionInfo() + k = ", ".join(["%s=%r" % x for x in kwargs.items()]) + if k: + k = ', ' + k + expr = '%s(%r%s)' %(getattr(func, '__name__', func), args, k) + pytest.fail("DID NOT RAISE") + +class RaisesContext(object): + def __init__(self, ExpectedException): + self.ExpectedException = ExpectedException + self.excinfo = None + + def __enter__(self): + self.excinfo = object.__new__(py.code.ExceptionInfo) + return self.excinfo + + def __exit__(self, *tp): + __tracebackhide__ = True + if tp[0] is None: + pytest.fail("DID NOT RAISE") + self.excinfo.__init__(tp) + return issubclass(self.excinfo.type, self.ExpectedException) + diff --git a/lib/pypy/_pytest/recwarn.py b/lib/pypy/_pytest/recwarn.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/recwarn.py @@ -0,0 +1,99 @@ +""" recording warnings during test function execution. """ + +import py +import sys, os + +def pytest_funcarg__recwarn(request): + """Return a WarningsRecorder instance that provides these methods: + + * ``pop(category=None)``: return last warning matching the category. + * ``clear()``: clear list of warnings + + See http://docs.python.org/library/warnings.html for information + on warning categories. + """ + if sys.version_info >= (2,7): + import warnings + oldfilters = warnings.filters[:] + warnings.simplefilter('default') + def reset_filters(): + warnings.filters[:] = oldfilters + request.addfinalizer(reset_filters) + wrec = WarningsRecorder() + request.addfinalizer(wrec.finalize) + return wrec + +def pytest_namespace(): + return {'deprecated_call': deprecated_call} + +def deprecated_call(func, *args, **kwargs): + """ assert that calling ``func(*args, **kwargs)`` + triggers a DeprecationWarning. + """ + warningmodule = py.std.warnings + l = [] + oldwarn_explicit = getattr(warningmodule, 'warn_explicit') + def warn_explicit(*args, **kwargs): + l.append(args) + oldwarn_explicit(*args, **kwargs) + oldwarn = getattr(warningmodule, 'warn') + def warn(*args, **kwargs): + l.append(args) + oldwarn(*args, **kwargs) + + warningmodule.warn_explicit = warn_explicit + warningmodule.warn = warn + try: + ret = func(*args, **kwargs) + finally: + warningmodule.warn_explicit = warn_explicit + warningmodule.warn = warn + if not l: + #print warningmodule + __tracebackhide__ = True + raise AssertionError("%r did not produce DeprecationWarning" %(func,)) + return ret + + +class RecordedWarning: + def __init__(self, message, category, filename, lineno, line): + self.message = message + self.category = category + self.filename = filename + self.lineno = lineno + self.line = line + +class WarningsRecorder: + def __init__(self): + warningmodule = py.std.warnings + self.list = [] + def showwarning(message, category, filename, lineno, line=0): + self.list.append(RecordedWarning( + message, category, filename, lineno, line)) + try: + self.old_showwarning(message, category, + filename, lineno, line=line) + except TypeError: + # < python2.6 + self.old_showwarning(message, category, filename, lineno) + self.old_showwarning = warningmodule.showwarning + warningmodule.showwarning = showwarning + + def pop(self, cls=Warning): + """ pop the first recorded warning, raise exception if not exists.""" + for i, w in enumerate(self.list): + if issubclass(w.category, cls): + return self.list.pop(i) + __tracebackhide__ = True + assert 0, "%r not found in %r" %(cls, self.list) + + #def resetregistry(self): + # import warnings + # warnings.onceregistry.clear() + # warnings.__warningregistry__.clear() + + def clear(self): + self.list[:] = [] + + def finalize(self): + py.std.warnings.showwarning = self.old_showwarning diff --git a/lib/pypy/_pytest/resultlog.py b/lib/pypy/_pytest/resultlog.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/resultlog.py @@ -0,0 +1,93 @@ +""" (disabled by default) create result information in a plain text file. """ + +import py + +def pytest_addoption(parser): + group = parser.getgroup("terminal reporting", "resultlog plugin options") + group.addoption('--resultlog', action="store", dest="resultlog", + metavar="path", default=None, + help="path for machine-readable result log.") + +def pytest_configure(config): + resultlog = config.option.resultlog + # prevent opening resultlog on slave nodes (xdist) + if resultlog and not hasattr(config, 'slaveinput'): + logfile = open(resultlog, 'w', 1) # line buffered + config._resultlog = ResultLog(config, logfile) + config.pluginmanager.register(config._resultlog) + +def pytest_unconfigure(config): + resultlog = getattr(config, '_resultlog', None) + if resultlog: + resultlog.logfile.close() + del config._resultlog + config.pluginmanager.unregister(resultlog) + +def generic_path(item): + chain = item.listchain() + gpath = [chain[0].name] + fspath = chain[0].fspath + fspart = False + for node in chain[1:]: + newfspath = node.fspath + if newfspath == fspath: + if fspart: + gpath.append(':') + fspart = False + else: + gpath.append('.') + else: + gpath.append('/') + fspart = True + name = node.name + if name[0] in '([': + gpath.pop() + gpath.append(name) + fspath = newfspath + return ''.join(gpath) + +class ResultLog(object): + def __init__(self, config, logfile): + self.config = config + self.logfile = logfile # preferably line buffered + + def write_log_entry(self, testpath, lettercode, longrepr): + py.builtin.print_("%s %s" % (lettercode, testpath), file=self.logfile) + for line in longrepr.splitlines(): + py.builtin.print_(" %s" % line, file=self.logfile) + + def log_outcome(self, report, lettercode, longrepr): + testpath = getattr(report, 'nodeid', None) + if testpath is None: + testpath = report.fspath + self.write_log_entry(testpath, lettercode, longrepr) + + def pytest_runtest_logreport(self, report): + res = self.config.hook.pytest_report_teststatus(report=report) + code = res[1] + if code == 'x': + longrepr = str(report.longrepr) + elif code == 'X': + longrepr = '' + elif report.passed: + longrepr = "" + elif report.failed: + longrepr = str(report.longrepr) + elif report.skipped: + longrepr = str(report.longrepr[2]) + self.log_outcome(report, code, longrepr) + + def pytest_collectreport(self, report): + if not report.passed: + if report.failed: + code = "F" + longrepr = str(report.longrepr.reprcrash) + else: + assert report.skipped + code = "S" + longrepr = "%s:%d: %s" % report.longrepr + self.log_outcome(report, code, longrepr) + + def pytest_internalerror(self, excrepr): + path = excrepr.reprcrash.path + self.write_log_entry(path, '!', str(excrepr)) diff --git a/lib/pypy/_pytest/runner.py b/lib/pypy/_pytest/runner.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/runner.py @@ -0,0 +1,388 @@ +""" basic collect and runtest protocol implementations """ + +import py, sys +from py._code.code import TerminalRepr + +def pytest_namespace(): + return { + 'fail' : fail, + 'skip' : skip, + 'importorskip' : importorskip, + 'exit' : exit, + } + +# +# pytest plugin hooks + +def pytest_sessionstart(session): + session._setupstate = SetupState() + +def pytest_sessionfinish(session, exitstatus): + hook = session.config.hook + rep = hook.pytest__teardown_final(session=session) + if rep: + hook.pytest__teardown_final_logerror(session=session, report=rep) + session.exitstatus = 1 + +class NodeInfo: + def __init__(self, location): + self.location = location + +def pytest_runtest_protocol(item): + item.ihook.pytest_runtest_logstart( + nodeid=item.nodeid, location=item.location, + ) + runtestprotocol(item) + return True + +def runtestprotocol(item, log=True): + rep = call_and_report(item, "setup", log) + reports = [rep] + if rep.passed: + reports.append(call_and_report(item, "call", log)) + reports.append(call_and_report(item, "teardown", log)) + return reports + +def pytest_runtest_setup(item): + item.session._setupstate.prepare(item) + +def pytest_runtest_call(item): + item.runtest() + +def pytest_runtest_teardown(item): + item.session._setupstate.teardown_exact(item) + +def pytest__teardown_final(session): + call = CallInfo(session._setupstate.teardown_all, when="teardown") + if call.excinfo: + ntraceback = call.excinfo.traceback .cut(excludepath=py._pydir) + call.excinfo.traceback = ntraceback.filter() + longrepr = call.excinfo.getrepr(funcargs=True) + return TeardownErrorReport(longrepr) + +def pytest_report_teststatus(report): + if report.when in ("setup", "teardown"): + if report.failed: + # category, shortletter, verbose-word + return "error", "E", "ERROR" + elif report.skipped: + return "skipped", "s", "SKIPPED" + else: + return "", "", "" + + +# +# Implementation + +def call_and_report(item, when, log=True): + call = call_runtest_hook(item, when) + hook = item.ihook + report = hook.pytest_runtest_makereport(item=item, call=call) + if log and (when == "call" or not report.passed): + hook.pytest_runtest_logreport(report=report) + return report + +def call_runtest_hook(item, when): + hookname = "pytest_runtest_" + when + ihook = getattr(item.ihook, hookname) + return CallInfo(lambda: ihook(item=item), when=when) + +class CallInfo: + """ Result/Exception info a function invocation. """ + #: None or ExceptionInfo object. + excinfo = None + def __init__(self, func, when): + #: context of invocation: one of "setup", "call", + #: "teardown", "memocollect" + self.when = when + try: + self.result = func() + except KeyboardInterrupt: + raise + except: + self.excinfo = py.code.ExceptionInfo() + + def __repr__(self): + if self.excinfo: + status = "exception: %s" % str(self.excinfo.value) + else: + status = "result: %r" % (self.result,) + return "" % (self.when, status) + +def getslaveinfoline(node): + try: + return node._slaveinfocache + except AttributeError: + d = node.slaveinfo + ver = "%s.%s.%s" % d['version_info'][:3] + node._slaveinfocache = s = "[%s] %s -- Python %s %s" % ( + d['id'], d['sysplatform'], ver, d['executable']) + return s + +class BaseReport(object): + def toterminal(self, out): + longrepr = self.longrepr + if hasattr(self, 'node'): + out.line(getslaveinfoline(self.node)) + if hasattr(longrepr, 'toterminal'): + longrepr.toterminal(out) + else: + out.line(str(longrepr)) + + passed = property(lambda x: x.outcome == "passed") + failed = property(lambda x: x.outcome == "failed") + skipped = property(lambda x: x.outcome == "skipped") + + @property + def fspath(self): + return self.nodeid.split("::")[0] + +def pytest_runtest_makereport(item, call): + when = call.when + keywords = dict([(x,1) for x in item.keywords]) + excinfo = call.excinfo + if not call.excinfo: + outcome = "passed" + longrepr = None + else: + excinfo = call.excinfo + if not isinstance(excinfo, py.code.ExceptionInfo): + outcome = "failed" + longrepr = excinfo + elif excinfo.errisinstance(py.test.skip.Exception): + outcome = "skipped" + r = excinfo._getreprcrash() + longrepr = (str(r.path), r.lineno, r.message) + else: + outcome = "failed" + if call.when == "call": + longrepr = item.repr_failure(excinfo) + else: # exception in setup or teardown + longrepr = item._repr_failure_py(excinfo) + return TestReport(item.nodeid, item.location, + keywords, outcome, longrepr, when) + +class TestReport(BaseReport): + """ Basic test report object (also used for setup and teardown calls if + they fail). + """ + def __init__(self, nodeid, location, + keywords, outcome, longrepr, when): + #: normalized collection node id + self.nodeid = nodeid + + #: a (filesystempath, lineno, domaininfo) tuple indicating the + #: actual location of a test item - it might be different from the + #: collected one e.g. if a method is inherited from a different module. + self.location = location + + #: a name -> value dictionary containing all keywords and + #: markers associated with a test invocation. + self.keywords = keywords + + #: test outcome, always one of "passed", "failed", "skipped". + self.outcome = outcome + + #: None or a failure representation. + self.longrepr = longrepr + + #: one of 'setup', 'call', 'teardown' to indicate runtest phase. + self.when = when + + def __repr__(self): + return "" % ( + self.nodeid, self.when, self.outcome) + +class TeardownErrorReport(BaseReport): + outcome = "failed" + when = "teardown" + def __init__(self, longrepr): + self.longrepr = longrepr + +def pytest_make_collect_report(collector): + call = CallInfo(collector._memocollect, "memocollect") + longrepr = None + if not call.excinfo: + outcome = "passed" + else: + if call.excinfo.errisinstance(py.test.skip.Exception): + outcome = "skipped" + r = collector._repr_failure_py(call.excinfo, "line").reprcrash + longrepr = (str(r.path), r.lineno, r.message) + else: + outcome = "failed" + errorinfo = collector.repr_failure(call.excinfo) + if not hasattr(errorinfo, "toterminal"): + errorinfo = CollectErrorRepr(errorinfo) + longrepr = errorinfo + return CollectReport(collector.nodeid, outcome, longrepr, + getattr(call, 'result', None)) + +class CollectReport(BaseReport): + def __init__(self, nodeid, outcome, longrepr, result): + self.nodeid = nodeid + self.outcome = outcome + self.longrepr = longrepr + self.result = result or [] + + @property + def location(self): + return (self.fspath, None, self.fspath) + + def __repr__(self): + return "" % ( + self.nodeid, len(self.result), self.outcome) + +class CollectErrorRepr(TerminalRepr): + def __init__(self, msg): + self.longrepr = msg + def toterminal(self, out): + out.line(str(self.longrepr), red=True) + +class SetupState(object): + """ shared state for setting up/tearing down test items or collectors. """ + def __init__(self): + self.stack = [] + self._finalizers = {} + + def addfinalizer(self, finalizer, colitem): + """ attach a finalizer to the given colitem. + if colitem is None, this will add a finalizer that + is called at the end of teardown_all(). + """ + assert hasattr(finalizer, '__call__') + #assert colitem in self.stack + self._finalizers.setdefault(colitem, []).append(finalizer) + + def _pop_and_teardown(self): + colitem = self.stack.pop() + self._teardown_with_finalization(colitem) + + def _callfinalizers(self, colitem): + finalizers = self._finalizers.pop(colitem, None) + while finalizers: + fin = finalizers.pop() + fin() + + def _teardown_with_finalization(self, colitem): + self._callfinalizers(colitem) + if colitem: + colitem.teardown() + for colitem in self._finalizers: + assert colitem is None or colitem in self.stack + + def teardown_all(self): + while self.stack: + self._pop_and_teardown() + self._teardown_with_finalization(None) + assert not self._finalizers + + def teardown_exact(self, item): + if self.stack and item == self.stack[-1]: + self._pop_and_teardown() + else: + self._callfinalizers(item) + + def prepare(self, colitem): + """ setup objects along the collector chain to the test-method + and teardown previously setup objects.""" + needed_collectors = colitem.listchain() + while self.stack: + if self.stack == needed_collectors[:len(self.stack)]: + break + self._pop_and_teardown() + # check if the last collection node has raised an error + for col in self.stack: + if hasattr(col, '_prepare_exc'): + py.builtin._reraise(*col._prepare_exc) + for col in needed_collectors[len(self.stack):]: + self.stack.append(col) + try: + col.setup() + except Exception: + col._prepare_exc = sys.exc_info() + raise + +# ============================================================= +# Test OutcomeExceptions and helpers for creating them. + + +class OutcomeException(Exception): + """ OutcomeException and its subclass instances indicate and + contain info about test and collection outcomes. + """ + def __init__(self, msg=None, pytrace=True): + self.msg = msg + self.pytrace = pytrace + + def __repr__(self): + if self.msg: + return str(self.msg) + return "<%s instance>" %(self.__class__.__name__,) + __str__ = __repr__ + +class Skipped(OutcomeException): + # XXX hackish: on 3k we fake to live in the builtins + # in order to have Skipped exception printing shorter/nicer + __module__ = 'builtins' + +class Failed(OutcomeException): + """ raised from an explicit call to py.test.fail() """ + __module__ = 'builtins' + +class Exit(KeyboardInterrupt): + """ raised for immediate program exits (no tracebacks/summaries)""" + def __init__(self, msg="unknown reason"): + self.msg = msg + KeyboardInterrupt.__init__(self, msg) + +# exposed helper methods + +def exit(msg): + """ exit testing process as if KeyboardInterrupt was triggered. """ + __tracebackhide__ = True + raise Exit(msg) + +exit.Exception = Exit + +def skip(msg=""): + """ skip an executing test with the given message. Note: it's usually + better to use the py.test.mark.skipif marker to declare a test to be + skipped under certain conditions like mismatching platforms or + dependencies. See the pytest_skipping plugin for details. + """ + __tracebackhide__ = True + raise Skipped(msg=msg) +skip.Exception = Skipped + +def fail(msg="", pytrace=True): + """ explicitely fail an currently-executing test with the given Message. + if @pytrace is not True the msg represents the full failure information. + """ + __tracebackhide__ = True + raise Failed(msg=msg, pytrace=pytrace) +fail.Exception = Failed + + +def importorskip(modname, minversion=None): + """ return imported module if it has a higher __version__ than the + optionally specified 'minversion' - otherwise call py.test.skip() + with a message detailing the mismatch. + """ + __tracebackhide__ = True + compile(modname, '', 'eval') # to catch syntaxerrors + try: + mod = __import__(modname, None, None, ['__doc__']) + except ImportError: + py.test.skip("could not import %r" %(modname,)) + if minversion is None: + return mod + verattr = getattr(mod, '__version__', None) + if isinstance(minversion, str): + minver = minversion.split(".") + else: + minver = list(minversion) + if verattr is None or verattr.split(".") < minver: + py.test.skip("module %r has __version__ %r, required is: %r" %( + modname, verattr, minversion)) + return mod diff --git a/lib/pypy/_pytest/skipping.py b/lib/pypy/_pytest/skipping.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/skipping.py @@ -0,0 +1,246 @@ +""" support for skip/xfail functions and markers. """ + +import py, pytest +import sys + +def pytest_addoption(parser): + group = parser.getgroup("general") + group.addoption('--runxfail', + action="store_true", dest="runxfail", default=False, + help="run tests even if they are marked xfail") + +def pytest_namespace(): + return dict(xfail=xfail) + +class XFailed(pytest.fail.Exception): + """ raised from an explicit call to py.test.xfail() """ + +def xfail(reason=""): + """ xfail an executing test or setup functions with the given reason.""" + __tracebackhide__ = True + raise XFailed(reason) +xfail.Exception = XFailed + +class MarkEvaluator: + def __init__(self, item, name): + self.item = item + self.name = name + + @property + def holder(self): + return self.item.keywords.get(self.name, None) + def __bool__(self): + return bool(self.holder) + __nonzero__ = __bool__ + + def wasvalid(self): + return not hasattr(self, 'exc') + + def istrue(self): + try: + return self._istrue() + except KeyboardInterrupt: + raise + except: + self.exc = sys.exc_info() + if isinstance(self.exc[1], SyntaxError): + msg = [" " * (self.exc[1].offset + 4) + "^",] + msg.append("SyntaxError: invalid syntax") + else: + msg = py.std.traceback.format_exception_only(*self.exc[:2]) + pytest.fail("Error evaluating %r expression\n" + " %s\n" + "%s" + %(self.name, self.expr, "\n".join(msg)), + pytrace=False) + + def _getglobals(self): + d = {'os': py.std.os, 'sys': py.std.sys, 'config': self.item.config} + func = self.item.obj + try: + d.update(func.__globals__) + except AttributeError: + d.update(func.func_globals) + return d + + def _istrue(self): + if self.holder: + d = self._getglobals() + if self.holder.args: + self.result = False + for expr in self.holder.args: + self.expr = expr + if isinstance(expr, str): + result = cached_eval(self.item.config, expr, d) + else: + pytest.fail("expression is not a string") + if result: + self.result = True + self.expr = expr + break + else: + self.result = True + return getattr(self, 'result', False) + + def get(self, attr, default=None): + return self.holder.kwargs.get(attr, default) + + def getexplanation(self): + expl = self.get('reason', None) + if not expl: + if not hasattr(self, 'expr'): + return "" + else: + return "condition: " + str(self.expr) + return expl + + +def pytest_runtest_setup(item): + if not isinstance(item, pytest.Function): + return + evalskip = MarkEvaluator(item, 'skipif') + if evalskip.istrue(): + py.test.skip(evalskip.getexplanation()) + item._evalxfail = MarkEvaluator(item, 'xfail') + check_xfail_no_run(item) + +def pytest_pyfunc_call(pyfuncitem): + check_xfail_no_run(pyfuncitem) + +def check_xfail_no_run(item): + if not item.config.option.runxfail: + evalxfail = item._evalxfail + if evalxfail.istrue(): + if not evalxfail.get('run', True): + py.test.xfail("[NOTRUN] " + evalxfail.getexplanation()) + +def pytest_runtest_makereport(__multicall__, item, call): + if not isinstance(item, pytest.Function): + return + if not (call.excinfo and + call.excinfo.errisinstance(py.test.xfail.Exception)): + evalxfail = getattr(item, '_evalxfail', None) + if not evalxfail: + return + if call.excinfo and call.excinfo.errisinstance(py.test.xfail.Exception): + if not item.config.getvalue("runxfail"): + rep = __multicall__.execute() + rep.keywords['xfail'] = "reason: " + call.excinfo.value.msg + rep.outcome = "skipped" + return rep + rep = __multicall__.execute() + evalxfail = item._evalxfail + if not item.config.option.runxfail: + if evalxfail.wasvalid() and evalxfail.istrue(): + if call.excinfo: + rep.outcome = "skipped" + rep.keywords['xfail'] = evalxfail.getexplanation() + elif call.when == "call": + rep.outcome = "failed" + rep.keywords['xfail'] = evalxfail.getexplanation() + return rep + if 'xfail' in rep.keywords: + del rep.keywords['xfail'] + return rep + +# called by terminalreporter progress reporting +def pytest_report_teststatus(report): + if 'xfail' in report.keywords: + if report.skipped: + return "xfailed", "x", "xfail" + elif report.failed: + return "xpassed", "X", "XPASS" + +# called by the terminalreporter instance/plugin +def pytest_terminal_summary(terminalreporter): + tr = terminalreporter + if not tr.reportchars: + #for name in "xfailed skipped failed xpassed": + # if not tr.stats.get(name, 0): + # tr.write_line("HINT: use '-r' option to see extra " + # "summary info about tests") + # break + return + + lines = [] + for char in tr.reportchars: + if char == "x": + show_xfailed(terminalreporter, lines) + elif char == "X": + show_xpassed(terminalreporter, lines) + elif char in "fF": + show_failed(terminalreporter, lines) + elif char in "sS": + show_skipped(terminalreporter, lines) + if lines: + tr._tw.sep("=", "short test summary info") + for line in lines: + tr._tw.line(line) + +def show_failed(terminalreporter, lines): + tw = terminalreporter._tw + failed = terminalreporter.stats.get("failed") + if failed: + for rep in failed: + pos = rep.nodeid + lines.append("FAIL %s" %(pos, )) + +def show_xfailed(terminalreporter, lines): + xfailed = terminalreporter.stats.get("xfailed") + if xfailed: + for rep in xfailed: + pos = rep.nodeid + reason = rep.keywords['xfail'] + lines.append("XFAIL %s" % (pos,)) + if reason: + lines.append(" " + str(reason)) + +def show_xpassed(terminalreporter, lines): + xpassed = terminalreporter.stats.get("xpassed") + if xpassed: + for rep in xpassed: + pos = rep.nodeid + reason = rep.keywords['xfail'] + lines.append("XPASS %s %s" %(pos, reason)) + +def cached_eval(config, expr, d): + if not hasattr(config, '_evalcache'): + config._evalcache = {} + try: + return config._evalcache[expr] + except KeyError: + #import sys + #print >>sys.stderr, ("cache-miss: %r" % expr) + exprcode = py.code.compile(expr, mode="eval") + config._evalcache[expr] = x = eval(exprcode, d) + return x + + +def folded_skips(skipped): + d = {} + for event in skipped: + key = event.longrepr + assert len(key) == 3, (event, key) + d.setdefault(key, []).append(event) + l = [] + for key, events in d.items(): + l.append((len(events),) + key) + return l + +def show_skipped(terminalreporter, lines): + tr = terminalreporter + skipped = tr.stats.get('skipped', []) + if skipped: + #if not tr.hasopt('skipped'): + # tr.write_line( + # "%d skipped tests, specify -rs for more info" % + # len(skipped)) + # return + fskips = folded_skips(skipped) + if fskips: + #tr.write_sep("_", "skipped test summary") + for num, fspath, lineno, reason in fskips: + if reason.startswith("Skipped: "): + reason = reason[9:] + lines.append("SKIP [%d] %s:%d: %s" % + (num, fspath, lineno, reason)) diff --git a/lib/pypy/_pytest/standalonetemplate.py b/lib/pypy/_pytest/standalonetemplate.py new file mode 100755 --- /dev/null +++ b/lib/pypy/_pytest/standalonetemplate.py @@ -0,0 +1,63 @@ +#! /usr/bin/env python + +sources = """ + at SOURCES@""" + +import sys +import base64 +import zlib +import imp + +class DictImporter(object): + def __init__(self, sources): + self.sources = sources + + def find_module(self, fullname, path=None): + if fullname in self.sources: + return self + if fullname + '.__init__' in self.sources: + return self + return None + + def load_module(self, fullname): + # print "load_module:", fullname + from types import ModuleType + try: + s = self.sources[fullname] + is_pkg = False + except KeyError: + s = self.sources[fullname + '.__init__'] + is_pkg = True + + co = compile(s, fullname, 'exec') + module = sys.modules.setdefault(fullname, ModuleType(fullname)) + module.__file__ = "%s/%s" % (__file__, fullname) + module.__loader__ = self + if is_pkg: + module.__path__ = [fullname] + + do_exec(co, module.__dict__) + return sys.modules[fullname] + + def get_source(self, name): + res = self.sources.get(name) + if res is None: + res = self.sources.get(name + '.__init__') + return res + +if __name__ == "__main__": + if sys.version_info >= (3, 0): + exec("def do_exec(co, loc): exec(co, loc)\n") + import pickle + sources = sources.encode("ascii") # ensure bytes + sources = pickle.loads(zlib.decompress(base64.decodebytes(sources))) + else: + import cPickle as pickle + exec("def do_exec(co, loc): exec co in loc\n") + sources = pickle.loads(zlib.decompress(base64.decodestring(sources))) + + importer = DictImporter(sources) + sys.meta_path.append(importer) + + entry = "@ENTRY@" + do_exec(entry, locals()) diff --git a/lib/pypy/_pytest/terminal.py b/lib/pypy/_pytest/terminal.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/terminal.py @@ -0,0 +1,451 @@ +""" terminal reporting of the full testing process. + +This is a good source for looking at the various reporting hooks. +""" +import pytest, py +import sys +import os + +def pytest_addoption(parser): + group = parser.getgroup("terminal reporting", "reporting", after="general") + group._addoption('-v', '--verbose', action="count", + dest="verbose", default=0, help="increase verbosity."), + group._addoption('-q', '--quiet', action="count", + dest="quiet", default=0, help="decreate verbosity."), + group._addoption('-r', + action="store", dest="reportchars", default=None, metavar="chars", + help="show extra test summary info as specified by chars (f)ailed, " + "(s)skipped, (x)failed, (X)passed.") + group._addoption('-l', '--showlocals', + action="store_true", dest="showlocals", default=False, + help="show locals in tracebacks (disabled by default).") + group._addoption('--report', + action="store", dest="report", default=None, metavar="opts", + help="(deprecated, use -r)") + group._addoption('--tb', metavar="style", + action="store", dest="tbstyle", default='long', + type="choice", choices=['long', 'short', 'no', 'line', 'native'], + help="traceback print mode (long/short/line/native/no).") + group._addoption('--fulltrace', + action="store_true", dest="fulltrace", default=False, + help="don't cut any tracebacks (default is to cut).") + +def pytest_configure(config): + config.option.verbose -= config.option.quiet + # we try hard to make printing resilient against + # later changes on FD level. + stdout = py.std.sys.stdout + if hasattr(os, 'dup') and hasattr(stdout, 'fileno'): + try: + newfd = os.dup(stdout.fileno()) + #print "got newfd", newfd + except ValueError: + pass + else: + stdout = os.fdopen(newfd, stdout.mode, 1) + config._toclose = stdout + reporter = TerminalReporter(config, stdout) + config.pluginmanager.register(reporter, 'terminalreporter') + if config.option.debug or config.option.traceconfig: + def mywriter(tags, args): + msg = " ".join(map(str, args)) + reporter.write_line("[traceconfig] " + msg) + config.trace.root.setprocessor("pytest:config", mywriter) + +def pytest_unconfigure(config): + if hasattr(config, '_toclose'): + #print "closing", config._toclose, config._toclose.fileno() + config._toclose.close() + +def getreportopt(config): + reportopts = "" + optvalue = config.option.report + if optvalue: + py.builtin.print_("DEPRECATED: use -r instead of --report option.", + file=py.std.sys.stderr) + if optvalue: + for setting in optvalue.split(","): + setting = setting.strip() + if setting == "skipped": + reportopts += "s" + elif setting == "xfailed": + reportopts += "x" + reportchars = config.option.reportchars + if reportchars: + for char in reportchars: + if char not in reportopts: + reportopts += char + return reportopts + +def pytest_report_teststatus(report): + if report.passed: + letter = "." + elif report.skipped: + letter = "s" + elif report.failed: + letter = "F" + if report.when != "call": + letter = "f" + return report.outcome, letter, report.outcome.upper() + +class TerminalReporter: + def __init__(self, config, file=None): + self.config = config + self.verbosity = self.config.option.verbose + self.showheader = self.verbosity >= 0 + self.showfspath = self.verbosity >= 0 + self.showlongtestinfo = self.verbosity > 0 + self._numcollected = 0 + + self.stats = {} + self.curdir = py.path.local() + if file is None: + file = py.std.sys.stdout + self._tw = py.io.TerminalWriter(file) + self.currentfspath = None + self.reportchars = getreportopt(config) + self.hasmarkup = self._tw.hasmarkup + + def hasopt(self, char): + char = {'xfailed': 'x', 'skipped': 's'}.get(char,char) + return char in self.reportchars + + def write_fspath_result(self, fspath, res): + if fspath != self.currentfspath: + self.currentfspath = fspath + #fspath = self.curdir.bestrelpath(fspath) + self._tw.line() + #relpath = self.curdir.bestrelpath(fspath) + self._tw.write(fspath + " ") + self._tw.write(res) + + def write_ensure_prefix(self, prefix, extra="", **kwargs): + if self.currentfspath != prefix: + self._tw.line() + self.currentfspath = prefix + self._tw.write(prefix) + if extra: + self._tw.write(extra, **kwargs) + self.currentfspath = -2 + + def ensure_newline(self): + if self.currentfspath: + self._tw.line() + self.currentfspath = None + + def write(self, content, **markup): + self._tw.write(content, **markup) + + def write_line(self, line, **markup): + line = str(line) + self.ensure_newline() + self._tw.line(line, **markup) + + def rewrite(self, line, **markup): + line = str(line) + self._tw.write("\r" + line, **markup) + + def write_sep(self, sep, title=None, **markup): + self.ensure_newline() + self._tw.sep(sep, title, **markup) + + def pytest_internalerror(self, excrepr): + for line in str(excrepr).split("\n"): + self.write_line("INTERNALERROR> " + line) + return 1 + + def pytest_plugin_registered(self, plugin): + if self.config.option.traceconfig: + msg = "PLUGIN registered: %s" %(plugin,) + # XXX this event may happen during setup/teardown time + # which unfortunately captures our output here + # which garbles our output if we use self.write_line + self.write_line(msg) + + def pytest_deselected(self, items): + self.stats.setdefault('deselected', []).extend(items) + + def pytest__teardown_final_logerror(self, report): + self.stats.setdefault("error", []).append(report) + + def pytest_runtest_logstart(self, nodeid, location): + # ensure that the path is printed before the + # 1st test of a module starts running + fspath = nodeid.split("::")[0] + if self.showlongtestinfo: + line = self._locationline(fspath, *location) + self.write_ensure_prefix(line, "") + elif self.showfspath: + self.write_fspath_result(fspath, "") + + def pytest_runtest_logreport(self, report): + rep = report + res = self.config.hook.pytest_report_teststatus(report=rep) + cat, letter, word = res + self.stats.setdefault(cat, []).append(rep) + if not letter and not word: + # probably passed setup/teardown + return + if self.verbosity <= 0: + if not hasattr(rep, 'node') and self.showfspath: + self.write_fspath_result(rep.fspath, letter) + else: + self._tw.write(letter) + else: + if isinstance(word, tuple): + word, markup = word + else: + if rep.passed: + markup = {'green':True} + elif rep.failed: + markup = {'red':True} + elif rep.skipped: + markup = {'yellow':True} + line = self._locationline(str(rep.fspath), *rep.location) + if not hasattr(rep, 'node'): + self.write_ensure_prefix(line, word, **markup) + #self._tw.write(word, **markup) + else: + self.ensure_newline() + if hasattr(rep, 'node'): + self._tw.write("[%s] " % rep.node.gateway.id) + self._tw.write(word, **markup) + self._tw.write(" " + line) + self.currentfspath = -2 + + def pytest_collection(self): + if not self.hasmarkup: + self.write("collecting ... ", bold=True) + + def pytest_collectreport(self, report): + if report.failed: + self.stats.setdefault("error", []).append(report) + elif report.skipped: + self.stats.setdefault("skipped", []).append(report) + items = [x for x in report.result if isinstance(x, pytest.Item)] + self._numcollected += len(items) + if self.hasmarkup: + #self.write_fspath_result(report.fspath, 'E') + self.report_collect() + + def report_collect(self, final=False): + errors = len(self.stats.get('error', [])) + skipped = len(self.stats.get('skipped', [])) + if final: + line = "collected " + else: + line = "collecting " + line += str(self._numcollected) + " items" + if errors: + line += " / %d errors" % errors + if skipped: + line += " / %d skipped" % skipped + if self.hasmarkup: + if final: + line += " \n" + self.rewrite(line, bold=True) + else: + self.write_line(line) + + def pytest_collection_modifyitems(self): + self.report_collect(True) + + def pytest_sessionstart(self, session): + self._sessionstarttime = py.std.time.time() + if not self.showheader: + return + self.write_sep("=", "test session starts", bold=True) + verinfo = ".".join(map(str, sys.version_info[:3])) + msg = "platform %s -- Python %s" % (sys.platform, verinfo) + if hasattr(sys, 'pypy_version_info'): + verinfo = ".".join(map(str, sys.pypy_version_info[:3])) + msg += "[pypy-%s]" % verinfo + msg += " -- pytest-%s" % (py.test.__version__) + if self.verbosity > 0 or self.config.option.debug or \ + getattr(self.config.option, 'pastebin', None): + msg += " -- " + str(sys.executable) + self.write_line(msg) + lines = self.config.hook.pytest_report_header(config=self.config) + lines.reverse() + for line in flatten(lines): + self.write_line(line) + + def pytest_collection_finish(self, session): + if self.config.option.collectonly: + self._printcollecteditems(session.items) + if self.stats.get('failed'): + self._tw.sep("!", "collection failures") + for rep in self.stats.get('failed'): + rep.toterminal(self._tw) + return 1 + return 0 + if not self.showheader: + return + #for i, testarg in enumerate(self.config.args): + # self.write_line("test path %d: %s" %(i+1, testarg)) + + def _printcollecteditems(self, items): + # to print out items and their parent collectors + # we take care to leave out Instances aka () + # because later versions are going to get rid of them anyway + if self.config.option.verbose < 0: + for item in items: + nodeid = item.nodeid + nodeid = nodeid.replace("::()::", "::") + self._tw.line(nodeid) + return + stack = [] + indent = "" + for item in items: + needed_collectors = item.listchain()[1:] # strip root node + while stack: + if stack == needed_collectors[:len(stack)]: + break + stack.pop() + for col in needed_collectors[len(stack):]: + stack.append(col) + #if col.name == "()": + # continue + indent = (len(stack)-1) * " " + self._tw.line("%s%s" %(indent, col)) + + def pytest_sessionfinish(self, exitstatus, __multicall__): + __multicall__.execute() + self._tw.line("") + if exitstatus in (0, 1, 2): + self.summary_errors() + self.summary_failures() + self.config.hook.pytest_terminal_summary(terminalreporter=self) + if exitstatus == 2: + self._report_keyboardinterrupt() + self.summary_deselected() + self.summary_stats() + + def pytest_keyboard_interrupt(self, excinfo): + self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True) + + def _report_keyboardinterrupt(self): + excrepr = self._keyboardinterrupt_memo + msg = excrepr.reprcrash.message + self.write_sep("!", msg) + if "KeyboardInterrupt" in msg: + if self.config.option.fulltrace: + excrepr.toterminal(self._tw) + else: + excrepr.reprcrash.toterminal(self._tw) + + def _locationline(self, collect_fspath, fspath, lineno, domain): + # collect_fspath comes from testid which has a "/"-normalized path + if fspath and fspath.replace("\\", "/") != collect_fspath: + fspath = "%s <- %s" % (collect_fspath, fspath) + if fspath: + line = str(fspath) + if lineno is not None: + lineno += 1 + line += ":" + str(lineno) + if domain: + line += ": " + str(domain) + else: + line = "[location]" + return line + " " + + def _getfailureheadline(self, rep): + if hasattr(rep, 'location'): + fspath, lineno, domain = rep.location + return domain + else: + return "test session" # XXX? + + def _getcrashline(self, rep): + try: + return str(rep.longrepr.reprcrash) + except AttributeError: + try: + return str(rep.longrepr)[:50] + except AttributeError: + return "" + + # + # summaries for sessionfinish + # + def getreports(self, name): + l = [] + for x in self.stats.get(name, []): + if not hasattr(x, '_pdbshown'): + l.append(x) + return l + + def summary_failures(self): + if self.config.option.tbstyle != "no": + reports = self.getreports('failed') + if not reports: + return + self.write_sep("=", "FAILURES") + for rep in reports: + if self.config.option.tbstyle == "line": + line = self._getcrashline(rep) + self.write_line(line) + else: + msg = self._getfailureheadline(rep) + self.write_sep("_", msg) + rep.toterminal(self._tw) + + def summary_errors(self): + if self.config.option.tbstyle != "no": + reports = self.getreports('error') + if not reports: + return + self.write_sep("=", "ERRORS") + for rep in self.stats['error']: + msg = self._getfailureheadline(rep) + if not hasattr(rep, 'when'): + # collect + msg = "ERROR collecting " + msg + elif rep.when == "setup": + msg = "ERROR at setup of " + msg + elif rep.when == "teardown": + msg = "ERROR at teardown of " + msg + self.write_sep("_", msg) + rep.toterminal(self._tw) + + def summary_stats(self): + session_duration = py.std.time.time() - self._sessionstarttime + + keys = "failed passed skipped deselected".split() + for key in self.stats.keys(): + if key not in keys: + keys.append(key) + parts = [] + for key in keys: + val = self.stats.get(key, None) + if val: + parts.append("%d %s" %(len(val), key)) + line = ", ".join(parts) + # XXX coloring + msg = "%s in %.2f seconds" %(line, session_duration) + if self.verbosity >= 0: + self.write_sep("=", msg, bold=True) + else: + self.write_line(msg, bold=True) + + def summary_deselected(self): + if 'deselected' in self.stats: + self.write_sep("=", "%d tests deselected by %r" %( + len(self.stats['deselected']), self.config.option.keyword), bold=True) + +def repr_pythonversion(v=None): + if v is None: + v = sys.version_info + try: + return "%s.%s.%s-%s-%s" % v + except (TypeError, ValueError): + return str(v) + +def flatten(l): + for x in l: + if isinstance(x, (list, tuple)): + for y in flatten(x): + yield y + else: + yield x + diff --git a/lib/pypy/_pytest/tmpdir.py b/lib/pypy/_pytest/tmpdir.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/tmpdir.py @@ -0,0 +1,68 @@ +""" support for providing temporary directories to test functions. """ +import pytest, py +from _pytest.monkeypatch import monkeypatch + +class TempdirHandler: + def __init__(self, config): + self.config = config + self.trace = config.trace.get("tmpdir") + + def ensuretemp(self, string, dir=1): + """ (deprecated) return temporary directory path with + the given string as the trailing part. It is usually + better to use the 'tmpdir' function argument which + provides an empty unique-per-test-invocation directory + and is guaranteed to be empty. + """ + #py.log._apiwarn(">1.1", "use tmpdir function argument") + return self.getbasetemp().ensure(string, dir=dir) + + def mktemp(self, basename, numbered=True): + basetemp = self.getbasetemp() + if not numbered: + p = basetemp.mkdir(basename) + else: + p = py.path.local.make_numbered_dir(prefix=basename, + keep=0, rootdir=basetemp, lock_timeout=None) + self.trace("mktemp", p) + return p + + def getbasetemp(self): + """ return base temporary directory. """ + try: + return self._basetemp + except AttributeError: + basetemp = self.config.option.basetemp + if basetemp: + basetemp = py.path.local(basetemp) + if basetemp.check(): + basetemp.remove() + basetemp.mkdir() + else: + basetemp = py.path.local.make_numbered_dir(prefix='pytest-') + self._basetemp = t = basetemp + self.trace("new basetemp", t) + return t + + def finish(self): + self.trace("finish") + +def pytest_configure(config): + mp = monkeypatch() + t = TempdirHandler(config) + config._cleanup.extend([mp.undo, t.finish]) + mp.setattr(config, '_tmpdirhandler', t, raising=False) + mp.setattr(pytest, 'ensuretemp', t.ensuretemp, raising=False) + +def pytest_funcarg__tmpdir(request): + """return a temporary directory path object + which is unique to each test function invocation, + created as a sub directory of the base temporary + directory. The returned object is a `py.path.local`_ + path object. + """ + name = request._pyfuncitem.name + name = py.std.re.sub("[\W]", "_", name) + x = request.config._tmpdirhandler.mktemp(name, numbered=True) + return x.realpath() + diff --git a/lib/pypy/_pytest/unittest.py b/lib/pypy/_pytest/unittest.py new file mode 100644 --- /dev/null +++ b/lib/pypy/_pytest/unittest.py @@ -0,0 +1,143 @@ +""" discovery and running of std-library "unittest" style tests. """ +import pytest, py +import sys, pdb + +def pytest_pycollect_makeitem(collector, name, obj): + unittest = sys.modules.get('unittest') + if unittest is None: + return # nobody can have derived unittest.TestCase + try: + isunit = issubclass(obj, unittest.TestCase) + except KeyboardInterrupt: + raise + except Exception: + pass + else: + if isunit: + return UnitTestCase(name, parent=collector) + +class UnitTestCase(pytest.Class): + def collect(self): + loader = py.std.unittest.TestLoader() + for name in loader.getTestCaseNames(self.obj): + yield TestCaseFunction(name, parent=self) + + def setup(self): + meth = getattr(self.obj, 'setUpClass', None) + if meth is not None: + meth() + super(UnitTestCase, self).setup() + + def teardown(self): + meth = getattr(self.obj, 'tearDownClass', None) + if meth is not None: + meth() + super(UnitTestCase, self).teardown() + +class TestCaseFunction(pytest.Function): + _excinfo = None + + def __init__(self, name, parent): + super(TestCaseFunction, self).__init__(name, parent) + if hasattr(self._obj, 'todo'): + getattr(self._obj, 'im_func', self._obj).xfail = \ + pytest.mark.xfail(reason=str(self._obj.todo)) + + def setup(self): + self._testcase = self.parent.obj(self.name) + self._obj = getattr(self._testcase, self.name) + if hasattr(self._testcase, 'setup_method'): + self._testcase.setup_method(self._obj) + + def teardown(self): + if hasattr(self._testcase, 'teardown_method'): + self._testcase.teardown_method(self._obj) + + def startTest(self, testcase): + pass + + def _addexcinfo(self, rawexcinfo): + # unwrap potential exception info (see twisted trial support below) + rawexcinfo = getattr(rawexcinfo, '_rawexcinfo', rawexcinfo) + try: + excinfo = py.code.ExceptionInfo(rawexcinfo) + except TypeError: + try: + try: + l = py.std.traceback.format_exception(*rawexcinfo) + l.insert(0, "NOTE: Incompatible Exception Representation, " + "displaying natively:\n\n") + pytest.fail("".join(l), pytrace=False) + except (pytest.fail.Exception, KeyboardInterrupt): + raise + except: + pytest.fail("ERROR: Unknown Incompatible Exception " + "representation:\n%r" %(rawexcinfo,), pytrace=False) + except KeyboardInterrupt: + raise + except pytest.fail.Exception: + excinfo = py.code.ExceptionInfo() + self.__dict__.setdefault('_excinfo', []).append(excinfo) + + def addError(self, testcase, rawexcinfo): + self._addexcinfo(rawexcinfo) + def addFailure(self, testcase, rawexcinfo): + self._addexcinfo(rawexcinfo) + def addSkip(self, testcase, reason): + try: + pytest.skip(reason) + except pytest.skip.Exception: + self._addexcinfo(sys.exc_info()) + def addExpectedFailure(self, testcase, rawexcinfo, reason): + try: + pytest.xfail(str(reason)) + except pytest.xfail.Exception: + self._addexcinfo(sys.exc_info()) + def addUnexpectedSuccess(self, testcase, reason): + pass + def addSuccess(self, testcase): + pass + def stopTest(self, testcase): + pass + def runtest(self): + self._testcase(result=self) + + def _prunetraceback(self, excinfo): + pytest.Function._prunetraceback(self, excinfo) + excinfo.traceback = excinfo.traceback.filter(lambda x:not x.frame.f_globals.get('__unittest')) + + at pytest.mark.tryfirst +def pytest_runtest_makereport(item, call): + if isinstance(item, TestCaseFunction): + if item._excinfo: + call.excinfo = item._excinfo.pop(0) + del call.result + +# twisted trial support +def pytest_runtest_protocol(item, __multicall__): + if isinstance(item, TestCaseFunction): + if 'twisted.trial.unittest' in sys.modules: + ut = sys.modules['twisted.python.failure'] + Failure__init__ = ut.Failure.__init__.im_func + check_testcase_implements_trial_reporter() + def excstore(self, exc_value=None, exc_type=None, exc_tb=None): + if exc_value is None: + self._rawexcinfo = sys.exc_info() + else: + if exc_type is None: + exc_type = type(exc_value) + self._rawexcinfo = (exc_type, exc_value, exc_tb) + Failure__init__(self, exc_value, exc_type, exc_tb) + ut.Failure.__init__ = excstore + try: + return __multicall__.execute() + finally: + ut.Failure.__init__ = Failure__init__ + +def check_testcase_implements_trial_reporter(done=[]): + if done: + return + from zope.interface import classImplements + from twisted.trial.itrial import IReporter + classImplements(TestCaseFunction, IReporter) + done.append(1) diff --git a/lib/pypy/ctypes_configure/__init__.py b/lib/pypy/ctypes_configure/__init__.py new file mode 100644 diff --git a/lib/pypy/ctypes_configure/cbuild.py b/lib/pypy/ctypes_configure/cbuild.py new file mode 100644 --- /dev/null +++ b/lib/pypy/ctypes_configure/cbuild.py @@ -0,0 +1,456 @@ + +import os, sys, inspect, re, imp, py +from ctypes_configure import stdoutcapture +import distutils + +debug = 0 + +configdir = py.path.local.make_numbered_dir(prefix='ctypes_configure-') + +class ExternalCompilationInfo(object): + + _ATTRIBUTES = ['pre_include_lines', 'includes', 'include_dirs', + 'post_include_lines', 'libraries', 'library_dirs', + 'separate_module_sources', 'separate_module_files'] + _AVOID_DUPLICATES = ['separate_module_files', 'libraries', 'includes', + 'include_dirs', 'library_dirs', 'separate_module_sources'] + + def __init__(self, + pre_include_lines = [], + includes = [], + include_dirs = [], + post_include_lines = [], + libraries = [], + library_dirs = [], + separate_module_sources = [], + separate_module_files = []): + """ + pre_include_lines: list of lines that should be put at the top + of the generated .c files, before any #include. They shouldn't + contain an #include themselves. + + includes: list of .h file names to be #include'd from the + generated .c files. + + include_dirs: list of dir names that is passed to the C compiler + + post_include_lines: list of lines that should be put at the top + of the generated .c files, after the #includes. + + libraries: list of library names that is passed to the linker + + library_dirs: list of dir names that is passed to the linker + + separate_module_sources: list of multiline strings that are + each written to a .c file and compiled separately and linked + later on. (If function prototypes are needed for other .c files + to access this, they can be put in post_include_lines.) + + separate_module_files: list of .c file names that are compiled + separately and linked later on. (If an .h file is needed for + other .c files to access this, it can be put in includes.) + """ + for name in self._ATTRIBUTES: + value = locals()[name] + assert isinstance(value, (list, tuple)) + setattr(self, name, tuple(value)) + + def _value(self): + return tuple([getattr(self, x) for x in self._ATTRIBUTES]) + + def __hash__(self): + return hash(self._value()) + + def __eq__(self, other): + return self.__class__ is other.__class__ and \ + self._value() == other._value() + + def __ne__(self, other): + return not self == other + + def __repr__(self): + info = [] + for attr in self._ATTRIBUTES: + val = getattr(self, attr) + info.append("%s=%s" % (attr, repr(val))) + return "" % ", ".join(info) + + def merge(self, *others): + others = list(others) + attrs = {} + for name in self._ATTRIBUTES: + if name not in self._AVOID_DUPLICATES: + s = [] + for i in [self] + others: + s += getattr(i, name) + attrs[name] = s + else: + s = set() + attr = [] + for one in [self] + others: + for elem in getattr(one, name): + if elem not in s: + s.add(elem) + attr.append(elem) + attrs[name] = attr + return ExternalCompilationInfo(**attrs) + + def write_c_header(self, fileobj): + for line in self.pre_include_lines: + print >> fileobj, line + for path in self.includes: + print >> fileobj, '#include <%s>' % (path,) + for line in self.post_include_lines: + print >> fileobj, line + + def _copy_attributes(self): + d = {} + for attr in self._ATTRIBUTES: + d[attr] = getattr(self, attr) + return d + + def convert_sources_to_files(self, cache_dir=None, being_main=False): + if not self.separate_module_sources: + return self + if cache_dir is None: + cache_dir = configdir.join('module_cache').ensure(dir=1) + num = 0 + files = [] + for source in self.separate_module_sources: + while 1: + filename = cache_dir.join('module_%d.c' % num) + num += 1 + if not filename.check(): + break + f = filename.open("w") + if being_main: + f.write("#define PYPY_NOT_MAIN_FILE\n") + self.write_c_header(f) + source = str(source) + f.write(source) + if not source.endswith('\n'): + f.write('\n') + f.close() + files.append(str(filename)) + d = self._copy_attributes() + d['separate_module_sources'] = () + d['separate_module_files'] += tuple(files) + return ExternalCompilationInfo(**d) + + def compile_shared_lib(self): + self = self.convert_sources_to_files() + if not self.separate_module_files: + return self + lib = compile_c_module([], 'externmod', self) + d = self._copy_attributes() + d['libraries'] += (lib,) + d['separate_module_files'] = () + d['separate_module_sources'] = () + return ExternalCompilationInfo(**d) + +if sys.platform == 'win32': + so_ext = '.dll' +else: + so_ext = '.so' + +def compiler_command(): + # e.g. for tcc, you might set this to + # "tcc -shared -o %s.so %s.c" + return os.getenv('PYPY_CC') + +def enable_fast_compilation(): + if sys.platform == 'win32': + dash = '/' + else: + dash = '-' + from distutils import sysconfig + gcv = sysconfig.get_config_vars() + opt = gcv.get('OPT') # not always existent + if opt: + opt = re.sub('%sO\d+' % dash, '%sO0' % dash, opt) + else: + opt = '%sO0' % dash + gcv['OPT'] = opt + +def ensure_correct_math(): + if sys.platform != 'win32': + return # so far + from distutils import sysconfig + gcv = sysconfig.get_config_vars() + opt = gcv.get('OPT') # not always existent + if opt and '/Op' not in opt: + opt += '/Op' + gcv['OPT'] = opt + + +def try_compile(c_files, eci): + try: + build_executable(c_files, eci) + result = True + except (distutils.errors.CompileError, + distutils.errors.LinkError): + result = False + return result + +def compile_c_module(cfiles, modbasename, eci, tmpdir=None): + #try: + # from distutils.log import set_threshold + # set_threshold(10000) + #except ImportError: + # print "ERROR IMPORTING" + # pass + cfiles = [py.path.local(f) for f in cfiles] + if tmpdir is None: + tmpdir = configdir.join("module_cache").ensure(dir=1) + num = 0 + cfiles += eci.separate_module_files + include_dirs = list(eci.include_dirs) + library_dirs = list(eci.library_dirs) + if sys.platform == 'darwin': # support Fink & Darwinports + for s in ('/sw/', '/opt/local/'): + if s + 'include' not in include_dirs and \ + os.path.exists(s + 'include'): + include_dirs.append(s + 'include') + if s + 'lib' not in library_dirs and \ + os.path.exists(s + 'lib'): + library_dirs.append(s + 'lib') + + num = 0 + modname = modbasename + while 1: + if not tmpdir.join(modname + so_ext).check(): + break + num += 1 + modname = '%s_%d' % (modbasename, num) + + lastdir = tmpdir.chdir() + libraries = eci.libraries + ensure_correct_math() + try: + if debug: print "modname", modname + c = stdoutcapture.Capture(mixed_out_err = True) + try: + try: + if compiler_command(): + # GCC-ish options only + from distutils import sysconfig + gcv = sysconfig.get_config_vars() + cmd = compiler_command().replace('%s', + str(tmpdir.join(modname))) + for dir in [gcv['INCLUDEPY']] + list(include_dirs): + cmd += ' -I%s' % dir + for dir in library_dirs: + cmd += ' -L%s' % dir + os.system(cmd) + else: + from distutils.dist import Distribution + from distutils.extension import Extension + from distutils.ccompiler import get_default_compiler + saved_environ = os.environ.items() + try: + # distutils.core.setup() is really meant for end-user + # interactive usage, because it eats most exceptions and + # turn them into SystemExits. Instead, we directly + # instantiate a Distribution, which also allows us to + # ignore unwanted features like config files. + extra_compile_args = [] + # ensure correct math on windows + if sys.platform == 'win32': + extra_compile_args.append('/Op') # get extra precision + if get_default_compiler() == 'unix': + old_version = False + try: + g = os.popen('gcc --version', 'r') + verinfo = g.read() + g.close() + except (OSError, IOError): + pass + else: + old_version = verinfo.startswith('2') + if not old_version: + extra_compile_args.extend(["-Wno-unused-label", + "-Wno-unused-variable"]) + attrs = { + 'name': "testmodule", + 'ext_modules': [ + Extension(modname, [str(cfile) for cfile in cfiles], + include_dirs=include_dirs, + library_dirs=library_dirs, + extra_compile_args=extra_compile_args, + libraries=list(libraries),) + ], + 'script_name': 'setup.py', + 'script_args': ['-q', 'build_ext', '--inplace', '--force'], + } + dist = Distribution(attrs) + if not dist.parse_command_line(): + raise ValueError, "distutils cmdline parse error" + dist.run_commands() + finally: + for key, value in saved_environ: + if os.environ.get(key) != value: + os.environ[key] = value + finally: + foutput, foutput = c.done() + data = foutput.read() + if data: + fdump = open("%s.errors" % modname, "w") + fdump.write(data) + fdump.close() + # XXX do we need to do some check on fout/ferr? + # XXX not a nice way to import a module + except: + print >>sys.stderr, data + raise + finally: + lastdir.chdir() + return str(tmpdir.join(modname) + so_ext) + +def make_module_from_c(cfile, eci): + cfile = py.path.local(cfile) + modname = cfile.purebasename + compile_c_module([cfile], modname, eci) + return import_module_from_directory(cfile.dirpath(), modname) + +def import_module_from_directory(dir, modname): + file, pathname, description = imp.find_module(modname, [str(dir)]) + try: + mod = imp.load_module(modname, file, pathname, description) + finally: + if file: + file.close() + return mod + + +def log_spawned_cmd(spawn): + def spawn_and_log(cmd, *args, **kwds): + if debug: + print ' '.join(cmd) + return spawn(cmd, *args, **kwds) + return spawn_and_log + + +class ProfOpt(object): + #XXX assuming gcc style flags for now + name = "profopt" + + def __init__(self, compiler): + self.compiler = compiler + + def first(self): + self.build('-fprofile-generate') + + def probe(self, exe, args): + # 'args' is a single string typically containing spaces + # and quotes, which represents several arguments. + os.system("'%s' %s" % (exe, args)) + + def after(self): + self.build('-fprofile-use') + + def build(self, option): + compiler = self.compiler + compiler.compile_extra.append(option) + compiler.link_extra.append(option) + try: + compiler._build() + finally: + compiler.compile_extra.pop() + compiler.link_extra.pop() + +class CCompiler: + + def __init__(self, cfilenames, eci, outputfilename=None, + compiler_exe=None, profbased=None): + self.cfilenames = cfilenames + ext = '' + self.compile_extra = [] + self.link_extra = [] + self.libraries = list(eci.libraries) + self.include_dirs = list(eci.include_dirs) + self.library_dirs = list(eci.library_dirs) + self.compiler_exe = compiler_exe + self.profbased = profbased + if not sys.platform in ('win32', 'darwin'): # xxx + if 'm' not in self.libraries: + self.libraries.append('m') + if 'pthread' not in self.libraries: + self.libraries.append('pthread') + self.compile_extra += ['-O3', '-fomit-frame-pointer', '-pthread'] + self.link_extra += ['-pthread'] + if sys.platform == 'win32': + self.link_extra += ['/DEBUG'] # generate .pdb file + if sys.platform == 'darwin': + # support Fink & Darwinports + for s in ('/sw/', '/opt/local/'): + if s + 'include' not in self.include_dirs and \ + os.path.exists(s + 'include'): + self.include_dirs.append(s + 'include') + if s + 'lib' not in self.library_dirs and \ + os.path.exists(s + 'lib'): + self.library_dirs.append(s + 'lib') + self.compile_extra += ['-O3', '-fomit-frame-pointer'] + + if outputfilename is None: + self.outputfilename = py.path.local(cfilenames[0]).new(ext=ext) + else: + self.outputfilename = py.path.local(outputfilename) + self.eci = eci + + def build(self, noerr=False): + basename = self.outputfilename.new(ext='') + data = '' + try: + saved_environ = os.environ.copy() + c = stdoutcapture.Capture(mixed_out_err = True) + try: + self._build() + finally: + # workaround for a distutils bugs where some env vars can + # become longer and longer every time it is used + for key, value in saved_environ.items(): + if os.environ.get(key) != value: + os.environ[key] = value + foutput, foutput = c.done() + data = foutput.read() + if data: + fdump = basename.new(ext='errors').open("w") + fdump.write(data) + fdump.close() + except: + if not noerr: + print >>sys.stderr, data + raise + + def _build(self): + from distutils.ccompiler import new_compiler + compiler = new_compiler(force=1) + if self.compiler_exe is not None: + for c in '''compiler compiler_so compiler_cxx + linker_exe linker_so'''.split(): + compiler.executables[c][0] = self.compiler_exe + compiler.spawn = log_spawned_cmd(compiler.spawn) + objects = [] + for cfile in self.cfilenames: + cfile = py.path.local(cfile) + old = cfile.dirpath().chdir() + try: + res = compiler.compile([cfile.basename], + include_dirs=self.eci.include_dirs, + extra_preargs=self.compile_extra) + assert len(res) == 1 + cobjfile = py.path.local(res[0]) + assert cobjfile.check() + objects.append(str(cobjfile)) + finally: + old.chdir() + compiler.link_executable(objects, str(self.outputfilename), + libraries=self.eci.libraries, + extra_preargs=self.link_extra, + library_dirs=self.eci.library_dirs) + +def build_executable(*args, **kwds): + noerr = kwds.pop('noerr', False) + compiler = CCompiler(*args, **kwds) + compiler.build(noerr=noerr) + return str(compiler.outputfilename) diff --git a/lib/pypy/ctypes_configure/configure.py b/lib/pypy/ctypes_configure/configure.py new file mode 100755 --- /dev/null +++ b/lib/pypy/ctypes_configure/configure.py @@ -0,0 +1,619 @@ +#! /usr/bin/env python + +import os, py, sys +import ctypes +from ctypes_configure.cbuild import build_executable, configdir, try_compile +from ctypes_configure.cbuild import ExternalCompilationInfo +import distutils + +# ____________________________________________________________ +# +# Helpers for simple cases + +def eci_from_header(c_header_source): + return ExternalCompilationInfo( + pre_include_lines=c_header_source.split("\n") + ) + + +def getstruct(name, c_header_source, interesting_fields): + class CConfig: + _compilation_info_ = eci_from_header(c_header_source) + STRUCT = Struct(name, interesting_fields) + return configure(CConfig)['STRUCT'] + +def getsimpletype(name, c_header_source, ctype_hint=ctypes.c_int): + class CConfig: + _compilation_info_ = eci_from_header(c_header_source) + TYPE = SimpleType(name, ctype_hint) + return configure(CConfig)['TYPE'] + +def getconstantinteger(name, c_header_source): + class CConfig: + _compilation_info_ = eci_from_header(c_header_source) + CONST = ConstantInteger(name) + return configure(CConfig)['CONST'] + +def getdefined(macro, c_header_source): + class CConfig: + _compilation_info_ = eci_from_header(c_header_source) + DEFINED = Defined(macro) + return configure(CConfig)['DEFINED'] + +def has(name, c_header_source): + class CConfig: + _compilation_info_ = eci_from_header(c_header_source) + HAS = Has(name) + return configure(CConfig)['HAS'] + +def check_eci(eci): + """Check if a given ExternalCompilationInfo compiles and links.""" + class CConfig: + _compilation_info_ = eci + WORKS = Works() + return configure(CConfig)['WORKS'] + +def sizeof(name, eci, **kwds): + class CConfig: + _compilation_info_ = eci + SIZE = SizeOf(name) + for k, v in kwds.items(): + setattr(CConfig, k, v) + return configure(CConfig)['SIZE'] + +def memory_alignment(): + """Return the alignment (in bytes) of memory allocations. + This is enough to make sure a structure with pointers and 'double' + fields is properly aligned.""" + global _memory_alignment + if _memory_alignment is None: + S = getstruct('struct memory_alignment_test', """ + struct memory_alignment_test { + double d; + void* p; + }; + """, []) + result = ctypes.alignment(S) + assert result & (result-1) == 0, "not a power of two??" + _memory_alignment = result + return _memory_alignment +_memory_alignment = None + +# ____________________________________________________________ +# +# General interface + +class ConfigResult: + def __init__(self, CConfig, info, entries): + self.CConfig = CConfig + self.result = {} + self.info = info + self.entries = entries + + def get_entry_result(self, entry): + try: + return self.result[entry] + except KeyError: + pass + name = self.entries[entry] + info = self.info[name] + self.result[entry] = entry.build_result(info, self) + + def get_result(self): + return dict([(name, self.result[entry]) + for entry, name in self.entries.iteritems()]) + + +class _CWriter(object): + """ A simple class which aggregates config parts + """ + def __init__(self, CConfig): + self.path = uniquefilepath() + self.f = self.path.open("w") + self.config = CConfig + + def write_header(self): + f = self.f + CConfig = self.config + CConfig._compilation_info_.write_c_header(f) + print >> f, C_HEADER + print >> f + + def write_entry(self, key, entry): + f = self.f + print >> f, 'void dump_section_%s(void) {' % (key,) + for line in entry.prepare_code(): + if line and line[0] != '#': + line = '\t' + line + print >> f, line + print >> f, '}' + print >> f + + def write_entry_main(self, key): + print >> self.f, '\tprintf("-+- %s\\n");' % (key,) + print >> self.f, '\tdump_section_%s();' % (key,) + print >> self.f, '\tprintf("---\\n");' + + def start_main(self): + print >> self.f, 'int main(int argc, char *argv[]) {' + + def close(self): + f = self.f + print >> f, '\treturn 0;' + print >> f, '}' + f.close() + + def ask_gcc(self, question): + self.start_main() + self.f.write(question + "\n") + self.close() + eci = self.config._compilation_info_ + return try_compile([self.path], eci) + + +def configure(CConfig, noerr=False): + """Examine the local system by running the C compiler. + The CConfig class contains CConfigEntry attribues that describe + what should be inspected; configure() returns a dict mapping + names to the results. + """ + for attr in ['_includes_', '_libraries_', '_sources_', '_library_dirs_', + '_include_dirs_', '_header_']: + assert not hasattr(CConfig, attr), "Found legacy attribut %s on CConfig" % (attr,) + entries = [] + for key in dir(CConfig): + value = getattr(CConfig, key) + if isinstance(value, CConfigEntry): + entries.append((key, value)) + + if entries: # can be empty if there are only CConfigSingleEntries + writer = _CWriter(CConfig) + writer.write_header() + for key, entry in entries: + writer.write_entry(key, entry) + + f = writer.f + writer.start_main() + for key, entry in entries: + writer.write_entry_main(key) + writer.close() + + eci = CConfig._compilation_info_ + infolist = list(run_example_code(writer.path, eci, noerr=noerr)) + assert len(infolist) == len(entries) + + resultinfo = {} + resultentries = {} + for info, (key, entry) in zip(infolist, entries): + resultinfo[key] = info + resultentries[entry] = key + + result = ConfigResult(CConfig, resultinfo, resultentries) + for name, entry in entries: + result.get_entry_result(entry) + res = result.get_result() + else: + res = {} + + for key in dir(CConfig): + value = getattr(CConfig, key) + if isinstance(value, CConfigSingleEntry): + writer = _CWriter(CConfig) + writer.write_header() + res[key] = value.question(writer.ask_gcc) + return res + +# ____________________________________________________________ + + +class CConfigEntry(object): + "Abstract base class." + +class Struct(CConfigEntry): + """An entry in a CConfig class that stands for an externally + defined structure. + """ + def __init__(self, name, interesting_fields, ifdef=None): + self.name = name + self.interesting_fields = interesting_fields + self.ifdef = ifdef + + def prepare_code(self): + if self.ifdef is not None: + yield '#ifdef %s' % (self.ifdef,) + yield 'typedef %s ctypesplatcheck_t;' % (self.name,) + yield 'typedef struct {' + yield ' char c;' + yield ' ctypesplatcheck_t s;' + yield '} ctypesplatcheck2_t;' + yield '' + yield 'ctypesplatcheck_t s;' + if self.ifdef is not None: + yield 'dump("defined", 1);' + yield 'dump("align", offsetof(ctypesplatcheck2_t, s));' + yield 'dump("size", sizeof(ctypesplatcheck_t));' + for fieldname, fieldtype in self.interesting_fields: + yield 'dump("fldofs %s", offsetof(ctypesplatcheck_t, %s));'%( + fieldname, fieldname) + yield 'dump("fldsize %s", sizeof(s.%s));' % ( + fieldname, fieldname) + if fieldtype in integer_class: + yield 's.%s = 0; s.%s = ~s.%s;' % (fieldname, + fieldname, + fieldname) + yield 'dump("fldunsigned %s", s.%s > 0);' % (fieldname, + fieldname) + if self.ifdef is not None: + yield '#else' + yield 'dump("defined", 0);' + yield '#endif' + + def build_result(self, info, config_result): + if self.ifdef is not None: + if not info['defined']: + return None + alignment = 1 + layout = [None] * info['size'] + for fieldname, fieldtype in self.interesting_fields: + if isinstance(fieldtype, Struct): + offset = info['fldofs ' + fieldname] + size = info['fldsize ' + fieldname] + c_fieldtype = config_result.get_entry_result(fieldtype) + layout_addfield(layout, offset, c_fieldtype, fieldname) + alignment = max(alignment, ctype_alignment(c_fieldtype)) + else: + offset = info['fldofs ' + fieldname] + size = info['fldsize ' + fieldname] + sign = info.get('fldunsigned ' + fieldname, False) + if (size, sign) != size_and_sign(fieldtype): + fieldtype = fixup_ctype(fieldtype, fieldname, (size, sign)) + layout_addfield(layout, offset, fieldtype, fieldname) + alignment = max(alignment, ctype_alignment(fieldtype)) + + # try to enforce the same alignment as the one of the original + # structure + if alignment < info['align']: + choices = [ctype for ctype in alignment_types + if ctype_alignment(ctype) == info['align']] + assert choices, "unsupported alignment %d" % (info['align'],) + choices = [(ctypes.sizeof(ctype), i, ctype) + for i, ctype in enumerate(choices)] + csize, _, ctype = min(choices) + for i in range(0, info['size'] - csize + 1, info['align']): + if layout[i:i+csize] == [None] * csize: + layout_addfield(layout, i, ctype, '_alignment') + break + else: + raise AssertionError("unenforceable alignment %d" % ( + info['align'],)) + + n = 0 + for i, cell in enumerate(layout): + if cell is not None: + continue + layout_addfield(layout, i, ctypes.c_char, '_pad%d' % (n,)) + n += 1 + + # build the ctypes Structure + seen = {} + fields = [] + for cell in layout: + if cell in seen: + continue + fields.append((cell.name, cell.ctype)) + seen[cell] = True + + class S(ctypes.Structure): + _fields_ = fields + name = self.name + if name.startswith('struct '): + name = name[7:] + S.__name__ = name + return S + +class SimpleType(CConfigEntry): + """An entry in a CConfig class that stands for an externally + defined simple numeric type. + """ + def __init__(self, name, ctype_hint=ctypes.c_int, ifdef=None): + self.name = name + self.ctype_hint = ctype_hint + self.ifdef = ifdef + + def prepare_code(self): + if self.ifdef is not None: + yield '#ifdef %s' % (self.ifdef,) + yield 'typedef %s ctypesplatcheck_t;' % (self.name,) + yield '' + yield 'ctypesplatcheck_t x;' + if self.ifdef is not None: + yield 'dump("defined", 1);' + yield 'dump("size", sizeof(ctypesplatcheck_t));' + if self.ctype_hint in integer_class: + yield 'x = 0; x = ~x;' + yield 'dump("unsigned", x > 0);' + if self.ifdef is not None: + yield '#else' + yield 'dump("defined", 0);' + yield '#endif' + + def build_result(self, info, config_result): + if self.ifdef is not None and not info['defined']: + return None + size = info['size'] + sign = info.get('unsigned', False) + ctype = self.ctype_hint + if (size, sign) != size_and_sign(ctype): + ctype = fixup_ctype(ctype, self.name, (size, sign)) + return ctype + +class ConstantInteger(CConfigEntry): + """An entry in a CConfig class that stands for an externally + defined integer constant. + """ + def __init__(self, name): + self.name = name + + def prepare_code(self): + yield 'if ((%s) < 0) {' % (self.name,) + yield ' long long x = (long long)(%s);' % (self.name,) + yield ' printf("value: %lld\\n", x);' + yield '} else {' + yield ' unsigned long long x = (unsigned long long)(%s);' % ( + self.name,) + yield ' printf("value: %llu\\n", x);' + yield '}' + + def build_result(self, info, config_result): + return info['value'] + +class DefinedConstantInteger(CConfigEntry): + """An entry in a CConfig class that stands for an externally + defined integer constant. If not #defined the value will be None. + """ + def __init__(self, macro): + self.name = self.macro = macro + + def prepare_code(self): + yield '#ifdef %s' % self.macro + yield 'dump("defined", 1);' + yield 'if ((%s) < 0) {' % (self.macro,) + yield ' long long x = (long long)(%s);' % (self.macro,) + yield ' printf("value: %lld\\n", x);' + yield '} else {' + yield ' unsigned long long x = (unsigned long long)(%s);' % ( + self.macro,) + yield ' printf("value: %llu\\n", x);' + yield '}' + yield '#else' + yield 'dump("defined", 0);' + yield '#endif' + + def build_result(self, info, config_result): + if info["defined"]: + return info['value'] + return None + + +class DefinedConstantString(CConfigEntry): + """ + """ + def __init__(self, macro): + self.macro = macro + self.name = macro + + def prepare_code(self): + yield '#ifdef %s' % self.macro + yield 'int i;' + yield 'char *p = %s;' % self.macro + yield 'dump("defined", 1);' + yield 'for (i = 0; p[i] != 0; i++ ) {' + yield ' printf("value_%d: %d\\n", i, (int)(unsigned char)p[i]);' + yield '}' + yield '#else' + yield 'dump("defined", 0);' + yield '#endif' + + def build_result(self, info, config_result): + if info["defined"]: + string = '' + d = 0 + while info.has_key('value_%d' % d): + string += chr(info['value_%d' % d]) + d += 1 + return string + return None + + +class Defined(CConfigEntry): + """A boolean, corresponding to an #ifdef. + """ + def __init__(self, macro): + self.macro = macro + self.name = macro + + def prepare_code(self): + yield '#ifdef %s' % (self.macro,) + yield 'dump("defined", 1);' + yield '#else' + yield 'dump("defined", 0);' + yield '#endif' + + def build_result(self, info, config_result): + return bool(info['defined']) + +class CConfigSingleEntry(object): + """ An abstract class of type which requires + gcc succeeding/failing instead of only asking + """ + pass + +class Has(CConfigSingleEntry): + def __init__(self, name): + self.name = name + + def question(self, ask_gcc): + return ask_gcc(self.name + ';') + +class Works(CConfigSingleEntry): + def question(self, ask_gcc): + return ask_gcc("") + +class SizeOf(CConfigEntry): + """An entry in a CConfig class that stands for + some external opaque type + """ + def __init__(self, name): + self.name = name + + def prepare_code(self): + yield 'dump("size", sizeof(%s));' % self.name + + def build_result(self, info, config_result): + return info['size'] + +# ____________________________________________________________ +# +# internal helpers + +def ctype_alignment(c_type): + if issubclass(c_type, ctypes.Structure): + return max([ctype_alignment(fld_type) + for fld_name, fld_type in c_type._fields_]) + + return ctypes.alignment(c_type) + +def uniquefilepath(LAST=[0]): + i = LAST[0] + LAST[0] += 1 + return configdir.join('ctypesplatcheck_%d.c' % i) + +alignment_types = [ + ctypes.c_short, + ctypes.c_int, + ctypes.c_long, + ctypes.c_float, + ctypes.c_double, + ctypes.c_char_p, + ctypes.c_void_p, + ctypes.c_longlong, + ctypes.c_wchar, + ctypes.c_wchar_p, + ] + +integer_class = [ctypes.c_byte, ctypes.c_ubyte, + ctypes.c_short, ctypes.c_ushort, + ctypes.c_int, ctypes.c_uint, + ctypes.c_long, ctypes.c_ulong, + ctypes.c_longlong, ctypes.c_ulonglong, + ] +float_class = [ctypes.c_float, ctypes.c_double] + +class Field(object): + def __init__(self, name, ctype): + self.name = name + self.ctype = ctype + def __repr__(self): + return '' % (self.name, self.ctype) + +def layout_addfield(layout, offset, ctype, prefix): + size = ctypes.sizeof(ctype) + name = prefix + i = 0 + while name in layout: + i += 1 + name = '%s_%d' % (prefix, i) + field = Field(name, ctype) + for i in range(offset, offset+size): + assert layout[i] is None, "%s overlaps %r" % (fieldname, layout[i]) + layout[i] = field + return field + +def size_and_sign(ctype): + return (ctypes.sizeof(ctype), + ctype in integer_class and ctype(-1).value > 0) + +def fixup_ctype(fieldtype, fieldname, expected_size_and_sign): + for typeclass in [integer_class, float_class]: + if fieldtype in typeclass: + for ctype in typeclass: + if size_and_sign(ctype) == expected_size_and_sign: + return ctype + if (hasattr(fieldtype, '_length_') + and getattr(fieldtype, '_type_', None) == ctypes.c_char): + # for now, assume it is an array of chars; otherwise we'd also + # have to check the exact integer type of the elements of the array + size, sign = expected_size_and_sign + return ctypes.c_char * size + if (hasattr(fieldtype, '_length_') + and getattr(fieldtype, '_type_', None) == ctypes.c_ubyte): + # grumble, fields of type 'c_char array' have automatic cast-to- + # Python-string behavior in ctypes, which may not be what you + # want, so here is the same with c_ubytes instead... + size, sign = expected_size_and_sign + return ctypes.c_ubyte * size + raise TypeError("conflicting field type %r for %r" % (fieldtype, + fieldname)) + + +C_HEADER = """ +#include +#include /* for offsetof() */ +#include /* FreeBSD: for uint64_t */ + +void dump(char* key, int value) { + printf("%s: %d\\n", key, value); +} +""" + +def run_example_code(filepath, eci, noerr=False): + executable = build_executable([filepath], eci, noerr=noerr) + output = py.process.cmdexec(executable) + section = None + for line in output.splitlines(): + line = line.strip() + if line.startswith('-+- '): # start of a new section + section = {} + elif line == '---': # section end + assert section is not None + yield section + section = None + elif line: + assert section is not None + key, value = line.split(': ') + section[key] = int(value) + +# ____________________________________________________________ + +def get_python_include_dir(): + from distutils import sysconfig + gcv = sysconfig.get_config_vars() + return gcv['INCLUDEPY'] + +if __name__ == '__main__': + doc = """Example: + + ctypes_platform.py -h sys/types.h -h netinet/in.h + 'struct sockaddr_in' + sin_port c_int + """ + import sys, getopt + opts, args = getopt.gnu_getopt(sys.argv[1:], 'h:') + if not args: + print >> sys.stderr, doc + else: + assert len(args) % 2 == 1 + headers = [] + for opt, value in opts: + if opt == '-h': + headers.append('#include <%s>' % (value,)) + name = args[0] + fields = [] + for i in range(1, len(args), 2): + ctype = getattr(ctypes, args[i+1]) + fields.append((args[i], ctype)) + + S = getstruct(name, '\n'.join(headers), fields) + + for key, value in S._fields_: + print key, value diff --git a/lib/pypy/ctypes_configure/doc/configure.html b/lib/pypy/ctypes_configure/doc/configure.html new file mode 100644 --- /dev/null +++ b/lib/pypy/ctypes_configure/doc/configure.html @@ -0,0 +1,30 @@ + + + + + + +ctypes configure + + +
      +

      ctypes configure

      +
      +

      idea

      +

      One of ctypes problems is that ctypes programs are usually not very +platform-independent. We created ctypes_configure, which invokes gcc +for various platform-dependent details like +exact sizes of types (for example size_t), #defines, exact outline +of structures etc. It replaces in this regard code generator (h2py).

      +
      +
      +

      installation

      +

      easy_install ctypes_configure

      +
      +
      +

      usage

      +

      sample.py explains in details how to use it.

      +
      +
      + + diff --git a/lib/pypy/ctypes_configure/doc/configure.txt b/lib/pypy/ctypes_configure/doc/configure.txt new file mode 100644 --- /dev/null +++ b/lib/pypy/ctypes_configure/doc/configure.txt @@ -0,0 +1,24 @@ +================= +ctypes configure +================= + +idea +==== + +One of ctypes problems is that ctypes programs are usually not very +platform-independent. We created ctypes_configure, which invokes gcc +for various platform-dependent details like +exact sizes of types (for example size\_t), #defines, exact outline +of structures etc. It replaces in this regard code generator (h2py). + +installation +============ + +``easy_install ctypes_configure`` + +usage +===== + +`sample.py`_ explains in details how to use it. + +.. _`sample.py`: http://codespeak.net/svn/pypy/dist/ctypes_configure/doc/sample.py diff --git a/lib/pypy/ctypes_configure/doc/sample.py b/lib/pypy/ctypes_configure/doc/sample.py new file mode 100644 --- /dev/null +++ b/lib/pypy/ctypes_configure/doc/sample.py @@ -0,0 +1,72 @@ + +from ctypes_configure import configure +import ctypes + +class CConfigure: + _compilation_info_ = configure.ExternalCompilationInfo( + + # all lines landing in C header before includes + pre_include_lines = [], + + # list of .h files to include + includes = ['time.h', 'sys/time.h', 'unistd.h'], + + # list of directories to search for include files + include_dirs = [], + + # all lines landing in C header after includes + post_include_lines = [], + + # libraries to link with + libraries = [], + + # library directories + library_dirs = [], + + # additional C sources to compile with (that go to + # created .c files) + separate_module_sources = [], + + # additional existing C source file names + separate_module_files = [], + ) + + # get real int type out of hint and name + size_t = configure.SimpleType('size_t', ctypes.c_int) + + # grab value of numerical #define + NULL = configure.ConstantInteger('NULL') + + # grab #define, whether it's defined or not + EXISTANT = configure.Defined('NULL') + NOT_EXISTANT = configure.Defined('XXXNOTNULL') + + # check for existance of C functions + has_write = configure.Has('write') + no_xxxwrite = configure.Has('xxxwrite') + + # check for size of type + sizeof_size_t = configure.SizeOf('size_t') + + # structure, with given hints for interesting fields, + # types does not need to be too specific. + # all interesting fields would end up with right offset + # size and order + struct_timeval = configure.Struct('struct timeval',[ + ('tv_sec', ctypes.c_int), + ('tv_usec', ctypes.c_int)]) + +info = configure.configure(CConfigure) + +assert info['has_write'] +assert not info['no_xxxwrite'] +assert info['NULL'] == 0 +size_t = info['size_t'] +print "size_t in ctypes is ", size_t +assert ctypes.sizeof(size_t) == info['sizeof_size_t'] +assert info['EXISTANT'] +assert not info['NOT_EXISTANT'] +print +print "fields of struct timeval are " +for name, value in info['struct_timeval']._fields_: + print " ", name, " ", value diff --git a/lib/pypy/ctypes_configure/dumpcache.py b/lib/pypy/ctypes_configure/dumpcache.py new file mode 100644 --- /dev/null +++ b/lib/pypy/ctypes_configure/dumpcache.py @@ -0,0 +1,46 @@ +import os, sys +import ctypes + + +def dumpcache(referencefilename, filename, config): + dirname = os.path.dirname(referencefilename) + filename = os.path.join(dirname, filename) + f = open(filename, 'w') + print >> f, 'import ctypes' + print >> f + names = config.keys() + names.sort() + print >> f, '__all__ = %r' % (tuple(names),) + print >> f + for key in names: + val = config[key] + if isinstance(val, (int, long)): + f.write("%s = %d\n" % (key, val)) + elif val is None: + f.write("%s = None\n" % key) + elif isinstance(val, ctypes.Structure.__class__): + f.write("class %s(ctypes.Structure):\n" % key) + f.write(" _fields_ = [\n") + for k, v in val._fields_: + f.write(" ('%s', %s),\n" % (k, ctypes_repr(v))) + f.write(" ]\n") + elif isinstance(val, (tuple, list)): + for x in val: + assert isinstance(x, (int, long, str)), \ + "lists of integers or strings only" + f.write("%s = %r\n" % (key, val)) + else: + # a simple type, hopefully + f.write("%s = %s\n" % (key, ctypes_repr(val))) + f.close() + print 'Wrote %s.' % (filename,) + sys.stdout.flush() + +def ctypes_repr(cls): + # ctypes_configure does not support nested structs so far + # so let's ignore it + if isinstance(cls, ctypes._SimpleCData.__class__): + return "ctypes." + cls.__name__ + if hasattr(cls, '_length_') and hasattr(cls, '_type_'): # assume an array + return '%s*%d' % (ctypes_repr(cls._type_), cls._length_) + raise NotImplementedError("saving of object with type %r" % type(cls)) diff --git a/lib/pypy/ctypes_configure/stdoutcapture.py b/lib/pypy/ctypes_configure/stdoutcapture.py new file mode 100644 --- /dev/null +++ b/lib/pypy/ctypes_configure/stdoutcapture.py @@ -0,0 +1,73 @@ +""" +A quick hack to capture stdout/stderr. +""" + +import os, sys + + +class Capture: + + def __init__(self, mixed_out_err = False): + "Start capture of the Unix-level stdout and stderr." + if (not hasattr(os, 'tmpfile') or + not hasattr(os, 'dup') or + not hasattr(os, 'dup2') or + not hasattr(os, 'fdopen')): + self.dummy = 1 + else: + self.dummy = 0 + # make new stdout/stderr files if needed + self.localoutfd = os.dup(1) + self.localerrfd = os.dup(2) + if hasattr(sys.stdout, 'fileno') and sys.stdout.fileno() == 1: + self.saved_stdout = sys.stdout + sys.stdout = os.fdopen(self.localoutfd, 'w', 1) + else: + self.saved_stdout = None + if hasattr(sys.stderr, 'fileno') and sys.stderr.fileno() == 2: + self.saved_stderr = sys.stderr + sys.stderr = os.fdopen(self.localerrfd, 'w', 0) + else: + self.saved_stderr = None + self.tmpout = os.tmpfile() + if mixed_out_err: + self.tmperr = self.tmpout + else: + self.tmperr = os.tmpfile() + os.dup2(self.tmpout.fileno(), 1) + os.dup2(self.tmperr.fileno(), 2) + + def done(self): + "End capture and return the captured text (stdoutfile, stderrfile)." + if self.dummy: + import cStringIO + return cStringIO.StringIO(), cStringIO.StringIO() + else: + os.dup2(self.localoutfd, 1) + os.dup2(self.localerrfd, 2) + if self.saved_stdout is not None: + f = sys.stdout + sys.stdout = self.saved_stdout + f.close() + else: + os.close(self.localoutfd) + if self.saved_stderr is not None: + f = sys.stderr + sys.stderr = self.saved_stderr + f.close() + else: + os.close(self.localerrfd) + self.tmpout.seek(0) + self.tmperr.seek(0) + return self.tmpout, self.tmperr + + +if __name__ == '__main__': + # test + c = Capture() + try: + os.system('echo hello') + finally: + fout, ferr = c.done() + print 'Output:', `fout.read()` + print 'Error:', `ferr.read()` diff --git a/lib/pypy/ctypes_configure/test/__init__.py b/lib/pypy/ctypes_configure/test/__init__.py new file mode 100644 diff --git a/lib/pypy/ctypes_configure/test/test_configure.py b/lib/pypy/ctypes_configure/test/test_configure.py new file mode 100644 --- /dev/null +++ b/lib/pypy/ctypes_configure/test/test_configure.py @@ -0,0 +1,212 @@ +import py, sys, struct +from ctypes_configure import configure +from ctypes_configure.cbuild import ExternalCompilationInfo +import ctypes + +def test_dirent(): + dirent = configure.getstruct("struct dirent", + """ + struct dirent /* for this example only, not the exact dirent */ + { + long d_ino; + int d_off; + unsigned short d_reclen; + char d_name[32]; + }; + """, + [("d_reclen", ctypes.c_ushort)]) + assert issubclass(dirent, ctypes.Structure) + ssize = (ctypes.sizeof(ctypes.c_long) + + ctypes.sizeof(ctypes.c_int) + + ctypes.sizeof(ctypes.c_ushort) + + 32) + extra_padding = (-ssize) % ctypes.alignment(ctypes.c_long) + + assert dirent._fields_ == [('_alignment', ctypes.c_long), + ('_pad0', ctypes.c_char), + ('_pad1', ctypes.c_char), + ('_pad2', ctypes.c_char), + ('_pad3', ctypes.c_char), + ('d_reclen', ctypes.c_ushort), + ] + [ + ('_pad%d' % n, ctypes.c_char) + for n in range(4, 4+32+extra_padding)] + assert ctypes.sizeof(dirent) == ssize + extra_padding + assert ctypes.alignment(dirent) == ctypes.alignment(ctypes.c_long) + +def test_fit_type(): + S = configure.getstruct("struct S", + """ + struct S { + signed char c; + unsigned char uc; + short s; + unsigned short us; + int i; + unsigned int ui; + long l; + unsigned long ul; + long long ll; + unsigned long long ull; + float f; + double d; + }; + """, + [("c", ctypes.c_int), + ("uc", ctypes.c_int), + ("s", ctypes.c_uint), + ("us", ctypes.c_int), + ("i", ctypes.c_int), + ("ui", ctypes.c_int), + ("l", ctypes.c_int), + ("ul", ctypes.c_int), + ("ll", ctypes.c_int), + ("ull", ctypes.c_int), + ("f", ctypes.c_double), + ("d", ctypes.c_float)]) + assert issubclass(S, ctypes.Structure) + fields = dict(S._fields_) + assert fields["c"] == ctypes.c_byte + assert fields["uc"] == ctypes.c_ubyte + assert fields["s"] == ctypes.c_short + assert fields["us"] == ctypes.c_ushort + assert fields["i"] == ctypes.c_int + assert fields["ui"] == ctypes.c_uint + assert fields["l"] == ctypes.c_long + assert fields["ul"] == ctypes.c_ulong + assert fields["ll"] == ctypes.c_longlong + assert fields["ull"] == ctypes.c_ulonglong + assert fields["f"] == ctypes.c_float + assert fields["d"] == ctypes.c_double + +def test_simple_type(): + ctype = configure.getsimpletype('test_t', + 'typedef unsigned short test_t;', + ctypes.c_int) + assert ctype == ctypes.c_ushort + +def test_constant_integer(): + value = configure.getconstantinteger('BLAH', + '#define BLAH (6*7)') + assert value == 42 + value = configure.getconstantinteger('BLAH', + '#define BLAH (-2147483648LL)') + assert value == -2147483648 + value = configure.getconstantinteger('BLAH', + '#define BLAH (3333333333ULL)') + assert value == 3333333333 + +def test_defined(): + res = configure.getdefined('ALFKJLKJFLKJFKLEJDLKEWMECEE', '') + assert not res + res = configure.getdefined('ALFKJLKJFLKJFKLEJDLKEWMECEE', + '#define ALFKJLKJFLKJFKLEJDLKEWMECEE') + assert res + +def test_configure(): + configdir = configure.configdir + test_h = configdir.join('test_ctypes_platform.h') + test_h.write('#define XYZZY 42\n') + + class CConfig: + _compilation_info_ = ExternalCompilationInfo( + pre_include_lines = ["/* a C comment */", + "#include ", + "#include "], + include_dirs = [str(configdir)] + ) + + FILE = configure.Struct('FILE', []) + ushort = configure.SimpleType('unsigned short') + XYZZY = configure.ConstantInteger('XYZZY') + + res = configure.configure(CConfig) + assert issubclass(res['FILE'], ctypes.Structure) + assert res == {'FILE': res['FILE'], + 'ushort': ctypes.c_ushort, + 'XYZZY': 42} + +def test_ifdef(): + class CConfig: + _compilation_info_ = ExternalCompilationInfo( + post_include_lines = ['/* a C comment */', + '#define XYZZY 42', + 'typedef int foo;', + 'struct s {', + 'int i;', + 'double f;' + '};']) + + + s = configure.Struct('struct s', [('i', ctypes.c_int)], + ifdef='XYZZY') + z = configure.Struct('struct z', [('i', ctypes.c_int)], + ifdef='FOOBAR') + + foo = configure.SimpleType('foo', ifdef='XYZZY') + bar = configure.SimpleType('bar', ifdef='FOOBAR') + + res = configure.configure(CConfig) + assert res['s'] is not None + assert res['z'] is None + assert res['foo'] is not None + assert res['bar'] is None + +def test_nested_structs(): + class CConfig: + _compilation_info_ = ExternalCompilationInfo( + post_include_lines=""" + struct x { + int foo; + unsigned long bar; + }; + struct y { + char c; + struct x x; + }; + """.split("\n")) + + x = configure.Struct("struct x", [("bar", ctypes.c_short)]) + y = configure.Struct("struct y", [("x", x)]) + + res = configure.configure(CConfig) + c_x = res["x"] + c_y = res["y"] + c_y_fields = dict(c_y._fields_) + assert issubclass(c_x , ctypes.Structure) + assert issubclass(c_y, ctypes.Structure) + assert c_y_fields["x"] is c_x + +def test_array(): + dirent = configure.getstruct("struct dirent", + """ + struct dirent /* for this example only, not the exact dirent */ + { + long d_ino; + int d_off; + unsigned short d_reclen; + char d_name[32]; + }; + """, + [("d_name", ctypes.c_char * 0)]) + assert dirent.d_name.size == 32 + +def test_has(): + assert configure.has("x", "int x = 3;") + assert not configure.has("x", "") + # has() should also not crash if it is given an invalid #include + assert not configure.has("x", "#include ") + +def test_check_eci(): + eci = ExternalCompilationInfo() + assert configure.check_eci(eci) + eci = ExternalCompilationInfo(libraries=['some_name_that_doesnt_exist_']) + assert not configure.check_eci(eci) + +def test_sizeof(): + assert configure.sizeof("char", ExternalCompilationInfo()) == 1 + +def test_memory_alignment(): + a = configure.memory_alignment() + print a + assert a % struct.calcsize("P") == 0 diff --git a/lib/pypy/ctypes_configure/test/test_dumpcache.py b/lib/pypy/ctypes_configure/test/test_dumpcache.py new file mode 100644 --- /dev/null +++ b/lib/pypy/ctypes_configure/test/test_dumpcache.py @@ -0,0 +1,61 @@ +import ctypes +from ctypes_configure import configure, dumpcache +from ctypes_configure.cbuild import ExternalCompilationInfo + + +def test_cache(): + configdir = configure.configdir + test_h = configdir.join('test_ctypes_platform2.h') + test_h.write('#define XYZZY 42\n' + "#define large 2147483648L\n") + + class CConfig: + _compilation_info_ = ExternalCompilationInfo( + pre_include_lines = ["/* a C comment */", + "#include ", + "#include "], + include_dirs = [str(configdir)] + ) + + FILE = configure.Struct('FILE', []) + ushort = configure.SimpleType('unsigned short') + XYZZY = configure.ConstantInteger('XYZZY') + XUZ = configure.Has('XUZ') + large = configure.DefinedConstantInteger('large') + undef = configure.Defined('really_undefined') + + res = configure.configure(CConfig) + + cachefile = configdir.join('cache') + dumpcache.dumpcache('', str(cachefile), res) + + d = {} + execfile(str(cachefile), d) + assert d['XYZZY'] == res['XYZZY'] + assert d['ushort'] == res['ushort'] + assert d['FILE']._fields_ == res['FILE']._fields_ + assert d['FILE'].__mro__[1:] == res['FILE'].__mro__[1:] + assert d['undef'] == res['undef'] + assert d['large'] == res['large'] + assert d['XUZ'] == res['XUZ'] + + +def test_cache_array(): + configdir = configure.configdir + res = {'foo': ctypes.c_short * 27} + cachefile = configdir.join('cache_array') + dumpcache.dumpcache('', str(cachefile), res) + # + d = {} + execfile(str(cachefile), d) + assert d['foo'] == res['foo'] + +def test_cache_array_array(): + configdir = configure.configdir + res = {'foo': (ctypes.c_int * 2) * 3} + cachefile = configdir.join('cache_array_array') + dumpcache.dumpcache('', str(cachefile), res) + # + d = {} + execfile(str(cachefile), d) + assert d['foo'] == res['foo'] diff --git a/lib/pypy/demo/autopath.py b/lib/pypy/demo/autopath.py new file mode 100644 --- /dev/null +++ b/lib/pypy/demo/autopath.py @@ -0,0 +1,2 @@ +import sys, os +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) diff --git a/lib/pypy/demo/bpnn.py b/lib/pypy/demo/bpnn.py new file mode 100755 --- /dev/null +++ b/lib/pypy/demo/bpnn.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python +""" + Translator Demo + + To analyse and type-annotate the functions and class defined in + this module, starting from the entry point function demo(), + use the following command line: + + ../pypy/translator/goal/translate.py bpnn.py + + Insert '--help' before 'bpnn.py' for a list of translation options, + or see the Overview of Command Line Options for translation at + http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html +""" +# Back-Propagation Neural Networks +# +# Written in Python. See http://www.python.org/ +# +# Neil Schemenauer +# +# Modifications to the original (Armin Rigo): +# * import random from PyPy's lib, which is Python 2.2's plain +# Python implementation +# * print a doc about how to start the Translator + +import sys +import math +import time + +import autopath +from pypy.rlib import rrandom + +PRINT_IT = True + +random = rrandom.Random(1) + +# calculate a random number where: a <= rand < b +def rand(a, b): + return (b-a)*random.random() + a + +# Make a matrix (we could use NumPy to speed this up) +def makeMatrix(I, J, fill=0.0): + m = [] + for i in range(I): + m.append([fill]*J) + return m + +class NN: + + def __init__(self, ni, nh, no): + # number of input, hidden, and output nodes + self.ni = ni + 1 # +1 for bias node + self.nh = nh + self.no = no + + # activations for nodes + self.ai = [1.0]*self.ni + self.ah = [1.0]*self.nh + self.ao = [1.0]*self.no + + # create weights + self.wi = makeMatrix(self.ni, self.nh) + self.wo = makeMatrix(self.nh, self.no) + # set them to random vaules + for i in range(self.ni): + for j in range(self.nh): + self.wi[i][j] = rand(-2.0, 2.0) + for j in range(self.nh): + for k in range(self.no): + self.wo[j][k] = rand(-2.0, 2.0) + + # last change in weights for momentum + self.ci = makeMatrix(self.ni, self.nh) + self.co = makeMatrix(self.nh, self.no) + + def update(self, inputs): + if len(inputs) != self.ni-1: + raise ValueError, 'wrong number of inputs' + + # input activations + for i in range(self.ni-1): + #self.ai[i] = 1.0/(1.0+math.exp(-inputs[i])) + self.ai[i] = inputs[i] + + # hidden activations + for j in range(self.nh): + sum = 0.0 + for i in range(self.ni): + sum = sum + self.ai[i] * self.wi[i][j] + self.ah[j] = 1.0/(1.0+math.exp(-sum)) + + # output activations + for k in range(self.no): + sum = 0.0 + for j in range(self.nh): + sum = sum + self.ah[j] * self.wo[j][k] + self.ao[k] = 1.0/(1.0+math.exp(-sum)) + + return self.ao[:] + + + def backPropagate(self, targets, N, M): + if len(targets) != self.no: + raise ValueError, 'wrong number of target values' + + # calculate error terms for output + output_deltas = [0.0] * self.no + for k in range(self.no): + ao = self.ao[k] + output_deltas[k] = ao*(1-ao)*(targets[k]-ao) + + # calculate error terms for hidden + hidden_deltas = [0.0] * self.nh + for j in range(self.nh): + sum = 0.0 + for k in range(self.no): + sum = sum + output_deltas[k]*self.wo[j][k] From noreply at buildbot.pypy.org Mon Jul 25 15:44:16 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 25 Jul 2011 15:44:16 +0200 (CEST) Subject: [pypy-commit] benchmarks default: add a translate.py benchmark, and hack the code around to make it working; in particular, we want to be able to return a list of subresults and to run a benchmark only on base_python but not on changed_python Message-ID: <20110725134416.2A0E1829C2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r132:51848ff7c705 Date: 2011-07-25 15:31 +0200 http://bitbucket.org/pypy/benchmarks/changeset/51848ff7c705/ Log: add a translate.py benchmark, and hack the code around to make it working; in particular, we want to be able to return a list of subresults and to run a benchmark only on base_python but not on changed_python diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -58,3 +58,75 @@ _register_new_bm('spitfire', 'spitfire_cstringio', globals(), extra_args=['--benchmark=python_cstringio']) + + +# ========================================================================= +# translate.py benchmark +# ========================================================================= + +def parse_timer(lines): + prefix = '[Timer] ' + n = len(prefix) + lines = [line[n:] for line in lines if line.startswith(prefix)] + timings = [] + for line in lines: + if (line == 'Timings:' or + line.startswith('============') or + line.startswith('Total:')): + continue + name, _, time = map(str.strip, line.partition('---')) + assert time.endswith(' s') + time = float(time[:-2]) + timings.append((name, time)) + return timings + +def test_parse_timer(): + lines = [ + 'foobar', + '....', + '[Timer] Timings:', + '[Timer] annotate --- 1.3 s', + '[Timer] rtype_lltype --- 4.6 s', + '[Timer] database_c --- 0.4 s', + '[Timer] ========================================', + '[Timer] Total: --- 6.3 s', + 'hello world', + '...', + ] + timings = parse_timer(lines) + assert timings == [ + ('annotate', 1.3), + ('rtype_lltype', 4.6), + ('database_c', 0.4) + ] + +def BM_translate(base_python, changed_python, options): + """ + Run translate.py and returns a benchmark result for each of the phases. + Note that we run it only with ``base_python`` (which corresponds to + pypy-c-jit in the nightly benchmarks, we are not interested in + ``changed_python`` (aka pypy-c-nojit) right now. + """ + from unladen_swallow.perf import RawResult + import subprocess + + translate_py = relative('lib/pypy/pypy/translator/goal/translate.py') + targetnop = relative('lib/pypy/pypy/translator/goal/targetnopstandalone.py') + args = base_python + [translate_py, + '--source', '--dont-write-c-files', + targetnop, + ] + try: + output = subprocess.check_output(args, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError, e: + print e.output + raise + + lines = output.splitlines() + timings = parse_timer(lines) + + result = [] + for name, time in timings: + data = RawResult([time], None) + result.append((name, data)) + return result diff --git a/saveresults.py b/saveresults.py --- a/saveresults.py +++ b/saveresults.py @@ -49,6 +49,14 @@ value = results['avg_changed'] else: value = results['avg_base'] + elif res_type == "RawResult": + if changed: + value = results["changed_times"] + else: + value = results["base_times"] + if value: + assert len(value) == 1 + value = value[0] else: print("ERROR: result type unknown " + b[1]) return 1 @@ -61,6 +69,9 @@ 'result_value': value, 'branch': 'default', } + if value is None: + print "Ignoring skipped result", data + continue if res_type == "ComparisonResult": if changed: data['std_dev'] = results['std_changed'] @@ -91,8 +102,10 @@ response += ' Reason: ' + str(e.reason) elif hasattr(e, 'code'): response = '\n The server couldn\'t fulfill the request' - response = "\n".join([response] + e.readlines()) - print("Server (%s) response: %s" % (SPEEDURL, response)) + response = "".join([response] + e.readlines()) + with open('error.html', 'w') as error_file: + error_file.write(response) + print("Server (%s) response written to error.html" % (SPEEDURL,)) print(' Error code: %s\n' % (e,)) return 1 print "saved correctly!\n" diff --git a/unladen_swallow/perf.py b/unladen_swallow/perf.py --- a/unladen_swallow/perf.py +++ b/unladen_swallow/perf.py @@ -1604,8 +1604,15 @@ for name in sorted(should_run): func = bench_funcs[name] print "Running %s..." % name - results.append((name, func(base_cmd_prefix, changed_cmd_prefix, - options))) + # PyPy specific modification: let the func to return a list of results + # for sub-benchmarks + bench_result = func(base_cmd_prefix, changed_cmd_prefix, options) + if isinstance(bench_result, list): + for subname, subresult in bench_result: + fullname = '%s_%s' % (name, subname) + results.append((fullname, subresult)) + else: + results.append((name, bench_result)) print print "Report on %s" % " ".join(platform.uname()) From noreply at buildbot.pypy.org Mon Jul 25 15:44:17 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 25 Jul 2011 15:44:17 +0200 (CEST) Subject: [pypy-commit] benchmarks default: try to have shorter names, like trans_rtype instead of translate_rtype_lltype Message-ID: <20110725134417.8176E829C2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r133:32d83a5e353b Date: 2011-07-25 15:41 +0200 http://bitbucket.org/pypy/benchmarks/changeset/32d83a5e353b/ Log: try to have shorter names, like trans_rtype instead of translate_rtype_lltype diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -75,6 +75,9 @@ line.startswith('Total:')): continue name, _, time = map(str.strip, line.partition('---')) + name = name.replace('_lltype', '') + name = name.replace('_c', '') + name = name.replace('stackcheckinsertion', 'stackcheck') assert time.endswith(' s') time = float(time[:-2]) timings.append((name, time)) @@ -87,6 +90,7 @@ '[Timer] Timings:', '[Timer] annotate --- 1.3 s', '[Timer] rtype_lltype --- 4.6 s', + '[Timer] stackcheckinsertion_lltype --- 2.3 s', '[Timer] database_c --- 0.4 s', '[Timer] ========================================', '[Timer] Total: --- 6.3 s', @@ -96,8 +100,9 @@ timings = parse_timer(lines) assert timings == [ ('annotate', 1.3), - ('rtype_lltype', 4.6), - ('database_c', 0.4) + ('rtype', 4.6), + ('stackcheck', 2.3), + ('database', 0.4) ] def BM_translate(base_python, changed_python, options): @@ -130,3 +135,4 @@ data = RawResult([time], None) result.append((name, data)) return result +BM_translate.benchmark_name = 'trans' diff --git a/unladen_swallow/perf.py b/unladen_swallow/perf.py --- a/unladen_swallow/perf.py +++ b/unladen_swallow/perf.py @@ -1607,6 +1607,7 @@ # PyPy specific modification: let the func to return a list of results # for sub-benchmarks bench_result = func(base_cmd_prefix, changed_cmd_prefix, options) + name = getattr(func, 'benchmark_name', name) if isinstance(bench_result, list): for subname, subresult in bench_result: fullname = '%s_%s' % (name, subname) From noreply at buildbot.pypy.org Mon Jul 25 15:44:18 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 25 Jul 2011 15:44:18 +0200 (CEST) Subject: [pypy-commit] benchmarks default: run the full pypy target instead of targetnop Message-ID: <20110725134418.D2797829C2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r134:1658f38e0e7f Date: 2011-07-25 15:44 +0200 http://bitbucket.org/pypy/benchmarks/changeset/1658f38e0e7f/ Log: run the full pypy target instead of targetnop diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -116,11 +116,8 @@ import subprocess translate_py = relative('lib/pypy/pypy/translator/goal/translate.py') - targetnop = relative('lib/pypy/pypy/translator/goal/targetnopstandalone.py') - args = base_python + [translate_py, - '--source', '--dont-write-c-files', - targetnop, - ] + #targetnop = relative('lib/pypy/pypy/translator/goal/targetnopstandalone.py') + args = base_python + [translate_py, '--source', '--dont-write-c-files'] try: output = subprocess.check_output(args, stderr=subprocess.STDOUT) except subprocess.CalledProcessError, e: From noreply at buildbot.pypy.org Mon Jul 25 16:00:29 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 25 Jul 2011 16:00:29 +0200 (CEST) Subject: [pypy-commit] buildbot default: Fix. Message-ID: <20110725140029.E321A829C2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r538:47acc29a6789 Date: 2011-07-25 16:00 +0200 http://bitbucket.org/pypy/buildbot/changeset/47acc29a6789/ Log: Fix. diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py --- a/bot2/pypybuildbot/master.py +++ b/bot2/pypybuildbot/master.py @@ -350,6 +350,6 @@ }, ], - 'buildbotURL': 'http://buildbot.pypy.org', + 'buildbotURL': 'http://buildbot.pypy.org/', # with a trailing '/'! 'projectURL': 'http://pypy.org/', 'projectName': 'PyPy'} From noreply at buildbot.pypy.org Mon Jul 25 17:20:27 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 25 Jul 2011 17:20:27 +0200 (CEST) Subject: [pypy-commit] benchmarks default: bah, fix for python2.6 which does not have subprocess.check_output Message-ID: <20110725152027.91A54829C2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r135:3211debf47b0 Date: 2011-07-25 17:20 +0200 http://bitbucket.org/pypy/benchmarks/changeset/3211debf47b0/ Log: bah, fix for python2.6 which does not have subprocess.check_output diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -118,13 +118,15 @@ translate_py = relative('lib/pypy/pypy/translator/goal/translate.py') #targetnop = relative('lib/pypy/pypy/translator/goal/targetnopstandalone.py') args = base_python + [translate_py, '--source', '--dont-write-c-files'] - try: - output = subprocess.check_output(args, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError, e: - print e.output - raise + proc = subprocess.Popen(args, stderr=subprocess.PIPE) + out, err = proc.communicate() + retcode = proc.poll() + if retcode != 0: + print out + print err + raise Exception("translate.py failed") - lines = output.splitlines() + lines = err.splitlines() timings = parse_timer(lines) result = [] From noreply at buildbot.pypy.org Mon Jul 25 17:53:27 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 25 Jul 2011 17:53:27 +0200 (CEST) Subject: [pypy-commit] pypy default: Avoid using hashes that are directly the address. It gives a few Message-ID: <20110725155327.95952829C2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45965:39a9093e603d Date: 2011-07-25 17:53 +0200 http://bitbucket.org/pypy/pypy/changeset/39a9093e603d/ Log: Avoid using hashes that are directly the address. It gives a few lower bits that are always 0, leading to many more collisions in dictionaries. CPython fixed this in 2009 by mangling the value in a similar way. diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -49,6 +49,7 @@ from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage from pypy.rpython.memory.gc.base import GCBase, MovingGCBase from pypy.rpython.memory.gc import minimarkpage, env +from pypy.rpython.memory.support import mangle_hash from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask, r_uint from pypy.rlib.rarithmetic import LONG_BIT_SHIFT from pypy.rlib.debug import ll_assert, debug_print, debug_start, debug_stop @@ -1793,7 +1794,7 @@ return self.id_or_identityhash(gcobj, False) def identityhash(self, gcobj): - return self.id_or_identityhash(gcobj, True) + return mangle_hash(self.id_or_identityhash(gcobj, True)) # ---------- diff --git a/pypy/rpython/memory/lldict.py b/pypy/rpython/memory/lldict.py --- a/pypy/rpython/memory/lldict.py +++ b/pypy/rpython/memory/lldict.py @@ -1,6 +1,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem import rdict from pypy.rlib.objectmodel import we_are_translated +from pypy.rpython.memory.support import mangle_hash # This is a low-level AddressDict, reusing a lot of the logic from rdict.py. # xxx this is very dependent on the details of rdict.py @@ -40,7 +41,8 @@ lltype.free(entries, flavor="raw") if not we_are_translated(): count_alloc(-1) -_hash = llmemory.cast_adr_to_int +def _hash(adr): + return mangle_hash(llmemory.cast_adr_to_int(adr)) def dict_keyhash(d, key): return _hash(key) diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -4,6 +4,15 @@ from pypy.rlib.debug import ll_assert from pypy.tool.identity_dict import identity_dict + +def mangle_hash(i): + # To hash pointers in dictionaries. Assumes that i shows some + # alignment (to 4, 8, maybe 16 bytes), so we use the following + # formula to avoid the trailing bits being always 0. + return i ^ (i >> 4) + +# ____________________________________________________________ + DEFAULT_CHUNK_SIZE = 1019 From noreply at buildbot.pypy.org Mon Jul 25 17:55:40 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 17:55:40 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: call support Message-ID: <20110725155540.7BA1F829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45966:4340dbad8abe Date: 2011-07-25 17:30 +0200 http://bitbucket.org/pypy/pypy/changeset/4340dbad8abe/ Log: call support diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -139,7 +139,7 @@ return 'builtin' if (hasattr(targetgraph, 'func') and hasattr(targetgraph.func, '_jit_unroll_if_const_')): - return 'regularifconst' + return 'regular_ifconst' elif op.opname == 'oosend': SELFTYPE, methname, opargs = support.decompose_oosend(op) if SELFTYPE.oopspec_name is not None: diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py --- a/pypy/jit/codewriter/test/test_call.py +++ b/pypy/jit/codewriter/test/test_call.py @@ -144,6 +144,17 @@ assert res is None assert cc.guess_call_kind(op) == 'residual' + class funcptr: + class graph: + class func: + _jit_unroll_if_const_ = (0,) + + op = SpaceOperation('direct_call', [Constant(funcptr), Variable()], + Variable()) + res = cc.graphs_from(op) + assert res is None + assert cc.guess_call_kind(op) == 'regular_ifconst' + # ____________________________________________________________ def test_get_jitcode(): @@ -191,4 +202,4 @@ [block, _] = list(f_graph.iterblocks()) [op] = block.operations call_descr = cc.getcalldescr(op) - assert call_descr.extrainfo.can_release_gil \ No newline at end of file + assert call_descr.extrainfo.can_release_gil From noreply at buildbot.pypy.org Mon Jul 25 17:55:41 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 17:55:41 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: jtransform support Message-ID: <20110725155541.CEB1E829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45967:e7febacd5843 Date: 2011-07-25 17:52 +0200 http://bitbucket.org/pypy/pypy/changeset/e7febacd5843/ Log: jtransform support diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -342,9 +342,15 @@ argument is jitcode, then number of const arg then calldescr and finally all other args """ - import pdb - pdb.set_trace() [targetgraph] = self.callcontrol.graphs_from(op) + jitcode = self.callcontrol.get_jitcode(targetgraph, + called_from=self.graph) + no = targetgraph.func._jit_unroll_if_const_[0] + calldescr = self.callcontrol.getcalldescr(op) + op0 = self.rewrite_call(op, 'inline_ifconst_call', [jitcode, no, + calldescr]) + op1 = SpaceOperation('-live-', [], None) + return [op0, op1] def handle_builtin_call(self, op): oopspec_name, args = support.decode_builtin_call(op) diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -54,6 +54,21 @@ assert graph == 'somegraph' return 'somejitcode' +class FakeRegularIfConstCallControl: + class somegraph: + class func: + _jit_unroll_if_const_ = (0,) + + def guess_call_kind(self, op): + return 'regularifconst' + def graphs_from(self, op): + return [self.somegraph] + def get_jitcode(self, graph, called_from=None): + assert graph is self.somegraph + return 'somejitcode' + def getcalldescr(self, op): + return 'calldescr' + class FakeResidualIndirectCallControl: def guess_call_kind(self, op): return 'residual' @@ -274,6 +289,7 @@ yield direct_call_test, ARGS, RESTYPE, expectedkind yield indirect_residual_call_test, ARGS, RESTYPE, expectedkind yield indirect_regular_call_test, ARGS, RESTYPE, expectedkind + yield regular_ifconst_call_test, ARGS, RESTYPE, expectedkind def get_direct_call_op(argtypes, restype): FUNC = lltype.FuncType(argtypes, restype) @@ -305,6 +321,16 @@ assert op1.opname == '-live-' assert op1.args == [] +def regular_ifconst_call_test(argtypes, restype, expectedkind): + op = get_direct_call_op(argtypes, restype) + tr = Transformer(FakeCPU(), FakeRegularIfConstCallControl()) + tr.graph = 'graph' + oplist = tr.rewrite_operation(op) + op0, op1 = oplist + reskind = getkind(restype)[0] + assert op0.opname == 'inline_ifconst_call_%s_%s' % (expectedkind, reskind) + assert op0.args[0] == 'somejitcode' + def direct_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) tr = Transformer(FakeCPU(), FakeRegularCallControl()) From noreply at buildbot.pypy.org Mon Jul 25 18:19:12 2011 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 25 Jul 2011 18:19:12 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix this test: when running on top of pypy, lltype.Ptr(S) returns Message-ID: <20110725161912.C8E49829C2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45968:06d6597d6647 Date: 2011-07-25 18:19 +0200 http://bitbucket.org/pypy/pypy/changeset/06d6597d6647/ Log: Fix this test: when running on top of pypy, lltype.Ptr(S) returns a pointer to the old S from the previous test which hasn't been freed yet --- which is fine. diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -769,7 +769,7 @@ def get_vinfo(self, v): return None def could_be_green_field(self, S1, name1): - assert S1 is S + assert S1 == S assert name1 == 'x' return True S = lltype.GcStruct('S', ('x', lltype.Char), From noreply at buildbot.pypy.org Mon Jul 25 18:49:16 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 18:49:16 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: oops, consistency Message-ID: <20110725164916.C68C1829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45969:0bdf5654d053 Date: 2011-07-25 18:05 +0200 http://bitbucket.org/pypy/pypy/changeset/0bdf5654d053/ Log: oops, consistency diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -337,7 +337,7 @@ op1 = SpaceOperation('-live-', [], None) return [op0, op1] - def handle_regularifconst_call(self, op): + def handle_regular_ifconst_call(self, op): """ A direct call that turns into inline_ifconst_call_xxx. The first argument is jitcode, then number of const arg then calldescr and finally all other args diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -60,7 +60,7 @@ _jit_unroll_if_const_ = (0,) def guess_call_kind(self, op): - return 'regularifconst' + return 'regular_ifconst' def graphs_from(self, op): return [self.somegraph] def get_jitcode(self, graph, called_from=None): From noreply at buildbot.pypy.org Mon Jul 25 18:49:18 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 18:49:18 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: test and a fix Message-ID: <20110725164918.283F0829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45970:5b8d8a10a0f3 Date: 2011-07-25 18:24 +0200 http://bitbucket.org/pypy/pypy/changeset/5b8d8a10a0f3/ Log: test and a fix diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -70,7 +70,7 @@ continue kind = self.guess_call_kind(op, is_candidate) # use callers() to view the calling chain in pdb - if kind != "regular": + if kind != "regular" and kind != 'regular_ifconst': continue for graph in self.graphs_from(op, is_candidate): if graph in candidate_graphs: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -347,7 +347,8 @@ called_from=self.graph) no = targetgraph.func._jit_unroll_if_const_[0] calldescr = self.callcontrol.getcalldescr(op) - op0 = self.rewrite_call(op, 'inline_ifconst_call', [jitcode, no, + c_no = Constant(no, lltype.Signed) + op0 = self.rewrite_call(op, 'inline_ifconst_call', [jitcode, c_no, calldescr]) op1 = SpaceOperation('-live-', [], None) return [op0, op1] diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -330,6 +330,8 @@ reskind = getkind(restype)[0] assert op0.opname == 'inline_ifconst_call_%s_%s' % (expectedkind, reskind) assert op0.args[0] == 'somejitcode' + assert op0.args[1].value == 0 + assert op0.args[2] == 'calldescr' def direct_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) From noreply at buildbot.pypy.org Mon Jul 25 18:49:19 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 18:49:19 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: jitcode has a descr already Message-ID: <20110725164919.78FE1829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45971:325f7c33fea9 Date: 2011-07-25 18:27 +0200 http://bitbucket.org/pypy/pypy/changeset/325f7c33fea9/ Log: jitcode has a descr already diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -346,10 +346,8 @@ jitcode = self.callcontrol.get_jitcode(targetgraph, called_from=self.graph) no = targetgraph.func._jit_unroll_if_const_[0] - calldescr = self.callcontrol.getcalldescr(op) c_no = Constant(no, lltype.Signed) - op0 = self.rewrite_call(op, 'inline_ifconst_call', [jitcode, c_no, - calldescr]) + op0 = self.rewrite_call(op, 'inline_ifconst_call', [jitcode, c_no]) op1 = SpaceOperation('-live-', [], None) return [op0, op1] diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -331,7 +331,7 @@ assert op0.opname == 'inline_ifconst_call_%s_%s' % (expectedkind, reskind) assert op0.args[0] == 'somejitcode' assert op0.args[1].value == 0 - assert op0.args[2] == 'calldescr' + assert len(op0.args) == 2 + len(expectedkind) def direct_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) From noreply at buildbot.pypy.org Mon Jul 25 18:49:20 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 18:49:20 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: pass also funcbox Message-ID: <20110725164920.CA7E6829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45972:26e58f6d6065 Date: 2011-07-25 18:44 +0200 http://bitbucket.org/pypy/pypy/changeset/26e58f6d6065/ Log: pass also funcbox diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -347,7 +347,8 @@ called_from=self.graph) no = targetgraph.func._jit_unroll_if_const_[0] c_no = Constant(no, lltype.Signed) - op0 = self.rewrite_call(op, 'inline_ifconst_call', [jitcode, c_no]) + op0 = self.rewrite_call(op, 'inline_ifconst_call', [jitcode, c_no, + op.args[0]]) op1 = SpaceOperation('-live-', [], None) return [op0, op1] diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -331,7 +331,8 @@ assert op0.opname == 'inline_ifconst_call_%s_%s' % (expectedkind, reskind) assert op0.args[0] == 'somejitcode' assert op0.args[1].value == 0 - assert len(op0.args) == 2 + len(expectedkind) + assert op0.args[2] == op.args[0] + assert len(op0.args) == 3 + len(expectedkind) def direct_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) From noreply at buildbot.pypy.org Mon Jul 25 18:49:22 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 18:49:22 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: revert last checkin Message-ID: <20110725164922.27FA6829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45973:5d5a76ae6d79 Date: 2011-07-25 18:45 +0200 http://bitbucket.org/pypy/pypy/changeset/5d5a76ae6d79/ Log: revert last checkin diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -347,8 +347,7 @@ called_from=self.graph) no = targetgraph.func._jit_unroll_if_const_[0] c_no = Constant(no, lltype.Signed) - op0 = self.rewrite_call(op, 'inline_ifconst_call', [jitcode, c_no, - op.args[0]]) + op0 = self.rewrite_call(op, 'inline_ifconst_call', [jitcode, c_no]) op1 = SpaceOperation('-live-', [], None) return [op0, op1] diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -331,8 +331,7 @@ assert op0.opname == 'inline_ifconst_call_%s_%s' % (expectedkind, reskind) assert op0.args[0] == 'somejitcode' assert op0.args[1].value == 0 - assert op0.args[2] == op.args[0] - assert len(op0.args) == 3 + len(expectedkind) + assert len(op0.args) == 2 + len(expectedkind) def direct_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) From noreply at buildbot.pypy.org Mon Jul 25 18:49:23 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 18:49:23 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: make this work, mostly boilerplate Message-ID: <20110725164923.93C20829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45974:c44c81b93c25 Date: 2011-07-25 18:49 +0200 http://bitbucket.org/pypy/pypy/changeset/c44c81b93c25/ Log: make this work, mostly boilerplate diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -1035,6 +1035,53 @@ return cpu.bh_call_v(jitcode.get_fnaddr_as_int(), jitcode.calldescr, args_i, args_r, args_f) + @arguments("cpu", "j", "i", "R", returns="i") + def bhimpl_inline_ifconst_call_r_i(cpu, jitcode, no, args_r): + return cpu.bh_call_i(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + None, args_r, None) + @arguments("cpu", "j", "i", "R", returns="r") + def bhimpl_inline_ifconst_call_r_r(cpu, jitcode, no, args_r): + return cpu.bh_call_r(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + None, args_r, None) + @arguments("cpu", "j", "i", "R") + def bhimpl_inline_ifconst_call_r_v(cpu, jitcode, no, args_r): + return cpu.bh_call_v(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + None, args_r, None) + + @arguments("cpu", "j", "i", "I", "R", returns="i") + def bhimpl_inline_ifconst_call_ir_i(cpu, jitcode, no, args_i, args_r): + return cpu.bh_call_i(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + args_i, args_r, None) + @arguments("cpu", "j", "i", "I", "R", returns="r") + def bhimpl_inline_ifconst_call_ir_r(cpu, jitcode, no, args_i, args_r): + return cpu.bh_call_r(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + args_i, args_r, None) + @arguments("cpu", "j", "i", "I", "R") + def bhimpl_inline_ifconst_call_ir_v(cpu, jitcode, no, args_i, args_r): + return cpu.bh_call_v(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + args_i, args_r, None) + + @arguments("cpu", "j", "i", "I", "R", "F", returns="i") + def bhimpl_inline_ifconst_call_irf_i(cpu, jitcode, no, args_i, args_r, + args_f): + return cpu.bh_call_i(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + args_i, args_r, args_f) + @arguments("cpu", "j", "i", "I", "R", "F", returns="r") + def bhimpl_inline_ifconst_call_irf_r(cpu, jitcode, no, args_i, args_r, + args_f): + return cpu.bh_call_r(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + args_i, args_r, args_f) + @arguments("cpu", "j", "i", "I", "R", "F", returns="f") + def bhimpl_inline_ifconst_call_irf_f(cpu, jitcode, no, args_i, args_r, + args_f): + return cpu.bh_call_f(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + args_i, args_r, args_f) + @arguments("cpu", "j", "i", "I", "R", "F") + def bhimpl_inline_ifconst_call_irf_v(cpu, jitcode, no, args_i, args_r, + args_f): + return cpu.bh_call_v(jitcode.get_fnaddr_as_int(), jitcode.calldescr, + args_i, args_r, args_f) + @arguments("cpu", "d", "i", returns="r") def bhimpl_new_array(cpu, arraydescr, length): return cpu.bh_new_array(arraydescr, length) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -751,6 +751,27 @@ opimpl_inline_call_irf_f = _opimpl_inline_call3 opimpl_inline_call_irf_v = _opimpl_inline_call3 + @arguments("jitcode", "int", "boxes") + def _opimpl_inline_ifconst_call1(self, jitcode, no, argboxes): + return self.do_inline_ifconst_call(jitcode, no, argboxes) + @arguments("jitcode", "int", "boxes2") + def _opimpl_inline_ifconst_call2(self, jitcode, no, argboxes): + return self.do_inline_ifconst_call(jitcode, no, argboxes) + @arguments("jitcode", "int", "boxes3") + def _opimpl_inline_ifconst_call3(self, jitcode, no, argboxes): + return self.do_inline_ifconst_call(jitcode, no, argboxes) + + opimpl_inline_ifconst_call_r_i = _opimpl_inline_ifconst_call1 + opimpl_inline_ifconst_call_r_r = _opimpl_inline_ifconst_call1 + opimpl_inline_ifconst_call_r_v = _opimpl_inline_ifconst_call1 + opimpl_inline_ifconst_call_ir_i = _opimpl_inline_ifconst_call2 + opimpl_inline_ifconst_call_ir_r = _opimpl_inline_ifconst_call2 + opimpl_inline_ifconst_call_ir_v = _opimpl_inline_ifconst_call2 + opimpl_inline_ifconst_call_irf_i = _opimpl_inline_ifconst_call3 + opimpl_inline_ifconst_call_irf_r = _opimpl_inline_ifconst_call3 + opimpl_inline_ifconst_call_irf_f = _opimpl_inline_ifconst_call3 + opimpl_inline_ifconst_call_irf_v = _opimpl_inline_ifconst_call3 + @arguments("box", "descr", "boxes") def _opimpl_residual_call1(self, funcbox, calldescr, argboxes): return self.do_residual_or_indirect_call(funcbox, calldescr, argboxes) @@ -1295,6 +1316,14 @@ # but we should not follow calls to that graph return self.do_residual_call(funcbox, calldescr, argboxes) + def do_inline_ifconst_call(self, jitcode, no, argboxes): + if isinstance(argboxes[no], Const): + return self.metainterp.perform_call(jitcode, argboxes) + else: + calldescr = jitcode.calldescr + funcbox = ConstInt(jitcode.get_fnaddr_as_int()) + return self.do_residual_call(funcbox, calldescr, argboxes) + # ____________________________________________________________ class MetaInterpStaticData(object): diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2424,10 +2424,10 @@ res = self.meta_interp(main, [0, 10, 2], enable_opts='') assert res == main(0, 10, 2) - self.check_loops(call=1) + self.check_loops(call_may_force=1) res = self.meta_interp(main, [1, 10, 2], enable_opts='') - assert res == main(0, 10, 2) - self.check_loops(call=0) + assert res == main(1, 10, 2) + self.check_loops(call_may_force=0) class TestOOtype(BasicTests, OOJitMixin): From noreply at buildbot.pypy.org Mon Jul 25 19:20:28 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 19:20:28 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: never print jitcodes on stderr (feel free to complain) Message-ID: <20110725172028.7D01C829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45975:f794b67c9eb6 Date: 2011-07-25 19:20 +0200 http://bitbucket.org/pypy/pypy/changeset/f794b67c9eb6/ Log: never print jitcodes on stderr (feel free to complain) diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -194,8 +194,7 @@ self.make_enter_functions() self.rewrite_jit_merge_points(policy) - verbose = not self.cpu.translate_support_code - self.codewriter.make_jitcodes(verbose=verbose) + self.codewriter.make_jitcodes(verbose=False) self.rewrite_can_enter_jits() self.rewrite_set_param() self.rewrite_force_virtual(vrefinfo) From noreply at buildbot.pypy.org Mon Jul 25 19:30:42 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 19:30:42 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: create some fast paths and add tests Message-ID: <20110725173042.5E870829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45976:dac2fefe4742 Date: 2011-07-25 19:30 +0200 http://bitbucket.org/pypy/pypy/changeset/dac2fefe4742/ Log: create some fast paths and add tests diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py --- a/pypy/rpython/lltypesystem/rbuilder.py +++ b/pypy/rpython/lltypesystem/rbuilder.py @@ -68,6 +68,8 @@ def ll_append(ll_builder, ll_str): used = ll_builder.used lgt = len(ll_str.chars) + if lgt == 0: + return needed = lgt + used if needed > ll_builder.allocated: ll_builder.grow(ll_builder, lgt) @@ -84,6 +86,8 @@ @staticmethod def ll_append_slice(ll_builder, ll_str, start, end): needed = end - start + if needed == 0: + return used = ll_builder.used if needed + used > ll_builder.allocated: ll_builder.grow(ll_builder, needed) @@ -93,6 +97,8 @@ @staticmethod def ll_append_multiple_char(ll_builder, char, times): + if times == 0: + return used = ll_builder.used if times + used > ll_builder.allocated: ll_builder.grow(ll_builder, times) diff --git a/pypy/rpython/test/test_rbuilder.py b/pypy/rpython/test/test_rbuilder.py --- a/pypy/rpython/test/test_rbuilder.py +++ b/pypy/rpython/test/test_rbuilder.py @@ -27,7 +27,9 @@ s.append("a") s.append("abc") s.append_slice("abc", 1, 2) + s.append_slice("abc", 1, 1) s.append_multiple_char('d', 4) + s.append_multiple_char('d', 0) return s.build() res = self.ll_to_string(self.interpret(func, [])) assert res == "aabcbdddd" @@ -36,6 +38,7 @@ def func(): s = StringBuilder(4) s.append("abcd") + s.append("") s.append("defg") s.append("rty") return s.build() @@ -47,6 +50,7 @@ s = UnicodeBuilder() s.append(u'a') s.append(u'abc') + s.append(u'') s.append(u'abcdef') s.append_slice(u'abc', 1, 2) s.append_multiple_char(u'u', 4) From noreply at buildbot.pypy.org Mon Jul 25 19:35:38 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 25 Jul 2011 19:35:38 +0200 (CEST) Subject: [pypy-commit] benchmarks default: bah, -O is a required 'option' Message-ID: <20110725173538.28773829C2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r136:4af8280b2330 Date: 2011-07-25 19:34 +0200 http://bitbucket.org/pypy/benchmarks/changeset/4af8280b2330/ Log: bah, -O is a required 'option' diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -117,7 +117,7 @@ translate_py = relative('lib/pypy/pypy/translator/goal/translate.py') #targetnop = relative('lib/pypy/pypy/translator/goal/targetnopstandalone.py') - args = base_python + [translate_py, '--source', '--dont-write-c-files'] + args = base_python + [translate_py, '--source', '--dont-write-c-files', '-O2'] proc = subprocess.Popen(args, stderr=subprocess.PIPE) out, err = proc.communicate() retcode = proc.poll() From noreply at buildbot.pypy.org Mon Jul 25 19:45:29 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 19:45:29 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: we want quick turnover here, disable stuff Message-ID: <20110725174529.D9071829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45977:e88af6cdf11d Date: 2011-07-25 19:45 +0200 http://bitbucket.org/pypy/pypy/changeset/e88af6cdf11d/ Log: we want quick turnover here, disable stuff diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py --- a/pypy/jit/tl/pypyjit.py +++ b/pypy/jit/tl/pypyjit.py @@ -37,13 +37,13 @@ set_opt_level(config, level='jit') config.objspace.allworkingmodules = False config.objspace.usemodules.pypyjit = True -config.objspace.usemodules.array = True +config.objspace.usemodules.array = False config.objspace.usemodules._weakref = True config.objspace.usemodules._sre = False -config.objspace.usemodules._lsprof = True +config.objspace.usemodules._lsprof = False # -config.objspace.usemodules._ffi = True -config.objspace.usemodules.micronumpy = True +config.objspace.usemodules._ffi = False +config.objspace.usemodules.micronumpy = False # set_pypy_opt_level(config, level='jit') diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -1,9 +1,7 @@ try: - import numpy - a = numpy.array(range(10)) - b = a + a + a - print b[3] + for i in range(1000): + "%d %d" % (i, i) except Exception, e: print "Exception: ", type(e) diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py --- a/pypy/objspace/std/formatting.py +++ b/pypy/objspace/std/formatting.py @@ -4,6 +4,7 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.rarithmetic import ovfcheck from pypy.rlib.rfloat import formatd, DTSF_ALT, isnan, isinf +from pypy.rlib import jit from pypy.interpreter.error import OperationError from pypy.tool.sourcetools import func_with_new_name from pypy.rlib.rstring import StringBuilder, UnicodeBuilder @@ -233,6 +234,7 @@ return w_value + @jit.unroll_safe def peel_flags(self): self.f_ljust = False self.f_sign = False @@ -255,6 +257,7 @@ break self.forward() + @jit.unroll_safe def peel_num(self): space = self.space c = self.peekchr() @@ -276,7 +279,9 @@ c = self.peekchr() return result - def format(self): + # Note: fmt is passed here only to specialize on + @jit.unroll_if_const(1) + def format(self, fmt): lgt = len(self.fmt) + 4 * len(self.values_w) + 10 if do_unicode: result = UnicodeBuilder(lgt) @@ -496,7 +501,7 @@ fmt = space.str_w(w_fmt) formatter = StringFormatter(space, fmt, values_w, w_valuedict) try: - result = formatter.format() + result = formatter.format(fmt) except NeedUnicodeFormattingError: # fall through to the unicode case from pypy.objspace.std.unicodetype import plain_str2unicode @@ -506,7 +511,7 @@ else: fmt = space.unicode_w(w_fmt) formatter = UnicodeFormatter(space, fmt, values_w, w_valuedict) - result = formatter.format() + result = formatter.format(fmt) return space.wrap(result) def mod_format(space, w_format, w_values, do_unicode=False): From noreply at buildbot.pypy.org Mon Jul 25 20:13:10 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 20:13:10 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: all of those can raise MemoryError. Mark it as such Message-ID: <20110725181310.34A6F829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45978:184f09b79158 Date: 2011-07-25 20:13 +0200 http://bitbucket.org/pypy/pypy/changeset/184f09b79158/ Log: all of those can raise MemoryError. Mark it as such diff --git a/pypy/rpython/rbuilder.py b/pypy/rpython/rbuilder.py --- a/pypy/rpython/rbuilder.py +++ b/pypy/rpython/rbuilder.py @@ -12,7 +12,7 @@ v_arg = hop.inputconst(lltype.Signed, INIT_SIZE) else: v_arg = hop.inputarg(lltype.Signed, 0) - hop.exception_cannot_occur() + hop.exception_is_here() return hop.gendirectcall(self.ll_new, v_arg) def rtype_method_append(self, hop): @@ -22,18 +22,18 @@ else: vlist = hop.inputargs(self, self.string_repr) func = self.ll_append - hop.exception_cannot_occur() + hop.exception_is_here() return hop.gendirectcall(func, *vlist) def rtype_method_append_slice(self, hop): vlist = hop.inputargs(self, self.string_repr, lltype.Signed, lltype.Signed) - hop.exception_cannot_occur() + hop.exception_is_here() return hop.gendirectcall(self.ll_append_slice, *vlist) def rtype_method_append_multiple_char(self, hop): vlist = hop.inputargs(self, self.char_repr, lltype.Signed) - hop.exception_cannot_occur() + hop.exception_is_here() return hop.gendirectcall(self.ll_append_multiple_char, *vlist) def rtype_method_getlength(self, hop): @@ -43,5 +43,5 @@ def rtype_method_build(self, hop): vlist = hop.inputargs(self) - hop.exception_cannot_occur() + hop.exception_is_here() return hop.gendirectcall(self.ll_build, *vlist) From noreply at buildbot.pypy.org Mon Jul 25 20:22:05 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 20:22:05 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: split loopless and looping part Message-ID: <20110725182205.C3556829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45979:4f0c816b4e43 Date: 2011-07-25 20:22 +0200 http://bitbucket.org/pypy/pypy/changeset/4f0c816b4e43/ Log: split loopless and looping part diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py --- a/pypy/rpython/lltypesystem/rbuilder.py +++ b/pypy/rpython/lltypesystem/rbuilder.py @@ -95,10 +95,14 @@ ll_str.copy_contents(ll_str, ll_builder.buf, start, used, needed) ll_builder.used = needed + used - @staticmethod - def ll_append_multiple_char(ll_builder, char, times): + @classmethod + def ll_append_multiple_char(cls, ll_builder, char, times): if times == 0: return + cls._ll_append_multiple_char(ll_builder, char, times) + + @staticmethod + def _ll_append_multiple_char(ll_builder, char, times): used = ll_builder.used if times + used > ll_builder.allocated: ll_builder.grow(ll_builder, times) From noreply at buildbot.pypy.org Mon Jul 25 20:35:20 2011 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 25 Jul 2011 20:35:20 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-const: improve the situation where we do "%d" % num in RPython Message-ID: <20110725183520.CDE3E829C2@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: unroll-if-const Changeset: r45980:5b64d3250a30 Date: 2011-07-25 20:35 +0200 http://bitbucket.org/pypy/pypy/changeset/5b64d3250a30/ Log: improve the situation where we do "%d" % num in RPython diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -920,21 +920,9 @@ return string_repr.convert_const(s) ll_constant._annspecialcase_ = 'specialize:memo' - def do_stringformat(cls, hop, sourcevarsrepr): - s_str = hop.args_s[0] - assert s_str.is_constant() - s = s_str.const - things = cls.parse_fmt_string(s) - size = inputconst(Signed, len(things)) # could be unsigned? - cTEMP = inputconst(Void, TEMP) - cflags = inputconst(Void, {'flavor': 'gc'}) - vtemp = hop.genop("malloc_varsize", [cTEMP, cflags, size], - resulttype=Ptr(TEMP)) - - argsiter = iter(sourcevarsrepr) - + @classmethod + def _stringformat_one_elem(cls, thing, argsiter, hop): InstanceRepr = hop.rtyper.type_system.rclass.InstanceRepr - for i, thing in enumerate(things): if isinstance(thing, tuple): code = thing[0] vitem, r_arg = argsiter.next() @@ -962,12 +950,31 @@ else: from pypy.rpython.lltypesystem.rstr import string_repr vchunk = inputconst(string_repr, thing) + return vchunk + + @classmethod + def do_stringformat(cls, hop, sourcevarsrepr): + s_str = hop.args_s[0] + assert s_str.is_constant() + s = s_str.const + things = cls.parse_fmt_string(s) + size = inputconst(Signed, len(things)) # could be unsigned? + cTEMP = inputconst(Void, TEMP) + cflags = inputconst(Void, {'flavor': 'gc'}) + argsiter = iter(sourcevarsrepr) + + if len(things) == 1: + return cls._stringformat_one_elem(things[0], argsiter, hop) + vtemp = hop.genop("malloc_varsize", [cTEMP, cflags, size], + resulttype=Ptr(TEMP)) + + for i, thing in enumerate(things): i = inputconst(Signed, i) + vchunk = cls._stringformat_one_elem(thing, argsiter, hop) hop.genop('setarrayitem', [vtemp, i, vchunk]) hop.exception_cannot_occur() # to ignore the ZeroDivisionError of '%' return hop.gendirectcall(cls.ll_join_strs, size, vtemp) - do_stringformat = classmethod(do_stringformat) TEMP = GcArray(Ptr(STR)) diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -502,6 +502,11 @@ res = self.interpret(moreThanOne, list(args)) assert self.ll_to_string(res) == moreThanOne(*args) + def onething(a): + return const("%x" % a) + res = self.interpret(onething, [10]) + assert self.ll_to_string(res) == onething(10) + def test_strformat_nontuple(self): const = self.const def percentD(i): From noreply at buildbot.pypy.org Mon Jul 25 20:46:23 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 25 Jul 2011 20:46:23 +0200 (CEST) Subject: [pypy-commit] pypy default: Don't emit strsetitem(p0, idx, 0) for freshly allocated strings, they are 0-filled. Message-ID: <20110725184623.6DD13829C2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45981:61e54a11bdfb Date: 2011-07-25 11:46 -0700 http://bitbucket.org/pypy/pypy/changeset/61e54a11bdfb/ Log: Don't emit strsetitem(p0, idx, 0) for freshly allocated strings, they are 0-filled. diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4586,6 +4586,21 @@ """ self.optimize_loop(ops, expected) + def test_null_char_str(self): + ops = """ + [p0] + p1 = newstr(4) + setfield_gc(p0, p1, descr=valuedescr) + jump(p0) + """ + expected = """ + [p0] + p1 = newstr(4) + setfield_gc(p0, p1, descr=valuedescr) + jump(p0) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -1,18 +1,15 @@ +from pypy.jit.codewriter import heaptracker +from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.metainterp.history import (Box, BoxInt, BoxPtr, Const, ConstInt, + ConstPtr, get_const_ptr_for_string, get_const_ptr_for_unicode) +from pypy.jit.metainterp.optimizeopt import optimizer, virtualize +from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1, llhelper +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.rlib.objectmodel import specialize, we_are_translated +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython import annlowlevel from pypy.rpython.lltypesystem import lltype, rstr, llmemory -from pypy.rpython import annlowlevel -from pypy.jit.metainterp.history import Box, BoxInt, BoxPtr -from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr -from pypy.jit.metainterp.history import get_const_ptr_for_string -from pypy.jit.metainterp.history import get_const_ptr_for_unicode -from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt import optimizer, virtualize -from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1 -from pypy.jit.metainterp.optimizeopt.optimizer import llhelper -from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.codewriter import heaptracker -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.objectmodel import specialize, we_are_translated class StrOrUnicode(object): @@ -147,6 +144,7 @@ def string_copy_parts(self, optimizer, targetbox, offsetbox, mode): for i in range(len(self._chars)): charbox = self._chars[i].force_box() + if not (isinstance(charbox, Const) and charbox.same_constant(CONST_0)): optimizer.emit_operation(ResOperation(mode.STRSETITEM, [targetbox, offsetbox, charbox], From noreply at buildbot.pypy.org Mon Jul 25 20:51:57 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Mon, 25 Jul 2011 20:51:57 +0200 (CEST) Subject: [pypy-commit] buildbot default: don't use hg diff -b, it's bad for python Message-ID: <20110725185157.50A64829C2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r539:b5dc7285c406 Date: 2011-07-25 20:51 +0200 http://bitbucket.org/pypy/buildbot/changeset/b5dc7285c406/ Log: don't use hg diff -b, it's bad for python diff --git a/bbhook/scm.py b/bbhook/scm.py --- a/bbhook/scm.py +++ b/bbhook/scm.py @@ -21,7 +21,7 @@ def get_diff(local_repo, hgid): - out = hg('-R', local_repo, 'diff', '-b', '--git', '-c', hgid) + out = hg('-R', local_repo, 'diff', '--git', '-c', hgid) lines = out.splitlines(True) return filter_diff(lines) From noreply at buildbot.pypy.org Mon Jul 25 23:21:29 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:29 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: dont check exact guard number Message-ID: <20110725212129.E7FF1829C3@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45983:05eebbe02d37 Date: 2011-07-24 19:35 +0200 http://bitbucket.org/pypy/pypy/changeset/05eebbe02d37/ Log: dont check exact guard number diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -284,17 +284,17 @@ i20 = force_token() setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) assert loop0.match_by_id('h1', """ i20 = force_token() i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) assert loop0.match_by_id('g2', """ i27 = force_token() i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) # loop1, = log.loops_by_id('g3') @@ -302,12 +302,12 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=) """) def test_stararg(self): From noreply at buildbot.pypy.org Mon Jul 25 23:21:28 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:28 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: nonconstnat index getarrayitem_gc_pure no longer moved across loop boundaries as that might require a bound check Message-ID: <20110725212128.B8F4B829C2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45982:1b29e7b1fdac Date: 2011-07-24 19:31 +0200 http://bitbucket.org/pypy/pypy/changeset/1b29e7b1fdac/ Log: nonconstnat index getarrayitem_gc_pure no longer moved across loop boundaries as that might require a bound check diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -205,6 +205,7 @@ assert log.result == 1000 loop, = log.loops_by_id('call') assert loop.match_by_id('call', """ + p14 = getarrayitem_gc_pure(p8, i9, descr=) i14 = force_token() i16 = force_token() """) From noreply at buildbot.pypy.org Mon Jul 25 23:21:31 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:31 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: generalize the renaming of result boxes on conflicts to support all kind of ops in the short preamble, not only setfields Message-ID: <20110725212131.2DF2F829C4@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45984:f4b02767e294 Date: 2011-07-24 21:22 +0200 http://bitbucket.org/pypy/pypy/changeset/f4b02767e294/ Log: generalize the renaming of result boxes on conflicts to support all kind of ops in the short preamble, not only setfields diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -125,15 +125,9 @@ if op and structvalue in self._cached_fields: if op.getopnum() == rop.SETFIELD_GC: result = op.getarg(1) - if result in shortboxes.potential_ops and \ - shortboxes.potential_ops[result] is None: - newresult = result.clonebox() - optimizer.make_equal_to(newresult, optimizer.getvalue(result)) - result = newresult - # XXX this will not allow for chains of operations getop = ResOperation(rop.GETFIELD_GC, [op.getarg(0)], result, op.getdescr()) - shortboxes.add_potential(getop) + getop = shortboxes.add_potential(getop) self._cached_fields_getfield_op[structvalue] = getop self._cached_fields[structvalue] = optimizer.getvalue(result) elif op.result is not None: diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -899,8 +899,6 @@ setfield_gc(p3, i2, descr=nextdescr) # XXX: VIRTUALHEAP (see above) i3 = getfield_gc(p3, descr=nextdescr) - i7 = int_is_true(i3) - guard_true(i7) [] jump(p3, i3) """ self.optimize_loop(ops, expected, preamble) @@ -2009,15 +2007,14 @@ guard_true(i3) [] i4 = int_neg(i2) setfield_gc(p1, i2, descr=valuedescr) - jump(p1, i1, i2, i4) - """ - expected = """ - [p1, i1, i2, i4] + jump(p1, i1, i2, i4, i4) + """ + expected = """ + [p1, i1, i2, i4, i5] setfield_gc(p1, i1, descr=valuedescr) guard_true(i4) [] - i5 = int_neg(i2) setfield_gc(p1, i2, descr=valuedescr) - jump(p1, i1, i2, i5) + jump(p1, i1, i2, i5, i5) """ self.optimize_loop(ops, expected, preamble) @@ -2040,15 +2037,14 @@ i4 = int_neg(i2) setfield_gc(p1, NULL, descr=nextdescr) escape() - jump(p1, i2, i4) - """ - expected = """ - [p1, i2, i4] + jump(p1, i2, i4, i4) + """ + expected = """ + [p1, i2, i4, i5] guard_true(i4) [p1] - i5 = int_neg(i2) setfield_gc(p1, NULL, descr=nextdescr) escape() - jump(p1, i2, i5) + jump(p1, i2, i5, i5) """ self.optimize_loop(ops, expected, preamble) @@ -2070,15 +2066,14 @@ i4 = int_neg(i2) setfield_gc(p1, NULL, descr=nextdescr) escape() - jump(p1, i2, i4) - """ - expected = """ - [p1, i2, i4] + jump(p1, i2, i4, i4) + """ + expected = """ + [p1, i2, i4, i5] guard_true(i4) [i2, p1] - i5 = int_neg(i2) setfield_gc(p1, NULL, descr=nextdescr) escape() - jump(p1, i2, i5) + jump(p1, i2, i5, i5) """ self.optimize_loop(ops, expected) @@ -2094,15 +2089,22 @@ setfield_gc(p1, i2, descr=valuedescr) jump(p1, i1, i2, i4) """ - preamble = ops - expected = """ - [p1, i1, i2, i4] + preamble = """ + [p1, i1, i2, i3] + setfield_gc(p1, i1, descr=valuedescr) + i5 = int_eq(i3, 5) + guard_true(i5) [] + i4 = int_neg(i2) + setfield_gc(p1, i2, descr=valuedescr) + jump(p1, i1, i2, i4, i4) + """ + expected = """ + [p1, i1, i2, i4, i7] setfield_gc(p1, i1, descr=valuedescr) i5 = int_eq(i4, 5) guard_true(i5) [] - i7 = int_neg(i2) setfield_gc(p1, i2, descr=valuedescr) - jump(p1, i1, i2, i7) + jump(p1, i1, i2, i7, i7) """ self.optimize_loop(ops, expected, preamble) @@ -2323,13 +2325,12 @@ jump(p1, i2, i4, p4) """ expected = """ - [p1, i2, i4, p4] + [p1, i2, i4, p4, i5] guard_true(i4) [p1, p4] - i5 = int_neg(i2) p2 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p2, p4, descr=nextdescr) setfield_gc(p1, p2, descr=nextdescr) - jump(p1, i2, i5, p4) + jump(p1, i2, i5, p4, i5) """ self.optimize_loop(ops, expected, preamble) @@ -5205,7 +5206,6 @@ """ expected = """ [p0] - p1 = getfield_gc(p0, descr=valuedescr) setfield_gc(p0, p0, descr=valuedescr) jump(p0) """ @@ -6216,12 +6216,25 @@ p25 = getfield_gc(ConstPtr(myptr), descr=otherdescr) jump(p25, p187, i184) """ - expected = """ - [p25, p187, i184] - jump(p25, p187, i184) - """ - self.optimize_loop(ops, expected, ops) - # FIXME: check jumparg 0 == getfield_gc() + preamble = """ + [p1, p187, i184] + p188 = getarrayitem_gc(p187, 42, descr=) + guard_value(p188, ConstPtr(myptr)) [] + p25 = getfield_gc(ConstPtr(myptr), descr=otherdescr) + jump(p25, p187, i184, p25) + """ + short = """ + [p1, p187, i184] + p188 = getarrayitem_gc(p187, 42, descr=) + guard_value(p188, ConstPtr(myptr)) [] + p25 = getfield_gc(ConstPtr(myptr), descr=otherdescr) + jump(p1, p187, i184, p25) + """ + expected = """ + [p25, p187, i184, p189] + jump(p189, p187, i184, p189) + """ + self.optimize_loop(ops, expected, preamble, expected_short=short) def test_constant_getfield1bis(self): ops = """ @@ -6305,9 +6318,11 @@ self.optimize_loop(ops, expected) def test_dont_cache_setfields(self): - # Caching the last two getfields here would specialize the loop to the state where - # the first two getfields return the same value. This state needs to be guarded for - # in the short preamble. + # Naivly caching the last two getfields here would specialize + # the loop to the state where the first two getfields return + # the same value. That state would need to be guarded for + # in the short preamble. Instead we make sure to keep the + # results of the two getfields as separate boxes. ops = """ [p0, p1, ii, ii2] i1 = getfield_gc(p0, descr=valuedescr) @@ -6319,14 +6334,21 @@ i5 = getfield_gc(p1, descr=otherdescr) jump(p0, p1, ii2, ii) """ - expected = """ + preamble = """ [p0, p1, ii, ii2] i1 = getfield_gc(p0, descr=valuedescr) i2 = getfield_gc(p1, descr=otherdescr) i3 = int_add(i1, i2) setfield_gc(p0, ii, descr=valuedescr) setfield_gc(p1, ii, descr=otherdescr) - jump(p0, p1, ii2, ii) + jump(p0, p1, ii2, ii, ii, ii) + """ + expected = """ + [p0, p1, ii, ii2, i1, i2] + i3 = int_add(i1, i2) + setfield_gc(p0, ii, descr=valuedescr) + setfield_gc(p1, ii, descr=otherdescr) + jump(p0, p1, ii2, ii, ii, ii) """ self.optimize_loop(ops, expected) @@ -6743,6 +6765,22 @@ """ self.optimize_loop(ops, expected) + def test_keep_getfields_and_inputargs_separate(self): + ops = """ + [p0] + call(p0, descr=nonwritedescr) + p1 = getfield_gc(ConstPtr(myptr), descr=nextdescr) + call(p1, descr=writeadescr) + jump(p1) + """ + expected = """ + [p0, p1] + call(p0, descr=nonwritedescr) + call(p1, descr=writeadescr) + jump(p1, p1) + """ + self.optimize_loop(ops, expected) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -209,7 +209,7 @@ debug_print('inputargs: ' + args) args = ", ".join([logops.repr_of_arg(arg) for arg in short_inputargs]) debug_print('short inputargs: ' + args) - self.short_boxes.debug_print(logops) + self.short_boxes.debug_print(logops) # Force virtuals amoung the jump_args of the preamble to get the # operations needed to setup the proper state of those virtuals @@ -249,7 +249,7 @@ newresult = self.optimizer.getvalue(op.result).get_key_box() if newresult is not op.result: self.short_boxes.alias(newresult, op.result) - + self.optimizer.flush() self.optimizer.emitting_dissabled = False @@ -268,7 +268,8 @@ # preamble_optimizer.send_extra_operation(jumpop) # return loop.inputargs = inputargs - args = [self.short_boxes.original(a) for a in inputargs] + args = [preamble_optimizer.getvalue(self.short_boxes.original(a)).force_box()\ + for a in inputargs] jmp = ResOperation(rop.JUMP, args, None) jmp.setdescr(loop.token) loop.preamble.operations.append(jmp) @@ -376,29 +377,29 @@ i = j = 0 - while i < len(self.optimizer.newoperations): - op = self.optimizer.newoperations[i] - - self.boxes_created_this_iteration[op.result] = True - args = op.getarglist() - if op.is_guard(): - args = args + op.getfailargs() - - if self.optimizer.loop.logops: - debug_print('OP: ' + self.optimizer.loop.logops.repr_of_resop(op)) - for a in args: - if self.optimizer.loop.logops: - debug_print('A: ' + self.optimizer.loop.logops.repr_of_arg(a)) - self.import_box(a, inputargs, short, short_jumpargs, - jumpargs, short_seen) - i += 1 - + while i < len(self.optimizer.newoperations) or j < len(jumpargs): if i == len(self.optimizer.newoperations): while j < len(jumpargs): a = jumpargs[j] self.import_box(a, inputargs, short, short_jumpargs, jumpargs, short_seen) j += 1 + else: + op = self.optimizer.newoperations[i] + + self.boxes_created_this_iteration[op.result] = True + args = op.getarglist() + if op.is_guard(): + args = args + op.getfailargs() + + if self.optimizer.loop.logops: + debug_print('OP: ' + self.optimizer.loop.logops.repr_of_resop(op)) + for a in args: + if self.optimizer.loop.logops: + debug_print('A: ' + self.optimizer.loop.logops.repr_of_arg(a)) + self.import_box(a, inputargs, short, short_jumpargs, + jumpargs, short_seen) + i += 1 jumpop.initarglist(jumpargs) self.optimizer.send_extra_operation(jumpop) @@ -445,6 +446,7 @@ return self.short_inliner.inline_arg(op.result) else: return None + for a in op.getarglist(): if not isinstance(a, Const) and a not in short_seen: self.add_op_to_short(self.short_boxes.producer(a), short, short_seen, @@ -479,7 +481,6 @@ def import_box(self, box, inputargs, short, short_jumpargs, jumpargs, short_seen): - if isinstance(box, Const) or box in inputargs: return if box in self.boxes_created_this_iteration: diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py --- a/pypy/jit/metainterp/optimizeopt/virtualstate.py +++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py @@ -456,12 +456,14 @@ class ShortBoxes(object): def __init__(self, optimizer, surviving_boxes): self.potential_ops = {} + self.duplicates = {} + self.optimizer = optimizer + for box in surviving_boxes: + self.potential_ops[box] = None optimizer.produce_potential_short_preamble_ops(self) self.aliases = {} self.short_boxes = {} - for box in surviving_boxes: - self.short_boxes[box] = None for box in self.potential_ops.keys(): try: @@ -476,14 +478,30 @@ return if box in self.potential_ops: op = self.potential_ops[box] - for arg in op.getarglist(): - self.produce_short_preamble_box(arg) + if op: + for arg in op.getarglist(): + self.produce_short_preamble_box(arg) self.short_boxes[box] = op else: raise BoxNotProducable def add_potential(self, op): - self.potential_ops[op.result] = op + if op.result not in self.potential_ops: + self.potential_ops[op.result] = op + return op + newop = op.clone() + newop.result = op.result.clonebox() + self.potential_ops[newop.result] = newop + if op.result in self.duplicates: + self.duplicates[op.result].append(newop.result) + else: + self.duplicates[op.result] = [newop.result] + self.optimizer.send_extra_operation(newop) + if newop.is_ovf(): + guard = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) + self.optimizer.send_extra_operation(guard) + return newop + def debug_print(self, logops): debug_start('jit-short-boxes') From noreply at buildbot.pypy.org Mon Jul 25 23:21:32 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:32 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: No point in emitting here, all we need is to make the boxes equal. Besides, it might mess up the values we use later Message-ID: <20110725212132.5E2D9829C2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45985:23033be41f5e Date: 2011-07-25 16:03 +0200 http://bitbucket.org/pypy/pypy/changeset/23033be41f5e/ Log: No point in emitting here, all we need is to make the boxes equal. Besides, it might mess up the values we use later diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -185,6 +185,7 @@ modifier = VirtualStateAdder(self.optimizer) virtual_state = modifier.get_virtual_state(jump_args) + values = [self.getvalue(arg) for arg in jump_args] inputargs = virtual_state.make_inputargs(values) short_inputargs = virtual_state.make_inputargs(values, keyboxes=True) diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py --- a/pypy/jit/metainterp/optimizeopt/virtualstate.py +++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py @@ -496,12 +496,8 @@ self.duplicates[op.result].append(newop.result) else: self.duplicates[op.result] = [newop.result] - self.optimizer.send_extra_operation(newop) - if newop.is_ovf(): - guard = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) - self.optimizer.send_extra_operation(guard) + self.optimizer.make_equal_to(newop.result, self.optimizer.getvalue(op.result)) return newop - def debug_print(self, logops): debug_start('jit-short-boxes') From noreply at buildbot.pypy.org Mon Jul 25 23:21:33 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:33 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: fixed test Message-ID: <20110725212133.9ACD2829C2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45986:8bb89c851096 Date: 2011-07-25 18:27 +0200 http://bitbucket.org/pypy/pypy/changeset/8bb89c851096/ Log: fixed test diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -197,8 +197,8 @@ return xy.inst_x res = self.meta_interp(f, [20]) assert res == 134 - self.check_loops(getfield_gc=1, setfield_gc=1) - self.check_loops(getfield_gc=2, setfield_gc=2, everywhere=True) + self.check_loops(getfield_gc=0, setfield_gc=1) + self.check_loops(getfield_gc=1, setfield_gc=2, everywhere=True) # ------------------------------ From noreply at buildbot.pypy.org Mon Jul 25 23:21:39 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:39 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: hg merge c3cdcacec880 Message-ID: <20110725212139.455DB829C2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45987:26de1fba7350 Date: 2011-07-25 19:36 +0200 http://bitbucket.org/pypy/pypy/changeset/26de1fba7350/ Log: hg merge c3cdcacec880 diff too long, truncating to 10000 out of 15314 lines diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,6 +1,7 @@ syntax: glob *.py[co] *~ +.*.swp syntax: regexp ^testresult$ @@ -38,6 +39,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -185,6 +185,7 @@ Jim Baker Philip Jenvey Rodrigo Araújo + Brett Cannon Heinrich-Heine University, Germany Open End AB (formerly AB Strakt), Sweden diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,6 +116,12 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + if "CFLAGS" in os.environ: + cflags = os.environ["CFLAGS"] + compiler.compiler.append(cflags) + compiler.compiler_so.append(cflags) + compiler.linker_so.append(cflags) + from sysconfig_cpython import ( parse_makefile, _variable_rx, expand_makefile_vars) diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib-python/2.7/test/test_tarfile.py b/lib-python/modified-2.7/test/test_tarfile.py copy from lib-python/2.7/test/test_tarfile.py copy to lib-python/modified-2.7/test/test_tarfile.py --- a/lib-python/2.7/test/test_tarfile.py +++ b/lib-python/modified-2.7/test/test_tarfile.py @@ -169,6 +169,7 @@ except tarfile.ReadError: self.fail("tarfile.open() failed on empty archive") self.assertListEqual(tar.getmembers(), []) + tar.close() def test_null_tarfile(self): # Test for issue6123: Allow opening empty archives. @@ -207,16 +208,21 @@ fobj = open(self.tarname, "rb") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, os.path.abspath(fobj.name)) + tar.close() def test_no_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) self.assertRaises(AttributeError, getattr, fobj, "name") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, None) def test_empty_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) fobj.name = "" tar = tarfile.open(fileobj=fobj, mode=self.mode) @@ -515,6 +521,7 @@ self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1") tarinfo = self.tar.getmember("pax/umlauts-�������") self._test_member(tarinfo, size=7011, chksum=md5_regtype) + self.tar.close() class LongnameTest(ReadTest): @@ -675,6 +682,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.rmdir(path) @@ -692,6 +700,7 @@ tar.gettarinfo(target) tarinfo = tar.gettarinfo(link) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(target) os.remove(link) @@ -704,6 +713,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(path) @@ -722,6 +732,7 @@ tar.add(dstname) os.chdir(cwd) self.assertTrue(tar.getnames() == [], "added the archive to itself") + tar.close() def test_exclude(self): tempdir = os.path.join(TEMPDIR, "exclude") @@ -742,6 +753,7 @@ tar = tarfile.open(tmpname, "r") self.assertEqual(len(tar.getmembers()), 1) self.assertEqual(tar.getnames()[0], "empty_dir") + tar.close() finally: shutil.rmtree(tempdir) @@ -859,7 +871,9 @@ fobj.close() elif self.mode.endswith("bz2"): dec = bz2.BZ2Decompressor() - data = open(tmpname, "rb").read() + f = open(tmpname, "rb") + data = f.read() + f.close() data = dec.decompress(data) self.assertTrue(len(dec.unused_data) == 0, "found trailing data") @@ -938,6 +952,7 @@ "unable to read longname member") self.assertEqual(tarinfo.linkname, member.linkname, "unable to read longname member") + tar.close() def test_longname_1023(self): self._test(("longnam/" * 127) + "longnam") @@ -1030,6 +1045,7 @@ else: n = tar.getmembers()[0].name self.assertTrue(name == n, "PAX longname creation failed") + tar.close() def test_pax_global_header(self): pax_headers = { @@ -1058,6 +1074,7 @@ tarfile.PAX_NUMBER_FIELDS[key](val) except (TypeError, ValueError): self.fail("unable to convert pax header field") + tar.close() def test_pax_extended_header(self): # The fields from the pax header have priority over the @@ -1077,6 +1094,7 @@ self.assertEqual(t.pax_headers, pax_headers) self.assertEqual(t.name, "foo") self.assertEqual(t.uid, 123) + tar.close() class UstarUnicodeTest(unittest.TestCase): @@ -1120,6 +1138,7 @@ tarinfo.name = "foo" tarinfo.uname = u"���" self.assertRaises(UnicodeError, tar.addfile, tarinfo) + tar.close() def test_unicode_argument(self): tar = tarfile.open(tarname, "r", encoding="iso8859-1", errors="strict") @@ -1174,6 +1193,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="ascii", errors=handler) self.assertEqual(tar.getnames()[0], name) + tar.close() self.assertRaises(UnicodeError, tarfile.open, tmpname, encoding="ascii", errors="strict") @@ -1186,6 +1206,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="iso8859-1", errors="utf-8") self.assertEqual(tar.getnames()[0], "���/" + u"�".encode("utf8")) + tar.close() class AppendTest(unittest.TestCase): @@ -1213,6 +1234,7 @@ def _test(self, names=["bar"], fileobj=None): tar = tarfile.open(self.tarname, fileobj=fileobj) self.assertEqual(tar.getnames(), names) + tar.close() def test_non_existing(self): self._add_testfile() @@ -1231,7 +1253,9 @@ def test_fileobj(self): self._create_testtar() - data = open(self.tarname).read() + f = open(self.tarname) + data = f.read() + f.close() fobj = StringIO.StringIO(data) self._add_testfile(fobj) fobj.seek(0) @@ -1257,7 +1281,9 @@ # Append mode is supposed to fail if the tarfile to append to # does not end with a zero block. def _test_error(self, data): - open(self.tarname, "wb").write(data) + f = open(self.tarname, "wb") + f.write(data) + f.close() self.assertRaises(tarfile.ReadError, self._add_testfile) def test_null(self): diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -48,7 +48,8 @@ return self.from_param(as_parameter) def get_ffi_param(self, value): - return self.from_param(value)._to_ffi_param() + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() def get_ffi_argtype(self): if self._ffiargtype: @@ -139,7 +140,10 @@ return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -218,5 +222,7 @@ 'z' : _ffi.types.void_p, 'O' : _ffi.types.void_p, 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, } diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -322,20 +322,20 @@ RuntimeWarning, stacklevel=2) if self._com_index: - assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None - - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -343,6 +343,11 @@ if not outargs: return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + if len(outargs) == 1: return outargs[0] return tuple(outargs) @@ -398,10 +403,10 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) cdll = self.dll._handle try: @@ -434,16 +439,15 @@ @classmethod def _conv_param(cls, argtype, arg): if isinstance(argtype, _CDataMeta): - #arg = argtype.from_param(arg) - arg = argtype.get_ffi_param(arg) - return arg, argtype + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - return arg._to_ffi_param(), type(arg) + return arg, arg._to_ffi_param(), type(arg) # # non-usual case: we do the import here to save a lot of code in the # jit trace of the normal case @@ -460,19 +464,16 @@ else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj._to_ffi_param(), type(cobj) + return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] + keepalives = [] newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -496,7 +497,8 @@ val = defval if val is marker: val = 0 - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): @@ -512,28 +514,32 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - newarg, newargtype = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) + keepalive = None newarg = ctypes.byref(val) newargtype = type(newarg) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - newarg, newargtype = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) inargs_idx += 1 @@ -542,12 +548,13 @@ extra = args[len(newargs):] for i, arg in enumerate(extra): try: - newarg, newargtype = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) - return newargs, newargtypes, outargs + return keepalives, newargs, newargtypes, outargs def _wrap_result(self, restype, result): @@ -587,13 +594,7 @@ retval = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, argsandobjs[0]) - else: - retval = int(resbuffer[0]) - elif restype is not None: + if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) @@ -601,7 +602,13 @@ # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value - retval = checker(val) + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) else: diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -216,10 +216,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -27,9 +27,9 @@ PythonPickler.__init__(self, self.__f, args[0], **kw) else: PythonPickler.__init__(self, *args, **kw) - + def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): diff --git a/lib_pypy/pyrepl/unix_console.py b/lib_pypy/pyrepl/unix_console.py --- a/lib_pypy/pyrepl/unix_console.py +++ b/lib_pypy/pyrepl/unix_console.py @@ -384,15 +384,19 @@ self.__maybe_write_code(self._smkx) - self.old_sigwinch = signal.signal( - signal.SIGWINCH, self.__sigwinch) + try: + self.old_sigwinch = signal.signal( + signal.SIGWINCH, self.__sigwinch) + except ValueError: + pass def restore(self): self.__maybe_write_code(self._rmkx) self.flushoutput() tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate) - signal.signal(signal.SIGWINCH, self.old_sigwinch) + if hasattr(self, 'old_sigwinch'): + signal.signal(signal.SIGWINCH, self.old_sigwinch) def __sigwinch(self, signum, frame): self.height, self.width = self.getheightwidth() diff --git a/pypy/config/config.py b/pypy/config/config.py --- a/pypy/config/config.py +++ b/pypy/config/config.py @@ -81,6 +81,12 @@ (self.__class__, name)) return self._cfgimpl_values[name] + def __dir__(self): + from_type = dir(type(self)) + from_dict = list(self.__dict__) + extras = list(self._cfgimpl_values) + return sorted(set(extras + from_type + from_dict)) + def __delattr__(self, name): # XXX if you use delattr you are responsible for all bad things # happening diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -327,6 +327,9 @@ BoolOption("mutable_builtintypes", "Allow the changing of builtin types", default=False, requires=[("objspace.std.builtinshortcut", True)]), + BoolOption("withidentitydict", + "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not", + default=True), ]), ]) diff --git a/pypy/config/support.py b/pypy/config/support.py --- a/pypy/config/support.py +++ b/pypy/config/support.py @@ -9,7 +9,7 @@ return 1 # don't override MAKEFLAGS. This will call 'make' without any '-j' option if sys.platform == 'darwin': return darwin_get_cpu_count() - elif sys.platform != 'linux2': + elif not sys.platform.startswith('linux'): return 1 # implement me try: if isinstance(filename_or_file, str): diff --git a/pypy/config/test/test_config.py b/pypy/config/test/test_config.py --- a/pypy/config/test/test_config.py +++ b/pypy/config/test/test_config.py @@ -63,6 +63,20 @@ py.test.raises(ConfigError, 'config.gc.name = "ref"') config.gc.name = "framework" +def test___dir__(): + descr = make_description() + config = Config(descr, bool=False) + attrs = dir(config) + assert '__repr__' in attrs # from the type + assert '_cfgimpl_values' in attrs # from self + assert 'gc' in attrs # custom attribute + assert 'objspace' in attrs # custom attribute + # + attrs = dir(config.gc) + assert 'name' in attrs + assert 'dummy' in attrs + assert 'float' in attrs + def test_arbitrary_option(): descr = OptionDescription("top", "", [ ArbitraryOption("a", "no help", default=None) diff --git a/pypy/config/test/test_support.py b/pypy/config/test/test_support.py --- a/pypy/config/test/test_support.py +++ b/pypy/config/test/test_support.py @@ -40,7 +40,7 @@ return self._value def test_cpuinfo_linux(): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("linux only") saved = os.environ try: diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -140,7 +140,10 @@ ["annotate", "rtype", "backendopt", "database", "source", "pyjitpl"], default=None, cmdline="--fork-before"), - + BoolOption("dont_write_c_files", + "Make the C backend write everyting to /dev/null. " + + "Useful for benchmarking, so you don't actually involve the disk", + default=False, cmdline="--dont-write-c-files"), ArbitraryOption("instrumentctl", "internal", default=None), StrOption("output", "Output file name", cmdline="--output"), diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -929,6 +929,19 @@ located in the ``py/bin/`` directory. For switches to modify test execution pass the ``-h`` option. +Coverage reports +---------------- + +In order to get coverage reports the `pytest-cov`_ plugin is included. +it adds some extra requirements ( coverage_ and `cov-core`_ ) +and can once they are installed coverage testing can be invoked via:: + + python test_all.py --cov file_or_direcory_to_cover file_or_directory + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov +.. _`coverage`: http://pypi.python.org/pypi/coverage +.. _`cov-core`: http://pypi.python.org/pypi/cov-core + Test conventions ---------------- diff --git a/pypy/doc/config/objspace.std.withidentitydict.txt b/pypy/doc/config/objspace.std.withidentitydict.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withidentitydict.txt @@ -0,0 +1,21 @@ +============================= +objspace.std.withidentitydict +============================= + +* **name:** withidentitydict + +* **description:** enable a dictionary strategy for "by identity" comparisons + +* **command-line:** --objspace-std-withidentitydict + +* **command-line for negation:** --no-objspace-std-withidentitydict + +* **option type:** boolean option + +* **default:** True + + +Enable a dictionary strategy specialized for instances of classes which +compares "by identity", which is the default unless you override ``__hash__``, +``__eq__`` or ``__cmp__``. This strategy will be used only with new-style +classes. diff --git a/pypy/doc/config/translation.dont_write_c_files.txt b/pypy/doc/config/translation.dont_write_c_files.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/translation.dont_write_c_files.txt @@ -0,0 +1,4 @@ +write the generated C files to ``/dev/null`` instead of to the disk. Useful if +you want to use translate.py as a benchmark and don't want to access the disk. + +.. _`translation documentation`: ../translation.html diff --git a/pypy/doc/config/translation.gc.txt b/pypy/doc/config/translation.gc.txt --- a/pypy/doc/config/translation.gc.txt +++ b/pypy/doc/config/translation.gc.txt @@ -1,4 +1,6 @@ -Choose the Garbage Collector used by the translated program: +Choose the Garbage Collector used by the translated program. +The good performing collectors are "hybrid" and "minimark". +The default is "minimark". - "ref": reference counting. Takes very long to translate and the result is slow. @@ -11,3 +13,12 @@ older generation. - "boehm": use the Boehm conservative GC. + + - "hybrid": a hybrid collector of "generation" together with a + mark-n-sweep old space + + - "markcompact": a slow, but memory-efficient collector, + influenced e.g. by Smalltalk systems. + + - "minimark": a generational mark-n-sweep collector with good + performance. Includes page marking for large arrays. diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -211,6 +211,38 @@ >>>> print d1['a'] 42 +Mutating classes of objects which are already used as dictionary keys +--------------------------------------------------------------------- + +Consider the following snippet of code:: + + class X(object): + pass + + def __evil_eq__(self, other): + print 'hello world' + return False + + def evil(y): + d = {x(): 1} + X.__eq__ = __evil_eq__ + d[y] # might trigger a call to __eq__? + +In CPython, __evil_eq__ **might** be called, although there is no way to write +a test which reliably calls it. It happens if ``y is not x`` and ``hash(y) == +hash(x)``, where ``hash(x)`` is computed when ``x`` is inserted into the +dictionary. If **by chance** the condition is satisfied, then ``__evil_eq__`` +is called. + +PyPy uses a special strategy to optimize dictionaries whose keys are instances +of user-defined classes which do not override the default ``__hash__``, +``__eq__`` and ``__cmp__``: when using this strategy, ``__eq__`` and +``__cmp__`` are never called, but instead the lookup is done by identity, so +in the case above it is guaranteed that ``__eq__`` won't be called. + +Note that in all other cases (e.g., if you have a custom ``__hash__`` and +``__eq__`` in ``y``) the behavior is exactly the same as CPython. + Ignored exceptions ----------------------- diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -19,12 +19,12 @@ section * Write them in pure python and use direct libffi low-level bindings, See - \_rawffi_ module description. + \_ffi_ module description. * Write them in RPython as mixedmodule_, using *rffi* as bindings. .. _ctypes: #CTypes -.. _\_rawffi: #LibFFI +.. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules CTypes @@ -42,41 +42,50 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. +ctypes call are optimized by the JIT and the resulting machine code contains a +direct call to the target C function. However, due to the very dynamic nature +of ctypes, some overhead over a bare C call is still present, in particular to +check/convert the types of the parameters. Moreover, even if most calls are +optimized, some cannot and thus need to follow the slow path, not optimized by +the JIT. + .. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure +.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html Pros ---- -Stable, CPython-compatible API +Stable, CPython-compatible API. Most calls are fast, optimized by JIT. Cons ---- -Only pure-python code (slow), problems with platform-dependency (although -we partially solve those). PyPy implementation is now very slow. +Problems with platform-dependency (although we partially solve +those). Although the JIT optimizes ctypes calls, some overhead is still +present. The slow-path is very slow. -_`CPython ctypes`: http://python.net/crew/theller/ctypes/ LibFFI ====== Mostly in order to be able to write a ctypes module, we developed a very -low-level libffi bindings. (libffi is a C-level library for dynamic calling, +low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling, which is used by CPython ctypes). This library provides stable and usable API, although it's API is a very low-level one. It does not contain any -magic. +magic. It is also optimized by the JIT, but has much less overhead than ctypes. Pros ---- -Works. Combines disadvantages of using ctypes with disadvantages of -using mixed modules. Probably more suitable for a delicate code -where ctypes magic goes in a way. +It Works. Probably more suitable for a delicate code where ctypes magic goes +in a way. All calls are optimized by the JIT, there is no slow path as in +ctypes. Cons ---- -Slow. CPython-incompatible API, very rough and low-level +It combines disadvantages of using ctypes with disadvantages of using mixed +modules. CPython-incompatible API, very rough and low-level. Mixed Modules ============= @@ -87,15 +96,15 @@ * a mixed module needs to be written in RPython, which is far more complicated than Python (XXX link) -* due to lack of separate compilation (as of April 2008), each +* due to lack of separate compilation (as of July 2011), each compilation-check requires to recompile whole PyPy python interpreter, which takes 0.5-1h. We plan to solve this at some point in near future. * although rpython is a garbage-collected language, the border between C and RPython needs to be managed by hand (each object that goes into the - C level must be explicitly freed) XXX we try to solve this + C level must be explicitly freed). -Some document is available `here`_ +Some documentation is available `here`_ .. _`here`: rffi.html diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -26,13 +30,6 @@ Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ @@ -289,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -32,6 +32,24 @@ modules that relies on third-party libraries. See below how to get and build them. +Preping Windows for the Large Build +----------------------------------- + +Normally 32bit programs are limited to 2GB of memory on Windows. It is +possible to raise this limit, to 3GB on Windows 32bit, and almost 4GB +on Windows 64bit. + +On Windows 32bit, it is necessary to modify the system: follow +http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 +to enable the "3GB" feature, and reboot. This step is not necessary on +Windows 64bit. + +Then you need to execute:: + + editbin /largeaddressaware pypy.exe + +on the pypy.exe file you compiled. + Installing external packages ---------------------------- diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -2541,8 +2541,9 @@ class ASTVisitor(object): def visit_sequence(self, seq): - for node in seq: - node.walkabout(self) + if seq is not None: + for node in seq: + node.walkabout(self) def default_visitor(self, node): raise NodeVisitorNotImplemented @@ -2673,46 +2674,36 @@ class GenericASTVisitor(ASTVisitor): def visit_Module(self, node): - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_Interactive(self, node): - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_Expression(self, node): node.body.walkabout(self) def visit_Suite(self, node): - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_FunctionDef(self, node): node.args.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.decorator_list: - self.visit_sequence(node.decorator_list) + self.visit_sequence(node.body) + self.visit_sequence(node.decorator_list) def visit_ClassDef(self, node): - if node.bases: - self.visit_sequence(node.bases) - if node.body: - self.visit_sequence(node.body) - if node.decorator_list: - self.visit_sequence(node.decorator_list) + self.visit_sequence(node.bases) + self.visit_sequence(node.body) + self.visit_sequence(node.decorator_list) def visit_Return(self, node): if node.value: node.value.walkabout(self) def visit_Delete(self, node): - if node.targets: - self.visit_sequence(node.targets) + self.visit_sequence(node.targets) def visit_Assign(self, node): - if node.targets: - self.visit_sequence(node.targets) + self.visit_sequence(node.targets) node.value.walkabout(self) def visit_AugAssign(self, node): @@ -2722,37 +2713,29 @@ def visit_Print(self, node): if node.dest: node.dest.walkabout(self) - if node.values: - self.visit_sequence(node.values) + self.visit_sequence(node.values) def visit_For(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.orelse) def visit_While(self, node): node.test.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.orelse) def visit_If(self, node): node.test.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.orelse) def visit_With(self, node): node.context_expr.walkabout(self) if node.optional_vars: node.optional_vars.walkabout(self) - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_Raise(self, node): if node.type: @@ -2763,18 +2746,13 @@ node.tback.walkabout(self) def visit_TryExcept(self, node): - if node.body: - self.visit_sequence(node.body) - if node.handlers: - self.visit_sequence(node.handlers) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.handlers) + self.visit_sequence(node.orelse) def visit_TryFinally(self, node): - if node.body: - self.visit_sequence(node.body) - if node.finalbody: - self.visit_sequence(node.finalbody) + self.visit_sequence(node.body) + self.visit_sequence(node.finalbody) def visit_Assert(self, node): node.test.walkabout(self) @@ -2782,12 +2760,10 @@ node.msg.walkabout(self) def visit_Import(self, node): - if node.names: - self.visit_sequence(node.names) + self.visit_sequence(node.names) def visit_ImportFrom(self, node): - if node.names: - self.visit_sequence(node.names) + self.visit_sequence(node.names) def visit_Exec(self, node): node.body.walkabout(self) @@ -2812,8 +2788,7 @@ pass def visit_BoolOp(self, node): - if node.values: - self.visit_sequence(node.values) + self.visit_sequence(node.values) def visit_BinOp(self, node): node.left.walkabout(self) @@ -2832,35 +2807,28 @@ node.orelse.walkabout(self) def visit_Dict(self, node): - if node.keys: - self.visit_sequence(node.keys) - if node.values: - self.visit_sequence(node.values) + self.visit_sequence(node.keys) + self.visit_sequence(node.values) def visit_Set(self, node): - if node.elts: - self.visit_sequence(node.elts) + self.visit_sequence(node.elts) def visit_ListComp(self, node): node.elt.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_SetComp(self, node): node.elt.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_DictComp(self, node): node.key.walkabout(self) node.value.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_GeneratorExp(self, node): node.elt.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_Yield(self, node): if node.value: @@ -2868,15 +2836,12 @@ def visit_Compare(self, node): node.left.walkabout(self) - if node.comparators: - self.visit_sequence(node.comparators) + self.visit_sequence(node.comparators) def visit_Call(self, node): node.func.walkabout(self) - if node.args: - self.visit_sequence(node.args) - if node.keywords: - self.visit_sequence(node.keywords) + self.visit_sequence(node.args) + self.visit_sequence(node.keywords) if node.starargs: node.starargs.walkabout(self) if node.kwargs: @@ -2902,12 +2867,10 @@ pass def visit_List(self, node): - if node.elts: - self.visit_sequence(node.elts) + self.visit_sequence(node.elts) def visit_Tuple(self, node): - if node.elts: - self.visit_sequence(node.elts) + self.visit_sequence(node.elts) def visit_Const(self, node): pass @@ -2924,8 +2887,7 @@ node.step.walkabout(self) def visit_ExtSlice(self, node): - if node.dims: - self.visit_sequence(node.dims) + self.visit_sequence(node.dims) def visit_Index(self, node): node.value.walkabout(self) @@ -2933,22 +2895,18 @@ def visit_comprehension(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.ifs: - self.visit_sequence(node.ifs) + self.visit_sequence(node.ifs) def visit_ExceptHandler(self, node): if node.type: node.type.walkabout(self) if node.name: node.name.walkabout(self) - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_arguments(self, node): - if node.args: - self.visit_sequence(node.args) - if node.defaults: - self.visit_sequence(node.defaults) + self.visit_sequence(node.args) + self.visit_sequence(node.defaults) def visit_keyword(self, node): node.value.walkabout(self) @@ -3069,6 +3027,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 _Expression_field_unroller = unrolling_iterable(['body']) @@ -3157,6 +3116,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def stmt_get_col_offset(space, w_self): @@ -3178,6 +3138,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask stmt.typedef = typedef.TypeDef("stmt", @@ -3208,6 +3169,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def FunctionDef_get_args(space, w_self): @@ -3229,6 +3191,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 2 def FunctionDef_get_body(space, w_self): @@ -3315,6 +3278,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def ClassDef_get_bases(space, w_self): @@ -3420,6 +3384,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Return_field_unroller = unrolling_iterable(['value']) @@ -3526,6 +3491,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _Assign_field_unroller = unrolling_iterable(['targets', 'value']) @@ -3573,6 +3539,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def AugAssign_get_op(space, w_self): @@ -3590,13 +3557,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def AugAssign_get_value(space, w_self): @@ -3618,6 +3585,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 4 _AugAssign_field_unroller = unrolling_iterable(['target', 'op', 'value']) @@ -3665,6 +3633,7 @@ raise w_self.setdictvalue(space, 'dest', w_new_value) return + w_self.deldictvalue(space, 'dest') w_self.initialization_state |= 1 def Print_get_values(space, w_self): @@ -3704,6 +3673,7 @@ raise w_self.setdictvalue(space, 'nl', w_new_value) return + w_self.deldictvalue(space, 'nl') w_self.initialization_state |= 4 _Print_field_unroller = unrolling_iterable(['dest', 'values', 'nl']) @@ -3752,6 +3722,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def For_get_iter(space, w_self): @@ -3773,6 +3744,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def For_get_body(space, w_self): @@ -3859,6 +3831,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def While_get_body(space, w_self): @@ -3944,6 +3917,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def If_get_body(space, w_self): @@ -4029,6 +4003,7 @@ raise w_self.setdictvalue(space, 'context_expr', w_new_value) return + w_self.deldictvalue(space, 'context_expr') w_self.initialization_state |= 1 def With_get_optional_vars(space, w_self): @@ -4050,6 +4025,7 @@ raise w_self.setdictvalue(space, 'optional_vars', w_new_value) return + w_self.deldictvalue(space, 'optional_vars') w_self.initialization_state |= 2 def With_get_body(space, w_self): @@ -4116,6 +4092,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def Raise_get_inst(space, w_self): @@ -4137,6 +4114,7 @@ raise w_self.setdictvalue(space, 'inst', w_new_value) return + w_self.deldictvalue(space, 'inst') w_self.initialization_state |= 2 def Raise_get_tback(space, w_self): @@ -4158,6 +4136,7 @@ raise w_self.setdictvalue(space, 'tback', w_new_value) return + w_self.deldictvalue(space, 'tback') w_self.initialization_state |= 4 _Raise_field_unroller = unrolling_iterable(['type', 'inst', 'tback']) @@ -4351,6 +4330,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def Assert_get_msg(space, w_self): @@ -4372,6 +4352,7 @@ raise w_self.setdictvalue(space, 'msg', w_new_value) return + w_self.deldictvalue(space, 'msg') w_self.initialization_state |= 2 _Assert_field_unroller = unrolling_iterable(['test', 'msg']) @@ -4464,6 +4445,7 @@ raise w_self.setdictvalue(space, 'module', w_new_value) return + w_self.deldictvalue(space, 'module') w_self.initialization_state |= 1 def ImportFrom_get_names(space, w_self): @@ -4503,6 +4485,7 @@ raise w_self.setdictvalue(space, 'level', w_new_value) return + w_self.deldictvalue(space, 'level') w_self.initialization_state |= 4 _ImportFrom_field_unroller = unrolling_iterable(['module', 'names', 'level']) @@ -4551,6 +4534,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 def Exec_get_globals(space, w_self): @@ -4572,6 +4556,7 @@ raise w_self.setdictvalue(space, 'globals', w_new_value) return + w_self.deldictvalue(space, 'globals') w_self.initialization_state |= 2 def Exec_get_locals(space, w_self): @@ -4593,6 +4578,7 @@ raise w_self.setdictvalue(space, 'locals', w_new_value) return + w_self.deldictvalue(space, 'locals') w_self.initialization_state |= 4 _Exec_field_unroller = unrolling_iterable(['body', 'globals', 'locals']) @@ -4683,6 +4669,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Expr_field_unroller = unrolling_iterable(['value']) @@ -4779,6 +4766,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def expr_get_col_offset(space, w_self): @@ -4800,6 +4788,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask expr.typedef = typedef.TypeDef("expr", @@ -4826,13 +4815,13 @@ try: obj = space.interp_w(boolop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def BoolOp_get_values(space, w_self): @@ -4898,6 +4887,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def BinOp_get_op(space, w_self): @@ -4915,13 +4905,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def BinOp_get_right(space, w_self): @@ -4943,6 +4933,7 @@ raise w_self.setdictvalue(space, 'right', w_new_value) return + w_self.deldictvalue(space, 'right') w_self.initialization_state |= 4 _BinOp_field_unroller = unrolling_iterable(['left', 'op', 'right']) @@ -4986,13 +4977,13 @@ try: obj = space.interp_w(unaryop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def UnaryOp_get_operand(space, w_self): @@ -5014,6 +5005,7 @@ raise w_self.setdictvalue(space, 'operand', w_new_value) return + w_self.deldictvalue(space, 'operand') w_self.initialization_state |= 2 _UnaryOp_field_unroller = unrolling_iterable(['op', 'operand']) @@ -5060,6 +5052,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 1 def Lambda_get_body(space, w_self): @@ -5081,6 +5074,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 _Lambda_field_unroller = unrolling_iterable(['args', 'body']) @@ -5127,6 +5121,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def IfExp_get_body(space, w_self): @@ -5148,6 +5143,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 def IfExp_get_orelse(space, w_self): @@ -5169,6 +5165,7 @@ raise w_self.setdictvalue(space, 'orelse', w_new_value) return + w_self.deldictvalue(space, 'orelse') w_self.initialization_state |= 4 _IfExp_field_unroller = unrolling_iterable(['test', 'body', 'orelse']) @@ -5322,6 +5319,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def ListComp_get_generators(space, w_self): @@ -5387,6 +5385,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def SetComp_get_generators(space, w_self): @@ -5452,6 +5451,7 @@ raise w_self.setdictvalue(space, 'key', w_new_value) return + w_self.deldictvalue(space, 'key') w_self.initialization_state |= 1 def DictComp_get_value(space, w_self): @@ -5473,6 +5473,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 def DictComp_get_generators(space, w_self): @@ -5539,6 +5540,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def GeneratorExp_get_generators(space, w_self): @@ -5604,6 +5606,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Yield_field_unroller = unrolling_iterable(['value']) @@ -5649,6 +5652,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def Compare_get_ops(space, w_self): @@ -5734,6 +5738,7 @@ raise w_self.setdictvalue(space, 'func', w_new_value) return + w_self.deldictvalue(space, 'func') w_self.initialization_state |= 1 def Call_get_args(space, w_self): @@ -5791,6 +5796,7 @@ raise w_self.setdictvalue(space, 'starargs', w_new_value) return + w_self.deldictvalue(space, 'starargs') w_self.initialization_state |= 8 def Call_get_kwargs(space, w_self): @@ -5812,6 +5818,7 @@ raise w_self.setdictvalue(space, 'kwargs', w_new_value) return + w_self.deldictvalue(space, 'kwargs') w_self.initialization_state |= 16 _Call_field_unroller = unrolling_iterable(['func', 'args', 'keywords', 'starargs', 'kwargs']) @@ -5863,6 +5870,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Repr_field_unroller = unrolling_iterable(['value']) @@ -5908,6 +5916,7 @@ raise w_self.setdictvalue(space, 'n', w_new_value) return + w_self.deldictvalue(space, 'n') w_self.initialization_state |= 1 _Num_field_unroller = unrolling_iterable(['n']) @@ -5953,6 +5962,7 @@ raise w_self.setdictvalue(space, 's', w_new_value) return + w_self.deldictvalue(space, 's') w_self.initialization_state |= 1 _Str_field_unroller = unrolling_iterable(['s']) @@ -5998,6 +6008,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Attribute_get_attr(space, w_self): @@ -6019,6 +6030,7 @@ raise w_self.setdictvalue(space, 'attr', w_new_value) return + w_self.deldictvalue(space, 'attr') w_self.initialization_state |= 2 def Attribute_get_ctx(space, w_self): @@ -6036,13 +6048,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Attribute_field_unroller = unrolling_iterable(['value', 'attr', 'ctx']) @@ -6090,6 +6102,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Subscript_get_slice(space, w_self): @@ -6111,6 +6124,7 @@ raise w_self.setdictvalue(space, 'slice', w_new_value) return + w_self.deldictvalue(space, 'slice') w_self.initialization_state |= 2 def Subscript_get_ctx(space, w_self): @@ -6128,13 +6142,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Subscript_field_unroller = unrolling_iterable(['value', 'slice', 'ctx']) @@ -6182,6 +6196,7 @@ raise w_self.setdictvalue(space, 'id', w_new_value) return + w_self.deldictvalue(space, 'id') w_self.initialization_state |= 1 def Name_get_ctx(space, w_self): @@ -6199,13 +6214,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Name_field_unroller = unrolling_iterable(['id', 'ctx']) @@ -6266,13 +6281,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _List_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6334,13 +6349,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Tuple_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6388,6 +6403,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Const_field_unroller = unrolling_iterable(['value']) @@ -6506,6 +6522,7 @@ raise w_self.setdictvalue(space, 'lower', w_new_value) return + w_self.deldictvalue(space, 'lower') w_self.initialization_state |= 1 def Slice_get_upper(space, w_self): @@ -6527,6 +6544,7 @@ raise w_self.setdictvalue(space, 'upper', w_new_value) return + w_self.deldictvalue(space, 'upper') w_self.initialization_state |= 2 def Slice_get_step(space, w_self): @@ -6548,6 +6566,7 @@ raise w_self.setdictvalue(space, 'step', w_new_value) return + w_self.deldictvalue(space, 'step') w_self.initialization_state |= 4 _Slice_field_unroller = unrolling_iterable(['lower', 'upper', 'step']) @@ -6638,6 +6657,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Index_field_unroller = unrolling_iterable(['value']) @@ -6907,6 +6927,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def comprehension_get_iter(space, w_self): @@ -6928,6 +6949,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def comprehension_get_ifs(space, w_self): @@ -6994,6 +7016,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def excepthandler_get_col_offset(space, w_self): @@ -7015,6 +7038,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask excepthandler.typedef = typedef.TypeDef("excepthandler", @@ -7045,6 +7069,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def ExceptHandler_get_name(space, w_self): @@ -7066,6 +7091,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 2 def ExceptHandler_get_body(space, w_self): @@ -7153,6 +7179,7 @@ raise w_self.setdictvalue(space, 'vararg', w_new_value) return + w_self.deldictvalue(space, 'vararg') w_self.initialization_state |= 2 def arguments_get_kwarg(space, w_self): @@ -7177,6 +7204,7 @@ raise w_self.setdictvalue(space, 'kwarg', w_new_value) return + w_self.deldictvalue(space, 'kwarg') w_self.initialization_state |= 4 def arguments_get_defaults(space, w_self): @@ -7245,6 +7273,7 @@ raise w_self.setdictvalue(space, 'arg', w_new_value) return + w_self.deldictvalue(space, 'arg') w_self.initialization_state |= 1 def keyword_get_value(space, w_self): @@ -7266,6 +7295,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _keyword_field_unroller = unrolling_iterable(['arg', 'value']) @@ -7312,6 +7342,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def alias_get_asname(space, w_self): @@ -7336,6 +7367,7 @@ raise w_self.setdictvalue(space, 'asname', w_new_value) return + w_self.deldictvalue(space, 'asname') w_self.initialization_state |= 2 _alias_field_unroller = unrolling_iterable(['name', 'asname']) diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -295,15 +295,11 @@ def visit_FunctionDef(self, func): self.update_position(func.lineno, True) # Load decorators first, but apply them after the function is created. - if func.decorator_list: - self.visit_sequence(func.decorator_list) + self.visit_sequence(func.decorator_list) args = func.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) - num_defaults = len(args.defaults) - else: - num_defaults = 0 + self.visit_sequence(args.defaults) + num_defaults = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(FunctionCodeGenerator, func.name, func, func.lineno) self._make_function(code, num_defaults) @@ -317,24 +313,17 @@ self.update_position(lam.lineno) args = lam.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) - default_count = len(args.defaults) - else: - default_count = 0 + self.visit_sequence(args.defaults) + default_count = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(LambdaCodeGenerator, "", lam, lam.lineno) self._make_function(code, default_count) def visit_ClassDef(self, cls): self.update_position(cls.lineno, True) - if cls.decorator_list: - self.visit_sequence(cls.decorator_list) + self.visit_sequence(cls.decorator_list) self.load_const(self.space.wrap(cls.name)) - if cls.bases: - bases_count = len(cls.bases) - self.visit_sequence(cls.bases) - else: - bases_count = 0 + self.visit_sequence(cls.bases) + bases_count = len(cls.bases) if cls.bases is not None else 0 self.emit_op_arg(ops.BUILD_TUPLE, bases_count) code = self.sub_scope(ClassCodeGenerator, cls.name, cls, cls.lineno) self._make_function(code, 0) @@ -446,8 +435,7 @@ end = self.new_block() test_constant = if_.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if if_.orelse: - self.visit_sequence(if_.orelse) + self.visit_sequence(if_.orelse) elif test_constant == optimize.CONST_TRUE: self.visit_sequence(if_.body) else: @@ -515,16 +503,14 @@ self.use_next_block(cleanup) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, start) - if fr.orelse: - self.visit_sequence(fr.orelse) + self.visit_sequence(fr.orelse) self.use_next_block(end) def visit_While(self, wh): self.update_position(wh.lineno, True) test_constant = wh.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if wh.orelse: - self.visit_sequence(wh.orelse) + self.visit_sequence(wh.orelse) else: end = self.new_block() anchor = None @@ -544,8 +530,7 @@ self.use_next_block(anchor) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, loop) - if wh.orelse: - self.visit_sequence(wh.orelse) + self.visit_sequence(wh.orelse) self.use_next_block(end) def visit_TryExcept(self, te): @@ -581,8 +566,7 @@ self.use_next_block(next_except) self.emit_op(ops.END_FINALLY) self.use_next_block(otherwise) - if te.orelse: - self.visit_sequence(te.orelse) + self.visit_sequence(te.orelse) self.use_next_block(end) def visit_TryFinally(self, tf): @@ -893,27 +877,19 @@ def visit_Tuple(self, tup): self.update_position(tup.lineno) - if tup.elts: - elt_count = len(tup.elts) - else: - elt_count = 0 + elt_count = len(tup.elts) if tup.elts is not None else 0 if tup.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: - self.visit_sequence(tup.elts) + self.visit_sequence(tup.elts) if tup.ctx == ast.Load: self.emit_op_arg(ops.BUILD_TUPLE, elt_count) def visit_List(self, l): self.update_position(l.lineno) - if l.elts: - elt_count = len(l.elts) - else: - elt_count = 0 + elt_count = len(l.elts) if l.elts is not None else 0 if l.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: - self.visit_sequence(l.elts) + self.visit_sequence(l.elts) if l.ctx == ast.Load: self.emit_op_arg(ops.BUILD_LIST, elt_count) @@ -944,11 +920,9 @@ if self._optimize_method_call(call): return call.func.walkabout(self) - arg = 0 + arg = len(call.args) if call.args is not None else 0 call_type = 0 - if call.args: - arg = len(call.args) - self.visit_sequence(call.args) + self.visit_sequence(call.args) if call.keywords: self.visit_sequence(call.keywords) arg |= len(call.keywords) << 8 @@ -984,16 +958,10 @@ assert isinstance(attr_lookup, ast.Attribute) attr_lookup.value.walkabout(self) self.emit_op_name(ops.LOOKUP_METHOD, self.names, attr_lookup.attr) - if call.args: - self.visit_sequence(call.args) - arg_count = len(call.args) - else: - arg_count = 0 - if call.keywords: - self.visit_sequence(call.keywords) - kwarg_count = len(call.keywords) - else: - kwarg_count = 0 + self.visit_sequence(call.args) + arg_count = len(call.args) if call.args is not None else 0 + self.visit_sequence(call.keywords) + kwarg_count = len(call.keywords) if call.keywords is not None else 0 self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) | arg_count) return True @@ -1251,7 +1219,10 @@ def _compile(self, func): assert isinstance(func, ast.FunctionDef) # If there's a docstring, store it as the first constant. - doc_expr = self.possible_docstring(func.body[0]) + if func.body: + doc_expr = self.possible_docstring(func.body[0]) + else: + doc_expr = None if doc_expr is not None: self.add_const(doc_expr.s) start = 1 @@ -1263,8 +1234,9 @@ if args.args: self._handle_nested_args(args.args) self.argcount = len(args.args) - for i in range(start, len(func.body)): - func.body[i].walkabout(self) + if func.body: + for i in range(start, len(func.body)): + func.body[i].walkabout(self) class LambdaCodeGenerator(AbstractFunctionCodeGenerator): diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -27,9 +27,10 @@ _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset) -def parse_future(tree): +def parse_future(tree, feature_flags): future_lineno = 0 future_column = 0 + flags = 0 have_docstring = False body = None if isinstance(tree, ast.Module): @@ -37,7 +38,7 @@ elif isinstance(tree, ast.Interactive): body = tree.body if body is None: - return 0, 0 + return 0, 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): if have_docstring: @@ -48,11 +49,16 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset + for alias in stmt.names: + assert isinstance(alias, ast.alias) + # If this is an invalid flag, it will be caught later in + # codegen.py. + flags |= feature_flags.get(alias.name, 0) else: break else: break - return future_lineno, future_column + return flags, future_lineno, future_column class ForbiddenNameAssignment(Exception): diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py --- a/pypy/interpreter/astcompiler/symtable.py +++ b/pypy/interpreter/astcompiler/symtable.py @@ -356,10 +356,8 @@ # Function defaults and decorators happen in the outer scope. args = func.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) - if func.decorator_list: - self.visit_sequence(func.decorator_list) + self.visit_sequence(args.defaults) + self.visit_sequence(func.decorator_list) new_scope = FunctionScope(func.name, func.lineno, func.col_offset) self.push_scope(new_scope, func) func.args.walkabout(self) @@ -372,10 +370,8 @@ def visit_ClassDef(self, clsdef): self.note_symbol(clsdef.name, SYM_ASSIGNED) - if clsdef.bases: - self.visit_sequence(clsdef.bases) - if clsdef.decorator_list: - self.visit_sequence(clsdef.decorator_list) + self.visit_sequence(clsdef.bases) + self.visit_sequence(clsdef.decorator_list) self.push_scope(ClassScope(clsdef), clsdef) self.visit_sequence(clsdef.body) self.pop_scope() @@ -431,8 +427,7 @@ def visit_Lambda(self, lamb): args = lamb.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) + self.visit_sequence(args.defaults) new_scope = FunctionScope("lambda", lamb.lineno, lamb.col_offset) self.push_scope(new_scope, lamb) lamb.args.walkabout(self) @@ -447,8 +442,7 @@ self.push_scope(new_scope, node) self.implicit_arg(0) outer.target.walkabout(self) - if outer.ifs: - self.visit_sequence(outer.ifs) + self.visit_sequence(outer.ifs) self.visit_sequence(comps[1:]) for item in list(consider): item.walkabout(self) diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -221,8 +221,9 @@ self.emit("class ASTVisitor(object):") self.emit("") self.emit("def visit_sequence(self, seq):", 1) - self.emit("for node in seq:", 2) - self.emit("node.walkabout(self)", 3) + self.emit("if seq is not None:", 2) + self.emit("for node in seq:", 3) + self.emit("node.walkabout(self)", 4) self.emit("") self.emit("def default_visitor(self, node):", 1) self.emit("raise NodeVisitorNotImplemented", 2) @@ -280,15 +281,13 @@ def visitField(self, field): if field.type.value not in asdl.builtin_types and \ field.type.value not in self.data.simple_types: - if field.seq or field.opt: + level = 2 + template = "node.%s.walkabout(self)" + if field.seq: + template = "self.visit_sequence(node.%s)" + elif field.opt: self.emit("if node.%s:" % (field.name,), 2) level = 3 - else: - level = 2 - if field.seq: - template = "self.visit_sequence(node.%s)" - else: - template = "node.%s.walkabout(self)" self.emit(template % (field.name,), level) return True return False @@ -446,6 +445,7 @@ if field.seq: self.emit("w_self.w_%s = w_new_value" % (field.name,), 1) else: + save_original_object = False self.emit("try:", 1) if field.type.value not in asdl.builtin_types: # These are always other AST nodes. @@ -454,9 +454,7 @@ (field.type,), 2) self.emit("w_self.%s = obj.to_simple_int(space)" % (field.name,), 2) - self.emit("# need to save the original object too", 2) - self.emit("w_self.setdictvalue(space, '%s', w_new_value)" - % (field.name,), 2) + save_original_object = True else: config = (field.name, field.type, repr(field.opt)) self.emit("w_self.%s = space.interp_w(%s, w_new_value, %s)" % @@ -480,6 +478,12 @@ self.emit(" w_self.setdictvalue(space, '%s', w_new_value)" % (field.name,), 1) self.emit(" return", 1) + if save_original_object: + self.emit("# need to save the original object too", 1) + self.emit("w_self.setdictvalue(space, '%s', w_new_value)" + % (field.name,), 1) + else: + self.emit("w_self.deldictvalue(space, '%s')" %(field.name,), 1) self.emit("w_self.initialization_state |= %s" % (flag,), 1) self.emit("") diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -44,11 +44,11 @@ return True return False - def deldictvalue(self, space, w_name): + def deldictvalue(self, space, attr): w_dict = self.getdict(space) if w_dict is not None: try: - space.delitem(w_dict, w_name) + space.delitem(w_dict, space.wrap(attr)) return True except OperationError, ex: if not ex.match(space, space.w_KeyError): @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): @@ -237,7 +239,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) @@ -925,6 +927,9 @@ return self.w_True return self.w_False + def issequence_w(self, w_obj): + return (self.findattr(w_obj, self.wrap("__getitem__")) is not None) + def isinstance_w(self, w_obj, w_type): return self.is_true(self.isinstance(w_obj, w_type)) @@ -1279,6 +1284,17 @@ self.wrap("expected a 32-bit integer")) return value + def truncatedint(self, w_obj): + # Like space.gateway_int_w(), but return the integer truncated + # instead of raising OverflowError. For obscure cases only. + try: + return self.int_w(w_obj) + except OperationError, e: + if not e.match(self, self.w_OverflowError): + raise + from pypy.rlib.rarithmetic import intmask + return intmask(self.bigint_w(w_obj).uintmask()) + def c_filedescriptor_w(self, w_fd): # This is only used sometimes in CPython, e.g. for os.fsync() but # not os.close(). It's likely designed for 'select'. It's irregular diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -189,7 +189,7 @@ if space.is_w(w_value, space.w_None): # raise Type: we assume we have to instantiate Type w_value = space.call_function(w_type) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: w_valuetype = space.exception_getclass(w_value) if space.exception_issubclass_w(w_valuetype, w_type): @@ -204,18 +204,12 @@ else: # raise Type, X: assume X is the constructor argument w_value = space.call_function(w_type, w_value) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: # the only case left here is (inst, None), from a 'raise inst'. w_inst = w_type - w_instclass = space.exception_getclass(w_inst) - if not space.exception_is_valid_class_w(w_instclass): - instclassname = w_instclass.getname(space) - msg = ("exceptions must be old-style classes or derived " - "from BaseException, not %s") - raise operationerrfmt(space.w_TypeError, msg, instclassname) - + w_instclass = self._exception_getclass(space, w_inst) if not space.is_w(w_value, space.w_None): raise OperationError(space.w_TypeError, space.wrap("instance exception may not " @@ -226,6 +220,15 @@ self.w_type = w_type self._w_value = w_value + def _exception_getclass(self, space, w_inst): + w_type = space.exception_getclass(w_inst) + if not space.exception_is_valid_class_w(w_type): + typename = w_type.getname(space) + msg = ("exceptions must be old-style classes or derived " + "from BaseException, not %s") + raise operationerrfmt(space.w_TypeError, msg, typename) + return w_type + def write_unraisable(self, space, where, w_object=None): if w_object is None: objrepr = '' diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -31,7 +31,8 @@ _immutable_fields_ = ['code?', 'w_func_globals?', 'closure?', - 'defs_w?[*]'] + 'defs_w?[*]', + 'name?'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -140,6 +140,9 @@ def visit_c_nonnegint(self, el, app_sig): self.checked_space_method(el, app_sig) + def visit_truncatedint(self, el, app_sig): + self.checked_space_method(el, app_sig) + def visit__Wrappable(self, el, app_sig): name = el.__name__ argname = self.orig_arg() @@ -257,6 +260,9 @@ def visit_c_nonnegint(self, typ): self.run_args.append("space.c_nonnegint_w(%s)" % (self.scopenext(),)) + def visit_truncatedint(self, typ): + self.run_args.append("space.truncatedint(%s)" % (self.scopenext(),)) + def _make_unwrap_activation_class(self, unwrap_spec, cache={}): try: key = tuple(unwrap_spec) @@ -387,6 +393,9 @@ def visit_c_nonnegint(self, typ): self.unwrap.append("space.c_nonnegint_w(%s)" % (self.nextarg(),)) + def visit_truncatedint(self, typ): + self.unwrap.append("space.truncatedint(%s)" % (self.nextarg(),)) + def make_fastfunc(unwrap_spec, func): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) @@ -396,11 +405,14 @@ fastfunc = func else: # try to avoid excessive bloat - if func.__module__ == 'pypy.interpreter.astcompiler.ast': + mod = func.__module__ + if mod is None: + mod = "" + if mod == 'pypy.interpreter.astcompiler.ast': raise FastFuncNotSupported - if (not func.__module__.startswith('pypy.module.__builtin__') and - not func.__module__.startswith('pypy.module.sys') and - not func.__module__.startswith('pypy.module.math')): + if (not mod.startswith('pypy.module.__builtin__') and + not mod.startswith('pypy.module.sys') and + not mod.startswith('pypy.module.math')): if not func.__name__.startswith('descr'): raise FastFuncNotSupported d = {} diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,10 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - future_pos = misc.parse_future(node) + fut = misc.parse_future(node, self.future_flags.compiler_features) + f_flags, f_lineno, f_col = fut + future_pos = f_lineno, f_col + flags |= f_flags info = pyparse.CompileInfo(filename, mode, flags, future_pos) return self._compile_ast(node, info) diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -905,16 +905,15 @@ def SETUP_WITH(self, offsettoend, next_instr): w_manager = self.peekvalue() + w_enter = self.space.lookup(w_manager, "__enter__") w_descr = self.space.lookup(w_manager, "__exit__") - if w_descr is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__exit__")) + if w_enter is None or w_descr is None: + typename = self.space.type(w_manager).getname(self.space) + raise operationerrfmt(self.space.w_AttributeError, + "'%s' object is not a context manager" + " (no __enter__/__exit__ method)", typename) w_exit = self.space.get(w_descr, w_manager) self.settopvalue(w_exit) - w_enter = self.space.lookup(w_manager, "__enter__") - if w_enter is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__enter__")) w_result = self.space.get_and_call_function(w_enter, w_manager) block = WithBlock(self, next_instr + offsettoend) self.append_block(block) diff --git a/pypy/interpreter/test/test_raise.py b/pypy/interpreter/test/test_raise.py --- a/pypy/interpreter/test/test_raise.py +++ b/pypy/interpreter/test/test_raise.py @@ -274,3 +274,9 @@ pass except A: pass + + def test_new_returns_bad_instance(self): + class MyException(Exception): + def __new__(cls, *args): + return object() + raises(TypeError, "raise MyException") diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -23,7 +23,7 @@ self.hasdict |= __base.hasdict self.weakrefable |= __base.weakrefable self.rawdict = {} - self.acceptable_as_base_class = True + self.acceptable_as_base_class = '__new__' in rawdict self.applevel_subclasses_base = None # xxx used by faking self.fakedcpytype = None @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) - if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') + if parent_destructor is not None: + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -858,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -453,21 +453,33 @@ class WriteBarrierDescr(AbstractDescr): def __init__(self, gc_ll_descr): + GCClass = gc_ll_descr.GCClass self.llop1 = gc_ll_descr.llop1 self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR - self.fielddescr_tid = get_field_descr(gc_ll_descr, - gc_ll_descr.GCClass.HDR, 'tid') - self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG - # if convenient for the backend, we also compute the info about + self.fielddescr_tid = get_field_descr(gc_ll_descr, GCClass.HDR, 'tid') + # + self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG + self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = ( + self.extract_flag_byte(self.jit_wb_if_flag)) + # + if hasattr(GCClass, 'JIT_WB_CARDS_SET'): + self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET + self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT + self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = ( + self.extract_flag_byte(self.jit_wb_cards_set)) + else: + self.jit_wb_cards_set = 0 + + def extract_flag_byte(self, flag_word): + # if convenient for the backend, we compute the info about # the flag as (byte-offset, single-byte-flag). import struct - value = struct.pack("l", self.jit_wb_if_flag) + value = struct.pack("l", flag_word) assert value.count('\x00') == len(value) - 1 # only one byte is != 0 i = 0 while value[i] == '\x00': i += 1 - self.jit_wb_if_flag_byteofs = i - self.jit_wb_if_flag_singlebyte = struct.unpack('b', value[i])[0] + return (i, struct.unpack('b', value[i])[0]) def get_write_barrier_fn(self, cpu): llop1 = self.llop1 diff --git a/pypy/jit/backend/llvm/llvm_rffi.py b/pypy/jit/backend/llvm/llvm_rffi.py --- a/pypy/jit/backend/llvm/llvm_rffi.py +++ b/pypy/jit/backend/llvm/llvm_rffi.py @@ -3,7 +3,7 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo, log -if sys.platform != 'linux2': +if not sys.platform.startswith('linux'): py.test.skip("Linux only for now") # ____________________________________________________________ diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -1707,6 +1707,7 @@ jit_wb_if_flag = 4096 jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 0 def get_write_barrier_from_array_fn(self, cpu): return funcbox.getint() # @@ -1728,6 +1729,72 @@ else: assert record == [] + def test_cond_call_gc_wb_array_card_marking_fast_path(self): + def func_void(a, b, c): + record.append((a, b, c)) + record = [] + # + S = lltype.Struct('S', ('tid', lltype.Signed)) + S_WITH_CARDS = lltype.Struct('S_WITH_CARDS', + ('card0', lltype.Char), + ('card1', lltype.Char), + ('card2', lltype.Char), + ('card3', lltype.Char), + ('card4', lltype.Char), + ('card5', lltype.Char), + ('card6', lltype.Char), + ('card7', lltype.Char), + ('data', S)) + FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)], + lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + funcbox = self.get_funcbox(self.cpu, func_ptr) + class WriteBarrierDescr(AbstractDescr): + jit_wb_if_flag = 4096 + jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') + jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 8192 + jit_wb_cards_set_byteofs = struct.pack("i", 8192).index('\x20') + jit_wb_cards_set_singlebyte = 0x20 + jit_wb_card_page_shift = 7 + def get_write_barrier_from_array_fn(self, cpu): + return funcbox.getint() + # + for BoxIndexCls in [BoxInt, ConstInt]: + for cond in [False, True]: + print + print '_'*79 + print 'BoxIndexCls =', BoxIndexCls + print 'JIT_WB_CARDS_SET =', cond + print + value = random.randrange(-sys.maxint, sys.maxint) + value |= 4096 + if cond: + value |= 8192 + else: + value &= ~8192 + s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True) + s.data.tid = value + sgcref = rffi.cast(llmemory.GCREF, s.data) + del record[:] + box_index = BoxIndexCls((9<<7) + 17) + self.execute_operation(rop.COND_CALL_GC_WB_ARRAY, + [BoxPtr(sgcref), box_index, BoxPtr(sgcref)], + 'void', descr=WriteBarrierDescr()) + if cond: + assert record == [] + assert s.card6 == '\x02' + else: + assert record == [(s.data, (9<<7) + 17, s.data)] + assert s.card6 == '\x00' + assert s.card0 == '\x00' + assert s.card1 == '\x00' + assert s.card2 == '\x00' + assert s.card3 == '\x00' + assert s.card4 == '\x00' + assert s.card5 == '\x00' + assert s.card7 == '\x00' + def test_force_operations_returning_void(self): values = [] def maybe_force(token, flag): diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -416,10 +416,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -478,9 +481,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d has address %x to %x" % + debug_start("jit-backend-addr") + debug_print("bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -2242,10 +2246,12 @@ if opnum == rop.COND_CALL_GC_WB: N = 2 func = descr.get_write_barrier_fn(self.cpu) + card_marking = False elif opnum == rop.COND_CALL_GC_WB_ARRAY: N = 3 func = descr.get_write_barrier_from_array_fn(self.cpu) assert func != 0 + card_marking = descr.jit_wb_cards_set != 0 else: raise AssertionError(opnum) # @@ -2254,6 +2260,18 @@ imm(descr.jit_wb_if_flag_singlebyte)) self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later jz_location = self.mc.get_relative_pos() + + # for cond_call_gc_wb_array, also add another fast path: + # if GCFLAG_CARDS_SET, then we can just set one bit and be done + if card_marking: + self.mc.TEST8(addr_add_const(loc_base, + descr.jit_wb_cards_set_byteofs), + imm(descr.jit_wb_cards_set_singlebyte)) + self.mc.J_il8(rx86.Conditions['NZ'], 0) # patched later + jnz_location = self.mc.get_relative_pos() + else: + jnz_location = 0 + # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. if IS_X86_32: @@ -2293,6 +2311,43 @@ loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) + + # if GCFLAG_CARDS_SET, then we can do the whole thing that would + # be done in the CALL above with just four instructions, so here + # is an inline copy of them + if card_marking: + self.mc.JMP_l8(0) # jump to the exit, patched later + jmp_location = self.mc.get_relative_pos() + # patch the JNZ above + offset = self.mc.get_relative_pos() - jnz_location + assert 0 < offset <= 127 + self.mc.overwrite(jnz_location-1, chr(offset)) + # + loc_index = arglocs[1] + if isinstance(loc_index, RegLoc): + # choose a scratch register + tmp1 = loc_index + self.mc.PUSH_r(tmp1.value) + # SHR tmp, card_page_shift + self.mc.SHR_ri(tmp1.value, descr.jit_wb_card_page_shift) + # XOR tmp, -8 + self.mc.XOR_ri(tmp1.value, -8) + # BTS [loc_base], tmp + self.mc.BTS(addr_add_const(loc_base, 0), tmp1) + # done + self.mc.POP_r(tmp1.value) + elif isinstance(loc_index, ImmedLoc): + byte_index = loc_index.value >> descr.jit_wb_card_page_shift + byte_ofs = ~(byte_index >> 3) + byte_val = 1 << (byte_index & 7) + self.mc.OR8(addr_add_const(loc_base, byte_ofs), imm(byte_val)) + else: + raise AssertionError("index is neither RegLoc nor ImmedLoc") + # patch the JMP above + offset = self.mc.get_relative_pos() - jmp_location + assert 0 < offset <= 127 + self.mc.overwrite(jmp_location-1, chr(offset)) + # # patch the JZ above offset = self.mc.get_relative_pos() - jz_location assert 0 < offset <= 127 diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -476,6 +476,7 @@ AND = _binaryop('AND') OR = _binaryop('OR') + OR8 = _binaryop('OR8') XOR = _binaryop('XOR') NOT = _unaryop('NOT') SHL = _binaryop('SHL') @@ -483,6 +484,7 @@ SAR = _binaryop('SAR') TEST = _binaryop('TEST') TEST8 = _binaryop('TEST8') + BTS = _binaryop('BTS') ADD = _binaryop('ADD') SUB = _binaryop('SUB') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -464,7 +464,7 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ @@ -496,6 +496,10 @@ AND8_rr = insn(rex_fw, '\x20', byte_register(1), byte_register(2,8), '\xC0') OR8_rr = insn(rex_fw, '\x08', byte_register(1), byte_register(2,8), '\xC0') + OR8_mi = insn(rex_fw, '\x80', orbyte(1<<3), mem_reg_plus_const(1), + immediate(2, 'b')) + OR8_ji = insn(rex_fw, '\x80', orbyte(1<<3), abs_, immediate(1), + immediate(2, 'b')) NEG_r = insn(rex_w, '\xF7', register(1), '\xD8') @@ -565,6 +569,9 @@ TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_, immediate(1), immediate(2, 'b')) TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0') + BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1)) + BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_, immediate(1)) + # x87 instructions FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) @@ -632,16 +639,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): @@ -44,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -58,10 +63,15 @@ expected = "\xE8" + struct.pack(' movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -524,6 +524,76 @@ def test_compile_framework_8(self): self.run('compile_framework_8') + def define_compile_framework_9(cls): + # Like compile_framework_8, but with variable indexes and large + # arrays, testing the card_marking case + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + num = 512 + (n & 7) + l = [None] * num + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[num-8] = X(n+70) + l[num-9] = X(n+80) + l[num-10] = X(n+90) + l[num-11] = X(n+100) + l[-12] = X(n+110) + l[-13] = X(n+120) + l[-14] = X(n+130) + l[-15] = X(n+140) + if n < 1800: + num = 512 + (n & 7) + check(len(l) == num) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[num-8].x == n+70) + check(l[num-9].x == n+80) + check(l[num-10].x == n+90) + check(l[num-11].x == n+100) + check(l[-12].x == n+110) + check(l[-13].x == n+120) + check(l[-14].x == n+130) + check(l[-15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 512) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[-8].x == 72) + check(l[-9].x == 82) + check(l[-10].x == 92) + check(l[-11].x == 102) + check(l[-12].x == 112) + check(l[-13].x == 122) + check(l[-14].x == 132) + check(l[-15].x == 142) + return before, f, after + + def test_compile_framework_9(self): + self.run('compile_framework_9') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -5,10 +5,9 @@ from pypy.jit.codewriter import support from pypy.jit.codewriter.jitcode import JitCode -from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer -from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer -from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze -from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection +from pypy.jit.codewriter.effectinfo import (VirtualizableAnalyzer, + QuasiImmutAnalyzer, CanReleaseGILAnalyzer, effectinfo_from_writeanalyze, + EffectInfo, CallInfoCollection) from pypy.translator.simplify import get_funcobj, get_functype from pypy.rpython.lltypesystem import lltype, llmemory from pypy.translator.backendopt.canraise import RaiseAnalyzer @@ -32,6 +31,7 @@ self.readwrite_analyzer = ReadWriteAnalyzer(translator) self.virtualizable_analyzer = VirtualizableAnalyzer(translator) self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator) + self.canreleasegil_analyzer = CanReleaseGILAnalyzer(translator) # for index, jd in enumerate(jitdrivers_sd): jd.index = index @@ -219,7 +219,9 @@ assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect - can_invalidate = self.quasiimmut_analyzer.analyze(op) + can_release_gil = self.canreleasegil_analyzer.analyze(op) + # can_release_gil implies can_invalidate + can_invalidate = can_release_gil or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE @@ -235,7 +237,7 @@ # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, - oopspecindex, can_invalidate) + oopspecindex, can_invalidate, can_release_gil) # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -79,13 +79,15 @@ write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, - can_invalidate=False): + can_invalidate=False, can_release_gil=False): key = (frozenset(readonly_descrs_fields), frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, - oopspecindex) + oopspecindex, + can_invalidate, + can_release_gil) if key in cls._cache: return cls._cache[key] result = object.__new__(cls) @@ -100,6 +102,7 @@ result.write_descrs_arrays = write_descrs_arrays result.extraeffect = extraeffect result.can_invalidate = can_invalidate + result.can_release_gil = can_release_gil result.oopspecindex = oopspecindex cls._cache[key] = result return result @@ -111,12 +114,13 @@ return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE def has_random_effects(self): - return self.oopspecindex == self.OS_LIBFFI_CALL + return self.oopspecindex == self.OS_LIBFFI_CALL or self.can_release_gil def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, - can_invalidate=False): + can_invalidate=False, + can_release_gil=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: return None @@ -158,7 +162,8 @@ write_descrs_arrays, extraeffect, oopspecindex, - can_invalidate) + can_invalidate, + can_release_gil) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: @@ -194,6 +199,16 @@ def analyze_simple_operation(self, op, graphinfo): return op.opname == 'jit_force_quasi_immutable' +class CanReleaseGILAnalyzer(BoolGraphAnalyzer): + def analyze_direct_call(self, graph, seen=None): + releases_gil = False + if hasattr(graph, "func") and hasattr(graph.func, "_ptr"): + releases_gil = graph.func._ptr._obj.releases_gil + return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen) + + def analyze_simple_operation(self, op, graphinfo): + return False + # ____________________________________________________________ class CallInfoCollection(object): diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -765,13 +765,65 @@ raise NotImplementedError("cast_ptr_to_int") def rewrite_op_force_cast(self, op): - from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof + assert not self._is_gc(op.args[0]) + fromll = longlong.is_longlong(op.args[0].concretetype) + toll = longlong.is_longlong(op.result.concretetype) + if fromll and toll: + return + if fromll: + args = op.args + opname = 'truncate_longlong_to_int' + RESULT = lltype.Signed + v = varoftype(RESULT) + op1 = SpaceOperation(opname, args, v) + op2 = self.rewrite_operation(op1) + oplist = self.force_cast_without_longlong(op2.result, op.result) + if oplist: + return [op2] + oplist + # + # force a renaming to put the correct result in place, even though + # it might be slightly mistyped (e.g. Signed versus Unsigned) + assert op2.result is v + op2.result = op.result + return op2 + elif toll: + from pypy.rpython.lltypesystem import rffi + size, unsigned = rffi.size_and_sign(op.args[0].concretetype) + if unsigned: + INTERMEDIATE = lltype.Unsigned + else: + INTERMEDIATE = lltype.Signed + v = varoftype(INTERMEDIATE) + oplist = self.force_cast_without_longlong(op.args[0], v) + if not oplist: + v = op.args[0] + oplist = [] + if unsigned: + opname = 'cast_uint_to_longlong' + else: + opname = 'cast_int_to_longlong' + op1 = SpaceOperation(opname, [v], op.result) + op2 = self.rewrite_operation(op1) + return oplist + [op2] + else: + return self.force_cast_without_longlong(op.args[0], op.result) + + def force_cast_without_longlong(self, v_arg, v_result): + from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT from pypy.rlib.rarithmetic import intmask - assert not self._is_gc(op.args[0]) - size2, unsigned2 = size_and_sign(op.result.concretetype) - if size2 >= sizeof(lltype.Signed): + # + if (v_result.concretetype in (FLOAT, lltype.Float) or + v_arg.concretetype in (FLOAT, lltype.Float)): + assert (v_result.concretetype == lltype.Float and + v_arg.concretetype == lltype.Float), "xxx unsupported cast" + return + # + size2, unsigned2 = size_and_sign(v_result.concretetype) + assert size2 <= sizeof(lltype.Signed) + if size2 == sizeof(lltype.Signed): return # the target type is LONG or ULONG - size1, unsigned1 = size_and_sign(op.args[0].concretetype) + size1, unsigned1 = size_and_sign(v_arg.concretetype) + assert size1 <= sizeof(lltype.Signed) # def bounds(size, unsigned): if unsigned: @@ -784,22 +836,28 @@ return # the target type includes the source range # result = [] - v1 = op.args[0] if min2: c_min2 = Constant(min2, lltype.Signed) - v2 = Variable(); v2.concretetype = lltype.Signed - result.append(SpaceOperation('int_sub', [v1, c_min2], v2)) + v2 = varoftype(lltype.Signed) + result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2)) else: - v2 = v1 + v2 = v_arg c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed) - v3 = Variable(); v3.concretetype = lltype.Signed + v3 = varoftype(lltype.Signed) result.append(SpaceOperation('int_and', [v2, c_mask], v3)) if min2: - result.append(SpaceOperation('int_add', [v3, c_min2], op.result)) + result.append(SpaceOperation('int_add', [v3, c_min2], v_result)) else: - result[-1].result = op.result + result[-1].result = v_result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from @@ -883,30 +941,7 @@ rewrite_op_ullong_is_true = rewrite_op_llong_is_true def rewrite_op_cast_primitive(self, op): - fromll = longlong.is_longlong(op.args[0].concretetype) - toll = longlong.is_longlong(op.result.concretetype) - if fromll != toll: - args = op.args - if fromll: - opname = 'truncate_longlong_to_int' - RESULT = lltype.Signed - else: - from pypy.rpython.lltypesystem import rffi - if rffi.cast(op.args[0].concretetype, -1) < 0: - opname = 'cast_int_to_longlong' - else: - opname = 'cast_uint_to_longlong' - RESULT = lltype.SignedLongLong - v = varoftype(RESULT) - op1 = SpaceOperation(opname, args, v) - op2 = self.rewrite_operation(op1) - # - # force a renaming to put the correct result in place, even though - # it might be slightly mistyped (e.g. Signed versus Unsigned) - assert op2.result is v - op2.result = op.result - # - return op2 + return self.rewrite_op_force_cast(op) # ---------- # Renames, from the _old opname to the _new one. @@ -1083,6 +1118,9 @@ return meth(op, args, *descrs) def _get_list_nonneg_canraise_flags(self, op): + # XXX as far as I can see, this function will always return True + # because functions that are neither nonneg nor fast don't have an + # oopspec any more # xxx break of abstraction: func = get_funcobj(op.args[0].value)._callable # base hints on the name of the ll function, which is a bit xxx-ish @@ -1240,7 +1278,7 @@ calldescr = self.callcontrol.getcalldescr(op, oopspecindex, extraeffect) if extraeffect is not None: - assert (type(calldescr) is str # for tests + assert (is_test_calldescr(calldescr) # for tests or calldescr.get_extra_info().extraeffect == extraeffect) if isinstance(op.args[0].value, str): pass # for tests only @@ -1401,6 +1439,9 @@ return "using virtualizable array in illegal way in %r" % ( self.args[0],) +def is_test_calldescr(calldescr): + return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False) + def _with_prefix(prefix): result = {} for name in dir(Transformer): diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -96,6 +96,7 @@ def _try_coalesce(self, v, w): if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: + assert getkind(w.concretetype) == self.kind dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -185,7 +185,7 @@ return llop.int_floordiv(lltype.Signed, x, y) def _ll_2_int_floordiv_ovf(x, y): - if x == -sys.maxint - 1 and y == -1: + if x == -sys.maxint - 1 and y == -1: raise OverflowError return llop.int_floordiv(lltype.Signed, x, y) @@ -222,7 +222,7 @@ return -x else: return x - + # math support # ------------ @@ -395,7 +395,7 @@ ('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed), ('int_abs', [lltype.Signed], lltype.Signed), ('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float), - ] +] class LLtypeHelpers: diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py --- a/pypy/jit/codewriter/test/test_call.py +++ b/pypy/jit/codewriter/test/test_call.py @@ -1,6 +1,6 @@ import py from pypy.objspace.flow.model import SpaceOperation, Constant, Variable -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.unsimplify import varoftype from pypy.rlib import jit from pypy.jit.codewriter.call import CallControl @@ -103,7 +103,7 @@ op = SpaceOperation('direct_call', [Constant(object())], Variable()) - assert cc.guess_call_kind(op) == 'residual' + assert cc.guess_call_kind(op) == 'residual' class funcptr: class graph: @@ -118,7 +118,7 @@ op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) - assert res == [g] + assert res == [g] assert cc.guess_call_kind(op) == 'regular' class funcptr: @@ -126,7 +126,7 @@ op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) - assert res is None + assert res is None assert cc.guess_call_kind(op) == 'residual' h = object() @@ -142,7 +142,7 @@ Variable()) res = cc.graphs_from(op) assert res is None - assert cc.guess_call_kind(op) == 'residual' + assert cc.guess_call_kind(op) == 'residual' # ____________________________________________________________ @@ -171,3 +171,24 @@ def test_jit_force_virtualizable_effectinfo(): py.test.skip("XXX add a test for CallControl.getcalldescr() -> EF_xxx") + +def test_releases_gil_analyzer(): + from pypy.jit.backend.llgraph.runner import LLtypeCPU + + T = rffi.CArrayPtr(rffi.TIME_T) + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + + @jit.dont_look_inside + def f(): + return external(lltype.nullptr(T.TO)) + + rtyper = support.annotate(f, []) + jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) + cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) + res = cc.find_all_graphs(FakePolicy()) + + [f_graph] = [x for x in res if x.func is f] + [block, _] = list(f_graph.iterblocks()) + [op] = block.operations + call_descr = cc.getcalldescr(op) + assert call_descr.extrainfo.can_release_gil \ No newline at end of file diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -3,6 +3,7 @@ from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register from pypy.jit.codewriter.format import assert_format +from pypy.jit.codewriter import longlong from pypy.jit.metainterp.history import AbstractDescr from pypy.rpython.lltypesystem import lltype, rclass, rstr from pypy.objspace.flow.model import SpaceOperation, Variable, Constant @@ -30,6 +31,9 @@ 'float': FakeRegAlloc()} class FakeDescr(AbstractDescr): + _for_tests_only = True + def __init__(self, oopspecindex=None): + self.oopspecindex = oopspecindex def __repr__(self): return '' def as_vtable_size_descr(self): @@ -55,19 +59,24 @@ def arraydescrof(self, ARRAY): return FakeDescr() +class FakeCallInfoCollection: + def add(self, *args): + pass + class FakeCallControl: _descr_cannot_raise = FakeDescr() + callinfocollection = FakeCallInfoCollection() def guess_call_kind(self, op): return 'residual' - def getcalldescr(self, op): + def getcalldescr(self, op, oopspecindex=None, extraeffect=None): try: if 'cannot_raise' in op.args[0].value._obj.graph.name: return self._descr_cannot_raise except AttributeError: pass - return FakeDescr() + return FakeDescr(oopspecindex) def calldescr_canraise(self, calldescr): - return calldescr is not self._descr_cannot_raise + return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None def get_vinfo(self, VTYPEPTR): return None @@ -734,7 +743,9 @@ def test_force_cast(self): from pypy.rpython.lltypesystem import rffi - + # NB: we don't need to test for INT here, the logic in jtransform is + # general enough so that if we have the below cases it should + # generalize also to INT for FROM, TO, expected in [ (rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""), (rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"), @@ -797,14 +808,44 @@ expected = [s.strip() for s in expected.splitlines()] check_force_cast(FROM, TO, expected, 42) check_force_cast(FROM, TO, expected, -42) - expected.append('int_return %i' + str(len(expected))) - expected = '\n'.join(expected) + returnvar = "%i" + str(len(expected)) + expected.append('int_return ' + returnvar) + expectedstr = '\n'.join(expected) # def f(n): return rffi.cast(TO, n) - self.encoding_test(f, [rffi.cast(FROM, 42)], expected, + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, transform=True) + if not longlong.is_64_bit: + if FROM in (rffi.LONG, rffi.ULONG): + if FROM == rffi.LONG: + FROM = rffi.LONGLONG + else: + FROM = rffi.ULONGLONG + expected.insert(0, + "residual_call_irf_i $<* fn llong_to_int>, , I[], R[], F[%f0] -> %i0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + elif TO in (rffi.LONG, rffi.ULONG): + if TO == rffi.LONG: + TO = rffi.LONGLONG + else: + TO = rffi.ULONGLONG + if rffi.cast(FROM, -1) < 0: + fnname = "llong_from_int" + else: + fnname = "llong_from_uint" + expected.pop() # remove int_return + expected.append( + "residual_call_irf_f $<* fn %s>, , I[%s], R[], F[] -> %%f0" + % (fnname, returnvar)) + expected.append("float_return %f0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + def test_force_cast_pointer(self): from pypy.rpython.lltypesystem import rffi def h(p): @@ -813,6 +854,23 @@ int_return %i0 """, transform=True) + def test_force_cast_float(self): + from pypy.rpython.lltypesystem import rffi + def f(n): + return rffi.cast(lltype.Float, n) + self.encoding_test(f, [12.456], """ + float_return %f0 + """, transform=True) + + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py --- a/pypy/jit/codewriter/test/test_longlong.py +++ b/pypy/jit/codewriter/test/test_longlong.py @@ -37,7 +37,7 @@ class TestLongLong: def setup_class(cls): - if sys.maxint > 2147483647: + if longlong.is_64_bit: py.test.skip("only for 32-bit platforms") def do_check(self, opname, oopspecindex, ARGS, RESULT): @@ -46,6 +46,8 @@ op = SpaceOperation(opname, vlist, v_result) tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) op1 = tr.rewrite_operation(op) + if isinstance(op1, list): + [op1] = op1 # def is_llf(TYPE): return (TYPE == lltype.SignedLongLong or @@ -196,6 +198,23 @@ for T2 in [lltype.Signed, lltype.Unsigned]: self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT, [T1], T2) + self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT, + [T1], T2) + if T2 == lltype.Signed: + expected = EffectInfo.OS_LLONG_FROM_INT + else: + expected = EffectInfo.OS_LLONG_FROM_UINT + self.do_check('cast_primitive', expected, [T2], T1) + self.do_check('force_cast', expected, [T2], T1) + # + for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + vlist = [varoftype(T1)] + v_result = varoftype(T2) + op = SpaceOperation('force_cast', vlist, v_result) + tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) + op1 = tr.rewrite_operation(op) + assert op1 is None def test_constants(self): for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]: diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -57,7 +57,6 @@ optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble, retraced) - if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -4,7 +4,7 @@ from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -207,13 +207,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -224,4 +218,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,5 +1,5 @@ import os -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException @@ -76,7 +76,7 @@ self._cached_fields[structvalue] = fieldvalue self._cached_fields_getfield_op[structvalue] = getfield_op - def force_lazy_setfield(self, optheap): + def force_lazy_setfield(self, optheap, can_cache=True): op = self._lazy_setfield if op is not None: # This is the way _lazy_setfield is usually reset to None. @@ -86,12 +86,16 @@ self.clear() self._lazy_setfield = None optheap.next_optimization.propagate_forward(op) + if not can_cache: + return # Once it is done, we can put at least one piece of information # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue, op) + elif not can_cache: + self.clear() def clear(self): self._cached_fields.clear() @@ -248,20 +252,9 @@ for arraydescr in effectinfo.readonly_descrs_arrays: self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: - self.force_lazy_setfield(fielddescr) - try: - cf = self.cached_fields[fielddescr] - cf.clear() - except KeyError: - pass + self.force_lazy_setfield(fielddescr, can_cache=False) for arraydescr in effectinfo.write_descrs_arrays: - self.force_lazy_setarrayitem(arraydescr) - try: - submap = self.cached_arrayitems[arraydescr] - for cf in submap.itervalues(): - cf.clear() - except KeyError: - pass + self.force_lazy_setarrayitem(arraydescr, can_cache=False) if effectinfo.check_forces_virtual_or_virtualizable(): vrefinfo = self.optimizer.metainterp_sd.virtualref_info self.force_lazy_setfield(vrefinfo.descr_forced) @@ -284,20 +277,20 @@ if value in cf._cached_fields: cf.turned_constant(newvalue, value) - def force_lazy_setfield(self, descr): + def force_lazy_setfield(self, descr, can_cache=True): try: cf = self.cached_fields[descr] except KeyError: return - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) - def force_lazy_setarrayitem(self, arraydescr): + def force_lazy_setarrayitem(self, arraydescr, can_cache=True): try: submap = self.cached_arrayitems[arraydescr] except KeyError: return for cf in submap.values(): - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes @@ -436,7 +429,7 @@ cf.do_setfield(self, op) else: # variable index, so make sure the lazy setarrayitems are done - self.force_lazy_setarrayitem(op.getdescr()) + self.force_lazy_setarrayitem(op.getdescr(), can_cache=False) # and then emit the operation self.emit_operation(op) @@ -480,13 +473,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0, \ MODE_ARRAY, MODE_STR, MODE_UNICODE -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, IntLowerBound, IntUpperBound) from pypy.jit.metainterp.history import Const, ConstInt @@ -39,14 +39,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -62,11 +59,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -462,5 +455,6 @@ propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp import jitprof from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp import resume, compile @@ -564,14 +564,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -723,7 +716,8 @@ -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.intutils import IntBound @@ -36,18 +36,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -219,6 +214,7 @@ )) return self.emit_operation(op) + self.pure(rop.FLOAT_MUL, [arg2, arg1], op.result) def optimize_FLOAT_NEG(self, op): v1 = op.getarg(0) @@ -494,5 +490,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1755,6 +1755,48 @@ """ self.optimize_loop(ops, expected) + def test_duplicate_getarrayitem_after_setarrayitem_bug(self): + ops = """ + [p0, i0, i1] + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i6 = int_add(i0, 1) + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + + def test_duplicate_getarrayitem_after_setarrayitem_bug2(self): + ops = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + def test_bug_1(self): ops = """ [i0, p1] @@ -3916,11 +3958,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3941,9 +3980,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3962,10 +3999,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -3987,14 +4023,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -4010,10 +4041,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4131,9 +4160,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -4178,11 +4205,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4374,11 +4398,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -4532,6 +4553,39 @@ """ self.optimize_loop(ops, expected) + def test_strslice_subtraction_folds(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + + def test_float_mul_reversed(self): + ops = """ + [f0, f1] + f2 = float_mul(f0, f1) + f3 = float_mul(f1, f0) + jump(f2, f3) + """ + expected = """ + [f0, f1] + f2 = float_mul(f0, f1) + jump(f2, f2) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -3074,11 +3074,11 @@ def test_residual_call_invalidate_some_arrays(self): ops = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) - p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p2, 0, descr=arraydescr2) p6 = getarrayitem_gc(p2, 1, descr=arraydescr2) i4 = getarrayitem_gc(p1, 1, descr=arraydescr) escape(p3) @@ -3091,7 +3091,7 @@ """ expected = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) @@ -5343,11 +5343,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected, expected) @@ -5368,9 +5365,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected, expected) @@ -5389,10 +5384,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5414,14 +5408,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected, expected) @@ -5437,10 +5426,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected, expected) @@ -5599,9 +5586,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected, expected) @@ -5711,11 +5696,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5939,11 +5921,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -20,9 +20,25 @@ if op_prefix and not name.startswith(op_prefix): continue if hasattr(Class, name_prefix + name): - result.append((value, getattr(Class, name_prefix + name))) + opclass = resoperation.opclasses[getattr(rop, name)] + assert name in opclass.__name__ + result.append((value, opclass, getattr(Class, name_prefix + name))) return unrolling_iterable(result) +def make_dispatcher_method(Class, name_prefix, op_prefix=None, default=None): + ops = _findall(Class, name_prefix, op_prefix) + def dispatch(self, op, *args): + opnum = op.getopnum() + for value, cls, func in ops: + if opnum == value: + assert isinstance(op, cls) + return func(self, op, *args) + if default: + return default(self, op, *args) + dispatch.func_name = "dispatch_" + name_prefix + return dispatch + + def partition(array, left, right): last_item = array[right] pivot = last_item.sort_key() diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -1,7 +1,7 @@ from pypy.jit.metainterp.history import Const, ConstInt, BoxInt from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs -from pypy.jit.metainterp.optimizeopt.util import descrlist_dict +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, sort_descrs from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.optimizeopt import optimizer from pypy.jit.metainterp.optimizeopt.optimizer import OptValue @@ -475,13 +475,8 @@ ###self.heap_op_optimizer.optimize_SETARRAYITEM_GC(op, value, fieldvalue) self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptVirtualize, 'optimize_') +dispatch_opt = make_dispatcher_method(OptVirtualize, 'optimize_', + default=OptVirtualize.emit_operation) + +OptVirtualize.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -8,7 +8,7 @@ from pypy.jit.metainterp.optimizeopt import optimizer, virtualize from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1 from pypy.jit.metainterp.optimizeopt.optimizer import llhelper -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter import heaptracker from pypy.rlib.unroll import unrolling_iterable @@ -61,7 +61,7 @@ self.ensure_nonnull() box = self.force_box() lengthbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox)) + optimization.optimize_default(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -72,13 +72,13 @@ else: return None - def string_copy_parts(self, optimization, targetbox, offsetbox, mode): + def string_copy_parts(self, optimizer, targetbox, offsetbox, mode): # Copies the pointer-to-string 'self' into the target string # given by 'targetbox', at the specified offset. Returns the offset # at the end of the copy. - lengthbox = self.getstrlen(optimization, mode) + lengthbox = self.getstrlen(optimizer, mode) srcbox = self.force_box() - return copy_str_content(optimization, srcbox, targetbox, + return copy_str_content(optimizer, srcbox, targetbox, CONST_0, offsetbox, lengthbox, mode) @@ -335,7 +335,7 @@ if optimizer is None: return None resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_ADD, [box1, box2], resbox)) return resbox def _int_sub(optimizer, box1, box2): @@ -345,10 +345,10 @@ if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() - optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) + optimizer.optimize_default(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox -def _strgetitem(optimization, strbox, indexbox, mode): +def _strgetitem(optimizer, strbox, indexbox, mode): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimizer.optimize_default(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -443,7 +443,7 @@ if vindex.is_constant(): return value.getitem(vindex.box.getint()) # - resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode) + resbox = _strgetitem(self.optimizer, value.force_box(), vindex.force_box(), mode) return self.getvalue(resbox) def optimize_STRLEN(self, op): @@ -453,7 +453,7 @@ def _optimize_STRLEN(self, op, mode): value = self.getvalue(op.getarg(0)) - lengthbox = value.getstrlen(self, mode) + lengthbox = value.getstrlen(self.optimizer, mode) self.make_equal_to(op.result, self.getvalue(lengthbox)) def optimize_CALL(self, op): @@ -652,16 +652,11 @@ self.emit_operation(op) return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) -optimize_ops = _findall(OptString, 'optimize_') +dispatch_opt = make_dispatcher_method(OptString, 'optimize_', + default=OptString.emit_operation) def _findall_call_oopspec(): prefix = 'opt_call_stroruni_' diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -56,6 +56,8 @@ # for resume.py operation self.parent_resumedata_snapshot = None self.parent_resumedata_frame_info_list = None + # counter for unrolling inlined loops + self.unroll_iterations = 1 @specialize.arg(3) def copy_constants(self, registers, constants, ConstClass): @@ -310,26 +312,27 @@ self.opimpl_goto_if_not(condbox, target) ''' % (_opimpl, _opimpl.upper())).compile() + + def _establish_nullity(self, box, orgpc): + value = box.nonnull() + if value: + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc) + else: + if not isinstance(box, Const): + self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc) + promoted_box = box.constbox() + self.metainterp.replace_box(box, promoted_box) + return value + @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_nonzero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if not value: + if not self._establish_nullity(box, orgpc): self.pc = target @arguments("orgpc", "box", "label") def opimpl_goto_if_not_ptr_iszero(self, orgpc, box, target): - value = box.nonnull() - if value: - opnum = rop.GUARD_NONNULL - else: - opnum = rop.GUARD_ISNULL - self.generate_guard(opnum, box, resumepc=orgpc) - if value: + if self._establish_nullity(box, orgpc): self.pc = target @arguments("box", "box", "box") @@ -364,7 +367,9 @@ def opimpl_new_with_vtable(self, sizedescr): cpu = self.metainterp.cpu cls = heaptracker.descr2vtable(cpu, sizedescr) - return self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + resbox = self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls)) + self.metainterp.known_class_boxes[resbox] = None + return resbox ## @FixME #arguments("box") ## def opimpl_runtimenew(self, classbox): @@ -387,8 +392,21 @@ @arguments("box", "descr", "box") def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox): - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache and isinstance(indexbox, ConstInt): + index = indexbox.getint() + frombox, tobox = cache.get(index, (None, None)) + if frombox is arraybox: + return tobox + resbox = self.execute_with_descr(rop.GETARRAYITEM_GC, + arraydescr, arraybox, indexbox) + if isinstance(indexbox, ConstInt): + if not cache: + cache = self.metainterp.heap_array_cache[arraydescr] = {} + index = indexbox.getint() + cache[index] = arraybox, resbox + return resbox + opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any @@ -416,6 +434,13 @@ indexbox, itembox): self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, itembox) + if isinstance(indexbox, ConstInt): + cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {}) + cache[indexbox.getint()] = arraybox, itembox + else: + cache = self.metainterp.heap_array_cache.get(arraydescr, None) + if cache: + cache.clear() opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any @@ -451,21 +476,17 @@ def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, - sbox, sizebox) + self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox) abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, sizebox) - self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, - sbox, abox) + self._opimpl_setfield_gc_any(sbox, itemsdescr, abox) return sbox @arguments("box", "descr", "descr", "box") def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - return self.execute_with_descr(rop.GETARRAYITEM_GC, - arraydescr, arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox) opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any @@ -474,10 +495,9 @@ @arguments("box", "descr", "descr", "box", "box") def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - itemsdescr, listbox) - self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, - indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr) + self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox, + valuebox) opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any @@ -499,18 +519,29 @@ @arguments("box", "descr") def _opimpl_getfield_gc_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC, box, fielddescr) opimpl_getfield_gc_i = _opimpl_getfield_gc_any opimpl_getfield_gc_r = _opimpl_getfield_gc_any opimpl_getfield_gc_f = _opimpl_getfield_gc_any @arguments("box", "descr") def _opimpl_getfield_gc_pure_any(self, box, fielddescr): - return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_PURE, box, fielddescr) opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any + @specialize.arg(1) + def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box: + return tobox + resbox = self.execute_with_descr(opnum, fielddescr, box) + self.metainterp.heap_cache[fielddescr] = (box, resbox) + return resbox + @arguments("orgpc", "box", "descr") def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr): ginfo = self.metainterp.jitdriver_sd.greenfield_info @@ -529,7 +560,11 @@ @arguments("box", "descr", "box") def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox): + frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None)) + if frombox is box and tobox is valuebox: + return self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + self.metainterp.heap_cache[fielddescr] = (box, valuebox) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any opimpl_setfield_gc_f = _opimpl_setfield_gc_any @@ -593,12 +628,16 @@ standard_box = self.metainterp.virtualizable_boxes[-1] if standard_box is box: return False + if box in self.metainterp.nonstandard_virtualizables: + return True eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None, box, standard_box) eqbox = self.implement_guard_value(pc, eqbox) isstandard = eqbox.getint() if isstandard: self.metainterp.replace_box(box, standard_box) + else: + self.metainterp.nonstandard_virtualizables[box] = None return not isstandard def _get_virtualizable_field_index(self, fielddescr): @@ -610,7 +649,7 @@ @arguments("orgpc", "box", "descr") def _opimpl_getfield_vable(self, pc, box, fielddescr): if self._nonstandard_virtualizable(pc, box): - return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box) + return self._opimpl_getfield_gc_any(box, fielddescr) self.metainterp.check_synchronized_virtualizable() index = self._get_virtualizable_field_index(fielddescr) return self.metainterp.virtualizable_boxes[index] @@ -622,8 +661,7 @@ @arguments("orgpc", "box", "descr", "box") def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox): if self._nonstandard_virtualizable(pc, box): - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) - return + return self._opimpl_setfield_gc_any(box, fielddescr, valuebox) index = self._get_virtualizable_field_index(fielddescr) self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -653,10 +691,8 @@ @arguments("orgpc", "box", "descr", "descr", "box") def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr, - arraybox, indexbox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox) self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) return self.metainterp.virtualizable_boxes[index] @@ -669,10 +705,9 @@ def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox, valuebox): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) - self.execute_with_descr(rop.SETARRAYITEM_GC, adescr, - arraybox, indexbox, valuebox) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) + self._opimpl_setarrayitem_gc_any(arraybox, adescr, + indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, fdescr, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -686,8 +721,7 @@ @arguments("orgpc", "box", "descr", "descr") def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): - arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - fdescr, box) + arraybox = self._opimpl_getfield_gc_any(box, fdescr) return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -845,7 +879,9 @@ @arguments("orgpc", "box") def opimpl_guard_class(self, orgpc, box): clsbox = self.cls_of_box(box) - self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + if box not in self.metainterp.known_class_boxes: + self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc) + self.metainterp.known_class_boxes[box] = None return clsbox @arguments("int", "orgpc") @@ -897,6 +933,10 @@ # 'redboxes' back into the registers where it comes from. put_back_list_of_boxes3(self, jcposition, redboxes) else: + if jitdriver_sd.warmstate.should_unroll_one_iteration(greenboxes): + if self.unroll_iterations > 0: + self.unroll_iterations -= 1 + return # warning! careful here. We have to return from the current # frame containing the jit_merge_point, and then use # do_recursive_call() to follow the recursive call. This is @@ -1128,13 +1168,11 @@ metainterp.jitdriver_sd.greenfield_info is not None): virtualizable_boxes = metainterp.virtualizable_boxes saved_pc = self.pc - try: - if resumepc >= 0: - self.pc = resumepc - resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, - metainterp.virtualref_boxes, resumedescr) - finally: - self.pc = saved_pc + if resumepc >= 0: + self.pc = resumepc + resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, + metainterp.virtualref_boxes, resumedescr) + self.pc = saved_pc def implement_guard_value(self, orgpc, box): """Promote the given Box into a Const. Note: be careful, it's a @@ -1449,6 +1487,16 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} + # contains frame boxes that are not virtualizables + self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1624,10 +1672,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1789,6 +1854,11 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} + self.heap_array_cache = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) @@ -2295,6 +2365,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -281,9 +281,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -11,7 +11,7 @@ from pypy import conftest from pypy.rlib.rarithmetic import ovfcheck from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -542,6 +542,32 @@ assert res == 84 - 61 - 62 self.check_history(call=1) # because the trace starts immediately + def test_unroll_one_loop_iteration(self): + def unroll(code): + return code == 0 + myjitdriver = JitDriver(greens = ['code'], + reds = ['loops', 'inner_loops', 's'], + should_unroll_one_iteration=unroll) + + def f(code, loops, inner_loops): + s = 0 + while loops > 0: + myjitdriver.jit_merge_point(code=code, loops=loops, + inner_loops=inner_loops, s=s) + if code == 1: + s += f(0, inner_loops, 0) + loops -= 1 + s += 1 + return s + + res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True) + assert res == f(1, 4, 1) + self.check_history(call_assembler=0) + + res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True) + assert res == f(1, 4, 2) + self.check_history(call_assembler=1) + def test_format(self): def f(n): return len("<%d>" % n) @@ -1018,11 +1044,14 @@ pass class B(A): pass + @dont_look_inside + def extern(n): + if n: + return A() + else: + return B() def fn(n): - if n: - obj = A() - else: - obj = B() + obj = extern(n) return isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res @@ -1055,6 +1084,7 @@ res = self.meta_interp(main, []) assert res == 55 + def test_assert_isinstance(self): class A: pass @@ -1215,7 +1245,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: @@ -1583,8 +1613,6 @@ assert res == 1 def test_raw_malloc_and_access(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Signed) def f(n): @@ -1598,8 +1626,6 @@ assert res == 10 def test_raw_malloc_and_access_float(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Float) def f(n, f): @@ -2130,7 +2156,7 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if 0 < a <= 5: pass if 0 < b <= 5: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa @@ -2140,10 +2166,10 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa - + assert self.meta_interp(f1, [5, 5]) == 50 self.check_loops(int_rshift=0, everywhere=True) @@ -2175,7 +2201,7 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if -5 <= a < 0: pass if 0 < b <= 5: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa @@ -2185,10 +2211,10 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa - + assert self.meta_interp(f1, [-5, 5]) == -50 self.check_loops(int_rshift=0, everywhere=True) @@ -2243,7 +2269,7 @@ def get_printable_location(i): return str(i) - + myjitdriver = JitDriver(greens = ['i'], reds = ['j', 'c', 'a'], get_printable_location=get_printable_location) bytecode = "0j10jc20a3" @@ -2352,7 +2378,7 @@ assert self.meta_interp(build, []) == 7 self.check_loops(getfield_gc_pure=0) self.check_loops(getfield_gc_pure=2, everywhere=True) - + def test_args_becomming_equal(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a', 'b']) def f(n, a, b): @@ -2707,7 +2733,7 @@ return sa res = self.meta_interp(f, []) assert res == f() - + def test_frame_finished_during_continued_retrace(self): class Base(object): pass @@ -2758,7 +2784,67 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? - def test_continue_tracing_with_boxes_in_start_snapshot_replaced_by_optimizer(self): + def test_retrace_ending_up_retracing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + def test_continue_tracing_with_boxes_in_start_snapshot_replaced_by_optimizer(self): myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'a', 'b']) def f(n): sa = a = 0 @@ -2798,6 +2884,11 @@ assert res == f(32) self.check_loops(arraylen_gc=1) + + + + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): @@ -3066,6 +3157,59 @@ res = self.meta_interp(f, [32]) assert res == f(32) self.check_loops(arraylen_gc=1, everywhere=True) + + def test_release_gil_flush_heap_cache(self): + T = rffi.CArrayPtr(rffi.TIME_T) + + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + # Not a real lock, has all the same properties with respect to GIL + # release though, so good for this test. + class Lock(object): + @dont_look_inside + def acquire(self): + external(lltype.nullptr(T.TO)) + @dont_look_inside + def release(self): + external(lltype.nullptr(T.TO)) + class X(object): + def __init__(self, idx): + self.field = idx + @dont_look_inside + def get_obj(z): + return X(z) + myjitdriver = JitDriver(greens=[], reds=["n", "l", "z", "lock"]) + def f(n, z): + lock = Lock() + l = 0 + while n > 0: + myjitdriver.jit_merge_point(lock=lock, l=l, n=n, z=z) + x = get_obj(z) + l += x.field + lock.acquire() + # This must not reuse the previous one. + n -= x.field + lock.release() + return n + res = self.meta_interp(f, [10, 1]) + self.check_loops(getfield_gc=2) + assert res == f(10, 1) + + def test_jit_merge_point_with_raw_pointer(self): + driver = JitDriver(greens = [], reds = ['n', 'x']) + + TP = lltype.Array(lltype.Signed, hints={'nolength': True}) + + def f(n): + x = lltype.malloc(TP, 10, flavor='raw') + x[0] = 1 + while n > 0: + driver.jit_merge_point(n=n, x=x) + n -= x[0] + lltype.free(x, flavor='raw') + return n + + self.meta_interp(f, [10], repeat=3) + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,407 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + l = [1] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * (4 + a) + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + len(frame.l) + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ @@ -1133,6 +1133,7 @@ res = self.meta_interp(f, [10]) assert res == 55 self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True) + self.check_history(ptr_eq=2) def test_virtual_child_frame_with_arrays(self): myjitdriver = JitDriver(greens = [], reds = ['frame'], diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -10,6 +10,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import fatalerror +from pypy.rlib.rstackovf import StackOverflow from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function @@ -408,21 +409,28 @@ jd.warmstate = state def crash_in_jit(e): - if not we_are_translated(): - print "~~~ Crash in JIT!" - print '~~~ %s: %s' % (e.__class__, e) - if sys.stdout == sys.__stdout__: - import pdb; pdb.post_mortem(sys.exc_info()[2]) - raise - fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) + try: + raise e + except JitException: + raise # go through + except MemoryError: + raise # go through + except StackOverflow: + raise # go through + except Exception, e: + if not we_are_translated(): + print "~~~ Crash in JIT!" + print '~~~ %s: %s' % (e.__class__, e) + if sys.stdout == sys.__stdout__: + import pdb; pdb.post_mortem(sys.exc_info()[2]) + raise + fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) crash_in_jit._dont_inline_ = True if self.translator.rtyper.type_system.name == 'lltypesystem': def maybe_enter_jit(*args): try: maybe_compile_and_run(state.increment_threshold, *args) - except JitException: - raise # go through except Exception, e: crash_in_jit(e) maybe_enter_jit._always_inline_ = True @@ -460,6 +468,9 @@ onlygreens=False) jd._can_never_inline_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool) + jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd, + annhelper, jd.jitdriver.should_unroll_one_iteration, + annmodel.s_Bool) annhelper.finish() def _make_hook_graph(self, jitdriver_sd, annhelper, func, diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -138,7 +138,10 @@ refvalue = cpu.ts.cast_to_ref(value) cpu.set_future_value_ref(j, refvalue) elif typecode == 'int': - intvalue = lltype.cast_primitive(lltype.Signed, value) + if isinstance(lltype.typeOf(value), lltype.Ptr): + intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value)) + else: + intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) elif typecode == 'float': if lltype.typeOf(value) is lltype.Float: @@ -569,6 +572,19 @@ return can_inline_greenargs(*greenargs) self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + + if jd._should_unroll_one_iteration_ptr is None: + def should_unroll_one_iteration(greenkey): + return False + else: + rtyper = self.warmrunnerdesc.rtyper + inline_ptr = jd._should_unroll_one_iteration_ptr + def should_unroll_one_iteration(greenkey): + greenargs = unwrap_greenkey(greenkey) + fn = support.maybe_on_top_of_llinterp(rtyper, inline_ptr) + return fn(*greenargs) + self.should_unroll_one_iteration = should_unroll_one_iteration + if hasattr(jd.jitdriver, 'on_compile'): def on_compile(logger, token, operations, type, greenkey): greenargs = unwrap_greenkey(greenkey) diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -337,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" diff --git a/pypy/module/__builtin__/abstractinst.py b/pypy/module/__builtin__/abstractinst.py --- a/pypy/module/__builtin__/abstractinst.py +++ b/pypy/module/__builtin__/abstractinst.py @@ -58,7 +58,10 @@ # -- case (anything, type) try: - w_result = space.isinstance(w_obj, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.isinstance_allow_override(w_obj, w_klass_or_tuple) + else: + w_result = space.isinstance(w_obj, w_klass_or_tuple) except OperationError, e: # if w_klass_or_tuple was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors @@ -72,8 +75,11 @@ w_pretendtype = space.getattr(w_obj, space.wrap('__class__')) if space.is_w(w_pretendtype, space.type(w_obj)): return False # common case: obj.__class__ is type(obj) - w_result = space.issubtype(w_pretendtype, w_klass_or_tuple, - allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_pretendtype, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_pretendtype, w_klass_or_tuple) except OperationError, e: if e.async(space): raise @@ -134,7 +140,11 @@ # -- case (type, type) try: - w_result = space.issubtype(w_derived, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_derived, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_derived, w_klass_or_tuple) except OperationError, e: # if one of the args was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py --- a/pypy/module/__builtin__/compiling.py +++ b/pypy/module/__builtin__/compiling.py @@ -5,7 +5,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError from pypy.interpreter.astcompiler import consts, ast -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec @unwrap_spec(filename=str, mode=str, flags=int, dont_inherit=int) def compile(space, w_source, filename, mode, flags=0, dont_inherit=0): diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py --- a/pypy/module/__builtin__/descriptor.py +++ b/pypy/module/__builtin__/descriptor.py @@ -1,12 +1,10 @@ - -from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.function import StaticMethod, ClassMethod from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.descroperation import object_getattribute, object_setattr -from pypy.interpreter.function import StaticMethod, ClassMethod -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \ - descr_set_dict, interp_attrproperty_w, generic_new_descr +from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w, + generic_new_descr) +from pypy.objspace.descroperation import object_getattribute class W_Super(Wrappable): def __init__(self, space, w_starttype, w_objtype, w_self): diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -4,13 +4,12 @@ """ from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import NoneNotWrapped, applevel +from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.objectmodel import specialize -from inspect import getsource, getfile from pypy.rlib.rbigint import rbigint @@ -662,7 +661,6 @@ def descr_reduce(self): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns space = self.space w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -1,11 +1,9 @@ import new from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import NoneNotWrapped, applevel, interp2app +from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict -from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, descr_set_dict from pypy.rlib.objectmodel import compute_identity_hash from pypy.rlib.debug import make_sure_not_resized from pypy.rlib import jit @@ -420,7 +418,7 @@ if w_meth is not None: space.call_function(w_meth, w_name) else: - if not self.deldictvalue(space, w_name): + if not self.deldictvalue(space, name): raise operationerrfmt( space.w_AttributeError, "%s instance has no attribute '%s'", diff --git a/pypy/module/__builtin__/interp_memoryview.py b/pypy/module/__builtin__/interp_memoryview.py --- a/pypy/module/__builtin__/interp_memoryview.py +++ b/pypy/module/__builtin__/interp_memoryview.py @@ -2,7 +2,7 @@ Implementation of the 'buffer' and 'memoryview' types. """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter import gateway, buffer +from pypy.interpreter import buffer from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -4,12 +4,10 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.runicode import UNICHR from pypy.rlib.rfloat import isnan, isinf, round_double from pypy.rlib import rfloat -import math import __builtin__ NoneNotWrapped = gateway.NoneNotWrapped diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -25,6 +25,7 @@ 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', 'lookup_special' : 'interp_magic.lookup_special', + 'do_what_I_mean' : 'interp_magic.do_what_I_mean', } submodules = { diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,5 +1,4 @@ -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib import debug, jit diff --git a/pypy/module/__pypy__/interp_identitydict.py b/pypy/module/__pypy__/interp_identitydict.py --- a/pypy/module/__pypy__/interp_identitydict.py +++ b/pypy/module/__pypy__/interp_identitydict.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app from pypy.interpreter.baseobjspace import Wrappable class W_IdentityDict(Wrappable): diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -70,3 +70,6 @@ if w_descr is None: return space.w_None return space.get(w_descr, w_obj) + +def do_what_I_mean(space): + return space.wrap(42) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -49,3 +49,8 @@ class X: pass raises(TypeError, lookup_special, X(), "foo") + + def test_do_what_I_mean(self): + from __pypy__ import do_what_I_mean + x = do_what_I_mean() + assert x == 42 diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -186,6 +186,11 @@ mod = self.get_ast("from __future__ import with_statement; import y; " \ "from __future__ import nested_scopes") raises(SyntaxError, compile, mod, "", "exec") + mod = self.get_ast("from __future__ import division\nx = 1/2") + co = compile(mod, "", "exec") + ns = {} + exec co in ns + assert ns["x"] == .5 def test_field_attr_writable(self): import _ast as ast @@ -245,3 +250,38 @@ assert x.left == n1 assert x.op == addop assert x.right == n3 + + def test_functiondef(self): + import _ast as ast + fAst = ast.FunctionDef( + name="foo", + args=ast.arguments( + args=[], vararg=None, kwarg=None, defaults=[], + kwonlyargs=[], kw_defaults=[]), + body=[], decorator_list=[], lineno=5, col_offset=0) + exprAst = ast.Interactive(body=[fAst]) + compiled = compile(exprAst, "", "single") + # + d = {} + eval(compiled, d, d) + assert type(d['foo']) is type(lambda: 42) + assert d['foo']() is None + + def test_missing_name(self): + import _ast as ast + n = ast.FunctionDef(name=None) + n.name = "foo" + n.name = "foo" + n.name = "foo" + assert n.name == "foo" + + def test_issue793(self): + import _ast as ast + body = ast.Module([ + ast.TryExcept([ast.Pass(lineno=2, col_offset=4)], + [ast.ExceptHandler(ast.Name('Exception', ast.Load(), + lineno=3, col_offset=0), + None, [], lineno=4, col_offset=0)], + [], lineno=1, col_offset=0) + ]) + exec compile(body, '', 'exec') diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.objectmodel import we_are_translated class CodecState(object): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -1,9 +1,8 @@ -import sys -from pypy.interpreter.baseobjspace import Wrappable, Arguments +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, \ operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi @@ -16,7 +15,7 @@ class W_FFIType(Wrappable): _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to'] - + def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None): self.name = name self.ffitype = ffitype @@ -83,7 +82,6 @@ def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P types = [ # note: most of the type name directly come from the C equivalent, # with the exception of bytes: in C, ubyte and char are equivalent, @@ -149,13 +147,19 @@ raise OperationError(space.w_TypeError, space.wrap(msg)) return res +def unwrap_truncate_int(TP, space, w_arg): + if space.is_true(space.isinstance(w_arg, space.w_int)): + return rffi.cast(TP, space.int_w(w_arg)) + else: + return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask()) +unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)' # ======================================================================== class W_FuncPtr(Wrappable): _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype'] - + def __init__(self, func, argtypes_w, w_restype): self.func = func self.argtypes_w = argtypes_w @@ -181,15 +185,14 @@ # note that we must check for longlong first, because either # is_signed or is_unsigned returns true anyway assert libffi.IS_32_BIT - kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind - self.arg_longlong(space, argchain, kind, w_arg) + self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): - argchain.arg(space.int_w(w_arg)) + argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) elif w_argtype.is_unsigned(): - argchain.arg(intmask(space.uint_w(w_arg))) + argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg)) elif w_argtype.is_char(): w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) @@ -202,7 +205,7 @@ argchain.arg_singlefloat(space.float_w(w_arg)) elif w_argtype.is_struct(): # arg_raw directly takes value to put inside ll_args - w_arg = space.interp_w(W_StructureInstance, w_arg) + w_arg = space.interp_w(W_StructureInstance, w_arg) ptrval = w_arg.ll_buffer argchain.arg_raw(ptrval) else: @@ -220,15 +223,10 @@ return w_arg @jit.dont_look_inside - def arg_longlong(self, space, argchain, kind, w_arg): + def arg_longlong(self, space, argchain, w_arg): bigarg = space.bigint_w(w_arg) - if kind == 'I': - llval = bigarg.tolonglong() - elif kind == 'U': - ullval = bigarg.toulonglong() - llval = rffi.cast(rffi.LONGLONG, ullval) - else: - assert False + ullval = bigarg.ulonglongmask() + llval = rffi.cast(rffi.LONGLONG, ullval) # this is a hack: we store the 64 bits of the long long into the # 64 bits of a float (i.e., a C double) floatval = libffi.longlong2float(llval) @@ -404,7 +402,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + return W_FuncPtr(func, argtypes_w, w_restype) @unwrap_spec(name=str) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -111,7 +111,6 @@ types.double) assert pow(2, 3) == 8 - def test_int_args(self): """ DLLEXPORT int sum_xy(int x, int y) @@ -119,10 +118,12 @@ return x+y; } """ + import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint) assert sum_xy(30, 12) == 42 + assert sum_xy(sys.maxint*2, 0) == -2 def test_void_result(self): """ @@ -247,6 +248,9 @@ types.ulong) assert sum_xy(sys.maxint, 12) == sys.maxint+12 assert sum_xy(sys.maxint+1, 12) == sys.maxint+13 + # + res = sum_xy(sys.maxint*2+3, 0) + assert res == 1 def test_unsigned_short_args(self): """ @@ -375,6 +379,9 @@ res = sum_xy(x, y) expected = maxint64 + 3 assert res == expected + # + res = sum_xy(maxint64*2+3, 0) + assert res == 1 def test_byval_argument(self): """ diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -43,11 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,12 +3,10 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.gateway import ObjSpace -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -import os def wrap_streamerror(space, e, w_filename=None): if isinstance(e, streamio.StreamError): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -4,7 +4,6 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.buffer import RWBuffer -from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstring import StringBuilder from pypy.rlib.rarithmetic import r_longlong, intmask from pypy.tool.sourcetools import func_renamer diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py --- a/pypy/module/_io/interp_fileio.py +++ b/pypy/module/_io/interp_fileio.py @@ -1,5 +1,4 @@ -from pypy.interpreter.typedef import ( - TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty) +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 from pypy.rlib.rarithmetic import r_longlong diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -6,7 +6,6 @@ TypeDef, interp_attrproperty, generic_new_descr) from pypy.module.exceptions.interp_exceptions import W_IOError from pypy.module._io.interp_fileio import W_FileIO -from pypy.module._io.interp_iobase import W_IOBase from pypy.module._io.interp_textio import W_TextIOWrapper from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -57,6 +57,11 @@ def __del__(self): self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + + def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -4,7 +4,7 @@ generic_new_descr) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint from pypy.rlib.rbigint import rbigint from pypy.rlib.rstring import UnicodeBuilder diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py --- a/pypy/module/_locale/interp_locale.py +++ b/pypy/module/_locale/interp_locale.py @@ -1,4 +1,3 @@ -from pypy.rpython.tool import rffi_platform as platform from pypy.rlib import rposix from pypy.rlib.rarithmetic import intmask diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -2,12 +2,10 @@ """ The ffi for rpython, need to be imported for side effects """ -import sys from pypy.rpython.lltypesystem import rffi from pypy.rpython.lltypesystem import lltype from pypy.rpython.tool import rffi_platform from pypy.rpython.extfunc import register_external -from pypy.rpython.extregistry import ExtRegistryEntry from pypy.module._minimal_curses import interp_curses from pypy.translator.tool.cbuild import ExternalCompilationInfo @@ -82,7 +80,7 @@ return res finally: rffi.free_charp(ll_cap) - + register_external(interp_curses._curses_tigetstr, [str], str, export_name='_curses.tigetstr', llimpl=tigetstr_llimpl) diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -1,4 +1,4 @@ -import py, sys +import py from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -4,7 +4,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import ( OperationError, wrap_oserror, operationerrfmt) -from pypy.rpython.lltypesystem import rffi, lltype, llmemory +from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll import sys diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -15,7 +15,6 @@ if sys.platform == 'win32': from pypy.rlib import rwin32 - from pypy.interpreter.error import wrap_windowserror from pypy.module._multiprocessing.interp_win32 import ( handle_w, _GetTickCount) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -1,4 +1,4 @@ -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError from pypy.interpreter.nestedscope import Cell from pypy.interpreter.pycode import PyCode from pypy.interpreter.function import Function, Method @@ -8,7 +8,6 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec -from pypy.objspace.std.dicttype import dictiter_typedef from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject @@ -79,7 +78,7 @@ try: return gateway.BuiltinCode.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin code: "+ identifier)) @@ -89,7 +88,7 @@ try: return function.Function.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin function: "+ identifier)) diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,10 +2,10 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rpython.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import get_elem, push_elem +from pypy.module._rawffi.array import push_elem from pypy.module._rawffi.structure import W_Structure -from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \ - wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes +from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, + unwrap_value, unpack_argshapes) from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL from pypy.rlib.clibffi import ffi_type_void from pypy.rlib import rweakref diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -1,7 +1,6 @@ -import sys from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib.clibffi import * @@ -15,7 +14,7 @@ from pypy.rlib import rwin32 from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.tracker import tracker TYPEMAP = { diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py --- a/pypy/module/_socket/interp_func.py +++ b/pypy/module/_socket/interp_func.py @@ -1,9 +1,8 @@ -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._socket.interp_socket import converted_error, W_RSocket from pypy.rlib import rsocket from pypy.rlib.rsocket import SocketError -from pypy.rlib.rarithmetic import r_uint -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError def gethostname(space): """gethostname() -> string diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,7 +1,7 @@ from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError -from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -11,7 +11,6 @@ from pypy.module._socket import interp_socket -import sys ## user defined constants X509_NAME_MAXLEN = 256 @@ -131,13 +130,13 @@ self._issuer = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN, flavor='raw') self._issuer[0] = '\0' self.shutdown_seen_zero = False - + def server(self): return self.space.wrap(rffi.charp2str(self._server)) - + def issuer(self): return self.space.wrap(rffi.charp2str(self._issuer)) - + def __del__(self): if self.peer_cert: libssl_X509_free(self.peer_cert) @@ -147,7 +146,7 @@ libssl_SSL_CTX_free(self.ctx) lltype.free(self._server, flavor='raw') lltype.free(self._issuer, flavor='raw') - + @unwrap_spec(data='bufferstr') def write(self, data): """write(s) -> len @@ -230,10 +229,10 @@ raw_buf, gc_buf = rffi.alloc_buffer(num_bytes) while True: err = 0 - + count = libssl_SSL_read(self.ssl, raw_buf, num_bytes) err = libssl_SSL_get_error(self.ssl, count) - + if err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout(self.space, self.w_socket, False) @@ -245,17 +244,17 @@ return self.space.wrap("") else: sockstate = SOCKET_OPERATION_OK - + if sockstate == SOCKET_HAS_TIMED_OUT: raise ssl_error(self.space, "The read operation timed out") elif sockstate == SOCKET_IS_NONBLOCKING: break - + if err == SSL_ERROR_WANT_READ or err == SSL_ERROR_WANT_WRITE: continue else: break - + if count <= 0: raise _ssl_seterror(self.space, self, count) @@ -351,7 +350,7 @@ self.shutdown_seen_zero = True continue - # Possibly retry shutdown until timeout or failure + # Possibly retry shutdown until timeout or failure ssl_err = libssl_SSL_get_error(self.ssl, ret) if ssl_err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout( @@ -397,7 +396,7 @@ else: w_proto = space.w_None - bits = libssl_SSL_CIPHER_get_bits(current, + bits = libssl_SSL_CIPHER_get_bits(current, lltype.nullptr(rffi.INTP.TO)) w_bits = space.newint(bits) @@ -552,7 +551,7 @@ ext = libssl_X509_get_ext(certificate, i) method = libssl_X509V3_EXT_get(ext) if not method: - raise ssl_error(space, + raise ssl_error(space, "No method for internalizing subjectAltName!'") with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr: @@ -858,7 +857,7 @@ cert = libssl_BIO_new(libssl_BIO_s_file()) if not cert: raise ssl_error(space, "Can't malloc memory to read file") - + try: if libssl_BIO_read_filename(cert, filename) <= 0: raise ssl_error(space, "Can't open file") @@ -873,7 +872,7 @@ libssl_X509_free(x) finally: libssl_BIO_free(cert) - + # this function is needed to perform locking on shared data # structures. (Note that OpenSSL uses a number of global data # structures that will be implicitly shared whenever multiple threads diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -15,13 +15,10 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import StaticMethod from pypy.module._stackless.stackless_flags import StacklessFlags from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit @@ -38,7 +35,7 @@ self.costate = costate if not space.is_true(space.callable(w_obj)): raise operationerrfmt( - space.w_TypeError, + space.w_TypeError, "'%s' object is not callable", space.type(w_obj).getname(space)) self.w_func = w_obj @@ -65,7 +62,7 @@ # Should be moved to interp_stackless.py if it's ever implemented... Currently # used by pypy/lib/stackless.py. -W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, +W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, """Tasklet killed manually.""") class AppCoroutine(Coroutine): # XXX, StacklessFlags): @@ -90,7 +87,7 @@ def _get_state(space): return space.fromcache(AppCoState) _get_state = staticmethod(_get_state) - + def w_bind(self, w_func, __args__): space = self.space if self.frame is not None: @@ -127,7 +124,7 @@ w_excvalue = operror.get_w_value(space) w_exctraceback = operror.get_traceback() w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback]) - + if w_exctype is self.costate.w_CoroutineExit: self.coroutine_exit = True else: @@ -146,22 +143,22 @@ def w_kill(self): self.kill() - + def w_throw(self, w_type, w_value=None, w_traceback=None): space = self.space operror = OperationError(w_type, w_value) operror.normalize_exception(space) - + if not space.is_w(w_traceback, space.w_None): from pypy.interpreter import pytraceback tb = space.interpclass_w(w_traceback) - if tb is None or not space.is_true(space.isinstance(tb, + if tb is None or not space.is_true(space.isinstance(tb, space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) operror.set_traceback(tb) - + self._kill(operror) def _userdel(self): @@ -280,7 +277,7 @@ assert isinstance(w_klass, W_TypeObject) old_flag = w_klass.flag_heaptype w_klass.flag_heaptype = True - + space.appexec([w_klass, space.wrap(funcname)], """ (klass, funcname): func = getattr(klass, funcname) @@ -332,23 +329,23 @@ # Exporting new exception to space self.w_CoroutineExit = space.gettypefor(W_CoroutineExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('CoroutineExit'), - self.w_CoroutineExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('CoroutineExit'), + space.exceptions_module.w_dict, + space.new_interned_str('CoroutineExit'), self.w_CoroutineExit) - + space.setitem(space.builtin.w_dict, + space.new_interned_str('CoroutineExit'), + self.w_CoroutineExit) + # Should be moved to interp_stackless.py if it's ever implemented... self.w_TaskletExit = space.gettypefor(W_TaskletExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - + space.exceptions_module.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + space.setitem(space.builtin.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + def post_install(self): self.current = self.main = AppCoroutine(self.space, state=self) self.main.subctx.clear_framestack() # wack @@ -378,7 +375,7 @@ instr = frame.last_instr opcode = ord(code[instr]) map = pythonopcode.opmap - call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], + call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] assert opcode in call_ops instr += 1 diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py --- a/pypy/module/_stackless/interp_stackless.py +++ b/pypy/module/_stackless/interp_stackless.py @@ -1,9 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError -from pypy.rlib.rarithmetic import intmask import os diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py --- a/pypy/module/_stackless/rclonable.py +++ b/pypy/module/_stackless/rclonable.py @@ -1,7 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.rlib.objectmodel import we_are_translated -from pypy.interpreter.error import OperationError class InterpClonableMixin: @@ -76,7 +75,7 @@ if not isinstance(current, InterpClonableCoroutine): raise RuntimeError("fork() in a non-clonable coroutine") thunk = ForkThunk(current) - coro_fork = InterpClonableCoroutine() + coro_fork = InterpClonableCoroutine() coro_fork.bind(thunk) coro_fork.switch() # we resume here twice. The following would need explanations about diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,16 +1,15 @@ import py -from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.interpreter.typedef import GetSetProperty, TypeDef +from pypy.interpreter.typedef import TypeDef from pypy.rlib import jit import weakref class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 @@ -23,8 +22,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,11 +119,8 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: - w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) + assert isinstance(w_self, W_WeakrefBase) + w_self.space.call_function(w_self.w_callable, w_self) def descr__repr__(self, space): w_obj = self.dereference() diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -1,6 +1,5 @@ from __future__ import with_statement from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError, wrap_windowserror diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,20 @@ from __future__ import with_statement +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError -from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -37,7 +39,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -73,6 +75,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +99,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +162,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -268,12 +269,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -311,6 +310,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -319,12 +326,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -387,7 +389,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -395,7 +397,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -413,7 +415,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -515,14 +517,14 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() @@ -569,10 +571,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): @@ -615,6 +614,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) + return w_a + def array_byteswap__Array(space, self): if mytype.bytes not in [1, 2, 4, 8]: msg = "byteswap not supported for this array" diff --git a/pypy/module/binascii/interp_crc32.py b/pypy/module/binascii/interp_crc32.py --- a/pypy/module/binascii/interp_crc32.py +++ b/pypy/module/binascii/interp_crc32.py @@ -61,7 +61,7 @@ crc_32_tab = map(r_uint, crc_32_tab) - at unwrap_spec(data='bufferstr', oldcrc='c_int') + at unwrap_spec(data='bufferstr', oldcrc='truncatedint') def crc32(space, data, oldcrc=0): "Compute the CRC-32 incrementally." diff --git a/pypy/module/binascii/test/test_binascii.py b/pypy/module/binascii/test/test_binascii.py --- a/pypy/module/binascii/test/test_binascii.py +++ b/pypy/module/binascii/test/test_binascii.py @@ -374,6 +374,8 @@ ('x', 10000, -1855256896), ('y', 10000, -429115818), ('z', 10000, 2137352172), + ('foo', 99999999999999999999999999, -1932704816), + ('bar', -99999999999999999999999999, 2000545409), ]: assert self.binascii.crc32(input, initial) == expected diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py --- a/pypy/module/bz2/interp_bz2.py +++ b/pypy/module/bz2/interp_bz2.py @@ -4,9 +4,8 @@ from pypy.rpython.lltypesystem import lltype from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.typedef import interp_attrproperty -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef, interp_attrproperty +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.rlib.streamio import Stream from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.translator.platform import platform as compiler @@ -67,7 +66,7 @@ 'BZ_OUTBUFF_FULL', 'BZ_CONFIG_ERROR'] for name in constant_names: setattr(CConfig, name, platform.DefinedConstantInteger(name)) - + class cConfig(object): pass for k, v in platform.configure(CConfig).items(): @@ -100,7 +99,7 @@ SMALLCHUNK = 8192 else: SMALLCHUNK = BUFSIZ - + if rffi.sizeof(rffi.INT) > 4: BIGCHUNK = 512 * 32 else: @@ -505,7 +504,7 @@ self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self._init_bz2comp(compresslevel) - + def _init_bz2comp(self, compresslevel): if compresslevel < 1 or compresslevel > 9: raise OperationError(self.space.w_ValueError, @@ -514,13 +513,13 @@ bzerror = intmask(BZ2_bzCompressInit(self.bzs, compresslevel, 0, 0)) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzCompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') - + @unwrap_spec(data='bufferstr') def compress(self, data): """compress(data) -> string @@ -529,12 +528,12 @@ compressed data whenever possible. When you've finished providing data to compress, call the flush() method to finish the compression process, and return what is left in the internal buffers.""" - + datasize = len(data) - + if datasize == 0: return self.space.wrap("") - + if not self.running: raise OperationError(self.space.w_ValueError, self.space.wrap("this object was already flushed")) @@ -562,7 +561,7 @@ res = out.make_result_string() return self.space.wrap(res) - + def flush(self): if not self.running: raise OperationError(self.space.w_ValueError, @@ -576,7 +575,7 @@ break elif bzerror != BZ_FINISH_OK: _catch_bz2_error(self.space, bzerror) - + if rffi.getintfield(self.bzs, 'c_avail_out') == 0: out.prepare_next_chunk() @@ -603,23 +602,23 @@ Create a new decompressor object. This object may be used to decompress data sequentially. If you want to decompress data in one shot, use the decompress() function instead.""" - + def __init__(self, space): self.space = space self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True) self.running = False self.unused_data = "" - + self._init_bz2decomp() - + def _init_bz2decomp(self): bzerror = BZ2_bzDecompressInit(self.bzs, 0, 0) if bzerror != BZ_OK: _catch_bz2_error(self.space, bzerror) - + self.running = True - + def __del__(self): BZ2_bzDecompressEnd(self.bzs) lltype.free(self.bzs, flavor='raw') @@ -687,7 +686,7 @@ Compress data in one shot. If you want to compress data sequentially, use an instance of BZ2Compressor instead. The compresslevel parameter, if given, must be a number between 1 and 9.""" - + if compresslevel < 1 or compresslevel > 9: raise OperationError(space.w_ValueError, space.wrap("compresslevel must be between 1 and 9")) @@ -731,7 +730,7 @@ Decompress data in one shot. If you want to decompress data sequentially, use an instance of BZ2Decompressor instead.""" - + in_bufsize = len(data) if in_bufsize == 0: return space.wrap("") diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -133,6 +133,7 @@ bz2f.seek(0) assert bz2f.tell() == 0 + del bz2f # delete from this frame, which is captured in the traceback def test_open_close_del(self): from bz2 import BZ2File @@ -246,11 +247,18 @@ assert text_read == self.TEXT bz2f.close() + def test_silently_closes(self): + from bz2 import BZ2File + self.create_broken_temp_file() + BZ2File(self.temppath) + # check that no C-level malloc is left behind + def test_read_broken_file(self): from bz2 import BZ2File self.create_broken_temp_file() bz2f = BZ2File(self.temppath) raises(EOFError, bz2f.read) + del bz2f # delete from this frame, which is captured in the traceback def test_subsequent_read_broken_file(self): from bz2 import BZ2File @@ -264,6 +272,7 @@ raise Exception("should generate EOFError earlier") except EOFError: pass + del bz2f # delete from this frame, which is captured in the traceback def test_read_chunk10(self): from bz2 import BZ2File @@ -416,6 +425,7 @@ bz2f.close() bz2f = BZ2File(self.temppath, 'r') assert bz2f.read() == self.random_data + del bz2f # delete from this frame, which is captured in the traceback def test_context_manager(self): from bz2 import BZ2File diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -1,4 +1,3 @@ -import sys from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef, GetSetProperty diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py --- a/pypy/module/cmath/interp_cmath.py +++ b/pypy/module/cmath/interp_cmath.py @@ -5,7 +5,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import NoneNotWrapped -from pypy.module.cmath import Module, names_and_docstrings +from pypy.module.cmath import names_and_docstrings from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG from pypy.module.cmath.constant import M_LN2, M_LN10 diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -337,7 +337,7 @@ 'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', 'init_capsule', 'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer', - + 'PyOS_getsig', 'PyOS_setsig', 'PyStructSequence_InitType', 'PyStructSequence_New', @@ -745,7 +745,7 @@ ctypes.c_void_p) setup_va_functions(eci) - + setup_init_functions(eci) return modulename.new(ext='') @@ -771,7 +771,7 @@ export_symbols[:] = renamed_symbols else: export_symbols[:] = [sym.replace("#", "") for sym in export_symbols] - + # Generate defines for macro_name, size in [ ("SIZEOF_LONG_LONG", rffi.LONGLONG), @@ -784,7 +784,7 @@ ]: pypy_macros.append("#define %s %s" % (macro_name, rffi.sizeof(size))) pypy_macros.append('') - + pypy_macros_h = udir.join('pypy_macros.h') pypy_macros_h.write('\n'.join(pypy_macros)) @@ -852,7 +852,7 @@ # Sometimes the library is wrapped into another DLL, ensure that # the correct bootstrap code is installed kwds["link_extra"] = ["msvcrt.lib"] - elif sys.platform == 'linux2': + elif sys.platform.startswith('linux'): compile_extra.append("-Werror=implicit-function-declaration") export_symbols_eci.append('pypyAPI') else: @@ -1007,7 +1007,7 @@ FT = lltype.typeOf(func).TO return make_generic_cpy_call(FT, False, False)(space, func, *args) - at specialize.ll() + at specialize.ll() def generic_cpy_call_expect_null(space, func, *args): FT = lltype.typeOf(func).TO return make_generic_cpy_call(FT, True, True)(space, func, *args) diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py --- a/pypy/module/cpyext/cdatetime.py +++ b/pypy/module/cpyext/cdatetime.py @@ -1,8 +1,7 @@ from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib.objectmodel import we_are_translated -from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef -from pypy.module.cpyext.api import ( - cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields) +from pypy.module.cpyext.pyobject import PyObject, make_ref +from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct, + PyObjectFields) from pypy.module.cpyext.import_ import PyImport_Import from pypy.module.cpyext.typeobject import PyTypeObjectPtr from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py --- a/pypy/module/cpyext/complexobject.py +++ b/pypy/module/cpyext/complexobject.py @@ -1,7 +1,6 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.module.cpyext.api import ( cpython_api, cpython_struct, PyObject, build_type_checkers) -from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.floatobject import PyFloat_AsDouble from pypy.objspace.std.complexobject import W_ComplexObject from pypy.interpreter.error import OperationError diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.1" /* PyPy version as a string */ -#define PYPY_VERSION "1.5.0" +#define PYPY_VERSION "1.6.0" /* Subversion Revision number of this file (not of the repository) */ #define PY_PATCHLEVEL_REVISION "$Revision: 77872 $" diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -22,7 +22,7 @@ def PySequence_Check(space, w_obj): """Return 1 if the object provides sequence protocol, and 0 otherwise. This function always succeeds.""" - return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None) + return int(space.issequence_w(w_obj)) @cpython_api([PyObject], Py_ssize_t, error=-1) def PySequence_Size(space, w_obj): diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -268,3 +268,7 @@ if errors: w_errors = space.wrap(rffi.charp2str(errors)) return space.call_method(w_str, 'encode', w_encoding, w_errors) + + at cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -188,7 +188,7 @@ kwds["compile_extra"] = ["/we4013"] else: kwds["link_files"] = [str(api_library + '.so')] - if sys.platform == 'linux2': + if sys.platform.startswith('linux'): kwds["compile_extra"]=["-Werror=implicit-function-declaration"] return compile_module(self.space, name, **kwds) diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py --- a/pypy/module/cpyext/test/test_stringobject.py +++ b/pypy/module/cpyext/test/test_stringobject.py @@ -287,3 +287,9 @@ def test_eq(self, space, api): assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'ab' diff --git a/pypy/module/crypt/interp_crypt.py b/pypy/module/crypt/interp_crypt.py --- a/pypy/module/crypt/interp_crypt.py +++ b/pypy/module/crypt/interp_crypt.py @@ -1,6 +1,5 @@ -from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.rpython.lltypesystem import rffi, lltype +from pypy.rpython.lltypesystem import rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo import sys @@ -22,4 +21,4 @@ if not res: return space.w_None str_res = rffi.charp2str(res) - return space.wrap(str_res) + return space.wrap(str_res) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -73,9 +73,8 @@ """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w,\ - GetSetProperty, interp_attrproperty, descr_get_dict, descr_set_dict,\ - descr_del_dict +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict, + descr_set_dict, descr_del_dict) from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError from pypy.rlib import rwin32 diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -11,9 +11,8 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.eval import Code from pypy.interpreter.pycode import PyCode -from pypy.rlib import streamio, jit, rposix +from pypy.rlib import streamio, jit from pypy.rlib.streamio import StreamErrors -from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION @@ -86,7 +85,7 @@ return SEARCH_ERROR, None, None -if sys.platform == 'linux2' or 'freebsd' in sys.platform: +if sys.platform.startswith('linux') or 'freebsd' in sys.platform: def case_ok(filename): return True else: diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -3,9 +3,9 @@ from pypy.rlib import streamio from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.module import Module -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import struct + def get_suffixes(space): w = space.wrap diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,7 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.rarithmetic import ovfcheck class W_Count(Wrappable): @@ -87,7 +86,7 @@ def __init__(self, space, w_obj, w_times): self.space = space self.w_obj = w_obj - + if space.is_w(w_times, space.w_None): self.counting = False self.count = 0 @@ -181,7 +180,7 @@ long as the predicate is true. Equivalent to : - + def takewhile(predicate, iterable): for x in iterable: if predicate(x): @@ -316,7 +315,7 @@ None, return the items that are false. Equivalent to : - + def ifilterfalse(predicate, iterable): if predicate is None: predicate = bool @@ -380,16 +379,23 @@ self.start = -1 else: # all following calls consume = self.step + if consume > 1: + self._ignore_items(consume-1) if self.stop >= 0: if self.stop < consume: + self.stop = 0 # reset the state so that a following next_w() + self.step = 1 # has no effect any more raise OperationError(self.space.w_StopIteration, self.space.w_None) self.stop -= consume + return self.space.next(self.iterable) + + def _ignore_items(self, num): while True: - w_obj = self.space.next(self.iterable) - consume -= 1 - if consume <= 0: - return w_obj + self.space.next(self.iterable) + num -= 1 + if num <= 0: + break def W_ISlice___new__(space, w_subtype, w_iterable, w_startstop, args_w): r = space.allocate_instance(W_ISlice, w_subtype) @@ -570,7 +576,7 @@ yield tuple(args) else: yield function(*args) - + """) @@ -728,9 +734,9 @@ __doc__ = """Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely. - + Equivalent to : - + def cycle(iterable): saved = [] for element in iterable: @@ -738,7 +744,7 @@ saved.append(element) while saved: for element in saved: - yield element + yield element """) class W_StarMap(Wrappable): @@ -778,7 +784,7 @@ def starmap(function, iterable): iterable = iter(iterable) while True: - yield function(*iterable.next()) + yield function(*iterable.next()) """) @@ -788,15 +794,15 @@ Note : once tee() has made a split, the original iterable should not be used anywhere else; otherwise, the iterable could get advanced without the tee objects being informed. - + Note : this member of the toolkit may require significant auxiliary storage (depending on how much temporary data needs to be stored). In general, if one iterator is going to use most or all of the data before the other iterator, it is faster to use list() instead of tee() - + Equivalent to : - + def tee(iterable, n=2): def gen(next, data={}, cnt=[0]): for i in count(): @@ -888,7 +894,7 @@ self.exhausted = False self.started = False # new_group - new group not started yet, next should not skip any items - self.new_group = True + self.new_group = True self.w_lookahead = self.space.w_None self.w_key = self.space.w_None diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -227,6 +227,45 @@ assert list(itertools.islice(xrange(10), None,None)) == range(10) assert list(itertools.islice(xrange(10), None,None,None)) == range(10) + def test_islice_dropitems_exact(self): + import itertools + + it = iter("abcdefghij") + itertools.islice(it, 2, 2) # doesn't eagerly drop anything + assert it.next() == "a" + itertools.islice(it, 3, 8, 2) # doesn't eagerly drop anything + assert it.next() == "b" + assert it.next() == "c" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 2, 3), None) # drops 2 items + assert x == "c" + assert it.next() == "d" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 3, 8, 2), None) # drops 3 items + assert x == "d" + assert it.next() == "e" + + it = iter("abcdefghij") + x = next(itertools.islice(it, None, 8), None) # drops 0 items + assert x == "a" + assert it.next() == "b" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 3, 2), None) # drops 3 items + assert x is None + assert it.next() == "d" + + it = iter("abcdefghij") + islc = itertools.islice(it, 3, 7, 2) + assert islc.next() == "d" # drops 0, 1, 2, returns item #3 + assert it.next() == "e" + assert islc.next() == "g" # drops the 4th and return item #5 + assert it.next() == "h" + raises(StopIteration, islc.next) # drops the 6th and raise + assert it.next() == "j" + def test_islice_overflow(self): import itertools import sys diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -1,10 +1,8 @@ -from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask from pypy.rlib import rstackovf from pypy.module._file.interp_file import W_File -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror -import sys + Py_MARSHAL_VERSION = 2 diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -10,18 +10,27 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + 'fromstring': 'interp_support.fromstring', # ufuncs 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', + 'add': 'interp_ufuncs.add', 'copysign': 'interp_ufuncs.copysign', + 'divide': 'interp_ufuncs.divide', 'exp': 'interp_ufuncs.exp', + 'fabs': 'interp_ufuncs.fabs', 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', + 'multiply': 'interp_ufuncs.multiply', 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'subtract': 'interp_ufuncs.subtract', + 'sin': 'interp_ufuncs.sin', + 'cos': 'interp_ufuncs.cos', + 'tan': 'interp_ufuncs.tan', } appleveldefs = { diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -3,7 +3,7 @@ It should not be imported by the module itself """ -from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray class BogusBytecode(Exception): pass @@ -18,6 +18,14 @@ def wrap(self, x): return x + def issequence_w(self, w_obj): + # Completley wrong in the general case, but good enough for this. + return isinstance(w_obj, BaseArray) + + def float_w(self, w_obj): + assert isinstance(w_obj, float) + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() stack = [] @@ -40,6 +48,11 @@ elif b == '/': right = stack.pop() stack.append(stack.pop().descr_div(space, right)) + elif b == '%': + right = stack.pop() + stack.append(stack.pop().descr_mod(space, right)) + elif b == '|': + stack.append(stack.pop().descr_abs(space)) else: print "Unknown opcode: %s" % b raise BogusBytecode() diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,43 +1,36 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable -from pypy.interpreter.error import operationerrfmt +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy.interp_support import Signature +from pypy.module.micronumpy import interp_ufuncs +from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit +from pypy.rlib.rfloat import DTSF_STR_PRECISION from pypy.rpython.lltypesystem import lltype from pypy.tool.sourcetools import func_with_new_name - - -def dummy1(v): - assert isinstance(v, float) - return v - -def dummy2(v): - assert isinstance(v, float) - return v +import math TP = lltype.Array(lltype.Float, hints={'nolength': True}) numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) - -class Signature(object): - def __init__(self): - self.transitions = {} - - def transition(self, target): - if target in self.transitions: - return self.transitions[target] - self.transitions[target] = new = Signature() - return new +all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) def add(v1, v2): return v1 + v2 -def sub(v1, v2): - return v1 - v2 def mul(v1, v2): return v1 * v2 -def div(v1, v2): - return v1 / v2 +def maximum(v1, v2): + return max(v1, v2) +def minimum(v1, v2): + return min(v1, v2) + +def float2string(x): + return float2string_orig(x, 'g', DTSF_STR_PRECISION) class BaseArray(Wrappable): def __init__(self): @@ -52,44 +45,185 @@ arr.force_if_needed() del self.invalidates[:] - def _binop_impl(function): - signature = Signature() + def _unaryop_impl(w_ufunc): + def impl(self, space): + return w_ufunc(space, self) + return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__) + + descr_pos = _unaryop_impl(interp_ufuncs.positive) + descr_neg = _unaryop_impl(interp_ufuncs.negative) + descr_abs = _unaryop_impl(interp_ufuncs.absolute) + + def _binop_impl(w_ufunc): def impl(self, space, w_other): - new_sig = self.signature.transition(signature) - if isinstance(w_other, BaseArray): - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - else: - w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + return w_ufunc(space, self, w_other) + return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__) - descr_add = _binop_impl(add) - descr_sub = _binop_impl(sub) - descr_mul = _binop_impl(mul) - descr_div = _binop_impl(div) + descr_add = _binop_impl(interp_ufuncs.add) + descr_sub = _binop_impl(interp_ufuncs.subtract) + descr_mul = _binop_impl(interp_ufuncs.multiply) + descr_div = _binop_impl(interp_ufuncs.divide) + descr_pow = _binop_impl(interp_ufuncs.power) + descr_mod = _binop_impl(interp_ufuncs.mod) + + def _binop_right_impl(w_ufunc): + def impl(self, space, w_other): + w_other = FloatWrapper(space.float_w(w_other)) + return w_ufunc(space, w_other, self) + return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__) + + descr_radd = _binop_right_impl(interp_ufuncs.add) + descr_rsub = _binop_right_impl(interp_ufuncs.subtract) + descr_rmul = _binop_right_impl(interp_ufuncs.multiply) + descr_rdiv = _binop_right_impl(interp_ufuncs.divide) + descr_rpow = _binop_right_impl(interp_ufuncs.power) + descr_rmod = _binop_right_impl(interp_ufuncs.mod) + + def _reduce_sum_prod_impl(function, init): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + + def loop(self, result, size): + i = 0 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + return space.wrap(loop(self, init, self.find_size())) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_max_min_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'self', 'result']) + def loop(self, result, size): + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result) + result = function(result, self.eval(i)) + i += 1 + return result + + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, self.eval(0), size)) + return func_with_new_name(impl, "reduce_%s_impl" % function.__name__) + + def _reduce_argmax_argmin_impl(function): + reduce_driver = jit.JitDriver(greens=['signature'], + reds = ['i', 'size', 'result', 'self', 'cur_best']) + def loop(self, size): + result = 0 + cur_best = self.eval(0) + i = 1 + while i < size: + reduce_driver.jit_merge_point(signature=self.signature, + self=self, size=size, i=i, + result=result, cur_best=cur_best) + new_best = function(cur_best, self.eval(i)) + if new_best != cur_best: + result = i + cur_best = new_best + i += 1 + return result + def impl(self, space): + size = self.find_size() + if size == 0: + raise OperationError(space.w_ValueError, + space.wrap("Can't call %s on zero-size arrays" \ + % function.__name__)) + return space.wrap(loop(self, size)) + return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__) + + def _all(self): + size = self.find_size() + i = 0 + while i < size: + all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if not self.eval(i): + return False + i += 1 + return True + def descr_all(self, space): + return space.wrap(self._all()) + + def _any(self): + size = self.find_size() + i = 0 + while i < size: + any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i) + if self.eval(i): + return True + i += 1 + return False + def descr_any(self, space): + return space.wrap(self._any()) + + descr_sum = _reduce_sum_prod_impl(add, 0.0) + descr_prod = _reduce_sum_prod_impl(mul, 1.0) + descr_max = _reduce_max_min_impl(maximum) + descr_min = _reduce_max_min_impl(minimum) + descr_argmax = _reduce_argmax_argmin_impl(maximum) + descr_argmin = _reduce_argmax_argmin_impl(minimum) + + def descr_dot(self, space, w_other): + if isinstance(w_other, BaseArray): + w_res = self.descr_mul(space, w_other) + assert isinstance(w_res, BaseArray) + return w_res.descr_sum(space) + else: + return self.descr_mul(space, w_other) + + def _getnums(self, comma): + if self.find_size() > 1000: + nums = [ + float2string(self.getitem(index)) + for index in range(3) + ] + nums.append("..." + "," * comma) + nums.extend([ + float2string(self.getitem(index)) + for index in range(self.find_size() - 3, self.find_size()) + ]) + else: + nums = [ + float2string(self.getitem(index)) + for index in range(self.find_size()) + ] + return nums def get_concrete(self): raise NotImplementedError + def descr_copy(self, space): + return new_numarray(space, self) + def descr_get_shape(self, space): return space.newtuple([self.descr_len(space)]) def descr_len(self, space): return self.get_concrete().descr_len(space) + def descr_repr(self, space): + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])") + + def descr_str(self, space): + # Simple implementation so that we can see the array. Needs work. + concrete = self.get_concrete() + return space.wrap("[" + " ".join(concrete._getnums(True)) + "]") + def descr_getitem(self, space, w_idx): # TODO: indexing by tuples start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) @@ -101,19 +235,61 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().setitem(start, space.float_w(w_value)) + else: + concrete = self.get_concrete() + if isinstance(w_value, BaseArray): + # for now we just copy if setting part of an array from + # part of itself. can be improved. + if (concrete.get_root_storage() == + w_value.get_concrete().get_root_storage()): + w_value = new_numarray(space, w_value) + else: + w_value = convert_to_array(space, w_value) + concrete.setslice(space, start, stop, step, + slice_length, w_value) def descr_mean(self, space): - s = 0 - concrete = self.get_concrete() - size = concrete.find_size() - for i in xrange(size): - s += concrete.getitem(i) - return space.wrap(s / size) + return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) + def _sliceloop1(self, start, stop, step, source, dest): + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, source, dest): + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + +def convert_to_array (space, w_obj): + if isinstance(w_obj, BaseArray): + return w_obj + elif space.issequence_w(w_obj): + # Convert to array. + return new_numarray(space, w_obj) + else: + # If it's a scalar + return FloatWrapper(space.float_w(w_obj)) class FloatWrapper(BaseArray): """ @@ -249,8 +425,8 @@ return self.parent.getitem(self.calc_index(item)) @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - return self.parent.descr_setitem(space, self.calc_index(item), value) + def setitem(self, item, value): + return self.parent.setitem(self.calc_index(item), value) def descr_len(self, space): return space.wrap(self.find_size()) @@ -264,14 +440,34 @@ def __init__(self, start, stop, step, slice_length, parent, signature): ViewArray.__init__(self, parent, signature) - self.start = start - self.stop = stop - self.step = step + if isinstance(parent, SingleDimSlice): + self.start = parent.calc_index(start) + self.stop = parent.calc_index(stop) + self.step = parent.step * step + self.parent = parent.parent + else: + self.start = start + self.stop = stop + self.step = step + self.parent = parent self.size = slice_length + def get_root_storage(self): + return self.parent.storage + def find_size(self): return self.size + def setslice(self, space, start, stop, step, slice_length, arr): + start = self.calc_index(start) + if stop != -1: + stop = self.calc_index(stop) + step = self.step * step + if step > 0: + self._sliceloop1(start, stop, step, arr, self.parent) + else: + self._sliceloop2(start, stop, step, arr, self.parent) + def calc_index(self, item): return (self.start + item * self.step) @@ -289,46 +485,45 @@ def get_concrete(self): return self + def get_root_storage(self): + return self.storage + def find_size(self): return self.size def eval(self, i): return self.storage[i] - def getindex(self, space, item): - if item >= self.size: - raise operationerrfmt(space.w_IndexError, - '%d above array size', item) - if item < 0: - item += self.size - if item < 0: - raise operationerrfmt(space.w_IndexError, - '%d below zero', item) - return item - def descr_len(self, space): return space.wrap(self.size) def getitem(self, item): return self.storage[item] - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - item = self.getindex(space, item) + def setitem(self, item, value): self.invalidated() self.storage[item] = value + def setslice(self, space, start, stop, step, slice_length, arr): + if step > 0: + self._sliceloop1(start, stop, step, arr, self) + else: + self._sliceloop2(start, stop, step, arr, self) + def __del__(self): lltype.free(self.storage, flavor='raw') -def descr_new_numarray(space, w_type, w_size_or_iterable): +def new_numarray(space, w_size_or_iterable): l = space.listview(w_size_or_iterable) arr = SingleDimArray(len(l)) i = 0 for w_elem in l: arr.storage[i] = space.float_w(space.float(w_elem)) i += 1 - return space.wrap(arr) + return arr + +def descr_new_numarray(space, w_type, w_size_or_iterable): + return space.wrap(new_numarray(space, w_size_or_iterable)) @unwrap_spec(size=int) def zeros(space, size): @@ -345,16 +540,39 @@ 'numarray', __new__ = interp2app(descr_new_numarray), + copy = interp2app(BaseArray.descr_copy), shape = GetSetProperty(BaseArray.descr_get_shape), __len__ = interp2app(BaseArray.descr_len), __getitem__ = interp2app(BaseArray.descr_getitem), __setitem__ = interp2app(BaseArray.descr_setitem), + __pos__ = interp2app(BaseArray.descr_pos), + __neg__ = interp2app(BaseArray.descr_neg), + __abs__ = interp2app(BaseArray.descr_abs), __add__ = interp2app(BaseArray.descr_add), __sub__ = interp2app(BaseArray.descr_sub), __mul__ = interp2app(BaseArray.descr_mul), __div__ = interp2app(BaseArray.descr_div), + __pow__ = interp2app(BaseArray.descr_pow), + __mod__ = interp2app(BaseArray.descr_mod), + __radd__ = interp2app(BaseArray.descr_radd), + __rsub__ = interp2app(BaseArray.descr_rsub), + __rmul__ = interp2app(BaseArray.descr_rmul), + __rdiv__ = interp2app(BaseArray.descr_rdiv), + __rpow__ = interp2app(BaseArray.descr_rpow), + __rmod__ = interp2app(BaseArray.descr_rmod), + __repr__ = interp2app(BaseArray.descr_repr), + __str__ = interp2app(BaseArray.descr_str), mean = interp2app(BaseArray.descr_mean), + sum = interp2app(BaseArray.descr_sum), + prod = interp2app(BaseArray.descr_prod), + max = interp2app(BaseArray.descr_max), + min = interp2app(BaseArray.descr_min), + argmax = interp2app(BaseArray.descr_argmax), + argmin = interp2app(BaseArray.descr_argmin), + all = interp2app(BaseArray.descr_all), + any = interp2app(BaseArray.descr_any), + dot = interp2app(BaseArray.descr_dot), ) diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_support.py @@ -0,0 +1,42 @@ +from pypy.rlib.rstruct.runpack import runpack +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec + + +FLOAT_SIZE = rffi.sizeof(lltype.Float) + + at unwrap_spec(s=str) +def fromstring(space, s): + from pypy.module.micronumpy.interp_numarray import SingleDimArray + length = len(s) + + if length % FLOAT_SIZE == 0: + number = length/FLOAT_SIZE + else: + raise OperationError(space.w_ValueError, space.wrap( + "string length %d not divisable by %d" % (length, FLOAT_SIZE))) + + a = SingleDimArray(number) + + start = 0 + end = FLOAT_SIZE + i = 0 + while i < number: + part = s[start:end] + a.storage[i] = runpack('d', part) + i += 1 + start += FLOAT_SIZE + end += FLOAT_SIZE + + return space.wrap(a) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,31 +1,36 @@ import math -from pypy.interpreter.gateway import unwrap_spec -from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature +from pypy.module.micronumpy.interp_support import Signature from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name - def ufunc(func): signature = Signature() def impl(space, w_obj): - if isinstance(w_obj, BaseArray): - w_res = Call1(func, w_obj, w_obj.signature.transition(signature)) - w_obj.invalidates.append(w_res) + from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array + if space.issequence_w(w_obj): + w_obj_arr = convert_to_array(space, w_obj) + w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) + w_obj_arr.invalidates.append(w_res) return w_res - return space.wrap(func(space.float_w(w_obj))) + else: + return space.wrap(func(space.float_w(w_obj))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): - if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray): - new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature) - w_res = Call2(func, w_lhs, w_rhs, new_sig) - w_lhs.invalidates.append(w_res) - w_rhs.invalidates.append(w_res) + from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array + if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): + w_lhs_arr = convert_to_array(space, w_lhs) + w_rhs_arr = convert_to_array(space, w_rhs) + new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature) + w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig) + w_lhs_arr.invalidates.append(w_res) + w_rhs_arr.invalidates.append(w_res) return w_res - return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) + else: + return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs))) return func_with_new_name(impl, "%s_dispatcher" % func.__name__) @ufunc @@ -33,9 +38,17 @@ return abs(value) @ufunc2 +def add(lvalue, rvalue): + return lvalue + rvalue + + at ufunc2 def copysign(lvalue, rvalue): return rfloat.copysign(lvalue, rvalue) + at ufunc2 +def divide(lvalue, rvalue): + return lvalue / rvalue + @ufunc def exp(value): try: @@ -43,6 +56,10 @@ except OverflowError: return rfloat.INFINITY + at ufunc +def fabs(value): + return math.fabs(value) + @ufunc2 def maximum(lvalue, rvalue): return max(lvalue, rvalue) @@ -51,6 +68,15 @@ def minimum(lvalue, rvalue): return min(lvalue, rvalue) + at ufunc2 +def multiply(lvalue, rvalue): + return lvalue * rvalue + +# Used by numarray for __pos__. Not visible from numpy application space. + at ufunc +def positive(value): + return value + @ufunc def negative(value): return -value @@ -61,6 +87,10 @@ return rfloat.copysign(rfloat.INFINITY, value) return 1.0 / value + at ufunc2 +def subtract(lvalue, rvalue): + return lvalue - rvalue + @ufunc def floor(value): return math.floor(value) @@ -70,3 +100,23 @@ if value == 0.0: return 0.0 return rfloat.copysign(1.0, value) + + at ufunc +def sin(value): + return math.sin(value) + + at ufunc +def cos(value): + return math.cos(value) + + at ufunc +def tan(value): + return math.tan(value) + + at ufunc2 +def power(lvalue, rvalue): + return math.pow(lvalue, rvalue) + + at ufunc2 +def mod(lvalue, rvalue): + return math.fmod(lvalue, rvalue) diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -1,12 +1,10 @@ from pypy.conftest import gettestobjspace from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper - class BaseNumpyAppTest(object): def setup_class(cls): cls.space = gettestobjspace(usemodules=('micronumpy',)) - class TestSignature(object): def test_binop_signature(self, space): ar = SingleDimArray(10) @@ -26,4 +24,4 @@ v3 = ar.descr_add(space, v1) v4 = ar.descr_add(space, v2) - assert v3.signature is v4.signature \ No newline at end of file + assert v3.signature is v4.signature diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1,6 +1,7 @@ import py from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest +from pypy.conftest import gettestobjspace class AppTestNumArray(BaseNumpyAppTest): @@ -37,11 +38,50 @@ a[2] = 4 assert a[2] == 4 + def test_copy(self): + from numpy import array + a = array(range(5)) + b = a.copy() + for i in xrange(5): + assert b[i] == a[i] + def test_iterator_init(self): from numpy import array a = array(range(5)) assert a[3] == 3 + def test_repr(self): + from numpy import array, zeros + a = array(range(5)) + assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])" + a = zeros(1001) + assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_repr_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert repr(b) == "array([1.0, 3.0])" + a = zeros(2002) + b = a[::2] + assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])" + + def test_str(self): + from numpy import array, zeros + a = array(range(5)) + assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + a = zeros(1001) + assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + + def test_str_slice(self): + from numpy import array, zeros + a = array(range(5)) + b = a[1::2] + assert str(b) == "[1.0 3.0]" + a = zeros(2002) + b = a[::2] + assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" + def test_getitem(self): from numpy import array a = array(range(5)) @@ -59,6 +99,51 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + b[::-1] = b + assert b[0] == 1. + assert b[1] == 0. + + def test_setslice_of_slice_array(self): + from numpy import array, zeros + a = zeros(5) + a[::2] = array([9., 10., 11.]) + assert a[0] == 9. + assert a[2] == 10. + assert a[4] == 11. + a[1:4:2][::-1] = array([1., 2.]) + assert a[0] == 9. + assert a[1] == 2. + assert a[2] == 10. + assert a[3] == 1. + assert a[4] == 11. + a = zeros(10) + a[::2][::-1][::2] = array(range(1,4)) + assert a[8] == 1. + assert a[4] == 2. + assert a[0] == 3. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) @@ -96,6 +181,21 @@ for i in range(5): assert b[i] == i + 5 + def test_radd(self): + from numpy import array + r = 3 + array(range(3)) + for i in range(3): + assert r[i] == i + 3 + + def test_add_list(self): + from numpy import array + a = array(range(5)) + b = list(reversed(range(5))) + c = a + b + assert isinstance(c, array) + for i in range(5): + assert c[i] == 4 + def test_subtract(self): from numpy import array a = array(range(5)) @@ -154,6 +254,72 @@ for i in range(5): assert b[i] == i / 5.0 + def test_pow(self): + from numpy import array + a = array(range(5)) + b = a ** a + for i in range(5): + print b[i], i**i + assert b[i] == i**i + + def test_pow_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a ** b + for i in range(5): + assert c[i] == i ** 2 + + def test_pow_constant(self): + from numpy import array + a = array(range(5)) + b = a ** 2 + for i in range(5): + assert b[i] == i ** 2 + + def test_mod(self): + from numpy import array + a = array(range(1,6)) + b = a % a + for i in range(5): + assert b[i] == 0 + + def test_mod_other(self): + from numpy import array + a = array(range(5)) + b = array([2, 2, 2, 2, 2]) + c = a % b + for i in range(5): + assert c[i] == i % 2 + + def test_mod_constant(self): + from numpy import array + a = array(range(5)) + b = a % 2 + for i in range(5): + assert b[i] == i % 2 + + def test_pos(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = +a + for i in range(5): + assert b[i] == a[i] + + def test_neg(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = -a + for i in range(5): + assert b[i] == -a[i] + + def test_abs(self): + from numpy import array + a = array([1.,-2.,3.,-4.,-5.]) + b = abs(a) + for i in range(5): + assert b[i] == abs(a[i]) + def test_auto_force(self): from numpy import array a = array(range(5)) @@ -210,7 +376,97 @@ assert d[1] == 12 def test_mean(self): - from numpy import array, mean + from numpy import array a = array(range(5)) assert a.mean() == 2.0 - assert a[:4].mean() == 1.5 \ No newline at end of file + assert a[:4].mean() == 1.5 + + def test_sum(self): + from numpy import array + a = array(range(5)) + assert a.sum() == 10.0 + assert a[:4].sum() == 6.0 + + def test_prod(self): + from numpy import array + a = array(range(1,6)) + assert a.prod() == 120.0 + assert a[:4].prod() == 24.0 + + def test_max(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.max() == 5.7 + b = array([]) + raises(ValueError, "b.max()") + + def test_max_add(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert (a+a).max() == 11.4 + + def test_min(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.min() == -3.0 + b = array([]) + raises(ValueError, "b.min()") + + def test_argmax(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmax() == 2 + b = array([]) + raises(ValueError, "b.argmax()") + + def test_argmin(self): + from numpy import array + a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) + assert a.argmin() == 3 + b = array([]) + raises(ValueError, "b.argmin()") + + def test_all(self): + from numpy import array + a = array(range(5)) + assert a.all() == False + a[0] = 3.0 + assert a.all() == True + b = array([]) + assert b.all() == True + + def test_any(self): + from numpy import array, zeros + a = array(range(5)) + assert a.any() == True + b = zeros(5) + assert b.any() == False + c = array([]) + assert c.any() == False + + def test_dot(self): + from numpy import array + a = array(range(5)) + assert a.dot(a) == 30.0 + + def test_dot_constant(self): + from numpy import array + a = array(range(5)) + b = a.dot(2.5) + for i in xrange(5): + assert b[i] == 2.5*a[i] + + +class AppTestSupport(object): + def setup_class(cls): + import struct + cls.space = gettestobjspace(usemodules=('micronumpy',)) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + + def test_fromstring(self): + from numpy import fromstring + a = fromstring(self.data) + for i in range(4): + assert a[i] == i + 1 + raises(ValueError, fromstring, "abc") + diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -10,6 +10,40 @@ assert sign(-0.0) == 0.0 assert minimum(2.0, 3.0) == 2.0 + def test_sequence(self): + from numpy import array, negative, minimum + a = array(range(3)) + b = [2.0, 1.0, 0.0] + c = 1.0 + b_neg = negative(b) + assert isinstance(b_neg, array) + for i in range(3): + assert b_neg[i] == -b[i] + min_a_b = minimum(a, b) + assert isinstance(min_a_b, array) + for i in range(3): + assert min_a_b[i] == min(a[i], b[i]) + min_b_a = minimum(b, a) + assert isinstance(min_b_a, array) + for i in range(3): + assert min_b_a[i] == min(a[i], b[i]) + min_a_c = minimum(a, c) + assert isinstance(min_a_c, array) + for i in range(3): + assert min_a_c[i] == min(a[i], c) + min_c_a = minimum(c, a) + assert isinstance(min_c_a, array) + for i in range(3): + assert min_c_a[i] == min(a[i], c) + min_b_c = minimum(b, c) + assert isinstance(min_b_c, array) + for i in range(3): + assert min_b_c[i] == min(b[i], c) + min_c_b = minimum(c, b) + assert isinstance(min_c_b, array) + for i in range(3): + assert min_c_b[i] == min(b[i], c) + def test_negative(self): from numpy import array, negative @@ -31,6 +65,33 @@ for i in range(3): assert b[i] == abs(a[i]) + def test_add(self): + from numpy import array, add + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = add(a, b) + for i in range(3): + assert c[i] == a[i] + b[i] + + def test_divide(self): + from numpy import array, divide + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = divide(a, b) + for i in range(3): + assert c[i] == a[i] / b[i] + + def test_fabs(self): + from numpy import array, fabs + from math import fabs as math_fabs + + a = array([-5.0, -0.0, 1.0]) + b = fabs(a) + for i in range(3): + assert b[i] == math_fabs(a[i]) + def test_minimum(self): from numpy import array, minimum @@ -49,6 +110,15 @@ for i in range(3): assert c[i] == max(a[i], b[i]) + def test_multiply(self): + from numpy import array, multiply + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = multiply(a, b) + for i in range(3): + assert c[i] == a[i] * b[i] + def test_sign(self): from numpy import array, sign @@ -67,6 +137,15 @@ for i in range(4): assert b[i] == reference[i] + def test_subtract(self): + from numpy import array, subtract + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = subtract(a, b) + for i in range(3): + assert c[i] == a[i] - b[i] + def test_floor(self): from numpy import array, floor @@ -99,3 +178,30 @@ except OverflowError: res = float('inf') assert b[i] == res + + def test_sin(self): + import math + from numpy import array, sin + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = sin(a) + for i in range(len(a)): + assert b[i] == math.sin(a[i]) + + def test_cos(self): + import math + from numpy import array, cos + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = cos(a) + for i in range(len(a)): + assert b[i] == math.cos(a[i]) + + def test_tan(self): + import math + from numpy import array, tan + + a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2]) + b = tan(a) + for i in range(len(a)): + assert b[i] == math.tan(a[i]) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,20 +1,30 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call1, Call2, SingleDimSlice, add, mul) + FloatWrapper, Call2, SingleDimSlice, add, mul, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile +from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): - pass + w_ValueError = None + + def issequence_w(self, w_obj): + return True + + @specialize.argtype(1) + def wrap(self, w_obj): + return w_obj + + def float_w(self, w_obj): + return float(w_obj) class TestNumpyJIt(LLJitMixin): def setup_class(cls): cls.space = FakeSpace() def test_add(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, ar, Signature()) @@ -27,8 +37,6 @@ assert result == f(5) def test_floatadd(self): - space = self.space - def f(i): ar = SingleDimArray(i) v = Call2(add, ar, FloatWrapper(4.5), Signature()) @@ -40,11 +48,118 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_already_forecd(self): + def test_sum(self): space = self.space def f(i): ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_sum(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 2, + "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_prod(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_prod(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_max(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_max(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_gt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, + "guard_false": 1, "jump": 1}) + assert result == f(5) + + def test_min(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_min(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + assert result == f(5) + + def test_argmin(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = float(j) + j += 1 + return ar.descr_add(space, ar).descr_argmin(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "float_lt": 1, "int_add": 1, + "int_lt": 1, "guard_true": 2, + "jump": 1}) + assert result == f(5) + + def test_all(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + j = 0 + while j < i: + ar.get_concrete().storage[j] = 1.0 + j += 1 + return ar.descr_add(space, ar).descr_all(space) + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, + "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) + + def test_any(self): + space = self.space + + def f(i): + ar = SingleDimArray(i) + return ar.descr_add(space, ar).descr_any(space) + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({"getarrayitem_raw": 2, "float_add": 1, + "int_add": 1, "float_ne": 1, "guard_false": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) + + def test_already_forecd(self): + def f(i): + ar = SingleDimArray(i) v1 = Call2(add, ar, FloatWrapper(4.5), Signature()) v2 = Call2(mul, v1, FloatWrapper(4.5), Signature()) v1.force_if_needed() @@ -95,8 +210,6 @@ self.check_loop_count(3) def test_slice(self): - space = self.space - def f(i): step = 3 ar = SingleDimArray(step*i) @@ -111,8 +224,6 @@ assert result == f(5) def test_slice2(self): - space = self.space - def f(i): step1 = 2 step2 = 3 @@ -128,6 +239,28 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar2.storage[1] = 5.5 + if NonConstant(False): + arg = ar2 + else: + arg = ar2.descr_add(space, ar2) + ar.setslice(space, 0, step*i, step, i, arg) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 2, + 'float_add' : 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == 11.0 + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py --- a/pypy/module/mmap/interp_mmap.py +++ b/pypy/module/mmap/interp_mmap.py @@ -1,21 +1,16 @@ -from pypy.rpython.tool import rffi_platform -from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped from pypy.rlib import rmmap from pypy.rlib.rmmap import RValueError, RTypeError, ROverflowError -import sys -import os -import platform -import stat + class W_MMap(Wrappable): def __init__(self, space, mmap_obj): self.space = space self.mmap = mmap_obj - + def close(self): self.mmap.close() diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -125,13 +125,13 @@ assert st.st_size == 14 assert st.st_nlink == 1 - #if sys.platform.startswith('linux2'): + #if sys.platform.startswith('linux'): # # expects non-integer timestamps - it's unlikely that they are # # all three integers # assert ((st.st_atime, st.st_mtime, st.st_ctime) != # (st[7], st[8], st[9])) # assert st.st_blksize * st.st_blocks >= st.st_size - if sys.platform.startswith('linux2'): + if sys.platform.startswith('linux'): assert hasattr(st, 'st_rdev') def test_stat_float_times(self): diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -15,7 +15,6 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.baseobjspace import ObjSpace, W_Root from opcode import opmap -from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.nonconst import NonConstant from pypy.jit.metainterp.resoperation import rop from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes @@ -45,9 +44,11 @@ ec.w_tracefunc is None) def can_never_inline(next_instr, is_being_profiled, bytecode): + return False + +def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode): return (bytecode.co_flags & CO_GENERATOR) != 0 - def wrap_oplist(space, logops, operations): list_w = [] for op in operations: @@ -66,7 +67,7 @@ def on_compile(self, logger, looptoken, operations, type, next_instr, is_being_profiled, ll_pycode): from pypy.rpython.annlowlevel import cast_base_ptr_to_instance - + space = self.space cache = space.fromcache(Cache) if cache.in_recursion: @@ -111,7 +112,9 @@ get_jitcell_at = get_jitcell_at, set_jitcell_at = set_jitcell_at, confirm_enter_jit = confirm_enter_jit, - can_never_inline = can_never_inline) + can_never_inline = can_never_inline, + should_unroll_one_iteration = + should_unroll_one_iteration) class __extend__(PyFrame): @@ -170,7 +173,7 @@ # ____________________________________________________________ # -# Public interface +# Public interface def set_param(space, __args__): '''Configure the tunable JIT parameters. @@ -212,7 +215,7 @@ class Cache(object): in_recursion = False - + def __init__(self, space): self.w_compile_hook = space.w_None diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -1,9 +1,9 @@ from pypy.interpreter.typedef import TypeDef, interp_attrproperty -from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import unwrap_spec, interp2app from pypy.interpreter.pycode import PyCode -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.lltypesystem.rclass import OBJECT diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -30,7 +30,6 @@ assert res == 8.0 * 300 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('fficall', """ - p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>) guard_not_invalidated(descr=...) i17 = force_token() setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -19,7 +19,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) + guard_true(i7, descr=...) i9 = int_add(i5, 1) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) @@ -39,11 +39,12 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated(descr=...) i13 = int_lt(i7, i9) - guard_true(i13, descr=) + guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>) i16 = int_add_ovf(i8, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = int_add(i7, 1) --TICK-- jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=) @@ -68,16 +69,17 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i13 = int_lt(i8, 307200) - guard_true(i13, descr=) + guard_true(i13, descr=...) + guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>) i15 = int_add_ovf(i9, i14) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>) i19 = int_add_ovf(i18, i15) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) # on 64bit, there is a guard checking that i19 actually fits into 32bit ... setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -80,19 +80,19 @@ # assert entry_bridge.match_by_id('call', """ p29 = getfield_gc(ConstPtr(ptr28), descr=) - guard_nonnull_class(p29, ConstClass(Function), descr=) + guard_nonnull_class(p29, ConstClass(Function), descr=...) p33 = getfield_gc(p29, descr=) - guard_value(p33, ConstPtr(ptr34), descr=) + guard_value(p33, ConstPtr(ptr34), descr=...) p35 = getfield_gc(p29, descr=) p36 = getfield_gc(p29, descr=) p38 = call(ConstClass(getexecutioncontext), descr=) p39 = getfield_gc(p38, descr=) i40 = force_token() p41 = getfield_gc(p38, descr=) - guard_isnull(p41, descr=) + guard_isnull(p41, descr=...) i42 = getfield_gc(p38, descr=) i43 = int_is_zero(i42) - guard_true(i43, descr=) + guard_true(i43, descr=...) i50 = force_token() """) # @@ -101,16 +101,16 @@ loop, = log.loops_by_id('call') assert loop.match(""" i12 = int_lt(i5, i6) - guard_true(i12, descr=) + guard_true(i12, descr=...) i13 = force_token() i15 = int_add(i5, 1) i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i21 = int_add_ovf(i20, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=) """) @@ -146,14 +146,14 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i15 = int_lt(i6, i9) - guard_true(i15, descr=) - guard_not_invalidated(descr=) + guard_true(i15, descr=...) + guard_not_invalidated(descr=...) i16 = force_token() i17 = int_add_ovf(i10, i6) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() i19 = int_add_ovf(i10, i17) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=) """) @@ -180,11 +180,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i14 = int_lt(i6, i9) - guard_true(i14, descr=) - guard_not_invalidated(descr=) + guard_true(i14, descr=...) + guard_not_invalidated(descr=...) i15 = force_token() i17 = int_add_ovf(i8, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) i18 = force_token() --TICK-- jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=) @@ -282,32 +282,30 @@ loop0, = log.loops_by_id('g1') assert loop0.match_by_id('g1', """ i20 = force_token() - setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>) i22 = int_add_ovf(i8, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('h1', """ i20 = force_token() i22 = int_add_ovf(i8, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop0.match_by_id('g2', """ i27 = force_token() i29 = int_add_ovf(i26, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) # loop1, = log.loops_by_id('g3') assert loop1.match_by_id('g3', """ i21 = force_token() - setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) i23 = int_add_ovf(i9, 3) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) assert loop1.match_by_id('h2', """ i25 = force_token() i27 = int_add_ovf(i23, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) """) def test_stararg(self): @@ -353,7 +351,7 @@ i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=) - guard_no_exception(descr=) + guard_no_exception(descr=...) p17 = getfield_gc(p8, descr=) p19 = new_with_vtable(ConstClass(W_IntObject)) setfield_gc(p19, i12, descr=) @@ -405,9 +403,9 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i10 = int_lt(i5, i6) - guard_true(i10, descr=) + guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i120 = int_add(i5, 1) - guard_not_invalidated(descr=) --TICK-- jump(..., descr=) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -23,3 +23,29 @@ ops = loop.ops_by_id('look') assert log.opnames(ops) == ['setfield_gc', 'guard_not_invalidated'] + + def test_identitydict(self): + def fn(n): + class X(object): + pass + x = X() + d = {} + d[x] = 1 + res = 0 + for i in range(300): + value = d[x] # ID: getitem + res += value + return res + # + log = self.run(fn, [1000]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # check that the call to ll_dict_lookup is not a call_may_force + assert loop.match_by_id("getitem", """ + i25 = call(ConstClass(_ll_1_gc_identityhash__objectPtr), p6, descr=...) + ... + i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...) + ... + p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py --- a/pypy/module/pypyjit/test_pypy_c/test_exception.py +++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py @@ -36,11 +36,11 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i5 = int_is_true(i3) - guard_true(i5, descr=) - guard_not_invalidated(descr=) + guard_true(i5, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i12 = int_sub_ovf(i3, 1) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(..., descr=) """) @@ -84,8 +84,8 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i4, i5) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) --EXC-TICK-- i14 = int_add(i4, 1) --TICK-- diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py @@ -0,0 +1,25 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGenerators(BaseTestPyPyC): + def test_simple_generator(self): + def main(n): + def f(): + for i in range(10000): + yield i + + def g(): + for i in f(): # ID: generator + pass + + g() + + log = self.run(main, [500]) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("generator", """ + i16 = force_token() + p45 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p45, i29, descr=) + setarrayitem_gc(p8, 0, p45, descr=) + jump(..., descr=...) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -0,0 +1,30 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGlobals(BaseTestPyPyC): + def test_load_builtin(self): + def main(n): + import pypyjit + + i = 0 + while i < n: + l = len # ID: loadglobal + i += pypyjit.residual_call(l, "a") + return i + # + log = self.run(main, [500]) + assert log.result == 500 + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("loadglobal", """ + p10 = getfield_gc(p0, descr=) + guard_value(p10, ConstPtr(ptr11), descr=...) + p12 = getfield_gc(p10, descr=) + guard_value(p12, ConstPtr(ptr13), descr=...) + p15 = getfield_gc(ConstPtr(ptr14), descr=) + guard_isnull(p15, descr=...) + guard_not_invalidated(descr=...) + p19 = getfield_gc(ConstPtr(p17), descr=) + guard_value(p19, ConstPtr(ptr20), descr=...) + p22 = getfield_gc(ConstPtr(ptr21), descr=) + guard_nonnull(p22, descr=...) + """) \ No newline at end of file diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py --- a/pypy/module/pypyjit/test_pypy_c/test_import.py +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -15,13 +15,13 @@ assert log.result == 500 loop, = log.loops_by_id('import') assert loop.match_by_id('import', """ + guard_not_invalidated(descr=...) p11 = getfield_gc(ConstPtr(ptr10), descr=) - guard_value(p11, ConstPtr(ptr12), descr=) - guard_not_invalidated(descr=) + guard_value(p11, ConstPtr(ptr12), descr=...) p14 = getfield_gc(ConstPtr(ptr13), descr=) p16 = getfield_gc(ConstPtr(ptr15), descr=) - guard_value(p14, ConstPtr(ptr17), descr=) - guard_isnull(p16, descr=) + guard_value(p14, ConstPtr(ptr17), descr=...) + guard_isnull(p16, descr=...) """) def test_import_fast_path(self, tmpdir): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -22,10 +22,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i7 = int_lt(i5, i6) - guard_true(i7, descr=) - guard_not_invalidated(descr=) + guard_true(i7, descr=...) + guard_not_invalidated(descr=...) i9 = int_add_ovf(i5, 2) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i9, i6, descr=) """) @@ -47,10 +47,10 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" i9 = int_lt(i5, i6) - guard_true(i9, descr=) - guard_not_invalidated(descr=) + guard_true(i9, descr=...) + guard_not_invalidated(descr=...) i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=) + guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=) """) @@ -115,7 +115,7 @@ # ---------------------- loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i9 = int_lt(i7, i8) + i9 = int_lt(i8, i7) guard_true(i9, descr=.*) guard_not_invalidated(descr=.*) i11 = int_add(i8, 1) @@ -124,7 +124,7 @@ p20 = new_with_vtable(ConstClass(W_IntObject)) From noreply at buildbot.pypy.org Mon Jul 25 23:21:40 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:40 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: fix test Message-ID: <20110725212140.83ED9829C2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45988:08ac45421b77 Date: 2011-07-25 19:36 +0200 http://bitbucket.org/pypy/pypy/changeset/08ac45421b77/ Log: fix test diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2322,7 +2322,7 @@ p2 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p2, p4, descr=nextdescr) setfield_gc(p1, p2, descr=nextdescr) - jump(p1, i2, i4, p4) + jump(p1, i2, i4, p4, i4) """ expected = """ [p1, i2, i4, p4, i5] From noreply at buildbot.pypy.org Mon Jul 25 23:21:41 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:41 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: reusing strlen from preamble in peeled loop Message-ID: <20110725212141.B81BD829C2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45989:ab6c3a539326 Date: 2011-07-25 19:50 +0200 http://bitbucket.org/pypy/pypy/changeset/ab6c3a539326/ Log: reusing strlen from preamble in peeled loop diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5337,7 +5337,7 @@ p3 = call(0, p1, p2, descr=strconcatdescr) jump(p2, p3) """ - expected = """ + preamble = """ [p1, p2] i1 = strlen(p1) i2 = strlen(p2) @@ -5345,9 +5345,18 @@ p3 = newstr(i3) copystrcontent(p1, p3, 0, 0, i1) copystrcontent(p2, p3, 0, i1, i2) - jump(p2, p3) - """ - self.optimize_strunicode_loop(ops, expected, expected) + jump(p2, p3, i2) + """ + expected = """ + [p1, p2, i1] + i2 = strlen(p2) + i3 = int_add(i1, i2) + p3 = newstr(i3) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) + jump(p2, p3, i2) + """ + self.optimize_strunicode_loop(ops, expected, preamble) def test_str_concat_vstr2_str(self): ops = """ diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py --- a/pypy/jit/metainterp/optimizeopt/virtualstate.py +++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py @@ -243,7 +243,7 @@ bad[self] = True bad[other] = True return False - elif self.lenbound or other.lenbound: + elif self.lenbound: bad[self] = True bad[other] = True return False From noreply at buildbot.pypy.org Mon Jul 25 23:21:42 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:42 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: reusing strlen from preamble in peeled loop Message-ID: <20110725212142.EA94E829C2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45990:3b1f1439c0b2 Date: 2011-07-25 19:53 +0200 http://bitbucket.org/pypy/pypy/changeset/3b1f1439c0b2/ Log: reusing strlen from preamble in peeled loop diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5409,7 +5409,7 @@ p5 = call(0, p4, p3, descr=strconcatdescr) jump(p2, p3, p5) """ - expected = """ + preamble = """ [p1, p2, p3] i1 = strlen(p1) i2 = strlen(p2) @@ -5420,9 +5420,20 @@ copystrcontent(p1, p5, 0, 0, i1) copystrcontent(p2, p5, 0, i1, i2) copystrcontent(p3, p5, 0, i12, i3) - jump(p2, p3, p5) - """ - self.optimize_strunicode_loop(ops, expected, expected) + jump(p2, p3, p5, i2, i3) + """ + expected = """ + [p1, p2, p3, i1, i2] + i12 = int_add(i1, i2) + i3 = strlen(p3) + i123 = int_add(i12, i3) + p5 = newstr(i123) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) + jump(p2, p3, p5, i2, i3) + """ + self.optimize_strunicode_loop(ops, expected, preamble) def test_str_concat_str_cstr1(self): ops = """ From noreply at buildbot.pypy.org Mon Jul 25 23:21:44 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:44 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: these are better optimized now Message-ID: <20110725212144.305D6829C2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45991:f32e84f613db Date: 2011-07-25 20:45 +0200 http://bitbucket.org/pypy/pypy/changeset/f32e84f613db/ Log: these are better optimized now diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -5471,16 +5471,23 @@ def test_str_slice_len_surviving1(self): ops = """ [p1, i1, i2, i3] + escape(i3) p2 = call(0, p1, i1, i2, descr=strslicedescr) i4 = strlen(p2) jump(p1, i1, i2, i4) """ - expected = """ + preamble = """ [p1, i1, i2, i3] + escape(i3) i4 = int_sub(i2, i1) - jump(p1, i1, i2, i4) - """ - self.optimize_strunicode_loop(ops, expected, expected) + jump(p1, i1, i2, i4, i4) + """ + expected = """ + [p1, i1, i2, i3, i4] + escape(i3) + jump(p1, i1, i2, i4, i4) + """ + self.optimize_strunicode_loop(ops, expected, preamble) def test_str_slice_len_surviving2(self): ops = """ @@ -5498,14 +5505,13 @@ escape(i5) i4 = int_sub(i2, i1) setfield_gc(p2, i4, descr=valuedescr) - jump(p1, i1, i2, p2, i4) - """ - expected = """ - [p1, i1, i2, p2, i5] + jump(p1, i1, i2, p2, i4, i4) + """ + expected = """ + [p1, i1, i2, p2, i5, i6] escape(i5) - i6 = int_sub(i2, i1) setfield_gc(p2, i6, descr=valuedescr) - jump(p1, i1, i2, p2, i6) + jump(p1, i1, i2, p2, i6, i6) """ self.optimize_strunicode_loop(ops, expected, preamble) @@ -5515,14 +5521,20 @@ p2 = call(0, p1, i1, i2, descr=strslicedescr) jump(p2, i1, i2) """ - expected = """ + preamble = """ [p1, i1, i2] i3 = int_sub(i2, i1) p2 = newstr(i3) copystrcontent(p1, p2, i1, 0, i3) - jump(p2, i1, i2) - """ - self.optimize_strunicode_loop(ops, expected, expected) + jump(p2, i1, i2, i3) + """ + expected = """ + [p1, i1, i2, i3] + p2 = newstr(i3) + copystrcontent(p1, p2, i1, 0, i3) + jump(p2, i1, i2, i3) + """ + self.optimize_strunicode_loop(ops, expected, preamble) def test_str_slice_2(self): ops = """ @@ -5545,16 +5557,22 @@ p3 = call(0, p2, i3, i4, descr=strslicedescr) jump(p3, i1, i2, i3, i4) """ - expected = """ + preamble = """ [p1, i1, i2, i3, i4] i0 = int_sub(i2, i1) # killed by the backend i5 = int_sub(i4, i3) i6 = int_add(i1, i3) p3 = newstr(i5) copystrcontent(p1, p3, i6, 0, i5) - jump(p3, i1, i2, i3, i4) - """ - self.optimize_strunicode_loop(ops, expected, expected) + jump(p3, i1, i2, i3, i4, i5, i6) + """ + expected = """ + [p1, i1, i2, i3, i4, i5, i6] + p3 = newstr(i5) + copystrcontent(p1, p3, i6, 0, i5) + jump(p3, i1, i2, i3, i4, i5, i6) + """ + self.optimize_strunicode_loop(ops, expected, preamble) def test_str_slice_getitem1(self): ops = """ @@ -5564,15 +5582,21 @@ escape(i4) jump(p1, i1, i2, i3) """ - expected = """ + preamble = """ [p1, i1, i2, i3] i6 = int_sub(i2, i1) # killed by the backend i5 = int_add(i1, i3) i4 = strgetitem(p1, i5) escape(i4) - jump(p1, i1, i2, i3) - """ - self.optimize_strunicode_loop(ops, expected, expected) + jump(p1, i1, i2, i3, i5) + """ + expected = """ + [p1, i1, i2, i3, i5] + i4 = strgetitem(p1, i5) + escape(i4) + jump(p1, i1, i2, i3, i5) + """ + self.optimize_strunicode_loop(ops, expected, preamble) def test_str_slice_plain(self): ops = """ @@ -5599,7 +5623,7 @@ p4 = call(0, p3, p2, descr=strconcatdescr) jump(p4, i1, i2, p2) """ - expected = """ + preamble = """ [p1, i1, i2, p2] i3 = int_sub(i2, i1) # length of p3 i4 = strlen(p2) @@ -5607,9 +5631,16 @@ p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) copystrcontent(p2, p4, 0, i3, i4) - jump(p4, i1, i2, p2) - """ - self.optimize_strunicode_loop(ops, expected, expected) + jump(p4, i1, i2, p2, i5, i3, i4) + """ + expected = """ + [p1, i1, i2, p2, i5, i3, i4] + p4 = newstr(i5) + copystrcontent(p1, p4, i1, 0, i3) + copystrcontent(p2, p4, 0, i3, i4) + jump(p4, i1, i2, p2, i5, i3, i4) + """ + self.optimize_strunicode_loop(ops, expected, preamble) def test_strgetitem_bounds(self): ops = """ @@ -5710,7 +5741,7 @@ escape(i0) jump(p1, p2, p3) """ - expected = """ + preamble = """ [p1, p2, p3] i1 = strlen(p1) i2 = strlen(p2) @@ -5720,10 +5751,19 @@ copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) - jump(p1, p2, p3) + jump(p1, p2, p3, i3, i1, i2) + """ + expected = """ + [p1, p2, p3, i3, i1, i2] + p4 = newstr(i3) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) + i0 = call(0, p3, p4, descr=strequaldescr) + escape(i0) + jump(p1, p2, p3, i3, i1, i2) """ self.optimize_strunicode_loop_extradescrs(ops, expected, - expected) + preamble) def test_str_equal_slice1(self): ops = """ @@ -5733,15 +5773,21 @@ escape(i0) jump(p1, i1, i2, p3) """ - expected = """ + preamble = """ [p1, i1, i2, p3] i3 = int_sub(i2, i1) i0 = call(0, p1, i1, i3, p3, descr=streq_slice_checknull_descr) escape(i0) - jump(p1, i1, i2, p3) + jump(p1, i1, i2, p3, i3) + """ + expected = """ + [p1, i1, i2, p3, i3] + i0 = call(0, p1, i1, i3, p3, descr=streq_slice_checknull_descr) + escape(i0) + jump(p1, i1, i2, p3, i3) """ self.optimize_strunicode_loop_extradescrs(ops, expected, - expected) + preamble) def test_str_equal_slice2(self): ops = """ @@ -5751,15 +5797,21 @@ escape(i0) jump(p1, i1, i2, p3) """ - expected = """ + preamble = """ [p1, i1, i2, p3] i4 = int_sub(i2, i1) i0 = call(0, p1, i1, i4, p3, descr=streq_slice_checknull_descr) escape(i0) - jump(p1, i1, i2, p3) + jump(p1, i1, i2, p3, i4) + """ + expected = """ + [p1, i1, i2, p3, i4] + i0 = call(0, p1, i1, i4, p3, descr=streq_slice_checknull_descr) + escape(i0) + jump(p1, i1, i2, p3, i4) """ self.optimize_strunicode_loop_extradescrs(ops, expected, - expected) + preamble) def test_str_equal_slice3(self): ops = """ @@ -5771,11 +5823,10 @@ jump(p1, i1, i2, p3) """ expected = """ - [p1, i1, i2, p3] - i4 = int_sub(i2, i1) + [p1, i1, i2, p3, i4] i0 = call(0, p1, i1, i4, p3, descr=streq_slice_nonnull_descr) escape(i0) - jump(p1, i1, i2, p3) + jump(p1, i1, i2, p3, i4) """ preamble = """ [p1, i1, i2, p3] @@ -5783,7 +5834,7 @@ i4 = int_sub(i2, i1) i0 = call(0, p1, i1, i4, p3, descr=streq_slice_nonnull_descr) escape(i0) - jump(p1, i1, i2, p3) + jump(p1, i1, i2, p3, i4) """ self.optimize_strunicode_loop_extradescrs(ops, expected, preamble) @@ -5796,15 +5847,21 @@ escape(i0) jump(p1, i1, i2) """ - expected = """ + preamble = """ [p1, i1, i2] i3 = int_sub(i2, i1) i0 = call(0, p1, i1, i3, 120, descr=streq_slice_char_descr) escape(i0) - jump(p1, i1, i2) + jump(p1, i1, i2, i3) + """ + expected = """ + [p1, i1, i2, i3] + i0 = call(0, p1, i1, i3, 120, descr=streq_slice_char_descr) + escape(i0) + jump(p1, i1, i2, i3) """ self.optimize_strunicode_loop_extradescrs(ops, expected, - expected) + preamble) def test_str_equal_slice5(self): ops = """ @@ -5816,15 +5873,21 @@ escape(i0) jump(p1, i1, i2, i3) """ - expected = """ + preamble = """ [p1, i1, i2, i3] i4 = int_sub(i2, i1) i0 = call(0, p1, i1, i4, i3, descr=streq_slice_char_descr) escape(i0) - jump(p1, i1, i2, i3) + jump(p1, i1, i2, i3, i4) + """ + expected = """ + [p1, i1, i2, i3, i4] + i0 = call(0, p1, i1, i4, i3, descr=streq_slice_char_descr) + escape(i0) + jump(p1, i1, i2, i3, i4) """ self.optimize_strunicode_loop_extradescrs(ops, expected, - expected) + preamble) def test_str_equal_none1(self): ops = """ @@ -5888,11 +5951,9 @@ jump(p1) """ expected = """ - [p1] - i1 = strlen(p1) - i0 = int_eq(i1, 0) + [p1, i0] escape(i0) - jump(p1) + jump(p1, i0) """ preamble = """ [p1] @@ -5900,7 +5961,7 @@ i1 = strlen(p1) i0 = int_eq(i1, 0) escape(i0) - jump(p1) + jump(p1, i0) """ self.optimize_strunicode_loop_extradescrs(ops, expected, preamble) @@ -5935,7 +5996,7 @@ escape(i0) jump(p1, p2) """ - expected = """ + preamble = """ [p1, p2] i1 = strlen(p1) i2 = strlen(p2) @@ -5945,9 +6006,18 @@ copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) - jump(p1, p2) - """ - self.optimize_strunicode_loop_extradescrs(ops, expected, expected) + jump(p1, p2, i3, i1, i2) + """ + expected = """ + [p1, p2, i3, i1, i2] + p4 = newstr(i3) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) + i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) + escape(i0) + jump(p1, p2, i3, i1, i2) + """ + self.optimize_strunicode_loop_extradescrs(ops, expected, preamble) def test_str_equal_chars0(self): ops = """ diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -254,6 +254,9 @@ self.optimizer.flush() self.optimizer.emitting_dissabled = False + import pdb; pdb.set_trace() + + initial_inputargs_len = len(inputargs) self.inliner = Inliner(loop.inputargs, jump_args) diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -430,6 +430,8 @@ self.make_equal_to(op.result, vresult) def strgetitem(self, value, vindex, mode): + import pdb; pdb.set_trace() + value.ensure_nonnull() # if value.is_virtual() and isinstance(value, VStringSliceValue): diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2844,7 +2844,7 @@ # 1 preamble and 6 speciealized versions of each loop self.check_tree_loop_count(2*(1 + 6)) - def test_continue_tracing_with_boxes_in_start_snapshot_replaced_by_optimizer(self): + def test_continue_tracing_with_boxes_in_start_snapshot_replaced_by_optimizer(self): myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'a', 'b']) def f(n): sa = a = 0 @@ -2883,11 +2883,6 @@ res = self.meta_interp(f, [32]) assert res == f(32) self.check_loops(arraylen_gc=1) - - - - - class TestOOtype(BasicTests, OOJitMixin): From noreply at buildbot.pypy.org Mon Jul 25 23:21:45 2011 From: noreply at buildbot.pypy.org (hakanardo) Date: Mon, 25 Jul 2011 23:21:45 +0200 (CEST) Subject: [pypy-commit] pypy jit-short_from_state: use optimization.propagate_forward instead to respect optimize_... methods Message-ID: <20110725212145.609D5829C2@wyvern.cs.uni-duesseldorf.de> Author: Hakan Ardo Branch: jit-short_from_state Changeset: r45992:129d2996f377 Date: 2011-07-25 20:52 +0200 http://bitbucket.org/pypy/pypy/changeset/129d2996f377/ Log: use optimization.propagate_forward instead to respect optimize_... methods diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -254,9 +254,6 @@ self.optimizer.flush() self.optimizer.emitting_dissabled = False - import pdb; pdb.set_trace() - - initial_inputargs_len = len(inputargs) self.inliner = Inliner(loop.inputargs, jump_args) diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -61,7 +61,7 @@ self.ensure_nonnull() box = self.force_box() lengthbox = BoxInt() - optimization.optimize_default(ResOperation(mode.STRLEN, [box], lengthbox)) + optimization.propagate_forward(ResOperation(mode.STRLEN, [box], lengthbox)) return lengthbox @specialize.arg(1) @@ -335,7 +335,7 @@ if optimizer is None: return None resbox = BoxInt() - optimizer.optimize_default(ResOperation(rop.INT_ADD, [box1, box2], resbox)) + optimizer.propagate_forward(ResOperation(rop.INT_ADD, [box1, box2], resbox)) return resbox def _int_sub(optimizer, box1, box2): @@ -345,7 +345,7 @@ if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() - optimizer.optimize_default(ResOperation(rop.INT_SUB, [box1, box2], resbox)) + optimizer.propagate_forward(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox def _strgetitem(optimizer, strbox, indexbox, mode): @@ -357,7 +357,7 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) resbox = BoxInt() - optimizer.optimize_default(ResOperation(mode.STRGETITEM, [strbox, indexbox], + optimizer.propagate_forward(ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox @@ -430,8 +430,6 @@ self.make_equal_to(op.result, vresult) def strgetitem(self, value, vindex, mode): - import pdb; pdb.set_trace() - value.ensure_nonnull() # if value.is_virtual() and isinstance(value, VStringSliceValue): From noreply at buildbot.pypy.org Tue Jul 26 00:13:49 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 26 Jul 2011 00:13:49 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove some dead imports, organize some more. Message-ID: <20110725221349.95244829C2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45993:e35164a2e0ff Date: 2011-07-25 15:13 -0700 http://bitbucket.org/pypy/pypy/changeset/e35164a2e0ff/ Log: Remove some dead imports, organize some more. diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -1,7 +1,7 @@ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.libffi import Func -from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method @@ -48,7 +48,7 @@ inst_argtypes is actually a low-level array, but we can use it directly since the only thing we do with it is to read its items """ - + llfunc = funcval.box.getref_base() if we_are_translated(): func = cast_base_ptr_to_instance(Func, llfunc) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,6 +1,6 @@ import os from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.optimizeopt.optimizer import Optimization diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,9 +1,9 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, - IntLowerBound, IntUpperBound) -from pypy.jit.metainterp.history import Const, ConstInt -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntLowerBound, + IntUpperBound) +from pypy.jit.metainterp.history import ConstInt +from pypy.jit.metainterp.resoperation import rop class OptIntBounds(Optimization): """Keeps track of the bounds placed on integers by guards and remove diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -1,17 +1,11 @@ -from pypy.jit.metainterp.history import Box, BoxInt, LoopToken, BoxFloat,\ - ConstFloat -from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF +from pypy.jit.metainterp import jitprof, resume, compile +from pypy.jit.metainterp.executor import execute_nonspec +from pypy.jit.metainterp.history import BoxInt, BoxFloat, Const, ConstInt, REF +from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded +from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method, + args_dict) from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp import jitprof -from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs -from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict -from pypy.jit.metainterp.optimize import InvalidLoop -from pypy.jit.metainterp import resume, compile from pypy.jit.metainterp.typesystem import llhelper, oohelper -from pypy.rpython.lltypesystem import lltype -from pypy.jit.metainterp.history import AbstractDescr, make_hashable_int -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded from pypy.tool.pairtype import extendabletype LEVEL_UNKNOWN = '\x00' diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,10 +1,11 @@ +from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.metainterp.history import ConstInt, make_hashable_int +from pypy.jit.metainterp.optimize import InvalidLoop +from pypy.jit.metainterp.optimizeopt.intutils import IntBound from pypy.jit.metainterp.optimizeopt.optimizer import * -from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex -from pypy.jit.metainterp.history import ConstInt from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method -from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.metainterp.optimizeopt.intutils import IntBound +from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop, + ResOperation) from pypy.rlib.rarithmetic import highest_bit diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -1,13 +1,11 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * -from pypy.jit.metainterp.optimizeopt.virtualize import AbstractVirtualValue from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.compile import ResumeGuardDescr from pypy.jit.metainterp.resume import Snapshot from pypy.jit.metainterp.history import TreeLoop, LoopToken -from pypy.rlib.debug import debug_start, debug_stop, debug_print +from pypy.rlib.debug import debug_print from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.jitexc import JitException -from pypy.jit.metainterp.history import make_hashable_int from pypy.jit.codewriter.effectinfo import EffectInfo # Assumptions @@ -22,7 +20,7 @@ # are also recreated to allow virtuals not supported to be forced. # # First of all, the optimizations are not allowed to introduce new -# boxes. It is the unoptimized version of the trace that is inlined to +# boxes. It is the unoptimized version of the trace that is inlined to # form the second iteration of the loop. Otherwise the # state of the virtuals would not be updated correctly. Whenever some # box from the first iteration is reused in the second iteration, it @@ -57,7 +55,7 @@ # be absorbed into the virtual p2 and never seen by the heap # optimizer. At the end of the loop both p2 and p3 are virtuals, but # the loop needs p2 to be a pointer to be able to call itself. So it -# is forced producing the operations +# is forced producing the operations # # p2 = new_with_vtable(ConstClass(node_vtable)) # setfield_gc(p2, i2, descr=nextdescr) @@ -68,7 +66,7 @@ # the trace were optimized under the wrong assumption that the # setfield_gc was store sinked which could lead to errors. In this # case what would happen is that it would be inserted once more in -# front of the guard. +# front of the guard. @@ -112,7 +110,7 @@ def inline_descr_inplace(self, descr): if isinstance(descr, ResumeGuardDescr): descr.rd_snapshot = self.inline_snapshot(descr.rd_snapshot) - + def inline_arg(self, arg): if arg is None: return None @@ -139,7 +137,7 @@ return False return True - def generate_guards(self, other, args, cpu, extra_guards): + def generate_guards(self, other, args, cpu, extra_guards): assert len(self.state) == len(other.state) == len(args) for i in range(len(self.state)): self.state[i].generate_guards(other.state[i], args[i], @@ -153,7 +151,7 @@ def register_virtual_fields(self, keybox, fieldboxes): self.fieldboxes[keybox] = fieldboxes - + def already_seen_virtual(self, keybox): return keybox in self.fieldboxes @@ -233,20 +231,20 @@ if self.level == LEVEL_CONSTANT: import pdb; pdb.set_trace() raise NotImplementedError - + class UnrollOptimizer(Optimization): """Unroll the loop into two iterations. The first one will become the preamble or entry bridge (don't think there is a distinction anymore)""" - + def __init__(self, metainterp_sd, loop, optimizations): self.optimizer = Optimizer(metainterp_sd, loop, optimizations) self.cloned_operations = [] for op in self.optimizer.loop.operations: newop = op.clone() self.cloned_operations.append(newop) - + def propagate_all_forward(self): loop = self.optimizer.loop jumpop = loop.operations[-1] @@ -284,7 +282,7 @@ assert isinstance(start_resumedescr, ResumeGuardDescr) snapshot = start_resumedescr.rd_snapshot while snapshot is not None: - snapshot_args = snapshot.boxes + snapshot_args = snapshot.boxes new_snapshot_args = [] for a in snapshot_args: if not isinstance(a, Const): @@ -313,7 +311,7 @@ short_loop.inputargs = loop.preamble.inputargs[:] short_loop.operations = short - # Clone ops and boxes to get private versions and + # Clone ops and boxes to get private versions and newargs = [a.clonebox() for a in short_loop.inputargs] inliner = Inliner(short_loop.inputargs, newargs) short_loop.inputargs = newargs @@ -336,10 +334,10 @@ for op in short_loop.operations: if op.result: op.result.forget_value() - + def inline(self, loop_operations, loop_args, jump_args): self.inliner = inliner = Inliner(loop_args, jump_args) - + for v in self.optimizer.values.values(): v.last_guard_index = -1 # FIXME: Are there any more indexes stored? @@ -371,12 +369,12 @@ jumpargs = jmp.getarglist() # FIXME: Should also loop over operations added by forcing things in this loop - for op in newoperations: + for op in newoperations: boxes_created_this_iteration[op.result] = True args = op.getarglist() if op.is_guard(): args = args + op.getfailargs() - + for a in args: if not isinstance(a, Const) and not a in boxes_created_this_iteration: if a not in inputargs: @@ -439,7 +437,7 @@ "at preamble position: ", preamble_i, "loop position: ", loop_i) return None - + if self.sameop(newop, loop_ops[loop_i]) \ and loop_i < len(loop_ops): try: @@ -460,7 +458,7 @@ "loop position: ", loop_i) return None short_preamble.append(op) - + state.update(op) preamble_i += 1 @@ -470,7 +468,7 @@ "at position", loop_i) return None - + jumpargs = [] for i in range(len(loop.inputargs)): try: @@ -498,7 +496,7 @@ return None if op.result: seen[op.result] = True - + return short_preamble class ExeState(object): @@ -508,7 +506,7 @@ self.unsafe_getitem = {} self.unsafe_getarrayitem = {} self.unsafe_getarrayitem_indexes = {} - + # Make sure it is safe to move the instrucions in short_preamble # to the top making short_preamble followed by loop equvivalent # to preamble @@ -549,11 +547,11 @@ effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False - + def update(self, op): if (op.has_no_side_effect() or op.is_ovf() or - op.is_guard()): + op.is_guard()): return opnum = op.getopnum() descr = op.getdescr() @@ -566,7 +564,7 @@ if (opnum == rop.SETARRAYITEM_GC or opnum == rop.SETARRAYITEM_RAW): index = op.getarg(1) - if isinstance(index, Const): + if isinstance(index, Const): d = self.unsafe_getarrayitem_indexes.get(descr, None) if d is None: d = self.unsafe_getarrayitem_indexes[descr] = {} @@ -592,7 +590,7 @@ def __init__(self): self.map = {} - + def link_ops(self, preambleop, loopop): pargs = preambleop.getarglist() largs = loopop.getarglist() @@ -606,7 +604,7 @@ if not loopop.result: raise ImpossibleLink self.link_boxes(preambleop.result, loopop.result) - + def link_boxes(self, pbox, lbox): if lbox in self.map: @@ -627,11 +625,11 @@ def __init__(self, retraced): self.retraced = retraced self.inliner = None - - + + def reconstruct_for_next_iteration(self, optimizer, valuemap): return self - + def propagate_forward(self, op): if op.getopnum() == rop.JUMP: descr = op.getdescr() @@ -657,7 +655,7 @@ sh.virtual_state.generate_guards(virtual_state, args, cpu, extra_guards) - + ok = True except InvalidLoop: pass @@ -697,7 +695,7 @@ else: debug_print("Retracing (%d of %d)" % (retraced_count, limit)) - + raise RetraceLoop else: if not descr.failed_states: @@ -705,21 +703,21 @@ else: descr.failed_states.append(virtual_state) self.emit_operation(op) - - - + + + def inline(self, loop_operations, loop_args, jump_args, dryrun=False): self.inliner = inliner = Inliner(loop_args, jump_args) for op in loop_operations: newop = inliner.inline_op(op) - + if not dryrun: self.emit_operation(newop) else: if not self.is_emittable(newop): return False - + return True #def inline_arg(self, arg): diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -1,7 +1,6 @@ -from pypy.jit.codewriter import heaptracker from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.metainterp.history import (Box, BoxInt, BoxPtr, Const, ConstInt, - ConstPtr, get_const_ptr_for_string, get_const_ptr_for_unicode) +from pypy.jit.metainterp.history import (BoxInt, Const, ConstInt, ConstPtr, + get_const_ptr_for_string, get_const_ptr_for_unicode) from pypy.jit.metainterp.optimizeopt import optimizer, virtualize from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1, llhelper from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method @@ -9,7 +8,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rpython import annlowlevel -from pypy.rpython.lltypesystem import lltype, rstr, llmemory +from pypy.rpython.lltypesystem import lltype, rstr class StrOrUnicode(object): From noreply at buildbot.pypy.org Tue Jul 26 04:25:05 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 26 Jul 2011 04:25:05 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove some more importants, and reorganize some others. Message-ID: <20110726022505.DFD10829C2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45994:95649f1056c0 Date: 2011-07-25 18:41 -0700 http://bitbucket.org/pypy/pypy/changeset/95649f1056c0/ Log: Remove some more importants, and reorganize some others. diff --git a/pypy/jit/codewriter/jitcode.py b/pypy/jit/codewriter/jitcode.py --- a/pypy/jit/codewriter/jitcode.py +++ b/pypy/jit/codewriter/jitcode.py @@ -1,7 +1,6 @@ from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.codewriter import heaptracker from pypy.rlib.objectmodel import we_are_translated -from pypy.rpython.lltypesystem import llmemory class JitCode(AbstractDescr): @@ -102,7 +101,7 @@ def _clone_if_mutable(self): raise NotImplementedError - + class MissingLiveness(Exception): pass diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -1,18 +1,16 @@ -import py, sys -from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass -from pypy.rpython import rlist -from pypy.jit.metainterp.history import getkind -from pypy.objspace.flow.model import SpaceOperation, Variable, Constant -from pypy.objspace.flow.model import Block, Link, c_last_exception -from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets +import py from pypy.jit.codewriter import support, heaptracker, longlong from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets from pypy.jit.codewriter.policy import log +from pypy.jit.metainterp import quasiimmut +from pypy.jit.metainterp.history import getkind from pypy.jit.metainterp.typesystem import deref, arrayItem -from pypy.jit.metainterp import quasiimmut -from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, c_last_exception from pypy.rlib import objectmodel from pypy.rlib.jit import _we_are_jitted +from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass +from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY from pypy.translator.simplify import get_funcobj from pypy.translator.unsimplify import varoftype @@ -810,7 +808,6 @@ def force_cast_without_longlong(self, v_arg, v_result): from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT - from pypy.rlib.rarithmetic import intmask # if (v_result.concretetype in (FLOAT, lltype.Float) or v_arg.concretetype in (FLOAT, lltype.Float)): @@ -1412,10 +1409,10 @@ assert vinfo is not None self.vable_flags[op.args[0]] = op.args[2].value return [] - + # --------- # ll_math.sqrt_nonneg() - + def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, EffectInfo.EF_ELIDABLE) diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -1,9 +1,7 @@ -from pypy.translator.simplify import get_funcobj from pypy.jit.metainterp import history -from pypy.rpython.lltypesystem import lltype, rclass from pypy.tool.udir import udir -import py, sys +import py from pypy.tool.ansi_print import ansi_log log = py.log.Producer('jitcodewriter') py.log.setconsumer('jitcodewriter', ansi_log) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,9 +1,10 @@ import os + +from pypy.jit.metainterp.jitexc import JitException +from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.resoperation import rop from pypy.rlib.objectmodel import we_are_translated -from pypy.jit.metainterp.jitexc import JitException -from pypy.jit.metainterp.optimizeopt.optimizer import Optimization class CachedField(object): diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,10 +1,11 @@ +from pypy.jit.metainterp.history import ConstInt +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntLowerBound, + IntUpperBound) from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntLowerBound, - IntUpperBound) -from pypy.jit.metainterp.history import ConstInt from pypy.jit.metainterp.resoperation import rop + class OptIntBounds(Optimization): """Keeps track of the bounds placed on integers by guards and remove redundant guards""" diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ - -from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.resoperation import ResOperation, rop + class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -1,12 +1,12 @@ +from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.metainterp.compile import ResumeGuardDescr +from pypy.jit.metainterp.history import TreeLoop, LoopToken +from pypy.jit.metainterp.jitexc import JitException +from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.compile import ResumeGuardDescr from pypy.jit.metainterp.resume import Snapshot -from pypy.jit.metainterp.history import TreeLoop, LoopToken from pypy.rlib.debug import debug_print -from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop -from pypy.jit.metainterp.jitexc import JitException -from pypy.jit.codewriter.effectinfo import EffectInfo # Assumptions # =========== diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -1,11 +1,11 @@ +from pypy.jit.codewriter.heaptracker import vtable2descr +from pypy.jit.metainterp.executor import execute from pypy.jit.metainterp.history import Const, ConstInt, BoxInt +from pypy.jit.metainterp.optimizeopt import optimizer +from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method, + descrlist_dict, sort_descrs) from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, sort_descrs from pypy.rlib.objectmodel import we_are_translated -from pypy.jit.metainterp.optimizeopt import optimizer -from pypy.jit.metainterp.executor import execute -from pypy.jit.codewriter.heaptracker import vtable2descr class AbstractVirtualValue(optimizer.OptValue): From noreply at buildbot.pypy.org Tue Jul 26 04:25:07 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 26 Jul 2011 04:25:07 +0200 (CEST) Subject: [pypy-commit] pypy default: When a newstr is allocated in the JIT, we can propogate the strlen, even if it isn't a constant. Message-ID: <20110726022507.19332829C3@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45995:27cc4adf52fe Date: 2011-07-25 19:25 -0700 http://bitbucket.org/pypy/pypy/changeset/27cc4adf52fe/ Log: When a newstr is allocated in the JIT, we can propogate the strlen, even if it isn't a constant. diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4593,6 +4593,9 @@ setfield_gc(p0, p1, descr=valuedescr) jump(p0) """ + # It used to be the case that this would have a series of + # strsetitem(p1, idx, 0), which was silly because memory is 0 filled + # when allocated. expected = """ [p0] p1 = newstr(4) @@ -4601,6 +4604,24 @@ """ self.optimize_loop(ops, expected) + def test_newstr_strlen(self): + ops = """ + [i0] + p0 = newstr(i0) + escape(p0) + i1 = strlen(p0) + i2 = int_add(i1, 1) + jump(i2) + """ + expected = """ + [i0] + p0 = newstr(i0) + escape(p0) + i1 = int_add(i0, 1) + jump(i1) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -399,6 +399,7 @@ else: self.getvalue(op.result).ensure_nonnull() self.emit_operation(op) + self.pure(mode.STRLEN, [op.result], op.getarg(0)) def optimize_STRSETITEM(self, op): value = self.getvalue(op.getarg(0)) From noreply at buildbot.pypy.org Tue Jul 26 04:28:49 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 26 Jul 2011 04:28:49 +0200 (CEST) Subject: [pypy-commit] pypy default: Run these tests on unicode as well as str. Message-ID: <20110726022849.4F1F3829C2@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r45996:896b632136ad Date: 2011-07-25 19:29 -0700 http://bitbucket.org/pypy/pypy/changeset/896b632136ad/ Log: Run these tests on unicode as well as str. diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4532,7 +4532,7 @@ escape(i1) jump(p0, i0) """ - self.optimize_loop(ops, expected) + self.optimize_strunicode_loop(ops, expected) def test_int_is_true_bounds(self): ops = """ @@ -4551,7 +4551,7 @@ guard_true(i1) [] jump(p0) """ - self.optimize_loop(ops, expected) + self.optimize_strunicode_loop(ops, expected) def test_strslice_subtraction_folds(self): ops = """ @@ -4602,7 +4602,7 @@ setfield_gc(p0, p1, descr=valuedescr) jump(p0) """ - self.optimize_loop(ops, expected) + self.optimize_strunicode_loop(ops, expected) def test_newstr_strlen(self): ops = """ @@ -4620,7 +4620,7 @@ i1 = int_add(i0, 1) jump(i1) """ - self.optimize_loop(ops, expected) + self.optimize_strunicode_loop(ops, expected) class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): From noreply at buildbot.pypy.org Tue Jul 26 10:01:10 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 26 Jul 2011 10:01:10 +0200 (CEST) Subject: [pypy-commit] pypy default: temporarily backout 39a9093e603d: it seems to trigger an asmgcc bug Message-ID: <20110726080110.4E934823B2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r45997:9d796d6049d6 Date: 2011-07-26 09:59 +0200 http://bitbucket.org/pypy/pypy/changeset/9d796d6049d6/ Log: temporarily backout 39a9093e603d: it seems to trigger an asmgcc bug diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -49,7 +49,6 @@ from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage from pypy.rpython.memory.gc.base import GCBase, MovingGCBase from pypy.rpython.memory.gc import minimarkpage, env -from pypy.rpython.memory.support import mangle_hash from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask, r_uint from pypy.rlib.rarithmetic import LONG_BIT_SHIFT from pypy.rlib.debug import ll_assert, debug_print, debug_start, debug_stop @@ -1794,7 +1793,7 @@ return self.id_or_identityhash(gcobj, False) def identityhash(self, gcobj): - return mangle_hash(self.id_or_identityhash(gcobj, True)) + return self.id_or_identityhash(gcobj, True) # ---------- diff --git a/pypy/rpython/memory/lldict.py b/pypy/rpython/memory/lldict.py --- a/pypy/rpython/memory/lldict.py +++ b/pypy/rpython/memory/lldict.py @@ -1,7 +1,6 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem import rdict from pypy.rlib.objectmodel import we_are_translated -from pypy.rpython.memory.support import mangle_hash # This is a low-level AddressDict, reusing a lot of the logic from rdict.py. # xxx this is very dependent on the details of rdict.py @@ -41,8 +40,7 @@ lltype.free(entries, flavor="raw") if not we_are_translated(): count_alloc(-1) -def _hash(adr): - return mangle_hash(llmemory.cast_adr_to_int(adr)) +_hash = llmemory.cast_adr_to_int def dict_keyhash(d, key): return _hash(key) diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -4,15 +4,6 @@ from pypy.rlib.debug import ll_assert from pypy.tool.identity_dict import identity_dict - -def mangle_hash(i): - # To hash pointers in dictionaries. Assumes that i shows some - # alignment (to 4, 8, maybe 16 bytes), so we use the following - # formula to avoid the trailing bits being always 0. - return i ^ (i >> 4) - -# ____________________________________________________________ - DEFAULT_CHUNK_SIZE = 1019 From noreply at buildbot.pypy.org Tue Jul 26 10:19:18 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Tue, 26 Jul 2011 10:19:18 +0200 (CEST) Subject: [pypy-commit] benchmarks default: put the postfix on the host instead of the executable name; this should put bench results in two separate environments on codespeed, tannit and tannit-64 Message-ID: <20110726081918.3BA1A823B2@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r137:9573b1c9a942 Date: 2011-07-26 10:19 +0200 http://bitbucket.org/pypy/benchmarks/changeset/9573b1c9a942/ Log: put the postfix on the host instead of the executable name; this should put bench results in two separate environments on codespeed, tannit and tannit-64 diff --git a/runner.py b/runner.py --- a/runner.py +++ b/runner.py @@ -13,9 +13,9 @@ from saveresults import save project = 'PyPy' if "--jit" in args: - name = "pypy-c" + postfix + name = "pypy-c" else: - name = "pypy-c-jit" + postfix + name = "pypy-c-jit" if "psyco.sh" in pypy_c_path: name = "cpython psyco-profile" revision = 100 @@ -24,6 +24,7 @@ host = force_host else: host = socket.gethostname() + host += postfix print save(project, revision, res, options, name, host, changed=changed) From noreply at buildbot.pypy.org Tue Jul 26 13:07:18 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 26 Jul 2011 13:07:18 +0200 (CEST) Subject: [pypy-commit] pypy custom-trace: hg merge default Message-ID: <20110726110718.6D20E823B2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: custom-trace Changeset: r45998:d193a25ed5eb Date: 2011-07-26 08:19 +0200 http://bitbucket.org/pypy/pypy/changeset/d193a25ed5eb/ Log: hg merge default diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -1,1 +1,2 @@ b590cf6de4190623aad9aa698694c22e614d67b9 release-1.5 +b48df0bf4e75b81d98f19ce89d4a7dc3e1dab5e5 benchmarked diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,6 +116,12 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + if "CFLAGS" in os.environ: + cflags = os.environ["CFLAGS"] + compiler.compiler.append(cflags) + compiler.compiler_so.append(cflags) + compiler.linker_so.append(cflags) + from sysconfig_cpython import ( parse_makefile, _variable_rx, expand_makefile_vars) diff --git a/lib-python/2.7/test/test_tarfile.py b/lib-python/modified-2.7/test/test_tarfile.py copy from lib-python/2.7/test/test_tarfile.py copy to lib-python/modified-2.7/test/test_tarfile.py --- a/lib-python/2.7/test/test_tarfile.py +++ b/lib-python/modified-2.7/test/test_tarfile.py @@ -169,6 +169,7 @@ except tarfile.ReadError: self.fail("tarfile.open() failed on empty archive") self.assertListEqual(tar.getmembers(), []) + tar.close() def test_null_tarfile(self): # Test for issue6123: Allow opening empty archives. @@ -207,16 +208,21 @@ fobj = open(self.tarname, "rb") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, os.path.abspath(fobj.name)) + tar.close() def test_no_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) self.assertRaises(AttributeError, getattr, fobj, "name") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, None) def test_empty_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) fobj.name = "" tar = tarfile.open(fileobj=fobj, mode=self.mode) @@ -515,6 +521,7 @@ self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1") tarinfo = self.tar.getmember("pax/umlauts-�������") self._test_member(tarinfo, size=7011, chksum=md5_regtype) + self.tar.close() class LongnameTest(ReadTest): @@ -675,6 +682,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.rmdir(path) @@ -692,6 +700,7 @@ tar.gettarinfo(target) tarinfo = tar.gettarinfo(link) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(target) os.remove(link) @@ -704,6 +713,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(path) @@ -722,6 +732,7 @@ tar.add(dstname) os.chdir(cwd) self.assertTrue(tar.getnames() == [], "added the archive to itself") + tar.close() def test_exclude(self): tempdir = os.path.join(TEMPDIR, "exclude") @@ -742,6 +753,7 @@ tar = tarfile.open(tmpname, "r") self.assertEqual(len(tar.getmembers()), 1) self.assertEqual(tar.getnames()[0], "empty_dir") + tar.close() finally: shutil.rmtree(tempdir) @@ -859,7 +871,9 @@ fobj.close() elif self.mode.endswith("bz2"): dec = bz2.BZ2Decompressor() - data = open(tmpname, "rb").read() + f = open(tmpname, "rb") + data = f.read() + f.close() data = dec.decompress(data) self.assertTrue(len(dec.unused_data) == 0, "found trailing data") @@ -938,6 +952,7 @@ "unable to read longname member") self.assertEqual(tarinfo.linkname, member.linkname, "unable to read longname member") + tar.close() def test_longname_1023(self): self._test(("longnam/" * 127) + "longnam") @@ -1030,6 +1045,7 @@ else: n = tar.getmembers()[0].name self.assertTrue(name == n, "PAX longname creation failed") + tar.close() def test_pax_global_header(self): pax_headers = { @@ -1058,6 +1074,7 @@ tarfile.PAX_NUMBER_FIELDS[key](val) except (TypeError, ValueError): self.fail("unable to convert pax header field") + tar.close() def test_pax_extended_header(self): # The fields from the pax header have priority over the @@ -1077,6 +1094,7 @@ self.assertEqual(t.pax_headers, pax_headers) self.assertEqual(t.name, "foo") self.assertEqual(t.uid, 123) + tar.close() class UstarUnicodeTest(unittest.TestCase): @@ -1120,6 +1138,7 @@ tarinfo.name = "foo" tarinfo.uname = u"���" self.assertRaises(UnicodeError, tar.addfile, tarinfo) + tar.close() def test_unicode_argument(self): tar = tarfile.open(tarname, "r", encoding="iso8859-1", errors="strict") @@ -1174,6 +1193,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="ascii", errors=handler) self.assertEqual(tar.getnames()[0], name) + tar.close() self.assertRaises(UnicodeError, tarfile.open, tmpname, encoding="ascii", errors="strict") @@ -1186,6 +1206,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="iso8859-1", errors="utf-8") self.assertEqual(tar.getnames()[0], "���/" + u"�".encode("utf8")) + tar.close() class AppendTest(unittest.TestCase): @@ -1213,6 +1234,7 @@ def _test(self, names=["bar"], fileobj=None): tar = tarfile.open(self.tarname, fileobj=fileobj) self.assertEqual(tar.getnames(), names) + tar.close() def test_non_existing(self): self._add_testfile() @@ -1231,7 +1253,9 @@ def test_fileobj(self): self._create_testtar() - data = open(self.tarname).read() + f = open(self.tarname) + data = f.read() + f.close() fobj = StringIO.StringIO(data) self._add_testfile(fobj) fobj.seek(0) @@ -1257,7 +1281,9 @@ # Append mode is supposed to fail if the tarfile to append to # does not end with a zero block. def _test_error(self, data): - open(self.tarname, "wb").write(data) + f = open(self.tarname, "wb") + f.write(data) + f.close() self.assertRaises(tarfile.ReadError, self._add_testfile) def test_null(self): diff --git a/lib_pypy/pyrepl/unix_console.py b/lib_pypy/pyrepl/unix_console.py --- a/lib_pypy/pyrepl/unix_console.py +++ b/lib_pypy/pyrepl/unix_console.py @@ -384,15 +384,19 @@ self.__maybe_write_code(self._smkx) - self.old_sigwinch = signal.signal( - signal.SIGWINCH, self.__sigwinch) + try: + self.old_sigwinch = signal.signal( + signal.SIGWINCH, self.__sigwinch) + except ValueError: + pass def restore(self): self.__maybe_write_code(self._rmkx) self.flushoutput() tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate) - signal.signal(signal.SIGWINCH, self.old_sigwinch) + if hasattr(self, 'old_sigwinch'): + signal.signal(signal.SIGWINCH, self.old_sigwinch) def __sigwinch(self, signum, frame): self.height, self.width = self.getheightwidth() diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -327,6 +327,9 @@ BoolOption("mutable_builtintypes", "Allow the changing of builtin types", default=False, requires=[("objspace.std.builtinshortcut", True)]), + BoolOption("withidentitydict", + "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not", + default=True), ]), ]) diff --git a/pypy/config/support.py b/pypy/config/support.py --- a/pypy/config/support.py +++ b/pypy/config/support.py @@ -9,7 +9,7 @@ return 1 # don't override MAKEFLAGS. This will call 'make' without any '-j' option if sys.platform == 'darwin': return darwin_get_cpu_count() - elif sys.platform != 'linux2': + elif not sys.platform.startswith('linux'): return 1 # implement me try: if isinstance(filename_or_file, str): diff --git a/pypy/config/test/test_support.py b/pypy/config/test/test_support.py --- a/pypy/config/test/test_support.py +++ b/pypy/config/test/test_support.py @@ -40,7 +40,7 @@ return self._value def test_cpuinfo_linux(): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("linux only") saved = os.environ try: diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -929,6 +929,19 @@ located in the ``py/bin/`` directory. For switches to modify test execution pass the ``-h`` option. +Coverage reports +---------------- + +In order to get coverage reports the `pytest-cov`_ plugin is included. +it adds some extra requirements ( coverage_ and `cov-core`_ ) +and can once they are installed coverage testing can be invoked via:: + + python test_all.py --cov file_or_direcory_to_cover file_or_directory + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov +.. _`coverage`: http://pypi.python.org/pypi/coverage +.. _`cov-core`: http://pypi.python.org/pypi/cov-core + Test conventions ---------------- diff --git a/pypy/doc/config/objspace.std.withidentitydict.txt b/pypy/doc/config/objspace.std.withidentitydict.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withidentitydict.txt @@ -0,0 +1,21 @@ +============================= +objspace.std.withidentitydict +============================= + +* **name:** withidentitydict + +* **description:** enable a dictionary strategy for "by identity" comparisons + +* **command-line:** --objspace-std-withidentitydict + +* **command-line for negation:** --no-objspace-std-withidentitydict + +* **option type:** boolean option + +* **default:** True + + +Enable a dictionary strategy specialized for instances of classes which +compares "by identity", which is the default unless you override ``__hash__``, +``__eq__`` or ``__cmp__``. This strategy will be used only with new-style +classes. diff --git a/pypy/doc/config/translation.dont_write_c_files.txt b/pypy/doc/config/translation.dont_write_c_files.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/translation.dont_write_c_files.txt @@ -0,0 +1,4 @@ +write the generated C files to ``/dev/null`` instead of to the disk. Useful if +you want to use translate.py as a benchmark and don't want to access the disk. + +.. _`translation documentation`: ../translation.html diff --git a/pypy/doc/config/translation.gc.txt b/pypy/doc/config/translation.gc.txt --- a/pypy/doc/config/translation.gc.txt +++ b/pypy/doc/config/translation.gc.txt @@ -1,4 +1,6 @@ -Choose the Garbage Collector used by the translated program: +Choose the Garbage Collector used by the translated program. +The good performing collectors are "hybrid" and "minimark". +The default is "minimark". - "ref": reference counting. Takes very long to translate and the result is slow. @@ -11,3 +13,12 @@ older generation. - "boehm": use the Boehm conservative GC. + + - "hybrid": a hybrid collector of "generation" together with a + mark-n-sweep old space + + - "markcompact": a slow, but memory-efficient collector, + influenced e.g. by Smalltalk systems. + + - "minimark": a generational mark-n-sweep collector with good + performance. Includes page marking for large arrays. diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -211,6 +211,38 @@ >>>> print d1['a'] 42 +Mutating classes of objects which are already used as dictionary keys +--------------------------------------------------------------------- + +Consider the following snippet of code:: + + class X(object): + pass + + def __evil_eq__(self, other): + print 'hello world' + return False + + def evil(y): + d = {x(): 1} + X.__eq__ = __evil_eq__ + d[y] # might trigger a call to __eq__? + +In CPython, __evil_eq__ **might** be called, although there is no way to write +a test which reliably calls it. It happens if ``y is not x`` and ``hash(y) == +hash(x)``, where ``hash(x)`` is computed when ``x`` is inserted into the +dictionary. If **by chance** the condition is satisfied, then ``__evil_eq__`` +is called. + +PyPy uses a special strategy to optimize dictionaries whose keys are instances +of user-defined classes which do not override the default ``__hash__``, +``__eq__`` and ``__cmp__``: when using this strategy, ``__eq__`` and +``__cmp__`` are never called, but instead the lookup is done by identity, so +in the case above it is guaranteed that ``__eq__`` won't be called. + +Note that in all other cases (e.g., if you have a custom ``__hash__`` and +``__eq__`` in ``y``) the behavior is exactly the same as CPython. + Ignored exceptions ----------------------- diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -32,6 +32,24 @@ modules that relies on third-party libraries. See below how to get and build them. +Preping Windows for the Large Build +----------------------------------- + +Normally 32bit programs are limited to 2GB of memory on Windows. It is +possible to raise this limit, to 3GB on Windows 32bit, and almost 4GB +on Windows 64bit. + +On Windows 32bit, it is necessary to modify the system: follow +http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 +to enable the "3GB" feature, and reboot. This step is not necessary on +Windows 64bit. + +Then you need to execute:: + + editbin /largeaddressaware pypy.exe + +on the pypy.exe file you compiled. + Installing external packages ---------------------------- diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -2541,8 +2541,9 @@ class ASTVisitor(object): def visit_sequence(self, seq): - for node in seq: - node.walkabout(self) + if seq is not None: + for node in seq: + node.walkabout(self) def default_visitor(self, node): raise NodeVisitorNotImplemented @@ -2673,46 +2674,36 @@ class GenericASTVisitor(ASTVisitor): def visit_Module(self, node): - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_Interactive(self, node): - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_Expression(self, node): node.body.walkabout(self) def visit_Suite(self, node): - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_FunctionDef(self, node): node.args.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.decorator_list: - self.visit_sequence(node.decorator_list) + self.visit_sequence(node.body) + self.visit_sequence(node.decorator_list) def visit_ClassDef(self, node): - if node.bases: - self.visit_sequence(node.bases) - if node.body: - self.visit_sequence(node.body) - if node.decorator_list: - self.visit_sequence(node.decorator_list) + self.visit_sequence(node.bases) + self.visit_sequence(node.body) + self.visit_sequence(node.decorator_list) def visit_Return(self, node): if node.value: node.value.walkabout(self) def visit_Delete(self, node): - if node.targets: - self.visit_sequence(node.targets) + self.visit_sequence(node.targets) def visit_Assign(self, node): - if node.targets: - self.visit_sequence(node.targets) + self.visit_sequence(node.targets) node.value.walkabout(self) def visit_AugAssign(self, node): @@ -2722,37 +2713,29 @@ def visit_Print(self, node): if node.dest: node.dest.walkabout(self) - if node.values: - self.visit_sequence(node.values) + self.visit_sequence(node.values) def visit_For(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.orelse) def visit_While(self, node): node.test.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.orelse) def visit_If(self, node): node.test.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.orelse) def visit_With(self, node): node.context_expr.walkabout(self) if node.optional_vars: node.optional_vars.walkabout(self) - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_Raise(self, node): if node.type: @@ -2763,18 +2746,13 @@ node.tback.walkabout(self) def visit_TryExcept(self, node): - if node.body: - self.visit_sequence(node.body) - if node.handlers: - self.visit_sequence(node.handlers) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.handlers) + self.visit_sequence(node.orelse) def visit_TryFinally(self, node): - if node.body: - self.visit_sequence(node.body) - if node.finalbody: - self.visit_sequence(node.finalbody) + self.visit_sequence(node.body) + self.visit_sequence(node.finalbody) def visit_Assert(self, node): node.test.walkabout(self) @@ -2782,12 +2760,10 @@ node.msg.walkabout(self) def visit_Import(self, node): - if node.names: - self.visit_sequence(node.names) + self.visit_sequence(node.names) def visit_ImportFrom(self, node): - if node.names: - self.visit_sequence(node.names) + self.visit_sequence(node.names) def visit_Exec(self, node): node.body.walkabout(self) @@ -2812,8 +2788,7 @@ pass def visit_BoolOp(self, node): - if node.values: - self.visit_sequence(node.values) + self.visit_sequence(node.values) def visit_BinOp(self, node): node.left.walkabout(self) @@ -2832,35 +2807,28 @@ node.orelse.walkabout(self) def visit_Dict(self, node): - if node.keys: - self.visit_sequence(node.keys) - if node.values: - self.visit_sequence(node.values) + self.visit_sequence(node.keys) + self.visit_sequence(node.values) def visit_Set(self, node): - if node.elts: - self.visit_sequence(node.elts) + self.visit_sequence(node.elts) def visit_ListComp(self, node): node.elt.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_SetComp(self, node): node.elt.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_DictComp(self, node): node.key.walkabout(self) node.value.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_GeneratorExp(self, node): node.elt.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_Yield(self, node): if node.value: @@ -2868,15 +2836,12 @@ def visit_Compare(self, node): node.left.walkabout(self) - if node.comparators: - self.visit_sequence(node.comparators) + self.visit_sequence(node.comparators) def visit_Call(self, node): node.func.walkabout(self) - if node.args: - self.visit_sequence(node.args) - if node.keywords: - self.visit_sequence(node.keywords) + self.visit_sequence(node.args) + self.visit_sequence(node.keywords) if node.starargs: node.starargs.walkabout(self) if node.kwargs: @@ -2902,12 +2867,10 @@ pass def visit_List(self, node): - if node.elts: - self.visit_sequence(node.elts) + self.visit_sequence(node.elts) def visit_Tuple(self, node): - if node.elts: - self.visit_sequence(node.elts) + self.visit_sequence(node.elts) def visit_Const(self, node): pass @@ -2924,8 +2887,7 @@ node.step.walkabout(self) def visit_ExtSlice(self, node): - if node.dims: - self.visit_sequence(node.dims) + self.visit_sequence(node.dims) def visit_Index(self, node): node.value.walkabout(self) @@ -2933,22 +2895,18 @@ def visit_comprehension(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.ifs: - self.visit_sequence(node.ifs) + self.visit_sequence(node.ifs) def visit_ExceptHandler(self, node): if node.type: node.type.walkabout(self) if node.name: node.name.walkabout(self) - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_arguments(self, node): - if node.args: - self.visit_sequence(node.args) - if node.defaults: - self.visit_sequence(node.defaults) + self.visit_sequence(node.args) + self.visit_sequence(node.defaults) def visit_keyword(self, node): node.value.walkabout(self) @@ -3069,6 +3027,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 _Expression_field_unroller = unrolling_iterable(['body']) @@ -3157,6 +3116,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def stmt_get_col_offset(space, w_self): @@ -3178,6 +3138,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask stmt.typedef = typedef.TypeDef("stmt", @@ -3208,6 +3169,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def FunctionDef_get_args(space, w_self): @@ -3229,6 +3191,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 2 def FunctionDef_get_body(space, w_self): @@ -3315,6 +3278,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def ClassDef_get_bases(space, w_self): @@ -3420,6 +3384,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Return_field_unroller = unrolling_iterable(['value']) @@ -3526,6 +3491,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _Assign_field_unroller = unrolling_iterable(['targets', 'value']) @@ -3573,6 +3539,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def AugAssign_get_op(space, w_self): @@ -3590,13 +3557,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def AugAssign_get_value(space, w_self): @@ -3618,6 +3585,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 4 _AugAssign_field_unroller = unrolling_iterable(['target', 'op', 'value']) @@ -3665,6 +3633,7 @@ raise w_self.setdictvalue(space, 'dest', w_new_value) return + w_self.deldictvalue(space, 'dest') w_self.initialization_state |= 1 def Print_get_values(space, w_self): @@ -3704,6 +3673,7 @@ raise w_self.setdictvalue(space, 'nl', w_new_value) return + w_self.deldictvalue(space, 'nl') w_self.initialization_state |= 4 _Print_field_unroller = unrolling_iterable(['dest', 'values', 'nl']) @@ -3752,6 +3722,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def For_get_iter(space, w_self): @@ -3773,6 +3744,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def For_get_body(space, w_self): @@ -3859,6 +3831,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def While_get_body(space, w_self): @@ -3944,6 +3917,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def If_get_body(space, w_self): @@ -4029,6 +4003,7 @@ raise w_self.setdictvalue(space, 'context_expr', w_new_value) return + w_self.deldictvalue(space, 'context_expr') w_self.initialization_state |= 1 def With_get_optional_vars(space, w_self): @@ -4050,6 +4025,7 @@ raise w_self.setdictvalue(space, 'optional_vars', w_new_value) return + w_self.deldictvalue(space, 'optional_vars') w_self.initialization_state |= 2 def With_get_body(space, w_self): @@ -4116,6 +4092,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def Raise_get_inst(space, w_self): @@ -4137,6 +4114,7 @@ raise w_self.setdictvalue(space, 'inst', w_new_value) return + w_self.deldictvalue(space, 'inst') w_self.initialization_state |= 2 def Raise_get_tback(space, w_self): @@ -4158,6 +4136,7 @@ raise w_self.setdictvalue(space, 'tback', w_new_value) return + w_self.deldictvalue(space, 'tback') w_self.initialization_state |= 4 _Raise_field_unroller = unrolling_iterable(['type', 'inst', 'tback']) @@ -4351,6 +4330,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def Assert_get_msg(space, w_self): @@ -4372,6 +4352,7 @@ raise w_self.setdictvalue(space, 'msg', w_new_value) return + w_self.deldictvalue(space, 'msg') w_self.initialization_state |= 2 _Assert_field_unroller = unrolling_iterable(['test', 'msg']) @@ -4464,6 +4445,7 @@ raise w_self.setdictvalue(space, 'module', w_new_value) return + w_self.deldictvalue(space, 'module') w_self.initialization_state |= 1 def ImportFrom_get_names(space, w_self): @@ -4503,6 +4485,7 @@ raise w_self.setdictvalue(space, 'level', w_new_value) return + w_self.deldictvalue(space, 'level') w_self.initialization_state |= 4 _ImportFrom_field_unroller = unrolling_iterable(['module', 'names', 'level']) @@ -4551,6 +4534,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 def Exec_get_globals(space, w_self): @@ -4572,6 +4556,7 @@ raise w_self.setdictvalue(space, 'globals', w_new_value) return + w_self.deldictvalue(space, 'globals') w_self.initialization_state |= 2 def Exec_get_locals(space, w_self): @@ -4593,6 +4578,7 @@ raise w_self.setdictvalue(space, 'locals', w_new_value) return + w_self.deldictvalue(space, 'locals') w_self.initialization_state |= 4 _Exec_field_unroller = unrolling_iterable(['body', 'globals', 'locals']) @@ -4683,6 +4669,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Expr_field_unroller = unrolling_iterable(['value']) @@ -4779,6 +4766,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def expr_get_col_offset(space, w_self): @@ -4800,6 +4788,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask expr.typedef = typedef.TypeDef("expr", @@ -4826,13 +4815,13 @@ try: obj = space.interp_w(boolop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def BoolOp_get_values(space, w_self): @@ -4898,6 +4887,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def BinOp_get_op(space, w_self): @@ -4915,13 +4905,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def BinOp_get_right(space, w_self): @@ -4943,6 +4933,7 @@ raise w_self.setdictvalue(space, 'right', w_new_value) return + w_self.deldictvalue(space, 'right') w_self.initialization_state |= 4 _BinOp_field_unroller = unrolling_iterable(['left', 'op', 'right']) @@ -4986,13 +4977,13 @@ try: obj = space.interp_w(unaryop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def UnaryOp_get_operand(space, w_self): @@ -5014,6 +5005,7 @@ raise w_self.setdictvalue(space, 'operand', w_new_value) return + w_self.deldictvalue(space, 'operand') w_self.initialization_state |= 2 _UnaryOp_field_unroller = unrolling_iterable(['op', 'operand']) @@ -5060,6 +5052,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 1 def Lambda_get_body(space, w_self): @@ -5081,6 +5074,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 _Lambda_field_unroller = unrolling_iterable(['args', 'body']) @@ -5127,6 +5121,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def IfExp_get_body(space, w_self): @@ -5148,6 +5143,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 def IfExp_get_orelse(space, w_self): @@ -5169,6 +5165,7 @@ raise w_self.setdictvalue(space, 'orelse', w_new_value) return + w_self.deldictvalue(space, 'orelse') w_self.initialization_state |= 4 _IfExp_field_unroller = unrolling_iterable(['test', 'body', 'orelse']) @@ -5322,6 +5319,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def ListComp_get_generators(space, w_self): @@ -5387,6 +5385,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def SetComp_get_generators(space, w_self): @@ -5452,6 +5451,7 @@ raise w_self.setdictvalue(space, 'key', w_new_value) return + w_self.deldictvalue(space, 'key') w_self.initialization_state |= 1 def DictComp_get_value(space, w_self): @@ -5473,6 +5473,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 def DictComp_get_generators(space, w_self): @@ -5539,6 +5540,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def GeneratorExp_get_generators(space, w_self): @@ -5604,6 +5606,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Yield_field_unroller = unrolling_iterable(['value']) @@ -5649,6 +5652,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def Compare_get_ops(space, w_self): @@ -5734,6 +5738,7 @@ raise w_self.setdictvalue(space, 'func', w_new_value) return + w_self.deldictvalue(space, 'func') w_self.initialization_state |= 1 def Call_get_args(space, w_self): @@ -5791,6 +5796,7 @@ raise w_self.setdictvalue(space, 'starargs', w_new_value) return + w_self.deldictvalue(space, 'starargs') w_self.initialization_state |= 8 def Call_get_kwargs(space, w_self): @@ -5812,6 +5818,7 @@ raise w_self.setdictvalue(space, 'kwargs', w_new_value) return + w_self.deldictvalue(space, 'kwargs') w_self.initialization_state |= 16 _Call_field_unroller = unrolling_iterable(['func', 'args', 'keywords', 'starargs', 'kwargs']) @@ -5863,6 +5870,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Repr_field_unroller = unrolling_iterable(['value']) @@ -5908,6 +5916,7 @@ raise w_self.setdictvalue(space, 'n', w_new_value) return + w_self.deldictvalue(space, 'n') w_self.initialization_state |= 1 _Num_field_unroller = unrolling_iterable(['n']) @@ -5953,6 +5962,7 @@ raise w_self.setdictvalue(space, 's', w_new_value) return + w_self.deldictvalue(space, 's') w_self.initialization_state |= 1 _Str_field_unroller = unrolling_iterable(['s']) @@ -5998,6 +6008,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Attribute_get_attr(space, w_self): @@ -6019,6 +6030,7 @@ raise w_self.setdictvalue(space, 'attr', w_new_value) return + w_self.deldictvalue(space, 'attr') w_self.initialization_state |= 2 def Attribute_get_ctx(space, w_self): @@ -6036,13 +6048,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Attribute_field_unroller = unrolling_iterable(['value', 'attr', 'ctx']) @@ -6090,6 +6102,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Subscript_get_slice(space, w_self): @@ -6111,6 +6124,7 @@ raise w_self.setdictvalue(space, 'slice', w_new_value) return + w_self.deldictvalue(space, 'slice') w_self.initialization_state |= 2 def Subscript_get_ctx(space, w_self): @@ -6128,13 +6142,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Subscript_field_unroller = unrolling_iterable(['value', 'slice', 'ctx']) @@ -6182,6 +6196,7 @@ raise w_self.setdictvalue(space, 'id', w_new_value) return + w_self.deldictvalue(space, 'id') w_self.initialization_state |= 1 def Name_get_ctx(space, w_self): @@ -6199,13 +6214,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Name_field_unroller = unrolling_iterable(['id', 'ctx']) @@ -6266,13 +6281,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _List_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6334,13 +6349,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Tuple_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6388,6 +6403,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Const_field_unroller = unrolling_iterable(['value']) @@ -6506,6 +6522,7 @@ raise w_self.setdictvalue(space, 'lower', w_new_value) return + w_self.deldictvalue(space, 'lower') w_self.initialization_state |= 1 def Slice_get_upper(space, w_self): @@ -6527,6 +6544,7 @@ raise w_self.setdictvalue(space, 'upper', w_new_value) return + w_self.deldictvalue(space, 'upper') w_self.initialization_state |= 2 def Slice_get_step(space, w_self): @@ -6548,6 +6566,7 @@ raise w_self.setdictvalue(space, 'step', w_new_value) return + w_self.deldictvalue(space, 'step') w_self.initialization_state |= 4 _Slice_field_unroller = unrolling_iterable(['lower', 'upper', 'step']) @@ -6638,6 +6657,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Index_field_unroller = unrolling_iterable(['value']) @@ -6907,6 +6927,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def comprehension_get_iter(space, w_self): @@ -6928,6 +6949,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def comprehension_get_ifs(space, w_self): @@ -6994,6 +7016,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def excepthandler_get_col_offset(space, w_self): @@ -7015,6 +7038,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask excepthandler.typedef = typedef.TypeDef("excepthandler", @@ -7045,6 +7069,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def ExceptHandler_get_name(space, w_self): @@ -7066,6 +7091,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 2 def ExceptHandler_get_body(space, w_self): @@ -7153,6 +7179,7 @@ raise w_self.setdictvalue(space, 'vararg', w_new_value) return + w_self.deldictvalue(space, 'vararg') w_self.initialization_state |= 2 def arguments_get_kwarg(space, w_self): @@ -7177,6 +7204,7 @@ raise w_self.setdictvalue(space, 'kwarg', w_new_value) return + w_self.deldictvalue(space, 'kwarg') w_self.initialization_state |= 4 def arguments_get_defaults(space, w_self): @@ -7245,6 +7273,7 @@ raise w_self.setdictvalue(space, 'arg', w_new_value) return + w_self.deldictvalue(space, 'arg') w_self.initialization_state |= 1 def keyword_get_value(space, w_self): @@ -7266,6 +7295,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _keyword_field_unroller = unrolling_iterable(['arg', 'value']) @@ -7312,6 +7342,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def alias_get_asname(space, w_self): @@ -7336,6 +7367,7 @@ raise w_self.setdictvalue(space, 'asname', w_new_value) return + w_self.deldictvalue(space, 'asname') w_self.initialization_state |= 2 _alias_field_unroller = unrolling_iterable(['name', 'asname']) diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -295,15 +295,11 @@ def visit_FunctionDef(self, func): self.update_position(func.lineno, True) # Load decorators first, but apply them after the function is created. - if func.decorator_list: - self.visit_sequence(func.decorator_list) + self.visit_sequence(func.decorator_list) args = func.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) - num_defaults = len(args.defaults) - else: - num_defaults = 0 + self.visit_sequence(args.defaults) + num_defaults = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(FunctionCodeGenerator, func.name, func, func.lineno) self._make_function(code, num_defaults) @@ -317,24 +313,17 @@ self.update_position(lam.lineno) args = lam.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) - default_count = len(args.defaults) - else: - default_count = 0 + self.visit_sequence(args.defaults) + default_count = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(LambdaCodeGenerator, "", lam, lam.lineno) self._make_function(code, default_count) def visit_ClassDef(self, cls): self.update_position(cls.lineno, True) - if cls.decorator_list: - self.visit_sequence(cls.decorator_list) + self.visit_sequence(cls.decorator_list) self.load_const(self.space.wrap(cls.name)) - if cls.bases: - bases_count = len(cls.bases) - self.visit_sequence(cls.bases) - else: - bases_count = 0 + self.visit_sequence(cls.bases) + bases_count = len(cls.bases) if cls.bases is not None else 0 self.emit_op_arg(ops.BUILD_TUPLE, bases_count) code = self.sub_scope(ClassCodeGenerator, cls.name, cls, cls.lineno) self._make_function(code, 0) @@ -446,8 +435,7 @@ end = self.new_block() test_constant = if_.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if if_.orelse: - self.visit_sequence(if_.orelse) + self.visit_sequence(if_.orelse) elif test_constant == optimize.CONST_TRUE: self.visit_sequence(if_.body) else: @@ -515,16 +503,14 @@ self.use_next_block(cleanup) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, start) - if fr.orelse: - self.visit_sequence(fr.orelse) + self.visit_sequence(fr.orelse) self.use_next_block(end) def visit_While(self, wh): self.update_position(wh.lineno, True) test_constant = wh.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if wh.orelse: - self.visit_sequence(wh.orelse) + self.visit_sequence(wh.orelse) else: end = self.new_block() anchor = None @@ -544,8 +530,7 @@ self.use_next_block(anchor) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, loop) - if wh.orelse: - self.visit_sequence(wh.orelse) + self.visit_sequence(wh.orelse) self.use_next_block(end) def visit_TryExcept(self, te): @@ -581,8 +566,7 @@ self.use_next_block(next_except) self.emit_op(ops.END_FINALLY) self.use_next_block(otherwise) - if te.orelse: - self.visit_sequence(te.orelse) + self.visit_sequence(te.orelse) self.use_next_block(end) def visit_TryFinally(self, tf): @@ -893,27 +877,19 @@ def visit_Tuple(self, tup): self.update_position(tup.lineno) - if tup.elts: - elt_count = len(tup.elts) - else: - elt_count = 0 + elt_count = len(tup.elts) if tup.elts is not None else 0 if tup.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: - self.visit_sequence(tup.elts) + self.visit_sequence(tup.elts) if tup.ctx == ast.Load: self.emit_op_arg(ops.BUILD_TUPLE, elt_count) def visit_List(self, l): self.update_position(l.lineno) - if l.elts: - elt_count = len(l.elts) - else: - elt_count = 0 + elt_count = len(l.elts) if l.elts is not None else 0 if l.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: - self.visit_sequence(l.elts) + self.visit_sequence(l.elts) if l.ctx == ast.Load: self.emit_op_arg(ops.BUILD_LIST, elt_count) @@ -944,11 +920,9 @@ if self._optimize_method_call(call): return call.func.walkabout(self) - arg = 0 + arg = len(call.args) if call.args is not None else 0 call_type = 0 - if call.args: - arg = len(call.args) - self.visit_sequence(call.args) + self.visit_sequence(call.args) if call.keywords: self.visit_sequence(call.keywords) arg |= len(call.keywords) << 8 @@ -984,16 +958,10 @@ assert isinstance(attr_lookup, ast.Attribute) attr_lookup.value.walkabout(self) self.emit_op_name(ops.LOOKUP_METHOD, self.names, attr_lookup.attr) - if call.args: - self.visit_sequence(call.args) - arg_count = len(call.args) - else: - arg_count = 0 - if call.keywords: - self.visit_sequence(call.keywords) - kwarg_count = len(call.keywords) - else: - kwarg_count = 0 + self.visit_sequence(call.args) + arg_count = len(call.args) if call.args is not None else 0 + self.visit_sequence(call.keywords) + kwarg_count = len(call.keywords) if call.keywords is not None else 0 self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) | arg_count) return True @@ -1251,7 +1219,10 @@ def _compile(self, func): assert isinstance(func, ast.FunctionDef) # If there's a docstring, store it as the first constant. - doc_expr = self.possible_docstring(func.body[0]) + if func.body: + doc_expr = self.possible_docstring(func.body[0]) + else: + doc_expr = None if doc_expr is not None: self.add_const(doc_expr.s) start = 1 @@ -1263,8 +1234,9 @@ if args.args: self._handle_nested_args(args.args) self.argcount = len(args.args) - for i in range(start, len(func.body)): - func.body[i].walkabout(self) + if func.body: + for i in range(start, len(func.body)): + func.body[i].walkabout(self) class LambdaCodeGenerator(AbstractFunctionCodeGenerator): diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py --- a/pypy/interpreter/astcompiler/symtable.py +++ b/pypy/interpreter/astcompiler/symtable.py @@ -356,10 +356,8 @@ # Function defaults and decorators happen in the outer scope. args = func.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) - if func.decorator_list: - self.visit_sequence(func.decorator_list) + self.visit_sequence(args.defaults) + self.visit_sequence(func.decorator_list) new_scope = FunctionScope(func.name, func.lineno, func.col_offset) self.push_scope(new_scope, func) func.args.walkabout(self) @@ -372,10 +370,8 @@ def visit_ClassDef(self, clsdef): self.note_symbol(clsdef.name, SYM_ASSIGNED) - if clsdef.bases: - self.visit_sequence(clsdef.bases) - if clsdef.decorator_list: - self.visit_sequence(clsdef.decorator_list) + self.visit_sequence(clsdef.bases) + self.visit_sequence(clsdef.decorator_list) self.push_scope(ClassScope(clsdef), clsdef) self.visit_sequence(clsdef.body) self.pop_scope() @@ -431,8 +427,7 @@ def visit_Lambda(self, lamb): args = lamb.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) + self.visit_sequence(args.defaults) new_scope = FunctionScope("lambda", lamb.lineno, lamb.col_offset) self.push_scope(new_scope, lamb) lamb.args.walkabout(self) @@ -447,8 +442,7 @@ self.push_scope(new_scope, node) self.implicit_arg(0) outer.target.walkabout(self) - if outer.ifs: - self.visit_sequence(outer.ifs) + self.visit_sequence(outer.ifs) self.visit_sequence(comps[1:]) for item in list(consider): item.walkabout(self) diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -221,8 +221,9 @@ self.emit("class ASTVisitor(object):") self.emit("") self.emit("def visit_sequence(self, seq):", 1) - self.emit("for node in seq:", 2) - self.emit("node.walkabout(self)", 3) + self.emit("if seq is not None:", 2) + self.emit("for node in seq:", 3) + self.emit("node.walkabout(self)", 4) self.emit("") self.emit("def default_visitor(self, node):", 1) self.emit("raise NodeVisitorNotImplemented", 2) @@ -280,15 +281,13 @@ def visitField(self, field): if field.type.value not in asdl.builtin_types and \ field.type.value not in self.data.simple_types: - if field.seq or field.opt: + level = 2 + template = "node.%s.walkabout(self)" + if field.seq: + template = "self.visit_sequence(node.%s)" + elif field.opt: self.emit("if node.%s:" % (field.name,), 2) level = 3 - else: - level = 2 - if field.seq: - template = "self.visit_sequence(node.%s)" - else: - template = "node.%s.walkabout(self)" self.emit(template % (field.name,), level) return True return False @@ -446,6 +445,7 @@ if field.seq: self.emit("w_self.w_%s = w_new_value" % (field.name,), 1) else: + save_original_object = False self.emit("try:", 1) if field.type.value not in asdl.builtin_types: # These are always other AST nodes. @@ -454,9 +454,7 @@ (field.type,), 2) self.emit("w_self.%s = obj.to_simple_int(space)" % (field.name,), 2) - self.emit("# need to save the original object too", 2) - self.emit("w_self.setdictvalue(space, '%s', w_new_value)" - % (field.name,), 2) + save_original_object = True else: config = (field.name, field.type, repr(field.opt)) self.emit("w_self.%s = space.interp_w(%s, w_new_value, %s)" % @@ -480,6 +478,12 @@ self.emit(" w_self.setdictvalue(space, '%s', w_new_value)" % (field.name,), 1) self.emit(" return", 1) + if save_original_object: + self.emit("# need to save the original object too", 1) + self.emit("w_self.setdictvalue(space, '%s', w_new_value)" + % (field.name,), 1) + else: + self.emit("w_self.deldictvalue(space, '%s')" %(field.name,), 1) self.emit("w_self.initialization_state |= %s" % (flag,), 1) self.emit("") diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -44,11 +44,11 @@ return True return False - def deldictvalue(self, space, w_name): + def deldictvalue(self, space, attr): w_dict = self.getdict(space) if w_dict is not None: try: - space.delitem(w_dict, w_name) + space.delitem(w_dict, space.wrap(attr)) return True except OperationError, ex: if not ex.match(space, space.w_KeyError): @@ -1284,6 +1284,17 @@ self.wrap("expected a 32-bit integer")) return value + def truncatedint(self, w_obj): + # Like space.gateway_int_w(), but return the integer truncated + # instead of raising OverflowError. For obscure cases only. + try: + return self.int_w(w_obj) + except OperationError, e: + if not e.match(self, self.w_OverflowError): + raise + from pypy.rlib.rarithmetic import intmask + return intmask(self.bigint_w(w_obj).uintmask()) + def c_filedescriptor_w(self, w_fd): # This is only used sometimes in CPython, e.g. for os.fsync() but # not os.close(). It's likely designed for 'select'. It's irregular diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -189,7 +189,7 @@ if space.is_w(w_value, space.w_None): # raise Type: we assume we have to instantiate Type w_value = space.call_function(w_type) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: w_valuetype = space.exception_getclass(w_value) if space.exception_issubclass_w(w_valuetype, w_type): @@ -204,18 +204,12 @@ else: # raise Type, X: assume X is the constructor argument w_value = space.call_function(w_type, w_value) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: # the only case left here is (inst, None), from a 'raise inst'. w_inst = w_type - w_instclass = space.exception_getclass(w_inst) - if not space.exception_is_valid_class_w(w_instclass): - instclassname = w_instclass.getname(space) - msg = ("exceptions must be old-style classes or derived " - "from BaseException, not %s") - raise operationerrfmt(space.w_TypeError, msg, instclassname) - + w_instclass = self._exception_getclass(space, w_inst) if not space.is_w(w_value, space.w_None): raise OperationError(space.w_TypeError, space.wrap("instance exception may not " @@ -226,6 +220,15 @@ self.w_type = w_type self._w_value = w_value + def _exception_getclass(self, space, w_inst): + w_type = space.exception_getclass(w_inst) + if not space.exception_is_valid_class_w(w_type): + typename = w_type.getname(space) + msg = ("exceptions must be old-style classes or derived " + "from BaseException, not %s") + raise operationerrfmt(space.w_TypeError, msg, typename) + return w_type + def write_unraisable(self, space, where, w_object=None): if w_object is None: objrepr = '' diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -140,6 +140,9 @@ def visit_c_nonnegint(self, el, app_sig): self.checked_space_method(el, app_sig) + def visit_truncatedint(self, el, app_sig): + self.checked_space_method(el, app_sig) + def visit__Wrappable(self, el, app_sig): name = el.__name__ argname = self.orig_arg() @@ -257,6 +260,9 @@ def visit_c_nonnegint(self, typ): self.run_args.append("space.c_nonnegint_w(%s)" % (self.scopenext(),)) + def visit_truncatedint(self, typ): + self.run_args.append("space.truncatedint(%s)" % (self.scopenext(),)) + def _make_unwrap_activation_class(self, unwrap_spec, cache={}): try: key = tuple(unwrap_spec) @@ -387,6 +393,9 @@ def visit_c_nonnegint(self, typ): self.unwrap.append("space.c_nonnegint_w(%s)" % (self.nextarg(),)) + def visit_truncatedint(self, typ): + self.unwrap.append("space.truncatedint(%s)" % (self.nextarg(),)) + def make_fastfunc(unwrap_spec, func): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -905,16 +905,15 @@ def SETUP_WITH(self, offsettoend, next_instr): w_manager = self.peekvalue() + w_enter = self.space.lookup(w_manager, "__enter__") w_descr = self.space.lookup(w_manager, "__exit__") - if w_descr is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__exit__")) + if w_enter is None or w_descr is None: + typename = self.space.type(w_manager).getname(self.space) + raise operationerrfmt(self.space.w_AttributeError, + "'%s' object is not a context manager" + " (no __enter__/__exit__ method)", typename) w_exit = self.space.get(w_descr, w_manager) self.settopvalue(w_exit) - w_enter = self.space.lookup(w_manager, "__enter__") - if w_enter is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__enter__")) w_result = self.space.get_and_call_function(w_enter, w_manager) block = WithBlock(self, next_instr + offsettoend) self.append_block(block) diff --git a/pypy/interpreter/test/test_raise.py b/pypy/interpreter/test/test_raise.py --- a/pypy/interpreter/test/test_raise.py +++ b/pypy/interpreter/test/test_raise.py @@ -274,3 +274,9 @@ pass except A: pass + + def test_new_returns_bad_instance(self): + class MyException(Exception): + def __new__(cls, *args): + return object() + raises(TypeError, "raise MyException") diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -23,7 +23,7 @@ self.hasdict |= __base.hasdict self.weakrefable |= __base.weakrefable self.rawdict = {} - self.acceptable_as_base_class = True + self.acceptable_as_base_class = '__new__' in rawdict self.applevel_subclasses_base = None # xxx used by faking self.fakedcpytype = None diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -453,21 +453,33 @@ class WriteBarrierDescr(AbstractDescr): def __init__(self, gc_ll_descr): + GCClass = gc_ll_descr.GCClass self.llop1 = gc_ll_descr.llop1 self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR - self.fielddescr_tid = get_field_descr(gc_ll_descr, - gc_ll_descr.GCClass.HDR, 'tid') - self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG - # if convenient for the backend, we also compute the info about + self.fielddescr_tid = get_field_descr(gc_ll_descr, GCClass.HDR, 'tid') + # + self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG + self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = ( + self.extract_flag_byte(self.jit_wb_if_flag)) + # + if hasattr(GCClass, 'JIT_WB_CARDS_SET'): + self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET + self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT + self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = ( + self.extract_flag_byte(self.jit_wb_cards_set)) + else: + self.jit_wb_cards_set = 0 + + def extract_flag_byte(self, flag_word): + # if convenient for the backend, we compute the info about # the flag as (byte-offset, single-byte-flag). import struct - value = struct.pack("l", self.jit_wb_if_flag) + value = struct.pack("l", flag_word) assert value.count('\x00') == len(value) - 1 # only one byte is != 0 i = 0 while value[i] == '\x00': i += 1 - self.jit_wb_if_flag_byteofs = i - self.jit_wb_if_flag_singlebyte = struct.unpack('b', value[i])[0] + return (i, struct.unpack('b', value[i])[0]) def get_write_barrier_fn(self, cpu): llop1 = self.llop1 diff --git a/pypy/jit/backend/llvm/llvm_rffi.py b/pypy/jit/backend/llvm/llvm_rffi.py --- a/pypy/jit/backend/llvm/llvm_rffi.py +++ b/pypy/jit/backend/llvm/llvm_rffi.py @@ -3,7 +3,7 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo, log -if sys.platform != 'linux2': +if not sys.platform.startswith('linux'): py.test.skip("Linux only for now") # ____________________________________________________________ diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -1707,6 +1707,7 @@ jit_wb_if_flag = 4096 jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 0 def get_write_barrier_from_array_fn(self, cpu): return funcbox.getint() # @@ -1728,6 +1729,72 @@ else: assert record == [] + def test_cond_call_gc_wb_array_card_marking_fast_path(self): + def func_void(a, b, c): + record.append((a, b, c)) + record = [] + # + S = lltype.Struct('S', ('tid', lltype.Signed)) + S_WITH_CARDS = lltype.Struct('S_WITH_CARDS', + ('card0', lltype.Char), + ('card1', lltype.Char), + ('card2', lltype.Char), + ('card3', lltype.Char), + ('card4', lltype.Char), + ('card5', lltype.Char), + ('card6', lltype.Char), + ('card7', lltype.Char), + ('data', S)) + FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)], + lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + funcbox = self.get_funcbox(self.cpu, func_ptr) + class WriteBarrierDescr(AbstractDescr): + jit_wb_if_flag = 4096 + jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') + jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 8192 + jit_wb_cards_set_byteofs = struct.pack("i", 8192).index('\x20') + jit_wb_cards_set_singlebyte = 0x20 + jit_wb_card_page_shift = 7 + def get_write_barrier_from_array_fn(self, cpu): + return funcbox.getint() + # + for BoxIndexCls in [BoxInt, ConstInt]: + for cond in [False, True]: + print + print '_'*79 + print 'BoxIndexCls =', BoxIndexCls + print 'JIT_WB_CARDS_SET =', cond + print + value = random.randrange(-sys.maxint, sys.maxint) + value |= 4096 + if cond: + value |= 8192 + else: + value &= ~8192 + s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True) + s.data.tid = value + sgcref = rffi.cast(llmemory.GCREF, s.data) + del record[:] + box_index = BoxIndexCls((9<<7) + 17) + self.execute_operation(rop.COND_CALL_GC_WB_ARRAY, + [BoxPtr(sgcref), box_index, BoxPtr(sgcref)], + 'void', descr=WriteBarrierDescr()) + if cond: + assert record == [] + assert s.card6 == '\x02' + else: + assert record == [(s.data, (9<<7) + 17, s.data)] + assert s.card6 == '\x00' + assert s.card0 == '\x00' + assert s.card1 == '\x00' + assert s.card2 == '\x00' + assert s.card3 == '\x00' + assert s.card4 == '\x00' + assert s.card5 == '\x00' + assert s.card7 == '\x00' + def test_force_operations_returning_void(self): values = [] def maybe_force(token, flag): diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -2246,10 +2246,12 @@ if opnum == rop.COND_CALL_GC_WB: N = 2 func = descr.get_write_barrier_fn(self.cpu) + card_marking = False elif opnum == rop.COND_CALL_GC_WB_ARRAY: N = 3 func = descr.get_write_barrier_from_array_fn(self.cpu) assert func != 0 + card_marking = descr.jit_wb_cards_set != 0 else: raise AssertionError(opnum) # @@ -2258,6 +2260,18 @@ imm(descr.jit_wb_if_flag_singlebyte)) self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later jz_location = self.mc.get_relative_pos() + + # for cond_call_gc_wb_array, also add another fast path: + # if GCFLAG_CARDS_SET, then we can just set one bit and be done + if card_marking: + self.mc.TEST8(addr_add_const(loc_base, + descr.jit_wb_cards_set_byteofs), + imm(descr.jit_wb_cards_set_singlebyte)) + self.mc.J_il8(rx86.Conditions['NZ'], 0) # patched later + jnz_location = self.mc.get_relative_pos() + else: + jnz_location = 0 + # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. if IS_X86_32: @@ -2297,6 +2311,43 @@ loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) + + # if GCFLAG_CARDS_SET, then we can do the whole thing that would + # be done in the CALL above with just four instructions, so here + # is an inline copy of them + if card_marking: + self.mc.JMP_l8(0) # jump to the exit, patched later + jmp_location = self.mc.get_relative_pos() + # patch the JNZ above + offset = self.mc.get_relative_pos() - jnz_location + assert 0 < offset <= 127 + self.mc.overwrite(jnz_location-1, chr(offset)) + # + loc_index = arglocs[1] + if isinstance(loc_index, RegLoc): + # choose a scratch register + tmp1 = loc_index + self.mc.PUSH_r(tmp1.value) + # SHR tmp, card_page_shift + self.mc.SHR_ri(tmp1.value, descr.jit_wb_card_page_shift) + # XOR tmp, -8 + self.mc.XOR_ri(tmp1.value, -8) + # BTS [loc_base], tmp + self.mc.BTS(addr_add_const(loc_base, 0), tmp1) + # done + self.mc.POP_r(tmp1.value) + elif isinstance(loc_index, ImmedLoc): + byte_index = loc_index.value >> descr.jit_wb_card_page_shift + byte_ofs = ~(byte_index >> 3) + byte_val = 1 << (byte_index & 7) + self.mc.OR8(addr_add_const(loc_base, byte_ofs), imm(byte_val)) + else: + raise AssertionError("index is neither RegLoc nor ImmedLoc") + # patch the JMP above + offset = self.mc.get_relative_pos() - jmp_location + assert 0 < offset <= 127 + self.mc.overwrite(jmp_location-1, chr(offset)) + # # patch the JZ above offset = self.mc.get_relative_pos() - jz_location assert 0 < offset <= 127 diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -476,6 +476,7 @@ AND = _binaryop('AND') OR = _binaryop('OR') + OR8 = _binaryop('OR8') XOR = _binaryop('XOR') NOT = _unaryop('NOT') SHL = _binaryop('SHL') @@ -483,6 +484,7 @@ SAR = _binaryop('SAR') TEST = _binaryop('TEST') TEST8 = _binaryop('TEST8') + BTS = _binaryop('BTS') ADD = _binaryop('ADD') SUB = _binaryop('SUB') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -496,6 +496,10 @@ AND8_rr = insn(rex_fw, '\x20', byte_register(1), byte_register(2,8), '\xC0') OR8_rr = insn(rex_fw, '\x08', byte_register(1), byte_register(2,8), '\xC0') + OR8_mi = insn(rex_fw, '\x80', orbyte(1<<3), mem_reg_plus_const(1), + immediate(2, 'b')) + OR8_ji = insn(rex_fw, '\x80', orbyte(1<<3), abs_, immediate(1), + immediate(2, 'b')) NEG_r = insn(rex_w, '\xF7', register(1), '\xD8') @@ -565,6 +569,9 @@ TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_, immediate(1), immediate(2, 'b')) TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0') + BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1)) + BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_, immediate(1)) + # x87 instructions FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -524,6 +524,76 @@ def test_compile_framework_8(self): self.run('compile_framework_8') + def define_compile_framework_9(cls): + # Like compile_framework_8, but with variable indexes and large + # arrays, testing the card_marking case + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + num = 512 + (n & 7) + l = [None] * num + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[num-8] = X(n+70) + l[num-9] = X(n+80) + l[num-10] = X(n+90) + l[num-11] = X(n+100) + l[-12] = X(n+110) + l[-13] = X(n+120) + l[-14] = X(n+130) + l[-15] = X(n+140) + if n < 1800: + num = 512 + (n & 7) + check(len(l) == num) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[num-8].x == n+70) + check(l[num-9].x == n+80) + check(l[num-10].x == n+90) + check(l[num-11].x == n+100) + check(l[-12].x == n+110) + check(l[-13].x == n+120) + check(l[-14].x == n+130) + check(l[-15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 512) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[-8].x == 72) + check(l[-9].x == 82) + check(l[-10].x == 92) + check(l[-11].x == 102) + check(l[-12].x == 112) + check(l[-13].x == 122) + check(l[-14].x == 132) + check(l[-15].x == 142) + return before, f, after + + def test_compile_framework_9(self): + self.run('compile_framework_9') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -420,10 +420,6 @@ _ll_1_dict_values.need_result_type = True _ll_1_dict_items .need_result_type = True - def _ll_1_newdictiter(ITER, d): - return ll_rdict.ll_dictiter(lltype.Ptr(ITER), d) - _ll_1_newdictiter.need_result_type = True - _dictnext_keys = staticmethod(ll_rdict.ll_dictnext_group['keys']) _dictnext_values = staticmethod(ll_rdict.ll_dictnext_group['values']) _dictnext_items = staticmethod(ll_rdict.ll_dictnext_group['items']) @@ -574,10 +570,6 @@ _ll_1_dict_values.need_result_type = True _ll_1_dict_items .need_result_type = True - def _ll_1_newdictiter(ITER, d): - return oo_rdict.ll_dictiter(ITER, d) - _ll_1_newdictiter.need_result_type = True - _dictnext_keys = staticmethod(oo_rdict.ll_dictnext_group['keys']) _dictnext_values = staticmethod(oo_rdict.ll_dictnext_group['values']) _dictnext_items = staticmethod(oo_rdict.ll_dictnext_group['items']) diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -769,7 +769,7 @@ def get_vinfo(self, v): return None def could_be_green_field(self, S1, name1): - assert S1 is S + assert S1 == S assert name1 == 'x' return True S = lltype.GcStruct('S', ('x', lltype.Char), diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2820,11 +2820,11 @@ def test_residual_call_invalidate_some_arrays(self): ops = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) - p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p2, 0, descr=arraydescr2) p6 = getarrayitem_gc(p2, 1, descr=arraydescr2) i4 = getarrayitem_gc(p1, 1, descr=arraydescr) escape(p3) @@ -2837,7 +2837,7 @@ """ expected = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -56,6 +56,8 @@ # for resume.py operation self.parent_resumedata_snapshot = None self.parent_resumedata_frame_info_list = None + # counter for unrolling inlined loops + self.unroll_iterations = 1 @specialize.arg(3) def copy_constants(self, registers, constants, ConstClass): @@ -931,6 +933,10 @@ # 'redboxes' back into the registers where it comes from. put_back_list_of_boxes3(self, jcposition, redboxes) else: + if jitdriver_sd.warmstate.should_unroll_one_iteration(greenboxes): + if self.unroll_iterations > 0: + self.unroll_iterations -= 1 + return # warning! careful here. We have to return from the current # frame containing the jit_merge_point, and then use # do_recursive_call() to follow the recursive call. This is @@ -1162,13 +1168,11 @@ metainterp.jitdriver_sd.greenfield_info is not None): virtualizable_boxes = metainterp.virtualizable_boxes saved_pc = self.pc - try: - if resumepc >= 0: - self.pc = resumepc - resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, - metainterp.virtualref_boxes, resumedescr) - finally: - self.pc = saved_pc + if resumepc >= 0: + self.pc = resumepc + resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, + metainterp.virtualref_boxes, resumedescr) + self.pc = saved_pc def implement_guard_value(self, orgpc, box): """Promote the given Box into a Const. Note: be careful, it's a diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -508,6 +508,32 @@ assert res == 84 - 61 - 62 self.check_history(call=1) # because the trace starts immediately + def test_unroll_one_loop_iteration(self): + def unroll(code): + return code == 0 + myjitdriver = JitDriver(greens = ['code'], + reds = ['loops', 'inner_loops', 's'], + should_unroll_one_iteration=unroll) + + def f(code, loops, inner_loops): + s = 0 + while loops > 0: + myjitdriver.jit_merge_point(code=code, loops=loops, + inner_loops=inner_loops, s=s) + if code == 1: + s += f(0, inner_loops, 0) + loops -= 1 + s += 1 + return s + + res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True) + assert res == f(1, 4, 1) + self.check_history(call_assembler=0) + + res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True) + assert res == f(1, 4, 2) + self.check_history(call_assembler=1) + def test_format(self): def f(n): return len("<%d>" % n) @@ -2586,7 +2612,23 @@ return n res = self.meta_interp(f, [10, 1]) self.check_loops(getfield_gc=2) + assert res == f(10, 1) + def test_jit_merge_point_with_raw_pointer(self): + driver = JitDriver(greens = [], reds = ['n', 'x']) + + TP = lltype.Array(lltype.Signed, hints={'nolength': True}) + + def f(n): + x = lltype.malloc(TP, 10, flavor='raw') + x[0] = 1 + while n > 0: + driver.jit_merge_point(n=n, x=x) + n -= x[0] + lltype.free(x, flavor='raw') + return n + + self.meta_interp(f, [10], repeat=3) class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -186,6 +186,7 @@ _get_printable_location_ptr = None _confirm_enter_jit_ptr = None _can_never_inline_ptr = None + _should_unroll_one_iteration_ptr = None class FakeCell: dont_trace_here = False state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) @@ -214,6 +215,7 @@ _confirm_enter_jit_ptr = None _can_never_inline_ptr = None _get_jitcell_at_ptr = None + _should_unroll_one_iteration_ptr = None state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) state.make_jitdriver_callbacks() res = state.get_location_str([ConstInt(5), constfloat(42.5)]) @@ -238,6 +240,7 @@ _confirm_enter_jit_ptr = llhelper(ENTER_JIT, confirm_enter_jit) _can_never_inline_ptr = None _get_jitcell_at_ptr = None + _should_unroll_one_iteration_ptr = None state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) state.make_jitdriver_callbacks() @@ -262,6 +265,7 @@ _confirm_enter_jit_ptr = None _can_never_inline_ptr = llhelper(CAN_NEVER_INLINE, can_never_inline) _get_jitcell_at_ptr = None + _should_unroll_one_iteration_ptr = None state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) state.make_jitdriver_callbacks() diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -10,6 +10,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import fatalerror +from pypy.rlib.rstackovf import StackOverflow from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function @@ -408,21 +409,28 @@ jd.warmstate = state def crash_in_jit(e): - if not we_are_translated(): - print "~~~ Crash in JIT!" - print '~~~ %s: %s' % (e.__class__, e) - if sys.stdout == sys.__stdout__: - import pdb; pdb.post_mortem(sys.exc_info()[2]) - raise - fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) + try: + raise e + except JitException: + raise # go through + except MemoryError: + raise # go through + except StackOverflow: + raise # go through + except Exception, e: + if not we_are_translated(): + print "~~~ Crash in JIT!" + print '~~~ %s: %s' % (e.__class__, e) + if sys.stdout == sys.__stdout__: + import pdb; pdb.post_mortem(sys.exc_info()[2]) + raise + fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) crash_in_jit._dont_inline_ = True if self.translator.rtyper.type_system.name == 'lltypesystem': def maybe_enter_jit(*args): try: maybe_compile_and_run(state.increment_threshold, *args) - except JitException: - raise # go through except Exception, e: crash_in_jit(e) maybe_enter_jit._always_inline_ = True @@ -460,6 +468,9 @@ onlygreens=False) jd._can_never_inline_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool) + jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd, + annhelper, jd.jitdriver.should_unroll_one_iteration, + annmodel.s_Bool) annhelper.finish() def _make_hook_graph(self, jitdriver_sd, annhelper, func, diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -138,7 +138,10 @@ refvalue = cpu.ts.cast_to_ref(value) cpu.set_future_value_ref(j, refvalue) elif typecode == 'int': - intvalue = lltype.cast_primitive(lltype.Signed, value) + if isinstance(lltype.typeOf(value), lltype.Ptr): + intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value)) + else: + intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) elif typecode == 'float': if lltype.typeOf(value) is lltype.Float: @@ -569,6 +572,19 @@ return can_inline_greenargs(*greenargs) self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + + if jd._should_unroll_one_iteration_ptr is None: + def should_unroll_one_iteration(greenkey): + return False + else: + rtyper = self.warmrunnerdesc.rtyper + inline_ptr = jd._should_unroll_one_iteration_ptr + def should_unroll_one_iteration(greenkey): + greenargs = unwrap_greenkey(greenkey) + fn = support.maybe_on_top_of_llinterp(rtyper, inline_ptr) + return fn(*greenargs) + self.should_unroll_one_iteration = should_unroll_one_iteration + if hasattr(jd.jitdriver, 'on_compile'): def on_compile(logger, token, operations, type, greenkey): greenargs = unwrap_greenkey(greenkey) diff --git a/pypy/module/__builtin__/abstractinst.py b/pypy/module/__builtin__/abstractinst.py --- a/pypy/module/__builtin__/abstractinst.py +++ b/pypy/module/__builtin__/abstractinst.py @@ -58,7 +58,10 @@ # -- case (anything, type) try: - w_result = space.isinstance(w_obj, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.isinstance_allow_override(w_obj, w_klass_or_tuple) + else: + w_result = space.isinstance(w_obj, w_klass_or_tuple) except OperationError, e: # if w_klass_or_tuple was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors @@ -72,8 +75,11 @@ w_pretendtype = space.getattr(w_obj, space.wrap('__class__')) if space.is_w(w_pretendtype, space.type(w_obj)): return False # common case: obj.__class__ is type(obj) - w_result = space.issubtype(w_pretendtype, w_klass_or_tuple, - allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_pretendtype, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_pretendtype, w_klass_or_tuple) except OperationError, e: if e.async(space): raise @@ -134,7 +140,11 @@ # -- case (type, type) try: - w_result = space.issubtype(w_derived, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_derived, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_derived, w_klass_or_tuple) except OperationError, e: # if one of the args was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -418,7 +418,7 @@ if w_meth is not None: space.call_function(w_meth, w_name) else: - if not self.deldictvalue(space, w_name): + if not self.deldictvalue(space, name): raise operationerrfmt( space.w_AttributeError, "%s instance has no attribute '%s'", diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -25,6 +25,7 @@ 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', 'lookup_special' : 'interp_magic.lookup_special', + 'do_what_I_mean' : 'interp_magic.do_what_I_mean', } submodules = { diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -70,3 +70,6 @@ if w_descr is None: return space.w_None return space.get(w_descr, w_obj) + +def do_what_I_mean(space): + return space.wrap(42) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -49,3 +49,8 @@ class X: pass raises(TypeError, lookup_special, X(), "foo") + + def test_do_what_I_mean(self): + from __pypy__ import do_what_I_mean + x = do_what_I_mean() + assert x == 42 diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -250,3 +250,38 @@ assert x.left == n1 assert x.op == addop assert x.right == n3 + + def test_functiondef(self): + import _ast as ast + fAst = ast.FunctionDef( + name="foo", + args=ast.arguments( + args=[], vararg=None, kwarg=None, defaults=[], + kwonlyargs=[], kw_defaults=[]), + body=[], decorator_list=[], lineno=5, col_offset=0) + exprAst = ast.Interactive(body=[fAst]) + compiled = compile(exprAst, "", "single") + # + d = {} + eval(compiled, d, d) + assert type(d['foo']) is type(lambda: 42) + assert d['foo']() is None + + def test_missing_name(self): + import _ast as ast + n = ast.FunctionDef(name=None) + n.name = "foo" + n.name = "foo" + n.name = "foo" + assert n.name == "foo" + + def test_issue793(self): + import _ast as ast + body = ast.Module([ + ast.TryExcept([ast.Pass(lineno=2, col_offset=4)], + [ast.ExceptHandler(ast.Name('Exception', ast.Load(), + lineno=3, col_offset=0), + None, [], lineno=4, col_offset=0)], + [], lineno=1, col_offset=0) + ]) + exec compile(body, '', 'exec') diff --git a/pypy/module/binascii/interp_crc32.py b/pypy/module/binascii/interp_crc32.py --- a/pypy/module/binascii/interp_crc32.py +++ b/pypy/module/binascii/interp_crc32.py @@ -61,7 +61,7 @@ crc_32_tab = map(r_uint, crc_32_tab) - at unwrap_spec(data='bufferstr', oldcrc='c_int') + at unwrap_spec(data='bufferstr', oldcrc='truncatedint') def crc32(space, data, oldcrc=0): "Compute the CRC-32 incrementally." diff --git a/pypy/module/binascii/test/test_binascii.py b/pypy/module/binascii/test/test_binascii.py --- a/pypy/module/binascii/test/test_binascii.py +++ b/pypy/module/binascii/test/test_binascii.py @@ -374,6 +374,8 @@ ('x', 10000, -1855256896), ('y', 10000, -429115818), ('z', 10000, 2137352172), + ('foo', 99999999999999999999999999, -1932704816), + ('bar', -99999999999999999999999999, 2000545409), ]: assert self.binascii.crc32(input, initial) == expected diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -337,7 +337,7 @@ 'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', 'init_capsule', 'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer', - + 'PyOS_getsig', 'PyOS_setsig', 'PyStructSequence_InitType', 'PyStructSequence_New', @@ -745,7 +745,7 @@ ctypes.c_void_p) setup_va_functions(eci) - + setup_init_functions(eci) return modulename.new(ext='') @@ -771,7 +771,7 @@ export_symbols[:] = renamed_symbols else: export_symbols[:] = [sym.replace("#", "") for sym in export_symbols] - + # Generate defines for macro_name, size in [ ("SIZEOF_LONG_LONG", rffi.LONGLONG), @@ -784,7 +784,7 @@ ]: pypy_macros.append("#define %s %s" % (macro_name, rffi.sizeof(size))) pypy_macros.append('') - + pypy_macros_h = udir.join('pypy_macros.h') pypy_macros_h.write('\n'.join(pypy_macros)) @@ -852,7 +852,7 @@ # Sometimes the library is wrapped into another DLL, ensure that # the correct bootstrap code is installed kwds["link_extra"] = ["msvcrt.lib"] - elif sys.platform == 'linux2': + elif sys.platform.startswith('linux'): compile_extra.append("-Werror=implicit-function-declaration") export_symbols_eci.append('pypyAPI') else: @@ -1007,7 +1007,7 @@ FT = lltype.typeOf(func).TO return make_generic_cpy_call(FT, False, False)(space, func, *args) - at specialize.ll() + at specialize.ll() def generic_cpy_call_expect_null(space, func, *args): FT = lltype.typeOf(func).TO return make_generic_cpy_call(FT, True, True)(space, func, *args) diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -188,7 +188,7 @@ kwds["compile_extra"] = ["/we4013"] else: kwds["link_files"] = [str(api_library + '.so')] - if sys.platform == 'linux2': + if sys.platform.startswith('linux'): kwds["compile_extra"]=["-Werror=implicit-function-declaration"] return compile_module(self.space, name, **kwds) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -85,7 +85,7 @@ return SEARCH_ERROR, None, None -if sys.platform == 'linux2' or 'freebsd' in sys.platform: +if sys.platform.startswith('linux') or 'freebsd' in sys.platform: def case_ok(filename): return True else: diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -379,16 +379,23 @@ self.start = -1 else: # all following calls consume = self.step + if consume > 1: + self._ignore_items(consume-1) if self.stop >= 0: if self.stop < consume: + self.stop = 0 # reset the state so that a following next_w() + self.step = 1 # has no effect any more raise OperationError(self.space.w_StopIteration, self.space.w_None) self.stop -= consume + return self.space.next(self.iterable) + + def _ignore_items(self, num): while True: - w_obj = self.space.next(self.iterable) - consume -= 1 - if consume <= 0: - return w_obj + self.space.next(self.iterable) + num -= 1 + if num <= 0: + break def W_ISlice___new__(space, w_subtype, w_iterable, w_startstop, args_w): r = space.allocate_instance(W_ISlice, w_subtype) diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -227,6 +227,45 @@ assert list(itertools.islice(xrange(10), None,None)) == range(10) assert list(itertools.islice(xrange(10), None,None,None)) == range(10) + def test_islice_dropitems_exact(self): + import itertools + + it = iter("abcdefghij") + itertools.islice(it, 2, 2) # doesn't eagerly drop anything + assert it.next() == "a" + itertools.islice(it, 3, 8, 2) # doesn't eagerly drop anything + assert it.next() == "b" + assert it.next() == "c" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 2, 3), None) # drops 2 items + assert x == "c" + assert it.next() == "d" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 3, 8, 2), None) # drops 3 items + assert x == "d" + assert it.next() == "e" + + it = iter("abcdefghij") + x = next(itertools.islice(it, None, 8), None) # drops 0 items + assert x == "a" + assert it.next() == "b" + + it = iter("abcdefghij") + x = next(itertools.islice(it, 3, 2), None) # drops 3 items + assert x is None + assert it.next() == "d" + + it = iter("abcdefghij") + islc = itertools.islice(it, 3, 7, 2) + assert islc.next() == "d" # drops 0, 1, 2, returns item #3 + assert it.next() == "e" + assert islc.next() == "g" # drops the 4th and return item #5 + assert it.next() == "h" + raises(StopIteration, islc.next) # drops the 6th and raise + assert it.next() == "j" + def test_islice_overflow(self): import itertools import sys diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -15,14 +15,19 @@ # ufuncs 'abs': 'interp_ufuncs.absolute', 'absolute': 'interp_ufuncs.absolute', + 'add': 'interp_ufuncs.add', 'copysign': 'interp_ufuncs.copysign', + 'divide': 'interp_ufuncs.divide', 'exp': 'interp_ufuncs.exp', + 'fabs': 'interp_ufuncs.fabs', 'floor': 'interp_ufuncs.floor', 'maximum': 'interp_ufuncs.maximum', 'minimum': 'interp_ufuncs.minimum', + 'multiply': 'interp_ufuncs.multiply', 'negative': 'interp_ufuncs.negative', 'reciprocal': 'interp_ufuncs.reciprocal', 'sign': 'interp_ufuncs.sign', + 'subtract': 'interp_ufuncs.subtract', 'sin': 'interp_ufuncs.sin', 'cos': 'interp_ufuncs.cos', 'tan': 'interp_ufuncs.tan', diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -3,7 +3,7 @@ It should not be imported by the module itself """ -from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray +from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray class BogusBytecode(Exception): pass @@ -18,6 +18,14 @@ def wrap(self, x): return x + def issequence_w(self, w_obj): + # Completley wrong in the general case, but good enough for this. + return isinstance(w_obj, BaseArray) + + def float_w(self, w_obj): + assert isinstance(w_obj, float) + return w_obj + def numpy_compile(bytecode, array_size): space = TrivialSpace() stack = [] diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -2,6 +2,8 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy.interp_support import Signature +from pypy.module.micronumpy import interp_ufuncs from pypy.objspace.std.floatobject import float2string as float2string_orig from pypy.rlib import jit from pypy.rlib.rfloat import DTSF_STR_PRECISION @@ -9,49 +11,19 @@ from pypy.tool.sourcetools import func_with_new_name import math -def dummy1(v): - assert isinstance(v, float) - return v - -def dummy2(v): - assert isinstance(v, float) - return v - TP = lltype.Array(lltype.Float, hints={'nolength': True}) numpy_driver = jit.JitDriver(greens = ['signature'], reds = ['result_size', 'i', 'self', 'result']) all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self']) +slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) +slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) -class Signature(object): - def __init__(self): - self.transitions = {} - - def transition(self, target): - if target in self.transitions: - return self.transitions[target] - self.transitions[target] = new = Signature() - return new - -def pos(v): - return v -def neg(v): - return -v -def absolute(v): - return abs(v) def add(v1, v2): return v1 + v2 -def sub(v1, v2): - return v1 - v2 def mul(v1, v2): return v1 * v2 -def div(v1, v2): - return v1 / v2 -def power(v1, v2): - return math.pow(v1, v2) -def mod(v1, v2): - return math.fmod(v1, v2) def maximum(v1, v2): return max(v1, v2) def minimum(v1, v2): @@ -73,67 +45,39 @@ arr.force_if_needed() del self.invalidates[:] - def _unop_impl(function): - signature = Signature() + def _unaryop_impl(w_ufunc): def impl(self, space): - new_sig = self.signature.transition(signature) - res = Call1( - function, - self, - new_sig) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "uniop_%s_impl" % function.__name__) + return w_ufunc(space, self) + return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__) - descr_pos = _unop_impl(pos) - descr_neg = _unop_impl(neg) - descr_abs = _unop_impl(absolute) + descr_pos = _unaryop_impl(interp_ufuncs.positive) + descr_neg = _unaryop_impl(interp_ufuncs.negative) + descr_abs = _unaryop_impl(interp_ufuncs.absolute) - def _binop_impl(function): - signature = Signature() + def _binop_impl(w_ufunc): def impl(self, space, w_other): - w_other = convert_to_array(space, w_other) - new_sig = self.signature.transition(signature) - res = Call2( - function, - self, - w_other, - new_sig.transition(w_other.signature) - ) - w_other.invalidates.append(res) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, "binop_%s_impl" % function.__name__) + return w_ufunc(space, self, w_other) + return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__) - descr_add = _binop_impl(add) - descr_sub = _binop_impl(sub) - descr_mul = _binop_impl(mul) - descr_div = _binop_impl(div) - descr_pow = _binop_impl(power) - descr_mod = _binop_impl(mod) + descr_add = _binop_impl(interp_ufuncs.add) + descr_sub = _binop_impl(interp_ufuncs.subtract) + descr_mul = _binop_impl(interp_ufuncs.multiply) + descr_div = _binop_impl(interp_ufuncs.divide) + descr_pow = _binop_impl(interp_ufuncs.power) + descr_mod = _binop_impl(interp_ufuncs.mod) - def _binop_right_impl(function): - signature = Signature() + def _binop_right_impl(w_ufunc): def impl(self, space, w_other): - new_sig = self.signature.transition(signature) w_other = FloatWrapper(space.float_w(w_other)) - res = Call2( - function, - w_other, - self, - new_sig.transition(w_other.signature) - ) - self.invalidates.append(res) - return space.wrap(res) - return func_with_new_name(impl, - "binop_right_%s_impl" % function.__name__) + return w_ufunc(space, w_other, self) + return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__) - descr_radd = _binop_right_impl(add) - descr_rsub = _binop_right_impl(sub) - descr_rmul = _binop_right_impl(mul) - descr_rdiv = _binop_right_impl(div) - descr_rpow = _binop_right_impl(power) - descr_rmod = _binop_right_impl(mod) + descr_radd = _binop_right_impl(interp_ufuncs.add) + descr_rsub = _binop_right_impl(interp_ufuncs.subtract) + descr_rmul = _binop_right_impl(interp_ufuncs.multiply) + descr_rdiv = _binop_right_impl(interp_ufuncs.divide) + descr_rpow = _binop_right_impl(interp_ufuncs.power) + descr_rmod = _binop_right_impl(interp_ufuncs.mod) def _reduce_sum_prod_impl(function, init): reduce_driver = jit.JitDriver(greens=['signature'], @@ -261,6 +205,9 @@ def get_concrete(self): raise NotImplementedError + def descr_copy(self, space): + return new_numarray(space, self) + def descr_get_shape(self, space): return space.newtuple([self.descr_len(space)]) @@ -288,14 +235,52 @@ res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) return space.wrap(res) - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): + def descr_setitem(self, space, w_idx, w_value): + # TODO: indexing by tuples and lists self.invalidated() - return self.get_concrete().descr_setitem(space, item, value) + start, stop, step, slice_length = space.decode_index4(w_idx, + self.find_size()) + if step == 0: + # Single index + self.get_concrete().setitem(start, space.float_w(w_value)) + else: + concrete = self.get_concrete() + if isinstance(w_value, BaseArray): + # for now we just copy if setting part of an array from + # part of itself. can be improved. + if (concrete.get_root_storage() == + w_value.get_concrete().get_root_storage()): + w_value = new_numarray(space, w_value) + else: + w_value = convert_to_array(space, w_value) + concrete.setslice(space, start, stop, step, + slice_length, w_value) def descr_mean(self, space): return space.wrap(space.float_w(self.descr_sum(space))/self.find_size()) + def _sliceloop1(self, start, stop, step, source, dest): + i = start + j = 0 + while i < stop: + slice_driver1.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + + def _sliceloop2(self, start, stop, step, source, dest): + i = start + j = 0 + while i > stop: + slice_driver2.jit_merge_point(signature=source.signature, + step=step, stop=stop, i=i, j=j, source=source, + dest=dest) + dest.storage[i] = source.eval(j) + j += 1 + i += step + def convert_to_array (space, w_obj): if isinstance(w_obj, BaseArray): return w_obj @@ -440,8 +425,8 @@ return self.parent.getitem(self.calc_index(item)) @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - return self.parent.descr_setitem(space, self.calc_index(item), value) + def setitem(self, item, value): + return self.parent.setitem(self.calc_index(item), value) def descr_len(self, space): return space.wrap(self.find_size()) @@ -455,14 +440,34 @@ def __init__(self, start, stop, step, slice_length, parent, signature): ViewArray.__init__(self, parent, signature) - self.start = start - self.stop = stop - self.step = step + if isinstance(parent, SingleDimSlice): + self.start = parent.calc_index(start) + self.stop = parent.calc_index(stop) + self.step = parent.step * step + self.parent = parent.parent + else: + self.start = start + self.stop = stop + self.step = step + self.parent = parent self.size = slice_length + def get_root_storage(self): + return self.parent.storage + def find_size(self): return self.size + def setslice(self, space, start, stop, step, slice_length, arr): + start = self.calc_index(start) + if stop != -1: + stop = self.calc_index(stop) + step = self.step * step + if step > 0: + self._sliceloop1(start, stop, step, arr, self.parent) + else: + self._sliceloop2(start, stop, step, arr, self.parent) + def calc_index(self, item): return (self.start + item * self.step) @@ -480,35 +485,31 @@ def get_concrete(self): return self + def get_root_storage(self): + return self.storage + def find_size(self): return self.size def eval(self, i): return self.storage[i] - def getindex(self, space, item): - if item >= self.size: - raise operationerrfmt(space.w_IndexError, - '%d above array size', item) - if item < 0: - item += self.size - if item < 0: - raise operationerrfmt(space.w_IndexError, - '%d below zero', item) - return item - def descr_len(self, space): return space.wrap(self.size) def getitem(self, item): return self.storage[item] - @unwrap_spec(item=int, value=float) - def descr_setitem(self, space, item, value): - item = self.getindex(space, item) + def setitem(self, item, value): self.invalidated() self.storage[item] = value + def setslice(self, space, start, stop, step, slice_length, arr): + if step > 0: + self._sliceloop1(start, stop, step, arr, self) + else: + self._sliceloop2(start, stop, step, arr, self) + def __del__(self): lltype.free(self.storage, flavor='raw') @@ -539,6 +540,7 @@ 'numarray', __new__ = interp2app(descr_new_numarray), + copy = interp2app(BaseArray.descr_copy), shape = GetSetProperty(BaseArray.descr_get_shape), __len__ = interp2app(BaseArray.descr_len), diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py --- a/pypy/module/micronumpy/interp_support.py +++ b/pypy/module/micronumpy/interp_support.py @@ -1,14 +1,14 @@ - from pypy.rlib.rstruct.runpack import runpack from pypy.rpython.lltypesystem import lltype, rffi +from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec -from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.interp_numarray import SingleDimArray + FLOAT_SIZE = rffi.sizeof(lltype.Float) @unwrap_spec(s=str) def fromstring(space, s): + from pypy.module.micronumpy.interp_numarray import SingleDimArray length = len(s) if length % FLOAT_SIZE == 0: @@ -30,3 +30,13 @@ end += FLOAT_SIZE return space.wrap(a) + +class Signature(object): + def __init__(self): + self.transitions = {} + + def transition(self, target): + if target in self.transitions: + return self.transitions[target] + self.transitions[target] = new = Signature() + return new \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,13 +1,13 @@ import math -from pypy.module.micronumpy.interp_numarray import (Call1, Call2, Signature, - convert_to_array) +from pypy.module.micronumpy.interp_support import Signature from pypy.rlib import rfloat from pypy.tool.sourcetools import func_with_new_name def ufunc(func): signature = Signature() def impl(space, w_obj): + from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array if space.issequence_w(w_obj): w_obj_arr = convert_to_array(space, w_obj) w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature)) @@ -20,6 +20,7 @@ def ufunc2(func): signature = Signature() def impl(space, w_lhs, w_rhs): + from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array if space.issequence_w(w_lhs) or space.issequence_w(w_rhs): w_lhs_arr = convert_to_array(space, w_lhs) w_rhs_arr = convert_to_array(space, w_rhs) @@ -37,9 +38,17 @@ return abs(value) @ufunc2 +def add(lvalue, rvalue): + return lvalue + rvalue + + at ufunc2 def copysign(lvalue, rvalue): return rfloat.copysign(lvalue, rvalue) + at ufunc2 +def divide(lvalue, rvalue): + return lvalue / rvalue + @ufunc def exp(value): try: @@ -47,6 +56,10 @@ except OverflowError: return rfloat.INFINITY + at ufunc +def fabs(value): + return math.fabs(value) + @ufunc2 def maximum(lvalue, rvalue): return max(lvalue, rvalue) @@ -55,6 +68,15 @@ def minimum(lvalue, rvalue): return min(lvalue, rvalue) + at ufunc2 +def multiply(lvalue, rvalue): + return lvalue * rvalue + +# Used by numarray for __pos__. Not visible from numpy application space. + at ufunc +def positive(value): + return value + @ufunc def negative(value): return -value @@ -65,6 +87,10 @@ return rfloat.copysign(rfloat.INFINITY, value) return 1.0 / value + at ufunc2 +def subtract(lvalue, rvalue): + return lvalue - rvalue + @ufunc def floor(value): return math.floor(value) @@ -86,3 +112,11 @@ @ufunc def tan(value): return math.tan(value) + + at ufunc2 +def power(lvalue, rvalue): + return math.pow(lvalue, rvalue) + + at ufunc2 +def mod(lvalue, rvalue): + return math.fmod(lvalue, rvalue) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -38,6 +38,13 @@ a[2] = 4 assert a[2] == 4 + def test_copy(self): + from numpy import array + a = array(range(5)) + b = a.copy() + for i in xrange(5): + assert b[i] == a[i] + def test_iterator_init(self): from numpy import array a = array(range(5)) @@ -92,6 +99,51 @@ raises(IndexError, "a[5] = 0.0") raises(IndexError, "a[-6] = 3.0") + def test_setslice_array(self): + from numpy import array + a = array(range(5)) + b = array(range(2)) + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + b[::-1] = b + assert b[0] == 1. + assert b[1] == 0. + + def test_setslice_of_slice_array(self): + from numpy import array, zeros + a = zeros(5) + a[::2] = array([9., 10., 11.]) + assert a[0] == 9. + assert a[2] == 10. + assert a[4] == 11. + a[1:4:2][::-1] = array([1., 2.]) + assert a[0] == 9. + assert a[1] == 2. + assert a[2] == 10. + assert a[3] == 1. + assert a[4] == 11. + a = zeros(10) + a[::2][::-1][::2] = array(range(1,4)) + assert a[8] == 1. + assert a[4] == 2. + assert a[0] == 3. + + def test_setslice_list(self): + from numpy import array + a = array(range(5)) + b = [0., 1.] + a[1:4:2] = b + assert a[1] == 0. + assert a[3] == 1. + + def test_setslice_constant(self): + from numpy import array + a = array(range(5)) + a[1:4:2] = 0. + assert a[1] == 0. + assert a[3] == 0. + def test_len(self): from numpy import array a = array(range(5)) @@ -129,6 +181,12 @@ for i in range(5): assert b[i] == i + 5 + def test_radd(self): + from numpy import array + r = 3 + array(range(3)) + for i in range(3): + assert r[i] == i + 3 + def test_add_list(self): from numpy import array a = array(range(5)) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -65,6 +65,33 @@ for i in range(3): assert b[i] == abs(a[i]) + def test_add(self): + from numpy import array, add + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = add(a, b) + for i in range(3): + assert c[i] == a[i] + b[i] + + def test_divide(self): + from numpy import array, divide + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = divide(a, b) + for i in range(3): + assert c[i] == a[i] / b[i] + + def test_fabs(self): + from numpy import array, fabs + from math import fabs as math_fabs + + a = array([-5.0, -0.0, 1.0]) + b = fabs(a) + for i in range(3): + assert b[i] == math_fabs(a[i]) + def test_minimum(self): from numpy import array, minimum @@ -83,6 +110,15 @@ for i in range(3): assert c[i] == max(a[i], b[i]) + def test_multiply(self): + from numpy import array, multiply + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = multiply(a, b) + for i in range(3): + assert c[i] == a[i] * b[i] + def test_sign(self): from numpy import array, sign @@ -101,6 +137,15 @@ for i in range(4): assert b[i] == reference[i] + def test_subtract(self): + from numpy import array, subtract + + a = array([-5.0, -0.0, 1.0]) + b = array([ 3.0, -2.0,-3.0]) + c = subtract(a, b) + for i in range(3): + assert c[i] == a[i] - b[i] + def test_floor(self): from numpy import array, floor diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -1,10 +1,11 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.rpython.test.test_llinterp import interpret from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature, - FloatWrapper, Call2, SingleDimSlice, add, mul, neg, Call1) + FloatWrapper, Call2, SingleDimSlice, add, mul, Call1) from pypy.module.micronumpy.interp_ufuncs import negative from pypy.module.micronumpy.compile import numpy_compile from pypy.rlib.objectmodel import specialize +from pypy.rlib.nonconst import NonConstant class FakeSpace(object): w_ValueError = None @@ -47,21 +48,6 @@ "int_lt": 1, "guard_true": 1, "jump": 1}) assert result == f(5) - def test_neg(self): - space = self.space - - def f(i): - ar = SingleDimArray(i) - v = Call1(neg, ar, Signature()) - return v.get_concrete().storage[3] - - result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({"getarrayitem_raw": 1, "float_neg": 1, - "setarrayitem_raw": 1, "int_add": 1, - "int_lt": 1, "guard_true": 1, "jump": 1}) - - assert result == f(5) - def test_sum(self): space = self.space @@ -104,6 +90,7 @@ "float_gt": 1, "int_add": 1, "int_lt": 1, "guard_true": 1, "guard_false": 1, "jump": 1}) + assert result == f(5) def test_min(self): space = self.space @@ -121,6 +108,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_argmin(self): space = self.space @@ -138,6 +126,7 @@ "float_lt": 1, "int_add": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_all(self): space = self.space @@ -153,6 +142,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "int_lt": 1, "guard_true": 2, "jump": 1}) + assert result == f(5) def test_any(self): space = self.space @@ -165,6 +155,7 @@ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "int_add": 1, "float_ne": 1, "guard_false": 1, "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == f(5) def test_already_forecd(self): def f(i): @@ -248,6 +239,28 @@ 'int_lt': 1, 'guard_true': 1, 'jump': 1}) assert result == f(5) + def test_setslice(self): + space = self.space + + def f(i): + step = NonConstant(3) + ar = SingleDimArray(step*i) + ar2 = SingleDimArray(i) + ar2.storage[1] = 5.5 + if NonConstant(False): + arg = ar2 + else: + arg = ar2.descr_add(space, ar2) + ar.setslice(space, 0, step*i, step, i, arg) + return ar.get_concrete().storage[3] + + result = self.meta_interp(f, [5], listops=True, backendopt=True) + self.check_loops({'getarrayitem_raw': 2, + 'float_add' : 1, + 'setarrayitem_raw': 1, 'int_add': 2, + 'int_lt': 1, 'guard_true': 1, 'jump': 1}) + assert result == 11.0 + class TestTranslation(object): def test_compile(self): x = numpy_compile('aa+f*f/a-', 10) diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -125,13 +125,13 @@ assert st.st_size == 14 assert st.st_nlink == 1 - #if sys.platform.startswith('linux2'): + #if sys.platform.startswith('linux'): # # expects non-integer timestamps - it's unlikely that they are # # all three integers # assert ((st.st_atime, st.st_mtime, st.st_ctime) != # (st[7], st[8], st[9])) # assert st.st_blksize * st.st_blocks >= st.st_size - if sys.platform.startswith('linux2'): + if sys.platform.startswith('linux'): assert hasattr(st, 'st_rdev') def test_stat_float_times(self): diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -44,9 +44,11 @@ ec.w_tracefunc is None) def can_never_inline(next_instr, is_being_profiled, bytecode): + return False + +def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode): return (bytecode.co_flags & CO_GENERATOR) != 0 - def wrap_oplist(space, logops, operations): list_w = [] for op in operations: @@ -110,7 +112,9 @@ get_jitcell_at = get_jitcell_at, set_jitcell_at = set_jitcell_at, confirm_enter_jit = confirm_enter_jit, - can_never_inline = can_never_inline) + can_never_inline = can_never_inline, + should_unroll_one_iteration = + should_unroll_one_iteration) class __extend__(PyFrame): diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -30,7 +30,6 @@ assert res == 8.0 * 300 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('fficall', """ - p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>) guard_not_invalidated(descr=...) i17 = force_token() setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -23,3 +23,29 @@ ops = loop.ops_by_id('look') assert log.opnames(ops) == ['setfield_gc', 'guard_not_invalidated'] + + def test_identitydict(self): + def fn(n): + class X(object): + pass + x = X() + d = {} + d[x] = 1 + res = 0 + for i in range(300): + value = d[x] # ID: getitem + res += value + return res + # + log = self.run(fn, [1000]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + # check that the call to ll_dict_lookup is not a call_may_force + assert loop.match_by_id("getitem", """ + i25 = call(ConstClass(_ll_1_gc_identityhash__objectPtr), p6, descr=...) + ... + i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...) + ... + p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...) + ... + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py @@ -0,0 +1,25 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGenerators(BaseTestPyPyC): + def test_simple_generator(self): + def main(n): + def f(): + for i in range(10000): + yield i + + def g(): + for i in f(): # ID: generator + pass + + g() + + log = self.run(main, [500]) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("generator", """ + i16 = force_token() + p45 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p45, i29, descr=) + setarrayitem_gc(p8, 0, p45, descr=) + jump(..., descr=...) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py --- a/pypy/module/pypyjit/test_pypy_c/test_math.py +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -30,3 +30,34 @@ --TICK-- jump(..., descr=) """) + + def test_sin_cos(self): + def main(n): + import math + + i = 1 + s = 0.0 + while i < n: + s += math.sin(i) - math.cos(i) + i += 1 + return s + log = self.run(main, [500]) + assert round(log.result, 6) == round(main(500), 6) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i2 = int_lt(i0, i1) + guard_true(i2, descr=...) + f1 = cast_int_to_float(i0) + i3 = float_eq(f1, inf) + i4 = float_eq(f1, -inf) + i5 = int_or(i3, i4) + i6 = int_is_true(i5) + guard_false(i6, descr=...) + f2 = call(ConstClass(sin), f1, descr=) + f3 = call(ConstClass(cos), f1, descr=) + f4 = float_sub(f2, f3) + f5 = float_add(f0, f4) + i7 = int_add(i0, f1) + --TICK-- + jump(..., descr=) + """) \ No newline at end of file diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -92,10 +92,10 @@ p51 = new_with_vtable(21136408) setfield_gc(p51, p28, descr=) setfield_gc(p51, ConstPtr(ptr51), descr=) - setfield_gc(p51, i29, descr=) setfield_gc(p51, 1, descr=) setfield_gc(p51, 16, descr=) setfield_gc(p51, p28, descr=) + setfield_gc(p51, i29, descr=) p55 = call(ConstClass(parse_digit_string), p51, descr=) guard_no_exception(descr=...) i57 = call(ConstClass(rbigint.toint), p55, descr=) @@ -104,4 +104,4 @@ guard_no_overflow(descr=...) --TICK-- jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=) - """) \ No newline at end of file + """) diff --git a/pypy/module/select/test/test_epoll.py b/pypy/module/select/test/test_epoll.py --- a/pypy/module/select/test/test_epoll.py +++ b/pypy/module/select/test/test_epoll.py @@ -138,7 +138,7 @@ expected.sort() assert events == expected - assert then - now < 0.01 + assert then - now < 0.02 now = time.time() events = ep.poll(timeout=2.1, maxevents=4) @@ -151,7 +151,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 events.sort() expected = [ @@ -168,7 +168,7 @@ now = time.time() events = ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 expected = [(server.fileno(), select.EPOLLOUT)] assert events == expected @@ -192,7 +192,7 @@ now = time.time() ep.poll(1, 4) then = time.time() - assert then - now < 0.01 + assert then - now < 0.02 server.close() ep.unregister(fd) diff --git a/pypy/module/zlib/interp_zlib.py b/pypy/module/zlib/interp_zlib.py --- a/pypy/module/zlib/interp_zlib.py +++ b/pypy/module/zlib/interp_zlib.py @@ -20,25 +20,15 @@ return intmask((x ^ SIGN_EXTEND2) - SIGN_EXTEND2) - at unwrap_spec(string='bufferstr') -def crc32(space, string, w_start = rzlib.CRC32_DEFAULT_START): + at unwrap_spec(string='bufferstr', start='truncatedint') +def crc32(space, string, start = rzlib.CRC32_DEFAULT_START): """ crc32(string[, start]) -- Compute a CRC-32 checksum of string. An optional starting value can be specified. The returned checksum is an integer. """ - if space.is_true(space.isinstance(w_start, space.w_long)): - num = space.bigint_w(w_start) - ustart = num.uintmask() - elif space.is_true(space.isinstance(w_start, space.w_int)): - start = space.int_w(w_start) - ustart = r_uint(start) - else: - raise OperationError(space.w_TypeError, - space.wrap("crc32() argument 2 must " - "be integer, not str")) - + ustart = r_uint(start) checksum = rzlib.crc32(string, ustart) # This is, perhaps, a little stupid. zlib returns the checksum unsigned. @@ -51,7 +41,7 @@ return space.wrap(checksum) - at unwrap_spec(string='bufferstr', start=r_uint) + at unwrap_spec(string='bufferstr', start='truncatedint') def adler32(space, string, start=rzlib.ADLER32_DEFAULT_START): """ adler32(string[, start]) -- Compute an Adler-32 checksum of string. @@ -59,7 +49,8 @@ An optional starting value can be specified. The returned checksum is an integer. """ - checksum = rzlib.adler32(string, start) + ustart = r_uint(start) + checksum = rzlib.adler32(string, ustart) # See comments in crc32() for the following line checksum = unsigned_to_signed_32bit(checksum) diff --git a/pypy/module/zlib/test/test_zlib.py b/pypy/module/zlib/test/test_zlib.py --- a/pypy/module/zlib/test/test_zlib.py +++ b/pypy/module/zlib/test/test_zlib.py @@ -78,15 +78,17 @@ def test_crc32_negative_long_start(self): v = self.zlib.crc32('', -1L) assert v == -1 + assert self.zlib.crc32('foo', -99999999999999999999999) == 1611238463 def test_crc32_long_start(self): import sys v = self.zlib.crc32('', sys.maxint*2) assert v == -2 + assert self.zlib.crc32('foo', 99999999999999999999999) == 1635107045 def test_adler32(self): """ - When called with a string, zlib.crc32 should compute its adler 32 + When called with a string, zlib.adler32() should compute its adler 32 checksum and return it as a signed 32 bit integer. On 64-bit machines too (it is a bug in CPython < 2.6 to return unsigned values in this case). @@ -113,6 +115,9 @@ helloworldsum = self.zlib.adler32(world, hellosum) assert helloworldsum == self.zlib.adler32(hello + world) + assert self.zlib.adler32('foo', -1) == 45547858 + assert self.zlib.adler32('foo', 99999999999999999999999) == -114818734 + def test_invalidLevel(self): """ diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -28,6 +28,13 @@ return w_delattr object_delattr._annspecialcase_ = 'specialize:memo' +def object_hash(space): + "Utility that returns the app-level descriptor object.__hash__." + w_src, w_hash = space.lookup_in_type_where(space.w_object, + '__hash__') + return w_hash +object_hash._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): w_type = space.type(w_obj) typename = w_type.getname(space) @@ -89,7 +96,7 @@ if space.is_data_descr(w_descr): space.delete(w_descr, w_obj) return - if w_obj.deldictvalue(space, w_name): + if w_obj.deldictvalue(space, name): return raiseattrerror(space, w_obj, name, w_descr) @@ -490,22 +497,25 @@ space.wrap("coercion should return None or 2-tuple")) return w_res - def issubtype(space, w_sub, w_type, allow_override=False): - if allow_override: - w_check = space.lookup(w_type, "__subclasscheck__") - if w_check is None: - raise OperationError(space.w_TypeError, - space.wrap("issubclass not supported here")) - return space.get_and_call_function(w_check, w_type, w_sub) + def issubtype(space, w_sub, w_type): return space._type_issubtype(w_sub, w_type) - def isinstance(space, w_inst, w_type, allow_override=False): - if allow_override: - w_check = space.lookup(w_type, "__instancecheck__") - if w_check is not None: - return space.get_and_call_function(w_check, w_type, w_inst) - return space.issubtype(space.type(w_inst), w_type, allow_override) + def isinstance(space, w_inst, w_type): + return space._type_isinstance(w_inst, w_type) + def issubtype_allow_override(space, w_sub, w_type): + w_check = space.lookup(w_type, "__subclasscheck__") + if w_check is None: + raise OperationError(space.w_TypeError, + space.wrap("issubclass not supported here")) + return space.get_and_call_function(w_check, w_type, w_sub) + + def isinstance_allow_override(space, w_inst, w_type): + w_check = space.lookup(w_type, "__instancecheck__") + if w_check is not None: + return space.get_and_call_function(w_check, w_type, w_inst) + else: + return space.isinstance(w_inst, w_type) # helpers diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -157,11 +157,15 @@ return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): - #XXX implement other strategies later + withidentitydict = self.space.config.objspace.std.withidentitydict if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) - elif self.space.is_w(self.space.type(w_key), self.space.w_int): + return + w_type = self.space.type(w_key) + if self.space.is_w(w_type, self.space.w_int): self.switch_to_int_strategy(w_dict) + elif withidentitydict and w_type.compares_by_identity(): + self.switch_to_identity_strategy(w_dict) else: self.switch_to_object_strategy(w_dict) @@ -177,6 +181,13 @@ w_dict.strategy = strategy w_dict.dstorage = storage + def switch_to_identity_strategy(self, w_dict): + from pypy.objspace.std.identitydict import IdentityDictStrategy + strategy = self.space.fromcache(IdentityDictStrategy) + storage = strategy.get_empty_storage() + w_dict.strategy = strategy + w_dict.dstorage = storage + def switch_to_object_strategy(self, w_dict): strategy = self.space.fromcache(ObjectDictStrategy) storage = strategy.get_empty_storage() @@ -338,7 +349,6 @@ def getitem(self, w_dict, w_key): space = self.space - if self.is_correct_type(w_key): return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None) elif self._never_equal_to(space.type(w_key)): @@ -404,6 +414,7 @@ def keys(self, w_dict): return self.unerase(w_dict.dstorage).keys() + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") @@ -448,7 +459,9 @@ return StrIteratorImplementation(self.space, self, w_dict) -class StrIteratorImplementation(IteratorImplementation): +class _WrappedIteratorMixin(object): + _mixin_ = True + def __init__(self, space, strategy, dictimplementation): IteratorImplementation.__init__(self, space, dictimplementation) self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() @@ -460,6 +473,23 @@ else: return None, None +class _UnwrappedIteratorMixin: + _mixin_ = True + + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for w_key, w_value in self.iterator: + return w_key, w_value + else: + return None, None + + +class StrIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass class IntDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("int") @@ -490,31 +520,11 @@ def iter(self, w_dict): return IntIteratorImplementation(self.space, self, w_dict) -class IntIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() +class IntIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation): + pass - def next_entry(self): - # note that this 'for' loop only runs once, at most - for key, w_value in self.iterator: - return self.space.wrap(key), w_value - else: - return None, None - - -class ObjectIteratorImplementation(IteratorImplementation): - def __init__(self, space, strategy, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems() - - def next_entry(self): - # note that this 'for' loop only runs once, at most - for w_key, w_value in self.iterator: - return w_key, w_value - else: - return None, None - +class ObjectIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass init_signature = Signature(['seq_or_map'], None, 'kwargs') init_defaults = [None] diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -61,7 +61,8 @@ space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): - if not self.unerase(w_dict.dstorage).deldictvalue(space, w_key): + key = self.space.str_w(w_key) + if not self.unerase(w_dict.dstorage).deldictvalue(space, key): raise KeyError else: raise KeyError @@ -86,7 +87,7 @@ def clear(self, w_dict): self.unerase(w_dict.dstorage).dict_w.clear() - self.unerase(w_dict.dstorage).mutated() + self.unerase(w_dict.dstorage).mutated(None) class DictProxyIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, dictimplementation): diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/identitydict.py @@ -0,0 +1,88 @@ +## ---------------------------------------------------------------------------- +## dict strategy (see dict_multiobject.py) + +from pypy.rlib import rerased +from pypy.rlib.debug import mark_dict_non_null +from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, + DictStrategy, + IteratorImplementation, + _UnwrappedIteratorMixin) + + +# this strategy is selected by EmptyDictStrategy.switch_to_correct_strategy +class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): + """ + Strategy for custom instances which compares by identity (i.e., the + default unless you override __hash__, __eq__ or __cmp__). The storage is + just a normal RPython dict, which has already the correct by-identity + semantics. + + Note that at a first sight, you might have problems if you mutate the + class of an object which is already inside an identitydict. Consider this + example:: + + class X(object): + pass + d = {x(): 1} + X.__eq__ = ... + d[y] # might trigger a call to __eq__? + + We want to be sure that x.__eq__ is called in the same cases as in + CPython. However, as long as the strategy is IdentityDictStrategy, the + __eq__ will never be called. + + It turns out that it's not a problem. In CPython (and in PyPy without + this strategy), the __eq__ is called if ``hash(y) == hash(x)`` and ``x is + not y``. Note that hash(x) is computed at the time when we insert x in + the dict, not at the time we lookup y. + + Now, how can hash(y) == hash(x)? There are two possibilities: + + 1. we write a custom __hash__ for the class of y, thus making it a not + "compares by reference" type + + 2. the class of y is "compares by reference" type, and by chance the + hash is the same as x + + In the first case, the getitem immediately notice that y is not of the + right type, and switches the strategy to ObjectDictStrategy, then the + lookup works as usual. + + The second case is completely non-deterministic, even in CPython. + Depending on the phase of the moon, you might call the __eq__ or not, so + it is perfectly fine to *never* call it. Morever, in practice with the + minimark GC we never have two live objects with the same hash, so it would + never happen anyway. + """ + + erase, unerase = rerased.new_erasing_pair("identitydict") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, unwrapped): + return unwrapped + + def unwrap(self, wrapped): + return wrapped + + def get_empty_storage(self): + d = {} + mark_dict_non_null(d) + return self.erase(d) + + def is_correct_type(self, w_obj): + w_type = self.space.type(w_obj) + return w_type.compares_by_identity() + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return IdentityDictIteratorImplementation(self.space, self, w_dict) + + def keys(self, w_dict): + return self.unerase(w_dict.dstorage).keys() + + +class IdentityDictIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation): + pass diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -369,8 +369,7 @@ def setdictvalue(self, space, attrname, w_value): return self._get_mapdict_map().write(self, (attrname, DICT), w_value) - def deldictvalue(self, space, w_name): - attrname = space.str_w(w_name) + def deldictvalue(self, space, attrname): new_obj = self._get_mapdict_map().delete(self, (attrname, DICT)) if new_obj is None: return False @@ -647,7 +646,8 @@ w_key_type = space.type(w_key) w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): - flag = w_obj.deldictvalue(space, w_key) + key = self.space.str_w(w_key) + flag = w_obj.deldictvalue(space, key) if not flag: raise KeyError elif _never_equal_to_string(space, w_key_type): diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -6,7 +6,7 @@ from pypy.objspace.descroperation import Object from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.register_all import register_all - +from pypy.objspace.std import identitydict def descr__repr__(space, w_obj): w = space.wrap diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -39,7 +39,6 @@ from pypy.objspace.std.stringtype import wrapstr from pypy.objspace.std.unicodetype import wrapunicode - class StdObjSpace(ObjSpace, DescrOperation): """The standard object space, implementing a general-purpose object library in Restricted Python.""" @@ -569,3 +568,8 @@ if isinstance(w_sub, W_TypeObject) and isinstance(w_type, W_TypeObject): return self.wrap(w_sub.issubtype(w_type)) raise OperationError(self.w_TypeError, self.wrap("need type objects")) + + def _type_isinstance(self, w_inst, w_type): + if isinstance(w_type, W_TypeObject): + return self.wrap(self.type(w_inst).issubtype(w_type)) + raise OperationError(self.w_TypeError, self.wrap("need type object")) diff --git a/pypy/objspace/std/proxyobject.py b/pypy/objspace/std/proxyobject.py --- a/pypy/objspace/std/proxyobject.py +++ b/pypy/objspace/std/proxyobject.py @@ -52,10 +52,10 @@ raise return False - def deldictvalue(self, space, w_attr): + def deldictvalue(self, space, attr): try: space.call_function(self.w_controller, space.wrap('__delattr__'), - w_attr) + space.wrap(attr)) return True except OperationError, e: if not e.match(space, space.w_AttributeError): diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -898,6 +898,7 @@ withsmalldicts = False withcelldict = False withmethodcache = False + withidentitydict = False FakeSpace.config = Config() @@ -1105,3 +1106,4 @@ fakespace = FakeSpace() d = fakespace.newdict(module=True) assert type(d.strategy) is StringDictStrategy + diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_identitydict.py @@ -0,0 +1,138 @@ +import py +from pypy.interpreter.gateway import interp2app +from pypy.conftest import gettestobjspace +from pypy.conftest import option + +class AppTestComparesByIdentity: + + def setup_class(cls): + from pypy.objspace.std import identitydict + cls.space = gettestobjspace( + **{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("interp2app doesn't work on appdirect") + + def compares_by_identity(space, w_cls): + return space.wrap(w_cls.compares_by_identity()) + cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity)) + + def test_compares_by_identity(self): + class Plain(object): + pass + + class CustomEq(object): + def __eq__(self, other): + return True + + class CustomCmp (object): + def __cmp__(self, other): + return 0 + + class CustomHash(object): + def __hash__(self): + return 0 + + assert self.compares_by_identity(Plain) + assert not self.compares_by_identity(CustomEq) + assert not self.compares_by_identity(CustomCmp) + assert not self.compares_by_identity(CustomHash) + + def test_modify_class(self): + class X(object): + pass + + assert self.compares_by_identity(X) + X.__eq__ = lambda x: None + assert not self.compares_by_identity(X) + del X.__eq__ + assert self.compares_by_identity(X) + + +class AppTestIdentityDict(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withidentitydict": True}) + if option.runappdirect: + py.test.skip("interp2app doesn't work on appdirect") + + def w_uses_identity_strategy(self, obj): + import __pypy__ + return "IdentityDictStrategy" in __pypy__.internal_repr(obj) + + def test_use_strategy(self): + class X(object): + pass + d = {} + x = X() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[x] == 1 + + def test_bad_item(self): + class X(object): + pass + class Y(object): + def __hash__(self): + return 32 + + d = {} + x = X() + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + d[y] = 2 + assert not self.uses_identity_strategy(d) + assert d[x] == 1 + assert d[y] == 2 + + def test_bad_key(self): + class X(object): + pass + d = {} + x = X() + + class Y(object): + def __hash__(self): + return hash(x) # to make sure we do x == y + + def __eq__(self, other): + return True + + y = Y() + d[x] = 1 + assert self.uses_identity_strategy(d) + assert d[y] == 1 + assert not self.uses_identity_strategy(d) + + def test_iter(self): + class X(object): + pass + x = X() + d = {x: 1} + assert self.uses_identity_strategy(d) + assert list(iter(d)) == [x] + + def test_mutate_class_and_then_compare(self): + class X(object): + pass + class Y(object): + pass + + x = X() + y = Y() + d1 = {x: 1} + d2 = {y: 1} + assert self.uses_identity_strategy(d1) + assert self.uses_identity_strategy(d2) + # + X.__hash__ = lambda self: hash(y) + X.__eq__ = lambda self, other: True + # + assert d1 == d2 + assert self.uses_identity_strategy(d1) + assert not self.uses_identity_strategy(d2) + + def test_old_style_classes(self): + class X: + pass + d = {X(): 1} + assert not self.uses_identity_strategy(d) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -7,6 +7,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member from pypy.objspace.std.objecttype import object_typedef +from pypy.objspace.std import identitydict from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash from pypy.rlib.jit import promote, elidable_promote, we_are_jitted @@ -76,6 +77,10 @@ for i in range(len(self.lookup_where)): self.lookup_where[i] = None_None +# possible values of compares_by_identity_status +UNKNOWN = 0 +COMPARES_BY_IDENTITY = 1 +OVERRIDES_EQ_CMP_OR_HASH = 2 class W_TypeObject(W_Object): from pypy.objspace.std.typetype import type_typedef as typedef @@ -102,6 +107,9 @@ # (False is a conservative default, fixed during real usage) uses_object_getattribute = False + # for config.objspace.std.withidentitydict + compares_by_identity_status = UNKNOWN + # used to cache the type __new__ function if it comes from a builtin type # != 'type', in that case call__Type will also assumes the result # of the __new__ is an instance of the type @@ -146,11 +154,17 @@ else: w_self.terminator = NoDictTerminator(space, w_self) - def mutated(w_self): + def mutated(w_self, key): + """ + The type is being mutated. key is either the string containing the + specific attribute which is being deleted/set or None to indicate a + generic mutation. + """ space = w_self.space assert w_self.is_heaptype() or space.config.objspace.std.mutable_builtintypes if (not space.config.objspace.std.withtypeversion and not space.config.objspace.std.getattributeshortcut and + not space.config.objspace.std.withidentitydict and not space.config.objspace.std.newshortcut): return @@ -158,6 +172,13 @@ w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage + if space.config.objspace.std.withidentitydict: + did_compare_by_identity = ( + w_self.compares_by_identity_status == COMPARES_BY_IDENTITY) + if (key is None or key == '__eq__' or + key == '__cmp__' or key == '__hash__'): + w_self.compares_by_identity_status = UNKNOWN + if space.config.objspace.std.newshortcut: w_self.w_bltin_new = None @@ -168,7 +189,7 @@ subclasses_w = w_self.get_subclasses() for w_subclass in subclasses_w: assert isinstance(w_subclass, W_TypeObject) - w_subclass.mutated() + w_subclass.mutated(key) def version_tag(w_self): if (not we_are_jitted() or w_self.is_heaptype() or @@ -207,6 +228,25 @@ def has_object_getattribute(w_self): return w_self.getattribute_if_not_from_object() is None + def compares_by_identity(w_self): + from pypy.objspace.descroperation import object_hash + if not w_self.space.config.objspace.std.withidentitydict: + return False # conservative + # + if w_self.compares_by_identity_status != UNKNOWN: + # fast path + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + # + default_hash = object_hash(w_self.space) + overrides_eq_cmp_or_hash = (w_self.lookup('__eq__') or + w_self.lookup('__cmp__') or + w_self.lookup('__hash__') is not default_hash) + if overrides_eq_cmp_or_hash: + w_self.compares_by_identity_status = OVERRIDES_EQ_CMP_OR_HASH + else: + w_self.compares_by_identity_status = COMPARES_BY_IDENTITY + return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY + def ready(w_self): for w_base in w_self.bases_w: if not isinstance(w_base, W_TypeObject): @@ -269,14 +309,13 @@ w_curr.w_value = w_value return True w_value = TypeCell(w_value) - w_self.mutated() + w_self.mutated(name) w_self.dict_w[name] = w_value return True - def deldictvalue(w_self, space, w_key): + def deldictvalue(w_self, space, key): if w_self.lazyloaders: w_self._freeze_() # force un-lazification - key = space.str_w(w_key) if (not space.config.objspace.std.mutable_builtintypes and not w_self.is_heaptype()): msg = "can't delete attributes on type object '%s'" @@ -286,7 +325,7 @@ except KeyError: return False else: - w_self.mutated() + w_self.mutated(key) return True def lookup(w_self, name): diff --git a/pypy/objspace/std/typetype.py b/pypy/objspace/std/typetype.py --- a/pypy/objspace/std/typetype.py +++ b/pypy/objspace/std/typetype.py @@ -141,7 +141,7 @@ w_oldbestbase.getname(space)) # invalidate the version_tag of all the current subclasses - w_type.mutated() + w_type.mutated(None) # now we can go ahead and change 'w_type.bases_w' saved_bases_w = w_type.bases_w @@ -226,7 +226,7 @@ def descr_del___abstractmethods__(space, w_type): w_type = _check(space, w_type) - if not w_type.deldictvalue(space, space.wrap("__abstractmethods__")): + if not w_type.deldictvalue(space, "__abstractmethods__"): raise OperationError(space.w_AttributeError, space.wrap("__abstractmethods__")) w_type.set_abstract(False) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -315,7 +315,7 @@ def __init__(self, greens=None, reds=None, virtualizables=None, get_jitcell_at=None, set_jitcell_at=None, get_printable_location=None, confirm_enter_jit=None, - can_never_inline=None): + can_never_inline=None, should_unroll_one_iteration=None): if greens is not None: self.greens = greens if reds is not None: @@ -334,6 +334,7 @@ self.get_printable_location = get_printable_location self.confirm_enter_jit = confirm_enter_jit self.can_never_inline = can_never_inline + self.should_unroll_one_iteration = should_unroll_one_iteration def _freeze_(self): return True diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -40,7 +40,7 @@ # In that case, do 5 bits at a time. The potential drawback is that # a table of 2**5 intermediate results is computed. -FIVEARY_CUTOFF = 8 +## FIVEARY_CUTOFF = 8 disabled for now def _mask_digit(x): @@ -456,7 +456,7 @@ # python adaptation: moved macros REDUCE(X) and MULT(X, Y, result) # into helper function result = _help_mult(x, y, c) - if b.numdigits() <= FIVEARY_CUTOFF: + if 1: ## b.numdigits() <= FIVEARY_CUTOFF: # Left-to-right binary exponentiation (HAC Algorithm 14.79) # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf i = b.numdigits() - 1 @@ -469,26 +469,30 @@ z = _help_mult(z, a, c) j >>= 1 i -= 1 - else: - # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) - # This is only useful in the case where c != None. - # z still holds 1L - table = [z] * 32 - table[0] = z - for i in range(1, 32): - table[i] = _help_mult(table[i-1], a, c) - i = b.numdigits() - 1 - while i >= 0: - bi = b.digit(i) - j = SHIFT - 5 - while j >= 0: - index = (bi >> j) & 0x1f - for k in range(5): - z = _help_mult(z, z, c) - if index: - z = _help_mult(z, table[index], c) - j -= 5 - i -= 1 +## else: +## This code is disabled for now, because it assumes that +## SHIFT is a multiple of 5. It could be fixed but it looks +## like it's more troubles than benefits... +## +## # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) +## # This is only useful in the case where c != None. +## # z still holds 1L +## table = [z] * 32 +## table[0] = z +## for i in range(1, 32): +## table[i] = _help_mult(table[i-1], a, c) +## i = b.numdigits() - 1 +## while i >= 0: +## bi = b.digit(i) +## j = SHIFT - 5 +## while j >= 0: +## index = (bi >> j) & 0x1f +## for k in range(5): +## z = _help_mult(z, z, c) +## if index: +## z = _help_mult(z, table[index], c) +## j -= 5 +## i -= 1 if negativeOutput and z.sign != 0: z = z.sub(c) diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py --- a/pypy/rlib/rerased.py +++ b/pypy/rlib/rerased.py @@ -113,7 +113,7 @@ if hop.r_result.lowleveltype is lltype.Void: return hop.inputconst(lltype.Void, None) [v] = hop.inputargs(hop.args_r[0]) - return hop.genop('cast_opaque_ptr', [v], resulttype = hop.r_result) + return hop.args_r[0].rtype_unerase(hop, v) return erase, unerase @@ -147,7 +147,7 @@ def specialize_call(self, hop): [v] = hop.inputargs(hop.args_r[0]) assert isinstance(hop.s_result, annmodel.SomeInteger) - return hop.gendirectcall(ll_unerase_int, v) + return hop.args_r[0].rtype_unerase_int(hop, v) def ll_unerase_int(gcref): from pypy.rpython.lltypesystem.lloperation import llop @@ -174,7 +174,10 @@ return False # cannot be None, but can contain a None def rtyper_makerepr(self, rtyper): - return ErasedRepr(rtyper) + if rtyper.type_system.name == 'lltypesystem': + return ErasedRepr(rtyper) + elif rtyper.type_system.name == 'ootypesystem': + return OOErasedRepr(rtyper) def rtyper_makekey(self): return self.__class__, @@ -200,6 +203,13 @@ return hop.genop('cast_opaque_ptr', [v_obj], resulttype=self.lowleveltype) + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_opaque_ptr', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + return hop.gendirectcall(ll_unerase_int, v) + def rtype_erase_int(self, hop): [v_value] = hop.inputargs(lltype.Signed) c_one = hop.inputconst(lltype.Signed, 1) @@ -224,3 +234,50 @@ return lltype.nullptr(self.lowleveltype.TO) v = r_obj.convert_const(value._x) return lltype.cast_opaque_ptr(self.lowleveltype, v) + +from pypy.rpython.ootypesystem import ootype + +class OOErasedRepr(Repr): + lowleveltype = ootype.Object + def __init__(self, rtyper): + self.rtyper = rtyper + + def rtype_erase(self, hop, s_obj): + hop.exception_cannot_occur() + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return hop.inputconst(self.lowleveltype, + ootype.NULL) + [v_obj] = hop.inputargs(r_obj) + return hop.genop('cast_to_object', [v_obj], + resulttype=self.lowleveltype) + + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_from_object', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('oounbox_int', [v], resulttype=hop.r_result) + return hop.genop('int_rshift', [v2, c_one], resulttype=lltype.Signed) + + def rtype_erase_int(self, hop): + hop.exception_is_here() + [v_value] = hop.inputargs(lltype.Signed) + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('int_lshift_ovf', [v_value, c_one], + resulttype = lltype.Signed) + v2p1 = hop.genop('int_add', [v2, c_one], + resulttype = lltype.Signed) + return hop.genop('oobox_int', [v2p1], resulttype=hop.r_result) + + def convert_const(self, value): + if value._identity is _identity_for_ints: + return value._x # FIXME: what should we do here? + bk = self.rtyper.annotator.bookkeeper + s_obj = value._identity.get_input_annotation(bk) + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return ootype.NULL + v = r_obj.convert_const(value._x) + return ootype.cast_to_object(v) diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -875,28 +875,32 @@ if bufsize == -1: # Get default from the class bufsize = self.bufsize self.bufsize = bufsize # buffer size (hint only) - self.buf = "" + self.buf = [] + self.buflen = 0 def flush_buffers(self): if self.buf: - self.do_write(self.buf) - self.buf = "" + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 def tell(self): - return self.do_tell() + len(self.buf) + return self.do_tell() + self.buflen def write(self, data): - buflen = len(self.buf) + buflen = self.buflen datalen = len(data) if datalen + buflen < self.bufsize: - self.buf += data + self.buf.append(data) + self.buflen += datalen elif buflen: - slice = self.bufsize - buflen - assert slice >= 0 - self.buf += data[:slice] - self.do_write(self.buf) - self.buf = "" - self.write(data[slice:]) + i = self.bufsize - buflen + assert i >= 0 + self.buf.append(data[:i]) + self.do_write(''.join(self.buf)) + self.buf = [] + self.buflen = 0 + self.write(data[i:]) else: self.do_write(data) @@ -922,11 +926,27 @@ """ def write(self, data): - BufferingOutputStream.write(self, data) - p = self.buf.rfind('\n') + 1 - if p >= 0: - self.do_write(self.buf[:p]) - self.buf = self.buf[p:] + p = data.rfind('\n') + 1 + assert p >= 0 + if self.buflen + len(data) < self.bufsize: + if p == 0: + self.buf.append(data) + self.buflen += len(data) + else: + if self.buflen: + self.do_write(''.join(self.buf)) + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) + else: + if self.buflen + p < self.bufsize: + p = self.bufsize - self.buflen + if self.buflen: + self.do_write(''.join(self.buf)) + assert p >= 0 + self.do_write(data[:p]) + self.buf = [data[p:]] + self.buflen = len(self.buf[0]) # ____________________________________________________________ diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py --- a/pypy/rlib/test/test_rbigint.py +++ b/pypy/rlib/test/test_rbigint.py @@ -373,6 +373,13 @@ print '--->', v assert v.tolong() == pow(x, y, z) + def test_pow_lll_bug(self): + two = rbigint.fromint(2) + t = rbigint.fromlong(2655689964083835493447941032762343136647965588635159615997220691002017799304) + for n, expected in [(37, 9), (1291, 931), (67889, 39464)]: + v = two.pow(t, rbigint.fromint(n)) + assert v.toint() == expected + def test_pow_lln(self): x = 10L y = 2L diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py --- a/pypy/rlib/test/test_rerased.py +++ b/pypy/rlib/test/test_rerased.py @@ -5,8 +5,10 @@ from pypy.annotation.annrpython import RPythonAnnotator from pypy.rpython.test.test_llinterp import interpret from pypy.rpython.lltypesystem.rclass import OBJECTPTR +from pypy.rpython.ootypesystem.rclass import OBJECT from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin class X(object): pass @@ -79,136 +81,6 @@ s = a.build_types(f, []) assert isinstance(s, annmodel.SomeInteger) -def test_rtype_1(): - def f(): - return eraseX(X()) - x = interpret(f, []) - assert lltype.typeOf(x) == llmemory.GCREF - -def test_rtype_2(): - def f(): - x1 = X() - e = eraseX(x1) - #assert not is_integer(e) - x2 = uneraseX(e) - return x2 - x = interpret(f, []) - assert lltype.castable(OBJECTPTR, lltype.typeOf(x)) > 0 - -def test_rtype_3(): - def f(): - e = erase_int(16) - #assert is_integer(e) - x2 = unerase_int(e) - return x2 - x = interpret(f, []) - assert x == 16 - - -def test_prebuilt_erased(): - e1 = erase_int(16) - x1 = X() - x1.foobar = 42 - e2 = eraseX(x1) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = unerase_int(e1) + uneraseX(e2).foobar - return x2 - x = interpret(f, []) - assert x == 16 + 42 + 1 - -def test_prebuilt_erased_in_instance(): - erase_empty, unerase_empty = new_erasing_pair("empty") - class FakeList(object): - pass - - x1 = X() - x1.foobar = 42 - l1 = FakeList() - l1.storage = eraseX(x1) - l2 = FakeList() - l2.storage = erase_empty(None) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) - return x2 - x = interpret(f, []) - assert x == 43 + True - - -def test_overflow(): - def f(i): - try: - e = erase_int(i) - except OverflowError: - return -1 - #assert is_integer(e) - return unerase_int(e) - x = interpret(f, [16]) - assert x == 16 - x = interpret(f, [sys.maxint]) - assert x == -1 - -def test_none(): - def foo(): - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - # - def foo(): - eraseX(X()) - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - -def test_union(): - s_e1 = SomeErased() - s_e1.const = 1 - s_e2 = SomeErased() - s_e2.const = 3 - assert not annmodel.pair(s_e1, s_e2).union().is_constant() - - -def test_rtype_list(): - prebuilt_l = [X()] - prebuilt_e = erase_list_X(prebuilt_l) - def l(flag): - if flag == 1: - l = [X()] - e = erase_list_X(l) - elif flag == 2: - l = prebuilt_l - e = erase_list_X(l) - else: - l = prebuilt_l - e = prebuilt_e - #assert is_integer(e) is False - assert unerase_list_X(e) is l - interpret(l, [0]) - interpret(l, [1]) - interpret(l, [2]) - -# ____________________________________________________________ - -def test_erasing_pair(): - erase, unerase = new_erasing_pair("test1") - class X: - pass - x = X() - erased = erase(x) - assert unerase(erased) is x - # - erase2, unerase2 = new_erasing_pair("test2") - py.test.raises(AssertionError, unerase2, erased) - def test_annotate_erasing_pair(): erase, unerase = new_erasing_pair("test1") erase2, unerase2 = new_erasing_pair("test2") @@ -296,3 +168,148 @@ a = RPythonAnnotator() s = a.build_types(f, [int]) assert isinstance(s, annmodel.SomeInteger) + +class BaseTestRErased(BaseRtypingTest): + def test_rtype_1(self): + def f(): + return eraseX(X()) + x = self.interpret(f, []) + assert lltype.typeOf(x) == self.ERASED_TYPE + + def test_rtype_2(self): + def f(): + x1 = X() + e = eraseX(x1) + #assert not is_integer(e) + x2 = uneraseX(e) + return x2 + x = self.interpret(f, []) + assert self.castable(self.UNERASED_TYPE, x) + + def test_rtype_3(self): + def f(): + e = erase_int(16) + #assert is_integer(e) + x2 = unerase_int(e) + return x2 + x = self.interpret(f, []) + assert x == 16 + + def test_prebuilt_erased(self): + e1 = erase_int(16) + x1 = X() + x1.foobar = 42 + e2 = eraseX(x1) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = unerase_int(e1) + uneraseX(e2).foobar + return x2 + x = self.interpret(f, []) + assert x == 16 + 42 + 1 + + def test_prebuilt_erased_in_instance(self): + erase_empty, unerase_empty = new_erasing_pair("empty") + class FakeList(object): + pass + + x1 = X() + x1.foobar = 42 + l1 = FakeList() + l1.storage = eraseX(x1) + l2 = FakeList() + l2.storage = erase_empty(None) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) + return x2 + x = self.interpret(f, []) + assert x == 43 + True + + def test_overflow(self): + def f(i): + try: + e = erase_int(i) + except OverflowError: + return -1 + #assert is_integer(e) + return unerase_int(e) + x = self.interpret(f, [16]) + assert x == 16 + x = self.interpret(f, [sys.maxint]) + assert x == -1 + + def test_none(self): + def foo(): + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + # + def foo(): + eraseX(X()) + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + + def test_rtype_list(self): + prebuilt_l = [X()] + prebuilt_e = erase_list_X(prebuilt_l) + def l(flag): + if flag == 1: + l = [X()] + e = erase_list_X(l) + elif flag == 2: + l = prebuilt_l + e = erase_list_X(l) + else: + l = prebuilt_l + e = prebuilt_e + #assert is_integer(e) is False + assert unerase_list_X(e) is l + self.interpret(l, [0]) + self.interpret(l, [1]) + self.interpret(l, [2]) + +class TestLLtype(BaseTestRErased, LLRtypeMixin): + ERASED_TYPE = llmemory.GCREF + UNERASED_TYPE = OBJECTPTR + def castable(self, TO, var): + return lltype.castable(TO, lltype.typeOf(var)) > 0 + +from pypy.rpython.ootypesystem.ootype import Object + +class TestOOtype(BaseTestRErased, OORtypeMixin): + ERASED_TYPE = Object + UNERASED_TYPE = OBJECT + def castable(self, TO, var): + return ootype.isSubclass(lltype.typeOf(var), TO) + @py.test.mark.xfail + def test_prebuilt_erased(self): + super(TestOOtype, self).test_prebuilt_erased() + +def test_union(): + s_e1 = SomeErased() + s_e1.const = 1 + s_e2 = SomeErased() + s_e2.const = 3 + assert not annmodel.pair(s_e1, s_e2).union().is_constant() + +# ____________________________________________________________ + +def test_erasing_pair(): + erase, unerase = new_erasing_pair("test1") + class X: + pass + x = X() + erased = erase(x) + assert unerase(erased) is x + # + erase2, unerase2 = new_erasing_pair("test2") + py.test.raises(AssertionError, unerase2, erased) diff --git a/pypy/rlib/test/test_rlocale.py b/pypy/rlib/test/test_rlocale.py --- a/pypy/rlib/test/test_rlocale.py +++ b/pypy/rlib/test/test_rlocale.py @@ -37,7 +37,7 @@ assert isinstance(grouping, str) def test_libintl(): - if sys.platform not in ("linux2", "darwin"): + if sys.platform != "darwin" or not sys.platform.startswith("linux"): py.test.skip("there is (maybe) no libintl here") _gettext = external('gettext', [rffi.CCHARP], rffi.CCHARP) res = _gettext("1234") diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py --- a/pypy/rpython/extfuncregistry.py +++ b/pypy/rpython/extfuncregistry.py @@ -42,6 +42,8 @@ ('sqrt', [float], float), ('log', [float], float), ('log10', [float], float), + ('sin', [float], float), + ('cos', [float], float), ]), ] for module, methods in _register: diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -1225,6 +1225,12 @@ except ValueError: self.make_llexception() + def op_oobox_int(self, i): + return ootype.oobox_int(i) + + def op_oounbox_int(self, x): + return ootype.oounbox_int(x) + class Tracer(object): Counter = 0 file = None diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -553,7 +553,7 @@ return _items _items.append(nextitem) i += 1 - + items = property(getitems) class _array_of_known_length(_array_of_unknown_length): @@ -934,7 +934,7 @@ return clibname+'.dll' else: return ctypes.util.find_library('c') - + libc_name = get_libc_name() # Make sure the name is determined during import, not at runtime # XXX is this always correct??? standard_c_lib = ctypes.CDLL(get_libc_name(), **load_library_kwargs) @@ -980,7 +980,7 @@ return lib[elem] except AttributeError: pass - + old_eci = funcptr._obj.compilation_info funcname = funcptr._obj._name if hasattr(old_eci, '_with_ctypes'): @@ -1331,7 +1331,7 @@ def _where_is_errno(): return standard_c_lib._errno() - elif sys.platform in ('linux2', 'freebsd6'): + elif sys.platform.startswith('linux') or sys.platform == 'freebsd6': standard_c_lib.__errno_location.restype = ctypes.POINTER(ctypes.c_int) def _where_is_errno(): return standard_c_lib.__errno_location() diff --git a/pypy/rpython/lltypesystem/llarena.py b/pypy/rpython/lltypesystem/llarena.py --- a/pypy/rpython/lltypesystem/llarena.py +++ b/pypy/rpython/lltypesystem/llarena.py @@ -404,7 +404,7 @@ from pypy.rpython.extfunc import register_external from pypy.rlib.objectmodel import CDefinedIntSymbolic -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): # This only works with linux's madvise(), which is really not a memory # usage hint but a real command. It guarantees that after MADV_DONTNEED # the pages are cleared again. diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -585,6 +585,8 @@ 'classof': LLOp(oo=True, canfold=True), 'subclassof': LLOp(oo=True, canfold=True), 'oostring': LLOp(oo=True, sideeffects=False), + 'oobox_int': LLOp(oo=True, sideeffects=False), + 'oounbox_int': LLOp(oo=True, sideeffects=False), 'ooparse_int': LLOp(oo=True, canraise=(ValueError,)), 'ooparse_float': LLOp(oo=True, canraise=(ValueError,)), 'oounicode': LLOp(oo=True, canraise=(UnicodeDecodeError,)), diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -69,6 +69,8 @@ [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) +math_sin = llexternal('sin', [rffi.DOUBLE], rffi.DOUBLE) +math_cos = llexternal('cos', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -340,6 +342,16 @@ raise ValueError("math domain error") return math_log10(x) +def ll_math_sin(x): + if isinf(x): + raise ValueError("math domain error") + return math_sin(x) + +def ll_math_cos(x): + if isinf(x): + raise ValueError("math domain error") + return math_cos(x) + # ____________________________________________________________ # # Default implementations @@ -377,8 +389,8 @@ unary_math_functions = [ 'acos', 'asin', 'atan', - 'ceil', 'cos', 'cosh', 'exp', 'fabs', - 'sin', 'sinh', 'tan', 'tanh', + 'ceil', 'cosh', 'exp', 'fabs', + 'sinh', 'tan', 'tanh', 'acosh', 'asinh', 'atanh', 'log1p', 'expm1', ] unary_math_functions_can_overflow = [ diff --git a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py --- a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py +++ b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py @@ -37,7 +37,7 @@ assert self.interpret(f, [0.3, 0.4]) == f(0.3, 0.4) return next_test - for name in ll_math.unary_math_functions + ['log', 'log10', 'sqrt']: + for name in ll_math.unary_math_functions + ['log', 'log10', 'sin', 'cos', 'sqrt']: func_name = 'test_%s' % (name,) next_test = new_unary_test(name) next_test.func_name = func_name diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -29,7 +29,7 @@ # DICTVALUE value; # int f_hash; # (optional) key hash, if hard to recompute # } -# +# # struct dicttable { # int num_items; # int num_pristine_entries; # never used entries @@ -50,12 +50,12 @@ self.custom_eq_hash = custom_eq_hash is not None if not isinstance(key_repr, rmodel.Repr): # not computed yet, done by setup() assert callable(key_repr) - self._key_repr_computer = key_repr + self._key_repr_computer = key_repr else: self.external_key_repr, self.key_repr = self.pickkeyrepr(key_repr) if not isinstance(value_repr, rmodel.Repr): # not computed yet, done by setup() assert callable(value_repr) - self._value_repr_computer = value_repr + self._value_repr_computer = value_repr else: self.external_value_repr, self.value_repr = self.pickrepr(value_repr) self.dictkey = dictkey @@ -176,7 +176,7 @@ self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY, adtmeths=entrymeths) fields = [ ("num_items", lltype.Signed), - ("num_pristine_entries", lltype.Signed), + ("num_pristine_entries", lltype.Signed), ("entries", lltype.Ptr(self.DICTENTRYARRAY)) ] if self.custom_eq_hash: self.r_rdict_eqfn, self.r_rdict_hashfn = self._custom_eq_hash_repr() @@ -211,7 +211,7 @@ def convert_const(self, dictobj): from pypy.rpython.lltypesystem import llmemory # get object from bound dict methods - #dictobj = getattr(dictobj, '__self__', dictobj) + #dictobj = getattr(dictobj, '__self__', dictobj) if dictobj is None: return lltype.nullptr(self.DICT) if not isinstance(dictobj, (dict, objectmodel.r_dict)): @@ -222,7 +222,7 @@ except KeyError: self.setup() l_dict = ll_newdict_size(self.DICT, len(dictobj)) - self.dict_cache[key] = l_dict + self.dict_cache[key] = l_dict r_key = self.key_repr if r_key.lowleveltype == llmemory.Address: raise TypeError("No prebuilt dicts of address keys") @@ -274,7 +274,7 @@ hop.exception_cannot_occur() v_res = hop.gendirectcall(ll_setdefault, v_dict, v_key, v_default) return self.recast_value(hop.llops, v_res) - + def rtype_method_copy(self, hop): v_dict, = hop.inputargs(self) hop.exception_cannot_occur() @@ -325,7 +325,7 @@ hop.exception_is_here() return hop.gendirectcall(ll_popitem, cTUPLE, v_dict) -class __extend__(pairtype(DictRepr, rmodel.Repr)): +class __extend__(pairtype(DictRepr, rmodel.Repr)): def rtype_getitem((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) @@ -338,7 +338,7 @@ def rtype_delitem((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) if not r_dict.custom_eq_hash: - hop.has_implicit_exception(KeyError) # record that we know about it + hop.has_implicit_exception(KeyError) # record that we know about it hop.exception_is_here() return hop.gendirectcall(ll_dict_delitem, v_dict, v_key) @@ -354,11 +354,11 @@ v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) hop.exception_is_here() return hop.gendirectcall(ll_contains, v_dict, v_key) - + class __extend__(pairtype(DictRepr, DictRepr)): def convert_from_to((r_dict1, r_dict2), v, llops): # check that we don't convert from Dicts with - # different key/value types + # different key/value types if r_dict1.dictkey is None or r_dict2.dictkey is None: return NotImplemented if r_dict1.dictkey is not r_dict2.dictkey: @@ -430,7 +430,7 @@ return hlinvoke(DICT.r_rdict_eqfn, d.fnkeyeq, key1, key2) def ll_dict_len(d): - return d.num_items + return d.num_items def ll_dict_is_true(d): # check if a dict is True, allowing for None @@ -491,8 +491,8 @@ if i & HIGHEST_BIT: raise KeyError _ll_dict_del(d, i) -ll_dict_delitem.oopspec = 'dict.delitem(d, key)' + at jit.dont_look_inside def _ll_dict_del(d, i): d.entries.mark_deleted(i) d.num_items -= 1 @@ -501,9 +501,6 @@ ENTRY = ENTRIES.OF entry = d.entries[i] if ENTRIES.must_clear_key: - key = entry.key # careful about destructor side effects: - # keep key alive until entry.value has also - # been zeroed (if it must be) entry.key = lltype.nullptr(ENTRY.key.TO) if ENTRIES.must_clear_value: entry.value = lltype.nullptr(ENTRY.value.TO) @@ -513,7 +510,7 @@ def ll_dict_resize(d): old_entries = d.entries - old_size = len(old_entries) + old_size = len(old_entries) # make a 'new_size' estimate and shrink it if there are many # deleted entry markers new_size = old_size * 2 @@ -541,7 +538,7 @@ direct_compare = not hasattr(ENTRIES, 'no_direct_compare') mask = len(entries) - 1 i = hash & mask - # do the first try before any looping + # do the first try before any looping if entries.valid(i): checkingkey = entries[i].key if direct_compare and checkingkey == key: @@ -565,8 +562,8 @@ # In the loop, a deleted entry (everused and not valid) is by far # (factor of 100s) the least likely outcome, so test for that last. - perturb = r_uint(hash) - while 1: + perturb = r_uint(hash) + while 1: # compute the next index using unsigned arithmetic i = r_uint(i) i = (i << 2) + i + perturb + 1 @@ -594,7 +591,7 @@ if found: return i # found the entry elif freeslot == -1: - freeslot = i + freeslot = i perturb >>= PERTURB_SHIFT def ll_dict_lookup_clean(d, hash): @@ -604,7 +601,7 @@ entries = d.entries mask = len(entries) - 1 i = hash & mask - perturb = r_uint(hash) + perturb = r_uint(hash) while entries.everused(i): i = r_uint(i) i = (i << 2) + i + perturb + 1 @@ -690,7 +687,6 @@ iter.dict = d iter.index = 0 return iter -ll_dictiter.oopspec = 'newdictiter(d)' def _make_ll_dictnext(kind): # make three versions of the following function: keys, values, items diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py --- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py +++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py @@ -186,7 +186,7 @@ assert not hasattr(sc.contents, 'length') lltype.free(s, flavor='raw') assert not ALLOCATED - + def test_strlen(self): eci = ExternalCompilationInfo(includes=['string.h']) strlen = rffi.llexternal('strlen', [rffi.CCHARP], rffi.SIZE_T, @@ -417,7 +417,7 @@ assert f() == 'z' res = interpret(f, []) assert res == 'z' - + def test_funcptr1(self): def dummy(n): return n+1 @@ -791,9 +791,9 @@ eci = ExternalCompilationInfo( post_include_bits = ["#define fn(x) (42 + x)"], ) - fn1 = rffi.llexternal('fn', [rffi.INT], rffi.INT, + fn1 = rffi.llexternal('fn', [rffi.INT], rffi.INT, compilation_info=eci, macro=True) - fn2 = rffi.llexternal('fn2', [rffi.DOUBLE], rffi.DOUBLE, + fn2 = rffi.llexternal('fn2', [rffi.DOUBLE], rffi.DOUBLE, compilation_info=eci, macro='fn') res = fn1(10) assert res == 52 @@ -804,9 +804,9 @@ header = py.code.Source(""" #ifndef _SOME_H #define _SOME_H - + #include - + static long x = 3; static int y = 5; char **z = NULL; @@ -815,10 +815,10 @@ """) h_file = udir.join("some_h.h") h_file.write(header) - + eci = ExternalCompilationInfo(includes=['stdio.h', str(h_file.basename)], include_dirs=[str(udir)]) - + get_x, set_x = rffi.CExternVariable(rffi.LONG, 'x', eci, c_type='long') get_y, set_y = rffi.CExternVariable(rffi.INT, 'y', eci, c_type='int') get_z, set_z = rffi.CExternVariable(rffi.CCHARPP, 'z', eci) @@ -1074,7 +1074,7 @@ assert not ref0 p1234 = ctypes.c_void_p(1234) - ref1234 = ctypes2lltype(llmemory.GCREF, p1234) + ref1234 = ctypes2lltype(llmemory.GCREF, p1234) assert p1234 def test_gcref_casts(self): @@ -1098,7 +1098,7 @@ ref2 = ctypes2lltype(llmemory.GCREF, intval1) assert lltype.cast_opaque_ptr(lltype.Ptr(NODE), ref2) == node - + #addr = llmemory.cast_ptr_to_adr(ref1) #assert llmemory.cast_adr_to_int(addr) == intval @@ -1147,7 +1147,7 @@ A = lltype.GcArray(lltype.Signed) a = lltype.malloc(A, 20) inside = lltype.direct_ptradd(lltype.direct_arrayitems(a), 3) - + lltype2ctypes(inside) start = rffi.cast(lltype.Signed, lltype.direct_arrayitems(a)) @@ -1162,7 +1162,7 @@ n1 = lltype.malloc(NODE) i1 = rffi.cast(lltype.Signed, n1) - ref1 = rffi.cast(llmemory.GCREF, i1) + ref1 = rffi.cast(llmemory.GCREF, i1) adr1 = llmemory.cast_ptr_to_adr(ref1) assert adr1 != adr0 @@ -1310,7 +1310,7 @@ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.annlowlevel import cast_instance_to_base_ptr from pypy.rpython.lltypesystem import rclass - + class Opaque(object): llopaque = True @@ -1348,7 +1348,7 @@ def test_prefix(self): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("Not supported") from pypy.translator.platform import platform diff --git a/pypy/rpython/memory/gc/env.py b/pypy/rpython/memory/gc/env.py --- a/pypy/rpython/memory/gc/env.py +++ b/pypy/rpython/memory/gc/env.py @@ -55,7 +55,7 @@ # will be huge on 64-bit systems. if sys.maxint == 2147483647: # 32-bit - if sys.platform == 'linux2': + if sys.platform.startswith('linux'): addressable_size = float(2**32) # 4GB elif sys.platform == 'win32': addressable_size = float(2**31) # 2GB @@ -65,7 +65,7 @@ addressable_size = float(2**63) # 64-bit -def get_total_memory_linux2(filename): +def get_total_memory_linux(filename): debug_start("gc-hardware") result = -1.0 try: @@ -93,7 +93,7 @@ result = addressable_size debug_stop("gc-hardware") return result - +get_total_memory_linux2 = get_total_memory_linux3 = get_total_memory_linux def get_total_memory_darwin(result): debug_start("gc-hardware") @@ -108,7 +108,7 @@ return result -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): def get_total_memory(): return get_total_memory_linux2('/proc/meminfo') diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -34,13 +34,6 @@ the GC in very small programs. Defaults to 8 times the nursery. - PYPY_GC_LOSTCARD If between two minor collections we see more than - 'PYPY_GC_LOSTCARD * length' writes to the same array, - then give up card marking and use the fast write - barrier instead. Defaults to 0.3333 for now. - Avoid values lower than 0.125: it is the growth - factor of list.append(). - PYPY_GC_DEBUG Enable extra checks around collections that are too slow for normal use. Values are 0 (off), 1 (on major collections) or 2 (also on minor @@ -56,6 +49,7 @@ from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage from pypy.rpython.memory.gc.base import GCBase, MovingGCBase from pypy.rpython.memory.gc import minimarkpage, env +from pypy.rpython.memory.support import mangle_hash from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask, r_uint from pypy.rlib.rarithmetic import LONG_BIT_SHIFT from pypy.rlib.debug import ll_assert, debug_print, debug_start, debug_stop @@ -205,9 +199,6 @@ # larger. A value of 0 disables card marking. "card_page_indices": 128, - # See PYPY_GC_LOSTCARD. - "lost_card": 1.0 / 3.0, - # Objects whose total size is at least 'large_object' bytes are # allocated out of the nursery immediately, as old objects. The # minimal allocated size of the nursery is 2x the following @@ -224,7 +215,6 @@ major_collection_threshold=2.5, growth_rate_max=2.5, # for tests card_page_indices=0, - lost_card=0.5, large_object=8*WORD, ArenaCollectionClass=None, **kwds): @@ -246,7 +236,6 @@ self.card_page_shift = 0 while (1 << self.card_page_shift) < self.card_page_indices: self.card_page_shift += 1 - self.lost_card = lost_card # # 'large_object' limit how big objects can be in the nursery, so # it gives a lower bound on the allowed size of the nursery. @@ -268,15 +257,18 @@ # (may) contain a pointer to a young object. Populated by # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we # add it to this list. - self.objects_pointing_to_young = self.AddressStack() + # Note that young array objects may (by temporary "mistake") be added + # to this list, but will be removed again at the start of the next + # minor collection. + self.old_objects_pointing_to_young = self.AddressStack() # - # Similar to 'objects_pointing_to_young', but lists objects + # Similar to 'old_objects_pointing_to_young', but lists objects # that have the GCFLAG_CARDS_SET bit. For large arrays. Note # that it is possible for an object to be listed both in here - # and in 'objects_pointing_to_young', in which case we + # and in 'old_objects_pointing_to_young', in which case we # should just clear the cards and trace it fully, as usual. - # Note also that young array objects may be added to this list. - self.objects_with_cards_set = self.AddressStack() + # Note also that young array objects are never listed here. + self.old_objects_with_cards_set = self.AddressStack() # # A list of all prebuilt GC objects that contain pointers to the heap self.prebuilt_root_objects = self.AddressStack() @@ -367,10 +359,6 @@ else: self.max_delta = 0.125 * env.get_total_memory() # - lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD') - if lost_card > 0.0: - self.lost_card = lost_card - # self.minor_collection() # to empty the nursery llarena.arena_free(self.nursery) self.nursery_size = newsize @@ -665,11 +653,15 @@ # else: # Reserve N extra words containing card bits before the object. - extra_words = self.card_marking_words_for_length(length) + 1 + extra_words = self.card_marking_words_for_length(length) cardheadersize = WORD * extra_words extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS - # note that if 'can_make_young', then card marking will only - # be used later, after (and if) the object becomes old + # if 'can_make_young', then we also immediately set + # GCFLAG_CARDS_SET, but without adding the object to + # 'old_objects_with_cards_set'. In this way it should + # never be added to that list as long as it is young. + if can_make_young: + extra_flags |= GCFLAG_CARDS_SET # # Detect very rare cases of overflows if raw_malloc_usage(totalsize) > (sys.maxint - (WORD-1) @@ -691,15 +683,11 @@ raise MemoryError("cannot allocate large object") # # Reserve the card mark bits as a list of single bytes - # followed by a Signed (the loop is empty in C). - if cardheadersize > 0: - i = 0 - while i < cardheadersize - WORD: - llarena.arena_reserve(arena + i, - llmemory.sizeof(lltype.Char)) - i += 1 - llarena.arena_reserve(arena + i, - llmemory.sizeof(lltype.Signed)) + # (the loop is empty in C). + i = 0 + while i < cardheadersize: + llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char)) + i += 1 # # Reserve the actual object. (This is also a no-op in C). result = arena + cardheadersize @@ -923,11 +911,14 @@ length = (obj + offset_to_length).signed[0] extra_words = self.card_marking_words_for_length(length) # + size_gc_header = self.gcheaderbuilder.size_gc_header + p = llarena.getfakearenaaddress(obj - size_gc_header) i = extra_words * WORD while i > 0: + p -= 1 + ll_assert(p.char[0] == '\x00', + "the card marker bits are not cleared") i -= 1 - ll_assert(self.get_card(obj, i).char[0] == '\x00', - "the card marker bits are not cleared") # ---------- # Write barrier @@ -937,6 +928,20 @@ # "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()") JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS + # for the JIT to generate custom code corresponding to the array + # write barrier for the simplest case of cards. If JIT_CARDS_SET + # is already set on an object, it will execute code like this: + # MOV eax, index + # SHR eax, JIT_WB_CARD_PAGE_SHIFT + # XOR eax, -8 + # BTS [object], eax + if TRANSLATION_PARAMS['card_page_indices'] > 0: + JIT_WB_CARDS_SET = GCFLAG_CARDS_SET + JIT_WB_CARD_PAGE_SHIFT = 1 + while ((1 << JIT_WB_CARD_PAGE_SHIFT) != + TRANSLATION_PARAMS['card_page_indices']): + JIT_WB_CARD_PAGE_SHIFT += 1 + @classmethod def JIT_max_size_of_young_obj(cls): return cls.TRANSLATION_PARAMS['large_object'] @@ -978,12 +983,12 @@ # If it seems that what we are writing is a pointer to a young obj # (as checked with appears_to_be_young()), then we need # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object - # to the list 'objects_pointing_to_young'. We know that + # to the list 'old_objects_pointing_to_young'. We know that # 'addr_struct' cannot be in the nursery, because nursery objects # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with. objhdr = self.header(addr_struct) if self.appears_to_be_young(newvalue): - self.objects_pointing_to_young.append(addr_struct) + self.old_objects_pointing_to_young.append(addr_struct) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # # Second part: if 'addr_struct' is actually a prebuilt GC @@ -1018,15 +1023,13 @@ "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") # # no cards, use default logic. Mostly copied from above. - self.objects_pointing_to_young.append(addr_array) + self.old_objects_pointing_to_young.append(addr_array) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS if objhdr.tid & GCFLAG_NO_HEAP_PTRS: objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS self.prebuilt_root_objects.append(addr_array) return # - self.set_cards_flag(addr_array) - # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1044,6 +1047,10 @@ # it seems more important that remember_young_pointer_from_array2() # does not take 3 arguments). addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.old_objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET remember_young_pointer_from_array2._dont_inline_ = True assert self.card_page_indices > 0 @@ -1072,8 +1079,6 @@ if not self.appears_to_be_young(newvalue): return # - self.set_cards_flag(addr_array) - # # 'addr_array' is a raw_malloc'ed array with card markers # in front. Compute the index of the bit to set: bitindex = index >> self.card_page_shift @@ -1086,6 +1091,10 @@ if byte & bitmask: return addr_byte.char[0] = chr(byte | bitmask) + # + if objhdr.tid & GCFLAG_CARDS_SET == 0: + self.old_objects_with_cards_set.append(addr_array) + objhdr.tid |= GCFLAG_CARDS_SET return # # Logic for the no-cards case, put here to minimize the number @@ -1095,7 +1104,7 @@ "young array with no card but GCFLAG_TRACK_YOUNG_PTRS") # if self.appears_to_be_young(newvalue): - self.objects_pointing_to_young.append(addr_array) + self.old_objects_pointing_to_young.append(addr_array) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS remember_young_pointer_from_array3._dont_inline_ = True @@ -1103,36 +1112,11 @@ self.remember_young_pointer_from_array3 = ( remember_young_pointer_from_array3) - def get_card_counter_addr(self, obj): + def get_card(self, obj, byteindex): size_gc_header = self.gcheaderbuilder.size_gc_header addr_byte = obj - size_gc_header - return llarena.getfakearenaaddress(addr_byte) - WORD + return llarena.getfakearenaaddress(addr_byte) + (~byteindex) - def get_card(self, obj, byteindex): - return self.get_card_counter_addr(obj) + (~byteindex) - - def set_cards_flag(self, obj): - hdr = self.header(obj) - if hdr.tid & GCFLAG_CARDS_SET == 0: - # - # first time we set a card bit in this object - self.header(obj).tid |= GCFLAG_CARDS_SET - self.objects_with_cards_set.append(obj) - # - # initialize the counter with the array length and self.lost_card - typeid = self.get_type_id(obj) - offset_to_length = self.varsize_offset_to_length(typeid) - length = (obj + offset_to_length).signed[0] - counter = int(length * self.lost_card) - self.get_card_counter_addr(obj).signed[0] = counter - else: - # decrement the counter and if zero is reached, give up on - # card marking (up to the next collection). - addr = self.get_card_counter_addr(obj) - addr.signed[0] -= 1 - if addr.signed[0] < 0: - self.objects_pointing_to_young.append(obj) - hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS def assume_young_pointers(self, addr_struct): """Called occasionally by the JIT to mean ``assume that 'addr_struct' @@ -1140,7 +1124,7 @@ """ objhdr = self.header(addr_struct) if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS: - self.objects_pointing_to_young.append(addr_struct) + self.old_objects_pointing_to_young.append(addr_struct) objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if objhdr.tid & GCFLAG_NO_HEAP_PTRS: @@ -1184,7 +1168,7 @@ # if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # there might be in source a pointer to a young object - self.objects_pointing_to_young.append(dest_addr) + self.old_objects_pointing_to_young.append(dest_addr) dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS # if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS: @@ -1197,15 +1181,21 @@ # manually copy the individual card marks from source to dest bytes = self.card_marking_bytes_for_length(length) # + anybyte = 0 i = 0 while i < bytes: addr_srcbyte = self.get_card(source_addr, i) addr_dstbyte = self.get_card(dest_addr, i) byte = ord(addr_srcbyte.char[0]) + anybyte |= byte addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte) i += 1 # - self.set_cards_flag(dest_addr) + if anybyte: + dest_hdr = self.header(dest_addr) + if dest_hdr.tid & GCFLAG_CARDS_SET == 0: + self.old_objects_with_cards_set.append(dest_addr) + dest_hdr.tid |= GCFLAG_CARDS_SET # ---------- # Nursery collection @@ -1216,13 +1206,18 @@ # debug_start("gc-minor") # + # Before everything else, remove from 'old_objects_pointing_to_young' + # the young arrays. + if self.young_rawmalloced_objects: + self.remove_young_arrays_from_old_objects_pointing_to_young() + # # First, find the roots that point to young objects. All nursery # objects found are copied out of the nursery, and the occasional # young raw-malloced object is flagged with GCFLAG_VISITED. # Note that during this step, we ignore references to further # young objects; only objects directly referenced by roots # are copied out or flagged. They are also added to the list - # 'objects_pointing_to_young'. + # 'old_objects_pointing_to_young'. self.collect_roots_in_nursery() # while True: @@ -1231,17 +1226,17 @@ if self.card_page_indices > 0: self.collect_cardrefs_to_nursery() # - # Now trace objects from 'objects_pointing_to_young'. + # Now trace objects from 'old_objects_pointing_to_young'. # All nursery objects they reference are copied out of the - # nursery, and again added to 'objects_pointing_to_young'. - # All young raw-malloced object found is flagged GCFLAG_VISITED. - # We proceed until 'objects_pointing_to_young' is empty. + # nursery, and again added to 'old_objects_pointing_to_young'. + # All young raw-malloced object found are flagged GCFLAG_VISITED. + # We proceed until 'old_objects_pointing_to_young' is empty. self.collect_oldrefs_to_nursery() # # We have to loop back if collect_oldrefs_to_nursery caused - # new objects to show up in objects_with_cards_set + # new objects to show up in old_objects_with_cards_set if self.card_page_indices > 0: - if self.objects_with_cards_set.non_empty(): + if self.old_objects_with_cards_set.non_empty(): continue break # @@ -1276,7 +1271,7 @@ # we don't need to trace prebuilt GcStructs during a minor collect: # if a prebuilt GcStruct contains a pointer to a young object, # then the write_barrier must have ensured that the prebuilt - # GcStruct is in the list self.objects_pointing_to_young. + # GcStruct is in the list self.old_objects_pointing_to_young. self.root_walker.walk_roots( MiniMarkGC._trace_drag_out1, # stack roots MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc @@ -1284,7 +1279,7 @@ def collect_cardrefs_to_nursery(self): size_gc_header = self.gcheaderbuilder.size_gc_header - oldlist = self.objects_with_cards_set + oldlist = self.old_objects_with_cards_set while oldlist.non_empty(): obj = oldlist.pop() # @@ -1299,10 +1294,9 @@ length = (obj + offset_to_length).signed[0] bytes = self.card_marking_bytes_for_length(length) p = llarena.getfakearenaaddress(obj - size_gc_header) - p -= WORD # # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it - # means that it is in 'objects_pointing_to_young' and + # means that it is in 'old_objects_pointing_to_young' and # will be fully traced by collect_oldrefs_to_nursery() just # afterwards. if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: @@ -1341,22 +1335,17 @@ def collect_oldrefs_to_nursery(self): - # Follow the objects_pointing_to_young list and move the + # Follow the old_objects_pointing_to_young list and move the # young objects they point to out of the nursery. - oldlist = self.objects_pointing_to_young + oldlist = self.old_objects_pointing_to_young while oldlist.non_empty(): obj = oldlist.pop() # - # Check (somehow) that the flags are correct: we must not have - # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's - # possible that the same obj is appended twice to the list - # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out - # here. - if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0: - ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0, - "objects_pointing_to_young contains obj with " - "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED") - continue + # Check that the flags are correct: we must not have + # GCFLAG_TRACK_YOUNG_PTRS so far. + ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0, + "old_objects_pointing_to_young contains obj with " + "GCFLAG_TRACK_YOUNG_PTRS") # # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should # have this flag set after a nursery collection. @@ -1364,7 +1353,7 @@ # # Trace the 'obj' to replace pointers to nursery with pointers # outside the nursery, possibly forcing nursery objects out - # and adding them to 'objects_pointing_to_young' as well. + # and adding them to 'old_objects_pointing_to_young' as well. self.trace_and_drag_out_of_nursery(obj) def trace_and_drag_out_of_nursery(self, obj): @@ -1400,22 +1389,7 @@ # arrive here. if (bool(self.young_rawmalloced_objects) and self.young_rawmalloced_objects.contains(obj)): - # 'obj' points to a young, raw-malloced object - if (self.header(obj).tid & GCFLAG_VISITED) == 0: - self.header(obj).tid |= GCFLAG_VISITED - # - # we just made 'obj' old, so we may need to add it - # in the correct list: - if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0: - # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so - # the object may contain young pointers anywhere - self.objects_pointing_to_young.append(obj) - else: - # large array case: the object contains card marks - # that tell us where young pointers are, and it - # is already in objects_with_cards_set. - ll_assert(self.header(obj).tid & GCFLAG_HAS_CARDS != 0, - "neither YOUNG_PTRS nor HAS_CARDS??") + self._visit_young_rawmalloced_object(obj) return # # If 'obj' was already forwarded, change it to its forwarding address. @@ -1462,11 +1436,39 @@ # Change the original pointer to this object. root.address[0] = newobj # - # Add the newobj to the list 'objects_pointing_to_young', + # Add the newobj to the list 'old_objects_pointing_to_young', # because it can contain further pointers to other young objects. # We will fix such references to point to the copy of the young - # objects when we walk 'objects_pointing_to_young'. - self.objects_pointing_to_young.append(newobj) + # objects when we walk 'old_objects_pointing_to_young'. + self.old_objects_pointing_to_young.append(newobj) + + def _visit_young_rawmalloced_object(self, obj): + # 'obj' points to a young, raw-malloced object. + # Any young rawmalloced object never seen by the code here + # will end up without GCFLAG_VISITED, and be freed at the + # end of the current minor collection. Note that there was + # a bug in which dying young arrays with card marks would + # still be scanned before being freed, keeping a lot of + # objects unnecessarily alive. + hdr = self.header(obj) + if hdr.tid & GCFLAG_VISITED: + return + hdr.tid |= GCFLAG_VISITED + # + # we just made 'obj' old, so we need to add it to the correct lists + added_somewhere = False + # + if hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: + self.old_objects_pointing_to_young.append(obj) + added_somewhere = True + # + if hdr.tid & GCFLAG_HAS_CARDS != 0: + ll_assert(hdr.tid & GCFLAG_CARDS_SET != 0, + "young array: GCFLAG_HAS_CARDS without GCFLAG_CARDS_SET") + self.old_objects_with_cards_set.append(obj) + added_somewhere = True + # + ll_assert(added_somewhere, "wrong flag combination on young array") def _malloc_out_of_nursery(self, totalsize): @@ -1506,6 +1508,18 @@ # and survives. Otherwise, it dies. self.free_rawmalloced_object_if_unvisited(obj) + def remove_young_arrays_from_old_objects_pointing_to_young(self): + old = self.old_objects_pointing_to_young + new = self.AddressStack() + while old.non_empty(): + obj = old.pop() + if not self.young_rawmalloced_objects.contains(obj): + new.append(obj) + # an extra copy, to avoid assignments to + # 'self.old_objects_pointing_to_young' + while new.non_empty(): + old.append(new.pop()) + new.delete() # ---------- # Full collection @@ -1638,7 +1652,7 @@ "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize") offset_to_length = self.varsize_offset_to_length(typeid) length = (obj + offset_to_length).signed[0] - extra_words = self.card_marking_words_for_length(length) + 1 + extra_words = self.card_marking_words_for_length(length) arena -= extra_words * WORD allocsize += extra_words * WORD # @@ -1780,7 +1794,7 @@ return self.id_or_identityhash(gcobj, False) def identityhash(self, gcobj): - return self.id_or_identityhash(gcobj, True) + return mangle_hash(self.id_or_identityhash(gcobj, True)) # ---------- diff --git a/pypy/rpython/memory/lldict.py b/pypy/rpython/memory/lldict.py --- a/pypy/rpython/memory/lldict.py +++ b/pypy/rpython/memory/lldict.py @@ -1,6 +1,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem import rdict from pypy.rlib.objectmodel import we_are_translated +from pypy.rpython.memory.support import mangle_hash # This is a low-level AddressDict, reusing a lot of the logic from rdict.py. # xxx this is very dependent on the details of rdict.py @@ -40,7 +41,8 @@ lltype.free(entries, flavor="raw") if not we_are_translated(): count_alloc(-1) -_hash = llmemory.cast_adr_to_int +def _hash(adr): + return mangle_hash(llmemory.cast_adr_to_int(adr)) def dict_keyhash(d, key): return _hash(key) diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -4,6 +4,15 @@ from pypy.rlib.debug import ll_assert from pypy.tool.identity_dict import identity_dict + +def mangle_hash(i): + # To hash pointers in dictionaries. Assumes that i shows some + # alignment (to 4, 8, maybe 16 bytes), so we use the following + # formula to avoid the trailing bits being always 0. + return i ^ (i >> 4) + +# ____________________________________________________________ + DEFAULT_CHUNK_SIZE = 1019 diff --git a/pypy/rpython/module/ll_os_stat.py b/pypy/rpython/module/ll_os_stat.py --- a/pypy/rpython/module/ll_os_stat.py +++ b/pypy/rpython/module/ll_os_stat.py @@ -21,7 +21,7 @@ # sub-second timestamps. # - TIMESPEC is defined when the "struct stat" contains st_atim field. -if sys.platform == 'linux2': +if sys.platform.startswith('linux'): TIMESPEC = platform.Struct('struct timespec', [('tv_sec', rffi.TIME_T), ('tv_nsec', rffi.LONG)]) @@ -145,7 +145,7 @@ if sys.platform != 'win32': LL_STAT_FIELDS = STAT_FIELDS[:] - + if TIMESPEC is not None: class CConfig_for_timespec: _compilation_info_ = compilation_info @@ -233,7 +233,7 @@ assert traits.str is str if sys.platform.startswith('linux'): - # because we always use _FILE_OFFSET_BITS 64 - this helps things work that are not a c compiler + # because we always use _FILE_OFFSET_BITS 64 - this helps things work that are not a c compiler _functions = {'stat': 'stat64', 'fstat': 'fstat64', 'lstat': 'lstat64'} diff --git a/pypy/rpython/ootypesystem/ooopimpl.py b/pypy/rpython/ootypesystem/ooopimpl.py --- a/pypy/rpython/ootypesystem/ooopimpl.py +++ b/pypy/rpython/ootypesystem/ooopimpl.py @@ -3,7 +3,6 @@ # ____________________________________________________________ # Implementation of the 'canfold' oo operations - def op_ooupcast(INST, inst): return ootype.ooupcast(INST, inst) op_ooupcast.need_result_type = True diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -1938,6 +1938,17 @@ assert typeOf(obj) is Object return obj._cast_to(EXPECTED_TYPE) +class Box(_object): + def __init__(self, i): + self._TYPE = Object + self.i = i + +def oobox_int(i): + return Box(i) + +def oounbox_int(x): + return x.i + def oostring(obj, base): """ Convert char, int, float, instances and str to str. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -255,7 +255,7 @@ methodname = None return fn, v_obj, methodname -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): from pypy.rlib import jit r_dict = hop.r_result diff --git a/pypy/rpython/test/test_rint.py b/pypy/rpython/test/test_rint.py --- a/pypy/rpython/test/test_rint.py +++ b/pypy/rpython/test/test_rint.py @@ -8,6 +8,9 @@ from pypy.rlib import objectmodel from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem.lloperation import llop class TestSnippet(object): @@ -412,4 +415,8 @@ pass class TestOOtype(BaseTestRint, OORtypeMixin): - pass + def test_oobox_int(self): + def f(): + x = llop.oobox_int(ootype.Object, 42) + return llop.oounbox_int(lltype.Signed, x) + assert self.interpret(f, []) == 42 diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -18,4 +18,5 @@ if __name__ == '__main__': import tool.autopath import pytest - sys.exit(pytest.main()) + import pytest_cov + sys.exit(pytest.main(plugins=[pytest_cov])) diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -30,6 +30,9 @@ def getres(self): return self._getvar(self.res) + def getdescr(self): + return self.descr + def _getvar(self, v): return v @@ -39,7 +42,7 @@ def repr(self): args = self.getargs() if self.descr is not None: - args.append('descr=%s' % self.descr) + args.append('descr=%s' % self.getdescr()) arglist = ', '.join(args) if self.res is not None: return '%s = %s(%s)' % (self.getres(), self.name, arglist) @@ -145,10 +148,10 @@ if operations[0].name == 'debug_merge_point': self.inline_level = int(operations[0].args[0]) m = re.search('\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', - operations[0].getarg(1)) + operations[0].args[1]) if m is None: # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1] + self.bytecode_name = operations[0].args[1][1:-1] else: self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() self.startlineno = int(lineno) diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,6 +1,6 @@ from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, Function, adjust_bridges, - import_log) + import_log, Op) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys @@ -181,7 +181,7 @@ """) ops = Function.from_operations(loop.operations, LoopStorage()) chunk = ops.chunks[0] - assert chunk.bytecode_name == 'StrLiteralSearch' + assert chunk.bytecode_name.startswith('StrLiteralSearch') def test_parsing_assembler(): backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" @@ -225,3 +225,9 @@ assert 'cmp' in loops[1].operations[1].asm # bridge assert 'jo' in loops[3].operations[3].asm + +def test_Op_repr_is_pure(): + op = Op('foobar', ['a', 'b'], 'c', 'mydescr') + myrepr = 'c = foobar(a, b, descr=mydescr)' + assert op.repr() == myrepr + assert op.repr() == myrepr # do it twice diff --git a/pypy/tool/release/win32build.py b/pypy/tool/release/win32build.py --- a/pypy/tool/release/win32build.py +++ b/pypy/tool/release/win32build.py @@ -24,6 +24,6 @@ shutil.copy(str(pypydir.join('..', '..', 'expat-2.0.1', 'win32', 'bin', 'release', 'libexpat.dll')), str(builddir)) make_pypy('', ['-Ojit']) -make_pypy('-nojit', []) +make_pypy('-nojit', ['-O2']) #make_pypy('-stackless', [--stackless]) #make_pypy('-sandbox', [--sandbox]) diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py --- a/pypy/translator/c/gc.py +++ b/pypy/translator/c/gc.py @@ -151,11 +151,11 @@ def OP_GC_CALL_RTTI_DESTRUCTOR(self, funcgen, op): args = [funcgen.expr(v) for v in op.args] line = '%s(%s);' % (args[0], ', '.join(args[1:])) - return line - + return line + def OP_GC_FREE(self, funcgen, op): args = [funcgen.expr(v) for v in op.args] - return 'OP_FREE(%s);' % (args[0], ) + return 'OP_FREE(%s);' % (args[0], ) def OP_GC__COLLECT(self, funcgen, op): return '' @@ -226,7 +226,7 @@ eci = eci.merge(configure_boehm()) pre_include_bits = [] - if sys.platform == "linux2": + if sys.platform.startswith('linux'): pre_include_bits += ["#define _REENTRANT 1", "#define GC_LINUX_THREADS 1"] if sys.platform != "win32": diff --git a/pypy/translator/cli/metavm.py b/pypy/translator/cli/metavm.py --- a/pypy/translator/cli/metavm.py +++ b/pypy/translator/cli/metavm.py @@ -1,6 +1,6 @@ from pypy.translator.cli import oopspec from pypy.rpython.ootypesystem import ootype -from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.oosupport.metavm import Generator, InstructionList, MicroInstruction,\ PushAllArgs, StoreResult, GetField, SetField, DownCast from pypy.translator.oosupport.metavm import _Call as _OOCall @@ -173,6 +173,16 @@ generator.load(v_obj) generator.ilasm.opcode('unbox.any', boxtype) +class _UnboxType(MicroInstruction): + def __init__(self, TO): + self.TO = TO + + def render(self, generator, op): + v_obj, = op.args + boxtype = generator.cts.lltype_to_cts(self.TO) + generator.load(v_obj) + generator.ilasm.opcode('unbox.any', boxtype) + class _NewArray(MicroInstruction): def render(self, generator, op): v_type, v_length = op.args @@ -312,6 +322,7 @@ #CastWeakAdrToPtr = _CastWeakAdrToPtr() Box = _Box() Unbox = _Unbox() +UnboxInt = _UnboxType(lltype.Signed) NewArray = _NewArray() GetArrayElem = _GetArrayElem() SetArrayElem = _SetArrayElem() diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py --- a/pypy/translator/cli/opcodes.py +++ b/pypy/translator/cli/opcodes.py @@ -2,7 +2,7 @@ IndirectCall, GetField, SetField, DownCast, NewCustomDict,\ MapException, Box, Unbox, NewArray, GetArrayElem, SetArrayElem,\ TypeOf, CastPrimitive, EventHandler, GetStaticField, SetStaticField, \ - DebugPrint + DebugPrint, UnboxInt from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult, InstructionList,\ New, RuntimeNew, CastTo, PushPrimitive, OOString, OOUnicode, OONewArray from pypy.translator.cli.cts import WEAKREF @@ -48,6 +48,8 @@ 'cast_from_object': [DownCast], 'clibox': [Box], 'cliunbox': [Unbox], + 'oobox_int': [Box], + 'oounbox_int': [UnboxInt], 'cli_newarray': [NewArray], 'cli_getelem': [GetArrayElem], 'cli_setelem': [SetArrayElem], @@ -92,6 +94,7 @@ 'debug_fatalerror': [PushAllArgs, 'call void [pypylib]pypy.runtime.Debug::DEBUG_FATALERROR(string)'], 'keepalive': Ignore, 'jit_marker': Ignore, + 'jit_force_quasi_immutable':Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, } diff --git a/pypy/translator/cli/test/test_int.py b/pypy/translator/cli/test/test_int.py --- a/pypy/translator/cli/test/test_int.py +++ b/pypy/translator/cli/test/test_int.py @@ -1,8 +1,8 @@ import py from pypy.translator.cli.test.runtest import CliTest -from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test -class TestCliInt(CliTest, BaseTestRint): +class TestCliInt(CliTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -77,6 +77,8 @@ 'oosend': [JvmCallMethod, StoreResult], 'ooupcast': DoNothing, 'oodowncast': [DownCast, StoreResult], + 'oobox_int': jvm.PYPYBOXINT, + 'oounbox_int': jvm.PYPYUNBOXINT, 'cast_to_object': DoNothing, 'cast_from_object': [DownCast, StoreResult], 'instanceof': [CastTo, StoreResult], diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -307,6 +307,14 @@ return result; } + public static Object box_integer(int x) { + return new Integer(x); + } + + public static int unbox_integer(Object o) { + Integer x = (Integer)o; + return x.intValue(); + } // Used in testing the JVM backend: // // A series of methods which serve a similar purpose to repr() in Python: diff --git a/pypy/translator/jvm/test/test_int.py b/pypy/translator/jvm/test/test_int.py --- a/pypy/translator/jvm/test/test_int.py +++ b/pypy/translator/jvm/test/test_int.py @@ -1,10 +1,11 @@ import py from pypy.translator.jvm.test.runtest import JvmTest from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test # ====> ../../../rpython/test/test_rint.py -class TestJvmInt(JvmTest, BaseTestRint): +class TestJvmInt(JvmTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/jvm/typesystem.py b/pypy/translator/jvm/typesystem.py --- a/pypy/translator/jvm/typesystem.py +++ b/pypy/translator/jvm/typesystem.py @@ -963,6 +963,8 @@ PYPYRUNTIMENEW = Method.s(jPyPy, 'RuntimeNew', (jClass,), jObject) PYPYSTRING2BYTES = Method.s(jPyPy, 'string2bytes', (jString,), jByteArray) PYPYARRAYTOLIST = Method.s(jPyPy, 'array_to_list', (jObjectArray,), jArrayList) +PYPYBOXINT = Method.s(jPyPy, 'box_integer', (jInt,), jObject) +PYPYUNBOXINT = Method.s(jPyPy, 'unbox_integer', (jObject,), jInt) PYPYOOPARSEFLOAT = Method.v(jPyPy, 'ooparse_float', (jString,), jDouble) OBJECTGETCLASS = Method.v(jObject, 'getClass', (), jClass) CLASSGETNAME = Method.v(jClass, 'getName', (), jString) diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py --- a/pypy/translator/oosupport/test_template/operations.py +++ b/pypy/translator/oosupport/test_template/operations.py @@ -1,3 +1,6 @@ +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype from pypy.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, ovfcheck from pypy.rlib import rstack from pypy.annotation import model as annmodel diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py --- a/pypy/translator/platform/__init__.py +++ b/pypy/translator/platform/__init__.py @@ -162,7 +162,7 @@ extra = self.shared_only cflags = list(self.cflags) + list(extra) return (cflags + list(eci.compile_extra) + args) - + def preprocess_library_dirs(self, library_dirs): if 'PYPY_LOCALBASE' in os.environ: dirs = list(self._preprocess_library_dirs(library_dirs)) @@ -224,13 +224,13 @@ raise NotImplementedError("Needs to be overwritten") def _library_dirs_for_libffi(self): - raise NotImplementedError("Needs to be overwritten") + raise NotImplementedError("Needs to be overwritten") def check___thread(self): return True - -if sys.platform == 'linux2': + +if sys.platform.startswith('linux'): from pypy.translator.platform.linux import Linux, Linux64 import platform if platform.architecture()[0] == '32bit': diff --git a/pypy/translator/sandbox/sandlib.py b/pypy/translator/sandbox/sandlib.py --- a/pypy/translator/sandbox/sandlib.py +++ b/pypy/translator/sandbox/sandlib.py @@ -209,7 +209,7 @@ def handle_until_return(self): child_stdin = self.popen.stdin child_stdout = self.popen.stdout - if self.os_level_sandboxing and sys.platform.startswith('linux2'): + if self.os_level_sandboxing and sys.platform.startswith('linux'): # rationale: we wait until the child process started completely, # letting the C library do any system calls it wants for # initialization. When the RPython code starts up, it quickly @@ -329,7 +329,7 @@ self._input.isatty()): # don't wait for all 'size' chars if reading from a tty, # to avoid blocking. Instead, stop after reading a line. - + # For now, waiting at the interactive console is the # only time that counts as idle. self.enter_idle() @@ -496,7 +496,7 @@ def __init__(self, *args, **kwds): super(VirtualizedSocketProc, self).__init__(*args, **kwds) self.sockets = {} - + def do_ll_os__ll_os_open(self, name, flags, mode): if not name.startswith("tcp://"): return super(VirtualizedSocketProc, self).do_ll_os__ll_os_open( @@ -520,4 +520,4 @@ return self.open_fds[fd].send(data) return super(VirtualizedSocketProc, self).do_ll_os__ll_os_write( fd, data) - + diff --git a/pypy/translator/sandbox/test/test_sandbox.py b/pypy/translator/sandbox/test/test_sandbox.py --- a/pypy/translator/sandbox/test/test_sandbox.py +++ b/pypy/translator/sandbox/test/test_sandbox.py @@ -145,7 +145,7 @@ g = pipe.stdin f = pipe.stdout expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GENERATIONGC_NURSERY",), None) - if sys.platform == 'linux2': # on Mac, uses another (sandboxsafe) approach + if sys.platform.startswith('linux'): # on Mac, uses another (sandboxsafe) approach expect(f, g, "ll_os.ll_os_open", ("/proc/cpuinfo", 0, 420), OSError(5232, "xyz")) expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GC_DEBUG",), None) @@ -158,7 +158,7 @@ def test_safe_alloc(): from pypy.rlib.rmmap import alloc, free - + def entry_point(argv): one = alloc(1024) free(one, 1024) @@ -180,7 +180,7 @@ py.test.skip("Since this stuff is unimplemented, it won't work anyway " "however, the day it starts working, it should pass test") from pypy.rlib.rmmap import mmap - + def entry_point(argv): try: res = mmap(0, 1024) diff --git a/pytest.py b/pytest.py --- a/pytest.py +++ b/pytest.py @@ -9,6 +9,8 @@ from _pytest import __version__ if __name__ == '__main__': # if run as a script or by 'python -m pytest' - raise SystemExit(main()) + #XXX: sync to upstream later + import pytest_cov + raise SystemExit(main(plugins=[pytest_cov])) else: _preloadplugins() # to populate pytest.* namespace so help(pytest) works diff --git a/pytest_cov.py b/pytest_cov.py new file mode 100644 --- /dev/null +++ b/pytest_cov.py @@ -0,0 +1,353 @@ +"""produce code coverage reports using the 'coverage' package, including support for distributed testing. + +This plugin produces coverage reports. It supports centralised testing and distributed testing in +both load and each modes. It also supports coverage of subprocesses. + +All features offered by the coverage package should be available, either through pytest-cov or +through coverage's config file. + + +Installation +------------ + +The `pytest-cov`_ package may be installed with pip or easy_install:: + + pip install pytest-cov + easy_install pytest-cov + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov/ + + +Uninstallation +-------------- + +Uninstalling packages is supported by pip:: + + pip uninstall pytest-cov + +However easy_install does not provide an uninstall facility. + +.. IMPORTANT:: + + Ensure that you manually delete the init_cov_core.pth file in your site-packages directory. + + This file starts coverage collection of subprocesses if appropriate during site initialisation + at python startup. + + +Usage +----- + +Centralised Testing +~~~~~~~~~~~~~~~~~~~ + +Centralised testing will report on the combined coverage of the main process and all of it's +subprocesses. + +Running centralised testing:: + + py.test --cov myproj tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Load +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to load will report on the combined coverage of all slaves. +The slaves may be spread out over any number of hosts and each slave may be located anywhere on the +file system. Each slave will have it's subprocesses measured. + +Running distributed testing with dist mode set to load:: + + py.test --cov myproj -n 2 tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Again but spread over different hosts and different directories:: + + py.test --cov myproj --dist load + --tx ssh=memedough at host1//chdir=testenv1 + --tx ssh=memedough at host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Distributed Testing: Each +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Distributed testing with dist mode set to each will report on the combined coverage of all slaves. +Since each slave is running all tests this allows generating a combined coverage report for multiple +environments. + +Running distributed testing with dist mode set to each:: + + py.test --cov myproj --dist each + --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python + --tx ssh=memedough at host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python + --rsyncdir myproj --rsyncdir tests --rsync examples + tests/ + +Shows a terminal report:: + + ---------------------------------------- coverage ---------------------------------------- + platform linux2, python 2.6.5-final-0 + platform linux2, python 2.7.0-final-0 + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +Reporting +--------- + +It is possible to generate any combination of the reports for a single test run. + +The available reports are terminal (with or without missing line numbers shown), HTML, XML and +annotated source code. + +The terminal report without line numbers (default):: + + py.test --cov-report term --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover + ---------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% + myproj/feature4286 94 7 92% + ---------------------------------------- + TOTAL 353 20 94% + + +The terminal report with line numbers:: + + py.test --cov-report term-missing --cov myproj tests/ + + -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- + Name Stmts Miss Cover Missing + -------------------------------------------------- + myproj/__init__ 2 0 100% + myproj/myproj 257 13 94% 24-26, 99, 149, 233-236, 297-298, 369-370 + myproj/feature4286 94 7 92% 183-188, 197 + -------------------------------------------------- + TOTAL 353 20 94% + + +The remaining three reports output to files without showing anything on the terminal (useful for +when the output is going to a continuous integration server):: + + py.test --cov-report html + --cov-report xml + --cov-report annotate + --cov myproj tests/ + + +Coverage Data File +------------------ + +The data file is erased at the beginning of testing to ensure clean data for each test run. + +The data file is left at the end of testing so that it is possible to use normal coverage tools to +examine it. + + +Coverage Config File +-------------------- + +This plugin provides a clean minimal set of command line options that are added to pytest. For +further control of coverage use a coverage config file. + +For example if tests are contained within the directory tree being measured the tests may be +excluded if desired by using a .coveragerc file with the omit option set:: + + py.test --cov-config .coveragerc + --cov myproj + myproj/tests/ + +Where the .coveragerc file contains file globs:: + + [run] + omit = tests/* + +For full details refer to the `coverage config file`_ documentation. + +.. _`coverage config file`: http://nedbatchelder.com/code/coverage/config.html + +Note that this plugin controls some options and setting the option in the config file will have no +effect. These include specifying source to be measured (source option) and all data file handling +(data_file and parallel options). + + +Limitations +----------- + +For distributed testing the slaves must have the pytest-cov package installed. This is needed since +the plugin must be registered through setuptools / distribute for pytest to start the plugin on the +slave. + +For subprocess measurement environment variables must make it from the main process to the +subprocess. The python used by the subprocess must have pytest-cov installed. The subprocess must +do normal site initialisation so that the environment variables can be detected and coverage +started. + + +Acknowledgements +---------------- + +Whilst this plugin has been built fresh from the ground up it has been influenced by the work done +on pytest-coverage (Ross Lawley, James Mills, Holger Krekel) and nose-cover (Jason Pellerin) which are +other coverage plugins. + +Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs. + +Holger Krekel for pytest with its distributed testing support. + +Jason Pellerin for nose. + +Michael Foord for unittest2. + +No doubt others have contributed to these tools as well. +""" + + +def pytest_addoption(parser): + """Add options to control coverage.""" + + group = parser.getgroup('coverage reporting with distributed testing support') + group.addoption('--cov', action='append', default=[], metavar='path', + dest='cov_source', + help='measure coverage for filesystem path (multi-allowed)') + group.addoption('--cov-report', action='append', default=[], metavar='type', + choices=['term', 'term-missing', 'annotate', 'html', 'xml'], + dest='cov_report', + help='type of report to generate: term, term-missing, annotate, html, xml (multi-allowed)') + group.addoption('--cov-config', action='store', default='.coveragerc', metavar='path', + dest='cov_config', + help='config file for coverage, default: .coveragerc') + + +def pytest_configure(config): + """Activate coverage plugin if appropriate.""" + + if config.getvalue('cov_source'): + config.pluginmanager.register(CovPlugin(), '_cov') + + +class CovPlugin(object): + """Use coverage package to produce code coverage reports. + + Delegates all work to a particular implementation based on whether + this test process is centralised, a distributed master or a + distributed slave. + """ + + def __init__(self): + """Creates a coverage pytest plugin. + + We read the rc file that coverage uses to get the data file + name. This is needed since we give coverage through it's API + the data file name. + """ + + # Our implementation is unknown at this time. + self.cov_controller = None + + def pytest_sessionstart(self, session): + """At session start determine our implementation and delegate to it.""" + + import cov_core + + cov_source = session.config.getvalue('cov_source') + cov_report = session.config.getvalue('cov_report') or ['term'] + cov_config = session.config.getvalue('cov_config') + + session_name = session.__class__.__name__ + is_master = (session.config.pluginmanager.hasplugin('dsession') or + session_name == 'DSession') + is_slave = (hasattr(session.config, 'slaveinput') or + session_name == 'SlaveSession') + nodeid = None + + if is_master: + controller_cls = cov_core.DistMaster + elif is_slave: + controller_cls = cov_core.DistSlave + nodeid = session.config.slaveinput.get('slaveid', getattr(session, 'nodeid')) + else: + controller_cls = cov_core.Central + + self.cov_controller = controller_cls(cov_source, + cov_report, + cov_config, + session.config, + nodeid) + + self.cov_controller.start() + + def pytest_configure_node(self, node): + """Delegate to our implementation.""" + + self.cov_controller.configure_node(node) + pytest_configure_node.optionalhook = True + + def pytest_testnodedown(self, node, error): + """Delegate to our implementation.""" + + self.cov_controller.testnodedown(node, error) + pytest_testnodedown.optionalhook = True + + def pytest_sessionfinish(self, session, exitstatus): + """Delegate to our implementation.""" + + self.cov_controller.finish() + + def pytest_terminal_summary(self, terminalreporter): + """Delegate to our implementation.""" + + self.cov_controller.summary(terminalreporter._tw) + + +def pytest_funcarg__cov(request): + """A pytest funcarg that provides access to the underlying coverage object.""" + + # Check with hasplugin to avoid getplugin exception in older pytest. + if request.config.pluginmanager.hasplugin('_cov'): + plugin = request.config.pluginmanager.getplugin('_cov') + if plugin.cov_controller: + return plugin.cov_controller.cov + return None From noreply at buildbot.pypy.org Tue Jul 26 13:07:19 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 26 Jul 2011 13:07:19 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Waaa. Intermediate check-in (untested) of this scary code. Message-ID: <20110726110719.AA90D823B2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r45999:f3d3bf4acb0c Date: 2011-07-26 11:01 +0200 http://bitbucket.org/pypy/pypy/changeset/f3d3bf4acb0c/ Log: Waaa. Intermediate check-in (untested) of this scary code. diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -31,7 +31,8 @@ BoolOption("tealet", "enable stackless features via tealets", default=False, cmdline="--tealet", requires=[("translation.type_system", "lltype"), - ("translation.gctransformer", "framework")]), + ("translation.gctransformer", "framework"), + ("translation.gcrootfinder", "asmgcc")]), #XXX for now ChoiceOption("type_system", "Type system to use when RTyping", ["lltype", "ootype"], cmdline=None, default="lltype", requires={ diff --git a/pypy/rlib/_tealet_rffi.py b/pypy/rlib/_tealet_rffi.py --- a/pypy/rlib/_tealet_rffi.py +++ b/pypy/rlib/_tealet_rffi.py @@ -24,3 +24,7 @@ rffi.VOIDP], rffi.INT) tealet_switch = llexternal("tealet_switch", [TEALET_P], rffi.INT) tealet_current = llexternal("tealet_current", [TEALET_P], TEALET_P) + +_tealet_translate_pointer = llexternal("_tealet_translate_pointer", + [TEALET_P, llmemory.Address], + llmemory.Address) diff --git a/pypy/rlib/rtealet.py b/pypy/rlib/rtealet.py --- a/pypy/rlib/rtealet.py +++ b/pypy/rlib/rtealet.py @@ -22,8 +22,7 @@ class Tealet(base_class): lltealet = _tealet_rffi.NULL_TEALET - _gc_gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) - _gc_signed_array = lltype.nullptr(SIGNED_ARRAY.TO) + _suspended_stack = NULL_SUSPSTACK def switch(self): _switch(self) @@ -61,22 +60,22 @@ exception = None switcher = Switcher() +llswitcher = lltype.malloc(rffi.CArray(_tealet_rffi.TEALET_P), 1, + flavor='raw', zero=True) + def _new(main, starting_tealet): switcher.current = main.current switcher.target = starting_tealet - llmain = main.lltealet + llswitcher[0] = main.lltealet + r = _stack_protected_call(llhelper(FUNCNOARG, _new_critical)) + _check_exception(r) + +def _new_critical(): + # critical function: no gc operation, and no gc variable alive! + llmain = llswitcher[0] llrun = llhelper(_tealet_rffi.TEALET_RUN_P, _run) llarg = _tealet_rffi.NULL - r = _new_critical(llmain, llrun, llarg) - _check_exception(r) - -def _new_critical(llmain, llrun, llarg): - # critical function: no gc operation, and no gc variable alive! - _save_shadow_stack() - r = _tealet_rffi.tealet_new(llmain, llrun, llarg) - _restore_shadow_stack() - return r -_new_critical._dont_inline_ = True + return _tealet_rffi.tealet_new(llmain, llrun, llarg) def _run(lltealet, llarg): llop.gc_stack_bottom(lltype.Void) @@ -110,20 +109,18 @@ switcher.current = main.current switcher.target = target main.current = target - r = _switch_critical(target.lltealet) + llswitcher[0] = target.lltealet + r = _stack_protected_call(llhelper(FUNCNOARG, _switch_critical)) + _check_exception(r) + +def _switch_critical(): + # critical code: no gc operation! + lltarget = llswitcher[0] + return _tealet_rffi.tealet_switch(lltarget) + +def _check_exception(r): switcher.current = None switcher.target = None - _check_exception(r) - -def _switch_critical(lltarget): - # critical code: no gc operation! - _save_shadow_stack() - r = _tealet_rffi.tealet_switch(lltarget) - _restore_shadow_stack() - return r -_switch_critical._dont_inline_ = True - -def _check_exception(r): r = rffi.cast(lltype.Signed, r) if r != 0: # rare case: tealet.c complains, e.g. out of memory. I think that @@ -138,36 +135,177 @@ # ____________________________________________________________ # -# Shadow stack saving/restoring. +# AsmGcRoot stack walking. +# XXX rethink the interfacing with asmgcroot.py +# +# This is a copy of the logic in asmgcroot.py, rewritten so that all +# pointer reads from the stack go via _tealet_translate_pointer() +# and also rewritten in an iterator-like style, with a next() method +# that just returns the next stack pointer. +# XXX avoid copying so much of the logic of asmgcroot -GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF)) -SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed)) -WALKER_PTR = lltype.Ptr(lltype.Struct('walker', - ('gcptr_array', GCPTR_ARRAY), - ('signed_array', SIGNED_ARRAY))) -walker = lltype.malloc(WALKER_PTR.TO, immortal=True) +_asmstackrootwalker = None # BIG HACK: monkey-patched by asmgcroot.py +_tealetrootwalker = None -def _save_shadow_stack(): - llop.gc_save_stack_roots(lltype.Void, walker) - tealet = switcher.current - ll_assert(not tealet._gc_gcptr_array, "tealet stack mismatch (save)") - tealet._gc_gcptr_array = walker.gcptr_array - tealet._gc_signed_array = walker.signed_array - walker.gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) - walker.signed_array = lltype.nullptr(SIGNED_ARRAY.TO) -_save_shadow_stack._dont_inline_ = True +def get_tealetrootwalker(): + # lazily called, to make the following imports lazy + global _tealetrootwalker + if _tealetrootwalker is not None: + return _tealetrootwalker -def _restore_shadow_stack(): - tealet = switcher.target - ll_assert(bool(tealet._gc_gcptr_array), "tealet stack mismatch (restore)") - walker.gcptr_array = tealet._gc_gcptr_array - walker.signed_array = tealet._gc_signed_array - tealet._gc_gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) - tealet._gc_signed_array = lltype.nullptr(SIGNED_ARRAY.TO) - llop.gc_restore_stack_roots(lltype.Void, walker) - walker.gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO) - walker.signed_array = lltype.nullptr(SIGNED_ARRAY.TO) -_restore_shadow_stack._dont_inline_ = True + from pypy.rpython.memory.gctransform.asmgcroot import ( + WALKFRAME, CALLEE_SAVED_REGS) + + assert _asmstackrootwalker is not None, "should have been monkey-patched" + basewalker = _asmstackrootwalker + + class TealetRootWalker(object): + _alloc_flavor_ = "raw" + + enumerating = False + + def setup(self, obj): + # initialization: read the SUSPSTACK object + p = llmemory.cast_adr_to_ptr(obj, lltype.Ptr(SUSPSTACK)) + if not p.context: + return False + self.context = p.context + initialframedata = p.initialframedata + del p + self.curframe = lltype.malloc(WALKFRAME, flavor='raw') + self.otherframe = lltype.malloc(WALKFRAME, flavor='raw') + basewalker.fill_initial_frame(self.curframe, self.initialframedata) + return True + + def teardown(self): + lltype.free(self.curframe, flavor='raw') + lltype.free(self.otherframe, flavor='raw') + self.context = _tealet_rffi.NULL_TEALET + return llmemory.NULL + + def next(self, obj, prev): + # + # Pointers to the stack can be "translated" or not: + # + # * Non-translated pointers point to where the data would be + # if the stack was installed and running. + # + # * Translated pointers correspond to where the data + # is now really in memory. + # + # Note that 'curframe' contains non-translated pointers, and + # of course the stack itself is full of non-translated pointers. + # + while True: + callee = self.curframe + # + if not self.enumerating: + if not prev: + if not self.setup(obj): # one-time initialization + return llmemory.NULL + prev = obj # random value, but non-NULL + retaddraddr = self.translateptr(callee.frame_address) + retaddr = retaddraddr.address[0] + basewalker.locate_caller_based_on_retaddr(retaddr) + self.enumerating = True + # + # not really a loop, but kept this way for similarity + # with asmgcroot: + while True: + location = basewalker._shape_decompressor.next() + if location == 0: + break + addr = basewalker.getlocation(callee, location) + # yield the translated addr of the next GCREF in the stack + return self.translateptr(addr) + # + self.enumerating = False + caller = self.otherframe + reg = CALLEE_SAVED_REGS - 1 + while reg >= 0: + location = basewalker._shape_decompressor.next() + addr = basewalker.getlocation(callee, location) + caller.regs_stored_at[reg] = addr # non-translated + reg -= 1 + + location = basewalker._shape_decompressor.next() + caller.frame_address = basewalker.getlocation(callee, location) + # ^^^ non-translated + if caller.frame_address == llmemory.NULL: + return self.teardown() # completely done with this stack + # + self.otherframe = callee + self.curframe = caller + # loop back + + def translateptr(self, addr): + return _tealet_rffi._tealet_translate_pointer(self.context, addr) + + _tealetrootwalker = TealetRootWalker() + return _tealetrootwalker +get_tealetrootwalker._annspecialcase_ = 'specialize:memo' + + +def customtrace(obj, prev): + tealetrootwalker = get_tealetrootwalker() + return tealetrootwalker.next(obj, prev) + +ASM_FRAMEDATA_HEAD_PTR = lltype.Ptr(lltype.FixedSizeArray(llmemory.Address, 2)) +SUSPSTACK = lltype.GcStruct('SuspStack', + ('context', _tealet_rffi.TEALET_P), + ('anchor', ASM_FRAMEDATA_HEAD_PTR), + ('my_index', lltype.Signed), + ('next_unused', lltype.Signed), + rtti=True) +CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], + llmemory.Address) +customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) +lltype.attachRuntimeTypeInfo(SUSPSTACK, customtraceptr=customtraceptr) +NULL_SUSPSTACK = lltype.Ptr(SUSPSTACK) + + +class SuspendedStacks: + + def __init__(self): + self.lst = [] + self.first_unused = -1 + + def acquire(self): + if self.first_unused == -1: + p = lltype.malloc(SUSPSTACK) + p.context = _tealet_rffi.NULL_TEALET + p.my_index = len(self.lst) + self.lst.append(p) + else: + p = self.lst[self.first_unused] + self.first_unused = p.next_unused + return p + + def release(self, p): + p.next_unused = self.first_unused + self.first_unused = p.my_index + +suspendedstacks = SuspendedStacks() + +def _stack_protected_call(callback): + # :-/ + p = suspendedstacks.acquire() + suspendedstacks.callback = callback + anchor = lltype.malloc(ASM_FRAMEDATA_HEAD_PTR.TO, flavor='raw') + anchor[0] = anchor[1] = llmemory.cast_ptr_to_adr(anchor) + p.anchor = anchor + r = pypy_asm_stackwalk2(callback, anchor) + suspendedstacks.release(p) + lltype.free(anchor, flavor='raw') + return r + +FUNCNOARG = lltype.FuncType([], rffi.INT) + +pypy_asm_stackwalk2 = rffi.llexternal('pypy_asm_stackwalk', + [lltype.Ptr(FUNCNOARG), + ASM_FRAMEDATA_HEAD_PTR], + rffi.INT, sandboxsafe=True, + _nowrapper=True) # ____________________________________________________________ diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py --- a/pypy/rpython/memory/gctransform/asmgcroot.py +++ b/pypy/rpython/memory/gctransform/asmgcroot.py @@ -149,52 +149,9 @@ self._extra_mark_sorted = lambda: True def need_tealet_support(self, gctransformer, getfn): - # tealet support: hooks to save and restore the GC pointers - # from the stack before it is whisked away by "tealet.c". - GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF)) - SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed)) - WALKER_PTR = lltype.Ptr(lltype.Struct('walker', - ('gcptr_array', GCPTR_ARRAY), - ('signed_array', SIGNED_ARRAY))) - gcdata = self.gcdata - # - def ll_count_locations(gc, addr): - gcdata._gc_tealet_count += 1 - # - def ll_save_locations(gc, addr): - gcref = llmemory.cast_adr_to_ptr(addr.address[0], llmemory.GCREF) - gcdata._gc_tealet_array[gcdata._gc_tealet_count] = gcref - gcdata._gc_tealet_count += 1 - # - def ll_restore_locations(gc, addr): - gcref = gcdata._gc_tealet_array[gcdata._gc_tealet_count] - gcdata._gc_tealet_count += 1 - addr.address[0] = llmemory.cast_ptr_to_adr(gcref) - # - def ll_save_stack_roots(walker): - gcdata._gc_tealet_count = 0 - self.walk_stack_roots(ll_count_locations) - count = gcdata._gc_tealet_count - gcdata._gc_tealet_count = 0 - gcdata._gc_tealet_array = lltype.malloc(GCPTR_ARRAY.TO, count) - self.walk_stack_roots(ll_save_locations) - walker.gcptr_array = gcdata._gc_tealet_array - gcdata._gc_tealet_array = lltype.nullptr(GCPTR_ARRAY.TO) - # - def ll_restore_stack_roots(walker): - gcdata._gc_tealet_array = walker.gcptr_array - gcdata._gc_tealet_count = 0 - self.walk_stack_roots(ll_restore_locations) - gcdata._gc_tealet_array = lltype.nullptr(GCPTR_ARRAY.TO) - # - self.ll_save_stack_roots_ptr = getfn(ll_save_stack_roots, - [annmodel.SomePtr(WALKER_PTR)], - annmodel.s_None, - minimal_transform=False) - self.ll_restore_stack_roots_ptr = getfn(ll_restore_stack_roots, - [annmodel.SomePtr(WALKER_PTR)], - annmodel.s_None, - minimal_transform=False) + # tealet support: BIG HACK for rlib.rtealet + from pypy.rlib import rtealet + rtealet._asmstackrootwalker = self # as a global! argh def need_thread_support(self, gctransformer, getfn): # Threads supported "out of the box" by the rest of the code. diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1593,31 +1593,20 @@ { __asm { mov\tedx, DWORD PTR [esp+4]\t; 1st argument, which is the callback - mov\tecx, DWORD PTR [esp+8]\t; 2nd argument, which is gcrootanchor mov\teax, esp\t\t; my frame top address push\teax\t\t\t; ASM_FRAMEDATA[6] push\tebp\t\t\t; ASM_FRAMEDATA[5] push\tedi\t\t\t; ASM_FRAMEDATA[4] push\tesi\t\t\t; ASM_FRAMEDATA[3] push\tebx\t\t\t; ASM_FRAMEDATA[2] - - ; Add this ASM_FRAMEDATA to the front of the circular linked - ; list. Let's call it 'self'. - - mov\teax, DWORD PTR [ecx+4]\t\t; next = gcrootanchor->next - push\teax\t\t\t\t\t\t\t\t\t; self->next = next - push\tecx ; self->prev = gcrootanchor - mov\tDWORD PTR [ecx+4], esp\t\t; gcrootanchor->next = self - mov\tDWORD PTR [eax+0], esp\t\t\t\t\t; next->prev = self + xor\teax, eax + push\teax\t\t\t; ASM_FRAMEDATA[1] + push\teax\t\t\t; ASM_FRAMEDATA[0] call\tedx\t\t\t\t\t\t; invoke the callback - ; Detach this ASM_FRAMEDATA from the circular linked list - pop\tesi\t\t\t\t\t\t\t; prev = self->prev - pop\tedi\t\t\t\t\t\t\t; next = self->next - mov\tDWORD PTR [esi+4], edi\t\t; prev->next = next - mov\tDWORD PTR [edi+0], esi\t\t; next->prev = prev - + pop\tecx\t\t\t\t; ignored ASM_FRAMEDATA[0] + pop\tecx\t\t\t\t; ignored ASM_FRAMEDATA[1] pop\tebx\t\t\t\t; restore from ASM_FRAMEDATA[2] pop\tesi\t\t\t\t; restore from ASM_FRAMEDATA[3] pop\tedi\t\t\t\t; restore from ASM_FRAMEDATA[4] @@ -1640,7 +1629,6 @@ /* See description in asmgcroot.py */ .cfi_startproc /* %rdi is the 1st argument, which is the callback */ - /* %rsi is the 2nd argument, which is gcrootanchor */ movq\t%rsp, %rax\t/* my frame top address */ pushq\t%rax\t\t/* ASM_FRAMEDATA[8] */ pushq\t%rbp\t\t/* ASM_FRAMEDATA[7] */ @@ -1649,26 +1637,17 @@ pushq\t%r13\t\t/* ASM_FRAMEDATA[4] */ pushq\t%r12\t\t/* ASM_FRAMEDATA[3] */ pushq\t%rbx\t\t/* ASM_FRAMEDATA[2] */ + xorq\t%rax,%rax + pushq\t%rax\t\t/* ASM_FRAMEDATA[1] */ + pushq\t%rax\t\t/* ASM_FRAMEDATA[0] */ - /* Add this ASM_FRAMEDATA to the front of the circular linked */ - /* list. Let's call it 'self'. */ - - movq\t8(%rsi), %rax\t/* next = gcrootanchor->next */ - pushq\t%rax\t\t\t\t/* self->next = next */ - pushq\t%rsi\t\t\t/* self->prev = gcrootanchor */ - movq\t%rsp, 8(%rsi)\t/* gcrootanchor->next = self */ - movq\t%rsp, 0(%rax)\t\t\t/* next->prev = self */ .cfi_def_cfa_offset 80\t/* 9 pushes + the retaddr = 80 bytes */ /* note: the Mac OS X 16 bytes aligment must be respected. */ call\t*%rdi\t\t/* invoke the callback */ - /* Detach this ASM_FRAMEDATA from the circular linked list */ - popq\t%rsi\t\t/* prev = self->prev */ - popq\t%rdi\t\t/* next = self->next */ - movq\t%rdi, 8(%rsi)\t/* prev->next = next */ - movq\t%rsi, 0(%rdi)\t/* next->prev = prev */ - + popq\t%rcx\t\t/* ignored ASM_FRAMEDATA[0] */ + popq\t%rcx\t\t/* ignored ASM_FRAMEDATA[1] */ popq\t%rbx\t\t/* restore from ASM_FRAMEDATA[2] */ popq\t%r12\t\t/* restore from ASM_FRAMEDATA[3] */ popq\t%r13\t\t/* restore from ASM_FRAMEDATA[4] */ @@ -1701,32 +1680,21 @@ print >> output, """\ /* See description in asmgcroot.py */ movl\t4(%esp), %edx\t/* 1st argument, which is the callback */ - movl\t8(%esp), %ecx\t/* 2nd argument, which is gcrootanchor */ movl\t%esp, %eax\t/* my frame top address */ pushl\t%eax\t\t/* ASM_FRAMEDATA[6] */ pushl\t%ebp\t\t/* ASM_FRAMEDATA[5] */ pushl\t%edi\t\t/* ASM_FRAMEDATA[4] */ pushl\t%esi\t\t/* ASM_FRAMEDATA[3] */ pushl\t%ebx\t\t/* ASM_FRAMEDATA[2] */ - - /* Add this ASM_FRAMEDATA to the front of the circular linked */ - /* list. Let's call it 'self'. */ - - movl\t4(%ecx), %eax\t/* next = gcrootanchor->next */ - pushl\t%eax\t\t\t\t/* self->next = next */ - pushl\t%ecx\t\t\t/* self->prev = gcrootanchor */ - movl\t%esp, 4(%ecx)\t/* gcrootanchor->next = self */ - movl\t%esp, 0(%eax)\t\t\t/* next->prev = self */ + xorl\t%eax,%eax + pushl\t%eax\t\t/* ASM_FRAMEDATA[1] */ + pushl\t%eax\t\t/* ASM_FRAMEDATA[0] */ /* note: the Mac OS X 16 bytes aligment must be respected. */ call\t*%edx\t\t/* invoke the callback */ - /* Detach this ASM_FRAMEDATA from the circular linked list */ - popl\t%esi\t\t/* prev = self->prev */ - popl\t%edi\t\t/* next = self->next */ - movl\t%edi, 4(%esi)\t/* prev->next = next */ - movl\t%esi, 0(%edi)\t/* next->prev = prev */ - + popl\t%ecx\t\t/* ignored ASM_FRAMEDATA[0] */ + popl\t%ecx\t\t/* ignored ASM_FRAMEDATA[1] */ popl\t%ebx\t\t/* restore from ASM_FRAMEDATA[2] */ popl\t%esi\t\t/* restore from ASM_FRAMEDATA[3] */ popl\t%edi\t\t/* restore from ASM_FRAMEDATA[4] */ diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h --- a/pypy/translator/c/src/mem.h +++ b/pypy/translator/c/src/mem.h @@ -6,7 +6,7 @@ extern char __gcmapstart; extern char __gcmapend; extern char __gccallshapes; -extern long pypy_asm_stackwalk(void*, void*); +extern long pypy_asm_stackwalk(void*); #define __gcnoreorderhack __gcmapend /* The following pseudo-instruction is used by --gcrootfinder=asmgcc @@ -52,7 +52,7 @@ extern void* __gcmapstart; extern void* __gcmapend; extern char* __gccallshapes; -extern long pypy_asm_stackwalk(void*, void*); +extern long pypy_asm_stackwalk(void*); /* With the msvc Microsoft Compiler, the optimizer seems free to move any code (even asm) that involves local memory (registers and stack). diff --git a/pypy/translator/c/src/tealet/tealet.c b/pypy/translator/c/src/tealet/tealet.c --- a/pypy/translator/c/src/tealet/tealet.c +++ b/pypy/translator/c/src/tealet/tealet.c @@ -598,3 +598,21 @@ stack_free(g_main, g_target->stack_copy); g_free(g_main, g_target); } + +#if STACK_DIRECTION != 0 +# error "fix _tealet_translate_pointer below" +#endif +char **_tealet_translate_pointer(tealet_t *context, char **ptr) +{ + tealet_sub_t *g_tealet = (tealet_sub_t *)context; + /* if g_tealet is not suspended, then stack_start is probably NULL, + giving nonsense in the following computation. But then stack_saved + is 0, so the following test can never be true. */ + char *p = (char *)ptr; + long delta = p - g_tealet->stack_start; + if (((unsigned long)delta) < ((unsigned long)g_tealet->stack_saved)) { + /* a pointer to a saved away word */ + return (char **)(g_tealet->stack_copy + delta); + } + return ptr; +} diff --git a/pypy/translator/c/src/tealet/tealet.h b/pypy/translator/c/src/tealet/tealet.h --- a/pypy/translator/c/src/tealet/tealet.h +++ b/pypy/translator/c/src/tealet/tealet.h @@ -144,4 +144,10 @@ TEALET_API int tealet_stub_run(tealet_t *stub, tealet_run_t run, void *run_arg); +/* Hack: translate a pointer into the stack of a tealet into a pointer + * to where it is really stored so far. Only to access word-sized data. + */ +TEALET_API +char **_tealet_translate_pointer(tealet_t *context, char **ptr); + #endif /* _TEALET_H_ */ From noreply at buildbot.pypy.org Tue Jul 26 13:07:20 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 26 Jul 2011 13:07:20 +0200 (CEST) Subject: [pypy-commit] pypy tealet: Revert these changes, checked in by mistake. Message-ID: <20110726110720.DD19E823B2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r46000:05d8782a6da4 Date: 2011-07-26 11:12 +0200 http://bitbucket.org/pypy/pypy/changeset/05d8782a6da4/ Log: Revert these changes, checked in by mistake. diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -1593,20 +1593,31 @@ { __asm { mov\tedx, DWORD PTR [esp+4]\t; 1st argument, which is the callback + mov\tecx, DWORD PTR [esp+8]\t; 2nd argument, which is gcrootanchor mov\teax, esp\t\t; my frame top address push\teax\t\t\t; ASM_FRAMEDATA[6] push\tebp\t\t\t; ASM_FRAMEDATA[5] push\tedi\t\t\t; ASM_FRAMEDATA[4] push\tesi\t\t\t; ASM_FRAMEDATA[3] push\tebx\t\t\t; ASM_FRAMEDATA[2] - xor\teax, eax - push\teax\t\t\t; ASM_FRAMEDATA[1] - push\teax\t\t\t; ASM_FRAMEDATA[0] + + ; Add this ASM_FRAMEDATA to the front of the circular linked + ; list. Let's call it 'self'. + + mov\teax, DWORD PTR [ecx+4]\t\t; next = gcrootanchor->next + push\teax\t\t\t\t\t\t\t\t\t; self->next = next + push\tecx ; self->prev = gcrootanchor + mov\tDWORD PTR [ecx+4], esp\t\t; gcrootanchor->next = self + mov\tDWORD PTR [eax+0], esp\t\t\t\t\t; next->prev = self call\tedx\t\t\t\t\t\t; invoke the callback - pop\tecx\t\t\t\t; ignored ASM_FRAMEDATA[0] - pop\tecx\t\t\t\t; ignored ASM_FRAMEDATA[1] + ; Detach this ASM_FRAMEDATA from the circular linked list + pop\tesi\t\t\t\t\t\t\t; prev = self->prev + pop\tedi\t\t\t\t\t\t\t; next = self->next + mov\tDWORD PTR [esi+4], edi\t\t; prev->next = next + mov\tDWORD PTR [edi+0], esi\t\t; next->prev = prev + pop\tebx\t\t\t\t; restore from ASM_FRAMEDATA[2] pop\tesi\t\t\t\t; restore from ASM_FRAMEDATA[3] pop\tedi\t\t\t\t; restore from ASM_FRAMEDATA[4] @@ -1629,6 +1640,7 @@ /* See description in asmgcroot.py */ .cfi_startproc /* %rdi is the 1st argument, which is the callback */ + /* %rsi is the 2nd argument, which is gcrootanchor */ movq\t%rsp, %rax\t/* my frame top address */ pushq\t%rax\t\t/* ASM_FRAMEDATA[8] */ pushq\t%rbp\t\t/* ASM_FRAMEDATA[7] */ @@ -1637,17 +1649,26 @@ pushq\t%r13\t\t/* ASM_FRAMEDATA[4] */ pushq\t%r12\t\t/* ASM_FRAMEDATA[3] */ pushq\t%rbx\t\t/* ASM_FRAMEDATA[2] */ - xorq\t%rax,%rax - pushq\t%rax\t\t/* ASM_FRAMEDATA[1] */ - pushq\t%rax\t\t/* ASM_FRAMEDATA[0] */ + /* Add this ASM_FRAMEDATA to the front of the circular linked */ + /* list. Let's call it 'self'. */ + + movq\t8(%rsi), %rax\t/* next = gcrootanchor->next */ + pushq\t%rax\t\t\t\t/* self->next = next */ + pushq\t%rsi\t\t\t/* self->prev = gcrootanchor */ + movq\t%rsp, 8(%rsi)\t/* gcrootanchor->next = self */ + movq\t%rsp, 0(%rax)\t\t\t/* next->prev = self */ .cfi_def_cfa_offset 80\t/* 9 pushes + the retaddr = 80 bytes */ /* note: the Mac OS X 16 bytes aligment must be respected. */ call\t*%rdi\t\t/* invoke the callback */ - popq\t%rcx\t\t/* ignored ASM_FRAMEDATA[0] */ - popq\t%rcx\t\t/* ignored ASM_FRAMEDATA[1] */ + /* Detach this ASM_FRAMEDATA from the circular linked list */ + popq\t%rsi\t\t/* prev = self->prev */ + popq\t%rdi\t\t/* next = self->next */ + movq\t%rdi, 8(%rsi)\t/* prev->next = next */ + movq\t%rsi, 0(%rdi)\t/* next->prev = prev */ + popq\t%rbx\t\t/* restore from ASM_FRAMEDATA[2] */ popq\t%r12\t\t/* restore from ASM_FRAMEDATA[3] */ popq\t%r13\t\t/* restore from ASM_FRAMEDATA[4] */ @@ -1680,21 +1701,32 @@ print >> output, """\ /* See description in asmgcroot.py */ movl\t4(%esp), %edx\t/* 1st argument, which is the callback */ + movl\t8(%esp), %ecx\t/* 2nd argument, which is gcrootanchor */ movl\t%esp, %eax\t/* my frame top address */ pushl\t%eax\t\t/* ASM_FRAMEDATA[6] */ pushl\t%ebp\t\t/* ASM_FRAMEDATA[5] */ pushl\t%edi\t\t/* ASM_FRAMEDATA[4] */ pushl\t%esi\t\t/* ASM_FRAMEDATA[3] */ pushl\t%ebx\t\t/* ASM_FRAMEDATA[2] */ - xorl\t%eax,%eax - pushl\t%eax\t\t/* ASM_FRAMEDATA[1] */ - pushl\t%eax\t\t/* ASM_FRAMEDATA[0] */ + + /* Add this ASM_FRAMEDATA to the front of the circular linked */ + /* list. Let's call it 'self'. */ + + movl\t4(%ecx), %eax\t/* next = gcrootanchor->next */ + pushl\t%eax\t\t\t\t/* self->next = next */ + pushl\t%ecx\t\t\t/* self->prev = gcrootanchor */ + movl\t%esp, 4(%ecx)\t/* gcrootanchor->next = self */ + movl\t%esp, 0(%eax)\t\t\t/* next->prev = self */ /* note: the Mac OS X 16 bytes aligment must be respected. */ call\t*%edx\t\t/* invoke the callback */ - popl\t%ecx\t\t/* ignored ASM_FRAMEDATA[0] */ - popl\t%ecx\t\t/* ignored ASM_FRAMEDATA[1] */ + /* Detach this ASM_FRAMEDATA from the circular linked list */ + popl\t%esi\t\t/* prev = self->prev */ + popl\t%edi\t\t/* next = self->next */ + movl\t%edi, 4(%esi)\t/* prev->next = next */ + movl\t%esi, 0(%edi)\t/* next->prev = prev */ + popl\t%ebx\t\t/* restore from ASM_FRAMEDATA[2] */ popl\t%esi\t\t/* restore from ASM_FRAMEDATA[3] */ popl\t%edi\t\t/* restore from ASM_FRAMEDATA[4] */ diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h --- a/pypy/translator/c/src/mem.h +++ b/pypy/translator/c/src/mem.h @@ -6,7 +6,7 @@ extern char __gcmapstart; extern char __gcmapend; extern char __gccallshapes; -extern long pypy_asm_stackwalk(void*); +extern long pypy_asm_stackwalk(void*, void*); #define __gcnoreorderhack __gcmapend /* The following pseudo-instruction is used by --gcrootfinder=asmgcc @@ -52,7 +52,7 @@ extern void* __gcmapstart; extern void* __gcmapend; extern char* __gccallshapes; -extern long pypy_asm_stackwalk(void*); +extern long pypy_asm_stackwalk(void*, void*); /* With the msvc Microsoft Compiler, the optimizer seems free to move any code (even asm) that involves local memory (registers and stack). From noreply at buildbot.pypy.org Tue Jul 26 13:07:22 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 26 Jul 2011 13:07:22 +0200 (CEST) Subject: [pypy-commit] pypy tealet: The test in rlib/test_rtealet passes now. Message-ID: <20110726110722.1B428823B2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: tealet Changeset: r46001:ca5a04e1b758 Date: 2011-07-26 11:41 +0200 http://bitbucket.org/pypy/pypy/changeset/ca5a04e1b758/ Log: The test in rlib/test_rtealet passes now. diff --git a/pypy/rlib/_tealet_rffi.py b/pypy/rlib/_tealet_rffi.py --- a/pypy/rlib/_tealet_rffi.py +++ b/pypy/rlib/_tealet_rffi.py @@ -1,5 +1,5 @@ import os -from pypy.rpython.lltypesystem import lltype, rffi +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo eci = ExternalCompilationInfo( diff --git a/pypy/rlib/rtealet.py b/pypy/rlib/rtealet.py --- a/pypy/rlib/rtealet.py +++ b/pypy/rlib/rtealet.py @@ -61,13 +61,13 @@ switcher = Switcher() llswitcher = lltype.malloc(rffi.CArray(_tealet_rffi.TEALET_P), 1, - flavor='raw', zero=True) + flavor='raw', zero=True, track_allocation=False) def _new(main, starting_tealet): switcher.current = main.current switcher.target = starting_tealet llswitcher[0] = main.lltealet - r = _stack_protected_call(llhelper(FUNCNOARG, _new_critical)) + r = _stack_protected_call(llhelper(FUNCNOARG_P, _new_critical)) _check_exception(r) def _new_critical(): @@ -110,7 +110,7 @@ switcher.target = target main.current = target llswitcher[0] = target.lltealet - r = _stack_protected_call(llhelper(FUNCNOARG, _switch_critical)) + r = _stack_protected_call(llhelper(FUNCNOARG_P, _switch_critical)) _check_exception(r) def _switch_critical(): @@ -154,7 +154,7 @@ return _tealetrootwalker from pypy.rpython.memory.gctransform.asmgcroot import ( - WALKFRAME, CALLEE_SAVED_REGS) + WALKFRAME, CALLEE_SAVED_REGS, sizeofaddr) assert _asmstackrootwalker is not None, "should have been monkey-patched" basewalker = _asmstackrootwalker @@ -170,13 +170,29 @@ if not p.context: return False self.context = p.context - initialframedata = p.initialframedata + anchor = p.anchor del p self.curframe = lltype.malloc(WALKFRAME, flavor='raw') self.otherframe = lltype.malloc(WALKFRAME, flavor='raw') - basewalker.fill_initial_frame(self.curframe, self.initialframedata) + initialframedata = anchor[1] + ll_assert(initialframedata != llmemory.cast_ptr_to_adr(anchor), + "no anchored tealet stack found") + ll_assert(initialframedata == anchor[0], + "more than one anchored tealet stack found") + self.fill_initial_frame(self.curframe, initialframedata) return True + def fill_initial_frame(self, curframe, initialframedata): + # Copy&paste :-( + initialframedata += 2*sizeofaddr + reg = 0 + while reg < CALLEE_SAVED_REGS: + curframe.regs_stored_at[reg] = initialframedata+reg*sizeofaddr + reg += 1 + retaddraddr = initialframedata + CALLEE_SAVED_REGS * sizeofaddr + retaddraddr = self.translateptr(retaddraddr) + curframe.frame_address = retaddraddr.address[0] + def teardown(self): lltype.free(self.curframe, flavor='raw') lltype.free(self.otherframe, flavor='raw') @@ -197,13 +213,12 @@ # of course the stack itself is full of non-translated pointers. # while True: - callee = self.curframe - # if not self.enumerating: if not prev: if not self.setup(obj): # one-time initialization return llmemory.NULL prev = obj # random value, but non-NULL + callee = self.curframe retaddraddr = self.translateptr(callee.frame_address) retaddr = retaddraddr.address[0] basewalker.locate_caller_based_on_retaddr(retaddr) @@ -211,6 +226,7 @@ # # not really a loop, but kept this way for similarity # with asmgcroot: + callee = self.curframe while True: location = basewalker._shape_decompressor.next() if location == 0: @@ -275,10 +291,14 @@ p = lltype.malloc(SUSPSTACK) p.context = _tealet_rffi.NULL_TEALET p.my_index = len(self.lst) + p.next_unused = -42000000 + p.anchor = lltype.malloc(ASM_FRAMEDATA_HEAD_PTR.TO, flavor='raw', + track_allocation=False) self.lst.append(p) else: p = self.lst[self.first_unused] self.first_unused = p.next_unused + p.anchor[0] = p.anchor[1] = llmemory.cast_ptr_to_adr(p.anchor) return p def release(self, p): @@ -288,21 +308,19 @@ suspendedstacks = SuspendedStacks() def _stack_protected_call(callback): - # :-/ p = suspendedstacks.acquire() - suspendedstacks.callback = callback - anchor = lltype.malloc(ASM_FRAMEDATA_HEAD_PTR.TO, flavor='raw') - anchor[0] = anchor[1] = llmemory.cast_ptr_to_adr(anchor) - p.anchor = anchor - r = pypy_asm_stackwalk2(callback, anchor) + p.context = switcher.current.lltealet + llop.gc_assume_young_pointers(lltype.Void, + llmemory.cast_ptr_to_adr(p)) + r = pypy_asm_stackwalk2(callback, p.anchor) + p.context = _tealet_rffi.NULL_TEALET suspendedstacks.release(p) - lltype.free(anchor, flavor='raw') return r -FUNCNOARG = lltype.FuncType([], rffi.INT) +FUNCNOARG_P = lltype.Ptr(lltype.FuncType([], rffi.INT)) pypy_asm_stackwalk2 = rffi.llexternal('pypy_asm_stackwalk', - [lltype.Ptr(FUNCNOARG), + [FUNCNOARG_P, ASM_FRAMEDATA_HEAD_PTR], rffi.INT, sandboxsafe=True, _nowrapper=True) diff --git a/pypy/rlib/test/test_rtealet.py b/pypy/rlib/test/test_rtealet.py --- a/pypy/rlib/test/test_rtealet.py +++ b/pypy/rlib/test/test_rtealet.py @@ -1,4 +1,5 @@ import py +from pypy.config.config import ConflictConfigError from pypy.translator.c.test.test_standalone import StandaloneTests @@ -9,7 +10,10 @@ config = get_pypy_config(translating=True) config.translation.gc = "minimark" config.translation.gcrootfinder = cls.gcrootfinder - config.translation.tealet = True + try: + config.translation.tealet = True + except ConflictConfigError, e: + py.test.skip(str(e)) cls.config = config def test_demo1(self): From noreply at buildbot.pypy.org Tue Jul 26 14:33:25 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 26 Jul 2011 14:33:25 +0200 (CEST) Subject: [pypy-commit] pypy default: Backed out changeset 9d796d6049d6, re-enabling 39a9093e603d Message-ID: <20110726123325.D29CC823B2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46002:96e2837af4ec Date: 2011-07-26 13:52 +0200 http://bitbucket.org/pypy/pypy/changeset/96e2837af4ec/ Log: Backed out changeset 9d796d6049d6, re-enabling 39a9093e603d (which I hope to fix in the next checkin). diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -49,6 +49,7 @@ from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage from pypy.rpython.memory.gc.base import GCBase, MovingGCBase from pypy.rpython.memory.gc import minimarkpage, env +from pypy.rpython.memory.support import mangle_hash from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask, r_uint from pypy.rlib.rarithmetic import LONG_BIT_SHIFT from pypy.rlib.debug import ll_assert, debug_print, debug_start, debug_stop @@ -1793,7 +1794,7 @@ return self.id_or_identityhash(gcobj, False) def identityhash(self, gcobj): - return self.id_or_identityhash(gcobj, True) + return mangle_hash(self.id_or_identityhash(gcobj, True)) # ---------- diff --git a/pypy/rpython/memory/lldict.py b/pypy/rpython/memory/lldict.py --- a/pypy/rpython/memory/lldict.py +++ b/pypy/rpython/memory/lldict.py @@ -1,6 +1,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem import rdict from pypy.rlib.objectmodel import we_are_translated +from pypy.rpython.memory.support import mangle_hash # This is a low-level AddressDict, reusing a lot of the logic from rdict.py. # xxx this is very dependent on the details of rdict.py @@ -40,7 +41,8 @@ lltype.free(entries, flavor="raw") if not we_are_translated(): count_alloc(-1) -_hash = llmemory.cast_adr_to_int +def _hash(adr): + return mangle_hash(llmemory.cast_adr_to_int(adr)) def dict_keyhash(d, key): return _hash(key) diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -4,6 +4,15 @@ from pypy.rlib.debug import ll_assert from pypy.tool.identity_dict import identity_dict + +def mangle_hash(i): + # To hash pointers in dictionaries. Assumes that i shows some + # alignment (to 4, 8, maybe 16 bytes), so we use the following + # formula to avoid the trailing bits being always 0. + return i ^ (i >> 4) + +# ____________________________________________________________ + DEFAULT_CHUNK_SIZE = 1019 From noreply at buildbot.pypy.org Tue Jul 26 14:33:27 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 26 Jul 2011 14:33:27 +0200 (CEST) Subject: [pypy-commit] pypy default: Hopefully fix 96e2837af4ec. It was already causing some Message-ID: <20110726123327.14882823B3@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46003:841f3e129c5b Date: 2011-07-26 14:33 +0200 http://bitbucket.org/pypy/pypy/changeset/841f3e129c5b/ Log: Hopefully fix 96e2837af4ec. It was already causing some failures, which are now fixed; at least: test_newgc.TestMiniMarkGC.test_hash_preservation test_newgc.TestMiniMarkGCMostCompact.test_hash_preservation and probably jit.backend.x86.test.test_z*.py. diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -1733,7 +1733,7 @@ # ---------- # id() and identityhash() support - def id_or_identityhash(self, gcobj, special_case_prebuilt): + def id_or_identityhash(self, gcobj, is_hash): """Implement the common logic of id() and identityhash() of an object, given as a GCREF. """ @@ -1776,7 +1776,7 @@ # The answer is the address of the shadow. obj = shadow # - elif special_case_prebuilt: + elif is_hash: if self.header(obj).tid & GCFLAG_HAS_SHADOW: # # For identityhash(), we need a special case for some @@ -1786,15 +1786,18 @@ # because the stored value might clash with a real one. size = self.get_size(obj) return (obj + size).signed[0] + # Important: the returned value is not mangle_hash()ed! # - return llmemory.cast_adr_to_int(obj) - + i = llmemory.cast_adr_to_int(obj) + if is_hash: + i = mangle_hash(i) + return i def id(self, gcobj): return self.id_or_identityhash(gcobj, False) def identityhash(self, gcobj): - return mangle_hash(self.id_or_identityhash(gcobj, True)) + return self.id_or_identityhash(gcobj, True) # ---------- diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -932,10 +932,10 @@ def gct_gc_identityhash(self, hop): livevars = self.push_roots(hop) [v_ptr] = hop.spaceop.args - v_adr = hop.genop("cast_ptr_to_adr", [v_ptr], - resulttype=llmemory.Address) + v_ptr = hop.genop("cast_opaque_ptr", [v_ptr], + resulttype=llmemory.GCREF) hop.genop("direct_call", - [self.identityhash_ptr, self.c_const_gc, v_adr], + [self.identityhash_ptr, self.c_const_gc, v_ptr], resultvar=hop.spaceop.result) self.pop_roots(hop, livevars) From noreply at buildbot.pypy.org Tue Jul 26 14:39:10 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 26 Jul 2011 14:39:10 +0200 (CEST) Subject: [pypy-commit] pypy default: Clarify this by moving the "return" statement after the comment. Message-ID: <20110726123910.A1F90823B2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46004:f89b43e167ad Date: 2011-07-26 14:39 +0200 http://bitbucket.org/pypy/pypy/changeset/f89b43e167ad/ Log: Clarify this by moving the "return" statement after the comment. diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -1785,8 +1785,9 @@ # after the object. But we cannot use it for id() # because the stored value might clash with a real one. size = self.get_size(obj) - return (obj + size).signed[0] + i = (obj + size).signed[0] # Important: the returned value is not mangle_hash()ed! + return i # i = llmemory.cast_adr_to_int(obj) if is_hash: From noreply at buildbot.pypy.org Tue Jul 26 20:36:50 2011 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 26 Jul 2011 20:36:50 +0200 (CEST) Subject: [pypy-commit] pypy default: Finally found a way to fix this: with asmgcc, across a malloc, the Message-ID: <20110726183650.CC673823B2@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46005:ebd086d01bf7 Date: 2011-07-26 19:09 +0200 http://bitbucket.org/pypy/pypy/changeset/ebd086d01bf7/ Log: Finally found a way to fix this: with asmgcc, across a malloc, the non-callee-save registers could not stay alive, even though in most cases (in the fast path) they would not be touched at all. Fixed by adopting the same solution as with shadowstack, but only for the registers that need to. diff --git a/pypy/jit/backend/x86/arch.py b/pypy/jit/backend/x86/arch.py --- a/pypy/jit/backend/x86/arch.py +++ b/pypy/jit/backend/x86/arch.py @@ -27,3 +27,6 @@ # which are used in the malloc itself. They are: # ecx, ebx, esi, edi [32 and 64 bits] # r8, r9, r10, r12, r13, r14, r15 [64 bits only] +# +# Note that with asmgcc, the locations corresponding to callee-save registers +# are never used. diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -181,6 +181,7 @@ # instructions in assembler, with a mark_gc_roots in between. # With shadowstack, this is not needed, so we produce a single helper. gcrootmap = self.cpu.gc_ll_descr.gcrootmap + shadow_stack = (gcrootmap is not None and gcrootmap.is_shadow_stack) # # ---------- first helper for the slow path of malloc ---------- mc = codebuf.MachineCodeBlockWrapper() @@ -190,10 +191,19 @@ mc.SUB_rr(edx.value, eax.value) # compute the size we want addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr() # - if gcrootmap is not None and gcrootmap.is_shadow_stack: + # The registers to save in the copy area: with shadowstack, most + # registers need to be saved. With asmgcc, the callee-saved registers + # don't need to. + save_in_copy_area = gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items() + if not shadow_stack: + save_in_copy_area = [(reg, ofs) for (reg, ofs) in save_in_copy_area + if reg not in gpr_reg_mgr_cls.REGLOC_TO_GCROOTMAP_REG_INDEX] + # + for reg, ofs in save_in_copy_area: + mc.MOV_br(ofs, reg.value) + # + if shadow_stack: # ---- shadowstack ---- - for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items(): - mc.MOV_br(ofs, reg.value) mc.SUB_ri(esp.value, 16 - WORD) # stack alignment of 16 bytes if IS_X86_32: mc.MOV_sr(0, edx.value) # push argument @@ -201,15 +211,13 @@ mc.MOV_rr(edi.value, edx.value) mc.CALL(imm(addr)) mc.ADD_ri(esp.value, 16 - WORD) - for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items(): - mc.MOV_rb(reg.value, ofs) else: # ---- asmgcc ---- if IS_X86_32: mc.MOV_sr(WORD, edx.value) # save it as the new argument elif IS_X86_64: - # rdi can be clobbered: its content was forced to the stack - # by _fastpath_malloc(), like all other save_around_call_regs. + # rdi can be clobbered: its content was saved in the + # copy area of the stack mc.MOV_rr(edi.value, edx.value) mc.JMP(imm(addr)) # tail call to the real malloc rawstart = mc.materialize(self.cpu.asmmemmgr, []) @@ -217,6 +225,10 @@ # ---------- second helper for the slow path of malloc ---------- mc = codebuf.MachineCodeBlockWrapper() # + for reg, ofs in save_in_copy_area: + mc.MOV_rb(reg.value, ofs) + assert reg is not eax and reg is not edx + # if self.cpu.supports_floats: # restore the XMM registers for i in range(self.cpu.NUM_REGS):# from where they were saved mc.MOVSD_xs(i, (WORD*2)+8*i) @@ -2424,8 +2436,7 @@ # there are two helpers to call only with asmgcc slowpath_addr1 = self.malloc_slowpath1 self.mc.CALL(imm(slowpath_addr1)) - self.mark_gc_roots(self.write_new_force_index(), - use_copy_area=shadow_stack) + self.mark_gc_roots(self.write_new_force_index(), use_copy_area=True) slowpath_addr2 = self.malloc_slowpath2 self.mc.CALL(imm(slowpath_addr2)) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -921,27 +921,13 @@ def _do_fastpath_malloc(self, op, size, tid): gc_ll_descr = self.assembler.cpu.gc_ll_descr self.rm.force_allocate_reg(op.result, selected_reg=eax) - - if gc_ll_descr.gcrootmap and gc_ll_descr.gcrootmap.is_shadow_stack: - # ---- shadowstack ---- - # We need edx as a temporary, but otherwise don't save any more - # register. See comments in _build_malloc_slowpath(). - tmp_box = TempBox() - self.rm.force_allocate_reg(tmp_box, selected_reg=edx) - self.rm.possibly_free_var(tmp_box) - else: - # ---- asmgcc ---- - # We need to force-allocate each of save_around_call_regs now. - # The alternative would be to save and restore them around the - # actual call to malloc(), in the rare case where we need to do - # it; however, mark_gc_roots() would need to be adapted to know - # where the variables end up being saved. Messy. - for reg in self.rm.save_around_call_regs: - if reg is not eax: - tmp_box = TempBox() - self.rm.force_allocate_reg(tmp_box, selected_reg=reg) - self.rm.possibly_free_var(tmp_box) - + # + # We need edx as a temporary, but otherwise don't save any more + # register. See comments in _build_malloc_slowpath(). + tmp_box = TempBox() + self.rm.force_allocate_reg(tmp_box, selected_reg=edx) + self.rm.possibly_free_var(tmp_box) + # self.assembler.malloc_cond( gc_ll_descr.get_nursery_free_addr(), gc_ll_descr.get_nursery_top_addr(), @@ -1337,14 +1323,26 @@ if reg is eax: continue # ok to ignore this one if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)): - if use_copy_area: - assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS - area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg] - gcrootmap.add_frame_offset(shape, area_offset) - else: - assert reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX - gcrootmap.add_callee_save_reg( - shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg]) + # + # The register 'reg' is alive across this call. + gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap + if gcrootmap is None or not gcrootmap.is_shadow_stack: + # + # Asmgcc: if reg is a callee-save register, we can + # explicitly mark it as containing a BoxPtr. + if reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX: + gcrootmap.add_callee_save_reg( + shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg]) + continue + # + # Else, 'use_copy_area' must be True (otherwise this BoxPtr + # should not be in a register). The copy area contains the + # real value of the register. + assert use_copy_area + assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS + area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg] + gcrootmap.add_frame_offset(shape, area_offset) + # return gcrootmap.compress_callshape(shape, self.assembler.datablockwrapper) From noreply at buildbot.pypy.org Wed Jul 27 09:21:29 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 09:21:29 +0200 (CEST) Subject: [pypy-commit] benchmarks default: log what we are running Message-ID: <20110727072129.6916C82110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r138:e9ec714eea98 Date: 2011-07-27 09:21 +0200 http://bitbucket.org/pypy/benchmarks/changeset/e9ec714eea98/ Log: log what we are running diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -1,5 +1,5 @@ - import os +import logging from unladen_swallow.perf import SimpleBenchmark, MeasureGeneric def relative(*args): @@ -118,6 +118,7 @@ translate_py = relative('lib/pypy/pypy/translator/goal/translate.py') #targetnop = relative('lib/pypy/pypy/translator/goal/targetnopstandalone.py') args = base_python + [translate_py, '--source', '--dont-write-c-files', '-O2'] + logging.info('Running %s', ' '.join(args)) proc = subprocess.Popen(args, stderr=subprocess.PIPE) out, err = proc.communicate() retcode = proc.poll() From noreply at buildbot.pypy.org Wed Jul 27 09:24:11 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 09:24:11 +0200 (CEST) Subject: [pypy-commit] buildbot default: increase the timeout for benchmarks now that we also run translate.py Message-ID: <20110727072411.0E50382110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r540:99a8616a4f05 Date: 2011-07-27 09:24 +0200 http://bitbucket.org/pypy/buildbot/changeset/99a8616a4f05/ Log: increase the timeout for benchmarks now that we also run translate.py diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -302,7 +302,8 @@ '--branch', WithProperties('%(branch)s'), ] + addopts, workdir='./benchmarks', - haltOnFailure=True)) + haltOnFailure=True, + timeout=3600)) # a bit obscure hack to get both os.path.expand and a property filename = '%(got_revision)s' + (postfix or '') resfile = os.path.expanduser("~/bench_results/%s.json" % filename) From noreply at buildbot.pypy.org Wed Jul 27 13:24:19 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 13:24:19 +0200 (CEST) Subject: [pypy-commit] pypy default: this makes all these tests failing, because pypy does not correctly unwrap the parameters before passing them to the callbacks Message-ID: <20110727112419.810A282110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46006:157edf3b2ce8 Date: 2011-07-27 10:43 +0200 http://bitbucket.org/pypy/pypy/changeset/157edf3b2ce8/ Log: this makes all these tests failing, because pypy does not correctly unwrap the parameters before passing them to the callbacks diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py @@ -14,14 +14,27 @@ return args[-1] def check_type(self, typ, arg): + unwrapped_types = { + c_float: float, + c_double: float, + c_char: str, + c_char_p: str, + c_uint: long, + c_ulong: long, + } + PROTO = self.functype.im_func(typ, typ) - result = PROTO(self.callback)(arg) + cfunc = PROTO(self.callback) + result = cfunc(arg) if typ == c_float: assert abs(result - arg) < 0.000001 else: assert self.got_args == (arg,) assert result == arg + result2 = cfunc(typ(arg)) + assert type(result2) is unwrapped_types.get(typ, int) + PROTO = self.functype.im_func(typ, c_byte, typ) result = PROTO(self.callback)(-3, arg) if typ == c_float: From noreply at buildbot.pypy.org Wed Jul 27 13:24:20 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 13:24:20 +0200 (CEST) Subject: [pypy-commit] pypy default: another failing test Message-ID: <20110727112420.B393782110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46007:d4b0a4841f2c Date: 2011-07-27 10:46 +0200 http://bitbucket.org/pypy/pypy/changeset/d4b0a4841f2c/ Log: another failing test diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py @@ -235,3 +235,11 @@ out, err = capsys.readouterr() assert (out, err) == ("", "") + def test_raise_argumenterror(self): + py.test.skip('FIXME') + def callback(x): + pass + FUNC = CFUNCTYPE(None, c_void_p) + cfunc = FUNC(callback) + param = c_uint(42) + py.test.raises(ArgumentError, "cfunc(param)") From noreply at buildbot.pypy.org Wed Jul 27 13:24:21 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 13:24:21 +0200 (CEST) Subject: [pypy-commit] pypy default: we don't need to pass through a callback to execute _cast_addr: all tests pass by just calling it Message-ID: <20110727112421.E8CD982110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46008:f35e37079ff2 Date: 2011-07-27 12:04 +0200 http://bitbucket.org/pypy/pypy/changeset/f35e37079ff2/ Log: we don't need to pass through a callback to execute _cast_addr: all tests pass by just calling it diff --git a/lib-python/modified-2.7/ctypes/__init__.py b/lib-python/modified-2.7/ctypes/__init__.py --- a/lib-python/modified-2.7/ctypes/__init__.py +++ b/lib-python/modified-2.7/ctypes/__init__.py @@ -489,9 +489,8 @@ _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI return CFunctionType -_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr) def cast(obj, typ): - return _cast(obj, obj, typ) + return _cast_addr(obj, obj, typ) _string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) def string_at(ptr, size=-1): From noreply at buildbot.pypy.org Wed Jul 27 13:24:23 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 13:24:23 +0200 (CEST) Subject: [pypy-commit] pypy default: fix test_callbacks by converting/unwrapping the arguments before calling the actual callback Message-ID: <20110727112423.23F9082110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46009:4d240d754afa Date: 2011-07-27 11:58 +0200 http://bitbucket.org/pypy/pypy/changeset/4d240d754afa/ Log: fix test_callbacks by converting/unwrapping the arguments before calling the actual callback diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -296,13 +296,9 @@ "This function takes %d argument%s (%s given)" % (len(self._argtypes_), plural, len(args))) - # check that arguments are convertible - ## XXX Not as long as ctypes.cast is a callback function with - ## py_object arguments... - ## self._convert_args(self._argtypes_, args, {}) - + newargs = self._convert_args_for_callback(argtypes, args) try: - res = self.callable(*args) + res = self.callable(*newargs) except: exc_info = sys.exc_info() traceback.print_tb(exc_info[2], file=sys.stderr) @@ -466,6 +462,16 @@ return cobj, cobj._to_ffi_param(), type(cobj) + def _convert_args_for_callback(self, argtypes, args): + assert len(argtypes) == len(args) + newargs = [] + for argtype, arg in zip(argtypes, args): + param = argtype.from_param(arg) + if self._is_primitive(argtype): + param = param.value + newargs.append(param) + return newargs + def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] @@ -556,6 +562,9 @@ newargtypes.append(newargtype) return keepalives, newargs, newargtypes, outargs + @staticmethod + def _is_primitive(argtype): + return argtype.__bases__[0] is _SimpleCData def _wrap_result(self, restype, result): """ @@ -564,7 +573,7 @@ """ # hack for performance: if restype is a "simple" primitive type, don't # allocate the buffer because it's going to be thrown away immediately - if restype.__bases__[0] is _SimpleCData and not restype._is_pointer_like(): + if self._is_primitive(restype) and not restype._is_pointer_like(): return result # shape = restype._ffishape diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -10,6 +10,8 @@ from _ctypes.builtin import ConvMode from _ctypes.array import Array from _ctypes.pointer import _Pointer, as_ffi_pointer +#from _ctypes.function import CFuncPtr # this import is moved at the bottom + # because else it's circular class NULL(object): pass @@ -86,7 +88,7 @@ return res if isinstance(value, Array): return value - if isinstance(value, _Pointer): + if isinstance(value, (_Pointer, CFuncPtr)): return cls.from_address(value._buffer.buffer) if isinstance(value, (int, long)): return cls(value) @@ -338,3 +340,5 @@ def __nonzero__(self): return self._buffer[0] not in (0, '\x00') + +from _ctypes.function import CFuncPtr diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py @@ -15,12 +15,12 @@ def check_type(self, typ, arg): unwrapped_types = { - c_float: float, - c_double: float, - c_char: str, - c_char_p: str, - c_uint: long, - c_ulong: long, + c_float: (float,), + c_double: (float,), + c_char: (str,), + c_char_p: (str,), + c_uint: (int, long), + c_ulong: (int, long), } PROTO = self.functype.im_func(typ, typ) @@ -33,7 +33,7 @@ assert result == arg result2 = cfunc(typ(arg)) - assert type(result2) is unwrapped_types.get(typ, int) + assert type(result2) in unwrapped_types.get(typ, (int, long)) PROTO = self.functype.im_func(typ, c_byte, typ) result = PROTO(self.callback)(-3, arg) From noreply at buildbot.pypy.org Wed Jul 27 13:24:24 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 13:24:24 +0200 (CEST) Subject: [pypy-commit] pypy default: a passing test Message-ID: <20110727112424.5193D82110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46010:68216f3eb946 Date: 2011-07-27 12:13 +0200 http://bitbucket.org/pypy/pypy/changeset/68216f3eb946/ Log: a passing test diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py @@ -235,6 +235,16 @@ out, err = capsys.readouterr() assert (out, err) == ("", "") + + def test_callback_pyobject(self): + def callback(obj): + return obj + + FUNC = CFUNCTYPE(py_object, py_object) + cfunc = FUNC(callback) + param = c_int(42) + assert cfunc(param) is param + def test_raise_argumenterror(self): py.test.skip('FIXME') def callback(x): From noreply at buildbot.pypy.org Wed Jul 27 13:24:25 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 13:24:25 +0200 (CEST) Subject: [pypy-commit] pypy default: fix this test Message-ID: <20110727112425.82B3A82110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46011:ca9f485900d4 Date: 2011-07-27 12:15 +0200 http://bitbucket.org/pypy/pypy/changeset/ca9f485900d4/ Log: fix this test diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -296,7 +296,10 @@ "This function takes %d argument%s (%s given)" % (len(self._argtypes_), plural, len(args))) - newargs = self._convert_args_for_callback(argtypes, args) + try: + newargs = self._convert_args_for_callback(argtypes, args) + except (UnicodeError, TypeError, ValueError), e: + raise ArgumentError(str(e)) try: res = self.callable(*newargs) except: diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py @@ -246,7 +246,6 @@ assert cfunc(param) is param def test_raise_argumenterror(self): - py.test.skip('FIXME') def callback(x): pass FUNC = CFUNCTYPE(None, c_void_p) From noreply at buildbot.pypy.org Wed Jul 27 13:24:26 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 13:24:26 +0200 (CEST) Subject: [pypy-commit] pypy default: test and fix for issue807 Message-ID: <20110727112426.B8CD082110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46012:e6043c6b9090 Date: 2011-07-27 13:12 +0200 http://bitbucket.org/pypy/pypy/changeset/e6043c6b9090/ Log: test and fix for issue807 diff --git a/lib-python/modified-2.7/ctypes/__init__.py b/lib-python/modified-2.7/ctypes/__init__.py --- a/lib-python/modified-2.7/ctypes/__init__.py +++ b/lib-python/modified-2.7/ctypes/__init__.py @@ -490,6 +490,10 @@ return CFunctionType def cast(obj, typ): + try: + c_void_p.from_param(obj) + except TypeError, e: + raise ArgumentError(str(e)) return _cast_addr(obj, obj, typ) _string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py b/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py @@ -90,3 +90,8 @@ assert sqrt._objects is my_sqrt._objects # on CPython too my_sqrt._objects.clear() my_sqrt._objects.update(saved_objects) + + def test_cast_argumenterror(self): + param = c_uint(42) + py.test.raises(ArgumentError, "cast(param, c_void_p)") + From noreply at buildbot.pypy.org Wed Jul 27 13:24:27 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 13:24:27 +0200 (CEST) Subject: [pypy-commit] pypy default: make sure that we always pass the numeric address when converting to c_void_p Message-ID: <20110727112427.E690C82110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46013:a1d33f438355 Date: 2011-07-27 13:23 +0200 http://bitbucket.org/pypy/pypy/changeset/a1d33f438355/ Log: make sure that we always pass the numeric address when converting to c_void_p diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -470,7 +470,9 @@ newargs = [] for argtype, arg in zip(argtypes, args): param = argtype.from_param(arg) - if self._is_primitive(argtype): + if argtype._type_ == 'P': # special-case for c_void_p + param = param._get_buffer_value() + elif self._is_primitive(argtype): param = param.value newargs.append(param) return newargs From noreply at buildbot.pypy.org Wed Jul 27 13:24:29 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 13:24:29 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20110727112429.5296082110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46014:7634d3a5a5b2 Date: 2011-07-27 13:24 +0200 http://bitbucket.org/pypy/pypy/changeset/7634d3a5a5b2/ Log: merge heads diff --git a/pypy/jit/backend/x86/arch.py b/pypy/jit/backend/x86/arch.py --- a/pypy/jit/backend/x86/arch.py +++ b/pypy/jit/backend/x86/arch.py @@ -27,3 +27,6 @@ # which are used in the malloc itself. They are: # ecx, ebx, esi, edi [32 and 64 bits] # r8, r9, r10, r12, r13, r14, r15 [64 bits only] +# +# Note that with asmgcc, the locations corresponding to callee-save registers +# are never used. diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -181,6 +181,7 @@ # instructions in assembler, with a mark_gc_roots in between. # With shadowstack, this is not needed, so we produce a single helper. gcrootmap = self.cpu.gc_ll_descr.gcrootmap + shadow_stack = (gcrootmap is not None and gcrootmap.is_shadow_stack) # # ---------- first helper for the slow path of malloc ---------- mc = codebuf.MachineCodeBlockWrapper() @@ -190,10 +191,19 @@ mc.SUB_rr(edx.value, eax.value) # compute the size we want addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr() # - if gcrootmap is not None and gcrootmap.is_shadow_stack: + # The registers to save in the copy area: with shadowstack, most + # registers need to be saved. With asmgcc, the callee-saved registers + # don't need to. + save_in_copy_area = gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items() + if not shadow_stack: + save_in_copy_area = [(reg, ofs) for (reg, ofs) in save_in_copy_area + if reg not in gpr_reg_mgr_cls.REGLOC_TO_GCROOTMAP_REG_INDEX] + # + for reg, ofs in save_in_copy_area: + mc.MOV_br(ofs, reg.value) + # + if shadow_stack: # ---- shadowstack ---- - for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items(): - mc.MOV_br(ofs, reg.value) mc.SUB_ri(esp.value, 16 - WORD) # stack alignment of 16 bytes if IS_X86_32: mc.MOV_sr(0, edx.value) # push argument @@ -201,15 +211,13 @@ mc.MOV_rr(edi.value, edx.value) mc.CALL(imm(addr)) mc.ADD_ri(esp.value, 16 - WORD) - for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items(): - mc.MOV_rb(reg.value, ofs) else: # ---- asmgcc ---- if IS_X86_32: mc.MOV_sr(WORD, edx.value) # save it as the new argument elif IS_X86_64: - # rdi can be clobbered: its content was forced to the stack - # by _fastpath_malloc(), like all other save_around_call_regs. + # rdi can be clobbered: its content was saved in the + # copy area of the stack mc.MOV_rr(edi.value, edx.value) mc.JMP(imm(addr)) # tail call to the real malloc rawstart = mc.materialize(self.cpu.asmmemmgr, []) @@ -217,6 +225,10 @@ # ---------- second helper for the slow path of malloc ---------- mc = codebuf.MachineCodeBlockWrapper() # + for reg, ofs in save_in_copy_area: + mc.MOV_rb(reg.value, ofs) + assert reg is not eax and reg is not edx + # if self.cpu.supports_floats: # restore the XMM registers for i in range(self.cpu.NUM_REGS):# from where they were saved mc.MOVSD_xs(i, (WORD*2)+8*i) @@ -2424,8 +2436,7 @@ # there are two helpers to call only with asmgcc slowpath_addr1 = self.malloc_slowpath1 self.mc.CALL(imm(slowpath_addr1)) - self.mark_gc_roots(self.write_new_force_index(), - use_copy_area=shadow_stack) + self.mark_gc_roots(self.write_new_force_index(), use_copy_area=True) slowpath_addr2 = self.malloc_slowpath2 self.mc.CALL(imm(slowpath_addr2)) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -921,27 +921,13 @@ def _do_fastpath_malloc(self, op, size, tid): gc_ll_descr = self.assembler.cpu.gc_ll_descr self.rm.force_allocate_reg(op.result, selected_reg=eax) - - if gc_ll_descr.gcrootmap and gc_ll_descr.gcrootmap.is_shadow_stack: - # ---- shadowstack ---- - # We need edx as a temporary, but otherwise don't save any more - # register. See comments in _build_malloc_slowpath(). - tmp_box = TempBox() - self.rm.force_allocate_reg(tmp_box, selected_reg=edx) - self.rm.possibly_free_var(tmp_box) - else: - # ---- asmgcc ---- - # We need to force-allocate each of save_around_call_regs now. - # The alternative would be to save and restore them around the - # actual call to malloc(), in the rare case where we need to do - # it; however, mark_gc_roots() would need to be adapted to know - # where the variables end up being saved. Messy. - for reg in self.rm.save_around_call_regs: - if reg is not eax: - tmp_box = TempBox() - self.rm.force_allocate_reg(tmp_box, selected_reg=reg) - self.rm.possibly_free_var(tmp_box) - + # + # We need edx as a temporary, but otherwise don't save any more + # register. See comments in _build_malloc_slowpath(). + tmp_box = TempBox() + self.rm.force_allocate_reg(tmp_box, selected_reg=edx) + self.rm.possibly_free_var(tmp_box) + # self.assembler.malloc_cond( gc_ll_descr.get_nursery_free_addr(), gc_ll_descr.get_nursery_top_addr(), @@ -1337,14 +1323,26 @@ if reg is eax: continue # ok to ignore this one if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)): - if use_copy_area: - assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS - area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg] - gcrootmap.add_frame_offset(shape, area_offset) - else: - assert reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX - gcrootmap.add_callee_save_reg( - shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg]) + # + # The register 'reg' is alive across this call. + gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap + if gcrootmap is None or not gcrootmap.is_shadow_stack: + # + # Asmgcc: if reg is a callee-save register, we can + # explicitly mark it as containing a BoxPtr. + if reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX: + gcrootmap.add_callee_save_reg( + shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg]) + continue + # + # Else, 'use_copy_area' must be True (otherwise this BoxPtr + # should not be in a register). The copy area contains the + # real value of the register. + assert use_copy_area + assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS + area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg] + gcrootmap.add_frame_offset(shape, area_offset) + # return gcrootmap.compress_callshape(shape, self.assembler.datablockwrapper) diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -1733,7 +1733,7 @@ # ---------- # id() and identityhash() support - def id_or_identityhash(self, gcobj, special_case_prebuilt): + def id_or_identityhash(self, gcobj, is_hash): """Implement the common logic of id() and identityhash() of an object, given as a GCREF. """ @@ -1776,7 +1776,7 @@ # The answer is the address of the shadow. obj = shadow # - elif special_case_prebuilt: + elif is_hash: if self.header(obj).tid & GCFLAG_HAS_SHADOW: # # For identityhash(), we need a special case for some @@ -1785,16 +1785,20 @@ # after the object. But we cannot use it for id() # because the stored value might clash with a real one. size = self.get_size(obj) - return (obj + size).signed[0] + i = (obj + size).signed[0] + # Important: the returned value is not mangle_hash()ed! + return i # - return llmemory.cast_adr_to_int(obj) - + i = llmemory.cast_adr_to_int(obj) + if is_hash: + i = mangle_hash(i) + return i def id(self, gcobj): return self.id_or_identityhash(gcobj, False) def identityhash(self, gcobj): - return mangle_hash(self.id_or_identityhash(gcobj, True)) + return self.id_or_identityhash(gcobj, True) # ---------- diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -932,10 +932,10 @@ def gct_gc_identityhash(self, hop): livevars = self.push_roots(hop) [v_ptr] = hop.spaceop.args - v_adr = hop.genop("cast_ptr_to_adr", [v_ptr], - resulttype=llmemory.Address) + v_ptr = hop.genop("cast_opaque_ptr", [v_ptr], + resulttype=llmemory.GCREF) hop.genop("direct_call", - [self.identityhash_ptr, self.c_const_gc, v_adr], + [self.identityhash_ptr, self.c_const_gc, v_ptr], resultvar=hop.spaceop.result) self.pop_roots(hop, livevars) From noreply at buildbot.pypy.org Wed Jul 27 14:38:50 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 14:38:50 +0200 (CEST) Subject: [pypy-commit] pypy default: (Alex_Gaynor, antocuni): special-case type.__eq__ so that type (and subclasses) are marked as compares_by_identity() Message-ID: <20110727123850.2E06882110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46015:bb9c6a2bd529 Date: 2011-07-27 14:39 +0200 http://bitbucket.org/pypy/pypy/changeset/bb9c6a2bd529/ Log: (Alex_Gaynor, antocuni): special-case type.__eq__ so that type (and subclasses) are marked as compares_by_identity() diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -35,6 +35,13 @@ return w_hash object_hash._annspecialcase_ = 'specialize:memo' +def type_eq(space): + "Utility that returns the app-level descriptor type.__eq__." + w_src, w_eq = space.lookup_in_type_where(space.w_type, + '__eq__') + return w_eq +type_eq._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): w_type = space.type(w_obj) typename = w_type.getname(space) diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py --- a/pypy/objspace/std/test/test_identitydict.py +++ b/pypy/objspace/std/test/test_identitydict.py @@ -32,10 +32,20 @@ def __hash__(self): return 0 + class TypeSubclass(type): + pass + + class TypeSubclassCustomCmp(type): + def __cmp__(self, other): + return 0 + assert self.compares_by_identity(Plain) assert not self.compares_by_identity(CustomEq) assert not self.compares_by_identity(CustomCmp) assert not self.compares_by_identity(CustomHash) + assert self.compares_by_identity(type) + assert self.compares_by_identity(TypeSubclass) + assert not self.compares_by_identity(TypeSubclassCustomCmp) def test_modify_class(self): class X(object): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -173,8 +173,6 @@ # ^^^ conservative default, fixed during real usage if space.config.objspace.std.withidentitydict: - did_compare_by_identity = ( - w_self.compares_by_identity_status == COMPARES_BY_IDENTITY) if (key is None or key == '__eq__' or key == '__cmp__' or key == '__hash__'): w_self.compares_by_identity_status = UNKNOWN @@ -229,7 +227,7 @@ return w_self.getattribute_if_not_from_object() is None def compares_by_identity(w_self): - from pypy.objspace.descroperation import object_hash + from pypy.objspace.descroperation import object_hash, type_eq if not w_self.space.config.objspace.std.withidentitydict: return False # conservative # @@ -238,7 +236,9 @@ return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY # default_hash = object_hash(w_self.space) - overrides_eq_cmp_or_hash = (w_self.lookup('__eq__') or + my_eq = w_self.lookup('__eq__') + overrides_eq = (my_eq and my_eq is not type_eq(w_self.space)) + overrides_eq_cmp_or_hash = (overrides_eq or w_self.lookup('__cmp__') or w_self.lookup('__hash__') is not default_hash) if overrides_eq_cmp_or_hash: From noreply at buildbot.pypy.org Wed Jul 27 18:22:39 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 18:22:39 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Revert the last 4 commits, up to c292d7b6630f. It should be Message-ID: <20110727162239.67D3782110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r46016:b09fe84eef7b Date: 2011-07-27 15:27 +0200 http://bitbucket.org/pypy/pypy/changeset/b09fe84eef7b/ Log: Revert the last 4 commits, up to c292d7b6630f. It should be done with a proper merge of the branch r15-for-exception, at some point. diff --git a/pypy/rlib/register.py b/pypy/rlib/register.py deleted file mode 100644 --- a/pypy/rlib/register.py +++ /dev/null @@ -1,81 +0,0 @@ -from pypy.translator.tool.cbuild import ExternalCompilationInfo -from pypy.rpython.tool import rffi_platform - -# On platforms with enough hardware registers and with gcc, we can -# (ab)use gcc to globally assign a register to a single global void* -# variable. We use it with a double meaning: -# -# - when it is NULL upon return from a function, it means that an -# exception occurred. It allows the caller to quickly check for -# exceptions. -# -# - in other cases, with --gcrootfinder=shadowstack, it points to -# the top of the shadow stack. - - -# For now, only for x86-64. Tries to use the register r15. -eci = ExternalCompilationInfo( - post_include_bits=[ - 'register void *pypy_r15 asm("r15");\n' - '#define PYPY_GET_SPECIAL_REG() pypy_r15\n' - '#define PYPY_SPECIAL_REG_NONNULL() (pypy_r15 != NULL)\n' - '#define PYPY_SET_SPECIAL_REG(x) (pypy_r15 = x)\n' - ], - ) - -_test_eci = eci.merge(ExternalCompilationInfo( - post_include_bits=[""" - void f(void) { - pypy_r15 = &f; - } - """])) - -try: - rffi_platform.verify_eci(_test_eci) - register_number = 15 # r15 -except rffi_platform.CompilationError: - eci = None - register_number = None -else: - - from pypy.rpython.lltypesystem import lltype, llmemory, rffi - - # use addr=load_from_reg() and store_into_reg(addr) to load and store - # an Address out of the special register. When running on top of Python, - # the behavior is emulated. - - _value_reg = None - - def _pypy_get_special_reg(): - assert _value_reg is not None - return _value_reg - - def _pypy_special_reg_nonnull(): - assert _value_reg is not None - return bool(_value_reg) - - def _pypy_set_special_reg(addr): - global _value_reg - _value_reg = addr - - load_from_reg = rffi.llexternal('PYPY_GET_SPECIAL_REG', [], - llmemory.Address, - _callable=_pypy_get_special_reg, - compilation_info=eci, - _nowrapper=True) - - reg_is_nonnull = rffi.llexternal('PYPY_SPECIAL_REG_NONNULL', [], - lltype.Bool, - _callable=_pypy_special_reg_nonnull, - compilation_info=eci, - _nowrapper=True) - - store_into_reg = rffi.llexternal('PYPY_SET_SPECIAL_REG', - [llmemory.Address], - lltype.Void, - _callable=_pypy_set_special_reg, - compilation_info=eci, - _nowrapper=True) - - # xxx temporary - nonnull = llmemory.cast_int_to_adr(-1) diff --git a/pypy/rlib/test/test_register.py b/pypy/rlib/test/test_register.py deleted file mode 100644 --- a/pypy/rlib/test/test_register.py +++ /dev/null @@ -1,55 +0,0 @@ -import py -from pypy.rlib import register -from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.translator.c.test.test_standalone import StandaloneTests - - -def test_register(): - # - from pypy.jit.backend.detect_cpu import autodetect - if autodetect() == 'x86_64': - assert register.eci is not None - assert register.register_number == 15 # r15 - else: - assert register.eci is None - assert register.register_number is None - - -class TestLoadStore(object): - def setup_class(cls): - if register.register_number is None: - py.test.skip("rlib/register not supported on this platform") - - def test_direct(self): - a = rffi.cast(llmemory.Address, 27) - register.store_into_reg(a) - b = register.load_from_reg() - assert lltype.typeOf(b) == llmemory.Address - assert rffi.cast(lltype.Signed, b) == 27 - - def test_llinterp(self): - from pypy.rpython.test.test_llinterp import interpret - def f(n): - a = rffi.cast(llmemory.Address, n) - register.store_into_reg(a) - b = register.load_from_reg() - return rffi.cast(lltype.Signed, b) - res = interpret(f, [41]) - assert res == 41 - - -class TestLoadStoreCompiled(StandaloneTests): - def setup_class(cls): - if register.register_number is None: - py.test.skip("rlib/register not supported on this platform") - - def test_compiled(self): - def f(argv): - a = rffi.cast(llmemory.Address, 43) - register.store_into_reg(a) - b = register.load_from_reg() - print rffi.cast(lltype.Signed, b) - return 0 - t, cbuilder = self.compile(f) - data = cbuilder.cmdexec('') - assert data.startswith('43\n') diff --git a/pypy/translator/c/database.py b/pypy/translator/c/database.py --- a/pypy/translator/c/database.py +++ b/pypy/translator/c/database.py @@ -60,8 +60,7 @@ if translator is None or translator.rtyper is None: self.exctransformer = None else: - self.exctransformer = translator.getexceptiontransformer( - standalone=standalone) + self.exctransformer = translator.getexceptiontransformer() if translator is not None: self.gctransformer = self.gcpolicy.transformerclass(translator) self.completed = False diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h --- a/pypy/translator/c/src/main.h +++ b/pypy/translator/c/src/main.h @@ -34,10 +34,6 @@ char *errmsg; int i, exitcode; RPyListOfString *list; -#ifdef PYPY_GET_SPECIAL_REG - void *pypy_reg_oldvalue = PYPY_GET_SPECIAL_REG(); - PYPY_SET_SPECIAL_REG((void*)-1); -#endif pypy_asm_stack_bottom(); instrument_setup(); @@ -74,10 +70,6 @@ pypy_debug_catch_fatal_exception(); } -#ifdef PYPY_GET_SPECIAL_REG - PYPY_SET_SPECIAL_REG(pypy_reg_oldvalue); -#endif - return exitcode; memory_out: @@ -87,7 +79,7 @@ fprintf(stderr, "Fatal error during initialization: %s\n", errmsg); #endif abort(); - return 1; /* not actually reachable */ + return 1; } int PYPY_MAIN_FUNCTION(int argc, char *argv[]) diff --git a/pypy/translator/exceptiontransform.py b/pypy/translator/exceptiontransform.py --- a/pypy/translator/exceptiontransform.py +++ b/pypy/translator/exceptiontransform.py @@ -14,7 +14,6 @@ from pypy.rlib.rarithmetic import r_singlefloat from pypy.rlib.debug import ll_assert from pypy.rlib.rstackovf import _StackOverflow -from pypy.rlib import register from pypy.annotation import model as annmodel from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.tool.sourcetools import func_with_new_name @@ -52,9 +51,8 @@ class BaseExceptionTransformer(object): - def __init__(self, translator, standalone): + def __init__(self, translator): self.translator = translator - self.standalone = standalone self.raise_analyzer = canraise.RaiseAnalyzer(translator) edata = translator.rtyper.getexceptiondata() self.lltype_of_exception_value = edata.lltype_of_exception_value @@ -74,21 +72,9 @@ assertion_error_ll_exc_type) self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type) - use_special_reg = standalone and register.register_number is not None - self.use_special_reg = use_special_reg - if use_special_reg: - self.c_nonnull_specialregister = constant_value(register.nonnull) - self.c_load_from_reg = constant_value(register.load_from_reg) - self.c_reg_is_nonnull = constant_value(register.reg_is_nonnull) - self.c_store_into_reg = constant_value(register.store_into_reg) - def rpyexc_occured(): - if use_special_reg: - # an exception occurred iff the special register is 0 - return register.load_from_reg() == llmemory.NULL - else: - exc_type = exc_data.exc_type - return bool(exc_type) + exc_type = exc_data.exc_type + return bool(exc_type) def rpyexc_fetch_type(): return exc_data.exc_type @@ -97,8 +83,6 @@ return exc_data.exc_value def rpyexc_clear(): - if use_special_reg: - register.store_into_reg(register.nonnull) exc_data.exc_type = null_type exc_data.exc_value = null_value @@ -115,15 +99,11 @@ exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_start_traceback(lltype.Void, etype) - if use_special_reg: - register.store_into_reg(llmemory.NULL) def rpyexc_reraise(etype, evalue): exc_data.exc_type = etype exc_data.exc_value = evalue lloperation.llop.debug_reraise_traceback(lltype.Void, etype) - if use_special_reg: - register.store_into_reg(llmemory.NULL) def rpyexc_fetch_exception(): evalue = rpyexc_fetch_value() @@ -134,8 +114,6 @@ if evalue: exc_data.exc_type = rclass.ll_inst_type(evalue) exc_data.exc_value = evalue - if use_special_reg: - register.store_into_reg(llmemory.NULL) def rpyexc_raise_stack_overflow(): rpyexc_raise(stackovf_ll_exc_type, stackovf_ll_exc) @@ -431,8 +409,6 @@ # self.gen_setfield('exc_value', self.c_null_evalue, llops) self.gen_setfield('exc_type', self.c_null_etype, llops) - if self.use_special_reg: - self.gen_setspecialregister(self.c_nonnull_specialregister, llops) excblock.operations[:] = llops newgraph.exceptblock.inputargs[0].concretetype = self.lltype_of_exception_type newgraph.exceptblock.inputargs[1].concretetype = self.lltype_of_exception_value @@ -456,8 +432,6 @@ if alloc_shortcut: T = spaceop.result.concretetype var_no_exc = self.gen_nonnull(spaceop.result, llops) - elif self.use_special_reg: - var_no_exc = self.gen_specialreg_no_exc(llops) else: v_exc_type = self.gen_getfield('exc_type', llops) var_no_exc = self.gen_isnull(v_exc_type, llops) @@ -553,17 +527,6 @@ def gen_nonnull(self, v, llops): return llops.genop('ptr_nonzero', [v], lltype.Bool) - def gen_getspecialregister(self, llops): - return llops.genop('direct_call', [self.c_load_from_reg], - resulttype = llmemory.Address) - - def gen_specialreg_no_exc(self, llops): - return llops.genop('direct_call', [self.c_reg_is_nonnull], - resulttype = lltype.Bool) - - def gen_setspecialregister(self, v, llops): - llops.genop('direct_call', [self.c_store_into_reg, v]) - def same_obj(self, ptr1, ptr2): return ptr1._same_obj(ptr2) @@ -650,10 +613,10 @@ def build_extra_funcs(self): pass -def ExceptionTransformer(translator, standalone): +def ExceptionTransformer(translator): type_system = translator.rtyper.type_system.name if type_system == 'lltypesystem': - return LLTypeExceptionTransformer(translator, standalone) + return LLTypeExceptionTransformer(translator) else: assert type_system == 'ootypesystem' - return OOTypeExceptionTransformer(translator, standalone) + return OOTypeExceptionTransformer(translator) diff --git a/pypy/translator/translator.py b/pypy/translator/translator.py --- a/pypy/translator/translator.py +++ b/pypy/translator/translator.py @@ -108,14 +108,13 @@ type_system = type_system) return self.rtyper - def getexceptiontransformer(self, standalone): + def getexceptiontransformer(self): if self.rtyper is None: raise ValueError("no rtyper") if self.exceptiontransformer is not None: - assert self.exceptiontransformer.standalone == standalone return self.exceptiontransformer from pypy.translator.exceptiontransform import ExceptionTransformer - self.exceptiontransformer = ExceptionTransformer(self, standalone) + self.exceptiontransformer = ExceptionTransformer(self) return self.exceptiontransformer def checkgraphs(self): From noreply at buildbot.pypy.org Wed Jul 27 18:22:40 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 18:22:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Move the ShadowStackRootWalker in its own file. No other change. Message-ID: <20110727162240.A1BFD82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46017:059ebcb10c75 Date: 2011-07-27 15:37 +0200 http://bitbucket.org/pypy/pypy/changeset/059ebcb10c75/ Log: Move the ShadowStackRootWalker in its own file. No other change. diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -525,7 +525,8 @@ self.c_vtinfo_skip_offset = rmodel.inputconst(lltype.typeOf(sko), sko) def build_root_walker(self): - return ShadowStackRootWalker(self) + from pypy.rpython.memory.gctransform import shadowstack + return shadowstack.ShadowStackRootWalker(self) def consider_constant(self, TYPE, value): self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc) @@ -1323,217 +1324,3 @@ def need_thread_support(self, gctransformer, getfn): raise Exception("%s does not support threads" % ( self.__class__.__name__,)) - - -class ShadowStackRootWalker(BaseRootWalker): - need_root_stack = True - collect_stacks_from_other_threads = None - - def __init__(self, gctransformer): - BaseRootWalker.__init__(self, gctransformer) - self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth - # NB. 'self' is frozen, but we can use self.gcdata to store state - gcdata = self.gcdata - - def incr_stack(n): - top = gcdata.root_stack_top - gcdata.root_stack_top = top + n*sizeofaddr - return top - self.incr_stack = incr_stack - - def decr_stack(n): - top = gcdata.root_stack_top - n*sizeofaddr - gcdata.root_stack_top = top - return top - self.decr_stack = decr_stack - - self.rootstackhook = gctransformer.root_stack_jit_hook - if self.rootstackhook is None: - def collect_stack_root(callback, gc, addr): - if gc.points_to_valid_gc_object(addr): - callback(gc, addr) - return sizeofaddr - self.rootstackhook = collect_stack_root - - def push_stack(self, addr): - top = self.incr_stack(1) - top.address[0] = addr - - def pop_stack(self): - top = self.decr_stack(1) - return top.address[0] - - def allocate_stack(self): - return llmemory.raw_malloc(self.rootstacksize) - - def setup_root_walker(self): - stackbase = self.allocate_stack() - ll_assert(bool(stackbase), "could not allocate root stack") - self.gcdata.root_stack_top = stackbase - self.gcdata.root_stack_base = stackbase - BaseRootWalker.setup_root_walker(self) - - def walk_stack_roots(self, collect_stack_root): - gcdata = self.gcdata - gc = self.gc - rootstackhook = self.rootstackhook - addr = gcdata.root_stack_base - end = gcdata.root_stack_top - while addr != end: - addr += rootstackhook(collect_stack_root, gc, addr) - if self.collect_stacks_from_other_threads is not None: - self.collect_stacks_from_other_threads(collect_stack_root) - - def need_thread_support(self, gctransformer, getfn): - from pypy.module.thread import ll_thread # xxx fish - from pypy.rpython.memory.support import AddressDict - from pypy.rpython.memory.support import copy_without_null_values - gcdata = self.gcdata - # the interfacing between the threads and the GC is done via - # three completely ad-hoc operations at the moment: - # gc_thread_prepare, gc_thread_run, gc_thread_die. - # See docstrings below. - - def get_aid(): - """Return the thread identifier, cast to an (opaque) address.""" - return llmemory.cast_int_to_adr(ll_thread.get_ident()) - - def thread_setup(): - """Called once when the program starts.""" - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} - gcdata._fresh_rootstack = llmemory.NULL - gcdata.dead_threads_count = 0 - - def thread_prepare(): - """Called just before thread.start_new_thread(). This - allocates a new shadow stack to be used by the future - thread. If memory runs out, this raises a MemoryError - (which can be handled by the caller instead of just getting - ignored if it was raised in the newly starting thread). - """ - if not gcdata._fresh_rootstack: - gcdata._fresh_rootstack = self.allocate_stack() - if not gcdata._fresh_rootstack: - raise MemoryError - - def thread_run(): - """Called whenever the current thread (re-)acquired the GIL. - This should ensure that the shadow stack installed in - gcdata.root_stack_top/root_stack_base is the one corresponding - to the current thread. - """ - aid = get_aid() - if gcdata.active_thread != aid: - switch_shadow_stacks(aid) - - def thread_die(): - """Called just before the final GIL release done by a dying - thread. After a thread_die(), no more gc operation should - occur in this thread. - """ - aid = get_aid() - if aid == gcdata.main_thread: - return # ignore calls to thread_die() in the main thread - # (which can occur after a fork()). - gcdata.thread_stacks.setitem(aid, llmemory.NULL) - old = gcdata.root_stack_base - if gcdata._fresh_rootstack == llmemory.NULL: - gcdata._fresh_rootstack = old - else: - llmemory.raw_free(old) - install_new_stack(gcdata.main_thread) - # from time to time, rehash the dictionary to remove - # old NULL entries - gcdata.dead_threads_count += 1 - if (gcdata.dead_threads_count & 511) == 0: - copy = copy_without_null_values(gcdata.thread_stacks) - gcdata.thread_stacks.delete() - gcdata.thread_stacks = copy - - def switch_shadow_stacks(new_aid): - save_away_current_stack() - install_new_stack(new_aid) - switch_shadow_stacks._dont_inline_ = True - - def save_away_current_stack(): - old_aid = gcdata.active_thread - # save root_stack_base on the top of the stack - self.push_stack(gcdata.root_stack_base) - # store root_stack_top into the dictionary - gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) - - def install_new_stack(new_aid): - # look for the new stack top - top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) - if top == llmemory.NULL: - # first time we see this thread. It is an error if no - # fresh new stack is waiting. - base = gcdata._fresh_rootstack - gcdata._fresh_rootstack = llmemory.NULL - ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") - gcdata.root_stack_top = base - gcdata.root_stack_base = base - else: - # restore the root_stack_base from the top of the stack - gcdata.root_stack_top = top - gcdata.root_stack_base = self.pop_stack() - # done - gcdata.active_thread = new_aid - - def collect_stack(aid, stacktop, callback): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - # collect all valid stacks from the dict (the entry - # corresponding to the current thread is not valid) - gc = self.gc - rootstackhook = self.rootstackhook - end = stacktop - sizeofaddr - addr = end.address[0] - while addr != end: - addr += rootstackhook(callback, gc, addr) - - def collect_more_stacks(callback): - ll_assert(get_aid() == gcdata.active_thread, - "collect_more_stacks(): invalid active_thread") - gcdata.thread_stacks.foreach(collect_stack, callback) - - def _free_if_not_current(aid, stacktop, _): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - end = stacktop - sizeofaddr - base = end.address[0] - llmemory.raw_free(base) - - def thread_after_fork(result_of_fork, opaqueaddr): - # we don't need a thread_before_fork in this case, so - # opaqueaddr == NULL. This is called after fork(). - if result_of_fork == 0: - # We are in the child process. Assumes that only the - # current thread survived, so frees the shadow stacks - # of all the other ones. - gcdata.thread_stacks.foreach(_free_if_not_current, None) - # Clears the dict (including the current thread, which - # was an invalid entry anyway and will be recreated by - # the next call to save_away_current_stack()). - gcdata.thread_stacks.clear() - # Finally, reset the stored thread IDs, in case it - # changed because of fork(). Also change the main - # thread to the current one (because there is not any - # other left). - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - - self.thread_setup = thread_setup - self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) - self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, - inline=True) - # no thread_start_ptr here - self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) - # no thread_before_fork_ptr here - self.thread_after_fork_ptr = getfn(thread_after_fork, - [annmodel.SomeInteger(), - annmodel.SomeAddress()], - annmodel.s_None) - self.collect_stacks_from_other_threads = collect_more_stacks diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py new file mode 100644 --- /dev/null +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -0,0 +1,218 @@ +from pypy.rpython.memory.gctransform.framework import BaseRootWalker +from pypy.rpython.memory.gctransform.framework import sizeofaddr +from pypy.rlib.debug import ll_assert +from pypy.rpython.lltypesystem import llmemory + + +class ShadowStackRootWalker(BaseRootWalker): + need_root_stack = True + collect_stacks_from_other_threads = None + + def __init__(self, gctransformer): + BaseRootWalker.__init__(self, gctransformer) + self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth + # NB. 'self' is frozen, but we can use self.gcdata to store state + gcdata = self.gcdata + + def incr_stack(n): + top = gcdata.root_stack_top + gcdata.root_stack_top = top + n*sizeofaddr + return top + self.incr_stack = incr_stack + + def decr_stack(n): + top = gcdata.root_stack_top - n*sizeofaddr + gcdata.root_stack_top = top + return top + self.decr_stack = decr_stack + + self.rootstackhook = gctransformer.root_stack_jit_hook + if self.rootstackhook is None: + def collect_stack_root(callback, gc, addr): + if gc.points_to_valid_gc_object(addr): + callback(gc, addr) + return sizeofaddr + self.rootstackhook = collect_stack_root + + def push_stack(self, addr): + top = self.incr_stack(1) + top.address[0] = addr + + def pop_stack(self): + top = self.decr_stack(1) + return top.address[0] + + def allocate_stack(self): + return llmemory.raw_malloc(self.rootstacksize) + + def setup_root_walker(self): + stackbase = self.allocate_stack() + ll_assert(bool(stackbase), "could not allocate root stack") + self.gcdata.root_stack_top = stackbase + self.gcdata.root_stack_base = stackbase + BaseRootWalker.setup_root_walker(self) + + def walk_stack_roots(self, collect_stack_root): + gcdata = self.gcdata + gc = self.gc + rootstackhook = self.rootstackhook + addr = gcdata.root_stack_base + end = gcdata.root_stack_top + while addr != end: + addr += rootstackhook(collect_stack_root, gc, addr) + if self.collect_stacks_from_other_threads is not None: + self.collect_stacks_from_other_threads(collect_stack_root) + + def need_thread_support(self, gctransformer, getfn): + from pypy.module.thread import ll_thread # xxx fish + from pypy.rpython.memory.support import AddressDict + from pypy.rpython.memory.support import copy_without_null_values + gcdata = self.gcdata + # the interfacing between the threads and the GC is done via + # three completely ad-hoc operations at the moment: + # gc_thread_prepare, gc_thread_run, gc_thread_die. + # See docstrings below. + + def get_aid(): + """Return the thread identifier, cast to an (opaque) address.""" + return llmemory.cast_int_to_adr(ll_thread.get_ident()) + + def thread_setup(): + """Called once when the program starts.""" + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} + gcdata._fresh_rootstack = llmemory.NULL + gcdata.dead_threads_count = 0 + + def thread_prepare(): + """Called just before thread.start_new_thread(). This + allocates a new shadow stack to be used by the future + thread. If memory runs out, this raises a MemoryError + (which can be handled by the caller instead of just getting + ignored if it was raised in the newly starting thread). + """ + if not gcdata._fresh_rootstack: + gcdata._fresh_rootstack = self.allocate_stack() + if not gcdata._fresh_rootstack: + raise MemoryError + + def thread_run(): + """Called whenever the current thread (re-)acquired the GIL. + This should ensure that the shadow stack installed in + gcdata.root_stack_top/root_stack_base is the one corresponding + to the current thread. + """ + aid = get_aid() + if gcdata.active_thread != aid: + switch_shadow_stacks(aid) + + def thread_die(): + """Called just before the final GIL release done by a dying + thread. After a thread_die(), no more gc operation should + occur in this thread. + """ + aid = get_aid() + if aid == gcdata.main_thread: + return # ignore calls to thread_die() in the main thread + # (which can occur after a fork()). + gcdata.thread_stacks.setitem(aid, llmemory.NULL) + old = gcdata.root_stack_base + if gcdata._fresh_rootstack == llmemory.NULL: + gcdata._fresh_rootstack = old + else: + llmemory.raw_free(old) + install_new_stack(gcdata.main_thread) + # from time to time, rehash the dictionary to remove + # old NULL entries + gcdata.dead_threads_count += 1 + if (gcdata.dead_threads_count & 511) == 0: + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy + + def switch_shadow_stacks(new_aid): + save_away_current_stack() + install_new_stack(new_aid) + switch_shadow_stacks._dont_inline_ = True + + def save_away_current_stack(): + old_aid = gcdata.active_thread + # save root_stack_base on the top of the stack + self.push_stack(gcdata.root_stack_base) + # store root_stack_top into the dictionary + gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) + + def install_new_stack(new_aid): + # look for the new stack top + top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) + if top == llmemory.NULL: + # first time we see this thread. It is an error if no + # fresh new stack is waiting. + base = gcdata._fresh_rootstack + gcdata._fresh_rootstack = llmemory.NULL + ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") + gcdata.root_stack_top = base + gcdata.root_stack_base = base + else: + # restore the root_stack_base from the top of the stack + gcdata.root_stack_top = top + gcdata.root_stack_base = self.pop_stack() + # done + gcdata.active_thread = new_aid + + def collect_stack(aid, stacktop, callback): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + # collect all valid stacks from the dict (the entry + # corresponding to the current thread is not valid) + gc = self.gc + rootstackhook = self.rootstackhook + end = stacktop - sizeofaddr + addr = end.address[0] + while addr != end: + addr += rootstackhook(callback, gc, addr) + + def collect_more_stacks(callback): + ll_assert(get_aid() == gcdata.active_thread, + "collect_more_stacks(): invalid active_thread") + gcdata.thread_stacks.foreach(collect_stack, callback) + + def _free_if_not_current(aid, stacktop, _): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + end = stacktop - sizeofaddr + base = end.address[0] + llmemory.raw_free(base) + + def thread_after_fork(result_of_fork, opaqueaddr): + # we don't need a thread_before_fork in this case, so + # opaqueaddr == NULL. This is called after fork(). + if result_of_fork == 0: + # We are in the child process. Assumes that only the + # current thread survived, so frees the shadow stacks + # of all the other ones. + gcdata.thread_stacks.foreach(_free_if_not_current, None) + # Clears the dict (including the current thread, which + # was an invalid entry anyway and will be recreated by + # the next call to save_away_current_stack()). + gcdata.thread_stacks.clear() + # Finally, reset the stored thread IDs, in case it + # changed because of fork(). Also change the main + # thread to the current one (because there is not any + # other left). + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + + self.thread_setup = thread_setup + self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) + self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, + inline=True) + # no thread_start_ptr here + self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) + # no thread_before_fork_ptr here + self.thread_after_fork_ptr = getfn(thread_after_fork, + [annmodel.SomeInteger(), + annmodel.SomeAddress()], + annmodel.s_None) + self.collect_stacks_from_other_threads = collect_more_stacks From noreply at buildbot.pypy.org Wed Jul 27 18:22:41 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 18:22:41 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge 0cdaf4c98369, moving regalloc.py to a general tool Message-ID: <20110727162241.D28F182110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46018:afb404b14725 Date: 2011-07-27 15:47 +0200 http://bitbucket.org/pypy/pypy/changeset/afb404b14725/ Log: Merge 0cdaf4c98369, moving regalloc.py to a general tool in pypy/tool/algo/. diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -1,129 +1,8 @@ -import sys -from pypy.objspace.flow.model import Variable -from pypy.tool.algo.color import DependencyGraph -from pypy.tool.algo.unionfind import UnionFind +from pypy.tool.algo import regalloc from pypy.jit.metainterp.history import getkind from pypy.jit.codewriter.flatten import ListOfKind + def perform_register_allocation(graph, kind): - """Perform register allocation for the Variables of the given 'kind' - in the 'graph'.""" - regalloc = RegAllocator(graph, kind) - regalloc.make_dependencies() - regalloc.coalesce_variables() - regalloc.find_node_coloring() - return regalloc - - -class RegAllocator(object): - DEBUG_REGALLOC = False - - def __init__(self, graph, kind): - self.graph = graph - self.kind = kind - - def make_dependencies(self): - dg = DependencyGraph() - for block in self.graph.iterblocks(): - # Compute die_at = {Variable: index_of_operation_with_last_usage} - die_at = dict.fromkeys(block.inputargs, 0) - for i, op in enumerate(block.operations): - for v in op.args: - if isinstance(v, Variable): - die_at[v] = i - elif isinstance(v, ListOfKind): - for v1 in v: - if isinstance(v1, Variable): - die_at[v1] = i - if op.result is not None: - die_at[op.result] = i + 1 - if isinstance(block.exitswitch, tuple): - for x in block.exitswitch: - die_at.pop(x, None) - else: - die_at.pop(block.exitswitch, None) - for link in block.exits: - for v in link.args: - die_at.pop(v, None) - die_at = [(value, key) for (key, value) in die_at.items()] - die_at.sort() - die_at.append((sys.maxint,)) - # Done. XXX the code above this line runs 3 times - # (for kind in KINDS) to produce the same result... - livevars = [v for v in block.inputargs - if getkind(v.concretetype) == self.kind] - # Add the variables of this block to the dependency graph - for i, v in enumerate(livevars): - dg.add_node(v) - for j in range(i): - dg.add_edge(livevars[j], v) - livevars = set(livevars) - die_index = 0 - for i, op in enumerate(block.operations): - while die_at[die_index][0] == i: - try: - livevars.remove(die_at[die_index][1]) - except KeyError: - pass - die_index += 1 - if (op.result is not None and - getkind(op.result.concretetype) == self.kind): - dg.add_node(op.result) - for v in livevars: - if getkind(v.concretetype) == self.kind: - dg.add_edge(v, op.result) - livevars.add(op.result) - self._depgraph = dg - - def coalesce_variables(self): - self._unionfind = UnionFind() - pendingblocks = list(self.graph.iterblocks()) - while pendingblocks: - block = pendingblocks.pop() - # Aggressively try to coalesce each source variable with its - # target. We start from the end of the graph instead of - # from the beginning. This is a bit arbitrary, but the idea - # is that the end of the graph runs typically more often - # than the start, given that we resume execution from the - # middle during blackholing. - for link in block.exits: - if link.last_exception is not None: - self._depgraph.add_node(link.last_exception) - if link.last_exc_value is not None: - self._depgraph.add_node(link.last_exc_value) - for i, v in enumerate(link.args): - self._try_coalesce(v, link.target.inputargs[i]) - - def _try_coalesce(self, v, w): - if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: - assert getkind(w.concretetype) == self.kind - dg = self._depgraph - uf = self._unionfind - v0 = uf.find_rep(v) - w0 = uf.find_rep(w) - if v0 is not w0 and v0 not in dg.neighbours[w0]: - _, rep, _ = uf.union(v0, w0) - assert uf.find_rep(v0) is uf.find_rep(w0) is rep - if rep is v0: - dg.coalesce(w0, v0) - else: - assert rep is w0 - dg.coalesce(v0, w0) - - def find_node_coloring(self): - self._coloring = self._depgraph.find_node_coloring() - if self.DEBUG_REGALLOC: - for block in self.graph.iterblocks(): - print block - for v in block.getvariables(): - print '\t', v, '\t', self.getcolor(v) - - def getcolor(self, v): - return self._coloring[self._unionfind.find_rep(v)] - - def swapcolors(self, col1, col2): - for key, value in self._coloring.items(): - if value == col1: - self._coloring[key] = col2 - elif value == col2: - self._coloring[key] = col1 + checkkind = lambda v: getkind(v.concretetype) == kind + return regalloc.perform_register_allocation(graph, checkkind, ListOfKind) diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/tool/algo/regalloc.py copy from pypy/jit/codewriter/regalloc.py copy to pypy/tool/algo/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/tool/algo/regalloc.py @@ -2,13 +2,11 @@ from pypy.objspace.flow.model import Variable from pypy.tool.algo.color import DependencyGraph from pypy.tool.algo.unionfind import UnionFind -from pypy.jit.metainterp.history import getkind -from pypy.jit.codewriter.flatten import ListOfKind -def perform_register_allocation(graph, kind): +def perform_register_allocation(graph, consider_var, ListOfKind=()): """Perform register allocation for the Variables of the given 'kind' in the 'graph'.""" - regalloc = RegAllocator(graph, kind) + regalloc = RegAllocator(graph, consider_var, ListOfKind) regalloc.make_dependencies() regalloc.coalesce_variables() regalloc.find_node_coloring() @@ -18,9 +16,10 @@ class RegAllocator(object): DEBUG_REGALLOC = False - def __init__(self, graph, kind): + def __init__(self, graph, consider_var, ListOfKind): self.graph = graph - self.kind = kind + self.consider_var = consider_var + self.ListOfKind = ListOfKind def make_dependencies(self): dg = DependencyGraph() @@ -31,7 +30,7 @@ for v in op.args: if isinstance(v, Variable): die_at[v] = i - elif isinstance(v, ListOfKind): + elif isinstance(v, self.ListOfKind): for v1 in v: if isinstance(v1, Variable): die_at[v1] = i @@ -51,7 +50,7 @@ # Done. XXX the code above this line runs 3 times # (for kind in KINDS) to produce the same result... livevars = [v for v in block.inputargs - if getkind(v.concretetype) == self.kind] + if self.consider_var(v)] # Add the variables of this block to the dependency graph for i, v in enumerate(livevars): dg.add_node(v) @@ -67,10 +66,10 @@ pass die_index += 1 if (op.result is not None and - getkind(op.result.concretetype) == self.kind): + self.consider_var(op.result)): dg.add_node(op.result) for v in livevars: - if getkind(v.concretetype) == self.kind: + if self.consider_var(v): dg.add_edge(v, op.result) livevars.add(op.result) self._depgraph = dg @@ -95,8 +94,8 @@ self._try_coalesce(v, link.target.inputargs[i]) def _try_coalesce(self, v, w): - if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: - assert getkind(w.concretetype) == self.kind + if isinstance(v, Variable) and self.consider_var(v): + assert self.consider_var(w) dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) From noreply at buildbot.pypy.org Wed Jul 27 18:22:48 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 18:22:48 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: hg merge default Message-ID: <20110727162248.B0AD782110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r46019:bf56d77d981a Date: 2011-07-27 15:52 +0200 http://bitbucket.org/pypy/pypy/changeset/bf56d77d981a/ Log: hg merge default diff too long, truncating to 10000 out of 21630 lines diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,6 +1,7 @@ syntax: glob *.py[co] *~ +.*.swp syntax: regexp ^testresult$ @@ -38,6 +39,8 @@ ^pypy/translator/benchmark/shootout_benchmarks$ ^pypy/translator/goal/pypy-translation-snapshot$ ^pypy/translator/goal/pypy-c +^pypy/translator/goal/pypy-jvm +^pypy/translator/goal/pypy-jvm.jar ^pypy/translator/goal/.+\.exe$ ^pypy/translator/goal/.+\.dll$ ^pypy/translator/goal/target.+-c$ diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -1,1 +1,2 @@ b590cf6de4190623aad9aa698694c22e614d67b9 release-1.5 +b48df0bf4e75b81d98f19ce89d4a7dc3e1dab5e5 benchmarked diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -185,6 +185,7 @@ Jim Baker Philip Jenvey Rodrigo Araújo + Brett Cannon Heinrich-Heine University, Germany Open End AB (formerly AB Strakt), Sweden diff --git a/lib-python/modified-2.7/ctypes/__init__.py b/lib-python/modified-2.7/ctypes/__init__.py --- a/lib-python/modified-2.7/ctypes/__init__.py +++ b/lib-python/modified-2.7/ctypes/__init__.py @@ -489,9 +489,12 @@ _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI return CFunctionType -_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr) def cast(obj, typ): - return _cast(obj, obj, typ) + try: + c_void_p.from_param(obj) + except TypeError, e: + raise ArgumentError(str(e)) + return _cast_addr(obj, obj, typ) _string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) def string_at(ptr, size=-1): diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py --- a/lib-python/modified-2.7/distutils/cygwinccompiler.py +++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py @@ -75,6 +75,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py --- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py +++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py @@ -116,6 +116,12 @@ if compiler.compiler_type == "unix": compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') + if "CFLAGS" in os.environ: + cflags = os.environ["CFLAGS"] + compiler.compiler.append(cflags) + compiler.compiler_so.append(cflags) + compiler.linker_so.append(cflags) + from sysconfig_cpython import ( parse_makefile, _variable_rx, expand_makefile_vars) diff --git a/lib-python/modified-2.7/opcode.py b/lib-python/modified-2.7/opcode.py --- a/lib-python/modified-2.7/opcode.py +++ b/lib-python/modified-2.7/opcode.py @@ -189,7 +189,6 @@ def_op('MAP_ADD', 147) # pypy modification, experimental bytecode -def_op('CALL_LIKELY_BUILTIN', 200) # #args + (#kwargs << 8) def_op('LOOKUP_METHOD', 201) # Index in name list hasname.append(201) def_op('CALL_METHOD', 202) # #args not including 'self' diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py --- a/lib-python/modified-2.7/pickle.py +++ b/lib-python/modified-2.7/pickle.py @@ -168,7 +168,7 @@ # Pickling machinery -class Pickler: +class Pickler(object): def __init__(self, file, protocol=None): """This takes a file-like object for writing a pickle data stream. diff --git a/lib-python/modified-2.7/test/test_descr.py b/lib-python/modified-2.7/test/test_descr.py --- a/lib-python/modified-2.7/test/test_descr.py +++ b/lib-python/modified-2.7/test/test_descr.py @@ -4400,7 +4400,10 @@ self.assertTrue(l.__add__ != l.__mul__) self.assertTrue(l.__add__.__name__ == '__add__') self.assertTrue(l.__add__.__self__ is l) - self.assertTrue(l.__add__.__objclass__ is list) + if hasattr(l.__add__, '__objclass__'): # CPython + self.assertTrue(l.__add__.__objclass__ is list) + else: # PyPy + self.assertTrue(l.__add__.im_class is list) self.assertEqual(l.__add__.__doc__, list.__add__.__doc__) try: hash(l.__add__) diff --git a/lib-python/modified-2.7/test/test_dis.py b/lib-python/modified-2.7/test/test_dis.py deleted file mode 100644 --- a/lib-python/modified-2.7/test/test_dis.py +++ /dev/null @@ -1,152 +0,0 @@ -# Minimal tests for dis module - -from test.test_support import run_unittest -import unittest -import sys -import dis -import StringIO - - -def _f(a): - print a - return 1 - -dis_f = """\ - %-4d 0 LOAD_FAST 0 (a) - 3 PRINT_ITEM - 4 PRINT_NEWLINE - - %-4d 5 LOAD_CONST 1 (1) - 8 RETURN_VALUE -"""%(_f.func_code.co_firstlineno + 1, - _f.func_code.co_firstlineno + 2) - - -# we "call" rangexxx() instead of range() to disable the -# pypy optimization that turns it into CALL_LIKELY_BUILTIN. -def bug708901(): - for res in rangexxx(1, - 10): - pass - -dis_bug708901 = """\ - %-4d 0 SETUP_LOOP 23 (to 26) - 3 LOAD_GLOBAL 0 (rangexxx) - 6 LOAD_CONST 1 (1) - - %-4d 9 LOAD_CONST 2 (10) - 12 CALL_FUNCTION 2 - 15 GET_ITER - >> 16 FOR_ITER 6 (to 25) - 19 STORE_FAST 0 (res) - - %-4d 22 JUMP_ABSOLUTE 16 - >> 25 POP_BLOCK - >> 26 LOAD_CONST 0 (None) - 29 RETURN_VALUE -"""%(bug708901.func_code.co_firstlineno + 1, - bug708901.func_code.co_firstlineno + 2, - bug708901.func_code.co_firstlineno + 3) - - -def bug1333982(x=[]): - assert 0, ([s for s in x] + - 1) - pass - -dis_bug1333982 = """\ - %-4d 0 LOAD_CONST 1 (0) - 3 POP_JUMP_IF_TRUE 38 - 6 LOAD_GLOBAL 0 (AssertionError) - 9 BUILD_LIST 0 - 12 LOAD_FAST 0 (x) - 15 GET_ITER - >> 16 FOR_ITER 12 (to 31) - 19 STORE_FAST 1 (s) - 22 LOAD_FAST 1 (s) - 25 LIST_APPEND 2 - 28 JUMP_ABSOLUTE 16 - - %-4d >> 31 LOAD_CONST 2 (1) - 34 BINARY_ADD - 35 RAISE_VARARGS 2 - - %-4d >> 38 LOAD_CONST 0 (None) - 41 RETURN_VALUE -"""%(bug1333982.func_code.co_firstlineno + 1, - bug1333982.func_code.co_firstlineno + 2, - bug1333982.func_code.co_firstlineno + 3) - -_BIG_LINENO_FORMAT = """\ -%3d 0 LOAD_GLOBAL 0 (spam) - 3 POP_TOP - 4 LOAD_CONST 0 (None) - 7 RETURN_VALUE -""" - -class DisTests(unittest.TestCase): - def do_disassembly_test(self, func, expected): - s = StringIO.StringIO() - save_stdout = sys.stdout - sys.stdout = s - dis.dis(func) - sys.stdout = save_stdout - got = s.getvalue() - # Trim trailing blanks (if any). - lines = got.split('\n') - lines = [line.rstrip() for line in lines] - expected = expected.split("\n") - import difflib - if expected != lines: - self.fail( - "events did not match expectation:\n" + - "\n".join(difflib.ndiff(expected, - lines))) - - def test_opmap(self): - self.assertEqual(dis.opmap["STOP_CODE"], 0) - self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) - self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) - - def test_opname(self): - self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") - - def test_boundaries(self): - self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) - self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) - - def test_dis(self): - self.do_disassembly_test(_f, dis_f) - - def test_bug_708901(self): - self.do_disassembly_test(bug708901, dis_bug708901) - - def test_bug_1333982(self): - # This one is checking bytecodes generated for an `assert` statement, - # so fails if the tests are run with -O. Skip this test then. - if __debug__: - self.do_disassembly_test(bug1333982, dis_bug1333982) - - def test_big_linenos(self): - def func(count): - namespace = {} - func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) - exec func in namespace - return namespace['foo'] - - # Test all small ranges - for i in xrange(1, 300): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - - # Test some larger ranges too - for i in xrange(300, 5000, 10): - expected = _BIG_LINENO_FORMAT % (i + 2) - self.do_disassembly_test(func(i), expected) - -def test_main(): - run_unittest(DisTests) - - -if __name__ == "__main__": - test_main() diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py copy from lib-python/2.7/test/test_sets.py copy to lib-python/modified-2.7/test/test_sets.py --- a/lib-python/2.7/test/test_sets.py +++ b/lib-python/modified-2.7/test/test_sets.py @@ -686,7 +686,9 @@ set_list = sorted(self.set) self.assertEqual(len(dup_list), len(set_list)) for i, el in enumerate(dup_list): - self.assertIs(el, set_list[i]) + # Object identity is not guarnteed for immutable objects, so we + # can't use assertIs here. + self.assertEqual(el, set_list[i]) def test_deep_copy(self): dup = copy.deepcopy(self.set) diff --git a/lib-python/2.7/test/test_tarfile.py b/lib-python/modified-2.7/test/test_tarfile.py copy from lib-python/2.7/test/test_tarfile.py copy to lib-python/modified-2.7/test/test_tarfile.py --- a/lib-python/2.7/test/test_tarfile.py +++ b/lib-python/modified-2.7/test/test_tarfile.py @@ -169,6 +169,7 @@ except tarfile.ReadError: self.fail("tarfile.open() failed on empty archive") self.assertListEqual(tar.getmembers(), []) + tar.close() def test_null_tarfile(self): # Test for issue6123: Allow opening empty archives. @@ -207,16 +208,21 @@ fobj = open(self.tarname, "rb") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, os.path.abspath(fobj.name)) + tar.close() def test_no_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) self.assertRaises(AttributeError, getattr, fobj, "name") tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, None) def test_empty_name_attribute(self): - data = open(self.tarname, "rb").read() + f = open(self.tarname, "rb") + data = f.read() + f.close() fobj = StringIO.StringIO(data) fobj.name = "" tar = tarfile.open(fileobj=fobj, mode=self.mode) @@ -515,6 +521,7 @@ self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1") tarinfo = self.tar.getmember("pax/umlauts-�������") self._test_member(tarinfo, size=7011, chksum=md5_regtype) + self.tar.close() class LongnameTest(ReadTest): @@ -675,6 +682,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.rmdir(path) @@ -692,6 +700,7 @@ tar.gettarinfo(target) tarinfo = tar.gettarinfo(link) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(target) os.remove(link) @@ -704,6 +713,7 @@ tar = tarfile.open(tmpname, self.mode) tarinfo = tar.gettarinfo(path) self.assertEqual(tarinfo.size, 0) + tar.close() finally: os.remove(path) @@ -722,6 +732,7 @@ tar.add(dstname) os.chdir(cwd) self.assertTrue(tar.getnames() == [], "added the archive to itself") + tar.close() def test_exclude(self): tempdir = os.path.join(TEMPDIR, "exclude") @@ -742,6 +753,7 @@ tar = tarfile.open(tmpname, "r") self.assertEqual(len(tar.getmembers()), 1) self.assertEqual(tar.getnames()[0], "empty_dir") + tar.close() finally: shutil.rmtree(tempdir) @@ -859,7 +871,9 @@ fobj.close() elif self.mode.endswith("bz2"): dec = bz2.BZ2Decompressor() - data = open(tmpname, "rb").read() + f = open(tmpname, "rb") + data = f.read() + f.close() data = dec.decompress(data) self.assertTrue(len(dec.unused_data) == 0, "found trailing data") @@ -938,6 +952,7 @@ "unable to read longname member") self.assertEqual(tarinfo.linkname, member.linkname, "unable to read longname member") + tar.close() def test_longname_1023(self): self._test(("longnam/" * 127) + "longnam") @@ -1030,6 +1045,7 @@ else: n = tar.getmembers()[0].name self.assertTrue(name == n, "PAX longname creation failed") + tar.close() def test_pax_global_header(self): pax_headers = { @@ -1058,6 +1074,7 @@ tarfile.PAX_NUMBER_FIELDS[key](val) except (TypeError, ValueError): self.fail("unable to convert pax header field") + tar.close() def test_pax_extended_header(self): # The fields from the pax header have priority over the @@ -1077,6 +1094,7 @@ self.assertEqual(t.pax_headers, pax_headers) self.assertEqual(t.name, "foo") self.assertEqual(t.uid, 123) + tar.close() class UstarUnicodeTest(unittest.TestCase): @@ -1120,6 +1138,7 @@ tarinfo.name = "foo" tarinfo.uname = u"���" self.assertRaises(UnicodeError, tar.addfile, tarinfo) + tar.close() def test_unicode_argument(self): tar = tarfile.open(tarname, "r", encoding="iso8859-1", errors="strict") @@ -1174,6 +1193,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="ascii", errors=handler) self.assertEqual(tar.getnames()[0], name) + tar.close() self.assertRaises(UnicodeError, tarfile.open, tmpname, encoding="ascii", errors="strict") @@ -1186,6 +1206,7 @@ tar = tarfile.open(tmpname, format=self.format, encoding="iso8859-1", errors="utf-8") self.assertEqual(tar.getnames()[0], "���/" + u"�".encode("utf8")) + tar.close() class AppendTest(unittest.TestCase): @@ -1213,6 +1234,7 @@ def _test(self, names=["bar"], fileobj=None): tar = tarfile.open(self.tarname, fileobj=fileobj) self.assertEqual(tar.getnames(), names) + tar.close() def test_non_existing(self): self._add_testfile() @@ -1231,7 +1253,9 @@ def test_fileobj(self): self._create_testtar() - data = open(self.tarname).read() + f = open(self.tarname) + data = f.read() + f.close() fobj = StringIO.StringIO(data) self._add_testfile(fobj) fobj.seek(0) @@ -1257,7 +1281,9 @@ # Append mode is supposed to fail if the tarfile to append to # does not end with a zero block. def _test_error(self, data): - open(self.tarname, "wb").write(data) + f = open(self.tarname, "wb") + f.write(data) + f.close() self.assertRaises(tarfile.ReadError, self._add_testfile) def test_null(self): diff --git a/lib-python/modified-2.7/test/test_weakref.py b/lib-python/modified-2.7/test/test_weakref.py --- a/lib-python/modified-2.7/test/test_weakref.py +++ b/lib-python/modified-2.7/test/test_weakref.py @@ -993,13 +993,13 @@ self.assertTrue(len(weakdict) == 2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 1) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) k, v = weakdict.popitem() self.assertTrue(len(weakdict) == 0) - if k is key1: + if k == key1: self.assertTrue(v is value1) else: self.assertTrue(v is value2) diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py --- a/lib_pypy/_ctypes/__init__.py +++ b/lib_pypy/_ctypes/__init__.py @@ -18,7 +18,16 @@ if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - CopyComPointer = None # XXX + + def CopyComPointer(src, dst): + from ctypes import c_void_p, cast + if src: + hr = src[0][0].AddRef(src) + if hr & 0x80000000: + return hr + dst[0] = cast(src, c_void_p).value + return 0 + LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -48,7 +48,8 @@ return self.from_param(as_parameter) def get_ffi_param(self, value): - return self.from_param(value)._to_ffi_param() + cdata = self.from_param(value) + return cdata, cdata._to_ffi_param() def get_ffi_argtype(self): if self._ffiargtype: @@ -139,7 +140,10 @@ return buffer(self._buffer) def _get_b_base(self): - return self._base + try: + return self._base + except AttributeError: + return None _b_base_ = property(_get_b_base) _b_needsfree_ = False @@ -218,5 +222,7 @@ 'z' : _ffi.types.void_p, 'O' : _ffi.types.void_p, 'Z' : _ffi.types.void_p, + 'X' : _ffi.types.void_p, + 'v' : _ffi.types.sshort, } diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -296,13 +296,12 @@ "This function takes %d argument%s (%s given)" % (len(self._argtypes_), plural, len(args))) - # check that arguments are convertible - ## XXX Not as long as ctypes.cast is a callback function with - ## py_object arguments... - ## self._convert_args(self._argtypes_, args, {}) - try: - res = self.callable(*args) + newargs = self._convert_args_for_callback(argtypes, args) + except (UnicodeError, TypeError, ValueError), e: + raise ArgumentError(str(e)) + try: + res = self.callable(*newargs) except: exc_info = sys.exc_info() traceback.print_tb(exc_info[2], file=sys.stderr) @@ -322,20 +321,20 @@ RuntimeWarning, stacklevel=2) if self._com_index: - assert False, 'TODO2' from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter" ) - thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents - argtypes = [c_void_p] + list(argtypes) - args = list(args) - args[0] = args[0].value + thisarg = cast(args[0], POINTER(POINTER(c_void_p))) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args[1:], kwargs) + newargs.insert(0, args[0].value) + argtypes.insert(0, c_void_p) else: thisarg = None - - newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs) + keepalives, newargs, argtypes, outargs = self._convert_args(argtypes, + args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) @@ -343,6 +342,11 @@ if not outargs: return result + + simple_cdata = type(c_void_p()).__bases__[0] + outargs = [x.value if type(x).__bases__[0] is simple_cdata else x + for x in outargs] + if len(outargs) == 1: return outargs[0] return tuple(outargs) @@ -398,10 +402,10 @@ # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") - ptr = thisarg[self._com_index - 0x1000] - argshapes = [arg._ffiargshape for arg in argtypes] - resshape = restype._ffiargshape - return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) + ptr = thisarg[0][self._com_index - 0x1000] + ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] + ffires = restype.get_ffi_argtype() + return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires) cdll = self.dll._handle try: @@ -434,16 +438,15 @@ @classmethod def _conv_param(cls, argtype, arg): if isinstance(argtype, _CDataMeta): - #arg = argtype.from_param(arg) - arg = argtype.get_ffi_param(arg) - return arg, argtype + cobj, ffiparam = argtype.get_ffi_param(arg) + return cobj, ffiparam, argtype if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): - return arg._to_ffi_param(), type(arg) + return arg, arg._to_ffi_param(), type(arg) # # non-usual case: we do the import here to save a lot of code in the # jit trace of the normal case @@ -460,19 +463,28 @@ else: raise TypeError("Don't know how to handle %s" % (arg,)) - return cobj._to_ffi_param(), type(cobj) + return cobj, cobj._to_ffi_param(), type(cobj) + + def _convert_args_for_callback(self, argtypes, args): + assert len(argtypes) == len(args) + newargs = [] + for argtype, arg in zip(argtypes, args): + param = argtype.from_param(arg) + if argtype._type_ == 'P': # special-case for c_void_p + param = param._get_buffer_value() + elif self._is_primitive(argtype): + param = param.value + newargs.append(param) + return newargs def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] + keepalives = [] newargtypes = [] total = len(args) paramflags = self._paramflags - - if self._com_index: - inargs_idx = 1 - else: - inargs_idx = 0 + inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") @@ -496,7 +508,8 @@ val = defval if val is marker: val = 0 - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): @@ -512,28 +525,32 @@ raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") - newarg, newargtype = self._conv_param(argtype, val) + keepalive, newarg, newargtype = self._conv_param(argtype, val) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) - newarg, newargtype = self._conv_param(argtype, defval) + keepalive, newarg, newargtype = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) + keepalive = None newarg = ctypes.byref(val) newargtype = type(newarg) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: - newarg, newargtype = self._conv_param(argtype, args[i]) + keepalive, newarg, newargtype = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) inargs_idx += 1 @@ -542,13 +559,17 @@ extra = args[len(newargs):] for i, arg in enumerate(extra): try: - newarg, newargtype = self._conv_param(None, arg) + keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) + keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) - return newargs, newargtypes, outargs + return keepalives, newargs, newargtypes, outargs + @staticmethod + def _is_primitive(argtype): + return argtype.__bases__[0] is _SimpleCData def _wrap_result(self, restype, result): """ @@ -557,7 +578,7 @@ """ # hack for performance: if restype is a "simple" primitive type, don't # allocate the buffer because it's going to be thrown away immediately - if restype.__bases__[0] is _SimpleCData and not restype._is_pointer_like(): + if self._is_primitive(restype) and not restype._is_pointer_like(): return result # shape = restype._ffishape @@ -587,13 +608,7 @@ retval = None - if self._com_index: - if resbuffer[0] & 0x80000000: - raise get_com_error(resbuffer[0], - self._com_iid, argsandobjs[0]) - else: - retval = int(resbuffer[0]) - elif restype is not None: + if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) @@ -601,7 +616,13 @@ # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value - retval = checker(val) + # XXX Raise a COMError when restype is HRESULT and + # checker(val) fails. How to check for restype == HRESULT? + if self._com_index: + if result & 0x80000000: + raise get_com_error(result, None, None) + else: + retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) else: diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -10,6 +10,8 @@ from _ctypes.builtin import ConvMode from _ctypes.array import Array from _ctypes.pointer import _Pointer, as_ffi_pointer +#from _ctypes.function import CFuncPtr # this import is moved at the bottom + # because else it's circular class NULL(object): pass @@ -86,7 +88,7 @@ return res if isinstance(value, Array): return value - if isinstance(value, _Pointer): + if isinstance(value, (_Pointer, CFuncPtr)): return cls.from_address(value._buffer.buffer) if isinstance(value, (int, long)): return cls(value) @@ -216,10 +218,15 @@ result.value = property(_getvalue, _setvalue) elif tp == 'X': - from ctypes import windll - SysAllocStringLen = windll.oleaut32.SysAllocStringLen - SysStringLen = windll.oleaut32.SysStringLen - SysFreeString = windll.oleaut32.SysFreeString + from ctypes import WinDLL + # Use WinDLL("oleaut32") instead of windll.oleaut32 + # because the latter is a shared (cached) object; and + # other code may set their own restypes. We need out own + # restype here. + oleaut32 = WinDLL("oleaut32") + SysAllocStringLen = oleaut32.SysAllocStringLen + SysStringLen = oleaut32.SysStringLen + SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: @@ -333,3 +340,5 @@ def __nonzero__(self): return self._buffer[0] not in (0, '\x00') + +from _ctypes.function import CFuncPtr diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py --- a/lib_pypy/binascii.py +++ b/lib_pypy/binascii.py @@ -659,7 +659,7 @@ crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8) #/* Note: (crc >> 8) MUST zero fill on left - result = crc ^ 0xffffffffL + result = crc ^ 0xffffffffL if result > 2**31: result = ((result + 2**31) % 2**32) - 2**31 diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -27,9 +27,9 @@ PythonPickler.__init__(self, self.__f, args[0], **kw) else: PythonPickler.__init__(self, *args, **kw) - + def memoize(self, obj): - self.memo[None] = None # cPickle starts counting at one + self.memo[id(None)] = None # cPickle starts counting at one return PythonPickler.memoize(self, obj) def getvalue(self): diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py --- a/lib_pypy/pwd.py +++ b/lib_pypy/pwd.py @@ -16,6 +16,7 @@ from ctypes_support import standard_c_lib as libc from ctypes import Structure, POINTER, c_int, c_char_p, c_long +from _structseq import structseqtype, structseqfield try: from __pypy__ import builtinify except ImportError: builtinify = lambda f: f @@ -68,7 +69,7 @@ yield self.pw_dir yield self.pw_shell -class struct_passwd(tuple): +class struct_passwd: """ pwd.struct_passwd: Results from getpw*() routines. @@ -76,15 +77,15 @@ (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) or via the object attributes as named in the above tuple. """ - def __init__(self, passwd): - self.pw_name = passwd.pw_name - self.pw_passwd = passwd.pw_passwd - self.pw_uid = passwd.pw_uid - self.pw_gid = passwd.pw_gid - self.pw_gecos = passwd.pw_gecos - self.pw_dir = passwd.pw_dir - self.pw_shell = passwd.pw_shell - tuple.__init__(self, passwd) + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + pw_name = structseqfield(0) + pw_passwd = structseqfield(1) + pw_uid = structseqfield(2) + pw_gid = structseqfield(3) + pw_gecos = structseqfield(4) + pw_dir = structseqfield(5) + pw_shell = structseqfield(6) passwd_p = POINTER(passwd) diff --git a/lib_pypy/pyrepl/unix_console.py b/lib_pypy/pyrepl/unix_console.py --- a/lib_pypy/pyrepl/unix_console.py +++ b/lib_pypy/pyrepl/unix_console.py @@ -384,15 +384,19 @@ self.__maybe_write_code(self._smkx) - self.old_sigwinch = signal.signal( - signal.SIGWINCH, self.__sigwinch) + try: + self.old_sigwinch = signal.signal( + signal.SIGWINCH, self.__sigwinch) + except ValueError: + pass def restore(self): self.__maybe_write_code(self._rmkx) self.flushoutput() tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate) - signal.signal(signal.SIGWINCH, self.old_sigwinch) + if hasattr(self, 'old_sigwinch'): + signal.signal(signal.SIGWINCH, self.old_sigwinch) def __sigwinch(self, signum, frame): self.height, self.width = self.getheightwidth() diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -357,17 +357,6 @@ def llmemory_cast_int_to_adr(s): return SomeAddress() - -##def rarith_ovfcheck(s_obj): -## if isinstance(s_obj, SomeInteger) and s_obj.unsigned: -## getbookkeeper().warning("ovfcheck on unsigned") -## return s_obj - -##def rarith_ovfcheck_lshift(s_obj1, s_obj2): -## if isinstance(s_obj1, SomeInteger) and s_obj1.unsigned: -## getbookkeeper().warning("ovfcheck_lshift with unsigned") -## return SomeInteger() - def unicodedata_decimal(s_uchr): raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" @@ -385,8 +374,6 @@ original = getattr(__builtin__, name[8:]) BUILTIN_ANALYZERS[original] = value -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck -##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( diff --git a/pypy/config/config.py b/pypy/config/config.py --- a/pypy/config/config.py +++ b/pypy/config/config.py @@ -81,6 +81,12 @@ (self.__class__, name)) return self._cfgimpl_values[name] + def __dir__(self): + from_type = dir(type(self)) + from_dict = list(self.__dict__) + extras = list(self._cfgimpl_values) + return sorted(set(extras + from_type + from_dict)) + def __delattr__(self, name): # XXX if you use delattr you are responsible for all bad things # happening diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -129,9 +129,6 @@ cmdline='--objspace -o'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ - BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions", - default=False, - requires=[("translation.stackless", False)]), BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()", default=False), ]), @@ -266,13 +263,7 @@ BoolOption("withcelldict", "use dictionaries that are optimized for being used as module dicts", default=False, - requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False), - ("objspace.honor__builtins__", False)]), - - BoolOption("withdictmeasurement", - "create huge files with masses of information " - "about dictionaries", - default=False), + requires=[("objspace.honor__builtins__", False)]), BoolOption("withmapdict", "make instances really small but slow without the JIT", @@ -336,6 +327,9 @@ BoolOption("mutable_builtintypes", "Allow the changing of builtin types", default=False, requires=[("objspace.std.builtinshortcut", True)]), + BoolOption("withidentitydict", + "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not", + default=True), ]), ]) @@ -355,8 +349,6 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3']: - config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withrangelist=True) diff --git a/pypy/config/support.py b/pypy/config/support.py --- a/pypy/config/support.py +++ b/pypy/config/support.py @@ -9,7 +9,7 @@ return 1 # don't override MAKEFLAGS. This will call 'make' without any '-j' option if sys.platform == 'darwin': return darwin_get_cpu_count() - elif sys.platform != 'linux2': + elif not sys.platform.startswith('linux'): return 1 # implement me try: if isinstance(filename_or_file, str): diff --git a/pypy/config/test/test_config.py b/pypy/config/test/test_config.py --- a/pypy/config/test/test_config.py +++ b/pypy/config/test/test_config.py @@ -63,6 +63,20 @@ py.test.raises(ConfigError, 'config.gc.name = "ref"') config.gc.name = "framework" +def test___dir__(): + descr = make_description() + config = Config(descr, bool=False) + attrs = dir(config) + assert '__repr__' in attrs # from the type + assert '_cfgimpl_values' in attrs # from self + assert 'gc' in attrs # custom attribute + assert 'objspace' in attrs # custom attribute + # + attrs = dir(config.gc) + assert 'name' in attrs + assert 'dummy' in attrs + assert 'float' in attrs + def test_arbitrary_option(): descr = OptionDescription("top", "", [ ArbitraryOption("a", "no help", default=None) diff --git a/pypy/config/test/test_support.py b/pypy/config/test/test_support.py --- a/pypy/config/test/test_support.py +++ b/pypy/config/test/test_support.py @@ -40,7 +40,7 @@ return self._value def test_cpuinfo_linux(): - if sys.platform != 'linux2': + if not sys.platform.startswith('linux'): py.test.skip("linux only") saved = os.environ try: diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py --- a/pypy/config/translationoption.py +++ b/pypy/config/translationoption.py @@ -140,7 +140,10 @@ ["annotate", "rtype", "backendopt", "database", "source", "pyjitpl"], default=None, cmdline="--fork-before"), - + BoolOption("dont_write_c_files", + "Make the C backend write everyting to /dev/null. " + + "Useful for benchmarking, so you don't actually involve the disk", + default=False, cmdline="--dont-write-c-files"), ArbitraryOption("instrumentctl", "internal", default=None), StrOption("output", "Output file name", cmdline="--output"), diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -929,6 +929,19 @@ located in the ``py/bin/`` directory. For switches to modify test execution pass the ``-h`` option. +Coverage reports +---------------- + +In order to get coverage reports the `pytest-cov`_ plugin is included. +it adds some extra requirements ( coverage_ and `cov-core`_ ) +and can once they are installed coverage testing can be invoked via:: + + python test_all.py --cov file_or_direcory_to_cover file_or_directory + +.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov +.. _`coverage`: http://pypi.python.org/pypi/coverage +.. _`cov-core`: http://pypi.python.org/pypi/cov-core + Test conventions ---------------- diff --git a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt b/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.opcodes.CALL_LIKELY_BUILTIN.txt +++ /dev/null @@ -1,12 +0,0 @@ -Introduce a new opcode called ``CALL_LIKELY_BUILTIN``. It is used when something -is called, that looks like a builtin function (but could in reality be shadowed -by a name in the module globals). For all module globals dictionaries it is -then tracked which builtin name is shadowed in this module. If the -``CALL_LIKELY_BUILTIN`` opcode is executed, it is checked whether the builtin is -shadowed. If not, the corresponding builtin is called. Otherwise the object that -is shadowing it is called instead. If no shadowing is happening, this saves two -dictionary lookups on calls to builtins. - -For more information, see the section in `Standard Interpreter Optimizations`_. - -.. _`Standard Interpreter Optimizations`: ../interpreter-optimizations.html#call-likely-builtin diff --git a/pypy/doc/config/objspace.std.withdictmeasurement.txt b/pypy/doc/config/objspace.std.withdictmeasurement.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withdictmeasurement.txt +++ /dev/null @@ -1,3 +0,0 @@ -Internal option. - -.. internal diff --git a/pypy/doc/config/objspace.std.withidentitydict.txt b/pypy/doc/config/objspace.std.withidentitydict.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withidentitydict.txt @@ -0,0 +1,21 @@ +============================= +objspace.std.withidentitydict +============================= + +* **name:** withidentitydict + +* **description:** enable a dictionary strategy for "by identity" comparisons + +* **command-line:** --objspace-std-withidentitydict + +* **command-line for negation:** --no-objspace-std-withidentitydict + +* **option type:** boolean option + +* **default:** True + + +Enable a dictionary strategy specialized for instances of classes which +compares "by identity", which is the default unless you override ``__hash__``, +``__eq__`` or ``__cmp__``. This strategy will be used only with new-style +classes. diff --git a/pypy/doc/config/translation.dont_write_c_files.txt b/pypy/doc/config/translation.dont_write_c_files.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/translation.dont_write_c_files.txt @@ -0,0 +1,4 @@ +write the generated C files to ``/dev/null`` instead of to the disk. Useful if +you want to use translate.py as a benchmark and don't want to access the disk. + +.. _`translation documentation`: ../translation.html diff --git a/pypy/doc/config/translation.gc.txt b/pypy/doc/config/translation.gc.txt --- a/pypy/doc/config/translation.gc.txt +++ b/pypy/doc/config/translation.gc.txt @@ -1,4 +1,6 @@ -Choose the Garbage Collector used by the translated program: +Choose the Garbage Collector used by the translated program. +The good performing collectors are "hybrid" and "minimark". +The default is "minimark". - "ref": reference counting. Takes very long to translate and the result is slow. @@ -11,3 +13,12 @@ older generation. - "boehm": use the Boehm conservative GC. + + - "hybrid": a hybrid collector of "generation" together with a + mark-n-sweep old space + + - "markcompact": a slow, but memory-efficient collector, + influenced e.g. by Smalltalk systems. + + - "minimark": a generational mark-n-sweep collector with good + performance. Includes page marking for large arrays. diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -211,6 +211,38 @@ >>>> print d1['a'] 42 +Mutating classes of objects which are already used as dictionary keys +--------------------------------------------------------------------- + +Consider the following snippet of code:: + + class X(object): + pass + + def __evil_eq__(self, other): + print 'hello world' + return False + + def evil(y): + d = {x(): 1} + X.__eq__ = __evil_eq__ + d[y] # might trigger a call to __eq__? + +In CPython, __evil_eq__ **might** be called, although there is no way to write +a test which reliably calls it. It happens if ``y is not x`` and ``hash(y) == +hash(x)``, where ``hash(x)`` is computed when ``x`` is inserted into the +dictionary. If **by chance** the condition is satisfied, then ``__evil_eq__`` +is called. + +PyPy uses a special strategy to optimize dictionaries whose keys are instances +of user-defined classes which do not override the default ``__hash__``, +``__eq__`` and ``__cmp__``: when using this strategy, ``__eq__`` and +``__cmp__`` are never called, but instead the lookup is done by identity, so +in the case above it is guaranteed that ``__eq__`` won't be called. + +Note that in all other cases (e.g., if you have a custom ``__hash__`` and +``__eq__`` in ``y``) the behavior is exactly the same as CPython. + Ignored exceptions ----------------------- @@ -248,5 +280,7 @@ never a dictionary as it sometimes is in CPython. Assigning to ``__builtins__`` has no effect. +* object identity of immutable keys in dictionaries is not necessarily preserved. + Never compare immutable objects with ``is``. + .. include:: _ref.txt - diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -19,12 +19,12 @@ section * Write them in pure python and use direct libffi low-level bindings, See - \_rawffi_ module description. + \_ffi_ module description. * Write them in RPython as mixedmodule_, using *rffi* as bindings. .. _ctypes: #CTypes -.. _\_rawffi: #LibFFI +.. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules CTypes @@ -42,41 +42,50 @@ platform-dependent details (compiling small snippets of C code and running them), so it'll benefit not pypy-related ctypes-based modules as well. +ctypes call are optimized by the JIT and the resulting machine code contains a +direct call to the target C function. However, due to the very dynamic nature +of ctypes, some overhead over a bare C call is still present, in particular to +check/convert the types of the parameters. Moreover, even if most calls are +optimized, some cannot and thus need to follow the slow path, not optimized by +the JIT. + .. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure +.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html Pros ---- -Stable, CPython-compatible API +Stable, CPython-compatible API. Most calls are fast, optimized by JIT. Cons ---- -Only pure-python code (slow), problems with platform-dependency (although -we partially solve those). PyPy implementation is now very slow. +Problems with platform-dependency (although we partially solve +those). Although the JIT optimizes ctypes calls, some overhead is still +present. The slow-path is very slow. -_`CPython ctypes`: http://python.net/crew/theller/ctypes/ LibFFI ====== Mostly in order to be able to write a ctypes module, we developed a very -low-level libffi bindings. (libffi is a C-level library for dynamic calling, +low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling, which is used by CPython ctypes). This library provides stable and usable API, although it's API is a very low-level one. It does not contain any -magic. +magic. It is also optimized by the JIT, but has much less overhead than ctypes. Pros ---- -Works. Combines disadvantages of using ctypes with disadvantages of -using mixed modules. Probably more suitable for a delicate code -where ctypes magic goes in a way. +It Works. Probably more suitable for a delicate code where ctypes magic goes +in a way. All calls are optimized by the JIT, there is no slow path as in +ctypes. Cons ---- -Slow. CPython-incompatible API, very rough and low-level +It combines disadvantages of using ctypes with disadvantages of using mixed +modules. CPython-incompatible API, very rough and low-level. Mixed Modules ============= @@ -87,15 +96,15 @@ * a mixed module needs to be written in RPython, which is far more complicated than Python (XXX link) -* due to lack of separate compilation (as of April 2008), each +* due to lack of separate compilation (as of July 2011), each compilation-check requires to recompile whole PyPy python interpreter, which takes 0.5-1h. We plan to solve this at some point in near future. * although rpython is a garbage-collected language, the border between C and RPython needs to be managed by hand (each object that goes into the - C level must be explicitly freed) XXX we try to solve this + C level must be explicitly freed). -Some document is available `here`_ +Some documentation is available `here`_ .. _`here`: rffi.html diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -51,7 +51,7 @@ --------------- PyPy is ready to be executed as soon as you unpack the tarball or the zip -file, with no need install it in any specific location:: +file, with no need to install it in any specific location:: $ tar xf pypy-1.5-linux.tar.bz2 diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -11,6 +11,10 @@ Getting into PyPy ... ============================================= +* `Getting started`_: how to install and run the PyPy Python interpreter + +* `FAQ`_: some frequently asked questions. + * `Release 1.5`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -26,13 +30,6 @@ Documentation for the PyPy Python Interpreter =============================================== -`getting started`_ provides hands-on instructions -including a two-liner to run the PyPy Python interpreter -on your system, examples on advanced features and -entry points for using the `RPython toolchain`_. - -`FAQ`_ contains some frequently asked questions. - New features of PyPy's Python Interpreter and Translation Framework: diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst --- a/pypy/doc/interpreter-optimizations.rst +++ b/pypy/doc/interpreter-optimizations.rst @@ -157,32 +157,6 @@ A more advanced version of sharing dicts, called *map dicts,* is available with the :config:`objspace.std.withmapdict` option. -Builtin-Shadowing -+++++++++++++++++ - -Usually the calling of builtins in Python requires two dictionary lookups: first -to see whether the current global dictionary contains an object with the same -name, then a lookup in the ``__builtin__`` dictionary. This is somehow -circumvented by storing an often used builtin into a local variable to get -the fast local lookup (which is a rather strange and ugly hack). - -The same problem is solved in a different way by "wary" dictionaries. They are -another dictionary representation used together with multidicts. This -representation is used only for module dictionaries. The representation checks on -every setitem whether the key that is used is the name of a builtin. If this is -the case, the dictionary is marked as shadowing that particular builtin. - -To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``) -is introduced. Whenever it is executed, the globals dictionary is checked -to see whether it masks the builtin (which is possible without a dictionary -lookup). Then the ``__builtin__`` dict is checked in the same way, -to see whether somebody replaced the real builtin with something else. In the -common case, the program didn't do any of these; the proper builtin can then -be called without using any dictionary lookup at all. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - List Optimizations ------------------ @@ -289,34 +263,6 @@ You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD` option. -.. _`call likely builtin`: - -CALL_LIKELY_BUILTIN -+++++++++++++++++++ - -A often heard "tip" for speeding up Python programs is to give an often used -builtin a local name, since local lookups are faster than lookups of builtins, -which involve doing two dictionary lookups: one in the globals dictionary and -one in the the builtins dictionary. PyPy approaches this problem at the -implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN`` -bytecode. This bytecode is produced by the compiler for a call whose target is -the name of a builtin. Since such a syntactic construct is very often actually -invoking the expected builtin at run-time, this information can be used to make -the call to the builtin directly, without going through any dictionary lookup. - -However, it can occur that the name is shadowed by a global name from the -current module. To catch this case, a special dictionary implementation for -multidicts is introduced, which is used for the dictionaries of modules. This -implementation keeps track which builtin name is shadowed by it. The -``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the -builtin that is about to be called and asks the dictionary of ``__builtin__`` -whether the original builtin was changed. These two checks are cheaper than -full lookups. In the common case, neither of these cases is true, so the -builtin can be directly invoked. - -You can enable this feature with the -:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option. - .. more here? Overall Effects diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -32,6 +32,24 @@ modules that relies on third-party libraries. See below how to get and build them. +Preping Windows for the Large Build +----------------------------------- + +Normally 32bit programs are limited to 2GB of memory on Windows. It is +possible to raise this limit, to 3GB on Windows 32bit, and almost 4GB +on Windows 64bit. + +On Windows 32bit, it is necessary to modify the system: follow +http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617 +to enable the "3GB" feature, and reboot. This step is not necessary on +Windows 64bit. + +Then you need to execute:: + + editbin /largeaddressaware pypy.exe + +on the pypy.exe file you compiled. + Installing external packages ---------------------------- diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -17,7 +17,7 @@ self.varargname = varargname self.kwargname = kwargname - @jit.purefunction + @jit.elidable def find_argname(self, name): try: return self.argnames.index(name) diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -655,9 +655,6 @@ def _compute_CALL_FUNCTION_VAR_KW(arg): return -_num_args(arg) - 2 -def _compute_CALL_LIKELY_BUILTIN(arg): - return -(arg & 0xFF) + 1 - def _compute_CALL_METHOD(arg): return -_num_args(arg) - 1 diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -2541,8 +2541,9 @@ class ASTVisitor(object): def visit_sequence(self, seq): - for node in seq: - node.walkabout(self) + if seq is not None: + for node in seq: + node.walkabout(self) def default_visitor(self, node): raise NodeVisitorNotImplemented @@ -2673,46 +2674,36 @@ class GenericASTVisitor(ASTVisitor): def visit_Module(self, node): - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_Interactive(self, node): - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_Expression(self, node): node.body.walkabout(self) def visit_Suite(self, node): - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_FunctionDef(self, node): node.args.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.decorator_list: - self.visit_sequence(node.decorator_list) + self.visit_sequence(node.body) + self.visit_sequence(node.decorator_list) def visit_ClassDef(self, node): - if node.bases: - self.visit_sequence(node.bases) - if node.body: - self.visit_sequence(node.body) - if node.decorator_list: - self.visit_sequence(node.decorator_list) + self.visit_sequence(node.bases) + self.visit_sequence(node.body) + self.visit_sequence(node.decorator_list) def visit_Return(self, node): if node.value: node.value.walkabout(self) def visit_Delete(self, node): - if node.targets: - self.visit_sequence(node.targets) + self.visit_sequence(node.targets) def visit_Assign(self, node): - if node.targets: - self.visit_sequence(node.targets) + self.visit_sequence(node.targets) node.value.walkabout(self) def visit_AugAssign(self, node): @@ -2722,37 +2713,29 @@ def visit_Print(self, node): if node.dest: node.dest.walkabout(self) - if node.values: - self.visit_sequence(node.values) + self.visit_sequence(node.values) def visit_For(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.orelse) def visit_While(self, node): node.test.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.orelse) def visit_If(self, node): node.test.walkabout(self) - if node.body: - self.visit_sequence(node.body) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.orelse) def visit_With(self, node): node.context_expr.walkabout(self) if node.optional_vars: node.optional_vars.walkabout(self) - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_Raise(self, node): if node.type: @@ -2763,18 +2746,13 @@ node.tback.walkabout(self) def visit_TryExcept(self, node): - if node.body: - self.visit_sequence(node.body) - if node.handlers: - self.visit_sequence(node.handlers) - if node.orelse: - self.visit_sequence(node.orelse) + self.visit_sequence(node.body) + self.visit_sequence(node.handlers) + self.visit_sequence(node.orelse) def visit_TryFinally(self, node): - if node.body: - self.visit_sequence(node.body) - if node.finalbody: - self.visit_sequence(node.finalbody) + self.visit_sequence(node.body) + self.visit_sequence(node.finalbody) def visit_Assert(self, node): node.test.walkabout(self) @@ -2782,12 +2760,10 @@ node.msg.walkabout(self) def visit_Import(self, node): - if node.names: - self.visit_sequence(node.names) + self.visit_sequence(node.names) def visit_ImportFrom(self, node): - if node.names: - self.visit_sequence(node.names) + self.visit_sequence(node.names) def visit_Exec(self, node): node.body.walkabout(self) @@ -2812,8 +2788,7 @@ pass def visit_BoolOp(self, node): - if node.values: - self.visit_sequence(node.values) + self.visit_sequence(node.values) def visit_BinOp(self, node): node.left.walkabout(self) @@ -2832,35 +2807,28 @@ node.orelse.walkabout(self) def visit_Dict(self, node): - if node.keys: - self.visit_sequence(node.keys) - if node.values: - self.visit_sequence(node.values) + self.visit_sequence(node.keys) + self.visit_sequence(node.values) def visit_Set(self, node): - if node.elts: - self.visit_sequence(node.elts) + self.visit_sequence(node.elts) def visit_ListComp(self, node): node.elt.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_SetComp(self, node): node.elt.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_DictComp(self, node): node.key.walkabout(self) node.value.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_GeneratorExp(self, node): node.elt.walkabout(self) - if node.generators: - self.visit_sequence(node.generators) + self.visit_sequence(node.generators) def visit_Yield(self, node): if node.value: @@ -2868,15 +2836,12 @@ def visit_Compare(self, node): node.left.walkabout(self) - if node.comparators: - self.visit_sequence(node.comparators) + self.visit_sequence(node.comparators) def visit_Call(self, node): node.func.walkabout(self) - if node.args: - self.visit_sequence(node.args) - if node.keywords: - self.visit_sequence(node.keywords) + self.visit_sequence(node.args) + self.visit_sequence(node.keywords) if node.starargs: node.starargs.walkabout(self) if node.kwargs: @@ -2902,12 +2867,10 @@ pass def visit_List(self, node): - if node.elts: - self.visit_sequence(node.elts) + self.visit_sequence(node.elts) def visit_Tuple(self, node): - if node.elts: - self.visit_sequence(node.elts) + self.visit_sequence(node.elts) def visit_Const(self, node): pass @@ -2924,8 +2887,7 @@ node.step.walkabout(self) def visit_ExtSlice(self, node): - if node.dims: - self.visit_sequence(node.dims) + self.visit_sequence(node.dims) def visit_Index(self, node): node.value.walkabout(self) @@ -2933,22 +2895,18 @@ def visit_comprehension(self, node): node.target.walkabout(self) node.iter.walkabout(self) - if node.ifs: - self.visit_sequence(node.ifs) + self.visit_sequence(node.ifs) def visit_ExceptHandler(self, node): if node.type: node.type.walkabout(self) if node.name: node.name.walkabout(self) - if node.body: - self.visit_sequence(node.body) + self.visit_sequence(node.body) def visit_arguments(self, node): - if node.args: - self.visit_sequence(node.args) - if node.defaults: - self.visit_sequence(node.defaults) + self.visit_sequence(node.args) + self.visit_sequence(node.defaults) def visit_keyword(self, node): node.value.walkabout(self) @@ -3069,6 +3027,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 _Expression_field_unroller = unrolling_iterable(['body']) @@ -3157,6 +3116,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def stmt_get_col_offset(space, w_self): @@ -3178,6 +3138,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask stmt.typedef = typedef.TypeDef("stmt", @@ -3208,6 +3169,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def FunctionDef_get_args(space, w_self): @@ -3229,6 +3191,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 2 def FunctionDef_get_body(space, w_self): @@ -3315,6 +3278,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def ClassDef_get_bases(space, w_self): @@ -3420,6 +3384,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Return_field_unroller = unrolling_iterable(['value']) @@ -3526,6 +3491,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _Assign_field_unroller = unrolling_iterable(['targets', 'value']) @@ -3573,6 +3539,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def AugAssign_get_op(space, w_self): @@ -3590,13 +3557,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def AugAssign_get_value(space, w_self): @@ -3618,6 +3585,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 4 _AugAssign_field_unroller = unrolling_iterable(['target', 'op', 'value']) @@ -3665,6 +3633,7 @@ raise w_self.setdictvalue(space, 'dest', w_new_value) return + w_self.deldictvalue(space, 'dest') w_self.initialization_state |= 1 def Print_get_values(space, w_self): @@ -3704,6 +3673,7 @@ raise w_self.setdictvalue(space, 'nl', w_new_value) return + w_self.deldictvalue(space, 'nl') w_self.initialization_state |= 4 _Print_field_unroller = unrolling_iterable(['dest', 'values', 'nl']) @@ -3752,6 +3722,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def For_get_iter(space, w_self): @@ -3773,6 +3744,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def For_get_body(space, w_self): @@ -3859,6 +3831,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def While_get_body(space, w_self): @@ -3944,6 +3917,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def If_get_body(space, w_self): @@ -4029,6 +4003,7 @@ raise w_self.setdictvalue(space, 'context_expr', w_new_value) return + w_self.deldictvalue(space, 'context_expr') w_self.initialization_state |= 1 def With_get_optional_vars(space, w_self): @@ -4050,6 +4025,7 @@ raise w_self.setdictvalue(space, 'optional_vars', w_new_value) return + w_self.deldictvalue(space, 'optional_vars') w_self.initialization_state |= 2 def With_get_body(space, w_self): @@ -4116,6 +4092,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def Raise_get_inst(space, w_self): @@ -4137,6 +4114,7 @@ raise w_self.setdictvalue(space, 'inst', w_new_value) return + w_self.deldictvalue(space, 'inst') w_self.initialization_state |= 2 def Raise_get_tback(space, w_self): @@ -4158,6 +4136,7 @@ raise w_self.setdictvalue(space, 'tback', w_new_value) return + w_self.deldictvalue(space, 'tback') w_self.initialization_state |= 4 _Raise_field_unroller = unrolling_iterable(['type', 'inst', 'tback']) @@ -4351,6 +4330,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def Assert_get_msg(space, w_self): @@ -4372,6 +4352,7 @@ raise w_self.setdictvalue(space, 'msg', w_new_value) return + w_self.deldictvalue(space, 'msg') w_self.initialization_state |= 2 _Assert_field_unroller = unrolling_iterable(['test', 'msg']) @@ -4464,6 +4445,7 @@ raise w_self.setdictvalue(space, 'module', w_new_value) return + w_self.deldictvalue(space, 'module') w_self.initialization_state |= 1 def ImportFrom_get_names(space, w_self): @@ -4503,6 +4485,7 @@ raise w_self.setdictvalue(space, 'level', w_new_value) return + w_self.deldictvalue(space, 'level') w_self.initialization_state |= 4 _ImportFrom_field_unroller = unrolling_iterable(['module', 'names', 'level']) @@ -4551,6 +4534,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 1 def Exec_get_globals(space, w_self): @@ -4572,6 +4556,7 @@ raise w_self.setdictvalue(space, 'globals', w_new_value) return + w_self.deldictvalue(space, 'globals') w_self.initialization_state |= 2 def Exec_get_locals(space, w_self): @@ -4593,6 +4578,7 @@ raise w_self.setdictvalue(space, 'locals', w_new_value) return + w_self.deldictvalue(space, 'locals') w_self.initialization_state |= 4 _Exec_field_unroller = unrolling_iterable(['body', 'globals', 'locals']) @@ -4683,6 +4669,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Expr_field_unroller = unrolling_iterable(['value']) @@ -4779,6 +4766,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def expr_get_col_offset(space, w_self): @@ -4800,6 +4788,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask expr.typedef = typedef.TypeDef("expr", @@ -4826,13 +4815,13 @@ try: obj = space.interp_w(boolop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def BoolOp_get_values(space, w_self): @@ -4898,6 +4887,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def BinOp_get_op(space, w_self): @@ -4915,13 +4905,13 @@ try: obj = space.interp_w(operator, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 2 def BinOp_get_right(space, w_self): @@ -4943,6 +4933,7 @@ raise w_self.setdictvalue(space, 'right', w_new_value) return + w_self.deldictvalue(space, 'right') w_self.initialization_state |= 4 _BinOp_field_unroller = unrolling_iterable(['left', 'op', 'right']) @@ -4986,13 +4977,13 @@ try: obj = space.interp_w(unaryop, w_new_value) w_self.op = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'op', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'op', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'op', w_new_value) w_self.initialization_state |= 1 def UnaryOp_get_operand(space, w_self): @@ -5014,6 +5005,7 @@ raise w_self.setdictvalue(space, 'operand', w_new_value) return + w_self.deldictvalue(space, 'operand') w_self.initialization_state |= 2 _UnaryOp_field_unroller = unrolling_iterable(['op', 'operand']) @@ -5060,6 +5052,7 @@ raise w_self.setdictvalue(space, 'args', w_new_value) return + w_self.deldictvalue(space, 'args') w_self.initialization_state |= 1 def Lambda_get_body(space, w_self): @@ -5081,6 +5074,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 _Lambda_field_unroller = unrolling_iterable(['args', 'body']) @@ -5127,6 +5121,7 @@ raise w_self.setdictvalue(space, 'test', w_new_value) return + w_self.deldictvalue(space, 'test') w_self.initialization_state |= 1 def IfExp_get_body(space, w_self): @@ -5148,6 +5143,7 @@ raise w_self.setdictvalue(space, 'body', w_new_value) return + w_self.deldictvalue(space, 'body') w_self.initialization_state |= 2 def IfExp_get_orelse(space, w_self): @@ -5169,6 +5165,7 @@ raise w_self.setdictvalue(space, 'orelse', w_new_value) return + w_self.deldictvalue(space, 'orelse') w_self.initialization_state |= 4 _IfExp_field_unroller = unrolling_iterable(['test', 'body', 'orelse']) @@ -5322,6 +5319,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def ListComp_get_generators(space, w_self): @@ -5387,6 +5385,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def SetComp_get_generators(space, w_self): @@ -5452,6 +5451,7 @@ raise w_self.setdictvalue(space, 'key', w_new_value) return + w_self.deldictvalue(space, 'key') w_self.initialization_state |= 1 def DictComp_get_value(space, w_self): @@ -5473,6 +5473,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 def DictComp_get_generators(space, w_self): @@ -5539,6 +5540,7 @@ raise w_self.setdictvalue(space, 'elt', w_new_value) return + w_self.deldictvalue(space, 'elt') w_self.initialization_state |= 1 def GeneratorExp_get_generators(space, w_self): @@ -5604,6 +5606,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Yield_field_unroller = unrolling_iterable(['value']) @@ -5649,6 +5652,7 @@ raise w_self.setdictvalue(space, 'left', w_new_value) return + w_self.deldictvalue(space, 'left') w_self.initialization_state |= 1 def Compare_get_ops(space, w_self): @@ -5734,6 +5738,7 @@ raise w_self.setdictvalue(space, 'func', w_new_value) return + w_self.deldictvalue(space, 'func') w_self.initialization_state |= 1 def Call_get_args(space, w_self): @@ -5791,6 +5796,7 @@ raise w_self.setdictvalue(space, 'starargs', w_new_value) return + w_self.deldictvalue(space, 'starargs') w_self.initialization_state |= 8 def Call_get_kwargs(space, w_self): @@ -5812,6 +5818,7 @@ raise w_self.setdictvalue(space, 'kwargs', w_new_value) return + w_self.deldictvalue(space, 'kwargs') w_self.initialization_state |= 16 _Call_field_unroller = unrolling_iterable(['func', 'args', 'keywords', 'starargs', 'kwargs']) @@ -5863,6 +5870,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Repr_field_unroller = unrolling_iterable(['value']) @@ -5908,6 +5916,7 @@ raise w_self.setdictvalue(space, 'n', w_new_value) return + w_self.deldictvalue(space, 'n') w_self.initialization_state |= 1 _Num_field_unroller = unrolling_iterable(['n']) @@ -5953,6 +5962,7 @@ raise w_self.setdictvalue(space, 's', w_new_value) return + w_self.deldictvalue(space, 's') w_self.initialization_state |= 1 _Str_field_unroller = unrolling_iterable(['s']) @@ -5998,6 +6008,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Attribute_get_attr(space, w_self): @@ -6019,6 +6030,7 @@ raise w_self.setdictvalue(space, 'attr', w_new_value) return + w_self.deldictvalue(space, 'attr') w_self.initialization_state |= 2 def Attribute_get_ctx(space, w_self): @@ -6036,13 +6048,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Attribute_field_unroller = unrolling_iterable(['value', 'attr', 'ctx']) @@ -6090,6 +6102,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 def Subscript_get_slice(space, w_self): @@ -6111,6 +6124,7 @@ raise w_self.setdictvalue(space, 'slice', w_new_value) return + w_self.deldictvalue(space, 'slice') w_self.initialization_state |= 2 def Subscript_get_ctx(space, w_self): @@ -6128,13 +6142,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 4 _Subscript_field_unroller = unrolling_iterable(['value', 'slice', 'ctx']) @@ -6182,6 +6196,7 @@ raise w_self.setdictvalue(space, 'id', w_new_value) return + w_self.deldictvalue(space, 'id') w_self.initialization_state |= 1 def Name_get_ctx(space, w_self): @@ -6199,13 +6214,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Name_field_unroller = unrolling_iterable(['id', 'ctx']) @@ -6266,13 +6281,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _List_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6334,13 +6349,13 @@ try: obj = space.interp_w(expr_context, w_new_value) w_self.ctx = obj.to_simple_int(space) - # need to save the original object too - w_self.setdictvalue(space, 'ctx', w_new_value) except OperationError, e: if not e.match(space, space.w_TypeError): raise w_self.setdictvalue(space, 'ctx', w_new_value) return + # need to save the original object too + w_self.setdictvalue(space, 'ctx', w_new_value) w_self.initialization_state |= 2 _Tuple_field_unroller = unrolling_iterable(['elts', 'ctx']) @@ -6388,6 +6403,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Const_field_unroller = unrolling_iterable(['value']) @@ -6506,6 +6522,7 @@ raise w_self.setdictvalue(space, 'lower', w_new_value) return + w_self.deldictvalue(space, 'lower') w_self.initialization_state |= 1 def Slice_get_upper(space, w_self): @@ -6527,6 +6544,7 @@ raise w_self.setdictvalue(space, 'upper', w_new_value) return + w_self.deldictvalue(space, 'upper') w_self.initialization_state |= 2 def Slice_get_step(space, w_self): @@ -6548,6 +6566,7 @@ raise w_self.setdictvalue(space, 'step', w_new_value) return + w_self.deldictvalue(space, 'step') w_self.initialization_state |= 4 _Slice_field_unroller = unrolling_iterable(['lower', 'upper', 'step']) @@ -6638,6 +6657,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 1 _Index_field_unroller = unrolling_iterable(['value']) @@ -6907,6 +6927,7 @@ raise w_self.setdictvalue(space, 'target', w_new_value) return + w_self.deldictvalue(space, 'target') w_self.initialization_state |= 1 def comprehension_get_iter(space, w_self): @@ -6928,6 +6949,7 @@ raise w_self.setdictvalue(space, 'iter', w_new_value) return + w_self.deldictvalue(space, 'iter') w_self.initialization_state |= 2 def comprehension_get_ifs(space, w_self): @@ -6994,6 +7016,7 @@ raise w_self.setdictvalue(space, 'lineno', w_new_value) return + w_self.deldictvalue(space, 'lineno') w_self.initialization_state |= w_self._lineno_mask def excepthandler_get_col_offset(space, w_self): @@ -7015,6 +7038,7 @@ raise w_self.setdictvalue(space, 'col_offset', w_new_value) return + w_self.deldictvalue(space, 'col_offset') w_self.initialization_state |= w_self._col_offset_mask excepthandler.typedef = typedef.TypeDef("excepthandler", @@ -7045,6 +7069,7 @@ raise w_self.setdictvalue(space, 'type', w_new_value) return + w_self.deldictvalue(space, 'type') w_self.initialization_state |= 1 def ExceptHandler_get_name(space, w_self): @@ -7066,6 +7091,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 2 def ExceptHandler_get_body(space, w_self): @@ -7153,6 +7179,7 @@ raise w_self.setdictvalue(space, 'vararg', w_new_value) return + w_self.deldictvalue(space, 'vararg') w_self.initialization_state |= 2 def arguments_get_kwarg(space, w_self): @@ -7177,6 +7204,7 @@ raise w_self.setdictvalue(space, 'kwarg', w_new_value) return + w_self.deldictvalue(space, 'kwarg') w_self.initialization_state |= 4 def arguments_get_defaults(space, w_self): @@ -7245,6 +7273,7 @@ raise w_self.setdictvalue(space, 'arg', w_new_value) return + w_self.deldictvalue(space, 'arg') w_self.initialization_state |= 1 def keyword_get_value(space, w_self): @@ -7266,6 +7295,7 @@ raise w_self.setdictvalue(space, 'value', w_new_value) return + w_self.deldictvalue(space, 'value') w_self.initialization_state |= 2 _keyword_field_unroller = unrolling_iterable(['arg', 'value']) @@ -7312,6 +7342,7 @@ raise w_self.setdictvalue(space, 'name', w_new_value) return + w_self.deldictvalue(space, 'name') w_self.initialization_state |= 1 def alias_get_asname(space, w_self): @@ -7336,6 +7367,7 @@ raise w_self.setdictvalue(space, 'asname', w_new_value) return + w_self.deldictvalue(space, 'asname') w_self.initialization_state |= 2 _alias_field_unroller = unrolling_iterable(['name', 'asname']) diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops from pypy.interpreter.error import OperationError -from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX def compile_ast(space, module, info): @@ -296,15 +295,11 @@ def visit_FunctionDef(self, func): self.update_position(func.lineno, True) # Load decorators first, but apply them after the function is created. - if func.decorator_list: - self.visit_sequence(func.decorator_list) + self.visit_sequence(func.decorator_list) args = func.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) - num_defaults = len(args.defaults) - else: - num_defaults = 0 + self.visit_sequence(args.defaults) + num_defaults = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(FunctionCodeGenerator, func.name, func, func.lineno) self._make_function(code, num_defaults) @@ -318,24 +313,17 @@ self.update_position(lam.lineno) args = lam.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) - default_count = len(args.defaults) - else: - default_count = 0 + self.visit_sequence(args.defaults) + default_count = len(args.defaults) if args.defaults is not None else 0 code = self.sub_scope(LambdaCodeGenerator, "", lam, lam.lineno) self._make_function(code, default_count) def visit_ClassDef(self, cls): self.update_position(cls.lineno, True) - if cls.decorator_list: - self.visit_sequence(cls.decorator_list) + self.visit_sequence(cls.decorator_list) self.load_const(self.space.wrap(cls.name)) - if cls.bases: - bases_count = len(cls.bases) - self.visit_sequence(cls.bases) - else: - bases_count = 0 + self.visit_sequence(cls.bases) + bases_count = len(cls.bases) if cls.bases is not None else 0 self.emit_op_arg(ops.BUILD_TUPLE, bases_count) code = self.sub_scope(ClassCodeGenerator, cls.name, cls, cls.lineno) self._make_function(code, 0) @@ -447,8 +435,7 @@ end = self.new_block() test_constant = if_.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if if_.orelse: - self.visit_sequence(if_.orelse) + self.visit_sequence(if_.orelse) elif test_constant == optimize.CONST_TRUE: self.visit_sequence(if_.body) else: @@ -516,16 +503,14 @@ self.use_next_block(cleanup) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, start) - if fr.orelse: - self.visit_sequence(fr.orelse) + self.visit_sequence(fr.orelse) self.use_next_block(end) def visit_While(self, wh): self.update_position(wh.lineno, True) test_constant = wh.test.as_constant_truth(self.space) if test_constant == optimize.CONST_FALSE: - if wh.orelse: - self.visit_sequence(wh.orelse) + self.visit_sequence(wh.orelse) else: end = self.new_block() anchor = None @@ -545,8 +530,7 @@ self.use_next_block(anchor) self.emit_op(ops.POP_BLOCK) self.pop_frame_block(F_BLOCK_LOOP, loop) - if wh.orelse: - self.visit_sequence(wh.orelse) + self.visit_sequence(wh.orelse) self.use_next_block(end) def visit_TryExcept(self, te): @@ -582,8 +566,7 @@ self.use_next_block(next_except) self.emit_op(ops.END_FINALLY) self.use_next_block(otherwise) - if te.orelse: - self.visit_sequence(te.orelse) + self.visit_sequence(te.orelse) self.use_next_block(end) def visit_TryFinally(self, tf): @@ -894,27 +877,19 @@ def visit_Tuple(self, tup): self.update_position(tup.lineno) - if tup.elts: - elt_count = len(tup.elts) - else: - elt_count = 0 + elt_count = len(tup.elts) if tup.elts is not None else 0 if tup.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: - self.visit_sequence(tup.elts) + self.visit_sequence(tup.elts) if tup.ctx == ast.Load: self.emit_op_arg(ops.BUILD_TUPLE, elt_count) def visit_List(self, l): self.update_position(l.lineno) - if l.elts: - elt_count = len(l.elts) - else: - elt_count = 0 + elt_count = len(l.elts) if l.elts is not None else 0 if l.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - if elt_count: - self.visit_sequence(l.elts) + self.visit_sequence(l.elts) if l.ctx == ast.Load: self.emit_op_arg(ops.BUILD_LIST, elt_count) @@ -942,15 +917,12 @@ def visit_Call(self, call): self.update_position(call.lineno) - if self._optimize_builtin_call(call) or \ - self._optimize_method_call(call): + if self._optimize_method_call(call): return call.func.walkabout(self) - arg = 0 + arg = len(call.args) if call.args is not None else 0 call_type = 0 - if call.args: - arg = len(call.args) - self.visit_sequence(call.args) + self.visit_sequence(call.args) if call.keywords: self.visit_sequence(call.keywords) arg |= len(call.keywords) << 8 @@ -977,28 +949,6 @@ def _call_has_simple_args(self, call): return self._call_has_no_star_args(call) and not call.keywords - def _optimize_builtin_call(self, call): - if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \ - not self._call_has_simple_args(call) or \ - not isinstance(call.func, ast.Name): - return False - func_name = call.func - assert isinstance(func_name, ast.Name) - name_scope = self.scope.lookup(func_name.id) - if name_scope == symtable.SCOPE_GLOBAL_IMPLICIT or \ - name_scope == symtable.SCOPE_UNKNOWN: - builtin_index = BUILTIN_TO_INDEX.get(func_name.id, -1) - if builtin_index != -1: - if call.args: - args_count = len(call.args) - self.visit_sequence(call.args) - else: - args_count = 0 - arg = builtin_index << 8 | args_count - self.emit_op_arg(ops.CALL_LIKELY_BUILTIN, arg) - return True - return False - def _optimize_method_call(self, call): if not self.space.config.objspace.opcodes.CALL_METHOD or \ not self._call_has_no_star_args(call) or \ @@ -1008,16 +958,10 @@ assert isinstance(attr_lookup, ast.Attribute) attr_lookup.value.walkabout(self) self.emit_op_name(ops.LOOKUP_METHOD, self.names, attr_lookup.attr) - if call.args: - self.visit_sequence(call.args) - arg_count = len(call.args) - else: - arg_count = 0 - if call.keywords: - self.visit_sequence(call.keywords) - kwarg_count = len(call.keywords) - else: - kwarg_count = 0 + self.visit_sequence(call.args) + arg_count = len(call.args) if call.args is not None else 0 + self.visit_sequence(call.keywords) + kwarg_count = len(call.keywords) if call.keywords is not None else 0 self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) | arg_count) return True @@ -1275,7 +1219,10 @@ def _compile(self, func): assert isinstance(func, ast.FunctionDef) # If there's a docstring, store it as the first constant. - doc_expr = self.possible_docstring(func.body[0]) + if func.body: + doc_expr = self.possible_docstring(func.body[0]) + else: + doc_expr = None if doc_expr is not None: self.add_const(doc_expr.s) start = 1 @@ -1287,8 +1234,9 @@ if args.args: self._handle_nested_args(args.args) self.argcount = len(args.args) - for i in range(start, len(func.body)): - func.body[i].walkabout(self) + if func.body: + for i in range(start, len(func.body)): + func.body[i].walkabout(self) class LambdaCodeGenerator(AbstractFunctionCodeGenerator): diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -27,9 +27,10 @@ _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset) -def parse_future(tree): +def parse_future(tree, feature_flags): future_lineno = 0 future_column = 0 + flags = 0 have_docstring = False body = None if isinstance(tree, ast.Module): @@ -37,7 +38,7 @@ elif isinstance(tree, ast.Interactive): body = tree.body if body is None: - return 0, 0 + return 0, 0, 0 for stmt in body: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str): if have_docstring: @@ -48,11 +49,16 @@ if stmt.module == "__future__": future_lineno = stmt.lineno future_column = stmt.col_offset + for alias in stmt.names: + assert isinstance(alias, ast.alias) + # If this is an invalid flag, it will be caught later in + # codegen.py. + flags |= feature_flags.get(alias.name, 0) else: break else: break - return future_lineno, future_column + return flags, future_lineno, future_column class ForbiddenNameAssignment(Exception): diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py --- a/pypy/interpreter/astcompiler/symtable.py +++ b/pypy/interpreter/astcompiler/symtable.py @@ -356,10 +356,8 @@ # Function defaults and decorators happen in the outer scope. args = func.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) - if func.decorator_list: - self.visit_sequence(func.decorator_list) + self.visit_sequence(args.defaults) + self.visit_sequence(func.decorator_list) new_scope = FunctionScope(func.name, func.lineno, func.col_offset) self.push_scope(new_scope, func) func.args.walkabout(self) @@ -372,10 +370,8 @@ def visit_ClassDef(self, clsdef): self.note_symbol(clsdef.name, SYM_ASSIGNED) - if clsdef.bases: - self.visit_sequence(clsdef.bases) - if clsdef.decorator_list: - self.visit_sequence(clsdef.decorator_list) + self.visit_sequence(clsdef.bases) + self.visit_sequence(clsdef.decorator_list) self.push_scope(ClassScope(clsdef), clsdef) self.visit_sequence(clsdef.body) self.pop_scope() @@ -431,8 +427,7 @@ def visit_Lambda(self, lamb): args = lamb.args assert isinstance(args, ast.arguments) - if args.defaults: - self.visit_sequence(args.defaults) + self.visit_sequence(args.defaults) new_scope = FunctionScope("lambda", lamb.lineno, lamb.col_offset) self.push_scope(new_scope, lamb) lamb.args.walkabout(self) @@ -447,8 +442,7 @@ self.push_scope(new_scope, node) self.implicit_arg(0) outer.target.walkabout(self) - if outer.ifs: - self.visit_sequence(outer.ifs) + self.visit_sequence(outer.ifs) self.visit_sequence(comps[1:]) for item in list(consider): item.walkabout(self) diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -221,8 +221,9 @@ self.emit("class ASTVisitor(object):") self.emit("") self.emit("def visit_sequence(self, seq):", 1) - self.emit("for node in seq:", 2) - self.emit("node.walkabout(self)", 3) + self.emit("if seq is not None:", 2) + self.emit("for node in seq:", 3) + self.emit("node.walkabout(self)", 4) self.emit("") self.emit("def default_visitor(self, node):", 1) self.emit("raise NodeVisitorNotImplemented", 2) @@ -280,15 +281,13 @@ def visitField(self, field): if field.type.value not in asdl.builtin_types and \ field.type.value not in self.data.simple_types: - if field.seq or field.opt: + level = 2 + template = "node.%s.walkabout(self)" + if field.seq: + template = "self.visit_sequence(node.%s)" + elif field.opt: self.emit("if node.%s:" % (field.name,), 2) level = 3 - else: - level = 2 - if field.seq: - template = "self.visit_sequence(node.%s)" - else: - template = "node.%s.walkabout(self)" self.emit(template % (field.name,), level) return True return False @@ -446,6 +445,7 @@ if field.seq: self.emit("w_self.w_%s = w_new_value" % (field.name,), 1) else: + save_original_object = False self.emit("try:", 1) if field.type.value not in asdl.builtin_types: # These are always other AST nodes. @@ -454,9 +454,7 @@ (field.type,), 2) self.emit("w_self.%s = obj.to_simple_int(space)" % (field.name,), 2) - self.emit("# need to save the original object too", 2) - self.emit("w_self.setdictvalue(space, '%s', w_new_value)" - % (field.name,), 2) + save_original_object = True else: config = (field.name, field.type, repr(field.opt)) self.emit("w_self.%s = space.interp_w(%s, w_new_value, %s)" % @@ -480,6 +478,12 @@ self.emit(" w_self.setdictvalue(space, '%s', w_new_value)" % (field.name,), 1) self.emit(" return", 1) + if save_original_object: + self.emit("# need to save the original object too", 1) + self.emit("w_self.setdictvalue(space, '%s', w_new_value)" + % (field.name,), 1) + else: + self.emit("w_self.deldictvalue(space, '%s')" %(field.name,), 1) self.emit("w_self.initialization_state |= %s" % (flag,), 1) self.emit("") diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -44,11 +44,11 @@ return True return False - def deldictvalue(self, space, w_name): + def deldictvalue(self, space, attr): w_dict = self.getdict(space) if w_dict is not None: try: - space.delitem(w_dict, w_name) + space.delitem(w_dict, space.wrap(attr)) return True except OperationError, ex: if not ex.match(space, space.w_KeyError): @@ -130,6 +130,9 @@ raise operationerrfmt(space.w_TypeError, "cannot create weak reference to '%s' object", typename) + def delweakref(self): + pass + def clear_all_weakrefs(self): """Call this at the beginning of interp-level __del__() methods in subclasses. It ensures that weakrefs (if any) are cleared @@ -143,29 +146,28 @@ # app-level, e.g. a user-defined __del__(), and this code # tries to use weakrefs again, it won't reuse the broken # (already-cleared) weakrefs from this lifeline. - self.setweakref(lifeline.space, None) + self.delweakref() lifeline.clear_all_weakrefs() - __already_enqueued_for_destruction = False + __already_enqueued_for_destruction = () - def _enqueue_for_destruction(self, space, call_user_del=True): + def enqueue_for_destruction(self, space, callback, descrname): """Put the object in the destructor queue of the space. - At a later, safe point in time, UserDelAction will use - space.userdel() to call the object's app-level __del__ method. + At a later, safe point in time, UserDelAction will call + callback(self). If that raises OperationError, prints it + to stderr with the descrname string. + + Note that 'callback' will usually need to start with: + assert isinstance(self, W_SpecificClass) """ # this function always resurect the object, so when # running on top of CPython we must manually ensure that # we enqueue it only once if not we_are_translated(): - if self.__already_enqueued_for_destruction: + if callback in self.__already_enqueued_for_destruction: return - self.__already_enqueued_for_destruction = True - self.clear_all_weakrefs() - if call_user_del: - space.user_del_action.register_dying_object(self) - - def _call_builtin_destructor(self): - pass # method overridden in typedef.py + self.__already_enqueued_for_destruction += (callback,) + space.user_del_action.register_callback(self, callback, descrname) # hooks that the mapdict implementations needs: def _get_mapdict_map(self): @@ -237,7 +239,7 @@ class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. - http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" + http://pypy.readthedocs.org/en/latest/objspace.html""" full_exceptions = True # full support for exceptions (normalization & more) @@ -311,9 +313,6 @@ mod = self.interpclass_w(w_mod) if isinstance(mod, Module) and mod.startup_called: mod.shutdown(self) - if self.config.objspace.std.withdictmeasurement: - from pypy.objspace.std.dictmultiobject import report - report() if self.config.objspace.logbytecodes: self.reportbytecodecounts() if self.config.objspace.std.logspaceoptypes: @@ -928,6 +927,9 @@ return self.w_True return self.w_False + def issequence_w(self, w_obj): + return (self.findattr(w_obj, self.wrap("__getitem__")) is not None) + def isinstance_w(self, w_obj, w_type): return self.is_true(self.isinstance(w_obj, w_type)) @@ -1282,6 +1284,17 @@ self.wrap("expected a 32-bit integer")) return value + def truncatedint(self, w_obj): + # Like space.gateway_int_w(), but return the integer truncated + # instead of raising OverflowError. For obscure cases only. + try: + return self.int_w(w_obj) + except OperationError, e: + if not e.match(self, self.w_OverflowError): + raise + from pypy.rlib.rarithmetic import intmask + return intmask(self.bigint_w(w_obj).uintmask()) + def c_filedescriptor_w(self, w_fd): # This is only used sometimes in CPython, e.g. for os.fsync() but # not os.close(). It's likely designed for 'select'. It's irregular diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -189,7 +189,7 @@ if space.is_w(w_value, space.w_None): # raise Type: we assume we have to instantiate Type w_value = space.call_function(w_type) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: w_valuetype = space.exception_getclass(w_value) if space.exception_issubclass_w(w_valuetype, w_type): @@ -204,18 +204,12 @@ else: # raise Type, X: assume X is the constructor argument w_value = space.call_function(w_type, w_value) - w_type = space.exception_getclass(w_value) + w_type = self._exception_getclass(space, w_value) else: # the only case left here is (inst, None), from a 'raise inst'. w_inst = w_type - w_instclass = space.exception_getclass(w_inst) - if not space.exception_is_valid_class_w(w_instclass): - instclassname = w_instclass.getname(space) - msg = ("exceptions must be old-style classes or derived " - "from BaseException, not %s") - raise operationerrfmt(space.w_TypeError, msg, instclassname) - + w_instclass = self._exception_getclass(space, w_inst) if not space.is_w(w_value, space.w_None): raise OperationError(space.w_TypeError, space.wrap("instance exception may not " @@ -226,6 +220,15 @@ self.w_type = w_type self._w_value = w_value + def _exception_getclass(self, space, w_inst): + w_type = space.exception_getclass(w_inst) + if not space.exception_is_valid_class_w(w_type): + typename = w_type.getname(space) + msg = ("exceptions must be old-style classes or derived " + "from BaseException, not %s") + raise operationerrfmt(space.w_TypeError, msg, typename) + return w_type + def write_unraisable(self, space, where, w_object=None): if w_object is None: objrepr = '' diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -484,44 +484,31 @@ def __init__(self, space): AsyncAction.__init__(self, space) - self.dying_objects_w = [] - self.weakrefs_w = [] + self.dying_objects = [] self.finalizers_lock_count = 0 - def register_dying_object(self, w_obj): - self.dying_objects_w.append(w_obj) - self.fire() - - def register_weakref_callback(self, w_ref): - self.weakrefs_w.append(w_ref) + def register_callback(self, w_obj, callback, descrname): + self.dying_objects.append((w_obj, callback, descrname)) self.fire() def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: return - # Each call to perform() first grabs the self.dying_objects_w + # Each call to perform() first grabs the self.dying_objects # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. - pending_w = self.dying_objects_w - self.dying_objects_w = [] + pending = self.dying_objects + self.dying_objects = [] space = self.space - for i in range(len(pending_w)): - w_obj = pending_w[i] - pending_w[i] = None + for i in range(len(pending)): + w_obj, callback, descrname = pending[i] + pending[i] = (None, None, None) try: - space.userdel(w_obj) + callback(w_obj) except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_obj) + e.write_unraisable(space, descrname, w_obj) e.clear(space) # break up reference cycles - # finally, this calls the interp-level destructor for the - # cases where there is both an app-level and a built-in __del__. - w_obj._call_builtin_destructor() - pending_w = self.weakrefs_w - self.weakrefs_w = [] - for i in range(len(pending_w)): - w_ref = pending_w[i] - w_ref.activate_callback() class FrameTraceAction(AsyncAction): """An action that calls the local trace functions (w_f_trace).""" diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -16,7 +16,7 @@ funccallunrolling = unrolling_iterable(range(4)) - at jit.purefunction_promote() + at jit.elidable_promote() def _get_immutable_code(func): assert not func.can_change_code return func.code @@ -31,7 +31,8 @@ _immutable_fields_ = ['code?', 'w_func_globals?', 'closure?', - 'defs_w?[*]'] + 'defs_w?[*]', + 'name?'] def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): @@ -63,7 +64,7 @@ if jit.we_are_jitted(): if not self.can_change_code: return _get_immutable_code(self) - return jit.hint(self.code, promote=True) + return jit.promote(self.code) return self.code def funccall(self, *args_w): # speed hack @@ -465,19 +466,23 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - myname = self.getname(space,"") - clsdescr = self.w_class.getname(space,"") + myname = self.getname(space, "") + clsdescr = self.w_class.getname(space, "") if clsdescr: - clsdescr+=" " + clsdescr += " instance" + else: + clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space,"") + instname = space.abstract_getclass(w_firstarg).getname(space, + "") if instname: - instname += " " - instdescr = "%sinstance" %instname - msg = ("unbound method %s() must be called with %s" - "instance as first argument (got %s instead)") + instdescr = instname + " instance" + else: + instdescr = "instance" + msg = ("unbound method %s() must be called with %s " + "as first argument (got %s instead)") raise operationerrfmt(space.w_TypeError, msg, myname, clsdescr, instdescr) return space.call_args(self.w_function, args) diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -140,6 +140,9 @@ def visit_c_nonnegint(self, el, app_sig): self.checked_space_method(el, app_sig) + def visit_truncatedint(self, el, app_sig): + self.checked_space_method(el, app_sig) + def visit__Wrappable(self, el, app_sig): name = el.__name__ argname = self.orig_arg() @@ -257,6 +260,9 @@ def visit_c_nonnegint(self, typ): self.run_args.append("space.c_nonnegint_w(%s)" % (self.scopenext(),)) + def visit_truncatedint(self, typ): + self.run_args.append("space.truncatedint(%s)" % (self.scopenext(),)) + def _make_unwrap_activation_class(self, unwrap_spec, cache={}): try: key = tuple(unwrap_spec) @@ -387,6 +393,9 @@ def visit_c_nonnegint(self, typ): self.unwrap.append("space.c_nonnegint_w(%s)" % (self.nextarg(),)) + def visit_truncatedint(self, typ): + self.unwrap.append("space.truncatedint(%s)" % (self.nextarg(),)) + def make_fastfunc(unwrap_spec, func): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) @@ -396,11 +405,14 @@ fastfunc = func else: # try to avoid excessive bloat - if func.__module__ == 'pypy.interpreter.astcompiler.ast': + mod = func.__module__ + if mod is None: + mod = "" + if mod == 'pypy.interpreter.astcompiler.ast': raise FastFuncNotSupported - if (not func.__module__.startswith('pypy.module.__builtin__') and - not func.__module__.startswith('pypy.module.sys') and - not func.__module__.startswith('pypy.module.math')): + if (not mod.startswith('pypy.module.__builtin__') and + not mod.startswith('pypy.module.sys') and + not mod.startswith('pypy.module.math')): if not func.__name__.startswith('descr'): raise FastFuncNotSupported d = {} diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -62,7 +62,7 @@ raise operr # XXX it's not clear that last_instr should be promoted at all # but as long as it is necessary for call_assembler, let's do it early - last_instr = jit.hint(frame.last_instr, promote=True) + last_instr = jit.promote(frame.last_instr) if last_instr == -1: if w_arg and not space.is_w(w_arg, space.w_None): msg = "can't send non-None value to a just-started generator" @@ -114,6 +114,7 @@ def descr_close(self): """x.close(arg) -> raise GeneratorExit inside generator.""" + assert isinstance(self, GeneratorIterator) space = self.space try: w_retval = self.throw(space.w_GeneratorExit, space.w_None, @@ -141,22 +142,16 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def descr__del__(self): - """ - applevel __del__, which is called at a safe point after the - interp-level __del__ enqueued the object for destruction - """ - self.descr_close() - def __del__(self): # Only bother enqueuing self to raise an exception if the frame is # still not finished and finally or except blocks are present. - must_call_close = False + self.clear_all_weakrefs() if self.frame is not None: block = self.frame.lastblock while block is not None: if not isinstance(block, LoopBlock): - must_call_close = True + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") break block = block.previous - self._enqueue_for_destruction(self.space, must_call_close) diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -9,6 +9,8 @@ class Module(Wrappable): """A module.""" + _immutable_fields_ = ["w_dict?"] + _frozen = False def __init__(self, space, w_name, w_dict=None, add_package=True): diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py --- a/pypy/interpreter/pycompiler.py +++ b/pypy/interpreter/pycompiler.py @@ -119,7 +119,10 @@ raise OperationError(self.space.w_TypeError, self.space.wrap( "invalid node type")) - future_pos = misc.parse_future(node) + fut = misc.parse_future(node, self.future_flags.compiler_features) + f_flags, f_lineno, f_col = fut + future_pos = f_lineno, f_col + flags |= f_flags info = pyparse.CompileInfo(filename, mode, flags, future_pos) return self._compile_ast(node, info) diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -905,16 +905,15 @@ def SETUP_WITH(self, offsettoend, next_instr): w_manager = self.peekvalue() + w_enter = self.space.lookup(w_manager, "__enter__") w_descr = self.space.lookup(w_manager, "__exit__") - if w_descr is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__exit__")) + if w_enter is None or w_descr is None: + typename = self.space.type(w_manager).getname(self.space) + raise operationerrfmt(self.space.w_AttributeError, + "'%s' object is not a context manager" + " (no __enter__/__exit__ method)", typename) w_exit = self.space.get(w_descr, w_manager) self.settopvalue(w_exit) - w_enter = self.space.lookup(w_manager, "__enter__") - if w_enter is None: - raise OperationError(self.space.w_AttributeError, - self.space.wrap("__enter__")) w_result = self.space.get_and_call_function(w_enter, w_manager) block = WithBlock(self, next_instr + offsettoend) self.append_block(block) @@ -1060,18 +1059,6 @@ def SET_LINENO(self, lineno, next_instr): pass - def CALL_LIKELY_BUILTIN(self, oparg, next_instr): - # overridden by faster version in the standard object space. - from pypy.module.__builtin__ import OPTIMIZED_BUILTINS - varname = OPTIMIZED_BUILTINS[oparg >> 8] - w_function = self._load_global(varname) - nargs = oparg&0xFF - try: - w_result = self.space.call_valuestack(w_function, nargs, self) - finally: - self.dropvalues(nargs) - self.pushvalue(w_result) - # overridden by faster version in the standard object space. LOOKUP_METHOD = LOAD_ATTR CALL_METHOD = CALL_FUNCTION diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py --- a/pypy/interpreter/test/test_executioncontext.py +++ b/pypy/interpreter/test/test_executioncontext.py @@ -106,7 +106,7 @@ if isinstance(seen[0], Method): found = 'method %s of %s' % ( seen[0].w_function.name, - seen[0].w_class.getname(space, '?')) + seen[0].w_class.getname(space)) else: assert isinstance(seen[0], Function) found = 'builtin %s' % seen[0].name @@ -232,31 +232,6 @@ assert [i[0] for i in events] == ['c_call', 'c_return', 'return', 'c_call'] assert events[0][1] == events[1][1] - def test_tracing_range_builtinshortcut(self): - opts = {"objspace.opcodes.CALL_LIKELY_BUILTIN": True} - space = gettestobjspace(**opts) - source = """def f(profile): - import sys - sys.setprofile(profile) - range(10) - sys.setprofile(None) - """ - w_events = space.appexec([space.wrap(source)], """(source): - import sys - l = [] - def profile(frame, event, arg): - l.append((event, arg)) - d = {} - exec source in d - f = d['f'] - f(profile) - import dis - print dis.dis(f) - return l - """) - events = space.unwrap(w_events) - assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] - def test_profile_and_exception(self): space = self.space w_res = space.appexec([], """(): @@ -280,9 +255,6 @@ """) -class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True} - class TestExecutionContextWithCallMethod(TestExecutionContext): keywords = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/interpreter/test/test_raise.py b/pypy/interpreter/test/test_raise.py --- a/pypy/interpreter/test/test_raise.py +++ b/pypy/interpreter/test/test_raise.py @@ -274,3 +274,9 @@ pass except A: pass + + def test_new_returns_bad_instance(self): + class MyException(Exception): + def __new__(cls, *args): + return object() + raises(TypeError, "raise MyException") diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -1,3 +1,4 @@ +import gc from pypy.interpreter import typedef from pypy.tool.udir import udir from pypy.interpreter.baseobjspace import Wrappable @@ -16,7 +17,7 @@ def g(): f() - + try: g() except: @@ -180,6 +181,85 @@ assert err.value.message == "'some_type' objects are unhashable" """) + def test_destructor(self): + space = self.space + class W_Level1(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + space.call_method(w_seen, 'append', space.wrap(1)) + class W_Level2(Wrappable): + def __init__(self, space1): + assert space1 is space + def __del__(self): + self.enqueue_for_destruction(space, W_Level2.destructormeth, + 'FOO ') + def destructormeth(self): + space.call_method(w_seen, 'append', space.wrap(2)) + W_Level1.typedef = typedef.TypeDef( + 'level1', + __new__ = typedef.generic_new_descr(W_Level1)) + W_Level2.typedef = typedef.TypeDef( + 'level2', + __new__ = typedef.generic_new_descr(W_Level2)) + # + w_seen = space.newlist([]) + W_Level1(space) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + W_Level2(space) + gc.collect(); gc.collect() + assert space.str_w(space.repr(w_seen)) == "[]" # not called yet + ec = space.getexecutioncontext() + self.space.user_del_action.perform(ec, None) + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef)], + """(level1): + class A3(level1): + pass + A3() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level1.typedef), + w_seen], + """(level1, seen): + class A4(level1): + def __del__(self): + seen.append(4) + A4() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [4, 1] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef)], + """(level2): + class A5(level2): + pass + A5() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [2] + # + w_seen = space.newlist([]) + self.space.appexec([self.space.gettypeobject(W_Level2.typedef), + w_seen], + """(level2, seen): + class A6(level2): + def __del__(self): + seen.append(6) + A6() + """) + gc.collect(); gc.collect() + assert space.unwrap(w_seen) == [6, 2] + class AppTestTypeDef: @@ -210,19 +290,20 @@ def m(self): "aaa" m.x = 3 + class B(A): + pass - bm = A().m + bm = B().m assert bm.__func__ is bm.im_func assert bm.__self__ is bm.im_self - assert bm.im_class is A - if '__pypy__' in sys.builtin_module_names: - assert bm.__objclass__ is A + assert bm.im_class is B assert bm.__doc__ == "aaa" assert bm.x == 3 raises(AttributeError, setattr, bm, 'x', 15) l = [] assert l.append.__self__ is l - if '__pypy__' in sys.builtin_module_names: - assert l.append.__objclass__ is list assert l.__add__.__self__ is l - assert l.__add__.__objclass__ is list + # note: 'l.__add__.__objclass__' is not defined in pypy + # because it's a regular method, and .__objclass__ + # differs from .im_class in case the method is + # defined in some parent class of l's actual class diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -9,7 +9,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote class TypeDef: def __init__(self, __name, __base=None, **rawdict): @@ -23,7 +23,7 @@ self.hasdict |= __base.hasdict self.weakrefable |= __base.weakrefable self.rawdict = {} - self.acceptable_as_base_class = True + self.acceptable_as_base_class = '__new__' in rawdict self.applevel_subclasses_base = None # xxx used by faking self.fakedcpytype = None @@ -206,7 +206,7 @@ user_overridden_class = True def getclass(self, space): - return hint(self.w__class__, promote=True) + return promote(self.w__class__) def setclass(self, space, w_subtype): # only used by descr_set___class__ @@ -228,21 +228,26 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None add(Proto) if "del" in features: + parent_destructor = getattr(supercls, '__del__', None) + def call_parent_del(self): + assert isinstance(self, subcls) + parent_destructor(self) + def call_applevel_del(self): + assert isinstance(self, subcls) + self.space.userdel(self) class Proto(object): def __del__(self): - self._enqueue_for_destruction(self.space) - # if the base class needs its own interp-level __del__, - # we override the _call_builtin_destructor() method to invoke it - # after the app-level destructor. - parent_destructor = getattr(supercls, '__del__', None) - if parent_destructor is not None: - def _call_builtin_destructor(self): - parent_destructor(self) - Proto._call_builtin_destructor = _call_builtin_destructor - + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, call_applevel_del, + 'method __del__ of ') + if parent_destructor is not None: + self.enqueue_for_destruction(self.space, call_parent_del, + 'internal destructor of ') add(Proto) if "slots" in features: @@ -630,9 +635,12 @@ return self._lifeline_ def setweakref(self, space, weakreflifeline): self._lifeline_ = weakreflifeline + def delweakref(self): + self._lifeline_ = None cls._lifeline_ = None cls.getweakref = getweakref cls.setweakref = setweakref + cls.delweakref = delweakref return weakref_descr @@ -771,7 +779,6 @@ im_self = interp_attrproperty_w('w_instance', cls=Method), __self__ = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), - __objclass__ = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), __eq__ = interp2app(Method.descr_method_eq), __ne__ = descr_generic_ne, @@ -859,8 +866,6 @@ descrmismatch='close'), __iter__ = interp2app(GeneratorIterator.descr__iter__, descrmismatch='__iter__'), - __del__ = interp2app(GeneratorIterator.descr__del__, - descrmismatch='__del__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame), gi_code = GetSetProperty(GeneratorIterator.descr_gi_code), diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -453,21 +453,33 @@ class WriteBarrierDescr(AbstractDescr): def __init__(self, gc_ll_descr): + GCClass = gc_ll_descr.GCClass self.llop1 = gc_ll_descr.llop1 self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR - self.fielddescr_tid = get_field_descr(gc_ll_descr, - gc_ll_descr.GCClass.HDR, 'tid') - self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG - # if convenient for the backend, we also compute the info about + self.fielddescr_tid = get_field_descr(gc_ll_descr, GCClass.HDR, 'tid') + # + self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG + self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = ( + self.extract_flag_byte(self.jit_wb_if_flag)) + # + if hasattr(GCClass, 'JIT_WB_CARDS_SET'): + self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET + self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT + self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = ( + self.extract_flag_byte(self.jit_wb_cards_set)) + else: + self.jit_wb_cards_set = 0 + + def extract_flag_byte(self, flag_word): + # if convenient for the backend, we compute the info about # the flag as (byte-offset, single-byte-flag). import struct - value = struct.pack("l", self.jit_wb_if_flag) + value = struct.pack("l", flag_word) assert value.count('\x00') == len(value) - 1 # only one byte is != 0 i = 0 while value[i] == '\x00': i += 1 - self.jit_wb_if_flag_byteofs = i - self.jit_wb_if_flag_singlebyte = struct.unpack('b', value[i])[0] + return (i, struct.unpack('b', value[i])[0]) def get_write_barrier_fn(self, cpu): llop1 = self.llop1 diff --git a/pypy/jit/backend/llvm/llvm_rffi.py b/pypy/jit/backend/llvm/llvm_rffi.py --- a/pypy/jit/backend/llvm/llvm_rffi.py +++ b/pypy/jit/backend/llvm/llvm_rffi.py @@ -3,7 +3,7 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo, log -if sys.platform != 'linux2': +if not sys.platform.startswith('linux'): py.test.skip("Linux only for now") # ____________________________________________________________ diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -1707,6 +1707,7 @@ jit_wb_if_flag = 4096 jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 0 def get_write_barrier_from_array_fn(self, cpu): return funcbox.getint() # @@ -1728,6 +1729,72 @@ else: assert record == [] + def test_cond_call_gc_wb_array_card_marking_fast_path(self): + def func_void(a, b, c): + record.append((a, b, c)) + record = [] + # + S = lltype.Struct('S', ('tid', lltype.Signed)) + S_WITH_CARDS = lltype.Struct('S_WITH_CARDS', + ('card0', lltype.Char), + ('card1', lltype.Char), + ('card2', lltype.Char), + ('card3', lltype.Char), + ('card4', lltype.Char), + ('card5', lltype.Char), + ('card6', lltype.Char), + ('card7', lltype.Char), + ('data', S)) + FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)], + lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + funcbox = self.get_funcbox(self.cpu, func_ptr) + class WriteBarrierDescr(AbstractDescr): + jit_wb_if_flag = 4096 + jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') + jit_wb_if_flag_singlebyte = 0x10 + jit_wb_cards_set = 8192 + jit_wb_cards_set_byteofs = struct.pack("i", 8192).index('\x20') + jit_wb_cards_set_singlebyte = 0x20 + jit_wb_card_page_shift = 7 + def get_write_barrier_from_array_fn(self, cpu): + return funcbox.getint() + # + for BoxIndexCls in [BoxInt, ConstInt]: + for cond in [False, True]: + print + print '_'*79 + print 'BoxIndexCls =', BoxIndexCls + print 'JIT_WB_CARDS_SET =', cond + print + value = random.randrange(-sys.maxint, sys.maxint) + value |= 4096 + if cond: + value |= 8192 + else: + value &= ~8192 + s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True) + s.data.tid = value + sgcref = rffi.cast(llmemory.GCREF, s.data) + del record[:] + box_index = BoxIndexCls((9<<7) + 17) + self.execute_operation(rop.COND_CALL_GC_WB_ARRAY, + [BoxPtr(sgcref), box_index, BoxPtr(sgcref)], + 'void', descr=WriteBarrierDescr()) + if cond: + assert record == [] + assert s.card6 == '\x02' + else: + assert record == [(s.data, (9<<7) + 17, s.data)] + assert s.card6 == '\x00' + assert s.card0 == '\x00' + assert s.card1 == '\x00' + assert s.card2 == '\x00' + assert s.card3 == '\x00' + assert s.card4 == '\x00' + assert s.card5 == '\x00' + assert s.card7 == '\x00' + def test_force_operations_returning_void(self): values = [] def maybe_force(token, flag): diff --git a/pypy/jit/backend/x86/arch.py b/pypy/jit/backend/x86/arch.py --- a/pypy/jit/backend/x86/arch.py +++ b/pypy/jit/backend/x86/arch.py @@ -27,3 +27,6 @@ # which are used in the malloc itself. They are: # ecx, ebx, esi, edi [32 and 64 bits] # r8, r9, r10, r12, r13, r14, r15 [64 bits only] +# +# Note that with asmgcc, the locations corresponding to callee-save registers +# are never used. diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -181,6 +181,7 @@ # instructions in assembler, with a mark_gc_roots in between. # With shadowstack, this is not needed, so we produce a single helper. gcrootmap = self.cpu.gc_ll_descr.gcrootmap + shadow_stack = (gcrootmap is not None and gcrootmap.is_shadow_stack) # # ---------- first helper for the slow path of malloc ---------- mc = codebuf.MachineCodeBlockWrapper() @@ -190,10 +191,19 @@ mc.SUB_rr(edx.value, eax.value) # compute the size we want addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr() # - if gcrootmap is not None and gcrootmap.is_shadow_stack: + # The registers to save in the copy area: with shadowstack, most + # registers need to be saved. With asmgcc, the callee-saved registers + # don't need to. + save_in_copy_area = gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items() + if not shadow_stack: + save_in_copy_area = [(reg, ofs) for (reg, ofs) in save_in_copy_area + if reg not in gpr_reg_mgr_cls.REGLOC_TO_GCROOTMAP_REG_INDEX] + # + for reg, ofs in save_in_copy_area: + mc.MOV_br(ofs, reg.value) + # + if shadow_stack: # ---- shadowstack ---- - for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items(): - mc.MOV_br(ofs, reg.value) mc.SUB_ri(esp.value, 16 - WORD) # stack alignment of 16 bytes if IS_X86_32: mc.MOV_sr(0, edx.value) # push argument @@ -201,15 +211,13 @@ mc.MOV_rr(edi.value, edx.value) mc.CALL(imm(addr)) mc.ADD_ri(esp.value, 16 - WORD) - for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items(): - mc.MOV_rb(reg.value, ofs) else: # ---- asmgcc ---- if IS_X86_32: mc.MOV_sr(WORD, edx.value) # save it as the new argument elif IS_X86_64: - # rdi can be clobbered: its content was forced to the stack - # by _fastpath_malloc(), like all other save_around_call_regs. + # rdi can be clobbered: its content was saved in the + # copy area of the stack mc.MOV_rr(edi.value, edx.value) mc.JMP(imm(addr)) # tail call to the real malloc rawstart = mc.materialize(self.cpu.asmmemmgr, []) @@ -217,6 +225,10 @@ # ---------- second helper for the slow path of malloc ---------- mc = codebuf.MachineCodeBlockWrapper() # + for reg, ofs in save_in_copy_area: + mc.MOV_rb(reg.value, ofs) + assert reg is not eax and reg is not edx + # if self.cpu.supports_floats: # restore the XMM registers for i in range(self.cpu.NUM_REGS):# from where they were saved mc.MOVSD_xs(i, (WORD*2)+8*i) @@ -416,10 +428,13 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - debug_print("Loop #%d (%s) has address %x to %x" % ( + debug_start("jit-backend-addr") + debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % ( looptoken.number, loopname, rawstart + self.looppos, - rawstart + directbootstrappos)) + rawstart + directbootstrappos, + rawstart)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -478,9 +493,10 @@ fullsize = self.mc.get_relative_pos() # rawstart = self.materialize_loop(original_loop_token) - - debug_print("Bridge out of guard %d has address %x to %x" % + debug_start("jit-backend-addr") + debug_print("bridge out of Guard %d has address %x to %x" % (descr_number, rawstart, rawstart + codeendpos)) + debug_stop("jit-backend-addr") self._patch_stackadjust(rawstart + stackadjustpos, frame_depth + param_depth) self.patch_pending_failure_recoveries(rawstart) @@ -2242,10 +2258,12 @@ if opnum == rop.COND_CALL_GC_WB: N = 2 func = descr.get_write_barrier_fn(self.cpu) + card_marking = False elif opnum == rop.COND_CALL_GC_WB_ARRAY: N = 3 func = descr.get_write_barrier_from_array_fn(self.cpu) assert func != 0 + card_marking = descr.jit_wb_cards_set != 0 else: raise AssertionError(opnum) # @@ -2254,6 +2272,18 @@ imm(descr.jit_wb_if_flag_singlebyte)) self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later jz_location = self.mc.get_relative_pos() + + # for cond_call_gc_wb_array, also add another fast path: + # if GCFLAG_CARDS_SET, then we can just set one bit and be done + if card_marking: + self.mc.TEST8(addr_add_const(loc_base, + descr.jit_wb_cards_set_byteofs), + imm(descr.jit_wb_cards_set_singlebyte)) + self.mc.J_il8(rx86.Conditions['NZ'], 0) # patched later + jnz_location = self.mc.get_relative_pos() + else: + jnz_location = 0 + # the following is supposed to be the slow path, so whenever possible # we choose the most compact encoding over the most efficient one. if IS_X86_32: @@ -2293,6 +2323,43 @@ loc = arglocs[i] assert isinstance(loc, RegLoc) self.mc.POP_r(loc.value) + + # if GCFLAG_CARDS_SET, then we can do the whole thing that would + # be done in the CALL above with just four instructions, so here + # is an inline copy of them + if card_marking: + self.mc.JMP_l8(0) # jump to the exit, patched later + jmp_location = self.mc.get_relative_pos() + # patch the JNZ above + offset = self.mc.get_relative_pos() - jnz_location + assert 0 < offset <= 127 + self.mc.overwrite(jnz_location-1, chr(offset)) + # + loc_index = arglocs[1] + if isinstance(loc_index, RegLoc): + # choose a scratch register + tmp1 = loc_index + self.mc.PUSH_r(tmp1.value) + # SHR tmp, card_page_shift + self.mc.SHR_ri(tmp1.value, descr.jit_wb_card_page_shift) + # XOR tmp, -8 + self.mc.XOR_ri(tmp1.value, -8) + # BTS [loc_base], tmp + self.mc.BTS(addr_add_const(loc_base, 0), tmp1) + # done + self.mc.POP_r(tmp1.value) + elif isinstance(loc_index, ImmedLoc): + byte_index = loc_index.value >> descr.jit_wb_card_page_shift + byte_ofs = ~(byte_index >> 3) + byte_val = 1 << (byte_index & 7) + self.mc.OR8(addr_add_const(loc_base, byte_ofs), imm(byte_val)) + else: + raise AssertionError("index is neither RegLoc nor ImmedLoc") + # patch the JMP above + offset = self.mc.get_relative_pos() - jmp_location + assert 0 < offset <= 127 + self.mc.overwrite(jmp_location-1, chr(offset)) + # # patch the JZ above offset = self.mc.get_relative_pos() - jz_location assert 0 < offset <= 127 @@ -2369,8 +2436,7 @@ # there are two helpers to call only with asmgcc slowpath_addr1 = self.malloc_slowpath1 self.mc.CALL(imm(slowpath_addr1)) - self.mark_gc_roots(self.write_new_force_index(), - use_copy_area=shadow_stack) + self.mark_gc_roots(self.write_new_force_index(), use_copy_area=True) slowpath_addr2 = self.malloc_slowpath2 self.mc.CALL(imm(slowpath_addr2)) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -921,27 +921,13 @@ def _do_fastpath_malloc(self, op, size, tid): gc_ll_descr = self.assembler.cpu.gc_ll_descr self.rm.force_allocate_reg(op.result, selected_reg=eax) - - if gc_ll_descr.gcrootmap and gc_ll_descr.gcrootmap.is_shadow_stack: - # ---- shadowstack ---- - # We need edx as a temporary, but otherwise don't save any more - # register. See comments in _build_malloc_slowpath(). - tmp_box = TempBox() - self.rm.force_allocate_reg(tmp_box, selected_reg=edx) - self.rm.possibly_free_var(tmp_box) - else: - # ---- asmgcc ---- - # We need to force-allocate each of save_around_call_regs now. - # The alternative would be to save and restore them around the - # actual call to malloc(), in the rare case where we need to do - # it; however, mark_gc_roots() would need to be adapted to know - # where the variables end up being saved. Messy. - for reg in self.rm.save_around_call_regs: - if reg is not eax: - tmp_box = TempBox() - self.rm.force_allocate_reg(tmp_box, selected_reg=reg) - self.rm.possibly_free_var(tmp_box) - + # + # We need edx as a temporary, but otherwise don't save any more + # register. See comments in _build_malloc_slowpath(). + tmp_box = TempBox() + self.rm.force_allocate_reg(tmp_box, selected_reg=edx) + self.rm.possibly_free_var(tmp_box) + # self.assembler.malloc_cond( gc_ll_descr.get_nursery_free_addr(), gc_ll_descr.get_nursery_top_addr(), @@ -1337,14 +1323,26 @@ if reg is eax: continue # ok to ignore this one if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)): - if use_copy_area: - assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS - area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg] - gcrootmap.add_frame_offset(shape, area_offset) - else: - assert reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX - gcrootmap.add_callee_save_reg( - shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg]) + # + # The register 'reg' is alive across this call. + gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap + if gcrootmap is None or not gcrootmap.is_shadow_stack: + # + # Asmgcc: if reg is a callee-save register, we can + # explicitly mark it as containing a BoxPtr. + if reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX: + gcrootmap.add_callee_save_reg( + shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg]) + continue + # + # Else, 'use_copy_area' must be True (otherwise this BoxPtr + # should not be in a register). The copy area contains the + # real value of the register. + assert use_copy_area + assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS + area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg] + gcrootmap.add_frame_offset(shape, area_offset) + # return gcrootmap.compress_callshape(shape, self.assembler.datablockwrapper) diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -476,6 +476,7 @@ AND = _binaryop('AND') OR = _binaryop('OR') + OR8 = _binaryop('OR8') XOR = _binaryop('XOR') NOT = _unaryop('NOT') SHL = _binaryop('SHL') @@ -483,6 +484,7 @@ SAR = _binaryop('SAR') TEST = _binaryop('TEST') TEST8 = _binaryop('TEST8') + BTS = _binaryop('BTS') ADD = _binaryop('ADD') SUB = _binaryop('SUB') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -464,7 +464,7 @@ # ------------------------------ MOV ------------------------------ - MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) + MOV_ri = insn(register(1), '\xB8', immediate(2)) MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b')) # ------------------------------ Arithmetic ------------------------------ @@ -496,6 +496,10 @@ AND8_rr = insn(rex_fw, '\x20', byte_register(1), byte_register(2,8), '\xC0') OR8_rr = insn(rex_fw, '\x08', byte_register(1), byte_register(2,8), '\xC0') + OR8_mi = insn(rex_fw, '\x80', orbyte(1<<3), mem_reg_plus_const(1), + immediate(2, 'b')) + OR8_ji = insn(rex_fw, '\x80', orbyte(1<<3), abs_, immediate(1), + immediate(2, 'b')) NEG_r = insn(rex_w, '\xF7', register(1), '\xD8') @@ -565,6 +569,9 @@ TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_, immediate(1), immediate(2, 'b')) TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0') + BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1)) + BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_, immediate(1)) + # x87 instructions FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) @@ -632,16 +639,20 @@ CQO = insn(rex_w, '\x99') - # MOV_ri from the parent class is not wrong, but here is a better encoding - # for the common case where the immediate fits in 32 bits + # Three different encodings... following what gcc does. From the + # shortest encoding to the longest one. + MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i')) MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i')) - MOV_ri64 = AbstractX86CodeBuilder.MOV_ri + MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q')) def MOV_ri(self, reg, immed): - if fits_in_32bits(immed): + if 0 <= immed <= 4294967295: + immed = intmask(rffi.cast(rffi.INT, immed)) + self.MOV_riu32(reg, immed) + elif fits_in_32bits(immed): # for negative values that fit in 32 bit self.MOV_ri32(reg, immed) else: - AbstractX86CodeBuilder.MOV_ri(self, reg, immed) + self.MOV_ri64(reg, immed) def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'): def add_insn(code, *modrm): diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py --- a/pypy/jit/backend/x86/test/test_regloc.py +++ b/pypy/jit/backend/x86/test/test_regloc.py @@ -24,9 +24,14 @@ assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000 assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011 assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9') - # XXX: What we are testing for here is actually not the most compact - # encoding. - assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30') + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected) + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30') + # for the next case we don't pick the most efficient encoding, but well + expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF' + assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected) assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30') def test_cmp_16(): @@ -44,7 +49,7 @@ def test_relocation(): from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.backend.x86 import codebuf - for target in [0x01020304, 0x0102030405060708]: + for target in [0x01020304, -0x05060708, 0x0102030405060708]: if target > sys.maxint: continue mc = codebuf.MachineCodeBlockWrapper() @@ -58,10 +63,15 @@ expected = "\xE8" + struct.pack(' movl $xxx, %eax + suffix = 'l' + if ops[1][2:].isdigit(): + ops[1] += 'd' + else: + ops[1] = '%e' + ops[1][2:] + # op = '\t%s%s %s%s' % (instrname.lower(), suffix, ', '.join(ops), following) g.write('%s\n' % op) diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py --- a/pypy/jit/backend/x86/test/test_zrpy_gc.py +++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py @@ -10,7 +10,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rlib.jit import JitDriver, dont_look_inside -from pypy.rlib.jit import purefunction, unroll_safe +from pypy.rlib.jit import elidable, unroll_safe from pypy.jit.backend.llsupport.gc import GcLLDescr_framework from pypy.tool.udir import udir from pypy.config.translationoption import DEFL_GC @@ -524,6 +524,76 @@ def test_compile_framework_8(self): self.run('compile_framework_8') + def define_compile_framework_9(cls): + # Like compile_framework_8, but with variable indexes and large + # arrays, testing the card_marking case + def before(n, x): + return n, x, None, None, None, None, None, None, None, None, [X(123)], None + def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + if n < 1900: + check(l[0].x == 123) + num = 512 + (n & 7) + l = [None] * num + l[0] = X(123) + l[1] = X(n) + l[2] = X(n+10) + l[3] = X(n+20) + l[4] = X(n+30) + l[5] = X(n+40) + l[6] = X(n+50) + l[7] = X(n+60) + l[num-8] = X(n+70) + l[num-9] = X(n+80) + l[num-10] = X(n+90) + l[num-11] = X(n+100) + l[-12] = X(n+110) + l[-13] = X(n+120) + l[-14] = X(n+130) + l[-15] = X(n+140) + if n < 1800: + num = 512 + (n & 7) + check(len(l) == num) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[num-8].x == n+70) + check(l[num-9].x == n+80) + check(l[num-10].x == n+90) + check(l[num-11].x == n+100) + check(l[-12].x == n+110) + check(l[-13].x == n+120) + check(l[-14].x == n+130) + check(l[-15].x == n+140) + n -= x.foo + return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s + def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s): + check(len(l) >= 512) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[-8].x == 72) + check(l[-9].x == 82) + check(l[-10].x == 92) + check(l[-11].x == 102) + check(l[-12].x == 112) + check(l[-13].x == 122) + check(l[-14].x == 132) + check(l[-15].x == 142) + return before, f, after + + def test_compile_framework_9(self): + self.run('compile_framework_9') + def define_compile_framework_external_exception_handling(cls): def before(n, x): x = X(0) @@ -561,7 +631,7 @@ self.run('compile_framework_external_exception_handling') def define_compile_framework_bug1(self): - @purefunction + @elidable def nonmoving(): x = X(1) for i in range(7): diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py --- a/pypy/jit/backend/x86/test/test_ztranslation.py +++ b/pypy/jit/backend/x86/test/test_ztranslation.py @@ -2,7 +2,7 @@ from pypy.tool.udir import udir from pypy.rlib.jit import JitDriver, unroll_parameters from pypy.rlib.jit import PARAMETERS, dont_look_inside -from pypy.rlib.jit import hint +from pypy.rlib.jit import promote from pypy.jit.metainterp.jitprof import Profiler from pypy.jit.backend.detect_cpu import getcpuclass from pypy.jit.backend.test.support import CCompiledMixin @@ -78,8 +78,7 @@ x = float(j) while i > 0: jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x) - jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() argchain.arg(x) res = func.call(argchain, rffi.DOUBLE) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -5,10 +5,9 @@ from pypy.jit.codewriter import support from pypy.jit.codewriter.jitcode import JitCode -from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer -from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer -from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze -from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection +from pypy.jit.codewriter.effectinfo import (VirtualizableAnalyzer, + QuasiImmutAnalyzer, CanReleaseGILAnalyzer, effectinfo_from_writeanalyze, + EffectInfo, CallInfoCollection) from pypy.translator.simplify import get_funcobj, get_functype from pypy.rpython.lltypesystem import lltype, llmemory from pypy.translator.backendopt.canraise import RaiseAnalyzer @@ -32,6 +31,7 @@ self.readwrite_analyzer = ReadWriteAnalyzer(translator) self.virtualizable_analyzer = VirtualizableAnalyzer(translator) self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator) + self.canreleasegil_analyzer = CanReleaseGILAnalyzer(translator) # for index, jd in enumerate(jitdrivers_sd): jd.index = index @@ -208,26 +208,28 @@ assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok - # get the 'pure' and 'loopinvariant' flags from the function object - pure = False + # get the 'elidable' and 'loopinvariant' flags from the function object + elidable = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) - pure = getattr(func, "_pure_function_", False) + elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect - can_invalidate = self.quasiimmut_analyzer.analyze(op) + can_release_gil = self.canreleasegil_analyzer.analyze(op) + # can_release_gil implies can_invalidate + can_invalidate = can_release_gil or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT - elif pure: + elif elidable: # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_PURE + extraeffect = EffectInfo.EF_ELIDABLE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -235,11 +237,11 @@ # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, - oopspecindex, can_invalidate) + oopspecindex, can_invalidate, can_release_gil) # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None - if pure or loopinvariant: + if elidable or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,7 +9,7 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_PURE = 0 #pure function (and cannot raise) + EF_ELIDABLE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise EF_CAN_RAISE = 3 #normal function (can raise) @@ -79,20 +79,22 @@ write_descrs_fields, write_descrs_arrays, extraeffect=EF_CAN_RAISE, oopspecindex=OS_NONE, - can_invalidate=False): + can_invalidate=False, can_release_gil=False): key = (frozenset(readonly_descrs_fields), frozenset(readonly_descrs_arrays), frozenset(write_descrs_fields), frozenset(write_descrs_arrays), extraeffect, - oopspecindex) + oopspecindex, + can_invalidate, + can_release_gil) if key in cls._cache: return cls._cache[key] result = object.__new__(cls) result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_PURE: + extraeffect == EffectInfo.EF_ELIDABLE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: @@ -100,6 +102,7 @@ result.write_descrs_arrays = write_descrs_arrays result.extraeffect = extraeffect result.can_invalidate = can_invalidate + result.can_release_gil = can_release_gil result.oopspecindex = oopspecindex cls._cache[key] = result return result @@ -111,12 +114,13 @@ return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE def has_random_effects(self): - return self.oopspecindex == self.OS_LIBFFI_CALL + return self.oopspecindex == self.OS_LIBFFI_CALL or self.can_release_gil def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, - can_invalidate=False): + can_invalidate=False, + can_release_gil=False): from pypy.translator.backendopt.writeanalyze import top_set if effects is top_set: return None @@ -158,7 +162,8 @@ write_descrs_arrays, extraeffect, oopspecindex, - can_invalidate) + can_invalidate, + can_release_gil) def consider_struct(TYPE, fieldname): if fieldType(TYPE, fieldname) is lltype.Void: @@ -194,6 +199,16 @@ def analyze_simple_operation(self, op, graphinfo): return op.opname == 'jit_force_quasi_immutable' +class CanReleaseGILAnalyzer(BoolGraphAnalyzer): + def analyze_direct_call(self, graph, seen=None): + releases_gil = False + if hasattr(graph, "func") and hasattr(graph.func, "_ptr"): + releases_gil = graph.func._ptr._obj.releases_gil + return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen) + + def analyze_simple_operation(self, op, graphinfo): + return False + # ____________________________________________________________ class CallInfoCollection(object): diff --git a/pypy/jit/codewriter/jitcode.py b/pypy/jit/codewriter/jitcode.py --- a/pypy/jit/codewriter/jitcode.py +++ b/pypy/jit/codewriter/jitcode.py @@ -1,7 +1,6 @@ from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.codewriter import heaptracker from pypy.rlib.objectmodel import we_are_translated -from pypy.rpython.lltypesystem import llmemory class JitCode(AbstractDescr): @@ -102,7 +101,7 @@ def _clone_if_mutable(self): raise NotImplementedError - + class MissingLiveness(Exception): pass diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -1,18 +1,16 @@ -import py, sys -from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass -from pypy.rpython import rlist -from pypy.jit.metainterp.history import getkind -from pypy.objspace.flow.model import SpaceOperation, Variable, Constant -from pypy.objspace.flow.model import Block, Link, c_last_exception -from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets +import py from pypy.jit.codewriter import support, heaptracker, longlong from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets from pypy.jit.codewriter.policy import log +from pypy.jit.metainterp import quasiimmut +from pypy.jit.metainterp.history import getkind from pypy.jit.metainterp.typesystem import deref, arrayItem -from pypy.jit.metainterp import quasiimmut -from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, c_last_exception from pypy.rlib import objectmodel from pypy.rlib.jit import _we_are_jitted +from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass +from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY from pypy.translator.simplify import get_funcobj from pypy.translator.unsimplify import varoftype @@ -765,13 +763,64 @@ raise NotImplementedError("cast_ptr_to_int") def rewrite_op_force_cast(self, op): - from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof - from pypy.rlib.rarithmetic import intmask assert not self._is_gc(op.args[0]) - size2, unsigned2 = size_and_sign(op.result.concretetype) - if size2 >= sizeof(lltype.Signed): + fromll = longlong.is_longlong(op.args[0].concretetype) + toll = longlong.is_longlong(op.result.concretetype) + if fromll and toll: + return + if fromll: + args = op.args + opname = 'truncate_longlong_to_int' + RESULT = lltype.Signed + v = varoftype(RESULT) + op1 = SpaceOperation(opname, args, v) + op2 = self.rewrite_operation(op1) + oplist = self.force_cast_without_longlong(op2.result, op.result) + if oplist: + return [op2] + oplist + # + # force a renaming to put the correct result in place, even though + # it might be slightly mistyped (e.g. Signed versus Unsigned) + assert op2.result is v + op2.result = op.result + return op2 + elif toll: + from pypy.rpython.lltypesystem import rffi + size, unsigned = rffi.size_and_sign(op.args[0].concretetype) + if unsigned: + INTERMEDIATE = lltype.Unsigned + else: + INTERMEDIATE = lltype.Signed + v = varoftype(INTERMEDIATE) + oplist = self.force_cast_without_longlong(op.args[0], v) + if not oplist: + v = op.args[0] + oplist = [] + if unsigned: + opname = 'cast_uint_to_longlong' + else: + opname = 'cast_int_to_longlong' + op1 = SpaceOperation(opname, [v], op.result) + op2 = self.rewrite_operation(op1) + return oplist + [op2] + else: + return self.force_cast_without_longlong(op.args[0], op.result) + + def force_cast_without_longlong(self, v_arg, v_result): + from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT + # + if (v_result.concretetype in (FLOAT, lltype.Float) or + v_arg.concretetype in (FLOAT, lltype.Float)): + assert (v_result.concretetype == lltype.Float and + v_arg.concretetype == lltype.Float), "xxx unsupported cast" + return + # + size2, unsigned2 = size_and_sign(v_result.concretetype) + assert size2 <= sizeof(lltype.Signed) + if size2 == sizeof(lltype.Signed): return # the target type is LONG or ULONG - size1, unsigned1 = size_and_sign(op.args[0].concretetype) + size1, unsigned1 = size_and_sign(v_arg.concretetype) + assert size1 <= sizeof(lltype.Signed) # def bounds(size, unsigned): if unsigned: @@ -784,22 +833,28 @@ return # the target type includes the source range # result = [] - v1 = op.args[0] if min2: c_min2 = Constant(min2, lltype.Signed) - v2 = Variable(); v2.concretetype = lltype.Signed - result.append(SpaceOperation('int_sub', [v1, c_min2], v2)) + v2 = varoftype(lltype.Signed) + result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2)) else: - v2 = v1 + v2 = v_arg c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed) - v3 = Variable(); v3.concretetype = lltype.Signed + v3 = varoftype(lltype.Signed) result.append(SpaceOperation('int_and', [v2, c_mask], v3)) if min2: - result.append(SpaceOperation('int_add', [v3, c_min2], op.result)) + result.append(SpaceOperation('int_add', [v3, c_min2], v_result)) else: - result[-1].result = op.result + result[-1].result = v_result return result + def rewrite_op_direct_ptradd(self, op): + from pypy.rpython.lltypesystem import rffi + # xxx otherwise, not implemented: + assert op.args[0].concretetype == rffi.CCHARP + # + return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result) + # ---------- # Long longs, for 32-bit only. Supported operations are left unmodified, # and unsupported ones are turned into a call to a function from @@ -847,7 +902,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -883,30 +938,7 @@ rewrite_op_ullong_is_true = rewrite_op_llong_is_true def rewrite_op_cast_primitive(self, op): - fromll = longlong.is_longlong(op.args[0].concretetype) - toll = longlong.is_longlong(op.result.concretetype) - if fromll != toll: - args = op.args - if fromll: - opname = 'truncate_longlong_to_int' - RESULT = lltype.Signed - else: - from pypy.rpython.lltypesystem import rffi - if rffi.cast(op.args[0].concretetype, -1) < 0: - opname = 'cast_int_to_longlong' - else: - opname = 'cast_uint_to_longlong' - RESULT = lltype.SignedLongLong - v = varoftype(RESULT) - op1 = SpaceOperation(opname, args, v) - op2 = self.rewrite_operation(op1) - # - # force a renaming to put the correct result in place, even though - # it might be slightly mistyped (e.g. Signed versus Unsigned) - assert op2.result is v - op2.result = op.result - # - return op2 + return self.rewrite_op_force_cast(op) # ---------- # Renames, from the _old opname to the _new one. @@ -1083,6 +1115,9 @@ return meth(op, args, *descrs) def _get_list_nonneg_canraise_flags(self, op): + # XXX as far as I can see, this function will always return True + # because functions that are neither nonneg nor fast don't have an + # oopspec any more # xxx break of abstraction: func = get_funcobj(op.args[0].value)._callable # base hints on the name of the ll function, which is a bit xxx-ish @@ -1240,7 +1275,7 @@ calldescr = self.callcontrol.getcalldescr(op, oopspecindex, extraeffect) if extraeffect is not None: - assert (type(calldescr) is str # for tests + assert (is_test_calldescr(calldescr) # for tests or calldescr.get_extra_info().extraeffect == extraeffect) if isinstance(op.args[0].value, str): pass # for tests only @@ -1328,13 +1363,13 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_PURE, because it can raise + # ll_str2unicode is not EF_ELIDABLE, because it can raise # UnicodeDecodeError... return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) @@ -1374,13 +1409,13 @@ assert vinfo is not None self.vable_flags[op.args[0]] = op.args[2].value return [] - + # --------- # ll_math.sqrt_nonneg() - + def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_PURE) + EffectInfo.EF_ELIDABLE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args @@ -1401,6 +1436,9 @@ return "using virtualizable array in illegal way in %r" % ( self.args[0],) +def is_test_calldescr(calldescr): + return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False) + def _with_prefix(prefix): result = {} for name in dir(Transformer): diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -1,9 +1,7 @@ -from pypy.translator.simplify import get_funcobj from pypy.jit.metainterp import history -from pypy.rpython.lltypesystem import lltype, rclass from pypy.tool.udir import udir -import py, sys +import py from pypy.tool.ansi_print import ansi_log log = py.log.Producer('jitcodewriter') py.log.setconsumer('jitcodewriter', ansi_log) @@ -35,8 +33,8 @@ def _reject_function(self, func): if hasattr(func, '_jit_look_inside_'): return not func._jit_look_inside_ - # explicitly pure functions are always opaque - if getattr(func, '_pure_function_', False): + # explicitly elidable functions are always opaque + if getattr(func, '_elidable_function_', False): return True # pypy.rpython.module.* are opaque helpers mod = func.__module__ or '?' diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -185,7 +185,7 @@ return llop.int_floordiv(lltype.Signed, x, y) def _ll_2_int_floordiv_ovf(x, y): - if x == -sys.maxint - 1 and y == -1: + if x == -sys.maxint - 1 and y == -1: raise OverflowError return llop.int_floordiv(lltype.Signed, x, y) @@ -222,7 +222,7 @@ return -x else: return x - + # math support # ------------ @@ -395,7 +395,7 @@ ('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed), ('int_abs', [lltype.Signed], lltype.Signed), ('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float), - ] +] class LLtypeHelpers: @@ -420,10 +420,6 @@ _ll_1_dict_values.need_result_type = True _ll_1_dict_items .need_result_type = True - def _ll_1_newdictiter(ITER, d): - return ll_rdict.ll_dictiter(lltype.Ptr(ITER), d) - _ll_1_newdictiter.need_result_type = True - _dictnext_keys = staticmethod(ll_rdict.ll_dictnext_group['keys']) _dictnext_values = staticmethod(ll_rdict.ll_dictnext_group['values']) _dictnext_items = staticmethod(ll_rdict.ll_dictnext_group['items']) @@ -574,10 +570,6 @@ _ll_1_dict_values.need_result_type = True _ll_1_dict_items .need_result_type = True - def _ll_1_newdictiter(ITER, d): - return oo_rdict.ll_dictiter(ITER, d) - _ll_1_newdictiter.need_result_type = True - _dictnext_keys = staticmethod(oo_rdict.ll_dictnext_group['keys']) _dictnext_values = staticmethod(oo_rdict.ll_dictnext_group['values']) _dictnext_items = staticmethod(oo_rdict.ll_dictnext_group['items']) diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py --- a/pypy/jit/codewriter/test/test_call.py +++ b/pypy/jit/codewriter/test/test_call.py @@ -1,6 +1,6 @@ import py from pypy.objspace.flow.model import SpaceOperation, Constant, Variable -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.unsimplify import varoftype from pypy.rlib import jit from pypy.jit.codewriter.call import CallControl @@ -103,7 +103,7 @@ op = SpaceOperation('direct_call', [Constant(object())], Variable()) - assert cc.guess_call_kind(op) == 'residual' + assert cc.guess_call_kind(op) == 'residual' class funcptr: class graph: @@ -118,7 +118,7 @@ op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) - assert res == [g] + assert res == [g] assert cc.guess_call_kind(op) == 'regular' class funcptr: @@ -126,7 +126,7 @@ op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) - assert res is None + assert res is None assert cc.guess_call_kind(op) == 'residual' h = object() @@ -142,7 +142,7 @@ Variable()) res = cc.graphs_from(op) assert res is None - assert cc.guess_call_kind(op) == 'residual' + assert cc.guess_call_kind(op) == 'residual' # ____________________________________________________________ @@ -171,3 +171,24 @@ def test_jit_force_virtualizable_effectinfo(): py.test.skip("XXX add a test for CallControl.getcalldescr() -> EF_xxx") + +def test_releases_gil_analyzer(): + from pypy.jit.backend.llgraph.runner import LLtypeCPU + + T = rffi.CArrayPtr(rffi.TIME_T) + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + + @jit.dont_look_inside + def f(): + return external(lltype.nullptr(T.TO)) + + rtyper = support.annotate(f, []) + jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) + cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) + res = cc.find_all_graphs(FakePolicy()) + + [f_graph] = [x for x in res if x.func is f] + [block, _] = list(f_graph.iterblocks()) + [op] = block.operations + call_descr = cc.getcalldescr(op) + assert call_descr.extrainfo.can_release_gil \ No newline at end of file diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py --- a/pypy/jit/codewriter/test/test_flatten.py +++ b/pypy/jit/codewriter/test/test_flatten.py @@ -3,6 +3,7 @@ from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register from pypy.jit.codewriter.format import assert_format +from pypy.jit.codewriter import longlong from pypy.jit.metainterp.history import AbstractDescr from pypy.rpython.lltypesystem import lltype, rclass, rstr from pypy.objspace.flow.model import SpaceOperation, Variable, Constant @@ -30,6 +31,9 @@ 'float': FakeRegAlloc()} class FakeDescr(AbstractDescr): + _for_tests_only = True + def __init__(self, oopspecindex=None): + self.oopspecindex = oopspecindex def __repr__(self): return '' def as_vtable_size_descr(self): @@ -55,19 +59,24 @@ def arraydescrof(self, ARRAY): return FakeDescr() +class FakeCallInfoCollection: + def add(self, *args): + pass + class FakeCallControl: _descr_cannot_raise = FakeDescr() + callinfocollection = FakeCallInfoCollection() def guess_call_kind(self, op): return 'residual' - def getcalldescr(self, op): + def getcalldescr(self, op, oopspecindex=None, extraeffect=None): try: if 'cannot_raise' in op.args[0].value._obj.graph.name: return self._descr_cannot_raise except AttributeError: pass - return FakeDescr() + return FakeDescr(oopspecindex) def calldescr_canraise(self, calldescr): - return calldescr is not self._descr_cannot_raise + return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None def get_vinfo(self, VTYPEPTR): return None @@ -734,7 +743,9 @@ def test_force_cast(self): from pypy.rpython.lltypesystem import rffi - + # NB: we don't need to test for INT here, the logic in jtransform is + # general enough so that if we have the below cases it should + # generalize also to INT for FROM, TO, expected in [ (rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""), (rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"), @@ -797,14 +808,44 @@ expected = [s.strip() for s in expected.splitlines()] check_force_cast(FROM, TO, expected, 42) check_force_cast(FROM, TO, expected, -42) - expected.append('int_return %i' + str(len(expected))) - expected = '\n'.join(expected) + returnvar = "%i" + str(len(expected)) + expected.append('int_return ' + returnvar) + expectedstr = '\n'.join(expected) # def f(n): return rffi.cast(TO, n) - self.encoding_test(f, [rffi.cast(FROM, 42)], expected, + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, transform=True) + if not longlong.is_64_bit: + if FROM in (rffi.LONG, rffi.ULONG): + if FROM == rffi.LONG: + FROM = rffi.LONGLONG + else: + FROM = rffi.ULONGLONG + expected.insert(0, + "residual_call_irf_i $<* fn llong_to_int>, , I[], R[], F[%f0] -> %i0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + elif TO in (rffi.LONG, rffi.ULONG): + if TO == rffi.LONG: + TO = rffi.LONGLONG + else: + TO = rffi.ULONGLONG + if rffi.cast(FROM, -1) < 0: + fnname = "llong_from_int" + else: + fnname = "llong_from_uint" + expected.pop() # remove int_return + expected.append( + "residual_call_irf_f $<* fn %s>, , I[%s], R[], F[] -> %%f0" + % (fnname, returnvar)) + expected.append("float_return %f0") + expectedstr = '\n'.join(expected) + self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr, + transform=True) + def test_force_cast_pointer(self): from pypy.rpython.lltypesystem import rffi def h(p): @@ -813,6 +854,23 @@ int_return %i0 """, transform=True) + def test_force_cast_float(self): + from pypy.rpython.lltypesystem import rffi + def f(n): + return rffi.cast(lltype.Float, n) + self.encoding_test(f, [12.456], """ + float_return %f0 + """, transform=True) + + def test_direct_ptradd(self): + from pypy.rpython.lltypesystem import rffi + def f(p, n): + return lltype.direct_ptradd(p, n) + self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """ + int_add %i0, %i1 -> %i2 + int_return %i2 + """, transform=True) + def check_force_cast(FROM, TO, operations, value): """Check that the test is correctly written...""" diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -122,7 +122,7 @@ if oopspecindex == EI.OS_STR2UNICODE: assert extraeffect == None # not pure, can raise! else: - assert extraeffect == EI.EF_PURE + assert extraeffect == EI.EF_ELIDABLE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False @@ -769,7 +769,7 @@ def get_vinfo(self, v): return None def could_be_green_field(self, S1, name1): - assert S1 is S + assert S1 == S assert name1 == 'x' return True S = lltype.GcStruct('S', ('x', lltype.Char), diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py --- a/pypy/jit/codewriter/test/test_longlong.py +++ b/pypy/jit/codewriter/test/test_longlong.py @@ -37,7 +37,7 @@ class TestLongLong: def setup_class(cls): - if sys.maxint > 2147483647: + if longlong.is_64_bit: py.test.skip("only for 32-bit platforms") def do_check(self, opname, oopspecindex, ARGS, RESULT): @@ -46,6 +46,8 @@ op = SpaceOperation(opname, vlist, v_result) tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) op1 = tr.rewrite_operation(op) + if isinstance(op1, list): + [op1] = op1 # def is_llf(TYPE): return (TYPE == lltype.SignedLongLong or @@ -196,6 +198,23 @@ for T2 in [lltype.Signed, lltype.Unsigned]: self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT, [T1], T2) + self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT, + [T1], T2) + if T2 == lltype.Signed: + expected = EffectInfo.OS_LLONG_FROM_INT + else: + expected = EffectInfo.OS_LLONG_FROM_UINT + self.do_check('cast_primitive', expected, [T2], T1) + self.do_check('force_cast', expected, [T2], T1) + # + for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]: + vlist = [varoftype(T1)] + v_result = varoftype(T2) + op = SpaceOperation('force_cast', vlist, v_result) + tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) + op1 = tr.rewrite_operation(op) + assert op1 is None def test_constants(self): for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]: diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -45,8 +45,8 @@ policy.set_supports_floats(False) assert not policy.look_inside_graph(graph) -def test_purefunction(): - @jit.purefunction +def test_elidable(): + @jit.elidable def g(x): return x + 2 graph = support.getgraph(g, [5]) diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -765,6 +765,7 @@ """ short_preamble = None failed_states = None + retraced_count = 0 terminating = False # see TerminatingLoopToken in compile.py outermost_jitdriver_sd = None # and more data specified by the backend when the loop is compiled diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -3,7 +3,7 @@ from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize from pypy.jit.metainterp.optimizeopt.heap import OptHeap -from pypy.jit.metainterp.optimizeopt.string import OptString +from pypy.jit.metainterp.optimizeopt.vstring import OptString from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify @@ -21,15 +21,14 @@ unroll_all_opts = unrolling_iterable(ALL_OPTS) ALL_OPTS_DICT = dict.fromkeys([name for name, _ in ALL_OPTS]) - +ALL_OPTS_LIST = [name for name, _ in ALL_OPTS] ALL_OPTS_NAMES = ':'.join([name for name, _ in ALL_OPTS]) -PARAMETERS['enable_opts'] = ALL_OPTS_NAMES def build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble=True, retraced=False): config = metainterp_sd.config optimizations = [] - unroll = 'unroll' in enable_opts + unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: @@ -62,7 +61,6 @@ optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, inline_short_preamble, retraced) - if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -1,10 +1,10 @@ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.libffi import Func -from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import _findall +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind @@ -48,7 +48,7 @@ inst_argtypes is actually a low-level array, but we can use it directly since the only thing we do with it is to read its items """ - + llfunc = funcval.box.getref_base() if we_are_translated(): func = cast_base_ptr_to_instance(Func, llfunc) @@ -203,13 +203,7 @@ def propagate_forward(self, op): if self.logops is not None: debug_print(self.logops.repr_of_resop(op)) - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def _get_oopspec(self, op): effectinfo = op.getdescr().get_extra_info() @@ -220,4 +214,5 @@ def _get_funcval(self, op): return self.getvalue(op.getarg(1)) -optimize_ops = _findall(OptFfiCall, 'optimize_') +dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_', + default=OptFfiCall.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,9 +1,10 @@ import os -from pypy.jit.metainterp.optimizeopt.util import _findall -from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.rlib.objectmodel import we_are_translated + from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.optimizeopt.optimizer import Optimization +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.resoperation import rop +from pypy.rlib.objectmodel import we_are_translated class CachedField(object): @@ -73,7 +74,7 @@ assert self._lazy_setfield is None self._cached_fields[structvalue] = fieldvalue - def force_lazy_setfield(self, optheap): + def force_lazy_setfield(self, optheap, can_cache=True): op = self._lazy_setfield if op is not None: # This is the way _lazy_setfield is usually reset to None. @@ -83,12 +84,16 @@ self._cached_fields.clear() self._lazy_setfield = None optheap.next_optimization.propagate_forward(op) + if not can_cache: + return # Once it is done, we can put at least one piece of information # back in the cache: the value of this particular structure's # field. structvalue = optheap.getvalue(op.getarg(0)) fieldvalue = optheap.getvalue(op.getarglist()[-1]) self.remember_field_value(structvalue, fieldvalue) + elif not can_cache: + self._cached_fields.clear() def get_reconstructed(self, optimizer, valuemap): assert self._lazy_setfield is None @@ -202,20 +207,9 @@ for arraydescr in effectinfo.readonly_descrs_arrays: self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: - self.force_lazy_setfield(fielddescr) - try: - cf = self.cached_fields[fielddescr] - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setfield(fielddescr, can_cache=False) for arraydescr in effectinfo.write_descrs_arrays: - self.force_lazy_setarrayitem(arraydescr) - try: - submap = self.cached_arrayitems[arraydescr] - for cf in submap.itervalues(): - cf._cached_fields.clear() - except KeyError: - pass + self.force_lazy_setarrayitem(arraydescr, can_cache=False) if effectinfo.check_forces_virtual_or_virtualizable(): vrefinfo = self.optimizer.metainterp_sd.virtualref_info self.force_lazy_setfield(vrefinfo.descr_forced) @@ -238,20 +232,20 @@ if value in cf._cached_fields: cf._cached_fields[newvalue] = cf._cached_fields[value] - def force_lazy_setfield(self, descr): + def force_lazy_setfield(self, descr, can_cache=True): try: cf = self.cached_fields[descr] except KeyError: return - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) - def force_lazy_setarrayitem(self, arraydescr): + def force_lazy_setarrayitem(self, arraydescr, can_cache=True): try: submap = self.cached_arrayitems[arraydescr] except KeyError: return for cf in submap.values(): - cf.force_lazy_setfield(self) + cf.force_lazy_setfield(self, can_cache) def fixup_guard_situation(self): # hackish: reverse the order of the last two operations if it makes @@ -387,7 +381,7 @@ cf.do_setfield(self, op) else: # variable index, so make sure the lazy setarrayitems are done - self.force_lazy_setarrayitem(op.getdescr()) + self.force_lazy_setarrayitem(op.getdescr(), can_cache=False) # and then emit the operation self.emit_operation(op) @@ -431,13 +425,7 @@ self._seen_guard_not_invalidated = True self.emit_operation(op) - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptHeap, 'optimize_') +dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_', + default=OptHeap.emit_operation) +OptHeap.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,9 +1,10 @@ +from pypy.jit.metainterp.history import ConstInt +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntLowerBound, + IntUpperBound) from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 -from pypy.jit.metainterp.optimizeopt.util import _findall -from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, - IntLowerBound, IntUpperBound) -from pypy.jit.metainterp.history import Const, ConstInt -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.resoperation import rop + class OptIntBounds(Optimization): """Keeps track of the bounds placed on integers by guards and remove @@ -34,14 +35,11 @@ op = self.posponedop self.posponedop = None - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - assert not op.is_ovf() - self.emit_operation(op) + dispatch_opt(self, op) + + def opt_default(self, op): + assert not op.is_ovf() + self.emit_operation(op) def propagate_bounds_backward(self, box): @@ -57,11 +55,7 @@ op = self.optimizer.producer[box] except KeyError: return - opnum = op.getopnum() - for value, func in propagate_bounds_ops: - if opnum == value: - func(self, op) - break + dispatch_bounds_ops(self, op) def optimize_GUARD_TRUE(self, op): self.emit_operation(op) @@ -382,6 +376,18 @@ v1.intbound.make_gt(IntBound(0, 0)) self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_IS_ZERO(self, op): + r = self.getvalue(op.result) + if r.is_constant(): + if r.box.same_constant(CONST_1): + v1 = self.getvalue(op.getarg(0)) + # Clever hack, we can't use self.make_constant_int yet because + # the args aren't in the values dictionary yet so it runs into + # an assert, this is a clever way of expressing the same thing. + v1.intbound.make_ge(IntBound(0, 0)) + v1.intbound.make_lt(IntBound(1, 1)) + self.propagate_bounds_backward(op.getarg(0)) + def propagate_bounds_INT_ADD(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) @@ -428,5 +434,6 @@ propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL -optimize_ops = _findall(OptIntBounds, 'optimize_') -propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_') +dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_', + default=OptIntBounds.opt_default) +dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_') diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -1,17 +1,11 @@ -from pypy.jit.metainterp.history import Box, BoxInt, LoopToken, BoxFloat,\ - ConstFloat -from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF +from pypy.jit.metainterp import jitprof, resume, compile +from pypy.jit.metainterp.executor import execute_nonspec +from pypy.jit.metainterp.history import BoxInt, BoxFloat, Const, ConstInt, REF +from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded +from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method, + args_dict) from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp import jitprof -from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs -from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict -from pypy.jit.metainterp.optimize import InvalidLoop -from pypy.jit.metainterp import resume, compile from pypy.jit.metainterp.typesystem import llhelper, oohelper -from pypy.rpython.lltypesystem import lltype -from pypy.jit.metainterp.history import AbstractDescr, make_hashable_int -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded from pypy.tool.pairtype import extendabletype LEVEL_UNKNOWN = '\x00' @@ -434,14 +428,7 @@ def propagate_forward(self, op): self.producer[op.result] = op - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.optimize_default(op) - #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n' + dispatch_opt(self, op) def test_emittable(self, op): return True @@ -569,7 +556,8 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) -optimize_ops = _findall(Optimizer, 'optimize_') +dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', + default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,10 +1,11 @@ +from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.metainterp.history import ConstInt, make_hashable_int +from pypy.jit.metainterp.optimize import InvalidLoop +from pypy.jit.metainterp.optimizeopt.intutils import IntBound from pypy.jit.metainterp.optimizeopt.optimizer import * -from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex -from pypy.jit.metainterp.history import ConstInt -from pypy.jit.metainterp.optimizeopt.util import _findall -from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.metainterp.optimizeopt.intutils import IntBound +from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method +from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop, + ResOperation) from pypy.rlib.rarithmetic import highest_bit @@ -21,18 +22,13 @@ if self.find_rewritable_bool(op, args): return - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) + dispatch_opt(self, op) def test_emittable(self, op): opnum = op.getopnum() - for value, func in optimize_guards: + for value, cls, func in optimize_guards: if opnum == value: + assert isinstance(op, cls) try: func(self, op, dryrun=True) return self.is_emittable(op) @@ -204,6 +200,7 @@ )) return self.emit_operation(op) + self.pure(rop.FLOAT_MUL, [arg2, arg1], op.result) def optimize_FLOAT_NEG(self, op): v1 = op.getarg(0) @@ -477,5 +474,6 @@ self.emit_operation(op) -optimize_ops = _findall(OptRewrite, 'optimize_') +dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_', + default=OptRewrite.emit_operation) optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD') diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ +from pypy.jit.metainterp.optimizeopt.optimizer import Optimization +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.metainterp.optimizeopt.util import _findall class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): @@ -25,13 +25,7 @@ # but it's a bit hard to implement robustly if heap.py is also run pass - def propagate_forward(self, op): - opnum = op.getopnum() - for value, func in optimize_ops: - if opnum == value: - func(self, op) - break - else: - self.emit_operation(op) -optimize_ops = _findall(OptSimplify, 'optimize_') +dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', + default=OptSimplify.emit_operation) +OptSimplify.propagate_forward = dispatch_opt diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -439,6 +439,23 @@ """ self.optimize_loop(ops, expected) + def test_int_is_zero_int_is_true(self): + ops = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + i2 = int_is_true(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i0] + i1 = int_is_zero(i0) + guard_true(i1) [] + jump(0) + """ + self.optimize_loop(ops, expected) + def test_ooisnull_oononnull_2(self): ops = """ [p0] @@ -1738,6 +1755,48 @@ """ self.optimize_loop(ops, expected) + def test_duplicate_getarrayitem_after_setarrayitem_bug(self): + ops = """ + [p0, i0, i1] + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i6 = int_add(i0, 1) + setarrayitem_gc(p0, 0, i0, descr=arraydescr) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i0) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + + def test_duplicate_getarrayitem_after_setarrayitem_bug2(self): + ops = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + expected = """ + [p0, i0, i1] + i2 = getarrayitem_gc(p0, 0, descr=arraydescr) + i6 = int_add(i0, 1) + setarrayitem_gc(p0, i1, i6, descr=arraydescr) + i10 = getarrayitem_gc(p0, 0, descr=arraydescr) + i11 = int_add(i10, i2) + jump(p0, i11, i1) + """ + self.optimize_loop(ops, expected) + def test_bug_1(self): ops = """ [i0, p1] @@ -3899,11 +3958,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3924,9 +3980,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -3945,10 +3999,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -3970,14 +4023,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -3993,10 +4041,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -4114,16 +4160,13 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -4162,11 +4205,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -4358,11 +4398,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) @@ -4495,7 +4532,7 @@ escape(i1) jump(p0, i0) """ - self.optimize_loop(ops, expected) + self.optimize_strunicode_loop(ops, expected) def test_int_is_true_bounds(self): ops = """ @@ -4514,8 +4551,77 @@ guard_true(i1) [] jump(p0) """ + self.optimize_strunicode_loop(ops, expected) + + def test_strslice_subtraction_folds(self): + ops = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = call(0, p0, i0, i1, descr=strslicedescr) + escape(p1) + jump(p0, i1) + """ + expected = """ + [p0, i0] + i1 = int_add(i0, 1) + p1 = newstr(1) + i2 = strgetitem(p0, i0) + strsetitem(p1, 0, i2) + escape(p1) + jump(p0, i1) + """ + self.optimize_strunicode_loop(ops, expected) + + def test_float_mul_reversed(self): + ops = """ + [f0, f1] + f2 = float_mul(f0, f1) + f3 = float_mul(f1, f0) + jump(f2, f3) + """ + expected = """ + [f0, f1] + f2 = float_mul(f0, f1) + jump(f2, f2) + """ self.optimize_loop(ops, expected) + def test_null_char_str(self): + ops = """ + [p0] + p1 = newstr(4) + setfield_gc(p0, p1, descr=valuedescr) + jump(p0) + """ + # It used to be the case that this would have a series of + # strsetitem(p1, idx, 0), which was silly because memory is 0 filled + # when allocated. + expected = """ + [p0] + p1 = newstr(4) + setfield_gc(p0, p1, descr=valuedescr) + jump(p0) + """ + self.optimize_strunicode_loop(ops, expected) + + def test_newstr_strlen(self): + ops = """ + [i0] + p0 = newstr(i0) + escape(p0) + i1 = strlen(p0) + i2 = int_add(i1, 1) + jump(i2) + """ + expected = """ + [i0] + p0 = newstr(i0) + escape(p0) + i1 = int_add(i0, 1) + jump(i1) + """ + self.optimize_strunicode_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2820,11 +2820,11 @@ def test_residual_call_invalidate_some_arrays(self): ops = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) - p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p2, 0, descr=arraydescr2) p6 = getarrayitem_gc(p2, 1, descr=arraydescr2) i4 = getarrayitem_gc(p1, 1, descr=arraydescr) escape(p3) @@ -2837,7 +2837,7 @@ """ expected = """ [p1, p2, i1] - p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr2) p4 = getarrayitem_gc(p2, 1, descr=arraydescr2) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = call(i1, descr=writearraydescr) @@ -5082,11 +5082,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p3 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p3, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p3, 0, i4, i5) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) jump(p2, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5107,9 +5104,7 @@ p3 = newstr(i3) strsetitem(p3, 0, i0) strsetitem(p3, 1, i1) - i4 = strlen(p2) - i5 = int_add(2, i4) # will be killed by the backend - copystrcontent(p2, p3, 0, 2, i4) + copystrcontent(p2, p3, 0, 2, i2) jump(i1, i0, p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5128,10 +5123,9 @@ i2 = strlen(p2) i3 = int_add(i2, 2) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, i0) - i5 = int_add(i4, 1) + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, i0) + i5 = int_add(i2, 1) strsetitem(p3, i5, i1) i6 = int_add(i5, 1) # will be killed by the backend jump(i1, i0, p3) @@ -5153,14 +5147,9 @@ i3 = strlen(p3) i123 = int_add(i12, i3) p5 = newstr(i123) - i1b = strlen(p1) - copystrcontent(p1, p5, 0, 0, i1b) - i2b = strlen(p2) - i12b = int_add(i1b, i2b) - copystrcontent(p2, p5, 0, i1b, i2b) - i3b = strlen(p3) - i123b = int_add(i12b, i3b) # will be killed by the backend - copystrcontent(p3, p5, 0, i12b, i3b) + copystrcontent(p1, p5, 0, 0, i1) + copystrcontent(p2, p5, 0, i1, i2) + copystrcontent(p3, p5, 0, i12, i3) jump(p2, p3, p5) """ self.optimize_strunicode_loop(ops, expected) @@ -5176,10 +5165,8 @@ i2 = strlen(p2) i3 = int_add(i2, 1) p3 = newstr(i3) - i4 = strlen(p2) - copystrcontent(p2, p3, 0, 0, i4) - strsetitem(p3, i4, 120) # == ord('x') - i5 = int_add(i4, 1) # will be killed by the backend + copystrcontent(p2, p3, 0, 0, i2) + strsetitem(p3, i2, 120) # == ord('x') jump(p3) """ self.optimize_strunicode_loop(ops, expected) @@ -5303,9 +5290,7 @@ i5 = int_add(i3, i4) p4 = newstr(i5) copystrcontent(p1, p4, i1, 0, i3) - i4b = strlen(p2) - i6 = int_add(i3, i4b) # killed by the backend - copystrcontent(p2, p4, 0, i3, i4b) + copystrcontent(p2, p4, 0, i3, i4) jump(p4, i1, i2, p2) """ self.optimize_strunicode_loop(ops, expected) @@ -5373,7 +5358,6 @@ # ---------- def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None): - from pypy.jit.metainterp.optimizeopt import string class FakeCallInfoCollection: def callinfo_for_oopspec(self, oopspecindex): calldescrtype = type(LLtypeMixin.strequaldescr) @@ -5412,11 +5396,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) @@ -5610,11 +5591,8 @@ i2 = strlen(p2) i3 = int_add(i1, i2) p4 = newstr(i3) - i4 = strlen(p1) - copystrcontent(p1, p4, 0, 0, i4) - i5 = strlen(p2) - i6 = int_add(i4, i5) # will be killed by the backend - copystrcontent(p2, p4, 0, i4, i5) + copystrcontent(p1, p4, 0, 0, i1) + copystrcontent(p2, p4, 0, i1, i2) i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -1,14 +1,12 @@ +from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.metainterp.compile import ResumeGuardDescr +from pypy.jit.metainterp.history import TreeLoop, LoopToken +from pypy.jit.metainterp.jitexc import JitException +from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.optimizeopt.optimizer import * -from pypy.jit.metainterp.optimizeopt.virtualize import AbstractVirtualValue from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.compile import ResumeGuardDescr from pypy.jit.metainterp.resume import Snapshot -from pypy.jit.metainterp.history import TreeLoop, LoopToken -from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop -from pypy.jit.metainterp.jitexc import JitException -from pypy.jit.metainterp.history import make_hashable_int -from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.rlib.debug import debug_print # Assumptions # =========== @@ -22,7 +20,7 @@ # are also recreated to allow virtuals not supported to be forced. # # First of all, the optimizations are not allowed to introduce new -# boxes. It is the unoptimized version of the trace that is inlined to +# boxes. It is the unoptimized version of the trace that is inlined to # form the second iteration of the loop. Otherwise the # state of the virtuals would not be updated correctly. Whenever some # box from the first iteration is reused in the second iteration, it @@ -57,7 +55,7 @@ # be absorbed into the virtual p2 and never seen by the heap # optimizer. At the end of the loop both p2 and p3 are virtuals, but # the loop needs p2 to be a pointer to be able to call itself. So it -# is forced producing the operations +# is forced producing the operations # # p2 = new_with_vtable(ConstClass(node_vtable)) # setfield_gc(p2, i2, descr=nextdescr) @@ -68,7 +66,7 @@ # the trace were optimized under the wrong assumption that the # setfield_gc was store sinked which could lead to errors. In this # case what would happen is that it would be inserted once more in -# front of the guard. +# front of the guard. @@ -112,7 +110,7 @@ def inline_descr_inplace(self, descr): if isinstance(descr, ResumeGuardDescr): descr.rd_snapshot = self.inline_snapshot(descr.rd_snapshot) - + def inline_arg(self, arg): if arg is None: return None @@ -139,7 +137,7 @@ return False return True - def generate_guards(self, other, args, cpu, extra_guards): + def generate_guards(self, other, args, cpu, extra_guards): assert len(self.state) == len(other.state) == len(args) for i in range(len(self.state)): self.state[i].generate_guards(other.state[i], args[i], @@ -153,7 +151,7 @@ def register_virtual_fields(self, keybox, fieldboxes): self.fieldboxes[keybox] = fieldboxes - + def already_seen_virtual(self, keybox): return keybox in self.fieldboxes @@ -233,20 +231,20 @@ if self.level == LEVEL_CONSTANT: import pdb; pdb.set_trace() raise NotImplementedError - + class UnrollOptimizer(Optimization): """Unroll the loop into two iterations. The first one will become the preamble or entry bridge (don't think there is a distinction anymore)""" - + def __init__(self, metainterp_sd, loop, optimizations): self.optimizer = Optimizer(metainterp_sd, loop, optimizations) self.cloned_operations = [] for op in self.optimizer.loop.operations: newop = op.clone() self.cloned_operations.append(newop) - + def propagate_all_forward(self): loop = self.optimizer.loop jumpop = loop.operations[-1] @@ -284,7 +282,7 @@ assert isinstance(start_resumedescr, ResumeGuardDescr) snapshot = start_resumedescr.rd_snapshot while snapshot is not None: - snapshot_args = snapshot.boxes + snapshot_args = snapshot.boxes new_snapshot_args = [] for a in snapshot_args: if not isinstance(a, Const): @@ -313,7 +311,7 @@ short_loop.inputargs = loop.preamble.inputargs[:] short_loop.operations = short - # Clone ops and boxes to get private versions and + # Clone ops and boxes to get private versions and newargs = [a.clonebox() for a in short_loop.inputargs] inliner = Inliner(short_loop.inputargs, newargs) short_loop.inputargs = newargs @@ -336,10 +334,10 @@ for op in short_loop.operations: if op.result: op.result.forget_value() - + def inline(self, loop_operations, loop_args, jump_args): self.inliner = inliner = Inliner(loop_args, jump_args) - + for v in self.optimizer.values.values(): v.last_guard_index = -1 # FIXME: Are there any more indexes stored? @@ -371,12 +369,12 @@ jumpargs = jmp.getarglist() # FIXME: Should also loop over operations added by forcing things in this loop - for op in newoperations: + for op in newoperations: boxes_created_this_iteration[op.result] = True args = op.getarglist() if op.is_guard(): args = args + op.getfailargs() - + for a in args: if not isinstance(a, Const) and not a in boxes_created_this_iteration: if a not in inputargs: @@ -439,7 +437,7 @@ "at preamble position: ", preamble_i, "loop position: ", loop_i) return None - + if self.sameop(newop, loop_ops[loop_i]) \ and loop_i < len(loop_ops): try: @@ -460,7 +458,7 @@ "loop position: ", loop_i) return None short_preamble.append(op) - + state.update(op) preamble_i += 1 @@ -470,7 +468,7 @@ "at position", loop_i) return None - + jumpargs = [] for i in range(len(loop.inputargs)): try: @@ -498,7 +496,7 @@ return None if op.result: seen[op.result] = True - + return short_preamble class ExeState(object): @@ -508,7 +506,7 @@ self.unsafe_getitem = {} self.unsafe_getarrayitem = {} self.unsafe_getarrayitem_indexes = {} - + # Make sure it is safe to move the instrucions in short_preamble # to the top making short_preamble followed by loop equvivalent # to preamble @@ -546,14 +544,14 @@ effectinfo = descr.get_extra_info() if effectinfo is not None: if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_PURE: + effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: return True return False - + def update(self, op): if (op.has_no_side_effect() or op.is_ovf() or - op.is_guard()): + op.is_guard()): return opnum = op.getopnum() descr = op.getdescr() @@ -566,7 +564,7 @@ if (opnum == rop.SETARRAYITEM_GC or opnum == rop.SETARRAYITEM_RAW): index = op.getarg(1) - if isinstance(index, Const): + if isinstance(index, Const): d = self.unsafe_getarrayitem_indexes.get(descr, None) if d is None: d = self.unsafe_getarrayitem_indexes[descr] = {} @@ -592,7 +590,7 @@ def __init__(self): self.map = {} - + def link_ops(self, preambleop, loopop): pargs = preambleop.getarglist() largs = loopop.getarglist() @@ -606,7 +604,7 @@ if not loopop.result: raise ImpossibleLink self.link_boxes(preambleop.result, loopop.result) - + def link_boxes(self, pbox, lbox): if lbox in self.map: @@ -627,11 +625,11 @@ def __init__(self, retraced): self.retraced = retraced self.inliner = None - - + + def reconstruct_for_next_iteration(self, optimizer, valuemap): return self - + def propagate_forward(self, op): if op.getopnum() == rop.JUMP: descr = op.getdescr() @@ -657,7 +655,7 @@ sh.virtual_state.generate_guards(virtual_state, args, cpu, extra_guards) - + ok = True except InvalidLoop: pass @@ -676,24 +674,28 @@ jumpop = self.optimizer.newoperations.pop() assert jumpop.getopnum() == rop.JUMP for guard in extra_guards: - descr = sh.start_resumedescr.clone_if_mutable() - self.inliner.inline_descr_inplace(descr) - guard.setdescr(descr) + d = sh.start_resumedescr.clone_if_mutable() + self.inliner.inline_descr_inplace(d) + guard.setdescr(d) self.emit_operation(guard) self.optimizer.newoperations.append(jumpop) return - retraced_count = len(short) - if descr.failed_states: - retraced_count += len(descr.failed_states) + retraced_count = descr.retraced_count + descr.retraced_count += 1 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if not self.retraced and retraced_count 0: + self.unroll_iterations -= 1 + return # warning! careful here. We have to return from the current # frame containing the jit_merge_point, and then use # do_recursive_call() to follow the recursive call. This is @@ -1128,13 +1168,11 @@ metainterp.jitdriver_sd.greenfield_info is not None): virtualizable_boxes = metainterp.virtualizable_boxes saved_pc = self.pc - try: - if resumepc >= 0: - self.pc = resumepc - resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, - metainterp.virtualref_boxes, resumedescr) - finally: - self.pc = saved_pc + if resumepc >= 0: + self.pc = resumepc + resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, + metainterp.virtualref_boxes, resumedescr) + self.pc = saved_pc def implement_guard_value(self, orgpc, box): """Promote the given Box into a Const. Note: be careful, it's a @@ -1233,7 +1271,7 @@ effect = effectinfo.extraeffect if effect == effectinfo.EF_CANNOT_RAISE: return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_PURE: + elif effect == effectinfo.EF_ELIDABLE: return self.metainterp.record_result_of_call_pure( self.execute_varargs(rop.CALL, allboxes, descr, False)) elif effect == effectinfo.EF_LOOPINVARIANT: @@ -1449,6 +1487,16 @@ self.last_exc_value_box = None self.retracing_loop_from = None self.call_pure_results = args_dict_box() + # contains boxes where the class is already known + self.known_class_boxes = {} + # contains frame boxes that are not virtualizables + self.nonstandard_virtualizables = {} + # heap cache + # maps descrs to (from_box, to_box) tuples + self.heap_cache = {} + # heap array cache + # maps descrs to {index: (from_box, to_box)} dicts + self.heap_array_cache = {} def perform_call(self, jitcode, boxes, greenkey=None): # causes the metainterp to enter the given subfunction @@ -1624,10 +1672,27 @@ # record the operation profiler = self.staticdata.profiler profiler.count_ops(opnum, RECORDED_OPS) + self._invalidate_caches(opnum, descr) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox + def _invalidate_caches(self, opnum, descr): + if opnum == rop.SETFIELD_GC: + return + if opnum == rop.SETARRAYITEM_GC: + return + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + return + if opnum == rop.CALL: + effectinfo = descr.get_extra_info() + if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: + return + if self.heap_cache: + self.heap_cache.clear() + if self.heap_array_cache: + self.heap_array_cache.clear() + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1789,6 +1854,11 @@ duplicates[box] = None def reached_loop_header(self, greenboxes, redboxes, resumedescr): + self.known_class_boxes = {} + self.nonstandard_virtualizables = {} # XXX maybe not needed? + self.heap_cache = {} + self.heap_array_cache = {} + duplicates = {} self.remove_consts_and_duplicates(redboxes, len(redboxes), duplicates) @@ -2295,6 +2365,16 @@ for i in range(len(boxes)): if boxes[i] is oldbox: boxes[i] = newbox + for descr, (frombox, tobox) in self.heap_cache.iteritems(): + change = False + if frombox is oldbox: + change = True + frombox = newbox + if tobox is oldbox: + change = True + tobox = newbox + if change: + self.heap_cache[descr] = frombox, tobox def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -281,9 +281,6 @@ assert len(args) == 2 self._arg0, self._arg1 = args - def getarglist(self): - return [self._arg0, self._arg1, self._arg2] - def numargs(self): return 2 diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,7 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant +from pypy.rlib.jit import loop_invariant, elidable, promote from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed from pypy.rlib.jit import unroll_safe, current_trace_length from pypy.jit.metainterp import pyjitpl, history @@ -11,7 +11,7 @@ from pypy import conftest from pypy.rlib.rarithmetic import ovfcheck from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -304,12 +304,12 @@ assert res == 42 self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) - def test_residual_call_pure(self): + def test_residual_call_elidable(self): def externfn(x, y): return x * y - externfn._pure_function_ = True + externfn._elidable_function_ = True def f(n): - n = hint(n, promote=True) + promote(n) return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 @@ -317,10 +317,10 @@ self.check_operations_history(int_add=0, int_mul=0, call=0, call_pure=0) - def test_residual_call_pure_1(self): + def test_residual_call_elidable_1(self): + @elidable def externfn(x, y): return x * y - externfn._pure_function_ = True def f(n): return externfn(n, n+1) res = self.interp_operations(f, [6]) @@ -329,11 +329,11 @@ self.check_operations_history(int_add=1, int_mul=0, call=0, call_pure=1) - def test_residual_call_pure_2(self): + def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) + @elidable def externfn(x): return x - 1 - externfn._pure_function_ = True def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) @@ -346,11 +346,11 @@ # by optimizeopt.py self.check_loops(int_sub=0, call=1, call_pure=0) - def test_constfold_call_pure(self): + def test_constfold_call_elidable(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -362,11 +362,11 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_constfold_call_pure_2(self): + def test_constfold_call_elidable_2(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable def externfn(x): return x - 3 - externfn._pure_function_ = True class V: def __init__(self, value): self.value = value @@ -382,19 +382,19 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) - def test_pure_function_returning_object(self): + def test_elidable_function_returning_object(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n']) class V: def __init__(self, x): self.x = x v1 = V(1) v2 = V(2) + @elidable def externfn(x): if x: return v1 else: return v2 - externfn._pure_function_ = True def f(n, m): while n > 0: myjitdriver.can_enter_jit(n=n, m=m) @@ -508,6 +508,32 @@ assert res == 84 - 61 - 62 self.check_history(call=1) # because the trace starts immediately + def test_unroll_one_loop_iteration(self): + def unroll(code): + return code == 0 + myjitdriver = JitDriver(greens = ['code'], + reds = ['loops', 'inner_loops', 's'], + should_unroll_one_iteration=unroll) + + def f(code, loops, inner_loops): + s = 0 + while loops > 0: + myjitdriver.jit_merge_point(code=code, loops=loops, + inner_loops=inner_loops, s=s) + if code == 1: + s += f(0, inner_loops, 0) + loops -= 1 + s += 1 + return s + + res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True) + assert res == f(1, 4, 1) + self.check_history(call_assembler=0) + + res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True) + assert res == f(1, 4, 2) + self.check_history(call_assembler=1) + def test_format(self): def f(n): return len("<%d>" % n) @@ -984,11 +1010,14 @@ pass class B(A): pass + @dont_look_inside + def extern(n): + if n: + return A() + else: + return B() def fn(n): - if n: - obj = A() - else: - obj = B() + obj = extern(n) return isinstance(obj, B) res = self.interp_operations(fn, [0]) assert res @@ -1021,6 +1050,7 @@ res = self.meta_interp(main, []) assert res == 55 + def test_assert_isinstance(self): class A: pass @@ -1181,7 +1211,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=1) + self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) def test_oosend_look_inside_only_one(self): class A: @@ -1252,7 +1282,7 @@ myjitdriver.jit_merge_point(x=x, l=l) a = l[x] x = a.g(x) - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1312,7 +1342,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1343,7 +1373,7 @@ x -= 5 else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) @@ -1377,7 +1407,7 @@ x = a.g(x) else: x -= 7 - hint(a, promote=True) + promote(a) return x res = self.meta_interp(f, [399], listops=True) assert res == f(399) @@ -1496,7 +1526,7 @@ glob.a = B() const = 2 else: - const = hint(const, promote=True) + promote(const) x -= const res += a.x a = None @@ -1531,7 +1561,7 @@ myjitdriver.can_enter_jit(x=x) myjitdriver.jit_merge_point(x=x) a = A() - hint(a, promote=True) + promote(a) x -= 1 self.meta_interp(f, [50]) self.check_loop_count(1) @@ -1549,8 +1579,6 @@ assert res == 1 def test_raw_malloc_and_access(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Signed) def f(n): @@ -1564,8 +1592,6 @@ assert res == 10 def test_raw_malloc_and_access_float(self): - from pypy.rpython.lltypesystem import rffi - TP = rffi.CArray(lltype.Float) def f(n, f): @@ -1595,9 +1621,9 @@ self.check_loops(jit_debug=2) def test_assert_green(self): - def f(x, promote): - if promote: - x = hint(x, promote=True) + def f(x, promote_flag): + if promote_flag: + promote(x) assert_green(x) return x res = self.interp_operations(f, [8, 1]) @@ -1676,8 +1702,8 @@ return a1.val + b1.val res = self.meta_interp(g, [6, 14]) assert res == g(6, 14) - self.check_loop_count(9) - self.check_loops(getarrayitem_gc=8, everywhere=True) + self.check_loop_count(8) + self.check_loops(getarrayitem_gc=7, everywhere=True) py.test.skip("for the following, we need setarrayitem(varindex)") self.check_loops(getarrayitem_gc=6, everywhere=True) @@ -1817,7 +1843,7 @@ while y > 0: myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const) myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const) - const = hint(const, promote=True) + const = promote(const) res = res.binop(A(const)) if y<7: res = x @@ -1994,7 +2020,7 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if 0 < a <= 5: pass if 0 < b <= 5: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa @@ -2002,12 +2028,12 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa - + assert self.meta_interp(f1, [5, 5]) == 50 self.check_loops(int_rshift=0, everywhere=True) @@ -2039,7 +2065,7 @@ myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) if -5 <= a < 0: pass if 0 < b <= 5: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa @@ -2047,12 +2073,12 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if -hint(sys.maxint/2, promote=True) < a < 0: pass + if -promote(sys.maxint/2) < a < 0: pass if 0 < b < 100: pass - sa += (((((a << b) << b) << b) >> b) >> b) >> b + sa += (((((a << b) << b) << b) >> b) >> b) >> b n += 1 return sa - + assert self.meta_interp(f1, [-5, 5]) == -50 self.check_loops(int_rshift=0, everywhere=True) @@ -2082,7 +2108,7 @@ n = sa = 0 while n < 10: myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa) - if 0 < a < hint(sys.maxint/2, promote=True): pass + if 0 < a < promote(sys.maxint/2): pass if 0 < b < 100: pass sa += (a << b) >> b n += 1 @@ -2123,7 +2149,7 @@ def get_printable_location(i): return str(i) - + myjitdriver = JitDriver(greens = ['i'], reds = ['j', 'c', 'a'], get_printable_location=get_printable_location) bytecode = "0j10jc20a3" @@ -2139,7 +2165,7 @@ if op == 'j': j += 1 elif op == 'c': - c = hint(c, promote=True) + promote(c) c = 1 - c elif op == '2': if j < 3: @@ -2208,7 +2234,8 @@ self.local_names[0] = 1 def retrieve(self): - variables = hint(self.variables, promote=True) + variables = self.variables + promote(variables) result = self.local_names[0] if result == 0: return -1 @@ -2231,7 +2258,7 @@ assert self.meta_interp(build, []) == 7 self.check_loops(getfield_gc_pure=0) self.check_loops(getfield_gc_pure=2, everywhere=True) - + def test_frame_finished_during_retrace(self): class Base(object): pass @@ -2262,7 +2289,7 @@ return sa res = self.meta_interp(f, []) assert res == f() - + def test_frame_finished_during_continued_retrace(self): class Base(object): pass @@ -2313,6 +2340,67 @@ assert res == -2 #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx? + def test_retrace_ending_up_retracing_another_loop(self): + + myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa']) + bytecode = "0+sI0+SI" + def f(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 1) + myjitdriver.set_param('retrace_limit', 5) + myjitdriver.set_param('function_threshold', -1) + pc = sa = i = 0 + while pc < len(bytecode): + myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i) + n = hint(n, promote=True) + op = bytecode[pc] + if op == '0': + i = 0 + elif op == '+': + i += 1 + elif op == 's': + sa += i + elif op == 'S': + sa += 2 + elif op == 'I': + if i < n: + pc -= 2 + myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i) + continue + pc += 1 + return sa + + def g(n1, n2): + for i in range(10): + f(n1) + for i in range(10): + f(n2) + + nn = [10, 3] + assert self.meta_interp(g, nn) == g(*nn) + + # The attempts of retracing first loop will end up retracing the + # second and thus fail 5 times, saturating the retrace_count. Instead a + # bridge back to the preamble of the first loop is produced. A guard in + # this bridge is later traced resulting in a retrace of the second loop. + # Thus we end up with: + # 1 preamble and 1 specialized version of first loop + # 1 preamble and 2 specialized version of second loop + self.check_tree_loop_count(2 + 3) + + # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times. + + def g(n): + for i in range(n): + for j in range(10): + f(n-i) + + res = self.meta_interp(g, [10]) + assert res == g(10) + # 1 preamble and 6 speciealized versions of each loop + self.check_tree_loop_count(2*(1 + 6)) + + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): @@ -2490,5 +2578,57 @@ self.meta_interp(f, [], enable_opts='') self.check_loops(new_with_vtable=1) + def test_release_gil_flush_heap_cache(self): + T = rffi.CArrayPtr(rffi.TIME_T) + + external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) + # Not a real lock, has all the same properties with respect to GIL + # release though, so good for this test. + class Lock(object): + @dont_look_inside + def acquire(self): + external(lltype.nullptr(T.TO)) + @dont_look_inside + def release(self): + external(lltype.nullptr(T.TO)) + class X(object): + def __init__(self, idx): + self.field = idx + @dont_look_inside + def get_obj(z): + return X(z) + myjitdriver = JitDriver(greens=[], reds=["n", "l", "z", "lock"]) + def f(n, z): + lock = Lock() + l = 0 + while n > 0: + myjitdriver.jit_merge_point(lock=lock, l=l, n=n, z=z) + x = get_obj(z) + l += x.field + lock.acquire() + # This must not reuse the previous one. + n -= x.field + lock.release() + return n + res = self.meta_interp(f, [10, 1]) + self.check_loops(getfield_gc=2) + assert res == f(10, 1) + + def test_jit_merge_point_with_raw_pointer(self): + driver = JitDriver(greens = [], reds = ['n', 'x']) + + TP = lltype.Array(lltype.Signed, hints={'nolength': True}) + + def f(n): + x = lltype.malloc(TP, 10, flavor='raw') + x[0] = 1 + while n > 0: + driver.jit_merge_point(n=n, x=x) + n -= x[0] + lltype.free(x, flavor='raw') + return n + + self.meta_interp(f, [10], repeat=3) + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong from pypy.rlib.libffi import IS_32_BIT @@ -49,8 +49,7 @@ res = init_result while n < 10: driver.jit_merge_point(n=n, res=res, func=func) - driver.can_enter_jit(n=n, res=res, func=func) - func = hint(func, promote=True) + promote(func) argchain = ArgChain() # this loop is unrolled for method_name, argval in method_and_args: diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py --- a/pypy/jit/metainterp/test/test_immutable.py +++ b/pypy/jit/metainterp/test/test_immutable.py @@ -1,5 +1,9 @@ +from pypy.rlib import jit from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin + at jit.dont_look_inside +def escape(x): + return x class ImmutableFieldsTests: @@ -11,7 +15,7 @@ self.x = x def f(x): - y = X(x) + y = escape(X(x)) return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 @@ -33,7 +37,7 @@ def f(x, y): X(x) # force the field 'x' to be on class 'X' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -42,7 +46,7 @@ def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' - z = Y(x, y) + z = escape(Y(x, y)) return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 @@ -58,7 +62,7 @@ def f(index): l = [1, 2, 3, 4] l[2] = 30 - a = X(l) + a = escape(X(l)) return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 @@ -76,7 +80,7 @@ self.y = y def f(x, index): - y = X([x], x+1) + y = escape(X([x], x+1)) return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py --- a/pypy/jit/metainterp/test/test_jitprof.py +++ b/pypy/jit/metainterp/test/test_jitprof.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction +from pypy.rlib.jit import JitDriver, dont_look_inside, elidable from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -89,7 +89,7 @@ assert profiler.calls == 1 def test_blackhole_pure(self): - @purefunction + @elidable def g(n): return n+1 diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py --- a/pypy/jit/metainterp/test/test_recursive.py +++ b/pypy/jit/metainterp/test/test_recursive.py @@ -1,6 +1,6 @@ import py from pypy.rlib.jit import JitDriver, we_are_jitted, hint -from pypy.rlib.jit import unroll_safe, dont_look_inside +from pypy.rlib.jit import unroll_safe, dont_look_inside, promote from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import fatalerror from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -926,7 +926,7 @@ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x) myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py --- a/pypy/jit/metainterp/test/test_send.py +++ b/pypy/jit/metainterp/test/test_send.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint, purefunction +from pypy.rlib.jit import JitDriver, promote, elidable from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -604,7 +604,7 @@ def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: - @purefunction + @elidable def foo(self): return 42 def fn(n, i): @@ -613,7 +613,7 @@ while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) - obj = hint(obj, promote=True) + promote(obj) res = obj.foo() i-=1 return res diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/test/test_tracingopts.py @@ -0,0 +1,407 @@ +import py +import sys +from pypy.rlib import jit +from pypy.jit.metainterp.test.support import LLJitMixin + + +class TestLLtype(LLJitMixin): + def test_dont_record_repeated_guard_class(self): + class A: + pass + class B(A): + pass + @jit.dont_look_inside + def extern(n): + if n == -7: + return None + elif n: + return A() + else: + return B() + def fn(n): + obj = extern(n) + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=1, guard_nonnull=1) + res = self.interp_operations(fn, [1]) + assert not res + + def test_dont_record_guard_class_after_new(self): + class A: + pass + class B(A): + pass + def fn(n): + if n == -7: + obj = None + elif n: + obj = A() + else: + obj = B() + return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + res = self.interp_operations(fn, [0]) + assert res == 4 + self.check_operations_history(guard_class=0, guard_nonnull=0) + res = self.interp_operations(fn, [1]) + assert not res + + def test_guard_isnull_nullifies(self): + class A: + pass + a = A() + a.x = None + def fn(n): + if n == -7: + a.x = "" + obj = a.x + res = 0 + if not obj: + res += 1 + if obj: + res += 1 + if obj is None: + res += 1 + if obj is not None: + res += 1 + return res + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(guard_isnull=1) + + def test_heap_caching_while_tracing(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def fn(n, ca, cb): + a1.x = n + a2.x = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a.x + b.x + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getfield_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_while_tracing_invalidation(self): + class A: + pass + a1 = A() + a2 = A() + @jit.dont_look_inside + def f(a): + a.x = 5 + l = [1] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + x1 = a.x + f(a) + x2 = a.x + l[0] = x2 + return a.x + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getfield_gc=1) + + def test_heap_caching_dont_store_same(self): + class A: + pass + a1 = A() + a2 = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.x = n + a.x = n + return a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + self.check_operations_history(getfield_gc=0, setfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 + self.check_operations_history(getfield_gc=0) + + def test_array_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_caching_while_tracing_invalidation(self): + a1 = [0, 0] + a2 = [0, 0] + @jit.dont_look_inside + def f(a): + a[0] = 5 + class A: pass + l = A() + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + x1 = a[0] + f(a) + x2 = a[0] + l.x = x2 + return a[0] + x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 5 * 2 + 7 + self.check_operations_history(getarrayitem_gc=1) + + def test_array_and_getfield_interaction(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + a.x = 0 + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, + getarrayitem_gc=0, getfield_gc=1) + + def test_promote_changes_heap_cache(self): + class A: pass + a1 = A() + a2 = A() + a1.l = a2.l = [0, 0] + a1.x = a2.x = 0 + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a.l = [0, 0] + jit.promote(a.x) + a.l[a.x] = n + a.x += 1 + a.l[a.x] = n + 1 + x1 = a.l[a.x] + a.x -= 1 + x2 = a.l[a.x] + return x1 + x2 + res = self.interp_operations(fn, [7]) + assert res == 7 * 2 + 1 + self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, + getarrayitem_gc=0, getfield_gc=2) + + def test_list_caching(self): + a1 = [0, 0] + a2 = [0, 0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + if n < -1000: + a.append(5) + a[0] = n + x1 = a[0] + a[n - n] = n + 1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=1) + + def fn(n, ca, cb): + a1[0] = n + a2[0] = n + a = a1 + if ca: + a = a2 + if n < -100: + a.append(5) + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == 7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == -7 * 2 + self.check_operations_history(getarrayitem_gc=1, + getfield_gc=3) + + def test_list_caching_negative(self): + def fn(n): + a = [0] * n + if n > 1000: + a.append(0) + a[-1] = n + x1 = a[-1] + a[n - n - 1] = n + 1 + return a[-1] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(setarrayitem_gc=2, + setfield_gc=2) + + def test_virtualizable_with_array_heap_cache(self): + myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['l[*]', 's'] + + def __init__(self, a, s): + self = jit.hint(self, access_directly=True, fresh_virtualizable=True) + self.l = [0] * (4 + a) + self.s = s + + def f(n, a, i): + frame = Frame(a, 0) + frame.l[0] = a + frame.l[1] = a + 1 + frame.l[2] = a + 2 + frame.l[3] = a + 3 + if not i: + return frame.l[0] + len(frame.l) + x = 0 + while n > 0: + myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i) + myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i) + frame.s = jit.promote(frame.s) + n -= 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + frame.s += 1 + s = frame.s + assert s >= 0 + x += frame.l[s] + x += len(frame.l) + x += f(n, n, 0) + frame.s -= 1 + return x + + res = self.meta_interp(f, [10, 1, 1], listops=True) + assert res == f(10, 1, 1) + self.check_history(getarrayitem_gc=0, getfield_gc=0) + + def test_heap_caching_pure(self): + class A(object): + pass + p1 = A() + p2 = A() + def fn(n): + if n >= 0: + a = (n, n + 1) + p = p1 + else: + a = (n + 1, n) + p = p2 + p.x = a + + return p.x[0] + p.x[1] + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 1 + self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + + def test_heap_caching_and_elidable_function(self): + class A: + pass + class B: pass + a1 = A() + a1.y = 6 + a2 = A() + a2.y = 13 + @jit.elidable + def f(b): + return b + 1 + def fn(n): + if n > 0: + a = a1 + else: + a = A() + a.x = n + z = f(6) + return z + a.x + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + self.check_operations_history(getfield_gc=0) + res = self.interp_operations(fn, [-7]) + assert res == -7 + 7 + self.check_operations_history(getfield_gc=0) + return diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py --- a/pypy/jit/metainterp/test/test_virtual.py +++ b/pypy/jit/metainterp/test/test_virtual.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver, hint +from pypy.rlib.jit import JitDriver, promote from pypy.rlib.objectmodel import compute_unique_id from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin @@ -300,7 +300,7 @@ while n > 0: myjitdriver.can_enter_jit(n=n, i=i, stufflist=stufflist) myjitdriver.jit_merge_point(n=n, i=i, stufflist=stufflist) - i = hint(i, promote=True) + promote(i) v = Stuff(i) n -= stufflist.lst[v.x].x return n diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py --- a/pypy/jit/metainterp/test/test_virtualizable.py +++ b/pypy/jit/metainterp/test/test_virtualizable.py @@ -5,7 +5,7 @@ from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY from pypy.jit.codewriter.policy import StopAtXPolicy from pypy.jit.codewriter import heaptracker -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin from pypy.rpython.rclass import FieldListAccessor @@ -377,7 +377,7 @@ expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected - self.check_loops(getfield_gc=3, setfield_gc=0, + self.check_loops(getfield_gc=1, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) # ------------------------------ @@ -480,7 +480,7 @@ while n > 0: myjitdriver.can_enter_jit(frame=frame, n=n, x=x) myjitdriver.jit_merge_point(frame=frame, n=n, x=x) - frame.s = hint(frame.s, promote=True) + frame.s = promote(frame.s) n -= 1 s = frame.s assert s >= 0 @@ -1133,6 +1133,7 @@ res = self.meta_interp(f, [10]) assert res == 55 self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True) + self.check_history(ptr_eq=2) def test_virtual_child_frame_with_arrays(self): myjitdriver = JitDriver(greens = [], reds = ['frame'], diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -186,6 +186,7 @@ _get_printable_location_ptr = None _confirm_enter_jit_ptr = None _can_never_inline_ptr = None + _should_unroll_one_iteration_ptr = None class FakeCell: dont_trace_here = False state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) @@ -214,6 +215,7 @@ _confirm_enter_jit_ptr = None _can_never_inline_ptr = None _get_jitcell_at_ptr = None + _should_unroll_one_iteration_ptr = None state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) state.make_jitdriver_callbacks() res = state.get_location_str([ConstInt(5), constfloat(42.5)]) @@ -238,6 +240,7 @@ _confirm_enter_jit_ptr = llhelper(ENTER_JIT, confirm_enter_jit) _can_never_inline_ptr = None _get_jitcell_at_ptr = None + _should_unroll_one_iteration_ptr = None state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) state.make_jitdriver_callbacks() @@ -262,6 +265,7 @@ _confirm_enter_jit_ptr = None _can_never_inline_ptr = llhelper(CAN_NEVER_INLINE, can_never_inline) _get_jitcell_at_ptr = None + _should_unroll_one_iteration_ptr = None state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) state.make_jitdriver_callbacks() diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -10,6 +10,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.debug import fatalerror +from pypy.rlib.rstackovf import StackOverflow from pypy.translator.simplify import get_functype from pypy.translator.unsimplify import call_final_function @@ -408,21 +409,28 @@ jd.warmstate = state def crash_in_jit(e): - if not we_are_translated(): - print "~~~ Crash in JIT!" - print '~~~ %s: %s' % (e.__class__, e) - if sys.stdout == sys.__stdout__: - import pdb; pdb.post_mortem(sys.exc_info()[2]) - raise - fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) + try: + raise e + except JitException: + raise # go through + except MemoryError: + raise # go through + except StackOverflow: + raise # go through + except Exception, e: + if not we_are_translated(): + print "~~~ Crash in JIT!" + print '~~~ %s: %s' % (e.__class__, e) + if sys.stdout == sys.__stdout__: + import pdb; pdb.post_mortem(sys.exc_info()[2]) + raise + fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) crash_in_jit._dont_inline_ = True if self.translator.rtyper.type_system.name == 'lltypesystem': def maybe_enter_jit(*args): try: maybe_compile_and_run(state.increment_threshold, *args) - except JitException: - raise # go through except Exception, e: crash_in_jit(e) maybe_enter_jit._always_inline_ = True @@ -460,6 +468,9 @@ onlygreens=False) jd._can_never_inline_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool) + jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd, + annhelper, jd.jitdriver.should_unroll_one_iteration, + annmodel.s_Bool) annhelper.finish() def _make_hook_graph(self, jitdriver_sd, annhelper, func, diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -138,7 +138,10 @@ refvalue = cpu.ts.cast_to_ref(value) cpu.set_future_value_ref(j, refvalue) elif typecode == 'int': - intvalue = lltype.cast_primitive(lltype.Signed, value) + if isinstance(lltype.typeOf(value), lltype.Ptr): + intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value)) + else: + intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) elif typecode == 'float': if lltype.typeOf(value) is lltype.Float: @@ -237,7 +240,7 @@ d = {} if NonConstant(False): value = 'blah' # not a constant '' - if value is None: + if value is None or value == 'all': value = ALL_OPTS_NAMES for name in value.split(":"): if name: @@ -569,6 +572,19 @@ return can_inline_greenargs(*greenargs) self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + + if jd._should_unroll_one_iteration_ptr is None: + def should_unroll_one_iteration(greenkey): + return False + else: + rtyper = self.warmrunnerdesc.rtyper + inline_ptr = jd._should_unroll_one_iteration_ptr + def should_unroll_one_iteration(greenkey): + greenargs = unwrap_greenkey(greenkey) + fn = support.maybe_on_top_of_llinterp(rtyper, inline_ptr) + return fn(*greenargs) + self.should_unroll_one_iteration = should_unroll_one_iteration + if hasattr(jd.jitdriver, 'on_compile'): def on_compile(logger, token, operations, type, greenkey): greenargs = unwrap_greenkey(greenkey) diff --git a/pypy/jit/tl/spli/interpreter.py b/pypy/jit/tl/spli/interpreter.py --- a/pypy/jit/tl/spli/interpreter.py +++ b/pypy/jit/tl/spli/interpreter.py @@ -2,7 +2,7 @@ from pypy.tool import stdlib_opcode from pypy.jit.tl.spli import objects, pycode from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.objectmodel import we_are_translated opcode_method_names = stdlib_opcode.host_bytecode_spec.method_names @@ -78,7 +78,7 @@ while True: jitdriver.jit_merge_point(code=code, instr_index=instr_index, frame=self) - self.stack_depth = hint(self.stack_depth, promote=True) + self.stack_depth = promote(self.stack_depth) op = ord(code[instr_index]) instr_index += 1 if op >= HAVE_ARGUMENT: diff --git a/pypy/jit/tl/tiny2.py b/pypy/jit/tl/tiny2.py --- a/pypy/jit/tl/tiny2.py +++ b/pypy/jit/tl/tiny2.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint +from pypy.rlib.jit import hint, promote # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -75,9 +75,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -108,7 +108,7 @@ # doesn't have to worry about the 'args' list being unpredictably # modified. oldargs = args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -160,8 +160,7 @@ # read out of the 'loops' list will be a compile-time constant # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the - # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + promote(pos) else: stack.append(StrBox(opcode)) return stack diff --git a/pypy/jit/tl/tiny2_hotpath.py b/pypy/jit/tl/tiny2_hotpath.py --- a/pypy/jit/tl/tiny2_hotpath.py +++ b/pypy/jit/tl/tiny2_hotpath.py @@ -27,7 +27,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import hint, promote, JitDriver # # See pypy/doc/jit.txt for a higher-level overview of the JIT techniques @@ -77,9 +77,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) try: z = IntBox(func_int(x.as_int(), y.as_int())) except ValueError: @@ -120,7 +120,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -189,7 +189,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tiny3_hotpath.py b/pypy/jit/tl/tiny3_hotpath.py --- a/pypy/jit/tl/tiny3_hotpath.py +++ b/pypy/jit/tl/tiny3_hotpath.py @@ -28,7 +28,7 @@ { #1 #1 1 SUB ->#1 #1 } => when called with 5, gives '5 4 3 2 1' """ -from pypy.rlib.jit import hint, JitDriver +from pypy.rlib.jit import promote, hint, JitDriver from pypy.rlib.objectmodel import specialize # @@ -83,9 +83,9 @@ # ones. The JIT compiler cannot look into indirect calls, but it # can analyze and inline the code in directly-called functions. stack, y = stack.pop() - hint(y.__class__, promote=True) + promote(y.__class__) stack, x = stack.pop() - hint(x.__class__, promote=True) + promote(x.__class__) if isinstance(x, IntBox) and isinstance(y, IntBox): z = IntBox(func_int(x.as_int(), y.as_int())) else: @@ -125,7 +125,7 @@ # modified. oldloops = invariants oldargs = reds.args - argcount = hint(len(oldargs), promote=True) + argcount = promote(len(oldargs)) args = [] n = 0 while n < argcount: @@ -194,7 +194,7 @@ # because it was pushed as a compile-time constant by the '{' # case above into 'loops', which is a virtual list, so the # promotion below is just a way to make the colors match. - pos = hint(pos, promote=True) + pos = promote(pos) tinyjitdriver.can_enter_jit(args=args, loops=loops, stack=stack, bytecode=bytecode, pos=pos) else: diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py --- a/pypy/jit/tl/tl.py +++ b/pypy/jit/tl/tl.py @@ -2,7 +2,7 @@ import py from pypy.jit.tl.tlopcode import * -from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import JitDriver, hint, dont_look_inside, promote def char2int(c): t = ord(c) @@ -81,7 +81,7 @@ myjitdriver.jit_merge_point(pc=pc, code=code, stack=stack, inputarg=inputarg) opcode = ord(code[pc]) - stack.stackpos = hint(stack.stackpos, promote=True) + stack.stackpos = promote(stack.stackpos) pc += 1 if opcode == NOP: diff --git a/pypy/jit/tl/tlc.py b/pypy/jit/tl/tlc.py --- a/pypy/jit/tl/tlc.py +++ b/pypy/jit/tl/tlc.py @@ -5,7 +5,7 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.tl.tlopcode import * from pypy.jit.tl import tlopcode -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, elidable class Obj(object): @@ -71,6 +71,7 @@ classes = [] # [(descr, cls), ...] + @elidable def get(key): for descr, cls in Class.classes: if key.attributes == descr.attributes and\ @@ -79,7 +80,6 @@ result = Class(key) Class.classes.append((key, result)) return result - get._pure_function_ = True get = staticmethod(get) def __init__(self, descr): diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -337,6 +337,11 @@ num += 1 return num, ops, last_offset + def postprocess(self, loop): + """ A hook that can be overloaded to do some postprocessing + """ + return loop + def parse_offset(self, line): if line.startswith('+'): # it begins with an offset, like: "+10: i1 = int_add(...)" diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py --- a/pypy/module/__builtin__/__init__.py +++ b/pypy/module/__builtin__/__init__.py @@ -5,20 +5,6 @@ # put builtins here that should be optimized somehow -OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", - "isinstance", "type", "zip", "file", "format", "open", "abs", "chr", - "unichr", "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", - "getattr", "setattr", "delattr", "callable", "int", "str", "float"] - -assert len(OPTIMIZED_BUILTINS) <= 256 - -BUILTIN_TO_INDEX = {} - -for i, name in enumerate(OPTIMIZED_BUILTINS): - BUILTIN_TO_INDEX[name] = i - -assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) - class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" expose__file__attribute = False @@ -141,9 +127,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space - self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) - for i, name in enumerate(OPTIMIZED_BUILTINS): - self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) diff --git a/pypy/module/__builtin__/abstractinst.py b/pypy/module/__builtin__/abstractinst.py --- a/pypy/module/__builtin__/abstractinst.py +++ b/pypy/module/__builtin__/abstractinst.py @@ -58,7 +58,10 @@ # -- case (anything, type) try: - w_result = space.isinstance(w_obj, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.isinstance_allow_override(w_obj, w_klass_or_tuple) + else: + w_result = space.isinstance(w_obj, w_klass_or_tuple) except OperationError, e: # if w_klass_or_tuple was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors @@ -72,8 +75,11 @@ w_pretendtype = space.getattr(w_obj, space.wrap('__class__')) if space.is_w(w_pretendtype, space.type(w_obj)): return False # common case: obj.__class__ is type(obj) - w_result = space.issubtype(w_pretendtype, w_klass_or_tuple, - allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_pretendtype, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_pretendtype, w_klass_or_tuple) except OperationError, e: if e.async(space): raise @@ -134,7 +140,11 @@ # -- case (type, type) try: - w_result = space.issubtype(w_derived, w_klass_or_tuple, allow_override) + if allow_override: + w_result = space.issubtype_allow_override(w_derived, + w_klass_or_tuple) + else: + w_result = space.issubtype(w_derived, w_klass_or_tuple) except OperationError, e: # if one of the args was not a type, ignore it if not e.match(space, space.w_TypeError): raise # propagate other errors diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py --- a/pypy/module/__builtin__/compiling.py +++ b/pypy/module/__builtin__/compiling.py @@ -5,7 +5,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError from pypy.interpreter.astcompiler import consts, ast -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec @unwrap_spec(filename=str, mode=str, flags=int, dont_inherit=int) def compile(space, w_source, filename, mode, flags=0, dont_inherit=0): diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py --- a/pypy/module/__builtin__/descriptor.py +++ b/pypy/module/__builtin__/descriptor.py @@ -1,12 +1,10 @@ - -from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.function import StaticMethod, ClassMethod from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.descroperation import object_getattribute, object_setattr -from pypy.interpreter.function import StaticMethod, ClassMethod -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \ - descr_set_dict, interp_attrproperty_w, generic_new_descr +from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w, + generic_new_descr) +from pypy.objspace.descroperation import object_getattribute class W_Super(Wrappable): def __init__(self, space, w_starttype, w_objtype, w_self): diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -4,13 +4,12 @@ """ from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import NoneNotWrapped, applevel +from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.objectmodel import specialize -from inspect import getsource, getfile from pypy.rlib.rbigint import rbigint @@ -662,7 +661,6 @@ def descr_reduce(self): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns space = self.space w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -1,18 +1,16 @@ import new from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import NoneNotWrapped, applevel, interp2app +from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, descr_get_dict -from pypy.interpreter.typedef import descr_set_dict -from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, descr_set_dict from pypy.rlib.objectmodel import compute_identity_hash from pypy.rlib.debug import make_sure_not_resized from pypy.rlib import jit def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space, '?') + type_name = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %s", argument, expected, type_name) @@ -420,7 +418,7 @@ if w_meth is not None: space.call_function(w_meth, w_name) else: - if not self.deldictvalue(space, w_name): + if not self.deldictvalue(space, name): raise operationerrfmt( space.w_AttributeError, "%s instance has no attribute '%s'", diff --git a/pypy/module/__builtin__/interp_memoryview.py b/pypy/module/__builtin__/interp_memoryview.py --- a/pypy/module/__builtin__/interp_memoryview.py +++ b/pypy/module/__builtin__/interp_memoryview.py @@ -2,7 +2,7 @@ Implementation of the 'buffer' and 'memoryview' types. """ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter import gateway, buffer +from pypy.interpreter import buffer from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -4,12 +4,10 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.runicode import UNICHR from pypy.rlib.rfloat import isnan, isinf, round_double from pypy.rlib import rfloat -import math import __builtin__ NoneNotWrapped = gateway.NoneNotWrapped diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -631,62 +631,6 @@ raises(TypeError, pr, end=3) raises(TypeError, pr, sep=42) -class AppTestBuiltinOptimized(object): - def setup_class(cls): - from pypy.conftest import gettestobjspace - cls.space = gettestobjspace(**{"objspace.opcodes.CALL_LIKELY_BUILTIN": True}) - - # hum, we need to invoke the compiler explicitely - def test_xrange_len(self): - s = """def test(): - x = xrange(33) - assert len(x) == 33 - x = xrange(33.2) - assert len(x) == 33 - x = xrange(33,0,-1) - assert len(x) == 33 - x = xrange(33,0) - assert len(x) == 0 - x = xrange(33,0.2) - assert len(x) == 0 - x = xrange(0,33) - assert len(x) == 33 - x = xrange(0,33,-1) - assert len(x) == 0 - x = xrange(0,33,2) - assert len(x) == 17 - x = xrange(0,32,2) - assert len(x) == 16 - """ - ns = {} - exec s in ns - ns["test"]() - - def test_delete_from_builtins(self): - s = """ """ - # XXX write this test! - - def test_shadow_case_bound_method(self): - s = """def test(l): - n = len(l) - old_len = len - class A(object): - x = 5 - def length(self, o): - return self.x*old_len(o) - import __builtin__ - __builtin__.len = A().length - try: - m = len(l) - finally: - __builtin__.len = old_len - return n+m - """ - ns = {} - exec s in ns - res = ns["test"]([2,3,4]) - assert res == 18 - def test_round(self): assert round(11.234) == 11.0 assert round(11.234, -1) == 10.0 diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -987,9 +987,9 @@ if option.runappdirect: py.test.skip("can only be run on py.py") def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import StrDictImplementation + from pypy.objspace.std.dictmultiobject import StringDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d, StrDictImplementation) and w_d.r_dict_content is None) + return space.wrap(isinstance(w_d.strategy, StringDictStrategy)) cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -25,6 +25,7 @@ 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', 'lookup_special' : 'interp_magic.lookup_special', + 'do_what_I_mean' : 'interp_magic.do_what_I_mean', } submodules = { diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py --- a/pypy/module/__pypy__/interp_debug.py +++ b/pypy/module/__pypy__/interp_debug.py @@ -1,5 +1,4 @@ -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec from pypy.rlib import debug, jit diff --git a/pypy/module/__pypy__/interp_identitydict.py b/pypy/module/__pypy__/interp_identitydict.py --- a/pypy/module/__pypy__/interp_identitydict.py +++ b/pypy/module/__pypy__/interp_identitydict.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef -from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app from pypy.interpreter.baseobjspace import Wrappable class W_IdentityDict(Wrappable): diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -70,3 +70,6 @@ if w_descr is None: return space.w_None return space.get(w_descr, w_obj) + +def do_what_I_mean(space): + return space.wrap(42) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -49,3 +49,8 @@ class X: pass raises(TypeError, lookup_special, X(), "foo") + + def test_do_what_I_mean(self): + from __pypy__ import do_what_I_mean + x = do_what_I_mean() + assert x == 42 diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -186,6 +186,11 @@ mod = self.get_ast("from __future__ import with_statement; import y; " \ "from __future__ import nested_scopes") raises(SyntaxError, compile, mod, "", "exec") + mod = self.get_ast("from __future__ import division\nx = 1/2") + co = compile(mod, "", "exec") + ns = {} + exec co in ns + assert ns["x"] == .5 def test_field_attr_writable(self): import _ast as ast @@ -245,3 +250,38 @@ assert x.left == n1 assert x.op == addop assert x.right == n3 + + def test_functiondef(self): + import _ast as ast + fAst = ast.FunctionDef( + name="foo", + args=ast.arguments( + args=[], vararg=None, kwarg=None, defaults=[], + kwonlyargs=[], kw_defaults=[]), + body=[], decorator_list=[], lineno=5, col_offset=0) + exprAst = ast.Interactive(body=[fAst]) + compiled = compile(exprAst, "", "single") + # + d = {} + eval(compiled, d, d) + assert type(d['foo']) is type(lambda: 42) + assert d['foo']() is None + + def test_missing_name(self): + import _ast as ast + n = ast.FunctionDef(name=None) + n.name = "foo" + n.name = "foo" + n.name = "foo" + assert n.name == "foo" + + def test_issue793(self): + import _ast as ast + body = ast.Module([ + ast.TryExcept([ast.Pass(lineno=2, col_offset=4)], + [ast.ExceptHandler(ast.Name('Exception', ast.Load(), + lineno=3, col_offset=0), + None, [], lineno=4, col_offset=0)], + [], lineno=1, col_offset=0) + ]) + exec compile(body, '', 'exec') diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.objectmodel import we_are_translated class CodecState(object): @@ -186,7 +186,7 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -207,7 +207,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) @@ -240,7 +240,7 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space, '?') + typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, "don't know how to handle %s in error callback", typename) diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -1,9 +1,8 @@ -import sys -from pypy.interpreter.baseobjspace import Wrappable, Arguments +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, \ operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import TypeDef from pypy.module._rawffi.structure import W_StructureInstance, W_Structure # from pypy.rpython.lltypesystem import lltype, rffi @@ -16,7 +15,7 @@ class W_FFIType(Wrappable): _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to'] - + def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None): self.name = name self.ffitype = ffitype @@ -83,7 +82,6 @@ def build_ffi_types(): - from pypy.rlib.clibffi import FFI_TYPE_P types = [ # note: most of the type name directly come from the C equivalent, # with the exception of bytes: in C, ubyte and char are equivalent, @@ -149,13 +147,19 @@ raise OperationError(space.w_TypeError, space.wrap(msg)) return res +def unwrap_truncate_int(TP, space, w_arg): + if space.is_true(space.isinstance(w_arg, space.w_int)): + return rffi.cast(TP, space.int_w(w_arg)) + else: + return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask()) +unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)' # ======================================================================== class W_FuncPtr(Wrappable): _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype'] - + def __init__(self, func, argtypes_w, w_restype): self.func = func self.argtypes_w = argtypes_w @@ -181,15 +185,14 @@ # note that we must check for longlong first, because either # is_signed or is_unsigned returns true anyway assert libffi.IS_32_BIT - kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind - self.arg_longlong(space, argchain, kind, w_arg) + self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): - argchain.arg(space.int_w(w_arg)) + argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) elif w_argtype.is_unsigned(): - argchain.arg(intmask(space.uint_w(w_arg))) + argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg)) elif w_argtype.is_char(): w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) @@ -202,7 +205,7 @@ argchain.arg_singlefloat(space.float_w(w_arg)) elif w_argtype.is_struct(): # arg_raw directly takes value to put inside ll_args - w_arg = space.interp_w(W_StructureInstance, w_arg) + w_arg = space.interp_w(W_StructureInstance, w_arg) ptrval = w_arg.ll_buffer argchain.arg_raw(ptrval) else: @@ -220,22 +223,17 @@ return w_arg @jit.dont_look_inside - def arg_longlong(self, space, argchain, kind, w_arg): + def arg_longlong(self, space, argchain, w_arg): bigarg = space.bigint_w(w_arg) - if kind == 'I': - llval = bigarg.tolonglong() - elif kind == 'U': - ullval = bigarg.toulonglong() - llval = rffi.cast(rffi.LONGLONG, ullval) - else: - assert False + ullval = bigarg.ulonglongmask() + llval = rffi.cast(rffi.LONGLONG, ullval) # this is a hack: we store the 64 bits of the long long into the # 64 bits of a float (i.e., a C double) floatval = libffi.longlong2float(llval) argchain.arg_longlong(floatval) def call(self, space, args_w): - self = jit.hint(self, promote=True) + self = jit.promote(self) argchain = self.build_argchain(space, args_w) w_restype = self.w_restype if w_restype.is_longlong(): @@ -404,7 +402,7 @@ except KeyError: raise operationerrfmt(space.w_AttributeError, "No symbol %s found in library %s", name, self.name) - + return W_FuncPtr(func, argtypes_w, w_restype) @unwrap_spec(name=str) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -111,7 +111,6 @@ types.double) assert pow(2, 3) == 8 - def test_int_args(self): """ DLLEXPORT int sum_xy(int x, int y) @@ -119,10 +118,12 @@ return x+y; } """ + import sys from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint) assert sum_xy(30, 12) == 42 + assert sum_xy(sys.maxint*2, 0) == -2 def test_void_result(self): """ @@ -247,6 +248,9 @@ types.ulong) assert sum_xy(sys.maxint, 12) == sys.maxint+12 assert sum_xy(sys.maxint+1, 12) == sys.maxint+13 + # + res = sum_xy(sys.maxint*2+3, 0) + assert res == 1 def test_unsigned_short_args(self): """ @@ -375,6 +379,9 @@ res = sum_xy(x, y) expected = maxint64 + 3 assert res == expected + # + res = sum_xy(maxint64*2+3, 0) + assert res == 1 def test_byval_argument(self): """ diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -43,11 +43,17 @@ # assume that the file and stream objects are only visible in the # thread that runs __del__, so no race condition should be possible self.clear_all_weakrefs() + if self.stream is not None: + self.enqueue_for_destruction(self.space, W_File.destructor, + 'close() method of ') + + def destructor(self): + assert isinstance(self, W_File) try: self.direct_close() except StreamErrors, e: operr = wrap_streamerror(self.space, e, self.w_name) - operr.write_unraisable(self.space, '__del__ of ', self) + raise operr def fdopenstream(self, stream, fd, mode, w_name=None): self.fd = fd diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -3,12 +3,10 @@ from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, wrap_oserror2 -from pypy.interpreter.gateway import ObjSpace -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -import os def wrap_streamerror(space, e, w_filename=None): if isinstance(e, streamio.StreamError): diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -4,7 +4,6 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.buffer import RWBuffer -from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstring import StringBuilder from pypy.rlib.rarithmetic import r_longlong, intmask from pypy.tool.sourcetools import func_renamer @@ -175,7 +174,7 @@ return space.call_method(self.w_raw, "isatty") def repr_w(self, space): - typename = space.type(self).getname(space, '?') + typename = space.type(self).getname(space) module = space.str_w(space.type(self).get_module()) try: w_name = space.getattr(self, space.wrap("name")) diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py --- a/pypy/module/_io/interp_fileio.py +++ b/pypy/module/_io/interp_fileio.py @@ -1,5 +1,4 @@ -from pypy.interpreter.typedef import ( - TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty) +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 from pypy.rlib.rarithmetic import r_longlong diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -6,7 +6,6 @@ TypeDef, interp_attrproperty, generic_new_descr) from pypy.module.exceptions.interp_exceptions import W_IOError from pypy.module._io.interp_fileio import W_FileIO -from pypy.module._io.interp_iobase import W_IOBase from pypy.module._io.interp_textio import W_TextIOWrapper from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES @@ -119,7 +118,7 @@ if buffering < 0: buffering = DEFAULT_BUFFER_SIZE - if "st_blksize" in STAT_FIELD_TYPES: + if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES: fileno = space.int_w(space.call_method(w_raw, "fileno")) try: st = os.fstat(fileno) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -57,6 +57,11 @@ def __del__(self): self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, W_IOBase.destructor, + 'internal __del__ of ') + + def destructor(self): + assert isinstance(self, W_IOBase) space = self.space w_closed = space.findattr(self, space.wrap('closed')) try: @@ -155,7 +160,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space, '?')) + "not '%s'", space.type(w_readahead).getname(space)) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -181,7 +186,7 @@ raise operationerrfmt( space.w_IOError, "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space, '?')) + "not '%s'", space.type(w_read).getname(space)) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -129,7 +129,7 @@ if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, "string argument expected, got '%s'", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self._check_closed(space) orig_size = space.len_w(w_obj) diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -4,7 +4,7 @@ generic_new_descr) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint from pypy.rlib.rbigint import rbigint from pypy.rlib.rstring import UnicodeBuilder diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py --- a/pypy/module/_locale/interp_locale.py +++ b/pypy/module/_locale/interp_locale.py @@ -1,4 +1,3 @@ -from pypy.rpython.tool import rffi_platform as platform from pypy.rlib import rposix from pypy.rlib.rarithmetic import intmask diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -149,7 +149,7 @@ factor * float(self.ll_it), w_sublist) return space.wrap(w_se) - @jit.purefunction + @jit.elidable def _get_or_make_subentry(self, entry, make=True): try: return self.calls[entry] @@ -167,7 +167,7 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry) subentry.recursionLevel += 1 self.ll_t0 = profobj.ll_timer() @@ -179,7 +179,7 @@ self.previous.ll_subt += tt entry._stop(tt, it) if profobj.subcalls and self.previous: - caller = jit.hint(self.previous.entry, promote=True) + caller = jit.promote(self.previous.entry) subentry = caller._get_or_make_subentry(entry, False) if subentry is not None: subentry._stop(tt, it) @@ -212,7 +212,7 @@ module += '.' return '{%s%s}' % (module, w_arg.name) else: - class_name = space.type(w_arg).getname(space, '?') + class_name = space.type(w_arg).getname(space) return "{'%s' object}" % (class_name,) def lsprof_call(space, w_self, frame, event, w_arg): @@ -282,7 +282,7 @@ c_setup_profiling() space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) - @jit.purefunction + @jit.elidable def _get_or_make_entry(self, f_code, make=True): try: return self.data[f_code] @@ -293,7 +293,7 @@ return entry return None - @jit.purefunction + @jit.elidable def _get_or_make_builtin_entry(self, key, make=True): try: return self.builtin_data[key] @@ -306,7 +306,7 @@ def _enter_call(self, f_code): # we have a superb gc, no point in freelist :) - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code) self.current_context = ProfilerContext(self, entry) @@ -314,14 +314,14 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_entry(f_code, False) if entry is not None: context._stop(self, entry) self.current_context = context.previous def _enter_builtin_call(self, key): - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key) self.current_context = ProfilerContext(self, entry) @@ -329,7 +329,7 @@ context = self.current_context if context is None: return - self = jit.hint(self, promote=True) + self = jit.promote(self) entry = self._get_or_make_builtin_entry(key, False) if entry is not None: context._stop(self, entry) diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -181,8 +181,7 @@ class AppTestWithDifferentBytecodes(AppTestCProfile): - keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True, - 'objspace.opcodes.CALL_METHOD': True} + keywords = {'objspace.opcodes.CALL_METHOD': True} expected_output = {} diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -2,12 +2,10 @@ """ The ffi for rpython, need to be imported for side effects """ -import sys from pypy.rpython.lltypesystem import rffi from pypy.rpython.lltypesystem import lltype from pypy.rpython.tool import rffi_platform from pypy.rpython.extfunc import register_external -from pypy.rpython.extregistry import ExtRegistryEntry from pypy.module._minimal_curses import interp_curses from pypy.translator.tool.cbuild import ExternalCompilationInfo @@ -82,7 +80,7 @@ return res finally: rffi.free_charp(ll_cap) - + register_external(interp_curses._curses_tigetstr, [str], str, export_name='_curses.tigetstr', llimpl=tigetstr_llimpl) diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py --- a/pypy/module/_multibytecodec/c_codecs.py +++ b/pypy/module/_multibytecodec/c_codecs.py @@ -1,4 +1,4 @@ -import py, sys +import py from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.tool.autopath import pypydir @@ -55,10 +55,12 @@ "pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk", "pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen", "pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed", + "pypy_cjk_dec_replace_on_error", "pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk", "pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen", "pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed", + "pypy_cjk_enc_replace_on_error", ] + ["pypy_cjkcodec_%s" % codec for codec in codecs], ) diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py --- a/pypy/module/_multibytecodec/interp_multibytecodec.py +++ b/pypy/module/_multibytecodec/interp_multibytecodec.py @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef from pypy.interpreter.error import OperationError from pypy.module._multibytecodec import c_codecs diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -4,7 +4,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import ( OperationError, wrap_oserror, operationerrfmt) -from pypy.rpython.lltypesystem import rffi, lltype, llmemory +from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.rarithmetic import intmask from pypy.rlib import rpoll import sys @@ -360,7 +360,7 @@ conn_type = ["read-only", "write-only", "read-write"][self.flags] return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space, '?'), self.do_fileno())) + conn_type, space.type(self).getname(space), self.do_fileno())) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -15,7 +15,6 @@ if sys.platform == 'win32': from pypy.rlib import rwin32 - from pypy.interpreter.error import wrap_windowserror from pypy.module._multiprocessing.interp_win32 import ( handle_w, _GetTickCount) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -1,4 +1,4 @@ -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError from pypy.interpreter.nestedscope import Cell from pypy.interpreter.pycode import PyCode from pypy.interpreter.function import Function, Method @@ -8,7 +8,6 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec -from pypy.objspace.std.dicttype import dictiter_typedef from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject @@ -79,7 +78,7 @@ try: return gateway.BuiltinCode.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin code: "+ identifier)) @@ -89,7 +88,7 @@ try: return function.Function.find(identifier) except KeyError: - raise OperationError(space.w_RuntimeError, + raise OperationError(space.w_RuntimeError, space.wrap("cannot unpickle builtin function: "+ identifier)) diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,10 +2,10 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rpython.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import get_elem, push_elem +from pypy.module._rawffi.array import push_elem from pypy.module._rawffi.structure import W_Structure -from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \ - wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes +from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, + unwrap_value, unpack_argshapes) from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL from pypy.rlib.clibffi import ffi_type_void from pypy.rlib import rweakref diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -1,7 +1,6 @@ -import sys from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt -from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.rlib.clibffi import * @@ -15,7 +14,7 @@ from pypy.rlib import rwin32 from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.tracker import tracker TYPEMAP = { diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py --- a/pypy/module/_socket/interp_func.py +++ b/pypy/module/_socket/interp_func.py @@ -1,9 +1,8 @@ -from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec +from pypy.interpreter.gateway import unwrap_spec from pypy.module._socket.interp_socket import converted_error, W_RSocket from pypy.rlib import rsocket from pypy.rlib.rsocket import SocketError -from pypy.rlib.rarithmetic import r_uint -from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import OperationError def gethostname(space): """gethostname() -> string diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -1,7 +1,7 @@ from __future__ import with_statement from pypy.rpython.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError -from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -11,7 +11,6 @@ from pypy.module._socket import interp_socket -import sys ## user defined constants X509_NAME_MAXLEN = 256 @@ -131,13 +130,13 @@ self._issuer = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN, flavor='raw') self._issuer[0] = '\0' self.shutdown_seen_zero = False - + def server(self): return self.space.wrap(rffi.charp2str(self._server)) - + def issuer(self): return self.space.wrap(rffi.charp2str(self._issuer)) - + def __del__(self): if self.peer_cert: libssl_X509_free(self.peer_cert) @@ -147,7 +146,7 @@ libssl_SSL_CTX_free(self.ctx) lltype.free(self._server, flavor='raw') lltype.free(self._issuer, flavor='raw') - + @unwrap_spec(data='bufferstr') def write(self, data): """write(s) -> len @@ -230,10 +229,10 @@ raw_buf, gc_buf = rffi.alloc_buffer(num_bytes) while True: err = 0 - + count = libssl_SSL_read(self.ssl, raw_buf, num_bytes) err = libssl_SSL_get_error(self.ssl, count) - + if err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout(self.space, self.w_socket, False) @@ -245,17 +244,17 @@ return self.space.wrap("") else: sockstate = SOCKET_OPERATION_OK - + if sockstate == SOCKET_HAS_TIMED_OUT: raise ssl_error(self.space, "The read operation timed out") elif sockstate == SOCKET_IS_NONBLOCKING: break - + if err == SSL_ERROR_WANT_READ or err == SSL_ERROR_WANT_WRITE: continue else: break - + if count <= 0: raise _ssl_seterror(self.space, self, count) @@ -351,7 +350,7 @@ self.shutdown_seen_zero = True continue - # Possibly retry shutdown until timeout or failure + # Possibly retry shutdown until timeout or failure ssl_err = libssl_SSL_get_error(self.ssl, ret) if ssl_err == SSL_ERROR_WANT_READ: sockstate = check_socket_and_wait_for_timeout( @@ -397,7 +396,7 @@ else: w_proto = space.w_None - bits = libssl_SSL_CIPHER_get_bits(current, + bits = libssl_SSL_CIPHER_get_bits(current, lltype.nullptr(rffi.INTP.TO)) w_bits = space.newint(bits) @@ -552,7 +551,7 @@ ext = libssl_X509_get_ext(certificate, i) method = libssl_X509V3_EXT_get(ext) if not method: - raise ssl_error(space, + raise ssl_error(space, "No method for internalizing subjectAltName!'") with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr: @@ -858,7 +857,7 @@ cert = libssl_BIO_new(libssl_BIO_s_file()) if not cert: raise ssl_error(space, "Can't malloc memory to read file") - + try: if libssl_BIO_read_filename(cert, filename) <= 0: raise ssl_error(space, "Can't open file") @@ -873,7 +872,7 @@ libssl_X509_free(x) finally: libssl_BIO_free(cert) - + # this function is needed to perform locking on shared data # structures. (Note that OpenSSL uses a number of global data # structures that will be implicitly shared whenever multiple threads diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py --- a/pypy/module/_stackless/interp_coroutine.py +++ b/pypy/module/_stackless/interp_coroutine.py @@ -15,13 +15,10 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import StaticMethod from pypy.module._stackless.stackless_flags import StacklessFlags from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit @@ -38,9 +35,9 @@ self.costate = costate if not space.is_true(space.callable(w_obj)): raise operationerrfmt( - space.w_TypeError, + space.w_TypeError, "'%s' object is not callable", - space.type(w_obj).getname(space, '?')) + space.type(w_obj).getname(space)) self.w_func = w_obj self.args = args @@ -65,7 +62,7 @@ # Should be moved to interp_stackless.py if it's ever implemented... Currently # used by pypy/lib/stackless.py. -W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, +W_TaskletExit = _new_exception('TaskletExit', W_SystemExit, """Tasklet killed manually.""") class AppCoroutine(Coroutine): # XXX, StacklessFlags): @@ -90,7 +87,7 @@ def _get_state(space): return space.fromcache(AppCoState) _get_state = staticmethod(_get_state) - + def w_bind(self, w_func, __args__): space = self.space if self.frame is not None: @@ -127,7 +124,7 @@ w_excvalue = operror.get_w_value(space) w_exctraceback = operror.get_traceback() w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback]) - + if w_exctype is self.costate.w_CoroutineExit: self.coroutine_exit = True else: @@ -146,22 +143,22 @@ def w_kill(self): self.kill() - + def w_throw(self, w_type, w_value=None, w_traceback=None): space = self.space operror = OperationError(w_type, w_value) operror.normalize_exception(space) - + if not space.is_w(w_traceback, space.w_None): from pypy.interpreter import pytraceback tb = space.interpclass_w(w_traceback) - if tb is None or not space.is_true(space.isinstance(tb, + if tb is None or not space.is_true(space.isinstance(tb, space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("throw: arg 3 must be a traceback or None")) operror.set_traceback(tb) - + self._kill(operror) def _userdel(self): @@ -280,7 +277,7 @@ assert isinstance(w_klass, W_TypeObject) old_flag = w_klass.flag_heaptype w_klass.flag_heaptype = True - + space.appexec([w_klass, space.wrap(funcname)], """ (klass, funcname): func = getattr(klass, funcname) @@ -332,23 +329,23 @@ # Exporting new exception to space self.w_CoroutineExit = space.gettypefor(W_CoroutineExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('CoroutineExit'), - self.w_CoroutineExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('CoroutineExit'), + space.exceptions_module.w_dict, + space.new_interned_str('CoroutineExit'), self.w_CoroutineExit) - + space.setitem(space.builtin.w_dict, + space.new_interned_str('CoroutineExit'), + self.w_CoroutineExit) + # Should be moved to interp_stackless.py if it's ever implemented... self.w_TaskletExit = space.gettypefor(W_TaskletExit) space.setitem( - space.exceptions_module.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - space.setitem(space.builtin.w_dict, - space.new_interned_str('TaskletExit'), - self.w_TaskletExit) - + space.exceptions_module.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + space.setitem(space.builtin.w_dict, + space.new_interned_str('TaskletExit'), + self.w_TaskletExit) + def post_install(self): self.current = self.main = AppCoroutine(self.space, state=self) self.main.subctx.clear_framestack() # wack @@ -378,7 +375,7 @@ instr = frame.last_instr opcode = ord(code[instr]) map = pythonopcode.opmap - call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], + call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']] assert opcode in call_ops instr += 1 diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py --- a/pypy/module/_stackless/interp_stackless.py +++ b/pypy/module/_stackless/interp_stackless.py @@ -1,9 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError -from pypy.rlib.rarithmetic import intmask import os diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py --- a/pypy/module/_stackless/rclonable.py +++ b/pypy/module/_stackless/rclonable.py @@ -1,7 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.rlib.objectmodel import we_are_translated -from pypy.interpreter.error import OperationError class InterpClonableMixin: @@ -76,7 +75,7 @@ if not isinstance(current, InterpClonableCoroutine): raise RuntimeError("fork() in a non-clonable coroutine") thunk = ForkThunk(current) - coro_fork = InterpClonableCoroutine() + coro_fork = InterpClonableCoroutine() coro_fork.bind(thunk) coro_fork.switch() # we resume here twice. The following would need explanations about diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,16 +1,15 @@ import py -from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.interpreter.typedef import GetSetProperty, TypeDef +from pypy.interpreter.typedef import TypeDef from pypy.rlib import jit import weakref class WeakrefLifeline(W_Root): def __init__(self, space): - self.space = space # this is here for W_Root.clear_all_weakrefs() + self.space = space self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 @@ -23,8 +22,10 @@ """ for i in range(len(self.refs_weak) - 1, -1, -1): w_ref = self.refs_weak[i]() - if w_ref is not None: - self.space.user_del_action.register_weakref_callback(w_ref) + if w_ref is not None and w_ref.w_callable is not None: + w_ref.enqueue_for_destruction(self.space, + W_WeakrefBase.activate_callback, + 'weakref callback of ') def clear_all_weakrefs(self): """Clear all weakrefs. This is called when an app-level object has @@ -118,18 +119,15 @@ self.w_obj_weak = dead_ref def activate_callback(w_self): - if not w_self.w_callable is None: - try: - w_self.space.call_function(w_self.w_callable, w_self) - except OperationError, e: - e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable) + assert isinstance(w_self, W_WeakrefBase) + w_self.space.call_function(w_self.w_callable, w_self) def descr__repr__(self, space): w_obj = self.dereference() if w_obj is None: state = '; dead' else: - typename = space.type(w_obj).getname(space, '?') + typename = space.type(w_obj).getname(space) objname = w_obj.getname(space, '') if objname: state = "; to '%s' (%s)" % (typename, objname) diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -1,6 +1,5 @@ from __future__ import with_statement from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.error import OperationError, wrap_windowserror diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -1,18 +1,20 @@ from __future__ import with_statement +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError -from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr -from pypy.rpython.lltypesystem import lltype, rffi from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.rarithmetic import ovfcheck -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr +from pypy.module._file.interp_file import W_File +from pypy.objspace.std.model import W_Object +from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import SMM, StdTypeDef from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.model import W_Object -from pypy.module._file.interp_file import W_File -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib.unroll import unrolling_iterable +from pypy.rpython.lltypesystem import lltype, rffi + + +memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): @@ -37,7 +39,7 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(w_initializer) + a.fromstring(space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_unicode: a.fromsequence(w_initializer) elif space.type(w_initializer) is space.w_list: @@ -73,6 +75,7 @@ array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) +array_copy = SMM('__copy__', 1) array_byteswap = SMM('byteswap', 1) @@ -96,7 +99,7 @@ itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), - ) +) W_ArrayBase.typedef.registermethods(globals()) @@ -159,8 +162,6 @@ self.data[index] = char - - def make_array(mytype): class W_Array(W_ArrayBase): itemsize = mytype.bytes @@ -268,12 +269,10 @@ raise self.setlen(oldlen + i) - def fromstring(self, w_s): - space = self.space - s = space.str_w(w_s) + def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) @@ -311,6 +310,14 @@ def charbuf(self): return rffi.cast(rffi.CCHARP, self.buffer) + def w_getitem(self, space, idx): + item = self.buffer[idx] + if mytype.typecode in 'bBhHil': + item = rffi.cast(lltype.Signed, item) + elif mytype.typecode == 'f': + item = float(item) + return space.wrap(item) + # Basic get/set/append/extend methods def len__Array(space, self): @@ -319,12 +326,7 @@ def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 - item = self.buffer[idx] - if mytype.typecode in 'bBhHil': - item = rffi.cast(lltype.Signed, item) - elif mytype.typecode == 'f': - item = float(item) - return self.space.wrap(item) + return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) @@ -387,7 +389,7 @@ def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) @@ -395,7 +397,7 @@ def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): - w_item = getitem__Array_ANY(space, self, space.wrap(i)) + w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' @@ -413,7 +415,7 @@ if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = getitem__Array_ANY(space, self, space.wrap(i)) + w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 @@ -515,14 +517,14 @@ def array_tolist__Array(space, self): w_l = space.newlist([]) for i in range(self.len): - w_l.append(getitem__Array_ANY(space, self, space.wrap(i))) + w_l.append(self.w_getitem(space, i)) return w_l def array_fromlist__Array_List(space, self, w_lst): self.fromlist(w_lst) def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(w_s) + self.fromstring(space.str_w(w_s)) def array_tostring__Array(space, self): cbuf = self.charbuf() @@ -569,10 +571,7 @@ self.fromsequence(w_ustr) def array_tounicode__Array(space, self): - u = u"" - for i in range(self.len): - u += self.buffer[i] - return space.wrap(u) + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) else: def array_fromunicode__Array_Unicode(space, self, w_ustr): @@ -615,6 +614,16 @@ dct = space.w_None return space.newtuple([space.type(self), space.newtuple(args), dct]) + def array_copy__Array(space, self): + w_a = mytype.w_class(self.space) + w_a.setlen(self.len) + memcpy( + rffi.cast(rffi.VOIDP, w_a.buffer), + rffi.cast(rffi.VOIDP, self.buffer), + self.len * mytype.bytes + ) From noreply at buildbot.pypy.org Wed Jul 27 18:22:49 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 18:22:49 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Starts to look good, but tests are still failing. Message-ID: <20110727162249.E53C282110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r46020:3c87c9250799 Date: 2011-07-27 18:22 +0200 http://bitbucket.org/pypy/pypy/changeset/3c87c9250799/ Log: Starts to look good, but tests are still failing. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -6,7 +6,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.tool.algo.regalloc import perform_register_allocation from pypy.translator.backendopt.ssa import DataFlowFamilyBuilder -from pypy.translator.unsimplify import copyvar +from pypy.translator.unsimplify import copyvar, insert_empty_block from pypy.objspace.flow.model import Block, Link, Constant from pypy.objspace.flow.model import checkgraph, mkentrymap from pypy.annotation import model as annmodel @@ -235,7 +235,7 @@ added in this complete graph, and replace them with real operations. """ # - # Use the SSA builder to find "spans" of variables that come a + # Use the SSA builder to find "spans" of variables that come from a # single point but may extend over several blocks. spans = DataFlowFamilyBuilder(graph).get_variable_families() interesting_vars = set() @@ -243,10 +243,14 @@ for op in block.operations: if op.opname in ('gc_push_roots', 'gc_pop_roots'): for v in op.args: + if isinstance(v, Constant): + continue interesting_vars.add(spans.find_rep(v)) if not interesting_vars: return # + # --------------------------------------------------- + # def is_interesting(v): return spans.find_rep(v) in interesting_vars regalloc = perform_register_allocation(graph, is_interesting) @@ -259,6 +263,8 @@ # # We replace gc_push_roots/gc_pop_roots with individual # operations raw_store/raw_load + blocks_push_roots = {} # {block: index-of-the-first} + blocks_pop_roots = {} # {block: index-just-after-the-last} negnumcolors = 0 c_type = rmodel.inputconst(lltype.Void, llmemory.Address) for block in graph.iterblocks(): @@ -269,12 +275,16 @@ if op.opname not in ("gc_push_roots", "gc_pop_roots"): llops.append(op) continue - top_addr = llops.genop("direct_call", - [gct.get_stack_top_ptr], - resulttype=llmemory.Address) + top_addr = None for v in op.args: if isinstance(v, Constant): continue + if op.opname == "gc_push_roots": + blocks_push_roots.setdefault(block, len(llops)) + if top_addr is None: + top_addr = llops.genop("direct_call", + [gct.get_stack_top_ptr], + resulttype=llmemory.Address) k = ~regalloc.getcolor(v) negnumcolors = min(negnumcolors, k) c_k = rmodel.inputconst(lltype.Signed, k) @@ -287,36 +297,119 @@ [top_addr, c_type, c_k], resulttype=llmemory.Address) llops.genop("gc_reload_possibly_moved", [v_newaddr, v]) + blocks_pop_roots[block] = len(llops) block.operations[:] = llops - # - # Put at the start of the graph: "incr_stack(); fill with zeroes" - llops = LowLevelOpList() numcolors = -negnumcolors c_numcolors = rmodel.inputconst(lltype.Signed, numcolors) - llops.genop("direct_call", [gct.incr_stack_ptr, c_numcolors], - resulttype=llmemory.Address) - top_addr = llops.genop("direct_call", - [gct.get_stack_top_ptr], - resulttype=llmemory.Address) - c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL) - for k in range(numcolors): - c_k = rmodel.inputconst(lltype.Signed, ~k) - llops.genop("raw_store", [top_addr, c_type, c_k, c_null]) - graph.startblock.operations[:0] = llops # - # Put at the end of the graph: "decr_stack()" - llops = LowLevelOpList() - llops.genop("direct_call", [gct.decr_stack_ptr, c_numcolors], - resulttype=llmemory.Address) - block = graph.returnblock - block.operations = list(llops) - [v_return] = block.inputargs - v_return2 = copyvar(gct.translator.annotator, v_return) - newexitblock = Block([v_return2]) - newexitblock.operations = () - newexitblock.exits = () - block.recloseblock(Link([v_return], newexitblock)) - graph.returnblock = newexitblock + # For each block, determine in which category it is: + # + # - dead: the block does not contain any gc_push_roots/gc_pop_roots + # and is not between two non-dead blocks + # + # - start: the block contains gc_push_roots, and all blocks + # leading to it are dead + # + # - stop: the block contains gc_pop_roots, and all blocks it + # goes to are dead + # + # - startstop: the block is both starting and stopping + # + # - alive: all other blocks + # + # The idea is to delay "incr_stack()" because sometimes the function + # has fast paths that don't call anything else. Also, it is important + # to delay it for functions that start without having the GIL, and only + # acquire it as they progress. + # + # Note that it is possible to transition directly from "dead" to + # "alive" or back; some graphs may not have any "start" or "stop" + # blocks. + # + blockstate = {} + push_roots_and_down = self.close_downwards(graph, blocks_push_roots) + pop_roots_and_up = self.close_upwards(graph, blocks_pop_roots) + assert push_roots_and_down.issuperset(blocks_pop_roots) + assert pop_roots_and_up.issuperset(blocks_push_roots) + # dead blocks are the ones that are not in both sets at once + non_dead_blocks = set() + for block in graph.iterblocks(): + if block in push_roots_and_down and block in pop_roots_and_up: + non_dead_blocks.add(block) + else: + blockstate[block] = "dead" + # + entrymap = mkentrymap(graph) + for block in blocks_push_roots: + for link in entrymap[block]: + if link.prevblock in non_dead_blocks: + break + else: + assert block not in blockstate + blockstate[block] = "start" + for block in blocks_pop_roots: + for link in block.exits: + if link.target in non_dead_blocks: + break + else: + prev = blockstate.get(block, "") + assert prev in ("", "start") + blockstate[block] = prev + "stop" + # + for block in graph.iterblocks(): + blockstate.setdefault(block, "alive") + # + # If graph.startblock is "alive", then we need a new startblock + # in which to put the "incr_stack()" operation later + if blockstate[graph.startblock] == "alive": + insert_empty_startblock(gct.translator.annotator, graph) + blocks_push_roots[graph.startblock] = 0 + blockstate[graph.startblock] = "start" + # + # Now detect direct transitions from "dead" to "alive", and + # insert new "start" blocks along the links. Similarly, detect + # direct transitions from "alive" to "dead" and put a "stop" block. + for block in blockstate.keys(): + if blockstate[block] == "dead": + for link in block.exits: + if blockstate[link.target] == "alive": + newblock = insert_empty_block(gct.translator.annotator, + link) + blocks_push_roots[newblock] = 0 + blockstate[newblock] = "start" + if blockstate[block] == "alive": + for link in block.exits: + if blockstate[link.target] == "dead": + newblock = insert_empty_block(gct.translator.annotator, + link) + blocks_pop_roots[newblock] = 0 + blockstate[newblock] = "stop" + # + # Now we can put "incr_stack(); fill with zeroes" in all "start" + # blocks; similarly, we put "decr_stack()" in all "stop" blocks. + for block in blockstate: + if "stop" in blockstate[block]: # "stop" or "startstop" + llops = LowLevelOpList() + llops.genop("direct_call", [gct.decr_stack_ptr, c_numcolors], + resulttype=llmemory.Address) + i = blocks_pop_roots[block] + block.operations[i:i] = llops + # ^^^ important: done first, in case it's a startstop block, + # otherwise the index in 'blocks_push_roots[block]' is + # off by one + if "start" in blockstate[block]: # "start" or "startstop" + llops = LowLevelOpList() + llops.genop("direct_call", [gct.incr_stack_ptr, c_numcolors], + resulttype=llmemory.Address) + top_addr = llops.genop("direct_call", + [gct.get_stack_top_ptr], + resulttype=llmemory.Address) + c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL) + for k in range(numcolors): + c_k = rmodel.inputconst(lltype.Signed, ~k) + llops.genop("raw_store", [top_addr, c_type, c_k, c_null]) + i = blocks_push_roots[block] + block.operations[i:i] = llops # checkgraph(graph) @@ -378,3 +471,29 @@ useless[block, op, v] = True gct.num_raw_store_avoided += 1 return useless + + + def close_downwards(self, graph, blockset): + blockset = set(blockset) + pending = list(blockset) + while pending: + block1 = pending.pop() + for link in block1.exits: + block2 = link.target + if block2 not in blockset: + blockset.add(block2) + pending.append(block2) + return blockset + + def close_upwards(self, graph, blockset): + blockset = set(blockset) + pending = list(blockset) + entrymap = mkentrymap(graph) + while pending: + block1 = pending.pop() + for link in entrymap[block1]: + block2 = link.prevblock + if block2 and block2 not in blockset: + blockset.add(block2) + pending.append(block2) + return blockset From noreply at buildbot.pypy.org Wed Jul 27 18:42:58 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 18:42:58 +0200 (CEST) Subject: [pypy-commit] pypy default: special case the type "pointer to char", and allow automatic conversion of strings to it Message-ID: <20110727164258.3596A82110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46021:d342648fe99a Date: 2011-07-27 18:33 +0200 http://bitbucket.org/pypy/pypy/changeset/d342648fe99a/ Log: special case the type "pointer to char", and allow automatic conversion of strings to it diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -74,6 +74,9 @@ def is_struct(self): return libffi.types.is_struct(self.ffitype) + def is_char_p(self): + return self is app_types.char_p + W_FFIType.typedef = TypeDef( 'FFIType', __repr__ = interp2app(W_FFIType.repr), @@ -115,7 +118,10 @@ ## 'Z' : ffi_type_pointer, ] - return dict([(t.name, t) for t in types]) + d = dict([(t.name, t) for t in types]) + w_char = d['char'] + d['char_p'] = W_FFIType('char_p', libffi.types.pointer, w_pointer_to = w_char) + return d class app_types: pass @@ -125,9 +131,12 @@ try: return descr_new_pointer.cache[w_pointer_to] except KeyError: - w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) - name = '(pointer to %s)' % w_pointer_to.name - w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to) + if w_pointer_to is app_types.char: + w_result = app_types.char_p + else: + w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) + name = '(pointer to %s)' % w_pointer_to.name + w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to) descr_new_pointer.cache[w_pointer_to] = w_result return w_result descr_new_pointer.cache = {} @@ -178,6 +187,8 @@ self.func.name, expected, arg, given) # argchain = libffi.ArgChain() + to_free = [] # list of automatically malloc()ed buffers that needs to + # be freed after the call for i in range(expected): w_argtype = self.argtypes_w[i] w_arg = args_w[i] @@ -188,6 +199,9 @@ self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) + elif self.add_char_p_maybe(space, argchain, to_free, w_arg, w_argtype): + # the argument is added to the argchain direcly by the method above + pass elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) @@ -210,7 +224,22 @@ argchain.arg_raw(ptrval) else: assert False, "Argument shape '%s' not supported" % w_argtype - return argchain + return argchain, to_free + + def add_char_p_maybe(self, space, argchain, to_free, w_arg, w_argtype): + """ + Automatic conversion from string to char_p. The allocated buffer will + be automatically freed after the call. + """ + w_type = jit.promote(space.type(w_arg)) + if w_argtype.is_char_p() and w_type is space.w_str: + strval = space.str_w(w_arg) + buf = rffi.str2charp(strval) + to_free.append(buf) + addr = rffi.cast(rffi.ULONG, buf) + argchain.arg(addr) + return True + return False def convert_pointer_arg_maybe(self, space, w_arg, w_argtype): """ @@ -234,7 +263,14 @@ def call(self, space, args_w): self = jit.promote(self) - argchain = self.build_argchain(space, args_w) + argchain, to_free = self.build_argchain(space, args_w) + try: + return self._do_call(space, argchain) + finally: + for buf in to_free: + lltype.free(buf, flavor='raw') + + def _do_call(self, space, argchain): w_restype = self.w_restype if w_restype.is_longlong(): # note that we must check for longlong first, because either diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -188,6 +188,29 @@ assert get_dummy() == 123 set_val_to_ptr(ptr2, 0) + def test_convert_strings_to_char_str_p(self): + """ + long mystrlen(char* s) + { + long len = 0; + while(*s++) + len++; + return len; + } + """ + from _ffi import CDLL, types + import _rawffi + libfoo = CDLL(self.libfoo_name) + mystrlen = libfoo.getfunc('mystrlen', [types.char_p], types.slong) + # + # first, try automatic conversion from a string + assert mystrlen('foobar') == 6 + # then, try to pass an explicit pointer + CharArray = _rawffi.Array('c') + mystr = CharArray(7, 'foobar') + assert mystrlen(mystr.buffer) == 6 + mystr.free() + def test_typed_pointer(self): from _ffi import types intptr = types.Pointer(types.sint) # create a typed pointer to sint @@ -204,6 +227,11 @@ assert x is y assert x is not z + def test_char_p_cached(self): + from _ffi import types + x = types.Pointer(types.char) + assert x is types.char_p + def test_typed_pointer_args(self): """ extern int dummy; // defined in test_void_result From noreply at buildbot.pypy.org Wed Jul 27 18:42:59 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 18:42:59 +0200 (CEST) Subject: [pypy-commit] pypy default: also support automatic conversion of unicode to unichar_p Message-ID: <20110727164259.66E9382110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46022:fe819dcd9aa2 Date: 2011-07-27 18:42 +0200 http://bitbucket.org/pypy/pypy/changeset/fe819dcd9aa2/ Log: also support automatic conversion of unicode to unichar_p diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -77,6 +77,10 @@ def is_char_p(self): return self is app_types.char_p + def is_unichar_p(self): + return self is app_types.unichar_p + + W_FFIType.typedef = TypeDef( 'FFIType', __repr__ = interp2app(W_FFIType.repr), @@ -120,7 +124,9 @@ ] d = dict([(t.name, t) for t in types]) w_char = d['char'] + w_unichar = d['unichar'] d['char_p'] = W_FFIType('char_p', libffi.types.pointer, w_pointer_to = w_char) + d['unichar_p'] = W_FFIType('unichar_p', libffi.types.pointer, w_pointer_to = w_unichar) return d class app_types: @@ -133,6 +139,8 @@ except KeyError: if w_pointer_to is app_types.char: w_result = app_types.char_p + elif w_pointer_to is app_types.unichar: + w_result = app_types.unichar_p else: w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) name = '(pointer to %s)' % w_pointer_to.name @@ -239,6 +247,14 @@ addr = rffi.cast(rffi.ULONG, buf) argchain.arg(addr) return True + elif w_argtype.is_unichar_p() and (w_type is space.w_str or + w_type is space.w_unicode): + unicodeval = space.unicode_w(w_arg) + buf = rffi.unicode2wcharp(unicodeval) + to_free.append(buf) + addr = rffi.cast(rffi.ULONG, buf) + argchain.arg(addr) + return True return False def convert_pointer_arg_maybe(self, space, w_arg, w_argtype): diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -188,7 +188,7 @@ assert get_dummy() == 123 set_val_to_ptr(ptr2, 0) - def test_convert_strings_to_char_str_p(self): + def test_convert_strings_to_char_p(self): """ long mystrlen(char* s) { @@ -211,6 +211,31 @@ assert mystrlen(mystr.buffer) == 6 mystr.free() + def test_convert_unicode_to_unichar_p(self): + """ + #include + long mystrlen_u(wchar_t* s) + { + long len = 0; + while(*s++) + len++; + return len; + } + """ + from _ffi import CDLL, types + import _rawffi + libfoo = CDLL(self.libfoo_name) + mystrlen = libfoo.getfunc('mystrlen_u', [types.unichar_p], types.slong) + # + # first, try automatic conversion from strings and unicode + assert mystrlen('foobar') == 6 + assert mystrlen(u'foobar') == 6 + # then, try to pass an explicit pointer + UniCharArray = _rawffi.Array('u') + mystr = UniCharArray(7, u'foobar') + assert mystrlen(mystr.buffer) == 6 + mystr.free() + def test_typed_pointer(self): from _ffi import types intptr = types.Pointer(types.sint) # create a typed pointer to sint @@ -231,6 +256,8 @@ from _ffi import types x = types.Pointer(types.char) assert x is types.char_p + x = types.Pointer(types.unichar) + assert x is types.unichar_p def test_typed_pointer_args(self): """ From noreply at buildbot.pypy.org Wed Jul 27 18:43:00 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 18:43:00 +0200 (CEST) Subject: [pypy-commit] pypy default: merge default Message-ID: <20110727164300.A3DA582110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46023:a5b76d2cd38c Date: 2011-07-27 18:43 +0200 http://bitbucket.org/pypy/pypy/changeset/a5b76d2cd38c/ Log: merge default diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -1,129 +1,8 @@ -import sys -from pypy.objspace.flow.model import Variable -from pypy.tool.algo.color import DependencyGraph -from pypy.tool.algo.unionfind import UnionFind +from pypy.tool.algo import regalloc from pypy.jit.metainterp.history import getkind from pypy.jit.codewriter.flatten import ListOfKind + def perform_register_allocation(graph, kind): - """Perform register allocation for the Variables of the given 'kind' - in the 'graph'.""" - regalloc = RegAllocator(graph, kind) - regalloc.make_dependencies() - regalloc.coalesce_variables() - regalloc.find_node_coloring() - return regalloc - - -class RegAllocator(object): - DEBUG_REGALLOC = False - - def __init__(self, graph, kind): - self.graph = graph - self.kind = kind - - def make_dependencies(self): - dg = DependencyGraph() - for block in self.graph.iterblocks(): - # Compute die_at = {Variable: index_of_operation_with_last_usage} - die_at = dict.fromkeys(block.inputargs, 0) - for i, op in enumerate(block.operations): - for v in op.args: - if isinstance(v, Variable): - die_at[v] = i - elif isinstance(v, ListOfKind): - for v1 in v: - if isinstance(v1, Variable): - die_at[v1] = i - if op.result is not None: - die_at[op.result] = i + 1 - if isinstance(block.exitswitch, tuple): - for x in block.exitswitch: - die_at.pop(x, None) - else: - die_at.pop(block.exitswitch, None) - for link in block.exits: - for v in link.args: - die_at.pop(v, None) - die_at = [(value, key) for (key, value) in die_at.items()] - die_at.sort() - die_at.append((sys.maxint,)) - # Done. XXX the code above this line runs 3 times - # (for kind in KINDS) to produce the same result... - livevars = [v for v in block.inputargs - if getkind(v.concretetype) == self.kind] - # Add the variables of this block to the dependency graph - for i, v in enumerate(livevars): - dg.add_node(v) - for j in range(i): - dg.add_edge(livevars[j], v) - livevars = set(livevars) - die_index = 0 - for i, op in enumerate(block.operations): - while die_at[die_index][0] == i: - try: - livevars.remove(die_at[die_index][1]) - except KeyError: - pass - die_index += 1 - if (op.result is not None and - getkind(op.result.concretetype) == self.kind): - dg.add_node(op.result) - for v in livevars: - if getkind(v.concretetype) == self.kind: - dg.add_edge(v, op.result) - livevars.add(op.result) - self._depgraph = dg - - def coalesce_variables(self): - self._unionfind = UnionFind() - pendingblocks = list(self.graph.iterblocks()) - while pendingblocks: - block = pendingblocks.pop() - # Aggressively try to coalesce each source variable with its - # target. We start from the end of the graph instead of - # from the beginning. This is a bit arbitrary, but the idea - # is that the end of the graph runs typically more often - # than the start, given that we resume execution from the - # middle during blackholing. - for link in block.exits: - if link.last_exception is not None: - self._depgraph.add_node(link.last_exception) - if link.last_exc_value is not None: - self._depgraph.add_node(link.last_exc_value) - for i, v in enumerate(link.args): - self._try_coalesce(v, link.target.inputargs[i]) - - def _try_coalesce(self, v, w): - if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: - assert getkind(w.concretetype) == self.kind - dg = self._depgraph - uf = self._unionfind - v0 = uf.find_rep(v) - w0 = uf.find_rep(w) - if v0 is not w0 and v0 not in dg.neighbours[w0]: - _, rep, _ = uf.union(v0, w0) - assert uf.find_rep(v0) is uf.find_rep(w0) is rep - if rep is v0: - dg.coalesce(w0, v0) - else: - assert rep is w0 - dg.coalesce(v0, w0) - - def find_node_coloring(self): - self._coloring = self._depgraph.find_node_coloring() - if self.DEBUG_REGALLOC: - for block in self.graph.iterblocks(): - print block - for v in block.getvariables(): - print '\t', v, '\t', self.getcolor(v) - - def getcolor(self, v): - return self._coloring[self._unionfind.find_rep(v)] - - def swapcolors(self, col1, col2): - for key, value in self._coloring.items(): - if value == col1: - self._coloring[key] = col2 - elif value == col2: - self._coloring[key] = col1 + checkkind = lambda v: getkind(v.concretetype) == kind + return regalloc.perform_register_allocation(graph, checkkind, ListOfKind) diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -525,7 +525,8 @@ self.c_vtinfo_skip_offset = rmodel.inputconst(lltype.typeOf(sko), sko) def build_root_walker(self): - return ShadowStackRootWalker(self) + from pypy.rpython.memory.gctransform import shadowstack + return shadowstack.ShadowStackRootWalker(self) def consider_constant(self, TYPE, value): self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc) @@ -1323,217 +1324,3 @@ def need_thread_support(self, gctransformer, getfn): raise Exception("%s does not support threads" % ( self.__class__.__name__,)) - - -class ShadowStackRootWalker(BaseRootWalker): - need_root_stack = True - collect_stacks_from_other_threads = None - - def __init__(self, gctransformer): - BaseRootWalker.__init__(self, gctransformer) - self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth - # NB. 'self' is frozen, but we can use self.gcdata to store state - gcdata = self.gcdata - - def incr_stack(n): - top = gcdata.root_stack_top - gcdata.root_stack_top = top + n*sizeofaddr - return top - self.incr_stack = incr_stack - - def decr_stack(n): - top = gcdata.root_stack_top - n*sizeofaddr - gcdata.root_stack_top = top - return top - self.decr_stack = decr_stack - - self.rootstackhook = gctransformer.root_stack_jit_hook - if self.rootstackhook is None: - def collect_stack_root(callback, gc, addr): - if gc.points_to_valid_gc_object(addr): - callback(gc, addr) - return sizeofaddr - self.rootstackhook = collect_stack_root - - def push_stack(self, addr): - top = self.incr_stack(1) - top.address[0] = addr - - def pop_stack(self): - top = self.decr_stack(1) - return top.address[0] - - def allocate_stack(self): - return llmemory.raw_malloc(self.rootstacksize) - - def setup_root_walker(self): - stackbase = self.allocate_stack() - ll_assert(bool(stackbase), "could not allocate root stack") - self.gcdata.root_stack_top = stackbase - self.gcdata.root_stack_base = stackbase - BaseRootWalker.setup_root_walker(self) - - def walk_stack_roots(self, collect_stack_root): - gcdata = self.gcdata - gc = self.gc - rootstackhook = self.rootstackhook - addr = gcdata.root_stack_base - end = gcdata.root_stack_top - while addr != end: - addr += rootstackhook(collect_stack_root, gc, addr) - if self.collect_stacks_from_other_threads is not None: - self.collect_stacks_from_other_threads(collect_stack_root) - - def need_thread_support(self, gctransformer, getfn): - from pypy.module.thread import ll_thread # xxx fish - from pypy.rpython.memory.support import AddressDict - from pypy.rpython.memory.support import copy_without_null_values - gcdata = self.gcdata - # the interfacing between the threads and the GC is done via - # three completely ad-hoc operations at the moment: - # gc_thread_prepare, gc_thread_run, gc_thread_die. - # See docstrings below. - - def get_aid(): - """Return the thread identifier, cast to an (opaque) address.""" - return llmemory.cast_int_to_adr(ll_thread.get_ident()) - - def thread_setup(): - """Called once when the program starts.""" - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} - gcdata._fresh_rootstack = llmemory.NULL - gcdata.dead_threads_count = 0 - - def thread_prepare(): - """Called just before thread.start_new_thread(). This - allocates a new shadow stack to be used by the future - thread. If memory runs out, this raises a MemoryError - (which can be handled by the caller instead of just getting - ignored if it was raised in the newly starting thread). - """ - if not gcdata._fresh_rootstack: - gcdata._fresh_rootstack = self.allocate_stack() - if not gcdata._fresh_rootstack: - raise MemoryError - - def thread_run(): - """Called whenever the current thread (re-)acquired the GIL. - This should ensure that the shadow stack installed in - gcdata.root_stack_top/root_stack_base is the one corresponding - to the current thread. - """ - aid = get_aid() - if gcdata.active_thread != aid: - switch_shadow_stacks(aid) - - def thread_die(): - """Called just before the final GIL release done by a dying - thread. After a thread_die(), no more gc operation should - occur in this thread. - """ - aid = get_aid() - if aid == gcdata.main_thread: - return # ignore calls to thread_die() in the main thread - # (which can occur after a fork()). - gcdata.thread_stacks.setitem(aid, llmemory.NULL) - old = gcdata.root_stack_base - if gcdata._fresh_rootstack == llmemory.NULL: - gcdata._fresh_rootstack = old - else: - llmemory.raw_free(old) - install_new_stack(gcdata.main_thread) - # from time to time, rehash the dictionary to remove - # old NULL entries - gcdata.dead_threads_count += 1 - if (gcdata.dead_threads_count & 511) == 0: - copy = copy_without_null_values(gcdata.thread_stacks) - gcdata.thread_stacks.delete() - gcdata.thread_stacks = copy - - def switch_shadow_stacks(new_aid): - save_away_current_stack() - install_new_stack(new_aid) - switch_shadow_stacks._dont_inline_ = True - - def save_away_current_stack(): - old_aid = gcdata.active_thread - # save root_stack_base on the top of the stack - self.push_stack(gcdata.root_stack_base) - # store root_stack_top into the dictionary - gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) - - def install_new_stack(new_aid): - # look for the new stack top - top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) - if top == llmemory.NULL: - # first time we see this thread. It is an error if no - # fresh new stack is waiting. - base = gcdata._fresh_rootstack - gcdata._fresh_rootstack = llmemory.NULL - ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") - gcdata.root_stack_top = base - gcdata.root_stack_base = base - else: - # restore the root_stack_base from the top of the stack - gcdata.root_stack_top = top - gcdata.root_stack_base = self.pop_stack() - # done - gcdata.active_thread = new_aid - - def collect_stack(aid, stacktop, callback): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - # collect all valid stacks from the dict (the entry - # corresponding to the current thread is not valid) - gc = self.gc - rootstackhook = self.rootstackhook - end = stacktop - sizeofaddr - addr = end.address[0] - while addr != end: - addr += rootstackhook(callback, gc, addr) - - def collect_more_stacks(callback): - ll_assert(get_aid() == gcdata.active_thread, - "collect_more_stacks(): invalid active_thread") - gcdata.thread_stacks.foreach(collect_stack, callback) - - def _free_if_not_current(aid, stacktop, _): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - end = stacktop - sizeofaddr - base = end.address[0] - llmemory.raw_free(base) - - def thread_after_fork(result_of_fork, opaqueaddr): - # we don't need a thread_before_fork in this case, so - # opaqueaddr == NULL. This is called after fork(). - if result_of_fork == 0: - # We are in the child process. Assumes that only the - # current thread survived, so frees the shadow stacks - # of all the other ones. - gcdata.thread_stacks.foreach(_free_if_not_current, None) - # Clears the dict (including the current thread, which - # was an invalid entry anyway and will be recreated by - # the next call to save_away_current_stack()). - gcdata.thread_stacks.clear() - # Finally, reset the stored thread IDs, in case it - # changed because of fork(). Also change the main - # thread to the current one (because there is not any - # other left). - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - - self.thread_setup = thread_setup - self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) - self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, - inline=True) - # no thread_start_ptr here - self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) - # no thread_before_fork_ptr here - self.thread_after_fork_ptr = getfn(thread_after_fork, - [annmodel.SomeInteger(), - annmodel.SomeAddress()], - annmodel.s_None) - self.collect_stacks_from_other_threads = collect_more_stacks diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py new file mode 100644 --- /dev/null +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -0,0 +1,218 @@ +from pypy.rpython.memory.gctransform.framework import BaseRootWalker +from pypy.rpython.memory.gctransform.framework import sizeofaddr +from pypy.rlib.debug import ll_assert +from pypy.rpython.lltypesystem import llmemory + + +class ShadowStackRootWalker(BaseRootWalker): + need_root_stack = True + collect_stacks_from_other_threads = None + + def __init__(self, gctransformer): + BaseRootWalker.__init__(self, gctransformer) + self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth + # NB. 'self' is frozen, but we can use self.gcdata to store state + gcdata = self.gcdata + + def incr_stack(n): + top = gcdata.root_stack_top + gcdata.root_stack_top = top + n*sizeofaddr + return top + self.incr_stack = incr_stack + + def decr_stack(n): + top = gcdata.root_stack_top - n*sizeofaddr + gcdata.root_stack_top = top + return top + self.decr_stack = decr_stack + + self.rootstackhook = gctransformer.root_stack_jit_hook + if self.rootstackhook is None: + def collect_stack_root(callback, gc, addr): + if gc.points_to_valid_gc_object(addr): + callback(gc, addr) + return sizeofaddr + self.rootstackhook = collect_stack_root + + def push_stack(self, addr): + top = self.incr_stack(1) + top.address[0] = addr + + def pop_stack(self): + top = self.decr_stack(1) + return top.address[0] + + def allocate_stack(self): + return llmemory.raw_malloc(self.rootstacksize) + + def setup_root_walker(self): + stackbase = self.allocate_stack() + ll_assert(bool(stackbase), "could not allocate root stack") + self.gcdata.root_stack_top = stackbase + self.gcdata.root_stack_base = stackbase + BaseRootWalker.setup_root_walker(self) + + def walk_stack_roots(self, collect_stack_root): + gcdata = self.gcdata + gc = self.gc + rootstackhook = self.rootstackhook + addr = gcdata.root_stack_base + end = gcdata.root_stack_top + while addr != end: + addr += rootstackhook(collect_stack_root, gc, addr) + if self.collect_stacks_from_other_threads is not None: + self.collect_stacks_from_other_threads(collect_stack_root) + + def need_thread_support(self, gctransformer, getfn): + from pypy.module.thread import ll_thread # xxx fish + from pypy.rpython.memory.support import AddressDict + from pypy.rpython.memory.support import copy_without_null_values + gcdata = self.gcdata + # the interfacing between the threads and the GC is done via + # three completely ad-hoc operations at the moment: + # gc_thread_prepare, gc_thread_run, gc_thread_die. + # See docstrings below. + + def get_aid(): + """Return the thread identifier, cast to an (opaque) address.""" + return llmemory.cast_int_to_adr(ll_thread.get_ident()) + + def thread_setup(): + """Called once when the program starts.""" + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} + gcdata._fresh_rootstack = llmemory.NULL + gcdata.dead_threads_count = 0 + + def thread_prepare(): + """Called just before thread.start_new_thread(). This + allocates a new shadow stack to be used by the future + thread. If memory runs out, this raises a MemoryError + (which can be handled by the caller instead of just getting + ignored if it was raised in the newly starting thread). + """ + if not gcdata._fresh_rootstack: + gcdata._fresh_rootstack = self.allocate_stack() + if not gcdata._fresh_rootstack: + raise MemoryError + + def thread_run(): + """Called whenever the current thread (re-)acquired the GIL. + This should ensure that the shadow stack installed in + gcdata.root_stack_top/root_stack_base is the one corresponding + to the current thread. + """ + aid = get_aid() + if gcdata.active_thread != aid: + switch_shadow_stacks(aid) + + def thread_die(): + """Called just before the final GIL release done by a dying + thread. After a thread_die(), no more gc operation should + occur in this thread. + """ + aid = get_aid() + if aid == gcdata.main_thread: + return # ignore calls to thread_die() in the main thread + # (which can occur after a fork()). + gcdata.thread_stacks.setitem(aid, llmemory.NULL) + old = gcdata.root_stack_base + if gcdata._fresh_rootstack == llmemory.NULL: + gcdata._fresh_rootstack = old + else: + llmemory.raw_free(old) + install_new_stack(gcdata.main_thread) + # from time to time, rehash the dictionary to remove + # old NULL entries + gcdata.dead_threads_count += 1 + if (gcdata.dead_threads_count & 511) == 0: + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy + + def switch_shadow_stacks(new_aid): + save_away_current_stack() + install_new_stack(new_aid) + switch_shadow_stacks._dont_inline_ = True + + def save_away_current_stack(): + old_aid = gcdata.active_thread + # save root_stack_base on the top of the stack + self.push_stack(gcdata.root_stack_base) + # store root_stack_top into the dictionary + gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) + + def install_new_stack(new_aid): + # look for the new stack top + top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) + if top == llmemory.NULL: + # first time we see this thread. It is an error if no + # fresh new stack is waiting. + base = gcdata._fresh_rootstack + gcdata._fresh_rootstack = llmemory.NULL + ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") + gcdata.root_stack_top = base + gcdata.root_stack_base = base + else: + # restore the root_stack_base from the top of the stack + gcdata.root_stack_top = top + gcdata.root_stack_base = self.pop_stack() + # done + gcdata.active_thread = new_aid + + def collect_stack(aid, stacktop, callback): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + # collect all valid stacks from the dict (the entry + # corresponding to the current thread is not valid) + gc = self.gc + rootstackhook = self.rootstackhook + end = stacktop - sizeofaddr + addr = end.address[0] + while addr != end: + addr += rootstackhook(callback, gc, addr) + + def collect_more_stacks(callback): + ll_assert(get_aid() == gcdata.active_thread, + "collect_more_stacks(): invalid active_thread") + gcdata.thread_stacks.foreach(collect_stack, callback) + + def _free_if_not_current(aid, stacktop, _): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + end = stacktop - sizeofaddr + base = end.address[0] + llmemory.raw_free(base) + + def thread_after_fork(result_of_fork, opaqueaddr): + # we don't need a thread_before_fork in this case, so + # opaqueaddr == NULL. This is called after fork(). + if result_of_fork == 0: + # We are in the child process. Assumes that only the + # current thread survived, so frees the shadow stacks + # of all the other ones. + gcdata.thread_stacks.foreach(_free_if_not_current, None) + # Clears the dict (including the current thread, which + # was an invalid entry anyway and will be recreated by + # the next call to save_away_current_stack()). + gcdata.thread_stacks.clear() + # Finally, reset the stored thread IDs, in case it + # changed because of fork(). Also change the main + # thread to the current one (because there is not any + # other left). + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + + self.thread_setup = thread_setup + self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) + self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, + inline=True) + # no thread_start_ptr here + self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) + # no thread_before_fork_ptr here + self.thread_after_fork_ptr = getfn(thread_after_fork, + [annmodel.SomeInteger(), + annmodel.SomeAddress()], + annmodel.s_None) + self.collect_stacks_from_other_threads = collect_more_stacks diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/tool/algo/regalloc.py copy from pypy/jit/codewriter/regalloc.py copy to pypy/tool/algo/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/tool/algo/regalloc.py @@ -2,13 +2,11 @@ from pypy.objspace.flow.model import Variable from pypy.tool.algo.color import DependencyGraph from pypy.tool.algo.unionfind import UnionFind -from pypy.jit.metainterp.history import getkind -from pypy.jit.codewriter.flatten import ListOfKind -def perform_register_allocation(graph, kind): +def perform_register_allocation(graph, consider_var, ListOfKind=()): """Perform register allocation for the Variables of the given 'kind' in the 'graph'.""" - regalloc = RegAllocator(graph, kind) + regalloc = RegAllocator(graph, consider_var, ListOfKind) regalloc.make_dependencies() regalloc.coalesce_variables() regalloc.find_node_coloring() @@ -18,9 +16,10 @@ class RegAllocator(object): DEBUG_REGALLOC = False - def __init__(self, graph, kind): + def __init__(self, graph, consider_var, ListOfKind): self.graph = graph - self.kind = kind + self.consider_var = consider_var + self.ListOfKind = ListOfKind def make_dependencies(self): dg = DependencyGraph() @@ -31,7 +30,7 @@ for v in op.args: if isinstance(v, Variable): die_at[v] = i - elif isinstance(v, ListOfKind): + elif isinstance(v, self.ListOfKind): for v1 in v: if isinstance(v1, Variable): die_at[v1] = i @@ -51,7 +50,7 @@ # Done. XXX the code above this line runs 3 times # (for kind in KINDS) to produce the same result... livevars = [v for v in block.inputargs - if getkind(v.concretetype) == self.kind] + if self.consider_var(v)] # Add the variables of this block to the dependency graph for i, v in enumerate(livevars): dg.add_node(v) @@ -67,10 +66,10 @@ pass die_index += 1 if (op.result is not None and - getkind(op.result.concretetype) == self.kind): + self.consider_var(op.result)): dg.add_node(op.result) for v in livevars: - if getkind(v.concretetype) == self.kind: + if self.consider_var(v): dg.add_edge(v, op.result) livevars.add(op.result) self._depgraph = dg @@ -95,8 +94,8 @@ self._try_coalesce(v, link.target.inputargs[i]) def _try_coalesce(self, v, w): - if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: - assert getkind(w.concretetype) == self.kind + if isinstance(v, Variable) and self.consider_var(v): + assert self.consider_var(w) dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) From noreply at buildbot.pypy.org Wed Jul 27 18:55:29 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 27 Jul 2011 18:55:29 +0200 (CEST) Subject: [pypy-commit] pypy default: rpython fix Message-ID: <20110727165529.64C9282110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46024:890f5790aaa4 Date: 2011-07-27 18:53 +0200 http://bitbucket.org/pypy/pypy/changeset/890f5790aaa4/ Log: rpython fix diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -243,7 +243,7 @@ if w_argtype.is_char_p() and w_type is space.w_str: strval = space.str_w(w_arg) buf = rffi.str2charp(strval) - to_free.append(buf) + to_free.append(rffi.cast(rffi.VOIDP, buf)) addr = rffi.cast(rffi.ULONG, buf) argchain.arg(addr) return True @@ -251,7 +251,7 @@ w_type is space.w_unicode): unicodeval = space.unicode_w(w_arg) buf = rffi.unicode2wcharp(unicodeval) - to_free.append(buf) + to_free.append(rffi.cast(rffi.VOIDP, buf)) addr = rffi.cast(rffi.ULONG, buf) argchain.arg(addr) return True From noreply at buildbot.pypy.org Wed Jul 27 19:45:49 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 27 Jul 2011 19:45:49 +0200 (CEST) Subject: [pypy-commit] pypy default: rename this function so it doesn't look like something we copied out of the CPython C-API Message-ID: <20110727174549.4318E82110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46025:042386e45958 Date: 2011-07-27 10:46 -0700 http://bitbucket.org/pypy/pypy/changeset/042386e45958/ Log: rename this function so it doesn't look like something we copied out of the CPython C-API diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -282,8 +282,8 @@ return space.wrap(''.join(w_bytearray.data)) def _convert_idx_params(space, w_self, w_start, w_stop): - start = slicetype._Eval_SliceIndex(space, w_start) - stop = slicetype._Eval_SliceIndex(space, w_stop) + start = slicetype.eval_slice_index(space, w_start) + stop = slicetype.eval_slice_index(space, w_stop) length = len(w_self.data) if start < 0: start += length diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py --- a/pypy/objspace/std/sliceobject.py +++ b/pypy/objspace/std/sliceobject.py @@ -4,7 +4,7 @@ from pypy.interpreter import gateway from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.slicetype import _Eval_SliceIndex +from pypy.objspace.std.slicetype import eval_slice_index class W_SliceObject(W_Object): from pypy.objspace.std.slicetype import slice_typedef as typedef @@ -25,7 +25,7 @@ if space.is_w(w_slice.w_step, space.w_None): step = 1 else: - step = _Eval_SliceIndex(space, w_slice.w_step) + step = eval_slice_index(space, w_slice.w_step) if step == 0: raise OperationError(space.w_ValueError, space.wrap("slice step cannot be zero")) @@ -35,7 +35,7 @@ else: start = 0 else: - start = _Eval_SliceIndex(space, w_slice.w_start) + start = eval_slice_index(space, w_slice.w_start) if start < 0: start += length if start < 0: @@ -54,7 +54,7 @@ else: stop = length else: - stop = _Eval_SliceIndex(space, w_slice.w_stop) + stop = eval_slice_index(space, w_slice.w_stop) if stop < 0: stop += length if stop < 0: diff --git a/pypy/objspace/std/slicetype.py b/pypy/objspace/std/slicetype.py --- a/pypy/objspace/std/slicetype.py +++ b/pypy/objspace/std/slicetype.py @@ -14,7 +14,7 @@ ' normal slices.') # utility functions -def _Eval_SliceIndex(space, w_int): +def eval_slice_index(space, w_int): try: return space.getindex_w(w_int, None) # clamp if long integer too large except OperationError, err: @@ -25,7 +25,7 @@ "None or have an __index__ method")) def adapt_lower_bound(space, size, w_index): - index = _Eval_SliceIndex(space, w_index) + index = eval_slice_index(space, w_index) if index < 0: index = index + size if index < 0: @@ -34,7 +34,7 @@ return index def adapt_bound(space, size, w_index): - index = _Eval_SliceIndex(space, w_index) + index = eval_slice_index(space, w_index) if index < 0: index = index + size if index < 0: diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -172,8 +172,8 @@ return space.wrap(count) def tuple_index__Tuple_ANY_ANY_ANY(space, w_tuple, w_obj, w_start, w_stop): - start = slicetype._Eval_SliceIndex(space, w_start) - stop = slicetype._Eval_SliceIndex(space, w_stop) + start = slicetype.eval_slice_index(space, w_start) + stop = slicetype.eval_slice_index(space, w_stop) length = len(w_tuple.wrappeditems) if start < 0: start += length From noreply at buildbot.pypy.org Wed Jul 27 20:01:16 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 20:01:16 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Temporarily add debugging aids. Should either be reverted or Message-ID: <20110727180116.C78B011B2DE1@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r46026:1b41b4ab3600 Date: 2011-07-27 19:03 +0200 http://bitbucket.org/pypy/pypy/changeset/1b41b4ab3600/ Log: Temporarily add debugging aids. Should either be reverted or made more official... diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -483,6 +483,9 @@ 'gc_dump_rpy_heap' : LLOp(), 'gc_typeids_z' : LLOp(), + '_d_incr': LLOp(sideeffects=False), + '_d_decr': LLOp(sideeffects=False), + # ------- JIT & GC interaction, only for some GCs ---------- 'gc_adr_of_nursery_free' : LLOp(), diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -393,12 +393,14 @@ llops.genop("direct_call", [gct.decr_stack_ptr, c_numcolors], resulttype=llmemory.Address) i = blocks_pop_roots[block] + llops.genop("_d_decr", []) block.operations[i:i] = llops # ^^^ important: done first, in case it's a startstop block, # otherwise the index in 'blocks_push_roots[block]' is # off by one if "start" in blockstate[block]: # "start" or "startstop" llops = LowLevelOpList() + llops.genop("_d_incr", []) llops.genop("direct_call", [gct.incr_stack_ptr, c_numcolors], resulttype=llmemory.Address) top_addr = llops.genop("direct_call", diff --git a/pypy/translator/c/funcgen.py b/pypy/translator/c/funcgen.py --- a/pypy/translator/c/funcgen.py +++ b/pypy/translator/c/funcgen.py @@ -210,6 +210,7 @@ def cfunction_body(self): graph = self.graph + yield 'void *dbg=0;' yield 'goto block0;' # to avoid a warning "this label is not used" # generate the body of each block diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h --- a/pypy/translator/c/src/mem.h +++ b/pypy/translator/c/src/mem.h @@ -246,3 +246,9 @@ #define OP_GC_GET_RPY_TYPE_INDEX(x, r) r = -1 #define OP_GC_IS_RPY_INSTANCE(x, r) r = 0 #define OP_GC_DUMP_RPY_HEAP(fd, r) r = 0 + + + + +#define OP__D_INCR(r) assert(!dbg); dbg = (&pypy_g_pypy_rpython_memory_gctypelayout_GCData)->gcd_inst_root_stack_top +#define OP__D_DECR(r) assert(dbg==(&pypy_g_pypy_rpython_memory_gctypelayout_GCData)->gcd_inst_root_stack_top); dbg = 0 From noreply at buildbot.pypy.org Wed Jul 27 20:01:18 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 20:01:18 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Found and fixed the bug. Message-ID: <20110727180118.0EE1911B2DE1@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r46027:377300db5cab Date: 2011-07-27 19:08 +0200 http://bitbucket.org/pypy/pypy/changeset/377300db5cab/ Log: Found and fixed the bug. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -366,18 +366,19 @@ blocks_push_roots[graph.startblock] = 0 blockstate[graph.startblock] = "start" # - # Now detect direct transitions from "dead" to "alive", and + # Now detect direct transitions from "dead" to "alive"/"stop", and # insert new "start" blocks along the links. Similarly, detect - # direct transitions from "alive" to "dead" and put a "stop" block. + # direct transitions from "alive"/"start" to "dead" and put a + # "stop" block. for block in blockstate.keys(): if blockstate[block] == "dead": for link in block.exits: - if blockstate[link.target] == "alive": + if blockstate[link.target] in ("alive", "stop"): newblock = insert_empty_block(gct.translator.annotator, link) blocks_push_roots[newblock] = 0 blockstate[newblock] = "start" - if blockstate[block] == "alive": + if blockstate[block] in ("alive", "start"): for link in block.exits: if blockstate[link.target] == "dead": newblock = insert_empty_block(gct.translator.annotator, From noreply at buildbot.pypy.org Wed Jul 27 20:01:19 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 20:01:19 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Improve the generated code somewhat. Message-ID: <20110727180119.4A56911B2DE1@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r46028:175ad120b085 Date: 2011-07-27 20:01 +0200 http://bitbucket.org/pypy/pypy/changeset/175ad120b085/ Log: Improve the generated code somewhat. diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -483,9 +483,6 @@ 'gc_dump_rpy_heap' : LLOp(), 'gc_typeids_z' : LLOp(), - '_d_incr': LLOp(sideeffects=False), - '_d_decr': LLOp(sideeffects=False), - # ------- JIT & GC interaction, only for some GCs ---------- 'gc_adr_of_nursery_free' : LLOp(), diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -243,21 +243,16 @@ annmodel.s_None) if root_walker.need_root_stack: - self.incr_stack_ptr = getfn(root_walker.incr_stack, - [annmodel.SomeInteger()], - annmodel.SomeAddress(), - inline = True) - self.decr_stack_ptr = getfn(root_walker.decr_stack, - [annmodel.SomeInteger()], - annmodel.SomeAddress(), - inline = True) self.get_stack_top_ptr = getfn(root_walker.get_stack_top, [], annmodel.SomeAddress(), inline = True) + self.set_stack_top_ptr = getfn(root_walker.set_stack_top, + [annmodel.SomeAddress()], + annmodel.s_None, + inline = True) else: - self.incr_stack_ptr = None - self.decr_stack_ptr = None self.get_stack_top_ptr = None + self.set_stack_top_ptr = None self.weakref_deref_ptr = self.inittime_helper( ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address) @@ -1191,7 +1186,7 @@ return livevars def push_roots(self, hop, keep_current_args=False): - if self.incr_stack_ptr is None: + if self.get_stack_top_ptr is None: return livevars = self.get_livevars_for_roots(hop, keep_current_args) if livevars: @@ -1200,7 +1195,7 @@ return livevars def pop_roots(self, hop, livevars): - if self.decr_stack_ptr is None: + if self.get_stack_top_ptr is None: return if livevars: hop.genop("gc_pop_roots", livevars) diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -6,7 +6,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.tool.algo.regalloc import perform_register_allocation from pypy.translator.backendopt.ssa import DataFlowFamilyBuilder -from pypy.translator.unsimplify import copyvar, insert_empty_block +from pypy.translator.unsimplify import insert_empty_block, varoftype from pypy.objspace.flow.model import Block, Link, Constant from pypy.objspace.flow.model import checkgraph, mkentrymap from pypy.annotation import model as annmodel @@ -22,22 +22,14 @@ # NB. 'self' is frozen, but we can use self.gcdata to store state gcdata = self.gcdata - def incr_stack(n): - top = gcdata.root_stack_top - gcdata.root_stack_top = top + n*sizeofaddr - return top - self.incr_stack = incr_stack - - def decr_stack(n): - top = gcdata.root_stack_top - n*sizeofaddr - gcdata.root_stack_top = top - return top - self.decr_stack = decr_stack - def get_stack_top(): return gcdata.root_stack_top self.get_stack_top = get_stack_top + def set_stack_top(addr): + gcdata.root_stack_top = addr + self.set_stack_top = set_stack_top + self.rootstackhook = gctransformer.root_stack_jit_hook if self.rootstackhook is None: def collect_stack_root(callback, gc, addr): @@ -47,11 +39,13 @@ self.rootstackhook = collect_stack_root def push_stack(self, addr): - top = self.incr_stack(1) + top = self.get_stack_top() top.address[0] = addr + self.set_stack_top(top + sizeofaddr) def pop_stack(self): - top = self.decr_stack(1) + top = self.get_stack_top() - sizeofaddr + self.set_stack_top(top) return top.address[0] def allocate_stack(self): @@ -265,6 +259,15 @@ # operations raw_store/raw_load blocks_push_roots = {} # {block: index-of-the-first} blocks_pop_roots = {} # {block: index-just-after-the-last} + topaddrs_v = {} # {block: (index-of-first-use, v_topaddr)} + # + def get_v_topaddr(block, firstuse=0): + if block in topaddrs_v: + return topaddrs_v[block][1] + v_topaddr = varoftype(llmemory.Address, 'top') + topaddrs_v[block] = (firstuse, v_topaddr) + return v_topaddr + # negnumcolors = 0 c_type = rmodel.inputconst(lltype.Void, llmemory.Address) for block in graph.iterblocks(): @@ -275,32 +278,27 @@ if op.opname not in ("gc_push_roots", "gc_pop_roots"): llops.append(op) continue - top_addr = None for v in op.args: if isinstance(v, Constant): continue - if op.opname == "gc_push_roots": - blocks_push_roots.setdefault(block, len(llops)) - if top_addr is None: - top_addr = llops.genop("direct_call", - [gct.get_stack_top_ptr], - resulttype=llmemory.Address) + v_topaddr = get_v_topaddr(block, firstuse=len(llops)) k = ~regalloc.getcolor(v) negnumcolors = min(negnumcolors, k) c_k = rmodel.inputconst(lltype.Signed, k) if op.opname == "gc_push_roots": + blocks_push_roots.setdefault(block, len(llops)) if (block, op, v) not in useless_stores: - llops.genop("raw_store", [top_addr, c_type, + llops.genop("raw_store", [v_topaddr, c_type, c_k, v]) else: v_newaddr = llops.genop("raw_load", - [top_addr, c_type, c_k], + [v_topaddr, c_type, c_k], resulttype=llmemory.Address) llops.genop("gc_reload_possibly_moved", [v_newaddr, v]) blocks_pop_roots[block] = len(llops) block.operations[:] = llops numcolors = -negnumcolors - c_numcolors = rmodel.inputconst(lltype.Signed, numcolors) + c_framesize = rmodel.inputconst(lltype.Signed, numcolors * sizeofaddr) # # For each block, determine in which category it is: # @@ -391,28 +389,37 @@ for block in blockstate: if "stop" in blockstate[block]: # "stop" or "startstop" llops = LowLevelOpList() - llops.genop("direct_call", [gct.decr_stack_ptr, c_numcolors], - resulttype=llmemory.Address) i = blocks_pop_roots[block] - llops.genop("_d_decr", []) + v_topaddr = get_v_topaddr(block, firstuse=i) + v_baseaddr = llops.genop("adr_sub", [v_topaddr, c_framesize], + resulttype=llmemory.Address) + llops.genop("direct_call", [gct.set_stack_top_ptr, v_baseaddr]) block.operations[i:i] = llops # ^^^ important: done first, in case it's a startstop block, # otherwise the index in 'blocks_push_roots[block]' is # off by one if "start" in blockstate[block]: # "start" or "startstop" llops = LowLevelOpList() - llops.genop("_d_incr", []) - llops.genop("direct_call", [gct.incr_stack_ptr, c_numcolors], - resulttype=llmemory.Address) - top_addr = llops.genop("direct_call", - [gct.get_stack_top_ptr], - resulttype=llmemory.Address) + v_topaddr = get_v_topaddr(block) + v_baseaddr = llops.genop("direct_call",[gct.get_stack_top_ptr], + resulttype=llmemory.Address) + llops.genop("adr_add", [v_baseaddr, c_framesize]) + llops[-1].result = v_topaddr + llops.genop("direct_call", [gct.set_stack_top_ptr, v_topaddr]) c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL) for k in range(numcolors): c_k = rmodel.inputconst(lltype.Signed, ~k) - llops.genop("raw_store", [top_addr, c_type, c_k, c_null]) + llops.genop("raw_store", [v_topaddr, c_type, c_k, c_null]) i = blocks_push_roots[block] block.operations[i:i] = llops + else: + if block in topaddrs_v: + # we need to get the current stack top for this block + i, topaddr_v = topaddrs_v[block] + llops = LowLevelOpList() + llops.genop("direct_call", [gct.get_stack_top_ptr]) + llops[-1].result = topaddr_v + block.operations[i:i] = llops # checkgraph(graph) diff --git a/pypy/translator/c/funcgen.py b/pypy/translator/c/funcgen.py --- a/pypy/translator/c/funcgen.py +++ b/pypy/translator/c/funcgen.py @@ -210,7 +210,6 @@ def cfunction_body(self): graph = self.graph - yield 'void *dbg=0;' yield 'goto block0;' # to avoid a warning "this label is not used" # generate the body of each block diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h --- a/pypy/translator/c/src/mem.h +++ b/pypy/translator/c/src/mem.h @@ -246,9 +246,3 @@ #define OP_GC_GET_RPY_TYPE_INDEX(x, r) r = -1 #define OP_GC_IS_RPY_INSTANCE(x, r) r = 0 #define OP_GC_DUMP_RPY_HEAP(fd, r) r = 0 - - - - -#define OP__D_INCR(r) assert(!dbg); dbg = (&pypy_g_pypy_rpython_memory_gctypelayout_GCData)->gcd_inst_root_stack_top -#define OP__D_DECR(r) assert(dbg==(&pypy_g_pypy_rpython_memory_gctypelayout_GCData)->gcd_inst_root_stack_top); dbg = 0 From noreply at buildbot.pypy.org Wed Jul 27 23:04:54 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 23:04:54 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Tentative tweak. Will measure. Message-ID: <20110727210454.4E67F11B2DE1@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r46029:bbb57672167a Date: 2011-07-27 21:20 +0200 http://bitbucket.org/pypy/pypy/changeset/bbb57672167a/ Log: Tentative tweak. Will measure. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -268,12 +268,17 @@ topaddrs_v[block] = (firstuse, v_topaddr) return v_topaddr # + # Handling of v_topaddr: the idea is that a gc_push_roots should try + # to reuse the v_topaddr already loaded for the current block, but + # not a gc_pop_roots, because that would force it to be in one of the + # relatively few callee-saved registers. negnumcolors = 0 c_type = rmodel.inputconst(lltype.Void, llmemory.Address) for block in graph.iterblocks(): if block.operations == (): continue llops = LowLevelOpList() + v_topaddr = None for op in block.operations: if op.opname not in ("gc_push_roots", "gc_pop_roots"): llops.append(op) @@ -281,16 +286,19 @@ for v in op.args: if isinstance(v, Constant): continue - v_topaddr = get_v_topaddr(block, firstuse=len(llops)) k = ~regalloc.getcolor(v) negnumcolors = min(negnumcolors, k) c_k = rmodel.inputconst(lltype.Signed, k) if op.opname == "gc_push_roots": + v_topaddr = (v_topaddr or + get_v_topaddr(block, firstuse=len(llops))) blocks_push_roots.setdefault(block, len(llops)) if (block, op, v) not in useless_stores: llops.genop("raw_store", [v_topaddr, c_type, c_k, v]) else: + v_topaddr = llops.genop("direct_call", + [gct.get_stack_top_ptr]) v_newaddr = llops.genop("raw_load", [v_topaddr, c_type, c_k], resulttype=llmemory.Address) From noreply at buildbot.pypy.org Wed Jul 27 23:04:55 2011 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 27 Jul 2011 23:04:55 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-perf: Fix. Message-ID: <20110727210455.7F57911B2DE1@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-perf Changeset: r46030:a25d76f90da7 Date: 2011-07-27 23:02 +0200 http://bitbucket.org/pypy/pypy/changeset/a25d76f90da7/ Log: Fix. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -298,7 +298,8 @@ c_k, v]) else: v_topaddr = llops.genop("direct_call", - [gct.get_stack_top_ptr]) + [gct.get_stack_top_ptr], + resulttype=llmemory.Address) v_newaddr = llops.genop("raw_load", [v_topaddr, c_type, c_k], resulttype=llmemory.Address) From noreply at buildbot.pypy.org Wed Jul 27 23:05:47 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Wed, 27 Jul 2011 23:05:47 +0200 (CEST) Subject: [pypy-commit] pypy default: Small speed-up for stream output buffers Message-ID: <20110727210547.2E6F911B2DE1@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r46031:410c4f324cf5 Date: 2011-07-27 15:04 -0600 http://bitbucket.org/pypy/pypy/changeset/410c4f324cf5/ Log: Small speed-up for stream output buffers diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -894,13 +894,10 @@ self.buf.append(data) self.buflen += datalen elif buflen: - i = self.bufsize - buflen - assert i >= 0 - self.buf.append(data[:i]) + self.buf.append(data) self.do_write(''.join(self.buf)) self.buf = [] self.buflen = 0 - self.write(data[i:]) else: self.do_write(data) From noreply at buildbot.pypy.org Thu Jul 28 03:14:53 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 28 Jul 2011 03:14:53 +0200 (CEST) Subject: [pypy-commit] pypy default: Introduce StringBuilder.append_charpsize, which takes a char* and a size and adds that to the builder, then use this in a few plcaes. Message-ID: <20110728011453.ED83011B2DE1@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46032:7cc899d8de19 Date: 2011-07-27 18:14 -0700 http://bitbucket.org/pypy/pypy/changeset/7cc899d8de19/ Log: Introduce StringBuilder.append_charpsize, which takes a char* and a size and adds that to the builder, then use this in a few plcaes. diff --git a/pypy/rlib/rstring.py b/pypy/rlib/rstring.py --- a/pypy/rlib/rstring.py +++ b/pypy/rlib/rstring.py @@ -1,8 +1,8 @@ """ String builder interface and string functions """ -from pypy.annotation.model import SomeObject, SomeString, s_None,\ - SomeChar, SomeInteger, SomeUnicodeCodePoint, SomeUnicodeString +from pypy.annotation.model import (SomeObject, SomeString, s_None, SomeChar, + SomeInteger, SomeUnicodeCodePoint, SomeUnicodeString, SomePtr) from pypy.rpython.extregistry import ExtRegistryEntry @@ -65,6 +65,12 @@ assert isinstance(c, self.tp) self.l.append(c * times) + def append_charpsize(self, s, size): + l = [] + for i in xrange(size): + l.append(s[i]) + self.l.append(self.tp("").join(l)) + def build(self): return self.tp("").join(self.l) @@ -100,6 +106,11 @@ assert isinstance(s_times, SomeInteger) return s_None + def method_append_charpsize(self, s_ptr, s_size): + assert isinstance(s_ptr, SomePtr) + assert isinstance(s_size, SomeInteger) + return s_None + def method_getlength(self): return SomeInteger(nonneg=True) @@ -127,6 +138,11 @@ assert isinstance(s_times, SomeInteger) return s_None + def method_append_charpsize(self, s_ptr, s_size): + assert isinstance(s_ptr, SomePtr) + assert isinstance(s_size, SomeInteger) + return s_None + def method_getlength(self): return SomeInteger(nonneg=True) diff --git a/pypy/rlib/rzlib.py b/pypy/rlib/rzlib.py --- a/pypy/rlib/rzlib.py +++ b/pypy/rlib/rzlib.py @@ -1,8 +1,11 @@ import sys + +from pypy.rlib.rstring import StringBuilder from pypy.rpython.lltypesystem import rffi, lltype from pypy.rpython.tool import rffi_platform +from pypy.translator.platform import platform as compiler, CompilationError from pypy.translator.tool.cbuild import ExternalCompilationInfo -from pypy.translator.platform import platform as compiler, CompilationError + if compiler.name == "msvc": libname = 'zlib' @@ -353,7 +356,7 @@ # of characters 'result'. We don't need to gradually # increase the output buffer size because there is no # quadratic factor. - result = [] + result = StringBuilder() while True: stream.c_next_out = rffi.cast(Bytefp, outbuf) @@ -369,8 +372,7 @@ if err == Z_OK or err == Z_STREAM_END: # accumulate data into 'result' avail_out = rffi.cast(lltype.Signed, stream.c_avail_out) - for i in xrange(bufsize - avail_out): - result.append(outbuf[i]) + result.append_charpsize(outbuf, bufsize - avail_out) # if the output buffer is full, there might be more data # so we need to try again. Otherwise, we're done. if avail_out > 0: @@ -401,6 +403,6 @@ # When decompressing, if the compressed stream of data was truncated, # then the zlib simply returns Z_OK and waits for more. If it is # complete it returns Z_STREAM_END. - return (''.join(result), + return (result.build(), err, rffi.cast(lltype.Signed, stream.c_avail_in)) diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py --- a/pypy/rpython/lltypesystem/rbuilder.py +++ b/pypy/rpython/lltypesystem/rbuilder.py @@ -1,13 +1,13 @@ - +from pypy.rlib import rgc +from pypy.rlib.objectmodel import enforceargs +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rpython.annlowlevel import llstr +from pypy.rpython.rptr import PtrRepr +from pypy.rpython.lltypesystem import lltype, rstr +from pypy.rpython.lltypesystem.lltype import staticAdtMethod +from pypy.rpython.lltypesystem.rstr import (STR, UNICODE, char_repr, + string_repr, unichar_repr, unicode_repr) from pypy.rpython.rbuilder import AbstractStringBuilderRepr -from pypy.rpython.lltypesystem import lltype, rstr -from pypy.rpython.lltypesystem.rstr import STR, UNICODE, char_repr,\ - string_repr, unichar_repr, unicode_repr -from pypy.rpython.annlowlevel import llstr -from pypy.rlib import rgc -from pypy.rlib.rarithmetic import ovfcheck -from pypy.rlib.objectmodel import enforceargs -from pypy.rpython.lltypesystem.lltype import staticAdtMethod from pypy.tool.sourcetools import func_with_new_name # Think about heuristics below, maybe we can come up with something @@ -73,7 +73,7 @@ ll_builder.grow(ll_builder, lgt) ll_str.copy_contents(ll_str, ll_builder.buf, 0, used, lgt) ll_builder.used = needed - + @staticmethod def ll_append_char(ll_builder, char): if ll_builder.used == ll_builder.allocated: @@ -102,6 +102,16 @@ ll_builder.used = used @staticmethod + def ll_append_charpsize(ll_builder, charp, size): + used = ll_builder.used + if used + size > ll_builder.allocated: + ll_builder.grow(ll_builder, size) + for i in xrange(size): + ll_builder.buf.chars[used] = charp[i] + used += 1 + ll_builder.used = used + + @staticmethod def ll_getlength(ll_builder): return ll_builder.used @@ -119,6 +129,9 @@ mallocfn = staticmethod(rstr.mallocstr) string_repr = string_repr char_repr = char_repr + raw_ptr_repr = PtrRepr( + lltype.Ptr(lltype.Array(lltype.Char, hints={'nolength': True})) + ) class UnicodeBuilderRepr(BaseStringBuilderRepr): lowleveltype = lltype.Ptr(UNICODEBUILDER) @@ -126,6 +139,9 @@ mallocfn = staticmethod(rstr.mallocunicode) string_repr = unicode_repr char_repr = unichar_repr + raw_ptr_repr = PtrRepr( + lltype.Ptr(lltype.Array(lltype.UniChar, hints={'nolength': True})) + ) unicodebuilder_repr = UnicodeBuilderRepr() stringbuilder_repr = StringBuilderRepr() diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -789,8 +789,7 @@ # char* and size -> str (which can contain null bytes) def charpsize2str(cp, size): b = builder_class(size) - for i in xrange(size): - b.append(cp[i]) + b.append_charpsize(cp, size) return b.build() charpsize2str._annenforceargs_ = [None, int] diff --git a/pypy/rpython/rbuilder.py b/pypy/rpython/rbuilder.py --- a/pypy/rpython/rbuilder.py +++ b/pypy/rpython/rbuilder.py @@ -36,6 +36,11 @@ hop.exception_cannot_occur() return hop.gendirectcall(self.ll_append_multiple_char, *vlist) + def rtype_method_append_charpsize(self, hop): + vlist = hop.inputargs(self, self.raw_ptr_repr, lltype.Signed) + hop.exception_cannot_occur() + return hop.gendirectcall(self.ll_append_charpsize, *vlist) + def rtype_method_getlength(self, hop): vlist = hop.inputargs(self) hop.exception_cannot_occur() diff --git a/pypy/rpython/rptr.py b/pypy/rpython/rptr.py --- a/pypy/rpython/rptr.py +++ b/pypy/rpython/rptr.py @@ -22,7 +22,7 @@ class __extend__(annmodel.SomeInteriorPtr): def rtyper_makerepr(self, rtyper): return InteriorPtrRepr(self.ll_ptrtype) - + class PtrRepr(Repr): @@ -91,7 +91,7 @@ vlist = hop.inputargs(*hop.args_r) nexpected = len(self.lowleveltype.TO.ARGS) nactual = len(vlist)-1 - if nactual != nexpected: + if nactual != nexpected: raise TyperError("argcount mismatch: expected %d got %d" % (nexpected, nactual)) if isinstance(vlist[0], flowmodel.Constant): @@ -111,7 +111,12 @@ hop.swap_fst_snd_args() hop.r_s_popfirstarg() return self.rtype_simple_call(hop) - + +class __extend__(pairtype(PtrRepr, PtrRepr)): + def convert_from_to((r_ptr1, r_ptr2), v, llop): + assert r_ptr1.lowleveltype == r_ptr2.lowleveltype + return v + class __extend__(pairtype(PtrRepr, IntegerRepr)): @@ -205,7 +210,7 @@ self.lowleveltype = adtmeth.ll_ptrtype self.ll_ptrtype = adtmeth.ll_ptrtype self.lowleveltype = rtyper.getrepr(annmodel.lltype_to_annotation(adtmeth.ll_ptrtype)).lowleveltype - + def rtype_simple_call(self, hop): hop2 = hop.copy() func = self.func @@ -242,7 +247,7 @@ if numitemoffsets > 0: self.lowleveltype = lltype.Ptr(self.parentptrtype._interior_ptr_type_with_index(self.resulttype.TO)) else: - self.lowleveltype = self.parentptrtype + self.lowleveltype = self.parentptrtype def getinteriorfieldargs(self, hop, v_self): vlist = [] @@ -305,7 +310,7 @@ class __extend__(pairtype(InteriorPtrRepr, IntegerRepr)): - def rtype_getitem((r_ptr, r_item), hop): + def rtype_getitem((r_ptr, r_item), hop): ARRAY = r_ptr.resulttype.TO ITEM_TYPE = ARRAY.OF if isinstance(ITEM_TYPE, lltype.ContainerType): @@ -325,7 +330,7 @@ vlist = r_ptr.getinteriorfieldargs(hop, v_self) + [v_index] return hop.genop('getinteriorfield', vlist, resulttype=ITEM_TYPE) - + def rtype_setitem((r_ptr, r_index), hop): ARRAY = r_ptr.resulttype.TO ITEM_TYPE = ARRAY.OF @@ -333,11 +338,11 @@ v_self, v_index, v_value = hop.inputargs(r_ptr, lltype.Signed, hop.args_r[2]) vlist = r_ptr.getinteriorfieldargs(hop, v_self) + [v_index, v_value] hop.genop('setinteriorfield', vlist) - + class __extend__(pairtype(InteriorPtrRepr, LLADTMethRepr)): def convert_from_to((r_from, r_to), v, llops): if r_from.lowleveltype == r_to.lowleveltype: return v return NotImplemented - + diff --git a/pypy/rpython/test/test_rbuilder.py b/pypy/rpython/test/test_rbuilder.py --- a/pypy/rpython/test/test_rbuilder.py +++ b/pypy/rpython/test/test_rbuilder.py @@ -1,8 +1,10 @@ import py + +from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rpython.annlowlevel import llstr, hlstr +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem.rbuilder import * from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin -from pypy.rpython.lltypesystem.rbuilder import * -from pypy.rpython.annlowlevel import llstr, hlstr -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder class TestStringBuilderDirect(object): @@ -73,6 +75,15 @@ res = self.interpret(func, []) assert res == 4 + def test_append_charpsize(self): + def func(l): + s = StringBuilder() + with rffi.scoped_str2charp("hello world") as x: + s.append_charpsize(x, l) + return s.build() + res = self.ll_to_string(self.interpret(func, [5])) + assert res == "hello" + class TestLLtype(BaseTestStringBuilder, LLRtypeMixin): pass @@ -81,3 +92,5 @@ py.test.skip("getlength(): not implemented on ootype") def test_unicode_getlength(self): py.test.skip("getlength(): not implemented on ootype") + def test_append_charpsize(self): + py.test.skip("append_charpsize(): not implemented on ootype") \ No newline at end of file From noreply at buildbot.pypy.org Thu Jul 28 03:14:55 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 28 Jul 2011 03:14:55 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20110728011455.2CB0311B2DE1@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46033:811906ece2d8 Date: 2011-07-27 18:15 -0700 http://bitbucket.org/pypy/pypy/changeset/811906ece2d8/ Log: merged upstream diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -894,13 +894,10 @@ self.buf.append(data) self.buflen += datalen elif buflen: - i = self.bufsize - buflen - assert i >= 0 - self.buf.append(data[:i]) + self.buf.append(data) self.do_write(''.join(self.buf)) self.buf = [] self.buflen = 0 - self.write(data[i:]) else: self.do_write(data) From noreply at buildbot.pypy.org Thu Jul 28 07:37:22 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 28 Jul 2011 07:37:22 +0200 (CEST) Subject: [pypy-commit] pypy default: Use the new context manager allocators, much nicer. Also update a comment. Message-ID: <20110728053722.1F37282110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46034:c5eae3c7710f Date: 2011-07-27 22:37 -0700 http://bitbucket.org/pypy/pypy/changeset/c5eae3c7710f/ Log: Use the new context manager allocators, much nicer. Also update a comment. diff --git a/pypy/rlib/rzlib.py b/pypy/rlib/rzlib.py --- a/pypy/rlib/rzlib.py +++ b/pypy/rlib/rzlib.py @@ -340,22 +340,17 @@ """Common code for compress() and decompress(). """ # Prepare the input buffer for the stream - inbuf = lltype.malloc(rffi.CCHARP.TO, len(data), flavor='raw') - try: + with lltype.scoped_alloc(rffi.CCHARP.TO, len(data)) as inbuf: for i in xrange(len(data)): inbuf[i] = data[i] stream.c_next_in = rffi.cast(Bytefp, inbuf) rffi.setintfield(stream, 'c_avail_in', len(data)) # Prepare the output buffer - outbuf = lltype.malloc(rffi.CCHARP.TO, OUTPUT_BUFFER_SIZE, - flavor='raw') - try: - # Strategy: we call deflate() to get as much output data as - # fits in the buffer, then accumulate all output into a list - # of characters 'result'. We don't need to gradually - # increase the output buffer size because there is no - # quadratic factor. + with lltype.scoped_alloc(rffi.CCHARP.TO, OUTPUT_BUFFER_SIZE) as outbuf: + # Strategy: we call deflate() to get as much output data as fits in + # the buffer, then accumulate all output into a StringBuffer + # 'result'. result = StringBuilder() while True: @@ -395,11 +390,6 @@ # fallback case: report this error raise RZlibError.fromstream(stream, err, while_doing) - finally: - lltype.free(outbuf, flavor='raw') - finally: - lltype.free(inbuf, flavor='raw') - # When decompressing, if the compressed stream of data was truncated, # then the zlib simply returns Z_OK and waits for more. If it is # complete it returns Z_STREAM_END. From noreply at buildbot.pypy.org Thu Jul 28 07:45:55 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 28 Jul 2011 07:45:55 +0200 (CEST) Subject: [pypy-commit] pypy default: Move the memcpy function to rffi.py. Message-ID: <20110728054555.303A882110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46035:18b8d8ab3f7b Date: 2011-07-27 22:46 -0700 http://bitbucket.org/pypy/pypy/changeset/18b8d8ab3f7b/ Log: Move the memcpy function to rffi.py. diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -14,8 +14,6 @@ from pypy.rpython.lltypesystem import lltype, rffi -memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) - @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): if len(__args__.arguments_w) > 1: @@ -617,7 +615,7 @@ def array_copy__Array(space, self): w_a = mytype.w_class(self.space) w_a.setlen(self.len) - memcpy( + rffi.c_memcpy( rffi.cast(rffi.VOIDP, w_a.buffer), rffi.cast(rffi.VOIDP, self.buffer), self.len * mytype.bytes diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -1061,3 +1061,11 @@ keep_unicodebuffer_alive_until_here(self.raw, self.gc_buf) def str(self, length): return unicode_from_buffer(self.raw, self.gc_buf, self.size, length) + +# You would have to have a *huge* amount of data for this to block long enough +# to be worth it to release the GIL. +c_memcpy = llexternal("memcpy", + [VOIDP, VOIDP, SIZE_T], + lltype.Void, + threadsafe=False +) \ No newline at end of file From noreply at buildbot.pypy.org Thu Jul 28 10:56:26 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 10:56:26 +0200 (CEST) Subject: [pypy-commit] pypy default: Missing import. Message-ID: <20110728085626.5BD8982110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46036:692c06726aea Date: 2011-07-28 10:56 +0200 http://bitbucket.org/pypy/pypy/changeset/692c06726aea/ Log: Missing import. diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py --- a/pypy/rpython/memory/gctransform/shadowstack.py +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -2,6 +2,7 @@ from pypy.rpython.memory.gctransform.framework import sizeofaddr from pypy.rlib.debug import ll_assert from pypy.rpython.lltypesystem import llmemory +from pypy.annotation import model as annmodel class ShadowStackRootWalker(BaseRootWalker): From noreply at buildbot.pypy.org Thu Jul 28 14:05:50 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 28 Jul 2011 14:05:50 +0200 (CEST) Subject: [pypy-commit] pypy default: we cannot immediately free the temp buffers that we allocate to convert strings, because the caller needs to have a chance to play with them in case they have been returned; instead, the temp buffers are owned by the function itself, and needs to be explicitly freed Message-ID: <20110728120550.225AD82110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46037:ddc4544bf357 Date: 2011-07-28 14:03 +0200 http://bitbucket.org/pypy/pypy/changeset/ddc4544bf357/ Log: we cannot immediately free the temp buffers that we allocate to convert strings, because the caller needs to have a chance to play with them in case they have been returned; instead, the temp buffers are owned by the function itself, and needs to be explicitly freed diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -11,6 +11,7 @@ from pypy.rlib import libffi from pypy.rlib.rdynload import DLOpenError from pypy.rlib.rarithmetic import intmask, r_uint +from pypy.rlib.objectmodel import we_are_translated class W_FFIType(Wrappable): @@ -181,6 +182,7 @@ self.func = func self.argtypes_w = argtypes_w self.w_restype = w_restype + self.to_free = [] @jit.unroll_safe def build_argchain(self, space, args_w): @@ -195,8 +197,6 @@ self.func.name, expected, arg, given) # argchain = libffi.ArgChain() - to_free = [] # list of automatically malloc()ed buffers that needs to - # be freed after the call for i in range(expected): w_argtype = self.argtypes_w[i] w_arg = args_w[i] @@ -207,7 +207,7 @@ self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) - elif self.add_char_p_maybe(space, argchain, to_free, w_arg, w_argtype): + elif self.add_char_p_maybe(space, argchain, w_arg, w_argtype): # the argument is added to the argchain direcly by the method above pass elif w_argtype.is_pointer(): @@ -232,9 +232,9 @@ argchain.arg_raw(ptrval) else: assert False, "Argument shape '%s' not supported" % w_argtype - return argchain, to_free + return argchain - def add_char_p_maybe(self, space, argchain, to_free, w_arg, w_argtype): + def add_char_p_maybe(self, space, argchain, w_arg, w_argtype): """ Automatic conversion from string to char_p. The allocated buffer will be automatically freed after the call. @@ -243,7 +243,7 @@ if w_argtype.is_char_p() and w_type is space.w_str: strval = space.str_w(w_arg) buf = rffi.str2charp(strval) - to_free.append(rffi.cast(rffi.VOIDP, buf)) + self.to_free.append(rffi.cast(rffi.VOIDP, buf)) addr = rffi.cast(rffi.ULONG, buf) argchain.arg(addr) return True @@ -251,7 +251,7 @@ w_type is space.w_unicode): unicodeval = space.unicode_w(w_arg) buf = rffi.unicode2wcharp(unicodeval) - to_free.append(rffi.cast(rffi.VOIDP, buf)) + self.to_free.append(rffi.cast(rffi.VOIDP, buf)) addr = rffi.cast(rffi.ULONG, buf) argchain.arg(addr) return True @@ -279,12 +279,16 @@ def call(self, space, args_w): self = jit.promote(self) - argchain, to_free = self.build_argchain(space, args_w) - try: - return self._do_call(space, argchain) - finally: - for buf in to_free: - lltype.free(buf, flavor='raw') + argchain = self.build_argchain(space, args_w) + return self._do_call(space, argchain) + + def free_temp_buffers(self, space): + for buf in self.to_free: + if not we_are_translated(): + buf[0] = '\00' # invalidate the buffer, so that + # test_keepalive_temp_buffer can fail + lltype.free(buf, flavor='raw') + self.to_free = [] def _do_call(self, space, argchain): w_restype = self.w_restype @@ -424,6 +428,7 @@ '_ffi.FuncPtr', __call__ = interp2app(W_FuncPtr.call), getaddr = interp2app(W_FuncPtr.getaddr), + free_temp_buffers = interp2app(W_FuncPtr.free_temp_buffers), fromaddr = interp2app(descr_fromaddr, as_classmethod=True) ) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -210,6 +210,7 @@ mystr = CharArray(7, 'foobar') assert mystrlen(mystr.buffer) == 6 mystr.free() + mystrlen.free_temp_buffers() def test_convert_unicode_to_unichar_p(self): """ @@ -235,6 +236,25 @@ mystr = UniCharArray(7, u'foobar') assert mystrlen(mystr.buffer) == 6 mystr.free() + mystrlen.free_temp_buffers() + + def test_keepalive_temp_buffer(self): + """ + char* do_nothing(char* s) + { + return s; + } + """ + from _ffi import CDLL, types + import _rawffi + libfoo = CDLL(self.libfoo_name) + do_nothing = libfoo.getfunc('do_nothing', [types.char_p], types.char_p) + CharArray = _rawffi.Array('c') + # + ptr = do_nothing('foobar') + array = CharArray.fromaddress(ptr, 7) + assert list(array) == list('foobar\00') + do_nothing.free_temp_buffers() def test_typed_pointer(self): from _ffi import types From noreply at buildbot.pypy.org Thu Jul 28 15:24:19 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 28 Jul 2011 15:24:19 +0200 (CEST) Subject: [pypy-commit] pypy default: free the temp buffers created by the _ffi function. Also, thanks to the new automatic string conversion in _ffi, passing a python string is now supported by the fast path Message-ID: <20110728132419.90BAE82110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46038:f65745081f3b Date: 2011-07-28 15:14 +0200 http://bitbucket.org/pypy/pypy/changeset/f65745081f3b/ Log: free the temp buffers created by the _ffi function. Also, thanks to the new automatic string conversion in _ffi, passing a python string is now supported by the fast path diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -365,7 +365,10 @@ if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) # - return self._build_result(self._restype_, result, newargs) + try: + return self._build_result(self._restype_, result, newargs) + finally: + funcptr.free_temp_buffers() def _do_errcheck(self, result, args): # The 'errcheck' protocol diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py @@ -63,13 +63,10 @@ result = f(mystr, ord("b")) assert result == "bcd" - @py.test.mark.xfail def test_strings(self): f = dll.my_strchr f.argtypes = [c_char_p, c_int] f.restype = c_char_p - # python strings need to be converted to c_char_p, but this is - # supported only in the slow path so far result = f("abcd", ord("b")) assert result == "bcd" From noreply at buildbot.pypy.org Thu Jul 28 15:24:20 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 28 Jul 2011 15:24:20 +0200 (CEST) Subject: [pypy-commit] pypy default: add one passing assert Message-ID: <20110728132420.C409F82111@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46039:764ca7f1f901 Date: 2011-07-28 15:23 +0200 http://bitbucket.org/pypy/pypy/changeset/764ca7f1f901/ Log: add one passing assert diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -231,6 +231,7 @@ # first, try automatic conversion from strings and unicode assert mystrlen('foobar') == 6 assert mystrlen(u'foobar') == 6 + assert mystrlen(u'ab\u2070') == 3 # then, try to pass an explicit pointer UniCharArray = _rawffi.Array('u') mystr = UniCharArray(7, u'foobar') From noreply at buildbot.pypy.org Thu Jul 28 15:24:22 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 28 Jul 2011 15:24:22 +0200 (CEST) Subject: [pypy-commit] pypy default: if the automatic conversion from str to c_wchar_p does not work, fallback to the slow path Message-ID: <20110728132422.0DE4382112@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46040:10359ec64a51 Date: 2011-07-28 15:24 +0200 http://bitbucket.org/pypy/pypy/changeset/10359ec64a51/ Log: if the automatic conversion from str to c_wchar_p does not work, fallback to the slow path diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -697,7 +697,7 @@ try: result = self._call_funcptr(funcptr, *args) result = self._do_errcheck(result, args) - except (TypeError, ArgumentError): # XXX, should be FFITypeError + except (TypeError, ArgumentError, UnicodeDecodeError): assert self._slowpath_allowed return CFuncPtr.__call__(self, *args) return result From noreply at buildbot.pypy.org Thu Jul 28 16:11:50 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Thu, 28 Jul 2011 16:11:50 +0200 (CEST) Subject: [pypy-commit] pypy default: don't raise a warning if the restype is not set, and add a test to check that we hit the fastpath even in that case Message-ID: <20110728141150.20CE882110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46041:9d98198682de Date: 2011-07-28 16:12 +0200 http://bitbucket.org/pypy/pypy/changeset/9d98198682de/ Log: don't raise a warning if the restype is not set, and add a test to check that we hit the fastpath even in that case diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -78,8 +78,6 @@ _com_iid = None _is_fastpath = False - __restype_set = False - def _getargtypes(self): return self._argtypes_ @@ -149,7 +147,6 @@ return self._restype_ def _setrestype(self, restype): - self.__restype_set = True self._ptr = None if restype is int: from ctypes import c_int @@ -315,10 +312,6 @@ warnings.warn('C function without declared arguments called', RuntimeWarning, stacklevel=2) argtypes = [] - - if not self.__restype_set: - warnings.warn('C function without declared return type called', - RuntimeWarning, stacklevel=2) if self._com_index: from ctypes import cast, c_void_p, POINTER diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py @@ -46,6 +46,18 @@ tf_b.argtypes = (c_byte,) assert tf_b(-126) == -42 + def test_undeclared_restype(self): + # make sure we get a fresh function + try: + del dll.tf_i + except AttributeError: + pass + tf_i = dll.tf_i + assert not tf_i._is_fastpath + tf_i.argtypes = (c_int,) + assert tf_i._is_fastpath + assert tf_i(12) == 4 + def test_pointer_args(self): f = dll._testfunc_p_p f.restype = POINTER(c_int) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -488,11 +488,9 @@ warnings.simplefilter("always") with warnings.catch_warnings(record=True) as w: dll.get_an_integer() - assert len(w) == 2 + assert len(w) == 1 assert issubclass(w[0].category, RuntimeWarning) - assert issubclass(w[1].category, RuntimeWarning) assert "C function without declared arguments called" in str(w[0].message) - assert "C function without declared return type called" in str(w[1].message) def test_errcheck(self): py.test.skip('fixme') From noreply at buildbot.pypy.org Thu Jul 28 16:15:05 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Thu, 28 Jul 2011 16:15:05 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: talk as given Message-ID: <20110728141505.582A482110@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: extradoc Changeset: r3842:e50a1115d4af Date: 2011-07-27 18:15 +0100 http://bitbucket.org/pypy/extradoc/changeset/e50a1115d4af/ Log: talk as given diff --git a/talk/icooolps2011/talk/figures/map.svg b/talk/icooolps2011/talk/figures/map.svg --- a/talk/icooolps2011/talk/figures/map.svg +++ b/talk/icooolps2011/talk/figures/map.svg @@ -49,7 +49,40 @@ id="path8552" d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" - transform="scale(0.8) translate(12.5,0)" />add "a" add "b" +map +"c": 0 +add "c" +"b": 1 -add "b" -map -"c": 0 -add "c" instance + id="text7703" + transform="scale(1,-1)" + x="8.2999992" + y="-249.89999">instance + map + id="text7711" + transform="matrix(1,0,0,-1,78.5,249.9)">map + storage + id="text7719" + transform="matrix(1,0,0,-1,122.5,249.9)">storage + array + id="text7733" + transform="matrix(1,0,0,-1,185.5,183.9)">array + 4 + id="text7741" + transform="matrix(1,0,0,-1,232.5,183.9)">4 + 6 + id="text7749" + transform="matrix(1,0,0,-1,256.5,183.9)">6 + \ No newline at end of file diff --git a/talk/icooolps2011/talk/figures/map01.pdf b/talk/icooolps2011/talk/figures/map01.pdf index d957a75d52a1e205b35f2139afe40e260bcaa5f7..b02a6212807255e3be3a63808946c1f87b32a64a GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/map02.pdf b/talk/icooolps2011/talk/figures/map02.pdf index c8f07cffbd5017707537c5fb18bf7a822384016f..8f23b0fb78a661be86adf7790844570eed590ef5 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/map03.pdf b/talk/icooolps2011/talk/figures/map03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e9944db6caa3a34e1852cfb8934df628bf64d089 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/talk.pdf b/talk/icooolps2011/talk/talk.pdf new file mode 100644 index 0000000000000000000000000000000000000000..66d79ac74735959368d77448b8d8606105e447f1 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/talk.tex b/talk/icooolps2011/talk/talk.tex --- a/talk/icooolps2011/talk/talk.tex +++ b/talk/icooolps2011/talk/talk.tex @@ -107,12 +107,12 @@ \end{frame} \begin{frame} - \frametitle{A Tracing JIT} + \frametitle{An Interpreter} \includegraphics[scale=0.5]{figures/trace01.pdf} \end{frame} \begin{frame} - \frametitle{An Interpreter} + \frametitle{A Tracing JIT} \includegraphics[scale=0.5]{figures/trace02.pdf} \end{frame} @@ -149,6 +149,7 @@ \begin{frame} \frametitle{Example: Attribute Reads in Python} What happens when an attribute \texttt{x.m} is read? (simplified) + \pause \begin{itemize} \item check for \texttt{x.\_\_getattribute\_\_}, if there, call it \pause @@ -180,7 +181,7 @@ \frametitle{Meta-Tracing JITs} \begin{block}{Advantages:} \begin{itemize} - \item semantics is always like that of the interpreter + \item semantics are always like that of the interpreter \item trace fully contains language semantics \item meta-tracers can be reused for various interpreters \end{itemize} @@ -240,12 +241,17 @@ \begin{frame} \frametitle{Example: Instances with Maps} - \includegraphics[scale=0.5]{figures/map01.pdf} + \includegraphics[scale=0.7]{figures/map01.pdf} \end{frame} \begin{frame} \frametitle{Example: Instances with Maps} - \includegraphics[scale=0.5]{figures/map02.pdf} + \includegraphics[scale=0.7]{figures/map02.pdf} +\end{frame} + +\begin{frame} + \frametitle{Example: Instances with Maps} + \includegraphics[scale=0.7]{figures/map03.pdf} \end{frame} \begin{frame}[containsverbatim] @@ -286,7 +292,7 @@ \end{frame} \begin{frame}[plain,containsverbatim] -\frametitle{Trace for code \texttt{inst.a + inst.b}} +\frametitle{Trace for Code \texttt{inst.a + inst.b}} \begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] # $inst_1$.getfield("a") $map_1$ = $inst_1$.map @@ -393,7 +399,6 @@ \PY{k}{def} \PY{n+nf}{getindex}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{,} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)} - \PY{n+nd}{@elidable} \PY{k}{def} \PY{n+nf}{add\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} \PY{o}{.}\PY{o}{.}\PY{o}{.} From noreply at buildbot.pypy.org Thu Jul 28 18:00:18 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:18 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and comment for elidable functions that can raise. Message-ID: <20110728160018.CF9E482110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46042:37f74b79d119 Date: 2011-07-28 10:05 +0200 http://bitbucket.org/pypy/pypy/changeset/37f74b79d119/ Log: Test and comment for elidable functions that can raise. diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -407,6 +407,32 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=0) + def test_elidable_raising(self): + myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable + def externfn(x): + if x <= 0: + raise ValueError + return x - 1 + def f(n, m): + while n > 0: + myjitdriver.can_enter_jit(n=n, m=m) + myjitdriver.jit_merge_point(n=n, m=m) + try: + n -= externfn(m) + except ValueError: + n -= 1 + return n + res = self.meta_interp(f, [22, 6]) + assert res == -3 + # the CALL_PURE is constant-folded away by optimizeopt.py + self.check_loops(int_sub=1, call=0, call_pure=0) + # + res = self.meta_interp(f, [22, -5]) + assert res == 0 + # raises: becomes CALL and is not constant-folded away + self.check_loops(int_sub=1, call=1, call_pure=0) + def test_constant_across_mp(self): myjitdriver = JitDriver(greens = [], reds = ['n']) class X(object): diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -16,7 +16,8 @@ Most importantly it doesn't mean that an elidable function has no observable side effect, but those side effects are idempotent (ie caching). - For now, such a function should never raise an exception. + The function can raise an exception, in which case this decorator is + ignored. """ func._elidable_function_ = True return func From noreply at buildbot.pypy.org Thu Jul 28 18:00:20 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:20 +0200 (CEST) Subject: [pypy-commit] pypy default: The recent rewrite of crash_in_jit() lost the original traceback Message-ID: <20110728160020.0BAAC82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46043:e02ef353c3c8 Date: 2011-07-28 10:22 +0200 http://bitbucket.org/pypy/pypy/changeset/e02ef353c3c8/ Log: The recent rewrite of crash_in_jit() lost the original traceback in non-translated versions. diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -409,6 +409,7 @@ jd.warmstate = state def crash_in_jit(e): + tb = not we_are_translated() and sys.exc_info()[2] try: raise e except JitException: @@ -422,8 +423,8 @@ print "~~~ Crash in JIT!" print '~~~ %s: %s' % (e.__class__, e) if sys.stdout == sys.__stdout__: - import pdb; pdb.post_mortem(sys.exc_info()[2]) - raise + import pdb; pdb.post_mortem(tb) + raise e.__class__, e, tb fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) crash_in_jit._dont_inline_ = True From noreply at buildbot.pypy.org Thu Jul 28 18:00:21 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:21 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove a guard_no_exception() at the start of the loop too. Message-ID: <20110728160021.43A6D82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46044:2cfe0f51122b Date: 2011-07-28 11:14 +0200 http://bitbucket.org/pypy/pypy/changeset/2cfe0f51122b/ Log: Remove a guard_no_exception() at the start of the loop too. diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -55,7 +55,7 @@ def optimize_loop_1(metainterp_sd, loop, enable_opts, - inline_short_preamble=True, retraced=False): + inline_short_preamble=True, retraced=False, bridge=False): """Optimize loop.operations to remove internal overheadish operations. """ @@ -64,7 +64,7 @@ if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: - optimizer = Optimizer(metainterp_sd, loop, optimizations) + optimizer = Optimizer(metainterp_sd, loop, optimizations, bridge) optimizer.propagate_all_forward() def optimize_bridge_1(metainterp_sd, bridge, enable_opts, @@ -76,7 +76,7 @@ except KeyError: pass optimize_loop_1(metainterp_sd, bridge, enable_opts, - inline_short_preamble, retraced) + inline_short_preamble, retraced, bridge=True) if __name__ == '__main__': print ALL_OPTS_NAMES diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -248,10 +248,11 @@ class Optimizer(Optimization): - def __init__(self, metainterp_sd, loop, optimizations=None): + def __init__(self, metainterp_sd, loop, optimizations=None, bridge=False): self.metainterp_sd = metainterp_sd self.cpu = metainterp_sd.cpu self.loop = loop + self.bridge = bridge self.values = {} self.interned_refs = self.cpu.ts.new_ref_dict() self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd) @@ -407,9 +408,7 @@ return CVAL_ZERO def propagate_all_forward(self): - self.exception_might_have_happened = True - # ^^^ at least at the start of bridges. For loops, we could set - # it to False, but we probably don't care + self.exception_might_have_happened = self.bridge self.newoperations = [] self.first_optimization.propagate_begin_forward() self.i = 0 diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -693,7 +693,6 @@ """ expected = """ [i] - guard_no_exception() [] i1 = int_add(i, 3) i2 = call(i1, descr=nonwritedescr) guard_no_exception() [i1, i2] diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -889,12 +889,10 @@ i3 = call(i2, descr=nonwritedescr) jump(i1) # the exception is considered lost when we loop back """ - # note that 'guard_no_exception' at the very start must be kept - # around: bridges may start with one. (In case of loops we could - # remove it, but we probably don't care.) + # note that 'guard_no_exception' at the very start is kept around + # for bridges, but not for loops preamble = """ [i] - guard_no_exception() [] i1 = int_add(i, 3) i2 = call(i1, descr=nonwritedescr) guard_no_exception() [i1, i2] @@ -2993,6 +2991,38 @@ ''' self.optimize_loop(ops, expected, preamble, call_pure_results) + def test_call_pure_constant_folding_exc(self): + # CALL_PURE may be followed by GUARD_NO_EXCEPTION + arg_consts = [ConstInt(i) for i in (123456, 4, 5, 6)] + call_pure_results = {tuple(arg_consts): ConstInt(42)} + ops = ''' + [i0, i1, i2] + escape(i1) + escape(i2) + i3 = call_pure(123456, 4, 5, 6, descr=plaincalldescr) + guard_no_exception() [] + i4 = call_pure(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i3, i4) + ''' + preamble = ''' + [i0, i1, i2] + escape(i1) + escape(i2) + i4 = call(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i4) + ''' + expected = ''' + [i0, i2] + escape(42) + escape(i2) + i4 = call(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i4) + ''' + self.optimize_loop(ops, expected, preamble, call_pure_results) + # ---------- def test_vref_nonvirtual_nonescape(self): From noreply at buildbot.pypy.org Thu Jul 28 18:00:22 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:22 +0200 (CEST) Subject: [pypy-commit] pypy default: Add a test (it was already passing, thanks to optimizeopt). Message-ID: <20110728160022.72EAB82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46045:7f452cc5f50d Date: 2011-07-28 11:28 +0200 http://bitbucket.org/pypy/pypy/changeset/7f452cc5f50d/ Log: Add a test (it was already passing, thanks to optimizeopt). diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py --- a/pypy/jit/metainterp/test/test_string.py +++ b/pypy/jit/metainterp/test/test_string.py @@ -358,3 +358,22 @@ self.check_loops(call=3, # str(), _str(), escape() newunicode=1, unicodegetitem=0, unicodesetitem=1, copyunicodecontent=1) + + def test_str2unicode_fold(self): + _str = self._str + jitdriver = JitDriver(greens = ['g'], reds = ['m']) + @dont_look_inside + def escape(x): + print str(x) + def f(g, m): + g = str(g) + while m >= 0: + jitdriver.can_enter_jit(g=g, m=m) + jitdriver.jit_merge_point(g=g, m=m) + escape(_str(g)) + m -= 1 + return 42 + self.meta_interp(f, [6, 7]) + self.check_loops(call_pure=0, call=1, + newunicode=0, unicodegetitem=0, + unicodesetitem=0, copyunicodecontent=0) From noreply at buildbot.pypy.org Thu Jul 28 18:00:23 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:23 +0200 (CEST) Subject: [pypy-commit] pypy default: Support elidable functions that can raise. Message-ID: <20110728160023.B4DC882110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46046:7d31a6bafd88 Date: 2011-07-28 11:30 +0200 http://bitbucket.org/pypy/pypy/changeset/7d31a6bafd88/ Log: Support elidable functions that can raise. diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -228,8 +228,10 @@ elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif elidable: - # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_ELIDABLE + if self._canraise(op): + extraeffect = EffectInfo.EF_ELIDABLE_CAN_RAISE + else: + extraeffect = EffectInfo.EF_ELIDABLE_CANNOT_RAISE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -263,7 +265,7 @@ def calldescr_canraise(self, calldescr): effectinfo = calldescr.get_extra_info() return (effectinfo is None or - effectinfo.extraeffect >= EffectInfo.EF_CAN_RAISE) + effectinfo.extraeffect > EffectInfo.EF_CANNOT_RAISE) def jitdriver_sd_from_portal_graph(self, graph): for jd in self.jitdrivers_sd: diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,10 +9,11 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_ELIDABLE = 0 #elidable function (and cannot raise) + EF_ELIDABLE_CANNOT_RAISE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise - EF_CAN_RAISE = 3 #normal function (can raise) + EF_ELIDABLE_CAN_RAISE = 3 #elidable function (but can raise) + EF_CAN_RAISE = 4 #normal function (can raise) EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables # the 'oopspecindex' field is one of the following values: @@ -94,7 +95,8 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_ELIDABLE: + extraeffect == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \ + extraeffect == EffectInfo.EF_ELIDABLE_CAN_RAISE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -902,7 +902,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1363,15 +1363,15 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_ELIDABLE, because it can raise - # UnicodeDecodeError... - return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) + # ll_str2unicode can raise UnicodeDecodeError + return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE, + EffectInfo.EF_ELIDABLE_CAN_RAISE) # ---------- # VirtualRefs. @@ -1415,7 +1415,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -120,9 +120,9 @@ assert argtypes[0] == [v.concretetype for v in op.args[1:]] assert argtypes[1] == op.result.concretetype if oopspecindex == EI.OS_STR2UNICODE: - assert extraeffect == None # not pure, can raise! + assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE else: - assert extraeffect == EI.EF_ELIDABLE + assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -543,8 +543,10 @@ elif opnum == rop.CALL: effectinfo = descr.get_extra_info() if effectinfo is not None: - if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: + ef = effectinfo.extraeffect + if ef == EffectInfo.EF_LOOPINVARIANT or \ + ef == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \ + ef == EffectInfo.EF_ELIDABLE_CAN_RAISE: return True return False diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1199,7 +1199,7 @@ return self.metainterp.execute_and_record(opnum, descr, *argboxes) @specialize.arg(1) - def execute_varargs(self, opnum, argboxes, descr, exc): + def execute_varargs(self, opnum, argboxes, descr, exc, pure): self.metainterp.clear_exception() resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes, descr=descr) @@ -1207,6 +1207,9 @@ self.make_result_of_lastop(resbox) # ^^^ this is done before handle_possible_exception() because we # need the box to show up in get_list_of_active_boxes() + if pure and self.metainterp.last_exc_value_box is None: + resbox = self.metainterp.record_result_of_call_pure(resbox) + exc = exc and not isinstance(resbox, Const) if exc: self.metainterp.handle_possible_exception() else: @@ -1269,16 +1272,14 @@ return resbox else: effect = effectinfo.extraeffect - if effect == effectinfo.EF_CANNOT_RAISE: - return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_ELIDABLE: - return self.metainterp.record_result_of_call_pure( - self.execute_varargs(rop.CALL, allboxes, descr, False)) - elif effect == effectinfo.EF_LOOPINVARIANT: + if effect == effectinfo.EF_LOOPINVARIANT: return self.execute_varargs(rop.CALL_LOOPINVARIANT, allboxes, - descr, False) - else: - return self.execute_varargs(rop.CALL, allboxes, descr, True) + descr, False, False) + exc = (effect != effectinfo.EF_CANNOT_RAISE and + effect != effectinfo.EF_ELIDABLE_CANNOT_RAISE) + pure = (effect == effectinfo.EF_ELIDABLE_CAN_RAISE or + effect == effectinfo.EF_ELIDABLE_CANNOT_RAISE) + return self.execute_varargs(rop.CALL, allboxes, descr, exc, pure) def do_residual_or_indirect_call(self, funcbox, calldescr, argboxes): """The 'residual_call' operation is emitted in two cases: @@ -1686,8 +1687,12 @@ return if opnum == rop.CALL: effectinfo = descr.get_extra_info() - if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: - return + if effectinfo is not None: + ef = effectinfo.extraeffect + if ef == effectinfo.EF_LOOPINVARIANT or \ + ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or \ + ef == effectinfo.EF_ELIDABLE_CAN_RAISE: + return if self.heap_cache: self.heap_cache.clear() if self.heap_array_cache: @@ -2375,6 +2380,7 @@ tobox = newbox if change: self.heap_cache[descr] = frombox, tobox + # XXX what about self.heap_array_cache? def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -277,3 +277,15 @@ NODE._add_fields({'value': ootype.Signed, 'next': NODE}) return NODE + +# ____________________________________________________________ + +class _Foo: + pass + +def noConst(x): + """Helper function for tests, returning 'x' as a BoxInt/BoxPtr + even if it is a ConstInt/ConstPtr.""" + f1 = _Foo(); f2 = _Foo() + f1.x = x; f2.x = 0 + return f1.x diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -14,7 +14,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT -from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, noConst class BasicTests: @@ -425,6 +425,32 @@ return n res = self.meta_interp(f, [22, 6]) assert res == -3 + # the CALL_PURE is constant-folded away during tracing + self.check_loops(int_sub=1, call=0, call_pure=0) + # + res = self.meta_interp(f, [22, -5]) + assert res == 0 + # raises: becomes CALL and is not constant-folded away + self.check_loops(int_sub=1, call=1, call_pure=0) + + def test_elidable_raising_2(self): + myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable + def externfn(x): + if x <= 0: + raise ValueError + return x - 1 + def f(n, m): + while n > 0: + myjitdriver.can_enter_jit(n=n, m=m) + myjitdriver.jit_merge_point(n=n, m=m) + try: + n -= externfn(noConst(m)) + except ValueError: + n -= 1 + return n + res = self.meta_interp(f, [22, 6]) + assert res == -3 # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0) # From noreply at buildbot.pypy.org Thu Jul 28 18:00:24 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:24 +0200 (CEST) Subject: [pypy-commit] pypy default: A reasonable fix: "ll_int_str() -> string" is pure, but if left in the trace, Message-ID: <20110728160024.E565482110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46047:7e2413d8482c Date: 2011-07-28 11:42 +0200 http://bitbucket.org/pypy/pypy/changeset/7e2413d8482c/ Log: A reasonable fix: "ll_int_str() -> string" is pure, but if left in the trace, we should check that it doesn't raise MemoryError. diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -157,7 +157,7 @@ # the same arguments are not folded, because we have conflicting # definitions of pure, once strhash can be appropriately folded # this should be decreased to seven. - self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 6, "guard_true": 1, "int_and": 1, "int_gt": 1, "int_is_true": 1, "int_sub": 1, "jump": 1, "new_with_vtable": 1, "setfield_gc": 1}) From noreply at buildbot.pypy.org Thu Jul 28 18:00:26 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:26 +0200 (CEST) Subject: [pypy-commit] pypy default: Add a number of @elidable, now that they can raise. Message-ID: <20110728160026.21A9F82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46048:a3001c18a307 Date: 2011-07-28 11:52 +0200 http://bitbucket.org/pypy/pypy/changeset/a3001c18a307/ Log: Add a number of @elidable, now that they can raise. diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -20,6 +20,7 @@ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.jit.metainterp.typesystem import deref from pypy.rlib import rgc +from pypy.rlib.jit import elidable from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask def getargtypes(annotator, values): @@ -167,9 +168,14 @@ _ll_5_list_ll_arraycopy = rgc.ll_arraycopy + at elidable def _ll_1_gc_identityhash(x): return lltype.identityhash(x) +# the following function should not be "@elidable": I can think of +# a corner case in which id(const) is constant-folded, and then 'const' +# disappears and is collected too early (possibly causing another object +# with the same id() to appear). def _ll_1_gc_id(ptr): return llop.gc_id(lltype.Signed, ptr) @@ -177,6 +183,7 @@ return llop.jit_force_virtual(lltype.typeOf(inst), inst) + at elidable def _ll_2_int_floordiv_ovf_zer(x, y): if y == 0: raise ZeroDivisionError @@ -184,16 +191,19 @@ raise OverflowError return llop.int_floordiv(lltype.Signed, x, y) + at elidable def _ll_2_int_floordiv_ovf(x, y): if x == -sys.maxint - 1 and y == -1: raise OverflowError return llop.int_floordiv(lltype.Signed, x, y) + at elidable def _ll_2_int_floordiv_zer(x, y): if y == 0: raise ZeroDivisionError return llop.int_floordiv(lltype.Signed, x, y) + at elidable def _ll_2_int_mod_ovf_zer(x, y): if y == 0: raise ZeroDivisionError @@ -201,22 +211,26 @@ raise OverflowError return llop.int_mod(lltype.Signed, x, y) + at elidable def _ll_2_int_mod_ovf(x, y): if x == -sys.maxint - 1 and y == -1: raise OverflowError return llop.int_mod(lltype.Signed, x, y) + at elidable def _ll_2_int_mod_zer(x, y): if y == 0: raise ZeroDivisionError return llop.int_mod(lltype.Signed, x, y) + at elidable def _ll_2_int_lshift_ovf(x, y): result = x << y if (result >> y) != x: raise OverflowError return result + at elidable def _ll_1_int_abs(x): if x < 0: return -x diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -323,6 +323,7 @@ _likely_raise(errno, r) return r + at jit.elidable def ll_math_sqrt(x): if x < 0.0: raise ValueError, "math domain error" From noreply at buildbot.pypy.org Thu Jul 28 18:00:27 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:27 +0200 (CEST) Subject: [pypy-commit] pypy default: Backed out changeset a3001c18a307: oups, that was wrong. Message-ID: <20110728160027.5215082110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46049:2bbb9f022bf7 Date: 2011-07-28 11:57 +0200 http://bitbucket.org/pypy/pypy/changeset/2bbb9f022bf7/ Log: Backed out changeset a3001c18a307: oups, that was wrong. @elidable turns the function call into a residual call. diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -20,7 +20,6 @@ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.jit.metainterp.typesystem import deref from pypy.rlib import rgc -from pypy.rlib.jit import elidable from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask def getargtypes(annotator, values): @@ -168,14 +167,9 @@ _ll_5_list_ll_arraycopy = rgc.ll_arraycopy - at elidable def _ll_1_gc_identityhash(x): return lltype.identityhash(x) -# the following function should not be "@elidable": I can think of -# a corner case in which id(const) is constant-folded, and then 'const' -# disappears and is collected too early (possibly causing another object -# with the same id() to appear). def _ll_1_gc_id(ptr): return llop.gc_id(lltype.Signed, ptr) @@ -183,7 +177,6 @@ return llop.jit_force_virtual(lltype.typeOf(inst), inst) - at elidable def _ll_2_int_floordiv_ovf_zer(x, y): if y == 0: raise ZeroDivisionError @@ -191,19 +184,16 @@ raise OverflowError return llop.int_floordiv(lltype.Signed, x, y) - at elidable def _ll_2_int_floordiv_ovf(x, y): if x == -sys.maxint - 1 and y == -1: raise OverflowError return llop.int_floordiv(lltype.Signed, x, y) - at elidable def _ll_2_int_floordiv_zer(x, y): if y == 0: raise ZeroDivisionError return llop.int_floordiv(lltype.Signed, x, y) - at elidable def _ll_2_int_mod_ovf_zer(x, y): if y == 0: raise ZeroDivisionError @@ -211,26 +201,22 @@ raise OverflowError return llop.int_mod(lltype.Signed, x, y) - at elidable def _ll_2_int_mod_ovf(x, y): if x == -sys.maxint - 1 and y == -1: raise OverflowError return llop.int_mod(lltype.Signed, x, y) - at elidable def _ll_2_int_mod_zer(x, y): if y == 0: raise ZeroDivisionError return llop.int_mod(lltype.Signed, x, y) - at elidable def _ll_2_int_lshift_ovf(x, y): result = x << y if (result >> y) != x: raise OverflowError return result - at elidable def _ll_1_int_abs(x): if x < 0: return -x diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -323,7 +323,6 @@ _likely_raise(errno, r) return r - at jit.elidable def ll_math_sqrt(x): if x < 0.0: raise ValueError, "math domain error" From noreply at buildbot.pypy.org Thu Jul 28 18:00:28 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:28 +0200 (CEST) Subject: [pypy-commit] pypy default: Put @elidable on calls to identityhash() only. Message-ID: <20110728160028.8433E82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46050:88f51d44dcd9 Date: 2011-07-28 11:58 +0200 http://bitbucket.org/pypy/pypy/changeset/88f51d44dcd9/ Log: Put @elidable on calls to identityhash() only. diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -20,6 +20,7 @@ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.jit.metainterp.typesystem import deref from pypy.rlib import rgc +from pypy.rlib.jit import elidable from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask def getargtypes(annotator, values): @@ -167,9 +168,14 @@ _ll_5_list_ll_arraycopy = rgc.ll_arraycopy + at elidable def _ll_1_gc_identityhash(x): return lltype.identityhash(x) +# the following function should not be "@elidable": I can think of +# a corner case in which id(const) is constant-folded, and then 'const' +# disappears and is collected too early (possibly causing another object +# with the same id() to appear). def _ll_1_gc_id(ptr): return llop.gc_id(lltype.Signed, ptr) From noreply at buildbot.pypy.org Thu Jul 28 18:00:29 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:00:29 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads: support @elidable functions that raise Message-ID: <20110728160029.D749282110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46051:4f19b0b10c0f Date: 2011-07-28 17:58 +0200 http://bitbucket.org/pypy/pypy/changeset/4f19b0b10c0f/ Log: merge heads: support @elidable functions that raise diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -228,8 +228,10 @@ elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif elidable: - # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_ELIDABLE + if self._canraise(op): + extraeffect = EffectInfo.EF_ELIDABLE_CAN_RAISE + else: + extraeffect = EffectInfo.EF_ELIDABLE_CANNOT_RAISE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -263,7 +265,7 @@ def calldescr_canraise(self, calldescr): effectinfo = calldescr.get_extra_info() return (effectinfo is None or - effectinfo.extraeffect >= EffectInfo.EF_CAN_RAISE) + effectinfo.extraeffect > EffectInfo.EF_CANNOT_RAISE) def jitdriver_sd_from_portal_graph(self, graph): for jd in self.jitdrivers_sd: diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,10 +9,11 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_ELIDABLE = 0 #elidable function (and cannot raise) + EF_ELIDABLE_CANNOT_RAISE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise - EF_CAN_RAISE = 3 #normal function (can raise) + EF_ELIDABLE_CAN_RAISE = 3 #elidable function (but can raise) + EF_CAN_RAISE = 4 #normal function (can raise) EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables # the 'oopspecindex' field is one of the following values: @@ -94,7 +95,8 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_ELIDABLE: + extraeffect == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \ + extraeffect == EffectInfo.EF_ELIDABLE_CAN_RAISE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -902,7 +902,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1363,15 +1363,15 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_ELIDABLE, because it can raise - # UnicodeDecodeError... - return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) + # ll_str2unicode can raise UnicodeDecodeError + return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE, + EffectInfo.EF_ELIDABLE_CAN_RAISE) # ---------- # VirtualRefs. @@ -1415,7 +1415,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -20,6 +20,7 @@ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.jit.metainterp.typesystem import deref from pypy.rlib import rgc +from pypy.rlib.jit import elidable from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask def getargtypes(annotator, values): @@ -167,9 +168,14 @@ _ll_5_list_ll_arraycopy = rgc.ll_arraycopy + at elidable def _ll_1_gc_identityhash(x): return lltype.identityhash(x) +# the following function should not be "@elidable": I can think of +# a corner case in which id(const) is constant-folded, and then 'const' +# disappears and is collected too early (possibly causing another object +# with the same id() to appear). def _ll_1_gc_id(ptr): return llop.gc_id(lltype.Signed, ptr) diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -120,9 +120,9 @@ assert argtypes[0] == [v.concretetype for v in op.args[1:]] assert argtypes[1] == op.result.concretetype if oopspecindex == EI.OS_STR2UNICODE: - assert extraeffect == None # not pure, can raise! + assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE else: - assert extraeffect == EI.EF_ELIDABLE + assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -55,7 +55,7 @@ def optimize_loop_1(metainterp_sd, loop, enable_opts, - inline_short_preamble=True, retraced=False): + inline_short_preamble=True, retraced=False, bridge=False): """Optimize loop.operations to remove internal overheadish operations. """ @@ -64,7 +64,7 @@ if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: - optimizer = Optimizer(metainterp_sd, loop, optimizations) + optimizer = Optimizer(metainterp_sd, loop, optimizations, bridge) optimizer.propagate_all_forward() def optimize_bridge_1(metainterp_sd, bridge, enable_opts, @@ -76,7 +76,7 @@ except KeyError: pass optimize_loop_1(metainterp_sd, bridge, enable_opts, - inline_short_preamble, retraced) + inline_short_preamble, retraced, bridge=True) if __name__ == '__main__': print ALL_OPTS_NAMES diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -248,10 +248,11 @@ class Optimizer(Optimization): - def __init__(self, metainterp_sd, loop, optimizations=None): + def __init__(self, metainterp_sd, loop, optimizations=None, bridge=False): self.metainterp_sd = metainterp_sd self.cpu = metainterp_sd.cpu self.loop = loop + self.bridge = bridge self.values = {} self.interned_refs = self.cpu.ts.new_ref_dict() self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd) @@ -407,9 +408,7 @@ return CVAL_ZERO def propagate_all_forward(self): - self.exception_might_have_happened = True - # ^^^ at least at the start of bridges. For loops, we could set - # it to False, but we probably don't care + self.exception_might_have_happened = self.bridge self.newoperations = [] self.first_optimization.propagate_begin_forward() self.i = 0 diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -693,7 +693,6 @@ """ expected = """ [i] - guard_no_exception() [] i1 = int_add(i, 3) i2 = call(i1, descr=nonwritedescr) guard_no_exception() [i1, i2] diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -889,12 +889,10 @@ i3 = call(i2, descr=nonwritedescr) jump(i1) # the exception is considered lost when we loop back """ - # note that 'guard_no_exception' at the very start must be kept - # around: bridges may start with one. (In case of loops we could - # remove it, but we probably don't care.) + # note that 'guard_no_exception' at the very start is kept around + # for bridges, but not for loops preamble = """ [i] - guard_no_exception() [] i1 = int_add(i, 3) i2 = call(i1, descr=nonwritedescr) guard_no_exception() [i1, i2] @@ -2993,6 +2991,38 @@ ''' self.optimize_loop(ops, expected, preamble, call_pure_results) + def test_call_pure_constant_folding_exc(self): + # CALL_PURE may be followed by GUARD_NO_EXCEPTION + arg_consts = [ConstInt(i) for i in (123456, 4, 5, 6)] + call_pure_results = {tuple(arg_consts): ConstInt(42)} + ops = ''' + [i0, i1, i2] + escape(i1) + escape(i2) + i3 = call_pure(123456, 4, 5, 6, descr=plaincalldescr) + guard_no_exception() [] + i4 = call_pure(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i3, i4) + ''' + preamble = ''' + [i0, i1, i2] + escape(i1) + escape(i2) + i4 = call(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i4) + ''' + expected = ''' + [i0, i2] + escape(42) + escape(i2) + i4 = call(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i4) + ''' + self.optimize_loop(ops, expected, preamble, call_pure_results) + # ---------- def test_vref_nonvirtual_nonescape(self): diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -543,8 +543,10 @@ elif opnum == rop.CALL: effectinfo = descr.get_extra_info() if effectinfo is not None: - if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: + ef = effectinfo.extraeffect + if ef == EffectInfo.EF_LOOPINVARIANT or \ + ef == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \ + ef == EffectInfo.EF_ELIDABLE_CAN_RAISE: return True return False diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1199,7 +1199,7 @@ return self.metainterp.execute_and_record(opnum, descr, *argboxes) @specialize.arg(1) - def execute_varargs(self, opnum, argboxes, descr, exc): + def execute_varargs(self, opnum, argboxes, descr, exc, pure): self.metainterp.clear_exception() resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes, descr=descr) @@ -1207,6 +1207,9 @@ self.make_result_of_lastop(resbox) # ^^^ this is done before handle_possible_exception() because we # need the box to show up in get_list_of_active_boxes() + if pure and self.metainterp.last_exc_value_box is None: + resbox = self.metainterp.record_result_of_call_pure(resbox) + exc = exc and not isinstance(resbox, Const) if exc: self.metainterp.handle_possible_exception() else: @@ -1269,16 +1272,14 @@ return resbox else: effect = effectinfo.extraeffect - if effect == effectinfo.EF_CANNOT_RAISE: - return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_ELIDABLE: - return self.metainterp.record_result_of_call_pure( - self.execute_varargs(rop.CALL, allboxes, descr, False)) - elif effect == effectinfo.EF_LOOPINVARIANT: + if effect == effectinfo.EF_LOOPINVARIANT: return self.execute_varargs(rop.CALL_LOOPINVARIANT, allboxes, - descr, False) - else: - return self.execute_varargs(rop.CALL, allboxes, descr, True) + descr, False, False) + exc = (effect != effectinfo.EF_CANNOT_RAISE and + effect != effectinfo.EF_ELIDABLE_CANNOT_RAISE) + pure = (effect == effectinfo.EF_ELIDABLE_CAN_RAISE or + effect == effectinfo.EF_ELIDABLE_CANNOT_RAISE) + return self.execute_varargs(rop.CALL, allboxes, descr, exc, pure) def do_residual_or_indirect_call(self, funcbox, calldescr, argboxes): """The 'residual_call' operation is emitted in two cases: @@ -1686,8 +1687,12 @@ return if opnum == rop.CALL: effectinfo = descr.get_extra_info() - if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: - return + if effectinfo is not None: + ef = effectinfo.extraeffect + if ef == effectinfo.EF_LOOPINVARIANT or \ + ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or \ + ef == effectinfo.EF_ELIDABLE_CAN_RAISE: + return if self.heap_cache: self.heap_cache.clear() if self.heap_array_cache: @@ -2375,6 +2380,7 @@ tobox = newbox if change: self.heap_cache[descr] = frombox, tobox + # XXX what about self.heap_array_cache? def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -277,3 +277,15 @@ NODE._add_fields({'value': ootype.Signed, 'next': NODE}) return NODE + +# ____________________________________________________________ + +class _Foo: + pass + +def noConst(x): + """Helper function for tests, returning 'x' as a BoxInt/BoxPtr + even if it is a ConstInt/ConstPtr.""" + f1 = _Foo(); f2 = _Foo() + f1.x = x; f2.x = 0 + return f1.x diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -14,7 +14,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT -from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, noConst class BasicTests: @@ -407,6 +407,58 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=0) + def test_elidable_raising(self): + myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable + def externfn(x): + if x <= 0: + raise ValueError + return x - 1 + def f(n, m): + while n > 0: + myjitdriver.can_enter_jit(n=n, m=m) + myjitdriver.jit_merge_point(n=n, m=m) + try: + n -= externfn(m) + except ValueError: + n -= 1 + return n + res = self.meta_interp(f, [22, 6]) + assert res == -3 + # the CALL_PURE is constant-folded away during tracing + self.check_loops(int_sub=1, call=0, call_pure=0) + # + res = self.meta_interp(f, [22, -5]) + assert res == 0 + # raises: becomes CALL and is not constant-folded away + self.check_loops(int_sub=1, call=1, call_pure=0) + + def test_elidable_raising_2(self): + myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable + def externfn(x): + if x <= 0: + raise ValueError + return x - 1 + def f(n, m): + while n > 0: + myjitdriver.can_enter_jit(n=n, m=m) + myjitdriver.jit_merge_point(n=n, m=m) + try: + n -= externfn(noConst(m)) + except ValueError: + n -= 1 + return n + res = self.meta_interp(f, [22, 6]) + assert res == -3 + # the CALL_PURE is constant-folded away by optimizeopt.py + self.check_loops(int_sub=1, call=0, call_pure=0) + # + res = self.meta_interp(f, [22, -5]) + assert res == 0 + # raises: becomes CALL and is not constant-folded away + self.check_loops(int_sub=1, call=1, call_pure=0) + def test_constant_across_mp(self): myjitdriver = JitDriver(greens = [], reds = ['n']) class X(object): diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -157,7 +157,7 @@ # the same arguments are not folded, because we have conflicting # definitions of pure, once strhash can be appropriately folded # this should be decreased to seven. - self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 6, "guard_true": 1, "int_and": 1, "int_gt": 1, "int_is_true": 1, "int_sub": 1, "jump": 1, "new_with_vtable": 1, "setfield_gc": 1}) diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py --- a/pypy/jit/metainterp/test/test_string.py +++ b/pypy/jit/metainterp/test/test_string.py @@ -358,3 +358,22 @@ self.check_loops(call=3, # str(), _str(), escape() newunicode=1, unicodegetitem=0, unicodesetitem=1, copyunicodecontent=1) + + def test_str2unicode_fold(self): + _str = self._str + jitdriver = JitDriver(greens = ['g'], reds = ['m']) + @dont_look_inside + def escape(x): + print str(x) + def f(g, m): + g = str(g) + while m >= 0: + jitdriver.can_enter_jit(g=g, m=m) + jitdriver.jit_merge_point(g=g, m=m) + escape(_str(g)) + m -= 1 + return 42 + self.meta_interp(f, [6, 7]) + self.check_loops(call_pure=0, call=1, + newunicode=0, unicodegetitem=0, + unicodesetitem=0, copyunicodecontent=0) diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -409,6 +409,7 @@ jd.warmstate = state def crash_in_jit(e): + tb = not we_are_translated() and sys.exc_info()[2] try: raise e except JitException: @@ -422,8 +423,8 @@ print "~~~ Crash in JIT!" print '~~~ %s: %s' % (e.__class__, e) if sys.stdout == sys.__stdout__: - import pdb; pdb.post_mortem(sys.exc_info()[2]) - raise + import pdb; pdb.post_mortem(tb) + raise e.__class__, e, tb fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) crash_in_jit._dont_inline_ = True diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -16,7 +16,8 @@ Most importantly it doesn't mean that an elidable function has no observable side effect, but those side effects are idempotent (ie caching). - For now, such a function should never raise an exception. + The function can raise an exception, in which case this decorator is + ignored. """ func._elidable_function_ = True return func From noreply at buildbot.pypy.org Thu Jul 28 18:07:10 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 28 Jul 2011 18:07:10 +0200 (CEST) Subject: [pypy-commit] pypy default: use functools.wrap here, should maintain some more of the functions attributes this way. Message-ID: <20110728160710.4FD6782110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46052:da9f3c16b424 Date: 2011-07-28 09:05 -0700 http://bitbucket.org/pypy/pypy/changeset/da9f3c16b424/ Log: use functools.wrap here, should maintain some more of the functions attributes this way. diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -1,10 +1,14 @@ +import functools +import sys + import py -import sys + +from pypy.rlib.nonconst import NonConstant +from pypy.rlib.objectmodel import (CDefinedIntSymbolic, keepalive_until_here, + specialize) +from pypy.rlib.unroll import unrolling_iterable from pypy.rpython.extregistry import ExtRegistryEntry -from pypy.rlib.objectmodel import CDefinedIntSymbolic -from pypy.rlib.objectmodel import keepalive_until_here, specialize -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.nonconst import NonConstant + def elidable(func): """ Decorate a function as "trace-elidable". This means precisely that: @@ -90,7 +94,7 @@ d = {"func": func, "hint": hint} exec py.code.Source("\n".join(code)).compile() in d result = d["f"] - result.func_name = func.func_name + "_promote" + functools.wraps(func)(result) return result return decorator @@ -279,7 +283,7 @@ def specialize_call(self, hop): pass - + vref_None = non_virtual_ref(None) # ____________________________________________________________ @@ -289,7 +293,7 @@ """Inconsistency in the JIT hints.""" PARAMETERS = {'threshold': 1032, # just above 1024 - 'function_threshold': 1617, # slightly more than one above + 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, 'inlining': 1, @@ -399,7 +403,7 @@ raise set_user_param._annspecialcase_ = 'specialize:arg(0)' - + def on_compile(self, logger, looptoken, operations, type, *greenargs): """ A hook called when loop is compiled. Overwrite for your own jitdriver if you want to do something special, like From noreply at buildbot.pypy.org Thu Jul 28 18:07:11 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 28 Jul 2011 18:07:11 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream. Message-ID: <20110728160711.A3C6282110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46053:25e36db72459 Date: 2011-07-28 09:07 -0700 http://bitbucket.org/pypy/pypy/changeset/25e36db72459/ Log: merged upstream. diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -228,8 +228,10 @@ elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif elidable: - # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_ELIDABLE + if self._canraise(op): + extraeffect = EffectInfo.EF_ELIDABLE_CAN_RAISE + else: + extraeffect = EffectInfo.EF_ELIDABLE_CANNOT_RAISE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -263,7 +265,7 @@ def calldescr_canraise(self, calldescr): effectinfo = calldescr.get_extra_info() return (effectinfo is None or - effectinfo.extraeffect >= EffectInfo.EF_CAN_RAISE) + effectinfo.extraeffect > EffectInfo.EF_CANNOT_RAISE) def jitdriver_sd_from_portal_graph(self, graph): for jd in self.jitdrivers_sd: diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,10 +9,11 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_ELIDABLE = 0 #elidable function (and cannot raise) + EF_ELIDABLE_CANNOT_RAISE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise - EF_CAN_RAISE = 3 #normal function (can raise) + EF_ELIDABLE_CAN_RAISE = 3 #elidable function (but can raise) + EF_CAN_RAISE = 4 #normal function (can raise) EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables # the 'oopspecindex' field is one of the following values: @@ -94,7 +95,8 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_ELIDABLE: + extraeffect == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \ + extraeffect == EffectInfo.EF_ELIDABLE_CAN_RAISE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -902,7 +902,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1363,15 +1363,15 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_ELIDABLE, because it can raise - # UnicodeDecodeError... - return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) + # ll_str2unicode can raise UnicodeDecodeError + return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE, + EffectInfo.EF_ELIDABLE_CAN_RAISE) # ---------- # VirtualRefs. @@ -1415,7 +1415,7 @@ def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -20,6 +20,7 @@ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.jit.metainterp.typesystem import deref from pypy.rlib import rgc +from pypy.rlib.jit import elidable from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask def getargtypes(annotator, values): @@ -167,9 +168,14 @@ _ll_5_list_ll_arraycopy = rgc.ll_arraycopy + at elidable def _ll_1_gc_identityhash(x): return lltype.identityhash(x) +# the following function should not be "@elidable": I can think of +# a corner case in which id(const) is constant-folded, and then 'const' +# disappears and is collected too early (possibly causing another object +# with the same id() to appear). def _ll_1_gc_id(ptr): return llop.gc_id(lltype.Signed, ptr) diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -120,9 +120,9 @@ assert argtypes[0] == [v.concretetype for v in op.args[1:]] assert argtypes[1] == op.result.concretetype if oopspecindex == EI.OS_STR2UNICODE: - assert extraeffect == None # not pure, can raise! + assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE else: - assert extraeffect == EI.EF_ELIDABLE + assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -55,7 +55,7 @@ def optimize_loop_1(metainterp_sd, loop, enable_opts, - inline_short_preamble=True, retraced=False): + inline_short_preamble=True, retraced=False, bridge=False): """Optimize loop.operations to remove internal overheadish operations. """ @@ -64,7 +64,7 @@ if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: - optimizer = Optimizer(metainterp_sd, loop, optimizations) + optimizer = Optimizer(metainterp_sd, loop, optimizations, bridge) optimizer.propagate_all_forward() def optimize_bridge_1(metainterp_sd, bridge, enable_opts, @@ -76,7 +76,7 @@ except KeyError: pass optimize_loop_1(metainterp_sd, bridge, enable_opts, - inline_short_preamble, retraced) + inline_short_preamble, retraced, bridge=True) if __name__ == '__main__': print ALL_OPTS_NAMES diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -248,10 +248,11 @@ class Optimizer(Optimization): - def __init__(self, metainterp_sd, loop, optimizations=None): + def __init__(self, metainterp_sd, loop, optimizations=None, bridge=False): self.metainterp_sd = metainterp_sd self.cpu = metainterp_sd.cpu self.loop = loop + self.bridge = bridge self.values = {} self.interned_refs = self.cpu.ts.new_ref_dict() self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd) @@ -407,9 +408,7 @@ return CVAL_ZERO def propagate_all_forward(self): - self.exception_might_have_happened = True - # ^^^ at least at the start of bridges. For loops, we could set - # it to False, but we probably don't care + self.exception_might_have_happened = self.bridge self.newoperations = [] self.first_optimization.propagate_begin_forward() self.i = 0 diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -693,7 +693,6 @@ """ expected = """ [i] - guard_no_exception() [] i1 = int_add(i, 3) i2 = call(i1, descr=nonwritedescr) guard_no_exception() [i1, i2] diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -889,12 +889,10 @@ i3 = call(i2, descr=nonwritedescr) jump(i1) # the exception is considered lost when we loop back """ - # note that 'guard_no_exception' at the very start must be kept - # around: bridges may start with one. (In case of loops we could - # remove it, but we probably don't care.) + # note that 'guard_no_exception' at the very start is kept around + # for bridges, but not for loops preamble = """ [i] - guard_no_exception() [] i1 = int_add(i, 3) i2 = call(i1, descr=nonwritedescr) guard_no_exception() [i1, i2] @@ -2993,6 +2991,38 @@ ''' self.optimize_loop(ops, expected, preamble, call_pure_results) + def test_call_pure_constant_folding_exc(self): + # CALL_PURE may be followed by GUARD_NO_EXCEPTION + arg_consts = [ConstInt(i) for i in (123456, 4, 5, 6)] + call_pure_results = {tuple(arg_consts): ConstInt(42)} + ops = ''' + [i0, i1, i2] + escape(i1) + escape(i2) + i3 = call_pure(123456, 4, 5, 6, descr=plaincalldescr) + guard_no_exception() [] + i4 = call_pure(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i3, i4) + ''' + preamble = ''' + [i0, i1, i2] + escape(i1) + escape(i2) + i4 = call(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i4) + ''' + expected = ''' + [i0, i2] + escape(42) + escape(i2) + i4 = call(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i4) + ''' + self.optimize_loop(ops, expected, preamble, call_pure_results) + # ---------- def test_vref_nonvirtual_nonescape(self): diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -543,8 +543,10 @@ elif opnum == rop.CALL: effectinfo = descr.get_extra_info() if effectinfo is not None: - if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: + ef = effectinfo.extraeffect + if ef == EffectInfo.EF_LOOPINVARIANT or \ + ef == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \ + ef == EffectInfo.EF_ELIDABLE_CAN_RAISE: return True return False diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1199,7 +1199,7 @@ return self.metainterp.execute_and_record(opnum, descr, *argboxes) @specialize.arg(1) - def execute_varargs(self, opnum, argboxes, descr, exc): + def execute_varargs(self, opnum, argboxes, descr, exc, pure): self.metainterp.clear_exception() resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes, descr=descr) @@ -1207,6 +1207,9 @@ self.make_result_of_lastop(resbox) # ^^^ this is done before handle_possible_exception() because we # need the box to show up in get_list_of_active_boxes() + if pure and self.metainterp.last_exc_value_box is None: + resbox = self.metainterp.record_result_of_call_pure(resbox) + exc = exc and not isinstance(resbox, Const) if exc: self.metainterp.handle_possible_exception() else: @@ -1269,16 +1272,14 @@ return resbox else: effect = effectinfo.extraeffect - if effect == effectinfo.EF_CANNOT_RAISE: - return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_ELIDABLE: - return self.metainterp.record_result_of_call_pure( - self.execute_varargs(rop.CALL, allboxes, descr, False)) - elif effect == effectinfo.EF_LOOPINVARIANT: + if effect == effectinfo.EF_LOOPINVARIANT: return self.execute_varargs(rop.CALL_LOOPINVARIANT, allboxes, - descr, False) - else: - return self.execute_varargs(rop.CALL, allboxes, descr, True) + descr, False, False) + exc = (effect != effectinfo.EF_CANNOT_RAISE and + effect != effectinfo.EF_ELIDABLE_CANNOT_RAISE) + pure = (effect == effectinfo.EF_ELIDABLE_CAN_RAISE or + effect == effectinfo.EF_ELIDABLE_CANNOT_RAISE) + return self.execute_varargs(rop.CALL, allboxes, descr, exc, pure) def do_residual_or_indirect_call(self, funcbox, calldescr, argboxes): """The 'residual_call' operation is emitted in two cases: @@ -1686,8 +1687,12 @@ return if opnum == rop.CALL: effectinfo = descr.get_extra_info() - if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: - return + if effectinfo is not None: + ef = effectinfo.extraeffect + if ef == effectinfo.EF_LOOPINVARIANT or \ + ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or \ + ef == effectinfo.EF_ELIDABLE_CAN_RAISE: + return if self.heap_cache: self.heap_cache.clear() if self.heap_array_cache: @@ -2375,6 +2380,7 @@ tobox = newbox if change: self.heap_cache[descr] = frombox, tobox + # XXX what about self.heap_array_cache? def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -277,3 +277,15 @@ NODE._add_fields({'value': ootype.Signed, 'next': NODE}) return NODE + +# ____________________________________________________________ + +class _Foo: + pass + +def noConst(x): + """Helper function for tests, returning 'x' as a BoxInt/BoxPtr + even if it is a ConstInt/ConstPtr.""" + f1 = _Foo(); f2 = _Foo() + f1.x = x; f2.x = 0 + return f1.x diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -14,7 +14,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT -from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, noConst class BasicTests: @@ -407,6 +407,58 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=0) + def test_elidable_raising(self): + myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable + def externfn(x): + if x <= 0: + raise ValueError + return x - 1 + def f(n, m): + while n > 0: + myjitdriver.can_enter_jit(n=n, m=m) + myjitdriver.jit_merge_point(n=n, m=m) + try: + n -= externfn(m) + except ValueError: + n -= 1 + return n + res = self.meta_interp(f, [22, 6]) + assert res == -3 + # the CALL_PURE is constant-folded away during tracing + self.check_loops(int_sub=1, call=0, call_pure=0) + # + res = self.meta_interp(f, [22, -5]) + assert res == 0 + # raises: becomes CALL and is not constant-folded away + self.check_loops(int_sub=1, call=1, call_pure=0) + + def test_elidable_raising_2(self): + myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable + def externfn(x): + if x <= 0: + raise ValueError + return x - 1 + def f(n, m): + while n > 0: + myjitdriver.can_enter_jit(n=n, m=m) + myjitdriver.jit_merge_point(n=n, m=m) + try: + n -= externfn(noConst(m)) + except ValueError: + n -= 1 + return n + res = self.meta_interp(f, [22, 6]) + assert res == -3 + # the CALL_PURE is constant-folded away by optimizeopt.py + self.check_loops(int_sub=1, call=0, call_pure=0) + # + res = self.meta_interp(f, [22, -5]) + assert res == 0 + # raises: becomes CALL and is not constant-folded away + self.check_loops(int_sub=1, call=1, call_pure=0) + def test_constant_across_mp(self): myjitdriver = JitDriver(greens = [], reds = ['n']) class X(object): diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -157,7 +157,7 @@ # the same arguments are not folded, because we have conflicting # definitions of pure, once strhash can be appropriately folded # this should be decreased to seven. - self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 6, "guard_true": 1, "int_and": 1, "int_gt": 1, "int_is_true": 1, "int_sub": 1, "jump": 1, "new_with_vtable": 1, "setfield_gc": 1}) diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py --- a/pypy/jit/metainterp/test/test_string.py +++ b/pypy/jit/metainterp/test/test_string.py @@ -358,3 +358,22 @@ self.check_loops(call=3, # str(), _str(), escape() newunicode=1, unicodegetitem=0, unicodesetitem=1, copyunicodecontent=1) + + def test_str2unicode_fold(self): + _str = self._str + jitdriver = JitDriver(greens = ['g'], reds = ['m']) + @dont_look_inside + def escape(x): + print str(x) + def f(g, m): + g = str(g) + while m >= 0: + jitdriver.can_enter_jit(g=g, m=m) + jitdriver.jit_merge_point(g=g, m=m) + escape(_str(g)) + m -= 1 + return 42 + self.meta_interp(f, [6, 7]) + self.check_loops(call_pure=0, call=1, + newunicode=0, unicodegetitem=0, + unicodesetitem=0, copyunicodecontent=0) diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -409,6 +409,7 @@ jd.warmstate = state def crash_in_jit(e): + tb = not we_are_translated() and sys.exc_info()[2] try: raise e except JitException: @@ -422,8 +423,8 @@ print "~~~ Crash in JIT!" print '~~~ %s: %s' % (e.__class__, e) if sys.stdout == sys.__stdout__: - import pdb; pdb.post_mortem(sys.exc_info()[2]) - raise + import pdb; pdb.post_mortem(tb) + raise e.__class__, e, tb fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) crash_in_jit._dont_inline_ = True diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -20,7 +20,8 @@ Most importantly it doesn't mean that an elidable function has no observable side effect, but those side effects are idempotent (ie caching). - For now, such a function should never raise an exception. + The function can raise an exception, in which case this decorator is + ignored. """ func._elidable_function_ = True return func From noreply at buildbot.pypy.org Thu Jul 28 18:17:26 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 18:17:26 +0200 (CEST) Subject: [pypy-commit] pypy default: Clarify. Message-ID: <20110728161726.EFE5182110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46054:86f2dedf6790 Date: 2011-07-28 18:17 +0200 http://bitbucket.org/pypy/pypy/changeset/86f2dedf6790/ Log: Clarify. diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -20,8 +20,8 @@ Most importantly it doesn't mean that an elidable function has no observable side effect, but those side effects are idempotent (ie caching). - The function can raise an exception, in which case this decorator is - ignored. + If a particular call to this function ends up raising an exception, then it + is handled like a normal function call (this decorator is ignored). """ func._elidable_function_ = True return func From noreply at buildbot.pypy.org Thu Jul 28 20:23:23 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 28 Jul 2011 20:23:23 +0200 (CEST) Subject: [pypy-commit] pypy default: Make this function do what was intended. Message-ID: <20110728182323.7855182110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46055:2d6634aa99eb Date: 2011-07-28 11:23 -0700 http://bitbucket.org/pypy/pypy/changeset/2d6634aa99eb/ Log: Make this function do what was intended. diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -95,8 +95,7 @@ d = {"func": func, "hint": hint} exec py.code.Source("\n".join(code)).compile() in d result = d["f"] - functools.wraps(func)(result) - return result + return functools.wraps(func)(result) return decorator def purefunction_promote(*args, **kwargs): From noreply at buildbot.pypy.org Thu Jul 28 20:32:08 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 28 Jul 2011 20:32:08 +0200 (CEST) Subject: [pypy-commit] pypy default: Rollback the use of functools here, I want to be sure I didn't break stuff. Message-ID: <20110728183208.9DE0482110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46056:129b4f6d202e Date: 2011-07-28 11:32 -0700 http://bitbucket.org/pypy/pypy/changeset/129b4f6d202e/ Log: Rollback the use of functools here, I want to be sure I didn't break stuff. diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -1,14 +1,10 @@ -import functools +import py import sys - -import py - +from pypy.rpython.extregistry import ExtRegistryEntry +from pypy.rlib.objectmodel import CDefinedIntSymbolic +from pypy.rlib.objectmodel import keepalive_until_here, specialize +from pypy.rlib.unroll import unrolling_iterable from pypy.rlib.nonconst import NonConstant -from pypy.rlib.objectmodel import (CDefinedIntSymbolic, keepalive_until_here, - specialize) -from pypy.rlib.unroll import unrolling_iterable -from pypy.rpython.extregistry import ExtRegistryEntry - def elidable(func): """ Decorate a function as "trace-elidable". This means precisely that: @@ -95,7 +91,8 @@ d = {"func": func, "hint": hint} exec py.code.Source("\n".join(code)).compile() in d result = d["f"] - return functools.wraps(func)(result) + result.func_name = func.func_name + "_promote" + return result return decorator def purefunction_promote(*args, **kwargs): @@ -283,7 +280,7 @@ def specialize_call(self, hop): pass - + vref_None = non_virtual_ref(None) # ____________________________________________________________ @@ -293,7 +290,7 @@ """Inconsistency in the JIT hints.""" PARAMETERS = {'threshold': 1032, # just above 1024 - 'function_threshold': 1617, # slightly more than one above + 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, 'inlining': 1, @@ -403,7 +400,7 @@ raise set_user_param._annspecialcase_ = 'specialize:arg(0)' - + def on_compile(self, logger, looptoken, operations, type, *greenargs): """ A hook called when loop is compiled. Overwrite for your own jitdriver if you want to do something special, like From noreply at buildbot.pypy.org Thu Jul 28 21:47:34 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 21:47:34 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: A branch in which to support singlefloats in the JIT. Message-ID: <20110728194734.F294E82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46057:3f9d39062ded Date: 2011-07-28 21:46 +0200 http://bitbucket.org/pypy/pypy/changeset/3f9d39062ded/ Log: A branch in which to support singlefloats in the JIT. From noreply at buildbot.pypy.org Thu Jul 28 21:47:36 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 21:47:36 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Add byte-by-byte conversion between ints and singlefloats. Message-ID: <20110728194736.2EAA382110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46058:619cf7b82467 Date: 2011-07-28 15:42 +0200 http://bitbucket.org/pypy/pypy/changeset/619cf7b82467/ Log: Add byte-by-byte conversion between ints and singlefloats. diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -11,6 +11,8 @@ # -------- implement longlong2float and float2longlong -------- DOUBLE_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.DOUBLE)) LONGLONG_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.LONGLONG)) +INT_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.INT)) +FLOAT_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.FLOAT)) # these definitions are used only in tests, when not translated def longlong2float_emulator(llval): @@ -29,6 +31,22 @@ lltype.free(d_array, flavor='raw') return llval +def int2singlefloat_emulator(ival): + f_array = lltype.malloc(FLOAT_ARRAY_PTR.TO, 1, flavor='raw') + i_array = rffi.cast(INT_ARRAY_PTR, f_array) + i_array[0] = ival + singlefloatval = f_array[0] + lltype.free(f_array, flavor='raw') + return singlefloatval + +def singlefloat2int_emulator(singlefloatval): + f_array = lltype.malloc(FLOAT_ARRAY_PTR.TO, 1, flavor='raw') + i_array = rffi.cast(INT_ARRAY_PTR, f_array) + f_array[0] = singlefloatval + ival = i_array[0] + lltype.free(f_array, flavor='raw') + return ival + from pypy.translator.tool.cbuild import ExternalCompilationInfo eci = ExternalCompilationInfo(includes=['string.h', 'assert.h'], post_include_bits=[""" @@ -44,6 +62,18 @@ memcpy(&ll, &x, 8); return ll; } +static float pypy__int2singlefloat(int x) { + float ff; + assert(sizeof(float) == 4 && sizeof(int) == 4); + memcpy(&ff, &x, 4); + return ff; +} +static int pypy__singlefloat2int(float x) { + int ii; + assert(sizeof(float) == 4 && sizeof(int) == 4); + memcpy(&ii, &x, 4); + return ii; +} """]) longlong2float = rffi.llexternal( @@ -55,3 +85,13 @@ "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG, _callable=float2longlong_emulator, compilation_info=eci, _nowrapper=True, elidable_function=True) + +int2singlefloat = rffi.llexternal( + "pypy__int2singlefloat", [rffi.INT], rffi.FLOAT, + _callable=int2singlefloat_emulator, compilation_info=eci, + _nowrapper=True, elidable_function=True) + +singlefloat2int = rffi.llexternal( + "pypy__singlefloat2int", [rffi.FLOAT], rffi.INT, + _callable=singlefloat2int_emulator, compilation_info=eci, + _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/test/test_longlong2float.py b/pypy/rlib/test/test_longlong2float.py --- a/pypy/rlib/test/test_longlong2float.py +++ b/pypy/rlib/test/test_longlong2float.py @@ -1,5 +1,7 @@ from pypy.translator.c.test.test_genc import compile from pypy.rlib.longlong2float import longlong2float, float2longlong +from pypy.rlib.longlong2float import int2singlefloat, singlefloat2int +from pypy.rlib.rarithmetic import r_singlefloat def fn(f1): @@ -28,3 +30,23 @@ for x in enum_floats(): res = fn2(x) assert repr(res) == repr(x) + +# ____________________________________________________________ + +def fnsingle(f1): + sf1 = r_singlefloat(f1) + ii = singlefloat2int(sf1) + sf2 = int2singlefloat(ii) + f2 = float(sf2) + return f2 + +def test_int_as_singlefloat(): + for x in enum_floats(): + res = fnsingle(x) + assert repr(res) == repr(float(r_singlefloat(x))) + +def test_compiled_single(): + fn2 = compile(fnsingle, [float]) + for x in enum_floats(): + res = fn2(x) + assert repr(res) == repr(float(r_singlefloat(x))) From noreply at buildbot.pypy.org Thu Jul 28 21:47:37 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 21:47:37 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Front-end support for singlefloats. Message-ID: <20110728194737.7206D82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46059:af30af85a7b1 Date: 2011-07-28 15:52 +0200 http://bitbucket.org/pypy/pypy/changeset/af30af85a7b1/ Log: Front-end support for singlefloats. diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -91,6 +91,7 @@ class BaseCPU(model.AbstractCPU): supports_floats = True supports_longlong = llimpl.IS_32_BIT + supports_singlefloats = True def __init__(self, rtyper, stats=None, opts=None, translate_support_code=False, diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -9,7 +9,7 @@ from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, c_last_exception from pypy.rlib import objectmodel from pypy.rlib.jit import _we_are_jitted -from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass +from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass, rffi from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY from pypy.translator.simplify import get_funcobj from pypy.translator.unsimplify import varoftype @@ -785,7 +785,6 @@ op2.result = op.result return op2 elif toll: - from pypy.rpython.lltypesystem import rffi size, unsigned = rffi.size_and_sign(op.args[0].concretetype) if unsigned: INTERMEDIATE = lltype.Unsigned @@ -807,20 +806,27 @@ return self.force_cast_without_longlong(op.args[0], op.result) def force_cast_without_longlong(self, v_arg, v_result): - from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT - # - if (v_result.concretetype in (FLOAT, lltype.Float) or - v_arg.concretetype in (FLOAT, lltype.Float)): - assert (v_result.concretetype == lltype.Float and - v_arg.concretetype == lltype.Float), "xxx unsupported cast" + if v_result.concretetype == v_arg.concretetype: return - # - size2, unsigned2 = size_and_sign(v_result.concretetype) - assert size2 <= sizeof(lltype.Signed) - if size2 == sizeof(lltype.Signed): + if v_arg.concretetype == rffi.FLOAT: + assert v_result.concretetype == lltype.Float, "cast %s -> %s" % ( + v_arg.concretetype, v_result.concretetype) + return SpaceOperation('cast_singlefloat_to_float', [v_arg], + v_result) + if v_result.concretetype == rffi.FLOAT: + assert v_arg.concretetype == lltype.Float, "cast %s -> %s" % ( + v_arg.concretetype, v_result.concretetype) + return SpaceOperation('cast_float_to_singlefloat', [v_arg], + v_result) + return self.force_cast_without_singlefloat(v_arg, v_result) + + def force_cast_without_singlefloat(self, v_arg, v_result): + size2, unsigned2 = rffi.size_and_sign(v_result.concretetype) + assert size2 <= rffi.sizeof(lltype.Signed) + if size2 == rffi.sizeof(lltype.Signed): return # the target type is LONG or ULONG - size1, unsigned1 = size_and_sign(v_arg.concretetype) - assert size1 <= sizeof(lltype.Signed) + size1, unsigned1 = rffi.size_and_sign(v_arg.concretetype) + assert size1 <= rffi.sizeof(lltype.Signed) # def bounds(size, unsigned): if unsigned: @@ -849,7 +855,6 @@ return result def rewrite_op_direct_ptradd(self, op): - from pypy.rpython.lltypesystem import rffi # xxx otherwise, not implemented: assert op.args[0].concretetype == rffi.CCHARP # diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -12,6 +12,7 @@ self.unsafe_loopy_graphs = set() self.supports_floats = False self.supports_longlong = False + self.supports_singlefloats = False def set_supports_floats(self, flag): self.supports_floats = flag @@ -19,6 +20,9 @@ def set_supports_longlong(self, flag): self.supports_longlong = flag + def set_supports_singlefloats(self, flag): + self.supports_singlefloats = flag + def dump_unsafe_loops(self): f = udir.join("unsafe-loops.txt").open('w') strs = [str(graph) for graph in self.unsafe_loopy_graphs] @@ -58,8 +62,9 @@ func, '_jit_unroll_safe_', False) unsupported = contains_unsupported_variable_type(graph, - self.supports_floats, - self.supports_longlong) + self.supports_floats, + self.supports_longlong, + self.supports_singlefloats) res = see_function and not unsupported if res and contains_loop: self.unsafe_loopy_graphs.add(graph) @@ -80,17 +85,24 @@ return res def contains_unsupported_variable_type(graph, supports_floats, - supports_longlong): + supports_longlong, + supports_singlefloats): getkind = history.getkind try: for block in graph.iterblocks(): for v in block.inputargs: - getkind(v.concretetype, supports_floats, supports_longlong) + getkind(v.concretetype, supports_floats, + supports_longlong, + supports_singlefloats) for op in block.operations: for v in op.args: - getkind(v.concretetype, supports_floats, supports_longlong) + getkind(v.concretetype, supports_floats, + supports_longlong, + supports_singlefloats) v = op.result - getkind(v.concretetype, supports_floats, supports_longlong) + getkind(v.concretetype, supports_floats, + supports_longlong, + supports_singlefloats) except NotImplementedError, e: log.WARNING('%s, ignoring graph' % (e,)) log.WARNING(' %s' % (graph,)) diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py --- a/pypy/jit/codewriter/test/test_policy.py +++ b/pypy/jit/codewriter/test/test_policy.py @@ -12,24 +12,30 @@ graph = support.getgraph(f, [5]) for sf in [False, True]: for sll in [False, True]: - assert not contains_unsupported_variable_type(graph, sf, sll) + for ssf in [False, True]: + assert not contains_unsupported_variable_type(graph, sf, + sll, ssf) # graph = support.getgraph(f, [5.5]) for sf in [False, True]: for sll in [False, True]: - res = contains_unsupported_variable_type(graph, sf, sll) - assert res is not sf + for ssf in [False, True]: + res = contains_unsupported_variable_type(graph, sf, sll, ssf) + assert res is not sf # graph = support.getgraph(f, [r_singlefloat(5.5)]) for sf in [False, True]: for sll in [False, True]: - assert contains_unsupported_variable_type(graph, sf, sll) + for ssf in [False, True]: + res = contains_unsupported_variable_type(graph, sf, sll, ssf) + assert res == (not ssf) # graph = support.getgraph(f, [r_longlong(5)]) for sf in [False, True]: for sll in [False, True]: - res = contains_unsupported_variable_type(graph, sf, sll) - assert res == (sys.maxint == 2147483647 and not sll) + for ssf in [False, True]: + res = contains_unsupported_variable_type(graph, sf, sll, ssf) + assert res == (sys.maxint == 2147483647 and not sll) def test_regular_function(): diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -623,6 +623,23 @@ x = float(a) return longlong.getfloatstorage(x) + @arguments("f", returns="i") + def bhimpl_cast_float_to_singlefloat(a): + from pypy.rlib.rarithmetic import r_singlefloat + from pypy.rlib.longlong2float import singlefloat2uint + a = longlong.getrealfloat(a) + a = r_singlefloat(a) + a = singlefloat2uint(a) + return intmask(a) + + @arguments("i", returns="f") + def bhimpl_cast_singlefloat_to_float(a): + from pypy.rpython.lltypesystem.rffi import r_uint + from pypy.rlib.longlong2float import uint2singlefloat + a = uint2singlefloat(r_uint(a)) + a = float(a) + return longlong.getfloatstorage(a) + # ---------- # control flow operations diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -20,12 +20,16 @@ FAILARGS_LIMIT = 1000 -def getkind(TYPE, supports_floats=True, supports_longlong=True): +def getkind(TYPE, supports_floats=True, + supports_longlong=True, + supports_singlefloats=True): if TYPE is lltype.Void: return "void" elif isinstance(TYPE, lltype.Primitive): if TYPE is lltype.Float and supports_floats: return 'float' + if TYPE is lltype.SingleFloat and supports_singlefloats: + return 'int' # singlefloats are stored in an int if TYPE in (lltype.Float, lltype.SingleFloat): raise NotImplementedError("type %s not supported" % TYPE) # XXX fix this for oo... diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -215,6 +215,7 @@ for _opimpl in ['int_is_true', 'int_is_zero', 'int_neg', 'int_invert', 'cast_float_to_int', 'cast_int_to_float', + 'cast_float_to_singlefloat', 'cast_singlefloat_to_float', 'float_neg', 'float_abs', ]: exec py.code.Source(''' diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -408,6 +408,8 @@ 'FLOAT_ABS/1', 'CAST_FLOAT_TO_INT/1', 'CAST_INT_TO_FLOAT/1', + 'CAST_FLOAT_TO_SINGLEFLOAT/1', + 'CAST_SINGLEFLOAT_TO_FLOAT/1', # 'INT_LT/2b', 'INT_LE/2b', diff --git a/pypy/jit/metainterp/test/test_float.py b/pypy/jit/metainterp/test/test_float.py --- a/pypy/jit/metainterp/test/test_float.py +++ b/pypy/jit/metainterp/test/test_float.py @@ -36,6 +36,15 @@ res = self.interp_operations(f, [x]) assert res == -x + def test_singlefloat(self): + from pypy.rlib.rarithmetic import r_singlefloat + def f(a): + a = float(r_singlefloat(a)) + a *= 4.25 + return float(r_singlefloat(a)) + res = self.interp_operations(f, [-2.0]) + assert res == -8.5 + class TestOOtype(FloatTests, OOJitMixin): pass diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -173,6 +173,7 @@ policy = JitPolicy() policy.set_supports_floats(self.cpu.supports_floats) policy.set_supports_longlong(self.cpu.supports_longlong) + policy.set_supports_singlefloats(self.cpu.supports_singlefloats) graphs = self.codewriter.find_all_graphs(policy) policy.dump_unsafe_loops() self.check_access_directly_sanity(graphs) diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py --- a/pypy/rlib/longlong2float.py +++ b/pypy/rlib/longlong2float.py @@ -11,7 +11,7 @@ # -------- implement longlong2float and float2longlong -------- DOUBLE_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.DOUBLE)) LONGLONG_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.LONGLONG)) -INT_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.INT)) +UINT_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.UINT)) FLOAT_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.FLOAT)) # these definitions are used only in tests, when not translated @@ -31,17 +31,17 @@ lltype.free(d_array, flavor='raw') return llval -def int2singlefloat_emulator(ival): +def uint2singlefloat_emulator(ival): f_array = lltype.malloc(FLOAT_ARRAY_PTR.TO, 1, flavor='raw') - i_array = rffi.cast(INT_ARRAY_PTR, f_array) + i_array = rffi.cast(UINT_ARRAY_PTR, f_array) i_array[0] = ival singlefloatval = f_array[0] lltype.free(f_array, flavor='raw') return singlefloatval -def singlefloat2int_emulator(singlefloatval): +def singlefloat2uint_emulator(singlefloatval): f_array = lltype.malloc(FLOAT_ARRAY_PTR.TO, 1, flavor='raw') - i_array = rffi.cast(INT_ARRAY_PTR, f_array) + i_array = rffi.cast(UINT_ARRAY_PTR, f_array) f_array[0] = singlefloatval ival = i_array[0] lltype.free(f_array, flavor='raw') @@ -62,15 +62,15 @@ memcpy(&ll, &x, 8); return ll; } -static float pypy__int2singlefloat(int x) { +static float pypy__uint2singlefloat(unsigned int x) { float ff; - assert(sizeof(float) == 4 && sizeof(int) == 4); + assert(sizeof(float) == 4 && sizeof(unsigned int) == 4); memcpy(&ff, &x, 4); return ff; } -static int pypy__singlefloat2int(float x) { - int ii; - assert(sizeof(float) == 4 && sizeof(int) == 4); +static unsigned int pypy__singlefloat2uint(float x) { + unsigned int ii; + assert(sizeof(float) == 4 && sizeof(unsigned int) == 4); memcpy(&ii, &x, 4); return ii; } @@ -86,12 +86,12 @@ _callable=float2longlong_emulator, compilation_info=eci, _nowrapper=True, elidable_function=True) -int2singlefloat = rffi.llexternal( - "pypy__int2singlefloat", [rffi.INT], rffi.FLOAT, - _callable=int2singlefloat_emulator, compilation_info=eci, +uint2singlefloat = rffi.llexternal( + "pypy__uint2singlefloat", [rffi.UINT], rffi.FLOAT, + _callable=uint2singlefloat_emulator, compilation_info=eci, _nowrapper=True, elidable_function=True) -singlefloat2int = rffi.llexternal( - "pypy__singlefloat2int", [rffi.FLOAT], rffi.INT, - _callable=singlefloat2int_emulator, compilation_info=eci, +singlefloat2uint = rffi.llexternal( + "pypy__singlefloat2uint", [rffi.FLOAT], rffi.UINT, + _callable=singlefloat2uint_emulator, compilation_info=eci, _nowrapper=True, elidable_function=True) diff --git a/pypy/rlib/test/test_longlong2float.py b/pypy/rlib/test/test_longlong2float.py --- a/pypy/rlib/test/test_longlong2float.py +++ b/pypy/rlib/test/test_longlong2float.py @@ -1,6 +1,6 @@ from pypy.translator.c.test.test_genc import compile from pypy.rlib.longlong2float import longlong2float, float2longlong -from pypy.rlib.longlong2float import int2singlefloat, singlefloat2int +from pypy.rlib.longlong2float import uint2singlefloat, singlefloat2uint from pypy.rlib.rarithmetic import r_singlefloat @@ -35,8 +35,8 @@ def fnsingle(f1): sf1 = r_singlefloat(f1) - ii = singlefloat2int(sf1) - sf2 = int2singlefloat(ii) + ii = singlefloat2uint(sf1) + sf2 = uint2singlefloat(ii) f2 = float(sf2) return f2 From noreply at buildbot.pypy.org Thu Jul 28 21:47:38 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 21:47:38 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Support for singlefloats in the x86 backend. Message-ID: <20110728194738.B263A82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46060:8f707b9d14a7 Date: 2011-07-28 16:12 +0200 http://bitbucket.org/pypy/pypy/changeset/8f707b9d14a7/ Log: Support for singlefloats in the x86 backend. diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -1267,6 +1267,20 @@ def genop_cast_int_to_float(self, op, arglocs, resloc): self.mc.CVTSI2SD(resloc, arglocs[0]) + def genop_cast_float_to_singlefloat(self, op, arglocs, resloc): + loc0, loctmp = arglocs + self.mc.CVTSD2SS(loctmp, loc0) + assert isinstance(resloc, RegLoc) + assert isinstance(loctmp, RegLoc) + self.mc.MOVD_rx(resloc.value, loctmp.value) + + def genop_cast_singlefloat_to_float(self, op, arglocs, resloc): + loc0, = arglocs + assert isinstance(resloc, RegLoc) + assert isinstance(loc0, RegLoc) + self.mc.MOVD_xr(resloc.value, loc0.value) + self.mc.CVTSS2SD_xx(resloc.value, resloc.value) + def genop_guard_int_is_true(self, op, guard_op, guard_token, arglocs, resloc): guard_opnum = guard_op.getopnum() self.mc.CMP(arglocs[0], imm0) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -705,6 +705,17 @@ self.Perform(op, [loc0], loc1) self.rm.possibly_free_var(op.getarg(0)) + def consider_cast_float_to_singlefloat(self, op): + loc0 = self.xrm.make_sure_var_in_reg(op.getarg(0)) + loc1 = self.rm.force_allocate_reg(op.result) + self.xrm.possibly_free_var(op.getarg(0)) + tmpxvar = TempBox() + loctmp = self.xrm.force_allocate_reg(tmpxvar) # may be equal to loc0 + self.xrm.possibly_free_var(tmpxvar) + self.Perform(op, [loc0, loctmp], loc1) + + consider_cast_singlefloat_to_float = consider_cast_int_to_float + def _consider_llong_binop_xx(self, op): # must force both arguments into xmm registers, because we don't # know if they will be suitably aligned. Exception: if the second diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -521,6 +521,8 @@ UCOMISD = _binaryop('UCOMISD') CVTSI2SD = _binaryop('CVTSI2SD') CVTTSD2SI = _binaryop('CVTTSD2SI') + CVTSD2SS = _binaryop('CVTSD2SS') + CVTSS2SD = _binaryop('CVTSS2SD') SQRTSD = _binaryop('SQRTSD') diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py --- a/pypy/jit/backend/x86/runner.py +++ b/pypy/jit/backend/x86/runner.py @@ -19,6 +19,7 @@ class AbstractX86CPU(AbstractLLCPU): debug = True supports_floats = True + supports_singlefloats = True BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) dont_keepalive_stuff = False # for tests diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -590,6 +590,15 @@ CVTTSD2SI_rx = xmminsn('\xF2', rex_w, '\x0F\x2C', register(1, 8), register(2), '\xC0') CVTTSD2SI_rb = xmminsn('\xF2', rex_w, '\x0F\x2C', register(1, 8), stack_bp(2)) + CVTSD2SS_xx = xmminsn('\xF2', rex_nw, '\x0F\x5A', + register(1, 8), register(2), '\xC0') + CVTSD2SS_xb = xmminsn('\xF2', rex_nw, '\x0F\x5A', + register(1, 8), stack_bp(2)) + CVTSS2SD_xx = xmminsn('\xF3', rex_nw, '\x0F\x5A', + register(1, 8), register(2), '\xC0') + CVTSS2SD_xb = xmminsn('\xF3', rex_nw, '\x0F\x5A', + register(1, 8), stack_bp(2)) + MOVD_rx = xmminsn('\x66', rex_w, '\x0F\x7E', register(2, 8), register(1), '\xC0') MOVD_xr = xmminsn('\x66', rex_w, '\x0F\x6E', register(1, 8), register(2), '\xC0') diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py --- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py +++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py @@ -185,7 +185,8 @@ # Special case: On 64-bit CPUs, rx86 assumes 64-bit integer # operands when converting to/from floating point, so we need to # indicate that with a suffix - if (self.WORD == 8) and instrname.startswith('CVT'): + if (self.WORD == 8) and (instrname.startswith('CVT') and + 'SI' in instrname): suffix = suffixes[self.WORD] if instr_suffix is not None: From noreply at buildbot.pypy.org Thu Jul 28 21:47:39 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 21:47:39 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Progress. Message-ID: <20110728194739.EE7FE82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46061:6d025e690834 Date: 2011-07-28 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/6d025e690834/ Log: Progress. diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -303,6 +303,8 @@ c = 'f' elif c == 'f' and longlong.supports_longlong: return 'longlong.getrealfloat(%s)' % (process('L'),) + elif c == 'S': + return 'longlong.int2singlefloat(%s)' % (process('i'),) arg = 'args_%s[%d]' % (c, seen[c]) seen[c] += 1 return arg @@ -318,6 +320,8 @@ return lltype.Void elif arg == 'L': return lltype.SignedLongLong + elif arg == 'S': + return lltype.SingleFloat else: raise AssertionError(arg) @@ -334,6 +338,8 @@ result = 'rffi.cast(lltype.SignedLongLong, res)' elif self.get_return_type() == history.VOID: result = 'None' + elif self.get_return_type() == 'S': + result = 'longlong.singlefloat2int(res)' else: assert 0 source = py.code.Source(""" @@ -344,14 +350,15 @@ """ % locals()) ARGS = [TYPE(arg) for arg in self.arg_classes] FUNC = lltype.FuncType(ARGS, RESULT) - d = locals().copy() - d.update(globals()) + d = globals().copy() + d.update(locals()) exec source.compile() in d self.call_stub = d['call_stub'] def verify_types(self, args_i, args_r, args_f, return_type): assert self._return_type in return_type - assert self.arg_classes.count('i') == len(args_i or ()) + assert (self.arg_classes.count('i') + + self.arg_classes.count('S')) == len(args_i or ()) assert self.arg_classes.count('r') == len(args_r or ()) assert (self.arg_classes.count('f') + self.arg_classes.count('L')) == len(args_f or ()) @@ -428,11 +435,21 @@ def get_result_size(self, translate_support_code): return 0 +SingleFloatCallDescr = None # built lazily + def getCallDescrClass(RESULT): if RESULT is lltype.Void: return VoidCallDescr if RESULT is lltype.Float: return FloatCallDescr + if RESULT is lltype.SingleFloat: + global SingleFloatCallDescr + if SingleFloatCallDescr is None: + assert rffi.sizeof(rffi.UINT) == rffi.sizeof(RESULT) + class SingleFloatCallDescr(getCallDescrClass(rffi.UINT)): + _clsname = 'SingleFloatCallDescr' + _return_type = 'S' + return SingleFloatCallDescr if is_longlong(RESULT): return LongLongCallDescr return getDescrClass(RESULT, BaseIntCallDescr, GcPtrCallDescr, @@ -444,7 +461,11 @@ arg_classes = [] for ARG in ARGS: kind = getkind(ARG) - if kind == 'int': arg_classes.append('i') + if kind == 'int': + if ARG is lltype.SingleFloat: + arg_classes.append('S') + else: + arg_classes.append('i') elif kind == 'ref': arg_classes.append('r') elif kind == 'float': if is_longlong(ARG): @@ -476,6 +497,9 @@ return GcPtrDescr else: return NonGcPtrDescr + if TYPE is lltype.SingleFloat: + assert rffi.sizeof(rffi.UINT) == rffi.sizeof(TYPE) + TYPE = rffi.UINT try: return _cache[nameprefix, TYPE] except KeyError: diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py --- a/pypy/jit/backend/llsupport/test/test_descr.py +++ b/pypy/jit/backend/llsupport/test/test_descr.py @@ -52,7 +52,8 @@ S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Ptr(T)), ('z', lltype.Ptr(U)), - ('f', lltype.Float)) + ('f', lltype.Float), + ('s', lltype.SingleFloat)) assert getFieldDescrClass(lltype.Ptr(T)) is GcPtrFieldDescr assert getFieldDescrClass(lltype.Ptr(U)) is NonGcPtrFieldDescr cls = getFieldDescrClass(lltype.Char) @@ -61,6 +62,10 @@ clsf = getFieldDescrClass(lltype.Float) assert clsf != cls assert clsf == getFieldDescrClass(lltype.Float) + clss = getFieldDescrClass(lltype.SingleFloat) + assert clss not in (cls, clsf) + assert clss == getFieldDescrClass(lltype.SingleFloat) + assert clss == getFieldDescrClass(rffi.UINT) # for now # c0 = GcCache(False) c1 = GcCache(True) @@ -72,14 +77,17 @@ descr_y = get_field_descr(c2, S, 'y') descr_z = get_field_descr(c2, S, 'z') descr_f = get_field_descr(c2, S, 'f') + descr_s = get_field_descr(c2, S, 's') assert descr_x.__class__ is cls assert descr_y.__class__ is GcPtrFieldDescr assert descr_z.__class__ is NonGcPtrFieldDescr assert descr_f.__class__ is clsf + assert descr_s.__class__ is clss assert descr_x.name == 'S.x' assert descr_y.name == 'S.y' assert descr_z.name == 'S.z' assert descr_f.name == 'S.f' + assert descr_s.name == 'S.s' if not tsc: assert descr_x.offset < descr_y.offset < descr_z.offset assert descr_x.sort_key() < descr_y.sort_key() < descr_z.sort_key() @@ -87,23 +95,29 @@ assert descr_y.get_field_size(False) == rffi.sizeof(lltype.Ptr(T)) assert descr_z.get_field_size(False) == rffi.sizeof(lltype.Ptr(U)) assert descr_f.get_field_size(False) == rffi.sizeof(lltype.Float) + assert descr_s.get_field_size(False) == rffi.sizeof( + lltype.SingleFloat) else: assert isinstance(descr_x.offset, Symbolic) assert isinstance(descr_y.offset, Symbolic) assert isinstance(descr_z.offset, Symbolic) assert isinstance(descr_f.offset, Symbolic) + assert isinstance(descr_s.offset, Symbolic) assert isinstance(descr_x.get_field_size(True), Symbolic) assert isinstance(descr_y.get_field_size(True), Symbolic) assert isinstance(descr_z.get_field_size(True), Symbolic) assert isinstance(descr_f.get_field_size(True), Symbolic) + assert isinstance(descr_s.get_field_size(True), Symbolic) assert not descr_x.is_pointer_field() assert descr_y.is_pointer_field() assert not descr_z.is_pointer_field() assert not descr_f.is_pointer_field() + assert not descr_s.is_pointer_field() assert not descr_x.is_float_field() assert not descr_y.is_float_field() assert not descr_z.is_float_field() assert descr_f.is_float_field() + assert not descr_s.is_float_field() def test_get_field_descr_sign(): @@ -135,6 +149,7 @@ A2 = lltype.GcArray(lltype.Ptr(T)) A3 = lltype.GcArray(lltype.Ptr(U)) A4 = lltype.GcArray(lltype.Float) + A5 = lltype.GcArray(lltype.SingleFloat) assert getArrayDescrClass(A2) is GcPtrArrayDescr assert getArrayDescrClass(A3) is NonGcPtrArrayDescr cls = getArrayDescrClass(A1) @@ -143,25 +158,32 @@ clsf = getArrayDescrClass(A4) assert clsf != cls assert clsf == getArrayDescrClass(lltype.GcArray(lltype.Float)) + clss = getArrayDescrClass(A5) + assert clss not in (clsf, cls) + assert clss == getArrayDescrClass(lltype.GcArray(rffi.UINT)) # c0 = GcCache(False) descr1 = get_array_descr(c0, A1) descr2 = get_array_descr(c0, A2) descr3 = get_array_descr(c0, A3) descr4 = get_array_descr(c0, A4) + descr5 = get_array_descr(c0, A5) assert descr1.__class__ is cls assert descr2.__class__ is GcPtrArrayDescr assert descr3.__class__ is NonGcPtrArrayDescr assert descr4.__class__ is clsf + assert descr5.__class__ is clss assert descr1 == get_array_descr(c0, lltype.GcArray(lltype.Char)) assert not descr1.is_array_of_pointers() assert descr2.is_array_of_pointers() assert not descr3.is_array_of_pointers() assert not descr4.is_array_of_pointers() + assert not descr5.is_array_of_pointers() assert not descr1.is_array_of_floats() assert not descr2.is_array_of_floats() assert not descr3.is_array_of_floats() assert descr4.is_array_of_floats() + assert not descr5.is_array_of_floats() # def get_alignment(code): # Retrieve default alignment for the compiler/platform @@ -170,27 +192,33 @@ assert descr2.get_base_size(False) == get_alignment('p') assert descr3.get_base_size(False) == get_alignment('p') assert descr4.get_base_size(False) == get_alignment('d') + assert descr5.get_base_size(False) == get_alignment('f') assert descr1.get_ofs_length(False) == 0 assert descr2.get_ofs_length(False) == 0 assert descr3.get_ofs_length(False) == 0 assert descr4.get_ofs_length(False) == 0 + assert descr5.get_ofs_length(False) == 0 assert descr1.get_item_size(False) == rffi.sizeof(lltype.Char) assert descr2.get_item_size(False) == rffi.sizeof(lltype.Ptr(T)) assert descr3.get_item_size(False) == rffi.sizeof(lltype.Ptr(U)) assert descr4.get_item_size(False) == rffi.sizeof(lltype.Float) + assert descr5.get_item_size(False) == rffi.sizeof(lltype.SingleFloat) # assert isinstance(descr1.get_base_size(True), Symbolic) assert isinstance(descr2.get_base_size(True), Symbolic) assert isinstance(descr3.get_base_size(True), Symbolic) assert isinstance(descr4.get_base_size(True), Symbolic) + assert isinstance(descr5.get_base_size(True), Symbolic) assert isinstance(descr1.get_ofs_length(True), Symbolic) assert isinstance(descr2.get_ofs_length(True), Symbolic) assert isinstance(descr3.get_ofs_length(True), Symbolic) assert isinstance(descr4.get_ofs_length(True), Symbolic) + assert isinstance(descr5.get_ofs_length(True), Symbolic) assert isinstance(descr1.get_item_size(True), Symbolic) assert isinstance(descr2.get_item_size(True), Symbolic) assert isinstance(descr3.get_item_size(True), Symbolic) assert isinstance(descr4.get_item_size(True), Symbolic) + assert isinstance(descr5.get_item_size(True), Symbolic) CA = rffi.CArray(lltype.Signed) descr = get_array_descr(c0, CA) assert not descr.is_array_of_floats() @@ -210,6 +238,11 @@ assert descr.is_array_of_floats() assert descr.get_base_size(False) == 0 assert descr.get_ofs_length(False) == -1 + CA = rffi.CArray(rffi.FLOAT) + descr = get_array_descr(c0, CA) + assert not descr.is_array_of_floats() + assert descr.get_base_size(False) == 0 + assert descr.get_ofs_length(False) == -1 def test_get_array_descr_sign(): @@ -257,6 +290,11 @@ assert descr4.get_result_size(False) == rffi.sizeof(lltype.Float) assert descr4.get_return_type() == history.FLOAT assert descr4.arg_classes == "ff" + # + descr5 = get_call_descr(c0, [lltype.SingleFloat], lltype.SingleFloat) + assert descr5.get_result_size(False) == rffi.sizeof(lltype.SingleFloat) + assert descr5.get_return_type() == "S" + assert descr5.arg_classes == "S" def test_get_call_descr_not_translated_longlong(): if sys.maxint > 2147483647: @@ -286,6 +324,11 @@ assert isinstance(descr4.get_result_size(True), Symbolic) assert descr4.get_return_type() == history.FLOAT assert descr4.arg_classes == "ff" + # + descr5 = get_call_descr(c1, [lltype.SingleFloat], lltype.SingleFloat) + assert isinstance(descr5.get_result_size(True), Symbolic) + assert descr5.get_return_type() == "S" + assert descr5.arg_classes == "S" def test_call_descr_extra_info(): c1 = GcCache(True) @@ -345,8 +388,11 @@ # descr4f = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Float) assert 'FloatCallDescr' in descr4f.repr_of_descr() + # + descr5f = get_call_descr(c0, [lltype.Char], lltype.SingleFloat) + assert 'SingleFloatCallDescr' in descr5f.repr_of_descr() -def test_call_stubs(): +def test_call_stubs_1(): c0 = GcCache(False) ARGS = [lltype.Char, lltype.Signed] RES = lltype.Char @@ -360,6 +406,8 @@ res = call_stub(rffi.cast(lltype.Signed, fnptr), [1, 2], None, None) assert res == ord('c') +def test_call_stubs_2(): + c0 = GcCache(False) ARRAY = lltype.GcArray(lltype.Signed) ARGS = [lltype.Float, lltype.Ptr(ARRAY)] RES = lltype.Float @@ -375,3 +423,27 @@ res = descr2.call_stub(rffi.cast(lltype.Signed, fnptr), [], [opaquea], [longlong.getfloatstorage(3.5)]) assert longlong.getrealfloat(res) == 4.5 + +def test_call_stubs_single_float(): + from pypy.rlib.longlong2float import uint2singlefloat, singlefloat2uint + from pypy.rlib.rarithmetic import r_singlefloat, intmask, r_uint + # + c0 = GcCache(False) + ARGS = [lltype.SingleFloat, lltype.SingleFloat, lltype.SingleFloat] + RES = lltype.SingleFloat + + def f(a, b, c): + a = float(a) + b = float(b) + c = float(c) + x = a - (b / c) + return r_singlefloat(x) + + fnptr = llhelper(lltype.Ptr(lltype.FuncType(ARGS, RES)), f) + descr2 = get_call_descr(c0, ARGS, RES) + a = intmask(singlefloat2uint(r_singlefloat(-10.0))) + b = intmask(singlefloat2uint(r_singlefloat(3.0))) + c = intmask(singlefloat2uint(r_singlefloat(2.0))) + res = descr2.call_stub(rffi.cast(lltype.Signed, fnptr), + [a, b, c], [], []) + assert float(uint2singlefloat(r_uint(res))) == -11.5 diff --git a/pypy/jit/codewriter/longlong.py b/pypy/jit/codewriter/longlong.py --- a/pypy/jit/codewriter/longlong.py +++ b/pypy/jit/codewriter/longlong.py @@ -7,7 +7,8 @@ """ import sys -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.rlib import rarithmetic, longlong2float if sys.maxint > 2147483647: @@ -31,8 +32,6 @@ # ---------- 32-bit platform ---------- # the type FloatStorage is r_longlong, and conversion is needed - from pypy.rlib import rarithmetic, longlong2float - is_64_bit = False supports_longlong = True r_float_storage = rarithmetic.r_longlong @@ -47,3 +46,13 @@ # ------------------------------------- ZEROF = getfloatstorage(0.0) + +# ____________________________________________________________ + +def int2singlefloat(x): + x = rffi.r_uint(x) + return longlong2float.uint2singlefloat(x) + +def singlefloat2int(x): + x = longlong2float.singlefloat2uint(x) + return rffi.cast(lltype.Signed, x) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -626,17 +626,13 @@ @arguments("f", returns="i") def bhimpl_cast_float_to_singlefloat(a): from pypy.rlib.rarithmetic import r_singlefloat - from pypy.rlib.longlong2float import singlefloat2uint a = longlong.getrealfloat(a) a = r_singlefloat(a) - a = singlefloat2uint(a) - return intmask(a) + return longlong.singlefloat2int(a) @arguments("i", returns="f") def bhimpl_cast_singlefloat_to_float(a): - from pypy.rpython.lltypesystem.rffi import r_uint - from pypy.rlib.longlong2float import uint2singlefloat - a = uint2singlefloat(r_uint(a)) + a = longlong.int2singlefloat(a) a = float(a) return longlong.getfloatstorage(a) diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -50,7 +50,7 @@ func = argboxes[0].getint() # do the call using the correct function from the cpu rettype = descr.get_return_type() - if rettype == INT: + if rettype == INT or rettype == 'S': # *S*ingle float try: result = cpu.bh_call_i(func, descr, args_i, args_r, args_f) except Exception, e: @@ -64,7 +64,7 @@ metainterp.execute_raised(e) result = NULL return BoxPtr(result) - if rettype == FLOAT or rettype == 'L': + if rettype == FLOAT or rettype == 'L': # *L*ong long try: result = cpu.bh_call_f(func, descr, args_i, args_r, args_f) except Exception, e: diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -149,6 +149,7 @@ """ Implement in call descr. Must return INT, REF, FLOAT, or 'v' for void. On 32-bit (hack) it can also be 'L' for longlongs. + Additionally it can be 'S' for singlefloats. """ raise NotImplementedError diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1228,7 +1228,7 @@ src_i = src_r = src_f = 0 i = 1 for kind in descr.get_arg_types(): - if kind == history.INT: + if kind == history.INT or kind == 'S': # single float while True: box = argboxes[src_i] src_i += 1 From noreply at buildbot.pypy.org Thu Jul 28 21:47:41 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 21:47:41 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Support no-thread environments. Message-ID: <20110728194741.2CE2A82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46062:78ad8b3ddc9e Date: 2011-07-28 17:43 +0200 http://bitbucket.org/pypy/pypy/changeset/78ad8b3ddc9e/ Log: Support no-thread environments. diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -27,7 +27,11 @@ from pypy.rpython import raddress from pypy.translator.platform import platform from array import array -from thread import _local as tlsobject +try: + from thread import _local as tlsobject +except ImportError: + class tlsobject(object): + pass # ____________________________________________________________ From noreply at buildbot.pypy.org Thu Jul 28 21:47:42 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 21:47:42 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: In-progress: calls returning SingleFloats. Message-ID: <20110728194742.775EB82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46063:5c768cc0e4bd Date: 2011-07-28 18:05 +0200 http://bitbucket.org/pypy/pypy/changeset/5c768cc0e4bd/ Log: In-progress: calls returning SingleFloats. diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -499,7 +499,7 @@ def bh_call_i(self, func, calldescr, args_i, args_r, args_f): assert isinstance(calldescr, BaseIntCallDescr) if not we_are_translated(): - calldescr.verify_types(args_i, args_r, args_f, history.INT) + calldescr.verify_types(args_i, args_r, args_f, history.INT + 'S') return calldescr.call_stub(func, args_i, args_r, args_f) def bh_call_r(self, func, calldescr, args_i, args_r, args_f): diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py --- a/pypy/jit/backend/model.py +++ b/pypy/jit/backend/model.py @@ -8,6 +8,7 @@ # ^^^ This is only useful on 32-bit platforms. If True, # longlongs are supported by the JIT, but stored as doubles. # Boxes and Consts are BoxFloats and ConstFloats. + supports_singlefloats = False done_with_this_frame_void_v = -1 done_with_this_frame_int_v = -1 diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py --- a/pypy/jit/backend/test/runner_test.py +++ b/pypy/jit/backend/test/runner_test.py @@ -2734,6 +2734,65 @@ 'float', descr=calldescr) assert res.getfloatstorage() == expected + def test_singlefloat_result_of_call_direct(self): + if not self.cpu.supports_singlefloats: + py.test.skip("singlefloat test") + from pypy.translator.tool.cbuild import ExternalCompilationInfo + from pypy.rlib.rarithmetic import r_singlefloat + eci = ExternalCompilationInfo( + separate_module_sources=[""" + float fn_test_result_of_call(float x) + { + return x / 2.0f; + } + """], + export_symbols=['fn_test_result_of_call']) + f = rffi.llexternal('fn_test_result_of_call', [lltype.SingleFloat], + lltype.SingleFloat, + compilation_info=eci, _nowrapper=True) + value = r_singlefloat(-42.5) + expected = r_singlefloat(-21.25) + assert f(value) == expected + # + FUNC = self.FuncType([lltype.SingleFloat], lltype.SingleFloat) + FPTR = self.Ptr(FUNC) + calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) + ivalue = longlong.singlefloat2int(value) + iexpected = longlong.singlefloat2int(expected) + x = self.cpu.bh_call_i(self.get_funcbox(self.cpu, f).value, + calldescr, [ivalue], None, None) + assert x == iexpected + + def test_singlefloat_result_of_call_compiled(self): + if not self.cpu.supports_singlefloats: + py.test.skip("test of singlefloat result") + from pypy.translator.tool.cbuild import ExternalCompilationInfo + from pypy.rlib.rarithmetic import r_singlefloat + eci = ExternalCompilationInfo( + separate_module_sources=[""" + float fn_test_result_of_call(float x) + { + return x / 2.0f; + } + """], + export_symbols=['fn_test_result_of_call']) + f = rffi.llexternal('fn_test_result_of_call', [lltype.SingleFloat], + lltype.SingleFloat, + compilation_info=eci, _nowrapper=True) + value = r_singlefloat(-42.5) + expected = r_singlefloat(-21.25) + assert f(value) == expected + # + FUNC = self.FuncType([lltype.SingleFloat], lltype.SingleFloat) + FPTR = self.Ptr(FUNC) + calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) + funcbox = self.get_funcbox(self.cpu, f) + ivalue = longlong.singlefloat2int(value) + iexpected = longlong.singlefloat2int(expected) + res = self.execute_operation(rop.CALL, [funcbox, BoxInt(ivalue)], + 'int', descr=calldescr) + assert res.value == iexpected + def test_free_loop_and_bridges(self): from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU if not isinstance(self.cpu, AbstractLLCPU): diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -2051,7 +2051,18 @@ # and this way is simpler also because the result loc # can just be always a stack location else: - self.mc.FSTP_b(resloc.value) # float return + self.mc.FSTPL_b(resloc.value) # float return + elif op.getdescr().get_return_type() == 'S': + # singlefloat return + assert resloc is eax + if IS_X86_32: + # must convert ST(0) to a 32-bit singlefloat and load it into EAX + # mess mess mess + self.mc.SUB_ri(esp.value, 4) + self.mc.FSTPS_s(0) + self.mc.POP_r(eax.value) + elif IS_X86_64: + XXX elif size == WORD: assert resloc is eax or resloc is xmm0 # a full word elif size == 0: diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -573,7 +573,8 @@ BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_, immediate(1)) # x87 instructions - FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) + FSTPL_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) # rffi.DOUBLE ('as' wants L??) + FSTPS_s = insn('\xD9', orbyte(3<<3), stack_sp(1)) # lltype.SingleFloat # ------------------------------ Random mess ----------------------- RDTSC = insn('\x0F\x31') diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py --- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py +++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py @@ -180,7 +180,8 @@ ## for m, extra in args: ## if m in (i386.MODRM, i386.MODRM8) or all: ## suffix = suffixes[sizes[m]] + suffix - if argmodes and not self.is_xmm_insn: + if (argmodes and not self.is_xmm_insn + and not instrname.startswith('FSTP')): suffix = suffixes[self.WORD] # Special case: On 64-bit CPUs, rx86 assumes 64-bit integer # operands when converting to/from floating point, so we need to diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -692,6 +692,8 @@ res = ctypes.cast(res, ctypes.c_void_p).value if res is None: return 0 + if T.TO.RESULT == lltype.SingleFloat: + res = res.value # baaaah, cannot return a c_float() return res def callback(*cargs): From noreply at buildbot.pypy.org Thu Jul 28 21:47:43 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 21:47:43 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: In-progress for 64-bit. It's actually a mess because some arguments Message-ID: <20110728194743.AE12182110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46064:cddbdea9da49 Date: 2011-07-28 18:44 +0200 http://bitbucket.org/pypy/pypy/changeset/cddbdea9da49/ Log: In-progress for 64-bit. It's actually a mess because some arguments may also have to be passed in the 32 lower bits of xmm registers... diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -2062,7 +2062,8 @@ self.mc.FSTPS_s(0) self.mc.POP_r(eax.value) elif IS_X86_64: - XXX + # must copy from the lower 32 bits of XMM0 into eax + self.mc.MOVD_rx(eax.value, xmm0.value) elif size == WORD: assert resloc is eax or resloc is xmm0 # a full word elif size == 0: diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -600,6 +600,7 @@ CVTSS2SD_xb = xmminsn('\xF3', rex_nw, '\x0F\x5A', register(1, 8), stack_bp(2)) + # note that MOVD is a word-sized move (i.e. really MOVQ on 64-bit) MOVD_rx = xmminsn('\x66', rex_w, '\x0F\x7E', register(2, 8), register(1), '\xC0') MOVD_xr = xmminsn('\x66', rex_w, '\x0F\x6E', register(1, 8), register(2), '\xC0') From noreply at buildbot.pypy.org Thu Jul 28 21:47:44 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 21:47:44 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Fix the calls with singlefloat arguments on 64-bit. Message-ID: <20110728194744.E499782110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46065:72d6f3a2e9a9 Date: 2011-07-28 21:23 +0200 http://bitbucket.org/pypy/pypy/changeset/72d6f3a2e9a9/ Log: Fix the calls with singlefloat arguments on 64-bit. diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -1068,9 +1068,10 @@ self.implement_guard(guard_token, checkfalsecond) return genop_cmp_guard_float - def _emit_call(self, force_index, x, arglocs, start=0, tmp=eax): + def _emit_call(self, force_index, x, arglocs, start=0, tmp=eax, + argtypes=None): if IS_X86_64: - return self._emit_call_64(force_index, x, arglocs, start) + return self._emit_call_64(force_index, x, arglocs, start, argtypes) p = 0 n = len(arglocs) @@ -1098,12 +1099,13 @@ self.mc.CALL(x) self.mark_gc_roots(force_index) - def _emit_call_64(self, force_index, x, arglocs, start): + def _emit_call_64(self, force_index, x, arglocs, start, argtypes): src_locs = [] dst_locs = [] xmm_src_locs = [] xmm_dst_locs = [] pass_on_stack = [] + singlefloats = None # In reverse order for use with pop() unused_gpr = [r9, r8, ecx, edx, esi, edi] @@ -1123,6 +1125,11 @@ xmm_dst_locs.append(unused_xmm.pop()) else: pass_on_stack.append(loc) + elif (argtypes is not None and argtypes[i-start] == 'S' and + len(unused_xmm) > 0): + # Singlefloat argument + if singlefloats is None: singlefloats = [] + singlefloats.append((loc, unused_xmm.pop())) else: if len(unused_gpr) > 0: src_locs.append(loc) @@ -1150,9 +1157,15 @@ else: self.mc.MOV_sr(i*WORD, loc.value) - # Handle register arguments + # Handle register arguments: first remap the xmm arguments + remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, + X86_64_XMM_SCRATCH_REG) + # Load the singlefloat arguments from main regs or stack to xmm regs + if singlefloats is not None: + for src, dst in singlefloats: + self.mc.MOVD(dst, src) + # Finally remap the arguments in the main regs remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG) - remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, X86_64_XMM_SCRATCH_REG) self._regalloc.reserve_param(len(pass_on_stack)) self.mc.CALL(x) @@ -2039,7 +2052,8 @@ else: tmp = eax - self._emit_call(force_index, x, arglocs, 3, tmp=tmp) + self._emit_call(force_index, x, arglocs, 3, tmp=tmp, + argtypes=op.getdescr().get_arg_types()) if IS_X86_32 and isinstance(resloc, StackLoc) and resloc.width == 8: # a float or a long long return diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py --- a/pypy/jit/backend/x86/regloc.py +++ b/pypy/jit/backend/x86/regloc.py @@ -536,6 +536,8 @@ PXOR = _binaryop('PXOR') PCMPEQD = _binaryop('PCMPEQD') + MOVD = _binaryop('MOVD') + CALL = _relative_unaryop('CALL') JMP = _relative_unaryop('JMP') diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py --- a/pypy/jit/backend/x86/rx86.py +++ b/pypy/jit/backend/x86/rx86.py @@ -603,6 +603,7 @@ # note that MOVD is a word-sized move (i.e. really MOVQ on 64-bit) MOVD_rx = xmminsn('\x66', rex_w, '\x0F\x7E', register(2, 8), register(1), '\xC0') MOVD_xr = xmminsn('\x66', rex_w, '\x0F\x6E', register(1, 8), register(2), '\xC0') + MOVD_xb = xmminsn('\x66', rex_w, '\x0F\x6E', register(1, 8), stack_bp(2)) PSRAD_xi = xmminsn('\x66', rex_nw, '\x0F\x72', register(1), '\xE0', immediate(2, 'b')) From noreply at buildbot.pypy.org Thu Jul 28 21:55:34 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Thu, 28 Jul 2011 21:55:34 +0200 (CEST) Subject: [pypy-commit] pypy streamio-bufinput: Revamped BufferingInputStream to be faster. Message-ID: <20110728195534.E6E4A82110@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: streamio-bufinput Changeset: r46066:4d206523194f Date: 2011-07-28 13:55 -0600 http://bitbucket.org/pypy/pypy/changeset/4d206523194f/ Log: Revamped BufferingInputStream to be faster. diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -496,29 +496,24 @@ if bufsize == -1: # Get default from the class bufsize = self.bufsize self.bufsize = bufsize # buffer size (hint only) - self.lines = [] # ready-made lines (sans "\n") - self.buf = "" # raw data (may contain "\n") - # Invariant: readahead == "\n".join(self.lines + [self.buf]) - # self.lines contains no "\n" - # self.buf may contain "\n" + self.buf = "" # raw data + self.pos = 0 def flush_buffers(self): - if self.lines or self.buf: + if self.buf: try: self.do_seek(self.tell(), 0) except MyNotImplementedError: pass else: - self.lines = [] self.buf = "" + self.pos = 0 def tell(self): - bytes = self.do_tell() # This may fail - offset = len(self.buf) - for line in self.lines: - offset += len(line) + 1 - assert bytes >= offset #, (locals(), self.__dict__) - return bytes - offset + tellpos = self.do_tell() # This may fail + offset = len(self.buf) - self.pos + assert tellpos >= offset #, (locals(), self.__dict__) + return tellpos - offset def seek(self, offset, whence): # This may fail on the do_seek() or do_tell() call. @@ -526,32 +521,25 @@ # Nor on a seek to the very end. if whence == 0: self.do_seek(offset, 0) - self.lines = [] self.buf = "" + self.pos = 0 return if whence == 1: + currentsize = len(self.buf) - self.pos if offset < 0: - self.do_seek(self.tell() + offset, 0) - self.lines = [] - self.buf = "" + if self.pos + offset >= 0: + self.pos += offset + else: + self.do_seek(self.tell() + offset, 0) + self.pos = 0 + self.buf = "" return - while self.lines: - line = self.lines[-1] - if offset <= len(line): - intoffset = intmask(offset) - assert intoffset >= 0 - self.lines[-1] = line[intoffset:] - return - offset -= len(self.lines[-1]) - 1 - self.lines.pop() - assert not self.lines - if offset <= len(self.buf): - intoffset = intmask(offset) - assert intoffset >= 0 - self.buf = self.buf[intoffset:] + elif offset <= currentsize: + self.pos += offset return - offset -= len(self.buf) self.buf = "" + self.pos = 0 + offset -= currentsize try: self.do_seek(offset, 1) except MyNotImplementedError: @@ -559,187 +547,135 @@ self.read(intoffset) return if whence == 2: - try: - self.do_seek(offset, 2) - except MyNotImplementedError: - pass - else: - self.lines = [] - self.buf = "" - return + self.do_seek(offset, 2) + self.pos = 0 + self.buf = "" + # We'll comment all of this for now unless someone really wants + # something like it + #try: + # self.do_seek(offset, 2) + #except MyNotImplementedError: + # pass + #else: + # self.pos = 0 + # self.buf = "" + # return # Skip relative to EOF by reading and saving only just as # much as needed - intoffset = offset2int(offset) - self.lines.reverse() - data = "\n".join(self.lines + [self.buf]) - total = len(data) - buffers = [data] - self.lines = [] - self.buf = "" - while 1: - data = self.do_read(self.bufsize) - if not data: - break - buffers.append(data) - total += len(data) - while buffers and total >= len(buffers[0]) - intoffset: - total -= len(buffers[0]) - del buffers[0] - cutoff = total + intoffset - if cutoff < 0: - raise StreamError("cannot seek back") - if buffers: - buffers[0] = buffers[0][cutoff:] - self.buf = "".join(buffers) - self.lines = [] - return + #intoffset = offset2int(offset) + #self.lines.reverse() + #data = "\n".join(self.lines + [self.buf]) + #total = len(data) + #buffers = [data] + #self.lines = [] + #self.buf = "" + #while 1: + #data = self.do_read(self.bufsize) + #if not data: + #break + #buffers.append(data) + #total += len(data) + #while buffers and total >= len(buffers[0]) - intoffset: + #total -= len(buffers[0]) + #del buffers[0] + #cutoff = total + intoffset + #if cutoff < 0: + #raise StreamError("cannot seek back") + #if buffers: + #buffers[0] = buffers[0][cutoff:] + #self.buf = "".join(buffers) + #self.lines = [] + #return raise StreamError("whence should be 0, 1 or 2") def readall(self): - self.lines.reverse() - self.lines.append(self.buf) - more = ["\n".join(self.lines)] - self.lines = [] + pos = self.pos + assert pos >= 0 + chunks = [self.buf[pos:]] self.buf = "" + self.pos = 0 bufsize = self.bufsize while 1: data = self.do_read(bufsize) if not data: break - more.append(data) + chunks.append(data) bufsize = min(bufsize*2, self.bigsize) - return "".join(more) + return "".join(chunks) - def read(self, n): + def read(self, n=-1): assert isinstance(n, int) - assert n >= 0 - if self.lines: - # See if this can be satisfied from self.lines[0] - line = self.lines[-1] - if len(line) >= n: - self.lines[-1] = line[n:] - return line[:n] - - # See if this can be satisfied *without exhausting* self.lines - k = 0 - i = 0 - lgt = len(self.lines) - for linenum in range(lgt-1,-1,-1): - line = self.lines[linenum] - k += len(line) - if k >= n: - lines = self.lines[linenum + 1:] - data = self.lines[linenum] - cutoff = len(data) - (k-n) - assert cutoff >= 0 - lines.reverse() - lines.append(data[:cutoff]) - del self.lines[linenum:] - self.lines.append(data[cutoff:]) - return "\n".join(lines) - k += 1 - - # See if this can be satisfied from self.lines plus self.buf - if k + len(self.buf) >= n: - lines = self.lines - lines.reverse() - self.lines = [] - cutoff = n - k - assert cutoff >= 0 - lines.append(self.buf[:cutoff]) - self.buf = self.buf[cutoff:] - return "\n".join(lines) - + if n < 0: + return self.readall() + currentsize = len(self.buf) - self.pos + start = self.pos + assert start >= 0 + if n <= currentsize: + stop = start + n + assert stop >= 0 + result = self.buf[start:stop] + self.pos += n + return result else: - # See if this can be satisfied from self.buf - data = self.buf - k = len(data) - if k >= n: - cutoff = len(data) - (k-n) - assert cutoff >= 0 - assert len(data) >= cutoff - self.buf = data[cutoff:] - return data[:cutoff] - - lines = self.lines - lines.reverse() - self.lines = [] - lines.append(self.buf) - self.buf = "" - data = "\n".join(lines) - more = [data] - k = len(data) - while k < n: - data = self.do_read(max(self.bufsize, n-k)) - k += len(data) - more.append(data) - if not data: - break - cutoff = len(data) - (k-n) - assert cutoff >= 0 - if len(data) <= cutoff: - self.buf = "" - else: - self.buf = data[cutoff:] - more[-1] = data[:cutoff] - return "".join(more) - - # read_next_bunch is generally this, version below is slightly faster - #def _read_next_bunch(self): - # self.lines = self.buf.split("\n") - # self.buf = self.lines.pop() - # self.lines.reverse() - - def _read_next_bunch(self): - numlines = self.buf.count("\n") - self.lines = [None] * numlines - last = -1 - num = numlines - 1 - while True: - start = last + 1 - assert start >= 0 - next = self.buf.find("\n", start) - if next == -1: - if last != -1: - self.buf = self.buf[start:] - break - assert next >= 0 - self.lines[num] = self.buf[start:next] - last = next - num -= 1 + chunks = [self.buf[start:]] + while 1: + self.buf = self.do_read(self.bufsize) + if not self.buf: + self.pos = 0 + break + currentsize += len(self.buf) + if currentsize >= n: + self.pos = len(self.buf) - (currentsize - n) + stop = self.pos + assert stop >= 0 + chunks.append(self.buf[:stop]) + break + chunks.append(self.buf) + return ''.join(chunks) def readline(self): - if self.lines: - return self.lines.pop() + "\n" - - # This block is needed because read() can leave self.buf - # containing newlines - self._read_next_bunch() - if self.lines: - return self.lines.pop() + "\n" - - if self.buf: - buf = [self.buf] - else: - buf = [] + pos = self.pos + assert pos >= 0 + i = self.buf.find("\n", pos) + start = self.pos + assert start >= 0 + if i >= 0: # new line found + i += 1 + result = self.buf[start:i] + self.pos = i + return result + temp = self.buf[start:] + # read one buffer and most of the time a new line will be found + self.buf = self.do_read(self.bufsize) + i = self.buf.find("\n") + if i >= 0: # new line found + i += 1 + result = temp + self.buf[:i] + self.pos = i + return result + if not self.buf: + self.pos = 0 + return temp + # need to keep getting data until we find a new line + chunks = [temp, self.buf] while 1: self.buf = self.do_read(self.bufsize) - self._read_next_bunch() - if self.lines: - buf.append(self.lines.pop()) - buf.append("\n") + if not self.buf: + self.pos = 0 break - if not self.buf: + i = self.buf.find("\n") + if i >= 0: + i += 1 + chunks.append(self.buf[:i]) + self.pos = i break - buf.append(self.buf) - - return "".join(buf) + chunks.append(self.buf) + return "".join(chunks) def peek(self): - if self.lines: - return self.lines[-1] + "\n" - else: - return self.buf + pos = self.pos + assert pos >= 0 + return self.buf[pos:] write = PassThrough("write", flush_buffers=True) truncate = PassThrough("truncate", flush_buffers=True) From noreply at buildbot.pypy.org Thu Jul 28 23:48:03 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 23:48:03 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Fix tests. Message-ID: <20110728214803.0CE6882110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46070:4936b4ec981c Date: 2011-07-28 23:44 +0200 http://bitbucket.org/pypy/pypy/changeset/4936b4ec981c/ Log: Fix tests. diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -1071,6 +1071,8 @@ return heaptracker.adr2int(llmemory.cast_ptr_to_adr(x)) if TP == llmemory.Address: return heaptracker.adr2int(x) + if TP is lltype.SingleFloat: + return longlong.singlefloat2int(x) return lltype.cast_primitive(lltype.Signed, x) def cast_from_int(TYPE, x): @@ -1086,6 +1088,9 @@ x = llmemory.cast_int_to_adr(x) assert lltype.typeOf(x) == llmemory.Address return x + elif TYPE is lltype.SingleFloat: + assert lltype.typeOf(x) is lltype.Signed + return longlong.int2singlefloat(x) else: if lltype.typeOf(x) == llmemory.Address: x = heaptracker.adr2int(x) From noreply at buildbot.pypy.org Thu Jul 28 23:48:04 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 23:48:04 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Oups, fix test. Message-ID: <20110728214804.3D69F82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46071:e131bb0832ae Date: 2011-07-28 23:46 +0200 http://bitbucket.org/pypy/pypy/changeset/e131bb0832ae/ Log: Oups, fix test. diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py --- a/pypy/jit/backend/llsupport/test/test_descr.py +++ b/pypy/jit/backend/llsupport/test/test_descr.py @@ -426,7 +426,7 @@ def test_call_stubs_single_float(): from pypy.rlib.longlong2float import uint2singlefloat, singlefloat2uint - from pypy.rlib.rarithmetic import r_singlefloat, intmask, r_uint + from pypy.rlib.rarithmetic import r_singlefloat, intmask # c0 = GcCache(False) ARGS = [lltype.SingleFloat, lltype.SingleFloat, lltype.SingleFloat] @@ -446,4 +446,4 @@ c = intmask(singlefloat2uint(r_singlefloat(2.0))) res = descr2.call_stub(rffi.cast(lltype.Signed, fnptr), [a, b, c], [], []) - assert float(uint2singlefloat(r_uint(res))) == -11.5 + assert float(uint2singlefloat(rffi.r_uint(res))) == -11.5 From noreply at buildbot.pypy.org Thu Jul 28 23:48:05 2011 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 28 Jul 2011 23:48:05 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Fix test. Message-ID: <20110728214805.7294582110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46072:08faa59c30c9 Date: 2011-07-28 23:48 +0200 http://bitbucket.org/pypy/pypy/changeset/08faa59c30c9/ Log: Fix test. diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py --- a/pypy/jit/metainterp/test/test_warmspot.py +++ b/pypy/jit/metainterp/test/test_warmspot.py @@ -303,6 +303,7 @@ class FakeCPU(object): supports_floats = False supports_longlong = False + supports_singlefloats = False ts = llhelper translate_support_code = False stats = "stats" From noreply at buildbot.pypy.org Fri Jul 29 00:39:26 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 00:39:26 +0200 (CEST) Subject: [pypy-commit] pypy default: Preallocate the result for str.__repr__ more appropriately, use len(self) + 2, which will be correct in the common case of "no special characgters". Message-ID: <20110728223926.243FB82110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46073:7982de091965 Date: 2011-07-28 15:39 -0700 http://bitbucket.org/pypy/pypy/changeset/7982de091965/ Log: Preallocate the result for str.__repr__ more appropriately, use len(self) + 2, which will be correct in the common case of "no special characgters". Alex diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -913,7 +913,7 @@ def repr__String(space, w_str): s = w_str._value - buf = StringBuilder(50) + buf = StringBuilder(len(s) + 2) quote = "'" if quote in s and '"' not in s: From pullrequests-noreply at bitbucket.org Fri Jul 29 01:54:45 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Thu, 28 Jul 2011 23:54:45 -0000 Subject: [pypy-commit] [OPEN] Pull request #5 for pypy: arcsin, arccos and arctan for numpy Message-ID: A new pull request has been opened by cgerum. cgerum/pypy has changes to be pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/5/arcsin-arccos-and-arctan-for-numpy Title: arcsin, arccos and arctan for numpy This pull request implements arcsin, arccos and arctan for numpy. Changes to be pulled: 47c7c4f3577f by cgerum: "merge default" c823c8aa0b57 by cgerum: "numpy: Added inf and -inf to test of arctan ufunc" cf22222905d0 by cgerum: "numpy: Added ufuncs for arcsin, arccos, arctan" -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From pullrequests-noreply at bitbucket.org Fri Jul 29 01:57:32 2011 From: pullrequests-noreply at bitbucket.org (Bitbucket) Date: Thu, 28 Jul 2011 23:57:32 -0000 Subject: [pypy-commit] [ACCEPTED] Pull request #5 for pypy: arcsin, arccos and arctan for numpy In-Reply-To: References: Message-ID: <20110728235732.16643.57535@bitbucket03.managed.contegix.com> Pull request #5 has been accepted by Alex Gaynor. Changes in cgerum/pypy have been pulled into pypy/pypy. https://bitbucket.org/pypy/pypy/pull-request/5/arcsin-arccos-and-arctan-for-numpy -- This is an issue notification from bitbucket.org. You are receiving this either because you are the participating in a pull request, or you are following it. From noreply at buildbot.pypy.org Fri Jul 29 01:57:03 2011 From: noreply at buildbot.pypy.org (cgerum) Date: Fri, 29 Jul 2011 01:57:03 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ufunc-trig: numpy: Added ufuncs for arcsin, arccos, arctan Message-ID: <20110728235703.CF73F82110@wyvern.cs.uni-duesseldorf.de> Author: Christoph Gerum Branch: numpy-ufunc-trig Changeset: r46074:cf22222905d0 Date: 2011-07-29 00:28 +0200 http://bitbucket.org/pypy/pypy/changeset/cf22222905d0/ Log: numpy: Added ufuncs for arcsin, arccos, arctan diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -31,6 +31,9 @@ 'sin': 'interp_ufuncs.sin', 'cos': 'interp_ufuncs.cos', 'tan': 'interp_ufuncs.tan', + 'arcsin': 'interp_ufuncs.arcsin', + 'arccos': 'interp_ufuncs.arccos', + 'arctan': 'interp_ufuncs.arctan', } appleveldefs = { diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -120,3 +120,20 @@ @ufunc2 def mod(lvalue, rvalue): return math.fmod(lvalue, rvalue) + + + at ufunc +def arcsin(value): + if value < -1.0 or value > 1.0: + return rfloat.NAN + return math.asin(value) + + at ufunc +def arccos(value): + if value < -1.0 or value > 1.0: + return rfloat.NAN + return math.acos(value) + + at ufunc +def arctan(value): + return math.atan(value) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -205,3 +205,47 @@ b = tan(a) for i in range(len(a)): assert b[i] == math.tan(a[i]) + + + def test_arcsin(self): + import math + from numpy import array, arcsin + + a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1]) + b = arcsin(a) + for i in range(len(a)): + assert b[i] == math.asin(a[i]) + + a = array([-10, -1.5, -1.01, 1.01, 1.5, 10, float('nan'), float('inf'), float('-inf')]) + b = arcsin(a) + for f in b: + assert math.isnan(f) + + def test_arccos(self): + import math + from numpy import array, arccos + + a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1]) + b = arccos(a) + for i in range(len(a)): + assert b[i] == math.acos(a[i]) + + + a = array([-10, -1.5, -1.01, 1.01, 1.5, 10, float('nan'), float('inf'), float('-inf')]) + b = arccos(a) + for f in b: + assert math.isnan(f) + + def test_arctan(self): + import math + from numpy import array, arctan + + a = array([-3, -2, -1, 0, 1, 2, 3]) + b = arctan(a) + for i in range(len(a)): + assert b[i] == math.atan(a[i]) + + a = array([float('nan')]) + b = arctan(a) + assert math.isnan(b[0]) + From noreply at buildbot.pypy.org Fri Jul 29 01:57:05 2011 From: noreply at buildbot.pypy.org (cgerum) Date: Fri, 29 Jul 2011 01:57:05 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ufunc-trig: numpy: Added inf and -inf to test of arctan ufunc Message-ID: <20110728235705.0A60182110@wyvern.cs.uni-duesseldorf.de> Author: Christoph Gerum Branch: numpy-ufunc-trig Changeset: r46075:c823c8aa0b57 Date: 2011-07-29 01:00 +0200 http://bitbucket.org/pypy/pypy/changeset/c823c8aa0b57/ Log: numpy: Added inf and -inf to test of arctan ufunc diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -240,7 +240,7 @@ import math from numpy import array, arctan - a = array([-3, -2, -1, 0, 1, 2, 3]) + a = array([-3, -2, -1, 0, 1, 2, 3, float('inf'), float('-inf')]) b = arctan(a) for i in range(len(a)): assert b[i] == math.atan(a[i]) From noreply at buildbot.pypy.org Fri Jul 29 01:57:07 2011 From: noreply at buildbot.pypy.org (cgerum) Date: Fri, 29 Jul 2011 01:57:07 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ufunc-trig: merge default Message-ID: <20110728235707.6EB7882110@wyvern.cs.uni-duesseldorf.de> Author: Christoph Gerum Branch: numpy-ufunc-trig Changeset: r46076:47c7c4f3577f Date: 2011-07-29 01:48 +0200 http://bitbucket.org/pypy/pypy/changeset/47c7c4f3577f/ Log: merge default diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -1,1 +1,2 @@ b590cf6de4190623aad9aa698694c22e614d67b9 release-1.5 +b48df0bf4e75b81d98f19ce89d4a7dc3e1dab5e5 benchmarked diff --git a/lib-python/modified-2.7/ctypes/__init__.py b/lib-python/modified-2.7/ctypes/__init__.py --- a/lib-python/modified-2.7/ctypes/__init__.py +++ b/lib-python/modified-2.7/ctypes/__init__.py @@ -489,9 +489,12 @@ _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI return CFunctionType -_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr) def cast(obj, typ): - return _cast(obj, obj, typ) + try: + c_void_p.from_param(obj) + except TypeError, e: + raise ArgumentError(str(e)) + return _cast_addr(obj, obj, typ) _string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) def string_at(ptr, size=-1): diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -78,8 +78,6 @@ _com_iid = None _is_fastpath = False - __restype_set = False - def _getargtypes(self): return self._argtypes_ @@ -149,7 +147,6 @@ return self._restype_ def _setrestype(self, restype): - self.__restype_set = True self._ptr = None if restype is int: from ctypes import c_int @@ -296,13 +293,12 @@ "This function takes %d argument%s (%s given)" % (len(self._argtypes_), plural, len(args))) - # check that arguments are convertible - ## XXX Not as long as ctypes.cast is a callback function with - ## py_object arguments... - ## self._convert_args(self._argtypes_, args, {}) - try: - res = self.callable(*args) + newargs = self._convert_args_for_callback(argtypes, args) + except (UnicodeError, TypeError, ValueError), e: + raise ArgumentError(str(e)) + try: + res = self.callable(*newargs) except: exc_info = sys.exc_info() traceback.print_tb(exc_info[2], file=sys.stderr) @@ -316,10 +312,6 @@ warnings.warn('C function without declared arguments called', RuntimeWarning, stacklevel=2) argtypes = [] - - if not self.__restype_set: - warnings.warn('C function without declared return type called', - RuntimeWarning, stacklevel=2) if self._com_index: from ctypes import cast, c_void_p, POINTER @@ -366,7 +358,10 @@ if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) # - return self._build_result(self._restype_, result, newargs) + try: + return self._build_result(self._restype_, result, newargs) + finally: + funcptr.free_temp_buffers() def _do_errcheck(self, result, args): # The 'errcheck' protocol @@ -466,6 +461,18 @@ return cobj, cobj._to_ffi_param(), type(cobj) + def _convert_args_for_callback(self, argtypes, args): + assert len(argtypes) == len(args) + newargs = [] + for argtype, arg in zip(argtypes, args): + param = argtype.from_param(arg) + if argtype._type_ == 'P': # special-case for c_void_p + param = param._get_buffer_value() + elif self._is_primitive(argtype): + param = param.value + newargs.append(param) + return newargs + def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] @@ -556,6 +563,9 @@ newargtypes.append(newargtype) return keepalives, newargs, newargtypes, outargs + @staticmethod + def _is_primitive(argtype): + return argtype.__bases__[0] is _SimpleCData def _wrap_result(self, restype, result): """ @@ -564,7 +574,7 @@ """ # hack for performance: if restype is a "simple" primitive type, don't # allocate the buffer because it's going to be thrown away immediately - if restype.__bases__[0] is _SimpleCData and not restype._is_pointer_like(): + if self._is_primitive(restype) and not restype._is_pointer_like(): return result # shape = restype._ffishape @@ -680,7 +690,7 @@ try: result = self._call_funcptr(funcptr, *args) result = self._do_errcheck(result, args) - except (TypeError, ArgumentError): # XXX, should be FFITypeError + except (TypeError, ArgumentError, UnicodeDecodeError): assert self._slowpath_allowed return CFuncPtr.__call__(self, *args) return result diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py --- a/lib_pypy/_ctypes/primitive.py +++ b/lib_pypy/_ctypes/primitive.py @@ -10,6 +10,8 @@ from _ctypes.builtin import ConvMode from _ctypes.array import Array from _ctypes.pointer import _Pointer, as_ffi_pointer +#from _ctypes.function import CFuncPtr # this import is moved at the bottom + # because else it's circular class NULL(object): pass @@ -86,7 +88,7 @@ return res if isinstance(value, Array): return value - if isinstance(value, _Pointer): + if isinstance(value, (_Pointer, CFuncPtr)): return cls.from_address(value._buffer.buffer) if isinstance(value, (int, long)): return cls(value) @@ -338,3 +340,5 @@ def __nonzero__(self): return self._buffer[0] not in (0, '\x00') + +from _ctypes.function import CFuncPtr diff --git a/lib_pypy/pyrepl/unix_console.py b/lib_pypy/pyrepl/unix_console.py --- a/lib_pypy/pyrepl/unix_console.py +++ b/lib_pypy/pyrepl/unix_console.py @@ -384,15 +384,19 @@ self.__maybe_write_code(self._smkx) - self.old_sigwinch = signal.signal( - signal.SIGWINCH, self.__sigwinch) + try: + self.old_sigwinch = signal.signal( + signal.SIGWINCH, self.__sigwinch) + except ValueError: + pass def restore(self): self.__maybe_write_code(self._rmkx) self.flushoutput() tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate) - signal.signal(signal.SIGWINCH, self.old_sigwinch) + if hasattr(self, 'old_sigwinch'): + signal.signal(signal.SIGWINCH, self.old_sigwinch) def __sigwinch(self, signum, frame): self.height, self.width = self.getheightwidth() diff --git a/pypy/jit/backend/x86/arch.py b/pypy/jit/backend/x86/arch.py --- a/pypy/jit/backend/x86/arch.py +++ b/pypy/jit/backend/x86/arch.py @@ -27,3 +27,6 @@ # which are used in the malloc itself. They are: # ecx, ebx, esi, edi [32 and 64 bits] # r8, r9, r10, r12, r13, r14, r15 [64 bits only] +# +# Note that with asmgcc, the locations corresponding to callee-save registers +# are never used. diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -181,6 +181,7 @@ # instructions in assembler, with a mark_gc_roots in between. # With shadowstack, this is not needed, so we produce a single helper. gcrootmap = self.cpu.gc_ll_descr.gcrootmap + shadow_stack = (gcrootmap is not None and gcrootmap.is_shadow_stack) # # ---------- first helper for the slow path of malloc ---------- mc = codebuf.MachineCodeBlockWrapper() @@ -190,10 +191,19 @@ mc.SUB_rr(edx.value, eax.value) # compute the size we want addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr() # - if gcrootmap is not None and gcrootmap.is_shadow_stack: + # The registers to save in the copy area: with shadowstack, most + # registers need to be saved. With asmgcc, the callee-saved registers + # don't need to. + save_in_copy_area = gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items() + if not shadow_stack: + save_in_copy_area = [(reg, ofs) for (reg, ofs) in save_in_copy_area + if reg not in gpr_reg_mgr_cls.REGLOC_TO_GCROOTMAP_REG_INDEX] + # + for reg, ofs in save_in_copy_area: + mc.MOV_br(ofs, reg.value) + # + if shadow_stack: # ---- shadowstack ---- - for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items(): - mc.MOV_br(ofs, reg.value) mc.SUB_ri(esp.value, 16 - WORD) # stack alignment of 16 bytes if IS_X86_32: mc.MOV_sr(0, edx.value) # push argument @@ -201,15 +211,13 @@ mc.MOV_rr(edi.value, edx.value) mc.CALL(imm(addr)) mc.ADD_ri(esp.value, 16 - WORD) - for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items(): - mc.MOV_rb(reg.value, ofs) else: # ---- asmgcc ---- if IS_X86_32: mc.MOV_sr(WORD, edx.value) # save it as the new argument elif IS_X86_64: - # rdi can be clobbered: its content was forced to the stack - # by _fastpath_malloc(), like all other save_around_call_regs. + # rdi can be clobbered: its content was saved in the + # copy area of the stack mc.MOV_rr(edi.value, edx.value) mc.JMP(imm(addr)) # tail call to the real malloc rawstart = mc.materialize(self.cpu.asmmemmgr, []) @@ -217,6 +225,10 @@ # ---------- second helper for the slow path of malloc ---------- mc = codebuf.MachineCodeBlockWrapper() # + for reg, ofs in save_in_copy_area: + mc.MOV_rb(reg.value, ofs) + assert reg is not eax and reg is not edx + # if self.cpu.supports_floats: # restore the XMM registers for i in range(self.cpu.NUM_REGS):# from where they were saved mc.MOVSD_xs(i, (WORD*2)+8*i) @@ -2424,8 +2436,7 @@ # there are two helpers to call only with asmgcc slowpath_addr1 = self.malloc_slowpath1 self.mc.CALL(imm(slowpath_addr1)) - self.mark_gc_roots(self.write_new_force_index(), - use_copy_area=shadow_stack) + self.mark_gc_roots(self.write_new_force_index(), use_copy_area=True) slowpath_addr2 = self.malloc_slowpath2 self.mc.CALL(imm(slowpath_addr2)) diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -921,27 +921,13 @@ def _do_fastpath_malloc(self, op, size, tid): gc_ll_descr = self.assembler.cpu.gc_ll_descr self.rm.force_allocate_reg(op.result, selected_reg=eax) - - if gc_ll_descr.gcrootmap and gc_ll_descr.gcrootmap.is_shadow_stack: - # ---- shadowstack ---- - # We need edx as a temporary, but otherwise don't save any more - # register. See comments in _build_malloc_slowpath(). - tmp_box = TempBox() - self.rm.force_allocate_reg(tmp_box, selected_reg=edx) - self.rm.possibly_free_var(tmp_box) - else: - # ---- asmgcc ---- - # We need to force-allocate each of save_around_call_regs now. - # The alternative would be to save and restore them around the - # actual call to malloc(), in the rare case where we need to do - # it; however, mark_gc_roots() would need to be adapted to know - # where the variables end up being saved. Messy. - for reg in self.rm.save_around_call_regs: - if reg is not eax: - tmp_box = TempBox() - self.rm.force_allocate_reg(tmp_box, selected_reg=reg) - self.rm.possibly_free_var(tmp_box) - + # + # We need edx as a temporary, but otherwise don't save any more + # register. See comments in _build_malloc_slowpath(). + tmp_box = TempBox() + self.rm.force_allocate_reg(tmp_box, selected_reg=edx) + self.rm.possibly_free_var(tmp_box) + # self.assembler.malloc_cond( gc_ll_descr.get_nursery_free_addr(), gc_ll_descr.get_nursery_top_addr(), @@ -1337,14 +1323,26 @@ if reg is eax: continue # ok to ignore this one if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)): - if use_copy_area: - assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS - area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg] - gcrootmap.add_frame_offset(shape, area_offset) - else: - assert reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX - gcrootmap.add_callee_save_reg( - shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg]) + # + # The register 'reg' is alive across this call. + gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap + if gcrootmap is None or not gcrootmap.is_shadow_stack: + # + # Asmgcc: if reg is a callee-save register, we can + # explicitly mark it as containing a BoxPtr. + if reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX: + gcrootmap.add_callee_save_reg( + shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg]) + continue + # + # Else, 'use_copy_area' must be True (otherwise this BoxPtr + # should not be in a register). The copy area contains the + # real value of the register. + assert use_copy_area + assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS + area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg] + gcrootmap.add_frame_offset(shape, area_offset) + # return gcrootmap.compress_callshape(shape, self.assembler.datablockwrapper) diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py --- a/pypy/jit/codewriter/call.py +++ b/pypy/jit/codewriter/call.py @@ -228,8 +228,10 @@ elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif elidable: - # XXX check what to do about exceptions (also MemoryError?) - extraeffect = EffectInfo.EF_ELIDABLE + if self._canraise(op): + extraeffect = EffectInfo.EF_ELIDABLE_CAN_RAISE + else: + extraeffect = EffectInfo.EF_ELIDABLE_CANNOT_RAISE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: @@ -263,7 +265,7 @@ def calldescr_canraise(self, calldescr): effectinfo = calldescr.get_extra_info() return (effectinfo is None or - effectinfo.extraeffect >= EffectInfo.EF_CAN_RAISE) + effectinfo.extraeffect > EffectInfo.EF_CANNOT_RAISE) def jitdriver_sd_from_portal_graph(self, graph): for jd in self.jitdrivers_sd: diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py --- a/pypy/jit/codewriter/effectinfo.py +++ b/pypy/jit/codewriter/effectinfo.py @@ -9,10 +9,11 @@ _cache = {} # the 'extraeffect' field is one of the following values: - EF_ELIDABLE = 0 #elidable function (and cannot raise) + EF_ELIDABLE_CANNOT_RAISE = 0 #elidable function (and cannot raise) EF_LOOPINVARIANT = 1 #special: call it only once per loop EF_CANNOT_RAISE = 2 #a function which cannot raise - EF_CAN_RAISE = 3 #normal function (can raise) + EF_ELIDABLE_CAN_RAISE = 3 #elidable function (but can raise) + EF_CAN_RAISE = 4 #normal function (can raise) EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables # the 'oopspecindex' field is one of the following values: @@ -94,7 +95,8 @@ result.readonly_descrs_fields = readonly_descrs_fields result.readonly_descrs_arrays = readonly_descrs_arrays if extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - extraeffect == EffectInfo.EF_ELIDABLE: + extraeffect == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \ + extraeffect == EffectInfo.EF_ELIDABLE_CAN_RAISE: result.write_descrs_fields = [] result.write_descrs_arrays = [] else: diff --git a/pypy/jit/codewriter/jitcode.py b/pypy/jit/codewriter/jitcode.py --- a/pypy/jit/codewriter/jitcode.py +++ b/pypy/jit/codewriter/jitcode.py @@ -1,7 +1,6 @@ from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.codewriter import heaptracker from pypy.rlib.objectmodel import we_are_translated -from pypy.rpython.lltypesystem import llmemory class JitCode(AbstractDescr): @@ -102,7 +101,7 @@ def _clone_if_mutable(self): raise NotImplementedError - + class MissingLiveness(Exception): pass diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -1,18 +1,16 @@ -import py, sys -from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass -from pypy.rpython import rlist -from pypy.jit.metainterp.history import getkind -from pypy.objspace.flow.model import SpaceOperation, Variable, Constant -from pypy.objspace.flow.model import Block, Link, c_last_exception -from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets +import py from pypy.jit.codewriter import support, heaptracker, longlong from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets from pypy.jit.codewriter.policy import log +from pypy.jit.metainterp import quasiimmut +from pypy.jit.metainterp.history import getkind from pypy.jit.metainterp.typesystem import deref, arrayItem -from pypy.jit.metainterp import quasiimmut -from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY +from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, c_last_exception from pypy.rlib import objectmodel from pypy.rlib.jit import _we_are_jitted +from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass +from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY from pypy.translator.simplify import get_funcobj from pypy.translator.unsimplify import varoftype @@ -810,7 +808,6 @@ def force_cast_without_longlong(self, v_arg, v_result): from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT - from pypy.rlib.rarithmetic import intmask # if (v_result.concretetype in (FLOAT, lltype.Float) or v_arg.concretetype in (FLOAT, lltype.Float)): @@ -905,7 +902,7 @@ op1 = self.prepare_builtin_call(op, "llong_%s", args) op2 = self._handle_oopspec_call(op1, args, EffectInfo.OS_LLONG_%s, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) if %r == "TO_INT": assert op2.result.concretetype == lltype.Signed return op2 @@ -1366,15 +1363,15 @@ otherindex += EffectInfo._OS_offset_uni self._register_extra_helper(otherindex, othername, argtypes, resulttype, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) # return self._handle_oopspec_call(op, args, dict[oopspec_name], - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) def _handle_str2unicode_call(self, op, oopspec_name, args): - # ll_str2unicode is not EF_ELIDABLE, because it can raise - # UnicodeDecodeError... - return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE) + # ll_str2unicode can raise UnicodeDecodeError + return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE, + EffectInfo.EF_ELIDABLE_CAN_RAISE) # ---------- # VirtualRefs. @@ -1412,13 +1409,13 @@ assert vinfo is not None self.vable_flags[op.args[0]] = op.args[2].value return [] - + # --------- # ll_math.sqrt_nonneg() - + def _handle_math_sqrt_call(self, op, oopspec_name, args): return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, - EffectInfo.EF_ELIDABLE) + EffectInfo.EF_ELIDABLE_CANNOT_RAISE) def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py --- a/pypy/jit/codewriter/policy.py +++ b/pypy/jit/codewriter/policy.py @@ -1,9 +1,7 @@ -from pypy.translator.simplify import get_funcobj from pypy.jit.metainterp import history -from pypy.rpython.lltypesystem import lltype, rclass from pypy.tool.udir import udir -import py, sys +import py from pypy.tool.ansi_print import ansi_log log = py.log.Producer('jitcodewriter') py.log.setconsumer('jitcodewriter', ansi_log) diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/jit/codewriter/regalloc.py @@ -1,129 +1,8 @@ -import sys -from pypy.objspace.flow.model import Variable -from pypy.tool.algo.color import DependencyGraph -from pypy.tool.algo.unionfind import UnionFind +from pypy.tool.algo import regalloc from pypy.jit.metainterp.history import getkind from pypy.jit.codewriter.flatten import ListOfKind + def perform_register_allocation(graph, kind): - """Perform register allocation for the Variables of the given 'kind' - in the 'graph'.""" - regalloc = RegAllocator(graph, kind) - regalloc.make_dependencies() - regalloc.coalesce_variables() - regalloc.find_node_coloring() - return regalloc - - -class RegAllocator(object): - DEBUG_REGALLOC = False - - def __init__(self, graph, kind): - self.graph = graph - self.kind = kind - - def make_dependencies(self): - dg = DependencyGraph() - for block in self.graph.iterblocks(): - # Compute die_at = {Variable: index_of_operation_with_last_usage} - die_at = dict.fromkeys(block.inputargs, 0) - for i, op in enumerate(block.operations): - for v in op.args: - if isinstance(v, Variable): - die_at[v] = i - elif isinstance(v, ListOfKind): - for v1 in v: - if isinstance(v1, Variable): - die_at[v1] = i - if op.result is not None: - die_at[op.result] = i + 1 - if isinstance(block.exitswitch, tuple): - for x in block.exitswitch: - die_at.pop(x, None) - else: - die_at.pop(block.exitswitch, None) - for link in block.exits: - for v in link.args: - die_at.pop(v, None) - die_at = [(value, key) for (key, value) in die_at.items()] - die_at.sort() - die_at.append((sys.maxint,)) - # Done. XXX the code above this line runs 3 times - # (for kind in KINDS) to produce the same result... - livevars = [v for v in block.inputargs - if getkind(v.concretetype) == self.kind] - # Add the variables of this block to the dependency graph - for i, v in enumerate(livevars): - dg.add_node(v) - for j in range(i): - dg.add_edge(livevars[j], v) - livevars = set(livevars) - die_index = 0 - for i, op in enumerate(block.operations): - while die_at[die_index][0] == i: - try: - livevars.remove(die_at[die_index][1]) - except KeyError: - pass - die_index += 1 - if (op.result is not None and - getkind(op.result.concretetype) == self.kind): - dg.add_node(op.result) - for v in livevars: - if getkind(v.concretetype) == self.kind: - dg.add_edge(v, op.result) - livevars.add(op.result) - self._depgraph = dg - - def coalesce_variables(self): - self._unionfind = UnionFind() - pendingblocks = list(self.graph.iterblocks()) - while pendingblocks: - block = pendingblocks.pop() - # Aggressively try to coalesce each source variable with its - # target. We start from the end of the graph instead of - # from the beginning. This is a bit arbitrary, but the idea - # is that the end of the graph runs typically more often - # than the start, given that we resume execution from the - # middle during blackholing. - for link in block.exits: - if link.last_exception is not None: - self._depgraph.add_node(link.last_exception) - if link.last_exc_value is not None: - self._depgraph.add_node(link.last_exc_value) - for i, v in enumerate(link.args): - self._try_coalesce(v, link.target.inputargs[i]) - - def _try_coalesce(self, v, w): - if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: - assert getkind(w.concretetype) == self.kind - dg = self._depgraph - uf = self._unionfind - v0 = uf.find_rep(v) - w0 = uf.find_rep(w) - if v0 is not w0 and v0 not in dg.neighbours[w0]: - _, rep, _ = uf.union(v0, w0) - assert uf.find_rep(v0) is uf.find_rep(w0) is rep - if rep is v0: - dg.coalesce(w0, v0) - else: - assert rep is w0 - dg.coalesce(v0, w0) - - def find_node_coloring(self): - self._coloring = self._depgraph.find_node_coloring() - if self.DEBUG_REGALLOC: - for block in self.graph.iterblocks(): - print block - for v in block.getvariables(): - print '\t', v, '\t', self.getcolor(v) - - def getcolor(self, v): - return self._coloring[self._unionfind.find_rep(v)] - - def swapcolors(self, col1, col2): - for key, value in self._coloring.items(): - if value == col1: - self._coloring[key] = col2 - elif value == col2: - self._coloring[key] = col1 + checkkind = lambda v: getkind(v.concretetype) == kind + return regalloc.perform_register_allocation(graph, checkkind, ListOfKind) diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -20,6 +20,7 @@ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.jit.metainterp.typesystem import deref from pypy.rlib import rgc +from pypy.rlib.jit import elidable from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask def getargtypes(annotator, values): @@ -167,9 +168,14 @@ _ll_5_list_ll_arraycopy = rgc.ll_arraycopy + at elidable def _ll_1_gc_identityhash(x): return lltype.identityhash(x) +# the following function should not be "@elidable": I can think of +# a corner case in which id(const) is constant-folded, and then 'const' +# disappears and is collected too early (possibly causing another object +# with the same id() to appear). def _ll_1_gc_id(ptr): return llop.gc_id(lltype.Signed, ptr) @@ -420,10 +426,6 @@ _ll_1_dict_values.need_result_type = True _ll_1_dict_items .need_result_type = True - def _ll_1_newdictiter(ITER, d): - return ll_rdict.ll_dictiter(lltype.Ptr(ITER), d) - _ll_1_newdictiter.need_result_type = True - _dictnext_keys = staticmethod(ll_rdict.ll_dictnext_group['keys']) _dictnext_values = staticmethod(ll_rdict.ll_dictnext_group['values']) _dictnext_items = staticmethod(ll_rdict.ll_dictnext_group['items']) @@ -574,10 +576,6 @@ _ll_1_dict_values.need_result_type = True _ll_1_dict_items .need_result_type = True - def _ll_1_newdictiter(ITER, d): - return oo_rdict.ll_dictiter(ITER, d) - _ll_1_newdictiter.need_result_type = True - _dictnext_keys = staticmethod(oo_rdict.ll_dictnext_group['keys']) _dictnext_values = staticmethod(oo_rdict.ll_dictnext_group['values']) _dictnext_items = staticmethod(oo_rdict.ll_dictnext_group['items']) diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py --- a/pypy/jit/codewriter/test/test_jtransform.py +++ b/pypy/jit/codewriter/test/test_jtransform.py @@ -120,9 +120,9 @@ assert argtypes[0] == [v.concretetype for v in op.args[1:]] assert argtypes[1] == op.result.concretetype if oopspecindex == EI.OS_STR2UNICODE: - assert extraeffect == None # not pure, can raise! + assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE else: - assert extraeffect == EI.EF_ELIDABLE + assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE return 'calldescr-%d' % oopspecindex def calldescr_canraise(self, calldescr): return False @@ -769,7 +769,7 @@ def get_vinfo(self, v): return None def could_be_green_field(self, S1, name1): - assert S1 is S + assert S1 == S assert name1 == 'x' return True S = lltype.GcStruct('S', ('x', lltype.Char), diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py --- a/pypy/jit/metainterp/optimizeopt/__init__.py +++ b/pypy/jit/metainterp/optimizeopt/__init__.py @@ -55,7 +55,7 @@ def optimize_loop_1(metainterp_sd, loop, enable_opts, - inline_short_preamble=True, retraced=False): + inline_short_preamble=True, retraced=False, bridge=False): """Optimize loop.operations to remove internal overheadish operations. """ @@ -64,7 +64,7 @@ if unroll: optimize_unroll(metainterp_sd, loop, optimizations) else: - optimizer = Optimizer(metainterp_sd, loop, optimizations) + optimizer = Optimizer(metainterp_sd, loop, optimizations, bridge) optimizer.propagate_all_forward() def optimize_bridge_1(metainterp_sd, bridge, enable_opts, @@ -76,7 +76,7 @@ except KeyError: pass optimize_loop_1(metainterp_sd, bridge, enable_opts, - inline_short_preamble, retraced) + inline_short_preamble, retraced, bridge=True) if __name__ == '__main__': print ALL_OPTS_NAMES diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -1,7 +1,7 @@ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.libffi import Func -from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints +from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method @@ -48,7 +48,7 @@ inst_argtypes is actually a low-level array, but we can use it directly since the only thing we do with it is to read its items """ - + llfunc = funcval.box.getref_base() if we_are_translated(): func = cast_base_ptr_to_instance(Func, llfunc) diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -1,9 +1,10 @@ import os -from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.rlib.objectmodel import we_are_translated + from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.optimizeopt.optimizer import Optimization +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.resoperation import rop +from pypy.rlib.objectmodel import we_are_translated class CachedField(object): diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py --- a/pypy/jit/metainterp/optimizeopt/intbounds.py +++ b/pypy/jit/metainterp/optimizeopt/intbounds.py @@ -1,9 +1,10 @@ +from pypy.jit.metainterp.history import ConstInt +from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntLowerBound, + IntUpperBound) from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded, - IntLowerBound, IntUpperBound) -from pypy.jit.metainterp.history import Const, ConstInt -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop + class OptIntBounds(Optimization): """Keeps track of the bounds placed on integers by guards and remove diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -1,17 +1,11 @@ -from pypy.jit.metainterp.history import Box, BoxInt, LoopToken, BoxFloat,\ - ConstFloat -from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF +from pypy.jit.metainterp import jitprof, resume, compile +from pypy.jit.metainterp.executor import execute_nonspec +from pypy.jit.metainterp.history import BoxInt, BoxFloat, Const, ConstInt, REF +from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded +from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method, + args_dict) from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp import jitprof -from pypy.jit.metainterp.executor import execute_nonspec -from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs -from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict -from pypy.jit.metainterp.optimize import InvalidLoop -from pypy.jit.metainterp import resume, compile from pypy.jit.metainterp.typesystem import llhelper, oohelper -from pypy.rpython.lltypesystem import lltype -from pypy.jit.metainterp.history import AbstractDescr, make_hashable_int -from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded from pypy.tool.pairtype import extendabletype LEVEL_UNKNOWN = '\x00' @@ -254,10 +248,11 @@ class Optimizer(Optimization): - def __init__(self, metainterp_sd, loop, optimizations=None): + def __init__(self, metainterp_sd, loop, optimizations=None, bridge=False): self.metainterp_sd = metainterp_sd self.cpu = metainterp_sd.cpu self.loop = loop + self.bridge = bridge self.values = {} self.interned_refs = self.cpu.ts.new_ref_dict() self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd) @@ -413,9 +408,7 @@ return CVAL_ZERO def propagate_all_forward(self): - self.exception_might_have_happened = True - # ^^^ at least at the start of bridges. For loops, we could set - # it to False, but we probably don't care + self.exception_might_have_happened = self.bridge self.newoperations = [] self.first_optimization.propagate_begin_forward() self.i = 0 diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -1,10 +1,11 @@ +from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.metainterp.history import ConstInt, make_hashable_int +from pypy.jit.metainterp.optimize import InvalidLoop +from pypy.jit.metainterp.optimizeopt.intutils import IntBound from pypy.jit.metainterp.optimizeopt.optimizer import * -from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex -from pypy.jit.metainterp.history import ConstInt from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method -from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.metainterp.optimizeopt.intutils import IntBound +from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop, + ResOperation) from pypy.rlib.rarithmetic import highest_bit diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,7 +1,7 @@ - -from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.resoperation import ResOperation, rop + class OptSimplify(Optimization): def optimize_CALL_PURE(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -693,7 +693,6 @@ """ expected = """ [i] - guard_no_exception() [] i1 = int_add(i, 3) i2 = call(i1, descr=nonwritedescr) guard_no_exception() [i1, i2] @@ -4532,7 +4531,7 @@ escape(i1) jump(p0, i0) """ - self.optimize_loop(ops, expected) + self.optimize_strunicode_loop(ops, expected) def test_int_is_true_bounds(self): ops = """ @@ -4551,7 +4550,7 @@ guard_true(i1) [] jump(p0) """ - self.optimize_loop(ops, expected) + self.optimize_strunicode_loop(ops, expected) def test_strslice_subtraction_folds(self): ops = """ @@ -4586,6 +4585,42 @@ """ self.optimize_loop(ops, expected) + def test_null_char_str(self): + ops = """ + [p0] + p1 = newstr(4) + setfield_gc(p0, p1, descr=valuedescr) + jump(p0) + """ + # It used to be the case that this would have a series of + # strsetitem(p1, idx, 0), which was silly because memory is 0 filled + # when allocated. + expected = """ + [p0] + p1 = newstr(4) + setfield_gc(p0, p1, descr=valuedescr) + jump(p0) + """ + self.optimize_strunicode_loop(ops, expected) + + def test_newstr_strlen(self): + ops = """ + [i0] + p0 = newstr(i0) + escape(p0) + i1 = strlen(p0) + i2 = int_add(i1, 1) + jump(i2) + """ + expected = """ + [i0] + p0 = newstr(i0) + escape(p0) + i1 = int_add(i0, 1) + jump(i1) + """ + self.optimize_strunicode_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -889,12 +889,10 @@ i3 = call(i2, descr=nonwritedescr) jump(i1) # the exception is considered lost when we loop back """ - # note that 'guard_no_exception' at the very start must be kept - # around: bridges may start with one. (In case of loops we could - # remove it, but we probably don't care.) + # note that 'guard_no_exception' at the very start is kept around + # for bridges, but not for loops preamble = """ [i] - guard_no_exception() [] i1 = int_add(i, 3) i2 = call(i1, descr=nonwritedescr) guard_no_exception() [i1, i2] @@ -2993,6 +2991,38 @@ ''' self.optimize_loop(ops, expected, preamble, call_pure_results) + def test_call_pure_constant_folding_exc(self): + # CALL_PURE may be followed by GUARD_NO_EXCEPTION + arg_consts = [ConstInt(i) for i in (123456, 4, 5, 6)] + call_pure_results = {tuple(arg_consts): ConstInt(42)} + ops = ''' + [i0, i1, i2] + escape(i1) + escape(i2) + i3 = call_pure(123456, 4, 5, 6, descr=plaincalldescr) + guard_no_exception() [] + i4 = call_pure(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i3, i4) + ''' + preamble = ''' + [i0, i1, i2] + escape(i1) + escape(i2) + i4 = call(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i4) + ''' + expected = ''' + [i0, i2] + escape(42) + escape(i2) + i4 = call(123456, 4, i0, 6, descr=plaincalldescr) + guard_no_exception() [] + jump(i0, i4) + ''' + self.optimize_loop(ops, expected, preamble, call_pure_results) + # ---------- def test_vref_nonvirtual_nonescape(self): diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -1,14 +1,12 @@ +from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.metainterp.compile import ResumeGuardDescr +from pypy.jit.metainterp.history import TreeLoop, LoopToken +from pypy.jit.metainterp.jitexc import JitException +from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.optimizeopt.optimizer import * -from pypy.jit.metainterp.optimizeopt.virtualize import AbstractVirtualValue from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.compile import ResumeGuardDescr from pypy.jit.metainterp.resume import Snapshot -from pypy.jit.metainterp.history import TreeLoop, LoopToken -from pypy.rlib.debug import debug_start, debug_stop, debug_print -from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop -from pypy.jit.metainterp.jitexc import JitException -from pypy.jit.metainterp.history import make_hashable_int -from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.rlib.debug import debug_print # Assumptions # =========== @@ -22,7 +20,7 @@ # are also recreated to allow virtuals not supported to be forced. # # First of all, the optimizations are not allowed to introduce new -# boxes. It is the unoptimized version of the trace that is inlined to +# boxes. It is the unoptimized version of the trace that is inlined to # form the second iteration of the loop. Otherwise the # state of the virtuals would not be updated correctly. Whenever some # box from the first iteration is reused in the second iteration, it @@ -57,7 +55,7 @@ # be absorbed into the virtual p2 and never seen by the heap # optimizer. At the end of the loop both p2 and p3 are virtuals, but # the loop needs p2 to be a pointer to be able to call itself. So it -# is forced producing the operations +# is forced producing the operations # # p2 = new_with_vtable(ConstClass(node_vtable)) # setfield_gc(p2, i2, descr=nextdescr) @@ -68,7 +66,7 @@ # the trace were optimized under the wrong assumption that the # setfield_gc was store sinked which could lead to errors. In this # case what would happen is that it would be inserted once more in -# front of the guard. +# front of the guard. @@ -112,7 +110,7 @@ def inline_descr_inplace(self, descr): if isinstance(descr, ResumeGuardDescr): descr.rd_snapshot = self.inline_snapshot(descr.rd_snapshot) - + def inline_arg(self, arg): if arg is None: return None @@ -139,7 +137,7 @@ return False return True - def generate_guards(self, other, args, cpu, extra_guards): + def generate_guards(self, other, args, cpu, extra_guards): assert len(self.state) == len(other.state) == len(args) for i in range(len(self.state)): self.state[i].generate_guards(other.state[i], args[i], @@ -153,7 +151,7 @@ def register_virtual_fields(self, keybox, fieldboxes): self.fieldboxes[keybox] = fieldboxes - + def already_seen_virtual(self, keybox): return keybox in self.fieldboxes @@ -233,20 +231,20 @@ if self.level == LEVEL_CONSTANT: import pdb; pdb.set_trace() raise NotImplementedError - + class UnrollOptimizer(Optimization): """Unroll the loop into two iterations. The first one will become the preamble or entry bridge (don't think there is a distinction anymore)""" - + def __init__(self, metainterp_sd, loop, optimizations): self.optimizer = Optimizer(metainterp_sd, loop, optimizations) self.cloned_operations = [] for op in self.optimizer.loop.operations: newop = op.clone() self.cloned_operations.append(newop) - + def propagate_all_forward(self): loop = self.optimizer.loop jumpop = loop.operations[-1] @@ -284,7 +282,7 @@ assert isinstance(start_resumedescr, ResumeGuardDescr) snapshot = start_resumedescr.rd_snapshot while snapshot is not None: - snapshot_args = snapshot.boxes + snapshot_args = snapshot.boxes new_snapshot_args = [] for a in snapshot_args: if not isinstance(a, Const): @@ -313,7 +311,7 @@ short_loop.inputargs = loop.preamble.inputargs[:] short_loop.operations = short - # Clone ops and boxes to get private versions and + # Clone ops and boxes to get private versions and newargs = [a.clonebox() for a in short_loop.inputargs] inliner = Inliner(short_loop.inputargs, newargs) short_loop.inputargs = newargs @@ -336,10 +334,10 @@ for op in short_loop.operations: if op.result: op.result.forget_value() - + def inline(self, loop_operations, loop_args, jump_args): self.inliner = inliner = Inliner(loop_args, jump_args) - + for v in self.optimizer.values.values(): v.last_guard_index = -1 # FIXME: Are there any more indexes stored? @@ -371,12 +369,12 @@ jumpargs = jmp.getarglist() # FIXME: Should also loop over operations added by forcing things in this loop - for op in newoperations: + for op in newoperations: boxes_created_this_iteration[op.result] = True args = op.getarglist() if op.is_guard(): args = args + op.getfailargs() - + for a in args: if not isinstance(a, Const) and not a in boxes_created_this_iteration: if a not in inputargs: @@ -439,7 +437,7 @@ "at preamble position: ", preamble_i, "loop position: ", loop_i) return None - + if self.sameop(newop, loop_ops[loop_i]) \ and loop_i < len(loop_ops): try: @@ -460,7 +458,7 @@ "loop position: ", loop_i) return None short_preamble.append(op) - + state.update(op) preamble_i += 1 @@ -470,7 +468,7 @@ "at position", loop_i) return None - + jumpargs = [] for i in range(len(loop.inputargs)): try: @@ -498,7 +496,7 @@ return None if op.result: seen[op.result] = True - + return short_preamble class ExeState(object): @@ -508,7 +506,7 @@ self.unsafe_getitem = {} self.unsafe_getarrayitem = {} self.unsafe_getarrayitem_indexes = {} - + # Make sure it is safe to move the instrucions in short_preamble # to the top making short_preamble followed by loop equvivalent # to preamble @@ -545,15 +543,17 @@ elif opnum == rop.CALL: effectinfo = descr.get_extra_info() if effectinfo is not None: - if effectinfo.extraeffect == EffectInfo.EF_LOOPINVARIANT or \ - effectinfo.extraeffect == EffectInfo.EF_ELIDABLE: + ef = effectinfo.extraeffect + if ef == EffectInfo.EF_LOOPINVARIANT or \ + ef == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \ + ef == EffectInfo.EF_ELIDABLE_CAN_RAISE: return True return False - + def update(self, op): if (op.has_no_side_effect() or op.is_ovf() or - op.is_guard()): + op.is_guard()): return opnum = op.getopnum() descr = op.getdescr() @@ -566,7 +566,7 @@ if (opnum == rop.SETARRAYITEM_GC or opnum == rop.SETARRAYITEM_RAW): index = op.getarg(1) - if isinstance(index, Const): + if isinstance(index, Const): d = self.unsafe_getarrayitem_indexes.get(descr, None) if d is None: d = self.unsafe_getarrayitem_indexes[descr] = {} @@ -592,7 +592,7 @@ def __init__(self): self.map = {} - + def link_ops(self, preambleop, loopop): pargs = preambleop.getarglist() largs = loopop.getarglist() @@ -606,7 +606,7 @@ if not loopop.result: raise ImpossibleLink self.link_boxes(preambleop.result, loopop.result) - + def link_boxes(self, pbox, lbox): if lbox in self.map: @@ -627,11 +627,11 @@ def __init__(self, retraced): self.retraced = retraced self.inliner = None - - + + def reconstruct_for_next_iteration(self, optimizer, valuemap): return self - + def propagate_forward(self, op): if op.getopnum() == rop.JUMP: descr = op.getdescr() @@ -657,7 +657,7 @@ sh.virtual_state.generate_guards(virtual_state, args, cpu, extra_guards) - + ok = True except InvalidLoop: pass @@ -697,7 +697,7 @@ else: debug_print("Retracing (%d of %d)" % (retraced_count, limit)) - + raise RetraceLoop else: if not descr.failed_states: @@ -705,21 +705,21 @@ else: descr.failed_states.append(virtual_state) self.emit_operation(op) - - - + + + def inline(self, loop_operations, loop_args, jump_args, dryrun=False): self.inliner = inliner = Inliner(loop_args, jump_args) for op in loop_operations: newop = inliner.inline_op(op) - + if not dryrun: self.emit_operation(newop) else: if not self.is_emittable(newop): return False - + return True #def inline_arg(self, arg): diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -1,11 +1,11 @@ +from pypy.jit.codewriter.heaptracker import vtable2descr +from pypy.jit.metainterp.executor import execute from pypy.jit.metainterp.history import Const, ConstInt, BoxInt +from pypy.jit.metainterp.optimizeopt import optimizer +from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method, + descrlist_dict, sort_descrs) from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, sort_descrs from pypy.rlib.objectmodel import we_are_translated -from pypy.jit.metainterp.optimizeopt import optimizer -from pypy.jit.metainterp.executor import execute -from pypy.jit.codewriter.heaptracker import vtable2descr class AbstractVirtualValue(optimizer.OptValue): diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -1,18 +1,14 @@ -from pypy.rpython.lltypesystem import lltype, rstr, llmemory +from pypy.jit.codewriter.effectinfo import EffectInfo +from pypy.jit.metainterp.history import (BoxInt, Const, ConstInt, ConstPtr, + get_const_ptr_for_string, get_const_ptr_for_unicode) +from pypy.jit.metainterp.optimizeopt import optimizer, virtualize +from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1, llhelper +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method +from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.rlib.objectmodel import specialize, we_are_translated +from pypy.rlib.unroll import unrolling_iterable from pypy.rpython import annlowlevel -from pypy.jit.metainterp.history import Box, BoxInt, BoxPtr -from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr -from pypy.jit.metainterp.history import get_const_ptr_for_string -from pypy.jit.metainterp.history import get_const_ptr_for_unicode -from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.optimizeopt import optimizer, virtualize -from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1 -from pypy.jit.metainterp.optimizeopt.optimizer import llhelper -from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.codewriter.effectinfo import EffectInfo -from pypy.jit.codewriter import heaptracker -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.objectmodel import specialize, we_are_translated +from pypy.rpython.lltypesystem import lltype, rstr class StrOrUnicode(object): @@ -147,10 +143,11 @@ def string_copy_parts(self, optimizer, targetbox, offsetbox, mode): for i in range(len(self._chars)): charbox = self._chars[i].force_box() - optimizer.emit_operation(ResOperation(mode.STRSETITEM, [targetbox, - offsetbox, - charbox], - None)) + if not (isinstance(charbox, Const) and charbox.same_constant(CONST_0)): + optimizer.emit_operation(ResOperation(mode.STRSETITEM, [targetbox, + offsetbox, + charbox], + None)) offsetbox = _int_add(optimizer, offsetbox, CONST_1) return offsetbox @@ -402,6 +399,7 @@ else: self.getvalue(op.result).ensure_nonnull() self.emit_operation(op) + self.pure(mode.STRLEN, [op.result], op.getarg(0)) def optimize_STRSETITEM(self, op): value = self.getvalue(op.getarg(0)) diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -56,6 +56,8 @@ # for resume.py operation self.parent_resumedata_snapshot = None self.parent_resumedata_frame_info_list = None + # counter for unrolling inlined loops + self.unroll_iterations = 1 @specialize.arg(3) def copy_constants(self, registers, constants, ConstClass): @@ -931,6 +933,10 @@ # 'redboxes' back into the registers where it comes from. put_back_list_of_boxes3(self, jcposition, redboxes) else: + if jitdriver_sd.warmstate.should_unroll_one_iteration(greenboxes): + if self.unroll_iterations > 0: + self.unroll_iterations -= 1 + return # warning! careful here. We have to return from the current # frame containing the jit_merge_point, and then use # do_recursive_call() to follow the recursive call. This is @@ -1193,7 +1199,7 @@ return self.metainterp.execute_and_record(opnum, descr, *argboxes) @specialize.arg(1) - def execute_varargs(self, opnum, argboxes, descr, exc): + def execute_varargs(self, opnum, argboxes, descr, exc, pure): self.metainterp.clear_exception() resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes, descr=descr) @@ -1201,6 +1207,9 @@ self.make_result_of_lastop(resbox) # ^^^ this is done before handle_possible_exception() because we # need the box to show up in get_list_of_active_boxes() + if pure and self.metainterp.last_exc_value_box is None: + resbox = self.metainterp.record_result_of_call_pure(resbox) + exc = exc and not isinstance(resbox, Const) if exc: self.metainterp.handle_possible_exception() else: @@ -1263,16 +1272,14 @@ return resbox else: effect = effectinfo.extraeffect - if effect == effectinfo.EF_CANNOT_RAISE: - return self.execute_varargs(rop.CALL, allboxes, descr, False) - elif effect == effectinfo.EF_ELIDABLE: - return self.metainterp.record_result_of_call_pure( - self.execute_varargs(rop.CALL, allboxes, descr, False)) - elif effect == effectinfo.EF_LOOPINVARIANT: + if effect == effectinfo.EF_LOOPINVARIANT: return self.execute_varargs(rop.CALL_LOOPINVARIANT, allboxes, - descr, False) - else: - return self.execute_varargs(rop.CALL, allboxes, descr, True) + descr, False, False) + exc = (effect != effectinfo.EF_CANNOT_RAISE and + effect != effectinfo.EF_ELIDABLE_CANNOT_RAISE) + pure = (effect == effectinfo.EF_ELIDABLE_CAN_RAISE or + effect == effectinfo.EF_ELIDABLE_CANNOT_RAISE) + return self.execute_varargs(rop.CALL, allboxes, descr, exc, pure) def do_residual_or_indirect_call(self, funcbox, calldescr, argboxes): """The 'residual_call' operation is emitted in two cases: @@ -1680,8 +1687,12 @@ return if opnum == rop.CALL: effectinfo = descr.get_extra_info() - if effectinfo.extraeffect == effectinfo.EF_ELIDABLE: - return + if effectinfo is not None: + ef = effectinfo.extraeffect + if ef == effectinfo.EF_LOOPINVARIANT or \ + ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or \ + ef == effectinfo.EF_ELIDABLE_CAN_RAISE: + return if self.heap_cache: self.heap_cache.clear() if self.heap_array_cache: @@ -2369,6 +2380,7 @@ tobox = newbox if change: self.heap_cache[descr] = frombox, tobox + # XXX what about self.heap_array_cache? def find_biggest_function(self): start_stack = [] diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py --- a/pypy/jit/metainterp/test/support.py +++ b/pypy/jit/metainterp/test/support.py @@ -277,3 +277,15 @@ NODE._add_fields({'value': ootype.Signed, 'next': NODE}) return NODE + +# ____________________________________________________________ + +class _Foo: + pass + +def noConst(x): + """Helper function for tests, returning 'x' as a BoxInt/BoxPtr + even if it is a ConstInt/ConstPtr.""" + f1 = _Foo(); f2 = _Foo() + f1.x = x; f2.x = 0 + return f1.x diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -14,7 +14,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT -from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, noConst class BasicTests: @@ -407,6 +407,58 @@ # the CALL_PURE is constant-folded away by optimizeopt.py self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=0) + def test_elidable_raising(self): + myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable + def externfn(x): + if x <= 0: + raise ValueError + return x - 1 + def f(n, m): + while n > 0: + myjitdriver.can_enter_jit(n=n, m=m) + myjitdriver.jit_merge_point(n=n, m=m) + try: + n -= externfn(m) + except ValueError: + n -= 1 + return n + res = self.meta_interp(f, [22, 6]) + assert res == -3 + # the CALL_PURE is constant-folded away during tracing + self.check_loops(int_sub=1, call=0, call_pure=0) + # + res = self.meta_interp(f, [22, -5]) + assert res == 0 + # raises: becomes CALL and is not constant-folded away + self.check_loops(int_sub=1, call=1, call_pure=0) + + def test_elidable_raising_2(self): + myjitdriver = JitDriver(greens = ['m'], reds = ['n']) + @elidable + def externfn(x): + if x <= 0: + raise ValueError + return x - 1 + def f(n, m): + while n > 0: + myjitdriver.can_enter_jit(n=n, m=m) + myjitdriver.jit_merge_point(n=n, m=m) + try: + n -= externfn(noConst(m)) + except ValueError: + n -= 1 + return n + res = self.meta_interp(f, [22, 6]) + assert res == -3 + # the CALL_PURE is constant-folded away by optimizeopt.py + self.check_loops(int_sub=1, call=0, call_pure=0) + # + res = self.meta_interp(f, [22, -5]) + assert res == 0 + # raises: becomes CALL and is not constant-folded away + self.check_loops(int_sub=1, call=1, call_pure=0) + def test_constant_across_mp(self): myjitdriver = JitDriver(greens = [], reds = ['n']) class X(object): @@ -508,6 +560,32 @@ assert res == 84 - 61 - 62 self.check_history(call=1) # because the trace starts immediately + def test_unroll_one_loop_iteration(self): + def unroll(code): + return code == 0 + myjitdriver = JitDriver(greens = ['code'], + reds = ['loops', 'inner_loops', 's'], + should_unroll_one_iteration=unroll) + + def f(code, loops, inner_loops): + s = 0 + while loops > 0: + myjitdriver.jit_merge_point(code=code, loops=loops, + inner_loops=inner_loops, s=s) + if code == 1: + s += f(0, inner_loops, 0) + loops -= 1 + s += 1 + return s + + res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True) + assert res == f(1, 4, 1) + self.check_history(call_assembler=0) + + res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True) + assert res == f(1, 4, 2) + self.check_history(call_assembler=1) + def test_format(self): def f(n): return len("<%d>" % n) diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -157,7 +157,7 @@ # the same arguments are not folded, because we have conflicting # definitions of pure, once strhash can be appropriately folded # this should be decreased to seven. - self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5, + self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 6, "guard_true": 1, "int_and": 1, "int_gt": 1, "int_is_true": 1, "int_sub": 1, "jump": 1, "new_with_vtable": 1, "setfield_gc": 1}) diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py --- a/pypy/jit/metainterp/test/test_string.py +++ b/pypy/jit/metainterp/test/test_string.py @@ -358,3 +358,22 @@ self.check_loops(call=3, # str(), _str(), escape() newunicode=1, unicodegetitem=0, unicodesetitem=1, copyunicodecontent=1) + + def test_str2unicode_fold(self): + _str = self._str + jitdriver = JitDriver(greens = ['g'], reds = ['m']) + @dont_look_inside + def escape(x): + print str(x) + def f(g, m): + g = str(g) + while m >= 0: + jitdriver.can_enter_jit(g=g, m=m) + jitdriver.jit_merge_point(g=g, m=m) + escape(_str(g)) + m -= 1 + return 42 + self.meta_interp(f, [6, 7]) + self.check_loops(call_pure=0, call=1, + newunicode=0, unicodegetitem=0, + unicodesetitem=0, copyunicodecontent=0) diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -186,6 +186,7 @@ _get_printable_location_ptr = None _confirm_enter_jit_ptr = None _can_never_inline_ptr = None + _should_unroll_one_iteration_ptr = None class FakeCell: dont_trace_here = False state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) @@ -214,6 +215,7 @@ _confirm_enter_jit_ptr = None _can_never_inline_ptr = None _get_jitcell_at_ptr = None + _should_unroll_one_iteration_ptr = None state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) state.make_jitdriver_callbacks() res = state.get_location_str([ConstInt(5), constfloat(42.5)]) @@ -238,6 +240,7 @@ _confirm_enter_jit_ptr = llhelper(ENTER_JIT, confirm_enter_jit) _can_never_inline_ptr = None _get_jitcell_at_ptr = None + _should_unroll_one_iteration_ptr = None state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) state.make_jitdriver_callbacks() @@ -262,6 +265,7 @@ _confirm_enter_jit_ptr = None _can_never_inline_ptr = llhelper(CAN_NEVER_INLINE, can_never_inline) _get_jitcell_at_ptr = None + _should_unroll_one_iteration_ptr = None state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) state.make_jitdriver_callbacks() diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -409,6 +409,7 @@ jd.warmstate = state def crash_in_jit(e): + tb = not we_are_translated() and sys.exc_info()[2] try: raise e except JitException: @@ -422,8 +423,8 @@ print "~~~ Crash in JIT!" print '~~~ %s: %s' % (e.__class__, e) if sys.stdout == sys.__stdout__: - import pdb; pdb.post_mortem(sys.exc_info()[2]) - raise + import pdb; pdb.post_mortem(tb) + raise e.__class__, e, tb fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True) crash_in_jit._dont_inline_ = True @@ -468,6 +469,9 @@ onlygreens=False) jd._can_never_inline_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool) + jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd, + annhelper, jd.jitdriver.should_unroll_one_iteration, + annmodel.s_Bool) annhelper.finish() def _make_hook_graph(self, jitdriver_sd, annhelper, func, diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -572,6 +572,19 @@ return can_inline_greenargs(*greenargs) self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + + if jd._should_unroll_one_iteration_ptr is None: + def should_unroll_one_iteration(greenkey): + return False + else: + rtyper = self.warmrunnerdesc.rtyper + inline_ptr = jd._should_unroll_one_iteration_ptr + def should_unroll_one_iteration(greenkey): + greenargs = unwrap_greenkey(greenkey) + fn = support.maybe_on_top_of_llinterp(rtyper, inline_ptr) + return fn(*greenargs) + self.should_unroll_one_iteration = should_unroll_one_iteration + if hasattr(jd.jitdriver, 'on_compile'): def on_compile(logger, token, operations, type, greenkey): greenargs = unwrap_greenkey(greenkey) diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -11,6 +11,7 @@ from pypy.rlib import libffi from pypy.rlib.rdynload import DLOpenError from pypy.rlib.rarithmetic import intmask, r_uint +from pypy.rlib.objectmodel import we_are_translated class W_FFIType(Wrappable): @@ -74,6 +75,13 @@ def is_struct(self): return libffi.types.is_struct(self.ffitype) + def is_char_p(self): + return self is app_types.char_p + + def is_unichar_p(self): + return self is app_types.unichar_p + + W_FFIType.typedef = TypeDef( 'FFIType', __repr__ = interp2app(W_FFIType.repr), @@ -115,7 +123,12 @@ ## 'Z' : ffi_type_pointer, ] - return dict([(t.name, t) for t in types]) + d = dict([(t.name, t) for t in types]) + w_char = d['char'] + w_unichar = d['unichar'] + d['char_p'] = W_FFIType('char_p', libffi.types.pointer, w_pointer_to = w_char) + d['unichar_p'] = W_FFIType('unichar_p', libffi.types.pointer, w_pointer_to = w_unichar) + return d class app_types: pass @@ -125,9 +138,14 @@ try: return descr_new_pointer.cache[w_pointer_to] except KeyError: - w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) - name = '(pointer to %s)' % w_pointer_to.name - w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to) + if w_pointer_to is app_types.char: + w_result = app_types.char_p + elif w_pointer_to is app_types.unichar: + w_result = app_types.unichar_p + else: + w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) + name = '(pointer to %s)' % w_pointer_to.name + w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to) descr_new_pointer.cache[w_pointer_to] = w_result return w_result descr_new_pointer.cache = {} @@ -164,6 +182,7 @@ self.func = func self.argtypes_w = argtypes_w self.w_restype = w_restype + self.to_free = [] @jit.unroll_safe def build_argchain(self, space, args_w): @@ -188,6 +207,9 @@ self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) + elif self.add_char_p_maybe(space, argchain, w_arg, w_argtype): + # the argument is added to the argchain direcly by the method above + pass elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) @@ -212,6 +234,29 @@ assert False, "Argument shape '%s' not supported" % w_argtype return argchain + def add_char_p_maybe(self, space, argchain, w_arg, w_argtype): + """ + Automatic conversion from string to char_p. The allocated buffer will + be automatically freed after the call. + """ + w_type = jit.promote(space.type(w_arg)) + if w_argtype.is_char_p() and w_type is space.w_str: + strval = space.str_w(w_arg) + buf = rffi.str2charp(strval) + self.to_free.append(rffi.cast(rffi.VOIDP, buf)) + addr = rffi.cast(rffi.ULONG, buf) + argchain.arg(addr) + return True + elif w_argtype.is_unichar_p() and (w_type is space.w_str or + w_type is space.w_unicode): + unicodeval = space.unicode_w(w_arg) + buf = rffi.unicode2wcharp(unicodeval) + self.to_free.append(rffi.cast(rffi.VOIDP, buf)) + addr = rffi.cast(rffi.ULONG, buf) + argchain.arg(addr) + return True + return False + def convert_pointer_arg_maybe(self, space, w_arg, w_argtype): """ Try to convert the argument by calling _as_ffi_pointer_() @@ -235,6 +280,17 @@ def call(self, space, args_w): self = jit.promote(self) argchain = self.build_argchain(space, args_w) + return self._do_call(space, argchain) + + def free_temp_buffers(self, space): + for buf in self.to_free: + if not we_are_translated(): + buf[0] = '\00' # invalidate the buffer, so that + # test_keepalive_temp_buffer can fail + lltype.free(buf, flavor='raw') + self.to_free = [] + + def _do_call(self, space, argchain): w_restype = self.w_restype if w_restype.is_longlong(): # note that we must check for longlong first, because either @@ -372,6 +428,7 @@ '_ffi.FuncPtr', __call__ = interp2app(W_FuncPtr.call), getaddr = interp2app(W_FuncPtr.getaddr), + free_temp_buffers = interp2app(W_FuncPtr.free_temp_buffers), fromaddr = interp2app(descr_fromaddr, as_classmethod=True) ) diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -188,6 +188,75 @@ assert get_dummy() == 123 set_val_to_ptr(ptr2, 0) + def test_convert_strings_to_char_p(self): + """ + long mystrlen(char* s) + { + long len = 0; + while(*s++) + len++; + return len; + } + """ + from _ffi import CDLL, types + import _rawffi + libfoo = CDLL(self.libfoo_name) + mystrlen = libfoo.getfunc('mystrlen', [types.char_p], types.slong) + # + # first, try automatic conversion from a string + assert mystrlen('foobar') == 6 + # then, try to pass an explicit pointer + CharArray = _rawffi.Array('c') + mystr = CharArray(7, 'foobar') + assert mystrlen(mystr.buffer) == 6 + mystr.free() + mystrlen.free_temp_buffers() + + def test_convert_unicode_to_unichar_p(self): + """ + #include + long mystrlen_u(wchar_t* s) + { + long len = 0; + while(*s++) + len++; + return len; + } + """ + from _ffi import CDLL, types + import _rawffi + libfoo = CDLL(self.libfoo_name) + mystrlen = libfoo.getfunc('mystrlen_u', [types.unichar_p], types.slong) + # + # first, try automatic conversion from strings and unicode + assert mystrlen('foobar') == 6 + assert mystrlen(u'foobar') == 6 + assert mystrlen(u'ab\u2070') == 3 + # then, try to pass an explicit pointer + UniCharArray = _rawffi.Array('u') + mystr = UniCharArray(7, u'foobar') + assert mystrlen(mystr.buffer) == 6 + mystr.free() + mystrlen.free_temp_buffers() + + def test_keepalive_temp_buffer(self): + """ + char* do_nothing(char* s) + { + return s; + } + """ + from _ffi import CDLL, types + import _rawffi + libfoo = CDLL(self.libfoo_name) + do_nothing = libfoo.getfunc('do_nothing', [types.char_p], types.char_p) + CharArray = _rawffi.Array('c') + # + ptr = do_nothing('foobar') + array = CharArray.fromaddress(ptr, 7) + assert list(array) == list('foobar\00') + do_nothing.free_temp_buffers() + def test_typed_pointer(self): from _ffi import types intptr = types.Pointer(types.sint) # create a typed pointer to sint @@ -204,6 +273,13 @@ assert x is y assert x is not z + def test_char_p_cached(self): + from _ffi import types + x = types.Pointer(types.char) + assert x is types.char_p + x = types.Pointer(types.unichar) + assert x is types.unichar_p + def test_typed_pointer_args(self): """ extern int dummy; // defined in test_void_result diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -14,8 +14,6 @@ from pypy.rpython.lltypesystem import lltype, rffi -memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void) - @unwrap_spec(typecode=str) def w_array(space, w_cls, typecode, __args__): if len(__args__.arguments_w) > 1: @@ -617,7 +615,7 @@ def array_copy__Array(space, self): w_a = mytype.w_class(self.space) w_a.setlen(self.len) - memcpy( + rffi.c_memcpy( rffi.cast(rffi.VOIDP, w_a.buffer), rffi.cast(rffi.VOIDP, self.buffer), self.len * mytype.bytes diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -44,9 +44,11 @@ ec.w_tracefunc is None) def can_never_inline(next_instr, is_being_profiled, bytecode): + return False + +def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode): return (bytecode.co_flags & CO_GENERATOR) != 0 - def wrap_oplist(space, logops, operations): list_w = [] for op in operations: @@ -110,7 +112,9 @@ get_jitcell_at = get_jitcell_at, set_jitcell_at = set_jitcell_at, confirm_enter_jit = confirm_enter_jit, - can_never_inline = can_never_inline) + can_never_inline = can_never_inline, + should_unroll_one_iteration = + should_unroll_one_iteration) class __extend__(PyFrame): diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py @@ -0,0 +1,25 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGenerators(BaseTestPyPyC): + def test_simple_generator(self): + def main(n): + def f(): + for i in range(10000): + yield i + + def g(): + for i in f(): # ID: generator + pass + + g() + + log = self.run(main, [500]) + loop, = log.loops_by_filename(self.filepath) + assert loop.match_by_id("generator", """ + i16 = force_token() + p45 = new_with_vtable(ConstClass(W_IntObject)) + setfield_gc(p45, i29, descr=) + setarrayitem_gc(p8, 0, p45, descr=) + jump(..., descr=...) + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py --- a/pypy/module/pypyjit/test_pypy_c/test_math.py +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -30,3 +30,34 @@ --TICK-- jump(..., descr=) """) + + def test_sin_cos(self): + def main(n): + import math + + i = 1 + s = 0.0 + while i < n: + s += math.sin(i) - math.cos(i) + i += 1 + return s + log = self.run(main, [500]) + assert round(log.result, 6) == round(main(500), 6) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i2 = int_lt(i0, i1) + guard_true(i2, descr=...) + f1 = cast_int_to_float(i0) + i3 = float_eq(f1, inf) + i4 = float_eq(f1, -inf) + i5 = int_or(i3, i4) + i6 = int_is_true(i5) + guard_false(i6, descr=...) + f2 = call(ConstClass(sin), f1, descr=) + f3 = call(ConstClass(cos), f1, descr=) + f4 = float_sub(f2, f3) + f5 = float_add(f0, f4) + i7 = int_add(i0, f1) + --TICK-- + jump(..., descr=) + """) \ No newline at end of file diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py @@ -14,14 +14,27 @@ return args[-1] def check_type(self, typ, arg): + unwrapped_types = { + c_float: (float,), + c_double: (float,), + c_char: (str,), + c_char_p: (str,), + c_uint: (int, long), + c_ulong: (int, long), + } + PROTO = self.functype.im_func(typ, typ) - result = PROTO(self.callback)(arg) + cfunc = PROTO(self.callback) + result = cfunc(arg) if typ == c_float: assert abs(result - arg) < 0.000001 else: assert self.got_args == (arg,) assert result == arg + result2 = cfunc(typ(arg)) + assert type(result2) in unwrapped_types.get(typ, (int, long)) + PROTO = self.functype.im_func(typ, c_byte, typ) result = PROTO(self.callback)(-3, arg) if typ == c_float: @@ -222,3 +235,20 @@ out, err = capsys.readouterr() assert (out, err) == ("", "") + + def test_callback_pyobject(self): + def callback(obj): + return obj + + FUNC = CFUNCTYPE(py_object, py_object) + cfunc = FUNC(callback) + param = c_int(42) + assert cfunc(param) is param + + def test_raise_argumenterror(self): + def callback(x): + pass + FUNC = CFUNCTYPE(None, c_void_p) + cfunc = FUNC(callback) + param = c_uint(42) + py.test.raises(ArgumentError, "cfunc(param)") diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py b/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py @@ -90,3 +90,8 @@ assert sqrt._objects is my_sqrt._objects # on CPython too my_sqrt._objects.clear() my_sqrt._objects.update(saved_objects) + + def test_cast_argumenterror(self): + param = c_uint(42) + py.test.raises(ArgumentError, "cast(param, c_void_p)") + diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py @@ -46,6 +46,18 @@ tf_b.argtypes = (c_byte,) assert tf_b(-126) == -42 + def test_undeclared_restype(self): + # make sure we get a fresh function + try: + del dll.tf_i + except AttributeError: + pass + tf_i = dll.tf_i + assert not tf_i._is_fastpath + tf_i.argtypes = (c_int,) + assert tf_i._is_fastpath + assert tf_i(12) == 4 + def test_pointer_args(self): f = dll._testfunc_p_p f.restype = POINTER(c_int) @@ -63,13 +75,10 @@ result = f(mystr, ord("b")) assert result == "bcd" - @py.test.mark.xfail def test_strings(self): f = dll.my_strchr f.argtypes = [c_char_p, c_int] f.restype = c_char_p - # python strings need to be converted to c_char_p, but this is - # supported only in the slow path so far result = f("abcd", ord("b")) assert result == "bcd" diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -488,11 +488,9 @@ warnings.simplefilter("always") with warnings.catch_warnings(record=True) as w: dll.get_an_integer() - assert len(w) == 2 + assert len(w) == 1 assert issubclass(w[0].category, RuntimeWarning) - assert issubclass(w[1].category, RuntimeWarning) assert "C function without declared arguments called" in str(w[0].message) - assert "C function without declared return type called" in str(w[1].message) def test_errcheck(self): py.test.skip('fixme') diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -35,6 +35,13 @@ return w_hash object_hash._annspecialcase_ = 'specialize:memo' +def type_eq(space): + "Utility that returns the app-level descriptor type.__eq__." + w_src, w_eq = space.lookup_in_type_where(space.w_type, + '__eq__') + return w_eq +type_eq._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): w_type = space.type(w_obj) typename = w_type.getname(space) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -282,8 +282,8 @@ return space.wrap(''.join(w_bytearray.data)) def _convert_idx_params(space, w_self, w_start, w_stop): - start = slicetype._Eval_SliceIndex(space, w_start) - stop = slicetype._Eval_SliceIndex(space, w_stop) + start = slicetype.eval_slice_index(space, w_start) + stop = slicetype.eval_slice_index(space, w_stop) length = len(w_self.data) if start < 0: start += length diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py --- a/pypy/objspace/std/identitydict.py +++ b/pypy/objspace/std/identitydict.py @@ -2,6 +2,7 @@ ## dict strategy (see dict_multiobject.py) from pypy.rlib import rerased +from pypy.rlib.debug import mark_dict_non_null from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy, DictStrategy, IteratorImplementation, @@ -50,7 +51,7 @@ The second case is completely non-deterministic, even in CPython. Depending on the phase of the moon, you might call the __eq__ or not, so it is perfectly fine to *never* call it. Morever, in practice with the - minimar GC we never have two live objects with the same hash, so it would + minimark GC we never have two live objects with the same hash, so it would never happen anyway. """ @@ -65,7 +66,9 @@ return wrapped def get_empty_storage(self): - return self.erase({}) + d = {} + mark_dict_non_null(d) + return self.erase(d) def is_correct_type(self, w_obj): w_type = self.space.type(w_obj) diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py --- a/pypy/objspace/std/sliceobject.py +++ b/pypy/objspace/std/sliceobject.py @@ -4,7 +4,7 @@ from pypy.interpreter import gateway from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.slicetype import _Eval_SliceIndex +from pypy.objspace.std.slicetype import eval_slice_index class W_SliceObject(W_Object): from pypy.objspace.std.slicetype import slice_typedef as typedef @@ -25,7 +25,7 @@ if space.is_w(w_slice.w_step, space.w_None): step = 1 else: - step = _Eval_SliceIndex(space, w_slice.w_step) + step = eval_slice_index(space, w_slice.w_step) if step == 0: raise OperationError(space.w_ValueError, space.wrap("slice step cannot be zero")) @@ -35,7 +35,7 @@ else: start = 0 else: - start = _Eval_SliceIndex(space, w_slice.w_start) + start = eval_slice_index(space, w_slice.w_start) if start < 0: start += length if start < 0: @@ -54,7 +54,7 @@ else: stop = length else: - stop = _Eval_SliceIndex(space, w_slice.w_stop) + stop = eval_slice_index(space, w_slice.w_stop) if stop < 0: stop += length if stop < 0: diff --git a/pypy/objspace/std/slicetype.py b/pypy/objspace/std/slicetype.py --- a/pypy/objspace/std/slicetype.py +++ b/pypy/objspace/std/slicetype.py @@ -14,7 +14,7 @@ ' normal slices.') # utility functions -def _Eval_SliceIndex(space, w_int): +def eval_slice_index(space, w_int): try: return space.getindex_w(w_int, None) # clamp if long integer too large except OperationError, err: @@ -25,7 +25,7 @@ "None or have an __index__ method")) def adapt_lower_bound(space, size, w_index): - index = _Eval_SliceIndex(space, w_index) + index = eval_slice_index(space, w_index) if index < 0: index = index + size if index < 0: @@ -34,7 +34,7 @@ return index def adapt_bound(space, size, w_index): - index = _Eval_SliceIndex(space, w_index) + index = eval_slice_index(space, w_index) if index < 0: index = index + size if index < 0: diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -913,7 +913,7 @@ def repr__String(space, w_str): s = w_str._value - buf = StringBuilder(50) + buf = StringBuilder(len(s) + 2) quote = "'" if quote in s and '"' not in s: diff --git a/pypy/objspace/std/test/test_identitydict.py b/pypy/objspace/std/test/test_identitydict.py --- a/pypy/objspace/std/test/test_identitydict.py +++ b/pypy/objspace/std/test/test_identitydict.py @@ -32,10 +32,20 @@ def __hash__(self): return 0 + class TypeSubclass(type): + pass + + class TypeSubclassCustomCmp(type): + def __cmp__(self, other): + return 0 + assert self.compares_by_identity(Plain) assert not self.compares_by_identity(CustomEq) assert not self.compares_by_identity(CustomCmp) assert not self.compares_by_identity(CustomHash) + assert self.compares_by_identity(type) + assert self.compares_by_identity(TypeSubclass) + assert not self.compares_by_identity(TypeSubclassCustomCmp) def test_modify_class(self): class X(object): diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -172,8 +172,8 @@ return space.wrap(count) def tuple_index__Tuple_ANY_ANY_ANY(space, w_tuple, w_obj, w_start, w_stop): - start = slicetype._Eval_SliceIndex(space, w_start) - stop = slicetype._Eval_SliceIndex(space, w_stop) + start = slicetype.eval_slice_index(space, w_start) + stop = slicetype.eval_slice_index(space, w_stop) length = len(w_tuple.wrappeditems) if start < 0: start += length diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -173,8 +173,6 @@ # ^^^ conservative default, fixed during real usage if space.config.objspace.std.withidentitydict: - did_compare_by_identity = ( - w_self.compares_by_identity_status == COMPARES_BY_IDENTITY) if (key is None or key == '__eq__' or key == '__cmp__' or key == '__hash__'): w_self.compares_by_identity_status = UNKNOWN @@ -229,7 +227,7 @@ return w_self.getattribute_if_not_from_object() is None def compares_by_identity(w_self): - from pypy.objspace.descroperation import object_hash + from pypy.objspace.descroperation import object_hash, type_eq if not w_self.space.config.objspace.std.withidentitydict: return False # conservative # @@ -238,7 +236,9 @@ return w_self.compares_by_identity_status == COMPARES_BY_IDENTITY # default_hash = object_hash(w_self.space) - overrides_eq_cmp_or_hash = (w_self.lookup('__eq__') or + my_eq = w_self.lookup('__eq__') + overrides_eq = (my_eq and my_eq is not type_eq(w_self.space)) + overrides_eq_cmp_or_hash = (overrides_eq or w_self.lookup('__cmp__') or w_self.lookup('__hash__') is not default_hash) if overrides_eq_cmp_or_hash: diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -16,7 +16,8 @@ Most importantly it doesn't mean that an elidable function has no observable side effect, but those side effects are idempotent (ie caching). - For now, such a function should never raise an exception. + If a particular call to this function ends up raising an exception, then it + is handled like a normal function call (this decorator is ignored). """ func._elidable_function_ = True return func @@ -315,7 +316,7 @@ def __init__(self, greens=None, reds=None, virtualizables=None, get_jitcell_at=None, set_jitcell_at=None, get_printable_location=None, confirm_enter_jit=None, - can_never_inline=None): + can_never_inline=None, should_unroll_one_iteration=None): if greens is not None: self.greens = greens if reds is not None: @@ -334,6 +335,7 @@ self.get_printable_location = get_printable_location self.confirm_enter_jit = confirm_enter_jit self.can_never_inline = can_never_inline + self.should_unroll_one_iteration = should_unroll_one_iteration def _freeze_(self): return True diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -40,7 +40,7 @@ # In that case, do 5 bits at a time. The potential drawback is that # a table of 2**5 intermediate results is computed. -FIVEARY_CUTOFF = 8 +## FIVEARY_CUTOFF = 8 disabled for now def _mask_digit(x): @@ -456,7 +456,7 @@ # python adaptation: moved macros REDUCE(X) and MULT(X, Y, result) # into helper function result = _help_mult(x, y, c) - if b.numdigits() <= FIVEARY_CUTOFF: + if 1: ## b.numdigits() <= FIVEARY_CUTOFF: # Left-to-right binary exponentiation (HAC Algorithm 14.79) # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf i = b.numdigits() - 1 @@ -469,26 +469,30 @@ z = _help_mult(z, a, c) j >>= 1 i -= 1 - else: - # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) - # This is only useful in the case where c != None. - # z still holds 1L - table = [z] * 32 - table[0] = z - for i in range(1, 32): - table[i] = _help_mult(table[i-1], a, c) - i = b.numdigits() - 1 - while i >= 0: - bi = b.digit(i) - j = SHIFT - 5 - while j >= 0: - index = (bi >> j) & 0x1f - for k in range(5): - z = _help_mult(z, z, c) - if index: - z = _help_mult(z, table[index], c) - j -= 5 - i -= 1 +## else: +## This code is disabled for now, because it assumes that +## SHIFT is a multiple of 5. It could be fixed but it looks +## like it's more troubles than benefits... +## +## # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) +## # This is only useful in the case where c != None. +## # z still holds 1L +## table = [z] * 32 +## table[0] = z +## for i in range(1, 32): +## table[i] = _help_mult(table[i-1], a, c) +## i = b.numdigits() - 1 +## while i >= 0: +## bi = b.digit(i) +## j = SHIFT - 5 +## while j >= 0: +## index = (bi >> j) & 0x1f +## for k in range(5): +## z = _help_mult(z, z, c) +## if index: +## z = _help_mult(z, table[index], c) +## j -= 5 +## i -= 1 if negativeOutput and z.sign != 0: z = z.sub(c) diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py --- a/pypy/rlib/rerased.py +++ b/pypy/rlib/rerased.py @@ -113,7 +113,7 @@ if hop.r_result.lowleveltype is lltype.Void: return hop.inputconst(lltype.Void, None) [v] = hop.inputargs(hop.args_r[0]) - return hop.genop('cast_opaque_ptr', [v], resulttype = hop.r_result) + return hop.args_r[0].rtype_unerase(hop, v) return erase, unerase @@ -147,7 +147,7 @@ def specialize_call(self, hop): [v] = hop.inputargs(hop.args_r[0]) assert isinstance(hop.s_result, annmodel.SomeInteger) - return hop.gendirectcall(ll_unerase_int, v) + return hop.args_r[0].rtype_unerase_int(hop, v) def ll_unerase_int(gcref): from pypy.rpython.lltypesystem.lloperation import llop @@ -174,7 +174,10 @@ return False # cannot be None, but can contain a None def rtyper_makerepr(self, rtyper): - return ErasedRepr(rtyper) + if rtyper.type_system.name == 'lltypesystem': + return ErasedRepr(rtyper) + elif rtyper.type_system.name == 'ootypesystem': + return OOErasedRepr(rtyper) def rtyper_makekey(self): return self.__class__, @@ -200,6 +203,13 @@ return hop.genop('cast_opaque_ptr', [v_obj], resulttype=self.lowleveltype) + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_opaque_ptr', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + return hop.gendirectcall(ll_unerase_int, v) + def rtype_erase_int(self, hop): [v_value] = hop.inputargs(lltype.Signed) c_one = hop.inputconst(lltype.Signed, 1) @@ -224,3 +234,50 @@ return lltype.nullptr(self.lowleveltype.TO) v = r_obj.convert_const(value._x) return lltype.cast_opaque_ptr(self.lowleveltype, v) + +from pypy.rpython.ootypesystem import ootype + +class OOErasedRepr(Repr): + lowleveltype = ootype.Object + def __init__(self, rtyper): + self.rtyper = rtyper + + def rtype_erase(self, hop, s_obj): + hop.exception_cannot_occur() + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return hop.inputconst(self.lowleveltype, + ootype.NULL) + [v_obj] = hop.inputargs(r_obj) + return hop.genop('cast_to_object', [v_obj], + resulttype=self.lowleveltype) + + def rtype_unerase(self, hop, s_obj): + [v] = hop.inputargs(hop.args_r[0]) + return hop.genop('cast_from_object', [v], resulttype=hop.r_result) + + def rtype_unerase_int(self, hop, v): + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('oounbox_int', [v], resulttype=hop.r_result) + return hop.genop('int_rshift', [v2, c_one], resulttype=lltype.Signed) + + def rtype_erase_int(self, hop): + hop.exception_is_here() + [v_value] = hop.inputargs(lltype.Signed) + c_one = hop.inputconst(lltype.Signed, 1) + v2 = hop.genop('int_lshift_ovf', [v_value, c_one], + resulttype = lltype.Signed) + v2p1 = hop.genop('int_add', [v2, c_one], + resulttype = lltype.Signed) + return hop.genop('oobox_int', [v2p1], resulttype=hop.r_result) + + def convert_const(self, value): + if value._identity is _identity_for_ints: + return value._x # FIXME: what should we do here? + bk = self.rtyper.annotator.bookkeeper + s_obj = value._identity.get_input_annotation(bk) + r_obj = self.rtyper.getrepr(s_obj) + if r_obj.lowleveltype is lltype.Void: + return ootype.NULL + v = r_obj.convert_const(value._x) + return ootype.cast_to_object(v) diff --git a/pypy/rlib/rstring.py b/pypy/rlib/rstring.py --- a/pypy/rlib/rstring.py +++ b/pypy/rlib/rstring.py @@ -1,8 +1,8 @@ """ String builder interface and string functions """ -from pypy.annotation.model import SomeObject, SomeString, s_None,\ - SomeChar, SomeInteger, SomeUnicodeCodePoint, SomeUnicodeString +from pypy.annotation.model import (SomeObject, SomeString, s_None, SomeChar, + SomeInteger, SomeUnicodeCodePoint, SomeUnicodeString, SomePtr) from pypy.rpython.extregistry import ExtRegistryEntry @@ -65,6 +65,12 @@ assert isinstance(c, self.tp) self.l.append(c * times) + def append_charpsize(self, s, size): + l = [] + for i in xrange(size): + l.append(s[i]) + self.l.append(self.tp("").join(l)) + def build(self): return self.tp("").join(self.l) @@ -100,6 +106,11 @@ assert isinstance(s_times, SomeInteger) return s_None + def method_append_charpsize(self, s_ptr, s_size): + assert isinstance(s_ptr, SomePtr) + assert isinstance(s_size, SomeInteger) + return s_None + def method_getlength(self): return SomeInteger(nonneg=True) @@ -127,6 +138,11 @@ assert isinstance(s_times, SomeInteger) return s_None + def method_append_charpsize(self, s_ptr, s_size): + assert isinstance(s_ptr, SomePtr) + assert isinstance(s_size, SomeInteger) + return s_None + def method_getlength(self): return SomeInteger(nonneg=True) diff --git a/pypy/rlib/rzlib.py b/pypy/rlib/rzlib.py --- a/pypy/rlib/rzlib.py +++ b/pypy/rlib/rzlib.py @@ -1,8 +1,11 @@ import sys + +from pypy.rlib.rstring import StringBuilder from pypy.rpython.lltypesystem import rffi, lltype from pypy.rpython.tool import rffi_platform +from pypy.translator.platform import platform as compiler, CompilationError from pypy.translator.tool.cbuild import ExternalCompilationInfo -from pypy.translator.platform import platform as compiler, CompilationError + if compiler.name == "msvc": libname = 'zlib' @@ -337,23 +340,18 @@ """Common code for compress() and decompress(). """ # Prepare the input buffer for the stream - inbuf = lltype.malloc(rffi.CCHARP.TO, len(data), flavor='raw') - try: + with lltype.scoped_alloc(rffi.CCHARP.TO, len(data)) as inbuf: for i in xrange(len(data)): inbuf[i] = data[i] stream.c_next_in = rffi.cast(Bytefp, inbuf) rffi.setintfield(stream, 'c_avail_in', len(data)) # Prepare the output buffer - outbuf = lltype.malloc(rffi.CCHARP.TO, OUTPUT_BUFFER_SIZE, - flavor='raw') - try: - # Strategy: we call deflate() to get as much output data as - # fits in the buffer, then accumulate all output into a list - # of characters 'result'. We don't need to gradually - # increase the output buffer size because there is no - # quadratic factor. - result = [] + with lltype.scoped_alloc(rffi.CCHARP.TO, OUTPUT_BUFFER_SIZE) as outbuf: + # Strategy: we call deflate() to get as much output data as fits in + # the buffer, then accumulate all output into a StringBuffer + # 'result'. + result = StringBuilder() while True: stream.c_next_out = rffi.cast(Bytefp, outbuf) @@ -369,8 +367,7 @@ if err == Z_OK or err == Z_STREAM_END: # accumulate data into 'result' avail_out = rffi.cast(lltype.Signed, stream.c_avail_out) - for i in xrange(bufsize - avail_out): - result.append(outbuf[i]) + result.append_charpsize(outbuf, bufsize - avail_out) # if the output buffer is full, there might be more data # so we need to try again. Otherwise, we're done. if avail_out > 0: @@ -393,14 +390,9 @@ # fallback case: report this error raise RZlibError.fromstream(stream, err, while_doing) - finally: - lltype.free(outbuf, flavor='raw') - finally: - lltype.free(inbuf, flavor='raw') - # When decompressing, if the compressed stream of data was truncated, # then the zlib simply returns Z_OK and waits for more. If it is # complete it returns Z_STREAM_END. - return (''.join(result), + return (result.build(), err, rffi.cast(lltype.Signed, stream.c_avail_in)) diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -894,13 +894,10 @@ self.buf.append(data) self.buflen += datalen elif buflen: - i = self.bufsize - buflen - assert i >= 0 - self.buf.append(data[:i]) + self.buf.append(data) self.do_write(''.join(self.buf)) self.buf = [] self.buflen = 0 - self.write(data[i:]) else: self.do_write(data) diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py --- a/pypy/rlib/test/test_rbigint.py +++ b/pypy/rlib/test/test_rbigint.py @@ -373,6 +373,13 @@ print '--->', v assert v.tolong() == pow(x, y, z) + def test_pow_lll_bug(self): + two = rbigint.fromint(2) + t = rbigint.fromlong(2655689964083835493447941032762343136647965588635159615997220691002017799304) + for n, expected in [(37, 9), (1291, 931), (67889, 39464)]: + v = two.pow(t, rbigint.fromint(n)) + assert v.toint() == expected + def test_pow_lln(self): x = 10L y = 2L diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py --- a/pypy/rlib/test/test_rerased.py +++ b/pypy/rlib/test/test_rerased.py @@ -5,8 +5,10 @@ from pypy.annotation.annrpython import RPythonAnnotator from pypy.rpython.test.test_llinterp import interpret from pypy.rpython.lltypesystem.rclass import OBJECTPTR +from pypy.rpython.ootypesystem.rclass import OBJECT from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin class X(object): pass @@ -79,136 +81,6 @@ s = a.build_types(f, []) assert isinstance(s, annmodel.SomeInteger) -def test_rtype_1(): - def f(): - return eraseX(X()) - x = interpret(f, []) - assert lltype.typeOf(x) == llmemory.GCREF - -def test_rtype_2(): - def f(): - x1 = X() - e = eraseX(x1) - #assert not is_integer(e) - x2 = uneraseX(e) - return x2 - x = interpret(f, []) - assert lltype.castable(OBJECTPTR, lltype.typeOf(x)) > 0 - -def test_rtype_3(): - def f(): - e = erase_int(16) - #assert is_integer(e) - x2 = unerase_int(e) - return x2 - x = interpret(f, []) - assert x == 16 - - -def test_prebuilt_erased(): - e1 = erase_int(16) - x1 = X() - x1.foobar = 42 - e2 = eraseX(x1) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = unerase_int(e1) + uneraseX(e2).foobar - return x2 - x = interpret(f, []) - assert x == 16 + 42 + 1 - -def test_prebuilt_erased_in_instance(): - erase_empty, unerase_empty = new_erasing_pair("empty") - class FakeList(object): - pass - - x1 = X() - x1.foobar = 42 - l1 = FakeList() - l1.storage = eraseX(x1) - l2 = FakeList() - l2.storage = erase_empty(None) - - def f(): - #assert is_integer(e1) - #assert not is_integer(e2) - x1.foobar += 1 - x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) - return x2 - x = interpret(f, []) - assert x == 43 + True - - -def test_overflow(): - def f(i): - try: - e = erase_int(i) - except OverflowError: - return -1 - #assert is_integer(e) - return unerase_int(e) - x = interpret(f, [16]) - assert x == 16 - x = interpret(f, [sys.maxint]) - assert x == -1 - -def test_none(): - def foo(): - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - # - def foo(): - eraseX(X()) - return uneraseX(eraseX(None)) - assert foo() is None - res = interpret(foo, []) - assert not res - -def test_union(): - s_e1 = SomeErased() - s_e1.const = 1 - s_e2 = SomeErased() - s_e2.const = 3 - assert not annmodel.pair(s_e1, s_e2).union().is_constant() - - -def test_rtype_list(): - prebuilt_l = [X()] - prebuilt_e = erase_list_X(prebuilt_l) - def l(flag): - if flag == 1: - l = [X()] - e = erase_list_X(l) - elif flag == 2: - l = prebuilt_l - e = erase_list_X(l) - else: - l = prebuilt_l - e = prebuilt_e - #assert is_integer(e) is False - assert unerase_list_X(e) is l - interpret(l, [0]) - interpret(l, [1]) - interpret(l, [2]) - -# ____________________________________________________________ - -def test_erasing_pair(): - erase, unerase = new_erasing_pair("test1") - class X: - pass - x = X() - erased = erase(x) - assert unerase(erased) is x - # - erase2, unerase2 = new_erasing_pair("test2") - py.test.raises(AssertionError, unerase2, erased) - def test_annotate_erasing_pair(): erase, unerase = new_erasing_pair("test1") erase2, unerase2 = new_erasing_pair("test2") @@ -296,3 +168,148 @@ a = RPythonAnnotator() s = a.build_types(f, [int]) assert isinstance(s, annmodel.SomeInteger) + +class BaseTestRErased(BaseRtypingTest): + def test_rtype_1(self): + def f(): + return eraseX(X()) + x = self.interpret(f, []) + assert lltype.typeOf(x) == self.ERASED_TYPE + + def test_rtype_2(self): + def f(): + x1 = X() + e = eraseX(x1) + #assert not is_integer(e) + x2 = uneraseX(e) + return x2 + x = self.interpret(f, []) + assert self.castable(self.UNERASED_TYPE, x) + + def test_rtype_3(self): + def f(): + e = erase_int(16) + #assert is_integer(e) + x2 = unerase_int(e) + return x2 + x = self.interpret(f, []) + assert x == 16 + + def test_prebuilt_erased(self): + e1 = erase_int(16) + x1 = X() + x1.foobar = 42 + e2 = eraseX(x1) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = unerase_int(e1) + uneraseX(e2).foobar + return x2 + x = self.interpret(f, []) + assert x == 16 + 42 + 1 + + def test_prebuilt_erased_in_instance(self): + erase_empty, unerase_empty = new_erasing_pair("empty") + class FakeList(object): + pass + + x1 = X() + x1.foobar = 42 + l1 = FakeList() + l1.storage = eraseX(x1) + l2 = FakeList() + l2.storage = erase_empty(None) + + def f(): + #assert is_integer(e1) + #assert not is_integer(e2) + x1.foobar += 1 + x2 = uneraseX(l1.storage).foobar + (unerase_empty(l2.storage) is None) + return x2 + x = self.interpret(f, []) + assert x == 43 + True + + def test_overflow(self): + def f(i): + try: + e = erase_int(i) + except OverflowError: + return -1 + #assert is_integer(e) + return unerase_int(e) + x = self.interpret(f, [16]) + assert x == 16 + x = self.interpret(f, [sys.maxint]) + assert x == -1 + + def test_none(self): + def foo(): + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + # + def foo(): + eraseX(X()) + return uneraseX(eraseX(None)) + assert foo() is None + res = self.interpret(foo, []) + assert not res + + def test_rtype_list(self): + prebuilt_l = [X()] + prebuilt_e = erase_list_X(prebuilt_l) + def l(flag): + if flag == 1: + l = [X()] + e = erase_list_X(l) + elif flag == 2: + l = prebuilt_l + e = erase_list_X(l) + else: + l = prebuilt_l + e = prebuilt_e + #assert is_integer(e) is False + assert unerase_list_X(e) is l + self.interpret(l, [0]) + self.interpret(l, [1]) + self.interpret(l, [2]) + +class TestLLtype(BaseTestRErased, LLRtypeMixin): + ERASED_TYPE = llmemory.GCREF + UNERASED_TYPE = OBJECTPTR + def castable(self, TO, var): + return lltype.castable(TO, lltype.typeOf(var)) > 0 + +from pypy.rpython.ootypesystem.ootype import Object + +class TestOOtype(BaseTestRErased, OORtypeMixin): + ERASED_TYPE = Object + UNERASED_TYPE = OBJECT + def castable(self, TO, var): + return ootype.isSubclass(lltype.typeOf(var), TO) + @py.test.mark.xfail + def test_prebuilt_erased(self): + super(TestOOtype, self).test_prebuilt_erased() + +def test_union(): + s_e1 = SomeErased() + s_e1.const = 1 + s_e2 = SomeErased() + s_e2.const = 3 + assert not annmodel.pair(s_e1, s_e2).union().is_constant() + +# ____________________________________________________________ + +def test_erasing_pair(): + erase, unerase = new_erasing_pair("test1") + class X: + pass + x = X() + erased = erase(x) + assert unerase(erased) is x + # + erase2, unerase2 = new_erasing_pair("test2") + py.test.raises(AssertionError, unerase2, erased) diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py --- a/pypy/rpython/extfuncregistry.py +++ b/pypy/rpython/extfuncregistry.py @@ -42,6 +42,8 @@ ('sqrt', [float], float), ('log', [float], float), ('log10', [float], float), + ('sin', [float], float), + ('cos', [float], float), ]), ] for module, methods in _register: diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py --- a/pypy/rpython/llinterp.py +++ b/pypy/rpython/llinterp.py @@ -1225,6 +1225,12 @@ except ValueError: self.make_llexception() + def op_oobox_int(self, i): + return ootype.oobox_int(i) + + def op_oounbox_int(self, x): + return ootype.oounbox_int(x) + class Tracer(object): Counter = 0 file = None diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -585,6 +585,8 @@ 'classof': LLOp(oo=True, canfold=True), 'subclassof': LLOp(oo=True, canfold=True), 'oostring': LLOp(oo=True, sideeffects=False), + 'oobox_int': LLOp(oo=True, sideeffects=False), + 'oounbox_int': LLOp(oo=True, sideeffects=False), 'ooparse_int': LLOp(oo=True, canraise=(ValueError,)), 'ooparse_float': LLOp(oo=True, canraise=(ValueError,)), 'oounicode': LLOp(oo=True, canraise=(UnicodeDecodeError,)), diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py --- a/pypy/rpython/lltypesystem/module/ll_math.py +++ b/pypy/rpython/lltypesystem/module/ll_math.py @@ -69,6 +69,8 @@ [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE) math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True) math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE) +math_sin = llexternal('sin', [rffi.DOUBLE], rffi.DOUBLE) +math_cos = llexternal('cos', [rffi.DOUBLE], rffi.DOUBLE) @jit.elidable def sqrt_nonneg(x): @@ -340,6 +342,16 @@ raise ValueError("math domain error") return math_log10(x) +def ll_math_sin(x): + if isinf(x): + raise ValueError("math domain error") + return math_sin(x) + +def ll_math_cos(x): + if isinf(x): + raise ValueError("math domain error") + return math_cos(x) + # ____________________________________________________________ # # Default implementations @@ -377,8 +389,8 @@ unary_math_functions = [ 'acos', 'asin', 'atan', - 'ceil', 'cos', 'cosh', 'exp', 'fabs', - 'sin', 'sinh', 'tan', 'tanh', + 'ceil', 'cosh', 'exp', 'fabs', + 'sinh', 'tan', 'tanh', 'acosh', 'asinh', 'atanh', 'log1p', 'expm1', ] unary_math_functions_can_overflow = [ diff --git a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py --- a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py +++ b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py @@ -37,7 +37,7 @@ assert self.interpret(f, [0.3, 0.4]) == f(0.3, 0.4) return next_test - for name in ll_math.unary_math_functions + ['log', 'log10', 'sqrt']: + for name in ll_math.unary_math_functions + ['log', 'log10', 'sin', 'cos', 'sqrt']: func_name = 'test_%s' % (name,) next_test = new_unary_test(name) next_test.func_name = func_name diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py --- a/pypy/rpython/lltypesystem/rbuilder.py +++ b/pypy/rpython/lltypesystem/rbuilder.py @@ -1,13 +1,13 @@ - +from pypy.rlib import rgc +from pypy.rlib.objectmodel import enforceargs +from pypy.rlib.rarithmetic import ovfcheck +from pypy.rpython.annlowlevel import llstr +from pypy.rpython.rptr import PtrRepr +from pypy.rpython.lltypesystem import lltype, rstr +from pypy.rpython.lltypesystem.lltype import staticAdtMethod +from pypy.rpython.lltypesystem.rstr import (STR, UNICODE, char_repr, + string_repr, unichar_repr, unicode_repr) from pypy.rpython.rbuilder import AbstractStringBuilderRepr -from pypy.rpython.lltypesystem import lltype, rstr -from pypy.rpython.lltypesystem.rstr import STR, UNICODE, char_repr,\ - string_repr, unichar_repr, unicode_repr -from pypy.rpython.annlowlevel import llstr -from pypy.rlib import rgc -from pypy.rlib.rarithmetic import ovfcheck -from pypy.rlib.objectmodel import enforceargs -from pypy.rpython.lltypesystem.lltype import staticAdtMethod from pypy.tool.sourcetools import func_with_new_name # Think about heuristics below, maybe we can come up with something @@ -73,7 +73,7 @@ ll_builder.grow(ll_builder, lgt) ll_str.copy_contents(ll_str, ll_builder.buf, 0, used, lgt) ll_builder.used = needed - + @staticmethod def ll_append_char(ll_builder, char): if ll_builder.used == ll_builder.allocated: @@ -102,6 +102,16 @@ ll_builder.used = used @staticmethod + def ll_append_charpsize(ll_builder, charp, size): + used = ll_builder.used + if used + size > ll_builder.allocated: + ll_builder.grow(ll_builder, size) + for i in xrange(size): + ll_builder.buf.chars[used] = charp[i] + used += 1 + ll_builder.used = used + + @staticmethod def ll_getlength(ll_builder): return ll_builder.used @@ -119,6 +129,9 @@ mallocfn = staticmethod(rstr.mallocstr) string_repr = string_repr char_repr = char_repr + raw_ptr_repr = PtrRepr( + lltype.Ptr(lltype.Array(lltype.Char, hints={'nolength': True})) + ) class UnicodeBuilderRepr(BaseStringBuilderRepr): lowleveltype = lltype.Ptr(UNICODEBUILDER) @@ -126,6 +139,9 @@ mallocfn = staticmethod(rstr.mallocunicode) string_repr = unicode_repr char_repr = unichar_repr + raw_ptr_repr = PtrRepr( + lltype.Ptr(lltype.Array(lltype.UniChar, hints={'nolength': True})) + ) unicodebuilder_repr = UnicodeBuilderRepr() stringbuilder_repr = StringBuilderRepr() diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -29,7 +29,7 @@ # DICTVALUE value; # int f_hash; # (optional) key hash, if hard to recompute # } -# +# # struct dicttable { # int num_items; # int num_pristine_entries; # never used entries @@ -50,12 +50,12 @@ self.custom_eq_hash = custom_eq_hash is not None if not isinstance(key_repr, rmodel.Repr): # not computed yet, done by setup() assert callable(key_repr) - self._key_repr_computer = key_repr + self._key_repr_computer = key_repr else: self.external_key_repr, self.key_repr = self.pickkeyrepr(key_repr) if not isinstance(value_repr, rmodel.Repr): # not computed yet, done by setup() assert callable(value_repr) - self._value_repr_computer = value_repr + self._value_repr_computer = value_repr else: self.external_value_repr, self.value_repr = self.pickrepr(value_repr) self.dictkey = dictkey @@ -176,7 +176,7 @@ self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY, adtmeths=entrymeths) fields = [ ("num_items", lltype.Signed), - ("num_pristine_entries", lltype.Signed), + ("num_pristine_entries", lltype.Signed), ("entries", lltype.Ptr(self.DICTENTRYARRAY)) ] if self.custom_eq_hash: self.r_rdict_eqfn, self.r_rdict_hashfn = self._custom_eq_hash_repr() @@ -211,7 +211,7 @@ def convert_const(self, dictobj): from pypy.rpython.lltypesystem import llmemory # get object from bound dict methods - #dictobj = getattr(dictobj, '__self__', dictobj) + #dictobj = getattr(dictobj, '__self__', dictobj) if dictobj is None: return lltype.nullptr(self.DICT) if not isinstance(dictobj, (dict, objectmodel.r_dict)): @@ -222,7 +222,7 @@ except KeyError: self.setup() l_dict = ll_newdict_size(self.DICT, len(dictobj)) - self.dict_cache[key] = l_dict + self.dict_cache[key] = l_dict r_key = self.key_repr if r_key.lowleveltype == llmemory.Address: raise TypeError("No prebuilt dicts of address keys") @@ -274,7 +274,7 @@ hop.exception_cannot_occur() v_res = hop.gendirectcall(ll_setdefault, v_dict, v_key, v_default) return self.recast_value(hop.llops, v_res) - + def rtype_method_copy(self, hop): v_dict, = hop.inputargs(self) hop.exception_cannot_occur() @@ -325,7 +325,7 @@ hop.exception_is_here() return hop.gendirectcall(ll_popitem, cTUPLE, v_dict) -class __extend__(pairtype(DictRepr, rmodel.Repr)): +class __extend__(pairtype(DictRepr, rmodel.Repr)): def rtype_getitem((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) @@ -338,7 +338,7 @@ def rtype_delitem((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) if not r_dict.custom_eq_hash: - hop.has_implicit_exception(KeyError) # record that we know about it + hop.has_implicit_exception(KeyError) # record that we know about it hop.exception_is_here() return hop.gendirectcall(ll_dict_delitem, v_dict, v_key) @@ -354,11 +354,11 @@ v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) hop.exception_is_here() return hop.gendirectcall(ll_contains, v_dict, v_key) - + class __extend__(pairtype(DictRepr, DictRepr)): def convert_from_to((r_dict1, r_dict2), v, llops): # check that we don't convert from Dicts with - # different key/value types + # different key/value types if r_dict1.dictkey is None or r_dict2.dictkey is None: return NotImplemented if r_dict1.dictkey is not r_dict2.dictkey: @@ -430,7 +430,7 @@ return hlinvoke(DICT.r_rdict_eqfn, d.fnkeyeq, key1, key2) def ll_dict_len(d): - return d.num_items + return d.num_items def ll_dict_is_true(d): # check if a dict is True, allowing for None @@ -491,8 +491,8 @@ if i & HIGHEST_BIT: raise KeyError _ll_dict_del(d, i) -ll_dict_delitem.oopspec = 'dict.delitem(d, key)' + at jit.dont_look_inside def _ll_dict_del(d, i): d.entries.mark_deleted(i) d.num_items -= 1 @@ -501,9 +501,6 @@ ENTRY = ENTRIES.OF entry = d.entries[i] if ENTRIES.must_clear_key: - key = entry.key # careful about destructor side effects: - # keep key alive until entry.value has also - # been zeroed (if it must be) entry.key = lltype.nullptr(ENTRY.key.TO) if ENTRIES.must_clear_value: entry.value = lltype.nullptr(ENTRY.value.TO) @@ -513,7 +510,7 @@ def ll_dict_resize(d): old_entries = d.entries - old_size = len(old_entries) + old_size = len(old_entries) # make a 'new_size' estimate and shrink it if there are many # deleted entry markers new_size = old_size * 2 @@ -541,7 +538,7 @@ direct_compare = not hasattr(ENTRIES, 'no_direct_compare') mask = len(entries) - 1 i = hash & mask - # do the first try before any looping + # do the first try before any looping if entries.valid(i): checkingkey = entries[i].key if direct_compare and checkingkey == key: @@ -565,8 +562,8 @@ # In the loop, a deleted entry (everused and not valid) is by far # (factor of 100s) the least likely outcome, so test for that last. - perturb = r_uint(hash) - while 1: + perturb = r_uint(hash) + while 1: # compute the next index using unsigned arithmetic i = r_uint(i) i = (i << 2) + i + perturb + 1 @@ -594,7 +591,7 @@ if found: return i # found the entry elif freeslot == -1: - freeslot = i + freeslot = i perturb >>= PERTURB_SHIFT def ll_dict_lookup_clean(d, hash): @@ -604,7 +601,7 @@ entries = d.entries mask = len(entries) - 1 i = hash & mask - perturb = r_uint(hash) + perturb = r_uint(hash) while entries.everused(i): i = r_uint(i) i = (i << 2) + i + perturb + 1 @@ -690,7 +687,6 @@ iter.dict = d iter.index = 0 return iter -ll_dictiter.oopspec = 'newdictiter(d)' def _make_ll_dictnext(kind): # make three versions of the following function: keys, values, items diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -789,8 +789,7 @@ # char* and size -> str (which can contain null bytes) def charpsize2str(cp, size): b = builder_class(size) - for i in xrange(size): - b.append(cp[i]) + b.append_charpsize(cp, size) return b.build() charpsize2str._annenforceargs_ = [None, int] @@ -1062,3 +1061,11 @@ keep_unicodebuffer_alive_until_here(self.raw, self.gc_buf) def str(self, length): return unicode_from_buffer(self.raw, self.gc_buf, self.size, length) + +# You would have to have a *huge* amount of data for this to block long enough +# to be worth it to release the GIL. +c_memcpy = llexternal("memcpy", + [VOIDP, VOIDP, SIZE_T], + lltype.Void, + threadsafe=False +) \ No newline at end of file diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -49,6 +49,7 @@ from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage from pypy.rpython.memory.gc.base import GCBase, MovingGCBase from pypy.rpython.memory.gc import minimarkpage, env +from pypy.rpython.memory.support import mangle_hash from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask, r_uint from pypy.rlib.rarithmetic import LONG_BIT_SHIFT from pypy.rlib.debug import ll_assert, debug_print, debug_start, debug_stop @@ -1732,7 +1733,7 @@ # ---------- # id() and identityhash() support - def id_or_identityhash(self, gcobj, special_case_prebuilt): + def id_or_identityhash(self, gcobj, is_hash): """Implement the common logic of id() and identityhash() of an object, given as a GCREF. """ @@ -1775,7 +1776,7 @@ # The answer is the address of the shadow. obj = shadow # - elif special_case_prebuilt: + elif is_hash: if self.header(obj).tid & GCFLAG_HAS_SHADOW: # # For identityhash(), we need a special case for some @@ -1784,10 +1785,14 @@ # after the object. But we cannot use it for id() # because the stored value might clash with a real one. size = self.get_size(obj) - return (obj + size).signed[0] + i = (obj + size).signed[0] + # Important: the returned value is not mangle_hash()ed! + return i # - return llmemory.cast_adr_to_int(obj) - + i = llmemory.cast_adr_to_int(obj) + if is_hash: + i = mangle_hash(i) + return i def id(self, gcobj): return self.id_or_identityhash(gcobj, False) diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -525,7 +525,8 @@ self.c_vtinfo_skip_offset = rmodel.inputconst(lltype.typeOf(sko), sko) def build_root_walker(self): - return ShadowStackRootWalker(self) + from pypy.rpython.memory.gctransform import shadowstack + return shadowstack.ShadowStackRootWalker(self) def consider_constant(self, TYPE, value): self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc) @@ -932,10 +933,10 @@ def gct_gc_identityhash(self, hop): livevars = self.push_roots(hop) [v_ptr] = hop.spaceop.args - v_adr = hop.genop("cast_ptr_to_adr", [v_ptr], - resulttype=llmemory.Address) + v_ptr = hop.genop("cast_opaque_ptr", [v_ptr], + resulttype=llmemory.GCREF) hop.genop("direct_call", - [self.identityhash_ptr, self.c_const_gc, v_adr], + [self.identityhash_ptr, self.c_const_gc, v_ptr], resultvar=hop.spaceop.result) self.pop_roots(hop, livevars) @@ -1323,217 +1324,3 @@ def need_thread_support(self, gctransformer, getfn): raise Exception("%s does not support threads" % ( self.__class__.__name__,)) - - -class ShadowStackRootWalker(BaseRootWalker): - need_root_stack = True - collect_stacks_from_other_threads = None - - def __init__(self, gctransformer): - BaseRootWalker.__init__(self, gctransformer) - self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth - # NB. 'self' is frozen, but we can use self.gcdata to store state - gcdata = self.gcdata - - def incr_stack(n): - top = gcdata.root_stack_top - gcdata.root_stack_top = top + n*sizeofaddr - return top - self.incr_stack = incr_stack - - def decr_stack(n): - top = gcdata.root_stack_top - n*sizeofaddr - gcdata.root_stack_top = top - return top - self.decr_stack = decr_stack - - self.rootstackhook = gctransformer.root_stack_jit_hook - if self.rootstackhook is None: - def collect_stack_root(callback, gc, addr): - if gc.points_to_valid_gc_object(addr): - callback(gc, addr) - return sizeofaddr - self.rootstackhook = collect_stack_root - - def push_stack(self, addr): - top = self.incr_stack(1) - top.address[0] = addr - - def pop_stack(self): - top = self.decr_stack(1) - return top.address[0] - - def allocate_stack(self): - return llmemory.raw_malloc(self.rootstacksize) - - def setup_root_walker(self): - stackbase = self.allocate_stack() - ll_assert(bool(stackbase), "could not allocate root stack") - self.gcdata.root_stack_top = stackbase - self.gcdata.root_stack_base = stackbase - BaseRootWalker.setup_root_walker(self) - - def walk_stack_roots(self, collect_stack_root): - gcdata = self.gcdata - gc = self.gc - rootstackhook = self.rootstackhook - addr = gcdata.root_stack_base - end = gcdata.root_stack_top - while addr != end: - addr += rootstackhook(collect_stack_root, gc, addr) - if self.collect_stacks_from_other_threads is not None: - self.collect_stacks_from_other_threads(collect_stack_root) - - def need_thread_support(self, gctransformer, getfn): - from pypy.module.thread import ll_thread # xxx fish - from pypy.rpython.memory.support import AddressDict - from pypy.rpython.memory.support import copy_without_null_values - gcdata = self.gcdata - # the interfacing between the threads and the GC is done via - # three completely ad-hoc operations at the moment: - # gc_thread_prepare, gc_thread_run, gc_thread_die. - # See docstrings below. - - def get_aid(): - """Return the thread identifier, cast to an (opaque) address.""" - return llmemory.cast_int_to_adr(ll_thread.get_ident()) - - def thread_setup(): - """Called once when the program starts.""" - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} - gcdata._fresh_rootstack = llmemory.NULL - gcdata.dead_threads_count = 0 - - def thread_prepare(): - """Called just before thread.start_new_thread(). This - allocates a new shadow stack to be used by the future - thread. If memory runs out, this raises a MemoryError - (which can be handled by the caller instead of just getting - ignored if it was raised in the newly starting thread). - """ - if not gcdata._fresh_rootstack: - gcdata._fresh_rootstack = self.allocate_stack() - if not gcdata._fresh_rootstack: - raise MemoryError - - def thread_run(): - """Called whenever the current thread (re-)acquired the GIL. - This should ensure that the shadow stack installed in - gcdata.root_stack_top/root_stack_base is the one corresponding - to the current thread. - """ - aid = get_aid() - if gcdata.active_thread != aid: - switch_shadow_stacks(aid) - - def thread_die(): - """Called just before the final GIL release done by a dying - thread. After a thread_die(), no more gc operation should - occur in this thread. - """ - aid = get_aid() - if aid == gcdata.main_thread: - return # ignore calls to thread_die() in the main thread - # (which can occur after a fork()). - gcdata.thread_stacks.setitem(aid, llmemory.NULL) - old = gcdata.root_stack_base - if gcdata._fresh_rootstack == llmemory.NULL: - gcdata._fresh_rootstack = old - else: - llmemory.raw_free(old) - install_new_stack(gcdata.main_thread) - # from time to time, rehash the dictionary to remove - # old NULL entries - gcdata.dead_threads_count += 1 - if (gcdata.dead_threads_count & 511) == 0: - copy = copy_without_null_values(gcdata.thread_stacks) - gcdata.thread_stacks.delete() - gcdata.thread_stacks = copy - - def switch_shadow_stacks(new_aid): - save_away_current_stack() - install_new_stack(new_aid) - switch_shadow_stacks._dont_inline_ = True - - def save_away_current_stack(): - old_aid = gcdata.active_thread - # save root_stack_base on the top of the stack - self.push_stack(gcdata.root_stack_base) - # store root_stack_top into the dictionary - gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) - - def install_new_stack(new_aid): - # look for the new stack top - top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) - if top == llmemory.NULL: - # first time we see this thread. It is an error if no - # fresh new stack is waiting. - base = gcdata._fresh_rootstack - gcdata._fresh_rootstack = llmemory.NULL - ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") - gcdata.root_stack_top = base - gcdata.root_stack_base = base - else: - # restore the root_stack_base from the top of the stack - gcdata.root_stack_top = top - gcdata.root_stack_base = self.pop_stack() - # done - gcdata.active_thread = new_aid - - def collect_stack(aid, stacktop, callback): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - # collect all valid stacks from the dict (the entry - # corresponding to the current thread is not valid) - gc = self.gc - rootstackhook = self.rootstackhook - end = stacktop - sizeofaddr - addr = end.address[0] - while addr != end: - addr += rootstackhook(callback, gc, addr) - - def collect_more_stacks(callback): - ll_assert(get_aid() == gcdata.active_thread, - "collect_more_stacks(): invalid active_thread") - gcdata.thread_stacks.foreach(collect_stack, callback) - - def _free_if_not_current(aid, stacktop, _): - if stacktop != llmemory.NULL and aid != gcdata.active_thread: - end = stacktop - sizeofaddr - base = end.address[0] - llmemory.raw_free(base) - - def thread_after_fork(result_of_fork, opaqueaddr): - # we don't need a thread_before_fork in this case, so - # opaqueaddr == NULL. This is called after fork(). - if result_of_fork == 0: - # We are in the child process. Assumes that only the - # current thread survived, so frees the shadow stacks - # of all the other ones. - gcdata.thread_stacks.foreach(_free_if_not_current, None) - # Clears the dict (including the current thread, which - # was an invalid entry anyway and will be recreated by - # the next call to save_away_current_stack()). - gcdata.thread_stacks.clear() - # Finally, reset the stored thread IDs, in case it - # changed because of fork(). Also change the main - # thread to the current one (because there is not any - # other left). - aid = get_aid() - gcdata.main_thread = aid - gcdata.active_thread = aid - - self.thread_setup = thread_setup - self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) - self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, - inline=True) - # no thread_start_ptr here - self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) - # no thread_before_fork_ptr here - self.thread_after_fork_ptr = getfn(thread_after_fork, - [annmodel.SomeInteger(), - annmodel.SomeAddress()], - annmodel.s_None) - self.collect_stacks_from_other_threads = collect_more_stacks diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py new file mode 100644 --- /dev/null +++ b/pypy/rpython/memory/gctransform/shadowstack.py @@ -0,0 +1,219 @@ +from pypy.rpython.memory.gctransform.framework import BaseRootWalker +from pypy.rpython.memory.gctransform.framework import sizeofaddr +from pypy.rlib.debug import ll_assert +from pypy.rpython.lltypesystem import llmemory +from pypy.annotation import model as annmodel + + +class ShadowStackRootWalker(BaseRootWalker): + need_root_stack = True + collect_stacks_from_other_threads = None + + def __init__(self, gctransformer): + BaseRootWalker.__init__(self, gctransformer) + self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth + # NB. 'self' is frozen, but we can use self.gcdata to store state + gcdata = self.gcdata + + def incr_stack(n): + top = gcdata.root_stack_top + gcdata.root_stack_top = top + n*sizeofaddr + return top + self.incr_stack = incr_stack + + def decr_stack(n): + top = gcdata.root_stack_top - n*sizeofaddr + gcdata.root_stack_top = top + return top + self.decr_stack = decr_stack + + self.rootstackhook = gctransformer.root_stack_jit_hook + if self.rootstackhook is None: + def collect_stack_root(callback, gc, addr): + if gc.points_to_valid_gc_object(addr): + callback(gc, addr) + return sizeofaddr + self.rootstackhook = collect_stack_root + + def push_stack(self, addr): + top = self.incr_stack(1) + top.address[0] = addr + + def pop_stack(self): + top = self.decr_stack(1) + return top.address[0] + + def allocate_stack(self): + return llmemory.raw_malloc(self.rootstacksize) + + def setup_root_walker(self): + stackbase = self.allocate_stack() + ll_assert(bool(stackbase), "could not allocate root stack") + self.gcdata.root_stack_top = stackbase + self.gcdata.root_stack_base = stackbase + BaseRootWalker.setup_root_walker(self) + + def walk_stack_roots(self, collect_stack_root): + gcdata = self.gcdata + gc = self.gc + rootstackhook = self.rootstackhook + addr = gcdata.root_stack_base + end = gcdata.root_stack_top + while addr != end: + addr += rootstackhook(collect_stack_root, gc, addr) + if self.collect_stacks_from_other_threads is not None: + self.collect_stacks_from_other_threads(collect_stack_root) + + def need_thread_support(self, gctransformer, getfn): + from pypy.module.thread import ll_thread # xxx fish + from pypy.rpython.memory.support import AddressDict + from pypy.rpython.memory.support import copy_without_null_values + gcdata = self.gcdata + # the interfacing between the threads and the GC is done via + # three completely ad-hoc operations at the moment: + # gc_thread_prepare, gc_thread_run, gc_thread_die. + # See docstrings below. + + def get_aid(): + """Return the thread identifier, cast to an (opaque) address.""" + return llmemory.cast_int_to_adr(ll_thread.get_ident()) + + def thread_setup(): + """Called once when the program starts.""" + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} + gcdata._fresh_rootstack = llmemory.NULL + gcdata.dead_threads_count = 0 + + def thread_prepare(): + """Called just before thread.start_new_thread(). This + allocates a new shadow stack to be used by the future + thread. If memory runs out, this raises a MemoryError + (which can be handled by the caller instead of just getting + ignored if it was raised in the newly starting thread). + """ + if not gcdata._fresh_rootstack: + gcdata._fresh_rootstack = self.allocate_stack() + if not gcdata._fresh_rootstack: + raise MemoryError + + def thread_run(): + """Called whenever the current thread (re-)acquired the GIL. + This should ensure that the shadow stack installed in + gcdata.root_stack_top/root_stack_base is the one corresponding + to the current thread. + """ + aid = get_aid() + if gcdata.active_thread != aid: + switch_shadow_stacks(aid) + + def thread_die(): + """Called just before the final GIL release done by a dying + thread. After a thread_die(), no more gc operation should + occur in this thread. + """ + aid = get_aid() + if aid == gcdata.main_thread: + return # ignore calls to thread_die() in the main thread + # (which can occur after a fork()). + gcdata.thread_stacks.setitem(aid, llmemory.NULL) + old = gcdata.root_stack_base + if gcdata._fresh_rootstack == llmemory.NULL: + gcdata._fresh_rootstack = old + else: + llmemory.raw_free(old) + install_new_stack(gcdata.main_thread) + # from time to time, rehash the dictionary to remove + # old NULL entries + gcdata.dead_threads_count += 1 + if (gcdata.dead_threads_count & 511) == 0: + copy = copy_without_null_values(gcdata.thread_stacks) + gcdata.thread_stacks.delete() + gcdata.thread_stacks = copy + + def switch_shadow_stacks(new_aid): + save_away_current_stack() + install_new_stack(new_aid) + switch_shadow_stacks._dont_inline_ = True + + def save_away_current_stack(): + old_aid = gcdata.active_thread + # save root_stack_base on the top of the stack + self.push_stack(gcdata.root_stack_base) + # store root_stack_top into the dictionary + gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) + + def install_new_stack(new_aid): + # look for the new stack top + top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) + if top == llmemory.NULL: + # first time we see this thread. It is an error if no + # fresh new stack is waiting. + base = gcdata._fresh_rootstack + gcdata._fresh_rootstack = llmemory.NULL + ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") + gcdata.root_stack_top = base + gcdata.root_stack_base = base + else: + # restore the root_stack_base from the top of the stack + gcdata.root_stack_top = top + gcdata.root_stack_base = self.pop_stack() + # done + gcdata.active_thread = new_aid + + def collect_stack(aid, stacktop, callback): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + # collect all valid stacks from the dict (the entry + # corresponding to the current thread is not valid) + gc = self.gc + rootstackhook = self.rootstackhook + end = stacktop - sizeofaddr + addr = end.address[0] + while addr != end: + addr += rootstackhook(callback, gc, addr) + + def collect_more_stacks(callback): + ll_assert(get_aid() == gcdata.active_thread, + "collect_more_stacks(): invalid active_thread") + gcdata.thread_stacks.foreach(collect_stack, callback) + + def _free_if_not_current(aid, stacktop, _): + if stacktop != llmemory.NULL and aid != gcdata.active_thread: + end = stacktop - sizeofaddr + base = end.address[0] + llmemory.raw_free(base) + + def thread_after_fork(result_of_fork, opaqueaddr): + # we don't need a thread_before_fork in this case, so + # opaqueaddr == NULL. This is called after fork(). + if result_of_fork == 0: + # We are in the child process. Assumes that only the + # current thread survived, so frees the shadow stacks + # of all the other ones. + gcdata.thread_stacks.foreach(_free_if_not_current, None) + # Clears the dict (including the current thread, which + # was an invalid entry anyway and will be recreated by + # the next call to save_away_current_stack()). + gcdata.thread_stacks.clear() + # Finally, reset the stored thread IDs, in case it + # changed because of fork(). Also change the main + # thread to the current one (because there is not any + # other left). + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + + self.thread_setup = thread_setup + self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) + self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, + inline=True) + # no thread_start_ptr here + self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) + # no thread_before_fork_ptr here + self.thread_after_fork_ptr = getfn(thread_after_fork, + [annmodel.SomeInteger(), + annmodel.SomeAddress()], + annmodel.s_None) + self.collect_stacks_from_other_threads = collect_more_stacks diff --git a/pypy/rpython/memory/lldict.py b/pypy/rpython/memory/lldict.py --- a/pypy/rpython/memory/lldict.py +++ b/pypy/rpython/memory/lldict.py @@ -1,6 +1,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem import rdict from pypy.rlib.objectmodel import we_are_translated +from pypy.rpython.memory.support import mangle_hash # This is a low-level AddressDict, reusing a lot of the logic from rdict.py. # xxx this is very dependent on the details of rdict.py @@ -40,7 +41,8 @@ lltype.free(entries, flavor="raw") if not we_are_translated(): count_alloc(-1) -_hash = llmemory.cast_adr_to_int +def _hash(adr): + return mangle_hash(llmemory.cast_adr_to_int(adr)) def dict_keyhash(d, key): return _hash(key) diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py --- a/pypy/rpython/memory/support.py +++ b/pypy/rpython/memory/support.py @@ -4,6 +4,15 @@ from pypy.rlib.debug import ll_assert from pypy.tool.identity_dict import identity_dict + +def mangle_hash(i): + # To hash pointers in dictionaries. Assumes that i shows some + # alignment (to 4, 8, maybe 16 bytes), so we use the following + # formula to avoid the trailing bits being always 0. + return i ^ (i >> 4) + +# ____________________________________________________________ + DEFAULT_CHUNK_SIZE = 1019 diff --git a/pypy/rpython/ootypesystem/ooopimpl.py b/pypy/rpython/ootypesystem/ooopimpl.py --- a/pypy/rpython/ootypesystem/ooopimpl.py +++ b/pypy/rpython/ootypesystem/ooopimpl.py @@ -3,7 +3,6 @@ # ____________________________________________________________ # Implementation of the 'canfold' oo operations - def op_ooupcast(INST, inst): return ootype.ooupcast(INST, inst) op_ooupcast.need_result_type = True diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py --- a/pypy/rpython/ootypesystem/ootype.py +++ b/pypy/rpython/ootypesystem/ootype.py @@ -1938,6 +1938,17 @@ assert typeOf(obj) is Object return obj._cast_to(EXPECTED_TYPE) +class Box(_object): + def __init__(self, i): + self._TYPE = Object + self.i = i + +def oobox_int(i): + return Box(i) + +def oounbox_int(x): + return x.i + def oostring(obj, base): """ Convert char, int, float, instances and str to str. diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -255,7 +255,7 @@ methodname = None return fn, v_obj, methodname -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): from pypy.rlib import jit r_dict = hop.r_result diff --git a/pypy/rpython/rbuilder.py b/pypy/rpython/rbuilder.py --- a/pypy/rpython/rbuilder.py +++ b/pypy/rpython/rbuilder.py @@ -36,6 +36,11 @@ hop.exception_cannot_occur() return hop.gendirectcall(self.ll_append_multiple_char, *vlist) + def rtype_method_append_charpsize(self, hop): + vlist = hop.inputargs(self, self.raw_ptr_repr, lltype.Signed) + hop.exception_cannot_occur() + return hop.gendirectcall(self.ll_append_charpsize, *vlist) + def rtype_method_getlength(self, hop): vlist = hop.inputargs(self) hop.exception_cannot_occur() diff --git a/pypy/rpython/rptr.py b/pypy/rpython/rptr.py --- a/pypy/rpython/rptr.py +++ b/pypy/rpython/rptr.py @@ -22,7 +22,7 @@ class __extend__(annmodel.SomeInteriorPtr): def rtyper_makerepr(self, rtyper): return InteriorPtrRepr(self.ll_ptrtype) - + class PtrRepr(Repr): @@ -91,7 +91,7 @@ vlist = hop.inputargs(*hop.args_r) nexpected = len(self.lowleveltype.TO.ARGS) nactual = len(vlist)-1 - if nactual != nexpected: + if nactual != nexpected: raise TyperError("argcount mismatch: expected %d got %d" % (nexpected, nactual)) if isinstance(vlist[0], flowmodel.Constant): @@ -111,7 +111,12 @@ hop.swap_fst_snd_args() hop.r_s_popfirstarg() return self.rtype_simple_call(hop) - + +class __extend__(pairtype(PtrRepr, PtrRepr)): + def convert_from_to((r_ptr1, r_ptr2), v, llop): + assert r_ptr1.lowleveltype == r_ptr2.lowleveltype + return v + class __extend__(pairtype(PtrRepr, IntegerRepr)): @@ -205,7 +210,7 @@ self.lowleveltype = adtmeth.ll_ptrtype self.ll_ptrtype = adtmeth.ll_ptrtype self.lowleveltype = rtyper.getrepr(annmodel.lltype_to_annotation(adtmeth.ll_ptrtype)).lowleveltype - + def rtype_simple_call(self, hop): hop2 = hop.copy() func = self.func @@ -242,7 +247,7 @@ if numitemoffsets > 0: self.lowleveltype = lltype.Ptr(self.parentptrtype._interior_ptr_type_with_index(self.resulttype.TO)) else: - self.lowleveltype = self.parentptrtype + self.lowleveltype = self.parentptrtype def getinteriorfieldargs(self, hop, v_self): vlist = [] @@ -305,7 +310,7 @@ class __extend__(pairtype(InteriorPtrRepr, IntegerRepr)): - def rtype_getitem((r_ptr, r_item), hop): + def rtype_getitem((r_ptr, r_item), hop): ARRAY = r_ptr.resulttype.TO ITEM_TYPE = ARRAY.OF if isinstance(ITEM_TYPE, lltype.ContainerType): @@ -325,7 +330,7 @@ vlist = r_ptr.getinteriorfieldargs(hop, v_self) + [v_index] return hop.genop('getinteriorfield', vlist, resulttype=ITEM_TYPE) - + def rtype_setitem((r_ptr, r_index), hop): ARRAY = r_ptr.resulttype.TO ITEM_TYPE = ARRAY.OF @@ -333,11 +338,11 @@ v_self, v_index, v_value = hop.inputargs(r_ptr, lltype.Signed, hop.args_r[2]) vlist = r_ptr.getinteriorfieldargs(hop, v_self) + [v_index, v_value] hop.genop('setinteriorfield', vlist) - + class __extend__(pairtype(InteriorPtrRepr, LLADTMethRepr)): def convert_from_to((r_from, r_to), v, llops): if r_from.lowleveltype == r_to.lowleveltype: return v return NotImplemented - + diff --git a/pypy/rpython/test/test_rbuilder.py b/pypy/rpython/test/test_rbuilder.py --- a/pypy/rpython/test/test_rbuilder.py +++ b/pypy/rpython/test/test_rbuilder.py @@ -1,8 +1,10 @@ import py + +from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rpython.annlowlevel import llstr, hlstr +from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem.rbuilder import * from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin -from pypy.rpython.lltypesystem.rbuilder import * -from pypy.rpython.annlowlevel import llstr, hlstr -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder class TestStringBuilderDirect(object): @@ -73,6 +75,15 @@ res = self.interpret(func, []) assert res == 4 + def test_append_charpsize(self): + def func(l): + s = StringBuilder() + with rffi.scoped_str2charp("hello world") as x: + s.append_charpsize(x, l) + return s.build() + res = self.ll_to_string(self.interpret(func, [5])) + assert res == "hello" + class TestLLtype(BaseTestStringBuilder, LLRtypeMixin): pass @@ -81,3 +92,5 @@ py.test.skip("getlength(): not implemented on ootype") def test_unicode_getlength(self): py.test.skip("getlength(): not implemented on ootype") + def test_append_charpsize(self): + py.test.skip("append_charpsize(): not implemented on ootype") \ No newline at end of file diff --git a/pypy/rpython/test/test_rint.py b/pypy/rpython/test/test_rint.py --- a/pypy/rpython/test/test_rint.py +++ b/pypy/rpython/test/test_rint.py @@ -8,6 +8,9 @@ from pypy.rlib import objectmodel from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem.lloperation import llop class TestSnippet(object): @@ -412,4 +415,8 @@ pass class TestOOtype(BaseTestRint, OORtypeMixin): - pass + def test_oobox_int(self): + def f(): + x = llop.oobox_int(ootype.Object, 42) + return llop.oounbox_int(lltype.Signed, x) + assert self.interpret(f, []) == 42 diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/tool/algo/regalloc.py copy from pypy/jit/codewriter/regalloc.py copy to pypy/tool/algo/regalloc.py --- a/pypy/jit/codewriter/regalloc.py +++ b/pypy/tool/algo/regalloc.py @@ -2,13 +2,11 @@ from pypy.objspace.flow.model import Variable from pypy.tool.algo.color import DependencyGraph from pypy.tool.algo.unionfind import UnionFind -from pypy.jit.metainterp.history import getkind -from pypy.jit.codewriter.flatten import ListOfKind -def perform_register_allocation(graph, kind): +def perform_register_allocation(graph, consider_var, ListOfKind=()): """Perform register allocation for the Variables of the given 'kind' in the 'graph'.""" - regalloc = RegAllocator(graph, kind) + regalloc = RegAllocator(graph, consider_var, ListOfKind) regalloc.make_dependencies() regalloc.coalesce_variables() regalloc.find_node_coloring() @@ -18,9 +16,10 @@ class RegAllocator(object): DEBUG_REGALLOC = False - def __init__(self, graph, kind): + def __init__(self, graph, consider_var, ListOfKind): self.graph = graph - self.kind = kind + self.consider_var = consider_var + self.ListOfKind = ListOfKind def make_dependencies(self): dg = DependencyGraph() @@ -31,7 +30,7 @@ for v in op.args: if isinstance(v, Variable): die_at[v] = i - elif isinstance(v, ListOfKind): + elif isinstance(v, self.ListOfKind): for v1 in v: if isinstance(v1, Variable): die_at[v1] = i @@ -51,7 +50,7 @@ # Done. XXX the code above this line runs 3 times # (for kind in KINDS) to produce the same result... livevars = [v for v in block.inputargs - if getkind(v.concretetype) == self.kind] + if self.consider_var(v)] # Add the variables of this block to the dependency graph for i, v in enumerate(livevars): dg.add_node(v) @@ -67,10 +66,10 @@ pass die_index += 1 if (op.result is not None and - getkind(op.result.concretetype) == self.kind): + self.consider_var(op.result)): dg.add_node(op.result) for v in livevars: - if getkind(v.concretetype) == self.kind: + if self.consider_var(v): dg.add_edge(v, op.result) livevars.add(op.result) self._depgraph = dg @@ -95,8 +94,8 @@ self._try_coalesce(v, link.target.inputargs[i]) def _try_coalesce(self, v, w): - if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: - assert getkind(w.concretetype) == self.kind + if isinstance(v, Variable) and self.consider_var(v): + assert self.consider_var(w) dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) diff --git a/pypy/translator/cli/metavm.py b/pypy/translator/cli/metavm.py --- a/pypy/translator/cli/metavm.py +++ b/pypy/translator/cli/metavm.py @@ -1,6 +1,6 @@ from pypy.translator.cli import oopspec from pypy.rpython.ootypesystem import ootype -from pypy.rpython.lltypesystem import rffi +from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.oosupport.metavm import Generator, InstructionList, MicroInstruction,\ PushAllArgs, StoreResult, GetField, SetField, DownCast from pypy.translator.oosupport.metavm import _Call as _OOCall @@ -173,6 +173,16 @@ generator.load(v_obj) generator.ilasm.opcode('unbox.any', boxtype) +class _UnboxType(MicroInstruction): + def __init__(self, TO): + self.TO = TO + + def render(self, generator, op): + v_obj, = op.args + boxtype = generator.cts.lltype_to_cts(self.TO) + generator.load(v_obj) + generator.ilasm.opcode('unbox.any', boxtype) + class _NewArray(MicroInstruction): def render(self, generator, op): v_type, v_length = op.args @@ -312,6 +322,7 @@ #CastWeakAdrToPtr = _CastWeakAdrToPtr() Box = _Box() Unbox = _Unbox() +UnboxInt = _UnboxType(lltype.Signed) NewArray = _NewArray() GetArrayElem = _GetArrayElem() SetArrayElem = _SetArrayElem() diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py --- a/pypy/translator/cli/opcodes.py +++ b/pypy/translator/cli/opcodes.py @@ -2,7 +2,7 @@ IndirectCall, GetField, SetField, DownCast, NewCustomDict,\ MapException, Box, Unbox, NewArray, GetArrayElem, SetArrayElem,\ TypeOf, CastPrimitive, EventHandler, GetStaticField, SetStaticField, \ - DebugPrint + DebugPrint, UnboxInt from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult, InstructionList,\ New, RuntimeNew, CastTo, PushPrimitive, OOString, OOUnicode, OONewArray from pypy.translator.cli.cts import WEAKREF @@ -48,6 +48,8 @@ 'cast_from_object': [DownCast], 'clibox': [Box], 'cliunbox': [Unbox], + 'oobox_int': [Box], + 'oounbox_int': [UnboxInt], 'cli_newarray': [NewArray], 'cli_getelem': [GetArrayElem], 'cli_setelem': [SetArrayElem], @@ -92,6 +94,7 @@ 'debug_fatalerror': [PushAllArgs, 'call void [pypylib]pypy.runtime.Debug::DEBUG_FATALERROR(string)'], 'keepalive': Ignore, 'jit_marker': Ignore, + 'jit_force_quasi_immutable':Ignore, 'jit_force_virtualizable': Ignore, 'jit_force_virtual': DoNothing, } diff --git a/pypy/translator/cli/test/test_int.py b/pypy/translator/cli/test/test_int.py --- a/pypy/translator/cli/test/test_int.py +++ b/pypy/translator/cli/test/test_int.py @@ -1,8 +1,8 @@ import py from pypy.translator.cli.test.runtest import CliTest -from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test -class TestCliInt(CliTest, BaseTestRint): +class TestCliInt(CliTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py --- a/pypy/translator/jvm/opcodes.py +++ b/pypy/translator/jvm/opcodes.py @@ -77,6 +77,8 @@ 'oosend': [JvmCallMethod, StoreResult], 'ooupcast': DoNothing, 'oodowncast': [DownCast, StoreResult], + 'oobox_int': jvm.PYPYBOXINT, + 'oounbox_int': jvm.PYPYUNBOXINT, 'cast_to_object': DoNothing, 'cast_from_object': [DownCast, StoreResult], 'instanceof': [CastTo, StoreResult], diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -307,6 +307,14 @@ return result; } + public static Object box_integer(int x) { + return new Integer(x); + } + + public static int unbox_integer(Object o) { + Integer x = (Integer)o; + return x.intValue(); + } // Used in testing the JVM backend: // // A series of methods which serve a similar purpose to repr() in Python: diff --git a/pypy/translator/jvm/test/test_int.py b/pypy/translator/jvm/test/test_int.py --- a/pypy/translator/jvm/test/test_int.py +++ b/pypy/translator/jvm/test/test_int.py @@ -1,10 +1,11 @@ import py from pypy.translator.jvm.test.runtest import JvmTest from pypy.rpython.test.test_rint import BaseTestRint +from pypy.rpython.test.test_rint import TestOOtype as _TestOOtype # so py.test won't run the base test # ====> ../../../rpython/test/test_rint.py -class TestJvmInt(JvmTest, BaseTestRint): +class TestJvmInt(JvmTest, _TestOOtype): def test_char_constant(self): def dummyfn(i): return chr(i) diff --git a/pypy/translator/jvm/typesystem.py b/pypy/translator/jvm/typesystem.py --- a/pypy/translator/jvm/typesystem.py +++ b/pypy/translator/jvm/typesystem.py @@ -963,6 +963,8 @@ PYPYRUNTIMENEW = Method.s(jPyPy, 'RuntimeNew', (jClass,), jObject) PYPYSTRING2BYTES = Method.s(jPyPy, 'string2bytes', (jString,), jByteArray) PYPYARRAYTOLIST = Method.s(jPyPy, 'array_to_list', (jObjectArray,), jArrayList) +PYPYBOXINT = Method.s(jPyPy, 'box_integer', (jInt,), jObject) +PYPYUNBOXINT = Method.s(jPyPy, 'unbox_integer', (jObject,), jInt) PYPYOOPARSEFLOAT = Method.v(jPyPy, 'ooparse_float', (jString,), jDouble) OBJECTGETCLASS = Method.v(jObject, 'getClass', (), jClass) CLASSGETNAME = Method.v(jClass, 'getName', (), jString) diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py --- a/pypy/translator/oosupport/test_template/operations.py +++ b/pypy/translator/oosupport/test_template/operations.py @@ -1,3 +1,6 @@ +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype from pypy.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, ovfcheck from pypy.rlib import rstack from pypy.annotation import model as annmodel From noreply at buildbot.pypy.org Fri Jul 29 03:33:07 2011 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 29 Jul 2011 03:33:07 +0200 (CEST) Subject: [pypy-commit] pypy default: fix handling of inf in jvm's frexp Message-ID: <20110729013307.C033382110@wyvern.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r46078:4d824e4fcf57 Date: 2011-07-28 18:32 -0700 http://bitbucket.org/pypy/pypy/changeset/4d824e4fcf57/ Log: fix handling of inf in jvm's frexp diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -1100,9 +1100,9 @@ if (Double.isNaN(x)) return interlink.recordFloatSigned(x, 0); - // Infinity: Python throws exception + // Infinity: Python returns (inf, 0) if (Double.isInfinite(x)) - interlink.throwOverflowError(); + return interlink.recordFloatSigned(x, 0); // Extract the various parts of the format: final long e=11, f=52; // number of bits in IEEE format From noreply at buildbot.pypy.org Fri Jul 29 05:22:23 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 05:22:23 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: A branch to implement a generic unroll-if decorator, as well as a jit.isconstant predicate. Message-ID: <20110729032223.7EB0B82110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46079:6159c9aad995 Date: 2011-07-28 19:44 -0700 http://bitbucket.org/pypy/pypy/changeset/6159c9aad995/ Log: A branch to implement a generic unroll-if decorator, as well as a jit.isconstant predicate. From noreply at buildbot.pypy.org Fri Jul 29 05:22:24 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 05:22:24 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Implement this mostly. unroll_if does simple python code gen, and isconstant has an oopspec so it's recognized by jtransform, which creates a spaceop for it. Pretty simple all in all. Message-ID: <20110729032224.BD43982110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46080:184d7477fc30 Date: 2011-07-28 20:22 -0700 http://bitbucket.org/pypy/pypy/changeset/184d7477fc30/ Log: Implement this mostly. unroll_if does simple python code gen, and isconstant has an oopspec so it's recognized by jtransform, which creates a spaceop for it. Pretty simple all in all. diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -1071,6 +1071,9 @@ return SpaceOperation('%s_assert_green' % kind, args, None) elif oopspec_name == 'jit.current_trace_length': return SpaceOperation('current_trace_length', [], op.result) + elif oopspec_name == 'jit.isconstant': + kind = getkind(args[0].concretetype) + return SpaceOperation('%s_isconstant' % kind, args, op.result) else: raise AssertionError("missing support for %r" % oopspec_name) diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -819,6 +819,10 @@ def bhimpl_current_trace_length(): return -1 + @arguments("i", returns="i") + def bhimpl_int_isconstant(x): + return False + # ---------- # the main hints and recursive calls diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1047,6 +1047,12 @@ return ConstInt(trace_length) @arguments("box") + def _opimpl_isconstant(self, box): + return ConstInt(isinstance(box, Const)) + + opimpl_int_isconstant = _opimpl_isconstant + + @arguments("box") def opimpl_virtual_ref(self, box): # Details on the content of metainterp.virtualref_boxes: # diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -1,23 +1,24 @@ +import sys + import py -import sys -from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside -from pypy.rlib.jit import loop_invariant, elidable, promote -from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed -from pypy.rlib.jit import unroll_safe, current_trace_length + +from pypy import conftest +from pypy.jit.codewriter.policy import JitPolicy, StopAtXPolicy from pypy.jit.metainterp import pyjitpl, history +from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT +from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, noConst +from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper +from pypy.jit.metainterp.warmspot import get_stats from pypy.jit.metainterp.warmstate import set_future_value -from pypy.jit.metainterp.warmspot import get_stats -from pypy.jit.codewriter.policy import JitPolicy, StopAtXPolicy -from pypy import conftest +from pypy.rlib.jit import (JitDriver, we_are_jitted, hint, dont_look_inside, + loop_invariant, elidable, promote, jit_debug, assert_green, + AssertGreenFailed, unroll_safe, current_trace_length, unroll_if, isconstant) from pypy.rlib.rarithmetic import ovfcheck -from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.ootypesystem import ootype -from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT -from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, noConst + class BasicTests: - def test_basic(self): def f(x, y): return x + y @@ -2682,5 +2683,35 @@ self.meta_interp(f, [10], repeat=3) + def test_unroll_if_const(self): + @unroll_if(lambda arg: isconstant(arg)) + def f(arg): + s = 0 + while arg > 0: + s += arg + arg -= 1 + return s + + driver = JitDriver(greens = ['code'], reds = ['n', 'arg', 's']) + + def main(code, n, arg): + s = 0 + while n > 0: + driver.jit_merge_point(code=code, n=n, arg=arg, s=s) + if code == 0: + s += f(arg) + else: + s += f(1) + n -= 1 + return s + + res = self.meta_interp(main, [0, 10, 2], enable_opts='') + assert res == main(0, 10, 2) + self.check_loops(call=1) + res = self.meta_interp(main, [1, 10, 2], enable_opts='') + assert res == main(1, 10, 2) + self.check_loops(call=0) + + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -1,10 +1,13 @@ +import sys + import py -import sys + +from pypy.rlib.nonconst import NonConstant +from pypy.rlib.objectmodel import CDefinedIntSymbolic, keepalive_until_here, specialize +from pypy.rlib.unroll import unrolling_iterable from pypy.rpython.extregistry import ExtRegistryEntry -from pypy.rlib.objectmodel import CDefinedIntSymbolic -from pypy.rlib.objectmodel import keepalive_until_here, specialize -from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.nonconst import NonConstant +from pypy.tool.sourcetools import func_with_new_name + def elidable(func): """ Decorate a function as "trace-elidable". This means precisely that: @@ -70,17 +73,22 @@ func._jit_loop_invariant_ = True return func +def _get_args(func): + import inspect + + args, varargs, varkw, defaults = inspect.getargspec(func) + args = ["v%s" % (i, ) for i in range(len(args))] + assert varargs is None and varkw is None + assert not defaults + return args + def elidable_promote(promote_args='all'): """ A decorator that promotes all arguments and then calls the supplied function """ def decorator(func): - import inspect elidable(func) - args, varargs, varkw, defaults = inspect.getargspec(func) - args = ["v%s" % (i, ) for i in range(len(args))] - assert varargs is None and varkw is None - assert not defaults + args = _get_args(func) argstring = ", ".join(args) code = ["def f(%s):\n" % (argstring, )] if promote_args != 'all': @@ -100,6 +108,26 @@ warnings.warn("purefunction_promote is deprecated, use elidable_promote instead", DeprecationWarning) return elidable_promote(*args, **kwargs) +def unroll_if(predicate): + def inner(func): + args = _get_args(func) + argstring = ", ".join(args) + d = { + "func": func, + "func_unroll": unroll_safe(func_with_new_name(func, func.__name__ + "_unroll")), + "predicate": predicate, + } + exec py.code.Source(""" + def f(%(argstring)s): + if predicate(%(argstring)s): + return func_unroll(%(argstring)s) + else: + return func(%(argstring)s) + """ % {"argstring": argstring}).compile() in d + result = d["f"] + result.func_name = func.func_name + "_unroll_if" + return result + return inner def oopspec(spec): def decorator(func): @@ -107,6 +135,18 @@ return func return decorator + at oopspec("jit.isconstant(value)") +def isconstant(value): + """ + While tracing, returns whether or not the value is currently known to be + constant. This is not perfect, values can become constant later. Mostly for + use with @unroll_if. + """ + # I hate the annotator so much. + if NonConstant(False): + return True + return False + class Entry(ExtRegistryEntry): _about_ = hint @@ -280,7 +320,7 @@ def specialize_call(self, hop): pass - + vref_None = non_virtual_ref(None) # ____________________________________________________________ @@ -290,7 +330,7 @@ """Inconsistency in the JIT hints.""" PARAMETERS = {'threshold': 1032, # just above 1024 - 'function_threshold': 1617, # slightly more than one above + 'function_threshold': 1617, # slightly more than one above 'trace_eagerness': 200, 'trace_limit': 12000, 'inlining': 1, @@ -400,7 +440,7 @@ raise set_user_param._annspecialcase_ = 'specialize:arg(0)' - + def on_compile(self, logger, looptoken, operations, type, *greenargs): """ A hook called when loop is compiled. Overwrite for your own jitdriver if you want to do something special, like From noreply at buildbot.pypy.org Fri Jul 29 05:53:44 2011 From: noreply at buildbot.pypy.org (justinpeel) Date: Fri, 29 Jul 2011 05:53:44 +0200 (CEST) Subject: [pypy-commit] pypy default: numpy: fix slices of virtual arrays Message-ID: <20110729035344.50BAA82110@wyvern.cs.uni-duesseldorf.de> Author: Justin Peel Branch: Changeset: r46081:8077531fdd4e Date: 2011-07-28 21:53 -0600 http://bitbucket.org/pypy/pypy/changeset/8077531fdd4e/ Log: numpy: fix slices of virtual arrays diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -187,17 +187,17 @@ def _getnums(self, comma): if self.find_size() > 1000: nums = [ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(3) ] nums.append("..." + "," * comma) nums.extend([ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(self.find_size() - 3, self.find_size()) ]) else: nums = [ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(self.find_size()) ] return nums @@ -229,7 +229,7 @@ start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) if step == 0: # Single index - return space.wrap(self.get_concrete().getitem(start)) + return space.wrap(self.get_concrete().eval(start)) else: # Slice res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) @@ -416,14 +416,12 @@ # in fact, ViewArray never gets "concrete" as it never stores data. # This implementation is needed for BaseArray getitem/setitem to work, # can be refactored. + self.parent.get_concrete() return self def eval(self, i): return self.parent.eval(self.calc_index(i)) - def getitem(self, item): - return self.parent.getitem(self.calc_index(item)) - @unwrap_spec(item=int, value=float) def setitem(self, item, value): return self.parent.setitem(self.calc_index(item), value) @@ -497,9 +495,6 @@ def descr_len(self, space): return space.wrap(self.size) - def getitem(self, item): - return self.storage[item] - def setitem(self, item, value): self.invalidated() self.storage[item] = value diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -70,6 +70,7 @@ from numpy import array, zeros a = array(range(5)) assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + assert str((2*a)[:]) == "[0.0 2.0 4.0 6.0 8.0]" a = zeros(1001) assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" From noreply at buildbot.pypy.org Fri Jul 29 06:29:26 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 06:29:26 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Use a closure, makes both gutworth and I happy. Also start messing with pypyjit. Message-ID: <20110729042926.AEFFF82110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46082:db578c6cbc4b Date: 2011-07-28 21:29 -0700 http://bitbucket.org/pypy/pypy/changeset/db578c6cbc4b/ Log: Use a closure, makes both gutworth and I happy. Also start messing with pypyjit. diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py --- a/pypy/jit/tl/pypyjit.py +++ b/pypy/jit/tl/pypyjit.py @@ -37,13 +37,13 @@ set_opt_level(config, level='jit') config.objspace.allworkingmodules = False config.objspace.usemodules.pypyjit = True -config.objspace.usemodules.array = True +config.objspace.usemodules.array = False config.objspace.usemodules._weakref = True config.objspace.usemodules._sre = False -config.objspace.usemodules._lsprof = True +config.objspace.usemodules._lsprof = False # -config.objspace.usemodules._ffi = True -config.objspace.usemodules.micronumpy = True +config.objspace.usemodules._ffi = False +config.objspace.usemodules.micronumpy = False # set_pypy_opt_level(config, level='jit') diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -1,9 +1,7 @@ try: - import numpy - a = numpy.array(range(10)) - b = a + a + a - print b[3] + for i in xrange(1000): + "%d %d" % (i, i) except Exception, e: print "Exception: ", type(e) diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -110,23 +110,16 @@ def unroll_if(predicate): def inner(func): - args = _get_args(func) - argstring = ", ".join(args) - d = { - "func": func, - "func_unroll": unroll_safe(func_with_new_name(func, func.__name__ + "_unroll")), - "predicate": predicate, - } - exec py.code.Source(""" - def f(%(argstring)s): - if predicate(%(argstring)s): - return func_unroll(%(argstring)s) - else: - return func(%(argstring)s) - """ % {"argstring": argstring}).compile() in d - result = d["f"] - result.func_name = func.func_name + "_unroll_if" - return result + func_unroll = unroll_safe(func_with_new_name(func, func.__name__ + "_unroll")) + + def f(*args): + if predicate(*args): + return func_unroll(*args) + else: + return func(*args) + + f.func_name = func.func_name + "_unroll_if" + return f return inner def oopspec(spec): From noreply at buildbot.pypy.org Fri Jul 29 09:08:46 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 09:08:46 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Handle ref types. Start playing with making this work for str mod, mostly copied from fijal's branch. Message-ID: <20110729070846.D096682110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46083:d8fcab4fa290 Date: 2011-07-29 00:09 -0700 http://bitbucket.org/pypy/pypy/changeset/d8fcab4fa290/ Log: Handle ref types. Start playing with making this work for str mod, mostly copied from fijal's branch. diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -823,6 +823,10 @@ def bhimpl_int_isconstant(x): return False + @arguments("r", returns="i") + def bhimpl_ref_isconstant(x): + return False + # ---------- # the main hints and recursive calls diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1050,7 +1050,7 @@ def _opimpl_isconstant(self, box): return ConstInt(isinstance(box, Const)) - opimpl_int_isconstant = _opimpl_isconstant + opimpl_int_isconstant = opimpl_ref_isconstant = _opimpl_isconstant @arguments("box") def opimpl_virtual_ref(self, box): diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py --- a/pypy/objspace/std/formatting.py +++ b/pypy/objspace/std/formatting.py @@ -1,13 +1,15 @@ """ String formatting routines. """ -from pypy.rlib.unroll import unrolling_iterable +from pypy.interpreter.error import OperationError +from pypy.objspace.std.unicodetype import unicode_from_object +from pypy.rlib import jit from pypy.rlib.rarithmetic import ovfcheck from pypy.rlib.rfloat import formatd, DTSF_ALT, isnan, isinf -from pypy.interpreter.error import OperationError +from pypy.rlib.rstring import StringBuilder, UnicodeBuilder +from pypy.rlib.unroll import unrolling_iterable from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.rstring import StringBuilder, UnicodeBuilder -from pypy.objspace.std.unicodetype import unicode_from_object + class BaseStringFormatter(object): def __init__(self, space, values_w, w_valuedict): @@ -233,6 +235,9 @@ return w_value + # Only shows up if we've already started inlining format(), so just + # unconditionally unroll this. + @jit.unroll_safe def peel_flags(self): self.f_ljust = False self.f_sign = False @@ -255,6 +260,8 @@ break self.forward() + # Same as peel_flags. + @jit.unroll_safe def peel_num(self): space = self.space c = self.peekchr() @@ -276,6 +283,7 @@ c = self.peekchr() return result + @jit.unroll_if(lambda self: jit.isconstant(self.fmt)) def format(self): lgt = len(self.fmt) + 4 * len(self.values_w) + 10 if do_unicode: diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py --- a/pypy/rlib/jit.py +++ b/pypy/rlib/jit.py @@ -129,6 +129,7 @@ return decorator @oopspec("jit.isconstant(value)") + at specialize.argtype(0) def isconstant(value): """ While tracing, returns whether or not the value is currently known to be From noreply at buildbot.pypy.org Fri Jul 29 10:11:19 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 29 Jul 2011 10:11:19 +0200 (CEST) Subject: [pypy-commit] pypy default: after armin's changes about elidable raising functions, we generate guard_no_exception here Message-ID: <20110729081119.528D882110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r46084:6114ad40966a Date: 2011-07-29 10:11 +0200 http://bitbucket.org/pypy/pypy/changeset/6114ad40966a/ Log: after armin's changes about elidable raising functions, we generate guard_no_exception here diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -63,6 +63,7 @@ i7 = int_gt(i4, 1) guard_true(i7, descr=...) p9 = call(ConstClass(fromint), i4, descr=...) + guard_no_exception(descr=...) p11 = call(ConstClass(rbigint.mul), p5, p9, descr=...) guard_no_exception(descr=...) i13 = int_sub(i4, 1) From noreply at buildbot.pypy.org Fri Jul 29 12:45:23 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 29 Jul 2011 12:45:23 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Missing a case: wrap(longlong). Message-ID: <20110729104523.C136782110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46085:d373caa523ad Date: 2011-07-29 11:40 +0200 http://bitbucket.org/pypy/pypy/changeset/d373caa523ad/ Log: Missing a case: wrap(longlong). diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -40,6 +40,10 @@ assert _is(wrap(None, 42, in_const_box=True), ConstInt(42)) assert _is(wrap(None, 42.5, in_const_box=True), constfloat(42.5)) assert _is(wrap(None, p, in_const_box=True), ConstPtr(po)) + if longlong.supports_longlong: + import sys + value = longlong.r_float_storage(sys.maxint*17) + assert _is(wrap(None, value), BoxFloat(value)) def test_hash_equal_whatever_lltype(): s1 = rstr.mallocstr(2) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -84,8 +84,10 @@ return history.ConstObj(value) else: return history.BoxObj(value) - elif isinstance(value, float): - value = longlong.getfloatstorage(value) + elif (isinstance(value, float) or + longlong.is_longlong(lltype.typeOf(value))): + if isinstance(value, float): + value = longlong.getfloatstorage(value) if in_const_box: return history.ConstFloat(value) else: From noreply at buildbot.pypy.org Fri Jul 29 12:45:25 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 29 Jul 2011 12:45:25 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Support longlongs in specialize_value() Message-ID: <20110729104525.012B182110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46086:a0921e661656 Date: 2011-07-29 11:45 +0200 http://bitbucket.org/pypy/pypy/changeset/a0921e661656/ Log: Support longlongs in specialize_value() diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rstr from pypy.rpython.ootypesystem import ootype from pypy.rpython.annlowlevel import llhelper -from pypy.jit.metainterp.warmstate import wrap, unwrap +from pypy.jit.metainterp.warmstate import wrap, unwrap, specialize_value from pypy.jit.metainterp.warmstate import equal_whatever, hash_whatever from pypy.jit.metainterp.warmstate import WarmEnterState, JitCell from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr @@ -45,6 +45,13 @@ value = longlong.r_float_storage(sys.maxint*17) assert _is(wrap(None, value), BoxFloat(value)) +def test_specialize_value(): + assert specialize_value(lltype.Char, 0x41) == '\x41' + if longlong.supports_longlong: + import sys + value = longlong.r_float_storage(sys.maxint*17) + assert specialize_value(lltype.SignedLongLong, value) == sys.maxint*17 + def test_hash_equal_whatever_lltype(): s1 = rstr.mallocstr(2) s2 = rstr.mallocstr(2) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -28,6 +28,8 @@ else: return lltype.cast_primitive(TYPE, x) elif INPUT is longlong.FLOATSTORAGE: + if longlong.is_longlong(TYPE): + return rffi.cast(TYPE, x) assert TYPE is lltype.Float return longlong.getrealfloat(x) else: From noreply at buildbot.pypy.org Fri Jul 29 12:45:26 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 29 Jul 2011 12:45:26 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Support SingleFloats in wrap() and specialize_value(). Message-ID: <20110729104526.30A6582110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46087:ce0d5a1ed8cc Date: 2011-07-29 12:42 +0200 http://bitbucket.org/pypy/pypy/changeset/ce0d5a1ed8cc/ Log: Support SingleFloats in wrap() and specialize_value(). diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -1,5 +1,5 @@ from pypy.rpython.test.test_llinterp import interpret -from pypy.rpython.lltypesystem import lltype, llmemory, rstr +from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi from pypy.rpython.ootypesystem import ootype from pypy.rpython.annlowlevel import llhelper from pypy.jit.metainterp.warmstate import wrap, unwrap, specialize_value @@ -8,6 +8,7 @@ from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr from pypy.jit.metainterp.history import ConstInt, ConstFloat, ConstPtr from pypy.jit.codewriter import longlong +from pypy.rlib.rarithmetic import r_singlefloat def boxfloat(x): return BoxFloat(longlong.getfloatstorage(x)) @@ -44,6 +45,11 @@ import sys value = longlong.r_float_storage(sys.maxint*17) assert _is(wrap(None, value), BoxFloat(value)) + assert _is(wrap(None, value, in_const_box=True), ConstFloat(value)) + sfval = r_singlefloat(42.5) + ival = longlong.singlefloat2int(sfval) + assert _is(wrap(None, sfval), BoxInt(ival)) + assert _is(wrap(None, sfval, in_const_box=True), ConstInt(ival)) def test_specialize_value(): assert specialize_value(lltype.Char, 0x41) == '\x41' @@ -51,6 +57,9 @@ import sys value = longlong.r_float_storage(sys.maxint*17) assert specialize_value(lltype.SignedLongLong, value) == sys.maxint*17 + sfval = r_singlefloat(42.5) + ival = longlong.singlefloat2int(sfval) + assert specialize_value(rffi.FLOAT, ival) == sfval def test_hash_equal_whatever_lltype(): s1 = rstr.mallocstr(2) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -25,6 +25,8 @@ if isinstance(TYPE, lltype.Ptr) and TYPE.TO._gckind == 'raw': # non-gc pointer return rffi.cast(TYPE, x) + elif TYPE is lltype.SingleFloat: + return longlong.int2singlefloat(x) else: return lltype.cast_primitive(TYPE, x) elif INPUT is longlong.FLOATSTORAGE: @@ -97,6 +99,8 @@ elif isinstance(value, str) or isinstance(value, unicode): assert len(value) == 1 # must be a character value = ord(value) + elif lltype.typeOf(value) is lltype.SingleFloat: + value = longlong.singlefloat2int(value) else: value = intmask(value) if in_const_box: From noreply at buildbot.pypy.org Fri Jul 29 12:45:27 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 29 Jul 2011 12:45:27 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: In-progress: simplify rlib/libffi to not depend on casting longlongs Message-ID: <20110729104527.7248382110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46088:066a4bfeb276 Date: 2011-07-29 12:44 +0200 http://bitbucket.org/pypy/pypy/changeset/066a4bfeb276/ Log: In-progress: simplify rlib/libffi to not depend on casting longlongs to floats. It was done this way to work around some small but obscure bugs left and right in the jit. Instead, fix these bugs. diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -1145,6 +1145,7 @@ del _future_values[:] def set_future_value_int(index, value): + assert type(value) is int set_future_value_ref(index, value) def set_future_value_float(index, value): diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -328,12 +328,16 @@ def calldescrof_dynamic(self, ffi_args, ffi_result, extrainfo=None): from pypy.jit.backend.llsupport.ffisupport import get_ffi_type_kind + from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind arg_types = [] - for arg in ffi_args: - kind = get_ffi_type_kind(arg) - if kind != history.VOID: - arg_types.append(kind) - reskind = get_ffi_type_kind(ffi_result) + try: + for arg in ffi_args: + kind = get_ffi_type_kind(self, arg) + if kind != history.VOID: + arg_types.append(kind) + reskind = get_ffi_type_kind(self, ffi_result) + except UnsupportedKind: + return None return self.getdescr(0, reskind, extrainfo=extrainfo, arg_types=''.join(arg_types)) diff --git a/pypy/jit/backend/llsupport/ffisupport.py b/pypy/jit/backend/llsupport/ffisupport.py --- a/pypy/jit/backend/llsupport/ffisupport.py +++ b/pypy/jit/backend/llsupport/ffisupport.py @@ -6,14 +6,14 @@ class UnsupportedKind(Exception): pass -def get_call_descr_dynamic(ffi_args, ffi_result, extrainfo=None): +def get_call_descr_dynamic(cpu, ffi_args, ffi_result, extrainfo=None): """Get a call descr: the types of result and args are represented by rlib.libffi.types.*""" try: - reskind = get_ffi_type_kind(ffi_result) - argkinds = [get_ffi_type_kind(arg) for arg in ffi_args] + reskind = get_ffi_type_kind(cpu, ffi_result) + argkinds = [get_ffi_type_kind(cpu, arg) for arg in ffi_args] except UnsupportedKind: - return None # ?? + return None arg_classes = ''.join(argkinds) if reskind == history.INT: size = intmask(ffi_result.c_size) @@ -27,15 +27,19 @@ return VoidCallDescr(arg_classes, extrainfo) assert False -def get_ffi_type_kind(ffi_type): +def get_ffi_type_kind(cpu, ffi_type): from pypy.rlib.libffi import types kind = types.getkind(ffi_type) if kind == 'i' or kind == 'u': return history.INT - elif kind == 'f': + elif cpu.supports_floats and kind == 'f': return history.FLOAT elif kind == 'v': return history.VOID + elif cpu.supports_longlong and (kind == 'I' or kind == 'U'): # longlong + return 'L' + elif cpu.supports_singlefloats and kind == 's': # singlefloat + return 'S' raise UnsupportedKind("Unsupported kind '%s'" % kind) def is_ffi_type_signed(ffi_type): diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -259,7 +259,7 @@ def calldescrof_dynamic(self, ffi_args, ffi_result, extrainfo=None): from pypy.jit.backend.llsupport import ffisupport - return ffisupport.get_call_descr_dynamic(ffi_args, ffi_result, + return ffisupport.get_call_descr_dynamic(self, ffi_args, ffi_result, extrainfo) def get_overflow_error(self): diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py --- a/pypy/jit/codewriter/test/test_longlong.py +++ b/pypy/jit/codewriter/test/test_longlong.py @@ -230,3 +230,18 @@ assert list(op1.args[3]) == [] assert list(op1.args[4]) == vlist assert op1.result == v_result + + +##def test_singlefloat_constants(): +## v_x = varoftype(TYPE) +## vlist = [v_x, const(rffi.cast(TYPE, 7))] +## v_result = varoftype(TYPE) +## op = SpaceOperation('llong_add', vlist, v_result) +## tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) +## op1 = tr.rewrite_operation(op) +## # +## assert op1.opname == 'residual_call_irf_f' +## assert list(op1.args[2]) == [] +## assert list(op1.args[3]) == [] +## assert list(op1.args[4]) == vlist +## assert op1.result == v_result diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -6,7 +6,6 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method from pypy.jit.metainterp.optimizeopt.optimizer import Optimization -from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind class FuncInfo(object): @@ -20,11 +19,8 @@ self.funcval = funcval self.opargs = [] argtypes, restype = self._get_signature(funcval) - try: - self.descr = cpu.calldescrof_dynamic(argtypes, restype) - except UnsupportedKind: - # e.g., I or U for long longs - self.descr = None + self.descr = cpu.calldescrof_dynamic(argtypes, restype) + # ^^^ may be None if unsupported self.prepare_op = prepare_op self.delayed_ops = [] @@ -184,7 +180,8 @@ def do_call(self, op): funcval = self._get_funcval(op) funcinfo = self.funcinfo - if not funcinfo or funcinfo.funcval is not funcval: + if (not funcinfo or funcinfo.funcval is not funcval or + funcinfo.descr is None): return [op] # cannot optimize funcsymval = self.getvalue(op.getarg(2)) arglist = [funcsymval.force_box()] diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -3,7 +3,7 @@ from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong from pypy.rlib.jit import JitDriver, promote, dont_look_inside from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.libffi import ArgChain, longlong2float, float2longlong +from pypy.rlib.libffi import ArgChain from pypy.rlib.libffi import IS_32_BIT from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall from pypy.rpython.lltypesystem import lltype, rffi @@ -12,10 +12,22 @@ from pypy.jit.metainterp.test.support import LLJitMixin class TestFfiCall(LLJitMixin, _TestLibffiCall): + supports_all = False # supports_{floats,longlong,singlefloats} # ===> ../../../rlib/test/test_libffi.py - def call(self, funcspec, args, RESULT, init_result=0, is_struct=False): + def check_loops_if_supported(self, *args, **kwds): + if self.supports_all: + self.check_loops(*args, **kwds) + else: + self.check_loops({'call': 1, + 'guard_no_exception': 1, + 'int_add': 1, + 'int_lt': 1, + 'guard_true': 1, + 'jump': 1}) + + def call(self, funcspec, args, RESULT, is_struct=False): """ Call the function specified by funcspec in a loop, and let the jit to see and optimize it. @@ -24,14 +36,7 @@ lib, name, argtypes, restype = funcspec method_and_args = [] for argval in args: - if type(argval) is r_singlefloat: - method_name = 'arg_singlefloat' - argval = float(argval) - elif IS_32_BIT and type(argval) in [r_longlong, r_ulonglong]: - method_name = 'arg_longlong' - argval = rffi.cast(rffi.LONGLONG, argval) - argval = longlong2float(argval) - elif isinstance(argval, tuple): + if isinstance(argval, tuple): method_name, argval = argval else: method_name = 'arg' @@ -39,10 +44,20 @@ method_and_args = unrolling_iterable(method_and_args) # reds = ['n', 'res', 'func'] - if (RESULT in [rffi.FLOAT, rffi.DOUBLE] or + if (RESULT is rffi.DOUBLE or IS_32_BIT and RESULT in [rffi.LONGLONG, rffi.ULONGLONG]): - reds = ['n', 'func', 'res'] # floats must be *after* refs + reds = ['n', 'func', 'res'] # 'double' floats must be *after* refs driver = JitDriver(reds=reds, greens=[]) + init_result = rffi.cast(RESULT, 0) + # + def g(func): + # a different function, which is marked as "dont_look_inside" + # in case it uses an unsupported argument + argchain = ArgChain() + # this loop is unrolled + for method_name, argval in method_and_args: + getattr(argchain, method_name)(argval) + return func.call(argchain, RESULT, is_struct=is_struct) # def f(n): func = lib.getpointer(name, argtypes, restype) @@ -50,18 +65,22 @@ while n < 10: driver.jit_merge_point(n=n, res=res, func=func) promote(func) - argchain = ArgChain() - # this loop is unrolled - for method_name, argval in method_and_args: - getattr(argchain, method_name)(argval) - res = func.call(argchain, RESULT, is_struct=is_struct) + res = g(func) n += 1 return res # - res = self.meta_interp(f, [0], backendopt=True) + res = self.meta_interp(f, [0], backendopt=True, + supports_floats = self.supports_all, + supports_longlong = self.supports_all, + supports_singlefloats = False) # XXX self.supports_all) + # the calls to check_loops() are in pypy.rlib.test.test_libffi return res def test_byval_result(self): _TestLibffiCall.test_byval_result(self) test_byval_result.__doc__ = _TestLibffiCall.test_byval_result.__doc__ test_byval_result.dont_track_allocations = True + + +class TestFfiCallSupportAll(TestFfiCall): + supports_all = True # supports_{floats,longlong,singlefloats} diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -284,7 +284,9 @@ auto_inline_graphs(self.translator, graphs, 0.01) def build_cpu(self, CPUClass, translate_support_code=False, - no_stats=False, **kwds): + no_stats=False, supports_floats=True, + supports_longlong=True, supports_singlefloats=True, + **kwds): assert CPUClass is not None self.opt = history.Options(**kwds) if no_stats: @@ -296,6 +298,9 @@ self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper) cpu = CPUClass(self.translator.rtyper, self.stats, self.opt, translate_support_code, gcdescr=self.gcdescr) + if not supports_floats: cpu.supports_floats = False + if not supports_longlong: cpu.supports_longlong = False + if not supports_singlefloats: cpu.supports_singlefloats = False self.cpu = cpu def build_meta_interp(self, ProfilerClass): diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -224,7 +224,7 @@ elif w_argtype.is_double(): argchain.arg(space.float_w(w_arg)) elif w_argtype.is_singlefloat(): - argchain.arg_singlefloat(space.float_w(w_arg)) + self.arg_singlefloat(space, argchain, w_arg) elif w_argtype.is_struct(): # arg_raw directly takes value to put inside ll_args w_arg = space.interp_w(W_StructureInstance, w_arg) @@ -267,15 +267,23 @@ else: return w_arg - @jit.dont_look_inside def arg_longlong(self, space, argchain, w_arg): + # a separate function, which can be seen by the jit or not, + # depending on whether longlongs are supported bigarg = space.bigint_w(w_arg) ullval = bigarg.ulonglongmask() llval = rffi.cast(rffi.LONGLONG, ullval) - # this is a hack: we store the 64 bits of the long long into the - # 64 bits of a float (i.e., a C double) - floatval = libffi.longlong2float(llval) - argchain.arg_longlong(floatval) + argchain.arg(llval) + arg_longlong._dont_inline_ = True + + def arg_singlefloat(self, space, argchain, w_arg): + # a separate function, which can be seen by the jit or not, + # depending on whether singlefloats are supported + from pypy.rlib.rarithmetic import r_singlefloat + fval = space.float_w(w_arg) + sfval = r_singlefloat(fval) + argchain.arg(sfval) + arg_singlefloat._dont_inline_ = True def call(self, space, args_w): self = jit.promote(self) diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -2,14 +2,13 @@ from pypy.rpython.lltypesystem import rffi, lltype from pypy.rlib.objectmodel import specialize, enforceargs, we_are_translated -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat +from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat, r_longlong from pypy.rlib import jit from pypy.rlib import clibffi from pypy.rlib.clibffi import get_libc_name, FUNCFLAG_CDECL, AbstractFuncPtr, \ push_arg_as_ffiptr, c_ffi_call, FFI_TYPE_STRUCT from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal from pypy.rlib.rdynload import DLLHANDLE -from pypy.rlib.longlong2float import longlong2float, float2longlong class types(object): """ @@ -122,9 +121,9 @@ elif TYPE is rffi.DOUBLE: cls = FloatArg elif TYPE is rffi.LONGLONG or TYPE is rffi.ULONGLONG: - raise TypeError, 'r_(u)longlong not supported by arg(), use arg_(u)longlong()' + cls = LongLongArg elif TYPE is rffi.FLOAT: - raise TypeError, 'r_singlefloat not supported by arg(), use arg_singlefloat()' + cls = SingleFloatArg else: raise TypeError, 'Unsupported argument type: %s' % TYPE self._append(cls(val)) @@ -133,25 +132,6 @@ def arg_raw(self, val): self._append(RawArg(val)) - def arg_longlong(self, val): - """ - Note: this is a hack. So far, the JIT does not support long longs, so - you must pass it as if it were a python Float (rffi.DOUBLE). You can - use the convenience functions longlong2float and float2longlong to do - the conversions. Note that if you use long longs, the call won't - be jitted at all. - """ - assert IS_32_BIT # use a normal integer on 64-bit platforms - self._append(LongLongArg(val)) - - def arg_singlefloat(self, val): - """ - Note: you must pass a python Float (rffi.DOUBLE), not a r_singlefloat - (else the jit complains). Note that if you use single floats, the - call won't be jitted at all. - """ - self._append(SingleFloatArg(val)) - def _append(self, arg): if self.first is None: self.first = self.last = arg @@ -196,25 +176,25 @@ func._push_raw(self.ptrval, ll_args, i) class SingleFloatArg(AbstractArg): - """ An argument representing a C float (but holding a C double) + """ An argument representing a C float """ - def __init__(self, floatval): - self.floatval = floatval + def __init__(self, singlefloatval): + self.singlefloatval = singlefloatval def push(self, func, ll_args, i): - func._push_single_float(self.floatval, ll_args, i) + func._push_singlefloat(self.singlefloatval, ll_args, i) class LongLongArg(AbstractArg): - """ An argument representing a C long long (but holding a C double) + """ An argument representing a C long long """ - def __init__(self, floatval): - self.floatval = floatval + def __init__(self, longlongval): + self.longlongval = longlongval def push(self, func, ll_args, i): - func._push_longlong(self.floatval, ll_args, i) + func._push_longlong(self.longlongval, ll_args, i) # ====================================================================== @@ -274,15 +254,10 @@ elif RESULT is rffi.DOUBLE: return self._do_call_float(self.funcsym, ll_args) elif RESULT is rffi.FLOAT: - # XXX: even if RESULT is FLOAT, we still return a DOUBLE, else the - # jit complains. Note that the jit is disabled in this case - return self._do_call_single_float(self.funcsym, ll_args) + return self._do_call_singlefloat(self.funcsym, ll_args) elif RESULT is rffi.LONGLONG or RESULT is rffi.ULONGLONG: - # XXX: even if RESULT is LONGLONG, we still return a DOUBLE, else the - # jit complains. Note that the jit is disabled in this case - # (it's not a typo, we really return a DOUBLE) assert IS_32_BIT - return self._do_call_longlong(self.funcsym, ll_args) + res = self._do_call_longlong(self.funcsym, ll_args) elif RESULT is lltype.Void: return self._do_call_void(self.funcsym, ll_args) else: @@ -320,16 +295,15 @@ def _push_float(self, value, ll_args, i): self._push_arg(value, ll_args, i) - @jit.dont_look_inside - def _push_single_float(self, value, ll_args, i): - self._push_arg(r_singlefloat(value), ll_args, i) + @jit.oopspec('libffi_push_singlefloat(self, value, ll_args, i)') + @enforceargs(None, r_singlefloat, None, int) # fix the annotation for tests + def _push_singlefloat(self, value, ll_args, i): + self._push_arg(value, ll_args, i) - @jit.dont_look_inside - def _push_longlong(self, floatval, ll_args, i): - """ - Takes a longlong represented as a python Float. It's a hack for the - jit, else we could not see the whole libffi module at all""" - self._push_arg(float2longlong(floatval), ll_args, i) + @jit.oopspec('libffi_push_longlong(self, value, ll_args, i)') + @enforceargs(None, r_longlong, None, int) # fix the annotation for tests + def _push_longlong(self, value, ll_args, i): + self._push_arg(value, ll_args, i) @jit.oopspec('libffi_call_int(self, funcsym, ll_args)') def _do_call_int(self, funcsym, ll_args): @@ -339,20 +313,18 @@ def _do_call_float(self, funcsym, ll_args): return self._do_call(funcsym, ll_args, rffi.DOUBLE) - @jit.dont_look_inside - def _do_call_single_float(self, funcsym, ll_args): - single_res = self._do_call(funcsym, ll_args, rffi.FLOAT) - return float(single_res) + @jit.oopspec('libffi_call_singlefloat(self, funcsym, ll_args)') + def _do_call_singlefloat(self, funcsym, ll_args): + return self._do_call(funcsym, ll_args, rffi.FLOAT) @jit.dont_look_inside def _do_call_raw(self, funcsym, ll_args): # same as _do_call_int, but marked as jit.dont_look_inside return self._do_call(funcsym, ll_args, rffi.LONG) - @jit.dont_look_inside + @jit.oopspec('libffi_call_longlong(self, funcsym, ll_args)') def _do_call_longlong(self, funcsym, ll_args): - llres = self._do_call(funcsym, ll_args, rffi.LONGLONG) - return longlong2float(llres) + return self._do_call(funcsym, ll_args, rffi.LONGLONG) @jit.oopspec('libffi_call_void(self, funcsym, ll_args)') def _do_call_void(self, funcsym, ll_args): diff --git a/pypy/rlib/test/test_libffi.py b/pypy/rlib/test/test_libffi.py --- a/pypy/rlib/test/test_libffi.py +++ b/pypy/rlib/test/test_libffi.py @@ -5,7 +5,7 @@ from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name, make_struct_ffitype_e from pypy.rlib.libffi import CDLL, Func, get_libc_name, ArgChain, types -from pypy.rlib.libffi import longlong2float, float2longlong, IS_32_BIT +from pypy.rlib.libffi import IS_32_BIT class TestLibffiMisc(BaseFfiTest): @@ -52,19 +52,6 @@ del lib assert not ALLOCATED - def test_longlong_as_float(self): - from pypy.translator.c.test.test_genc import compile - maxint64 = r_longlong(9223372036854775807) - def fn(x): - d = longlong2float(x) - ll = float2longlong(d) - return ll - assert fn(maxint64) == maxint64 - # - fn2 = compile(fn, [r_longlong]) - res = fn2(maxint64) - assert res == maxint64 - class TestLibffiCall(BaseFfiTest): """ Test various kind of calls through libffi. @@ -111,7 +98,7 @@ def get_libfoo(self): return self.CDLL(self.libfoo_name) - def call(self, funcspec, args, RESULT, init_result=0, is_struct=False): + def call(self, funcspec, args, RESULT, is_struct=False): """ Call the specified function after constructing and ArgChain with the arguments in ``args``. @@ -128,14 +115,7 @@ func = lib.getpointer(name, argtypes, restype) chain = ArgChain() for arg in args: - if isinstance(arg, r_singlefloat): - chain.arg_singlefloat(float(arg)) - elif IS_32_BIT and isinstance(arg, r_longlong): - chain.arg_longlong(longlong2float(arg)) - elif IS_32_BIT and isinstance(arg, r_ulonglong): - arg = rffi.cast(rffi.LONGLONG, arg) - chain.arg_longlong(longlong2float(arg)) - elif isinstance(arg, tuple): + if isinstance(arg, tuple): methname, arg = arg meth = getattr(chain, methname) meth(arg) @@ -149,8 +129,35 @@ """ pass + def check_loops_if_supported(self, *args, **kwds): + """ + Same as check_loops(), but only if support for + float/longlong/singlefloat has been enabled + """ + pass + # ------------------------------------------------------------------------ + def test_very_simple(self): + """ + int diff_xy(int x, long y) + { + return x - y; + } + """ + libfoo = self.get_libfoo() + func = (libfoo, 'diff_xy', [types.sint, types.slong], types.sint) + res = self.call(func, [50, 8], lltype.Signed) + assert res == 42 + self.check_loops({ + 'call_release_gil': 1, + 'guard_no_exception': 1, + 'guard_not_forced': 1, + 'int_add': 1, + 'int_lt': 1, + 'guard_true': 1, + 'jump': 1}) + def test_simple(self): """ int sum_xy(int x, double y) @@ -160,9 +167,9 @@ """ libfoo = self.get_libfoo() func = (libfoo, 'sum_xy', [types.sint, types.double], types.sint) - res = self.call(func, [38, 4.2], rffi.LONG) + res = self.call(func, [38, 4.2], lltype.Signed) assert res == 42 - self.check_loops({ + self.check_loops_if_supported({ 'call_release_gil': 1, 'guard_no_exception': 1, 'guard_not_forced': 1, @@ -174,9 +181,11 @@ def test_float_result(self): libm = self.get_libm() func = (libm, 'pow', [types.double, types.double], types.double) - res = self.call(func, [2.0, 3.0], rffi.DOUBLE, init_result=0.0) + res = self.call(func, [2.0, 3.0], rffi.DOUBLE) assert res == 8.0 - self.check_loops(call_release_gil=1, guard_no_exception=1, guard_not_forced=1) + self.check_loops_if_supported(call_release_gil=1, + guard_no_exception=1, + guard_not_forced=1) def test_cast_result(self): """ @@ -271,8 +280,7 @@ libfoo = self.get_libfoo() func = (libfoo, 'get_pointer_to_b', [], types.pointer) LONGP = lltype.Ptr(rffi.CArray(rffi.LONG)) - null = lltype.nullptr(LONGP.TO) - res = self.call(func, [], LONGP, init_result=null) + res = self.call(func, [], LONGP) assert res[0] == 20 def test_void_result(self): @@ -287,7 +295,7 @@ # initval = self.call(get_dummy, [], rffi.LONG) # - res = self.call(set_dummy, [initval+1], lltype.Void, init_result=None) + res = self.call(set_dummy, [initval+1], lltype.Void) assert res is None # res = self.call(get_dummy, [], rffi.LONG) @@ -305,9 +313,10 @@ func = (libfoo, 'sum_xy_float', [types.float, types.float], types.float) x = r_singlefloat(12.34) y = r_singlefloat(56.78) - res = self.call(func, [x, y], rffi.FLOAT, init_result=0.0) + res = self.call(func, [x, y], rffi.FLOAT) expected = c_float(c_float(12.34).value + c_float(56.78).value).value - assert res == expected + assert float(res) == expected + self.check_loops_if_supported({}) def test_slonglong_args(self): """ @@ -325,18 +334,15 @@ if IS_32_BIT: x = r_longlong(maxint32+1) y = r_longlong(maxint32+2) - zero = longlong2float(r_longlong(0)) else: x = maxint32+1 y = maxint32+2 - zero = 0 - res = self.call(func, [x, y], rffi.LONGLONG, init_result=zero) - if IS_32_BIT: - # obscure, on 32bit it's really a long long, so it returns a - # DOUBLE because of the JIT hack - res = float2longlong(res) + res = self.call(func, [x, y], rffi.LONGLONG) expected = maxint32*2 + 3 assert res == expected + self.check_loops_if_supported(call_release_gil=1, + guard_no_exception=1, + guard_not_forced=1) def test_ulonglong_args(self): """ @@ -354,12 +360,7 @@ types.ulonglong) x = r_ulonglong(maxint64+1) y = r_ulonglong(2) - res = self.call(func, [x, y], rffi.ULONGLONG, init_result=0) - if IS_32_BIT: - # obscure, on 32bit it's really a long long, so it returns a - # DOUBLE because of the JIT hack - res = float2longlong(res) - res = rffi.cast(rffi.ULONGLONG, res) + res = self.call(func, [x, y], rffi.ULONGLONG) expected = maxint64 + 3 assert res == expected @@ -406,7 +407,7 @@ buf[0] = 30 buf[1] = 12 adr = rffi.cast(rffi.VOIDP, buf) - res = self.call(sum_point, [('arg_raw', adr)], rffi.LONG, init_result=0) + res = self.call(sum_point, [('arg_raw', adr)], rffi.LONG) assert res == 42 # check that we still have the ownership on the buffer assert buf[0] == 30 @@ -431,8 +432,7 @@ make_point = (libfoo, 'make_point', [types.slong, types.slong], ffi_point) # PTR = lltype.Ptr(rffi.CArray(rffi.LONG)) - p = self.call(make_point, [12, 34], PTR, init_result=lltype.nullptr(PTR.TO), - is_struct=True) + p = self.call(make_point, [12, 34], PTR, is_struct=True) assert p[0] == 12 assert p[1] == 34 lltype.free(p, flavor='raw') From noreply at buildbot.pypy.org Fri Jul 29 14:20:58 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 29 Jul 2011 14:20:58 +0200 (CEST) Subject: [pypy-commit] buildbot default: use buildbot locks to make sure that benchmarks are run when nothing else is using the CPU; it needs a bit of care because we use two different slaves (tannit32 and tannit64) on the same physical machine, look at the comment at the top of builds.py Message-ID: <20110729122058.91A7C82110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r541:9724de536c4c Date: 2011-07-29 14:07 +0200 http://bitbucket.org/pypy/buildbot/changeset/9724de536c4c/ Log: use buildbot locks to make sure that benchmarks are run when nothing else is using the CPU; it needs a bit of care because we use two different slaves (tannit32 and tannit64) on the same physical machine, look at the comment at the top of builds.py diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -2,9 +2,26 @@ from buildbot.steps import source, shell, transfer, master from buildbot.status.builder import SUCCESS from buildbot.process.properties import WithProperties +from buildbot import locks from pypybuildbot.util import symlink_force import os +# buildbot supports SlaveLocks, which can be used to limit the amout of builds +# to be run on each slave in parallel. However, they assume that each +# buildslave is on a differen physical machine, which is not the case for +# tannit32 and tannit64. As a result, we have to use a global lock, and +# manually tell each builder that uses tannit to acquire it. +# +# Look at the various "locks" session in master.py/BuildmasterConfig. For +# benchmarks, the locks is aquired for the single steps: this way we can run +# translations in parallel, but then the actual benchmarks are run in +# sequence. + +# there are 8 logical CPUs, but only 4 physical ones. We use a maxCount of 6 +# to allow a bit more parallelism, but not too much +TannitCPU = locks.MasterLock('tannit_cpu', maxCount=6) + + class ShellCmd(shell.ShellCommand): # our own version that can distinguish abort cases (rc == -1) @@ -142,7 +159,7 @@ repourl = 'https://bitbucket.org/pypy/pypy/' if getpass.getuser() == 'antocuni': # for debugging - repourl = '/home/antocuni/pypy/pypy-hg' + repourl = '/home/antocuni/pypy/default' # if platform == 'win32': command = "if not exist .hg rmdir /q /s ." @@ -285,13 +302,23 @@ command=['svn', 'co', 'https://bitbucket.org/pypy/benchmarks/trunk', 'benchmarks'], workdir='.')) - self.addStep(Translate(['-Ojit'], [])) + self.addStep( + Translate( + translationArgs=['-Ojit'], + targetArgs=[], + haltOnFailure=False, + # this step can be executed in parallel with other builds + locks=[TannitCPU.access('counting')], + ) + ) pypy_c_rel = "../build/pypy/translator/goal/pypy-c" if postfix: addopts = ['--postfix', postfix] else: addopts = [] self.addStep(ShellCmd( + # this step needs exclusive access to the CPU + locks=[TannitCPU.access('exclusive')], description="run benchmarks on top of pypy-c", command=["python", "runner.py", '--output-filename', 'result.json', '--pypy-c', pypy_c_rel, diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py --- a/bot2/pypybuildbot/master.py +++ b/bot2/pypybuildbot/master.py @@ -105,6 +105,7 @@ pypybuilds = load('pypybuildbot.builds') +TannitCPU = pypybuilds.TannitCPU pypyOwnTestFactory = pypybuilds.Own() pypyOwnTestFactoryWin = pypybuilds.Own(platform="win32") @@ -250,13 +251,25 @@ "slavenames": ["cobra", "bigdogvm1", "tannit32"], "builddir": LINUX32, "factory": pypyOwnTestFactory, - "category": 'linux32' + "category": 'linux32', + # this build needs 4 CPUs + "locks": [TannitCPU.access('counting'), + TannitCPU.access('counting'), + TannitCPU.access('counting'), + TannitCPU.access('counting'), + ], }, {"name": LINUX64, "slavenames": ["tannit64"], "builddir": LINUX64, "factory": pypyOwnTestFactory, - "category": 'linux64' + "category": 'linux64', + # this build needs 4 CPUs + "locks": [TannitCPU.access('counting'), + TannitCPU.access('counting'), + TannitCPU.access('counting'), + TannitCPU.access('counting'), + ], }, {"name": MACOSX32, "slavenames": ["minime"], @@ -274,25 +287,29 @@ "slavenames": ["bigdogvm1", "tannit32"], "builddir": APPLVLLINUX32, "factory": pypyTranslatedAppLevelTestFactory, - 'category': 'linux32' + 'category': 'linux32', + "locks": [TannitCPU.access('counting')], }, {"name": APPLVLLINUX64, "slavenames": ["tannit64"], "builddir": APPLVLLINUX64, "factory": pypyTranslatedAppLevelTestFactory64, - "category": "linux64" + "category": "linux64", + "locks": [TannitCPU.access('counting')], }, {"name": STACKLESSAPPLVLLINUX32, "slavenames": ["bigdogvm1", "tannit32"], "builddir": STACKLESSAPPLVLLINUX32, "factory": pypyStacklessTranslatedAppLevelTestFactory, - "category": 'linux32-stackless' + "category": 'linux32-stackless', + "locks": [TannitCPU.access('counting')], }, {"name": OJITLINUX32, "slavenames": ["bigdogvm1", "tannit32"], "builddir": OJITLINUX32, "factory": pypy_OjitTranslatedTestFactory, - "category": 'linux32' + "category": 'linux32', + "locks": [TannitCPU.access('counting')], }, {"name": APPLVLWIN32, "slavenames": ["bigboard"], @@ -311,12 +328,14 @@ 'builddir' : JITLINUX32, 'factory' : pypyJITTranslatedTestFactory, 'category' : 'linux32', + "locks": [TannitCPU.access('counting')], }, {'name': JITLINUX64, 'slavenames': ['tannit64'], 'builddir': JITLINUX64, 'factory': pypyJITTranslatedTestFactory64, 'category': 'linux64', + "locks": [TannitCPU.access('counting')], }, {"name" : JITMACOSX64, "slavenames": ["macmini-mvt", "xerxes"], @@ -334,19 +353,22 @@ "slavenames": ["tannit32", "bigdogvm1"], "builddir": JITONLYLINUX32, "factory": pypyJitOnlyOwnTestFactory, - "category": 'linux32' + "category": 'linux32', + "locks": [TannitCPU.access('counting')], }, {"name": JITBENCH, "slavenames": ["tannit32"], "builddir": JITBENCH, "factory": pypyJITBenchmarkFactory, "category": 'benchmark-run', + # the locks are acquired with fine grain inside the build }, {"name": JITBENCH64, "slavenames": ["tannit64"], "builddir": JITBENCH64, "factory": pypyJITBenchmarkFactory64, "category": "benchmark-run", + # the locks are acquired with fine grain inside the build }, ], From noreply at buildbot.pypy.org Fri Jul 29 14:20:59 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 29 Jul 2011 14:20:59 +0200 (CEST) Subject: [pypy-commit] buildbot default: rewrite the schedulers in a way that they take advantage of the locks Message-ID: <20110729122059.9F62482110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r542:4e59a65d3475 Date: 2011-07-29 14:21 +0200 http://bitbucket.org/pypy/buildbot/changeset/4e59a65d3475/ Log: rewrite the schedulers in a way that they take advantage of the locks diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -17,9 +17,8 @@ # translations in parallel, but then the actual benchmarks are run in # sequence. -# there are 8 logical CPUs, but only 4 physical ones. We use a maxCount of 6 -# to allow a bit more parallelism, but not too much -TannitCPU = locks.MasterLock('tannit_cpu', maxCount=6) +# there are 8 logical CPUs, but only 4 physical ones +TannitCPU = locks.MasterLock('tannit_cpu', maxCount=4) class ShellCmd(shell.ShellCommand): diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py --- a/bot2/pypybuildbot/master.py +++ b/bot2/pypybuildbot/master.py @@ -209,37 +209,67 @@ 'slavePortnum': slavePortnum, 'change_source': [], + ## 'schedulers': [ + ## Nightly("nightly-0-00", [ + ## JITBENCH, # on tannit -- nothing else there during first round! + ## MACOSX32, # on minime + ## ], hour=0, minute=0), + ## Nightly("nighly-2-00", [ + ## JITBENCH64, # on tannit -- nothing else there during first round! + ## ], hour=2, minute=0), + ## Nightly("nightly-4-00", [ + ## # rule: what we pick here on tannit should take at most 8 cores + ## # and be hopefully finished after 2 hours + ## LINUX32, # on tannit32, uses 4 cores + ## JITLINUX32, # on tannit32, uses 1 core + ## JITLINUX64, # on tannit64, uses 1 core + ## OJITLINUX32, # on tannit32, uses 1 core + ## JITWIN32, # on bigboard + ## STACKLESSAPPLVLFREEBSD64, # on headless + ## JITMACOSX64, # on mvt's machine + ## ], hour=4, minute=0), + ## Nightly("nightly-6-00", [ + ## # there should be only JITLINUX32 that takes a bit longer than + ## # that. We can use a few more cores now. + ## APPLVLLINUX32, # on tannit32, uses 1 core + ## APPLVLLINUX64, # on tannit64, uses 1 core + ## STACKLESSAPPLVLLINUX32, # on tannit32, uses 1 core + ## ], hour=6, minute=0), + ## Nightly("nightly-7-00", [ + ## # the remaining quickly-run stuff on tannit + ## LINUX64, # on tannit64, uses 4 cores + ## ], hour=7, minute=0), + ## ], + 'schedulers': [ + # first of all, we run the benchmarks: the two translations take ~2800 + # seconds and are executed in parallel. Running benchmarks takes ~3400 + # seconds and is executed sequentially. In total, 2800 + (3300*2) ~= + # 160 minutes Nightly("nightly-0-00", [ - JITBENCH, # on tannit -- nothing else there during first round! + JITBENCH, # on tannit32, uses 1 core (in part exclusively) + JITBENCH64, # on tannit64, uses 1 core (in part exclusively) MACOSX32, # on minime ], hour=0, minute=0), - Nightly("nighly-2-00", [ - JITBENCH64, # on tannit -- nothing else there during first round! - ], hour=2, minute=0), - Nightly("nightly-4-00", [ - # rule: what we pick here on tannit should take at most 8 cores - # and be hopefully finished after 2 hours + # + # then, we schedule all the rest. The locks will take care not to run + # all of them in parallel + Nightly("nighly-3-00", [ LINUX32, # on tannit32, uses 4 cores + LINUX64, # on tannit64, uses 4 cores JITLINUX32, # on tannit32, uses 1 core JITLINUX64, # on tannit64, uses 1 core OJITLINUX32, # on tannit32, uses 1 core + APPLVLLINUX32, # on tannit32, uses 1 core + APPLVLLINUX64, # on tannit64, uses 1 core + STACKLESSAPPLVLLINUX32, # on tannit32, uses 1 core + # JITWIN32, # on bigboard STACKLESSAPPLVLFREEBSD64, # on headless JITMACOSX64, # on mvt's machine - ], hour=4, minute=0), - Nightly("nightly-6-00", [ - # there should be only JITLINUX32 that takes a bit longer than - # that. We can use a few more cores now. - APPLVLLINUX32, # on tannit32, uses 1 core - APPLVLLINUX64, # on tannit64, uses 1 core - STACKLESSAPPLVLLINUX32, # on tannit32, uses 1 core - ], hour=6, minute=0), - Nightly("nightly-7-00", [ - # the remaining quickly-run stuff on tannit - LINUX64, # on tannit64, uses 4 cores - ], hour=7, minute=0), + ], hour=3, minute=0) ], + 'status': [status], 'slaves': [BuildSlave(name, password) From noreply at buildbot.pypy.org Fri Jul 29 16:37:59 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 29 Jul 2011 16:37:59 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: put ideas that I killed from z/projects.rst Message-ID: <20110729143759.8ED0182110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: extradoc Changeset: r3843:e2b49cd801ff Date: 2011-07-14 13:54 +0200 http://bitbucket.org/pypy/extradoc/changeset/e2b49cd801ff/ Log: put ideas that I killed from z/projects.rst diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -199,3 +199,33 @@ at the end of the preamble unnessesary. If that policy wont hold in the long run it should be straight forward to augument the VirtualState objects with information about storesinking. + + +Random ideas from hakanardo +---------------------------- + + - Let bridges inherit more information form their parent traces to allow + them to be better optimized. One idea is to augument the resumedata with + the index within the trace inputargs for each failarg that comes directly + from the inputargs. That way a lot of info can be deduced from the short + preamble. Another idea is to actually store a lot of status information on + the guards as they are generated, but then forget (and free) that info as + the guards grow older (in terms of the number of generated guards or + something). + + - Generalisation strategies. Once jit-short_from_state is merged we'll have + a nice platform to experiment with generalizing the loops created. Today + unrolling makes the jit specialize as much as possible which is one reason + it's hard for bridges to reuse the created peeled loops. There is also a + tradeoff between forcing things to be able to reuse an existing loop and + retracing it to form a new specialized version. + + - Better pointer aliasing analyzer that will emit guards that pointers are + different when needed. + + - Make heap optimizer aware of setitems produced by forcing virtuals. + + - Movinging loop-invariant setitems out of the loops entierly. + + - Better support for generators (I red some irc log about inlining them into + their parent frames) From noreply at buildbot.pypy.org Fri Jul 29 16:38:01 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 29 Jul 2011 16:38:01 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: merge heads Message-ID: <20110729143801.279DE82111@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: extradoc Changeset: r3844:d19d57e5c26d Date: 2011-07-29 15:51 +0200 http://bitbucket.org/pypy/extradoc/changeset/d19d57e5c26d/ Log: merge heads diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -1,3 +1,5 @@ +tasks with "(( ))" around them are unlikely. + BUGS ---- @@ -8,23 +10,15 @@ [arigo] - cpython has sys._current_frames(), but not pypy; however relying on this looks like it's not the job of the jit -* we should run nightly 64bit benchmarks. As of mid-April, richards - was noticably (30-50%) slower on 64bit than 32bit. I didn't notice - other benchmarks, but since we don't run it, we don't have a way - to compare. +* fix the cases of MemoryError during the execution of machine code + (they are now a fatal RPython error) + NEW TASKS --------- -- think about whether W_TypeObject._pure_lookup_where_with_method_cache needs a - different decorator, because it cannot be moved around arbitrarily. - - have benchmarks for jit compile time and jit memory usage -- kill GUARD_(NO)_EXCEPTION; replace that by LAST_EXC_VALUE to load the - current exception from the struct in memory, followed by a regular - GUARD_CLASS. (Armin: Look like a simplification, but it's a bit messy too) - - maybe refactor a bit the x86 backend, particularly the register allocation @@ -32,17 +26,8 @@ is a compile time constant (and call unrolled version of string formatting loop in this case). -- generators?? - - consider how much old style classes in stdlib hurt us. -- support raw mallocs - -- support casting from Signed to an opaque pointer - -- local imports should be jitted more efficiently, right now they produce a - long trace and they are rather common (e.g. in translate.py) - - the integer range analysis cannot deal with int_between, because it is lowered to uint arithmetic too early @@ -52,23 +37,19 @@ re.search("(ab)+", "a" * 1000 + "b") almost doesn't get compiled and gets very modest speedups with the JIT on (10-20%) -- consider an automated way to take a function with a loop and generate a +- consider an automated way in RPython: a function with a loop and generate a JITable preamble and postamble with a call to the loop in the middle. - implement small tuples, there are a lot of places where they are hashed and compared +- support single floats in the JIT + OPTIMIZATIONS ------------- Things we can do mostly by editing optimizeopt/: -- getfields which result is never used never get removed (probable cause - - they used to be as livevars in removed guards). also getfields which result - is only used as a livevar in a guard should be removed and encoded in - the guard recovert code (only if we are sure that the stored field cannot - change) - - if we move a promotion up the chain, some arguments don't get replaced with constants (those between current and previous locations). So we get like @@ -80,10 +61,15 @@ maybe we should move promote even higher, before the first use and we could possibly remove more stuff? -- f31 = f17 * f16 - f32 = f16 * f17 + This shows up in another way as well, the Python code - Should be just a matter of synthesizing reverse operations in rewrite.py + if x is None: + i += x + + We promote the guard_nonnull when we load x into guard_nonnull class, + however this happens after the optimizer sees `x is None`, so that ptr_eq + still remains, even though it's obviously not necessary since x and None + will have different known_classes. - optimize arraycopy also in the cases where one of the arrays is a virtual and short. This is seen a lot in translate.py @@ -95,36 +81,17 @@ Extracted from some real-life Python programs, examples that don't give nice code at all so far: -- string manipulation: s[n], s[-n], s[i:j], most operations on single - chars, building a big string with repeated "s += t", "a,b=s.split()", - etc. PARTIALLY DONE with virtual strings - -- http://paste.pocoo.org/show/188520/ - this will compile new assembler path for each new type, even though that's - overspecialization since in this particular case it's not relevant. - This is treated as a megamorphic call (promotion of w_self in typeobject.py) - while in fact it is not. - -- guard_true(frame.is_being_profiled) all over the place - -- cProfile should be supported (right now it prevents JITting completely): - the calls to get the time should be done with the single assembler - instruction "read high-perf time stamp". The dict lookups done by - cProfile should be folded away. IN PROGRESS - - let super() work with the method cache. -- turn max(x, y)/min(x, y) into MAXSD, MINSD instructions when x and y are - floats. - -- xxx (find more examples :-) +- ((turn max(x, y)/min(x, y) into MAXSD, MINSD instructions when x and y are + floats.)) BACKEND TASKS ------------- -Look into avoiding double load of memory into register on 64bit. +Look into avoiding double load of constant into register on 64bit. In case we want to first read a value, increment it and store (for example), -we end up with double load of memory into register. Like: +we end up with double load of constant into register. Like: movabs 0xsomemem,r11 mov (r11), r10 @@ -139,14 +106,12 @@ - think out looking into functions or not, based on arguments, for example contains__Tuple should be unrolled if tuple is of constant - length. HARD, blocked by the fact that we don't know constants soon enough + length. This should be possible now that we do some heap opt during + tracing. Also, an unrolled loop means several copies of the guards, which may fail independently, leading to an exponential number of bridges -- out-of-line guards (when an external change would invalidate existing - pieces of assembler) - -- merge tails of loops-and-bridges? +- ((merge tails of loops-and-bridges?)) UNROLLING --------- diff --git a/talk/icooolps2011/talk/figures/bench.pdf b/talk/icooolps2011/talk/figures/bench.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0def86736f36c863a02694883f29401e911f9c25 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/map.svg b/talk/icooolps2011/talk/figures/map.svg new file mode 100644 --- /dev/null +++ b/talk/icooolps2011/talk/figures/map.svg @@ -0,0 +1,386 @@ + + + +image/svg+xmlmap +map +"a": 0 +add "a" +add "b" +map +"c": 0 +add "c" +map +"a": 0 +"b": 1 +instance + +map + +storage + +array + +4 + +6 + + \ No newline at end of file diff --git a/talk/icooolps2011/talk/figures/map01.pdf b/talk/icooolps2011/talk/figures/map01.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b02a6212807255e3be3a63808946c1f87b32a64a GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/map02.pdf b/talk/icooolps2011/talk/figures/map02.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8f23b0fb78a661be86adf7790844570eed590ef5 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/map03.pdf b/talk/icooolps2011/talk/figures/map03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e9944db6caa3a34e1852cfb8934df628bf64d089 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/metatrace01.pdf b/talk/icooolps2011/talk/figures/metatrace01.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0b7181b5a476093c16ff1233f37535378ef7bf8a GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace-levels-metatracing.svg b/talk/icooolps2011/talk/figures/trace-levels-metatracing.svg new file mode 100644 --- /dev/null +++ b/talk/icooolps2011/talk/figures/trace-levels-metatracing.svg @@ -0,0 +1,833 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + CPU + + Interpreter + + User Program + + + f1 + + + + + f2 + + + + + main_loop + + + + + + BINARY_ADD + + + + JUMP_IF_FALSE + + + + + + + ... + ... + + + + + + + + + + Trace for f1 + + ops frommain_loop...ops fromBINARY_ADD...more ops frommain_loop...ops_fromJUMP_IF_FALSEguard(...)jump to start + + + Tracer + + + CPU + + + diff --git a/talk/icooolps2011/talk/figures/trace-levels-tracing.svg b/talk/icooolps2011/talk/figures/trace-levels-tracing.svg new file mode 100644 --- /dev/null +++ b/talk/icooolps2011/talk/figures/trace-levels-tracing.svg @@ -0,0 +1,991 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + CPU + + Interpreter + + + + + main_loop + + + + + + BINARY_ADD + + + + JUMP_IF_FALSE + + + + + + + ... + ... + + + + + + Tracer + + + CPU + + + + + + + CPU + User Program + + + f1 + + + + + f2 + + + + diff --git a/talk/icooolps2011/talk/figures/trace01.pdf b/talk/icooolps2011/talk/figures/trace01.pdf new file mode 100644 index 0000000000000000000000000000000000000000..252b5089e72d3626e636cd02397204a464c7ca22 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace02.pdf b/talk/icooolps2011/talk/figures/trace02.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ece12fe0c3f96856afea26c49d92ade630db9328 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace03.pdf b/talk/icooolps2011/talk/figures/trace03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..04b38b8996eb2c297214c017bbe1cce1f8f64bdb GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace04.pdf b/talk/icooolps2011/talk/figures/trace04.pdf new file mode 100644 index 0000000000000000000000000000000000000000..472b798aeae005652fc0d749ed6571117c5819d9 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/trace05.pdf b/talk/icooolps2011/talk/figures/trace05.pdf new file mode 100644 index 0000000000000000000000000000000000000000..977e3bbda8d4d349f27f06fcdaa3bd100e95e1a7 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/talk.pdf b/talk/icooolps2011/talk/talk.pdf new file mode 100644 index 0000000000000000000000000000000000000000..66d79ac74735959368d77448b8d8606105e447f1 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/talk.tex b/talk/icooolps2011/talk/talk.tex new file mode 100644 --- /dev/null +++ b/talk/icooolps2011/talk/talk.tex @@ -0,0 +1,531 @@ +\documentclass[utf8x]{beamer} + +% This file is a solution template for: + +% - Talk at a conference/colloquium. +% - Talk length is about 20min. +% - Style is ornate. + +\mode +{ + \usetheme{Warsaw} + % or ... + + %\setbeamercovered{transparent} + % or whatever (possibly just delete it) +} + + +\usepackage[english]{babel} +\usepackage{listings} +\usepackage{fancyvrb} +\usepackage{ulem} +\usepackage{color} +\usepackage{alltt} + +\usepackage[utf8x]{inputenc} + +\input{pygments} + +\newcommand\redsout[1]{{\color{red}\sout{\hbox{\color{black}{#1}}}}} +\newcommand{\noop}{} + +% or whatever + +% Or whatever. Note that the encoding and the font should match. If T1 +% does not look nice, try deleting the line with the fontenc. + + +\title[Runtime Feedback in a Meta-Tracing JIT]{Runtime Feedback in a Meta-Tracing JIT for Efficient Dynamic Languages} + +\author[Carl Friedrich Bolz et. al.]{\emph{Carl Friedrich Bolz}\inst{1} \and Antonio Cuni\inst{3} \and Maciej Fijałkowski\inst{2} \and Michael Leuschel\inst{1} \and Samuele Pedroni\inst{3} \and Armin Rigo\inst{1}} +% - Give the names in the same order as the appear in the paper. +% - Use the \inst{?} command only if the authors have different +% affiliation. + +\institute[Heinrich-Heine-Universität Düsseldorf] +{$^1$Heinrich-Heine-Universität Düsseldorf, STUPS Group, Germany \and + + $^2$merlinux GmbH, Hildesheim, Germany \and + + $^3$Open End, Göteborg, Sweden \and +} + +\date{ICOOOLPS 2011, July 26, 2011} +% - Either use conference name or its abbreviation. +% - Not really informative to the audience, more for people (including +% yourself) who are reading the slides online + + +% If you have a file called "university-logo-filename.xxx", where xxx +% is a graphic format that can be processed by latex or pdflatex, +% resp., then you can add a logo as follows: + + + + +% Delete this, if you do not want the table of contents to pop up at +% the beginning of each subsection: +%\AtBeginSubsection[] +%{ +% \begin{frame} +% \frametitle{Outline} +% \tableofcontents[currentsection,currentsubsection] +% \end{frame} +%} + + +% If you wish to uncover everything in a step-wise fashion, uncomment +% the following command: + +%\beamerdefaultoverlayspecification{<+->} + + +\begin{document} + +\begin{frame} + \titlepage +\end{frame} + +\begin{frame} + \frametitle{Good JIT Compilers for Dynamic Languages are Hard} + \begin{itemize} + \item recent languages like Python, Ruby, JS have complex core semantics + \item many corner cases, even hard to interpret correctly + \pause + \item feedback of runtime information to the compiler is necessary + \item correct exploitation of this information in the compiler + \end{itemize} + \pause + \begin{block}{Problems} + \begin{enumerate} + \item implement all corner-cases of semantics correctly + \item ... and the common cases efficiently + \item feed back and exploit runtime information + \end{enumerate} + \end{block} +\end{frame} + +\begin{frame} + \frametitle{An Interpreter} + \includegraphics[scale=0.5]{figures/trace01.pdf} +\end{frame} + +\begin{frame} + \frametitle{A Tracing JIT} + \includegraphics[scale=0.5]{figures/trace02.pdf} +\end{frame} + +\begin{frame} + \frametitle{A Tracing JIT} + \includegraphics[scale=0.5]{figures/trace03.pdf} +\end{frame} + +\begin{frame} + \frametitle{A Tracing JIT} + \includegraphics[scale=0.5]{figures/trace04.pdf} +\end{frame} + +\begin{frame} + \frametitle{Tracing JITs} + Advantages: + \begin{itemize} + \item can be added to existing VM + \item interpreter does a lot of work + \item can fall back to interpreter for uncommon paths + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Granularity Problems} + \begin{itemize} + \item if the tracer records bytecode, not enough information is there + \item many dynamic languages have bytecodes that contain complex logic + \item need to expand the bytecode in the trace into something more explicit + \item this duplicates the lanuage semantics in the tracer/optimizer + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Example: Attribute Reads in Python} + What happens when an attribute \texttt{x.m} is read? (simplified) + \pause + \begin{itemize} + \item check for \texttt{x.\_\_getattribute\_\_}, if there, call it + \pause + \item look for the attribute in the object's dictionary, if it's there, return it + \pause + \item walk up the MRO and look in each class' dictionary for the attribute + \pause + \item if the attribute is found, call its \texttt{\_\_get\_\_} attribute and return the result + \pause + \item if the attribute is not found, look for \texttt{x.\_\_getattr\_\_}, if there, call it + \pause + \item raise an \texttt{AttributeError} + \end{itemize} + \pause + all this is one bytecode +\end{frame} + +\begin{frame} + \frametitle{Idea of Meta-Tracing} + \includegraphics[scale=0.5]{figures/trace05.pdf} +\end{frame} + +\begin{frame} + \frametitle{Meta-Tracing} + \includegraphics[scale=0.5]{figures/metatrace01.pdf} +\end{frame} + +\begin{frame} + \frametitle{Meta-Tracing JITs} + \begin{block}{Advantages:} + \begin{itemize} + \item semantics are always like that of the interpreter + \item trace fully contains language semantics + \item meta-tracers can be reused for various interpreters + \end{itemize} + \end{block} + \pause + a few meta-tracing systems have been built: + \begin{itemize} + \item Sullivan et.al. describe a meta-tracer using the Dynamo RIO system + \item Yermolovich et.al. run a Lua implementation on top of a tracing JS implementation + \item SPUR is a tracing JIT for CLR bytecodes, which is used to speed up a JS implementation in C\# + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{PyPy} + A general environment for implementing dynamic languages + \pause + \begin{block}{Approach} + \begin{itemize} + \item write an interpreter for the language in RPython + \item compilable to an efficient C-based VM + \pause + \item (RPython is a restricted subset of Python) + \end{itemize} + \end{block} + \pause + \begin{block}{PyPy's Meta-Tracing JIT} + \begin{itemize} + \item PyPy contains a meta-tracing JIT for interpreters in RPython + \item needs a few source-code hints (or annotations) \emph{in the interpreter} + \item powerful general optimizations + \end{itemize} + \end{block} +\end{frame} + +\begin{frame} + \frametitle{Runtime Feedback} + Problems of Naive Meta-Tracing: + \begin{itemize} + \item no runtime feedback of user-level types + \item tracer does not know about invariants in the interpreter + \end{itemize} + \pause + \begin{block}{Proposed Solutions} + \begin{itemize} + \item introduce \textit{hints} that the interpreter-author can use + \item hints are annotation in the interpreter + \item they give information to the meta-tracer + \pause + \item two hints presented here + \item one to induce runtime feedback of arbitrary information + \item the second one to influence constant folding + \end{itemize} + \end{block} +\end{frame} + + +\begin{frame} + \frametitle{Example: Instances with Maps} + \includegraphics[scale=0.7]{figures/map01.pdf} +\end{frame} + +\begin{frame} + \frametitle{Example: Instances with Maps} + \includegraphics[scale=0.7]{figures/map02.pdf} +\end{frame} + +\begin{frame} + \frametitle{Example: Instances with Maps} + \includegraphics[scale=0.7]{figures/map03.pdf} +\end{frame} + +\begin{frame}[containsverbatim] +\frametitle{Map Implementation} + +\begin{Verbatim}[commandchars=\\\{\}] +\PY{k}{class} \PY{n+nc}{Map}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} + \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{indexes}\PY{p}{)}\PY{p}{:} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes} \PY{o}{=} \PY{n}{indexes} + \PY{o}{.}\PY{o}{.}\PY{o}{.} + + \PY{k}{def} \PY{n+nf}{getindex}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{,} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)} + + \PY{k}{def} \PY{n+nf}{add\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{o}{.}\PY{o}{.}\PY{o}{.} + +\PY{n}{EMPTY\PYZus{}MAP} \PY{o}{=} \PY{n}{Map}\PY{p}{(}\PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}\PY{p}{)} +\end{Verbatim} +\end{frame} + +\begin{frame}[plain,containsverbatim] +\begin{Verbatim}[commandchars=\\\{\}] +\PY{k}{class} \PY{n+nc}{Instance}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} + \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{)}\PY{p}{:} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map} \PY{o}{=} \PY{n}{EMPTY\PYZus{}MAP} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{storage} \PY{o}{=} \PY{p}{[}\PY{p}{]} + + \PY{k}{def} \PY{n+nf}{getfield}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{n}{index} \PY{o}{=} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{name}\PY{p}{)} + \PY{k}{if} \PY{n}{index} \PY{o}{!=} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{:} + \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{storage}\PY{p}{[}\PY{n}{index}\PY{p}{]} + \PY{k}{return} \PY{n+nb+bp}{None} + + \PY{k}{def} \PY{n+nf}{write\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{value}\PY{p}{)}\PY{p}{:} + \PY{o}{.}\PY{o}{.}\PY{o}{.} +\end{Verbatim} +\end{frame} + +\begin{frame}[plain,containsverbatim] +\frametitle{Trace for Code \texttt{inst.a + inst.b}} +\begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] +# $inst_1$.getfield("a") +$map_1$ = $inst_1$.map +$index_1$ = Map.getindex($map_1$, "a") +guard($index_1$ != -1) +$storage_1$ = $inst_1$.storage +$result_1$ = $storage_1$[$index_1$] +|\pause| +# $inst_1$.getfield("b") +$map_2$ = $inst_1$.map +$index_2$ = Map.getindex($map_2$, "b") +guard($index_2$ != -1) +$storage_2$ = $inst_1$.storage +$result_2$ = $storage_2$[$index_2$] + +$v_1$ = $result_1$ + $result_2$ +\end{lstlisting} +\end{frame} + +\begin{frame}[plain,containsverbatim] +\frametitle{Trace for Code \texttt{inst.a + inst.b}} +\begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] +# $inst_1$.getfield("a") +$map_1$ = $inst_1$.map +$index_1$ = Map.getindex($map_1$, "a") +guard($index_1$ != -1) +$storage_1$ = $inst_1$.storage +$result_1$ = $storage_1$[$index_1$] + +# $inst_1$.getfield("b") +$map_2$ = $inst_1$.map +$index_2$ = Map.getindex($map_2$, "b") +guard($index_2$ != -1) +$storage_2$ = $inst_1$.storage +$result_2$ = $storage_2$[$index_2$] + +$v_1$ = $result_1$ + $result_2$ +\end{lstlisting} +\end{frame} + +\begin{frame}[containsverbatim] + \frametitle{Runtime Feedback Controlled by the Interpreter Author} + \begin{itemize} + \item give the interpreter author a way to feed back runtime values into the trace + \item written as \texttt{promote(x)} + \item captures the argument's runtime value during tracing + \item should be used only for variables that take few values + \end{itemize} + \pause +\end{frame} + +\begin{frame}[containsverbatim] + \frametitle{Tiny Example} + \begin{minipage}[b]{6cm} + \centering + {\noop + \begin{lstlisting}[mathescape,basicstyle=\ttfamily] +def f1(x, y): + promote(x) + z = x * 2 + 1 + return z + y + \end{lstlisting} + } + \end{minipage} + \vline + \hspace{0.5cm} + \begin{minipage}[b]{4cm} + {\noop + \begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily] +guard($x_1$ == 4) +|{\color{gray}$v_1$ = $x_1$ * 2}| +|{\color{gray}$z_1$ = $v_1$ + 1}| +$v_2$ = $z_1$ + $y_1$ +return($v_2$) + \end{lstlisting} + } + \end{minipage} +\end{frame} + +\begin{frame} + \frametitle{Foldable Operations Defined by the Interpreter Author} + \begin{itemize} + \item let the interpreter author define foldable functions + \item those functions typically don't look foldable + \item otherwise there is no need for an annotation + \item done via a function decorator \texttt{@elidable} + \pause + \item decorated functions should be pure + \item or have idempotent side effects (such as a function that memoizes) + \item trace optimizer will remove calls to such functions with constant arguments + \end{itemize} +\end{frame} + +\begin{frame}[containsverbatim] +\frametitle{Adding Hints to Maps} + +\begin{Verbatim}[commandchars=\\\{\}] +\PY{k}{class} \PY{n+nc}{Map}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} + \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{indexes}\PY{p}{)}\PY{p}{:} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes} \PY{o}{=} \PY{n}{indexes} + \PY{o}{.}\PY{o}{.}\PY{o}{.} + + \PY{n+nd}{@elidable} + \PY{k}{def} \PY{n+nf}{getindex}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{,} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)} + + \PY{k}{def} \PY{n+nf}{add\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{o}{.}\PY{o}{.}\PY{o}{.} + +\PY{n}{EMPTY\PYZus{}MAP} \PY{o}{=} \PY{n}{Map}\PY{p}{(}\PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}\PY{p}{)} +\end{Verbatim} +\end{frame} + +\begin{frame}[containsverbatim] +\frametitle{Adding Hints to Maps} + +\begin{Verbatim}[commandchars=\\\{\}] +\PY{k}{class} \PY{n+nc}{Instance}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:} + \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{)}\PY{p}{:} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map} \PY{o}{=} \PY{n}{EMPTY\PYZus{}MAP} + \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{storage} \PY{o}{=} \PY{p}{[}\PY{p}{]} + + \PY{k}{def} \PY{n+nf}{getfield}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} + \PY{n}{promote}\PY{p}{(}\PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map}\PY{p}{)} + \PY{n}{index} \PY{o}{=} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{name}\PY{p}{)} + \PY{k}{if} \PY{n}{index} \PY{o}{!=} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{:} + \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{storage}\PY{p}{[}\PY{n}{index}\PY{p}{]} + \PY{k}{return} \PY{n+nb+bp}{None} + + \PY{k}{def} \PY{n+nf}{write\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{value}\PY{p}{)}\PY{p}{:} + \PY{o}{.}\PY{o}{.}\PY{o}{.} +\end{Verbatim} +\end{frame} + + +\begin{frame}[containsverbatim,plain] + \frametitle{Trace with Hints for Code \texttt{inst.a + inst.b}} +\begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] +# $inst_1$.getfield("a") +$map_1$ = $inst_1$.map +guard($map_1$ == 0xb74af4a8) +|{\color{gray}$index_1$ = Map.getindex($map_1$, "a")}| +|{\color{gray}guard($index_1$ != -1)}| +$storage_1$ = $inst_1$.storage +$result_1$ = $storage_1$[$index_1$}] + +# $inst_1$.getfield("b") +|{\color{gray}$map_2$ = $inst_1$.map| +|{\color{gray}guard($map_2$ == 0xb74af4a8)}| +|{\color{gray}$index_2$ = Map.getindex($map_2$, "b")}| +|{\color{gray}guard($index_2$ != -1)}| +|{\color{gray}$storage_2$ = $inst_1$.storage}| +$result_2$ = $storage_2$[$index_2$] + +$v_1$ = $result_1$ + $result_2$ +\end{lstlisting} +\end{frame} + +\begin{frame}[containsverbatim,plain] + \frametitle{Final Trace} +\begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] +$map_1$ = $inst_1$.map +guard($map_1$ == 0xb74af4a8) +$storage_1$ = $inst_1$.storage +$result_1$ = $storage_1$[$0$] +$result_2$ = $storage_2$[$1$] +$v_1$ = $result_1$ + $result_2$ +\end{lstlisting} +\end{frame} + + +\begin{frame} + \frametitle{Uses of These Hints} + \begin{block}{\texttt{promote} lets one specialize on various things:} + \begin{itemize} + \item user-level types + \item shapes of instances + \item the current state of a classes' methods + \item ... + \end{itemize} + \end{block} + \pause + \begin{block}{uses of \texttt{@elidable}} + \begin{itemize} + \item define immutable fields by decorating a getter + \item declare arbitrary invariants + \end{itemize} + + \end{block} +\end{frame} + +\begin{frame} + \frametitle{Some Benchmarks} + \begin{itemize} + \item benchmarks done using PyPy's Python interpreter + \item about 30'000 lines of code + \item 20 calls to \texttt{promote} + \item 10 applications of \texttt{@elidable} + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Some Benchmarks} + \includegraphics[scale=0.5]{figures/bench.pdf} +\end{frame} + +\begin{frame} + \frametitle{Conclusion} + \begin{itemize} + \item meta-tracing can make the efficient implementation of complex dynamic languages easier + \item only requires to write a correct interpreter + \item two kinds of hints to be added by the interpreter author allow arbitrary runtime feedback and its exploitation + \item the hints are expressive enough to re-implement classical optimizations such as maps + \item usage of the hints leads to good speedups for object-oriented code in PyPy's Python interpreter + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Bonus: Comparison with Partial Evaluation} + \begin{itemize} + \pause + \item the only difference between meta-tracing and partial evaluation is that meta-tracing works + \pause + \item ... mostly kidding + \pause + \item very similar from the motivation and ideas + \item PE was never scaled up to perform well on large interpreters + \item classical PE mostly ahead of time + \item PE tried very carefully to select the right paths to inline and optimize + \item quite often this fails and inlines too much or too little + \item tracing is much more pragmatic: simply look what happens + \end{itemize} +\end{frame} + + +\end{document} From noreply at buildbot.pypy.org Fri Jul 29 16:38:02 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Fri, 29 Jul 2011 16:38:02 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: draft of the blog post about pypy success stories Message-ID: <20110729143802.4771582112@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: extradoc Changeset: r3845:a3012a09e298 Date: 2011-07-29 16:38 +0200 http://bitbucket.org/pypy/extradoc/changeset/a3012a09e298/ Log: draft of the blog post about pypy success stories diff --git a/blog/draft/success_stories.rst b/blog/draft/success_stories.rst new file mode 100644 --- /dev/null +++ b/blog/draft/success_stories.rst @@ -0,0 +1,43 @@ +PyPy success stories +==================== + +Regular readers of this blog know the great progresses that PyPy achieved in +the past few years in terms of speed_, stability, and adoption. + +All of this has been made possibile thanks to the help of the Open Source +community, but also thanks to the `Eurostars programme`_, which let some of us +core developers to work full time on PyPy for the past two years. (XXX: is it +correct? Feel free to expand this section to explain better what it is) + +Our participation to Eurostars is ending in August, and at the moment we are +exploring several different ways of funding PyPy through other sources. We +will write more about that in the next days. During this process, it is +important to show that PyPy has stopped to be "just" a research project, but +that it is also a robust and solid solution for industries. + +We would like to write a "PyPy success stories" list, and thus we ask for your +help: + + - if you are already using PyPy in production; + + - if you are actively testing PyPy on your codebase; + + - or even if you are simply considering switching to PyPy and experimenting with it; + +in those cases, please let us know about it. We would like to know which +company you work for, what are you using PyPy for, and why you decided to +switch to it. Ideally, we would like the permission to publish these +informations and share it with the public. + +If for any reason you cannot or do not want to make them public, we are still +interested to hear about it. In that case, don't hesitate to contact us +privately, we will not publish your data. + +At your preference, you can write the information directly as a comment of +this blog post, by writing an email to the `pypy-dev`_ mailing list or by +writing a private email to me (`Antonio Cuni`_) or `Laura Creighton`_. (XXX: I +don't like too much the way I wrote this sentence, feel free to rephrase it) + +We hope to hear about lots of PyPy success stories. Remind that the more of +them we collect, the easier for us to find sponsors to fund further +development of PyPy! From noreply at buildbot.pypy.org Fri Jul 29 17:01:03 2011 From: noreply at buildbot.pypy.org (cfbolz) Date: Fri, 29 Jul 2011 17:01:03 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: this is done, no? Message-ID: <20110729150103.6CF6182110@wyvern.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: extradoc Changeset: r3846:61b1a3e7522c Date: 2011-07-29 17:01 +0100 http://bitbucket.org/pypy/extradoc/changeset/61b1a3e7522c/ Log: this is done, no? diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -192,5 +192,3 @@ - Movinging loop-invariant setitems out of the loops entierly. - - Better support for generators (I red some irc log about inlining them into - their parent frames) From noreply at buildbot.pypy.org Fri Jul 29 18:38:00 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 18:38:00 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Unroll another function if the arg is constant. Message-ID: <20110729163800.22DA082110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46089:85c61453ca2f Date: 2011-07-29 09:38 -0700 http://bitbucket.org/pypy/pypy/changeset/85c61453ca2f/ Log: Unroll another function if the arg is constant. diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -4,7 +4,7 @@ from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs from pypy.rlib.debug import ll_assert -from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside +from pypy.rlib import jit from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -58,7 +58,7 @@ llmemory.sizeof(CHAR_TP) * item) # It'd be nice to be able to look inside this function. - @dont_look_inside + @jit.dont_look_inside @enforceargs(None, None, int, int, int) def copy_string_contents(src, dst, srcstart, dststart, length): assert srcstart >= 0 @@ -144,7 +144,7 @@ self.ll = LLHelpers self.malloc = mallocunicode - @elidable + @jit.elidable def ll_str(self, s): # XXX crazy that this is here, but I don't want to break # rmodel logic @@ -159,7 +159,7 @@ result.chars[i] = cast_primitive(Char, c) return result - @elidable + @jit.elidable def ll_encode_latin1(self, s): length = len(s.chars) result = mallocstr(length) @@ -258,7 +258,7 @@ class LLHelpers(AbstractLLHelpers): - @elidable + @jit.elidable def ll_str_mul(s, times): if times < 0: times = 0 @@ -280,7 +280,7 @@ i += j return newstr - @elidable + @jit.elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr @@ -325,7 +325,7 @@ return s ll_str2unicode.oopspec = 'str.str2unicode(str)' - @elidable + @jit.elidable def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the @@ -341,7 +341,7 @@ def ll_strfasthash(s): return s.hash # assumes that the hash is already computed - @elidable + @jit.elidable def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -351,7 +351,7 @@ return newstr ll_strconcat.oopspec = 'stroruni.concat(s1, s2)' - @elidable + @jit.elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: @@ -369,7 +369,7 @@ s.copy_contents(s, result, lpos, 0, r_len) return result - @elidable + @jit.elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) @@ -386,7 +386,7 @@ i += 1 return result - @elidable + @jit.elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) @@ -427,7 +427,7 @@ i += 1 return result - @elidable + @jit.elidable def ll_strcmp(s1, s2): if not s1 and not s2: return True @@ -450,7 +450,7 @@ i += 1 return len1 - len2 - @elidable + @jit.elidable def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True @@ -470,7 +470,7 @@ return True ll_streq.oopspec = 'stroruni.equal(s1, s2)' - @elidable + @jit.elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -491,7 +491,7 @@ return False return s.chars[0] == ch - @elidable + @jit.elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) @@ -513,7 +513,7 @@ return False return s.chars[len(s.chars) - 1] == ch - @elidable + @jit.elidable def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): @@ -525,7 +525,7 @@ return -1 ll_find_char._annenforceargs_ = [None, None, int, int] - @elidable + @jit.elidable def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) @@ -536,7 +536,7 @@ return i return -1 - @elidable + @jit.elidable def ll_count_char(s, ch, start, end): count = 0 i = start @@ -604,7 +604,7 @@ res = 0 return res - @elidable + @jit.elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start @@ -683,6 +683,8 @@ return -1 return count + @jit.unroll_if(lambda length, items: jit.isconstant(length) and length <= 2) + @enforceargs(int, None) def ll_join_strs(length, items): num_items = length itemslen = 0 @@ -707,7 +709,6 @@ res_index += item_len i += 1 return result - ll_join_strs._annenforceargs_ = [int, None] def ll_join_chars(length, chars, RES): # no need to optimize this, will be replaced by string builder @@ -727,7 +728,7 @@ i += 1 return result - @elidable + @jit.elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 @@ -742,7 +743,7 @@ return LLHelpers._ll_stringslice(s1, start, len(s1.chars)) def ll_stringslice_startstop(s1, start, stop): - if we_are_jitted(): + if jit.we_are_jitted(): if stop > len(s1.chars): stop = len(s1.chars) else: @@ -825,7 +826,7 @@ item.copy_contents(s, item, j, 0, i - j) return res - @elidable + @jit.elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) @@ -840,7 +841,7 @@ j += 1 return newstr - @elidable + @jit.elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) @@ -851,7 +852,7 @@ i += 1 return False - @elidable + @jit.elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError From noreply at buildbot.pypy.org Fri Jul 29 19:51:35 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 19:51:35 +0200 (CEST) Subject: [pypy-commit] pypy default: hash_w is a bit prettier. Message-ID: <20110729175135.AE51E82110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46090:3431a63b8581 Date: 2011-07-28 17:48 -0700 http://bitbucket.org/pypy/pypy/changeset/3431a63b8581/ Log: hash_w is a bit prettier. diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -154,7 +154,7 @@ x = 0x345678 z = len(wrappeditems) for w_item in wrappeditems: - y = space.int_w(space.hash(w_item)) + y = space.hash_w(w_item) x = (x ^ y) * mult z -= 1 mult += 82520 + z + z From noreply at buildbot.pypy.org Fri Jul 29 19:51:36 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 19:51:36 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20110729175136.E8B6682110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46091:17974b065704 Date: 2011-07-28 17:48 -0700 http://bitbucket.org/pypy/pypy/changeset/17974b065704/ Log: merged upstream diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -31,6 +31,9 @@ 'sin': 'interp_ufuncs.sin', 'cos': 'interp_ufuncs.cos', 'tan': 'interp_ufuncs.tan', + 'arcsin': 'interp_ufuncs.arcsin', + 'arccos': 'interp_ufuncs.arccos', + 'arctan': 'interp_ufuncs.arctan', } appleveldefs = { diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -120,3 +120,20 @@ @ufunc2 def mod(lvalue, rvalue): return math.fmod(lvalue, rvalue) + + + at ufunc +def arcsin(value): + if value < -1.0 or value > 1.0: + return rfloat.NAN + return math.asin(value) + + at ufunc +def arccos(value): + if value < -1.0 or value > 1.0: + return rfloat.NAN + return math.acos(value) + + at ufunc +def arctan(value): + return math.atan(value) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -205,3 +205,47 @@ b = tan(a) for i in range(len(a)): assert b[i] == math.tan(a[i]) + + + def test_arcsin(self): + import math + from numpy import array, arcsin + + a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1]) + b = arcsin(a) + for i in range(len(a)): + assert b[i] == math.asin(a[i]) + + a = array([-10, -1.5, -1.01, 1.01, 1.5, 10, float('nan'), float('inf'), float('-inf')]) + b = arcsin(a) + for f in b: + assert math.isnan(f) + + def test_arccos(self): + import math + from numpy import array, arccos + + a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1]) + b = arccos(a) + for i in range(len(a)): + assert b[i] == math.acos(a[i]) + + + a = array([-10, -1.5, -1.01, 1.01, 1.5, 10, float('nan'), float('inf'), float('-inf')]) + b = arccos(a) + for f in b: + assert math.isnan(f) + + def test_arctan(self): + import math + from numpy import array, arctan + + a = array([-3, -2, -1, 0, 1, 2, 3, float('inf'), float('-inf')]) + b = arctan(a) + for i in range(len(a)): + assert b[i] == math.atan(a[i]) + + a = array([float('nan')]) + b = arctan(a) + assert math.isnan(b[0]) + From noreply at buildbot.pypy.org Fri Jul 29 19:51:38 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 19:51:38 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream. Message-ID: <20110729175138.3A73282110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r46092:ffbcbca32e2b Date: 2011-07-29 10:51 -0700 http://bitbucket.org/pypy/pypy/changeset/ffbcbca32e2b/ Log: merged upstream. diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -187,17 +187,17 @@ def _getnums(self, comma): if self.find_size() > 1000: nums = [ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(3) ] nums.append("..." + "," * comma) nums.extend([ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(self.find_size() - 3, self.find_size()) ]) else: nums = [ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(self.find_size()) ] return nums @@ -229,7 +229,7 @@ start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) if step == 0: # Single index - return space.wrap(self.get_concrete().getitem(start)) + return space.wrap(self.get_concrete().eval(start)) else: # Slice res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) @@ -416,14 +416,12 @@ # in fact, ViewArray never gets "concrete" as it never stores data. # This implementation is needed for BaseArray getitem/setitem to work, # can be refactored. + self.parent.get_concrete() return self def eval(self, i): return self.parent.eval(self.calc_index(i)) - def getitem(self, item): - return self.parent.getitem(self.calc_index(item)) - @unwrap_spec(item=int, value=float) def setitem(self, item, value): return self.parent.setitem(self.calc_index(item), value) @@ -497,9 +495,6 @@ def descr_len(self, space): return space.wrap(self.size) - def getitem(self, item): - return self.storage[item] - def setitem(self, item, value): self.invalidated() self.storage[item] = value diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -70,6 +70,7 @@ from numpy import array, zeros a = array(range(5)) assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + assert str((2*a)[:]) == "[0.0 2.0 4.0 6.0 8.0]" a = zeros(1001) assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -63,6 +63,7 @@ i7 = int_gt(i4, 1) guard_true(i7, descr=...) p9 = call(ConstClass(fromint), i4, descr=...) + guard_no_exception(descr=...) p11 = call(ConstClass(rbigint.mul), p5, p9, descr=...) guard_no_exception(descr=...) i13 = int_sub(i4, 1) diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -1100,9 +1100,9 @@ if (Double.isNaN(x)) return interlink.recordFloatSigned(x, 0); - // Infinity: Python throws exception + // Infinity: Python returns (inf, 0) if (Double.isInfinite(x)) - interlink.throwOverflowError(); + return interlink.recordFloatSigned(x, 0); // Extract the various parts of the format: final long e=11, f=52; // number of bits in IEEE format From noreply at buildbot.pypy.org Fri Jul 29 21:01:34 2011 From: noreply at buildbot.pypy.org (lac) Date: Fri, 29 Jul 2011 21:01:34 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: English, rephrasing, and add that if they want to sponsor pypy they should contact us about that as well. Message-ID: <20110729190134.3ECBD82110@wyvern.cs.uni-duesseldorf.de> Author: Laura Creighton Branch: extradoc Changeset: r3847:33af871e13d6 Date: 2011-07-29 20:56 +0200 http://bitbucket.org/pypy/extradoc/changeset/33af871e13d6/ Log: English, rephrasing, and add that if they want to sponsor pypy they should contact us about that as well. diff --git a/blog/draft/success_stories.rst b/blog/draft/success_stories.rst --- a/blog/draft/success_stories.rst +++ b/blog/draft/success_stories.rst @@ -6,16 +6,15 @@ All of this has been made possibile thanks to the help of the Open Source community, but also thanks to the `Eurostars programme`_, which let some of us -core developers to work full time on PyPy for the past two years. (XXX: is it -correct? Feel free to expand this section to explain better what it is) +core developers work full time on PyPy for the past two years. Our participation to Eurostars is ending in August, and at the moment we are exploring several different ways of funding PyPy through other sources. We will write more about that in the next days. During this process, it is -important to show that PyPy has stopped to be "just" a research project, but -that it is also a robust and solid solution for industries. +important to show that PyPy has stopped being "just" a research project, but +that it is also a robust and solid solution for industry. -We would like to write a "PyPy success stories" list, and thus we ask for your +We would like to write a list of "PyPy success stories", and thus we ask for your help: - if you are already using PyPy in production; @@ -26,18 +25,26 @@ in those cases, please let us know about it. We would like to know which company you work for, what are you using PyPy for, and why you decided to -switch to it. Ideally, we would like the permission to publish these -informations and share it with the public. +switch to it. Ideally, we would like the permission to publish this +information and share it with the public. -If for any reason you cannot or do not want to make them public, we are still -interested to hear about it. In that case, don't hesitate to contact us -privately, we will not publish your data. +If for any reason you cannot or do not want to make this public, we are still +interested in hearing about you. In that case, don't hesitate to contact us +privately - we will not publish your data. But we have potential sponsors +who are intersted in supporting PyPy, and showing them a list of companies +that are using PyPy (+ 3 anonymous ones in the financial services sector) is +almost as good as showing them a list with all the company names filled in. +What they are looking for is evidence that PyPy is not a research toy, but +of actual use to industry. -At your preference, you can write the information directly as a comment of -this blog post, by writing an email to the `pypy-dev`_ mailing list or by -writing a private email to me (`Antonio Cuni`_) or `Laura Creighton`_. (XXX: I -don't like too much the way I wrote this sentence, feel free to rephrase it) +Please take the time to respond either as a comment to this blog post +directly, or byt sending email to the `pypy-dev`_ mailing list or by +writing a private email to me (`Antonio Cuni`_) or `Laura Creighton`_. We hope to hear about lots of PyPy success stories. Remind that the more of them we collect, the easier for us to find sponsors to fund further -development of PyPy! +development of PyPy! And, of course, if any of you are interested in +_becoming_ one of these sponsors, we would like to hear about that, as well. + +Thanks very much (in advance) for all your help, +Laura and Anto (for the entire PyPy team) From noreply at buildbot.pypy.org Fri Jul 29 21:01:35 2011 From: noreply at buildbot.pypy.org (lac) Date: Fri, 29 Jul 2011 21:01:35 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: add link for Eurostars, reword it slightly. Message-ID: <20110729190135.5D1A082110@wyvern.cs.uni-duesseldorf.de> Author: Laura Creighton Branch: extradoc Changeset: r3848:f52a50ef0fb3 Date: 2011-07-29 21:01 +0200 http://bitbucket.org/pypy/extradoc/changeset/f52a50ef0fb3/ Log: add link for Eurostars, reword it slightly. diff --git a/blog/draft/success_stories.rst b/blog/draft/success_stories.rst --- a/blog/draft/success_stories.rst +++ b/blog/draft/success_stories.rst @@ -5,7 +5,8 @@ the past few years in terms of speed_, stability, and adoption. All of this has been made possibile thanks to the help of the Open Source -community, but also thanks to the `Eurostars programme`_, which let some of us +community, but also thanks to the German and Swedish governments, which +funded us through the `Eurostars programme`_. This let some of us core developers work full time on PyPy for the past two years. Our participation to Eurostars is ending in August, and at the moment we are @@ -48,3 +49,5 @@ Thanks very much (in advance) for all your help, Laura and Anto (for the entire PyPy team) + +_`Eurostars programme` : http://www.eurostars-eureka.eu/ \ No newline at end of file From noreply at buildbot.pypy.org Fri Jul 29 21:10:52 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 29 Jul 2011 21:10:52 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Test and fix. Message-ID: <20110729191052.DB48A82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46093:0bd0ef88fb4e Date: 2011-07-29 19:42 +0200 http://bitbucket.org/pypy/pypy/changeset/0bd0ef88fb4e/ Log: Test and fix. diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py --- a/pypy/jit/metainterp/test/test_warmstate.py +++ b/pypy/jit/metainterp/test/test_warmstate.py @@ -43,9 +43,12 @@ assert _is(wrap(None, p, in_const_box=True), ConstPtr(po)) if longlong.supports_longlong: import sys - value = longlong.r_float_storage(sys.maxint*17) + from pypy.rlib.rarithmetic import r_longlong, r_ulonglong + value = r_longlong(-sys.maxint*17) assert _is(wrap(None, value), BoxFloat(value)) assert _is(wrap(None, value, in_const_box=True), ConstFloat(value)) + value_unsigned = r_ulonglong(-sys.maxint*17) + assert _is(wrap(None, value_unsigned), BoxFloat(value)) sfval = r_singlefloat(42.5) ival = longlong.singlefloat2int(sfval) assert _is(wrap(None, sfval), BoxInt(ival)) diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py --- a/pypy/jit/metainterp/warmstate.py +++ b/pypy/jit/metainterp/warmstate.py @@ -92,6 +92,8 @@ longlong.is_longlong(lltype.typeOf(value))): if isinstance(value, float): value = longlong.getfloatstorage(value) + else: + value = rffi.cast(lltype.SignedLongLong, value) if in_const_box: return history.ConstFloat(value) else: From noreply at buildbot.pypy.org Fri Jul 29 21:10:54 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 29 Jul 2011 21:10:54 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Fix. Message-ID: <20110729191054.160F482110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46094:1c1ee144338b Date: 2011-07-29 19:43 +0200 http://bitbucket.org/pypy/pypy/changeset/1c1ee144338b/ Log: Fix. diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py --- a/pypy/rlib/libffi.py +++ b/pypy/rlib/libffi.py @@ -122,6 +122,7 @@ cls = FloatArg elif TYPE is rffi.LONGLONG or TYPE is rffi.ULONGLONG: cls = LongLongArg + val = rffi.cast(rffi.LONGLONG, val) elif TYPE is rffi.FLOAT: cls = SingleFloatArg else: From noreply at buildbot.pypy.org Fri Jul 29 21:10:55 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 29 Jul 2011 21:10:55 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Fixes. Message-ID: <20110729191055.4F30682110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46095:7e43eb0ad5c9 Date: 2011-07-29 20:41 +0200 http://bitbucket.org/pypy/pypy/changeset/7e43eb0ad5c9/ Log: Fixes. diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -1494,6 +1494,7 @@ 'i': lltype.Signed, 'f': lltype.Float, 'L': lltype.SignedLongLong, + 'S': lltype.SingleFloat, 'v': lltype.Void, } diff --git a/pypy/jit/codewriter/assembler.py b/pypy/jit/codewriter/assembler.py --- a/pypy/jit/codewriter/assembler.py +++ b/pypy/jit/codewriter/assembler.py @@ -76,6 +76,8 @@ TYPE = llmemory.Address if TYPE == llmemory.Address: value = heaptracker.adr2int(value) + if TYPE is lltype.SingleFloat: + value = longlong.singlefloat2int(value) if not isinstance(value, (llmemory.AddressAsInt, ComputedIntSymbolic)): value = lltype.cast_primitive(lltype.Signed, value) diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -16,18 +16,7 @@ # ===> ../../../rlib/test/test_libffi.py - def check_loops_if_supported(self, *args, **kwds): - if self.supports_all: - self.check_loops(*args, **kwds) - else: - self.check_loops({'call': 1, - 'guard_no_exception': 1, - 'int_add': 1, - 'int_lt': 1, - 'guard_true': 1, - 'jump': 1}) - - def call(self, funcspec, args, RESULT, is_struct=False): + def call(self, funcspec, args, RESULT, is_struct=False, jitif=[]): """ Call the function specified by funcspec in a loop, and let the jit to see and optimize it. @@ -72,8 +61,30 @@ res = self.meta_interp(f, [0], backendopt=True, supports_floats = self.supports_all, supports_longlong = self.supports_all, - supports_singlefloats = False) # XXX self.supports_all) - # the calls to check_loops() are in pypy.rlib.test.test_libffi + supports_singlefloats = self.supports_all) + d = {'floats': self.supports_all, + 'longlong': self.supports_all, + 'singlefloats': self.supports_all, + 'byval': False} + supported = all(d[check] for check in jitif) + if supported: + self.check_loops( + call_release_gil=1, # a CALL_RELEASE_GIL, and no other CALLs + call=0, + call_may_force=0, + guard_no_exception=1, + guard_not_forced=1, + int_add=1, + int_lt=1, + guard_true=1, + jump=1) + else: + self.check_loops( + call_release_gil=0, # no CALL_RELEASE_GIL + int_add=1, + int_lt=1, + guard_true=1, + jump=1) return res def test_byval_result(self): diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py --- a/pypy/rlib/rarithmetic.py +++ b/pypy/rlib/rarithmetic.py @@ -71,9 +71,8 @@ return int(n) def longlongmask(n): - if isinstance(n, int): - n = long(n) - assert isinstance(n, long) + assert isinstance(n, (int, long)) + n = long(n) n &= LONGLONG_MASK if n >= LONGLONG_TEST: n -= 2*LONGLONG_TEST diff --git a/pypy/rlib/test/test_libffi.py b/pypy/rlib/test/test_libffi.py --- a/pypy/rlib/test/test_libffi.py +++ b/pypy/rlib/test/test_libffi.py @@ -98,7 +98,7 @@ def get_libfoo(self): return self.CDLL(self.libfoo_name) - def call(self, funcspec, args, RESULT, is_struct=False): + def call(self, funcspec, args, RESULT, is_struct=False, jitif=[]): """ Call the specified function after constructing and ArgChain with the arguments in ``args``. @@ -123,19 +123,6 @@ chain.arg(arg) return func.call(chain, RESULT, is_struct=is_struct) - def check_loops(self, *args, **kwds): - """ - Ignored here, but does something in the JIT tests - """ - pass - - def check_loops_if_supported(self, *args, **kwds): - """ - Same as check_loops(), but only if support for - float/longlong/singlefloat has been enabled - """ - pass - # ------------------------------------------------------------------------ def test_very_simple(self): @@ -149,14 +136,6 @@ func = (libfoo, 'diff_xy', [types.sint, types.slong], types.sint) res = self.call(func, [50, 8], lltype.Signed) assert res == 42 - self.check_loops({ - 'call_release_gil': 1, - 'guard_no_exception': 1, - 'guard_not_forced': 1, - 'int_add': 1, - 'int_lt': 1, - 'guard_true': 1, - 'jump': 1}) def test_simple(self): """ @@ -167,25 +146,14 @@ """ libfoo = self.get_libfoo() func = (libfoo, 'sum_xy', [types.sint, types.double], types.sint) - res = self.call(func, [38, 4.2], lltype.Signed) + res = self.call(func, [38, 4.2], lltype.Signed, jitif=["floats"]) assert res == 42 - self.check_loops_if_supported({ - 'call_release_gil': 1, - 'guard_no_exception': 1, - 'guard_not_forced': 1, - 'int_add': 1, - 'int_lt': 1, - 'guard_true': 1, - 'jump': 1}) def test_float_result(self): libm = self.get_libm() func = (libm, 'pow', [types.double, types.double], types.double) - res = self.call(func, [2.0, 3.0], rffi.DOUBLE) + res = self.call(func, [2.0, 3.0], rffi.DOUBLE, jitif=["floats"]) assert res == 8.0 - self.check_loops_if_supported(call_release_gil=1, - guard_no_exception=1, - guard_not_forced=1) def test_cast_result(self): """ @@ -198,7 +166,6 @@ func = (libfoo, 'cast_to_uchar_and_ovf', [types.sint], types.uchar) res = self.call(func, [0], rffi.UCHAR) assert res == 200 - self.check_loops(call_release_gil=1, guard_no_exception=1, guard_not_forced=1) def test_cast_argument(self): """ @@ -313,10 +280,9 @@ func = (libfoo, 'sum_xy_float', [types.float, types.float], types.float) x = r_singlefloat(12.34) y = r_singlefloat(56.78) - res = self.call(func, [x, y], rffi.FLOAT) + res = self.call(func, [x, y], rffi.FLOAT, jitif=["singlefloats"]) expected = c_float(c_float(12.34).value + c_float(56.78).value).value assert float(res) == expected - self.check_loops_if_supported({}) def test_slonglong_args(self): """ @@ -337,12 +303,9 @@ else: x = maxint32+1 y = maxint32+2 - res = self.call(func, [x, y], rffi.LONGLONG) + res = self.call(func, [x, y], rffi.LONGLONG, jitif=["longlong"]) expected = maxint32*2 + 3 assert res == expected - self.check_loops_if_supported(call_release_gil=1, - guard_no_exception=1, - guard_not_forced=1) def test_ulonglong_args(self): """ @@ -360,7 +323,7 @@ types.ulonglong) x = r_ulonglong(maxint64+1) y = r_ulonglong(2) - res = self.call(func, [x, y], rffi.ULONGLONG) + res = self.call(func, [x, y], rffi.ULONGLONG, jitif=["longlong"]) expected = maxint64 + 3 assert res == expected @@ -407,7 +370,8 @@ buf[0] = 30 buf[1] = 12 adr = rffi.cast(rffi.VOIDP, buf) - res = self.call(sum_point, [('arg_raw', adr)], rffi.LONG) + res = self.call(sum_point, [('arg_raw', adr)], rffi.LONG, + jitif=["byval"]) assert res == 42 # check that we still have the ownership on the buffer assert buf[0] == 30 @@ -432,7 +396,8 @@ make_point = (libfoo, 'make_point', [types.slong, types.slong], ffi_point) # PTR = lltype.Ptr(rffi.CArray(rffi.LONG)) - p = self.call(make_point, [12, 34], PTR, is_struct=True) + p = self.call(make_point, [12, 34], PTR, is_struct=True, + jitif=["byval"]) assert p[0] == 12 assert p[1] == 34 lltype.free(p, flavor='raw') diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -1,7 +1,7 @@ import py from pypy.rlib.rarithmetic import (r_int, r_uint, intmask, r_singlefloat, r_ulonglong, r_longlong, r_longfloat, - base_int, normalizedinttype) + base_int, normalizedinttype, longlongmask) from pypy.rlib.objectmodel import Symbolic from pypy.tool.uid import Hashable from pypy.tool.identity_dict import identity_dict @@ -654,6 +654,9 @@ _numbertypes = {int: Number("Signed", int, intmask)} _numbertypes[r_int] = _numbertypes[int] +if r_longlong is not r_int: + _numbertypes[r_longlong] = Number("SignedLongLong", r_longlong, + longlongmask) def build_number(name, type): try: From noreply at buildbot.pypy.org Fri Jul 29 21:10:56 2011 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 29 Jul 2011 21:10:56 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Fix on 64-bit. Message-ID: <20110729191056.7FB0C82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46096:dead3650d9af Date: 2011-07-29 20:44 +0200 http://bitbucket.org/pypy/pypy/changeset/dead3650d9af/ Log: Fix on 64-bit. diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py --- a/pypy/jit/metainterp/test/test_fficall.py +++ b/pypy/jit/metainterp/test/test_fficall.py @@ -63,7 +63,7 @@ supports_longlong = self.supports_all, supports_singlefloats = self.supports_all) d = {'floats': self.supports_all, - 'longlong': self.supports_all, + 'longlong': self.supports_all or not IS_32_BIT, 'singlefloats': self.supports_all, 'byval': False} supported = all(d[check] for check in jitif) From noreply at buildbot.pypy.org Fri Jul 29 21:17:43 2011 From: noreply at buildbot.pypy.org (gutworth) Date: Fri, 29 Jul 2011 21:17:43 +0200 (CEST) Subject: [pypy-commit] pypy default: refactor to not increment two counters Message-ID: <20110729191743.3B2A482110@wyvern.cs.uni-duesseldorf.de> Author: Benjamin Peterson Branch: Changeset: r46097:54515dec1d20 Date: 2011-07-29 14:17 -0500 http://bitbucket.org/pypy/pypy/changeset/54515dec1d20/ Log: refactor to not increment two counters diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py --- a/pypy/rpython/lltypesystem/rbuilder.py +++ b/pypy/rpython/lltypesystem/rbuilder.py @@ -93,23 +93,21 @@ @staticmethod def ll_append_multiple_char(ll_builder, char, times): - used = ll_builder.used - if times + used > ll_builder.allocated: + use = ll_builder.used + times + if use > ll_builder.allocated: ll_builder.grow(ll_builder, times) - for i in range(times): - ll_builder.buf.chars[used] = char - used += 1 - ll_builder.used = used + for i in range(ll_builder.used, use): + ll_builder.buf.chars[i] = char + ll_builder.used = use @staticmethod def ll_append_charpsize(ll_builder, charp, size): - used = ll_builder.used - if used + size > ll_builder.allocated: + use = ll_builder.used + size + if use > ll_builder.allocated: ll_builder.grow(ll_builder, size) - for i in xrange(size): - ll_builder.buf.chars[used] = charp[i] - used += 1 - ll_builder.used = used + for i in xrange(ll_builder.used, use): + ll_builder.buf.chars[i] = charp[i] + ll_builder.used = use @staticmethod def ll_getlength(ll_builder): From noreply at buildbot.pypy.org Fri Jul 29 23:36:50 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 29 Jul 2011 23:36:50 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Generate COPY{STR, UNICODE}CONTENT resops for copy_{string, unicode}contents calls. And optimize away those ops which have lengthboxes of 0. Message-ID: <20110729213650.7202482110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46098:16f06b5f8a48 Date: 2011-07-29 14:37 -0700 http://bitbucket.org/pypy/pypy/changeset/16f06b5f8a48/ Log: Generate COPY{STR,UNICODE}CONTENT resops for copy_{string,unicode}contents calls. And optimize away those ops which have lengthboxes of 0. diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -496,6 +496,16 @@ u = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), string) u.chars[index] = unichr(newvalue) + def bh_copystrcontent(self, src, dst, srcstart, dststart, length): + src = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), src) + dst = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), dst) + rstr.copy_string_contents(src, dst, srcstart, dststart, length) + + def bh_copyunicodecontent(self, src, dst, srcstart, dststart, length): + src = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), src) + dst = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), dst) + rstr.copy_unicode_contents(src, dst, srcstart, dststart, length) + def bh_call_i(self, func, calldescr, args_i, args_r, args_f): assert isinstance(calldescr, BaseIntCallDescr) if not we_are_translated(): diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -1331,6 +1331,14 @@ else: assert 0, "args[0].concretetype must be STR or UNICODE" # + if oopspec_name == 'stroruni.copy_contents': + if SoU.TO == rstr.STR: + new_op = 'copystrcontent' + elif SoU.TO == rstr.UNICODE: + new_op = 'copyunicodecontent' + else: + assert 0 + return SpaceOperation(new_op, args, op.result) if oopspec_name == "stroruni.equal": for otherindex, othername, argtypes, resulttype in [ (EffectInfo.OS_STREQ_SLICE_CHECKNULL, diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -1216,6 +1216,9 @@ @arguments("cpu", "r", "i", "i") def bhimpl_strsetitem(cpu, string, index, newchr): cpu.bh_strsetitem(string, index, newchr) + @arguments("cpu", "r", "r", "i", "i", "i") + def bhimpl_copystrcontent(cpu, src, dst, srcstart, dststart, length): + cpu.bh_copystrcontent(src, dst, srcstart, dststart, length) @arguments("cpu", "i", returns="r") def bhimpl_newunicode(cpu, length): @@ -1229,6 +1232,9 @@ @arguments("cpu", "r", "i", "i") def bhimpl_unicodesetitem(cpu, unicode, index, newchr): cpu.bh_unicodesetitem(unicode, index, newchr) + @arguments("cpu", "r", "r", "i", "i", "i") + def bhimpl_copyunicodecontent(cpu, src, dst, srcstart, dststart, length): + cpu.bh_copyunicodecontent(src, dst, srcstart, dststart, length) @arguments(returns=(longlong.is_64_bit and "i" or "f")) def bhimpl_ll_read_timestamp(): diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4621,6 +4621,22 @@ """ self.optimize_strunicode_loop(ops, expected) + def test_empty_copystrunicontent(self): + ops = """ + [p0, p1, i0, i2, i3] + i4 = int_eq(i3, 0) + guard_true(i4) [] + copystrcontent(p0, p1, i0, i2, i3) + jump(p0, p1, i0, i2, i3) + """ + expected = """ + [p0, p1, i0, i2, i3] + i4 = int_eq(i3, 0) + guard_true(i4) [] + jump(p0, p1, i0, i2, 0) + """ + self.optimize_strunicode_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -296,7 +296,7 @@ def copy_str_content(optimizer, srcbox, targetbox, - srcoffsetbox, offsetbox, lengthbox, mode): + srcoffsetbox, offsetbox, lengthbox, mode, need_next_offset=True): if isinstance(srcbox, ConstPtr) and isinstance(srcoffsetbox, Const): M = 5 else: @@ -313,7 +313,10 @@ None)) offsetbox = _int_add(optimizer, offsetbox, CONST_1) else: - nextoffsetbox = _int_add(optimizer, offsetbox, lengthbox) + if need_next_offset: + nextoffsetbox = _int_add(optimizer, offsetbox, lengthbox) + else: + nextoffsetbox = None op = ResOperation(mode.COPYSTRCONTENT, [srcbox, targetbox, srcoffsetbox, offsetbox, lengthbox], None) @@ -451,6 +454,20 @@ lengthbox = value.getstrlen(self.optimizer, mode) self.make_equal_to(op.result, self.getvalue(lengthbox)) + def optimize_COPYSTRCONTENT(self, op): + self._optimize_COPYSTRCONTENT(op, mode_string) + def optimize_COPYUNICODECONTENT(self, op): + self._optimize_COPYSTRCONTENT(op, mode_unicode) + + def _optimize_COPYSTRCONTENT(self, op, mode): + # args: src dst srcstart dststart length + src = self.getvalue(op.getarg(0)) + dst = self.getvalue(op.getarg(1)) + srcstart = self.getvalue(op.getarg(2)) + dststart = self.getvalue(op.getarg(3)) + length = self.getvalue(op.getarg(4)) + copy_str_content(self.optimizer, src.box, dst.box, srcstart.box, dststart.box, length.box, mode, need_next_offset=False) + def optimize_CALL(self, op): # dispatch based on 'oopspecindex' to a method that handles # specifically the given oopspec call. For non-oopspec calls, diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -853,6 +853,14 @@ def opimpl_newunicode(self, lengthbox): return self.execute(rop.NEWUNICODE, lengthbox) + @arguments("box", "box", "box", "box", "box") + def opimpl_copystrcontent(self, srcbox, dstbox, srcstartbox, dststartbox, lengthbox): + return self.execute(rop.COPYSTRCONTENT, srcbox, dstbox, srcstartbox, dststartbox, lengthbox) + + @arguments("box", "box", "box", "box", "box") + def opimpl_copyunicodecontent(self, srcbox, dstbox, srcstartbox, dststartbox, lengthbox): + return self.execute(rop.COPYUNICODECONTENT, srcbox, dstbox, srcstartbox, dststartbox, lengthbox) + ## @FixME #arguments("descr", "varargs") ## def opimpl_residual_oosend_canraise(self, methdescr, varargs): ## return self.execute_varargs(rop.OOSEND, varargs, descr=methdescr, diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -68,8 +68,8 @@ dst = llmemory.cast_ptr_to_adr(dst) + _str_ofs(dststart) llmemory.raw_memcopy(src, dst, llmemory.sizeof(CHAR_TP) * length) copy_string_contents._always_inline_ = True - #copy_string_contents.oopspec = ( - # '%s.copy_contents(src, dst, srcstart, dststart, length)' % name) + copy_string_contents.oopspec = ( + 'stroruni.copy_contents(src, dst, srcstart, dststart, length)') return func_with_new_name(copy_string_contents, 'copy_%s_contents' % name) copy_string_contents = _new_copy_contents_fun(STR, Char, 'string') From noreply at buildbot.pypy.org Sat Jul 30 02:08:07 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 30 Jul 2011 02:08:07 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Builder.append_multiple_char can be unrolled if `times` is a Const. This causes a segfault, but it is in teh register allocator, so that needs to be debugged indepdently. Message-ID: <20110730000807.3EFED82110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46099:0047db5c6851 Date: 2011-07-29 17:08 -0700 http://bitbucket.org/pypy/pypy/changeset/0047db5c6851/ Log: Builder.append_multiple_char can be unrolled if `times` is a Const. This causes a segfault, but it is in teh register allocator, so that needs to be debugged indepdently. diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py --- a/pypy/rpython/lltypesystem/rbuilder.py +++ b/pypy/rpython/lltypesystem/rbuilder.py @@ -1,4 +1,4 @@ -from pypy.rlib import rgc +from pypy.rlib import rgc, jit from pypy.rlib.objectmodel import enforceargs from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.annlowlevel import llstr @@ -92,6 +92,7 @@ ll_builder.used = needed + used @staticmethod + @jit.unroll_if(lambda ll_builder, char, times: jit.isconstant(times) and times <= 4) def ll_append_multiple_char(ll_builder, char, times): used = ll_builder.used if times + used > ll_builder.allocated: From noreply at buildbot.pypy.org Sat Jul 30 06:05:10 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 30 Jul 2011 06:05:10 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: You can't just grab the box of a virtual, call force_box. NOTE: this causes a slight regression, strcopycontent now forces boht the src and dst boxes, even if the op will be eliminated because it is length 0. FIX THIS! Message-ID: <20110730040510.2680082110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46100:43844f5e9cdc Date: 2011-07-29 21:05 -0700 http://bitbucket.org/pypy/pypy/changeset/43844f5e9cdc/ Log: You can't just grab the box of a virtual, call force_box. NOTE: this causes a slight regression, strcopycontent now forces boht the src and dst boxes, even if the op will be eliminated because it is length 0. FIX THIS! diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -466,7 +466,14 @@ srcstart = self.getvalue(op.getarg(2)) dststart = self.getvalue(op.getarg(3)) length = self.getvalue(op.getarg(4)) - copy_str_content(self.optimizer, src.box, dst.box, srcstart.box, dststart.box, length.box, mode, need_next_offset=False) + copy_str_content(self.optimizer, + src.force_box(), + dst.force_box(), + srcstart.force_box(), + dststart.force_box(), + length.force_box(), + mode, need_next_offset=False + ) def optimize_CALL(self, op): # dispatch based on 'oopspecindex' to a method that handles From noreply at buildbot.pypy.org Sat Jul 30 08:20:03 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 30 Jul 2011 08:20:03 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Special case for length == 1 here, helps the non-jit case as well. Message-ID: <20110730062003.6C63082110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46101:e18517492237 Date: 2011-07-29 23:20 -0700 http://bitbucket.org/pypy/pypy/changeset/e18517492237/ Log: Special case for length == 1 here, helps the non-jit case as well. diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -686,6 +686,10 @@ @jit.unroll_if(lambda length, items: jit.isconstant(length) and length <= 2) @enforceargs(int, None) def ll_join_strs(length, items): + # Special case for length 1 items, helps both the JIT and other code + if length == 1: + return items[0] + num_items = length itemslen = 0 i = 0 From noreply at buildbot.pypy.org Sat Jul 30 08:20:04 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 30 Jul 2011 08:20:04 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Failing test, not sure how to fix it besides a special case :/ Message-ID: <20110730062004.9FF0382110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46102:0a65df43b4ab Date: 2011-07-29 23:20 -0700 http://bitbucket.org/pypy/pypy/changeset/0a65df43b4ab/ Log: Failing test, not sure how to fix it besides a special case :/ diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4637,6 +4637,19 @@ """ self.optimize_strunicode_loop(ops, expected) + def test_empty_copystrunicontent_virtual(self): + ops = """ + [p0] + p1 = newstr(23) + copystrcontent(p0, p1, 0, 0, 0) + jump(p0) + """ + expected = """ + [p0] + jump(p0) + """ + self.optimize_strunicode_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass From noreply at buildbot.pypy.org Sat Jul 30 09:05:05 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 30 Jul 2011 09:05:05 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: reflow the para Message-ID: <20110730070505.0F8FE82110@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3849:bbd09b6200d1 Date: 2011-07-30 09:05 +0200 http://bitbucket.org/pypy/extradoc/changeset/bbd09b6200d1/ Log: reflow the para diff --git a/blog/draft/success_stories.rst b/blog/draft/success_stories.rst --- a/blog/draft/success_stories.rst +++ b/blog/draft/success_stories.rst @@ -15,8 +15,8 @@ important to show that PyPy has stopped being "just" a research project, but that it is also a robust and solid solution for industry. -We would like to write a list of "PyPy success stories", and thus we ask for your -help: +We would like to write a list of "PyPy success stories", and thus we ask +for your help: - if you are already using PyPy in production; @@ -50,4 +50,4 @@ Thanks very much (in advance) for all your help, Laura and Anto (for the entire PyPy team) -_`Eurostars programme` : http://www.eurostars-eureka.eu/ \ No newline at end of file +_`Eurostars programme` : http://www.eurostars-eureka.eu/ From noreply at buildbot.pypy.org Sat Jul 30 10:36:18 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 30 Jul 2011 10:36:18 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Approprite special case here. Message-ID: <20110730083618.A5FBB82110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46103:a02e7bf45eb9 Date: 2011-07-30 01:36 -0700 http://bitbucket.org/pypy/pypy/changeset/a02e7bf45eb9/ Log: Approprite special case here. diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -466,6 +466,9 @@ srcstart = self.getvalue(op.getarg(2)) dststart = self.getvalue(op.getarg(3)) length = self.getvalue(op.getarg(4)) + + if length.is_constant() and length.box.getint() == 0: + return copy_str_content(self.optimizer, src.force_box(), dst.force_box(), From noreply at buildbot.pypy.org Sat Jul 30 10:53:50 2011 From: noreply at buildbot.pypy.org (antocuni) Date: Sat, 30 Jul 2011 10:53:50 +0200 (CEST) Subject: [pypy-commit] buildbot default: halt if translate.py fails (this was a leftover of some experiments); also, try to increase the number of available CPUs Message-ID: <20110730085350.4A41282110@wyvern.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: Changeset: r543:bdad3c3b23ef Date: 2011-07-30 10:54 +0200 http://bitbucket.org/pypy/buildbot/changeset/bdad3c3b23ef/ Log: halt if translate.py fails (this was a leftover of some experiments); also, try to increase the number of available CPUs diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py --- a/bot2/pypybuildbot/builds.py +++ b/bot2/pypybuildbot/builds.py @@ -18,7 +18,7 @@ # sequence. # there are 8 logical CPUs, but only 4 physical ones -TannitCPU = locks.MasterLock('tannit_cpu', maxCount=4) +TannitCPU = locks.MasterLock('tannit_cpu', maxCount=6) class ShellCmd(shell.ShellCommand): @@ -305,7 +305,7 @@ Translate( translationArgs=['-Ojit'], targetArgs=[], - haltOnFailure=False, + haltOnFailure=True, # this step can be executed in parallel with other builds locks=[TannitCPU.access('counting')], ) From noreply at buildbot.pypy.org Sat Jul 30 11:24:42 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 11:24:42 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Fixes. Message-ID: <20110730092442.5974482110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46104:f52a31bf5e6d Date: 2011-07-29 19:44 +0000 http://bitbucket.org/pypy/pypy/changeset/f52a31bf5e6d/ Log: Fixes. diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -1145,7 +1145,7 @@ del _future_values[:] def set_future_value_int(index, value): - assert type(value) is int + assert lltype.typeOf(value) is lltype.Signed set_future_value_ref(index, value) def set_future_value_float(index, value): diff --git a/pypy/jit/codewriter/longlong.py b/pypy/jit/codewriter/longlong.py --- a/pypy/jit/codewriter/longlong.py +++ b/pypy/jit/codewriter/longlong.py @@ -40,8 +40,8 @@ getfloatstorage = longlong2float.float2longlong getrealfloat = longlong2float.longlong2float gethash = lambda xll: rarithmetic.intmask(xll - (xll >> 32)) - is_longlong = lambda TYPE: (TYPE == lltype.SignedLongLong or - TYPE == lltype.UnsignedLongLong) + is_longlong = lambda TYPE: (TYPE is lltype.SignedLongLong or + TYPE is lltype.UnsignedLongLong) # ------------------------------------- From noreply at buildbot.pypy.org Sat Jul 30 11:24:43 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 11:24:43 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Clean up the structure and put everything about floats, longlongs and Message-ID: <20110730092443.8AA9D82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46105:3068909b06ca Date: 2011-07-30 11:06 +0200 http://bitbucket.org/pypy/pypy/changeset/3068909b06ca/ Log: Clean up the structure and put everything about floats, longlongs and singlefloats in subfunctions that can be disabled by the JIT's codewriter. diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -222,7 +222,7 @@ w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) elif w_argtype.is_double(): - argchain.arg(space.float_w(w_arg)) + self.arg_float(space, argchain, w_arg) elif w_argtype.is_singlefloat(): self.arg_singlefloat(space, argchain, w_arg) elif w_argtype.is_struct(): @@ -267,6 +267,11 @@ else: return w_arg + def arg_float(self, space, argchain, w_arg): + # a separate function, which can be seen by the jit or not, + # depending on whether floats are supported + argchain.arg(space.float_w(w_arg)) + def arg_longlong(self, space, argchain, w_arg): # a separate function, which can be seen by the jit or not, # depending on whether longlongs are supported @@ -274,7 +279,6 @@ ullval = bigarg.ulonglongmask() llval = rffi.cast(rffi.LONGLONG, ullval) argchain.arg(llval) - arg_longlong._dont_inline_ = True def arg_singlefloat(self, space, argchain, w_arg): # a separate function, which can be seen by the jit or not, @@ -283,7 +287,6 @@ fval = space.float_w(w_arg) sfval = r_singlefloat(fval) argchain.arg(sfval) - arg_singlefloat._dont_inline_ = True def call(self, space, args_w): self = jit.promote(self) @@ -304,8 +307,7 @@ # note that we must check for longlong first, because either # is_signed or is_unsigned returns true anyway assert libffi.IS_32_BIT - reskind = libffi.types.getkind(self.func.restype) # XXX: remove the kind - return self._call_longlong(space, argchain, reskind) + return self._call_longlong(space, argchain) elif w_restype.is_signed(): return self._call_int(space, argchain) elif w_restype.is_unsigned() or w_restype.is_pointer(): @@ -317,12 +319,9 @@ intres = self.func.call(argchain, rffi.WCHAR_T) return space.wrap(unichr(intres)) elif w_restype.is_double(): - floatres = self.func.call(argchain, rffi.DOUBLE) - return space.wrap(floatres) + return self._call_float(space, argchain) elif w_restype.is_singlefloat(): - # the result is a float, but widened to be inside a double - floatres = self.func.call(argchain, rffi.FLOAT) - return space.wrap(floatres) + return self._call_singlefloat(space, argchain) elif w_restype.is_struct(): w_datashape = w_restype.w_datashape assert isinstance(w_datashape, W_Structure) @@ -391,19 +390,32 @@ space.wrap('Unsupported restype')) return space.wrap(intres) - @jit.dont_look_inside - def _call_longlong(self, space, argchain, reskind): - # this is a hack: we store the 64 bits of the long long into the 64 - # bits of a float (i.e., a C double) - floatres = self.func.call(argchain, rffi.LONGLONG) - llres = libffi.float2longlong(floatres) - if reskind == 'I': + def _call_float(self, space, argchain): + # a separate function, which can be seen by the jit or not, + # depending on whether floats are supported + floatres = self.func.call(argchain, rffi.DOUBLE) + return space.wrap(floatres) + + def _call_longlong(self, space, argchain): + # a separate function, which can be seen by the jit or not, + # depending on whether longlongs are supported + restype = self.func.restype + call = self.func.call + if restype is libffi.types.slonglong: + llres = call(argchain, rffi.LONGLONG) return space.wrap(llres) - elif reskind == 'U': - ullres = rffi.cast(rffi.ULONGLONG, llres) + elif restype is libffi.types.ulonglong: + ullres = call(argchain, rffi.ULONGLONG) return space.wrap(ullres) else: - assert False + raise OperationError(space.w_ValueError, + space.wrap('Unsupported longlong restype')) + + def _call_singlefloat(self, space, argchain): + # a separate function, which can be seen by the jit or not, + # depending on whether singlefloats are supported + sfres = self.func.call(argchain, rffi.FLOAT) + return space.wrap(float(sfres)) def getaddr(self, space): """ From noreply at buildbot.pypy.org Sat Jul 30 11:24:44 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 11:24:44 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: merge heads Message-ID: <20110730092444.C0F5882110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46106:b1f3b4800080 Date: 2011-07-30 11:06 +0200 http://bitbucket.org/pypy/pypy/changeset/b1f3b4800080/ Log: merge heads diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -222,7 +222,7 @@ w_arg = space.ord(w_arg) argchain.arg(space.int_w(w_arg)) elif w_argtype.is_double(): - argchain.arg(space.float_w(w_arg)) + self.arg_float(space, argchain, w_arg) elif w_argtype.is_singlefloat(): self.arg_singlefloat(space, argchain, w_arg) elif w_argtype.is_struct(): @@ -267,6 +267,11 @@ else: return w_arg + def arg_float(self, space, argchain, w_arg): + # a separate function, which can be seen by the jit or not, + # depending on whether floats are supported + argchain.arg(space.float_w(w_arg)) + def arg_longlong(self, space, argchain, w_arg): # a separate function, which can be seen by the jit or not, # depending on whether longlongs are supported @@ -274,7 +279,6 @@ ullval = bigarg.ulonglongmask() llval = rffi.cast(rffi.LONGLONG, ullval) argchain.arg(llval) - arg_longlong._dont_inline_ = True def arg_singlefloat(self, space, argchain, w_arg): # a separate function, which can be seen by the jit or not, @@ -283,7 +287,6 @@ fval = space.float_w(w_arg) sfval = r_singlefloat(fval) argchain.arg(sfval) - arg_singlefloat._dont_inline_ = True def call(self, space, args_w): self = jit.promote(self) @@ -304,8 +307,7 @@ # note that we must check for longlong first, because either # is_signed or is_unsigned returns true anyway assert libffi.IS_32_BIT - reskind = libffi.types.getkind(self.func.restype) # XXX: remove the kind - return self._call_longlong(space, argchain, reskind) + return self._call_longlong(space, argchain) elif w_restype.is_signed(): return self._call_int(space, argchain) elif w_restype.is_unsigned() or w_restype.is_pointer(): @@ -317,12 +319,9 @@ intres = self.func.call(argchain, rffi.WCHAR_T) return space.wrap(unichr(intres)) elif w_restype.is_double(): - floatres = self.func.call(argchain, rffi.DOUBLE) - return space.wrap(floatres) + return self._call_float(space, argchain) elif w_restype.is_singlefloat(): - # the result is a float, but widened to be inside a double - floatres = self.func.call(argchain, rffi.FLOAT) - return space.wrap(floatres) + return self._call_singlefloat(space, argchain) elif w_restype.is_struct(): w_datashape = w_restype.w_datashape assert isinstance(w_datashape, W_Structure) @@ -391,19 +390,32 @@ space.wrap('Unsupported restype')) return space.wrap(intres) - @jit.dont_look_inside - def _call_longlong(self, space, argchain, reskind): - # this is a hack: we store the 64 bits of the long long into the 64 - # bits of a float (i.e., a C double) - floatres = self.func.call(argchain, rffi.LONGLONG) - llres = libffi.float2longlong(floatres) - if reskind == 'I': + def _call_float(self, space, argchain): + # a separate function, which can be seen by the jit or not, + # depending on whether floats are supported + floatres = self.func.call(argchain, rffi.DOUBLE) + return space.wrap(floatres) + + def _call_longlong(self, space, argchain): + # a separate function, which can be seen by the jit or not, + # depending on whether longlongs are supported + restype = self.func.restype + call = self.func.call + if restype is libffi.types.slonglong: + llres = call(argchain, rffi.LONGLONG) return space.wrap(llres) - elif reskind == 'U': - ullres = rffi.cast(rffi.ULONGLONG, llres) + elif restype is libffi.types.ulonglong: + ullres = call(argchain, rffi.ULONGLONG) return space.wrap(ullres) else: - assert False + raise OperationError(space.w_ValueError, + space.wrap('Unsupported longlong restype')) + + def _call_singlefloat(self, space, argchain): + # a separate function, which can be seen by the jit or not, + # depending on whether singlefloats are supported + sfres = self.func.call(argchain, rffi.FLOAT) + return space.wrap(float(sfres)) def getaddr(self, space): """ From noreply at buildbot.pypy.org Sat Jul 30 12:27:59 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 12:27:59 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: hg merge default Message-ID: <20110730102759.4053682110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46107:ffc16e8f8e6e Date: 2011-07-30 10:10 +0000 http://bitbucket.org/pypy/pypy/changeset/ffc16e8f8e6e/ Log: hg merge default diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -31,6 +31,9 @@ 'sin': 'interp_ufuncs.sin', 'cos': 'interp_ufuncs.cos', 'tan': 'interp_ufuncs.tan', + 'arcsin': 'interp_ufuncs.arcsin', + 'arccos': 'interp_ufuncs.arccos', + 'arctan': 'interp_ufuncs.arctan', } appleveldefs = { diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -187,17 +187,17 @@ def _getnums(self, comma): if self.find_size() > 1000: nums = [ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(3) ] nums.append("..." + "," * comma) nums.extend([ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(self.find_size() - 3, self.find_size()) ]) else: nums = [ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(self.find_size()) ] return nums @@ -229,7 +229,7 @@ start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) if step == 0: # Single index - return space.wrap(self.get_concrete().getitem(start)) + return space.wrap(self.get_concrete().eval(start)) else: # Slice res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) @@ -416,14 +416,12 @@ # in fact, ViewArray never gets "concrete" as it never stores data. # This implementation is needed for BaseArray getitem/setitem to work, # can be refactored. + self.parent.get_concrete() return self def eval(self, i): return self.parent.eval(self.calc_index(i)) - def getitem(self, item): - return self.parent.getitem(self.calc_index(item)) - @unwrap_spec(item=int, value=float) def setitem(self, item, value): return self.parent.setitem(self.calc_index(item), value) @@ -497,9 +495,6 @@ def descr_len(self, space): return space.wrap(self.size) - def getitem(self, item): - return self.storage[item] - def setitem(self, item, value): self.invalidated() self.storage[item] = value diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -120,3 +120,20 @@ @ufunc2 def mod(lvalue, rvalue): return math.fmod(lvalue, rvalue) + + + at ufunc +def arcsin(value): + if value < -1.0 or value > 1.0: + return rfloat.NAN + return math.asin(value) + + at ufunc +def arccos(value): + if value < -1.0 or value > 1.0: + return rfloat.NAN + return math.acos(value) + + at ufunc +def arctan(value): + return math.atan(value) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -70,6 +70,7 @@ from numpy import array, zeros a = array(range(5)) assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + assert str((2*a)[:]) == "[0.0 2.0 4.0 6.0 8.0]" a = zeros(1001) assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -205,3 +205,47 @@ b = tan(a) for i in range(len(a)): assert b[i] == math.tan(a[i]) + + + def test_arcsin(self): + import math + from numpy import array, arcsin + + a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1]) + b = arcsin(a) + for i in range(len(a)): + assert b[i] == math.asin(a[i]) + + a = array([-10, -1.5, -1.01, 1.01, 1.5, 10, float('nan'), float('inf'), float('-inf')]) + b = arcsin(a) + for f in b: + assert math.isnan(f) + + def test_arccos(self): + import math + from numpy import array, arccos + + a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1]) + b = arccos(a) + for i in range(len(a)): + assert b[i] == math.acos(a[i]) + + + a = array([-10, -1.5, -1.01, 1.01, 1.5, 10, float('nan'), float('inf'), float('-inf')]) + b = arccos(a) + for f in b: + assert math.isnan(f) + + def test_arctan(self): + import math + from numpy import array, arctan + + a = array([-3, -2, -1, 0, 1, 2, 3, float('inf'), float('-inf')]) + b = arctan(a) + for i in range(len(a)): + assert b[i] == math.atan(a[i]) + + a = array([float('nan')]) + b = arctan(a) + assert math.isnan(b[0]) + diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -63,6 +63,7 @@ i7 = int_gt(i4, 1) guard_true(i7, descr=...) p9 = call(ConstClass(fromint), i4, descr=...) + guard_no_exception(descr=...) p11 = call(ConstClass(rbigint.mul), p5, p9, descr=...) guard_no_exception(descr=...) i13 = int_sub(i4, 1) diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -913,7 +913,7 @@ def repr__String(space, w_str): s = w_str._value - buf = StringBuilder(50) + buf = StringBuilder(len(s) + 2) quote = "'" if quote in s and '"' not in s: diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -154,7 +154,7 @@ x = 0x345678 z = len(wrappeditems) for w_item in wrappeditems: - y = space.int_w(space.hash(w_item)) + y = space.hash_w(w_item) x = (x ^ y) * mult z -= 1 mult += 82520 + z + z diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py --- a/pypy/rpython/lltypesystem/rbuilder.py +++ b/pypy/rpython/lltypesystem/rbuilder.py @@ -93,23 +93,21 @@ @staticmethod def ll_append_multiple_char(ll_builder, char, times): - used = ll_builder.used - if times + used > ll_builder.allocated: + use = ll_builder.used + times + if use > ll_builder.allocated: ll_builder.grow(ll_builder, times) - for i in range(times): - ll_builder.buf.chars[used] = char - used += 1 - ll_builder.used = used + for i in range(ll_builder.used, use): + ll_builder.buf.chars[i] = char + ll_builder.used = use @staticmethod def ll_append_charpsize(ll_builder, charp, size): - used = ll_builder.used - if used + size > ll_builder.allocated: + use = ll_builder.used + size + if use > ll_builder.allocated: ll_builder.grow(ll_builder, size) - for i in xrange(size): - ll_builder.buf.chars[used] = charp[i] - used += 1 - ll_builder.used = used + for i in xrange(ll_builder.used, use): + ll_builder.buf.chars[i] = charp[i] + ll_builder.used = use @staticmethod def ll_getlength(ll_builder): diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java --- a/pypy/translator/jvm/src/pypy/PyPy.java +++ b/pypy/translator/jvm/src/pypy/PyPy.java @@ -1100,9 +1100,9 @@ if (Double.isNaN(x)) return interlink.recordFloatSigned(x, 0); - // Infinity: Python throws exception + // Infinity: Python returns (inf, 0) if (Double.isInfinite(x)) - interlink.throwOverflowError(); + return interlink.recordFloatSigned(x, 0); // Extract the various parts of the format: final long e=11, f=52; // number of bits in IEEE format From noreply at buildbot.pypy.org Sat Jul 30 12:28:00 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 12:28:00 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: A basic test about arrays of doubles, and a version about arrays of floats. Message-ID: <20110730102800.6DC4282111@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46108:f3bf3bf10b0c Date: 2011-07-30 10:22 +0000 http://bitbucket.org/pypy/pypy/changeset/f3bf3bf10b0c/ Log: A basic test about arrays of doubles, and a version about arrays of floats. diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -88,6 +88,69 @@ jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=) """) + def test_array_of_doubles(self): + def main(): + from array import array + img = array('d', [21.5]*1000) + i = 0 + while i < 1000: + img[i] += 20.5 + assert img[i] == 42.0 + i += 1 + return 123 + # + log = self.run(main, []) + assert log.result == 123 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i6, 1000) + guard_true(i10, descr=...) + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + f13 = getarrayitem_raw(i8, i6, descr=) + f15 = float_add(f13, 20.500000) + setarrayitem_raw(i8, i6, f15, descr=) + f16 = getarrayitem_raw(i8, i6, descr=) + i18 = float_eq(f16, 42.000000) + guard_true(i18, descr=...) + i20 = int_add(i6, 1) + --TICK-- + jump(..., descr=) + """) + + def test_array_of_floats(self): + def main(): + from array import array + img = array('f', [21.5]*1000) + i = 0 + while i < 1000: + img[i] += 20.5 + assert img[i] == 42.0 + i += 1 + return 321 + # + log = self.run(main, []) + assert log.result == 321 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i10 = int_lt(i6, 1000) + guard_true(i10, descr=...) + i11 = int_lt(i6, i7) + guard_true(i11, descr=...) + i13 = getarrayitem_raw(i8, i6, descr=) + f14 = cast_singlefloat_to_float(i13) + f16 = float_add(f14, 20.500000) + i17 = cast_float_to_singlefloat(f16) + setarrayitem_raw(i8, i6,i17, descr=) + i18 = getarrayitem_raw(i8, i6, descr=) + f19 = cast_singlefloat_to_float(i18) + i21 = float_eq(f19, 42.000000) + guard_true(i21, descr=...) + i23 = int_add(i6, 1) + --TICK-- + jump(..., descr=) + """) + def test_zeropadded(self): def main(): From noreply at buildbot.pypy.org Sat Jul 30 12:28:01 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 12:28:01 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Fix the test on 64-bit. Message-ID: <20110730102801.9C42E82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46109:7e531f6007ba Date: 2011-07-30 12:25 +0200 http://bitbucket.org/pypy/pypy/changeset/7e531f6007ba/ Log: Fix the test on 64-bit. diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -1,4 +1,4 @@ -import py +import py, sys from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC class TestArray(BaseTestPyPyC): @@ -132,24 +132,28 @@ log = self.run(main, []) assert log.result == 321 loop, = log.loops_by_filename(self.filepath) + if sys.maxint == 2147483647: + arraydescr = 'UnsignedArrayNoLengthDescr' + else: + arraydescr = 'UINTArrayNoLengthDescr' assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) - i13 = getarrayitem_raw(i8, i6, descr=) + i13 = getarrayitem_raw(i8, i6, descr=<%s>) f14 = cast_singlefloat_to_float(i13) f16 = float_add(f14, 20.500000) i17 = cast_float_to_singlefloat(f16) - setarrayitem_raw(i8, i6,i17, descr=) - i18 = getarrayitem_raw(i8, i6, descr=) + setarrayitem_raw(i8, i6,i17, descr=<%s>) + i18 = getarrayitem_raw(i8, i6, descr=<%s>) f19 = cast_singlefloat_to_float(i18) i21 = float_eq(f19, 42.000000) guard_true(i21, descr=...) i23 = int_add(i6, 1) --TICK-- jump(..., descr=) - """) + """ % (arraydescr, arraydescr, arraydescr)) def test_zeropadded(self): From noreply at buildbot.pypy.org Sat Jul 30 13:08:31 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 30 Jul 2011 13:08:31 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Allow elidable function call results to be reused within a loop. Message-ID: <20110730110831.495BE82110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46110:170db2bb70ac Date: 2011-07-30 04:08 -0700 http://bitbucket.org/pypy/pypy/changeset/170db2bb70ac/ Log: Allow elidable function call results to be reused within a loop. diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -484,8 +484,12 @@ def make_args_key(self, op): n = op.numargs() - args = [None] * (n + 2) - for i in range(n): + if op.getopnum() == rop.CALL_PURE: + start = 1 + else: + start = 0 + args = [None] * (n + 2 - start) + for i in range(start, n): arg = op.getarg(i) try: value = self.values[arg] @@ -493,9 +497,9 @@ pass else: arg = value.get_key_box() - args[i] = arg - args[n] = ConstInt(op.getopnum()) - args[n+1] = op.getdescr() + args[i - start] = arg + args[n - start] = ConstInt(op.getopnum()) + args[n + 1 - start] = op.getdescr() return args def optimize_default(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -224,6 +224,16 @@ else: self.make_constant(op.result, result) return + + args = self.optimizer.make_args_key(op) + oldop = self.optimizer.pure_operations.get(args, None) + if oldop is not None and oldop.getdescr() is op.getdescr(): + assert oldop.getopnum() == op.getopnum() + self.make_equal_to(op.result, self.getvalue(oldop.result)) + return + else: + self.optimizer.pure_operations[args] = op + # replace CALL_PURE with just CALL args = op.getarglist() self.emit_operation(ResOperation(rop.CALL, args, op.result, diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2932,13 +2932,17 @@ jump(p1, i4, i3) ''' expected = ''' + [p1, i4, i3] + jump(p1, i3, i3) + ''' + preamble = ''' [p1, i1, i4] setfield_gc(p1, i1, descr=valuedescr) i3 = call(p1, descr=plaincalldescr) setfield_gc(p1, i3, descr=valuedescr) jump(p1, i4, i3) ''' - self.optimize_loop(ops, expected, expected) + self.optimize_loop(ops, expected, preamble) def test_call_pure_invalidates_heap_knowledge(self): # CALL_PURE should still force the setfield_gc() to occur before it @@ -2950,21 +2954,20 @@ jump(p1, i4, i3) ''' expected = ''' + [p1, i4, i3] + setfield_gc(p1, i4, descr=valuedescr) + jump(p1, i3, i3) + ''' + preamble = ''' [p1, i1, i4] setfield_gc(p1, i1, descr=valuedescr) i3 = call(p1, descr=plaincalldescr) setfield_gc(p1, i1, descr=valuedescr) jump(p1, i4, i3) ''' - self.optimize_loop(ops, expected, expected) + self.optimize_loop(ops, expected, preamble) def test_call_pure_constant_folding(self): - # CALL_PURE is not marked as is_always_pure(), because it is wrong - # to call the function arbitrary many times at arbitrary points in - # time. Check that it is either constant-folded (and replaced by - # the result of the call, recorded as the first arg), or turned into - # a regular CALL. - # XXX can this test be improved with unrolling? arg_consts = [ConstInt(i) for i in (123456, 4, 5, 6)] call_pure_results = {tuple(arg_consts): ConstInt(42)} ops = ''' @@ -2983,10 +2986,9 @@ jump(i0, i4) ''' expected = ''' - [i0, i2] + [i0, i4] escape(42) - escape(i2) - i4 = call(123456, 4, i0, 6, descr=plaincalldescr) + escape(i4) jump(i0, i4) ''' self.optimize_loop(ops, expected, preamble, call_pure_results) @@ -3017,9 +3019,7 @@ [i0, i2] escape(42) escape(i2) - i4 = call(123456, 4, i0, 6, descr=plaincalldescr) - guard_no_exception() [] - jump(i0, i4) + jump(i0, i2) ''' self.optimize_loop(ops, expected, preamble, call_pure_results) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -2712,6 +2712,22 @@ assert res == main(1, 10, 2) self.check_loops(call=0) + def test_reuse_elidable_result(self): + driver = JitDriver(reds=['n', 's'], greens = []) + def main(n): + s = 0 + while n > 0: + driver.jit_merge_point(s=s, n=n) + s += len(str(n)) + len(str(n)) + n -= 1 + return s + res = self.meta_interp(main, [10]) + assert res == main(10) + self.check_loops({ + 'call': 1, 'guard_no_exception': 1, 'guard_true': 1, 'int_add': 2, + 'int_gt': 1, 'int_sub': 1, 'strlen': 1, 'jump': 1, + }) + class TestLLtype(BaseLLtypeTests, LLJitMixin): pass diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py --- a/pypy/jit/metainterp/test/test_dict.py +++ b/pypy/jit/metainterp/test/test_dict.py @@ -153,11 +153,7 @@ res = self.meta_interp(f, [100], listops=True) assert res == f(50) - # XXX: ideally there would be 7 calls here, but repeated CALL_PURE with - # the same arguments are not folded, because we have conflicting - # definitions of pure, once strhash can be appropriately folded - # this should be decreased to seven. - self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 6, + self.check_loops({"call": 7, "guard_false": 1, "guard_no_exception": 6, "guard_true": 1, "int_and": 1, "int_gt": 1, "int_is_true": 1, "int_sub": 1, "jump": 1, "new_with_vtable": 1, "setfield_gc": 1}) diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py --- a/pypy/jit/metainterp/test/test_string.py +++ b/pypy/jit/metainterp/test/test_string.py @@ -26,7 +26,7 @@ return i res = self.meta_interp(f, [10, True, _str('h')], listops=True) assert res == 5 - self.check_loops(**{self.CALL: 1, self.CALL_PURE: 0}) + self.check_loops(**{self.CALL: 1, self.CALL_PURE: 0, 'everywhere': True}) def test_eq_folded(self): _str = self._str @@ -355,7 +355,7 @@ m -= 1 return 42 self.meta_interp(f, [6, 7]) - self.check_loops(call=3, # str(), _str(), escape() + self.check_loops(call=1, # escape() newunicode=1, unicodegetitem=0, unicodesetitem=1, copyunicodecontent=1) From noreply at buildbot.pypy.org Sat Jul 30 14:16:49 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 14:16:49 +0200 (CEST) Subject: [pypy-commit] pypy jit-singlefloat: Add a case, shown missing by the test. Message-ID: <20110730121649.E588282110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: jit-singlefloat Changeset: r46111:b0ac9b9fef8b Date: 2011-07-30 14:17 +0200 http://bitbucket.org/pypy/pypy/changeset/b0ac9b9fef8b/ Log: Add a case, shown missing by the test. diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py --- a/pypy/jit/backend/llsupport/descr.py +++ b/pypy/jit/backend/llsupport/descr.py @@ -435,7 +435,7 @@ def get_result_size(self, translate_support_code): return 0 -SingleFloatCallDescr = None # built lazily +_SingleFloatCallDescr = None # built lazily def getCallDescrClass(RESULT): if RESULT is lltype.Void: @@ -443,19 +443,21 @@ if RESULT is lltype.Float: return FloatCallDescr if RESULT is lltype.SingleFloat: - global SingleFloatCallDescr - if SingleFloatCallDescr is None: + global _SingleFloatCallDescr + if _SingleFloatCallDescr is None: assert rffi.sizeof(rffi.UINT) == rffi.sizeof(RESULT) class SingleFloatCallDescr(getCallDescrClass(rffi.UINT)): _clsname = 'SingleFloatCallDescr' _return_type = 'S' - return SingleFloatCallDescr + _SingleFloatCallDescr = SingleFloatCallDescr + return _SingleFloatCallDescr if is_longlong(RESULT): return LongLongCallDescr return getDescrClass(RESULT, BaseIntCallDescr, GcPtrCallDescr, NonGcPtrCallDescr, 'Call', 'get_result_size', Ellipsis, # <= floatattrname should not be used here '_is_result_signed') +getCallDescrClass._annspecialcase_ = 'specialize:memo' def get_call_descr(gccache, ARGS, RESULT, extrainfo=None): arg_classes = [] diff --git a/pypy/jit/backend/llsupport/ffisupport.py b/pypy/jit/backend/llsupport/ffisupport.py --- a/pypy/jit/backend/llsupport/ffisupport.py +++ b/pypy/jit/backend/llsupport/ffisupport.py @@ -1,7 +1,9 @@ from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp import history -from pypy.jit.backend.llsupport.descr import DynamicIntCallDescr, NonGcPtrCallDescr,\ - FloatCallDescr, VoidCallDescr +from pypy.rpython.lltypesystem import rffi +from pypy.jit.backend.llsupport.descr import ( + DynamicIntCallDescr, NonGcPtrCallDescr, FloatCallDescr, VoidCallDescr, + LongLongCallDescr, getCallDescrClass) class UnsupportedKind(Exception): pass @@ -25,6 +27,11 @@ return FloatCallDescr(arg_classes, extrainfo) elif reskind == history.VOID: return VoidCallDescr(arg_classes, extrainfo) + elif reskind == 'L': + return LongLongCallDescr(arg_classes, extrainfo) + elif reskind == 'S': + SingleFloatCallDescr = getCallDescrClass(rffi.FLOAT) + return SingleFloatCallDescr(arg_classes, extrainfo) assert False def get_ffi_type_kind(cpu, ffi_type): diff --git a/pypy/jit/backend/llsupport/test/test_ffisupport.py b/pypy/jit/backend/llsupport/test/test_ffisupport.py --- a/pypy/jit/backend/llsupport/test/test_ffisupport.py +++ b/pypy/jit/backend/llsupport/test/test_ffisupport.py @@ -1,24 +1,48 @@ from pypy.rlib.libffi import types -from pypy.jit.backend.llsupport.ffisupport import get_call_descr_dynamic, \ - VoidCallDescr, DynamicIntCallDescr - +from pypy.jit.backend.llsupport.ffisupport import * + + +class FakeCPU: + def __init__(self, supports_floats=False, supports_longlong=False, + supports_singlefloats=False): + self.supports_floats = supports_floats + self.supports_longlong = supports_longlong + self.supports_singlefloats = supports_singlefloats + + def test_call_descr_dynamic(): + args = [types.sint, types.pointer] + descr = get_call_descr_dynamic(FakeCPU(), args, types.sint) + assert isinstance(descr, DynamicIntCallDescr) + assert descr.arg_classes == 'ii' args = [types.sint, types.double, types.pointer] - descr = get_call_descr_dynamic(args, types.void) + descr = get_call_descr_dynamic(FakeCPU(), args, types.void) + assert descr is None # missing floats + descr = get_call_descr_dynamic(FakeCPU(supports_floats=True), + args, types.void) assert isinstance(descr, VoidCallDescr) assert descr.arg_classes == 'ifi' - descr = get_call_descr_dynamic([], types.sint8) + descr = get_call_descr_dynamic(FakeCPU(), [], types.sint8) assert isinstance(descr, DynamicIntCallDescr) assert descr.get_result_size(False) == 1 assert descr.is_result_signed() == True - descr = get_call_descr_dynamic([], types.uint8) + descr = get_call_descr_dynamic(FakeCPU(), [], types.uint8) assert isinstance(descr, DynamicIntCallDescr) assert descr.get_result_size(False) == 1 assert descr.is_result_signed() == False - descr = get_call_descr_dynamic([], types.float) - assert descr is None # single floats are not supported so far - + descr = get_call_descr_dynamic(FakeCPU(), [], types.slonglong) + assert descr is None # missing longlongs + descr = get_call_descr_dynamic(FakeCPU(supports_longlong=True), + [], types.slonglong) + assert isinstance(descr, LongLongCallDescr) + + descr = get_call_descr_dynamic(FakeCPU(), [], types.float) + assert descr is None # missing singlefloats + descr = get_call_descr_dynamic(FakeCPU(supports_singlefloats=True), + [], types.float) + SingleFloatCallDescr = getCallDescrClass(rffi.FLOAT) + assert isinstance(descr, SingleFloatCallDescr) From noreply at buildbot.pypy.org Sat Jul 30 15:29:53 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 15:29:53 +0200 (CEST) Subject: [pypy-commit] pypy default: Backed out changeset 54515dec1d20: it is responsible for the Message-ID: <20110730132953.8B32A82110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46112:7bfcde50cf5b Date: 2011-07-30 15:30 +0200 http://bitbucket.org/pypy/pypy/changeset/7bfcde50cf5b/ Log: Backed out changeset 54515dec1d20: it is responsible for the failures in lib-python's tests shown by tonight's buildbot run. diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py --- a/pypy/rpython/lltypesystem/rbuilder.py +++ b/pypy/rpython/lltypesystem/rbuilder.py @@ -93,21 +93,23 @@ @staticmethod def ll_append_multiple_char(ll_builder, char, times): - use = ll_builder.used + times - if use > ll_builder.allocated: + used = ll_builder.used + if times + used > ll_builder.allocated: ll_builder.grow(ll_builder, times) - for i in range(ll_builder.used, use): - ll_builder.buf.chars[i] = char - ll_builder.used = use + for i in range(times): + ll_builder.buf.chars[used] = char + used += 1 + ll_builder.used = used @staticmethod def ll_append_charpsize(ll_builder, charp, size): - use = ll_builder.used + size - if use > ll_builder.allocated: + used = ll_builder.used + if used + size > ll_builder.allocated: ll_builder.grow(ll_builder, size) - for i in xrange(ll_builder.used, use): - ll_builder.buf.chars[i] = charp[i] - ll_builder.used = use + for i in xrange(size): + ll_builder.buf.chars[used] = charp[i] + used += 1 + ll_builder.used = used @staticmethod def ll_getlength(ll_builder): From noreply at buildbot.pypy.org Sat Jul 30 23:31:16 2011 From: noreply at buildbot.pypy.org (gutworth) Date: Sat, 30 Jul 2011 23:31:16 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: allow _build_string to be unrolled if the template is constant Message-ID: <20110730213116.57E4382110@wyvern.cs.uni-duesseldorf.de> Author: Benjamin Peterson Branch: unroll-if-alt Changeset: r46113:f45b04b331a6 Date: 2011-07-30 16:31 -0500 http://bitbucket.org/pypy/pypy/changeset/f45b04b331a6/ Log: allow _build_string to be unrolled if the template is constant diff --git a/pypy/objspace/std/newformat.py b/pypy/objspace/std/newformat.py --- a/pypy/objspace/std/newformat.py +++ b/pypy/objspace/std/newformat.py @@ -3,7 +3,8 @@ import string from pypy.interpreter.error import OperationError -from pypy.rlib import rstring, runicode, rlocale, rarithmetic, rfloat +from pypy.tool import sourcetools +from pypy.rlib import rstring, runicode, rlocale, rarithmetic, rfloat, jit from pypy.rlib.objectmodel import specialize from pypy.rlib.rfloat import copysign, formatd @@ -65,6 +66,13 @@ space.wrap("Recursion depth exceeded")) level -= 1 s = self.template + if jit.isconstant(s): + return self._do_build_string_unroll(start, end, level, out, s) + else: + return self._do_build_string(start, end, level, out, s) + + def _do_build_string(self, start, end, level, out, s): + space = self.space last_literal = i = start while i < end: c = s[i] @@ -115,6 +123,11 @@ out.append_slice(s, last_literal, end) return out.build() + f = sourcetools.func_with_new_name(_do_build_string, + "_do_build_string_unroll") + _do_build_string_unroll = jit.unroll_safe(f) + del f + def _parse_field(self, start, end): s = self.template # Find ":" or "!" From noreply at buildbot.pypy.org Sat Jul 30 23:48:39 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 23:48:39 +0200 (CEST) Subject: [pypy-commit] pypy default: Add track_allocation=False to the raw memory allocated by array.array(). Message-ID: <20110730214839.067A182110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46114:1c74e688ab5b Date: 2011-07-30 21:47 +0200 http://bitbucket.org/pypy/pypy/changeset/1c74e688ab5b/ Log: Add track_allocation=False to the raw memory allocated by array.array(). diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -226,7 +226,8 @@ some += size >> 3 self.allocated = size + some new_buffer = lltype.malloc(mytype.arraytype, - self.allocated, flavor='raw') + self.allocated, flavor='raw', + track_allocation=False) for i in range(min(size, self.len)): new_buffer[i] = self.buffer[i] else: From noreply at buildbot.pypy.org Sat Jul 30 23:48:40 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 23:48:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Add a test, failing so far. Message-ID: <20110730214840.3A99882110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46115:67b8331d21aa Date: 2011-07-30 21:47 +0200 http://bitbucket.org/pypy/pypy/changeset/67b8331d21aa/ Log: Add a test, failing so far. diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -1390,6 +1390,29 @@ def test_gc_heap_stats(self): py.test.skip("not implemented") + def define_nongc_attached_to_gc(cls): + from pypy.rpython.lltypesystem import rffi + ARRAY = rffi.CArray(rffi.INT) + class A: + def __init__(self, n): + self.buf = lltype.malloc(ARRAY, n, flavor='raw', + track_allocation=False) + def __del__(self): + lltype.free(self.buf, flavor='raw', track_allocation=False) + def f(): + # allocate a total of ~77GB, but if the automatic gc'ing works, + # it should never need more than a few MBs at once + am1 = am2 = am3 = None + for i in range(100000): + am3 = am2 + am2 = am1 + am1 = A(i * 4) + return 42 + return f + + def test_nongc_attached_to_gc(self): + self.run("nongc_attached_to_gc") + # ____________________________________________________________________ class TaggedPointersTest(object): From noreply at buildbot.pypy.org Sat Jul 30 23:48:41 2011 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 30 Jul 2011 23:48:41 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix the test. This gives a first approximation of the .NET Message-ID: <20110730214841.81E6482110@wyvern.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46116:e7121092d73f Date: 2011-07-30 22:41 +0200 http://bitbucket.org/pypy/pypy/changeset/e7121092d73f/ Log: Fix the test. This gives a first approximation of the .NET AddMemoryPressure(). This version is simpler than a counter that needs to be carefully incremented and decremented by the exact same amount. The idea is to use track_allocation=False to know when a raw malloc is going to be attached to a GC object (good enough for now). All such raw mallocs make the next major collection occur earlier. So the major collection is triggered when sum( GC object surviving minor collections + rawmallocs with track_allocation=False ) > trigger The raw mallocs are attached to GC objects with a __del__, which are never allocated young, so they will survive at least until the major collection. But if they survive for longer, they are ignored for future major collections. This is again an approximation, but in the "safe" way. Indeed, *not* ignoring them would simply mean having a higher trigger, computed as (1.82*previous size). diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -390,6 +390,11 @@ # initialize the threshold self.min_heap_size = max(self.min_heap_size, self.nursery_size * self.major_collection_threshold) + # the following two values are usually equal, but during raw mallocs + # of arrays, next_major_collection_threshold is decremented to make + # the next major collection arrive earlier. + # See translator/c/test/test_newgc, test_nongc_attached_to_gc + self.next_major_collection_initial = self.min_heap_size self.next_major_collection_threshold = self.min_heap_size self.set_major_threshold_from(0.0) debug_stop("gc-set-nursery-size") @@ -397,7 +402,7 @@ def set_major_threshold_from(self, threshold, reserving_size=0): # Set the next_major_collection_threshold. - threshold_max = (self.next_major_collection_threshold * + threshold_max = (self.next_major_collection_initial * self.growth_rate_max) if threshold > threshold_max: threshold = threshold_max @@ -412,6 +417,7 @@ else: bounded = False # + self.next_major_collection_initial = threshold self.next_major_collection_threshold = threshold return bounded @@ -718,9 +724,18 @@ def set_max_heap_size(self, size): self.max_heap_size = float(size) if self.max_heap_size > 0.0: + if self.max_heap_size < self.next_major_collection_initial: + self.next_major_collection_initial = self.max_heap_size if self.max_heap_size < self.next_major_collection_threshold: self.next_major_collection_threshold = self.max_heap_size + def raw_malloc_varsize_hint(self, sizehint): + self.next_major_collection_threshold -= sizehint + if self.next_major_collection_threshold < 0: + # cannot trigger a full collection now, but we can ensure + # that one will occur very soon + self.nursery_free = self.nursery_top + def can_malloc_nonmovable(self): return True @@ -1600,7 +1615,7 @@ # Max heap size: gives an upper bound on the threshold. If we # already have at least this much allocated, raise MemoryError. if bounded and (float(self.get_total_memory_used()) + reserving_size >= - self.next_major_collection_threshold): + self.next_major_collection_initial): # # First raise MemoryError, giving the program a chance to # quit cleanly. It might still allocate in the nursery, diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -386,6 +386,18 @@ else: self.malloc_varsize_nonmovable_ptr = None + if getattr(GCClass, 'raw_malloc_varsize_hint', False): + def raw_malloc_varsize_hint(length, itemsize): + totalmem = length * itemsize + if totalmem > 0: + gcdata.gc.raw_malloc_varsize_hint(totalmem) + #else: probably an overflow -- the following rawmalloc + # will fail then + self.raw_malloc_varsize_hint_ptr = getfn( + raw_malloc_varsize_hint, + [annmodel.SomeInteger(), annmodel.SomeInteger()], + annmodel.s_None, minimal_transform = False) + self.identityhash_ptr = getfn(GCClass.identityhash.im_func, [s_gc, s_gcref], annmodel.SomeInteger(), diff --git a/pypy/rpython/memory/gctransform/transform.py b/pypy/rpython/memory/gctransform/transform.py --- a/pypy/rpython/memory/gctransform/transform.py +++ b/pypy/rpython/memory/gctransform/transform.py @@ -590,6 +590,16 @@ def gct_fv_raw_malloc_varsize(self, hop, flags, TYPE, v_length, c_const_size, c_item_size, c_offset_to_length): + track_allocation = flags.get('track_allocation', True) + if not track_allocation: + # idea: raw mallocs with track_allocation=False correspond + # generally to raw mallocs of stuff that we store in GC objects. + # So we tell the GC about such raw mallocs, so that it can + # adjust its total size estimate. + if hasattr(self, 'raw_malloc_varsize_hint_ptr'): + hop.genop("direct_call", + [self.raw_malloc_varsize_hint_ptr, + v_length, c_item_size]) if c_offset_to_length is None: if flags.get('zero'): fnptr = self.raw_malloc_varsize_no_length_zero_ptr @@ -605,7 +615,7 @@ [self.raw_malloc_varsize_ptr, v_length, c_const_size, c_item_size, c_offset_to_length], resulttype=llmemory.Address) - if flags.get('track_allocation', True): + if track_allocation: hop.genop("track_alloc_start", [v_raw]) return v_raw diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -1403,15 +1403,20 @@ # allocate a total of ~77GB, but if the automatic gc'ing works, # it should never need more than a few MBs at once am1 = am2 = am3 = None - for i in range(100000): + res = 0 + for i in range(1, 100001): + if am3 is not None: + res += rffi.cast(lltype.Signed, am3.buf[0]) am3 = am2 am2 = am1 am1 = A(i * 4) - return 42 + am1.buf[0] = rffi.cast(rffi.INT, i-50000) + return res return f def test_nongc_attached_to_gc(self): - self.run("nongc_attached_to_gc") + res = self.run("nongc_attached_to_gc") + assert res == -99997 # ____________________________________________________________________ From noreply at buildbot.pypy.org Sun Jul 31 00:29:37 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 00:29:37 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: First pass at a blog post. Message-ID: <20110730222937.063D682110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3850:309e625a09c3 Date: 2011-07-30 15:29 -0700 http://bitbucket.org/pypy/extradoc/changeset/309e625a09c3/ Log: First pass at a blog post. diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst new file mode 100644 --- /dev/null +++ b/blog/draft/string-formatting.rst @@ -0,0 +1,50 @@ +String formatting with PyPy +=========================== + +String formatting is probably something you do just about every day in Python, +and never think about. It's so easy, just ``"%d %d" % (i, i)`` and you're +done. No thinking about how to size your result buffer, whether your output +has an appropriae NUL byte at the end, or any other details. A simple C +equivilant might be:: + + char x[23]; + sprintf(x, "%d %d", i, i); + +Which is fine, except you can't even return ``x`` from this function, a more +fair comparison might be:: + + char *x = calloc(23, sizeof(char)); + sprintf(x, "%d %d", i, i); + +``x`` is slightly overallocated in some situations, but that's fine. + +But we're not here to discuss the exact syntax of string formatting, we're here +to discuss how blazing fast PyPy is at it, with the new ``unroll-if-alt`` +branch. Given the Python code:: + + def main(): + for i in xrange(10000000): + "%d %d" % (i, i) + + main() + +and the C code:: + + #include + #include + + + int main() { + int i = 0; + char x[23]; + for (i = 0; i < 10000000; i++) { + sprintf(x, "%d %d", i, i); + } + } + +Ran under PyPy, at the head of the ``unroll-if-alt`` branch, and compiled with +GCC 4.5.2 at -O4 (other optimization levels were tested, this produced the best +performance). It took .85 seconds to execute under PyPy, and 1.63 seconds with +the compiled binary. We think this demonstrates the incredible potential of +dynamic compilation, GCC is unable to inline or unroll the ``sprintf`` call, +because it sits inside of libc. \ No newline at end of file From noreply at buildbot.pypy.org Sun Jul 31 00:29:38 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 00:29:38 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: merged upstream. Message-ID: <20110730222938.6ED7982110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3851:8d612fff616c Date: 2011-07-30 15:29 -0700 http://bitbucket.org/pypy/extradoc/changeset/8d612fff616c/ Log: merged upstream. diff --git a/blog/draft/success_stories.rst b/blog/draft/success_stories.rst new file mode 100644 --- /dev/null +++ b/blog/draft/success_stories.rst @@ -0,0 +1,53 @@ +PyPy success stories +==================== + +Regular readers of this blog know the great progresses that PyPy achieved in +the past few years in terms of speed_, stability, and adoption. + +All of this has been made possibile thanks to the help of the Open Source +community, but also thanks to the German and Swedish governments, which +funded us through the `Eurostars programme`_. This let some of us +core developers work full time on PyPy for the past two years. + +Our participation to Eurostars is ending in August, and at the moment we are +exploring several different ways of funding PyPy through other sources. We +will write more about that in the next days. During this process, it is +important to show that PyPy has stopped being "just" a research project, but +that it is also a robust and solid solution for industry. + +We would like to write a list of "PyPy success stories", and thus we ask +for your help: + + - if you are already using PyPy in production; + + - if you are actively testing PyPy on your codebase; + + - or even if you are simply considering switching to PyPy and experimenting with it; + +in those cases, please let us know about it. We would like to know which +company you work for, what are you using PyPy for, and why you decided to +switch to it. Ideally, we would like the permission to publish this +information and share it with the public. + +If for any reason you cannot or do not want to make this public, we are still +interested in hearing about you. In that case, don't hesitate to contact us +privately - we will not publish your data. But we have potential sponsors +who are intersted in supporting PyPy, and showing them a list of companies +that are using PyPy (+ 3 anonymous ones in the financial services sector) is +almost as good as showing them a list with all the company names filled in. +What they are looking for is evidence that PyPy is not a research toy, but +of actual use to industry. + +Please take the time to respond either as a comment to this blog post +directly, or byt sending email to the `pypy-dev`_ mailing list or by +writing a private email to me (`Antonio Cuni`_) or `Laura Creighton`_. + +We hope to hear about lots of PyPy success stories. Remind that the more of +them we collect, the easier for us to find sponsors to fund further +development of PyPy! And, of course, if any of you are interested in +_becoming_ one of these sponsors, we would like to hear about that, as well. + +Thanks very much (in advance) for all your help, +Laura and Anto (for the entire PyPy team) + +_`Eurostars programme` : http://www.eurostars-eureka.eu/ diff --git a/planning/jit.txt b/planning/jit.txt --- a/planning/jit.txt +++ b/planning/jit.txt @@ -164,3 +164,31 @@ at the end of the preamble unnessesary. If that policy wont hold in the long run it should be straight forward to augument the VirtualState objects with information about storesinking. + + +Random ideas from hakanardo +---------------------------- + + - Let bridges inherit more information form their parent traces to allow + them to be better optimized. One idea is to augument the resumedata with + the index within the trace inputargs for each failarg that comes directly + from the inputargs. That way a lot of info can be deduced from the short + preamble. Another idea is to actually store a lot of status information on + the guards as they are generated, but then forget (and free) that info as + the guards grow older (in terms of the number of generated guards or + something). + + - Generalisation strategies. Once jit-short_from_state is merged we'll have + a nice platform to experiment with generalizing the loops created. Today + unrolling makes the jit specialize as much as possible which is one reason + it's hard for bridges to reuse the created peeled loops. There is also a + tradeoff between forcing things to be able to reuse an existing loop and + retracing it to form a new specialized version. + + - Better pointer aliasing analyzer that will emit guards that pointers are + different when needed. + + - Make heap optimizer aware of setitems produced by forcing virtuals. + + - Movinging loop-invariant setitems out of the loops entierly. + diff --git a/talk/icooolps2011/talk/figures/map.svg b/talk/icooolps2011/talk/figures/map.svg --- a/talk/icooolps2011/talk/figures/map.svg +++ b/talk/icooolps2011/talk/figures/map.svg @@ -49,7 +49,40 @@ id="path8552" d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" - transform="scale(0.8) translate(12.5,0)" />add "a" add "b" +map +"c": 0 +add "c" +"b": 1 -add "b" -map -"c": 0 -add "c" instance + id="text7703" + transform="scale(1,-1)" + x="8.2999992" + y="-249.89999">instance + map + id="text7711" + transform="matrix(1,0,0,-1,78.5,249.9)">map + storage + id="text7719" + transform="matrix(1,0,0,-1,122.5,249.9)">storage + array + id="text7733" + transform="matrix(1,0,0,-1,185.5,183.9)">array + 4 + id="text7741" + transform="matrix(1,0,0,-1,232.5,183.9)">4 + 6 + id="text7749" + transform="matrix(1,0,0,-1,256.5,183.9)">6 + \ No newline at end of file diff --git a/talk/icooolps2011/talk/figures/map01.pdf b/talk/icooolps2011/talk/figures/map01.pdf index d957a75d52a1e205b35f2139afe40e260bcaa5f7..b02a6212807255e3be3a63808946c1f87b32a64a GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/map02.pdf b/talk/icooolps2011/talk/figures/map02.pdf index c8f07cffbd5017707537c5fb18bf7a822384016f..8f23b0fb78a661be86adf7790844570eed590ef5 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/figures/map03.pdf b/talk/icooolps2011/talk/figures/map03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e9944db6caa3a34e1852cfb8934df628bf64d089 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/talk.pdf b/talk/icooolps2011/talk/talk.pdf new file mode 100644 index 0000000000000000000000000000000000000000..66d79ac74735959368d77448b8d8606105e447f1 GIT binary patch [cut] diff --git a/talk/icooolps2011/talk/talk.tex b/talk/icooolps2011/talk/talk.tex --- a/talk/icooolps2011/talk/talk.tex +++ b/talk/icooolps2011/talk/talk.tex @@ -107,12 +107,12 @@ \end{frame} \begin{frame} - \frametitle{A Tracing JIT} + \frametitle{An Interpreter} \includegraphics[scale=0.5]{figures/trace01.pdf} \end{frame} \begin{frame} - \frametitle{An Interpreter} + \frametitle{A Tracing JIT} \includegraphics[scale=0.5]{figures/trace02.pdf} \end{frame} @@ -149,6 +149,7 @@ \begin{frame} \frametitle{Example: Attribute Reads in Python} What happens when an attribute \texttt{x.m} is read? (simplified) + \pause \begin{itemize} \item check for \texttt{x.\_\_getattribute\_\_}, if there, call it \pause @@ -180,7 +181,7 @@ \frametitle{Meta-Tracing JITs} \begin{block}{Advantages:} \begin{itemize} - \item semantics is always like that of the interpreter + \item semantics are always like that of the interpreter \item trace fully contains language semantics \item meta-tracers can be reused for various interpreters \end{itemize} @@ -240,12 +241,17 @@ \begin{frame} \frametitle{Example: Instances with Maps} - \includegraphics[scale=0.5]{figures/map01.pdf} + \includegraphics[scale=0.7]{figures/map01.pdf} \end{frame} \begin{frame} \frametitle{Example: Instances with Maps} - \includegraphics[scale=0.5]{figures/map02.pdf} + \includegraphics[scale=0.7]{figures/map02.pdf} +\end{frame} + +\begin{frame} + \frametitle{Example: Instances with Maps} + \includegraphics[scale=0.7]{figures/map03.pdf} \end{frame} \begin{frame}[containsverbatim] @@ -286,7 +292,7 @@ \end{frame} \begin{frame}[plain,containsverbatim] -\frametitle{Trace for code \texttt{inst.a + inst.b}} +\frametitle{Trace for Code \texttt{inst.a + inst.b}} \begin{lstlisting}[mathescape,escapechar=|,basicstyle=\ttfamily]] # $inst_1$.getfield("a") $map_1$ = $inst_1$.map @@ -393,7 +399,6 @@ \PY{k}{def} \PY{n+nf}{getindex}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{indexes}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{,} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)} - \PY{n+nd}{@elidable} \PY{k}{def} \PY{n+nf}{add\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:} \PY{o}{.}\PY{o}{.}\PY{o}{.} From noreply at buildbot.pypy.org Sun Jul 31 00:31:35 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 00:31:35 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: sexier title. Message-ID: <20110730223135.5385482110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3852:72616546df0f Date: 2011-07-30 15:31 -0700 http://bitbucket.org/pypy/extradoc/changeset/72616546df0f/ Log: sexier title. diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -1,5 +1,5 @@ -String formatting with PyPy -=========================== +PyPy is faster than C, again: string formatting +=============================================== String formatting is probably something you do just about every day in Python, and never think about. It's so easy, just ``"%d %d" % (i, i)`` and you're From noreply at buildbot.pypy.org Sun Jul 31 00:41:38 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 00:41:38 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: add numvbers for the malloc version. Message-ID: <20110730224138.7B9D082110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3853:a08ae7b91546 Date: 2011-07-30 15:42 -0700 http://bitbucket.org/pypy/extradoc/changeset/a08ae7b91546/ Log: add numvbers for the malloc version. diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -47,4 +47,21 @@ performance). It took .85 seconds to execute under PyPy, and 1.63 seconds with the compiled binary. We think this demonstrates the incredible potential of dynamic compilation, GCC is unable to inline or unroll the ``sprintf`` call, -because it sits inside of libc. \ No newline at end of file +because it sits inside of libc. + +Benchmarking the C code:: + + #include + #include + + + int main() { + int i = 0; + for (i = 0; i < 10000000; i++) { + char *x = malloc(23 * sizeof(char)); + sprintf(x, "%d %d", i, i); + free(x); + } + } + +Which as discussed above, is more comperable to the Python, takes 1.93 seconds. \ No newline at end of file From noreply at buildbot.pypy.org Sun Jul 31 00:44:13 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 31 Jul 2011 00:44:13 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: update Message-ID: <20110730224413.5014982110@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3854:9c28e3872bf2 Date: 2011-07-31 00:44 +0200 http://bitbucket.org/pypy/extradoc/changeset/9c28e3872bf2/ Log: update diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -4,16 +4,19 @@ String formatting is probably something you do just about every day in Python, and never think about. It's so easy, just ``"%d %d" % (i, i)`` and you're done. No thinking about how to size your result buffer, whether your output -has an appropriae NUL byte at the end, or any other details. A simple C +has an appropriae NULL byte at the end, or any other details. A C equivilant might be:: - char x[23]; + char x[41]; sprintf(x, "%d %d", i, i); -Which is fine, except you can't even return ``x`` from this function, a more +Note that we had to stop for a second and consider how big numbers might get +and overestimate the size (41 = length of the biggest number on 64bit + 1 for +the sign). +This is fine, except you can't even return ``x`` from this function, a more fair comparison might be:: - char *x = calloc(23, sizeof(char)); + char *x = malloc(41 * sizeof(char)); sprintf(x, "%d %d", i, i); ``x`` is slightly overallocated in some situations, but that's fine. @@ -36,7 +39,7 @@ int main() { int i = 0; - char x[23]; + char x[41]; for (i = 0; i < 10000000; i++) { sprintf(x, "%d %d", i, i); } @@ -64,4 +67,4 @@ } } -Which as discussed above, is more comperable to the Python, takes 1.93 seconds. \ No newline at end of file +Which as discussed above, is more comperable to the Python, takes 1.93 seconds. From noreply at buildbot.pypy.org Sun Jul 31 00:46:46 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 00:46:46 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: malloc version is a smidgen slower. Message-ID: <20110730224646.4D14882110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3855:4919af68bda1 Date: 2011-07-30 15:47 -0700 http://bitbucket.org/pypy/extradoc/changeset/4919af68bda1/ Log: malloc version is a smidgen slower. diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -67,4 +67,4 @@ } } -Which as discussed above, is more comperable to the Python, takes 1.93 seconds. +Which as discussed above, is more comperable to the Python, takes 1.96 seconds. From noreply at buildbot.pypy.org Sun Jul 31 00:47:43 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 31 Jul 2011 00:47:43 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: actually, 42 Message-ID: <20110730224743.D6B8982110@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3856:892da22e569b Date: 2011-07-31 00:47 +0200 http://bitbucket.org/pypy/extradoc/changeset/892da22e569b/ Log: actually, 42 diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -7,16 +7,17 @@ has an appropriae NULL byte at the end, or any other details. A C equivilant might be:: - char x[41]; + char x[42]; sprintf(x, "%d %d", i, i); Note that we had to stop for a second and consider how big numbers might get -and overestimate the size (41 = length of the biggest number on 64bit + 1 for -the sign). +and overestimate the size (42 surprisingly enough is also the (length of the +biggest number on 64bit + 1 for +the sign) * 2 + 1 for space + 1 for the NULL byte). This is fine, except you can't even return ``x`` from this function, a more fair comparison might be:: - char *x = malloc(41 * sizeof(char)); + char *x = malloc(42 * sizeof(char)); sprintf(x, "%d %d", i, i); ``x`` is slightly overallocated in some situations, but that's fine. @@ -39,7 +40,7 @@ int main() { int i = 0; - char x[41]; + char x[42]; for (i = 0; i < 10000000; i++) { sprintf(x, "%d %d", i, i); } From noreply at buildbot.pypy.org Sun Jul 31 00:47:45 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 31 Jul 2011 00:47:45 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: merge Message-ID: <20110730224745.062C182110@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3857:128a91f1b88c Date: 2011-07-31 00:47 +0200 http://bitbucket.org/pypy/extradoc/changeset/128a91f1b88c/ Log: merge diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -68,4 +68,4 @@ } } -Which as discussed above, is more comperable to the Python, takes 1.93 seconds. +Which as discussed above, is more comperable to the Python, takes 1.96 seconds. From noreply at buildbot.pypy.org Sun Jul 31 00:50:21 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 00:50:21 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: Update text. Message-ID: <20110730225021.E4F3782110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3858:9b50137bded4 Date: 2011-07-30 15:49 -0700 http://bitbucket.org/pypy/extradoc/changeset/9b50137bded4/ Log: Update text. diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -7,16 +7,15 @@ has an appropriae NULL byte at the end, or any other details. A C equivilant might be:: - char x[41]; + char x[44]; sprintf(x, "%d %d", i, i); Note that we had to stop for a second and consider how big numbers might get -and overestimate the size (41 = length of the biggest number on 64bit + 1 for -the sign). -This is fine, except you can't even return ``x`` from this function, a more -fair comparison might be:: +and overestimate the size (42 = length of the biggest number on 64bit (20) + +1 for the sign * 2 + 1 (for the space) + 1 (NUL byte)). This is fine, except +you can't even return ``x`` from this function, a more fair comparison might be:: - char *x = malloc(41 * sizeof(char)); + char *x = malloc(44 * sizeof(char)); sprintf(x, "%d %d", i, i); ``x`` is slightly overallocated in some situations, but that's fine. @@ -39,7 +38,7 @@ int main() { int i = 0; - char x[41]; + char x[44]; for (i = 0; i < 10000000; i++) { sprintf(x, "%d %d", i, i); } @@ -61,7 +60,7 @@ int main() { int i = 0; for (i = 0; i < 10000000; i++) { - char *x = malloc(23 * sizeof(char)); + char *x = malloc(44 * sizeof(char)); sprintf(x, "%d %d", i, i); free(x); } From noreply at buildbot.pypy.org Sun Jul 31 00:50:23 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 00:50:23 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: I think it is 44 actually. Message-ID: <20110730225023.0D9E882110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3859:64ce3f920647 Date: 2011-07-30 15:50 -0700 http://bitbucket.org/pypy/extradoc/changeset/64ce3f920647/ Log: I think it is 44 actually. From noreply at buildbot.pypy.org Sun Jul 31 00:53:03 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 00:53:03 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: note that C is hard. Message-ID: <20110730225303.04D7882110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3860:043a2320fb40 Date: 2011-07-30 15:53 -0700 http://bitbucket.org/pypy/extradoc/changeset/043a2320fb40/ Log: note that C is hard. diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -12,8 +12,10 @@ Note that we had to stop for a second and consider how big numbers might get and overestimate the size (42 = length of the biggest number on 64bit (20) + -1 for the sign * 2 + 1 (for the space) + 1 (NUL byte)). This is fine, except -you can't even return ``x`` from this function, a more fair comparison might be:: +1 for the sign * 2 + 1 (for the space) + 1 (NUL byte)), it took the authors of +this post, two experienced programs, 3 tries to get the math right on this. +This is fine, except you can't even return ``x`` from this function, a more +fair comparison might be:: char *x = malloc(44 * sizeof(char)); sprintf(x, "%d %d", i, i); From noreply at buildbot.pypy.org Sun Jul 31 00:56:32 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 00:56:32 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: we are not machines. Message-ID: <20110730225632.34DBB82110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r3861:887b24045858 Date: 2011-07-30 15:56 -0700 http://bitbucket.org/pypy/extradoc/changeset/887b24045858/ Log: we are not machines. diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -13,7 +13,7 @@ Note that we had to stop for a second and consider how big numbers might get and overestimate the size (42 = length of the biggest number on 64bit (20) + 1 for the sign * 2 + 1 (for the space) + 1 (NUL byte)), it took the authors of -this post, two experienced programs, 3 tries to get the math right on this. +this post, two experienced programmers, 3 tries to get the math right on this. This is fine, except you can't even return ``x`` from this function, a more fair comparison might be:: From noreply at buildbot.pypy.org Sun Jul 31 00:58:38 2011 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 31 Jul 2011 00:58:38 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: a smiley, name guilty and update nos Message-ID: <20110730225838.52C2682110@wyvern.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r3862:305ae73ddaad Date: 2011-07-31 00:58 +0200 http://bitbucket.org/pypy/extradoc/changeset/305ae73ddaad/ Log: a smiley, name guilty and update nos diff --git a/blog/draft/string-formatting.rst b/blog/draft/string-formatting.rst --- a/blog/draft/string-formatting.rst +++ b/blog/draft/string-formatting.rst @@ -11,9 +11,11 @@ sprintf(x, "%d %d", i, i); Note that we had to stop for a second and consider how big numbers might get -and overestimate the size (42 = length of the biggest number on 64bit (20) + +and overestimate the size (44 = length of the biggest number on 64bit (20) + 1 for the sign * 2 + 1 (for the space) + 1 (NUL byte)), it took the authors of -this post, two experienced programmers, 3 tries to get the math right on this. +this post, two experienced programmers, 3 tries to get the math +right on this :-) + This is fine, except you can't even return ``x`` from this function, a more fair comparison might be:: From noreply at buildbot.pypy.org Sun Jul 31 03:00:29 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 03:00:29 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Merged default. Message-ID: <20110731010029.BC54882110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46117:d190258333e1 Date: 2011-07-30 18:00 -0700 http://bitbucket.org/pypy/pypy/changeset/d190258333e1/ Log: Merged default. diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -226,7 +226,8 @@ some += size >> 3 self.allocated = size + some new_buffer = lltype.malloc(mytype.arraytype, - self.allocated, flavor='raw') + self.allocated, flavor='raw', + track_allocation=False) for i in range(min(size, self.len)): new_buffer[i] = self.buffer[i] else: diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -187,17 +187,17 @@ def _getnums(self, comma): if self.find_size() > 1000: nums = [ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(3) ] nums.append("..." + "," * comma) nums.extend([ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(self.find_size() - 3, self.find_size()) ]) else: nums = [ - float2string(self.getitem(index)) + float2string(self.eval(index)) for index in range(self.find_size()) ] return nums @@ -229,7 +229,7 @@ start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size()) if step == 0: # Single index - return space.wrap(self.get_concrete().getitem(start)) + return space.wrap(self.get_concrete().eval(start)) else: # Slice res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature)) @@ -416,14 +416,12 @@ # in fact, ViewArray never gets "concrete" as it never stores data. # This implementation is needed for BaseArray getitem/setitem to work, # can be refactored. + self.parent.get_concrete() return self def eval(self, i): return self.parent.eval(self.calc_index(i)) - def getitem(self, item): - return self.parent.getitem(self.calc_index(item)) - @unwrap_spec(item=int, value=float) def setitem(self, item, value): return self.parent.setitem(self.calc_index(item), value) @@ -497,9 +495,6 @@ def descr_len(self, space): return space.wrap(self.size) - def getitem(self, item): - return self.storage[item] - def setitem(self, item, value): self.invalidated() self.storage[item] = value diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -70,6 +70,7 @@ from numpy import array, zeros a = array(range(5)) assert str(a) == "[0.0 1.0 2.0 3.0 4.0]" + assert str((2*a)[:]) == "[0.0 2.0 4.0 6.0 8.0]" a = zeros(1001) assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]" diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -63,6 +63,7 @@ i7 = int_gt(i4, 1) guard_true(i7, descr=...) p9 = call(ConstClass(fromint), i4, descr=...) + guard_no_exception(descr=...) p11 = call(ConstClass(rbigint.mul), p5, p9, descr=...) guard_no_exception(descr=...) i13 = int_sub(i4, 1) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -154,7 +154,7 @@ x = 0x345678 z = len(wrappeditems) for w_item in wrappeditems: - y = space.int_w(space.hash(w_item)) + y = space.hash_w(w_item) x = (x ^ y) * mult z -= 1 mult += 82520 + z + z diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -390,6 +390,11 @@ # initialize the threshold self.min_heap_size = max(self.min_heap_size, self.nursery_size * self.major_collection_threshold) + # the following two values are usually equal, but during raw mallocs + # of arrays, next_major_collection_threshold is decremented to make + # the next major collection arrive earlier. + # See translator/c/test/test_newgc, test_nongc_attached_to_gc + self.next_major_collection_initial = self.min_heap_size self.next_major_collection_threshold = self.min_heap_size self.set_major_threshold_from(0.0) debug_stop("gc-set-nursery-size") @@ -397,7 +402,7 @@ def set_major_threshold_from(self, threshold, reserving_size=0): # Set the next_major_collection_threshold. - threshold_max = (self.next_major_collection_threshold * + threshold_max = (self.next_major_collection_initial * self.growth_rate_max) if threshold > threshold_max: threshold = threshold_max @@ -412,6 +417,7 @@ else: bounded = False # + self.next_major_collection_initial = threshold self.next_major_collection_threshold = threshold return bounded @@ -718,9 +724,18 @@ def set_max_heap_size(self, size): self.max_heap_size = float(size) if self.max_heap_size > 0.0: + if self.max_heap_size < self.next_major_collection_initial: + self.next_major_collection_initial = self.max_heap_size if self.max_heap_size < self.next_major_collection_threshold: self.next_major_collection_threshold = self.max_heap_size + def raw_malloc_varsize_hint(self, sizehint): + self.next_major_collection_threshold -= sizehint + if self.next_major_collection_threshold < 0: + # cannot trigger a full collection now, but we can ensure + # that one will occur very soon + self.nursery_free = self.nursery_top + def can_malloc_nonmovable(self): return True @@ -1600,7 +1615,7 @@ # Max heap size: gives an upper bound on the threshold. If we # already have at least this much allocated, raise MemoryError. if bounded and (float(self.get_total_memory_used()) + reserving_size >= - self.next_major_collection_threshold): + self.next_major_collection_initial): # # First raise MemoryError, giving the program a chance to # quit cleanly. It might still allocate in the nursery, diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py --- a/pypy/rpython/memory/gctransform/framework.py +++ b/pypy/rpython/memory/gctransform/framework.py @@ -386,6 +386,18 @@ else: self.malloc_varsize_nonmovable_ptr = None + if getattr(GCClass, 'raw_malloc_varsize_hint', False): + def raw_malloc_varsize_hint(length, itemsize): + totalmem = length * itemsize + if totalmem > 0: + gcdata.gc.raw_malloc_varsize_hint(totalmem) + #else: probably an overflow -- the following rawmalloc + # will fail then + self.raw_malloc_varsize_hint_ptr = getfn( + raw_malloc_varsize_hint, + [annmodel.SomeInteger(), annmodel.SomeInteger()], + annmodel.s_None, minimal_transform = False) + self.identityhash_ptr = getfn(GCClass.identityhash.im_func, [s_gc, s_gcref], annmodel.SomeInteger(), diff --git a/pypy/rpython/memory/gctransform/transform.py b/pypy/rpython/memory/gctransform/transform.py --- a/pypy/rpython/memory/gctransform/transform.py +++ b/pypy/rpython/memory/gctransform/transform.py @@ -590,6 +590,16 @@ def gct_fv_raw_malloc_varsize(self, hop, flags, TYPE, v_length, c_const_size, c_item_size, c_offset_to_length): + track_allocation = flags.get('track_allocation', True) + if not track_allocation: + # idea: raw mallocs with track_allocation=False correspond + # generally to raw mallocs of stuff that we store in GC objects. + # So we tell the GC about such raw mallocs, so that it can + # adjust its total size estimate. + if hasattr(self, 'raw_malloc_varsize_hint_ptr'): + hop.genop("direct_call", + [self.raw_malloc_varsize_hint_ptr, + v_length, c_item_size]) if c_offset_to_length is None: if flags.get('zero'): fnptr = self.raw_malloc_varsize_no_length_zero_ptr @@ -605,7 +615,7 @@ [self.raw_malloc_varsize_ptr, v_length, c_const_size, c_item_size, c_offset_to_length], resulttype=llmemory.Address) - if flags.get('track_allocation', True): + if track_allocation: hop.genop("track_alloc_start", [v_raw]) return v_raw diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py --- a/pypy/translator/c/test/test_newgc.py +++ b/pypy/translator/c/test/test_newgc.py @@ -1390,6 +1390,34 @@ def test_gc_heap_stats(self): py.test.skip("not implemented") + def define_nongc_attached_to_gc(cls): + from pypy.rpython.lltypesystem import rffi + ARRAY = rffi.CArray(rffi.INT) + class A: + def __init__(self, n): + self.buf = lltype.malloc(ARRAY, n, flavor='raw', + track_allocation=False) + def __del__(self): + lltype.free(self.buf, flavor='raw', track_allocation=False) + def f(): + # allocate a total of ~77GB, but if the automatic gc'ing works, + # it should never need more than a few MBs at once + am1 = am2 = am3 = None + res = 0 + for i in range(1, 100001): + if am3 is not None: + res += rffi.cast(lltype.Signed, am3.buf[0]) + am3 = am2 + am2 = am1 + am1 = A(i * 4) + am1.buf[0] = rffi.cast(rffi.INT, i-50000) + return res + return f + + def test_nongc_attached_to_gc(self): + res = self.run("nongc_attached_to_gc") + assert res == -99997 + # ____________________________________________________________________ class TaggedPointersTest(object): From noreply at buildbot.pypy.org Sun Jul 31 05:42:58 2011 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 31 Jul 2011 05:42:58 +0200 (CEST) Subject: [pypy-commit] pypy unroll-if-alt: Unroll this function so that "const str" % mapping is fast. Message-ID: <20110731034258.8C7E382110@wyvern.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: unroll-if-alt Changeset: r46118:f6a4c8d01004 Date: 2011-07-30 20:43 -0700 http://bitbucket.org/pypy/pypy/changeset/f6a4c8d01004/ Log: Unroll this function so that "const str" % mapping is fast. diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py --- a/pypy/objspace/std/formatting.py +++ b/pypy/objspace/std/formatting.py @@ -175,6 +175,9 @@ raise OperationError(space.w_ValueError, space.wrap("incomplete format")) + # Only shows up if we've already started inlining format(), so just + # unconditionally unroll this. + @jit.unroll_safe def getmappingkey(self): # return the mapping key in a '%(key)s' specifier fmt = self.fmt @@ -235,8 +238,7 @@ return w_value - # Only shows up if we've already started inlining format(), so just - # unconditionally unroll this. + # Same as getmappingkey @jit.unroll_safe def peel_flags(self): self.f_ljust = False @@ -260,7 +262,7 @@ break self.forward() - # Same as peel_flags. + # Same as getmappingkey @jit.unroll_safe def peel_num(self): space = self.space From notifications-noreply at bitbucket.org Sun Jul 31 17:35:07 2011 From: notifications-noreply at bitbucket.org (Bitbucket) Date: Sun, 31 Jul 2011 15:35:07 -0000 Subject: [pypy-commit] Notification: pypy Message-ID: <20110731153507.14256.4711@bitbucket03.managed.contegix.com> You have received a notification from fijal. Hi, I forked pypy. My fork is at https://bitbucket.org/fijal/pypy. -- Change your notification settings at https://bitbucket.org/account/notifications/